diff --git a/.clang-format b/.clang-format new file mode 100644 index 000000000..f0a989e26 --- /dev/null +++ b/.clang-format @@ -0,0 +1,11 @@ +# Important: Use the same version of clang-format as our linter, which is: +# +# $ ./scripts/install_deps.py --only-python +# $ ./build/python/bin/clang-format --version +# +# Warning: If you use a different version, the formatting will be different. +# +# To install a specific version of clang-format, use pip: +# $ pip install clang-format== + +BasedOnStyle: LLVM diff --git a/.github/workflows/lint-cmake-files.yml b/.github/workflows/lint-cmake-files.yml deleted file mode 100644 index ebee5d289..000000000 --- a/.github/workflows/lint-cmake-files.yml +++ /dev/null @@ -1,23 +0,0 @@ -# Runs - -name: "Lint CMake files" -on: - pull_request: - -jobs: - lint-cmake-files: - runs-on: ubuntu-latest - timeout-minutes: 10 - - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Install dependencies - run: | - python3 -m venv build/python - source build/python/bin/activate - pip install cmake_format pyyaml - - - name: Lint CMake files - run: ./scripts/lint_cmake_files.py diff --git a/.github/workflows/lint-source.yml b/.github/workflows/lint-source.yml new file mode 100644 index 000000000..5f9401803 --- /dev/null +++ b/.github/workflows/lint-source.yml @@ -0,0 +1,26 @@ +# Lints CMake config and C++ source code. + +name: "Lint source code" +on: + pull_request: + +jobs: + lint-cmake-files: + runs-on: ubuntu-latest + timeout-minutes: 5 + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Install dependencies + run: | + python3 -m venv build/python + source build/python/bin/activate + pip install pyyaml cmake_format clang_format + + - name: Linting with CMake formatter + run: ./scripts/lint_cmake.py + + - name: Linting with Clang format + run: ./scripts/lint_clang.py diff --git a/ChangeLog b/ChangeLog index 1eb1dfe2d..3570f5e6b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -38,6 +38,7 @@ Enhancements: - #7360 Re-implement packaging for GitHub workflows (Windows) - #7361 Re-implement packaging for GitHub workflows (Linux) - #7363 Schedule CI daily at 5am to detect code rot early +- #7364 Format all source with Clang and introduce lint workflow # 1.14.6 diff --git a/scripts/install_deps.py b/scripts/install_deps.py index 99620e895..83cba1aad 100755 --- a/scripts/install_deps.py +++ b/scripts/install_deps.py @@ -13,6 +13,11 @@ def main(): parser.add_argument( "--only", type=str, help="Only install the specified dependency" ) + parser.add_argument( + "--only-python", + action="store_true", + help="Only install Python dependencies", + ) args = parser.parse_args() env.ensure_dependencies() @@ -20,12 +25,13 @@ def main(): env.install_requirements() error = False - try: - deps = Dependencies(args.only) - deps.install() - except Exception: - traceback.print_exc() - error = True + if not args.only_python: + try: + deps = Dependencies(args.only) + deps.install() + except Exception: + traceback.print_exc() + error = True if args.pause_on_exit: input("Press enter to continue...") diff --git a/scripts/lib/fs.py b/scripts/lib/fs.py new file mode 100644 index 000000000..5bd6da113 --- /dev/null +++ b/scripts/lib/fs.py @@ -0,0 +1,14 @@ +import os, fnmatch + + +def find_files(search_dirs, include_files, exclude_dirs=[]): + """Recursively find files, excluding specified directories""" + matches = [] + for dir in search_dirs: + for root, dirnames, filenames in os.walk(dir): + dirnames[:] = [d for d in dirnames if d not in exclude_dirs] + + for pattern in include_files: + for filename in fnmatch.filter(filenames, pattern): + matches.append(os.path.join(root, filename)) + return matches diff --git a/scripts/lint_clang.py b/scripts/lint_clang.py new file mode 100755 index 000000000..e7e32b9ef --- /dev/null +++ b/scripts/lint_clang.py @@ -0,0 +1,57 @@ +#!/usr/bin/env python3 + +import argparse, sys +import lib.fs as fs +import lib.env as env + +include_files = [ + "*.h", + "*.c", + "*.hpp", + "*.cpp", +] + +dirs = ["src"] + + +def main(): + """ + Cross-platform equivalent of using find and xargs with clang-format. + Lints by performing a dry run (--dry-run) which fails when formatting is needed. + """ + parser = argparse.ArgumentParser() + parser.add_argument( + "--format", + action="store_true", + help="In-place format all files", + ) + args = parser.parse_args() + + env.ensure_in_venv(__file__) + from clang_format import clang_format # type: ignore + + cmd_args = ["-i"] if args.format else ["--dry-run", "--Werror"] + files_recursive = fs.find_files(dirs, include_files) + + if args.format: + print("Formatting files with Clang formatter:") + else: + print("Checking files with Clang formatter:") + + for file in files_recursive: + print(file) + + if files_recursive: + sys.argv = [""] + cmd_args + files_recursive + result = clang_format() + if result == 0: + print("Clang lint passed") + + sys.exit(result) + else: + print("No files for Clang to process", file=sys.stderr) + sys.exit(0) + + +if __name__ == "__main__": + main() diff --git a/scripts/lint_cmake.py b/scripts/lint_cmake.py new file mode 100755 index 000000000..5d9facaa6 --- /dev/null +++ b/scripts/lint_cmake.py @@ -0,0 +1,59 @@ +#!/usr/bin/env python3 + +import sys, argparse +import lib.env as env +import lib.fs as fs + +include_files = [ + "*.cmake", + "CMakeLists.txt", +] + +exclude_dirs = [ + "ext", + "build", +] + + +def main(): + """ + Cross-platform equivalent of using find and xargs with cmake-format. + Lints by performing a dry run (--check) which fails when formatting is needed. + """ + parser = argparse.ArgumentParser() + parser.add_argument( + "--format", + action="store_true", + help="In-place format all files", + ) + args = parser.parse_args() + + env.ensure_in_venv(__file__) + from cmakelang.format.__main__ import main as cmake_format_main + + cmd_args = ["--in-place"] if args.format else ["--check"] + files_recursive = fs.find_files(".", include_files, exclude_dirs) + + if args.format: + print("Formatting files with CMake formatter:") + else: + print("Checking files with CMake formatter:") + + for file in files_recursive: + print(file) + + if files_recursive: + sys.argv = [""] + cmd_args + files_recursive + + result = cmake_format_main() + if result == 0: + print("CMake lint passed") + + sys.exit(result) + else: + print("No CMake files found to process.", file=sys.stderr) + sys.exit(0) + + +if __name__ == "__main__": + main() diff --git a/scripts/lint_cmake_files.py b/scripts/lint_cmake_files.py deleted file mode 100755 index 49302ba12..000000000 --- a/scripts/lint_cmake_files.py +++ /dev/null @@ -1,51 +0,0 @@ -#!/usr/bin/env python3 - -import sys, os, argparse, fnmatch -import lib.env as env - -include_files = [ - "*.cmake", - "CMakeLists.txt", -] - -exclude_dirs = [ - "ext", - "build", -] - - -def find_files(base_dir, include_files, exclude_dirs): - """Recursively find files, excluding specified directories""" - matches = [] - for root, dirnames, filenames in os.walk(base_dir): - dirnames[:] = [d for d in dirnames if d not in exclude_dirs] - - for pattern in include_files: - for filename in fnmatch.filter(filenames, pattern): - matches.append(os.path.join(root, filename)) - return matches - - -def main(): - parser = argparse.ArgumentParser() - parser.add_argument("--format", action="store_true", help="Formats all CMake files") - args = parser.parse_args() - - # important: load venv before loading modules that install deps. - env.ensure_in_venv(__file__) - - from cmakelang.format.__main__ import main as cmake_format_main - - new_args = ["--in-place"] if args.format else ["--check"] - files_recursive = find_files(".", include_files, exclude_dirs) - - if files_recursive: - sys.argv = [""] + new_args + files_recursive - sys.exit(cmake_format_main()) - else: - print("No CMake files found to process.") - sys.exit(0) - - -if __name__ == "__main__": - main() diff --git a/scripts/requirements.txt b/scripts/requirements.txt index ecaef651e..5c483c105 100644 --- a/scripts/requirements.txt +++ b/scripts/requirements.txt @@ -1,4 +1,5 @@ cmake_format +clang-format python-dotenv pyyaml dmgbuild; sys_platform == 'darwin' diff --git a/src/cmd/synergy-core/synergy-core.cpp b/src/cmd/synergy-core/synergy-core.cpp index bf41f710f..0bda69b67 100644 --- a/src/cmd/synergy-core/synergy-core.cpp +++ b/src/cmd/synergy-core/synergy-core.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2022 Symless 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 LICENSE 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 @@ -15,54 +15,54 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -#include +#include "arch/Arch.h" +#include "base/EventQueue.h" +#include "base/Log.h" #include "synergy/ClientApp.h" #include "synergy/ServerApp.h" -#include "arch/Arch.h" -#include "base/Log.h" -#include "base/EventQueue.h" +#include -void showHelp() -{ - std::cout<<"Usage: synergy-core [...options]"< --help for more information."< 1 && argv[1] == std::string("server")); -} - -bool isClient(int argc, char** argv) -{ - return (argc > 1 && argv[1] == std::string("client")); -} - -int main(int argc, char** argv) -{ #if SYSAPI_WIN32 - ArchMiscWindows::setInstanceWin32(GetModuleHandle(NULL)); +#include "arch/win32/ArchMiscWindows.h" #endif - Arch arch; - arch.init(); - - Log log; - EventQueue events; - - if (isServer(argc, argv)) { - ServerApp app(&events, nullptr); - return app.run(argc, argv); - } - else if (isClient(argc, argv)) { - ClientApp app(&events, nullptr); - return app.run(argc, argv); - } - else { - showHelp(); - } - - return 0; +void showHelp() { + std::cout << "Usage: synergy-core [...options]" + << std::endl; + std::cout << "server - start as a server (synergys)" << std::endl; + std::cout << "client - start as a client (synergyc)" << std::endl; + std::cout << "use synergy-core --help for more information." + << std::endl; +} + +bool isServer(int argc, char **argv) { + return (argc > 1 && argv[1] == std::string("server")); +} + +bool isClient(int argc, char **argv) { + return (argc > 1 && argv[1] == std::string("client")); +} + +int main(int argc, char **argv) { +#if SYSAPI_WIN32 + ArchMiscWindows::setInstanceWin32(GetModuleHandle(NULL)); +#endif + + Arch arch; + arch.init(); + + Log log; + EventQueue events; + + if (isServer(argc, argv)) { + ServerApp app(&events, nullptr); + return app.run(argc, argv); + } else if (isClient(argc, argv)) { + ClientApp app(&events, nullptr); + return app.run(argc, argv); + } else { + showHelp(); + } + + return 0; } diff --git a/src/cmd/synergyc/MSWindowsClientTaskBarReceiver.cpp b/src/cmd/synergyc/MSWindowsClientTaskBarReceiver.cpp index 05af63a5b..1d0926357 100644 --- a/src/cmd/synergyc/MSWindowsClientTaskBarReceiver.cpp +++ b/src/cmd/synergyc/MSWindowsClientTaskBarReceiver.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2003 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 LICENSE 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 @@ -18,359 +18,308 @@ #include "MSWindowsClientTaskBarReceiver.h" -#include "resource.h" +#include "arch/Arch.h" +#include "arch/win32/ArchMiscWindows.h" +#include "arch/win32/ArchTaskBarWindows.h" +#include "base/EventQueue.h" +#include "base/EventTypes.h" +#include "base/log_outputters.h" #include "client/Client.h" #include "platform/MSWindowsClipboard.h" #include "platform/MSWindowsScreen.h" -#include "arch/win32/ArchTaskBarWindows.h" -#include "arch/win32/ArchMiscWindows.h" -#include "arch/Arch.h" -#include "base/EventQueue.h" -#include "base/log_outputters.h" -#include "base/EventTypes.h" +#include "resource.h" // // MSWindowsClientTaskBarReceiver // -const UINT MSWindowsClientTaskBarReceiver::s_stateToIconID[kMaxState] = -{ - IDI_TASKBAR_NOT_RUNNING, - IDI_TASKBAR_NOT_WORKING, - IDI_TASKBAR_NOT_CONNECTED, - IDI_TASKBAR_NOT_CONNECTED, - IDI_TASKBAR_CONNECTED -}; +const UINT MSWindowsClientTaskBarReceiver::s_stateToIconID[kMaxState] = { + IDI_TASKBAR_NOT_RUNNING, IDI_TASKBAR_NOT_WORKING, IDI_TASKBAR_NOT_CONNECTED, + IDI_TASKBAR_NOT_CONNECTED, IDI_TASKBAR_CONNECTED}; MSWindowsClientTaskBarReceiver::MSWindowsClientTaskBarReceiver( - HINSTANCE appInstance, const BufferedLogOutputter* logBuffer, IEventQueue* events) : - ClientTaskBarReceiver(events), - m_appInstance(appInstance), - m_window(NULL), - m_logBuffer(logBuffer) -{ - for (UInt32 i = 0; i < kMaxState; ++i) { - m_icon[i] = loadIcon(s_stateToIconID[i]); + HINSTANCE appInstance, const BufferedLogOutputter *logBuffer, + IEventQueue *events) + : ClientTaskBarReceiver(events), m_appInstance(appInstance), m_window(NULL), + m_logBuffer(logBuffer) { + for (UInt32 i = 0; i < kMaxState; ++i) { + m_icon[i] = loadIcon(s_stateToIconID[i]); + } + m_menu = LoadMenu(m_appInstance, MAKEINTRESOURCE(IDR_TASKBAR)); + + // don't create the window yet. we'll create it on demand. this + // has the side benefit of being created in the thread used for + // the task bar. that's good because it means the existence of + // the window won't prevent changing the main thread's desktop. + + // add ourself to the task bar + ARCH->addReceiver(this); +} + +MSWindowsClientTaskBarReceiver::~MSWindowsClientTaskBarReceiver() { cleanup(); } + +void MSWindowsClientTaskBarReceiver::cleanup() { + ARCH->removeReceiver(this); + for (UInt32 i = 0; i < kMaxState; ++i) { + deleteIcon(m_icon[i]); + } + DestroyMenu(m_menu); + destroyWindow(); +} + +void MSWindowsClientTaskBarReceiver::showStatus() { + // create the window + createWindow(); + + // lock self while getting status + lock(); + + // get the current status + std::string status = getToolTip(); + + // done getting status + unlock(); + + // update dialog + HWND child = GetDlgItem(m_window, IDC_TASKBAR_STATUS_STATUS); + SendMessage(child, WM_SETTEXT, 0, (LPARAM)status.c_str()); + + if (!IsWindowVisible(m_window)) { + // position it by the mouse + POINT cursorPos; + GetCursorPos(&cursorPos); + RECT windowRect; + GetWindowRect(m_window, &windowRect); + int x = cursorPos.x; + int y = cursorPos.y; + int fw = GetSystemMetrics(SM_CXDLGFRAME); + int fh = GetSystemMetrics(SM_CYDLGFRAME); + int ww = windowRect.right - windowRect.left; + int wh = windowRect.bottom - windowRect.top; + int sw = GetSystemMetrics(SM_CXFULLSCREEN); + int sh = GetSystemMetrics(SM_CYFULLSCREEN); + if (fw < 1) { + fw = 1; } - m_menu = LoadMenu(m_appInstance, MAKEINTRESOURCE(IDR_TASKBAR)); - - // don't create the window yet. we'll create it on demand. this - // has the side benefit of being created in the thread used for - // the task bar. that's good because it means the existence of - // the window won't prevent changing the main thread's desktop. - - // add ourself to the task bar - ARCH->addReceiver(this); -} - -MSWindowsClientTaskBarReceiver::~MSWindowsClientTaskBarReceiver() -{ - cleanup(); -} - -void -MSWindowsClientTaskBarReceiver::cleanup() -{ - ARCH->removeReceiver(this); - for (UInt32 i = 0; i < kMaxState; ++i) { - deleteIcon(m_icon[i]); + if (fh < 1) { + fh = 1; } - DestroyMenu(m_menu); - destroyWindow(); -} - -void -MSWindowsClientTaskBarReceiver::showStatus() -{ - // create the window - createWindow(); - - // lock self while getting status - lock(); - - // get the current status - std::string status = getToolTip(); - - // done getting status - unlock(); - - // update dialog - HWND child = GetDlgItem(m_window, IDC_TASKBAR_STATUS_STATUS); - SendMessage(child, WM_SETTEXT, 0, (LPARAM)status.c_str()); - - if (!IsWindowVisible(m_window)) { - // position it by the mouse - POINT cursorPos; - GetCursorPos(&cursorPos); - RECT windowRect; - GetWindowRect(m_window, &windowRect); - int x = cursorPos.x; - int y = cursorPos.y; - int fw = GetSystemMetrics(SM_CXDLGFRAME); - int fh = GetSystemMetrics(SM_CYDLGFRAME); - int ww = windowRect.right - windowRect.left; - int wh = windowRect.bottom - windowRect.top; - int sw = GetSystemMetrics(SM_CXFULLSCREEN); - int sh = GetSystemMetrics(SM_CYFULLSCREEN); - if (fw < 1) { - fw = 1; - } - if (fh < 1) { - fh = 1; - } - if (x + ww - fw > sw) { - x -= ww - fw; - } - else { - x -= fw; - } - if (x < 0) { - x = 0; - } - if (y + wh - fh > sh) { - y -= wh - fh; - } - else { - y -= fh; - } - if (y < 0) { - y = 0; - } - SetWindowPos(m_window, HWND_TOPMOST, x, y, ww, wh, - SWP_SHOWWINDOW); + if (x + ww - fw > sw) { + x -= ww - fw; + } else { + x -= fw; } -} - -void -MSWindowsClientTaskBarReceiver::runMenu(int x, int y) -{ - // do popup menu. we need a window to pass to TrackPopupMenu(). - // the SetForegroundWindow() and SendMessage() calls around - // TrackPopupMenu() are to get the menu to be dismissed when - // another window gets activated and are just one of those - // win32 weirdnesses. - createWindow(); - SetForegroundWindow(m_window); - HMENU menu = GetSubMenu(m_menu, 0); - SetMenuDefaultItem(menu, IDC_TASKBAR_STATUS, FALSE); - HMENU logLevelMenu = GetSubMenu(menu, 3); - CheckMenuRadioItem(logLevelMenu, 0, 6, - CLOG->getFilter() - kERROR, MF_BYPOSITION); - int n = TrackPopupMenu(menu, - TPM_NONOTIFY | - TPM_RETURNCMD | - TPM_LEFTBUTTON | - TPM_RIGHTBUTTON, - x, y, 0, m_window, NULL); - SendMessage(m_window, WM_NULL, 0, 0); - - // perform the requested operation - switch (n) { - case IDC_TASKBAR_STATUS: - showStatus(); - break; - - case IDC_TASKBAR_LOG: - copyLog(); - break; - - case IDC_TASKBAR_SHOW_LOG: - ARCH->showConsole(true); - break; - - case IDC_TASKBAR_LOG_LEVEL_ERROR: - CLOG->setFilter(kERROR); - break; - - case IDC_TASKBAR_LOG_LEVEL_WARNING: - CLOG->setFilter(kWARNING); - break; - - case IDC_TASKBAR_LOG_LEVEL_NOTE: - CLOG->setFilter(kNOTE); - break; - - case IDC_TASKBAR_LOG_LEVEL_INFO: - CLOG->setFilter(kINFO); - break; - - case IDC_TASKBAR_LOG_LEVEL_DEBUG: - CLOG->setFilter(kDEBUG); - break; - - case IDC_TASKBAR_LOG_LEVEL_DEBUG1: - CLOG->setFilter(kDEBUG1); - break; - - case IDC_TASKBAR_LOG_LEVEL_DEBUG2: - CLOG->setFilter(kDEBUG2); - break; - - case IDC_TASKBAR_QUIT: - quit(); - break; + if (x < 0) { + x = 0; } + if (y + wh - fh > sh) { + y -= wh - fh; + } else { + y -= fh; + } + if (y < 0) { + y = 0; + } + SetWindowPos(m_window, HWND_TOPMOST, x, y, ww, wh, SWP_SHOWWINDOW); + } } -void -MSWindowsClientTaskBarReceiver::primaryAction() -{ +void MSWindowsClientTaskBarReceiver::runMenu(int x, int y) { + // do popup menu. we need a window to pass to TrackPopupMenu(). + // the SetForegroundWindow() and SendMessage() calls around + // TrackPopupMenu() are to get the menu to be dismissed when + // another window gets activated and are just one of those + // win32 weirdnesses. + createWindow(); + SetForegroundWindow(m_window); + HMENU menu = GetSubMenu(m_menu, 0); + SetMenuDefaultItem(menu, IDC_TASKBAR_STATUS, FALSE); + HMENU logLevelMenu = GetSubMenu(menu, 3); + CheckMenuRadioItem(logLevelMenu, 0, 6, CLOG->getFilter() - kERROR, + MF_BYPOSITION); + int n = TrackPopupMenu( + menu, TPM_NONOTIFY | TPM_RETURNCMD | TPM_LEFTBUTTON | TPM_RIGHTBUTTON, x, + y, 0, m_window, NULL); + SendMessage(m_window, WM_NULL, 0, 0); + + // perform the requested operation + switch (n) { + case IDC_TASKBAR_STATUS: showStatus(); + break; + + case IDC_TASKBAR_LOG: + copyLog(); + break; + + case IDC_TASKBAR_SHOW_LOG: + ARCH->showConsole(true); + break; + + case IDC_TASKBAR_LOG_LEVEL_ERROR: + CLOG->setFilter(kERROR); + break; + + case IDC_TASKBAR_LOG_LEVEL_WARNING: + CLOG->setFilter(kWARNING); + break; + + case IDC_TASKBAR_LOG_LEVEL_NOTE: + CLOG->setFilter(kNOTE); + break; + + case IDC_TASKBAR_LOG_LEVEL_INFO: + CLOG->setFilter(kINFO); + break; + + case IDC_TASKBAR_LOG_LEVEL_DEBUG: + CLOG->setFilter(kDEBUG); + break; + + case IDC_TASKBAR_LOG_LEVEL_DEBUG1: + CLOG->setFilter(kDEBUG1); + break; + + case IDC_TASKBAR_LOG_LEVEL_DEBUG2: + CLOG->setFilter(kDEBUG2); + break; + + case IDC_TASKBAR_QUIT: + quit(); + break; + } } +void MSWindowsClientTaskBarReceiver::primaryAction() { showStatus(); } + const IArchTaskBarReceiver::Icon -MSWindowsClientTaskBarReceiver::getIcon() const -{ - return static_cast(m_icon[getStatus()]); +MSWindowsClientTaskBarReceiver::getIcon() const { + return static_cast(m_icon[getStatus()]); } -void -MSWindowsClientTaskBarReceiver::copyLog() const -{ - if (m_logBuffer != NULL) { - // collect log buffer - String data; - for (BufferedLogOutputter::const_iterator index = m_logBuffer->begin(); - index != m_logBuffer->end(); ++index) { - data += *index; - data += "\n"; - } - - // copy log to clipboard - if (!data.empty()) { - MSWindowsClipboard clipboard(m_window); - clipboard.open(0); - clipboard.emptyUnowned(); - clipboard.add(IClipboard::kText, data); - clipboard.close(); - } +void MSWindowsClientTaskBarReceiver::copyLog() const { + if (m_logBuffer != NULL) { + // collect log buffer + String data; + for (BufferedLogOutputter::const_iterator index = m_logBuffer->begin(); + index != m_logBuffer->end(); ++index) { + data += *index; + data += "\n"; } + + // copy log to clipboard + if (!data.empty()) { + MSWindowsClipboard clipboard(m_window); + clipboard.open(0); + clipboard.emptyUnowned(); + clipboard.add(IClipboard::kText, data); + clipboard.close(); + } + } } -void -MSWindowsClientTaskBarReceiver::onStatusChanged() -{ - if (IsWindowVisible(m_window)) { - showStatus(); - } +void MSWindowsClientTaskBarReceiver::onStatusChanged() { + if (IsWindowVisible(m_window)) { + showStatus(); + } } HICON -MSWindowsClientTaskBarReceiver::loadIcon(UINT id) -{ - HANDLE icon = LoadImage(m_appInstance, - MAKEINTRESOURCE(id), - IMAGE_ICON, - 0, 0, - LR_DEFAULTCOLOR); - return static_cast(icon); +MSWindowsClientTaskBarReceiver::loadIcon(UINT id) { + HANDLE icon = LoadImage(m_appInstance, MAKEINTRESOURCE(id), IMAGE_ICON, 0, 0, + LR_DEFAULTCOLOR); + return static_cast(icon); } -void -MSWindowsClientTaskBarReceiver::deleteIcon(HICON icon) -{ - if (icon != NULL) { - DestroyIcon(icon); - } +void MSWindowsClientTaskBarReceiver::deleteIcon(HICON icon) { + if (icon != NULL) { + DestroyIcon(icon); + } } -void -MSWindowsClientTaskBarReceiver::createWindow() -{ - // ignore if already created - if (m_window != NULL) { - return; - } +void MSWindowsClientTaskBarReceiver::createWindow() { + // ignore if already created + if (m_window != NULL) { + return; + } - // get the status dialog - m_window = CreateDialogParam(m_appInstance, - MAKEINTRESOURCE(IDD_TASKBAR_STATUS), - NULL, - (DLGPROC)&MSWindowsClientTaskBarReceiver::staticDlgProc, - reinterpret_cast( - static_cast(this))); + // get the status dialog + m_window = CreateDialogParam( + m_appInstance, MAKEINTRESOURCE(IDD_TASKBAR_STATUS), NULL, + (DLGPROC)&MSWindowsClientTaskBarReceiver::staticDlgProc, + reinterpret_cast(static_cast(this))); - // window should appear on top of everything, including (especially) - // the task bar. - LONG_PTR style = GetWindowLongPtr(m_window, GWL_EXSTYLE); - style |= WS_EX_TOOLWINDOW | WS_EX_TOPMOST; - SetWindowLongPtr(m_window, GWL_EXSTYLE, style); + // window should appear on top of everything, including (especially) + // the task bar. + LONG_PTR style = GetWindowLongPtr(m_window, GWL_EXSTYLE); + style |= WS_EX_TOOLWINDOW | WS_EX_TOPMOST; + SetWindowLongPtr(m_window, GWL_EXSTYLE, style); - // tell the task bar about this dialog - ArchTaskBarWindows::addDialog(m_window); + // tell the task bar about this dialog + ArchTaskBarWindows::addDialog(m_window); } -void -MSWindowsClientTaskBarReceiver::destroyWindow() -{ - if (m_window != NULL) { - ArchTaskBarWindows::removeDialog(m_window); - DestroyWindow(m_window); - m_window = NULL; - } +void MSWindowsClientTaskBarReceiver::destroyWindow() { + if (m_window != NULL) { + ArchTaskBarWindows::removeDialog(m_window); + DestroyWindow(m_window); + m_window = NULL; + } } -BOOL -MSWindowsClientTaskBarReceiver::dlgProc(HWND hwnd, - UINT msg, WPARAM wParam, LPARAM) -{ - switch (msg) { - case WM_INITDIALOG: - // use default focus - return TRUE; +BOOL MSWindowsClientTaskBarReceiver::dlgProc(HWND hwnd, UINT msg, WPARAM wParam, + LPARAM) { + switch (msg) { + case WM_INITDIALOG: + // use default focus + return TRUE; - case WM_ACTIVATE: - // hide when another window is activated - if (LOWORD(wParam) == WA_INACTIVE) { - ShowWindow(hwnd, SW_HIDE); - } - break; + case WM_ACTIVATE: + // hide when another window is activated + if (LOWORD(wParam) == WA_INACTIVE) { + ShowWindow(hwnd, SW_HIDE); } - return FALSE; + break; + } + return FALSE; } -BOOL CALLBACK -MSWindowsClientTaskBarReceiver::staticDlgProc(HWND hwnd, - UINT msg, WPARAM wParam, LPARAM lParam) -{ - // if msg is WM_INITDIALOG, extract the MSWindowsClientTaskBarReceiver* - // and put it in the extra window data then forward the call. - MSWindowsClientTaskBarReceiver* self = NULL; - if (msg == WM_INITDIALOG) { - self = static_cast( - reinterpret_cast(lParam)); - SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR) lParam); - } - else { - // get the extra window data and forward the call - LONG_PTR data = GetWindowLongPtr(hwnd, GWLP_USERDATA); - if (data != 0) { - self = (MSWindowsClientTaskBarReceiver*) data; - } +BOOL CALLBACK MSWindowsClientTaskBarReceiver::staticDlgProc(HWND hwnd, UINT msg, + WPARAM wParam, + LPARAM lParam) { + // if msg is WM_INITDIALOG, extract the MSWindowsClientTaskBarReceiver* + // and put it in the extra window data then forward the call. + MSWindowsClientTaskBarReceiver *self = NULL; + if (msg == WM_INITDIALOG) { + self = static_cast( + reinterpret_cast(lParam)); + SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)lParam); + } else { + // get the extra window data and forward the call + LONG_PTR data = GetWindowLongPtr(hwnd, GWLP_USERDATA); + if (data != 0) { + self = (MSWindowsClientTaskBarReceiver *)data; } + } - // forward the message - if (self != NULL) { - return self->dlgProc(hwnd, msg, wParam, lParam); - } - else { - return (msg == WM_INITDIALOG) ? TRUE : FALSE; - } + // forward the message + if (self != NULL) { + return self->dlgProc(hwnd, msg, wParam, lParam); + } else { + return (msg == WM_INITDIALOG) ? TRUE : FALSE; + } } -IArchTaskBarReceiver* -createTaskBarReceiver(const BufferedLogOutputter* logBuffer, IEventQueue* events) -{ - ArchMiscWindows::setIcons( - (HICON)LoadImage(ArchMiscWindows::instanceWin32(), - MAKEINTRESOURCE(IDI_SYNERGY), - IMAGE_ICON, - 32, 32, LR_SHARED), - (HICON)LoadImage(ArchMiscWindows::instanceWin32(), - MAKEINTRESOURCE(IDI_SYNERGY), - IMAGE_ICON, - 16, 16, LR_SHARED)); +IArchTaskBarReceiver * +createTaskBarReceiver(const BufferedLogOutputter *logBuffer, + IEventQueue *events) { + ArchMiscWindows::setIcons((HICON)LoadImage(ArchMiscWindows::instanceWin32(), + MAKEINTRESOURCE(IDI_SYNERGY), + IMAGE_ICON, 32, 32, LR_SHARED), + (HICON)LoadImage(ArchMiscWindows::instanceWin32(), + MAKEINTRESOURCE(IDI_SYNERGY), + IMAGE_ICON, 16, 16, LR_SHARED)); - return new MSWindowsClientTaskBarReceiver( - MSWindowsScreen::getWindowInstance(), logBuffer, events); + return new MSWindowsClientTaskBarReceiver( + MSWindowsScreen::getWindowInstance(), logBuffer, events); } diff --git a/src/cmd/synergyc/MSWindowsClientTaskBarReceiver.h b/src/cmd/synergyc/MSWindowsClientTaskBarReceiver.h index 0fa3c8fa2..75d10580f 100644 --- a/src/cmd/synergyc/MSWindowsClientTaskBarReceiver.h +++ b/src/cmd/synergyc/MSWindowsClientTaskBarReceiver.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2003 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 LICENSE 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 @@ -29,40 +29,39 @@ class IEventQueue; //! Implementation of ClientTaskBarReceiver for Microsoft Windows class MSWindowsClientTaskBarReceiver : public ClientTaskBarReceiver { public: - MSWindowsClientTaskBarReceiver(HINSTANCE, const BufferedLogOutputter*, IEventQueue* events); - virtual ~MSWindowsClientTaskBarReceiver(); + MSWindowsClientTaskBarReceiver(HINSTANCE, const BufferedLogOutputter *, + IEventQueue *events); + virtual ~MSWindowsClientTaskBarReceiver(); - // IArchTaskBarReceiver overrides - virtual void showStatus(); - virtual void runMenu(int x, int y); - virtual void primaryAction(); - virtual const Icon getIcon() const; - void cleanup(); + // IArchTaskBarReceiver overrides + virtual void showStatus(); + virtual void runMenu(int x, int y); + virtual void primaryAction(); + virtual const Icon getIcon() const; + void cleanup(); protected: - void copyLog() const; + void copyLog() const; - // ClientTaskBarReceiver overrides - virtual void onStatusChanged(); + // ClientTaskBarReceiver overrides + virtual void onStatusChanged(); private: - HICON loadIcon(UINT); - void deleteIcon(HICON); - void createWindow(); - void destroyWindow(); + HICON loadIcon(UINT); + void deleteIcon(HICON); + void createWindow(); + void destroyWindow(); - BOOL dlgProc(HWND hwnd, - UINT msg, WPARAM wParam, LPARAM lParam); - static BOOL CALLBACK - staticDlgProc(HWND hwnd, - UINT msg, WPARAM wParam, LPARAM lParam); + BOOL dlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); + static BOOL CALLBACK staticDlgProc(HWND hwnd, UINT msg, WPARAM wParam, + LPARAM lParam); private: - HINSTANCE m_appInstance; - HWND m_window; - HMENU m_menu; - HICON m_icon[kMaxState]; - const BufferedLogOutputter* m_logBuffer; + HINSTANCE m_appInstance; + HWND m_window; + HMENU m_menu; + HICON m_icon[kMaxState]; + const BufferedLogOutputter *m_logBuffer; - static const UINT s_stateToIconID[]; + static const UINT s_stateToIconID[]; }; diff --git a/src/cmd/synergyc/OSXClientTaskBarReceiver.cpp b/src/cmd/synergyc/OSXClientTaskBarReceiver.cpp index 488698ba7..4d86b6e3f 100644 --- a/src/cmd/synergyc/OSXClientTaskBarReceiver.cpp +++ b/src/cmd/synergyc/OSXClientTaskBarReceiver.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 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 LICENSE 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 @@ -23,47 +23,35 @@ // OSXClientTaskBarReceiver // -OSXClientTaskBarReceiver::OSXClientTaskBarReceiver( - const BufferedLogOutputter*, - IEventQueue* events) : - ClientTaskBarReceiver(events) -{ - // add ourself to the task bar - ARCH->addReceiver(this); +OSXClientTaskBarReceiver::OSXClientTaskBarReceiver(const BufferedLogOutputter *, + IEventQueue *events) + : ClientTaskBarReceiver(events) { + // add ourself to the task bar + ARCH->addReceiver(this); } -OSXClientTaskBarReceiver::~OSXClientTaskBarReceiver() -{ - ARCH->removeReceiver(this); +OSXClientTaskBarReceiver::~OSXClientTaskBarReceiver() { + ARCH->removeReceiver(this); } -void -OSXClientTaskBarReceiver::showStatus() -{ - // do nothing +void OSXClientTaskBarReceiver::showStatus() { + // do nothing } -void -OSXClientTaskBarReceiver::runMenu(int, int) -{ - // do nothing +void OSXClientTaskBarReceiver::runMenu(int, int) { + // do nothing } -void -OSXClientTaskBarReceiver::primaryAction() -{ - // do nothing +void OSXClientTaskBarReceiver::primaryAction() { + // do nothing } -const IArchTaskBarReceiver::Icon -OSXClientTaskBarReceiver::getIcon() const -{ - return NULL; +const IArchTaskBarReceiver::Icon OSXClientTaskBarReceiver::getIcon() const { + return NULL; } -IArchTaskBarReceiver* -createTaskBarReceiver(const BufferedLogOutputter* logBuffer, IEventQueue* events) -{ - return new OSXClientTaskBarReceiver(logBuffer, events); +IArchTaskBarReceiver * +createTaskBarReceiver(const BufferedLogOutputter *logBuffer, + IEventQueue *events) { + return new OSXClientTaskBarReceiver(logBuffer, events); } - diff --git a/src/cmd/synergyc/OSXClientTaskBarReceiver.h b/src/cmd/synergyc/OSXClientTaskBarReceiver.h index a24856f80..49d1c169d 100644 --- a/src/cmd/synergyc/OSXClientTaskBarReceiver.h +++ b/src/cmd/synergyc/OSXClientTaskBarReceiver.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 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 LICENSE 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 @@ -26,12 +26,12 @@ class IEventQueue; //! Implementation of ClientTaskBarReceiver for OS X class OSXClientTaskBarReceiver : public ClientTaskBarReceiver { public: - OSXClientTaskBarReceiver(const BufferedLogOutputter*, IEventQueue* events); - virtual ~OSXClientTaskBarReceiver(); + OSXClientTaskBarReceiver(const BufferedLogOutputter *, IEventQueue *events); + virtual ~OSXClientTaskBarReceiver(); - // IArchTaskBarReceiver overrides - virtual void showStatus(); - virtual void runMenu(int x, int y); - virtual void primaryAction(); - virtual const Icon getIcon() const; + // IArchTaskBarReceiver overrides + virtual void showStatus(); + virtual void runMenu(int x, int y); + virtual void primaryAction(); + virtual const Icon getIcon() const; }; diff --git a/src/cmd/synergyc/XWindowsClientTaskBarReceiver.cpp b/src/cmd/synergyc/XWindowsClientTaskBarReceiver.cpp index 20001360c..2075681fd 100644 --- a/src/cmd/synergyc/XWindowsClientTaskBarReceiver.cpp +++ b/src/cmd/synergyc/XWindowsClientTaskBarReceiver.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2003 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 LICENSE 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 @@ -24,45 +24,35 @@ // CXWindowsClientTaskBarReceiver::CXWindowsClientTaskBarReceiver( - const BufferedLogOutputter*, - IEventQueue* events) : - ClientTaskBarReceiver(events) -{ - // add ourself to the task bar - ARCH->addReceiver(this); + const BufferedLogOutputter *, IEventQueue *events) + : ClientTaskBarReceiver(events) { + // add ourself to the task bar + ARCH->addReceiver(this); } -CXWindowsClientTaskBarReceiver::~CXWindowsClientTaskBarReceiver() -{ - ARCH->removeReceiver(this); +CXWindowsClientTaskBarReceiver::~CXWindowsClientTaskBarReceiver() { + ARCH->removeReceiver(this); } -void -CXWindowsClientTaskBarReceiver::showStatus() -{ - // do nothing +void CXWindowsClientTaskBarReceiver::showStatus() { + // do nothing } -void -CXWindowsClientTaskBarReceiver::runMenu(int, int) -{ - // do nothing +void CXWindowsClientTaskBarReceiver::runMenu(int, int) { + // do nothing } -void -CXWindowsClientTaskBarReceiver::primaryAction() -{ - // do nothing +void CXWindowsClientTaskBarReceiver::primaryAction() { + // do nothing } const IArchTaskBarReceiver::Icon -CXWindowsClientTaskBarReceiver::getIcon() const -{ - return NULL; +CXWindowsClientTaskBarReceiver::getIcon() const { + return NULL; } -IArchTaskBarReceiver* -createTaskBarReceiver(const BufferedLogOutputter* logBuffer, IEventQueue* events) -{ - return new CXWindowsClientTaskBarReceiver(logBuffer, events); +IArchTaskBarReceiver * +createTaskBarReceiver(const BufferedLogOutputter *logBuffer, + IEventQueue *events) { + return new CXWindowsClientTaskBarReceiver(logBuffer, events); } diff --git a/src/cmd/synergyc/XWindowsClientTaskBarReceiver.h b/src/cmd/synergyc/XWindowsClientTaskBarReceiver.h index d72c2f33a..24aaec6be 100644 --- a/src/cmd/synergyc/XWindowsClientTaskBarReceiver.h +++ b/src/cmd/synergyc/XWindowsClientTaskBarReceiver.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2003 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 LICENSE 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 @@ -26,18 +26,21 @@ class IEventQueue; //! Implementation of ClientTaskBarReceiver for X Windows class CXWindowsClientTaskBarReceiver : public ClientTaskBarReceiver { public: - CXWindowsClientTaskBarReceiver( - const BufferedLogOutputter*, IEventQueue* events); - CXWindowsClientTaskBarReceiver(const CXWindowsClientTaskBarReceiver &) =delete; - CXWindowsClientTaskBarReceiver(CXWindowsClientTaskBarReceiver &&) =delete; - virtual ~CXWindowsClientTaskBarReceiver(); + CXWindowsClientTaskBarReceiver(const BufferedLogOutputter *, + IEventQueue *events); + CXWindowsClientTaskBarReceiver(const CXWindowsClientTaskBarReceiver &) = + delete; + CXWindowsClientTaskBarReceiver(CXWindowsClientTaskBarReceiver &&) = delete; + virtual ~CXWindowsClientTaskBarReceiver(); - CXWindowsClientTaskBarReceiver& operator=(const CXWindowsClientTaskBarReceiver &) =delete; - CXWindowsClientTaskBarReceiver& operator=(CXWindowsClientTaskBarReceiver &&) =delete; + CXWindowsClientTaskBarReceiver & + operator=(const CXWindowsClientTaskBarReceiver &) = delete; + CXWindowsClientTaskBarReceiver & + operator=(CXWindowsClientTaskBarReceiver &&) = delete; - // IArchTaskBarReceiver overrides - virtual void showStatus(); - virtual void runMenu(int x, int y); - virtual void primaryAction(); - virtual const Icon getIcon() const; + // IArchTaskBarReceiver overrides + virtual void showStatus(); + virtual void runMenu(int x, int y); + virtual void primaryAction(); + virtual const Icon getIcon() const; }; diff --git a/src/cmd/synergyc/resource.h b/src/cmd/synergyc/resource.h index eeee6e1ec..a21e9c048 100644 --- a/src/cmd/synergyc/resource.h +++ b/src/cmd/synergyc/resource.h @@ -2,36 +2,36 @@ // Microsoft Developer Studio generated include file. // Used by synergyc.rc // -#define IDS_FAILED 1 -#define IDS_INIT_FAILED 2 -#define IDS_UNCAUGHT_EXCEPTION 3 -#define IDI_SYNERGY 101 -#define IDI_TASKBAR_NOT_RUNNING 102 -#define IDI_TASKBAR_NOT_WORKING 103 -#define IDI_TASKBAR_NOT_CONNECTED 104 -#define IDI_TASKBAR_CONNECTED 105 -#define IDR_TASKBAR 107 -#define IDD_TASKBAR_STATUS 108 -#define IDC_TASKBAR_STATUS_STATUS 1000 -#define IDC_TASKBAR_QUIT 40001 -#define IDC_TASKBAR_STATUS 40002 -#define IDC_TASKBAR_LOG 40003 -#define IDC_TASKBAR_SHOW_LOG 40004 -#define IDC_TASKBAR_LOG_LEVEL_ERROR 40009 -#define IDC_TASKBAR_LOG_LEVEL_WARNING 40010 -#define IDC_TASKBAR_LOG_LEVEL_NOTE 40011 -#define IDC_TASKBAR_LOG_LEVEL_INFO 40012 -#define IDC_TASKBAR_LOG_LEVEL_DEBUG 40013 -#define IDC_TASKBAR_LOG_LEVEL_DEBUG1 40014 -#define IDC_TASKBAR_LOG_LEVEL_DEBUG2 40015 +#define IDS_FAILED 1 +#define IDS_INIT_FAILED 2 +#define IDS_UNCAUGHT_EXCEPTION 3 +#define IDI_SYNERGY 101 +#define IDI_TASKBAR_NOT_RUNNING 102 +#define IDI_TASKBAR_NOT_WORKING 103 +#define IDI_TASKBAR_NOT_CONNECTED 104 +#define IDI_TASKBAR_CONNECTED 105 +#define IDR_TASKBAR 107 +#define IDD_TASKBAR_STATUS 108 +#define IDC_TASKBAR_STATUS_STATUS 1000 +#define IDC_TASKBAR_QUIT 40001 +#define IDC_TASKBAR_STATUS 40002 +#define IDC_TASKBAR_LOG 40003 +#define IDC_TASKBAR_SHOW_LOG 40004 +#define IDC_TASKBAR_LOG_LEVEL_ERROR 40009 +#define IDC_TASKBAR_LOG_LEVEL_WARNING 40010 +#define IDC_TASKBAR_LOG_LEVEL_NOTE 40011 +#define IDC_TASKBAR_LOG_LEVEL_INFO 40012 +#define IDC_TASKBAR_LOG_LEVEL_DEBUG 40013 +#define IDC_TASKBAR_LOG_LEVEL_DEBUG1 40014 +#define IDC_TASKBAR_LOG_LEVEL_DEBUG2 40015 // Next default values for new objects -// +// #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 109 -#define _APS_NEXT_COMMAND_VALUE 40016 -#define _APS_NEXT_CONTROL_VALUE 1001 -#define _APS_NEXT_SYMED_VALUE 101 +#define _APS_NEXT_RESOURCE_VALUE 109 +#define _APS_NEXT_COMMAND_VALUE 40016 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 #endif #endif diff --git a/src/cmd/synergyc/synergyc.cpp b/src/cmd/synergyc/synergyc.cpp index 5d598add9..137b07e2a 100644 --- a/src/cmd/synergyc/synergyc.cpp +++ b/src/cmd/synergyc/synergyc.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -16,10 +16,14 @@ * along with this program. If not, see . */ -#include "synergy/ClientApp.h" #include "arch/Arch.h" -#include "base/Log.h" #include "base/EventQueue.h" +#include "base/Log.h" +#include "synergy/ClientApp.h" + +#if SYSAPI_WIN32 +#include "arch/win32/ArchMiscWindows.h" +#endif #if WINAPI_MSWINDOWS #include "MSWindowsClientTaskBarReceiver.h" @@ -31,20 +35,18 @@ #error Platform not supported. #endif -int -main(int argc, char** argv) -{ +int main(int argc, char **argv) { #if SYSAPI_WIN32 - // record window instance for tray icon, etc - ArchMiscWindows::setInstanceWin32(GetModuleHandle(NULL)); + // record window instance for tray icon, etc + ArchMiscWindows::setInstanceWin32(GetModuleHandle(NULL)); #endif - - Arch arch; - arch.init(); - Log log; - EventQueue events; + Arch arch; + arch.init(); - ClientApp app(&events, createTaskBarReceiver); - return app.run(argc, argv); + Log log; + EventQueue events; + + ClientApp app(&events, createTaskBarReceiver); + return app.run(argc, argv); } diff --git a/src/cmd/synergyd/synergyd.cpp b/src/cmd/synergyd/synergyd.cpp index 74f3fd2f3..446ee3717 100644 --- a/src/cmd/synergyd/synergyd.cpp +++ b/src/cmd/synergyd/synergyd.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2012 Nick Bolton - * + * * 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 LICENSE 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 @@ -22,11 +22,9 @@ #ifdef SYSAPI_UNIX -int -main(int argc, char** argv) -{ - DaemonApp app; - return app.run(argc, argv); +int main(int argc, char **argv) { + DaemonApp app; + return app.run(argc, argv); } #elif SYSAPI_WIN32 @@ -34,11 +32,9 @@ main(int argc, char** argv) #define WIN32_LEAN_AND_MEAN #include -int WINAPI -WinMain(HINSTANCE, HINSTANCE, LPSTR, int) -{ - DaemonApp app; - return app.run(__argc, __argv); +int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) { + DaemonApp app; + return app.run(__argc, __argv); } #endif diff --git a/src/cmd/synergys/MSWindowsServerTaskBarReceiver.cpp b/src/cmd/synergys/MSWindowsServerTaskBarReceiver.cpp index 2b63c0c27..33d84c389 100644 --- a/src/cmd/synergys/MSWindowsServerTaskBarReceiver.cpp +++ b/src/cmd/synergys/MSWindowsServerTaskBarReceiver.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2003 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 LICENSE 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 @@ -18,391 +18,339 @@ #include "MSWindowsServerTaskBarReceiver.h" -#include "resource.h" -#include "server/Server.h" -#include "platform/MSWindowsClipboard.h" -#include "platform/MSWindowsScreen.h" -#include "arch/win32/ArchTaskBarWindows.h" -#include "arch/win32/ArchMiscWindows.h" #include "arch/Arch.h" +#include "arch/win32/ArchMiscWindows.h" +#include "arch/win32/ArchTaskBarWindows.h" #include "base/EventQueue.h" +#include "base/EventTypes.h" #include "base/IEventQueue.h" #include "base/log_outputters.h" -#include "base/EventTypes.h" +#include "platform/MSWindowsClipboard.h" +#include "platform/MSWindowsScreen.h" +#include "resource.h" +#include "server/Server.h" // // MSWindowsServerTaskBarReceiver // -const UINT MSWindowsServerTaskBarReceiver::s_stateToIconID[kMaxState] = -{ - IDI_TASKBAR_NOT_RUNNING, - IDI_TASKBAR_NOT_WORKING, - IDI_TASKBAR_NOT_CONNECTED, - IDI_TASKBAR_CONNECTED -}; +const UINT MSWindowsServerTaskBarReceiver::s_stateToIconID[kMaxState] = { + IDI_TASKBAR_NOT_RUNNING, IDI_TASKBAR_NOT_WORKING, IDI_TASKBAR_NOT_CONNECTED, + IDI_TASKBAR_CONNECTED}; MSWindowsServerTaskBarReceiver::MSWindowsServerTaskBarReceiver( - HINSTANCE appInstance, const BufferedLogOutputter* logBuffer, IEventQueue* events) : - ServerTaskBarReceiver(events), - m_events(events), - m_appInstance(appInstance), - m_window(NULL), - m_logBuffer(logBuffer) -{ - for (UInt32 i = 0; i < kMaxState; ++i) { - m_icon[i] = loadIcon(s_stateToIconID[i]); - } - m_menu = LoadMenu(m_appInstance, MAKEINTRESOURCE(IDR_TASKBAR)); + HINSTANCE appInstance, const BufferedLogOutputter *logBuffer, + IEventQueue *events) + : ServerTaskBarReceiver(events), m_events(events), + m_appInstance(appInstance), m_window(NULL), m_logBuffer(logBuffer) { + for (UInt32 i = 0; i < kMaxState; ++i) { + m_icon[i] = loadIcon(s_stateToIconID[i]); + } + m_menu = LoadMenu(m_appInstance, MAKEINTRESOURCE(IDR_TASKBAR)); - // don't create the window yet. we'll create it on demand. this - // has the side benefit of being created in the thread used for - // the task bar. that's good because it means the existence of - // the window won't prevent changing the main thread's desktop. + // don't create the window yet. we'll create it on demand. this + // has the side benefit of being created in the thread used for + // the task bar. that's good because it means the existence of + // the window won't prevent changing the main thread's desktop. - // add ourself to the task bar - ARCH->addReceiver(this); + // add ourself to the task bar + ARCH->addReceiver(this); } -void -MSWindowsServerTaskBarReceiver::cleanup() -{ - ARCH->removeReceiver(this); - for (UInt32 i = 0; i < kMaxState; ++i) { - deleteIcon(m_icon[i]); - } - DestroyMenu(m_menu); - destroyWindow(); +void MSWindowsServerTaskBarReceiver::cleanup() { + ARCH->removeReceiver(this); + for (UInt32 i = 0; i < kMaxState; ++i) { + deleteIcon(m_icon[i]); + } + DestroyMenu(m_menu); + destroyWindow(); } -MSWindowsServerTaskBarReceiver::~MSWindowsServerTaskBarReceiver() -{ - cleanup(); +MSWindowsServerTaskBarReceiver::~MSWindowsServerTaskBarReceiver() { cleanup(); } + +void MSWindowsServerTaskBarReceiver::showStatus() { + // create the window + createWindow(); + + // lock self while getting status + lock(); + + // get the current status + std::string status = getToolTip(); + + // get the connect clients, if any + const Clients &clients = getClients(); + + // done getting status + unlock(); + + // update dialog + HWND child = GetDlgItem(m_window, IDC_TASKBAR_STATUS_STATUS); + SendMessage(child, WM_SETTEXT, 0, (LPARAM)status.c_str()); + child = GetDlgItem(m_window, IDC_TASKBAR_STATUS_CLIENTS); + SendMessage(child, LB_RESETCONTENT, 0, 0); + for (Clients::const_iterator index = clients.begin(); + index != clients.end();) { + const char *client = index->c_str(); + if (++index == clients.end()) { + SendMessage(child, LB_ADDSTRING, 0, (LPARAM)client); + } else { + SendMessage(child, LB_INSERTSTRING, (WPARAM)-1, (LPARAM)client); + } + } + + if (!IsWindowVisible(m_window)) { + // position it by the mouse + POINT cursorPos; + GetCursorPos(&cursorPos); + RECT windowRect; + GetWindowRect(m_window, &windowRect); + int x = cursorPos.x; + int y = cursorPos.y; + int fw = GetSystemMetrics(SM_CXDLGFRAME); + int fh = GetSystemMetrics(SM_CYDLGFRAME); + int ww = windowRect.right - windowRect.left; + int wh = windowRect.bottom - windowRect.top; + int sw = GetSystemMetrics(SM_CXFULLSCREEN); + int sh = GetSystemMetrics(SM_CYFULLSCREEN); + if (fw < 1) { + fw = 1; + } + if (fh < 1) { + fh = 1; + } + if (x + ww - fw > sw) { + x -= ww - fw; + } else { + x -= fw; + } + if (x < 0) { + x = 0; + } + if (y + wh - fh > sh) { + y -= wh - fh; + } else { + y -= fh; + } + if (y < 0) { + y = 0; + } + SetWindowPos(m_window, HWND_TOPMOST, x, y, ww, wh, SWP_SHOWWINDOW); + } } -void -MSWindowsServerTaskBarReceiver::showStatus() -{ - // create the window - createWindow(); +void MSWindowsServerTaskBarReceiver::runMenu(int x, int y) { + // do popup menu. we need a window to pass to TrackPopupMenu(). + // the SetForegroundWindow() and SendMessage() calls around + // TrackPopupMenu() are to get the menu to be dismissed when + // another window gets activated and are just one of those + // win32 weirdnesses. + createWindow(); + SetForegroundWindow(m_window); + HMENU menu = GetSubMenu(m_menu, 0); + SetMenuDefaultItem(menu, IDC_TASKBAR_STATUS, FALSE); + HMENU logLevelMenu = GetSubMenu(menu, 3); + CheckMenuRadioItem(logLevelMenu, 0, 6, CLOG->getFilter() - kERROR, + MF_BYPOSITION); + int n = TrackPopupMenu( + menu, TPM_NONOTIFY | TPM_RETURNCMD | TPM_LEFTBUTTON | TPM_RIGHTBUTTON, x, + y, 0, m_window, NULL); + SendMessage(m_window, WM_NULL, 0, 0); - // lock self while getting status - lock(); - - // get the current status - std::string status = getToolTip(); - - // get the connect clients, if any - const Clients& clients = getClients(); - - // done getting status - unlock(); - - // update dialog - HWND child = GetDlgItem(m_window, IDC_TASKBAR_STATUS_STATUS); - SendMessage(child, WM_SETTEXT, 0, (LPARAM)status.c_str()); - child = GetDlgItem(m_window, IDC_TASKBAR_STATUS_CLIENTS); - SendMessage(child, LB_RESETCONTENT, 0, 0); - for (Clients::const_iterator index = clients.begin(); - index != clients.end(); ) { - const char* client = index->c_str(); - if (++index == clients.end()) { - SendMessage(child, LB_ADDSTRING, 0, (LPARAM)client); - } - else { - SendMessage(child, LB_INSERTSTRING, (WPARAM)-1, (LPARAM)client); - } - } - - if (!IsWindowVisible(m_window)) { - // position it by the mouse - POINT cursorPos; - GetCursorPos(&cursorPos); - RECT windowRect; - GetWindowRect(m_window, &windowRect); - int x = cursorPos.x; - int y = cursorPos.y; - int fw = GetSystemMetrics(SM_CXDLGFRAME); - int fh = GetSystemMetrics(SM_CYDLGFRAME); - int ww = windowRect.right - windowRect.left; - int wh = windowRect.bottom - windowRect.top; - int sw = GetSystemMetrics(SM_CXFULLSCREEN); - int sh = GetSystemMetrics(SM_CYFULLSCREEN); - if (fw < 1) { - fw = 1; - } - if (fh < 1) { - fh = 1; - } - if (x + ww - fw > sw) { - x -= ww - fw; - } - else { - x -= fw; - } - if (x < 0) { - x = 0; - } - if (y + wh - fh > sh) { - y -= wh - fh; - } - else { - y -= fh; - } - if (y < 0) { - y = 0; - } - SetWindowPos(m_window, HWND_TOPMOST, x, y, ww, wh, - SWP_SHOWWINDOW); - } -} - -void -MSWindowsServerTaskBarReceiver::runMenu(int x, int y) -{ - // do popup menu. we need a window to pass to TrackPopupMenu(). - // the SetForegroundWindow() and SendMessage() calls around - // TrackPopupMenu() are to get the menu to be dismissed when - // another window gets activated and are just one of those - // win32 weirdnesses. - createWindow(); - SetForegroundWindow(m_window); - HMENU menu = GetSubMenu(m_menu, 0); - SetMenuDefaultItem(menu, IDC_TASKBAR_STATUS, FALSE); - HMENU logLevelMenu = GetSubMenu(menu, 3); - CheckMenuRadioItem(logLevelMenu, 0, 6, - CLOG->getFilter() - kERROR, MF_BYPOSITION); - int n = TrackPopupMenu(menu, - TPM_NONOTIFY | - TPM_RETURNCMD | - TPM_LEFTBUTTON | - TPM_RIGHTBUTTON, - x, y, 0, m_window, NULL); - SendMessage(m_window, WM_NULL, 0, 0); - - // perform the requested operation - switch (n) { - case IDC_TASKBAR_STATUS: - showStatus(); - break; - - case IDC_TASKBAR_LOG: - copyLog(); - break; - - case IDC_TASKBAR_SHOW_LOG: - ARCH->showConsole(true); - break; - - case IDC_RELOAD_CONFIG: - m_events->addEvent(Event(m_events->forServerApp().reloadConfig(), - m_events->getSystemTarget())); - break; - - case IDC_FORCE_RECONNECT: - m_events->addEvent(Event(m_events->forServerApp().forceReconnect(), - m_events->getSystemTarget())); - break; - - case ID_SYNERGY_RESETSERVER: - m_events->addEvent(Event(m_events->forServerApp().resetServer(), - m_events->getSystemTarget())); - break; - - case IDC_TASKBAR_LOG_LEVEL_ERROR: - CLOG->setFilter(kERROR); - break; - - case IDC_TASKBAR_LOG_LEVEL_WARNING: - CLOG->setFilter(kWARNING); - break; - - case IDC_TASKBAR_LOG_LEVEL_NOTE: - CLOG->setFilter(kNOTE); - break; - - case IDC_TASKBAR_LOG_LEVEL_INFO: - CLOG->setFilter(kINFO); - break; - - case IDC_TASKBAR_LOG_LEVEL_DEBUG: - CLOG->setFilter(kDEBUG); - break; - - case IDC_TASKBAR_LOG_LEVEL_DEBUG1: - CLOG->setFilter(kDEBUG1); - break; - - case IDC_TASKBAR_LOG_LEVEL_DEBUG2: - CLOG->setFilter(kDEBUG2); - break; - - case IDC_TASKBAR_QUIT: - quit(); - break; - } -} - -void -MSWindowsServerTaskBarReceiver::primaryAction() -{ + // perform the requested operation + switch (n) { + case IDC_TASKBAR_STATUS: showStatus(); + break; + + case IDC_TASKBAR_LOG: + copyLog(); + break; + + case IDC_TASKBAR_SHOW_LOG: + ARCH->showConsole(true); + break; + + case IDC_RELOAD_CONFIG: + m_events->addEvent(Event(m_events->forServerApp().reloadConfig(), + m_events->getSystemTarget())); + break; + + case IDC_FORCE_RECONNECT: + m_events->addEvent(Event(m_events->forServerApp().forceReconnect(), + m_events->getSystemTarget())); + break; + + case ID_SYNERGY_RESETSERVER: + m_events->addEvent(Event(m_events->forServerApp().resetServer(), + m_events->getSystemTarget())); + break; + + case IDC_TASKBAR_LOG_LEVEL_ERROR: + CLOG->setFilter(kERROR); + break; + + case IDC_TASKBAR_LOG_LEVEL_WARNING: + CLOG->setFilter(kWARNING); + break; + + case IDC_TASKBAR_LOG_LEVEL_NOTE: + CLOG->setFilter(kNOTE); + break; + + case IDC_TASKBAR_LOG_LEVEL_INFO: + CLOG->setFilter(kINFO); + break; + + case IDC_TASKBAR_LOG_LEVEL_DEBUG: + CLOG->setFilter(kDEBUG); + break; + + case IDC_TASKBAR_LOG_LEVEL_DEBUG1: + CLOG->setFilter(kDEBUG1); + break; + + case IDC_TASKBAR_LOG_LEVEL_DEBUG2: + CLOG->setFilter(kDEBUG2); + break; + + case IDC_TASKBAR_QUIT: + quit(); + break; + } } +void MSWindowsServerTaskBarReceiver::primaryAction() { showStatus(); } + const IArchTaskBarReceiver::Icon -MSWindowsServerTaskBarReceiver::getIcon() const -{ - return static_cast(m_icon[getStatus()]); +MSWindowsServerTaskBarReceiver::getIcon() const { + return static_cast(m_icon[getStatus()]); } -void -MSWindowsServerTaskBarReceiver::copyLog() const -{ - if (m_logBuffer != NULL) { - // collect log buffer - String data; - for (BufferedLogOutputter::const_iterator index = m_logBuffer->begin(); - index != m_logBuffer->end(); ++index) { - data += *index; - data += "\n"; - } - - // copy log to clipboard - if (!data.empty()) { - MSWindowsClipboard clipboard(m_window); - clipboard.open(0); - clipboard.emptyUnowned(); - clipboard.add(IClipboard::kText, data); - clipboard.close(); - } +void MSWindowsServerTaskBarReceiver::copyLog() const { + if (m_logBuffer != NULL) { + // collect log buffer + String data; + for (BufferedLogOutputter::const_iterator index = m_logBuffer->begin(); + index != m_logBuffer->end(); ++index) { + data += *index; + data += "\n"; } + + // copy log to clipboard + if (!data.empty()) { + MSWindowsClipboard clipboard(m_window); + clipboard.open(0); + clipboard.emptyUnowned(); + clipboard.add(IClipboard::kText, data); + clipboard.close(); + } + } } -void -MSWindowsServerTaskBarReceiver::onStatusChanged() -{ - if (IsWindowVisible(m_window)) { - showStatus(); - } +void MSWindowsServerTaskBarReceiver::onStatusChanged() { + if (IsWindowVisible(m_window)) { + showStatus(); + } } HICON -MSWindowsServerTaskBarReceiver::loadIcon(UINT id) -{ - HANDLE icon = LoadImage(m_appInstance, - MAKEINTRESOURCE(id), - IMAGE_ICON, - 0, 0, - LR_DEFAULTCOLOR); - return static_cast(icon); +MSWindowsServerTaskBarReceiver::loadIcon(UINT id) { + HANDLE icon = LoadImage(m_appInstance, MAKEINTRESOURCE(id), IMAGE_ICON, 0, 0, + LR_DEFAULTCOLOR); + return static_cast(icon); } -void -MSWindowsServerTaskBarReceiver::deleteIcon(HICON icon) -{ - if (icon != NULL) { - DestroyIcon(icon); - } +void MSWindowsServerTaskBarReceiver::deleteIcon(HICON icon) { + if (icon != NULL) { + DestroyIcon(icon); + } } -void -MSWindowsServerTaskBarReceiver::createWindow() -{ - // ignore if already created - if (m_window != NULL) { - return; - } +void MSWindowsServerTaskBarReceiver::createWindow() { + // ignore if already created + if (m_window != NULL) { + return; + } - // get the status dialog - m_window = CreateDialogParam(m_appInstance, - MAKEINTRESOURCE(IDD_TASKBAR_STATUS), - NULL, - (DLGPROC)&MSWindowsServerTaskBarReceiver::staticDlgProc, - reinterpret_cast( - static_cast(this))); + // get the status dialog + m_window = CreateDialogParam( + m_appInstance, MAKEINTRESOURCE(IDD_TASKBAR_STATUS), NULL, + (DLGPROC)&MSWindowsServerTaskBarReceiver::staticDlgProc, + reinterpret_cast(static_cast(this))); - // window should appear on top of everything, including (especially) - // the task bar. - LONG_PTR style = GetWindowLongPtr(m_window, GWL_EXSTYLE); - style |= WS_EX_TOOLWINDOW | WS_EX_TOPMOST; - SetWindowLongPtr(m_window, GWL_EXSTYLE, style); + // window should appear on top of everything, including (especially) + // the task bar. + LONG_PTR style = GetWindowLongPtr(m_window, GWL_EXSTYLE); + style |= WS_EX_TOOLWINDOW | WS_EX_TOPMOST; + SetWindowLongPtr(m_window, GWL_EXSTYLE, style); - // tell the task bar about this dialog - ArchTaskBarWindows::addDialog(m_window); + // tell the task bar about this dialog + ArchTaskBarWindows::addDialog(m_window); } -void -MSWindowsServerTaskBarReceiver::destroyWindow() -{ - if (m_window != NULL) { - ArchTaskBarWindows::removeDialog(m_window); - DestroyWindow(m_window); - m_window = NULL; - } +void MSWindowsServerTaskBarReceiver::destroyWindow() { + if (m_window != NULL) { + ArchTaskBarWindows::removeDialog(m_window); + DestroyWindow(m_window); + m_window = NULL; + } } -BOOL -MSWindowsServerTaskBarReceiver::dlgProc(HWND hwnd, - UINT msg, WPARAM wParam, LPARAM) -{ - switch (msg) { - case WM_INITDIALOG: - // use default focus - return TRUE; +BOOL MSWindowsServerTaskBarReceiver::dlgProc(HWND hwnd, UINT msg, WPARAM wParam, + LPARAM) { + switch (msg) { + case WM_INITDIALOG: + // use default focus + return TRUE; - case WM_ACTIVATE: - // hide when another window is activated - if (LOWORD(wParam) == WA_INACTIVE) { - ShowWindow(hwnd, SW_HIDE); - } - break; + case WM_ACTIVATE: + // hide when another window is activated + if (LOWORD(wParam) == WA_INACTIVE) { + ShowWindow(hwnd, SW_HIDE); } - return FALSE; + break; + } + return FALSE; } -BOOL CALLBACK -MSWindowsServerTaskBarReceiver::staticDlgProc(HWND hwnd, - UINT msg, WPARAM wParam, LPARAM lParam) -{ - // if msg is WM_INITDIALOG, extract the MSWindowsServerTaskBarReceiver* - // and put it in the extra window data then forward the call. - MSWindowsServerTaskBarReceiver* self = NULL; - if (msg == WM_INITDIALOG) { - self = static_cast( - reinterpret_cast(lParam)); - SetWindowLongPtr(hwnd, GWLP_USERDATA, lParam); - } - else { - // get the extra window data and forward the call - LONG_PTR data = GetWindowLongPtr(hwnd, GWLP_USERDATA); - if (data != 0) { - self = static_cast( - reinterpret_cast(data)); - } +BOOL CALLBACK MSWindowsServerTaskBarReceiver::staticDlgProc(HWND hwnd, UINT msg, + WPARAM wParam, + LPARAM lParam) { + // if msg is WM_INITDIALOG, extract the MSWindowsServerTaskBarReceiver* + // and put it in the extra window data then forward the call. + MSWindowsServerTaskBarReceiver *self = NULL; + if (msg == WM_INITDIALOG) { + self = static_cast( + reinterpret_cast(lParam)); + SetWindowLongPtr(hwnd, GWLP_USERDATA, lParam); + } else { + // get the extra window data and forward the call + LONG_PTR data = GetWindowLongPtr(hwnd, GWLP_USERDATA); + if (data != 0) { + self = static_cast( + reinterpret_cast(data)); } + } - // forward the message - if (self != NULL) { - return self->dlgProc(hwnd, msg, wParam, lParam); - } - else { - return (msg == WM_INITDIALOG) ? TRUE : FALSE; - } + // forward the message + if (self != NULL) { + return self->dlgProc(hwnd, msg, wParam, lParam); + } else { + return (msg == WM_INITDIALOG) ? TRUE : FALSE; + } } -IArchTaskBarReceiver* -createTaskBarReceiver(const BufferedLogOutputter* logBuffer, IEventQueue* events) -{ - ArchMiscWindows::setIcons( - (HICON)LoadImage(ArchMiscWindows::instanceWin32(), - MAKEINTRESOURCE(IDI_SYNERGY), - IMAGE_ICON, - 32, 32, LR_SHARED), - (HICON)LoadImage(ArchMiscWindows::instanceWin32(), - MAKEINTRESOURCE(IDI_SYNERGY), - IMAGE_ICON, - 16, 16, LR_SHARED)); +IArchTaskBarReceiver * +createTaskBarReceiver(const BufferedLogOutputter *logBuffer, + IEventQueue *events) { + ArchMiscWindows::setIcons((HICON)LoadImage(ArchMiscWindows::instanceWin32(), + MAKEINTRESOURCE(IDI_SYNERGY), + IMAGE_ICON, 32, 32, LR_SHARED), + (HICON)LoadImage(ArchMiscWindows::instanceWin32(), + MAKEINTRESOURCE(IDI_SYNERGY), + IMAGE_ICON, 16, 16, LR_SHARED)); - return new MSWindowsServerTaskBarReceiver( - MSWindowsScreen::getWindowInstance(), logBuffer, events); + return new MSWindowsServerTaskBarReceiver( + MSWindowsScreen::getWindowInstance(), logBuffer, events); } diff --git a/src/cmd/synergys/MSWindowsServerTaskBarReceiver.h b/src/cmd/synergys/MSWindowsServerTaskBarReceiver.h index 07f033663..8f9e9d309 100644 --- a/src/cmd/synergys/MSWindowsServerTaskBarReceiver.h +++ b/src/cmd/synergys/MSWindowsServerTaskBarReceiver.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2003 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 LICENSE 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 @@ -29,41 +29,40 @@ class IEventQueue; //! Implementation of ServerTaskBarReceiver for Microsoft Windows class MSWindowsServerTaskBarReceiver : public ServerTaskBarReceiver { public: - MSWindowsServerTaskBarReceiver(HINSTANCE, const BufferedLogOutputter*, IEventQueue* events); - virtual ~MSWindowsServerTaskBarReceiver(); + MSWindowsServerTaskBarReceiver(HINSTANCE, const BufferedLogOutputter *, + IEventQueue *events); + virtual ~MSWindowsServerTaskBarReceiver(); - // IArchTaskBarReceiver overrides - virtual void showStatus(); - virtual void runMenu(int x, int y); - virtual void primaryAction(); - virtual const Icon getIcon() const; - void cleanup(); + // IArchTaskBarReceiver overrides + virtual void showStatus(); + virtual void runMenu(int x, int y); + virtual void primaryAction(); + virtual const Icon getIcon() const; + void cleanup(); protected: - void copyLog() const; + void copyLog() const; - // ServerTaskBarReceiver overrides - virtual void onStatusChanged(); + // ServerTaskBarReceiver overrides + virtual void onStatusChanged(); private: - HICON loadIcon(UINT); - void deleteIcon(HICON); - void createWindow(); - void destroyWindow(); + HICON loadIcon(UINT); + void deleteIcon(HICON); + void createWindow(); + void destroyWindow(); - BOOL dlgProc(HWND hwnd, - UINT msg, WPARAM wParam, LPARAM lParam); - static BOOL CALLBACK - staticDlgProc(HWND hwnd, - UINT msg, WPARAM wParam, LPARAM lParam); + BOOL dlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); + static BOOL CALLBACK staticDlgProc(HWND hwnd, UINT msg, WPARAM wParam, + LPARAM lParam); private: - HINSTANCE m_appInstance; - HWND m_window; - HMENU m_menu; - HICON m_icon[kMaxState]; - const BufferedLogOutputter* m_logBuffer; - IEventQueue* m_events; + HINSTANCE m_appInstance; + HWND m_window; + HMENU m_menu; + HICON m_icon[kMaxState]; + const BufferedLogOutputter *m_logBuffer; + IEventQueue *m_events; - static const UINT s_stateToIconID[]; + static const UINT s_stateToIconID[]; }; diff --git a/src/cmd/synergys/OSXServerTaskBarReceiver.cpp b/src/cmd/synergys/OSXServerTaskBarReceiver.cpp index cd51c3f02..f16f695f7 100644 --- a/src/cmd/synergys/OSXServerTaskBarReceiver.cpp +++ b/src/cmd/synergys/OSXServerTaskBarReceiver.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 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 LICENSE 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 @@ -23,45 +23,35 @@ // OSXServerTaskBarReceiver // -OSXServerTaskBarReceiver::OSXServerTaskBarReceiver( - const BufferedLogOutputter*, IEventQueue* events) : - ServerTaskBarReceiver(events) -{ - // add ourself to the task bar - ARCH->addReceiver(this); +OSXServerTaskBarReceiver::OSXServerTaskBarReceiver(const BufferedLogOutputter *, + IEventQueue *events) + : ServerTaskBarReceiver(events) { + // add ourself to the task bar + ARCH->addReceiver(this); } -OSXServerTaskBarReceiver::~OSXServerTaskBarReceiver() -{ - ARCH->removeReceiver(this); +OSXServerTaskBarReceiver::~OSXServerTaskBarReceiver() { + ARCH->removeReceiver(this); } -void -OSXServerTaskBarReceiver::showStatus() -{ - // do nothing +void OSXServerTaskBarReceiver::showStatus() { + // do nothing } -void -OSXServerTaskBarReceiver::runMenu(int, int) -{ - // do nothing +void OSXServerTaskBarReceiver::runMenu(int, int) { + // do nothing } -void -OSXServerTaskBarReceiver::primaryAction() -{ - // do nothing +void OSXServerTaskBarReceiver::primaryAction() { + // do nothing } -const IArchTaskBarReceiver::Icon -OSXServerTaskBarReceiver::getIcon() const -{ - return NULL; +const IArchTaskBarReceiver::Icon OSXServerTaskBarReceiver::getIcon() const { + return NULL; } -IArchTaskBarReceiver* -createTaskBarReceiver(const BufferedLogOutputter* logBuffer, IEventQueue* events) -{ - return new OSXServerTaskBarReceiver(logBuffer, events); +IArchTaskBarReceiver * +createTaskBarReceiver(const BufferedLogOutputter *logBuffer, + IEventQueue *events) { + return new OSXServerTaskBarReceiver(logBuffer, events); } diff --git a/src/cmd/synergys/OSXServerTaskBarReceiver.h b/src/cmd/synergys/OSXServerTaskBarReceiver.h index c230ee53a..b95702d3c 100644 --- a/src/cmd/synergys/OSXServerTaskBarReceiver.h +++ b/src/cmd/synergys/OSXServerTaskBarReceiver.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 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 LICENSE 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 @@ -25,12 +25,12 @@ class BufferedLogOutputter; //! Implementation of ServerTaskBarReceiver for OS X class OSXServerTaskBarReceiver : public ServerTaskBarReceiver { public: - OSXServerTaskBarReceiver(const BufferedLogOutputter*, IEventQueue* events); - virtual ~OSXServerTaskBarReceiver(); + OSXServerTaskBarReceiver(const BufferedLogOutputter *, IEventQueue *events); + virtual ~OSXServerTaskBarReceiver(); - // IArchTaskBarReceiver overrides - virtual void showStatus(); - virtual void runMenu(int x, int y); - virtual void primaryAction(); - virtual const Icon getIcon() const; + // IArchTaskBarReceiver overrides + virtual void showStatus(); + virtual void runMenu(int x, int y); + virtual void primaryAction(); + virtual const Icon getIcon() const; }; diff --git a/src/cmd/synergys/XWindowsServerTaskBarReceiver.cpp b/src/cmd/synergys/XWindowsServerTaskBarReceiver.cpp index cdee1a282..d75cadc96 100644 --- a/src/cmd/synergys/XWindowsServerTaskBarReceiver.cpp +++ b/src/cmd/synergys/XWindowsServerTaskBarReceiver.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2003 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 LICENSE 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 @@ -24,44 +24,35 @@ // CXWindowsServerTaskBarReceiver::CXWindowsServerTaskBarReceiver( - const BufferedLogOutputter*, IEventQueue* events) : - ServerTaskBarReceiver(events) -{ - // add ourself to the task bar - ARCH->addReceiver(this); + const BufferedLogOutputter *, IEventQueue *events) + : ServerTaskBarReceiver(events) { + // add ourself to the task bar + ARCH->addReceiver(this); } -CXWindowsServerTaskBarReceiver::~CXWindowsServerTaskBarReceiver() -{ - ARCH->removeReceiver(this); +CXWindowsServerTaskBarReceiver::~CXWindowsServerTaskBarReceiver() { + ARCH->removeReceiver(this); } -void -CXWindowsServerTaskBarReceiver::showStatus() -{ - // do nothing +void CXWindowsServerTaskBarReceiver::showStatus() { + // do nothing } -void -CXWindowsServerTaskBarReceiver::runMenu(int, int) -{ - // do nothing +void CXWindowsServerTaskBarReceiver::runMenu(int, int) { + // do nothing } -void -CXWindowsServerTaskBarReceiver::primaryAction() -{ - // do nothing +void CXWindowsServerTaskBarReceiver::primaryAction() { + // do nothing } const IArchTaskBarReceiver::Icon -CXWindowsServerTaskBarReceiver::getIcon() const -{ - return NULL; +CXWindowsServerTaskBarReceiver::getIcon() const { + return NULL; } -IArchTaskBarReceiver* -createTaskBarReceiver(const BufferedLogOutputter* logBuffer, IEventQueue* events) -{ - return new CXWindowsServerTaskBarReceiver(logBuffer, events); +IArchTaskBarReceiver * +createTaskBarReceiver(const BufferedLogOutputter *logBuffer, + IEventQueue *events) { + return new CXWindowsServerTaskBarReceiver(logBuffer, events); } diff --git a/src/cmd/synergys/XWindowsServerTaskBarReceiver.h b/src/cmd/synergys/XWindowsServerTaskBarReceiver.h index dcfedf71c..be70475b3 100644 --- a/src/cmd/synergys/XWindowsServerTaskBarReceiver.h +++ b/src/cmd/synergys/XWindowsServerTaskBarReceiver.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2003 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 LICENSE 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 @@ -26,18 +26,21 @@ class IEventQueue; //! Implementation of ServerTaskBarReceiver for X Windows class CXWindowsServerTaskBarReceiver : public ServerTaskBarReceiver { public: - CXWindowsServerTaskBarReceiver( - const BufferedLogOutputter*, IEventQueue* events); - CXWindowsServerTaskBarReceiver(const CXWindowsServerTaskBarReceiver&) =delete; - CXWindowsServerTaskBarReceiver(CXWindowsServerTaskBarReceiver&&) =delete; - virtual ~CXWindowsServerTaskBarReceiver(); - - CXWindowsServerTaskBarReceiver& operator=(const CXWindowsServerTaskBarReceiver&) =delete; - CXWindowsServerTaskBarReceiver& operator=(const CXWindowsServerTaskBarReceiver&&) =delete; + CXWindowsServerTaskBarReceiver(const BufferedLogOutputter *, + IEventQueue *events); + CXWindowsServerTaskBarReceiver(const CXWindowsServerTaskBarReceiver &) = + delete; + CXWindowsServerTaskBarReceiver(CXWindowsServerTaskBarReceiver &&) = delete; + virtual ~CXWindowsServerTaskBarReceiver(); - // IArchTaskBarReceiver overrides - virtual void showStatus(); - virtual void runMenu(int x, int y); - virtual void primaryAction(); - virtual const Icon getIcon() const; + CXWindowsServerTaskBarReceiver & + operator=(const CXWindowsServerTaskBarReceiver &) = delete; + CXWindowsServerTaskBarReceiver & + operator=(const CXWindowsServerTaskBarReceiver &&) = delete; + + // IArchTaskBarReceiver overrides + virtual void showStatus(); + virtual void runMenu(int x, int y); + virtual void primaryAction(); + virtual const Icon getIcon() const; }; diff --git a/src/cmd/synergys/resource.h b/src/cmd/synergys/resource.h index 1cc1e8b99..2d098c7c1 100644 --- a/src/cmd/synergys/resource.h +++ b/src/cmd/synergys/resource.h @@ -2,41 +2,41 @@ // Microsoft Visual C++ generated include file. // Used by synergys.rc // -#define IDS_FAILED 1 -#define IDS_INIT_FAILED 2 -#define IDS_UNCAUGHT_EXCEPTION 3 -#define IDI_SYNERGY 101 -#define IDI_TASKBAR_NOT_RUNNING 102 -#define IDI_TASKBAR_NOT_WORKING 103 -#define IDI_TASKBAR_NOT_CONNECTED 104 -#define IDI_TASKBAR_CONNECTED 105 -#define IDR_TASKBAR 107 -#define IDD_TASKBAR_STATUS 108 -#define IDC_TASKBAR_STATUS_STATUS 1000 -#define IDC_TASKBAR_STATUS_CLIENTS 1001 -#define IDC_TASKBAR_QUIT 40003 -#define IDC_TASKBAR_STATUS 40004 -#define IDC_TASKBAR_LOG 40005 -#define IDC_RELOAD_CONFIG 40006 -#define IDC_FORCE_RECONNECT 40007 -#define IDC_TASKBAR_SHOW_LOG 40008 -#define IDC_TASKBAR_LOG_LEVEL_ERROR 40009 -#define IDC_TASKBAR_LOG_LEVEL_WARNING 40010 -#define IDC_TASKBAR_LOG_LEVEL_NOTE 40011 -#define IDC_TASKBAR_LOG_LEVEL_INFO 40012 -#define IDC_TASKBAR_LOG_LEVEL_DEBUG 40013 -#define IDC_TASKBAR_LOG_LEVEL_DEBUG1 40014 -#define IDC_TASKBAR_LOG_LEVEL_DEBUG2 40015 -#define ID_SYNERGY_RELOADSYSTEM 40016 -#define ID_SYNERGY_RESETSERVER 40017 +#define IDS_FAILED 1 +#define IDS_INIT_FAILED 2 +#define IDS_UNCAUGHT_EXCEPTION 3 +#define IDI_SYNERGY 101 +#define IDI_TASKBAR_NOT_RUNNING 102 +#define IDI_TASKBAR_NOT_WORKING 103 +#define IDI_TASKBAR_NOT_CONNECTED 104 +#define IDI_TASKBAR_CONNECTED 105 +#define IDR_TASKBAR 107 +#define IDD_TASKBAR_STATUS 108 +#define IDC_TASKBAR_STATUS_STATUS 1000 +#define IDC_TASKBAR_STATUS_CLIENTS 1001 +#define IDC_TASKBAR_QUIT 40003 +#define IDC_TASKBAR_STATUS 40004 +#define IDC_TASKBAR_LOG 40005 +#define IDC_RELOAD_CONFIG 40006 +#define IDC_FORCE_RECONNECT 40007 +#define IDC_TASKBAR_SHOW_LOG 40008 +#define IDC_TASKBAR_LOG_LEVEL_ERROR 40009 +#define IDC_TASKBAR_LOG_LEVEL_WARNING 40010 +#define IDC_TASKBAR_LOG_LEVEL_NOTE 40011 +#define IDC_TASKBAR_LOG_LEVEL_INFO 40012 +#define IDC_TASKBAR_LOG_LEVEL_DEBUG 40013 +#define IDC_TASKBAR_LOG_LEVEL_DEBUG1 40014 +#define IDC_TASKBAR_LOG_LEVEL_DEBUG2 40015 +#define ID_SYNERGY_RELOADSYSTEM 40016 +#define ID_SYNERGY_RESETSERVER 40017 // Next default values for new objects -// +// #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 109 -#define _APS_NEXT_COMMAND_VALUE 40018 -#define _APS_NEXT_CONTROL_VALUE 1003 -#define _APS_NEXT_SYMED_VALUE 101 +#define _APS_NEXT_RESOURCE_VALUE 109 +#define _APS_NEXT_COMMAND_VALUE 40018 +#define _APS_NEXT_CONTROL_VALUE 1003 +#define _APS_NEXT_SYMED_VALUE 101 #endif #endif diff --git a/src/cmd/synergys/synergys.cpp b/src/cmd/synergys/synergys.cpp index 1ec3fe4eb..65d67ced3 100644 --- a/src/cmd/synergys/synergys.cpp +++ b/src/cmd/synergys/synergys.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -16,10 +16,14 @@ * along with this program. If not, see . */ -#include "synergy/ServerApp.h" #include "arch/Arch.h" -#include "base/Log.h" #include "base/EventQueue.h" +#include "base/Log.h" +#include "synergy/ServerApp.h" + +#if SYSAPI_WIN32 +#include "arch/win32/ArchMiscWindows.h" +#endif #if WINAPI_MSWINDOWS #include "MSWindowsServerTaskBarReceiver.h" @@ -31,20 +35,18 @@ #error Platform not supported. #endif -int -main(int argc, char** argv) -{ +int main(int argc, char **argv) { #if SYSAPI_WIN32 - // record window instance for tray icon, etc - ArchMiscWindows::setInstanceWin32(GetModuleHandle(NULL)); + // record window instance for tray icon, etc + ArchMiscWindows::setInstanceWin32(GetModuleHandle(NULL)); #endif - - Arch arch; - arch.init(); - Log log; - EventQueue events; + Arch arch; + arch.init(); - ServerApp app(&events, createTaskBarReceiver); - return app.run(argc, argv); + Log log; + EventQueue events; + + ServerApp app(&events, createTaskBarReceiver); + return app.run(argc, argv); } diff --git a/src/cmd/syntool/syntool.cpp b/src/cmd/syntool/syntool.cpp index cf3d8e99b..d813c7ba2 100644 --- a/src/cmd/syntool/syntool.cpp +++ b/src/cmd/syntool/syntool.cpp @@ -1,11 +1,11 @@ /* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2014-2016 Symless Ltd. - * + * * 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 LICENSE 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 @@ -15,17 +15,19 @@ * along with this program. If not, see . */ -#include "synergy/ToolApp.h" #include "arch/Arch.h" +#include "synergy/ToolApp.h" -int -main(int argc, char** argv) -{ #if SYSAPI_WIN32 - // record window instance for tray icon, etc - ArchMiscWindows::setInstanceWin32(GetModuleHandle(NULL)); +#include "arch/win32/ArchMiscWindows.h" #endif - ToolApp app; - return app.run(argc, argv); +int main(int argc, char **argv) { +#if SYSAPI_WIN32 + // record window instance for tray icon, etc + ArchMiscWindows::setInstanceWin32(GetModuleHandle(NULL)); +#endif + + ToolApp app; + return app.run(argc, argv); } diff --git a/src/gui/src/AboutDialog.cpp b/src/gui/src/AboutDialog.cpp index d79b9a78d..b10b94399 100644 --- a/src/gui/src/AboutDialog.cpp +++ b/src/gui/src/AboutDialog.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2008 Volker Lanz (vl@fidra.de) - * + * * 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 LICENSE 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 @@ -16,72 +16,68 @@ * along with this program. If not, see . */ -#include "OSXHelpers.h" #include "AboutDialog.h" +#include "OSXHelpers.h" -AboutDialog::AboutDialog(MainWindow* parent, const AppConfig& config) : - QDialog(parent, Qt::WindowTitleHint | Qt::WindowSystemMenuHint), - Ui::AboutDialogBase() -{ - setupUi(this); +AboutDialog::AboutDialog(MainWindow *parent, const AppConfig &config) + : QDialog(parent, Qt::WindowTitleHint | Qt::WindowSystemMenuHint), + Ui::AboutDialogBase() { + setupUi(this); - m_versionChecker.setApp(parent->appPath(config.synergycName())); - m_pLabelSynergyVersion->setText(SYNERGY_VERSION); + m_versionChecker.setApp(parent->appPath(config.synergycName())); + m_pLabelSynergyVersion->setText(SYNERGY_VERSION); - QString buildDateString = QString::fromLocal8Bit(__DATE__).simplified(); - QDate buildDate = QLocale("en_US").toDate(buildDateString, "MMM d yyyy"); - m_pLabelBuildDate->setText(buildDate.toString(Qt::SystemLocaleLongDate)); + QString buildDateString = QString::fromLocal8Bit(__DATE__).simplified(); + QDate buildDate = QLocale("en_US").toDate(buildDateString, "MMM d yyyy"); + m_pLabelBuildDate->setText(buildDate.toString(Qt::SystemLocaleLongDate)); - textEliteBackers->hide(); - labelEliteBackers->hide(); - labelEliteBackerLink->hide(); - labelCreditsLink->hide(); + textEliteBackers->hide(); + labelEliteBackers->hide(); + labelEliteBackerLink->hide(); + labelCreditsLink->hide(); } -int AboutDialog::exec() -{ - //Sets the current build year into the copyright text - label_3->setText(getCopyrights() + getKeyContributors()); - resizeWindow(); - updateLogo(); +int AboutDialog::exec() { + // Sets the current build year into the copyright text + label_3->setText(getCopyrights() + getKeyContributors()); + resizeWindow(); + updateLogo(); - return QDialog::exec(); + return QDialog::exec(); } -void AboutDialog::resizeWindow() -{ - QSize size(600, 310); - setMaximumSize(size); - setMinimumSize(size); - resize(size); +void AboutDialog::resizeWindow() { + QSize size(600, 310); + setMaximumSize(size); + setMinimumSize(size); + resize(size); } -void AboutDialog::updateLogo() const -{ +void AboutDialog::updateLogo() const { #if defined(Q_OS_MAC) - if (isOSXInterfaceStyleDark()) { - QPixmap logo(":/res/image/about-dark.png"); - if (!logo.isNull()) { - label_Logo->setPixmap(logo); - } + if (isOSXInterfaceStyleDark()) { + QPixmap logo(":/res/image/about-dark.png"); + if (!logo.isNull()) { + label_Logo->setPixmap(logo); } + } #endif } -QString AboutDialog::getKeyContributors() const -{ - return QString(R"(

Key contributors
+QString AboutDialog::getKeyContributors() const { + return QString(R"(

Key contributors
Chris Schoeneman, Nick Bolton, Richard Lee, Adam Feder, Volker Lanz, Ryan Breen, Guido Poschta, Bertrand Landry Hetu, Tom Chadwick, Brent Priddy, Kyle Bloom, Daun Chung, Serhii Hadzhylov, Oleksandr Lysytsia, Olena Kutytska, Francisco Magalhães.

)"); } -QString AboutDialog::getCopyrights() const -{ - QString buildDateString = QString::fromLocal8Bit(__DATE__).simplified(); - QDate buildDate = QLocale("en_US").toDate(buildDateString, "MMM d yyyy"); +QString AboutDialog::getCopyrights() const { + QString buildDateString = QString::fromLocal8Bit(__DATE__).simplified(); + QDate buildDate = QLocale("en_US").toDate(buildDateString, "MMM d yyyy"); - QString copyrights(R"(

Keyboard and mouse sharing application.

Copyright © %%YEAR%% Symless Ltd.

)"); - return copyrights.replace(QString("%%YEAR%%"), QString::number(buildDate.year())); + QString copyrights( + R"(

Keyboard and mouse sharing application.

Copyright © %%YEAR%% Symless Ltd.

)"); + return copyrights.replace(QString("%%YEAR%%"), + QString::number(buildDate.year())); } diff --git a/src/gui/src/AboutDialog.h b/src/gui/src/AboutDialog.h index 951984061..348e29db3 100644 --- a/src/gui/src/AboutDialog.h +++ b/src/gui/src/AboutDialog.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2008 Volker Lanz (vl@fidra.de) - * + * * 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 LICENSE 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 @@ -20,9 +20,9 @@ #define ABOUTDIALOG__H -#include -#include "VersionChecker.h" #include "MainWindow.h" +#include "VersionChecker.h" +#include #include "ui_AboutDialogBase.h" @@ -30,18 +30,18 @@ class QWidget; class QString; class AboutDialog : public QDialog, public Ui::AboutDialogBase { - Q_OBJECT + Q_OBJECT public: - AboutDialog(MainWindow* parent, const AppConfig& config); - int exec() override; -private: - VersionChecker m_versionChecker; - void updateLogo() const; + AboutDialog(MainWindow *parent, const AppConfig &config); + int exec() override; - virtual void resizeWindow(); - virtual QString getCopyrights() const; - virtual QString getKeyContributors() const; +private: + VersionChecker m_versionChecker; + void updateLogo() const; + + virtual void resizeWindow(); + virtual QString getCopyrights() const; + virtual QString getKeyContributors() const; }; #endif - diff --git a/src/gui/src/AboutDialogEliteBackers.cpp b/src/gui/src/AboutDialogEliteBackers.cpp index f4fad9763..8f0494084 100644 --- a/src/gui/src/AboutDialogEliteBackers.cpp +++ b/src/gui/src/AboutDialogEliteBackers.cpp @@ -14,60 +14,59 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -#include "CreditsLoader.h" #include "AboutDialogEliteBackers.h" +#include "CreditsLoader.h" -AboutDialogEliteBackers::AboutDialogEliteBackers(MainWindow* parent, const AppConfig& config) : - AboutDialog(parent, config), - credits(*parent, config) -{ - setupCreditsLoader(); +AboutDialogEliteBackers::AboutDialogEliteBackers(MainWindow *parent, + const AppConfig &config) + : AboutDialog(parent, config), credits(*parent, config) { + setupCreditsLoader(); - textEliteBackers->show(); - labelEliteBackers->show(); - labelEliteBackerLink->show(); - labelCreditsLink->show(); + textEliteBackers->show(); + labelEliteBackers->show(); + labelEliteBackerLink->show(); + labelCreditsLink->show(); } -void AboutDialogEliteBackers::setupCreditsLoader() -{ - this->textEliteBackers->setText("Loading..."); - this->textEliteBackers->viewport()->setAutoFillBackground(false); - this->textEliteBackers->document()->setDocumentMargin(0); +void AboutDialogEliteBackers::setupCreditsLoader() { + this->textEliteBackers->setText("Loading..."); + this->textEliteBackers->viewport()->setAutoFillBackground(false); + this->textEliteBackers->document()->setDocumentMargin(0); - connect(&credits, SIGNAL(loaded(const QString&)), this, SLOT(updateEliteBackers(const QString&))); - credits.loadEliteBackers(); + connect(&credits, SIGNAL(loaded(const QString &)), this, + SLOT(updateEliteBackers(const QString &))); + credits.loadEliteBackers(); } -void AboutDialogEliteBackers::updateEliteBackers(const QString& eliteBackers) const -{ - this->textEliteBackers->setText(eliteBackers); +void AboutDialogEliteBackers::updateEliteBackers( + const QString &eliteBackers) const { + this->textEliteBackers->setText(eliteBackers); } -QString AboutDialogEliteBackers::getCopyrights() const -{ - QString buildDateString = QString::fromLocal8Bit(__DATE__).simplified(); - QDate buildDate = QLocale("en_US").toDate(buildDateString, "MMM d yyyy"); +QString AboutDialogEliteBackers::getCopyrights() const { + QString buildDateString = QString::fromLocal8Bit(__DATE__).simplified(); + QDate buildDate = QLocale("en_US").toDate(buildDateString, "MMM d yyyy"); - QString aboutText(R"(

Keyboard and mouse sharing application. Cross platform and open source since 2001.

+ QString aboutText( + R"(

Keyboard and mouse sharing application. Cross platform and open source since 2001.

Copyright © %%YEAR%% Symless Ltd.

Synergy is released under the GNU General Public License (GPLv2).

)"); - return aboutText.replace(QString("%%YEAR%%"), QString::number(buildDate.year())); + return aboutText.replace(QString("%%YEAR%%"), + QString::number(buildDate.year())); } -void AboutDialogEliteBackers::resizeWindow() -{ +void AboutDialogEliteBackers::resizeWindow() { // change default size based on os #if defined(Q_OS_MAC) - QSize size(600, 490); - setMaximumSize(size); - setMinimumSize(size); - resize(size); + QSize size(600, 490); + setMaximumSize(size); + setMinimumSize(size); + resize(size); #elif defined(Q_OS_LINUX) - QSize size(600, 420); - setMaximumSize(size); - setMinimumSize(size); - resize(size); + QSize size(600, 420); + setMaximumSize(size); + setMinimumSize(size); + resize(size); #endif } diff --git a/src/gui/src/AboutDialogEliteBackers.h b/src/gui/src/AboutDialogEliteBackers.h index 8344991d5..3ef7183d3 100644 --- a/src/gui/src/AboutDialogEliteBackers.h +++ b/src/gui/src/AboutDialogEliteBackers.h @@ -16,21 +16,21 @@ */ #pragma once -#include "CreditsLoader.h" #include "AboutDialog.h" +#include "CreditsLoader.h" class AboutDialogEliteBackers : public AboutDialog { - Q_OBJECT + Q_OBJECT public: - AboutDialogEliteBackers(MainWindow* parent, const AppConfig& config); + AboutDialogEliteBackers(MainWindow *parent, const AppConfig &config); public slots: - void updateEliteBackers(const QString& eliteBackers) const; + void updateEliteBackers(const QString &eliteBackers) const; private: - CreditsLoader credits; + CreditsLoader credits; - void setupCreditsLoader(); - void resizeWindow() override; - QString getCopyrights() const override; + void setupCreditsLoader(); + void resizeWindow() override; + QString getCopyrights() const override; }; diff --git a/src/gui/src/Action.cpp b/src/gui/src/Action.cpp index 84299fdd6..f697f8c33 100644 --- a/src/gui/src/Action.cpp +++ b/src/gui/src/Action.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2008 Volker Lanz (vl@fidra.de) - * + * * 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 LICENSE 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 @@ -21,148 +21,129 @@ #include #include -const char* Action::m_ActionTypeNames[] = -{ - "keyDown", "keyUp", "keystroke", - "switchToScreen", "switchInDirection", "lockCursorToScreen", "restartServer", - "mouseDown", "mouseUp", "mousebutton" -}; +const char *Action::m_ActionTypeNames[] = { + "keyDown", "keyUp", + "keystroke", "switchToScreen", + "switchInDirection", "lockCursorToScreen", + "restartServer", "mouseDown", + "mouseUp", "mousebutton"}; -const char* Action::m_SwitchDirectionNames[] = { "left", "right", "up", "down" }; -const char* Action::m_LockCursorModeNames[] = { "toggle", "on", "off" }; +const char *Action::m_SwitchDirectionNames[] = {"left", "right", "up", "down"}; +const char *Action::m_LockCursorModeNames[] = {"toggle", "on", "off"}; -Action::Action() : - m_KeySequence(), - m_Type(keystroke), - m_TypeScreenNames(), - m_SwitchScreenName(), - m_SwitchDirection(switchLeft), - m_LockCursorMode(lockCursorToggle), - m_ActiveOnRelease(false), - m_HasScreens(false) -{ -} +Action::Action() + : m_KeySequence(), m_Type(keystroke), m_TypeScreenNames(), + m_SwitchScreenName(), m_SwitchDirection(switchLeft), + m_LockCursorMode(lockCursorToggle), m_ActiveOnRelease(false), + m_HasScreens(false) {} -QString Action::text() const -{ - QString text = QString(m_ActionTypeNames[keySequence().isMouseButton() ? type() + 6 : type() ]) + "("; +QString Action::text() const { + QString text = + QString(m_ActionTypeNames[keySequence().isMouseButton() ? type() + 6 + : type()]) + + "("; - switch (type()) - { - case keyDown: - case keyUp: - case keystroke: - { - text += keySequence().toString(); + switch (type()) { + case keyDown: + case keyUp: + case keystroke: { + text += keySequence().toString(); - if (!keySequence().isMouseButton()) - { - const QStringList& screens = typeScreenNames(); - if (haveScreens() && !screens.isEmpty()) - { - text += ","; + if (!keySequence().isMouseButton()) { + const QStringList &screens = typeScreenNames(); + if (haveScreens() && !screens.isEmpty()) { + text += ","; - for (int i = 0; i < screens.size(); i++) - { - text += screens[i]; - if (i != screens.size() - 1) - text += ":"; - } - } - else - text += ",*"; - } - } - break; - - case switchToScreen: - text += switchScreenName(); - break; - - case switchInDirection: - text += m_SwitchDirectionNames[m_SwitchDirection]; - break; - - case lockCursorToScreen: - text += m_LockCursorModeNames[m_LockCursorMode]; - break; - - case restartAllConnections: - text += "restart"; - break; - default: - Q_ASSERT(0); - break; + for (int i = 0; i < screens.size(); i++) { + text += screens[i]; + if (i != screens.size() - 1) + text += ":"; + } + } else + text += ",*"; } + } break; - text += ")"; + case switchToScreen: + text += switchScreenName(); + break; - return text; + case switchInDirection: + text += m_SwitchDirectionNames[m_SwitchDirection]; + break; + + case lockCursorToScreen: + text += m_LockCursorModeNames[m_LockCursorMode]; + break; + + case restartAllConnections: + text += "restart"; + break; + default: + Q_ASSERT(0); + break; + } + + text += ")"; + + return text; } -void Action::loadSettings(QSettings& settings) -{ - keySequence().loadSettings(settings); - setType(settings.value("type", keyDown).toInt()); +void Action::loadSettings(QSettings &settings) { + keySequence().loadSettings(settings); + setType(settings.value("type", keyDown).toInt()); - typeScreenNames().clear(); - int numTypeScreens = settings.beginReadArray("typeScreenNames"); - for (int i = 0; i < numTypeScreens; i++) - { - settings.setArrayIndex(i); - typeScreenNames().append(settings.value("typeScreenName").toString()); - } - settings.endArray(); + typeScreenNames().clear(); + int numTypeScreens = settings.beginReadArray("typeScreenNames"); + for (int i = 0; i < numTypeScreens; i++) { + settings.setArrayIndex(i); + typeScreenNames().append(settings.value("typeScreenName").toString()); + } + settings.endArray(); - setSwitchScreenName(settings.value("switchScreenName").toString()); - setSwitchDirection(settings.value("switchInDirection", switchLeft).toInt()); - setLockCursorMode(settings.value("lockCursorToScreen", lockCursorToggle).toInt()); - setActiveOnRelease(settings.value("activeOnRelease", false).toBool()); - setHaveScreens(settings.value("hasScreens", false).toBool()); - setRestartServer(settings.value("restartServer", false).toBool()); + setSwitchScreenName(settings.value("switchScreenName").toString()); + setSwitchDirection(settings.value("switchInDirection", switchLeft).toInt()); + setLockCursorMode( + settings.value("lockCursorToScreen", lockCursorToggle).toInt()); + setActiveOnRelease(settings.value("activeOnRelease", false).toBool()); + setHaveScreens(settings.value("hasScreens", false).toBool()); + setRestartServer(settings.value("restartServer", false).toBool()); } -void Action::saveSettings(QSettings& settings) const -{ - keySequence().saveSettings(settings); - settings.setValue("type", type()); +void Action::saveSettings(QSettings &settings) const { + keySequence().saveSettings(settings); + settings.setValue("type", type()); - settings.beginWriteArray("typeScreenNames"); - for (int i = 0; i < typeScreenNames().size(); i++) - { - settings.setArrayIndex(i); - settings.setValue("typeScreenName", typeScreenNames()[i]); - } - settings.endArray(); + settings.beginWriteArray("typeScreenNames"); + for (int i = 0; i < typeScreenNames().size(); i++) { + settings.setArrayIndex(i); + settings.setValue("typeScreenName", typeScreenNames()[i]); + } + settings.endArray(); - settings.setValue("switchScreenName", switchScreenName()); - settings.setValue("switchInDirection", switchDirection()); - settings.setValue("lockCursorToScreen", lockCursorMode()); - settings.setValue("activeOnRelease", activeOnRelease()); - settings.setValue("hasScreens", haveScreens()); - settings.setValue("restartServer", restartServer()); + settings.setValue("switchScreenName", switchScreenName()); + settings.setValue("switchInDirection", switchDirection()); + settings.setValue("lockCursorToScreen", lockCursorMode()); + settings.setValue("activeOnRelease", activeOnRelease()); + settings.setValue("hasScreens", haveScreens()); + settings.setValue("restartServer", restartServer()); } -bool Action::operator==(const Action& a) const -{ - return m_KeySequence == a.m_KeySequence && - m_Type == a.m_Type && - m_TypeScreenNames == a.m_TypeScreenNames && - m_SwitchScreenName == a.m_SwitchScreenName && - m_SwitchDirection == a.m_SwitchDirection && - m_LockCursorMode == a.m_LockCursorMode && - m_ActiveOnRelease == a.m_ActiveOnRelease && - m_HasScreens == a.m_HasScreens && - m_restartServer == a.m_restartServer; +bool Action::operator==(const Action &a) const { + return m_KeySequence == a.m_KeySequence && m_Type == a.m_Type && + m_TypeScreenNames == a.m_TypeScreenNames && + m_SwitchScreenName == a.m_SwitchScreenName && + m_SwitchDirection == a.m_SwitchDirection && + m_LockCursorMode == a.m_LockCursorMode && + m_ActiveOnRelease == a.m_ActiveOnRelease && + m_HasScreens == a.m_HasScreens && m_restartServer == a.m_restartServer; } -QTextStream& operator<<(QTextStream& outStream, const Action& action) -{ - if (action.activeOnRelease()) - outStream << ";"; +QTextStream &operator<<(QTextStream &outStream, const Action &action) { + if (action.activeOnRelease()) + outStream << ";"; - outStream << action.text(); + outStream << action.text(); - return outStream; + return outStream; } - diff --git a/src/gui/src/Action.h b/src/gui/src/Action.h index 154f3c43b..3a6ef3369 100644 --- a/src/gui/src/Action.h +++ b/src/gui/src/Action.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2008 Volker Lanz (vl@fidra.de) - * + * * 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 LICENSE 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 @@ -22,93 +22,83 @@ #include "KeySequence.h" +#include #include #include -#include class ActionDialog; class QSettings; class QTextStream; -class Action -{ - friend class ActionDialog; - friend QTextStream& operator<<(QTextStream& outStream, const Action& action); +class Action { + friend class ActionDialog; + friend QTextStream &operator<<(QTextStream &outStream, const Action &action); - public: - enum ActionType { - keyDown, - keyUp, - keystroke, - switchToScreen, - switchInDirection, - lockCursorToScreen, - restartAllConnections, - mouseDown, - mouseUp, - mousebutton, - }; - enum SwitchDirection { - switchLeft, - switchRight, - switchUp, - switchDown - }; - enum LockCursorMode { - lockCursorToggle, - lockCursonOn, - lockCursorOff - }; +public: + enum ActionType { + keyDown, + keyUp, + keystroke, + switchToScreen, + switchInDirection, + lockCursorToScreen, + restartAllConnections, + mouseDown, + mouseUp, + mousebutton, + }; + enum SwitchDirection { switchLeft, switchRight, switchUp, switchDown }; + enum LockCursorMode { lockCursorToggle, lockCursonOn, lockCursorOff }; - public: - Action(); +public: + Action(); - public: - QString text() const; - const KeySequence& keySequence() const { return m_KeySequence; } - void loadSettings(QSettings& settings); - void saveSettings(QSettings& settings) const; - int type() const { return m_Type; } - const QStringList& typeScreenNames() const { return m_TypeScreenNames; } - const QString& switchScreenName() const { return m_SwitchScreenName; } - int switchDirection() const { return m_SwitchDirection; } - int lockCursorMode() const { return m_LockCursorMode; } - bool activeOnRelease() const { return m_ActiveOnRelease; } - bool haveScreens() const { return m_HasScreens; } - bool restartServer() const { return m_restartServer; } +public: + QString text() const; + const KeySequence &keySequence() const { return m_KeySequence; } + void loadSettings(QSettings &settings); + void saveSettings(QSettings &settings) const; + int type() const { return m_Type; } + const QStringList &typeScreenNames() const { return m_TypeScreenNames; } + const QString &switchScreenName() const { return m_SwitchScreenName; } + int switchDirection() const { return m_SwitchDirection; } + int lockCursorMode() const { return m_LockCursorMode; } + bool activeOnRelease() const { return m_ActiveOnRelease; } + bool haveScreens() const { return m_HasScreens; } + bool restartServer() const { return m_restartServer; } - bool operator==(const Action& a) const; + bool operator==(const Action &a) const; - protected: - KeySequence& keySequence() { return m_KeySequence; } - void setKeySequence(const KeySequence& seq) { m_KeySequence = seq; } - void setType(int t) { m_Type = t; } - QStringList& typeScreenNames() { return m_TypeScreenNames; } - void setSwitchScreenName(const QString& n) { m_SwitchScreenName = n; } - void setSwitchDirection(int d) { m_SwitchDirection = d; } - void setLockCursorMode(int m) { m_LockCursorMode = m; } - void setActiveOnRelease(bool b) { m_ActiveOnRelease = b; } - void setHaveScreens(bool b) { m_HasScreens = b; } - void setRestartServer( bool b) { m_restartServer = b; } +protected: + KeySequence &keySequence() { return m_KeySequence; } + void setKeySequence(const KeySequence &seq) { m_KeySequence = seq; } + void setType(int t) { m_Type = t; } + QStringList &typeScreenNames() { return m_TypeScreenNames; } + void setSwitchScreenName(const QString &n) { m_SwitchScreenName = n; } + void setSwitchDirection(int d) { m_SwitchDirection = d; } + void setLockCursorMode(int m) { m_LockCursorMode = m; } + void setActiveOnRelease(bool b) { m_ActiveOnRelease = b; } + void setHaveScreens(bool b) { m_HasScreens = b; } + void setRestartServer(bool b) { m_restartServer = b; } - private: - KeySequence m_KeySequence; - int m_Type; - QStringList m_TypeScreenNames; - QString m_SwitchScreenName; - int m_SwitchDirection; - int m_LockCursorMode; - bool m_ActiveOnRelease; - bool m_HasScreens; - bool m_restartServer; +private: + KeySequence m_KeySequence; + int m_Type; + QStringList m_TypeScreenNames; + QString m_SwitchScreenName; + int m_SwitchDirection; + int m_LockCursorMode; + bool m_ActiveOnRelease; + bool m_HasScreens; + bool m_restartServer; - static const char* m_ActionTypeNames[]; - static const char* m_SwitchDirectionNames[]; - static const char* m_LockCursorModeNames[]; + static const char *m_ActionTypeNames[]; + static const char *m_SwitchDirectionNames[]; + static const char *m_LockCursorModeNames[]; }; typedef QList ActionList; -QTextStream& operator<<(QTextStream& outStream, const Action& action); +QTextStream &operator<<(QTextStream &outStream, const Action &action); #endif diff --git a/src/gui/src/ActionDialog.cpp b/src/gui/src/ActionDialog.cpp index d8961a2cc..cf6569cc1 100644 --- a/src/gui/src/ActionDialog.cpp +++ b/src/gui/src/ActionDialog.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2008 Volker Lanz (vl@fidra.de) - * + * * 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 LICENSE 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 @@ -18,94 +18,93 @@ #include "ActionDialog.h" -#include "Hotkey.h" #include "Action.h" -#include "ServerConfig.h" +#include "Hotkey.h" #include "KeySequence.h" +#include "ServerConfig.h" +#include #include #include -#include -ActionDialog::ActionDialog(QWidget* parent, ServerConfig& config, Hotkey& hotkey, Action& action) : - QDialog(parent, Qt::WindowTitleHint | Qt::WindowSystemMenuHint), - Ui::ActionDialogBase(), - m_ServerConfig(config), - m_Hotkey(hotkey), - m_Action(action), - m_pButtonGroupType(new QButtonGroup(this)) -{ - setupUi(this); +ActionDialog::ActionDialog(QWidget *parent, ServerConfig &config, + Hotkey &hotkey, Action &action) + : QDialog(parent, Qt::WindowTitleHint | Qt::WindowSystemMenuHint), + Ui::ActionDialogBase(), m_ServerConfig(config), m_Hotkey(hotkey), + m_Action(action), m_pButtonGroupType(new QButtonGroup(this)) { + setupUi(this); - // work around Qt Designer's lack of a QButtonGroup; we need it to get - // at the button id of the checked radio button - QRadioButton* const typeButtons[] = { m_pRadioPress, m_pRadioRelease, m_pRadioPressAndRelease, m_pRadioSwitchToScreen, m_pRadioSwitchInDirection, m_pRadioLockCursorToScreen , m_pRadioRestartAllConnections}; + // work around Qt Designer's lack of a QButtonGroup; we need it to get + // at the button id of the checked radio button + QRadioButton *const typeButtons[] = {m_pRadioPress, + m_pRadioRelease, + m_pRadioPressAndRelease, + m_pRadioSwitchToScreen, + m_pRadioSwitchInDirection, + m_pRadioLockCursorToScreen, + m_pRadioRestartAllConnections}; - for (unsigned int i = 0; i < sizeof(typeButtons) / sizeof(typeButtons[0]); i++) - m_pButtonGroupType->addButton(typeButtons[i], i); + for (unsigned int i = 0; i < sizeof(typeButtons) / sizeof(typeButtons[0]); + i++) + m_pButtonGroupType->addButton(typeButtons[i], i); - m_pKeySequenceWidgetHotkey->setText(m_Action.keySequence().toString()); - m_pKeySequenceWidgetHotkey->setKeySequence(m_Action.keySequence()); - m_pButtonGroupType->button(m_Action.type())->setChecked(true); - m_pComboSwitchInDirection->setCurrentIndex(m_Action.switchDirection()); - m_pComboLockCursorToScreen->setCurrentIndex(m_Action.lockCursorMode()); + m_pKeySequenceWidgetHotkey->setText(m_Action.keySequence().toString()); + m_pKeySequenceWidgetHotkey->setKeySequence(m_Action.keySequence()); + m_pButtonGroupType->button(m_Action.type())->setChecked(true); + m_pComboSwitchInDirection->setCurrentIndex(m_Action.switchDirection()); + m_pComboLockCursorToScreen->setCurrentIndex(m_Action.lockCursorMode()); - if (m_Action.activeOnRelease()) - m_pRadioHotkeyReleased->setChecked(true); - else - m_pRadioHotkeyPressed->setChecked(true); + if (m_Action.activeOnRelease()) + m_pRadioHotkeyReleased->setChecked(true); + else + m_pRadioHotkeyPressed->setChecked(true); - m_pGroupBoxScreens->setChecked(m_Action.haveScreens()); + m_pGroupBoxScreens->setChecked(m_Action.haveScreens()); - int idx = 0; - foreach(const Screen& screen, serverConfig().screens()) - if (!screen.isNull()) - { - QListWidgetItem *pListItem = new QListWidgetItem(screen.name()); - m_pListScreens->addItem(pListItem); - if (m_Action.typeScreenNames().indexOf(screen.name()) != -1) - m_pListScreens->setCurrentItem(pListItem); + int idx = 0; + foreach (const Screen &screen, serverConfig().screens()) + if (!screen.isNull()) { + QListWidgetItem *pListItem = new QListWidgetItem(screen.name()); + m_pListScreens->addItem(pListItem); + if (m_Action.typeScreenNames().indexOf(screen.name()) != -1) + m_pListScreens->setCurrentItem(pListItem); - m_pComboSwitchToScreen->addItem(screen.name()); - if (screen.name() == m_Action.switchScreenName()) - m_pComboSwitchToScreen->setCurrentIndex(idx); + m_pComboSwitchToScreen->addItem(screen.name()); + if (screen.name() == m_Action.switchScreenName()) + m_pComboSwitchToScreen->setCurrentIndex(idx); - idx++; - } -} - -void ActionDialog::accept() -{ - if (!sequenceWidget()->valid() && m_pButtonGroupType->checkedId() >= 0 && m_pButtonGroupType->checkedId() < 3) - return; - - m_Action.setKeySequence(sequenceWidget()->keySequence()); - m_Action.setType(m_pButtonGroupType->checkedId()); - m_Action.setHaveScreens(m_pGroupBoxScreens->isChecked()); - - m_Action.typeScreenNames().clear(); - foreach(const QListWidgetItem* pItem, m_pListScreens->selectedItems()) - m_Action.typeScreenNames().append(pItem->text()); - - m_Action.setSwitchScreenName(m_pComboSwitchToScreen->currentText()); - m_Action.setSwitchDirection(m_pComboSwitchInDirection->currentIndex()); - m_Action.setLockCursorMode(m_pComboLockCursorToScreen->currentIndex()); - m_Action.setActiveOnRelease(m_pRadioHotkeyReleased->isChecked()); - m_Action.setRestartServer(m_pRadioRestartAllConnections->isChecked()); - - QDialog::accept(); -} - -void ActionDialog::on_m_pKeySequenceWidgetHotkey_keySequenceChanged() -{ - if (sequenceWidget()->keySequence().isMouseButton()) - { - m_pGroupBoxScreens->setEnabled(false); - m_pListScreens->setEnabled(false); - } - else - { - m_pGroupBoxScreens->setEnabled(true); - m_pListScreens->setEnabled(true); + idx++; } } + +void ActionDialog::accept() { + if (!sequenceWidget()->valid() && m_pButtonGroupType->checkedId() >= 0 && + m_pButtonGroupType->checkedId() < 3) + return; + + m_Action.setKeySequence(sequenceWidget()->keySequence()); + m_Action.setType(m_pButtonGroupType->checkedId()); + m_Action.setHaveScreens(m_pGroupBoxScreens->isChecked()); + + m_Action.typeScreenNames().clear(); + foreach (const QListWidgetItem *pItem, m_pListScreens->selectedItems()) + m_Action.typeScreenNames().append(pItem->text()); + + m_Action.setSwitchScreenName(m_pComboSwitchToScreen->currentText()); + m_Action.setSwitchDirection(m_pComboSwitchInDirection->currentIndex()); + m_Action.setLockCursorMode(m_pComboLockCursorToScreen->currentIndex()); + m_Action.setActiveOnRelease(m_pRadioHotkeyReleased->isChecked()); + m_Action.setRestartServer(m_pRadioRestartAllConnections->isChecked()); + + QDialog::accept(); +} + +void ActionDialog::on_m_pKeySequenceWidgetHotkey_keySequenceChanged() { + if (sequenceWidget()->keySequence().isMouseButton()) { + m_pGroupBoxScreens->setEnabled(false); + m_pListScreens->setEnabled(false); + } else { + m_pGroupBoxScreens->setEnabled(true); + m_pListScreens->setEnabled(true); + } +} diff --git a/src/gui/src/ActionDialog.h b/src/gui/src/ActionDialog.h index 34e4e8562..c5ae1acdd 100644 --- a/src/gui/src/ActionDialog.h +++ b/src/gui/src/ActionDialog.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2008 Volker Lanz (vl@fidra.de) - * + * * 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 LICENSE 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 @@ -30,27 +30,29 @@ class QRadioButton; class QButtonGroup; class ServerConfig; -class ActionDialog : public QDialog, public Ui::ActionDialogBase -{ - Q_OBJECT +class ActionDialog : public QDialog, public Ui::ActionDialogBase { + Q_OBJECT - public: - ActionDialog(QWidget* parent, ServerConfig& config, Hotkey& hotkey, Action& action); +public: + ActionDialog(QWidget *parent, ServerConfig &config, Hotkey &hotkey, + Action &action); - protected slots: - void accept(); - void on_m_pKeySequenceWidgetHotkey_keySequenceChanged(); +protected slots: + void accept(); + void on_m_pKeySequenceWidgetHotkey_keySequenceChanged(); - protected: - const KeySequenceWidget* sequenceWidget() const { return m_pKeySequenceWidgetHotkey; } - const ServerConfig& serverConfig() const { return m_ServerConfig; } +protected: + const KeySequenceWidget *sequenceWidget() const { + return m_pKeySequenceWidgetHotkey; + } + const ServerConfig &serverConfig() const { return m_ServerConfig; } - private: - const ServerConfig& m_ServerConfig; - Hotkey& m_Hotkey; - Action& m_Action; +private: + const ServerConfig &m_ServerConfig; + Hotkey &m_Hotkey; + Action &m_Action; - QButtonGroup* m_pButtonGroupType; + QButtonGroup *m_pButtonGroupType; }; #endif diff --git a/src/gui/src/ActivationDialog.cpp b/src/gui/src/ActivationDialog.cpp index f7e0d8a90..e07f9ae01 100644 --- a/src/gui/src/ActivationDialog.cpp +++ b/src/gui/src/ActivationDialog.cpp @@ -1,107 +1,102 @@ #include "ActivationDialog.h" -#include "ui_ActivationDialog.h" -#include "CancelActivationDialog.h" -#include "AppConfig.h" -#include #include "ActivationNotifier.h" +#include "AppConfig.h" +#include "CancelActivationDialog.h" +#include "FailedLoginDialog.h" +#include "LicenseManager.h" #include "MainWindow.h" #include "QUtility.h" -#include "LicenseManager.h" -#include "FailedLoginDialog.h" +#include "ui_ActivationDialog.h" +#include #include #include #include -ActivationDialog::ActivationDialog(QWidget* parent, AppConfig& appConfig, - LicenseManager& licenseManager) : - QDialog(parent), - ui(new Ui::ActivationDialog), - m_appConfig(&appConfig), - m_LicenseManager (&licenseManager) -{ - ui->setupUi(this); +ActivationDialog::ActivationDialog(QWidget *parent, AppConfig &appConfig, + LicenseManager &licenseManager) + : QDialog(parent), ui(new Ui::ActivationDialog), m_appConfig(&appConfig), + m_LicenseManager(&licenseManager) { + ui->setupUi(this); + refreshSerialKey(); + time_t currentTime = ::time(0); + if (!m_LicenseManager->serialKey().isExpired(currentTime)) { + ui->m_trialWidget->hide(); + } +} + +void ActivationDialog::refreshSerialKey() { + ui->m_pTextEditSerialKey->setText(m_appConfig->serialKey()); + ui->m_pTextEditSerialKey->setFocus(); + ui->m_pTextEditSerialKey->moveCursor(QTextCursor::End); + ui->m_trialLabel->setText( + tr(m_LicenseManager->getLicenseNotice().toStdString().c_str())); +} + +ActivationDialog::~ActivationDialog() { delete ui; } + +void ActivationDialog::reject() { + if (m_LicenseManager->activeEdition() == kUnregistered) { + CancelActivationDialog cancelActivationDialog(this); + if (QDialog::Accepted == cancelActivationDialog.exec()) { + m_LicenseManager->skipActivation(); + } else { + return; + } + } + QDialog::reject(); +} + +void ActivationDialog::accept() { + QMessageBox message; + m_appConfig->activationHasRun(true); + + try { + SerialKey serialKey( + ui->m_pTextEditSerialKey->toPlainText().trimmed().toStdString()); + m_LicenseManager->setSerialKey(serialKey); + } catch (std::exception &e) { + message.critical( + this, "Activation failed", + tr("An error occurred while trying to activate Synergy. " + "" + "Please contact the helpdesk, and provide the following " + "information:" + "

%1") + .arg(e.what())); refreshSerialKey(); - time_t currentTime = ::time(0); - if (!m_LicenseManager->serialKey().isExpired(currentTime)) { - ui->m_trialWidget->hide(); - } -} + return; + } -void ActivationDialog::refreshSerialKey() -{ - ui->m_pTextEditSerialKey->setText(m_appConfig->serialKey()); - ui->m_pTextEditSerialKey->setFocus(); - ui->m_pTextEditSerialKey->moveCursor(QTextCursor::End); - ui->m_trialLabel->setText(tr(m_LicenseManager->getLicenseNotice().toStdString().c_str())); -} + m_LicenseManager->notifyActivation("serial:" + m_appConfig->serialKey()); + Edition edition = m_LicenseManager->activeEdition(); + time_t daysLeft = m_LicenseManager->serialKey().daysLeft(::time(0)); + if (edition != kUnregistered) { + QString thanksMessage = tr("Thanks for trying %1! %5\n\n%2 day%3 of " + "your trial remain%4") + .arg(m_LicenseManager->getEditionName(edition)) + .arg(daysLeft) + .arg((daysLeft == 1) ? "" : "s") + .arg((daysLeft == 1) ? "s" : ""); -ActivationDialog::~ActivationDialog() -{ - delete ui; -} - -void ActivationDialog::reject() -{ - if (m_LicenseManager->activeEdition() == kUnregistered) { - CancelActivationDialog cancelActivationDialog(this); - if (QDialog::Accepted == cancelActivationDialog.exec()) { - m_LicenseManager->skipActivation(); - } else { - return; - } - } - QDialog::reject(); -} - -void ActivationDialog::accept() -{ - QMessageBox message; - m_appConfig->activationHasRun(true); - - try { - SerialKey serialKey (ui->m_pTextEditSerialKey->toPlainText(). - trimmed().toStdString()); - m_LicenseManager->setSerialKey(serialKey); - } - catch (std::exception& e) { - message.critical(this, "Activation failed", - tr("An error occurred while trying to activate Synergy. " - "" - "Please contact the helpdesk, and provide the following information:" - "

%1").arg(e.what())); - refreshSerialKey(); - return; - } - - m_LicenseManager->notifyActivation("serial:" + m_appConfig->serialKey()); - Edition edition = m_LicenseManager->activeEdition(); - time_t daysLeft = m_LicenseManager->serialKey().daysLeft(::time(0)); - if (edition != kUnregistered) { - QString thanksMessage = tr("Thanks for trying %1! %5\n\n%2 day%3 of " - "your trial remain%4"). - arg (m_LicenseManager->getEditionName(edition)). - arg (daysLeft). - arg ((daysLeft == 1) ? "" : "s"). - arg ((daysLeft == 1) ? "s" : ""); - - if (m_appConfig->isCryptoAvailable()) { - m_appConfig->generateCertificate(); - thanksMessage = thanksMessage.arg("If you're using SSL, " + if (m_appConfig->isCryptoAvailable()) { + m_appConfig->generateCertificate(); + thanksMessage = + thanksMessage.arg("If you're using SSL, " "remember to activate all of your devices."); - } else { - thanksMessage = thanksMessage.arg(""); - } - - if (m_LicenseManager->serialKey().isTrial()) { - message.information(this, "Thanks!", thanksMessage); - } - else { - message.information(this, "Activated!", - tr("Thanks for activating %1!").arg - (m_LicenseManager->getEditionName(edition))); - } + } else { + thanksMessage = thanksMessage.arg(""); } - QDialog::accept(); + if (m_LicenseManager->serialKey().isTrial()) { + message.information(this, "Thanks!", thanksMessage); + } else { + message.information(this, "Activated!", + tr("Thanks for activating %1!") + .arg(m_LicenseManager->getEditionName(edition))); + } + } + + QDialog::accept(); } diff --git a/src/gui/src/ActivationDialog.h b/src/gui/src/ActivationDialog.h index 0644bfc9f..ed623d5bc 100644 --- a/src/gui/src/ActivationDialog.h +++ b/src/gui/src/ActivationDialog.h @@ -1,8 +1,8 @@ #ifndef ACTIVATIONDIALOG_H #define ACTIVATIONDIALOG_H -#include #include +#include namespace Ui { class ActivationDialog; @@ -10,26 +10,25 @@ class ActivationDialog; class AppConfig; -class ActivationDialog : public QDialog -{ - Q_OBJECT +class ActivationDialog : public QDialog { + Q_OBJECT public: - ActivationDialog(QWidget *parent, AppConfig& appConfig, - LicenseManager& licenseManager); - ~ActivationDialog(); + ActivationDialog(QWidget *parent, AppConfig &appConfig, + LicenseManager &licenseManager); + ~ActivationDialog(); public slots: - void reject(); - void accept(); + void reject(); + void accept(); protected: - void refreshSerialKey(); + void refreshSerialKey(); private: - Ui::ActivationDialog *ui; - AppConfig* m_appConfig; - LicenseManager* m_LicenseManager; + Ui::ActivationDialog *ui; + AppConfig *m_appConfig; + LicenseManager *m_LicenseManager; }; #endif // ACTIVATIONDIALOG_H diff --git a/src/gui/src/ActivationNotifier.cpp b/src/gui/src/ActivationNotifier.cpp index d63c85053..a96514d74 100644 --- a/src/gui/src/ActivationNotifier.cpp +++ b/src/gui/src/ActivationNotifier.cpp @@ -19,31 +19,24 @@ #include "CoreInterface.h" -ActivationNotifier::ActivationNotifier(QObject *parent) : - QObject(parent) -{ +ActivationNotifier::ActivationNotifier(QObject *parent) : QObject(parent) {} + +void ActivationNotifier::setIdentity(QString identity) { + m_Identity = identity; } -void ActivationNotifier::setIdentity(QString identity) -{ - m_Identity = identity; +void ActivationNotifier::setUpdateInfo(QString const &fromVersion, + QString const &toVersion, + QString const &serialKey) { + m_fromVersion = fromVersion; + m_toVersion = toVersion; + m_serialKey = serialKey; } -void ActivationNotifier::setUpdateInfo(QString const& fromVersion, - QString const& toVersion, - QString const& serialKey) -{ - m_fromVersion = fromVersion; - m_toVersion = toVersion; - m_serialKey = serialKey; +void ActivationNotifier::notify() { + // TODO: use something other than CURL } -void ActivationNotifier::notify() -{ - // TODO: use something other than CURL -} - -void ActivationNotifier::notifyUpdate() -{ - // TODO: use something other than CURL +void ActivationNotifier::notifyUpdate() { + // TODO: use something other than CURL } diff --git a/src/gui/src/ActivationNotifier.h b/src/gui/src/ActivationNotifier.h index 36ac76f45..6a87f4447 100644 --- a/src/gui/src/ActivationNotifier.h +++ b/src/gui/src/ActivationNotifier.h @@ -20,28 +20,27 @@ #include -class ActivationNotifier : public QObject -{ -Q_OBJECT +class ActivationNotifier : public QObject { + Q_OBJECT public: - explicit ActivationNotifier(QObject *parent = 0); + explicit ActivationNotifier(QObject *parent = 0); - void setIdentity(QString identity); - void setUpdateInfo(QString const& fromVersion, - QString const& toVersion, QString const& serialKey); + void setIdentity(QString identity); + void setUpdateInfo(QString const &fromVersion, QString const &toVersion, + QString const &serialKey); public slots: - void notify(); - void notifyUpdate(); + void notify(); + void notifyUpdate(); signals: - void finished(); + void finished(); private: - QString m_Identity; - QString m_fromVersion; - QString m_toVersion; - QString m_serialKey; + QString m_Identity; + QString m_fromVersion; + QString m_toVersion; + QString m_serialKey; }; #endif // ACTIVATIONNOTIFIER_H diff --git a/src/gui/src/AddClientDialog.cpp b/src/gui/src/AddClientDialog.cpp index fd2f1d102..bd067c506 100644 --- a/src/gui/src/AddClientDialog.cpp +++ b/src/gui/src/AddClientDialog.cpp @@ -18,112 +18,103 @@ #include "AddClientDialog.h" #include "ui_AddClientDialogBase.h" -#include #include +#include -AddClientDialog::AddClientDialog(const QString& clientName, QWidget* parent) : - QDialog(parent, Qt::WindowTitleHint | Qt::WindowSystemMenuHint), - Ui::AddClientDialog(), - m_AddResult(kAddClientIgnore), - m_IgnoreAutoConfigClient(false) -{ - setupUi(this); +AddClientDialog::AddClientDialog(const QString &clientName, QWidget *parent) + : QDialog(parent, Qt::WindowTitleHint | Qt::WindowSystemMenuHint), + Ui::AddClientDialog(), m_AddResult(kAddClientIgnore), + m_IgnoreAutoConfigClient(false) { + setupUi(this); - m_pLabelHead->setText("A client wants to connect. " - "Please choose a location for " + clientName + "."); + m_pLabelHead->setText("A client wants to connect. " + "Please choose a location for " + + clientName + "."); - QIcon icon(":res/icons/64x64/video-display.png"); - QSize IconSize(32,32); + QIcon icon(":res/icons/64x64/video-display.png"); + QSize IconSize(32, 32); - m_pButtonLeft = new QPushButton(this); - m_pButtonLeft->setIcon(icon); - m_pButtonLeft->setIconSize(IconSize); - gridLayout->addWidget(m_pButtonLeft, 2, 0, 1, 1, Qt::AlignCenter); - connect(m_pButtonLeft, SIGNAL(clicked()), this, SLOT(handleButtonLeft())); + m_pButtonLeft = new QPushButton(this); + m_pButtonLeft->setIcon(icon); + m_pButtonLeft->setIconSize(IconSize); + gridLayout->addWidget(m_pButtonLeft, 2, 0, 1, 1, Qt::AlignCenter); + connect(m_pButtonLeft, SIGNAL(clicked()), this, SLOT(handleButtonLeft())); - m_pButtonUp = new QPushButton(this); - m_pButtonUp->setIcon(icon); - m_pButtonUp->setIconSize(IconSize); - gridLayout->addWidget(m_pButtonUp, 1, 1, 1, 1, Qt::AlignCenter); - connect(m_pButtonUp, SIGNAL(clicked()), this, SLOT(handleButtonUp())); + m_pButtonUp = new QPushButton(this); + m_pButtonUp->setIcon(icon); + m_pButtonUp->setIconSize(IconSize); + gridLayout->addWidget(m_pButtonUp, 1, 1, 1, 1, Qt::AlignCenter); + connect(m_pButtonUp, SIGNAL(clicked()), this, SLOT(handleButtonUp())); - m_pButtonRight = new QPushButton(this); - m_pButtonRight->setIcon(icon); - m_pButtonRight->setIconSize(IconSize); - gridLayout->addWidget(m_pButtonRight, 2, 2, 1, 1, Qt::AlignCenter); - connect(m_pButtonRight, SIGNAL(clicked()), this, SLOT(handleButtonRight())); + m_pButtonRight = new QPushButton(this); + m_pButtonRight->setIcon(icon); + m_pButtonRight->setIconSize(IconSize); + gridLayout->addWidget(m_pButtonRight, 2, 2, 1, 1, Qt::AlignCenter); + connect(m_pButtonRight, SIGNAL(clicked()), this, SLOT(handleButtonRight())); - m_pButtonDown = new QPushButton(this); - m_pButtonDown->setIcon(icon); - m_pButtonDown->setIconSize(IconSize); - gridLayout->addWidget(m_pButtonDown, 3, 1, 1, 1, Qt::AlignCenter); - connect(m_pButtonDown, SIGNAL(clicked()), this, SLOT(handleButtonDown())); + m_pButtonDown = new QPushButton(this); + m_pButtonDown->setIcon(icon); + m_pButtonDown->setIconSize(IconSize); + gridLayout->addWidget(m_pButtonDown, 3, 1, 1, 1, Qt::AlignCenter); + connect(m_pButtonDown, SIGNAL(clicked()), this, SLOT(handleButtonDown())); - m_pLabelCenter = new QLabel(this); - m_pLabelCenter->setPixmap(QPixmap(":res/icons/64x64/video-display.png")); - gridLayout->addWidget(m_pLabelCenter, 2, 1, 1, 1, Qt::AlignCenter); + m_pLabelCenter = new QLabel(this); + m_pLabelCenter->setPixmap(QPixmap(":res/icons/64x64/video-display.png")); + gridLayout->addWidget(m_pLabelCenter, 2, 1, 1, 1, Qt::AlignCenter); #if defined(Q_OS_MAC) - m_pDialogButtonBox->setLayoutDirection(Qt::RightToLeft); + m_pDialogButtonBox->setLayoutDirection(Qt::RightToLeft); #endif - QPushButton* advanced = m_pDialogButtonBox->addButton("Advanced", - QDialogButtonBox::HelpRole); - connect(advanced, SIGNAL(clicked()), this, SLOT(handleButtonAdvanced())); + QPushButton *advanced = + m_pDialogButtonBox->addButton("Advanced", QDialogButtonBox::HelpRole); + connect(advanced, SIGNAL(clicked()), this, SLOT(handleButtonAdvanced())); } -AddClientDialog::~AddClientDialog() -{ - delete m_pButtonUp; - delete m_pButtonDown; - delete m_pButtonLeft; - delete m_pButtonRight; - delete m_pLabelCenter; +AddClientDialog::~AddClientDialog() { + delete m_pButtonUp; + delete m_pButtonDown; + delete m_pButtonLeft; + delete m_pButtonRight; + delete m_pLabelCenter; } -void AddClientDialog::changeEvent(QEvent *e) -{ - QDialog::changeEvent(e); - switch (e->type()) { - case QEvent::LanguageChange: - retranslateUi(this); - break; - default: - break; - } +void AddClientDialog::changeEvent(QEvent *e) { + QDialog::changeEvent(e); + switch (e->type()) { + case QEvent::LanguageChange: + retranslateUi(this); + break; + default: + break; + } } -void AddClientDialog::handleButtonLeft() -{ - m_AddResult = kAddClientLeft; - close(); +void AddClientDialog::handleButtonLeft() { + m_AddResult = kAddClientLeft; + close(); } -void AddClientDialog::handleButtonUp() -{ - m_AddResult = kAddClientUp; - close(); +void AddClientDialog::handleButtonUp() { + m_AddResult = kAddClientUp; + close(); } -void AddClientDialog::handleButtonRight() -{ - m_AddResult = kAddClientRight; - close(); +void AddClientDialog::handleButtonRight() { + m_AddResult = kAddClientRight; + close(); } -void AddClientDialog::handleButtonDown() -{ - m_AddResult = kAddClientDown; - close(); +void AddClientDialog::handleButtonDown() { + m_AddResult = kAddClientDown; + close(); } -void AddClientDialog::handleButtonAdvanced() -{ - m_AddResult = kAddClientOther; - close(); +void AddClientDialog::handleButtonAdvanced() { + m_AddResult = kAddClientOther; + close(); } -void AddClientDialog::on_m_pCheckBoxIgnoreClient_toggled(bool checked) -{ - m_IgnoreAutoConfigClient = checked; +void AddClientDialog::on_m_pCheckBoxIgnoreClient_toggled(bool checked) { + m_IgnoreAutoConfigClient = checked; } diff --git a/src/gui/src/AddClientDialog.h b/src/gui/src/AddClientDialog.h index 0563ddc73..95043dfb8 100644 --- a/src/gui/src/AddClientDialog.h +++ b/src/gui/src/AddClientDialog.h @@ -26,43 +26,42 @@ class QPushButton; class QLabel; enum { - kAddClientRight, - kAddClientLeft, - kAddClientUp, - kAddClientDown, - kAddClientOther, - kAddClientIgnore + kAddClientRight, + kAddClientLeft, + kAddClientUp, + kAddClientDown, + kAddClientOther, + kAddClientIgnore }; -class AddClientDialog : public QDialog, public Ui::AddClientDialog -{ - Q_OBJECT +class AddClientDialog : public QDialog, public Ui::AddClientDialog { + Q_OBJECT public: - AddClientDialog(const QString& clientName, QWidget* parent = 0); - ~AddClientDialog(); + AddClientDialog(const QString &clientName, QWidget *parent = 0); + ~AddClientDialog(); - int addResult() { return m_AddResult; } - bool ignoreAutoConfigClient() { return m_IgnoreAutoConfigClient; } + int addResult() { return m_AddResult; } + bool ignoreAutoConfigClient() { return m_IgnoreAutoConfigClient; } protected: - void changeEvent(QEvent *e); + void changeEvent(QEvent *e); private slots: - void on_m_pCheckBoxIgnoreClient_toggled(bool checked); - void handleButtonLeft(); - void handleButtonUp(); - void handleButtonRight(); - void handleButtonDown(); - void handleButtonAdvanced(); + void on_m_pCheckBoxIgnoreClient_toggled(bool checked); + void handleButtonLeft(); + void handleButtonUp(); + void handleButtonRight(); + void handleButtonDown(); + void handleButtonAdvanced(); private: - QPushButton* m_pButtonLeft; - QPushButton* m_pButtonUp; - QPushButton* m_pButtonRight; - QPushButton* m_pButtonDown; - QLabel* m_pLabelCenter; - int m_AddResult; - bool m_IgnoreAutoConfigClient; + QPushButton *m_pButtonLeft; + QPushButton *m_pButtonUp; + QPushButton *m_pButtonRight; + QPushButton *m_pButtonDown; + QLabel *m_pLabelCenter; + int m_AddResult; + bool m_IgnoreAutoConfigClient; }; #endif // ADDCLIENTDIALOG_H diff --git a/src/gui/src/AppConfig.cpp b/src/gui/src/AppConfig.cpp index f663ce8f2..14d70cd91 100644 --- a/src/gui/src/AppConfig.cpp +++ b/src/gui/src/AppConfig.cpp @@ -16,14 +16,14 @@ * along with this program. If not, see . */ -#include "QSynergyApplication.h" #include "AppConfig.h" +#include "QSynergyApplication.h" #include "QUtility.h" +#include #include #include #include -#include #include "ConfigWriter.h" #include "SslCertificate.h" @@ -45,97 +45,77 @@ const char AppConfig::synergyConfigName[] = "synergy.conf"; const ElevateMode defaultElevateMode = ElevateAsNeeded; -const char* AppConfig::m_SynergySettingsName[] = { - "screenName", - "port", - "interface", - "logLevel2", - "logToFile", - "logFilename", - "wizardLastRun", - "language", - "startedBefore", - "autoConfig", - "autoConfigServer", - "elevateMode", - "elevateModeEnum", - "edition", - "cryptoEnabled", - "autoHide", - "serialKey", - "lastVersion", - "lastExpiringWarningTime", - "activationHasRun", - "minimizeToTray", - "ActivateEmail", - "loadFromSystemScope", - "groupServerChecked", - "useExternalConfig", - "configFile", - "useInternalConfig", - "groupClientChecked", - "serverHostname", - "tlsCertPath", - "tlsKeyLength", - "preventSleep", - "languageSync", - "invertScrollDirection", - "eliteBackersUrl", - "guid", - "licenseRegistryUrl", - "licenseNextCheck", - "initiateConnectionFromServer", - "clientHostMode", - "serverClientMode" -}; +const char *AppConfig::m_SynergySettingsName[] = { + "screenName", + "port", + "interface", + "logLevel2", + "logToFile", + "logFilename", + "wizardLastRun", + "language", + "startedBefore", + "autoConfig", + "autoConfigServer", + "elevateMode", + "elevateModeEnum", + "edition", + "cryptoEnabled", + "autoHide", + "serialKey", + "lastVersion", + "lastExpiringWarningTime", + "activationHasRun", + "minimizeToTray", + "ActivateEmail", + "loadFromSystemScope", + "groupServerChecked", + "useExternalConfig", + "configFile", + "useInternalConfig", + "groupClientChecked", + "serverHostname", + "tlsCertPath", + "tlsKeyLength", + "preventSleep", + "languageSync", + "invertScrollDirection", + "eliteBackersUrl", + "guid", + "licenseRegistryUrl", + "licenseNextCheck", + "initiateConnectionFromServer", + "clientHostMode", + "serverClientMode"}; -static const char* logLevelNames[] = -{ - "INFO", - "DEBUG", - "DEBUG1", - "DEBUG2" -}; +static const char *logLevelNames[] = {"INFO", "DEBUG", "DEBUG1", "DEBUG2"}; -AppConfig::AppConfig() : - m_ScreenName(), - m_Port(24800), - m_Interface(), - m_LogLevel(0), - m_LogToFile(), - m_WizardLastRun(0), - m_ProcessMode(DEFAULT_PROCESS_MODE), - m_StartedBefore(), - m_AutoConfig(true), - m_AutoConfigServer(), - m_ElevateMode(defaultElevateMode), - m_Edition(kUnregistered), - m_CryptoEnabled(false), - m_AutoHide(false), - m_LastExpiringWarningTime(0), - m_ActivationHasRun(), - m_MinimizeToTray(false), - m_ServerGroupChecked(), - m_UseExternalConfig(), - m_UseInternalConfig(), - m_ClientGroupChecked(), - m_LoadFromSystemScope() -{ +AppConfig::AppConfig() + : m_ScreenName(), m_Port(24800), m_Interface(), m_LogLevel(0), + m_LogToFile(), m_WizardLastRun(0), m_ProcessMode(DEFAULT_PROCESS_MODE), + m_StartedBefore(), m_AutoConfig(true), m_AutoConfigServer(), + m_ElevateMode(defaultElevateMode), m_Edition(kUnregistered), + m_CryptoEnabled(false), m_AutoHide(false), m_LastExpiringWarningTime(0), + m_ActivationHasRun(), m_MinimizeToTray(false), m_ServerGroupChecked(), + m_UseExternalConfig(), m_UseInternalConfig(), m_ClientGroupChecked(), + m_LoadFromSystemScope() { - auto writer = ConfigWriter::make(); + auto writer = ConfigWriter::make(); - //Register this class to receive global load and saves - writer->registerClass(this); - writer->globalLoad(); + // Register this class to receive global load and saves + writer->registerClass(this); + writer->globalLoad(); - //User settings exist and the load from system scope variable is true - if (writer->hasSetting(settingName(kLoadSystemSettings), ConfigWriter::kUser)) { - setLoadFromSystemScope(m_LoadFromSystemScope); - } - //If user setting don't exist but system ones do, load the system settings - else if (writer->hasSetting(settingName(kScreenName), ConfigWriter::kSystem)) { - setLoadFromSystemScope(true); - } + // User settings exist and the load from system scope variable is true + if (writer->hasSetting(settingName(kLoadSystemSettings), + ConfigWriter::kUser)) { + setLoadFromSystemScope(m_LoadFromSystemScope); + } + // If user setting don't exist but system ones do, load the system settings + else if (writer->hasSetting(settingName(kScreenName), + ConfigWriter::kSystem)) { + setLoadFromSystemScope(true); + } } const QString &AppConfig::screenName() const { return m_ScreenName; } @@ -150,47 +130,41 @@ bool AppConfig::logToFile() const { return m_LogToFile; } const QString &AppConfig::logFilename() const { return m_LogFilename; } -QString AppConfig::synergyLogDir() const -{ - // by default log to home dir - return QDir::home().absolutePath() + "/"; +QString AppConfig::synergyLogDir() const { + // by default log to home dir + return QDir::home().absolutePath() + "/"; } -QString AppConfig::synergyProgramDir() const -{ - // synergy binaries should be in the same dir. - return QCoreApplication::applicationDirPath() + "/"; +QString AppConfig::synergyProgramDir() const { + // synergy binaries should be in the same dir. + return QCoreApplication::applicationDirPath() + "/"; } -void AppConfig::persistLogDir() -{ - QDir dir = synergyLogDir(); +void AppConfig::persistLogDir() { + QDir dir = synergyLogDir(); - // persist the log directory - if (!dir.exists()) - { - dir.mkpath(dir.path()); - } + // persist the log directory + if (!dir.exists()) { + dir.mkpath(dir.path()); + } } -const QString AppConfig::logFilenameCmd() const -{ - QString filename = m_LogFilename; +const QString AppConfig::logFilenameCmd() const { + QString filename = m_LogFilename; #if defined(Q_OS_WIN) - // wrap in quotes in case username contains spaces. - filename = QString("\"%1\"").arg(filename); + // wrap in quotes in case username contains spaces. + filename = QString("\"%1\"").arg(filename); #endif - return filename; + return filename; } -QString AppConfig::logLevelText() const -{ - return logLevelNames[logLevel()]; -} +QString AppConfig::logLevelText() const { return logLevelNames[logLevel()]; } ProcessMode AppConfig::processMode() const { return m_ProcessMode; } -bool AppConfig::wizardShouldRun() const { return m_WizardLastRun < kWizardVersion; } +bool AppConfig::wizardShouldRun() const { + return m_WizardLastRun < kWizardVersion; +} const QString &AppConfig::language() const { return m_Language; } @@ -198,239 +172,235 @@ bool AppConfig::startedBefore() const { return m_StartedBefore; } bool AppConfig::autoConfig() const { #if !defined(SYNERGY_ENTERPRISE) && defined(SYNERGY_AUTOCONFIG) - return m_AutoConfig; + return m_AutoConfig; #else - // always disable auto config for enterprise edition. - return false; + // always disable auto config for enterprise edition. + return false; #endif } QString AppConfig::autoConfigServer() const { return m_AutoConfigServer; } -void AppConfig::loadSettings() -{ - m_ScreenName = loadSetting(kScreenName, QHostInfo::localHostName()).toString(); - if (m_ScreenName.isEmpty()) { - m_ScreenName = QHostInfo::localHostName(); +void AppConfig::loadSettings() { + m_ScreenName = + loadSetting(kScreenName, QHostInfo::localHostName()).toString(); + if (m_ScreenName.isEmpty()) { + m_ScreenName = QHostInfo::localHostName(); + } + + m_Port = loadSetting(kPort, 24800).toInt(); + m_Interface = loadSetting(kInterfaceSetting).toString(); + m_LogLevel = loadSetting(kLogLevel, 0).toInt(); + m_LogToFile = loadSetting(kLogToFile, false).toBool(); + m_LogFilename = + loadSetting(kLogFilename, synergyLogDir() + "synergy.log").toString(); + m_WizardLastRun = loadCommonSetting(kWizardLastRun, 0).toInt(); + m_Language = loadSetting(kLanguage, QLocale::system().name()).toString(); + m_StartedBefore = loadSetting(kStartedBefore, false).toBool(); + m_AutoConfig = loadSetting(kAutoConfig, false).toBool(); + m_AutoConfigServer = loadSetting(kAutoConfigServer, "").toString(); + + { // Scope related code together + // TODO Investigate why kElevateModeEnum isn't loaded fully + QVariant elevateMode = loadSetting(kElevateModeEnum); + if (!elevateMode.isValid()) { + elevateMode = loadSetting(kElevateModeSetting, + QVariant(static_cast(defaultElevateMode))); } + m_ElevateMode = static_cast(elevateMode.toInt()); + } - m_Port = loadSetting(kPort, 24800).toInt(); - m_Interface = loadSetting(kInterfaceSetting).toString(); - m_LogLevel = loadSetting(kLogLevel, 0).toInt(); - m_LogToFile = loadSetting(kLogToFile, false).toBool(); - m_LogFilename = loadSetting(kLogFilename, synergyLogDir() + "synergy.log").toString(); - m_WizardLastRun = loadCommonSetting(kWizardLastRun, 0).toInt(); - m_Language = loadSetting(kLanguage, QLocale::system().name()).toString(); - m_StartedBefore = loadSetting(kStartedBefore, false).toBool(); - m_AutoConfig = loadSetting(kAutoConfig, false).toBool(); - m_AutoConfigServer = loadSetting(kAutoConfigServer, "").toString(); + m_ActivateEmail = loadSetting(kActivateEmail, "").toString(); + m_CryptoEnabled = loadSetting(kCryptoEnabled, true).toBool(); + m_AutoHide = loadSetting(kAutoHide, false).toBool(); + m_lastVersion = loadSetting(kLastVersion, "Unknown").toString(); + m_LastExpiringWarningTime = loadSetting(kLastExpireWarningTime, 0).toInt(); + m_ActivationHasRun = loadSetting(kActivationHasRun, false).toBool(); + m_MinimizeToTray = loadSetting(kMinimizeToTray, false).toBool(); + m_LoadFromSystemScope = + loadCommonSetting(kLoadSystemSettings, false).toBool(); + m_ServerGroupChecked = loadSetting(kGroupServerCheck, false).toBool(); + m_UseExternalConfig = loadSetting(kUseExternalConfig, false).toBool(); + m_ConfigFile = + loadSetting(kConfigFile, QDir::homePath() + "/" + synergyConfigName) + .toString(); + m_UseInternalConfig = loadSetting(kUseInternalConfig, false).toBool(); + m_ClientGroupChecked = loadSetting(kGroupClientCheck, false).toBool(); + m_ServerHostname = loadSetting(kServerHostname).toString(); + m_PreventSleep = loadSetting(kPreventSleep, false).toBool(); + m_LanguageSync = loadSetting(kLanguageSync, false).toBool(); + m_InvertScrollDirection = loadSetting(kInvertScrollDirection, false).toBool(); + m_eliteBackersUrl = + loadCommonSetting(kEliteBackersUrl, + "https://api2.prod.symless.com/credits/elite-backers") + .toString(); + m_guid = loadCommonSetting(kGuid, QUuid::createUuid()).toString(); + m_licenseRegistryUrl = + loadCommonSetting(kLicenseRegistryUrl, + "https://api2.prod.symless.com/license/register") + .toString(); + m_licenseNextCheck = loadCommonSetting(kLicenseNextCheck, 0).toULongLong(); + m_ClientHostMode = loadSetting(kClientHostMode, true).toBool(); + m_ServerClientMode = loadSetting(kServerClientMode, true).toBool(); + m_InitiateConnectionFromServer = + loadSetting(kInitiateConnectionFromServer, false).toBool(); - { //Scope related code together - // TODO Investigate why kElevateModeEnum isn't loaded fully - QVariant elevateMode = loadSetting(kElevateModeEnum); - if (!elevateMode.isValid()) { - elevateMode = loadSetting(kElevateModeSetting, - QVariant(static_cast(defaultElevateMode))); - } - m_ElevateMode = static_cast(elevateMode.toInt()); - } + // only change the serial key if the settings being loaded contains a key + bool updateSerial = ConfigWriter::make()->hasSetting( + settingName(kLoadSystemSettings), ConfigWriter::kCurrent); + // if the setting exists and is not empty + updateSerial = updateSerial && + !loadSetting(kSerialKey, "").toString().trimmed().isEmpty(); - m_ActivateEmail = loadSetting(kActivateEmail, "").toString(); - m_CryptoEnabled = loadSetting(kCryptoEnabled, true).toBool(); - m_AutoHide = loadSetting(kAutoHide, false).toBool(); - m_lastVersion = loadSetting(kLastVersion, "Unknown").toString(); - m_LastExpiringWarningTime = loadSetting(kLastExpireWarningTime, 0).toInt(); - m_ActivationHasRun = loadSetting(kActivationHasRun, false).toBool(); - m_MinimizeToTray = loadSetting(kMinimizeToTray, false).toBool(); - m_LoadFromSystemScope = loadCommonSetting(kLoadSystemSettings, false).toBool(); - m_ServerGroupChecked = loadSetting(kGroupServerCheck, false).toBool(); - m_UseExternalConfig = loadSetting(kUseExternalConfig, false).toBool(); - m_ConfigFile = loadSetting(kConfigFile, QDir::homePath() + "/" + synergyConfigName).toString(); - m_UseInternalConfig = loadSetting(kUseInternalConfig, false).toBool(); - m_ClientGroupChecked = loadSetting(kGroupClientCheck, false).toBool(); - m_ServerHostname = loadSetting(kServerHostname).toString(); - m_PreventSleep = loadSetting(kPreventSleep, false).toBool(); - m_LanguageSync = loadSetting(kLanguageSync, false).toBool(); - m_InvertScrollDirection = loadSetting(kInvertScrollDirection, false).toBool(); - m_eliteBackersUrl = loadCommonSetting(kEliteBackersUrl, "https://api2.prod.symless.com/credits/elite-backers").toString(); - m_guid = loadCommonSetting(kGuid, QUuid::createUuid()).toString(); - m_licenseRegistryUrl = loadCommonSetting(kLicenseRegistryUrl, "https://api2.prod.symless.com/license/register").toString(); - m_licenseNextCheck = loadCommonSetting(kLicenseNextCheck, 0).toULongLong(); - m_ClientHostMode = loadSetting(kClientHostMode, true).toBool(); - m_ServerClientMode = loadSetting(kServerClientMode, true).toBool(); - m_InitiateConnectionFromServer = loadSetting(kInitiateConnectionFromServer, false).toBool(); + if (updateSerial) { + m_Serialkey = loadSetting(kSerialKey, "").toString().trimmed(); + m_Edition = static_cast( + loadSetting(kEditionSetting, kUnregistered).toInt()); + } - //only change the serial key if the settings being loaded contains a key - bool updateSerial = ConfigWriter::make() - ->hasSetting(settingName(kLoadSystemSettings),ConfigWriter::kCurrent); - //if the setting exists and is not empty - updateSerial = updateSerial && !loadSetting(kSerialKey, "").toString().trimmed().isEmpty(); + // Set the default path of the TLS certificate file in the users DIR + QString certificateFilename = + QString("%1/%2/%3") + .arg(m_CoreInterface.getProfileDir(), "SSL", "Synergy.pem"); - if (updateSerial) { - m_Serialkey = loadSetting(kSerialKey, "").toString().trimmed(); - m_Edition = static_cast(loadSetting(kEditionSetting, kUnregistered).toInt()); - } - - //Set the default path of the TLS certificate file in the users DIR - QString certificateFilename = QString("%1/%2/%3").arg(m_CoreInterface.getProfileDir(), - "SSL", - "Synergy.pem"); - - m_TLSCertificatePath = loadSetting(kTLSCertPath, certificateFilename).toString(); - m_TLSKeyLength = loadSetting(kTLSKeyLength, "2048").toString(); - - if (getCryptoEnabled()) { - generateCertificate(); - } + m_TLSCertificatePath = + loadSetting(kTLSCertPath, certificateFilename).toString(); + m_TLSKeyLength = loadSetting(kTLSKeyLength, "2048").toString(); + if (getCryptoEnabled()) { + generateCertificate(); + } } -void AppConfig::saveSettings() -{ - setCommonSetting(kWizardLastRun, m_WizardLastRun); - setCommonSetting(kLoadSystemSettings, m_LoadFromSystemScope); - setCommonSetting(kGroupClientCheck, m_ClientGroupChecked); - setCommonSetting(kGroupServerCheck, m_ServerGroupChecked); - setCommonSetting(kEliteBackersUrl, m_eliteBackersUrl); - setCommonSetting(kGuid, m_guid); - setCommonSetting(kLicenseRegistryUrl, m_licenseRegistryUrl); - setCommonSetting(kLicenseNextCheck, m_licenseNextCheck); +void AppConfig::saveSettings() { + setCommonSetting(kWizardLastRun, m_WizardLastRun); + setCommonSetting(kLoadSystemSettings, m_LoadFromSystemScope); + setCommonSetting(kGroupClientCheck, m_ClientGroupChecked); + setCommonSetting(kGroupServerCheck, m_ServerGroupChecked); + setCommonSetting(kEliteBackersUrl, m_eliteBackersUrl); + setCommonSetting(kGuid, m_guid); + setCommonSetting(kLicenseRegistryUrl, m_licenseRegistryUrl); + setCommonSetting(kLicenseNextCheck, m_licenseNextCheck); - if (isWritable()) { - setSetting(kScreenName, m_ScreenName); - setSetting(kPort, m_Port); - setSetting(kInterfaceSetting, m_Interface); - setSetting(kLogLevel, m_LogLevel); - setSetting(kLogToFile, m_LogToFile); - setSetting(kLogFilename, m_LogFilename); - setSetting(kLanguage, m_Language); - setSetting(kStartedBefore, m_StartedBefore); - setSetting(kAutoConfig, m_AutoConfig); - setSetting(kAutoConfigServer, m_AutoConfigServer); - // Refer to enum ElevateMode declaration for insight in to why this - // flag is mapped this way - setSetting(kElevateModeSetting, m_ElevateMode == ElevateAlways); - setSetting(kElevateModeEnum, static_cast(m_ElevateMode)); - setSetting(kEditionSetting, m_Edition); - setSetting(kCryptoEnabled, m_CryptoEnabled); - setSetting(kAutoHide, m_AutoHide); - setSetting(kSerialKey, m_Serialkey); - setSetting(kLastVersion, m_lastVersion); - setSetting(kLastExpireWarningTime, m_LastExpiringWarningTime); - setSetting(kActivationHasRun, m_ActivationHasRun); - setSetting(kMinimizeToTray, m_MinimizeToTray); - setSetting(kUseExternalConfig, m_UseExternalConfig); - setSetting(kConfigFile, m_ConfigFile); - setSetting(kUseInternalConfig, m_UseInternalConfig); - setSetting(kServerHostname, m_ServerHostname); - setSetting(kPreventSleep, m_PreventSleep); - setSetting(kLanguageSync, m_LanguageSync); - setSetting(kInvertScrollDirection, m_InvertScrollDirection); - setSetting(kClientHostMode, m_ClientHostMode); - setSetting(kServerClientMode, m_ServerClientMode); - } + if (isWritable()) { + setSetting(kScreenName, m_ScreenName); + setSetting(kPort, m_Port); + setSetting(kInterfaceSetting, m_Interface); + setSetting(kLogLevel, m_LogLevel); + setSetting(kLogToFile, m_LogToFile); + setSetting(kLogFilename, m_LogFilename); + setSetting(kLanguage, m_Language); + setSetting(kStartedBefore, m_StartedBefore); + setSetting(kAutoConfig, m_AutoConfig); + setSetting(kAutoConfigServer, m_AutoConfigServer); + // Refer to enum ElevateMode declaration for insight in to why this + // flag is mapped this way + setSetting(kElevateModeSetting, m_ElevateMode == ElevateAlways); + setSetting(kElevateModeEnum, static_cast(m_ElevateMode)); + setSetting(kEditionSetting, m_Edition); + setSetting(kCryptoEnabled, m_CryptoEnabled); + setSetting(kAutoHide, m_AutoHide); + setSetting(kSerialKey, m_Serialkey); + setSetting(kLastVersion, m_lastVersion); + setSetting(kLastExpireWarningTime, m_LastExpiringWarningTime); + setSetting(kActivationHasRun, m_ActivationHasRun); + setSetting(kMinimizeToTray, m_MinimizeToTray); + setSetting(kUseExternalConfig, m_UseExternalConfig); + setSetting(kConfigFile, m_ConfigFile); + setSetting(kUseInternalConfig, m_UseInternalConfig); + setSetting(kServerHostname, m_ServerHostname); + setSetting(kPreventSleep, m_PreventSleep); + setSetting(kLanguageSync, m_LanguageSync); + setSetting(kInvertScrollDirection, m_InvertScrollDirection); + setSetting(kClientHostMode, m_ClientHostMode); + setSetting(kServerClientMode, m_ServerClientMode); + } - m_unsavedChanges = false; + m_unsavedChanges = false; } #ifndef SYNERGY_ENTERPRISE -bool AppConfig::activationHasRun() const -{ - return m_ActivationHasRun; -} +bool AppConfig::activationHasRun() const { return m_ActivationHasRun; } -AppConfig& AppConfig::activationHasRun(bool value) -{ - m_ActivationHasRun = value; - return *this; +AppConfig &AppConfig::activationHasRun(bool value) { + m_ActivationHasRun = value; + return *this; } #endif -QString AppConfig::lastVersion() const -{ - return m_lastVersion; -} +QString AppConfig::lastVersion() const { return m_lastVersion; } -void AppConfig::setLastVersion(const QString& version) { - setSettingModified(m_lastVersion, version); +void AppConfig::setLastVersion(const QString &version) { + setSettingModified(m_lastVersion, version); } void AppConfig::setScreenName(const QString &s) { - setSettingModified(m_ScreenName, s); - emit screenNameChanged(); + setSettingModified(m_ScreenName, s); + emit screenNameChanged(); } -void AppConfig::setPort(int i) { - setSettingModified(m_Port, i); -} +void AppConfig::setPort(int i) { setSettingModified(m_Port, i); } void AppConfig::setNetworkInterface(const QString &s) { - setSettingModified(m_Interface, s); + setSettingModified(m_Interface, s); } -void AppConfig::setLogLevel(int i) { - setSettingModified(m_LogLevel, i); -} +void AppConfig::setLogLevel(int i) { setSettingModified(m_LogLevel, i); } -void AppConfig::setLogToFile(bool b) { - setSettingModified(m_LogToFile, b); -} +void AppConfig::setLogToFile(bool b) { setSettingModified(m_LogToFile, b); } void AppConfig::setLogFilename(const QString &s) { - setSettingModified(m_LogFilename, s); + setSettingModified(m_LogFilename, s); } void AppConfig::setWizardHasRun() { - setSettingModified(m_WizardLastRun, kWizardVersion); + setSettingModified(m_WizardLastRun, kWizardVersion); } -void AppConfig::setLanguage(const QString& language) { - setSettingModified(m_Language, language); +void AppConfig::setLanguage(const QString &language) { + setSettingModified(m_Language, language); } void AppConfig::setStartedBefore(bool b) { - setSettingModified(m_StartedBefore, b); + setSettingModified(m_StartedBefore, b); } void AppConfig::setElevateMode(ElevateMode em) { - setSettingModified(m_ElevateMode, em); + setSettingModified(m_ElevateMode, em); } -void AppConfig::setAutoConfig(bool autoConfig) -{ - setSettingModified(m_AutoConfig, autoConfig); - emit zeroConfToggled(); +void AppConfig::setAutoConfig(bool autoConfig) { + setSettingModified(m_AutoConfig, autoConfig); + emit zeroConfToggled(); } -void AppConfig::setAutoConfigServer(const QString& autoConfigServer) -{ - setSettingModified(m_AutoConfigServer, autoConfigServer); +void AppConfig::setAutoConfigServer(const QString &autoConfigServer) { + setSettingModified(m_AutoConfigServer, autoConfigServer); } #ifndef SYNERGY_ENTERPRISE void AppConfig::setEdition(Edition e) { - setSettingModified(m_Edition, e); - setCommonSetting(kEditionSetting, m_Edition); + setSettingModified(m_Edition, e); + setCommonSetting(kEditionSetting, m_Edition); } Edition AppConfig::edition() const { return m_Edition; } -void AppConfig::setSerialKey(const QString& serial) { - setSettingModified(m_Serialkey, serial); - setCommonSetting(kSerialKey, m_Serialkey); +void AppConfig::setSerialKey(const QString &serial) { + setSettingModified(m_Serialkey, serial); + setCommonSetting(kSerialKey, m_Serialkey); } -void AppConfig::clearSerialKey() -{ - m_Serialkey.clear(); -} +void AppConfig::clearSerialKey() { m_Serialkey.clear(); } QString AppConfig::serialKey() const { return m_Serialkey; } -int AppConfig::lastExpiringWarningTime() const { return m_LastExpiringWarningTime; } +int AppConfig::lastExpiringWarningTime() const { + return m_LastExpiringWarningTime; +} void AppConfig::setLastExpiringWarningTime(int newValue) { - setSettingModified(m_LastExpiringWarningTime, newValue); + setSettingModified(m_LastExpiringWarningTime, newValue); } #endif @@ -438,275 +408,245 @@ QString AppConfig::synergysName() const { return m_SynergysName; } QString AppConfig::synergycName() const { return m_SynergycName; } -ElevateMode AppConfig::elevateMode() -{ - return m_ElevateMode; -} +ElevateMode AppConfig::elevateMode() { return m_ElevateMode; } void AppConfig::setCryptoEnabled(bool newValue) { - if (m_CryptoEnabled != newValue && newValue){ - generateCertificate(); - } - else { - emit sslToggled(); - } - setSettingModified(m_CryptoEnabled, newValue); + if (m_CryptoEnabled != newValue && newValue) { + generateCertificate(); + } else { + emit sslToggled(); + } + setSettingModified(m_CryptoEnabled, newValue); } bool AppConfig::isCryptoAvailable() const { - bool result {true}; + bool result{true}; #if !defined(SYNERGY_ENTERPRISE) && !defined(SYNERGY_BUSINESS) - result = (edition() == kPro || - edition() == kPro_China || - edition() == kBusiness || - edition() == kUltimate); + result = (edition() == kPro || edition() == kPro_China || + edition() == kBusiness || edition() == kUltimate); #endif - return result; + return result; } bool AppConfig::getCryptoEnabled() const { - return isCryptoAvailable() && m_CryptoEnabled; + return isCryptoAvailable() && m_CryptoEnabled; } -void AppConfig::setAutoHide(bool b) { - setSettingModified(m_AutoHide, b); -} +void AppConfig::setAutoHide(bool b) { setSettingModified(m_AutoHide, b); } bool AppConfig::getAutoHide() { return m_AutoHide; } void AppConfig::setMinimizeToTray(bool newValue) { - setSettingModified(m_MinimizeToTray, newValue); + setSettingModified(m_MinimizeToTray, newValue); } bool AppConfig::getInvertScrollDirection() const { - return m_InvertScrollDirection; + return m_InvertScrollDirection; } -void AppConfig::setEliteBackersUrl(const QString& newValue) { - setSettingModified(m_eliteBackersUrl, newValue); +void AppConfig::setEliteBackersUrl(const QString &newValue) { + setSettingModified(m_eliteBackersUrl, newValue); } void AppConfig::setLicenseNextCheck(unsigned long long time) { - setSettingModified(m_licenseNextCheck, time); + setSettingModified(m_licenseNextCheck, time); } -const QString& AppConfig::getEliteBackersUrl() const { - return m_eliteBackersUrl; +const QString &AppConfig::getEliteBackersUrl() const { + return m_eliteBackersUrl; } -const QString& AppConfig::getLicenseRegistryUrl() const { - return m_licenseRegistryUrl; +const QString &AppConfig::getLicenseRegistryUrl() const { + return m_licenseRegistryUrl; } unsigned long long AppConfig::getLicenseNextCheck() const { - return m_licenseNextCheck; + return m_licenseNextCheck; } -const QString& AppConfig::getGuid() const { - return m_guid; -} +const QString &AppConfig::getGuid() const { return m_guid; } bool AppConfig::getLanguageSync() const { return m_LanguageSync; } void AppConfig::setInvertScrollDirection(bool newValue) { - setSettingModified(m_InvertScrollDirection, newValue); + setSettingModified(m_InvertScrollDirection, newValue); } void AppConfig::setLanguageSync(bool newValue) { - setSettingModified(m_LanguageSync, newValue); + setSettingModified(m_LanguageSync, newValue); } bool AppConfig::getPreventSleep() const { return m_PreventSleep; } bool AppConfig::getClientHostMode() const { - return (m_ClientHostMode && getInitiateConnectionFromServer()); + return (m_ClientHostMode && getInitiateConnectionFromServer()); } bool AppConfig::getServerClientMode() const { - return (m_ServerClientMode && getInitiateConnectionFromServer()); + return (m_ServerClientMode && getInitiateConnectionFromServer()); } bool AppConfig::getInitiateConnectionFromServer() const { - return m_InitiateConnectionFromServer; + return m_InitiateConnectionFromServer; } void AppConfig::setPreventSleep(bool newValue) { - setSettingModified(m_PreventSleep, newValue); + setSettingModified(m_PreventSleep, newValue); } bool AppConfig::getMinimizeToTray() { return m_MinimizeToTray; } QString AppConfig::settingName(AppConfig::Setting name) { - return m_SynergySettingsName[name]; + return m_SynergySettingsName[name]; } -template +template void AppConfig::setSetting(AppConfig::Setting name, T value) { - ConfigWriter::make()->setSetting(settingName(name), value); + ConfigWriter::make()->setSetting(settingName(name), value); } -template +template void AppConfig::setCommonSetting(AppConfig::Setting name, T value) { - ConfigWriter::make()->setSetting(settingName(name), value, ConfigWriter::kUser); - ConfigWriter::make()->setSetting(settingName(name), value, ConfigWriter::kSystem); + ConfigWriter::make()->setSetting(settingName(name), value, + ConfigWriter::kUser); + ConfigWriter::make()->setSetting(settingName(name), value, + ConfigWriter::kSystem); } -QVariant AppConfig::loadSetting(AppConfig::Setting name, const QVariant& defaultValue) { - return ConfigWriter::make()->loadSetting(settingName(name), defaultValue); +QVariant AppConfig::loadSetting(AppConfig::Setting name, + const QVariant &defaultValue) { + return ConfigWriter::make()->loadSetting(settingName(name), defaultValue); } -QVariant AppConfig::loadCommonSetting(AppConfig::Setting name, const QVariant& defaultValue) const { - QVariant result(defaultValue); - QString setting(settingName(name)); - auto& writer = *ConfigWriter::make(); +QVariant AppConfig::loadCommonSetting(AppConfig::Setting name, + const QVariant &defaultValue) const { + QVariant result(defaultValue); + QString setting(settingName(name)); + auto &writer = *ConfigWriter::make(); - if (writer.hasSetting(setting)) { - result = writer.loadSetting(setting, defaultValue); - } - else if (writer.getScope() == ConfigWriter::kSystem ) { - if (writer.hasSetting(setting, ConfigWriter::kUser)) { - result = writer.loadSetting(setting, defaultValue, ConfigWriter::kUser); - } - } - else if (writer.hasSetting(setting, ConfigWriter::kSystem)){ - result = writer.loadSetting(setting, defaultValue, ConfigWriter::kSystem); + if (writer.hasSetting(setting)) { + result = writer.loadSetting(setting, defaultValue); + } else if (writer.getScope() == ConfigWriter::kSystem) { + if (writer.hasSetting(setting, ConfigWriter::kUser)) { + result = writer.loadSetting(setting, defaultValue, ConfigWriter::kUser); } + } else if (writer.hasSetting(setting, ConfigWriter::kSystem)) { + result = writer.loadSetting(setting, defaultValue, ConfigWriter::kSystem); + } - return result; + return result; } void AppConfig::loadScope(ConfigWriter::Scope scope) { - auto writer = ConfigWriter::make(); + auto writer = ConfigWriter::make(); - if (writer->getScope() != scope) { - setDefaultValues(); - writer->setScope(scope); - if (writer->hasSetting(settingName(kScreenName), writer->getScope())) { - //If the user already has settings, then load them up now. - writer->globalLoad(); - } - } + if (writer->getScope() != scope) { + setDefaultValues(); + writer->setScope(scope); + if (writer->hasSetting(settingName(kScreenName), writer->getScope())) { + // If the user already has settings, then load them up now. + writer->globalLoad(); + } + } } -void AppConfig::setDefaultValues() -{ - m_InitiateConnectionFromServer = false; -} +void AppConfig::setDefaultValues() { m_InitiateConnectionFromServer = false; } void AppConfig::setLoadFromSystemScope(bool value) { - if (value) { - loadScope(ConfigWriter::kSystem); - } - else { - loadScope(ConfigWriter::kUser); - } + if (value) { + loadScope(ConfigWriter::kSystem); + } else { + loadScope(ConfigWriter::kUser); + } - /* - * It's very imprortant to set this variable after loadScope - * because during scope loading this variable can be rewritten with old value + /* + * It's very imprortant to set this variable after loadScope + * because during scope loading this variable can be rewritten with old value */ - m_LoadFromSystemScope = value; + m_LoadFromSystemScope = value; } -bool AppConfig::isWritable() const { - return ConfigWriter::make()->isWritable(); +bool AppConfig::isWritable() const { + return ConfigWriter::make()->isWritable(); } bool AppConfig::isSystemScoped() const { - return ConfigWriter::make()->getScope() == ConfigWriter::kSystem; + return ConfigWriter::make()->getScope() == ConfigWriter::kSystem; } -bool AppConfig::getServerGroupChecked() const { - return m_ServerGroupChecked; -} +bool AppConfig::getServerGroupChecked() const { return m_ServerGroupChecked; } -bool AppConfig::getUseExternalConfig() const { - return m_UseExternalConfig; -} +bool AppConfig::getUseExternalConfig() const { return m_UseExternalConfig; } -const QString& AppConfig::getConfigFile() const { - return m_ConfigFile; -} +const QString &AppConfig::getConfigFile() const { return m_ConfigFile; } -bool AppConfig::getUseInternalConfig() const { - return m_UseInternalConfig; -} +bool AppConfig::getUseInternalConfig() const { return m_UseInternalConfig; } -bool AppConfig::getClientGroupChecked() const { - return m_ClientGroupChecked; -} +bool AppConfig::getClientGroupChecked() const { return m_ClientGroupChecked; } -QString AppConfig::getServerHostname() const { - return m_ServerHostname; -} +QString AppConfig::getServerHostname() const { return m_ServerHostname; } void AppConfig::setServerGroupChecked(bool newValue) { - setSettingModified(m_ServerGroupChecked, newValue); + setSettingModified(m_ServerGroupChecked, newValue); } void AppConfig::setUseExternalConfig(bool newValue) { - setSettingModified(m_UseExternalConfig, newValue); + setSettingModified(m_UseExternalConfig, newValue); } -void AppConfig::setConfigFile(const QString& newValue) { - setSettingModified(m_ConfigFile, newValue); +void AppConfig::setConfigFile(const QString &newValue) { + setSettingModified(m_ConfigFile, newValue); } void AppConfig::setUseInternalConfig(bool newValue) { - setSettingModified(m_UseInternalConfig, newValue); + setSettingModified(m_UseInternalConfig, newValue); } void AppConfig::setClientGroupChecked(bool newValue) { - setSettingModified(m_ClientGroupChecked, newValue); + setSettingModified(m_ClientGroupChecked, newValue); } -void AppConfig::setServerHostname(const QString& newValue) { - setSettingModified(m_ServerHostname, newValue); +void AppConfig::setServerHostname(const QString &newValue) { + setSettingModified(m_ServerHostname, newValue); } void AppConfig::setClientHostMode(bool newValue) { - setSettingModified(m_ClientHostMode, newValue); + setSettingModified(m_ClientHostMode, newValue); } void AppConfig::setServerClientMode(bool newValue) { - setSettingModified(m_ServerClientMode, newValue); + setSettingModified(m_ServerClientMode, newValue); } -template -void AppConfig::setSettingModified(T &variable, const T& newValue) { - if (variable != newValue) - { - variable = newValue; - m_unsavedChanges = true; - } +template +void AppConfig::setSettingModified(T &variable, const T &newValue) { + if (variable != newValue) { + variable = newValue; + m_unsavedChanges = true; + } } -void AppConfig::setTLSCertPath(const QString& path) { - m_TLSCertificatePath = path; +void AppConfig::setTLSCertPath(const QString &path) { + m_TLSCertificatePath = path; } -QString AppConfig::getTLSCertPath() const { - return m_TLSCertificatePath; -} +QString AppConfig::getTLSCertPath() const { return m_TLSCertificatePath; } -QString AppConfig::getTLSKeyLength() const { - return m_TLSKeyLength; -} +QString AppConfig::getTLSKeyLength() const { return m_TLSKeyLength; } -void AppConfig::setTLSKeyLength(const QString& length) { - if (m_TLSKeyLength != length) { - m_TLSKeyLength = length; - generateCertificate(true); - } +void AppConfig::setTLSKeyLength(const QString &length) { + if (m_TLSKeyLength != length) { + m_TLSKeyLength = length; + generateCertificate(true); + } } void AppConfig::generateCertificate(bool forceGeneration) const { - SslCertificate sslCertificate; - sslCertificate.generateCertificate(getTLSCertPath(), getTLSKeyLength(), forceGeneration); - emit sslToggled(); + SslCertificate sslCertificate; + sslCertificate.generateCertificate(getTLSCertPath(), getTLSKeyLength(), + forceGeneration); + emit sslToggled(); } - - diff --git a/src/gui/src/AppConfig.h b/src/gui/src/AppConfig.h index e61c9c106..250514f13 100644 --- a/src/gui/src/AppConfig.h +++ b/src/gui/src/AppConfig.h @@ -20,15 +20,15 @@ #define APPCONFIG_H -#include -#include -#include -#include "ElevateMode.h" -#include -#include #include "ConfigBase.h" #include "ConfigWriter.h" #include "CoreInterface.h" +#include "ElevateMode.h" +#include +#include +#include +#include +#include // this should be incremented each time a new page is added. this is // saved to settings when the user finishes running the wizard. if @@ -52,308 +52,307 @@ class SettingsDialog; class ServerConfig; class LicenseRegister; -enum ProcessMode { - Service, - Desktop -}; +enum ProcessMode { Service, Desktop }; -class AppConfig: public QObject, public GUI::Config::ConfigBase -{ - Q_OBJECT +class AppConfig : public QObject, public GUI::Config::ConfigBase { + Q_OBJECT - friend class SettingsDialog; - friend class MainWindow; - friend class SetupWizard; - friend class ServerConfig; + friend class SettingsDialog; + friend class MainWindow; + friend class SetupWizard; + friend class ServerConfig; - public: - AppConfig(); +public: + AppConfig(); - public: - bool isWritable() const; - bool isSystemScoped() const; +public: + bool isWritable() const; + bool isSystemScoped() const; - const QString& screenName() const; - int port() const; - const QString& networkInterface() const; - int logLevel() const; - bool logToFile() const; - const QString& logFilename() const; - const QString logFilenameCmd() const; - QString logLevelText() const; - ProcessMode processMode() const; - bool wizardShouldRun() const; - const QString& language() const; - bool startedBefore() const; - bool autoConfig() const; - void setAutoConfig(bool autoConfig); - QString autoConfigServer() const; - void setAutoConfigServer(const QString& autoConfigServer); + const QString &screenName() const; + int port() const; + const QString &networkInterface() const; + int logLevel() const; + bool logToFile() const; + const QString &logFilename() const; + const QString logFilenameCmd() const; + QString logLevelText() const; + ProcessMode processMode() const; + bool wizardShouldRun() const; + const QString &language() const; + bool startedBefore() const; + bool autoConfig() const; + void setAutoConfig(bool autoConfig); + QString autoConfigServer() const; + void setAutoConfigServer(const QString &autoConfigServer); #ifndef SYNERGY_ENTERPRISE - void setEdition(Edition); - Edition edition() const; - void setSerialKey(const QString& serial); - void clearSerialKey(); - QString serialKey() const; - int lastExpiringWarningTime() const; - void setLastExpiringWarningTime(int t); + void setEdition(Edition); + Edition edition() const; + void setSerialKey(const QString &serial); + void clearSerialKey(); + QString serialKey() const; + int lastExpiringWarningTime() const; + void setLastExpiringWarningTime(int t); #endif - QString synergysName() const; - QString synergycName() const; - QString synergyProgramDir() const; - QString synergyLogDir() const; + QString synergysName() const; + QString synergycName() const; + QString synergyProgramDir() const; + QString synergyLogDir() const; - void persistLogDir(); - ElevateMode elevateMode(); + void persistLogDir(); + ElevateMode elevateMode(); - bool isCryptoAvailable() const; - void setCryptoEnabled(bool e); - bool getCryptoEnabled() const; + bool isCryptoAvailable() const; + void setCryptoEnabled(bool e); + bool getCryptoEnabled() const; - void setAutoHide(bool b); - bool getAutoHide(); - void setInvertScrollDirection(bool b); - bool getInvertScrollDirection() const; - void setEliteBackersUrl(const QString&); - void setLicenseNextCheck(unsigned long long); - const QString& getEliteBackersUrl() const; - const QString& getLicenseRegistryUrl() const; - unsigned long long getLicenseNextCheck() const; - const QString& getGuid() const; - void setLanguageSync(bool b); - bool getLanguageSync() const; - void setPreventSleep(bool b); - bool getPreventSleep() const; - bool getClientHostMode() const; - bool getServerClientMode() const; - bool getInitiateConnectionFromServer() const; + void setAutoHide(bool b); + bool getAutoHide(); + void setInvertScrollDirection(bool b); + bool getInvertScrollDirection() const; + void setEliteBackersUrl(const QString &); + void setLicenseNextCheck(unsigned long long); + const QString &getEliteBackersUrl() const; + const QString &getLicenseRegistryUrl() const; + unsigned long long getLicenseNextCheck() const; + const QString &getGuid() const; + void setLanguageSync(bool b); + bool getLanguageSync() const; + void setPreventSleep(bool b); + bool getPreventSleep() const; + bool getClientHostMode() const; + bool getServerClientMode() const; + bool getInitiateConnectionFromServer() const; #ifndef SYNERGY_ENTERPRISE - bool activationHasRun() const; - AppConfig& activationHasRun(bool value); + bool activationHasRun() const; + AppConfig &activationHasRun(bool value); #endif - /// @brief Sets the user preference to load from SystemScope. - /// @param [in] value - /// True - This will set the variable and load the global scope settings. - /// False - This will set the variable and load the user scope settings. - void setLoadFromSystemScope(bool value); + /// @brief Sets the user preference to load from SystemScope. + /// @param [in] value + /// True - This will set the variable and load the global scope + /// settings. False - This will set the variable and load the user + /// scope settings. + void setLoadFromSystemScope(bool value); + bool getServerGroupChecked() const; + bool getUseExternalConfig() const; + const QString &getConfigFile() const; + bool getUseInternalConfig() const; + bool getClientGroupChecked() const; + QString getServerHostname() const; - bool getServerGroupChecked() const; - bool getUseExternalConfig() const; - const QString& getConfigFile() const; - bool getUseInternalConfig() const; - bool getClientGroupChecked() const; - QString getServerHostname() const; + /// @brief Gets the current TLS certificate path + /// @return QString The path to the cert + QString getTLSCertPath() const; - /// @brief Gets the current TLS certificate path - /// @return QString The path to the cert - QString getTLSCertPath() const; + /// @brief Get the key length to be used for the private key of a TLS cert + /// @return QString The key length in bits + QString getTLSKeyLength() const; - /// @brief Get the key length to be used for the private key of a TLS cert - /// @return QString The key length in bits - QString getTLSKeyLength() const; + void setServerGroupChecked(bool); + void setUseExternalConfig(bool); + void setConfigFile(const QString &); + void setUseInternalConfig(bool); + void setClientGroupChecked(bool); + void setServerHostname(const QString &); + void setClientHostMode(bool newValue); + void setServerClientMode(bool newValue); - void setServerGroupChecked(bool); - void setUseExternalConfig(bool) ; - void setConfigFile(const QString&); - void setUseInternalConfig(bool) ; - void setClientGroupChecked(bool) ; - void setServerHostname(const QString&); - void setClientHostMode(bool newValue); - void setServerClientMode(bool newValue); + /// @brief Set the path to the TLS/SSL certificate file that will be used + /// @param [in] path The path to the Certificate + void setTLSCertPath(const QString &path); - /// @brief Set the path to the TLS/SSL certificate file that will be used - /// @param [in] path The path to the Certificate - void setTLSCertPath(const QString& path); + /// @brief Sets the key length of the private key to use in a TLS connection + /// @param [in] QString length The key length eg: 1024, 2048, 4096 + void setTLSKeyLength(const QString &length); - /// @brief Sets the key length of the private key to use in a TLS connection - /// @param [in] QString length The key length eg: 1024, 2048, 4096 - void setTLSKeyLength(const QString& length); + QString lastVersion() const; + void setMinimizeToTray(bool b); + bool getMinimizeToTray(); - QString lastVersion() const; + void saveSettings() override; + void setLastVersion(const QString &version); - void setMinimizeToTray(bool b); - bool getMinimizeToTray(); - - void saveSettings() override; - void setLastVersion(const QString& version); - - /// @brief Generates TLS certificate - /// @param [in] bool forceGeneration Generate certificate even if it's exists. - void generateCertificate(bool forceGeneration=false) const; + /// @brief Generates TLS certificate + /// @param [in] bool forceGeneration Generate certificate even if it's exists. + void generateCertificate(bool forceGeneration = false) const; protected: - /// @brief The enumeration to easily access the names of the setting inside m_SynergySettingsName - enum Setting { - kScreenName, - kPort, - kInterfaceSetting, - kLogLevel, - kLogToFile, - kLogFilename, - kWizardLastRun, - kLanguage, - kStartedBefore, - kAutoConfig, - kAutoConfigServer, - kElevateModeSetting, - kElevateModeEnum, - kEditionSetting, - kCryptoEnabled, - kAutoHide, - kSerialKey, - kLastVersion, - kLastExpireWarningTime, - kActivationHasRun, - kMinimizeToTray, - kActivateEmail, - kLoadSystemSettings, - kGroupServerCheck, - kUseExternalConfig, - kConfigFile, - kUseInternalConfig, - kGroupClientCheck, - kServerHostname, - kTLSCertPath, - kTLSKeyLength, - kPreventSleep, - kLanguageSync, - kInvertScrollDirection, - kEliteBackersUrl, - kGuid, - kLicenseRegistryUrl, - kLicenseNextCheck, - kInitiateConnectionFromServer, - kClientHostMode, - kServerClientMode - }; + /// @brief The enumeration to easily access the names of the setting inside + /// m_SynergySettingsName + enum Setting { + kScreenName, + kPort, + kInterfaceSetting, + kLogLevel, + kLogToFile, + kLogFilename, + kWizardLastRun, + kLanguage, + kStartedBefore, + kAutoConfig, + kAutoConfigServer, + kElevateModeSetting, + kElevateModeEnum, + kEditionSetting, + kCryptoEnabled, + kAutoHide, + kSerialKey, + kLastVersion, + kLastExpireWarningTime, + kActivationHasRun, + kMinimizeToTray, + kActivateEmail, + kLoadSystemSettings, + kGroupServerCheck, + kUseExternalConfig, + kConfigFile, + kUseInternalConfig, + kGroupClientCheck, + kServerHostname, + kTLSCertPath, + kTLSKeyLength, + kPreventSleep, + kLanguageSync, + kInvertScrollDirection, + kEliteBackersUrl, + kGuid, + kLicenseRegistryUrl, + kLicenseNextCheck, + kInitiateConnectionFromServer, + kClientHostMode, + kServerClientMode + }; - void setScreenName(const QString& s); - void setPort(int i); - void setNetworkInterface(const QString& s); - void setLogLevel(int i); - void setLogToFile(bool b); - void setLogFilename(const QString& s); - void setWizardHasRun(); - void setLanguage(const QString& language); - void setStartedBefore(bool b); - void setElevateMode(ElevateMode em); + void setScreenName(const QString &s); + void setPort(int i); + void setNetworkInterface(const QString &s); + void setLogLevel(int i); + void setLogToFile(bool b); + void setLogFilename(const QString &s); + void setWizardHasRun(); + void setLanguage(const QString &language); + void setStartedBefore(bool b); + void setElevateMode(ElevateMode em); - /// @brief loads the setting from the current scope - /// @param ignoreSystem should the load feature ignore the globalScope setting that was saved - void loadSettings() override; - static QString settingName(AppConfig::Setting name); + /// @brief loads the setting from the current scope + /// @param ignoreSystem should the load feature ignore the globalScope setting + /// that was saved + void loadSettings() override; + static QString settingName(AppConfig::Setting name); - private: +private: + QString m_ScreenName; + int m_Port; + QString m_Interface; + int m_LogLevel; + bool m_LogToFile; + QString m_LogFilename; + int m_WizardLastRun; + ProcessMode m_ProcessMode; + QString m_Language; + bool m_StartedBefore; + bool m_AutoConfig; + QString m_AutoConfigServer; + ElevateMode m_ElevateMode; + Edition m_Edition; + QString m_ActivateEmail; + bool m_CryptoEnabled; + bool m_AutoHide; + QString m_Serialkey; + QString m_lastVersion; + QString m_eliteBackersUrl; + QString m_guid; + QString m_licenseRegistryUrl; + unsigned long long m_licenseNextCheck; + int m_LastExpiringWarningTime; + bool m_ActivationHasRun; + bool m_MinimizeToTray; + bool m_InvertScrollDirection = false; + bool m_LanguageSync = true; + bool m_PreventSleep = false; + bool m_InitiateConnectionFromServer = false; + bool m_ClientHostMode = true; + bool m_ServerClientMode = true; - QString m_ScreenName; - int m_Port; - QString m_Interface; - int m_LogLevel; - bool m_LogToFile; - QString m_LogFilename; - int m_WizardLastRun; - ProcessMode m_ProcessMode; - QString m_Language; - bool m_StartedBefore; - bool m_AutoConfig; - QString m_AutoConfigServer; - ElevateMode m_ElevateMode; - Edition m_Edition; - QString m_ActivateEmail; - bool m_CryptoEnabled; - bool m_AutoHide; - QString m_Serialkey; - QString m_lastVersion; - QString m_eliteBackersUrl; - QString m_guid; - QString m_licenseRegistryUrl; - unsigned long long m_licenseNextCheck; - int m_LastExpiringWarningTime; - bool m_ActivationHasRun; - bool m_MinimizeToTray; - bool m_InvertScrollDirection = false; - bool m_LanguageSync = true; - bool m_PreventSleep = false; - bool m_InitiateConnectionFromServer = false; - bool m_ClientHostMode = true; - bool m_ServerClientMode = true; + bool m_ServerGroupChecked; + bool m_UseExternalConfig; + QString m_ConfigFile; + bool m_UseInternalConfig; + bool m_ClientGroupChecked; + QString m_ServerHostname; - bool m_ServerGroupChecked; - bool m_UseExternalConfig; - QString m_ConfigFile; - bool m_UseInternalConfig; - bool m_ClientGroupChecked; - QString m_ServerHostname; + QString m_TLSCertificatePath; /// @brief The path to the TLS certificate file + QString m_TLSKeyLength; /// @brief The key length of the TLS cert to make - QString m_TLSCertificatePath; /// @brief The path to the TLS certificate file - QString m_TLSKeyLength; /// @brief The key length of the TLS cert to make + bool m_LoadFromSystemScope; /// @brief should the setting be loaded from + /// SystemScope + /// If the user has settings but this is + /// true then system settings will be + /// loaded instead of the users - bool m_LoadFromSystemScope; /// @brief should the setting be loaded from SystemScope - /// If the user has settings but this is true then - /// system settings will be loaded instead of the users + CoreInterface m_CoreInterface; - CoreInterface m_CoreInterface; + static const char m_SynergysName[]; + static const char m_SynergycName[]; + static const char m_SynergyLogDir[]; - static const char m_SynergysName[]; - static const char m_SynergycName[]; - static const char m_SynergyLogDir[]; + /// @brief Contains the string values of the settings names that will be saved + static const char *m_SynergySettingsName[]; - /// @brief Contains the string values of the settings names that will be saved - static const char* m_SynergySettingsName[]; + /// @brief Contains the name of the default configuration filename + static const char synergyConfigName[]; - /// @brief Contains the name of the default configuration filename - static const char synergyConfigName[]; + /// @brief Sets the value of a setting + /// @param [in] name The Setting to be saved + /// @param [in] value The Value to be saved + template void setSetting(AppConfig::Setting name, T value); - /// @brief Sets the value of a setting - /// @param [in] name The Setting to be saved - /// @param [in] value The Value to be saved - template - void setSetting(AppConfig::Setting name, T value); + /// @brief Sets the value of a common setting + /// which should have the same value for all scopes + /// @param [in] name The Setting to be saved + /// @param [in] value The Value to be saved + template void setCommonSetting(AppConfig::Setting name, T value); - /// @brief Sets the value of a common setting - /// which should have the same value for all scopes - /// @param [in] name The Setting to be saved - /// @param [in] value The Value to be saved - template - void setCommonSetting(AppConfig::Setting name, T value); + /// @brief Loads a setting + /// @param [in] name The setting to be loaded + /// @param [in] defaultValue The default value of the setting + QVariant loadSetting(AppConfig::Setting name, + const QVariant &defaultValue = QVariant()); - /// @brief Loads a setting - /// @param [in] name The setting to be loaded - /// @param [in] defaultValue The default value of the setting - QVariant loadSetting(AppConfig::Setting name, const QVariant& defaultValue = QVariant()); + /// @brief Loads a common setting + /// @param [in] name The setting to be loaded + /// @param [in] defaultValue The default value of the setting + QVariant loadCommonSetting(AppConfig::Setting name, + const QVariant &defaultValue = QVariant()) const; - /// @brief Loads a common setting - /// @param [in] name The setting to be loaded - /// @param [in] defaultValue The default value of the setting - QVariant loadCommonSetting(AppConfig::Setting name, const QVariant& defaultValue = QVariant()) const; + /// @brief As the settings will be accessible by multiple objects this lock + /// will ensure that + /// it cant be modified by more that one object at a time if the + /// setting is being switched from system to user. + std::mutex m_settings_lock; - /// @brief As the settings will be accessible by multiple objects this lock will ensure that - /// it cant be modified by more that one object at a time if the setting is being switched - /// from system to user. - std::mutex m_settings_lock; + /// @brief Sets the setting in the config checking if it has changed and + /// flagging that settings + /// needs to be saved if the setting was different + /// @param [in] variable the setting that will be changed + /// @param [in] newValue The new value of the setting + template void setSettingModified(T &variable, const T &newValue); - /// @brief Sets the setting in the config checking if it has changed and flagging that settings - /// needs to be saved if the setting was different - /// @param [in] variable the setting that will be changed - /// @param [in] newValue The new value of the setting - template - void setSettingModified(T& variable,const T& newValue); + /// @brief This method loads config from specified scope + /// @param [in] scope which should be loaded. + void loadScope(GUI::Config::ConfigWriter::Scope scope); - /// @brief This method loads config from specified scope - /// @param [in] scope which should be loaded. - void loadScope(GUI::Config::ConfigWriter::Scope scope); + /// @brief This function sets default values + /// for settings that shouldn't be copied from between scopes. + void setDefaultValues(); - /// @brief This function sets default values - /// for settings that shouldn't be copied from between scopes. - void setDefaultValues(); - - signals: - void sslToggled() const; - void zeroConfToggled(); - void screenNameChanged() const; +signals: + void sslToggled() const; + void zeroConfToggled(); + void screenNameChanged() const; }; #endif diff --git a/src/gui/src/AppDelegate.h b/src/gui/src/AppDelegate.h index 81b50720c..755dfd742 100644 --- a/src/gui/src/AppDelegate.h +++ b/src/gui/src/AppDelegate.h @@ -7,9 +7,12 @@ extern "C" { #import #if OSX_DEPLOYMENT_TARGET >= 1014 #import -@interface AppDelegate : NSObject +@interface AppDelegate + : NSObject #else -@interface AppDelegate : NSObject +@interface AppDelegate + : NSObject #endif @end diff --git a/src/gui/src/BaseConfig.cpp b/src/gui/src/BaseConfig.cpp index 8def4f7b7..c2528ae4b 100644 --- a/src/gui/src/BaseConfig.cpp +++ b/src/gui/src/BaseConfig.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2008 Volker Lanz (vl@fidra.de) - * + * * 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 LICENSE 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 @@ -18,29 +18,12 @@ #include "BaseConfig.h" -const char* BaseConfig::m_ModifierNames[] = -{ - "shift", - "ctrl", - "alt", - "meta", - "super", - "none" -}; +const char *BaseConfig::m_ModifierNames[] = {"shift", "ctrl", "alt", + "meta", "super", "none"}; -const char* BaseConfig::m_FixNames[] = -{ - "halfDuplexCapsLock", - "halfDuplexNumLock", - "halfDuplexScrollLock", - "xtestIsXineramaUnaware" -}; - -const char* BaseConfig::m_SwitchCornerNames[] = -{ - "top-left", - "top-right", - "bottom-left", - "bottom-right" -}; +const char *BaseConfig::m_FixNames[] = { + "halfDuplexCapsLock", "halfDuplexNumLock", "halfDuplexScrollLock", + "xtestIsXineramaUnaware"}; +const char *BaseConfig::m_SwitchCornerNames[] = {"top-left", "top-right", + "bottom-left", "bottom-right"}; diff --git a/src/gui/src/BaseConfig.h b/src/gui/src/BaseConfig.h index f6f388347..d293c0bb9 100644 --- a/src/gui/src/BaseConfig.h +++ b/src/gui/src/BaseConfig.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2008 Volker Lanz (vl@fidra.de) - * + * * 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 LICENSE 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 @@ -24,68 +24,80 @@ #include #include -class BaseConfig -{ - public: - enum Modifier { DefaultMod = -1, Shift, Ctrl, Alt, Meta, Super, None, NumModifiers }; - enum SwitchCorner { TopLeft, TopRight, BottomLeft, BottomRight, NumSwitchCorners }; - enum Fix { CapsLock, NumLock, ScrollLock, XTest, NumFixes }; +class BaseConfig { +public: + enum Modifier { + DefaultMod = -1, + Shift, + Ctrl, + Alt, + Meta, + Super, + None, + NumModifiers + }; + enum SwitchCorner { + TopLeft, + TopRight, + BottomLeft, + BottomRight, + NumSwitchCorners + }; + enum Fix { CapsLock, NumLock, ScrollLock, XTest, NumFixes }; - protected: - BaseConfig() {} - virtual ~BaseConfig() {} +protected: + BaseConfig() {} + virtual ~BaseConfig() {} - protected: - template - void readSettings(QSettings& settings, T1& array, const QString& arrayName, const T2& deflt) - { - int entries = settings.beginReadArray(arrayName + "Array"); - array.clear(); - for (int i = 0; i < entries; i++) - { - settings.setArrayIndex(i); - QVariant v = settings.value(arrayName, deflt); - array.append(v.value()); - } - settings.endArray(); - } +protected: + template + void readSettings(QSettings &settings, T1 &array, const QString &arrayName, + const T2 &deflt) { + int entries = settings.beginReadArray(arrayName + "Array"); + array.clear(); + for (int i = 0; i < entries; i++) { + settings.setArrayIndex(i); + QVariant v = settings.value(arrayName, deflt); + array.append(v.value()); + } + settings.endArray(); + } - template - void readSettings(QSettings& settings, T1& array, const QString& arrayName, const T2& deflt, int entries) - { - Q_ASSERT(array.size() >= entries); - settings.beginReadArray(arrayName + "Array"); - for (int i = 0; i < entries; i++) - { - settings.setArrayIndex(i); - QVariant v = settings.value(arrayName, deflt); - array[i] = v.value(); - } - settings.endArray(); - } + template + void readSettings(QSettings &settings, T1 &array, const QString &arrayName, + const T2 &deflt, int entries) { + Q_ASSERT(array.size() >= entries); + settings.beginReadArray(arrayName + "Array"); + for (int i = 0; i < entries; i++) { + settings.setArrayIndex(i); + QVariant v = settings.value(arrayName, deflt); + array[i] = v.value(); + } + settings.endArray(); + } - template - void writeSettings(QSettings& settings, const T& array, const QString& arrayName) const - { - settings.beginWriteArray(arrayName + "Array"); - for (int i = 0; i < array.size(); i++) - { - settings.setArrayIndex(i); - settings.setValue(arrayName, array[i]); - } - settings.endArray(); - } + template + void writeSettings(QSettings &settings, const T &array, + const QString &arrayName) const { + settings.beginWriteArray(arrayName + "Array"); + for (int i = 0; i < array.size(); i++) { + settings.setArrayIndex(i); + settings.setValue(arrayName, array[i]); + } + settings.endArray(); + } +public: + static const char *modifierName(int idx) { return m_ModifierNames[idx]; } + static const char *fixName(int idx) { return m_FixNames[idx]; } + static const char *switchCornerName(int idx) { + return m_SwitchCornerNames[idx]; + } - public: - static const char* modifierName(int idx) { return m_ModifierNames[idx]; } - static const char* fixName(int idx) { return m_FixNames[idx]; } - static const char* switchCornerName(int idx) { return m_SwitchCornerNames[idx]; } - - private: - static const char* m_ModifierNames[]; - static const char* m_FixNames[]; - static const char* m_SwitchCornerNames[]; +private: + static const char *m_ModifierNames[]; + static const char *m_FixNames[]; + static const char *m_SwitchCornerNames[]; }; #endif diff --git a/src/gui/src/BonjourWindows.cpp b/src/gui/src/BonjourWindows.cpp index b16a0c789..5f1badd14 100644 --- a/src/gui/src/BonjourWindows.cpp +++ b/src/gui/src/BonjourWindows.cpp @@ -19,185 +19,172 @@ #if defined(Q_OS_WIN) -#include "MainWindow.h" -#include "SettingsDialog.h" -#include "DataDownloader.h" -#include "QUtility.h" #include "CommandProcess.h" +#include "DataDownloader.h" +#include "MainWindow.h" +#include "QUtility.h" +#include "SettingsDialog.h" -#include -#include #include -#include #include +#include +#include +#include #define WIN32_LEAN_AND_MEAN #include -BonjourWindows::BonjourWindows( - SettingsDialog* settingsDialog, - MainWindow* mainWindow, - AppConfig& appConfig) : - m_pSettingsDialog(settingsDialog), - m_pMainWindow(mainWindow), - m_pBonjourInstall(nullptr), - m_pDownloadMessageBox(nullptr), - m_pDataDownloader(nullptr), - m_appConfig(appConfig) -{ +BonjourWindows::BonjourWindows(SettingsDialog *settingsDialog, + MainWindow *mainWindow, AppConfig &appConfig) + : m_pSettingsDialog(settingsDialog), m_pMainWindow(mainWindow), + m_pBonjourInstall(nullptr), m_pDownloadMessageBox(nullptr), + m_pDataDownloader(nullptr), m_appConfig(appConfig) {} + +BonjourWindows::~BonjourWindows() { + if (m_pBonjourInstall != nullptr) { + delete m_pBonjourInstall; + } + + if (m_pDownloadMessageBox != nullptr) { + delete m_pDownloadMessageBox; + } + + if (m_pDataDownloader != nullptr) { + delete m_pDataDownloader; + } } -BonjourWindows::~BonjourWindows() -{ - if (m_pBonjourInstall != nullptr) { - delete m_pBonjourInstall; - } +void BonjourWindows::downloadAndInstall() { + QUrl url; + int arch = getProcessorArch(); + if (arch == kProcessorArchWin32) { + url.setUrl(bonjourBaseUrl + bonjourFilename32); + m_pMainWindow->appendLogInfo("downloading bonjour (32-bit)"); + } else if (arch == kProcessorArchWin64) { + url.setUrl(bonjourBaseUrl + bonjourFilename64); + m_pMainWindow->appendLogInfo("downloading bonjour (64-bit)"); + } else { + QMessageBox::critical(m_pSettingsDialog, tr("Synergy Auto Config"), + tr("Failed to detect system architecture.")); + return; + } - if (m_pDownloadMessageBox != nullptr) { - delete m_pDownloadMessageBox; - } + if (m_pDataDownloader == nullptr) { + m_pDataDownloader = new DataDownloader(this); + connect(m_pDataDownloader, SIGNAL(isComplete()), SLOT(downloadFinished())); + } - if (m_pDataDownloader != nullptr) { - delete m_pDataDownloader; - } + m_pDataDownloader->download(url); + + if (m_pDownloadMessageBox != nullptr) { + delete m_pDownloadMessageBox; + m_pDownloadMessageBox = nullptr; + } + + m_pDownloadMessageBox = new QMessageBox(m_pSettingsDialog); + m_pDownloadMessageBox->setWindowTitle("Synergy Auto Config"); + m_pDownloadMessageBox->setIcon(QMessageBox::Information); + m_pDownloadMessageBox->setText("Installing Bonjour, please wait..."); + QAbstractButton *cancel = + m_pDownloadMessageBox->addButton(tr("Cancel"), QMessageBox::RejectRole); + + m_pDownloadMessageBox->exec(); + + if (cancel == m_pDownloadMessageBox->clickedButton()) { + m_pDataDownloader->cancel(); + } } -void BonjourWindows::downloadAndInstall() -{ - QUrl url; - int arch = getProcessorArch(); - if (arch == kProcessorArchWin32) { - url.setUrl(bonjourBaseUrl + bonjourFilename32); - m_pMainWindow->appendLogInfo("downloading bonjour (32-bit)"); - } - else if (arch == kProcessorArchWin64) { - url.setUrl(bonjourBaseUrl + bonjourFilename64); - m_pMainWindow->appendLogInfo("downloading bonjour (64-bit)"); - } - else { - QMessageBox::critical( - m_pSettingsDialog, tr("Synergy Auto Config"), - tr("Failed to detect system architecture.")); - return; - } - - if (m_pDataDownloader == nullptr) { - m_pDataDownloader = new DataDownloader(this); - connect(m_pDataDownloader, SIGNAL(isComplete()), SLOT(downloadFinished())); - } - - m_pDataDownloader->download(url); - - if (m_pDownloadMessageBox != nullptr) { - delete m_pDownloadMessageBox; - m_pDownloadMessageBox = nullptr; - } - - m_pDownloadMessageBox = new QMessageBox(m_pSettingsDialog); - m_pDownloadMessageBox->setWindowTitle("Synergy Auto Config"); - m_pDownloadMessageBox->setIcon(QMessageBox::Information); - m_pDownloadMessageBox->setText("Installing Bonjour, please wait..."); - QAbstractButton* cancel = m_pDownloadMessageBox->addButton( - tr("Cancel"), QMessageBox::RejectRole); - - m_pDownloadMessageBox->exec(); - - if (cancel == m_pDownloadMessageBox->clickedButton()) { - m_pDataDownloader->cancel(); - } +void BonjourWindows::downloadFinished() { + m_pMainWindow->appendLogInfo("bonjour downloaded"); + install(); } -void BonjourWindows::downloadFinished() -{ - m_pMainWindow->appendLogInfo("bonjour downloaded"); - install(); -} +void BonjourWindows::install() { + m_pMainWindow->appendLogInfo("installing bonjour"); -void BonjourWindows::install() -{ - m_pMainWindow->appendLogInfo("installing bonjour"); - - QString tempLocation = QStandardPaths::writableLocation(QStandardPaths::TempLocation); - - QString filename = tempLocation; - filename.append("\\").append(bonjourTargetFilename); - QFile file(filename); - if (!file.open(QIODevice::WriteOnly)) { - m_pDownloadMessageBox->hide(); - - QMessageBox::warning( - m_pSettingsDialog, "Synergy", - tr("Failed to download Bonjour installer to location: %1") - .arg(tempLocation)); - return; - } - - file.write(m_pDataDownloader->data()); - file.close(); - - QStringList arguments; - arguments.append("/i"); - QString winFilename = QDir::toNativeSeparators(filename); - arguments.append(winFilename); - arguments.append("/passive"); - - if (m_pBonjourInstall != nullptr) { - delete m_pBonjourInstall; - m_pBonjourInstall = nullptr; - } - - m_pBonjourInstall = new CommandProcess("msiexec", arguments); - - QThread* thread = new QThread; - connect(m_pBonjourInstall, SIGNAL(finished()), this, SLOT(installFinished())); - connect(m_pBonjourInstall, SIGNAL(finished()), thread, SLOT(quit())); - connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); - - m_pBonjourInstall->moveToThread(thread); - thread->start(); - - QMetaObject::invokeMethod(m_pBonjourInstall, "run", Qt::QueuedConnection); + QString tempLocation = + QStandardPaths::writableLocation(QStandardPaths::TempLocation); + QString filename = tempLocation; + filename.append("\\").append(bonjourTargetFilename); + QFile file(filename); + if (!file.open(QIODevice::WriteOnly)) { m_pDownloadMessageBox->hide(); + + QMessageBox::warning( + m_pSettingsDialog, "Synergy", + tr("Failed to download Bonjour installer to location: %1") + .arg(tempLocation)); + return; + } + + file.write(m_pDataDownloader->data()); + file.close(); + + QStringList arguments; + arguments.append("/i"); + QString winFilename = QDir::toNativeSeparators(filename); + arguments.append(winFilename); + arguments.append("/passive"); + + if (m_pBonjourInstall != nullptr) { + delete m_pBonjourInstall; + m_pBonjourInstall = nullptr; + } + + m_pBonjourInstall = new CommandProcess("msiexec", arguments); + + QThread *thread = new QThread; + connect(m_pBonjourInstall, SIGNAL(finished()), this, SLOT(installFinished())); + connect(m_pBonjourInstall, SIGNAL(finished()), thread, SLOT(quit())); + connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); + + m_pBonjourInstall->moveToThread(thread); + thread->start(); + + QMetaObject::invokeMethod(m_pBonjourInstall, "run", Qt::QueuedConnection); + + m_pDownloadMessageBox->hide(); } -bool BonjourWindows::isRunning() const -{ - QString name = "Bonjour Service"; +bool BonjourWindows::isRunning() const { + QString name = "Bonjour Service"; - SC_HANDLE hSCManager; - hSCManager = OpenSCManager(nullptr, nullptr, SC_MANAGER_CONNECT); - - if (hSCManager == nullptr) { - m_pMainWindow->appendLogError( - QString("failed to open a service controller manager, error: %1").arg(GetLastError())); - return false; - } - - auto array = name.toLocal8Bit(); - SC_HANDLE hService = OpenService(hSCManager, array.data(), SERVICE_QUERY_STATUS); - - if (hService == nullptr) { - m_pMainWindow->appendLogDebug( - QString("failed to open service: %1").arg(name)); - return false; - } - - SERVICE_STATUS status; - if (QueryServiceStatus(hService, &status)) { - if (status.dwCurrentState == SERVICE_RUNNING) { - return true; - } - } + SC_HANDLE hSCManager; + hSCManager = OpenSCManager(nullptr, nullptr, SC_MANAGER_CONNECT); + if (hSCManager == nullptr) { + m_pMainWindow->appendLogError( + QString("failed to open a service controller manager, error: %1") + .arg(GetLastError())); return false; + } + + auto array = name.toLocal8Bit(); + SC_HANDLE hService = + OpenService(hSCManager, array.data(), SERVICE_QUERY_STATUS); + + if (hService == nullptr) { + m_pMainWindow->appendLogDebug( + QString("failed to open service: %1").arg(name)); + return false; + } + + SERVICE_STATUS status; + if (QueryServiceStatus(hService, &status)) { + if (status.dwCurrentState == SERVICE_RUNNING) { + return true; + } + } + + return false; } -void BonjourWindows::installFinished() -{ - m_pMainWindow->appendLogInfo("bonjour installed"); - m_appConfig.setAutoConfig(true); - m_pSettingsDialog->allowAutoConfig(); +void BonjourWindows::installFinished() { + m_pMainWindow->appendLogInfo("bonjour installed"); + m_appConfig.setAutoConfig(true); + m_pSettingsDialog->allowAutoConfig(); } #endif // Q_OS_WIN diff --git a/src/gui/src/BonjourWindows.h b/src/gui/src/BonjourWindows.h index 7c2cbe222..5eab5371e 100644 --- a/src/gui/src/BonjourWindows.h +++ b/src/gui/src/BonjourWindows.h @@ -34,32 +34,32 @@ class CommandProcess; class DataDownloader; class AppConfig; -class BonjourWindows : public QObject -{ - Q_OBJECT +class BonjourWindows : public QObject { + Q_OBJECT public: - BonjourWindows(SettingsDialog* settingsDialog, MainWindow* mainWindow, AppConfig& appConfig); - virtual ~BonjourWindows(); + BonjourWindows(SettingsDialog *settingsDialog, MainWindow *mainWindow, + AppConfig &appConfig); + virtual ~BonjourWindows(); public: - void downloadAndInstall(); - bool isRunning() const; + void downloadAndInstall(); + bool isRunning() const; protected slots: - void downloadFinished(); - void installFinished(); + void downloadFinished(); + void installFinished(); private: - void install(); + void install(); private: - SettingsDialog* m_pSettingsDialog; - MainWindow* m_pMainWindow; - CommandProcess* m_pBonjourInstall; - QMessageBox* m_pDownloadMessageBox; - DataDownloader* m_pDataDownloader; - AppConfig& m_appConfig; + SettingsDialog *m_pSettingsDialog; + MainWindow *m_pMainWindow; + CommandProcess *m_pBonjourInstall; + QMessageBox *m_pDownloadMessageBox; + DataDownloader *m_pDataDownloader; + AppConfig &m_appConfig; }; #endif // Q_OS_WIN diff --git a/src/gui/src/CancelActivationDialog.cpp b/src/gui/src/CancelActivationDialog.cpp index 3397309e2..95c62cde2 100644 --- a/src/gui/src/CancelActivationDialog.cpp +++ b/src/gui/src/CancelActivationDialog.cpp @@ -1,14 +1,9 @@ #include "CancelActivationDialog.h" #include "ui_CancelActivationDialog.h" -CancelActivationDialog::CancelActivationDialog(QWidget *parent) : - QDialog(parent), - ui(new Ui::CancelActivationDialog) -{ - ui->setupUi(this); +CancelActivationDialog::CancelActivationDialog(QWidget *parent) + : QDialog(parent), ui(new Ui::CancelActivationDialog) { + ui->setupUi(this); } -CancelActivationDialog::~CancelActivationDialog() -{ - delete ui; -} +CancelActivationDialog::~CancelActivationDialog() { delete ui; } diff --git a/src/gui/src/CancelActivationDialog.h b/src/gui/src/CancelActivationDialog.h index bd387186d..a37f53b15 100644 --- a/src/gui/src/CancelActivationDialog.h +++ b/src/gui/src/CancelActivationDialog.h @@ -7,16 +7,15 @@ namespace Ui { class CancelActivationDialog; } -class CancelActivationDialog : public QDialog -{ - Q_OBJECT - +class CancelActivationDialog : public QDialog { + Q_OBJECT + public: - explicit CancelActivationDialog(QWidget *parent = 0); - ~CancelActivationDialog(); - + explicit CancelActivationDialog(QWidget *parent = 0); + ~CancelActivationDialog(); + private: - Ui::CancelActivationDialog *ui; + Ui::CancelActivationDialog *ui; }; #endif // CANCELACTIVATIONDIALOG_H diff --git a/src/gui/src/ClientConnection.cpp b/src/gui/src/ClientConnection.cpp index 22b62c376..fb25b0eeb 100644 --- a/src/gui/src/ClientConnection.cpp +++ b/src/gui/src/ClientConnection.cpp @@ -20,78 +20,65 @@ #include "MainWindow.h" -#include #include +#include -ClientConnection::ClientConnection(MainWindow& parent) : - m_parent(parent) -{ -} +ClientConnection::ClientConnection(MainWindow &parent) : m_parent(parent) {} -void ClientConnection::update(const QString& line) -{ - if (m_checkConnection && checkMainWindow()) - { - if (line.contains("failed to connect to server")) - { - m_checkConnection = false; - if (!line.contains("server refused client with our name") && - !line.contains("Trying next address")) - { - showMessage(getMessage(line)); - } - } - else if (line.contains("connected to server")) - { - m_checkConnection = false; - } +void ClientConnection::update(const QString &line) { + if (m_checkConnection && checkMainWindow()) { + if (line.contains("failed to connect to server")) { + m_checkConnection = false; + if (!line.contains("server refused client with our name") && + !line.contains("Trying next address")) { + showMessage(getMessage(line)); + } + } else if (line.contains("connected to server")) { + m_checkConnection = false; } + } } -bool ClientConnection::checkMainWindow() -{ - bool result = m_parent.isActiveWindow(); +bool ClientConnection::checkMainWindow() { + bool result = m_parent.isActiveWindow(); - if (m_parent.isMinimized() || m_parent.isHidden()) - { - m_parent.showNormal(); - m_parent.activateWindow(); - result = true; + if (m_parent.isMinimized() || m_parent.isHidden()) { + m_parent.showNormal(); + m_parent.activateWindow(); + result = true; + } + + return result; +} + +QString ClientConnection::getMessage(const QString &line) const { + QString message(QObject::tr("Connection failed.\nCheck the IP address on the " + "server, your TLS and firewall settings.")); + + if (line.contains("server already has a connected client with our name")) { + message = + QObject::tr("Connection failed.\nYou can’t name 2 computers the same."); + } else { + QHostAddress address(m_parent.appConfig().getServerHostname()); + if (address.isNull()) { + message = + QObject::tr( + "We can’t connect to the server \"%1\" try to connect using the " + "server IP address and check your firewall settings.") + .arg(m_parent.appConfig().getServerHostname()); } + } - return result; + return message; } -QString ClientConnection::getMessage(const QString& line) const -{ - QString message(QObject::tr("Connection failed.\nCheck the IP address on the server, your TLS and firewall settings.")); - - if (line.contains("server already has a connected client with our name")) - { - message = QObject::tr("Connection failed.\nYou can’t name 2 computers the same."); - } - else - { - QHostAddress address(m_parent.appConfig().getServerHostname()); - if (address.isNull()) - { - message = QObject::tr("We can’t connect to the server \"%1\" try to connect using the server IP address and check your firewall settings.") - .arg(m_parent.appConfig().getServerHostname()); - } - } - - return message; +void ClientConnection::showMessage(const QString &message) const { + QMessageBox dialog(&m_parent); + dialog.addButton(QObject::tr("Close"), QMessageBox::RejectRole); + dialog.setText(message); + dialog.exec(); } -void ClientConnection::showMessage(const QString& message) const -{ - QMessageBox dialog(&m_parent); - dialog.addButton(QObject::tr("Close"), QMessageBox::RejectRole); - dialog.setText(message); - dialog.exec(); -} - -void ClientConnection::setCheckConnection(bool checkConnection) -{ - m_checkConnection = checkConnection; +void ClientConnection::setCheckConnection(bool checkConnection) { + m_checkConnection = checkConnection; } diff --git a/src/gui/src/ClientConnection.h b/src/gui/src/ClientConnection.h index abe5ba3a1..6e5803953 100644 --- a/src/gui/src/ClientConnection.h +++ b/src/gui/src/ClientConnection.h @@ -23,20 +23,19 @@ class MainWindow; -class ClientConnection -{ - MainWindow& m_parent; - bool m_checkConnection = false; +class ClientConnection { + MainWindow &m_parent; + bool m_checkConnection = false; public: - explicit ClientConnection(MainWindow& parent); - void update(const QString& line); - void setCheckConnection(bool checkConnection); + explicit ClientConnection(MainWindow &parent); + void update(const QString &line); + void setCheckConnection(bool checkConnection); private: - QString getMessage(const QString& line) const; - bool checkMainWindow(); - void showMessage(const QString& message) const; + QString getMessage(const QString &line) const; + bool checkMainWindow(); + void showMessage(const QString &message) const; }; #endif // CLIENTCONNECTION_H diff --git a/src/gui/src/CommandProcess.cpp b/src/gui/src/CommandProcess.cpp index e86d5a30f..3b2fc7210 100644 --- a/src/gui/src/CommandProcess.cpp +++ b/src/gui/src/CommandProcess.cpp @@ -20,44 +20,38 @@ #include #include -CommandProcess::CommandProcess(QString cmd, QStringList arguments, QString input) : - m_Command(cmd), - m_Arguments(arguments), - m_Input(input) -{ -} +CommandProcess::CommandProcess(QString cmd, QStringList arguments, + QString input) + : m_Command(cmd), m_Arguments(arguments), m_Input(input) {} -QString CommandProcess::run() -{ - QProcess process; - process.setReadChannel(QProcess::StandardOutput); - process.start(m_Command, m_Arguments); - bool success = process.waitForStarted(); +QString CommandProcess::run() { + QProcess process; + process.setReadChannel(QProcess::StandardOutput); + process.start(m_Command, m_Arguments); + bool success = process.waitForStarted(); - QString output, error; - if (success) - { - if (!m_Input.isEmpty()) { - process.write(m_Input.toStdString().c_str()); - } - - if (process.waitForFinished()) { - output = QString::fromLocal8Bit(process.readAllStandardOutput().trimmed()); - error = process.readAllStandardError().trimmed(); - } + QString output, error; + if (success) { + if (!m_Input.isEmpty()) { + process.write(m_Input.toStdString().c_str()); } - int code = process.exitCode(); - if (!error.isEmpty() || !success || code != 0) - { - throw std::runtime_error( - QString("Code: %1\nError: %2") - .arg(process.exitCode()) - .arg(error.isEmpty() ? "Unknown" : error) - .toStdString()); + if (process.waitForFinished()) { + output = + QString::fromLocal8Bit(process.readAllStandardOutput().trimmed()); + error = process.readAllStandardError().trimmed(); } + } - emit finished(); + int code = process.exitCode(); + if (!error.isEmpty() || !success || code != 0) { + throw std::runtime_error(QString("Code: %1\nError: %2") + .arg(process.exitCode()) + .arg(error.isEmpty() ? "Unknown" : error) + .toStdString()); + } - return output; + emit finished(); + + return output; } diff --git a/src/gui/src/CommandProcess.h b/src/gui/src/CommandProcess.h index 623979070..98eb4aecd 100644 --- a/src/gui/src/CommandProcess.h +++ b/src/gui/src/CommandProcess.h @@ -21,23 +21,22 @@ #include #include -class CommandProcess : public QObject -{ - Q_OBJECT +class CommandProcess : public QObject { + Q_OBJECT public: - CommandProcess(QString cmd, QStringList arguments, QString input = ""); + CommandProcess(QString cmd, QStringList arguments, QString input = ""); signals: - void finished(); + void finished(); public slots: - QString run(); + QString run(); private: - QString m_Command; - QStringList m_Arguments; - QString m_Input; + QString m_Command; + QStringList m_Arguments; + QString m_Input; }; #endif // COMMANDTHREAD_H diff --git a/src/gui/src/ConfigBase.h b/src/gui/src/ConfigBase.h index 5ea7389ec..49ac9ee99 100644 --- a/src/gui/src/ConfigBase.h +++ b/src/gui/src/ConfigBase.h @@ -19,30 +19,33 @@ #define SYNERGY_CORE_CONFIGBASE_H namespace GUI { - namespace Config { +namespace Config { - ///@brief This abstract class will be used by all classes that use the ConfigWriter - /// to allow global saving and loading - class ConfigBase { - public : - ConfigBase() = default; +///@brief This abstract class will be used by all classes that use the +/// ConfigWriter +/// to allow global saving and loading +class ConfigBase { +public: + ConfigBase() = default; - virtual ~ConfigBase() = default; + virtual ~ConfigBase() = default; - /// @brief The function that is called when the settings need to be loaded from file - virtual void loadSettings() = 0; + /// @brief The function that is called when the settings need to be loaded + /// from file + virtual void loadSettings() = 0; - /// @brief The function that is called when the settings need to be saved to file - virtual void saveSettings() = 0; + /// @brief The function that is called when the settings need to be saved to + /// file + virtual void saveSettings() = 0; - /// @brief Returns true if the class has marked itself with having unsaved changes - bool modified() const { return m_unsavedChanges; } + /// @brief Returns true if the class has marked itself with having unsaved + /// changes + bool modified() const { return m_unsavedChanges; } - protected: - /// @brief Does the class have unsaved changes in it. - bool m_unsavedChanges = false; - - }; - } -} -#endif //SYNERGY_CORE_CONFIGBASE_H +protected: + /// @brief Does the class have unsaved changes in it. + bool m_unsavedChanges = false; +}; +} // namespace Config +} // namespace GUI +#endif // SYNERGY_CORE_CONFIGBASE_H diff --git a/src/gui/src/ConfigWriter.cpp b/src/gui/src/ConfigWriter.cpp index 1d61ccbc7..4d1a9c5f5 100644 --- a/src/gui/src/ConfigWriter.cpp +++ b/src/gui/src/ConfigWriter.cpp @@ -20,207 +20,193 @@ #include #include -#include "ConfigWriter.h" #include "ConfigBase.h" +#include "ConfigWriter.h" namespace { -QString getSystemSettingPath() -{ - const QString settingFilename("SystemConfig.ini"); - QString path; +QString getSystemSettingPath() { + const QString settingFilename("SystemConfig.ini"); + QString path; #if defined(Q_OS_WIN) - // Program file - path = QCoreApplication::applicationDirPath() + "\\"; + // Program file + path = QCoreApplication::applicationDirPath() + "\\"; #elif defined(Q_OS_DARWIN) - //Global preferances dir - // Would be nice to use /library, but QT has no elevate system in place - path = "/usr/local/etc/symless/"; + // Global preferances dir + // Would be nice to use /library, but QT has no elevate system in place + path = "/usr/local/etc/symless/"; #elif defined(Q_OS_LINUX) - // QT adds application and filename to the end of the path already on linux - path = "/usr/local/etc/symless/"; - return path; + // QT adds application and filename to the end of the path already on linux + path = "/usr/local/etc/symless/"; + return path; #else - assert("OS not supported"); + assert("OS not supported"); #endif - return path + settingFilename; + return path + settingFilename; } #if defined(Q_OS_WIN) -void loadOldSystemSettings(QSettings& settings) -{ - if (!QFile(settings.fileName()).exists()) { - QSettings::setPath(QSettings::IniFormat, QSettings::SystemScope, "SystemConfig.ini"); - QSettings oldSystemSettings (QSettings::IniFormat, - QSettings::SystemScope, - QCoreApplication::organizationName(), - QCoreApplication::applicationName()); +void loadOldSystemSettings(QSettings &settings) { + if (!QFile(settings.fileName()).exists()) { + QSettings::setPath(QSettings::IniFormat, QSettings::SystemScope, + "SystemConfig.ini"); + QSettings oldSystemSettings(QSettings::IniFormat, QSettings::SystemScope, + QCoreApplication::organizationName(), + QCoreApplication::applicationName()); - if (QFile(oldSystemSettings.fileName()).exists()) { - for (const auto& key : oldSystemSettings.allKeys()) { - settings.setValue(key, oldSystemSettings.value(key)); - } - } - - //Restore system settings path - QSettings::setPath(QSettings::IniFormat, QSettings::SystemScope, getSystemSettingPath()); + if (QFile(oldSystemSettings.fileName()).exists()) { + for (const auto &key : oldSystemSettings.allKeys()) { + settings.setValue(key, oldSystemSettings.value(key)); + } } + + // Restore system settings path + QSettings::setPath(QSettings::IniFormat, QSettings::SystemScope, + getSystemSettingPath()); + } } #endif -} +} // namespace namespace GUI { - namespace Config { - //Assignment of static variable - ConfigWriter *ConfigWriter::s_pConfiguration = nullptr; +namespace Config { +// Assignment of static variable +ConfigWriter *ConfigWriter::s_pConfiguration = nullptr; - - ConfigWriter *ConfigWriter::make() { - // Only one ConfigWriter can exist at any one time (Singleton) - if (!s_pConfiguration) { - s_pConfiguration = new ConfigWriter(); - } - return s_pConfiguration; - } - - ConfigWriter::ConfigWriter() { - QSettings::setPath(QSettings::Format::IniFormat, - QSettings::Scope::SystemScope, - getSystemSettingPath()); - - //Config will default to User settings if they exist, - // otherwise it will load System setting and save them to User settings - m_pSettingsSystem = new QSettings(QSettings::Format::IniFormat, - QSettings::Scope::SystemScope, - QCoreApplication::organizationName(), - QCoreApplication::applicationName()); - - #if defined(Q_OS_WIN) - //This call is needed for backwardcapability with old settings. - loadOldSystemSettings(*m_pSettingsSystem); - #endif - - //defaults to user scope, if we set the scope specifically then we also have to set - // the application name and the organisation name which breaks backwards compatibility - // See #6730 - m_pSettingsUser = new QSettings(); - - //Set scope to user for initially - m_pSettingsCurrent = m_pSettingsUser; - } - - - void ConfigWriter::destroy() { - destroy(s_pConfiguration); - } - - ConfigWriter::~ConfigWriter() { - while(!m_pCallerList.empty()) { - m_pCallerList.pop_back(); - } - m_pSettingsCurrent = nullptr; //this only references other pointers - destroy(m_pSettingsSystem); - destroy(m_pSettingsUser); - } - - - bool ConfigWriter::hasSetting(const QString &name, Scope scope) const { - switch (scope){ - case kUser: - return m_pSettingsUser->contains(name); - case kSystem: - return m_pSettingsSystem->contains(name); - default: - return m_pSettingsCurrent->contains(name); - } - } - - bool ConfigWriter::isWritable() const { - return m_pSettingsCurrent->isWritable(); - } - - QVariant ConfigWriter::loadSetting(const QString& name, const QVariant &defaultValue, Scope scope) { - switch (scope){ - case kUser: - return m_pSettingsUser->value(name, defaultValue); - case kSystem: - return m_pSettingsSystem->value(name, defaultValue); - default: - return m_pSettingsCurrent->value(name, defaultValue); - } - } - - - void ConfigWriter::setScope(ConfigWriter::Scope scope) { - if (m_CurrentScope != scope) { - m_CurrentScope = scope; - switch (scope) { - case kUser: - m_pSettingsCurrent = m_pSettingsUser; - break; - case kSystem: - m_pSettingsCurrent = m_pSettingsSystem; - break; - default: - //setScope should never be kCurrent - assert(scope); - } - } - } - - ConfigWriter::Scope ConfigWriter::getScope() const { - return m_CurrentScope; - } - - void ConfigWriter::globalLoad() { - for (auto &i : m_pCallerList) { - i->loadSettings(); - } - } - - void ConfigWriter::globalSave() { - - //Save if there are any unsaved changes otherwise skip - if (unsavedChanges()) { - for (auto &i : m_pCallerList) { - i->saveSettings(); - } - - m_pSettingsUser->sync(); - m_pSettingsSystem->sync(); - - m_unsavedChanges = false; - } - } - - QSettings &ConfigWriter::settings() { - return *m_pSettingsCurrent; - } - - void ConfigWriter::registerClass(ConfigBase * receiver) { - m_pCallerList.push_back(receiver); - } - - - - bool ConfigWriter::unsavedChanges() const { - if (m_unsavedChanges) { - return true; - } - - for (const auto &i : m_pCallerList) { - if (i->modified()){ - //If any class returns true there is no point checking more - return true; - } - } - // If this line is reached no class has unsaved changes - return false; - } - - void ConfigWriter::markUnsaved() { - m_unsavedChanges = true; - } - } +ConfigWriter *ConfigWriter::make() { + // Only one ConfigWriter can exist at any one time (Singleton) + if (!s_pConfiguration) { + s_pConfiguration = new ConfigWriter(); + } + return s_pConfiguration; } + +ConfigWriter::ConfigWriter() { + QSettings::setPath(QSettings::Format::IniFormat, + QSettings::Scope::SystemScope, getSystemSettingPath()); + + // Config will default to User settings if they exist, + // otherwise it will load System setting and save them to User settings + m_pSettingsSystem = + new QSettings(QSettings::Format::IniFormat, QSettings::Scope::SystemScope, + QCoreApplication::organizationName(), + QCoreApplication::applicationName()); + +#if defined(Q_OS_WIN) + // This call is needed for backwardcapability with old settings. + loadOldSystemSettings(*m_pSettingsSystem); +#endif + + // defaults to user scope, if we set the scope specifically then we also have + // to set + // the application name and the organisation name which breaks backwards + // compatibility See #6730 + m_pSettingsUser = new QSettings(); + + // Set scope to user for initially + m_pSettingsCurrent = m_pSettingsUser; +} + +void ConfigWriter::destroy() { destroy(s_pConfiguration); } + +ConfigWriter::~ConfigWriter() { + while (!m_pCallerList.empty()) { + m_pCallerList.pop_back(); + } + m_pSettingsCurrent = nullptr; // this only references other pointers + destroy(m_pSettingsSystem); + destroy(m_pSettingsUser); +} + +bool ConfigWriter::hasSetting(const QString &name, Scope scope) const { + switch (scope) { + case kUser: + return m_pSettingsUser->contains(name); + case kSystem: + return m_pSettingsSystem->contains(name); + default: + return m_pSettingsCurrent->contains(name); + } +} + +bool ConfigWriter::isWritable() const { + return m_pSettingsCurrent->isWritable(); +} + +QVariant ConfigWriter::loadSetting(const QString &name, + const QVariant &defaultValue, Scope scope) { + switch (scope) { + case kUser: + return m_pSettingsUser->value(name, defaultValue); + case kSystem: + return m_pSettingsSystem->value(name, defaultValue); + default: + return m_pSettingsCurrent->value(name, defaultValue); + } +} + +void ConfigWriter::setScope(ConfigWriter::Scope scope) { + if (m_CurrentScope != scope) { + m_CurrentScope = scope; + switch (scope) { + case kUser: + m_pSettingsCurrent = m_pSettingsUser; + break; + case kSystem: + m_pSettingsCurrent = m_pSettingsSystem; + break; + default: + // setScope should never be kCurrent + assert(scope); + } + } +} + +ConfigWriter::Scope ConfigWriter::getScope() const { return m_CurrentScope; } + +void ConfigWriter::globalLoad() { + for (auto &i : m_pCallerList) { + i->loadSettings(); + } +} + +void ConfigWriter::globalSave() { + + // Save if there are any unsaved changes otherwise skip + if (unsavedChanges()) { + for (auto &i : m_pCallerList) { + i->saveSettings(); + } + + m_pSettingsUser->sync(); + m_pSettingsSystem->sync(); + + m_unsavedChanges = false; + } +} + +QSettings &ConfigWriter::settings() { return *m_pSettingsCurrent; } + +void ConfigWriter::registerClass(ConfigBase *receiver) { + m_pCallerList.push_back(receiver); +} + +bool ConfigWriter::unsavedChanges() const { + if (m_unsavedChanges) { + return true; + } + + for (const auto &i : m_pCallerList) { + if (i->modified()) { + // If any class returns true there is no point checking more + return true; + } + } + // If this line is reached no class has unsaved changes + return false; +} + +void ConfigWriter::markUnsaved() { m_unsavedChanges = true; } +} // namespace Config +} // namespace GUI diff --git a/src/gui/src/ConfigWriter.h b/src/gui/src/ConfigWriter.h index da70942d3..bddbd59d0 100644 --- a/src/gui/src/ConfigWriter.h +++ b/src/gui/src/ConfigWriter.h @@ -17,133 +17,141 @@ #ifndef SYNERGY_CORE_CONFIGWRITER_H #define SYNERGY_CORE_CONFIGWRITER_H -#include #include +#include /// @brief Contains GUI code namespace GUI { - /// @brief Contains Configuration code - namespace Config { +/// @brief Contains Configuration code +namespace Config { - //Forward declare the class referenced by pointer - class ConfigBase; +// Forward declare the class referenced by pointer +class ConfigBase; - class ConfigWriter: private QObject { +class ConfigWriter : private QObject { - public: +public: + /// @brief the public way to construct the configuration calls + /// The pointer returned is owned by this class and should not be + /// stored by other classes. + static ConfigWriter *make(); - /// @brief the public way to construct the configuration calls - /// The pointer returned is owned by this class and should not be stored - /// by other classes. - static ConfigWriter* make(); + /// @brief the public way to destroy the configuration class + static void destroy(); - /// @brief the public way to destroy the configuration class - static void destroy(); + ~ConfigWriter() override; - ~ConfigWriter() override; + ///@brief An Enumeration of all the scopes available + enum Scope { kCurrent, kSystem, kUser }; - ///@brief An Enumeration of all the scopes available - enum Scope { kCurrent, kSystem, kUser}; + /// @brief Checks if the setting exists + /// @param [in] name The name of the setting to check + /// @param [in] scope The scope to search in + /// @return bool True if the current scope has the named setting + bool hasSetting(const QString &name, Scope scope = kCurrent) const; - /// @brief Checks if the setting exists - /// @param [in] name The name of the setting to check - /// @param [in] scope The scope to search in - /// @return bool True if the current scope has the named setting - bool hasSetting(const QString& name, Scope scope = kCurrent) const; + /// @brief Checks if the current scope settings writable + /// @return bool True if the current scope writable + bool isWritable() const; - /// @brief Checks if the current scope settings writable - /// @return bool True if the current scope writable - bool isWritable() const; + /// @brief Sets the value of a setting + /// @param [in] name The Setting to be saved + /// @param [in] value The Value to be saved (Templated) + /// @param [in] scope The scope to get the value from, default is current + /// scope + template + void setSetting(const QString &name, T value, Scope scope = kCurrent); - /// @brief Sets the value of a setting - /// @param [in] name The Setting to be saved - /// @param [in] value The Value to be saved (Templated) - /// @param [in] scope The scope to get the value from, default is current scope - template - void setSetting(const QString& name, T value, Scope scope = kCurrent); + /// @brief Loads a setting + /// @param [in] name The setting to be loaded + /// @param [in] defaultValue The default value of the setting + /// @param [in] scope The scope to get the value from, default is current + /// scope + QVariant loadSetting(const QString &name, + const QVariant &defaultValue = QVariant(), + Scope scope = kCurrent); - /// @brief Loads a setting - /// @param [in] name The setting to be loaded - /// @param [in] defaultValue The default value of the setting - /// @param [in] scope The scope to get the value from, default is current scope - QVariant loadSetting(const QString& name, const QVariant& defaultValue = QVariant(), Scope scope = kCurrent); + /// @brief Changes the setting save and load location between System and User + /// scope + /// @param [in] scope The scope to set + void setScope(Scope scope = kUser); - /// @brief Changes the setting save and load location between System and User scope - /// @param [in] scope The scope to set - void setScope(Scope scope = kUser); + /// @brief Get the current scope the settings are loading and save from. + /// @return Scope An enum defining the current scope + Scope getScope() const; - /// @brief Get the current scope the settings are loading and save from. - /// @return Scope An enum defining the current scope - Scope getScope() const; + /// @brief trigger a config load across all registered classes + void globalLoad(); - /// @brief trigger a config load across all registered classes - void globalLoad(); + /// @brief trigger a config save across all registered classes + void globalSave(); - /// @brief trigger a config save across all registered classes - void globalSave(); + /// @brief Returns the current scopes settings object + /// If more specialize control into the settings is needed this can + /// provide direct access to the settings file handler + /// @return QSettings The Settings object as a reference + QSettings &settings(); - /// @brief Returns the current scopes settings object - /// If more specialize control into the settings is needed this can provide - /// direct access to the settings file handler - /// @return QSettings The Settings object as a reference - QSettings& settings(); + /// @brief This marks the settings as unsaved if the settings() was used to + /// directly affect the config file + void markUnsaved(); - /// @brief This marks the settings as unsaved if the settings() was used to directly affect the config file - void markUnsaved(); + /// @brief Register a class to receives globalLoad and globalSave events + /// @param [in] ConfigBase The class that will receive the events + void registerClass(ConfigBase *receiver); - /// @brief Register a class to receives globalLoad and globalSave events - /// @param [in] ConfigBase The class that will receive the events - void registerClass(ConfigBase* receiver); + /// @brief Checks if any registered class has any unsaved changes + /// @return bool True if any registered class has unsaved changes + bool unsavedChanges() const; - /// @brief Checks if any registered class has any unsaved changes - /// @return bool True if any registered class has unsaved changes - bool unsavedChanges() const; +protected: + Scope m_CurrentScope = kUser; /// @brief The current scope of the settings - protected: + QSettings *m_pSettingsCurrent = + nullptr; /// @brief The currently active settings + QSettings *m_pSettingsUser = nullptr; /// @brief The user specific settings + QSettings *m_pSettingsSystem = nullptr; /// @brief The system wide settings - Scope m_CurrentScope = kUser; /// @brief The current scope of the settings +private: + /// @brief Contains a list all all classes that hook into the writer. + /// This allows all classes that save settings to be called an updated + /// on a save and reload by any other class + std::list m_pCallerList; - QSettings* m_pSettingsCurrent = nullptr; /// @brief The currently active settings - QSettings* m_pSettingsUser = nullptr; /// @brief The user specific settings - QSettings* m_pSettingsSystem = nullptr; /// @brief The system wide settings + /// @brief if this class modified settings then set the flag + bool m_unsavedChanges = false; - private: + /// @brief The constructor, as this is a singolton we want to control who can + /// call the constructor + ConfigWriter(); - /// @brief Contains a list all all classes that hook into the writer. - /// This allows all classes that save settings to be called an updated - /// on a save and reload by any other class - std::list m_pCallerList; + /// @brief the pointer of the ConfigWriter for singolton use + static ConfigWriter *s_pConfiguration; - /// @brief if this class modified settings then set the flag - bool m_unsavedChanges = false; + /// @brief deletes pointers and sets the value to null + template static inline void destroy(T *&p) { + delete p; + p = 0; + } +}; - /// @brief The constructor, as this is a singolton we want to control who can call the constructor - ConfigWriter(); - - /// @brief the pointer of the ConfigWriter for singolton use - static ConfigWriter* s_pConfiguration; - - /// @brief deletes pointers and sets the value to null - template static inline void destroy(T*& p) { delete p; p = 0; } - }; - - // Implementation of a template function needs to be visible to all calls thus is must be in the header - // Moved so its not bulking out the class definition - template - void ConfigWriter::setSetting(const QString& name, T value, Scope scope) { - switch (scope){ - case kUser: - m_pSettingsUser->setValue(name, value); - break; - case kSystem: - m_pSettingsSystem->setValue(name, value); - break; - default: - m_pSettingsCurrent->setValue(name, value); - break; - } - m_unsavedChanges = true; - } - } +// Implementation of a template function needs to be visible to all calls thus +// is must be in the header Moved so its not bulking out the class definition +template +void ConfigWriter::setSetting(const QString &name, T value, Scope scope) { + switch (scope) { + case kUser: + m_pSettingsUser->setValue(name, value); + break; + case kSystem: + m_pSettingsSystem->setValue(name, value); + break; + default: + m_pSettingsCurrent->setValue(name, value); + break; + } + m_unsavedChanges = true; } -#endif //SYNERGY_CORE_CONFIGWRITER_H +} // namespace Config +} // namespace GUI +#endif // SYNERGY_CORE_CONFIGWRITER_H diff --git a/src/gui/src/CoreInterface.cpp b/src/gui/src/CoreInterface.cpp index 38f09f07c..6b9c6b7fd 100644 --- a/src/gui/src/CoreInterface.cpp +++ b/src/gui/src/CoreInterface.cpp @@ -21,9 +21,9 @@ #include "QUtility.h" #include +#include #include #include -#include #include static const char kCoreBinary[] = "syntool"; @@ -34,40 +34,31 @@ static const char kSerialKeyFilename[] = "Synergy.subkey"; static const char kSerialKeyFilename[] = ".synergy.subkey"; #endif -CoreInterface::CoreInterface() -{ +CoreInterface::CoreInterface() {} + +QString CoreInterface::getProfileDir() { + QStringList args("--get-profile-dir"); + return run(args); } -QString CoreInterface::getProfileDir() -{ - QStringList args("--get-profile-dir"); - return run(args); +QString CoreInterface::getInstalledDir() { + QStringList args("--get-installed-dir"); + return run(args); } -QString CoreInterface::getInstalledDir() -{ - QStringList args("--get-installed-dir"); - return run(args); +QString CoreInterface::getArch() { + QStringList args("--get-arch"); + return run(args); } -QString CoreInterface::getArch() -{ - QStringList args("--get-arch"); - return run(args); +QString CoreInterface::getSerialKeyFilePath() { + QString filename = getProfileDir() + QDir::separator() + kSerialKeyFilename; + return filename; } -QString CoreInterface::getSerialKeyFilePath() -{ - QString filename = getProfileDir() + QDir::separator() + kSerialKeyFilename; - return filename; -} +QString CoreInterface::run(const QStringList &args, const QString &input) { + QString program(QCoreApplication::applicationDirPath() + "/" + kCoreBinary); -QString CoreInterface::run(const QStringList& args, const QString& input) -{ - QString program( - QCoreApplication::applicationDirPath() - + "/" + kCoreBinary); - - CommandProcess commandProcess(program, args, input); - return commandProcess.run(); + CommandProcess commandProcess(program, args, input); + return commandProcess.run(); } diff --git a/src/gui/src/CoreInterface.h b/src/gui/src/CoreInterface.h index ce8bf1a78..ffce03747 100644 --- a/src/gui/src/CoreInterface.h +++ b/src/gui/src/CoreInterface.h @@ -19,14 +19,13 @@ #include -class CoreInterface -{ +class CoreInterface { public: - CoreInterface(); + CoreInterface(); - QString getProfileDir(); - QString getInstalledDir(); - QString getArch(); - QString getSerialKeyFilePath(); - QString run(const QStringList& args, const QString& input = ""); + QString getProfileDir(); + QString getInstalledDir(); + QString getArch(); + QString getSerialKeyFilePath(); + QString run(const QStringList &args, const QString &input = ""); }; diff --git a/src/gui/src/CreditsLoader.cpp b/src/gui/src/CreditsLoader.cpp index 5b8c7b37b..090e36ae4 100644 --- a/src/gui/src/CreditsLoader.cpp +++ b/src/gui/src/CreditsLoader.cpp @@ -16,93 +16,83 @@ */ #include "CreditsLoader.h" -#include "MainWindow.h" #include "AppConfig.h" +#include "MainWindow.h" -#include -#include #include #include +#include +#include namespace { class CreditsResponse { public: - explicit CreditsResponse(const QByteArray& response) { - auto data = parseJson(response); - m_status = data["status"].toString(); + explicit CreditsResponse(const QByteArray &response) { + auto data = parseJson(response); + m_status = data["status"].toString(); - if (isSuccess()) { - m_data = data["data"].toString(); - } - else if (isFailed()) { - m_data = data["message"].toString(); - } - else { - m_data = "Unknown response from the server"; - } + if (isSuccess()) { + m_data = data["data"].toString(); + } else if (isFailed()) { + m_data = data["message"].toString(); + } else { + m_data = "Unknown response from the server"; } + } - bool isSuccess() const { - return (m_status == "success"); - } + bool isSuccess() const { return (m_status == "success"); } - bool isFailed() const { - return (m_status == "failed"); - } + bool isFailed() const { return (m_status == "failed"); } - const QString& getData() const { - return m_data; - } + const QString &getData() const { return m_data; } private: - QMap parseJson(const QByteArray& json) const { - QJsonParseError jsonError; - auto data = QJsonDocument::fromJson(json, &jsonError); - if (jsonError.error == QJsonParseError::NoError) { - return data.toVariant().toMap(); - } - return QMap(); + QMap parseJson(const QByteArray &json) const { + QJsonParseError jsonError; + auto data = QJsonDocument::fromJson(json, &jsonError); + if (jsonError.error == QJsonParseError::NoError) { + return data.toVariant().toMap(); } + return QMap(); + } - QString m_data; - QString m_status; + QString m_data; + QString m_status; }; +} // namespace + +CreditsLoader::CreditsLoader(MainWindow &mainWindow, const AppConfig &config) + : m_mainWindow(mainWindow), m_config(config) { + connect(&m_manager, SIGNAL(finished(QNetworkReply *)), this, + SLOT(replyFinished(QNetworkReply *))); } -CreditsLoader::CreditsLoader(MainWindow& mainWindow, const AppConfig& config) : - m_mainWindow(mainWindow), - m_config(config) -{ - connect(&m_manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(replyFinished(QNetworkReply*))); +void CreditsLoader::loadEliteBackers() { + const auto ELITE_BACKERS_URL = m_config.getEliteBackersUrl(); + m_mainWindow.appendLogDebug( + QString("Send request: %1").arg(ELITE_BACKERS_URL)); + const auto url = QUrl(ELITE_BACKERS_URL); + const auto request = QNetworkRequest(url); + m_manager.get(request); } -void CreditsLoader::loadEliteBackers() -{ - const auto ELITE_BACKERS_URL = m_config.getEliteBackersUrl(); - m_mainWindow.appendLogDebug(QString("Send request: %1").arg(ELITE_BACKERS_URL)); - const auto url = QUrl(ELITE_BACKERS_URL); - const auto request = QNetworkRequest(url); - m_manager.get(request); +void CreditsLoader::replyFinished(QNetworkReply *reply) const { + auto response = reply->readAll(); + m_mainWindow.appendLogDebug( + QString("Received response: %1").arg(response.toStdString().c_str())); + + CreditsResponse creditsResponse(response); + if (creditsResponse.isSuccess()) { + emit loaded(creditsResponse.getData()); + } else { + error(QString("Server error: %1").arg(creditsResponse.getData())); + } } -void CreditsLoader::replyFinished(QNetworkReply* reply) const -{ - auto response = reply->readAll(); - m_mainWindow.appendLogDebug(QString("Received response: %1").arg(response.toStdString().c_str())); - - CreditsResponse creditsResponse(response); - if (creditsResponse.isSuccess()) { - emit loaded(creditsResponse.getData()); - } - else { - error(QString("Server error: %1").arg(creditsResponse.getData())); - } -} - -void CreditsLoader::error(const QString& error) const -{ - m_mainWindow.appendLogError(error); - emit loaded("Something went wrong when retrieving the list of Elite Backers. Check the logs for more info."); +void CreditsLoader::error(const QString &error) const { + m_mainWindow.appendLogError(error); + emit loaded("Something went wrong when retrieving the list of Elite Backers. " + "Check the logs for more info."); } diff --git a/src/gui/src/CreditsLoader.h b/src/gui/src/CreditsLoader.h index 8ab4df6ff..0eba8a7b6 100644 --- a/src/gui/src/CreditsLoader.h +++ b/src/gui/src/CreditsLoader.h @@ -16,30 +16,29 @@ */ #pragma once -#include #include +#include class QNetworkReply; class MainWindow; class AppConfig; -class CreditsLoader : public QObject -{ - Q_OBJECT +class CreditsLoader : public QObject { + Q_OBJECT public: - explicit CreditsLoader(MainWindow& mainWindow, const AppConfig& config); - void loadEliteBackers(); + explicit CreditsLoader(MainWindow &mainWindow, const AppConfig &config); + void loadEliteBackers(); signals: - void loaded(const QString& eliteBakers) const; + void loaded(const QString &eliteBakers) const; public slots: - void replyFinished(QNetworkReply* reply) const; + void replyFinished(QNetworkReply *reply) const; private: - MainWindow& m_mainWindow; - const AppConfig& m_config; - QNetworkAccessManager m_manager; + MainWindow &m_mainWindow; + const AppConfig &m_config; + QNetworkAccessManager m_manager; - void error(const QString& error) const; + void error(const QString &error) const; }; diff --git a/src/gui/src/DataDownloader.cpp b/src/gui/src/DataDownloader.cpp index 215adc8fd..5b81d86c3 100644 --- a/src/gui/src/DataDownloader.cpp +++ b/src/gui/src/DataDownloader.cpp @@ -17,45 +17,34 @@ #include "DataDownloader.h" -DataDownloader::DataDownloader(QObject* parent) : - QObject(parent), - m_pReply(nullptr), - m_IsFinished(false) -{ - connect(&m_NetworkManager, SIGNAL(finished(QNetworkReply*)), - SLOT(complete(QNetworkReply*))); +DataDownloader::DataDownloader(QObject *parent) + : QObject(parent), m_pReply(nullptr), m_IsFinished(false) { + connect(&m_NetworkManager, SIGNAL(finished(QNetworkReply *)), + SLOT(complete(QNetworkReply *))); } -DataDownloader::~DataDownloader() -{ +DataDownloader::~DataDownloader() {} + +void DataDownloader::complete(QNetworkReply *reply) { + m_Data = reply->readAll(); + reply->deleteLater(); + m_pReply = nullptr; + + if (!m_Data.isEmpty()) { + m_IsFinished = true; + emit isComplete(); + } } -void DataDownloader::complete(QNetworkReply* reply) -{ - m_Data = reply->readAll(); - reply->deleteLater(); - m_pReply = nullptr; +QByteArray DataDownloader::data() const { return m_Data; } - if (!m_Data.isEmpty()) { - m_IsFinished = true; - emit isComplete(); - } +void DataDownloader::cancel() { + if (m_pReply != nullptr) { + m_pReply->abort(); + } } -QByteArray DataDownloader::data() const -{ - return m_Data; -} - -void DataDownloader::cancel() -{ - if (m_pReply != nullptr) { - m_pReply->abort(); - } -} - -void DataDownloader::download(QUrl url) -{ - QNetworkRequest request(url); - m_pReply = m_NetworkManager.get(request); +void DataDownloader::download(QUrl url) { + QNetworkRequest request(url); + m_pReply = m_NetworkManager.get(request); } diff --git a/src/gui/src/DataDownloader.h b/src/gui/src/DataDownloader.h index 7eb7d3ed2..629e896ef 100644 --- a/src/gui/src/DataDownloader.h +++ b/src/gui/src/DataDownloader.h @@ -18,36 +18,35 @@ #ifndef DATADOWNLOADER_H #define DATADOWNLOADER_H -#include #include #include -#include #include +#include +#include -class DataDownloader : public QObject -{ - Q_OBJECT +class DataDownloader : public QObject { + Q_OBJECT public: - explicit DataDownloader(QObject* parent = 0); - virtual ~DataDownloader(); + explicit DataDownloader(QObject *parent = 0); + virtual ~DataDownloader(); - QByteArray data() const; - void cancel(); - void download(QUrl url); - bool isFinished() const { return m_IsFinished; } + QByteArray data() const; + void cancel(); + void download(QUrl url); + bool isFinished() const { return m_IsFinished; } signals: - void isComplete(); + void isComplete(); private slots: - void complete(QNetworkReply* reply); + void complete(QNetworkReply *reply); private: - QNetworkAccessManager m_NetworkManager; - QByteArray m_Data; - QNetworkReply* m_pReply; - bool m_IsFinished; + QNetworkAccessManager m_NetworkManager; + QByteArray m_Data; + QNetworkReply *m_pReply; + bool m_IsFinished; }; #endif // DATADOWNLOADER_H diff --git a/src/gui/src/ElevateMode.h b/src/gui/src/ElevateMode.h index 7e39eb52a..64a1e3e40 100644 --- a/src/gui/src/ElevateMode.h +++ b/src/gui/src/ElevateMode.h @@ -32,10 +32,6 @@ // ElevateAlways | false | true // ElevateNever | false | false // -enum ElevateMode { - ElevateAsNeeded = 0, - ElevateAlways = 1, - ElevateNever = 2 -}; +enum ElevateMode { ElevateAsNeeded = 0, ElevateAlways = 1, ElevateNever = 2 }; extern const ElevateMode defaultElevateMode; diff --git a/src/gui/src/FailedLoginDialog.cpp b/src/gui/src/FailedLoginDialog.cpp index ba53ce454..48cfa8bea 100644 --- a/src/gui/src/FailedLoginDialog.cpp +++ b/src/gui/src/FailedLoginDialog.cpp @@ -1,15 +1,10 @@ #include "FailedLoginDialog.h" #include "ui_FailedLoginDialog.h" -FailedLoginDialog::FailedLoginDialog(QWidget *parent, QString message): - QDialog(parent), - ui(new Ui::FailedLoginDialog) -{ - ui->setupUi(this); - ui->messageLabel->setText(ui->messageLabel->text().arg(message)); +FailedLoginDialog::FailedLoginDialog(QWidget *parent, QString message) + : QDialog(parent), ui(new Ui::FailedLoginDialog) { + ui->setupUi(this); + ui->messageLabel->setText(ui->messageLabel->text().arg(message)); } -FailedLoginDialog::~FailedLoginDialog() -{ - delete ui; -} +FailedLoginDialog::~FailedLoginDialog() { delete ui; } diff --git a/src/gui/src/FailedLoginDialog.h b/src/gui/src/FailedLoginDialog.h index d15bd7060..5934ed075 100644 --- a/src/gui/src/FailedLoginDialog.h +++ b/src/gui/src/FailedLoginDialog.h @@ -8,16 +8,15 @@ namespace Ui { class FailedLoginDialog; } -class FailedLoginDialog : public QDialog -{ - Q_OBJECT - +class FailedLoginDialog : public QDialog { + Q_OBJECT + public: - explicit FailedLoginDialog(QWidget *parent = 0, QString message = ""); - ~FailedLoginDialog(); - + explicit FailedLoginDialog(QWidget *parent = 0, QString message = ""); + ~FailedLoginDialog(); + private: - Ui::FailedLoginDialog *ui; + Ui::FailedLoginDialog *ui; }; #endif // FAILEDLOGINDIALOG_H diff --git a/src/gui/src/Fingerprint.cpp b/src/gui/src/Fingerprint.cpp index c9d331e6f..e5aac71e3 100644 --- a/src/gui/src/Fingerprint.cpp +++ b/src/gui/src/Fingerprint.cpp @@ -27,123 +27,100 @@ static const char kLocalFilename[] = "Local.txt"; static const char kTrustedServersFilename[] = "TrustedServers.txt"; static const char kTrustedClientsFilename[] = "TrustedClients.txt"; -Fingerprint::Fingerprint(const QString& filename) -{ - m_Filename = filename; +Fingerprint::Fingerprint(const QString &filename) { m_Filename = filename; } + +void Fingerprint::trust(const QString &fingerprintText, bool append) { + Fingerprint::persistDirectory(); + + QIODevice::OpenMode openMode; + if (append) { + openMode = QIODevice::Append; + } else { + openMode = QIODevice::WriteOnly; + } + + QFile file(filePath()); + if (file.open(openMode)) { + QTextStream out(&file); + out << fingerprintText << "\n"; + file.close(); + } } -void Fingerprint::trust(const QString& fingerprintText, bool append) -{ - Fingerprint::persistDirectory(); - - QIODevice::OpenMode openMode; - if (append) { - openMode = QIODevice::Append; - } - else { - openMode = QIODevice::WriteOnly; - } - - QFile file(filePath()); - if (file.open(openMode)) - { - QTextStream out(&file); - out << fingerprintText << "\n"; - file.close(); - } -} - -bool Fingerprint::fileExists() const -{ - QString dirName = Fingerprint::directoryPath(); - if (!QDir(dirName).exists()) { - return false; - } - - QFile file(filePath()); - return file.exists(); -} - -bool Fingerprint::isTrusted(const QString& fingerprintText) -{ - QStringList list = readList(); - foreach (QString trusted, list) - { - if (trusted == fingerprintText) { - return true; - } - } +bool Fingerprint::fileExists() const { + QString dirName = Fingerprint::directoryPath(); + if (!QDir(dirName).exists()) { return false; + } + + QFile file(filePath()); + return file.exists(); } -QStringList Fingerprint::readList(const int readTo) -{ - QStringList list; - - QString dirName = Fingerprint::directoryPath(); - if (!QDir(dirName).exists()) { - return list; +bool Fingerprint::isTrusted(const QString &fingerprintText) { + QStringList list = readList(); + foreach (QString trusted, list) { + if (trusted == fingerprintText) { + return true; } + } + return false; +} - QFile file(filePath()); - - if (file.open(QIODevice::ReadOnly)) - { - QTextStream in(&file); - while (!in.atEnd()) - { - list.append(in.readLine()); - if (list.size() == readTo) { - break; - } - } - file.close(); - } +QStringList Fingerprint::readList(const int readTo) { + QStringList list; + QString dirName = Fingerprint::directoryPath(); + if (!QDir(dirName).exists()) { return list; -} + } -QString Fingerprint::readFirst() -{ - QStringList list = readList(1); - return list.at(0); -} + QFile file(filePath()); -QString Fingerprint::filePath() const -{ - QString dir = Fingerprint::directoryPath(); - return QString("%1/%2").arg(dir).arg(m_Filename); -} - -void Fingerprint::persistDirectory() -{ - QDir dir(Fingerprint::directoryPath()); - if (!dir.exists()) { - dir.mkpath("."); + if (file.open(QIODevice::ReadOnly)) { + QTextStream in(&file); + while (!in.atEnd()) { + list.append(in.readLine()); + if (list.size() == readTo) { + break; + } } + file.close(); + } + + return list; } -QString Fingerprint::directoryPath() -{ - CoreInterface coreInterface; - QString profileDir = coreInterface.getProfileDir(); - - return QString("%1/%2") - .arg(profileDir) - .arg(kDirName); +QString Fingerprint::readFirst() { + QStringList list = readList(1); + return list.at(0); } -Fingerprint Fingerprint::local() -{ - return Fingerprint(kLocalFilename); +QString Fingerprint::filePath() const { + QString dir = Fingerprint::directoryPath(); + return QString("%1/%2").arg(dir).arg(m_Filename); } -Fingerprint Fingerprint::trustedServers() -{ - return Fingerprint(kTrustedServersFilename); +void Fingerprint::persistDirectory() { + QDir dir(Fingerprint::directoryPath()); + if (!dir.exists()) { + dir.mkpath("."); + } } -Fingerprint Fingerprint::trustedClients() -{ - return Fingerprint(kTrustedClientsFilename); +QString Fingerprint::directoryPath() { + CoreInterface coreInterface; + QString profileDir = coreInterface.getProfileDir(); + + return QString("%1/%2").arg(profileDir).arg(kDirName); +} + +Fingerprint Fingerprint::local() { return Fingerprint(kLocalFilename); } + +Fingerprint Fingerprint::trustedServers() { + return Fingerprint(kTrustedServersFilename); +} + +Fingerprint Fingerprint::trustedClients() { + return Fingerprint(kTrustedClientsFilename); } diff --git a/src/gui/src/Fingerprint.h b/src/gui/src/Fingerprint.h index 24e10984f..563967a4d 100644 --- a/src/gui/src/Fingerprint.h +++ b/src/gui/src/Fingerprint.h @@ -19,28 +19,27 @@ #include -class Fingerprint -{ +class Fingerprint { private: - Fingerprint(const QString& filename); + Fingerprint(const QString &filename); public: - void trust(const QString& fingerprintText, bool append = true); - bool isTrusted(const QString& fingerprintText); - QStringList readList(const int readTo = -1); - QString readFirst(); - QString filePath() const; - bool fileExists() const; + void trust(const QString &fingerprintText, bool append = true); + bool isTrusted(const QString &fingerprintText); + QStringList readList(const int readTo = -1); + QString readFirst(); + QString filePath() const; + bool fileExists() const; public: - static Fingerprint local(); - static Fingerprint trustedServers(); - static Fingerprint trustedClients(); - static QString directoryPath(); - static QString localFingerprint(); - static bool localFingerprintExists(); - static void persistDirectory(); + static Fingerprint local(); + static Fingerprint trustedServers(); + static Fingerprint trustedClients(); + static QString directoryPath(); + static QString localFingerprint(); + static bool localFingerprintExists(); + static void persistDirectory(); private: - QString m_Filename; + QString m_Filename; }; diff --git a/src/gui/src/Hotkey.cpp b/src/gui/src/Hotkey.cpp index f711e84c6..a0ce55fa9 100644 --- a/src/gui/src/Hotkey.cpp +++ b/src/gui/src/Hotkey.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2008 Volker Lanz (vl@fidra.de) - * + * * 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 LICENSE 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 @@ -20,61 +20,50 @@ #include -Hotkey::Hotkey() : - m_KeySequence(), - m_Actions() -{ +Hotkey::Hotkey() : m_KeySequence(), m_Actions() {} + +QString Hotkey::text() const { + QString text = keySequence().toString(); + + if (keySequence().isMouseButton()) + return "mousebutton(" + text + ")"; + + return "keystroke(" + text + ")"; } -QString Hotkey::text() const -{ - QString text = keySequence().toString(); +void Hotkey::loadSettings(QSettings &settings) { + keySequence().loadSettings(settings); - if (keySequence().isMouseButton()) - return "mousebutton(" + text + ")"; + actions().clear(); + int num = settings.beginReadArray("actions"); + for (int i = 0; i < num; i++) { + settings.setArrayIndex(i); + Action a; + a.loadSettings(settings); + actions().append(a); + } - return "keystroke(" + text + ")"; + settings.endArray(); } -void Hotkey::loadSettings(QSettings& settings) -{ - keySequence().loadSettings(settings); +void Hotkey::saveSettings(QSettings &settings) const { + keySequence().saveSettings(settings); - actions().clear(); - int num = settings.beginReadArray("actions"); - for (int i = 0; i < num; i++) - { - settings.setArrayIndex(i); - Action a; - a.loadSettings(settings); - actions().append(a); - } - - settings.endArray(); + settings.beginWriteArray("actions"); + for (int i = 0; i < actions().size(); i++) { + settings.setArrayIndex(i); + actions()[i].saveSettings(settings); + } + settings.endArray(); } -void Hotkey::saveSettings(QSettings& settings) const -{ - keySequence().saveSettings(settings); - - settings.beginWriteArray("actions"); - for (int i = 0; i < actions().size(); i++) - { - settings.setArrayIndex(i); - actions()[i].saveSettings(settings); - } - settings.endArray(); +bool Hotkey::operator==(const Hotkey &hk) const { + return m_KeySequence == hk.m_KeySequence && m_Actions == hk.m_Actions; } -bool Hotkey::operator==(const Hotkey& hk) const -{ - return m_KeySequence == hk.m_KeySequence && m_Actions == hk.m_Actions; -} +QTextStream &operator<<(QTextStream &outStream, const Hotkey &hotkey) { + for (int i = 0; i < hotkey.actions().size(); i++) + outStream << "\t" << hotkey.text() << " = " << hotkey.actions()[i] << endl; -QTextStream& operator<<(QTextStream& outStream, const Hotkey& hotkey) -{ - for (int i = 0; i < hotkey.actions().size(); i++) - outStream << "\t" << hotkey.text() << " = " << hotkey.actions()[i] << endl; - - return outStream; + return outStream; } diff --git a/src/gui/src/Hotkey.h b/src/gui/src/Hotkey.h index 8d4e4813c..efeecadc2 100644 --- a/src/gui/src/Hotkey.h +++ b/src/gui/src/Hotkey.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2008 Volker Lanz (vl@fidra.de) - * + * * 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 LICENSE 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 @@ -20,8 +20,8 @@ #define HOTKEY_H -#include #include +#include #include #include "Action.h" @@ -31,38 +31,36 @@ class HotkeyDialog; class ServerConfigDialog; class QSettings; -class Hotkey -{ - friend class HotkeyDialog; - friend class ServerConfigDialog; - friend QTextStream& operator<<(QTextStream& outStream, const Hotkey& hotkey); +class Hotkey { + friend class HotkeyDialog; + friend class ServerConfigDialog; + friend QTextStream &operator<<(QTextStream &outStream, const Hotkey &hotkey); - public: - Hotkey(); +public: + Hotkey(); - public: - QString text() const; - const KeySequence& keySequence() const { return m_KeySequence; } - const ActionList& actions() const { return m_Actions; } +public: + QString text() const; + const KeySequence &keySequence() const { return m_KeySequence; } + const ActionList &actions() const { return m_Actions; } - void loadSettings(QSettings& settings); - void saveSettings(QSettings& settings) const; + void loadSettings(QSettings &settings); + void saveSettings(QSettings &settings) const; - bool operator==(const Hotkey& hk) const; + bool operator==(const Hotkey &hk) const; - protected: - KeySequence& keySequence() { return m_KeySequence; } - void setKeySequence(const KeySequence& seq) { m_KeySequence = seq; } - ActionList& actions() { return m_Actions; } +protected: + KeySequence &keySequence() { return m_KeySequence; } + void setKeySequence(const KeySequence &seq) { m_KeySequence = seq; } + ActionList &actions() { return m_Actions; } - - private: - KeySequence m_KeySequence; - ActionList m_Actions; +private: + KeySequence m_KeySequence; + ActionList m_Actions; }; typedef QList HotkeyList; -QTextStream& operator<<(QTextStream& outStream, const Hotkey& hotkey); +QTextStream &operator<<(QTextStream &outStream, const Hotkey &hotkey); #endif diff --git a/src/gui/src/HotkeyDialog.cpp b/src/gui/src/HotkeyDialog.cpp index 5c08d38f2..377bba2d8 100644 --- a/src/gui/src/HotkeyDialog.cpp +++ b/src/gui/src/HotkeyDialog.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2008 Volker Lanz (vl@fidra.de) - * + * * 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 LICENSE 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 @@ -21,21 +21,18 @@ #include #include -HotkeyDialog::HotkeyDialog (QWidget* parent, Hotkey& hotkey) : - QDialog(parent, Qt::WindowTitleHint | Qt::WindowSystemMenuHint), - Ui::HotkeyDialogBase(), - m_Hotkey(hotkey) -{ - setupUi(this); +HotkeyDialog::HotkeyDialog(QWidget *parent, Hotkey &hotkey) + : QDialog(parent, Qt::WindowTitleHint | Qt::WindowSystemMenuHint), + Ui::HotkeyDialogBase(), m_Hotkey(hotkey) { + setupUi(this); - m_pKeySequenceWidgetHotkey->setText(m_Hotkey.text()); + m_pKeySequenceWidgetHotkey->setText(m_Hotkey.text()); } -void HotkeyDialog::accept() -{ - if (!sequenceWidget()->valid()) - return; +void HotkeyDialog::accept() { + if (!sequenceWidget()->valid()) + return; - hotkey().setKeySequence(sequenceWidget()->keySequence()); - QDialog::accept(); + hotkey().setKeySequence(sequenceWidget()->keySequence()); + QDialog::accept(); } diff --git a/src/gui/src/HotkeyDialog.h b/src/gui/src/HotkeyDialog.h index efea813fd..1ba17d734 100644 --- a/src/gui/src/HotkeyDialog.h +++ b/src/gui/src/HotkeyDialog.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2008 Volker Lanz (vl@fidra.de) - * + * * 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 LICENSE 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 @@ -20,30 +20,31 @@ #define HOTKEYDIALOG_H -#include "ui_HotkeyDialogBase.h" #include "Hotkey.h" +#include "ui_HotkeyDialogBase.h" #include -class HotkeyDialog : public QDialog, public Ui::HotkeyDialogBase -{ - Q_OBJECT +class HotkeyDialog : public QDialog, public Ui::HotkeyDialogBase { + Q_OBJECT - public: - HotkeyDialog(QWidget* parent, Hotkey& hotkey); +public: + HotkeyDialog(QWidget *parent, Hotkey &hotkey); - public: - const Hotkey& hotkey() const { return m_Hotkey; } +public: + const Hotkey &hotkey() const { return m_Hotkey; } - protected slots: - void accept(); +protected slots: + void accept(); - protected: - const KeySequenceWidget* sequenceWidget() const { return m_pKeySequenceWidgetHotkey; } - Hotkey& hotkey() { return m_Hotkey; } +protected: + const KeySequenceWidget *sequenceWidget() const { + return m_pKeySequenceWidgetHotkey; + } + Hotkey &hotkey() { return m_Hotkey; } - private: - Hotkey& m_Hotkey; +private: + Hotkey &m_Hotkey; }; #endif diff --git a/src/gui/src/Ipc.cpp b/src/gui/src/Ipc.cpp index 3f4afbc79..39be8686c 100644 --- a/src/gui/src/Ipc.cpp +++ b/src/gui/src/Ipc.cpp @@ -20,7 +20,7 @@ #include "Ipc.h" -const char* kIpcMsgHello = "IHEL%1i"; -const char* kIpcMsgLogLine = "ILOG%s"; -const char* kIpcMsgCommand = "ICMD%s%1i"; -const char* kIpcMsgShutdown = "ISDN"; +const char *kIpcMsgHello = "IHEL%1i"; +const char *kIpcMsgLogLine = "ILOG%s"; +const char *kIpcMsgCommand = "ICMD%s%1i"; +const char *kIpcMsgShutdown = "ISDN"; diff --git a/src/gui/src/Ipc.h b/src/gui/src/Ipc.h index 9e6275957..76d7bc6b0 100644 --- a/src/gui/src/Ipc.h +++ b/src/gui/src/Ipc.h @@ -24,19 +24,19 @@ #define IPC_PORT 24801 enum qIpcMessageType { - kIpcHello, - kIpcLogLine, - kIpcCommand, - kIpcShutdown, + kIpcHello, + kIpcLogLine, + kIpcCommand, + kIpcShutdown, }; enum qIpcClientType { - kIpcClientUnknown, - kIpcClientGui, - kIpcClientNode, + kIpcClientUnknown, + kIpcClientGui, + kIpcClientNode, }; -extern const char* kIpcMsgHello; -extern const char* kIpcMsgLogLine; -extern const char* kIpcMsgCommand; -extern const char* kIpcMsgShutdown; +extern const char *kIpcMsgHello; +extern const char *kIpcMsgLogLine; +extern const char *kIpcMsgCommand; +extern const char *kIpcMsgShutdown; diff --git a/src/gui/src/IpcClient.cpp b/src/gui/src/IpcClient.cpp index daa112b6c..0672b5163 100644 --- a/src/gui/src/IpcClient.cpp +++ b/src/gui/src/IpcClient.cpp @@ -17,130 +17,122 @@ */ #include "IpcClient.h" -#include -#include -#include -#include -#include "IpcReader.h" #include "Ipc.h" +#include "IpcReader.h" #include +#include +#include +#include +#include -IpcClient::IpcClient() : -m_ReaderStarted(false), -m_Enabled(false) -{ - m_Socket = new QTcpSocket(this); - connect(m_Socket, SIGNAL(connected()), this, SLOT(connected())); - connect(m_Socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(error(QAbstractSocket::SocketError))); +IpcClient::IpcClient() : m_ReaderStarted(false), m_Enabled(false) { + m_Socket = new QTcpSocket(this); + connect(m_Socket, SIGNAL(connected()), this, SLOT(connected())); + connect(m_Socket, SIGNAL(error(QAbstractSocket::SocketError)), this, + SLOT(error(QAbstractSocket::SocketError))); - m_Reader = new IpcReader(m_Socket); - connect(m_Reader, SIGNAL(readLogLine(const QString&)), this, SLOT(handleReadLogLine(const QString&))); + m_Reader = new IpcReader(m_Socket); + connect(m_Reader, SIGNAL(readLogLine(const QString &)), this, + SLOT(handleReadLogLine(const QString &))); } -IpcClient::~IpcClient() -{ +IpcClient::~IpcClient() {} + +void IpcClient::connected() { + sendHello(); + infoMessage("connection established"); } -void IpcClient::connected() -{ - sendHello(); - infoMessage("connection established"); +void IpcClient::connectToHost() { + m_Enabled = true; + + infoMessage("connecting to service..."); + m_Socket->connectToHost(QHostAddress(QHostAddress::LocalHost), IPC_PORT); + + if (!m_ReaderStarted) { + m_Reader->start(); + m_ReaderStarted = true; + } } -void IpcClient::connectToHost() -{ - m_Enabled = true; - - infoMessage("connecting to service..."); - m_Socket->connectToHost(QHostAddress(QHostAddress::LocalHost), IPC_PORT); - - if (!m_ReaderStarted) { - m_Reader->start(); - m_ReaderStarted = true; - } +void IpcClient::disconnectFromHost() { + infoMessage("service disconnect"); + m_Reader->stop(); + m_Socket->close(); } -void IpcClient::disconnectFromHost() -{ - infoMessage("service disconnect"); - m_Reader->stop(); - m_Socket->close(); +void IpcClient::error(QAbstractSocket::SocketError error) { + QString text; + switch (error) { + case 0: + text = "connection refused"; + break; + case 1: + text = "remote host closed"; + break; + default: + text = QString("code=%1").arg(error); + break; + } + + errorMessage(QString("ipc connection error, %1").arg(text)); + + QTimer::singleShot(1000, this, SLOT(retryConnect())); } -void IpcClient::error(QAbstractSocket::SocketError error) -{ - QString text; - switch (error) { - case 0: text = "connection refused"; break; - case 1: text = "remote host closed"; break; - default: text = QString("code=%1").arg(error); break; - } - - errorMessage(QString("ipc connection error, %1").arg(text)); - - QTimer::singleShot(1000, this, SLOT(retryConnect())); +void IpcClient::retryConnect() { + if (m_Enabled) { + connectToHost(); + } } -void IpcClient::retryConnect() -{ - if (m_Enabled) { - connectToHost(); - } +void IpcClient::sendHello() { + QDataStream stream(m_Socket); + stream.writeRawData(kIpcMsgHello, 4); + + char typeBuf[1]; + typeBuf[0] = kIpcClientGui; + stream.writeRawData(typeBuf, 1); } -void IpcClient::sendHello() -{ - QDataStream stream(m_Socket); - stream.writeRawData(kIpcMsgHello, 4); +void IpcClient::sendCommand(const QString &command, ElevateMode const elevate) { + QDataStream stream(m_Socket); - char typeBuf[1]; - typeBuf[0] = kIpcClientGui; - stream.writeRawData(typeBuf, 1); + stream.writeRawData(kIpcMsgCommand, 4); + + std::string stdStringCommand = command.toStdString(); + const char *charCommand = stdStringCommand.c_str(); + int length = static_cast( + strlen(charCommand)); // Compliant: we made sure that charCommand variable + // ended with null(String type is safe) + + char lenBuf[4]; + intToBytes(length, lenBuf, 4); + stream.writeRawData(lenBuf, 4); + stream.writeRawData(charCommand, length); + + char elevateBuf[1]; + // Refer to enum ElevateMode documentation for why this flag is mapped this + // way + elevateBuf[0] = (elevate == ElevateAlways) ? 1 : 0; + stream.writeRawData(elevateBuf, 1); } -void IpcClient::sendCommand(const QString& command, ElevateMode const elevate) -{ - QDataStream stream(m_Socket); - - stream.writeRawData(kIpcMsgCommand, 4); - - std::string stdStringCommand = command.toStdString(); - const char* charCommand = stdStringCommand.c_str(); - int length = static_cast(strlen(charCommand)); // Compliant: we made sure that charCommand variable ended with null(String type is safe) - - char lenBuf[4]; - intToBytes(length, lenBuf, 4); - stream.writeRawData(lenBuf, 4); - stream.writeRawData(charCommand, length); - - char elevateBuf[1]; - // Refer to enum ElevateMode documentation for why this flag is mapped this way - elevateBuf[0] = (elevate == ElevateAlways) ? 1 : 0; - stream.writeRawData(elevateBuf, 1); -} - -void IpcClient::handleReadLogLine(const QString& text) -{ - readLogLine(text); -} +void IpcClient::handleReadLogLine(const QString &text) { readLogLine(text); } // TODO: qt must have a built in way of converting int to bytes. -void IpcClient::intToBytes(int value, char *buffer, int size) -{ - if (size == 1) { - buffer[0] = value & 0xff; - } - else if (size == 2) { - buffer[0] = (value >> 8) & 0xff; - buffer[1] = value & 0xff; - } - else if (size == 4) { - buffer[0] = (value >> 24) & 0xff; - buffer[1] = (value >> 16) & 0xff; - buffer[2] = (value >> 8) & 0xff; - buffer[3] = value & 0xff; - } - else { - // TODO: other sizes, if needed. - } +void IpcClient::intToBytes(int value, char *buffer, int size) { + if (size == 1) { + buffer[0] = value & 0xff; + } else if (size == 2) { + buffer[0] = (value >> 8) & 0xff; + buffer[1] = value & 0xff; + } else if (size == 4) { + buffer[0] = (value >> 24) & 0xff; + buffer[1] = (value >> 16) & 0xff; + buffer[2] = (value >> 8) & 0xff; + buffer[3] = value & 0xff; + } else { + // TODO: other sizes, if needed. + } } diff --git a/src/gui/src/IpcClient.h b/src/gui/src/IpcClient.h index ea4b45064..0fac1ad78 100644 --- a/src/gui/src/IpcClient.h +++ b/src/gui/src/IpcClient.h @@ -18,46 +18,45 @@ #pragma once -#include #include +#include #include "ElevateMode.h" class QTcpSocket; class IpcReader; -class IpcClient : public QObject -{ - Q_OBJECT +class IpcClient : public QObject { + Q_OBJECT public: - IpcClient(); - virtual ~IpcClient(); + IpcClient(); + virtual ~IpcClient(); - void sendHello(); - void sendCommand(const QString& command, ElevateMode elevate); - void connectToHost(); - void disconnectFromHost(); + void sendHello(); + void sendCommand(const QString &command, ElevateMode elevate); + void connectToHost(); + void disconnectFromHost(); public slots: - void retryConnect(); + void retryConnect(); private: - void intToBytes(int value, char* buffer, int size); + void intToBytes(int value, char *buffer, int size); private slots: - void connected(); - void error(QAbstractSocket::SocketError error); - void handleReadLogLine(const QString& text); + void connected(); + void error(QAbstractSocket::SocketError error); + void handleReadLogLine(const QString &text); signals: - void readLogLine(const QString& text); - void infoMessage(const QString& text); - void errorMessage(const QString& text); + void readLogLine(const QString &text); + void infoMessage(const QString &text); + void errorMessage(const QString &text); private: - QTcpSocket* m_Socket; - IpcReader* m_Reader; - bool m_ReaderStarted; - bool m_Enabled; + QTcpSocket *m_Socket; + IpcReader *m_Reader; + bool m_ReaderStarted; + bool m_Enabled; }; diff --git a/src/gui/src/IpcReader.cpp b/src/gui/src/IpcReader.cpp index 323a41037..73fe67cfc 100644 --- a/src/gui/src/IpcReader.cpp +++ b/src/gui/src/IpcReader.cpp @@ -17,115 +17,96 @@ */ #include "IpcReader.h" -#include #include "Ipc.h" -#include -#include #include +#include +#include +#include -IpcReader::IpcReader(QTcpSocket* socket) : -m_Socket(socket) -{ +IpcReader::IpcReader(QTcpSocket *socket) : m_Socket(socket) {} + +IpcReader::~IpcReader() {} + +void IpcReader::start() { + connect(m_Socket, SIGNAL(readyRead()), this, SLOT(read())); } -IpcReader::~IpcReader() -{ +void IpcReader::stop() { + disconnect(m_Socket, SIGNAL(readyRead()), this, SLOT(read())); } -void IpcReader::start() -{ - connect(m_Socket, SIGNAL(readyRead()), this, SLOT(read())); +void IpcReader::read() { + QMutexLocker locker(&m_Mutex); + std::cout << "ready read" << std::endl; + + while (m_Socket->bytesAvailable()) { + std::cout << "bytes available" << std::endl; + + char codeBuf[5]; + readStream(codeBuf, 4); + codeBuf[4] = 0; + std::cout << "ipc read: " << codeBuf << std::endl; + + if (memcmp(codeBuf, kIpcMsgLogLine, 4) == 0) { + std::cout << "reading log line" << std::endl; + + char lenBuf[4]; + readStream(lenBuf, 4); + int len = bytesToInt(lenBuf, 4); + + char *data = new char[len]; + readStream(data, len); + QString line = QString::fromUtf8(data, len); + delete[] data; + + readLogLine(line); + } else { + std::cerr << "aborting, message invalid" << std::endl; + return; + } + } + + std::cout << "read done" << std::endl; } -void IpcReader::stop() -{ - disconnect(m_Socket, SIGNAL(readyRead()), this, SLOT(read())); -} +bool IpcReader::readStream(char *buffer, int length) { + std::cout << "reading stream" << std::endl; -void IpcReader::read() -{ - QMutexLocker locker(&m_Mutex); - std::cout << "ready read" << std::endl; - - while (m_Socket->bytesAvailable()) { - std::cout << "bytes available" << std::endl; - - char codeBuf[5]; - readStream(codeBuf, 4); - codeBuf[4] = 0; - std::cout << "ipc read: " << codeBuf << std::endl; - - if (memcmp(codeBuf, kIpcMsgLogLine, 4) == 0) { - std::cout << "reading log line" << std::endl; - - char lenBuf[4]; - readStream(lenBuf, 4); - int len = bytesToInt(lenBuf, 4); - - char* data = new char[len]; - readStream(data, len); - QString line = QString::fromUtf8(data, len); - delete[] data; - - readLogLine(line); - } - else { - std::cerr << "aborting, message invalid" << std::endl; - return; - } + int read = 0; + while (read < length) { + int ask = length - read; + if (m_Socket->bytesAvailable() < ask) { + std::cout << "buffer too short, waiting" << std::endl; + m_Socket->waitForReadyRead(-1); } - std::cout << "read done" << std::endl; + int got = m_Socket->read(buffer, ask); + read += got; + + std::cout << "> ask=" << ask << " got=" << got << " read=" << read + << std::endl; + + if (got == -1) { + std::cout << "socket ended, aborting" << std::endl; + return false; + } else if (length - read > 0) { + std::cout << "more remains, seek to " << got << std::endl; + buffer += got; + } + } + return true; } -bool IpcReader::readStream(char* buffer, int length) -{ - std::cout << "reading stream" << std::endl; - - int read = 0; - while (read < length) { - int ask = length - read; - if (m_Socket->bytesAvailable() < ask) { - std::cout << "buffer too short, waiting" << std::endl; - m_Socket->waitForReadyRead(-1); - } - - int got = m_Socket->read(buffer, ask); - read += got; - - std::cout << "> ask=" << ask << " got=" << got - << " read=" << read << std::endl; - - if (got == -1) { - std::cout << "socket ended, aborting" << std::endl; - return false; - } - else if (length - read > 0) { - std::cout << "more remains, seek to " << got << std::endl; - buffer += got; - } - } - return true; -} - -int IpcReader::bytesToInt(const char *buffer, int size) -{ - if (size == 1) { - return (unsigned char)buffer[0]; - } - else if (size == 2) { - return - (((unsigned char)buffer[0]) << 8) + - (unsigned char)buffer[1]; - } - else if (size == 4) { - return - (((unsigned char)buffer[0]) << 24) + - (((unsigned char)buffer[1]) << 16) + - (((unsigned char)buffer[2]) << 8) + - (unsigned char)buffer[3]; - } - else { - return 0; - } +int IpcReader::bytesToInt(const char *buffer, int size) { + if (size == 1) { + return (unsigned char)buffer[0]; + } else if (size == 2) { + return (((unsigned char)buffer[0]) << 8) + (unsigned char)buffer[1]; + } else if (size == 4) { + return (((unsigned char)buffer[0]) << 24) + + (((unsigned char)buffer[1]) << 16) + + (((unsigned char)buffer[2]) << 8) + (unsigned char)buffer[3]; + } else { + return 0; + } } diff --git a/src/gui/src/IpcReader.h b/src/gui/src/IpcReader.h index 8a3e7c094..0e473aa36 100644 --- a/src/gui/src/IpcReader.h +++ b/src/gui/src/IpcReader.h @@ -18,32 +18,31 @@ #pragma once -#include #include +#include class QTcpSocket; -class IpcReader : public QObject -{ - Q_OBJECT; +class IpcReader : public QObject { + Q_OBJECT; public: - IpcReader(QTcpSocket* socket); - virtual ~IpcReader(); - void start(); - void stop(); + IpcReader(QTcpSocket *socket); + virtual ~IpcReader(); + void start(); + void stop(); signals: - void readLogLine(const QString& text); + void readLogLine(const QString &text); private: - bool readStream(char* buffer, int length); - int bytesToInt(const char* buffer, int size); + bool readStream(char *buffer, int length); + int bytesToInt(const char *buffer, int size); private slots: - void read(); + void read(); private: - QTcpSocket* m_Socket; - QMutex m_Mutex; + QTcpSocket *m_Socket; + QMutex m_Mutex; }; diff --git a/src/gui/src/KeySequence.cpp b/src/gui/src/KeySequence.cpp index 64a2d4905..0c0eaa284 100644 --- a/src/gui/src/KeySequence.cpp +++ b/src/gui/src/KeySequence.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2008 Volker Lanz (vl@fidra.de) - * + * * 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 LICENSE 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 @@ -23,222 +23,198 @@ // this table originally comes from Qt sources (gui/kernel/qkeysequence.cpp) // and is heavily modified for QSynergy -static const struct -{ - int key; - const char* name; -} keyname[] = -{ - { Qt::Key_Space, "Space" }, - { Qt::Key_Escape, "Escape" }, - { Qt::Key_Tab, "Tab" }, - { Qt::Key_Backtab, "LeftTab" }, - { Qt::Key_Backspace, "BackSpace" }, - { Qt::Key_Return, "Return" }, - { Qt::Key_Insert, "Insert" }, - { Qt::Key_Delete, "Delete" }, - { Qt::Key_Pause, "Pause" }, - { Qt::Key_Print, "Print" }, - { Qt::Key_SysReq, "SysReq" }, - { Qt::Key_Home, "Home" }, - { Qt::Key_End, "End" }, - { Qt::Key_Left, "Left" }, - { Qt::Key_Up, "Up" }, - { Qt::Key_Right, "Right" }, - { Qt::Key_Down, "Down" }, - { Qt::Key_PageUp, "PageUp" }, - { Qt::Key_PageDown, "PageDown" }, - { Qt::Key_CapsLock, "CapsLock" }, - { Qt::Key_NumLock, "NumLock" }, - { Qt::Key_ScrollLock, "ScrollLock" }, - { Qt::Key_Menu, "Menu" }, - { Qt::Key_Help, "Help" }, - { Qt::Key_Enter, "KP_Enter" }, - { Qt::Key_Clear, "Clear" }, +static const struct { + int key; + const char *name; +} keyname[] = {{Qt::Key_Space, "Space"}, + {Qt::Key_Escape, "Escape"}, + {Qt::Key_Tab, "Tab"}, + {Qt::Key_Backtab, "LeftTab"}, + {Qt::Key_Backspace, "BackSpace"}, + {Qt::Key_Return, "Return"}, + {Qt::Key_Insert, "Insert"}, + {Qt::Key_Delete, "Delete"}, + {Qt::Key_Pause, "Pause"}, + {Qt::Key_Print, "Print"}, + {Qt::Key_SysReq, "SysReq"}, + {Qt::Key_Home, "Home"}, + {Qt::Key_End, "End"}, + {Qt::Key_Left, "Left"}, + {Qt::Key_Up, "Up"}, + {Qt::Key_Right, "Right"}, + {Qt::Key_Down, "Down"}, + {Qt::Key_PageUp, "PageUp"}, + {Qt::Key_PageDown, "PageDown"}, + {Qt::Key_CapsLock, "CapsLock"}, + {Qt::Key_NumLock, "NumLock"}, + {Qt::Key_ScrollLock, "ScrollLock"}, + {Qt::Key_Menu, "Menu"}, + {Qt::Key_Help, "Help"}, + {Qt::Key_Enter, "KP_Enter"}, + {Qt::Key_Clear, "Clear"}, - { Qt::Key_Back, "WWWBack" }, - { Qt::Key_Forward, "WWWForward" }, - { Qt::Key_Stop, "WWWStop" }, - { Qt::Key_Refresh, "WWWRefresh" }, - { Qt::Key_VolumeDown, "AudioDown" }, - { Qt::Key_VolumeMute, "AudioMute" }, - { Qt::Key_VolumeUp, "AudioUp" }, - { Qt::Key_MediaPlay, "AudioPlay" }, - { Qt::Key_MediaStop, "AudioStop" }, - { Qt::Key_MediaPrevious,"AudioPrev" }, - { Qt::Key_MediaNext, "AudioNext" }, - { Qt::Key_HomePage, "WWWHome" }, - { Qt::Key_Favorites, "WWWFavorites" }, - { Qt::Key_Search, "WWWSearch" }, - { Qt::Key_Standby, "Sleep" }, - { Qt::Key_LaunchMail, "AppMail" }, - { Qt::Key_LaunchMedia, "AppMedia" }, - { Qt::Key_Launch0, "AppUser1" }, - { Qt::Key_Launch1, "AppUser2" }, - { Qt::Key_Select, "Select" }, + {Qt::Key_Back, "WWWBack"}, + {Qt::Key_Forward, "WWWForward"}, + {Qt::Key_Stop, "WWWStop"}, + {Qt::Key_Refresh, "WWWRefresh"}, + {Qt::Key_VolumeDown, "AudioDown"}, + {Qt::Key_VolumeMute, "AudioMute"}, + {Qt::Key_VolumeUp, "AudioUp"}, + {Qt::Key_MediaPlay, "AudioPlay"}, + {Qt::Key_MediaStop, "AudioStop"}, + {Qt::Key_MediaPrevious, "AudioPrev"}, + {Qt::Key_MediaNext, "AudioNext"}, + {Qt::Key_HomePage, "WWWHome"}, + {Qt::Key_Favorites, "WWWFavorites"}, + {Qt::Key_Search, "WWWSearch"}, + {Qt::Key_Standby, "Sleep"}, + {Qt::Key_LaunchMail, "AppMail"}, + {Qt::Key_LaunchMedia, "AppMedia"}, + {Qt::Key_Launch0, "AppUser1"}, + {Qt::Key_Launch1, "AppUser2"}, + {Qt::Key_Select, "Select"}, - { 0, 0 } -}; + {0, 0}}; -KeySequence::KeySequence() : - m_Sequence(), - m_Modifiers(0), - m_IsValid(false) -{ +KeySequence::KeySequence() : m_Sequence(), m_Modifiers(0), m_IsValid(false) {} + +bool KeySequence::isMouseButton() const { + return !m_Sequence.isEmpty() && m_Sequence.last() < Qt::Key_Space; } -bool KeySequence::isMouseButton() const -{ - return !m_Sequence.isEmpty() && m_Sequence.last() < Qt::Key_Space; +QString KeySequence::toString() const { + QString result; + + for (int i = 0; i < m_Sequence.size(); i++) { + result += keyToString(m_Sequence[i]); + + if (i != m_Sequence.size() - 1) + result += "+"; + } + + return result; } -QString KeySequence::toString() const -{ - QString result; +bool KeySequence::appendMouseButton(int button) { return appendKey(button, 0); } - for (int i = 0; i < m_Sequence.size(); i++) - { - result += keyToString(m_Sequence[i]); - - if (i != m_Sequence.size() - 1) - result += "+"; - } - - return result; -} - -bool KeySequence::appendMouseButton(int button) -{ - return appendKey(button, 0); -} - -bool KeySequence::appendKey(int key, int modifiers) -{ - if (m_Sequence.size() == 4) - return true; - - switch(key) - { - case Qt::Key_AltGr: - return false; - - case Qt::Key_Control: - case Qt::Key_Alt: - case Qt::Key_Shift: - case Qt::Key_Meta: - case Qt::Key_Menu: - { - int mod = modifiers & (~m_Modifiers); - if (mod) - { - m_Sequence.append(mod); - m_Modifiers |= mod; - } - } - break; - - default: - // see if we can handle this key, if not, don't accept it - if (keyToString(key).isEmpty()) - break; - - m_Sequence.append(key); - setValid(true); - return true; - } +bool KeySequence::appendKey(int key, int modifiers) { + if (m_Sequence.size() == 4) + return true; + switch (key) { + case Qt::Key_AltGr: return false; -} -void KeySequence::loadSettings(QSettings& settings) -{ - sequence().clear(); - int num = settings.beginReadArray("keys"); - for (int i = 0; i < num; i++) - { - settings.setArrayIndex(i); - sequence().append(settings.value("key", 0).toInt()); + case Qt::Key_Control: + case Qt::Key_Alt: + case Qt::Key_Shift: + case Qt::Key_Meta: + case Qt::Key_Menu: { + int mod = modifiers & (~m_Modifiers); + if (mod) { + m_Sequence.append(mod); + m_Modifiers |= mod; } - settings.endArray(); + } break; - setModifiers(0); + default: + // see if we can handle this key, if not, don't accept it + if (keyToString(key).isEmpty()) + break; + + m_Sequence.append(key); setValid(true); + return true; + } + + return false; } -void KeySequence::saveSettings(QSettings& settings) const -{ - settings.beginWriteArray("keys"); - for (int i = 0; i < sequence().size(); i++) - { - settings.setArrayIndex(i); - settings.setValue("key", sequence()[i]); - } - settings.endArray(); +void KeySequence::loadSettings(QSettings &settings) { + sequence().clear(); + int num = settings.beginReadArray("keys"); + for (int i = 0; i < num; i++) { + settings.setArrayIndex(i); + sequence().append(settings.value("key", 0).toInt()); + } + settings.endArray(); + + setModifiers(0); + setValid(true); } -QString KeySequence::keyToString(int key) -{ - // nothing there? - if (key == 0) - return ""; +void KeySequence::saveSettings(QSettings &settings) const { + settings.beginWriteArray("keys"); + for (int i = 0; i < sequence().size(); i++) { + settings.setArrayIndex(i); + settings.setValue("key", sequence()[i]); + } + settings.endArray(); +} - // a hack to handle mouse buttons as if they were keys - if (key < Qt::Key_Space) - { - switch(key) - { - case Qt::LeftButton: return "1"; - case Qt::RightButton: return "2"; - case Qt::MidButton: return "3"; - } - - return "4"; // qt only knows three mouse buttons, so assume it's an unknown fourth one - } - - // modifiers? - if (key & Qt::ShiftModifier) - return "Shift"; - - if (key & Qt::ControlModifier) - return "Control"; - - if (key & Qt::AltModifier) - return "Alt"; - - if (key & Qt::MetaModifier) - return "Meta"; - - // treat key pad like normal keys (FIXME: we should have another lookup table for keypad keys instead) - key &= ~Qt::KeypadModifier; - - // a printable 7 bit character? - if (key < 0x80 && key != Qt::Key_Space) - return QChar(key & 0x7f).toLower(); - - // a function key? - if (key >= Qt::Key_F1 && key <= Qt::Key_F35) - return QString::fromUtf8("F%1").arg(key - Qt::Key_F1 + 1); - - // a special key? - int i=0; - while (keyname[i].name) - { - if (key == keyname[i].key) - return QString::fromUtf8(keyname[i].name); - i++; - } - - // representable in ucs2? - if (key < 0x10000) - return QString("\\u%1").arg(QChar(key).toLower().unicode(), 4, 16, QChar('0')); - - // give up, synergy probably won't handle this +QString KeySequence::keyToString(int key) { + // nothing there? + if (key == 0) return ""; + + // a hack to handle mouse buttons as if they were keys + if (key < Qt::Key_Space) { + switch (key) { + case Qt::LeftButton: + return "1"; + case Qt::RightButton: + return "2"; + case Qt::MidButton: + return "3"; + } + + return "4"; // qt only knows three mouse buttons, so assume it's an unknown + // fourth one + } + + // modifiers? + if (key & Qt::ShiftModifier) + return "Shift"; + + if (key & Qt::ControlModifier) + return "Control"; + + if (key & Qt::AltModifier) + return "Alt"; + + if (key & Qt::MetaModifier) + return "Meta"; + + // treat key pad like normal keys (FIXME: we should have another lookup table + // for keypad keys instead) + key &= ~Qt::KeypadModifier; + + // a printable 7 bit character? + if (key < 0x80 && key != Qt::Key_Space) + return QChar(key & 0x7f).toLower(); + + // a function key? + if (key >= Qt::Key_F1 && key <= Qt::Key_F35) + return QString::fromUtf8("F%1").arg(key - Qt::Key_F1 + 1); + + // a special key? + int i = 0; + while (keyname[i].name) { + if (key == keyname[i].key) + return QString::fromUtf8(keyname[i].name); + i++; + } + + // representable in ucs2? + if (key < 0x10000) + return QString("\\u%1").arg(QChar(key).toLower().unicode(), 4, 16, + QChar('0')); + + // give up, synergy probably won't handle this + return ""; } -bool KeySequence::operator==(const KeySequence& ks) const -{ - return m_Sequence == ks.m_Sequence && - m_Modifiers == ks.m_Modifiers && - m_IsValid == ks.m_IsValid; +bool KeySequence::operator==(const KeySequence &ks) const { + return m_Sequence == ks.m_Sequence && m_Modifiers == ks.m_Modifiers && + m_IsValid == ks.m_IsValid; } diff --git a/src/gui/src/KeySequence.h b/src/gui/src/KeySequence.h index aadc7a3c5..94c67a478 100644 --- a/src/gui/src/KeySequence.h +++ b/src/gui/src/KeySequence.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2008 Volker Lanz (vl@fidra.de) - * + * * 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 LICENSE 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 @@ -25,36 +25,34 @@ class QSettings; -class KeySequence -{ - public: - KeySequence(); +class KeySequence { +public: + KeySequence(); - public: - QString toString() const; - bool appendKey(int modifiers, int key); - bool appendMouseButton(int button); - bool isMouseButton() const; - bool valid() const { return m_IsValid; } - int modifiers() const { return m_Modifiers; } - void saveSettings(QSettings& settings) const; - void loadSettings(QSettings& settings); - const QList& sequence() const { return m_Sequence; } +public: + QString toString() const; + bool appendKey(int modifiers, int key); + bool appendMouseButton(int button); + bool isMouseButton() const; + bool valid() const { return m_IsValid; } + int modifiers() const { return m_Modifiers; } + void saveSettings(QSettings &settings) const; + void loadSettings(QSettings &settings); + const QList &sequence() const { return m_Sequence; } - bool operator==(const KeySequence& ks) const; + bool operator==(const KeySequence &ks) const; - private: - void setValid(bool b) { m_IsValid = b; } - void setModifiers(int i) { m_Modifiers = i; } - QList& sequence() { return m_Sequence; } +private: + void setValid(bool b) { m_IsValid = b; } + void setModifiers(int i) { m_Modifiers = i; } + QList &sequence() { return m_Sequence; } - private: - QList m_Sequence; - int m_Modifiers; - bool m_IsValid; +private: + QList m_Sequence; + int m_Modifiers; + bool m_IsValid; - static QString keyToString(int key); + static QString keyToString(int key); }; #endif - diff --git a/src/gui/src/KeySequenceWidget.cpp b/src/gui/src/KeySequenceWidget.cpp index c4ca43565..18fad7f0a 100644 --- a/src/gui/src/KeySequenceWidget.cpp +++ b/src/gui/src/KeySequenceWidget.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2008 Volker Lanz (vl@fidra.de) - * + * * 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 LICENSE 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 @@ -18,128 +18,110 @@ #include "KeySequenceWidget.h" -#include #include +#include -KeySequenceWidget::KeySequenceWidget(QWidget* parent, const KeySequence& seq) : - QPushButton(parent), - m_KeySequence(seq), - m_BackupSequence(seq), - m_Status(Stopped), - m_MousePrefix("mousebutton("), - m_MousePostfix(")"), - m_KeyPrefix("keystroke("), - m_KeyPostfix(")") -{ - setFocusPolicy(Qt::NoFocus); +KeySequenceWidget::KeySequenceWidget(QWidget *parent, const KeySequence &seq) + : QPushButton(parent), m_KeySequence(seq), m_BackupSequence(seq), + m_Status(Stopped), m_MousePrefix("mousebutton("), m_MousePostfix(")"), + m_KeyPrefix("keystroke("), m_KeyPostfix(")") { + setFocusPolicy(Qt::NoFocus); + updateOutput(); +} + +void KeySequenceWidget::setKeySequence(const KeySequence &seq) { + keySequence() = seq; + backupSequence() = seq; + + setStatus(Stopped); + updateOutput(); +} + +void KeySequenceWidget::mousePressEvent(QMouseEvent *event) { + event->accept(); + + if (status() == Stopped) { + startRecording(); + return; + } + + if (m_KeySequence.appendMouseButton(event->button())) + stopRecording(); + + updateOutput(); +} + +void KeySequenceWidget::startRecording() { + keySequence() = KeySequence(); + setDown(true); + setFocus(); + grabKeyboard(); + setStatus(Recording); +} + +void KeySequenceWidget::stopRecording() { + if (!keySequence().valid()) { + keySequence() = backupSequence(); updateOutput(); + } + + setDown(false); + focusNextChild(); + releaseKeyboard(); + setStatus(Stopped); + emit keySequenceChanged(); } -void KeySequenceWidget::setKeySequence(const KeySequence& seq) -{ - keySequence() = seq; - backupSequence() = seq; +bool KeySequenceWidget::event(QEvent *event) { + if (status() == Recording) { + switch (event->type()) { + case QEvent::KeyPress: + keyPressEvent(static_cast(event)); + return true; - setStatus(Stopped); - updateOutput(); -} + case QEvent::MouseButtonRelease: + event->accept(); + return true; -void KeySequenceWidget::mousePressEvent(QMouseEvent* event) -{ - event->accept(); + case QEvent::ShortcutOverride: + event->accept(); + return true; - if (status() == Stopped) - { - startRecording(); - return; - } - - if (m_KeySequence.appendMouseButton(event->button())) - stopRecording(); - - updateOutput(); -} - -void KeySequenceWidget::startRecording() -{ - keySequence() = KeySequence(); - setDown(true); - setFocus(); - grabKeyboard(); - setStatus(Recording); -} - -void KeySequenceWidget::stopRecording() -{ - if (!keySequence().valid()) - { + case QEvent::FocusOut: + stopRecording(); + if (!valid()) { keySequence() = backupSequence(); updateOutput(); + } + break; + + default: + break; } + } - setDown(false); - focusNextChild(); - releaseKeyboard(); - setStatus(Stopped); - emit keySequenceChanged(); + return QPushButton::event(event); } -bool KeySequenceWidget::event(QEvent* event) -{ - if (status() == Recording) - { - switch(event->type()) - { - case QEvent::KeyPress: - keyPressEvent(static_cast(event)); - return true; +void KeySequenceWidget::keyPressEvent(QKeyEvent *event) { + event->accept(); - case QEvent::MouseButtonRelease: - event->accept(); - return true; + if (status() == Stopped) + return; - case QEvent::ShortcutOverride: - event->accept(); - return true; + if (m_KeySequence.appendKey(event->key(), event->modifiers())) + stopRecording(); - case QEvent::FocusOut: - stopRecording(); - if (!valid()) - { - keySequence() = backupSequence(); - updateOutput(); - } - break; - - default: - break; - } - } - - return QPushButton::event(event); + updateOutput(); } -void KeySequenceWidget::keyPressEvent(QKeyEvent* event) -{ - event->accept(); +void KeySequenceWidget::updateOutput() { + QString s; - if (status() == Stopped) - return; + if (m_KeySequence.isMouseButton()) + s = mousePrefix() + m_KeySequence.toString() + mousePostfix(); + else + s = keyPrefix() + m_KeySequence.toString() + keyPostfix(); - if (m_KeySequence.appendKey(event->key(), event->modifiers())) - stopRecording(); - - updateOutput(); -} - -void KeySequenceWidget::updateOutput() -{ - QString s; - - if (m_KeySequence.isMouseButton()) - s = mousePrefix() + m_KeySequence.toString() + mousePostfix(); - else - s = keyPrefix() + m_KeySequence.toString() + keyPostfix(); - - setText(s); + setText(s); } diff --git a/src/gui/src/KeySequenceWidget.h b/src/gui/src/KeySequenceWidget.h index ecd81b945..4dc6bac45 100644 --- a/src/gui/src/KeySequenceWidget.h +++ b/src/gui/src/KeySequenceWidget.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2008 Volker Lanz (vl@fidra.de) - * + * * 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 LICENSE 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 @@ -24,58 +24,56 @@ #include "KeySequence.h" -class KeySequenceWidget : public QPushButton -{ - Q_OBJECT +class KeySequenceWidget : public QPushButton { + Q_OBJECT - public: - KeySequenceWidget(QWidget* parent, const KeySequence& seq = KeySequence()); +public: + KeySequenceWidget(QWidget *parent, const KeySequence &seq = KeySequence()); - signals: - void keySequenceChanged(); +signals: + void keySequenceChanged(); - public: - const QString& mousePrefix() const { return m_MousePrefix; } - const QString& mousePostfix() const { return m_MousePostfix; } - const QString& keyPrefix() const { return m_KeyPrefix; } - const QString& keyPostfix() const { return m_KeyPostfix; } +public: + const QString &mousePrefix() const { return m_MousePrefix; } + const QString &mousePostfix() const { return m_MousePostfix; } + const QString &keyPrefix() const { return m_KeyPrefix; } + const QString &keyPostfix() const { return m_KeyPostfix; } - void setMousePrefix(const QString& s) { m_MousePrefix = s; } - void setMousePostfix(const QString& s) { m_MousePostfix = s; } - void setKeyPrefix(const QString& s) { m_KeyPrefix = s; } - void setKeyPostfix(const QString& s) { m_KeyPostfix = s; } + void setMousePrefix(const QString &s) { m_MousePrefix = s; } + void setMousePostfix(const QString &s) { m_MousePostfix = s; } + void setKeyPrefix(const QString &s) { m_KeyPrefix = s; } + void setKeyPostfix(const QString &s) { m_KeyPostfix = s; } - const KeySequence& keySequence() const { return m_KeySequence; } - const KeySequence& backupSequence() const { return m_BackupSequence; } - void setKeySequence(const KeySequence& seq); + const KeySequence &keySequence() const { return m_KeySequence; } + const KeySequence &backupSequence() const { return m_BackupSequence; } + void setKeySequence(const KeySequence &seq); - bool valid() const { return keySequence().valid(); } + bool valid() const { return keySequence().valid(); } - protected: - void mousePressEvent(QMouseEvent*); - void keyPressEvent(QKeyEvent*); - bool event(QEvent* event); - void appendToSequence(int key); - void updateOutput(); - void startRecording(); - void stopRecording(); - KeySequence& keySequence() { return m_KeySequence; } - KeySequence& backupSequence() { return m_BackupSequence; } +protected: + void mousePressEvent(QMouseEvent *); + void keyPressEvent(QKeyEvent *); + bool event(QEvent *event); + void appendToSequence(int key); + void updateOutput(); + void startRecording(); + void stopRecording(); + KeySequence &keySequence() { return m_KeySequence; } + KeySequence &backupSequence() { return m_BackupSequence; } - private: - enum Status { Stopped, Recording }; - void setStatus(Status s) { m_Status = s; } - Status status() const { return m_Status; } +private: + enum Status { Stopped, Recording }; + void setStatus(Status s) { m_Status = s; } + Status status() const { return m_Status; } - private: - KeySequence m_KeySequence; - KeySequence m_BackupSequence; - Status m_Status; - QString m_MousePrefix; - QString m_MousePostfix; - QString m_KeyPrefix; - QString m_KeyPostfix; +private: + KeySequence m_KeySequence; + KeySequence m_BackupSequence; + Status m_Status; + QString m_MousePrefix; + QString m_MousePostfix; + QString m_KeyPrefix; + QString m_KeyPostfix; }; #endif - diff --git a/src/gui/src/LicenseManager.cpp b/src/gui/src/LicenseManager.cpp index b4c899b36..a1ecda15f 100644 --- a/src/gui/src/LicenseManager.cpp +++ b/src/gui/src/LicenseManager.cpp @@ -17,255 +17,218 @@ #include "LicenseManager.h" #include "AppConfig.h" +#include +#include +#include +#include #include #include #include -#include -#include -#include -#include namespace { -std::string -getMaintenanceMessage(const SerialKey& serialKey) -{ - auto expiration = QDateTime::fromTime_t(serialKey.getExpiration()).date(); - QString message = "The license key you used will only work with versions of Synergy released before %1." - "

To use this version, you’ll need to renew your Synergy maintenance license. " - "Renew today.

"; - auto formatedDate = QLocale("en_US").toString(expiration, "MMM dd yyyy"); - return message.arg(formatedDate).toStdString(); +std::string getMaintenanceMessage(const SerialKey &serialKey) { + auto expiration = QDateTime::fromTime_t(serialKey.getExpiration()).date(); + QString message = + "The license key you used will only work with versions of Synergy " + "released before %1." + "

To use this version, you’ll need to renew your Synergy maintenance " + "license. " + "Renew today.

"; + auto formatedDate = QLocale("en_US").toString(expiration, "MMM dd yyyy"); + return message.arg(formatedDate).toStdString(); } -void -checkSerialKey(const SerialKey& serialKey, bool acceptExpired) -{ - if (serialKey.isMaintenance()) { - auto buildDate = QDateTime::fromString(__TIMESTAMP__).toTime_t(); +void checkSerialKey(const SerialKey &serialKey, bool acceptExpired) { + if (serialKey.isMaintenance()) { + auto buildDate = QDateTime::fromString(__TIMESTAMP__).toTime_t(); - if (buildDate > serialKey.getExpiration()) { - throw std::runtime_error(getMaintenanceMessage(serialKey)); - } + if (buildDate > serialKey.getExpiration()) { + throw std::runtime_error(getMaintenanceMessage(serialKey)); } + } - if (!acceptExpired && serialKey.isExpired(::time(nullptr))) { - throw std::runtime_error("Serial key expired"); + if (!acceptExpired && serialKey.isExpired(::time(nullptr))) { + throw std::runtime_error("Serial key expired"); + } + +#ifdef SYNERGY_BUSINESS + if (!serialKey.isValid()) { + throw std::runtime_error("The serial key is not compatible with the " + "business version of Synergy."); + } +#endif +} + +} // namespace + +LicenseManager::LicenseManager(AppConfig *appConfig) + : m_AppConfig(appConfig), m_serialKey(appConfig->edition()), + m_registry(*appConfig) {} + +void LicenseManager::setSerialKey(SerialKey serialKey, bool acceptExpired) { + checkSerialKey(serialKey, acceptExpired); + + if (serialKey != m_serialKey) { + using std::swap; + swap(serialKey, m_serialKey); + m_AppConfig->setSerialKey(QString::fromStdString(m_serialKey.toString())); + + emit showLicenseNotice(getLicenseNotice()); + validateSerialKey(); + m_registry.scheduleRegistration(); + + if (m_serialKey.edition() != serialKey.edition()) { + m_AppConfig->setEdition(m_serialKey.edition()); + emit editionChanged(m_serialKey.edition()); } + } +} - #ifdef SYNERGY_BUSINESS - if (!serialKey.isValid()) { - throw std::runtime_error("The serial key is not compatible with the business version of Synergy."); +void LicenseManager::notifyUpdate(QString fromVersion, + QString toVersion) const { + if ((fromVersion == "Unknown") && (m_serialKey == SerialKey(kUnregistered))) { + return; + } + + ActivationNotifier *notifier = new ActivationNotifier(); + notifier->setUpdateInfo(fromVersion, toVersion, + QString::fromStdString(m_serialKey.toString())); + + QThread *thread = new QThread(); + connect(notifier, SIGNAL(finished()), thread, SLOT(quit())); + connect(notifier, SIGNAL(finished()), notifier, SLOT(deleteLater())); + connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); + + notifier->moveToThread(thread); + thread->start(); + + QMetaObject::invokeMethod(notifier, "notifyUpdate", Qt::QueuedConnection); +} + +Edition LicenseManager::activeEdition() const { return m_serialKey.edition(); } + +QString LicenseManager::activeEditionName() const { + return getEditionName(activeEdition(), m_serialKey.isTrial()); +} + +const SerialKey &LicenseManager::serialKey() const { return m_serialKey; } + +void LicenseManager::refresh() { + if (!m_AppConfig->serialKey().isEmpty()) { + try { + SerialKey serialKey(m_AppConfig->serialKey().toStdString()); + setSerialKey(serialKey, true); + } catch (...) { + m_serialKey = SerialKey(); + m_AppConfig->clearSerialKey(); } - #endif + } + if (!m_serialKey.isValid()) { + emit InvalidLicense(); + } } +void LicenseManager::skipActivation() const { + notifyActivation("skip:unknown"); } +QString LicenseManager::getEditionName(Edition const edition, bool trial) { + SerialKeyEdition KeyEdition(edition); + std::string name = KeyEdition.getDisplayName(); -LicenseManager::LicenseManager(AppConfig* appConfig) : - m_AppConfig(appConfig), - m_serialKey(appConfig->edition()), - m_registry(*appConfig) { + if (trial) { + name += " (Trial)"; + } + + return QString::fromUtf8(name.c_str(), static_cast(name.size())); } -void -LicenseManager::setSerialKey(SerialKey serialKey, bool acceptExpired) -{ - checkSerialKey(serialKey, acceptExpired); +void LicenseManager::notifyActivation(QString identity) const { + ActivationNotifier *notifier = new ActivationNotifier(); + notifier->setIdentity(identity); - if (serialKey != m_serialKey) { - using std::swap; - swap (serialKey, m_serialKey); - m_AppConfig->setSerialKey(QString::fromStdString - (m_serialKey.toString())); + QThread *thread = new QThread(); + connect(notifier, SIGNAL(finished()), thread, SLOT(quit())); + connect(notifier, SIGNAL(finished()), notifier, SLOT(deleteLater())); + connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); - emit showLicenseNotice(getLicenseNotice()); - validateSerialKey(); - m_registry.scheduleRegistration(); + notifier->moveToThread(thread); + thread->start(); - if (m_serialKey.edition() != serialKey.edition()) { - m_AppConfig->setEdition(m_serialKey.edition()); - emit editionChanged(m_serialKey.edition()); - } + QMetaObject::invokeMethod(notifier, "notify", Qt::QueuedConnection); +} + +QString LicenseManager::getLicenseNotice() const { + QString Notice; + + if (m_serialKey.isTemporary()) { + if (m_serialKey.isTrial()) { + Notice = getTrialNotice(); + } else { + Notice = getTemporaryNotice(); } + } + + return Notice; } -void -LicenseManager::notifyUpdate(QString fromVersion, QString toVersion) const { - if ((fromVersion == "Unknown") - && (m_serialKey == SerialKey(kUnregistered))) { - return; - } - - ActivationNotifier* notifier = new ActivationNotifier(); - notifier->setUpdateInfo (fromVersion, toVersion, - QString::fromStdString(m_serialKey.toString())); - - QThread* thread = new QThread(); - connect(notifier, SIGNAL(finished()), thread, SLOT(quit())); - connect(notifier, SIGNAL(finished()), notifier, SLOT(deleteLater())); - connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); - - notifier->moveToThread(thread); - thread->start(); - - QMetaObject::invokeMethod(notifier, "notifyUpdate", - Qt::QueuedConnection); -} - -Edition -LicenseManager::activeEdition() const -{ - return m_serialKey.edition(); -} - -QString -LicenseManager::activeEditionName() const -{ - return getEditionName(activeEdition(), m_serialKey.isTrial()); -} - -const SerialKey& -LicenseManager::serialKey() const -{ - return m_serialKey; -} - -void -LicenseManager::refresh() -{ - if (!m_AppConfig->serialKey().isEmpty()) { - try { - SerialKey serialKey (m_AppConfig->serialKey().toStdString()); - setSerialKey(serialKey, true); - } catch (...) { - m_serialKey = SerialKey(); - m_AppConfig->clearSerialKey(); - } - } - if (!m_serialKey.isValid()) { - emit InvalidLicense(); - } -} - -void -LicenseManager::skipActivation() const -{ - notifyActivation ("skip:unknown"); -} - -QString -LicenseManager::getEditionName(Edition const edition, bool trial) -{ - SerialKeyEdition KeyEdition(edition); - std::string name = KeyEdition.getDisplayName(); - - if (trial) { - name += " (Trial)"; - } - - return QString::fromUtf8 (name.c_str(), static_cast(name.size())); -} - -void -LicenseManager::notifyActivation(QString identity) const -{ - ActivationNotifier* notifier = new ActivationNotifier(); - notifier->setIdentity(identity); - - QThread* thread = new QThread(); - connect(notifier, SIGNAL(finished()), thread, SLOT(quit())); - connect(notifier, SIGNAL(finished()), notifier, SLOT(deleteLater())); - connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); - - notifier->moveToThread(thread); - thread->start(); - - QMetaObject::invokeMethod(notifier, "notify", Qt::QueuedConnection); -} - -QString -LicenseManager::getLicenseNotice() const -{ - QString Notice; - - if (m_serialKey.isTemporary()){ - if (m_serialKey.isTrial()){ - Notice = getTrialNotice(); - } - else{ - Notice = getTemporaryNotice(); - } - } - - return Notice; -} - -void -LicenseManager::registerLicense() -{ - m_registry.registerLicense(); -} - -QString -LicenseManager::getTrialNotice() const -{ - QString Notice; - - if (m_serialKey.isExpired(::time(0))){ - Notice = "

" - "Trial expired - " - "Buy now" - "

"; - } - else{ - Notice = "

" - "Trial expires in %1 day%2 - " - "Buy now" - "

"; - - time_t daysLeft = m_serialKey.daysLeft(::time(0)); - Notice = Notice.arg (daysLeft).arg ((daysLeft == 1) ? "" : "s"); - } - - return Notice; -} - -QString -LicenseManager::getTemporaryNotice() const -{ - QString Notice; - - if (m_serialKey.isExpired(::time(0))) { - Notice = "

" - "License expired - " - "Renew now" - "

"; - } - else if (m_serialKey.isExpiring(::time(0))) { - Notice = "

" - "License expires in %1 day%2 - " - "Renew now" - "

"; - - time_t daysLeft = m_serialKey.daysLeft(::time(0)); - Notice = Notice.arg (daysLeft).arg ((daysLeft == 1) ? "" : "s"); - } - - return Notice; -} - -void -LicenseManager::validateSerialKey() const -{ - if (m_serialKey.isValid()) { - if (m_serialKey.isTemporary()){ - QTimer::singleShot(m_serialKey.getSpanLeft(), this, SLOT(validateSerialKey())); - } - } - else{ - emit InvalidLicense(); +void LicenseManager::registerLicense() { m_registry.registerLicense(); } + +QString LicenseManager::getTrialNotice() const { + QString Notice; + + if (m_serialKey.isExpired(::time(0))) { + Notice = "

" + "Trial expired - " + "Buy now" + "

"; + } else { + Notice = "

" + "Trial expires in %1 day%2 - " + "Buy now" + "

"; + + time_t daysLeft = m_serialKey.daysLeft(::time(0)); + Notice = Notice.arg(daysLeft).arg((daysLeft == 1) ? "" : "s"); + } + + return Notice; +} + +QString LicenseManager::getTemporaryNotice() const { + QString Notice; + + if (m_serialKey.isExpired(::time(0))) { + Notice = "

" + "License expired - " + "Renew now" + "

"; + } else if (m_serialKey.isExpiring(::time(0))) { + Notice = "

" + "License expires in %1 day%2 - " + "Renew now" + "

"; + + time_t daysLeft = m_serialKey.daysLeft(::time(0)); + Notice = Notice.arg(daysLeft).arg((daysLeft == 1) ? "" : "s"); + } + + return Notice; +} + +void LicenseManager::validateSerialKey() const { + if (m_serialKey.isValid()) { + if (m_serialKey.isTemporary()) { + QTimer::singleShot(m_serialKey.getSpanLeft(), this, + SLOT(validateSerialKey())); } + } else { + emit InvalidLicense(); + } } diff --git a/src/gui/src/LicenseManager.h b/src/gui/src/LicenseManager.h index 1c9feeefb..065705eee 100644 --- a/src/gui/src/LicenseManager.h +++ b/src/gui/src/LicenseManager.h @@ -17,48 +17,47 @@ #pragma once +#include #include #include #include -#include #include #include "LicenseRegistry.h" class AppConfig; -class LicenseManager: public QObject -{ - Q_OBJECT +class LicenseManager : public QObject { + Q_OBJECT public: - LicenseManager(AppConfig* appConfig); - void setSerialKey(SerialKey serialKey, bool acceptExpired = false); - void refresh(); - Edition activeEdition() const; - QString activeEditionName() const; - const SerialKey& serialKey() const; - void skipActivation() const; - void notifyUpdate(QString fromVersion, QString toVersion) const; - static QString getEditionName(Edition edition, bool trial = false); - void notifyActivation(QString identity) const; - QString getLicenseNotice() const; + LicenseManager(AppConfig *appConfig); + void setSerialKey(SerialKey serialKey, bool acceptExpired = false); + void refresh(); + Edition activeEdition() const; + QString activeEditionName() const; + const SerialKey &serialKey() const; + void skipActivation() const; + void notifyUpdate(QString fromVersion, QString toVersion) const; + static QString getEditionName(Edition edition, bool trial = false); + void notifyActivation(QString identity) const; + QString getLicenseNotice() const; private: - AppConfig* m_AppConfig; - SerialKey m_serialKey; - LicenseRegistry m_registry; + AppConfig *m_AppConfig; + SerialKey m_serialKey; + LicenseRegistry m_registry; public slots: - void validateSerialKey() const; - void registerLicense(); + void validateSerialKey() const; + void registerLicense(); signals: - void editionChanged (Edition) const; - void InvalidLicense () const; - void showLicenseNotice(const QString& notice) const; + void editionChanged(Edition) const; + void InvalidLicense() const; + void showLicenseNotice(const QString ¬ice) const; protected: - QString getTrialNotice() const; - QString getTemporaryNotice() const; + QString getTrialNotice() const; + QString getTemporaryNotice() const; }; diff --git a/src/gui/src/LicenseRegistry.cpp b/src/gui/src/LicenseRegistry.cpp index 3549dffd4..31dff55cd 100644 --- a/src/gui/src/LicenseRegistry.cpp +++ b/src/gui/src/LicenseRegistry.cpp @@ -14,92 +14,85 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -#include -#include #include +#include +#include #include -#include "LicenseRegistry.h" #include "AppConfig.h" +#include "LicenseRegistry.h" #include -LicenseRegistry::LicenseRegistry(AppConfig& config) : - m_config(config) -{ - connect(&m_timer, SIGNAL(timeout()), this, SLOT(registerLicense())); +LicenseRegistry::LicenseRegistry(AppConfig &config) : m_config(config) { + connect(&m_timer, SIGNAL(timeout()), this, SLOT(registerLicense())); } -void LicenseRegistry::registerLicense() -{ - m_timer.stop(); - if (m_config.edition() == Edition::kBusiness) { - const auto REGISTER_LICENSE_URL = m_config.getLicenseRegistryUrl(); - const auto url = QUrl(REGISTER_LICENSE_URL); +void LicenseRegistry::registerLicense() { + m_timer.stop(); + if (m_config.edition() == Edition::kBusiness) { + const auto REGISTER_LICENSE_URL = m_config.getLicenseRegistryUrl(); + const auto url = QUrl(REGISTER_LICENSE_URL); - auto request = QNetworkRequest(url); - request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); + auto request = QNetworkRequest(url); + request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); - m_manager.post(request, getRequestData()); - connect(&m_manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(handleResponse(QNetworkReply*))); + m_manager.post(request, getRequestData()); + connect(&m_manager, SIGNAL(finished(QNetworkReply *)), this, + SLOT(handleResponse(QNetworkReply *))); + } +} + +void LicenseRegistry::handleResponse(QNetworkReply *reply) { + if (reply) { + const auto HOUR = (60 * 60); // seconds per hour + const auto DAY = (24 * HOUR); // seconds per day + const auto WEEK = (7 * DAY); // seconds per week + const auto currentTimestamp = time(nullptr); + + if (reply->error() == QNetworkReply::NoError) { + m_config.setLicenseNextCheck(currentTimestamp + WEEK); + } else { + m_config.setLicenseNextCheck(currentTimestamp + HOUR); } + + scheduleRegistration(); + reply->deleteLater(); + } } -void LicenseRegistry::handleResponse(QNetworkReply *reply) -{ - if (reply) { - const auto HOUR = (60*60); //seconds per hour - const auto DAY = (24*HOUR);//seconds per day - const auto WEEK = (7*DAY); //seconds per week - const auto currentTimestamp = time(nullptr); - - if(reply->error() == QNetworkReply::NoError) { - m_config.setLicenseNextCheck(currentTimestamp + WEEK); - } - else{ - m_config.setLicenseNextCheck(currentTimestamp + HOUR); - } - - scheduleRegistration(); - reply->deleteLater(); - } -} - -QByteArray LicenseRegistry::getRequestData() const -{ +QByteArray LicenseRegistry::getRequestData() const { #if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0) - QString guid(QSysInfo::machineUniqueId()); + QString guid(QSysInfo::machineUniqueId()); #else - QString guid; + QString guid; #endif - QJsonObject data; - if (!guid.isEmpty()) { - data["guid"] = guid; - data["guid_type"] = "system"; - } - else { - data["guid"] = m_config.getGuid(); - data["guid_type"] = "synergy"; - } + QJsonObject data; + if (!guid.isEmpty()) { + data["guid"] = guid; + data["guid_type"] = "system"; + } else { + data["guid"] = m_config.getGuid(); + data["guid_type"] = "synergy"; + } - data["key"] = m_config.serialKey(); - data["is_server"] = m_config.getServerGroupChecked(); + data["key"] = m_config.serialKey(); + data["is_server"] = m_config.getServerGroupChecked(); - return QJsonDocument(data).toJson(); + return QJsonDocument(data).toJson(); } -void LicenseRegistry::scheduleRegistration() -{ - const auto nextCheck = m_config.getLicenseNextCheck(); - const auto currentTimestamp = static_cast(time(nullptr)); +void LicenseRegistry::scheduleRegistration() { + const auto nextCheck = m_config.getLicenseNextCheck(); + const auto currentTimestamp = static_cast(time(nullptr)); - if (currentTimestamp >= nextCheck) { - registerLicense(); - } - else { - const auto interval = (nextCheck - currentTimestamp) * 1000; //interval in milliseconds - m_timer.setInterval(static_cast(interval)); - m_timer.setSingleShot(true); - m_timer.start(); - } + if (currentTimestamp >= nextCheck) { + registerLicense(); + } else { + const auto interval = + (nextCheck - currentTimestamp) * 1000; // interval in milliseconds + m_timer.setInterval(static_cast(interval)); + m_timer.setSingleShot(true); + m_timer.start(); + } } diff --git a/src/gui/src/LicenseRegistry.h b/src/gui/src/LicenseRegistry.h index 8fa45b00c..beef26f7e 100644 --- a/src/gui/src/LicenseRegistry.h +++ b/src/gui/src/LicenseRegistry.h @@ -16,29 +16,28 @@ */ #pragma once +#include #include #include -#include class QNetworkReply; class AppConfig; -class LicenseRegistry : public QObject -{ - Q_OBJECT +class LicenseRegistry : public QObject { + Q_OBJECT public: - explicit LicenseRegistry(AppConfig& config); - void scheduleRegistration(); + explicit LicenseRegistry(AppConfig &config); + void scheduleRegistration(); public slots: - void registerLicense(); - void handleResponse(QNetworkReply *reply); + void registerLicense(); + void handleResponse(QNetworkReply *reply); private: - AppConfig& m_config; - QNetworkAccessManager m_manager; - QTimer m_timer; + AppConfig &m_config; + QNetworkAccessManager m_manager; + QTimer m_timer; - QByteArray getRequestData() const; + QByteArray getRequestData() const; }; diff --git a/src/gui/src/MainWindow.cpp b/src/gui/src/MainWindow.cpp index 1524322a3..d173bc5ca 100644 --- a/src/gui/src/MainWindow.cpp +++ b/src/gui/src/MainWindow.cpp @@ -17,1595 +17,1453 @@ */ #define DOWNLOAD_URL "http://symless.com/?source=gui" -#define HELP_URL "http://symless.com/help?source=gui" +#define HELP_URL "http://symless.com/help?source=gui" #include #include "MainWindow.h" -#include "Fingerprint.h" #include "AboutDialog.h" #include "AboutDialogEliteBackers.h" +#include "ActivationDialog.h" +#include "CommandProcess.h" +#include "DataDownloader.h" +#include "Fingerprint.h" +#include "LicenseManager.h" +#include "ProcessorArch.h" +#include "QUtility.h" #include "ServerConfigDialog.h" #include "SettingsDialog.h" -#include "ActivationDialog.h" -#include "DataDownloader.h" -#include "CommandProcess.h" -#include "LicenseManager.h" -#include -#include "QUtility.h" -#include "ProcessorArch.h" #include "SslCertificate.h" #include "Zeroconf.h" #include +#include #if defined(Q_OS_MAC) #include "OSXHelpers.h" #endif -#include -#include -#include -#include +#include +#include +#include #include #include #include -#include -#include -#include +#include +#include +#include +#include #if defined(Q_OS_MAC) #include #endif -static const char* tlsCheckString = "network encryption protocol: "; +static const char *tlsCheckString = "network encryption protocol: "; static const int debugLogLevel = 1; -static const char* synergyLightIconFiles[] = -{ +static const char *synergyLightIconFiles[] = { ":/res/icons/64x64/synergy-light-disconnected.png", ":/res/icons/64x64/synergy-light-disconnected.png", ":/res/icons/64x64/synergy-light-connected.png", ":/res/icons/64x64/synergy-light-transfering.png", - ":/res/icons/64x64/synergy-light-disconnected.png" -}; + ":/res/icons/64x64/synergy-light-disconnected.png"}; -static const char* synergyDarkIconFiles[] = -{ +static const char *synergyDarkIconFiles[] = { ":/res/icons/64x64/synergy-dark-disconnected.png", ":/res/icons/64x64/synergy-dark-disconnected.png", ":/res/icons/64x64/synergy-dark-connected.png", ":/res/icons/64x64/synergy-dark-transfering.png", - ":/res/icons/64x64/synergy-dark-disconnected.png" //synergyPendingRetry + ":/res/icons/64x64/synergy-dark-disconnected.png" // synergyPendingRetry }; -static const char* synergyDefaultIconFiles[] = -{ - ":/res/icons/16x16/synergy-disconnected.png", //synergyDisconnected - ":/res/icons/16x16/synergy-disconnected.png", //synergyConnecting - ":/res/icons/16x16/synergy-connected.png", //synergyConnected - ":/res/icons/16x16/synergy-transfering.png", //synergyListening - ":/res/icons/16x16/synergy-disconnected.png" //synergyPendingRetry +static const char *synergyDefaultIconFiles[] = { + ":/res/icons/16x16/synergy-disconnected.png", // synergyDisconnected + ":/res/icons/16x16/synergy-disconnected.png", // synergyConnecting + ":/res/icons/16x16/synergy-connected.png", // synergyConnected + ":/res/icons/16x16/synergy-transfering.png", // synergyListening + ":/res/icons/16x16/synergy-disconnected.png" // synergyPendingRetry }; #ifdef SYNERGY_ENTERPRISE -MainWindow::MainWindow (AppConfig& appConfig) +MainWindow::MainWindow(AppConfig &appConfig) #else -MainWindow::MainWindow (AppConfig& appConfig, - LicenseManager& licenseManager) +MainWindow::MainWindow(AppConfig &appConfig, LicenseManager &licenseManager) #endif -: + : #ifndef SYNERGY_ENTERPRISE - m_LicenseManager(&licenseManager), - m_ActivationDialogRunning(false), + m_LicenseManager(&licenseManager), m_ActivationDialogRunning(false), #endif - m_pZeroconf(nullptr), - m_AppConfig(&appConfig), - m_pSynergy(NULL), - m_SynergyState(synergyDisconnected), - m_ServerConfig(5, 3, m_AppConfig, this), - m_AlreadyHidden(false), - m_pMenuBar(NULL), - m_pMenuFile(NULL), - m_pMenuEdit(NULL), - m_pMenuWindow(NULL), - m_pMenuHelp(NULL), - m_pCancelButton(NULL), - m_ExpectedRunningState(kStopped), - m_SecureSocket(false), - m_serverConnection(*this), - m_clientConnection(*this) -{ + m_pZeroconf(nullptr), m_AppConfig(&appConfig), m_pSynergy(NULL), + m_SynergyState(synergyDisconnected), + m_ServerConfig(5, 3, m_AppConfig, this), m_AlreadyHidden(false), + m_pMenuBar(NULL), m_pMenuFile(NULL), m_pMenuEdit(NULL), + m_pMenuWindow(NULL), m_pMenuHelp(NULL), m_pCancelButton(NULL), + m_ExpectedRunningState(kStopped), m_SecureSocket(false), + m_serverConnection(*this), m_clientConnection(*this) { #if !defined(SYNERGY_ENTERPRISE) && defined(SYNERGY_AUTOCONFIG) - m_pZeroconf = new Zeroconf(this); + m_pZeroconf = new Zeroconf(this); #endif - setupUi(this); + setupUi(this); #if defined(Q_OS_MAC) - m_pRadioGroupServer->setAttribute(Qt::WA_MacShowFocusRect,0); - m_pRadioGroupClient->setAttribute(Qt::WA_MacShowFocusRect,0); + m_pRadioGroupServer->setAttribute(Qt::WA_MacShowFocusRect, 0); + m_pRadioGroupClient->setAttribute(Qt::WA_MacShowFocusRect, 0); #endif - updateAutoConfigWidgets(); + updateAutoConfigWidgets(); - createMenuBar(); - loadSettings(); - initConnections(); + createMenuBar(); + loadSettings(); + initConnections(); - m_pWidgetUpdate->hide(); - m_VersionChecker.setApp(appPath(appConfig.synergycName())); + m_pWidgetUpdate->hide(); + m_VersionChecker.setApp(appPath(appConfig.synergycName())); - updateScreenName(); - connect(m_AppConfig, SIGNAL(screenNameChanged()), this, SLOT(updateScreenName())); - m_pLabelIpAddresses->setText(tr("This computer's IP addresses: %1").arg(getIPAddresses())); + updateScreenName(); + connect(m_AppConfig, SIGNAL(screenNameChanged()), this, + SLOT(updateScreenName())); + m_pLabelIpAddresses->setText( + tr("This computer's IP addresses: %1").arg(getIPAddresses())); #if defined(Q_OS_WIN) - // ipc must always be enabled, so that we can disable command when switching to desktop mode. - connect(&m_IpcClient, SIGNAL(readLogLine(const QString&)), this, SLOT(appendLogRaw(const QString&))); - connect(&m_IpcClient, SIGNAL(errorMessage(const QString&)), this, SLOT(appendLogError(const QString&))); - connect(&m_IpcClient, SIGNAL(infoMessage(const QString&)), this, SLOT(appendLogInfo(const QString&))); - connect(&m_IpcClient, SIGNAL(readLogLine(const QString&)), this, SLOT(handleIdleService(const QString&))); - m_IpcClient.connectToHost(); + // ipc must always be enabled, so that we can disable command when switching + // to desktop mode. + connect(&m_IpcClient, SIGNAL(readLogLine(const QString &)), this, + SLOT(appendLogRaw(const QString &))); + connect(&m_IpcClient, SIGNAL(errorMessage(const QString &)), this, + SLOT(appendLogError(const QString &))); + connect(&m_IpcClient, SIGNAL(infoMessage(const QString &)), this, + SLOT(appendLogInfo(const QString &))); + connect(&m_IpcClient, SIGNAL(readLogLine(const QString &)), this, + SLOT(handleIdleService(const QString &))); + m_IpcClient.connectToHost(); #endif - // change default size based on os + // change default size based on os #if defined(Q_OS_MAC) - resize(720, 550); - setMinimumSize(size()); + resize(720, 550); + setMinimumSize(size()); #elif defined(Q_OS_LINUX) - resize(700, 530); - setMinimumSize(size()); + resize(700, 530); + setMinimumSize(size()); #endif - m_trialLabel->hide(); + m_trialLabel->hide(); - // hide padlock icon - secureSocket(false); + // hide padlock icon + secureSocket(false); - - - connect (this, SIGNAL(windowShown()), - this, SLOT(on_windowShown()), Qt::QueuedConnection); + connect(this, SIGNAL(windowShown()), this, SLOT(on_windowShown()), + Qt::QueuedConnection); #ifndef SYNERGY_ENTERPRISE - connect (m_LicenseManager, SIGNAL(editionChanged(Edition)), - this, SLOT(setEdition(Edition)), Qt::QueuedConnection); + connect(m_LicenseManager, SIGNAL(editionChanged(Edition)), this, + SLOT(setEdition(Edition)), Qt::QueuedConnection); - connect (m_LicenseManager, SIGNAL(showLicenseNotice(QString)), - this, SLOT(showLicenseNotice(QString)), Qt::QueuedConnection); + connect(m_LicenseManager, SIGNAL(showLicenseNotice(QString)), this, + SLOT(showLicenseNotice(QString)), Qt::QueuedConnection); - connect (m_LicenseManager, SIGNAL(InvalidLicense()), - this, SLOT(InvalidLicense()), Qt::QueuedConnection); + connect(m_LicenseManager, SIGNAL(InvalidLicense()), this, + SLOT(InvalidLicense()), Qt::QueuedConnection); #endif - connect (m_AppConfig, SIGNAL(sslToggled()), - this, SLOT(updateLocalFingerprint()), Qt::QueuedConnection); + connect(m_AppConfig, SIGNAL(sslToggled()), this, + SLOT(updateLocalFingerprint()), Qt::QueuedConnection); - connect (m_AppConfig, SIGNAL(zeroConfToggled()), - this, SLOT(zeroConfToggled()), Qt::QueuedConnection); + connect(m_AppConfig, SIGNAL(zeroConfToggled()), this, SLOT(zeroConfToggled()), + Qt::QueuedConnection); - updateWindowTitle(); + updateWindowTitle(); - QString lastVersion = m_AppConfig->lastVersion(); - if (lastVersion != SYNERGY_VERSION) { - m_AppConfig->setLastVersion (SYNERGY_VERSION); + QString lastVersion = m_AppConfig->lastVersion(); + if (lastVersion != SYNERGY_VERSION) { + m_AppConfig->setLastVersion(SYNERGY_VERSION); #ifndef SYNERGY_ENTERPRISE - m_LicenseManager->notifyUpdate (lastVersion, SYNERGY_VERSION); + m_LicenseManager->notifyUpdate(lastVersion, SYNERGY_VERSION); #endif - } + } #ifdef SYNERGY_ENTERPRISE - m_pActivate->setVisible(false); + m_pActivate->setVisible(false); #endif #if !defined(SYNERGY_ENTERPRISE) && defined(SYNERGY_AUTOCONFIG) - updateZeroconfService(); + updateZeroconfService(); - addZeroconfServer(m_AppConfig->autoConfigServer()); + addZeroconfServer(m_AppConfig->autoConfigServer()); - updateAutoConfigWidgets(); + updateAutoConfigWidgets(); #endif } -MainWindow::~MainWindow() -{ - if (appConfig().processMode() == Desktop) { - m_ExpectedRunningState = kStopped; - try { - stopDesktop(); - } - catch (...) { - // do not throw, since throwing from a dtor can result in unreliable behaviour. - qCritical() << "error stopping desktop in main window destructor"; - } +MainWindow::~MainWindow() { + if (appConfig().processMode() == Desktop) { + m_ExpectedRunningState = kStopped; + try { + stopDesktop(); + } catch (...) { + // do not throw, since throwing from a dtor can result in unreliable + // behaviour. + qCritical() << "error stopping desktop in main window destructor"; } + } #if !defined(SYNERGY_ENTERPRISE) && defined(SYNERGY_AUTOCONFIG) - delete m_pZeroconf; + delete m_pZeroconf; #endif } -void MainWindow::open() -{ - std::array trayMenu = { - m_pActionStartSynergy, - m_pActionStopSynergy, - nullptr, - m_pActionMinimize, - m_pActionRestore, - nullptr, - m_pActionQuit - }; +void MainWindow::open() { + std::array trayMenu = { + m_pActionStartSynergy, m_pActionStopSynergy, nullptr, + m_pActionMinimize, m_pActionRestore, nullptr, + m_pActionQuit}; - m_trayIcon.create(trayMenu, [this](QObject const *o, const char *s) { - connect(o, s, this, SLOT(trayActivated(QSystemTrayIcon::ActivationReason))); - setIcon(synergyDisconnected); - }); + m_trayIcon.create(trayMenu, [this](QObject const *o, const char *s) { + connect(o, s, this, SLOT(trayActivated(QSystemTrayIcon::ActivationReason))); + setIcon(synergyDisconnected); + }); - if (appConfig().getAutoHide()) { - hide(); - } else { - showNormal(); - } + if (appConfig().getAutoHide()) { + hide(); + } else { + showNormal(); + } - m_VersionChecker.checkLatest(); + m_VersionChecker.checkLatest(); - // only start if user has previously started. this stops the gui from - // auto hiding before the user has configured synergy (which of course - // confuses first time users, who think synergy has crashed). - if (appConfig().startedBefore() && appConfig().processMode() == ProcessMode::Desktop) { - startSynergy(); - } + // only start if user has previously started. this stops the gui from + // auto hiding before the user has configured synergy (which of course + // confuses first time users, who think synergy has crashed). + if (appConfig().startedBefore() && + appConfig().processMode() == ProcessMode::Desktop) { + startSynergy(); + } } -void MainWindow::setStatus(const QString &status) -{ - m_pStatusLabel->setText(status); +void MainWindow::setStatus(const QString &status) { + m_pStatusLabel->setText(status); } -void MainWindow::retranslateMenuBar() -{ - m_pMenuFile->setTitle(tr("&File")); - m_pMenuEdit->setTitle(tr("&Edit")); - m_pMenuWindow->setTitle(tr("&Window")); - m_pMenuHelp->setTitle(tr("&Help")); +void MainWindow::retranslateMenuBar() { + m_pMenuFile->setTitle(tr("&File")); + m_pMenuEdit->setTitle(tr("&Edit")); + m_pMenuWindow->setTitle(tr("&Window")); + m_pMenuHelp->setTitle(tr("&Help")); } -void MainWindow::createMenuBar() -{ - m_pMenuBar = new QMenuBar(this); - m_pMenuFile = new QMenu("", m_pMenuBar); - m_pMenuEdit = new QMenu("", m_pMenuBar); - m_pMenuWindow = new QMenu("", m_pMenuBar); - m_pMenuHelp = new QMenu("", m_pMenuBar); - retranslateMenuBar(); +void MainWindow::createMenuBar() { + m_pMenuBar = new QMenuBar(this); + m_pMenuFile = new QMenu("", m_pMenuBar); + m_pMenuEdit = new QMenu("", m_pMenuBar); + m_pMenuWindow = new QMenu("", m_pMenuBar); + m_pMenuHelp = new QMenu("", m_pMenuBar); + retranslateMenuBar(); - m_pMenuBar->addAction(m_pMenuFile->menuAction()); - m_pMenuBar->addAction(m_pMenuEdit->menuAction()); + m_pMenuBar->addAction(m_pMenuFile->menuAction()); + m_pMenuBar->addAction(m_pMenuEdit->menuAction()); #if !defined(Q_OS_MAC) - m_pMenuBar->addAction(m_pMenuWindow->menuAction()); + m_pMenuBar->addAction(m_pMenuWindow->menuAction()); #endif - m_pMenuBar->addAction(m_pMenuHelp->menuAction()); + m_pMenuBar->addAction(m_pMenuHelp->menuAction()); - m_pMenuFile->addAction(m_pActionStartSynergy); - m_pMenuFile->addAction(m_pActionStopSynergy); - m_pMenuFile->addSeparator(); - m_pMenuFile->addAction(m_pActivate); - m_pMenuFile->addSeparator(); - m_pMenuFile->addAction(m_pActionSave); - m_pMenuFile->addSeparator(); - m_pMenuFile->addAction(m_pActionQuit); - m_pMenuEdit->addAction(m_pActionSettings); - m_pMenuWindow->addAction(m_pActionMinimize); - m_pMenuWindow->addAction(m_pActionRestore); - m_pMenuHelp->addAction(m_pActionAbout); - m_pMenuHelp->addAction(m_pActionHelp); + m_pMenuFile->addAction(m_pActionStartSynergy); + m_pMenuFile->addAction(m_pActionStopSynergy); + m_pMenuFile->addSeparator(); + m_pMenuFile->addAction(m_pActivate); + m_pMenuFile->addSeparator(); + m_pMenuFile->addAction(m_pActionSave); + m_pMenuFile->addSeparator(); + m_pMenuFile->addAction(m_pActionQuit); + m_pMenuEdit->addAction(m_pActionSettings); + m_pMenuWindow->addAction(m_pActionMinimize); + m_pMenuWindow->addAction(m_pActionRestore); + m_pMenuHelp->addAction(m_pActionAbout); + m_pMenuHelp->addAction(m_pActionHelp); - - setMenuBar(m_pMenuBar); + setMenuBar(m_pMenuBar); } -void MainWindow::loadSettings() -{ - enableServer(appConfig().getServerGroupChecked()); - enableClient(appConfig().getClientGroupChecked()); +void MainWindow::loadSettings() { + enableServer(appConfig().getServerGroupChecked()); + enableClient(appConfig().getClientGroupChecked()); - m_pLineEditHostname->setText(appConfig().getServerHostname()); - m_pLineEditClienIp->setText(serverConfig().getClientAddress()); + m_pLineEditHostname->setText(appConfig().getServerHostname()); + m_pLineEditClienIp->setText(serverConfig().getClientAddress()); } -void MainWindow::initConnections() -{ - connect(m_pActionMinimize, SIGNAL(triggered()), this, SLOT(hide())); - connect(m_pActionRestore, SIGNAL(triggered()), this, SLOT(showNormal())); - connect(m_pActionStartSynergy, SIGNAL(triggered()), this, SLOT(actionStart())); - connect(m_pActionStopSynergy, SIGNAL(triggered()), this, SLOT(stopSynergy())); - connect(m_pActionQuit, SIGNAL(triggered()), qApp, SLOT(quit())); - connect(&m_VersionChecker, SIGNAL(updateFound(const QString&)), this, SLOT(updateFound(const QString&))); +void MainWindow::initConnections() { + connect(m_pActionMinimize, SIGNAL(triggered()), this, SLOT(hide())); + connect(m_pActionRestore, SIGNAL(triggered()), this, SLOT(showNormal())); + connect(m_pActionStartSynergy, SIGNAL(triggered()), this, + SLOT(actionStart())); + connect(m_pActionStopSynergy, SIGNAL(triggered()), this, SLOT(stopSynergy())); + connect(m_pActionQuit, SIGNAL(triggered()), qApp, SLOT(quit())); + connect(&m_VersionChecker, SIGNAL(updateFound(const QString &)), this, + SLOT(updateFound(const QString &))); } -void MainWindow::saveSettings() -{ - // program settings - appConfig().setServerGroupChecked(m_pRadioGroupServer->isChecked()); - appConfig().setClientGroupChecked(m_pRadioGroupClient->isChecked()); - appConfig().setServerHostname(m_pLineEditHostname->text()); - serverConfig().setClientAddress(m_pLineEditClienIp->text()); +void MainWindow::saveSettings() { + // program settings + appConfig().setServerGroupChecked(m_pRadioGroupServer->isChecked()); + appConfig().setClientGroupChecked(m_pRadioGroupClient->isChecked()); + appConfig().setServerHostname(m_pLineEditHostname->text()); + serverConfig().setClientAddress(m_pLineEditClienIp->text()); - /* Save everything */ - GUI::Config::ConfigWriter::make()->globalSave(); + /* Save everything */ + GUI::Config::ConfigWriter::make()->globalSave(); } void MainWindow::zeroConfToggled() { #if !defined(SYNERGY_ENTERPRISE) && defined(SYNERGY_AUTOCONFIG) - updateZeroconfService(); + updateZeroconfService(); - addZeroconfServer(m_AppConfig->autoConfigServer()); + addZeroconfServer(m_AppConfig->autoConfigServer()); - updateAutoConfigWidgets(); + updateAutoConfigWidgets(); #endif } -void MainWindow::setIcon(qSynergyState state) const -{ - QIcon icon; +void MainWindow::setIcon(qSynergyState state) const { + QIcon icon; #ifdef Q_OS_MAC - switch(getOSXIconsTheme()) { - case IconsTheme::ICONS_DARK: - icon.addFile(synergyDarkIconFiles[state]); - break; - case IconsTheme::ICONS_LIGHT: - icon.addFile(synergyLightIconFiles[state]); - break; - case IconsTheme::ICONS_TEMPLATE: - default: - icon.addFile(synergyDarkIconFiles[state]); - icon.setIsMask(true); - break; - } + switch (getOSXIconsTheme()) { + case IconsTheme::ICONS_DARK: + icon.addFile(synergyDarkIconFiles[state]); + break; + case IconsTheme::ICONS_LIGHT: + icon.addFile(synergyLightIconFiles[state]); + break; + case IconsTheme::ICONS_TEMPLATE: + default: + icon.addFile(synergyDarkIconFiles[state]); + icon.setIsMask(true); + break; + } #else - icon.addFile(synergyDefaultIconFiles[state]); + icon.addFile(synergyDefaultIconFiles[state]); #endif - m_trayIcon.set(icon); + m_trayIcon.set(icon); } -void MainWindow::trayActivated(QSystemTrayIcon::ActivationReason reason) -{ - if (reason == QSystemTrayIcon::DoubleClick) - { - if (isVisible()) - { - hide(); - } - else - { - showNormal(); - activateWindow(); - } +void MainWindow::trayActivated(QSystemTrayIcon::ActivationReason reason) { + if (reason == QSystemTrayIcon::DoubleClick) { + if (isVisible()) { + hide(); + } else { + showNormal(); + activateWindow(); } + } } -void MainWindow::logOutput() -{ - if (m_pSynergy) - { - QString text(m_pSynergy->readAllStandardOutput()); - foreach(QString line, text.split(QRegExp("\r|\n|\r\n"))) - { - if (!line.isEmpty()) - { - appendLogRaw(line); - } - } +void MainWindow::logOutput() { + if (m_pSynergy) { + QString text(m_pSynergy->readAllStandardOutput()); + foreach (QString line, text.split(QRegExp("\r|\n|\r\n"))) { + if (!line.isEmpty()) { + appendLogRaw(line); + } } + } } -void MainWindow::logError() -{ - if (m_pSynergy) - { - appendLogRaw(m_pSynergy->readAllStandardError()); +void MainWindow::logError() { + if (m_pSynergy) { + appendLogRaw(m_pSynergy->readAllStandardError()); + } +} + +void MainWindow::updateFound(const QString &version) { + m_pWidgetUpdate->show(); + m_pLabelUpdate->setText(tr("

Your version of Synergy is out of date. " + "Version %1 is now available to " + "download.

") + .arg(version) + .arg(DOWNLOAD_URL)); +} + +void MainWindow::appendLogInfo(const QString &text) { + appendLogRaw(getTimeStamp() + " INFO: " + text); +} + +void MainWindow::appendLogDebug(const QString &text) { + if (appConfig().logLevel() >= debugLogLevel) { + appendLogRaw(getTimeStamp() + " DEBUG: " + text); + } +} + +void MainWindow::appendLogError(const QString &text) { + appendLogRaw(getTimeStamp() + " ERROR: " + text); +} + +void MainWindow::appendLogRaw(const QString &text) { + foreach (QString line, text.split(QRegExp("\r|\n|\r\n"))) { + if (!line.isEmpty()) { + + // HACK: macOS 10.13.4+ spamming error lines in logs making them + // impossible to read and debug; giving users a red herring. + if (line.contains("calling TIS/TSM in non-main thread environment")) { + continue; + } + + m_pLogOutput->appendPlainText(line); + updateFromLogLine(line); } + } } -void MainWindow::updateFound(const QString &version) -{ - m_pWidgetUpdate->show(); - m_pLabelUpdate->setText( - tr("

Your version of Synergy is out of date. " - "Version %1 is now available to " - "download.

") - .arg(version).arg(DOWNLOAD_URL)); -} - -void MainWindow::appendLogInfo(const QString& text) -{ - appendLogRaw(getTimeStamp() + " INFO: " + text); -} - -void MainWindow::appendLogDebug(const QString& text) { - if (appConfig().logLevel() >= debugLogLevel) { - appendLogRaw(getTimeStamp() + " DEBUG: " + text); +void MainWindow::handleIdleService(const QString &text) { + foreach (QString line, text.split(QRegExp("\r|\n|\r\n"))) { + // only start if there is no active service running + if (!line.isEmpty() && line.contains("service status: idle") && + appConfig().startedBefore()) { + startSynergy(); } + } } -void MainWindow::appendLogError(const QString& text) -{ - appendLogRaw(getTimeStamp() + " ERROR: " + text); -} +void MainWindow::updateFromLogLine(const QString &line) { + // TODO: This shouldn't be updating from log needs a better way of doing this + checkConnected(line); + checkFingerprint(line); + checkSecureSocket(line); -void MainWindow::appendLogRaw(const QString& text) -{ - foreach(QString line, text.split(QRegExp("\r|\n|\r\n"))) { - if (!line.isEmpty()) { - - // HACK: macOS 10.13.4+ spamming error lines in logs making them - // impossible to read and debug; giving users a red herring. - if (line.contains("calling TIS/TSM in non-main thread environment")) { - continue; - } - - m_pLogOutput->appendPlainText(line); - updateFromLogLine(line); - } - } -} - -void MainWindow::handleIdleService(const QString& text) -{ - foreach(QString line, text.split(QRegExp("\r|\n|\r\n"))) { - // only start if there is no active service running - if (!line.isEmpty() && line.contains("service status: idle") && appConfig().startedBefore()) { - startSynergy(); - } - } -} - -void MainWindow::updateFromLogLine(const QString &line) -{ - // TODO: This shouldn't be updating from log needs a better way of doing this - checkConnected(line); - checkFingerprint(line); - checkSecureSocket(line); - - // subprocess (synergys, synergyc) is not allowed to show notifications - // process the log from it and show notificatino from synergy instead + // subprocess (synergys, synergyc) is not allowed to show notifications + // process the log from it and show notificatino from synergy instead #ifdef Q_OS_MAC - checkOSXNotification(line); + checkOSXNotification(line); #endif #ifndef SYNERGY_ENTERPRISE - checkLicense(line); + checkLicense(line); #endif } -void MainWindow::checkConnected(const QString& line) -{ - // TODO: implement ipc connection state messages to replace this hack. - if (m_pRadioGroupServer->isChecked()) - { - m_serverConnection.update(line); - m_pLabelServerState->updateServerState(line); +void MainWindow::checkConnected(const QString &line) { + // TODO: implement ipc connection state messages to replace this hack. + if (m_pRadioGroupServer->isChecked()) { + m_serverConnection.update(line); + m_pLabelServerState->updateServerState(line); + } else { + m_clientConnection.update(line); + m_pLabelClientState->updateClientState(line); + } + + if (line.contains("connected to server") || line.contains("has connected")) { + setSynergyState(synergyConnected); + + if (!appConfig().startedBefore() && isVisible()) { + QMessageBox::information( + this, "Synergy", + tr("Synergy is now connected. You can close the " + "config window and Synergy will remain connected in " + "the background.")); + + appConfig().setStartedBefore(true); } - else - { - m_clientConnection.update(line); - m_pLabelClientState->updateClientState(line); - } - - if (line.contains("connected to server") || line.contains("has connected")) - { - setSynergyState(synergyConnected); - - if (!appConfig().startedBefore() && isVisible()) { - QMessageBox::information( - this, "Synergy", - tr("Synergy is now connected. You can close the " - "config window and Synergy will remain connected in " - "the background.")); - - appConfig().setStartedBefore(true); - } - } - else if (line.contains("started server")) - { - setSynergyState(synergyListening); - } - else if (line.contains("disconnected from server") || line.contains("process exited")) - { - setSynergyState(synergyDisconnected); - } - else if (line.contains("connecting to")) - { - setSynergyState(synergyConnecting); - } -} - -#ifndef SYNERGY_ENTERPRISE -void MainWindow::checkLicense(const QString &line) -{ - if (line.contains("trial has expired")) { - licenseManager().refresh(); - raiseActivationDialog(); - } -} -#endif - -void MainWindow::checkFingerprint(const QString& line) -{ - QRegExp fingerprintRegex(".*server fingerprint: ([A-F0-9:]+)"); - if (!fingerprintRegex.exactMatch(line)) { - return; - } - - QString fingerprint = fingerprintRegex.cap(1); - if (Fingerprint::trustedServers().isTrusted(fingerprint)) { - return; - } - - static bool messageBoxAlreadyShown = false; - - if (!messageBoxAlreadyShown) { - stopSynergy(); - - messageBoxAlreadyShown = true; - QMessageBox::StandardButton fingerprintReply = - QMessageBox::information( - this, tr("Security question"), - tr("You are connecting to a server. Here is it's fingerprint:\n\n" - "%1\n\n" - "Compare this fingerprint to the one on your server's screen." - "If the two don't match exactly, then it's probably not the server " - "you're expecting (it could be a malicious user).\n\n" - "To automatically trust this fingerprint for future " - "connections, click Yes. To reject this fingerprint and " - "disconnect from the server, click No.") - .arg(fingerprint), - QMessageBox::Yes | QMessageBox::No); - - if (fingerprintReply == QMessageBox::Yes) { - // restart core process after trusting fingerprint. - Fingerprint::trustedServers().trust(fingerprint); - startSynergy(); - } - - messageBoxAlreadyShown = false; - } -} - -void MainWindow::checkSecureSocket(const QString& line) -{ - // obviously not very secure, since this can be tricked by injecting something - // into the log. however, since we don't have IPC between core and GUI... patches welcome. - const int index = line.indexOf(tlsCheckString, 0, Qt::CaseInsensitive); - if (index > 0) { - secureSocket(true); - - //Get the protocol version from the line - m_SecureSocketVersion = line.mid(index + strlen(tlsCheckString)); // Compliant: we made sure that tlsCheckString variable ended with null(static const char* declaration) - } -} - -#ifdef Q_OS_MAC -void MainWindow::checkOSXNotification(const QString& line) -{ - static const QString OSXNotificationSubstring = "OSX Notification: "; - if (line.contains(OSXNotificationSubstring) && line.contains('|')) { - int delimterPosition = line.indexOf('|'); - int notificationStartPosition = line.indexOf(OSXNotificationSubstring); - QString title = - line.mid(notificationStartPosition + OSXNotificationSubstring.length(), - delimterPosition - notificationStartPosition - OSXNotificationSubstring.length()); - QString body = - line.mid(delimterPosition + 1, - line.length() - delimterPosition); - if (!showOSXNotification(title, body)) { - appendLogInfo("OSX notification was not shown"); - } - } -} -#endif - -QString MainWindow::getTimeStamp() -{ - QDateTime current = QDateTime::currentDateTime(); - return '[' + current.toString(Qt::ISODate) + ']'; -} - -void MainWindow::restartSynergy() -{ - stopSynergy(); - startSynergy(); -} - -void MainWindow::proofreadInfo() -{ - int oldState = m_SynergyState; - m_SynergyState = synergyDisconnected; - setSynergyState((qSynergyState)oldState); -} - -void MainWindow::showEvent(QShowEvent* event) -{ - QMainWindow::showEvent(event); - emit windowShown(); -} - -void MainWindow::clearLog() -{ - m_pLogOutput->clear(); -} - -void MainWindow::startSynergy() -{ - saveSettings(); - -#ifdef Q_OS_MAC - requestOSXNotificationPermission(); -#endif - -#ifndef SYNERGY_ENTERPRISE - SerialKey serialKey = m_LicenseManager->serialKey(); - if (!serialKey.isValid()) { - if (QDialog::Rejected == raiseActivationDialog()) { - return; - } - } - m_LicenseManager->registerLicense(); -#endif - bool desktopMode = appConfig().processMode() == Desktop; - bool serviceMode = appConfig().processMode() == Service; - - appendLogDebug("starting process"); - m_ExpectedRunningState = kStarted; + } else if (line.contains("started server")) { + setSynergyState(synergyListening); + } else if (line.contains("disconnected from server") || + line.contains("process exited")) { + setSynergyState(synergyDisconnected); + } else if (line.contains("connecting to")) { setSynergyState(synergyConnecting); + } +} - QString app; - QStringList args; +#ifndef SYNERGY_ENTERPRISE +void MainWindow::checkLicense(const QString &line) { + if (line.contains("trial has expired")) { + licenseManager().refresh(); + raiseActivationDialog(); + } +} +#endif - args << "-f" << "--no-tray" << "--debug" << appConfig().logLevelText(); +void MainWindow::checkFingerprint(const QString &line) { + QRegExp fingerprintRegex(".*server fingerprint: ([A-F0-9:]+)"); + if (!fingerprintRegex.exactMatch(line)) { + return; + } + QString fingerprint = fingerprintRegex.cap(1); + if (Fingerprint::trustedServers().isTrusted(fingerprint)) { + return; + } - args << "--name" << appConfig().screenName(); + static bool messageBoxAlreadyShown = false; - if (desktopMode) - { - setSynergyProcess(new QProcess(this)); + if (!messageBoxAlreadyShown) { + stopSynergy(); + + messageBoxAlreadyShown = true; + QMessageBox::StandardButton fingerprintReply = QMessageBox::information( + this, tr("Security question"), + tr("You are connecting to a server. Here is it's fingerprint:\n\n" + "%1\n\n" + "Compare this fingerprint to the one on your server's screen." + "If the two don't match exactly, then it's probably not the server " + "you're expecting (it could be a malicious user).\n\n" + "To automatically trust this fingerprint for future " + "connections, click Yes. To reject this fingerprint and " + "disconnect from the server, click No.") + .arg(fingerprint), + QMessageBox::Yes | QMessageBox::No); + + if (fingerprintReply == QMessageBox::Yes) { + // restart core process after trusting fingerprint. + Fingerprint::trustedServers().trust(fingerprint); + startSynergy(); } - else - { - // tell client/server to talk to daemon through ipc. - args << "--ipc"; + + messageBoxAlreadyShown = false; + } +} + +void MainWindow::checkSecureSocket(const QString &line) { + // obviously not very secure, since this can be tricked by injecting something + // into the log. however, since we don't have IPC between core and GUI... + // patches welcome. + const int index = line.indexOf(tlsCheckString, 0, Qt::CaseInsensitive); + if (index > 0) { + secureSocket(true); + + // Get the protocol version from the line + m_SecureSocketVersion = line.mid( + index + strlen(tlsCheckString)); // Compliant: we made sure that + // tlsCheckString variable ended with + // null(static const char* declaration) + } +} + +#ifdef Q_OS_MAC +void MainWindow::checkOSXNotification(const QString &line) { + static const QString OSXNotificationSubstring = "OSX Notification: "; + if (line.contains(OSXNotificationSubstring) && line.contains('|')) { + int delimterPosition = line.indexOf('|'); + int notificationStartPosition = line.indexOf(OSXNotificationSubstring); + QString title = + line.mid(notificationStartPosition + OSXNotificationSubstring.length(), + delimterPosition - notificationStartPosition - + OSXNotificationSubstring.length()); + QString body = + line.mid(delimterPosition + 1, line.length() - delimterPosition); + if (!showOSXNotification(title, body)) { + appendLogInfo("OSX notification was not shown"); + } + } +} +#endif + +QString MainWindow::getTimeStamp() { + QDateTime current = QDateTime::currentDateTime(); + return '[' + current.toString(Qt::ISODate) + ']'; +} + +void MainWindow::restartSynergy() { + stopSynergy(); + startSynergy(); +} + +void MainWindow::proofreadInfo() { + int oldState = m_SynergyState; + m_SynergyState = synergyDisconnected; + setSynergyState((qSynergyState)oldState); +} + +void MainWindow::showEvent(QShowEvent *event) { + QMainWindow::showEvent(event); + emit windowShown(); +} + +void MainWindow::clearLog() { m_pLogOutput->clear(); } + +void MainWindow::startSynergy() { + saveSettings(); + +#ifdef Q_OS_MAC + requestOSXNotificationPermission(); +#endif + +#ifndef SYNERGY_ENTERPRISE + SerialKey serialKey = m_LicenseManager->serialKey(); + if (!serialKey.isValid()) { + if (QDialog::Rejected == raiseActivationDialog()) { + return; + } + } + m_LicenseManager->registerLicense(); +#endif + bool desktopMode = appConfig().processMode() == Desktop; + bool serviceMode = appConfig().processMode() == Service; + + appendLogDebug("starting process"); + m_ExpectedRunningState = kStarted; + setSynergyState(synergyConnecting); + + QString app; + QStringList args; + + args << "-f" + << "--no-tray" + << "--debug" << appConfig().logLevelText(); + + args << "--name" << appConfig().screenName(); + + if (desktopMode) { + setSynergyProcess(new QProcess(this)); + } else { + // tell client/server to talk to daemon through ipc. + args << "--ipc"; #if defined(Q_OS_WIN) - // tell the client/server to shut down when a ms windows desk - // is switched; this is because we may need to elevate or not - // based on which desk the user is in (login always needs - // elevation, where as default desk does not). - // Note that this is only enabled when synergy is set to elevate - // 'as needed' (e.g. on a UAC dialog popup) in order to prevent - // unnecessary restarts when synergy was started elevated or - // when it is not allowed to elevate. In these cases restarting - // the server is fruitless. - if (appConfig().elevateMode() == ElevateAsNeeded) { - args << "--stop-on-desk-switch"; - } -#endif + // tell the client/server to shut down when a ms windows desk + // is switched; this is because we may need to elevate or not + // based on which desk the user is in (login always needs + // elevation, where as default desk does not). + // Note that this is only enabled when synergy is set to elevate + // 'as needed' (e.g. on a UAC dialog popup) in order to prevent + // unnecessary restarts when synergy was started elevated or + // when it is not allowed to elevate. In these cases restarting + // the server is fruitless. + if (appConfig().elevateMode() == ElevateAsNeeded) { + args << "--stop-on-desk-switch"; } +#endif + } #ifndef Q_OS_LINUX - if (m_ServerConfig.enableDragAndDrop()) { - args << "--enable-drag-drop"; - } + if (m_ServerConfig.enableDragAndDrop()) { + args << "--enable-drag-drop"; + } #endif #if defined(Q_OS_WIN) - if (m_AppConfig->getCryptoEnabled()) { - args << "--enable-crypto"; - args << "--tls-cert" << QString("\"%1\"").arg(m_AppConfig->getTLSCertPath()); - } - // on windows, the profile directory changes depending on the user that - // launched the process (e.g. when launched with elevation). setting the - // profile dir on launch ensures it uses the same profile dir is used - // no matter how its relaunched. - args << "--profile-dir" << getProfileRootForArg(); + if (m_AppConfig->getCryptoEnabled()) { + args << "--enable-crypto"; + args << "--tls-cert" + << QString("\"%1\"").arg(m_AppConfig->getTLSCertPath()); + } + // on windows, the profile directory changes depending on the user that + // launched the process (e.g. when launched with elevation). setting the + // profile dir on launch ensures it uses the same profile dir is used + // no matter how its relaunched. + args << "--profile-dir" << getProfileRootForArg(); #else - if (m_AppConfig->getCryptoEnabled()) { - args << "--enable-crypto"; - args << "--tls-cert" << m_AppConfig->getTLSCertPath(); - } + if (m_AppConfig->getCryptoEnabled()) { + args << "--enable-crypto"; + args << "--tls-cert" << m_AppConfig->getTLSCertPath(); + } #endif - if (m_AppConfig->getPreventSleep()) - { - args << "--prevent-sleep"; + if (m_AppConfig->getPreventSleep()) { + args << "--prevent-sleep"; + } + + // put a space between last log output and new instance. + if (!m_pLogOutput->toPlainText().isEmpty()) + appendLogRaw(""); + + appendLogInfo("starting " + + QString(synergyType() == synergyServer ? "server" : "client")); + + if ((synergyType() == synergyClient && !clientArgs(args, app)) || + (synergyType() == synergyServer && !serverArgs(args, app))) { + stopSynergy(); + return; + } + + if (desktopMode) { + connect(synergyProcess(), SIGNAL(finished(int, QProcess::ExitStatus)), this, + SLOT(synergyFinished(int, QProcess::ExitStatus))); + connect(synergyProcess(), SIGNAL(readyReadStandardOutput()), this, + SLOT(logOutput())); + connect(synergyProcess(), SIGNAL(readyReadStandardError()), this, + SLOT(logError())); + } + + qDebug() << args; + + // show command if debug log level... + if (appConfig().logLevel() >= 4) { + appendLogInfo(QString("command: %1 %2").arg(app, args.join(" "))); + } + + appendLogInfo("log level: " + appConfig().logLevelText()); + + if (appConfig().logToFile()) + appendLogInfo("log file: " + appConfig().logFilename()); + + if (desktopMode) { + synergyProcess()->start(app, args); + if (!synergyProcess()->waitForStarted()) { + show(); + QMessageBox::warning( + this, tr("Program can not be started"), + QString( + tr("The executable

%1

could not be successfully " + "started, although it does exist. Please check if you have " + "sufficient permissions to run this program.") + .arg(app))); + return; } + } - // put a space between last log output and new instance. - if (!m_pLogOutput->toPlainText().isEmpty()) - appendLogRaw(""); - - appendLogInfo("starting " + QString(synergyType() == synergyServer ? "server" : "client")); - - if ((synergyType() == synergyClient && !clientArgs(args, app)) - || (synergyType() == synergyServer && !serverArgs(args, app))) - { - stopSynergy(); - return; - } - - if (desktopMode) - { - connect(synergyProcess(), SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(synergyFinished(int, QProcess::ExitStatus))); - connect(synergyProcess(), SIGNAL(readyReadStandardOutput()), this, SLOT(logOutput())); - connect(synergyProcess(), SIGNAL(readyReadStandardError()), this, SLOT(logError())); - } - - qDebug() << args; - - // show command if debug log level... - if (appConfig().logLevel() >= 4) { - appendLogInfo(QString("command: %1 %2").arg(app, args.join(" "))); - } - - appendLogInfo("log level: " + appConfig().logLevelText()); - - if (appConfig().logToFile()) - appendLogInfo("log file: " + appConfig().logFilename()); - - if (desktopMode) - { - synergyProcess()->start(app, args); - if (!synergyProcess()->waitForStarted()) - { - show(); - QMessageBox::warning(this, tr("Program can not be started"), QString(tr("The executable

%1

could not be successfully started, although it does exist. Please check if you have sufficient permissions to run this program.").arg(app))); - return; - } - } - - if (serviceMode) - { - QString command(app + " " + args.join(" ")); - m_IpcClient.sendCommand(command, appConfig().elevateMode()); - } + if (serviceMode) { + QString command(app + " " + args.join(" ")); + m_IpcClient.sendCommand(command, appConfig().elevateMode()); + } } -void MainWindow::actionStart() -{ - m_clientConnection.setCheckConnection(true); +void MainWindow::actionStart() { + m_clientConnection.setCheckConnection(true); + startSynergy(); +} + +void MainWindow::retryStart() { + // This function is only called after a failed start + // Only start synergy if the current state is pending retry + if (m_SynergyState == synergyPendingRetry) { startSynergy(); + } } -void MainWindow::retryStart() -{ - //This function is only called after a failed start - //Only start synergy if the current state is pending retry - if (m_SynergyState == synergyPendingRetry) - { - startSynergy(); - } -} +bool MainWindow::clientArgs(QStringList &args, QString &app) { + app = appPath(appConfig().synergycName()); -bool MainWindow::clientArgs(QStringList& args, QString& app) -{ - app = appPath(appConfig().synergycName()); - - if (!QFile::exists(app)) - { - show(); - QMessageBox::warning(this, tr("Synergy client not found"), - tr("The executable for the synergy client does not exist.")); - return false; - } + if (!QFile::exists(app)) { + show(); + QMessageBox::warning( + this, tr("Synergy client not found"), + tr("The executable for the synergy client does not exist.")); + return false; + } #if defined(Q_OS_WIN) - // wrap in quotes so a malicious user can't start \Program.exe as admin. - app = QString("\"%1\"").arg(app); + // wrap in quotes so a malicious user can't start \Program.exe as admin. + app = QString("\"%1\"").arg(app); #endif - if (appConfig().logToFile()) - { - appConfig().persistLogDir(); - args << "--log" << appConfig().logFilenameCmd(); - } + if (appConfig().logToFile()) { + appConfig().persistLogDir(); + args << "--log" << appConfig().logFilenameCmd(); + } - if (appConfig().getLanguageSync()) { - args << "--sync-language"; - } + if (appConfig().getLanguageSync()) { + args << "--sync-language"; + } - if (appConfig().getInvertScrollDirection()) { - args <<"--invert-scroll"; - } + if (appConfig().getInvertScrollDirection()) { + args << "--invert-scroll"; + } #if !defined(SYNERGY_ENTERPRISE) && defined(SYNERGY_AUTOCONFIG) - // check auto config first, if it is disabled or no server detected, - // use line edit host name if it is not empty - if (appConfig().autoConfig()) { - if (m_pComboServerList->count() != 0) { - QString serverIp = m_pComboServerList->currentText(); - args << serverIp + ":" + QString::number(appConfig().port()); - return true; - } - else { - show(); - QMessageBox::warning( - this, tr("No server selected"), - tr("No auto config server was selected, try manual mode instead.")); - return false; - } + // check auto config first, if it is disabled or no server detected, + // use line edit host name if it is not empty + if (appConfig().autoConfig()) { + if (m_pComboServerList->count() != 0) { + QString serverIp = m_pComboServerList->currentText(); + args << serverIp + ":" + QString::number(appConfig().port()); + return true; + } else { + show(); + QMessageBox::warning( + this, tr("No server selected"), + tr("No auto config server was selected, try manual mode instead.")); + return false; } + } #endif - if (m_pLineEditHostname->text().isEmpty() && !appConfig().getClientHostMode()) - { + if (m_pLineEditHostname->text().isEmpty() && + !appConfig().getClientHostMode()) { #if !defined(SYNERGY_ENTERPRISE) && defined(SYNERGY_AUTOCONFIG) - //check if autoconfig mode is enabled - if (!appConfig().autoConfig()) - { + // check if autoconfig mode is enabled + if (!appConfig().autoConfig()) { #endif - show(); - QMessageBox::warning( - this, tr("Hostname is empty"), - tr("Please fill in a hostname for the synergy client to connect to.")); - return false; + show(); + QMessageBox::warning(this, tr("Hostname is empty"), + tr("Please fill in a hostname for the synergy " + "client to connect to.")); + return false; #if !defined(SYNERGY_ENTERPRISE) && defined(SYNERGY_AUTOCONFIG) - } - else - { - return false; - } + } else { + return false; + } #endif - } + } - if (appConfig().getClientHostMode()) { - args <<"--host"; - args <<":" + QString::number(appConfig().port()); - } - else { - QString hostName = m_pLineEditHostname->text(); - // if interface is IPv6 - ensure that ip is in square brackets - if (hostName.count(':') > 1) { - if(hostName[0] != '[') { - hostName.insert(0, '['); - } - if(hostName[hostName.size() - 1] != ']') { - hostName.push_back(']'); - } - } - args << hostName + ":" + QString::number(appConfig().port()); - } - - return true; -} - -QString MainWindow::configFilename() -{ - QString configFullPath; - if (appConfig().getUseExternalConfig()) - { - configFullPath = appConfig().getConfigFile(); - } - else - { - QStringList errors; - for (auto path : {QStandardPaths::AppDataLocation, - QStandardPaths::AppConfigLocation}) - { - auto configDirPath = QStandardPaths::writableLocation(path); - if (!QDir().mkpath(configDirPath)) - { - errors.push_back(tr("Failed to create config folder \"%1\"").arg(configDirPath)); - continue; - } - - QFile configFile(configDirPath + "/LastConfig.cfg"); - if (!configFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) - { - errors.push_back(tr("File:\"%1\" Error:%2").arg(configFile.fileName(), configFile.errorString())); - continue; - } - - serverConfig().save(configFile); - configFile.close(); - configFullPath = configFile.fileName(); - - break; - } - - if (configFullPath.isEmpty()) - { - QMessageBox::critical(this, tr("Cannot write configuration file"), errors.join('\n')); - } - } - - return configFullPath; -} - -QString MainWindow::address() const -{ - QString i = appConfig().networkInterface(); + if (appConfig().getClientHostMode()) { + args << "--host"; + args << ":" + QString::number(appConfig().port()); + } else { + QString hostName = m_pLineEditHostname->text(); // if interface is IPv6 - ensure that ip is in square brackets - if (i.count(':') > 1) { - if(i[0] != '[') { - i.insert(0, '['); - } - if(i[i.size() - 1] != ']') { - i.push_back(']'); - } + if (hostName.count(':') > 1) { + if (hostName[0] != '[') { + hostName.insert(0, '['); + } + if (hostName[hostName.size() - 1] != ']') { + hostName.push_back(']'); + } } - return (!i.isEmpty() ? i : "") + ":" + QString::number(appConfig().port()); + args << hostName + ":" + QString::number(appConfig().port()); + } + + return true; } -QString MainWindow::appPath(const QString& name) -{ - return appConfig().synergyProgramDir() + name; +QString MainWindow::configFilename() { + QString configFullPath; + if (appConfig().getUseExternalConfig()) { + configFullPath = appConfig().getConfigFile(); + } else { + QStringList errors; + for (auto path : + {QStandardPaths::AppDataLocation, QStandardPaths::AppConfigLocation}) { + auto configDirPath = QStandardPaths::writableLocation(path); + if (!QDir().mkpath(configDirPath)) { + errors.push_back( + tr("Failed to create config folder \"%1\"").arg(configDirPath)); + continue; + } + + QFile configFile(configDirPath + "/LastConfig.cfg"); + if (!configFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) { + errors.push_back( + tr("File:\"%1\" Error:%2") + .arg(configFile.fileName(), configFile.errorString())); + continue; + } + + serverConfig().save(configFile); + configFile.close(); + configFullPath = configFile.fileName(); + + break; + } + + if (configFullPath.isEmpty()) { + QMessageBox::critical(this, tr("Cannot write configuration file"), + errors.join('\n')); + } + } + + return configFullPath; } -bool MainWindow::serverArgs(QStringList& args, QString& app) -{ - app = appPath(appConfig().synergysName()); - - if (!QFile::exists(app)) - { - QMessageBox::warning(this, tr("Synergy server not found"), - tr("The executable for the synergy server does not exist.")); - return false; +QString MainWindow::address() const { + QString i = appConfig().networkInterface(); + // if interface is IPv6 - ensure that ip is in square brackets + if (i.count(':') > 1) { + if (i[0] != '[') { + i.insert(0, '['); } - - if (appConfig().getServerClientMode() && - m_pLineEditClienIp->text().isEmpty()) - { - QMessageBox::warning(this, tr("Client IP address or name is empty"), - tr("Please fill in a client IP address or name.")); - return false; + if (i[i.size() - 1] != ']') { + i.push_back(']'); } + } + return (!i.isEmpty() ? i : "") + ":" + QString::number(appConfig().port()); +} + +QString MainWindow::appPath(const QString &name) { + return appConfig().synergyProgramDir() + name; +} + +bool MainWindow::serverArgs(QStringList &args, QString &app) { + app = appPath(appConfig().synergysName()); + + if (!QFile::exists(app)) { + QMessageBox::warning( + this, tr("Synergy server not found"), + tr("The executable for the synergy server does not exist.")); + return false; + } + + if (appConfig().getServerClientMode() && + m_pLineEditClienIp->text().isEmpty()) { + QMessageBox::warning(this, tr("Client IP address or name is empty"), + tr("Please fill in a client IP address or name.")); + return false; + } #if defined(Q_OS_WIN) - // wrap in quotes so a malicious user can't start \Program.exe as admin. - app = QString("\"%1\"").arg(app); + // wrap in quotes so a malicious user can't start \Program.exe as admin. + app = QString("\"%1\"").arg(app); #endif - if (appConfig().logToFile()) - { - appConfig().persistLogDir(); + if (appConfig().logToFile()) { + appConfig().persistLogDir(); - args << "--log" << appConfig().logFilenameCmd(); - } + args << "--log" << appConfig().logFilenameCmd(); + } - QString configFilename = this->configFilename(); - if (configFilename.isEmpty()) - { - return false; - } + QString configFilename = this->configFilename(); + if (configFilename.isEmpty()) { + return false; + } #if defined(Q_OS_WIN) - // wrap in quotes in case username contains spaces. - configFilename = QString("\"%1\"").arg(configFilename); + // wrap in quotes in case username contains spaces. + configFilename = QString("\"%1\"").arg(configFilename); #endif - args << "-c" << configFilename << "--address" << address(); - appendLogInfo("config file: " + configFilename); + args << "-c" << configFilename << "--address" << address(); + appendLogInfo("config file: " + configFilename); #ifndef SYNERGY_ENTERPRISE - if (!appConfig().serialKey().isEmpty()) { - args << "--serial-key" << appConfig().serialKey(); - } + if (!appConfig().serialKey().isEmpty()) { + args << "--serial-key" << appConfig().serialKey(); + } #endif - return true; + return true; } -void MainWindow::stopSynergy() -{ - appendLogDebug("stopping process"); +void MainWindow::stopSynergy() { + appendLogDebug("stopping process"); - m_ExpectedRunningState = kStopped; + m_ExpectedRunningState = kStopped; - if (appConfig().processMode() == Service) - { - stopService(); - } - else if (appConfig().processMode() == Desktop) - { - stopDesktop(); - } + if (appConfig().processMode() == Service) { + stopService(); + } else if (appConfig().processMode() == Desktop) { + stopDesktop(); + } + setSynergyState(synergyDisconnected); + + // reset so that new connects cause auto-hide. + m_AlreadyHidden = false; +} + +void MainWindow::stopService() { + // send empty command to stop service from laucning anything. + m_IpcClient.sendCommand("", appConfig().elevateMode()); +} + +void MainWindow::stopDesktop() { + QMutexLocker locker(&m_StopDesktopMutex); + if (!synergyProcess()) { + return; + } + + appendLogInfo("stopping synergy desktop process"); + + if (synergyProcess()->isOpen()) { + synergyProcess()->close(); + } + + delete synergyProcess(); + setSynergyProcess(NULL); +} + +void MainWindow::synergyFinished(int exitCode, QProcess::ExitStatus) { + if (exitCode == 0) { + appendLogInfo(QString("process exited normally")); + } else { + appendLogError(QString("process exited with error code: %1").arg(exitCode)); + } + + if (m_ExpectedRunningState == kStarted) { + + setSynergyState(synergyPendingRetry); + QTimer::singleShot(1000, this, SLOT(retryStart())); + appendLogInfo(QString("detected process not running, auto restarting")); + } else { setSynergyState(synergyDisconnected); - - // reset so that new connects cause auto-hide. - m_AlreadyHidden = false; + } } -void MainWindow::stopService() -{ - // send empty command to stop service from laucning anything. - m_IpcClient.sendCommand("", appConfig().elevateMode()); +void MainWindow::setSynergyState(qSynergyState state) { + // always assume connection is not secure when connection changes + // to anything except connected. the only way the padlock shows is + // when the correct TLS version string is detected. + if (state != synergyConnected) { + secureSocket(false); + } + + if (synergyState() == state) + return; + + if ((state == synergyConnected) || (state == synergyConnecting) || + (state == synergyListening) || (state == synergyPendingRetry)) { + disconnect(m_pButtonToggleStart, SIGNAL(clicked()), m_pActionStartSynergy, + SLOT(trigger())); + connect(m_pButtonToggleStart, SIGNAL(clicked()), m_pActionStopSynergy, + SLOT(trigger())); + m_pButtonToggleStart->setText(tr("&Stop")); + m_pButtonApply->setEnabled(true); + } else if (state == synergyDisconnected) { + disconnect(m_pButtonToggleStart, SIGNAL(clicked()), m_pActionStopSynergy, + SLOT(trigger())); + connect(m_pButtonToggleStart, SIGNAL(clicked()), m_pActionStartSynergy, + SLOT(trigger())); + m_pButtonToggleStart->setText(tr("&Start")); + m_pButtonApply->setEnabled(false); + } + + bool running = false; + if (state == synergyConnected || state == synergyListening) { + running = true; + } + + m_pActionStartSynergy->setEnabled(!running); + m_pActionStopSynergy->setEnabled(running); + + switch (state) { + case synergyListening: { + if (synergyType() == synergyServer) { + setStatus( + tr("Synergy is waiting for clients").arg(m_SecureSocketVersion)); + } + + break; + } + case synergyConnected: { + if (m_SecureSocket) { + setStatus( + tr("Synergy is connected (with %1)").arg(m_SecureSocketVersion)); + } else { + setStatus(tr("Synergy is running (without TLS encryption)") + .arg(m_SecureSocketVersion)); + } + break; + } + case synergyConnecting: + setStatus(tr("Synergy is starting...")); + break; + case synergyPendingRetry: + setStatus(tr("There was an error, retrying...")); + break; + case synergyDisconnected: + setStatus(tr("Synergy is not running")); + break; + } + + setIcon(state); + + m_SynergyState = state; } -void MainWindow::stopDesktop() -{ - QMutexLocker locker(&m_StopDesktopMutex); - if (!synergyProcess()) { - return; - } - - appendLogInfo("stopping synergy desktop process"); - - if (synergyProcess()->isOpen()) { - synergyProcess()->close(); - } - - delete synergyProcess(); - setSynergyProcess(NULL); -} - -void MainWindow::synergyFinished(int exitCode, QProcess::ExitStatus) -{ - if (exitCode == 0) { - appendLogInfo(QString("process exited normally")); - } - else { - appendLogError(QString("process exited with error code: %1").arg(exitCode)); - } - - if (m_ExpectedRunningState == kStarted) { - - setSynergyState(synergyPendingRetry); - QTimer::singleShot(1000, this, SLOT(retryStart())); - appendLogInfo(QString("detected process not running, auto restarting")); - } - else { - setSynergyState(synergyDisconnected); - } -} - -void MainWindow::setSynergyState(qSynergyState state) -{ - // always assume connection is not secure when connection changes - // to anything except connected. the only way the padlock shows is - // when the correct TLS version string is detected. - if (state != synergyConnected) { - secureSocket(false); - } - - if (synergyState() == state) - return; - - if ((state == synergyConnected) || (state == synergyConnecting) || (state == synergyListening) || (state == synergyPendingRetry)) - { - disconnect (m_pButtonToggleStart, SIGNAL(clicked()), m_pActionStartSynergy, SLOT(trigger())); - connect (m_pButtonToggleStart, SIGNAL(clicked()), m_pActionStopSynergy, SLOT(trigger())); - m_pButtonToggleStart->setText(tr("&Stop")); - m_pButtonApply->setEnabled(true); - } - else if (state == synergyDisconnected) - { - disconnect (m_pButtonToggleStart, SIGNAL(clicked()), m_pActionStopSynergy, SLOT(trigger())); - connect (m_pButtonToggleStart, SIGNAL(clicked()), m_pActionStartSynergy, SLOT(trigger())); - m_pButtonToggleStart->setText(tr("&Start")); - m_pButtonApply->setEnabled(false); - } - - bool running = false; - if (state == synergyConnected || state == synergyListening) { - running = true; - } - - m_pActionStartSynergy->setEnabled(!running); - m_pActionStopSynergy->setEnabled(running); - - switch (state) - { - case synergyListening: { - if (synergyType() == synergyServer) { - setStatus(tr("Synergy is waiting for clients").arg(m_SecureSocketVersion)); - } - - break; - } - case synergyConnected: { - if (m_SecureSocket) { - setStatus(tr("Synergy is connected (with %1)").arg(m_SecureSocketVersion)); - } - else { - setStatus(tr("Synergy is running (without TLS encryption)").arg(m_SecureSocketVersion)); - } - break; - } - case synergyConnecting: - setStatus(tr("Synergy is starting...")); - break; - case synergyPendingRetry: - setStatus(tr("There was an error, retrying...")); - break; - case synergyDisconnected: - setStatus(tr("Synergy is not running")); - break; - } - - setIcon(state); - - m_SynergyState = state; -} - -void MainWindow::setVisible(bool visible) -{ - QMainWindow::setVisible(visible); - m_pActionMinimize->setEnabled(visible); - m_pActionRestore->setEnabled(!visible); +void MainWindow::setVisible(bool visible) { + QMainWindow::setVisible(visible); + m_pActionMinimize->setEnabled(visible); + m_pActionRestore->setEnabled(!visible); #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 // lion - // dock hide only supported on lion :( - ProcessSerialNumber psn = { 0, kCurrentProcess }; + // dock hide only supported on lion :( + ProcessSerialNumber psn = {0, kCurrentProcess}; #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdeprecated-declarations" - GetCurrentProcess(&psn); + GetCurrentProcess(&psn); #pragma GCC diagnostic pop - if (visible) - TransformProcessType(&psn, kProcessTransformToForegroundApplication); - else - TransformProcessType(&psn, kProcessTransformToBackgroundApplication); + if (visible) + TransformProcessType(&psn, kProcessTransformToForegroundApplication); + else + TransformProcessType(&psn, kProcessTransformToBackgroundApplication); #endif } -QString MainWindow::getIPAddresses() -{ - QStringList result; - bool hinted = false; - const auto localnet = QHostAddress::parseSubnet("192.168.0.0/16"); - const QList addresses = QNetworkInterface::allAddresses(); +QString MainWindow::getIPAddresses() { + QStringList result; + bool hinted = false; + const auto localnet = QHostAddress::parseSubnet("192.168.0.0/16"); + const QList addresses = QNetworkInterface::allAddresses(); - for (const auto& address : addresses) { - if (address.protocol() == QAbstractSocket::IPv4Protocol && - address != QHostAddress(QHostAddress::LocalHost) && - !address.isInSubnet(QHostAddress::parseSubnet("169.254.0.0/16"))) { + for (const auto &address : addresses) { + if (address.protocol() == QAbstractSocket::IPv4Protocol && + address != QHostAddress(QHostAddress::LocalHost) && + !address.isInSubnet(QHostAddress::parseSubnet("169.254.0.0/16"))) { - // usually 192.168.x.x is a useful ip for the user, so indicate - // this by making it bold. - if (!hinted && address.isInSubnet(localnet)) { - QString format = "%1"; - result.append(format.arg(address.toString())); - hinted = true; - } - else { - result.append(address.toString()); - } - } + // usually 192.168.x.x is a useful ip for the user, so indicate + // this by making it bold. + if (!hinted && address.isInSubnet(localnet)) { + QString format = "%1"; + result.append(format.arg(address.toString())); + hinted = true; + } else { + result.append(address.toString()); + } } + } - if (result.isEmpty()) { - result.append(tr("Unknown")); - } + if (result.isEmpty()) { + result.append(tr("Unknown")); + } - return result.join(", "); + return result.join(", "); } -void MainWindow::changeEvent(QEvent* event) -{ - if (event != 0) - { - switch (event->type()) - { - case QEvent::LanguageChange: - { - retranslateUi(this); - retranslateMenuBar(); - updateWindowTitle(); - proofreadInfo(); +void MainWindow::changeEvent(QEvent *event) { + if (event != 0) { + switch (event->type()) { + case QEvent::LanguageChange: { + retranslateUi(this); + retranslateMenuBar(); + updateWindowTitle(); + proofreadInfo(); - break; - } - case QEvent::WindowStateChange: - { - windowStateChanged(); - break; - } - } + break; } - // all that do not return are allowing the event to propagate - QMainWindow::changeEvent(event); + case QEvent::WindowStateChange: { + windowStateChanged(); + break; + } + } + } + // all that do not return are allowing the event to propagate + QMainWindow::changeEvent(event); } -void MainWindow::addZeroconfServer(const QString name) -{ - // don't add yourself to the server list. - if (getIPAddresses().contains(name)) { - return; - } +void MainWindow::addZeroconfServer(const QString name) { + // don't add yourself to the server list. + if (getIPAddresses().contains(name)) { + return; + } - if (m_pComboServerList->findText(name) == -1) { - m_pComboServerList->addItem(name); - } + if (m_pComboServerList->findText(name) == -1) { + m_pComboServerList->addItem(name); + } } -void MainWindow::setEdition(Edition edition) -{ +void MainWindow::setEdition(Edition edition) { #ifndef SYNERGY_ENTERPRISE - setWindowTitle(m_LicenseManager->getEditionName (edition)); + setWindowTitle(m_LicenseManager->getEditionName(edition)); #endif } #ifndef SYNERGY_ENTERPRISE -void MainWindow::InvalidLicense() -{ - stopSynergy(); - m_AppConfig->activationHasRun(false); +void MainWindow::InvalidLicense() { + stopSynergy(); + m_AppConfig->activationHasRun(false); } -void MainWindow::showLicenseNotice(const QString& notice) -{ - this->m_trialLabel->hide(); +void MainWindow::showLicenseNotice(const QString ¬ice) { + this->m_trialLabel->hide(); - if (!notice.isEmpty()) { - this->m_trialLabel->setText(notice); - this->m_trialLabel->show(); - } + if (!notice.isEmpty()) { + this->m_trialLabel->setText(notice); + this->m_trialLabel->show(); + } - setWindowTitle (m_LicenseManager->activeEditionName()); + setWindowTitle(m_LicenseManager->activeEditionName()); } #endif -void MainWindow::updateLocalFingerprint() -{ - if (m_AppConfig->getCryptoEnabled() && - Fingerprint::local().fileExists() && - m_pRadioGroupServer->isChecked()) - { - m_pLabelFingerprint->setVisible(true); - } - else - { - m_pLabelFingerprint->setVisible(false); - } +void MainWindow::updateLocalFingerprint() { + if (m_AppConfig->getCryptoEnabled() && Fingerprint::local().fileExists() && + m_pRadioGroupServer->isChecked()) { + m_pLabelFingerprint->setVisible(true); + } else { + m_pLabelFingerprint->setVisible(false); + } } #ifndef SYNERGY_ENTERPRISE -LicenseManager& -MainWindow::licenseManager() const -{ - return *m_LicenseManager; -} +LicenseManager &MainWindow::licenseManager() const { return *m_LicenseManager; } #endif -bool MainWindow::on_m_pActionSave_triggered() -{ - QString fileName = QFileDialog::getSaveFileName(this, tr("Save configuration as...")); +bool MainWindow::on_m_pActionSave_triggered() { + QString fileName = + QFileDialog::getSaveFileName(this, tr("Save configuration as...")); - if (!fileName.isEmpty() && !serverConfig().save(fileName)) - { - QMessageBox::warning(this, tr("Save failed"), tr("Could not save configuration to file.")); - return true; - } + if (!fileName.isEmpty() && !serverConfig().save(fileName)) { + QMessageBox::warning(this, tr("Save failed"), + tr("Could not save configuration to file.")); + return true; + } - return false; + return false; } -void MainWindow::on_m_pActionAbout_triggered() -{ +void MainWindow::on_m_pActionAbout_triggered() { #if defined(SYNERGY_ENTERPRISE) || defined(SYNERGY_BUSINESS) + AboutDialog dlg(this, appConfig()); + dlg.exec(); +#else + if (appConfig().edition() == Edition::kBusiness) { AboutDialog dlg(this, appConfig()); dlg.exec(); -#else - if (appConfig().edition() == Edition::kBusiness) { - AboutDialog dlg(this, appConfig()); - dlg.exec(); - } - else { - AboutDialogEliteBackers dlg(this, appConfig()); - dlg.exec(); - } + } else { + AboutDialogEliteBackers dlg(this, appConfig()); + dlg.exec(); + } #endif } -void MainWindow::on_m_pActionHelp_triggered() -{ - QDesktopServices::openUrl(QUrl(HELP_URL)); +void MainWindow::on_m_pActionHelp_triggered() { + QDesktopServices::openUrl(QUrl(HELP_URL)); } -void MainWindow::updateZeroconfService() -{ +void MainWindow::updateZeroconfService() { #if !defined(SYNERGY_ENTERPRISE) && defined(SYNERGY_AUTOCONFIG) - // reset the server list in case one has gone away. - // it'll be re-added after the zeroconf service restarts. - m_pComboServerList->clear(); + // reset the server list in case one has gone away. + // it'll be re-added after the zeroconf service restarts. + m_pComboServerList->clear(); - if (m_pZeroconf != nullptr) { - if (appConfig().autoConfig()) { - m_pZeroconf->startService(); - } - else { - m_pZeroconf->stopService(); - } + if (m_pZeroconf != nullptr) { + if (appConfig().autoConfig()) { + m_pZeroconf->startService(); + } else { + m_pZeroconf->stopService(); } + } #endif } -void MainWindow::updateAutoConfigWidgets() -{ - m_pLabelServerName->show(); - m_pLineEditHostname->show(); +void MainWindow::updateAutoConfigWidgets() { + m_pLabelServerName->show(); + m_pLineEditHostname->show(); - m_pLabelAutoDetected->hide(); - m_pComboServerList->hide(); + m_pLabelAutoDetected->hide(); + m_pComboServerList->hide(); } -void MainWindow::updateWindowTitle() -{ +void MainWindow::updateWindowTitle() { #ifdef SYNERGY_ENTERPRISE - setWindowTitle ("Synergy 1 Enterprise"); + setWindowTitle("Synergy 1 Enterprise"); #else - setWindowTitle (m_LicenseManager->activeEditionName()); - m_LicenseManager->refresh(); + setWindowTitle(m_LicenseManager->activeEditionName()); + m_LicenseManager->refresh(); #endif } -void MainWindow::on_m_pActionSettings_triggered() -{ - auto result = SettingsDialog(this, appConfig()).exec(); - if(result == QDialog::Accepted) - { - enableServer(appConfig().getServerGroupChecked()); - enableClient(appConfig().getClientGroupChecked()); - auto state = synergyState(); - if ((state == synergyConnected) || (state == synergyConnecting) || (state == synergyListening)) { - restartSynergy(); - } +void MainWindow::on_m_pActionSettings_triggered() { + auto result = SettingsDialog(this, appConfig()).exec(); + if (result == QDialog::Accepted) { + enableServer(appConfig().getServerGroupChecked()); + enableClient(appConfig().getClientGroupChecked()); + auto state = synergyState(); + if ((state == synergyConnected) || (state == synergyConnecting) || + (state == synergyListening)) { + restartSynergy(); } + } } -void MainWindow::autoAddScreen(const QString name) -{ - if (m_ServerConfig.ignoreAutoConfigClient()) { - appendLogDebug(QString("ignoring zeroconf screen: %1").arg(name)); - return; - } +void MainWindow::autoAddScreen(const QString name) { + if (m_ServerConfig.ignoreAutoConfigClient()) { + appendLogDebug(QString("ignoring zeroconf screen: %1").arg(name)); + return; + } #ifndef SYNERGY_ENTERPRISE - if (m_ActivationDialogRunning) { - // TODO: refactor this code - // add this screen to the pending list and check this list until - // users finish activation dialog - m_PendingClientNames.append(name); - return; - } + if (m_ActivationDialogRunning) { + // TODO: refactor this code + // add this screen to the pending list and check this list until + // users finish activation dialog + m_PendingClientNames.append(name); + return; + } #endif - int r = m_ServerConfig.autoAddScreen(name); - if (r != kAutoAddScreenOk) { - switch (r) { - case kAutoAddScreenManualServer: - showConfigureServer( - tr("Please add the server (%1) to the grid.") - .arg(appConfig().screenName())); - break; + int r = m_ServerConfig.autoAddScreen(name); + if (r != kAutoAddScreenOk) { + switch (r) { + case kAutoAddScreenManualServer: + showConfigureServer(tr("Please add the server (%1) to the grid.") + .arg(appConfig().screenName())); + break; - case kAutoAddScreenManualClient: - showConfigureServer( - tr("Please drag the new client screen (%1) " - "to the desired position on the grid.") - .arg(name)); - break; - } + case kAutoAddScreenManualClient: + showConfigureServer(tr("Please drag the new client screen (%1) " + "to the desired position on the grid.") + .arg(name)); + break; } + } } -void MainWindow::showConfigureServer(const QString& message) -{ - ServerConfigDialog dlg(this, serverConfig()); - dlg.message(message); - auto result = dlg.exec(); +void MainWindow::showConfigureServer(const QString &message) { + ServerConfigDialog dlg(this, serverConfig()); + dlg.message(message); + auto result = dlg.exec(); - if(result == QDialog::Accepted) { - auto state = synergyState(); - if ((state == synergyConnected) || (state == synergyConnecting) || (state == synergyListening)) { - restartSynergy(); - } + if (result == QDialog::Accepted) { + auto state = synergyState(); + if ((state == synergyConnected) || (state == synergyConnecting) || + (state == synergyListening)) { + restartSynergy(); } + } } -void MainWindow::on_m_pButtonConfigureServer_clicked() -{ - showConfigureServer(); +void MainWindow::on_m_pButtonConfigureServer_clicked() { + showConfigureServer(); } -void MainWindow::on_m_pActivate_triggered() -{ +void MainWindow::on_m_pActivate_triggered() { #ifndef SYNERGY_ENTERPRISE + raiseActivationDialog(); +#endif +} + +void MainWindow::on_m_pButtonApply_clicked() { + m_clientConnection.setCheckConnection(true); + restartSynergy(); +} + +#ifndef SYNERGY_ENTERPRISE +int MainWindow::raiseActivationDialog() { + if (m_ActivationDialogRunning) { + return QDialog::Rejected; + } + ActivationDialog activationDialog(this, appConfig(), licenseManager()); + m_ActivationDialogRunning = true; + int result = activationDialog.exec(); + m_ActivationDialogRunning = false; + if (!m_PendingClientNames.empty()) { + foreach (const QString &name, m_PendingClientNames) { + autoAddScreen(name); + } + + m_PendingClientNames.clear(); + } + return result; +} +#endif + +void MainWindow::on_windowShown() { +#ifndef SYNERGY_ENTERPRISE + auto serialKey = m_LicenseManager->serialKey(); + if (!m_AppConfig->activationHasRun() && !serialKey.isValid()) { + setEdition(Edition::kUnregistered); raiseActivationDialog(); + } #endif } -void MainWindow::on_m_pButtonApply_clicked() -{ - m_clientConnection.setCheckConnection(true); - restartSynergy(); -} +QString MainWindow::getProfileRootForArg() { + CoreInterface coreInterface; + QString dir = coreInterface.getProfileDir(); -#ifndef SYNERGY_ENTERPRISE -int MainWindow::raiseActivationDialog() -{ - if (m_ActivationDialogRunning) { - return QDialog::Rejected; - } - ActivationDialog activationDialog (this, appConfig(), licenseManager()); - m_ActivationDialogRunning = true; - int result = activationDialog.exec(); - m_ActivationDialogRunning = false; - if (!m_PendingClientNames.empty()) { - foreach (const QString& name, m_PendingClientNames) { - autoAddScreen(name); - } - - m_PendingClientNames.clear(); - } - return result; -} -#endif - -void MainWindow::on_windowShown() -{ -#ifndef SYNERGY_ENTERPRISE - auto serialKey = m_LicenseManager->serialKey(); - if (!m_AppConfig->activationHasRun() && !serialKey.isValid()) { - setEdition(Edition::kUnregistered); - raiseActivationDialog(); - } -#endif -} - -QString MainWindow::getProfileRootForArg() -{ - CoreInterface coreInterface; - QString dir = coreInterface.getProfileDir(); - - // HACK: strip our app name since we're returning the root dir. + // HACK: strip our app name since we're returning the root dir. #if defined(Q_OS_WIN) - dir.replace("\\Synergy", ""); + dir.replace("\\Synergy", ""); #else - dir.replace("/.synergy", ""); + dir.replace("/.synergy", ""); #endif - return QString("\"%1\"").arg(dir); + return QString("\"%1\"").arg(dir); } -void MainWindow::secureSocket(bool secureSocket) -{ - m_SecureSocket = secureSocket; - if (secureSocket) { - m_pLabelPadlock->show(); +void MainWindow::secureSocket(bool secureSocket) { + m_SecureSocket = secureSocket; + if (secureSocket) { + m_pLabelPadlock->show(); + } else { + m_pLabelPadlock->hide(); + } +} + +void MainWindow::on_m_pLabelComputerName_linkActivated(const QString &) { + m_pActionSettings->trigger(); +} + +void MainWindow::on_m_pLabelFingerprint_linkActivated(const QString &) { + QMessageBox::information(this, "SSL/TLS fingerprint", + Fingerprint::local().readFirst()); +} + +void MainWindow::on_m_pComboServerList_currentIndexChanged( + const QString &server) { + appConfig().setAutoConfigServer(server); +} + +void MainWindow::windowStateChanged() { + if (windowState() == Qt::WindowMinimized && appConfig().getMinimizeToTray()) + hide(); +} + +void MainWindow::updateScreenName() { + m_pLabelComputerName->setText( + tr("This computer's name: %1 (Preferences)") + .arg(appConfig().screenName())); + serverConfig().updateServerName(); +} + +void MainWindow::enableServer(bool enable) { + m_AppConfig->setServerGroupChecked(enable); + m_pRadioGroupServer->setChecked(enable); + + if (enable) { + if (m_AppConfig->getServerClientMode()) { + m_pLabelClientIp->show(); + m_pLineEditClienIp->show(); + m_pButtonConnectToClient->show(); + } else { + m_pLabelClientIp->hide(); + m_pLineEditClienIp->hide(); + m_pButtonConnectToClient->hide(); } - else { - m_pLabelPadlock->hide(); + + m_pButtonConfigureServer->show(); + m_pLabelServerState->show(); + updateLocalFingerprint(); + m_pButtonToggleStart->setEnabled(enable); + } else { + m_pLabelFingerprint->hide(); + m_pButtonConfigureServer->hide(); + m_pLabelServerState->hide(); + m_pLabelClientIp->hide(); + m_pLineEditClienIp->hide(); + m_pButtonConnectToClient->hide(); + } +} + +void MainWindow::enableClient(bool enable) { + m_AppConfig->setClientGroupChecked(enable); + m_pRadioGroupClient->setChecked(enable); + + if (enable) { + if (m_AppConfig->getClientHostMode()) { + m_pLabelServerName->hide(); + m_pLineEditHostname->hide(); + m_pButtonConnect->hide(); + } else { + m_pLabelServerName->show(); + m_pLineEditHostname->show(); + m_pButtonConnect->show(); } + m_pButtonToggleStart->setEnabled(enable); + } else { + m_pLabelClientState->hide(); + m_pLabelServerName->hide(); + m_pLineEditHostname->hide(); + m_pButtonConnect->hide(); + } } -void MainWindow::on_m_pLabelComputerName_linkActivated(const QString&) -{ - m_pActionSettings->trigger(); -} - -void MainWindow::on_m_pLabelFingerprint_linkActivated(const QString&) -{ - QMessageBox::information(this, "SSL/TLS fingerprint", Fingerprint::local().readFirst()); -} - -void MainWindow::on_m_pComboServerList_currentIndexChanged(const QString &server) -{ - appConfig().setAutoConfigServer(server); -} - -void MainWindow::windowStateChanged() -{ - if (windowState() == Qt::WindowMinimized && appConfig().getMinimizeToTray()) - hide(); -} - -void MainWindow::updateScreenName() -{ - m_pLabelComputerName->setText(tr("This computer's name: %1 (Preferences)").arg(appConfig().screenName())); - serverConfig().updateServerName(); -} - -void MainWindow::enableServer(bool enable) -{ - m_AppConfig->setServerGroupChecked(enable); - m_pRadioGroupServer->setChecked(enable); - - if (enable) - { - if (m_AppConfig->getServerClientMode()) { - m_pLabelClientIp->show(); - m_pLineEditClienIp->show(); - m_pButtonConnectToClient->show(); - } - else { - m_pLabelClientIp->hide(); - m_pLineEditClienIp->hide(); - m_pButtonConnectToClient->hide(); - } - - m_pButtonConfigureServer->show(); - m_pLabelServerState->show(); - updateLocalFingerprint(); - m_pButtonToggleStart->setEnabled(enable); - } - else - { - m_pLabelFingerprint->hide(); - m_pButtonConfigureServer->hide(); - m_pLabelServerState->hide(); - m_pLabelClientIp->hide(); - m_pLineEditClienIp->hide(); - m_pButtonConnectToClient->hide(); - } -} - -void MainWindow::enableClient(bool enable) -{ - m_AppConfig->setClientGroupChecked(enable); - m_pRadioGroupClient->setChecked(enable); - - if (enable) - { - if (m_AppConfig->getClientHostMode()) - { - m_pLabelServerName->hide(); - m_pLineEditHostname->hide(); - m_pButtonConnect->hide(); - } - else - { - m_pLabelServerName->show(); - m_pLineEditHostname->show(); - m_pButtonConnect->show(); - } - m_pButtonToggleStart->setEnabled(enable); - } - else - { - m_pLabelClientState->hide(); - m_pLabelServerName->hide(); - m_pLineEditHostname->hide(); - m_pButtonConnect->hide(); - } -} - -void MainWindow::closeEvent(QCloseEvent* event) -{ -#if defined (Q_OS_LINUX) - QCoreApplication::quit(); +void MainWindow::closeEvent(QCloseEvent *event) { +#if defined(Q_OS_LINUX) + QCoreApplication::quit(); #endif - QWidget::closeEvent(event); + QWidget::closeEvent(event); } -void MainWindow::on_m_pRadioGroupServer_clicked(bool) -{ - enableServer(true); - enableClient(false); - m_AppConfig->saveSettings(); +void MainWindow::on_m_pRadioGroupServer_clicked(bool) { + enableServer(true); + enableClient(false); + m_AppConfig->saveSettings(); } -void MainWindow::on_m_pRadioGroupClient_clicked(bool) -{ - enableClient(true); - enableServer(false); - m_AppConfig->saveSettings(); +void MainWindow::on_m_pRadioGroupClient_clicked(bool) { + enableClient(true); + enableServer(false); + m_AppConfig->saveSettings(); } -void MainWindow::on_m_pButtonConnect_clicked() -{ - on_m_pButtonApply_clicked(); -} +void MainWindow::on_m_pButtonConnect_clicked() { on_m_pButtonApply_clicked(); } -void MainWindow::on_m_pButtonConnectToClient_clicked() -{ - on_m_pButtonApply_clicked(); +void MainWindow::on_m_pButtonConnectToClient_clicked() { + on_m_pButtonApply_clicked(); } - diff --git a/src/gui/src/MainWindow.h b/src/gui/src/MainWindow.h index 56a6c9477..dd7d8c58c 100644 --- a/src/gui/src/MainWindow.h +++ b/src/gui/src/MainWindow.h @@ -19,23 +19,23 @@ #pragma once #include -#include -#include -#include -#include #include +#include +#include +#include +#include #include "ui_MainWindowBase.h" +#include "ActivationDialog.h" +#include "AppConfig.h" +#include "ClientConnection.h" +#include "ConfigWriter.h" +#include "Ipc.h" +#include "IpcClient.h" #include "ServerConfig.h" #include "ServerConnection.h" -#include "ClientConnection.h" -#include "AppConfig.h" #include "VersionChecker.h" -#include "IpcClient.h" -#include "Ipc.h" -#include "ActivationDialog.h" -#include "ConfigWriter.h" #include "TrayIcon.h" @@ -61,210 +61,203 @@ class SslCertificate; class LicenseManager; class Zeroconf; -class MainWindow : public QMainWindow, public Ui::MainWindowBase -{ - Q_OBJECT +class MainWindow : public QMainWindow, public Ui::MainWindowBase { + Q_OBJECT - friend class QSynergyApplication; - friend class SetupWizard; - friend class ActivationDialog; - friend class SettingsDialog; - friend class ServerConnection; - friend class ClientConnection; + friend class QSynergyApplication; + friend class SetupWizard; + friend class ActivationDialog; + friend class SettingsDialog; + friend class ServerConnection; + friend class ClientConnection; - public: - enum qSynergyState - { - synergyDisconnected, - synergyConnecting, - synergyConnected, - synergyListening, - synergyPendingRetry - }; +public: + enum qSynergyState { + synergyDisconnected, + synergyConnecting, + synergyConnected, + synergyListening, + synergyPendingRetry + }; - enum qSynergyType - { - synergyClient, - synergyServer - }; + enum qSynergyType { synergyClient, synergyServer }; - enum qLevel { - Error, - Info - }; + enum qLevel { Error, Info }; - enum qRuningState { - kStarted, - kStopped - }; + enum qRuningState { kStarted, kStopped }; - public: +public: #ifdef SYNERGY_ENTERPRISE - MainWindow(AppConfig& appConfig); + MainWindow(AppConfig &appConfig); #else - MainWindow(AppConfig& appConfig, - LicenseManager& licenseManager); + MainWindow(AppConfig &appConfig, LicenseManager &licenseManager); #endif - ~MainWindow(); + ~MainWindow(); - public: - void setVisible(bool visible); - int synergyType() const { return m_pRadioGroupClient->isChecked() ? synergyClient : synergyServer; } - int synergyState() const { return m_SynergyState; } - QString hostname() const { return m_pLineEditHostname->text(); } - QString configFilename(); - QString address() const; - QString appPath(const QString& name); - void open(); - void clearLog(); - VersionChecker& versionChecker() { return m_VersionChecker; } - ServerConfig& serverConfig() { return m_ServerConfig; } - void showConfigureServer(const QString& message); - void showConfigureServer() { showConfigureServer(""); } - void autoAddScreen(const QString name); - void addZeroconfServer(const QString name); - Zeroconf& zeroconf() { return *m_pZeroconf; } +public: + void setVisible(bool visible); + int synergyType() const { + return m_pRadioGroupClient->isChecked() ? synergyClient : synergyServer; + } + int synergyState() const { return m_SynergyState; } + QString hostname() const { return m_pLineEditHostname->text(); } + QString configFilename(); + QString address() const; + QString appPath(const QString &name); + void open(); + void clearLog(); + VersionChecker &versionChecker() { return m_VersionChecker; } + ServerConfig &serverConfig() { return m_ServerConfig; } + void showConfigureServer(const QString &message); + void showConfigureServer() { showConfigureServer(""); } + void autoAddScreen(const QString name); + void addZeroconfServer(const QString name); + Zeroconf &zeroconf() { return *m_pZeroconf; } #ifndef SYNERGY_ENTERPRISE - LicenseManager& licenseManager() const; - int raiseActivationDialog(); + LicenseManager &licenseManager() const; + int raiseActivationDialog(); #endif - void updateZeroconfService(); + void updateZeroconfService(); public slots: - void setEdition(Edition edition); + void setEdition(Edition edition); #ifndef SYNERGY_ENTERPRISE - void InvalidLicense(); - void showLicenseNotice(const QString& message); + void InvalidLicense(); + void showLicenseNotice(const QString &message); #endif - void appendLogRaw(const QString& text); - void appendLogInfo(const QString& text); - void appendLogDebug(const QString& text); - void appendLogError(const QString& text); - void startSynergy(); - void retryStart(); // If the connection failed this will retry a startSynergy - void actionStart(); - void handleIdleService(const QString& text); + void appendLogRaw(const QString &text); + void appendLogInfo(const QString &text); + void appendLogDebug(const QString &text); + void appendLogError(const QString &text); + void startSynergy(); + void retryStart(); // If the connection failed this will retry a startSynergy + void actionStart(); + void handleIdleService(const QString &text); - protected slots: - void updateLocalFingerprint(); - void updateScreenName(); - void on_m_pRadioGroupServer_clicked(bool); - void on_m_pRadioGroupClient_clicked(bool); - void on_m_pButtonConfigureServer_clicked(); - bool on_m_pActionSave_triggered(); - void on_m_pActionAbout_triggered(); - void on_m_pActionHelp_triggered(); - void on_m_pActionSettings_triggered(); - void on_m_pActivate_triggered(); - void synergyFinished(int exitCode, QProcess::ExitStatus); - void trayActivated(QSystemTrayIcon::ActivationReason reason); - void stopSynergy(); - void logOutput(); - void logError(); - void updateFound(const QString& version); - void saveSettings(); +protected slots: + void updateLocalFingerprint(); + void updateScreenName(); + void on_m_pRadioGroupServer_clicked(bool); + void on_m_pRadioGroupClient_clicked(bool); + void on_m_pButtonConfigureServer_clicked(); + bool on_m_pActionSave_triggered(); + void on_m_pActionAbout_triggered(); + void on_m_pActionHelp_triggered(); + void on_m_pActionSettings_triggered(); + void on_m_pActivate_triggered(); + void synergyFinished(int exitCode, QProcess::ExitStatus); + void trayActivated(QSystemTrayIcon::ActivationReason reason); + void stopSynergy(); + void logOutput(); + void logError(); + void updateFound(const QString &version); + void saveSettings(); - /// @brief Receives the signal that the auto config option has changed - void zeroConfToggled(); + /// @brief Receives the signal that the auto config option has changed + void zeroConfToggled(); - protected: - // TODO This should be properly using the ConfigWriter system. - QSettings& settings() { return GUI::Config::ConfigWriter::make()->settings(); } - AppConfig& appConfig() { return *m_AppConfig; } - AppConfig const& appConfig() const { return *m_AppConfig; } - QProcess* synergyProcess() { return m_pSynergy; } - void setSynergyProcess(QProcess* p) { m_pSynergy = p; } - void initConnections(); - void createMenuBar(); - void createStatusBar(); - void createTrayIcon(); - void loadSettings(); - void setIcon(qSynergyState state) const; - void setSynergyState(qSynergyState state); - bool checkForApp(int which, QString& app); - bool clientArgs(QStringList& args, QString& app); - bool serverArgs(QStringList& args, QString& app); - void setStatus(const QString& status); - void sendIpcMessage(qIpcMessageType type, const char* buffer, bool showErrors); - void updateFromLogLine(const QString& line); - QString getIPAddresses(); - void stopService(); - void stopDesktop(); - void changeEvent(QEvent* event); - void retranslateMenuBar(); - void enableServer(bool enable); - void enableClient(bool enable); - void closeEvent(QCloseEvent* event) override; +protected: + // TODO This should be properly using the ConfigWriter system. + QSettings &settings() { + return GUI::Config::ConfigWriter::make()->settings(); + } + AppConfig &appConfig() { return *m_AppConfig; } + AppConfig const &appConfig() const { return *m_AppConfig; } + QProcess *synergyProcess() { return m_pSynergy; } + void setSynergyProcess(QProcess *p) { m_pSynergy = p; } + void initConnections(); + void createMenuBar(); + void createStatusBar(); + void createTrayIcon(); + void loadSettings(); + void setIcon(qSynergyState state) const; + void setSynergyState(qSynergyState state); + bool checkForApp(int which, QString &app); + bool clientArgs(QStringList &args, QString &app); + bool serverArgs(QStringList &args, QString &app); + void setStatus(const QString &status); + void sendIpcMessage(qIpcMessageType type, const char *buffer, + bool showErrors); + void updateFromLogLine(const QString &line); + QString getIPAddresses(); + void stopService(); + void stopDesktop(); + void changeEvent(QEvent *event); + void retranslateMenuBar(); + void enableServer(bool enable); + void enableClient(bool enable); + void closeEvent(QCloseEvent *event) override; #if defined(Q_OS_WIN) - bool isServiceRunning(QString name); + bool isServiceRunning(QString name); #else - bool isServiceRunning(); + bool isServiceRunning(); #endif - QString getProfileRootForArg(); - void checkConnected(const QString& line); - void checkFingerprint(const QString& line); - void checkSecureSocket(const QString& line); + QString getProfileRootForArg(); + void checkConnected(const QString &line); + void checkFingerprint(const QString &line); + void checkSecureSocket(const QString &line); #ifdef Q_OS_MAC - void checkOSXNotification(const QString& line); + void checkOSXNotification(const QString &line); #endif #ifndef SYNERGY_ENTERPRISE - void checkLicense(const QString& line); + void checkLicense(const QString &line); #endif - QString getTimeStamp(); - void restartSynergy(); - void proofreadInfo(); + QString getTimeStamp(); + void restartSynergy(); + void proofreadInfo(); - void showEvent (QShowEvent*); - void secureSocket(bool secureSocket); + void showEvent(QShowEvent *); + void secureSocket(bool secureSocket); - void windowStateChanged(); + void windowStateChanged(); - - private: +private: #ifndef SYNERGY_ENTERPRISE - LicenseManager* m_LicenseManager; - bool m_ActivationDialogRunning; - QStringList m_PendingClientNames; + LicenseManager *m_LicenseManager; + bool m_ActivationDialogRunning; + QStringList m_PendingClientNames; #endif - Zeroconf* m_pZeroconf; - AppConfig* m_AppConfig; - QProcess* m_pSynergy; - int m_SynergyState; - ServerConfig m_ServerConfig; - bool m_AlreadyHidden; - VersionChecker m_VersionChecker; - IpcClient m_IpcClient; - QMenuBar* m_pMenuBar; - QMenu* m_pMenuFile; - QMenu* m_pMenuEdit; - QMenu* m_pMenuWindow; - QMenu* m_pMenuHelp; - QAbstractButton* m_pCancelButton; - TrayIcon m_trayIcon; - qRuningState m_ExpectedRunningState; - QMutex m_StopDesktopMutex; - bool m_SecureSocket; // brief Is the program running a secure socket protocol (SSL/TLS) - QString m_SecureSocketVersion; // brief Contains the version of the Secure Socket currently active - ServerConnection m_serverConnection; - ClientConnection m_clientConnection; + Zeroconf *m_pZeroconf; + AppConfig *m_AppConfig; + QProcess *m_pSynergy; + int m_SynergyState; + ServerConfig m_ServerConfig; + bool m_AlreadyHidden; + VersionChecker m_VersionChecker; + IpcClient m_IpcClient; + QMenuBar *m_pMenuBar; + QMenu *m_pMenuFile; + QMenu *m_pMenuEdit; + QMenu *m_pMenuWindow; + QMenu *m_pMenuHelp; + QAbstractButton *m_pCancelButton; + TrayIcon m_trayIcon; + qRuningState m_ExpectedRunningState; + QMutex m_StopDesktopMutex; + bool m_SecureSocket; // brief Is the program running a secure socket protocol + // (SSL/TLS) + QString m_SecureSocketVersion; // brief Contains the version of the Secure + // Socket currently active + ServerConnection m_serverConnection; + ClientConnection m_clientConnection; + + void updateAutoConfigWidgets(); + void updateWindowTitle(); - void updateAutoConfigWidgets(); - void updateWindowTitle(); - private slots: - void on_m_pButtonApply_clicked(); - void on_windowShown(); + void on_m_pButtonApply_clicked(); + void on_windowShown(); - void on_m_pLabelComputerName_linkActivated(const QString &link); - void on_m_pLabelFingerprint_linkActivated(const QString& link); - void on_m_pComboServerList_currentIndexChanged(const QString &arg1); + void on_m_pLabelComputerName_linkActivated(const QString &link); + void on_m_pLabelFingerprint_linkActivated(const QString &link); + void on_m_pComboServerList_currentIndexChanged(const QString &arg1); - void on_m_pButtonConnect_clicked(); - void on_m_pButtonConnectToClient_clicked(); + void on_m_pButtonConnect_clicked(); + void on_m_pButtonConnectToClient_clicked(); signals: - void windowShown(); + void windowShown(); }; diff --git a/src/gui/src/OSXHelpers.h b/src/gui/src/OSXHelpers.h index 0b98bee71..1911e89a0 100644 --- a/src/gui/src/OSXHelpers.h +++ b/src/gui/src/OSXHelpers.h @@ -21,15 +21,11 @@ #include -enum class IconsTheme { - ICONS_DARK, - ICONS_LIGHT, - ICONS_TEMPLATE -}; +enum class IconsTheme { ICONS_DARK, ICONS_LIGHT, ICONS_TEMPLATE }; void requestOSXNotificationPermission(); bool isOSXDevelopmentBuild(); -bool showOSXNotification(const QString& title, const QString& body); +bool showOSXNotification(const QString &title, const QString &body); bool isOSXInterfaceStyleDark(); IconsTheme getOSXIconsTheme(); diff --git a/src/gui/src/ProcessorArch.h b/src/gui/src/ProcessorArch.h index cb2d30fc0..e47957f8b 100644 --- a/src/gui/src/ProcessorArch.h +++ b/src/gui/src/ProcessorArch.h @@ -18,11 +18,11 @@ #pragma once enum qProcessorArch { - kProcessorArchWin32, - kProcessorArchWin64, - kProcessorArchMac32, - kProcessorArchMac64, - kProcessorArchLinux32, - kProcessorArchLinux64, - kProcessorArchUnknown + kProcessorArchWin32, + kProcessorArchWin64, + kProcessorArchMac32, + kProcessorArchMac64, + kProcessorArchLinux32, + kProcessorArchLinux64, + kProcessorArchUnknown }; diff --git a/src/gui/src/QSynergyApplication.cpp b/src/gui/src/QSynergyApplication.cpp index cc0f837cc..f5ba92112 100644 --- a/src/gui/src/QSynergyApplication.cpp +++ b/src/gui/src/QSynergyApplication.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2008 Volker Lanz (vl@fidra.de) - * + * * 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 LICENSE 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 @@ -22,57 +22,44 @@ #include #include -QSynergyApplication* QSynergyApplication::s_Instance = NULL; +QSynergyApplication *QSynergyApplication::s_Instance = NULL; -QSynergyApplication::QSynergyApplication(int& argc, char** argv) : - QApplication(argc, argv), - m_Translator(NULL) -{ - s_Instance = this; +QSynergyApplication::QSynergyApplication(int &argc, char **argv) + : QApplication(argc, argv), m_Translator(NULL) { + s_Instance = this; - QFontDatabase::addApplicationFont(":/res/fonts/Arial.ttf"); - QFont Arial("Arial"); - Arial.setPixelSize(13); - Arial.setStyleHint(QFont::SansSerif); - setFont(Arial); + QFontDatabase::addApplicationFont(":/res/fonts/Arial.ttf"); + QFont Arial("Arial"); + Arial.setPixelSize(13); + Arial.setStyleHint(QFont::SansSerif); + setFont(Arial); } -QSynergyApplication::~QSynergyApplication() -{ +QSynergyApplication::~QSynergyApplication() { delete m_Translator; } + +void QSynergyApplication::commitData(QSessionManager &) { + foreach (QWidget *widget, topLevelWidgets()) { + MainWindow *mainWindow = qobject_cast(widget); + if (mainWindow) + mainWindow->saveSettings(); + } +} + +QSynergyApplication *QSynergyApplication::getInstance() { return s_Instance; } + +void QSynergyApplication::switchTranslator(QString lang) { + if (m_Translator != NULL) { + removeTranslator(m_Translator); delete m_Translator; + } + + QResource locale(":/res/lang/gui_" + lang + ".qm"); + m_Translator = new QTranslator(); + m_Translator->load(locale.data(), locale.size()); + installTranslator(m_Translator); } -void QSynergyApplication::commitData(QSessionManager&) -{ - foreach(QWidget* widget, topLevelWidgets()) - { - MainWindow* mainWindow = qobject_cast(widget); - if (mainWindow) - mainWindow->saveSettings(); - } -} - -QSynergyApplication* QSynergyApplication::getInstance() -{ - return s_Instance; -} - -void QSynergyApplication::switchTranslator(QString lang) -{ - if (m_Translator != NULL) - { - removeTranslator(m_Translator); - delete m_Translator; - } - - QResource locale(":/res/lang/gui_" + lang + ".qm"); - m_Translator = new QTranslator(); - m_Translator->load(locale.data(), locale.size()); - installTranslator(m_Translator); -} - -void QSynergyApplication::setTranslator(QTranslator* translator) -{ - m_Translator = translator; - installTranslator(m_Translator); +void QSynergyApplication::setTranslator(QTranslator *translator) { + m_Translator = translator; + installTranslator(m_Translator); } diff --git a/src/gui/src/QSynergyApplication.h b/src/gui/src/QSynergyApplication.h index 26c3be5ea..0424838ee 100644 --- a/src/gui/src/QSynergyApplication.h +++ b/src/gui/src/QSynergyApplication.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2008 Volker Lanz (vl@fidra.de) - * + * * 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 LICENSE 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 @@ -24,24 +24,22 @@ class QSessionManager; -class QSynergyApplication : public QApplication -{ - public: - QSynergyApplication(int& argc, char** argv); - ~QSynergyApplication(); +class QSynergyApplication : public QApplication { +public: + QSynergyApplication(int &argc, char **argv); + ~QSynergyApplication(); - public: - void commitData(QSessionManager& manager); - void switchTranslator(QString lang); - void setTranslator(QTranslator* translator); +public: + void commitData(QSessionManager &manager); + void switchTranslator(QString lang); + void setTranslator(QTranslator *translator); - static QSynergyApplication* getInstance(); + static QSynergyApplication *getInstance(); - private: - QTranslator* m_Translator; +private: + QTranslator *m_Translator; - static QSynergyApplication* s_Instance; + static QSynergyApplication *s_Instance; }; #endif - diff --git a/src/gui/src/QUtility.cpp b/src/gui/src/QUtility.cpp index 38bba3be1..2fa48ab18 100644 --- a/src/gui/src/QUtility.cpp +++ b/src/gui/src/QUtility.cpp @@ -17,12 +17,12 @@ #include "QUtility.h" -#include "ProcessorArch.h" #include "CommandProcess.h" +#include "ProcessorArch.h" #if defined(Q_OS_LINUX) -#include #include +#include #endif #if defined(Q_OS_WIN) @@ -30,50 +30,45 @@ #include #endif -void setIndexFromItemData(QComboBox* comboBox, const QVariant& itemData) -{ - for (int i = 0; i < comboBox->count(); ++i) - { - if (comboBox->itemData(i) == itemData) - { - comboBox->setCurrentIndex(i); - return; - } +void setIndexFromItemData(QComboBox *comboBox, const QVariant &itemData) { + for (int i = 0; i < comboBox->count(); ++i) { + if (comboBox->itemData(i) == itemData) { + comboBox->setCurrentIndex(i); + return; } + } } -QString hash(const QString& string) -{ - QByteArray data = string.toUtf8(); - QByteArray hash = QCryptographicHash::hash(data, QCryptographicHash::Md5); - return hash.toHex(); +QString hash(const QString &string) { + QByteArray data = string.toUtf8(); + QByteArray hash = QCryptographicHash::hash(data, QCryptographicHash::Md5); + return hash.toHex(); } -qProcessorArch getProcessorArch() -{ +qProcessorArch getProcessorArch() { #if defined(Q_OS_WIN) - SYSTEM_INFO systemInfo; - GetNativeSystemInfo(&systemInfo); + SYSTEM_INFO systemInfo; + GetNativeSystemInfo(&systemInfo); - switch (systemInfo.wProcessorArchitecture) { - case PROCESSOR_ARCHITECTURE_INTEL: - return kProcessorArchWin32; - case PROCESSOR_ARCHITECTURE_IA64: - return kProcessorArchWin64; - case PROCESSOR_ARCHITECTURE_AMD64: - return kProcessorArchWin64; - default: - return kProcessorArchUnknown; - } + switch (systemInfo.wProcessorArchitecture) { + case PROCESSOR_ARCHITECTURE_INTEL: + return kProcessorArchWin32; + case PROCESSOR_ARCHITECTURE_IA64: + return kProcessorArchWin64; + case PROCESSOR_ARCHITECTURE_AMD64: + return kProcessorArchWin64; + default: + return kProcessorArchUnknown; + } #endif #if defined(Q_OS_LINUX) #ifdef __i386__ - return kProcessorArchLinux32; + return kProcessorArchLinux32; #else - return kProcessorArchLinux64; + return kProcessorArchLinux64; #endif #endif - return kProcessorArchUnknown; + return kProcessorArchUnknown; } diff --git a/src/gui/src/QUtility.h b/src/gui/src/QUtility.h index 56e76bb88..060ab5a82 100644 --- a/src/gui/src/QUtility.h +++ b/src/gui/src/QUtility.h @@ -20,10 +20,10 @@ #include "ProcessorArch.h" #include -#include #include #include +#include -void setIndexFromItemData(QComboBox* comboBox, const QVariant& itemData); -QString hash(const QString& string); +void setIndexFromItemData(QComboBox *comboBox, const QVariant &itemData); +QString hash(const QString &string); qProcessorArch getProcessorArch(); diff --git a/src/gui/src/Screen.cpp b/src/gui/src/Screen.cpp index 6745d73db..bdbec7c6f 100644 --- a/src/gui/src/Screen.cpp +++ b/src/gui/src/Screen.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2008 Volker Lanz (vl@fidra.de) - * + * * 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 LICENSE 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 @@ -21,141 +21,124 @@ #include #include -Screen::Screen() : - m_Pixmap(QPixmap(":res/icons/64x64/video-display.png")), - m_Swapped(false) -{ - init(); +Screen::Screen() + : m_Pixmap(QPixmap(":res/icons/64x64/video-display.png")), + m_Swapped(false) { + init(); } -Screen::Screen(const QString& name) : - m_Pixmap(QPixmap(":res/icons/64x64/video-display.png")), - m_Swapped(false) -{ - init(); - setName(name); +Screen::Screen(const QString &name) + : m_Pixmap(QPixmap(":res/icons/64x64/video-display.png")), + m_Swapped(false) { + init(); + setName(name); } -void Screen::init() -{ - name().clear(); - aliases().clear(); - modifiers().clear(); - switchCorners().clear(); - fixes().clear(); - setSwitchCornerSize(0); +void Screen::init() { + name().clear(); + aliases().clear(); + modifiers().clear(); + switchCorners().clear(); + fixes().clear(); + setSwitchCornerSize(0); - // m_Modifiers, m_SwitchCorners and m_Fixes are QLists we use like fixed-size arrays, - // thus we need to make sure to fill them with the required number of elements. - for (int i = 0; i < NumModifiers; i++) - modifiers() << i; + // m_Modifiers, m_SwitchCorners and m_Fixes are QLists we use like fixed-size + // arrays, thus we need to make sure to fill them with the required number of + // elements. + for (int i = 0; i < NumModifiers; i++) + modifiers() << i; - for (int i = 0; i < NumSwitchCorners; i++) - switchCorners() << false; + for (int i = 0; i < NumSwitchCorners; i++) + switchCorners() << false; - for (int i = 0; i < NumFixes; i++) - fixes() << false; + for (int i = 0; i < NumFixes; i++) + fixes() << false; } -void Screen::loadSettings(QSettings& settings) -{ - setName(settings.value("name").toString()); +void Screen::loadSettings(QSettings &settings) { + setName(settings.value("name").toString()); - if (name().isEmpty()) - return; + if (name().isEmpty()) + return; - setSwitchCornerSize(settings.value("switchCornerSize").toInt()); + setSwitchCornerSize(settings.value("switchCornerSize").toInt()); - readSettings(settings, aliases(), "alias", QString("")); - readSettings(settings, modifiers(), "modifier", static_cast(DefaultMod), NumModifiers); - readSettings(settings, switchCorners(), "switchCorner", false, NumSwitchCorners); - readSettings(settings, fixes(), "fix", false, NumFixes); + readSettings(settings, aliases(), "alias", QString("")); + readSettings(settings, modifiers(), "modifier", static_cast(DefaultMod), + NumModifiers); + readSettings(settings, switchCorners(), "switchCorner", false, + NumSwitchCorners); + readSettings(settings, fixes(), "fix", false, NumFixes); } -void Screen::saveSettings(QSettings& settings) const -{ - settings.setValue("name", name()); +void Screen::saveSettings(QSettings &settings) const { + settings.setValue("name", name()); - if (name().isEmpty()) - return; + if (name().isEmpty()) + return; - settings.setValue("switchCornerSize", switchCornerSize()); + settings.setValue("switchCornerSize", switchCornerSize()); - writeSettings(settings, aliases(), "alias"); - writeSettings(settings, modifiers(), "modifier"); - writeSettings(settings, switchCorners(), "switchCorner"); - writeSettings(settings, fixes(), "fix"); + writeSettings(settings, aliases(), "alias"); + writeSettings(settings, modifiers(), "modifier"); + writeSettings(settings, switchCorners(), "switchCorner"); + writeSettings(settings, fixes(), "fix"); } -QTextStream& Screen::writeScreensSection(QTextStream& outStream) const -{ +QTextStream &Screen::writeScreensSection(QTextStream &outStream) const { + outStream << "\t" << name() << ":" << endl; + + for (int i = 0; i < modifiers().size(); i++) + if (modifier(i) != i) + outStream << "\t\t" << modifierName(i) << " = " + << modifierName(modifier(i)) << endl; + + for (int i = 0; i < fixes().size(); i++) + outStream << "\t\t" << fixName(i) << " = " + << (fixes()[i] ? "true" : "false") << endl; + + outStream << "\t\t" + << "switchCorners = none "; + for (int i = 0; i < switchCorners().size(); i++) + if (switchCorners()[i]) + outStream << "+" << switchCornerName(i) << " "; + outStream << endl; + + outStream << "\t\t" + << "switchCornerSize = " << switchCornerSize() << endl; + + return outStream; +} + +QTextStream &Screen::writeAliasesSection(QTextStream &outStream) const { + if (!aliases().isEmpty()) { outStream << "\t" << name() << ":" << endl; - for (int i = 0; i < modifiers().size(); i++) - if (modifier(i) != i) - outStream << "\t\t" << modifierName(i) << " = " << modifierName(modifier(i)) << endl; + foreach (const QString &alias, aliases()) + outStream << "\t\t" << alias << endl; + } - for (int i = 0; i < fixes().size(); i++) - outStream << "\t\t" << fixName(i) << " = " << (fixes()[i] ? "true" : "false") << endl; - - outStream << "\t\t" << "switchCorners = none "; - for (int i = 0; i < switchCorners().size(); i++) - if (switchCorners()[i]) - outStream << "+" << switchCornerName(i) << " "; - outStream << endl; - - outStream << "\t\t" << "switchCornerSize = " << switchCornerSize() << endl; - - return outStream; + return outStream; } -QTextStream& Screen::writeAliasesSection(QTextStream& outStream) const -{ - if (!aliases().isEmpty()) - { - outStream << "\t" << name() << ":" << endl; - - foreach (const QString& alias, aliases()) - outStream << "\t\t" << alias << endl; - } - - return outStream; +bool Screen::operator==(const Screen &screen) const { + return m_Name == screen.m_Name && m_Aliases == screen.m_Aliases && + m_Modifiers == screen.m_Modifiers && + m_SwitchCorners == screen.m_SwitchCorners && + m_SwitchCornerSize == screen.m_SwitchCornerSize && + m_Fixes == screen.m_Fixes && m_Swapped == screen.m_Swapped && + m_isServer == screen.m_isServer; } -bool Screen::operator==(const Screen& screen) const -{ - return m_Name == screen.m_Name && - m_Aliases == screen.m_Aliases && - m_Modifiers == screen.m_Modifiers && - m_SwitchCorners == screen.m_SwitchCorners && - m_SwitchCornerSize == screen.m_SwitchCornerSize && - m_Fixes == screen.m_Fixes && - m_Swapped == screen.m_Swapped && - m_isServer == screen.m_isServer; +QDataStream &operator<<(QDataStream &outStream, const Screen &screen) { + return outStream << screen.name() << screen.switchCornerSize() + << screen.aliases() << screen.modifiers() + << screen.switchCorners() << screen.fixes() + << screen.isServer(); } -QDataStream& operator<<(QDataStream& outStream, const Screen& screen) -{ - return outStream - << screen.name() - << screen.switchCornerSize() - << screen.aliases() - << screen.modifiers() - << screen.switchCorners() - << screen.fixes() - << screen.isServer() - ; -} - -QDataStream& operator>>(QDataStream& inStream, Screen& screen) -{ - return inStream - >> screen.m_Name - >> screen.m_SwitchCornerSize - >> screen.m_Aliases - >> screen.m_Modifiers - >> screen.m_SwitchCorners - >> screen.m_Fixes - >> screen.m_isServer - ; +QDataStream &operator>>(QDataStream &inStream, Screen &screen) { + return inStream >> screen.m_Name >> screen.m_SwitchCornerSize >> + screen.m_Aliases >> screen.m_Modifiers >> screen.m_SwitchCorners >> + screen.m_Fixes >> screen.m_isServer; } diff --git a/src/gui/src/Screen.h b/src/gui/src/Screen.h index 57c791e0c..f8a6221ca 100644 --- a/src/gui/src/Screen.h +++ b/src/gui/src/Screen.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2008 Volker Lanz (vl@fidra.de) - * + * * 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 LICENSE 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 @@ -20,9 +20,9 @@ #define SCREEN__H +#include #include #include -#include #include #include "BaseConfig.h" @@ -32,75 +32,75 @@ class QTextStream; class ScreenSettingsDialog; -class Screen : public BaseConfig -{ - friend QDataStream& operator<<(QDataStream& outStream, const Screen& screen); - friend QDataStream& operator>>(QDataStream& inStream, Screen& screen); - friend class ScreenSettingsDialog; - friend class ScreenSetupModel; - friend class ScreenSetupView; +class Screen : public BaseConfig { + friend QDataStream &operator<<(QDataStream &outStream, const Screen &screen); + friend QDataStream &operator>>(QDataStream &inStream, Screen &screen); + friend class ScreenSettingsDialog; + friend class ScreenSetupModel; + friend class ScreenSetupView; - public: - Screen(); - Screen(const QString& name); +public: + Screen(); + Screen(const QString &name); - public: - const QPixmap& pixmap() const { return m_Pixmap; } - const QString& name() const { return m_Name; } - const QStringList& aliases() const { return m_Aliases; } +public: + const QPixmap &pixmap() const { return m_Pixmap; } + const QString &name() const { return m_Name; } + const QStringList &aliases() const { return m_Aliases; } - bool isNull() const { return m_Name.isEmpty(); } - int modifier(int m) const { return m_Modifiers[m] == DefaultMod ? m : m_Modifiers[m]; } - const QList& modifiers() const { return m_Modifiers; } - bool switchCorner(int c) const { return m_SwitchCorners[c]; } - const QList& switchCorners() const { return m_SwitchCorners; } - int switchCornerSize() const { return m_SwitchCornerSize; } - bool fix(Fix f) const { return m_Fixes[f]; } - const QList& fixes() const { return m_Fixes; } + bool isNull() const { return m_Name.isEmpty(); } + int modifier(int m) const { + return m_Modifiers[m] == DefaultMod ? m : m_Modifiers[m]; + } + const QList &modifiers() const { return m_Modifiers; } + bool switchCorner(int c) const { return m_SwitchCorners[c]; } + const QList &switchCorners() const { return m_SwitchCorners; } + int switchCornerSize() const { return m_SwitchCornerSize; } + bool fix(Fix f) const { return m_Fixes[f]; } + const QList &fixes() const { return m_Fixes; } - void loadSettings(QSettings& settings); - void saveSettings(QSettings& settings) const; - QTextStream& writeScreensSection(QTextStream& outStream) const; - QTextStream& writeAliasesSection(QTextStream& outStream) const; + void loadSettings(QSettings &settings); + void saveSettings(QSettings &settings) const; + QTextStream &writeScreensSection(QTextStream &outStream) const; + QTextStream &writeAliasesSection(QTextStream &outStream) const; - bool swapped() const { return m_Swapped; } - QString& name() { return m_Name; } - void setName(const QString& name) { m_Name = name; } - bool isServer() const { return m_isServer;} - void markAsServer() { m_isServer = true; } + bool swapped() const { return m_Swapped; } + QString &name() { return m_Name; } + void setName(const QString &name) { m_Name = name; } + bool isServer() const { return m_isServer; } + void markAsServer() { m_isServer = true; } - bool operator==(const Screen& screen) const; + bool operator==(const Screen &screen) const; - protected: - void init(); +protected: + void init(); - QStringList& aliases() { return m_Aliases; } - void setModifier(int m, int n) { m_Modifiers[m] = n; } - QList& modifiers() { return m_Modifiers; } - void addAlias(const QString& alias) { m_Aliases.append(alias); } - void setSwitchCorner(int c, bool on) { m_SwitchCorners[c] = on; } - QList& switchCorners() { return m_SwitchCorners; } - void setSwitchCornerSize(int val) { m_SwitchCornerSize = val; } - void setFix(int f, bool on) { m_Fixes[f] = on; } - QList& fixes() { return m_Fixes; } - void setSwapped(bool on) { m_Swapped = on; } + QStringList &aliases() { return m_Aliases; } + void setModifier(int m, int n) { m_Modifiers[m] = n; } + QList &modifiers() { return m_Modifiers; } + void addAlias(const QString &alias) { m_Aliases.append(alias); } + void setSwitchCorner(int c, bool on) { m_SwitchCorners[c] = on; } + QList &switchCorners() { return m_SwitchCorners; } + void setSwitchCornerSize(int val) { m_SwitchCornerSize = val; } + void setFix(int f, bool on) { m_Fixes[f] = on; } + QList &fixes() { return m_Fixes; } + void setSwapped(bool on) { m_Swapped = on; } - private: - QPixmap m_Pixmap; - QString m_Name; +private: + QPixmap m_Pixmap; + QString m_Name; - QStringList m_Aliases; - QList m_Modifiers; - QList m_SwitchCorners; - int m_SwitchCornerSize; - QList m_Fixes; + QStringList m_Aliases; + QList m_Modifiers; + QList m_SwitchCorners; + int m_SwitchCornerSize; + QList m_Fixes; - bool m_Swapped; - bool m_isServer = false; + bool m_Swapped; + bool m_isServer = false; }; -QDataStream& operator<<(QDataStream& outStream, const Screen& screen); -QDataStream& operator>>(QDataStream& inStream, Screen& screen); +QDataStream &operator<<(QDataStream &outStream, const Screen &screen); +QDataStream &operator>>(QDataStream &inStream, Screen &screen); #endif - diff --git a/src/gui/src/ScreenList.cpp b/src/gui/src/ScreenList.cpp index 5ff2cfeca..e269c03a6 100644 --- a/src/gui/src/ScreenList.cpp +++ b/src/gui/src/ScreenList.cpp @@ -28,33 +28,42 @@ namespace { * @param size of the grid * @return indexes for server neighbors */ -std::array getNeighborsIndexes(int serverIndex, int width, int size) -{ - const int UNSET = -1; - const int LEFT = 0; - const int RIGHT = 1; - const int TOP = 2; - const int BOTTOM = 3; - const int TOP_LEFT = 4; - const int TOP_RIGHT = 5; - const int BOTTOM_RIGHT = 6; - const int BOTTOM_LEFT = 7; +std::array getNeighborsIndexes(int serverIndex, int width, int size) { + const int UNSET = -1; + const int LEFT = 0; + const int RIGHT = 1; + const int TOP = 2; + const int BOTTOM = 3; + const int TOP_LEFT = 4; + const int TOP_RIGHT = 5; + const int BOTTOM_RIGHT = 6; + const int BOTTOM_LEFT = 7; - std::array indexes = { UNSET }; + std::array indexes = {UNSET}; - if (serverIndex >= 0 && serverIndex < size) - { - indexes[LEFT] = (serverIndex - 1) % width != width - 1 ? (serverIndex - 1) : UNSET; - indexes[RIGHT] = (serverIndex + 1) % width != 0 ? (serverIndex + 1) : UNSET; - indexes[TOP] = (serverIndex - width) >= 0 ? (serverIndex - width) : UNSET; - indexes[BOTTOM] = (serverIndex + width) < size ? (serverIndex + width) : UNSET; - indexes[TOP_LEFT] = (indexes[TOP] != UNSET && indexes[LEFT] != UNSET) ? indexes[TOP] - 1 : UNSET; - indexes[TOP_RIGHT] = (indexes[TOP] != UNSET && indexes[RIGHT] != UNSET) ? indexes[TOP] + 1 : UNSET; - indexes[BOTTOM_RIGHT] = (indexes[BOTTOM] != UNSET && indexes[RIGHT] != UNSET) ? indexes[BOTTOM] + 1 : UNSET; - indexes[BOTTOM_LEFT] = (indexes[BOTTOM] != UNSET && indexes[LEFT] != UNSET) ? indexes[BOTTOM] - 1 : UNSET; - } + if (serverIndex >= 0 && serverIndex < size) { + indexes[LEFT] = + (serverIndex - 1) % width != width - 1 ? (serverIndex - 1) : UNSET; + indexes[RIGHT] = (serverIndex + 1) % width != 0 ? (serverIndex + 1) : UNSET; + indexes[TOP] = (serverIndex - width) >= 0 ? (serverIndex - width) : UNSET; + indexes[BOTTOM] = + (serverIndex + width) < size ? (serverIndex + width) : UNSET; + indexes[TOP_LEFT] = (indexes[TOP] != UNSET && indexes[LEFT] != UNSET) + ? indexes[TOP] - 1 + : UNSET; + indexes[TOP_RIGHT] = (indexes[TOP] != UNSET && indexes[RIGHT] != UNSET) + ? indexes[TOP] + 1 + : UNSET; + indexes[BOTTOM_RIGHT] = + (indexes[BOTTOM] != UNSET && indexes[RIGHT] != UNSET) + ? indexes[BOTTOM] + 1 + : UNSET; + indexes[BOTTOM_LEFT] = (indexes[BOTTOM] != UNSET && indexes[LEFT] != UNSET) + ? indexes[BOTTOM] - 1 + : UNSET; + } - return indexes; + return indexes; } /** @@ -62,71 +71,54 @@ std::array getNeighborsIndexes(int serverIndex, int width, int size) * @param screens list to find server * @return server index */ -int getServerIndex(const ScreenList& screens) -{ - int serverIndex = -1; +int getServerIndex(const ScreenList &screens) { + int serverIndex = -1; - for (int i = 0; i < screens.size(); ++i) - { - if (screens[i].isServer()){ - serverIndex = i; - break; - } + for (int i = 0; i < screens.size(); ++i) { + if (screens[i].isServer()) { + serverIndex = i; + break; } + } - return serverIndex; + return serverIndex; } -} //namespace +} // namespace -ScreenList::ScreenList(int width) : - QList(), - m_width(width) -{ +ScreenList::ScreenList(int width) : QList(), m_width(width) {} -} +void ScreenList::addScreenByPriority(const Screen &newScreen) { + int serverIndex = getServerIndex(*this); + auto indexes = getNeighborsIndexes(serverIndex, m_width, size()); -void ScreenList::addScreenByPriority(const Screen& newScreen) -{ - int serverIndex = getServerIndex(*this); - auto indexes = getNeighborsIndexes(serverIndex, m_width, size()); - - bool isAdded = false; - for (const auto& index : indexes) - { - if (index >= 0 && index < size()) - { - auto& screen = operator[](index); - if (screen.isNull()) - { - screen = newScreen; - isAdded = true; - break; - } - } + bool isAdded = false; + for (const auto &index : indexes) { + if (index >= 0 && index < size()) { + auto &screen = operator[](index); + if (screen.isNull()) { + screen = newScreen; + isAdded = true; + break; + } } + } - if (!isAdded) - { - addScreenToFirstEmpty(newScreen); + if (!isAdded) { + addScreenToFirstEmpty(newScreen); + } +} + +void ScreenList::addScreenToFirstEmpty(const Screen &newScreen) { + for (int i = 0; i < size(); ++i) { + auto &screen = operator[](i); + if (screen.isNull()) { + screen = newScreen; + break; } + } } -void ScreenList::addScreenToFirstEmpty(const Screen& newScreen) -{ - for (int i = 0; i < size(); ++i) - { - auto& screen = operator[](i); - if (screen.isNull()) - { - screen = newScreen; - break; - } - } +bool ScreenList::operator==(const ScreenList &sc) const { + return m_width == sc.m_width && QList::operator==(sc); } - -bool ScreenList::operator==(const ScreenList& sc) const -{ - return m_width == sc.m_width && QList::operator==(sc); -} - diff --git a/src/gui/src/ScreenList.h b/src/gui/src/ScreenList.h index 136ddfde0..f2c247b56 100644 --- a/src/gui/src/ScreenList.h +++ b/src/gui/src/ScreenList.h @@ -20,39 +20,36 @@ #include "Screen.h" -class ScreenList : public QList -{ - int m_width = 5; +class ScreenList : public QList { + int m_width = 5; public: - explicit ScreenList(int width = 5); + explicit ScreenList(int width = 5); - /** - * @brief addScreenByPriority adds a new screen according to the following priority: - * 1.left side of the server - * 2.right side of the server - * 3.top - * 4.down - * 5.top left-hand diagonally - * 6.top right-hand diagonally - * 7.bottom right-hand diagonally - * 8.bottom left-hand diagonally - * 9.In case all places from the list have already booked, place in any spare place - * @param newScreen - */ - void addScreenByPriority(const Screen& newScreen); + /** + * @brief addScreenByPriority adds a new screen according to the following + * priority: 1.left side of the server 2.right side of the server 3.top 4.down + * 5.top left-hand diagonally + * 6.top right-hand diagonally + * 7.bottom right-hand diagonally + * 8.bottom left-hand diagonally + * 9.In case all places from the list have already booked, place in any spare + * place + * @param newScreen + */ + void addScreenByPriority(const Screen &newScreen); - /** - * @brief addScreenToFirstEmpty adds screen into the first empty place - * @param newScreen - */ - void addScreenToFirstEmpty(const Screen& newScreen); + /** + * @brief addScreenToFirstEmpty adds screen into the first empty place + * @param newScreen + */ + void addScreenToFirstEmpty(const Screen &newScreen); - /** - * @brief Returns true if screens are equal - * @param sc - */ - bool operator==(const ScreenList& sc) const; + /** + * @brief Returns true if screens are equal + * @param sc + */ + bool operator==(const ScreenList &sc) const; }; #endif // SCREENLIST_H diff --git a/src/gui/src/ScreenSettingsDialog.cpp b/src/gui/src/ScreenSettingsDialog.cpp index ed4d31e26..0f91faabb 100644 --- a/src/gui/src/ScreenSettingsDialog.cpp +++ b/src/gui/src/ScreenSettingsDialog.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2008 Volker Lanz (vl@fidra.de) - * + * * 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 LICENSE 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 @@ -16,125 +16,127 @@ * along with this program. If not, see . */ -#include "validators/ScreenNameValidator.h" -#include "validators/AliasValidator.h" #include "ScreenSettingsDialog.h" #include "Screen.h" +#include "validators/AliasValidator.h" +#include "validators/ScreenNameValidator.h" +#include #include #include -#include -ScreenSettingsDialog::ScreenSettingsDialog(QWidget* parent, Screen* pScreen,const ScreenList* pScreens) : - QDialog(parent, Qt::WindowTitleHint | Qt::WindowSystemMenuHint), - Ui::ScreenSettingsDialogBase(), - m_pScreen(pScreen) -{ - setupUi(this); +ScreenSettingsDialog::ScreenSettingsDialog(QWidget *parent, Screen *pScreen, + const ScreenList *pScreens) + : QDialog(parent, Qt::WindowTitleHint | Qt::WindowSystemMenuHint), + Ui::ScreenSettingsDialogBase(), m_pScreen(pScreen) { + setupUi(this); - m_pLineEditName->setText(m_pScreen->name()); - m_pLineEditName->setValidator(new validators::ScreenNameValidator(m_pLineEditName, m_pLabelNameError, pScreens)); - m_pLineEditName->selectAll(); + m_pLineEditName->setText(m_pScreen->name()); + m_pLineEditName->setValidator(new validators::ScreenNameValidator( + m_pLineEditName, m_pLabelNameError, pScreens)); + m_pLineEditName->selectAll(); - m_pLineEditAlias->setValidator(new validators::AliasValidator(m_pLineEditAlias, m_pLabelAliasError)); + m_pLineEditAlias->setValidator( + new validators::AliasValidator(m_pLineEditAlias, m_pLabelAliasError)); - for (int i = 0; i < m_pScreen->aliases().count(); i++) - new QListWidgetItem(m_pScreen->aliases()[i], m_pListAliases); + for (int i = 0; i < m_pScreen->aliases().count(); i++) + new QListWidgetItem(m_pScreen->aliases()[i], m_pListAliases); - m_pComboBoxShift->setCurrentIndex(m_pScreen->modifier(Screen::Shift)); - m_pComboBoxCtrl->setCurrentIndex(m_pScreen->modifier(Screen::Ctrl)); - m_pComboBoxAlt->setCurrentIndex(m_pScreen->modifier(Screen::Alt)); - m_pComboBoxMeta->setCurrentIndex(m_pScreen->modifier(Screen::Meta)); - m_pComboBoxSuper->setCurrentIndex(m_pScreen->modifier(Screen::Super)); + m_pComboBoxShift->setCurrentIndex(m_pScreen->modifier(Screen::Shift)); + m_pComboBoxCtrl->setCurrentIndex(m_pScreen->modifier(Screen::Ctrl)); + m_pComboBoxAlt->setCurrentIndex(m_pScreen->modifier(Screen::Alt)); + m_pComboBoxMeta->setCurrentIndex(m_pScreen->modifier(Screen::Meta)); + m_pComboBoxSuper->setCurrentIndex(m_pScreen->modifier(Screen::Super)); - m_pCheckBoxCornerTopLeft->setChecked(m_pScreen->switchCorner(Screen::TopLeft)); - m_pCheckBoxCornerTopRight->setChecked(m_pScreen->switchCorner(Screen::TopRight)); - m_pCheckBoxCornerBottomLeft->setChecked(m_pScreen->switchCorner(Screen::BottomLeft)); - m_pCheckBoxCornerBottomRight->setChecked(m_pScreen->switchCorner(Screen::BottomRight)); - m_pSpinBoxSwitchCornerSize->setValue(m_pScreen->switchCornerSize()); + m_pCheckBoxCornerTopLeft->setChecked( + m_pScreen->switchCorner(Screen::TopLeft)); + m_pCheckBoxCornerTopRight->setChecked( + m_pScreen->switchCorner(Screen::TopRight)); + m_pCheckBoxCornerBottomLeft->setChecked( + m_pScreen->switchCorner(Screen::BottomLeft)); + m_pCheckBoxCornerBottomRight->setChecked( + m_pScreen->switchCorner(Screen::BottomRight)); + m_pSpinBoxSwitchCornerSize->setValue(m_pScreen->switchCornerSize()); - m_pCheckBoxCapsLock->setChecked(m_pScreen->fix(Screen::CapsLock)); - m_pCheckBoxNumLock->setChecked(m_pScreen->fix(Screen::NumLock)); - m_pCheckBoxScrollLock->setChecked(m_pScreen->fix(Screen::ScrollLock)); - m_pCheckBoxXTest->setChecked(m_pScreen->fix(Screen::XTest)); + m_pCheckBoxCapsLock->setChecked(m_pScreen->fix(Screen::CapsLock)); + m_pCheckBoxNumLock->setChecked(m_pScreen->fix(Screen::NumLock)); + m_pCheckBoxScrollLock->setChecked(m_pScreen->fix(Screen::ScrollLock)); + m_pCheckBoxXTest->setChecked(m_pScreen->fix(Screen::XTest)); } -void ScreenSettingsDialog::accept() -{ - if (m_pLineEditName->text().isEmpty()) - { - QMessageBox::warning( - this, tr("Screen name is empty"), - tr("The screen name cannot be empty. " - "Please either fill in a name or cancel the dialog.")); - return; - } - else if (!m_pLabelNameError->text().isEmpty()) { - return; +void ScreenSettingsDialog::accept() { + if (m_pLineEditName->text().isEmpty()) { + QMessageBox::warning( + this, tr("Screen name is empty"), + tr("The screen name cannot be empty. " + "Please either fill in a name or cancel the dialog.")); + return; + } else if (!m_pLabelNameError->text().isEmpty()) { + return; + } + + m_pScreen->init(); + + m_pScreen->setName(m_pLineEditName->text()); + + for (int i = 0; i < m_pListAliases->count(); i++) { + QString alias(m_pListAliases->item(i)->text()); + if (alias == m_pLineEditName->text()) { + QMessageBox::warning( + this, tr("Screen name matches alias"), + tr("The screen name cannot be the same as an alias. " + "Please either remove the alias or change the screen name.")); + return; } + m_pScreen->addAlias(alias); + } - m_pScreen->init(); + m_pScreen->setModifier(Screen::Shift, m_pComboBoxShift->currentIndex()); + m_pScreen->setModifier(Screen::Ctrl, m_pComboBoxCtrl->currentIndex()); + m_pScreen->setModifier(Screen::Alt, m_pComboBoxAlt->currentIndex()); + m_pScreen->setModifier(Screen::Meta, m_pComboBoxMeta->currentIndex()); + m_pScreen->setModifier(Screen::Super, m_pComboBoxSuper->currentIndex()); - m_pScreen->setName(m_pLineEditName->text()); + m_pScreen->setSwitchCorner(Screen::TopLeft, + m_pCheckBoxCornerTopLeft->isChecked()); + m_pScreen->setSwitchCorner(Screen::TopRight, + m_pCheckBoxCornerTopRight->isChecked()); + m_pScreen->setSwitchCorner(Screen::BottomLeft, + m_pCheckBoxCornerBottomLeft->isChecked()); + m_pScreen->setSwitchCorner(Screen::BottomRight, + m_pCheckBoxCornerBottomRight->isChecked()); + m_pScreen->setSwitchCornerSize(m_pSpinBoxSwitchCornerSize->value()); - for (int i = 0; i < m_pListAliases->count(); i++) - { - QString alias(m_pListAliases->item(i)->text()); - if (alias == m_pLineEditName->text()) - { - QMessageBox::warning( - this, tr("Screen name matches alias"), - tr("The screen name cannot be the same as an alias. " - "Please either remove the alias or change the screen name.")); - return; - } - m_pScreen->addAlias(alias); - } + m_pScreen->setFix(Screen::CapsLock, m_pCheckBoxCapsLock->isChecked()); + m_pScreen->setFix(Screen::NumLock, m_pCheckBoxNumLock->isChecked()); + m_pScreen->setFix(Screen::ScrollLock, m_pCheckBoxScrollLock->isChecked()); + m_pScreen->setFix(Screen::XTest, m_pCheckBoxXTest->isChecked()); - m_pScreen->setModifier(Screen::Shift, m_pComboBoxShift->currentIndex()); - m_pScreen->setModifier(Screen::Ctrl, m_pComboBoxCtrl->currentIndex()); - m_pScreen->setModifier(Screen::Alt, m_pComboBoxAlt->currentIndex()); - m_pScreen->setModifier(Screen::Meta, m_pComboBoxMeta->currentIndex()); - m_pScreen->setModifier(Screen::Super, m_pComboBoxSuper->currentIndex()); - - m_pScreen->setSwitchCorner(Screen::TopLeft, m_pCheckBoxCornerTopLeft->isChecked()); - m_pScreen->setSwitchCorner(Screen::TopRight, m_pCheckBoxCornerTopRight->isChecked()); - m_pScreen->setSwitchCorner(Screen::BottomLeft, m_pCheckBoxCornerBottomLeft->isChecked()); - m_pScreen->setSwitchCorner(Screen::BottomRight, m_pCheckBoxCornerBottomRight->isChecked()); - m_pScreen->setSwitchCornerSize(m_pSpinBoxSwitchCornerSize->value()); - - m_pScreen->setFix(Screen::CapsLock, m_pCheckBoxCapsLock->isChecked()); - m_pScreen->setFix(Screen::NumLock, m_pCheckBoxNumLock->isChecked()); - m_pScreen->setFix(Screen::ScrollLock, m_pCheckBoxScrollLock->isChecked()); - m_pScreen->setFix(Screen::XTest, m_pCheckBoxXTest->isChecked()); - - QDialog::accept(); + QDialog::accept(); } -void ScreenSettingsDialog::on_m_pButtonAddAlias_clicked() -{ - if (!m_pLineEditAlias->text().isEmpty() && m_pListAliases->findItems(m_pLineEditAlias->text(), Qt::MatchFixedString).isEmpty()) - { - new QListWidgetItem(m_pLineEditAlias->text(), m_pListAliases); - m_pLineEditAlias->clear(); - } +void ScreenSettingsDialog::on_m_pButtonAddAlias_clicked() { + if (!m_pLineEditAlias->text().isEmpty() && + m_pListAliases->findItems(m_pLineEditAlias->text(), Qt::MatchFixedString) + .isEmpty()) { + new QListWidgetItem(m_pLineEditAlias->text(), m_pListAliases); + m_pLineEditAlias->clear(); + } } -void ScreenSettingsDialog::on_m_pLineEditAlias_textChanged(const QString& text) -{ - m_pButtonAddAlias->setEnabled(!text.isEmpty() && m_pLabelAliasError->text().isEmpty()); +void ScreenSettingsDialog::on_m_pLineEditAlias_textChanged( + const QString &text) { + m_pButtonAddAlias->setEnabled(!text.isEmpty() && + m_pLabelAliasError->text().isEmpty()); } -void ScreenSettingsDialog::on_m_pButtonRemoveAlias_clicked() -{ - QList items = m_pListAliases->selectedItems(); +void ScreenSettingsDialog::on_m_pButtonRemoveAlias_clicked() { + QList items = m_pListAliases->selectedItems(); - for (int i = 0; i < items.count(); i++) - delete items[i]; + for (int i = 0; i < items.count(); i++) + delete items[i]; } -void ScreenSettingsDialog::on_m_pListAliases_itemSelectionChanged() -{ - m_pButtonRemoveAlias->setEnabled(!m_pListAliases->selectedItems().isEmpty()); +void ScreenSettingsDialog::on_m_pListAliases_itemSelectionChanged() { + m_pButtonRemoveAlias->setEnabled(!m_pListAliases->selectedItems().isEmpty()); } - diff --git a/src/gui/src/ScreenSettingsDialog.h b/src/gui/src/ScreenSettingsDialog.h index 97232bde5..781cefb75 100644 --- a/src/gui/src/ScreenSettingsDialog.h +++ b/src/gui/src/ScreenSettingsDialog.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2008 Volker Lanz (vl@fidra.de) - * + * * 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 LICENSE 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 @@ -31,26 +31,25 @@ class QString; class Screen; class ScreenList; -class ScreenSettingsDialog : public QDialog, public Ui::ScreenSettingsDialogBase -{ - Q_OBJECT +class ScreenSettingsDialog : public QDialog, + public Ui::ScreenSettingsDialogBase { + Q_OBJECT - public: - ScreenSettingsDialog(QWidget* parent, Screen* pScreen = nullptr, const ScreenList* pScreens = nullptr); +public: + ScreenSettingsDialog(QWidget *parent, Screen *pScreen = nullptr, + const ScreenList *pScreens = nullptr); - public slots: - void accept(); +public slots: + void accept(); - private slots: - void on_m_pButtonAddAlias_clicked(); - void on_m_pButtonRemoveAlias_clicked(); - void on_m_pLineEditAlias_textChanged(const QString& text); - void on_m_pListAliases_itemSelectionChanged(); - - private: - Screen* m_pScreen; +private slots: + void on_m_pButtonAddAlias_clicked(); + void on_m_pButtonRemoveAlias_clicked(); + void on_m_pLineEditAlias_textChanged(const QString &text); + void on_m_pListAliases_itemSelectionChanged(); +private: + Screen *m_pScreen; }; #endif - diff --git a/src/gui/src/ScreenSetupModel.cpp b/src/gui/src/ScreenSetupModel.cpp index 3c64b98d5..80bee72df 100644 --- a/src/gui/src/ScreenSetupModel.cpp +++ b/src/gui/src/ScreenSetupModel.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2008 Volker Lanz (vl@fidra.de) - * + * * 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 LICENSE 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 @@ -24,136 +24,130 @@ const QString ScreenSetupModel::m_MimeType = "application/x-qsynergy-screen"; -ScreenSetupModel::ScreenSetupModel(ScreenList& screens, int numColumns, int numRows) : - QAbstractTableModel(NULL), - m_Screens(screens), - m_NumColumns(numColumns), - m_NumRows(numRows) -{ - if (m_NumColumns * m_NumRows > screens.size()) - qFatal("Not enough elements (%u) in screens QList for %d columns and %d rows", screens.size(), m_NumColumns, m_NumRows); +ScreenSetupModel::ScreenSetupModel(ScreenList &screens, int numColumns, + int numRows) + : QAbstractTableModel(NULL), m_Screens(screens), m_NumColumns(numColumns), + m_NumRows(numRows) { + if (m_NumColumns * m_NumRows > screens.size()) + qFatal( + "Not enough elements (%u) in screens QList for %d columns and %d rows", + screens.size(), m_NumColumns, m_NumRows); } -QVariant ScreenSetupModel::data(const QModelIndex& index, int role) const -{ - if (index.isValid() && index.row() < m_NumRows && index.column() < m_NumColumns) - { - switch(role) - { - case Qt::DecorationRole: - if (screen(index).isNull()) - break; - return QIcon(screen(index).pixmap()); +QVariant ScreenSetupModel::data(const QModelIndex &index, int role) const { + if (index.isValid() && index.row() < m_NumRows && + index.column() < m_NumColumns) { + switch (role) { + case Qt::DecorationRole: + if (screen(index).isNull()) + break; + return QIcon(screen(index).pixmap()); - case Qt::ToolTipRole: - if (screen(index).isNull()) - break; - return QString(tr( - "
Screen: %1
" - "
Double click to edit settings" - "
Drag screen to the trashcan to remove it")).arg(screen(index).name()); + case Qt::ToolTipRole: + if (screen(index).isNull()) + break; + return QString(tr("
Screen: %1
" + "
Double click to edit settings" + "
Drag screen to the trashcan to remove it")) + .arg(screen(index).name()); - case Qt::DisplayRole: - if (screen(index).isNull()) - break; - return screen(index).name(); - } + case Qt::DisplayRole: + if (screen(index).isNull()) + break; + return screen(index).name(); } + } - return QVariant(); + return QVariant(); } -Qt::ItemFlags ScreenSetupModel::flags(const QModelIndex& index) const -{ - if (!index.isValid() || index.row() >= m_NumRows || index.column() >= m_NumColumns) - return 0; +Qt::ItemFlags ScreenSetupModel::flags(const QModelIndex &index) const { + if (!index.isValid() || index.row() >= m_NumRows || + index.column() >= m_NumColumns) + return 0; - if (!screen(index).isNull()) - return Qt::ItemIsEnabled | Qt::ItemIsDragEnabled | Qt::ItemIsSelectable | Qt::ItemIsDropEnabled; + if (!screen(index).isNull()) + return Qt::ItemIsEnabled | Qt::ItemIsDragEnabled | Qt::ItemIsSelectable | + Qt::ItemIsDropEnabled; - return Qt::ItemIsDropEnabled; + return Qt::ItemIsDropEnabled; } -Qt::DropActions ScreenSetupModel::supportedDropActions() const -{ - return Qt::MoveAction | Qt::CopyAction; +Qt::DropActions ScreenSetupModel::supportedDropActions() const { + return Qt::MoveAction | Qt::CopyAction; } -QStringList ScreenSetupModel::mimeTypes() const -{ - return QStringList() << m_MimeType; +QStringList ScreenSetupModel::mimeTypes() const { + return QStringList() << m_MimeType; } -QMimeData* ScreenSetupModel::mimeData(const QModelIndexList& indexes) const -{ - QMimeData* pMimeData = new QMimeData(); - QByteArray encodedData; +QMimeData *ScreenSetupModel::mimeData(const QModelIndexList &indexes) const { + QMimeData *pMimeData = new QMimeData(); + QByteArray encodedData; - QDataStream stream(&encodedData, QIODevice::WriteOnly); + QDataStream stream(&encodedData, QIODevice::WriteOnly); - foreach (const QModelIndex& index, indexes) - if (index.isValid()) - stream << index.column() << index.row() << screen(index); + foreach (const QModelIndex &index, indexes) + if (index.isValid()) + stream << index.column() << index.row() << screen(index); - pMimeData->setData(m_MimeType, encodedData); + pMimeData->setData(m_MimeType, encodedData); - return pMimeData; + return pMimeData; } -bool ScreenSetupModel::dropMimeData(const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent) -{ - if (action == Qt::IgnoreAction) - return true; - - if (!data->hasFormat(m_MimeType)) - return false; - - if (!parent.isValid() || row != -1 || column != -1) - return false; - - QByteArray encodedData = data->data(m_MimeType); - QDataStream stream(&encodedData, QIODevice::ReadOnly); - - int sourceColumn = -1; - int sourceRow = -1; - - stream >> sourceColumn; - stream >> sourceRow; - - // don't drop screen onto itself - if (sourceColumn == parent.column() && sourceRow == parent.row()) - return false; - - Screen droppedScreen; - stream >> droppedScreen; - - Screen oldScreen = screen(parent.column(), parent.row()); - if (!oldScreen.isNull() && sourceColumn != -1 && sourceRow != -1) - { - // mark the screen so it isn't deleted after the dragndrop succeeded - // see ScreenSetupView::startDrag() - oldScreen.setSwapped(true); - screen(sourceColumn, sourceRow) = oldScreen; - } - - screen(parent.column(), parent.row()) = droppedScreen; - - emit screensChanged(); - +bool ScreenSetupModel::dropMimeData(const QMimeData *data, + Qt::DropAction action, int row, int column, + const QModelIndex &parent) { + if (action == Qt::IgnoreAction) return true; + + if (!data->hasFormat(m_MimeType)) + return false; + + if (!parent.isValid() || row != -1 || column != -1) + return false; + + QByteArray encodedData = data->data(m_MimeType); + QDataStream stream(&encodedData, QIODevice::ReadOnly); + + int sourceColumn = -1; + int sourceRow = -1; + + stream >> sourceColumn; + stream >> sourceRow; + + // don't drop screen onto itself + if (sourceColumn == parent.column() && sourceRow == parent.row()) + return false; + + Screen droppedScreen; + stream >> droppedScreen; + + Screen oldScreen = screen(parent.column(), parent.row()); + if (!oldScreen.isNull() && sourceColumn != -1 && sourceRow != -1) { + // mark the screen so it isn't deleted after the dragndrop succeeded + // see ScreenSetupView::startDrag() + oldScreen.setSwapped(true); + screen(sourceColumn, sourceRow) = oldScreen; + } + + screen(parent.column(), parent.row()) = droppedScreen; + + emit screensChanged(); + + return true; } -void ScreenSetupModel::addScreen(const Screen& newScreen) -{ - m_Screens.addScreenByPriority(newScreen); - emit screensChanged(); +void ScreenSetupModel::addScreen(const Screen &newScreen) { + m_Screens.addScreenByPriority(newScreen); + emit screensChanged(); } -bool ScreenSetupModel::isFull() const -{ - auto emptyScreen = std::find_if(m_Screens.cbegin(), m_Screens.cend(), - [](const Screen& item) { return item.isNull(); }); +bool ScreenSetupModel::isFull() const { + auto emptyScreen = + std::find_if(m_Screens.cbegin(), m_Screens.cend(), + [](const Screen &item) { return item.isNull(); }); - return (emptyScreen == m_Screens.cend()); + return (emptyScreen == m_Screens.cend()); } - diff --git a/src/gui/src/ScreenSetupModel.h b/src/gui/src/ScreenSetupModel.h index 2891679d7..2445698be 100644 --- a/src/gui/src/ScreenSetupModel.h +++ b/src/gui/src/ScreenSetupModel.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2008 Volker Lanz (vl@fidra.de) - * + * * 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 LICENSE 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 @@ -30,48 +30,54 @@ class ScreenSetupView; class ServerConfigDialog; -class ScreenSetupModel : public QAbstractTableModel -{ - Q_OBJECT +class ScreenSetupModel : public QAbstractTableModel { + Q_OBJECT - friend class ScreenSetupView; - friend class ServerConfigDialog; + friend class ScreenSetupView; + friend class ServerConfigDialog; - public: - ScreenSetupModel(ScreenList& screens, int numColumns, int numRows); +public: + ScreenSetupModel(ScreenList &screens, int numColumns, int numRows); - public: - static const QString& mimeType() { return m_MimeType; } - QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const; - int rowCount() const { return m_NumRows; } - int columnCount() const { return m_NumColumns; } - int rowCount(const QModelIndex&) const { return rowCount(); } - int columnCount(const QModelIndex&) const { return columnCount(); } - Qt::DropActions supportedDropActions() const; - Qt::ItemFlags flags(const QModelIndex& index) const; - QStringList mimeTypes() const; - QMimeData* mimeData(const QModelIndexList& indexes) const; - bool isFull() const; +public: + static const QString &mimeType() { return m_MimeType; } + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; + int rowCount() const { return m_NumRows; } + int columnCount() const { return m_NumColumns; } + int rowCount(const QModelIndex &) const { return rowCount(); } + int columnCount(const QModelIndex &) const { return columnCount(); } + Qt::DropActions supportedDropActions() const; + Qt::ItemFlags flags(const QModelIndex &index) const; + QStringList mimeTypes() const; + QMimeData *mimeData(const QModelIndexList &indexes) const; + bool isFull() const; - signals: - void screensChanged(); +signals: + void screensChanged(); +protected: + bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, + int column, const QModelIndex &parent); + const Screen &screen(const QModelIndex &index) const { + return screen(index.column(), index.row()); + } + Screen &screen(const QModelIndex &index) { + return screen(index.column(), index.row()); + } + const Screen &screen(int column, int row) const { + return m_Screens[row * m_NumColumns + column]; + } + Screen &screen(int column, int row) { + return m_Screens[row * m_NumColumns + column]; + } + void addScreen(const Screen &newScreen); - protected: - bool dropMimeData(const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent); - const Screen& screen(const QModelIndex& index) const { return screen(index.column(), index.row()); } - Screen& screen(const QModelIndex& index) { return screen(index.column(), index.row()); } - const Screen& screen(int column, int row) const { return m_Screens[row * m_NumColumns + column]; } - Screen& screen(int column, int row) { return m_Screens[row * m_NumColumns + column]; } - void addScreen(const Screen& newScreen); +private: + ScreenList &m_Screens; + const int m_NumColumns; + const int m_NumRows; - private: - ScreenList& m_Screens; - const int m_NumColumns; - const int m_NumRows; - - static const QString m_MimeType; + static const QString m_MimeType; }; #endif - diff --git a/src/gui/src/ScreenSetupView.cpp b/src/gui/src/ScreenSetupView.cpp index 8bbb020ee..0a01949fa 100644 --- a/src/gui/src/ScreenSetupView.cpp +++ b/src/gui/src/ScreenSetupView.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2008 Volker Lanz (vl@fidra.de) - * + * * 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 LICENSE 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 @@ -17,149 +17,129 @@ */ #include "ScreenSetupView.h" -#include "ScreenSetupModel.h" #include "ScreenSettingsDialog.h" +#include "ScreenSetupModel.h" +#include #include #include -#include -ScreenSetupView::ScreenSetupView(QWidget* parent) : - QTableView(parent) -{ - setDropIndicatorShown(true); - setDragDropMode(DragDrop); - setSelectionMode(SingleSelection); +ScreenSetupView::ScreenSetupView(QWidget *parent) : QTableView(parent) { + setDropIndicatorShown(true); + setDragDropMode(DragDrop); + setSelectionMode(SingleSelection); - setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - setIconSize(QSize(64, 64)); - horizontalHeader()->hide(); - verticalHeader()->hide(); + setIconSize(QSize(64, 64)); + horizontalHeader()->hide(); + verticalHeader()->hide(); } -void ScreenSetupView::setModel(QAbstractItemModel* model) -{ - QTableView::setModel(model); - setTableSize(); +void ScreenSetupView::setModel(QAbstractItemModel *model) { + QTableView::setModel(model); + setTableSize(); } -ScreenSetupModel* ScreenSetupView::model() const -{ - return qobject_cast(QTableView::model()); +ScreenSetupModel *ScreenSetupView::model() const { + return qobject_cast(QTableView::model()); } -void ScreenSetupView::setTableSize() -{ - for (int i = 0; i < model()->columnCount(); i++) - setColumnWidth(i, width() / model()->columnCount()); +void ScreenSetupView::setTableSize() { + for (int i = 0; i < model()->columnCount(); i++) + setColumnWidth(i, width() / model()->columnCount()); - for (int i = 0; i < model()->rowCount(); i++) - setRowHeight(i, height() / model()->rowCount()); + for (int i = 0; i < model()->rowCount(); i++) + setRowHeight(i, height() / model()->rowCount()); } -void ScreenSetupView::resizeEvent(QResizeEvent* event) -{ - setTableSize(); +void ScreenSetupView::resizeEvent(QResizeEvent *event) { + setTableSize(); + event->ignore(); +} + +void ScreenSetupView::mouseDoubleClickEvent(QMouseEvent *event) { + if (event->buttons() & Qt::LeftButton) { + int col = columnAt(event->pos().x()); + int row = rowAt(event->pos().y()); + + if (!model()->screen(col, row).isNull()) { + ScreenSettingsDialog dlg(this, &model()->screen(col, row), + &model()->m_Screens); + dlg.exec(); + emit model() -> screensChanged(); + } + } else event->ignore(); } -void ScreenSetupView::mouseDoubleClickEvent(QMouseEvent* event) -{ - if (event->buttons() & Qt::LeftButton) - { - int col = columnAt(event->pos().x()); - int row = rowAt(event->pos().y()); - - if (!model()->screen(col, row).isNull()) - { - ScreenSettingsDialog dlg(this, &model()->screen(col, row), &model()->m_Screens); - dlg.exec(); - emit model()->screensChanged(); - } - } - else - event->ignore(); +void ScreenSetupView::dragEnterEvent(QDragEnterEvent *event) { + // we accept anything that enters us by a drag as long as the + // mime type is okay. anything else is dealt with in dragMoveEvent() + if (event->mimeData()->hasFormat(ScreenSetupModel::mimeType())) + event->accept(); + else + event->ignore(); } -void ScreenSetupView::dragEnterEvent(QDragEnterEvent* event) -{ - // we accept anything that enters us by a drag as long as the - // mime type is okay. anything else is dealt with in dragMoveEvent() - if (event->mimeData()->hasFormat(ScreenSetupModel::mimeType())) - event->accept(); - else +void ScreenSetupView::dragMoveEvent(QDragMoveEvent *event) { + if (event->mimeData()->hasFormat(ScreenSetupModel::mimeType())) { + // where does the event come from? myself or someone else? + if (event->source() == this) { + // myself is ok, but then it must be a move action, never a copy + event->setDropAction(Qt::MoveAction); + event->accept(); + } else { + int col = columnAt(event->pos().x()); + int row = rowAt(event->pos().y()); + + // a drop from outside is not allowed if there's a screen already there. + if (!model()->screen(col, row).isNull()) event->ignore(); -} - -void ScreenSetupView::dragMoveEvent(QDragMoveEvent* event) -{ - if (event->mimeData()->hasFormat(ScreenSetupModel::mimeType())) - { - // where does the event come from? myself or someone else? - if (event->source() == this) - { - // myself is ok, but then it must be a move action, never a copy - event->setDropAction(Qt::MoveAction); - event->accept(); - } - else - { - int col = columnAt(event->pos().x()); - int row = rowAt(event->pos().y()); - - // a drop from outside is not allowed if there's a screen already there. - if (!model()->screen(col, row).isNull()) - event->ignore(); - else - event->acceptProposedAction(); - } + else + event->acceptProposedAction(); } - else - event->ignore(); + } else + event->ignore(); } // this is reimplemented from QAbstractItemView::startDrag() -void ScreenSetupView::startDrag(Qt::DropActions) -{ - QModelIndexList indexes = selectedIndexes(); +void ScreenSetupView::startDrag(Qt::DropActions) { + QModelIndexList indexes = selectedIndexes(); - if (indexes.count() != 1) - return; + if (indexes.count() != 1) + return; - QMimeData* pData = model()->mimeData(indexes); - if (pData == NULL) - return; + QMimeData *pData = model()->mimeData(indexes); + if (pData == NULL) + return; - const QPixmap& pixmap = model()->screen(indexes[0]).pixmap(); - QDrag* pDrag = new QDrag(this); - pDrag->setPixmap(pixmap); - pDrag->setMimeData(pData); - pDrag->setHotSpot(QPoint(pixmap.width() / 2, pixmap.height() / 2)); + const QPixmap &pixmap = model()->screen(indexes[0]).pixmap(); + QDrag *pDrag = new QDrag(this); + pDrag->setPixmap(pixmap); + pDrag->setMimeData(pData); + pDrag->setHotSpot(QPoint(pixmap.width() / 2, pixmap.height() / 2)); - if (pDrag->exec(Qt::MoveAction, Qt::MoveAction) == Qt::MoveAction) - { - selectionModel()->clear(); + if (pDrag->exec(Qt::MoveAction, Qt::MoveAction) == Qt::MoveAction) { + selectionModel()->clear(); - // make sure to only delete the drag source if screens weren't swapped - // see ScreenSetupModel::dropMimeData - if (!model()->screen(indexes[0]).swapped()) - model()->screen(indexes[0]) = Screen(); - else - model()->screen(indexes[0]).setSwapped(false); + // make sure to only delete the drag source if screens weren't swapped + // see ScreenSetupModel::dropMimeData + if (!model()->screen(indexes[0]).swapped()) + model()->screen(indexes[0]) = Screen(); + else + model()->screen(indexes[0]).setSwapped(false); - emit model()->screensChanged(); - } + emit model() -> screensChanged(); + } } -QStyleOptionViewItem ScreenSetupView::viewOptions() const -{ - QStyleOptionViewItem option = QTableView::viewOptions(); - option.showDecorationSelected = true; - option.decorationPosition = QStyleOptionViewItem::Top; - option.displayAlignment = Qt::AlignCenter; - option.textElideMode = Qt::ElideMiddle; - return option; +QStyleOptionViewItem ScreenSetupView::viewOptions() const { + QStyleOptionViewItem option = QTableView::viewOptions(); + option.showDecorationSelected = true; + option.decorationPosition = QStyleOptionViewItem::Top; + option.displayAlignment = Qt::AlignCenter; + option.textElideMode = Qt::ElideMiddle; + return option; } - diff --git a/src/gui/src/ScreenSetupView.h b/src/gui/src/ScreenSetupView.h index 865a6c558..1b0132838 100644 --- a/src/gui/src/ScreenSetupView.h +++ b/src/gui/src/ScreenSetupView.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2008 Volker Lanz (vl@fidra.de) - * + * * 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 LICENSE 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 @@ -20,8 +20,8 @@ #define SCREENSETUPVIEW__H -#include #include +#include #include "Screen.h" @@ -31,27 +31,25 @@ class QResizeEvent; class QDragEnterEvent; class ScreenSetupModel; -class ScreenSetupView : public QTableView -{ - Q_OBJECT +class ScreenSetupView : public QTableView { + Q_OBJECT - public: - ScreenSetupView(QWidget* parent); +public: + ScreenSetupView(QWidget *parent); - public: - void setModel(QAbstractItemModel* model) override; - ScreenSetupModel* model() const; +public: + void setModel(QAbstractItemModel *model) override; + ScreenSetupModel *model() const; - protected: - void mouseDoubleClickEvent(QMouseEvent*) override; - void setTableSize(); - void resizeEvent(QResizeEvent*) override; - void dragEnterEvent(QDragEnterEvent* event) override; - void dragMoveEvent(QDragMoveEvent* event) override; - void startDrag(Qt::DropActions supportedActions) override; - QStyleOptionViewItem viewOptions() const override; - void scrollTo(const QModelIndex&, ScrollHint) override {} +protected: + void mouseDoubleClickEvent(QMouseEvent *) override; + void setTableSize(); + void resizeEvent(QResizeEvent *) override; + void dragEnterEvent(QDragEnterEvent *event) override; + void dragMoveEvent(QDragMoveEvent *event) override; + void startDrag(Qt::DropActions supportedActions) override; + QStyleOptionViewItem viewOptions() const override; + void scrollTo(const QModelIndex &, ScrollHint) override {} }; #endif - diff --git a/src/gui/src/ServerConfig.cpp b/src/gui/src/ServerConfig.cpp index e2491ecbd..6db533534 100644 --- a/src/gui/src/ServerConfig.cpp +++ b/src/gui/src/ServerConfig.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2008 Volker Lanz (vl@fidra.de) - * + * * 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 LICENSE 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 @@ -17,578 +17,558 @@ */ #include "ServerConfig.h" +#include "AddClientDialog.h" #include "Hotkey.h" #include "MainWindow.h" -#include "AddClientDialog.h" -#include -#include #include +#include #include +#include -static const struct -{ - int x; - int y; - const char* name; -} neighbourDirs[] = -{ - { 1, 0, "right" }, - { -1, 0, "left" }, - { 0, -1, "up" }, - { 0, 1, "down" }, +static const struct { + int x; + int y; + const char *name; +} neighbourDirs[] = { + {1, 0, "right"}, + {-1, 0, "left"}, + {0, -1, "up"}, + {0, 1, "down"}, }; const int serverDefaultIndex = 7; -ServerConfig::ServerConfig(int numColumns, int numRows, AppConfig* appConfig, MainWindow* mainWindow) : +ServerConfig::ServerConfig(int numColumns, int numRows, AppConfig *appConfig, + MainWindow *mainWindow) + : - m_Screens(numColumns), - m_NumColumns(numColumns), - m_NumRows(numRows), - m_pAppConfig(appConfig), - m_IgnoreAutoConfigClient(false), - m_EnableDragAndDrop(false), - m_DisableLockToScreen(false), - m_ClipboardSharing(true), - m_ClipboardSharingSize(defaultClipboardSharingSize()), - m_pMainWindow(mainWindow) -{ - GUI::Config::ConfigWriter::make()->registerClass(this); - ServerConfig::loadSettings(); + m_Screens(numColumns), m_NumColumns(numColumns), m_NumRows(numRows), + m_pAppConfig(appConfig), m_IgnoreAutoConfigClient(false), + m_EnableDragAndDrop(false), m_DisableLockToScreen(false), + m_ClipboardSharing(true), + m_ClipboardSharingSize(defaultClipboardSharingSize()), + m_pMainWindow(mainWindow) { + GUI::Config::ConfigWriter::make()->registerClass(this); + ServerConfig::loadSettings(); } -ServerConfig::~ServerConfig() -{ - try { - ServerConfig::saveSettings(); - } catch (const std::exception& e) { - m_pMainWindow->appendLogError(e.what()); - } +ServerConfig::~ServerConfig() { + try { + ServerConfig::saveSettings(); + } catch (const std::exception &e) { + m_pMainWindow->appendLogError(e.what()); + } } -bool ServerConfig::save(const QString& fileName) const -{ - QFile file(fileName); - if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) - return false; +bool ServerConfig::save(const QString &fileName) const { + QFile file(fileName); + if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) + return false; - save(file); - file.close(); + save(file); + file.close(); - return true; + return true; } -bool ServerConfig::operator==(const ServerConfig& sc) const -{ - return m_Screens == sc.m_Screens && - m_NumColumns == sc.m_NumColumns && - m_NumRows == sc.m_NumRows && - m_HasHeartbeat == sc.m_HasHeartbeat && - m_Heartbeat == sc.m_Heartbeat && - m_RelativeMouseMoves == sc.m_RelativeMouseMoves && - m_Win32KeepForeground == sc.m_Win32KeepForeground && - m_HasSwitchDelay == sc.m_HasSwitchDelay && - m_SwitchDelay == sc.m_SwitchDelay && - m_HasSwitchDoubleTap == sc.m_HasSwitchDoubleTap && - m_SwitchDoubleTap == sc.m_SwitchDoubleTap && - m_SwitchCornerSize == sc.m_SwitchCornerSize && - m_SwitchCorners == sc.m_SwitchCorners && - m_Hotkeys == sc.m_Hotkeys && - m_pAppConfig == sc.m_pAppConfig && - m_IgnoreAutoConfigClient == sc.m_IgnoreAutoConfigClient && - m_EnableDragAndDrop == sc.m_EnableDragAndDrop && - m_DisableLockToScreen == sc.m_DisableLockToScreen && - m_ClipboardSharing == sc.m_ClipboardSharing && - m_ClipboardSharingSize == sc.m_ClipboardSharingSize && - m_pMainWindow == sc.m_pMainWindow; +bool ServerConfig::operator==(const ServerConfig &sc) const { + return m_Screens == sc.m_Screens && m_NumColumns == sc.m_NumColumns && + m_NumRows == sc.m_NumRows && m_HasHeartbeat == sc.m_HasHeartbeat && + m_Heartbeat == sc.m_Heartbeat && + m_RelativeMouseMoves == sc.m_RelativeMouseMoves && + m_Win32KeepForeground == sc.m_Win32KeepForeground && + m_HasSwitchDelay == sc.m_HasSwitchDelay && + m_SwitchDelay == sc.m_SwitchDelay && + m_HasSwitchDoubleTap == sc.m_HasSwitchDoubleTap && + m_SwitchDoubleTap == sc.m_SwitchDoubleTap && + m_SwitchCornerSize == sc.m_SwitchCornerSize && + m_SwitchCorners == sc.m_SwitchCorners && m_Hotkeys == sc.m_Hotkeys && + m_pAppConfig == sc.m_pAppConfig && + m_IgnoreAutoConfigClient == sc.m_IgnoreAutoConfigClient && + m_EnableDragAndDrop == sc.m_EnableDragAndDrop && + m_DisableLockToScreen == sc.m_DisableLockToScreen && + m_ClipboardSharing == sc.m_ClipboardSharing && + m_ClipboardSharingSize == sc.m_ClipboardSharingSize && + m_pMainWindow == sc.m_pMainWindow; } -void ServerConfig::save(QFile& file) const -{ - QTextStream outStream(&file); - outStream << *this; +void ServerConfig::save(QFile &file) const { + QTextStream outStream(&file); + outStream << *this; } -void ServerConfig::init() -{ - switchCorners().clear(); - screens().clear(); - hotkeys().clear(); +void ServerConfig::init() { + switchCorners().clear(); + screens().clear(); + hotkeys().clear(); - // m_NumSwitchCorners is used as a fixed size array. See Screen::init() - for (int i = 0; i < NumSwitchCorners; i++) - switchCorners() << false; + // m_NumSwitchCorners is used as a fixed size array. See Screen::init() + for (int i = 0; i < NumSwitchCorners; i++) + switchCorners() << false; - // There must always be screen objects for each cell in the screens QList. Unused screens - // are identified by having an empty name. - for (int i = 0; i < numColumns() * numRows(); i++) - addScreen(Screen()); + // There must always be screen objects for each cell in the screens QList. + // Unused screens are identified by having an empty name. + for (int i = 0; i < numColumns() * numRows(); i++) + addScreen(Screen()); } -void ServerConfig::saveSettings() -{ - settings().beginGroup("internalConfig"); - settings().remove(""); +void ServerConfig::saveSettings() { + settings().beginGroup("internalConfig"); + settings().remove(""); - settings().setValue("numColumns", numColumns()); - settings().setValue("numRows", numRows()); + settings().setValue("numColumns", numColumns()); + settings().setValue("numRows", numRows()); - settings().setValue("hasHeartbeat", hasHeartbeat()); - settings().setValue("heartbeat", heartbeat()); - settings().setValue("relativeMouseMoves", relativeMouseMoves()); - settings().setValue("win32KeepForeground", win32KeepForeground()); - settings().setValue("hasSwitchDelay", hasSwitchDelay()); - settings().setValue("switchDelay", switchDelay()); - settings().setValue("hasSwitchDoubleTap", hasSwitchDoubleTap()); - settings().setValue("switchDoubleTap", switchDoubleTap()); - settings().setValue("switchCornerSize", switchCornerSize()); - settings().setValue("ignoreAutoConfigClient", ignoreAutoConfigClient()); - settings().setValue("disableLockToScreen", disableLockToScreen()); - settings().setValue("enableDragAndDrop", enableDragAndDrop()); - settings().setValue("clipboardSharing", clipboardSharing()); - settings().setValue("clipboardSharingSize", QVariant::fromValue(clipboardSharingSize())); + settings().setValue("hasHeartbeat", hasHeartbeat()); + settings().setValue("heartbeat", heartbeat()); + settings().setValue("relativeMouseMoves", relativeMouseMoves()); + settings().setValue("win32KeepForeground", win32KeepForeground()); + settings().setValue("hasSwitchDelay", hasSwitchDelay()); + settings().setValue("switchDelay", switchDelay()); + settings().setValue("hasSwitchDoubleTap", hasSwitchDoubleTap()); + settings().setValue("switchDoubleTap", switchDoubleTap()); + settings().setValue("switchCornerSize", switchCornerSize()); + settings().setValue("ignoreAutoConfigClient", ignoreAutoConfigClient()); + settings().setValue("disableLockToScreen", disableLockToScreen()); + settings().setValue("enableDragAndDrop", enableDragAndDrop()); + settings().setValue("clipboardSharing", clipboardSharing()); + settings().setValue("clipboardSharingSize", + QVariant::fromValue(clipboardSharingSize())); - if (!getClientAddress().isEmpty()) { - settings().setValue("clientAddress", getClientAddress()); + if (!getClientAddress().isEmpty()) { + settings().setValue("clientAddress", getClientAddress()); + } + + writeSettings(settings(), switchCorners(), "switchCorner"); + + settings().beginWriteArray("screens"); + for (int i = 0; i < screens().size(); i++) { + settings().setArrayIndex(i); + auto &screen = screens()[i]; + screen.saveSettings(settings()); + if (screen.isServer() && m_pAppConfig->screenName() != screen.name()) { + m_pAppConfig->setScreenName(screen.name()); } + } + settings().endArray(); - writeSettings(settings(), switchCorners(), "switchCorner"); + settings().beginWriteArray("hotkeys"); + for (int i = 0; i < hotkeys().size(); i++) { + settings().setArrayIndex(i); + hotkeys()[i].saveSettings(settings()); + } + settings().endArray(); - settings().beginWriteArray("screens"); - for (int i = 0; i < screens().size(); i++) - { - settings().setArrayIndex(i); - auto& screen = screens()[i]; - screen.saveSettings(settings()); - if (screen.isServer() && m_pAppConfig->screenName() != screen.name()){ - m_pAppConfig->setScreenName(screen.name()); - } - } - settings().endArray(); + settings().endGroup(); - settings().beginWriteArray("hotkeys"); - for (int i = 0; i < hotkeys().size(); i++) - { - settings().setArrayIndex(i); - hotkeys()[i].saveSettings(settings()); - } - settings().endArray(); - - settings().endGroup(); - - m_pAppConfig->saveSettings(); - //Tell the config writer there are changes - GUI::Config::ConfigWriter::make()->markUnsaved(); + m_pAppConfig->saveSettings(); + // Tell the config writer there are changes + GUI::Config::ConfigWriter::make()->markUnsaved(); } -void ServerConfig::loadSettings() -{ - settings().beginGroup("internalConfig"); +void ServerConfig::loadSettings() { + settings().beginGroup("internalConfig"); - setNumColumns(settings().value("numColumns", 5).toInt()); - setNumRows(settings().value("numRows", 3).toInt()); + setNumColumns(settings().value("numColumns", 5).toInt()); + setNumRows(settings().value("numRows", 3).toInt()); - // we need to know the number of columns and rows before we can set up ourselves - init(); + // we need to know the number of columns and rows before we can set up + // ourselves + init(); - haveHeartbeat(settings().value("hasHeartbeat", false).toBool()); - setHeartbeat(settings().value("heartbeat", 5000).toInt()); - setRelativeMouseMoves(settings().value("relativeMouseMoves", false).toBool()); - setWin32KeepForeground(settings().value("win32KeepForeground", false).toBool()); - haveSwitchDelay(settings().value("hasSwitchDelay", false).toBool()); - setSwitchDelay(settings().value("switchDelay", 250).toInt()); - haveSwitchDoubleTap(settings().value("hasSwitchDoubleTap", false).toBool()); - setSwitchDoubleTap(settings().value("switchDoubleTap", 250).toInt()); - setSwitchCornerSize(settings().value("switchCornerSize").toInt()); - setIgnoreAutoConfigClient(settings().value("ignoreAutoConfigClient").toBool()); - setDisableLockToScreen(settings().value("disableLockToScreen", false).toBool()); - setEnableDragAndDrop(settings().value("enableDragAndDrop", false).toBool()); - setClipboardSharingSize(settings().value("clipboardSharingSize", - (int) ServerConfig::defaultClipboardSharingSize()).toULongLong()); - setClipboardSharing(settings().value("clipboardSharing", true).toBool()); - setClientAddress(settings().value("clientAddress", "").toString()); + haveHeartbeat(settings().value("hasHeartbeat", false).toBool()); + setHeartbeat(settings().value("heartbeat", 5000).toInt()); + setRelativeMouseMoves(settings().value("relativeMouseMoves", false).toBool()); + setWin32KeepForeground( + settings().value("win32KeepForeground", false).toBool()); + haveSwitchDelay(settings().value("hasSwitchDelay", false).toBool()); + setSwitchDelay(settings().value("switchDelay", 250).toInt()); + haveSwitchDoubleTap(settings().value("hasSwitchDoubleTap", false).toBool()); + setSwitchDoubleTap(settings().value("switchDoubleTap", 250).toInt()); + setSwitchCornerSize(settings().value("switchCornerSize").toInt()); + setIgnoreAutoConfigClient( + settings().value("ignoreAutoConfigClient").toBool()); + setDisableLockToScreen( + settings().value("disableLockToScreen", false).toBool()); + setEnableDragAndDrop(settings().value("enableDragAndDrop", false).toBool()); + setClipboardSharingSize( + settings() + .value("clipboardSharingSize", + (int)ServerConfig::defaultClipboardSharingSize()) + .toULongLong()); + setClipboardSharing(settings().value("clipboardSharing", true).toBool()); + setClientAddress(settings().value("clientAddress", "").toString()); - readSettings(settings(), switchCorners(), "switchCorner", false, NumSwitchCorners); + readSettings(settings(), switchCorners(), "switchCorner", false, + NumSwitchCorners); - int numScreens = settings().beginReadArray("screens"); - Q_ASSERT(numScreens <= screens().size()); - for (int i = 0; i < numScreens; i++) - { - settings().setArrayIndex(i); - screens()[i].loadSettings(settings()); - if (getServerName() == screens()[i].name()) { - screens()[i].markAsServer(); - } + int numScreens = settings().beginReadArray("screens"); + Q_ASSERT(numScreens <= screens().size()); + for (int i = 0; i < numScreens; i++) { + settings().setArrayIndex(i); + screens()[i].loadSettings(settings()); + if (getServerName() == screens()[i].name()) { + screens()[i].markAsServer(); } - settings().endArray(); + } + settings().endArray(); - int numHotkeys = settings().beginReadArray("hotkeys"); - for (int i = 0; i < numHotkeys; i++) - { - settings().setArrayIndex(i); - Hotkey h; - h.loadSettings(settings()); - hotkeys().append(h); - } - settings().endArray(); + int numHotkeys = settings().beginReadArray("hotkeys"); + for (int i = 0; i < numHotkeys; i++) { + settings().setArrayIndex(i); + Hotkey h; + h.loadSettings(settings()); + hotkeys().append(h); + } + settings().endArray(); - settings().endGroup(); + settings().endGroup(); } -int ServerConfig::adjacentScreenIndex(int idx, int deltaColumn, int deltaRow) const -{ - if (screens()[idx].isNull()) - return -1; +int ServerConfig::adjacentScreenIndex(int idx, int deltaColumn, + int deltaRow) const { + if (screens()[idx].isNull()) + return -1; - // if we're at the left or right end of the table, don't find results going further left or right - if ((deltaColumn > 0 && (idx+1) % numColumns() == 0) - || (deltaColumn < 0 && idx % numColumns() == 0)) - return -1; + // if we're at the left or right end of the table, don't find results going + // further left or right + if ((deltaColumn > 0 && (idx + 1) % numColumns() == 0) || + (deltaColumn < 0 && idx % numColumns() == 0)) + return -1; - int arrayPos = idx + deltaColumn + deltaRow * numColumns(); + int arrayPos = idx + deltaColumn + deltaRow * numColumns(); - if (arrayPos >= screens().size() || arrayPos < 0) - return -1; + if (arrayPos >= screens().size() || arrayPos < 0) + return -1; - return arrayPos; + return arrayPos; } -QTextStream& operator<<(QTextStream& outStream, const ServerConfig& config) -{ - outStream << "section: screens" << endl; +QTextStream &operator<<(QTextStream &outStream, const ServerConfig &config) { + outStream << "section: screens" << endl; - foreach (const Screen& s, config.screens()) - if (!s.isNull()) - s.writeScreensSection(outStream); + foreach (const Screen &s, config.screens()) + if (!s.isNull()) + s.writeScreensSection(outStream); - outStream << "end" << endl << endl; + outStream << "end" << endl << endl; - outStream << "section: aliases" << endl; + outStream << "section: aliases" << endl; - foreach (const Screen& s, config.screens()) - if (!s.isNull()) - s.writeAliasesSection(outStream); + foreach (const Screen &s, config.screens()) + if (!s.isNull()) + s.writeAliasesSection(outStream); - outStream << "end" << endl << endl; + outStream << "end" << endl << endl; - outStream << "section: links" << endl; + outStream << "section: links" << endl; - for (int i = 0; i < config.screens().size(); i++) - if (!config.screens()[i].isNull()) - { - outStream << "\t" << config.screens()[i].name() << ":" << endl; + for (int i = 0; i < config.screens().size(); i++) + if (!config.screens()[i].isNull()) { + outStream << "\t" << config.screens()[i].name() << ":" << endl; - for (unsigned int j = 0; j < sizeof(neighbourDirs) / sizeof(neighbourDirs[0]); j++) - { - int idx = config.adjacentScreenIndex(i, neighbourDirs[j].x, neighbourDirs[j].y); - if (idx != -1 && !config.screens()[idx].isNull()) - outStream << "\t\t" << neighbourDirs[j].name << " = " << config.screens()[idx].name() << endl; - } - } - - outStream << "end" << endl << endl; - - outStream << "section: options" << endl; - - if (config.hasHeartbeat()) - outStream << "\t" << "heartbeat = " << config.heartbeat() << endl; - - outStream << "\t" << "relativeMouseMoves = " << (config.relativeMouseMoves() ? "true" : "false") << endl; - outStream << "\t" << "win32KeepForeground = " << (config.win32KeepForeground() ? "true" : "false") << endl; - outStream << "\t" << "disableLockToScreen = " << (config.disableLockToScreen() ? "true" : "false") << endl; - outStream << "\t" << "clipboardSharing = " << (config.clipboardSharing() ? "true" : "false") << endl; - outStream << "\t" << "clipboardSharingSize = " << config.clipboardSharingSize() << endl; - - if (!config.getClientAddress().isEmpty()) { - outStream << "\t" << "clientAddress = " << config.getClientAddress() << endl; - } - - if (config.hasSwitchDelay()) - outStream << "\t" << "switchDelay = " << config.switchDelay() << endl; - - if (config.hasSwitchDoubleTap()) - outStream << "\t" << "switchDoubleTap = " << config.switchDoubleTap() << endl; - - outStream << "\t" << "switchCorners = none "; - for (int i = 0; i < config.switchCorners().size(); i++) - if (config.switchCorners()[i]) - outStream << "+" << config.switchCornerName(i) << " "; - outStream << endl; - - outStream << "\t" << "switchCornerSize = " << config.switchCornerSize() << endl; - - foreach(const Hotkey& hotkey, config.hotkeys()) - outStream << hotkey; - - outStream << "end" << endl << endl; - - return outStream; -} - -int ServerConfig::numScreens() const -{ - int rval = 0; - - foreach(const Screen& s, screens()) - if (!s.isNull()) - rval++; - - return rval; -} - -int ServerConfig::autoAddScreen(const QString name) -{ - int serverIndex = -1; - int targetIndex = -1; - if (!findScreenName(m_pAppConfig->screenName(), serverIndex) && - !fixNoServer(m_pAppConfig->screenName(), serverIndex)) - { - return kAutoAddScreenManualServer; - } - - if (findScreenName(name, targetIndex)) { - m_pMainWindow->appendLogDebug(QString("ignoring screen already in config: %1").arg(name)); - return kAutoAddScreenIgnore; - } - - int result = showAddClientDialog(name); - - if (result == kAddClientIgnore) { - return kAutoAddScreenIgnore; - } - - if (result == kAddClientOther) { - addToFirstEmptyGrid(name); - return kAutoAddScreenManualClient; - } - - bool success = false; - int startIndex = serverIndex; - int offset = 1; - int dirIndex = 0; - - if (result == kAddClientLeft) { - offset = -1; - dirIndex = 1; - } - else if (result == kAddClientUp) { - offset = -5; - dirIndex = 2; - } - else if (result == kAddClientDown) { - offset = 5; - dirIndex = 3; - } - - - int idx = adjacentScreenIndex(startIndex, neighbourDirs[dirIndex].x, - neighbourDirs[dirIndex].y); - while (idx != -1) { - if (screens()[idx].isNull()) { - m_Screens[idx].setName(name); - success = true; - break; - } - - startIndex += offset; - idx = adjacentScreenIndex(startIndex, neighbourDirs[dirIndex].x, - neighbourDirs[dirIndex].y); - } - - if (!success) { - addToFirstEmptyGrid(name); - return kAutoAddScreenManualClient; - } - - saveSettings(); - return kAutoAddScreenOk; -} - -const QString& ServerConfig::getServerName() const -{ - return m_pAppConfig->screenName(); -} - -void ServerConfig::updateServerName() -{ - for (auto& screen : screens()) { - if (screen.isServer()) { - screen.setName(m_pAppConfig->screenName()); - saveSettings(); - break; + for (unsigned int j = 0; + j < sizeof(neighbourDirs) / sizeof(neighbourDirs[0]); j++) { + int idx = config.adjacentScreenIndex(i, neighbourDirs[j].x, + neighbourDirs[j].y); + if (idx != -1 && !config.screens()[idx].isNull()) + outStream << "\t\t" << neighbourDirs[j].name << " = " + << config.screens()[idx].name() << endl; } - } -} - -const QString& ServerConfig::getConfigFile() const -{ - return m_pAppConfig->getConfigFile(); -} - -bool ServerConfig::getUseExternalConfig() const -{ - return m_pAppConfig->getUseExternalConfig(); -} - -bool ServerConfig::isFull() const -{ - bool isFull = true; - - for (const auto& screen : screens()) - { - if (screen.isNull()) - { - isFull = false; - break; - } } - return isFull; + outStream << "end" << endl << endl; + + outStream << "section: options" << endl; + + if (config.hasHeartbeat()) + outStream << "\t" + << "heartbeat = " << config.heartbeat() << endl; + + outStream << "\t" + << "relativeMouseMoves = " + << (config.relativeMouseMoves() ? "true" : "false") << endl; + outStream << "\t" + << "win32KeepForeground = " + << (config.win32KeepForeground() ? "true" : "false") << endl; + outStream << "\t" + << "disableLockToScreen = " + << (config.disableLockToScreen() ? "true" : "false") << endl; + outStream << "\t" + << "clipboardSharing = " + << (config.clipboardSharing() ? "true" : "false") << endl; + outStream << "\t" + << "clipboardSharingSize = " << config.clipboardSharingSize() + << endl; + + if (!config.getClientAddress().isEmpty()) { + outStream << "\t" + << "clientAddress = " << config.getClientAddress() << endl; + } + + if (config.hasSwitchDelay()) + outStream << "\t" + << "switchDelay = " << config.switchDelay() << endl; + + if (config.hasSwitchDoubleTap()) + outStream << "\t" + << "switchDoubleTap = " << config.switchDoubleTap() << endl; + + outStream << "\t" + << "switchCorners = none "; + for (int i = 0; i < config.switchCorners().size(); i++) + if (config.switchCorners()[i]) + outStream << "+" << config.switchCornerName(i) << " "; + outStream << endl; + + outStream << "\t" + << "switchCornerSize = " << config.switchCornerSize() << endl; + + foreach (const Hotkey &hotkey, config.hotkeys()) + outStream << hotkey; + + outStream << "end" << endl << endl; + + return outStream; } -bool ServerConfig::isScreenExists(const QString& screenName) const -{ - bool isExists = false; +int ServerConfig::numScreens() const { + int rval = 0; - for (const auto& screen : screens()) - { - if (!screen.isNull() && - screen.name() == screenName) - { - isExists = true; - break; - } + foreach (const Screen &s, screens()) + if (!s.isNull()) + rval++; + + return rval; +} + +int ServerConfig::autoAddScreen(const QString name) { + int serverIndex = -1; + int targetIndex = -1; + if (!findScreenName(m_pAppConfig->screenName(), serverIndex) && + !fixNoServer(m_pAppConfig->screenName(), serverIndex)) { + return kAutoAddScreenManualServer; + } + + if (findScreenName(name, targetIndex)) { + m_pMainWindow->appendLogDebug( + QString("ignoring screen already in config: %1").arg(name)); + return kAutoAddScreenIgnore; + } + + int result = showAddClientDialog(name); + + if (result == kAddClientIgnore) { + return kAutoAddScreenIgnore; + } + + if (result == kAddClientOther) { + addToFirstEmptyGrid(name); + return kAutoAddScreenManualClient; + } + + bool success = false; + int startIndex = serverIndex; + int offset = 1; + int dirIndex = 0; + + if (result == kAddClientLeft) { + offset = -1; + dirIndex = 1; + } else if (result == kAddClientUp) { + offset = -5; + dirIndex = 2; + } else if (result == kAddClientDown) { + offset = 5; + dirIndex = 3; + } + + int idx = adjacentScreenIndex(startIndex, neighbourDirs[dirIndex].x, + neighbourDirs[dirIndex].y); + while (idx != -1) { + if (screens()[idx].isNull()) { + m_Screens[idx].setName(name); + success = true; + break; } - return isExists; + startIndex += offset; + idx = adjacentScreenIndex(startIndex, neighbourDirs[dirIndex].x, + neighbourDirs[dirIndex].y); + } + + if (!success) { + addToFirstEmptyGrid(name); + return kAutoAddScreenManualClient; + } + + saveSettings(); + return kAutoAddScreenOk; } -void ServerConfig::addClient(const QString& clientName) -{ - int serverIndex = -1; +const QString &ServerConfig::getServerName() const { + return m_pAppConfig->screenName(); +} - if (findScreenName(m_pAppConfig->screenName(), serverIndex)) - { - m_Screens[serverIndex].markAsServer(); +void ServerConfig::updateServerName() { + for (auto &screen : screens()) { + if (screen.isServer()) { + screen.setName(m_pAppConfig->screenName()); + saveSettings(); + break; } - else - { - fixNoServer(m_pAppConfig->screenName(), serverIndex); + } +} + +const QString &ServerConfig::getConfigFile() const { + return m_pAppConfig->getConfigFile(); +} + +bool ServerConfig::getUseExternalConfig() const { + return m_pAppConfig->getUseExternalConfig(); +} + +bool ServerConfig::isFull() const { + bool isFull = true; + + for (const auto &screen : screens()) { + if (screen.isNull()) { + isFull = false; + break; } + } - m_Screens.addScreenByPriority(clientName); + return isFull; } -void ServerConfig::setConfigFile(const QString& configFile) -{ - m_pAppConfig->setConfigFile(configFile); -} +bool ServerConfig::isScreenExists(const QString &screenName) const { + bool isExists = false; -void ServerConfig::setUseExternalConfig(bool useExternalConfig) -{ - m_pAppConfig->setUseExternalConfig(useExternalConfig); -} - -bool ServerConfig::findScreenName(const QString& name, int& index) -{ - bool found = false; - for (int i = 0; i < screens().size(); i++) { - if (!screens()[i].isNull() && - screens()[i].name().compare(name) == 0) { - index = i; - found = true; - break; - } + for (const auto &screen : screens()) { + if (!screen.isNull() && screen.name() == screenName) { + isExists = true; + break; } - return found; + } + + return isExists; } -bool ServerConfig::fixNoServer(const QString& name, int& index) -{ - bool fixed = false; - if (screens()[serverDefaultIndex].isNull()) { - m_Screens[serverDefaultIndex].setName(name); - m_Screens[serverDefaultIndex].markAsServer(); - index = serverDefaultIndex; - fixed = true; - } +void ServerConfig::addClient(const QString &clientName) { + int serverIndex = -1; - return fixed; + if (findScreenName(m_pAppConfig->screenName(), serverIndex)) { + m_Screens[serverIndex].markAsServer(); + } else { + fixNoServer(m_pAppConfig->screenName(), serverIndex); + } + + m_Screens.addScreenByPriority(clientName); } -int ServerConfig::showAddClientDialog(const QString& clientName) -{ - int result = kAddClientIgnore; - - if (!m_pMainWindow->isActiveWindow()) { - m_pMainWindow->showNormal(); - m_pMainWindow->activateWindow(); - } - - AddClientDialog addClientDialog(clientName, m_pMainWindow); - addClientDialog.exec(); - result = addClientDialog.addResult(); - m_IgnoreAutoConfigClient = addClientDialog.ignoreAutoConfigClient(); - - return result; +void ServerConfig::setConfigFile(const QString &configFile) { + m_pAppConfig->setConfigFile(configFile); } -void::ServerConfig::addToFirstEmptyGrid(const QString &clientName) -{ - for (int i = 0; i < screens().size(); i++) { - if (screens()[i].isNull()) { - m_Screens[i].setName(clientName); - break; - } +void ServerConfig::setUseExternalConfig(bool useExternalConfig) { + m_pAppConfig->setUseExternalConfig(useExternalConfig); +} + +bool ServerConfig::findScreenName(const QString &name, int &index) { + bool found = false; + for (int i = 0; i < screens().size(); i++) { + if (!screens()[i].isNull() && screens()[i].name().compare(name) == 0) { + index = i; + found = true; + break; } + } + return found; +} + +bool ServerConfig::fixNoServer(const QString &name, int &index) { + bool fixed = false; + if (screens()[serverDefaultIndex].isNull()) { + m_Screens[serverDefaultIndex].setName(name); + m_Screens[serverDefaultIndex].markAsServer(); + index = serverDefaultIndex; + fixed = true; + } + + return fixed; +} + +int ServerConfig::showAddClientDialog(const QString &clientName) { + int result = kAddClientIgnore; + + if (!m_pMainWindow->isActiveWindow()) { + m_pMainWindow->showNormal(); + m_pMainWindow->activateWindow(); + } + + AddClientDialog addClientDialog(clientName, m_pMainWindow); + addClientDialog.exec(); + result = addClientDialog.addResult(); + m_IgnoreAutoConfigClient = addClientDialog.ignoreAutoConfigClient(); + + return result; +} + +void ::ServerConfig::addToFirstEmptyGrid(const QString &clientName) { + for (int i = 0; i < screens().size(); i++) { + if (screens()[i].isNull()) { + m_Screens[i].setName(clientName); + break; + } + } } size_t ServerConfig::defaultClipboardSharingSize() { - return 3 * 1024; // 3 MiB + return 3 * 1024; // 3 MiB } size_t ServerConfig::setClipboardSharingSize(size_t size) { - if (size) { - size += 512; // Round up to the nearest megabyte - size /= 1024; - size *= 1024; - setClipboardSharing(true); - } else { - setClipboardSharing(false); - } - using std::swap; - swap (size, m_ClipboardSharingSize); - return size; + if (size) { + size += 512; // Round up to the nearest megabyte + size /= 1024; + size *= 1024; + setClipboardSharing(true); + } else { + setClipboardSharing(false); + } + using std::swap; + swap(size, m_ClipboardSharingSize); + return size; } -void ServerConfig::setClientAddress(const QString& address) { - if (m_pAppConfig->getServerClientMode()) { - m_clientAddress = address; - } +void ServerConfig::setClientAddress(const QString &address) { + if (m_pAppConfig->getServerClientMode()) { + m_clientAddress = address; + } } QString ServerConfig::getClientAddress() const { - QString clientAddress; + QString clientAddress; - if (m_pAppConfig->getServerClientMode()) { - clientAddress = m_clientAddress.trimmed(); - } + if (m_pAppConfig->getServerClientMode()) { + clientAddress = m_clientAddress.trimmed(); + } - return clientAddress; + return clientAddress; } QSettings &ServerConfig::settings() { - using GUI::Config::ConfigWriter; + using GUI::Config::ConfigWriter; - return ConfigWriter::make()->settings(); + return ConfigWriter::make()->settings(); } bool ServerConfig::isHotkeysAvailable() const { #ifndef SYNERGY_ENTERPRISE - return (m_pAppConfig->edition() != Edition::kLite); + return (m_pAppConfig->edition() != Edition::kLite); #else - return true; + return true; #endif } diff --git a/src/gui/src/ServerConfig.h b/src/gui/src/ServerConfig.h index c71988cbd..02ca2ceb8 100644 --- a/src/gui/src/ServerConfig.h +++ b/src/gui/src/ServerConfig.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2008 Volker Lanz (vl@fidra.de) - * + * * 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 LICENSE 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 @@ -22,10 +22,10 @@ #include -#include "ScreenList.h" #include "BaseConfig.h" -#include "Hotkey.h" #include "ConfigBase.h" +#include "Hotkey.h" +#include "ScreenList.h" class QTextStream; class QSettings; @@ -35,132 +35,132 @@ class ServerConfigDialog; class MainWindow; class AppConfig; -class ServerConfig : public BaseConfig, public GUI::Config::ConfigBase -{ - friend class ServerConfigDialog; - friend class ServerConnection; - friend QTextStream& operator<<(QTextStream& outStream, const ServerConfig& config); +class ServerConfig : public BaseConfig, public GUI::Config::ConfigBase { + friend class ServerConfigDialog; + friend class ServerConnection; + friend QTextStream &operator<<(QTextStream &outStream, + const ServerConfig &config); - public: - ServerConfig(int numColumns, int numRows, AppConfig* appConfig, MainWindow* mainWindow); +public: + ServerConfig(int numColumns, int numRows, AppConfig *appConfig, + MainWindow *mainWindow); - ServerConfig(const ServerConfig &src) =default; - ServerConfig(ServerConfig &&) =default; - ~ServerConfig(); - ServerConfig& operator=(const ServerConfig &src) =default; - ServerConfig& operator=(ServerConfig &&) =delete; + ServerConfig(const ServerConfig &src) = default; + ServerConfig(ServerConfig &&) = default; + ~ServerConfig(); + ServerConfig &operator=(const ServerConfig &src) = default; + ServerConfig &operator=(ServerConfig &&) = delete; - bool operator==(const ServerConfig& sc) const; + bool operator==(const ServerConfig &sc) const; - public: - const ScreenList& screens() const { return m_Screens; } - int numColumns() const { return m_NumColumns; } - int numRows() const { return m_NumRows; } - bool hasHeartbeat() const { return m_HasHeartbeat; } - int heartbeat() const { return m_Heartbeat; } - bool relativeMouseMoves() const { return m_RelativeMouseMoves; } - bool win32KeepForeground() const { return m_Win32KeepForeground; } - bool hasSwitchDelay() const { return m_HasSwitchDelay; } - int switchDelay() const { return m_SwitchDelay; } - bool hasSwitchDoubleTap() const { return m_HasSwitchDoubleTap; } - int switchDoubleTap() const { return m_SwitchDoubleTap; } - bool switchCorner(int c) const { return m_SwitchCorners[c]; } - int switchCornerSize() const { return m_SwitchCornerSize; } - const QList& switchCorners() const { return m_SwitchCorners; } - const HotkeyList& hotkeys() const { return m_Hotkeys; } - bool ignoreAutoConfigClient() const { return m_IgnoreAutoConfigClient; } - bool enableDragAndDrop() const { return m_EnableDragAndDrop; } - bool disableLockToScreen() const { return m_DisableLockToScreen; } - bool clipboardSharing() const { return m_ClipboardSharing; } - size_t clipboardSharingSize() const { return m_ClipboardSharingSize; } - static size_t defaultClipboardSharingSize(); +public: + const ScreenList &screens() const { return m_Screens; } + int numColumns() const { return m_NumColumns; } + int numRows() const { return m_NumRows; } + bool hasHeartbeat() const { return m_HasHeartbeat; } + int heartbeat() const { return m_Heartbeat; } + bool relativeMouseMoves() const { return m_RelativeMouseMoves; } + bool win32KeepForeground() const { return m_Win32KeepForeground; } + bool hasSwitchDelay() const { return m_HasSwitchDelay; } + int switchDelay() const { return m_SwitchDelay; } + bool hasSwitchDoubleTap() const { return m_HasSwitchDoubleTap; } + int switchDoubleTap() const { return m_SwitchDoubleTap; } + bool switchCorner(int c) const { return m_SwitchCorners[c]; } + int switchCornerSize() const { return m_SwitchCornerSize; } + const QList &switchCorners() const { return m_SwitchCorners; } + const HotkeyList &hotkeys() const { return m_Hotkeys; } + bool ignoreAutoConfigClient() const { return m_IgnoreAutoConfigClient; } + bool enableDragAndDrop() const { return m_EnableDragAndDrop; } + bool disableLockToScreen() const { return m_DisableLockToScreen; } + bool clipboardSharing() const { return m_ClipboardSharing; } + size_t clipboardSharingSize() const { return m_ClipboardSharingSize; } + static size_t defaultClipboardSharingSize(); - void saveSettings() override; - void loadSettings() override; - bool save(const QString& fileName) const; - void save(QFile& file) const; - int numScreens() const; - int autoAddScreen(const QString name); - const QString& getServerName() const; - void updateServerName(); - const QString& getConfigFile() const; - bool getUseExternalConfig() const; - bool isFull() const; - bool isScreenExists(const QString& screenName) const; - void addClient(const QString& clientName); - bool isHotkeysAvailable() const; - QString getClientAddress() const; - void setClientAddress(const QString& address); + void saveSettings() override; + void loadSettings() override; + bool save(const QString &fileName) const; + void save(QFile &file) const; + int numScreens() const; + int autoAddScreen(const QString name); + const QString &getServerName() const; + void updateServerName(); + const QString &getConfigFile() const; + bool getUseExternalConfig() const; + bool isFull() const; + bool isScreenExists(const QString &screenName) const; + void addClient(const QString &clientName); + bool isHotkeysAvailable() const; + QString getClientAddress() const; + void setClientAddress(const QString &address); - protected: - QSettings& settings(); - ScreenList& screens() { return m_Screens; } - void setScreens(const ScreenList& screens) { m_Screens = screens; } - void addScreen(const Screen& screen) { m_Screens.append(screen); } - void setNumColumns(int n) { m_NumColumns = n; } - void setNumRows(int n) { m_NumRows = n; } - void haveHeartbeat(bool on) { m_HasHeartbeat = on; } - void setHeartbeat(int val) { m_Heartbeat = val; } - void setRelativeMouseMoves(bool on) { m_RelativeMouseMoves = on; } - void setWin32KeepForeground(bool on) { m_Win32KeepForeground = on; } - void haveSwitchDelay(bool on) { m_HasSwitchDelay = on; } - void setSwitchDelay(int val) { m_SwitchDelay = val; } - void haveSwitchDoubleTap(bool on) { m_HasSwitchDoubleTap = on; } - void setSwitchDoubleTap(int val) { m_SwitchDoubleTap = val; } - void setSwitchCorner(int c, bool on) { m_SwitchCorners[c] = on; } - void setSwitchCornerSize(int val) { m_SwitchCornerSize = val; } - void setIgnoreAutoConfigClient(bool on) { m_IgnoreAutoConfigClient = on; } - void setEnableDragAndDrop(bool on) { m_EnableDragAndDrop = on; } - void setDisableLockToScreen(bool on) { m_DisableLockToScreen = on; } - void setClipboardSharing(bool on) { m_ClipboardSharing = on; } - void setConfigFile(const QString& configFile); - void setUseExternalConfig(bool useExternalConfig); - size_t setClipboardSharingSize(size_t size); - QList& switchCorners() { return m_SwitchCorners; } - HotkeyList& hotkeys() { return m_Hotkeys; } +protected: + QSettings &settings(); + ScreenList &screens() { return m_Screens; } + void setScreens(const ScreenList &screens) { m_Screens = screens; } + void addScreen(const Screen &screen) { m_Screens.append(screen); } + void setNumColumns(int n) { m_NumColumns = n; } + void setNumRows(int n) { m_NumRows = n; } + void haveHeartbeat(bool on) { m_HasHeartbeat = on; } + void setHeartbeat(int val) { m_Heartbeat = val; } + void setRelativeMouseMoves(bool on) { m_RelativeMouseMoves = on; } + void setWin32KeepForeground(bool on) { m_Win32KeepForeground = on; } + void haveSwitchDelay(bool on) { m_HasSwitchDelay = on; } + void setSwitchDelay(int val) { m_SwitchDelay = val; } + void haveSwitchDoubleTap(bool on) { m_HasSwitchDoubleTap = on; } + void setSwitchDoubleTap(int val) { m_SwitchDoubleTap = val; } + void setSwitchCorner(int c, bool on) { m_SwitchCorners[c] = on; } + void setSwitchCornerSize(int val) { m_SwitchCornerSize = val; } + void setIgnoreAutoConfigClient(bool on) { m_IgnoreAutoConfigClient = on; } + void setEnableDragAndDrop(bool on) { m_EnableDragAndDrop = on; } + void setDisableLockToScreen(bool on) { m_DisableLockToScreen = on; } + void setClipboardSharing(bool on) { m_ClipboardSharing = on; } + void setConfigFile(const QString &configFile); + void setUseExternalConfig(bool useExternalConfig); + size_t setClipboardSharingSize(size_t size); + QList &switchCorners() { return m_SwitchCorners; } + HotkeyList &hotkeys() { return m_Hotkeys; } - void init(); - int adjacentScreenIndex(int idx, int deltaColumn, int deltaRow) const; + void init(); + int adjacentScreenIndex(int idx, int deltaColumn, int deltaRow) const; - private: - bool findScreenName(const QString& name, int& index); - bool fixNoServer(const QString& name, int& index); - int showAddClientDialog(const QString& clientName); - void addToFirstEmptyGrid(const QString& clientName); +private: + bool findScreenName(const QString &name, int &index); + bool fixNoServer(const QString &name, int &index); + int showAddClientDialog(const QString &clientName); + void addToFirstEmptyGrid(const QString &clientName); - private: - ScreenList m_Screens; - int m_NumColumns; - int m_NumRows; - bool m_HasHeartbeat; - int m_Heartbeat; - bool m_RelativeMouseMoves; - bool m_Win32KeepForeground; - bool m_HasSwitchDelay; - int m_SwitchDelay; - bool m_HasSwitchDoubleTap; - int m_SwitchDoubleTap; - int m_SwitchCornerSize; - QList m_SwitchCorners; - HotkeyList m_Hotkeys; - AppConfig* m_pAppConfig; - bool m_IgnoreAutoConfigClient; - bool m_EnableDragAndDrop; - bool m_DisableLockToScreen; - bool m_ClipboardSharing; - size_t m_ClipboardSharingSize; - QString m_clientAddress; - MainWindow* m_pMainWindow; +private: + ScreenList m_Screens; + int m_NumColumns; + int m_NumRows; + bool m_HasHeartbeat; + int m_Heartbeat; + bool m_RelativeMouseMoves; + bool m_Win32KeepForeground; + bool m_HasSwitchDelay; + int m_SwitchDelay; + bool m_HasSwitchDoubleTap; + int m_SwitchDoubleTap; + int m_SwitchCornerSize; + QList m_SwitchCorners; + HotkeyList m_Hotkeys; + AppConfig *m_pAppConfig; + bool m_IgnoreAutoConfigClient; + bool m_EnableDragAndDrop; + bool m_DisableLockToScreen; + bool m_ClipboardSharing; + size_t m_ClipboardSharingSize; + QString m_clientAddress; + MainWindow *m_pMainWindow; }; -QTextStream& operator<<(QTextStream& outStream, const ServerConfig& config); +QTextStream &operator<<(QTextStream &outStream, const ServerConfig &config); enum { - kAutoAddScreenOk, - kAutoAddScreenManualServer, - kAutoAddScreenManualClient, - kAutoAddScreenIgnore + kAutoAddScreenOk, + kAutoAddScreenManualServer, + kAutoAddScreenManualClient, + kAutoAddScreenIgnore }; #endif - diff --git a/src/gui/src/ServerConfigDialog.cpp b/src/gui/src/ServerConfigDialog.cpp index b02b93eeb..74be8ac64 100644 --- a/src/gui/src/ServerConfigDialog.cpp +++ b/src/gui/src/ServerConfigDialog.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2008 Volker Lanz (vl@fidra.de) - * + * * 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 LICENSE 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 @@ -16,368 +16,429 @@ * along with this program. If not, see . */ -#include "ScreenSettingsDialog.h" #include "ServerConfigDialog.h" -#include "ServerConfig.h" -#include "HotkeyDialog.h" #include "ActionDialog.h" +#include "HotkeyDialog.h" +#include "ScreenSettingsDialog.h" +#include "ServerConfig.h" #include "UpgradeDialog.h" +#include +#include #include #include -#include -#include -ServerConfigDialog::ServerConfigDialog(QWidget* parent, ServerConfig& config) : - QDialog(parent, Qt::WindowTitleHint | Qt::WindowSystemMenuHint), - Ui::ServerConfigDialogBase(), - m_OrigServerConfig(config), - m_OrigServerAppConfigUseExternalConfig(config.getUseExternalConfig()), - m_OrigServerAppConfigExternalConfigFile(config.getConfigFile()), - m_ServerConfig(config), - m_ScreenSetupModel(serverConfig().screens(), serverConfig().numColumns(), serverConfig().numRows()), - m_Message("") -{ - setupUi(this); +ServerConfigDialog::ServerConfigDialog(QWidget *parent, ServerConfig &config) + : QDialog(parent, Qt::WindowTitleHint | Qt::WindowSystemMenuHint), + Ui::ServerConfigDialogBase(), m_OrigServerConfig(config), + m_OrigServerAppConfigUseExternalConfig(config.getUseExternalConfig()), + m_OrigServerAppConfigExternalConfigFile(config.getConfigFile()), + m_ServerConfig(config), + m_ScreenSetupModel(serverConfig().screens(), serverConfig().numColumns(), + serverConfig().numRows()), + m_Message("") { + setupUi(this); - m_pEditConfigFile->setText(serverConfig().getConfigFile()); - m_pCheckBoxUseExternalConfig->setChecked(serverConfig().getUseExternalConfig()); - m_pCheckBoxHeartbeat->setChecked(serverConfig().hasHeartbeat()); - m_pSpinBoxHeartbeat->setValue(serverConfig().heartbeat()); + m_pEditConfigFile->setText(serverConfig().getConfigFile()); + m_pCheckBoxUseExternalConfig->setChecked( + serverConfig().getUseExternalConfig()); + m_pCheckBoxHeartbeat->setChecked(serverConfig().hasHeartbeat()); + m_pSpinBoxHeartbeat->setValue(serverConfig().heartbeat()); - m_pCheckBoxRelativeMouseMoves->setChecked(serverConfig().relativeMouseMoves()); - m_pCheckBoxWin32KeepForeground->setChecked(serverConfig().win32KeepForeground()); + m_pCheckBoxRelativeMouseMoves->setChecked( + serverConfig().relativeMouseMoves()); + m_pCheckBoxWin32KeepForeground->setChecked( + serverConfig().win32KeepForeground()); - m_pCheckBoxSwitchDelay->setChecked(serverConfig().hasSwitchDelay()); - m_pSpinBoxSwitchDelay->setValue(serverConfig().switchDelay()); + m_pCheckBoxSwitchDelay->setChecked(serverConfig().hasSwitchDelay()); + m_pSpinBoxSwitchDelay->setValue(serverConfig().switchDelay()); - m_pCheckBoxSwitchDoubleTap->setChecked(serverConfig().hasSwitchDoubleTap()); - m_pSpinBoxSwitchDoubleTap->setValue(serverConfig().switchDoubleTap()); + m_pCheckBoxSwitchDoubleTap->setChecked(serverConfig().hasSwitchDoubleTap()); + m_pSpinBoxSwitchDoubleTap->setValue(serverConfig().switchDoubleTap()); - m_pCheckBoxCornerTopLeft->setChecked(serverConfig().switchCorner(BaseConfig::TopLeft)); - m_pCheckBoxCornerTopRight->setChecked(serverConfig().switchCorner(BaseConfig::TopRight)); - m_pCheckBoxCornerBottomLeft->setChecked(serverConfig().switchCorner(BaseConfig::BottomLeft)); - m_pCheckBoxCornerBottomRight->setChecked(serverConfig().switchCorner(BaseConfig::BottomRight)); - m_pSpinBoxSwitchCornerSize->setValue(serverConfig().switchCornerSize()); - m_pCheckBoxDisableLockToScreen->setChecked(serverConfig().disableLockToScreen()); + m_pCheckBoxCornerTopLeft->setChecked( + serverConfig().switchCorner(BaseConfig::TopLeft)); + m_pCheckBoxCornerTopRight->setChecked( + serverConfig().switchCorner(BaseConfig::TopRight)); + m_pCheckBoxCornerBottomLeft->setChecked( + serverConfig().switchCorner(BaseConfig::BottomLeft)); + m_pCheckBoxCornerBottomRight->setChecked( + serverConfig().switchCorner(BaseConfig::BottomRight)); + m_pSpinBoxSwitchCornerSize->setValue(serverConfig().switchCornerSize()); + m_pCheckBoxDisableLockToScreen->setChecked( + serverConfig().disableLockToScreen()); - m_pCheckBoxIgnoreAutoConfigClient->setChecked(serverConfig().ignoreAutoConfigClient()); + m_pCheckBoxIgnoreAutoConfigClient->setChecked( + serverConfig().ignoreAutoConfigClient()); - m_pCheckBoxEnableClipboard->setChecked(serverConfig().clipboardSharing()); - int clipboardSharingSizeM = static_cast(serverConfig().clipboardSharingSize() / 1024); - m_pSpinBoxClipboardSizeLimit->setValue(clipboardSharingSizeM); - m_pSpinBoxClipboardSizeLimit->setEnabled(serverConfig().clipboardSharing()); + m_pCheckBoxEnableClipboard->setChecked(serverConfig().clipboardSharing()); + int clipboardSharingSizeM = + static_cast(serverConfig().clipboardSharingSize() / 1024); + m_pSpinBoxClipboardSizeLimit->setValue(clipboardSharingSizeM); + m_pSpinBoxClipboardSizeLimit->setEnabled(serverConfig().clipboardSharing()); - foreach(const Hotkey& hotkey, serverConfig().hotkeys()) - m_pListHotkeys->addItem(hotkey.text()); + foreach (const Hotkey &hotkey, serverConfig().hotkeys()) + m_pListHotkeys->addItem(hotkey.text()); - m_pScreenSetupView->setModel(&m_ScreenSetupModel); + m_pScreenSetupView->setModel(&m_ScreenSetupModel); - auto& screens = serverConfig().screens(); - auto server = std::find_if(screens.begin(), screens.end(), [this](const Screen& screen){ return (screen.name() == serverConfig().getServerName());}); + auto &screens = serverConfig().screens(); + auto server = std::find_if( + screens.begin(), screens.end(), [this](const Screen &screen) { + return (screen.name() == serverConfig().getServerName()); + }); - if (server == screens.end()) { - Screen serverScreen(serverConfig().getServerName()); - serverScreen.markAsServer(); - model().screen(serverConfig().numColumns() / 2, serverConfig().numRows() / 2) = serverScreen; - } - else { - server->markAsServer(); - } + if (server == screens.end()) { + Screen serverScreen(serverConfig().getServerName()); + serverScreen.markAsServer(); + model().screen(serverConfig().numColumns() / 2, + serverConfig().numRows() / 2) = serverScreen; + } else { + server->markAsServer(); + } - m_pButtonAddComputer->setEnabled(!model().isFull()); - connect(m_pTrashScreenWidget, SIGNAL(screenRemoved()), this, SLOT(onScreenRemoved())); + m_pButtonAddComputer->setEnabled(!model().isFull()); + connect(m_pTrashScreenWidget, SIGNAL(screenRemoved()), this, + SLOT(onScreenRemoved())); - onChange(); + onChange(); - //computers - connect(&m_ScreenSetupModel, &ScreenSetupModel::screensChanged, this, &ServerConfigDialog::onChange); + // computers + connect(&m_ScreenSetupModel, &ScreenSetupModel::screensChanged, this, + &ServerConfigDialog::onChange); - //advanced - connect(m_pCheckBoxSwitchDelay, &QCheckBox::stateChanged, - this, [this]( const int& v ) { serverConfig().haveSwitchDelay(v); onChange();}); - connect(m_pSpinBoxSwitchDelay, static_cast(&QSpinBox::valueChanged), - this, [this]( const int& v ) { serverConfig().setSwitchDelay(v); onChange();}); - connect(m_pCheckBoxSwitchDoubleTap, &QCheckBox::stateChanged, - this, [this]( const int& v ) { serverConfig().haveSwitchDoubleTap(v); onChange();}); - connect(m_pSpinBoxSwitchDoubleTap, static_cast(&QSpinBox::valueChanged), - this, [this]( const int& v ) { serverConfig().setSwitchDoubleTap(v); onChange();}); - connect(m_pCheckBoxEnableClipboard, &QCheckBox::stateChanged, - this, [this]( const int& v ) { serverConfig().setClipboardSharing(v); onChange();}); - connect(m_pSpinBoxClipboardSizeLimit, static_cast(&QSpinBox::valueChanged), - this, [this]( const int& v ) { serverConfig().setClipboardSharingSize(v * 1024); onChange();}); - connect(m_pCheckBoxHeartbeat, &QCheckBox::stateChanged, - this, [this]( const int& v ) { serverConfig().haveHeartbeat(v); onChange();}); - connect(m_pSpinBoxHeartbeat, static_cast(&QSpinBox::valueChanged), - this, [this]( const int& v ) { serverConfig().setHeartbeat(v); onChange();}); - connect(m_pCheckBoxRelativeMouseMoves, &QCheckBox::stateChanged, - this, [this]( const int& v ) { serverConfig().setRelativeMouseMoves(v); onChange();}); - connect(m_pCheckBoxWin32KeepForeground, &QCheckBox::stateChanged, - this, [this]( const int& v ) { serverConfig().setWin32KeepForeground(v); onChange();}); - connect(m_pCheckBoxIgnoreAutoConfigClient, &QCheckBox::stateChanged, - this, [this]( const int& v ) { serverConfig().setIgnoreAutoConfigClient(v); onChange();}); - connect(m_pCheckBoxDisableLockToScreen, &QCheckBox::stateChanged, - this, [this]( const int& v ) { serverConfig().setDisableLockToScreen(v); onChange();}); - connect(m_pCheckBoxCornerTopLeft, &QCheckBox::stateChanged, - this, [this]( const int& v ) { serverConfig().setSwitchCorner(BaseConfig::TopLeft, v); onChange();}); - connect(m_pCheckBoxCornerTopRight, &QCheckBox::stateChanged, - this, [this]( const int& v ) { serverConfig().setSwitchCorner(BaseConfig::TopRight, v); onChange();}); - connect(m_pCheckBoxCornerBottomLeft, &QCheckBox::stateChanged, - this, [this]( const int& v ) { serverConfig().setSwitchCorner(BaseConfig::BottomLeft, v); onChange();}); - connect(m_pCheckBoxCornerBottomRight, &QCheckBox::stateChanged, - this, [this]( const int& v ) { serverConfig().setSwitchCorner(BaseConfig::BottomRight, v); onChange();}); - connect(m_pSpinBoxSwitchCornerSize, static_cast(&QSpinBox::valueChanged), - this, [this]( const int& v ) { serverConfig().setSwitchCornerSize(v); onChange();}); - - //config - connect(m_pCheckBoxUseExternalConfig, &QCheckBox::stateChanged, - this, [this]( const int& v ) { serverConfig().setUseExternalConfig(v); onChange();}); - connect(m_pEditConfigFile, &QLineEdit::textChanged, - this, [this]() { serverConfig().setConfigFile(m_pEditConfigFile->text()); onChange();}); -} - -bool ServerConfigDialog::addClient(const QString& clientName) -{ - return addComputer(clientName, true); -} - -void ServerConfigDialog::showEvent(QShowEvent* event) -{ - QDialog::show(); - - if (!m_Message.isEmpty()) - { - // TODO: ideally this massage box should pop up after the dialog is shown - QMessageBox::information(this, tr("Configure server"), m_Message); - } -} - -void ServerConfigDialog::accept() -{ - if (m_pCheckBoxUseExternalConfig->isChecked() && - !QFile::exists(m_pEditConfigFile->text())) - { - auto title = tr("Configuration filename invalid"); - auto description = tr("You have not filled in a valid configuration file for the synergy server. " - "Do you want to browse for the configuration file now?"); - - auto selectedButton = QMessageBox::warning(this, title, description, QMessageBox::Yes | QMessageBox::No); - - if (selectedButton != QMessageBox::Yes || - !on_m_pButtonBrowseConfigFile_clicked()) - { - return; - } - } - - // now that the dialog has been accepted, copy the new server config to the original one, - // which is a reference to the one in MainWindow. - setOrigServerConfig(serverConfig()); - - QDialog::accept(); -} - -void ServerConfigDialog::reject() -{ - serverConfig().setUseExternalConfig(m_OrigServerAppConfigUseExternalConfig); - serverConfig().setConfigFile(m_OrigServerAppConfigExternalConfigFile); - - QDialog::reject(); -} - -void ServerConfigDialog::on_m_pButtonNewHotkey_clicked() -{ - if (serverConfig().isHotkeysAvailable()) { - Hotkey hotkey; - HotkeyDialog dlg(this, hotkey); - if (dlg.exec() == QDialog::Accepted) { - serverConfig().hotkeys().append(hotkey); - m_pListHotkeys->addItem(hotkey.text()); + // advanced + connect(m_pCheckBoxSwitchDelay, &QCheckBox::stateChanged, this, + [this](const int &v) { + serverConfig().haveSwitchDelay(v); onChange(); - } - } - else { - UpgradeDialog upgradeDialog(this); - upgradeDialog.showDialog( - "Configuring custom hotkeys is a Synergy Ultimate feature.", - "synergy/purchase/purchase-ultimate-upgrade?source=gui" - ); - } + }); + connect(m_pSpinBoxSwitchDelay, + static_cast(&QSpinBox::valueChanged), this, + [this](const int &v) { + serverConfig().setSwitchDelay(v); + onChange(); + }); + connect(m_pCheckBoxSwitchDoubleTap, &QCheckBox::stateChanged, this, + [this](const int &v) { + serverConfig().haveSwitchDoubleTap(v); + onChange(); + }); + connect(m_pSpinBoxSwitchDoubleTap, + static_cast(&QSpinBox::valueChanged), this, + [this](const int &v) { + serverConfig().setSwitchDoubleTap(v); + onChange(); + }); + connect(m_pCheckBoxEnableClipboard, &QCheckBox::stateChanged, this, + [this](const int &v) { + serverConfig().setClipboardSharing(v); + onChange(); + }); + connect(m_pSpinBoxClipboardSizeLimit, + static_cast(&QSpinBox::valueChanged), this, + [this](const int &v) { + serverConfig().setClipboardSharingSize(v * 1024); + onChange(); + }); + connect(m_pCheckBoxHeartbeat, &QCheckBox::stateChanged, this, + [this](const int &v) { + serverConfig().haveHeartbeat(v); + onChange(); + }); + connect(m_pSpinBoxHeartbeat, + static_cast(&QSpinBox::valueChanged), this, + [this](const int &v) { + serverConfig().setHeartbeat(v); + onChange(); + }); + connect(m_pCheckBoxRelativeMouseMoves, &QCheckBox::stateChanged, this, + [this](const int &v) { + serverConfig().setRelativeMouseMoves(v); + onChange(); + }); + connect(m_pCheckBoxWin32KeepForeground, &QCheckBox::stateChanged, this, + [this](const int &v) { + serverConfig().setWin32KeepForeground(v); + onChange(); + }); + connect(m_pCheckBoxIgnoreAutoConfigClient, &QCheckBox::stateChanged, this, + [this](const int &v) { + serverConfig().setIgnoreAutoConfigClient(v); + onChange(); + }); + connect(m_pCheckBoxDisableLockToScreen, &QCheckBox::stateChanged, this, + [this](const int &v) { + serverConfig().setDisableLockToScreen(v); + onChange(); + }); + connect(m_pCheckBoxCornerTopLeft, &QCheckBox::stateChanged, this, + [this](const int &v) { + serverConfig().setSwitchCorner(BaseConfig::TopLeft, v); + onChange(); + }); + connect(m_pCheckBoxCornerTopRight, &QCheckBox::stateChanged, this, + [this](const int &v) { + serverConfig().setSwitchCorner(BaseConfig::TopRight, v); + onChange(); + }); + connect(m_pCheckBoxCornerBottomLeft, &QCheckBox::stateChanged, this, + [this](const int &v) { + serverConfig().setSwitchCorner(BaseConfig::BottomLeft, v); + onChange(); + }); + connect(m_pCheckBoxCornerBottomRight, &QCheckBox::stateChanged, this, + [this](const int &v) { + serverConfig().setSwitchCorner(BaseConfig::BottomRight, v); + onChange(); + }); + connect(m_pSpinBoxSwitchCornerSize, + static_cast(&QSpinBox::valueChanged), this, + [this](const int &v) { + serverConfig().setSwitchCornerSize(v); + onChange(); + }); + + // config + connect(m_pCheckBoxUseExternalConfig, &QCheckBox::stateChanged, this, + [this](const int &v) { + serverConfig().setUseExternalConfig(v); + onChange(); + }); + connect(m_pEditConfigFile, &QLineEdit::textChanged, this, [this]() { + serverConfig().setConfigFile(m_pEditConfigFile->text()); + onChange(); + }); } -void ServerConfigDialog::on_m_pButtonEditHotkey_clicked() -{ - int idx = m_pListHotkeys->currentRow(); - Q_ASSERT(idx >= 0 && idx < serverConfig().hotkeys().size()); - Hotkey& hotkey = serverConfig().hotkeys()[idx]; +bool ServerConfigDialog::addClient(const QString &clientName) { + return addComputer(clientName, true); +} + +void ServerConfigDialog::showEvent(QShowEvent *event) { + QDialog::show(); + + if (!m_Message.isEmpty()) { + // TODO: ideally this massage box should pop up after the dialog is shown + QMessageBox::information(this, tr("Configure server"), m_Message); + } +} + +void ServerConfigDialog::accept() { + if (m_pCheckBoxUseExternalConfig->isChecked() && + !QFile::exists(m_pEditConfigFile->text())) { + auto title = tr("Configuration filename invalid"); + auto description = + tr("You have not filled in a valid configuration file for the synergy " + "server. " + "Do you want to browse for the configuration file now?"); + + auto selectedButton = QMessageBox::warning( + this, title, description, QMessageBox::Yes | QMessageBox::No); + + if (selectedButton != QMessageBox::Yes || + !on_m_pButtonBrowseConfigFile_clicked()) { + return; + } + } + + // now that the dialog has been accepted, copy the new server config to the + // original one, which is a reference to the one in MainWindow. + setOrigServerConfig(serverConfig()); + + QDialog::accept(); +} + +void ServerConfigDialog::reject() { + serverConfig().setUseExternalConfig(m_OrigServerAppConfigUseExternalConfig); + serverConfig().setConfigFile(m_OrigServerAppConfigExternalConfigFile); + + QDialog::reject(); +} + +void ServerConfigDialog::on_m_pButtonNewHotkey_clicked() { + if (serverConfig().isHotkeysAvailable()) { + Hotkey hotkey; HotkeyDialog dlg(this, hotkey); if (dlg.exec() == QDialog::Accepted) { - m_pListHotkeys->currentItem()->setText(hotkey.text()); - onChange(); + serverConfig().hotkeys().append(hotkey); + m_pListHotkeys->addItem(hotkey.text()); + onChange(); } + } else { + UpgradeDialog upgradeDialog(this); + upgradeDialog.showDialog( + "Configuring custom hotkeys is a Synergy Ultimate feature.", + "synergy/purchase/purchase-ultimate-upgrade?source=gui"); + } } -void ServerConfigDialog::on_m_pButtonRemoveHotkey_clicked() -{ - int idx = m_pListHotkeys->currentRow(); - Q_ASSERT(idx >= 0 && idx < serverConfig().hotkeys().size()); - serverConfig().hotkeys().removeAt(idx); +void ServerConfigDialog::on_m_pButtonEditHotkey_clicked() { + int idx = m_pListHotkeys->currentRow(); + Q_ASSERT(idx >= 0 && idx < serverConfig().hotkeys().size()); + Hotkey &hotkey = serverConfig().hotkeys()[idx]; + HotkeyDialog dlg(this, hotkey); + if (dlg.exec() == QDialog::Accepted) { + m_pListHotkeys->currentItem()->setText(hotkey.text()); + onChange(); + } +} + +void ServerConfigDialog::on_m_pButtonRemoveHotkey_clicked() { + int idx = m_pListHotkeys->currentRow(); + Q_ASSERT(idx >= 0 && idx < serverConfig().hotkeys().size()); + serverConfig().hotkeys().removeAt(idx); + m_pListActions->clear(); + delete m_pListHotkeys->item(idx); + onChange(); +} + +void ServerConfigDialog::on_m_pListHotkeys_itemSelectionChanged() { + bool itemsSelected = !m_pListHotkeys->selectedItems().isEmpty(); + m_pButtonEditHotkey->setEnabled(itemsSelected); + m_pButtonRemoveHotkey->setEnabled(itemsSelected); + m_pButtonNewAction->setEnabled(itemsSelected); + + if (itemsSelected && serverConfig().hotkeys().size() > 0) { m_pListActions->clear(); - delete m_pListHotkeys->item(idx); - onChange(); -} -void ServerConfigDialog::on_m_pListHotkeys_itemSelectionChanged() -{ - bool itemsSelected = !m_pListHotkeys->selectedItems().isEmpty(); - m_pButtonEditHotkey->setEnabled(itemsSelected); - m_pButtonRemoveHotkey->setEnabled(itemsSelected); - m_pButtonNewAction->setEnabled(itemsSelected); + int idx = m_pListHotkeys->row(m_pListHotkeys->selectedItems()[0]); - if (itemsSelected && serverConfig().hotkeys().size() > 0) - { - m_pListActions->clear(); + // There's a bug somewhere around here: We get idx == 1 right after we + // deleted the next to last item, so idx can only possibly be 0. GDB shows + // we got called indirectly from the delete line in + // on_m_pButtonRemoveHotkey_clicked() above, but the delete is of course + // necessary and seems correct. The while() is a generalized workaround for + // all that and shouldn't be required. + while (idx >= 0 && idx >= serverConfig().hotkeys().size()) + idx--; - int idx = m_pListHotkeys->row(m_pListHotkeys->selectedItems()[0]); - - // There's a bug somewhere around here: We get idx == 1 right after we deleted the next to last item, so idx can - // only possibly be 0. GDB shows we got called indirectly from the delete line in - // on_m_pButtonRemoveHotkey_clicked() above, but the delete is of course necessary and seems correct. - // The while() is a generalized workaround for all that and shouldn't be required. - while (idx >= 0 && idx >= serverConfig().hotkeys().size()) - idx--; - - Q_ASSERT(idx >= 0 && idx < serverConfig().hotkeys().size()); - - const Hotkey& hotkey = serverConfig().hotkeys()[idx]; - foreach(const Action& action, hotkey.actions()) - m_pListActions->addItem(action.text()); - } -} - -void ServerConfigDialog::on_m_pButtonNewAction_clicked() -{ - int idx = m_pListHotkeys->currentRow(); Q_ASSERT(idx >= 0 && idx < serverConfig().hotkeys().size()); - Hotkey& hotkey = serverConfig().hotkeys()[idx]; - Action action; - ActionDialog dlg(this, serverConfig(), hotkey, action); - if (dlg.exec() == QDialog::Accepted) - { - hotkey.actions().append(action); - m_pListActions->addItem(action.text()); - onChange(); - } + const Hotkey &hotkey = serverConfig().hotkeys()[idx]; + foreach (const Action &action, hotkey.actions()) + m_pListActions->addItem(action.text()); + } } -void ServerConfigDialog::on_m_pButtonEditAction_clicked() -{ - int idxHotkey = m_pListHotkeys->currentRow(); - Q_ASSERT(idxHotkey >= 0 && idxHotkey < serverConfig().hotkeys().size()); - Hotkey& hotkey = serverConfig().hotkeys()[idxHotkey]; +void ServerConfigDialog::on_m_pButtonNewAction_clicked() { + int idx = m_pListHotkeys->currentRow(); + Q_ASSERT(idx >= 0 && idx < serverConfig().hotkeys().size()); + Hotkey &hotkey = serverConfig().hotkeys()[idx]; - int idxAction = m_pListActions->currentRow(); - Q_ASSERT(idxAction >= 0 && idxAction < hotkey.actions().size()); - Action& action = hotkey.actions()[idxAction]; - - ActionDialog dlg(this, serverConfig(), hotkey, action); - if (dlg.exec() == QDialog::Accepted) { - m_pListActions->currentItem()->setText(action.text()); - onChange(); - } -} - -void ServerConfigDialog::on_m_pButtonRemoveAction_clicked() -{ - int idxHotkey = m_pListHotkeys->currentRow(); - Q_ASSERT(idxHotkey >= 0 && idxHotkey < serverConfig().hotkeys().size()); - Hotkey& hotkey = serverConfig().hotkeys()[idxHotkey]; - - int idxAction = m_pListActions->currentRow(); - Q_ASSERT(idxAction >= 0 && idxAction < hotkey.actions().size()); - - hotkey.actions().removeAt(idxAction); - delete m_pListActions->currentItem(); + Action action; + ActionDialog dlg(this, serverConfig(), hotkey, action); + if (dlg.exec() == QDialog::Accepted) { + hotkey.actions().append(action); + m_pListActions->addItem(action.text()); onChange(); + } } -void ServerConfigDialog::on_m_pCheckBoxEnableClipboard_stateChanged(int const state) -{ - m_pSpinBoxClipboardSizeLimit->setEnabled (state == Qt::Checked); - if ((state == Qt::Checked) && (!m_pSpinBoxClipboardSizeLimit->value())) { - int size = static_cast((serverConfig().defaultClipboardSharingSize() + 512) / 1024); - m_pSpinBoxClipboardSizeLimit->setValue (size ? size : 1); - } -} +void ServerConfigDialog::on_m_pButtonEditAction_clicked() { + int idxHotkey = m_pListHotkeys->currentRow(); + Q_ASSERT(idxHotkey >= 0 && idxHotkey < serverConfig().hotkeys().size()); + Hotkey &hotkey = serverConfig().hotkeys()[idxHotkey]; -void ServerConfigDialog::on_m_pListActions_itemSelectionChanged() -{ - m_pButtonEditAction->setEnabled(!m_pListActions->selectedItems().isEmpty()); - m_pButtonRemoveAction->setEnabled(!m_pListActions->selectedItems().isEmpty()); -} + int idxAction = m_pListActions->currentRow(); + Q_ASSERT(idxAction >= 0 && idxAction < hotkey.actions().size()); + Action &action = hotkey.actions()[idxAction]; -void ServerConfigDialog::on_m_pButtonAddComputer_clicked() -{ - addComputer("", false); -} - -void ServerConfigDialog::onScreenRemoved() -{ - m_pButtonAddComputer->setEnabled(true); + ActionDialog dlg(this, serverConfig(), hotkey, action); + if (dlg.exec() == QDialog::Accepted) { + m_pListActions->currentItem()->setText(action.text()); onChange(); + } } -void ServerConfigDialog::on_m_pCheckBoxUseExternalConfig_toggled(bool checked) -{ - m_pLabelConfigFile->setEnabled(checked); - m_pEditConfigFile->setEnabled(checked); - m_pButtonBrowseConfigFile->setEnabled(checked); +void ServerConfigDialog::on_m_pButtonRemoveAction_clicked() { + int idxHotkey = m_pListHotkeys->currentRow(); + Q_ASSERT(idxHotkey >= 0 && idxHotkey < serverConfig().hotkeys().size()); + Hotkey &hotkey = serverConfig().hotkeys()[idxHotkey]; - m_pTabWidget->setTabEnabled(0, !checked); - m_pTabWidget->setTabEnabled(1, !checked); - m_pTabWidget->setTabEnabled(2, !checked); + int idxAction = m_pListActions->currentRow(); + Q_ASSERT(idxAction >= 0 && idxAction < hotkey.actions().size()); + + hotkey.actions().removeAt(idxAction); + delete m_pListActions->currentItem(); + onChange(); } -bool ServerConfigDialog::on_m_pButtonBrowseConfigFile_clicked() -{ +void ServerConfigDialog::on_m_pCheckBoxEnableClipboard_stateChanged( + int const state) { + m_pSpinBoxClipboardSizeLimit->setEnabled(state == Qt::Checked); + if ((state == Qt::Checked) && (!m_pSpinBoxClipboardSizeLimit->value())) { + int size = static_cast( + (serverConfig().defaultClipboardSharingSize() + 512) / 1024); + m_pSpinBoxClipboardSizeLimit->setValue(size ? size : 1); + } +} + +void ServerConfigDialog::on_m_pListActions_itemSelectionChanged() { + m_pButtonEditAction->setEnabled(!m_pListActions->selectedItems().isEmpty()); + m_pButtonRemoveAction->setEnabled(!m_pListActions->selectedItems().isEmpty()); +} + +void ServerConfigDialog::on_m_pButtonAddComputer_clicked() { + addComputer("", false); +} + +void ServerConfigDialog::onScreenRemoved() { + m_pButtonAddComputer->setEnabled(true); + onChange(); +} + +void ServerConfigDialog::on_m_pCheckBoxUseExternalConfig_toggled(bool checked) { + m_pLabelConfigFile->setEnabled(checked); + m_pEditConfigFile->setEnabled(checked); + m_pButtonBrowseConfigFile->setEnabled(checked); + + m_pTabWidget->setTabEnabled(0, !checked); + m_pTabWidget->setTabEnabled(1, !checked); + m_pTabWidget->setTabEnabled(2, !checked); +} + +bool ServerConfigDialog::on_m_pButtonBrowseConfigFile_clicked() { #if defined(Q_OS_WIN) - const QString synergyConfigFilter(QObject::tr("Synergy Configurations (*.sgc);;All files (*.*)")); + const QString synergyConfigFilter( + QObject::tr("Synergy Configurations (*.sgc);;All files (*.*)")); #else - const QString synergyConfigFilter(QObject::tr("Synergy Configurations (*.conf);;All files (*.*)")); + const QString synergyConfigFilter( + QObject::tr("Synergy Configurations (*.conf);;All files (*.*)")); #endif - QString fileName = QFileDialog::getOpenFileName(this, tr("Browse for a synergys config file"), QString(), synergyConfigFilter); + QString fileName = QFileDialog::getOpenFileName( + this, tr("Browse for a synergys config file"), QString(), + synergyConfigFilter); - if (!fileName.isEmpty()) - { - m_pEditConfigFile->setText(fileName); - return true; - } + if (!fileName.isEmpty()) { + m_pEditConfigFile->setText(fileName); + return true; + } - return false; + return false; } -bool ServerConfigDialog::addComputer(const QString& clientName, bool doSilent) -{ - bool isAccepted = false; - Screen newScreen(clientName); +bool ServerConfigDialog::addComputer(const QString &clientName, bool doSilent) { + bool isAccepted = false; + Screen newScreen(clientName); + ScreenSettingsDialog dlg(this, &newScreen, &model().m_Screens); + if (doSilent || dlg.exec() == QDialog::Accepted) { + model().addScreen(newScreen); + isAccepted = true; + } - ScreenSettingsDialog dlg(this, &newScreen, &model().m_Screens); - if (doSilent || dlg.exec() == QDialog::Accepted) - { - model().addScreen(newScreen); - isAccepted = true; - } - - m_pButtonAddComputer->setEnabled(!model().isFull()); - return isAccepted; + m_pButtonAddComputer->setEnabled(!model().isFull()); + return isAccepted; } -void ServerConfigDialog::onChange() -{ - bool isAppConfigDataEqual = m_OrigServerAppConfigUseExternalConfig == serverConfig().getUseExternalConfig() && - m_OrigServerAppConfigExternalConfigFile == serverConfig().getConfigFile(); - m_pButtonBox->button(QDialogButtonBox::Ok)->setEnabled(!isAppConfigDataEqual || !(m_OrigServerConfig == m_ServerConfig)); +void ServerConfigDialog::onChange() { + bool isAppConfigDataEqual = + m_OrigServerAppConfigUseExternalConfig == + serverConfig().getUseExternalConfig() && + m_OrigServerAppConfigExternalConfigFile == serverConfig().getConfigFile(); + m_pButtonBox->button(QDialogButtonBox::Ok) + ->setEnabled(!isAppConfigDataEqual || + !(m_OrigServerConfig == m_ServerConfig)); } diff --git a/src/gui/src/ServerConfigDialog.h b/src/gui/src/ServerConfigDialog.h index 0d880e815..dab541850 100644 --- a/src/gui/src/ServerConfigDialog.h +++ b/src/gui/src/ServerConfigDialog.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2008 Volker Lanz (vl@fidra.de) - * + * * 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 LICENSE 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 @@ -27,53 +27,51 @@ #include -class ServerConfigDialog : public QDialog, public Ui::ServerConfigDialogBase -{ - Q_OBJECT +class ServerConfigDialog : public QDialog, public Ui::ServerConfigDialogBase { + Q_OBJECT - public: - ServerConfigDialog(QWidget* parent, ServerConfig& config); - bool addClient(const QString& clientName); +public: + ServerConfigDialog(QWidget *parent, ServerConfig &config); + bool addClient(const QString &clientName); - public slots: - void accept(); - void reject() override; - void showEvent(QShowEvent* event); - void message(const QString& message) { m_Message = message; } +public slots: + void accept(); + void reject() override; + void showEvent(QShowEvent *event); + void message(const QString &message) { m_Message = message; } - protected slots: - void on_m_pButtonNewHotkey_clicked(); - void on_m_pListHotkeys_itemSelectionChanged(); - void on_m_pButtonEditHotkey_clicked(); - void on_m_pButtonRemoveHotkey_clicked(); +protected slots: + void on_m_pButtonNewHotkey_clicked(); + void on_m_pListHotkeys_itemSelectionChanged(); + void on_m_pButtonEditHotkey_clicked(); + void on_m_pButtonRemoveHotkey_clicked(); - void on_m_pButtonNewAction_clicked(); - void on_m_pListActions_itemSelectionChanged(); - void on_m_pButtonEditAction_clicked(); - void on_m_pButtonRemoveAction_clicked(); - void on_m_pCheckBoxEnableClipboard_stateChanged(int state); - void on_m_pButtonAddComputer_clicked(); - void onScreenRemoved(); - void on_m_pCheckBoxUseExternalConfig_toggled(bool checked = false); - bool on_m_pButtonBrowseConfigFile_clicked(); + void on_m_pButtonNewAction_clicked(); + void on_m_pListActions_itemSelectionChanged(); + void on_m_pButtonEditAction_clicked(); + void on_m_pButtonRemoveAction_clicked(); + void on_m_pCheckBoxEnableClipboard_stateChanged(int state); + void on_m_pButtonAddComputer_clicked(); + void onScreenRemoved(); + void on_m_pCheckBoxUseExternalConfig_toggled(bool checked = false); + bool on_m_pButtonBrowseConfigFile_clicked(); - protected: - bool addComputer(const QString& clientName, bool doSilent); - ServerConfig& serverConfig() { return m_ServerConfig; } - void setOrigServerConfig(const ServerConfig& s) { m_OrigServerConfig = s; } - ScreenSetupModel& model() { return m_ScreenSetupModel; } +protected: + bool addComputer(const QString &clientName, bool doSilent); + ServerConfig &serverConfig() { return m_ServerConfig; } + void setOrigServerConfig(const ServerConfig &s) { m_OrigServerConfig = s; } + ScreenSetupModel &model() { return m_ScreenSetupModel; } - private: - ServerConfig& m_OrigServerConfig; - bool m_OrigServerAppConfigUseExternalConfig; - QString m_OrigServerAppConfigExternalConfigFile; - ServerConfig m_ServerConfig; - ScreenSetupModel m_ScreenSetupModel; - QString m_Message; +private: + ServerConfig &m_OrigServerConfig; + bool m_OrigServerAppConfigUseExternalConfig; + QString m_OrigServerAppConfigExternalConfigFile; + ServerConfig m_ServerConfig; + ScreenSetupModel m_ScreenSetupModel; + QString m_Message; - private slots: - void onChange(); +private slots: + void onChange(); }; #endif - diff --git a/src/gui/src/ServerConnection.cpp b/src/gui/src/ServerConnection.cpp index 769a6d55b..42107e166 100644 --- a/src/gui/src/ServerConnection.cpp +++ b/src/gui/src/ServerConnection.cpp @@ -24,66 +24,53 @@ #include +ServerConnection::ServerConnection(MainWindow &parent) : m_parent(parent) {} -ServerConnection::ServerConnection(MainWindow& parent) : - m_parent(parent) -{ +void ServerConnection::update(const QString &line) { + ServerMessage message(line); + if (!m_parent.appConfig().getUseExternalConfig() && + message.isNewClientMessage() && + !m_ignoredClients.contains(message.getClientName())) { + addClient(message.getClientName()); + } } -void ServerConnection::update(const QString& line) -{ - ServerMessage message(line); +bool ServerConnection::checkMainWindow() { + bool result = m_parent.isActiveWindow(); - if (!m_parent.appConfig().getUseExternalConfig() && - message.isNewClientMessage() && - !m_ignoredClients.contains(message.getClientName())) - { - addClient(message.getClientName()); + if (m_parent.isMinimized() || m_parent.isHidden()) { + m_parent.showNormal(); + m_parent.activateWindow(); + result = true; + } + + return result; +} + +void ServerConnection::addClient(const QString &clientName) { + if (!m_parent.serverConfig().isFull() && + !m_parent.serverConfig().isScreenExists(clientName) && + checkMainWindow()) { + QMessageBox message(&m_parent); + message.addButton(QObject::tr("Ignore"), QMessageBox::RejectRole); + message.addButton(QObject::tr("Accept and configure"), + QMessageBox::AcceptRole); + message.setText( + QObject::tr("%1 client has made a connection request").arg(clientName)); + + if (message.exec() == QMessageBox::Accepted) { + configureClient(clientName); + } else { + m_ignoredClients.append(clientName); } + } } -bool ServerConnection::checkMainWindow() -{ - bool result = m_parent.isActiveWindow(); +void ServerConnection::configureClient(const QString &clientName) { + ServerConfigDialog dlg(&m_parent, m_parent.serverConfig()); - if (m_parent.isMinimized() || m_parent.isHidden()) - { - m_parent.showNormal(); - m_parent.activateWindow(); - result = true; - } - - return result; -} - -void ServerConnection::addClient(const QString& clientName) -{ - if (!m_parent.serverConfig().isFull() && - !m_parent.serverConfig().isScreenExists(clientName) && - checkMainWindow()) - { - QMessageBox message(&m_parent); - message.addButton(QObject::tr("Ignore"), QMessageBox::RejectRole); - message.addButton(QObject::tr("Accept and configure"), QMessageBox::AcceptRole); - message.setText(QObject::tr("%1 client has made a connection request").arg(clientName)); - - if (message.exec() == QMessageBox::Accepted) - { - configureClient(clientName); - } - else - { - m_ignoredClients.append(clientName); - } - } -} - -void ServerConnection::configureClient(const QString& clientName) -{ - ServerConfigDialog dlg(&m_parent, m_parent.serverConfig()); - - if(dlg.addClient(clientName) && dlg.exec() == QDialog::Accepted) { - m_parent.restartSynergy(); - } + if (dlg.addClient(clientName) && dlg.exec() == QDialog::Accepted) { + m_parent.restartSynergy(); + } } diff --git a/src/gui/src/ServerConnection.h b/src/gui/src/ServerConnection.h index 9a8731730..954b7bf1c 100644 --- a/src/gui/src/ServerConnection.h +++ b/src/gui/src/ServerConnection.h @@ -24,19 +24,18 @@ class MainWindow; -class ServerConnection -{ - MainWindow& m_parent; - QStringList m_ignoredClients; +class ServerConnection { + MainWindow &m_parent; + QStringList m_ignoredClients; public: - explicit ServerConnection(MainWindow& parent); - void update(const QString& line); + explicit ServerConnection(MainWindow &parent); + void update(const QString &line); private: - void addClient(const QString& clientName); - void configureClient(const QString& clientName); - bool checkMainWindow(); + void addClient(const QString &clientName); + void configureClient(const QString &clientName); + bool checkMainWindow(); }; #endif // SERVERCONNECTION_H diff --git a/src/gui/src/ServerMessage.cpp b/src/gui/src/ServerMessage.cpp index d1fa625ac..96810ce1e 100644 --- a/src/gui/src/ServerMessage.cpp +++ b/src/gui/src/ServerMessage.cpp @@ -17,48 +17,35 @@ */ #include "ServerMessage.h" -ServerMessage::ServerMessage(const QString& message) : - m_message(message), - m_clienName(parseClientName(message)) -{ +ServerMessage::ServerMessage(const QString &message) + : m_message(message), m_clienName(parseClientName(message)) {} +bool ServerMessage::isNewClientMessage() const { + return m_message.contains("unrecognised client name"); } -bool ServerMessage::isNewClientMessage() const -{ - return m_message.contains("unrecognised client name"); +bool ServerMessage::isExitMessage() const { + return m_message.contains("process exited"); } -bool ServerMessage::isExitMessage() const -{ - return m_message.contains("process exited"); +bool ServerMessage::isConnectedMessage() const { + return m_message.contains("has connected"); } -bool ServerMessage::isConnectedMessage() const -{ - return m_message.contains("has connected"); +bool ServerMessage::isDisconnectedMessage() const { + return m_message.contains("has disconnected"); } -bool ServerMessage::isDisconnectedMessage() const -{ - return m_message.contains("has disconnected"); -} - -const QString& ServerMessage::getClientName() const -{ - return m_clienName; -} - -QString ServerMessage::parseClientName(const QString& line) const -{ - QString clientName("Unknown"); - auto nameStart = line.indexOf('"') + 1; - auto nameEnd = line.indexOf('"', nameStart); - - if (nameEnd > nameStart) - { - clientName = line.mid(nameStart, nameEnd - nameStart); - } - - return clientName; +const QString &ServerMessage::getClientName() const { return m_clienName; } + +QString ServerMessage::parseClientName(const QString &line) const { + QString clientName("Unknown"); + auto nameStart = line.indexOf('"') + 1; + auto nameEnd = line.indexOf('"', nameStart); + + if (nameEnd > nameStart) { + clientName = line.mid(nameStart, nameEnd - nameStart); + } + + return clientName; } diff --git a/src/gui/src/ServerMessage.h b/src/gui/src/ServerMessage.h index 4efd02375..e162dad1d 100644 --- a/src/gui/src/ServerMessage.h +++ b/src/gui/src/ServerMessage.h @@ -21,24 +21,22 @@ #include -class ServerMessage -{ - QString m_message; - QString m_clienName; +class ServerMessage { + QString m_message; + QString m_clienName; public: - explicit ServerMessage(const QString& message); + explicit ServerMessage(const QString &message); - bool isNewClientMessage() const; - bool isExitMessage() const; - bool isConnectedMessage() const; - bool isDisconnectedMessage() const; + bool isNewClientMessage() const; + bool isExitMessage() const; + bool isConnectedMessage() const; + bool isDisconnectedMessage() const; - const QString& getClientName() const; + const QString &getClientName() const; private: - QString parseClientName(const QString& line) const; - + QString parseClientName(const QString &line) const; }; #endif // SERVERMESSAGE_H diff --git a/src/gui/src/SettingsDialog.cpp b/src/gui/src/SettingsDialog.cpp index bce376f60..3e2b6ac23 100644 --- a/src/gui/src/SettingsDialog.cpp +++ b/src/gui/src/SettingsDialog.cpp @@ -18,421 +18,417 @@ #include "SettingsDialog.h" #include "validators/ScreenNameValidator.h" +#include "AppConfig.h" +#include "BonjourWindows.h" #include "CoreInterface.h" -#include "SynergyLocale.h" +#include "MainWindow.h" #include "QSynergyApplication.h" #include "QUtility.h" -#include "AppConfig.h" #include "SslCertificate.h" -#include "MainWindow.h" -#include "BonjourWindows.h" -#include "Zeroconf.h" +#include "SynergyLocale.h" #include "UpgradeDialog.h" +#include "Zeroconf.h" +#include +#include +#include #include #include -#include -#include -#include -SettingsDialog::SettingsDialog(QWidget* parent, AppConfig& config) : - QDialog(parent, Qt::WindowTitleHint | Qt::WindowSystemMenuHint), - Ui::SettingsDialogBase(), - m_appConfig(config), - m_pBonjourWindows(nullptr) -{ - setupUi(this); +SettingsDialog::SettingsDialog(QWidget *parent, AppConfig &config) + : QDialog(parent, Qt::WindowTitleHint | Qt::WindowSystemMenuHint), + Ui::SettingsDialogBase(), m_appConfig(config), + m_pBonjourWindows(nullptr) { + setupUi(this); - // TODO: maybe just accept MainWindow type in ctor? - m_pMainWindow = dynamic_cast(parent); + // TODO: maybe just accept MainWindow type in ctor? + m_pMainWindow = dynamic_cast(parent); - m_Locale.fillLanguageComboBox(m_pComboLanguage); + m_Locale.fillLanguageComboBox(m_pComboLanguage); - loadFromConfig(); - m_isSystemAtStart = appConfig().isSystemScoped(); - buttonBox->button(QDialogButtonBox::Save)->setEnabled(false); - enableControls(appConfig().isWritable()); + loadFromConfig(); + m_isSystemAtStart = appConfig().isSystemScoped(); + buttonBox->button(QDialogButtonBox::Save)->setEnabled(false); + enableControls(appConfig().isWritable()); - m_pCheckBoxLanguageSync->setVisible(isClientMode()); - m_pCheckBoxScrollDirection->setVisible(isClientMode()); + m_pCheckBoxLanguageSync->setVisible(isClientMode()); + m_pCheckBoxScrollDirection->setVisible(isClientMode()); - const auto& serveConfig = m_pMainWindow->serverConfig(); - m_pLineEditScreenName->setValidator(new validators::ScreenNameValidator(m_pLineEditScreenName, m_pLabelNameError, (&serveConfig.screens()))); + const auto &serveConfig = m_pMainWindow->serverConfig(); + m_pLineEditScreenName->setValidator(new validators::ScreenNameValidator( + m_pLineEditScreenName, m_pLabelNameError, (&serveConfig.screens()))); - connect(m_pLineEditLogFilename, SIGNAL(textChanged(QString)), this, SLOT(onChange())); - connect(m_pComboLogLevel, SIGNAL(currentIndexChanged(int)), this, SLOT(onChange())); - connect(m_pLineEditCertificatePath, SIGNAL(textChanged(QString)), this, SLOT(onChange())); - connect(m_pCheckBoxAutoConfig, SIGNAL(clicked()), this, SLOT(onChange())); - connect(m_pCheckBoxMinimizeToTray, SIGNAL(clicked()), this, SLOT(onChange())); - connect(m_pCheckBoxAutoHide, SIGNAL(clicked()), this, SLOT(onChange())); - connect(m_pCheckBoxPreventSleep, SIGNAL(clicked()), this, SLOT(onChange())); - connect(m_pLineEditInterface, SIGNAL(textEdited(QString)), this, SLOT(onChange())); - connect(m_pSpinBoxPort, SIGNAL(valueChanged(int)), this, SLOT(onChange())); - connect(m_pLineEditScreenName, SIGNAL(textEdited(QString)), this, SLOT(onChange())); - connect(m_pComboElevate, SIGNAL(currentIndexChanged(int)), this, SLOT(onChange())); - connect(m_pCheckBoxLanguageSync, SIGNAL(clicked()), this, SLOT(onChange())); - connect(m_pCheckBoxScrollDirection, SIGNAL(clicked()), this, SLOT(onChange())); - connect(m_pCheckBoxClientHostMode, SIGNAL(clicked()), this, SLOT(onChange())); - connect(m_pCheckBoxServerClientMode,SIGNAL(clicked()), this, SLOT(onChange())); + connect(m_pLineEditLogFilename, SIGNAL(textChanged(QString)), this, + SLOT(onChange())); + connect(m_pComboLogLevel, SIGNAL(currentIndexChanged(int)), this, + SLOT(onChange())); + connect(m_pLineEditCertificatePath, SIGNAL(textChanged(QString)), this, + SLOT(onChange())); + connect(m_pCheckBoxAutoConfig, SIGNAL(clicked()), this, SLOT(onChange())); + connect(m_pCheckBoxMinimizeToTray, SIGNAL(clicked()), this, SLOT(onChange())); + connect(m_pCheckBoxAutoHide, SIGNAL(clicked()), this, SLOT(onChange())); + connect(m_pCheckBoxPreventSleep, SIGNAL(clicked()), this, SLOT(onChange())); + connect(m_pLineEditInterface, SIGNAL(textEdited(QString)), this, + SLOT(onChange())); + connect(m_pSpinBoxPort, SIGNAL(valueChanged(int)), this, SLOT(onChange())); + connect(m_pLineEditScreenName, SIGNAL(textEdited(QString)), this, + SLOT(onChange())); + connect(m_pComboElevate, SIGNAL(currentIndexChanged(int)), this, + SLOT(onChange())); + connect(m_pCheckBoxLanguageSync, SIGNAL(clicked()), this, SLOT(onChange())); + connect(m_pCheckBoxScrollDirection, SIGNAL(clicked()), this, + SLOT(onChange())); + connect(m_pCheckBoxClientHostMode, SIGNAL(clicked()), this, SLOT(onChange())); + connect(m_pCheckBoxServerClientMode, SIGNAL(clicked()), this, + SLOT(onChange())); - adjustSize(); + adjustSize(); } -void SettingsDialog::accept() -{ - appConfig().setLoadFromSystemScope(m_pRadioSystemScope->isChecked()); - appConfig().setScreenName(m_pLineEditScreenName->text()); - appConfig().setPort(m_pSpinBoxPort->value()); - appConfig().setNetworkInterface(m_pLineEditInterface->text()); - appConfig().setLogLevel(m_pComboLogLevel->currentIndex()); - appConfig().setLogToFile(m_pCheckBoxLogToFile->isChecked()); - appConfig().setLogFilename(m_pLineEditLogFilename->text()); - appConfig().setLanguage(m_pComboLanguage->itemData(m_pComboLanguage->currentIndex()).toString()); - appConfig().setElevateMode(static_cast(m_pComboElevate->currentIndex())); - appConfig().setAutoHide(m_pCheckBoxAutoHide->isChecked()); - appConfig().setPreventSleep(m_pCheckBoxPreventSleep->isChecked()); - appConfig().setAutoConfig(m_pCheckBoxAutoConfig->isChecked()); - appConfig().setMinimizeToTray(m_pCheckBoxMinimizeToTray->isChecked()); - appConfig().setTLSCertPath(m_pLineEditCertificatePath->text()); - appConfig().setTLSKeyLength(m_pComboBoxKeyLength->currentText()); - appConfig().setCryptoEnabled(m_pCheckBoxEnableCrypto->isChecked()); - appConfig().setLanguageSync(m_pCheckBoxLanguageSync->isChecked()); - appConfig().setInvertScrollDirection(m_pCheckBoxScrollDirection->isChecked()); - appConfig().setClientHostMode(m_pCheckBoxClientHostMode->isChecked()); - appConfig().setServerClientMode(m_pCheckBoxServerClientMode->isChecked()); +void SettingsDialog::accept() { + appConfig().setLoadFromSystemScope(m_pRadioSystemScope->isChecked()); + appConfig().setScreenName(m_pLineEditScreenName->text()); + appConfig().setPort(m_pSpinBoxPort->value()); + appConfig().setNetworkInterface(m_pLineEditInterface->text()); + appConfig().setLogLevel(m_pComboLogLevel->currentIndex()); + appConfig().setLogToFile(m_pCheckBoxLogToFile->isChecked()); + appConfig().setLogFilename(m_pLineEditLogFilename->text()); + appConfig().setLanguage( + m_pComboLanguage->itemData(m_pComboLanguage->currentIndex()).toString()); + appConfig().setElevateMode( + static_cast(m_pComboElevate->currentIndex())); + appConfig().setAutoHide(m_pCheckBoxAutoHide->isChecked()); + appConfig().setPreventSleep(m_pCheckBoxPreventSleep->isChecked()); + appConfig().setAutoConfig(m_pCheckBoxAutoConfig->isChecked()); + appConfig().setMinimizeToTray(m_pCheckBoxMinimizeToTray->isChecked()); + appConfig().setTLSCertPath(m_pLineEditCertificatePath->text()); + appConfig().setTLSKeyLength(m_pComboBoxKeyLength->currentText()); + appConfig().setCryptoEnabled(m_pCheckBoxEnableCrypto->isChecked()); + appConfig().setLanguageSync(m_pCheckBoxLanguageSync->isChecked()); + appConfig().setInvertScrollDirection(m_pCheckBoxScrollDirection->isChecked()); + appConfig().setClientHostMode(m_pCheckBoxClientHostMode->isChecked()); + appConfig().setServerClientMode(m_pCheckBoxServerClientMode->isChecked()); - appConfig().saveSettings(); - QDialog::accept(); + appConfig().saveSettings(); + QDialog::accept(); } -void SettingsDialog::reject() -{ - if (appConfig().language() != m_pComboLanguage->itemData(m_pComboLanguage->currentIndex()).toString()) { - QSynergyApplication::getInstance()->switchTranslator(appConfig().language()); - } +void SettingsDialog::reject() { + if (appConfig().language() != + m_pComboLanguage->itemData(m_pComboLanguage->currentIndex()).toString()) { + QSynergyApplication::getInstance()->switchTranslator( + appConfig().language()); + } - // We should restore scope at start if the user rejects changes. - if (appConfig().isSystemScoped() != m_isSystemAtStart) { - appConfig().setLoadFromSystemScope(m_isSystemAtStart); - } + // We should restore scope at start if the user rejects changes. + if (appConfig().isSystemScoped() != m_isSystemAtStart) { + appConfig().setLoadFromSystemScope(m_isSystemAtStart); + } - QDialog::reject(); + QDialog::reject(); } -void SettingsDialog::changeEvent(QEvent* event) -{ - if (event != nullptr) - { - switch (event->type()) - { - case QEvent::LanguageChange: - { - int logLevelIndex = m_pComboLogLevel->currentIndex(); +void SettingsDialog::changeEvent(QEvent *event) { + if (event != nullptr) { + switch (event->type()) { + case QEvent::LanguageChange: { + int logLevelIndex = m_pComboLogLevel->currentIndex(); - m_pComboLanguage->blockSignals(true); - retranslateUi(this); - m_pComboLanguage->blockSignals(false); + m_pComboLanguage->blockSignals(true); + retranslateUi(this); + m_pComboLanguage->blockSignals(false); - m_pComboLogLevel->setCurrentIndex(logLevelIndex); - break; - } - - default: - QDialog::changeEvent(event); - } + m_pComboLogLevel->setCurrentIndex(logLevelIndex); + break; } + + default: + QDialog::changeEvent(event); + } + } } void SettingsDialog::loadFromConfig() { - m_pLineEditScreenName->setText(appConfig().screenName()); - m_pSpinBoxPort->setValue(appConfig().port()); - m_pLineEditInterface->setText(appConfig().networkInterface()); - m_pComboLogLevel->setCurrentIndex(appConfig().logLevel()); - m_pCheckBoxLogToFile->setChecked(appConfig().logToFile()); - m_pLineEditLogFilename->setText(appConfig().logFilename()); - setIndexFromItemData(m_pComboLanguage, appConfig().language()); - m_pCheckBoxAutoHide->setChecked(appConfig().getAutoHide()); - m_pCheckBoxPreventSleep->setChecked(appConfig().getPreventSleep()); - m_pCheckBoxMinimizeToTray->setChecked(appConfig().getMinimizeToTray()); - m_pLineEditCertificatePath->setText(appConfig().getTLSCertPath()); - m_pCheckBoxEnableCrypto->setChecked(m_appConfig.getCryptoEnabled()); - m_pCheckBoxLanguageSync->setChecked(m_appConfig.getLanguageSync()); - m_pCheckBoxScrollDirection->setChecked(m_appConfig.getInvertScrollDirection()); - m_pCheckBoxClientHostMode->setChecked(m_appConfig.getClientHostMode()); - m_pCheckBoxServerClientMode->setChecked(m_appConfig.getServerClientMode()); + m_pLineEditScreenName->setText(appConfig().screenName()); + m_pSpinBoxPort->setValue(appConfig().port()); + m_pLineEditInterface->setText(appConfig().networkInterface()); + m_pComboLogLevel->setCurrentIndex(appConfig().logLevel()); + m_pCheckBoxLogToFile->setChecked(appConfig().logToFile()); + m_pLineEditLogFilename->setText(appConfig().logFilename()); + setIndexFromItemData(m_pComboLanguage, appConfig().language()); + m_pCheckBoxAutoHide->setChecked(appConfig().getAutoHide()); + m_pCheckBoxPreventSleep->setChecked(appConfig().getPreventSleep()); + m_pCheckBoxMinimizeToTray->setChecked(appConfig().getMinimizeToTray()); + m_pLineEditCertificatePath->setText(appConfig().getTLSCertPath()); + m_pCheckBoxEnableCrypto->setChecked(m_appConfig.getCryptoEnabled()); + m_pCheckBoxLanguageSync->setChecked(m_appConfig.getLanguageSync()); + m_pCheckBoxScrollDirection->setChecked( + m_appConfig.getInvertScrollDirection()); + m_pCheckBoxClientHostMode->setChecked(m_appConfig.getClientHostMode()); + m_pCheckBoxServerClientMode->setChecked(m_appConfig.getServerClientMode()); - setupSeurity(); + setupSeurity(); - if (m_appConfig.isSystemScoped()) { - m_pRadioSystemScope->setChecked(true); - } - else { - m_pRadioUserScope->setChecked(true); - } + if (m_appConfig.isSystemScoped()) { + m_pRadioSystemScope->setChecked(true); + } else { + m_pRadioUserScope->setChecked(true); + } #if defined(Q_OS_WIN) - m_pBonjourWindows = new BonjourWindows(this, m_pMainWindow, m_appConfig); - if (m_pBonjourWindows->isRunning()) { - allowAutoConfig(); - } + m_pBonjourWindows = new BonjourWindows(this, m_pMainWindow, m_appConfig); + if (m_pBonjourWindows->isRunning()) { + allowAutoConfig(); + } - m_pComboElevate->setCurrentIndex(static_cast(appConfig().elevateMode())); + m_pComboElevate->setCurrentIndex(static_cast(appConfig().elevateMode())); #else - // elevate checkbox is only useful on ms windows. - m_pLabelElevate->hide(); - m_pComboElevate->hide(); + // elevate checkbox is only useful on ms windows. + m_pLabelElevate->hide(); + m_pComboElevate->hide(); - // for linux and mac, allow auto config by default - allowAutoConfig(); + // for linux and mac, allow auto config by default + allowAutoConfig(); #endif #if !defined(SYNERGY_ENTERPRISE) && defined(SYNERGY_AUTOCONFIG) - m_pCheckBoxAutoConfig->setChecked(appConfig().autoConfig()); + m_pCheckBoxAutoConfig->setChecked(appConfig().autoConfig()); #else - m_pCheckBoxAutoConfig->hide(); - m_pLabelInstallBonjour->hide(); + m_pCheckBoxAutoConfig->hide(); + m_pLabelInstallBonjour->hide(); #endif - m_pCheckBoxClientHostMode->setVisible(isClientMode() && appConfig().getInitiateConnectionFromServer()); - m_pCheckBoxServerClientMode->setVisible(!isClientMode() && appConfig().getInitiateConnectionFromServer()); + m_pCheckBoxClientHostMode->setVisible( + isClientMode() && appConfig().getInitiateConnectionFromServer()); + m_pCheckBoxServerClientMode->setVisible( + !isClientMode() && appConfig().getInitiateConnectionFromServer()); } -void SettingsDialog::setupSeurity() -{ - //If the tls file exists test its key length - if (QFile(appConfig().getTLSCertPath()).exists()) { - updateKeyLengthOnFile(appConfig().getTLSCertPath()); - } else { - m_pComboBoxKeyLength->setCurrentIndex(m_pComboBoxKeyLength->findText(appConfig().getTLSKeyLength())); - } +void SettingsDialog::setupSeurity() { + // If the tls file exists test its key length + if (QFile(appConfig().getTLSCertPath()).exists()) { + updateKeyLengthOnFile(appConfig().getTLSCertPath()); + } else { + m_pComboBoxKeyLength->setCurrentIndex( + m_pComboBoxKeyLength->findText(appConfig().getTLSKeyLength())); + } - m_pCheckBoxEnableCrypto->setChecked(m_appConfig.getCryptoEnabled()); + m_pCheckBoxEnableCrypto->setChecked(m_appConfig.getCryptoEnabled()); - if (appConfig().getClientGroupChecked()) { - m_pLabelKeyLength->hide(); - m_pComboBoxKeyLength->hide(); - m_pLabelCertificate->hide(); - m_pLineEditCertificatePath->hide(); - m_pPushButtonBrowseCert->hide(); - m_pPushButtonRegenCert->hide(); - } + if (appConfig().getClientGroupChecked()) { + m_pLabelKeyLength->hide(); + m_pComboBoxKeyLength->hide(); + m_pLabelCertificate->hide(); + m_pLineEditCertificatePath->hide(); + m_pPushButtonBrowseCert->hide(); + m_pPushButtonRegenCert->hide(); + } } -bool SettingsDialog::isClientMode() const -{ - return (m_pMainWindow->synergyType() == MainWindow::synergyClient); +bool SettingsDialog::isClientMode() const { + return (m_pMainWindow->synergyType() == MainWindow::synergyClient); } -void SettingsDialog::allowAutoConfig() -{ - m_pLabelInstallBonjour->hide(); - m_pCheckBoxAutoConfig->setEnabled(true); - m_pCheckBoxAutoConfig->setChecked(m_appConfig.autoConfig()); +void SettingsDialog::allowAutoConfig() { + m_pLabelInstallBonjour->hide(); + m_pCheckBoxAutoConfig->setEnabled(true); + m_pCheckBoxAutoConfig->setChecked(m_appConfig.autoConfig()); } -void SettingsDialog::on_m_pCheckBoxLogToFile_stateChanged(int i) -{ - bool checked = i == 2; +void SettingsDialog::on_m_pCheckBoxLogToFile_stateChanged(int i) { + bool checked = i == 2; + + m_pLabelLogPath->setEnabled(checked); + m_pLineEditLogFilename->setEnabled(checked); + m_pButtonBrowseLog->setEnabled(checked); + buttonBox->button(QDialogButtonBox::Save)->setEnabled(isModified()); +} + +void SettingsDialog::on_m_pButtonBrowseLog_clicked() { + QString fileName = QFileDialog::getSaveFileName( + this, tr("Save log file to..."), m_pLineEditLogFilename->text(), + "Logs (*.log *.txt)"); + + if (!fileName.isEmpty()) { + m_pLineEditLogFilename->setText(fileName); + } +} + +void SettingsDialog::on_m_pComboLanguage_currentIndexChanged(int index) { + QString ietfCode = m_pComboLanguage->itemData(index).toString(); + QSynergyApplication::getInstance()->switchTranslator(ietfCode); + buttonBox->button(QDialogButtonBox::Save)->setEnabled(isModified()); +} + +void SettingsDialog::on_m_pCheckBoxEnableCrypto_clicked(bool checked) { + if (appConfig().isCryptoAvailable()) { + m_pLabelKeyLength->setEnabled(checked); + m_pComboBoxKeyLength->setEnabled(checked); + m_pLabelCertificate->setEnabled(checked); + m_pLineEditCertificatePath->setEnabled(checked); + m_pPushButtonBrowseCert->setEnabled(checked); + m_pPushButtonRegenCert->setEnabled(checked); - m_pLabelLogPath->setEnabled(checked); - m_pLineEditLogFilename->setEnabled(checked); - m_pButtonBrowseLog->setEnabled(checked); buttonBox->button(QDialogButtonBox::Save)->setEnabled(isModified()); -} - -void SettingsDialog::on_m_pButtonBrowseLog_clicked() -{ - QString fileName = QFileDialog::getSaveFileName( - this, tr("Save log file to..."), - m_pLineEditLogFilename->text(), - "Logs (*.log *.txt)"); - - if (!fileName.isEmpty()) - { - m_pLineEditLogFilename->setText(fileName); - } -} - -void SettingsDialog::on_m_pComboLanguage_currentIndexChanged(int index) -{ - QString ietfCode = m_pComboLanguage->itemData(index).toString(); - QSynergyApplication::getInstance()->switchTranslator(ietfCode); - buttonBox->button(QDialogButtonBox::Save)->setEnabled(isModified()); -} - -void SettingsDialog::on_m_pCheckBoxEnableCrypto_clicked(bool checked) -{ - if (appConfig().isCryptoAvailable()) - { - m_pLabelKeyLength->setEnabled(checked); - m_pComboBoxKeyLength->setEnabled(checked); - m_pLabelCertificate->setEnabled(checked); - m_pLineEditCertificatePath->setEnabled(checked); - m_pPushButtonBrowseCert->setEnabled(checked); - m_pPushButtonRegenCert->setEnabled(checked); - - buttonBox->button(QDialogButtonBox::Save)->setEnabled(isModified()); - } - else - { - m_pCheckBoxEnableCrypto->setChecked(false); + } else { + m_pCheckBoxEnableCrypto->setChecked(false); #if !defined(SYNERGY_ENTERPRISE) && !defined(SYNERGY_BUSINESS) - UpgradeDialog upgradeDialog(this); - if (appConfig().edition() == Edition::kLite) - { - upgradeDialog.showDialog( - "TLS encryption is a Synergy Ultimate feature.", - "synergy/purchase/purchase-ultimate-upgrade?source=gui" - ); - } - else - { - upgradeDialog.showDialog( - "TLS encryption is a Synergy Pro feature.", - "synergy/purchase/upgrade?source=gui" - ); - } -#endif + UpgradeDialog upgradeDialog(this); + if (appConfig().edition() == Edition::kLite) { + upgradeDialog.showDialog( + "TLS encryption is a Synergy Ultimate feature.", + "synergy/purchase/purchase-ultimate-upgrade?source=gui"); + } else { + upgradeDialog.showDialog("TLS encryption is a Synergy Pro feature.", + "synergy/purchase/upgrade?source=gui"); } +#endif + } } -void SettingsDialog::on_m_pLabelInstallBonjour_linkActivated(const QString&) -{ +void SettingsDialog::on_m_pLabelInstallBonjour_linkActivated(const QString &) { #if defined(Q_OS_WIN) - m_pBonjourWindows->downloadAndInstall(); + m_pBonjourWindows->downloadAndInstall(); #endif } -void SettingsDialog::on_m_pRadioSystemScope_toggled(bool checked) -{ - //We only need to test the System scoped Radio as they are connected - appConfig().setLoadFromSystemScope(checked); - loadFromConfig(); - buttonBox->button(QDialogButtonBox::Save)->setEnabled(m_isSystemAtStart != checked); - enableControls(appConfig().isWritable()); +void SettingsDialog::on_m_pRadioSystemScope_toggled(bool checked) { + // We only need to test the System scoped Radio as they are connected + appConfig().setLoadFromSystemScope(checked); + loadFromConfig(); + buttonBox->button(QDialogButtonBox::Save) + ->setEnabled(m_isSystemAtStart != checked); + enableControls(appConfig().isWritable()); } void SettingsDialog::on_m_pPushButtonBrowseCert_clicked() { - QString fileName = QFileDialog::getSaveFileName( - this, tr("Select a TLS certificate to use..."), - m_pLineEditCertificatePath->text(), - "Cert (*.pem)", - nullptr, - QFileDialog::DontConfirmOverwrite); + QString fileName = QFileDialog::getSaveFileName( + this, tr("Select a TLS certificate to use..."), + m_pLineEditCertificatePath->text(), "Cert (*.pem)", nullptr, + QFileDialog::DontConfirmOverwrite); - if (!fileName.isEmpty()) { - m_pLineEditCertificatePath->setText(fileName); - //If the tls file exists test its key length and update - if (QFile(appConfig().getTLSCertPath()).exists()) { - updateKeyLengthOnFile(fileName); - } + if (!fileName.isEmpty()) { + m_pLineEditCertificatePath->setText(fileName); + // If the tls file exists test its key length and update + if (QFile(appConfig().getTLSCertPath()).exists()) { + updateKeyLengthOnFile(fileName); } - updateRegenButton(); + } + updateRegenButton(); } void SettingsDialog::on_m_pComboBoxKeyLength_currentIndexChanged(int index) { - buttonBox->button(QDialogButtonBox::Save)->setEnabled(isModified()); - updateRegenButton(); + buttonBox->button(QDialogButtonBox::Save)->setEnabled(isModified()); + updateRegenButton(); } void SettingsDialog::updateRegenButton() { - // Disable the Regenerate cert button if the key length is different to saved - auto keyChanged = appConfig().getTLSKeyLength() != m_pComboBoxKeyLength->currentText(); - auto pathChanged = appConfig().getTLSCertPath() != m_pLineEditCertificatePath->text(); - //NOR the above bools, if any have changed regen should be disabled as it will be done on save - auto nor = !(keyChanged || pathChanged); - m_pPushButtonRegenCert->setEnabled(nor && m_pCheckBoxEnableCrypto->isChecked()); + // Disable the Regenerate cert button if the key length is different to saved + auto keyChanged = + appConfig().getTLSKeyLength() != m_pComboBoxKeyLength->currentText(); + auto pathChanged = + appConfig().getTLSCertPath() != m_pLineEditCertificatePath->text(); + // NOR the above bools, if any have changed regen should be disabled as it + // will be done on save + auto nor = !(keyChanged || pathChanged); + m_pPushButtonRegenCert->setEnabled(nor && + m_pCheckBoxEnableCrypto->isChecked()); } void SettingsDialog::on_m_pPushButtonRegenCert_clicked() { - appConfig().generateCertificate(true); + appConfig().generateCertificate(true); } void SettingsDialog::updateKeyLengthOnFile(const QString &path) { - SslCertificate ssl; - auto length = ssl.getCertKeyLength(path); - auto index = m_pComboBoxKeyLength->findText(length); - m_pComboBoxKeyLength->setCurrentIndex(index); - //Also update what is in the appconfig to match the file itself - appConfig().setTLSKeyLength(length); + SslCertificate ssl; + auto length = ssl.getCertKeyLength(path); + auto index = m_pComboBoxKeyLength->findText(length); + m_pComboBoxKeyLength->setCurrentIndex(index); + // Also update what is in the appconfig to match the file itself + appConfig().setTLSKeyLength(length); } -bool SettingsDialog::isModified() -{ - return (!m_pLineEditScreenName->text().isEmpty() && +bool SettingsDialog::isModified() { + return ( + !m_pLineEditScreenName->text().isEmpty() && m_pLabelNameError->text().isEmpty() && - (appConfig().screenName() != m_pLineEditScreenName->text() - || appConfig().port() != m_pSpinBoxPort->value() - || appConfig().networkInterface() != m_pLineEditInterface->text() - || appConfig().logLevel() != m_pComboLogLevel->currentIndex() - || appConfig().logToFile() != m_pCheckBoxLogToFile->isChecked() - || appConfig().logFilename() != m_pLineEditLogFilename->text() - || appConfig().language() != m_pComboLanguage->itemData(m_pComboLanguage->currentIndex()).toString() - || appConfig().elevateMode() != static_cast(m_pComboElevate->currentIndex()) - || appConfig().getAutoHide() != m_pCheckBoxAutoHide->isChecked() - || appConfig().getPreventSleep() != m_pCheckBoxPreventSleep->isChecked() - || appConfig().autoConfig() != m_pCheckBoxAutoConfig->isChecked() - || appConfig().getMinimizeToTray() != m_pCheckBoxMinimizeToTray->isChecked() - || appConfig().getTLSCertPath() != m_pLineEditCertificatePath->text() - || appConfig().getTLSKeyLength() != m_pComboBoxKeyLength->currentText() - || appConfig().getCryptoEnabled() != m_pCheckBoxEnableCrypto->isChecked() - || appConfig().isSystemScoped() != m_isSystemAtStart - || appConfig().getLanguageSync() != m_pCheckBoxLanguageSync->isChecked() - || appConfig().getClientHostMode() != m_pCheckBoxClientHostMode->isChecked() - || appConfig().getServerClientMode() != m_pCheckBoxServerClientMode->isChecked() - || appConfig().getInvertScrollDirection() != m_pCheckBoxScrollDirection->isChecked()) - ); + (appConfig().screenName() != m_pLineEditScreenName->text() || + appConfig().port() != m_pSpinBoxPort->value() || + appConfig().networkInterface() != m_pLineEditInterface->text() || + appConfig().logLevel() != m_pComboLogLevel->currentIndex() || + appConfig().logToFile() != m_pCheckBoxLogToFile->isChecked() || + appConfig().logFilename() != m_pLineEditLogFilename->text() || + appConfig().language() != + m_pComboLanguage->itemData(m_pComboLanguage->currentIndex()) + .toString() || + appConfig().elevateMode() != + static_cast(m_pComboElevate->currentIndex()) || + appConfig().getAutoHide() != m_pCheckBoxAutoHide->isChecked() || + appConfig().getPreventSleep() != m_pCheckBoxPreventSleep->isChecked() || + appConfig().autoConfig() != m_pCheckBoxAutoConfig->isChecked() || + appConfig().getMinimizeToTray() != + m_pCheckBoxMinimizeToTray->isChecked() || + appConfig().getTLSCertPath() != m_pLineEditCertificatePath->text() || + appConfig().getTLSKeyLength() != m_pComboBoxKeyLength->currentText() || + appConfig().getCryptoEnabled() != m_pCheckBoxEnableCrypto->isChecked() || + appConfig().isSystemScoped() != m_isSystemAtStart || + appConfig().getLanguageSync() != m_pCheckBoxLanguageSync->isChecked() || + appConfig().getClientHostMode() != + m_pCheckBoxClientHostMode->isChecked() || + appConfig().getServerClientMode() != + m_pCheckBoxServerClientMode->isChecked() || + appConfig().getInvertScrollDirection() != + m_pCheckBoxScrollDirection->isChecked())); } void SettingsDialog::enableControls(bool enable) { - m_pLineEditScreenName->setEnabled(enable); - m_pSpinBoxPort->setEnabled(enable); - m_pLineEditInterface->setEnabled(enable); - m_pComboLogLevel->setEnabled(enable); - m_pCheckBoxLogToFile->setEnabled(enable); - m_pComboLanguage->setEnabled(enable); - m_pComboElevate->setEnabled(enable); - m_pCheckBoxAutoHide->setEnabled(enable); - m_pCheckBoxPreventSleep->setEnabled(enable); - m_pCheckBoxAutoConfig->setEnabled(enable); - m_pCheckBoxMinimizeToTray->setEnabled(enable); - m_pLineEditCertificatePath->setEnabled(enable); + m_pLineEditScreenName->setEnabled(enable); + m_pSpinBoxPort->setEnabled(enable); + m_pLineEditInterface->setEnabled(enable); + m_pComboLogLevel->setEnabled(enable); + m_pCheckBoxLogToFile->setEnabled(enable); + m_pComboLanguage->setEnabled(enable); + m_pComboElevate->setEnabled(enable); + m_pCheckBoxAutoHide->setEnabled(enable); + m_pCheckBoxPreventSleep->setEnabled(enable); + m_pCheckBoxAutoConfig->setEnabled(enable); + m_pCheckBoxMinimizeToTray->setEnabled(enable); + m_pLineEditCertificatePath->setEnabled(enable); + m_pComboBoxKeyLength->setEnabled(enable); + m_pPushButtonBrowseCert->setEnabled(enable); + m_pCheckBoxEnableCrypto->setEnabled(enable); + m_labelAdminRightsMessage->setVisible(!enable); + m_pCheckBoxLanguageSync->setEnabled(enable); + m_pCheckBoxScrollDirection->setEnabled(enable); + m_pCheckBoxClientHostMode->setEnabled(enable); + m_pCheckBoxServerClientMode->setEnabled(enable); + + if (enable) { + m_pLabelLogPath->setEnabled(m_pCheckBoxLogToFile->isChecked()); + m_pLineEditLogFilename->setEnabled(m_pCheckBoxLogToFile->isChecked()); + m_pButtonBrowseLog->setEnabled(m_pCheckBoxLogToFile->isChecked()); + m_pLabelKeyLength->setEnabled(m_pCheckBoxEnableCrypto->isChecked()); + m_pComboBoxKeyLength->setEnabled(m_pCheckBoxEnableCrypto->isChecked()); + m_pLabelCertificate->setEnabled(m_pCheckBoxEnableCrypto->isChecked()); + m_pLineEditCertificatePath->setEnabled( + m_pCheckBoxEnableCrypto->isChecked()); + m_pPushButtonBrowseCert->setEnabled(m_pCheckBoxEnableCrypto->isChecked()); + updateRegenButton(); + } else { + m_pLabelLogPath->setEnabled(enable); + m_pLineEditLogFilename->setEnabled(enable); + m_pButtonBrowseLog->setEnabled(enable); + m_pLabelKeyLength->setEnabled(enable); m_pComboBoxKeyLength->setEnabled(enable); + m_pLabelCertificate->setEnabled(enable); + m_pLineEditCertificatePath->setEnabled(enable); m_pPushButtonBrowseCert->setEnabled(enable); - m_pCheckBoxEnableCrypto->setEnabled(enable); - m_labelAdminRightsMessage->setVisible(!enable); - m_pCheckBoxLanguageSync->setEnabled(enable); - m_pCheckBoxScrollDirection->setEnabled(enable); - m_pCheckBoxClientHostMode->setEnabled(enable); - m_pCheckBoxServerClientMode->setEnabled(enable); - - if (enable) { - m_pLabelLogPath->setEnabled(m_pCheckBoxLogToFile->isChecked()); - m_pLineEditLogFilename->setEnabled(m_pCheckBoxLogToFile->isChecked()); - m_pButtonBrowseLog->setEnabled(m_pCheckBoxLogToFile->isChecked()); - m_pLabelKeyLength->setEnabled(m_pCheckBoxEnableCrypto->isChecked()); - m_pComboBoxKeyLength->setEnabled(m_pCheckBoxEnableCrypto->isChecked()); - m_pLabelCertificate->setEnabled(m_pCheckBoxEnableCrypto->isChecked()); - m_pLineEditCertificatePath->setEnabled(m_pCheckBoxEnableCrypto->isChecked()); - m_pPushButtonBrowseCert->setEnabled(m_pCheckBoxEnableCrypto->isChecked()); - updateRegenButton(); - } - else { - m_pLabelLogPath->setEnabled(enable); - m_pLineEditLogFilename->setEnabled(enable); - m_pButtonBrowseLog->setEnabled(enable); - m_pLabelKeyLength->setEnabled(enable); - m_pComboBoxKeyLength->setEnabled(enable); - m_pLabelCertificate->setEnabled(enable); - m_pLineEditCertificatePath->setEnabled(enable); - m_pPushButtonBrowseCert->setEnabled(enable); - m_pPushButtonRegenCert->setEnabled(enable); - } + m_pPushButtonRegenCert->setEnabled(enable); + } } -void SettingsDialog::onChange() -{ - buttonBox->button(QDialogButtonBox::Save)->setEnabled(isModified()); +void SettingsDialog::onChange() { + buttonBox->button(QDialogButtonBox::Save)->setEnabled(isModified()); } diff --git a/src/gui/src/SettingsDialog.h b/src/gui/src/SettingsDialog.h index 75b4ce434..71ec17da5 100644 --- a/src/gui/src/SettingsDialog.h +++ b/src/gui/src/SettingsDialog.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2008 Volker Lanz (vl@fidra.de) - * + * * 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 LICENSE 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 @@ -20,92 +20,96 @@ #define SETTINGSDIALOG_H -#include -#include #include "ui_SettingsDialogBase.h" +#include +#include -#include "SynergyLocale.h" #include "CoreInterface.h" +#include "SynergyLocale.h" class MainWindow; class AppConfig; class BonjourWindows; -class SettingsDialog : public QDialog, public Ui::SettingsDialogBase -{ - Q_OBJECT +class SettingsDialog : public QDialog, public Ui::SettingsDialogBase { + Q_OBJECT - public: - SettingsDialog(QWidget* parent, AppConfig& config); - static QString browseForSynergyc(QWidget* parent, const QString& programDir, const QString& synergycName); - static QString browseForSynergys(QWidget* parent, const QString& programDir, const QString& synergysName); - void allowAutoConfig(); +public: + SettingsDialog(QWidget *parent, AppConfig &config); + static QString browseForSynergyc(QWidget *parent, const QString &programDir, + const QString &synergycName); + static QString browseForSynergys(QWidget *parent, const QString &programDir, + const QString &synergysName); + void allowAutoConfig(); - protected: - void accept() override; - void reject() override; - void changeEvent(QEvent* event) override; - AppConfig& appConfig() { return m_appConfig; } +protected: + void accept() override; + void reject() override; + void changeEvent(QEvent *event) override; + AppConfig &appConfig() { return m_appConfig; } - /// @brief Causes the dialog to load all the settings from m_appConfig - void loadFromConfig(); + /// @brief Causes the dialog to load all the settings from m_appConfig + void loadFromConfig(); - /// @brief Check if the regenerate button should be enabled or disabled and sets it - void updateRegenButton(); + /// @brief Check if the regenerate button should be enabled or disabled and + /// sets it + void updateRegenButton(); - /// @brief Updates the key length value based on the loaded file - /// @param [in] QString path The path to the file to test - void updateKeyLengthOnFile(const QString& path); + /// @brief Updates the key length value based on the loaded file + /// @param [in] QString path The path to the file to test + void updateKeyLengthOnFile(const QString &path); - /// @brief Check if there are modifications. - /// @return true if there are modifications. - bool isModified(); + /// @brief Check if there are modifications. + /// @return true if there are modifications. + bool isModified(); - /// @brief Enables\disables all controls. - void enableControls(bool enabled); + /// @brief Enables\disables all controls. + void enableControls(bool enabled); - /// @brief This method setups security section in setting - void setupSeurity(); + /// @brief This method setups security section in setting + void setupSeurity(); - /// @brief Returns true if current mode is a client mode - bool isClientMode() const; + /// @brief Returns true if current mode is a client mode + bool isClientMode() const; - private: - MainWindow* m_pMainWindow; - AppConfig& m_appConfig; - SynergyLocale m_Locale; - CoreInterface m_CoreInterface; - BonjourWindows* m_pBonjourWindows; +private: + MainWindow *m_pMainWindow; + AppConfig &m_appConfig; + SynergyLocale m_Locale; + CoreInterface m_CoreInterface; + BonjourWindows *m_pBonjourWindows; - /// @brief Stores settings scope at start of settings dialog - /// This is neccessary to restore state if user changes - /// the scope and doesn't save changes - bool m_isSystemAtStart = false; + /// @brief Stores settings scope at start of settings dialog + /// This is neccessary to restore state if user changes + /// the scope and doesn't save changes + bool m_isSystemAtStart = false; - private slots: - void on_m_pCheckBoxEnableCrypto_clicked(bool checked); - void on_m_pComboLanguage_currentIndexChanged(int index); - void on_m_pCheckBoxLogToFile_stateChanged(int ); - void on_m_pButtonBrowseLog_clicked(); - void on_m_pLabelInstallBonjour_linkActivated(const QString &link); +private slots: + void on_m_pCheckBoxEnableCrypto_clicked(bool checked); + void on_m_pComboLanguage_currentIndexChanged(int index); + void on_m_pCheckBoxLogToFile_stateChanged(int); + void on_m_pButtonBrowseLog_clicked(); + void on_m_pLabelInstallBonjour_linkActivated(const QString &link); - /// @brief Handles the toggling of the system scoped radio button - /// As the user scope radio is connected this will fire for either radio button - void on_m_pRadioSystemScope_toggled(bool checked); + /// @brief Handles the toggling of the system scoped radio button + /// As the user scope radio is connected this will fire for either + /// radio button + void on_m_pRadioSystemScope_toggled(bool checked); - /// @brief Handles the click event of the Cert Path browse button - /// displaying a file browser - void on_m_pPushButtonBrowseCert_clicked(); + /// @brief Handles the click event of the Cert Path browse button + /// displaying a file browser + void on_m_pPushButtonBrowseCert_clicked(); - /// @brief Handles the TLS cert key length changed event - void on_m_pComboBoxKeyLength_currentIndexChanged(int index); + /// @brief Handles the TLS cert key length changed event + void on_m_pComboBoxKeyLength_currentIndexChanged(int index); - /// @brief handels the regenerate cert button event - /// This will regenerate the TLS certificate as long as the settings haven't changed - void on_m_pPushButtonRegenCert_clicked(); + /// @brief handels the regenerate cert button event + /// This will regenerate the TLS certificate as long as the settings + /// haven't changed + void on_m_pPushButtonRegenCert_clicked(); - /// @brief This slot handles common functionality for all fields. - void onChange(); + /// @brief This slot handles common functionality for all fields. + void onChange(); }; #endif diff --git a/src/gui/src/SetupWizard.cpp b/src/gui/src/SetupWizard.cpp index 16998fbbd..41121bcae 100644 --- a/src/gui/src/SetupWizard.cpp +++ b/src/gui/src/SetupWizard.cpp @@ -19,37 +19,34 @@ #include "MainWindow.h" #include "validators/ScreenNameValidator.h" -SetupWizard::SetupWizard(MainWindow& mainWindow) : - m_MainWindow(mainWindow) -{ - setupUi(this); +SetupWizard::SetupWizard(MainWindow &mainWindow) : m_MainWindow(mainWindow) { + setupUi(this); - m_pLineEditName->setText(m_MainWindow.appConfig().screenName()); - m_pLineEditName->setValidator(new validators::ScreenNameValidator(m_pLineEditName, label_ErrorMessage)); + m_pLineEditName->setText(m_MainWindow.appConfig().screenName()); + m_pLineEditName->setValidator( + new validators::ScreenNameValidator(m_pLineEditName, label_ErrorMessage)); - connect(m_pButtonApply, SIGNAL(clicked()), this, SLOT(accept())); - connect(m_pLineEditName, SIGNAL(textEdited(QString)), this, SLOT(onNameChanged())); + connect(m_pButtonApply, SIGNAL(clicked()), this, SLOT(accept())); + connect(m_pLineEditName, SIGNAL(textEdited(QString)), this, + SLOT(onNameChanged())); } -void SetupWizard::accept() -{ - AppConfig& appConfig = m_MainWindow.appConfig(); +void SetupWizard::accept() { + AppConfig &appConfig = m_MainWindow.appConfig(); - appConfig.setWizardHasRun(); - appConfig.setScreenName(m_pLineEditName->text()); - appConfig.saveSettings(); + appConfig.setWizardHasRun(); + appConfig.setScreenName(m_pLineEditName->text()); + appConfig.saveSettings(); - m_MainWindow.open(); - QDialog::accept(); + m_MainWindow.open(); + QDialog::accept(); } -void SetupWizard::onNameChanged() -{ - m_pButtonApply->setEnabled(label_ErrorMessage->text().isEmpty()); +void SetupWizard::onNameChanged() { + m_pButtonApply->setEnabled(label_ErrorMessage->text().isEmpty()); } -void SetupWizard::reject() -{ - QDialog::reject(); - QApplication::exit(); +void SetupWizard::reject() { + QDialog::reject(); + QApplication::exit(); } diff --git a/src/gui/src/SetupWizard.h b/src/gui/src/SetupWizard.h index eb4622f29..a2b9fde8f 100644 --- a/src/gui/src/SetupWizard.h +++ b/src/gui/src/SetupWizard.h @@ -1,11 +1,11 @@ /* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. - * + * * 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 LICENSE 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 @@ -16,26 +16,25 @@ */ #pragma once -#include #include "ui_SetupWizardBase.h" #include +#include class MainWindow; -class SetupWizard : public QDialog, public Ui::SetupWizardBase -{ - Q_OBJECT +class SetupWizard : public QDialog, public Ui::SetupWizardBase { + Q_OBJECT public: - explicit SetupWizard(MainWindow& mainWindow); + explicit SetupWizard(MainWindow &mainWindow); protected: - void accept(); - void reject(); + void accept(); + void reject(); private: - MainWindow& m_MainWindow; + MainWindow &m_MainWindow; private slots: - void onNameChanged(); + void onNameChanged(); }; diff --git a/src/gui/src/SetupWizardBlocker.cpp b/src/gui/src/SetupWizardBlocker.cpp index 088af6765..87906b2a1 100644 --- a/src/gui/src/SetupWizardBlocker.cpp +++ b/src/gui/src/SetupWizardBlocker.cpp @@ -18,8 +18,8 @@ #include #include -#include "SetupWizardBlocker.h" #include "MainWindow.h" +#include "SetupWizardBlocker.h" static const std::vector blockerTitels = { "No Wayland support", @@ -32,27 +32,28 @@ static const std::vector blockerText = { "Please switch to Xorg if you wish to continue using Synergy today.", }; -SetupWizardBlocker::SetupWizardBlocker(MainWindow& mainWindow, qBlockerType type) : - m_MainWindow(mainWindow) -{ - setupUi(this); +SetupWizardBlocker::SetupWizardBlocker(MainWindow &mainWindow, + qBlockerType type) + : m_MainWindow(mainWindow) { + setupUi(this); - label_Title->setText(blockerTitels[static_cast(type)]); + label_Title->setText(blockerTitels[static_cast(type)]); - label_HelpInfo->setText(blockerText[static_cast(type)]); + label_HelpInfo->setText(blockerText[static_cast(type)]); - connect(m_pButtonSupport, &QPushButton::released, this, &SetupWizardBlocker::onlineSupport); - connect(m_pButtonCancel, &QPushButton::released, this, &SetupWizardBlocker::cancel); + connect(m_pButtonSupport, &QPushButton::released, this, + &SetupWizardBlocker::onlineSupport); + connect(m_pButtonCancel, &QPushButton::released, this, + &SetupWizardBlocker::cancel); } -void SetupWizardBlocker::onlineSupport() -{ - QDesktopServices::openUrl(QUrl("https://symless.com/synergy/help?source=gui")); - cancel(); +void SetupWizardBlocker::onlineSupport() { + QDesktopServices::openUrl( + QUrl("https://symless.com/synergy/help?source=gui")); + cancel(); } -void SetupWizardBlocker::cancel() -{ - QDialog::reject(); - QCoreApplication::quit(); +void SetupWizardBlocker::cancel() { + QDialog::reject(); + QCoreApplication::quit(); } diff --git a/src/gui/src/SetupWizardBlocker.h b/src/gui/src/SetupWizardBlocker.h index 7620ed43b..62ca9b611 100644 --- a/src/gui/src/SetupWizardBlocker.h +++ b/src/gui/src/SetupWizardBlocker.h @@ -1,11 +1,11 @@ /* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. - * + * * 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 LICENSE 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 @@ -21,21 +21,17 @@ class MainWindow; -class SetupWizardBlocker : public QDialog, public Ui::SetupWizardBlocker -{ - Q_OBJECT +class SetupWizardBlocker : public QDialog, public Ui::SetupWizardBlocker { + Q_OBJECT public: - enum class qBlockerType - { - waylandDetected - }; - explicit SetupWizardBlocker(MainWindow& mainWindow, qBlockerType type); + enum class qBlockerType { waylandDetected }; + explicit SetupWizardBlocker(MainWindow &mainWindow, qBlockerType type); protected: - void onlineSupport(); - void cancel(); + void onlineSupport(); + void cancel(); private: - MainWindow& m_MainWindow; + MainWindow &m_MainWindow; }; diff --git a/src/gui/src/SslCertificate.cpp b/src/gui/src/SslCertificate.cpp index 636554e3f..e177a0bde 100644 --- a/src/gui/src/SslCertificate.cpp +++ b/src/gui/src/SslCertificate.cpp @@ -19,14 +19,14 @@ #include "Fingerprint.h" -#include -#include #include +#include +#include - - -static const char kCertificateKeyLength[] = "rsa:"; //RSA Bit length (e.g. 1024/2048/4096) -static const char kCertificateHashAlgorithm[] = "-sha256"; //fingerprint hashing algorithm +static const char kCertificateKeyLength[] = + "rsa:"; // RSA Bit length (e.g. 1024/2048/4096) +static const char kCertificateHashAlgorithm[] = + "-sha256"; // fingerprint hashing algorithm static const char kCertificateLifetime[] = "365"; static const char kCertificateSubjectInfo[] = "/CN=Synergy"; static const char kCertificateFilename[] = "Synergy.pem"; @@ -38,175 +38,163 @@ static const char kWinOpenSslBinary[] = "OpenSSL\\openssl.exe"; static const char kConfigFile[] = "OpenSSL\\synergy.conf"; #endif -SslCertificate::SslCertificate(QObject *parent) : - QObject(parent) -{ - m_ProfileDir = m_CoreInterface.getProfileDir(); - if (m_ProfileDir.isEmpty()) { - emit error(tr("Failed to get profile directory.")); - } +SslCertificate::SslCertificate(QObject *parent) : QObject(parent) { + m_ProfileDir = m_CoreInterface.getProfileDir(); + if (m_ProfileDir.isEmpty()) { + emit error(tr("Failed to get profile directory.")); + } } -bool SslCertificate::runTool(const QStringList& args) -{ - QString program; +bool SslCertificate::runTool(const QStringList &args) { + QString program; #if defined(Q_OS_WIN) - program = QCoreApplication::applicationDirPath(); - program.append("\\").append(kWinOpenSslBinary); + program = QCoreApplication::applicationDirPath(); + program.append("\\").append(kWinOpenSslBinary); #else - program = kUnixOpenSslCommand; + program = kUnixOpenSslCommand; #endif - - QStringList environment; + QStringList environment; #if defined(Q_OS_WIN) - environment << QString("OPENSSL_CONF=%1\\%2") - .arg(QCoreApplication::applicationDirPath()) - .arg(kConfigFile); + environment << QString("OPENSSL_CONF=%1\\%2") + .arg(QCoreApplication::applicationDirPath()) + .arg(kConfigFile); #endif - QProcess process; - process.setEnvironment(environment); - process.start(program, args); + QProcess process; + process.setEnvironment(environment); + process.start(program, args); - bool success = process.waitForStarted(); + bool success = process.waitForStarted(); - QString standardError; - if (success && process.waitForFinished()) - { - m_ToolOutput = process.readAllStandardOutput().trimmed(); - standardError = process.readAllStandardError().trimmed(); - } + QString standardError; + if (success && process.waitForFinished()) { + m_ToolOutput = process.readAllStandardOutput().trimmed(); + standardError = process.readAllStandardError().trimmed(); + } - int code = process.exitCode(); - if (!success || code != 0) - { - emit error( - QString("SSL tool failed: %1\n\nCode: %2\nError: %3") - .arg(program) - .arg(process.exitCode()) - .arg(standardError.isEmpty() ? "Unknown" : standardError)); - return false; - } + int code = process.exitCode(); + if (!success || code != 0) { + emit error(QString("SSL tool failed: %1\n\nCode: %2\nError: %3") + .arg(program) + .arg(process.exitCode()) + .arg(standardError.isEmpty() ? "Unknown" : standardError)); + return false; + } - - return true; + return true; } -void SslCertificate::generateCertificate(const QString& path, const QString& keyLength, bool forceGen) -{ - QString sslDirPath = QString("%1%2%3") - .arg(m_ProfileDir) - .arg(QDir::separator()) - .arg(kSslDir); +void SslCertificate::generateCertificate(const QString &path, + const QString &keyLength, + bool forceGen) { + QString sslDirPath = + QString("%1%2%3").arg(m_ProfileDir).arg(QDir::separator()).arg(kSslDir); - QString filename = QString("%1%2%3") - .arg(sslDirPath) - .arg(QDir::separator()) - .arg(kCertificateFilename); + QString filename = QString("%1%2%3") + .arg(sslDirPath) + .arg(QDir::separator()) + .arg(kCertificateFilename); - QString keySize = kCertificateKeyLength + keyLength; + QString keySize = kCertificateKeyLength + keyLength; - const QString pathToUse = path.isEmpty() ? filename : path; + const QString pathToUse = path.isEmpty() ? filename : path; - //If path is empty use filename - QFile file(pathToUse); - if (!file.exists() || forceGen) { - QStringList arguments; - - // self signed certificate - arguments.append("req"); - arguments.append("-x509"); - arguments.append("-nodes"); - - // valide duration - arguments.append("-days"); - arguments.append(kCertificateLifetime); - - // subject information - arguments.append("-subj"); - - QString subInfo(kCertificateSubjectInfo); - arguments.append(subInfo); - - // private key - arguments.append("-newkey"); - arguments.append(keySize); - - QDir sslDir(sslDirPath); - if (!sslDir.exists()) { - sslDir.mkpath("."); - } - - // key output filename - arguments.append("-keyout"); - arguments.append(pathToUse); - - // certificate output filename - arguments.append("-out"); - arguments.append(pathToUse); - - if (!runTool(arguments)) { - return; - } - - generateFingerprint(pathToUse); - emit info(tr("SSL certificate generated.")); - } - - emit generateFinished(); -} - -void SslCertificate::generateFingerprint(const QString& certificateFilename) -{ + // If path is empty use filename + QFile file(pathToUse); + if (!file.exists() || forceGen) { QStringList arguments; - arguments.append("x509"); - arguments.append("-fingerprint"); - arguments.append(kCertificateHashAlgorithm); - arguments.append("-noout"); - arguments.append("-in"); - arguments.append(certificateFilename); + + // self signed certificate + arguments.append("req"); + arguments.append("-x509"); + arguments.append("-nodes"); + + // valide duration + arguments.append("-days"); + arguments.append(kCertificateLifetime); + + // subject information + arguments.append("-subj"); + + QString subInfo(kCertificateSubjectInfo); + arguments.append(subInfo); + + // private key + arguments.append("-newkey"); + arguments.append(keySize); + + QDir sslDir(sslDirPath); + if (!sslDir.exists()) { + sslDir.mkpath("."); + } + + // key output filename + arguments.append("-keyout"); + arguments.append(pathToUse); + + // certificate output filename + arguments.append("-out"); + arguments.append(pathToUse); if (!runTool(arguments)) { - return; + return; } - // find the fingerprint from the tool output - int i = m_ToolOutput.indexOf("="); - if (i != -1) { - i++; - QString fingerprint = m_ToolOutput.mid( - i, m_ToolOutput.size() - i); + generateFingerprint(pathToUse); + emit info(tr("SSL certificate generated.")); + } - Fingerprint::local().trust(fingerprint, false); - emit info(tr("SSL fingerprint generated.")); - } - else { - emit error(tr("Failed to find SSL fingerprint.")); - } + emit generateFinished(); +} + +void SslCertificate::generateFingerprint(const QString &certificateFilename) { + QStringList arguments; + arguments.append("x509"); + arguments.append("-fingerprint"); + arguments.append(kCertificateHashAlgorithm); + arguments.append("-noout"); + arguments.append("-in"); + arguments.append(certificateFilename); + + if (!runTool(arguments)) { + return; + } + + // find the fingerprint from the tool output + int i = m_ToolOutput.indexOf("="); + if (i != -1) { + i++; + QString fingerprint = m_ToolOutput.mid(i, m_ToolOutput.size() - i); + + Fingerprint::local().trust(fingerprint, false); + emit info(tr("SSL fingerprint generated.")); + } else { + emit error(tr("Failed to find SSL fingerprint.")); + } } QString SslCertificate::getCertKeyLength(const QString &path) { - QStringList arguments; - arguments.append("rsa"); - arguments.append("-in"); - arguments.append(path); - arguments.append("-text"); - arguments.append("-noout"); + QStringList arguments; + arguments.append("rsa"); + arguments.append("-in"); + arguments.append(path); + arguments.append("-text"); + arguments.append("-noout"); - if (!runTool(arguments)) { - return QString(); - } - const QString searchStart("Private-Key: ("); - const QString searchEnd(" bit"); + if (!runTool(arguments)) { + return QString(); + } + const QString searchStart("Private-Key: ("); + const QString searchEnd(" bit"); - //Get the line that contains the key length from the output - const auto indexStart = m_ToolOutput.indexOf(searchStart); - const auto indexEnd = m_ToolOutput.indexOf(searchEnd, indexStart); - const auto start = indexStart + searchStart.length(); - const auto end = indexEnd - (indexStart + searchStart.length()); - auto keyLength = m_ToolOutput.mid(start, end); + // Get the line that contains the key length from the output + const auto indexStart = m_ToolOutput.indexOf(searchStart); + const auto indexEnd = m_ToolOutput.indexOf(searchEnd, indexStart); + const auto start = indexStart + searchStart.length(); + const auto end = indexEnd - (indexStart + searchStart.length()); + auto keyLength = m_ToolOutput.mid(start, end); - return keyLength; + return keyLength; } diff --git a/src/gui/src/SslCertificate.h b/src/gui/src/SslCertificate.h index a88a41af1..0d1b33136 100644 --- a/src/gui/src/SslCertificate.h +++ b/src/gui/src/SslCertificate.h @@ -22,36 +22,38 @@ #include #include -class SslCertificate : public QObject -{ -Q_OBJECT +class SslCertificate : public QObject { + Q_OBJECT public: - explicit SslCertificate(QObject *parent = 0); + explicit SslCertificate(QObject *parent = 0); public slots: - /// @brief Generates a TLS cert and private key - /// @param [in] QString path The path of the file to be generated - /// @param [in] QString keyLength The size of the private key. default: 2048 - /// @param [in] bool Should the file be created regardless of if the file already exists - void generateCertificate(const QString& path = QString(), const QString& keyLength = "2048", bool forceGen = false); + /// @brief Generates a TLS cert and private key + /// @param [in] QString path The path of the file to be generated + /// @param [in] QString keyLength The size of the private key. default: 2048 + /// @param [in] bool Should the file be created regardless of if the file + /// already exists + void generateCertificate(const QString &path = QString(), + const QString &keyLength = "2048", + bool forceGen = false); - /// @brief Get the key length of a TLS private key - /// @param [in] QString path The path of the file to checked - /// @return QString The key legnth as a string - QString getCertKeyLength(const QString& path); + /// @brief Get the key length of a TLS private key + /// @param [in] QString path The path of the file to checked + /// @return QString The key legnth as a string + QString getCertKeyLength(const QString &path); signals: - void error(QString e); - void info(QString i); - void generateFinished(); + void error(QString e); + void info(QString i); + void generateFinished(); private: - bool runTool(const QStringList& args); - void generateFingerprint(const QString& certificateFilename); + bool runTool(const QStringList &args); + void generateFingerprint(const QString &certificateFilename); private: - QString m_ProfileDir; - QString m_ToolOutput; - CoreInterface m_CoreInterface; + QString m_ProfileDir; + QString m_ToolOutput; + CoreInterface m_CoreInterface; }; diff --git a/src/gui/src/SynergyLocale.cpp b/src/gui/src/SynergyLocale.cpp index 488cd0f0b..915e82c92 100644 --- a/src/gui/src/SynergyLocale.cpp +++ b/src/gui/src/SynergyLocale.cpp @@ -17,52 +17,42 @@ #include "SynergyLocale.h" +#include #include #include -#include -SynergyLocale::SynergyLocale() -{ - loadLanguages(); -} +SynergyLocale::SynergyLocale() { loadLanguages(); } -void SynergyLocale::loadLanguages() -{ - QResource resource(":/res/lang/Languages.xml"); - QByteArray bytes(reinterpret_cast(resource.data()), resource.size()); - QXmlStreamReader xml(bytes); +void SynergyLocale::loadLanguages() { + QResource resource(":/res/lang/Languages.xml"); + QByteArray bytes(reinterpret_cast(resource.data()), + resource.size()); + QXmlStreamReader xml(bytes); - while (!xml.atEnd()) - { - QXmlStreamReader::TokenType token = xml.readNext(); - if (xml.hasError()) - { - qCritical() << xml.errorString(); - throw std::exception(); - } - - if (xml.name() == "language" && token == QXmlStreamReader::StartElement) - { - QXmlStreamAttributes attributes = xml.attributes(); - addLanguage( - attributes.value("ietfCode").toString(), - attributes.value("name").toString()); - } + while (!xml.atEnd()) { + QXmlStreamReader::TokenType token = xml.readNext(); + if (xml.hasError()) { + qCritical() << xml.errorString(); + throw std::exception(); } -} -void SynergyLocale::addLanguage(const QString& ietfCode, const QString& name) -{ - m_Languages.push_back(SynergyLocale::Language(ietfCode, name)); -} - -void SynergyLocale::fillLanguageComboBox(QComboBox* comboBox) -{ - comboBox->blockSignals(true); - QVector::iterator it; - for (it = m_Languages.begin(); it != m_Languages.end(); ++it) - { - comboBox->addItem((*it).m_Name, (*it).m_IetfCode); + if (xml.name() == "language" && token == QXmlStreamReader::StartElement) { + QXmlStreamAttributes attributes = xml.attributes(); + addLanguage(attributes.value("ietfCode").toString(), + attributes.value("name").toString()); } - comboBox->blockSignals(false); + } +} + +void SynergyLocale::addLanguage(const QString &ietfCode, const QString &name) { + m_Languages.push_back(SynergyLocale::Language(ietfCode, name)); +} + +void SynergyLocale::fillLanguageComboBox(QComboBox *comboBox) { + comboBox->blockSignals(true); + QVector::iterator it; + for (it = m_Languages.begin(); it != m_Languages.end(); ++it) { + comboBox->addItem((*it).m_Name, (*it).m_IetfCode); + } + comboBox->blockSignals(false); } diff --git a/src/gui/src/SynergyLocale.h b/src/gui/src/SynergyLocale.h index beaa4f7dd..b39f6850c 100644 --- a/src/gui/src/SynergyLocale.h +++ b/src/gui/src/SynergyLocale.h @@ -17,32 +17,30 @@ #pragma once +#include #include #include -#include -class SynergyLocale -{ - class Language - { - public: - Language() { } - Language(const QString& IetfCode, const QString& name) - : m_IetfCode(IetfCode), m_Name(name) { } +class SynergyLocale { + class Language { + public: + Language() {} + Language(const QString &IetfCode, const QString &name) + : m_IetfCode(IetfCode), m_Name(name) {} - public: - QString m_IetfCode; - QString m_Name; - }; + public: + QString m_IetfCode; + QString m_Name; + }; public: - SynergyLocale(); - void fillLanguageComboBox(QComboBox* comboBox); + SynergyLocale(); + void fillLanguageComboBox(QComboBox *comboBox); private: - void loadLanguages(); - void addLanguage(const QString& IetfCode, const QString& name); + void loadLanguages(); + void addLanguage(const QString &IetfCode, const QString &name); private: - QVector m_Languages; + QVector m_Languages; }; diff --git a/src/gui/src/TrashScreenWidget.cpp b/src/gui/src/TrashScreenWidget.cpp index 056ab0856..ffed00a65 100644 --- a/src/gui/src/TrashScreenWidget.cpp +++ b/src/gui/src/TrashScreenWidget.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2008 Volker Lanz (vl@fidra.de) - * + * * 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 LICENSE 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 @@ -22,27 +22,19 @@ #include #include -void TrashScreenWidget::dragEnterEvent(QDragEnterEvent* event) -{ - if (event->mimeData()->hasFormat(ScreenSetupModel::mimeType())) - { - event->setDropAction(Qt::MoveAction); - event->accept(); - } - else - event->ignore(); +void TrashScreenWidget::dragEnterEvent(QDragEnterEvent *event) { + if (event->mimeData()->hasFormat(ScreenSetupModel::mimeType())) { + event->setDropAction(Qt::MoveAction); + event->accept(); + } else + event->ignore(); } -void TrashScreenWidget::dropEvent(QDropEvent* event) -{ - if (event->mimeData()->hasFormat(ScreenSetupModel::mimeType())) - { - event->acceptProposedAction(); - emit screenRemoved(); - } - else - { - event->ignore(); - } +void TrashScreenWidget::dropEvent(QDropEvent *event) { + if (event->mimeData()->hasFormat(ScreenSetupModel::mimeType())) { + event->acceptProposedAction(); + emit screenRemoved(); + } else { + event->ignore(); + } } - diff --git a/src/gui/src/TrashScreenWidget.h b/src/gui/src/TrashScreenWidget.h index 39e2442ac..0c4dad00d 100644 --- a/src/gui/src/TrashScreenWidget.h +++ b/src/gui/src/TrashScreenWidget.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2008 Volker Lanz (vl@fidra.de) - * + * * 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 LICENSE 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 @@ -26,21 +26,18 @@ class QWidget; class QDragEnterEvent; class QDropEvent; -class TrashScreenWidget : public QLabel -{ - Q_OBJECT +class TrashScreenWidget : public QLabel { + Q_OBJECT - public: - TrashScreenWidget(QWidget* parent) : QLabel(parent) {} +public: + TrashScreenWidget(QWidget *parent) : QLabel(parent) {} - public: - void dragEnterEvent(QDragEnterEvent* event); - void dropEvent(QDropEvent* event); - - signals: - void screenRemoved(); +public: + void dragEnterEvent(QDragEnterEvent *event); + void dropEvent(QDropEvent *event); +signals: + void screenRemoved(); }; #endif - diff --git a/src/gui/src/TrayIcon.cpp b/src/gui/src/TrayIcon.cpp index f44cfa33c..bf4ef9ddd 100644 --- a/src/gui/src/TrayIcon.cpp +++ b/src/gui/src/TrayIcon.cpp @@ -1,14 +1,17 @@ #include "TrayIcon.h" -void TrayIcon::tryCreate() const -{ - QSystemTrayIcon trayIcon; // by creating a new tray icon, we actually make the DBus implementation refresh the connection (DBus) - trayIcon.hide(); // we ony hide it in order for the compiler to not optimise-out the object (make some use of it) - if (QSystemTrayIcon::isSystemTrayAvailable()) { // this ends up calling the underlying DBus connection (on DBus) - m_pTrayIcon->show(); - m_connector(m_pTrayIcon.get(), SIGNAL(activated(QSystemTrayIcon::ActivationReason))); - } - else { - QTimer::singleShot(2500, this, &TrayIcon::tryCreate); - } +void TrayIcon::tryCreate() const { + QSystemTrayIcon trayIcon; // by creating a new tray icon, we actually make the + // DBus implementation refresh the connection (DBus) + trayIcon.hide(); // we ony hide it in order for the compiler to not + // optimise-out the object (make some use of it) + if (QSystemTrayIcon::isSystemTrayAvailable()) { // this ends up calling the + // underlying DBus connection + // (on DBus) + m_pTrayIcon->show(); + m_connector(m_pTrayIcon.get(), + SIGNAL(activated(QSystemTrayIcon::ActivationReason))); + } else { + QTimer::singleShot(2500, this, &TrayIcon::tryCreate); + } } diff --git a/src/gui/src/TrayIcon.h b/src/gui/src/TrayIcon.h index b9d515537..0a5c77395 100644 --- a/src/gui/src/TrayIcon.h +++ b/src/gui/src/TrayIcon.h @@ -1,60 +1,55 @@ #pragma once -#include -#include -#include #include +#include +#include +#include #include #include -class TrayIcon : public QObject -{ - Q_OBJECT +class TrayIcon : public QObject { + Q_OBJECT public: - using TConnector = std::function; + using TConnector = std::function; - TrayIcon() - { - m_set = [this](const QIcon &icon){ - m_init = [this,icon](){ - this->set(icon); - }; - }; + TrayIcon() { + m_set = [this](const QIcon &icon) { + m_init = [this, icon]() { this->set(icon); }; + }; + } + + template + void create(TActionContainer const &actionContainer, + TConnector const &connector) { + m_connector = connector; + m_pTrayIconMenu = std::make_unique(); + + for (auto action : actionContainer) { + if (action) { + m_pTrayIconMenu->addAction(action); + } else { + m_pTrayIconMenu->addSeparator(); + } } - template - void create(TActionContainer const &actionContainer, TConnector const &connector) - { - m_connector = connector; - m_pTrayIconMenu = std::make_unique(); + m_pTrayIcon = std::make_unique(); + m_pTrayIcon->setContextMenu(m_pTrayIconMenu.get()); + m_pTrayIcon->setToolTip("Synergy"); + m_set = [this](const QIcon &icon) { m_pTrayIcon->setIcon(icon); }; - for (auto action: actionContainer) { - if (action) { - m_pTrayIconMenu->addAction(action); - } - else { - m_pTrayIconMenu->addSeparator(); - } - } - - m_pTrayIcon = std::make_unique(); - m_pTrayIcon->setContextMenu(m_pTrayIconMenu.get()); - m_pTrayIcon->setToolTip("Synergy"); - m_set = [this](const QIcon& icon) { m_pTrayIcon->setIcon(icon); }; - - tryCreate(); - if (m_init) { - m_init(); - m_init = std::function(); - } + tryCreate(); + if (m_init) { + m_init(); + m_init = std::function(); } + } - void tryCreate() const; - void set(const QIcon& icon) const { m_set(icon); } + void tryCreate() const; + void set(const QIcon &icon) const { m_set(icon); } private: - std::unique_ptr m_pTrayIcon {}; - std::unique_ptr m_pTrayIconMenu {}; - TConnector m_connector; - std::function m_init; - std::function m_set; + std::unique_ptr m_pTrayIcon{}; + std::unique_ptr m_pTrayIconMenu{}; + TConnector m_connector; + std::function m_init; + std::function m_set; }; diff --git a/src/gui/src/UpgradeDialog.cpp b/src/gui/src/UpgradeDialog.cpp index b41a8e9f7..4a603c12e 100644 --- a/src/gui/src/UpgradeDialog.cpp +++ b/src/gui/src/UpgradeDialog.cpp @@ -19,20 +19,17 @@ #include #include -UpgradeDialog::UpgradeDialog(QWidget* parent) : - QMessageBox(parent) -{ - setWindowTitle(QObject::tr("Upgrade to access this feature")); - addButton(QObject::tr("Close"), QMessageBox::RejectRole); - addButton(QObject::tr("Upgrade"), QMessageBox::AcceptRole); +UpgradeDialog::UpgradeDialog(QWidget *parent) : QMessageBox(parent) { + setWindowTitle(QObject::tr("Upgrade to access this feature")); + addButton(QObject::tr("Close"), QMessageBox::RejectRole); + addButton(QObject::tr("Upgrade"), QMessageBox::AcceptRole); } -void UpgradeDialog::showDialog(const QString& text, const QString& link) -{ - setText(QObject::tr(text.toStdString().c_str())); +void UpgradeDialog::showDialog(const QString &text, const QString &link) { + setText(QObject::tr(text.toStdString().c_str())); - if (exec() == QMessageBox::Accepted) - { - QDesktopServices::openUrl(QUrl(QCoreApplication::organizationDomain() + link)); - } + if (exec() == QMessageBox::Accepted) { + QDesktopServices::openUrl( + QUrl(QCoreApplication::organizationDomain() + link)); + } } diff --git a/src/gui/src/UpgradeDialog.h b/src/gui/src/UpgradeDialog.h index 9b119d4b5..f9ad199e5 100644 --- a/src/gui/src/UpgradeDialog.h +++ b/src/gui/src/UpgradeDialog.h @@ -17,9 +17,8 @@ #pragma once #include -class UpgradeDialog : public QMessageBox -{ +class UpgradeDialog : public QMessageBox { public: - explicit UpgradeDialog(QWidget *parent = nullptr); - void showDialog(const QString& text, const QString& link); + explicit UpgradeDialog(QWidget *parent = nullptr); + void showDialog(const QString &text, const QString &link); }; diff --git a/src/gui/src/VersionChecker.cpp b/src/gui/src/VersionChecker.cpp index e60304113..139d5fbef 100644 --- a/src/gui/src/VersionChecker.cpp +++ b/src/gui/src/VersionChecker.cpp @@ -18,111 +18,104 @@ #include "VersionChecker.h" -#include -#include -#include -#include #include +#include +#include +#include +#include #define VERSION_URL "https://api.symless.com/version" -VersionChecker::VersionChecker() -{ - m_manager = new QNetworkAccessManager(this); +VersionChecker::VersionChecker() { + m_manager = new QNetworkAccessManager(this); - connect(m_manager, SIGNAL(finished(QNetworkReply*)), - this, SLOT(replyFinished(QNetworkReply*))); + connect(m_manager, SIGNAL(finished(QNetworkReply *)), this, + SLOT(replyFinished(QNetworkReply *))); } -VersionChecker::~VersionChecker() -{ - delete m_manager; +VersionChecker::~VersionChecker() { delete m_manager; } + +void VersionChecker::checkLatest() { + auto request = QNetworkRequest(QUrl(VERSION_URL)); + request.setHeader(QNetworkRequest::UserAgentHeader, + QString("Synergy (") + SYNERGY_VERSION + ") " + + QSysInfo::prettyProductName()); + request.setRawHeader("X-Synergy-Version", SYNERGY_VERSION); + request.setRawHeader("X-Synergy-Language", + QLocale::system().name().toStdString().c_str()); + m_manager->get(request); } -void VersionChecker::checkLatest() -{ - auto request = QNetworkRequest(QUrl(VERSION_URL)); - request.setHeader(QNetworkRequest::UserAgentHeader, QString("Synergy (") + SYNERGY_VERSION + ") " + QSysInfo::prettyProductName()); - request.setRawHeader("X-Synergy-Version", SYNERGY_VERSION ); - request.setRawHeader("X-Synergy-Language", QLocale::system().name().toStdString().c_str() ); - m_manager->get(request); +void VersionChecker::replyFinished(QNetworkReply *reply) { + auto newestVersion = QString(reply->readAll()); + if (!newestVersion.isEmpty() && + compareVersions(SYNERGY_VERSION, newestVersion) > 0) { + emit updateFound(newestVersion); + } } -void VersionChecker::replyFinished(QNetworkReply* reply) -{ - auto newestVersion = QString(reply->readAll()); - if (!newestVersion.isEmpty() && compareVersions(SYNERGY_VERSION, newestVersion) > 0) { - emit updateFound(newestVersion); +int VersionChecker::getStageVersion(QString stage) const { + const char *stableName = "stable"; + const char *rcName = "rc"; + const char *betaName = "beta"; + + // use max int for stable so it's always the highest value. + const int stableValue = INT_MAX; + const int rcValue = 2; + const int betaValue = 1; + const int otherValue = 0; + + if (stage == stableName) { + return stableValue; + } else if (stage.toLower().startsWith(rcName)) { + QRegExp rx("\\d*", Qt::CaseInsensitive); + if (rx.indexIn(stage) != -1) { + // return the rc value plus the rc number (e.g. 2 + 1) + // this should be ok since stable is max int. + return rcValue + rx.cap(1).toInt(); } + } else if (stage == betaName) { + return betaValue; + } + + return otherValue; } -int VersionChecker::getStageVersion(QString stage) const -{ - const char* stableName = "stable"; - const char* rcName = "rc"; - const char* betaName = "beta"; +int VersionChecker::compareVersions(const QString &left, const QString &right) { + if (left.compare(right) == 0) + return 0; // versions are same. - // use max int for stable so it's always the highest value. - const int stableValue = INT_MAX; - const int rcValue = 2; - const int betaValue = 1; - const int otherValue = 0; + QStringList leftParts = left.split("-"); + QStringList rightParts = right.split("-"); - if (stage == stableName) - { - return stableValue; - } - else if (stage.toLower().startsWith(rcName)) - { - QRegExp rx("\\d*", Qt::CaseInsensitive); - if (rx.indexIn(stage) != -1) - { - // return the rc value plus the rc number (e.g. 2 + 1) - // this should be ok since stable is max int. - return rcValue + rx.cap(1).toInt(); - } - } - else if (stage == betaName) - { - return betaValue; - } - - return otherValue; + if (leftParts.size() < 1 || rightParts.size() < 1) + return 0; // versions are same. + + QString leftNumber = leftParts.at(0); + QString rightNumber = rightParts.at(0); + + QStringList leftNumberParts = left.split("."); + QStringList rightNumberParts = right.split("."); + + const int leftMajor = leftNumberParts.at(0).toInt(); + const int leftMinor = leftNumberParts.at(1).toInt(); + const int leftPatch = leftNumberParts.at(2).toInt(); + const int leftStage = + leftParts.size() > 1 ? getStageVersion(leftParts.at(1)) : 0; + + const int rightMajor = rightNumberParts.at(0).toInt(); + const int rightMinor = rightNumberParts.at(1).toInt(); + const int rightPatch = rightNumberParts.at(2).toInt(); + const int rightStage = + rightParts.size() > 1 ? getStageVersion(rightParts.at(1)) : 0; + + const bool rightWins = + (rightMajor > leftMajor) || + ((rightMajor >= leftMajor) && (rightMinor > leftMinor)) || + ((rightMajor >= leftMajor) && (rightMinor >= leftMinor) && + (rightPatch > leftPatch)) || + ((rightMajor >= leftMajor) && (rightMinor >= leftMinor) && + (rightPatch >= leftPatch) && (rightStage > leftStage)); + + return rightWins ? 1 : -1; } - -int VersionChecker::compareVersions(const QString& left, const QString& right) -{ - if (left.compare(right) == 0) - return 0; // versions are same. - - QStringList leftParts = left.split("-"); - QStringList rightParts = right.split("-"); - - if (leftParts.size() < 1 || rightParts.size() < 1) - return 0; // versions are same. - - QString leftNumber = leftParts.at(0); - QString rightNumber = rightParts.at(0); - - QStringList leftNumberParts = left.split("."); - QStringList rightNumberParts = right.split("."); - - const int leftMajor = leftNumberParts.at(0).toInt(); - const int leftMinor = leftNumberParts.at(1).toInt(); - const int leftPatch = leftNumberParts.at(2).toInt(); - const int leftStage = leftParts.size() > 1 ? getStageVersion(leftParts.at(1)) : 0; - - const int rightMajor = rightNumberParts.at(0).toInt(); - const int rightMinor = rightNumberParts.at(1).toInt(); - const int rightPatch = rightNumberParts.at(2).toInt(); - const int rightStage = rightParts.size() > 1 ? getStageVersion(rightParts.at(1)) : 0; - - const bool rightWins = - ( rightMajor > leftMajor) || - ((rightMajor >= leftMajor) && (rightMinor > leftMinor)) || - ((rightMajor >= leftMajor) && (rightMinor >= leftMinor) && (rightPatch > leftPatch)) || - ((rightMajor >= leftMajor) && (rightMinor >= leftMinor) && (rightPatch >= leftPatch) && (rightStage > leftStage)); - - return rightWins ? 1 : -1; -} - diff --git a/src/gui/src/VersionChecker.h b/src/gui/src/VersionChecker.h index cce00ad22..2d4d89184 100644 --- a/src/gui/src/VersionChecker.h +++ b/src/gui/src/VersionChecker.h @@ -24,27 +24,28 @@ class QNetworkAccessManager; class QNetworkReply; -class VersionChecker : public QObject -{ - Q_OBJECT +class VersionChecker : public QObject { + Q_OBJECT public: - VersionChecker(); - virtual ~VersionChecker(); - void checkLatest(); - void setApp(const QString& app) { m_app = app; } - int compareVersions(const QString& left, const QString& right); + VersionChecker(); + virtual ~VersionChecker(); + void checkLatest(); + void setApp(const QString &app) { m_app = app; } + int compareVersions(const QString &left, const QString &right); public slots: - void replyFinished(QNetworkReply* reply); + void replyFinished(QNetworkReply *reply); signals: - void updateFound(const QString& version); -private: - QNetworkAccessManager* m_manager; - QString m_app; + void updateFound(const QString &version); - /** - * \brief Converts a string stage to a integer value - * \param stage The string containing the stage version - * \return An integer representation of the stage, the higher the number the more recent the version - */ - int getStageVersion(QString stage) const; +private: + QNetworkAccessManager *m_manager; + QString m_app; + + /** + * \brief Converts a string stage to a integer value + * \param stage The string containing the stage version + * \return An integer representation of the stage, the higher the number the + * more recent the version + */ + int getStageVersion(QString stage) const; }; diff --git a/src/gui/src/Zeroconf.cpp b/src/gui/src/Zeroconf.cpp index b2a0e6b7f..52b7780ba 100644 --- a/src/gui/src/Zeroconf.cpp +++ b/src/gui/src/Zeroconf.cpp @@ -17,42 +17,33 @@ #include "Zeroconf.h" -#include "ZeroconfService.h" #include "MainWindow.h" +#include "ZeroconfService.h" -Zeroconf::Zeroconf(MainWindow* mainWindow) : - m_pMainWindow(mainWindow), - m_pZeroconfService(nullptr) -{ +Zeroconf::Zeroconf(MainWindow *mainWindow) + : m_pMainWindow(mainWindow), m_pZeroconfService(nullptr) {} + +Zeroconf::~Zeroconf() { stopService(); } + +void Zeroconf::startService() { + if (m_pZeroconfService != nullptr) { + m_pMainWindow->appendLogInfo("restarting zeroconf service"); + delete m_pZeroconfService; + m_pZeroconfService = nullptr; + } else { + m_pMainWindow->appendLogInfo("starting zeroconf service"); + } + + m_pZeroconfService = new ZeroconfService(m_pMainWindow); + + m_pMainWindow->appendLogInfo("started zeroconf service"); } -Zeroconf::~Zeroconf() -{ - stopService(); -} - -void Zeroconf::startService() -{ - if (m_pZeroconfService != nullptr) { - m_pMainWindow->appendLogInfo("restarting zeroconf service"); - delete m_pZeroconfService; - m_pZeroconfService = nullptr; - } - else { - m_pMainWindow->appendLogInfo("starting zeroconf service"); - } - - m_pZeroconfService = new ZeroconfService(m_pMainWindow); - - m_pMainWindow->appendLogInfo("started zeroconf service"); -} - -void Zeroconf::stopService() -{ - if (m_pZeroconfService != nullptr) { - m_pMainWindow->appendLogInfo("stopping zeroconf service"); - delete m_pZeroconfService; - m_pZeroconfService = nullptr; - m_pMainWindow->appendLogInfo("stopped zeroconf service"); - } +void Zeroconf::stopService() { + if (m_pZeroconfService != nullptr) { + m_pMainWindow->appendLogInfo("stopping zeroconf service"); + delete m_pZeroconfService; + m_pZeroconfService = nullptr; + m_pMainWindow->appendLogInfo("stopped zeroconf service"); + } } diff --git a/src/gui/src/Zeroconf.h b/src/gui/src/Zeroconf.h index c2e771915..58528c4cc 100644 --- a/src/gui/src/Zeroconf.h +++ b/src/gui/src/Zeroconf.h @@ -22,17 +22,16 @@ class MainWindow; class ZeroconfService; -class Zeroconf : public QObject -{ - Q_OBJECT +class Zeroconf : public QObject { + Q_OBJECT public: - Zeroconf(MainWindow* mainWindow); - virtual ~Zeroconf(); - void startService(); - void stopService(); + Zeroconf(MainWindow *mainWindow); + virtual ~Zeroconf(); + void startService(); + void stopService(); private: - MainWindow* m_pMainWindow; - ZeroconfService* m_pZeroconfService; + MainWindow *m_pMainWindow; + ZeroconfService *m_pZeroconfService; }; diff --git a/src/gui/src/ZeroconfBrowser.cpp b/src/gui/src/ZeroconfBrowser.cpp index 00764ce53..a636a2b43 100644 --- a/src/gui/src/ZeroconfBrowser.cpp +++ b/src/gui/src/ZeroconfBrowser.cpp @@ -19,74 +19,62 @@ #include -ZeroconfBrowser::ZeroconfBrowser(QObject* parent) : - QObject(parent), - m_DnsServiceRef(0), - m_pSocket(0) -{ +ZeroconfBrowser::ZeroconfBrowser(QObject *parent) + : QObject(parent), m_DnsServiceRef(0), m_pSocket(0) {} + +ZeroconfBrowser::~ZeroconfBrowser() { + if (m_pSocket) { + delete m_pSocket; + } + + if (m_DnsServiceRef) { + DNSServiceRefDeallocate(m_DnsServiceRef); + m_DnsServiceRef = 0; + } } -ZeroconfBrowser::~ZeroconfBrowser() -{ - if (m_pSocket) { - delete m_pSocket; - } +void ZeroconfBrowser::browseForType(const QString &type) { + DNSServiceErrorType err = DNSServiceBrowse( + &m_DnsServiceRef, 0, 0, type.toUtf8().constData(), 0, browseReply, this); - if (m_DnsServiceRef) { - DNSServiceRefDeallocate(m_DnsServiceRef); - m_DnsServiceRef = 0; + if (err != kDNSServiceErr_NoError) { + emit error(err); + } else { + int sockFD = DNSServiceRefSockFD(m_DnsServiceRef); + if (sockFD == -1) { + emit error(kDNSServiceErr_Invalid); + } else { + m_pSocket = new QSocketNotifier(sockFD, QSocketNotifier::Read, this); + connect(m_pSocket, SIGNAL(activated(int)), this, SLOT(socketReadyRead())); } + } } -void ZeroconfBrowser::browseForType(const QString& type) -{ - DNSServiceErrorType err = DNSServiceBrowse(&m_DnsServiceRef, 0, 0, - type.toUtf8().constData(), 0, browseReply, this); - - if (err != kDNSServiceErr_NoError) { - emit error(err); - } - else { - int sockFD = DNSServiceRefSockFD(m_DnsServiceRef); - if (sockFD == -1) { - emit error(kDNSServiceErr_Invalid); - } - else { - m_pSocket = new QSocketNotifier(sockFD, QSocketNotifier::Read, this); - connect(m_pSocket, SIGNAL(activated(int)), this, - SLOT(socketReadyRead())); - } - } +void ZeroconfBrowser::socketReadyRead() { + DNSServiceErrorType err = DNSServiceProcessResult(m_DnsServiceRef); + if (err != kDNSServiceErr_NoError) { + emit error(err); + } } -void ZeroconfBrowser::socketReadyRead() -{ - DNSServiceErrorType err = DNSServiceProcessResult(m_DnsServiceRef); - if (err != kDNSServiceErr_NoError) { - emit error(err); - } -} - -void ZeroconfBrowser::browseReply(DNSServiceRef, DNSServiceFlags flags, - quint32, DNSServiceErrorType errorCode, const char* serviceName, - const char* regType, const char* replyDomain, void* context) -{ - ZeroconfBrowser* browser = static_cast(context); - if (errorCode != kDNSServiceErr_NoError) { - emit browser->error(errorCode); - } - else { - ZeroconfRecord record(serviceName, regType, replyDomain); - if (flags & kDNSServiceFlagsAdd) { - if (!browser->m_Records.contains(record)) { - browser->m_Records.append(record); - } - } - else { - browser->m_Records.removeAll(record); - } - if (!(flags & kDNSServiceFlagsMoreComing)) { - emit browser->currentRecordsChanged(browser->m_Records); - } +void ZeroconfBrowser::browseReply(DNSServiceRef, DNSServiceFlags flags, quint32, + DNSServiceErrorType errorCode, + const char *serviceName, const char *regType, + const char *replyDomain, void *context) { + ZeroconfBrowser *browser = static_cast(context); + if (errorCode != kDNSServiceErr_NoError) { + emit browser->error(errorCode); + } else { + ZeroconfRecord record(serviceName, regType, replyDomain); + if (flags & kDNSServiceFlagsAdd) { + if (!browser->m_Records.contains(record)) { + browser->m_Records.append(record); + } + } else { + browser->m_Records.removeAll(record); } + if (!(flags & kDNSServiceFlagsMoreComing)) { + emit browser->currentRecordsChanged(browser->m_Records); + } + } } diff --git a/src/gui/src/ZeroconfBrowser.h b/src/gui/src/ZeroconfBrowser.h index c15a24bf0..1456a8b93 100644 --- a/src/gui/src/ZeroconfBrowser.h +++ b/src/gui/src/ZeroconfBrowser.h @@ -21,37 +21,38 @@ #include #define _MSL_STDINT_H -#include #include +#include class QSocketNotifier; -class ZeroconfBrowser : public QObject -{ - Q_OBJECT +class ZeroconfBrowser : public QObject { + Q_OBJECT public: - ZeroconfBrowser(QObject* parent = 0); - ~ZeroconfBrowser(); - void browseForType(const QString& type); - inline QList currentRecords() const { return m_Records; } - inline QString serviceType() const { return m_BrowsingType; } + ZeroconfBrowser(QObject *parent = 0); + ~ZeroconfBrowser(); + void browseForType(const QString &type); + inline QList currentRecords() const { return m_Records; } + inline QString serviceType() const { return m_BrowsingType; } signals: - void currentRecordsChanged(const QList& list); - void error(DNSServiceErrorType err); + void currentRecordsChanged(const QList &list); + void error(DNSServiceErrorType err); private slots: - void socketReadyRead(); + void socketReadyRead(); private: - static void DNSSD_API browseReply(DNSServiceRef, DNSServiceFlags flags, - quint32, DNSServiceErrorType errorCode, const char* serviceName, - const char* regType, const char* replyDomain, void* context); + static void DNSSD_API browseReply(DNSServiceRef, DNSServiceFlags flags, + quint32, DNSServiceErrorType errorCode, + const char *serviceName, + const char *regType, + const char *replyDomain, void *context); private: - DNSServiceRef m_DnsServiceRef; - QSocketNotifier* m_pSocket; - QList m_Records; - QString m_BrowsingType; + DNSServiceRef m_DnsServiceRef; + QSocketNotifier *m_pSocket; + QList m_Records; + QString m_BrowsingType; }; diff --git a/src/gui/src/ZeroconfRecord.h b/src/gui/src/ZeroconfRecord.h index 0da155a1e..73d25e351 100644 --- a/src/gui/src/ZeroconfRecord.h +++ b/src/gui/src/ZeroconfRecord.h @@ -20,31 +20,28 @@ #include #include -class ZeroconfRecord -{ +class ZeroconfRecord { public: - ZeroconfRecord() {} - ZeroconfRecord(const QString& name, const QString& regType, - const QString& domain) - : serviceName(name), registeredType(regType), replyDomain(domain) - {} - ZeroconfRecord(const char* name, const char* regType, const char* domain) - { - serviceName = QString::fromUtf8(name); - registeredType = QString::fromUtf8(regType); - replyDomain = QString::fromUtf8(domain); - } + ZeroconfRecord() {} + ZeroconfRecord(const QString &name, const QString ®Type, + const QString &domain) + : serviceName(name), registeredType(regType), replyDomain(domain) {} + ZeroconfRecord(const char *name, const char *regType, const char *domain) { + serviceName = QString::fromUtf8(name); + registeredType = QString::fromUtf8(regType); + replyDomain = QString::fromUtf8(domain); + } - bool operator==(const ZeroconfRecord& other) const { - return serviceName == other.serviceName - && registeredType == other.registeredType - && replyDomain == other.replyDomain; - } + bool operator==(const ZeroconfRecord &other) const { + return serviceName == other.serviceName && + registeredType == other.registeredType && + replyDomain == other.replyDomain; + } public: - QString serviceName; - QString registeredType; - QString replyDomain; + QString serviceName; + QString registeredType; + QString replyDomain; }; Q_DECLARE_METATYPE(ZeroconfRecord) diff --git a/src/gui/src/ZeroconfRegister.cpp b/src/gui/src/ZeroconfRegister.cpp index 3e7e3c754..b86179f99 100644 --- a/src/gui/src/ZeroconfRegister.cpp +++ b/src/gui/src/ZeroconfRegister.cpp @@ -19,76 +19,69 @@ #include -ZeroconfRegister::ZeroconfRegister(QObject* parent) : - QObject(parent), - m_DnsServiceRef(0), - m_pSocket(0) -{ +ZeroconfRegister::ZeroconfRegister(QObject *parent) + : QObject(parent), m_DnsServiceRef(0), m_pSocket(0) {} + +ZeroconfRegister::~ZeroconfRegister() { + if (m_pSocket) { + delete m_pSocket; + } + + if (m_DnsServiceRef) { + DNSServiceRefDeallocate(m_DnsServiceRef); + m_DnsServiceRef = 0; + } } -ZeroconfRegister::~ZeroconfRegister() -{ - if (m_pSocket) { - delete m_pSocket; - } +void ZeroconfRegister::registerService(const ZeroconfRecord &record, + quint16 servicePort) { + if (m_DnsServiceRef) { + qWarning("Warning: Already registered a service for this object"); + return; + } - if (m_DnsServiceRef) { - DNSServiceRefDeallocate(m_DnsServiceRef); - m_DnsServiceRef = 0; - } -} - -void ZeroconfRegister::registerService(const ZeroconfRecord& record, - quint16 servicePort) -{ - if (m_DnsServiceRef) { - qWarning("Warning: Already registered a service for this object"); - return; - } - - quint16 bigEndianPort = servicePort; + quint16 bigEndianPort = servicePort; #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN - { - bigEndianPort = 0 | ((servicePort & 0x00ff) << 8) | ((servicePort & 0xff00) >> 8); - } + { + bigEndianPort = + 0 | ((servicePort & 0x00ff) << 8) | ((servicePort & 0xff00) >> 8); + } #endif - DNSServiceErrorType err = DNSServiceRegister(&m_DnsServiceRef, - kDNSServiceFlagsNoAutoRename, 0, - record.serviceName.toUtf8().constData(), - record.registeredType.toUtf8().constData(), - record.replyDomain.isEmpty() ? 0 : record.replyDomain.toUtf8().constData(), - 0, bigEndianPort, 0, 0, registerService, this); + DNSServiceErrorType err = DNSServiceRegister( + &m_DnsServiceRef, kDNSServiceFlagsNoAutoRename, 0, + record.serviceName.toUtf8().constData(), + record.registeredType.toUtf8().constData(), + record.replyDomain.isEmpty() ? 0 + : record.replyDomain.toUtf8().constData(), + 0, bigEndianPort, 0, 0, registerService, this); - if (err != kDNSServiceErr_NoError) { - emit error(err); - } - else { - int sockfd = DNSServiceRefSockFD(m_DnsServiceRef); - if (sockfd == -1) { - emit error(kDNSServiceErr_Invalid); - } - else { - m_pSocket = new QSocketNotifier(sockfd, QSocketNotifier::Read, this); - connect(m_pSocket, SIGNAL(activated(int)), this, SLOT(socketReadyRead())); - } + if (err != kDNSServiceErr_NoError) { + emit error(err); + } else { + int sockfd = DNSServiceRefSockFD(m_DnsServiceRef); + if (sockfd == -1) { + emit error(kDNSServiceErr_Invalid); + } else { + m_pSocket = new QSocketNotifier(sockfd, QSocketNotifier::Read, this); + connect(m_pSocket, SIGNAL(activated(int)), this, SLOT(socketReadyRead())); } + } } -void ZeroconfRegister::socketReadyRead() -{ - DNSServiceErrorType err = DNSServiceProcessResult(m_DnsServiceRef); - if (err != kDNSServiceErr_NoError) { - emit error(err); - } +void ZeroconfRegister::socketReadyRead() { + DNSServiceErrorType err = DNSServiceProcessResult(m_DnsServiceRef); + if (err != kDNSServiceErr_NoError) { + emit error(err); + } } void ZeroconfRegister::registerService(DNSServiceRef, DNSServiceFlags, - DNSServiceErrorType errorCode, const char* name, const char* regtype, - const char* domain, void* data) -{ - ZeroconfRegister* serviceRegister = static_cast(data); - if (errorCode != kDNSServiceErr_NoError) { - emit serviceRegister->error(errorCode); - } + DNSServiceErrorType errorCode, + const char *name, const char *regtype, + const char *domain, void *data) { + ZeroconfRegister *serviceRegister = static_cast(data); + if (errorCode != kDNSServiceErr_NoError) { + emit serviceRegister->error(errorCode); + } } diff --git a/src/gui/src/ZeroconfRegister.h b/src/gui/src/ZeroconfRegister.h index 05487e12e..389f192eb 100644 --- a/src/gui/src/ZeroconfRegister.h +++ b/src/gui/src/ZeroconfRegister.h @@ -31,31 +31,31 @@ class QSocketNotifier; #endif #include -class ZeroconfRegister : public QObject -{ - Q_OBJECT +class ZeroconfRegister : public QObject { + Q_OBJECT public: - ZeroconfRegister(QObject* parent = 0); - ~ZeroconfRegister(); + ZeroconfRegister(QObject *parent = 0); + ~ZeroconfRegister(); - void registerService(const ZeroconfRecord& record, quint16 servicePort); - inline ZeroconfRecord registeredRecord() const { return finalRecord; } + void registerService(const ZeroconfRecord &record, quint16 servicePort); + inline ZeroconfRecord registeredRecord() const { return finalRecord; } signals: - void error(DNSServiceErrorType error); - void serviceRegistered(const ZeroconfRecord& record); + void error(DNSServiceErrorType error); + void serviceRegistered(const ZeroconfRecord &record); private slots: - void socketReadyRead(); + void socketReadyRead(); private: - static void DNSSD_API registerService(DNSServiceRef sdRef, - DNSServiceFlags, DNSServiceErrorType errorCode, const char* name, - const char* regtype, const char* domain, void* context); + static void DNSSD_API registerService(DNSServiceRef sdRef, DNSServiceFlags, + DNSServiceErrorType errorCode, + const char *name, const char *regtype, + const char *domain, void *context); private: - DNSServiceRef m_DnsServiceRef; - QSocketNotifier* m_pSocket; - ZeroconfRecord finalRecord; + DNSServiceRef m_DnsServiceRef; + QSocketNotifier *m_pSocket; + ZeroconfRecord finalRecord; }; diff --git a/src/gui/src/ZeroconfServer.cpp b/src/gui/src/ZeroconfServer.cpp index e4d6dfd85..406b7fee8 100644 --- a/src/gui/src/ZeroconfServer.cpp +++ b/src/gui/src/ZeroconfServer.cpp @@ -20,14 +20,10 @@ #include -ZeroconfServer::ZeroconfServer(QObject* parent) : - QTcpServer(parent) -{ -} +ZeroconfServer::ZeroconfServer(QObject *parent) : QTcpServer(parent) {} -void ZeroconfServer::incomingConnection(qintptr socketDescriptor) -{ - ZeroconfThread* thread = new ZeroconfThread(socketDescriptor, this); - connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); - thread->start(); +void ZeroconfServer::incomingConnection(qintptr socketDescriptor) { + ZeroconfThread *thread = new ZeroconfThread(socketDescriptor, this); + connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); + thread->start(); } diff --git a/src/gui/src/ZeroconfServer.h b/src/gui/src/ZeroconfServer.h index 2f6c6f119..941881c8d 100644 --- a/src/gui/src/ZeroconfServer.h +++ b/src/gui/src/ZeroconfServer.h @@ -22,16 +22,15 @@ class ZeroconfRegister; -class ZeroconfServer : public QTcpServer -{ - Q_OBJECT +class ZeroconfServer : public QTcpServer { + Q_OBJECT public: - ZeroconfServer(QObject* parent = 0); + ZeroconfServer(QObject *parent = 0); protected: - void incomingConnection(qintptr socketDescriptor) override; + void incomingConnection(qintptr socketDescriptor) override; private: - QStringList fortunes; + QStringList fortunes; }; diff --git a/src/gui/src/ZeroconfService.cpp b/src/gui/src/ZeroconfService.cpp index 461ac1392..022a5c4e6 100644 --- a/src/gui/src/ZeroconfService.cpp +++ b/src/gui/src/ZeroconfService.cpp @@ -18,119 +18,102 @@ #include "ZeroconfService.h" #include "MainWindow.h" -#include "ZeroconfRegister.h" #include "ZeroconfBrowser.h" +#include "ZeroconfRegister.h" -#include #include +#include #define _MSL_STDINT_H -#include #include +#include -static const QStringList preferedIPAddress( - QStringList() << - "192.168." << - "10." << - "172."); +static const QStringList preferedIPAddress(QStringList() << "192.168." + << "10." + << "172."); -const char* ZeroconfService:: m_ServerServiceName = "_synergyServer._tcp"; -const char* ZeroconfService:: m_ClientServiceName = "_synergyClient._tcp"; +const char *ZeroconfService::m_ServerServiceName = "_synergyServer._tcp"; +const char *ZeroconfService::m_ClientServiceName = "_synergyClient._tcp"; -ZeroconfService::ZeroconfService(MainWindow* mainWindow) : - m_pMainWindow(mainWindow), - m_pZeroconfBrowser(nullptr), - m_pZeroconfRegister(nullptr), - m_ServiceRegistered(false) -{ - if (m_pMainWindow->synergyType() == MainWindow::synergyServer) { - if (registerService(true)) { - m_pZeroconfBrowser = new ZeroconfBrowser(this); - connect(m_pZeroconfBrowser, SIGNAL( - currentRecordsChanged(const QList&)), - this, SLOT(clientDetected(const QList&))); - m_pZeroconfBrowser->browseForType( - QLatin1String(m_ClientServiceName)); - } - } - else { - m_pZeroconfBrowser = new ZeroconfBrowser(this); - connect(m_pZeroconfBrowser, SIGNAL( - currentRecordsChanged(const QList&)), - this, SLOT(serverDetected(const QList&))); - m_pZeroconfBrowser->browseForType( - QLatin1String(m_ServerServiceName)); +ZeroconfService::ZeroconfService(MainWindow *mainWindow) + : m_pMainWindow(mainWindow), m_pZeroconfBrowser(nullptr), + m_pZeroconfRegister(nullptr), m_ServiceRegistered(false) { + if (m_pMainWindow->synergyType() == MainWindow::synergyServer) { + if (registerService(true)) { + m_pZeroconfBrowser = new ZeroconfBrowser(this); + connect(m_pZeroconfBrowser, + SIGNAL(currentRecordsChanged(const QList &)), + this, SLOT(clientDetected(const QList &))); + m_pZeroconfBrowser->browseForType(QLatin1String(m_ClientServiceName)); } + } else { + m_pZeroconfBrowser = new ZeroconfBrowser(this); + connect(m_pZeroconfBrowser, + SIGNAL(currentRecordsChanged(const QList &)), this, + SLOT(serverDetected(const QList &))); + m_pZeroconfBrowser->browseForType(QLatin1String(m_ServerServiceName)); + } - connect(m_pZeroconfBrowser, SIGNAL(error(DNSServiceErrorType)), - this, SLOT(errorHandle(DNSServiceErrorType))); + connect(m_pZeroconfBrowser, SIGNAL(error(DNSServiceErrorType)), this, + SLOT(errorHandle(DNSServiceErrorType))); } -ZeroconfService::~ZeroconfService() -{ - if (m_pZeroconfBrowser) { - delete m_pZeroconfBrowser; - } - if (m_pZeroconfRegister) { - delete m_pZeroconfRegister; - } +ZeroconfService::~ZeroconfService() { + if (m_pZeroconfBrowser) { + delete m_pZeroconfBrowser; + } + if (m_pZeroconfRegister) { + delete m_pZeroconfRegister; + } } -void ZeroconfService::serverDetected(const QList& list) -{ - foreach (ZeroconfRecord record, list) { - registerService(false); - m_pMainWindow->appendLogInfo(tr("zeroconf server detected: %1").arg( - record.serviceName)); - m_pMainWindow->addZeroconfServer(record.serviceName); +void ZeroconfService::serverDetected(const QList &list) { + foreach (ZeroconfRecord record, list) { + registerService(false); + m_pMainWindow->appendLogInfo( + tr("zeroconf server detected: %1").arg(record.serviceName)); + m_pMainWindow->addZeroconfServer(record.serviceName); + } +} + +void ZeroconfService::clientDetected(const QList &list) { + foreach (ZeroconfRecord record, list) { + m_pMainWindow->appendLogInfo( + tr("zeroconf client detected: %1").arg(record.serviceName)); + m_pMainWindow->autoAddScreen(record.serviceName); + } +} + +void ZeroconfService::errorHandle(DNSServiceErrorType errorCode) { + QMessageBox::critical(m_pMainWindow, tr("Synergy Auto Config"), + tr("Error code: %1.").arg(errorCode)); +} + +bool ZeroconfService::registerService(bool server) { + bool result = true; + + if (!m_ServiceRegistered) { + if (!m_zeroconfServer.listen()) { + QMessageBox::critical(m_pMainWindow, tr("Synergy Auto Config"), + tr("Unable to start zeroconf: %1.") + .arg(m_zeroconfServer.errorString())); + result = false; + } else { + m_pZeroconfRegister = new ZeroconfRegister(this); + if (server) { + m_pZeroconfRegister->registerService( + ZeroconfRecord(tr("%1").arg(m_pMainWindow->getScreenName()), + QLatin1String(m_ServerServiceName), QString()), + m_zeroconfServer.serverPort()); + } else { + m_pZeroconfRegister->registerService( + ZeroconfRecord(tr("%1").arg(m_pMainWindow->getScreenName()), + QLatin1String(m_ClientServiceName), QString()), + m_zeroconfServer.serverPort()); + } + + m_ServiceRegistered = true; } -} - -void ZeroconfService::clientDetected(const QList& list) -{ - foreach (ZeroconfRecord record, list) { - m_pMainWindow->appendLogInfo(tr("zeroconf client detected: %1").arg( - record.serviceName)); - m_pMainWindow->autoAddScreen(record.serviceName); - } -} - -void ZeroconfService::errorHandle(DNSServiceErrorType errorCode) -{ - QMessageBox::critical( - m_pMainWindow, tr("Synergy Auto Config"), - tr("Error code: %1.").arg(errorCode)); -} - -bool ZeroconfService::registerService(bool server) -{ - bool result = true; - - if (!m_ServiceRegistered) { - if (!m_zeroconfServer.listen()) { - QMessageBox::critical( - m_pMainWindow, tr("Synergy Auto Config"), - tr("Unable to start zeroconf: %1.") - .arg(m_zeroconfServer.errorString())); - result = false; - } - else { - m_pZeroconfRegister = new ZeroconfRegister(this); - if (server) { - m_pZeroconfRegister->registerService( - ZeroconfRecord(tr("%1").arg(m_pMainWindow->getScreenName()), - QLatin1String(m_ServerServiceName), QString()), - m_zeroconfServer.serverPort()); - } - else { - m_pZeroconfRegister->registerService( - ZeroconfRecord(tr("%1").arg(m_pMainWindow->getScreenName()), - QLatin1String(m_ClientServiceName), QString()), - m_zeroconfServer.serverPort()); - } - - m_ServiceRegistered = true; - } - } - - return result; + } + + return result; } diff --git a/src/gui/src/ZeroconfService.h b/src/gui/src/ZeroconfService.h index d77125323..81060e101 100644 --- a/src/gui/src/ZeroconfService.h +++ b/src/gui/src/ZeroconfService.h @@ -17,40 +17,39 @@ #pragma once -#include "ZeroconfServer.h" #include "ZeroconfRecord.h" +#include "ZeroconfServer.h" #include -typedef int32_t DNSServiceErrorType; +typedef int32_t DNSServiceErrorType; class ZeroconfRegister; class ZeroconfBrowser; class MainWindow; -class ZeroconfService : public QObject -{ - Q_OBJECT +class ZeroconfService : public QObject { + Q_OBJECT public: - ZeroconfService(MainWindow* mainWindow); - ~ZeroconfService(); + ZeroconfService(MainWindow *mainWindow); + ~ZeroconfService(); private slots: - void serverDetected(const QList& list); - void clientDetected(const QList& list); - void errorHandle(DNSServiceErrorType errorCode); + void serverDetected(const QList &list); + void clientDetected(const QList &list); + void errorHandle(DNSServiceErrorType errorCode); private: - bool registerService(bool server); + bool registerService(bool server); private: - MainWindow* m_pMainWindow; - ZeroconfServer m_zeroconfServer; - ZeroconfBrowser* m_pZeroconfBrowser; - ZeroconfRegister* m_pZeroconfRegister; - bool m_ServiceRegistered; + MainWindow *m_pMainWindow; + ZeroconfServer m_zeroconfServer; + ZeroconfBrowser *m_pZeroconfBrowser; + ZeroconfRegister *m_pZeroconfRegister; + bool m_ServiceRegistered; - static const char* m_ServerServiceName; - static const char* m_ClientServiceName; + static const char *m_ServerServiceName; + static const char *m_ClientServiceName; }; diff --git a/src/gui/src/ZeroconfThread.cpp b/src/gui/src/ZeroconfThread.cpp index 48e9fd8ae..631ba9bc1 100644 --- a/src/gui/src/ZeroconfThread.cpp +++ b/src/gui/src/ZeroconfThread.cpp @@ -19,20 +19,16 @@ #include -ZeroconfThread::ZeroconfThread(int socketDescriptor, QObject* parent) : - QThread(parent), - m_SocketDescriptor(socketDescriptor) -{ -} +ZeroconfThread::ZeroconfThread(int socketDescriptor, QObject *parent) + : QThread(parent), m_SocketDescriptor(socketDescriptor) {} -void ZeroconfThread::run() -{ - QTcpSocket tcpSocket; - if (!tcpSocket.setSocketDescriptor(m_SocketDescriptor)) { - emit error(tcpSocket.error()); - return; - } +void ZeroconfThread::run() { + QTcpSocket tcpSocket; + if (!tcpSocket.setSocketDescriptor(m_SocketDescriptor)) { + emit error(tcpSocket.error()); + return; + } - tcpSocket.disconnectFromHost(); - tcpSocket.waitForDisconnected(); + tcpSocket.disconnectFromHost(); + tcpSocket.waitForDisconnected(); } diff --git a/src/gui/src/ZeroconfThread.h b/src/gui/src/ZeroconfThread.h index b2e7485e2..07c98dd4e 100644 --- a/src/gui/src/ZeroconfThread.h +++ b/src/gui/src/ZeroconfThread.h @@ -17,22 +17,21 @@ #pragma once -#include #include +#include -class ZeroconfThread : public QThread -{ - Q_OBJECT +class ZeroconfThread : public QThread { + Q_OBJECT public: - ZeroconfThread(int socketDescriptor, QObject* parent); + ZeroconfThread(int socketDescriptor, QObject *parent); - void run(); + void run(); signals: - void error(QTcpSocket::SocketError socketError); + void error(QTcpSocket::SocketError socketError); private: - int m_SocketDescriptor; - QString m_Text; + int m_SocketDescriptor; + QString m_Text; }; diff --git a/src/gui/src/main.cpp b/src/gui/src/main.cpp index d2ab11aff..ea9564acc 100644 --- a/src/gui/src/main.cpp +++ b/src/gui/src/main.cpp @@ -16,16 +16,16 @@ * along with this program. If not, see . */ -#include "QSynergyApplication.h" +#include "AppConfig.h" #include "LicenseManager.h" #include "MainWindow.h" -#include "AppConfig.h" +#include "QSynergyApplication.h" #include "SetupWizard.h" #include "SetupWizardBlocker.h" +#include #include #include -#include #if defined(Q_OS_MAC) #include @@ -35,13 +35,9 @@ #include #endif -class QThreadImpl : public QThread -{ +class QThreadImpl : public QThread { public: - static void msleep(unsigned long msecs) - { - QThread::msleep(msecs); - } + static void msleep(unsigned long msecs) { QThread::msleep(msecs); } }; QString getSystemSettingPath(); @@ -50,117 +46,111 @@ QString getSystemSettingPath(); bool checkMacAssistiveDevices(); #endif -int main(int argc, char* argv[]) -{ +int main(int argc, char *argv[]) { #ifdef Q_OS_DARWIN - /* Workaround for QTBUG-40332 - "High ping when QNetworkAccessManager is instantiated" */ - ::setenv ("QT_BEARER_POLL_TIMEOUT", "-1", 1); + /* Workaround for QTBUG-40332 - "High ping when QNetworkAccessManager is + * instantiated" */ + ::setenv("QT_BEARER_POLL_TIMEOUT", "-1", 1); #endif #if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0) - QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); + QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); #endif - QCoreApplication::setOrganizationName("Synergy"); - QCoreApplication::setOrganizationDomain("http://symless.com/"); - QCoreApplication::setApplicationName("Synergy"); + QCoreApplication::setOrganizationName("Synergy"); + QCoreApplication::setOrganizationDomain("http://symless.com/"); + QCoreApplication::setApplicationName("Synergy"); - QSynergyApplication app(argc, argv); + QSynergyApplication app(argc, argv); #if defined(Q_OS_MAC) - if (app.applicationDirPath().startsWith("/Volumes/")) { - QMessageBox::information( - NULL, "Synergy", - "Please drag Synergy to the Applications folder, and open it from there."); - return 1; - } + if (app.applicationDirPath().startsWith("/Volumes/")) { + QMessageBox::information(NULL, "Synergy", + "Please drag Synergy to the Applications folder, " + "and open it from there."); + return 1; + } - if (!checkMacAssistiveDevices()) - { - return 1; - } + if (!checkMacAssistiveDevices()) { + return 1; + } #endif #ifndef Q_OS_WIN - QApplication::setQuitOnLastWindowClosed(false); + QApplication::setQuitOnLastWindowClosed(false); #endif - AppConfig appConfig; - qRegisterMetaType("Edition"); + AppConfig appConfig; + qRegisterMetaType("Edition"); #ifndef SYNERGY_ENTERPRISE - LicenseManager licenseManager (&appConfig); + LicenseManager licenseManager(&appConfig); #endif - app.switchTranslator(appConfig.language()); + app.switchTranslator(appConfig.language()); #ifdef SYNERGY_ENTERPRISE - MainWindow mainWindow(appConfig); + MainWindow mainWindow(appConfig); #else - MainWindow mainWindow(appConfig, licenseManager); + MainWindow mainWindow(appConfig, licenseManager); #endif - QObject::connect(dynamic_cast(&app), SIGNAL(aboutToQuit()), - &mainWindow, SLOT(saveSettings())); + QObject::connect(dynamic_cast(&app), SIGNAL(aboutToQuit()), + &mainWindow, SLOT(saveSettings())); - std::unique_ptr setupBlocker; - if (qgetenv("XDG_SESSION_TYPE") == "wayland") - { - setupBlocker.reset(new SetupWizardBlocker(mainWindow, SetupWizardBlocker::qBlockerType::waylandDetected)); - setupBlocker->show(); - return QApplication::exec(); - } + std::unique_ptr setupBlocker; + if (qgetenv("XDG_SESSION_TYPE") == "wayland") { + setupBlocker.reset(new SetupWizardBlocker( + mainWindow, SetupWizardBlocker::qBlockerType::waylandDetected)); + setupBlocker->show(); + return QApplication::exec(); + } - std::unique_ptr setupWizard; - if (appConfig.wizardShouldRun()) - { - setupWizard.reset(new SetupWizard(mainWindow)); - setupWizard->show(); - } - else - { - mainWindow.open(); - } + std::unique_ptr setupWizard; + if (appConfig.wizardShouldRun()) { + setupWizard.reset(new SetupWizard(mainWindow)); + setupWizard->show(); + } else { + mainWindow.open(); + } - return app.exec(); + return app.exec(); } - #if defined(Q_OS_MAC) -bool checkMacAssistiveDevices() -{ +bool checkMacAssistiveDevices() { #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090 // mavericks - // new in mavericks, applications are trusted individually - // with use of the accessibility api. this call will show a - // prompt which can show the security/privacy/accessibility - // tab, with a list of allowed applications. synergy should - // show up there automatically, but will be unchecked. + // new in mavericks, applications are trusted individually + // with use of the accessibility api. this call will show a + // prompt which can show the security/privacy/accessibility + // tab, with a list of allowed applications. synergy should + // show up there automatically, but will be unchecked. - if (AXIsProcessTrusted()) { - return true; - } + if (AXIsProcessTrusted()) { + return true; + } - const void* keys[] = { kAXTrustedCheckOptionPrompt }; - const void* trueValue[] = { kCFBooleanTrue }; - CFDictionaryRef options = CFDictionaryCreate(NULL, keys, trueValue, 1, NULL, NULL); + const void *keys[] = {kAXTrustedCheckOptionPrompt}; + const void *trueValue[] = {kCFBooleanTrue}; + CFDictionaryRef options = + CFDictionaryCreate(NULL, keys, trueValue, 1, NULL, NULL); - bool result = AXIsProcessTrustedWithOptions(options); - CFRelease(options); - return result; + bool result = AXIsProcessTrustedWithOptions(options); + CFRelease(options); + return result; #else - // now deprecated in mavericks. - bool result = AXAPIEnabled(); - if (!result) { - QMessageBox::information( - NULL, "Synergy", - "Please enable access to assistive devices " - "System Preferences -> Security & Privacy -> " - "Privacy -> Accessibility, then re-open Synergy."); - } - return result; + // now deprecated in mavericks. + bool result = AXAPIEnabled(); + if (!result) { + QMessageBox::information(NULL, "Synergy", + "Please enable access to assistive devices " + "System Preferences -> Security & Privacy -> " + "Privacy -> Accessibility, then re-open Synergy."); + } + return result; #endif } diff --git a/src/gui/src/validators/AliasValidator.cpp b/src/gui/src/validators/AliasValidator.cpp index fdf122f3f..9630fab7e 100644 --- a/src/gui/src/validators/AliasValidator.cpp +++ b/src/gui/src/validators/AliasValidator.cpp @@ -15,19 +15,19 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -#include "validators/SpacesValidator.h" #include "validators/RegExpValidator.h" +#include "validators/SpacesValidator.h" #include "AliasValidator.h" -namespace validators -{ +namespace validators { -AliasValidator::AliasValidator(QLineEdit* parent, QLabel* errors) : - LineEditValidator(parent, errors) -{ - addValidator(std::make_unique("Remove spaces")); - addValidator(std::make_unique("Remove unsupported characters", QRegExp("[a-z0-9\\._-]{,255}", Qt::CaseInsensitive))); +AliasValidator::AliasValidator(QLineEdit *parent, QLabel *errors) + : LineEditValidator(parent, errors) { + addValidator(std::make_unique("Remove spaces")); + addValidator(std::make_unique( + "Remove unsupported characters", + QRegExp("[a-z0-9\\._-]{,255}", Qt::CaseInsensitive))); } -} +} // namespace validators diff --git a/src/gui/src/validators/AliasValidator.h b/src/gui/src/validators/AliasValidator.h index f3cc68c03..1ed40758b 100644 --- a/src/gui/src/validators/AliasValidator.h +++ b/src/gui/src/validators/AliasValidator.h @@ -20,15 +20,14 @@ #include "LineEditValidator.h" -namespace validators -{ +namespace validators { -class AliasValidator : public LineEditValidator -{ +class AliasValidator : public LineEditValidator { public: - explicit AliasValidator(QLineEdit* parent = nullptr, QLabel* errors = nullptr); + explicit AliasValidator(QLineEdit *parent = nullptr, + QLabel *errors = nullptr); }; -} +} // namespace validators #endif // ALIASVALIDATOR_H diff --git a/src/gui/src/validators/EmptyStringValidator.cpp b/src/gui/src/validators/EmptyStringValidator.cpp index a695aa197..f1392cbef 100644 --- a/src/gui/src/validators/EmptyStringValidator.cpp +++ b/src/gui/src/validators/EmptyStringValidator.cpp @@ -17,18 +17,13 @@ */ #include "EmptyStringValidator.h" -namespace validators -{ +namespace validators { -EmptyStringValidator::EmptyStringValidator(const QString& message) : - IStringValidator(message) -{ +EmptyStringValidator::EmptyStringValidator(const QString &message) + : IStringValidator(message) {} +bool EmptyStringValidator::validate(const QString &input) const { + return !input.isEmpty(); } -bool EmptyStringValidator::validate(const QString& input) const -{ - return !input.isEmpty(); -} - -} +} // namespace validators diff --git a/src/gui/src/validators/EmptyStringValidator.h b/src/gui/src/validators/EmptyStringValidator.h index e3b0077cd..8677cc4b7 100644 --- a/src/gui/src/validators/EmptyStringValidator.h +++ b/src/gui/src/validators/EmptyStringValidator.h @@ -20,16 +20,14 @@ #include "IStringValidator.h" -namespace validators -{ +namespace validators { -class EmptyStringValidator : public IStringValidator -{ +class EmptyStringValidator : public IStringValidator { public: - explicit EmptyStringValidator(const QString& message); - bool validate(const QString& input) const override; + explicit EmptyStringValidator(const QString &message); + bool validate(const QString &input) const override; }; -} +} // namespace validators #endif // EMPTYSTRINGVALIDATOR_H diff --git a/src/gui/src/validators/IStringValidator.cpp b/src/gui/src/validators/IStringValidator.cpp index 7fb26511d..7a9bbf267 100644 --- a/src/gui/src/validators/IStringValidator.cpp +++ b/src/gui/src/validators/IStringValidator.cpp @@ -17,18 +17,11 @@ */ #include "EmptyStringValidator.h" -namespace validators -{ +namespace validators { -IStringValidator::IStringValidator(const QString& message) : - m_Message(message) -{ +IStringValidator::IStringValidator(const QString &message) + : m_Message(message) {} -} +const QString &IStringValidator::getMessage() const { return m_Message; } -const QString& IStringValidator::getMessage() const -{ - return m_Message; -} - -} +} // namespace validators diff --git a/src/gui/src/validators/IStringValidator.h b/src/gui/src/validators/IStringValidator.h index dfd9b4e95..bb70600ed 100644 --- a/src/gui/src/validators/IStringValidator.h +++ b/src/gui/src/validators/IStringValidator.h @@ -20,23 +20,20 @@ #include -namespace validators -{ +namespace validators { -class IStringValidator -{ - QString m_Message; +class IStringValidator { + QString m_Message; public: - IStringValidator() = default; - explicit IStringValidator(const QString& message); - const QString& getMessage() const; + IStringValidator() = default; + explicit IStringValidator(const QString &message); + const QString &getMessage() const; - virtual bool validate(const QString& input) const = 0; - virtual ~IStringValidator() = default; + virtual bool validate(const QString &input) const = 0; + virtual ~IStringValidator() = default; }; -} - +} // namespace validators #endif // IVALIDATOR_H diff --git a/src/gui/src/validators/LineEditValidator.cpp b/src/gui/src/validators/LineEditValidator.cpp index ef8140771..8cc2692ea 100644 --- a/src/gui/src/validators/LineEditValidator.cpp +++ b/src/gui/src/validators/LineEditValidator.cpp @@ -17,59 +17,47 @@ */ #include "LineEditValidator.h" -namespace validators -{ +namespace validators { -LineEditValidator::LineEditValidator(QLineEdit* parent, QLabel* errors) : - m_pErrors(errors), - m_pControl(parent) -{ - if (m_pErrors) { +LineEditValidator::LineEditValidator(QLineEdit *parent, QLabel *errors) + : m_pErrors(errors), m_pControl(parent) { + if (m_pErrors) { + m_pErrors->hide(); + } +} + +void LineEditValidator::addValidator( + std::unique_ptr validator) { + m_Validators.push_back(std::move(validator)); +} + +QValidator::State LineEditValidator::validate(QString &input, int &pos) const { + if (m_pControl) { + showError(""); + m_pControl->setStyleSheet(""); + + for (const auto &validator : m_Validators) { + if (!validator->validate(input)) { + m_pControl->setStyleSheet("border: 1px solid #EC4C47"); + showError(validator->getMessage()); + break; + } + } + } + + return Acceptable; +} + +void LineEditValidator::showError(const QString &message) const { + if (m_pErrors) { + m_pErrors->setText(message); + + if (m_pErrors->text().isEmpty()) { m_pErrors->hide(); - } + } else { + m_pErrors->show(); + } + } } -void LineEditValidator::addValidator(std::unique_ptr validator) -{ - m_Validators.push_back(std::move(validator)); -} - -QValidator::State LineEditValidator::validate(QString& input, int& pos) const -{ - if (m_pControl) - { - showError(""); - m_pControl->setStyleSheet(""); - - for (const auto& validator : m_Validators) - { - if (!validator->validate(input)) - { - m_pControl->setStyleSheet("border: 1px solid #EC4C47"); - showError(validator->getMessage()); - break; - } - } - } - - return Acceptable; -} - -void LineEditValidator::showError(const QString& message) const -{ - if (m_pErrors) - { - m_pErrors->setText(message); - - if (m_pErrors->text().isEmpty()) - { - m_pErrors->hide(); - } - else - { - m_pErrors->show(); - } - } -} - -} +} // namespace validators diff --git a/src/gui/src/validators/LineEditValidator.h b/src/gui/src/validators/LineEditValidator.h index 2d9a5b15c..d72338b8e 100644 --- a/src/gui/src/validators/LineEditValidator.h +++ b/src/gui/src/validators/LineEditValidator.h @@ -21,31 +21,29 @@ #include #include -#include #include #include +#include #include "IStringValidator.h" -namespace validators -{ +namespace validators { -class LineEditValidator : public QValidator -{ +class LineEditValidator : public QValidator { public: - explicit LineEditValidator(QLineEdit* parent = nullptr, QLabel* errors = nullptr); - QValidator::State validate(QString& input, int& pos) const override; - void addValidator(std::unique_ptr validator); + explicit LineEditValidator(QLineEdit *parent = nullptr, + QLabel *errors = nullptr); + QValidator::State validate(QString &input, int &pos) const override; + void addValidator(std::unique_ptr validator); private: - QLabel* m_pErrors = nullptr; - QLineEdit* m_pControl = nullptr; - std::vector> m_Validators; - - void showError(const QString& message) const; + QLabel *m_pErrors = nullptr; + QLineEdit *m_pControl = nullptr; + std::vector> m_Validators; + void showError(const QString &message) const; }; -} +} // namespace validators #endif // LINEEDITVALIDATOR_H diff --git a/src/gui/src/validators/RegExpValidator.cpp b/src/gui/src/validators/RegExpValidator.cpp index 53bd66db7..396c36501 100644 --- a/src/gui/src/validators/RegExpValidator.cpp +++ b/src/gui/src/validators/RegExpValidator.cpp @@ -17,19 +17,14 @@ */ #include "RegExpValidator.h" -namespace validators -{ - -RegExpValidator::RegExpValidator(const QString& message, const QRegExp& validator) : - IStringValidator(message), - m_Validator(validator) -{ -} - -bool RegExpValidator::validate(const QString& input) const -{ - return (m_Validator.exactMatch(input)); -} +namespace validators { +RegExpValidator::RegExpValidator(const QString &message, + const QRegExp &validator) + : IStringValidator(message), m_Validator(validator) {} + +bool RegExpValidator::validate(const QString &input) const { + return (m_Validator.exactMatch(input)); } +} // namespace validators diff --git a/src/gui/src/validators/RegExpValidator.h b/src/gui/src/validators/RegExpValidator.h index bcaeabead..5da28b4cc 100644 --- a/src/gui/src/validators/RegExpValidator.h +++ b/src/gui/src/validators/RegExpValidator.h @@ -18,20 +18,19 @@ #ifndef REGEXPVALIDATOR_H #define REGEXPVALIDATOR_H -#include #include "IStringValidator.h" +#include -namespace validators -{ +namespace validators { + +class RegExpValidator : public IStringValidator { + QRegExp m_Validator; -class RegExpValidator : public IStringValidator -{ - QRegExp m_Validator; public: - RegExpValidator(const QString& message, const QRegExp& validator); - bool validate(const QString& input) const override; + RegExpValidator(const QString &message, const QRegExp &validator); + bool validate(const QString &input) const override; }; -} +} // namespace validators #endif // REGEXPVALIDATOR_H diff --git a/src/gui/src/validators/ScreenDuplicationsValidator.cpp b/src/gui/src/validators/ScreenDuplicationsValidator.cpp index 0af01f352..4bb9213e0 100644 --- a/src/gui/src/validators/ScreenDuplicationsValidator.cpp +++ b/src/gui/src/validators/ScreenDuplicationsValidator.cpp @@ -17,35 +17,28 @@ */ #include "ScreenDuplicationsValidator.h" -namespace validators -{ +namespace validators { -ScreenDuplicationsValidator::ScreenDuplicationsValidator(const QString& message, const QString& defaultName,const ScreenList* pScreens) : - IStringValidator(message), - m_defaultName(defaultName), - m_pScreenList(pScreens) -{ +ScreenDuplicationsValidator::ScreenDuplicationsValidator( + const QString &message, const QString &defaultName, + const ScreenList *pScreens) + : IStringValidator(message), m_defaultName(defaultName), + m_pScreenList(pScreens) {} -} +bool ScreenDuplicationsValidator::validate(const QString &input) const { + bool result = true; -bool ScreenDuplicationsValidator::validate(const QString& input) const -{ - bool result = true; - - if (m_pScreenList) - { - for (const auto& screen : (*m_pScreenList)) - { - if (!screen.isNull() && !screen.isServer() && - input != m_defaultName && input == screen.name()) - { - result = false; - break; - } + if (m_pScreenList) { + for (const auto &screen : (*m_pScreenList)) { + if (!screen.isNull() && !screen.isServer() && input != m_defaultName && + input == screen.name()) { + result = false; + break; } - } + } + } - return result; + return result; } -} +} // namespace validators diff --git a/src/gui/src/validators/ScreenDuplicationsValidator.h b/src/gui/src/validators/ScreenDuplicationsValidator.h index a97d832fc..6fb37d81b 100644 --- a/src/gui/src/validators/ScreenDuplicationsValidator.h +++ b/src/gui/src/validators/ScreenDuplicationsValidator.h @@ -18,22 +18,22 @@ #ifndef SCREENDUPLICATIONSVALIDATOR_H #define SCREENDUPLICATIONSVALIDATOR_H -#include "ScreenList.h" #include "IStringValidator.h" +#include "ScreenList.h" -namespace validators -{ +namespace validators { -class ScreenDuplicationsValidator : public IStringValidator -{ - const QString m_defaultName; - const ScreenList* m_pScreenList = nullptr; +class ScreenDuplicationsValidator : public IStringValidator { + const QString m_defaultName; + const ScreenList *m_pScreenList = nullptr; public: - ScreenDuplicationsValidator(const QString& message, const QString& defaultName,const ScreenList* pScreens); - bool validate(const QString& input) const override; + ScreenDuplicationsValidator(const QString &message, + const QString &defaultName, + const ScreenList *pScreens); + bool validate(const QString &input) const override; }; -} +} // namespace validators #endif // SCREENDUPLICATIONSVALIDATOR_H diff --git a/src/gui/src/validators/ScreenNameValidator.cpp b/src/gui/src/validators/ScreenNameValidator.cpp index 3e91307b0..1fad5964b 100644 --- a/src/gui/src/validators/ScreenNameValidator.cpp +++ b/src/gui/src/validators/ScreenNameValidator.cpp @@ -17,22 +17,26 @@ */ #include -#include "validators/SpacesValidator.h" -#include "validators/RegExpValidator.h" -#include "validators/EmptyStringValidator.h" -#include "validators/ScreenDuplicationsValidator.h" #include "ScreenNameValidator.h" +#include "validators/EmptyStringValidator.h" +#include "validators/RegExpValidator.h" +#include "validators/ScreenDuplicationsValidator.h" +#include "validators/SpacesValidator.h" -namespace validators -{ +namespace validators { -ScreenNameValidator::ScreenNameValidator(QLineEdit* parent, QLabel* errors, const ScreenList* pScreens) : - LineEditValidator(parent, errors) -{ - addValidator(std::make_unique("Computer name is required")); - addValidator(std::make_unique("Remove spaces")); - addValidator(std::make_unique("Remove unsupported characters", QRegExp("[a-z0-9\\._-]{,255}", Qt::CaseInsensitive))); - addValidator(std::make_unique("A computer with this name already exists", parent ? parent->text() : "", pScreens)); +ScreenNameValidator::ScreenNameValidator(QLineEdit *parent, QLabel *errors, + const ScreenList *pScreens) + : LineEditValidator(parent, errors) { + addValidator( + std::make_unique("Computer name is required")); + addValidator(std::make_unique("Remove spaces")); + addValidator(std::make_unique( + "Remove unsupported characters", + QRegExp("[a-z0-9\\._-]{,255}", Qt::CaseInsensitive))); + addValidator(std::make_unique( + "A computer with this name already exists", parent ? parent->text() : "", + pScreens)); } -} +} // namespace validators diff --git a/src/gui/src/validators/ScreenNameValidator.h b/src/gui/src/validators/ScreenNameValidator.h index 1a602a69e..87032c383 100644 --- a/src/gui/src/validators/ScreenNameValidator.h +++ b/src/gui/src/validators/ScreenNameValidator.h @@ -18,18 +18,18 @@ #ifndef SCREENNAMEVALIDATOR_H #define SCREENNAMEVALIDATOR_H -#include "ScreenList.h" #include "LineEditValidator.h" +#include "ScreenList.h" -namespace validators -{ +namespace validators { -class ScreenNameValidator : public LineEditValidator -{ +class ScreenNameValidator : public LineEditValidator { public: - explicit ScreenNameValidator(QLineEdit* parent = nullptr, QLabel* errors = nullptr, const ScreenList* pScreens = nullptr); + explicit ScreenNameValidator(QLineEdit *parent = nullptr, + QLabel *errors = nullptr, + const ScreenList *pScreens = nullptr); }; -} +} // namespace validators #endif // SCREENNAMEVALIDATOR_H diff --git a/src/gui/src/validators/SpacesValidator.cpp b/src/gui/src/validators/SpacesValidator.cpp index a58663510..6e3cbde22 100644 --- a/src/gui/src/validators/SpacesValidator.cpp +++ b/src/gui/src/validators/SpacesValidator.cpp @@ -17,18 +17,13 @@ */ #include "SpacesValidator.h" -namespace validators -{ +namespace validators { -SpacesValidator::SpacesValidator(const QString& message) : - IStringValidator(message) -{ +SpacesValidator::SpacesValidator(const QString &message) + : IStringValidator(message) {} +bool SpacesValidator::validate(const QString &input) const { + return !input.contains(' '); } -bool SpacesValidator::validate(const QString& input) const -{ - return !input.contains(' '); -} - -} +} // namespace validators diff --git a/src/gui/src/validators/SpacesValidator.h b/src/gui/src/validators/SpacesValidator.h index df51caee4..40f50f9da 100644 --- a/src/gui/src/validators/SpacesValidator.h +++ b/src/gui/src/validators/SpacesValidator.h @@ -20,16 +20,14 @@ #include "IStringValidator.h" -namespace validators -{ +namespace validators { -class SpacesValidator : public IStringValidator -{ +class SpacesValidator : public IStringValidator { public: - explicit SpacesValidator(const QString& message); - bool validate(const QString& input) const override; + explicit SpacesValidator(const QString &message); + bool validate(const QString &input) const override; }; -} +} // namespace validators #endif // SPACESVALIDATOR_H diff --git a/src/gui/src/widgets/ClientStateLabel.cpp b/src/gui/src/widgets/ClientStateLabel.cpp index 3669e6aa4..c2f21c442 100644 --- a/src/gui/src/widgets/ClientStateLabel.cpp +++ b/src/gui/src/widgets/ClientStateLabel.cpp @@ -17,25 +17,17 @@ */ #include "ClientStateLabel.h" -namespace synergy_widgets -{ +namespace synergy_widgets { -ClientStateLabel::ClientStateLabel(QWidget* parent) : - QLabel(parent) -{ +ClientStateLabel::ClientStateLabel(QWidget *parent) : QLabel(parent) { hide(); } + +void ClientStateLabel::updateClientState(const QString &line) { + if (line.contains("connected to server")) { + show(); + } else if (line.contains("disconnected from server") || + line.contains("process exited")) { hide(); + } } -void ClientStateLabel::updateClientState(const QString& line) -{ - if (line.contains("connected to server")) - { - show(); - } - else if (line.contains("disconnected from server") || line.contains("process exited")) - { - hide(); - } -} - -} +} // namespace synergy_widgets diff --git a/src/gui/src/widgets/ClientStateLabel.h b/src/gui/src/widgets/ClientStateLabel.h index 373cb426d..8612b3051 100644 --- a/src/gui/src/widgets/ClientStateLabel.h +++ b/src/gui/src/widgets/ClientStateLabel.h @@ -21,14 +21,12 @@ #include -namespace synergy_widgets -{ +namespace synergy_widgets { -class ClientStateLabel : public QLabel -{ +class ClientStateLabel : public QLabel { public: - explicit ClientStateLabel(QWidget* parent = nullptr); - void updateClientState(const QString& line); + explicit ClientStateLabel(QWidget *parent = nullptr); + void updateClientState(const QString &line); }; } // namespace synergy_widgets diff --git a/src/gui/src/widgets/ServerStateLabel.cpp b/src/gui/src/widgets/ServerStateLabel.cpp index 80f14770d..3a52a1699 100644 --- a/src/gui/src/widgets/ServerStateLabel.cpp +++ b/src/gui/src/widgets/ServerStateLabel.cpp @@ -20,44 +20,30 @@ #include "ServerMessage.h" -namespace synergy_widgets -{ +namespace synergy_widgets { -ServerStateLabel::ServerStateLabel(QWidget* parent) : - QLabel(parent) -{ +ServerStateLabel::ServerStateLabel(QWidget *parent) : QLabel(parent) {} + +void ServerStateLabel::updateServerState(const QString &line) { + ServerMessage message(line); + + if (message.isExitMessage()) { + m_clients.clear(); + } else if (message.isConnectedMessage()) { + m_clients.append(message.getClientName()); + } else if (message.isDisconnectedMessage()) { + m_clients.removeAll(message.getClientName()); + } + + updateState(); } -void ServerStateLabel::updateServerState(const QString& line) -{ - ServerMessage message(line); - - if (message.isExitMessage()) - { - m_clients.clear(); - } - else if (message.isConnectedMessage()) - { - m_clients.append(message.getClientName()); - } - else if (message.isDisconnectedMessage()) - { - m_clients.removeAll(message.getClientName()); - } - - updateState(); +void ServerStateLabel::updateState() { + if (m_clients.isEmpty()) { + show(); + } else { + hide(); + } } -void ServerStateLabel::updateState() -{ - if (m_clients.isEmpty()) - { - show(); - } - else - { - hide(); - } -} - -} //namespace synergy_widgets +} // namespace synergy_widgets diff --git a/src/gui/src/widgets/ServerStateLabel.h b/src/gui/src/widgets/ServerStateLabel.h index 288b64b4f..d740c311d 100644 --- a/src/gui/src/widgets/ServerStateLabel.h +++ b/src/gui/src/widgets/ServerStateLabel.h @@ -22,21 +22,19 @@ #include #include -namespace synergy_widgets -{ +namespace synergy_widgets { -class ServerStateLabel : public QLabel -{ +class ServerStateLabel : public QLabel { public: - explicit ServerStateLabel(QWidget* parent = nullptr); - void updateServerState(const QString& line); + explicit ServerStateLabel(QWidget *parent = nullptr); + void updateServerState(const QString &line); private: - QStringList m_clients; + QStringList m_clients; - void updateState(); + void updateState(); }; -} //namespace synergy_widgets +} // namespace synergy_widgets #endif // SERVERSTATELABEL_H diff --git a/src/lib/arch/Arch.cpp b/src/lib/arch/Arch.cpp index 5eb0025db..13a07751d 100644 --- a/src/lib/arch/Arch.cpp +++ b/src/lib/arch/Arch.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -18,43 +18,38 @@ #include "arch/Arch.h" +#if SYSAPI_WIN32 +#include "arch/win32/ArchMiscWindows.h" +#endif + // // Arch // -Arch* Arch::s_instance = NULL; +Arch *Arch::s_instance = NULL; -Arch::Arch() -{ - assert(s_instance == NULL); - s_instance = this; +Arch::Arch() { + assert(s_instance == NULL); + s_instance = this; } -Arch::Arch(Arch* arch) -{ - s_instance = arch; -} +Arch::Arch(Arch *arch) { s_instance = arch; } -Arch::~Arch() -{ +Arch::~Arch() { #if SYSAPI_WIN32 - ArchMiscWindows::cleanup(); + ArchMiscWindows::cleanup(); #endif } -void -Arch::init() -{ - ARCH_NETWORK::init(); +void Arch::init() { + ARCH_NETWORK::init(); #if SYSAPI_WIN32 - ARCH_TASKBAR::init(); - ArchMiscWindows::init(); + ARCH_TASKBAR::init(); + ArchMiscWindows::init(); #endif } -Arch* -Arch::getInstance() -{ - assert(s_instance != NULL); - return s_instance; +Arch *Arch::getInstance() { + assert(s_instance != NULL); + return s_instance; } diff --git a/src/lib/arch/Arch.h b/src/lib/arch/Arch.h index 6d0560de5..7da51eec1 100644 --- a/src/lib/arch/Arch.h +++ b/src/lib/arch/Arch.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -38,39 +38,43 @@ #include "common/common.h" #if SYSAPI_WIN32 -# include "arch/win32/ArchConsoleWindows.h" -# include "arch/win32/ArchDaemonWindows.h" -# include "arch/win32/ArchFileWindows.h" -# include "arch/win32/ArchLogWindows.h" -# include "arch/win32/ArchMiscWindows.h" -# include "arch/win32/ArchMultithreadWindows.h" -# include "arch/win32/ArchNetworkWinsock.h" -# include "arch/win32/ArchSleepWindows.h" -# include "arch/win32/ArchStringWindows.h" -# include "arch/win32/ArchSystemWindows.h" -# include "arch/win32/ArchTaskBarWindows.h" -# include "arch/win32/ArchTimeWindows.h" + +#include "arch/win32/ArchConsoleWindows.h" +#include "arch/win32/ArchDaemonWindows.h" +#include "arch/win32/ArchFileWindows.h" +#include "arch/win32/ArchLogWindows.h" +#include "arch/win32/ArchMultithreadWindows.h" +#include "arch/win32/ArchNetworkWinsock.h" +#include "arch/win32/ArchSleepWindows.h" +#include "arch/win32/ArchStringWindows.h" +#include "arch/win32/ArchSystemWindows.h" +#include "arch/win32/ArchTaskBarWindows.h" +#include "arch/win32/ArchTimeWindows.h" + #elif SYSAPI_UNIX -# include "arch/unix/ArchConsoleUnix.h" -# include "arch/unix/ArchDaemonUnix.h" -# include "arch/unix/ArchFileUnix.h" -# include "arch/unix/ArchLogUnix.h" -# if HAVE_PTHREAD -# include "arch/unix/ArchMultithreadPosix.h" -# endif -# include "arch/unix/ArchNetworkBSD.h" -# include "arch/unix/ArchSleepUnix.h" -# include "arch/unix/ArchStringUnix.h" -# include "arch/unix/ArchSystemUnix.h" -# include "arch/unix/ArchTaskBarXWindows.h" -# include "arch/unix/ArchTimeUnix.h" + +#include "arch/unix/ArchConsoleUnix.h" +#include "arch/unix/ArchDaemonUnix.h" +#include "arch/unix/ArchFileUnix.h" +#include "arch/unix/ArchLogUnix.h" +#include "arch/unix/ArchNetworkBSD.h" +#include "arch/unix/ArchSleepUnix.h" +#include "arch/unix/ArchStringUnix.h" +#include "arch/unix/ArchSystemUnix.h" +#include "arch/unix/ArchTaskBarXWindows.h" +#include "arch/unix/ArchTimeUnix.h" + +#if HAVE_PTHREAD +#include "arch/unix/ArchMultithreadPosix.h" +#endif + #endif /*! \def ARCH This macro evaluates to the singleton Arch object. */ -#define ARCH (Arch::getInstance()) +#define ARCH (Arch::getInstance()) //! Delegating implementation of architecture dependent interfaces /*! @@ -83,62 +87,56 @@ exactly one of these objects before attempting to call any method, typically at the beginning of \c main(). */ class Arch : public ARCH_CONSOLE, - public ARCH_DAEMON, - public ARCH_FILE, - public ARCH_LOG, - public ARCH_MULTITHREAD, - public ARCH_NETWORK, - public ARCH_SLEEP, - public ARCH_STRING, - public ARCH_SYSTEM, - public ARCH_TASKBAR, - public ARCH_TIME { + public ARCH_DAEMON, + public ARCH_FILE, + public ARCH_LOG, + public ARCH_MULTITHREAD, + public ARCH_NETWORK, + public ARCH_SLEEP, + public ARCH_STRING, + public ARCH_SYSTEM, + public ARCH_TASKBAR, + public ARCH_TIME { public: - Arch(); - Arch(Arch* arch); - virtual ~Arch(); + Arch(); + Arch(Arch *arch); + virtual ~Arch(); - //! Call init on other arch classes. - /*! - Some arch classes depend on others to exist first. When init is called - these classes will have ARCH available for use. - */ - virtual void init(); + //! Call init on other arch classes. + /*! + Some arch classes depend on others to exist first. When init is called + these classes will have ARCH available for use. + */ + virtual void init(); - // - // accessors - // + // + // accessors + // - //! Return the singleton instance - /*! - The client must have instantiated exactly once Arch object before - calling this function. - */ - static Arch* getInstance(); + //! Return the singleton instance + /*! + The client must have instantiated exactly once Arch object before + calling this function. + */ + static Arch *getInstance(); - static void setInstance(Arch* s) { s_instance = s; } + static void setInstance(Arch *s) { s_instance = s; } private: - static Arch* s_instance; + static Arch *s_instance; }; //! Convenience object to lock/unlock an arch mutex class ArchMutexLock { public: - ArchMutexLock(ArchMutex mutex) : m_mutex(mutex) - { - ARCH->lockMutex(m_mutex); - } - ArchMutexLock(ArchMutexLock const &) =delete; - ArchMutexLock(ArchMutexLock &&) =delete; - ~ArchMutexLock() - { - ARCH->unlockMutex(m_mutex); - } + ArchMutexLock(ArchMutex mutex) : m_mutex(mutex) { ARCH->lockMutex(m_mutex); } + ArchMutexLock(ArchMutexLock const &) = delete; + ArchMutexLock(ArchMutexLock &&) = delete; + ~ArchMutexLock() { ARCH->unlockMutex(m_mutex); } - ArchMutexLock& operator=(ArchMutexLock const &) =delete; - ArchMutexLock& operator=(ArchMutexLock &&) =delete; + ArchMutexLock &operator=(ArchMutexLock const &) = delete; + ArchMutexLock &operator=(ArchMutexLock &&) = delete; private: - ArchMutex m_mutex; + ArchMutex m_mutex; }; diff --git a/src/lib/arch/ArchConsoleStd.cpp b/src/lib/arch/ArchConsoleStd.cpp index 44814ba8e..7c6b7aaeb 100644 --- a/src/lib/arch/ArchConsoleStd.cpp +++ b/src/lib/arch/ArchConsoleStd.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -21,13 +21,11 @@ #include -void -ArchConsoleStd::writeConsole(ELevel level, const char* str) -{ - if ((level >= kFATAL) && (level <= kWARNING)) - std::cerr << str << std::endl; - else - std::cout << str << std::endl; +void ArchConsoleStd::writeConsole(ELevel level, const char *str) { + if ((level >= kFATAL) && (level <= kWARNING)) + std::cerr << str << std::endl; + else + std::cout << str << std::endl; - std::cout.flush(); + std::cout.flush(); } \ No newline at end of file diff --git a/src/lib/arch/ArchConsoleStd.h b/src/lib/arch/ArchConsoleStd.h index 0bc7d2efb..92bb092ac 100644 --- a/src/lib/arch/ArchConsoleStd.h +++ b/src/lib/arch/ArchConsoleStd.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -23,12 +23,12 @@ //! Cross platform implementation of IArchConsole class ArchConsoleStd : public IArchConsole { public: - ArchConsoleStd() { } - virtual ~ArchConsoleStd() { } + ArchConsoleStd() {} + virtual ~ArchConsoleStd() {} - // IArchConsole overrides - virtual void openConsole(const char* title) { } - virtual void closeConsole() { } - virtual void showConsole(bool) { } - virtual void writeConsole(ELevel level, const char*); + // IArchConsole overrides + virtual void openConsole(const char *title) {} + virtual void closeConsole() {} + virtual void showConsole(bool) {} + virtual void writeConsole(ELevel level, const char *); }; diff --git a/src/lib/arch/ArchDaemonNone.cpp b/src/lib/arch/ArchDaemonNone.cpp index 71210632f..3c49ff5f9 100644 --- a/src/lib/arch/ArchDaemonNone.cpp +++ b/src/lib/arch/ArchDaemonNone.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -22,64 +22,35 @@ // ArchDaemonNone // -ArchDaemonNone::ArchDaemonNone() -{ - // do nothing +ArchDaemonNone::ArchDaemonNone() { + // do nothing } -ArchDaemonNone::~ArchDaemonNone() -{ - // do nothing +ArchDaemonNone::~ArchDaemonNone() { + // do nothing } -void -ArchDaemonNone::installDaemon(const char*, - const char*, - const char*, - const char*, - const char*) -{ - // do nothing +void ArchDaemonNone::installDaemon(const char *, const char *, const char *, + const char *, const char *) { + // do nothing } -void -ArchDaemonNone::uninstallDaemon(const char*) -{ - // do nothing +void ArchDaemonNone::uninstallDaemon(const char *) { + // do nothing } -int -ArchDaemonNone::daemonize(const char* name, DaemonFunc func) -{ - // simply forward the call to func. obviously, this doesn't - // do any daemonizing. - return func(1, &name); +int ArchDaemonNone::daemonize(const char *name, DaemonFunc func) { + // simply forward the call to func. obviously, this doesn't + // do any daemonizing. + return func(1, &name); } -bool -ArchDaemonNone::canInstallDaemon(const char*) -{ - return false; -} +bool ArchDaemonNone::canInstallDaemon(const char *) { return false; } -bool -ArchDaemonNone::isDaemonInstalled(const char*) -{ - return false; -} +bool ArchDaemonNone::isDaemonInstalled(const char *) { return false; } -void -ArchDaemonNone::installDaemon() -{ -} +void ArchDaemonNone::installDaemon() {} -void -ArchDaemonNone::uninstallDaemon() -{ -} +void ArchDaemonNone::uninstallDaemon() {} -std::string -ArchDaemonNone::commandLine() const -{ - return ""; -} +std::string ArchDaemonNone::commandLine() const { return ""; } diff --git a/src/lib/arch/ArchDaemonNone.h b/src/lib/arch/ArchDaemonNone.h index decb5aa2f..e2210f419 100644 --- a/src/lib/arch/ArchDaemonNone.h +++ b/src/lib/arch/ArchDaemonNone.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -31,20 +31,18 @@ function and returns its result. */ class ArchDaemonNone : public IArchDaemon { public: - ArchDaemonNone(); - virtual ~ArchDaemonNone(); + ArchDaemonNone(); + virtual ~ArchDaemonNone(); - // IArchDaemon overrides - virtual void installDaemon(const char* name, - const char* description, - const char* pathname, - const char* commandLine, - const char* dependencies); - virtual void uninstallDaemon(const char* name); - virtual int daemonize(const char* name, DaemonFunc func); - virtual bool canInstallDaemon(const char* name); - virtual bool isDaemonInstalled(const char* name); - virtual void installDaemon(); - virtual void uninstallDaemon(); - virtual std::string commandLine() const; + // IArchDaemon overrides + virtual void installDaemon(const char *name, const char *description, + const char *pathname, const char *commandLine, + const char *dependencies); + virtual void uninstallDaemon(const char *name); + virtual int daemonize(const char *name, DaemonFunc func); + virtual bool canInstallDaemon(const char *name); + virtual bool isDaemonInstalled(const char *name); + virtual void installDaemon(); + virtual void uninstallDaemon(); + virtual std::string commandLine() const; }; diff --git a/src/lib/arch/IArchConsole.h b/src/lib/arch/IArchConsole.h index 3c009a2f7..424917e1b 100644 --- a/src/lib/arch/IArchConsole.h +++ b/src/lib/arch/IArchConsole.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -18,8 +18,8 @@ #pragma once -#include "common/IInterface.h" #include "base/ELevel.h" +#include "common/IInterface.h" //! Interface for architecture dependent console output /*! @@ -28,39 +28,39 @@ synergy. Each architecture must implement this interface. */ class IArchConsole : public IInterface { public: - //! @name manipulators - //@{ + //! @name manipulators + //@{ - //! Open the console - /*! - Opens the console for writing. The console is opened automatically - on the first write so calling this method is optional. Uses \c title - for the console's title if appropriate for the architecture. Calling - this method on an already open console must have no effect. - */ - virtual void openConsole(const char* title) = 0; + //! Open the console + /*! + Opens the console for writing. The console is opened automatically + on the first write so calling this method is optional. Uses \c title + for the console's title if appropriate for the architecture. Calling + this method on an already open console must have no effect. + */ + virtual void openConsole(const char *title) = 0; - //! Close the console - /*! - Close the console. Calling this method on an already closed console - must have no effect. - */ - virtual void closeConsole() = 0; + //! Close the console + /*! + Close the console. Calling this method on an already closed console + must have no effect. + */ + virtual void closeConsole() = 0; - //! Show the console - /*! - Causes the console to become visible. This generally only makes sense - for a console in a graphical user interface. Other implementations - will do nothing. Iff \p showIfEmpty is \c false then the implementation - may optionally only show the console if it's not empty. - */ - virtual void showConsole(bool showIfEmpty) = 0; + //! Show the console + /*! + Causes the console to become visible. This generally only makes sense + for a console in a graphical user interface. Other implementations + will do nothing. Iff \p showIfEmpty is \c false then the implementation + may optionally only show the console if it's not empty. + */ + virtual void showConsole(bool showIfEmpty) = 0; - //! Write to the console - /*! - Writes the given string to the console, opening it if necessary. - */ - virtual void writeConsole(ELevel, const char*) = 0; + //! Write to the console + /*! + Writes the given string to the console, opening it if necessary. + */ + virtual void writeConsole(ELevel, const char *) = 0; - //@} + //@} }; diff --git a/src/lib/arch/IArchDaemon.h b/src/lib/arch/IArchDaemon.h index 5db49f10c..806eaff0c 100644 --- a/src/lib/arch/IArchDaemon.h +++ b/src/lib/arch/IArchDaemon.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -18,8 +18,8 @@ #pragma once -#include "common/IInterface.h" #include "base/String.h" +#include "common/IInterface.h" //! Interface for architecture dependent daemonizing /*! @@ -29,100 +29,98 @@ implement this interface. */ class IArchDaemon : public IInterface { public: - typedef int (*DaemonFunc)(int argc, const char** argv); + typedef int (*DaemonFunc)(int argc, const char **argv); - //! @name manipulators - //@{ + //! @name manipulators + //@{ - //! Install daemon - /*! - Install a daemon. \c name is the name of the daemon passed to the - system and \c description is a short human readable description of - the daemon. \c pathname is the path to the daemon executable. - \c commandLine should \b not include the name of program as the - first argument. If \c allUsers is true then the daemon will be - installed to start at boot time, otherwise it will be installed to - start when the current user logs in. If \p dependencies is not NULL - then it's a concatenation of NUL terminated other daemon names - followed by a NUL; the daemon will be configured to startup after - the listed daemons. Throws an \c XArchDaemon exception on failure. - */ - virtual void installDaemon(const char* name, - const char* description, - const char* pathname, - const char* commandLine, - const char* dependencies) = 0; + //! Install daemon + /*! + Install a daemon. \c name is the name of the daemon passed to the + system and \c description is a short human readable description of + the daemon. \c pathname is the path to the daemon executable. + \c commandLine should \b not include the name of program as the + first argument. If \c allUsers is true then the daemon will be + installed to start at boot time, otherwise it will be installed to + start when the current user logs in. If \p dependencies is not NULL + then it's a concatenation of NUL terminated other daemon names + followed by a NUL; the daemon will be configured to startup after + the listed daemons. Throws an \c XArchDaemon exception on failure. + */ + virtual void installDaemon(const char *name, const char *description, + const char *pathname, const char *commandLine, + const char *dependencies) = 0; - //! Uninstall daemon - /*! - Uninstall a daemon. Throws an \c XArchDaemon on failure. - */ - virtual void uninstallDaemon(const char* name) = 0; + //! Uninstall daemon + /*! + Uninstall a daemon. Throws an \c XArchDaemon on failure. + */ + virtual void uninstallDaemon(const char *name) = 0; - //! Install daemon - /*! - Installs the default daemon. - */ - virtual void installDaemon() = 0; - - //! Uninstall daemon - /*! - Uninstalls the default daemon. - */ - virtual void uninstallDaemon() = 0; + //! Install daemon + /*! + Installs the default daemon. + */ + virtual void installDaemon() = 0; - //! Daemonize the process - /*! - Daemonize. Throw XArchDaemonFailed on error. \c name is the name - of the daemon. Once daemonized, \c func is invoked and daemonize - returns when and what it does. - - Exactly what happens when daemonizing depends on the platform. -
    -
  • unix: - Detaches from terminal. \c func gets passed one argument, the - name passed to daemonize(). -
  • win32: - Becomes a service. Argument 0 is the name of the service - and the rest are the arguments passed to StartService(). - \c func is only called when the service is actually started. - \c func must call \c ArchMiscWindows::runDaemon() to finally - becoming a service. The \c runFunc function passed to \c runDaemon() - must call \c ArchMiscWindows::daemonRunning(true) when it - enters the main loop (i.e. after initialization) and - \c ArchMiscWindows::daemonRunning(false) when it leaves - the main loop. The \c stopFunc function passed to \c runDaemon() - is called when the daemon must exit the main loop and it must cause - \c runFunc to return. \c func should return what \c runDaemon() - returns. \c func or \c runFunc can call - \c ArchMiscWindows::daemonFailed() to indicate startup failure. -
- */ - virtual int daemonize(const char* name, DaemonFunc func) = 0; + //! Uninstall daemon + /*! + Uninstalls the default daemon. + */ + virtual void uninstallDaemon() = 0; - //! Check if user has permission to install the daemon - /*! - Returns true iff the caller has permission to install or - uninstall the daemon. Note that even if this method returns - true it's possible that installing/uninstalling the service - may still fail. This method ignores whether or not the - service is already installed. - */ - virtual bool canInstallDaemon(const char* name) = 0; + //! Daemonize the process + /*! + Daemonize. Throw XArchDaemonFailed on error. \c name is the name + of the daemon. Once daemonized, \c func is invoked and daemonize + returns when and what it does. - //! Check if the daemon is installed - /*! - Returns true iff the daemon is installed. - */ - virtual bool isDaemonInstalled(const char* name) = 0; + Exactly what happens when daemonizing depends on the platform. +
    +
  • unix: + Detaches from terminal. \c func gets passed one argument, the + name passed to daemonize(). +
  • win32: + Becomes a service. Argument 0 is the name of the service + and the rest are the arguments passed to StartService(). + \c func is only called when the service is actually started. + \c func must call \c ArchMiscWindows::runDaemon() to finally + becoming a service. The \c runFunc function passed to \c runDaemon() + must call \c ArchMiscWindows::daemonRunning(true) when it + enters the main loop (i.e. after initialization) and + \c ArchMiscWindows::daemonRunning(false) when it leaves + the main loop. The \c stopFunc function passed to \c runDaemon() + is called when the daemon must exit the main loop and it must cause + \c runFunc to return. \c func should return what \c runDaemon() + returns. \c func or \c runFunc can call + \c ArchMiscWindows::daemonFailed() to indicate startup failure. +
+ */ + virtual int daemonize(const char *name, DaemonFunc func) = 0; - //@} + //! Check if user has permission to install the daemon + /*! + Returns true iff the caller has permission to install or + uninstall the daemon. Note that even if this method returns + true it's possible that installing/uninstalling the service + may still fail. This method ignores whether or not the + service is already installed. + */ + virtual bool canInstallDaemon(const char *name) = 0; - //! Get the command line - /*! - Gets the command line with which the application was started. - */ - virtual std::string commandLine() const = 0; + //! Check if the daemon is installed + /*! + Returns true iff the daemon is installed. + */ + virtual bool isDaemonInstalled(const char *name) = 0; - //@} + //@} + + //! Get the command line + /*! + Gets the command line with which the application was started. + */ + virtual std::string commandLine() const = 0; + + //@} }; diff --git a/src/lib/arch/IArchFile.h b/src/lib/arch/IArchFile.h index 7a5ea6adf..d41213bb8 100644 --- a/src/lib/arch/IArchFile.h +++ b/src/lib/arch/IArchFile.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -18,9 +18,9 @@ #pragma once +#include "base/String.h" #include "common/IInterface.h" #include "common/stdstring.h" -#include "base/String.h" //! Interface for architecture dependent file system operations /*! @@ -29,77 +29,76 @@ synergy. Each architecture must implement this interface. */ class IArchFile : public IInterface { public: - //! @name manipulators - //@{ + //! @name manipulators + //@{ - //! Extract base name - /*! - Find the base name in the given \c pathname. - */ - virtual const char* getBasename(const char* pathname) = 0; + //! Extract base name + /*! + Find the base name in the given \c pathname. + */ + virtual const char *getBasename(const char *pathname) = 0; - //! Get user's home directory - /*! - Returns the user's home directory. Returns the empty string if - this cannot be determined. - */ - virtual std::string getUserDirectory() = 0; + //! Get user's home directory + /*! + Returns the user's home directory. Returns the empty string if + this cannot be determined. + */ + virtual std::string getUserDirectory() = 0; - //! Get system directory - /*! - Returns the ussystem configuration file directory. - */ - virtual std::string getSystemDirectory() = 0; + //! Get system directory + /*! + Returns the ussystem configuration file directory. + */ + virtual std::string getSystemDirectory() = 0; - //! Get installed directory - /*! - Returns the directory in which Synergy is installed. - */ - virtual std::string getInstalledDirectory() = 0; + //! Get installed directory + /*! + Returns the directory in which Synergy is installed. + */ + virtual std::string getInstalledDirectory() = 0; - //! Get log directory - /*! - Returns the log file directory. - */ - virtual std::string getLogDirectory() = 0; + //! Get log directory + /*! + Returns the log file directory. + */ + virtual std::string getLogDirectory() = 0; - //! Get plugins directory - /*! - Returns the plugin files directory. If no plugin directory is set, - this will return the plugin folder within the user's profile. - */ - virtual std::string getPluginDirectory() = 0; + //! Get plugins directory + /*! + Returns the plugin files directory. If no plugin directory is set, + this will return the plugin folder within the user's profile. + */ + virtual std::string getPluginDirectory() = 0; - //! Get user's profile directory - /*! - Returns the user's profile directory. If no profile directory is set, - this will return the user's profile according to the operating system, - which will depend on which user launched the program. - */ - virtual std::string getProfileDirectory() = 0; + //! Get user's profile directory + /*! + Returns the user's profile directory. If no profile directory is set, + this will return the user's profile according to the operating system, + which will depend on which user launched the program. + */ + virtual std::string getProfileDirectory() = 0; - //! Concatenate path components - /*! - Concatenate pathname components with a directory separator - between them. This should not check if the resulting path - is longer than allowed by the system; we'll rely on the - system calls to tell us that. - */ - virtual std::string concatPath( - const std::string& prefix, - const std::string& suffix) = 0; - - //@} - //! Set the user's profile directory - /* - Returns the user's profile directory. - */ - virtual void setProfileDirectory(const String& s) = 0; + //! Concatenate path components + /*! + Concatenate pathname components with a directory separator + between them. This should not check if the resulting path + is longer than allowed by the system; we'll rely on the + system calls to tell us that. + */ + virtual std::string concatPath(const std::string &prefix, + const std::string &suffix) = 0; - //@} - //! Set the user's plugin directory - /* - Returns the user's plugin directory. - */ - virtual void setPluginDirectory(const String& s) = 0; + //@} + //! Set the user's profile directory + /* + Returns the user's profile directory. + */ + virtual void setProfileDirectory(const String &s) = 0; + + //@} + //! Set the user's plugin directory + /* + Returns the user's plugin directory. + */ + virtual void setPluginDirectory(const String &s) = 0; }; diff --git a/src/lib/arch/IArchLog.h b/src/lib/arch/IArchLog.h index 94197b885..0566ee876 100644 --- a/src/lib/arch/IArchLog.h +++ b/src/lib/arch/IArchLog.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -18,8 +18,8 @@ #pragma once -#include "common/IInterface.h" #include "base/ELevel.h" +#include "common/IInterface.h" //! Interface for architecture dependent logging /*! @@ -28,36 +28,36 @@ synergy. Each architecture must implement this interface. */ class IArchLog : public IInterface { public: - //! @name manipulators - //@{ + //! @name manipulators + //@{ - //! Open the log - /*! - Opens the log for writing. The log must be opened before being - written to. - */ - virtual void openLog(const char* name) = 0; + //! Open the log + /*! + Opens the log for writing. The log must be opened before being + written to. + */ + virtual void openLog(const char *name) = 0; - //! Close the log - /*! - Close the log. - */ - virtual void closeLog() = 0; + //! Close the log + /*! + Close the log. + */ + virtual void closeLog() = 0; - //! Show the log - /*! - Causes the log to become visible. This generally only makes sense - for a log in a graphical user interface. Other implementations - will do nothing. Iff \p showIfEmpty is \c false then the implementation - may optionally only show the log if it's not empty. - */ - virtual void showLog(bool showIfEmpty) = 0; + //! Show the log + /*! + Causes the log to become visible. This generally only makes sense + for a log in a graphical user interface. Other implementations + will do nothing. Iff \p showIfEmpty is \c false then the implementation + may optionally only show the log if it's not empty. + */ + virtual void showLog(bool showIfEmpty) = 0; - //! Write to the log - /*! - Writes the given string to the log with the given level. - */ - virtual void writeLog(ELevel, const char*) = 0; + //! Write to the log + /*! + Writes the given string to the log with the given level. + */ + virtual void writeLog(ELevel, const char *) = 0; - //@} + //@} }; diff --git a/src/lib/arch/IArchMultithread.h b/src/lib/arch/IArchMultithread.h index 9ad7a15be..fdd2b53cc 100644 --- a/src/lib/arch/IArchMultithread.h +++ b/src/lib/arch/IArchMultithread.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -20,7 +20,7 @@ #include "common/IInterface.h" -/*! +/*! \class ArchCondImpl \brief Internal condition variable data. An architecture dependent type holding the necessary data for a @@ -28,40 +28,40 @@ condition variable. */ class ArchCondImpl; -/*! +/*! \var ArchCond \brief Opaque condition variable type. An opaque type representing a condition variable. */ -typedef ArchCondImpl* ArchCond; +typedef ArchCondImpl *ArchCond; -/*! +/*! \class ArchMutexImpl \brief Internal mutex data. An architecture dependent type holding the necessary data for a mutex. */ class ArchMutexImpl; -/*! +/*! \var ArchMutex \brief Opaque mutex type. An opaque type representing a mutex. */ -typedef ArchMutexImpl* ArchMutex; +typedef ArchMutexImpl *ArchMutex; -/*! +/*! \class ArchThreadImpl \brief Internal thread data. An architecture dependent type holding the necessary data for a thread. */ class ArchThreadImpl; -/*! +/*! \var ArchThread \brief Opaque thread type. An opaque type representing a thread. */ -typedef ArchThreadImpl* ArchThread; +typedef ArchThreadImpl *ArchThread; //! Interface for architecture dependent multithreading /*! @@ -70,204 +70,203 @@ synergy. Each architecture must implement this interface. */ class IArchMultithread : public IInterface { public: - //! Type of thread entry point - typedef void* (*ThreadFunc)(void*); - //! Type of thread identifier - typedef unsigned int ThreadID; - //! Types of signals - /*! - Not all platforms support all signals. Unsupported signals are - ignored. - */ - enum ESignal { - kINTERRUPT, //!< Interrupt (e.g. Ctrl+C) - kTERMINATE, //!< Terminate (e.g. Ctrl+Break) - kHANGUP, //!< Hangup (SIGHUP) - kUSER, //!< User (SIGUSR2) - kNUM_SIGNALS - }; - //! Type of signal handler function - typedef void (*SignalFunc)(ESignal, void* userData); + //! Type of thread entry point + typedef void *(*ThreadFunc)(void *); + //! Type of thread identifier + typedef unsigned int ThreadID; + //! Types of signals + /*! + Not all platforms support all signals. Unsupported signals are + ignored. + */ + enum ESignal { + kINTERRUPT, //!< Interrupt (e.g. Ctrl+C) + kTERMINATE, //!< Terminate (e.g. Ctrl+Break) + kHANGUP, //!< Hangup (SIGHUP) + kUSER, //!< User (SIGUSR2) + kNUM_SIGNALS + }; + //! Type of signal handler function + typedef void (*SignalFunc)(ESignal, void *userData); - //! @name manipulators - //@{ + //! @name manipulators + //@{ - // - // condition variable methods - // + // + // condition variable methods + // - //! Create a condition variable - /*! - The condition variable is an opaque data type. - */ - virtual ArchCond newCondVar() = 0; + //! Create a condition variable + /*! + The condition variable is an opaque data type. + */ + virtual ArchCond newCondVar() = 0; - //! Destroy a condition variable - virtual void closeCondVar(ArchCond) = 0; + //! Destroy a condition variable + virtual void closeCondVar(ArchCond) = 0; - //! Signal a condition variable - /*! - Signalling a condition variable releases one waiting thread. - */ - virtual void signalCondVar(ArchCond) = 0; + //! Signal a condition variable + /*! + Signalling a condition variable releases one waiting thread. + */ + virtual void signalCondVar(ArchCond) = 0; - //! Broadcast a condition variable - /*! - Broadcasting a condition variable releases all waiting threads. - */ - virtual void broadcastCondVar(ArchCond) = 0; + //! Broadcast a condition variable + /*! + Broadcasting a condition variable releases all waiting threads. + */ + virtual void broadcastCondVar(ArchCond) = 0; - //! Wait on a condition variable - /*! - Wait on a conditation variable for up to \c timeout seconds. - If \c timeout is < 0 then there is no timeout. The mutex must - be locked when this method is called. The mutex is unlocked - during the wait and locked again before returning. Returns - true if the condition variable was signalled and false on - timeout. + //! Wait on a condition variable + /*! + Wait on a conditation variable for up to \c timeout seconds. + If \c timeout is < 0 then there is no timeout. The mutex must + be locked when this method is called. The mutex is unlocked + during the wait and locked again before returning. Returns + true if the condition variable was signalled and false on + timeout. - (Cancellation point) - */ - virtual bool waitCondVar(ArchCond, ArchMutex, double timeout) = 0; + (Cancellation point) + */ + virtual bool waitCondVar(ArchCond, ArchMutex, double timeout) = 0; - // - // mutex methods - // + // + // mutex methods + // - //! Create a recursive mutex - /*! - Creates a recursive mutex. A thread may lock a recursive mutex - when it already holds a lock on that mutex. The mutex is an - opaque data type. - */ - virtual ArchMutex newMutex() = 0; + //! Create a recursive mutex + /*! + Creates a recursive mutex. A thread may lock a recursive mutex + when it already holds a lock on that mutex. The mutex is an + opaque data type. + */ + virtual ArchMutex newMutex() = 0; - //! Destroy a mutex - virtual void closeMutex(ArchMutex) = 0; + //! Destroy a mutex + virtual void closeMutex(ArchMutex) = 0; - //! Lock a mutex - virtual void lockMutex(ArchMutex) = 0; + //! Lock a mutex + virtual void lockMutex(ArchMutex) = 0; - //! Unlock a mutex - virtual void unlockMutex(ArchMutex) = 0; + //! Unlock a mutex + virtual void unlockMutex(ArchMutex) = 0; - // - // thread methods - // + // + // thread methods + // - //! Start a new thread - /*! - Creates and starts a new thread, using \c func as the entry point - and passing it \c userData. The thread is an opaque data type. - */ - virtual ArchThread newThread(ThreadFunc func, void* userData) = 0; + //! Start a new thread + /*! + Creates and starts a new thread, using \c func as the entry point + and passing it \c userData. The thread is an opaque data type. + */ + virtual ArchThread newThread(ThreadFunc func, void *userData) = 0; - //! Get a reference to the calling thread - /*! - Returns a thread representing the current (i.e. calling) thread. - */ - virtual ArchThread newCurrentThread() = 0; + //! Get a reference to the calling thread + /*! + Returns a thread representing the current (i.e. calling) thread. + */ + virtual ArchThread newCurrentThread() = 0; - //! Copy a thread object - /*! - Returns a reference to to thread referred to by \c thread. - */ - virtual ArchThread copyThread(ArchThread thread) = 0; + //! Copy a thread object + /*! + Returns a reference to to thread referred to by \c thread. + */ + virtual ArchThread copyThread(ArchThread thread) = 0; - //! Release a thread reference - /*! - Deletes the given thread object. This does not destroy the thread - the object referred to, even if there are no remaining references. - Use cancelThread() and waitThread() to stop a thread and wait for - it to exit. - */ - virtual void closeThread(ArchThread) = 0; + //! Release a thread reference + /*! + Deletes the given thread object. This does not destroy the thread + the object referred to, even if there are no remaining references. + Use cancelThread() and waitThread() to stop a thread and wait for + it to exit. + */ + virtual void closeThread(ArchThread) = 0; - //! Force a thread to exit - /*! - Causes \c thread to exit when it next calls a cancellation point. - A thread avoids cancellation as long as it nevers calls a - cancellation point. Once it begins the cancellation process it - must always let cancellation go to completion but may take as - long as necessary to clean up. - */ - virtual void cancelThread(ArchThread thread) = 0; + //! Force a thread to exit + /*! + Causes \c thread to exit when it next calls a cancellation point. + A thread avoids cancellation as long as it nevers calls a + cancellation point. Once it begins the cancellation process it + must always let cancellation go to completion but may take as + long as necessary to clean up. + */ + virtual void cancelThread(ArchThread thread) = 0; - //! Change thread priority - /*! - Changes the priority of \c thread by \c n. If \c n is positive - the thread has a lower priority and if negative a higher priority. - Some architectures may not support either or both directions. - */ - virtual void setPriorityOfThread(ArchThread, int n) = 0; + //! Change thread priority + /*! + Changes the priority of \c thread by \c n. If \c n is positive + the thread has a lower priority and if negative a higher priority. + Some architectures may not support either or both directions. + */ + virtual void setPriorityOfThread(ArchThread, int n) = 0; - //! Cancellation point - /*! - This method does nothing but is a cancellation point. Clients - can make their own functions cancellation points by calling this - method at appropriate times. + //! Cancellation point + /*! + This method does nothing but is a cancellation point. Clients + can make their own functions cancellation points by calling this + method at appropriate times. - (Cancellation point) - */ - virtual void testCancelThread() = 0; + (Cancellation point) + */ + virtual void testCancelThread() = 0; - //! Wait for a thread to exit - /*! - Waits for up to \c timeout seconds for \c thread to exit (normally - or by cancellation). Waits forever if \c timeout < 0. Returns - true if the thread exited, false otherwise. Waiting on the current - thread returns immediately with false. + //! Wait for a thread to exit + /*! + Waits for up to \c timeout seconds for \c thread to exit (normally + or by cancellation). Waits forever if \c timeout < 0. Returns + true if the thread exited, false otherwise. Waiting on the current + thread returns immediately with false. - (Cancellation point) - */ - virtual bool wait(ArchThread thread, double timeout) = 0; + (Cancellation point) + */ + virtual bool wait(ArchThread thread, double timeout) = 0; - //! Compare threads - /*! - Returns true iff two thread objects refer to the same thread. - Note that comparing thread objects directly is meaningless. - */ - virtual bool isSameThread(ArchThread, ArchThread) = 0; + //! Compare threads + /*! + Returns true iff two thread objects refer to the same thread. + Note that comparing thread objects directly is meaningless. + */ + virtual bool isSameThread(ArchThread, ArchThread) = 0; - //! Test if thread exited - /*! - Returns true iff \c thread has exited. - */ - virtual bool isExitedThread(ArchThread thread) = 0; + //! Test if thread exited + /*! + Returns true iff \c thread has exited. + */ + virtual bool isExitedThread(ArchThread thread) = 0; - //! Returns the exit code of a thread - /*! - Waits indefinitely for \c thread to exit (if it hasn't yet) then - returns the thread's exit code. + //! Returns the exit code of a thread + /*! + Waits indefinitely for \c thread to exit (if it hasn't yet) then + returns the thread's exit code. - (Cancellation point) - */ - virtual void* getResultOfThread(ArchThread thread) = 0; + (Cancellation point) + */ + virtual void *getResultOfThread(ArchThread thread) = 0; - //! Returns an ID for a thread - /*! - Returns some ID number for \c thread. This is for logging purposes. - All thread objects referring to the same thread return the same ID. - However, clients should us isSameThread() to compare thread objects - instead of comparing IDs. - */ - virtual ThreadID getIDOfThread(ArchThread thread) = 0; + //! Returns an ID for a thread + /*! + Returns some ID number for \c thread. This is for logging purposes. + All thread objects referring to the same thread return the same ID. + However, clients should us isSameThread() to compare thread objects + instead of comparing IDs. + */ + virtual ThreadID getIDOfThread(ArchThread thread) = 0; - //! Set the interrupt handler - /*! - Sets the function to call on receipt of an external interrupt. - By default and when \p func is NULL, the main thread is cancelled. - */ - virtual void setSignalHandler(ESignal, SignalFunc func, - void* userData) = 0; + //! Set the interrupt handler + /*! + Sets the function to call on receipt of an external interrupt. + By default and when \p func is NULL, the main thread is cancelled. + */ + virtual void setSignalHandler(ESignal, SignalFunc func, void *userData) = 0; - //! Invoke the signal handler - /*! - Invokes the signal handler for \p signal, if any. If no handler - cancels the main thread for \c kINTERRUPT and \c kTERMINATE and - ignores the call otherwise. - */ - virtual void raiseSignal(ESignal signal) = 0; + //! Invoke the signal handler + /*! + Invokes the signal handler for \p signal, if any. If no handler + cancels the main thread for \c kINTERRUPT and \c kTERMINATE and + ignores the call otherwise. + */ + virtual void raiseSignal(ESignal signal) = 0; - //@} + //@} }; diff --git a/src/lib/arch/IArchNetwork.h b/src/lib/arch/IArchNetwork.h index e9e4edfa4..bcbd55f8b 100644 --- a/src/lib/arch/IArchNetwork.h +++ b/src/lib/arch/IArchNetwork.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -24,23 +24,23 @@ #include class ArchThreadImpl; -typedef ArchThreadImpl* ArchThread; +typedef ArchThreadImpl *ArchThread; -/*! +/*! \class ArchSocketImpl \brief Internal socket data. An architecture dependent type holding the necessary data for a socket. */ class ArchSocketImpl; -/*! +/*! \var ArchSocket \brief Opaque socket type. An opaque type representing a socket. */ -typedef ArchSocketImpl* ArchSocket; +typedef ArchSocketImpl *ArchSocket; -/*! +/*! \class ArchNetAddressImpl \brief Internal network address data. An architecture dependent type holding the necessary data for a network @@ -48,12 +48,12 @@ address. */ class ArchNetAddressImpl; -/*! +/*! \var ArchNetAddress \brief Opaque network address type. An opaque type representing a network address. */ -typedef ArchNetAddressImpl* ArchNetAddress; +typedef ArchNetAddressImpl *ArchNetAddress; //! Interface for architecture dependent networking /*! @@ -62,225 +62,220 @@ synergy. Each architecture must implement this interface. */ class IArchNetwork : public IInterface { public: - //! Supported address families - enum EAddressFamily { - kUNKNOWN, - kINET, - kINET6, - }; + //! Supported address families + enum EAddressFamily { + kUNKNOWN, + kINET, + kINET6, + }; - //! Supported socket types - enum ESocketType { - kDGRAM, - kSTREAM - }; + //! Supported socket types + enum ESocketType { kDGRAM, kSTREAM }; - //! Events for \c poll() + //! Events for \c poll() + /*! + Events for \c poll() are bitmasks and can be combined using the + bitwise operators. + */ + enum { + kPOLLIN = 1, //!< Socket is readable + kPOLLOUT = 2, //!< Socket is writable + kPOLLERR = 4, //!< The socket is in an error state + kPOLLNVAL = 8 //!< The socket is invalid + }; + + //! A socket query for \c poll() + class PollEntry { + public: + //! The socket to query + ArchSocket m_socket; + + //! The events to query for /*! - Events for \c poll() are bitmasks and can be combined using the - bitwise operators. + The events to query for can be any combination of kPOLLIN and + kPOLLOUT. */ - enum { - kPOLLIN = 1, //!< Socket is readable - kPOLLOUT = 2, //!< Socket is writable - kPOLLERR = 4, //!< The socket is in an error state - kPOLLNVAL = 8 //!< The socket is invalid - }; + unsigned short m_events; - //! A socket query for \c poll() - class PollEntry { - public: - //! The socket to query - ArchSocket m_socket; + //! The result events + unsigned short m_revents; + }; - //! The events to query for - /*! - The events to query for can be any combination of kPOLLIN and - kPOLLOUT. - */ - unsigned short m_events; + //! @name manipulators + //@{ - //! The result events - unsigned short m_revents; - }; + //! Create a new socket + /*! + The socket is an opaque data type. + */ + virtual ArchSocket newSocket(EAddressFamily, ESocketType) = 0; - //! @name manipulators - //@{ + //! Copy a socket object + /*! + Returns a reference to to socket referred to by \c s. + */ + virtual ArchSocket copySocket(ArchSocket s) = 0; - //! Create a new socket - /*! - The socket is an opaque data type. - */ - virtual ArchSocket newSocket(EAddressFamily, ESocketType) = 0; + //! Release a socket reference + /*! + Deletes the given socket object. This does not destroy the socket + the object referred to until there are no remaining references for + the socket. + */ + virtual void closeSocket(ArchSocket s) = 0; - //! Copy a socket object - /*! - Returns a reference to to socket referred to by \c s. - */ - virtual ArchSocket copySocket(ArchSocket s) = 0; + //! Close socket for further reads + /*! + Calling this disallows future reads on socket \c s. + */ + virtual void closeSocketForRead(ArchSocket s) = 0; - //! Release a socket reference - /*! - Deletes the given socket object. This does not destroy the socket - the object referred to until there are no remaining references for - the socket. - */ - virtual void closeSocket(ArchSocket s) = 0; + //! Close socket for further writes + /*! + Calling this disallows future writes on socket \c s. + */ + virtual void closeSocketForWrite(ArchSocket s) = 0; - //! Close socket for further reads - /*! - Calling this disallows future reads on socket \c s. - */ - virtual void closeSocketForRead(ArchSocket s) = 0; + //! Bind socket to address + /*! + Binds socket \c s to the address \c addr. + */ + virtual void bindSocket(ArchSocket s, ArchNetAddress addr) = 0; - //! Close socket for further writes - /*! - Calling this disallows future writes on socket \c s. - */ - virtual void closeSocketForWrite(ArchSocket s) = 0; + //! Listen for connections on socket + /*! + Causes the socket \c s to begin listening for incoming connections. + */ + virtual void listenOnSocket(ArchSocket s) = 0; - //! Bind socket to address - /*! - Binds socket \c s to the address \c addr. - */ - virtual void bindSocket(ArchSocket s, ArchNetAddress addr) = 0; + //! Accept connection on socket + /*! + Accepts a connection on socket \c s, returning a new socket for the + connection and filling in \c addr with the address of the remote + end. \c addr may be NULL if the remote address isn't required. + The original socket \c s is unaffected and remains in the listening + state. The new socket shares most of the properties of \c s except + it's not in the listening state and it's connected. Returns NULL + if there are no pending connection requests. + */ + virtual ArchSocket acceptSocket(ArchSocket s, ArchNetAddress *addr) = 0; - //! Listen for connections on socket - /*! - Causes the socket \c s to begin listening for incoming connections. - */ - virtual void listenOnSocket(ArchSocket s) = 0; + //! Connect socket + /*! + Connects the socket \c s to the remote address \c addr. Returns + true if the connection succeed immediately, false if the connection + is in progress, and throws if the connection failed immediately. + If it returns false, \c pollSocket() can be used to wait on the + socket for writing to detect when the connection finally succeeds + or fails. + */ + virtual bool connectSocket(ArchSocket s, ArchNetAddress addr) = 0; - //! Accept connection on socket - /*! - Accepts a connection on socket \c s, returning a new socket for the - connection and filling in \c addr with the address of the remote - end. \c addr may be NULL if the remote address isn't required. - The original socket \c s is unaffected and remains in the listening - state. The new socket shares most of the properties of \c s except - it's not in the listening state and it's connected. Returns NULL - if there are no pending connection requests. - */ - virtual ArchSocket acceptSocket(ArchSocket s, ArchNetAddress* addr) = 0; + //! Check socket state + /*! + Tests the state of \c num sockets for readability and/or writability. + Waits up to \c timeout seconds for some socket to become readable + and/or writable (or indefinitely if \c timeout < 0). Returns the + number of sockets that were readable (if readability was being + queried) or writable (if writablility was being queried) and sets + the \c m_revents members of the entries. \c kPOLLERR and \c kPOLLNVAL + are set in \c m_revents as appropriate. If a socket indicates + \c kPOLLERR then \c throwErrorOnSocket() can be used to determine + the type of error. Returns 0 immediately regardless of the \c timeout + if no valid sockets are selected for testing. - //! Connect socket - /*! - Connects the socket \c s to the remote address \c addr. Returns - true if the connection succeed immediately, false if the connection - is in progress, and throws if the connection failed immediately. - If it returns false, \c pollSocket() can be used to wait on the - socket for writing to detect when the connection finally succeeds - or fails. - */ - virtual bool connectSocket(ArchSocket s, ArchNetAddress addr) = 0; + (Cancellation point) + */ + virtual int pollSocket(PollEntry[], int num, double timeout) = 0; - //! Check socket state - /*! - Tests the state of \c num sockets for readability and/or writability. - Waits up to \c timeout seconds for some socket to become readable - and/or writable (or indefinitely if \c timeout < 0). Returns the - number of sockets that were readable (if readability was being - queried) or writable (if writablility was being queried) and sets - the \c m_revents members of the entries. \c kPOLLERR and \c kPOLLNVAL - are set in \c m_revents as appropriate. If a socket indicates - \c kPOLLERR then \c throwErrorOnSocket() can be used to determine - the type of error. Returns 0 immediately regardless of the \c timeout - if no valid sockets are selected for testing. + //! Unblock thread in pollSocket() + /*! + Cause a thread that's in a pollSocket() call to return. This + call may return before the thread is unblocked. If the thread is + not in a pollSocket() call this call has no effect. + */ + virtual void unblockPollSocket(ArchThread thread) = 0; - (Cancellation point) - */ - virtual int pollSocket(PollEntry[], int num, double timeout) = 0; + //! Read data from socket + /*! + Read up to \c len bytes from socket \c s in \c buf and return the + number of bytes read. The number of bytes can be less than \c len + if not enough data is available. Returns 0 if the remote end has + disconnected and/or there is no more queued received data. + */ + virtual size_t readSocket(ArchSocket s, void *buf, size_t len) = 0; - //! Unblock thread in pollSocket() - /*! - Cause a thread that's in a pollSocket() call to return. This - call may return before the thread is unblocked. If the thread is - not in a pollSocket() call this call has no effect. - */ - virtual void unblockPollSocket(ArchThread thread) = 0; + //! Write data from socket + /*! + Write up to \c len bytes to socket \c s from \c buf and return the + number of bytes written. The number of bytes can be less than + \c len if the remote end disconnected or the internal buffers fill + up. + */ + virtual size_t writeSocket(ArchSocket s, const void *buf, size_t len) = 0; - //! Read data from socket - /*! - Read up to \c len bytes from socket \c s in \c buf and return the - number of bytes read. The number of bytes can be less than \c len - if not enough data is available. Returns 0 if the remote end has - disconnected and/or there is no more queued received data. - */ - virtual size_t readSocket(ArchSocket s, void* buf, size_t len) = 0; + //! Check error on socket + /*! + If the socket \c s is in an error state then throws an appropriate + XArchNetwork exception. + */ + virtual void throwErrorOnSocket(ArchSocket s) = 0; - //! Write data from socket - /*! - Write up to \c len bytes to socket \c s from \c buf and return the - number of bytes written. The number of bytes can be less than - \c len if the remote end disconnected or the internal buffers fill - up. - */ - virtual size_t writeSocket(ArchSocket s, - const void* buf, size_t len) = 0; + //! Turn Nagle algorithm on or off on socket + /*! + Set socket to send messages immediately (true) or to collect small + messages into one packet (false). Returns the previous state. + */ + virtual bool setNoDelayOnSocket(ArchSocket, bool noDelay) = 0; - //! Check error on socket - /*! - If the socket \c s is in an error state then throws an appropriate - XArchNetwork exception. - */ - virtual void throwErrorOnSocket(ArchSocket s) = 0; + //! Turn address reuse on or off on socket + /*! + Allows the address this socket is bound to to be reused while in the + TIME_WAIT state. Returns the previous state. + */ + virtual bool setReuseAddrOnSocket(ArchSocket, bool reuse) = 0; - //! Turn Nagle algorithm on or off on socket - /*! - Set socket to send messages immediately (true) or to collect small - messages into one packet (false). Returns the previous state. - */ - virtual bool setNoDelayOnSocket(ArchSocket, bool noDelay) = 0; + //! Return local host's name + virtual std::string getHostName() = 0; - //! Turn address reuse on or off on socket - /*! - Allows the address this socket is bound to to be reused while in the - TIME_WAIT state. Returns the previous state. - */ - virtual bool setReuseAddrOnSocket(ArchSocket, bool reuse) = 0; + //! Create an "any" network address + virtual ArchNetAddress newAnyAddr(EAddressFamily) = 0; - //! Return local host's name - virtual std::string getHostName() = 0; + //! Copy a network address + virtual ArchNetAddress copyAddr(ArchNetAddress) = 0; - //! Create an "any" network address - virtual ArchNetAddress newAnyAddr(EAddressFamily) = 0; + //! Convert a name to a network address + virtual std::vector nameToAddr(const std::string &) = 0; - //! Copy a network address - virtual ArchNetAddress copyAddr(ArchNetAddress) = 0; + //! Destroy a network address + virtual void closeAddr(ArchNetAddress) = 0; - //! Convert a name to a network address - virtual std::vector - nameToAddr(const std::string&) = 0; + //! Convert an address to a host name + virtual std::string addrToName(ArchNetAddress) = 0; - //! Destroy a network address - virtual void closeAddr(ArchNetAddress) = 0; + //! Convert an address to a string + virtual std::string addrToString(ArchNetAddress) = 0; - //! Convert an address to a host name - virtual std::string addrToName(ArchNetAddress) = 0; + //! Get an address's family + virtual EAddressFamily getAddrFamily(ArchNetAddress) = 0; - //! Convert an address to a string - virtual std::string addrToString(ArchNetAddress) = 0; + //! Set the port of an address + virtual void setAddrPort(ArchNetAddress, int port) = 0; - //! Get an address's family - virtual EAddressFamily getAddrFamily(ArchNetAddress) = 0; + //! Get the port of an address + virtual int getAddrPort(ArchNetAddress) = 0; - //! Set the port of an address - virtual void setAddrPort(ArchNetAddress, int port) = 0; + //! Test addresses for equality + virtual bool isEqualAddr(ArchNetAddress, ArchNetAddress) = 0; - //! Get the port of an address - virtual int getAddrPort(ArchNetAddress) = 0; + //! Test for the "any" address + /*! + Returns true if \c addr is the "any" address. \c newAnyAddr() + returns an "any" address. + */ + virtual bool isAnyAddr(ArchNetAddress addr) = 0; - //! Test addresses for equality - virtual bool isEqualAddr(ArchNetAddress, ArchNetAddress) = 0; + //@} - //! Test for the "any" address - /*! - Returns true if \c addr is the "any" address. \c newAnyAddr() - returns an "any" address. - */ - virtual bool isAnyAddr(ArchNetAddress addr) = 0; - - //@} - - virtual void init() = 0; + virtual void init() = 0; }; diff --git a/src/lib/arch/IArchSleep.h b/src/lib/arch/IArchSleep.h index 4a18a041d..9ee0076a4 100644 --- a/src/lib/arch/IArchSleep.h +++ b/src/lib/arch/IArchSleep.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -27,18 +27,18 @@ synergy. Each architecture must implement this interface. */ class IArchSleep : public IInterface { public: - //! @name manipulators - //@{ + //! @name manipulators + //@{ - //! Sleep - /*! - Blocks the calling thread for \c timeout seconds. If - \c timeout < 0.0 then the call returns immediately. If \c timeout - == 0.0 then the calling thread yields the CPU. + //! Sleep + /*! + Blocks the calling thread for \c timeout seconds. If + \c timeout < 0.0 then the call returns immediately. If \c timeout + == 0.0 then the calling thread yields the CPU. - (cancellation point) - */ - virtual void sleep(double timeout) = 0; + (cancellation point) + */ + virtual void sleep(double timeout) = 0; - //@} + //@} }; diff --git a/src/lib/arch/IArchString.cpp b/src/lib/arch/IArchString.cpp index 7d89bea42..9c1cb63ac 100644 --- a/src/lib/arch/IArchString.cpp +++ b/src/lib/arch/IArchString.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2011 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 LICENSE 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 @@ -21,178 +21,170 @@ #include "common/common.h" #include -#include #include +#include -static ArchMutex s_mutex = NULL; +static ArchMutex s_mutex = NULL; // // use C library non-reentrant multibyte conversion with mutex // -IArchString::~IArchString() -{ - if (s_mutex != NULL) { - ARCH->closeMutex(s_mutex); - s_mutex = NULL; - } +IArchString::~IArchString() { + if (s_mutex != NULL) { + ARCH->closeMutex(s_mutex); + s_mutex = NULL; + } } -int -IArchString::convStringWCToMB(char* dst, - const wchar_t* src, UInt32 n, bool* errors) -{ - ptrdiff_t len = 0; +int IArchString::convStringWCToMB(char *dst, const wchar_t *src, UInt32 n, + bool *errors) { + ptrdiff_t len = 0; - bool dummyErrors; - if (errors == NULL) { - errors = &dummyErrors; + bool dummyErrors; + if (errors == NULL) { + errors = &dummyErrors; + } + *errors = false; + + if (s_mutex == NULL) { + s_mutex = ARCH->newMutex(); + } + + ARCH->lockMutex(s_mutex); + + if (dst == NULL) { + char dummy[MB_LEN_MAX]; + const wchar_t *scan = src; + for (; n > 0; --n) { + ptrdiff_t mblen = wctomb(dummy, *scan); + if (mblen == -1) { + *errors = true; + mblen = 1; + } + len += mblen; + ++scan; } - *errors = false; - - if (s_mutex == NULL) { - s_mutex = ARCH->newMutex(); + ptrdiff_t mblen = wctomb(dummy, L'\0'); + if (mblen != -1) { + len += mblen - 1; } - - ARCH->lockMutex(s_mutex); - - if (dst == NULL) { - char dummy[MB_LEN_MAX]; - const wchar_t* scan = src; - for (; n > 0; --n) { - ptrdiff_t mblen = wctomb(dummy, *scan); - if (mblen == -1) { - *errors = true; - mblen = 1; - } - len += mblen; - ++scan; - } - ptrdiff_t mblen = wctomb(dummy, L'\0'); - if (mblen != -1) { - len += mblen - 1; - } + } else { + char *dst0 = dst; + const wchar_t *scan = src; + for (; n > 0; --n) { + ptrdiff_t mblen = wctomb(dst, *scan); + if (mblen == -1) { + *errors = true; + *dst++ = '?'; + } else { + dst += mblen; + } + ++scan; } - else { - char* dst0 = dst; - const wchar_t* scan = src; - for (; n > 0; --n) { - ptrdiff_t mblen = wctomb(dst, *scan); - if (mblen == -1) { - *errors = true; - *dst++ = '?'; - } - else { - dst += mblen; - } - ++scan; - } - ptrdiff_t mblen = wctomb(dst, L'\0'); - if (mblen != -1) { - // don't include nul terminator - dst += mblen - 1; - } - len = dst - dst0; + ptrdiff_t mblen = wctomb(dst, L'\0'); + if (mblen != -1) { + // don't include nul terminator + dst += mblen - 1; } - ARCH->unlockMutex(s_mutex); + len = dst - dst0; + } + ARCH->unlockMutex(s_mutex); - return static_cast(len); + return static_cast(len); } -int -IArchString::convStringMBToWC(wchar_t* dst, - const char* src, UInt32 n, bool* errors) -{ - ptrdiff_t len = 0; - wchar_t dummy; +int IArchString::convStringMBToWC(wchar_t *dst, const char *src, UInt32 n, + bool *errors) { + ptrdiff_t len = 0; + wchar_t dummy; - bool dummyErrors; - if (errors == NULL) { - errors = &dummyErrors; + bool dummyErrors; + if (errors == NULL) { + errors = &dummyErrors; + } + *errors = false; + + if (s_mutex == NULL) { + s_mutex = ARCH->newMutex(); + } + + ARCH->lockMutex(s_mutex); + + if (dst == NULL) { + const char *scan = src; + while (n > 0) { + ptrdiff_t mblen = mbtowc(&dummy, scan, n); + switch (mblen) { + case -2: + // incomplete last character. convert to unknown character. + *errors = true; + len += 1; + n = 0; + break; + + case -1: + // invalid character. count one unknown character and + // start at the next byte. + *errors = true; + len += 1; + scan += 1; + n -= 1; + break; + + case 0: + len += 1; + scan += 1; + n -= 1; + break; + + default: + // normal character + len += 1; + scan += static_cast(mblen); + n -= static_cast(mblen); + break; + } } - *errors = false; + } else { + wchar_t *dst0 = dst; + const char *scan = src; + while (n > 0) { + ptrdiff_t mblen = mbtowc(dst, scan, n); + switch (mblen) { + case -2: + // incomplete character. convert to unknown character. + *errors = true; + *dst = (wchar_t)0xfffd; + n = 0; + break; - if (s_mutex == NULL) { - s_mutex = ARCH->newMutex(); + case -1: + // invalid character. count one unknown character and + // start at the next byte. + *errors = true; + *dst = (wchar_t)0xfffd; + scan += 1; + n -= 1; + break; + + case 0: + *dst = (wchar_t)0x0000; + scan += 1; + n -= 1; + break; + + default: + // normal character + scan += static_cast(mblen); + n -= static_cast(mblen); + break; + } + ++dst; } + len = dst - dst0; + } + ARCH->unlockMutex(s_mutex); - ARCH->lockMutex(s_mutex); - - if (dst == NULL) { - const char* scan = src; - while (n > 0) { - ptrdiff_t mblen = mbtowc(&dummy, scan, n); - switch (mblen) { - case -2: - // incomplete last character. convert to unknown character. - *errors = true; - len += 1; - n = 0; - break; - - case -1: - // invalid character. count one unknown character and - // start at the next byte. - *errors = true; - len += 1; - scan += 1; - n -= 1; - break; - - case 0: - len += 1; - scan += 1; - n -= 1; - break; - - default: - // normal character - len += 1; - scan += static_cast(mblen); - n -= static_cast(mblen); - break; - } - } - } - else { - wchar_t* dst0 = dst; - const char* scan = src; - while (n > 0) { - ptrdiff_t mblen = mbtowc(dst, scan, n); - switch (mblen) { - case -2: - // incomplete character. convert to unknown character. - *errors = true; - *dst = (wchar_t)0xfffd; - n = 0; - break; - - case -1: - // invalid character. count one unknown character and - // start at the next byte. - *errors = true; - *dst = (wchar_t)0xfffd; - scan += 1; - n -= 1; - break; - - case 0: - *dst = (wchar_t)0x0000; - scan += 1; - n -= 1; - break; - - default: - // normal character - scan += static_cast(mblen); - n -= static_cast(mblen); - break; - } - ++dst; - } - len = dst - dst0; - } - ARCH->unlockMutex(s_mutex); - - return static_cast(len); + return static_cast(len); } diff --git a/src/lib/arch/IArchString.h b/src/lib/arch/IArchString.h index 898165d98..46e7bbc0e 100644 --- a/src/lib/arch/IArchString.h +++ b/src/lib/arch/IArchString.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -30,50 +30,46 @@ synergy. Each architecture must implement this interface. */ class IArchString : public IInterface { public: - IArchString() =default; - IArchString(const IArchString &) =delete; - IArchString(IArchString &&) =delete; - virtual ~IArchString(); + IArchString() = default; + IArchString(const IArchString &) = delete; + IArchString(IArchString &&) = delete; + virtual ~IArchString(); - IArchString& operator=(const IArchString &) =delete; - IArchString& operator=(IArchString &&) =delete; + IArchString &operator=(const IArchString &) = delete; + IArchString &operator=(IArchString &&) = delete; - //! Wide character encodings - /*! - The known wide character encodings - */ - enum EWideCharEncoding { - kUCS2, //!< The UCS-2 encoding - kUCS4, //!< The UCS-4 encoding - kUTF16, //!< The UTF-16 encoding - kUTF32, //!< The UTF-32 encoding - kPlatformDetermined - }; + //! Wide character encodings + /*! + The known wide character encodings + */ + enum EWideCharEncoding { + kUCS2, //!< The UCS-2 encoding + kUCS4, //!< The UCS-4 encoding + kUTF16, //!< The UTF-16 encoding + kUTF32, //!< The UTF-32 encoding + kPlatformDetermined + }; - //! @name manipulators - //@{ + //! @name manipulators + //@{ - //! printf() to limited size buffer with va_list - /*! - This method is equivalent to vsprintf() except it will not write - more than \c n bytes to the buffer, returning -1 if the output - was truncated and the number of bytes written not including the - trailing NUL otherwise. - */ - virtual int vsnprintf(char* str, - int size, const char* fmt, va_list ap); + //! printf() to limited size buffer with va_list + /*! + This method is equivalent to vsprintf() except it will not write + more than \c n bytes to the buffer, returning -1 if the output + was truncated and the number of bytes written not including the + trailing NUL otherwise. + */ + virtual int vsnprintf(char *str, int size, const char *fmt, va_list ap); - //! Convert multibyte string to wide character string - virtual int convStringMBToWC(wchar_t*, - const char*, UInt32 n, bool* errors); + //! Convert multibyte string to wide character string + virtual int convStringMBToWC(wchar_t *, const char *, UInt32 n, bool *errors); - //! Convert wide character string to multibyte string - virtual int convStringWCToMB(char*, - const wchar_t*, UInt32 n, bool* errors); + //! Convert wide character string to multibyte string + virtual int convStringWCToMB(char *, const wchar_t *, UInt32 n, bool *errors); - //! Return the architecture's native wide character encoding - virtual EWideCharEncoding - getWideCharEncoding() = 0; + //! Return the architecture's native wide character encoding + virtual EWideCharEncoding getWideCharEncoding() = 0; - //@} + //@} }; diff --git a/src/lib/arch/IArchSystem.h b/src/lib/arch/IArchSystem.h index b5a46e256..5ee5de346 100644 --- a/src/lib/arch/IArchSystem.h +++ b/src/lib/arch/IArchSystem.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 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 LICENSE 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 @@ -27,33 +27,34 @@ This interface defines operations for querying system info. */ class IArchSystem : public IInterface { public: - //! @name accessors - //@{ + //! @name accessors + //@{ - //! Identify the OS - /*! - Returns a string identifying the operating system. - */ - virtual std::string getOSName() const = 0; + //! Identify the OS + /*! + Returns a string identifying the operating system. + */ + virtual std::string getOSName() const = 0; - //! Identify the platform - /*! - Returns a string identifying the platform this OS is running on. - */ - virtual std::string getPlatformName() const = 0; - //@} + //! Identify the platform + /*! + Returns a string identifying the platform this OS is running on. + */ + virtual std::string getPlatformName() const = 0; + //@} - //! Get a Synergy setting - /*! - Reads a Synergy setting from the system. - */ - virtual std::string setting(const std::string& valueName) const = 0; - //@} + //! Get a Synergy setting + /*! + Reads a Synergy setting from the system. + */ + virtual std::string setting(const std::string &valueName) const = 0; + //@} - //! Set a Synergy setting - /*! - Writes a Synergy setting from the system. - */ - virtual void setting(const std::string& valueName, const std::string& valueString) const = 0; - //@} + //! Set a Synergy setting + /*! + Writes a Synergy setting from the system. + */ + virtual void setting(const std::string &valueName, + const std::string &valueString) const = 0; + //@} }; diff --git a/src/lib/arch/IArchTaskBar.h b/src/lib/arch/IArchTaskBar.h index abf48fd3b..c0f2f2495 100644 --- a/src/lib/arch/IArchTaskBar.h +++ b/src/lib/arch/IArchTaskBar.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2003 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 LICENSE 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 @@ -30,34 +30,34 @@ though each operation can be a no-op. */ class IArchTaskBar : public IInterface { public: - //! @name manipulators - //@{ + //! @name manipulators + //@{ - //! Add a receiver - /*! - Add a receiver object to be notified of user and application - events. This should be called before other methods. When - the receiver is added to the task bar, its icon appears on - the task bar. - */ - virtual void addReceiver(IArchTaskBarReceiver*) = 0; + //! Add a receiver + /*! + Add a receiver object to be notified of user and application + events. This should be called before other methods. When + the receiver is added to the task bar, its icon appears on + the task bar. + */ + virtual void addReceiver(IArchTaskBarReceiver *) = 0; - //! Remove a receiver - /*! - Remove a receiver object from the task bar. This removes the - icon from the task bar. - */ - virtual void removeReceiver(IArchTaskBarReceiver*) = 0; + //! Remove a receiver + /*! + Remove a receiver object from the task bar. This removes the + icon from the task bar. + */ + virtual void removeReceiver(IArchTaskBarReceiver *) = 0; - //! Update a receiver - /*! - Updates the display of the receiver on the task bar. This - should be called when the receiver appearance may have changed - (e.g. it's icon or tool tip has changed). - */ - virtual void updateReceiver(IArchTaskBarReceiver*) = 0; + //! Update a receiver + /*! + Updates the display of the receiver on the task bar. This + should be called when the receiver appearance may have changed + (e.g. it's icon or tool tip has changed). + */ + virtual void updateReceiver(IArchTaskBarReceiver *) = 0; - //@} + //@} - virtual void init() = 0; + virtual void init() = 0; }; diff --git a/src/lib/arch/IArchTaskBarReceiver.h b/src/lib/arch/IArchTaskBarReceiver.h index aa6fc7f56..a05604f18 100644 --- a/src/lib/arch/IArchTaskBarReceiver.h +++ b/src/lib/arch/IArchTaskBarReceiver.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2003 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 LICENSE 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 @@ -32,67 +32,67 @@ though each operation can be a no-op. */ class IArchTaskBarReceiver : public IInterface { public: - // Icon data is architecture dependent - typedef void* Icon; + // Icon data is architecture dependent + typedef void *Icon; - //! @name manipulators - //@{ + //! @name manipulators + //@{ - //! Show status window - /*! - Open a window displaying current status. This should return - immediately without waiting for the window to be closed. - */ - virtual void showStatus() = 0; + //! Show status window + /*! + Open a window displaying current status. This should return + immediately without waiting for the window to be closed. + */ + virtual void showStatus() = 0; - //! Popup menu - /*! - Popup a menu of operations at or around \c x,y and perform the - chosen operation. - */ - virtual void runMenu(int x, int y) = 0; + //! Popup menu + /*! + Popup a menu of operations at or around \c x,y and perform the + chosen operation. + */ + virtual void runMenu(int x, int y) = 0; - //! Perform primary action - /*! - Perform the primary (default) action. - */ - virtual void primaryAction() = 0; + //! Perform primary action + /*! + Perform the primary (default) action. + */ + virtual void primaryAction() = 0; - //@} - //! @name accessors - //@{ + //@} + //! @name accessors + //@{ - //! Lock receiver - /*! - Locks the receiver from changing state. The receiver should be - locked when querying it's state to ensure consistent results. - Each call to \c lock() must have a matching \c unlock() and - locks cannot be nested. - */ - virtual void lock() const = 0; + //! Lock receiver + /*! + Locks the receiver from changing state. The receiver should be + locked when querying it's state to ensure consistent results. + Each call to \c lock() must have a matching \c unlock() and + locks cannot be nested. + */ + virtual void lock() const = 0; - //! Unlock receiver - virtual void unlock() const = 0; + //! Unlock receiver + virtual void unlock() const = 0; - //! Get icon - /*! - Returns the icon to display in the task bar. The interface - to set the icon is left to subclasses. Getting and setting - the icon must be thread safe. - */ - virtual const Icon getIcon() const = 0; + //! Get icon + /*! + Returns the icon to display in the task bar. The interface + to set the icon is left to subclasses. Getting and setting + the icon must be thread safe. + */ + virtual const Icon getIcon() const = 0; - //! Get tooltip - /*! - Returns the tool tip to display in the task bar. The interface - to set the tooltip is left to sublclasses. Getting and setting - the icon must be thread safe. - */ - virtual std::string getToolTip() const = 0; + //! Get tooltip + /*! + Returns the tool tip to display in the task bar. The interface + to set the tooltip is left to sublclasses. Getting and setting + the icon must be thread safe. + */ + virtual std::string getToolTip() const = 0; - virtual void updateStatus(INode*, const String& errorMsg) = 0; + virtual void updateStatus(INode *, const String &errorMsg) = 0; - virtual void cleanup() {} + virtual void cleanup() {} - //@} + //@} }; diff --git a/src/lib/arch/IArchTime.h b/src/lib/arch/IArchTime.h index e59baf43d..067d54375 100644 --- a/src/lib/arch/IArchTime.h +++ b/src/lib/arch/IArchTime.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -27,15 +27,15 @@ synergy. Each architecture must implement this interface. */ class IArchTime : public IInterface { public: - //! @name manipulators - //@{ + //! @name manipulators + //@{ - //! Get the current time - /*! - Returns the number of seconds since some arbitrary starting time. - This should return as high a precision as reasonable. - */ - virtual double time() = 0; + //! Get the current time + /*! + Returns the number of seconds since some arbitrary starting time. + This should return as high a precision as reasonable. + */ + virtual double time() = 0; - //@} + //@} }; diff --git a/src/lib/arch/XArch.h b/src/lib/arch/XArch.h index 622452701..f838cbec1 100644 --- a/src/lib/arch/XArch.h +++ b/src/lib/arch/XArch.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -19,8 +19,8 @@ #pragma once #include "common/common.h" -#include "common/stdstring.h" #include "common/stdexcept.h" +#include "common/stdstring.h" //! Generic thread exception /*! @@ -28,14 +28,14 @@ Exceptions derived from this class are used by the multithreading library to perform stack unwinding when a thread terminates. These exceptions must always be rethrown by clients when caught. */ -class XThread { }; +class XThread {}; //! Thread exception to cancel /*! Thrown to cancel a thread. Clients must not throw this type, but must rethrow it if caught (by XThreadCancel, XThread, or ...). */ -class XThreadCancel : public XThread { }; +class XThreadCancel : public XThread {}; /*! \def RETHROW_XTHREAD @@ -43,8 +43,13 @@ Convenience macro to rethrow an XThread exception but ignore other exceptions. Put this in your catch (...) handler after necessary cleanup but before leaving or returning from the handler. */ -#define RETHROW_XTHREAD \ - try { throw; } catch (XThread&) { throw; } catch (...) { } +#define RETHROW_XTHREAD \ + try { \ + throw; \ + } catch (XThread &) { \ + throw; \ + } catch (...) { \ + } //! Lazy error message string evaluation /*! @@ -55,27 +60,29 @@ string for that error code. */ class XArchEval { public: - XArchEval() { } - virtual ~XArchEval() _NOEXCEPT { } - - virtual std::string eval() const = 0; + XArchEval() {} + virtual ~XArchEval() _NOEXCEPT {} + + virtual std::string eval() const = 0; }; //! Generic exception architecture dependent library class XArch : public std::runtime_error { public: - XArch(XArchEval* adopted) : std::runtime_error(adopted->eval()) { delete adopted; } - XArch(const std::string& msg) : std::runtime_error(msg) { } - virtual ~XArch() _NOEXCEPT { } + XArch(XArchEval *adopted) : std::runtime_error(adopted->eval()) { + delete adopted; + } + XArch(const std::string &msg) : std::runtime_error(msg) {} + virtual ~XArch() _NOEXCEPT {} }; // Macro to declare XArch derived types -#define XARCH_SUBCLASS(name_, super_) \ -class name_ : public super_ { \ -public: \ - name_(XArchEval* adoptedEvaluator) : super_(adoptedEvaluator) { } \ - name_(const std::string& msg) : super_(msg) { } \ -} +#define XARCH_SUBCLASS(name_, super_) \ + class name_ : public super_ { \ + public: \ + name_(XArchEval *adoptedEvaluator) : super_(adoptedEvaluator) {} \ + name_(const std::string &msg) : super_(msg) {} \ + } //! Generic network exception /*! diff --git a/src/lib/arch/multibyte.h b/src/lib/arch/multibyte.h index 3ab48a3aa..e95dad31f 100644 --- a/src/lib/arch/multibyte.h +++ b/src/lib/arch/multibyte.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -18,39 +18,33 @@ #pragma once -#include "common/common.h" #include "arch/Arch.h" +#include "common/common.h" #include -#include #include +#include #if HAVE_LOCALE_H -# include +#include #endif #if HAVE_WCHAR_H || defined(_MSC_VER) -# include +#include #elif __APPLE__ - // wtf? Darwin puts mbtowc() et al. in stdlib -# include +// wtf? Darwin puts mbtowc() et al. in stdlib +#include #else - // platform apparently has no wchar_t support. provide dummy - // implementations. hopefully at least the C++ compiler has - // a built-in wchar_t type. +// platform apparently has no wchar_t support. provide dummy +// implementations. hopefully at least the C++ compiler has +// a built-in wchar_t type. -static inline -int -mbtowc(wchar_t* dst, const char* src, int n) -{ - *dst = static_cast(*src); - return 1; +static inline int mbtowc(wchar_t *dst, const char *src, int n) { + *dst = static_cast(*src); + return 1; } -static inline -int -wctomb(char* dst, wchar_t src) -{ - *dst = static_cast(src); - return 1; +static inline int wctomb(char *dst, wchar_t src) { + *dst = static_cast(src); + return 1; } #endif diff --git a/src/lib/arch/unix/ArchConsoleUnix.cpp b/src/lib/arch/unix/ArchConsoleUnix.cpp index b5e20223e..13d499f8a 100644 --- a/src/lib/arch/unix/ArchConsoleUnix.cpp +++ b/src/lib/arch/unix/ArchConsoleUnix.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -18,6 +18,6 @@ #include "arch/unix/ArchConsoleUnix.h" -ArchConsoleUnix::ArchConsoleUnix() { } +ArchConsoleUnix::ArchConsoleUnix() {} -ArchConsoleUnix::~ArchConsoleUnix() { } +ArchConsoleUnix::~ArchConsoleUnix() {} diff --git a/src/lib/arch/unix/ArchConsoleUnix.h b/src/lib/arch/unix/ArchConsoleUnix.h index 718c2dc6b..609abbc9e 100644 --- a/src/lib/arch/unix/ArchConsoleUnix.h +++ b/src/lib/arch/unix/ArchConsoleUnix.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -24,6 +24,6 @@ class ArchConsoleUnix : public ArchConsoleStd { public: - ArchConsoleUnix(); - virtual ~ArchConsoleUnix(); + ArchConsoleUnix(); + virtual ~ArchConsoleUnix(); }; diff --git a/src/lib/arch/unix/ArchDaemonUnix.cpp b/src/lib/arch/unix/ArchDaemonUnix.cpp index 9041e1a02..020635ba9 100644 --- a/src/lib/arch/unix/ArchDaemonUnix.cpp +++ b/src/lib/arch/unix/ArchDaemonUnix.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -21,112 +21,103 @@ #include "arch/unix/XArchUnix.h" #include "base/Log.h" -#include -#include -#include -#include -#include #include +#include +#include +#include +#include +#include // // ArchDaemonUnix // -ArchDaemonUnix::ArchDaemonUnix() -{ - // do nothing +ArchDaemonUnix::ArchDaemonUnix() { + // do nothing } -ArchDaemonUnix::~ArchDaemonUnix() -{ - // do nothing +ArchDaemonUnix::~ArchDaemonUnix() { + // do nothing } - #ifdef __APPLE__ // In Mac OS X, fork()'d child processes can't use most APIs (the frameworks // that Synergy uses in fact prevent it and make the process just up and die), // so need to exec a copy of the program that doesn't fork so isn't limited. -int -execSelfNonDaemonized() -{ - extern char** NXArgv; - char** selfArgv = NXArgv; - - setenv("_SYNERGY_DAEMONIZED", "", 1); - - execvp(selfArgv[0], selfArgv); - return 0; +int execSelfNonDaemonized() { + extern char **NXArgv; + char **selfArgv = NXArgv; + + setenv("_SYNERGY_DAEMONIZED", "", 1); + + execvp(selfArgv[0], selfArgv); + return 0; } -bool alreadyDaemonized() { - return getenv("_SYNERGY_DAEMONIZED") != NULL; -} +bool alreadyDaemonized() { return getenv("_SYNERGY_DAEMONIZED") != NULL; } #endif -int -ArchDaemonUnix::daemonize(const char* name, DaemonFunc func) -{ +int ArchDaemonUnix::daemonize(const char *name, DaemonFunc func) { #ifdef __APPLE__ - if (alreadyDaemonized()) - return func(1, &name); -#endif - - // fork so shell thinks we're done and so we're not a process - // group leader - switch (fork()) { - case -1: - // failed - throw XArchDaemonFailed(new XArchEvalUnix(errno)); - - case 0: - // child - break; - - default: - // parent exits - exit(0); - } - - // become leader of a new session - setsid(); - -#ifndef __APPLE__ - // NB: don't run chdir on apple; causes strange behaviour. - // chdir to root so we don't keep mounted filesystems points busy - // TODO: this is a bit of a hack - can we find a better solution? - int chdirErr = chdir("/"); - if (chdirErr) - // NB: file logging actually isn't working at this point! - LOG((CLOG_ERR "chdir error: %i", chdirErr)); -#endif - - // mask off permissions for any but owner - umask(077); - - // close open files. we only expect stdin, stdout, stderr to be open. - close(0); - close(1); - close(2); - - // attach file descriptors 0, 1, 2 to /dev/null so inadvertent use - // of standard I/O safely goes in the bit bucket. - open("/dev/null", O_RDONLY); - open("/dev/null", O_RDWR); - - int dupErr = dup(1); - - if (dupErr < 0) { - // NB: file logging actually isn't working at this point! - LOG((CLOG_ERR "dup error: %i", dupErr)); - } - -#ifdef __APPLE__ - return execSelfNonDaemonized(); -#endif - - // invoke function + if (alreadyDaemonized()) return func(1, &name); +#endif + + // fork so shell thinks we're done and so we're not a process + // group leader + switch (fork()) { + case -1: + // failed + throw XArchDaemonFailed(new XArchEvalUnix(errno)); + + case 0: + // child + break; + + default: + // parent exits + exit(0); + } + + // become leader of a new session + setsid(); + +#ifndef __APPLE__ + // NB: don't run chdir on apple; causes strange behaviour. + // chdir to root so we don't keep mounted filesystems points busy + // TODO: this is a bit of a hack - can we find a better solution? + int chdirErr = chdir("/"); + if (chdirErr) + // NB: file logging actually isn't working at this point! + LOG((CLOG_ERR "chdir error: %i", chdirErr)); +#endif + + // mask off permissions for any but owner + umask(077); + + // close open files. we only expect stdin, stdout, stderr to be open. + close(0); + close(1); + close(2); + + // attach file descriptors 0, 1, 2 to /dev/null so inadvertent use + // of standard I/O safely goes in the bit bucket. + open("/dev/null", O_RDONLY); + open("/dev/null", O_RDWR); + + int dupErr = dup(1); + + if (dupErr < 0) { + // NB: file logging actually isn't working at this point! + LOG((CLOG_ERR "dup error: %i", dupErr)); + } + +#ifdef __APPLE__ + return execSelfNonDaemonized(); +#endif + + // invoke function + return func(1, &name); } diff --git a/src/lib/arch/unix/ArchDaemonUnix.h b/src/lib/arch/unix/ArchDaemonUnix.h index 0098a090b..6622fff82 100644 --- a/src/lib/arch/unix/ArchDaemonUnix.h +++ b/src/lib/arch/unix/ArchDaemonUnix.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -26,11 +26,11 @@ //! Unix implementation of IArchDaemon class ArchDaemonUnix : public ArchDaemonNone { public: - ArchDaemonUnix(); - virtual ~ArchDaemonUnix(); + ArchDaemonUnix(); + virtual ~ArchDaemonUnix(); - // IArchDaemon overrides - virtual int daemonize(const char* name, DaemonFunc func); + // IArchDaemon overrides + virtual int daemonize(const char *name, DaemonFunc func); }; #define CONFIG_FILE "/etc/synergy/synergyd.conf" diff --git a/src/lib/arch/unix/ArchFileUnix.cpp b/src/lib/arch/unix/ArchFileUnix.cpp index bbf841640..9167a8480 100644 --- a/src/lib/arch/unix/ArchFileUnix.cpp +++ b/src/lib/arch/unix/ArchFileUnix.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -18,146 +18,117 @@ #include "arch/unix/ArchFileUnix.h" -#include -#include -#include -#include #include +#include +#include +#include +#include // // ArchFileUnix // -ArchFileUnix::ArchFileUnix() -{ - // do nothing +ArchFileUnix::ArchFileUnix() { + // do nothing } -ArchFileUnix::~ArchFileUnix() -{ - // do nothing +ArchFileUnix::~ArchFileUnix() { + // do nothing } -const char* -ArchFileUnix::getBasename(const char* pathname) -{ - if (pathname == NULL) { - return NULL; - } +const char *ArchFileUnix::getBasename(const char *pathname) { + if (pathname == NULL) { + return NULL; + } - const char* basename = strrchr(pathname, '/'); - if (basename != NULL) { - return basename + 1; - } - else { - return pathname; - } + const char *basename = strrchr(pathname, '/'); + if (basename != NULL) { + return basename + 1; + } else { + return pathname; + } } -std::string -ArchFileUnix::getUserDirectory() -{ - char* buffer = NULL; - std::string dir; +std::string ArchFileUnix::getUserDirectory() { + char *buffer = NULL; + std::string dir; #if HAVE_GETPWUID_R - struct passwd pwent; - struct passwd* pwentp {}; + struct passwd pwent; + struct passwd *pwentp{}; #if defined(_SC_GETPW_R_SIZE_MAX) - long size = sysconf(_SC_GETPW_R_SIZE_MAX); - if (size == -1) { - size = BUFSIZ; - } + long size = sysconf(_SC_GETPW_R_SIZE_MAX); + if (size == -1) { + size = BUFSIZ; + } #else - long size = BUFSIZ; + long size = BUFSIZ; #endif - buffer = new char[size]; - getpwuid_r(getuid(), &pwent, buffer, size, &pwentp); + buffer = new char[size]; + getpwuid_r(getuid(), &pwent, buffer, size, &pwentp); #else - struct passwd* pwentp = getpwuid(getuid()); + struct passwd *pwentp = getpwuid(getuid()); #endif - if (pwentp != NULL && pwentp->pw_dir != NULL) { - dir = pwentp->pw_dir; - } - delete[] buffer; - return dir; + if (pwentp != NULL && pwentp->pw_dir != NULL) { + dir = pwentp->pw_dir; + } + delete[] buffer; + return dir; } -std::string -ArchFileUnix::getSystemDirectory() -{ - return "/etc"; -} +std::string ArchFileUnix::getSystemDirectory() { return "/etc"; } -std::string -ArchFileUnix::getInstalledDirectory() -{ +std::string ArchFileUnix::getInstalledDirectory() { #if WINAPI_XWINDOWS - return "/usr/bin"; + return "/usr/bin"; #else - return "/Applications/Synergy.app/Contents/MacOS"; + return "/Applications/Synergy.app/Contents/MacOS"; #endif } -std::string -ArchFileUnix::getLogDirectory() -{ - return "/var/log"; -} +std::string ArchFileUnix::getLogDirectory() { return "/var/log"; } -std::string -ArchFileUnix::getPluginDirectory() -{ - if (!m_pluginDirectory.empty()) { - return m_pluginDirectory; - } +std::string ArchFileUnix::getPluginDirectory() { + if (!m_pluginDirectory.empty()) { + return m_pluginDirectory; + } #if WINAPI_XWINDOWS - return getProfileDirectory().append("/plugins"); + return getProfileDirectory().append("/plugins"); #else - return getProfileDirectory().append("/Plugins"); + return getProfileDirectory().append("/Plugins"); #endif } -std::string -ArchFileUnix::getProfileDirectory() -{ - String dir; - if (!m_profileDirectory.empty()) { - dir = m_profileDirectory; - } - else { +std::string ArchFileUnix::getProfileDirectory() { + String dir; + if (!m_profileDirectory.empty()) { + dir = m_profileDirectory; + } else { #if WINAPI_XWINDOWS - dir = getUserDirectory().append("/.synergy"); + dir = getUserDirectory().append("/.synergy"); #else - dir = getUserDirectory().append("/Library/Synergy"); + dir = getUserDirectory().append("/Library/Synergy"); #endif - } - return dir; - + } + return dir; } -std::string -ArchFileUnix::concatPath(const std::string& prefix, - const std::string& suffix) -{ - std::string path; - path.reserve(prefix.size() + 1 + suffix.size()); - path += prefix; - if (path.size() == 0 || path[path.size() - 1] != '/') { - path += '/'; - } - path += suffix; - return path; +std::string ArchFileUnix::concatPath(const std::string &prefix, + const std::string &suffix) { + std::string path; + path.reserve(prefix.size() + 1 + suffix.size()); + path += prefix; + if (path.size() == 0 || path[path.size() - 1] != '/') { + path += '/'; + } + path += suffix; + return path; } -void -ArchFileUnix::setProfileDirectory(const String& s) -{ - m_profileDirectory = s; +void ArchFileUnix::setProfileDirectory(const String &s) { + m_profileDirectory = s; } -void -ArchFileUnix::setPluginDirectory(const String& s) -{ - m_pluginDirectory = s; +void ArchFileUnix::setPluginDirectory(const String &s) { + m_pluginDirectory = s; } diff --git a/src/lib/arch/unix/ArchFileUnix.h b/src/lib/arch/unix/ArchFileUnix.h index fe58f8029..8c5938989 100644 --- a/src/lib/arch/unix/ArchFileUnix.h +++ b/src/lib/arch/unix/ArchFileUnix.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -25,23 +25,23 @@ //! Unix implementation of IArchFile class ArchFileUnix : public IArchFile { public: - ArchFileUnix(); - virtual ~ArchFileUnix(); + ArchFileUnix(); + virtual ~ArchFileUnix(); - // IArchFile overrides - virtual const char* getBasename(const char* pathname); - virtual std::string getUserDirectory(); - virtual std::string getSystemDirectory(); - virtual std::string getInstalledDirectory(); - virtual std::string getLogDirectory(); - virtual std::string getPluginDirectory(); - virtual std::string getProfileDirectory(); - virtual std::string concatPath(const std::string& prefix, - const std::string& suffix); - virtual void setProfileDirectory(const String& s); - virtual void setPluginDirectory(const String& s); + // IArchFile overrides + virtual const char *getBasename(const char *pathname); + virtual std::string getUserDirectory(); + virtual std::string getSystemDirectory(); + virtual std::string getInstalledDirectory(); + virtual std::string getLogDirectory(); + virtual std::string getPluginDirectory(); + virtual std::string getProfileDirectory(); + virtual std::string concatPath(const std::string &prefix, + const std::string &suffix); + virtual void setProfileDirectory(const String &s); + virtual void setPluginDirectory(const String &s); private: - String m_profileDirectory; - String m_pluginDirectory; + String m_profileDirectory; + String m_pluginDirectory; }; diff --git a/src/lib/arch/unix/ArchLogUnix.cpp b/src/lib/arch/unix/ArchLogUnix.cpp index 070e02722..4ea3f0e4d 100644 --- a/src/lib/arch/unix/ArchLogUnix.cpp +++ b/src/lib/arch/unix/ArchLogUnix.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -24,61 +24,47 @@ // ArchLogUnix // -ArchLogUnix::ArchLogUnix() -{ - // do nothing +ArchLogUnix::ArchLogUnix() { + // do nothing } -ArchLogUnix::~ArchLogUnix() -{ - // do nothing +ArchLogUnix::~ArchLogUnix() { + // do nothing } -void -ArchLogUnix::openLog(const char* name) -{ - openlog(name, 0, LOG_DAEMON); +void ArchLogUnix::openLog(const char *name) { openlog(name, 0, LOG_DAEMON); } + +void ArchLogUnix::closeLog() { closelog(); } + +void ArchLogUnix::showLog(bool) { + // do nothing } -void -ArchLogUnix::closeLog() -{ - closelog(); -} - -void -ArchLogUnix::showLog(bool) -{ - // do nothing -} - -void -ArchLogUnix::writeLog(ELevel level, const char* msg) -{ - // convert level - int priority; - switch (level) { - case kERROR: - priority = LOG_ERR; - break; - - case kWARNING: - priority = LOG_WARNING; - break; - - case kNOTE: - priority = LOG_NOTICE; - break; - - case kINFO: - priority = LOG_INFO; - break; - - default: - priority = LOG_DEBUG; - break; - } - - // log it - syslog(priority, "%s", msg); +void ArchLogUnix::writeLog(ELevel level, const char *msg) { + // convert level + int priority; + switch (level) { + case kERROR: + priority = LOG_ERR; + break; + + case kWARNING: + priority = LOG_WARNING; + break; + + case kNOTE: + priority = LOG_NOTICE; + break; + + case kINFO: + priority = LOG_INFO; + break; + + default: + priority = LOG_DEBUG; + break; + } + + // log it + syslog(priority, "%s", msg); } diff --git a/src/lib/arch/unix/ArchLogUnix.h b/src/lib/arch/unix/ArchLogUnix.h index 08f04fd49..0742e4026 100644 --- a/src/lib/arch/unix/ArchLogUnix.h +++ b/src/lib/arch/unix/ArchLogUnix.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -25,12 +25,12 @@ //! Unix implementation of IArchLog class ArchLogUnix : public IArchLog { public: - ArchLogUnix(); - virtual ~ArchLogUnix(); + ArchLogUnix(); + virtual ~ArchLogUnix(); - // IArchLog overrides - virtual void openLog(const char* name); - virtual void closeLog(); - virtual void showLog(bool); - virtual void writeLog(ELevel, const char*); + // IArchLog overrides + virtual void openLog(const char *name); + virtual void closeLog(); + virtual void showLog(bool); + virtual void writeLog(ELevel, const char *); }; diff --git a/src/lib/arch/unix/ArchMultithreadPosix.cpp b/src/lib/arch/unix/ArchMultithreadPosix.cpp index 958a19cdf..da9aa397a 100644 --- a/src/lib/arch/unix/ArchMultithreadPosix.cpp +++ b/src/lib/arch/unix/ArchMultithreadPosix.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -23,39 +23,36 @@ #include #if TIME_WITH_SYS_TIME -# include -# include +#include +#include #else -# if HAVE_SYS_TIME_H -# include -# else -# include -# endif +#if HAVE_SYS_TIME_H +#include +#else +#include +#endif #endif #include #define SIGWAKEUP SIGUSR1 #if !HAVE_PTHREAD_SIGNAL - // boy, is this platform broken. forget about pthread signal - // handling and let signals through to every process. synergy - // will not terminate cleanly when it gets SIGTERM or SIGINT. -# define pthread_sigmask sigprocmask -# define pthread_kill(tid_, sig_) kill(0, (sig_)) -# define sigwait(set_, sig_) -# undef HAVE_POSIX_SIGWAIT -# define HAVE_POSIX_SIGWAIT 1 +// boy, is this platform broken. forget about pthread signal +// handling and let signals through to every process. synergy +// will not terminate cleanly when it gets SIGTERM or SIGINT. +#define pthread_sigmask sigprocmask +#define pthread_kill(tid_, sig_) kill(0, (sig_)) +#define sigwait(set_, sig_) +#undef HAVE_POSIX_SIGWAIT +#define HAVE_POSIX_SIGWAIT 1 #endif -static -void -setSignalSet(sigset_t* sigset) -{ - sigemptyset(sigset); - sigaddset(sigset, SIGHUP); - sigaddset(sigset, SIGINT); - sigaddset(sigset, SIGTERM); - sigaddset(sigset, SIGUSR2); +static void setSignalSet(sigset_t *sigset) { + sigemptyset(sigset); + sigaddset(sigset, SIGHUP); + sigaddset(sigset, SIGINT); + sigaddset(sigset, SIGTERM); + sigaddset(sigset, SIGUSR2); } // @@ -64,751 +61,661 @@ setSignalSet(sigset_t* sigset) class ArchThreadImpl { public: - ArchThreadImpl(); + ArchThreadImpl(); public: - int m_refCount; - IArchMultithread::ThreadID m_id; - pthread_t m_thread; - IArchMultithread::ThreadFunc m_func; - void* m_userData; - bool m_cancel; - bool m_cancelling; - bool m_exited; - void* m_result; - void* m_networkData; + int m_refCount; + IArchMultithread::ThreadID m_id; + pthread_t m_thread; + IArchMultithread::ThreadFunc m_func; + void *m_userData; + bool m_cancel; + bool m_cancelling; + bool m_exited; + void *m_result; + void *m_networkData; }; -ArchThreadImpl::ArchThreadImpl() : - m_refCount(1), - m_id(0), - m_func(NULL), - m_userData(NULL), - m_cancel(false), - m_cancelling(false), - m_exited(false), - m_result(NULL), - m_networkData(NULL) -{ - // do nothing +ArchThreadImpl::ArchThreadImpl() + : m_refCount(1), m_id(0), m_func(NULL), m_userData(NULL), m_cancel(false), + m_cancelling(false), m_exited(false), m_result(NULL), + m_networkData(NULL) { + // do nothing } - // // ArchMultithreadPosix // -ArchMultithreadPosix* ArchMultithreadPosix::s_instance = NULL; +ArchMultithreadPosix *ArchMultithreadPosix::s_instance = NULL; -ArchMultithreadPosix::ArchMultithreadPosix() : - m_newThreadCalled(false), - m_nextID(0) -{ - assert(s_instance == NULL); +ArchMultithreadPosix::ArchMultithreadPosix() + : m_newThreadCalled(false), m_nextID(0) { + assert(s_instance == NULL); - s_instance = this; + s_instance = this; - // no signal handlers - for (size_t i = 0; i < kNUM_SIGNALS; ++i) { - m_signalFunc[i] = NULL; - m_signalUserData[i] = NULL; - } + // no signal handlers + for (size_t i = 0; i < kNUM_SIGNALS; ++i) { + m_signalFunc[i] = NULL; + m_signalUserData[i] = NULL; + } - // create mutex for thread list - m_threadMutex = newMutex(); + // create mutex for thread list + m_threadMutex = newMutex(); - // create thread for calling (main) thread and add it to our - // list. no need to lock the mutex since we're the only thread. - m_mainThread = new ArchThreadImpl; - m_mainThread->m_thread = pthread_self(); - insert(m_mainThread); + // create thread for calling (main) thread and add it to our + // list. no need to lock the mutex since we're the only thread. + m_mainThread = new ArchThreadImpl; + m_mainThread->m_thread = pthread_self(); + insert(m_mainThread); - // install SIGWAKEUP handler. this causes SIGWAKEUP to interrupt - // system calls. we use that when cancelling a thread to force it - // to wake up immediately if it's blocked in a system call. we - // won't need this until another thread is created but it's fine - // to install it now. - struct sigaction act; - sigemptyset(&act.sa_mask); -# if defined(SA_INTERRUPT) - act.sa_flags = SA_INTERRUPT; -# else - act.sa_flags = 0; -# endif - act.sa_handler = &threadCancel; - sigaction(SIGWAKEUP, &act, NULL); - - // set desired signal dispositions. let SIGWAKEUP through but - // ignore SIGPIPE (we'll handle EPIPE). - sigset_t sigset; - sigemptyset(&sigset); - sigaddset(&sigset, SIGWAKEUP); - pthread_sigmask(SIG_UNBLOCK, &sigset, NULL); - sigemptyset(&sigset); - sigaddset(&sigset, SIGPIPE); - pthread_sigmask(SIG_BLOCK, &sigset, NULL); -} - -ArchMultithreadPosix::~ArchMultithreadPosix() -{ - assert(s_instance != NULL); - - closeMutex(m_threadMutex); - s_instance = NULL; -} - -void -ArchMultithreadPosix::setNetworkDataForCurrentThread(void* data) -{ - lockMutex(m_threadMutex); - ArchThreadImpl* thread = find(pthread_self()); - thread->m_networkData = data; - unlockMutex(m_threadMutex); -} - -void* -ArchMultithreadPosix::getNetworkDataForThread(ArchThread thread) -{ - lockMutex(m_threadMutex); - void* data = thread->m_networkData; - unlockMutex(m_threadMutex); - return data; -} - -ArchMultithreadPosix* -ArchMultithreadPosix::getInstance() -{ - return s_instance; -} - -ArchCond -ArchMultithreadPosix::newCondVar() -{ - ArchCondImpl* cond = new ArchCondImpl; - int status = pthread_cond_init(&cond->m_cond, NULL); - (void)status; - assert(status == 0); - return cond; -} - -void -ArchMultithreadPosix::closeCondVar(ArchCond cond) -{ - int status = pthread_cond_destroy(&cond->m_cond); - (void)status; - assert(status == 0); - delete cond; -} - -void -ArchMultithreadPosix::signalCondVar(ArchCond cond) -{ - int status = pthread_cond_signal(&cond->m_cond); - (void)status; - assert(status == 0); -} - -void -ArchMultithreadPosix::broadcastCondVar(ArchCond cond) -{ - int status = pthread_cond_broadcast(&cond->m_cond); - (void)status; - assert(status == 0); -} - -bool -ArchMultithreadPosix::waitCondVar(ArchCond cond, - ArchMutex mutex, double timeout) -{ - // we can't wait on a condition variable and also wake it up for - // cancellation since we don't use posix cancellation. so we - // must wake up periodically to check for cancellation. we - // can't simply go back to waiting after the check since the - // condition may have changed and we'll have lost the signal. - // so we have to return to the caller. since the caller will - // always check for spurious wakeups the only drawback here is - // performance: we're waking up a lot more than desired. - static const double maxCancellationLatency = 0.1; - if (timeout < 0.0 || timeout > maxCancellationLatency) { - timeout = maxCancellationLatency; - } - - // see if we should cancel this thread - testCancelThread(); - - // get final time - struct timeval now; - gettimeofday(&now, NULL); - struct timespec finalTime; - finalTime.tv_sec = now.tv_sec; - finalTime.tv_nsec = now.tv_usec * 1000; - long timeout_sec = (long)timeout; - long timeout_nsec = (long)(1.0e+9 * (timeout - timeout_sec)); - finalTime.tv_sec += timeout_sec; - finalTime.tv_nsec += timeout_nsec; - if (finalTime.tv_nsec >= 1000000000) { - finalTime.tv_nsec -= 1000000000; - finalTime.tv_sec += 1; - } - - // wait - int status = pthread_cond_timedwait(&cond->m_cond, - &mutex->m_mutex, &finalTime); - - // check for cancel again - testCancelThread(); - - switch (status) { - case 0: - // success - return true; - - case ETIMEDOUT: - return false; - - default: - assert(0 && "condition variable wait error"); - return false; - } -} - -ArchMutex -ArchMultithreadPosix::newMutex() -{ - pthread_mutexattr_t attr; - int status = pthread_mutexattr_init(&attr); - assert(status == 0); - ArchMutexImpl* mutex = new ArchMutexImpl; - status = pthread_mutex_init(&mutex->m_mutex, &attr); - assert(status == 0); - return mutex; -} - -void -ArchMultithreadPosix::closeMutex(ArchMutex mutex) -{ - int status = pthread_mutex_destroy(&mutex->m_mutex); - (void)status; - assert(status == 0); - delete mutex; -} - -void -ArchMultithreadPosix::lockMutex(ArchMutex mutex) -{ - int status = pthread_mutex_lock(&mutex->m_mutex); - - switch (status) { - case 0: - // success - return; - - case EDEADLK: - assert(0 && "lock already owned"); - break; - - case EAGAIN: - assert(0 && "too many recursive locks"); - break; - - default: - assert(0 && "unexpected error"); - break; - } -} - -void -ArchMultithreadPosix::unlockMutex(ArchMutex mutex) -{ - int status = pthread_mutex_unlock(&mutex->m_mutex); - - switch (status) { - case 0: - // success - return; - - case EPERM: - assert(0 && "thread doesn't own a lock"); - break; - - default: - assert(0 && "unexpected error"); - break; - } -} - -ArchThread -ArchMultithreadPosix::newThread(ThreadFunc func, void* data) -{ - assert(func != NULL); - - // initialize signal handler. we do this here instead of the - // constructor so we can avoid daemonizing (using fork()) - // when there are multiple threads. clients can safely - // use condition variables and mutexes before creating a - // new thread and they can safely use the only thread - // they have access to, the main thread, so they really - // can't tell the difference. - if (!m_newThreadCalled) { - m_newThreadCalled = true; -#if HAVE_PTHREAD_SIGNAL - startSignalHandler(); + // install SIGWAKEUP handler. this causes SIGWAKEUP to interrupt + // system calls. we use that when cancelling a thread to force it + // to wake up immediately if it's blocked in a system call. we + // won't need this until another thread is created but it's fine + // to install it now. + struct sigaction act; + sigemptyset(&act.sa_mask); +#if defined(SA_INTERRUPT) + act.sa_flags = SA_INTERRUPT; +#else + act.sa_flags = 0; #endif - } + act.sa_handler = &threadCancel; + sigaction(SIGWAKEUP, &act, NULL); - lockMutex(m_threadMutex); + // set desired signal dispositions. let SIGWAKEUP through but + // ignore SIGPIPE (we'll handle EPIPE). + sigset_t sigset; + sigemptyset(&sigset); + sigaddset(&sigset, SIGWAKEUP); + pthread_sigmask(SIG_UNBLOCK, &sigset, NULL); + sigemptyset(&sigset); + sigaddset(&sigset, SIGPIPE); + pthread_sigmask(SIG_BLOCK, &sigset, NULL); +} - // create thread impl for new thread - ArchThreadImpl* thread = new ArchThreadImpl; - thread->m_func = func; - thread->m_userData = data; +ArchMultithreadPosix::~ArchMultithreadPosix() { + assert(s_instance != NULL); - // create the thread. pthread_create() on RedHat 7.2 smp fails - // if passed a NULL attr so use a default attr. - pthread_attr_t attr; - int status = pthread_attr_init(&attr); - if (status == 0) { - status = pthread_create(&thread->m_thread, &attr, + closeMutex(m_threadMutex); + s_instance = NULL; +} + +void ArchMultithreadPosix::setNetworkDataForCurrentThread(void *data) { + lockMutex(m_threadMutex); + ArchThreadImpl *thread = find(pthread_self()); + thread->m_networkData = data; + unlockMutex(m_threadMutex); +} + +void *ArchMultithreadPosix::getNetworkDataForThread(ArchThread thread) { + lockMutex(m_threadMutex); + void *data = thread->m_networkData; + unlockMutex(m_threadMutex); + return data; +} + +ArchMultithreadPosix *ArchMultithreadPosix::getInstance() { return s_instance; } + +ArchCond ArchMultithreadPosix::newCondVar() { + ArchCondImpl *cond = new ArchCondImpl; + int status = pthread_cond_init(&cond->m_cond, NULL); + (void)status; + assert(status == 0); + return cond; +} + +void ArchMultithreadPosix::closeCondVar(ArchCond cond) { + int status = pthread_cond_destroy(&cond->m_cond); + (void)status; + assert(status == 0); + delete cond; +} + +void ArchMultithreadPosix::signalCondVar(ArchCond cond) { + int status = pthread_cond_signal(&cond->m_cond); + (void)status; + assert(status == 0); +} + +void ArchMultithreadPosix::broadcastCondVar(ArchCond cond) { + int status = pthread_cond_broadcast(&cond->m_cond); + (void)status; + assert(status == 0); +} + +bool ArchMultithreadPosix::waitCondVar(ArchCond cond, ArchMutex mutex, + double timeout) { + // we can't wait on a condition variable and also wake it up for + // cancellation since we don't use posix cancellation. so we + // must wake up periodically to check for cancellation. we + // can't simply go back to waiting after the check since the + // condition may have changed and we'll have lost the signal. + // so we have to return to the caller. since the caller will + // always check for spurious wakeups the only drawback here is + // performance: we're waking up a lot more than desired. + static const double maxCancellationLatency = 0.1; + if (timeout < 0.0 || timeout > maxCancellationLatency) { + timeout = maxCancellationLatency; + } + + // see if we should cancel this thread + testCancelThread(); + + // get final time + struct timeval now; + gettimeofday(&now, NULL); + struct timespec finalTime; + finalTime.tv_sec = now.tv_sec; + finalTime.tv_nsec = now.tv_usec * 1000; + long timeout_sec = (long)timeout; + long timeout_nsec = (long)(1.0e+9 * (timeout - timeout_sec)); + finalTime.tv_sec += timeout_sec; + finalTime.tv_nsec += timeout_nsec; + if (finalTime.tv_nsec >= 1000000000) { + finalTime.tv_nsec -= 1000000000; + finalTime.tv_sec += 1; + } + + // wait + int status = + pthread_cond_timedwait(&cond->m_cond, &mutex->m_mutex, &finalTime); + + // check for cancel again + testCancelThread(); + + switch (status) { + case 0: + // success + return true; + + case ETIMEDOUT: + return false; + + default: + assert(0 && "condition variable wait error"); + return false; + } +} + +ArchMutex ArchMultithreadPosix::newMutex() { + pthread_mutexattr_t attr; + int status = pthread_mutexattr_init(&attr); + assert(status == 0); + ArchMutexImpl *mutex = new ArchMutexImpl; + status = pthread_mutex_init(&mutex->m_mutex, &attr); + assert(status == 0); + return mutex; +} + +void ArchMultithreadPosix::closeMutex(ArchMutex mutex) { + int status = pthread_mutex_destroy(&mutex->m_mutex); + (void)status; + assert(status == 0); + delete mutex; +} + +void ArchMultithreadPosix::lockMutex(ArchMutex mutex) { + int status = pthread_mutex_lock(&mutex->m_mutex); + + switch (status) { + case 0: + // success + return; + + case EDEADLK: + assert(0 && "lock already owned"); + break; + + case EAGAIN: + assert(0 && "too many recursive locks"); + break; + + default: + assert(0 && "unexpected error"); + break; + } +} + +void ArchMultithreadPosix::unlockMutex(ArchMutex mutex) { + int status = pthread_mutex_unlock(&mutex->m_mutex); + + switch (status) { + case 0: + // success + return; + + case EPERM: + assert(0 && "thread doesn't own a lock"); + break; + + default: + assert(0 && "unexpected error"); + break; + } +} + +ArchThread ArchMultithreadPosix::newThread(ThreadFunc func, void *data) { + assert(func != NULL); + + // initialize signal handler. we do this here instead of the + // constructor so we can avoid daemonizing (using fork()) + // when there are multiple threads. clients can safely + // use condition variables and mutexes before creating a + // new thread and they can safely use the only thread + // they have access to, the main thread, so they really + // can't tell the difference. + if (!m_newThreadCalled) { + m_newThreadCalled = true; +#if HAVE_PTHREAD_SIGNAL + startSignalHandler(); +#endif + } + + lockMutex(m_threadMutex); + + // create thread impl for new thread + ArchThreadImpl *thread = new ArchThreadImpl; + thread->m_func = func; + thread->m_userData = data; + + // create the thread. pthread_create() on RedHat 7.2 smp fails + // if passed a NULL attr so use a default attr. + pthread_attr_t attr; + int status = pthread_attr_init(&attr); + if (status == 0) { + status = pthread_create(&thread->m_thread, &attr, &ArchMultithreadPosix::threadFunc, thread); - pthread_attr_destroy(&attr); - } + pthread_attr_destroy(&attr); + } - // check if thread was started - if (status != 0) { - // failed to start thread so clean up - delete thread; - thread = NULL; - } - else { - // add thread to list - insert(thread); + // check if thread was started + if (status != 0) { + // failed to start thread so clean up + delete thread; + thread = NULL; + } else { + // add thread to list + insert(thread); - // increment ref count to account for the thread itself - refThread(thread); - } - - // note that the child thread will wait until we release this mutex - unlockMutex(m_threadMutex); - - return thread; -} - -ArchThread -ArchMultithreadPosix::newCurrentThread() -{ - lockMutex(m_threadMutex); - ArchThreadImpl* thread = find(pthread_self()); - unlockMutex(m_threadMutex); - assert(thread != NULL); - return thread; -} - -void -ArchMultithreadPosix::closeThread(ArchThread thread) -{ - assert(thread != NULL); - - // decrement ref count and clean up thread if no more references - if (--thread->m_refCount == 0) { - // detach from thread (unless it's the main thread) - if (thread->m_func != NULL) { - pthread_detach(thread->m_thread); - } - - // remove thread from list - lockMutex(m_threadMutex); - assert(findNoRef(thread->m_thread) == thread); - erase(thread); - unlockMutex(m_threadMutex); - - // done with thread - delete thread; - } -} - -ArchThread -ArchMultithreadPosix::copyThread(ArchThread thread) -{ + // increment ref count to account for the thread itself refThread(thread); - return thread; + } + + // note that the child thread will wait until we release this mutex + unlockMutex(m_threadMutex); + + return thread; } -void -ArchMultithreadPosix::cancelThread(ArchThread thread) -{ - assert(thread != NULL); +ArchThread ArchMultithreadPosix::newCurrentThread() { + lockMutex(m_threadMutex); + ArchThreadImpl *thread = find(pthread_self()); + unlockMutex(m_threadMutex); + assert(thread != NULL); + return thread; +} - // set cancel and wakeup flags if thread can be cancelled - bool wakeup = false; +void ArchMultithreadPosix::closeThread(ArchThread thread) { + assert(thread != NULL); + + // decrement ref count and clean up thread if no more references + if (--thread->m_refCount == 0) { + // detach from thread (unless it's the main thread) + if (thread->m_func != NULL) { + pthread_detach(thread->m_thread); + } + + // remove thread from list lockMutex(m_threadMutex); - if (!thread->m_exited && !thread->m_cancelling) { - thread->m_cancel = true; - wakeup = true; - } - unlockMutex(m_threadMutex); - - // force thread to exit system calls if wakeup is true - if (wakeup) { - pthread_kill(thread->m_thread, SIGWAKEUP); - } -} - -void -ArchMultithreadPosix::setPriorityOfThread(ArchThread thread, int /*n*/) -{ - assert(thread != NULL); - - // FIXME -} - -void -ArchMultithreadPosix::testCancelThread() -{ - // find current thread - lockMutex(m_threadMutex); - ArchThreadImpl* thread = findNoRef(pthread_self()); - unlockMutex(m_threadMutex); - - // test cancel on thread - testCancelThreadImpl(thread); -} - -bool -ArchMultithreadPosix::wait(ArchThread target, double timeout) -{ - assert(target != NULL); - - lockMutex(m_threadMutex); - - // find current thread - ArchThreadImpl* self = findNoRef(pthread_self()); - - // ignore wait if trying to wait on ourself - if (target == self) { - unlockMutex(m_threadMutex); - return false; - } - - // ref the target so it can't go away while we're watching it - refThread(target); - - unlockMutex(m_threadMutex); - - try { - // do first test regardless of timeout - testCancelThreadImpl(self); - if (isExitedThread(target)) { - closeThread(target); - return true; - } - - // wait and repeat test if there's a timeout - if (timeout != 0.0) { - const double start = ARCH->time(); - do { - // wait a little - ARCH->sleep(0.05); - - // repeat test - testCancelThreadImpl(self); - if (isExitedThread(target)) { - closeThread(target); - return true; - } - - // repeat wait and test until timed out - } while (timeout < 0.0 || (ARCH->time() - start) <= timeout); - } - - closeThread(target); - return false; - } - catch (...) { - closeThread(target); - throw; - } -} - -bool -ArchMultithreadPosix::isSameThread(ArchThread thread1, ArchThread thread2) -{ - return (thread1 == thread2); -} - -bool -ArchMultithreadPosix::isExitedThread(ArchThread thread) -{ - lockMutex(m_threadMutex); - bool exited = thread->m_exited; - unlockMutex(m_threadMutex); - return exited; -} - -void* -ArchMultithreadPosix::getResultOfThread(ArchThread thread) -{ - lockMutex(m_threadMutex); - void* result = thread->m_result; - unlockMutex(m_threadMutex); - return result; -} - -IArchMultithread::ThreadID -ArchMultithreadPosix::getIDOfThread(ArchThread thread) -{ - return thread->m_id; -} - -void -ArchMultithreadPosix::setSignalHandler( - ESignal signal, SignalFunc func, void* userData) -{ - lockMutex(m_threadMutex); - m_signalFunc[signal] = func; - m_signalUserData[signal] = userData; - unlockMutex(m_threadMutex); -} - -void -ArchMultithreadPosix::raiseSignal(ESignal signal) -{ - lockMutex(m_threadMutex); - if (m_signalFunc[signal] != NULL) { - m_signalFunc[signal](signal, m_signalUserData[signal]); - pthread_kill(m_mainThread->m_thread, SIGWAKEUP); - } - else if (signal == kINTERRUPT || signal == kTERMINATE) { - ARCH->cancelThread(m_mainThread); - } - unlockMutex(m_threadMutex); -} - -void -ArchMultithreadPosix::startSignalHandler() -{ - // set signal mask. the main thread blocks these signals and - // the signal handler thread will listen for them. - sigset_t sigset, oldsigset; - setSignalSet(&sigset); - pthread_sigmask(SIG_BLOCK, &sigset, &oldsigset); - - // fire up the INT and TERM signal handler thread. we could - // instead arrange to catch and handle these signals but - // we'd be unable to cancel the main thread since no pthread - // calls are allowed in a signal handler. - pthread_attr_t attr; - int status = pthread_attr_init(&attr); - if (status == 0) { - status = pthread_create(&m_signalThread, &attr, - &ArchMultithreadPosix::threadSignalHandler, - NULL); - pthread_attr_destroy(&attr); - } - if (status != 0) { - // can't create thread to wait for signal so don't block - // the signals. - pthread_sigmask(SIG_UNBLOCK, &oldsigset, NULL); - } -} - -ArchThreadImpl* -ArchMultithreadPosix::find(pthread_t thread) -{ - ArchThreadImpl* impl = findNoRef(thread); - if (impl != NULL) { - refThread(impl); - } - return impl; -} - -ArchThreadImpl* -ArchMultithreadPosix::findNoRef(pthread_t thread) -{ - // linear search - for (ThreadList::const_iterator index = m_threadList.begin(); - index != m_threadList.end(); ++index) { - if ((*index)->m_thread == thread) { - return *index; - } - } - return NULL; -} - -void -ArchMultithreadPosix::insert(ArchThreadImpl* thread) -{ - assert(thread != NULL); - - // thread shouldn't already be on the list - assert(findNoRef(thread->m_thread) == NULL); - - // set thread id. note that we don't worry about m_nextID - // wrapping back to 0 and duplicating thread ID's since the - // likelihood of synergy running that long is vanishingly - // small. - thread->m_id = ++m_nextID; - - // append to list - m_threadList.push_back(thread); -} - -void -ArchMultithreadPosix::erase(ArchThreadImpl* thread) -{ - for (ThreadList::iterator index = m_threadList.begin(); - index != m_threadList.end(); ++index) { - if (*index == thread) { - m_threadList.erase(index); - break; - } - } -} - -void -ArchMultithreadPosix::refThread(ArchThreadImpl* thread) -{ - assert(thread != NULL); - assert(findNoRef(thread->m_thread) != NULL); - ++thread->m_refCount; -} - -void -ArchMultithreadPosix::testCancelThreadImpl(ArchThreadImpl* thread) -{ - assert(thread != NULL); - - // update cancel state - lockMutex(m_threadMutex); - bool cancel = false; - if (thread->m_cancel && !thread->m_cancelling) { - thread->m_cancelling = true; - thread->m_cancel = false; - cancel = true; - } - unlockMutex(m_threadMutex); - - // unwind thread's stack if cancelling - if (cancel) { - throw XThreadCancel(); - } -} - -void* -ArchMultithreadPosix::threadFunc(void* vrep) -{ - // get the thread - ArchThreadImpl* thread = static_cast(vrep); - - // setup pthreads - pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); - pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL); - - // run thread - s_instance->doThreadFunc(thread); - - // terminate the thread - return NULL; -} - -void -ArchMultithreadPosix::doThreadFunc(ArchThread thread) -{ - // default priority is slightly below normal - setPriorityOfThread(thread, 1); - - // wait for parent to initialize this object - lockMutex(m_threadMutex); - unlockMutex(m_threadMutex); - - void* result = nullptr; - try { - // go - result = (*thread->m_func)(thread->m_userData); - } - - catch (XThreadCancel&) { - // client called cancel() - // set base value - result = nullptr; - } - catch (...) { - // note -- don't catch (...) to avoid masking bugs - lockMutex(m_threadMutex); - thread->m_exited = true; - unlockMutex(m_threadMutex); - closeThread(thread); - throw; - } - - // thread has exited - lockMutex(m_threadMutex); - thread->m_result = result; - thread->m_exited = true; + assert(findNoRef(thread->m_thread) == thread); + erase(thread); unlockMutex(m_threadMutex); // done with thread - closeThread(thread); + delete thread; + } } -void -ArchMultithreadPosix::threadCancel(int) -{ - // do nothing +ArchThread ArchMultithreadPosix::copyThread(ArchThread thread) { + refThread(thread); + return thread; } -void* -ArchMultithreadPosix::threadSignalHandler(void*) -{ - // detach - pthread_detach(pthread_self()); +void ArchMultithreadPosix::cancelThread(ArchThread thread) { + assert(thread != NULL); - // add signal to mask - sigset_t sigset; - setSignalSet(&sigset); + // set cancel and wakeup flags if thread can be cancelled + bool wakeup = false; + lockMutex(m_threadMutex); + if (!thread->m_exited && !thread->m_cancelling) { + thread->m_cancel = true; + wakeup = true; + } + unlockMutex(m_threadMutex); - // also wait on SIGABRT. on linux (others?) this thread (process) - // will persist after all the other threads evaporate due to an - // assert unless we wait on SIGABRT. that means our resources (like - // the socket we're listening on) are not released and never will be - // until the lingering thread is killed. i don't know why sigwait() - // should protect the thread from being killed. note that sigwait() - // doesn't actually return if we receive SIGABRT and, for some - // reason, we don't have to block SIGABRT. - sigaddset(&sigset, SIGABRT); + // force thread to exit system calls if wakeup is true + if (wakeup) { + pthread_kill(thread->m_thread, SIGWAKEUP); + } +} - // we exit the loop via thread cancellation in sigwait() - for (;;) { - // wait -#if HAVE_POSIX_SIGWAIT - int signal = 0; - sigwait(&sigset, &signal); -#else - sigwait(&sigset); -#endif +void ArchMultithreadPosix::setPriorityOfThread(ArchThread thread, int /*n*/) { + assert(thread != NULL); - // if we get here then the signal was raised - switch (signal) { - case SIGINT: - ARCH->raiseSignal(kINTERRUPT); - break; + // FIXME +} - case SIGTERM: - ARCH->raiseSignal(kTERMINATE); - break; +void ArchMultithreadPosix::testCancelThread() { + // find current thread + lockMutex(m_threadMutex); + ArchThreadImpl *thread = findNoRef(pthread_self()); + unlockMutex(m_threadMutex); - case SIGHUP: - ARCH->raiseSignal(kHANGUP); - break; + // test cancel on thread + testCancelThreadImpl(thread); +} - case SIGUSR2: - ARCH->raiseSignal(kUSER); - break; +bool ArchMultithreadPosix::wait(ArchThread target, double timeout) { + assert(target != NULL); - default: - // ignore - break; - } + lockMutex(m_threadMutex); + + // find current thread + ArchThreadImpl *self = findNoRef(pthread_self()); + + // ignore wait if trying to wait on ourself + if (target == self) { + unlockMutex(m_threadMutex); + return false; + } + + // ref the target so it can't go away while we're watching it + refThread(target); + + unlockMutex(m_threadMutex); + + try { + // do first test regardless of timeout + testCancelThreadImpl(self); + if (isExitedThread(target)) { + closeThread(target); + return true; } - return NULL; + // wait and repeat test if there's a timeout + if (timeout != 0.0) { + const double start = ARCH->time(); + do { + // wait a little + ARCH->sleep(0.05); + + // repeat test + testCancelThreadImpl(self); + if (isExitedThread(target)) { + closeThread(target); + return true; + } + + // repeat wait and test until timed out + } while (timeout < 0.0 || (ARCH->time() - start) <= timeout); + } + + closeThread(target); + return false; + } catch (...) { + closeThread(target); + throw; + } +} + +bool ArchMultithreadPosix::isSameThread(ArchThread thread1, + ArchThread thread2) { + return (thread1 == thread2); +} + +bool ArchMultithreadPosix::isExitedThread(ArchThread thread) { + lockMutex(m_threadMutex); + bool exited = thread->m_exited; + unlockMutex(m_threadMutex); + return exited; +} + +void *ArchMultithreadPosix::getResultOfThread(ArchThread thread) { + lockMutex(m_threadMutex); + void *result = thread->m_result; + unlockMutex(m_threadMutex); + return result; +} + +IArchMultithread::ThreadID +ArchMultithreadPosix::getIDOfThread(ArchThread thread) { + return thread->m_id; +} + +void ArchMultithreadPosix::setSignalHandler(ESignal signal, SignalFunc func, + void *userData) { + lockMutex(m_threadMutex); + m_signalFunc[signal] = func; + m_signalUserData[signal] = userData; + unlockMutex(m_threadMutex); +} + +void ArchMultithreadPosix::raiseSignal(ESignal signal) { + lockMutex(m_threadMutex); + if (m_signalFunc[signal] != NULL) { + m_signalFunc[signal](signal, m_signalUserData[signal]); + pthread_kill(m_mainThread->m_thread, SIGWAKEUP); + } else if (signal == kINTERRUPT || signal == kTERMINATE) { + ARCH->cancelThread(m_mainThread); + } + unlockMutex(m_threadMutex); +} + +void ArchMultithreadPosix::startSignalHandler() { + // set signal mask. the main thread blocks these signals and + // the signal handler thread will listen for them. + sigset_t sigset, oldsigset; + setSignalSet(&sigset); + pthread_sigmask(SIG_BLOCK, &sigset, &oldsigset); + + // fire up the INT and TERM signal handler thread. we could + // instead arrange to catch and handle these signals but + // we'd be unable to cancel the main thread since no pthread + // calls are allowed in a signal handler. + pthread_attr_t attr; + int status = pthread_attr_init(&attr); + if (status == 0) { + status = pthread_create(&m_signalThread, &attr, + &ArchMultithreadPosix::threadSignalHandler, NULL); + pthread_attr_destroy(&attr); + } + if (status != 0) { + // can't create thread to wait for signal so don't block + // the signals. + pthread_sigmask(SIG_UNBLOCK, &oldsigset, NULL); + } +} + +ArchThreadImpl *ArchMultithreadPosix::find(pthread_t thread) { + ArchThreadImpl *impl = findNoRef(thread); + if (impl != NULL) { + refThread(impl); + } + return impl; +} + +ArchThreadImpl *ArchMultithreadPosix::findNoRef(pthread_t thread) { + // linear search + for (ThreadList::const_iterator index = m_threadList.begin(); + index != m_threadList.end(); ++index) { + if ((*index)->m_thread == thread) { + return *index; + } + } + return NULL; +} + +void ArchMultithreadPosix::insert(ArchThreadImpl *thread) { + assert(thread != NULL); + + // thread shouldn't already be on the list + assert(findNoRef(thread->m_thread) == NULL); + + // set thread id. note that we don't worry about m_nextID + // wrapping back to 0 and duplicating thread ID's since the + // likelihood of synergy running that long is vanishingly + // small. + thread->m_id = ++m_nextID; + + // append to list + m_threadList.push_back(thread); +} + +void ArchMultithreadPosix::erase(ArchThreadImpl *thread) { + for (ThreadList::iterator index = m_threadList.begin(); + index != m_threadList.end(); ++index) { + if (*index == thread) { + m_threadList.erase(index); + break; + } + } +} + +void ArchMultithreadPosix::refThread(ArchThreadImpl *thread) { + assert(thread != NULL); + assert(findNoRef(thread->m_thread) != NULL); + ++thread->m_refCount; +} + +void ArchMultithreadPosix::testCancelThreadImpl(ArchThreadImpl *thread) { + assert(thread != NULL); + + // update cancel state + lockMutex(m_threadMutex); + bool cancel = false; + if (thread->m_cancel && !thread->m_cancelling) { + thread->m_cancelling = true; + thread->m_cancel = false; + cancel = true; + } + unlockMutex(m_threadMutex); + + // unwind thread's stack if cancelling + if (cancel) { + throw XThreadCancel(); + } +} + +void *ArchMultithreadPosix::threadFunc(void *vrep) { + // get the thread + ArchThreadImpl *thread = static_cast(vrep); + + // setup pthreads + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); + pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL); + + // run thread + s_instance->doThreadFunc(thread); + + // terminate the thread + return NULL; +} + +void ArchMultithreadPosix::doThreadFunc(ArchThread thread) { + // default priority is slightly below normal + setPriorityOfThread(thread, 1); + + // wait for parent to initialize this object + lockMutex(m_threadMutex); + unlockMutex(m_threadMutex); + + void *result = nullptr; + try { + // go + result = (*thread->m_func)(thread->m_userData); + } + + catch (XThreadCancel &) { + // client called cancel() + // set base value + result = nullptr; + } catch (...) { + // note -- don't catch (...) to avoid masking bugs + lockMutex(m_threadMutex); + thread->m_exited = true; + unlockMutex(m_threadMutex); + closeThread(thread); + throw; + } + + // thread has exited + lockMutex(m_threadMutex); + thread->m_result = result; + thread->m_exited = true; + unlockMutex(m_threadMutex); + + // done with thread + closeThread(thread); +} + +void ArchMultithreadPosix::threadCancel(int) { + // do nothing +} + +void *ArchMultithreadPosix::threadSignalHandler(void *) { + // detach + pthread_detach(pthread_self()); + + // add signal to mask + sigset_t sigset; + setSignalSet(&sigset); + + // also wait on SIGABRT. on linux (others?) this thread (process) + // will persist after all the other threads evaporate due to an + // assert unless we wait on SIGABRT. that means our resources (like + // the socket we're listening on) are not released and never will be + // until the lingering thread is killed. i don't know why sigwait() + // should protect the thread from being killed. note that sigwait() + // doesn't actually return if we receive SIGABRT and, for some + // reason, we don't have to block SIGABRT. + sigaddset(&sigset, SIGABRT); + + // we exit the loop via thread cancellation in sigwait() + for (;;) { + // wait +#if HAVE_POSIX_SIGWAIT + int signal = 0; + sigwait(&sigset, &signal); +#else + sigwait(&sigset); +#endif + + // if we get here then the signal was raised + switch (signal) { + case SIGINT: + ARCH->raiseSignal(kINTERRUPT); + break; + + case SIGTERM: + ARCH->raiseSignal(kTERMINATE); + break; + + case SIGHUP: + ARCH->raiseSignal(kHANGUP); + break; + + case SIGUSR2: + ARCH->raiseSignal(kUSER); + break; + + default: + // ignore + break; + } + } + + return NULL; } diff --git a/src/lib/arch/unix/ArchMultithreadPosix.h b/src/lib/arch/unix/ArchMultithreadPosix.h index ff0838418..8ed3af6eb 100644 --- a/src/lib/arch/unix/ArchMultithreadPosix.h +++ b/src/lib/arch/unix/ArchMultithreadPosix.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -27,94 +27,94 @@ class ArchCondImpl { public: - pthread_cond_t m_cond; + pthread_cond_t m_cond; }; class ArchMutexImpl { public: - pthread_mutex_t m_mutex; + pthread_mutex_t m_mutex; }; //! Posix implementation of IArchMultithread class ArchMultithreadPosix : public IArchMultithread { public: - ArchMultithreadPosix(); - ArchMultithreadPosix(ArchMultithreadPosix const &) =delete; - ArchMultithreadPosix(ArchMultithreadPosix &&) =delete; - virtual ~ArchMultithreadPosix(); + ArchMultithreadPosix(); + ArchMultithreadPosix(ArchMultithreadPosix const &) = delete; + ArchMultithreadPosix(ArchMultithreadPosix &&) = delete; + virtual ~ArchMultithreadPosix(); - ArchMultithreadPosix& operator=(ArchMultithreadPosix const &) =delete; - ArchMultithreadPosix& operator=(ArchMultithreadPosix &&) =delete; + ArchMultithreadPosix &operator=(ArchMultithreadPosix const &) = delete; + ArchMultithreadPosix &operator=(ArchMultithreadPosix &&) = delete; - //! @name manipulators - //@{ + //! @name manipulators + //@{ - void setNetworkDataForCurrentThread(void*); + void setNetworkDataForCurrentThread(void *); - //@} - //! @name accessors - //@{ + //@} + //! @name accessors + //@{ - void* getNetworkDataForThread(ArchThread); + void *getNetworkDataForThread(ArchThread); - static ArchMultithreadPosix* getInstance(); + static ArchMultithreadPosix *getInstance(); - //@} + //@} - // IArchMultithread overrides - virtual ArchCond newCondVar(); - virtual void closeCondVar(ArchCond); - virtual void signalCondVar(ArchCond); - virtual void broadcastCondVar(ArchCond); - virtual bool waitCondVar(ArchCond, ArchMutex, double timeout); - virtual ArchMutex newMutex(); - virtual void closeMutex(ArchMutex); - virtual void lockMutex(ArchMutex); - virtual void unlockMutex(ArchMutex); - virtual ArchThread newThread(ThreadFunc, void*); - virtual ArchThread newCurrentThread(); - virtual ArchThread copyThread(ArchThread); - virtual void closeThread(ArchThread); - virtual void cancelThread(ArchThread); - virtual void setPriorityOfThread(ArchThread, int n); - virtual void testCancelThread(); - virtual bool wait(ArchThread, double timeout); - virtual bool isSameThread(ArchThread, ArchThread); - virtual bool isExitedThread(ArchThread); - virtual void* getResultOfThread(ArchThread); - virtual ThreadID getIDOfThread(ArchThread); - virtual void setSignalHandler(ESignal, SignalFunc, void*); - virtual void raiseSignal(ESignal); + // IArchMultithread overrides + virtual ArchCond newCondVar(); + virtual void closeCondVar(ArchCond); + virtual void signalCondVar(ArchCond); + virtual void broadcastCondVar(ArchCond); + virtual bool waitCondVar(ArchCond, ArchMutex, double timeout); + virtual ArchMutex newMutex(); + virtual void closeMutex(ArchMutex); + virtual void lockMutex(ArchMutex); + virtual void unlockMutex(ArchMutex); + virtual ArchThread newThread(ThreadFunc, void *); + virtual ArchThread newCurrentThread(); + virtual ArchThread copyThread(ArchThread); + virtual void closeThread(ArchThread); + virtual void cancelThread(ArchThread); + virtual void setPriorityOfThread(ArchThread, int n); + virtual void testCancelThread(); + virtual bool wait(ArchThread, double timeout); + virtual bool isSameThread(ArchThread, ArchThread); + virtual bool isExitedThread(ArchThread); + virtual void *getResultOfThread(ArchThread); + virtual ThreadID getIDOfThread(ArchThread); + virtual void setSignalHandler(ESignal, SignalFunc, void *); + virtual void raiseSignal(ESignal); private: - void startSignalHandler(); + void startSignalHandler(); - ArchThreadImpl* find(pthread_t thread); - ArchThreadImpl* findNoRef(pthread_t thread); - void insert(ArchThreadImpl* thread); - void erase(ArchThreadImpl* thread); + ArchThreadImpl *find(pthread_t thread); + ArchThreadImpl *findNoRef(pthread_t thread); + void insert(ArchThreadImpl *thread); + void erase(ArchThreadImpl *thread); - void refThread(ArchThreadImpl* rep); - void testCancelThreadImpl(ArchThreadImpl* rep); + void refThread(ArchThreadImpl *rep); + void testCancelThreadImpl(ArchThreadImpl *rep); - void doThreadFunc(ArchThread thread); - static void* threadFunc(void* vrep); - static void threadCancel(int); - static void* threadSignalHandler(void* vrep); + void doThreadFunc(ArchThread thread); + static void *threadFunc(void *vrep); + static void threadCancel(int); + static void *threadSignalHandler(void *vrep); private: - typedef std::list ThreadList; + typedef std::list ThreadList; - static ArchMultithreadPosix* s_instance; + static ArchMultithreadPosix *s_instance; - bool m_newThreadCalled; + bool m_newThreadCalled; - ArchMutex m_threadMutex; - ArchThread m_mainThread; - ThreadList m_threadList; - ThreadID m_nextID; + ArchMutex m_threadMutex; + ArchThread m_mainThread; + ThreadList m_threadList; + ThreadID m_nextID; - pthread_t m_signalThread; - SignalFunc m_signalFunc[kNUM_SIGNALS]; - void* m_signalUserData[kNUM_SIGNALS]; + pthread_t m_signalThread; + SignalFunc m_signalFunc[kNUM_SIGNALS]; + void *m_signalUserData[kNUM_SIGNALS]; }; diff --git a/src/lib/arch/unix/ArchNetworkBSD.cpp b/src/lib/arch/unix/ArchNetworkBSD.cpp index 0eed900b4..5389307f9 100644 --- a/src/lib/arch/unix/ArchNetworkBSD.cpp +++ b/src/lib/arch/unix/ArchNetworkBSD.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -23,20 +23,20 @@ #include "arch/unix/XArchUnix.h" #if HAVE_UNISTD_H -# include +#include #endif #include #include #if !defined(TCP_NODELAY) -# include +#include #endif #include +#include #include #include -#include #if !HAVE_INET_ATON -# include +#include #endif static const int s_family[] = { @@ -44,31 +44,25 @@ static const int s_family[] = { PF_INET, PF_INET6, }; -static const int s_type[] = { - SOCK_DGRAM, - SOCK_STREAM -}; +static const int s_type[] = {SOCK_DGRAM, SOCK_STREAM}; #if !HAVE_INET_ATON // parse dotted quad addresses. we don't bother with the weird BSD'ism // of handling octal and hex and partial forms. -static -in_addr_t -inet_aton(const char* cp, struct in_addr* inp) -{ - unsigned int a, b, c, d; - if (sscanf(cp, "%u.%u.%u.%u", &a, &b, &c, &d) != 4) { - return 0; - } - if (a >= 256 || b >= 256 || c >= 256 || d >= 256) { - return 0; - } - unsigned char* incp = (unsigned char*)inp; - incp[0] = (unsigned char)(a & 0xffu); - incp[1] = (unsigned char)(b & 0xffu); - incp[2] = (unsigned char)(c & 0xffu); - incp[3] = (unsigned char)(d & 0xffu); - return inp->s_addr; +static in_addr_t inet_aton(const char *cp, struct in_addr *inp) { + unsigned int a, b, c, d; + if (sscanf(cp, "%u.%u.%u.%u", &a, &b, &c, &d) != 4) { + return 0; + } + if (a >= 256 || b >= 256 || c >= 256 || d >= 256) { + return 0; + } + unsigned char *incp = (unsigned char *)inp; + incp[0] = (unsigned char)(a & 0xffu); + incp[1] = (unsigned char)(b & 0xffu); + incp[2] = (unsigned char)(c & 0xffu); + incp[3] = (unsigned char)(d & 0xffu); + return inp->s_addr; } #endif @@ -78,932 +72,855 @@ inet_aton(const char* cp, struct in_addr* inp) ArchNetworkBSD::Connectors ArchNetworkBSD::s_connectors; -ArchNetworkBSD::ArchNetworkBSD() -= default; +ArchNetworkBSD::ArchNetworkBSD() = default; -ArchNetworkBSD::~ArchNetworkBSD() -{ - if (m_mutex) ARCH->closeMutex(m_mutex); +ArchNetworkBSD::~ArchNetworkBSD() { + if (m_mutex) + ARCH->closeMutex(m_mutex); } -void -ArchNetworkBSD::init() -{ - // create mutex to make some calls thread safe - m_mutex = ARCH->newMutex(); +void ArchNetworkBSD::init() { + // create mutex to make some calls thread safe + m_mutex = ARCH->newMutex(); } -ArchSocket -ArchNetworkBSD::newSocket(EAddressFamily family, ESocketType type) -{ - // create socket - int fd = socket(s_family[family], s_type[type], 0); - if (fd == -1) { - throwError(errno); - } - try { - setBlockingOnSocket(fd, false); - } - catch (...) { - close(fd); - throw; - } +ArchSocket ArchNetworkBSD::newSocket(EAddressFamily family, ESocketType type) { + // create socket + int fd = socket(s_family[family], s_type[type], 0); + if (fd == -1) { + throwError(errno); + } + try { + setBlockingOnSocket(fd, false); + } catch (...) { + close(fd); + throw; + } - // allocate socket object - auto* newSocket = new ArchSocketImpl; - newSocket->m_fd = fd; - newSocket->m_refCount = 1; - return newSocket; + // allocate socket object + auto *newSocket = new ArchSocketImpl; + newSocket->m_fd = fd; + newSocket->m_refCount = 1; + return newSocket; } -ArchSocket -ArchNetworkBSD::copySocket(ArchSocket s) -{ - assert(s != NULL); +ArchSocket ArchNetworkBSD::copySocket(ArchSocket s) { + assert(s != NULL); - // ref the socket and return it - ARCH->lockMutex(m_mutex); - ++s->m_refCount; - ARCH->unlockMutex(m_mutex); - return s; + // ref the socket and return it + ARCH->lockMutex(m_mutex); + ++s->m_refCount; + ARCH->unlockMutex(m_mutex); + return s; } -void -ArchNetworkBSD::closeSocket(ArchSocket s) -{ - assert(s != NULL); +void ArchNetworkBSD::closeSocket(ArchSocket s) { + assert(s != NULL); - // unref the socket and note if it should be released - ARCH->lockMutex(m_mutex); - const bool doClose = (--s->m_refCount == 0); - ARCH->unlockMutex(m_mutex); + // unref the socket and note if it should be released + ARCH->lockMutex(m_mutex); + const bool doClose = (--s->m_refCount == 0); + ARCH->unlockMutex(m_mutex); - // close the socket if necessary - if (doClose) { - if (close(s->m_fd) == -1) { - // close failed. restore the last ref and throw. - int err = errno; - ARCH->lockMutex(m_mutex); - ++s->m_refCount; - ARCH->unlockMutex(m_mutex); - throwError(err); - } - delete s; + // close the socket if necessary + if (doClose) { + if (close(s->m_fd) == -1) { + // close failed. restore the last ref and throw. + int err = errno; + ARCH->lockMutex(m_mutex); + ++s->m_refCount; + ARCH->unlockMutex(m_mutex); + throwError(err); } + delete s; + } } -void -ArchNetworkBSD::closeSocketForRead(ArchSocket s) -{ - assert(s != NULL); +void ArchNetworkBSD::closeSocketForRead(ArchSocket s) { + assert(s != NULL); - if (shutdown(s->m_fd, 0) == -1) { - if (errno != ENOTCONN) { - throwError(errno); - } + if (shutdown(s->m_fd, 0) == -1) { + if (errno != ENOTCONN) { + throwError(errno); } + } } -void -ArchNetworkBSD::closeSocketForWrite(ArchSocket s) -{ - assert(s != NULL); +void ArchNetworkBSD::closeSocketForWrite(ArchSocket s) { + assert(s != NULL); - if (shutdown(s->m_fd, 1) == -1) { - if (errno != ENOTCONN) { - throwError(errno); - } + if (shutdown(s->m_fd, 1) == -1) { + if (errno != ENOTCONN) { + throwError(errno); } + } } -void -ArchNetworkBSD::bindSocket(ArchSocket s, ArchNetAddress addr) -{ - assert(s != NULL); - assert(addr != NULL); +void ArchNetworkBSD::bindSocket(ArchSocket s, ArchNetAddress addr) { + assert(s != NULL); + assert(addr != NULL); - if (bind(s->m_fd, TYPED_ADDR(struct sockaddr, addr), addr->m_len) == -1) { - throwError(errno); - } + if (bind(s->m_fd, TYPED_ADDR(struct sockaddr, addr), addr->m_len) == -1) { + throwError(errno); + } } -void -ArchNetworkBSD::listenOnSocket(ArchSocket s) -{ - assert(s != NULL); +void ArchNetworkBSD::listenOnSocket(ArchSocket s) { + assert(s != NULL); - // hardcoding backlog - if (listen(s->m_fd, 3) == -1) { - throwError(errno); - } + // hardcoding backlog + if (listen(s->m_fd, 3) == -1) { + throwError(errno); + } } -ArchSocket -ArchNetworkBSD::acceptSocket(ArchSocket s, ArchNetAddress* addr) -{ - assert(s != NULL); +ArchSocket ArchNetworkBSD::acceptSocket(ArchSocket s, ArchNetAddress *addr) { + assert(s != NULL); - // if user passed NULL in addr then use scratch space - ArchNetAddress dummy; - if (addr == nullptr) { - addr = &dummy; + // if user passed NULL in addr then use scratch space + ArchNetAddress dummy; + if (addr == nullptr) { + addr = &dummy; + } + + // create new socket and address + auto *newSocket = new ArchSocketImpl; + *addr = new ArchNetAddressImpl; + + // accept on socket + auto len = ((*addr)->m_len); + int fd = accept(s->m_fd, TYPED_ADDR(struct sockaddr, (*addr)), &len); + (*addr)->m_len = len; + if (fd == -1) { + int err = errno; + delete newSocket; + delete *addr; + *addr = nullptr; + if (err == EAGAIN) { + return nullptr; } + throwError(err); + } - // create new socket and address - auto* newSocket = new ArchSocketImpl; - *addr = new ArchNetAddressImpl; + try { + setBlockingOnSocket(fd, false); + } catch (...) { + close(fd); + delete newSocket; + delete *addr; + *addr = nullptr; + throw; + } - // accept on socket - auto len = ((*addr)->m_len); - int fd = accept(s->m_fd, TYPED_ADDR(struct sockaddr, (*addr)), &len); - (*addr)->m_len = len; - if (fd == -1) { - int err = errno; - delete newSocket; - delete *addr; - *addr = nullptr; - if (err == EAGAIN) { - return nullptr; - } - throwError(err); - } + // initialize socket + newSocket->m_fd = fd; + newSocket->m_refCount = 1; - try { - setBlockingOnSocket(fd, false); - } - catch (...) { - close(fd); - delete newSocket; - delete *addr; - *addr = nullptr; - throw; - } + // discard address if not requested + if (addr == &dummy) { + ARCH->closeAddr(dummy); + } - // initialize socket - newSocket->m_fd = fd; - newSocket->m_refCount = 1; - - // discard address if not requested - if (addr == &dummy) { - ARCH->closeAddr(dummy); - } - - return newSocket; + return newSocket; } -bool -ArchNetworkBSD::connectSocket(ArchSocket s, ArchNetAddress addr) -{ - assert(s != NULL); - assert(addr != NULL); +bool ArchNetworkBSD::connectSocket(ArchSocket s, ArchNetAddress addr) { + assert(s != NULL); + assert(addr != NULL); - if (connect(s->m_fd, TYPED_ADDR(struct sockaddr, addr), addr->m_len) == -1) { - if (errno == EISCONN) { - return true; - } - if (errno == EINPROGRESS) { - return false; - } - throwError(errno); + if (connect(s->m_fd, TYPED_ADDR(struct sockaddr, addr), addr->m_len) == -1) { + if (errno == EISCONN) { + return true; } - return true; + if (errno == EINPROGRESS) { + return false; + } + throwError(errno); + } + return true; } #if HAVE_POLL -int -ArchNetworkBSD::pollSocket(PollEntry pe[], int num, double timeout) -{ - assert(pe != NULL || num == 0); +int ArchNetworkBSD::pollSocket(PollEntry pe[], int num, double timeout) { + assert(pe != NULL || num == 0); - // return if nothing to do - if (num == 0) { - if (timeout > 0.0) { - ARCH->sleep(timeout); - } - return 0; + // return if nothing to do + if (num == 0) { + if (timeout > 0.0) { + ARCH->sleep(timeout); } + return 0; + } - // allocate space for translated query - auto* pfd = new struct pollfd[1 + num]; + // allocate space for translated query + auto *pfd = new struct pollfd[1 + num]; - // translate query - for (int i = 0; i < num; ++i) { - pfd[i].fd = (pe[i].m_socket == nullptr) ? -1 : pe[i].m_socket->m_fd; - pfd[i].events = 0; - if ((pe[i].m_events & kPOLLIN) != 0) { - pfd[i].events |= POLLIN; - } - if ((pe[i].m_events & kPOLLOUT) != 0) { - pfd[i].events |= POLLOUT; - } + // translate query + for (int i = 0; i < num; ++i) { + pfd[i].fd = (pe[i].m_socket == nullptr) ? -1 : pe[i].m_socket->m_fd; + pfd[i].events = 0; + if ((pe[i].m_events & kPOLLIN) != 0) { + pfd[i].events |= POLLIN; } - int n = num; - - // add the unblock pipe - const int* unblockPipe = getUnblockPipe(); - if (unblockPipe != nullptr) { - pfd[n].fd = unblockPipe[0]; - pfd[n].events = POLLIN; - ++n; + if ((pe[i].m_events & kPOLLOUT) != 0) { + pfd[i].events |= POLLOUT; } + } + int n = num; - // prepare timeout - int t = (timeout < 0.0) ? -1 : static_cast(1000.0 * timeout); + // add the unblock pipe + const int *unblockPipe = getUnblockPipe(); + if (unblockPipe != nullptr) { + pfd[n].fd = unblockPipe[0]; + pfd[n].events = POLLIN; + ++n; + } - // do the poll - n = s_connectors.poll_impl(pfd, n, t); + // prepare timeout + int t = (timeout < 0.0) ? -1 : static_cast(1000.0 * timeout); - // reset the unblock pipe - if (n > 0 && unblockPipe != nullptr && (pfd[num].revents & POLLIN) != 0) { - // the unblock event was signalled. flush the pipe. - char dummy[100]; - int ignore; + // do the poll + n = s_connectors.poll_impl(pfd, n, t); - do { - ignore = read(unblockPipe[0], dummy, sizeof(dummy)); - } while (errno != EAGAIN); + // reset the unblock pipe + if (n > 0 && unblockPipe != nullptr && (pfd[num].revents & POLLIN) != 0) { + // the unblock event was signalled. flush the pipe. + char dummy[100]; + int ignore; - // don't count this unblock pipe in return value - --n; + do { + ignore = read(unblockPipe[0], dummy, sizeof(dummy)); + } while (errno != EAGAIN); + + // don't count this unblock pipe in return value + --n; + } + + // handle results + if (n == -1) { + if (errno == EINTR) { + // interrupted system call + ARCH->testCancelThread(); + delete[] pfd; + return 0; } - - // handle results - if (n == -1) { - if (errno == EINTR) { - // interrupted system call - ARCH->testCancelThread(); - delete[] pfd; - return 0; - } - delete[] pfd; - throwError(errno); - return -1; - } - - // translate back - for (int i = 0; i < num; ++i) { - pe[i].m_revents = 0; - if ((pfd[i].revents & POLLIN) != 0) { - pe[i].m_revents |= kPOLLIN; - } - if ((pfd[i].revents & POLLOUT) != 0) { - pe[i].m_revents |= kPOLLOUT; - } - if ((pfd[i].revents & POLLERR) != 0) { - pe[i].m_revents |= kPOLLERR; - } - if ((pfd[i].revents & POLLNVAL) != 0) { - pe[i].m_revents |= kPOLLNVAL; - } - } - delete[] pfd; - return n; + throwError(errno); + return -1; + } + + // translate back + for (int i = 0; i < num; ++i) { + pe[i].m_revents = 0; + if ((pfd[i].revents & POLLIN) != 0) { + pe[i].m_revents |= kPOLLIN; + } + if ((pfd[i].revents & POLLOUT) != 0) { + pe[i].m_revents |= kPOLLOUT; + } + if ((pfd[i].revents & POLLERR) != 0) { + pe[i].m_revents |= kPOLLERR; + } + if ((pfd[i].revents & POLLNVAL) != 0) { + pe[i].m_revents |= kPOLLNVAL; + } + } + + delete[] pfd; + return n; } #else -int -ArchNetworkBSD::pollSocket(PollEntry pe[], int num, double timeout) -{ - int i, n; +int ArchNetworkBSD::pollSocket(PollEntry pe[], int num, double timeout) { + int i, n; - // prepare sets for select - n = 0; - fd_set readSet, writeSet, errSet; - fd_set* readSetP = NULL; - fd_set* writeSetP = NULL; - fd_set* errSetP = NULL; - FD_ZERO(&readSet); - FD_ZERO(&writeSet); - FD_ZERO(&errSet); - for (i = 0; i < num; ++i) { - // reset return flags - pe[i].m_revents = 0; + // prepare sets for select + n = 0; + fd_set readSet, writeSet, errSet; + fd_set *readSetP = NULL; + fd_set *writeSetP = NULL; + fd_set *errSetP = NULL; + FD_ZERO(&readSet); + FD_ZERO(&writeSet); + FD_ZERO(&errSet); + for (i = 0; i < num; ++i) { + // reset return flags + pe[i].m_revents = 0; - // set invalid flag if socket is bogus then go to next socket - if (pe[i].m_socket == NULL) { - pe[i].m_revents |= kPOLLNVAL; - continue; - } - - int fdi = pe[i].m_socket->m_fd; - if (pe[i].m_events & kPOLLIN) { - FD_SET(pe[i].m_socket->m_fd, &readSet); - readSetP = &readSet; - if (fdi > n) { - n = fdi; - } - } - if (pe[i].m_events & kPOLLOUT) { - FD_SET(pe[i].m_socket->m_fd, &writeSet); - writeSetP = &writeSet; - if (fdi > n) { - n = fdi; - } - } - if (true) { - FD_SET(pe[i].m_socket->m_fd, &errSet); - errSetP = &errSet; - if (fdi > n) { - n = fdi; - } - } + // set invalid flag if socket is bogus then go to next socket + if (pe[i].m_socket == NULL) { + pe[i].m_revents |= kPOLLNVAL; + continue; } - // add the unblock pipe - const int* unblockPipe = getUnblockPipe(); - if (unblockPipe != NULL) { - FD_SET(unblockPipe[0], &readSet); - readSetP = &readSet; - if (unblockPipe[0] > n) { - n = unblockPipe[0]; - } + int fdi = pe[i].m_socket->m_fd; + if (pe[i].m_events & kPOLLIN) { + FD_SET(pe[i].m_socket->m_fd, &readSet); + readSetP = &readSet; + if (fdi > n) { + n = fdi; + } } + if (pe[i].m_events & kPOLLOUT) { + FD_SET(pe[i].m_socket->m_fd, &writeSet); + writeSetP = &writeSet; + if (fdi > n) { + n = fdi; + } + } + if (true) { + FD_SET(pe[i].m_socket->m_fd, &errSet); + errSetP = &errSet; + if (fdi > n) { + n = fdi; + } + } + } - // if there are no sockets then don't block forever - if (n == 0 && timeout < 0.0) { - timeout = 0.0; + // add the unblock pipe + const int *unblockPipe = getUnblockPipe(); + if (unblockPipe != NULL) { + FD_SET(unblockPipe[0], &readSet); + readSetP = &readSet; + if (unblockPipe[0] > n) { + n = unblockPipe[0]; } + } - // prepare timeout for select - struct timeval timeout2; - struct timeval* timeout2P; - if (timeout < 0.0) { - timeout2P = NULL; - } - else { - timeout2P = &timeout2; - timeout2.tv_sec = static_cast(timeout); - timeout2.tv_usec = static_cast(1.0e+6 * - (timeout - timeout2.tv_sec)); - } + // if there are no sockets then don't block forever + if (n == 0 && timeout < 0.0) { + timeout = 0.0; + } - // do the select - n = select((SELECT_TYPE_ARG1) n + 1, - SELECT_TYPE_ARG234 readSetP, - SELECT_TYPE_ARG234 writeSetP, - SELECT_TYPE_ARG234 errSetP, - SELECT_TYPE_ARG5 timeout2P); + // prepare timeout for select + struct timeval timeout2; + struct timeval *timeout2P; + if (timeout < 0.0) { + timeout2P = NULL; + } else { + timeout2P = &timeout2; + timeout2.tv_sec = static_cast(timeout); + timeout2.tv_usec = static_cast(1.0e+6 * (timeout - timeout2.tv_sec)); + } - // reset the unblock pipe - if (n > 0 && unblockPipe != NULL && FD_ISSET(unblockPipe[0], &readSet)) { - // the unblock event was signalled. flush the pipe. - char dummy[100]; - do { - read(unblockPipe[0], dummy, sizeof(dummy)); - } while (errno != EAGAIN); - } + // do the select + n = select((SELECT_TYPE_ARG1)n + 1, SELECT_TYPE_ARG234 readSetP, + SELECT_TYPE_ARG234 writeSetP, SELECT_TYPE_ARG234 errSetP, + SELECT_TYPE_ARG5 timeout2P); - // handle results - if (n == -1) { - if (errno == EINTR) { - // interrupted system call - ARCH->testCancelThread(); - return 0; - } - throwError(errno); - } - n = 0; - for (i = 0; i < num; ++i) { - if (pe[i].m_socket != NULL) { - if (FD_ISSET(pe[i].m_socket->m_fd, &readSet)) { - pe[i].m_revents |= kPOLLIN; - } - if (FD_ISSET(pe[i].m_socket->m_fd, &writeSet)) { - pe[i].m_revents |= kPOLLOUT; - } - if (FD_ISSET(pe[i].m_socket->m_fd, &errSet)) { - pe[i].m_revents |= kPOLLERR; - } - } - if (pe[i].m_revents != 0) { - ++n; - } - } + // reset the unblock pipe + if (n > 0 && unblockPipe != NULL && FD_ISSET(unblockPipe[0], &readSet)) { + // the unblock event was signalled. flush the pipe. + char dummy[100]; + do { + read(unblockPipe[0], dummy, sizeof(dummy)); + } while (errno != EAGAIN); + } - return n; + // handle results + if (n == -1) { + if (errno == EINTR) { + // interrupted system call + ARCH->testCancelThread(); + return 0; + } + throwError(errno); + } + n = 0; + for (i = 0; i < num; ++i) { + if (pe[i].m_socket != NULL) { + if (FD_ISSET(pe[i].m_socket->m_fd, &readSet)) { + pe[i].m_revents |= kPOLLIN; + } + if (FD_ISSET(pe[i].m_socket->m_fd, &writeSet)) { + pe[i].m_revents |= kPOLLOUT; + } + if (FD_ISSET(pe[i].m_socket->m_fd, &errSet)) { + pe[i].m_revents |= kPOLLERR; + } + } + if (pe[i].m_revents != 0) { + ++n; + } + } + + return n; } #endif -void -ArchNetworkBSD::unblockPollSocket(ArchThread thread) -{ - const int* unblockPipe = getUnblockPipeForThread(thread); - if (unblockPipe != nullptr) { - char dummy = 0; - int ignore; +void ArchNetworkBSD::unblockPollSocket(ArchThread thread) { + const int *unblockPipe = getUnblockPipeForThread(thread); + if (unblockPipe != nullptr) { + char dummy = 0; + int ignore; - ignore = write(unblockPipe[1], &dummy, 1); - } + ignore = write(unblockPipe[1], &dummy, 1); + } } -size_t -ArchNetworkBSD::readSocket(ArchSocket s, void* buf, size_t len) -{ - assert(s != NULL); +size_t ArchNetworkBSD::readSocket(ArchSocket s, void *buf, size_t len) { + assert(s != NULL); - ssize_t n = read(s->m_fd, buf, len); - if (n == -1) { - if (errno == EINTR || errno == EAGAIN) { - return 0; - } - throwError(errno); + ssize_t n = read(s->m_fd, buf, len); + if (n == -1) { + if (errno == EINTR || errno == EAGAIN) { + return 0; } - return n; + throwError(errno); + } + return n; } -size_t -ArchNetworkBSD::writeSocket(ArchSocket s, const void* buf, size_t len) -{ - assert(s != NULL); +size_t ArchNetworkBSD::writeSocket(ArchSocket s, const void *buf, size_t len) { + assert(s != NULL); - ssize_t n = write(s->m_fd, buf, len); - if (n == -1) { - if (errno == EINTR || errno == EAGAIN) { - return 0; - } - throwError(errno); + ssize_t n = write(s->m_fd, buf, len); + if (n == -1) { + if (errno == EINTR || errno == EAGAIN) { + return 0; } - return n; + throwError(errno); + } + return n; } -void -ArchNetworkBSD::throwErrorOnSocket(ArchSocket s) -{ - assert(s != NULL); +void ArchNetworkBSD::throwErrorOnSocket(ArchSocket s) { + assert(s != NULL); - // get the error from the socket layer - int err = 0; - auto size = static_cast(sizeof(err)); - if (getsockopt(s->m_fd, SOL_SOCKET, SO_ERROR, - reinterpret_cast(&err), &size) == -1) { - err = errno; - } + // get the error from the socket layer + int err = 0; + auto size = static_cast(sizeof(err)); + if (getsockopt(s->m_fd, SOL_SOCKET, SO_ERROR, + reinterpret_cast(&err), &size) == -1) { + err = errno; + } - // throw if there's an error - if (err != 0) { - throwError(err); - } + // throw if there's an error + if (err != 0) { + throwError(err); + } } -void -ArchNetworkBSD::setBlockingOnSocket(int fd, bool blocking) -{ - assert(fd != -1); +void ArchNetworkBSD::setBlockingOnSocket(int fd, bool blocking) { + assert(fd != -1); - int mode = fcntl(fd, F_GETFL, 0); - if (mode == -1) { - throwError(errno); - } - if (blocking) { - mode &= ~O_NONBLOCK; - } - else { - mode |= O_NONBLOCK; - } - if (fcntl(fd, F_SETFL, mode) == -1) { - throwError(errno); - } + int mode = fcntl(fd, F_GETFL, 0); + if (mode == -1) { + throwError(errno); + } + if (blocking) { + mode &= ~O_NONBLOCK; + } else { + mode |= O_NONBLOCK; + } + if (fcntl(fd, F_SETFL, mode) == -1) { + throwError(errno); + } } -bool -ArchNetworkBSD::setNoDelayOnSocket(ArchSocket s, bool noDelay) -{ - assert(s != NULL); +bool ArchNetworkBSD::setNoDelayOnSocket(ArchSocket s, bool noDelay) { + assert(s != NULL); - // get old state - int oflag; - auto size = static_cast(sizeof(oflag)); - if (getsockopt(s->m_fd, IPPROTO_TCP, TCP_NODELAY, - reinterpret_cast(&oflag), &size) == -1) { - throwError(errno); - } + // get old state + int oflag; + auto size = static_cast(sizeof(oflag)); + if (getsockopt(s->m_fd, IPPROTO_TCP, TCP_NODELAY, + reinterpret_cast(&oflag), &size) == -1) { + throwError(errno); + } - int flag = noDelay ? 1 : 0; - size = static_cast(sizeof(flag)); - if (setsockopt(s->m_fd, IPPROTO_TCP, TCP_NODELAY, - reinterpret_cast(&flag), size) == -1) { - throwError(errno); - } + int flag = noDelay ? 1 : 0; + size = static_cast(sizeof(flag)); + if (setsockopt(s->m_fd, IPPROTO_TCP, TCP_NODELAY, + reinterpret_cast(&flag), size) == -1) { + throwError(errno); + } - return (oflag != 0); + return (oflag != 0); } -bool -ArchNetworkBSD::setReuseAddrOnSocket(ArchSocket s, bool reuse) -{ - assert(s != NULL); +bool ArchNetworkBSD::setReuseAddrOnSocket(ArchSocket s, bool reuse) { + assert(s != NULL); - // get old state - int oflag; - auto size = static_cast(sizeof(oflag)); - if (getsockopt(s->m_fd, SOL_SOCKET, SO_REUSEADDR, - reinterpret_cast(&oflag), &size) == -1) { - throwError(errno); - } + // get old state + int oflag; + auto size = static_cast(sizeof(oflag)); + if (getsockopt(s->m_fd, SOL_SOCKET, SO_REUSEADDR, + reinterpret_cast(&oflag), &size) == -1) { + throwError(errno); + } - int flag = reuse ? 1 : 0; - size = static_cast(sizeof(flag)); - if (setsockopt(s->m_fd, SOL_SOCKET, SO_REUSEADDR, - reinterpret_cast(&flag), size) == -1) { - throwError(errno); - } + int flag = reuse ? 1 : 0; + size = static_cast(sizeof(flag)); + if (setsockopt(s->m_fd, SOL_SOCKET, SO_REUSEADDR, + reinterpret_cast(&flag), size) == -1) { + throwError(errno); + } - return (oflag != 0); + return (oflag != 0); } -std::string -ArchNetworkBSD::getHostName() -{ - char name[256]; - if (gethostname(name, sizeof(name)) == -1) { - name[0] = '\0'; - } - else { - name[sizeof(name) - 1] = '\0'; - } - return name; +std::string ArchNetworkBSD::getHostName() { + char name[256]; + if (gethostname(name, sizeof(name)) == -1) { + name[0] = '\0'; + } else { + name[sizeof(name) - 1] = '\0'; + } + return name; } -ArchNetAddress -ArchNetworkBSD::newAnyAddr(EAddressFamily family) -{ - // allocate address - auto* addr = new ArchNetAddressImpl; +ArchNetAddress ArchNetworkBSD::newAnyAddr(EAddressFamily family) { + // allocate address + auto *addr = new ArchNetAddressImpl; - // fill it in - switch (family) { - case kINET: { - auto* ipAddr = TYPED_ADDR(struct sockaddr_in, addr); - ipAddr->sin_family = AF_INET; - ipAddr->sin_port = 0; - ipAddr->sin_addr.s_addr = INADDR_ANY; - addr->m_len = static_cast(sizeof(struct sockaddr_in)); - break; - } + // fill it in + switch (family) { + case kINET: { + auto *ipAddr = TYPED_ADDR(struct sockaddr_in, addr); + ipAddr->sin_family = AF_INET; + ipAddr->sin_port = 0; + ipAddr->sin_addr.s_addr = INADDR_ANY; + addr->m_len = static_cast(sizeof(struct sockaddr_in)); + break; + } - case kINET6: { - struct sockaddr_in6* ipAddr = TYPED_ADDR(struct sockaddr_in6, addr); - ipAddr->sin6_family = AF_INET6; - ipAddr->sin6_port = 0; - memcpy(&ipAddr->sin6_addr, &in6addr_any, sizeof(in6addr_any)); - addr->m_len = (socklen_t)sizeof(struct sockaddr_in6); - break; - } - default: - delete addr; - assert(0 && "invalid family"); - } + case kINET6: { + struct sockaddr_in6 *ipAddr = TYPED_ADDR(struct sockaddr_in6, addr); + ipAddr->sin6_family = AF_INET6; + ipAddr->sin6_port = 0; + memcpy(&ipAddr->sin6_addr, &in6addr_any, sizeof(in6addr_any)); + addr->m_len = (socklen_t)sizeof(struct sockaddr_in6); + break; + } + default: + delete addr; + assert(0 && "invalid family"); + } - return addr; + return addr; } -ArchNetAddress -ArchNetworkBSD::copyAddr(ArchNetAddress addr) -{ - assert(addr != NULL); +ArchNetAddress ArchNetworkBSD::copyAddr(ArchNetAddress addr) { + assert(addr != NULL); - // allocate and copy address - return new ArchNetAddressImpl(*addr); + // allocate and copy address + return new ArchNetAddressImpl(*addr); } std::vector -ArchNetworkBSD::nameToAddr(const std::string& name) -{ - struct addrinfo hints; - struct in6_addr serveraddr; +ArchNetworkBSD::nameToAddr(const std::string &name) { + struct addrinfo hints; + struct in6_addr serveraddr; - memset(&hints, 0, sizeof(hints)); - hints.ai_flags = AI_NUMERICSERV; - hints.ai_family = AF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; + memset(&hints, 0, sizeof(hints)); + hints.ai_flags = AI_NUMERICSERV; + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; - if (inet_pton(AF_INET, name.c_str(), &serveraddr) == 1) { - hints.ai_family = AF_INET; - hints.ai_flags |= AI_NUMERICHOST; - } - else if (inet_pton(AF_INET6, name.c_str(), &serveraddr) == 1) { - hints.ai_family = AF_INET6; - hints.ai_flags |= AI_NUMERICHOST; - } + if (inet_pton(AF_INET, name.c_str(), &serveraddr) == 1) { + hints.ai_family = AF_INET; + hints.ai_flags |= AI_NUMERICHOST; + } else if (inet_pton(AF_INET6, name.c_str(), &serveraddr) == 1) { + hints.ai_family = AF_INET6; + hints.ai_flags |= AI_NUMERICHOST; + } - // done with static buffer - ARCH->lockMutex(m_mutex); - struct addrinfo *pResult = nullptr; - int ret = getaddrinfo(name.c_str(), nullptr, &hints, &pResult); - if (ret != 0) { - ARCH->unlockMutex(m_mutex); - throwNameError(ret); - } - - // allocate address - std::vector addresses; - for (auto address = pResult; address != nullptr; address = address->ai_next ) { - addresses.push_back(new ArchNetAddressImpl); - if (address->ai_family == AF_INET) { - addresses.back()->m_len = (socklen_t)sizeof(struct sockaddr_in); - } else { - addresses.back()->m_len = (socklen_t)sizeof(struct sockaddr_in6); - } - - memcpy(&addresses.back()->m_addr, address->ai_addr, addresses.back()->m_len); - } - - freeaddrinfo(pResult); + // done with static buffer + ARCH->lockMutex(m_mutex); + struct addrinfo *pResult = nullptr; + int ret = getaddrinfo(name.c_str(), nullptr, &hints, &pResult); + if (ret != 0) { ARCH->unlockMutex(m_mutex); + throwNameError(ret); + } - return addresses; -} - -void -ArchNetworkBSD::closeAddr(ArchNetAddress addr) -{ - assert(addr != NULL); - - delete addr; -} - -std::string -ArchNetworkBSD::addrToName(ArchNetAddress addr) -{ - assert(addr != NULL); - - // mutexed name lookup (ugh) - ARCH->lockMutex(m_mutex); - char host[1024]; - char service[20]; - int ret = getnameinfo(TYPED_ADDR(struct sockaddr, addr), addr->m_len, host, sizeof(host), service, sizeof(service), 0); - if (ret != 0) { - ARCH->unlockMutex(m_mutex); - throwNameError(ret); + // allocate address + std::vector addresses; + for (auto address = pResult; address != nullptr; address = address->ai_next) { + addresses.push_back(new ArchNetAddressImpl); + if (address->ai_family == AF_INET) { + addresses.back()->m_len = (socklen_t)sizeof(struct sockaddr_in); + } else { + addresses.back()->m_len = (socklen_t)sizeof(struct sockaddr_in6); } - // save (primary) name - std::string name = host; + memcpy(&addresses.back()->m_addr, address->ai_addr, + addresses.back()->m_len); + } - // done with static buffer + freeaddrinfo(pResult); + ARCH->unlockMutex(m_mutex); + + return addresses; +} + +void ArchNetworkBSD::closeAddr(ArchNetAddress addr) { + assert(addr != NULL); + + delete addr; +} + +std::string ArchNetworkBSD::addrToName(ArchNetAddress addr) { + assert(addr != NULL); + + // mutexed name lookup (ugh) + ARCH->lockMutex(m_mutex); + char host[1024]; + char service[20]; + int ret = getnameinfo(TYPED_ADDR(struct sockaddr, addr), addr->m_len, host, + sizeof(host), service, sizeof(service), 0); + if (ret != 0) { ARCH->unlockMutex(m_mutex); + throwNameError(ret); + } - return name; + // save (primary) name + std::string name = host; + + // done with static buffer + ARCH->unlockMutex(m_mutex); + + return name; } -std::string -ArchNetworkBSD::addrToString(ArchNetAddress addr) -{ - assert(addr != NULL); +std::string ArchNetworkBSD::addrToString(ArchNetAddress addr) { + assert(addr != NULL); - switch (getAddrFamily(addr)) { - case kINET: { - auto* ipAddr = TYPED_ADDR(struct sockaddr_in, addr); - ARCH->lockMutex(m_mutex); - std::string s = inet_ntoa(ipAddr->sin_addr); - ARCH->unlockMutex(m_mutex); - return s; - } + switch (getAddrFamily(addr)) { + case kINET: { + auto *ipAddr = TYPED_ADDR(struct sockaddr_in, addr); + ARCH->lockMutex(m_mutex); + std::string s = inet_ntoa(ipAddr->sin_addr); + ARCH->unlockMutex(m_mutex); + return s; + } - case kINET6: { - char strAddr[INET6_ADDRSTRLEN]; - struct sockaddr_in6* ipAddr = TYPED_ADDR(struct sockaddr_in6, addr); - ARCH->lockMutex(m_mutex); - inet_ntop(AF_INET6, &ipAddr->sin6_addr, strAddr, INET6_ADDRSTRLEN); - ARCH->unlockMutex(m_mutex); - return strAddr; - } + case kINET6: { + char strAddr[INET6_ADDRSTRLEN]; + struct sockaddr_in6 *ipAddr = TYPED_ADDR(struct sockaddr_in6, addr); + ARCH->lockMutex(m_mutex); + inet_ntop(AF_INET6, &ipAddr->sin6_addr, strAddr, INET6_ADDRSTRLEN); + ARCH->unlockMutex(m_mutex); + return strAddr; + } - default: - assert(0 && "unknown address family"); - return ""; - } + default: + assert(0 && "unknown address family"); + return ""; + } } IArchNetwork::EAddressFamily -ArchNetworkBSD::getAddrFamily(ArchNetAddress addr) -{ - assert(addr != NULL); +ArchNetworkBSD::getAddrFamily(ArchNetAddress addr) { + assert(addr != NULL); - switch (addr->m_addr.ss_family) { - case AF_INET: - return kINET; - case AF_INET6: - return kINET6; + switch (addr->m_addr.ss_family) { + case AF_INET: + return kINET; + case AF_INET6: + return kINET6; - default: - return kUNKNOWN; - } + default: + return kUNKNOWN; + } } -void -ArchNetworkBSD::setAddrPort(ArchNetAddress addr, int port) -{ - assert(addr != NULL); +void ArchNetworkBSD::setAddrPort(ArchNetAddress addr, int port) { + assert(addr != NULL); - switch (getAddrFamily(addr)) { - case kINET: { - auto* ipAddr = TYPED_ADDR(struct sockaddr_in, addr); - ipAddr->sin_port = htons(port); - break; - } + switch (getAddrFamily(addr)) { + case kINET: { + auto *ipAddr = TYPED_ADDR(struct sockaddr_in, addr); + ipAddr->sin_port = htons(port); + break; + } - case kINET6: { - struct sockaddr_in6* ipAddr = TYPED_ADDR(struct sockaddr_in6, addr); - ipAddr->sin6_port = htons(port); - break; - } + case kINET6: { + struct sockaddr_in6 *ipAddr = TYPED_ADDR(struct sockaddr_in6, addr); + ipAddr->sin6_port = htons(port); + break; + } - default: - assert(0 && "unknown address family"); - break; - } + default: + assert(0 && "unknown address family"); + break; + } } -int -ArchNetworkBSD::getAddrPort(ArchNetAddress addr) -{ - assert(addr != NULL); +int ArchNetworkBSD::getAddrPort(ArchNetAddress addr) { + assert(addr != NULL); - switch (getAddrFamily(addr)) { - case kINET: { - auto* ipAddr = TYPED_ADDR(struct sockaddr_in, addr); - return ntohs(ipAddr->sin_port); - } + switch (getAddrFamily(addr)) { + case kINET: { + auto *ipAddr = TYPED_ADDR(struct sockaddr_in, addr); + return ntohs(ipAddr->sin_port); + } - case kINET6: { - struct sockaddr_in6* ipAddr = TYPED_ADDR(struct sockaddr_in6, addr); - return ntohs(ipAddr->sin6_port); - } + case kINET6: { + struct sockaddr_in6 *ipAddr = TYPED_ADDR(struct sockaddr_in6, addr); + return ntohs(ipAddr->sin6_port); + } - default: - assert(0 && "unknown address family"); - return 0; - } + default: + assert(0 && "unknown address family"); + return 0; + } } -bool -ArchNetworkBSD::isAnyAddr(ArchNetAddress addr) -{ - assert(addr != NULL); +bool ArchNetworkBSD::isAnyAddr(ArchNetAddress addr) { + assert(addr != NULL); - switch (getAddrFamily(addr)) { - case kINET: { - auto* ipAddr = TYPED_ADDR(struct sockaddr_in, addr); - return (ipAddr->sin_addr.s_addr == INADDR_ANY && - addr->m_len == static_cast(sizeof(struct sockaddr_in))); - } + switch (getAddrFamily(addr)) { + case kINET: { + auto *ipAddr = TYPED_ADDR(struct sockaddr_in, addr); + return (ipAddr->sin_addr.s_addr == INADDR_ANY && + addr->m_len == static_cast(sizeof(struct sockaddr_in))); + } - case kINET6: { - struct sockaddr_in6* ipAddr = TYPED_ADDR(struct sockaddr_in6, addr); - return (addr->m_len == (socklen_t)sizeof(struct sockaddr_in6) && - memcmp(static_cast(&ipAddr->sin6_addr), static_cast(&in6addr_any), sizeof(in6_addr)) == 0); - } + case kINET6: { + struct sockaddr_in6 *ipAddr = TYPED_ADDR(struct sockaddr_in6, addr); + return (addr->m_len == (socklen_t)sizeof(struct sockaddr_in6) && + memcmp(static_cast(&ipAddr->sin6_addr), + static_cast(&in6addr_any), + sizeof(in6_addr)) == 0); + } - default: - assert(0 && "unknown address family"); - return true; - } + default: + assert(0 && "unknown address family"); + return true; + } } -bool -ArchNetworkBSD::isEqualAddr(ArchNetAddress a, ArchNetAddress b) -{ - return (a->m_len == b->m_len && - memcmp(&a->m_addr, &b->m_addr, a->m_len) == 0); +bool ArchNetworkBSD::isEqualAddr(ArchNetAddress a, ArchNetAddress b) { + return (a->m_len == b->m_len && + memcmp(&a->m_addr, &b->m_addr, a->m_len) == 0); } -const int* -ArchNetworkBSD::getUnblockPipe() -{ - ArchMultithreadPosix* mt = ArchMultithreadPosix::getInstance(); - ArchThread thread = mt->newCurrentThread(); - const int* p = getUnblockPipeForThread(thread); - ARCH->closeThread(thread); - return p; +const int *ArchNetworkBSD::getUnblockPipe() { + ArchMultithreadPosix *mt = ArchMultithreadPosix::getInstance(); + ArchThread thread = mt->newCurrentThread(); + const int *p = getUnblockPipeForThread(thread); + ARCH->closeThread(thread); + return p; } -const int* -ArchNetworkBSD::getUnblockPipeForThread(ArchThread thread) -{ - ArchMultithreadPosix* mt = ArchMultithreadPosix::getInstance(); - auto* unblockPipe = static_cast(mt->getNetworkDataForThread(thread)); - if (unblockPipe == nullptr) { - unblockPipe = new int[2]; - if (pipe(unblockPipe) != -1) { - try { - setBlockingOnSocket(unblockPipe[0], false); - mt->setNetworkDataForCurrentThread(unblockPipe); - } - catch (...) { - delete[] unblockPipe; - unblockPipe = nullptr; - } - } - else { - delete[] unblockPipe; - unblockPipe = nullptr; - } +const int *ArchNetworkBSD::getUnblockPipeForThread(ArchThread thread) { + ArchMultithreadPosix *mt = ArchMultithreadPosix::getInstance(); + auto *unblockPipe = static_cast(mt->getNetworkDataForThread(thread)); + if (unblockPipe == nullptr) { + unblockPipe = new int[2]; + if (pipe(unblockPipe) != -1) { + try { + setBlockingOnSocket(unblockPipe[0], false); + mt->setNetworkDataForCurrentThread(unblockPipe); + } catch (...) { + delete[] unblockPipe; + unblockPipe = nullptr; + } + } else { + delete[] unblockPipe; + unblockPipe = nullptr; } - return unblockPipe; + } + return unblockPipe; } -void -ArchNetworkBSD::throwError(int err) -{ - switch (err) { - case EINTR: - ARCH->testCancelThread(); - throw XArchNetworkInterrupted(new XArchEvalUnix(err)); +void ArchNetworkBSD::throwError(int err) { + switch (err) { + case EINTR: + ARCH->testCancelThread(); + throw XArchNetworkInterrupted(new XArchEvalUnix(err)); - case EACCES: - case EPERM: - throw XArchNetworkAccess(new XArchEvalUnix(err)); + case EACCES: + case EPERM: + throw XArchNetworkAccess(new XArchEvalUnix(err)); - case ENFILE: - case EMFILE: - case ENODEV: - case ENOBUFS: - case ENOMEM: - case ENETDOWN: + case ENFILE: + case EMFILE: + case ENODEV: + case ENOBUFS: + case ENOMEM: + case ENETDOWN: #if defined(ENOSR) - case ENOSR: + case ENOSR: #endif - throw XArchNetworkResource(new XArchEvalUnix(err)); + throw XArchNetworkResource(new XArchEvalUnix(err)); - case EPROTOTYPE: - case EPROTONOSUPPORT: - case EAFNOSUPPORT: - case EPFNOSUPPORT: - case ESOCKTNOSUPPORT: - case EINVAL: - case ENOPROTOOPT: - case EOPNOTSUPP: - case ESHUTDOWN: + case EPROTOTYPE: + case EPROTONOSUPPORT: + case EAFNOSUPPORT: + case EPFNOSUPPORT: + case ESOCKTNOSUPPORT: + case EINVAL: + case ENOPROTOOPT: + case EOPNOTSUPP: + case ESHUTDOWN: #if defined(ENOPKG) - case ENOPKG: + case ENOPKG: #endif - throw XArchNetworkSupport(new XArchEvalUnix(err)); + throw XArchNetworkSupport(new XArchEvalUnix(err)); - case EIO: - throw XArchNetworkIO(new XArchEvalUnix(err)); + case EIO: + throw XArchNetworkIO(new XArchEvalUnix(err)); - case EADDRNOTAVAIL: - throw XArchNetworkNoAddress(new XArchEvalUnix(err)); + case EADDRNOTAVAIL: + throw XArchNetworkNoAddress(new XArchEvalUnix(err)); - case EADDRINUSE: - throw XArchNetworkAddressInUse(new XArchEvalUnix(err)); + case EADDRINUSE: + throw XArchNetworkAddressInUse(new XArchEvalUnix(err)); - case EHOSTUNREACH: - case ENETUNREACH: - throw XArchNetworkNoRoute(new XArchEvalUnix(err)); + case EHOSTUNREACH: + case ENETUNREACH: + throw XArchNetworkNoRoute(new XArchEvalUnix(err)); - case ENOTCONN: - throw XArchNetworkNotConnected(new XArchEvalUnix(err)); + case ENOTCONN: + throw XArchNetworkNotConnected(new XArchEvalUnix(err)); - case EPIPE: - throw XArchNetworkShutdown(new XArchEvalUnix(err)); + case EPIPE: + throw XArchNetworkShutdown(new XArchEvalUnix(err)); - case ECONNABORTED: - case ECONNRESET: - throw XArchNetworkDisconnected(new XArchEvalUnix(err)); + case ECONNABORTED: + case ECONNRESET: + throw XArchNetworkDisconnected(new XArchEvalUnix(err)); - case ECONNREFUSED: - throw XArchNetworkConnectionRefused(new XArchEvalUnix(err)); + case ECONNREFUSED: + throw XArchNetworkConnectionRefused(new XArchEvalUnix(err)); - case EHOSTDOWN: - case ETIMEDOUT: - throw XArchNetworkTimedOut(new XArchEvalUnix(err)); + case EHOSTDOWN: + case ETIMEDOUT: + throw XArchNetworkTimedOut(new XArchEvalUnix(err)); - default: - throw XArchNetwork(new XArchEvalUnix(err)); - } + default: + throw XArchNetwork(new XArchEvalUnix(err)); + } } -void -ArchNetworkBSD::throwNameError(int err) -{ - static const char* s_msg[] = { - "The specified host is unknown", - "The requested name is valid but does not have an IP address", - "A non-recoverable name server error occurred", - "A temporary error occurred on an authoritative name server", - "An unknown name server error occurred" - }; +void ArchNetworkBSD::throwNameError(int err) { + static const char *s_msg[] = { + "The specified host is unknown", + "The requested name is valid but does not have an IP address", + "A non-recoverable name server error occurred", + "A temporary error occurred on an authoritative name server", + "An unknown name server error occurred"}; - switch (err) { - case HOST_NOT_FOUND: - throw XArchNetworkNameUnknown(s_msg[0]); + switch (err) { + case HOST_NOT_FOUND: + throw XArchNetworkNameUnknown(s_msg[0]); - case NO_DATA: - throw XArchNetworkNameNoAddress(s_msg[1]); + case NO_DATA: + throw XArchNetworkNameNoAddress(s_msg[1]); - case NO_RECOVERY: - throw XArchNetworkNameFailure(s_msg[2]); + case NO_RECOVERY: + throw XArchNetworkNameFailure(s_msg[2]); - case TRY_AGAIN: - throw XArchNetworkNameUnavailable(s_msg[3]); + case TRY_AGAIN: + throw XArchNetworkNameUnavailable(s_msg[3]); - default: - throw XArchNetworkName(s_msg[4]); - } + default: + throw XArchNetworkName(s_msg[4]); + } } diff --git a/src/lib/arch/unix/ArchNetworkBSD.h b/src/lib/arch/unix/ArchNetworkBSD.h index f90e105f7..21c12f313 100644 --- a/src/lib/arch/unix/ArchNetworkBSD.h +++ b/src/lib/arch/unix/ArchNetworkBSD.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -18,21 +18,21 @@ #pragma once -#include "arch/IArchNetwork.h" #include "arch/IArchMultithread.h" +#include "arch/IArchNetwork.h" #if HAVE_SYS_TYPES_H -# include +#include #endif #if HAVE_SYS_SOCKET_H -# include +#include #else struct sockaddr_storage { - unsigned char ss_len; /* address length */ - unsigned char ss_family; /* [XSI] address family */ - char __ss_pad1[_SS_PAD1SIZE]; - long long __ss_align; /* force structure storage alignment */ - char __ss_pad2[_SS_PAD2SIZE]; + unsigned char ss_len; /* address length */ + unsigned char ss_family; /* [XSI] address family */ + char __ss_pad1[_SS_PAD1SIZE]; + long long __ss_align; /* force structure storage alignment */ + char __ss_pad2[_SS_PAD2SIZE]; }; #endif @@ -41,14 +41,14 @@ typedef int socklen_t; #endif #if HAVE_POLL -# include +#include #else -# if HAVE_SYS_SELECT_H -# include -# endif -# if HAVE_SYS_TIME_H -# include -# endif +#if HAVE_SYS_SELECT_H +#include +#endif +#if HAVE_SYS_TIME_H +#include +#endif #endif // old systems may use char* for [gs]etsockopt()'s optval argument. @@ -57,87 +57,85 @@ typedef int socklen_t; typedef char optval_t; #define ARCH_NETWORK ArchNetworkBSD -#define TYPED_ADDR(type_, addr_) (reinterpret_cast(&addr_->m_addr)) +#define TYPED_ADDR(type_, addr_) (reinterpret_cast(&addr_->m_addr)) class ArchSocketImpl { public: - int m_fd; - int m_refCount; + int m_fd; + int m_refCount; }; class ArchNetAddressImpl { public: - ArchNetAddressImpl() : m_len(sizeof(m_addr)) { } + ArchNetAddressImpl() : m_len(sizeof(m_addr)) {} public: - struct sockaddr_storage m_addr; - socklen_t m_len; + struct sockaddr_storage m_addr; + socklen_t m_len; }; //! Berkeley (BSD) sockets implementation of IArchNetwork class ArchNetworkBSD : public IArchNetwork { public: - ArchNetworkBSD(); - ArchNetworkBSD(ArchNetworkBSD const &) =delete; - ArchNetworkBSD(ArchNetworkBSD &&) =delete; - virtual ~ArchNetworkBSD(); + ArchNetworkBSD(); + ArchNetworkBSD(ArchNetworkBSD const &) = delete; + ArchNetworkBSD(ArchNetworkBSD &&) = delete; + virtual ~ArchNetworkBSD(); - ArchNetworkBSD& operator=(ArchNetworkBSD const &) =delete; - ArchNetworkBSD& operator=(ArchNetworkBSD &&) =delete; + ArchNetworkBSD &operator=(ArchNetworkBSD const &) = delete; + ArchNetworkBSD &operator=(ArchNetworkBSD &&) = delete; - virtual void init(); + virtual void init(); - // IArchNetwork overrides - virtual ArchSocket newSocket(EAddressFamily, ESocketType); - virtual ArchSocket copySocket(ArchSocket s); - virtual void closeSocket(ArchSocket s); - virtual void closeSocketForRead(ArchSocket s); - virtual void closeSocketForWrite(ArchSocket s); - virtual void bindSocket(ArchSocket s, ArchNetAddress addr); - virtual void listenOnSocket(ArchSocket s); - virtual ArchSocket acceptSocket(ArchSocket s, ArchNetAddress* addr); - virtual bool connectSocket(ArchSocket s, ArchNetAddress name); - virtual int pollSocket(PollEntry[], int num, double timeout); - virtual void unblockPollSocket(ArchThread thread); - virtual size_t readSocket(ArchSocket s, void* buf, size_t len); - virtual size_t writeSocket(ArchSocket s, - const void* buf, size_t len); - virtual void throwErrorOnSocket(ArchSocket); - virtual bool setNoDelayOnSocket(ArchSocket, bool noDelay); - virtual bool setReuseAddrOnSocket(ArchSocket, bool reuse); - virtual std::string getHostName(); - virtual ArchNetAddress newAnyAddr(EAddressFamily); - virtual ArchNetAddress copyAddr(ArchNetAddress); - virtual std::vector nameToAddr(const std::string&); - virtual void closeAddr(ArchNetAddress); - virtual std::string addrToName(ArchNetAddress); - virtual std::string addrToString(ArchNetAddress); - virtual EAddressFamily getAddrFamily(ArchNetAddress); - virtual void setAddrPort(ArchNetAddress, int port); - virtual int getAddrPort(ArchNetAddress); - virtual bool isAnyAddr(ArchNetAddress); - virtual bool isEqualAddr(ArchNetAddress, ArchNetAddress); + // IArchNetwork overrides + virtual ArchSocket newSocket(EAddressFamily, ESocketType); + virtual ArchSocket copySocket(ArchSocket s); + virtual void closeSocket(ArchSocket s); + virtual void closeSocketForRead(ArchSocket s); + virtual void closeSocketForWrite(ArchSocket s); + virtual void bindSocket(ArchSocket s, ArchNetAddress addr); + virtual void listenOnSocket(ArchSocket s); + virtual ArchSocket acceptSocket(ArchSocket s, ArchNetAddress *addr); + virtual bool connectSocket(ArchSocket s, ArchNetAddress name); + virtual int pollSocket(PollEntry[], int num, double timeout); + virtual void unblockPollSocket(ArchThread thread); + virtual size_t readSocket(ArchSocket s, void *buf, size_t len); + virtual size_t writeSocket(ArchSocket s, const void *buf, size_t len); + virtual void throwErrorOnSocket(ArchSocket); + virtual bool setNoDelayOnSocket(ArchSocket, bool noDelay); + virtual bool setReuseAddrOnSocket(ArchSocket, bool reuse); + virtual std::string getHostName(); + virtual ArchNetAddress newAnyAddr(EAddressFamily); + virtual ArchNetAddress copyAddr(ArchNetAddress); + virtual std::vector nameToAddr(const std::string &); + virtual void closeAddr(ArchNetAddress); + virtual std::string addrToName(ArchNetAddress); + virtual std::string addrToString(ArchNetAddress); + virtual EAddressFamily getAddrFamily(ArchNetAddress); + virtual void setAddrPort(ArchNetAddress, int port); + virtual int getAddrPort(ArchNetAddress); + virtual bool isAnyAddr(ArchNetAddress); + virtual bool isEqualAddr(ArchNetAddress, ArchNetAddress); - struct Connectors - { + struct Connectors { #if HAVE_POLL - int (*poll_impl)(struct pollfd *, nfds_t, int); + int (*poll_impl)(struct pollfd *, nfds_t, int); #endif // HAVE_POLL - Connectors() { + Connectors() { #if HAVE_POLL - poll_impl = poll; + poll_impl = poll; #endif // HAVE_POLL - } - }; - static Connectors s_connectors; + } + }; + static Connectors s_connectors; private: - const int* getUnblockPipe(); - const int* getUnblockPipeForThread(ArchThread); - void setBlockingOnSocket(int fd, bool blocking); - void throwError(int); - void throwNameError(int); + const int *getUnblockPipe(); + const int *getUnblockPipeForThread(ArchThread); + void setBlockingOnSocket(int fd, bool blocking); + void throwError(int); + void throwNameError(int); private: - ArchMutex m_mutex {}; + ArchMutex m_mutex{}; }; diff --git a/src/lib/arch/unix/ArchSleepUnix.cpp b/src/lib/arch/unix/ArchSleepUnix.cpp index ad093c309..3c837d941 100644 --- a/src/lib/arch/unix/ArchSleepUnix.cpp +++ b/src/lib/arch/unix/ArchSleepUnix.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -21,74 +21,67 @@ #include "arch/Arch.h" #if TIME_WITH_SYS_TIME -# include -# include +#include +#include #else -# if HAVE_SYS_TIME_H -# include -# else -# include -# endif +#if HAVE_SYS_TIME_H +#include +#else +#include +#endif #endif #if !HAVE_NANOSLEEP -# if HAVE_SYS_SELECT_H -# include -# endif -# if HAVE_SYS_TYPES_H -# include -# endif -# if HAVE_UNISTD_H -# include -# endif +#if HAVE_SYS_SELECT_H +#include +#endif +#if HAVE_SYS_TYPES_H +#include +#endif +#if HAVE_UNISTD_H +#include +#endif #endif // // ArchSleepUnix // -ArchSleepUnix::ArchSleepUnix() -{ - // do nothing +ArchSleepUnix::ArchSleepUnix() { + // do nothing } -ArchSleepUnix::~ArchSleepUnix() -{ - // do nothing +ArchSleepUnix::~ArchSleepUnix() { + // do nothing } -void -ArchSleepUnix::sleep(double timeout) -{ - ARCH->testCancelThread(); - if (timeout < 0.0) { - return; - } +void ArchSleepUnix::sleep(double timeout) { + ARCH->testCancelThread(); + if (timeout < 0.0) { + return; + } #if HAVE_NANOSLEEP - // prep timeout - struct timespec t; - t.tv_sec = (long)timeout; - t.tv_nsec = (long)(1.0e+9 * (timeout - (double)t.tv_sec)); + // prep timeout + struct timespec t; + t.tv_sec = (long)timeout; + t.tv_nsec = (long)(1.0e+9 * (timeout - (double)t.tv_sec)); - // wait - while (nanosleep(&t, &t) < 0) - ARCH->testCancelThread(); + // wait + while (nanosleep(&t, &t) < 0) + ARCH->testCancelThread(); #else - /* emulate nanosleep() with select() */ - double startTime = ARCH->time(); - double timeLeft = timeout; - while (timeLeft > 0.0) { - struct timeval timeout2; - timeout2.tv_sec = static_cast(timeLeft); - timeout2.tv_usec = static_cast(1.0e+6 * (timeLeft - - timeout2.tv_sec)); - select((SELECT_TYPE_ARG1) 0, - SELECT_TYPE_ARG234 NULL, - SELECT_TYPE_ARG234 NULL, - SELECT_TYPE_ARG234 NULL, - SELECT_TYPE_ARG5 &timeout2); - ARCH->testCancelThread(); - timeLeft = timeout - (ARCH->time() - startTime); - } + /* emulate nanosleep() with select() */ + double startTime = ARCH->time(); + double timeLeft = timeout; + while (timeLeft > 0.0) { + struct timeval timeout2; + timeout2.tv_sec = static_cast(timeLeft); + timeout2.tv_usec = static_cast(1.0e+6 * (timeLeft - timeout2.tv_sec)); + select((SELECT_TYPE_ARG1)0, SELECT_TYPE_ARG234 NULL, + SELECT_TYPE_ARG234 NULL, SELECT_TYPE_ARG234 NULL, + SELECT_TYPE_ARG5 & timeout2); + ARCH->testCancelThread(); + timeLeft = timeout - (ARCH->time() - startTime); + } #endif } diff --git a/src/lib/arch/unix/ArchSleepUnix.h b/src/lib/arch/unix/ArchSleepUnix.h index 0027549bf..6c5abd942 100644 --- a/src/lib/arch/unix/ArchSleepUnix.h +++ b/src/lib/arch/unix/ArchSleepUnix.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -25,9 +25,9 @@ //! Unix implementation of IArchSleep class ArchSleepUnix : public IArchSleep { public: - ArchSleepUnix(); - virtual ~ArchSleepUnix(); + ArchSleepUnix(); + virtual ~ArchSleepUnix(); - // IArchSleep overrides - virtual void sleep(double timeout); + // IArchSleep overrides + virtual void sleep(double timeout); }; diff --git a/src/lib/arch/unix/ArchStringUnix.cpp b/src/lib/arch/unix/ArchStringUnix.cpp index fbb3e098f..87d885c28 100644 --- a/src/lib/arch/unix/ArchStringUnix.cpp +++ b/src/lib/arch/unix/ArchStringUnix.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -27,16 +27,10 @@ #include "arch/multibyte.h" #include "arch/vsnprintf.h" -ArchStringUnix::ArchStringUnix() -{ -} +ArchStringUnix::ArchStringUnix() {} -ArchStringUnix::~ArchStringUnix() -{ -} +ArchStringUnix::~ArchStringUnix() {} -IArchString::EWideCharEncoding -ArchStringUnix::getWideCharEncoding() -{ - return kUCS4; +IArchString::EWideCharEncoding ArchStringUnix::getWideCharEncoding() { + return kUCS4; } diff --git a/src/lib/arch/unix/ArchStringUnix.h b/src/lib/arch/unix/ArchStringUnix.h index ce5c5531d..2fba78017 100644 --- a/src/lib/arch/unix/ArchStringUnix.h +++ b/src/lib/arch/unix/ArchStringUnix.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -25,10 +25,9 @@ //! Unix implementation of IArchString class ArchStringUnix : public IArchString { public: - ArchStringUnix(); - virtual ~ArchStringUnix(); + ArchStringUnix(); + virtual ~ArchStringUnix(); - // IArchString overrides - virtual EWideCharEncoding - getWideCharEncoding(); + // IArchString overrides + virtual EWideCharEncoding getWideCharEncoding(); }; diff --git a/src/lib/arch/unix/ArchSystemUnix.cpp b/src/lib/arch/unix/ArchSystemUnix.cpp index 848f9c328..dc2216a3c 100644 --- a/src/lib/arch/unix/ArchSystemUnix.cpp +++ b/src/lib/arch/unix/ArchSystemUnix.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 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 LICENSE 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 @@ -16,8 +16,8 @@ * along with this program. If not, see . */ -#include #include "arch/unix/ArchSystemUnix.h" +#include #include #ifndef __APPLE__ @@ -28,130 +28,100 @@ // ArchSystemUnix // -ArchSystemUnix::ArchSystemUnix() -{ - // do nothing +ArchSystemUnix::ArchSystemUnix() { + // do nothing } -ArchSystemUnix::~ArchSystemUnix() -{ - // do nothing +ArchSystemUnix::~ArchSystemUnix() { + // do nothing } -std::string -ArchSystemUnix::getOSName() const -{ +std::string ArchSystemUnix::getOSName() const { #if defined(HAVE_SYS_UTSNAME_H) - struct utsname info; - if (uname(&info) == 0) { - std::string msg; - msg += info.sysname; - msg += " "; - msg += info.release; - return msg; - } + struct utsname info; + if (uname(&info) == 0) { + std::string msg; + msg += info.sysname; + msg += " "; + msg += info.release; + return msg; + } #endif - return "Unix"; + return "Unix"; } -std::string -ArchSystemUnix::getPlatformName() const -{ +std::string ArchSystemUnix::getPlatformName() const { #if defined(HAVE_SYS_UTSNAME_H) - struct utsname info; - if (uname(&info) == 0) { - return std::string(info.machine); - } + struct utsname info; + if (uname(&info) == 0) { + return std::string(info.machine); + } #endif - return "unknown"; + return "unknown"; } -std::string -ArchSystemUnix::setting(const std::string&) const -{ - return ""; -} +std::string ArchSystemUnix::setting(const std::string &) const { return ""; } -void -ArchSystemUnix::setting(const std::string&, const std::string&) const -{ -} +void ArchSystemUnix::setting(const std::string &, const std::string &) const {} -std::string -ArchSystemUnix::getLibsUsed(void) const -{ - return "not implemented.\nuse lsof on shell"; +std::string ArchSystemUnix::getLibsUsed(void) const { + return "not implemented.\nuse lsof on shell"; } #ifndef __APPLE__ -bool -ArchSystemUnix::DBusInhibitScreenCall(InhibitScreenServices serviceID, bool state, std::string& error) -{ - error = ""; - static const std::array services = - { - "org.freedesktop.ScreenSaver", - "org.gnome.SessionManager" - }; - static const std::array paths = - { - "/org/freedesktop/ScreenSaver", - "/org/gnome/SessionManager" - }; - static std::array cookies; +bool ArchSystemUnix::DBusInhibitScreenCall(InhibitScreenServices serviceID, + bool state, std::string &error) { + error = ""; + static const std::array services = {"org.freedesktop.ScreenSaver", + "org.gnome.SessionManager"}; + static const std::array paths = {"/org/freedesktop/ScreenSaver", + "/org/gnome/SessionManager"}; + static std::array cookies; - auto serviceNum = static_cast(serviceID); + auto serviceNum = static_cast(serviceID); - QDBusConnection bus = QDBusConnection::sessionBus(); - if (!bus.isConnected()) - { - error = "bus failed to connect"; - return false; + QDBusConnection bus = QDBusConnection::sessionBus(); + if (!bus.isConnected()) { + error = "bus failed to connect"; + return false; + } + + QDBusInterface screenSaverInterface(services[serviceNum], paths[serviceNum], + services[serviceNum], bus); + + if (!screenSaverInterface.isValid()) { + error = "screen saver interface failed to initialize"; + return false; + } + + QDBusReply reply; + if (state) { + if (cookies[serviceNum]) { + error = "coockies are not empty"; + return false; } - QDBusInterface screenSaverInterface( - services[serviceNum], - paths[serviceNum], - services[serviceNum], - bus); - - if (!screenSaverInterface.isValid()) - { - error = "screen saver interface failed to initialize"; - return false; + reply = screenSaverInterface.call( + "Inhibit", "Synergy", + "Sleep is manually prevented by the Synergy preferences"); + if (reply.isValid()) + cookies[serviceNum] = reply.value(); + } else { + if (!cookies[serviceNum]) { + error = "coockies are empty"; + return false; } + reply = screenSaverInterface.call("UnInhibit", cookies[serviceNum]); + cookies[serviceNum] = 0; + } - QDBusReply reply; - if(state) - { - if (cookies[serviceNum]) - { - error = "coockies are not empty"; - return false; - } + if (!reply.isValid()) { + QDBusError qerror = reply.error(); + error = + qerror.name().toStdString() + " : " + qerror.message().toStdString(); + return false; + } - reply = screenSaverInterface.call("Inhibit", "Synergy", "Sleep is manually prevented by the Synergy preferences"); - if (reply.isValid()) - cookies[serviceNum] = reply.value(); - } - else - { - if(!cookies[serviceNum]) - { - error = "coockies are empty"; - return false; - } - reply = screenSaverInterface.call("UnInhibit", cookies[serviceNum]); - cookies[serviceNum] = 0; - } - - if(!reply.isValid()) - { - QDBusError qerror = reply.error(); - error = qerror.name().toStdString() + " : " + qerror.message().toStdString(); - return false; - } - - return true; + return true; } #endif diff --git a/src/lib/arch/unix/ArchSystemUnix.h b/src/lib/arch/unix/ArchSystemUnix.h index 734213952..377d40671 100644 --- a/src/lib/arch/unix/ArchSystemUnix.h +++ b/src/lib/arch/unix/ArchSystemUnix.h @@ -25,21 +25,19 @@ //! Unix implementation of IArchString class ArchSystemUnix : public IArchSystem { public: - ArchSystemUnix(); - virtual ~ArchSystemUnix(); + ArchSystemUnix(); + virtual ~ArchSystemUnix(); - // IArchSystem overrides - virtual std::string getOSName() const; - virtual std::string getPlatformName() const; - virtual std::string setting(const std::string&) const; - virtual void setting(const std::string&, const std::string&) const; - virtual std::string getLibsUsed(void) const; + // IArchSystem overrides + virtual std::string getOSName() const; + virtual std::string getPlatformName() const; + virtual std::string setting(const std::string &) const; + virtual void setting(const std::string &, const std::string &) const; + virtual std::string getLibsUsed(void) const; #ifndef __APPLE__ - enum class InhibitScreenServices { - kScreenSaver, - kSessionManager - }; - static bool DBusInhibitScreenCall(InhibitScreenServices serviceID, bool state, std::string& error); + enum class InhibitScreenServices { kScreenSaver, kSessionManager }; + static bool DBusInhibitScreenCall(InhibitScreenServices serviceID, bool state, + std::string &error); #endif }; diff --git a/src/lib/arch/unix/ArchTaskBarXWindows.cpp b/src/lib/arch/unix/ArchTaskBarXWindows.cpp index 85d8fe79a..db01c7bd1 100644 --- a/src/lib/arch/unix/ArchTaskBarXWindows.cpp +++ b/src/lib/arch/unix/ArchTaskBarXWindows.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2003 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 LICENSE 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 @@ -22,30 +22,22 @@ // ArchTaskBarXWindows // -ArchTaskBarXWindows::ArchTaskBarXWindows() -{ - // do nothing +ArchTaskBarXWindows::ArchTaskBarXWindows() { + // do nothing } -ArchTaskBarXWindows::~ArchTaskBarXWindows() -{ - // do nothing +ArchTaskBarXWindows::~ArchTaskBarXWindows() { + // do nothing } -void -ArchTaskBarXWindows::addReceiver(IArchTaskBarReceiver* /*receiver*/) -{ - // do nothing +void ArchTaskBarXWindows::addReceiver(IArchTaskBarReceiver * /*receiver*/) { + // do nothing } -void -ArchTaskBarXWindows::removeReceiver(IArchTaskBarReceiver* /*receiver*/) -{ - // do nothing +void ArchTaskBarXWindows::removeReceiver(IArchTaskBarReceiver * /*receiver*/) { + // do nothing } -void -ArchTaskBarXWindows::updateReceiver(IArchTaskBarReceiver* /*receiver*/) -{ - // do nothing +void ArchTaskBarXWindows::updateReceiver(IArchTaskBarReceiver * /*receiver*/) { + // do nothing } diff --git a/src/lib/arch/unix/ArchTaskBarXWindows.h b/src/lib/arch/unix/ArchTaskBarXWindows.h index 2bd7c5699..1a6e7dd5e 100644 --- a/src/lib/arch/unix/ArchTaskBarXWindows.h +++ b/src/lib/arch/unix/ArchTaskBarXWindows.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2003 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 LICENSE 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 @@ -25,11 +25,11 @@ //! X11 implementation of IArchTaskBar class ArchTaskBarXWindows : public IArchTaskBar { public: - ArchTaskBarXWindows(); - virtual ~ArchTaskBarXWindows(); + ArchTaskBarXWindows(); + virtual ~ArchTaskBarXWindows(); - // IArchTaskBar overrides - virtual void addReceiver(IArchTaskBarReceiver*); - virtual void removeReceiver(IArchTaskBarReceiver*); - virtual void updateReceiver(IArchTaskBarReceiver*); + // IArchTaskBar overrides + virtual void addReceiver(IArchTaskBarReceiver *); + virtual void removeReceiver(IArchTaskBarReceiver *); + virtual void updateReceiver(IArchTaskBarReceiver *); }; diff --git a/src/lib/arch/unix/ArchTimeUnix.cpp b/src/lib/arch/unix/ArchTimeUnix.cpp index cc5d7a389..fd6e91a51 100644 --- a/src/lib/arch/unix/ArchTimeUnix.cpp +++ b/src/lib/arch/unix/ArchTimeUnix.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -19,34 +19,30 @@ #include "arch/unix/ArchTimeUnix.h" #if TIME_WITH_SYS_TIME -# include -# include +#include +#include #else -# if HAVE_SYS_TIME_H -# include -# else -# include -# endif +#if HAVE_SYS_TIME_H +#include +#else +#include +#endif #endif // // ArchTimeUnix // -ArchTimeUnix::ArchTimeUnix() -{ - // do nothing +ArchTimeUnix::ArchTimeUnix() { + // do nothing } -ArchTimeUnix::~ArchTimeUnix() -{ - // do nothing +ArchTimeUnix::~ArchTimeUnix() { + // do nothing } -double -ArchTimeUnix::time() -{ - struct timeval t; - gettimeofday(&t, NULL); - return (double)t.tv_sec + 1.0e-6 * (double)t.tv_usec; +double ArchTimeUnix::time() { + struct timeval t; + gettimeofday(&t, NULL); + return (double)t.tv_sec + 1.0e-6 * (double)t.tv_usec; } diff --git a/src/lib/arch/unix/ArchTimeUnix.h b/src/lib/arch/unix/ArchTimeUnix.h index 770bf32eb..fe8133d78 100644 --- a/src/lib/arch/unix/ArchTimeUnix.h +++ b/src/lib/arch/unix/ArchTimeUnix.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -25,9 +25,9 @@ //! Generic Unix implementation of IArchTime class ArchTimeUnix : public IArchTime { public: - ArchTimeUnix(); - virtual ~ArchTimeUnix(); + ArchTimeUnix(); + virtual ~ArchTimeUnix(); - // IArchTime overrides - virtual double time(); + // IArchTime overrides + virtual double time(); }; diff --git a/src/lib/arch/unix/XArchUnix.cpp b/src/lib/arch/unix/XArchUnix.cpp index 5178bbfe6..a85c935de 100644 --- a/src/lib/arch/unix/XArchUnix.cpp +++ b/src/lib/arch/unix/XArchUnix.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -24,9 +24,7 @@ // XArchEvalUnix // -std::string -XArchEvalUnix::eval() const -{ - // FIXME -- not thread safe - return strerror(m_error); +std::string XArchEvalUnix::eval() const { + // FIXME -- not thread safe + return strerror(m_error); } diff --git a/src/lib/arch/unix/XArchUnix.h b/src/lib/arch/unix/XArchUnix.h index 53c9f5b10..c91c6931e 100644 --- a/src/lib/arch/unix/XArchUnix.h +++ b/src/lib/arch/unix/XArchUnix.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -23,11 +23,11 @@ //! Lazy error message string evaluation for unix class XArchEvalUnix : public XArchEval { public: - XArchEvalUnix(int error) : m_error(error) { } - virtual ~XArchEvalUnix() _NOEXCEPT { } + XArchEvalUnix(int error) : m_error(error) {} + virtual ~XArchEvalUnix() _NOEXCEPT {} - virtual std::string eval() const; + virtual std::string eval() const; private: - int m_error; + int m_error; }; diff --git a/src/lib/arch/vsnprintf.h b/src/lib/arch/vsnprintf.h index f6216ee88..56dd02e9e 100644 --- a/src/lib/arch/vsnprintf.h +++ b/src/lib/arch/vsnprintf.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -21,43 +21,38 @@ #if HAVE_VSNPRINTF #if !defined(ARCH_VSNPRINTF) -# define ARCH_VSNPRINTF vsnprintf +#define ARCH_VSNPRINTF vsnprintf #endif -int -IArchString::vsnprintf(char* str, int size, const char* fmt, va_list ap) -{ - int n = ::ARCH_VSNPRINTF(str, size, fmt, ap); - if (n > size) { - n = -1; - } - return n; +int IArchString::vsnprintf(char *str, int size, const char *fmt, va_list ap) { + int n = ::ARCH_VSNPRINTF(str, size, fmt, ap); + if (n > size) { + n = -1; + } + return n; } #elif SYSAPI_UNIX // !HAVE_VSNPRINTF #include -int -IArchString::vsnprintf(char* str, int size, const char* fmt, va_list ap) -{ - static FILE* bitbucket = fopen("/dev/null", "w"); - if (bitbucket == NULL) { - // uh oh - if (size > 0) { - str[0] = '\0'; - } - return 0; +int IArchString::vsnprintf(char *str, int size, const char *fmt, va_list ap) { + static FILE *bitbucket = fopen("/dev/null", "w"); + if (bitbucket == NULL) { + // uh oh + if (size > 0) { + str[0] = '\0'; } - else { - // count the characters using the bitbucket - int n = vfprintf(bitbucket, fmt, ap); - if (n + 1 <= size) { - // it'll fit so print it into str - vsprintf(str, fmt, ap); - } - return n; + return 0; + } else { + // count the characters using the bitbucket + int n = vfprintf(bitbucket, fmt, ap); + if (n + 1 <= size) { + // it'll fit so print it into str + vsprintf(str, fmt, ap); } + return n; + } } #else // !HAVE_VSNPRINTF && !SYSAPI_UNIX diff --git a/src/lib/arch/win32/ArchConsoleWindows.cpp b/src/lib/arch/win32/ArchConsoleWindows.cpp index 6a1a5ff6b..d6b3eb8b4 100644 --- a/src/lib/arch/win32/ArchConsoleWindows.cpp +++ b/src/lib/arch/win32/ArchConsoleWindows.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -18,6 +18,6 @@ #include "arch/win32/ArchConsoleWindows.h" -ArchConsoleWindows::ArchConsoleWindows() { } +ArchConsoleWindows::ArchConsoleWindows() {} -ArchConsoleWindows::~ArchConsoleWindows() { } +ArchConsoleWindows::~ArchConsoleWindows() {} diff --git a/src/lib/arch/win32/ArchConsoleWindows.h b/src/lib/arch/win32/ArchConsoleWindows.h index 4342de303..beb8b447a 100644 --- a/src/lib/arch/win32/ArchConsoleWindows.h +++ b/src/lib/arch/win32/ArchConsoleWindows.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -24,6 +24,6 @@ class ArchConsoleWindows : public ArchConsoleStd { public: - ArchConsoleWindows(); - virtual ~ArchConsoleWindows(); + ArchConsoleWindows(); + virtual ~ArchConsoleWindows(); }; diff --git a/src/lib/arch/win32/ArchDaemonWindows.cpp b/src/lib/arch/win32/ArchDaemonWindows.cpp index 9c29be356..1b2cc059d 100644 --- a/src/lib/arch/win32/ArchDaemonWindows.cpp +++ b/src/lib/arch/win32/ArchDaemonWindows.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -17,9 +17,9 @@ */ #include "arch/win32/ArchDaemonWindows.h" +#include "arch/Arch.h" #include "arch/win32/ArchMiscWindows.h" #include "arch/win32/XArchWindows.h" -#include "arch/Arch.h" #include "common/stdvector.h" #include @@ -28,685 +28,602 @@ // ArchDaemonWindows // -ArchDaemonWindows* ArchDaemonWindows::s_daemon = NULL; +ArchDaemonWindows *ArchDaemonWindows::s_daemon = NULL; -ArchDaemonWindows::ArchDaemonWindows() : -m_daemonThreadID(0) -{ - m_quitMessage = RegisterWindowMessage("SynergyDaemonExit"); +ArchDaemonWindows::ArchDaemonWindows() : m_daemonThreadID(0) { + m_quitMessage = RegisterWindowMessage("SynergyDaemonExit"); } -ArchDaemonWindows::~ArchDaemonWindows() -{ - // do nothing +ArchDaemonWindows::~ArchDaemonWindows() { + // do nothing } -int -ArchDaemonWindows::runDaemon(RunFunc runFunc) -{ - assert(s_daemon != NULL); - return s_daemon->doRunDaemon(runFunc); +int ArchDaemonWindows::runDaemon(RunFunc runFunc) { + assert(s_daemon != NULL); + return s_daemon->doRunDaemon(runFunc); } -void -ArchDaemonWindows::daemonRunning(bool running) -{ - if (s_daemon != NULL) { - s_daemon->doDaemonRunning(running); - } +void ArchDaemonWindows::daemonRunning(bool running) { + if (s_daemon != NULL) { + s_daemon->doDaemonRunning(running); + } } -UINT -ArchDaemonWindows::getDaemonQuitMessage() -{ - if (s_daemon != NULL) { - return s_daemon->doGetDaemonQuitMessage(); - } - else { - return 0; - } +UINT ArchDaemonWindows::getDaemonQuitMessage() { + if (s_daemon != NULL) { + return s_daemon->doGetDaemonQuitMessage(); + } else { + return 0; + } } -void -ArchDaemonWindows::daemonFailed(int result) -{ - assert(s_daemon != NULL); - throw XArchDaemonRunFailed(result); +void ArchDaemonWindows::daemonFailed(int result) { + assert(s_daemon != NULL); + throw XArchDaemonRunFailed(result); } -void -ArchDaemonWindows::installDaemon(const char* name, - const char* description, - const char* pathname, - const char* commandLine, - const char* dependencies) -{ - // open service manager - SC_HANDLE mgr = OpenSCManager(NULL, NULL, GENERIC_WRITE); - if (mgr == NULL) { - // can't open service manager - throw XArchDaemonInstallFailed(new XArchEvalWindows); +void ArchDaemonWindows::installDaemon(const char *name, const char *description, + const char *pathname, + const char *commandLine, + const char *dependencies) { + // open service manager + SC_HANDLE mgr = OpenSCManager(NULL, NULL, GENERIC_WRITE); + if (mgr == NULL) { + // can't open service manager + throw XArchDaemonInstallFailed(new XArchEvalWindows); + } + + // create the service + SC_HANDLE service = + CreateService(mgr, name, name, 0, + SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS, + SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, pathname, NULL, + NULL, dependencies, NULL, NULL); + + if (service == NULL) { + // can't create service + DWORD err = GetLastError(); + if (err != ERROR_SERVICE_EXISTS) { + CloseServiceHandle(mgr); + throw XArchDaemonInstallFailed(new XArchEvalWindows(err)); } - - // create the service - SC_HANDLE service = CreateService( - mgr, - name, - name, - 0, - SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS, - SERVICE_AUTO_START, - SERVICE_ERROR_NORMAL, - pathname, - NULL, - NULL, - dependencies, - NULL, - NULL); - - if (service == NULL) { - // can't create service - DWORD err = GetLastError(); - if (err != ERROR_SERVICE_EXISTS) { - CloseServiceHandle(mgr); - throw XArchDaemonInstallFailed(new XArchEvalWindows(err)); - } - } - else { - // done with service (but only try to close if not null) - CloseServiceHandle(service); - } - - // done with manager - CloseServiceHandle(mgr); - - // open the registry key for this service - HKEY key = openNTServicesKey(); - key = ArchMiscWindows::addKey(key, name); - if (key == NULL) { - // can't open key - DWORD err = GetLastError(); - try { - uninstallDaemon(name); - } - catch (...) { - // ignore - } - throw XArchDaemonInstallFailed(new XArchEvalWindows(err)); - } - - // set the description - ArchMiscWindows::setValue(key, _T("Description"), description); - - // set command line - key = ArchMiscWindows::addKey(key, _T("Parameters")); - if (key == NULL) { - // can't open key - DWORD err = GetLastError(); - ArchMiscWindows::closeKey(key); - try { - uninstallDaemon(name); - } - catch (...) { - // ignore - } - throw XArchDaemonInstallFailed(new XArchEvalWindows(err)); - } - ArchMiscWindows::setValue(key, _T("CommandLine"), commandLine); - - // done with registry - ArchMiscWindows::closeKey(key); -} - -void -ArchDaemonWindows::uninstallDaemon(const char* name) -{ - // remove parameters for this service. ignore failures. - HKEY key = openNTServicesKey(); - key = ArchMiscWindows::openKey(key, name); - if (key != NULL) { - ArchMiscWindows::deleteKey(key, _T("Parameters")); - ArchMiscWindows::closeKey(key); - } - - // open service manager - SC_HANDLE mgr = OpenSCManager(NULL, NULL, GENERIC_WRITE); - if (mgr == NULL) { - // can't open service manager - throw XArchDaemonUninstallFailed(new XArchEvalWindows); - } - - // open the service. oddly, you must open a service to delete it. - SC_HANDLE service = OpenService(mgr, name, DELETE | SERVICE_STOP); - if (service == NULL) { - DWORD err = GetLastError(); - CloseServiceHandle(mgr); - if (err != ERROR_SERVICE_DOES_NOT_EXIST) { - throw XArchDaemonUninstallFailed(new XArchEvalWindows(err)); - } - throw XArchDaemonUninstallNotInstalled(new XArchEvalWindows(err)); - } - - // stop the service. we don't care if we fail. - SERVICE_STATUS status; - ControlService(service, SERVICE_CONTROL_STOP, &status); - - // delete the service - const bool okay = (DeleteService(service) == 0); - const DWORD err = GetLastError(); - - // clean up + } else { + // done with service (but only try to close if not null) CloseServiceHandle(service); - CloseServiceHandle(mgr); + } - // give windows a chance to remove the service before - // we check if it still exists. - ARCH->sleep(1); - - // handle failure. ignore error if service isn't installed anymore. - if (!okay && isDaemonInstalled(name)) { - if (err == ERROR_SUCCESS) { - // this seems to occur even though the uninstall was successful. - // it could be a timing issue, i.e., isDaemonInstalled is - // called too soon. i've added a sleep to try and stop this. - return; - } - if (err == ERROR_IO_PENDING) { - // this seems to be a spurious error - return; - } - if (err != ERROR_SERVICE_MARKED_FOR_DELETE) { - throw XArchDaemonUninstallFailed(new XArchEvalWindows(err)); - } - throw XArchDaemonUninstallNotInstalled(new XArchEvalWindows(err)); - } -} - -int -ArchDaemonWindows::daemonize(const char* name, DaemonFunc func) -{ - assert(name != NULL); - assert(func != NULL); - - // save daemon function - m_daemonFunc = func; - - // construct the service entry - SERVICE_TABLE_ENTRY entry[2]; - entry[0].lpServiceName = const_cast(name); - entry[0].lpServiceProc = &ArchDaemonWindows::serviceMainEntry; - entry[1].lpServiceName = NULL; - entry[1].lpServiceProc = NULL; - - // hook us up to the service control manager. this won't return - // (if successful) until the processes have terminated. - s_daemon = this; - if (StartServiceCtrlDispatcher(entry) == 0) { - // StartServiceCtrlDispatcher failed - s_daemon = NULL; - throw XArchDaemonFailed(new XArchEvalWindows); - } - - s_daemon = NULL; - return m_daemonResult; -} - -bool -ArchDaemonWindows::canInstallDaemon(const char* /*name*/) -{ - // check if we can open service manager for write - SC_HANDLE mgr = OpenSCManager(NULL, NULL, GENERIC_WRITE); - if (mgr == NULL) { - return false; - } - CloseServiceHandle(mgr); - - // check if we can open the registry key - HKEY key = openNTServicesKey(); - ArchMiscWindows::closeKey(key); - - return (key != NULL); -} - -bool -ArchDaemonWindows::isDaemonInstalled(const char* name) -{ - // open service manager - SC_HANDLE mgr = OpenSCManager(NULL, NULL, GENERIC_READ); - if (mgr == NULL) { - return false; - } - - // open the service - SC_HANDLE service = OpenService(mgr, name, GENERIC_READ); - - // clean up - if (service != NULL) { - CloseServiceHandle(service); - } - CloseServiceHandle(mgr); - - return (service != NULL); -} - -HKEY -ArchDaemonWindows::openNTServicesKey() -{ - static const char* s_keyNames[] = { - _T("SYSTEM"), - _T("CurrentControlSet"), - _T("Services"), - NULL - }; - - return ArchMiscWindows::addKey(HKEY_LOCAL_MACHINE, s_keyNames); -} - -bool -ArchDaemonWindows::isRunState(DWORD state) -{ - switch (state) { - case SERVICE_START_PENDING: - case SERVICE_CONTINUE_PENDING: - case SERVICE_RUNNING: - return true; - - default: - return false; - } -} - -int -ArchDaemonWindows::doRunDaemon(RunFunc run) -{ - // should only be called from DaemonFunc - assert(m_serviceMutex != NULL); - assert(run != NULL); - - // create message queue for this thread - MSG dummy; - PeekMessage(&dummy, NULL, 0, 0, PM_NOREMOVE); - - int result = 0; - ARCH->lockMutex(m_serviceMutex); - m_daemonThreadID = GetCurrentThreadId(); - while (m_serviceState != SERVICE_STOPPED) { - // wait until we're told to start - while (!isRunState(m_serviceState) && - m_serviceState != SERVICE_STOP_PENDING) { - ARCH->waitCondVar(m_serviceCondVar, m_serviceMutex, -1.0); - } - - // run unless told to stop - if (m_serviceState != SERVICE_STOP_PENDING) { - ARCH->unlockMutex(m_serviceMutex); - try { - result = run(); - } - catch (...) { - ARCH->lockMutex(m_serviceMutex); - setStatusError(0); - m_serviceState = SERVICE_STOPPED; - setStatus(m_serviceState); - ARCH->broadcastCondVar(m_serviceCondVar); - ARCH->unlockMutex(m_serviceMutex); - throw; - } - ARCH->lockMutex(m_serviceMutex); - } - - // notify of new state - if (m_serviceState == SERVICE_PAUSE_PENDING) { - m_serviceState = SERVICE_PAUSED; - } - else { - m_serviceState = SERVICE_STOPPED; - } - setStatus(m_serviceState); - ARCH->broadcastCondVar(m_serviceCondVar); - } - ARCH->unlockMutex(m_serviceMutex); - return result; -} - -void -ArchDaemonWindows::doDaemonRunning(bool running) -{ - ARCH->lockMutex(m_serviceMutex); - if (running) { - m_serviceState = SERVICE_RUNNING; - setStatus(m_serviceState); - ARCH->broadcastCondVar(m_serviceCondVar); - } - ARCH->unlockMutex(m_serviceMutex); -} - -UINT -ArchDaemonWindows::doGetDaemonQuitMessage() -{ - return m_quitMessage; -} - -void -ArchDaemonWindows::setStatus(DWORD state) -{ - setStatus(state, 0, 0); -} - -void -ArchDaemonWindows::setStatus(DWORD state, DWORD step, DWORD waitHint) -{ - assert(s_daemon != NULL); - - SERVICE_STATUS status; - status.dwServiceType = SERVICE_WIN32_OWN_PROCESS | - SERVICE_INTERACTIVE_PROCESS; - status.dwCurrentState = state; - status.dwControlsAccepted = SERVICE_ACCEPT_STOP | - SERVICE_ACCEPT_PAUSE_CONTINUE | - SERVICE_ACCEPT_SHUTDOWN; - status.dwWin32ExitCode = NO_ERROR; - status.dwServiceSpecificExitCode = 0; - status.dwCheckPoint = step; - status.dwWaitHint = waitHint; - SetServiceStatus(s_daemon->m_statusHandle, &status); -} - -void -ArchDaemonWindows::setStatusError(DWORD error) -{ - assert(s_daemon != NULL); - - SERVICE_STATUS status; - status.dwServiceType = SERVICE_WIN32_OWN_PROCESS | - SERVICE_INTERACTIVE_PROCESS; - status.dwCurrentState = SERVICE_STOPPED; - status.dwControlsAccepted = SERVICE_ACCEPT_STOP | - SERVICE_ACCEPT_PAUSE_CONTINUE | - SERVICE_ACCEPT_SHUTDOWN; - status.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR; - status.dwServiceSpecificExitCode = error; - status.dwCheckPoint = 0; - status.dwWaitHint = 0; - SetServiceStatus(s_daemon->m_statusHandle, &status); -} - -void -ArchDaemonWindows::serviceMain(DWORD argc, LPTSTR* argvIn) -{ - typedef std::vector ArgList; - typedef std::vector Arguments; - const char** argv = const_cast(argvIn); - - // create synchronization objects - m_serviceMutex = ARCH->newMutex(); - m_serviceCondVar = ARCH->newCondVar(); - - // register our service handler function - m_statusHandle = RegisterServiceCtrlHandler(argv[0], - &ArchDaemonWindows::serviceHandlerEntry); - if (m_statusHandle == 0) { - // cannot start as service - m_daemonResult = -1; - ARCH->closeCondVar(m_serviceCondVar); - ARCH->closeMutex(m_serviceMutex); - return; - } - - // tell service control manager that we're starting - m_serviceState = SERVICE_START_PENDING; - setStatus(m_serviceState, 0, 10000); - - std::string commandLine; - - // if no arguments supplied then try getting them from the registry. - // the first argument doesn't count because it's the service name. - Arguments args; - ArgList myArgv; - if (argc <= 1) { - // read command line - HKEY key = openNTServicesKey(); - key = ArchMiscWindows::openKey(key, argvIn[0]); - key = ArchMiscWindows::openKey(key, _T("Parameters")); - if (key != NULL) { - commandLine = ArchMiscWindows::readValueString(key, - _T("CommandLine")); - } - - // if the command line isn't empty then parse and use it - if (!commandLine.empty()) { - // parse, honoring double quoted substrings - std::string::size_type i = commandLine.find_first_not_of(" \t"); - while (i != std::string::npos && i != commandLine.size()) { - // find end of string - std::string::size_type e; - if (commandLine[i] == '\"') { - // quoted. find closing quote. - ++i; - e = commandLine.find("\"", i); - - // whitespace must follow closing quote - if (e == std::string::npos || - (e + 1 != commandLine.size() && - commandLine[e + 1] != ' ' && - commandLine[e + 1] != '\t')) { - args.clear(); - break; - } - - // extract - args.push_back(commandLine.substr(i, e - i)); - i = e + 1; - } - else { - // unquoted. find next whitespace. - e = commandLine.find_first_of(" \t", i); - if (e == std::string::npos) { - e = commandLine.size(); - } - - // extract - args.push_back(commandLine.substr(i, e - i)); - i = e + 1; - } - - // next argument - i = commandLine.find_first_not_of(" \t", i); - } - - // service name goes first - myArgv.push_back(argv[0]); - - // get pointers - for (size_t j = 0; j < args.size(); ++j) { - myArgv.push_back(args[j].c_str()); - } - - // adjust argc/argv - argc = (DWORD)myArgv.size(); - argv = &myArgv[0]; - } - } - - m_commandLine = commandLine; + // done with manager + CloseServiceHandle(mgr); + // open the registry key for this service + HKEY key = openNTServicesKey(); + key = ArchMiscWindows::addKey(key, name); + if (key == NULL) { + // can't open key + DWORD err = GetLastError(); try { - // invoke daemon function - m_daemonResult = m_daemonFunc(static_cast(argc), argv); + uninstallDaemon(name); + } catch (...) { + // ignore } - catch (XArchDaemonRunFailed& e) { - setStatusError(e.m_result); - m_daemonResult = -1; + throw XArchDaemonInstallFailed(new XArchEvalWindows(err)); + } + + // set the description + ArchMiscWindows::setValue(key, _T("Description"), description); + + // set command line + key = ArchMiscWindows::addKey(key, _T("Parameters")); + if (key == NULL) { + // can't open key + DWORD err = GetLastError(); + ArchMiscWindows::closeKey(key); + try { + uninstallDaemon(name); + } catch (...) { + // ignore } - catch (...) { - setStatusError(1); - m_daemonResult = -1; + throw XArchDaemonInstallFailed(new XArchEvalWindows(err)); + } + ArchMiscWindows::setValue(key, _T("CommandLine"), commandLine); + + // done with registry + ArchMiscWindows::closeKey(key); +} + +void ArchDaemonWindows::uninstallDaemon(const char *name) { + // remove parameters for this service. ignore failures. + HKEY key = openNTServicesKey(); + key = ArchMiscWindows::openKey(key, name); + if (key != NULL) { + ArchMiscWindows::deleteKey(key, _T("Parameters")); + ArchMiscWindows::closeKey(key); + } + + // open service manager + SC_HANDLE mgr = OpenSCManager(NULL, NULL, GENERIC_WRITE); + if (mgr == NULL) { + // can't open service manager + throw XArchDaemonUninstallFailed(new XArchEvalWindows); + } + + // open the service. oddly, you must open a service to delete it. + SC_HANDLE service = OpenService(mgr, name, DELETE | SERVICE_STOP); + if (service == NULL) { + DWORD err = GetLastError(); + CloseServiceHandle(mgr); + if (err != ERROR_SERVICE_DOES_NOT_EXIST) { + throw XArchDaemonUninstallFailed(new XArchEvalWindows(err)); + } + throw XArchDaemonUninstallNotInstalled(new XArchEvalWindows(err)); + } + + // stop the service. we don't care if we fail. + SERVICE_STATUS status; + ControlService(service, SERVICE_CONTROL_STOP, &status); + + // delete the service + const bool okay = (DeleteService(service) == 0); + const DWORD err = GetLastError(); + + // clean up + CloseServiceHandle(service); + CloseServiceHandle(mgr); + + // give windows a chance to remove the service before + // we check if it still exists. + ARCH->sleep(1); + + // handle failure. ignore error if service isn't installed anymore. + if (!okay && isDaemonInstalled(name)) { + if (err == ERROR_SUCCESS) { + // this seems to occur even though the uninstall was successful. + // it could be a timing issue, i.e., isDaemonInstalled is + // called too soon. i've added a sleep to try and stop this. + return; + } + if (err == ERROR_IO_PENDING) { + // this seems to be a spurious error + return; + } + if (err != ERROR_SERVICE_MARKED_FOR_DELETE) { + throw XArchDaemonUninstallFailed(new XArchEvalWindows(err)); + } + throw XArchDaemonUninstallNotInstalled(new XArchEvalWindows(err)); + } +} + +int ArchDaemonWindows::daemonize(const char *name, DaemonFunc func) { + assert(name != NULL); + assert(func != NULL); + + // save daemon function + m_daemonFunc = func; + + // construct the service entry + SERVICE_TABLE_ENTRY entry[2]; + entry[0].lpServiceName = const_cast(name); + entry[0].lpServiceProc = &ArchDaemonWindows::serviceMainEntry; + entry[1].lpServiceName = NULL; + entry[1].lpServiceProc = NULL; + + // hook us up to the service control manager. this won't return + // (if successful) until the processes have terminated. + s_daemon = this; + if (StartServiceCtrlDispatcher(entry) == 0) { + // StartServiceCtrlDispatcher failed + s_daemon = NULL; + throw XArchDaemonFailed(new XArchEvalWindows); + } + + s_daemon = NULL; + return m_daemonResult; +} + +bool ArchDaemonWindows::canInstallDaemon(const char * /*name*/) { + // check if we can open service manager for write + SC_HANDLE mgr = OpenSCManager(NULL, NULL, GENERIC_WRITE); + if (mgr == NULL) { + return false; + } + CloseServiceHandle(mgr); + + // check if we can open the registry key + HKEY key = openNTServicesKey(); + ArchMiscWindows::closeKey(key); + + return (key != NULL); +} + +bool ArchDaemonWindows::isDaemonInstalled(const char *name) { + // open service manager + SC_HANDLE mgr = OpenSCManager(NULL, NULL, GENERIC_READ); + if (mgr == NULL) { + return false; + } + + // open the service + SC_HANDLE service = OpenService(mgr, name, GENERIC_READ); + + // clean up + if (service != NULL) { + CloseServiceHandle(service); + } + CloseServiceHandle(mgr); + + return (service != NULL); +} + +HKEY ArchDaemonWindows::openNTServicesKey() { + static const char *s_keyNames[] = {_T("SYSTEM"), _T("CurrentControlSet"), + _T("Services"), NULL}; + + return ArchMiscWindows::addKey(HKEY_LOCAL_MACHINE, s_keyNames); +} + +bool ArchDaemonWindows::isRunState(DWORD state) { + switch (state) { + case SERVICE_START_PENDING: + case SERVICE_CONTINUE_PENDING: + case SERVICE_RUNNING: + return true; + + default: + return false; + } +} + +int ArchDaemonWindows::doRunDaemon(RunFunc run) { + // should only be called from DaemonFunc + assert(m_serviceMutex != NULL); + assert(run != NULL); + + // create message queue for this thread + MSG dummy; + PeekMessage(&dummy, NULL, 0, 0, PM_NOREMOVE); + + int result = 0; + ARCH->lockMutex(m_serviceMutex); + m_daemonThreadID = GetCurrentThreadId(); + while (m_serviceState != SERVICE_STOPPED) { + // wait until we're told to start + while (!isRunState(m_serviceState) && + m_serviceState != SERVICE_STOP_PENDING) { + ARCH->waitCondVar(m_serviceCondVar, m_serviceMutex, -1.0); } - // clean up + // run unless told to stop + if (m_serviceState != SERVICE_STOP_PENDING) { + ARCH->unlockMutex(m_serviceMutex); + try { + result = run(); + } catch (...) { + ARCH->lockMutex(m_serviceMutex); + setStatusError(0); + m_serviceState = SERVICE_STOPPED; + setStatus(m_serviceState); + ARCH->broadcastCondVar(m_serviceCondVar); + ARCH->unlockMutex(m_serviceMutex); + throw; + } + ARCH->lockMutex(m_serviceMutex); + } + + // notify of new state + if (m_serviceState == SERVICE_PAUSE_PENDING) { + m_serviceState = SERVICE_PAUSED; + } else { + m_serviceState = SERVICE_STOPPED; + } + setStatus(m_serviceState); + ARCH->broadcastCondVar(m_serviceCondVar); + } + ARCH->unlockMutex(m_serviceMutex); + return result; +} + +void ArchDaemonWindows::doDaemonRunning(bool running) { + ARCH->lockMutex(m_serviceMutex); + if (running) { + m_serviceState = SERVICE_RUNNING; + setStatus(m_serviceState); + ARCH->broadcastCondVar(m_serviceCondVar); + } + ARCH->unlockMutex(m_serviceMutex); +} + +UINT ArchDaemonWindows::doGetDaemonQuitMessage() { return m_quitMessage; } + +void ArchDaemonWindows::setStatus(DWORD state) { setStatus(state, 0, 0); } + +void ArchDaemonWindows::setStatus(DWORD state, DWORD step, DWORD waitHint) { + assert(s_daemon != NULL); + + SERVICE_STATUS status; + status.dwServiceType = + SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS; + status.dwCurrentState = state; + status.dwControlsAccepted = SERVICE_ACCEPT_STOP | + SERVICE_ACCEPT_PAUSE_CONTINUE | + SERVICE_ACCEPT_SHUTDOWN; + status.dwWin32ExitCode = NO_ERROR; + status.dwServiceSpecificExitCode = 0; + status.dwCheckPoint = step; + status.dwWaitHint = waitHint; + SetServiceStatus(s_daemon->m_statusHandle, &status); +} + +void ArchDaemonWindows::setStatusError(DWORD error) { + assert(s_daemon != NULL); + + SERVICE_STATUS status; + status.dwServiceType = + SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS; + status.dwCurrentState = SERVICE_STOPPED; + status.dwControlsAccepted = SERVICE_ACCEPT_STOP | + SERVICE_ACCEPT_PAUSE_CONTINUE | + SERVICE_ACCEPT_SHUTDOWN; + status.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR; + status.dwServiceSpecificExitCode = error; + status.dwCheckPoint = 0; + status.dwWaitHint = 0; + SetServiceStatus(s_daemon->m_statusHandle, &status); +} + +void ArchDaemonWindows::serviceMain(DWORD argc, LPTSTR *argvIn) { + typedef std::vector ArgList; + typedef std::vector Arguments; + const char **argv = const_cast(argvIn); + + // create synchronization objects + m_serviceMutex = ARCH->newMutex(); + m_serviceCondVar = ARCH->newCondVar(); + + // register our service handler function + m_statusHandle = RegisterServiceCtrlHandler( + argv[0], &ArchDaemonWindows::serviceHandlerEntry); + if (m_statusHandle == 0) { + // cannot start as service + m_daemonResult = -1; ARCH->closeCondVar(m_serviceCondVar); ARCH->closeMutex(m_serviceMutex); + return; + } - // we're going to exit now, so set status to stopped - m_serviceState = SERVICE_STOPPED; - setStatus(m_serviceState, 0, 10000); -} + // tell service control manager that we're starting + m_serviceState = SERVICE_START_PENDING; + setStatus(m_serviceState, 0, 10000); -void WINAPI -ArchDaemonWindows::serviceMainEntry(DWORD argc, LPTSTR* argv) -{ - s_daemon->serviceMain(argc, argv); -} + std::string commandLine; -void -ArchDaemonWindows::serviceHandler(DWORD ctrl) -{ - assert(m_serviceMutex != NULL); - assert(m_serviceCondVar != NULL); - - ARCH->lockMutex(m_serviceMutex); - - // ignore request if service is already stopped - if (s_daemon == NULL || m_serviceState == SERVICE_STOPPED) { - if (s_daemon != NULL) { - setStatus(m_serviceState); - } - ARCH->unlockMutex(m_serviceMutex); - return; + // if no arguments supplied then try getting them from the registry. + // the first argument doesn't count because it's the service name. + Arguments args; + ArgList myArgv; + if (argc <= 1) { + // read command line + HKEY key = openNTServicesKey(); + key = ArchMiscWindows::openKey(key, argvIn[0]); + key = ArchMiscWindows::openKey(key, _T("Parameters")); + if (key != NULL) { + commandLine = ArchMiscWindows::readValueString(key, _T("CommandLine")); } - switch (ctrl) { - case SERVICE_CONTROL_PAUSE: - m_serviceState = SERVICE_PAUSE_PENDING; - setStatus(m_serviceState, 0, 5000); - PostThreadMessage(m_daemonThreadID, m_quitMessage, 0, 0); - while (isRunState(m_serviceState)) { - ARCH->waitCondVar(m_serviceCondVar, m_serviceMutex, -1.0); + // if the command line isn't empty then parse and use it + if (!commandLine.empty()) { + // parse, honoring double quoted substrings + std::string::size_type i = commandLine.find_first_not_of(" \t"); + while (i != std::string::npos && i != commandLine.size()) { + // find end of string + std::string::size_type e; + if (commandLine[i] == '\"') { + // quoted. find closing quote. + ++i; + e = commandLine.find("\"", i); + + // whitespace must follow closing quote + if (e == std::string::npos || + (e + 1 != commandLine.size() && commandLine[e + 1] != ' ' && + commandLine[e + 1] != '\t')) { + args.clear(); + break; + } + + // extract + args.push_back(commandLine.substr(i, e - i)); + i = e + 1; + } else { + // unquoted. find next whitespace. + e = commandLine.find_first_of(" \t", i); + if (e == std::string::npos) { + e = commandLine.size(); + } + + // extract + args.push_back(commandLine.substr(i, e - i)); + i = e + 1; } - break; - case SERVICE_CONTROL_CONTINUE: - // FIXME -- maybe should flush quit messages from queue - m_serviceState = SERVICE_CONTINUE_PENDING; - setStatus(m_serviceState, 0, 5000); - ARCH->broadcastCondVar(m_serviceCondVar); - break; + // next argument + i = commandLine.find_first_not_of(" \t", i); + } - case SERVICE_CONTROL_STOP: - case SERVICE_CONTROL_SHUTDOWN: - m_serviceState = SERVICE_STOP_PENDING; - setStatus(m_serviceState, 0, 5000); - PostThreadMessage(m_daemonThreadID, m_quitMessage, 0, 0); - ARCH->broadcastCondVar(m_serviceCondVar); - while (isRunState(m_serviceState)) { - ARCH->waitCondVar(m_serviceCondVar, m_serviceMutex, -1.0); - } - break; + // service name goes first + myArgv.push_back(argv[0]); - default: - // unknown service command - // fall through + // get pointers + for (size_t j = 0; j < args.size(); ++j) { + myArgv.push_back(args[j].c_str()); + } - case SERVICE_CONTROL_INTERROGATE: - setStatus(m_serviceState); - break; + // adjust argc/argv + argc = (DWORD)myArgv.size(); + argv = &myArgv[0]; } + } + m_commandLine = commandLine; + + try { + // invoke daemon function + m_daemonResult = m_daemonFunc(static_cast(argc), argv); + } catch (XArchDaemonRunFailed &e) { + setStatusError(e.m_result); + m_daemonResult = -1; + } catch (...) { + setStatusError(1); + m_daemonResult = -1; + } + + // clean up + ARCH->closeCondVar(m_serviceCondVar); + ARCH->closeMutex(m_serviceMutex); + + // we're going to exit now, so set status to stopped + m_serviceState = SERVICE_STOPPED; + setStatus(m_serviceState, 0, 10000); +} + +void WINAPI ArchDaemonWindows::serviceMainEntry(DWORD argc, LPTSTR *argv) { + s_daemon->serviceMain(argc, argv); +} + +void ArchDaemonWindows::serviceHandler(DWORD ctrl) { + assert(m_serviceMutex != NULL); + assert(m_serviceCondVar != NULL); + + ARCH->lockMutex(m_serviceMutex); + + // ignore request if service is already stopped + if (s_daemon == NULL || m_serviceState == SERVICE_STOPPED) { + if (s_daemon != NULL) { + setStatus(m_serviceState); + } ARCH->unlockMutex(m_serviceMutex); + return; + } + + switch (ctrl) { + case SERVICE_CONTROL_PAUSE: + m_serviceState = SERVICE_PAUSE_PENDING; + setStatus(m_serviceState, 0, 5000); + PostThreadMessage(m_daemonThreadID, m_quitMessage, 0, 0); + while (isRunState(m_serviceState)) { + ARCH->waitCondVar(m_serviceCondVar, m_serviceMutex, -1.0); + } + break; + + case SERVICE_CONTROL_CONTINUE: + // FIXME -- maybe should flush quit messages from queue + m_serviceState = SERVICE_CONTINUE_PENDING; + setStatus(m_serviceState, 0, 5000); + ARCH->broadcastCondVar(m_serviceCondVar); + break; + + case SERVICE_CONTROL_STOP: + case SERVICE_CONTROL_SHUTDOWN: + m_serviceState = SERVICE_STOP_PENDING; + setStatus(m_serviceState, 0, 5000); + PostThreadMessage(m_daemonThreadID, m_quitMessage, 0, 0); + ARCH->broadcastCondVar(m_serviceCondVar); + while (isRunState(m_serviceState)) { + ARCH->waitCondVar(m_serviceCondVar, m_serviceMutex, -1.0); + } + break; + + default: + // unknown service command + // fall through + + case SERVICE_CONTROL_INTERROGATE: + setStatus(m_serviceState); + break; + } + + ARCH->unlockMutex(m_serviceMutex); } -void WINAPI -ArchDaemonWindows::serviceHandlerEntry(DWORD ctrl) -{ - s_daemon->serviceHandler(ctrl); +void WINAPI ArchDaemonWindows::serviceHandlerEntry(DWORD ctrl) { + s_daemon->serviceHandler(ctrl); } -void -ArchDaemonWindows::start(const char* name) -{ - // open service manager - SC_HANDLE mgr = OpenSCManager(NULL, NULL, GENERIC_READ); - if (mgr == NULL) { - throw XArchDaemonFailed(new XArchEvalWindows()); - } +void ArchDaemonWindows::start(const char *name) { + // open service manager + SC_HANDLE mgr = OpenSCManager(NULL, NULL, GENERIC_READ); + if (mgr == NULL) { + throw XArchDaemonFailed(new XArchEvalWindows()); + } - // open the service - SC_HANDLE service = OpenService( - mgr, name, SERVICE_START); + // open the service + SC_HANDLE service = OpenService(mgr, name, SERVICE_START); - if (service == NULL) { - CloseServiceHandle(mgr); - throw XArchDaemonFailed(new XArchEvalWindows()); - } + if (service == NULL) { + CloseServiceHandle(mgr); + throw XArchDaemonFailed(new XArchEvalWindows()); + } - // start the service - if (!StartService(service, 0, NULL)) { - throw XArchDaemonFailed(new XArchEvalWindows()); - } + // start the service + if (!StartService(service, 0, NULL)) { + throw XArchDaemonFailed(new XArchEvalWindows()); + } } -void -ArchDaemonWindows::stop(const char* name) -{ - // open service manager - SC_HANDLE mgr = OpenSCManager(NULL, NULL, GENERIC_READ); - if (mgr == NULL) { - throw XArchDaemonFailed(new XArchEvalWindows()); - } +void ArchDaemonWindows::stop(const char *name) { + // open service manager + SC_HANDLE mgr = OpenSCManager(NULL, NULL, GENERIC_READ); + if (mgr == NULL) { + throw XArchDaemonFailed(new XArchEvalWindows()); + } - // open the service - SC_HANDLE service = OpenService( - mgr, name, - SERVICE_STOP | SERVICE_QUERY_STATUS); + // open the service + SC_HANDLE service = + OpenService(mgr, name, SERVICE_STOP | SERVICE_QUERY_STATUS); - if (service == NULL) { - CloseServiceHandle(mgr); - throw XArchDaemonFailed(new XArchEvalWindows()); - } + if (service == NULL) { + CloseServiceHandle(mgr); + throw XArchDaemonFailed(new XArchEvalWindows()); + } - // ask the service to stop, asynchronously - SERVICE_STATUS ss; - if (!ControlService(service, SERVICE_CONTROL_STOP, &ss)) { - DWORD dwErrCode = GetLastError(); - if (dwErrCode != ERROR_SERVICE_NOT_ACTIVE) { - throw XArchDaemonFailed(new XArchEvalWindows()); - } + // ask the service to stop, asynchronously + SERVICE_STATUS ss; + if (!ControlService(service, SERVICE_CONTROL_STOP, &ss)) { + DWORD dwErrCode = GetLastError(); + if (dwErrCode != ERROR_SERVICE_NOT_ACTIVE) { + throw XArchDaemonFailed(new XArchEvalWindows()); } + } } -void -ArchDaemonWindows::installDaemon() -{ - // install default daemon if not already installed. - if (!isDaemonInstalled(DEFAULT_DAEMON_NAME)) { - char path[MAX_PATH]; - GetModuleFileName(ArchMiscWindows::instanceWin32(), path, MAX_PATH); - - // wrap in quotes so a malicious user can't start \Program.exe as admin. - std::stringstream ss; - ss << '"'; - ss << path; - ss << '"'; +void ArchDaemonWindows::installDaemon() { + // install default daemon if not already installed. + if (!isDaemonInstalled(DEFAULT_DAEMON_NAME)) { + char path[MAX_PATH]; + GetModuleFileName(ArchMiscWindows::instanceWin32(), path, MAX_PATH); - installDaemon(DEFAULT_DAEMON_NAME, DEFAULT_DAEMON_INFO, ss.str().c_str(), "", ""); - } + // wrap in quotes so a malicious user can't start \Program.exe as admin. + std::stringstream ss; + ss << '"'; + ss << path; + ss << '"'; - start(DEFAULT_DAEMON_NAME); + installDaemon(DEFAULT_DAEMON_NAME, DEFAULT_DAEMON_INFO, ss.str().c_str(), + "", ""); + } + + start(DEFAULT_DAEMON_NAME); } -void -ArchDaemonWindows::uninstallDaemon() -{ - // remove legacy services if installed. - if (isDaemonInstalled(LEGACY_SERVER_DAEMON_NAME)) { - uninstallDaemon(LEGACY_SERVER_DAEMON_NAME); - } - if (isDaemonInstalled(LEGACY_CLIENT_DAEMON_NAME)) { - uninstallDaemon(LEGACY_CLIENT_DAEMON_NAME); - } +void ArchDaemonWindows::uninstallDaemon() { + // remove legacy services if installed. + if (isDaemonInstalled(LEGACY_SERVER_DAEMON_NAME)) { + uninstallDaemon(LEGACY_SERVER_DAEMON_NAME); + } + if (isDaemonInstalled(LEGACY_CLIENT_DAEMON_NAME)) { + uninstallDaemon(LEGACY_CLIENT_DAEMON_NAME); + } - // remove new service if installed. - if (isDaemonInstalled(DEFAULT_DAEMON_NAME)) { - uninstallDaemon(DEFAULT_DAEMON_NAME); - } + // remove new service if installed. + if (isDaemonInstalled(DEFAULT_DAEMON_NAME)) { + uninstallDaemon(DEFAULT_DAEMON_NAME); + } } diff --git a/src/lib/arch/win32/ArchDaemonWindows.h b/src/lib/arch/win32/ArchDaemonWindows.h index a3be9a58e..bad076e52 100644 --- a/src/lib/arch/win32/ArchDaemonWindows.h +++ b/src/lib/arch/win32/ArchDaemonWindows.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -31,112 +31,110 @@ //! Win32 implementation of IArchDaemon class ArchDaemonWindows : public IArchDaemon { public: - typedef int (*RunFunc)(void); + typedef int (*RunFunc)(void); - ArchDaemonWindows(); - virtual ~ArchDaemonWindows(); + ArchDaemonWindows(); + virtual ~ArchDaemonWindows(); - //! Run the daemon - /*! - When the client calls \c daemonize(), the \c DaemonFunc should call this - function after initialization and argument parsing to perform the - daemon processing. The \c runFunc should perform the daemon's - main loop, calling \c daemonRunning(true) when it enters the main loop - (i.e. after initialization) and \c daemonRunning(false) when it leaves - the main loop. The \c runFunc is called in a new thread and when the - daemon must exit the main loop due to some external control the - getDaemonQuitMessage() is posted to the thread. This function returns - what \c runFunc returns. \c runFunc should call \c daemonFailed() if - the daemon fails. - */ - static int runDaemon(RunFunc runFunc); + //! Run the daemon + /*! + When the client calls \c daemonize(), the \c DaemonFunc should call this + function after initialization and argument parsing to perform the + daemon processing. The \c runFunc should perform the daemon's + main loop, calling \c daemonRunning(true) when it enters the main loop + (i.e. after initialization) and \c daemonRunning(false) when it leaves + the main loop. The \c runFunc is called in a new thread and when the + daemon must exit the main loop due to some external control the + getDaemonQuitMessage() is posted to the thread. This function returns + what \c runFunc returns. \c runFunc should call \c daemonFailed() if + the daemon fails. + */ + static int runDaemon(RunFunc runFunc); - //! Indicate daemon is in main loop - /*! - The \c runFunc passed to \c runDaemon() should call this function - to indicate when it has entered (\c running is \c true) or exited - (\c running is \c false) the main loop. - */ - static void daemonRunning(bool running); + //! Indicate daemon is in main loop + /*! + The \c runFunc passed to \c runDaemon() should call this function + to indicate when it has entered (\c running is \c true) or exited + (\c running is \c false) the main loop. + */ + static void daemonRunning(bool running); - //! Indicate failure of running daemon - /*! - The \c runFunc passed to \c runDaemon() should call this function - to indicate failure. \c result is returned by \c daemonize(). - */ - static void daemonFailed(int result); + //! Indicate failure of running daemon + /*! + The \c runFunc passed to \c runDaemon() should call this function + to indicate failure. \c result is returned by \c daemonize(). + */ + static void daemonFailed(int result); - //! Get daemon quit message - /*! - The windows NT daemon tells daemon thread to exit by posting this - message to it. The thread must, of course, have a message queue - for this to work. - */ - static UINT getDaemonQuitMessage(); + //! Get daemon quit message + /*! + The windows NT daemon tells daemon thread to exit by posting this + message to it. The thread must, of course, have a message queue + for this to work. + */ + static UINT getDaemonQuitMessage(); - // IArchDaemon overrides - virtual void installDaemon(const char* name, - const char* description, - const char* pathname, - const char* commandLine, - const char* dependencies); - virtual void uninstallDaemon(const char* name); - virtual void installDaemon(); - virtual void uninstallDaemon(); - virtual int daemonize(const char* name, DaemonFunc func); - virtual bool canInstallDaemon(const char* name); - virtual bool isDaemonInstalled(const char* name); - std::string commandLine() const { return m_commandLine; } + // IArchDaemon overrides + virtual void installDaemon(const char *name, const char *description, + const char *pathname, const char *commandLine, + const char *dependencies); + virtual void uninstallDaemon(const char *name); + virtual void installDaemon(); + virtual void uninstallDaemon(); + virtual int daemonize(const char *name, DaemonFunc func); + virtual bool canInstallDaemon(const char *name); + virtual bool isDaemonInstalled(const char *name); + std::string commandLine() const { return m_commandLine; } private: - static HKEY openNTServicesKey(); + static HKEY openNTServicesKey(); - int doRunDaemon(RunFunc runFunc); - void doDaemonRunning(bool running); - UINT doGetDaemonQuitMessage(); + int doRunDaemon(RunFunc runFunc); + void doDaemonRunning(bool running); + UINT doGetDaemonQuitMessage(); - static void setStatus(DWORD state); - static void setStatus(DWORD state, DWORD step, DWORD waitHint); - static void setStatusError(DWORD error); + static void setStatus(DWORD state); + static void setStatus(DWORD state, DWORD step, DWORD waitHint); + static void setStatusError(DWORD error); - static bool isRunState(DWORD state); + static bool isRunState(DWORD state); - void serviceMain(DWORD, LPTSTR*); - static void WINAPI serviceMainEntry(DWORD, LPTSTR*); + void serviceMain(DWORD, LPTSTR *); + static void WINAPI serviceMainEntry(DWORD, LPTSTR *); - void serviceHandler(DWORD ctrl); - static void WINAPI serviceHandlerEntry(DWORD ctrl); + void serviceHandler(DWORD ctrl); + static void WINAPI serviceHandlerEntry(DWORD ctrl); - void start(const char* name); - void stop(const char* name); + void start(const char *name); + void stop(const char *name); private: - class XArchDaemonRunFailed { - public: - XArchDaemonRunFailed(int result) : m_result(result) { } + class XArchDaemonRunFailed { + public: + XArchDaemonRunFailed(int result) : m_result(result) {} - public: - int m_result; - }; + public: + int m_result; + }; private: - static ArchDaemonWindows* s_daemon; + static ArchDaemonWindows *s_daemon; - ArchMutex m_serviceMutex; - ArchCond m_serviceCondVar; - DWORD m_serviceState; - bool m_serviceHandlerWaiting; - bool m_serviceRunning; + ArchMutex m_serviceMutex; + ArchCond m_serviceCondVar; + DWORD m_serviceState; + bool m_serviceHandlerWaiting; + bool m_serviceRunning; - DWORD m_daemonThreadID; - DaemonFunc m_daemonFunc; - int m_daemonResult; + DWORD m_daemonThreadID; + DaemonFunc m_daemonFunc; + int m_daemonResult; - SERVICE_STATUS_HANDLE m_statusHandle; + SERVICE_STATUS_HANDLE m_statusHandle; - UINT m_quitMessage; + UINT m_quitMessage; - std::string m_commandLine; + std::string m_commandLine; }; #define DEFAULT_DAEMON_NAME _T("Synergy") @@ -145,10 +143,6 @@ private: #define LEGACY_SERVER_DAEMON_NAME _T("Synergy Server") #define LEGACY_CLIENT_DAEMON_NAME _T("Synergy Client") -static const TCHAR* const g_daemonKeyPath[] = { - _T("SOFTWARE"), - _T("The Synergy Project"), - _T("Synergy"), - _T("Service"), - NULL -}; +static const TCHAR *const g_daemonKeyPath[] = { + _T("SOFTWARE"), _T("The Synergy Project"), _T("Synergy"), _T("Service"), + NULL}; diff --git a/src/lib/arch/win32/ArchFileWindows.cpp b/src/lib/arch/win32/ArchFileWindows.cpp index 38679c1b5..d5a727a04 100644 --- a/src/lib/arch/win32/ArchFileWindows.cpp +++ b/src/lib/arch/win32/ArchFileWindows.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -21,183 +21,157 @@ #define WIN32_LEAN_AND_MEAN #include #include -#include #include +#include // // ArchFileWindows // -ArchFileWindows::ArchFileWindows() -{ - // do nothing +ArchFileWindows::ArchFileWindows() { + // do nothing } -ArchFileWindows::~ArchFileWindows() -{ - // do nothing +ArchFileWindows::~ArchFileWindows() { + // do nothing } -const char* -ArchFileWindows::getBasename(const char* pathname) -{ - if (pathname == NULL) { - return NULL; - } +const char *ArchFileWindows::getBasename(const char *pathname) { + if (pathname == NULL) { + return NULL; + } - // check for last slash - const char* basename = strrchr(pathname, '/'); - if (basename != NULL) { - ++basename; - } - else { - basename = pathname; - } + // check for last slash + const char *basename = strrchr(pathname, '/'); + if (basename != NULL) { + ++basename; + } else { + basename = pathname; + } - // check for last backslash - const char* basename2 = strrchr(pathname, '\\'); - if (basename2 != NULL && basename2 > basename) { - basename = basename2 + 1; - } + // check for last backslash + const char *basename2 = strrchr(pathname, '\\'); + if (basename2 != NULL && basename2 > basename) { + basename = basename2 + 1; + } - return basename; + return basename; } -std::string -ArchFileWindows::getUserDirectory() -{ - // try %HOMEPATH% - TCHAR dir[MAX_PATH]; - DWORD size = sizeof(dir) / sizeof(TCHAR); - DWORD result = GetEnvironmentVariable(_T("HOMEPATH"), dir, size); - if (result != 0 && result <= size) { - // sanity check -- if dir doesn't appear to start with a - // drive letter and isn't a UNC name then don't use it - // FIXME -- allow UNC names - if (dir[0] != '\0' && (dir[1] == ':' || - ((dir[0] == '\\' || dir[0] == '/') && - (dir[1] == '\\' || dir[1] == '/')))) { - return dir; - } +std::string ArchFileWindows::getUserDirectory() { + // try %HOMEPATH% + TCHAR dir[MAX_PATH]; + DWORD size = sizeof(dir) / sizeof(TCHAR); + DWORD result = GetEnvironmentVariable(_T("HOMEPATH"), dir, size); + if (result != 0 && result <= size) { + // sanity check -- if dir doesn't appear to start with a + // drive letter and isn't a UNC name then don't use it + // FIXME -- allow UNC names + if (dir[0] != '\0' && + (dir[1] == ':' || ((dir[0] == '\\' || dir[0] == '/') && + (dir[1] == '\\' || dir[1] == '/')))) { + return dir; + } + } + + // get the location of the personal files. that's as close to + // a home directory as we're likely to find. + ITEMIDLIST *idl; + if (SUCCEEDED(SHGetSpecialFolderLocation(NULL, CSIDL_PERSONAL, &idl))) { + TCHAR *path = NULL; + if (SHGetPathFromIDList(idl, dir)) { + DWORD attr = GetFileAttributes(dir); + if (attr != 0xffffffff && (attr & FILE_ATTRIBUTE_DIRECTORY) != 0) + path = dir; } - // get the location of the personal files. that's as close to - // a home directory as we're likely to find. - ITEMIDLIST* idl; - if (SUCCEEDED(SHGetSpecialFolderLocation(NULL, CSIDL_PERSONAL, &idl))) { - TCHAR* path = NULL; - if (SHGetPathFromIDList(idl, dir)) { - DWORD attr = GetFileAttributes(dir); - if (attr != 0xffffffff && (attr & FILE_ATTRIBUTE_DIRECTORY) != 0) - path = dir; - } - - IMalloc* shalloc; - if (SUCCEEDED(SHGetMalloc(&shalloc))) { - shalloc->Free(idl); - shalloc->Release(); - } - - if (path != NULL) { - return path; - } + IMalloc *shalloc; + if (SUCCEEDED(SHGetMalloc(&shalloc))) { + shalloc->Free(idl); + shalloc->Release(); } - // use root of C drive as a default + if (path != NULL) { + return path; + } + } + + // use root of C drive as a default + return "C:"; +} + +std::string ArchFileWindows::getSystemDirectory() { + // get windows directory + char dir[MAX_PATH]; + if (GetWindowsDirectory(dir, sizeof(dir)) != 0) { + return dir; + } else { + // can't get it. use C:\ as a default. return "C:"; + } } -std::string -ArchFileWindows::getSystemDirectory() -{ - // get windows directory - char dir[MAX_PATH]; - if (GetWindowsDirectory(dir, sizeof(dir)) != 0) { - return dir; - } - else { - // can't get it. use C:\ as a default. - return "C:"; +std::string ArchFileWindows::getInstalledDirectory() { + char fileNameBuffer[MAX_PATH]; + GetModuleFileName(NULL, fileNameBuffer, MAX_PATH); + std::string fileName(fileNameBuffer); + size_t lastSlash = fileName.find_last_of("\\"); + fileName = fileName.substr(0, lastSlash); + + return fileName; +} + +std::string ArchFileWindows::getLogDirectory() { + return getInstalledDirectory(); +} + +std::string ArchFileWindows::getPluginDirectory() { + if (!m_pluginDirectory.empty()) { + return m_pluginDirectory; + } + + std::string dir = getProfileDirectory(); + dir.append("\\Plugins"); + return dir; +} + +std::string ArchFileWindows::getProfileDirectory() { + String dir; + if (!m_profileDirectory.empty()) { + dir = m_profileDirectory; + } else { + TCHAR result[MAX_PATH]; + if (SUCCEEDED( + SHGetFolderPath(NULL, CSIDL_LOCAL_APPDATA, NULL, 0, result))) { + dir = result; + } else { + dir = getUserDirectory(); } + } + + // HACK: append program name, this seems wrong. + dir.append("\\Synergy"); + + return dir; } -std::string -ArchFileWindows::getInstalledDirectory() -{ - char fileNameBuffer[MAX_PATH]; - GetModuleFileName(NULL, fileNameBuffer, MAX_PATH); - std::string fileName(fileNameBuffer); - size_t lastSlash = fileName.find_last_of("\\"); - fileName = fileName.substr(0, lastSlash); - - return fileName; +std::string ArchFileWindows::concatPath(const std::string &prefix, + const std::string &suffix) { + std::string path; + path.reserve(prefix.size() + 1 + suffix.size()); + path += prefix; + if (path.size() == 0 || + (path[path.size() - 1] != '\\' && path[path.size() - 1] != '/')) { + path += '\\'; + } + path += suffix; + return path; } -std::string -ArchFileWindows::getLogDirectory() -{ - return getInstalledDirectory(); +void ArchFileWindows::setProfileDirectory(const String &s) { + m_profileDirectory = s; } -std::string -ArchFileWindows::getPluginDirectory() -{ - if (!m_pluginDirectory.empty()) { - return m_pluginDirectory; - } - - std::string dir = getProfileDirectory(); - dir.append("\\Plugins"); - return dir; -} - -std::string -ArchFileWindows::getProfileDirectory() -{ - String dir; - if (!m_profileDirectory.empty()) { - dir = m_profileDirectory; - } - else { - TCHAR result[MAX_PATH]; - if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_LOCAL_APPDATA, NULL, 0, result))) { - dir = result; - } - else { - dir = getUserDirectory(); - } - } - - // HACK: append program name, this seems wrong. - dir.append("\\Synergy"); - - return dir; -} - -std::string -ArchFileWindows::concatPath(const std::string& prefix, - const std::string& suffix) -{ - std::string path; - path.reserve(prefix.size() + 1 + suffix.size()); - path += prefix; - if (path.size() == 0 || - (path[path.size() - 1] != '\\' && - path[path.size() - 1] != '/')) { - path += '\\'; - } - path += suffix; - return path; -} - -void -ArchFileWindows::setProfileDirectory(const String& s) -{ - m_profileDirectory = s; -} - -void -ArchFileWindows::setPluginDirectory(const String& s) -{ - m_pluginDirectory = s; +void ArchFileWindows::setPluginDirectory(const String &s) { + m_pluginDirectory = s; } diff --git a/src/lib/arch/win32/ArchFileWindows.h b/src/lib/arch/win32/ArchFileWindows.h index be1bdf811..218863def 100644 --- a/src/lib/arch/win32/ArchFileWindows.h +++ b/src/lib/arch/win32/ArchFileWindows.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -25,23 +25,23 @@ //! Win32 implementation of IArchFile class ArchFileWindows : public IArchFile { public: - ArchFileWindows(); - virtual ~ArchFileWindows(); + ArchFileWindows(); + virtual ~ArchFileWindows(); - // IArchFile overrides - virtual const char* getBasename(const char* pathname); - virtual std::string getUserDirectory(); - virtual std::string getSystemDirectory(); - virtual std::string getInstalledDirectory(); - virtual std::string getLogDirectory(); - virtual std::string getPluginDirectory(); - virtual std::string getProfileDirectory(); - virtual std::string concatPath(const std::string& prefix, - const std::string& suffix); - virtual void setProfileDirectory(const String& s); - virtual void setPluginDirectory(const String& s); + // IArchFile overrides + virtual const char *getBasename(const char *pathname); + virtual std::string getUserDirectory(); + virtual std::string getSystemDirectory(); + virtual std::string getInstalledDirectory(); + virtual std::string getLogDirectory(); + virtual std::string getPluginDirectory(); + virtual std::string getProfileDirectory(); + virtual std::string concatPath(const std::string &prefix, + const std::string &suffix); + virtual void setProfileDirectory(const String &s); + virtual void setPluginDirectory(const String &s); private: - String m_profileDirectory; - String m_pluginDirectory; + String m_profileDirectory; + String m_pluginDirectory; }; diff --git a/src/lib/arch/win32/ArchLogWindows.cpp b/src/lib/arch/win32/ArchLogWindows.cpp index f9b24bd01..7006251ac 100644 --- a/src/lib/arch/win32/ArchLogWindows.cpp +++ b/src/lib/arch/win32/ArchLogWindows.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -25,71 +25,60 @@ // ArchLogWindows // -ArchLogWindows::ArchLogWindows() : m_eventLog(NULL) -{ - // do nothing +ArchLogWindows::ArchLogWindows() : m_eventLog(NULL) { + // do nothing } -ArchLogWindows::~ArchLogWindows() -{ - // do nothing +ArchLogWindows::~ArchLogWindows() { + // do nothing } -void -ArchLogWindows::openLog(const char* name) -{ - if (m_eventLog == NULL) { - m_eventLog = RegisterEventSource(NULL, name); - } -} - -void -ArchLogWindows::closeLog() -{ - if (m_eventLog != NULL) { - DeregisterEventSource(m_eventLog); - m_eventLog = NULL; - } -} - -void -ArchLogWindows::showLog(bool) -{ - // do nothing -} - -void -ArchLogWindows::writeLog(ELevel level, const char* msg) -{ - if (m_eventLog != NULL) { - // convert priority - WORD type; - switch (level) { - case kERROR: - type = EVENTLOG_ERROR_TYPE; - break; - - case kWARNING: - type = EVENTLOG_WARNING_TYPE; - break; - - default: - type = EVENTLOG_INFORMATION_TYPE; - break; - } - - // log it - // FIXME -- win32 wants to use a message table to look up event - // strings. log messages aren't organized that way so we'll - // just dump our string into the raw data section of the event - // so users can at least see the message. note that we use our - // level as the event category. - ReportEvent(m_eventLog, type, static_cast(level), - 0, // event ID - NULL, - 0, - (DWORD)strlen(msg) + 1, // raw data size - NULL, - const_cast(msg));// raw data +void ArchLogWindows::openLog(const char *name) { + if (m_eventLog == NULL) { + m_eventLog = RegisterEventSource(NULL, name); + } +} + +void ArchLogWindows::closeLog() { + if (m_eventLog != NULL) { + DeregisterEventSource(m_eventLog); + m_eventLog = NULL; + } +} + +void ArchLogWindows::showLog(bool) { + // do nothing +} + +void ArchLogWindows::writeLog(ELevel level, const char *msg) { + if (m_eventLog != NULL) { + // convert priority + WORD type; + switch (level) { + case kERROR: + type = EVENTLOG_ERROR_TYPE; + break; + + case kWARNING: + type = EVENTLOG_WARNING_TYPE; + break; + + default: + type = EVENTLOG_INFORMATION_TYPE; + break; } + + // log it + // FIXME -- win32 wants to use a message table to look up event + // strings. log messages aren't organized that way so we'll + // just dump our string into the raw data section of the event + // so users can at least see the message. note that we use our + // level as the event category. + ReportEvent(m_eventLog, type, static_cast(level), + 0, // event ID + NULL, 0, + (DWORD)strlen(msg) + 1, // raw data size + NULL, + const_cast(msg)); // raw data + } } diff --git a/src/lib/arch/win32/ArchLogWindows.h b/src/lib/arch/win32/ArchLogWindows.h index 68e1ab056..f5cbef821 100644 --- a/src/lib/arch/win32/ArchLogWindows.h +++ b/src/lib/arch/win32/ArchLogWindows.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -28,15 +28,15 @@ //! Win32 implementation of IArchLog class ArchLogWindows : public IArchLog { public: - ArchLogWindows(); - virtual ~ArchLogWindows(); + ArchLogWindows(); + virtual ~ArchLogWindows(); - // IArchLog overrides - virtual void openLog(const char* name); - virtual void closeLog(); - virtual void showLog(bool showIfEmpty); - virtual void writeLog(ELevel, const char*); + // IArchLog overrides + virtual void openLog(const char *name); + virtual void closeLog(); + virtual void showLog(bool showIfEmpty); + virtual void writeLog(ELevel, const char *); private: - HANDLE m_eventLog; + HANDLE m_eventLog; }; diff --git a/src/lib/arch/win32/ArchMiscWindows.cpp b/src/lib/arch/win32/ArchMiscWindows.cpp index 7a6b3d525..a2f2cf820 100644 --- a/src/lib/arch/win32/ArchMiscWindows.cpp +++ b/src/lib/arch/win32/ArchMiscWindows.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -22,21 +22,21 @@ #include "common/Version.h" #include -#pragma warning(disable: 4099) +#pragma warning(disable : 4099) #include -#pragma warning(default: 4099) +#pragma warning(default : 4099) // parent process name for services in Vista #define SERVICE_LAUNCHER "services.exe" #ifndef ES_SYSTEM_REQUIRED -#define ES_SYSTEM_REQUIRED ((DWORD)0x00000001) +#define ES_SYSTEM_REQUIRED ((DWORD)0x00000001) #endif #ifndef ES_DISPLAY_REQUIRED #define ES_DISPLAY_REQUIRED ((DWORD)0x00000002) #endif #ifndef ES_CONTINUOUS -#define ES_CONTINUOUS ((DWORD)0x80000000) +#define ES_CONTINUOUS ((DWORD)0x80000000) #endif typedef DWORD EXECUTION_STATE; @@ -44,481 +44,400 @@ typedef DWORD EXECUTION_STATE; // ArchMiscWindows // -ArchMiscWindows::Dialogs* ArchMiscWindows::s_dialogs = NULL; -DWORD ArchMiscWindows::s_busyState = 0; -ArchMiscWindows::STES_t ArchMiscWindows::s_stes = NULL; -HICON ArchMiscWindows::s_largeIcon = NULL; -HICON ArchMiscWindows::s_smallIcon = NULL; -HINSTANCE ArchMiscWindows::s_instanceWin32 = NULL; +ArchMiscWindows::Dialogs *ArchMiscWindows::s_dialogs = NULL; +DWORD ArchMiscWindows::s_busyState = 0; +ArchMiscWindows::STES_t ArchMiscWindows::s_stes = NULL; +HICON ArchMiscWindows::s_largeIcon = NULL; +HICON ArchMiscWindows::s_smallIcon = NULL; +HINSTANCE ArchMiscWindows::s_instanceWin32 = NULL; -void -ArchMiscWindows::cleanup() -{ - delete s_dialogs; +void ArchMiscWindows::cleanup() { delete s_dialogs; } + +void ArchMiscWindows::init() { + // stop windows system error dialogs from showing. + SetErrorMode(SEM_FAILCRITICALERRORS); + + s_dialogs = new Dialogs; } -void -ArchMiscWindows::init() -{ - // stop windows system error dialogs from showing. - SetErrorMode(SEM_FAILCRITICALERRORS); - - s_dialogs = new Dialogs; +void ArchMiscWindows::setIcons(HICON largeIcon, HICON smallIcon) { + s_largeIcon = largeIcon; + s_smallIcon = smallIcon; } -void -ArchMiscWindows::setIcons(HICON largeIcon, HICON smallIcon) -{ - s_largeIcon = largeIcon; - s_smallIcon = smallIcon; +void ArchMiscWindows::getIcons(HICON &largeIcon, HICON &smallIcon) { + largeIcon = s_largeIcon; + smallIcon = s_smallIcon; } -void -ArchMiscWindows::getIcons(HICON& largeIcon, HICON& smallIcon) -{ - largeIcon = s_largeIcon; - smallIcon = s_smallIcon; +int ArchMiscWindows::runDaemon(RunFunc runFunc) { + return ArchDaemonWindows::runDaemon(runFunc); } -int -ArchMiscWindows::runDaemon(RunFunc runFunc) -{ - return ArchDaemonWindows::runDaemon(runFunc); +void ArchMiscWindows::daemonRunning(bool running) { + ArchDaemonWindows::daemonRunning(running); } -void -ArchMiscWindows::daemonRunning(bool running) -{ - ArchDaemonWindows::daemonRunning(running); +void ArchMiscWindows::daemonFailed(int result) { + ArchDaemonWindows::daemonFailed(result); } -void -ArchMiscWindows::daemonFailed(int result) -{ - ArchDaemonWindows::daemonFailed(result); +UINT ArchMiscWindows::getDaemonQuitMessage() { + return ArchDaemonWindows::getDaemonQuitMessage(); } -UINT -ArchMiscWindows::getDaemonQuitMessage() -{ - return ArchDaemonWindows::getDaemonQuitMessage(); +HKEY ArchMiscWindows::openKey(HKEY key, const TCHAR *keyName) { + return openKey(key, keyName, false); } -HKEY -ArchMiscWindows::openKey(HKEY key, const TCHAR* keyName) -{ - return openKey(key, keyName, false); +HKEY ArchMiscWindows::openKey(HKEY key, const TCHAR *const *keyNames) { + return openKey(key, keyNames, false); } -HKEY -ArchMiscWindows::openKey(HKEY key, const TCHAR* const* keyNames) -{ - return openKey(key, keyNames, false); +HKEY ArchMiscWindows::addKey(HKEY key, const TCHAR *keyName) { + return openKey(key, keyName, true); } -HKEY -ArchMiscWindows::addKey(HKEY key, const TCHAR* keyName) -{ - return openKey(key, keyName, true); +HKEY ArchMiscWindows::addKey(HKEY key, const TCHAR *const *keyNames) { + return openKey(key, keyNames, true); } -HKEY -ArchMiscWindows::addKey(HKEY key, const TCHAR* const* keyNames) -{ - return openKey(key, keyNames, true); +HKEY ArchMiscWindows::openKey(HKEY key, const TCHAR *keyName, bool create) { + // ignore if parent is NULL + if (key == NULL) { + return NULL; + } + + // open next key + HKEY newKey; + LSTATUS result = + RegOpenKeyEx(key, keyName, 0, KEY_WRITE | KEY_QUERY_VALUE, &newKey); + if (result != ERROR_SUCCESS && create) { + DWORD disp; + result = RegCreateKeyEx(key, keyName, 0, NULL, 0, + KEY_WRITE | KEY_QUERY_VALUE, NULL, &newKey, &disp); + } + if (result != ERROR_SUCCESS) { + RegCloseKey(key); + return NULL; + } + + // switch to new key + RegCloseKey(key); + return newKey; } -HKEY -ArchMiscWindows::openKey(HKEY key, const TCHAR* keyName, bool create) -{ - // ignore if parent is NULL - if (key == NULL) { - return NULL; - } - +HKEY ArchMiscWindows::openKey(HKEY key, const TCHAR *const *keyNames, + bool create) { + for (size_t i = 0; key != NULL && keyNames[i] != NULL; ++i) { // open next key - HKEY newKey; - LSTATUS result = RegOpenKeyEx(key, keyName, 0, - KEY_WRITE | KEY_QUERY_VALUE, &newKey); - if (result != ERROR_SUCCESS && create) { - DWORD disp; - result = RegCreateKeyEx(key, keyName, 0, NULL, - 0, KEY_WRITE | KEY_QUERY_VALUE, - NULL, &newKey, &disp); - } - if (result != ERROR_SUCCESS) { - RegCloseKey(key); - return NULL; - } - - // switch to new key - RegCloseKey(key); - return newKey; + key = openKey(key, keyNames[i], create); + } + return key; } -HKEY -ArchMiscWindows::openKey(HKEY key, const TCHAR* const* keyNames, bool create) -{ - for (size_t i = 0; key != NULL && keyNames[i] != NULL; ++i) { - // open next key - key = openKey(key, keyNames[i], create); - } - return key; +void ArchMiscWindows::closeKey(HKEY key) { + assert(key != NULL); + if (key == NULL) + return; + RegCloseKey(key); } -void -ArchMiscWindows::closeKey(HKEY key) -{ - assert(key != NULL); - if (key==NULL) return; - RegCloseKey(key); +void ArchMiscWindows::deleteKey(HKEY key, const TCHAR *name) { + assert(key != NULL); + assert(name != NULL); + if (key == NULL || name == NULL) + return; + RegDeleteKey(key, name); } -void -ArchMiscWindows::deleteKey(HKEY key, const TCHAR* name) -{ - assert(key != NULL); - assert(name != NULL); - if (key==NULL || name==NULL) return; - RegDeleteKey(key, name); +void ArchMiscWindows::deleteValue(HKEY key, const TCHAR *name) { + assert(key != NULL); + assert(name != NULL); + if (key == NULL || name == NULL) + return; + RegDeleteValue(key, name); } -void -ArchMiscWindows::deleteValue(HKEY key, const TCHAR* name) -{ - assert(key != NULL); - assert(name != NULL); - if (key==NULL || name==NULL) return; - RegDeleteValue(key, name); +bool ArchMiscWindows::hasValue(HKEY key, const TCHAR *name) { + DWORD type; + LONG result = RegQueryValueEx(key, name, 0, &type, NULL, NULL); + return (result == ERROR_SUCCESS && (type == REG_DWORD || type == REG_SZ)); } -bool -ArchMiscWindows::hasValue(HKEY key, const TCHAR* name) -{ - DWORD type; - LONG result = RegQueryValueEx(key, name, 0, &type, NULL, NULL); - return (result == ERROR_SUCCESS && - (type == REG_DWORD || type == REG_SZ)); +ArchMiscWindows::EValueType ArchMiscWindows::typeOfValue(HKEY key, + const TCHAR *name) { + DWORD type; + LONG result = RegQueryValueEx(key, name, 0, &type, NULL, NULL); + if (result != ERROR_SUCCESS) { + return kNO_VALUE; + } + switch (type) { + case REG_DWORD: + return kUINT; + + case REG_SZ: + return kSTRING; + + case REG_BINARY: + return kBINARY; + + default: + return kUNKNOWN; + } } -ArchMiscWindows::EValueType -ArchMiscWindows::typeOfValue(HKEY key, const TCHAR* name) -{ - DWORD type; - LONG result = RegQueryValueEx(key, name, 0, &type, NULL, NULL); - if (result != ERROR_SUCCESS) { - return kNO_VALUE; - } - switch (type) { - case REG_DWORD: - return kUINT; - - case REG_SZ: - return kSTRING; - - case REG_BINARY: - return kBINARY; - - default: - return kUNKNOWN; - } +void ArchMiscWindows::setValue(HKEY key, const TCHAR *name, + const std::string &value) { + assert(key != NULL); + if (key == NULL) { + // TODO: throw exception + return; + } + RegSetValueEx(key, name, 0, REG_SZ, + reinterpret_cast(value.c_str()), + (DWORD)value.size() + 1); } -void -ArchMiscWindows::setValue(HKEY key, - const TCHAR* name, const std::string& value) -{ - assert(key != NULL); - if (key == NULL) { - // TODO: throw exception - return; - } - RegSetValueEx(key, name, 0, REG_SZ, - reinterpret_cast(value.c_str()), - (DWORD)value.size() + 1); +void ArchMiscWindows::setValue(HKEY key, const TCHAR *name, DWORD value) { + assert(key != NULL); + if (key == NULL) { + // TODO: throw exception + return; + } + RegSetValueEx(key, name, 0, REG_DWORD, reinterpret_cast(&value), + sizeof(DWORD)); } -void -ArchMiscWindows::setValue(HKEY key, const TCHAR* name, DWORD value) -{ - assert(key != NULL); - if (key == NULL) { - // TODO: throw exception - return; - } - RegSetValueEx(key, name, 0, REG_DWORD, - reinterpret_cast(&value), - sizeof(DWORD)); +void ArchMiscWindows::setValueBinary(HKEY key, const TCHAR *name, + const std::string &value) { + assert(key != NULL); + assert(name != NULL); + if (key == NULL || name == NULL) { + // TODO: throw exception + return; + } + RegSetValueEx(key, name, 0, REG_BINARY, + reinterpret_cast(value.data()), + (DWORD)value.size()); } -void -ArchMiscWindows::setValueBinary(HKEY key, - const TCHAR* name, const std::string& value) -{ - assert(key != NULL); - assert(name != NULL); - if (key == NULL || name == NULL) { - // TODO: throw exception - return; - } - RegSetValueEx(key, name, 0, REG_BINARY, - reinterpret_cast(value.data()), - (DWORD)value.size()); -} +std::string ArchMiscWindows::readBinaryOrString(HKEY key, const TCHAR *name, + DWORD type) { + // get the size of the string + DWORD actualType; + DWORD size = 0; + LONG result = RegQueryValueEx(key, name, 0, &actualType, NULL, &size); + if (result != ERROR_SUCCESS || actualType != type) { + return std::string(); + } -std::string -ArchMiscWindows::readBinaryOrString(HKEY key, const TCHAR* name, DWORD type) -{ - // get the size of the string - DWORD actualType; - DWORD size = 0; - LONG result = RegQueryValueEx(key, name, 0, &actualType, NULL, &size); - if (result != ERROR_SUCCESS || actualType != type) { - return std::string(); - } + // if zero size then return empty string + if (size == 0) { + return std::string(); + } - // if zero size then return empty string - if (size == 0) { - return std::string(); - } + // allocate space + char *buffer = new char[size]; - // allocate space - char* buffer = new char[size]; - - // read it - result = RegQueryValueEx(key, name, 0, &actualType, - reinterpret_cast(buffer), &size); - if (result != ERROR_SUCCESS || actualType != type) { - delete[] buffer; - return std::string(); - } - - // clean up and return value - if (type == REG_SZ && buffer[size - 1] == '\0') { - // don't include terminating nul; std::string will add one. - --size; - } - std::string value(buffer, size); + // read it + result = RegQueryValueEx(key, name, 0, &actualType, + reinterpret_cast(buffer), &size); + if (result != ERROR_SUCCESS || actualType != type) { delete[] buffer; - return value; + return std::string(); + } + + // clean up and return value + if (type == REG_SZ && buffer[size - 1] == '\0') { + // don't include terminating nul; std::string will add one. + --size; + } + std::string value(buffer, size); + delete[] buffer; + return value; } -std::string -ArchMiscWindows::readValueString(HKEY key, const TCHAR* name) -{ - return readBinaryOrString(key, name, REG_SZ); +std::string ArchMiscWindows::readValueString(HKEY key, const TCHAR *name) { + return readBinaryOrString(key, name, REG_SZ); } -std::string -ArchMiscWindows::readValueBinary(HKEY key, const TCHAR* name) -{ - return readBinaryOrString(key, name, REG_BINARY); +std::string ArchMiscWindows::readValueBinary(HKEY key, const TCHAR *name) { + return readBinaryOrString(key, name, REG_BINARY); } DWORD -ArchMiscWindows::readValueInt(HKEY key, const TCHAR* name) -{ - DWORD type; - DWORD value; - DWORD size = sizeof(value); - LONG result = RegQueryValueEx(key, name, 0, &type, - reinterpret_cast(&value), &size); - if (result != ERROR_SUCCESS || type != REG_DWORD) { - return 0; - } - return value; -} - -void -ArchMiscWindows::addDialog(HWND hwnd) -{ - s_dialogs->insert(hwnd); -} - -void -ArchMiscWindows::removeDialog(HWND hwnd) -{ - s_dialogs->erase(hwnd); -} - -bool -ArchMiscWindows::processDialog(MSG* msg) -{ - for (Dialogs::const_iterator index = s_dialogs->begin(); - index != s_dialogs->end(); ++index) { - if (IsDialogMessage(*index, msg)) { - return true; - } - } - return false; -} - -void -ArchMiscWindows::addBusyState(DWORD busyModes) -{ - s_busyState |= busyModes; - setThreadExecutionState(s_busyState); -} - -void -ArchMiscWindows::removeBusyState(DWORD busyModes) -{ - s_busyState &= ~busyModes; - setThreadExecutionState(s_busyState); -} - -void -ArchMiscWindows::setThreadExecutionState(DWORD busyModes) -{ - // look up function dynamically so we work on older systems - if (s_stes == NULL) { - HINSTANCE kernel = LoadLibrary("kernel32.dll"); - if (kernel != NULL) { - s_stes = reinterpret_cast(GetProcAddress(kernel, - "SetThreadExecutionState")); - } - if (s_stes == NULL) { - s_stes = &ArchMiscWindows::dummySetThreadExecutionState; - } - } - - // convert to STES form - EXECUTION_STATE state = 0; - if ((busyModes & kSYSTEM) != 0) { - state |= ES_SYSTEM_REQUIRED; - } - if ((busyModes & kDISPLAY) != 0) { - state |= ES_DISPLAY_REQUIRED; - } - if (state != 0) { - state |= ES_CONTINUOUS; - } - - // do it - s_stes(state); -} - -DWORD -ArchMiscWindows::dummySetThreadExecutionState(DWORD) -{ - // do nothing +ArchMiscWindows::readValueInt(HKEY key, const TCHAR *name) { + DWORD type; + DWORD value; + DWORD size = sizeof(value); + LONG result = RegQueryValueEx(key, name, 0, &type, + reinterpret_cast(&value), &size); + if (result != ERROR_SUCCESS || type != REG_DWORD) { return 0; + } + return value; } -void -ArchMiscWindows::wakeupDisplay() -{ - // We can't use ::setThreadExecutionState here because it sets - // ES_CONTINUOUS, which we don't want. +void ArchMiscWindows::addDialog(HWND hwnd) { s_dialogs->insert(hwnd); } +void ArchMiscWindows::removeDialog(HWND hwnd) { s_dialogs->erase(hwnd); } + +bool ArchMiscWindows::processDialog(MSG *msg) { + for (Dialogs::const_iterator index = s_dialogs->begin(); + index != s_dialogs->end(); ++index) { + if (IsDialogMessage(*index, msg)) { + return true; + } + } + return false; +} + +void ArchMiscWindows::addBusyState(DWORD busyModes) { + s_busyState |= busyModes; + setThreadExecutionState(s_busyState); +} + +void ArchMiscWindows::removeBusyState(DWORD busyModes) { + s_busyState &= ~busyModes; + setThreadExecutionState(s_busyState); +} + +void ArchMiscWindows::setThreadExecutionState(DWORD busyModes) { + // look up function dynamically so we work on older systems + if (s_stes == NULL) { + HINSTANCE kernel = LoadLibrary("kernel32.dll"); + if (kernel != NULL) { + s_stes = reinterpret_cast( + GetProcAddress(kernel, "SetThreadExecutionState")); + } if (s_stes == NULL) { - HINSTANCE kernel = LoadLibrary("kernel32.dll"); - if (kernel != NULL) { - s_stes = reinterpret_cast(GetProcAddress(kernel, - "SetThreadExecutionState")); - } - if (s_stes == NULL) { - s_stes = &ArchMiscWindows::dummySetThreadExecutionState; - } + s_stes = &ArchMiscWindows::dummySetThreadExecutionState; } + } - s_stes(ES_DISPLAY_REQUIRED); + // convert to STES form + EXECUTION_STATE state = 0; + if ((busyModes & kSYSTEM) != 0) { + state |= ES_SYSTEM_REQUIRED; + } + if ((busyModes & kDISPLAY) != 0) { + state |= ES_DISPLAY_REQUIRED; + } + if (state != 0) { + state |= ES_CONTINUOUS; + } - // restore the original execution states - setThreadExecutionState(s_busyState); + // do it + s_stes(state); } -bool -ArchMiscWindows::wasLaunchedAsService() -{ - String name; - if (!getParentProcessName(name)) { - LOG((CLOG_ERR "cannot determine if process was launched as service")); - return false; - } - - return (name == SERVICE_LAUNCHER); +DWORD +ArchMiscWindows::dummySetThreadExecutionState(DWORD) { + // do nothing + return 0; } -bool -ArchMiscWindows::getParentProcessName(String &name) -{ - PROCESSENTRY32 parentEntry; - if (!getParentProcessEntry(parentEntry)){ - LOG((CLOG_ERR "could not get entry for parent process")); - return false; - } +void ArchMiscWindows::wakeupDisplay() { + // We can't use ::setThreadExecutionState here because it sets + // ES_CONTINUOUS, which we don't want. - name = parentEntry.szExeFile; - return true; + if (s_stes == NULL) { + HINSTANCE kernel = LoadLibrary("kernel32.dll"); + if (kernel != NULL) { + s_stes = reinterpret_cast( + GetProcAddress(kernel, "SetThreadExecutionState")); + } + if (s_stes == NULL) { + s_stes = &ArchMiscWindows::dummySetThreadExecutionState; + } + } + + s_stes(ES_DISPLAY_REQUIRED); + + // restore the original execution states + setThreadExecutionState(s_busyState); } -BOOL WINAPI -ArchMiscWindows::getSelfProcessEntry(PROCESSENTRY32& entry) -{ - // get entry from current PID - return getProcessEntry(entry, GetCurrentProcessId()); +bool ArchMiscWindows::wasLaunchedAsService() { + String name; + if (!getParentProcessName(name)) { + LOG((CLOG_ERR "cannot determine if process was launched as service")); + return false; + } + + return (name == SERVICE_LAUNCHER); } -BOOL WINAPI -ArchMiscWindows::getParentProcessEntry(PROCESSENTRY32& entry) -{ - // get the current process, so we can get parent PID - PROCESSENTRY32 selfEntry; - if (!getSelfProcessEntry(selfEntry)) { - return FALSE; - } +bool ArchMiscWindows::getParentProcessName(String &name) { + PROCESSENTRY32 parentEntry; + if (!getParentProcessEntry(parentEntry)) { + LOG((CLOG_ERR "could not get entry for parent process")); + return false; + } - // get entry from parent PID - return getProcessEntry(entry, selfEntry.th32ParentProcessID); + name = parentEntry.szExeFile; + return true; } -BOOL WINAPI -ArchMiscWindows::getProcessEntry(PROCESSENTRY32& entry, DWORD processID) -{ - // first we need to take a snapshot of the running processes - HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); - if (snapshot == INVALID_HANDLE_VALUE) { - LOG((CLOG_ERR "could not get process snapshot (error: %i)", - GetLastError())); - return FALSE; - } - - entry.dwSize = sizeof(PROCESSENTRY32); - - // get the first process, and if we can't do that then it's - // unlikely we can go any further - BOOL gotEntry = Process32First(snapshot, &entry); - if (!gotEntry) { - LOG((CLOG_ERR "could not get first process entry (error: %i)", - GetLastError())); - return FALSE; - } - - while(gotEntry) { - - if (entry.th32ProcessID == processID) { - // found current process - return TRUE; - } - - // now move on to the next entry (when we reach end, loop will stop) - gotEntry = Process32Next(snapshot, &entry); - } +BOOL WINAPI ArchMiscWindows::getSelfProcessEntry(PROCESSENTRY32 &entry) { + // get entry from current PID + return getProcessEntry(entry, GetCurrentProcessId()); +} +BOOL WINAPI ArchMiscWindows::getParentProcessEntry(PROCESSENTRY32 &entry) { + // get the current process, so we can get parent PID + PROCESSENTRY32 selfEntry; + if (!getSelfProcessEntry(selfEntry)) { return FALSE; + } + + // get entry from parent PID + return getProcessEntry(entry, selfEntry.th32ParentProcessID); +} + +BOOL WINAPI ArchMiscWindows::getProcessEntry(PROCESSENTRY32 &entry, + DWORD processID) { + // first we need to take a snapshot of the running processes + HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); + if (snapshot == INVALID_HANDLE_VALUE) { + LOG((CLOG_ERR "could not get process snapshot (error: %i)", + GetLastError())); + return FALSE; + } + + entry.dwSize = sizeof(PROCESSENTRY32); + + // get the first process, and if we can't do that then it's + // unlikely we can go any further + BOOL gotEntry = Process32First(snapshot, &entry); + if (!gotEntry) { + LOG((CLOG_ERR "could not get first process entry (error: %i)", + GetLastError())); + return FALSE; + } + + while (gotEntry) { + + if (entry.th32ProcessID == processID) { + // found current process + return TRUE; + } + + // now move on to the next entry (when we reach end, loop will stop) + gotEntry = Process32Next(snapshot, &entry); + } + + return FALSE; } HINSTANCE -ArchMiscWindows::instanceWin32() -{ - assert(s_instanceWin32 != NULL); - return s_instanceWin32; +ArchMiscWindows::instanceWin32() { + assert(s_instanceWin32 != NULL); + return s_instanceWin32; } -void -ArchMiscWindows::setInstanceWin32(HINSTANCE instance) -{ - assert(instance != NULL); - s_instanceWin32 = instance; +void ArchMiscWindows::setInstanceWin32(HINSTANCE instance) { + assert(instance != NULL); + s_instanceWin32 = instance; } \ No newline at end of file diff --git a/src/lib/arch/win32/ArchMiscWindows.h b/src/lib/arch/win32/ArchMiscWindows.h index 7758abaf6..192681aa0 100644 --- a/src/lib/arch/win32/ArchMiscWindows.h +++ b/src/lib/arch/win32/ArchMiscWindows.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -18,185 +18,173 @@ #pragma once -#include "common/common.h" -#include "common/stdstring.h" -#include "common/stdset.h" #include "base/String.h" +#include "common/stdset.h" +#include "common/stdstring.h" #define WIN32_LEAN_AND_MEAN #include + #include //! Miscellaneous win32 functions. class ArchMiscWindows { public: - enum EValueType { - kUNKNOWN, - kNO_VALUE, - kUINT, - kSTRING, - kBINARY - }; - enum EBusyModes { - kIDLE = 0x0000, - kSYSTEM = 0x0001, - kDISPLAY = 0x0002 - }; + enum EValueType { kUNKNOWN, kNO_VALUE, kUINT, kSTRING, kBINARY }; + enum EBusyModes { kIDLE = 0x0000, kSYSTEM = 0x0001, kDISPLAY = 0x0002 }; - typedef int (*RunFunc)(void); + typedef int (*RunFunc)(void); - //! Initialize - static void init(); + //! Initialize + static void init(); - //! Delete memory - static void cleanup(); + //! Delete memory + static void cleanup(); - //! Set the application icons - /*! - Set the application icons. - */ - static void setIcons(HICON largeIcon, HICON smallIcon); + //! Set the application icons + /*! + Set the application icons. + */ + static void setIcons(HICON largeIcon, HICON smallIcon); - //! Get the application icons - /*! - Get the application icons. - */ - static void getIcons(HICON& largeIcon, HICON& smallIcon); + //! Get the application icons + /*! + Get the application icons. + */ + static void getIcons(HICON &largeIcon, HICON &smallIcon); - //! Run the daemon - /*! - Delegates to ArchDaemonWindows. - */ - static int runDaemon(RunFunc runFunc); + //! Run the daemon + /*! + Delegates to ArchDaemonWindows. + */ + static int runDaemon(RunFunc runFunc); - //! Indicate daemon is in main loop - /*! - Delegates to ArchDaemonWindows. - */ - static void daemonRunning(bool running); + //! Indicate daemon is in main loop + /*! + Delegates to ArchDaemonWindows. + */ + static void daemonRunning(bool running); - //! Indicate failure of running daemon - /*! - Delegates to ArchDaemonWindows. - */ - static void daemonFailed(int result); + //! Indicate failure of running daemon + /*! + Delegates to ArchDaemonWindows. + */ + static void daemonFailed(int result); - //! Get daemon quit message - /*! - Delegates to ArchDaemonWindows. - */ - static UINT getDaemonQuitMessage(); + //! Get daemon quit message + /*! + Delegates to ArchDaemonWindows. + */ + static UINT getDaemonQuitMessage(); - //! Open and return a registry key, closing the parent key - static HKEY openKey(HKEY parent, const TCHAR* child); + //! Open and return a registry key, closing the parent key + static HKEY openKey(HKEY parent, const TCHAR *child); - //! Open and return a registry key, closing the parent key - static HKEY openKey(HKEY parent, const TCHAR* const* keyPath); + //! Open and return a registry key, closing the parent key + static HKEY openKey(HKEY parent, const TCHAR *const *keyPath); - //! Open/create and return a registry key, closing the parent key - static HKEY addKey(HKEY parent, const TCHAR* child); + //! Open/create and return a registry key, closing the parent key + static HKEY addKey(HKEY parent, const TCHAR *child); - //! Open/create and return a registry key, closing the parent key - static HKEY addKey(HKEY parent, const TCHAR* const* keyPath); + //! Open/create and return a registry key, closing the parent key + static HKEY addKey(HKEY parent, const TCHAR *const *keyPath); - //! Close a key - static void closeKey(HKEY); + //! Close a key + static void closeKey(HKEY); - //! Delete a key (which should have no subkeys) - static void deleteKey(HKEY parent, const TCHAR* name); + //! Delete a key (which should have no subkeys) + static void deleteKey(HKEY parent, const TCHAR *name); - //! Delete a value - static void deleteValue(HKEY parent, const TCHAR* name); + //! Delete a value + static void deleteValue(HKEY parent, const TCHAR *name); - //! Test if a value exists - static bool hasValue(HKEY key, const TCHAR* name); + //! Test if a value exists + static bool hasValue(HKEY key, const TCHAR *name); - //! Get type of value - static EValueType typeOfValue(HKEY key, const TCHAR* name); + //! Get type of value + static EValueType typeOfValue(HKEY key, const TCHAR *name); - //! Set a string value in the registry - static void setValue(HKEY key, const TCHAR* name, - const std::string& value); + //! Set a string value in the registry + static void setValue(HKEY key, const TCHAR *name, const std::string &value); - //! Set a DWORD value in the registry - static void setValue(HKEY key, const TCHAR* name, DWORD value); + //! Set a DWORD value in the registry + static void setValue(HKEY key, const TCHAR *name, DWORD value); - //! Set a BINARY value in the registry - /*! - Sets the \p name value of \p key to \p value.data(). - */ - static void setValueBinary(HKEY key, const TCHAR* name, - const std::string& value); + //! Set a BINARY value in the registry + /*! + Sets the \p name value of \p key to \p value.data(). + */ + static void setValueBinary(HKEY key, const TCHAR *name, + const std::string &value); - //! Read a string value from the registry - static std::string readValueString(HKEY, const TCHAR* name); + //! Read a string value from the registry + static std::string readValueString(HKEY, const TCHAR *name); - //! Read a DWORD value from the registry - static DWORD readValueInt(HKEY, const TCHAR* name); + //! Read a DWORD value from the registry + static DWORD readValueInt(HKEY, const TCHAR *name); - //! Read a BINARY value from the registry - static std::string readValueBinary(HKEY, const TCHAR* name); + //! Read a BINARY value from the registry + static std::string readValueBinary(HKEY, const TCHAR *name); - //! Add a dialog - static void addDialog(HWND); + //! Add a dialog + static void addDialog(HWND); - //! Remove a dialog - static void removeDialog(HWND); + //! Remove a dialog + static void removeDialog(HWND); - //! Process dialog message - /*! - Checks if the message is destined for a dialog. If so the message - is passed to the dialog and returns true, otherwise returns false. - */ - static bool processDialog(MSG*); + //! Process dialog message + /*! + Checks if the message is destined for a dialog. If so the message + is passed to the dialog and returns true, otherwise returns false. + */ + static bool processDialog(MSG *); - //! Disable power saving - static void addBusyState(DWORD busyModes); + //! Disable power saving + static void addBusyState(DWORD busyModes); - //! Enable power saving - static void removeBusyState(DWORD busyModes); + //! Enable power saving + static void removeBusyState(DWORD busyModes); - //! Briefly interrupt power saving - static void wakeupDisplay(); + //! Briefly interrupt power saving + static void wakeupDisplay(); - //! Returns true if this process was launched via NT service host. - static bool wasLaunchedAsService(); + //! Returns true if this process was launched via NT service host. + static bool wasLaunchedAsService(); - //! Returns true if we got the parent process name. - static bool getParentProcessName(String &name); + //! Returns true if we got the parent process name. + static bool getParentProcessName(String &name); - static HINSTANCE instanceWin32(); + static HINSTANCE instanceWin32(); - static void setInstanceWin32(HINSTANCE instance); - - static BOOL WINAPI getProcessEntry(PROCESSENTRY32& entry, DWORD processID); - static BOOL WINAPI getSelfProcessEntry(PROCESSENTRY32& entry); - static BOOL WINAPI getParentProcessEntry(PROCESSENTRY32& entry); + static void setInstanceWin32(HINSTANCE instance); + + static BOOL WINAPI getProcessEntry(PROCESSENTRY32 &entry, DWORD processID); + static BOOL WINAPI getSelfProcessEntry(PROCESSENTRY32 &entry); + static BOOL WINAPI getParentProcessEntry(PROCESSENTRY32 &entry); private: - //! Open and return a registry key, closing the parent key - static HKEY openKey(HKEY parent, const TCHAR* child, bool create); + //! Open and return a registry key, closing the parent key + static HKEY openKey(HKEY parent, const TCHAR *child, bool create); - //! Open and return a registry key, closing the parent key - static HKEY openKey(HKEY parent, const TCHAR* const* keyPath, - bool create); + //! Open and return a registry key, closing the parent key + static HKEY openKey(HKEY parent, const TCHAR *const *keyPath, bool create); - //! Read a string value from the registry - static std::string readBinaryOrString(HKEY, const TCHAR* name, DWORD type); + //! Read a string value from the registry + static std::string readBinaryOrString(HKEY, const TCHAR *name, DWORD type); - //! Set thread busy state - static void setThreadExecutionState(DWORD); + //! Set thread busy state + static void setThreadExecutionState(DWORD); - static DWORD WINAPI dummySetThreadExecutionState(DWORD); + static DWORD WINAPI dummySetThreadExecutionState(DWORD); private: - typedef std::set Dialogs; - typedef DWORD (WINAPI *STES_t)(DWORD); + typedef std::set Dialogs; + typedef DWORD(WINAPI *STES_t)(DWORD); - static Dialogs* s_dialogs; - static DWORD s_busyState; - static STES_t s_stes; - static HICON s_largeIcon; - static HICON s_smallIcon; - static HINSTANCE s_instanceWin32; + static Dialogs *s_dialogs; + static DWORD s_busyState; + static STES_t s_stes; + static HICON s_largeIcon; + static HICON s_smallIcon; + static HINSTANCE s_instanceWin32; }; diff --git a/src/lib/arch/win32/ArchMultithreadWindows.cpp b/src/lib/arch/win32/ArchMultithreadWindows.cpp index 063f44f0d..e58cbadcd 100644 --- a/src/lib/arch/win32/ArchMultithreadWindows.cpp +++ b/src/lib/arch/win32/ArchMultithreadWindows.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -17,7 +17,7 @@ */ #if defined(_MSC_VER) && !defined(_MT) -# error multithreading compile option is required +#error multithreading compile option is required #endif #include "arch/win32/ArchMultithreadWindows.h" @@ -42,663 +42,575 @@ class ArchThreadImpl { public: - ArchThreadImpl(); - ~ArchThreadImpl(); + ArchThreadImpl(); + ~ArchThreadImpl(); public: - int m_refCount; - HANDLE m_thread; - DWORD m_id; - IArchMultithread::ThreadFunc m_func; - void* m_userData; - HANDLE m_cancel; - bool m_cancelling; - HANDLE m_exit; - void* m_result; - void* m_networkData; + int m_refCount; + HANDLE m_thread; + DWORD m_id; + IArchMultithread::ThreadFunc m_func; + void *m_userData; + HANDLE m_cancel; + bool m_cancelling; + HANDLE m_exit; + void *m_result; + void *m_networkData; }; -ArchThreadImpl::ArchThreadImpl() : - m_refCount(1), - m_thread(NULL), - m_id(0), - m_func(NULL), - m_userData(NULL), - m_cancelling(false), - m_result(NULL), - m_networkData(NULL) -{ - m_exit = CreateEvent(NULL, TRUE, FALSE, NULL); - m_cancel = CreateEvent(NULL, TRUE, FALSE, NULL); +ArchThreadImpl::ArchThreadImpl() + : m_refCount(1), m_thread(NULL), m_id(0), m_func(NULL), m_userData(NULL), + m_cancelling(false), m_result(NULL), m_networkData(NULL) { + m_exit = CreateEvent(NULL, TRUE, FALSE, NULL); + m_cancel = CreateEvent(NULL, TRUE, FALSE, NULL); } -ArchThreadImpl::~ArchThreadImpl() -{ - CloseHandle(m_exit); - CloseHandle(m_cancel); +ArchThreadImpl::~ArchThreadImpl() { + CloseHandle(m_exit); + CloseHandle(m_cancel); } - // // ArchMultithreadWindows // -ArchMultithreadWindows* ArchMultithreadWindows::s_instance = NULL; +ArchMultithreadWindows *ArchMultithreadWindows::s_instance = NULL; -ArchMultithreadWindows::ArchMultithreadWindows() -{ - assert(s_instance == NULL); - s_instance = this; +ArchMultithreadWindows::ArchMultithreadWindows() { + assert(s_instance == NULL); + s_instance = this; - // no signal handlers - for (size_t i = 0; i < kNUM_SIGNALS; ++i) { - m_signalFunc[i] = NULL; - m_signalUserData[i] = NULL; - } + // no signal handlers + for (size_t i = 0; i < kNUM_SIGNALS; ++i) { + m_signalFunc[i] = NULL; + m_signalUserData[i] = NULL; + } - // create mutex for thread list - m_threadMutex = newMutex(); + // create mutex for thread list + m_threadMutex = newMutex(); - // create thread for calling (main) thread and add it to our - // list. no need to lock the mutex since we're the only thread. - m_mainThread = new ArchThreadImpl; - m_mainThread->m_thread = NULL; - m_mainThread->m_id = GetCurrentThreadId(); - insert(m_mainThread); + // create thread for calling (main) thread and add it to our + // list. no need to lock the mutex since we're the only thread. + m_mainThread = new ArchThreadImpl; + m_mainThread->m_thread = NULL; + m_mainThread->m_id = GetCurrentThreadId(); + insert(m_mainThread); } -ArchMultithreadWindows::~ArchMultithreadWindows() -{ - s_instance = NULL; +ArchMultithreadWindows::~ArchMultithreadWindows() { + s_instance = NULL; - // clean up thread list - for (ThreadList::iterator index = m_threadList.begin(); - index != m_threadList.end(); ++index) { - delete *index; - } + // clean up thread list + for (ThreadList::iterator index = m_threadList.begin(); + index != m_threadList.end(); ++index) { + delete *index; + } - // done with mutex - delete m_threadMutex; + // done with mutex + delete m_threadMutex; } -void -ArchMultithreadWindows::setNetworkDataForCurrentThread(void* data) -{ - lockMutex(m_threadMutex); - ArchThreadImpl* thread = findNoRef(GetCurrentThreadId()); - thread->m_networkData = data; - unlockMutex(m_threadMutex); +void ArchMultithreadWindows::setNetworkDataForCurrentThread(void *data) { + lockMutex(m_threadMutex); + ArchThreadImpl *thread = findNoRef(GetCurrentThreadId()); + thread->m_networkData = data; + unlockMutex(m_threadMutex); } -void* -ArchMultithreadWindows::getNetworkDataForThread(ArchThread thread) -{ - lockMutex(m_threadMutex); - void* data = thread->m_networkData; - unlockMutex(m_threadMutex); - return data; +void *ArchMultithreadWindows::getNetworkDataForThread(ArchThread thread) { + lockMutex(m_threadMutex); + void *data = thread->m_networkData; + unlockMutex(m_threadMutex); + return data; } HANDLE -ArchMultithreadWindows::getCancelEventForCurrentThread() -{ - lockMutex(m_threadMutex); - ArchThreadImpl* thread = findNoRef(GetCurrentThreadId()); - unlockMutex(m_threadMutex); - return thread->m_cancel; +ArchMultithreadWindows::getCancelEventForCurrentThread() { + lockMutex(m_threadMutex); + ArchThreadImpl *thread = findNoRef(GetCurrentThreadId()); + unlockMutex(m_threadMutex); + return thread->m_cancel; } -ArchMultithreadWindows* -ArchMultithreadWindows::getInstance() -{ - return s_instance; +ArchMultithreadWindows *ArchMultithreadWindows::getInstance() { + return s_instance; } -ArchCond -ArchMultithreadWindows::newCondVar() -{ - ArchCondImpl* cond = new ArchCondImpl; - cond->m_events[ArchCondImpl::kSignal] = CreateEvent(NULL, - FALSE, FALSE, NULL); - cond->m_events[ArchCondImpl::kBroadcast] = CreateEvent(NULL, - TRUE, FALSE, NULL); - cond->m_waitCountMutex = newMutex(); - cond->m_waitCount = 0; - return cond; +ArchCond ArchMultithreadWindows::newCondVar() { + ArchCondImpl *cond = new ArchCondImpl; + cond->m_events[ArchCondImpl::kSignal] = CreateEvent(NULL, FALSE, FALSE, NULL); + cond->m_events[ArchCondImpl::kBroadcast] = + CreateEvent(NULL, TRUE, FALSE, NULL); + cond->m_waitCountMutex = newMutex(); + cond->m_waitCount = 0; + return cond; } -void -ArchMultithreadWindows::closeCondVar(ArchCond cond) -{ - CloseHandle(cond->m_events[ArchCondImpl::kSignal]); - CloseHandle(cond->m_events[ArchCondImpl::kBroadcast]); - closeMutex(cond->m_waitCountMutex); - delete cond; +void ArchMultithreadWindows::closeCondVar(ArchCond cond) { + CloseHandle(cond->m_events[ArchCondImpl::kSignal]); + CloseHandle(cond->m_events[ArchCondImpl::kBroadcast]); + closeMutex(cond->m_waitCountMutex); + delete cond; } -void -ArchMultithreadWindows::signalCondVar(ArchCond cond) -{ - // is anybody waiting? - lockMutex(cond->m_waitCountMutex); - const bool hasWaiter = (cond->m_waitCount > 0); - unlockMutex(cond->m_waitCountMutex); +void ArchMultithreadWindows::signalCondVar(ArchCond cond) { + // is anybody waiting? + lockMutex(cond->m_waitCountMutex); + const bool hasWaiter = (cond->m_waitCount > 0); + unlockMutex(cond->m_waitCountMutex); - // wake one thread if anybody is waiting - if (hasWaiter) { - SetEvent(cond->m_events[ArchCondImpl::kSignal]); - } + // wake one thread if anybody is waiting + if (hasWaiter) { + SetEvent(cond->m_events[ArchCondImpl::kSignal]); + } } -void -ArchMultithreadWindows::broadcastCondVar(ArchCond cond) -{ - // is anybody waiting? - lockMutex(cond->m_waitCountMutex); - const bool hasWaiter = (cond->m_waitCount > 0); - unlockMutex(cond->m_waitCountMutex); +void ArchMultithreadWindows::broadcastCondVar(ArchCond cond) { + // is anybody waiting? + lockMutex(cond->m_waitCountMutex); + const bool hasWaiter = (cond->m_waitCount > 0); + unlockMutex(cond->m_waitCountMutex); - // wake all threads if anybody is waiting - if (hasWaiter) { - SetEvent(cond->m_events[ArchCondImpl::kBroadcast]); - } + // wake all threads if anybody is waiting + if (hasWaiter) { + SetEvent(cond->m_events[ArchCondImpl::kBroadcast]); + } } -bool -ArchMultithreadWindows::waitCondVar(ArchCond cond, - ArchMutex mutex, double timeout) -{ - // prepare to wait - const DWORD winTimeout = (timeout < 0.0) ? INFINITE : - static_cast(1000.0 * timeout); +bool ArchMultithreadWindows::waitCondVar(ArchCond cond, ArchMutex mutex, + double timeout) { + // prepare to wait + const DWORD winTimeout = + (timeout < 0.0) ? INFINITE : static_cast(1000.0 * timeout); - // make a list of the condition variable events and the cancel event - // for the current thread. - HANDLE handles[4]; - handles[0] = cond->m_events[ArchCondImpl::kSignal]; - handles[1] = cond->m_events[ArchCondImpl::kBroadcast]; - handles[2] = getCancelEventForCurrentThread(); + // make a list of the condition variable events and the cancel event + // for the current thread. + HANDLE handles[4]; + handles[0] = cond->m_events[ArchCondImpl::kSignal]; + handles[1] = cond->m_events[ArchCondImpl::kBroadcast]; + handles[2] = getCancelEventForCurrentThread(); - // update waiter count - lockMutex(cond->m_waitCountMutex); - ++cond->m_waitCount; - unlockMutex(cond->m_waitCountMutex); + // update waiter count + lockMutex(cond->m_waitCountMutex); + ++cond->m_waitCount; + unlockMutex(cond->m_waitCountMutex); - // release mutex. this should be atomic with the wait so that it's - // impossible for another thread to signal us between the unlock and - // the wait, which would lead to a lost signal on broadcasts. - // however, we're using a manual reset event for broadcasts which - // stays set until we reset it, so we don't lose the broadcast. - unlockMutex(mutex); + // release mutex. this should be atomic with the wait so that it's + // impossible for another thread to signal us between the unlock and + // the wait, which would lead to a lost signal on broadcasts. + // however, we're using a manual reset event for broadcasts which + // stays set until we reset it, so we don't lose the broadcast. + unlockMutex(mutex); - // wait for a signal or broadcast - DWORD result = WaitForMultipleObjects(3, handles, FALSE, winTimeout); + // wait for a signal or broadcast + DWORD result = WaitForMultipleObjects(3, handles, FALSE, winTimeout); - // cancel takes priority - if (result != WAIT_OBJECT_0 + 2 && - WaitForSingleObject(handles[2], 0) == WAIT_OBJECT_0) { - result = WAIT_OBJECT_0 + 2; - } + // cancel takes priority + if (result != WAIT_OBJECT_0 + 2 && + WaitForSingleObject(handles[2], 0) == WAIT_OBJECT_0) { + result = WAIT_OBJECT_0 + 2; + } - // update the waiter count and check if we're the last waiter - lockMutex(cond->m_waitCountMutex); - --cond->m_waitCount; - const bool last = (result == WAIT_OBJECT_0 + 1 && cond->m_waitCount == 0); - unlockMutex(cond->m_waitCountMutex); + // update the waiter count and check if we're the last waiter + lockMutex(cond->m_waitCountMutex); + --cond->m_waitCount; + const bool last = (result == WAIT_OBJECT_0 + 1 && cond->m_waitCount == 0); + unlockMutex(cond->m_waitCountMutex); - // reset the broadcast event if we're the last waiter - if (last) { - ResetEvent(cond->m_events[ArchCondImpl::kBroadcast]); - } + // reset the broadcast event if we're the last waiter + if (last) { + ResetEvent(cond->m_events[ArchCondImpl::kBroadcast]); + } - // reacquire the mutex - lockMutex(mutex); + // reacquire the mutex + lockMutex(mutex); - // cancel thread if necessary - if (result == WAIT_OBJECT_0 + 2) { - ARCH->testCancelThread(); - } + // cancel thread if necessary + if (result == WAIT_OBJECT_0 + 2) { + ARCH->testCancelThread(); + } - // return success or failure - return (result == WAIT_OBJECT_0 + 0 || - result == WAIT_OBJECT_0 + 1); + // return success or failure + return (result == WAIT_OBJECT_0 + 0 || result == WAIT_OBJECT_0 + 1); } -ArchMutex -ArchMultithreadWindows::newMutex() -{ - ArchMutexImpl* mutex = new ArchMutexImpl; - InitializeCriticalSection(&mutex->m_mutex); - return mutex; +ArchMutex ArchMultithreadWindows::newMutex() { + ArchMutexImpl *mutex = new ArchMutexImpl; + InitializeCriticalSection(&mutex->m_mutex); + return mutex; } -void -ArchMultithreadWindows::closeMutex(ArchMutex mutex) -{ - DeleteCriticalSection(&mutex->m_mutex); - delete mutex; +void ArchMultithreadWindows::closeMutex(ArchMutex mutex) { + DeleteCriticalSection(&mutex->m_mutex); + delete mutex; } -void -ArchMultithreadWindows::lockMutex(ArchMutex mutex) -{ - EnterCriticalSection(&mutex->m_mutex); +void ArchMultithreadWindows::lockMutex(ArchMutex mutex) { + EnterCriticalSection(&mutex->m_mutex); } -void -ArchMultithreadWindows::unlockMutex(ArchMutex mutex) -{ - LeaveCriticalSection(&mutex->m_mutex); +void ArchMultithreadWindows::unlockMutex(ArchMutex mutex) { + LeaveCriticalSection(&mutex->m_mutex); } -ArchThread -ArchMultithreadWindows::newThread(ThreadFunc func, void* data) -{ - lockMutex(m_threadMutex); +ArchThread ArchMultithreadWindows::newThread(ThreadFunc func, void *data) { + lockMutex(m_threadMutex); - // create thread impl for new thread - ArchThreadImpl* thread = new ArchThreadImpl; - thread->m_func = func; - thread->m_userData = data; + // create thread impl for new thread + ArchThreadImpl *thread = new ArchThreadImpl; + thread->m_func = func; + thread->m_userData = data; - // create thread - unsigned int id = 0; - thread->m_thread = reinterpret_cast(_beginthreadex(NULL, 0, - threadFunc, (void*)thread, 0, &id)); - thread->m_id = static_cast(id); + // create thread + unsigned int id = 0; + thread->m_thread = reinterpret_cast( + _beginthreadex(NULL, 0, threadFunc, (void *)thread, 0, &id)); + thread->m_id = static_cast(id); - // check if thread was started - if (thread->m_thread == 0) { - // failed to start thread so clean up - delete thread; - thread = NULL; - } - else { - // add thread to list - insert(thread); + // check if thread was started + if (thread->m_thread == 0) { + // failed to start thread so clean up + delete thread; + thread = NULL; + } else { + // add thread to list + insert(thread); - // increment ref count to account for the thread itself - refThread(thread); - } - - // note that the child thread will wait until we release this mutex - unlockMutex(m_threadMutex); - - return thread; -} - -ArchThread -ArchMultithreadWindows::newCurrentThread() -{ - lockMutex(m_threadMutex); - ArchThreadImpl* thread = find(GetCurrentThreadId()); - unlockMutex(m_threadMutex); - assert(thread != NULL); - return thread; -} - -void -ArchMultithreadWindows::closeThread(ArchThread thread) -{ - assert(thread != NULL); - - // decrement ref count and clean up thread if no more references - if (--thread->m_refCount == 0) { - // close the handle (main thread has a NULL handle) - if (thread->m_thread != NULL) { - CloseHandle(thread->m_thread); - } - - // remove thread from list - lockMutex(m_threadMutex); - assert(findNoRefOrCreate(thread->m_id) == thread); - erase(thread); - unlockMutex(m_threadMutex); - - // done with thread - delete thread; - } -} - -ArchThread -ArchMultithreadWindows::copyThread(ArchThread thread) -{ + // increment ref count to account for the thread itself refThread(thread); - return thread; + } + + // note that the child thread will wait until we release this mutex + unlockMutex(m_threadMutex); + + return thread; } -void -ArchMultithreadWindows::cancelThread(ArchThread thread) -{ - assert(thread != NULL); - - // set cancel flag - SetEvent(thread->m_cancel); +ArchThread ArchMultithreadWindows::newCurrentThread() { + lockMutex(m_threadMutex); + ArchThreadImpl *thread = find(GetCurrentThreadId()); + unlockMutex(m_threadMutex); + assert(thread != NULL); + return thread; } -void -ArchMultithreadWindows::setPriorityOfThread(ArchThread thread, int n) -{ - struct PriorityInfo { - public: - DWORD m_class; - int m_level; - }; - static const PriorityInfo s_pClass[] = { - { IDLE_PRIORITY_CLASS, THREAD_PRIORITY_IDLE }, - { IDLE_PRIORITY_CLASS, THREAD_PRIORITY_LOWEST }, - { IDLE_PRIORITY_CLASS, THREAD_PRIORITY_BELOW_NORMAL }, - { IDLE_PRIORITY_CLASS, THREAD_PRIORITY_NORMAL }, - { IDLE_PRIORITY_CLASS, THREAD_PRIORITY_ABOVE_NORMAL }, - { IDLE_PRIORITY_CLASS, THREAD_PRIORITY_HIGHEST }, - { NORMAL_PRIORITY_CLASS, THREAD_PRIORITY_LOWEST }, - { NORMAL_PRIORITY_CLASS, THREAD_PRIORITY_BELOW_NORMAL }, - { NORMAL_PRIORITY_CLASS, THREAD_PRIORITY_NORMAL }, - { NORMAL_PRIORITY_CLASS, THREAD_PRIORITY_ABOVE_NORMAL }, - { NORMAL_PRIORITY_CLASS, THREAD_PRIORITY_HIGHEST }, - { HIGH_PRIORITY_CLASS, THREAD_PRIORITY_LOWEST }, - { HIGH_PRIORITY_CLASS, THREAD_PRIORITY_BELOW_NORMAL }, - { HIGH_PRIORITY_CLASS, THREAD_PRIORITY_NORMAL }, - { HIGH_PRIORITY_CLASS, THREAD_PRIORITY_ABOVE_NORMAL }, - { HIGH_PRIORITY_CLASS, THREAD_PRIORITY_HIGHEST }, - { REALTIME_PRIORITY_CLASS, THREAD_PRIORITY_IDLE }, - { REALTIME_PRIORITY_CLASS, THREAD_PRIORITY_LOWEST }, - { REALTIME_PRIORITY_CLASS, THREAD_PRIORITY_BELOW_NORMAL }, - { REALTIME_PRIORITY_CLASS, THREAD_PRIORITY_NORMAL }, - { REALTIME_PRIORITY_CLASS, THREAD_PRIORITY_ABOVE_NORMAL }, - { REALTIME_PRIORITY_CLASS, THREAD_PRIORITY_HIGHEST }, - { REALTIME_PRIORITY_CLASS, THREAD_PRIORITY_TIME_CRITICAL} - }; +void ArchMultithreadWindows::closeThread(ArchThread thread) { + assert(thread != NULL); + + // decrement ref count and clean up thread if no more references + if (--thread->m_refCount == 0) { + // close the handle (main thread has a NULL handle) + if (thread->m_thread != NULL) { + CloseHandle(thread->m_thread); + } + + // remove thread from list + lockMutex(m_threadMutex); + assert(findNoRefOrCreate(thread->m_id) == thread); + erase(thread); + unlockMutex(m_threadMutex); + + // done with thread + delete thread; + } +} + +ArchThread ArchMultithreadWindows::copyThread(ArchThread thread) { + refThread(thread); + return thread; +} + +void ArchMultithreadWindows::cancelThread(ArchThread thread) { + assert(thread != NULL); + + // set cancel flag + SetEvent(thread->m_cancel); +} + +void ArchMultithreadWindows::setPriorityOfThread(ArchThread thread, int n) { + struct PriorityInfo { + public: + DWORD m_class; + int m_level; + }; + static const PriorityInfo s_pClass[] = { + {IDLE_PRIORITY_CLASS, THREAD_PRIORITY_IDLE}, + {IDLE_PRIORITY_CLASS, THREAD_PRIORITY_LOWEST}, + {IDLE_PRIORITY_CLASS, THREAD_PRIORITY_BELOW_NORMAL}, + {IDLE_PRIORITY_CLASS, THREAD_PRIORITY_NORMAL}, + {IDLE_PRIORITY_CLASS, THREAD_PRIORITY_ABOVE_NORMAL}, + {IDLE_PRIORITY_CLASS, THREAD_PRIORITY_HIGHEST}, + {NORMAL_PRIORITY_CLASS, THREAD_PRIORITY_LOWEST}, + {NORMAL_PRIORITY_CLASS, THREAD_PRIORITY_BELOW_NORMAL}, + {NORMAL_PRIORITY_CLASS, THREAD_PRIORITY_NORMAL}, + {NORMAL_PRIORITY_CLASS, THREAD_PRIORITY_ABOVE_NORMAL}, + {NORMAL_PRIORITY_CLASS, THREAD_PRIORITY_HIGHEST}, + {HIGH_PRIORITY_CLASS, THREAD_PRIORITY_LOWEST}, + {HIGH_PRIORITY_CLASS, THREAD_PRIORITY_BELOW_NORMAL}, + {HIGH_PRIORITY_CLASS, THREAD_PRIORITY_NORMAL}, + {HIGH_PRIORITY_CLASS, THREAD_PRIORITY_ABOVE_NORMAL}, + {HIGH_PRIORITY_CLASS, THREAD_PRIORITY_HIGHEST}, + {REALTIME_PRIORITY_CLASS, THREAD_PRIORITY_IDLE}, + {REALTIME_PRIORITY_CLASS, THREAD_PRIORITY_LOWEST}, + {REALTIME_PRIORITY_CLASS, THREAD_PRIORITY_BELOW_NORMAL}, + {REALTIME_PRIORITY_CLASS, THREAD_PRIORITY_NORMAL}, + {REALTIME_PRIORITY_CLASS, THREAD_PRIORITY_ABOVE_NORMAL}, + {REALTIME_PRIORITY_CLASS, THREAD_PRIORITY_HIGHEST}, + {REALTIME_PRIORITY_CLASS, THREAD_PRIORITY_TIME_CRITICAL}}; #if defined(_DEBUG) - // don't use really high priorities when debugging - static const size_t s_pMax = 13; + // don't use really high priorities when debugging + static const size_t s_pMax = 13; #else - static const size_t s_pMax = sizeof(s_pClass) / sizeof(s_pClass[0]) - 1; + static const size_t s_pMax = sizeof(s_pClass) / sizeof(s_pClass[0]) - 1; #endif - static const size_t s_pBase = 8; // index of normal priority + static const size_t s_pBase = 8; // index of normal priority - assert(thread != NULL); + assert(thread != NULL); - size_t index; - if (n > 0 && s_pBase < (size_t)n) { - // lowest priority - index = 0; + size_t index; + if (n > 0 && s_pBase < (size_t)n) { + // lowest priority + index = 0; + } else { + index = (size_t)((int)s_pBase - n); + if (index > s_pMax) { + // highest priority + index = s_pMax; } - else { - index = (size_t)((int)s_pBase - n); - if (index > s_pMax) { - // highest priority - index = s_pMax; - } - } - SetPriorityClass(GetCurrentProcess(), s_pClass[index].m_class); - SetThreadPriority(thread->m_thread, s_pClass[index].m_level); + } + SetPriorityClass(GetCurrentProcess(), s_pClass[index].m_class); + SetThreadPriority(thread->m_thread, s_pClass[index].m_level); } -void -ArchMultithreadWindows::testCancelThread() -{ - // find current thread - lockMutex(m_threadMutex); - ArchThreadImpl* thread = findNoRef(GetCurrentThreadId()); +void ArchMultithreadWindows::testCancelThread() { + // find current thread + lockMutex(m_threadMutex); + ArchThreadImpl *thread = findNoRef(GetCurrentThreadId()); + unlockMutex(m_threadMutex); + + // test cancel on thread + testCancelThreadImpl(thread); +} + +bool ArchMultithreadWindows::wait(ArchThread target, double timeout) { + assert(target != NULL); + + lockMutex(m_threadMutex); + + // find current thread + ArchThreadImpl *self = findNoRef(GetCurrentThreadId()); + + // ignore wait if trying to wait on ourself + if (target == self) { unlockMutex(m_threadMutex); + return false; + } - // test cancel on thread - testCancelThreadImpl(thread); + // ref the target so it can't go away while we're watching it + refThread(target); + + unlockMutex(m_threadMutex); + + // convert timeout + DWORD t; + if (timeout < 0.0) { + t = INFINITE; + } else { + t = (DWORD)(1000.0 * timeout); + } + + // wait for this thread to be cancelled or woken up or for the + // target thread to terminate. + HANDLE handles[2]; + handles[0] = target->m_exit; + handles[1] = self->m_cancel; + DWORD result = WaitForMultipleObjects(2, handles, FALSE, t); + + // cancel takes priority + if (result != WAIT_OBJECT_0 + 1 && + WaitForSingleObject(handles[1], 0) == WAIT_OBJECT_0) { + result = WAIT_OBJECT_0 + 1; + } + + // release target + closeThread(target); + + // handle result + switch (result) { + case WAIT_OBJECT_0 + 0: + // target thread terminated + return true; + + case WAIT_OBJECT_0 + 1: + // this thread was cancelled. does not return. + testCancelThreadImpl(self); + + default: + // timeout or error + return false; + } } -bool -ArchMultithreadWindows::wait(ArchThread target, double timeout) -{ - assert(target != NULL); - - lockMutex(m_threadMutex); - - // find current thread - ArchThreadImpl* self = findNoRef(GetCurrentThreadId()); - - // ignore wait if trying to wait on ourself - if (target == self) { - unlockMutex(m_threadMutex); - return false; - } - - // ref the target so it can't go away while we're watching it - refThread(target); - - unlockMutex(m_threadMutex); - - // convert timeout - DWORD t; - if (timeout < 0.0) { - t = INFINITE; - } - else { - t = (DWORD)(1000.0 * timeout); - } - - // wait for this thread to be cancelled or woken up or for the - // target thread to terminate. - HANDLE handles[2]; - handles[0] = target->m_exit; - handles[1] = self->m_cancel; - DWORD result = WaitForMultipleObjects(2, handles, FALSE, t); - - // cancel takes priority - if (result != WAIT_OBJECT_0 + 1 && - WaitForSingleObject(handles[1], 0) == WAIT_OBJECT_0) { - result = WAIT_OBJECT_0 + 1; - } - - // release target - closeThread(target); - - // handle result - switch (result) { - case WAIT_OBJECT_0 + 0: - // target thread terminated - return true; - - case WAIT_OBJECT_0 + 1: - // this thread was cancelled. does not return. - testCancelThreadImpl(self); - - default: - // timeout or error - return false; - } +bool ArchMultithreadWindows::isSameThread(ArchThread thread1, + ArchThread thread2) { + return (thread1 == thread2); } -bool -ArchMultithreadWindows::isSameThread(ArchThread thread1, ArchThread thread2) -{ - return (thread1 == thread2); +bool ArchMultithreadWindows::isExitedThread(ArchThread thread) { + // poll exit event + return (WaitForSingleObject(thread->m_exit, 0) == WAIT_OBJECT_0); } -bool -ArchMultithreadWindows::isExitedThread(ArchThread thread) -{ - // poll exit event - return (WaitForSingleObject(thread->m_exit, 0) == WAIT_OBJECT_0); -} - -void* -ArchMultithreadWindows::getResultOfThread(ArchThread thread) -{ - lockMutex(m_threadMutex); - void* result = thread->m_result; - unlockMutex(m_threadMutex); - return result; +void *ArchMultithreadWindows::getResultOfThread(ArchThread thread) { + lockMutex(m_threadMutex); + void *result = thread->m_result; + unlockMutex(m_threadMutex); + return result; } IArchMultithread::ThreadID -ArchMultithreadWindows::getIDOfThread(ArchThread thread) -{ - return static_cast(thread->m_id); +ArchMultithreadWindows::getIDOfThread(ArchThread thread) { + return static_cast(thread->m_id); } -void -ArchMultithreadWindows::setSignalHandler( - ESignal signal, SignalFunc func, void* userData) -{ - lockMutex(m_threadMutex); - m_signalFunc[signal] = func; - m_signalUserData[signal] = userData; - unlockMutex(m_threadMutex); +void ArchMultithreadWindows::setSignalHandler(ESignal signal, SignalFunc func, + void *userData) { + lockMutex(m_threadMutex); + m_signalFunc[signal] = func; + m_signalUserData[signal] = userData; + unlockMutex(m_threadMutex); } -void -ArchMultithreadWindows::raiseSignal(ESignal signal) -{ - lockMutex(m_threadMutex); - if (m_signalFunc[signal] != NULL) { - m_signalFunc[signal](signal, m_signalUserData[signal]); - ARCH->unblockPollSocket(m_mainThread); - } - else if (signal == kINTERRUPT || signal == kTERMINATE) { - ARCH->cancelThread(m_mainThread); - } - unlockMutex(m_threadMutex); +void ArchMultithreadWindows::raiseSignal(ESignal signal) { + lockMutex(m_threadMutex); + if (m_signalFunc[signal] != NULL) { + m_signalFunc[signal](signal, m_signalUserData[signal]); + ARCH->unblockPollSocket(m_mainThread); + } else if (signal == kINTERRUPT || signal == kTERMINATE) { + ARCH->cancelThread(m_mainThread); + } + unlockMutex(m_threadMutex); } -ArchThreadImpl* -ArchMultithreadWindows::find(DWORD id) -{ - ArchThreadImpl* impl = findNoRef(id); - if (impl != NULL) { - refThread(impl); - } - return impl; +ArchThreadImpl *ArchMultithreadWindows::find(DWORD id) { + ArchThreadImpl *impl = findNoRef(id); + if (impl != NULL) { + refThread(impl); + } + return impl; } -ArchThreadImpl* -ArchMultithreadWindows::findNoRef(DWORD id) -{ - ArchThreadImpl* impl = findNoRefOrCreate(id); - if (impl == NULL) { - // create thread for calling thread which isn't in our list and - // add it to the list. this won't normally happen but it can if - // the system calls us under a new thread, like it does when we - // run as a service. - impl = new ArchThreadImpl; - impl->m_thread = NULL; - impl->m_id = GetCurrentThreadId(); - insert(impl); - } - return impl; +ArchThreadImpl *ArchMultithreadWindows::findNoRef(DWORD id) { + ArchThreadImpl *impl = findNoRefOrCreate(id); + if (impl == NULL) { + // create thread for calling thread which isn't in our list and + // add it to the list. this won't normally happen but it can if + // the system calls us under a new thread, like it does when we + // run as a service. + impl = new ArchThreadImpl; + impl->m_thread = NULL; + impl->m_id = GetCurrentThreadId(); + insert(impl); + } + return impl; } -ArchThreadImpl* -ArchMultithreadWindows::findNoRefOrCreate(DWORD id) -{ - // linear search - for (ThreadList::const_iterator index = m_threadList.begin(); - index != m_threadList.end(); ++index) { - if ((*index)->m_id == id) { - return *index; - } +ArchThreadImpl *ArchMultithreadWindows::findNoRefOrCreate(DWORD id) { + // linear search + for (ThreadList::const_iterator index = m_threadList.begin(); + index != m_threadList.end(); ++index) { + if ((*index)->m_id == id) { + return *index; } - return NULL; + } + return NULL; } -void -ArchMultithreadWindows::insert(ArchThreadImpl* thread) -{ - assert(thread != NULL); +void ArchMultithreadWindows::insert(ArchThreadImpl *thread) { + assert(thread != NULL); - // thread shouldn't already be on the list - assert(findNoRefOrCreate(thread->m_id) == NULL); + // thread shouldn't already be on the list + assert(findNoRefOrCreate(thread->m_id) == NULL); - // append to list - m_threadList.push_back(thread); + // append to list + m_threadList.push_back(thread); } -void -ArchMultithreadWindows::erase(ArchThreadImpl* thread) -{ - for (ThreadList::iterator index = m_threadList.begin(); - index != m_threadList.end(); ++index) { - if (*index == thread) { - m_threadList.erase(index); - break; - } +void ArchMultithreadWindows::erase(ArchThreadImpl *thread) { + for (ThreadList::iterator index = m_threadList.begin(); + index != m_threadList.end(); ++index) { + if (*index == thread) { + m_threadList.erase(index); + break; } + } } -void -ArchMultithreadWindows::refThread(ArchThreadImpl* thread) -{ - assert(thread != NULL); - assert(findNoRefOrCreate(thread->m_id) != NULL); - ++thread->m_refCount; +void ArchMultithreadWindows::refThread(ArchThreadImpl *thread) { + assert(thread != NULL); + assert(findNoRefOrCreate(thread->m_id) != NULL); + ++thread->m_refCount; } -void -ArchMultithreadWindows::testCancelThreadImpl(ArchThreadImpl* thread) -{ - assert(thread != NULL); +void ArchMultithreadWindows::testCancelThreadImpl(ArchThreadImpl *thread) { + assert(thread != NULL); - // poll cancel event. return if not set. - const DWORD result = WaitForSingleObject(thread->m_cancel, 0); - if (result != WAIT_OBJECT_0) { - return; - } + // poll cancel event. return if not set. + const DWORD result = WaitForSingleObject(thread->m_cancel, 0); + if (result != WAIT_OBJECT_0) { + return; + } - // update cancel state - lockMutex(m_threadMutex); - bool cancel = !thread->m_cancelling; - thread->m_cancelling = true; - ResetEvent(thread->m_cancel); - unlockMutex(m_threadMutex); + // update cancel state + lockMutex(m_threadMutex); + bool cancel = !thread->m_cancelling; + thread->m_cancelling = true; + ResetEvent(thread->m_cancel); + unlockMutex(m_threadMutex); - // unwind thread's stack if cancelling - if (cancel) { - throw XThreadCancel(); - } + // unwind thread's stack if cancelling + if (cancel) { + throw XThreadCancel(); + } } -unsigned int __stdcall -ArchMultithreadWindows::threadFunc(void* vrep) -{ - // get the thread - ArchThreadImpl* thread = static_cast(vrep); +unsigned int __stdcall ArchMultithreadWindows::threadFunc(void *vrep) { + // get the thread + ArchThreadImpl *thread = static_cast(vrep); - // run thread - s_instance->doThreadFunc(thread); + // run thread + s_instance->doThreadFunc(thread); - // terminate the thread - return 0; + // terminate the thread + return 0; } -void -ArchMultithreadWindows::doThreadFunc(ArchThread thread) -{ - // wait for parent to initialize this object - lockMutex(m_threadMutex); - unlockMutex(m_threadMutex); +void ArchMultithreadWindows::doThreadFunc(ArchThread thread) { + // wait for parent to initialize this object + lockMutex(m_threadMutex); + unlockMutex(m_threadMutex); - void* result = NULL; - try { - // go - result = (*thread->m_func)(thread->m_userData); - } + void *result = NULL; + try { + // go + result = (*thread->m_func)(thread->m_userData); + } - catch (XThreadCancel&) { - // client called cancel() - } - catch (...) { - // note -- don't catch (...) to avoid masking bugs - SetEvent(thread->m_exit); - closeThread(thread); - throw; - } - - // thread has exited - lockMutex(m_threadMutex); - thread->m_result = result; - unlockMutex(m_threadMutex); + catch (XThreadCancel &) { + // client called cancel() + } catch (...) { + // note -- don't catch (...) to avoid masking bugs SetEvent(thread->m_exit); - - // done with thread closeThread(thread); + throw; + } + + // thread has exited + lockMutex(m_threadMutex); + thread->m_result = result; + unlockMutex(m_threadMutex); + SetEvent(thread->m_exit); + + // done with thread + closeThread(thread); } diff --git a/src/lib/arch/win32/ArchMultithreadWindows.h b/src/lib/arch/win32/ArchMultithreadWindows.h index ac4daa57b..527338ba0 100644 --- a/src/lib/arch/win32/ArchMultithreadWindows.h +++ b/src/lib/arch/win32/ArchMultithreadWindows.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -28,89 +28,89 @@ class ArchCondImpl { public: - enum { kSignal = 0, kBroadcast }; + enum { kSignal = 0, kBroadcast }; - HANDLE m_events[2]; - mutable int m_waitCount; - ArchMutex m_waitCountMutex; + HANDLE m_events[2]; + mutable int m_waitCount; + ArchMutex m_waitCountMutex; }; class ArchMutexImpl { public: - CRITICAL_SECTION m_mutex; + CRITICAL_SECTION m_mutex; }; //! Win32 implementation of IArchMultithread class ArchMultithreadWindows : public IArchMultithread { public: - ArchMultithreadWindows(); - virtual ~ArchMultithreadWindows(); + ArchMultithreadWindows(); + virtual ~ArchMultithreadWindows(); - //! @name manipulators - //@{ + //! @name manipulators + //@{ - void setNetworkDataForCurrentThread(void*); + void setNetworkDataForCurrentThread(void *); - //@} - //! @name accessors - //@{ + //@} + //! @name accessors + //@{ - HANDLE getCancelEventForCurrentThread(); + HANDLE getCancelEventForCurrentThread(); - void* getNetworkDataForThread(ArchThread); + void *getNetworkDataForThread(ArchThread); - static ArchMultithreadWindows* getInstance(); + static ArchMultithreadWindows *getInstance(); - //@} + //@} - // IArchMultithread overrides - virtual ArchCond newCondVar(); - virtual void closeCondVar(ArchCond); - virtual void signalCondVar(ArchCond); - virtual void broadcastCondVar(ArchCond); - virtual bool waitCondVar(ArchCond, ArchMutex, double timeout); - virtual ArchMutex newMutex(); - virtual void closeMutex(ArchMutex); - virtual void lockMutex(ArchMutex); - virtual void unlockMutex(ArchMutex); - virtual ArchThread newThread(ThreadFunc, void*); - virtual ArchThread newCurrentThread(); - virtual ArchThread copyThread(ArchThread); - virtual void closeThread(ArchThread); - virtual void cancelThread(ArchThread); - virtual void setPriorityOfThread(ArchThread, int n); - virtual void testCancelThread(); - virtual bool wait(ArchThread, double timeout); - virtual bool isSameThread(ArchThread, ArchThread); - virtual bool isExitedThread(ArchThread); - virtual void* getResultOfThread(ArchThread); - virtual ThreadID getIDOfThread(ArchThread); - virtual void setSignalHandler(ESignal, SignalFunc, void*); - virtual void raiseSignal(ESignal); + // IArchMultithread overrides + virtual ArchCond newCondVar(); + virtual void closeCondVar(ArchCond); + virtual void signalCondVar(ArchCond); + virtual void broadcastCondVar(ArchCond); + virtual bool waitCondVar(ArchCond, ArchMutex, double timeout); + virtual ArchMutex newMutex(); + virtual void closeMutex(ArchMutex); + virtual void lockMutex(ArchMutex); + virtual void unlockMutex(ArchMutex); + virtual ArchThread newThread(ThreadFunc, void *); + virtual ArchThread newCurrentThread(); + virtual ArchThread copyThread(ArchThread); + virtual void closeThread(ArchThread); + virtual void cancelThread(ArchThread); + virtual void setPriorityOfThread(ArchThread, int n); + virtual void testCancelThread(); + virtual bool wait(ArchThread, double timeout); + virtual bool isSameThread(ArchThread, ArchThread); + virtual bool isExitedThread(ArchThread); + virtual void *getResultOfThread(ArchThread); + virtual ThreadID getIDOfThread(ArchThread); + virtual void setSignalHandler(ESignal, SignalFunc, void *); + virtual void raiseSignal(ESignal); private: - ArchThreadImpl* find(DWORD id); - ArchThreadImpl* findNoRef(DWORD id); - ArchThreadImpl* findNoRefOrCreate(DWORD id); - void insert(ArchThreadImpl* thread); - void erase(ArchThreadImpl* thread); + ArchThreadImpl *find(DWORD id); + ArchThreadImpl *findNoRef(DWORD id); + ArchThreadImpl *findNoRefOrCreate(DWORD id); + void insert(ArchThreadImpl *thread); + void erase(ArchThreadImpl *thread); - void refThread(ArchThreadImpl* rep); - void testCancelThreadImpl(ArchThreadImpl* rep); + void refThread(ArchThreadImpl *rep); + void testCancelThreadImpl(ArchThreadImpl *rep); - void doThreadFunc(ArchThread thread); - static unsigned int __stdcall threadFunc(void* vrep); + void doThreadFunc(ArchThread thread); + static unsigned int __stdcall threadFunc(void *vrep); private: - typedef std::list ThreadList; + typedef std::list ThreadList; - static ArchMultithreadWindows* s_instance; + static ArchMultithreadWindows *s_instance; - ArchMutex m_threadMutex; + ArchMutex m_threadMutex; - ThreadList m_threadList; - ArchThread m_mainThread; + ThreadList m_threadList; + ArchThread m_mainThread; - SignalFunc m_signalFunc[kNUM_SIGNALS]; - void* m_signalUserData[kNUM_SIGNALS]; + SignalFunc m_signalFunc[kNUM_SIGNALS]; + void *m_signalUserData[kNUM_SIGNALS]; }; diff --git a/src/lib/arch/win32/ArchNetworkWinsock.cpp b/src/lib/arch/win32/ArchNetworkWinsock.cpp index b034c574f..d01a234ae 100644 --- a/src/lib/arch/win32/ArchNetworkWinsock.cpp +++ b/src/lib/arch/win32/ArchNetworkWinsock.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -17,10 +17,10 @@ */ #include "arch/win32/ArchNetworkWinsock.h" +#include "arch/Arch.h" +#include "arch/IArchMultithread.h" #include "arch/win32/ArchMultithreadWindows.h" #include "arch/win32/XArchWindows.h" -#include "arch/IArchMultithread.h" -#include "arch/Arch.h" #include @@ -29,959 +29,928 @@ static const int s_family[] = { PF_INET, PF_INET6, }; -static const int s_type[] = { - SOCK_DGRAM, - SOCK_STREAM -}; +static const int s_type[] = {SOCK_DGRAM, SOCK_STREAM}; -static SOCKET (PASCAL FAR *accept_winsock)(SOCKET s, struct sockaddr FAR *addr, int FAR *addrlen); -static int (PASCAL FAR *bind_winsock)(SOCKET s, const struct sockaddr FAR *addr, int namelen); -static int (PASCAL FAR *close_winsock)(SOCKET s); -static int (PASCAL FAR *connect_winsock)(SOCKET s, const struct sockaddr FAR *name, int namelen); -static int (PASCAL FAR *gethostname_winsock)(char FAR * name, int namelen); -static int (PASCAL FAR *getsockerror_winsock)(void); -static int (PASCAL FAR *getsockopt_winsock)(SOCKET s, int level, int optname, void FAR * optval, int FAR *optlen); -static u_short (PASCAL FAR *htons_winsock)(u_short v); -static char FAR * (PASCAL FAR *inet_ntoa_winsock)(struct in_addr in); -static unsigned long (PASCAL FAR *inet_addr_winsock)(const char FAR * cp); -static int (PASCAL FAR *ioctl_winsock)(SOCKET s, int cmd, void FAR * data); -static int (PASCAL FAR *listen_winsock)(SOCKET s, int backlog); -static u_short (PASCAL FAR *ntohs_winsock)(u_short v); -static int (PASCAL FAR *recv_winsock)(SOCKET s, void FAR * buf, int len, int flags); -static int (PASCAL FAR *select_winsock)(int nfds, fd_set FAR *readfds, fd_set FAR *writefds, fd_set FAR *exceptfds, const struct timeval FAR *timeout); -static int (PASCAL FAR *send_winsock)(SOCKET s, const void FAR * buf, int len, int flags); -static int (PASCAL FAR *setsockopt_winsock)(SOCKET s, int level, int optname, const void FAR * optval, int optlen); -static int (PASCAL FAR *shutdown_winsock)(SOCKET s, int how); -static SOCKET (PASCAL FAR *socket_winsock)(int af, int type, int protocol); -static struct hostent FAR * (PASCAL FAR *gethostbyaddr_winsock)(const char FAR * addr, int len, int type); -static struct hostent FAR * (PASCAL FAR *gethostbyname_winsock)(const char FAR * name); -static int (PASCAL FAR *WSACleanup_winsock)(void); -static int (PASCAL FAR *WSAFDIsSet_winsock)(SOCKET, fd_set FAR * fdset); -static WSAEVENT (PASCAL FAR *WSACreateEvent_winsock)(void); -static BOOL (PASCAL FAR *WSACloseEvent_winsock)(WSAEVENT); -static BOOL (PASCAL FAR *WSASetEvent_winsock)(WSAEVENT); -static BOOL (PASCAL FAR *WSAResetEvent_winsock)(WSAEVENT); -static int (PASCAL FAR *WSAEventSelect_winsock)(SOCKET, WSAEVENT, long); -static DWORD (PASCAL FAR *WSAWaitForMultipleEvents_winsock)(DWORD, const WSAEVENT FAR*, BOOL, DWORD, BOOL); -static int (PASCAL FAR *WSAEnumNetworkEvents_winsock)(SOCKET, WSAEVENT, LPWSANETWORKEVENTS); +static SOCKET(PASCAL FAR *accept_winsock)(SOCKET s, struct sockaddr FAR *addr, + int FAR *addrlen); +static int(PASCAL FAR *bind_winsock)(SOCKET s, const struct sockaddr FAR *addr, + int namelen); +static int(PASCAL FAR *close_winsock)(SOCKET s); +static int(PASCAL FAR *connect_winsock)(SOCKET s, + const struct sockaddr FAR *name, + int namelen); +static int(PASCAL FAR *gethostname_winsock)(char FAR *name, int namelen); +static int(PASCAL FAR *getsockerror_winsock)(void); +static int(PASCAL FAR *getsockopt_winsock)(SOCKET s, int level, int optname, + void FAR *optval, int FAR *optlen); +static u_short(PASCAL FAR *htons_winsock)(u_short v); +static char FAR *(PASCAL FAR *inet_ntoa_winsock)(struct in_addr in); +static unsigned long(PASCAL FAR *inet_addr_winsock)(const char FAR *cp); +static int(PASCAL FAR *ioctl_winsock)(SOCKET s, int cmd, void FAR *data); +static int(PASCAL FAR *listen_winsock)(SOCKET s, int backlog); +static u_short(PASCAL FAR *ntohs_winsock)(u_short v); +static int(PASCAL FAR *recv_winsock)(SOCKET s, void FAR *buf, int len, + int flags); +static int(PASCAL FAR *select_winsock)(int nfds, fd_set FAR *readfds, + fd_set FAR *writefds, + fd_set FAR *exceptfds, + const struct timeval FAR *timeout); +static int(PASCAL FAR *send_winsock)(SOCKET s, const void FAR *buf, int len, + int flags); +static int(PASCAL FAR *setsockopt_winsock)(SOCKET s, int level, int optname, + const void FAR *optval, int optlen); +static int(PASCAL FAR *shutdown_winsock)(SOCKET s, int how); +static SOCKET(PASCAL FAR *socket_winsock)(int af, int type, int protocol); +static struct hostent FAR *(PASCAL FAR *gethostbyaddr_winsock)( + const char FAR *addr, int len, int type); +static struct hostent FAR *(PASCAL FAR *gethostbyname_winsock)( + const char FAR *name); +static int(PASCAL FAR *WSACleanup_winsock)(void); +static int(PASCAL FAR *WSAFDIsSet_winsock)(SOCKET, fd_set FAR *fdset); +static WSAEVENT(PASCAL FAR *WSACreateEvent_winsock)(void); +static BOOL(PASCAL FAR *WSACloseEvent_winsock)(WSAEVENT); +static BOOL(PASCAL FAR *WSASetEvent_winsock)(WSAEVENT); +static BOOL(PASCAL FAR *WSAResetEvent_winsock)(WSAEVENT); +static int(PASCAL FAR *WSAEventSelect_winsock)(SOCKET, WSAEVENT, long); +static DWORD(PASCAL FAR *WSAWaitForMultipleEvents_winsock)(DWORD, + const WSAEVENT FAR *, + BOOL, DWORD, BOOL); +static int(PASCAL FAR *WSAEnumNetworkEvents_winsock)(SOCKET, WSAEVENT, + LPWSANETWORKEVENTS); #undef FD_ISSET #define FD_ISSET(fd, set) WSAFDIsSet_winsock((SOCKET)(fd), (fd_set FAR *)(set)) #define setfunc(var, name, type) var = (type)netGetProcAddress(module, #name) -static HMODULE s_networkModule = NULL; +static HMODULE s_networkModule = NULL; -static -FARPROC -netGetProcAddress(HMODULE module, LPCSTR name) -{ - FARPROC func = ::GetProcAddress(module, name); - if (!func) { - throw XArchNetworkSupport(""); - } - return func; +static FARPROC netGetProcAddress(HMODULE module, LPCSTR name) { + FARPROC func = ::GetProcAddress(module, name); + if (!func) { + throw XArchNetworkSupport(""); + } + return func; } -ArchNetAddressImpl* -ArchNetAddressImpl::alloc(size_t size) -{ - size_t totalSize = size + ADDR_HDR_SIZE; - ArchNetAddressImpl* addr = (ArchNetAddressImpl*)malloc(totalSize); - addr->m_len = (int)size; - return addr; +ArchNetAddressImpl *ArchNetAddressImpl::alloc(size_t size) { + size_t totalSize = size + ADDR_HDR_SIZE; + ArchNetAddressImpl *addr = (ArchNetAddressImpl *)malloc(totalSize); + addr->m_len = (int)size; + return addr; } - // // ArchNetworkWinsock // -ArchNetworkWinsock::ArchNetworkWinsock() : - m_mutex(NULL) -{ +ArchNetworkWinsock::ArchNetworkWinsock() : m_mutex(NULL) {} + +ArchNetworkWinsock::~ArchNetworkWinsock() { + if (s_networkModule != NULL) { + WSACleanup_winsock(); + ::FreeLibrary(s_networkModule); + + WSACleanup_winsock = NULL; + s_networkModule = NULL; + } + if (m_mutex != NULL) { + ARCH->closeMutex(m_mutex); + } + + EventList::iterator it; + for (it = m_unblockEvents.begin(); it != m_unblockEvents.end(); it++) { + delete *it; + } } -ArchNetworkWinsock::~ArchNetworkWinsock() -{ - if (s_networkModule != NULL) { - WSACleanup_winsock(); - ::FreeLibrary(s_networkModule); +void ArchNetworkWinsock::init() { + static const char *s_library[] = {"ws2_32.dll"}; - WSACleanup_winsock = NULL; - s_networkModule = NULL; - } - if (m_mutex != NULL) { - ARCH->closeMutex(m_mutex); - } + assert(WSACleanup_winsock == NULL); + assert(s_networkModule == NULL); - EventList::iterator it; - for (it = m_unblockEvents.begin(); it != m_unblockEvents.end(); it++) { - delete *it; - } -} - -void -ArchNetworkWinsock::init() -{ - static const char* s_library[] = { "ws2_32.dll" }; - - assert(WSACleanup_winsock == NULL); - assert(s_networkModule == NULL); - - // try each winsock library - for (size_t i = 0; i < sizeof(s_library) / sizeof(s_library[0]); ++i) { - try { - initModule((HMODULE)::LoadLibrary(s_library[i])); - m_mutex = ARCH->newMutex(); - return; - } - catch (XArchNetwork&) { - // ignore - } - } - - // can't initialize any library - throw XArchNetworkSupport("Cannot load winsock library"); -} - -void -ArchNetworkWinsock::initModule(HMODULE module) -{ - if (module == NULL) { - throw XArchNetworkSupport(""); - } - - // get startup function address - int (PASCAL FAR *startup)(WORD, LPWSADATA); - setfunc(startup, WSAStartup, int(PASCAL FAR*)(WORD, LPWSADATA)); - - // startup network library - WORD version = MAKEWORD(2 /*major*/, 2 /*minor*/); - WSADATA data; - int err = startup(version, &data); - if (data.wVersion != version) { - throw XArchNetworkSupport(new XArchEvalWinsock(err)); - } - if (err != 0) { - // some other initialization error - throwError(err); - } - - // get function addresses - setfunc(accept_winsock, accept, SOCKET (PASCAL FAR *)(SOCKET s, struct sockaddr FAR *addr, int FAR *addrlen)); - setfunc(bind_winsock, bind, int (PASCAL FAR *)(SOCKET s, const struct sockaddr FAR *addr, int namelen)); - setfunc(close_winsock, closesocket, int (PASCAL FAR *)(SOCKET s)); - setfunc(connect_winsock, connect, int (PASCAL FAR *)(SOCKET s, const struct sockaddr FAR *name, int namelen)); - setfunc(gethostname_winsock, gethostname, int (PASCAL FAR *)(char FAR * name, int namelen)); - setfunc(getsockerror_winsock, WSAGetLastError, int (PASCAL FAR *)(void)); - setfunc(getsockopt_winsock, getsockopt, int (PASCAL FAR *)(SOCKET s, int level, int optname, void FAR * optval, int FAR *optlen)); - setfunc(htons_winsock, htons, u_short (PASCAL FAR *)(u_short v)); - setfunc(inet_ntoa_winsock, inet_ntoa, char FAR * (PASCAL FAR *)(struct in_addr in)); - setfunc(inet_addr_winsock, inet_addr, unsigned long (PASCAL FAR *)(const char FAR * cp)); - setfunc(ioctl_winsock, ioctlsocket, int (PASCAL FAR *)(SOCKET s, int cmd, void FAR *)); - setfunc(listen_winsock, listen, int (PASCAL FAR *)(SOCKET s, int backlog)); - setfunc(ntohs_winsock, ntohs, u_short (PASCAL FAR *)(u_short v)); - setfunc(recv_winsock, recv, int (PASCAL FAR *)(SOCKET s, void FAR * buf, int len, int flags)); - setfunc(select_winsock, select, int (PASCAL FAR *)(int nfds, fd_set FAR *readfds, fd_set FAR *writefds, fd_set FAR *exceptfds, const struct timeval FAR *timeout)); - setfunc(send_winsock, send, int (PASCAL FAR *)(SOCKET s, const void FAR * buf, int len, int flags)); - setfunc(setsockopt_winsock, setsockopt, int (PASCAL FAR *)(SOCKET s, int level, int optname, const void FAR * optval, int optlen)); - setfunc(shutdown_winsock, shutdown, int (PASCAL FAR *)(SOCKET s, int how)); - setfunc(socket_winsock, socket, SOCKET (PASCAL FAR *)(int af, int type, int protocol)); - setfunc(gethostbyaddr_winsock, gethostbyaddr, struct hostent FAR * (PASCAL FAR *)(const char FAR * addr, int len, int type)); - setfunc(gethostbyname_winsock, gethostbyname, struct hostent FAR * (PASCAL FAR *)(const char FAR * name)); - setfunc(WSACleanup_winsock, WSACleanup, int (PASCAL FAR *)(void)); - setfunc(WSAFDIsSet_winsock, __WSAFDIsSet, int (PASCAL FAR *)(SOCKET, fd_set FAR *)); - setfunc(WSACreateEvent_winsock, WSACreateEvent, WSAEVENT (PASCAL FAR *)(void)); - setfunc(WSACloseEvent_winsock, WSACloseEvent, BOOL (PASCAL FAR *)(WSAEVENT)); - setfunc(WSASetEvent_winsock, WSASetEvent, BOOL (PASCAL FAR *)(WSAEVENT)); - setfunc(WSAResetEvent_winsock, WSAResetEvent, BOOL (PASCAL FAR *)(WSAEVENT)); - setfunc(WSAEventSelect_winsock, WSAEventSelect, int (PASCAL FAR *)(SOCKET, WSAEVENT, long)); - setfunc(WSAWaitForMultipleEvents_winsock, WSAWaitForMultipleEvents, DWORD (PASCAL FAR *)(DWORD, const WSAEVENT FAR*, BOOL, DWORD, BOOL)); - setfunc(WSAEnumNetworkEvents_winsock, WSAEnumNetworkEvents, int (PASCAL FAR *)(SOCKET, WSAEVENT, LPWSANETWORKEVENTS)); - - s_networkModule = module; -} - -ArchSocket -ArchNetworkWinsock::newSocket(EAddressFamily family, ESocketType type) -{ - // create socket - SOCKET fd = socket_winsock(s_family[family], s_type[type], 0); - if (fd == INVALID_SOCKET) { - throwError(getsockerror_winsock()); - } + // try each winsock library + for (size_t i = 0; i < sizeof(s_library) / sizeof(s_library[0]); ++i) { try { - setBlockingOnSocket(fd, false); - BOOL flag = 0; - int size = sizeof(flag); - if (setsockopt_winsock(fd, IPPROTO_IPV6, IPV6_V6ONLY, &flag, size) == SOCKET_ERROR) { - throwError(getsockerror_winsock()); - } - } - catch (...) { - close_winsock(fd); - throw; + initModule((HMODULE)::LoadLibrary(s_library[i])); + m_mutex = ARCH->newMutex(); + return; + } catch (XArchNetwork &) { + // ignore } + } - // allocate socket object - ArchSocketImpl* socket = new ArchSocketImpl; - socket->m_socket = fd; - socket->m_refCount = 1; - socket->m_event = WSACreateEvent_winsock(); - socket->m_pollWrite = true; - return socket; + // can't initialize any library + throw XArchNetworkSupport("Cannot load winsock library"); } -ArchSocket -ArchNetworkWinsock::copySocket(ArchSocket s) -{ - assert(s != NULL); +void ArchNetworkWinsock::initModule(HMODULE module) { + if (module == NULL) { + throw XArchNetworkSupport(""); + } - // ref the socket and return it - ARCH->lockMutex(m_mutex); - ++s->m_refCount; - ARCH->unlockMutex(m_mutex); - return s; + // get startup function address + int(PASCAL FAR * startup)(WORD, LPWSADATA); + setfunc(startup, WSAStartup, int(PASCAL FAR *)(WORD, LPWSADATA)); + + // startup network library + WORD version = MAKEWORD(2 /*major*/, 2 /*minor*/); + WSADATA data; + int err = startup(version, &data); + if (data.wVersion != version) { + throw XArchNetworkSupport(new XArchEvalWinsock(err)); + } + if (err != 0) { + // some other initialization error + throwError(err); + } + + // get function addresses + setfunc(accept_winsock, accept, + SOCKET(PASCAL FAR *)(SOCKET s, struct sockaddr FAR * addr, + int FAR *addrlen)); + setfunc(bind_winsock, bind, + int(PASCAL FAR *)(SOCKET s, const struct sockaddr FAR *addr, + int namelen)); + setfunc(close_winsock, closesocket, int(PASCAL FAR *)(SOCKET s)); + setfunc(connect_winsock, connect, + int(PASCAL FAR *)(SOCKET s, const struct sockaddr FAR *name, + int namelen)); + setfunc(gethostname_winsock, gethostname, + int(PASCAL FAR *)(char FAR *name, int namelen)); + setfunc(getsockerror_winsock, WSAGetLastError, int(PASCAL FAR *)(void)); + setfunc(getsockopt_winsock, getsockopt, + int(PASCAL FAR *)(SOCKET s, int level, int optname, void FAR *optval, + int FAR *optlen)); + setfunc(htons_winsock, htons, u_short(PASCAL FAR *)(u_short v)); + setfunc(inet_ntoa_winsock, inet_ntoa, + char FAR *(PASCAL FAR *)(struct in_addr in)); + setfunc(inet_addr_winsock, inet_addr, + unsigned long(PASCAL FAR *)(const char FAR *cp)); + setfunc(ioctl_winsock, ioctlsocket, + int(PASCAL FAR *)(SOCKET s, int cmd, void FAR *)); + setfunc(listen_winsock, listen, int(PASCAL FAR *)(SOCKET s, int backlog)); + setfunc(ntohs_winsock, ntohs, u_short(PASCAL FAR *)(u_short v)); + setfunc(recv_winsock, recv, + int(PASCAL FAR *)(SOCKET s, void FAR *buf, int len, int flags)); + setfunc(select_winsock, select, + int(PASCAL FAR *)(int nfds, fd_set FAR *readfds, fd_set FAR *writefds, + fd_set FAR *exceptfds, + const struct timeval FAR *timeout)); + setfunc(send_winsock, send, + int(PASCAL FAR *)(SOCKET s, const void FAR *buf, int len, int flags)); + setfunc(setsockopt_winsock, setsockopt, + int(PASCAL FAR *)(SOCKET s, int level, int optname, + const void FAR *optval, int optlen)); + setfunc(shutdown_winsock, shutdown, int(PASCAL FAR *)(SOCKET s, int how)); + setfunc(socket_winsock, socket, + SOCKET(PASCAL FAR *)(int af, int type, int protocol)); + setfunc(gethostbyaddr_winsock, gethostbyaddr, + struct hostent FAR * + (PASCAL FAR *)(const char FAR *addr, int len, int type)); + setfunc(gethostbyname_winsock, gethostbyname, + struct hostent FAR * (PASCAL FAR *)(const char FAR *name)); + setfunc(WSACleanup_winsock, WSACleanup, int(PASCAL FAR *)(void)); + setfunc(WSAFDIsSet_winsock, __WSAFDIsSet, + int(PASCAL FAR *)(SOCKET, fd_set FAR *)); + setfunc(WSACreateEvent_winsock, WSACreateEvent, WSAEVENT(PASCAL FAR *)(void)); + setfunc(WSACloseEvent_winsock, WSACloseEvent, BOOL(PASCAL FAR *)(WSAEVENT)); + setfunc(WSASetEvent_winsock, WSASetEvent, BOOL(PASCAL FAR *)(WSAEVENT)); + setfunc(WSAResetEvent_winsock, WSAResetEvent, BOOL(PASCAL FAR *)(WSAEVENT)); + setfunc(WSAEventSelect_winsock, WSAEventSelect, + int(PASCAL FAR *)(SOCKET, WSAEVENT, long)); + setfunc(WSAWaitForMultipleEvents_winsock, WSAWaitForMultipleEvents, + DWORD(PASCAL FAR *)(DWORD, const WSAEVENT FAR *, BOOL, DWORD, BOOL)); + setfunc(WSAEnumNetworkEvents_winsock, WSAEnumNetworkEvents, + int(PASCAL FAR *)(SOCKET, WSAEVENT, LPWSANETWORKEVENTS)); + + s_networkModule = module; } -void -ArchNetworkWinsock::closeSocket(ArchSocket s) -{ - assert(s != NULL); - - // unref the socket and note if it should be released - ARCH->lockMutex(m_mutex); - const bool doClose = (--s->m_refCount == 0); - ARCH->unlockMutex(m_mutex); - - // close the socket if necessary - if (doClose) { - if (close_winsock(s->m_socket) == SOCKET_ERROR) { - // close failed. restore the last ref and throw. - int err = getsockerror_winsock(); - ARCH->lockMutex(m_mutex); - ++s->m_refCount; - ARCH->unlockMutex(m_mutex); - throwError(err); - } - WSACloseEvent_winsock(s->m_event); - delete s; +ArchSocket ArchNetworkWinsock::newSocket(EAddressFamily family, + ESocketType type) { + // create socket + SOCKET fd = socket_winsock(s_family[family], s_type[type], 0); + if (fd == INVALID_SOCKET) { + throwError(getsockerror_winsock()); + } + try { + setBlockingOnSocket(fd, false); + BOOL flag = 0; + int size = sizeof(flag); + if (setsockopt_winsock(fd, IPPROTO_IPV6, IPV6_V6ONLY, &flag, size) == + SOCKET_ERROR) { + throwError(getsockerror_winsock()); } + } catch (...) { + close_winsock(fd); + throw; + } + + // allocate socket object + ArchSocketImpl *socket = new ArchSocketImpl; + socket->m_socket = fd; + socket->m_refCount = 1; + socket->m_event = WSACreateEvent_winsock(); + socket->m_pollWrite = true; + return socket; } -void -ArchNetworkWinsock::closeSocketForRead(ArchSocket s) -{ - assert(s != NULL); +ArchSocket ArchNetworkWinsock::copySocket(ArchSocket s) { + assert(s != NULL); - if (shutdown_winsock(s->m_socket, SD_RECEIVE) == SOCKET_ERROR) { - if (getsockerror_winsock() != WSAENOTCONN) { - throwError(getsockerror_winsock()); - } - } + // ref the socket and return it + ARCH->lockMutex(m_mutex); + ++s->m_refCount; + ARCH->unlockMutex(m_mutex); + return s; } -void -ArchNetworkWinsock::closeSocketForWrite(ArchSocket s) -{ - assert(s != NULL); +void ArchNetworkWinsock::closeSocket(ArchSocket s) { + assert(s != NULL); - if (shutdown_winsock(s->m_socket, SD_SEND) == SOCKET_ERROR) { - if (getsockerror_winsock() != WSAENOTCONN) { - throwError(getsockerror_winsock()); - } + // unref the socket and note if it should be released + ARCH->lockMutex(m_mutex); + const bool doClose = (--s->m_refCount == 0); + ARCH->unlockMutex(m_mutex); + + // close the socket if necessary + if (doClose) { + if (close_winsock(s->m_socket) == SOCKET_ERROR) { + // close failed. restore the last ref and throw. + int err = getsockerror_winsock(); + ARCH->lockMutex(m_mutex); + ++s->m_refCount; + ARCH->unlockMutex(m_mutex); + throwError(err); } + WSACloseEvent_winsock(s->m_event); + delete s; + } } -void -ArchNetworkWinsock::bindSocket(ArchSocket s, ArchNetAddress addr) -{ - assert(s != NULL); - assert(addr != NULL); +void ArchNetworkWinsock::closeSocketForRead(ArchSocket s) { + assert(s != NULL); - if (bind_winsock(s->m_socket, TYPED_ADDR(struct sockaddr, addr), addr->m_len) == SOCKET_ERROR) { - throwError(getsockerror_winsock()); + if (shutdown_winsock(s->m_socket, SD_RECEIVE) == SOCKET_ERROR) { + if (getsockerror_winsock() != WSAENOTCONN) { + throwError(getsockerror_winsock()); } + } } -void -ArchNetworkWinsock::listenOnSocket(ArchSocket s) -{ - assert(s != NULL); +void ArchNetworkWinsock::closeSocketForWrite(ArchSocket s) { + assert(s != NULL); - // hardcoding backlog - if (listen_winsock(s->m_socket, 3) == SOCKET_ERROR) { - throwError(getsockerror_winsock()); + if (shutdown_winsock(s->m_socket, SD_SEND) == SOCKET_ERROR) { + if (getsockerror_winsock() != WSAENOTCONN) { + throwError(getsockerror_winsock()); } + } } -ArchSocket -ArchNetworkWinsock::acceptSocket(ArchSocket s, ArchNetAddress* const addr) -{ - assert(s != NULL); +void ArchNetworkWinsock::bindSocket(ArchSocket s, ArchNetAddress addr) { + assert(s != NULL); + assert(addr != NULL); - // create new socket and temporary address - ArchSocketImpl* socket = new ArchSocketImpl; - ArchNetAddress tmp = ArchNetAddressImpl::alloc(sizeof(struct sockaddr_in6)); + if (bind_winsock(s->m_socket, TYPED_ADDR(struct sockaddr, addr), + addr->m_len) == SOCKET_ERROR) { + throwError(getsockerror_winsock()); + } +} - // accept on socket - SOCKET fd = accept_winsock(s->m_socket, TYPED_ADDR(struct sockaddr, tmp), &tmp->m_len); - if (fd == INVALID_SOCKET) { - int err = getsockerror_winsock(); - delete socket; - free(tmp); - if (addr) { - *addr = NULL; - } - if (err == WSAEWOULDBLOCK) { - return NULL; - } - throwError(err); - } +void ArchNetworkWinsock::listenOnSocket(ArchSocket s) { + assert(s != NULL); - try { - setBlockingOnSocket(fd, false); - } - catch (...) { - close_winsock(fd); - delete socket; - free(tmp); - if (addr) { - *addr = NULL; - } - throw; - } + // hardcoding backlog + if (listen_winsock(s->m_socket, 3) == SOCKET_ERROR) { + throwError(getsockerror_winsock()); + } +} - // initialize socket - socket->m_socket = fd; - socket->m_refCount = 1; - socket->m_event = WSACreateEvent_winsock(); - socket->m_pollWrite = true; +ArchSocket ArchNetworkWinsock::acceptSocket(ArchSocket s, + ArchNetAddress *const addr) { + assert(s != NULL); - // copy address if requested - if (addr != NULL) { - *addr = ARCH->copyAddr(tmp); - } + // create new socket and temporary address + ArchSocketImpl *socket = new ArchSocketImpl; + ArchNetAddress tmp = ArchNetAddressImpl::alloc(sizeof(struct sockaddr_in6)); + // accept on socket + SOCKET fd = accept_winsock(s->m_socket, TYPED_ADDR(struct sockaddr, tmp), + &tmp->m_len); + if (fd == INVALID_SOCKET) { + int err = getsockerror_winsock(); + delete socket; free(tmp); - return socket; -} - -bool -ArchNetworkWinsock::connectSocket(ArchSocket s, ArchNetAddress addr) -{ - assert(s != NULL); - assert(addr != NULL); - - if (connect_winsock(s->m_socket, TYPED_ADDR(struct sockaddr, addr), - addr->m_len) == SOCKET_ERROR) { - if (getsockerror_winsock() == WSAEISCONN) { - return true; - } - if (getsockerror_winsock() == WSAEWOULDBLOCK) { - return false; - } - throwError(getsockerror_winsock()); + if (addr) { + *addr = NULL; } - return true; + if (err == WSAEWOULDBLOCK) { + return NULL; + } + throwError(err); + } + + try { + setBlockingOnSocket(fd, false); + } catch (...) { + close_winsock(fd); + delete socket; + free(tmp); + if (addr) { + *addr = NULL; + } + throw; + } + + // initialize socket + socket->m_socket = fd; + socket->m_refCount = 1; + socket->m_event = WSACreateEvent_winsock(); + socket->m_pollWrite = true; + + // copy address if requested + if (addr != NULL) { + *addr = ARCH->copyAddr(tmp); + } + + free(tmp); + return socket; } -int -ArchNetworkWinsock::pollSocket(PollEntry pe[], int num, double timeout) -{ - int i; - DWORD n; +bool ArchNetworkWinsock::connectSocket(ArchSocket s, ArchNetAddress addr) { + assert(s != NULL); + assert(addr != NULL); - // prepare sockets and wait list - bool canWrite = false; - WSAEVENT* events = (WSAEVENT*)alloca((num + 1) * sizeof(WSAEVENT)); - for (i = 0, n = 0; i < num; ++i) { - // reset return flags - pe[i].m_revents = 0; + if (connect_winsock(s->m_socket, TYPED_ADDR(struct sockaddr, addr), + addr->m_len) == SOCKET_ERROR) { + if (getsockerror_winsock() == WSAEISCONN) { + return true; + } + if (getsockerror_winsock() == WSAEWOULDBLOCK) { + return false; + } + throwError(getsockerror_winsock()); + } + return true; +} - // set invalid flag if socket is bogus then go to next socket - if (pe[i].m_socket == NULL) { - pe[i].m_revents |= kPOLLNVAL; - continue; - } +int ArchNetworkWinsock::pollSocket(PollEntry pe[], int num, double timeout) { + int i; + DWORD n; - // select desired events - long socketEvents = 0; + // prepare sockets and wait list + bool canWrite = false; + WSAEVENT *events = (WSAEVENT *)alloca((num + 1) * sizeof(WSAEVENT)); + for (i = 0, n = 0; i < num; ++i) { + // reset return flags + pe[i].m_revents = 0; + + // set invalid flag if socket is bogus then go to next socket + if (pe[i].m_socket == NULL) { + pe[i].m_revents |= kPOLLNVAL; + continue; + } + + // select desired events + long socketEvents = 0; + if ((pe[i].m_events & kPOLLIN) != 0) { + socketEvents |= FD_READ | FD_ACCEPT | FD_CLOSE; + } + if ((pe[i].m_events & kPOLLOUT) != 0) { + socketEvents |= FD_WRITE | FD_CONNECT | FD_CLOSE; + + // if m_pollWrite is false then we assume the socket is + // writable. winsock doesn't signal writability except + // when the state changes from unwritable. + if (!pe[i].m_socket->m_pollWrite) { + canWrite = true; + pe[i].m_revents |= kPOLLOUT; + } + } + + // if no events then ignore socket + if (socketEvents == 0) { + continue; + } + + // select socket for desired events + WSAEventSelect_winsock(pe[i].m_socket->m_socket, pe[i].m_socket->m_event, + socketEvents); + + // add socket event to wait list + events[n++] = pe[i].m_socket->m_event; + } + + // if no sockets then return immediately + if (n == 0) { + return 0; + } + + // add the unblock event + ArchMultithreadWindows *mt = ArchMultithreadWindows::getInstance(); + ArchThread thread = mt->newCurrentThread(); + WSAEVENT *unblockEvent = (WSAEVENT *)mt->getNetworkDataForThread(thread); + ARCH->closeThread(thread); + if (unblockEvent == NULL) { + unblockEvent = new WSAEVENT; + m_unblockEvents.push_back(unblockEvent); + *unblockEvent = WSACreateEvent_winsock(); + mt->setNetworkDataForCurrentThread(unblockEvent); + } + events[n++] = *unblockEvent; + + // prepare timeout + DWORD t = (timeout < 0.0) ? INFINITE : (DWORD)(1000.0 * timeout); + if (canWrite) { + // if we know we can write then don't block + t = 0; + } + + // wait + DWORD result = WSAWaitForMultipleEvents_winsock(n, events, FALSE, t, FALSE); + + // reset the unblock event + WSAResetEvent_winsock(*unblockEvent); + + // handle results + if (result == WSA_WAIT_FAILED) { + if (getsockerror_winsock() == WSAEINTR) { + // interrupted system call + ARCH->testCancelThread(); + return 0; + } + throwError(getsockerror_winsock()); + } + if (result == WSA_WAIT_TIMEOUT && !canWrite) { + return 0; + } + if (result == WSA_WAIT_EVENT_0 + n - 1) { + // the unblock event was signalled + return 0; + } + for (i = 0, n = 0; i < num; ++i) { + // skip events we didn't check + if (pe[i].m_socket == NULL || + (pe[i].m_events & (kPOLLIN | kPOLLOUT)) == 0) { + continue; + } + + // get events + WSANETWORKEVENTS info; + if (WSAEnumNetworkEvents_winsock(pe[i].m_socket->m_socket, + pe[i].m_socket->m_event, + &info) == SOCKET_ERROR) { + continue; + } + if ((info.lNetworkEvents & FD_READ) != 0) { + pe[i].m_revents |= kPOLLIN; + } + if ((info.lNetworkEvents & FD_ACCEPT) != 0) { + pe[i].m_revents |= kPOLLIN; + } + if ((info.lNetworkEvents & FD_WRITE) != 0) { + pe[i].m_revents |= kPOLLOUT; + + // socket is now writable so don't bothing polling for + // writable until it becomes unwritable. + pe[i].m_socket->m_pollWrite = false; + } + if ((info.lNetworkEvents & FD_CONNECT) != 0) { + if (info.iErrorCode[FD_CONNECT_BIT] != 0) { + pe[i].m_revents |= kPOLLERR; + } else { + pe[i].m_revents |= kPOLLOUT; + pe[i].m_socket->m_pollWrite = false; + } + } + if ((info.lNetworkEvents & FD_CLOSE) != 0) { + if (info.iErrorCode[FD_CLOSE_BIT] != 0) { + pe[i].m_revents |= kPOLLERR; + } else { if ((pe[i].m_events & kPOLLIN) != 0) { - socketEvents |= FD_READ | FD_ACCEPT | FD_CLOSE; + pe[i].m_revents |= kPOLLIN; } if ((pe[i].m_events & kPOLLOUT) != 0) { - socketEvents |= FD_WRITE | FD_CONNECT | FD_CLOSE; - - // if m_pollWrite is false then we assume the socket is - // writable. winsock doesn't signal writability except - // when the state changes from unwritable. - if (!pe[i].m_socket->m_pollWrite) { - canWrite = true; - pe[i].m_revents |= kPOLLOUT; - } + pe[i].m_revents |= kPOLLOUT; } - - // if no events then ignore socket - if (socketEvents == 0) { - continue; - } - - // select socket for desired events - WSAEventSelect_winsock(pe[i].m_socket->m_socket, - pe[i].m_socket->m_event, socketEvents); - - // add socket event to wait list - events[n++] = pe[i].m_socket->m_event; + } } - - // if no sockets then return immediately - if (n == 0) { - return 0; + if (pe[i].m_revents != 0) { + ++n; } + } - // add the unblock event - ArchMultithreadWindows* mt = ArchMultithreadWindows::getInstance(); - ArchThread thread = mt->newCurrentThread(); - WSAEVENT* unblockEvent = (WSAEVENT*)mt->getNetworkDataForThread(thread); - ARCH->closeThread(thread); - if (unblockEvent == NULL) { - unblockEvent = new WSAEVENT; - m_unblockEvents.push_back(unblockEvent); - *unblockEvent = WSACreateEvent_winsock(); - mt->setNetworkDataForCurrentThread(unblockEvent); - } - events[n++] = *unblockEvent; - - // prepare timeout - DWORD t = (timeout < 0.0) ? INFINITE : (DWORD)(1000.0 * timeout); - if (canWrite) { - // if we know we can write then don't block - t = 0; - } - - // wait - DWORD result = WSAWaitForMultipleEvents_winsock(n, events, FALSE, t, FALSE); - - // reset the unblock event - WSAResetEvent_winsock(*unblockEvent); - - // handle results - if (result == WSA_WAIT_FAILED) { - if (getsockerror_winsock() == WSAEINTR) { - // interrupted system call - ARCH->testCancelThread(); - return 0; - } - throwError(getsockerror_winsock()); - } - if (result == WSA_WAIT_TIMEOUT && !canWrite) { - return 0; - } - if (result == WSA_WAIT_EVENT_0 + n - 1) { - // the unblock event was signalled - return 0; - } - for (i = 0, n = 0; i < num; ++i) { - // skip events we didn't check - if (pe[i].m_socket == NULL || - (pe[i].m_events & (kPOLLIN | kPOLLOUT)) == 0) { - continue; - } - - // get events - WSANETWORKEVENTS info; - if (WSAEnumNetworkEvents_winsock(pe[i].m_socket->m_socket, - pe[i].m_socket->m_event, &info) == SOCKET_ERROR) { - continue; - } - if ((info.lNetworkEvents & FD_READ) != 0) { - pe[i].m_revents |= kPOLLIN; - } - if ((info.lNetworkEvents & FD_ACCEPT) != 0) { - pe[i].m_revents |= kPOLLIN; - } - if ((info.lNetworkEvents & FD_WRITE) != 0) { - pe[i].m_revents |= kPOLLOUT; - - // socket is now writable so don't bothing polling for - // writable until it becomes unwritable. - pe[i].m_socket->m_pollWrite = false; - } - if ((info.lNetworkEvents & FD_CONNECT) != 0) { - if (info.iErrorCode[FD_CONNECT_BIT] != 0) { - pe[i].m_revents |= kPOLLERR; - } - else { - pe[i].m_revents |= kPOLLOUT; - pe[i].m_socket->m_pollWrite = false; - } - } - if ((info.lNetworkEvents & FD_CLOSE) != 0) { - if (info.iErrorCode[FD_CLOSE_BIT] != 0) { - pe[i].m_revents |= kPOLLERR; - } - else { - if ((pe[i].m_events & kPOLLIN) != 0) { - pe[i].m_revents |= kPOLLIN; - } - if ((pe[i].m_events & kPOLLOUT) != 0) { - pe[i].m_revents |= kPOLLOUT; - } - } - } - if (pe[i].m_revents != 0) { - ++n; - } - } - - return (int)n; + return (int)n; } -void -ArchNetworkWinsock::unblockPollSocket(ArchThread thread) -{ - // set the unblock event - ArchMultithreadWindows* mt = ArchMultithreadWindows::getInstance(); - WSAEVENT* unblockEvent = (WSAEVENT*)mt->getNetworkDataForThread(thread); - if (unblockEvent != NULL) { - WSASetEvent_winsock(*unblockEvent); - } +void ArchNetworkWinsock::unblockPollSocket(ArchThread thread) { + // set the unblock event + ArchMultithreadWindows *mt = ArchMultithreadWindows::getInstance(); + WSAEVENT *unblockEvent = (WSAEVENT *)mt->getNetworkDataForThread(thread); + if (unblockEvent != NULL) { + WSASetEvent_winsock(*unblockEvent); + } } -size_t -ArchNetworkWinsock::readSocket(ArchSocket s, void* buf, size_t len) -{ - assert(s != NULL); +size_t ArchNetworkWinsock::readSocket(ArchSocket s, void *buf, size_t len) { + assert(s != NULL); - int n = recv_winsock(s->m_socket, buf, (int)len, 0); - if (n == SOCKET_ERROR) { - int err = getsockerror_winsock(); - if (err == WSAEINTR || err == WSAEWOULDBLOCK) { - return 0; - } - throwError(err); + int n = recv_winsock(s->m_socket, buf, (int)len, 0); + if (n == SOCKET_ERROR) { + int err = getsockerror_winsock(); + if (err == WSAEINTR || err == WSAEWOULDBLOCK) { + return 0; } - return static_cast(n); + throwError(err); + } + return static_cast(n); } -size_t -ArchNetworkWinsock::writeSocket(ArchSocket s, const void* buf, size_t len) -{ - assert(s != NULL); +size_t ArchNetworkWinsock::writeSocket(ArchSocket s, const void *buf, + size_t len) { + assert(s != NULL); - int n = send_winsock(s->m_socket, buf, (int)len, 0); - if (n == SOCKET_ERROR) { - int err = getsockerror_winsock(); - if (err == WSAEINTR) { - return 0; - } - if (err == WSAEWOULDBLOCK) { - s->m_pollWrite = true; - return 0; - } - throwError(err); + int n = send_winsock(s->m_socket, buf, (int)len, 0); + if (n == SOCKET_ERROR) { + int err = getsockerror_winsock(); + if (err == WSAEINTR) { + return 0; } - return static_cast(n); + if (err == WSAEWOULDBLOCK) { + s->m_pollWrite = true; + return 0; + } + throwError(err); + } + return static_cast(n); } -void -ArchNetworkWinsock::throwErrorOnSocket(ArchSocket s) -{ - assert(s != NULL); +void ArchNetworkWinsock::throwErrorOnSocket(ArchSocket s) { + assert(s != NULL); - // get the error from the socket layer - int err = 0; - int size = sizeof(err); - if (getsockopt_winsock(s->m_socket, SOL_SOCKET, - SO_ERROR, &err, &size) == SOCKET_ERROR) { - err = getsockerror_winsock(); - } + // get the error from the socket layer + int err = 0; + int size = sizeof(err); + if (getsockopt_winsock(s->m_socket, SOL_SOCKET, SO_ERROR, &err, &size) == + SOCKET_ERROR) { + err = getsockerror_winsock(); + } - // throw if there's an error - if (err != 0) { - throwError(err); - } + // throw if there's an error + if (err != 0) { + throwError(err); + } } -void -ArchNetworkWinsock::setBlockingOnSocket(SOCKET s, bool blocking) -{ - assert(s != 0); +void ArchNetworkWinsock::setBlockingOnSocket(SOCKET s, bool blocking) { + assert(s != 0); - int flag = blocking ? 0 : 1; - if (ioctl_winsock(s, FIONBIO, &flag) == SOCKET_ERROR) { - throwError(getsockerror_winsock()); - } + int flag = blocking ? 0 : 1; + if (ioctl_winsock(s, FIONBIO, &flag) == SOCKET_ERROR) { + throwError(getsockerror_winsock()); + } } -bool -ArchNetworkWinsock::setNoDelayOnSocket(ArchSocket s, bool noDelay) -{ - assert(s != NULL); +bool ArchNetworkWinsock::setNoDelayOnSocket(ArchSocket s, bool noDelay) { + assert(s != NULL); - // get old state - BOOL oflag; - int size = sizeof(oflag); - if (getsockopt_winsock(s->m_socket, IPPROTO_TCP, - TCP_NODELAY, &oflag, &size) == SOCKET_ERROR) { - throwError(getsockerror_winsock()); - } + // get old state + BOOL oflag; + int size = sizeof(oflag); + if (getsockopt_winsock(s->m_socket, IPPROTO_TCP, TCP_NODELAY, &oflag, + &size) == SOCKET_ERROR) { + throwError(getsockerror_winsock()); + } - // set new state - BOOL flag = noDelay ? 1 : 0; - size = sizeof(flag); - if (setsockopt_winsock(s->m_socket, IPPROTO_TCP, - TCP_NODELAY, &flag, size) == SOCKET_ERROR) { - throwError(getsockerror_winsock()); - } + // set new state + BOOL flag = noDelay ? 1 : 0; + size = sizeof(flag); + if (setsockopt_winsock(s->m_socket, IPPROTO_TCP, TCP_NODELAY, &flag, size) == + SOCKET_ERROR) { + throwError(getsockerror_winsock()); + } - return (oflag != 0); + return (oflag != 0); } -bool -ArchNetworkWinsock::setReuseAddrOnSocket(ArchSocket s, bool reuse) -{ - assert(s != NULL); +bool ArchNetworkWinsock::setReuseAddrOnSocket(ArchSocket s, bool reuse) { + assert(s != NULL); - // get old state - BOOL oflag; - int size = sizeof(oflag); - if (getsockopt_winsock(s->m_socket, SOL_SOCKET, - SO_REUSEADDR, &oflag, &size) == SOCKET_ERROR) { - throwError(getsockerror_winsock()); - } + // get old state + BOOL oflag; + int size = sizeof(oflag); + if (getsockopt_winsock(s->m_socket, SOL_SOCKET, SO_REUSEADDR, &oflag, + &size) == SOCKET_ERROR) { + throwError(getsockerror_winsock()); + } - // set new state - BOOL flag = reuse ? 1 : 0; - size = sizeof(flag); - if (setsockopt_winsock(s->m_socket, SOL_SOCKET, - SO_REUSEADDR, &flag, size) == SOCKET_ERROR) { - throwError(getsockerror_winsock()); - } + // set new state + BOOL flag = reuse ? 1 : 0; + size = sizeof(flag); + if (setsockopt_winsock(s->m_socket, SOL_SOCKET, SO_REUSEADDR, &flag, size) == + SOCKET_ERROR) { + throwError(getsockerror_winsock()); + } - return (oflag != 0); + return (oflag != 0); } -std::string -ArchNetworkWinsock::getHostName() -{ - char name[256]; - if (gethostname_winsock(name, sizeof(name)) == -1) { - name[0] = '\0'; - } - else { - name[sizeof(name) - 1] = '\0'; - } - return name; +std::string ArchNetworkWinsock::getHostName() { + char name[256]; + if (gethostname_winsock(name, sizeof(name)) == -1) { + name[0] = '\0'; + } else { + name[sizeof(name) - 1] = '\0'; + } + return name; } -ArchNetAddress -ArchNetworkWinsock::newAnyAddr(EAddressFamily family) -{ - ArchNetAddressImpl* addr = NULL; - switch (family) { - case kINET: { - addr = ArchNetAddressImpl::alloc(sizeof(struct sockaddr_in)); - struct sockaddr_in* ipAddr = TYPED_ADDR(struct sockaddr_in, addr); - ipAddr->sin_family = AF_INET; - ipAddr->sin_port = 0; - ipAddr->sin_addr.s_addr = INADDR_ANY; - break; - } +ArchNetAddress ArchNetworkWinsock::newAnyAddr(EAddressFamily family) { + ArchNetAddressImpl *addr = NULL; + switch (family) { + case kINET: { + addr = ArchNetAddressImpl::alloc(sizeof(struct sockaddr_in)); + struct sockaddr_in *ipAddr = TYPED_ADDR(struct sockaddr_in, addr); + ipAddr->sin_family = AF_INET; + ipAddr->sin_port = 0; + ipAddr->sin_addr.s_addr = INADDR_ANY; + break; + } - case kINET6: { - addr = ArchNetAddressImpl::alloc(sizeof(struct sockaddr_in6)); - struct sockaddr_in6* ipAddr = TYPED_ADDR(struct sockaddr_in6, addr); - ipAddr->sin6_family = AF_INET6; - ipAddr->sin6_port = 0; - memcpy(&ipAddr->sin6_addr, &in6addr_any, sizeof(in6addr_any)); - break; - } + case kINET6: { + addr = ArchNetAddressImpl::alloc(sizeof(struct sockaddr_in6)); + struct sockaddr_in6 *ipAddr = TYPED_ADDR(struct sockaddr_in6, addr); + ipAddr->sin6_family = AF_INET6; + ipAddr->sin6_port = 0; + memcpy(&ipAddr->sin6_addr, &in6addr_any, sizeof(in6addr_any)); + break; + } - default: - assert(0 && "invalid family"); - } - return addr; + default: + assert(0 && "invalid family"); + } + return addr; } -ArchNetAddress -ArchNetworkWinsock::copyAddr(ArchNetAddress addr) -{ - assert(addr != NULL); +ArchNetAddress ArchNetworkWinsock::copyAddr(ArchNetAddress addr) { + assert(addr != NULL); - ArchNetAddressImpl* copy = ArchNetAddressImpl::alloc(addr->m_len); - memcpy(TYPED_ADDR(void, copy), TYPED_ADDR(void, addr), addr->m_len); - return copy; + ArchNetAddressImpl *copy = ArchNetAddressImpl::alloc(addr->m_len); + memcpy(TYPED_ADDR(void, copy), TYPED_ADDR(void, addr), addr->m_len); + return copy; } std::vector -ArchNetworkWinsock::nameToAddr(const std::string& name) -{ - // allocate address - std::vector addresses; +ArchNetworkWinsock::nameToAddr(const std::string &name) { + // allocate address + std::vector addresses; - struct addrinfo hints; - struct addrinfo *pResult; - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_UNSPEC; - int ret = -1; + struct addrinfo hints; + struct addrinfo *pResult; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + int ret = -1; - ARCH->lockMutex(m_mutex); - if ((ret = getaddrinfo(name.c_str(), NULL, &hints, &pResult)) != 0) { - ARCH->unlockMutex(m_mutex); - throwNameError(ret); - } - - for(auto address = pResult; address != nullptr; address = address->ai_next ){ - addresses.push_back(new ArchNetAddressImpl); - if (address->ai_family == AF_INET) { - addresses.back()->m_len = (socklen_t)sizeof(struct sockaddr_in); - } else { - addresses.back()->m_len = (socklen_t)sizeof(struct sockaddr_in6); - } - - memcpy(&addresses.back()->m_addr, address->ai_addr, addresses.back()->m_len); - } - - freeaddrinfo(pResult); + ARCH->lockMutex(m_mutex); + if ((ret = getaddrinfo(name.c_str(), NULL, &hints, &pResult)) != 0) { ARCH->unlockMutex(m_mutex); - return addresses; + throwNameError(ret); + } + + for (auto address = pResult; address != nullptr; address = address->ai_next) { + addresses.push_back(new ArchNetAddressImpl); + if (address->ai_family == AF_INET) { + addresses.back()->m_len = (socklen_t)sizeof(struct sockaddr_in); + } else { + addresses.back()->m_len = (socklen_t)sizeof(struct sockaddr_in6); + } + + memcpy(&addresses.back()->m_addr, address->ai_addr, + addresses.back()->m_len); + } + + freeaddrinfo(pResult); + ARCH->unlockMutex(m_mutex); + return addresses; } -void -ArchNetworkWinsock::closeAddr(ArchNetAddress addr) -{ - assert(addr != NULL); +void ArchNetworkWinsock::closeAddr(ArchNetAddress addr) { + assert(addr != NULL); - free(addr); + free(addr); } -std::string -ArchNetworkWinsock::addrToName(ArchNetAddress addr) -{ - assert(addr != NULL); +std::string ArchNetworkWinsock::addrToName(ArchNetAddress addr) { + assert(addr != NULL); - char host[1024]; - char service[20]; - int ret = getnameinfo(TYPED_ADDR(struct sockaddr, addr), addr->m_len, host, sizeof(host), service, sizeof(service), 0); + char host[1024]; + char service[20]; + int ret = getnameinfo(TYPED_ADDR(struct sockaddr, addr), addr->m_len, host, + sizeof(host), service, sizeof(service), 0); - if (ret != NULL) { - throwNameError(ret); - } + if (ret != NULL) { + throwNameError(ret); + } - // return (primary) name - std::string name = host; - return name; + // return (primary) name + std::string name = host; + return name; } -std::string -ArchNetworkWinsock::addrToString(ArchNetAddress addr) -{ - assert(addr != NULL); +std::string ArchNetworkWinsock::addrToString(ArchNetAddress addr) { + assert(addr != NULL); - switch (getAddrFamily(addr)) { - case kINET: { - struct sockaddr_in* ipAddr = TYPED_ADDR(struct sockaddr_in, addr); - return inet_ntoa_winsock(ipAddr->sin_addr); - } + switch (getAddrFamily(addr)) { + case kINET: { + struct sockaddr_in *ipAddr = TYPED_ADDR(struct sockaddr_in, addr); + return inet_ntoa_winsock(ipAddr->sin_addr); + } - case kINET6: { - char strAddr[INET6_ADDRSTRLEN]; - struct sockaddr_in6* ipAddr = TYPED_ADDR(struct sockaddr_in6, addr); - inet_ntop(AF_INET6, &ipAddr->sin6_addr, strAddr, INET6_ADDRSTRLEN); - return strAddr; - } + case kINET6: { + char strAddr[INET6_ADDRSTRLEN]; + struct sockaddr_in6 *ipAddr = TYPED_ADDR(struct sockaddr_in6, addr); + inet_ntop(AF_INET6, &ipAddr->sin6_addr, strAddr, INET6_ADDRSTRLEN); + return strAddr; + } - default: - assert(0 && "unknown address family"); - return ""; - } + default: + assert(0 && "unknown address family"); + return ""; + } } IArchNetwork::EAddressFamily -ArchNetworkWinsock::getAddrFamily(ArchNetAddress addr) -{ - assert(addr != NULL); +ArchNetworkWinsock::getAddrFamily(ArchNetAddress addr) { + assert(addr != NULL); - switch (addr->m_addr.ss_family) { - case AF_INET: - return kINET; + switch (addr->m_addr.ss_family) { + case AF_INET: + return kINET; - case AF_INET6: - return kINET6; + case AF_INET6: + return kINET6; - default: - return kUNKNOWN; - } + default: + return kUNKNOWN; + } } -void -ArchNetworkWinsock::setAddrPort(ArchNetAddress addr, int port) -{ - assert(addr != NULL); +void ArchNetworkWinsock::setAddrPort(ArchNetAddress addr, int port) { + assert(addr != NULL); - switch (getAddrFamily(addr)) { - case kINET: { - struct sockaddr_in* ipAddr = TYPED_ADDR(struct sockaddr_in, addr); - ipAddr->sin_port = htons_winsock(static_cast(port)); - break; - } + switch (getAddrFamily(addr)) { + case kINET: { + struct sockaddr_in *ipAddr = TYPED_ADDR(struct sockaddr_in, addr); + ipAddr->sin_port = htons_winsock(static_cast(port)); + break; + } - case kINET6: { - struct sockaddr_in6* ipAddr = TYPED_ADDR(struct sockaddr_in6, addr); - ipAddr->sin6_port = htons_winsock(static_cast(port)); - break; - } + case kINET6: { + struct sockaddr_in6 *ipAddr = TYPED_ADDR(struct sockaddr_in6, addr); + ipAddr->sin6_port = htons_winsock(static_cast(port)); + break; + } - default: - assert(0 && "unknown address family"); - break; - } + default: + assert(0 && "unknown address family"); + break; + } } -int -ArchNetworkWinsock::getAddrPort(ArchNetAddress addr) -{ - assert(addr != NULL); +int ArchNetworkWinsock::getAddrPort(ArchNetAddress addr) { + assert(addr != NULL); - switch (getAddrFamily(addr)) { - case kINET: { - struct sockaddr_in* ipAddr = TYPED_ADDR(struct sockaddr_in, addr); - return ntohs_winsock(ipAddr->sin_port); - } + switch (getAddrFamily(addr)) { + case kINET: { + struct sockaddr_in *ipAddr = TYPED_ADDR(struct sockaddr_in, addr); + return ntohs_winsock(ipAddr->sin_port); + } - case kINET6: { - struct sockaddr_in6* ipAddr = TYPED_ADDR(struct sockaddr_in6, addr); - return ntohs_winsock(ipAddr->sin6_port); - } + case kINET6: { + struct sockaddr_in6 *ipAddr = TYPED_ADDR(struct sockaddr_in6, addr); + return ntohs_winsock(ipAddr->sin6_port); + } - default: - assert(0 && "unknown address family"); - return 0; - } + default: + assert(0 && "unknown address family"); + return 0; + } } -bool -ArchNetworkWinsock::isAnyAddr(ArchNetAddress addr) -{ - assert(addr != NULL); +bool ArchNetworkWinsock::isAnyAddr(ArchNetAddress addr) { + assert(addr != NULL); - switch (getAddrFamily(addr)) { - case kINET: { - struct sockaddr_in* ipAddr = TYPED_ADDR(struct sockaddr_in, addr); - return (addr->m_len == sizeof(struct sockaddr_in) && - ipAddr->sin_addr.s_addr == INADDR_ANY); - } + switch (getAddrFamily(addr)) { + case kINET: { + struct sockaddr_in *ipAddr = TYPED_ADDR(struct sockaddr_in, addr); + return (addr->m_len == sizeof(struct sockaddr_in) && + ipAddr->sin_addr.s_addr == INADDR_ANY); + } - case kINET6: { - struct sockaddr_in6* ipAddr = TYPED_ADDR(struct sockaddr_in6, addr); - return (addr->m_len == sizeof(struct sockaddr_in) && - memcmp(&ipAddr->sin6_addr, &in6addr_any, sizeof(in6addr_any))== 0); - } + case kINET6: { + struct sockaddr_in6 *ipAddr = TYPED_ADDR(struct sockaddr_in6, addr); + return (addr->m_len == sizeof(struct sockaddr_in) && + memcmp(&ipAddr->sin6_addr, &in6addr_any, sizeof(in6addr_any)) == 0); + } - default: - assert(0 && "unknown address family"); - return true; - } + default: + assert(0 && "unknown address family"); + return true; + } } -bool -ArchNetworkWinsock::isEqualAddr(ArchNetAddress a, ArchNetAddress b) -{ - return (a == b || (a->m_len == b->m_len && - memcmp(&a->m_addr, &b->m_addr, a->m_len) == 0)); +bool ArchNetworkWinsock::isEqualAddr(ArchNetAddress a, ArchNetAddress b) { + return (a == b || (a->m_len == b->m_len && + memcmp(&a->m_addr, &b->m_addr, a->m_len) == 0)); } -void -ArchNetworkWinsock::throwError(int err) -{ - switch (err) { - case WSAEACCES: - throw XArchNetworkAccess(new XArchEvalWinsock(err)); +void ArchNetworkWinsock::throwError(int err) { + switch (err) { + case WSAEACCES: + throw XArchNetworkAccess(new XArchEvalWinsock(err)); - case WSAEMFILE: - case WSAENOBUFS: - case WSAENETDOWN: - throw XArchNetworkResource(new XArchEvalWinsock(err)); + case WSAEMFILE: + case WSAENOBUFS: + case WSAENETDOWN: + throw XArchNetworkResource(new XArchEvalWinsock(err)); - case WSAEPROTOTYPE: - case WSAEPROTONOSUPPORT: - case WSAEAFNOSUPPORT: - case WSAEPFNOSUPPORT: - case WSAESOCKTNOSUPPORT: - case WSAEINVAL: - case WSAENOPROTOOPT: - case WSAEOPNOTSUPP: - case WSAESHUTDOWN: - case WSANOTINITIALISED: - case WSAVERNOTSUPPORTED: - case WSASYSNOTREADY: - throw XArchNetworkSupport(new XArchEvalWinsock(err)); + case WSAEPROTOTYPE: + case WSAEPROTONOSUPPORT: + case WSAEAFNOSUPPORT: + case WSAEPFNOSUPPORT: + case WSAESOCKTNOSUPPORT: + case WSAEINVAL: + case WSAENOPROTOOPT: + case WSAEOPNOTSUPP: + case WSAESHUTDOWN: + case WSANOTINITIALISED: + case WSAVERNOTSUPPORTED: + case WSASYSNOTREADY: + throw XArchNetworkSupport(new XArchEvalWinsock(err)); - case WSAEADDRNOTAVAIL: - throw XArchNetworkNoAddress(new XArchEvalWinsock(err)); + case WSAEADDRNOTAVAIL: + throw XArchNetworkNoAddress(new XArchEvalWinsock(err)); - case WSAEADDRINUSE: - throw XArchNetworkAddressInUse(new XArchEvalWinsock(err)); + case WSAEADDRINUSE: + throw XArchNetworkAddressInUse(new XArchEvalWinsock(err)); - case WSAEHOSTUNREACH: - case WSAENETUNREACH: - throw XArchNetworkNoRoute(new XArchEvalWinsock(err)); + case WSAEHOSTUNREACH: + case WSAENETUNREACH: + throw XArchNetworkNoRoute(new XArchEvalWinsock(err)); - case WSAENOTCONN: - throw XArchNetworkNotConnected(new XArchEvalWinsock(err)); + case WSAENOTCONN: + throw XArchNetworkNotConnected(new XArchEvalWinsock(err)); - case WSAEDISCON: - throw XArchNetworkShutdown(new XArchEvalWinsock(err)); + case WSAEDISCON: + throw XArchNetworkShutdown(new XArchEvalWinsock(err)); - case WSAENETRESET: - case WSAECONNABORTED: - case WSAECONNRESET: - throw XArchNetworkDisconnected(new XArchEvalWinsock(err)); + case WSAENETRESET: + case WSAECONNABORTED: + case WSAECONNRESET: + throw XArchNetworkDisconnected(new XArchEvalWinsock(err)); - case WSAECONNREFUSED: - throw XArchNetworkConnectionRefused(new XArchEvalWinsock(err)); + case WSAECONNREFUSED: + throw XArchNetworkConnectionRefused(new XArchEvalWinsock(err)); - case WSAEHOSTDOWN: - case WSAETIMEDOUT: - throw XArchNetworkTimedOut(new XArchEvalWinsock(err)); + case WSAEHOSTDOWN: + case WSAETIMEDOUT: + throw XArchNetworkTimedOut(new XArchEvalWinsock(err)); - case WSAHOST_NOT_FOUND: - throw XArchNetworkNameUnknown(new XArchEvalWinsock(err)); + case WSAHOST_NOT_FOUND: + throw XArchNetworkNameUnknown(new XArchEvalWinsock(err)); - case WSANO_DATA: - throw XArchNetworkNameNoAddress(new XArchEvalWinsock(err)); + case WSANO_DATA: + throw XArchNetworkNameNoAddress(new XArchEvalWinsock(err)); - case WSANO_RECOVERY: - throw XArchNetworkNameFailure(new XArchEvalWinsock(err)); + case WSANO_RECOVERY: + throw XArchNetworkNameFailure(new XArchEvalWinsock(err)); - case WSATRY_AGAIN: - throw XArchNetworkNameUnavailable(new XArchEvalWinsock(err)); + case WSATRY_AGAIN: + throw XArchNetworkNameUnavailable(new XArchEvalWinsock(err)); - default: - throw XArchNetwork(new XArchEvalWinsock(err)); - } + default: + throw XArchNetwork(new XArchEvalWinsock(err)); + } } -void -ArchNetworkWinsock::throwNameError(int err) -{ - switch (err) { - case WSAHOST_NOT_FOUND: - throw XArchNetworkNameUnknown(new XArchEvalWinsock(err)); +void ArchNetworkWinsock::throwNameError(int err) { + switch (err) { + case WSAHOST_NOT_FOUND: + throw XArchNetworkNameUnknown(new XArchEvalWinsock(err)); - case WSANO_DATA: - throw XArchNetworkNameNoAddress(new XArchEvalWinsock(err)); + case WSANO_DATA: + throw XArchNetworkNameNoAddress(new XArchEvalWinsock(err)); - case WSANO_RECOVERY: - throw XArchNetworkNameFailure(new XArchEvalWinsock(err)); + case WSANO_RECOVERY: + throw XArchNetworkNameFailure(new XArchEvalWinsock(err)); - case WSATRY_AGAIN: - throw XArchNetworkNameUnavailable(new XArchEvalWinsock(err)); + case WSATRY_AGAIN: + throw XArchNetworkNameUnavailable(new XArchEvalWinsock(err)); - default: - throw XArchNetworkName(new XArchEvalWinsock(err)); - } + default: + throw XArchNetworkName(new XArchEvalWinsock(err)); + } } diff --git a/src/lib/arch/win32/ArchNetworkWinsock.h b/src/lib/arch/win32/ArchNetworkWinsock.h index 4b991b52e..0c8e4f1b9 100644 --- a/src/lib/arch/win32/ArchNetworkWinsock.h +++ b/src/lib/arch/win32/ArchNetworkWinsock.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -25,8 +25,8 @@ #endif #define INCL_WINSOCK_API_TYPEDEFS 0 -#include "arch/IArchNetwork.h" #include "arch/IArchMultithread.h" +#include "arch/IArchNetwork.h" #include #define WIN32_LEAN_AND_MEAN @@ -39,73 +39,72 @@ class ArchSocketImpl { public: - SOCKET m_socket; - int m_refCount; - WSAEVENT m_event; - bool m_pollWrite; + SOCKET m_socket; + int m_refCount; + WSAEVENT m_event; + bool m_pollWrite; }; class ArchNetAddressImpl { public: - static ArchNetAddressImpl* alloc(size_t); + static ArchNetAddressImpl *alloc(size_t); public: - int m_len; - struct sockaddr_storage m_addr; + int m_len; + struct sockaddr_storage m_addr; }; -#define ADDR_HDR_SIZE offsetof(ArchNetAddressImpl, m_addr) -#define TYPED_ADDR(type_, addr_) (reinterpret_cast(&addr_->m_addr)) +#define ADDR_HDR_SIZE offsetof(ArchNetAddressImpl, m_addr) +#define TYPED_ADDR(type_, addr_) (reinterpret_cast(&addr_->m_addr)) //! Win32 implementation of IArchNetwork class ArchNetworkWinsock : public IArchNetwork { public: - ArchNetworkWinsock(); - virtual ~ArchNetworkWinsock(); + ArchNetworkWinsock(); + virtual ~ArchNetworkWinsock(); - virtual void init(); + virtual void init(); - // IArchNetwork overrides - virtual ArchSocket newSocket(EAddressFamily, ESocketType); - virtual ArchSocket copySocket(ArchSocket s); - virtual void closeSocket(ArchSocket s); - virtual void closeSocketForRead(ArchSocket s); - virtual void closeSocketForWrite(ArchSocket s); - virtual void bindSocket(ArchSocket s, ArchNetAddress addr); - virtual void listenOnSocket(ArchSocket s); - virtual ArchSocket acceptSocket(ArchSocket s, ArchNetAddress* addr); - virtual bool connectSocket(ArchSocket s, ArchNetAddress name); - virtual int pollSocket(PollEntry[], int num, double timeout); - virtual void unblockPollSocket(ArchThread thread); - virtual size_t readSocket(ArchSocket s, void* buf, size_t len); - virtual size_t writeSocket(ArchSocket s, - const void* buf, size_t len); - virtual void throwErrorOnSocket(ArchSocket); - virtual bool setNoDelayOnSocket(ArchSocket, bool noDelay); - virtual bool setReuseAddrOnSocket(ArchSocket, bool reuse); - virtual std::string getHostName(); - virtual ArchNetAddress newAnyAddr(EAddressFamily); - virtual ArchNetAddress copyAddr(ArchNetAddress); - virtual std::vector nameToAddr(const std::string&); - virtual void closeAddr(ArchNetAddress); - virtual std::string addrToName(ArchNetAddress); - virtual std::string addrToString(ArchNetAddress); - virtual EAddressFamily getAddrFamily(ArchNetAddress); - virtual void setAddrPort(ArchNetAddress, int port); - virtual int getAddrPort(ArchNetAddress); - virtual bool isAnyAddr(ArchNetAddress); - virtual bool isEqualAddr(ArchNetAddress, ArchNetAddress); + // IArchNetwork overrides + virtual ArchSocket newSocket(EAddressFamily, ESocketType); + virtual ArchSocket copySocket(ArchSocket s); + virtual void closeSocket(ArchSocket s); + virtual void closeSocketForRead(ArchSocket s); + virtual void closeSocketForWrite(ArchSocket s); + virtual void bindSocket(ArchSocket s, ArchNetAddress addr); + virtual void listenOnSocket(ArchSocket s); + virtual ArchSocket acceptSocket(ArchSocket s, ArchNetAddress *addr); + virtual bool connectSocket(ArchSocket s, ArchNetAddress name); + virtual int pollSocket(PollEntry[], int num, double timeout); + virtual void unblockPollSocket(ArchThread thread); + virtual size_t readSocket(ArchSocket s, void *buf, size_t len); + virtual size_t writeSocket(ArchSocket s, const void *buf, size_t len); + virtual void throwErrorOnSocket(ArchSocket); + virtual bool setNoDelayOnSocket(ArchSocket, bool noDelay); + virtual bool setReuseAddrOnSocket(ArchSocket, bool reuse); + virtual std::string getHostName(); + virtual ArchNetAddress newAnyAddr(EAddressFamily); + virtual ArchNetAddress copyAddr(ArchNetAddress); + virtual std::vector nameToAddr(const std::string &); + virtual void closeAddr(ArchNetAddress); + virtual std::string addrToName(ArchNetAddress); + virtual std::string addrToString(ArchNetAddress); + virtual EAddressFamily getAddrFamily(ArchNetAddress); + virtual void setAddrPort(ArchNetAddress, int port); + virtual int getAddrPort(ArchNetAddress); + virtual bool isAnyAddr(ArchNetAddress); + virtual bool isEqualAddr(ArchNetAddress, ArchNetAddress); private: - void initModule(HMODULE); + void initModule(HMODULE); - void setBlockingOnSocket(SOCKET, bool blocking); + void setBlockingOnSocket(SOCKET, bool blocking); - void throwError(int); - void throwNameError(int); + void throwError(int); + void throwNameError(int); private: - typedef std::list EventList; + typedef std::list EventList; - ArchMutex m_mutex; - EventList m_unblockEvents; + ArchMutex m_mutex; + EventList m_unblockEvents; }; diff --git a/src/lib/arch/win32/ArchSleepWindows.cpp b/src/lib/arch/win32/ArchSleepWindows.cpp index 67e487844..97bf48d26 100644 --- a/src/lib/arch/win32/ArchSleepWindows.cpp +++ b/src/lib/arch/win32/ArchSleepWindows.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -24,38 +24,33 @@ // ArchSleepWindows // -ArchSleepWindows::ArchSleepWindows() -{ - // do nothing +ArchSleepWindows::ArchSleepWindows() { + // do nothing } -ArchSleepWindows::~ArchSleepWindows() -{ - // do nothing +ArchSleepWindows::~ArchSleepWindows() { + // do nothing } -void -ArchSleepWindows::sleep(double timeout) -{ - ARCH->testCancelThread(); - if (timeout < 0.0) { - return; - } +void ArchSleepWindows::sleep(double timeout) { + ARCH->testCancelThread(); + if (timeout < 0.0) { + return; + } - // get the cancel event from the current thread. this only - // works if we're using the windows multithread object but - // this is windows so that's pretty certain; we'll get a - // link error if we're not, though. - ArchMultithreadWindows* mt = ArchMultithreadWindows::getInstance(); - if (mt != NULL) { - HANDLE cancelEvent = mt->getCancelEventForCurrentThread(); - WaitForSingleObject(cancelEvent, (DWORD)(1000.0 * timeout)); - if (timeout == 0.0) { - Sleep(0); - } + // get the cancel event from the current thread. this only + // works if we're using the windows multithread object but + // this is windows so that's pretty certain; we'll get a + // link error if we're not, though. + ArchMultithreadWindows *mt = ArchMultithreadWindows::getInstance(); + if (mt != NULL) { + HANDLE cancelEvent = mt->getCancelEventForCurrentThread(); + WaitForSingleObject(cancelEvent, (DWORD)(1000.0 * timeout)); + if (timeout == 0.0) { + Sleep(0); } - else { - Sleep((DWORD)(1000.0 * timeout)); - } - ARCH->testCancelThread(); + } else { + Sleep((DWORD)(1000.0 * timeout)); + } + ARCH->testCancelThread(); } diff --git a/src/lib/arch/win32/ArchSleepWindows.h b/src/lib/arch/win32/ArchSleepWindows.h index d78cf6edb..d4f8f742a 100644 --- a/src/lib/arch/win32/ArchSleepWindows.h +++ b/src/lib/arch/win32/ArchSleepWindows.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -25,9 +25,9 @@ //! Win32 implementation of IArchSleep class ArchSleepWindows : public IArchSleep { public: - ArchSleepWindows(); - virtual ~ArchSleepWindows(); + ArchSleepWindows(); + virtual ~ArchSleepWindows(); - // IArchSleep overrides - virtual void sleep(double timeout); + // IArchSleep overrides + virtual void sleep(double timeout); }; diff --git a/src/lib/arch/win32/ArchStringWindows.cpp b/src/lib/arch/win32/ArchStringWindows.cpp index 85ab66ca9..78a22c0ca 100644 --- a/src/lib/arch/win32/ArchStringWindows.cpp +++ b/src/lib/arch/win32/ArchStringWindows.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -31,16 +31,10 @@ #define ARCH_VSNPRINTF _vsnprintf #include "arch/vsnprintf.h" -ArchStringWindows::ArchStringWindows() -{ -} +ArchStringWindows::ArchStringWindows() {} -ArchStringWindows::~ArchStringWindows() -{ -} +ArchStringWindows::~ArchStringWindows() {} -IArchString::EWideCharEncoding -ArchStringWindows::getWideCharEncoding() -{ - return kUTF16; +IArchString::EWideCharEncoding ArchStringWindows::getWideCharEncoding() { + return kUTF16; } diff --git a/src/lib/arch/win32/ArchStringWindows.h b/src/lib/arch/win32/ArchStringWindows.h index c273cd672..a7730fe4d 100644 --- a/src/lib/arch/win32/ArchStringWindows.h +++ b/src/lib/arch/win32/ArchStringWindows.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -25,10 +25,9 @@ //! Win32 implementation of IArchString class ArchStringWindows : public IArchString { public: - ArchStringWindows(); - virtual ~ArchStringWindows(); + ArchStringWindows(); + virtual ~ArchStringWindows(); - // IArchString overrides - virtual EWideCharEncoding - getWideCharEncoding(); + // IArchString overrides + virtual EWideCharEncoding getWideCharEncoding(); }; diff --git a/src/lib/arch/win32/ArchSystemWindows.cpp b/src/lib/arch/win32/ArchSystemWindows.cpp index 3e0f0fcef..f7dd3b359 100644 --- a/src/lib/arch/win32/ArchSystemWindows.cpp +++ b/src/lib/arch/win32/ArchSystemWindows.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 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 LICENSE 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 @@ -18,113 +18,96 @@ #include "arch/win32/ArchSystemWindows.h" #include "arch/win32/ArchMiscWindows.h" -#include "arch/win32/XArchWindows.h" + +#include "arch/XArch.h" #include "tchar.h" #include -#include #include +#include -static const char* s_settingsKeyNames[] = { - _T("SOFTWARE"), - _T("Synergy"), - NULL -}; +static const char *s_settingsKeyNames[] = {_T("SOFTWARE"), _T("Synergy"), NULL}; // // ArchSystemWindows // -ArchSystemWindows::ArchSystemWindows() -{ - // do nothing +ArchSystemWindows::ArchSystemWindows() { + // do nothing } -ArchSystemWindows::~ArchSystemWindows() -{ - // do nothing +ArchSystemWindows::~ArchSystemWindows() { + // do nothing } -std::string -ArchSystemWindows::getOSName() const -{ - std::string osName ("Microsoft Windows "); - static const TCHAR* const windowsVersionKeyNames[] = { - _T("SOFTWARE"), - _T("Microsoft"), - _T("Windows NT"), - _T("CurrentVersion"), - NULL - }; +std::string ArchSystemWindows::getOSName() const { + std::string osName("Microsoft Windows "); + static const TCHAR *const windowsVersionKeyNames[] = { + _T("SOFTWARE"), _T("Microsoft"), _T("Windows NT"), _T("CurrentVersion"), + NULL}; - HKEY key = ArchMiscWindows::openKey(HKEY_LOCAL_MACHINE, windowsVersionKeyNames); - if (key == NULL) { - return osName; - } + HKEY key = + ArchMiscWindows::openKey(HKEY_LOCAL_MACHINE, windowsVersionKeyNames); + if (key == NULL) { + return osName; + } - std::string productName = ArchMiscWindows::readValueString(key, "ProductName"); - if (osName.empty()) { - return osName; - } + std::string productName = + ArchMiscWindows::readValueString(key, "ProductName"); + if (osName.empty()) { + return osName; + } - return "Microsoft " + productName; + return "Microsoft " + productName; } -std::string -ArchSystemWindows::getPlatformName() const -{ +std::string ArchSystemWindows::getPlatformName() const { #ifdef _X86_ - if (isWOW64()) - return "x86 (WOW64)"; - else - return "x86"; + if (isWOW64()) + return "x86 (WOW64)"; + else + return "x86"; #else #ifdef _AMD64_ - return "x64"; + return "x64"; #else - return "Unknown"; + return "Unknown"; #endif #endif } -std::string -ArchSystemWindows::setting(const std::string& valueName) const -{ - HKEY key = ArchMiscWindows::openKey(HKEY_LOCAL_MACHINE, s_settingsKeyNames); - if (key == NULL) - return ""; +std::string ArchSystemWindows::setting(const std::string &valueName) const { + HKEY key = ArchMiscWindows::openKey(HKEY_LOCAL_MACHINE, s_settingsKeyNames); + if (key == NULL) + return ""; - return ArchMiscWindows::readValueString(key, valueName.c_str()); + return ArchMiscWindows::readValueString(key, valueName.c_str()); } -void -ArchSystemWindows::setting(const std::string& valueName, const std::string& valueString) const -{ - HKEY key = ArchMiscWindows::addKey(HKEY_LOCAL_MACHINE, s_settingsKeyNames); - if (key == NULL) - throw XArch(std::string("could not access registry key: ") + valueName); - ArchMiscWindows::setValue(key, valueName.c_str(), valueString.c_str()); +void ArchSystemWindows::setting(const std::string &valueName, + const std::string &valueString) const { + HKEY key = ArchMiscWindows::addKey(HKEY_LOCAL_MACHINE, s_settingsKeyNames); + if (key == NULL) + throw XArch(std::string("could not access registry key: ") + valueName); + ArchMiscWindows::setValue(key, valueName.c_str(), valueString.c_str()); } -bool -ArchSystemWindows::isWOW64() const -{ +bool ArchSystemWindows::isWOW64() const { #if WINVER >= _WIN32_WINNT_WINXP - typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL); - HMODULE hModule = GetModuleHandle(TEXT("kernel32")); - if (!hModule) return FALSE; + typedef BOOL(WINAPI * LPFN_ISWOW64PROCESS)(HANDLE, PBOOL); + HMODULE hModule = GetModuleHandle(TEXT("kernel32")); + if (!hModule) + return FALSE; - LPFN_ISWOW64PROCESS fnIsWow64Process = - (LPFN_ISWOW64PROCESS) GetProcAddress(hModule, "IsWow64Process"); + LPFN_ISWOW64PROCESS fnIsWow64Process = + (LPFN_ISWOW64PROCESS)GetProcAddress(hModule, "IsWow64Process"); - BOOL bIsWow64 = FALSE; - if (NULL != fnIsWow64Process && - fnIsWow64Process(GetCurrentProcess(), &bIsWow64) && - bIsWow64) - { - return true; - } + BOOL bIsWow64 = FALSE; + if (NULL != fnIsWow64Process && + fnIsWow64Process(GetCurrentProcess(), &bIsWow64) && bIsWow64) { + return true; + } #endif - return false; + return false; } diff --git a/src/lib/arch/win32/ArchSystemWindows.h b/src/lib/arch/win32/ArchSystemWindows.h index 4b1986021..e57e143a7 100644 --- a/src/lib/arch/win32/ArchSystemWindows.h +++ b/src/lib/arch/win32/ArchSystemWindows.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 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 LICENSE 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 @@ -25,14 +25,15 @@ //! Win32 implementation of IArchString class ArchSystemWindows : public IArchSystem { public: - ArchSystemWindows(); - virtual ~ArchSystemWindows(); + ArchSystemWindows(); + virtual ~ArchSystemWindows(); - // IArchSystem overrides - virtual std::string getOSName() const; - virtual std::string getPlatformName() const; - virtual std::string setting(const std::string& valueName) const; - virtual void setting(const std::string& valueName, const std::string& valueString) const; + // IArchSystem overrides + virtual std::string getOSName() const; + virtual std::string getPlatformName() const; + virtual std::string setting(const std::string &valueName) const; + virtual void setting(const std::string &valueName, + const std::string &valueString) const; - bool isWOW64() const; + bool isWOW64() const; }; diff --git a/src/lib/arch/win32/ArchTaskBarWindows.cpp b/src/lib/arch/win32/ArchTaskBarWindows.cpp index ca2c4616e..3475ab17a 100644 --- a/src/lib/arch/win32/ArchTaskBarWindows.cpp +++ b/src/lib/arch/win32/ArchTaskBarWindows.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2003 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 LICENSE 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 @@ -17,508 +17,450 @@ */ #include "arch/win32/ArchTaskBarWindows.h" -#include "arch/win32/ArchMiscWindows.h" -#include "arch/IArchTaskBarReceiver.h" #include "arch/Arch.h" +#include "arch/IArchTaskBarReceiver.h" #include "arch/XArch.h" +#include "arch/win32/ArchMiscWindows.h" #include "synergy/win32/AppUtilWindows.h" -#include #include +#include -static const UINT kAddReceiver = WM_USER + 10; -static const UINT kRemoveReceiver = WM_USER + 11; -static const UINT kUpdateReceiver = WM_USER + 12; -static const UINT kNotifyReceiver = WM_USER + 13; -static const UINT kFirstReceiverID = WM_USER + 14; +static const UINT kAddReceiver = WM_USER + 10; +static const UINT kRemoveReceiver = WM_USER + 11; +static const UINT kUpdateReceiver = WM_USER + 12; +static const UINT kNotifyReceiver = WM_USER + 13; +static const UINT kFirstReceiverID = WM_USER + 14; // // ArchTaskBarWindows // -ArchTaskBarWindows* ArchTaskBarWindows::s_instance = NULL; +ArchTaskBarWindows *ArchTaskBarWindows::s_instance = NULL; -ArchTaskBarWindows::ArchTaskBarWindows() : - m_mutex(NULL), - m_condVar(NULL), - m_ready(false), - m_result(0), - m_thread(NULL), - m_hwnd(NULL), - m_taskBarRestart(0), - m_nextID(kFirstReceiverID) -{ - // save the singleton instance - s_instance = this; +ArchTaskBarWindows::ArchTaskBarWindows() + : m_mutex(NULL), m_condVar(NULL), m_ready(false), m_result(0), + m_thread(NULL), m_hwnd(NULL), m_taskBarRestart(0), + m_nextID(kFirstReceiverID) { + // save the singleton instance + s_instance = this; } -ArchTaskBarWindows::~ArchTaskBarWindows() -{ - if (m_thread != NULL) { - PostMessage(m_hwnd, WM_QUIT, 0, 0); - ARCH->wait(m_thread, -1.0); - ARCH->closeThread(m_thread); - } - if (m_condVar != NULL) { - ARCH->closeCondVar(m_condVar); - } - if (m_mutex != NULL) { - ARCH->closeMutex(m_mutex); - } - s_instance = NULL; +ArchTaskBarWindows::~ArchTaskBarWindows() { + if (m_thread != NULL) { + PostMessage(m_hwnd, WM_QUIT, 0, 0); + ARCH->wait(m_thread, -1.0); + ARCH->closeThread(m_thread); + } + if (m_condVar != NULL) { + ARCH->closeCondVar(m_condVar); + } + if (m_mutex != NULL) { + ARCH->closeMutex(m_mutex); + } + s_instance = NULL; } -void -ArchTaskBarWindows::init() -{ - // we need a mutex - m_mutex = ARCH->newMutex(); +void ArchTaskBarWindows::init() { + // we need a mutex + m_mutex = ARCH->newMutex(); - // and a condition variable which uses the above mutex - m_ready = false; - m_condVar = ARCH->newCondVar(); + // and a condition variable which uses the above mutex + m_ready = false; + m_condVar = ARCH->newCondVar(); - // we're going to want to get a result from the thread we're - // about to create to know if it initialized successfully. - // so we lock the condition variable. - ARCH->lockMutex(m_mutex); + // we're going to want to get a result from the thread we're + // about to create to know if it initialized successfully. + // so we lock the condition variable. + ARCH->lockMutex(m_mutex); - // open a window and run an event loop in a separate thread. - // this has to happen in a separate thread because if we - // create a window on the current desktop with the current - // thread then the current thread won't be able to switch - // desktops if it needs to. - m_thread = ARCH->newThread(&ArchTaskBarWindows::threadEntry, this); + // open a window and run an event loop in a separate thread. + // this has to happen in a separate thread because if we + // create a window on the current desktop with the current + // thread then the current thread won't be able to switch + // desktops if it needs to. + m_thread = ARCH->newThread(&ArchTaskBarWindows::threadEntry, this); - // wait for child thread - while (!m_ready) { - ARCH->waitCondVar(m_condVar, m_mutex, -1.0); - } + // wait for child thread + while (!m_ready) { + ARCH->waitCondVar(m_condVar, m_mutex, -1.0); + } - // ready - ARCH->unlockMutex(m_mutex); + // ready + ARCH->unlockMutex(m_mutex); } -void -ArchTaskBarWindows::addDialog(HWND hwnd) -{ - ArchMiscWindows::addDialog(hwnd); +void ArchTaskBarWindows::addDialog(HWND hwnd) { + ArchMiscWindows::addDialog(hwnd); } -void -ArchTaskBarWindows::removeDialog(HWND hwnd) -{ - ArchMiscWindows::removeDialog(hwnd); +void ArchTaskBarWindows::removeDialog(HWND hwnd) { + ArchMiscWindows::removeDialog(hwnd); } -void -ArchTaskBarWindows::addReceiver(IArchTaskBarReceiver* receiver) -{ - // ignore bogus receiver - if (receiver == NULL) { - return; - } +void ArchTaskBarWindows::addReceiver(IArchTaskBarReceiver *receiver) { + // ignore bogus receiver + if (receiver == NULL) { + return; + } - // add receiver if necessary - ReceiverToInfoMap::iterator index = m_receivers.find(receiver); - if (index == m_receivers.end()) { - // add it, creating a new message ID for it - ReceiverInfo info; - info.m_id = getNextID(); - index = m_receivers.insert(std::make_pair(receiver, info)).first; + // add receiver if necessary + ReceiverToInfoMap::iterator index = m_receivers.find(receiver); + if (index == m_receivers.end()) { + // add it, creating a new message ID for it + ReceiverInfo info; + info.m_id = getNextID(); + index = m_receivers.insert(std::make_pair(receiver, info)).first; - // add ID to receiver mapping - m_idTable.insert(std::make_pair(info.m_id, index)); - } + // add ID to receiver mapping + m_idTable.insert(std::make_pair(info.m_id, index)); + } - // add receiver - PostMessage(m_hwnd, kAddReceiver, index->second.m_id, 0); + // add receiver + PostMessage(m_hwnd, kAddReceiver, index->second.m_id, 0); } -void -ArchTaskBarWindows::removeReceiver(IArchTaskBarReceiver* receiver) -{ - // find receiver - ReceiverToInfoMap::iterator index = m_receivers.find(receiver); - if (index == m_receivers.end()) { - return; - } +void ArchTaskBarWindows::removeReceiver(IArchTaskBarReceiver *receiver) { + // find receiver + ReceiverToInfoMap::iterator index = m_receivers.find(receiver); + if (index == m_receivers.end()) { + return; + } - // remove icon. wait for this to finish before returning. - SendMessage(m_hwnd, kRemoveReceiver, index->second.m_id, 0); + // remove icon. wait for this to finish before returning. + SendMessage(m_hwnd, kRemoveReceiver, index->second.m_id, 0); - // recycle the ID - recycleID(index->second.m_id); + // recycle the ID + recycleID(index->second.m_id); - // discard - m_idTable.erase(index->second.m_id); - m_receivers.erase(index); + // discard + m_idTable.erase(index->second.m_id); + m_receivers.erase(index); } -void -ArchTaskBarWindows::updateReceiver(IArchTaskBarReceiver* receiver) -{ - // find receiver - ReceiverToInfoMap::const_iterator index = m_receivers.find(receiver); - if (index == m_receivers.end()) { - return; - } +void ArchTaskBarWindows::updateReceiver(IArchTaskBarReceiver *receiver) { + // find receiver + ReceiverToInfoMap::const_iterator index = m_receivers.find(receiver); + if (index == m_receivers.end()) { + return; + } - // update icon and tool tip - PostMessage(m_hwnd, kUpdateReceiver, index->second.m_id, 0); + // update icon and tool tip + PostMessage(m_hwnd, kUpdateReceiver, index->second.m_id, 0); } -UINT -ArchTaskBarWindows::getNextID() -{ - if (m_oldIDs.empty()) { - return m_nextID++; - } - UINT id = m_oldIDs.back(); - m_oldIDs.pop_back(); - return id; +UINT ArchTaskBarWindows::getNextID() { + if (m_oldIDs.empty()) { + return m_nextID++; + } + UINT id = m_oldIDs.back(); + m_oldIDs.pop_back(); + return id; } -void -ArchTaskBarWindows::recycleID(UINT id) -{ - m_oldIDs.push_back(id); +void ArchTaskBarWindows::recycleID(UINT id) { m_oldIDs.push_back(id); } + +void ArchTaskBarWindows::addIcon(UINT id) { + ARCH->lockMutex(m_mutex); + CIDToReceiverMap::const_iterator index = m_idTable.find(id); + if (index != m_idTable.end()) { + modifyIconNoLock(index->second, NIM_ADD); + } + ARCH->unlockMutex(m_mutex); } -void -ArchTaskBarWindows::addIcon(UINT id) -{ - ARCH->lockMutex(m_mutex); - CIDToReceiverMap::const_iterator index = m_idTable.find(id); - if (index != m_idTable.end()) { - modifyIconNoLock(index->second, NIM_ADD); - } - ARCH->unlockMutex(m_mutex); +void ArchTaskBarWindows::removeIcon(UINT id) { + ARCH->lockMutex(m_mutex); + removeIconNoLock(id); + ARCH->unlockMutex(m_mutex); } -void -ArchTaskBarWindows::removeIcon(UINT id) -{ - ARCH->lockMutex(m_mutex); - removeIconNoLock(id); - ARCH->unlockMutex(m_mutex); +void ArchTaskBarWindows::updateIcon(UINT id) { + ARCH->lockMutex(m_mutex); + CIDToReceiverMap::const_iterator index = m_idTable.find(id); + if (index != m_idTable.end()) { + modifyIconNoLock(index->second, NIM_MODIFY); + } + ARCH->unlockMutex(m_mutex); } -void -ArchTaskBarWindows::updateIcon(UINT id) -{ - ARCH->lockMutex(m_mutex); - CIDToReceiverMap::const_iterator index = m_idTable.find(id); - if (index != m_idTable.end()) { - modifyIconNoLock(index->second, NIM_MODIFY); - } - ARCH->unlockMutex(m_mutex); +void ArchTaskBarWindows::addAllIcons() { + ARCH->lockMutex(m_mutex); + for (ReceiverToInfoMap::const_iterator index = m_receivers.begin(); + index != m_receivers.end(); ++index) { + modifyIconNoLock(index, NIM_ADD); + } + ARCH->unlockMutex(m_mutex); } -void -ArchTaskBarWindows::addAllIcons() -{ - ARCH->lockMutex(m_mutex); - for (ReceiverToInfoMap::const_iterator index = m_receivers.begin(); - index != m_receivers.end(); ++index) { - modifyIconNoLock(index, NIM_ADD); - } - ARCH->unlockMutex(m_mutex); +void ArchTaskBarWindows::removeAllIcons() { + ARCH->lockMutex(m_mutex); + for (ReceiverToInfoMap::const_iterator index = m_receivers.begin(); + index != m_receivers.end(); ++index) { + removeIconNoLock(index->second.m_id); + } + ARCH->unlockMutex(m_mutex); } -void -ArchTaskBarWindows::removeAllIcons() -{ - ARCH->lockMutex(m_mutex); - for (ReceiverToInfoMap::const_iterator index = m_receivers.begin(); - index != m_receivers.end(); ++index) { - removeIconNoLock(index->second.m_id); - } - ARCH->unlockMutex(m_mutex); +void ArchTaskBarWindows::modifyIconNoLock( + ReceiverToInfoMap::const_iterator index, DWORD taskBarMessage) { + // get receiver + UINT id = index->second.m_id; + IArchTaskBarReceiver *receiver = index->first; + + // lock receiver so icon and tool tip are guaranteed to be consistent + receiver->lock(); + + // get icon data + HICON icon = static_cast( + const_cast(receiver->getIcon())); + + // get tool tip + std::string toolTip = receiver->getToolTip(); + + // done querying + receiver->unlock(); + + // prepare to add icon + NOTIFYICONDATA data; + data.cbSize = sizeof(NOTIFYICONDATA); + data.hWnd = m_hwnd; + data.uID = id; + data.uFlags = NIF_MESSAGE; + data.uCallbackMessage = kNotifyReceiver; + data.hIcon = icon; + if (icon != NULL) { + data.uFlags |= NIF_ICON; + } + if (!toolTip.empty()) { + strncpy(data.szTip, toolTip.c_str(), sizeof(data.szTip)); + data.szTip[sizeof(data.szTip) - 1] = '\0'; + data.uFlags |= NIF_TIP; + } else { + data.szTip[0] = '\0'; + } + + // add icon + if (Shell_NotifyIcon(taskBarMessage, &data) == 0) { + // failed + } } -void -ArchTaskBarWindows::modifyIconNoLock( - ReceiverToInfoMap::const_iterator index, DWORD taskBarMessage) -{ - // get receiver - UINT id = index->second.m_id; - IArchTaskBarReceiver* receiver = index->first; - - // lock receiver so icon and tool tip are guaranteed to be consistent - receiver->lock(); - - // get icon data - HICON icon = static_cast( - const_cast(receiver->getIcon())); - - // get tool tip - std::string toolTip = receiver->getToolTip(); - - // done querying - receiver->unlock(); - - // prepare to add icon - NOTIFYICONDATA data; - data.cbSize = sizeof(NOTIFYICONDATA); - data.hWnd = m_hwnd; - data.uID = id; - data.uFlags = NIF_MESSAGE; - data.uCallbackMessage = kNotifyReceiver; - data.hIcon = icon; - if (icon != NULL) { - data.uFlags |= NIF_ICON; - } - if (!toolTip.empty()) { - strncpy(data.szTip, toolTip.c_str(), sizeof(data.szTip)); - data.szTip[sizeof(data.szTip) - 1] = '\0'; - data.uFlags |= NIF_TIP; - } - else { - data.szTip[0] = '\0'; - } - - // add icon - if (Shell_NotifyIcon(taskBarMessage, &data) == 0) { - // failed - } +void ArchTaskBarWindows::removeIconNoLock(UINT id) { + NOTIFYICONDATA data; + data.cbSize = sizeof(NOTIFYICONDATA); + data.hWnd = m_hwnd; + data.uID = id; + if (Shell_NotifyIcon(NIM_DELETE, &data) == 0) { + // failed + } } -void -ArchTaskBarWindows::removeIconNoLock(UINT id) -{ - NOTIFYICONDATA data; - data.cbSize = sizeof(NOTIFYICONDATA); - data.hWnd = m_hwnd; - data.uID = id; - if (Shell_NotifyIcon(NIM_DELETE, &data) == 0) { - // failed - } +void ArchTaskBarWindows::handleIconMessage(IArchTaskBarReceiver *receiver, + LPARAM lParam) { + // process message + switch (lParam) { + case WM_LBUTTONDOWN: + receiver->showStatus(); + break; + + case WM_LBUTTONDBLCLK: + receiver->primaryAction(); + break; + + case WM_RBUTTONUP: { + POINT p; + GetCursorPos(&p); + receiver->runMenu(p.x, p.y); + break; + } + + case WM_MOUSEMOVE: + // currently unused + break; + + default: + // unused + break; + } } -void -ArchTaskBarWindows::handleIconMessage( - IArchTaskBarReceiver* receiver, LPARAM lParam) -{ - // process message - switch (lParam) { - case WM_LBUTTONDOWN: - receiver->showStatus(); - break; +bool ArchTaskBarWindows::processDialogs(MSG *msg) { + // only one thread can be in this method on any particular object + // at any given time. that's not a problem since only our event + // loop calls this method and there's just one of those. - case WM_LBUTTONDBLCLK: - receiver->primaryAction(); - break; + ARCH->lockMutex(m_mutex); - case WM_RBUTTONUP: { - POINT p; - GetCursorPos(&p); - receiver->runMenu(p.x, p.y); - break; - } - - case WM_MOUSEMOVE: - // currently unused - break; - - default: - // unused - break; - } -} - -bool -ArchTaskBarWindows::processDialogs(MSG* msg) -{ - // only one thread can be in this method on any particular object - // at any given time. that's not a problem since only our event - // loop calls this method and there's just one of those. - - ARCH->lockMutex(m_mutex); - - // there was previously some code here, with the comment "remove removed dialogs": - // m_dialogs.erase(false); - // - // it's not entirely clear what this code was doing, but it was probably trying to - // erase dialogs that had been removed (i.e. the map value was `false`). - for (auto it = m_dialogs.begin(); it != m_dialogs.end(); ) { + // there was previously some code here, with the comment "remove removed + // dialogs": + // m_dialogs.erase(false); + // + // it's not entirely clear what this code was doing, but it was probably + // trying to erase dialogs that had been removed (i.e. the map value was + // `false`). + for (auto it = m_dialogs.begin(); it != m_dialogs.end();) { if (it->second == false) { - it = m_dialogs.erase(it); + it = m_dialogs.erase(it); } else { - ++it; + ++it; } -} + } - // merge added dialogs into the dialog list - for (Dialogs::const_iterator index = m_addedDialogs.begin(); - index != m_addedDialogs.end(); ++index) { - m_dialogs.insert(std::make_pair(index->first, index->second)); + // merge added dialogs into the dialog list + for (Dialogs::const_iterator index = m_addedDialogs.begin(); + index != m_addedDialogs.end(); ++index) { + m_dialogs.insert(std::make_pair(index->first, index->second)); + } + m_addedDialogs.clear(); + + ARCH->unlockMutex(m_mutex); + + // check message against all dialogs until one handles it. + // note that we don't hold a lock while checking because + // the message is processed and may make calls to this + // object. that's okay because addDialog() and + // removeDialog() don't change the map itself (just the + // values of some elements). + ARCH->lockMutex(m_mutex); + for (Dialogs::const_iterator index = m_dialogs.begin(); + index != m_dialogs.end(); ++index) { + if (index->second) { + ARCH->unlockMutex(m_mutex); + if (IsDialogMessage(index->first, msg)) { + return true; + } + ARCH->lockMutex(m_mutex); } - m_addedDialogs.clear(); + } + ARCH->unlockMutex(m_mutex); - ARCH->unlockMutex(m_mutex); - - // check message against all dialogs until one handles it. - // note that we don't hold a lock while checking because - // the message is processed and may make calls to this - // object. that's okay because addDialog() and - // removeDialog() don't change the map itself (just the - // values of some elements). - ARCH->lockMutex(m_mutex); - for (Dialogs::const_iterator index = m_dialogs.begin(); - index != m_dialogs.end(); ++index) { - if (index->second) { - ARCH->unlockMutex(m_mutex); - if (IsDialogMessage(index->first, msg)) { - return true; - } - ARCH->lockMutex(m_mutex); - } - } - ARCH->unlockMutex(m_mutex); - - return false; + return false; } LRESULT -ArchTaskBarWindows::wndProc(HWND hwnd, - UINT msg, WPARAM wParam, LPARAM lParam) -{ - switch (msg) { - case kNotifyReceiver: { - // lookup receiver - CIDToReceiverMap::const_iterator index = m_idTable.find((UINT)wParam); - if (index != m_idTable.end()) { - IArchTaskBarReceiver* receiver = index->second->first; - handleIconMessage(receiver, lParam); - return 0; - } - break; +ArchTaskBarWindows::wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { + switch (msg) { + case kNotifyReceiver: { + // lookup receiver + CIDToReceiverMap::const_iterator index = m_idTable.find((UINT)wParam); + if (index != m_idTable.end()) { + IArchTaskBarReceiver *receiver = index->second->first; + handleIconMessage(receiver, lParam); + return 0; } + break; + } - case kAddReceiver: - addIcon((UINT)wParam); - break; + case kAddReceiver: + addIcon((UINT)wParam); + break; - case kRemoveReceiver: - removeIcon((UINT)wParam); - break; + case kRemoveReceiver: + removeIcon((UINT)wParam); + break; - case kUpdateReceiver: - updateIcon((UINT)wParam); - break; + case kUpdateReceiver: + updateIcon((UINT)wParam); + break; - default: - if (msg == m_taskBarRestart) { - // task bar was recreated so re-add our icons - addAllIcons(); - } - break; + default: + if (msg == m_taskBarRestart) { + // task bar was recreated so re-add our icons + addAllIcons(); } + break; + } + return DefWindowProc(hwnd, msg, wParam, lParam); +} + +LRESULT CALLBACK ArchTaskBarWindows::staticWndProc(HWND hwnd, UINT msg, + WPARAM wParam, + LPARAM lParam) { + // if msg is WM_NCCREATE, extract the ArchTaskBarWindows* and put + // it in the extra window data then forward the call. + ArchTaskBarWindows *self = NULL; + if (msg == WM_NCCREATE) { + CREATESTRUCT *createInfo; + createInfo = reinterpret_cast(lParam); + self = static_cast(createInfo->lpCreateParams); + SetWindowLongPtr(hwnd, 0, + reinterpret_cast(createInfo->lpCreateParams)); + } else { + // get the extra window data and forward the call + LONG_PTR data = GetWindowLongPtr(hwnd, 0); + if (data != 0) { + self = static_cast(reinterpret_cast(data)); + } + } + + // forward the message + if (self != NULL) { + return self->wndProc(hwnd, msg, wParam, lParam); + } else { return DefWindowProc(hwnd, msg, wParam, lParam); + } } -LRESULT CALLBACK -ArchTaskBarWindows::staticWndProc(HWND hwnd, UINT msg, - WPARAM wParam, LPARAM lParam) -{ - // if msg is WM_NCCREATE, extract the ArchTaskBarWindows* and put - // it in the extra window data then forward the call. - ArchTaskBarWindows* self = NULL; - if (msg == WM_NCCREATE) { - CREATESTRUCT* createInfo; - createInfo = reinterpret_cast(lParam); - self = static_cast( - createInfo->lpCreateParams); - SetWindowLongPtr(hwnd, 0, reinterpret_cast(createInfo->lpCreateParams)); - } - else { - // get the extra window data and forward the call - LONG_PTR data = GetWindowLongPtr(hwnd, 0); - if (data != 0) { - self = static_cast(reinterpret_cast(data)); - } - } +void ArchTaskBarWindows::threadMainLoop() { + // register the task bar restart message + m_taskBarRestart = RegisterWindowMessage(TEXT("TaskbarCreated")); - // forward the message - if (self != NULL) { - return self->wndProc(hwnd, msg, wParam, lParam); - } - else { - return DefWindowProc(hwnd, msg, wParam, lParam); - } -} + // register a window class + LPCTSTR className = TEXT("SynergyTaskBar"); + WNDCLASSEX classInfo; + classInfo.cbSize = sizeof(classInfo); + classInfo.style = CS_NOCLOSE; + classInfo.lpfnWndProc = &ArchTaskBarWindows::staticWndProc; + classInfo.cbClsExtra = 0; + classInfo.cbWndExtra = sizeof(ArchTaskBarWindows *); + classInfo.hInstance = instanceWin32(); + classInfo.hIcon = NULL; + classInfo.hCursor = NULL; + classInfo.hbrBackground = NULL; + classInfo.lpszMenuName = NULL; + classInfo.lpszClassName = className; + classInfo.hIconSm = NULL; + ATOM windowClass = RegisterClassEx(&classInfo); -void -ArchTaskBarWindows::threadMainLoop() -{ - // register the task bar restart message - m_taskBarRestart = RegisterWindowMessage(TEXT("TaskbarCreated")); + // create window + m_hwnd = CreateWindowEx(WS_EX_TOOLWINDOW, className, TEXT("Synergy Task Bar"), + WS_POPUP, 0, 0, 1, 1, NULL, NULL, instanceWin32(), + static_cast(this)); - // register a window class - LPCTSTR className = TEXT("SynergyTaskBar"); - WNDCLASSEX classInfo; - classInfo.cbSize = sizeof(classInfo); - classInfo.style = CS_NOCLOSE; - classInfo.lpfnWndProc = &ArchTaskBarWindows::staticWndProc; - classInfo.cbClsExtra = 0; - classInfo.cbWndExtra = sizeof(ArchTaskBarWindows*); - classInfo.hInstance = instanceWin32(); - classInfo.hIcon = NULL; - classInfo.hCursor = NULL; - classInfo.hbrBackground = NULL; - classInfo.lpszMenuName = NULL; - classInfo.lpszClassName = className; - classInfo.hIconSm = NULL; - ATOM windowClass = RegisterClassEx(&classInfo); + // signal ready + ARCH->lockMutex(m_mutex); + m_ready = true; + ARCH->broadcastCondVar(m_condVar); + ARCH->unlockMutex(m_mutex); - // create window - m_hwnd = CreateWindowEx(WS_EX_TOOLWINDOW, - className, - TEXT("Synergy Task Bar"), - WS_POPUP, - 0, 0, 1, 1, - NULL, - NULL, - instanceWin32(), - static_cast(this)); - - // signal ready - ARCH->lockMutex(m_mutex); - m_ready = true; - ARCH->broadcastCondVar(m_condVar); - ARCH->unlockMutex(m_mutex); - - // handle failure - if (m_hwnd == NULL) { - UnregisterClass(className, instanceWin32()); - return; - } - - // main loop - MSG msg; - while (GetMessage(&msg, NULL, 0, 0)) { - if (!processDialogs(&msg)) { - TranslateMessage(&msg); - DispatchMessage(&msg); - } - } - - // clean up - removeAllIcons(); - DestroyWindow(m_hwnd); + // handle failure + if (m_hwnd == NULL) { UnregisterClass(className, instanceWin32()); + return; + } + + // main loop + MSG msg; + while (GetMessage(&msg, NULL, 0, 0)) { + if (!processDialogs(&msg)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } + + // clean up + removeAllIcons(); + DestroyWindow(m_hwnd); + UnregisterClass(className, instanceWin32()); } -void* -ArchTaskBarWindows::threadEntry(void* self) -{ - static_cast(self)->threadMainLoop(); - return NULL; +void *ArchTaskBarWindows::threadEntry(void *self) { + static_cast(self)->threadMainLoop(); + return NULL; } -HINSTANCE ArchTaskBarWindows::instanceWin32() -{ - return ArchMiscWindows::instanceWin32(); +HINSTANCE ArchTaskBarWindows::instanceWin32() { + return ArchMiscWindows::instanceWin32(); } \ No newline at end of file diff --git a/src/lib/arch/win32/ArchTaskBarWindows.h b/src/lib/arch/win32/ArchTaskBarWindows.h index 2df7f46db..105f0bfd2 100644 --- a/src/lib/arch/win32/ArchTaskBarWindows.h +++ b/src/lib/arch/win32/ArchTaskBarWindows.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2003 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 LICENSE 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 @@ -18,8 +18,8 @@ #pragma once -#include "arch/IArchTaskBar.h" #include "arch/IArchMultithread.h" +#include "arch/IArchTaskBar.h" #include "common/stdmap.h" #include "common/stdvector.h" @@ -31,84 +31,83 @@ //! Win32 implementation of IArchTaskBar class ArchTaskBarWindows : public IArchTaskBar { public: - ArchTaskBarWindows(); - virtual ~ArchTaskBarWindows(); + ArchTaskBarWindows(); + virtual ~ArchTaskBarWindows(); - virtual void init(); + virtual void init(); - //! Add a dialog window - /*! - Tell the task bar event loop about a dialog. Win32 annoyingly - requires messages destined for modeless dialog boxes to be - dispatched differently than other messages. - */ - static void addDialog(HWND); + //! Add a dialog window + /*! + Tell the task bar event loop about a dialog. Win32 annoyingly + requires messages destined for modeless dialog boxes to be + dispatched differently than other messages. + */ + static void addDialog(HWND); - //! Remove a dialog window - /*! - Remove a dialog window added via \c addDialog(). - */ - static void removeDialog(HWND); + //! Remove a dialog window + /*! + Remove a dialog window added via \c addDialog(). + */ + static void removeDialog(HWND); - // IArchTaskBar overrides - virtual void addReceiver(IArchTaskBarReceiver*); - virtual void removeReceiver(IArchTaskBarReceiver*); - virtual void updateReceiver(IArchTaskBarReceiver*); + // IArchTaskBar overrides + virtual void addReceiver(IArchTaskBarReceiver *); + virtual void removeReceiver(IArchTaskBarReceiver *); + virtual void updateReceiver(IArchTaskBarReceiver *); private: - class ReceiverInfo { - public: - UINT m_id; - }; + class ReceiverInfo { + public: + UINT m_id; + }; - typedef std::map ReceiverToInfoMap; - typedef std::map CIDToReceiverMap; - typedef std::vector CIDStack; - typedef std::map Dialogs; + typedef std::map ReceiverToInfoMap; + typedef std::map CIDToReceiverMap; + typedef std::vector CIDStack; + typedef std::map Dialogs; - UINT getNextID(); - void recycleID(UINT); + UINT getNextID(); + void recycleID(UINT); - void addIcon(UINT); - void removeIcon(UINT); - void updateIcon(UINT); - void addAllIcons(); - void removeAllIcons(); - void modifyIconNoLock(ReceiverToInfoMap::const_iterator, - DWORD taskBarMessage); - void removeIconNoLock(UINT id); - void handleIconMessage(IArchTaskBarReceiver*, LPARAM); + void addIcon(UINT); + void removeIcon(UINT); + void updateIcon(UINT); + void addAllIcons(); + void removeAllIcons(); + void modifyIconNoLock(ReceiverToInfoMap::const_iterator, + DWORD taskBarMessage); + void removeIconNoLock(UINT id); + void handleIconMessage(IArchTaskBarReceiver *, LPARAM); - bool processDialogs(MSG*); - LRESULT wndProc(HWND, UINT, WPARAM, LPARAM); - static LRESULT CALLBACK - staticWndProc(HWND, UINT, WPARAM, LPARAM); - void threadMainLoop(); - static void* threadEntry(void*); + bool processDialogs(MSG *); + LRESULT wndProc(HWND, UINT, WPARAM, LPARAM); + static LRESULT CALLBACK staticWndProc(HWND, UINT, WPARAM, LPARAM); + void threadMainLoop(); + static void *threadEntry(void *); - HINSTANCE instanceWin32(); + HINSTANCE instanceWin32(); private: - static ArchTaskBarWindows* s_instance; + static ArchTaskBarWindows *s_instance; - // multithread data - ArchMutex m_mutex; - ArchCond m_condVar; - bool m_ready; - int m_result; - ArchThread m_thread; + // multithread data + ArchMutex m_mutex; + ArchCond m_condVar; + bool m_ready; + int m_result; + ArchThread m_thread; - // child thread data - HWND m_hwnd; - UINT m_taskBarRestart; + // child thread data + HWND m_hwnd; + UINT m_taskBarRestart; - // shared data - ReceiverToInfoMap m_receivers; - CIDToReceiverMap m_idTable; - CIDStack m_oldIDs; - UINT m_nextID; + // shared data + ReceiverToInfoMap m_receivers; + CIDToReceiverMap m_idTable; + CIDStack m_oldIDs; + UINT m_nextID; - // dialogs - Dialogs m_dialogs; - Dialogs m_addedDialogs; + // dialogs + Dialogs m_dialogs; + Dialogs m_addedDialogs; }; diff --git a/src/lib/arch/win32/ArchTimeWindows.cpp b/src/lib/arch/win32/ArchTimeWindows.cpp index 389e07a41..8cfb002dc 100644 --- a/src/lib/arch/win32/ArchTimeWindows.cpp +++ b/src/lib/arch/win32/ArchTimeWindows.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -21,69 +21,61 @@ #define WIN32_LEAN_AND_MEAN #include -#define MMNODRV // Disable: Installable driver support -#define MMNOSOUND // Disable: Sound support -#define MMNOWAVE // Disable: Waveform support -#define MMNOMIDI // Disable: MIDI support -#define MMNOAUX // Disable: Auxiliary audio support -#define MMNOMIXER // Disable: Mixer support -#define MMNOJOY // Disable: Joystick support -#define MMNOMCI // Disable: MCI support -#define MMNOMMIO // Disable: Multimedia file I/O support -#define MMNOMMSYSTEM // Disable: General MMSYSTEM functions +#define MMNODRV // Disable: Installable driver support +#define MMNOSOUND // Disable: Sound support +#define MMNOWAVE // Disable: Waveform support +#define MMNOMIDI // Disable: MIDI support +#define MMNOAUX // Disable: Auxiliary audio support +#define MMNOMIXER // Disable: Mixer support +#define MMNOJOY // Disable: Joystick support +#define MMNOMCI // Disable: MCI support +#define MMNOMMIO // Disable: Multimedia file I/O support +#define MMNOMMSYSTEM // Disable: General MMSYSTEM functions #include -typedef WINMMAPI DWORD (WINAPI *PTimeGetTime)(void); - -static double s_freq = 0.0; -static HINSTANCE s_mmInstance = NULL; -static PTimeGetTime s_tgt = NULL; +typedef WINMMAPI DWORD(WINAPI *PTimeGetTime)(void); +static double s_freq = 0.0; +static HINSTANCE s_mmInstance = NULL; +static PTimeGetTime s_tgt = NULL; // // ArchTimeWindows // -ArchTimeWindows::ArchTimeWindows() -{ - assert(s_freq == 0.0 || s_mmInstance == NULL); +ArchTimeWindows::ArchTimeWindows() { + assert(s_freq == 0.0 || s_mmInstance == NULL); - LARGE_INTEGER freq; - if (QueryPerformanceFrequency(&freq) && freq.QuadPart != 0) { - s_freq = 1.0 / static_cast(freq.QuadPart); - } - else { - // load winmm.dll and get timeGetTime - s_mmInstance = LoadLibrary("winmm"); - if (s_mmInstance != NULL) { - s_tgt = (PTimeGetTime)GetProcAddress(s_mmInstance, "timeGetTime"); - } + LARGE_INTEGER freq; + if (QueryPerformanceFrequency(&freq) && freq.QuadPart != 0) { + s_freq = 1.0 / static_cast(freq.QuadPart); + } else { + // load winmm.dll and get timeGetTime + s_mmInstance = LoadLibrary("winmm"); + if (s_mmInstance != NULL) { + s_tgt = (PTimeGetTime)GetProcAddress(s_mmInstance, "timeGetTime"); } + } } -ArchTimeWindows::~ArchTimeWindows() -{ - s_freq = 0.0; - if (s_mmInstance == NULL) { - FreeLibrary(static_cast(s_mmInstance)); - s_tgt = NULL; - s_mmInstance = NULL; - } +ArchTimeWindows::~ArchTimeWindows() { + s_freq = 0.0; + if (s_mmInstance == NULL) { + FreeLibrary(static_cast(s_mmInstance)); + s_tgt = NULL; + s_mmInstance = NULL; + } } -double -ArchTimeWindows::time() -{ - // get time. we try three ways, in order of descending precision - if (s_freq != 0.0) { - LARGE_INTEGER c; - QueryPerformanceCounter(&c); - return s_freq * static_cast(c.QuadPart); - } - else if (s_tgt != NULL) { - return 0.001 * static_cast(s_tgt()); - } - else { - return 0.001 * static_cast(GetTickCount()); - } +double ArchTimeWindows::time() { + // get time. we try three ways, in order of descending precision + if (s_freq != 0.0) { + LARGE_INTEGER c; + QueryPerformanceCounter(&c); + return s_freq * static_cast(c.QuadPart); + } else if (s_tgt != NULL) { + return 0.001 * static_cast(s_tgt()); + } else { + return 0.001 * static_cast(GetTickCount()); + } } diff --git a/src/lib/arch/win32/ArchTimeWindows.h b/src/lib/arch/win32/ArchTimeWindows.h index 5a6336c51..b057e48bc 100644 --- a/src/lib/arch/win32/ArchTimeWindows.h +++ b/src/lib/arch/win32/ArchTimeWindows.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -25,9 +25,9 @@ //! Win32 implementation of IArchTime class ArchTimeWindows : public IArchTime { public: - ArchTimeWindows(); - virtual ~ArchTimeWindows(); + ArchTimeWindows(); + virtual ~ArchTimeWindows(); - // IArchTime overrides - virtual double time(); + // IArchTime overrides + virtual double time(); }; diff --git a/src/lib/arch/win32/XArchWindows.cpp b/src/lib/arch/win32/XArchWindows.cpp index d4ec26bef..c7f5e8a90 100644 --- a/src/lib/arch/win32/XArchWindows.cpp +++ b/src/lib/arch/win32/XArchWindows.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -24,97 +24,136 @@ // XArchEvalWindows // -std::string -XArchEvalWindows::eval() const throw() -{ - char* cmsg; - if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_IGNORE_INSERTS | - FORMAT_MESSAGE_FROM_SYSTEM, - 0, - m_error, - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - (LPTSTR)&cmsg, - 0, - NULL) == 0) { - cmsg = NULL; - return synergy::string::sprintf("Unknown error, code %d", m_error); - } - std::string smsg(cmsg); - LocalFree(cmsg); - return smsg; +std::string XArchEvalWindows::eval() const throw() { + char *cmsg; + if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_IGNORE_INSERTS | + FORMAT_MESSAGE_FROM_SYSTEM, + 0, m_error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR)&cmsg, 0, NULL) == 0) { + cmsg = NULL; + return synergy::string::sprintf("Unknown error, code %d", m_error); + } + std::string smsg(cmsg); + LocalFree(cmsg); + return smsg; } - // // XArchEvalWinsock // -std::string -XArchEvalWinsock::eval() const throw() -{ - // built-in windows function for looking up error message strings - // may not look up network error messages correctly. we'll have - // to do it ourself. - static const struct { int m_code; const char* m_msg; } s_netErrorCodes[] = { - /* 10004 */{WSAEINTR, "The (blocking) call was canceled via WSACancelBlockingCall"}, - /* 10009 */{WSAEBADF, "Bad file handle"}, - /* 10013 */{WSAEACCES, "The requested address is a broadcast address, but the appropriate flag was not set"}, - /* 10014 */{WSAEFAULT, "WSAEFAULT"}, - /* 10022 */{WSAEINVAL, "WSAEINVAL"}, - /* 10024 */{WSAEMFILE, "No more file descriptors available"}, - /* 10035 */{WSAEWOULDBLOCK, "Socket is marked as non-blocking and no connections are present or the receive operation would block"}, - /* 10036 */{WSAEINPROGRESS, "A blocking Windows Sockets operation is in progress"}, - /* 10037 */{WSAEALREADY, "The asynchronous routine being canceled has already completed"}, - /* 10038 */{WSAENOTSOCK, "At least on descriptor is not a socket"}, - /* 10039 */{WSAEDESTADDRREQ, "A destination address is required"}, - /* 10040 */{WSAEMSGSIZE, "The datagram was too large to fit into the specified buffer and was truncated"}, - /* 10041 */{WSAEPROTOTYPE, "The specified protocol is the wrong type for this socket"}, - /* 10042 */{WSAENOPROTOOPT, "The option is unknown or unsupported"}, - /* 10043 */{WSAEPROTONOSUPPORT,"The specified protocol is not supported"}, - /* 10044 */{WSAESOCKTNOSUPPORT,"The specified socket type is not supported by this address family"}, - /* 10045 */{WSAEOPNOTSUPP, "The referenced socket is not a type that supports that operation"}, - /* 10046 */{WSAEPFNOSUPPORT, "BSD: Protocol family not supported"}, - /* 10047 */{WSAEAFNOSUPPORT, "The specified address family is not supported"}, - /* 10048 */{WSAEADDRINUSE, "The specified address is already in use"}, - /* 10049 */{WSAEADDRNOTAVAIL, "The specified address is not available from the local machine"}, - /* 10050 */{WSAENETDOWN, "The Windows Sockets implementation has detected that the network subsystem has failed"}, - /* 10051 */{WSAENETUNREACH, "The network can't be reached from this host at this time"}, - /* 10052 */{WSAENETRESET, "The connection must be reset because the Windows Sockets implementation dropped it"}, - /* 10053 */{WSAECONNABORTED, "The virtual circuit was aborted due to timeout or other failure"}, - /* 10054 */{WSAECONNRESET, "The virtual circuit was reset by the remote side"}, - /* 10055 */{WSAENOBUFS, "No buffer space is available or a buffer deadlock has occured. The socket cannot be created"}, - /* 10056 */{WSAEISCONN, "The socket is already connected"}, - /* 10057 */{WSAENOTCONN, "The socket is not connected"}, - /* 10058 */{WSAESHUTDOWN, "The socket has been shutdown"}, - /* 10059 */{WSAETOOMANYREFS, "BSD: Too many references"}, - /* 10060 */{WSAETIMEDOUT, "Attempt to connect timed out without establishing a connection"}, - /* 10061 */{WSAECONNREFUSED, "Connection was refused"}, - /* 10062 */{WSAELOOP, "Undocumented WinSock error code used in BSD"}, - /* 10063 */{WSAENAMETOOLONG, "Undocumented WinSock error code used in BSD"}, - /* 10064 */{WSAEHOSTDOWN, "Undocumented WinSock error code used in BSD"}, - /* 10065 */{WSAEHOSTUNREACH, "No route to host"}, - /* 10066 */{WSAENOTEMPTY, "Undocumented WinSock error code"}, - /* 10067 */{WSAEPROCLIM, "Undocumented WinSock error code"}, - /* 10068 */{WSAEUSERS, "Undocumented WinSock error code"}, - /* 10069 */{WSAEDQUOT, "Undocumented WinSock error code"}, - /* 10070 */{WSAESTALE, "Undocumented WinSock error code"}, - /* 10071 */{WSAEREMOTE, "Undocumented WinSock error code"}, - /* 10091 */{WSASYSNOTREADY, "Underlying network subsytem is not ready for network communication"}, - /* 10092 */{WSAVERNOTSUPPORTED, "The version of WinSock API support requested is not provided in this implementation"}, - /* 10093 */{WSANOTINITIALISED, "WinSock subsystem not properly initialized"}, - /* 10101 */{WSAEDISCON, "Virtual circuit has gracefully terminated connection"}, - /* 11001 */{WSAHOST_NOT_FOUND, "The specified host is unknown"}, - /* 11002 */{WSATRY_AGAIN, "A temporary error occurred on an authoritative name server"}, - /* 11003 */{WSANO_RECOVERY, "A non-recoverable name server error occurred"}, - /* 11004 */{WSANO_DATA, "The requested name is valid but does not have an IP address"}, - /* end */{0, NULL} - }; +std::string XArchEvalWinsock::eval() const throw() { + // built-in windows function for looking up error message strings + // may not look up network error messages correctly. we'll have + // to do it ourself. + static const struct { + int m_code; + const char *m_msg; + } s_netErrorCodes[] = { + /* 10004 */ { + WSAEINTR, + "The (blocking) call was canceled via WSACancelBlockingCall"}, + /* 10009 */ {WSAEBADF, "Bad file handle"}, + /* 10013 */ + {WSAEACCES, "The requested address is a broadcast address, but the " + "appropriate flag was not set"}, + /* 10014 */ {WSAEFAULT, "WSAEFAULT"}, + /* 10022 */ {WSAEINVAL, "WSAEINVAL"}, + /* 10024 */ {WSAEMFILE, "No more file descriptors available"}, + /* 10035 */ + {WSAEWOULDBLOCK, "Socket is marked as non-blocking and no connections " + "are present or the receive operation would block"}, + /* 10036 */ + {WSAEINPROGRESS, "A blocking Windows Sockets operation is in progress"}, + /* 10037 */ + {WSAEALREADY, + "The asynchronous routine being canceled has already completed"}, + /* 10038 */ {WSAENOTSOCK, "At least on descriptor is not a socket"}, + /* 10039 */ {WSAEDESTADDRREQ, "A destination address is required"}, + /* 10040 */ + {WSAEMSGSIZE, "The datagram was too large to fit into the specified " + "buffer and was truncated"}, + /* 10041 */ + {WSAEPROTOTYPE, + "The specified protocol is the wrong type for this socket"}, + /* 10042 */ {WSAENOPROTOOPT, "The option is unknown or unsupported"}, + /* 10043 */ + {WSAEPROTONOSUPPORT, "The specified protocol is not supported"}, + /* 10044 */ + {WSAESOCKTNOSUPPORT, + "The specified socket type is not supported by this address family"}, + /* 10045 */ + {WSAEOPNOTSUPP, + "The referenced socket is not a type that supports that operation"}, + /* 10046 */ {WSAEPFNOSUPPORT, "BSD: Protocol family not supported"}, + /* 10047 */ + {WSAEAFNOSUPPORT, "The specified address family is not supported"}, + /* 10048 */ {WSAEADDRINUSE, "The specified address is already in use"}, + /* 10049 */ + {WSAEADDRNOTAVAIL, + "The specified address is not available from the local machine"}, + /* 10050 */ + {WSAENETDOWN, "The Windows Sockets implementation has detected that the " + "network subsystem has failed"}, + /* 10051 */ + {WSAENETUNREACH, + "The network can't be reached from this host at this time"}, + /* 10052 */ + {WSAENETRESET, "The connection must be reset because the Windows Sockets " + "implementation dropped it"}, + /* 10053 */ + {WSAECONNABORTED, + "The virtual circuit was aborted due to timeout or other failure"}, + /* 10054 */ + {WSAECONNRESET, "The virtual circuit was reset by the remote side"}, + /* 10055 */ + {WSAENOBUFS, "No buffer space is available or a buffer deadlock has " + "occured. The socket cannot be created"}, + /* 10056 */ {WSAEISCONN, "The socket is already connected"}, + /* 10057 */ {WSAENOTCONN, "The socket is not connected"}, + /* 10058 */ {WSAESHUTDOWN, "The socket has been shutdown"}, + /* 10059 */ {WSAETOOMANYREFS, "BSD: Too many references"}, + /* 10060 */ + {WSAETIMEDOUT, + "Attempt to connect timed out without establishing a connection"}, + /* 10061 */ {WSAECONNREFUSED, "Connection was refused"}, + /* 10062 */ {WSAELOOP, "Undocumented WinSock error code used in BSD"}, + /* 10063 */ + {WSAENAMETOOLONG, "Undocumented WinSock error code used in BSD"}, + /* 10064 */ {WSAEHOSTDOWN, "Undocumented WinSock error code used in BSD"}, + /* 10065 */ {WSAEHOSTUNREACH, "No route to host"}, + /* 10066 */ {WSAENOTEMPTY, "Undocumented WinSock error code"}, + /* 10067 */ {WSAEPROCLIM, "Undocumented WinSock error code"}, + /* 10068 */ {WSAEUSERS, "Undocumented WinSock error code"}, + /* 10069 */ {WSAEDQUOT, "Undocumented WinSock error code"}, + /* 10070 */ {WSAESTALE, "Undocumented WinSock error code"}, + /* 10071 */ {WSAEREMOTE, "Undocumented WinSock error code"}, + /* 10091 */ + {WSASYSNOTREADY, + "Underlying network subsytem is not ready for network communication"}, + /* 10092 */ + {WSAVERNOTSUPPORTED, "The version of WinSock API support requested is " + "not provided in this implementation"}, + /* 10093 */ + {WSANOTINITIALISED, "WinSock subsystem not properly initialized"}, + /* 10101 */ + {WSAEDISCON, "Virtual circuit has gracefully terminated connection"}, + /* 11001 */ {WSAHOST_NOT_FOUND, "The specified host is unknown"}, + /* 11002 */ + {WSATRY_AGAIN, + "A temporary error occurred on an authoritative name server"}, + /* 11003 */ + {WSANO_RECOVERY, "A non-recoverable name server error occurred"}, + /* 11004 */ + {WSANO_DATA, + "The requested name is valid but does not have an IP address"}, + /* end */ {0, NULL}}; - for (unsigned int i = 0; s_netErrorCodes[i].m_code != 0; ++i) { - if (s_netErrorCodes[i].m_code == m_error) { - return s_netErrorCodes[i].m_msg; - } + for (unsigned int i = 0; s_netErrorCodes[i].m_code != 0; ++i) { + if (s_netErrorCodes[i].m_code == m_error) { + return s_netErrorCodes[i].m_msg; } - return "Unknown error"; + } + return "Unknown error"; } diff --git a/src/lib/arch/win32/XArchWindows.h b/src/lib/arch/win32/XArchWindows.h index 29351259a..44c6d5894 100644 --- a/src/lib/arch/win32/XArchWindows.h +++ b/src/lib/arch/win32/XArchWindows.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -26,24 +26,24 @@ //! Lazy error message string evaluation for windows class XArchEvalWindows : public XArchEval { public: - XArchEvalWindows() : m_error(GetLastError()) { } - XArchEvalWindows(DWORD error) : m_error(error) { } - virtual ~XArchEvalWindows() { } + XArchEvalWindows() : m_error(GetLastError()) {} + XArchEvalWindows(DWORD error) : m_error(error) {} + virtual ~XArchEvalWindows() {} - virtual std::string eval() const; + virtual std::string eval() const; private: - DWORD m_error; + DWORD m_error; }; //! Lazy error message string evaluation for winsock class XArchEvalWinsock : public XArchEval { public: - XArchEvalWinsock(int error) : m_error(error) { } - virtual ~XArchEvalWinsock() { } + XArchEvalWinsock(int error) : m_error(error) {} + virtual ~XArchEvalWinsock() {} - virtual std::string eval() const; + virtual std::string eval() const; private: - int m_error; + int m_error; }; diff --git a/src/lib/base/ELevel.h b/src/lib/base/ELevel.h index 89c1a2237..1783b83df 100644 --- a/src/lib/base/ELevel.h +++ b/src/lib/base/ELevel.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2011 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 LICENSE 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 @@ -23,16 +23,16 @@ The logging priority levels in order of highest to lowest priority. */ enum ELevel { - kPRINT = -1, //!< For print only (no file or time) - kFATAL, //!< For fatal errors - kERROR, //!< For serious errors - kWARNING, //!< For minor errors and warnings - kNOTE, //!< For messages about notable events - kINFO, //!< For informational messages - kDEBUG, //!< For important debugging messages - kDEBUG1, //!< For verbosity +1 debugging messages - kDEBUG2, //!< For verbosity +2 debugging messages - kDEBUG3, //!< For verbosity +3 debugging messages - kDEBUG4, //!< For verbosity +4 debugging messages - kDEBUG5 //!< For verbosity +5 debugging messages + kPRINT = -1, //!< For print only (no file or time) + kFATAL, //!< For fatal errors + kERROR, //!< For serious errors + kWARNING, //!< For minor errors and warnings + kNOTE, //!< For messages about notable events + kINFO, //!< For informational messages + kDEBUG, //!< For important debugging messages + kDEBUG1, //!< For verbosity +1 debugging messages + kDEBUG2, //!< For verbosity +2 debugging messages + kDEBUG3, //!< For verbosity +3 debugging messages + kDEBUG4, //!< For verbosity +4 debugging messages + kDEBUG5 //!< For verbosity +5 debugging messages }; diff --git a/src/lib/base/Event.cpp b/src/lib/base/Event.cpp index f7a3b79f9..59e507027 100644 --- a/src/lib/base/Event.cpp +++ b/src/lib/base/Event.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 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 LICENSE 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 @@ -23,88 +23,50 @@ // Event // -Event::Event() : - m_type(kUnknown), - m_target(NULL), - m_data(NULL), - m_flags(0), - m_dataObject(nullptr) -{ - // do nothing +Event::Event() + : m_type(kUnknown), m_target(NULL), m_data(NULL), m_flags(0), + m_dataObject(nullptr) { + // do nothing } -Event::Event(Type type, void* target, void* data, Flags flags) : - m_type(type), - m_target(target), - m_data(data), - m_flags(flags), - m_dataObject(nullptr) -{ - // do nothing +Event::Event(Type type, void *target, void *data, Flags flags) + : m_type(type), m_target(target), m_data(data), m_flags(flags), + m_dataObject(nullptr) { + // do nothing } -Event::Event(Type type, void* target, EventData* dataObject) : - m_type(type), - m_target(target), - m_data(nullptr), - m_flags(kNone), - m_dataObject(dataObject) -{ +Event::Event(Type type, void *target, EventData *dataObject) + : m_type(type), m_target(target), m_data(nullptr), m_flags(kNone), + m_dataObject(dataObject) {} -} +Event::Type Event::getType() const { return m_type; } -Event::Type -Event::getType() const -{ - return m_type; -} +void *Event::getTarget() const { return m_target; } -void* -Event::getTarget() const -{ - return m_target; -} +void *Event::getData() const { return m_data; } -void* -Event::getData() const -{ - return m_data; -} +EventData *Event::getDataObject() const { return m_dataObject; } -EventData* -Event::getDataObject() const -{ - return m_dataObject; -} +Event::Flags Event::getFlags() const { return m_flags; } -Event::Flags -Event::getFlags() const -{ - return m_flags; -} +void Event::deleteData(const Event &event) { + switch (event.getType()) { + case kUnknown: + case kQuit: + case kSystem: + case kTimer: + break; -void -Event::deleteData(const Event& 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; + default: + if ((event.getFlags() & kDontFreeData) == 0) { + free(event.getData()); + delete event.getDataObject(); } + break; + } } -void -Event::setDataObject(EventData* dataObject) -{ - assert(m_dataObject == nullptr); - m_dataObject = dataObject; +void Event::setDataObject(EventData *dataObject) { + assert(m_dataObject == nullptr); + m_dataObject = dataObject; } diff --git a/src/lib/base/Event.h b/src/lib/base/Event.h index b99eac83d..4b27af2c3 100644 --- a/src/lib/base/Event.h +++ b/src/lib/base/Event.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 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 LICENSE 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 @@ -23,8 +23,8 @@ class EventData { public: - EventData() { } - virtual ~EventData() { } + EventData() {} + virtual ~EventData() {} }; //! Event @@ -33,102 +33,101 @@ A \c Event holds an event type and a pointer to event data. */ class Event { public: - typedef UInt32 Type; - enum { - kUnknown, //!< The event type is unknown - kQuit, //!< The quit event - kSystem, //!< The data points to a system event type - kTimer, //!< The data points to timer info - kLast //!< Must be last - }; + typedef UInt32 Type; + enum { + kUnknown, //!< The event type is unknown + kQuit, //!< The quit event + kSystem, //!< The data points to a system event type + kTimer, //!< The data points to timer info + kLast //!< Must be last + }; - typedef UInt32 Flags; - enum { - kNone = 0x00, //!< No flags - kDeliverImmediately = 0x01, //!< Dispatch and free event immediately - kDontFreeData = 0x02 //!< Don't free data in deleteData - }; + typedef UInt32 Flags; + enum { + kNone = 0x00, //!< No flags + kDeliverImmediately = 0x01, //!< Dispatch and free event immediately + kDontFreeData = 0x02 //!< Don't free data in deleteData + }; - Event(); + Event(); - //! Create \c Event with data (POD) - /*! - The \p data must be POD (plain old data) allocated by malloc(), - which means it cannot have a constructor, destructor or be - composed of any types that do. For non-POD (normal C++ objects - use \c setDataObject() or use appropriate constructor. - \p target is the intended recipient of the event. - \p flags is any combination of \c Flags. - */ - Event(Type type, void* target = NULL, void* data = NULL, - Flags flags = kNone); + //! Create \c Event with data (POD) + /*! + The \p data must be POD (plain old data) allocated by malloc(), + which means it cannot have a constructor, destructor or be + composed of any types that do. For non-POD (normal C++ objects + use \c setDataObject() or use appropriate constructor. + \p target is the intended recipient of the event. + \p flags is any combination of \c Flags. + */ + Event(Type type, void *target = NULL, void *data = NULL, Flags flags = kNone); - //! Create \c Event with non-POD data - /*! - \p type of the event - \p target is the intended recipient of the event. - \p dataObject with event data - */ - Event(Type type, void* target, EventData* dataObject); + //! Create \c Event with non-POD data + /*! + \p type of the event + \p target is the intended recipient of the event. + \p dataObject with event data + */ + Event(Type type, void *target, EventData *dataObject); - //! @name manipulators - //@{ + //! @name manipulators + //@{ - //! Release event data - /*! - Deletes event data for the given event (using free()). - */ - static void deleteData(const Event&); - - //! Set data (non-POD) - /*! - Set non-POD (non plain old data), where delete is called when the event - is deleted, and the destructor is called. - */ - void setDataObject(EventData* dataObject); + //! Release event data + /*! + Deletes event data for the given event (using free()). + */ + static void deleteData(const Event &); - //@} - //! @name accessors - //@{ + //! Set data (non-POD) + /*! + Set non-POD (non plain old data), where delete is called when the event + is deleted, and the destructor is called. + */ + void setDataObject(EventData *dataObject); - //! Get event type - /*! - Returns the event type. - */ - Type getType() const; + //@} + //! @name accessors + //@{ - //! Get the event target - /*! - Returns the event target. - */ - void* getTarget() const; + //! Get event type + /*! + Returns the event type. + */ + Type getType() const; - //! Get the event data (POD). - /*! - Returns the event data (POD). - */ - void* getData() const; + //! Get the event target + /*! + Returns the event target. + */ + void *getTarget() const; - //! Get the event data (non-POD) - /*! - Returns the event data (non-POD). The difference between this and - \c getData() is that when delete is called on this data, so non-POD - (non plain old data) dtor is called. - */ - EventData* getDataObject() const; + //! Get the event data (POD). + /*! + Returns the event data (POD). + */ + void *getData() const; - //! Get event flags - /*! - Returns the event flags. - */ - Flags getFlags() const; - - //@} + //! Get the event data (non-POD) + /*! + Returns the event data (non-POD). The difference between this and + \c getData() is that when delete is called on this data, so non-POD + (non plain old data) dtor is called. + */ + EventData *getDataObject() const; + + //! Get event flags + /*! + Returns the event flags. + */ + Flags getFlags() const; + + //@} private: - Type m_type; - void* m_target; - void* m_data; - Flags m_flags; - EventData* m_dataObject; + Type m_type; + void *m_target; + void *m_data; + Flags m_flags; + EventData *m_dataObject; }; diff --git a/src/lib/base/EventQueue.cpp b/src/lib/base/EventQueue.cpp index dfdebe209..374b6260d 100644 --- a/src/lib/base/EventQueue.cpp +++ b/src/lib/base/EventQueue.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 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 LICENSE 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 @@ -18,15 +18,15 @@ #include "base/EventQueue.h" -#include "mt/Mutex.h" -#include "mt/Lock.h" #include "arch/Arch.h" +#include "base/EventTypes.h" +#include "base/IEventJob.h" +#include "base/Log.h" #include "base/SimpleEventQueueBuffer.h" #include "base/Stopwatch.h" -#include "base/IEventJob.h" -#include "base/EventTypes.h" -#include "base/Log.h" #include "base/XBase.h" +#include "mt/Lock.h" +#include "mt/Mutex.h" EVENT_TYPE_ACCESSOR(Client) EVENT_TYPE_ACCESSOR(IStream) @@ -50,596 +50,498 @@ EVENT_TYPE_ACCESSOR(Clipboard) EVENT_TYPE_ACCESSOR(File) // interrupt handler. this just adds a quit event to the queue. -static -void -interrupt(Arch::ESignal, void* data) -{ - EventQueue* events = static_cast(data); - events->addEvent(Event(Event::kQuit)); +static void interrupt(Arch::ESignal, void *data) { + EventQueue *events = static_cast(data); + events->addEvent(Event(Event::kQuit)); } - // // EventQueue // -EventQueue::EventQueue() : - m_systemTarget(0), - m_nextType(Event::kLast), - m_typesForClient(NULL), - m_typesForIStream(NULL), - m_typesForIpcClient(NULL), - m_typesForIpcClientProxy(NULL), - m_typesForIpcServer(NULL), - m_typesForIpcServerProxy(NULL), - m_typesForIDataSocket(NULL), - m_typesForIListenSocket(NULL), - m_typesForISocket(NULL), - m_typesForOSXScreen(NULL), - m_typesForClientListener(NULL), - m_typesForClientProxy(NULL), - m_typesForClientProxyUnknown(NULL), - m_typesForServer(NULL), - m_typesForServerApp(NULL), - m_typesForIKeyState(NULL), - m_typesForIPrimaryScreen(NULL), - m_typesForIScreen(NULL), - m_typesForClipboard(NULL), - m_typesForFile(NULL), - m_readyMutex(new Mutex), - m_readyCondVar(new CondVar(m_readyMutex, false)) -{ - m_mutex = ARCH->newMutex(); - ARCH->setSignalHandler(Arch::kINTERRUPT, &interrupt, this); - ARCH->setSignalHandler(Arch::kTERMINATE, &interrupt, this); - m_buffer = new SimpleEventQueueBuffer; +EventQueue::EventQueue() + : m_systemTarget(0), m_nextType(Event::kLast), m_typesForClient(NULL), + m_typesForIStream(NULL), m_typesForIpcClient(NULL), + m_typesForIpcClientProxy(NULL), m_typesForIpcServer(NULL), + m_typesForIpcServerProxy(NULL), m_typesForIDataSocket(NULL), + m_typesForIListenSocket(NULL), m_typesForISocket(NULL), + m_typesForOSXScreen(NULL), m_typesForClientListener(NULL), + m_typesForClientProxy(NULL), m_typesForClientProxyUnknown(NULL), + m_typesForServer(NULL), m_typesForServerApp(NULL), + m_typesForIKeyState(NULL), m_typesForIPrimaryScreen(NULL), + m_typesForIScreen(NULL), m_typesForClipboard(NULL), m_typesForFile(NULL), + m_readyMutex(new Mutex), + m_readyCondVar(new CondVar(m_readyMutex, false)) { + m_mutex = ARCH->newMutex(); + ARCH->setSignalHandler(Arch::kINTERRUPT, &interrupt, this); + ARCH->setSignalHandler(Arch::kTERMINATE, &interrupt, this); + m_buffer = new SimpleEventQueueBuffer; } -EventQueue::~EventQueue() -{ - delete m_buffer; - delete m_readyCondVar; - delete m_readyMutex; - - ARCH->setSignalHandler(Arch::kINTERRUPT, NULL, NULL); - ARCH->setSignalHandler(Arch::kTERMINATE, NULL, NULL); - ARCH->closeMutex(m_mutex); +EventQueue::~EventQueue() { + delete m_buffer; + delete m_readyCondVar; + delete m_readyMutex; + + ARCH->setSignalHandler(Arch::kINTERRUPT, NULL, NULL); + ARCH->setSignalHandler(Arch::kTERMINATE, NULL, NULL); + ARCH->closeMutex(m_mutex); } -void -EventQueue::loop() -{ - m_buffer->init(); - { - Lock lock(m_readyMutex); - *m_readyCondVar = true; - m_readyCondVar->signal(); - } - LOG((CLOG_DEBUG "event queue is ready")); - while (!m_pending.empty()) { - LOG((CLOG_DEBUG "add pending events to buffer")); - Event& event = m_pending.front(); - addEventToBuffer(event); - m_pending.pop(); - } - - Event event; +void EventQueue::loop() { + m_buffer->init(); + { + Lock lock(m_readyMutex); + *m_readyCondVar = true; + m_readyCondVar->signal(); + } + LOG((CLOG_DEBUG "event queue is ready")); + while (!m_pending.empty()) { + LOG((CLOG_DEBUG "add pending events to buffer")); + Event &event = m_pending.front(); + addEventToBuffer(event); + m_pending.pop(); + } + + Event event; + getEvent(event); + while (event.getType() != Event::kQuit) { + dispatchEvent(event); + Event::deleteData(event); getEvent(event); - while (event.getType() != Event::kQuit) { - dispatchEvent(event); - Event::deleteData(event); - getEvent(event); - } + } } -Event::Type -EventQueue::registerTypeOnce(Event::Type& type, const char* name) -{ - ArchMutexLock lock(m_mutex); - if (type == Event::kUnknown) { - m_typeMap.insert(std::make_pair(m_nextType, name)); - m_nameMap.insert(std::make_pair(name, m_nextType)); - LOG((CLOG_DEBUG1 "registered event type %s as %d", name, m_nextType)); - type = m_nextType++; - } - return type; +Event::Type EventQueue::registerTypeOnce(Event::Type &type, const char *name) { + ArchMutexLock lock(m_mutex); + if (type == Event::kUnknown) { + m_typeMap.insert(std::make_pair(m_nextType, name)); + m_nameMap.insert(std::make_pair(name, m_nextType)); + LOG((CLOG_DEBUG1 "registered event type %s as %d", name, m_nextType)); + type = m_nextType++; + } + return type; } -const char* -EventQueue::getTypeName(Event::Type type) -{ - switch (type) { - case Event::kUnknown: - return "nil"; +const char *EventQueue::getTypeName(Event::Type type) { + switch (type) { + case Event::kUnknown: + return "nil"; - case Event::kQuit: - return "quit"; + case Event::kQuit: + return "quit"; - case Event::kSystem: - return "system"; + case Event::kSystem: + return "system"; - case Event::kTimer: - return "timer"; + case Event::kTimer: + return "timer"; - default: - TypeMap::const_iterator i = m_typeMap.find(type); - if (i == m_typeMap.end()) { - return ""; - } - else { - return i->second; - } + default: + TypeMap::const_iterator i = m_typeMap.find(type); + if (i == m_typeMap.end()) { + return ""; + } else { + return i->second; } + } } -void -EventQueue::adoptBuffer(IEventQueueBuffer* buffer) -{ - ArchMutexLock lock(m_mutex); +void EventQueue::adoptBuffer(IEventQueueBuffer *buffer) { + ArchMutexLock lock(m_mutex); - LOG((CLOG_DEBUG "adopting new buffer")); + LOG((CLOG_DEBUG "adopting new buffer")); - if (m_events.size() != 0) { - // this can come as a nasty surprise to programmers expecting - // their events to be raised, only to have them deleted. - LOG((CLOG_DEBUG "discarding %d event(s)", m_events.size())); - } + if (m_events.size() != 0) { + // this can come as a nasty surprise to programmers expecting + // their events to be raised, only to have them deleted. + LOG((CLOG_DEBUG "discarding %d event(s)", m_events.size())); + } - // discard old buffer and old events - delete m_buffer; - for (EventTable::iterator i = m_events.begin(); i != m_events.end(); ++i) { - Event::deleteData(i->second); - } - m_events.clear(); - m_oldEventIDs.clear(); + // discard old buffer and old events + delete m_buffer; + for (EventTable::iterator i = m_events.begin(); i != m_events.end(); ++i) { + Event::deleteData(i->second); + } + m_events.clear(); + m_oldEventIDs.clear(); - // use new buffer - m_buffer = buffer; - if (m_buffer == NULL) { - m_buffer = new SimpleEventQueueBuffer; - } + // use new buffer + m_buffer = buffer; + if (m_buffer == NULL) { + m_buffer = new SimpleEventQueueBuffer; + } } -bool -EventQueue::getEvent(Event& event, double timeout) -{ - Stopwatch timer(true); +bool EventQueue::getEvent(Event &event, double timeout) { + Stopwatch timer(true); retry: - // if no events are waiting then handle timers and then wait - while (m_buffer->isEmpty()) { - // handle timers first - if (hasTimerExpired(event)) { - return true; - } - - // get time remaining in timeout - double timeLeft = timeout - timer.getTime(); - if (timeout >= 0.0 && timeLeft <= 0.0) { - return false; - } - - // get time until next timer expires. if there is a timer - // and it'll expire before the client's timeout then use - // that duration for our timeout instead. - double timerTimeout = getNextTimerTimeout(); - if (timeout < 0.0 || (timerTimeout >= 0.0 && timerTimeout < timeLeft)) { - timeLeft = timerTimeout; - } - - // wait for an event - m_buffer->waitForEvent(timeLeft); + // if no events are waiting then handle timers and then wait + while (m_buffer->isEmpty()) { + // handle timers first + if (hasTimerExpired(event)) { + return true; } - // get the event - UInt32 dataID; - IEventQueueBuffer::Type type = m_buffer->getEvent(event, dataID); - switch (type) { - case IEventQueueBuffer::kNone: - if (timeout < 0.0 || timeout <= timer.getTime()) { - // don't want to fail if client isn't expecting that - // so if getEvent() fails with an infinite timeout - // then just try getting another event. - goto retry; - } - return false; - - case IEventQueueBuffer::kSystem: - return true; - - case IEventQueueBuffer::kUser: - { - ArchMutexLock lock(m_mutex); - event = removeEvent(dataID); - return true; - } - - default: - assert(0 && "invalid event type"); - return false; + // get time remaining in timeout + double timeLeft = timeout - timer.getTime(); + if (timeout >= 0.0 && timeLeft <= 0.0) { + return false; } -} -bool -EventQueue::dispatchEvent(const Event& event) -{ - void* target = event.getTarget(); - IEventJob* job = getHandler(event.getType(), target); - if (job == NULL) { - job = getHandler(Event::kUnknown, target); + // get time until next timer expires. if there is a timer + // and it'll expire before the client's timeout then use + // that duration for our timeout instead. + double timerTimeout = getNextTimerTimeout(); + if (timeout < 0.0 || (timerTimeout >= 0.0 && timerTimeout < timeLeft)) { + timeLeft = timerTimeout; } - if (job != NULL) { - job->run(event); - return true; + + // wait for an event + m_buffer->waitForEvent(timeLeft); + } + + // get the event + UInt32 dataID; + IEventQueueBuffer::Type type = m_buffer->getEvent(event, dataID); + switch (type) { + case IEventQueueBuffer::kNone: + if (timeout < 0.0 || timeout <= timer.getTime()) { + // don't want to fail if client isn't expecting that + // so if getEvent() fails with an infinite timeout + // then just try getting another event. + goto retry; } return false; -} - -void -EventQueue::addEvent(const Event& event) -{ - // discard bogus event types - switch (event.getType()) { - case Event::kUnknown: - case Event::kSystem: - case Event::kTimer: - return; - - default: - break; - } - - if ((event.getFlags() & Event::kDeliverImmediately) != 0) { - dispatchEvent(event); - Event::deleteData(event); - } - else if (!(*m_readyCondVar)) { - m_pending.push(event); - } - else { - addEventToBuffer(event); - } -} - -void -EventQueue::addEventToBuffer(const Event& event) -{ - ArchMutexLock 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); - Event::deleteData(event); - } -} - -EventQueueTimer* -EventQueue::newTimer(double duration, void* target) -{ - assert(duration > 0.0); - - EventQueueTimer* timer = m_buffer->newTimer(duration, false); - if (target == NULL) { - target = timer; - } - ArchMutexLock lock(m_mutex); - m_timers.insert(timer); - // initial duration is requested duration plus whatever's on - // the clock currently because the latter will be subtracted - // the next time we check for timers. - m_timerQueue.push(Timer(timer, duration, - duration + m_time.getTime(), target, false)); - return timer; -} - -EventQueueTimer* -EventQueue::newOneShotTimer(double duration, void* target) -{ - assert(duration > 0.0); - - EventQueueTimer* timer = m_buffer->newTimer(duration, true); - if (target == NULL) { - target = timer; - } - ArchMutexLock lock(m_mutex); - m_timers.insert(timer); - // initial duration is requested duration plus whatever's on - // the clock currently because the latter will be subtracted - // the next time we check for timers. - m_timerQueue.push(Timer(timer, duration, - duration + m_time.getTime(), target, true)); - return timer; -} - -void -EventQueue::deleteTimer(EventQueueTimer* timer) -{ - ArchMutexLock lock(m_mutex); - for (TimerQueue::iterator index = m_timerQueue.begin(); - index != m_timerQueue.end(); ++index) { - if (index->getTimer() == timer) { - m_timerQueue.erase(index); - break; - } - } - Timers::iterator index = m_timers.find(timer); - if (index != m_timers.end()) { - m_timers.erase(index); - } - m_buffer->deleteTimer(timer); -} - -void -EventQueue::adoptHandler(Event::Type type, void* target, IEventJob* handler) -{ - ArchMutexLock lock(m_mutex); - IEventJob*& job = m_handlers[target][type]; - delete job; - job = handler; -} - -void -EventQueue::removeHandler(Event::Type type, void* target) -{ - IEventJob* handler = NULL; - { - ArchMutexLock lock(m_mutex); - HandlerTable::iterator index = m_handlers.find(target); - if (index != m_handlers.end()) { - TypeHandlerTable& typeHandlers = index->second; - TypeHandlerTable::iterator index2 = typeHandlers.find(type); - if (index2 != typeHandlers.end()) { - handler = index2->second; - typeHandlers.erase(index2); - } - } - } - delete handler; -} - -void -EventQueue::removeHandlers(void* target) -{ - std::vector handlers; - { - ArchMutexLock lock(m_mutex); - HandlerTable::iterator index = m_handlers.find(target); - if (index != m_handlers.end()) { - // copy to handlers array and clear table for target - TypeHandlerTable& typeHandlers = index->second; - for (TypeHandlerTable::iterator index2 = typeHandlers.begin(); - index2 != typeHandlers.end(); ++index2) { - handlers.push_back(index2->second); - } - typeHandlers.clear(); - } - } - - // delete handlers - for (std::vector::iterator index = handlers.begin(); - index != handlers.end(); ++index) { - delete *index; - } -} - -bool -EventQueue::isEmpty() const -{ - return (m_buffer->isEmpty() && getNextTimerTimeout() != 0.0); -} - -IEventJob* -EventQueue::getHandler(Event::Type type, void* target) const -{ - ArchMutexLock lock(m_mutex); - HandlerTable::const_iterator index = m_handlers.find(target); - if (index != m_handlers.end()) { - const TypeHandlerTable& typeHandlers = index->second; - TypeHandlerTable::const_iterator index2 = typeHandlers.find(type); - if (index2 != typeHandlers.end()) { - return index2->second; - } - } - return NULL; -} - -UInt32 -EventQueue::saveEvent(const Event& event) -{ - // choose id - UInt32 id; - if (!m_oldEventIDs.empty()) { - // reuse an id - id = m_oldEventIDs.back(); - m_oldEventIDs.pop_back(); - } - else { - // make a new id - id = static_cast(m_events.size()); - } - - // save data - m_events[id] = event; - return id; -} - -Event -EventQueue::removeEvent(UInt32 eventID) -{ - // look up id - EventTable::iterator index = m_events.find(eventID); - if (index == m_events.end()) { - return Event(); - } - - // get data - Event event = index->second; - m_events.erase(index); - - // save old id for reuse - m_oldEventIDs.push_back(eventID); - - return event; -} - -bool -EventQueue::hasTimerExpired(Event& event) -{ - // return true if there's a timer in the timer priority queue that - // has expired. if returning true then fill in event appropriately - // and reset and reinsert the timer. - if (m_timerQueue.empty()) { - return false; - } - - // get time elapsed since last check - const double time = m_time.getTime(); - m_time.reset(); - - // countdown elapsed time - for (TimerQueue::iterator index = m_timerQueue.begin(); - index != m_timerQueue.end(); ++index) { - (*index) -= time; - } - - // done if no timers are expired - if (m_timerQueue.top() > 0.0) { - return false; - } - - // remove timer from queue - Timer timer = m_timerQueue.top(); - m_timerQueue.pop(); - - // prepare event and reset the timer's clock - timer.fillEvent(m_timerEvent); - event = Event(Event::kTimer, timer.getTarget(), &m_timerEvent); - timer.reset(); - - // reinsert timer into queue if it's not a one-shot - if (!timer.isOneShot()) { - m_timerQueue.push(timer); - } + case IEventQueueBuffer::kSystem: return true; + + case IEventQueueBuffer::kUser: { + ArchMutexLock lock(m_mutex); + event = removeEvent(dataID); + return true; + } + + default: + assert(0 && "invalid event type"); + return false; + } } -double -EventQueue::getNextTimerTimeout() const -{ - // return -1 if no timers, 0 if the top timer has expired, otherwise - // the time until the top timer in the timer priority queue will - // expire. - if (m_timerQueue.empty()) { - return -1.0; +bool EventQueue::dispatchEvent(const Event &event) { + void *target = event.getTarget(); + IEventJob *job = getHandler(event.getType(), target); + if (job == NULL) { + job = getHandler(Event::kUnknown, target); + } + if (job != NULL) { + job->run(event); + return true; + } + return false; +} + +void EventQueue::addEvent(const Event &event) { + // discard bogus event types + switch (event.getType()) { + case Event::kUnknown: + case Event::kSystem: + case Event::kTimer: + return; + + default: + break; + } + + if ((event.getFlags() & Event::kDeliverImmediately) != 0) { + dispatchEvent(event); + Event::deleteData(event); + } else if (!(*m_readyCondVar)) { + m_pending.push(event); + } else { + addEventToBuffer(event); + } +} + +void EventQueue::addEventToBuffer(const Event &event) { + ArchMutexLock 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); + Event::deleteData(event); + } +} + +EventQueueTimer *EventQueue::newTimer(double duration, void *target) { + assert(duration > 0.0); + + EventQueueTimer *timer = m_buffer->newTimer(duration, false); + if (target == NULL) { + target = timer; + } + ArchMutexLock lock(m_mutex); + m_timers.insert(timer); + // initial duration is requested duration plus whatever's on + // the clock currently because the latter will be subtracted + // the next time we check for timers. + m_timerQueue.push( + Timer(timer, duration, duration + m_time.getTime(), target, false)); + return timer; +} + +EventQueueTimer *EventQueue::newOneShotTimer(double duration, void *target) { + assert(duration > 0.0); + + EventQueueTimer *timer = m_buffer->newTimer(duration, true); + if (target == NULL) { + target = timer; + } + ArchMutexLock lock(m_mutex); + m_timers.insert(timer); + // initial duration is requested duration plus whatever's on + // the clock currently because the latter will be subtracted + // the next time we check for timers. + m_timerQueue.push( + Timer(timer, duration, duration + m_time.getTime(), target, true)); + return timer; +} + +void EventQueue::deleteTimer(EventQueueTimer *timer) { + ArchMutexLock lock(m_mutex); + for (TimerQueue::iterator index = m_timerQueue.begin(); + index != m_timerQueue.end(); ++index) { + if (index->getTimer() == timer) { + m_timerQueue.erase(index); + break; } - if (m_timerQueue.top() <= 0.0) { - return 0.0; + } + Timers::iterator index = m_timers.find(timer); + if (index != m_timers.end()) { + m_timers.erase(index); + } + m_buffer->deleteTimer(timer); +} + +void EventQueue::adoptHandler(Event::Type type, void *target, + IEventJob *handler) { + ArchMutexLock lock(m_mutex); + IEventJob *&job = m_handlers[target][type]; + delete job; + job = handler; +} + +void EventQueue::removeHandler(Event::Type type, void *target) { + IEventJob *handler = NULL; + { + ArchMutexLock lock(m_mutex); + HandlerTable::iterator index = m_handlers.find(target); + if (index != m_handlers.end()) { + TypeHandlerTable &typeHandlers = index->second; + TypeHandlerTable::iterator index2 = typeHandlers.find(type); + if (index2 != typeHandlers.end()) { + handler = index2->second; + typeHandlers.erase(index2); + } } - return m_timerQueue.top(); + } + delete handler; } -Event::Type -EventQueue::getRegisteredType(const String& name) const -{ - NameMap::const_iterator found = m_nameMap.find(name); - if (found != m_nameMap.end()) - return found->second; - - return Event::kUnknown; -} - -void* -EventQueue::getSystemTarget() -{ - // any unique arbitrary pointer will do - return &m_systemTarget; -} - -void -EventQueue::waitForReady() const -{ - double timeout = ARCH->time() + 10; - Lock lock(m_readyMutex); - - while (!m_readyCondVar->wait()) { - if (ARCH->time() > timeout) { - throw std::runtime_error("event queue is not ready within 5 sec"); - } +void EventQueue::removeHandlers(void *target) { + std::vector handlers; + { + ArchMutexLock lock(m_mutex); + HandlerTable::iterator index = m_handlers.find(target); + if (index != m_handlers.end()) { + // copy to handlers array and clear table for target + TypeHandlerTable &typeHandlers = index->second; + for (TypeHandlerTable::iterator index2 = typeHandlers.begin(); + index2 != typeHandlers.end(); ++index2) { + handlers.push_back(index2->second); + } + typeHandlers.clear(); } + } + + // delete handlers + for (std::vector::iterator index = handlers.begin(); + index != handlers.end(); ++index) { + delete *index; + } +} + +bool EventQueue::isEmpty() const { + return (m_buffer->isEmpty() && getNextTimerTimeout() != 0.0); +} + +IEventJob *EventQueue::getHandler(Event::Type type, void *target) const { + ArchMutexLock lock(m_mutex); + HandlerTable::const_iterator index = m_handlers.find(target); + if (index != m_handlers.end()) { + const TypeHandlerTable &typeHandlers = index->second; + TypeHandlerTable::const_iterator index2 = typeHandlers.find(type); + if (index2 != typeHandlers.end()) { + return index2->second; + } + } + return NULL; +} + +UInt32 EventQueue::saveEvent(const Event &event) { + // choose id + UInt32 id; + if (!m_oldEventIDs.empty()) { + // reuse an id + id = m_oldEventIDs.back(); + m_oldEventIDs.pop_back(); + } else { + // make a new id + id = static_cast(m_events.size()); + } + + // save data + m_events[id] = event; + return id; +} + +Event EventQueue::removeEvent(UInt32 eventID) { + // look up id + EventTable::iterator index = m_events.find(eventID); + if (index == m_events.end()) { + return Event(); + } + + // get data + Event event = index->second; + m_events.erase(index); + + // save old id for reuse + m_oldEventIDs.push_back(eventID); + + return event; +} + +bool EventQueue::hasTimerExpired(Event &event) { + // return true if there's a timer in the timer priority queue that + // has expired. if returning true then fill in event appropriately + // and reset and reinsert the timer. + if (m_timerQueue.empty()) { + return false; + } + + // get time elapsed since last check + const double time = m_time.getTime(); + m_time.reset(); + + // countdown elapsed time + for (TimerQueue::iterator index = m_timerQueue.begin(); + index != m_timerQueue.end(); ++index) { + (*index) -= time; + } + + // done if no timers are expired + if (m_timerQueue.top() > 0.0) { + return false; + } + + // remove timer from queue + Timer timer = m_timerQueue.top(); + m_timerQueue.pop(); + + // prepare event and reset the timer's clock + timer.fillEvent(m_timerEvent); + event = Event(Event::kTimer, timer.getTarget(), &m_timerEvent); + timer.reset(); + + // reinsert timer into queue if it's not a one-shot + if (!timer.isOneShot()) { + m_timerQueue.push(timer); + } + + return true; +} + +double EventQueue::getNextTimerTimeout() const { + // return -1 if no timers, 0 if the top timer has expired, otherwise + // the time until the top timer in the timer priority queue will + // expire. + if (m_timerQueue.empty()) { + return -1.0; + } + if (m_timerQueue.top() <= 0.0) { + return 0.0; + } + return m_timerQueue.top(); +} + +Event::Type EventQueue::getRegisteredType(const String &name) const { + NameMap::const_iterator found = m_nameMap.find(name); + if (found != m_nameMap.end()) + return found->second; + + return Event::kUnknown; +} + +void *EventQueue::getSystemTarget() { + // any unique arbitrary pointer will do + return &m_systemTarget; +} + +void EventQueue::waitForReady() const { + double timeout = ARCH->time() + 10; + Lock lock(m_readyMutex); + + while (!m_readyCondVar->wait()) { + if (ARCH->time() > timeout) { + throw std::runtime_error("event queue is not ready within 5 sec"); + } + } } // // EventQueue::Timer // -EventQueue::Timer::Timer(EventQueueTimer* timer, double timeout, - double initialTime, void* target, bool oneShot) : - m_timer(timer), - m_timeout(timeout), - m_target(target), - m_oneShot(oneShot), - m_time(initialTime) -{ - assert(m_timeout > 0.0); +EventQueue::Timer::Timer(EventQueueTimer *timer, double timeout, + double initialTime, void *target, bool oneShot) + : m_timer(timer), m_timeout(timeout), m_target(target), m_oneShot(oneShot), + m_time(initialTime) { + assert(m_timeout > 0.0); } -EventQueue::Timer::~Timer() -{ - // do nothing +EventQueue::Timer::~Timer() { + // do nothing } -void -EventQueue::Timer::reset() -{ - m_time = m_timeout; +void EventQueue::Timer::reset() { m_time = m_timeout; } + +EventQueue::Timer &EventQueue::Timer::operator-=(double dt) { + m_time -= dt; + return *this; } -EventQueue::Timer& -EventQueue::Timer::operator-=(double dt) -{ - m_time -= dt; - return *this; +EventQueue::Timer::operator double() const { return m_time; } + +bool EventQueue::Timer::isOneShot() const { return m_oneShot; } + +EventQueueTimer *EventQueue::Timer::getTimer() const { return m_timer; } + +void *EventQueue::Timer::getTarget() const { return m_target; } + +void EventQueue::Timer::fillEvent(TimerEvent &event) const { + event.m_timer = m_timer; + event.m_count = 0; + if (m_time <= 0.0) { + event.m_count = static_cast((m_timeout - m_time) / m_timeout); + } } -EventQueue::Timer::operator double() const -{ - return m_time; -} - -bool -EventQueue::Timer::isOneShot() const -{ - return m_oneShot; -} - -EventQueueTimer* -EventQueue::Timer::getTimer() const -{ - return m_timer; -} - -void* -EventQueue::Timer::getTarget() const -{ - return m_target; -} - -void -EventQueue::Timer::fillEvent(TimerEvent& event) const -{ - event.m_timer = m_timer; - event.m_count = 0; - if (m_time <= 0.0) { - event.m_count = static_cast((m_timeout - m_time) / m_timeout); - } -} - -bool -EventQueue::Timer::operator<(const Timer& t) const -{ - return m_time < t.m_time; +bool EventQueue::Timer::operator<(const Timer &t) const { + return m_time < t.m_time; } diff --git a/src/lib/base/EventQueue.h b/src/lib/base/EventQueue.h index cfb72ef86..853512b5b 100644 --- a/src/lib/base/EventQueue.h +++ b/src/lib/base/EventQueue.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 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 LICENSE 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 @@ -18,14 +18,14 @@ #pragma once -#include "mt/CondVar.h" #include "arch/IArchMultithread.h" -#include "base/IEventQueue.h" #include "base/Event.h" +#include "base/IEventQueue.h" #include "base/PriorityQueue.h" #include "base/Stopwatch.h" #include "common/stdmap.h" #include "common/stdset.h" +#include "mt/CondVar.h" #include @@ -38,164 +38,158 @@ delegates the platform dependent parts to a subclass. */ class EventQueue : public IEventQueue { public: - EventQueue(); - EventQueue(EventQueue const &) =delete; - EventQueue(EventQueue &&) =delete; - virtual ~EventQueue(); - EventQueue& operator=(EventQueue const &) =delete; - EventQueue& operator=(EventQueue &&) =delete; + EventQueue(); + EventQueue(EventQueue const &) = delete; + EventQueue(EventQueue &&) = delete; + virtual ~EventQueue(); + EventQueue &operator=(EventQueue const &) = delete; + EventQueue &operator=(EventQueue &&) = delete; - // IEventQueue overrides - virtual void loop(); - virtual void adoptBuffer(IEventQueueBuffer*); - virtual bool getEvent(Event& event, double timeout = -1.0); - virtual bool dispatchEvent(const Event& event); - virtual void addEvent(const Event& event); - virtual EventQueueTimer* - newTimer(double duration, void* target); - virtual EventQueueTimer* - newOneShotTimer(double duration, void* target); - virtual void deleteTimer(EventQueueTimer*); - virtual void adoptHandler(Event::Type type, - void* target, IEventJob* handler); - virtual void removeHandler(Event::Type type, void* target); - virtual void removeHandlers(void* target); - virtual Event::Type - registerTypeOnce(Event::Type& type, const char* name); - virtual bool isEmpty() const; - virtual IEventJob* getHandler(Event::Type type, void* target) const; - virtual const char* getTypeName(Event::Type type); - virtual Event::Type - getRegisteredType(const String& name) const; - void* getSystemTarget(); - virtual void waitForReady() const; + // IEventQueue overrides + virtual void loop(); + virtual void adoptBuffer(IEventQueueBuffer *); + virtual bool getEvent(Event &event, double timeout = -1.0); + virtual bool dispatchEvent(const Event &event); + virtual void addEvent(const Event &event); + virtual EventQueueTimer *newTimer(double duration, void *target); + virtual EventQueueTimer *newOneShotTimer(double duration, void *target); + virtual void deleteTimer(EventQueueTimer *); + virtual void adoptHandler(Event::Type type, void *target, IEventJob *handler); + virtual void removeHandler(Event::Type type, void *target); + virtual void removeHandlers(void *target); + virtual Event::Type registerTypeOnce(Event::Type &type, const char *name); + virtual bool isEmpty() const; + virtual IEventJob *getHandler(Event::Type type, void *target) const; + virtual const char *getTypeName(Event::Type type); + virtual Event::Type getRegisteredType(const String &name) const; + void *getSystemTarget(); + virtual void waitForReady() const; private: - UInt32 saveEvent(const Event& event); - Event removeEvent(UInt32 eventID); - bool hasTimerExpired(Event& event); - double getNextTimerTimeout() const; - void addEventToBuffer(const Event& event); - + UInt32 saveEvent(const Event &event); + Event removeEvent(UInt32 eventID); + bool hasTimerExpired(Event &event); + double getNextTimerTimeout() const; + void addEventToBuffer(const Event &event); + private: - class Timer { - public: - Timer(EventQueueTimer*, double timeout, double initialTime, - void* target, bool oneShot); - ~Timer(); + class Timer { + public: + Timer(EventQueueTimer *, double timeout, double initialTime, void *target, + bool oneShot); + ~Timer(); - void reset(); + void reset(); - Timer& operator-=(double); + Timer &operator-=(double); - operator double() const; + operator double() const; - bool isOneShot() const; - EventQueueTimer* - getTimer() const; - void* getTarget() const; - void fillEvent(TimerEvent&) const; + bool isOneShot() const; + EventQueueTimer *getTimer() const; + void *getTarget() const; + void fillEvent(TimerEvent &) const; - bool operator<(const Timer&) const; + bool operator<(const Timer &) const; - private: - EventQueueTimer* m_timer; - double m_timeout; - void* m_target; - bool m_oneShot; - double m_time; - }; + private: + EventQueueTimer *m_timer; + double m_timeout; + void *m_target; + bool m_oneShot; + double m_time; + }; - typedef std::set Timers; - typedef PriorityQueue TimerQueue; - typedef std::map EventTable; - typedef std::vector EventIDList; - typedef std::map TypeMap; - typedef std::map NameMap; - typedef std::map TypeHandlerTable; - typedef std::map HandlerTable; + typedef std::set Timers; + typedef PriorityQueue TimerQueue; + typedef std::map EventTable; + typedef std::vector EventIDList; + typedef std::map TypeMap; + typedef std::map NameMap; + typedef std::map TypeHandlerTable; + typedef std::map HandlerTable; - int m_systemTarget; - ArchMutex m_mutex; + int m_systemTarget; + ArchMutex m_mutex; - // registered events - Event::Type m_nextType; - TypeMap m_typeMap; - NameMap m_nameMap; + // registered events + Event::Type m_nextType; + TypeMap m_typeMap; + NameMap m_nameMap; - // buffer of events - IEventQueueBuffer* m_buffer; + // buffer of events + IEventQueueBuffer *m_buffer; - // saved events - EventTable m_events; - EventIDList m_oldEventIDs; + // saved events + EventTable m_events; + EventIDList m_oldEventIDs; - // timers - Stopwatch m_time; - Timers m_timers; - TimerQueue m_timerQueue; - TimerEvent m_timerEvent; + // timers + Stopwatch m_time; + Timers m_timers; + TimerQueue m_timerQueue; + TimerEvent m_timerEvent; - // event handlers - HandlerTable m_handlers; + // event handlers + HandlerTable m_handlers; public: - // - // Event type providers. - // - ClientEvents& forClient(); - IStreamEvents& forIStream(); - IpcClientEvents& forIpcClient(); - IpcClientProxyEvents& forIpcClientProxy(); - IpcServerEvents& forIpcServer(); - IpcServerProxyEvents& forIpcServerProxy(); - IDataSocketEvents& forIDataSocket(); - IListenSocketEvents& forIListenSocket(); - ISocketEvents& forISocket(); - OSXScreenEvents& forOSXScreen(); - ClientListenerEvents& forClientListener(); - ClientProxyEvents& forClientProxy(); - ClientProxyUnknownEvents& forClientProxyUnknown(); - ServerEvents& forServer(); - ServerAppEvents& forServerApp(); - IKeyStateEvents& forIKeyState(); - IPrimaryScreenEvents& forIPrimaryScreen(); - IScreenEvents& forIScreen(); - ClipboardEvents& forClipboard(); - FileEvents& forFile(); + // + // Event type providers. + // + ClientEvents &forClient(); + IStreamEvents &forIStream(); + IpcClientEvents &forIpcClient(); + IpcClientProxyEvents &forIpcClientProxy(); + IpcServerEvents &forIpcServer(); + IpcServerProxyEvents &forIpcServerProxy(); + IDataSocketEvents &forIDataSocket(); + IListenSocketEvents &forIListenSocket(); + ISocketEvents &forISocket(); + OSXScreenEvents &forOSXScreen(); + ClientListenerEvents &forClientListener(); + ClientProxyEvents &forClientProxy(); + ClientProxyUnknownEvents &forClientProxyUnknown(); + ServerEvents &forServer(); + ServerAppEvents &forServerApp(); + IKeyStateEvents &forIKeyState(); + IPrimaryScreenEvents &forIPrimaryScreen(); + IScreenEvents &forIScreen(); + ClipboardEvents &forClipboard(); + FileEvents &forFile(); private: - ClientEvents* m_typesForClient; - IStreamEvents* m_typesForIStream; - IpcClientEvents* m_typesForIpcClient; - IpcClientProxyEvents* m_typesForIpcClientProxy; - IpcServerEvents* m_typesForIpcServer; - IpcServerProxyEvents* m_typesForIpcServerProxy; - IDataSocketEvents* m_typesForIDataSocket; - IListenSocketEvents* m_typesForIListenSocket; - ISocketEvents* m_typesForISocket; - OSXScreenEvents* m_typesForOSXScreen; - ClientListenerEvents* m_typesForClientListener; - ClientProxyEvents* m_typesForClientProxy; - ClientProxyUnknownEvents* m_typesForClientProxyUnknown; - ServerEvents* m_typesForServer; - ServerAppEvents* m_typesForServerApp; - IKeyStateEvents* m_typesForIKeyState; - IPrimaryScreenEvents* m_typesForIPrimaryScreen; - IScreenEvents* m_typesForIScreen; - ClipboardEvents* m_typesForClipboard; - FileEvents* m_typesForFile; - Mutex* m_readyMutex; - CondVar* m_readyCondVar; - std::queue m_pending; + ClientEvents *m_typesForClient; + IStreamEvents *m_typesForIStream; + IpcClientEvents *m_typesForIpcClient; + IpcClientProxyEvents *m_typesForIpcClientProxy; + IpcServerEvents *m_typesForIpcServer; + IpcServerProxyEvents *m_typesForIpcServerProxy; + IDataSocketEvents *m_typesForIDataSocket; + IListenSocketEvents *m_typesForIListenSocket; + ISocketEvents *m_typesForISocket; + OSXScreenEvents *m_typesForOSXScreen; + ClientListenerEvents *m_typesForClientListener; + ClientProxyEvents *m_typesForClientProxy; + ClientProxyUnknownEvents *m_typesForClientProxyUnknown; + ServerEvents *m_typesForServer; + ServerAppEvents *m_typesForServerApp; + IKeyStateEvents *m_typesForIKeyState; + IPrimaryScreenEvents *m_typesForIPrimaryScreen; + IScreenEvents *m_typesForIScreen; + ClipboardEvents *m_typesForClipboard; + FileEvents *m_typesForFile; + Mutex *m_readyMutex; + CondVar *m_readyCondVar; + std::queue m_pending; }; -#define EVENT_TYPE_ACCESSOR(type_) \ +#define EVENT_TYPE_ACCESSOR(type_) \ type_##Events& \ -EventQueue::for##type_() { \ - if (m_typesFor##type_ == NULL) { \ - m_typesFor##type_ = new type_##Events(); \ - m_typesFor##type_->setEvents(dynamic_cast(this)); \ - } \ - return *m_typesFor##type_; \ -} +EventQueue::for##type_() { \ + if (m_typesFor##type_ == NULL) { \ + m_typesFor##type_ = new type_##Events(); \ + m_typesFor##type_->setEvents(dynamic_cast(this)); \ + } \ + return *m_typesFor##type_; \ + } diff --git a/src/lib/base/EventTypes.cpp b/src/lib/base/EventTypes.cpp index 7551939c8..34e8ccba6 100644 --- a/src/lib/base/EventTypes.cpp +++ b/src/lib/base/EventTypes.cpp @@ -1,11 +1,11 @@ /* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2013-2016 Symless Ltd. - * + * * 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 LICENSE 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 @@ -21,23 +21,14 @@ #include #include -EventTypes::EventTypes() : - m_events(NULL) -{ +EventTypes::EventTypes() : m_events(NULL) {} + +IEventQueue *EventTypes::getEvents() const { + assert(m_events != NULL); + return m_events; } -IEventQueue* -EventTypes::getEvents() const -{ - assert(m_events != NULL); - return m_events; -} - -void -EventTypes::setEvents(IEventQueue* events) -{ - m_events = events; -} +void EventTypes::setEvents(IEventQueue *events) { m_events = events; } // // Client diff --git a/src/lib/base/EventTypes.h b/src/lib/base/EventTypes.h index e9de70164..36c0d9491 100644 --- a/src/lib/base/EventTypes.h +++ b/src/lib/base/EventTypes.h @@ -1,11 +1,11 @@ /* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2013-2016 Symless Ltd. - * + * * 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 LICENSE 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 @@ -23,735 +23,710 @@ class IEventQueue; class EventTypes { public: - EventTypes(); - void setEvents(IEventQueue* events); + EventTypes(); + void setEvents(IEventQueue *events); protected: - IEventQueue* getEvents() const; + IEventQueue *getEvents() const; private: - IEventQueue* m_events; + IEventQueue *m_events; }; -#define REGISTER_EVENT(type_, name_) \ -Event::Type \ -type_##Events::name_() \ -{ \ - return getEvents()->registerTypeOnce(m_##name_, __FUNCTION__); \ -} +#define REGISTER_EVENT(type_, name_) \ + Event::Type type_##Events::name_() { \ + return getEvents()->registerTypeOnce(m_##name_, __FUNCTION__); \ + } class ClientEvents : public EventTypes { public: - //! @name accessors - //@{ + //! @name accessors + //@{ - //! Get connected event type - /*! - Returns the connected event type. This is sent when the client has - successfully connected to the server. - */ - Event::Type connected(); + //! Get connected event type + /*! + Returns the connected event type. This is sent when the client has + successfully connected to the server. + */ + Event::Type connected(); - //! Get connection failed event type - /*! - Returns the connection failed event type. This is sent when the - server fails for some reason. The event data is a FailInfo*. - */ - Event::Type connectionFailed(); + //! Get connection failed event type + /*! + Returns the connection failed event type. This is sent when the + server fails for some reason. The event data is a FailInfo*. + */ + Event::Type connectionFailed(); - //! Get connection refused event type - /*! - Returns the connection refused event type. This is sent when the - server refuses for some reason. The event data is a FailInfo*. - */ - Event::Type connectionRefused(); + //! Get connection refused event type + /*! + Returns the connection refused event type. This is sent when the + server refuses for some reason. The event data is a FailInfo*. + */ + Event::Type connectionRefused(); - //! Get disconnected event type - /*! - Returns the disconnected event type. This is sent when the client - has disconnected from the server (and only after having successfully - connected). - */ - Event::Type disconnected(); + //! Get disconnected event type + /*! + Returns the disconnected event type. This is sent when the client + has disconnected from the server (and only after having successfully + connected). + */ + Event::Type disconnected(); - //@} + //@} private: - Event::Type m_connected = Event::kUnknown; - Event::Type m_connectionFailed = Event::kUnknown; - Event::Type m_connectionRefused = Event::kUnknown; - Event::Type m_disconnected = Event::kUnknown; + Event::Type m_connected = Event::kUnknown; + Event::Type m_connectionFailed = Event::kUnknown; + Event::Type m_connectionRefused = Event::kUnknown; + Event::Type m_disconnected = Event::kUnknown; }; class IStreamEvents : public EventTypes { public: - IStreamEvents() : - m_inputReady(Event::kUnknown), - m_outputFlushed(Event::kUnknown), - m_outputError(Event::kUnknown), - m_inputShutdown(Event::kUnknown), - m_outputShutdown(Event::kUnknown) { } + IStreamEvents() + : m_inputReady(Event::kUnknown), m_outputFlushed(Event::kUnknown), + m_outputError(Event::kUnknown), m_inputShutdown(Event::kUnknown), + m_outputShutdown(Event::kUnknown) {} - //! @name accessors - //@{ + //! @name accessors + //@{ - //! Get input ready event type - /*! - Returns the input ready event type. A stream sends this event - when \c read() will return with data. - */ - Event::Type inputReady(); + //! Get input ready event type + /*! + Returns the input ready event type. A stream sends this event + when \c read() will return with data. + */ + Event::Type inputReady(); - //! Get output flushed event type - /*! - Returns the output flushed event type. A stream sends this event - when the output buffer has been flushed. If there have been no - writes since the event was posted, calling \c shutdownOutput() or - \c close() will not discard any data and \c flush() will return - immediately. - */ - Event::Type outputFlushed(); + //! Get output flushed event type + /*! + Returns the output flushed event type. A stream sends this event + when the output buffer has been flushed. If there have been no + writes since the event was posted, calling \c shutdownOutput() or + \c close() will not discard any data and \c flush() will return + immediately. + */ + Event::Type outputFlushed(); - //! Get output error event type - /*! - Returns the output error event type. A stream sends this event - when a write has failed. - */ - Event::Type outputError(); + //! Get output error event type + /*! + Returns the output error event type. A stream sends this event + when a write has failed. + */ + Event::Type outputError(); - //! Get input shutdown event type - /*! - Returns the input shutdown event type. This is sent when the - input side of the stream has shutdown. When the input has - shutdown, no more data will ever be available to read. - */ - Event::Type inputShutdown(); + //! Get input shutdown event type + /*! + Returns the input shutdown event type. This is sent when the + input side of the stream has shutdown. When the input has + shutdown, no more data will ever be available to read. + */ + Event::Type inputShutdown(); - //! Get output shutdown event type - /*! - Returns the output shutdown event type. This is sent when the - output side of the stream has shutdown. When the output has - shutdown, no more data can ever be written to the stream. Any - attempt to do so will generate a output error event. - */ - Event::Type outputShutdown(); + //! Get output shutdown event type + /*! + Returns the output shutdown event type. This is sent when the + output side of the stream has shutdown. When the output has + shutdown, no more data can ever be written to the stream. Any + attempt to do so will generate a output error event. + */ + Event::Type outputShutdown(); + + //@} - //@} - private: - Event::Type m_inputReady; - Event::Type m_outputFlushed; - Event::Type m_outputError; - Event::Type m_inputShutdown; - Event::Type m_outputShutdown; + Event::Type m_inputReady; + Event::Type m_outputFlushed; + Event::Type m_outputError; + Event::Type m_inputShutdown; + Event::Type m_outputShutdown; }; class IpcClientEvents : public EventTypes { public: - IpcClientEvents() : - m_connected(Event::kUnknown), - m_messageReceived(Event::kUnknown) { } + IpcClientEvents() + : m_connected(Event::kUnknown), m_messageReceived(Event::kUnknown) {} - //! @name accessors - //@{ + //! @name accessors + //@{ - //! Raised when the socket is connected. - Event::Type connected(); + //! Raised when the socket is connected. + Event::Type connected(); - //! Raised when a message is received. - Event::Type messageReceived(); + //! Raised when a message is received. + Event::Type messageReceived(); + + //@} - //@} - private: - Event::Type m_connected; - Event::Type m_messageReceived; + Event::Type m_connected; + Event::Type m_messageReceived; }; class IpcClientProxyEvents : public EventTypes { public: - IpcClientProxyEvents() : - m_messageReceived(Event::kUnknown), - m_disconnected(Event::kUnknown) { } + IpcClientProxyEvents() + : m_messageReceived(Event::kUnknown), m_disconnected(Event::kUnknown) {} - //! @name accessors - //@{ + //! @name accessors + //@{ - //! Raised when the server receives a message from a client. - Event::Type messageReceived(); + //! Raised when the server receives a message from a client. + Event::Type messageReceived(); - //! Raised when the client disconnects from the server. - Event::Type disconnected(); - - //@} + //! Raised when the client disconnects from the server. + Event::Type disconnected(); + + //@} private: - Event::Type m_messageReceived; - Event::Type m_disconnected; + Event::Type m_messageReceived; + Event::Type m_disconnected; }; class IpcServerEvents : public EventTypes { public: - IpcServerEvents() : - m_clientConnected(Event::kUnknown), - m_messageReceived(Event::kUnknown) { } + IpcServerEvents() + : m_clientConnected(Event::kUnknown), m_messageReceived(Event::kUnknown) { + } - //! @name accessors - //@{ + //! @name accessors + //@{ - //! Raised when we have created the client proxy. - Event::Type clientConnected(); - - //! Raised when a message is received through a client proxy. - Event::Type messageReceived(); + //! Raised when we have created the client proxy. + Event::Type clientConnected(); - //@} + //! Raised when a message is received through a client proxy. + Event::Type messageReceived(); + + //@} private: - Event::Type m_clientConnected; - Event::Type m_messageReceived; + Event::Type m_clientConnected; + Event::Type m_messageReceived; }; class IpcServerProxyEvents : public EventTypes { public: - IpcServerProxyEvents() : - m_messageReceived(Event::kUnknown) { } + IpcServerProxyEvents() : m_messageReceived(Event::kUnknown) {} - //! @name accessors - //@{ + //! @name accessors + //@{ - //! Raised when the client receives a message from the server. - Event::Type messageReceived(); + //! Raised when the client receives a message from the server. + Event::Type messageReceived(); - //@} + //@} private: - Event::Type m_messageReceived; + Event::Type m_messageReceived; }; class IDataSocketEvents : public EventTypes { public: - IDataSocketEvents() : - m_connected(Event::kUnknown), - m_secureConnected(Event::kUnknown), - m_connectionFailed(Event::kUnknown) { } + IDataSocketEvents() + : m_connected(Event::kUnknown), m_secureConnected(Event::kUnknown), + m_connectionFailed(Event::kUnknown) {} - //! @name accessors - //@{ + //! @name accessors + //@{ - //! Get connected event type - /*! - Returns the socket connected event type. A socket sends this - event when a remote connection has been established. - */ - Event::Type connected(); - - //! Get secure connected event type - /*! - Returns the secure socket connected event type. A secure socket sends - this event when a remote connection has been established. - */ - Event::Type secureConnected(); + //! Get connected event type + /*! + Returns the socket connected event type. A socket sends this + event when a remote connection has been established. + */ + Event::Type connected(); - //! Get connection failed event type - /*! - Returns the socket connection failed event type. A socket sends - this event when an attempt to connect to a remote port has failed. - The data is a pointer to a ConnectionFailedInfo. - */ - Event::Type connectionFailed(); + //! Get secure connected event type + /*! + Returns the secure socket connected event type. A secure socket sends + this event when a remote connection has been established. + */ + Event::Type secureConnected(); - //@} + //! Get connection failed event type + /*! + Returns the socket connection failed event type. A socket sends + this event when an attempt to connect to a remote port has failed. + The data is a pointer to a ConnectionFailedInfo. + */ + Event::Type connectionFailed(); + + //@} private: - Event::Type m_connected; - Event::Type m_secureConnected; - Event::Type m_connectionFailed; + Event::Type m_connected; + Event::Type m_secureConnected; + Event::Type m_connectionFailed; }; class IListenSocketEvents : public EventTypes { public: - IListenSocketEvents() : - m_connecting(Event::kUnknown) { } + IListenSocketEvents() : m_connecting(Event::kUnknown) {} - //! @name accessors - //@{ + //! @name accessors + //@{ - //! Get connecting event type - /*! - Returns the socket connecting event type. A socket sends this - event when a remote connection is waiting to be accepted. - */ - Event::Type connecting(); + //! Get connecting event type + /*! + Returns the socket connecting event type. A socket sends this + event when a remote connection is waiting to be accepted. + */ + Event::Type connecting(); - //@} + //@} private: - Event::Type m_connecting; + Event::Type m_connecting; }; class ISocketEvents : public EventTypes { public: - ISocketEvents() : - m_disconnected(Event::kUnknown), - m_stopRetry(Event::kUnknown) { } + ISocketEvents() + : m_disconnected(Event::kUnknown), m_stopRetry(Event::kUnknown) {} - //! @name accessors - //@{ + //! @name accessors + //@{ - //! Get disconnected event type - /*! - Returns the socket disconnected event type. A socket sends this - event when the remote side of the socket has disconnected or - shutdown both input and output. - */ - Event::Type disconnected(); + //! Get disconnected event type + /*! + Returns the socket disconnected event type. A socket sends this + event when the remote side of the socket has disconnected or + shutdown both input and output. + */ + Event::Type disconnected(); - //! Get stop retry event type - /*! - Returns the stop retry event type. This is sent when the client - doesn't want to reconnect after it disconnects from the server. - */ - Event::Type stopRetry(); + //! Get stop retry event type + /*! + Returns the stop retry event type. This is sent when the client + doesn't want to reconnect after it disconnects from the server. + */ + Event::Type stopRetry(); - //@} + //@} private: - Event::Type m_disconnected; - Event::Type m_stopRetry; + Event::Type m_disconnected; + Event::Type m_stopRetry; }; class OSXScreenEvents : public EventTypes { public: - OSXScreenEvents() : - m_confirmSleep(Event::kUnknown) { } + OSXScreenEvents() : m_confirmSleep(Event::kUnknown) {} - //! @name accessors - //@{ + //! @name accessors + //@{ - Event::Type confirmSleep(); + Event::Type confirmSleep(); - //@} + //@} private: - Event::Type m_confirmSleep; + Event::Type m_confirmSleep; }; class ClientListenerEvents : public EventTypes { public: - ClientListenerEvents() : - m_accepted(Event::kUnknown), - m_connected(Event::kUnknown) { } + ClientListenerEvents() + : m_accepted(Event::kUnknown), m_connected(Event::kUnknown) {} - //! @name accessors - //@{ - - //! Get accepted event type - /*! - Returns the accepted event type. This is sent whenever a server - accepts a client. - */ - Event::Type accepted(); - - //! Get connected event type - /*! - Returns the connected event type. This is sent whenever a - a client connects. - */ - Event::Type connected(); + //! @name accessors + //@{ - //@} + //! Get accepted event type + /*! + Returns the accepted event type. This is sent whenever a server + accepts a client. + */ + Event::Type accepted(); + + //! Get connected event type + /*! + Returns the connected event type. This is sent whenever a + a client connects. + */ + Event::Type connected(); + + //@} private: - Event::Type m_accepted; - Event::Type m_connected; + Event::Type m_accepted; + Event::Type m_connected; }; class ClientProxyEvents : public EventTypes { public: - ClientProxyEvents() : - m_ready(Event::kUnknown), - m_disconnected(Event::kUnknown) { } + ClientProxyEvents() + : m_ready(Event::kUnknown), m_disconnected(Event::kUnknown) {} - //! @name accessors - //@{ + //! @name accessors + //@{ - //! Get ready event type - /*! - Returns the ready event type. This is sent when the client has - completed the initial handshake. Until it is sent, the client is - not fully connected. - */ - Event::Type ready(); + //! Get ready event type + /*! + Returns the ready event type. This is sent when the client has + completed the initial handshake. Until it is sent, the client is + not fully connected. + */ + Event::Type ready(); - //! Get disconnect event type - /*! - Returns the disconnect event type. This is sent when the client - disconnects or is disconnected. The target is getEventTarget(). - */ - Event::Type disconnected(); + //! Get disconnect event type + /*! + Returns the disconnect event type. This is sent when the client + disconnects or is disconnected. The target is getEventTarget(). + */ + Event::Type disconnected(); - //@} + //@} private: - Event::Type m_ready; - Event::Type m_disconnected; + Event::Type m_ready; + Event::Type m_disconnected; }; class ClientProxyUnknownEvents : public EventTypes { public: - ClientProxyUnknownEvents() : - m_success(Event::kUnknown), - m_failure(Event::kUnknown) { } + ClientProxyUnknownEvents() + : m_success(Event::kUnknown), m_failure(Event::kUnknown) {} - //! @name accessors - //@{ + //! @name accessors + //@{ - //! Get success event type - /*! - Returns the success event type. This is sent when the client has - correctly responded to the hello message. The target is this. - */ - Event::Type success(); + //! Get success event type + /*! + Returns the success event type. This is sent when the client has + correctly responded to the hello message. The target is this. + */ + Event::Type success(); - //! Get failure event type - /*! - Returns the failure event type. This is sent when a client fails - to correctly respond to the hello message. The target is this. - */ - Event::Type failure(); + //! Get failure event type + /*! + Returns the failure event type. This is sent when a client fails + to correctly respond to the hello message. The target is this. + */ + Event::Type failure(); + + //@} - //@} - private: - Event::Type m_success; - Event::Type m_failure; + Event::Type m_success; + Event::Type m_failure; }; class ServerEvents : public EventTypes { public: - ServerEvents() : - m_error(Event::kUnknown), - m_connected(Event::kUnknown), - m_disconnected(Event::kUnknown), - m_switchToScreen(Event::kUnknown), + ServerEvents() + : m_error(Event::kUnknown), m_connected(Event::kUnknown), + m_disconnected(Event::kUnknown), m_switchToScreen(Event::kUnknown), m_switchInDirection(Event::kUnknown), m_keyboardBroadcast(Event::kUnknown), m_lockCursorToScreen(Event::kUnknown), - m_screenSwitched(Event::kUnknown) { } + m_screenSwitched(Event::kUnknown) {} - //! @name accessors - //@{ + //! @name accessors + //@{ - //! Get error event type - /*! - Returns the error event type. This is sent when the server fails - for some reason. - */ - Event::Type error(); + //! Get error event type + /*! + Returns the error event type. This is sent when the server fails + for some reason. + */ + Event::Type error(); - //! Get connected event type - /*! - Returns the connected event type. This is sent when a client screen - has connected. The event data is a \c ScreenConnectedInfo* that - indicates the connected screen. - */ - Event::Type connected(); + //! Get connected event type + /*! + Returns the connected event type. This is sent when a client screen + has connected. The event data is a \c ScreenConnectedInfo* that + indicates the connected screen. + */ + Event::Type connected(); - //! Get disconnected event type - /*! - Returns the disconnected event type. This is sent when all the - clients have disconnected. - */ - Event::Type disconnected(); + //! Get disconnected event type + /*! + Returns the disconnected event type. This is sent when all the + clients have disconnected. + */ + Event::Type disconnected(); - //! Get switch to screen event type - /*! - Returns the switch to screen event type. The server responds to this - by switching screens. The event data is a \c SwitchToScreenInfo* - that indicates the target screen. - */ - Event::Type switchToScreen(); + //! Get switch to screen event type + /*! + Returns the switch to screen event type. The server responds to this + by switching screens. The event data is a \c SwitchToScreenInfo* + that indicates the target screen. + */ + Event::Type switchToScreen(); - //! Get switch in direction event type - /*! - Returns the switch in direction event type. The server responds to this - by switching screens. The event data is a \c SwitchInDirectionInfo* - that indicates the target direction. - */ - Event::Type switchInDirection(); + //! Get switch in direction event type + /*! + Returns the switch in direction event type. The server responds to this + by switching screens. The event data is a \c SwitchInDirectionInfo* + that indicates the target direction. + */ + Event::Type switchInDirection(); - //! Get keyboard broadcast event type - /*! - Returns the keyboard broadcast event type. The server responds - to this by turning on keyboard broadcasting or turning it off. The - event data is a \c KeyboardBroadcastInfo*. - */ - Event::Type keyboardBroadcast(); + //! Get keyboard broadcast event type + /*! + Returns the keyboard broadcast event type. The server responds + to this by turning on keyboard broadcasting or turning it off. The + event data is a \c KeyboardBroadcastInfo*. + */ + Event::Type keyboardBroadcast(); - //! Get lock cursor event type - /*! - Returns the lock cursor event type. The server responds to this - by locking the cursor to the active screen or unlocking it. The - event data is a \c LockCursorToScreenInfo*. - */ - Event::Type lockCursorToScreen(); + //! Get lock cursor event type + /*! + Returns the lock cursor event type. The server responds to this + by locking the cursor to the active screen or unlocking it. The + event data is a \c LockCursorToScreenInfo*. + */ + Event::Type lockCursorToScreen(); - //! Get screen switched event type - /*! - Returns the screen switched event type. This is raised when the - screen has been switched to a client. - */ - Event::Type screenSwitched(); + //! Get screen switched event type + /*! + Returns the screen switched event type. This is raised when the + screen has been switched to a client. + */ + Event::Type screenSwitched(); + + //@} - //@} - private: - Event::Type m_error; - Event::Type m_connected; - Event::Type m_disconnected; - Event::Type m_switchToScreen; - Event::Type m_switchInDirection; - Event::Type m_keyboardBroadcast; - Event::Type m_lockCursorToScreen; - Event::Type m_screenSwitched; + Event::Type m_error; + Event::Type m_connected; + Event::Type m_disconnected; + Event::Type m_switchToScreen; + Event::Type m_switchInDirection; + Event::Type m_keyboardBroadcast; + Event::Type m_lockCursorToScreen; + Event::Type m_screenSwitched; }; class ServerAppEvents : public EventTypes { public: - ServerAppEvents() : - m_reloadConfig(Event::kUnknown), - m_forceReconnect(Event::kUnknown), - m_resetServer(Event::kUnknown) { } - - //! @name accessors - //@{ - - Event::Type reloadConfig(); - Event::Type forceReconnect(); - Event::Type resetServer(); + ServerAppEvents() + : m_reloadConfig(Event::kUnknown), m_forceReconnect(Event::kUnknown), + m_resetServer(Event::kUnknown) {} + + //! @name accessors + //@{ + + Event::Type reloadConfig(); + Event::Type forceReconnect(); + Event::Type resetServer(); + + //@} - //@} - private: - Event::Type m_reloadConfig; - Event::Type m_forceReconnect; - Event::Type m_resetServer; + Event::Type m_reloadConfig; + Event::Type m_forceReconnect; + Event::Type m_resetServer; }; class IKeyStateEvents : public EventTypes { public: - IKeyStateEvents() : - m_keyDown(Event::kUnknown), - m_keyUp(Event::kUnknown), - m_keyRepeat(Event::kUnknown) { } + IKeyStateEvents() + : m_keyDown(Event::kUnknown), m_keyUp(Event::kUnknown), + m_keyRepeat(Event::kUnknown) {} - //! @name accessors - //@{ + //! @name accessors + //@{ - //! Get key down event type. Event data is KeyInfo*, count == 1. - Event::Type keyDown(); + //! Get key down event type. Event data is KeyInfo*, count == 1. + Event::Type keyDown(); - //! Get key up event type. Event data is KeyInfo*, count == 1. - Event::Type keyUp(); + //! Get key up event type. Event data is KeyInfo*, count == 1. + Event::Type keyUp(); - //! Get key repeat event type. Event data is KeyInfo*. - Event::Type keyRepeat(); + //! Get key repeat event type. Event data is KeyInfo*. + Event::Type keyRepeat(); + + //@} - //@} - private: - Event::Type m_keyDown; - Event::Type m_keyUp; - Event::Type m_keyRepeat; + Event::Type m_keyDown; + Event::Type m_keyUp; + Event::Type m_keyRepeat; }; class IPrimaryScreenEvents : public EventTypes { public: - IPrimaryScreenEvents() : - m_buttonDown(Event::kUnknown), - m_buttonUp(Event::kUnknown), + IPrimaryScreenEvents() + : m_buttonDown(Event::kUnknown), m_buttonUp(Event::kUnknown), m_motionOnPrimary(Event::kUnknown), - m_motionOnSecondary(Event::kUnknown), - m_wheel(Event::kUnknown), + m_motionOnSecondary(Event::kUnknown), m_wheel(Event::kUnknown), m_screensaverActivated(Event::kUnknown), m_screensaverDeactivated(Event::kUnknown), - m_hotKeyDown(Event::kUnknown), - m_hotKeyUp(Event::kUnknown), - m_fakeInputBegin(Event::kUnknown), - m_fakeInputEnd(Event::kUnknown) { } + m_hotKeyDown(Event::kUnknown), m_hotKeyUp(Event::kUnknown), + m_fakeInputBegin(Event::kUnknown), m_fakeInputEnd(Event::kUnknown) {} - //! @name accessors - //@{ - - //! button down event type. Event data is ButtonInfo*. - Event::Type buttonDown(); + //! @name accessors + //@{ - //! button up event type. Event data is ButtonInfo*. - Event::Type buttonUp(); + //! button down event type. Event data is ButtonInfo*. + Event::Type buttonDown(); - //! mouse motion on the primary screen event type - /*! - Event data is MotionInfo* and the values are an absolute position. - */ - Event::Type motionOnPrimary(); + //! button up event type. Event data is ButtonInfo*. + Event::Type buttonUp(); - //! mouse motion on a secondary screen event type - /*! - Event data is MotionInfo* and the values are motion deltas not - absolute coordinates. - */ - Event::Type motionOnSecondary(); + //! mouse motion on the primary screen event type + /*! + Event data is MotionInfo* and the values are an absolute position. + */ + Event::Type motionOnPrimary(); - //! mouse wheel event type. Event data is WheelInfo*. - Event::Type wheel(); + //! mouse motion on a secondary screen event type + /*! + Event data is MotionInfo* and the values are motion deltas not + absolute coordinates. + */ + Event::Type motionOnSecondary(); - //! screensaver activated event type - Event::Type screensaverActivated(); + //! mouse wheel event type. Event data is WheelInfo*. + Event::Type wheel(); - //! screensaver deactivated event type - Event::Type screensaverDeactivated(); + //! screensaver activated event type + Event::Type screensaverActivated(); - //! hot key down event type. Event data is HotKeyInfo*. - Event::Type hotKeyDown(); + //! screensaver deactivated event type + Event::Type screensaverDeactivated(); - //! hot key up event type. Event data is HotKeyInfo*. - Event::Type hotKeyUp(); + //! hot key down event type. Event data is HotKeyInfo*. + Event::Type hotKeyDown(); - //! start of fake input event type - Event::Type fakeInputBegin(); + //! hot key up event type. Event data is HotKeyInfo*. + Event::Type hotKeyUp(); - //! end of fake input event type - Event::Type fakeInputEnd(); + //! start of fake input event type + Event::Type fakeInputBegin(); - //@} + //! end of fake input event type + Event::Type fakeInputEnd(); + + //@} private: - Event::Type m_buttonDown; - Event::Type m_buttonUp; - Event::Type m_motionOnPrimary; - Event::Type m_motionOnSecondary; - Event::Type m_wheel; - Event::Type m_screensaverActivated; - Event::Type m_screensaverDeactivated; - Event::Type m_hotKeyDown; - Event::Type m_hotKeyUp; - Event::Type m_fakeInputBegin; - Event::Type m_fakeInputEnd; + Event::Type m_buttonDown; + Event::Type m_buttonUp; + Event::Type m_motionOnPrimary; + Event::Type m_motionOnSecondary; + Event::Type m_wheel; + Event::Type m_screensaverActivated; + Event::Type m_screensaverDeactivated; + Event::Type m_hotKeyDown; + Event::Type m_hotKeyUp; + Event::Type m_fakeInputBegin; + Event::Type m_fakeInputEnd; }; class IScreenEvents : public EventTypes { public: - IScreenEvents() : - m_error(Event::kUnknown), - m_shapeChanged(Event::kUnknown), - m_suspend(Event::kUnknown), - m_resume(Event::kUnknown) { } + IScreenEvents() + : m_error(Event::kUnknown), m_shapeChanged(Event::kUnknown), + m_suspend(Event::kUnknown), m_resume(Event::kUnknown) {} - //! @name accessors - //@{ + //! @name accessors + //@{ - //! Get error event type - /*! - Returns the error event type. This is sent whenever the screen has - failed for some reason (e.g. the X Windows server died). - */ - Event::Type error(); + //! Get error event type + /*! + Returns the error event type. This is sent whenever the screen has + failed for some reason (e.g. the X Windows server died). + */ + Event::Type error(); - //! Get shape changed event type - /*! - Returns the shape changed event type. This is sent whenever the - screen's shape changes. - */ - Event::Type shapeChanged(); + //! Get shape changed event type + /*! + Returns the shape changed event type. This is sent whenever the + screen's shape changes. + */ + Event::Type shapeChanged(); - //! Get suspend event type - /*! - Returns the suspend event type. This is sent whenever the system goes - to sleep or a user session is deactivated (fast user switching). - */ - Event::Type suspend(); - - //! Get resume event type - /*! - Returns the resume event type. This is sent whenever the system wakes - up or a user session is activated (fast user switching). - */ - Event::Type resume(); + //! Get suspend event type + /*! + Returns the suspend event type. This is sent whenever the system goes + to sleep or a user session is deactivated (fast user switching). + */ + Event::Type suspend(); + + //! Get resume event type + /*! + Returns the resume event type. This is sent whenever the system wakes + up or a user session is activated (fast user switching). + */ + Event::Type resume(); + + //@} - //@} - private: - Event::Type m_error; - Event::Type m_shapeChanged; - Event::Type m_suspend; - Event::Type m_resume; + Event::Type m_error; + Event::Type m_shapeChanged; + Event::Type m_suspend; + Event::Type m_resume; }; class ClipboardEvents : public EventTypes { public: - ClipboardEvents() : - m_clipboardGrabbed(Event::kUnknown), + ClipboardEvents() + : m_clipboardGrabbed(Event::kUnknown), m_clipboardChanged(Event::kUnknown), - m_clipboardSending(Event::kUnknown) { } + m_clipboardSending(Event::kUnknown) {} - //! @name accessors - //@{ + //! @name accessors + //@{ - //! Get clipboard grabbed event type - /*! - Returns the clipboard grabbed event type. This is sent whenever the - clipboard is grabbed by some other application so we don't own it - anymore. The data is a pointer to a ClipboardInfo. - */ - Event::Type clipboardGrabbed(); + //! Get clipboard grabbed event type + /*! + Returns the clipboard grabbed event type. This is sent whenever the + clipboard is grabbed by some other application so we don't own it + anymore. The data is a pointer to a ClipboardInfo. + */ + Event::Type clipboardGrabbed(); - //! Get clipboard changed event type - /*! - Returns the clipboard changed event type. This is sent whenever the - contents of the clipboard has changed. The data is a pointer to a - IScreen::ClipboardInfo. - */ - Event::Type clipboardChanged(); + //! Get clipboard changed event type + /*! + Returns the clipboard changed event type. This is sent whenever the + contents of the clipboard has changed. The data is a pointer to a + IScreen::ClipboardInfo. + */ + Event::Type clipboardChanged(); - //! Clipboard sending event type - /*! - Returns the clipboard sending event type. This is used to send - clipboard chunks. - */ - Event::Type clipboardSending(); + //! Clipboard sending event type + /*! + Returns the clipboard sending event type. This is used to send + clipboard chunks. + */ + Event::Type clipboardSending(); - //@} + //@} private: - Event::Type m_clipboardGrabbed; - Event::Type m_clipboardChanged; - Event::Type m_clipboardSending; + Event::Type m_clipboardGrabbed; + Event::Type m_clipboardChanged; + Event::Type m_clipboardSending; }; class FileEvents : public EventTypes { public: - FileEvents() : - m_fileChunkSending(Event::kUnknown), - m_fileRecieveCompleted(Event::kUnknown), - m_keepAlive(Event::kUnknown) { } + FileEvents() + : m_fileChunkSending(Event::kUnknown), + m_fileRecieveCompleted(Event::kUnknown), m_keepAlive(Event::kUnknown) {} - //! @name accessors - //@{ + //! @name accessors + //@{ - //! Sending a file chunk - Event::Type fileChunkSending(); + //! Sending a file chunk + Event::Type fileChunkSending(); - //! Completed receiving a file - Event::Type fileRecieveCompleted(); + //! Completed receiving a file + Event::Type fileRecieveCompleted(); - //! Send a keep alive - Event::Type keepAlive(); + //! Send a keep alive + Event::Type keepAlive(); - //@} + //@} private: - Event::Type m_fileChunkSending; - Event::Type m_fileRecieveCompleted; - Event::Type m_keepAlive; + Event::Type m_fileChunkSending; + Event::Type m_fileRecieveCompleted; + Event::Type m_keepAlive; }; diff --git a/src/lib/base/FunctionEventJob.cpp b/src/lib/base/FunctionEventJob.cpp index 88ea35c62..a504c8dc4 100644 --- a/src/lib/base/FunctionEventJob.cpp +++ b/src/lib/base/FunctionEventJob.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 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 LICENSE 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 @@ -22,23 +22,18 @@ // FunctionEventJob // -FunctionEventJob::FunctionEventJob( - void (*func)(const Event&, void*), void* arg) : - m_func(func), - m_arg(arg) -{ - // do nothing +FunctionEventJob::FunctionEventJob(void (*func)(const Event &, void *), + void *arg) + : m_func(func), m_arg(arg) { + // do nothing } -FunctionEventJob::~FunctionEventJob() -{ - // do nothing +FunctionEventJob::~FunctionEventJob() { + // do nothing } -void -FunctionEventJob::run(const Event& event) -{ - if (m_func != NULL) { - m_func(event, m_arg); - } +void FunctionEventJob::run(const Event &event) { + if (m_func != NULL) { + m_func(event, m_arg); + } } diff --git a/src/lib/base/FunctionEventJob.h b/src/lib/base/FunctionEventJob.h index 05f30cabc..232ad680c 100644 --- a/src/lib/base/FunctionEventJob.h +++ b/src/lib/base/FunctionEventJob.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 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 LICENSE 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 @@ -26,14 +26,14 @@ An event job class that invokes a function. */ class FunctionEventJob : public IEventJob { public: - //! run() invokes \c func(arg) - FunctionEventJob(void (*func)(const Event&, void*), void* arg = NULL); - virtual ~FunctionEventJob(); + //! run() invokes \c func(arg) + FunctionEventJob(void (*func)(const Event &, void *), void *arg = NULL); + virtual ~FunctionEventJob(); - // IEventJob overrides - virtual void run(const Event&); + // IEventJob overrides + virtual void run(const Event &); private: - void (*m_func)(const Event&, void*); - void* m_arg; + void (*m_func)(const Event &, void *); + void *m_arg; }; diff --git a/src/lib/base/FunctionJob.cpp b/src/lib/base/FunctionJob.cpp index 10b06c440..b1e6395e2 100644 --- a/src/lib/base/FunctionJob.cpp +++ b/src/lib/base/FunctionJob.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -22,22 +22,17 @@ // FunctionJob // -FunctionJob::FunctionJob(void (*func)(void*), void* arg) : - m_func(func), - m_arg(arg) -{ - // do nothing +FunctionJob::FunctionJob(void (*func)(void *), void *arg) + : m_func(func), m_arg(arg) { + // do nothing } -FunctionJob::~FunctionJob() -{ - // do nothing +FunctionJob::~FunctionJob() { + // do nothing } -void -FunctionJob::run() -{ - if (m_func != NULL) { - m_func(m_arg); - } +void FunctionJob::run() { + if (m_func != NULL) { + m_func(m_arg); + } } diff --git a/src/lib/base/FunctionJob.h b/src/lib/base/FunctionJob.h index 1f8aea97c..79fa6aa90 100644 --- a/src/lib/base/FunctionJob.h +++ b/src/lib/base/FunctionJob.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -26,14 +26,14 @@ A job class that invokes a function. */ class FunctionJob : public IJob { public: - //! run() invokes \c func(arg) - FunctionJob(void (*func)(void*), void* arg = NULL); - virtual ~FunctionJob(); + //! run() invokes \c func(arg) + FunctionJob(void (*func)(void *), void *arg = NULL); + virtual ~FunctionJob(); - // IJob overrides - virtual void run(); + // IJob overrides + virtual void run(); private: - void (*m_func)(void*); - void* m_arg; + void (*m_func)(void *); + void *m_arg; }; diff --git a/src/lib/base/IEventJob.h b/src/lib/base/IEventJob.h index 8d3c5ed31..bafb8c61c 100644 --- a/src/lib/base/IEventJob.h +++ b/src/lib/base/IEventJob.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 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 LICENSE 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 @@ -28,6 +28,6 @@ An event job is an interface for executing a event handler. */ class IEventJob : public IInterface { public: - //! Run the job - virtual void run(const Event&) = 0; + //! Run the job + virtual void run(const Event &) = 0; }; diff --git a/src/lib/base/IEventQueue.h b/src/lib/base/IEventQueue.h index 82b271082..0453bc51b 100644 --- a/src/lib/base/IEventQueue.h +++ b/src/lib/base/IEventQueue.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 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 LICENSE 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 @@ -18,9 +18,9 @@ #pragma once -#include "common/IInterface.h" #include "base/Event.h" #include "base/String.h" +#include "common/IInterface.h" class IEventJob; class IEventQueueBuffer; @@ -60,192 +60,187 @@ timers which generate events periodically. */ class IEventQueue : public IInterface { public: - class TimerEvent { - public: - EventQueueTimer* m_timer; //!< The timer - UInt32 m_count; //!< Number of repeats - }; + class TimerEvent { + public: + EventQueueTimer *m_timer; //!< The timer + UInt32 m_count; //!< Number of repeats + }; - //! @name manipulators - //@{ + //! @name manipulators + //@{ - //! Loop the event queue until quit - /*! - Dequeues and dispatches events until the kQuit event is found. - */ - virtual void loop() = 0; + //! Loop the event queue until quit + /*! + Dequeues and dispatches events until the kQuit event is found. + */ + virtual void loop() = 0; - //! Set the buffer - /*! - Replace the current event queue buffer. Any queued events are - discarded. The queue takes ownership of the buffer. - */ - virtual void adoptBuffer(IEventQueueBuffer*) = 0; + //! Set the buffer + /*! + Replace the current event queue buffer. Any queued events are + discarded. The queue takes ownership of the buffer. + */ + virtual void adoptBuffer(IEventQueueBuffer *) = 0; - //! Remove event from queue - /*! - Returns the next event on the queue into \p event. If no event is - available then blocks for up to \p timeout seconds, or forever if - \p timeout is negative. Returns true iff an event was available. - */ - virtual bool getEvent(Event& event, double timeout = -1.0) = 0; + //! Remove event from queue + /*! + Returns the next event on the queue into \p event. If no event is + available then blocks for up to \p timeout seconds, or forever if + \p timeout is negative. Returns true iff an event was available. + */ + virtual bool getEvent(Event &event, double timeout = -1.0) = 0; - //! Dispatch an event - /*! - Looks up the dispatcher for the event's target and invokes it. - Returns true iff a dispatcher exists for the target. - */ - virtual bool dispatchEvent(const Event& event) = 0; + //! Dispatch an event + /*! + Looks up the dispatcher for the event's target and invokes it. + Returns true iff a dispatcher exists for the target. + */ + virtual bool dispatchEvent(const Event &event) = 0; - //! Add event to queue - /*! - Adds \p event to the end of the queue. - */ - virtual void addEvent(const Event& event) = 0; + //! Add event to queue + /*! + Adds \p event to the end of the queue. + */ + virtual void addEvent(const Event &event) = 0; - //! Create a recurring timer - /*! - Creates and returns a timer. An event is returned after \p duration - seconds and the timer is reset to countdown again. When a timer event - is returned the data points to a \c TimerEvent. The client must pass - the returned timer to \c deleteTimer() (whether or not the timer has - expired) to release the timer. The returned timer event uses the - given \p target. If \p target is NULL it uses the returned timer as - the target. + //! Create a recurring timer + /*! + Creates and returns a timer. An event is returned after \p duration + seconds and the timer is reset to countdown again. When a timer event + is returned the data points to a \c TimerEvent. The client must pass + the returned timer to \c deleteTimer() (whether or not the timer has + expired) to release the timer. The returned timer event uses the + given \p target. If \p target is NULL it uses the returned timer as + the target. - Events for a single timer don't accumulate in the queue, even if the - client reading events can't keep up. Instead, the \c m_count member - of the \c TimerEvent indicates how many events for the timer would - have been put on the queue since the last event for the timer was - removed (or since the timer was added). - */ - virtual EventQueueTimer* - newTimer(double duration, void* target) = 0; + Events for a single timer don't accumulate in the queue, even if the + client reading events can't keep up. Instead, the \c m_count member + of the \c TimerEvent indicates how many events for the timer would + have been put on the queue since the last event for the timer was + removed (or since the timer was added). + */ + virtual EventQueueTimer *newTimer(double duration, void *target) = 0; - //! Create a one-shot timer - /*! - Creates and returns a one-shot timer. An event is returned when - the timer expires and the timer is removed from further handling. - When a timer event is returned the data points to a \c TimerEvent. - The c_count member of the \c TimerEvent is always 1. The client - must pass the returned timer to \c deleteTimer() (whether or not the - timer has expired) to release the timer. The returned timer event - uses the given \p target. If \p target is NULL it uses the returned - timer as the target. - */ - virtual EventQueueTimer* - newOneShotTimer(double duration, - void* target) = 0; + //! Create a one-shot timer + /*! + Creates and returns a one-shot timer. An event is returned when + the timer expires and the timer is removed from further handling. + When a timer event is returned the data points to a \c TimerEvent. + The c_count member of the \c TimerEvent is always 1. The client + must pass the returned timer to \c deleteTimer() (whether or not the + timer has expired) to release the timer. The returned timer event + uses the given \p target. If \p target is NULL it uses the returned + timer as the target. + */ + virtual EventQueueTimer *newOneShotTimer(double duration, void *target) = 0; - //! Destroy a timer - /*! - Destroys a previously created timer. The timer is removed from the - queue and will not generate event, even if the timer has expired. - */ - virtual void deleteTimer(EventQueueTimer*) = 0; + //! Destroy a timer + /*! + Destroys a previously created timer. The timer is removed from the + queue and will not generate event, even if the timer has expired. + */ + virtual void deleteTimer(EventQueueTimer *) = 0; - //! Register an event handler for an event type - /*! - Registers an event handler for \p type and \p target. The \p handler - is adopted. Any existing handler for the type,target pair is deleted. - \c dispatchEvent() will invoke \p handler for any event for \p target - of type \p type. If no such handler exists it will use the handler - for \p target and type \p kUnknown if it exists. - */ - virtual void adoptHandler(Event::Type type, - void* target, IEventJob* handler) = 0; + //! Register an event handler for an event type + /*! + Registers an event handler for \p type and \p target. The \p handler + is adopted. Any existing handler for the type,target pair is deleted. + \c dispatchEvent() will invoke \p handler for any event for \p target + of type \p type. If no such handler exists it will use the handler + for \p target and type \p kUnknown if it exists. + */ + virtual void adoptHandler(Event::Type type, void *target, + IEventJob *handler) = 0; - //! Unregister an event handler for an event type - /*! - Unregisters an event handler for the \p type, \p target pair and - deletes it. - */ - virtual void removeHandler(Event::Type type, void* target) = 0; + //! Unregister an event handler for an event type + /*! + Unregisters an event handler for the \p type, \p target pair and + deletes it. + */ + virtual void removeHandler(Event::Type type, void *target) = 0; - //! Unregister all event handlers for an event target - /*! - Unregisters all event handlers for the \p target and deletes them. - */ - virtual void removeHandlers(void* target) = 0; + //! Unregister all event handlers for an event target + /*! + Unregisters all event handlers for the \p target and deletes them. + */ + virtual void removeHandlers(void *target) = 0; - //! Creates a new event type - /*! - If \p type contains \c kUnknown then it is set to a unique event - type id otherwise it is left alone. The final value of \p type - is returned. - */ - virtual Event::Type - registerTypeOnce(Event::Type& type, - const char* name) = 0; + //! Creates a new event type + /*! + If \p type contains \c kUnknown then it is set to a unique event + type id otherwise it is left alone. The final value of \p type + is returned. + */ + virtual Event::Type registerTypeOnce(Event::Type &type, const char *name) = 0; - //! Wait for event queue to become ready - /*! - Blocks on the current thread until the event queue is ready for events to - be added. - */ - virtual void waitForReady() const = 0; - - //@} - //! @name accessors - //@{ + //! Wait for event queue to become ready + /*! + Blocks on the current thread until the event queue is ready for events to + be added. + */ + virtual void waitForReady() const = 0; - //! Test if queue is empty - /*! - Returns true iff the queue has no events in it, including timer - events. - */ - virtual bool isEmpty() const = 0; + //@} + //! @name accessors + //@{ - //! Get an event handler - /*! - Finds and returns the event handler for the \p type, \p target pair - if it exists, otherwise it returns NULL. - */ - virtual IEventJob* getHandler(Event::Type type, void* target) const = 0; + //! Test if queue is empty + /*! + Returns true iff the queue has no events in it, including timer + events. + */ + virtual bool isEmpty() const = 0; - //! Get name for event - /*! - Returns the name for the event \p type. This is primarily for - debugging. - */ - virtual const char* getTypeName(Event::Type type) = 0; + //! Get an event handler + /*! + Finds and returns the event handler for the \p type, \p target pair + if it exists, otherwise it returns NULL. + */ + virtual IEventJob *getHandler(Event::Type type, void *target) const = 0; - //! Get an event type by name - /*! - Returns the registered type for an event for a given name. - */ - virtual Event::Type getRegisteredType(const String& name) const = 0; + //! Get name for event + /*! + Returns the name for the event \p type. This is primarily for + debugging. + */ + virtual const char *getTypeName(Event::Type type) = 0; - //! Get the system event type target - /*! - Returns the target to use for dispatching \c Event::kSystem events. - */ - virtual void* getSystemTarget() = 0; + //! Get an event type by name + /*! + Returns the registered type for an event for a given name. + */ + virtual Event::Type getRegisteredType(const String &name) const = 0; - //@} - - // - // Event type providers. - // + //! Get the system event type target + /*! + Returns the target to use for dispatching \c Event::kSystem events. + */ + virtual void *getSystemTarget() = 0; - virtual ClientEvents& forClient() = 0; - virtual IStreamEvents& forIStream() = 0; - virtual IpcClientEvents& forIpcClient() = 0; - virtual IpcClientProxyEvents& forIpcClientProxy() = 0; - virtual IpcServerEvents& forIpcServer() = 0; - virtual IpcServerProxyEvents& forIpcServerProxy() = 0; - virtual IDataSocketEvents& forIDataSocket() = 0; - virtual IListenSocketEvents& forIListenSocket() = 0; - virtual ISocketEvents& forISocket() = 0; - virtual OSXScreenEvents& forOSXScreen() = 0; - virtual ClientListenerEvents& forClientListener() = 0; - virtual ClientProxyEvents& forClientProxy() = 0; - virtual ClientProxyUnknownEvents& forClientProxyUnknown() = 0; - virtual ServerEvents& forServer() = 0; - virtual ServerAppEvents& forServerApp() = 0; - virtual IKeyStateEvents& forIKeyState() = 0; - virtual IPrimaryScreenEvents& forIPrimaryScreen() = 0; - virtual IScreenEvents& forIScreen() = 0; - virtual ClipboardEvents& forClipboard() = 0; - virtual FileEvents& forFile() = 0; + //@} + + // + // Event type providers. + // + + virtual ClientEvents &forClient() = 0; + virtual IStreamEvents &forIStream() = 0; + virtual IpcClientEvents &forIpcClient() = 0; + virtual IpcClientProxyEvents &forIpcClientProxy() = 0; + virtual IpcServerEvents &forIpcServer() = 0; + virtual IpcServerProxyEvents &forIpcServerProxy() = 0; + virtual IDataSocketEvents &forIDataSocket() = 0; + virtual IListenSocketEvents &forIListenSocket() = 0; + virtual ISocketEvents &forISocket() = 0; + virtual OSXScreenEvents &forOSXScreen() = 0; + virtual ClientListenerEvents &forClientListener() = 0; + virtual ClientProxyEvents &forClientProxy() = 0; + virtual ClientProxyUnknownEvents &forClientProxyUnknown() = 0; + virtual ServerEvents &forServer() = 0; + virtual ServerAppEvents &forServerApp() = 0; + virtual IKeyStateEvents &forIKeyState() = 0; + virtual IPrimaryScreenEvents &forIPrimaryScreen() = 0; + virtual IScreenEvents &forIScreen() = 0; + virtual ClipboardEvents &forClipboard() = 0; + virtual FileEvents &forFile() = 0; }; diff --git a/src/lib/base/IEventQueueBuffer.h b/src/lib/base/IEventQueueBuffer.h index 67132e883..59302b9d8 100644 --- a/src/lib/base/IEventQueueBuffer.h +++ b/src/lib/base/IEventQueueBuffer.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 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 LICENSE 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 @@ -30,72 +30,71 @@ An event queue buffer provides a queue of events for an IEventQueue. */ class IEventQueueBuffer : public IInterface { public: - enum Type { - kNone, //!< No event is available - kSystem, //!< Event is a system event - kUser //!< Event is a user event - }; + enum Type { + kNone, //!< No event is available + kSystem, //!< Event is a system event + kUser //!< Event is a user event + }; - //! @name manipulators - //@{ - - //! Initialize - /*! - Useful for platform-specific initialisation from a specific thread. - */ - virtual void init() = 0; + //! @name manipulators + //@{ - //! Block waiting for an event - /*! - Wait for an event in the event queue buffer for up to \p timeout - seconds. - */ - virtual void waitForEvent(double timeout) = 0; + //! Initialize + /*! + Useful for platform-specific initialisation from a specific thread. + */ + virtual void init() = 0; - //! Get the next event - /*! - Get the next event from the buffer. Return kNone if no event is - available. If a system event is next, return kSystem and fill in - event. The event data in a system event can point to a static - buffer (because Event::deleteData() will not attempt to delete - data in a kSystem event). Otherwise, return kUser and fill in - \p dataID with the value passed to \c addEvent(). - */ - virtual Type getEvent(Event& event, UInt32& dataID) = 0; + //! Block waiting for an event + /*! + Wait for an event in the event queue buffer for up to \p timeout + seconds. + */ + virtual void waitForEvent(double timeout) = 0; - //! Post an event - /*! - Add the given event to the end of the queue buffer. This is a user - event and \c getEvent() must be able to identify it as such and - return \p dataID. This method must cause \c waitForEvent() to - return at some future time if it's blocked waiting on an event. - */ - virtual bool addEvent(UInt32 dataID) = 0; + //! Get the next event + /*! + Get the next event from the buffer. Return kNone if no event is + available. If a system event is next, return kSystem and fill in + event. The event data in a system event can point to a static + buffer (because Event::deleteData() will not attempt to delete + data in a kSystem event). Otherwise, return kUser and fill in + \p dataID with the value passed to \c addEvent(). + */ + virtual Type getEvent(Event &event, UInt32 &dataID) = 0; - //@} - //! @name accessors - //@{ + //! Post an event + /*! + Add the given event to the end of the queue buffer. This is a user + event and \c getEvent() must be able to identify it as such and + return \p dataID. This method must cause \c waitForEvent() to + return at some future time if it's blocked waiting on an event. + */ + virtual bool addEvent(UInt32 dataID) = 0; - //! Check if event queue buffer is empty - /*! - Return true iff the event queue buffer is empty. - */ - virtual bool isEmpty() const = 0; + //@} + //! @name accessors + //@{ - //! Create a timer object - /*! - Create and return a timer object. The object is opaque and is - used only by the buffer but it must be a valid object (i.e. - not NULL). - */ - virtual EventQueueTimer* - newTimer(double duration, bool oneShot) const = 0; + //! Check if event queue buffer is empty + /*! + Return true iff the event queue buffer is empty. + */ + virtual bool isEmpty() const = 0; - //! Destroy a timer object - /*! - Destroy a timer object previously returned by \c newTimer(). - */ - virtual void deleteTimer(EventQueueTimer*) const = 0; + //! Create a timer object + /*! + Create and return a timer object. The object is opaque and is + used only by the buffer but it must be a valid object (i.e. + not NULL). + */ + virtual EventQueueTimer *newTimer(double duration, bool oneShot) const = 0; - //@} + //! Destroy a timer object + /*! + Destroy a timer object previously returned by \c newTimer(). + */ + virtual void deleteTimer(EventQueueTimer *) const = 0; + + //@} }; diff --git a/src/lib/base/IJob.h b/src/lib/base/IJob.h index 4a2767975..a4ede28fb 100644 --- a/src/lib/base/IJob.h +++ b/src/lib/base/IJob.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -26,6 +26,6 @@ A job is an interface for executing some function. */ class IJob : public IInterface { public: - //! Run the job - virtual void run() = 0; + //! Run the job + virtual void run() = 0; }; diff --git a/src/lib/base/ILogOutputter.h b/src/lib/base/ILogOutputter.h index 28563a248..f403fa6de 100644 --- a/src/lib/base/ILogOutputter.h +++ b/src/lib/base/ILogOutputter.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -18,8 +18,8 @@ #pragma once -#include "base/Log.h" #include "base/ELevel.h" +#include "base/Log.h" #include "common/IInterface.h" //! Outputter interface @@ -30,40 +30,40 @@ directly or indirectly. */ class ILogOutputter : public IInterface { public: - //! @name manipulators - //@{ + //! @name manipulators + //@{ - //! Open the outputter - /*! - Opens the outputter for writing. Calling this method on an - already open outputter must have no effect. - */ - virtual void open(const char* title) = 0; + //! Open the outputter + /*! + Opens the outputter for writing. Calling this method on an + already open outputter must have no effect. + */ + virtual void open(const char *title) = 0; - //! Close the outputter - /*! - Close the outputter. Calling this method on an already closed - outputter must have no effect. - */ - virtual void close() = 0; + //! Close the outputter + /*! + Close the outputter. Calling this method on an already closed + outputter must have no effect. + */ + virtual void close() = 0; - //! Show the outputter - /*! - Causes the output to become visible. This generally only makes sense - for a logger in a graphical user interface. Other implementations - will do nothing. Iff \p showIfEmpty is \c false then the implementation - may optionally only show the log if it's not empty. - */ - virtual void show(bool showIfEmpty) = 0; + //! Show the outputter + /*! + Causes the output to become visible. This generally only makes sense + for a logger in a graphical user interface. Other implementations + will do nothing. Iff \p showIfEmpty is \c false then the implementation + may optionally only show the log if it's not empty. + */ + virtual void show(bool showIfEmpty) = 0; - //! Write a message with level - /*! - Writes \c message, which has the given \c level, to a log. - If this method returns true then Log will stop passing the - message to all outputters in the outputter chain, otherwise - it continues. Most implementations should return true. - */ - virtual bool write(ELevel level, const char* message) = 0; + //! Write a message with level + /*! + Writes \c message, which has the given \c level, to a log. + If this method returns true then Log will stop passing the + message to all outputters in the outputter chain, otherwise + it continues. Most implementations should return true. + */ + virtual bool write(ELevel level, const char *message) = 0; - //@} + //@} }; diff --git a/src/lib/base/Log.cpp b/src/lib/base/Log.cpp index 7cec4cdde..feedc5b2c 100644 --- a/src/lib/base/Log.cpp +++ b/src/lib/base/Log.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -16,9 +16,9 @@ * along with this program. If not, see . */ +#include "base/Log.h" #include "arch/Arch.h" #include "arch/XArch.h" -#include "base/Log.h" #include "base/String.h" #include "base/log_outputters.h" #include "common/Version.h" @@ -26,26 +26,17 @@ #include #include #include -#include #include +#include // names of priorities -static const char* g_priority[] = { - "FATAL", - "ERROR", - "WARNING", - "NOTE", - "INFO", - "DEBUG", - "DEBUG1", - "DEBUG2", - "DEBUG3", - "DEBUG4", - "DEBUG5" -}; +static const char *g_priority[] = {"FATAL", "ERROR", "WARNING", "NOTE", + "INFO", "DEBUG", "DEBUG1", "DEBUG2", + "DEBUG3", "DEBUG4", "DEBUG5"}; // number of priorities -static const int g_numPriority = (int)(sizeof(g_priority) / sizeof(g_priority[0])); +static const int g_numPriority = + (int)(sizeof(g_priority) / sizeof(g_priority[0])); // if NDEBUG (not debug) is not specified, i.e. you're building in debug, // then set default log level to DEBUG, otherwise the max level is INFO. @@ -54,267 +45,248 @@ static const int g_numPriority = (int)(sizeof(g_priority) / sizeof(g_priority[0] // for visual studio, then NDEBUG will be set (even if your VS solution // config is Debug). #ifndef NDEBUG -static const int g_defaultMaxPriority = kDEBUG; +static const int g_defaultMaxPriority = kDEBUG; #else -static const int g_defaultMaxPriority = kINFO; +static const int g_defaultMaxPriority = kINFO; #endif // // Log // -Log* Log::s_log = NULL; +Log *Log::s_log = NULL; -Log::Log() -{ - assert(s_log == NULL); +Log::Log() { + assert(s_log == NULL); - // create mutex for multithread safe operation - m_mutex = ARCH->newMutex(); + // create mutex for multithread safe operation + m_mutex = ARCH->newMutex(); - // other initalization - m_maxPriority = g_defaultMaxPriority; - m_maxNewlineLength = 0; - insert(new ConsoleLogOutputter); + // other initalization + m_maxPriority = g_defaultMaxPriority; + m_maxNewlineLength = 0; + insert(new ConsoleLogOutputter); - s_log = this; + s_log = this; } -Log::Log(Log* src) -{ - s_log = src; +Log::Log(Log *src) { s_log = src; } + +Log::~Log() { + // clean up + for (OutputterList::iterator index = m_outputters.begin(); + index != m_outputters.end(); ++index) { + delete *index; + } + for (OutputterList::iterator index = m_alwaysOutputters.begin(); + index != m_alwaysOutputters.end(); ++index) { + delete *index; + } + ARCH->closeMutex(m_mutex); } -Log::~Log() -{ - // clean up - for (OutputterList::iterator index = m_outputters.begin(); - index != m_outputters.end(); ++index) { - delete *index; - } - for (OutputterList::iterator index = m_alwaysOutputters.begin(); - index != m_alwaysOutputters.end(); ++index) { - delete *index; - } - ARCH->closeMutex(m_mutex); +Log *Log::getInstance() { + assert(s_log != NULL); + return s_log; } -Log* -Log::getInstance() -{ - assert(s_log != NULL); - return s_log; +const char *Log::getFilterName() const { return getFilterName(getFilter()); } + +const char *Log::getFilterName(int level) const { + if (level < 0) { + return "Message"; + } + return g_priority[level]; } -const char* -Log::getFilterName() const -{ - return getFilterName(getFilter()); -} +void Log::print(const char *file, int line, const char *fmt, ...) { + // check if fmt begins with a priority argument + ELevel priority = kINFO; + if ((strnlen(fmt, SIZE_MAX) > 2) && (fmt[0] == '%' && fmt[1] == 'z')) { -const char* -Log::getFilterName(int level) const -{ - if (level < 0) { - return "Message"; - } - return g_priority[level]; -} + // 060 in octal is 0 (48 in decimal), so subtracting this converts ascii + // number it a true number. we could use atoi instead, but this is how + // it was done originally. + priority = (ELevel)(fmt[2] - '\060'); -void -Log::print(const char* file, int line, const char* fmt, ...) -{ - // check if fmt begins with a priority argument - ELevel priority = kINFO; - if ((strnlen(fmt, SIZE_MAX) > 2) && (fmt[0] == '%' && fmt[1] == 'z')) { + // move the pointer on past the debug priority char + fmt += 3; + } - // 060 in octal is 0 (48 in decimal), so subtracting this converts ascii - // number it a true number. we could use atoi instead, but this is how - // it was done originally. - priority = (ELevel)(fmt[2] - '\060'); + // done if below priority threshold + if (priority > getFilter()) { + return; + } - // move the pointer on past the debug priority char - fmt += 3; - } + // compute prefix padding length + char stack[1024]; - // done if below priority threshold - if (priority > getFilter()) { - return; - } + // compute suffix padding length + int sPad = m_maxNewlineLength; - // compute prefix padding length - char stack[1024]; + // print to buffer, leaving space for a newline at the end and prefix + // at the beginning. + char *buffer = stack; + int len = (int)(sizeof(stack) / sizeof(stack[0])); + while (true) { + // try printing into the buffer + va_list args; + va_start(args, fmt); + int n = ARCH->vsnprintf(buffer, len - sPad, fmt, args); + va_end(args); - // compute suffix padding length - int sPad = m_maxNewlineLength; - - // print to buffer, leaving space for a newline at the end and prefix - // at the beginning. - char* buffer = stack; - int len = (int)(sizeof(stack) / sizeof(stack[0])); - while (true) { - // try printing into the buffer - va_list args; - va_start(args, fmt); - int n = ARCH->vsnprintf(buffer, len - sPad, fmt, args); - va_end(args); - - // if the buffer wasn't big enough then make it bigger and try again - if (n < 0 || n > (int)len) { - if (buffer != stack) { - delete[] buffer; - } - len *= 2; - buffer = new char[len]; - } - - // if the buffer was big enough then continue - else { - break; - } - } - - // print the prefix to the buffer. leave space for priority label. - // do not prefix time and file for kPRINT (CLOG_PRINT) - if (priority != kPRINT) { - - struct tm tm; - static const int timestamp_size = 50; - char timestamp[timestamp_size]; - time_t t; - time(&t); -#if WINAPI_MSWINDOWS - localtime_s(&tm, &t); -#else - localtime_r(&t, &tm); -#endif - snprintf(timestamp, timestamp_size, "%04i-%02i-%02iT%02i:%02i:%02i", tm.tm_year + 1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); - - // square brackets, spaces, comma and null terminator take about 10 - int size = 10; - size += static_cast(strlen(timestamp)); // Compliant: we made sure that timestamp variable ended with null(terminating null character is automatically appended in snprintf) - size += static_cast(strlen(g_priority[priority])); // Compliant: we made sure that g_priority[priority] variable ended with null(static const char* declaration) - size += static_cast(strnlen(buffer, len)); -#ifndef NDEBUG - size += static_cast(strnlen(file, SIZE_MAX)); - // assume there is no file contains over 100k lines of code - size += 6; -#endif - char* message = new char[size]; - -#ifndef NDEBUG - snprintf(message, size, "[%s] %s: %s\n\t%s:%d", timestamp, g_priority[priority], buffer, file, line); -#else - snprintf(message, size, "[%s] %s: %s", timestamp, g_priority[priority], buffer); -#endif - - output(priority, message); - delete[] message; - } else { - output(priority, buffer); - } - - // clean up - if (buffer != stack) { + // if the buffer wasn't big enough then make it bigger and try again + if (n < 0 || n > (int)len) { + if (buffer != stack) { delete[] buffer; + } + len *= 2; + buffer = new char[len]; } -} -void -Log::insert(ILogOutputter* outputter, bool alwaysAtHead) -{ - assert(outputter != NULL); - - ArchMutexLock lock(m_mutex); - if (alwaysAtHead) { - m_alwaysOutputters.push_front(outputter); - } + // if the buffer was big enough then continue else { - m_outputters.push_front(outputter); + break; } + } - outputter->open(kAppVersion); + // print the prefix to the buffer. leave space for priority label. + // do not prefix time and file for kPRINT (CLOG_PRINT) + if (priority != kPRINT) { - // Issue 41 - // don't show log unless user requests it, as some users find this - // feature irritating (i.e. when they lose network connectivity). - // in windows the log window can be displayed by selecting "show log" - // from the synergy system tray icon. - // if this causes problems for other architectures, then a different - // work around should be attempted. - //outputter->show(false); + struct tm tm; + static const int timestamp_size = 50; + char timestamp[timestamp_size]; + time_t t; + time(&t); +#if WINAPI_MSWINDOWS + localtime_s(&tm, &t); +#else + localtime_r(&t, &tm); +#endif + snprintf(timestamp, timestamp_size, "%04i-%02i-%02iT%02i:%02i:%02i", + tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, + tm.tm_min, tm.tm_sec); + + // square brackets, spaces, comma and null terminator take about 10 + int size = 10; + size += static_cast( + strlen(timestamp)); // Compliant: we made sure that timestamp variable + // ended with null(terminating null character is + // automatically appended in snprintf) + size += static_cast(strlen( + g_priority[priority])); // Compliant: we made sure that + // g_priority[priority] variable ended with + // null(static const char* declaration) + size += static_cast(strnlen(buffer, len)); +#ifndef NDEBUG + size += static_cast(strnlen(file, SIZE_MAX)); + // assume there is no file contains over 100k lines of code + size += 6; +#endif + char *message = new char[size]; + +#ifndef NDEBUG + snprintf(message, size, "[%s] %s: %s\n\t%s:%d", timestamp, + g_priority[priority], buffer, file, line); +#else + snprintf(message, size, "[%s] %s: %s", timestamp, g_priority[priority], + buffer); +#endif + + output(priority, message); + delete[] message; + } else { + output(priority, buffer); + } + + // clean up + if (buffer != stack) { + delete[] buffer; + } } -void -Log::remove(ILogOutputter* outputter) -{ - ArchMutexLock lock(m_mutex); - m_outputters.remove(outputter); - m_alwaysOutputters.remove(outputter); +void Log::insert(ILogOutputter *outputter, bool alwaysAtHead) { + assert(outputter != NULL); + + ArchMutexLock lock(m_mutex); + if (alwaysAtHead) { + m_alwaysOutputters.push_front(outputter); + } else { + m_outputters.push_front(outputter); + } + + outputter->open(kAppVersion); + + // Issue 41 + // don't show log unless user requests it, as some users find this + // feature irritating (i.e. when they lose network connectivity). + // in windows the log window can be displayed by selecting "show log" + // from the synergy system tray icon. + // if this causes problems for other architectures, then a different + // work around should be attempted. + // outputter->show(false); } -void -Log::pop_front(bool alwaysAtHead) -{ - ArchMutexLock lock(m_mutex); - OutputterList* list = alwaysAtHead ? &m_alwaysOutputters : &m_outputters; - if (!list->empty()) { - delete list->front(); - list->pop_front(); +void Log::remove(ILogOutputter *outputter) { + ArchMutexLock lock(m_mutex); + m_outputters.remove(outputter); + m_alwaysOutputters.remove(outputter); +} + +void Log::pop_front(bool alwaysAtHead) { + ArchMutexLock lock(m_mutex); + OutputterList *list = alwaysAtHead ? &m_alwaysOutputters : &m_outputters; + if (!list->empty()) { + delete list->front(); + list->pop_front(); + } +} + +bool Log::setFilter(const char *maxPriority) { + if (maxPriority != NULL) { + for (int i = 0; i < g_numPriority; ++i) { + if (strcmp(maxPriority, g_priority[i]) == 0) { + setFilter(i); + return true; + } } + return false; + } + return true; } -bool -Log::setFilter(const char* maxPriority) -{ - if (maxPriority != NULL) { - for (int i = 0; i < g_numPriority; ++i) { - if (strcmp(maxPriority, g_priority[i]) == 0) { - setFilter(i); - return true; - } - } - return false; - } - return true; -} - -void -Log::setFilter(int maxPriority) -{ - ArchMutexLock lock(m_mutex); - m_maxPriority = maxPriority; -} - -int -Log::getFilter() const -{ - ArchMutexLock lock(m_mutex); - return m_maxPriority; -} - -void -Log::output(ELevel priority, char* msg) -{ - assert(priority >= -1 && priority < g_numPriority); - assert(msg != NULL); - if (!msg) return; - - ArchMutexLock lock(m_mutex); - - OutputterList::const_iterator i; - - for (i = m_alwaysOutputters.begin(); i != m_alwaysOutputters.end(); ++i) { - - // write to outputter - (*i)->write(priority, msg); - } - - for (i = m_outputters.begin(); i != m_outputters.end(); ++i) { - - // write to outputter and break out of loop if it returns false - if (!(*i)->write(priority, msg)) { - break; - } +void Log::setFilter(int maxPriority) { + ArchMutexLock lock(m_mutex); + m_maxPriority = maxPriority; +} + +int Log::getFilter() const { + ArchMutexLock lock(m_mutex); + return m_maxPriority; +} + +void Log::output(ELevel priority, char *msg) { + assert(priority >= -1 && priority < g_numPriority); + assert(msg != NULL); + if (!msg) + return; + + ArchMutexLock lock(m_mutex); + + OutputterList::const_iterator i; + + for (i = m_alwaysOutputters.begin(); i != m_alwaysOutputters.end(); ++i) { + + // write to outputter + (*i)->write(priority, msg); + } + + for (i = m_outputters.begin(); i != m_outputters.end(); ++i) { + + // write to outputter and break out of loop if it returns false + if (!(*i)->write(priority, msg)) { + break; } + } } diff --git a/src/lib/base/Log.h b/src/lib/base/Log.h index 90485fac3..34eb0844a 100644 --- a/src/lib/base/Log.h +++ b/src/lib/base/Log.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -18,8 +18,8 @@ #pragma once -#include "arch/IArchMultithread.h" #include "arch/Arch.h" +#include "arch/IArchMultithread.h" #include "common/common.h" #include "common/stdlist.h" @@ -40,108 +40,107 @@ LOGC() provide convenient access. */ class Log { public: - Log(); - Log(Log* src); - Log(Log const &) =delete; - Log(Log &&) =delete; - ~Log(); + Log(); + Log(Log *src); + Log(Log const &) = delete; + Log(Log &&) = delete; + ~Log(); - Log& operator=(Log const &) =delete; - Log& operator=(Log &&) =delete; + Log &operator=(Log const &) = delete; + Log &operator=(Log &&) = delete; - //! @name manipulators - //@{ + //! @name manipulators + //@{ - //! Add an outputter to the head of the list - /*! - Inserts an outputter to the head of the outputter list. When the - logger writes a message, it goes to the outputter at the head of - the outputter list. If that outputter's \c write() method returns - true then it also goes to the next outputter, as so on until an - outputter returns false or there are no more outputters. Outputters - still in the outputter list when the log is destroyed will be - deleted. If \c alwaysAtHead is true then the outputter is always - called before all outputters with \c alwaysAtHead false and the - return value of the outputter is ignored. + //! Add an outputter to the head of the list + /*! + Inserts an outputter to the head of the outputter list. When the + logger writes a message, it goes to the outputter at the head of + the outputter list. If that outputter's \c write() method returns + true then it also goes to the next outputter, as so on until an + outputter returns false or there are no more outputters. Outputters + still in the outputter list when the log is destroyed will be + deleted. If \c alwaysAtHead is true then the outputter is always + called before all outputters with \c alwaysAtHead false and the + return value of the outputter is ignored. - By default, the logger has one outputter installed which writes to - the console. - */ - void insert(ILogOutputter* adopted, - bool alwaysAtHead = false); + By default, the logger has one outputter installed which writes to + the console. + */ + void insert(ILogOutputter *adopted, bool alwaysAtHead = false); - //! Remove an outputter from the list - /*! - Removes the first occurrence of the given outputter from the - outputter list. It does nothing if the outputter is not in the - list. The outputter is not deleted. - */ - void remove(ILogOutputter* orphaned); + //! Remove an outputter from the list + /*! + Removes the first occurrence of the given outputter from the + outputter list. It does nothing if the outputter is not in the + list. The outputter is not deleted. + */ + void remove(ILogOutputter *orphaned); - //! Remove the outputter from the head of the list - /*! - Removes and deletes the outputter at the head of the outputter list. - This does nothing if the outputter list is empty. Only removes - outputters that were inserted with the matching \c alwaysAtHead. - */ - void pop_front(bool alwaysAtHead = false); + //! Remove the outputter from the head of the list + /*! + Removes and deletes the outputter at the head of the outputter list. + This does nothing if the outputter list is empty. Only removes + outputters that were inserted with the matching \c alwaysAtHead. + */ + void pop_front(bool alwaysAtHead = false); - //! Set the minimum priority filter. - /*! - Set the filter. Messages below this priority are discarded. - The default priority is 4 (INFO) (unless built without NDEBUG - in which case it's 5 (DEBUG)). setFilter(const char*) returns - true if the priority \c name was recognized; if \c name is NULL - then it simply returns true. - */ - bool setFilter(const char* name); - - //! Set the minimum priority filter (by ordinal). - void setFilter(int); + //! Set the minimum priority filter. + /*! + Set the filter. Messages below this priority are discarded. + The default priority is 4 (INFO) (unless built without NDEBUG + in which case it's 5 (DEBUG)). setFilter(const char*) returns + true if the priority \c name was recognized; if \c name is NULL + then it simply returns true. + */ + bool setFilter(const char *name); - //@} - //! @name accessors - //@{ + //! Set the minimum priority filter (by ordinal). + void setFilter(int); - //! Print a log message - /*! - Print a log message using the printf-like \c format and arguments - preceded by the filename and line number. If \c file is NULL then - neither the file nor the line are printed. - */ - void print(const char* file, int line, - const char* format, ...); + //@} + //! @name accessors + //@{ - //! Get the minimum priority level. - int getFilter() const; + //! Print a log message + /*! + Print a log message using the printf-like \c format and arguments + preceded by the filename and line number. If \c file is NULL then + neither the file nor the line are printed. + */ + void print(const char *file, int line, const char *format, ...); - //! Get the filter name of the current filter level. - const char* getFilterName() const; + //! Get the minimum priority level. + int getFilter() const; - //! Get the filter name of a specified filter level. - const char* getFilterName(int level) const; + //! Get the filter name of the current filter level. + const char *getFilterName() const; - //! Get the singleton instance of the log - static Log* getInstance(); + //! Get the filter name of a specified filter level. + const char *getFilterName(int level) const; - //! Get the console filter level (messages above this are not sent to console). - int getConsoleMaxLevel() const { return kDEBUG2; } + //! Get the singleton instance of the log + static Log *getInstance(); - //@} + //! Get the console filter level (messages above this are not sent to + //! console). + int getConsoleMaxLevel() const { return kDEBUG2; } + + //@} private: - void output(ELevel priority, char* msg); + void output(ELevel priority, char *msg); private: - typedef std::list OutputterList; + typedef std::list OutputterList; - static Log* s_log; + static Log *s_log; - ArchMutex m_mutex; - OutputterList m_outputters; - OutputterList m_alwaysOutputters; - int m_maxNewlineLength; - int m_maxPriority; + ArchMutex m_mutex; + OutputterList m_outputters; + OutputterList m_alwaysOutputters; + int m_maxNewlineLength; + int m_maxPriority; }; /*! @@ -188,29 +187,33 @@ otherwise it expands to a call that doesn't. #define LOGC(_a1, _a2) #define CLOG_TRACE #elif defined(NDEBUG) -#define LOG(_a1) CLOG->print _a1 -#define LOGC(_a1, _a2) if (_a1) CLOG->print _a2 -#define CLOG_TRACE NULL, 0, +#define LOG(_a1) CLOG->print _a1 +#define LOGC(_a1, _a2) \ + if (_a1) \ + CLOG->print _a2 +#define CLOG_TRACE NULL, 0, #else -#define LOG(_a1) CLOG->print _a1 -#define LOGC(_a1, _a2) if (_a1) CLOG->print _a2 -#define CLOG_TRACE __FILE__, __LINE__, +#define LOG(_a1) CLOG->print _a1 +#define LOGC(_a1, _a2) \ + if (_a1) \ + CLOG->print _a2 +#define CLOG_TRACE __FILE__, __LINE__, #endif -// the CLOG_* defines are line and file plus %z and an octal number (060=0, -// 071=9), but the limitation is that once we run out of numbers at either -// end, then we resort to using non-numerical chars. this still works (since +// the CLOG_* defines are line and file plus %z and an octal number (060=0, +// 071=9), but the limitation is that once we run out of numbers at either +// end, then we resort to using non-numerical chars. this still works (since // to deduce the number we subtract octal \060, so '/' is -1, and ':' is 10 -#define CLOG_PRINT CLOG_TRACE "%z\057" // char is '/' -#define CLOG_CRIT CLOG_TRACE "%z\060" // char is '0' -#define CLOG_ERR CLOG_TRACE "%z\061" -#define CLOG_WARN CLOG_TRACE "%z\062" -#define CLOG_NOTE CLOG_TRACE "%z\063" -#define CLOG_INFO CLOG_TRACE "%z\064" -#define CLOG_DEBUG CLOG_TRACE "%z\065" -#define CLOG_DEBUG1 CLOG_TRACE "%z\066" -#define CLOG_DEBUG2 CLOG_TRACE "%z\067" -#define CLOG_DEBUG3 CLOG_TRACE "%z\070" -#define CLOG_DEBUG4 CLOG_TRACE "%z\071" // char is '9' -#define CLOG_DEBUG5 CLOG_TRACE "%z\072" // char is ':' +#define CLOG_PRINT CLOG_TRACE "%z\057" // char is '/' +#define CLOG_CRIT CLOG_TRACE "%z\060" // char is '0' +#define CLOG_ERR CLOG_TRACE "%z\061" +#define CLOG_WARN CLOG_TRACE "%z\062" +#define CLOG_NOTE CLOG_TRACE "%z\063" +#define CLOG_INFO CLOG_TRACE "%z\064" +#define CLOG_DEBUG CLOG_TRACE "%z\065" +#define CLOG_DEBUG1 CLOG_TRACE "%z\066" +#define CLOG_DEBUG2 CLOG_TRACE "%z\067" +#define CLOG_DEBUG3 CLOG_TRACE "%z\070" +#define CLOG_DEBUG4 CLOG_TRACE "%z\071" // char is '9' +#define CLOG_DEBUG5 CLOG_TRACE "%z\072" // char is ':' diff --git a/src/lib/base/Path.cpp b/src/lib/base/Path.cpp index 1e0fa3265..d407fcf80 100644 --- a/src/lib/base/Path.cpp +++ b/src/lib/base/Path.cpp @@ -26,27 +26,24 @@ namespace filesystem { #ifdef SYSAPI_WIN32 -std::wstring path(const String& filePath) -{ - std::wstring result; +std::wstring path(const String &filePath) { + std::wstring result; - auto lenght = MultiByteToWideChar(CP_UTF8, 0, filePath.c_str(), filePath.length(), NULL, 0); - if (lenght > 0) - { - result.resize(lenght); - MultiByteToWideChar(CP_UTF8, 0, filePath.c_str(), filePath.length(), &result[0], lenght); - } + auto lenght = MultiByteToWideChar(CP_UTF8, 0, filePath.c_str(), + filePath.length(), NULL, 0); + if (lenght > 0) { + result.resize(lenght); + MultiByteToWideChar(CP_UTF8, 0, filePath.c_str(), filePath.length(), + &result[0], lenght); + } - return result; + return result; } #else -std::string path(const String& filePath) -{ - return filePath; -} +std::string path(const String &filePath) { return filePath; } #endif -} //namespace filesystem +} // namespace filesystem -} //namespace synergy +} // namespace synergy diff --git a/src/lib/base/Path.h b/src/lib/base/Path.h index ee8d43e6b..98c8e3a5a 100644 --- a/src/lib/base/Path.h +++ b/src/lib/base/Path.h @@ -24,14 +24,13 @@ namespace synergy { namespace filesystem { #ifdef SYSAPI_WIN32 - std::wstring path(const String& filePath); +std::wstring path(const String &filePath); #else - std::string path(const String& filePath); +std::string path(const String &filePath); #endif +} // namespace filesystem -} //namespace filesystem - -} //namespace synergy +} // namespace synergy #endif // SYNERGY_PATH_H diff --git a/src/lib/base/PriorityQueue.h b/src/lib/base/PriorityQueue.h index 31f68794e..384aedea2 100644 --- a/src/lib/base/PriorityQueue.h +++ b/src/lib/base/PriorityQueue.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2003 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 LICENSE 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 @@ -31,108 +31,80 @@ it sorts by std::greater, it has a forward iterator through the elements */ template , #if defined(_MSC_VER) - class Compare = std::greater > + class Compare = std::greater> #else - class Compare = std::greater > + class Compare = std::greater> #endif class PriorityQueue { public: - typedef typename Container::value_type value_type; - typedef typename Container::size_type size_type; - typedef typename Container::iterator iterator; - typedef typename Container::const_iterator const_iterator; - typedef Container container_type; + typedef typename Container::value_type value_type; + typedef typename Container::size_type size_type; + typedef typename Container::iterator iterator; + typedef typename Container::const_iterator const_iterator; + typedef Container container_type; - PriorityQueue() { } - PriorityQueue(Container& swappedIn) { swap(swappedIn); } - ~PriorityQueue() { } + PriorityQueue() {} + PriorityQueue(Container &swappedIn) { swap(swappedIn); } + ~PriorityQueue() {} - //! @name manipulators - //@{ + //! @name manipulators + //@{ - //! Add element - void push(const value_type& v) - { - c.push_back(v); - std::push_heap(c.begin(), c.end(), comp); - } + //! Add element + void push(const value_type &v) { + c.push_back(v); + std::push_heap(c.begin(), c.end(), comp); + } - //! Remove head element - void pop() - { - std::pop_heap(c.begin(), c.end(), comp); - c.pop_back(); - } + //! Remove head element + void pop() { + std::pop_heap(c.begin(), c.end(), comp); + c.pop_back(); + } - //! Erase element - void erase(iterator i) - { - c.erase(i); - std::make_heap(c.begin(), c.end(), comp); - } + //! Erase element + void erase(iterator i) { + c.erase(i); + std::make_heap(c.begin(), c.end(), comp); + } - //! Get start iterator - iterator begin() - { - return c.begin(); - } + //! Get start iterator + iterator begin() { return c.begin(); } - //! Get end iterator - iterator end() - { - return c.end(); - } + //! Get end iterator + iterator end() { return c.end(); } - //! Swap contents with another priority queue - void swap(PriorityQueue& q) - { - c.swap(q.c); - } + //! Swap contents with another priority queue + void swap(PriorityQueue &q) { c.swap(q.c); } - //! Swap contents with another container - void swap(Container& c2) - { - c.swap(c2); - std::make_heap(c.begin(), c.end(), comp); - } + //! Swap contents with another container + void swap(Container &c2) { + c.swap(c2); + std::make_heap(c.begin(), c.end(), comp); + } - //@} - //! @name accessors - //@{ + //@} + //! @name accessors + //@{ - //! Returns true if there are no elements - bool empty() const - { - return c.empty(); - } + //! Returns true if there are no elements + bool empty() const { return c.empty(); } - //! Returns the number of elements - size_type size() const - { - return c.size(); - } + //! Returns the number of elements + size_type size() const { return c.size(); } - //! Returns the head element - const value_type& top() const - { - return c.front(); - } + //! Returns the head element + const value_type &top() const { return c.front(); } - //! Get start iterator - const_iterator begin() const - { - return c.begin(); - } + //! Get start iterator + const_iterator begin() const { return c.begin(); } - //! Get end iterator - const_iterator end() const - { - return c.end(); - } + //! Get end iterator + const_iterator end() const { return c.end(); } - //@} + //@} private: - Container c; - Compare comp; + Container c; + Compare comp; }; diff --git a/src/lib/base/SimpleEventQueueBuffer.cpp b/src/lib/base/SimpleEventQueueBuffer.cpp index b8603403f..f303a7090 100644 --- a/src/lib/base/SimpleEventQueueBuffer.cpp +++ b/src/lib/base/SimpleEventQueueBuffer.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 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 LICENSE 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 @@ -17,85 +17,72 @@ */ #include "base/SimpleEventQueueBuffer.h" -#include "base/Stopwatch.h" #include "arch/Arch.h" +#include "base/Stopwatch.h" -class EventQueueTimer { }; +class EventQueueTimer {}; // // SimpleEventQueueBuffer // -SimpleEventQueueBuffer::SimpleEventQueueBuffer() -{ - m_queueMutex = ARCH->newMutex(); - m_queueReadyCond = ARCH->newCondVar(); - m_queueReady = false; +SimpleEventQueueBuffer::SimpleEventQueueBuffer() { + m_queueMutex = ARCH->newMutex(); + m_queueReadyCond = ARCH->newCondVar(); + m_queueReady = false; } -SimpleEventQueueBuffer::~SimpleEventQueueBuffer() -{ - ARCH->closeCondVar(m_queueReadyCond); - ARCH->closeMutex(m_queueMutex); +SimpleEventQueueBuffer::~SimpleEventQueueBuffer() { + ARCH->closeCondVar(m_queueReadyCond); + ARCH->closeMutex(m_queueMutex); } -void -SimpleEventQueueBuffer::waitForEvent(double timeout) -{ - ArchMutexLock lock(m_queueMutex); - Stopwatch timer(true); - while (!m_queueReady) { - double timeLeft = timeout; - if (timeLeft >= 0.0) { - timeLeft -= timer.getTime(); - if (timeLeft < 0.0) { - return; - } - } - ARCH->waitCondVar(m_queueReadyCond, m_queueMutex, timeLeft); +void SimpleEventQueueBuffer::waitForEvent(double timeout) { + ArchMutexLock lock(m_queueMutex); + Stopwatch timer(true); + while (!m_queueReady) { + double timeLeft = timeout; + if (timeLeft >= 0.0) { + timeLeft -= timer.getTime(); + if (timeLeft < 0.0) { + return; + } } + ARCH->waitCondVar(m_queueReadyCond, m_queueMutex, timeLeft); + } } -IEventQueueBuffer::Type -SimpleEventQueueBuffer::getEvent(Event&, UInt32& dataID) -{ - ArchMutexLock lock(m_queueMutex); - if (!m_queueReady) { - return kNone; - } - dataID = m_queue.back(); - m_queue.pop_back(); - m_queueReady = !m_queue.empty(); - return kUser; +IEventQueueBuffer::Type SimpleEventQueueBuffer::getEvent(Event &, + UInt32 &dataID) { + ArchMutexLock lock(m_queueMutex); + if (!m_queueReady) { + return kNone; + } + dataID = m_queue.back(); + m_queue.pop_back(); + m_queueReady = !m_queue.empty(); + return kUser; } -bool -SimpleEventQueueBuffer::addEvent(UInt32 dataID) -{ - ArchMutexLock lock(m_queueMutex); - m_queue.push_front(dataID); - if (!m_queueReady) { - m_queueReady = true; - ARCH->broadcastCondVar(m_queueReadyCond); - } - return true; +bool SimpleEventQueueBuffer::addEvent(UInt32 dataID) { + ArchMutexLock lock(m_queueMutex); + m_queue.push_front(dataID); + if (!m_queueReady) { + m_queueReady = true; + ARCH->broadcastCondVar(m_queueReadyCond); + } + return true; } -bool -SimpleEventQueueBuffer::isEmpty() const -{ - ArchMutexLock lock(m_queueMutex); - return !m_queueReady; +bool SimpleEventQueueBuffer::isEmpty() const { + ArchMutexLock lock(m_queueMutex); + return !m_queueReady; } -EventQueueTimer* -SimpleEventQueueBuffer::newTimer(double, bool) const -{ - return new EventQueueTimer; +EventQueueTimer *SimpleEventQueueBuffer::newTimer(double, bool) const { + return new EventQueueTimer; } -void -SimpleEventQueueBuffer::deleteTimer(EventQueueTimer* timer) const -{ - delete timer; +void SimpleEventQueueBuffer::deleteTimer(EventQueueTimer *timer) const { + delete timer; } diff --git a/src/lib/base/SimpleEventQueueBuffer.h b/src/lib/base/SimpleEventQueueBuffer.h index 9fe51b80d..c1678f4c5 100644 --- a/src/lib/base/SimpleEventQueueBuffer.h +++ b/src/lib/base/SimpleEventQueueBuffer.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 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 LICENSE 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 @@ -18,8 +18,8 @@ #pragma once -#include "base/IEventQueueBuffer.h" #include "arch/IArchMultithread.h" +#include "base/IEventQueueBuffer.h" #include "common/stddeque.h" //! In-memory event queue buffer @@ -28,30 +28,28 @@ An event queue buffer provides a queue of events for an IEventQueue. */ class SimpleEventQueueBuffer : public IEventQueueBuffer { public: - SimpleEventQueueBuffer(); - SimpleEventQueueBuffer(SimpleEventQueueBuffer const &) = delete; - SimpleEventQueueBuffer(SimpleEventQueueBuffer &&) = delete; - ~SimpleEventQueueBuffer(); + SimpleEventQueueBuffer(); + SimpleEventQueueBuffer(SimpleEventQueueBuffer const &) = delete; + SimpleEventQueueBuffer(SimpleEventQueueBuffer &&) = delete; + ~SimpleEventQueueBuffer(); - SimpleEventQueueBuffer& operator=(SimpleEventQueueBuffer const &) = delete; - SimpleEventQueueBuffer& operator=(SimpleEventQueueBuffer &&) = delete; + SimpleEventQueueBuffer &operator=(SimpleEventQueueBuffer const &) = delete; + SimpleEventQueueBuffer &operator=(SimpleEventQueueBuffer &&) = delete; - // IEventQueueBuffer overrides - void init() { } - virtual void waitForEvent(double timeout); - virtual Type getEvent(Event& event, UInt32& dataID); - virtual bool addEvent(UInt32 dataID); - virtual bool isEmpty() const; - virtual EventQueueTimer* - newTimer(double duration, bool oneShot) const; - virtual void deleteTimer(EventQueueTimer*) const; + // IEventQueueBuffer overrides + void init() {} + virtual void waitForEvent(double timeout); + virtual Type getEvent(Event &event, UInt32 &dataID); + virtual bool addEvent(UInt32 dataID); + virtual bool isEmpty() const; + virtual EventQueueTimer *newTimer(double duration, bool oneShot) const; + virtual void deleteTimer(EventQueueTimer *) const; private: - typedef std::deque EventDeque; + typedef std::deque EventDeque; - ArchMutex m_queueMutex; - ArchCond m_queueReadyCond; - bool m_queueReady; - EventDeque m_queue; + ArchMutex m_queueMutex; + ArchCond m_queueReadyCond; + bool m_queueReady; + EventDeque m_queue; }; - diff --git a/src/lib/base/Stopwatch.cpp b/src/lib/base/Stopwatch.cpp index f5dee0450..5f40de303 100644 --- a/src/lib/base/Stopwatch.cpp +++ b/src/lib/base/Stopwatch.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -23,108 +23,78 @@ // Stopwatch // -Stopwatch::Stopwatch(bool triggered) : - m_mark(0.0), - m_triggered(triggered), - m_stopped(triggered) -{ - if (!triggered) { - m_mark = ARCH->time(); - } +Stopwatch::Stopwatch(bool triggered) + : m_mark(0.0), m_triggered(triggered), m_stopped(triggered) { + if (!triggered) { + m_mark = ARCH->time(); + } } -Stopwatch::~Stopwatch() -{ - // do nothing +Stopwatch::~Stopwatch() { + // do nothing } -double -Stopwatch::reset() -{ - if (m_stopped) { - const double dt = m_mark; - m_mark = 0.0; - return dt; - } - else { - const double t = ARCH->time(); - const double dt = t - m_mark; - m_mark = t; - return dt; - } +double Stopwatch::reset() { + if (m_stopped) { + const double dt = m_mark; + m_mark = 0.0; + return dt; + } else { + const double t = ARCH->time(); + const double dt = t - m_mark; + m_mark = t; + return dt; + } } -void -Stopwatch::stop() -{ - if (m_stopped) { - return; - } +void Stopwatch::stop() { + if (m_stopped) { + return; + } - // save the elapsed time - m_mark = ARCH->time() - m_mark; - m_stopped = true; + // save the elapsed time + m_mark = ARCH->time() - m_mark; + m_stopped = true; } -void -Stopwatch::start() -{ - m_triggered = false; - if (!m_stopped) { - return; - } +void Stopwatch::start() { + m_triggered = false; + if (!m_stopped) { + return; + } - // set the mark such that it reports the time elapsed at stop() - m_mark = ARCH->time() - m_mark; - m_stopped = false; + // set the mark such that it reports the time elapsed at stop() + m_mark = ARCH->time() - m_mark; + m_stopped = false; } -void -Stopwatch::setTrigger() -{ - stop(); - m_triggered = true; +void Stopwatch::setTrigger() { + stop(); + m_triggered = true; } -double -Stopwatch::getTime() -{ - if (m_triggered) { - const double dt = m_mark; - start(); - return dt; - } - else if (m_stopped) { - return m_mark; - } - else { - return ARCH->time() - m_mark; - } +double Stopwatch::getTime() { + if (m_triggered) { + const double dt = m_mark; + start(); + return dt; + } else if (m_stopped) { + return m_mark; + } else { + return ARCH->time() - m_mark; + } } -Stopwatch::operator double() -{ - return getTime(); +Stopwatch::operator double() { return getTime(); } + +bool Stopwatch::isStopped() const { return m_stopped; } + +double Stopwatch::getTime() const { + if (m_stopped) { + return m_mark; + } else { + return ARCH->time() - m_mark; + } } -bool -Stopwatch::isStopped() const -{ - return m_stopped; -} - -double -Stopwatch::getTime() const -{ - if (m_stopped) { - return m_mark; - } - else { - return ARCH->time() - m_mark; - } -} - -Stopwatch::operator double() const -{ - return getTime(); -} +Stopwatch::operator double() const { return getTime(); } diff --git a/src/lib/base/Stopwatch.h b/src/lib/base/Stopwatch.h index 49ec627ca..2abac2020 100644 --- a/src/lib/base/Stopwatch.h +++ b/src/lib/base/Stopwatch.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -27,83 +27,83 @@ should use this class. */ class Stopwatch { public: - /*! - The default constructor does an implicit reset() or setTrigger(). - If triggered == false then the clock starts ticking. - */ - Stopwatch(bool triggered = false); - ~Stopwatch(); + /*! + The default constructor does an implicit reset() or setTrigger(). + If triggered == false then the clock starts ticking. + */ + Stopwatch(bool triggered = false); + ~Stopwatch(); - //! @name manipulators - //@{ + //! @name manipulators + //@{ - //! Reset the timer to zero - /*! - Set the start time to the current time, returning the time since - the last reset. This does not remove the trigger if it's set nor - does it start a stopped clock. If the clock is stopped then - subsequent reset()'s will return 0. - */ - double reset(); + //! Reset the timer to zero + /*! + Set the start time to the current time, returning the time since + the last reset. This does not remove the trigger if it's set nor + does it start a stopped clock. If the clock is stopped then + subsequent reset()'s will return 0. + */ + double reset(); - //! Stop the timer - /*! - Stop the stopwatch. The time interval while stopped is not - counted by the stopwatch. stop() does not remove the trigger. - Has no effect if already stopped. - */ - void stop(); + //! Stop the timer + /*! + Stop the stopwatch. The time interval while stopped is not + counted by the stopwatch. stop() does not remove the trigger. + Has no effect if already stopped. + */ + void stop(); - //! Start the timer - /*! - Start the stopwatch. start() removes the trigger, even if the - stopwatch was already started. - */ - void start(); + //! Start the timer + /*! + Start the stopwatch. start() removes the trigger, even if the + stopwatch was already started. + */ + void start(); - //! Stop the timer and set the trigger - /*! - setTrigger() stops the clock like stop() except there's an - implicit start() the next time (non-const) getTime() is called. - This is useful when you want the clock to start the first time - you check it. - */ - void setTrigger(); + //! Stop the timer and set the trigger + /*! + setTrigger() stops the clock like stop() except there's an + implicit start() the next time (non-const) getTime() is called. + This is useful when you want the clock to start the first time + you check it. + */ + void setTrigger(); - //! Get elapsed time - /*! - Returns the time since the last reset() (or calls reset() and - returns zero if the trigger is set). - */ - double getTime(); - //! Same as getTime() - operator double(); - //@} - //! @name accessors - //@{ + //! Get elapsed time + /*! + Returns the time since the last reset() (or calls reset() and + returns zero if the trigger is set). + */ + double getTime(); + //! Same as getTime() + operator double(); + //@} + //! @name accessors + //@{ - //! Check if timer is stopped - /*! - Returns true if the stopwatch is stopped. - */ - bool isStopped() const; + //! Check if timer is stopped + /*! + Returns true if the stopwatch is stopped. + */ + bool isStopped() const; - // return the time since the last reset(). - //! Get elapsed time - /*! - Returns the time since the last reset(). This cannot trigger the - stopwatch to start and will not clear the trigger. - */ - double getTime() const; - //! Same as getTime() const - operator double() const; - //@} + // return the time since the last reset(). + //! Get elapsed time + /*! + Returns the time since the last reset(). This cannot trigger the + stopwatch to start and will not clear the trigger. + */ + double getTime() const; + //! Same as getTime() const + operator double() const; + //@} private: - double getClock() const; + double getClock() const; private: - double m_mark; - bool m_triggered; - bool m_stopped; + double m_mark; + bool m_triggered; + bool m_stopped; }; diff --git a/src/lib/base/String.cpp b/src/lib/base/String.cpp index bf6c2758e..44b18157b 100644 --- a/src/lib/base/String.cpp +++ b/src/lib/base/String.cpp @@ -1,11 +1,11 @@ /* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2014-2016 Symless Ltd. - * + * * 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 LICENSE 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 @@ -15,284 +15,244 @@ * along with this program. If not, see . */ -#include "arch/Arch.h" #include "base/String.h" +#include "arch/Arch.h" #include "common/common.h" #include "common/stdvector.h" +#include #include +#include +#include #include #include #include #include -#include -#include -#include -#include #include -#include -#include +#include +#include namespace synergy { namespace string { -String -format(const char* fmt, ...) -{ +String format(const char *fmt, ...) { + va_list args; + va_start(args, fmt); + String result = vformat(fmt, args); + va_end(args); + return result; +} + +String vformat(const char *fmt, va_list args) { + // find highest indexed substitution and the locations of substitutions + std::vector pos; + std::vector width; + std::vector index; + size_t maxIndex = 0; + const char *scan = fmt; + while (*scan) { + if (*scan == '%') { + ++scan; + if (*scan == '\0') { + break; + } else if (*scan == '%') { + // literal + index.push_back(0); + pos.push_back(static_cast((scan - 1) - fmt)); + width.push_back(2); + } else if (*scan == '{') { + // get argument index + char *end; + errno = 0; + long i = strtol(scan + 1, &end, 10); + if (errno || (i < 0) || (*end != '}')) { + // invalid index -- ignore + scan = end - 1; // BUG if there are digits? + } else { + index.push_back(i); + pos.push_back(static_cast((scan - 1) - fmt)); + width.push_back(static_cast((end - scan) + 2)); + if (i > maxIndex) { + maxIndex = i; + } + scan = end; + } + } else { + // improper escape -- ignore + } + } + ++scan; + } + + // get args + std::vector value; + std::vector length; + value.push_back("%"); + length.push_back(1); + for (int i = 0; i < maxIndex; ++i) { + const char *arg = va_arg(args, const char *); + size_t len = strnlen(arg, SIZE_MAX); + value.push_back(arg); + length.push_back(len); + } + + // compute final length + size_t resultLength = + strlen(fmt); // Compliant: we made sure that fmt variable ended with + // null(in while loop higher) + const int n = static_cast(pos.size()); + for (int i = 0; i < n; ++i) { + resultLength -= width[i]; + resultLength += length[index[i]]; + } + + // substitute + String result; + result.reserve(resultLength); + size_t src = 0; + for (int i = 0; i < n; ++i) { + result.append(fmt + src, pos[i] - src); + result.append(value[index[i]]); + src = pos[i] + width[i]; + } + result.append(fmt + src); + + return result; +} + +String sprintf(const char *fmt, ...) { + char tmp[1024]; + char *buffer = tmp; + int len = (int)(sizeof(tmp) / sizeof(tmp[0])); + String result; + while (buffer != NULL) { + // try printing into the buffer va_list args; va_start(args, fmt); - String result = vformat(fmt, args); + int n = ARCH->vsnprintf(buffer, len, fmt, args); va_end(args); - return result; -} -String -vformat(const char* fmt, va_list args) -{ - // find highest indexed substitution and the locations of substitutions - std::vector pos; - std::vector width; - std::vector index; - size_t maxIndex = 0; - const char* scan = fmt; - while ( *scan ) { - if (*scan == '%') { - ++scan; - if (*scan == '\0') { - break; - } - else if (*scan == '%') { - // literal - index.push_back(0); - pos.push_back(static_cast((scan - 1) - fmt)); - width.push_back(2); - } - else if (*scan == '{') { - // get argument index - char* end; - errno = 0; - long i = strtol(scan + 1, &end, 10); - if (errno || (i < 0) || (*end != '}')) { - // invalid index -- ignore - scan = end - 1; // BUG if there are digits? - } - else { - index.push_back(i); - pos.push_back(static_cast((scan - 1) - fmt)); - width.push_back(static_cast((end - scan) + 2)); - if (i > maxIndex) { - maxIndex = i; - } - scan = end; - } - } - else { - // improper escape -- ignore - } - } - ++scan; + // if the buffer wasn't big enough then make it bigger and try again + if (n < 0 || n > len) { + if (buffer != tmp) { + delete[] buffer; + } + len *= 2; + buffer = new char[len]; } - // get args - std::vector value; - std::vector length; - value.push_back("%"); - length.push_back(1); - for (int i = 0; i < maxIndex; ++i) { - const char* arg = va_arg(args, const char*); - size_t len = strnlen(arg, SIZE_MAX); - value.push_back(arg); - length.push_back(len); + // if it was big enough then save the string and don't try again + else { + result = buffer; + if (buffer != tmp) { + delete[] buffer; + } + buffer = NULL; } + } - // compute final length - size_t resultLength = strlen(fmt); // Compliant: we made sure that fmt variable ended with null(in while loop higher) - const int n = static_cast(pos.size()); - for (int i = 0; i < n; ++i) { - resultLength -= width[i]; - resultLength += length[index[i]]; - } - - // substitute - String result; - result.reserve(resultLength); - size_t src = 0; - for (int i = 0; i < n; ++i) { - result.append(fmt + src, pos[i] - src); - result.append(value[index[i]]); - src = pos[i] + width[i]; - } - result.append(fmt + src); - - return result; + return result; } -String -sprintf(const char* fmt, ...) -{ - char tmp[1024]; - char* buffer = tmp; - int len = (int)(sizeof(tmp) / sizeof(tmp[0])); - String result; - while (buffer != NULL) { - // try printing into the buffer - va_list args; - va_start(args, fmt); - int n = ARCH->vsnprintf(buffer, len, fmt, args); - va_end(args); +void findReplaceAll(String &subject, const String &find, + const String &replace) { + size_t pos = 0; + while ((pos = subject.find(find, pos)) != String::npos) { + subject.replace(pos, find.length(), replace); + pos += replace.length(); + } +} - // if the buffer wasn't big enough then make it bigger and try again - if (n < 0 || n > len) { - if (buffer != tmp) { - delete[] buffer; - } - len *= 2; - buffer = new char[len]; - } +String removeFileExt(String filename) { + size_t dot = filename.find_last_of('.'); - // if it was big enough then save the string and don't try again - else { - result = buffer; - if (buffer != tmp) { - delete[] buffer; - } - buffer = NULL; - } + if (dot == String::npos) { + return filename; + } + + return filename.substr(0, dot); +} + +void toHex(String &subject, int width, const char fill) { + std::stringstream ss; + ss << std::hex; + for (unsigned int i = 0; i < subject.length(); i++) { + ss << std::setw(width) << std::setfill(fill) + << (int)(unsigned char)subject[i]; + } + + subject = ss.str(); +} + +void uppercase(String &subject) { + std::transform(subject.begin(), subject.end(), subject.begin(), ::toupper); +} + +void removeChar(String &subject, const char c) { + subject.erase(std::remove(subject.begin(), subject.end(), c), subject.end()); +} + +String sizeTypeToString(size_t n) { + std::stringstream ss; + ss << n; + return ss.str(); +} + +size_t stringToSizeType(String string) { + std::istringstream iss(string); + size_t value; + iss >> value; + return value; +} + +std::vector splitString(String string, const char c) { + std::vector results; + + size_t head = 0; + size_t separator = string.find(c); + while (separator != String::npos) { + if (head != separator) { + results.push_back(string.substr(head, separator - head)); } + head = separator + 1; + separator = string.find(c, head); + } - return result; -} + if (head < string.size()) { + results.push_back(string.substr(head, string.size() - head)); + } -void -findReplaceAll( - String& subject, - const String& find, - const String& replace) -{ - size_t pos = 0; - while ((pos = subject.find(find, pos)) != String::npos) { - subject.replace(pos, find.length(), replace); - pos += replace.length(); - } -} - -String -removeFileExt(String filename) -{ - size_t dot = filename.find_last_of('.'); - - if (dot == String::npos) { - return filename; - } - - return filename.substr(0, dot); -} - -void -toHex(String& subject, int width, const char fill) -{ - std::stringstream ss; - ss << std::hex; - for (unsigned int i = 0; i < subject.length(); i++) { - ss << std::setw(width) << std::setfill(fill) << (int)(unsigned char)subject[i]; - } - - subject = ss.str(); -} - -void -uppercase(String& subject) -{ - std::transform(subject.begin(), subject.end(), subject.begin(), ::toupper); -} - -void -removeChar(String& subject, const char c) -{ - subject.erase(std::remove(subject.begin(), subject.end(), c), subject.end()); -} - -String -sizeTypeToString(size_t n) -{ - std::stringstream ss; - ss << n; - return ss.str(); -} - -size_t -stringToSizeType(String string) -{ - std::istringstream iss(string); - size_t value; - iss >> value; - return value; -} - -std::vector -splitString(String string, const char c) -{ - std::vector results; - - size_t head = 0; - size_t separator = string.find(c); - while (separator != String::npos) { - if (head!=separator) { - results.push_back(string.substr(head, separator - head)); - } - head = separator + 1; - separator = string.find(c, head); - } - - if (head < string.size()) { - results.push_back(string.substr(head, string.size() - head)); - } - - return results; + return results; } // // CaselessCmp // -bool -CaselessCmp::cmpEqual( - const String::value_type& a, - const String::value_type& b) -{ - // should use std::tolower but not in all versions of libstdc++ have it - return tolower(a) == tolower(b); +bool CaselessCmp::cmpEqual(const String::value_type &a, + const String::value_type &b) { + // should use std::tolower but not in all versions of libstdc++ have it + return tolower(a) == tolower(b); } -bool -CaselessCmp::cmpLess( - const String::value_type& a, - const String::value_type& b) -{ - // should use std::tolower but not in all versions of libstdc++ have it - return tolower(a) < tolower(b); +bool CaselessCmp::cmpLess(const String::value_type &a, + const String::value_type &b) { + // should use std::tolower but not in all versions of libstdc++ have it + return tolower(a) < tolower(b); } -bool -CaselessCmp::less(const String& a, const String& b) -{ - return std::lexicographical_compare( - a.begin(), a.end(), - b.begin(), b.end(), - &synergy::string::CaselessCmp::cmpLess); +bool CaselessCmp::less(const String &a, const String &b) { + return std::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end(), + &synergy::string::CaselessCmp::cmpLess); } -bool -CaselessCmp::equal(const String& a, const String& b) -{ - return !(less(a, b) || less(b, a)); +bool CaselessCmp::equal(const String &a, const String &b) { + return !(less(a, b) || less(b, a)); } -bool -CaselessCmp::operator()(const String& a, const String& b) const -{ - return less(a, b); +bool CaselessCmp::operator()(const String &a, const String &b) const { + return less(a, b); } -} -} +} // namespace string +} // namespace synergy diff --git a/src/lib/base/String.h b/src/lib/base/String.h index 92d707126..cd8703b3d 100644 --- a/src/lib/base/String.h +++ b/src/lib/base/String.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -45,25 +45,25 @@ characters and conversion specifications introduced by `\%': All arguments in the variable list are const char*. Positional elements are indexed from 1. */ -String format(const char* fmt, ...); +String format(const char *fmt, ...); //! Format positional arguments /*! Same as format() except takes va_list. */ -String vformat(const char* fmt, va_list); +String vformat(const char *fmt, va_list); //! Print a string using sprintf-style formatting /*! Equivalent to sprintf() except the result is returned as a String. */ -String sprintf(const char* fmt, ...); +String sprintf(const char *fmt, ...); //! Find and replace all /*! Finds \c find inside \c subject and replaces it with \c replace */ -void findReplaceAll(String& subject, const String& find, const String& replace); +void findReplaceAll(String &subject, const String &find, const String &replace); //! Remove file extension /*! @@ -75,19 +75,19 @@ String removeFileExt(String filename); /*! Convert each character in \c subject into hexdecimal form with \c width */ -void toHex(String& subject, int width, const char fill = '0'); +void toHex(String &subject, int width, const char fill = '0'); //! Convert to all uppercase /*! Convert each character in \c subject to uppercase */ -void uppercase(String& subject); +void uppercase(String &subject); //! Remove all specific char in suject /*! Remove all specific \c c in \c suject */ -void removeChar(String& subject, const char c); +void removeChar(String &subject, const char c); //! Convert a size type to a string /*! @@ -112,24 +112,23 @@ std::vector splitString(String string, const char c); This class provides case-insensitve comparison functions. */ class CaselessCmp { - public: - //! Same as less() - bool operator()(const String& a, const String& b) const; +public: + //! Same as less() + bool operator()(const String &a, const String &b) const; - //! Returns true iff \c a is lexicographically less than \c b - static bool less(const String& a, const String& b); + //! Returns true iff \c a is lexicographically less than \c b + static bool less(const String &a, const String &b); - //! Returns true iff \c a is lexicographically equal to \c b - static bool equal(const String& a, const String& b); + //! Returns true iff \c a is lexicographically equal to \c b + static bool equal(const String &a, const String &b); - //! Returns true iff \c a is lexicographically less than \c b - static bool cmpLess(const String::value_type& a, - const String::value_type& b); + //! Returns true iff \c a is lexicographically less than \c b + static bool cmpLess(const String::value_type &a, const String::value_type &b); - //! Returns true iff \c a is lexicographically equal to \c b - static bool cmpEqual(const String::value_type& a, - const String::value_type& b); + //! Returns true iff \c a is lexicographically equal to \c b + static bool cmpEqual(const String::value_type &a, + const String::value_type &b); }; -} -} +} // namespace string +} // namespace synergy diff --git a/src/lib/base/TMethodEventJob.h b/src/lib/base/TMethodEventJob.h index f50270e3d..8332ec7aa 100644 --- a/src/lib/base/TMethodEventJob.h +++ b/src/lib/base/TMethodEventJob.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 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 LICENSE 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 @@ -24,48 +24,35 @@ /*! An event job class that invokes a member function. */ -template -class TMethodEventJob : public IEventJob { +template class TMethodEventJob : public IEventJob { public: - //! run(event) invokes \c object->method(event, arg) - TMethodEventJob(T* object, - void (T::*method)(const Event&, void*), - void* arg = NULL); - virtual ~TMethodEventJob(); + //! run(event) invokes \c object->method(event, arg) + TMethodEventJob(T *object, void (T::*method)(const Event &, void *), + void *arg = NULL); + virtual ~TMethodEventJob(); - // IJob overrides - virtual void run(const Event&); + // IJob overrides + virtual void run(const Event &); private: - T* m_object; - void (T::*m_method)(const Event&, void*); - void* m_arg; + T *m_object; + void (T::*m_method)(const Event &, void *); + void *m_arg; }; template -inline -TMethodEventJob::TMethodEventJob(T* object, - void (T::*method)(const Event&, void*), void* arg) : - m_object(object), - m_method(method), - m_arg(arg) -{ - // do nothing +inline TMethodEventJob::TMethodEventJob( + T *object, void (T::*method)(const Event &, void *), void *arg) + : m_object(object), m_method(method), m_arg(arg) { + // do nothing } -template -inline -TMethodEventJob::~TMethodEventJob() -{ - // do nothing +template inline TMethodEventJob::~TMethodEventJob() { + // do nothing } -template -inline -void -TMethodEventJob::run(const Event& event) -{ - if (m_object != NULL) { - (m_object->*m_method)(event, m_arg); - } +template inline void TMethodEventJob::run(const Event &event) { + if (m_object != NULL) { + (m_object->*m_method)(event, m_arg); + } } diff --git a/src/lib/base/TMethodJob.h b/src/lib/base/TMethodJob.h index 6d38ce047..4163f16f4 100644 --- a/src/lib/base/TMethodJob.h +++ b/src/lib/base/TMethodJob.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -24,45 +24,34 @@ /*! A job class that invokes a member function. */ -template -class TMethodJob : public IJob { +template class TMethodJob : public IJob { public: - //! run() invokes \c object->method(arg) - TMethodJob(T* object, void (T::*method)(void*), void* arg = NULL); - virtual ~TMethodJob(); + //! run() invokes \c object->method(arg) + TMethodJob(T *object, void (T::*method)(void *), void *arg = NULL); + virtual ~TMethodJob(); - // IJob overrides - virtual void run(); + // IJob overrides + virtual void run(); private: - T* m_object; - void (T::*m_method)(void*); - void* m_arg; + T *m_object; + void (T::*m_method)(void *); + void *m_arg; }; template -inline -TMethodJob::TMethodJob(T* object, void (T::*method)(void*), void* arg) : - m_object(object), - m_method(method), - m_arg(arg) -{ - // do nothing +inline TMethodJob::TMethodJob(T *object, void (T::*method)(void *), + void *arg) + : m_object(object), m_method(method), m_arg(arg) { + // do nothing } -template -inline -TMethodJob::~TMethodJob() -{ - // do nothing +template inline TMethodJob::~TMethodJob() { + // do nothing } -template -inline -void -TMethodJob::run() -{ - if (m_object != NULL) { - (m_object->*m_method)(m_arg); - } +template inline void TMethodJob::run() { + if (m_object != NULL) { + (m_object->*m_method)(m_arg); + } } diff --git a/src/lib/base/Unicode.cpp b/src/lib/base/Unicode.cpp index 2d21dd3bb..48311f7ea 100644 --- a/src/lib/base/Unicode.cpp +++ b/src/lib/base/Unicode.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -16,8 +16,8 @@ * along with this program. If not, see . */ -#include "arch/Arch.h" #include "base/Unicode.h" +#include "arch/Arch.h" #include @@ -25,768 +25,686 @@ // local utility functions // -inline -static -UInt16 -decode16(const UInt8* n, bool byteSwapped) -{ - union x16 { - UInt8 n8[2]; - UInt16 n16; - } c; - if (byteSwapped) { - c.n8[0] = n[1]; - c.n8[1] = n[0]; - } - else { - c.n8[0] = n[0]; - c.n8[1] = n[1]; - } - return c.n16; +inline static UInt16 decode16(const UInt8 *n, bool byteSwapped) { + union x16 { + UInt8 n8[2]; + UInt16 n16; + } c; + if (byteSwapped) { + c.n8[0] = n[1]; + c.n8[1] = n[0]; + } else { + c.n8[0] = n[0]; + c.n8[1] = n[1]; + } + return c.n16; } -inline -static -UInt32 -decode32(const UInt8* n, bool byteSwapped) -{ - union x32 { - UInt8 n8[4]; - UInt32 n32; - } c; - if (byteSwapped) { - c.n8[0] = n[3]; - c.n8[1] = n[2]; - c.n8[2] = n[1]; - c.n8[3] = n[0]; - } - else { - c.n8[0] = n[0]; - c.n8[1] = n[1]; - c.n8[2] = n[2]; - c.n8[3] = n[3]; - } - return c.n32; +inline static UInt32 decode32(const UInt8 *n, bool byteSwapped) { + union x32 { + UInt8 n8[4]; + UInt32 n32; + } c; + if (byteSwapped) { + c.n8[0] = n[3]; + c.n8[1] = n[2]; + c.n8[2] = n[1]; + c.n8[3] = n[0]; + } else { + c.n8[0] = n[0]; + c.n8[1] = n[1]; + c.n8[2] = n[2]; + c.n8[3] = n[3]; + } + return c.n32; } -inline -static -void -resetError(bool* errors) -{ - if (errors != NULL) { - *errors = false; - } +inline static void resetError(bool *errors) { + if (errors != NULL) { + *errors = false; + } } -inline -static -void -setError(bool* errors) -{ - if (errors != NULL) { - *errors = true; - } +inline static void setError(bool *errors) { + if (errors != NULL) { + *errors = true; + } } - // // Unicode // -UInt32 Unicode::s_invalid = 0x0000ffff; -UInt32 Unicode::s_replacement = 0x0000fffd; +UInt32 Unicode::s_invalid = 0x0000ffff; +UInt32 Unicode::s_replacement = 0x0000fffd; -bool -Unicode::isUTF8(const String& src) -{ - // convert and test each character - const UInt8* data = reinterpret_cast(src.c_str()); - for (UInt32 n = (UInt32)src.size(); n > 0; ) { - if (fromUTF8(data, n) == s_invalid) { - return false; - } +bool Unicode::isUTF8(const String &src) { + // convert and test each character + const UInt8 *data = reinterpret_cast(src.c_str()); + for (UInt32 n = (UInt32)src.size(); n > 0;) { + if (fromUTF8(data, n) == s_invalid) { + return false; } - return true; + } + return true; } -String -Unicode::UTF8ToUCS2(const String& src, bool* errors) -{ - // default to success - resetError(errors); +String Unicode::UTF8ToUCS2(const String &src, bool *errors) { + // default to success + resetError(errors); - // get size of input string and reserve some space in output - UInt32 n = (UInt32)src.size(); - String dst; - dst.reserve(2 * n); + // get size of input string and reserve some space in output + UInt32 n = (UInt32)src.size(); + String dst; + dst.reserve(2 * n); - // convert each character - const UInt8* data = reinterpret_cast(src.c_str()); - while (n > 0) { - UInt32 c = fromUTF8(data, n); - if (c == s_invalid) { - c = s_replacement; - } - else if (c >= 0x00010000) { - setError(errors); - c = s_replacement; - } - UInt16 ucs2 = static_cast(c); - dst.append(reinterpret_cast(&ucs2), 2); + // convert each character + const UInt8 *data = reinterpret_cast(src.c_str()); + while (n > 0) { + UInt32 c = fromUTF8(data, n); + if (c == s_invalid) { + c = s_replacement; + } else if (c >= 0x00010000) { + setError(errors); + c = s_replacement; } + UInt16 ucs2 = static_cast(c); + dst.append(reinterpret_cast(&ucs2), 2); + } - return dst; + return dst; } -String -Unicode::UTF8ToUCS4(const String& src, bool* errors) -{ - // default to success - resetError(errors); +String Unicode::UTF8ToUCS4(const String &src, bool *errors) { + // default to success + resetError(errors); - // get size of input string and reserve some space in output - UInt32 n = (UInt32)src.size(); - String dst; - dst.reserve(4 * n); + // get size of input string and reserve some space in output + UInt32 n = (UInt32)src.size(); + String dst; + dst.reserve(4 * n); - // convert each character - const UInt8* data = reinterpret_cast(src.c_str()); - while (n > 0) { - UInt32 c = fromUTF8(data, n); - if (c == s_invalid) { - c = s_replacement; - } - dst.append(reinterpret_cast(&c), 4); + // convert each character + const UInt8 *data = reinterpret_cast(src.c_str()); + while (n > 0) { + UInt32 c = fromUTF8(data, n); + if (c == s_invalid) { + c = s_replacement; } + dst.append(reinterpret_cast(&c), 4); + } - return dst; + return dst; } -String -Unicode::UTF8ToUTF16(const String& src, bool* errors) -{ - // default to success - resetError(errors); +String Unicode::UTF8ToUTF16(const String &src, bool *errors) { + // default to success + resetError(errors); - // get size of input string and reserve some space in output - UInt32 n = (UInt32)src.size(); - String dst; - dst.reserve(2 * n); + // get size of input string and reserve some space in output + UInt32 n = (UInt32)src.size(); + String dst; + dst.reserve(2 * n); - // convert each character - const UInt8* data = reinterpret_cast(src.c_str()); - while (n > 0) { - UInt32 c = fromUTF8(data, n); - if (c == s_invalid) { - c = s_replacement; - } - else if (c >= 0x00110000) { - setError(errors); - c = s_replacement; - } - if (c < 0x00010000) { - UInt16 ucs2 = static_cast(c); - dst.append(reinterpret_cast(&ucs2), 2); - } - else { - c -= 0x00010000; - UInt16 utf16h = static_cast((c >> 10) + 0xd800); - UInt16 utf16l = static_cast((c & 0x03ff) + 0xdc00); - dst.append(reinterpret_cast(&utf16h), 2); - dst.append(reinterpret_cast(&utf16l), 2); - } + // convert each character + const UInt8 *data = reinterpret_cast(src.c_str()); + while (n > 0) { + UInt32 c = fromUTF8(data, n); + if (c == s_invalid) { + c = s_replacement; + } else if (c >= 0x00110000) { + setError(errors); + c = s_replacement; } - - return dst; -} - -String -Unicode::UTF8ToUTF32(const String& src, bool* errors) -{ - // default to success - resetError(errors); - - // get size of input string and reserve some space in output - UInt32 n = (UInt32)src.size(); - String dst; - dst.reserve(4 * n); - - // convert each character - const UInt8* data = reinterpret_cast(src.c_str()); - while (n > 0) { - UInt32 c = fromUTF8(data, n); - if (c == s_invalid) { - c = s_replacement; - } - else if (c >= 0x00110000) { - setError(errors); - c = s_replacement; - } - dst.append(reinterpret_cast(&c), 4); + if (c < 0x00010000) { + UInt16 ucs2 = static_cast(c); + dst.append(reinterpret_cast(&ucs2), 2); + } else { + c -= 0x00010000; + UInt16 utf16h = static_cast((c >> 10) + 0xd800); + UInt16 utf16l = static_cast((c & 0x03ff) + 0xdc00); + dst.append(reinterpret_cast(&utf16h), 2); + dst.append(reinterpret_cast(&utf16l), 2); } + } - return dst; + return dst; } -String -Unicode::UTF8ToText(const String& src, bool* errors) -{ - // default to success - resetError(errors); +String Unicode::UTF8ToUTF32(const String &src, bool *errors) { + // default to success + resetError(errors); - // convert to wide char - UInt32 size; - wchar_t* tmp = UTF8ToWideChar(src, size, errors); + // get size of input string and reserve some space in output + UInt32 n = (UInt32)src.size(); + String dst; + dst.reserve(4 * n); - // convert string to multibyte - int len = ARCH->convStringWCToMB(NULL, tmp, size, errors); - char* mbs = new char[len + 1]; - ARCH->convStringWCToMB(mbs, tmp, size, errors); - String text(mbs, len); + // convert each character + const UInt8 *data = reinterpret_cast(src.c_str()); + while (n > 0) { + UInt32 c = fromUTF8(data, n); + if (c == s_invalid) { + c = s_replacement; + } else if (c >= 0x00110000) { + setError(errors); + c = s_replacement; + } + dst.append(reinterpret_cast(&c), 4); + } - // clean up - delete[] mbs; - delete[] tmp; - - return text; + return dst; } -String -Unicode::UCS2ToUTF8(const String& src, bool* errors) -{ - // default to success - resetError(errors); +String Unicode::UTF8ToText(const String &src, bool *errors) { + // default to success + resetError(errors); - // convert - UInt32 n = (UInt32)src.size() >> 1; - return doUCS2ToUTF8(reinterpret_cast(src.data()), n, errors); + // convert to wide char + UInt32 size; + wchar_t *tmp = UTF8ToWideChar(src, size, errors); + + // convert string to multibyte + int len = ARCH->convStringWCToMB(NULL, tmp, size, errors); + char *mbs = new char[len + 1]; + ARCH->convStringWCToMB(mbs, tmp, size, errors); + String text(mbs, len); + + // clean up + delete[] mbs; + delete[] tmp; + + return text; } -String -Unicode::UCS4ToUTF8(const String& src, bool* errors) -{ - // default to success - resetError(errors); +String Unicode::UCS2ToUTF8(const String &src, bool *errors) { + // default to success + resetError(errors); - // convert - UInt32 n = (UInt32)src.size() >> 2; - return doUCS4ToUTF8(reinterpret_cast(src.data()), n, errors); + // convert + UInt32 n = (UInt32)src.size() >> 1; + return doUCS2ToUTF8(reinterpret_cast(src.data()), n, errors); } -String -Unicode::UTF16ToUTF8(const String& src, bool* errors) -{ - // default to success - resetError(errors); +String Unicode::UCS4ToUTF8(const String &src, bool *errors) { + // default to success + resetError(errors); - // convert - UInt32 n = (UInt32)src.size() >> 1; - return doUTF16ToUTF8(reinterpret_cast(src.data()), n, errors); + // convert + UInt32 n = (UInt32)src.size() >> 2; + return doUCS4ToUTF8(reinterpret_cast(src.data()), n, errors); } -String -Unicode::UTF32ToUTF8(const String& src, bool* errors) -{ - // default to success - resetError(errors); +String Unicode::UTF16ToUTF8(const String &src, bool *errors) { + // default to success + resetError(errors); - // convert - UInt32 n = (UInt32)src.size() >> 2; - return doUTF32ToUTF8(reinterpret_cast(src.data()), n, errors); + // convert + UInt32 n = (UInt32)src.size() >> 1; + return doUTF16ToUTF8(reinterpret_cast(src.data()), n, errors); } -String -Unicode::textToUTF8(const String& src, bool* errors, IArchString::EWideCharEncoding encoding) -{ - // default to success - resetError(errors); +String Unicode::UTF32ToUTF8(const String &src, bool *errors) { + // default to success + resetError(errors); - // convert string to wide characters - UInt32 n = (UInt32)src.size(); - int len = ARCH->convStringMBToWC(NULL, src.c_str(), n, errors); - wchar_t* wcs = new wchar_t[len + 1]; - ARCH->convStringMBToWC(wcs, src.c_str(), n, errors); - - // convert to UTF8 - String utf8 = wideCharToUTF8(wcs, len, errors, encoding); - - // clean up - delete[] wcs; - - return utf8; + // convert + UInt32 n = (UInt32)src.size() >> 2; + return doUTF32ToUTF8(reinterpret_cast(src.data()), n, errors); } -wchar_t* -Unicode::UTF8ToWideChar(const String& src, UInt32& size, bool* errors) -{ - // convert to platform's wide character encoding - String tmp; - switch (ARCH->getWideCharEncoding()) { - case IArchString::kUCS2: - tmp = UTF8ToUCS2(src, errors); - size = (UInt32)tmp.size() >> 1; - break; +String Unicode::textToUTF8(const String &src, bool *errors, + IArchString::EWideCharEncoding encoding) { + // default to success + resetError(errors); - case IArchString::kUCS4: - tmp = UTF8ToUCS4(src, errors); - size = (UInt32)tmp.size() >> 2; - break; + // convert string to wide characters + UInt32 n = (UInt32)src.size(); + int len = ARCH->convStringMBToWC(NULL, src.c_str(), n, errors); + wchar_t *wcs = new wchar_t[len + 1]; + ARCH->convStringMBToWC(wcs, src.c_str(), n, errors); - case IArchString::kUTF16: - tmp = UTF8ToUTF16(src, errors); - size = (UInt32)tmp.size() >> 1; - break; + // convert to UTF8 + String utf8 = wideCharToUTF8(wcs, len, errors, encoding); - case IArchString::kUTF32: - tmp = UTF8ToUTF32(src, errors); - size = (UInt32)tmp.size() >> 2; - break; + // clean up + delete[] wcs; + + return utf8; +} + +wchar_t *Unicode::UTF8ToWideChar(const String &src, UInt32 &size, + bool *errors) { + // convert to platform's wide character encoding + String tmp; + switch (ARCH->getWideCharEncoding()) { + case IArchString::kUCS2: + tmp = UTF8ToUCS2(src, errors); + size = (UInt32)tmp.size() >> 1; + break; + + case IArchString::kUCS4: + tmp = UTF8ToUCS4(src, errors); + size = (UInt32)tmp.size() >> 2; + break; + + case IArchString::kUTF16: + tmp = UTF8ToUTF16(src, errors); + size = (UInt32)tmp.size() >> 1; + break; + + case IArchString::kUTF32: + tmp = UTF8ToUTF32(src, errors); + size = (UInt32)tmp.size() >> 2; + break; + + default: + assert(0 && "unknown wide character encoding"); + } + + // copy to a wchar_t array + wchar_t *dst = new wchar_t[size]; + ::memcpy(dst, tmp.data(), sizeof(wchar_t) * size); + return dst; +} + +String Unicode::wideCharToUTF8(const wchar_t *src, UInt32 size, bool *errors, + IArchString::EWideCharEncoding encoding) { + if (encoding == IArchString::kPlatformDetermined) { + encoding = ARCH->getWideCharEncoding(); + } + // convert from platform's wide character encoding. + // note -- this must include a wide nul character (independent of + // the String's nul character). + switch (encoding) { + case IArchString::kUCS2: + return doUCS2ToUTF8(reinterpret_cast(src), size, errors); + + case IArchString::kUCS4: + return doUCS4ToUTF8(reinterpret_cast(src), size, errors); + + case IArchString::kUTF16: + return doUTF16ToUTF8(reinterpret_cast(src), size, errors); + + case IArchString::kUTF32: + return doUTF32ToUTF8(reinterpret_cast(src), size, errors); + + default: + assert(0 && "unknown wide character encoding"); + return String(); + } +} + +String Unicode::doUCS2ToUTF8(const UInt8 *data, UInt32 n, bool *errors) { + // make some space + String dst; + dst.reserve(n); + + // check if first character is 0xfffe or 0xfeff + bool byteSwapped = false; + if (n >= 1) { + switch (decode16(data, false)) { + case 0x0000feff: + data += 2; + --n; + break; + + case 0x0000fffe: + byteSwapped = true; + data += 2; + --n; + break; default: - assert(0 && "unknown wide character encoding"); + break; } + } - // copy to a wchar_t array - wchar_t* dst = new wchar_t[size]; - ::memcpy(dst, tmp.data(), sizeof(wchar_t) * size); - return dst; + // convert each character + for (; n > 0; --n) { + UInt32 c = decode16(data, byteSwapped); + toUTF8(dst, c, errors); + data += 2; + } + + return dst; } -String -Unicode::wideCharToUTF8(const wchar_t* src, UInt32 size, bool* errors, IArchString::EWideCharEncoding encoding) -{ - if (encoding == IArchString::kPlatformDetermined) { - encoding = ARCH->getWideCharEncoding(); - } - // convert from platform's wide character encoding. - // note -- this must include a wide nul character (independent of - // the String's nul character). - switch (encoding) { - case IArchString::kUCS2: - return doUCS2ToUTF8(reinterpret_cast(src), size, errors); +String Unicode::doUCS4ToUTF8(const UInt8 *data, UInt32 n, bool *errors) { + // make some space + String dst; + dst.reserve(n); - case IArchString::kUCS4: - return doUCS4ToUTF8(reinterpret_cast(src), size, errors); + // check if first character is 0xfffe or 0xfeff + bool byteSwapped = false; + if (n >= 1) { + switch (decode32(data, false)) { + case 0x0000feff: + data += 4; + --n; + break; - case IArchString::kUTF16: - return doUTF16ToUTF8(reinterpret_cast(src), size, errors); - - case IArchString::kUTF32: - return doUTF32ToUTF8(reinterpret_cast(src), size, errors); + case 0x0000fffe: + byteSwapped = true; + data += 4; + --n; + break; default: - assert(0 && "unknown wide character encoding"); - return String(); + break; } + } + + // convert each character + for (; n > 0; --n) { + UInt32 c = decode32(data, byteSwapped); + toUTF8(dst, c, errors); + data += 4; + } + + return dst; } -String -Unicode::doUCS2ToUTF8(const UInt8* data, UInt32 n, bool* errors) -{ - // make some space - String dst; - dst.reserve(n); +String Unicode::doUTF16ToUTF8(const UInt8 *data, UInt32 n, bool *errors) { + // make some space + String dst; + dst.reserve(n); - // check if first character is 0xfffe or 0xfeff - bool byteSwapped = false; - if (n >= 1) { - switch (decode16(data, false)) { - case 0x0000feff: - data += 2; - --n; - break; + // check if first character is 0xfffe or 0xfeff + bool byteSwapped = false; + if (n >= 1) { + switch (decode16(data, false)) { + case 0x0000feff: + data += 2; + --n; + break; - case 0x0000fffe: - byteSwapped = true; - data += 2; - --n; - break; - - default: - break; - } - } - - // convert each character - for (; n > 0; --n) { - UInt32 c = decode16(data, byteSwapped); - toUTF8(dst, c, errors); - data += 2; - } - - return dst; -} - -String -Unicode::doUCS4ToUTF8(const UInt8* data, UInt32 n, bool* errors) -{ - // make some space - String dst; - dst.reserve(n); - - // check if first character is 0xfffe or 0xfeff - bool byteSwapped = false; - if (n >= 1) { - switch (decode32(data, false)) { - case 0x0000feff: - data += 4; - --n; - break; - - case 0x0000fffe: - byteSwapped = true; - data += 4; - --n; - break; - - default: - break; - } - } - - // convert each character - for (; n > 0; --n) { - UInt32 c = decode32(data, byteSwapped); - toUTF8(dst, c, errors); - data += 4; - } - - return dst; -} - -String -Unicode::doUTF16ToUTF8(const UInt8* data, UInt32 n, bool* errors) -{ - // make some space - String dst; - dst.reserve(n); - - // check if first character is 0xfffe or 0xfeff - bool byteSwapped = false; - if (n >= 1) { - switch (decode16(data, false)) { - case 0x0000feff: - data += 2; - --n; - break; - - case 0x0000fffe: - byteSwapped = true; - data += 2; - --n; - break; - - default: - break; - } - } - - // convert each character - while (n > 0) { - UInt32 c = decode16(data, byteSwapped); - if (c < 0x0000d800 || c > 0x0000dfff) { - toUTF8(dst, c, errors); - } - else if (n == 1) { - // error -- missing second word - setError(errors); - toUTF8(dst, s_replacement, NULL); - } - else if (c >= 0x0000d800 && c <= 0x0000dbff) { - UInt32 c2 = decode16(data, byteSwapped); - data += 2; - --n; - if (c2 < 0x0000dc00 || c2 > 0x0000dfff) { - // error -- [d800,dbff] not followed by [dc00,dfff] - setError(errors); - toUTF8(dst, s_replacement, NULL); - } - else { - c = (((c - 0x0000d800) << 10) | (c2 - 0x0000dc00)) + 0x00010000; - toUTF8(dst, c, errors); - } - } - else { - // error -- [dc00,dfff] without leading [d800,dbff] - setError(errors); - toUTF8(dst, s_replacement, NULL); - } - data += 2; - --n; - } - - return dst; -} - -String -Unicode::doUTF32ToUTF8(const UInt8* data, UInt32 n, bool* errors) -{ - // make some space - String dst; - dst.reserve(n); - - // check if first character is 0xfffe or 0xfeff - bool byteSwapped = false; - if (n >= 1) { - switch (decode32(data, false)) { - case 0x0000feff: - data += 4; - --n; - break; - - case 0x0000fffe: - byteSwapped = true; - data += 4; - --n; - break; - - default: - break; - } - } - - // convert each character - for (; n > 0; --n) { - UInt32 c = decode32(data, byteSwapped); - if (c >= 0x00110000) { - setError(errors); - c = s_replacement; - } - toUTF8(dst, c, errors); - data += 4; - } - - return dst; -} - -UInt32 -Unicode::fromUTF8(const UInt8*& data, UInt32& n) -{ - assert(data != NULL); - assert(n != 0); - - // compute character encoding length, checking for overlong - // sequences (i.e. characters that don't use the shortest - // possible encoding). - UInt32 size; - if (data[0] < 0x80) { - // 0xxxxxxx - size = 1; - } - else if (data[0] < 0xc0) { - // 10xxxxxx -- in the middle of a multibyte character. counts - // as one invalid character. - --n; - ++data; - return s_invalid; - } - else if (data[0] < 0xe0) { - // 110xxxxx - size = 2; - } - else if (data[0] < 0xf0) { - // 1110xxxx - size = 3; - } - else if (data[0] < 0xf8) { - // 11110xxx - size = 4; - } - else if (data[0] < 0xfc) { - // 111110xx - size = 5; - } - else if (data[0] < 0xfe) { - // 1111110x - size = 6; - } - else { - // invalid sequence. dunno how many bytes to skip so skip one. - --n; - ++data; - return s_invalid; - } - - // make sure we have enough data - if (size > n) { - data += n; - n = 0; - return s_invalid; - } - - // extract character - UInt32 c; - switch (size) { - case 1: - c = static_cast(data[0]); - break; - - case 2: - c = ((static_cast(data[0]) & 0x1f) << 6) | - ((static_cast(data[1]) & 0x3f) ); - break; - - case 3: - c = ((static_cast(data[0]) & 0x0f) << 12) | - ((static_cast(data[1]) & 0x3f) << 6) | - ((static_cast(data[2]) & 0x3f) ); - break; - - case 4: - c = ((static_cast(data[0]) & 0x07) << 18) | - ((static_cast(data[1]) & 0x3f) << 12) | - ((static_cast(data[2]) & 0x3f) << 6) | - ((static_cast(data[3]) & 0x3f) ); - break; - - case 5: - c = ((static_cast(data[0]) & 0x03) << 24) | - ((static_cast(data[1]) & 0x3f) << 18) | - ((static_cast(data[2]) & 0x3f) << 12) | - ((static_cast(data[3]) & 0x3f) << 6) | - ((static_cast(data[4]) & 0x3f) ); - break; - - case 6: - c = ((static_cast(data[0]) & 0x01) << 30) | - ((static_cast(data[1]) & 0x3f) << 24) | - ((static_cast(data[2]) & 0x3f) << 18) | - ((static_cast(data[3]) & 0x3f) << 12) | - ((static_cast(data[4]) & 0x3f) << 6) | - ((static_cast(data[5]) & 0x3f) ); - break; + case 0x0000fffe: + byteSwapped = true; + data += 2; + --n; + break; default: - assert(0 && "invalid size"); - return s_invalid; + break; } + } - // check that all bytes after the first have the pattern 10xxxxxx. - // truncated sequences are treated as a single malformed character. - bool truncated = false; - switch (size) { - case 6: - if ((data[5] & 0xc0) != 0x80) { - truncated = true; - size = 5; - } - // fall through - - case 5: - if ((data[4] & 0xc0) != 0x80) { - truncated = true; - size = 4; - } - // fall through - - case 4: - if ((data[3] & 0xc0) != 0x80) { - truncated = true; - size = 3; - } - // fall through - - case 3: - if ((data[2] & 0xc0) != 0x80) { - truncated = true; - size = 2; - } - // fall through - - case 2: - if ((data[1] & 0xc0) != 0x80) { - truncated = true; - size = 1; - } - } - - // update parameters - data += size; - n -= size; - - // invalid if sequence was truncated - if (truncated) { - return s_invalid; - } - - // check for characters that didn't use the smallest possible encoding - static UInt32 s_minChar[] = { - 0, - 0x00000000, - 0x00000080, - 0x00000800, - 0x00010000, - 0x00200000, - 0x04000000 - }; - if (c < s_minChar[size]) { - return s_invalid; - } - - // check for characters not in ISO-10646 - if (c >= 0x0000d800 && c <= 0x0000dfff) { - return s_invalid; - } - if (c >= 0x0000fffe && c <= 0x0000ffff) { - return s_invalid; - } - - return c; -} - -void -Unicode::toUTF8(String& dst, UInt32 c, bool* errors) -{ - UInt8 data[6]; - - // handle characters outside the valid range - if ((c >= 0x0000d800 && c <= 0x0000dfff) || c >= 0x80000000) { + // convert each character + while (n > 0) { + UInt32 c = decode16(data, byteSwapped); + if (c < 0x0000d800 || c > 0x0000dfff) { + toUTF8(dst, c, errors); + } else if (n == 1) { + // error -- missing second word + setError(errors); + toUTF8(dst, s_replacement, NULL); + } else if (c >= 0x0000d800 && c <= 0x0000dbff) { + UInt32 c2 = decode16(data, byteSwapped); + data += 2; + --n; + if (c2 < 0x0000dc00 || c2 > 0x0000dfff) { + // error -- [d800,dbff] not followed by [dc00,dfff] setError(errors); - c = s_replacement; + toUTF8(dst, s_replacement, NULL); + } else { + c = (((c - 0x0000d800) << 10) | (c2 - 0x0000dc00)) + 0x00010000; + toUTF8(dst, c, errors); + } + } else { + // error -- [dc00,dfff] without leading [d800,dbff] + setError(errors); + toUTF8(dst, s_replacement, NULL); } + data += 2; + --n; + } - // convert to UTF-8 - if (c < 0x00000080) { - data[0] = static_cast(c); - dst.append(reinterpret_cast(data), 1); - } - else if (c < 0x00000800) { - data[0] = static_cast(((c >> 6) & 0x0000001f) + 0xc0); - data[1] = static_cast((c & 0x0000003f) + 0x80); - dst.append(reinterpret_cast(data), 2); - } - else if (c < 0x00010000) { - data[0] = static_cast(((c >> 12) & 0x0000000f) + 0xe0); - data[1] = static_cast(((c >> 6) & 0x0000003f) + 0x80); - data[2] = static_cast((c & 0x0000003f) + 0x80); - dst.append(reinterpret_cast(data), 3); - } - else if (c < 0x00200000) { - data[0] = static_cast(((c >> 18) & 0x00000007) + 0xf0); - data[1] = static_cast(((c >> 12) & 0x0000003f) + 0x80); - data[2] = static_cast(((c >> 6) & 0x0000003f) + 0x80); - data[3] = static_cast((c & 0x0000003f) + 0x80); - dst.append(reinterpret_cast(data), 4); - } - else if (c < 0x04000000) { - data[0] = static_cast(((c >> 24) & 0x00000003) + 0xf8); - data[1] = static_cast(((c >> 18) & 0x0000003f) + 0x80); - data[2] = static_cast(((c >> 12) & 0x0000003f) + 0x80); - data[3] = static_cast(((c >> 6) & 0x0000003f) + 0x80); - data[4] = static_cast((c & 0x0000003f) + 0x80); - dst.append(reinterpret_cast(data), 5); - } - else if (c < 0x80000000) { - data[0] = static_cast(((c >> 30) & 0x00000001) + 0xfc); - data[1] = static_cast(((c >> 24) & 0x0000003f) + 0x80); - data[2] = static_cast(((c >> 18) & 0x0000003f) + 0x80); - data[3] = static_cast(((c >> 12) & 0x0000003f) + 0x80); - data[4] = static_cast(((c >> 6) & 0x0000003f) + 0x80); - data[5] = static_cast((c & 0x0000003f) + 0x80); - dst.append(reinterpret_cast(data), 6); - } - else { - assert(0 && "character out of range"); - } + return dst; +} + +String Unicode::doUTF32ToUTF8(const UInt8 *data, UInt32 n, bool *errors) { + // make some space + String dst; + dst.reserve(n); + + // check if first character is 0xfffe or 0xfeff + bool byteSwapped = false; + if (n >= 1) { + switch (decode32(data, false)) { + case 0x0000feff: + data += 4; + --n; + break; + + case 0x0000fffe: + byteSwapped = true; + data += 4; + --n; + break; + + default: + break; + } + } + + // convert each character + for (; n > 0; --n) { + UInt32 c = decode32(data, byteSwapped); + if (c >= 0x00110000) { + setError(errors); + c = s_replacement; + } + toUTF8(dst, c, errors); + data += 4; + } + + return dst; +} + +UInt32 Unicode::fromUTF8(const UInt8 *&data, UInt32 &n) { + assert(data != NULL); + assert(n != 0); + + // compute character encoding length, checking for overlong + // sequences (i.e. characters that don't use the shortest + // possible encoding). + UInt32 size; + if (data[0] < 0x80) { + // 0xxxxxxx + size = 1; + } else if (data[0] < 0xc0) { + // 10xxxxxx -- in the middle of a multibyte character. counts + // as one invalid character. + --n; + ++data; + return s_invalid; + } else if (data[0] < 0xe0) { + // 110xxxxx + size = 2; + } else if (data[0] < 0xf0) { + // 1110xxxx + size = 3; + } else if (data[0] < 0xf8) { + // 11110xxx + size = 4; + } else if (data[0] < 0xfc) { + // 111110xx + size = 5; + } else if (data[0] < 0xfe) { + // 1111110x + size = 6; + } else { + // invalid sequence. dunno how many bytes to skip so skip one. + --n; + ++data; + return s_invalid; + } + + // make sure we have enough data + if (size > n) { + data += n; + n = 0; + return s_invalid; + } + + // extract character + UInt32 c; + switch (size) { + case 1: + c = static_cast(data[0]); + break; + + case 2: + c = ((static_cast(data[0]) & 0x1f) << 6) | + ((static_cast(data[1]) & 0x3f)); + break; + + case 3: + c = ((static_cast(data[0]) & 0x0f) << 12) | + ((static_cast(data[1]) & 0x3f) << 6) | + ((static_cast(data[2]) & 0x3f)); + break; + + case 4: + c = ((static_cast(data[0]) & 0x07) << 18) | + ((static_cast(data[1]) & 0x3f) << 12) | + ((static_cast(data[2]) & 0x3f) << 6) | + ((static_cast(data[3]) & 0x3f)); + break; + + case 5: + c = ((static_cast(data[0]) & 0x03) << 24) | + ((static_cast(data[1]) & 0x3f) << 18) | + ((static_cast(data[2]) & 0x3f) << 12) | + ((static_cast(data[3]) & 0x3f) << 6) | + ((static_cast(data[4]) & 0x3f)); + break; + + case 6: + c = ((static_cast(data[0]) & 0x01) << 30) | + ((static_cast(data[1]) & 0x3f) << 24) | + ((static_cast(data[2]) & 0x3f) << 18) | + ((static_cast(data[3]) & 0x3f) << 12) | + ((static_cast(data[4]) & 0x3f) << 6) | + ((static_cast(data[5]) & 0x3f)); + break; + + default: + assert(0 && "invalid size"); + return s_invalid; + } + + // check that all bytes after the first have the pattern 10xxxxxx. + // truncated sequences are treated as a single malformed character. + bool truncated = false; + switch (size) { + case 6: + if ((data[5] & 0xc0) != 0x80) { + truncated = true; + size = 5; + } + // fall through + + case 5: + if ((data[4] & 0xc0) != 0x80) { + truncated = true; + size = 4; + } + // fall through + + case 4: + if ((data[3] & 0xc0) != 0x80) { + truncated = true; + size = 3; + } + // fall through + + case 3: + if ((data[2] & 0xc0) != 0x80) { + truncated = true; + size = 2; + } + // fall through + + case 2: + if ((data[1] & 0xc0) != 0x80) { + truncated = true; + size = 1; + } + } + + // update parameters + data += size; + n -= size; + + // invalid if sequence was truncated + if (truncated) { + return s_invalid; + } + + // check for characters that didn't use the smallest possible encoding + static UInt32 s_minChar[] = {0, 0x00000000, 0x00000080, 0x00000800, + 0x00010000, 0x00200000, 0x04000000}; + if (c < s_minChar[size]) { + return s_invalid; + } + + // check for characters not in ISO-10646 + if (c >= 0x0000d800 && c <= 0x0000dfff) { + return s_invalid; + } + if (c >= 0x0000fffe && c <= 0x0000ffff) { + return s_invalid; + } + + return c; +} + +void Unicode::toUTF8(String &dst, UInt32 c, bool *errors) { + UInt8 data[6]; + + // handle characters outside the valid range + if ((c >= 0x0000d800 && c <= 0x0000dfff) || c >= 0x80000000) { + setError(errors); + c = s_replacement; + } + + // convert to UTF-8 + if (c < 0x00000080) { + data[0] = static_cast(c); + dst.append(reinterpret_cast(data), 1); + } else if (c < 0x00000800) { + data[0] = static_cast(((c >> 6) & 0x0000001f) + 0xc0); + data[1] = static_cast((c & 0x0000003f) + 0x80); + dst.append(reinterpret_cast(data), 2); + } else if (c < 0x00010000) { + data[0] = static_cast(((c >> 12) & 0x0000000f) + 0xe0); + data[1] = static_cast(((c >> 6) & 0x0000003f) + 0x80); + data[2] = static_cast((c & 0x0000003f) + 0x80); + dst.append(reinterpret_cast(data), 3); + } else if (c < 0x00200000) { + data[0] = static_cast(((c >> 18) & 0x00000007) + 0xf0); + data[1] = static_cast(((c >> 12) & 0x0000003f) + 0x80); + data[2] = static_cast(((c >> 6) & 0x0000003f) + 0x80); + data[3] = static_cast((c & 0x0000003f) + 0x80); + dst.append(reinterpret_cast(data), 4); + } else if (c < 0x04000000) { + data[0] = static_cast(((c >> 24) & 0x00000003) + 0xf8); + data[1] = static_cast(((c >> 18) & 0x0000003f) + 0x80); + data[2] = static_cast(((c >> 12) & 0x0000003f) + 0x80); + data[3] = static_cast(((c >> 6) & 0x0000003f) + 0x80); + data[4] = static_cast((c & 0x0000003f) + 0x80); + dst.append(reinterpret_cast(data), 5); + } else if (c < 0x80000000) { + data[0] = static_cast(((c >> 30) & 0x00000001) + 0xfc); + data[1] = static_cast(((c >> 24) & 0x0000003f) + 0x80); + data[2] = static_cast(((c >> 18) & 0x0000003f) + 0x80); + data[3] = static_cast(((c >> 12) & 0x0000003f) + 0x80); + data[4] = static_cast(((c >> 6) & 0x0000003f) + 0x80); + data[5] = static_cast((c & 0x0000003f) + 0x80); + dst.append(reinterpret_cast(data), 6); + } else { + assert(0 && "character out of range"); + } } diff --git a/src/lib/base/Unicode.h b/src/lib/base/Unicode.h index 91cb92983..f9958f224 100644 --- a/src/lib/base/Unicode.h +++ b/src/lib/base/Unicode.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -18,8 +18,8 @@ #pragma once -#include "base/String.h" #include "arch/IArchString.h" +#include "base/String.h" #include "common/basic_types.h" //! Unicode utility functions @@ -29,118 +29,119 @@ encodings and the current locale encoding. */ class Unicode { public: - //! @name accessors - //@{ + //! @name accessors + //@{ - //! Test UTF-8 string for validity - /*! - Returns true iff the string contains a valid sequence of UTF-8 - encoded characters. - */ - static bool isUTF8(const String&); + //! Test UTF-8 string for validity + /*! + Returns true iff the string contains a valid sequence of UTF-8 + encoded characters. + */ + static bool isUTF8(const String &); - //! Convert from UTF-8 to UCS-2 encoding - /*! - Convert from UTF-8 to UCS-2. If errors is not NULL then *errors - is set to true iff any character could not be encoded in UCS-2. - Decoding errors do not set *errors. - */ - static String UTF8ToUCS2(const String&, bool* errors = NULL); + //! Convert from UTF-8 to UCS-2 encoding + /*! + Convert from UTF-8 to UCS-2. If errors is not NULL then *errors + is set to true iff any character could not be encoded in UCS-2. + Decoding errors do not set *errors. + */ + static String UTF8ToUCS2(const String &, bool *errors = NULL); - //! Convert from UTF-8 to UCS-4 encoding - /*! - Convert from UTF-8 to UCS-4. If errors is not NULL then *errors - is set to true iff any character could not be encoded in UCS-4. - Decoding errors do not set *errors. - */ - static String UTF8ToUCS4(const String&, bool* errors = NULL); + //! Convert from UTF-8 to UCS-4 encoding + /*! + Convert from UTF-8 to UCS-4. If errors is not NULL then *errors + is set to true iff any character could not be encoded in UCS-4. + Decoding errors do not set *errors. + */ + static String UTF8ToUCS4(const String &, bool *errors = NULL); - //! Convert from UTF-8 to UTF-16 encoding - /*! - Convert from UTF-8 to UTF-16. If errors is not NULL then *errors - is set to true iff any character could not be encoded in UTF-16. - Decoding errors do not set *errors. - */ - static String UTF8ToUTF16(const String&, bool* errors = NULL); + //! Convert from UTF-8 to UTF-16 encoding + /*! + Convert from UTF-8 to UTF-16. If errors is not NULL then *errors + is set to true iff any character could not be encoded in UTF-16. + Decoding errors do not set *errors. + */ + static String UTF8ToUTF16(const String &, bool *errors = NULL); - //! Convert from UTF-8 to UTF-32 encoding - /*! - Convert from UTF-8 to UTF-32. If errors is not NULL then *errors - is set to true iff any character could not be encoded in UTF-32. - Decoding errors do not set *errors. - */ - static String UTF8ToUTF32(const String&, bool* errors = NULL); + //! Convert from UTF-8 to UTF-32 encoding + /*! + Convert from UTF-8 to UTF-32. If errors is not NULL then *errors + is set to true iff any character could not be encoded in UTF-32. + Decoding errors do not set *errors. + */ + static String UTF8ToUTF32(const String &, bool *errors = NULL); - //! Convert from UTF-8 to the current locale encoding - /*! - Convert from UTF-8 to the current locale encoding. If errors is not - NULL then *errors is set to true iff any character could not be encoded. - Decoding errors do not set *errors. - */ - static String UTF8ToText(const String&, bool* errors = NULL); + //! Convert from UTF-8 to the current locale encoding + /*! + Convert from UTF-8 to the current locale encoding. If errors is not + NULL then *errors is set to true iff any character could not be encoded. + Decoding errors do not set *errors. + */ + static String UTF8ToText(const String &, bool *errors = NULL); - //! Convert from UCS-2 to UTF-8 - /*! - Convert from UCS-2 to UTF-8. If errors is not NULL then *errors is - set to true iff any character could not be decoded. - */ - static String UCS2ToUTF8(const String&, bool* errors = NULL); + //! Convert from UCS-2 to UTF-8 + /*! + Convert from UCS-2 to UTF-8. If errors is not NULL then *errors is + set to true iff any character could not be decoded. + */ + static String UCS2ToUTF8(const String &, bool *errors = NULL); - //! Convert from UCS-4 to UTF-8 - /*! - Convert from UCS-4 to UTF-8. If errors is not NULL then *errors is - set to true iff any character could not be decoded. - */ - static String UCS4ToUTF8(const String&, bool* errors = NULL); + //! Convert from UCS-4 to UTF-8 + /*! + Convert from UCS-4 to UTF-8. If errors is not NULL then *errors is + set to true iff any character could not be decoded. + */ + static String UCS4ToUTF8(const String &, bool *errors = NULL); - //! Convert from UTF-16 to UTF-8 - /*! - Convert from UTF-16 to UTF-8. If errors is not NULL then *errors is - set to true iff any character could not be decoded. - */ - static String UTF16ToUTF8(const String&, bool* errors = NULL); + //! Convert from UTF-16 to UTF-8 + /*! + Convert from UTF-16 to UTF-8. If errors is not NULL then *errors is + set to true iff any character could not be decoded. + */ + static String UTF16ToUTF8(const String &, bool *errors = NULL); - //! Convert from UTF-32 to UTF-8 - /*! - Convert from UTF-32 to UTF-8. If errors is not NULL then *errors is - set to true iff any character could not be decoded. - */ - static String UTF32ToUTF8(const String&, bool* errors = NULL); + //! Convert from UTF-32 to UTF-8 + /*! + Convert from UTF-32 to UTF-8. If errors is not NULL then *errors is + set to true iff any character could not be decoded. + */ + static String UTF32ToUTF8(const String &, bool *errors = NULL); - //! Convert from the current locale encoding to UTF-8 - /*! - Convert from the current locale encoding to UTF-8. If errors is not - NULL then *errors is set to true iff any character could not be decoded. - */ - static String textToUTF8(const String&, bool* errors = nullptr, IArchString::EWideCharEncoding encoding = IArchString::kPlatformDetermined); + //! Convert from the current locale encoding to UTF-8 + /*! + Convert from the current locale encoding to UTF-8. If errors is not + NULL then *errors is set to true iff any character could not be decoded. + */ + static String textToUTF8(const String &, bool *errors = nullptr, + IArchString::EWideCharEncoding encoding = + IArchString::kPlatformDetermined); - //@} + //@} private: - // convert UTF8 to wchar_t string (using whatever encoding is native - // to the platform). caller must delete[] the returned string. the - // string is *not* nul terminated; the length (in characters) is - // returned in size. - static wchar_t* UTF8ToWideChar(const String&, - UInt32& size, bool* errors); + // convert UTF8 to wchar_t string (using whatever encoding is native + // to the platform). caller must delete[] the returned string. the + // string is *not* nul terminated; the length (in characters) is + // returned in size. + static wchar_t *UTF8ToWideChar(const String &, UInt32 &size, bool *errors); - // convert nul terminated wchar_t string (in platform's native - // encoding) to UTF8. - static String wideCharToUTF8(const wchar_t*, - UInt32 size, bool* errors, - IArchString::EWideCharEncoding encoding = IArchString::kPlatformDetermined); + // convert nul terminated wchar_t string (in platform's native + // encoding) to UTF8. + static String wideCharToUTF8(const wchar_t *, UInt32 size, bool *errors, + IArchString::EWideCharEncoding encoding = + IArchString::kPlatformDetermined); - // internal conversion to UTF8 - static String doUCS2ToUTF8(const UInt8* src, UInt32 n, bool* errors); - static String doUCS4ToUTF8(const UInt8* src, UInt32 n, bool* errors); - static String doUTF16ToUTF8(const UInt8* src, UInt32 n, bool* errors); - static String doUTF32ToUTF8(const UInt8* src, UInt32 n, bool* errors); + // internal conversion to UTF8 + static String doUCS2ToUTF8(const UInt8 *src, UInt32 n, bool *errors); + static String doUCS4ToUTF8(const UInt8 *src, UInt32 n, bool *errors); + static String doUTF16ToUTF8(const UInt8 *src, UInt32 n, bool *errors); + static String doUTF32ToUTF8(const UInt8 *src, UInt32 n, bool *errors); - // convert characters to/from UTF8 - static UInt32 fromUTF8(const UInt8*& src, UInt32& size); - static void toUTF8(String& dst, UInt32 c, bool* errors); + // convert characters to/from UTF8 + static UInt32 fromUTF8(const UInt8 *&src, UInt32 &size); + static void toUTF8(String &dst, UInt32 c, bool *errors); private: - static UInt32 s_invalid; - static UInt32 s_replacement; + static UInt32 s_invalid; + static UInt32 s_replacement; }; diff --git a/src/lib/base/XBase.cpp b/src/lib/base/XBase.cpp index 824aa101d..2df764e1a 100644 --- a/src/lib/base/XBase.cpp +++ b/src/lib/base/XBase.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -26,52 +26,44 @@ // XBase // -XBase::XBase() : - std::runtime_error("") -{ - // do nothing +XBase::XBase() : std::runtime_error("") { + // do nothing } -XBase::XBase(const String& msg) : - std::runtime_error(msg) -{ - // do nothing +XBase::XBase(const String &msg) : std::runtime_error(msg) { + // do nothing } -XBase::~XBase() _NOEXCEPT -{ - // do nothing +XBase::~XBase() _NOEXCEPT { + // do nothing } -const char* -XBase::what() const _NOEXCEPT -{ - const char* what = std::runtime_error::what(); - if (strlen(what) == 0) { // Compliant: we made sure that what variable ended with null(std what func return pointer to a null-terminated string) - m_what = getWhat(); - return m_what.c_str(); - } - return what; +const char *XBase::what() const _NOEXCEPT { + const char *what = std::runtime_error::what(); + if (strlen(what) == + 0) { // Compliant: we made sure that what variable ended with null(std + // what func return pointer to a null-terminated string) + m_what = getWhat(); + return m_what.c_str(); + } + return what; } -String -XBase::format(const char* /*id*/, const char* fmt, ...) const throw() -{ - // FIXME -- lookup message string using id as an index. set - // fmt to that string if it exists. +String XBase::format(const char * /*id*/, const char *fmt, ...) const throw() { + // FIXME -- lookup message string using id as an index. set + // fmt to that string if it exists. - // format - String result; - va_list args; - va_start(args, fmt); - try { - result = synergy::string::vformat(fmt, args); - } - catch (...) { - // ignore - result.clear(); - } - va_end(args); + // format + String result; + va_list args; + va_start(args, fmt); + try { + result = synergy::string::vformat(fmt, args); + } catch (...) { + // ignore + result.clear(); + } + va_end(args); - return result; + return result; } diff --git a/src/lib/base/XBase.h b/src/lib/base/XBase.h index 33da3bc44..416e7bd77 100644 --- a/src/lib/base/XBase.h +++ b/src/lib/base/XBase.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -27,29 +27,30 @@ This is the base class of most exception types. */ class XBase : public std::runtime_error { public: - //! Use getWhat() as the result of what() - XBase(); - //! Use \c msg as the result of what() - XBase(const String& msg); - virtual ~XBase() _NOEXCEPT; + //! Use getWhat() as the result of what() + XBase(); + //! Use \c msg as the result of what() + XBase(const String &msg); + virtual ~XBase() _NOEXCEPT; - //! Reason for exception - virtual const char* what() const _NOEXCEPT; + //! Reason for exception + virtual const char *what() const _NOEXCEPT; protected: - //! Get a human readable string describing the exception - virtual String getWhat() const throw() { return ""; } + //! Get a human readable string describing the exception + virtual String getWhat() const throw() { return ""; } + + //! Format a string + /*! + Looks up a message format using \c id, using \c defaultFormat if + no format can be found, then replaces positional parameters in + the format string and returns the result. + */ + virtual String format(const char *id, const char *defaultFormat, ...) const + throw(); - //! Format a string - /*! - Looks up a message format using \c id, using \c defaultFormat if - no format can be found, then replaces positional parameters in - the format string and returns the result. - */ - virtual String format(const char* id, - const char* defaultFormat, ...) const throw(); private: - mutable String m_what; + mutable String m_what; }; /*! @@ -58,13 +59,13 @@ Convenience macro to subclass from XBase (or a subclass of it), providing the c'tor taking a const String&. getWhat() is not declared. */ -#define XBASE_SUBCLASS(name_, super_) \ -class name_ : public super_ { \ -public: \ - name_() : super_() { } \ - name_(const String& msg) : super_(msg) { } \ - virtual ~name_() _NOEXCEPT { } \ -} +#define XBASE_SUBCLASS(name_, super_) \ + class name_ : public super_ { \ + public: \ + name_() : super_() {} \ + name_(const String &msg) : super_(msg) {} \ + virtual ~name_() _NOEXCEPT {} \ + } /*! \def XBASE_SUBCLASS @@ -72,16 +73,16 @@ Convenience macro to subclass from XBase (or a subclass of it), providing the c'tor taking a const String&. getWhat() must be implemented. */ -#define XBASE_SUBCLASS_WHAT(name_, super_) \ -class name_ : public super_ { \ -public: \ - name_() : super_() { } \ - name_(const String& msg) : super_(msg) { } \ - virtual ~name_() _NOEXCEPT { } \ - \ -protected: \ - virtual String getWhat() const throw(); \ -} +#define XBASE_SUBCLASS_WHAT(name_, super_) \ + class name_ : public super_ { \ + public: \ + name_() : super_() {} \ + name_(const String &msg) : super_(msg) {} \ + virtual ~name_() _NOEXCEPT {} \ + \ + protected: \ + virtual String getWhat() const throw(); \ + } /*! \def XBASE_SUBCLASS_FORMAT @@ -91,35 +92,33 @@ to call getWhat() when first called; getWhat() can format the error message and can call what() to get the message passed to the c'tor. */ -#define XBASE_SUBCLASS_FORMAT(name_, super_) \ -class name_ : public super_ { \ -private: \ - enum EState { kFirst, kFormat, kDone }; \ - \ -public: \ - name_() : super_(), m_state(kDone) { } \ - name_(const String& msg) : super_(msg), m_state(kFirst) { } \ - virtual ~name_() _NOEXCEPT { } \ - \ - virtual const char* what() const _NOEXCEPT \ - { \ - if (m_state == kFirst) { \ - m_state = kFormat; \ - m_formatted = getWhat(); \ - m_state = kDone; \ - } \ - if (m_state == kDone) { \ - return m_formatted.c_str(); \ - } \ - else { \ - return super_::what(); \ - } \ - } \ - \ -protected: \ - virtual String getWhat() const throw(); \ - \ -private: \ - mutable EState m_state; \ - mutable std::string m_formatted; \ -} +#define XBASE_SUBCLASS_FORMAT(name_, super_) \ + class name_ : public super_ { \ + private: \ + enum EState { kFirst, kFormat, kDone }; \ + \ + public: \ + name_() : super_(), m_state(kDone) {} \ + name_(const String &msg) : super_(msg), m_state(kFirst) {} \ + virtual ~name_() _NOEXCEPT {} \ + \ + virtual const char *what() const _NOEXCEPT { \ + if (m_state == kFirst) { \ + m_state = kFormat; \ + m_formatted = getWhat(); \ + m_state = kDone; \ + } \ + if (m_state == kDone) { \ + return m_formatted.c_str(); \ + } else { \ + return super_::what(); \ + } \ + } \ + \ + protected: \ + virtual String getWhat() const throw(); \ + \ + private: \ + mutable EState m_state; \ + mutable std::string m_formatted; \ + } diff --git a/src/lib/base/log_outputters.cpp b/src/lib/base/log_outputters.cpp index 20b904a40..11cb2e203 100644 --- a/src/lib/base/log_outputters.cpp +++ b/src/lib/base/log_outputters.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -17,322 +17,235 @@ */ #include "base/log_outputters.h" -#include "base/TMethodJob.h" -#include "base/Path.h" #include "arch/Arch.h" +#include "base/Path.h" +#include "base/TMethodJob.h" #include enum EFileLogOutputter { - kFileSizeLimit = 1024 // kb + kFileSizeLimit = 1024 // kb }; // // StopLogOutputter // -StopLogOutputter::StopLogOutputter() -{ - // do nothing +StopLogOutputter::StopLogOutputter() { + // do nothing } -StopLogOutputter::~StopLogOutputter() -{ - // do nothing +StopLogOutputter::~StopLogOutputter() { + // do nothing } -void -StopLogOutputter::open(const char*) -{ - // do nothing +void StopLogOutputter::open(const char *) { + // do nothing } -void -StopLogOutputter::close() -{ - // do nothing +void StopLogOutputter::close() { + // do nothing } -void -StopLogOutputter::show(bool) -{ - // do nothing -} - -bool -StopLogOutputter::write(ELevel, const char*) -{ - return false; +void StopLogOutputter::show(bool) { + // do nothing } +bool StopLogOutputter::write(ELevel, const char *) { return false; } // // ConsoleLogOutputter // -ConsoleLogOutputter::ConsoleLogOutputter() -{ +ConsoleLogOutputter::ConsoleLogOutputter() {} + +ConsoleLogOutputter::~ConsoleLogOutputter() {} + +void ConsoleLogOutputter::open(const char *title) { ARCH->openConsole(title); } + +void ConsoleLogOutputter::close() { ARCH->closeConsole(); } + +void ConsoleLogOutputter::show(bool showIfEmpty) { + ARCH->showConsole(showIfEmpty); } -ConsoleLogOutputter::~ConsoleLogOutputter() -{ -} - -void -ConsoleLogOutputter::open(const char* title) -{ - ARCH->openConsole(title); -} - -void -ConsoleLogOutputter::close() -{ - ARCH->closeConsole(); -} - -void -ConsoleLogOutputter::show(bool showIfEmpty) -{ - ARCH->showConsole(showIfEmpty); -} - -bool -ConsoleLogOutputter::write(ELevel level, const char* msg) -{ - ARCH->writeConsole(level, msg); - return true; -} - -void -ConsoleLogOutputter::flush() -{ - +bool ConsoleLogOutputter::write(ELevel level, const char *msg) { + ARCH->writeConsole(level, msg); + return true; } +void ConsoleLogOutputter::flush() {} // // SystemLogOutputter // -SystemLogOutputter::SystemLogOutputter() -{ - // do nothing +SystemLogOutputter::SystemLogOutputter() { + // do nothing } -SystemLogOutputter::~SystemLogOutputter() -{ - // do nothing +SystemLogOutputter::~SystemLogOutputter() { + // do nothing } -void -SystemLogOutputter::open(const char* title) -{ - ARCH->openLog(title); -} +void SystemLogOutputter::open(const char *title) { ARCH->openLog(title); } -void -SystemLogOutputter::close() -{ - ARCH->closeLog(); -} +void SystemLogOutputter::close() { ARCH->closeLog(); } -void -SystemLogOutputter::show(bool showIfEmpty) -{ - ARCH->showLog(showIfEmpty); -} +void SystemLogOutputter::show(bool showIfEmpty) { ARCH->showLog(showIfEmpty); } -bool -SystemLogOutputter::write(ELevel level, const char* msg) -{ - ARCH->writeLog(level, msg); - return true; +bool SystemLogOutputter::write(ELevel level, const char *msg) { + ARCH->writeLog(level, msg); + return true; } // // SystemLogger // -SystemLogger::SystemLogger(const char* title, bool blockConsole) : - m_stop(NULL) -{ - // redirect log messages - if (blockConsole) { - m_stop = new StopLogOutputter; - CLOG->insert(m_stop); - } - m_syslog = new SystemLogOutputter; - m_syslog->open(title); - CLOG->insert(m_syslog); +SystemLogger::SystemLogger(const char *title, bool blockConsole) + : m_stop(NULL) { + // redirect log messages + if (blockConsole) { + m_stop = new StopLogOutputter; + CLOG->insert(m_stop); + } + m_syslog = new SystemLogOutputter; + m_syslog->open(title); + CLOG->insert(m_syslog); } -SystemLogger::~SystemLogger() -{ - CLOG->remove(m_syslog); - delete m_syslog; - if (m_stop != NULL) { - CLOG->remove(m_stop); - delete m_stop; - } +SystemLogger::~SystemLogger() { + CLOG->remove(m_syslog); + delete m_syslog; + if (m_stop != NULL) { + CLOG->remove(m_stop); + delete m_stop; + } } - // // BufferedLogOutputter // -BufferedLogOutputter::BufferedLogOutputter(UInt32 maxBufferSize) : - m_maxBufferSize(maxBufferSize) -{ - // do nothing +BufferedLogOutputter::BufferedLogOutputter(UInt32 maxBufferSize) + : m_maxBufferSize(maxBufferSize) { + // do nothing } -BufferedLogOutputter::~BufferedLogOutputter() -{ - // do nothing +BufferedLogOutputter::~BufferedLogOutputter() { + // do nothing } -BufferedLogOutputter::const_iterator -BufferedLogOutputter::begin() const -{ - return m_buffer.begin(); +BufferedLogOutputter::const_iterator BufferedLogOutputter::begin() const { + return m_buffer.begin(); } -BufferedLogOutputter::const_iterator -BufferedLogOutputter::end() const -{ - return m_buffer.end(); +BufferedLogOutputter::const_iterator BufferedLogOutputter::end() const { + return m_buffer.end(); } -void -BufferedLogOutputter::open(const char*) -{ - // do nothing +void BufferedLogOutputter::open(const char *) { + // do nothing } -void -BufferedLogOutputter::close() -{ - // remove all elements from the buffer - m_buffer.clear(); +void BufferedLogOutputter::close() { + // remove all elements from the buffer + m_buffer.clear(); } -void -BufferedLogOutputter::show(bool) -{ - // do nothing +void BufferedLogOutputter::show(bool) { + // do nothing } -bool -BufferedLogOutputter::write(ELevel, const char* message) -{ - while (m_buffer.size() >= m_maxBufferSize) { - m_buffer.pop_front(); - } - m_buffer.push_back(String(message)); - return true; +bool BufferedLogOutputter::write(ELevel, const char *message) { + while (m_buffer.size() >= m_maxBufferSize) { + m_buffer.pop_front(); + } + m_buffer.push_back(String(message)); + return true; } - // // FileLogOutputter // -FileLogOutputter::FileLogOutputter(const char* logFile) -{ - setLogFilename(logFile); +FileLogOutputter::FileLogOutputter(const char *logFile) { + setLogFilename(logFile); } -FileLogOutputter::~FileLogOutputter() -{ +FileLogOutputter::~FileLogOutputter() {} + +void FileLogOutputter::setLogFilename(const char *logFile) { + assert(logFile != NULL); + m_fileName = logFile; } -void -FileLogOutputter::setLogFilename(const char* logFile) -{ - assert(logFile != NULL); - m_fileName = logFile; -} +bool FileLogOutputter::write(ELevel level, const char *message) { + bool moveFile = false; -bool -FileLogOutputter::write(ELevel level, const char *message) -{ - bool moveFile = false; + std::ofstream m_handle; + m_handle.open(synergy::filesystem::path(m_fileName), std::fstream::app); + if (m_handle.is_open() && m_handle.fail() != true) { + m_handle << message << std::endl; - std::ofstream m_handle; - m_handle.open(synergy::filesystem::path(m_fileName), std::fstream::app); - if (m_handle.is_open() && m_handle.fail() != true) { - m_handle << message << std::endl; - - // when file size exceeds limits, move to 'old log' filename. - size_t p = m_handle.tellp(); - if (p > (kFileSizeLimit * 1024)) { - moveFile = true; - } + // when file size exceeds limits, move to 'old log' filename. + size_t p = m_handle.tellp(); + if (p > (kFileSizeLimit * 1024)) { + moveFile = true; } - m_handle.close(); + } + m_handle.close(); - if (moveFile) { - String oldLogFilename = synergy::string::sprintf("%s.1", m_fileName.c_str()); - remove(oldLogFilename.c_str()); - rename(m_fileName.c_str(), oldLogFilename.c_str()); - } + if (moveFile) { + String oldLogFilename = + synergy::string::sprintf("%s.1", m_fileName.c_str()); + remove(oldLogFilename.c_str()); + rename(m_fileName.c_str(), oldLogFilename.c_str()); + } - return true; + return true; } -void -FileLogOutputter::open(const char *title) {} +void FileLogOutputter::open(const char *title) {} -void -FileLogOutputter::close() {} +void FileLogOutputter::close() {} -void -FileLogOutputter::show(bool showIfEmpty) {} +void FileLogOutputter::show(bool showIfEmpty) {} // // MesssageBoxLogOutputter // -MesssageBoxLogOutputter::MesssageBoxLogOutputter() -{ - // do nothing +MesssageBoxLogOutputter::MesssageBoxLogOutputter() { + // do nothing } -MesssageBoxLogOutputter::~MesssageBoxLogOutputter() -{ - // do nothing +MesssageBoxLogOutputter::~MesssageBoxLogOutputter() { + // do nothing } -void -MesssageBoxLogOutputter::open(const char* title) -{ - // do nothing +void MesssageBoxLogOutputter::open(const char *title) { + // do nothing } -void -MesssageBoxLogOutputter::close() -{ - // do nothing +void MesssageBoxLogOutputter::close() { + // do nothing } -void -MesssageBoxLogOutputter::show(bool showIfEmpty) -{ - // do nothing +void MesssageBoxLogOutputter::show(bool showIfEmpty) { + // do nothing } -bool -MesssageBoxLogOutputter::write(ELevel level, const char* msg) -{ - // don't spam user with messages. - if (level > kERROR) { - return true; - } +bool MesssageBoxLogOutputter::write(ELevel level, const char *msg) { + // don't spam user with messages. + if (level > kERROR) { + return true; + } #if SYSAPI_WIN32 - MessageBox(NULL, msg, CLOG->getFilterName(level), MB_OK); + MessageBox(NULL, msg, CLOG->getFilterName(level), MB_OK); #endif - return true; + return true; } diff --git a/src/lib/base/log_outputters.h b/src/lib/base/log_outputters.h index a4f83831f..2bf65060e 100644 --- a/src/lib/base/log_outputters.h +++ b/src/lib/base/log_outputters.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -18,14 +18,14 @@ #pragma once -#include "mt/Thread.h" #include "base/ILogOutputter.h" #include "base/String.h" #include "common/basic_types.h" #include "common/stddeque.h" +#include "mt/Thread.h" -#include #include +#include //! Stop traversing log chain outputter /*! @@ -35,14 +35,14 @@ this to prevent already inserted outputters from writing. */ class StopLogOutputter : public ILogOutputter { public: - StopLogOutputter(); - virtual ~StopLogOutputter(); + StopLogOutputter(); + virtual ~StopLogOutputter(); - // ILogOutputter overrides - virtual void open(const char* title); - virtual void close(); - virtual void show(bool showIfEmpty); - virtual bool write(ELevel level, const char* message); + // ILogOutputter overrides + virtual void open(const char *title); + virtual void close(); + virtual void show(bool showIfEmpty); + virtual bool write(ELevel level, const char *message); }; //! Write log to console @@ -52,15 +52,15 @@ message is ignored. */ class ConsoleLogOutputter : public ILogOutputter { public: - ConsoleLogOutputter(); - virtual ~ConsoleLogOutputter(); + ConsoleLogOutputter(); + virtual ~ConsoleLogOutputter(); - // ILogOutputter overrides - virtual void open(const char* title); - virtual void close(); - virtual void show(bool showIfEmpty); - virtual bool write(ELevel level, const char* message); - virtual void flush(); + // ILogOutputter overrides + virtual void open(const char *title); + virtual void close(); + virtual void show(bool showIfEmpty); + virtual bool write(ELevel level, const char *message); + virtual void flush(); }; //! Write log to file @@ -71,19 +71,19 @@ message is ignored. class FileLogOutputter : public ILogOutputter { public: - FileLogOutputter(const char* logFile); - virtual ~FileLogOutputter(); + FileLogOutputter(const char *logFile); + virtual ~FileLogOutputter(); - // ILogOutputter overrides - virtual void open(const char* title); - virtual void close(); - virtual void show(bool showIfEmpty); - virtual bool write(ELevel level, const char* message); + // ILogOutputter overrides + virtual void open(const char *title); + virtual void close(); + virtual void show(bool showIfEmpty); + virtual bool write(ELevel level, const char *message); - void setLogFilename(const char* title); + void setLogFilename(const char *title); private: - std::string m_fileName; + std::string m_fileName; }; //! Write log to system log @@ -92,14 +92,14 @@ This outputter writes output to the system log. */ class SystemLogOutputter : public ILogOutputter { public: - SystemLogOutputter(); - virtual ~SystemLogOutputter(); + SystemLogOutputter(); + virtual ~SystemLogOutputter(); - // ILogOutputter overrides - virtual void open(const char* title); - virtual void close(); - virtual void show(bool showIfEmpty); - virtual bool write(ELevel level, const char* message); + // ILogOutputter overrides + virtual void open(const char *title); + virtual void close(); + virtual void show(bool showIfEmpty); + virtual bool write(ELevel level, const char *message); }; //! Write log to system log only @@ -112,17 +112,17 @@ the scope. */ class SystemLogger { public: - SystemLogger(const char* title, bool blockConsole); - SystemLogger(SystemLogger const &) =delete; - SystemLogger(SystemLogger &&) =delete; - ~SystemLogger(); + SystemLogger(const char *title, bool blockConsole); + SystemLogger(SystemLogger const &) = delete; + SystemLogger(SystemLogger &&) = delete; + ~SystemLogger(); - SystemLogger& operator=(SystemLogger const &) =delete; - SystemLogger& operator=(SystemLogger &&) =delete; + SystemLogger &operator=(SystemLogger const &) = delete; + SystemLogger &operator=(SystemLogger &&) = delete; private: - ILogOutputter* m_syslog; - ILogOutputter* m_stop; + ILogOutputter *m_syslog; + ILogOutputter *m_stop; }; //! Save log history @@ -131,33 +131,34 @@ This outputter records the last N log messages. */ class BufferedLogOutputter : public ILogOutputter { private: - typedef std::deque Buffer; + typedef std::deque Buffer; public: - typedef Buffer::const_iterator const_iterator; + typedef Buffer::const_iterator const_iterator; - BufferedLogOutputter(UInt32 maxBufferSize); - virtual ~BufferedLogOutputter(); + BufferedLogOutputter(UInt32 maxBufferSize); + virtual ~BufferedLogOutputter(); - //! @name accessors - //@{ + //! @name accessors + //@{ - //! Get start of buffer - const_iterator begin() const; + //! Get start of buffer + const_iterator begin() const; - //! Get end of buffer - const_iterator end() const; + //! Get end of buffer + const_iterator end() const; - //@} + //@} + + // ILogOutputter overrides + virtual void open(const char *title); + virtual void close(); + virtual void show(bool showIfEmpty); + virtual bool write(ELevel level, const char *message); - // ILogOutputter overrides - virtual void open(const char* title); - virtual void close(); - virtual void show(bool showIfEmpty); - virtual bool write(ELevel level, const char* message); private: - UInt32 m_maxBufferSize; - Buffer m_buffer; + UInt32 m_maxBufferSize; + Buffer m_buffer; }; //! Write log to message box @@ -166,12 +167,12 @@ The level for each message is ignored. */ class MesssageBoxLogOutputter : public ILogOutputter { public: - MesssageBoxLogOutputter(); - virtual ~MesssageBoxLogOutputter(); + MesssageBoxLogOutputter(); + virtual ~MesssageBoxLogOutputter(); - // ILogOutputter overrides - virtual void open(const char* title); - virtual void close(); - virtual void show(bool showIfEmpty); - virtual bool write(ELevel level, const char* message); + // ILogOutputter overrides + virtual void open(const char *title); + virtual void close(); + virtual void show(bool showIfEmpty); + virtual bool write(ELevel level, const char *message); }; diff --git a/src/lib/client/Client.cpp b/src/lib/client/Client.cpp index c56954417..2fd3b8ab8 100644 --- a/src/lib/client/Client.cpp +++ b/src/lib/client/Client.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -18,911 +18,736 @@ #include "client/Client.h" +#include "arch/Arch.h" +#include "base/IEventQueue.h" +#include "base/Log.h" +#include "base/TMethodEventJob.h" +#include "base/TMethodJob.h" #include "client/ServerProxy.h" -#include "synergy/AppUtil.h" -#include "synergy/Screen.h" -#include "synergy/FileChunk.h" -#include "synergy/DropHelper.h" -#include "synergy/PacketStreamFilter.h" -#include "synergy/ProtocolUtil.h" -#include "synergy/protocol_types.h" -#include "synergy/XSynergy.h" -#include "synergy/StreamChunker.h" -#include "synergy/IPlatformScreen.h" +#include "common/stdexcept.h" #include "mt/Thread.h" -#include "net/TCPSocket.h" #include "net/IDataSocket.h" #include "net/ISocketFactory.h" #include "net/SecureSocket.h" -#include "arch/Arch.h" -#include "base/Log.h" -#include "base/IEventQueue.h" -#include "base/TMethodEventJob.h" -#include "base/TMethodJob.h" -#include "common/stdexcept.h" +#include "net/TCPSocket.h" +#include "synergy/AppUtil.h" +#include "synergy/DropHelper.h" +#include "synergy/FileChunk.h" +#include "synergy/IPlatformScreen.h" +#include "synergy/PacketStreamFilter.h" +#include "synergy/ProtocolUtil.h" +#include "synergy/Screen.h" +#include "synergy/StreamChunker.h" +#include "synergy/XSynergy.h" +#include "synergy/protocol_types.h" -#include -#include -#include -#include #include #include +#include +#include +#include #include +#include // // Client // -Client::Client( - IEventQueue* events, - const String& name, const NetworkAddress& address, - ISocketFactory* socketFactory, - synergy::Screen* screen, - lib::synergy::ClientArgs const& args) : - m_mock(false), - m_name(name), - m_serverAddress(address), - m_socketFactory(socketFactory), - m_screen(screen), - m_stream(NULL), - m_timer(NULL), - m_server(NULL), - m_ready(false), - m_active(false), - m_suspended(false), - m_connectOnResume(false), - m_events(events), - m_sendFileThread(nullptr), - m_writeToDropDirThread(nullptr), - m_useSecureNetwork(args.m_enableCrypto), - m_args(args), - m_enableClipboard(true), - m_maximumClipboardSize(INT_MAX) -{ - assert(m_socketFactory != NULL); - assert(m_screen != NULL); +Client::Client(IEventQueue *events, const String &name, + const NetworkAddress &address, ISocketFactory *socketFactory, + synergy::Screen *screen, lib::synergy::ClientArgs const &args) + : m_mock(false), m_name(name), m_serverAddress(address), + m_socketFactory(socketFactory), m_screen(screen), m_stream(NULL), + m_timer(NULL), m_server(NULL), m_ready(false), m_active(false), + m_suspended(false), m_connectOnResume(false), m_events(events), + m_sendFileThread(nullptr), m_writeToDropDirThread(nullptr), + m_useSecureNetwork(args.m_enableCrypto), m_args(args), + m_enableClipboard(true), m_maximumClipboardSize(INT_MAX) { + assert(m_socketFactory != NULL); + assert(m_screen != NULL); - // register suspend/resume event handlers - m_events->adoptHandler(m_events->forIScreen().suspend(), - getEventTarget(), - new TMethodEventJob(this, - &Client::handleSuspend)); - m_events->adoptHandler(m_events->forIScreen().resume(), - getEventTarget(), - new TMethodEventJob(this, - &Client::handleResume)); + // register suspend/resume event handlers + m_events->adoptHandler( + m_events->forIScreen().suspend(), getEventTarget(), + new TMethodEventJob(this, &Client::handleSuspend)); + m_events->adoptHandler( + m_events->forIScreen().resume(), getEventTarget(), + new TMethodEventJob(this, &Client::handleResume)); - if (m_args.m_enableDragDrop) { - m_events->adoptHandler(m_events->forFile().fileChunkSending(), - this, - new TMethodEventJob(this, - &Client::handleFileChunkSending)); - m_events->adoptHandler(m_events->forFile().fileRecieveCompleted(), - this, - new TMethodEventJob(this, - &Client::handleFileRecieveCompleted)); - } + if (m_args.m_enableDragDrop) { + m_events->adoptHandler( + m_events->forFile().fileChunkSending(), this, + new TMethodEventJob(this, &Client::handleFileChunkSending)); + m_events->adoptHandler( + m_events->forFile().fileRecieveCompleted(), this, + new TMethodEventJob(this, &Client::handleFileRecieveCompleted)); + } } -Client::~Client() -{ - if (m_mock) { - return; +Client::~Client() { + if (m_mock) { + return; + } + + m_events->removeHandler(m_events->forIScreen().suspend(), getEventTarget()); + m_events->removeHandler(m_events->forIScreen().resume(), getEventTarget()); + + cleanupTimer(); + cleanupScreen(); + cleanupConnecting(); + cleanupConnection(); + delete m_socketFactory; +} + +void Client::connect(size_t addressIndex) { + if (m_stream != NULL) { + return; + } + if (m_suspended) { + m_connectOnResume = true; + return; + } + + try { + if (m_args.m_hostMode) { + LOG((CLOG_NOTE "waiting for server conection on %i port", + m_serverAddress.getPort())); + } else { + // resolve the server hostname. do this every time we connect + // in case we couldn't resolve the address earlier or the address + // has changed (which can happen frequently if this is a laptop + // being shuttled between various networks). patch by Brent + // Priddy. + m_resolvedAddressesCount = m_serverAddress.resolve(addressIndex); + + // m_serverAddress will be null if the hostname address is not reolved + if (m_serverAddress.getAddress() != nullptr) { + // to help users troubleshoot, show server host name (issue: 60) + LOG((CLOG_NOTE "connecting to '%s': %s:%i", + m_serverAddress.getHostname().c_str(), + ARCH->addrToString(m_serverAddress.getAddress()).c_str(), + m_serverAddress.getPort())); + } } - m_events->removeHandler(m_events->forIScreen().suspend(), - getEventTarget()); - m_events->removeHandler(m_events->forIScreen().resume(), - getEventTarget()); - - cleanupTimer(); - cleanupScreen(); - cleanupConnecting(); - cleanupConnection(); - delete m_socketFactory; -} - -void -Client::connect(size_t addressIndex) -{ - if (m_stream != NULL) { - return; - } - if (m_suspended) { - m_connectOnResume = true; - return; - } - - try { - if (m_args.m_hostMode) - { - LOG((CLOG_NOTE "waiting for server conection on %i port", m_serverAddress.getPort())); - } - else { - // resolve the server hostname. do this every time we connect - // in case we couldn't resolve the address earlier or the address - // has changed (which can happen frequently if this is a laptop - // being shuttled between various networks). patch by Brent - // Priddy. - m_resolvedAddressesCount = m_serverAddress.resolve(addressIndex); - - // m_serverAddress will be null if the hostname address is not reolved - if (m_serverAddress.getAddress() != nullptr) { - // to help users troubleshoot, show server host name (issue: 60) - LOG((CLOG_NOTE "connecting to '%s': %s:%i", - m_serverAddress.getHostname().c_str(), - ARCH->addrToString(m_serverAddress.getAddress()).c_str(), - m_serverAddress.getPort())); - } - } - - // create the socket - IDataSocket* socket = m_socketFactory->create(m_useSecureNetwork, ARCH->getAddrFamily(m_serverAddress.getAddress())); - bindNetworkInterface(socket); - - // filter socket messages, including a packetizing filter - m_stream = new PacketStreamFilter(m_events, socket, true); - - // connect - LOG((CLOG_DEBUG1 "connecting to server")); - setupConnecting(); - setupTimer(); - socket->connect(m_serverAddress); - } - catch (XBase& e) { - cleanupTimer(); - cleanupConnecting(); - cleanupStream(); - LOG((CLOG_DEBUG1 "connection failed")); - sendConnectionFailedEvent(e.what()); - return; - } -} - -void -Client::disconnect(const char* msg) -{ - cleanup(); - - if (msg) { - sendConnectionFailedEvent(msg); - } - else { - sendEvent(m_events->forClient().disconnected(), NULL); - } -} - -void -Client::refuseConnection(const char* msg) -{ - cleanup(); - - if (msg) { - auto info = new FailInfo(msg); - info->m_retry = true; - Event event(m_events->forClient().connectionRefused(), getEventTarget(), info, Event::kDontFreeData); - m_events->addEvent(event); - } -} - -void -Client::handshakeComplete() -{ - m_ready = true; - m_screen->enable(); - sendEvent(m_events->forClient().connected(), NULL); -} - -bool -Client::isConnected() const -{ - return (m_server != NULL); -} - -bool -Client::isConnecting() const -{ - return (m_timer != NULL); -} - -NetworkAddress -Client::getServerAddress() const -{ - return m_serverAddress; -} - -void* -Client::getEventTarget() const -{ - return m_screen->getEventTarget(); -} - -bool -Client::getClipboard(ClipboardID id, IClipboard* clipboard) const -{ - return m_screen->getClipboard(id, clipboard); -} - -void -Client::getShape(SInt32& x, SInt32& y, SInt32& w, SInt32& h) const -{ - m_screen->getShape(x, y, w, h); -} - -void -Client::getCursorPos(SInt32& x, SInt32& y) const -{ - m_screen->getCursorPos(x, y); -} - -void -Client::enter(SInt32 xAbs, SInt32 yAbs, UInt32, KeyModifierMask mask, bool) -{ - m_active = true; - m_screen->mouseMove(xAbs, yAbs); - m_screen->enter(mask); - - if (m_sendFileThread) { - StreamChunker::interruptFile(); - m_sendFileThread.reset(nullptr); - } -} - -bool -Client::leave() -{ - m_active = false; - - m_screen->leave(); - - if (m_enableClipboard) { - // send clipboards that we own and that have changed - for (ClipboardID id = 0; id < kClipboardEnd; ++id) { - if (m_ownClipboard[id]) { - sendClipboard(id); - } - } - } - - return true; -} - -void -Client::setClipboard(ClipboardID id, const IClipboard* clipboard) -{ - m_screen->setClipboard(id, clipboard); - m_ownClipboard[id] = false; - m_sentClipboard[id] = false; -} - -void -Client::grabClipboard(ClipboardID id) -{ - m_screen->grabClipboard(id); - m_ownClipboard[id] = false; - m_sentClipboard[id] = false; -} - -void -Client::setClipboardDirty(ClipboardID, bool) -{ - assert(0 && "shouldn't be called"); -} - -void -Client::keyDown(KeyID id, KeyModifierMask mask, KeyButton button, const String &lang) -{ - m_screen->keyDown(id, mask, button, lang); -} - -void -Client::keyRepeat(KeyID id, KeyModifierMask mask, - SInt32 count, KeyButton button, const String& lang) -{ - m_screen->keyRepeat(id, mask, count, button, lang); -} - -void -Client::keyUp(KeyID id, KeyModifierMask mask, KeyButton button) -{ - m_screen->keyUp(id, mask, button); -} - -void -Client::mouseDown(ButtonID id) -{ - m_screen->mouseDown(id); -} - -void -Client::mouseUp(ButtonID id) -{ - m_screen->mouseUp(id); -} - -void -Client::mouseMove(SInt32 x, SInt32 y) -{ - m_screen->mouseMove(x, y); -} - -void -Client::mouseRelativeMove(SInt32 dx, SInt32 dy) -{ - m_screen->mouseRelativeMove(dx, dy); -} - -void -Client::mouseWheel(SInt32 xDelta, SInt32 yDelta) -{ - m_screen->mouseWheel(xDelta, yDelta); -} - -void -Client::screensaver(bool activate) -{ - m_screen->screensaver(activate); -} - -void -Client::resetOptions() -{ - m_screen->resetOptions(); -} - -void -Client::setOptions(const OptionsList& options) -{ - for (OptionsList::const_iterator index = options.begin(); - index != options.end(); ++index) { - const OptionID id = *index; - if (id == kOptionClipboardSharing) { - index++; - if (index != options.end()) { - if (!*index) { - LOG((CLOG_NOTE "clipboard sharing disabled by server")); - } - m_enableClipboard = *index; - } - } else if (id == kOptionClipboardSharingSize) { - index++; - if (index != options.end()) { - m_maximumClipboardSize = *index; - } - } - } - - if (m_enableClipboard && !m_maximumClipboardSize) { - m_enableClipboard = false; - LOG((CLOG_NOTE "clipboard sharing is disabled because the server " - "set the maximum clipboard size to 0")); - } - - m_screen->setOptions(options); -} - -String -Client::getName() const -{ - return m_name; -} - -void -Client::sendClipboard(ClipboardID id) -{ - // note -- m_mutex must be locked on entry - assert(m_screen != NULL); - assert(m_server != NULL); - - // get clipboard data. set the clipboard time to the last - // clipboard time before getting the data from the screen - // as the screen may detect an unchanged clipboard and - // avoid copying the data. - Clipboard clipboard; - if (clipboard.open(m_timeClipboard[id])) { - clipboard.close(); - } - m_screen->getClipboard(id, &clipboard); - - // check time - if (m_timeClipboard[id] == 0 || - clipboard.getTime() != m_timeClipboard[id]) { - // marshall the data - String data = clipboard.marshall(); - if (data.size() >= m_maximumClipboardSize * 1024) { - LOG((CLOG_NOTE "skipping clipboard transfer because the clipboard" - " contents exceeds the %i MB size limit set by the server", - m_maximumClipboardSize / 1024)); - return; - } - - // save new time - m_timeClipboard[id] = clipboard.getTime(); - // save and send data if different or not yet sent - if (!m_sentClipboard[id] || data != m_dataClipboard[id]) { - m_sentClipboard[id] = true; - m_dataClipboard[id] = data; - m_server->onClipboardChanged(id, &clipboard); - } - } -} - -void -Client::sendEvent(Event::Type type, void* data) -{ - m_events->addEvent(Event(type, getEventTarget(), data)); -} - -void -Client::sendConnectionFailedEvent(const char* msg) -{ - FailInfo* info = new FailInfo(msg); - info->m_retry = true; - Event event(m_events->forClient().connectionFailed(), getEventTarget(), info, Event::kDontFreeData); - m_events->addEvent(event); -} - -void -Client::sendFileChunk(const void* data) -{ - FileChunk* chunk = static_cast(const_cast(data)); - LOG((CLOG_DEBUG1 "send file chunk")); - assert(m_server != NULL); - - // relay - m_server->fileChunkSending(chunk->m_chunk[0], &chunk->m_chunk[1], chunk->m_dataSize); -} - -void -Client::setupConnecting() -{ - assert(m_stream != NULL); - - if (m_args.m_enableCrypto) { - m_events->adoptHandler(m_events->forIDataSocket().secureConnected(), - m_stream->getEventTarget(), - new TMethodEventJob(this, - &Client::handleConnected)); - } - else { - m_events->adoptHandler(m_events->forIDataSocket().connected(), - m_stream->getEventTarget(), - new TMethodEventJob(this, - &Client::handleConnected)); - } - - m_events->adoptHandler(m_events->forIDataSocket().connectionFailed(), - m_stream->getEventTarget(), - new TMethodEventJob(this, - &Client::handleConnectionFailed)); -} - -void -Client::setupConnection() -{ - assert(m_stream != NULL); - - m_events->adoptHandler(m_events->forISocket().disconnected(), - m_stream->getEventTarget(), - new TMethodEventJob(this, - &Client::handleDisconnected)); - m_events->adoptHandler(m_events->forIStream().inputReady(), - m_stream->getEventTarget(), - new TMethodEventJob(this, - &Client::handleHello)); - m_events->adoptHandler(m_events->forIStream().outputError(), - m_stream->getEventTarget(), - new TMethodEventJob(this, - &Client::handleOutputError)); - m_events->adoptHandler(m_events->forIStream().inputShutdown(), - m_stream->getEventTarget(), - new TMethodEventJob(this, - &Client::handleDisconnected)); - m_events->adoptHandler(m_events->forIStream().outputShutdown(), - m_stream->getEventTarget(), - new TMethodEventJob(this, - &Client::handleDisconnected)); - - m_events->adoptHandler(m_events->forISocket().stopRetry(), - m_stream->getEventTarget(), - new TMethodEventJob(this, &Client::handleStopRetry)); -} - -void -Client::setupScreen() -{ - assert(m_server == NULL); - - m_ready = false; - m_server = new ServerProxy(this, m_stream, m_events); - m_events->adoptHandler(m_events->forIScreen().shapeChanged(), - getEventTarget(), - new TMethodEventJob(this, - &Client::handleShapeChanged)); - m_events->adoptHandler(m_events->forClipboard().clipboardGrabbed(), - getEventTarget(), - new TMethodEventJob(this, - &Client::handleClipboardGrabbed)); -} - -void -Client::setupTimer() -{ - assert(m_timer == NULL); - - if (!m_args.m_hostMode) { - m_timer = m_events->newOneShotTimer(2.0, NULL); - m_events->adoptHandler(Event::kTimer, m_timer, - new TMethodEventJob(this, - &Client::handleConnectTimeout)); - } -} - -void -Client::cleanup() -{ - m_connectOnResume = false; - cleanupTimer(); - cleanupScreen(); - cleanupConnecting(); - cleanupConnection(); -} - -void -Client::cleanupConnecting() -{ - if (m_stream != NULL) { - m_events->removeHandler(m_events->forIDataSocket().connected(), - m_stream->getEventTarget()); - m_events->removeHandler(m_events->forIDataSocket().connectionFailed(), - m_stream->getEventTarget()); - } -} - -void -Client::cleanupConnection() -{ - if (m_stream != NULL) { - m_events->removeHandler(m_events->forIStream().inputReady(), - m_stream->getEventTarget()); - m_events->removeHandler(m_events->forIStream().outputError(), - m_stream->getEventTarget()); - m_events->removeHandler(m_events->forIStream().inputShutdown(), - m_stream->getEventTarget()); - m_events->removeHandler(m_events->forIStream().outputShutdown(), - m_stream->getEventTarget()); - m_events->removeHandler(m_events->forISocket().disconnected(), - m_stream->getEventTarget()); - m_events->removeHandler(m_events->forISocket().stopRetry(), - m_stream->getEventTarget()); - cleanupStream(); - } -} - -void -Client::cleanupScreen() -{ - if (m_server != NULL) { - if (m_ready) { - m_screen->disable(); - m_ready = false; - } - m_events->removeHandler(m_events->forIScreen().shapeChanged(), - getEventTarget()); - m_events->removeHandler(m_events->forClipboard().clipboardGrabbed(), - getEventTarget()); - delete m_server; - m_server = NULL; - } -} - -void -Client::cleanupTimer() -{ - if (m_timer != NULL) { - m_events->removeHandler(Event::kTimer, m_timer); - m_events->deleteTimer(m_timer); - m_timer = NULL; - } -} - -void -Client::cleanupStream() -{ - delete m_stream; - m_stream = NULL; -} - -void -Client::handleConnected(const Event&, void*) -{ - LOG((CLOG_DEBUG1 "connected; wait for hello")); - cleanupConnecting(); - setupConnection(); - - // reset clipboard state - for (ClipboardID id = 0; id < kClipboardEnd; ++id) { - m_ownClipboard[id] = false; - m_sentClipboard[id] = false; - m_timeClipboard[id] = 0; - } -} - -void -Client::handleConnectionFailed(const Event& event, void*) -{ - IDataSocket::ConnectionFailedInfo* info = - static_cast(event.getData()); - + // create the socket + IDataSocket *socket = m_socketFactory->create( + m_useSecureNetwork, ARCH->getAddrFamily(m_serverAddress.getAddress())); + bindNetworkInterface(socket); + + // filter socket messages, including a packetizing filter + m_stream = new PacketStreamFilter(m_events, socket, true); + + // connect + LOG((CLOG_DEBUG1 "connecting to server")); + setupConnecting(); + setupTimer(); + socket->connect(m_serverAddress); + } catch (XBase &e) { cleanupTimer(); cleanupConnecting(); cleanupStream(); LOG((CLOG_DEBUG1 "connection failed")); - sendConnectionFailedEvent(info->m_what.c_str()); - delete info; + sendConnectionFailedEvent(e.what()); + return; + } } -void -Client::handleConnectTimeout(const Event&, void*) -{ - cleanupTimer(); - cleanupConnecting(); - cleanupConnection(); - cleanupStream(); - LOG((CLOG_DEBUG1 "connection timed out")); - sendConnectionFailedEvent("Timed out"); -} +void Client::disconnect(const char *msg) { + cleanup(); -void -Client::handleOutputError(const Event&, void*) -{ - cleanupTimer(); - cleanupScreen(); - cleanupConnection(); - LOG((CLOG_WARN "error sending to server")); + if (msg) { + sendConnectionFailedEvent(msg); + } else { sendEvent(m_events->forClient().disconnected(), NULL); + } } -void -Client::handleDisconnected(const Event&, void*) -{ - cleanupTimer(); - cleanupScreen(); - cleanupConnection(); - LOG((CLOG_DEBUG1 "disconnected")); - sendEvent(m_events->forClient().disconnected(), NULL); +void Client::refuseConnection(const char *msg) { + cleanup(); + + if (msg) { + auto info = new FailInfo(msg); + info->m_retry = true; + Event event(m_events->forClient().connectionRefused(), getEventTarget(), + info, Event::kDontFreeData); + m_events->addEvent(event); + } } -void -Client::handleShapeChanged(const Event&, void*) -{ - LOG((CLOG_DEBUG "resolution changed")); - m_server->onInfoChanged(); +void Client::handshakeComplete() { + m_ready = true; + m_screen->enable(); + sendEvent(m_events->forClient().connected(), NULL); } -void -Client::handleClipboardGrabbed(const Event& event, void*) -{ - if (!m_enableClipboard || (m_maximumClipboardSize == 0)) { - return; - } +bool Client::isConnected() const { return (m_server != NULL); } - const IScreen::ClipboardInfo* info = - static_cast(event.getData()); +bool Client::isConnecting() const { return (m_timer != NULL); } - // grab ownership - m_server->onGrabClipboard(info->m_id); +NetworkAddress Client::getServerAddress() const { return m_serverAddress; } - // we now own the clipboard and it has not been sent to the server - m_ownClipboard[info->m_id] = true; - m_sentClipboard[info->m_id] = false; - m_timeClipboard[info->m_id] = 0; +void *Client::getEventTarget() const { return m_screen->getEventTarget(); } - // if we're not the active screen then send the clipboard now, - // otherwise we'll wait until we leave. - if (!m_active) { - sendClipboard(info->m_id); - } +bool Client::getClipboard(ClipboardID id, IClipboard *clipboard) const { + return m_screen->getClipboard(id, clipboard); } -bool -Client::isCompatible(int major, int minor) const -{ - const std::map< int, std::set > compatibleTable { - {6, {7, 8}}, //1.6 is compatible with 1.7 and 1.8 - {7, {8}} //1.7 is compatible with 1.8 - }; - - bool isCompatible = false; - - if (major == kProtocolMajorVersion) { - auto versions = compatibleTable.find(minor); - if (versions != compatibleTable.end()) { - auto compatibleVersions = versions->second; - isCompatible = compatibleVersions.find(kProtocolMinorVersion) != compatibleVersions.end(); - } - } - - return isCompatible; +void Client::getShape(SInt32 &x, SInt32 &y, SInt32 &w, SInt32 &h) const { + m_screen->getShape(x, y, w, h); } -void -Client::handleHello(const Event&, void*) -{ - SInt16 major, minor; - if (!ProtocolUtil::readf(m_stream, kMsgHello, &major, &minor)) { - sendConnectionFailedEvent("Protocol error from server, check encryption settings"); - cleanupTimer(); - cleanupConnection(); - return; - } - - // check versions - LOG((CLOG_DEBUG1 "got hello version %d.%d", major, minor)); - SInt16 helloBackMajor = kProtocolMajorVersion; - SInt16 helloBackMinor = kProtocolMinorVersion; - - if (isCompatible(major, minor)) { - //because 1.6 is comptable with 1.7 and 1.8 - downgrading protocol for server - LOG((CLOG_NOTE "downgrading protocol version for server")); - helloBackMinor = minor; - } - else if (major < kProtocolMajorVersion || - (major == kProtocolMajorVersion && minor < kProtocolMinorVersion)) { - sendConnectionFailedEvent(XIncompatibleClient(major, minor).what()); - cleanupTimer(); - cleanupConnection(); - return; - } - - // say hello back - LOG((CLOG_DEBUG1 "say hello version %d.%d", helloBackMajor, helloBackMinor)); - ProtocolUtil::writef(m_stream, kMsgHelloBack, helloBackMajor, helloBackMinor, &m_name); - - // now connected but waiting to complete handshake - setupScreen(); - cleanupTimer(); - - // make sure we process any remaining messages later. we won't - // receive another event for already pending messages so we fake - // one. - if (m_stream->isReady()) { - m_events->addEvent(Event(m_events->forIStream().inputReady(), - m_stream->getEventTarget())); - } +void Client::getCursorPos(SInt32 &x, SInt32 &y) const { + m_screen->getCursorPos(x, y); } -void -Client::handleSuspend(const Event&, void*) -{ - if (!m_suspended) { - LOG((CLOG_INFO "suspend")); - m_suspended = true; - bool wasConnected = isConnected(); - disconnect(NULL); - m_connectOnResume = wasConnected; - } -} - -void -Client::handleResume(const Event&, void*) -{ - if (m_suspended) { - LOG((CLOG_INFO "resume")); - m_suspended = false; - if (m_connectOnResume) { - m_connectOnResume = false; - connect(); - } - } -} - -void -Client::handleFileChunkSending(const Event& event, void*) -{ - sendFileChunk(event.getDataObject()); -} - -void -Client::handleFileRecieveCompleted(const Event& event, void*) -{ - onFileRecieveCompleted(); -} - -void -Client::onFileRecieveCompleted() -{ - if (isReceivedFileSizeValid()) { - auto method = new TMethodJob(this, &Client::writeToDropDirThread); - m_writeToDropDirThread.reset(new Thread(method)); - } -} - -void Client::bindNetworkInterface(IDataSocket *socket) const -{ - try { - if (!m_args.m_synergyAddress.empty()) { - LOG((CLOG_DEBUG1 "bind to network interface: %s", m_args.m_synergyAddress.c_str())); - - NetworkAddress bindAddress(m_args.m_synergyAddress); - bindAddress.resolve(); - - socket->bind(bindAddress); - } - } - catch(XBase& e) { - LOG((CLOG_WARN "%s", e.what())); - LOG((CLOG_WARN "operating system will select network interface automatically")); - } -} - -void -Client::handleStopRetry(const Event&, void*) -{ - m_args.m_restartable = false; -} - -void -Client::writeToDropDirThread(void*) -{ - LOG((CLOG_DEBUG "starting write to drop dir thread")); - - while (m_screen->isFakeDraggingStarted()) { - ARCH->sleep(.1f); - } - - DropHelper::writeToDir(m_screen->getDropTarget(), m_dragFileList, - m_receivedFileData); -} - -void -Client::dragInfoReceived(UInt32 fileNum, String data) -{ - // TODO: fix duplicate function from CServer - if (!m_args.m_enableDragDrop) { - LOG((CLOG_DEBUG "drag drop not enabled, ignoring drag info.")); - return; - } - - DragInformation::parseDragInfo(m_dragFileList, fileNum, data); - - m_screen->startDraggingFiles(m_dragFileList); -} - -bool -Client::isReceivedFileSizeValid() -{ - return m_expectedFileSize == m_receivedFileData.size(); -} - -void -Client::sendFileToServer(const char* filename) -{ - if (m_sendFileThread) { - StreamChunker::interruptFile(); - } - - auto data = static_cast(const_cast(filename)); - auto method = new TMethodJob(this, &Client::sendFileThread, data); - m_sendFileThread.reset(new Thread(method)); -} - -void -Client::sendFileThread(void* filename) -{ - try { - char* name = static_cast(filename); - StreamChunker::sendFile(name, m_events, this); - } - catch (std::runtime_error& error) { - LOG((CLOG_ERR "failed sending file chunks: %s", error.what())); - } +void Client::enter(SInt32 xAbs, SInt32 yAbs, UInt32, KeyModifierMask mask, + bool) { + m_active = true; + m_screen->mouseMove(xAbs, yAbs); + m_screen->enter(mask); + if (m_sendFileThread) { + StreamChunker::interruptFile(); m_sendFileThread.reset(nullptr); + } } -void -Client::sendDragInfo(UInt32 fileCount, String& info, size_t size) -{ - m_server->sendDragInfo(fileCount, info.c_str(), size); +bool Client::leave() { + m_active = false; + + m_screen->leave(); + + if (m_enableClipboard) { + // send clipboards that we own and that have changed + for (ClipboardID id = 0; id < kClipboardEnd; ++id) { + if (m_ownClipboard[id]) { + sendClipboard(id); + } + } + } + + return true; +} + +void Client::setClipboard(ClipboardID id, const IClipboard *clipboard) { + m_screen->setClipboard(id, clipboard); + m_ownClipboard[id] = false; + m_sentClipboard[id] = false; +} + +void Client::grabClipboard(ClipboardID id) { + m_screen->grabClipboard(id); + m_ownClipboard[id] = false; + m_sentClipboard[id] = false; +} + +void Client::setClipboardDirty(ClipboardID, bool) { + assert(0 && "shouldn't be called"); +} + +void Client::keyDown(KeyID id, KeyModifierMask mask, KeyButton button, + const String &lang) { + m_screen->keyDown(id, mask, button, lang); +} + +void Client::keyRepeat(KeyID id, KeyModifierMask mask, SInt32 count, + KeyButton button, const String &lang) { + m_screen->keyRepeat(id, mask, count, button, lang); +} + +void Client::keyUp(KeyID id, KeyModifierMask mask, KeyButton button) { + m_screen->keyUp(id, mask, button); +} + +void Client::mouseDown(ButtonID id) { m_screen->mouseDown(id); } + +void Client::mouseUp(ButtonID id) { m_screen->mouseUp(id); } + +void Client::mouseMove(SInt32 x, SInt32 y) { m_screen->mouseMove(x, y); } + +void Client::mouseRelativeMove(SInt32 dx, SInt32 dy) { + m_screen->mouseRelativeMove(dx, dy); +} + +void Client::mouseWheel(SInt32 xDelta, SInt32 yDelta) { + m_screen->mouseWheel(xDelta, yDelta); +} + +void Client::screensaver(bool activate) { m_screen->screensaver(activate); } + +void Client::resetOptions() { m_screen->resetOptions(); } + +void Client::setOptions(const OptionsList &options) { + for (OptionsList::const_iterator index = options.begin(); + index != options.end(); ++index) { + const OptionID id = *index; + if (id == kOptionClipboardSharing) { + index++; + if (index != options.end()) { + if (!*index) { + LOG((CLOG_NOTE "clipboard sharing disabled by server")); + } + m_enableClipboard = *index; + } + } else if (id == kOptionClipboardSharingSize) { + index++; + if (index != options.end()) { + m_maximumClipboardSize = *index; + } + } + } + + if (m_enableClipboard && !m_maximumClipboardSize) { + m_enableClipboard = false; + LOG((CLOG_NOTE "clipboard sharing is disabled because the server " + "set the maximum clipboard size to 0")); + } + + m_screen->setOptions(options); +} + +String Client::getName() const { return m_name; } + +void Client::sendClipboard(ClipboardID id) { + // note -- m_mutex must be locked on entry + assert(m_screen != NULL); + assert(m_server != NULL); + + // get clipboard data. set the clipboard time to the last + // clipboard time before getting the data from the screen + // as the screen may detect an unchanged clipboard and + // avoid copying the data. + Clipboard clipboard; + if (clipboard.open(m_timeClipboard[id])) { + clipboard.close(); + } + m_screen->getClipboard(id, &clipboard); + + // check time + if (m_timeClipboard[id] == 0 || clipboard.getTime() != m_timeClipboard[id]) { + // marshall the data + String data = clipboard.marshall(); + if (data.size() >= m_maximumClipboardSize * 1024) { + LOG((CLOG_NOTE "skipping clipboard transfer because the clipboard" + " contents exceeds the %i MB size limit set by the server", + m_maximumClipboardSize / 1024)); + return; + } + + // save new time + m_timeClipboard[id] = clipboard.getTime(); + // save and send data if different or not yet sent + if (!m_sentClipboard[id] || data != m_dataClipboard[id]) { + m_sentClipboard[id] = true; + m_dataClipboard[id] = data; + m_server->onClipboardChanged(id, &clipboard); + } + } +} + +void Client::sendEvent(Event::Type type, void *data) { + m_events->addEvent(Event(type, getEventTarget(), data)); +} + +void Client::sendConnectionFailedEvent(const char *msg) { + FailInfo *info = new FailInfo(msg); + info->m_retry = true; + Event event(m_events->forClient().connectionFailed(), getEventTarget(), info, + Event::kDontFreeData); + m_events->addEvent(event); +} + +void Client::sendFileChunk(const void *data) { + FileChunk *chunk = static_cast(const_cast(data)); + LOG((CLOG_DEBUG1 "send file chunk")); + assert(m_server != NULL); + + // relay + m_server->fileChunkSending(chunk->m_chunk[0], &chunk->m_chunk[1], + chunk->m_dataSize); +} + +void Client::setupConnecting() { + assert(m_stream != NULL); + + if (m_args.m_enableCrypto) { + m_events->adoptHandler( + m_events->forIDataSocket().secureConnected(), + m_stream->getEventTarget(), + new TMethodEventJob(this, &Client::handleConnected)); + } else { + m_events->adoptHandler( + m_events->forIDataSocket().connected(), m_stream->getEventTarget(), + new TMethodEventJob(this, &Client::handleConnected)); + } + + m_events->adoptHandler( + m_events->forIDataSocket().connectionFailed(), m_stream->getEventTarget(), + new TMethodEventJob(this, &Client::handleConnectionFailed)); +} + +void Client::setupConnection() { + assert(m_stream != NULL); + + m_events->adoptHandler( + m_events->forISocket().disconnected(), m_stream->getEventTarget(), + new TMethodEventJob(this, &Client::handleDisconnected)); + m_events->adoptHandler( + m_events->forIStream().inputReady(), m_stream->getEventTarget(), + new TMethodEventJob(this, &Client::handleHello)); + m_events->adoptHandler( + m_events->forIStream().outputError(), m_stream->getEventTarget(), + new TMethodEventJob(this, &Client::handleOutputError)); + m_events->adoptHandler( + m_events->forIStream().inputShutdown(), m_stream->getEventTarget(), + new TMethodEventJob(this, &Client::handleDisconnected)); + m_events->adoptHandler( + m_events->forIStream().outputShutdown(), m_stream->getEventTarget(), + new TMethodEventJob(this, &Client::handleDisconnected)); + + m_events->adoptHandler( + m_events->forISocket().stopRetry(), m_stream->getEventTarget(), + new TMethodEventJob(this, &Client::handleStopRetry)); +} + +void Client::setupScreen() { + assert(m_server == NULL); + + m_ready = false; + m_server = new ServerProxy(this, m_stream, m_events); + m_events->adoptHandler( + m_events->forIScreen().shapeChanged(), getEventTarget(), + new TMethodEventJob(this, &Client::handleShapeChanged)); + m_events->adoptHandler( + m_events->forClipboard().clipboardGrabbed(), getEventTarget(), + new TMethodEventJob(this, &Client::handleClipboardGrabbed)); +} + +void Client::setupTimer() { + assert(m_timer == NULL); + + if (!m_args.m_hostMode) { + m_timer = m_events->newOneShotTimer(2.0, NULL); + m_events->adoptHandler( + Event::kTimer, m_timer, + new TMethodEventJob(this, &Client::handleConnectTimeout)); + } +} + +void Client::cleanup() { + m_connectOnResume = false; + cleanupTimer(); + cleanupScreen(); + cleanupConnecting(); + cleanupConnection(); +} + +void Client::cleanupConnecting() { + if (m_stream != NULL) { + m_events->removeHandler(m_events->forIDataSocket().connected(), + m_stream->getEventTarget()); + m_events->removeHandler(m_events->forIDataSocket().connectionFailed(), + m_stream->getEventTarget()); + } +} + +void Client::cleanupConnection() { + if (m_stream != NULL) { + m_events->removeHandler(m_events->forIStream().inputReady(), + m_stream->getEventTarget()); + m_events->removeHandler(m_events->forIStream().outputError(), + m_stream->getEventTarget()); + m_events->removeHandler(m_events->forIStream().inputShutdown(), + m_stream->getEventTarget()); + m_events->removeHandler(m_events->forIStream().outputShutdown(), + m_stream->getEventTarget()); + m_events->removeHandler(m_events->forISocket().disconnected(), + m_stream->getEventTarget()); + m_events->removeHandler(m_events->forISocket().stopRetry(), + m_stream->getEventTarget()); + cleanupStream(); + } +} + +void Client::cleanupScreen() { + if (m_server != NULL) { + if (m_ready) { + m_screen->disable(); + m_ready = false; + } + m_events->removeHandler(m_events->forIScreen().shapeChanged(), + getEventTarget()); + m_events->removeHandler(m_events->forClipboard().clipboardGrabbed(), + getEventTarget()); + delete m_server; + m_server = NULL; + } +} + +void Client::cleanupTimer() { + if (m_timer != NULL) { + m_events->removeHandler(Event::kTimer, m_timer); + m_events->deleteTimer(m_timer); + m_timer = NULL; + } +} + +void Client::cleanupStream() { + delete m_stream; + m_stream = NULL; +} + +void Client::handleConnected(const Event &, void *) { + LOG((CLOG_DEBUG1 "connected; wait for hello")); + cleanupConnecting(); + setupConnection(); + + // reset clipboard state + for (ClipboardID id = 0; id < kClipboardEnd; ++id) { + m_ownClipboard[id] = false; + m_sentClipboard[id] = false; + m_timeClipboard[id] = 0; + } +} + +void Client::handleConnectionFailed(const Event &event, void *) { + IDataSocket::ConnectionFailedInfo *info = + static_cast(event.getData()); + + cleanupTimer(); + cleanupConnecting(); + cleanupStream(); + LOG((CLOG_DEBUG1 "connection failed")); + sendConnectionFailedEvent(info->m_what.c_str()); + delete info; +} + +void Client::handleConnectTimeout(const Event &, void *) { + cleanupTimer(); + cleanupConnecting(); + cleanupConnection(); + cleanupStream(); + LOG((CLOG_DEBUG1 "connection timed out")); + sendConnectionFailedEvent("Timed out"); +} + +void Client::handleOutputError(const Event &, void *) { + cleanupTimer(); + cleanupScreen(); + cleanupConnection(); + LOG((CLOG_WARN "error sending to server")); + sendEvent(m_events->forClient().disconnected(), NULL); +} + +void Client::handleDisconnected(const Event &, void *) { + cleanupTimer(); + cleanupScreen(); + cleanupConnection(); + LOG((CLOG_DEBUG1 "disconnected")); + sendEvent(m_events->forClient().disconnected(), NULL); +} + +void Client::handleShapeChanged(const Event &, void *) { + LOG((CLOG_DEBUG "resolution changed")); + m_server->onInfoChanged(); +} + +void Client::handleClipboardGrabbed(const Event &event, void *) { + if (!m_enableClipboard || (m_maximumClipboardSize == 0)) { + return; + } + + const IScreen::ClipboardInfo *info = + static_cast(event.getData()); + + // grab ownership + m_server->onGrabClipboard(info->m_id); + + // we now own the clipboard and it has not been sent to the server + m_ownClipboard[info->m_id] = true; + m_sentClipboard[info->m_id] = false; + m_timeClipboard[info->m_id] = 0; + + // if we're not the active screen then send the clipboard now, + // otherwise we'll wait until we leave. + if (!m_active) { + sendClipboard(info->m_id); + } +} + +bool Client::isCompatible(int major, int minor) const { + const std::map> compatibleTable{ + {6, {7, 8}}, // 1.6 is compatible with 1.7 and 1.8 + {7, {8}} // 1.7 is compatible with 1.8 + }; + + bool isCompatible = false; + + if (major == kProtocolMajorVersion) { + auto versions = compatibleTable.find(minor); + if (versions != compatibleTable.end()) { + auto compatibleVersions = versions->second; + isCompatible = compatibleVersions.find(kProtocolMinorVersion) != + compatibleVersions.end(); + } + } + + return isCompatible; +} + +void Client::handleHello(const Event &, void *) { + SInt16 major, minor; + if (!ProtocolUtil::readf(m_stream, kMsgHello, &major, &minor)) { + sendConnectionFailedEvent( + "Protocol error from server, check encryption settings"); + cleanupTimer(); + cleanupConnection(); + return; + } + + // check versions + LOG((CLOG_DEBUG1 "got hello version %d.%d", major, minor)); + SInt16 helloBackMajor = kProtocolMajorVersion; + SInt16 helloBackMinor = kProtocolMinorVersion; + + if (isCompatible(major, minor)) { + // because 1.6 is comptable with 1.7 and 1.8 - downgrading protocol for + // server + LOG((CLOG_NOTE "downgrading protocol version for server")); + helloBackMinor = minor; + } else if (major < kProtocolMajorVersion || (major == kProtocolMajorVersion && + minor < kProtocolMinorVersion)) { + sendConnectionFailedEvent(XIncompatibleClient(major, minor).what()); + cleanupTimer(); + cleanupConnection(); + return; + } + + // say hello back + LOG((CLOG_DEBUG1 "say hello version %d.%d", helloBackMajor, helloBackMinor)); + ProtocolUtil::writef(m_stream, kMsgHelloBack, helloBackMajor, helloBackMinor, + &m_name); + + // now connected but waiting to complete handshake + setupScreen(); + cleanupTimer(); + + // make sure we process any remaining messages later. we won't + // receive another event for already pending messages so we fake + // one. + if (m_stream->isReady()) { + m_events->addEvent( + Event(m_events->forIStream().inputReady(), m_stream->getEventTarget())); + } +} + +void Client::handleSuspend(const Event &, void *) { + if (!m_suspended) { + LOG((CLOG_INFO "suspend")); + m_suspended = true; + bool wasConnected = isConnected(); + disconnect(NULL); + m_connectOnResume = wasConnected; + } +} + +void Client::handleResume(const Event &, void *) { + if (m_suspended) { + LOG((CLOG_INFO "resume")); + m_suspended = false; + if (m_connectOnResume) { + m_connectOnResume = false; + connect(); + } + } +} + +void Client::handleFileChunkSending(const Event &event, void *) { + sendFileChunk(event.getDataObject()); +} + +void Client::handleFileRecieveCompleted(const Event &event, void *) { + onFileRecieveCompleted(); +} + +void Client::onFileRecieveCompleted() { + if (isReceivedFileSizeValid()) { + auto method = new TMethodJob(this, &Client::writeToDropDirThread); + m_writeToDropDirThread.reset(new Thread(method)); + } +} + +void Client::bindNetworkInterface(IDataSocket *socket) const { + try { + if (!m_args.m_synergyAddress.empty()) { + LOG((CLOG_DEBUG1 "bind to network interface: %s", + m_args.m_synergyAddress.c_str())); + + NetworkAddress bindAddress(m_args.m_synergyAddress); + bindAddress.resolve(); + + socket->bind(bindAddress); + } + } catch (XBase &e) { + LOG((CLOG_WARN "%s", e.what())); + LOG((CLOG_WARN + "operating system will select network interface automatically")); + } +} + +void Client::handleStopRetry(const Event &, void *) { + m_args.m_restartable = false; +} + +void Client::writeToDropDirThread(void *) { + LOG((CLOG_DEBUG "starting write to drop dir thread")); + + while (m_screen->isFakeDraggingStarted()) { + ARCH->sleep(.1f); + } + + DropHelper::writeToDir(m_screen->getDropTarget(), m_dragFileList, + m_receivedFileData); +} + +void Client::dragInfoReceived(UInt32 fileNum, String data) { + // TODO: fix duplicate function from CServer + if (!m_args.m_enableDragDrop) { + LOG((CLOG_DEBUG "drag drop not enabled, ignoring drag info.")); + return; + } + + DragInformation::parseDragInfo(m_dragFileList, fileNum, data); + + m_screen->startDraggingFiles(m_dragFileList); +} + +bool Client::isReceivedFileSizeValid() { + return m_expectedFileSize == m_receivedFileData.size(); +} + +void Client::sendFileToServer(const char *filename) { + if (m_sendFileThread) { + StreamChunker::interruptFile(); + } + + auto data = static_cast(const_cast(filename)); + auto method = new TMethodJob(this, &Client::sendFileThread, data); + m_sendFileThread.reset(new Thread(method)); +} + +void Client::sendFileThread(void *filename) { + try { + char *name = static_cast(filename); + StreamChunker::sendFile(name, m_events, this); + } catch (std::runtime_error &error) { + LOG((CLOG_ERR "failed sending file chunks: %s", error.what())); + } + + m_sendFileThread.reset(nullptr); +} + +void Client::sendDragInfo(UInt32 fileCount, String &info, size_t size) { + m_server->sendDragInfo(fileCount, info.c_str(), size); } diff --git a/src/lib/client/Client.h b/src/lib/client/Client.h index 7c5f14147..c0dfeaa2b 100644 --- a/src/lib/client/Client.h +++ b/src/lib/client/Client.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -20,21 +20,25 @@ #include "synergy/IClient.h" +#include "base/EventTypes.h" +#include "mt/CondVar.h" +#include "net/NetworkAddress.h" +#include "synergy/ClientArgs.h" #include "synergy/Clipboard.h" #include "synergy/DragInformation.h" #include "synergy/INode.h" -#include "synergy/ClientArgs.h" -#include "net/NetworkAddress.h" -#include "base/EventTypes.h" -#include "mt/CondVar.h" #include class EventQueueTimer; -namespace synergy { class Screen; } +namespace synergy { +class Screen; +} class ServerProxy; class IDataSocket; class ISocketFactory; -namespace synergy { class IStream; } +namespace synergy { +class IStream; +} class IEventQueue; class Thread; class TCPSocket; @@ -45,203 +49,203 @@ This class implements the top-level client algorithms for synergy. */ class Client : public IClient, public INode { public: - class FailInfo { - public: - FailInfo(const char* what) : m_retry(false), m_what(what) { } - bool m_retry; - String m_what; - }; + class FailInfo { + public: + FailInfo(const char *what) : m_retry(false), m_what(what) {} + bool m_retry; + String m_what; + }; public: - /*! - This client will attempt to connect to the server using \p name - as its name and \p address as the server's address and \p factory - to create the socket. \p screen is the local screen. - */ - Client(IEventQueue* events, const String& name, - const NetworkAddress& address, ISocketFactory* socketFactory, - synergy::Screen* screen, lib::synergy::ClientArgs const& args); - Client(Client const &) =delete; - Client(Client &&) =delete; - ~Client(); + /*! + This client will attempt to connect to the server using \p name + as its name and \p address as the server's address and \p factory + to create the socket. \p screen is the local screen. + */ + Client(IEventQueue *events, const String &name, const NetworkAddress &address, + ISocketFactory *socketFactory, synergy::Screen *screen, + lib::synergy::ClientArgs const &args); + Client(Client const &) = delete; + Client(Client &&) = delete; + ~Client(); - Client& operator=(Client const &) =delete; - Client& operator=(Client &&) =delete; + Client &operator=(Client const &) = delete; + Client &operator=(Client &&) = delete; - //! @name manipulators - //@{ + //! @name manipulators + //@{ - //! Connect to server - /*! - Starts an attempt to connect to the server. This is ignored if - the client is trying to connect or is already connected. - */ - void connect(size_t addressIndex = 0); + //! Connect to server + /*! + Starts an attempt to connect to the server. This is ignored if + the client is trying to connect or is already connected. + */ + void connect(size_t addressIndex = 0); - //! Disconnect - /*! - Disconnects from the server with an optional error message. - */ - void disconnect(const char* msg); + //! Disconnect + /*! + Disconnects from the server with an optional error message. + */ + void disconnect(const char *msg); - //! Refuse connection - /*! - Disconnects from the server with an optional error message. - Unlike disconnect this function doesn't try to use other ip addresses - */ - void refuseConnection(const char* msg); + //! Refuse connection + /*! + Disconnects from the server with an optional error message. + Unlike disconnect this function doesn't try to use other ip addresses + */ + void refuseConnection(const char *msg); - //! Notify of handshake complete - /*! - Notifies the client that the connection handshake has completed. - */ - virtual void handshakeComplete(); + //! Notify of handshake complete + /*! + Notifies the client that the connection handshake has completed. + */ + virtual void handshakeComplete(); - //! Received drag information - void dragInfoReceived(UInt32 fileNum, String data); + //! Received drag information + void dragInfoReceived(UInt32 fileNum, String data); - //! Create a new thread and use it to send file to Server - void sendFileToServer(const char* filename); - - //! Send dragging file information back to server - void sendDragInfo(UInt32 fileCount, String& info, size_t size); + //! Create a new thread and use it to send file to Server + void sendFileToServer(const char *filename); - - //@} - //! @name accessors - //@{ + //! Send dragging file information back to server + void sendDragInfo(UInt32 fileCount, String &info, size_t size); - //! Test if connected - /*! - Returns true iff the client is successfully connected to the server. - */ - bool isConnected() const; + //@} + //! @name accessors + //@{ - //! Test if connecting - /*! - Returns true iff the client is currently attempting to connect to - the server. - */ - bool isConnecting() const; + //! Test if connected + /*! + Returns true iff the client is successfully connected to the server. + */ + bool isConnected() const; - //! Get address of server - /*! - Returns the address of the server the client is connected (or wants - to connect) to. - */ - NetworkAddress getServerAddress() const; - - //! Return true if received file size is valid - bool isReceivedFileSizeValid(); + //! Test if connecting + /*! + Returns true iff the client is currently attempting to connect to + the server. + */ + bool isConnecting() const; - //! Return expected file size - size_t& getExpectedFileSize() { return m_expectedFileSize; } + //! Get address of server + /*! + Returns the address of the server the client is connected (or wants + to connect) to. + */ + NetworkAddress getServerAddress() const; - //! Return received file data - String& getReceivedFileData() { return m_receivedFileData; } + //! Return true if received file size is valid + bool isReceivedFileSizeValid(); - //! Return drag file list - DragFileList getDragFileList() { return m_dragFileList; } + //! Return expected file size + size_t &getExpectedFileSize() { return m_expectedFileSize; } - //! Return last resolved adresses count - size_t getLastResolvedAddressesCount() const { return m_resolvedAddressesCount; } + //! Return received file data + String &getReceivedFileData() { return m_receivedFileData; } - //@} + //! Return drag file list + DragFileList getDragFileList() { return m_dragFileList; } - // IScreen overrides - virtual void* getEventTarget() const; - virtual bool getClipboard(ClipboardID id, IClipboard*) const; - virtual void getShape(SInt32& x, SInt32& y, - SInt32& width, SInt32& height) const; - virtual void getCursorPos(SInt32& x, SInt32& y) const; + //! Return last resolved adresses count + size_t getLastResolvedAddressesCount() const { + return m_resolvedAddressesCount; + } - // IClient overrides - virtual void enter(SInt32 xAbs, SInt32 yAbs, - UInt32 seqNum, KeyModifierMask mask, - bool forScreensaver); - virtual bool leave(); - virtual void setClipboard(ClipboardID, const IClipboard*); - virtual void grabClipboard(ClipboardID); - virtual void setClipboardDirty(ClipboardID, bool); - virtual void keyDown(KeyID, KeyModifierMask, KeyButton, const String&); - virtual void keyRepeat(KeyID, KeyModifierMask, - SInt32 count, KeyButton, const String& lang); - virtual void keyUp(KeyID, KeyModifierMask, KeyButton); - virtual void mouseDown(ButtonID); - virtual void mouseUp(ButtonID); - virtual void mouseMove(SInt32 xAbs, SInt32 yAbs); - virtual void mouseRelativeMove(SInt32 xRel, SInt32 yRel); - virtual void mouseWheel(SInt32 xDelta, SInt32 yDelta); - virtual void screensaver(bool activate); - virtual void resetOptions(); - virtual void setOptions(const OptionsList& options); - virtual String getName() const; + //@} + + // IScreen overrides + virtual void *getEventTarget() const; + virtual bool getClipboard(ClipboardID id, IClipboard *) const; + virtual void getShape(SInt32 &x, SInt32 &y, SInt32 &width, + SInt32 &height) const; + virtual void getCursorPos(SInt32 &x, SInt32 &y) const; + + // IClient overrides + virtual void enter(SInt32 xAbs, SInt32 yAbs, UInt32 seqNum, + KeyModifierMask mask, bool forScreensaver); + virtual bool leave(); + virtual void setClipboard(ClipboardID, const IClipboard *); + virtual void grabClipboard(ClipboardID); + virtual void setClipboardDirty(ClipboardID, bool); + virtual void keyDown(KeyID, KeyModifierMask, KeyButton, const String &); + virtual void keyRepeat(KeyID, KeyModifierMask, SInt32 count, KeyButton, + const String &lang); + virtual void keyUp(KeyID, KeyModifierMask, KeyButton); + virtual void mouseDown(ButtonID); + virtual void mouseUp(ButtonID); + virtual void mouseMove(SInt32 xAbs, SInt32 yAbs); + virtual void mouseRelativeMove(SInt32 xRel, SInt32 yRel); + virtual void mouseWheel(SInt32 xDelta, SInt32 yDelta); + virtual void screensaver(bool activate); + virtual void resetOptions(); + virtual void setOptions(const OptionsList &options); + virtual String getName() const; private: - void sendClipboard(ClipboardID); - void sendEvent(Event::Type, void*); - void sendConnectionFailedEvent(const char* msg); - void sendFileChunk(const void* data); - void sendFileThread(void*); - void writeToDropDirThread(void*); - void setupConnecting(); - void setupConnection(); - void setupScreen(); - void setupTimer(); - void cleanup(); - void cleanupConnecting(); - void cleanupConnection(); - void cleanupScreen(); - void cleanupTimer(); - void cleanupStream(); - void handleConnected(const Event&, void*); - void handleConnectionFailed(const Event&, void*); - void handleConnectTimeout(const Event&, void*); - void handleOutputError(const Event&, void*); - void handleDisconnected(const Event&, void*); - void handleShapeChanged(const Event&, void*); - void handleClipboardGrabbed(const Event&, void*); - bool isCompatible(int major, int minor) const; - void handleHello(const Event&, void*); - void handleSuspend(const Event& event, void*); - void handleResume(const Event& event, void*); - void handleFileChunkSending(const Event&, void*); - void handleFileRecieveCompleted(const Event&, void*); - void handleStopRetry(const Event&, void*); - void onFileRecieveCompleted(); - void sendClipboardThread(void*); - void bindNetworkInterface(IDataSocket* socket) const; + void sendClipboard(ClipboardID); + void sendEvent(Event::Type, void *); + void sendConnectionFailedEvent(const char *msg); + void sendFileChunk(const void *data); + void sendFileThread(void *); + void writeToDropDirThread(void *); + void setupConnecting(); + void setupConnection(); + void setupScreen(); + void setupTimer(); + void cleanup(); + void cleanupConnecting(); + void cleanupConnection(); + void cleanupScreen(); + void cleanupTimer(); + void cleanupStream(); + void handleConnected(const Event &, void *); + void handleConnectionFailed(const Event &, void *); + void handleConnectTimeout(const Event &, void *); + void handleOutputError(const Event &, void *); + void handleDisconnected(const Event &, void *); + void handleShapeChanged(const Event &, void *); + void handleClipboardGrabbed(const Event &, void *); + bool isCompatible(int major, int minor) const; + void handleHello(const Event &, void *); + void handleSuspend(const Event &event, void *); + void handleResume(const Event &event, void *); + void handleFileChunkSending(const Event &, void *); + void handleFileRecieveCompleted(const Event &, void *); + void handleStopRetry(const Event &, void *); + void onFileRecieveCompleted(); + void sendClipboardThread(void *); + void bindNetworkInterface(IDataSocket *socket) const; public: - bool m_mock; + bool m_mock; private: - String m_name; - NetworkAddress m_serverAddress; - ISocketFactory* m_socketFactory; - synergy::Screen* m_screen; - synergy::IStream* m_stream; - EventQueueTimer* m_timer; - ServerProxy* m_server; - bool m_ready; - bool m_active; - bool m_suspended; - bool m_connectOnResume; - bool m_ownClipboard[kClipboardEnd]; - bool m_sentClipboard[kClipboardEnd]; - IClipboard::Time m_timeClipboard[kClipboardEnd]; - String m_dataClipboard[kClipboardEnd]; - IEventQueue* m_events; - std::size_t m_expectedFileSize; - String m_receivedFileData; - DragFileList m_dragFileList; - String m_dragFileExt; - using AutoThread = std::unique_ptr; - AutoThread m_sendFileThread; - AutoThread m_writeToDropDirThread; - bool m_useSecureNetwork; - bool m_enableClipboard; - size_t m_maximumClipboardSize; - lib::synergy::ClientArgs m_args; - size_t m_resolvedAddressesCount = 0; + String m_name; + NetworkAddress m_serverAddress; + ISocketFactory *m_socketFactory; + synergy::Screen *m_screen; + synergy::IStream *m_stream; + EventQueueTimer *m_timer; + ServerProxy *m_server; + bool m_ready; + bool m_active; + bool m_suspended; + bool m_connectOnResume; + bool m_ownClipboard[kClipboardEnd]; + bool m_sentClipboard[kClipboardEnd]; + IClipboard::Time m_timeClipboard[kClipboardEnd]; + String m_dataClipboard[kClipboardEnd]; + IEventQueue *m_events; + std::size_t m_expectedFileSize; + String m_receivedFileData; + DragFileList m_dragFileList; + String m_dragFileExt; + using AutoThread = std::unique_ptr; + AutoThread m_sendFileThread; + AutoThread m_writeToDropDirThread; + bool m_useSecureNetwork; + bool m_enableClipboard; + size_t m_maximumClipboardSize; + lib::synergy::ClientArgs m_args; + size_t m_resolvedAddressesCount = 0; }; diff --git a/src/lib/client/ServerProxy.cpp b/src/lib/client/ServerProxy.cpp index e2882acc7..7e8e7199f 100644 --- a/src/lib/client/ServerProxy.cpp +++ b/src/lib/client/ServerProxy.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -18,984 +18,882 @@ #include "client/ServerProxy.h" -#include "client/Client.h" -#include "synergy/FileChunk.h" -#include "synergy/ClipboardChunk.h" -#include "synergy/StreamChunker.h" -#include "synergy/Clipboard.h" -#include "synergy/ProtocolUtil.h" -#include "synergy/option_types.h" -#include "synergy/protocol_types.h" -#include "synergy/AppUtil.h" -#include "io/IStream.h" -#include "base/Log.h" #include "base/IEventQueue.h" +#include "base/Log.h" #include "base/TMethodEventJob.h" #include "base/XBase.h" +#include "client/Client.h" +#include "io/IStream.h" +#include "synergy/AppUtil.h" +#include "synergy/Clipboard.h" +#include "synergy/ClipboardChunk.h" +#include "synergy/FileChunk.h" +#include "synergy/ProtocolUtil.h" +#include "synergy/StreamChunker.h" +#include "synergy/option_types.h" +#include "synergy/protocol_types.h" -#include #include #include +#include // // ServerProxy // -ServerProxy::ServerProxy(Client* client, synergy::IStream* stream, IEventQueue* events) : - m_client(client), - m_stream(stream), - m_seqNum(0), - m_compressMouse(false), - m_compressMouseRelative(false), - m_xMouse(0), - m_yMouse(0), - m_dxMouse(0), - m_dyMouse(0), - m_ignoreMouse(false), - m_keepAliveAlarm(0.0), - m_keepAliveAlarmTimer(NULL), - m_parser(&ServerProxy::parseHandshakeMessage), - m_events(events) -{ - assert(m_client != NULL); - assert(m_stream != NULL); +ServerProxy::ServerProxy(Client *client, synergy::IStream *stream, + IEventQueue *events) + : m_client(client), m_stream(stream), m_seqNum(0), m_compressMouse(false), + m_compressMouseRelative(false), m_xMouse(0), m_yMouse(0), m_dxMouse(0), + m_dyMouse(0), m_ignoreMouse(false), m_keepAliveAlarm(0.0), + m_keepAliveAlarmTimer(NULL), + m_parser(&ServerProxy::parseHandshakeMessage), m_events(events) { + assert(m_client != NULL); + assert(m_stream != NULL); - // initialize modifier translation table - for (KeyModifierID id = 0; id < kKeyModifierIDLast; ++id) - m_modifierTranslationTable[id] = id; + // initialize modifier translation table + for (KeyModifierID id = 0; id < kKeyModifierIDLast; ++id) + m_modifierTranslationTable[id] = id; - // handle data on stream - m_events->adoptHandler(m_events->forIStream().inputReady(), - m_stream->getEventTarget(), - new TMethodEventJob(this, - &ServerProxy::handleData)); + // handle data on stream + m_events->adoptHandler( + m_events->forIStream().inputReady(), m_stream->getEventTarget(), + new TMethodEventJob(this, &ServerProxy::handleData)); - m_events->adoptHandler(m_events->forClipboard().clipboardSending(), - this, - new TMethodEventJob(this, - &ServerProxy::handleClipboardSendingEvent)); + m_events->adoptHandler(m_events->forClipboard().clipboardSending(), this, + new TMethodEventJob( + this, &ServerProxy::handleClipboardSendingEvent)); - // send heartbeat - setKeepAliveRate(kKeepAliveRate); + // send heartbeat + setKeepAliveRate(kKeepAliveRate); } -ServerProxy::~ServerProxy() -{ - setKeepAliveRate(-1.0); - m_events->removeHandler(m_events->forIStream().inputReady(), - m_stream->getEventTarget()); +ServerProxy::~ServerProxy() { + setKeepAliveRate(-1.0); + m_events->removeHandler(m_events->forIStream().inputReady(), + m_stream->getEventTarget()); } -void -ServerProxy::resetKeepAliveAlarm() -{ - if (m_keepAliveAlarmTimer != NULL) { - m_events->removeHandler(Event::kTimer, m_keepAliveAlarmTimer); - m_events->deleteTimer(m_keepAliveAlarmTimer); - m_keepAliveAlarmTimer = NULL; - } - if (m_keepAliveAlarm > 0.0) { - m_keepAliveAlarmTimer = - m_events->newOneShotTimer(m_keepAliveAlarm, NULL); - m_events->adoptHandler(Event::kTimer, m_keepAliveAlarmTimer, - new TMethodEventJob(this, - &ServerProxy::handleKeepAliveAlarm)); - } +void ServerProxy::resetKeepAliveAlarm() { + if (m_keepAliveAlarmTimer != NULL) { + m_events->removeHandler(Event::kTimer, m_keepAliveAlarmTimer); + m_events->deleteTimer(m_keepAliveAlarmTimer); + m_keepAliveAlarmTimer = NULL; + } + if (m_keepAliveAlarm > 0.0) { + m_keepAliveAlarmTimer = m_events->newOneShotTimer(m_keepAliveAlarm, NULL); + m_events->adoptHandler(Event::kTimer, m_keepAliveAlarmTimer, + new TMethodEventJob( + this, &ServerProxy::handleKeepAliveAlarm)); + } } -void -ServerProxy::setKeepAliveRate(double rate) -{ - m_keepAliveAlarm = rate * kKeepAlivesUntilDeath; - resetKeepAliveAlarm(); +void ServerProxy::setKeepAliveRate(double rate) { + m_keepAliveAlarm = rate * kKeepAlivesUntilDeath; + resetKeepAliveAlarm(); } -void -ServerProxy::handleData(const Event&, void*) -{ - // handle messages until there are no more. first read message code. - UInt8 code[4]; - UInt32 n = m_stream->read(code, 4); - while (n != 0) { - // verify we got an entire code - if (n != 4) { - LOG((CLOG_ERR "incomplete message from server: %d bytes", n)); - m_client->disconnect("incomplete message from server"); - return; - } - - // parse message - LOG((CLOG_DEBUG2 "msg from server: %c%c%c%c", code[0], code[1], code[2], code[3])); - switch ((this->*m_parser)(code)) { - case kOkay: - break; - - case kUnknown: - LOG((CLOG_ERR "invalid message from server: %c%c%c%c", code[0], code[1], code[2], code[3])); - // not possible to determine message boundaries - // read the whole stream to discard unkonwn data - while (m_stream->read(nullptr, 4)); - break; - - case kDisconnect: - return; - } - - // next message - n = m_stream->read(code, 4); +void ServerProxy::handleData(const Event &, void *) { + // handle messages until there are no more. first read message code. + UInt8 code[4]; + UInt32 n = m_stream->read(code, 4); + while (n != 0) { + // verify we got an entire code + if (n != 4) { + LOG((CLOG_ERR "incomplete message from server: %d bytes", n)); + m_client->disconnect("incomplete message from server"); + return; } - flushCompressedMouse(); + // parse message + LOG((CLOG_DEBUG2 "msg from server: %c%c%c%c", code[0], code[1], code[2], + code[3])); + switch ((this->*m_parser)(code)) { + case kOkay: + break; + + case kUnknown: + LOG((CLOG_ERR "invalid message from server: %c%c%c%c", code[0], code[1], + code[2], code[3])); + // not possible to determine message boundaries + // read the whole stream to discard unkonwn data + while (m_stream->read(nullptr, 4)) + ; + break; + + case kDisconnect: + return; + } + + // next message + n = m_stream->read(code, 4); + } + + flushCompressedMouse(); } -ServerProxy::EResult -ServerProxy::parseHandshakeMessage(const UInt8* code) -{ - if (memcmp(code, kMsgQInfo, 4) == 0) { - queryInfo(); - } - - else if (memcmp(code, kMsgCInfoAck, 4) == 0) { - infoAcknowledgment(); - } - - else if (memcmp(code, kMsgDSetOptions, 4) == 0) { - setOptions(); - - // handshake is complete - m_parser = &ServerProxy::parseMessage; - checkMissedLanguages(); - m_client->handshakeComplete(); - } - - else if (memcmp(code, kMsgCResetOptions, 4) == 0) { - resetOptions(); - } - - else if (memcmp(code, kMsgCKeepAlive, 4) == 0) { - // echo keep alives and reset alarm - ProtocolUtil::writef(m_stream, kMsgCKeepAlive); - resetKeepAliveAlarm(); - } - - else if (memcmp(code, kMsgCNoop, 4) == 0) { - // accept and discard no-op - } - - else if (memcmp(code, kMsgCClose, 4) == 0) { - // server wants us to hangup - LOG((CLOG_DEBUG1 "recv close")); - m_client->disconnect(NULL); - return kDisconnect; - } - - else if (memcmp(code, kMsgEIncompatible, 4) == 0) { - SInt32 major, minor; - ProtocolUtil::readf(m_stream, - kMsgEIncompatible + 4, &major, &minor); - LOG((CLOG_ERR "server has incompatible version %d.%d", major, minor)); - m_client->refuseConnection("server has incompatible version"); - return kDisconnect; - } - - else if (memcmp(code, kMsgEBusy, 4) == 0) { - LOG((CLOG_ERR "server already has a connected client with name \"%s\"", m_client->getName().c_str())); - m_client->refuseConnection("server already has a connected client with our name"); - return kDisconnect; - } - - else if (memcmp(code, kMsgEUnknown, 4) == 0) { - LOG((CLOG_ERR "server refused client with name \"%s\"", m_client->getName().c_str())); - m_client->refuseConnection("server refused client with our name"); - return kDisconnect; - } - - else if (memcmp(code, kMsgEBad, 4) == 0) { - LOG((CLOG_ERR "server disconnected due to a protocol error")); - m_client->refuseConnection("server reported a protocol error"); - return kDisconnect; - } - else if (memcmp(code, kMsgDLanguageSynchronisation, 4) == 0) { - setServerLanguages(); - } - else { - return kUnknown; - } - - return kOkay; -} - -ServerProxy::EResult -ServerProxy::parseMessage(const UInt8* code) -{ - if (memcmp(code, kMsgDMouseMove, 4) == 0) { - mouseMove(); - } - - else if (memcmp(code, kMsgDMouseRelMove, 4) == 0) { - mouseRelativeMove(); - } - - else if (memcmp(code, kMsgDMouseWheel, 4) == 0) { - mouseWheel(); - } - - else if (memcmp(code, kMsgDKeyDown, 4) == 0) { - UInt16 id = 0; - UInt16 mask = 0; - UInt16 button = 0; - ProtocolUtil::readf(m_stream, kMsgDKeyDown + 4, &id, &mask, &button); - LOG((CLOG_DEBUG1 "recv key down id=0x%08x, mask=0x%04x, button=0x%04x", id, mask, button)); - - keyDown(id, mask, button, ""); - } - - else if (memcmp(code, kMsgDKeyDownLang, 4) == 0) { - String lang; - UInt16 id = 0; - UInt16 mask = 0; - UInt16 button = 0; - - ProtocolUtil::readf(m_stream, kMsgDKeyDownLang + 4, &id, &mask, &button, &lang); - LOG((CLOG_DEBUG1 "recv key down id=0x%08x, mask=0x%04x, button=0x%04x, lang=\"%s\"", id, mask, button, lang.c_str())); - - keyDown(id, mask, button, lang); - } - - else if (memcmp(code, kMsgDKeyUp, 4) == 0) { - keyUp(); - } - - else if (memcmp(code, kMsgDMouseDown, 4) == 0) { - mouseDown(); - } - - else if (memcmp(code, kMsgDMouseUp, 4) == 0) { - mouseUp(); - } - - else if (memcmp(code, kMsgDKeyRepeat, 4) == 0) { - keyRepeat(); - } - - else if (memcmp(code, kMsgCKeepAlive, 4) == 0) { - // echo keep alives and reset alarm - ProtocolUtil::writef(m_stream, kMsgCKeepAlive); - resetKeepAliveAlarm(); - } - - else if (memcmp(code, kMsgCNoop, 4) == 0) { - // accept and discard no-op - } - - else if (memcmp(code, kMsgCEnter, 4) == 0) { - enter(); - } - - else if (memcmp(code, kMsgCLeave, 4) == 0) { - leave(); - } - - else if (memcmp(code, kMsgCClipboard, 4) == 0) { - grabClipboard(); - } - - else if (memcmp(code, kMsgCScreenSaver, 4) == 0) { - screensaver(); - } - - else if (memcmp(code, kMsgQInfo, 4) == 0) { - queryInfo(); - } - - else if (memcmp(code, kMsgCInfoAck, 4) == 0) { - infoAcknowledgment(); - } - - else if (memcmp(code, kMsgDClipboard, 4) == 0) { - setClipboard(); - } - - else if (memcmp(code, kMsgCResetOptions, 4) == 0) { - resetOptions(); - } - - else if (memcmp(code, kMsgDSetOptions, 4) == 0) { - setOptions(); - } - - else if (memcmp(code, kMsgDFileTransfer, 4) == 0) { - fileChunkReceived(); - } - else if (memcmp(code, kMsgDDragInfo, 4) == 0) { - dragInfoReceived(); - } - else if (memcmp(code, kMsgDSecureInputNotification, 4) == 0) { - secureInputNotification(); - } - - else if (memcmp(code, kMsgCClose, 4) == 0) { - // server wants us to hangup - LOG((CLOG_DEBUG1 "recv close")); - m_client->disconnect(NULL); - return kDisconnect; - } - else if (memcmp(code, kMsgEBad, 4) == 0) { - LOG((CLOG_ERR "server disconnected due to a protocol error")); - m_client->disconnect("server reported a protocol error"); - return kDisconnect; - } - else { - return kUnknown; - } - - // send a reply. this is intended to work around a delay when - // running a linux server and an OS X (any BSD?) client. the - // client waits to send an ACK (if the system control flag - // net.inet.tcp.delayed_ack is 1) in hopes of piggybacking it - // on a data packet. we provide that packet here. i don't - // know why a delayed ACK should cause the server to wait since - // TCP_NODELAY is enabled. - ProtocolUtil::writef(m_stream, kMsgCNoop); - - return kOkay; -} - -void -ServerProxy::handleKeepAliveAlarm(const Event&, void*) -{ - LOG((CLOG_NOTE "server is dead")); - m_client->disconnect("server is not responding"); -} - -void -ServerProxy::onInfoChanged() -{ - // ignore mouse motion until we receive acknowledgment of our info - // change message. - m_ignoreMouse = true; - - // send info update +ServerProxy::EResult ServerProxy::parseHandshakeMessage(const UInt8 *code) { + if (memcmp(code, kMsgQInfo, 4) == 0) { queryInfo(); + } + + else if (memcmp(code, kMsgCInfoAck, 4) == 0) { + infoAcknowledgment(); + } + + else if (memcmp(code, kMsgDSetOptions, 4) == 0) { + setOptions(); + + // handshake is complete + m_parser = &ServerProxy::parseMessage; + checkMissedLanguages(); + m_client->handshakeComplete(); + } + + else if (memcmp(code, kMsgCResetOptions, 4) == 0) { + resetOptions(); + } + + else if (memcmp(code, kMsgCKeepAlive, 4) == 0) { + // echo keep alives and reset alarm + ProtocolUtil::writef(m_stream, kMsgCKeepAlive); + resetKeepAliveAlarm(); + } + + else if (memcmp(code, kMsgCNoop, 4) == 0) { + // accept and discard no-op + } + + else if (memcmp(code, kMsgCClose, 4) == 0) { + // server wants us to hangup + LOG((CLOG_DEBUG1 "recv close")); + m_client->disconnect(NULL); + return kDisconnect; + } + + else if (memcmp(code, kMsgEIncompatible, 4) == 0) { + SInt32 major, minor; + ProtocolUtil::readf(m_stream, kMsgEIncompatible + 4, &major, &minor); + LOG((CLOG_ERR "server has incompatible version %d.%d", major, minor)); + m_client->refuseConnection("server has incompatible version"); + return kDisconnect; + } + + else if (memcmp(code, kMsgEBusy, 4) == 0) { + LOG((CLOG_ERR "server already has a connected client with name \"%s\"", + m_client->getName().c_str())); + m_client->refuseConnection( + "server already has a connected client with our name"); + return kDisconnect; + } + + else if (memcmp(code, kMsgEUnknown, 4) == 0) { + LOG((CLOG_ERR "server refused client with name \"%s\"", + m_client->getName().c_str())); + m_client->refuseConnection("server refused client with our name"); + return kDisconnect; + } + + else if (memcmp(code, kMsgEBad, 4) == 0) { + LOG((CLOG_ERR "server disconnected due to a protocol error")); + m_client->refuseConnection("server reported a protocol error"); + return kDisconnect; + } else if (memcmp(code, kMsgDLanguageSynchronisation, 4) == 0) { + setServerLanguages(); + } else { + return kUnknown; + } + + return kOkay; } -bool -ServerProxy::onGrabClipboard(ClipboardID id) -{ - LOG((CLOG_DEBUG1 "sending clipboard %d changed", id)); - ProtocolUtil::writef(m_stream, kMsgCClipboard, id, m_seqNum); - return true; -} +ServerProxy::EResult ServerProxy::parseMessage(const UInt8 *code) { + if (memcmp(code, kMsgDMouseMove, 4) == 0) { + mouseMove(); + } -void -ServerProxy::onClipboardChanged(ClipboardID id, const IClipboard* clipboard) -{ - String data = IClipboard::marshall(clipboard); - LOG((CLOG_DEBUG "sending clipboard %d seqnum=%d", id, m_seqNum)); + else if (memcmp(code, kMsgDMouseRelMove, 4) == 0) { + mouseRelativeMove(); + } - StreamChunker::sendClipboard(data, data.size(), id, m_seqNum, m_events, this); -} + else if (memcmp(code, kMsgDMouseWheel, 4) == 0) { + mouseWheel(); + } -void -ServerProxy::flushCompressedMouse() -{ - if (m_compressMouse) { - m_compressMouse = false; - m_client->mouseMove(m_xMouse, m_yMouse); - } - if (m_compressMouseRelative) { - m_compressMouseRelative = false; - m_client->mouseRelativeMove(m_dxMouse, m_dyMouse); - m_dxMouse = 0; - m_dyMouse = 0; - } -} + else if (memcmp(code, kMsgDKeyDown, 4) == 0) { + UInt16 id = 0; + UInt16 mask = 0; + UInt16 button = 0; + ProtocolUtil::readf(m_stream, kMsgDKeyDown + 4, &id, &mask, &button); + LOG((CLOG_DEBUG1 "recv key down id=0x%08x, mask=0x%04x, button=0x%04x", id, + mask, button)); -void -ServerProxy::sendInfo(const ClientInfo& info) -{ - LOG((CLOG_DEBUG1 "sending info shape=%d,%d %dx%d", info.m_x, info.m_y, info.m_w, info.m_h)); - ProtocolUtil::writef(m_stream, kMsgDInfo, - info.m_x, info.m_y, - info.m_w, info.m_h, 0, - info.m_mx, info.m_my); -} + keyDown(id, mask, button, ""); + } -KeyID -ServerProxy::translateKey(KeyID id) const -{ - static const KeyID s_translationTable[kKeyModifierIDLast][2] = { - { kKeyNone, kKeyNone }, - { kKeyShift_L, kKeyShift_R }, - { kKeyControl_L, kKeyControl_R }, - { kKeyAlt_L, kKeyAlt_R }, - { kKeyMeta_L, kKeyMeta_R }, - { kKeySuper_L, kKeySuper_R }, - { kKeyAltGr, kKeyAltGr} - }; - - KeyModifierID id2 = kKeyModifierIDNull; - UInt32 side = 0; - switch (id) { - case kKeyShift_L: - id2 = kKeyModifierIDShift; - side = 0; - break; - - case kKeyShift_R: - id2 = kKeyModifierIDShift; - side = 1; - break; - - case kKeyControl_L: - id2 = kKeyModifierIDControl; - side = 0; - break; - - case kKeyControl_R: - id2 = kKeyModifierIDControl; - side = 1; - break; - - case kKeyAlt_L: - id2 = kKeyModifierIDAlt; - side = 0; - break; - - case kKeyAlt_R: - id2 = kKeyModifierIDAlt; - side = 1; - break; - - case kKeyAltGr: - id2 = kKeyModifierIDAltGr; - side = 1; // there is only one alt gr key on the right side - break; - - case kKeyMeta_L: - id2 = kKeyModifierIDMeta; - side = 0; - break; - - case kKeyMeta_R: - id2 = kKeyModifierIDMeta; - side = 1; - break; - - case kKeySuper_L: - id2 = kKeyModifierIDSuper; - side = 0; - break; - - case kKeySuper_R: - id2 = kKeyModifierIDSuper; - side = 1; - break; - } - - if (id2 != kKeyModifierIDNull) { - return s_translationTable[m_modifierTranslationTable[id2]][side]; - } - else { - return id; - } -} - -KeyModifierMask -ServerProxy::translateModifierMask(KeyModifierMask mask) const -{ - static const KeyModifierMask s_masks[kKeyModifierIDLast] = { - 0x0000, - KeyModifierShift, - KeyModifierControl, - KeyModifierAlt, - KeyModifierMeta, - KeyModifierSuper, - KeyModifierAltGr - }; - - KeyModifierMask newMask = mask & ~(KeyModifierShift | - KeyModifierControl | - KeyModifierAlt | - KeyModifierMeta | - KeyModifierSuper | - KeyModifierAltGr ); - if ((mask & KeyModifierShift) != 0) { - newMask |= s_masks[m_modifierTranslationTable[kKeyModifierIDShift]]; - } - if ((mask & KeyModifierControl) != 0) { - newMask |= s_masks[m_modifierTranslationTable[kKeyModifierIDControl]]; - } - if ((mask & KeyModifierAlt) != 0) { - newMask |= s_masks[m_modifierTranslationTable[kKeyModifierIDAlt]]; - } - if ((mask & KeyModifierAltGr) != 0) { - newMask |= s_masks[m_modifierTranslationTable[kKeyModifierIDAltGr]]; - } - if ((mask & KeyModifierMeta) != 0) { - newMask |= s_masks[m_modifierTranslationTable[kKeyModifierIDMeta]]; - } - if ((mask & KeyModifierSuper) != 0) { - newMask |= s_masks[m_modifierTranslationTable[kKeyModifierIDSuper]]; - } - return newMask; -} - -void -ServerProxy::enter() -{ - // parse - SInt16 x, y; - UInt16 mask; - UInt32 seqNum; - ProtocolUtil::readf(m_stream, kMsgCEnter + 4, &x, &y, &seqNum, &mask); - LOG((CLOG_DEBUG1 "recv enter, %d,%d %d %04x", x, y, seqNum, mask)); - - // discard old compressed mouse motion, if any - m_compressMouse = false; - m_compressMouseRelative = false; - m_dxMouse = 0; - m_dyMouse = 0; - m_seqNum = seqNum; - m_serverLanguage = ""; - m_isUserNotifiedAboutLanguageSyncError = false; - - // forward - m_client->enter(x, y, seqNum, static_cast(mask), false); -} - -void -ServerProxy::leave() -{ - // parse - LOG((CLOG_DEBUG1 "recv leave")); - - // send last mouse motion - flushCompressedMouse(); - - // forward - m_client->leave(); -} - -void -ServerProxy::setClipboard() -{ - // parse - static String dataCached; - ClipboardID id; - UInt32 seq; - - int r = ClipboardChunk::assemble(m_stream, dataCached, id, seq); - - if (r == kStart) { - size_t size = ClipboardChunk::getExpectedSize(); - LOG((CLOG_DEBUG "receiving clipboard %d size=%d", id, size)); - } - else if (r == kFinish) { - LOG((CLOG_DEBUG "received clipboard %d size=%d", id, dataCached.size())); - - // forward - Clipboard clipboard; - clipboard.unmarshall(dataCached, 0); - m_client->setClipboard(id, &clipboard); - - LOG((CLOG_INFO "clipboard was updated")); - } -} - -void -ServerProxy::grabClipboard() -{ - // parse - ClipboardID id; - UInt32 seqNum; - ProtocolUtil::readf(m_stream, kMsgCClipboard + 4, &id, &seqNum); - LOG((CLOG_DEBUG "recv grab clipboard %d", id)); - - // validate - if (id >= kClipboardEnd) { - return; - } - - // forward - m_client->grabClipboard(id); -} - -void -ServerProxy::keyDown(UInt16 id, UInt16 mask, UInt16 button, const String& lang) -{ - // get mouse up to date - flushCompressedMouse(); - setActiveServerLanguage(lang); - - // translate - KeyID id2 = translateKey(static_cast(id)); - KeyModifierMask mask2 = translateModifierMask( - static_cast(mask)); - if (id2 != static_cast(id) || - mask2 != static_cast(mask)) - LOG((CLOG_DEBUG1 "key down translated to id=0x%08x, mask=0x%04x", id2, mask2)); - - // forward - m_client->keyDown(id2, mask2, button, lang); -} - -void -ServerProxy::keyRepeat() -{ - // get mouse up to date - flushCompressedMouse(); - - // parse - UInt16 id, mask, count, button; + else if (memcmp(code, kMsgDKeyDownLang, 4) == 0) { String lang; - ProtocolUtil::readf(m_stream, kMsgDKeyRepeat + 4, - &id, &mask, &count, &button, &lang); - LOG((CLOG_DEBUG1 "recv key repeat id=0x%08x, mask=0x%04x, count=%d, button=0x%04x, lang=\"%s\"", id, mask, count, button, lang.c_str())); + UInt16 id = 0; + UInt16 mask = 0; + UInt16 button = 0; - // translate - KeyID id2 = translateKey(static_cast(id)); - KeyModifierMask mask2 = translateModifierMask( - static_cast(mask)); - if (id2 != static_cast(id) || - mask2 != static_cast(mask)) - LOG((CLOG_DEBUG1 "key repeat translated to id=0x%08x, mask=0x%04x", id2, mask2)); + ProtocolUtil::readf(m_stream, kMsgDKeyDownLang + 4, &id, &mask, &button, + &lang); + LOG((CLOG_DEBUG1 + "recv key down id=0x%08x, mask=0x%04x, button=0x%04x, lang=\"%s\"", + id, mask, button, lang.c_str())); + + keyDown(id, mask, button, lang); + } + + else if (memcmp(code, kMsgDKeyUp, 4) == 0) { + keyUp(); + } + + else if (memcmp(code, kMsgDMouseDown, 4) == 0) { + mouseDown(); + } + + else if (memcmp(code, kMsgDMouseUp, 4) == 0) { + mouseUp(); + } + + else if (memcmp(code, kMsgDKeyRepeat, 4) == 0) { + keyRepeat(); + } + + else if (memcmp(code, kMsgCKeepAlive, 4) == 0) { + // echo keep alives and reset alarm + ProtocolUtil::writef(m_stream, kMsgCKeepAlive); + resetKeepAliveAlarm(); + } + + else if (memcmp(code, kMsgCNoop, 4) == 0) { + // accept and discard no-op + } + + else if (memcmp(code, kMsgCEnter, 4) == 0) { + enter(); + } + + else if (memcmp(code, kMsgCLeave, 4) == 0) { + leave(); + } + + else if (memcmp(code, kMsgCClipboard, 4) == 0) { + grabClipboard(); + } + + else if (memcmp(code, kMsgCScreenSaver, 4) == 0) { + screensaver(); + } + + else if (memcmp(code, kMsgQInfo, 4) == 0) { + queryInfo(); + } + + else if (memcmp(code, kMsgCInfoAck, 4) == 0) { + infoAcknowledgment(); + } + + else if (memcmp(code, kMsgDClipboard, 4) == 0) { + setClipboard(); + } + + else if (memcmp(code, kMsgCResetOptions, 4) == 0) { + resetOptions(); + } + + else if (memcmp(code, kMsgDSetOptions, 4) == 0) { + setOptions(); + } + + else if (memcmp(code, kMsgDFileTransfer, 4) == 0) { + fileChunkReceived(); + } else if (memcmp(code, kMsgDDragInfo, 4) == 0) { + dragInfoReceived(); + } else if (memcmp(code, kMsgDSecureInputNotification, 4) == 0) { + secureInputNotification(); + } + + else if (memcmp(code, kMsgCClose, 4) == 0) { + // server wants us to hangup + LOG((CLOG_DEBUG1 "recv close")); + m_client->disconnect(NULL); + return kDisconnect; + } else if (memcmp(code, kMsgEBad, 4) == 0) { + LOG((CLOG_ERR "server disconnected due to a protocol error")); + m_client->disconnect("server reported a protocol error"); + return kDisconnect; + } else { + return kUnknown; + } + + // send a reply. this is intended to work around a delay when + // running a linux server and an OS X (any BSD?) client. the + // client waits to send an ACK (if the system control flag + // net.inet.tcp.delayed_ack is 1) in hopes of piggybacking it + // on a data packet. we provide that packet here. i don't + // know why a delayed ACK should cause the server to wait since + // TCP_NODELAY is enabled. + ProtocolUtil::writef(m_stream, kMsgCNoop); + + return kOkay; +} + +void ServerProxy::handleKeepAliveAlarm(const Event &, void *) { + LOG((CLOG_NOTE "server is dead")); + m_client->disconnect("server is not responding"); +} + +void ServerProxy::onInfoChanged() { + // ignore mouse motion until we receive acknowledgment of our info + // change message. + m_ignoreMouse = true; + + // send info update + queryInfo(); +} + +bool ServerProxy::onGrabClipboard(ClipboardID id) { + LOG((CLOG_DEBUG1 "sending clipboard %d changed", id)); + ProtocolUtil::writef(m_stream, kMsgCClipboard, id, m_seqNum); + return true; +} + +void ServerProxy::onClipboardChanged(ClipboardID id, + const IClipboard *clipboard) { + String data = IClipboard::marshall(clipboard); + LOG((CLOG_DEBUG "sending clipboard %d seqnum=%d", id, m_seqNum)); + + StreamChunker::sendClipboard(data, data.size(), id, m_seqNum, m_events, this); +} + +void ServerProxy::flushCompressedMouse() { + if (m_compressMouse) { + m_compressMouse = false; + m_client->mouseMove(m_xMouse, m_yMouse); + } + if (m_compressMouseRelative) { + m_compressMouseRelative = false; + m_client->mouseRelativeMove(m_dxMouse, m_dyMouse); + m_dxMouse = 0; + m_dyMouse = 0; + } +} + +void ServerProxy::sendInfo(const ClientInfo &info) { + LOG((CLOG_DEBUG1 "sending info shape=%d,%d %dx%d", info.m_x, info.m_y, + info.m_w, info.m_h)); + ProtocolUtil::writef(m_stream, kMsgDInfo, info.m_x, info.m_y, info.m_w, + info.m_h, 0, info.m_mx, info.m_my); +} + +KeyID ServerProxy::translateKey(KeyID id) const { + static const KeyID s_translationTable[kKeyModifierIDLast][2] = { + {kKeyNone, kKeyNone}, {kKeyShift_L, kKeyShift_R}, + {kKeyControl_L, kKeyControl_R}, {kKeyAlt_L, kKeyAlt_R}, + {kKeyMeta_L, kKeyMeta_R}, {kKeySuper_L, kKeySuper_R}, + {kKeyAltGr, kKeyAltGr}}; + + KeyModifierID id2 = kKeyModifierIDNull; + UInt32 side = 0; + switch (id) { + case kKeyShift_L: + id2 = kKeyModifierIDShift; + side = 0; + break; + + case kKeyShift_R: + id2 = kKeyModifierIDShift; + side = 1; + break; + + case kKeyControl_L: + id2 = kKeyModifierIDControl; + side = 0; + break; + + case kKeyControl_R: + id2 = kKeyModifierIDControl; + side = 1; + break; + + case kKeyAlt_L: + id2 = kKeyModifierIDAlt; + side = 0; + break; + + case kKeyAlt_R: + id2 = kKeyModifierIDAlt; + side = 1; + break; + + case kKeyAltGr: + id2 = kKeyModifierIDAltGr; + side = 1; // there is only one alt gr key on the right side + break; + + case kKeyMeta_L: + id2 = kKeyModifierIDMeta; + side = 0; + break; + + case kKeyMeta_R: + id2 = kKeyModifierIDMeta; + side = 1; + break; + + case kKeySuper_L: + id2 = kKeyModifierIDSuper; + side = 0; + break; + + case kKeySuper_R: + id2 = kKeyModifierIDSuper; + side = 1; + break; + } + + if (id2 != kKeyModifierIDNull) { + return s_translationTable[m_modifierTranslationTable[id2]][side]; + } else { + return id; + } +} + +KeyModifierMask ServerProxy::translateModifierMask(KeyModifierMask mask) const { + static const KeyModifierMask s_masks[kKeyModifierIDLast] = { + 0x0000, KeyModifierShift, KeyModifierControl, KeyModifierAlt, + KeyModifierMeta, KeyModifierSuper, KeyModifierAltGr}; + + KeyModifierMask newMask = + mask & ~(KeyModifierShift | KeyModifierControl | KeyModifierAlt | + KeyModifierMeta | KeyModifierSuper | KeyModifierAltGr); + if ((mask & KeyModifierShift) != 0) { + newMask |= s_masks[m_modifierTranslationTable[kKeyModifierIDShift]]; + } + if ((mask & KeyModifierControl) != 0) { + newMask |= s_masks[m_modifierTranslationTable[kKeyModifierIDControl]]; + } + if ((mask & KeyModifierAlt) != 0) { + newMask |= s_masks[m_modifierTranslationTable[kKeyModifierIDAlt]]; + } + if ((mask & KeyModifierAltGr) != 0) { + newMask |= s_masks[m_modifierTranslationTable[kKeyModifierIDAltGr]]; + } + if ((mask & KeyModifierMeta) != 0) { + newMask |= s_masks[m_modifierTranslationTable[kKeyModifierIDMeta]]; + } + if ((mask & KeyModifierSuper) != 0) { + newMask |= s_masks[m_modifierTranslationTable[kKeyModifierIDSuper]]; + } + return newMask; +} + +void ServerProxy::enter() { + // parse + SInt16 x, y; + UInt16 mask; + UInt32 seqNum; + ProtocolUtil::readf(m_stream, kMsgCEnter + 4, &x, &y, &seqNum, &mask); + LOG((CLOG_DEBUG1 "recv enter, %d,%d %d %04x", x, y, seqNum, mask)); + + // discard old compressed mouse motion, if any + m_compressMouse = false; + m_compressMouseRelative = false; + m_dxMouse = 0; + m_dyMouse = 0; + m_seqNum = seqNum; + m_serverLanguage = ""; + m_isUserNotifiedAboutLanguageSyncError = false; + + // forward + m_client->enter(x, y, seqNum, static_cast(mask), false); +} + +void ServerProxy::leave() { + // parse + LOG((CLOG_DEBUG1 "recv leave")); + + // send last mouse motion + flushCompressedMouse(); + + // forward + m_client->leave(); +} + +void ServerProxy::setClipboard() { + // parse + static String dataCached; + ClipboardID id; + UInt32 seq; + + int r = ClipboardChunk::assemble(m_stream, dataCached, id, seq); + + if (r == kStart) { + size_t size = ClipboardChunk::getExpectedSize(); + LOG((CLOG_DEBUG "receiving clipboard %d size=%d", id, size)); + } else if (r == kFinish) { + LOG((CLOG_DEBUG "received clipboard %d size=%d", id, dataCached.size())); // forward - m_client->keyRepeat(id2, mask2, count, button, lang); + Clipboard clipboard; + clipboard.unmarshall(dataCached, 0); + m_client->setClipboard(id, &clipboard); + + LOG((CLOG_INFO "clipboard was updated")); + } } -void -ServerProxy::keyUp() -{ - // get mouse up to date - flushCompressedMouse(); +void ServerProxy::grabClipboard() { + // parse + ClipboardID id; + UInt32 seqNum; + ProtocolUtil::readf(m_stream, kMsgCClipboard + 4, &id, &seqNum); + LOG((CLOG_DEBUG "recv grab clipboard %d", id)); - // parse - UInt16 id, mask, button; - ProtocolUtil::readf(m_stream, kMsgDKeyUp + 4, &id, &mask, &button); - LOG((CLOG_DEBUG1 "recv key up id=0x%08x, mask=0x%04x, button=0x%04x", id, mask, button)); + // validate + if (id >= kClipboardEnd) { + return; + } - // translate - KeyID id2 = translateKey(static_cast(id)); - KeyModifierMask mask2 = translateModifierMask( - static_cast(mask)); - if (id2 != static_cast(id) || - mask2 != static_cast(mask)) - LOG((CLOG_DEBUG1 "key up translated to id=0x%08x, mask=0x%04x", id2, mask2)); - - // forward - m_client->keyUp(id2, mask2, button); + // forward + m_client->grabClipboard(id); } -void -ServerProxy::mouseDown() -{ - // get mouse up to date - flushCompressedMouse(); +void ServerProxy::keyDown(UInt16 id, UInt16 mask, UInt16 button, + const String &lang) { + // get mouse up to date + flushCompressedMouse(); + setActiveServerLanguage(lang); - // parse - SInt8 id; - ProtocolUtil::readf(m_stream, kMsgDMouseDown + 4, &id); - LOG((CLOG_DEBUG1 "recv mouse down id=%d", id)); + // translate + KeyID id2 = translateKey(static_cast(id)); + KeyModifierMask mask2 = + translateModifierMask(static_cast(mask)); + if (id2 != static_cast(id) || + mask2 != static_cast(mask)) + LOG((CLOG_DEBUG1 "key down translated to id=0x%08x, mask=0x%04x", id2, + mask2)); - // forward - m_client->mouseDown(static_cast(id)); + // forward + m_client->keyDown(id2, mask2, button, lang); } -void -ServerProxy::mouseUp() -{ - // get mouse up to date - flushCompressedMouse(); +void ServerProxy::keyRepeat() { + // get mouse up to date + flushCompressedMouse(); - // parse - SInt8 id; - ProtocolUtil::readf(m_stream, kMsgDMouseUp + 4, &id); - LOG((CLOG_DEBUG1 "recv mouse up id=%d", id)); + // parse + UInt16 id, mask, count, button; + String lang; + ProtocolUtil::readf(m_stream, kMsgDKeyRepeat + 4, &id, &mask, &count, &button, + &lang); + LOG((CLOG_DEBUG1 "recv key repeat id=0x%08x, mask=0x%04x, count=%d, " + "button=0x%04x, lang=\"%s\"", + id, mask, count, button, lang.c_str())); - // forward - m_client->mouseUp(static_cast(id)); + // translate + KeyID id2 = translateKey(static_cast(id)); + KeyModifierMask mask2 = + translateModifierMask(static_cast(mask)); + if (id2 != static_cast(id) || + mask2 != static_cast(mask)) + LOG((CLOG_DEBUG1 "key repeat translated to id=0x%08x, mask=0x%04x", id2, + mask2)); + + // forward + m_client->keyRepeat(id2, mask2, count, button, lang); } -void -ServerProxy::mouseMove() -{ - // parse - bool ignore; - SInt16 x, y; - ProtocolUtil::readf(m_stream, kMsgDMouseMove + 4, &x, &y); +void ServerProxy::keyUp() { + // get mouse up to date + flushCompressedMouse(); - // note if we should ignore the move - ignore = m_ignoreMouse; + // parse + UInt16 id, mask, button; + ProtocolUtil::readf(m_stream, kMsgDKeyUp + 4, &id, &mask, &button); + LOG((CLOG_DEBUG1 "recv key up id=0x%08x, mask=0x%04x, button=0x%04x", id, + mask, button)); - // compress mouse motion events if more input follows - if (!ignore && !m_compressMouse && m_stream->isReady()) { - m_compressMouse = true; + // translate + KeyID id2 = translateKey(static_cast(id)); + KeyModifierMask mask2 = + translateModifierMask(static_cast(mask)); + if (id2 != static_cast(id) || + mask2 != static_cast(mask)) + LOG((CLOG_DEBUG1 "key up translated to id=0x%08x, mask=0x%04x", id2, + mask2)); + + // forward + m_client->keyUp(id2, mask2, button); +} + +void ServerProxy::mouseDown() { + // get mouse up to date + flushCompressedMouse(); + + // parse + SInt8 id; + ProtocolUtil::readf(m_stream, kMsgDMouseDown + 4, &id); + LOG((CLOG_DEBUG1 "recv mouse down id=%d", id)); + + // forward + m_client->mouseDown(static_cast(id)); +} + +void ServerProxy::mouseUp() { + // get mouse up to date + flushCompressedMouse(); + + // parse + SInt8 id; + ProtocolUtil::readf(m_stream, kMsgDMouseUp + 4, &id); + LOG((CLOG_DEBUG1 "recv mouse up id=%d", id)); + + // forward + m_client->mouseUp(static_cast(id)); +} + +void ServerProxy::mouseMove() { + // parse + bool ignore; + SInt16 x, y; + ProtocolUtil::readf(m_stream, kMsgDMouseMove + 4, &x, &y); + + // note if we should ignore the move + ignore = m_ignoreMouse; + + // compress mouse motion events if more input follows + if (!ignore && !m_compressMouse && m_stream->isReady()) { + m_compressMouse = true; + } + + // if compressing then ignore the motion but record it + if (m_compressMouse) { + m_compressMouseRelative = false; + ignore = true; + m_xMouse = x; + m_yMouse = y; + m_dxMouse = 0; + m_dyMouse = 0; + } + LOG((CLOG_DEBUG2 "recv mouse move %d,%d", x, y)); + + // forward + if (!ignore) { + m_client->mouseMove(x, y); + } +} + +void ServerProxy::mouseRelativeMove() { + // parse + bool ignore; + SInt16 dx, dy; + ProtocolUtil::readf(m_stream, kMsgDMouseRelMove + 4, &dx, &dy); + + // note if we should ignore the move + ignore = m_ignoreMouse; + + // compress mouse motion events if more input follows + if (!ignore && !m_compressMouseRelative && m_stream->isReady()) { + m_compressMouseRelative = true; + } + + // if compressing then ignore the motion but record it + if (m_compressMouseRelative) { + ignore = true; + m_dxMouse += dx; + m_dyMouse += dy; + } + LOG((CLOG_DEBUG2 "recv mouse relative move %d,%d", dx, dy)); + + // forward + if (!ignore) { + m_client->mouseRelativeMove(dx, dy); + } +} + +void ServerProxy::mouseWheel() { + // get mouse up to date + flushCompressedMouse(); + + // parse + SInt16 xDelta, yDelta; + ProtocolUtil::readf(m_stream, kMsgDMouseWheel + 4, &xDelta, &yDelta); + LOG((CLOG_DEBUG2 "recv mouse wheel %+d,%+d", xDelta, yDelta)); + + // forward + m_client->mouseWheel(xDelta, yDelta); +} + +void ServerProxy::screensaver() { + // parse + SInt8 on; + ProtocolUtil::readf(m_stream, kMsgCScreenSaver + 4, &on); + LOG((CLOG_DEBUG1 "recv screen saver on=%d", on)); + + // forward + m_client->screensaver(on != 0); +} + +void ServerProxy::resetOptions() { + // parse + LOG((CLOG_DEBUG1 "recv reset options")); + + // forward + m_client->resetOptions(); + + // reset keep alive + setKeepAliveRate(kKeepAliveRate); + + // reset modifier translation table + for (KeyModifierID id = 0; id < kKeyModifierIDLast; ++id) { + m_modifierTranslationTable[id] = id; + } +} + +void ServerProxy::setOptions() { + // parse + OptionsList options; + ProtocolUtil::readf(m_stream, kMsgDSetOptions + 4, &options); + LOG((CLOG_DEBUG1 "recv set options size=%d", options.size())); + + // forward + m_client->setOptions(options); + + // update modifier table + for (UInt32 i = 0, n = (UInt32)options.size(); i < n; i += 2) { + KeyModifierID id = kKeyModifierIDNull; + if (options[i] == kOptionModifierMapForShift) { + id = kKeyModifierIDShift; + } else if (options[i] == kOptionModifierMapForControl) { + id = kKeyModifierIDControl; + } else if (options[i] == kOptionModifierMapForAlt) { + id = kKeyModifierIDAlt; + } else if (options[i] == kOptionModifierMapForAltGr) { + id = kKeyModifierIDAltGr; + } else if (options[i] == kOptionModifierMapForMeta) { + id = kKeyModifierIDMeta; + } else if (options[i] == kOptionModifierMapForSuper) { + id = kKeyModifierIDSuper; + } else if (options[i] == kOptionHeartbeat) { + // update keep alive + setKeepAliveRate(1.0e-3 * static_cast(options[i + 1])); } - // if compressing then ignore the motion but record it - if (m_compressMouse) { - m_compressMouseRelative = false; - ignore = true; - m_xMouse = x; - m_yMouse = y; - m_dxMouse = 0; - m_dyMouse = 0; - } - LOG((CLOG_DEBUG2 "recv mouse move %d,%d", x, y)); - - // forward - if (!ignore) { - m_client->mouseMove(x, y); + if (id != kKeyModifierIDNull) { + m_modifierTranslationTable[id] = + static_cast(options[i + 1]); + LOG((CLOG_DEBUG1 "modifier %d mapped to %d", id, + m_modifierTranslationTable[id])); } + } } -void -ServerProxy::mouseRelativeMove() -{ - // parse - bool ignore; - SInt16 dx, dy; - ProtocolUtil::readf(m_stream, kMsgDMouseRelMove + 4, &dx, &dy); +void ServerProxy::queryInfo() { + ClientInfo info; + m_client->getShape(info.m_x, info.m_y, info.m_w, info.m_h); + m_client->getCursorPos(info.m_mx, info.m_my); + sendInfo(info); +} - // note if we should ignore the move - ignore = m_ignoreMouse; +void ServerProxy::infoAcknowledgment() { + LOG((CLOG_DEBUG1 "recv info acknowledgment")); + m_ignoreMouse = false; +} - // compress mouse motion events if more input follows - if (!ignore && !m_compressMouseRelative && m_stream->isReady()) { - m_compressMouseRelative = true; +void ServerProxy::fileChunkReceived() { + int result = FileChunk::assemble(m_stream, m_client->getReceivedFileData(), + m_client->getExpectedFileSize()); + + if (result == kFinish) { + m_events->addEvent( + Event(m_events->forFile().fileRecieveCompleted(), m_client)); + } else if (result == kStart) { + if (m_client->getDragFileList().size() > 0) { + String filename = m_client->getDragFileList().at(0).getFilename(); + LOG((CLOG_DEBUG "start receiving %s", filename.c_str())); + } + } +} + +void ServerProxy::dragInfoReceived() { + // parse + UInt32 fileNum = 0; + String content; + ProtocolUtil::readf(m_stream, kMsgDDragInfo + 4, &fileNum, &content); + + m_client->dragInfoReceived(fileNum, content); +} + +void ServerProxy::handleClipboardSendingEvent(const Event &event, void *) { + ClipboardChunk::send(m_stream, event.getDataObject()); +} + +void ServerProxy::fileChunkSending(UInt8 mark, char *data, size_t dataSize) { + FileChunk::send(m_stream, mark, data, dataSize); +} + +void ServerProxy::sendDragInfo(UInt32 fileCount, const char *info, + size_t size) { + String data(info, size); + ProtocolUtil::writef(m_stream, kMsgDDragInfo, fileCount, &data); +} + +void ServerProxy::secureInputNotification() { + String app; + ProtocolUtil::readf(m_stream, kMsgDSecureInputNotification + 4, &app); + + // display this notification on the client + if (app != "unknown") { + AppUtil::instance().showNotification("The keyboard may stop working.", + "'Secure input' enabled by " + app + + " on the server. " + "To fix the keyboard, " + + app + " must be closed."); + } else { + AppUtil::instance().showNotification( + "The keyboard may stop working.", + "'Secure input' enabled by an application on the server. " + "To fix the keyboard, the application must be closed."); + } +} + +void ServerProxy::setServerLanguages() { + String serverLanguages; + ProtocolUtil::readf(m_stream, kMsgDLanguageSynchronisation + 4, + &serverLanguages); + m_languageManager.setRemoteLanguages(serverLanguages); +} + +void ServerProxy::setActiveServerLanguage(const String &language) { + if (!language.empty() && std::strlen(language.c_str()) > 0) { + if (m_serverLanguage != language) { + m_isUserNotifiedAboutLanguageSyncError = false; + m_serverLanguage = language; } - // if compressing then ignore the motion but record it - if (m_compressMouseRelative) { - ignore = true; - m_dxMouse += dx; - m_dyMouse += dy; - } - LOG((CLOG_DEBUG2 "recv mouse relative move %d,%d", dx, dy)); - - // forward - if (!ignore) { - m_client->mouseRelativeMove(dx, dy); + if (!m_languageManager.isLanguageInstalled(m_serverLanguage)) { + if (!m_isUserNotifiedAboutLanguageSyncError) { + LOG((CLOG_WARN "current server language is not installed on client")); + m_isUserNotifiedAboutLanguageSyncError = true; + } + } else { + m_isUserNotifiedAboutLanguageSyncError = false; } + } else { + LOG((CLOG_DEBUG1 "active server langauge is empty")); + } } -void -ServerProxy::mouseWheel() -{ - // get mouse up to date - flushCompressedMouse(); - - // parse - SInt16 xDelta, yDelta; - ProtocolUtil::readf(m_stream, kMsgDMouseWheel + 4, &xDelta, &yDelta); - LOG((CLOG_DEBUG2 "recv mouse wheel %+d,%+d", xDelta, yDelta)); - - // forward - m_client->mouseWheel(xDelta, yDelta); -} - -void -ServerProxy::screensaver() -{ - // parse - SInt8 on; - ProtocolUtil::readf(m_stream, kMsgCScreenSaver + 4, &on); - LOG((CLOG_DEBUG1 "recv screen saver on=%d", on)); - - // forward - m_client->screensaver(on != 0); -} - -void -ServerProxy::resetOptions() -{ - // parse - LOG((CLOG_DEBUG1 "recv reset options")); - - // forward - m_client->resetOptions(); - - // reset keep alive - setKeepAliveRate(kKeepAliveRate); - - // reset modifier translation table - for (KeyModifierID id = 0; id < kKeyModifierIDLast; ++id) { - m_modifierTranslationTable[id] = id; - } -} - -void -ServerProxy::setOptions() -{ - // parse - OptionsList options; - ProtocolUtil::readf(m_stream, kMsgDSetOptions + 4, &options); - LOG((CLOG_DEBUG1 "recv set options size=%d", options.size())); - - // forward - m_client->setOptions(options); - - // update modifier table - for (UInt32 i = 0, n = (UInt32)options.size(); i < n; i += 2) { - KeyModifierID id = kKeyModifierIDNull; - if (options[i] == kOptionModifierMapForShift) { - id = kKeyModifierIDShift; - } - else if (options[i] == kOptionModifierMapForControl) { - id = kKeyModifierIDControl; - } - else if (options[i] == kOptionModifierMapForAlt) { - id = kKeyModifierIDAlt; - } - else if (options[i] == kOptionModifierMapForAltGr) { - id = kKeyModifierIDAltGr; - } - else if (options[i] == kOptionModifierMapForMeta) { - id = kKeyModifierIDMeta; - } - else if (options[i] == kOptionModifierMapForSuper) { - id = kKeyModifierIDSuper; - } - else if (options[i] == kOptionHeartbeat) { - // update keep alive - setKeepAliveRate(1.0e-3 * static_cast(options[i + 1])); - } - - if (id != kKeyModifierIDNull) { - m_modifierTranslationTable[id] = - static_cast(options[i + 1]); - LOG((CLOG_DEBUG1 "modifier %d mapped to %d", id, m_modifierTranslationTable[id])); - } - } -} - -void -ServerProxy::queryInfo() -{ - ClientInfo info; - m_client->getShape(info.m_x, info.m_y, info.m_w, info.m_h); - m_client->getCursorPos(info.m_mx, info.m_my); - sendInfo(info); -} - -void -ServerProxy::infoAcknowledgment() -{ - LOG((CLOG_DEBUG1 "recv info acknowledgment")); - m_ignoreMouse = false; -} - -void -ServerProxy::fileChunkReceived() -{ - int result = FileChunk::assemble( - m_stream, - m_client->getReceivedFileData(), - m_client->getExpectedFileSize()); - - if (result == kFinish) { - m_events->addEvent(Event(m_events->forFile().fileRecieveCompleted(), m_client)); - } - else if (result == kStart) { - if (m_client->getDragFileList().size() > 0) { - String filename = m_client->getDragFileList().at(0).getFilename(); - LOG((CLOG_DEBUG "start receiving %s", filename.c_str())); - } - } -} - -void -ServerProxy::dragInfoReceived() -{ - // parse - UInt32 fileNum = 0; - String content; - ProtocolUtil::readf(m_stream, kMsgDDragInfo + 4, &fileNum, &content); - - m_client->dragInfoReceived(fileNum, content); -} - -void -ServerProxy::handleClipboardSendingEvent(const Event& event, void*) -{ - ClipboardChunk::send(m_stream, event.getDataObject()); -} - -void -ServerProxy::fileChunkSending(UInt8 mark, char* data, size_t dataSize) -{ - FileChunk::send(m_stream, mark, data, dataSize); -} - -void -ServerProxy::sendDragInfo(UInt32 fileCount, const char* info, size_t size) -{ - String data(info, size); - ProtocolUtil::writef(m_stream, kMsgDDragInfo, fileCount, &data); -} - -void -ServerProxy::secureInputNotification() -{ - String app; - ProtocolUtil::readf(m_stream, kMsgDSecureInputNotification + 4, &app); - - // display this notification on the client - if (app != "unknown") { - AppUtil::instance().showNotification( - "The keyboard may stop working.", - "'Secure input' enabled by " + app + " on the server. " \ - "To fix the keyboard, " + app + " must be closed."); - } - else { - AppUtil::instance().showNotification( - "The keyboard may stop working.", - "'Secure input' enabled by an application on the server. " \ - "To fix the keyboard, the application must be closed."); - } -} - -void -ServerProxy::setServerLanguages() -{ - String serverLanguages; - ProtocolUtil::readf(m_stream, kMsgDLanguageSynchronisation + 4, &serverLanguages); - m_languageManager.setRemoteLanguages(serverLanguages); -} - -void -ServerProxy::setActiveServerLanguage(const String& language) -{ - if (!language.empty() && std::strlen(language.c_str()) > 0) { - if(m_serverLanguage != language) { - m_isUserNotifiedAboutLanguageSyncError = false; - m_serverLanguage = language; - } - - if (!m_languageManager.isLanguageInstalled(m_serverLanguage)) { - if(!m_isUserNotifiedAboutLanguageSyncError) { - LOG((CLOG_WARN "current server language is not installed on client")); - m_isUserNotifiedAboutLanguageSyncError = true; - } - } - else { - m_isUserNotifiedAboutLanguageSyncError = false; - } - } - else { - LOG((CLOG_DEBUG1 "active server langauge is empty")); - } -} - -void -ServerProxy::checkMissedLanguages() const -{ - auto missedLanguages = m_languageManager.getMissedLanguages(); - if (!missedLanguages.empty()) { - LOG((CLOG_WARN - "You need to install these languages on this computer and restart Synergy to enable support for multiple languages: %s", - missedLanguages.c_str())); - } +void ServerProxy::checkMissedLanguages() const { + auto missedLanguages = m_languageManager.getMissedLanguages(); + if (!missedLanguages.empty()) { + LOG((CLOG_WARN + "You need to install these languages on this computer and restart " + "Synergy to enable support for multiple languages: %s", + missedLanguages.c_str())); + } } diff --git a/src/lib/client/ServerProxy.h b/src/lib/client/ServerProxy.h index 876492937..0061dd810 100644 --- a/src/lib/client/ServerProxy.h +++ b/src/lib/client/ServerProxy.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -18,18 +18,20 @@ #pragma once -#include "synergy/languages/LanguageManager.h" -#include "synergy/clipboard_types.h" -#include "synergy/key_types.h" #include "base/Event.h" #include "base/Stopwatch.h" #include "base/String.h" +#include "synergy/clipboard_types.h" +#include "synergy/key_types.h" +#include "synergy/languages/LanguageManager.h" class Client; class ClientInfo; class EventQueueTimer; class IClipboard; -namespace synergy { class IStream; } +namespace synergy { +class IStream; +} class IEventQueue; //! Proxy for server @@ -39,108 +41,108 @@ to the server and messages from the server to calls on the client. */ class ServerProxy { public: - /*! - Process messages from the server on \p stream and forward to - \p client. - */ - ServerProxy(Client* client, synergy::IStream* stream, IEventQueue* events); - ServerProxy(ServerProxy const &) =delete; - ServerProxy(ServerProxy &&) =delete; - ~ServerProxy(); + /*! + Process messages from the server on \p stream and forward to + \p client. + */ + ServerProxy(Client *client, synergy::IStream *stream, IEventQueue *events); + ServerProxy(ServerProxy const &) = delete; + ServerProxy(ServerProxy &&) = delete; + ~ServerProxy(); - ServerProxy& operator=(ServerProxy const &) =delete; - ServerProxy& operator=(ServerProxy &&) =delete; + ServerProxy &operator=(ServerProxy const &) = delete; + ServerProxy &operator=(ServerProxy &&) = delete; - //! @name manipulators - //@{ + //! @name manipulators + //@{ - void onInfoChanged(); - bool onGrabClipboard(ClipboardID); - void onClipboardChanged(ClipboardID, const IClipboard*); + void onInfoChanged(); + bool onGrabClipboard(ClipboardID); + void onClipboardChanged(ClipboardID, const IClipboard *); - //@} + //@} - // sending file chunk to server - void fileChunkSending(UInt8 mark, char* data, size_t dataSize); + // sending file chunk to server + void fileChunkSending(UInt8 mark, char *data, size_t dataSize); + + // sending dragging information to server + void sendDragInfo(UInt32 fileCount, const char *info, size_t size); - // sending dragging information to server - void sendDragInfo(UInt32 fileCount, const char* info, size_t size); - #ifdef TEST_ENV - void handleDataForTest() { handleData(Event(), NULL); } + void handleDataForTest() { handleData(Event(), NULL); } #endif protected: - enum EResult { kOkay, kUnknown, kDisconnect }; - EResult parseHandshakeMessage(const UInt8* code); - EResult parseMessage(const UInt8* code); + enum EResult { kOkay, kUnknown, kDisconnect }; + EResult parseHandshakeMessage(const UInt8 *code); + EResult parseMessage(const UInt8 *code); private: - // if compressing mouse motion then send the last motion now - void flushCompressedMouse(); + // if compressing mouse motion then send the last motion now + void flushCompressedMouse(); - void sendInfo(const ClientInfo&); + void sendInfo(const ClientInfo &); - void resetKeepAliveAlarm(); - void setKeepAliveRate(double); + void resetKeepAliveAlarm(); + void setKeepAliveRate(double); - // modifier key translation - KeyID translateKey(KeyID) const; - KeyModifierMask translateModifierMask(KeyModifierMask) const; + // modifier key translation + KeyID translateKey(KeyID) const; + KeyModifierMask translateModifierMask(KeyModifierMask) const; - // event handlers - void handleData(const Event&, void*); - void handleKeepAliveAlarm(const Event&, void*); + // event handlers + void handleData(const Event &, void *); + void handleKeepAliveAlarm(const Event &, void *); - // message handlers - void enter(); - void leave(); - void setClipboard(); - void grabClipboard(); - void keyDown(UInt16 id, UInt16 mask, UInt16 button, const String& lang); - void keyRepeat(); - void keyUp(); - void mouseDown(); - void mouseUp(); - void mouseMove(); - void mouseRelativeMove(); - void mouseWheel(); - void screensaver(); - void resetOptions(); - void setOptions(); - void queryInfo(); - void infoAcknowledgment(); - void fileChunkReceived(); - void dragInfoReceived(); - void handleClipboardSendingEvent(const Event&, void*); - void secureInputNotification(); - void setServerLanguages(); - void setActiveServerLanguage(const String& language); - void checkMissedLanguages() const; + // message handlers + void enter(); + void leave(); + void setClipboard(); + void grabClipboard(); + void keyDown(UInt16 id, UInt16 mask, UInt16 button, const String &lang); + void keyRepeat(); + void keyUp(); + void mouseDown(); + void mouseUp(); + void mouseMove(); + void mouseRelativeMove(); + void mouseWheel(); + void screensaver(); + void resetOptions(); + void setOptions(); + void queryInfo(); + void infoAcknowledgment(); + void fileChunkReceived(); + void dragInfoReceived(); + void handleClipboardSendingEvent(const Event &, void *); + void secureInputNotification(); + void setServerLanguages(); + void setActiveServerLanguage(const String &language); + void checkMissedLanguages() const; private: - typedef EResult (ServerProxy::*MessageParser)(const UInt8*); + typedef EResult (ServerProxy::*MessageParser)(const UInt8 *); - Client* m_client; - synergy::IStream* m_stream; + Client *m_client; + synergy::IStream *m_stream; - UInt32 m_seqNum; + UInt32 m_seqNum; - bool m_compressMouse; - bool m_compressMouseRelative; - SInt32 m_xMouse, m_yMouse; - SInt32 m_dxMouse, m_dyMouse; + bool m_compressMouse; + bool m_compressMouseRelative; + SInt32 m_xMouse, m_yMouse; + SInt32 m_dxMouse, m_dyMouse; - bool m_ignoreMouse; + bool m_ignoreMouse; - KeyModifierID m_modifierTranslationTable[kKeyModifierIDLast]; + KeyModifierID m_modifierTranslationTable[kKeyModifierIDLast]; - double m_keepAliveAlarm; - EventQueueTimer* m_keepAliveAlarmTimer; + double m_keepAliveAlarm; + EventQueueTimer *m_keepAliveAlarmTimer; - MessageParser m_parser; - IEventQueue* m_events; - String m_serverLanguage = ""; - bool m_isUserNotifiedAboutLanguageSyncError = false; - synergy::languages::LanguageManager m_languageManager; + MessageParser m_parser; + IEventQueue *m_events; + String m_serverLanguage = ""; + bool m_isUserNotifiedAboutLanguageSyncError = false; + synergy::languages::LanguageManager m_languageManager; }; diff --git a/src/lib/common/IInterface.h b/src/lib/common/IInterface.h index 606c21f15..4e0d38d67 100644 --- a/src/lib/common/IInterface.h +++ b/src/lib/common/IInterface.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -27,6 +27,6 @@ only pure virtual methods. */ class IInterface { public: - //! Interface destructor does nothing - virtual ~IInterface() { } + //! Interface destructor does nothing + virtual ~IInterface() {} }; diff --git a/src/lib/common/MacOSXPrecomp.h b/src/lib/common/MacOSXPrecomp.h index cb49b7438..8ae4edeef 100644 --- a/src/lib/common/MacOSXPrecomp.h +++ b/src/lib/common/MacOSXPrecomp.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -15,9 +15,10 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - - // -// Prefix header for all source files of the 'deleteme' target in the 'deleteme' project. + +// +// Prefix header for all source files of the 'deleteme' target in the 'deleteme' +// project. // #include diff --git a/src/lib/common/Version.cpp b/src/lib/common/Version.cpp index 100598c64..3c7fee081 100644 --- a/src/lib/common/Version.cpp +++ b/src/lib/common/Version.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 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 LICENSE 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 @@ -18,12 +18,12 @@ #include "common/Version.h" -const char* kBuildYear = __DATE__ + 7; -const char* kApplication = "Synergy"; -const char* kCopyright = "Copyright (C) 2012-%s Symless Ltd.\n" - "Copyright (C) 2008-2014 Nick Bolton\n" - "Copyright (C) 2002-2014 Chris Schoeneman"; -const char* kContact = "Email: engineering@symless.com"; -const char* kWebsite = "https://symless.com/"; -const char* kVersion = SYNERGY_VERSION; -const char* kAppVersion = "Synergy " SYNERGY_VERSION; +const char *kBuildYear = __DATE__ + 7; +const char *kApplication = "Synergy"; +const char *kCopyright = "Copyright (C) 2012-%s Symless Ltd.\n" + "Copyright (C) 2008-2014 Nick Bolton\n" + "Copyright (C) 2002-2014 Chris Schoeneman"; +const char *kContact = "Email: engineering@symless.com"; +const char *kWebsite = "https://symless.com/"; +const char *kVersion = SYNERGY_VERSION; +const char *kAppVersion = "Synergy " SYNERGY_VERSION; diff --git a/src/lib/common/Version.h b/src/lib/common/Version.h index 6a7bc7293..7af073f8a 100644 --- a/src/lib/common/Version.h +++ b/src/lib/common/Version.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -26,15 +26,15 @@ #endif // important strings -extern const char* kApplication; -extern const char* kCopyright; -extern const char* kContact; -extern const char* kWebsite; -extern const char* kBuildYear; +extern const char *kApplication; +extern const char *kCopyright; +extern const char *kContact; +extern const char *kWebsite; +extern const char *kBuildYear; // build version. follows linux kernel style: an even minor number implies // a release version, odd implies development version. -extern const char* kVersion; +extern const char *kVersion; // application version -extern const char* kAppVersion; +extern const char *kAppVersion; diff --git a/src/lib/common/basic_types.h b/src/lib/common/basic_types.h index 3b25278b4..02b9945ef 100644 --- a/src/lib/common/basic_types.h +++ b/src/lib/common/basic_types.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -23,10 +23,10 @@ // VC++ has built-in sized types // moved from common.h (why was it there?) #if defined(_MSC_VER) -# include -# define TYPE_OF_SIZE_1 __int8 -# define TYPE_OF_SIZE_2 __int16 -# define TYPE_OF_SIZE_4 __int32 +#include +#define TYPE_OF_SIZE_1 __int8 +#define TYPE_OF_SIZE_2 __int16 +#define TYPE_OF_SIZE_4 __int32 #endif // @@ -34,43 +34,42 @@ // #if !defined(TYPE_OF_SIZE_1) -# if SIZEOF_CHAR == 1 -# define TYPE_OF_SIZE_1 char -# endif +#if SIZEOF_CHAR == 1 +#define TYPE_OF_SIZE_1 char +#endif #endif #if !defined(TYPE_OF_SIZE_2) -# if SIZEOF_INT == 2 -# define TYPE_OF_SIZE_2 int -# else -# define TYPE_OF_SIZE_2 short -# endif +#if SIZEOF_INT == 2 +#define TYPE_OF_SIZE_2 int +#else +#define TYPE_OF_SIZE_2 short +#endif #endif #if !defined(TYPE_OF_SIZE_4) - // Carbon defines SInt32 and UInt32 in terms of long -# if SIZEOF_INT == 4 && !defined(__APPLE__) -# define TYPE_OF_SIZE_4 int -# else -# define TYPE_OF_SIZE_4 long -# endif +// Carbon defines SInt32 and UInt32 in terms of long +#if SIZEOF_INT == 4 && !defined(__APPLE__) +#define TYPE_OF_SIZE_4 int +#else +#define TYPE_OF_SIZE_4 long +#endif #endif - // +// // verify existence of required types // #if !defined(TYPE_OF_SIZE_1) -# error No 1 byte integer type +#error No 1 byte integer type #endif #if !defined(TYPE_OF_SIZE_2) -# error No 2 byte integer type +#error No 2 byte integer type #endif #if !defined(TYPE_OF_SIZE_4) -# error No 4 byte integer type +#error No 4 byte integer type #endif - // // make typedefs // @@ -79,17 +78,18 @@ // larger than indicated. // -// Added this because it doesn't compile on OS X 10.6 because they are already defined in Carbon +// Added this because it doesn't compile on OS X 10.6 because they are already +// defined in Carbon #if !defined(__MACTYPES__) #if defined(__APPLE__) #include #else -typedef signed TYPE_OF_SIZE_1 SInt8; -typedef signed TYPE_OF_SIZE_2 SInt16; -typedef signed TYPE_OF_SIZE_4 SInt32; -typedef unsigned TYPE_OF_SIZE_1 UInt8; -typedef unsigned TYPE_OF_SIZE_2 UInt16; -typedef unsigned TYPE_OF_SIZE_4 UInt32; +typedef signed TYPE_OF_SIZE_1 SInt8; +typedef signed TYPE_OF_SIZE_2 SInt16; +typedef signed TYPE_OF_SIZE_4 SInt32; +typedef unsigned TYPE_OF_SIZE_1 UInt8; +typedef unsigned TYPE_OF_SIZE_2 UInt16; +typedef unsigned TYPE_OF_SIZE_4 UInt32; #endif #endif // diff --git a/src/lib/common/common.h b/src/lib/common/common.h index aa9fde18e..8b8a04add 100644 --- a/src/lib/common/common.h +++ b/src/lib/common/common.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -19,12 +19,12 @@ #pragma once #if defined(_WIN32) -# define SYSAPI_WIN32 1 -# define WINAPI_MSWINDOWS 1 +#define SYSAPI_WIN32 1 +#define WINAPI_MSWINDOWS 1 #elif HAVE_CONFIG_H -# include "config.h" +#include "config.h" #else -# error "config.h missing" +#error "config.h missing" #endif // define NULL @@ -36,10 +36,10 @@ #include enum { - kExitSuccess = 0, // successful completion - kExitFailed = 1, // general failure - kExitTerminated = 2, // killed by signal - kExitArgs = 3, // bad arguments - kExitConfig = 4, // cannot read configuration - kExitSubscription = 5 // subscription error + kExitSuccess = 0, // successful completion + kExitFailed = 1, // general failure + kExitTerminated = 2, // killed by signal + kExitArgs = 3, // bad arguments + kExitConfig = 4, // cannot read configuration + kExitSubscription = 5 // subscription error }; diff --git a/src/lib/common/stdbitset.h b/src/lib/common/stdbitset.h index 103a48a35..a4d51edf2 100644 --- a/src/lib/common/stdbitset.h +++ b/src/lib/common/stdbitset.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -17,5 +17,7 @@ */ #include "common/stdpre.h" + #include + #include "common/stdpost.h" diff --git a/src/lib/common/stddeque.h b/src/lib/common/stddeque.h index 1fabe6828..c781b8f81 100644 --- a/src/lib/common/stddeque.h +++ b/src/lib/common/stddeque.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -17,5 +17,7 @@ */ #include "common/stdpre.h" + #include -#include "common/stdpost.h" + +#include "common/stdpost.h" \ No newline at end of file diff --git a/src/lib/common/stdexcept.h b/src/lib/common/stdexcept.h index 5be8049da..52ce3ab0d 100644 --- a/src/lib/common/stdexcept.h +++ b/src/lib/common/stdexcept.h @@ -1,11 +1,11 @@ /* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2014-2016 Symless Ltd. - * + * * 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 LICENSE 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 @@ -19,5 +19,5 @@ // apple declares _NOEXCEPT #ifndef _NOEXCEPT -# define _NOEXCEPT throw() +#define _NOEXCEPT throw() #endif diff --git a/src/lib/common/stdfstream.h b/src/lib/common/stdfstream.h index 459c1f4d4..b6845c55b 100644 --- a/src/lib/common/stdfstream.h +++ b/src/lib/common/stdfstream.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -17,6 +17,8 @@ */ #include "common/stdpre.h" -#include -#include "common/stdpost.h" + #include "common/stdistream.h" +#include + +#include "common/stdpost.h" diff --git a/src/lib/common/stdistream.h b/src/lib/common/stdistream.h index 86f29f77c..2adda50bc 100644 --- a/src/lib/common/stdistream.h +++ b/src/lib/common/stdistream.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -17,31 +17,33 @@ */ #include "common/stdpre.h" + #if HAVE_ISTREAM #include #else #include #endif + #include "common/stdpost.h" #if defined(_MSC_VER) && _MSC_VER <= 1200 // VC++6 istream has no overloads for __int* types, .NET does -inline -std::istream& operator>>(std::istream& s, SInt8& i) -{ return s >> (signed char&)i; } -inline -std::istream& operator>>(std::istream& s, SInt16& i) -{ return s >> (short&)i; } -inline -std::istream& operator>>(std::istream& s, SInt32& i) -{ return s >> (int&)i; } -inline -std::istream& operator>>(std::istream& s, UInt8& i) -{ return s >> (unsigned char&)i; } -inline -std::istream& operator>>(std::istream& s, UInt16& i) -{ return s >> (unsigned short&)i; } -inline -std::istream& operator>>(std::istream& s, UInt32& i) -{ return s >> (unsigned int&)i; } +inline std::istream &operator>>(std::istream &s, SInt8 &i) { + return s >> (signed char &)i; +} +inline std::istream &operator>>(std::istream &s, SInt16 &i) { + return s >> (short &)i; +} +inline std::istream &operator>>(std::istream &s, SInt32 &i) { + return s >> (int &)i; +} +inline std::istream &operator>>(std::istream &s, UInt8 &i) { + return s >> (unsigned char &)i; +} +inline std::istream &operator>>(std::istream &s, UInt16 &i) { + return s >> (unsigned short &)i; +} +inline std::istream &operator>>(std::istream &s, UInt32 &i) { + return s >> (unsigned int &)i; +} #endif diff --git a/src/lib/common/stdlist.h b/src/lib/common/stdlist.h index 9e0b32746..64ac1752c 100644 --- a/src/lib/common/stdlist.h +++ b/src/lib/common/stdlist.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -17,5 +17,7 @@ */ #include "common/stdpre.h" + #include + #include "common/stdpost.h" diff --git a/src/lib/common/stdmap.h b/src/lib/common/stdmap.h index 1b4c5a462..28e4ad327 100644 --- a/src/lib/common/stdmap.h +++ b/src/lib/common/stdmap.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -17,5 +17,7 @@ */ #include "common/stdpre.h" + #include -#include "common/stdpost.h" + +#include "common/stdpost.h" \ No newline at end of file diff --git a/src/lib/common/stdostream.h b/src/lib/common/stdostream.h index d51cafbdc..c82a02506 100644 --- a/src/lib/common/stdostream.h +++ b/src/lib/common/stdostream.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -17,9 +17,11 @@ */ #include "common/stdpre.h" + #if HAVE_OSTREAM #include #else #include #endif + #include "common/stdpost.h" diff --git a/src/lib/common/stdpost.h b/src/lib/common/stdpost.h index 80ea6c006..2658532f8 100644 --- a/src/lib/common/stdpost.h +++ b/src/lib/common/stdpost.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 diff --git a/src/lib/common/stdpre.h b/src/lib/common/stdpre.h index 3a028b609..b09a70747 100644 --- a/src/lib/common/stdpre.h +++ b/src/lib/common/stdpre.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -17,15 +17,15 @@ */ #if defined(_MSC_VER) -#pragma warning(disable: 4786) // identifier truncated -#pragma warning(disable: 4514) // unreferenced inline -#pragma warning(disable: 4710) // not inlined -#pragma warning(disable: 4663) // C++ change, template specialization -#pragma warning(disable: 4503) // decorated name length too long +#pragma warning(disable : 4786) // identifier truncated +#pragma warning(disable : 4514) // unreferenced inline +#pragma warning(disable : 4710) // not inlined +#pragma warning(disable : 4663) // C++ change, template specialization +#pragma warning(disable : 4503) // decorated name length too long #pragma warning(push, 3) -#pragma warning(disable: 4018) // signed/unsigned mismatch -#pragma warning(disable: 4284) -#pragma warning(disable: 4146) // unary minus on unsigned value -#pragma warning(disable: 4127) // conditional expression is constant -#pragma warning(disable: 4701) // variable possibly used uninitialized +#pragma warning(disable : 4018) // signed/unsigned mismatch +#pragma warning(disable : 4284) +#pragma warning(disable : 4146) // unary minus on unsigned value +#pragma warning(disable : 4127) // conditional expression is constant +#pragma warning(disable : 4701) // variable possibly used uninitialized #endif diff --git a/src/lib/common/stdset.h b/src/lib/common/stdset.h index 2bf2b6e2b..9a0be8d30 100644 --- a/src/lib/common/stdset.h +++ b/src/lib/common/stdset.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -17,5 +17,7 @@ */ #include "common/stdpre.h" + #include -#include "common/stdpost.h" + +#include "common/stdpost.h" \ No newline at end of file diff --git a/src/lib/common/stdsstream.h b/src/lib/common/stdsstream.h index 8011ba98c..8184ef053 100644 --- a/src/lib/common/stdsstream.h +++ b/src/lib/common/stdsstream.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -58,319 +58,232 @@ the executable file might be covered by the GNU General Public License. */ #include #include -namespace std -{ - class stringbuf : public streambuf - { - public: - typedef char char_type; - typedef int int_type; - typedef streampos pos_type; - typedef streamoff off_type; +namespace std { +class stringbuf : public streambuf { +public: + typedef char char_type; + typedef int int_type; + typedef streampos pos_type; + typedef streamoff off_type; - explicit - stringbuf(int which=ios::in|ios::out) - : streambuf(), mode(static_cast(which)), - stream(NULL), stream_len(0) - { - stringbuf_init(); - } + explicit stringbuf(int which = ios::in | ios::out) + : streambuf(), mode(static_cast(which)), stream(NULL), + stream_len(0) { + stringbuf_init(); + } - explicit - stringbuf(const string &str, int which=ios::in|ios::out) - : streambuf(), mode(static_cast(which)), - stream(NULL), stream_len(0) - { - if (mode & (ios::in|ios::out)) - { + explicit stringbuf(const string &str, int which = ios::in | ios::out) + : streambuf(), mode(static_cast(which)), stream(NULL), + stream_len(0) { + if (mode & (ios::in | ios::out)) { stream_len = str.size(); stream = new char_type[stream_len]; str.copy(stream, stream_len); } - stringbuf_init(); - } + stringbuf_init(); + } - virtual - ~stringbuf() - { - delete[] stream; - } + virtual ~stringbuf() { delete[] stream; } - string - str() const - { - if (pbase() != 0) - return string(stream, pptr()-pbase()); - else - return string(); - } + string str() const { + if (pbase() != 0) + return string(stream, pptr() - pbase()); + else + return string(); + } - void - str(const string& str) - { - delete[] stream; - stream_len = str.size(); - stream = new char_type[stream_len]; - str.copy(stream, stream_len); - stringbuf_init(); - } + void str(const string &str) { + delete[] stream; + stream_len = str.size(); + stream = new char_type[stream_len]; + str.copy(stream, stream_len); + stringbuf_init(); + } - protected: - // The buffer is already in gptr, so if it ends then it is out of data. - virtual int - underflow() - { - return EOF; - } +protected: + // The buffer is already in gptr, so if it ends then it is out of data. + virtual int underflow() { return EOF; } - virtual int - overflow(int c = EOF) - { - int res; - if (mode & ios::out) - { - if (c != EOF) - { - streamsize old_stream_len = stream_len; - stream_len += 1; - char_type* new_stream = new char_type[stream_len]; - memcpy(new_stream, stream, old_stream_len); - delete[] stream; - stream = new_stream; - stringbuf_sync(gptr()-eback(), pptr()-pbase()); - sputc(c); - res = c; - } - else + virtual int overflow(int c = EOF) { + int res; + if (mode & ios::out) { + if (c != EOF) { + streamsize old_stream_len = stream_len; + stream_len += 1; + char_type *new_stream = new char_type[stream_len]; + memcpy(new_stream, stream, old_stream_len); + delete[] stream; + stream = new_stream; + stringbuf_sync(gptr() - eback(), pptr() - pbase()); + sputc(c); + res = c; + } else res = EOF; - } - else - res = 0; - return res; - } + } else + res = 0; + return res; + } - virtual streambuf* - setbuf(char_type* s, streamsize n) - { - if (n != 0) - { + virtual streambuf *setbuf(char_type *s, streamsize n) { + if (n != 0) { delete[] stream; stream = new char_type[n]; memcpy(stream, s, n); stream_len = n; stringbuf_sync(0, 0); } - return this; - } + return this; + } - virtual pos_type - seekoff(off_type off, ios::seek_dir way, int which = ios::in | ios::out) - { - pos_type ret = pos_type(off_type(-1)); - bool testin = which & ios::in && mode & ios::in; - bool testout = which & ios::out && mode & ios::out; - bool testboth = testin && testout && way != ios::cur; + virtual pos_type seekoff(off_type off, ios::seek_dir way, + int which = ios::in | ios::out) { + pos_type ret = pos_type(off_type(-1)); + bool testin = which & ios::in && mode & ios::in; + bool testout = which & ios::out && mode & ios::out; + bool testboth = testin && testout && way != ios::cur; - if (stream_len && ((testin != testout) || testboth)) - { - char_type* beg = stream; - char_type* curi = NULL; - char_type* curo = NULL; - char_type* endi = NULL; - char_type* endo = NULL; + if (stream_len && ((testin != testout) || testboth)) { + char_type *beg = stream; + char_type *curi = NULL; + char_type *curo = NULL; + char_type *endi = NULL; + char_type *endo = NULL; - if (testin) - { - curi = gptr(); - endi = egptr(); - } - if (testout) - { - curo = pptr(); - endo = epptr(); - } + if (testin) { + curi = gptr(); + endi = egptr(); + } + if (testout) { + curo = pptr(); + endo = epptr(); + } off_type newoffi = 0; off_type newoffo = 0; - if (way == ios::beg) - { - newoffi = beg - curi; - newoffo = beg - curo; - } - else if (way == ios::end) - { - newoffi = endi - curi; - newoffo = endo - curo; - } + if (way == ios::beg) { + newoffi = beg - curi; + newoffo = beg - curo; + } else if (way == ios::end) { + newoffi = endi - curi; + newoffo = endo - curo; + } if (testin && newoffi + off + curi - beg >= 0 && - endi - beg >= newoffi + off + curi - beg) - { - gbump(newoffi + off); - ret = pos_type(newoffi + off + curi); - } + endi - beg >= newoffi + off + curi - beg) { + gbump(newoffi + off); + ret = pos_type(newoffi + off + curi); + } if (testout && newoffo + off + curo - beg >= 0 && - endo - beg >= newoffo + off + curo - beg) - { - pbump(newoffo + off); - ret = pos_type(newoffo + off + curo); - } - } - return ret; + endo - beg >= newoffo + off + curo - beg) { + pbump(newoffo + off); + ret = pos_type(newoffo + off + curo); + } } + return ret; + } - virtual pos_type - seekpos(pos_type sp, int which = ios::in | ios::out) - { - pos_type ret = seekoff(sp, ios::beg, which); - return ret; - } + virtual pos_type seekpos(pos_type sp, int which = ios::in | ios::out) { + pos_type ret = seekoff(sp, ios::beg, which); + return ret; + } - private: - void - stringbuf_sync(streamsize i, streamsize o) - { - if (mode & ios::in) - setg(stream, stream + i, stream + stream_len); - if (mode & ios::out) - { +private: + void stringbuf_sync(streamsize i, streamsize o) { + if (mode & ios::in) + setg(stream, stream + i, stream + stream_len); + if (mode & ios::out) { setp(stream, stream + stream_len); pbump(o); } - } - void - stringbuf_init() - { - if (mode & ios::ate) - stringbuf_sync(0, stream_len); - else - stringbuf_sync(0, 0); - } + } + void stringbuf_init() { + if (mode & ios::ate) + stringbuf_sync(0, stream_len); + else + stringbuf_sync(0, 0); + } - private: - ios::open_mode mode; - char_type* stream; - streamsize stream_len; - }; - - class istringstream : public istream { - public: - typedef char char_type; - typedef int int_type; - typedef streampos pos_type; - typedef streamoff off_type; - - explicit - istringstream(int which=ios::in) - : istream(&sb), sb(which | ios::in) - { } - - explicit - istringstream(const string& str, int which=ios::in) - : istream(&sb), sb(str, which | ios::in) - { } - - stringbuf* - rdbuf() const - { - return const_cast(&sb); - } - - string - str() const - { - return rdbuf()->str(); - } - void - str(const string& s) - { - rdbuf()->str(s); - } - private: - stringbuf sb; - }; - - class ostringstream : public ostream { - public: - typedef char char_type; - typedef int int_type; - typedef streampos pos_type; - typedef streamoff off_type; - - explicit - ostringstream(int which=ios::out) - : ostream(&sb), sb(which | ios::out) - { } - - explicit - ostringstream(const string& str, int which=ios::out) - : ostream(&sb), sb(str, which | ios::out) - { } - - stringbuf* - rdbuf() const - { - return const_cast(&sb); - } - - string - str() const - { - return rdbuf()->str(); - } - - void str(const string& s) - { - rdbuf()->str(s); - } - private: - stringbuf sb; - }; - - class stringstream : public iostream { - public: - typedef char char_type; - typedef int int_type; - typedef streampos pos_type; - typedef streamoff off_type; - - explicit - stringstream(int which=ios::out|ios::in) - : iostream(&sb), sb(which) - { } - - explicit - stringstream(const string& str, int which=ios::out|ios::in) - : iostream(&sb), sb(str, which) - { } - - stringbuf* - rdbuf() const - { - return const_cast(&sb); - } - - string - str() const - { - return rdbuf()->str(); - } - - void - str(const string& s) - { - rdbuf()->str(s); - } - private: - stringbuf sb; - }; +private: + ios::open_mode mode; + char_type *stream; + streamsize stream_len; }; +class istringstream : public istream { +public: + typedef char char_type; + typedef int int_type; + typedef streampos pos_type; + typedef streamoff off_type; + + explicit istringstream(int which = ios::in) + : istream(&sb), sb(which | ios::in) {} + + explicit istringstream(const string &str, int which = ios::in) + : istream(&sb), sb(str, which | ios::in) {} + + stringbuf *rdbuf() const { return const_cast(&sb); } + + string str() const { return rdbuf()->str(); } + void str(const string &s) { rdbuf()->str(s); } + +private: + stringbuf sb; +}; + +class ostringstream : public ostream { +public: + typedef char char_type; + typedef int int_type; + typedef streampos pos_type; + typedef streamoff off_type; + + explicit ostringstream(int which = ios::out) + : ostream(&sb), sb(which | ios::out) {} + + explicit ostringstream(const string &str, int which = ios::out) + : ostream(&sb), sb(str, which | ios::out) {} + + stringbuf *rdbuf() const { return const_cast(&sb); } + + string str() const { return rdbuf()->str(); } + + void str(const string &s) { rdbuf()->str(s); } + +private: + stringbuf sb; +}; + +class stringstream : public iostream { +public: + typedef char char_type; + typedef int int_type; + typedef streampos pos_type; + typedef streamoff off_type; + + explicit stringstream(int which = ios::out | ios::in) + : iostream(&sb), sb(which) {} + + explicit stringstream(const string &str, int which = ios::out | ios::in) + : iostream(&sb), sb(str, which) {} + + stringbuf *rdbuf() const { return const_cast(&sb); } + + string str() const { return rdbuf()->str(); } + + void str(const string &s) { rdbuf()->str(s); } + +private: + stringbuf sb; +}; +}; // namespace std + #else /* not g++ 2.95 and no */ #error "Standard C++ library is missing required sstream header." #endif /* not g++ 2.95 and no */ -#include "common/stdpost.h" #include "common/stdistream.h" + +#include "common/stdpost.h" diff --git a/src/lib/common/stdstring.h b/src/lib/common/stdstring.h index 20ce67ef0..69433e374 100644 --- a/src/lib/common/stdstring.h +++ b/src/lib/common/stdstring.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -17,5 +17,7 @@ */ #include "common/stdpre.h" + #include -#include "common/stdpost.h" + +#include "common/stdpost.h" \ No newline at end of file diff --git a/src/lib/common/stdvector.h b/src/lib/common/stdvector.h index 75a332983..0fcb993db 100644 --- a/src/lib/common/stdvector.h +++ b/src/lib/common/stdvector.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -17,5 +17,7 @@ */ #include "common/stdpre.h" + #include + #include "common/stdpost.h" diff --git a/src/lib/io/IStream.h b/src/lib/io/IStream.h index 905004a67..a5289aa0e 100644 --- a/src/lib/io/IStream.h +++ b/src/lib/io/IStream.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 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 LICENSE 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 @@ -18,10 +18,10 @@ #pragma once -#include "common/IInterface.h" #include "base/Event.h" -#include "base/IEventQueue.h" #include "base/EventTypes.h" +#include "base/IEventQueue.h" +#include "common/IInterface.h" class IEventQueue; @@ -33,88 +33,88 @@ Defines the interface for all streams. */ class IStream : public IInterface { public: - IStream() { } + IStream() {} - //! @name manipulators - //@{ + //! @name manipulators + //@{ - //! Close the stream - /*! - Closes the stream. Pending input data and buffered output data - are discarded. Use \c flush() before \c close() to send buffered - output data. Attempts to \c read() after a close return 0, - attempts to \c write() generate output error events, and attempts - to \c flush() return immediately. - */ - virtual void close() = 0; + //! Close the stream + /*! + Closes the stream. Pending input data and buffered output data + are discarded. Use \c flush() before \c close() to send buffered + output data. Attempts to \c read() after a close return 0, + attempts to \c write() generate output error events, and attempts + to \c flush() return immediately. + */ + virtual void close() = 0; - //! Read from stream - /*! - Read up to \p n bytes into \p buffer, returning the number read - (zero if no data is available or input is shutdown). \p buffer - may be NULL in which case the data is discarded. - */ - virtual UInt32 read(void* buffer, UInt32 n) = 0; + //! Read from stream + /*! + Read up to \p n bytes into \p buffer, returning the number read + (zero if no data is available or input is shutdown). \p buffer + may be NULL in which case the data is discarded. + */ + virtual UInt32 read(void *buffer, UInt32 n) = 0; - //! Write to stream - /*! - Write \c n bytes from \c buffer to the stream. If this can't - complete immediately it will block. Data may be buffered in - order to return more quickly. A output error event is generated - when writing fails. - */ - virtual void write(const void* buffer, UInt32 n) = 0; + //! Write to stream + /*! + Write \c n bytes from \c buffer to the stream. If this can't + complete immediately it will block. Data may be buffered in + order to return more quickly. A output error event is generated + when writing fails. + */ + virtual void write(const void *buffer, UInt32 n) = 0; - //! Flush the stream - /*! - Waits until all buffered data has been written to the stream. - */ - virtual void flush() = 0; + //! Flush the stream + /*! + Waits until all buffered data has been written to the stream. + */ + virtual void flush() = 0; - //! Shutdown input - /*! - Shutdown the input side of the stream. Any pending input data is - discarded and further reads immediately return 0. - */ - virtual void shutdownInput() = 0; + //! Shutdown input + /*! + Shutdown the input side of the stream. Any pending input data is + discarded and further reads immediately return 0. + */ + virtual void shutdownInput() = 0; - //! Shutdown output - /*! - Shutdown the output side of the stream. Any buffered output data - is discarded and further writes generate output error events. Use - \c flush() before \c shutdownOutput() to send buffered output data. - */ - virtual void shutdownOutput() = 0; + //! Shutdown output + /*! + Shutdown the output side of the stream. Any buffered output data + is discarded and further writes generate output error events. Use + \c flush() before \c shutdownOutput() to send buffered output data. + */ + virtual void shutdownOutput() = 0; - //@} - //! @name accessors - //@{ + //@} + //! @name accessors + //@{ - //! Get event target - /*! - Returns the event target for events generated by this stream. It - should be the source stream in a chain of stream filters. - */ - virtual void* getEventTarget() const = 0; + //! Get event target + /*! + Returns the event target for events generated by this stream. It + should be the source stream in a chain of stream filters. + */ + virtual void *getEventTarget() const = 0; - //! Test if \c read() will succeed - /*! - Returns true iff an immediate \c read() will return data. This - may or may not be the same as \c getSize() > 0, depending on the - stream type. - */ - virtual bool isReady() const = 0; + //! Test if \c read() will succeed + /*! + Returns true iff an immediate \c read() will return data. This + may or may not be the same as \c getSize() > 0, depending on the + stream type. + */ + virtual bool isReady() const = 0; - //! Get bytes available to read - /*! - Returns a conservative estimate of the available bytes to read - (i.e. a number not greater than the actual number of bytes). - Some streams may not be able to determine this and will always - return zero. - */ - virtual UInt32 getSize() const = 0; + //! Get bytes available to read + /*! + Returns a conservative estimate of the available bytes to read + (i.e. a number not greater than the actual number of bytes). + Some streams may not be able to determine this and will always + return zero. + */ + virtual UInt32 getSize() const = 0; - //@} + //@} }; -} +} // namespace synergy diff --git a/src/lib/io/StreamBuffer.cpp b/src/lib/io/StreamBuffer.cpp index f7cf86bd7..2ba264e96 100644 --- a/src/lib/io/StreamBuffer.cpp +++ b/src/lib/io/StreamBuffer.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -23,125 +23,111 @@ // StreamBuffer // -const UInt32 StreamBuffer::kChunkSize = 4096; +const UInt32 StreamBuffer::kChunkSize = 4096; -StreamBuffer::StreamBuffer() : - m_size(0), - m_headUsed(0) -{ - // do nothing +StreamBuffer::StreamBuffer() : m_size(0), m_headUsed(0) { + // do nothing } -StreamBuffer::~StreamBuffer() -{ - // do nothing +StreamBuffer::~StreamBuffer() { + // do nothing } -const void* -StreamBuffer::peek(UInt32 n) -{ - assert(n <= m_size); +const void *StreamBuffer::peek(UInt32 n) { + assert(n <= m_size); - // if requesting no data then return NULL so we don't try to access - // an empty list. - if (n == 0) { - return NULL; - } + // if requesting no data then return NULL so we don't try to access + // an empty list. + if (n == 0) { + return NULL; + } - // reserve space in first chunk - ChunkList::iterator head = m_chunks.begin(); - head->reserve(n + m_headUsed); + // reserve space in first chunk + ChunkList::iterator head = m_chunks.begin(); + head->reserve(n + m_headUsed); - // consolidate chunks into the first chunk until it has n bytes - ChunkList::iterator scan = head; - ++scan; - while (head->size() - m_headUsed < n && scan != m_chunks.end()) { - head->insert(head->end(), scan->begin(), scan->end()); - scan = m_chunks.erase(scan); - } + // consolidate chunks into the first chunk until it has n bytes + ChunkList::iterator scan = head; + ++scan; + while (head->size() - m_headUsed < n && scan != m_chunks.end()) { + head->insert(head->end(), scan->begin(), scan->end()); + scan = m_chunks.erase(scan); + } - return static_cast(&(head->begin()[m_headUsed])); + return static_cast(&(head->begin()[m_headUsed])); } -void -StreamBuffer::pop(UInt32 n) -{ - // discard all chunks if n is greater than or equal to m_size - if (n >= m_size) { - m_size = 0; - m_headUsed = 0; - m_chunks.clear(); - return; - } +void StreamBuffer::pop(UInt32 n) { + // discard all chunks if n is greater than or equal to m_size + if (n >= m_size) { + m_size = 0; + m_headUsed = 0; + m_chunks.clear(); + return; + } - // update size - m_size -= n; + // update size + m_size -= n; - // discard chunks until more than n bytes would've been discarded - ChunkList::iterator scan = m_chunks.begin(); + // discard chunks until more than n bytes would've been discarded + ChunkList::iterator scan = m_chunks.begin(); + assert(scan != m_chunks.end()); + while (scan->size() - m_headUsed <= n) { + n -= (UInt32)scan->size() - m_headUsed; + m_headUsed = 0; + scan = m_chunks.erase(scan); assert(scan != m_chunks.end()); - while (scan->size() - m_headUsed <= n) { - n -= (UInt32)scan->size() - m_headUsed; - m_headUsed = 0; - scan = m_chunks.erase(scan); - assert(scan != m_chunks.end()); - } + } - // remove left over bytes from the head chunk + // remove left over bytes from the head chunk + if (n > 0) { + m_headUsed += n; + } +} + +void StreamBuffer::write(const void *vdata, UInt32 n) { + assert(vdata != NULL); + + // ignore if no data, otherwise update size + if (n == 0) { + return; + } + m_size += n; + + // cast data to bytes + const UInt8 *data = static_cast(vdata); + + // point to last chunk if it has space, otherwise append an empty chunk + ChunkList::iterator scan = m_chunks.end(); + if (scan != m_chunks.begin()) { + --scan; + if (scan->size() >= kChunkSize) { + ++scan; + } + } + if (scan == m_chunks.end()) { + scan = m_chunks.insert(scan, Chunk()); + } + + // append data in chunks + while (n > 0) { + // choose number of bytes for next chunk + assert(scan->size() <= kChunkSize); + UInt32 count = kChunkSize - (UInt32)scan->size(); + if (count > n) + count = n; + + // transfer data + scan->insert(scan->end(), data, data + count); + n -= count; + data += count; + + // append another empty chunk if we're not done yet if (n > 0) { - m_headUsed += n; + ++scan; + scan = m_chunks.insert(scan, Chunk()); } + } } -void -StreamBuffer::write(const void* vdata, UInt32 n) -{ - assert(vdata != NULL); - - // ignore if no data, otherwise update size - if (n == 0) { - return; - } - m_size += n; - - // cast data to bytes - const UInt8* data = static_cast(vdata); - - // point to last chunk if it has space, otherwise append an empty chunk - ChunkList::iterator scan = m_chunks.end(); - if (scan != m_chunks.begin()) { - --scan; - if (scan->size() >= kChunkSize) { - ++scan; - } - } - if (scan == m_chunks.end()) { - scan = m_chunks.insert(scan, Chunk()); - } - - // append data in chunks - while (n > 0) { - // choose number of bytes for next chunk - assert(scan->size() <= kChunkSize); - UInt32 count = kChunkSize - (UInt32)scan->size(); - if (count > n) - count = n; - - // transfer data - scan->insert(scan->end(), data, data + count); - n -= count; - data += count; - - // append another empty chunk if we're not done yet - if (n > 0) { - ++scan; - scan = m_chunks.insert(scan, Chunk()); - } - } -} - -UInt32 -StreamBuffer::getSize() const -{ - return m_size; -} +UInt32 StreamBuffer::getSize() const { return m_size; } diff --git a/src/lib/io/StreamBuffer.h b/src/lib/io/StreamBuffer.h index db218cc0d..5d0478d8f 100644 --- a/src/lib/io/StreamBuffer.h +++ b/src/lib/io/StreamBuffer.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -28,52 +28,52 @@ This class maintains a FIFO (first-in, last-out) buffer of bytes. */ class StreamBuffer { public: - StreamBuffer(); - ~StreamBuffer(); + StreamBuffer(); + ~StreamBuffer(); - //! @name manipulators - //@{ + //! @name manipulators + //@{ - //! Read data without removing from buffer - /*! - Return a pointer to memory with the next \c n bytes in the buffer - (which must be <= getSize()). The caller must not modify the returned - memory nor delete it. - */ - const void* peek(UInt32 n); + //! Read data without removing from buffer + /*! + Return a pointer to memory with the next \c n bytes in the buffer + (which must be <= getSize()). The caller must not modify the returned + memory nor delete it. + */ + const void *peek(UInt32 n); - //! Discard data - /*! - Discards the next \c n bytes. If \c n >= getSize() then the buffer - is cleared. - */ - void pop(UInt32 n); + //! Discard data + /*! + Discards the next \c n bytes. If \c n >= getSize() then the buffer + is cleared. + */ + void pop(UInt32 n); - //! Write data to buffer - /*! - Appends \c n bytes from \c data to the buffer. - */ - void write(const void* data, UInt32 n); + //! Write data to buffer + /*! + Appends \c n bytes from \c data to the buffer. + */ + void write(const void *data, UInt32 n); - //@} - //! @name accessors - //@{ + //@} + //! @name accessors + //@{ - //! Get size of buffer - /*! - Returns the number of bytes in the buffer. - */ - UInt32 getSize() const; + //! Get size of buffer + /*! + Returns the number of bytes in the buffer. + */ + UInt32 getSize() const; - //@} + //@} private: - static const UInt32 kChunkSize; + static const UInt32 kChunkSize; - typedef std::vector Chunk; - typedef std::list ChunkList; + typedef std::vector Chunk; + typedef std::list ChunkList; - ChunkList m_chunks; - UInt32 m_size; - UInt32 m_headUsed; + ChunkList m_chunks; + UInt32 m_size; + UInt32 m_headUsed; }; diff --git a/src/lib/io/StreamFilter.cpp b/src/lib/io/StreamFilter.cpp index ceefb89e7..db4c030f1 100644 --- a/src/lib/io/StreamFilter.cpp +++ b/src/lib/io/StreamFilter.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 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 LICENSE 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 @@ -24,95 +24,54 @@ // StreamFilter // -StreamFilter::StreamFilter(IEventQueue* events, synergy::IStream* stream, bool adoptStream) : - m_stream(stream), - m_adopted(adoptStream), - m_events(events) -{ - // replace handlers for m_stream - m_events->removeHandlers(m_stream->getEventTarget()); - m_events->adoptHandler(Event::kUnknown, m_stream->getEventTarget(), - new TMethodEventJob(this, - &StreamFilter::handleUpstreamEvent)); +StreamFilter::StreamFilter(IEventQueue *events, synergy::IStream *stream, + bool adoptStream) + : m_stream(stream), m_adopted(adoptStream), m_events(events) { + // replace handlers for m_stream + m_events->removeHandlers(m_stream->getEventTarget()); + m_events->adoptHandler(Event::kUnknown, m_stream->getEventTarget(), + new TMethodEventJob( + this, &StreamFilter::handleUpstreamEvent)); } -StreamFilter::~StreamFilter() -{ - m_events->removeHandler(Event::kUnknown, m_stream->getEventTarget()); - if (m_adopted) { - delete m_stream; - } +StreamFilter::~StreamFilter() { + m_events->removeHandler(Event::kUnknown, m_stream->getEventTarget()); + if (m_adopted) { + delete m_stream; + } } -void -StreamFilter::close() -{ - getStream()->close(); +void StreamFilter::close() { getStream()->close(); } + +UInt32 StreamFilter::read(void *buffer, UInt32 n) { + return getStream()->read(buffer, n); } -UInt32 -StreamFilter::read(void* buffer, UInt32 n) -{ - return getStream()->read(buffer, n); +void StreamFilter::write(const void *buffer, UInt32 n) { + getStream()->write(buffer, n); } -void -StreamFilter::write(const void* buffer, UInt32 n) -{ - getStream()->write(buffer, n); +void StreamFilter::flush() { getStream()->flush(); } + +void StreamFilter::shutdownInput() { getStream()->shutdownInput(); } + +void StreamFilter::shutdownOutput() { getStream()->shutdownOutput(); } + +void *StreamFilter::getEventTarget() const { + return const_cast(static_cast(this)); } -void -StreamFilter::flush() -{ - getStream()->flush(); +bool StreamFilter::isReady() const { return getStream()->isReady(); } + +UInt32 StreamFilter::getSize() const { return getStream()->getSize(); } + +synergy::IStream *StreamFilter::getStream() const { return m_stream; } + +void StreamFilter::filterEvent(const Event &event) { + m_events->dispatchEvent( + Event(event.getType(), getEventTarget(), event.getData())); } -void -StreamFilter::shutdownInput() -{ - getStream()->shutdownInput(); -} - -void -StreamFilter::shutdownOutput() -{ - getStream()->shutdownOutput(); -} - -void* -StreamFilter::getEventTarget() const -{ - return const_cast(static_cast(this)); -} - -bool -StreamFilter::isReady() const -{ - return getStream()->isReady(); -} - -UInt32 -StreamFilter::getSize() const -{ - return getStream()->getSize(); -} - -synergy::IStream* -StreamFilter::getStream() const -{ - return m_stream; -} - -void -StreamFilter::filterEvent(const Event& event) -{ - m_events->dispatchEvent(Event(event.getType(), - getEventTarget(), event.getData())); -} - -void -StreamFilter::handleUpstreamEvent(const Event& event, void*) -{ - filterEvent(event); +void StreamFilter::handleUpstreamEvent(const Event &event, void *) { + filterEvent(event); } diff --git a/src/lib/io/StreamFilter.h b/src/lib/io/StreamFilter.h index 62630ba52..23d46444c 100644 --- a/src/lib/io/StreamFilter.h +++ b/src/lib/io/StreamFilter.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 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 LICENSE 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 @@ -18,8 +18,8 @@ #pragma once -#include "io/IStream.h" #include "base/IEventQueue.h" +#include "io/IStream.h" //! A stream filter /*! @@ -28,51 +28,52 @@ to the wrapped stream, typically performing some filtering. */ class StreamFilter : public synergy::IStream { public: - /*! - Create a wrapper around \c stream. Iff \c adoptStream is true then - this object takes ownership of the stream and will delete it in the - d'tor. - */ - StreamFilter(IEventQueue* events, synergy::IStream* stream, bool adoptStream = true); - StreamFilter(StreamFilter const &) =delete; - StreamFilter(StreamFilter &&) =delete; - virtual ~StreamFilter(); + /*! + Create a wrapper around \c stream. Iff \c adoptStream is true then + this object takes ownership of the stream and will delete it in the + d'tor. + */ + StreamFilter(IEventQueue *events, synergy::IStream *stream, + bool adoptStream = true); + StreamFilter(StreamFilter const &) = delete; + StreamFilter(StreamFilter &&) = delete; + virtual ~StreamFilter(); - StreamFilter& operator=(StreamFilter const &) =delete; - StreamFilter& operator=(StreamFilter &&) =delete; + StreamFilter &operator=(StreamFilter const &) = delete; + StreamFilter &operator=(StreamFilter &&) = delete; - // IStream overrides - // These all just forward to the underlying stream except getEventTarget. - // Override as necessary. getEventTarget returns a pointer to this. - virtual void close(); - virtual UInt32 read(void* buffer, UInt32 n); - virtual void write(const void* buffer, UInt32 n); - virtual void flush(); - virtual void shutdownInput(); - virtual void shutdownOutput(); - virtual void* getEventTarget() const; - virtual bool isReady() const; - virtual UInt32 getSize() const; + // IStream overrides + // These all just forward to the underlying stream except getEventTarget. + // Override as necessary. getEventTarget returns a pointer to this. + virtual void close(); + virtual UInt32 read(void *buffer, UInt32 n); + virtual void write(const void *buffer, UInt32 n); + virtual void flush(); + virtual void shutdownInput(); + virtual void shutdownOutput(); + virtual void *getEventTarget() const; + virtual bool isReady() const; + virtual UInt32 getSize() const; - //! Get the stream - /*! - Returns the stream passed to the c'tor. - */ - synergy::IStream* getStream() const; + //! Get the stream + /*! + Returns the stream passed to the c'tor. + */ + synergy::IStream *getStream() const; protected: - //! Handle events from source stream - /*! - Does the event filtering. The default simply dispatches an event - identical except using this object as the event target. - */ - virtual void filterEvent(const Event&); + //! Handle events from source stream + /*! + Does the event filtering. The default simply dispatches an event + identical except using this object as the event target. + */ + virtual void filterEvent(const Event &); private: - void handleUpstreamEvent(const Event&, void*); + void handleUpstreamEvent(const Event &, void *); private: - synergy::IStream* m_stream; - bool m_adopted; - IEventQueue* m_events; + synergy::IStream *m_stream; + bool m_adopted; + IEventQueue *m_events; }; diff --git a/src/lib/io/XIO.cpp b/src/lib/io/XIO.cpp index 5ff04fc4b..54edae83f 100644 --- a/src/lib/io/XIO.cpp +++ b/src/lib/io/XIO.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -22,30 +22,22 @@ // XIOClosed // -String -XIOClosed::getWhat() const throw() -{ - return format("XIOClosed", "already closed"); +String XIOClosed::getWhat() const throw() { + return format("XIOClosed", "already closed"); } - // // XIOEndOfStream // -String -XIOEndOfStream::getWhat() const throw() -{ - return format("XIOEndOfStream", "reached end of stream"); +String XIOEndOfStream::getWhat() const throw() { + return format("XIOEndOfStream", "reached end of stream"); } - // // XIOWouldBlock // -String -XIOWouldBlock::getWhat() const throw() -{ - return format("XIOWouldBlock", "stream operation would block"); +String XIOWouldBlock::getWhat() const throw() { + return format("XIOWouldBlock", "stream operation would block"); } diff --git a/src/lib/io/XIO.h b/src/lib/io/XIO.h index fe7ad2036..2d0656aae 100644 --- a/src/lib/io/XIO.h +++ b/src/lib/io/XIO.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 diff --git a/src/lib/ipc/Ipc.cpp b/src/lib/ipc/Ipc.cpp index a2b77e09c..d7f9fba72 100644 --- a/src/lib/ipc/Ipc.cpp +++ b/src/lib/ipc/Ipc.cpp @@ -18,9 +18,9 @@ #include "ipc/Ipc.h" -const char* kIpcMsgHello = "IHEL%1i"; -const char* kIpcMsgHelloBack = "IHEL"; -const char* kIpcMsgLogLine = "ILOG%s"; -const char* kIpcMsgCommand = "ICMD%s%1i"; -const char* kIpcMsgShutdown = "ISDN"; -const char* kIpcMsgSetting = "SSET%s%s"; +const char *kIpcMsgHello = "IHEL%1i"; +const char *kIpcMsgHelloBack = "IHEL"; +const char *kIpcMsgLogLine = "ILOG%s"; +const char *kIpcMsgCommand = "ICMD%s%1i"; +const char *kIpcMsgShutdown = "ISDN"; +const char *kIpcMsgSetting = "SSET%s%s"; diff --git a/src/lib/ipc/Ipc.h b/src/lib/ipc/Ipc.h index ffd9215ac..22253276d 100644 --- a/src/lib/ipc/Ipc.h +++ b/src/lib/ipc/Ipc.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2012 Nick Bolton - * + * * 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 LICENSE 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 @@ -22,42 +22,38 @@ #define IPC_PORT 24801 enum EIpcMessage { - kIpcHello, - kIpcHelloBack, - kIpcLogLine, - kIpcCommand, - kIpcShutdown, - kIpcSetting + kIpcHello, + kIpcHelloBack, + kIpcLogLine, + kIpcCommand, + kIpcShutdown, + kIpcSetting }; -enum EIpcClientType { - kIpcClientUnknown, - kIpcClientGui, - kIpcClientNode -}; +enum EIpcClientType { kIpcClientUnknown, kIpcClientGui, kIpcClientNode }; // handshake: node/gui -> daemon // $1 = type, the client identifies it's self as gui or node (synergyc/s). -extern const char* kIpcMsgHello; +extern const char *kIpcMsgHello; // handshake: daemon -> node/gui // the daemon responds to the handshake. -extern const char* kIpcMsgHelloBack; +extern const char *kIpcMsgHelloBack; // log line: daemon -> gui // $1 = aggregate log lines collected from synergys/c or the daemon itself. -extern const char* kIpcMsgLogLine; +extern const char *kIpcMsgLogLine; // command: gui -> daemon // $1 = command; the command for the daemon to launch, typically the full // path to synergys/c. $2 = true when process must be elevated on ms windows. -extern const char* kIpcMsgCommand; +extern const char *kIpcMsgCommand; // shutdown: daemon -> node // the daemon tells synergys/c to shut down gracefully. -extern const char* kIpcMsgShutdown; +extern const char *kIpcMsgShutdown; // set setting: gui -> daemon // $1 = setting name // $2 = setting value -extern const char* kIpcMsgSetting; +extern const char *kIpcMsgSetting; diff --git a/src/lib/ipc/IpcClient.cpp b/src/lib/ipc/IpcClient.cpp index 22726abcb..32876ee2b 100644 --- a/src/lib/ipc/IpcClient.cpp +++ b/src/lib/ipc/IpcClient.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2012 Nick Bolton - * + * * 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 LICENSE 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 @@ -17,92 +17,71 @@ */ #include "ipc/IpcClient.h" -#include "ipc/Ipc.h" -#include "ipc/IpcServerProxy.h" -#include "ipc/IpcMessage.h" #include "base/TMethodEventJob.h" +#include "ipc/Ipc.h" +#include "ipc/IpcMessage.h" +#include "ipc/IpcServerProxy.h" // // IpcClient // -IpcClient::IpcClient(IEventQueue* events, SocketMultiplexer* socketMultiplexer) : - m_serverAddress(NetworkAddress(IPC_HOST, IPC_PORT)), - m_socket(events, socketMultiplexer), - m_server(nullptr), - m_events(events) -{ - init(); +IpcClient::IpcClient(IEventQueue *events, SocketMultiplexer *socketMultiplexer) + : m_serverAddress(NetworkAddress(IPC_HOST, IPC_PORT)), + m_socket(events, socketMultiplexer), m_server(nullptr), m_events(events) { + init(); } -IpcClient::IpcClient(IEventQueue* events, SocketMultiplexer* socketMultiplexer, int port) : - m_serverAddress(NetworkAddress(IPC_HOST, port)), - m_socket(events, socketMultiplexer), - m_server(nullptr), - m_events(events) -{ - init(); +IpcClient::IpcClient(IEventQueue *events, SocketMultiplexer *socketMultiplexer, + int port) + : m_serverAddress(NetworkAddress(IPC_HOST, port)), + m_socket(events, socketMultiplexer), m_server(nullptr), m_events(events) { + init(); } -void -IpcClient::init() -{ - m_serverAddress.resolve(); +void IpcClient::init() { m_serverAddress.resolve(); } + +IpcClient::~IpcClient() {} + +void IpcClient::connect() { + m_events->adoptHandler( + m_events->forIDataSocket().connected(), m_socket.getEventTarget(), + new TMethodEventJob(this, &IpcClient::handleConnected)); + + m_socket.connect(m_serverAddress); + m_server = new IpcServerProxy(m_socket, m_events); + + m_events->adoptHandler( + m_events->forIpcServerProxy().messageReceived(), m_server, + new TMethodEventJob(this, &IpcClient::handleMessageReceived)); } -IpcClient::~IpcClient() -{ +void IpcClient::disconnect() { + m_events->removeHandler(m_events->forIDataSocket().connected(), + m_socket.getEventTarget()); + m_events->removeHandler(m_events->forIpcServerProxy().messageReceived(), + m_server); + + m_server->disconnect(); + delete m_server; + m_server = nullptr; } -void -IpcClient::connect() -{ - m_events->adoptHandler( - m_events->forIDataSocket().connected(), m_socket.getEventTarget(), - new TMethodEventJob( - this, &IpcClient::handleConnected)); - - m_socket.connect(m_serverAddress); - m_server = new IpcServerProxy(m_socket, m_events); - - m_events->adoptHandler( - m_events->forIpcServerProxy().messageReceived(), m_server, - new TMethodEventJob( - this, &IpcClient::handleMessageReceived)); +void IpcClient::send(const IpcMessage &message) { + assert(m_server != nullptr); + m_server->send(message); } -void -IpcClient::disconnect() -{ - m_events->removeHandler(m_events->forIDataSocket().connected(), m_socket.getEventTarget()); - m_events->removeHandler(m_events->forIpcServerProxy().messageReceived(), m_server); +void IpcClient::handleConnected(const Event &, void *) { + m_events->addEvent(Event(m_events->forIpcClient().connected(), this, m_server, + Event::kDontFreeData)); - m_server->disconnect(); - delete m_server; - m_server = nullptr; + IpcHelloMessage message(kIpcClientNode); + send(message); } -void -IpcClient::send(const IpcMessage& message) -{ - assert(m_server != nullptr); - m_server->send(message); -} - -void -IpcClient::handleConnected(const Event&, void*) -{ - m_events->addEvent(Event( - m_events->forIpcClient().connected(), this, m_server, Event::kDontFreeData)); - - IpcHelloMessage message(kIpcClientNode); - send(message); -} - -void -IpcClient::handleMessageReceived(const Event& e, void*) -{ - Event event(m_events->forIpcClient().messageReceived(), this); - event.setDataObject(e.getDataObject()); - m_events->addEvent(event); +void IpcClient::handleMessageReceived(const Event &e, void *) { + Event event(m_events->forIpcClient().messageReceived(), this); + event.setDataObject(e.getDataObject()); + m_events->addEvent(event); } diff --git a/src/lib/ipc/IpcClient.h b/src/lib/ipc/IpcClient.h index fb31a26d5..b03667de1 100644 --- a/src/lib/ipc/IpcClient.h +++ b/src/lib/ipc/IpcClient.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2012 Nick Bolton - * + * * 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 LICENSE 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 @@ -18,9 +18,9 @@ #pragma once +#include "base/EventTypes.h" #include "net/NetworkAddress.h" #include "net/TCPSocket.h" -#include "base/EventTypes.h" class IpcServerProxy; class IpcMessage; @@ -33,32 +33,33 @@ class SocketMultiplexer; */ class IpcClient { public: - IpcClient(IEventQueue* events, SocketMultiplexer* socketMultiplexer); - IpcClient(IEventQueue* events, SocketMultiplexer* socketMultiplexer, int port); - virtual ~IpcClient(); + IpcClient(IEventQueue *events, SocketMultiplexer *socketMultiplexer); + IpcClient(IEventQueue *events, SocketMultiplexer *socketMultiplexer, + int port); + virtual ~IpcClient(); - //! @name manipulators - //@{ + //! @name manipulators + //@{ - //! Connects to the IPC server at localhost. - void connect(); - - //! Disconnects from the IPC server. - void disconnect(); + //! Connects to the IPC server at localhost. + void connect(); - //! Sends a message to the server. - void send(const IpcMessage& message); + //! Disconnects from the IPC server. + void disconnect(); - //@} + //! Sends a message to the server. + void send(const IpcMessage &message); + + //@} private: - void init(); - void handleConnected(const Event&, void*); - void handleMessageReceived(const Event&, void*); + void init(); + void handleConnected(const Event &, void *); + void handleMessageReceived(const Event &, void *); private: - NetworkAddress m_serverAddress; - TCPSocket m_socket; - IpcServerProxy* m_server; - IEventQueue* m_events; + NetworkAddress m_serverAddress; + TCPSocket m_socket; + IpcServerProxy *m_server; + IEventQueue *m_events; }; diff --git a/src/lib/ipc/IpcClientProxy.cpp b/src/lib/ipc/IpcClientProxy.cpp index a342c3e33..27d26096f 100644 --- a/src/lib/ipc/IpcClientProxy.cpp +++ b/src/lib/ipc/IpcClientProxy.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2012 Nick Bolton - * + * * 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 LICENSE 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 @@ -18,197 +18,173 @@ #include "ipc/IpcClientProxy.h" +#include "arch/Arch.h" +#include "base/Log.h" +#include "base/TMethodEventJob.h" +#include "io/IStream.h" #include "ipc/Ipc.h" #include "ipc/IpcMessage.h" #include "ipc/IpcSettingMessage.h" #include "synergy/ProtocolUtil.h" -#include "io/IStream.h" -#include "arch/Arch.h" -#include "base/TMethodEventJob.h" -#include "base/Log.h" // // IpcClientProxy // -IpcClientProxy::IpcClientProxy(synergy::IStream& stream, IEventQueue* events) : - m_stream(stream), - m_clientType(kIpcClientUnknown), - m_disconnecting(false), - m_readMutex(ARCH->newMutex()), - m_writeMutex(ARCH->newMutex()), - m_events(events) -{ - m_events->adoptHandler( - m_events->forIStream().inputReady(), stream.getEventTarget(), - new TMethodEventJob( - this, &IpcClientProxy::handleData)); +IpcClientProxy::IpcClientProxy(synergy::IStream &stream, IEventQueue *events) + : m_stream(stream), m_clientType(kIpcClientUnknown), m_disconnecting(false), + m_readMutex(ARCH->newMutex()), m_writeMutex(ARCH->newMutex()), + m_events(events) { + m_events->adoptHandler( + m_events->forIStream().inputReady(), stream.getEventTarget(), + new TMethodEventJob(this, &IpcClientProxy::handleData)); - m_events->adoptHandler( - m_events->forIStream().outputError(), stream.getEventTarget(), - new TMethodEventJob( - this, &IpcClientProxy::handleWriteError)); + m_events->adoptHandler(m_events->forIStream().outputError(), + stream.getEventTarget(), + new TMethodEventJob( + this, &IpcClientProxy::handleWriteError)); - m_events->adoptHandler( - m_events->forIStream().inputShutdown(), stream.getEventTarget(), - new TMethodEventJob( - this, &IpcClientProxy::handleDisconnect)); + m_events->adoptHandler(m_events->forIStream().inputShutdown(), + stream.getEventTarget(), + new TMethodEventJob( + this, &IpcClientProxy::handleDisconnect)); - m_events->adoptHandler( - m_events->forIStream().outputShutdown(), stream.getEventTarget(), - new TMethodEventJob( - this, &IpcClientProxy::handleWriteError)); + m_events->adoptHandler(m_events->forIStream().outputShutdown(), + stream.getEventTarget(), + new TMethodEventJob( + this, &IpcClientProxy::handleWriteError)); } -IpcClientProxy::~IpcClientProxy() -{ - m_events->removeHandler( - m_events->forIStream().inputReady(), m_stream.getEventTarget()); - m_events->removeHandler( - m_events->forIStream().outputError(), m_stream.getEventTarget()); - m_events->removeHandler( - m_events->forIStream().inputShutdown(), m_stream.getEventTarget()); - m_events->removeHandler( - m_events->forIStream().outputShutdown(), m_stream.getEventTarget()); - - // don't delete the stream while it's being used. - ARCH->lockMutex(m_readMutex); - ARCH->lockMutex(m_writeMutex); - delete &m_stream; - ARCH->unlockMutex(m_readMutex); - ARCH->unlockMutex(m_writeMutex); +IpcClientProxy::~IpcClientProxy() { + m_events->removeHandler(m_events->forIStream().inputReady(), + m_stream.getEventTarget()); + m_events->removeHandler(m_events->forIStream().outputError(), + m_stream.getEventTarget()); + m_events->removeHandler(m_events->forIStream().inputShutdown(), + m_stream.getEventTarget()); + m_events->removeHandler(m_events->forIStream().outputShutdown(), + m_stream.getEventTarget()); - ARCH->closeMutex(m_readMutex); - ARCH->closeMutex(m_writeMutex); + // don't delete the stream while it's being used. + ARCH->lockMutex(m_readMutex); + ARCH->lockMutex(m_writeMutex); + delete &m_stream; + ARCH->unlockMutex(m_readMutex); + ARCH->unlockMutex(m_writeMutex); + + ARCH->closeMutex(m_readMutex); + ARCH->closeMutex(m_writeMutex); } -void -IpcClientProxy::handleDisconnect(const Event&, void*) -{ - disconnect(); - LOG((CLOG_DEBUG "ipc client disconnected")); +void IpcClientProxy::handleDisconnect(const Event &, void *) { + disconnect(); + LOG((CLOG_DEBUG "ipc client disconnected")); } -void -IpcClientProxy::handleWriteError(const Event&, void*) -{ - disconnect(); - LOG((CLOG_DEBUG "ipc client write error")); +void IpcClientProxy::handleWriteError(const Event &, void *) { + disconnect(); + LOG((CLOG_DEBUG "ipc client write error")); } -void -IpcClientProxy::handleData(const Event&, void*) -{ - // don't allow the dtor to destroy the stream while we're using it. - ArchMutexLock lock(m_readMutex); +void IpcClientProxy::handleData(const Event &, void *) { + // don't allow the dtor to destroy the stream while we're using it. + ArchMutexLock lock(m_readMutex); - LOG((CLOG_DEBUG "start ipc handle data")); + LOG((CLOG_DEBUG "start ipc handle data")); - UInt8 code[4]; - UInt32 n = m_stream.read(code, 4); - while (n != 0) { + UInt8 code[4]; + UInt32 n = m_stream.read(code, 4); + while (n != 0) { - LOG((CLOG_DEBUG "ipc read: %c%c%c%c", - code[0], code[1], code[2], code[3])); + LOG((CLOG_DEBUG "ipc read: %c%c%c%c", code[0], code[1], code[2], code[3])); - IpcMessage* m = nullptr; - if (memcmp(code, kIpcMsgHello, 4) == 0) { - m = parseHello(); - } - else if (memcmp(code, kIpcMsgCommand, 4) == 0) { - m = parseCommand(); - } - else if (memcmp(code, kIpcMsgSetting, 4) == 0) { - m = parseSetting(); - } - else { - LOG((CLOG_ERR "invalid ipc message")); - disconnect(); - } - - // don't delete with this event; the data is passed to a new event. - Event e(m_events->forIpcClientProxy().messageReceived(), this, NULL, Event::kDontFreeData); - e.setDataObject(m); - m_events->addEvent(e); - - n = m_stream.read(code, 4); + IpcMessage *m = nullptr; + if (memcmp(code, kIpcMsgHello, 4) == 0) { + m = parseHello(); + } else if (memcmp(code, kIpcMsgCommand, 4) == 0) { + m = parseCommand(); + } else if (memcmp(code, kIpcMsgSetting, 4) == 0) { + m = parseSetting(); + } else { + LOG((CLOG_ERR "invalid ipc message")); + disconnect(); } - LOG((CLOG_DEBUG "finished ipc handle data")); + // don't delete with this event; the data is passed to a new event. + Event e(m_events->forIpcClientProxy().messageReceived(), this, NULL, + Event::kDontFreeData); + e.setDataObject(m); + m_events->addEvent(e); + + n = m_stream.read(code, 4); + } + + LOG((CLOG_DEBUG "finished ipc handle data")); } -void -IpcClientProxy::send(const IpcMessage& message) -{ - // don't allow other threads to write until we've finished the entire - // message. stream write is locked, but only for that single write. - // also, don't allow the dtor to destroy the stream while we're using it. - ArchMutexLock lock(m_writeMutex); +void IpcClientProxy::send(const IpcMessage &message) { + // don't allow other threads to write until we've finished the entire + // message. stream write is locked, but only for that single write. + // also, don't allow the dtor to destroy the stream while we're using it. + ArchMutexLock lock(m_writeMutex); - LOG((CLOG_DEBUG4 "ipc write: %d", message.type())); + LOG((CLOG_DEBUG4 "ipc write: %d", message.type())); - switch (message.type()) { - case kIpcLogLine: { - const IpcLogLineMessage& llm = static_cast(message); - const String logLine = llm.logLine(); - ProtocolUtil::writef(&m_stream, kIpcMsgLogLine, &logLine); - break; - } - - case kIpcShutdown: - ProtocolUtil::writef(&m_stream, kIpcMsgShutdown); - break; + switch (message.type()) { + case kIpcLogLine: { + const IpcLogLineMessage &llm = + static_cast(message); + const String logLine = llm.logLine(); + ProtocolUtil::writef(&m_stream, kIpcMsgLogLine, &logLine); + break; + } - case kIpcHelloBack: - ProtocolUtil::writef(&m_stream, kIpcMsgHelloBack); - break; + case kIpcShutdown: + ProtocolUtil::writef(&m_stream, kIpcMsgShutdown); + break; - default: - LOG((CLOG_ERR "ipc message not supported: %d", message.type())); - break; - } + case kIpcHelloBack: + ProtocolUtil::writef(&m_stream, kIpcMsgHelloBack); + break; + + default: + LOG((CLOG_ERR "ipc message not supported: %d", message.type())); + break; + } } -IpcHelloMessage* -IpcClientProxy::parseHello() -{ - UInt8 type; - ProtocolUtil::readf(&m_stream, kIpcMsgHello + 4, &type); +IpcHelloMessage *IpcClientProxy::parseHello() { + UInt8 type; + ProtocolUtil::readf(&m_stream, kIpcMsgHello + 4, &type); - m_clientType = static_cast(type); + m_clientType = static_cast(type); - // must be deleted by event handler. - return new IpcHelloMessage(m_clientType); + // must be deleted by event handler. + return new IpcHelloMessage(m_clientType); } -IpcCommandMessage* -IpcClientProxy::parseCommand() -{ - String command; - UInt8 elevate; - ProtocolUtil::readf(&m_stream, kIpcMsgCommand + 4, &command, &elevate); +IpcCommandMessage *IpcClientProxy::parseCommand() { + String command; + UInt8 elevate; + ProtocolUtil::readf(&m_stream, kIpcMsgCommand + 4, &command, &elevate); - // must be deleted by event handler. - return new IpcCommandMessage(command, elevate != 0); + // must be deleted by event handler. + return new IpcCommandMessage(command, elevate != 0); } -IpcSettingMessage* -IpcClientProxy::parseSetting() const -{ - String name; - String value; +IpcSettingMessage *IpcClientProxy::parseSetting() const { + String name; + String value; - ProtocolUtil::readf(&m_stream, kIpcMsgSetting + 4, &name, &value); + ProtocolUtil::readf(&m_stream, kIpcMsgSetting + 4, &name, &value); - // must be deleted by event handler. - return new IpcSettingMessage(name, value); + // must be deleted by event handler. + return new IpcSettingMessage(name, value); } -void -IpcClientProxy::disconnect() -{ - LOG((CLOG_DEBUG "ipc disconnect, closing stream")); - m_disconnecting = true; - m_stream.close(); - m_events->addEvent(Event(m_events->forIpcClientProxy().disconnected(), this)); +void IpcClientProxy::disconnect() { + LOG((CLOG_DEBUG "ipc disconnect, closing stream")); + m_disconnecting = true; + m_stream.close(); + m_events->addEvent(Event(m_events->forIpcClientProxy().disconnected(), this)); } diff --git a/src/lib/ipc/IpcClientProxy.h b/src/lib/ipc/IpcClientProxy.h index 09691f171..4b61900da 100644 --- a/src/lib/ipc/IpcClientProxy.h +++ b/src/lib/ipc/IpcClientProxy.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2012 Nick Bolton - * + * * 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 LICENSE 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 @@ -18,12 +18,14 @@ #pragma once -#include "ipc/Ipc.h" #include "arch/IArchMultithread.h" -#include "base/EventTypes.h" #include "base/Event.h" +#include "base/EventTypes.h" +#include "ipc/Ipc.h" -namespace synergy { class IStream; } +namespace synergy { +class IStream; +} class IpcMessage; class IpcCommandMessage; class IpcSettingMessage; @@ -31,32 +33,32 @@ class IpcHelloMessage; class IEventQueue; class IpcClientProxy { - friend class IpcServer; + friend class IpcServer; public: - IpcClientProxy(synergy::IStream& stream, IEventQueue* events); - IpcClientProxy(IpcClientProxy const &) =delete; - IpcClientProxy(IpcClientProxy &&) =delete; - virtual ~IpcClientProxy(); + IpcClientProxy(synergy::IStream &stream, IEventQueue *events); + IpcClientProxy(IpcClientProxy const &) = delete; + IpcClientProxy(IpcClientProxy &&) = delete; + virtual ~IpcClientProxy(); - IpcClientProxy& operator=(IpcClientProxy const &) =delete; - IpcClientProxy& operator=(IpcClientProxy &&) =delete; + IpcClientProxy &operator=(IpcClientProxy const &) = delete; + IpcClientProxy &operator=(IpcClientProxy &&) = delete; private: - void send(const IpcMessage& message); - void handleData(const Event&, void*); - void handleDisconnect(const Event&, void*); - void handleWriteError(const Event&, void*); - IpcHelloMessage* parseHello(); - IpcCommandMessage* parseCommand(); - IpcSettingMessage* parseSetting() const; - void disconnect(); - + void send(const IpcMessage &message); + void handleData(const Event &, void *); + void handleDisconnect(const Event &, void *); + void handleWriteError(const Event &, void *); + IpcHelloMessage *parseHello(); + IpcCommandMessage *parseCommand(); + IpcSettingMessage *parseSetting() const; + void disconnect(); + private: - synergy::IStream& m_stream; - EIpcClientType m_clientType; - bool m_disconnecting; - ArchMutex m_readMutex; - ArchMutex m_writeMutex; - IEventQueue* m_events; + synergy::IStream &m_stream; + EIpcClientType m_clientType; + bool m_disconnecting; + ArchMutex m_readMutex; + ArchMutex m_writeMutex; + IEventQueue *m_events; }; diff --git a/src/lib/ipc/IpcLogOutputter.cpp b/src/lib/ipc/IpcLogOutputter.cpp index 120fd66f5..be9a8c5af 100644 --- a/src/lib/ipc/IpcLogOutputter.cpp +++ b/src/lib/ipc/IpcLogOutputter.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2012 Nick Bolton - * + * * 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 LICENSE 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 @@ -18,211 +18,171 @@ #include "ipc/IpcLogOutputter.h" -#include "ipc/IpcServer.h" -#include "ipc/IpcMessage.h" -#include "ipc/Ipc.h" -#include "ipc/IpcClientProxy.h" -#include "mt/Thread.h" #include "arch/Arch.h" #include "arch/XArch.h" #include "base/Event.h" #include "base/EventQueue.h" #include "base/TMethodEventJob.h" #include "base/TMethodJob.h" +#include "ipc/Ipc.h" +#include "ipc/IpcClientProxy.h" +#include "ipc/IpcMessage.h" +#include "ipc/IpcServer.h" +#include "mt/Thread.h" enum EIpcLogOutputter { - kBufferMaxSize = 1000, - kMaxSendLines = 100, - kBufferRateWriteLimit = 1000, // writes per kBufferRateTime - kBufferRateTimeLimit = 1 // seconds + kBufferMaxSize = 1000, + kMaxSendLines = 100, + kBufferRateWriteLimit = 1000, // writes per kBufferRateTime + kBufferRateTimeLimit = 1 // seconds }; -IpcLogOutputter::IpcLogOutputter(IpcServer& ipcServer, EIpcClientType clientType, bool useThread) : - m_ipcServer(ipcServer), - m_bufferMutex(ARCH->newMutex()), - m_sending(false), - m_bufferThread(nullptr), - m_running(false), - m_notifyCond(ARCH->newCondVar()), - m_notifyMutex(ARCH->newMutex()), - m_bufferThreadId(0), - m_bufferWaiting(false), - m_bufferMaxSize(kBufferMaxSize), - m_bufferRateWriteLimit(kBufferRateWriteLimit), - m_bufferRateTimeLimit(kBufferRateTimeLimit), - m_bufferWriteCount(0), - m_bufferRateStart(ARCH->time()), - m_clientType(clientType), - m_runningMutex(ARCH->newMutex()) -{ - if (useThread) { - m_bufferThread = new Thread(new TMethodJob( - this, &IpcLogOutputter::bufferThread)); - } +IpcLogOutputter::IpcLogOutputter(IpcServer &ipcServer, + EIpcClientType clientType, bool useThread) + : m_ipcServer(ipcServer), m_bufferMutex(ARCH->newMutex()), m_sending(false), + m_bufferThread(nullptr), m_running(false), + m_notifyCond(ARCH->newCondVar()), m_notifyMutex(ARCH->newMutex()), + m_bufferThreadId(0), m_bufferWaiting(false), + m_bufferMaxSize(kBufferMaxSize), + m_bufferRateWriteLimit(kBufferRateWriteLimit), + m_bufferRateTimeLimit(kBufferRateTimeLimit), m_bufferWriteCount(0), + m_bufferRateStart(ARCH->time()), m_clientType(clientType), + m_runningMutex(ARCH->newMutex()) { + if (useThread) { + m_bufferThread = new Thread( + new TMethodJob(this, &IpcLogOutputter::bufferThread)); + } } -IpcLogOutputter::~IpcLogOutputter() -{ - close(); +IpcLogOutputter::~IpcLogOutputter() { + close(); - ARCH->closeMutex(m_bufferMutex); + ARCH->closeMutex(m_bufferMutex); - if (m_bufferThread != nullptr) { - m_bufferThread->cancel(); - m_bufferThread->wait(); - delete m_bufferThread; - } + if (m_bufferThread != nullptr) { + m_bufferThread->cancel(); + m_bufferThread->wait(); + delete m_bufferThread; + } - ARCH->closeCondVar(m_notifyCond); - ARCH->closeMutex(m_notifyMutex); + ARCH->closeCondVar(m_notifyCond); + ARCH->closeMutex(m_notifyMutex); } -void -IpcLogOutputter::open(const char* title) -{ -} +void IpcLogOutputter::open(const char *title) {} -void -IpcLogOutputter::close() -{ - if (m_bufferThread != nullptr) { - ArchMutexLock lock(m_runningMutex); - m_running = false; - notifyBuffer(); - m_bufferThread->wait(5); - } -} - -void -IpcLogOutputter::show(bool showIfEmpty) -{ -} - -bool -IpcLogOutputter::write(ELevel, const char* text) -{ - // ignore events from the buffer thread (would cause recursion). - if (m_bufferThread != nullptr && - Thread::getCurrentThread().getID() == m_bufferThreadId) { - return true; - } - - appendBuffer(text); - notifyBuffer(); - - return true; -} - -void -IpcLogOutputter::appendBuffer(const String& text) -{ - ArchMutexLock lock(m_bufferMutex); - - double elapsed = ARCH->time() - m_bufferRateStart; - if (elapsed < m_bufferRateTimeLimit) { - if (m_bufferWriteCount >= m_bufferRateWriteLimit) { - // discard the log line if we've logged too much. - return; - } - } - else { - m_bufferWriteCount = 0; - m_bufferRateStart = ARCH->time(); - } - - if (m_buffer.size() >= m_bufferMaxSize) { - // if the queue is exceeds size limit, - // throw away the oldest item - m_buffer.pop_front(); - } - - m_buffer.push_back(text); - m_bufferWriteCount++; -} - -bool -IpcLogOutputter::isRunning() -{ +void IpcLogOutputter::close() { + if (m_bufferThread != nullptr) { ArchMutexLock lock(m_runningMutex); - return m_running; + m_running = false; + notifyBuffer(); + m_bufferThread->wait(5); + } } -void -IpcLogOutputter::bufferThread(void*) -{ - m_bufferThreadId = m_bufferThread->getID(); - m_running = true; +void IpcLogOutputter::show(bool showIfEmpty) {} - try { - while (isRunning()) { - if (m_buffer.empty() || !m_ipcServer.hasClients(m_clientType)) { - ArchMutexLock lock(m_notifyMutex); - ARCH->waitCondVar(m_notifyCond, m_notifyMutex, -1); - } +bool IpcLogOutputter::write(ELevel, const char *text) { + // ignore events from the buffer thread (would cause recursion). + if (m_bufferThread != nullptr && + Thread::getCurrentThread().getID() == m_bufferThreadId) { + return true; + } - sendBuffer(); - } + appendBuffer(text); + notifyBuffer(); + + return true; +} + +void IpcLogOutputter::appendBuffer(const String &text) { + ArchMutexLock lock(m_bufferMutex); + + double elapsed = ARCH->time() - m_bufferRateStart; + if (elapsed < m_bufferRateTimeLimit) { + if (m_bufferWriteCount >= m_bufferRateWriteLimit) { + // discard the log line if we've logged too much. + return; } - catch (XArch& e) { - LOG((CLOG_ERR "ipc log buffer thread error, %s", e.what())); + } else { + m_bufferWriteCount = 0; + m_bufferRateStart = ARCH->time(); + } + + if (m_buffer.size() >= m_bufferMaxSize) { + // if the queue is exceeds size limit, + // throw away the oldest item + m_buffer.pop_front(); + } + + m_buffer.push_back(text); + m_bufferWriteCount++; +} + +bool IpcLogOutputter::isRunning() { + ArchMutexLock lock(m_runningMutex); + return m_running; +} + +void IpcLogOutputter::bufferThread(void *) { + m_bufferThreadId = m_bufferThread->getID(); + m_running = true; + + try { + while (isRunning()) { + if (m_buffer.empty() || !m_ipcServer.hasClients(m_clientType)) { + ArchMutexLock lock(m_notifyMutex); + ARCH->waitCondVar(m_notifyCond, m_notifyMutex, -1); + } + + sendBuffer(); } + } catch (XArch &e) { + LOG((CLOG_ERR "ipc log buffer thread error, %s", e.what())); + } - LOG((CLOG_DEBUG "ipc log buffer thread finished")); + LOG((CLOG_DEBUG "ipc log buffer thread finished")); } -void -IpcLogOutputter::notifyBuffer() -{ - ArchMutexLock lock(m_notifyMutex); - ARCH->broadcastCondVar(m_notifyCond); +void IpcLogOutputter::notifyBuffer() { + ArchMutexLock lock(m_notifyMutex); + ARCH->broadcastCondVar(m_notifyCond); } -String -IpcLogOutputter::getChunk(size_t count) -{ - ArchMutexLock lock(m_bufferMutex); +String IpcLogOutputter::getChunk(size_t count) { + ArchMutexLock lock(m_bufferMutex); - if (m_buffer.size() < count) { - count = m_buffer.size(); - } + if (m_buffer.size() < count) { + count = m_buffer.size(); + } - String chunk; - for (size_t i = 0; i < count; i++) { - chunk.append(m_buffer.front()); - chunk.append("\n"); - m_buffer.pop_front(); - } - return chunk; + String chunk; + for (size_t i = 0; i < count; i++) { + chunk.append(m_buffer.front()); + chunk.append("\n"); + m_buffer.pop_front(); + } + return chunk; } -void -IpcLogOutputter::sendBuffer() -{ - if (m_buffer.empty() || !m_ipcServer.hasClients(m_clientType)) { - return; - } +void IpcLogOutputter::sendBuffer() { + if (m_buffer.empty() || !m_ipcServer.hasClients(m_clientType)) { + return; + } - IpcLogLineMessage message(getChunk(kMaxSendLines)); - m_sending = true; - m_ipcServer.send(message, kIpcClientGui); - m_sending = false; + IpcLogLineMessage message(getChunk(kMaxSendLines)); + m_sending = true; + m_ipcServer.send(message, kIpcClientGui); + m_sending = false; } -void -IpcLogOutputter::bufferMaxSize(UInt16 bufferMaxSize) -{ - m_bufferMaxSize = bufferMaxSize; +void IpcLogOutputter::bufferMaxSize(UInt16 bufferMaxSize) { + m_bufferMaxSize = bufferMaxSize; } -UInt16 -IpcLogOutputter::bufferMaxSize() const -{ - return m_bufferMaxSize; -} +UInt16 IpcLogOutputter::bufferMaxSize() const { return m_bufferMaxSize; } -void -IpcLogOutputter::bufferRateLimit(UInt16 writeLimit, double timeLimit) -{ - m_bufferRateWriteLimit = writeLimit; - m_bufferRateTimeLimit = timeLimit; +void IpcLogOutputter::bufferRateLimit(UInt16 writeLimit, double timeLimit) { + m_bufferRateWriteLimit = writeLimit; + m_bufferRateTimeLimit = timeLimit; } diff --git a/src/lib/ipc/IpcLogOutputter.h b/src/lib/ipc/IpcLogOutputter.h index 15c00ad79..bc985776c 100644 --- a/src/lib/ipc/IpcLogOutputter.h +++ b/src/lib/ipc/IpcLogOutputter.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2012 Nick Bolton - * + * * 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 LICENSE 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 @@ -35,86 +35,86 @@ This outputter writes output to the GUI via IPC. */ class IpcLogOutputter : public ILogOutputter { public: - /*! - If \p useThread is \c true, the buffer will be sent using a thread. - If \p useThread is \c false, then the buffer needs to be sent manually - using the \c sendBuffer() function. - */ - IpcLogOutputter(IpcServer& ipcServer, EIpcClientType clientType, bool useThread); - IpcLogOutputter(IpcLogOutputter const &) =delete; - virtual ~IpcLogOutputter(); + /*! + If \p useThread is \c true, the buffer will be sent using a thread. + If \p useThread is \c false, then the buffer needs to be sent manually + using the \c sendBuffer() function. + */ + IpcLogOutputter(IpcServer &ipcServer, EIpcClientType clientType, + bool useThread); + IpcLogOutputter(IpcLogOutputter const &) = delete; + virtual ~IpcLogOutputter(); - // ILogOutputter overrides - virtual void open(const char* title); - virtual void close(); - virtual void show(bool showIfEmpty); - virtual bool write(ELevel level, const char* message); - - //! @name manipulators - //@{ + // ILogOutputter overrides + virtual void open(const char *title); + virtual void close(); + virtual void show(bool showIfEmpty); + virtual bool write(ELevel level, const char *message); - //! Notify that the buffer should be sent. - void notifyBuffer(); + //! @name manipulators + //@{ - //! Set the buffer size - /*! - Set the maximum size of the buffer to protect memory - from runaway logging. - */ - void bufferMaxSize(UInt16 bufferMaxSize); + //! Notify that the buffer should be sent. + void notifyBuffer(); - //! Set the rate limit - /*! - Set the maximum number of \p writeRate for every \p timeRate in seconds. - */ - void bufferRateLimit(UInt16 writeLimit, double timeLimit); + //! Set the buffer size + /*! + Set the maximum size of the buffer to protect memory + from runaway logging. + */ + void bufferMaxSize(UInt16 bufferMaxSize); - //! Send the buffer - /*! - Sends a chunk of the buffer to the IPC server, normally called - when threaded mode is on. - */ - void sendBuffer(); - - //@} - - //! @name accessors - //@{ - - //! Get the buffer size - /*! - Returns the maximum size of the buffer. - */ - UInt16 bufferMaxSize() const; - - //@} + //! Set the rate limit + /*! + Set the maximum number of \p writeRate for every \p timeRate in seconds. + */ + void bufferRateLimit(UInt16 writeLimit, double timeLimit); + + //! Send the buffer + /*! + Sends a chunk of the buffer to the IPC server, normally called + when threaded mode is on. + */ + void sendBuffer(); + + //@} + + //! @name accessors + //@{ + + //! Get the buffer size + /*! + Returns the maximum size of the buffer. + */ + UInt16 bufferMaxSize() const; + + //@} private: - void init(); - void bufferThread(void*); - String getChunk(size_t count); - void appendBuffer(const String& text); - bool isRunning(); + void init(); + void bufferThread(void *); + String getChunk(size_t count); + void appendBuffer(const String &text); + bool isRunning(); private: - typedef std::deque Buffer; + typedef std::deque Buffer; - IpcServer& m_ipcServer; - Buffer m_buffer; - ArchMutex m_bufferMutex; - bool m_sending; - Thread* m_bufferThread; - bool m_running; - ArchCond m_notifyCond; - ArchMutex m_notifyMutex; - bool m_bufferWaiting; - IArchMultithread::ThreadID - m_bufferThreadId; - UInt16 m_bufferMaxSize; - UInt16 m_bufferRateWriteLimit; - double m_bufferRateTimeLimit; - UInt16 m_bufferWriteCount; - double m_bufferRateStart; - EIpcClientType m_clientType; - ArchMutex m_runningMutex; + IpcServer &m_ipcServer; + Buffer m_buffer; + ArchMutex m_bufferMutex; + bool m_sending; + Thread *m_bufferThread; + bool m_running; + ArchCond m_notifyCond; + ArchMutex m_notifyMutex; + bool m_bufferWaiting; + IArchMultithread::ThreadID m_bufferThreadId; + UInt16 m_bufferMaxSize; + UInt16 m_bufferRateWriteLimit; + double m_bufferRateTimeLimit; + UInt16 m_bufferWriteCount; + double m_bufferRateStart; + EIpcClientType m_clientType; + ArchMutex m_runningMutex; }; diff --git a/src/lib/ipc/IpcMessage.cpp b/src/lib/ipc/IpcMessage.cpp index 05a2bda7c..5aef66f5d 100644 --- a/src/lib/ipc/IpcMessage.cpp +++ b/src/lib/ipc/IpcMessage.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2012 Nick Bolton - * + * * 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 LICENSE 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 @@ -19,60 +19,29 @@ #include "ipc/IpcMessage.h" #include "ipc/Ipc.h" -IpcMessage::IpcMessage(UInt8 type) : - m_type(type) -{ -} +IpcMessage::IpcMessage(UInt8 type) : m_type(type) {} -IpcMessage::~IpcMessage() -{ -} +IpcMessage::~IpcMessage() {} -IpcHelloMessage::IpcHelloMessage(EIpcClientType clientType) : - IpcMessage(kIpcHello), - m_clientType(clientType) -{ -} +IpcHelloMessage::IpcHelloMessage(EIpcClientType clientType) + : IpcMessage(kIpcHello), m_clientType(clientType) {} -IpcHelloMessage::~IpcHelloMessage() -{ -} +IpcHelloMessage::~IpcHelloMessage() {} -IpcHelloBackMessage::IpcHelloBackMessage() : - IpcMessage(kIpcHelloBack) -{ -} +IpcHelloBackMessage::IpcHelloBackMessage() : IpcMessage(kIpcHelloBack) {} -IpcHelloBackMessage::~IpcHelloBackMessage() -{ -} +IpcHelloBackMessage::~IpcHelloBackMessage() {} -IpcShutdownMessage::IpcShutdownMessage() : -IpcMessage(kIpcShutdown) -{ -} +IpcShutdownMessage::IpcShutdownMessage() : IpcMessage(kIpcShutdown) {} -IpcShutdownMessage::~IpcShutdownMessage() -{ -} +IpcShutdownMessage::~IpcShutdownMessage() {} -IpcLogLineMessage::IpcLogLineMessage(const String& logLine) : -IpcMessage(kIpcLogLine), -m_logLine(logLine) -{ -} +IpcLogLineMessage::IpcLogLineMessage(const String &logLine) + : IpcMessage(kIpcLogLine), m_logLine(logLine) {} -IpcLogLineMessage::~IpcLogLineMessage() -{ -} +IpcLogLineMessage::~IpcLogLineMessage() {} -IpcCommandMessage::IpcCommandMessage(const String& command, bool elevate) : -IpcMessage(kIpcCommand), -m_command(command), -m_elevate(elevate) -{ -} +IpcCommandMessage::IpcCommandMessage(const String &command, bool elevate) + : IpcMessage(kIpcCommand), m_command(command), m_elevate(elevate) {} -IpcCommandMessage::~IpcCommandMessage() -{ -} +IpcCommandMessage::~IpcCommandMessage() {} diff --git a/src/lib/ipc/IpcMessage.h b/src/lib/ipc/IpcMessage.h index d9d1889b4..a10a4647c 100644 --- a/src/lib/ipc/IpcMessage.h +++ b/src/lib/ipc/IpcMessage.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2012 Nick Bolton - * + * * 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 LICENSE 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 @@ -18,74 +18,73 @@ #pragma once -#include "ipc/Ipc.h" +#include "base/Event.h" #include "base/EventTypes.h" #include "base/String.h" -#include "base/Event.h" +#include "ipc/Ipc.h" class IpcMessage : public EventData { public: - virtual ~IpcMessage(); + virtual ~IpcMessage(); - //! Gets the message type ID. - UInt8 type() const { return m_type; } + //! Gets the message type ID. + UInt8 type() const { return m_type; } protected: - IpcMessage(UInt8 type); + IpcMessage(UInt8 type); private: - UInt8 m_type; + UInt8 m_type; }; class IpcHelloMessage : public IpcMessage { public: - IpcHelloMessage(EIpcClientType clientType); - virtual ~IpcHelloMessage(); + IpcHelloMessage(EIpcClientType clientType); + virtual ~IpcHelloMessage(); - //! Gets the message type ID. - EIpcClientType clientType() const { return m_clientType; } + //! Gets the message type ID. + EIpcClientType clientType() const { return m_clientType; } private: - EIpcClientType m_clientType; + EIpcClientType m_clientType; }; class IpcHelloBackMessage : public IpcMessage { public: - IpcHelloBackMessage(); - virtual ~IpcHelloBackMessage(); + IpcHelloBackMessage(); + virtual ~IpcHelloBackMessage(); }; class IpcShutdownMessage : public IpcMessage { public: - IpcShutdownMessage(); - virtual ~IpcShutdownMessage(); + IpcShutdownMessage(); + virtual ~IpcShutdownMessage(); }; - class IpcLogLineMessage : public IpcMessage { public: - IpcLogLineMessage(const String& logLine); - virtual ~IpcLogLineMessage(); + IpcLogLineMessage(const String &logLine); + virtual ~IpcLogLineMessage(); - //! Gets the log line. - String logLine() const { return m_logLine; } + //! Gets the log line. + String logLine() const { return m_logLine; } private: - String m_logLine; + String m_logLine; }; class IpcCommandMessage : public IpcMessage { public: - IpcCommandMessage(const String& command, bool elevate); - virtual ~IpcCommandMessage(); + IpcCommandMessage(const String &command, bool elevate); + virtual ~IpcCommandMessage(); - //! Gets the command. - String command() const { return m_command; } + //! Gets the command. + String command() const { return m_command; } - //! Gets whether or not the process should be elevated on MS Windows. - bool elevate() const { return m_elevate; } + //! Gets whether or not the process should be elevated on MS Windows. + bool elevate() const { return m_elevate; } private: - String m_command; - bool m_elevate; + String m_command; + bool m_elevate; }; diff --git a/src/lib/ipc/IpcServer.cpp b/src/lib/ipc/IpcServer.cpp index e285a3843..c055ebffd 100644 --- a/src/lib/ipc/IpcServer.cpp +++ b/src/lib/ipc/IpcServer.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2012 Nick Bolton - * + * * 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 LICENSE 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 @@ -18,170 +18,144 @@ #include "ipc/IpcServer.h" +#include "base/Event.h" +#include "base/IEventQueue.h" +#include "base/Log.h" +#include "base/TMethodEventJob.h" +#include "io/IStream.h" #include "ipc/Ipc.h" #include "ipc/IpcClientProxy.h" #include "ipc/IpcMessage.h" #include "net/IDataSocket.h" -#include "io/IStream.h" -#include "base/IEventQueue.h" -#include "base/TMethodEventJob.h" -#include "base/Event.h" -#include "base/Log.h" // // IpcServer // -IpcServer::IpcServer(IEventQueue* events, SocketMultiplexer* socketMultiplexer) : - m_mock(false), - m_events(events), - m_socketMultiplexer(socketMultiplexer), - m_socket(nullptr), - m_address(NetworkAddress(IPC_HOST, IPC_PORT)) -{ - init(); +IpcServer::IpcServer(IEventQueue *events, SocketMultiplexer *socketMultiplexer) + : m_mock(false), m_events(events), m_socketMultiplexer(socketMultiplexer), + m_socket(nullptr), m_address(NetworkAddress(IPC_HOST, IPC_PORT)) { + init(); } -IpcServer::IpcServer(IEventQueue* events, SocketMultiplexer* socketMultiplexer, int port) : - m_mock(false), - m_events(events), - m_socketMultiplexer(socketMultiplexer), - m_address(NetworkAddress(IPC_HOST, port)) -{ - init(); +IpcServer::IpcServer(IEventQueue *events, SocketMultiplexer *socketMultiplexer, + int port) + : m_mock(false), m_events(events), m_socketMultiplexer(socketMultiplexer), + m_address(NetworkAddress(IPC_HOST, port)) { + init(); } -void -IpcServer::init() -{ - m_socket = new TCPListenSocket(m_events, m_socketMultiplexer, IArchNetwork::EAddressFamily::kINET); +void IpcServer::init() { + m_socket = new TCPListenSocket(m_events, m_socketMultiplexer, + IArchNetwork::EAddressFamily::kINET); - m_clientsMutex = ARCH->newMutex(); - m_address.resolve(); + m_clientsMutex = ARCH->newMutex(); + m_address.resolve(); - m_events->adoptHandler( - m_events->forIListenSocket().connecting(), m_socket, - new TMethodEventJob( - this, &IpcServer::handleClientConnecting)); + m_events->adoptHandler( + m_events->forIListenSocket().connecting(), m_socket, + new TMethodEventJob(this, &IpcServer::handleClientConnecting)); } -IpcServer::~IpcServer() -{ - if (m_mock) { - return; - } +IpcServer::~IpcServer() { + if (m_mock) { + return; + } - if (m_socket != nullptr) { - delete m_socket; - } + if (m_socket != nullptr) { + delete m_socket; + } - ARCH->lockMutex(m_clientsMutex); - ClientList::iterator it; - for (it = m_clients.begin(); it != m_clients.end(); it++) { - deleteClient(*it); - } - m_clients.clear(); - ARCH->unlockMutex(m_clientsMutex); - ARCH->closeMutex(m_clientsMutex); - - m_events->removeHandler(m_events->forIListenSocket().connecting(), m_socket); + ARCH->lockMutex(m_clientsMutex); + ClientList::iterator it; + for (it = m_clients.begin(); it != m_clients.end(); it++) { + deleteClient(*it); + } + m_clients.clear(); + ARCH->unlockMutex(m_clientsMutex); + ARCH->closeMutex(m_clientsMutex); + + m_events->removeHandler(m_events->forIListenSocket().connecting(), m_socket); } -void -IpcServer::listen() -{ - m_socket->bind(m_address); +void IpcServer::listen() { m_socket->bind(m_address); } + +void IpcServer::handleClientConnecting(const Event &, void *) { + synergy::IStream *stream = m_socket->accept(); + if (stream == NULL) { + return; + } + + LOG((CLOG_DEBUG "accepted ipc client connection")); + + ARCH->lockMutex(m_clientsMutex); + IpcClientProxy *proxy = new IpcClientProxy(*stream, m_events); + m_clients.push_back(proxy); + ARCH->unlockMutex(m_clientsMutex); + + m_events->adoptHandler(m_events->forIpcClientProxy().disconnected(), proxy, + new TMethodEventJob( + this, &IpcServer::handleClientDisconnected)); + + m_events->adoptHandler( + m_events->forIpcClientProxy().messageReceived(), proxy, + new TMethodEventJob(this, &IpcServer::handleMessageReceived)); + + m_events->addEvent(Event(m_events->forIpcServer().clientConnected(), this, + proxy, Event::kDontFreeData)); } -void -IpcServer::handleClientConnecting(const Event&, void*) -{ - synergy::IStream* stream = m_socket->accept(); - if (stream == NULL) { - return; - } +void IpcServer::handleClientDisconnected(const Event &e, void *) { + IpcClientProxy *proxy = static_cast(e.getTarget()); - LOG((CLOG_DEBUG "accepted ipc client connection")); + ArchMutexLock lock(m_clientsMutex); + m_clients.remove(proxy); + deleteClient(proxy); - ARCH->lockMutex(m_clientsMutex); - IpcClientProxy* proxy = new IpcClientProxy(*stream, m_events); - m_clients.push_back(proxy); - ARCH->unlockMutex(m_clientsMutex); - - m_events->adoptHandler( - m_events->forIpcClientProxy().disconnected(), proxy, - new TMethodEventJob( - this, &IpcServer::handleClientDisconnected)); - - m_events->adoptHandler( - m_events->forIpcClientProxy().messageReceived(), proxy, - new TMethodEventJob( - this, &IpcServer::handleMessageReceived)); - - m_events->addEvent(Event( - m_events->forIpcServer().clientConnected(), this, proxy, Event::kDontFreeData)); + LOG((CLOG_DEBUG "ipc client proxy removed, connected=%d", m_clients.size())); } -void -IpcServer::handleClientDisconnected(const Event& e, void*) -{ - IpcClientProxy* proxy = static_cast(e.getTarget()); - - ArchMutexLock lock(m_clientsMutex); - m_clients.remove(proxy); - deleteClient(proxy); - - LOG((CLOG_DEBUG "ipc client proxy removed, connected=%d", m_clients.size())); +void IpcServer::handleMessageReceived(const Event &e, void *) { + Event event(m_events->forIpcServer().messageReceived(), this); + event.setDataObject(e.getDataObject()); + m_events->addEvent(event); } -void -IpcServer::handleMessageReceived(const Event& e, void*) -{ - Event event(m_events->forIpcServer().messageReceived(), this); - event.setDataObject(e.getDataObject()); - m_events->addEvent(event); +void IpcServer::deleteClient(IpcClientProxy *proxy) { + m_events->removeHandler(m_events->forIpcClientProxy().messageReceived(), + proxy); + m_events->removeHandler(m_events->forIpcClientProxy().disconnected(), proxy); + delete proxy; } -void -IpcServer::deleteClient(IpcClientProxy* proxy) -{ - m_events->removeHandler(m_events->forIpcClientProxy().messageReceived(), proxy); - m_events->removeHandler(m_events->forIpcClientProxy().disconnected(), proxy); - delete proxy; -} +bool IpcServer::hasClients(EIpcClientType clientType) const { + ArchMutexLock lock(m_clientsMutex); -bool -IpcServer::hasClients(EIpcClientType clientType) const -{ - ArchMutexLock lock(m_clientsMutex); - - if (m_clients.empty()) { - return false; - } - - ClientList::const_iterator it; - for (it = m_clients.begin(); it != m_clients.end(); it++) { - // at least one client is alive and type matches, there are clients. - IpcClientProxy* p = *it; - if (!p->m_disconnecting && p->m_clientType == clientType) { - return true; - } - } - - // all clients must be disconnecting, no active clients. + if (m_clients.empty()) { return false; -} + } -void -IpcServer::send(const IpcMessage& message, EIpcClientType filterType) -{ - ArchMutexLock lock(m_clientsMutex); - - ClientList::iterator it; - for (it = m_clients.begin(); it != m_clients.end(); it++) { - IpcClientProxy* proxy = *it; - if (proxy->m_clientType == filterType) { - proxy->send(message); - } + ClientList::const_iterator it; + for (it = m_clients.begin(); it != m_clients.end(); it++) { + // at least one client is alive and type matches, there are clients. + IpcClientProxy *p = *it; + if (!p->m_disconnecting && p->m_clientType == clientType) { + return true; } + } + + // all clients must be disconnecting, no active clients. + return false; +} + +void IpcServer::send(const IpcMessage &message, EIpcClientType filterType) { + ArchMutexLock lock(m_clientsMutex); + + ClientList::iterator it; + for (it = m_clients.begin(); it != m_clients.end(); it++) { + IpcClientProxy *proxy = *it; + if (proxy->m_clientType == filterType) { + proxy->send(message); + } + } } diff --git a/src/lib/ipc/IpcServer.h b/src/lib/ipc/IpcServer.h index 1944bfbe4..0f235ea99 100644 --- a/src/lib/ipc/IpcServer.h +++ b/src/lib/ipc/IpcServer.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2012 Nick Bolton - * + * * 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 LICENSE 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 @@ -18,11 +18,11 @@ #pragma once -#include "ipc/Ipc.h" -#include "net/TCPListenSocket.h" -#include "net/NetworkAddress.h" #include "arch/Arch.h" #include "base/EventTypes.h" +#include "ipc/Ipc.h" +#include "net/NetworkAddress.h" +#include "net/TCPListenSocket.h" #include @@ -41,57 +41,56 @@ and allows the daemon and client/server to send log data to the GUI. */ class IpcServer { public: - IpcServer(IEventQueue* events, SocketMultiplexer* socketMultiplexer); - IpcServer(IEventQueue* events, SocketMultiplexer* socketMultiplexer, int port); - IpcServer(IpcServer const &) =delete; - IpcServer(IpcServer &&) =delete; - virtual ~IpcServer(); + IpcServer(IEventQueue *events, SocketMultiplexer *socketMultiplexer); + IpcServer(IEventQueue *events, SocketMultiplexer *socketMultiplexer, + int port); + IpcServer(IpcServer const &) = delete; + IpcServer(IpcServer &&) = delete; + virtual ~IpcServer(); - IpcServer& operator=(IpcServer const &) =delete; - IpcServer& operator=(IpcServer &&) =delete; + IpcServer &operator=(IpcServer const &) = delete; + IpcServer &operator=(IpcServer &&) = delete; - //! @name manipulators - //@{ + //! @name manipulators + //@{ - //! Opens a TCP socket only allowing local connections. - virtual void listen(); + //! Opens a TCP socket only allowing local connections. + virtual void listen(); - //! Send a message to all clients matching the filter type. - virtual void send(const IpcMessage& message, EIpcClientType filterType); + //! Send a message to all clients matching the filter type. + virtual void send(const IpcMessage &message, EIpcClientType filterType); - //@} - //! @name accessors - //@{ + //@} + //! @name accessors + //@{ - //! Returns true when there are clients of the specified type connected. - virtual bool hasClients(EIpcClientType clientType) const; + //! Returns true when there are clients of the specified type connected. + virtual bool hasClients(EIpcClientType clientType) const; - //@} + //@} private: - void init(); - void handleClientConnecting(const Event&, void*); - void handleClientDisconnected(const Event&, void*); - void handleMessageReceived(const Event&, void*); - void deleteClient(IpcClientProxy* proxy); + void init(); + void handleClientConnecting(const Event &, void *); + void handleClientDisconnected(const Event &, void *); + void handleMessageReceived(const Event &, void *); + void deleteClient(IpcClientProxy *proxy); private: - typedef std::list ClientList; - - bool m_mock; - IEventQueue* m_events; - SocketMultiplexer* m_socketMultiplexer; - TCPListenSocket* m_socket; - NetworkAddress m_address; - ClientList m_clients; - ArchMutex m_clientsMutex; + typedef std::list ClientList; + + bool m_mock; + IEventQueue *m_events; + SocketMultiplexer *m_socketMultiplexer; + TCPListenSocket *m_socket; + NetworkAddress m_address; + ClientList m_clients; + ArchMutex m_clientsMutex; #ifdef TEST_ENV public: - IpcServer() : - m_mock(true), - m_events(nullptr), - m_socketMultiplexer(nullptr), - m_socket(nullptr) { } + IpcServer() + : m_mock(true), m_events(nullptr), m_socketMultiplexer(nullptr), + m_socket(nullptr) {} #endif }; diff --git a/src/lib/ipc/IpcServerProxy.cpp b/src/lib/ipc/IpcServerProxy.cpp index 3cf59f7b9..480804964 100644 --- a/src/lib/ipc/IpcServerProxy.cpp +++ b/src/lib/ipc/IpcServerProxy.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2012 Nick Bolton - * + * * 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 LICENSE 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 @@ -18,106 +18,93 @@ #include "ipc/IpcServerProxy.h" -#include "ipc/IpcMessage.h" -#include "ipc/Ipc.h" -#include "synergy/ProtocolUtil.h" -#include "io/IStream.h" -#include "base/TMethodEventJob.h" #include "base/Log.h" +#include "base/TMethodEventJob.h" +#include "io/IStream.h" +#include "ipc/Ipc.h" +#include "ipc/IpcMessage.h" +#include "synergy/ProtocolUtil.h" // // IpcServerProxy // -IpcServerProxy::IpcServerProxy(synergy::IStream& stream, IEventQueue* events) : - m_stream(stream), - m_events(events) -{ - m_events->adoptHandler(m_events->forIStream().inputReady(), - stream.getEventTarget(), - new TMethodEventJob( - this, &IpcServerProxy::handleData)); +IpcServerProxy::IpcServerProxy(synergy::IStream &stream, IEventQueue *events) + : m_stream(stream), m_events(events) { + m_events->adoptHandler( + m_events->forIStream().inputReady(), stream.getEventTarget(), + new TMethodEventJob(this, &IpcServerProxy::handleData)); } -IpcServerProxy::~IpcServerProxy() -{ - m_events->removeHandler(m_events->forIStream().inputReady(), - m_stream.getEventTarget()); +IpcServerProxy::~IpcServerProxy() { + m_events->removeHandler(m_events->forIStream().inputReady(), + m_stream.getEventTarget()); } -void -IpcServerProxy::handleData(const Event&, void*) -{ - LOG((CLOG_DEBUG "start ipc handle data")); +void IpcServerProxy::handleData(const Event &, void *) { + LOG((CLOG_DEBUG "start ipc handle data")); - UInt8 code[4]; - UInt32 n = m_stream.read(code, 4); - while (n != 0) { + UInt8 code[4]; + UInt32 n = m_stream.read(code, 4); + while (n != 0) { - LOG((CLOG_DEBUG "ipc read: %c%c%c%c", - code[0], code[1], code[2], code[3])); - - IpcMessage* m = nullptr; - if (memcmp(code, kIpcMsgLogLine, 4) == 0) { - m = parseLogLine(); - } - else if (memcmp(code, kIpcMsgShutdown, 4) == 0) { - m = new IpcShutdownMessage(); - } - else { - LOG((CLOG_ERR "invalid ipc message")); - disconnect(); - } - - // don't delete with this event; the data is passed to a new event. - Event e(m_events->forIpcServerProxy().messageReceived(), this, NULL, Event::kDontFreeData); - e.setDataObject(m); - m_events->addEvent(e); + LOG((CLOG_DEBUG "ipc read: %c%c%c%c", code[0], code[1], code[2], code[3])); - n = m_stream.read(code, 4); - } - - LOG((CLOG_DEBUG "finished ipc handle data")); -} - -void -IpcServerProxy::send(const IpcMessage& message) -{ - LOG((CLOG_DEBUG4 "ipc write: %d", message.type())); - - switch (message.type()) { - case kIpcHello: { - const IpcHelloMessage& hm = static_cast(message); - ProtocolUtil::writef(&m_stream, kIpcMsgHello, hm.clientType()); - break; + IpcMessage *m = nullptr; + if (memcmp(code, kIpcMsgLogLine, 4) == 0) { + m = parseLogLine(); + } else if (memcmp(code, kIpcMsgShutdown, 4) == 0) { + m = new IpcShutdownMessage(); + } else { + LOG((CLOG_ERR "invalid ipc message")); + disconnect(); } - case kIpcCommand: { - const IpcCommandMessage& cm = static_cast(message); - const String command = cm.command(); - ProtocolUtil::writef(&m_stream, kIpcMsgCommand, &command); - break; - } + // don't delete with this event; the data is passed to a new event. + Event e(m_events->forIpcServerProxy().messageReceived(), this, NULL, + Event::kDontFreeData); + e.setDataObject(m); + m_events->addEvent(e); - default: - LOG((CLOG_ERR "ipc message not supported: %d", message.type())); - break; - } + n = m_stream.read(code, 4); + } + + LOG((CLOG_DEBUG "finished ipc handle data")); } -IpcLogLineMessage* -IpcServerProxy::parseLogLine() -{ - String logLine; - ProtocolUtil::readf(&m_stream, kIpcMsgLogLine + 4, &logLine); - - // must be deleted by event handler. - return new IpcLogLineMessage(logLine); +void IpcServerProxy::send(const IpcMessage &message) { + LOG((CLOG_DEBUG4 "ipc write: %d", message.type())); + + switch (message.type()) { + case kIpcHello: { + const IpcHelloMessage &hm = static_cast(message); + ProtocolUtil::writef(&m_stream, kIpcMsgHello, hm.clientType()); + break; + } + + case kIpcCommand: { + const IpcCommandMessage &cm = + static_cast(message); + const String command = cm.command(); + ProtocolUtil::writef(&m_stream, kIpcMsgCommand, &command); + break; + } + + default: + LOG((CLOG_ERR "ipc message not supported: %d", message.type())); + break; + } } -void -IpcServerProxy::disconnect() -{ - LOG((CLOG_DEBUG "ipc disconnect, closing stream")); - m_stream.close(); +IpcLogLineMessage *IpcServerProxy::parseLogLine() { + String logLine; + ProtocolUtil::readf(&m_stream, kIpcMsgLogLine + 4, &logLine); + + // must be deleted by event handler. + return new IpcLogLineMessage(logLine); +} + +void IpcServerProxy::disconnect() { + LOG((CLOG_DEBUG "ipc disconnect, closing stream")); + m_stream.close(); } diff --git a/src/lib/ipc/IpcServerProxy.h b/src/lib/ipc/IpcServerProxy.h index f04cdd041..4fd96b0f7 100644 --- a/src/lib/ipc/IpcServerProxy.h +++ b/src/lib/ipc/IpcServerProxy.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2012 Nick Bolton - * + * * 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 LICENSE 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 @@ -21,27 +21,29 @@ #include "base/Event.h" #include "base/EventTypes.h" -namespace synergy { class IStream; } +namespace synergy { +class IStream; +} class IpcMessage; class IpcLogLineMessage; class IEventQueue; class IpcServerProxy { - friend class IpcClient; + friend class IpcClient; public: - IpcServerProxy(synergy::IStream& stream, IEventQueue* events); - IpcServerProxy(IpcServerProxy const &) =delete; - virtual ~IpcServerProxy(); + IpcServerProxy(synergy::IStream &stream, IEventQueue *events); + IpcServerProxy(IpcServerProxy const &) = delete; + virtual ~IpcServerProxy(); private: - void send(const IpcMessage& message); + void send(const IpcMessage &message); - void handleData(const Event&, void*); - IpcLogLineMessage* parseLogLine(); - void disconnect(); + void handleData(const Event &, void *); + IpcLogLineMessage *parseLogLine(); + void disconnect(); private: - synergy::IStream& m_stream; - IEventQueue* m_events; + synergy::IStream &m_stream; + IEventQueue *m_events; }; diff --git a/src/lib/ipc/IpcSettingMessage.cpp b/src/lib/ipc/IpcSettingMessage.cpp index a37aaa3e0..b31e86099 100644 --- a/src/lib/ipc/IpcSettingMessage.cpp +++ b/src/lib/ipc/IpcSettingMessage.cpp @@ -18,21 +18,10 @@ #include "IpcSettingMessage.h" -IpcSettingMessage::IpcSettingMessage(const std::string& name, const std::string& value) : - IpcMessage(kIpcSetting), - m_name(name), - m_value(value) -{ +IpcSettingMessage::IpcSettingMessage(const std::string &name, + const std::string &value) + : IpcMessage(kIpcSetting), m_name(name), m_value(value) {} -} - -const std::string& IpcSettingMessage::getName() const -{ - return m_name; -} - -const std::string& IpcSettingMessage::getValue() const -{ - return m_value; -} +const std::string &IpcSettingMessage::getName() const { return m_name; } +const std::string &IpcSettingMessage::getValue() const { return m_value; } diff --git a/src/lib/ipc/IpcSettingMessage.h b/src/lib/ipc/IpcSettingMessage.h index ae82fc2ec..86937c80c 100644 --- a/src/lib/ipc/IpcSettingMessage.h +++ b/src/lib/ipc/IpcSettingMessage.h @@ -18,33 +18,31 @@ #pragma once -#include #include "IpcMessage.h" +#include -class IpcSettingMessage : public IpcMessage -{ +class IpcSettingMessage : public IpcMessage { public: - //! - //! \brief IpcSettingMessage constructor - //! \param name - setting name - //! \param value - setting value - //! - IpcSettingMessage(const std::string& name, const std::string& value); + //! + //! \brief IpcSettingMessage constructor + //! \param name - setting name + //! \param value - setting value + //! + IpcSettingMessage(const std::string &name, const std::string &value); - //! - //! \brief getName is a getter for the setting name - //! \return setting name - //! - const std::string& getName() const; + //! + //! \brief getName is a getter for the setting name + //! \return setting name + //! + const std::string &getName() const; - //! - //! \brief getValue is a getter for the setting value - //! \return setting value - //! - const std::string& getValue() const; + //! + //! \brief getValue is a getter for the setting value + //! \return setting value + //! + const std::string &getValue() const; private: - std::string m_name; - std::string m_value; + std::string m_name; + std::string m_value; }; - diff --git a/src/lib/mt/CondVar.cpp b/src/lib/mt/CondVar.cpp index 99ebf2672..34f0e645b 100644 --- a/src/lib/mt/CondVar.cpp +++ b/src/lib/mt/CondVar.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -24,68 +24,40 @@ // CondVarBase // -CondVarBase::CondVarBase(Mutex* mutex) : - m_mutex(mutex) -{ - assert(m_mutex != NULL); - m_cond = ARCH->newCondVar(); +CondVarBase::CondVarBase(Mutex *mutex) : m_mutex(mutex) { + assert(m_mutex != NULL); + m_cond = ARCH->newCondVar(); } -CondVarBase::~CondVarBase() -{ - ARCH->closeCondVar(m_cond); +CondVarBase::~CondVarBase() { ARCH->closeCondVar(m_cond); } + +void CondVarBase::lock() const { m_mutex->lock(); } + +void CondVarBase::unlock() const { m_mutex->unlock(); } + +void CondVarBase::signal() { ARCH->signalCondVar(m_cond); } + +void CondVarBase::broadcast() { ARCH->broadcastCondVar(m_cond); } + +bool CondVarBase::wait(Stopwatch &timer, double timeout) const { + double remain = timeout - timer.getTime(); + // Some ARCH wait()s return prematurely, retry until really timed out + // In particular, ArchMultithreadPosix::waitCondVar() returns every 100ms + do { + // Always call wait at least once, even if remain is 0, to give + // other thread a chance to grab the mutex to avoid deadlocks on + // busy waiting. + if (remain < 0.0) + remain = 0.0; + if (wait(remain)) + return true; + remain = timeout - timer.getTime(); + } while (remain >= 0.0); + return false; } -void -CondVarBase::lock() const -{ - m_mutex->lock(); +bool CondVarBase::wait(double timeout) const { + return ARCH->waitCondVar(m_cond, m_mutex->m_mutex, timeout); } -void -CondVarBase::unlock() const -{ - m_mutex->unlock(); -} - -void -CondVarBase::signal() -{ - ARCH->signalCondVar(m_cond); -} - -void -CondVarBase::broadcast() -{ - ARCH->broadcastCondVar(m_cond); -} - -bool -CondVarBase::wait(Stopwatch& timer, double timeout) const -{ - double remain = timeout-timer.getTime(); - // Some ARCH wait()s return prematurely, retry until really timed out - // In particular, ArchMultithreadPosix::waitCondVar() returns every 100ms - do { - // Always call wait at least once, even if remain is 0, to give - // other thread a chance to grab the mutex to avoid deadlocks on - // busy waiting. - if (remain<0.0) remain=0.0; - if (wait(remain)) - return true; - remain = timeout - timer.getTime(); - } while (remain >= 0.0); - return false; -} - -bool -CondVarBase::wait(double timeout) const -{ - return ARCH->waitCondVar(m_cond, m_mutex->m_mutex, timeout); -} - -Mutex* -CondVarBase::getMutex() const -{ - return m_mutex; -} +Mutex *CondVarBase::getMutex() const { return m_mutex; } diff --git a/src/lib/mt/CondVar.h b/src/lib/mt/CondVar.h index 8e5f1ec0f..d8c30f68d 100644 --- a/src/lib/mt/CondVar.h +++ b/src/lib/mt/CondVar.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -18,8 +18,8 @@ #pragma once -#include "mt/Mutex.h" #include "common/basic_types.h" +#include "mt/Mutex.h" class Stopwatch; @@ -32,194 +32,171 @@ variable has an associated mutex. */ class CondVarBase { public: - /*! - \c mutex must not be NULL. All condition variables have an - associated mutex. The mutex needn't be unique to one condition - variable. - */ - CondVarBase(Mutex* mutex); - ~CondVarBase(); + /*! + \c mutex must not be NULL. All condition variables have an + associated mutex. The mutex needn't be unique to one condition + variable. + */ + CondVarBase(Mutex *mutex); + ~CondVarBase(); - //! @name manipulators - //@{ + //! @name manipulators + //@{ - //! Lock the condition variable's mutex - /*! - Lock the condition variable's mutex. The condition variable should - be locked before reading or writing it. It must be locked for a - call to wait(). Locks are not recursive; locking a locked mutex - will deadlock the thread. - */ - void lock() const; + //! Lock the condition variable's mutex + /*! + Lock the condition variable's mutex. The condition variable should + be locked before reading or writing it. It must be locked for a + call to wait(). Locks are not recursive; locking a locked mutex + will deadlock the thread. + */ + void lock() const; - //! Unlock the condition variable's mutex - void unlock() const; + //! Unlock the condition variable's mutex + void unlock() const; - //! Signal the condition variable - /*! - Wake up one waiting thread, if there are any. Which thread gets - woken is undefined. - */ - void signal(); + //! Signal the condition variable + /*! + Wake up one waiting thread, if there are any. Which thread gets + woken is undefined. + */ + void signal(); - //! Signal the condition variable - /*! - Wake up all waiting threads, if any. - */ - void broadcast(); + //! Signal the condition variable + /*! + Wake up all waiting threads, if any. + */ + void broadcast(); - //@} - //! @name accessors - //@{ + //@} + //! @name accessors + //@{ - //! Wait on the condition variable - /*! - Wait on the condition variable. If \c timeout < 0 then wait until - signalled, otherwise up to \c timeout seconds or until signalled, - whichever comes first. Returns true if the object was signalled - during the wait, false otherwise. - - The proper way to wait for a condition is: - \code - cv.lock(); - while (cv-expr) { - cv.wait(); - } - cv.unlock(); - \endcode - where \c cv-expr involves the value of \c cv and is false when the - condition is satisfied. + //! Wait on the condition variable + /*! + Wait on the condition variable. If \c timeout < 0 then wait until + signalled, otherwise up to \c timeout seconds or until signalled, + whichever comes first. Returns true if the object was signalled + during the wait, false otherwise. - (cancellation point) - */ - bool wait(double timeout = -1.0) const; + The proper way to wait for a condition is: + \code + cv.lock(); + while (cv-expr) { + cv.wait(); + } + cv.unlock(); + \endcode + where \c cv-expr involves the value of \c cv and is false when the + condition is satisfied. - //! Wait on the condition variable - /*! - Same as \c wait(double) but use \c timer to compare against \c timeout. - Since clients normally wait on condition variables in a loop, clients - can use this to avoid recalculating \c timeout on each iteration. - Passing a stopwatch with a negative \c timeout is pointless (it will - never time out) but permitted. + (cancellation point) + */ + bool wait(double timeout = -1.0) const; - (cancellation point) - */ - bool wait(Stopwatch& timer, double timeout) const; + //! Wait on the condition variable + /*! + Same as \c wait(double) but use \c timer to compare against \c timeout. + Since clients normally wait on condition variables in a loop, clients + can use this to avoid recalculating \c timeout on each iteration. + Passing a stopwatch with a negative \c timeout is pointless (it will + never time out) but permitted. - //! Get the mutex - /*! - Get the mutex passed to the c'tor. - */ - Mutex* getMutex() const; + (cancellation point) + */ + bool wait(Stopwatch &timer, double timeout) const; - //@} + //! Get the mutex + /*! + Get the mutex passed to the c'tor. + */ + Mutex *getMutex() const; + + //@} private: - // not implemented - CondVarBase(const CondVarBase&); - CondVarBase& operator=(const CondVarBase&); + // not implemented + CondVarBase(const CondVarBase &); + CondVarBase &operator=(const CondVarBase &); private: - Mutex* m_mutex; - ArchCond m_cond; + Mutex *m_mutex; + ArchCond m_cond; }; //! Condition variable /*! A condition variable with storage for type \c T. */ -template -class CondVar : public CondVarBase { +template class CondVar : public CondVarBase { public: - //! Initialize using \c value - CondVar(Mutex* mutex, const T& value); - //! Initialize using another condition variable's value - CondVar(const CondVar&); - ~CondVar(); + //! Initialize using \c value + CondVar(Mutex *mutex, const T &value); + //! Initialize using another condition variable's value + CondVar(const CondVar &); + ~CondVar(); - //! @name manipulators - //@{ + //! @name manipulators + //@{ - //! Assigns the value of \c cv to this - /*! - Set the variable's value. The condition variable should be locked - before calling this method. - */ - CondVar& operator=(const CondVar& cv); + //! Assigns the value of \c cv to this + /*! + Set the variable's value. The condition variable should be locked + before calling this method. + */ + CondVar &operator=(const CondVar &cv); - //! Assigns \c value to this - /*! - Set the variable's value. The condition variable should be locked - before calling this method. - */ - CondVar& operator=(const T& v); + //! Assigns \c value to this + /*! + Set the variable's value. The condition variable should be locked + before calling this method. + */ + CondVar &operator=(const T &v); - //@} - //! @name accessors - //@{ + //@} + //! @name accessors + //@{ - //! Get the variable's value - /*! - Get the variable's value. The condition variable should be locked - before calling this method. - */ - operator const volatile T&() const; + //! Get the variable's value + /*! + Get the variable's value. The condition variable should be locked + before calling this method. + */ + operator const volatile T &() const; - //@} + //@} private: - volatile T m_data; + volatile T m_data; }; template -inline -CondVar::CondVar( - Mutex* mutex, - const T& data) : - CondVarBase(mutex), - m_data(data) -{ - // do nothing +inline CondVar::CondVar(Mutex *mutex, const T &data) + : CondVarBase(mutex), m_data(data) { + // do nothing } template -inline -CondVar::CondVar( - const CondVar& cv) : - CondVarBase(cv.getMutex()), - m_data(cv.m_data) -{ - // do nothing +inline CondVar::CondVar(const CondVar &cv) + : CondVarBase(cv.getMutex()), m_data(cv.m_data) { + // do nothing +} + +template inline CondVar::~CondVar() { + // do nothing } template -inline -CondVar::~CondVar() -{ - // do nothing +inline CondVar &CondVar::operator=(const CondVar &cv) { + m_data = cv.m_data; + return *this; } -template -inline -CondVar& -CondVar::operator=(const CondVar& cv) -{ - m_data = cv.m_data; - return *this; +template inline CondVar &CondVar::operator=(const T &data) { + m_data = data; + return *this; } -template -inline -CondVar& -CondVar::operator=(const T& data) -{ - m_data = data; - return *this; -} - -template -inline -CondVar::operator const volatile T&() const -{ - return m_data; +template inline CondVar::operator const volatile T &() const { + return m_data; } diff --git a/src/lib/mt/Lock.cpp b/src/lib/mt/Lock.cpp index a9970ebe9..4806742b1 100644 --- a/src/lib/mt/Lock.cpp +++ b/src/lib/mt/Lock.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -24,19 +24,8 @@ // Lock // -Lock::Lock(const Mutex* mutex) : - m_mutex(mutex) -{ - m_mutex->lock(); -} +Lock::Lock(const Mutex *mutex) : m_mutex(mutex) { m_mutex->lock(); } -Lock::Lock(const CondVarBase* cv) : - m_mutex(cv->getMutex()) -{ - m_mutex->lock(); -} +Lock::Lock(const CondVarBase *cv) : m_mutex(cv->getMutex()) { m_mutex->lock(); } -Lock::~Lock() -{ - m_mutex->unlock(); -} +Lock::~Lock() { m_mutex->unlock(); } diff --git a/src/lib/mt/Lock.h b/src/lib/mt/Lock.h index 1c07d0ed6..18efb0648 100644 --- a/src/lib/mt/Lock.h +++ b/src/lib/mt/Lock.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -32,18 +32,18 @@ exits (including by unwinding due to an exception). */ class Lock { public: - //! Lock the mutex \c mutex - Lock(const Mutex* mutex); - //! Lock the condition variable \c cv - Lock(const CondVarBase* cv); - //! Unlock the mutex or condition variable - ~Lock(); + //! Lock the mutex \c mutex + Lock(const Mutex *mutex); + //! Lock the condition variable \c cv + Lock(const CondVarBase *cv); + //! Unlock the mutex or condition variable + ~Lock(); private: - // not implemented - Lock(const Lock&); - Lock& operator=(const Lock&); + // not implemented + Lock(const Lock &); + Lock &operator=(const Lock &); private: - const Mutex* m_mutex; + const Mutex *m_mutex; }; diff --git a/src/lib/mt/Mutex.cpp b/src/lib/mt/Mutex.cpp index beed6aa37..79b65a159 100644 --- a/src/lib/mt/Mutex.cpp +++ b/src/lib/mt/Mutex.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -24,35 +24,14 @@ // Mutex // -Mutex::Mutex() -{ - m_mutex = ARCH->newMutex(); -} +Mutex::Mutex() { m_mutex = ARCH->newMutex(); } -Mutex::Mutex(const Mutex&) -{ - m_mutex = ARCH->newMutex(); -} +Mutex::Mutex(const Mutex &) { m_mutex = ARCH->newMutex(); } -Mutex::~Mutex() -{ - ARCH->closeMutex(m_mutex); -} +Mutex::~Mutex() { ARCH->closeMutex(m_mutex); } -Mutex& -Mutex::operator=(const Mutex&) -{ - return *this; -} +Mutex &Mutex::operator=(const Mutex &) { return *this; } -void -Mutex::lock() const -{ - ARCH->lockMutex(m_mutex); -} +void Mutex::lock() const { ARCH->lockMutex(m_mutex); } -void -Mutex::unlock() const -{ - ARCH->unlockMutex(m_mutex); -} +void Mutex::unlock() const { ARCH->unlockMutex(m_mutex); } diff --git a/src/lib/mt/Mutex.h b/src/lib/mt/Mutex.h index b8ef5a007..dd93b259b 100644 --- a/src/lib/mt/Mutex.h +++ b/src/lib/mt/Mutex.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -31,49 +31,49 @@ it tries it will deadlock itself. */ class Mutex { public: - Mutex(); - //! Equivalent to default c'tor - /*! - Copy c'tor doesn't copy anything. It just makes it possible to - copy objects that contain a mutex. - */ - Mutex(const Mutex&); - ~Mutex(); + Mutex(); + //! Equivalent to default c'tor + /*! + Copy c'tor doesn't copy anything. It just makes it possible to + copy objects that contain a mutex. + */ + Mutex(const Mutex &); + ~Mutex(); - //! @name manipulators - //@{ + //! @name manipulators + //@{ - //! Does nothing - /*! - This does nothing. It just makes it possible to assign objects - that contain a mutex. - */ - Mutex& operator=(const Mutex&); + //! Does nothing + /*! + This does nothing. It just makes it possible to assign objects + that contain a mutex. + */ + Mutex &operator=(const Mutex &); - //@} - //! @name accessors - //@{ + //@} + //! @name accessors + //@{ - //! Lock the mutex - /*! - Locks the mutex, which must not have been previously locked by the - calling thread. This blocks if the mutex is already locked by another - thread. + //! Lock the mutex + /*! + Locks the mutex, which must not have been previously locked by the + calling thread. This blocks if the mutex is already locked by another + thread. - (cancellation point) - */ - void lock() const; + (cancellation point) + */ + void lock() const; - //! Unlock the mutex - /*! - Unlocks the mutex, which must have been previously locked by the - calling thread. - */ - void unlock() const; + //! Unlock the mutex + /*! + Unlocks the mutex, which must have been previously locked by the + calling thread. + */ + void unlock() const; - //@} + //@} private: - friend class CondVarBase; - ArchMutex m_mutex; + friend class CondVarBase; + ArchMutex m_mutex; }; diff --git a/src/lib/mt/Thread.cpp b/src/lib/mt/Thread.cpp index 4bfe1fe49..d0148aab7 100644 --- a/src/lib/mt/Thread.cpp +++ b/src/lib/mt/Thread.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -18,176 +18,125 @@ #include "mt/Thread.h" +#include "arch/Arch.h" +#include "base/IJob.h" +#include "base/Log.h" #include "mt/XMT.h" #include "mt/XThread.h" -#include "arch/Arch.h" -#include "base/Log.h" -#include "base/IJob.h" #include // // Thread // -Thread::Thread(IJob* job) -{ - m_thread = ARCH->newThread(&Thread::threadFunc, job); - if (m_thread == NULL) { - // couldn't create thread - delete job; - throw XMTThreadUnavailable(); - } -} - -Thread::Thread(const Thread& thread) -{ - m_thread = ARCH->copyThread(thread.m_thread); -} - -Thread::Thread(ArchThread adoptedThread) -{ - m_thread = adoptedThread; -} - -Thread::~Thread() -{ - ARCH->closeThread(m_thread); -} - -Thread& -Thread::operator=(const Thread& thread) -{ - // copy given thread and release ours - ArchThread copy = ARCH->copyThread(thread.m_thread); - ARCH->closeThread(m_thread); - - // cut over - m_thread = copy; - - return *this; -} - -void -Thread::exit(void* result) -{ - throw XThreadExit(result); -} - -void -Thread::cancel() -{ - ARCH->cancelThread(m_thread); -} - -void -Thread::setPriority(int n) -{ - ARCH->setPriorityOfThread(m_thread, n); -} - -void -Thread::unblockPollSocket() -{ - ARCH->unblockPollSocket(m_thread); -} - -Thread -Thread::getCurrentThread() -{ - return Thread(ARCH->newCurrentThread()); -} - -void -Thread::testCancel() -{ - ARCH->testCancelThread(); -} - -bool -Thread::wait(double timeout) const -{ - return ARCH->wait(m_thread, timeout); -} - -void* -Thread::getResult() const -{ - if (wait()) - return ARCH->getResultOfThread(m_thread); - else - return NULL; -} - -IArchMultithread::ThreadID -Thread::getID() const -{ - return ARCH->getIDOfThread(m_thread); -} - -bool -Thread::operator==(const Thread& thread) const -{ - return ARCH->isSameThread(m_thread, thread.m_thread); -} - -bool -Thread::operator!=(const Thread& thread) const -{ - return !ARCH->isSameThread(m_thread, thread.m_thread); -} - -void* -Thread::threadFunc(void* vjob) -{ - // get this thread's id for logging - IArchMultithread::ThreadID id; - { - ArchThread thread = ARCH->newCurrentThread(); - id = ARCH->getIDOfThread(thread); - ARCH->closeThread(thread); - } - - // get job - IJob* job = static_cast(vjob); - - // run job - void* result = NULL; - try { - // go - LOG((CLOG_DEBUG1 "thread 0x%08x entry", id)); - job->run(); - LOG((CLOG_DEBUG1 "thread 0x%08x exit", id)); - } - catch (XThreadCancel&) { - // client called cancel() - LOG((CLOG_DEBUG1 "caught cancel on thread 0x%08x", id)); - delete job; - throw; - } - catch (XThreadExit& e) { - // client called exit() - result = e.m_result; - LOG((CLOG_DEBUG1 "caught exit on thread 0x%08x, result %p", id, result)); - } - catch (XBase& e) { - LOG((CLOG_ERR "synergy exception on thread 0x%08x: %s", id, e.what())); - delete job; - throw; - } - catch (std::exception& e) { - LOG((CLOG_ERR "standard exception on thread 0x%08x: %s", id, e.what())); - delete job; - throw; - } - catch (...) { - LOG((CLOG_ERR "non-exception throw on thread 0x%08x: ", id)); - delete job; - throw; - } - - // done with job +Thread::Thread(IJob *job) { + m_thread = ARCH->newThread(&Thread::threadFunc, job); + if (m_thread == NULL) { + // couldn't create thread delete job; - - // return exit result - return result; + throw XMTThreadUnavailable(); + } +} + +Thread::Thread(const Thread &thread) { + m_thread = ARCH->copyThread(thread.m_thread); +} + +Thread::Thread(ArchThread adoptedThread) { m_thread = adoptedThread; } + +Thread::~Thread() { ARCH->closeThread(m_thread); } + +Thread &Thread::operator=(const Thread &thread) { + // copy given thread and release ours + ArchThread copy = ARCH->copyThread(thread.m_thread); + ARCH->closeThread(m_thread); + + // cut over + m_thread = copy; + + return *this; +} + +void Thread::exit(void *result) { throw XThreadExit(result); } + +void Thread::cancel() { ARCH->cancelThread(m_thread); } + +void Thread::setPriority(int n) { ARCH->setPriorityOfThread(m_thread, n); } + +void Thread::unblockPollSocket() { ARCH->unblockPollSocket(m_thread); } + +Thread Thread::getCurrentThread() { return Thread(ARCH->newCurrentThread()); } + +void Thread::testCancel() { ARCH->testCancelThread(); } + +bool Thread::wait(double timeout) const { + return ARCH->wait(m_thread, timeout); +} + +void *Thread::getResult() const { + if (wait()) + return ARCH->getResultOfThread(m_thread); + else + return NULL; +} + +IArchMultithread::ThreadID Thread::getID() const { + return ARCH->getIDOfThread(m_thread); +} + +bool Thread::operator==(const Thread &thread) const { + return ARCH->isSameThread(m_thread, thread.m_thread); +} + +bool Thread::operator!=(const Thread &thread) const { + return !ARCH->isSameThread(m_thread, thread.m_thread); +} + +void *Thread::threadFunc(void *vjob) { + // get this thread's id for logging + IArchMultithread::ThreadID id; + { + ArchThread thread = ARCH->newCurrentThread(); + id = ARCH->getIDOfThread(thread); + ARCH->closeThread(thread); + } + + // get job + IJob *job = static_cast(vjob); + + // run job + void *result = NULL; + try { + // go + LOG((CLOG_DEBUG1 "thread 0x%08x entry", id)); + job->run(); + LOG((CLOG_DEBUG1 "thread 0x%08x exit", id)); + } catch (XThreadCancel &) { + // client called cancel() + LOG((CLOG_DEBUG1 "caught cancel on thread 0x%08x", id)); + delete job; + throw; + } catch (XThreadExit &e) { + // client called exit() + result = e.m_result; + LOG((CLOG_DEBUG1 "caught exit on thread 0x%08x, result %p", id, result)); + } catch (XBase &e) { + LOG((CLOG_ERR "synergy exception on thread 0x%08x: %s", id, e.what())); + delete job; + throw; + } catch (std::exception &e) { + LOG((CLOG_ERR "standard exception on thread 0x%08x: %s", id, e.what())); + delete job; + throw; + } catch (...) { + LOG((CLOG_ERR "non-exception throw on thread 0x%08x: ", id)); + delete job; + throw; + } + + // done with job + delete job; + + // return exit result + return result; } diff --git a/src/lib/mt/Thread.h b/src/lib/mt/Thread.h index e33202308..c6eddbe7d 100644 --- a/src/lib/mt/Thread.h +++ b/src/lib/mt/Thread.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -42,169 +42,168 @@ documentation. // note -- do not derive from this class class Thread { public: - //! Run \c adoptedJob in a new thread - /*! - Create and start a new thread executing the \c adoptedJob. The - new thread takes ownership of \c adoptedJob and will delete it. - */ - Thread(IJob* adoptedJob); + //! Run \c adoptedJob in a new thread + /*! + Create and start a new thread executing the \c adoptedJob. The + new thread takes ownership of \c adoptedJob and will delete it. + */ + Thread(IJob *adoptedJob); - //! Duplicate a thread handle - /*! - Make a new thread object that refers to an existing thread. - This does \b not start a new thread. - */ - Thread(const Thread&); + //! Duplicate a thread handle + /*! + Make a new thread object that refers to an existing thread. + This does \b not start a new thread. + */ + Thread(const Thread &); - //! Release a thread handle - /*! - Release a thread handle. This does not terminate the thread. A thread - will keep running until the job completes or calls exit() or allows - itself to be cancelled. - */ - ~Thread(); + //! Release a thread handle + /*! + Release a thread handle. This does not terminate the thread. A thread + will keep running until the job completes or calls exit() or allows + itself to be cancelled. + */ + ~Thread(); - //! @name manipulators - //@{ + //! @name manipulators + //@{ - //! Assign thread handle - /*! - Assign a thread handle. This has no effect on the threads, it simply - makes this thread object refer to another thread. It does \b not - start a new thread. - */ - Thread& operator=(const Thread&); + //! Assign thread handle + /*! + Assign a thread handle. This has no effect on the threads, it simply + makes this thread object refer to another thread. It does \b not + start a new thread. + */ + Thread &operator=(const Thread &); - //! Terminate the calling thread - /*! - Terminate the calling thread. This function does not return but - the stack is unwound and automatic objects are destroyed, as if - exit() threw an exception (which is, in fact, what it does). The - argument is saved as the result returned by getResult(). If you - have \c catch(...) blocks then you should add the following before - each to avoid catching the exit: - \code - catch(ThreadExit&) { throw; } - \endcode - or add the \c RETHROW_XTHREAD macro to the \c catch(...) block. - */ - static void exit(void*); + //! Terminate the calling thread + /*! + Terminate the calling thread. This function does not return but + the stack is unwound and automatic objects are destroyed, as if + exit() threw an exception (which is, in fact, what it does). The + argument is saved as the result returned by getResult(). If you + have \c catch(...) blocks then you should add the following before + each to avoid catching the exit: + \code + catch(ThreadExit&) { throw; } + \endcode + or add the \c RETHROW_XTHREAD macro to the \c catch(...) block. + */ + static void exit(void *); - //! Cancel thread - /*! - Cancel the thread. cancel() never waits for the thread to - terminate; it just posts the cancel and returns. A thread will - terminate when it enters a cancellation point with cancellation - enabled. If cancellation is disabled then the cancel is - remembered but not acted on until the first call to a - cancellation point after cancellation is enabled. - - A cancellation point is a function that can act on cancellation. - A cancellation point does not return if there's a cancel pending. - Instead, it unwinds the stack and destroys automatic objects, as - if cancel() threw an exception (which is, in fact, what it does). - Threads must take care to unlock and clean up any resources they - may have, especially mutexes. They can \c catch(XThreadCancel) to - do that then rethrow the exception or they can let it happen - automatically by doing clean up in the d'tors of automatic - objects (like Lock). Clients are strongly encouraged to do the latter. - During cancellation, further cancel() calls are ignored (i.e. - a thread cannot be interrupted by a cancel during cancellation). - - Clients that \c catch(XThreadCancel) must always rethrow the - exception. Clients that \c catch(...) must either rethrow the - exception or include a \c catch(XThreadCancel) handler that - rethrows. The \c RETHROW_XTHREAD macro may be useful for that. - */ - void cancel(); + //! Cancel thread + /*! + Cancel the thread. cancel() never waits for the thread to + terminate; it just posts the cancel and returns. A thread will + terminate when it enters a cancellation point with cancellation + enabled. If cancellation is disabled then the cancel is + remembered but not acted on until the first call to a + cancellation point after cancellation is enabled. - //! Change thread priority - /*! - Change the priority of the thread. Normal priority is 0, 1 is - the next lower, etc. -1 is the next higher, etc. but boosting - the priority may not be permitted and will be silenty ignored. - */ - void setPriority(int n); + A cancellation point is a function that can act on cancellation. + A cancellation point does not return if there's a cancel pending. + Instead, it unwinds the stack and destroys automatic objects, as + if cancel() threw an exception (which is, in fact, what it does). + Threads must take care to unlock and clean up any resources they + may have, especially mutexes. They can \c catch(XThreadCancel) to + do that then rethrow the exception or they can let it happen + automatically by doing clean up in the d'tors of automatic + objects (like Lock). Clients are strongly encouraged to do the latter. + During cancellation, further cancel() calls are ignored (i.e. + a thread cannot be interrupted by a cancel during cancellation). - //! Force pollSocket() to return - /*! - Forces a currently blocked pollSocket() in the thread to return - immediately. - */ - void unblockPollSocket(); + Clients that \c catch(XThreadCancel) must always rethrow the + exception. Clients that \c catch(...) must either rethrow the + exception or include a \c catch(XThreadCancel) handler that + rethrows. The \c RETHROW_XTHREAD macro may be useful for that. + */ + void cancel(); - //@} - //! @name accessors - //@{ + //! Change thread priority + /*! + Change the priority of the thread. Normal priority is 0, 1 is + the next lower, etc. -1 is the next higher, etc. but boosting + the priority may not be permitted and will be silenty ignored. + */ + void setPriority(int n); - //! Get current thread's handle - /*! - Return a Thread object representing the calling thread. - */ - static Thread getCurrentThread(); + //! Force pollSocket() to return + /*! + Forces a currently blocked pollSocket() in the thread to return + immediately. + */ + void unblockPollSocket(); - //! Test for cancellation - /*! - testCancel() does nothing but is a cancellation point. Call - this to make a function itself a cancellation point. If the - thread was cancelled and cancellation is enabled this will - cause the thread to unwind the stack and terminate. + //@} + //! @name accessors + //@{ - (cancellation point) - */ - static void testCancel(); + //! Get current thread's handle + /*! + Return a Thread object representing the calling thread. + */ + static Thread getCurrentThread(); - //! Wait for thread to terminate - /*! - Waits for the thread to terminate (by exit() or cancel() or - by returning from the thread job) for up to \c timeout seconds, - returning true if the thread terminated and false otherwise. - This returns immediately with false if called by a thread on - itself and immediately with true if the thread has already - terminated. This will wait forever if \c timeout < 0.0. + //! Test for cancellation + /*! + testCancel() does nothing but is a cancellation point. Call + this to make a function itself a cancellation point. If the + thread was cancelled and cancellation is enabled this will + cause the thread to unwind the stack and terminate. - (cancellation point) - */ - bool wait(double timeout = -1.0) const; + (cancellation point) + */ + static void testCancel(); - //! Get the exit result - /*! - Returns the exit result. This does an implicit wait(). It returns - NULL immediately if called by a thread on itself or on a thread that - was cancelled. + //! Wait for thread to terminate + /*! + Waits for the thread to terminate (by exit() or cancel() or + by returning from the thread job) for up to \c timeout seconds, + returning true if the thread terminated and false otherwise. + This returns immediately with false if called by a thread on + itself and immediately with true if the thread has already + terminated. This will wait forever if \c timeout < 0.0. - (cancellation point) - */ - void* getResult() const; + (cancellation point) + */ + bool wait(double timeout = -1.0) const; - //! Get the thread id - /*! - Returns an integer id for this thread. This id must not be used to - check if two Thread objects refer to the same thread. Use - operator==() for that. - */ - IArchMultithread::ThreadID - getID() const; + //! Get the exit result + /*! + Returns the exit result. This does an implicit wait(). It returns + NULL immediately if called by a thread on itself or on a thread that + was cancelled. - //! Compare thread handles - /*! - Returns true if two Thread objects refer to the same thread. - */ - bool operator==(const Thread&) const; + (cancellation point) + */ + void *getResult() const; - //! Compare thread handles - /*! - Returns true if two Thread objects do not refer to the same thread. - */ - bool operator!=(const Thread&) const; + //! Get the thread id + /*! + Returns an integer id for this thread. This id must not be used to + check if two Thread objects refer to the same thread. Use + operator==() for that. + */ + IArchMultithread::ThreadID getID() const; - //@} + //! Compare thread handles + /*! + Returns true if two Thread objects refer to the same thread. + */ + bool operator==(const Thread &) const; + + //! Compare thread handles + /*! + Returns true if two Thread objects do not refer to the same thread. + */ + bool operator!=(const Thread &) const; + + //@} private: - Thread(ArchThread); + Thread(ArchThread); - static void* threadFunc(void*); + static void *threadFunc(void *); private: - ArchThread m_thread; + ArchThread m_thread; }; diff --git a/src/lib/mt/XMT.cpp b/src/lib/mt/XMT.cpp index ff7d8751f..ad4b87541 100644 --- a/src/lib/mt/XMT.cpp +++ b/src/lib/mt/XMT.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -22,8 +22,6 @@ // XMTThreadUnavailable // -String -XMTThreadUnavailable::getWhat() const throw() -{ - return format("XMTThreadUnavailable", "cannot create thread"); +String XMTThreadUnavailable::getWhat() const throw() { + return format("XMTThreadUnavailable", "cannot create thread"); } diff --git a/src/lib/mt/XMT.h b/src/lib/mt/XMT.h index 16cef278d..1c2c5e725 100644 --- a/src/lib/mt/XMT.h +++ b/src/lib/mt/XMT.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 diff --git a/src/lib/mt/XThread.h b/src/lib/mt/XThread.h index bc502851b..18985ff87 100644 --- a/src/lib/mt/XThread.h +++ b/src/lib/mt/XThread.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -28,10 +28,10 @@ XThreadExit, XThread, or ...). */ class XThreadExit : public XThread { public: - //! \c result is the result of the thread - XThreadExit(void* result) : m_result(result) { } - ~XThreadExit() { } + //! \c result is the result of the thread + XThreadExit(void *result) : m_result(result) {} + ~XThreadExit() {} public: - void* m_result; + void *m_result; }; diff --git a/src/lib/net/IDataSocket.cpp b/src/lib/net/IDataSocket.cpp index 4d4d89447..51d3092b5 100644 --- a/src/lib/net/IDataSocket.cpp +++ b/src/lib/net/IDataSocket.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -23,17 +23,13 @@ // IDataSocket // -void -IDataSocket::close() -{ - // this is here to work around a VC++6 bug. see the header file. - assert(0 && "bad call"); +void IDataSocket::close() { + // this is here to work around a VC++6 bug. see the header file. + assert(0 && "bad call"); } -void* -IDataSocket::getEventTarget() const -{ - // this is here to work around a VC++6 bug. see the header file. - assert(0 && "bad call"); - return NULL; +void *IDataSocket::getEventTarget() const { + // this is here to work around a VC++6 bug. see the header file. + assert(0 && "bad call"); + return NULL; } diff --git a/src/lib/net/IDataSocket.h b/src/lib/net/IDataSocket.h index a58c4df6d..5561796d9 100644 --- a/src/lib/net/IDataSocket.h +++ b/src/lib/net/IDataSocket.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 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 LICENSE 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 @@ -18,10 +18,10 @@ #pragma once -#include "net/ISocket.h" -#include "io/IStream.h" -#include "base/String.h" #include "base/EventTypes.h" +#include "base/String.h" +#include "io/IStream.h" +#include "net/ISocket.h" //! Data stream socket interface /*! @@ -30,44 +30,44 @@ represent a full-duplex data stream. */ class IDataSocket : public ISocket, public synergy::IStream { public: - class ConnectionFailedInfo { - public: - ConnectionFailedInfo(const char* what) : m_what(what) { } - String m_what; - }; + class ConnectionFailedInfo { + public: + ConnectionFailedInfo(const char *what) : m_what(what) {} + String m_what; + }; - IDataSocket(IEventQueue* events) { } + IDataSocket(IEventQueue *events) {} - //! @name manipulators - //@{ + //! @name manipulators + //@{ - //! Connect socket - /*! - Attempt to connect to a remote endpoint. This returns immediately - and sends a connected event when successful or a connection failed - event when it fails. The stream acts as if shutdown for input and - output until the stream connects. - */ - virtual void connect(const NetworkAddress&) = 0; + //! Connect socket + /*! + Attempt to connect to a remote endpoint. This returns immediately + and sends a connected event when successful or a connection failed + event when it fails. The stream acts as if shutdown for input and + output until the stream connects. + */ + virtual void connect(const NetworkAddress &) = 0; - //@} + //@} - // ISocket overrides - // close() and getEventTarget() aren't pure to work around a bug - // in VC++6. it claims the methods are unused locals and warns - // that it's removing them. it's presumably tickled by inheriting - // methods with identical signatures from both superclasses. - virtual void bind(const NetworkAddress&) = 0; - virtual void close(); - virtual void* getEventTarget() const; + // ISocket overrides + // close() and getEventTarget() aren't pure to work around a bug + // in VC++6. it claims the methods are unused locals and warns + // that it's removing them. it's presumably tickled by inheriting + // methods with identical signatures from both superclasses. + virtual void bind(const NetworkAddress &) = 0; + virtual void close(); + virtual void *getEventTarget() const; - // IStream overrides - virtual UInt32 read(void* buffer, UInt32 n) = 0; - virtual void write(const void* buffer, UInt32 n) = 0; - virtual void flush() = 0; - virtual void shutdownInput() = 0; - virtual void shutdownOutput() = 0; - virtual bool isReady() const = 0; - virtual bool isFatal() const = 0; - virtual UInt32 getSize() const = 0; + // IStream overrides + virtual UInt32 read(void *buffer, UInt32 n) = 0; + virtual void write(const void *buffer, UInt32 n) = 0; + virtual void flush() = 0; + virtual void shutdownInput() = 0; + virtual void shutdownOutput() = 0; + virtual bool isReady() const = 0; + virtual bool isFatal() const = 0; + virtual UInt32 getSize() const = 0; }; diff --git a/src/lib/net/IListenSocket.h b/src/lib/net/IListenSocket.h index cbf1d2523..d64488bfd 100644 --- a/src/lib/net/IListenSocket.h +++ b/src/lib/net/IListenSocket.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -18,8 +18,8 @@ #pragma once -#include "net/ISocket.h" #include "base/EventTypes.h" +#include "net/ISocket.h" class IDataSocket; @@ -30,22 +30,21 @@ listen for incoming connections. */ class IListenSocket : public ISocket { public: - //! @name manipulators - //@{ + //! @name manipulators + //@{ - //! Accept connection - /*! - Accept a connection, returning a socket representing the full-duplex - data stream. Returns NULL if no socket is waiting to be accepted. - This is only valid after a call to \c bind(). - */ - virtual IDataSocket* - accept() = 0; - - //@} + //! Accept connection + /*! + Accept a connection, returning a socket representing the full-duplex + data stream. Returns NULL if no socket is waiting to be accepted. + This is only valid after a call to \c bind(). + */ + virtual IDataSocket *accept() = 0; - // ISocket overrides - virtual void bind(const NetworkAddress&) = 0; - virtual void close() = 0; - virtual void* getEventTarget() const = 0; + //@} + + // ISocket overrides + virtual void bind(const NetworkAddress &) = 0; + virtual void close() = 0; + virtual void *getEventTarget() const = 0; }; diff --git a/src/lib/net/ISocket.h b/src/lib/net/ISocket.h index 2d5d63112..0c6f536d9 100644 --- a/src/lib/net/ISocket.h +++ b/src/lib/net/ISocket.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -18,9 +18,9 @@ #pragma once -#include "common/IInterface.h" #include "base/Event.h" #include "base/EventTypes.h" +#include "common/IInterface.h" class NetworkAddress; @@ -31,30 +31,30 @@ Generated events use \c this as the target. */ class ISocket : public IInterface { public: - //! @name manipulators - //@{ + //! @name manipulators + //@{ - //! Bind socket to address - /*! - Binds the socket to a particular address. - */ - virtual void bind(const NetworkAddress&) = 0; + //! Bind socket to address + /*! + Binds the socket to a particular address. + */ + virtual void bind(const NetworkAddress &) = 0; - //! Close socket - /*! - Closes the socket. This should flush the output stream. - */ - virtual void close() = 0; + //! Close socket + /*! + Closes the socket. This should flush the output stream. + */ + virtual void close() = 0; - //@} - //! @name accessors - //@{ + //@} + //! @name accessors + //@{ - //! Get event target - /*! - Returns the event target for events generated by this socket. - */ - virtual void* getEventTarget() const = 0; + //! Get event target + /*! + Returns the event target for events generated by this socket. + */ + virtual void *getEventTarget() const = 0; - //@} + //@} }; diff --git a/src/lib/net/ISocketFactory.h b/src/lib/net/ISocketFactory.h index 9ba61685f..3f063c482 100644 --- a/src/lib/net/ISocketFactory.h +++ b/src/lib/net/ISocketFactory.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -18,8 +18,8 @@ #pragma once -#include "common/IInterface.h" #include "arch/IArchNetwork.h" +#include "common/IInterface.h" class IDataSocket; class IListenSocket; @@ -31,14 +31,18 @@ create sockets. */ class ISocketFactory : public IInterface { public: - //! @name accessors - //@{ + //! @name accessors + //@{ - //! Create data socket - virtual IDataSocket* create(bool secure, IArchNetwork::EAddressFamily family = IArchNetwork::kINET) const = 0; + //! Create data socket + virtual IDataSocket * + create(bool secure, + IArchNetwork::EAddressFamily family = IArchNetwork::kINET) const = 0; - //! Create listen socket - virtual IListenSocket* createListen(bool secure, IArchNetwork::EAddressFamily family = IArchNetwork::kINET) const = 0; + //! Create listen socket + virtual IListenSocket *createListen( + bool secure, + IArchNetwork::EAddressFamily family = IArchNetwork::kINET) const = 0; - //@} + //@} }; diff --git a/src/lib/net/ISocketMultiplexerJob.h b/src/lib/net/ISocketMultiplexerJob.h index cc1d0d935..fdd819bb8 100644 --- a/src/lib/net/ISocketMultiplexerJob.h +++ b/src/lib/net/ISocketMultiplexerJob.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 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 LICENSE 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 @@ -27,50 +27,50 @@ A socket multiplexer job handles events on a socket. */ class ISocketMultiplexerJob : public IInterface { public: - //! @name manipulators - //@{ + //! @name manipulators + //@{ - //! Handle socket event - /*! - Called by a socket multiplexer when the socket becomes readable, - writable, or has an error. It should return itself if the same - job can continue to service events, a new job if the socket must - be serviced differently, or NULL if the socket should no longer - be serviced. The socket is readable if \p readable is true, - writable if \p writable is true, and in error if \p error is - true. + //! Handle socket event + /*! + Called by a socket multiplexer when the socket becomes readable, + writable, or has an error. It should return itself if the same + job can continue to service events, a new job if the socket must + be serviced differently, or NULL if the socket should no longer + be serviced. The socket is readable if \p readable is true, + writable if \p writable is true, and in error if \p error is + true. - This call must not attempt to directly change the job for this - socket by calling \c addSocket() or \c removeSocket() on the - multiplexer. It must instead return the new job. It can, - however, add or remove jobs for other sockets. - */ - virtual ISocketMultiplexerJob* - run(bool readable, bool writable, bool error) = 0; + This call must not attempt to directly change the job for this + socket by calling \c addSocket() or \c removeSocket() on the + multiplexer. It must instead return the new job. It can, + however, add or remove jobs for other sockets. + */ + virtual ISocketMultiplexerJob *run(bool readable, bool writable, + bool error) = 0; - //@} - //! @name accessors - //@{ + //@} + //! @name accessors + //@{ - //! Get the socket - /*! - Return the socket to multiplex - */ - virtual ArchSocket getSocket() const = 0; + //! Get the socket + /*! + Return the socket to multiplex + */ + virtual ArchSocket getSocket() const = 0; - //! Check for interest in readability - /*! - Return true if the job is interested in being run if the socket - becomes readable. - */ - virtual bool isReadable() const = 0; + //! Check for interest in readability + /*! + Return true if the job is interested in being run if the socket + becomes readable. + */ + virtual bool isReadable() const = 0; - //! Check for interest in writability - /*! - Return true if the job is interested in being run if the socket - becomes writable. - */ - virtual bool isWritable() const = 0; + //! Check for interest in writability + /*! + Return true if the job is interested in being run if the socket + becomes writable. + */ + virtual bool isWritable() const = 0; - //@} + //@} }; diff --git a/src/lib/net/InverseSockets/AutoArchSocket.cpp b/src/lib/net/InverseSockets/AutoArchSocket.cpp index 391f718a9..2972b6adc 100644 --- a/src/lib/net/InverseSockets/AutoArchSocket.cpp +++ b/src/lib/net/InverseSockets/AutoArchSocket.cpp @@ -17,185 +17,152 @@ */ #include "AutoArchSocket.h" -#include "base/Log.h" #include "arch/Arch.h" #include "arch/XArch.h" +#include "base/Log.h" #include "net/XSocket.h" -AutoArchSocket::AutoArchSocket(IArchNetwork::EAddressFamily family) -{ - try { - m_socket = ARCH->newSocket(family, IArchNetwork::kSTREAM); - LOG((CLOG_DEBUG "opening new socket: %08X", m_socket)); - } - catch (const XArchNetwork& e) { - throw XSocketCreate(e.what()); - } +AutoArchSocket::AutoArchSocket(IArchNetwork::EAddressFamily family) { + try { + m_socket = ARCH->newSocket(family, IArchNetwork::kSTREAM); + LOG((CLOG_DEBUG "opening new socket: %08X", m_socket)); + } catch (const XArchNetwork &e) { + throw XSocketCreate(e.what()); + } } -AutoArchSocket::~AutoArchSocket() -{ +AutoArchSocket::~AutoArchSocket() { closeSocket(); } + +void AutoArchSocket::setNoDelayOnSocket(bool value) { + if (isValid()) { + ARCH->setNoDelayOnSocket(m_socket, value); + } +} + +void AutoArchSocket::setReuseAddrOnSocket(bool value) { + if (isValid()) { + ARCH->setReuseAddrOnSocket(m_socket, value); + } +} + +void AutoArchSocket::closeSocket() { + if (isValid()) { + try { + LOG((CLOG_DEBUG "closing socket: %08X", m_socket)); + ARCH->closeSocket(m_socket); + m_socket = nullptr; + } catch (const XArchNetwork &e) { + // ignore, there's not much we can do + LOG((CLOG_WARN "error closing socket: %s", e.what())); + } + } else { + LOG((CLOG_WARN "error closing socket because the socket already closed")); + } +} + +void AutoArchSocket::bindSocket(const NetworkAddress &addr) { + if (isValid()) { + try { + ARCH->bindSocket(m_socket, addr.getAddress()); + } catch (const XArchNetworkAddressInUse &e) { + throw XSocketAddressInUse(e.what()); + } catch (const XArchNetwork &e) { + throw XSocketBind(e.what()); + } + } +} + +void AutoArchSocket::bindAndListen(const NetworkAddress &addr) { + try { + setReuseAddrOnSocket(); + bindSocket(addr); + listenOnSocket(); + } catch (const XArchNetworkAddressInUse &e) { + throw XSocketAddressInUse(e.what()); + } catch (const XArchNetwork &e) { + throw XSocketBind(e.what()); + } +} + +void AutoArchSocket::listenOnSocket() { + if (isValid()) { + ARCH->listenOnSocket(m_socket); + } +} + +ArchSocket AutoArchSocket::acceptSocket() { + return ARCH->acceptSocket(m_socket, nullptr); +} + +void AutoArchSocket::closeSocketForRead() { + if (isValid()) { + try { + ARCH->closeSocketForRead(m_socket); + } catch (const XArchNetwork &e) { + // ignore, there's not much we can do + LOG((CLOG_WARN "error closing socket: %s", e.what())); + } + } +} + +void AutoArchSocket::closeSocketForWrite() { + if (isValid()) { + try { + ARCH->closeSocketForWrite(m_socket); + } catch (const XArchNetwork &e) { + // ignore, there's not much we can do + LOG((CLOG_WARN "error closing socket: %s", e.what())); + } + } +} + +bool AutoArchSocket::connectSocket(const NetworkAddress &addr) { + bool result = false; + + if (isValid()) { + // turn off Nagle algorithm. we send lots of very short messages + // that should be sent without (much) delay. for example, the + // mouse motion messages are much less useful if they're delayed. + setNoDelayOnSocket(); + result = ARCH->connectSocket(m_socket, addr.getAddress()); + } + + return result; +} + +size_t AutoArchSocket::readSocket(UInt8 *buffer, size_t size) { + size_t result = 0; + + if (isValid()) { + result = ARCH->readSocket(m_socket, buffer, size); + } + + return result; +} + +size_t AutoArchSocket::writeSocket(const UInt8 *buffer, size_t size) { + size_t result = 0; + + if (isValid()) { + result = ARCH->writeSocket(m_socket, buffer, size); + } + + return result; +} + +void AutoArchSocket::throwErrorOnSocket() { + if (isValid()) { + ARCH->throwErrorOnSocket(m_socket); + } +} + +ArchSocket AutoArchSocket::getRawSocket() const { return m_socket; } + +bool AutoArchSocket::isValid() const { return (m_socket != nullptr); } + +void AutoArchSocket::operator=(ArchSocket socket) { + if (isValid()) { closeSocket(); -} - -void AutoArchSocket::setNoDelayOnSocket(bool value) -{ - if (isValid()) { - ARCH->setNoDelayOnSocket(m_socket, value); - } -} - -void AutoArchSocket::setReuseAddrOnSocket(bool value) -{ - if (isValid()) { - ARCH->setReuseAddrOnSocket(m_socket, value); - } -} - -void AutoArchSocket::closeSocket() -{ - if (isValid()) { - try { - LOG((CLOG_DEBUG "closing socket: %08X", m_socket)); - ARCH->closeSocket(m_socket); - m_socket = nullptr; - } - catch (const XArchNetwork& e) { - // ignore, there's not much we can do - LOG((CLOG_WARN "error closing socket: %s", e.what())); - } - } - else { - LOG((CLOG_WARN "error closing socket because the socket already closed")); - } -} - -void AutoArchSocket::bindSocket(const NetworkAddress &addr) -{ - if (isValid()) { - try { - ARCH->bindSocket(m_socket, addr.getAddress()); - } - catch (const XArchNetworkAddressInUse& e) { - throw XSocketAddressInUse(e.what()); - } - catch (const XArchNetwork& e) { - throw XSocketBind(e.what()); - } - } -} - -void AutoArchSocket::bindAndListen(const NetworkAddress &addr) -{ - try { - setReuseAddrOnSocket(); - bindSocket(addr); - listenOnSocket(); - } - catch (const XArchNetworkAddressInUse& e) { - throw XSocketAddressInUse(e.what()); - } - catch (const XArchNetwork& e) { - throw XSocketBind(e.what()); - } -} - -void AutoArchSocket::listenOnSocket() -{ - if (isValid()) { - ARCH->listenOnSocket(m_socket); - } -} - -ArchSocket AutoArchSocket::acceptSocket() -{ - return ARCH->acceptSocket(m_socket, nullptr); -} - -void AutoArchSocket::closeSocketForRead() -{ - if (isValid()) { - try { - ARCH->closeSocketForRead(m_socket); - } - catch (const XArchNetwork& e) { - // ignore, there's not much we can do - LOG((CLOG_WARN "error closing socket: %s", e.what())); - } - } -} - -void AutoArchSocket::closeSocketForWrite() -{ - if (isValid()) { - try { - ARCH->closeSocketForWrite(m_socket); - } - catch (const XArchNetwork& e) { - // ignore, there's not much we can do - LOG((CLOG_WARN "error closing socket: %s", e.what())); - } - } -} - -bool AutoArchSocket::connectSocket(const NetworkAddress &addr) -{ - bool result = false; - - if (isValid()) { - // turn off Nagle algorithm. we send lots of very short messages - // that should be sent without (much) delay. for example, the - // mouse motion messages are much less useful if they're delayed. - setNoDelayOnSocket(); - result = ARCH->connectSocket(m_socket, addr.getAddress()); - } - - return result; -} - -size_t AutoArchSocket::readSocket(UInt8* buffer, size_t size) -{ - size_t result = 0; - - if (isValid()) { - result = ARCH->readSocket(m_socket, buffer, size); - } - - return result; -} - -size_t AutoArchSocket::writeSocket(const UInt8* buffer, size_t size) -{ - size_t result = 0; - - if (isValid()) { - result = ARCH->writeSocket(m_socket, buffer, size); - } - - return result; -} - -void AutoArchSocket::throwErrorOnSocket() -{ - if (isValid()) { - ARCH->throwErrorOnSocket(m_socket); - } -} - -ArchSocket AutoArchSocket::getRawSocket() const -{ - return m_socket; -} - -bool AutoArchSocket::isValid() const -{ - return (m_socket != nullptr); -} - -void AutoArchSocket::operator =(ArchSocket socket) -{ - if (isValid()) { - closeSocket(); - } - m_socket = socket; + } + m_socket = socket; } diff --git a/src/lib/net/InverseSockets/AutoArchSocket.h b/src/lib/net/InverseSockets/AutoArchSocket.h index 7fb006eab..ab0db7028 100644 --- a/src/lib/net/InverseSockets/AutoArchSocket.h +++ b/src/lib/net/InverseSockets/AutoArchSocket.h @@ -18,36 +18,35 @@ #pragma once #include "net/NetworkAddress.h" -class AutoArchSocket -{ +class AutoArchSocket { public: - explicit AutoArchSocket(IArchNetwork::EAddressFamily family); - ~AutoArchSocket(); + explicit AutoArchSocket(IArchNetwork::EAddressFamily family); + ~AutoArchSocket(); - AutoArchSocket(const AutoArchSocket&) = delete; - AutoArchSocket& operator =(const AutoArchSocket&) = delete; + AutoArchSocket(const AutoArchSocket &) = delete; + AutoArchSocket &operator=(const AutoArchSocket &) = delete; - void setNoDelayOnSocket(bool value = true); - void setReuseAddrOnSocket(bool value = true); + void setNoDelayOnSocket(bool value = true); + void setReuseAddrOnSocket(bool value = true); - void listenOnSocket(); - ArchSocket acceptSocket(); - void bindSocket(const NetworkAddress& addr); - bool connectSocket(const NetworkAddress& addr); - void bindAndListen(const NetworkAddress& addr); + void listenOnSocket(); + ArchSocket acceptSocket(); + void bindSocket(const NetworkAddress &addr); + bool connectSocket(const NetworkAddress &addr); + void bindAndListen(const NetworkAddress &addr); - void closeSocket(); - void closeSocketForRead(); - void closeSocketForWrite(); + void closeSocket(); + void closeSocketForRead(); + void closeSocketForWrite(); - size_t readSocket(UInt8* buffer, size_t size); - size_t writeSocket(const UInt8* buffer, size_t size); - void throwErrorOnSocket(); + size_t readSocket(UInt8 *buffer, size_t size); + size_t writeSocket(const UInt8 *buffer, size_t size); + void throwErrorOnSocket(); - bool isValid() const; - ArchSocket getRawSocket() const; - void operator =(ArchSocket socket); + bool isValid() const; + ArchSocket getRawSocket() const; + void operator=(ArchSocket socket); private: - ArchSocket m_socket = nullptr; + ArchSocket m_socket = nullptr; }; diff --git a/src/lib/net/InverseSockets/InverseClientSocket.cpp b/src/lib/net/InverseSockets/InverseClientSocket.cpp index f0a8b9813..07c8f0dbd 100644 --- a/src/lib/net/InverseSockets/InverseClientSocket.cpp +++ b/src/lib/net/InverseSockets/InverseClientSocket.cpp @@ -18,435 +18,379 @@ #include "InverseClientSocket.h" +#include "arch/Arch.h" +#include "arch/XArch.h" +#include "base/IEventJob.h" +#include "base/IEventQueue.h" +#include "base/Log.h" +#include "mt/Lock.h" #include "net/NetworkAddress.h" #include "net/SocketMultiplexer.h" #include "net/TSocketMultiplexerMethodJob.h" #include "net/XSocket.h" -#include "mt/Lock.h" -#include "arch/Arch.h" -#include "arch/XArch.h" -#include "base/Log.h" -#include "base/IEventQueue.h" -#include "base/IEventJob.h" -#include #include +#include #include // // InverseClientSocket // -InverseClientSocket::InverseClientSocket(IEventQueue* events, SocketMultiplexer* socketMultiplexer, IArchNetwork::EAddressFamily family) : - IDataSocket(events), - m_events(events), - m_socket(family), - m_listener(family), - m_flushed(&m_mutex, true), - m_socketMultiplexer(socketMultiplexer) -{ +InverseClientSocket::InverseClientSocket(IEventQueue *events, + SocketMultiplexer *socketMultiplexer, + IArchNetwork::EAddressFamily family) + : IDataSocket(events), m_events(events), m_socket(family), + m_listener(family), m_flushed(&m_mutex, true), + m_socketMultiplexer(socketMultiplexer) {} + +InverseClientSocket::~InverseClientSocket() { + try { + // warning virtual function in destructor is very danger practice + InverseClientSocket::close(); + } catch (...) { + LOG((CLOG_DEBUG "error while TCP socket destruction")); + } } -InverseClientSocket::~InverseClientSocket() -{ - try { - // warning virtual function in destructor is very danger practice - InverseClientSocket::close(); - } - catch (...) { - LOG((CLOG_DEBUG "error while TCP socket destruction")); - } +void InverseClientSocket::bind(const NetworkAddress &addr) { + m_socket.bindSocket(addr); } -void -InverseClientSocket::bind(const NetworkAddress& addr) -{ - m_socket.bindSocket(addr); +void InverseClientSocket::close() { + setJob(nullptr); + + Lock lock(&m_mutex); + onDisconnected(); } -void -InverseClientSocket::close() -{ - setJob(nullptr); +void *InverseClientSocket::getEventTarget() const { + return const_cast(static_cast(this)); +} +UInt32 InverseClientSocket::read(void *buffer, UInt32 n) { + // copy data directly from our input buffer + Lock lock(&m_mutex); + UInt32 size = m_inputBuffer.getSize(); + if (n > size) { + n = size; + } + if (buffer != nullptr && n != 0) { + memcpy(buffer, m_inputBuffer.peek(n), n); + } + m_inputBuffer.pop(n); + + // if no more data and we cannot read or write then send disconnected + if (n > 0 && m_inputBuffer.getSize() == 0 && !m_readable && !m_writable) { + sendEvent(m_events->forISocket().disconnected()); + m_connected = false; + } + + return n; +} + +void InverseClientSocket::write(const void *buffer, UInt32 n) { + bool wasEmpty; + { Lock lock(&m_mutex); - onDisconnected(); + + // must not have shutdown output + if (!m_writable) { + sendEvent(m_events->forIStream().outputError()); + return; + } + + // ignore empty writes + if (n == 0) { + return; + } + + // copy data to the output buffer + wasEmpty = (m_outputBuffer.getSize() == 0); + m_outputBuffer.write(buffer, n); + + // there's data to write + m_flushed = false; + } + + // make sure we're waiting to write + if (wasEmpty) { + setJob(newJob(m_socket.getRawSocket())); + } } -void* -InverseClientSocket::getEventTarget() const -{ - return const_cast(static_cast(this)); +void InverseClientSocket::flush() { + Lock lock(&m_mutex); + while (m_flushed == false) { + m_flushed.wait(); + } } -UInt32 -InverseClientSocket::read(void* buffer, UInt32 n) -{ - // copy data directly from our input buffer +void InverseClientSocket::shutdownInput() { + bool useNewJob = false; + { Lock lock(&m_mutex); - UInt32 size = m_inputBuffer.getSize(); - if (n > size) { - n = size; - } - if (buffer != nullptr && n != 0) { - memcpy(buffer, m_inputBuffer.peek(n), n); - } - m_inputBuffer.pop(n); - // if no more data and we cannot read or write then send disconnected - if (n > 0 && m_inputBuffer.getSize() == 0 && !m_readable && !m_writable) { - sendEvent(m_events->forISocket().disconnected()); - m_connected = false; - } + // shutdown socket for reading + m_socket.closeSocketForRead(); - return n; + // shutdown buffer for reading + if (m_readable) { + sendEvent(m_events->forIStream().inputShutdown()); + onInputShutdown(); + useNewJob = true; + } + } + if (useNewJob) { + setJob(newJob(m_socket.getRawSocket())); + } } -void -InverseClientSocket::write(const void* buffer, UInt32 n) -{ - bool wasEmpty; - { - Lock lock(&m_mutex); +void InverseClientSocket::shutdownOutput() { + bool useNewJob = false; + { + Lock lock(&m_mutex); - // must not have shutdown output - if (!m_writable) { - sendEvent(m_events->forIStream().outputError()); - return; - } + // shutdown socket for writing + m_socket.closeSocketForWrite(); - // ignore empty writes - if (n == 0) { - return; - } - - // copy data to the output buffer - wasEmpty = (m_outputBuffer.getSize() == 0); - m_outputBuffer.write(buffer, n); - - // there's data to write - m_flushed = false; + // shutdown buffer for writing + if (m_writable) { + sendEvent(m_events->forIStream().outputShutdown()); + onOutputShutdown(); + useNewJob = true; } + } + if (useNewJob) { + setJob(newJob(m_socket.getRawSocket())); + } +} - // make sure we're waiting to write +bool InverseClientSocket::isReady() const { + Lock lock(&m_mutex); + return (m_inputBuffer.getSize() > 0); +} + +bool InverseClientSocket::isFatal() const { + // TCP sockets aren't ever left in a fatal state. + LOG((CLOG_ERR "isFatal() not valid for non-secure connections")); + return false; +} + +UInt32 InverseClientSocket::getSize() const { + Lock lock(&m_mutex); + return m_inputBuffer.getSize(); +} + +void InverseClientSocket::connect(const NetworkAddress &addr) { + { + Lock lock(&m_mutex); + m_listener.bindAndListen(addr); + m_writable = true; + m_readable = true; + } + setJob(newJob(m_listener.getRawSocket())); +} + +InverseClientSocket::EJobResult InverseClientSocket::doRead() { + UInt8 buffer[4096] = {0}; + size_t bytesRead = m_socket.readSocket(buffer, sizeof(buffer)); + + if (bytesRead > 0) { + bool wasEmpty = (m_inputBuffer.getSize() == 0); + + // slurp up as much as possible + do { + m_inputBuffer.write(buffer, static_cast(bytesRead)); + + bytesRead = m_socket.readSocket(buffer, sizeof(buffer)); + } while (bytesRead > 0); + + // send input ready if input buffer was empty if (wasEmpty) { - setJob(newJob(m_socket.getRawSocket())); + sendEvent(m_events->forIStream().inputReady()); } -} - -void -InverseClientSocket::flush() -{ - Lock lock(&m_mutex); - while (m_flushed == false) { - m_flushed.wait(); + } else { + // remote write end of stream hungup. our input side + // has therefore shutdown but don't flush our buffer + // since there's still data to be read. + sendEvent(m_events->forIStream().inputShutdown()); + if (!m_writable && m_inputBuffer.getSize() == 0) { + sendEvent(m_events->forISocket().disconnected()); + m_connected = false; } -} - -void -InverseClientSocket::shutdownInput() -{ - bool useNewJob = false; - { - Lock lock(&m_mutex); - - // shutdown socket for reading - m_socket.closeSocketForRead(); - - // shutdown buffer for reading - if (m_readable) { - sendEvent(m_events->forIStream().inputShutdown()); - onInputShutdown(); - useNewJob = true; - } - } - if (useNewJob) { - setJob(newJob(m_socket.getRawSocket())); - } -} - -void -InverseClientSocket::shutdownOutput() -{ - bool useNewJob = false; - { - Lock lock(&m_mutex); - - // shutdown socket for writing - m_socket.closeSocketForWrite(); - - // shutdown buffer for writing - if (m_writable) { - sendEvent(m_events->forIStream().outputShutdown()); - onOutputShutdown(); - useNewJob = true; - } - } - if (useNewJob) { - setJob(newJob(m_socket.getRawSocket())); - } -} - -bool -InverseClientSocket::isReady() const -{ - Lock lock(&m_mutex); - return (m_inputBuffer.getSize() > 0); -} - -bool -InverseClientSocket::isFatal() const -{ - // TCP sockets aren't ever left in a fatal state. - LOG((CLOG_ERR "isFatal() not valid for non-secure connections")); - return false; -} - -UInt32 -InverseClientSocket::getSize() const -{ - Lock lock(&m_mutex); - return m_inputBuffer.getSize(); -} - -void -InverseClientSocket::connect(const NetworkAddress& addr) -{ - { - Lock lock(&m_mutex); - m_listener.bindAndListen(addr); - m_writable = true; - m_readable = true; - } - setJob(newJob(m_listener.getRawSocket())); -} - -InverseClientSocket::EJobResult -InverseClientSocket::doRead() -{ - UInt8 buffer[4096] = {0}; - size_t bytesRead = m_socket.readSocket(buffer, sizeof(buffer)); - - if (bytesRead > 0) { - bool wasEmpty = (m_inputBuffer.getSize() == 0); - - // slurp up as much as possible - do { - m_inputBuffer.write(buffer, static_cast(bytesRead)); - - bytesRead = m_socket.readSocket(buffer, sizeof(buffer)); - } while (bytesRead > 0); - - // send input ready if input buffer was empty - if (wasEmpty) { - sendEvent(m_events->forIStream().inputReady()); - } - } - else { - // remote write end of stream hungup. our input side - // has therefore shutdown but don't flush our buffer - // since there's still data to be read. - sendEvent(m_events->forIStream().inputShutdown()); - if (!m_writable && m_inputBuffer.getSize() == 0) { - sendEvent(m_events->forISocket().disconnected()); - m_connected = false; - } - m_readable = false; - return InverseClientSocket::EJobResult::kNew; - } - - return InverseClientSocket::EJobResult::kRetry; -} - -InverseClientSocket::EJobResult -InverseClientSocket::doWrite() -{ - UInt32 bufferSize = m_outputBuffer.getSize(); - auto buffer = static_cast(m_outputBuffer.peek(bufferSize)); - const auto bytesWrote = static_cast(m_socket.writeSocket(buffer, bufferSize)); - - if (bytesWrote > 0) { - discardWrittenData(bytesWrote); - return InverseClientSocket::EJobResult::kNew; - } - - return InverseClientSocket::EJobResult::kRetry; -} - -void -InverseClientSocket::setJob(ISocketMultiplexerJob* job) -{ - // multiplexer will delete the old job - if (job == nullptr) { - m_socketMultiplexer->removeSocket(this); - } - else { - m_socketMultiplexer->addSocket(this, job); - } -} - -ISocketMultiplexerJob* -InverseClientSocket::newJob(ArchSocket socket) -{ - // note -- must have m_mutex locked on entry - - ISocketMultiplexerJob* result = nullptr; - - if (socket) { - auto isWritable = m_writable; - auto handler = &InverseClientSocket::serviceConnecting; - - if (m_connected) { - handler = &InverseClientSocket::serviceConnected; - isWritable = (isWritable && (m_outputBuffer.getSize() > 0)); - } - - if (m_readable || isWritable) { - result = new TSocketMultiplexerMethodJob(this, handler, socket, m_readable, isWritable); - } - } - - return result; -} - -void -InverseClientSocket::sendConnectionFailedEvent(const char* msg) -{ - auto info = new ConnectionFailedInfo(msg); - m_events->addEvent(Event(m_events->forIDataSocket().connectionFailed(), - getEventTarget(), info, Event::kDontFreeData)); -} - -void -InverseClientSocket::sendEvent(Event::Type type) -{ - m_events->addEvent(Event(type, getEventTarget())); -} - -void -InverseClientSocket::discardWrittenData(int bytesWrote) -{ - m_outputBuffer.pop(bytesWrote); - if (m_outputBuffer.getSize() == 0) { - sendEvent(m_events->forIStream().outputFlushed()); - m_flushed = true; - m_flushed.broadcast(); - } -} - -void -InverseClientSocket::onConnected() -{ - sendEvent(m_events->forIDataSocket().connected()); - m_connected = true; - m_readable = true; - m_writable = true; -} - -void -InverseClientSocket::onInputShutdown() -{ - m_inputBuffer.pop(m_inputBuffer.getSize()); m_readable = false; + return InverseClientSocket::EJobResult::kNew; + } + + return InverseClientSocket::EJobResult::kRetry; } -void -InverseClientSocket::onOutputShutdown() -{ - m_outputBuffer.pop(m_outputBuffer.getSize()); - m_writable = false; +InverseClientSocket::EJobResult InverseClientSocket::doWrite() { + UInt32 bufferSize = m_outputBuffer.getSize(); + auto buffer = static_cast(m_outputBuffer.peek(bufferSize)); + const auto bytesWrote = + static_cast(m_socket.writeSocket(buffer, bufferSize)); - // we're now flushed + if (bytesWrote > 0) { + discardWrittenData(bytesWrote); + return InverseClientSocket::EJobResult::kNew; + } + + return InverseClientSocket::EJobResult::kRetry; +} + +void InverseClientSocket::setJob(ISocketMultiplexerJob *job) { + // multiplexer will delete the old job + if (job == nullptr) { + m_socketMultiplexer->removeSocket(this); + } else { + m_socketMultiplexer->addSocket(this, job); + } +} + +ISocketMultiplexerJob *InverseClientSocket::newJob(ArchSocket socket) { + // note -- must have m_mutex locked on entry + + ISocketMultiplexerJob *result = nullptr; + + if (socket) { + auto isWritable = m_writable; + auto handler = &InverseClientSocket::serviceConnecting; + + if (m_connected) { + handler = &InverseClientSocket::serviceConnected; + isWritable = (isWritable && (m_outputBuffer.getSize() > 0)); + } + + if (m_readable || isWritable) { + result = new TSocketMultiplexerMethodJob( + this, handler, socket, m_readable, isWritable); + } + } + + return result; +} + +void InverseClientSocket::sendConnectionFailedEvent(const char *msg) { + auto info = new ConnectionFailedInfo(msg); + m_events->addEvent(Event(m_events->forIDataSocket().connectionFailed(), + getEventTarget(), info, Event::kDontFreeData)); +} + +void InverseClientSocket::sendEvent(Event::Type type) { + m_events->addEvent(Event(type, getEventTarget())); +} + +void InverseClientSocket::discardWrittenData(int bytesWrote) { + m_outputBuffer.pop(bytesWrote); + if (m_outputBuffer.getSize() == 0) { + sendEvent(m_events->forIStream().outputFlushed()); m_flushed = true; m_flushed.broadcast(); + } } -void -InverseClientSocket::onDisconnected() -{ - if (m_connected) { +void InverseClientSocket::onConnected() { + sendEvent(m_events->forIDataSocket().connected()); + m_connected = true; + m_readable = true; + m_writable = true; +} + +void InverseClientSocket::onInputShutdown() { + m_inputBuffer.pop(m_inputBuffer.getSize()); + m_readable = false; +} + +void InverseClientSocket::onOutputShutdown() { + m_outputBuffer.pop(m_outputBuffer.getSize()); + m_writable = false; + + // we're now flushed + m_flushed = true; + m_flushed.broadcast(); +} + +void InverseClientSocket::onDisconnected() { + if (m_connected) { + sendEvent(m_events->forISocket().disconnected()); + } + // disconnected + onInputShutdown(); + onOutputShutdown(); + m_connected = false; +} + +ISocketMultiplexerJob * +InverseClientSocket::serviceConnecting(ISocketMultiplexerJob *job, bool read, + bool, bool) { + Lock lock(&m_mutex); + + if (read) { + m_socket = m_listener.acceptSocket(); + onConnected(); + return newJob(m_socket.getRawSocket()); + } + + return job; +} + +ISocketMultiplexerJob * +InverseClientSocket::serviceConnected(ISocketMultiplexerJob *job, bool read, + bool write, bool error) { + Lock lock(&m_mutex); + + if (error) { + onDisconnected(); + return newJob(m_listener.getRawSocket()); + } + + EJobResult result = InverseClientSocket::EJobResult::kRetry; + if (write) { + try { + result = doWrite(); + } catch (const XArchNetworkShutdown &) { + // remote read end of stream hungup. our output side + // has therefore shutdown. + onOutputShutdown(); + sendEvent(m_events->forIStream().outputShutdown()); + if (!m_readable && m_inputBuffer.getSize() == 0) { sendEvent(m_events->forISocket().disconnected()); + m_connected = false; + } + result = InverseClientSocket::EJobResult::kNew; + } catch (const XArchNetworkDisconnected &) { + // stream hungup + onDisconnected(); + result = InverseClientSocket::EJobResult::kNew; + } catch (const XArchNetwork &e) { + // other write error + LOG((CLOG_WARN "error writing socket: %s", e.what())); + onDisconnected(); + sendEvent(m_events->forIStream().outputError()); + result = InverseClientSocket::EJobResult::kNew; } - // disconnected - onInputShutdown(); - onOutputShutdown(); - m_connected = false; -} - -ISocketMultiplexerJob* -InverseClientSocket::serviceConnecting(ISocketMultiplexerJob* job, - bool read, bool, bool) -{ - Lock lock(&m_mutex); - - if (read) { - m_socket = m_listener.acceptSocket(); - onConnected(); - return newJob(m_socket.getRawSocket()); - } - - return job; -} - -ISocketMultiplexerJob* -InverseClientSocket::serviceConnected(ISocketMultiplexerJob* job, - bool read, bool write, bool error) -{ - Lock lock(&m_mutex); - - if (error) { - onDisconnected(); - return newJob(m_listener.getRawSocket()); - } - - EJobResult result = InverseClientSocket::EJobResult::kRetry; - if (write) { - try { - result = doWrite(); - } - catch (const XArchNetworkShutdown&) { - // remote read end of stream hungup. our output side - // has therefore shutdown. - onOutputShutdown(); - sendEvent(m_events->forIStream().outputShutdown()); - if (!m_readable && m_inputBuffer.getSize() == 0) { - sendEvent(m_events->forISocket().disconnected()); - m_connected = false; - } - result = InverseClientSocket::EJobResult::kNew; - } - catch (const XArchNetworkDisconnected&) { - // stream hungup - onDisconnected(); - result = InverseClientSocket::EJobResult::kNew; - } - catch (const XArchNetwork& e) { - // other write error - LOG((CLOG_WARN "error writing socket: %s", e.what())); - onDisconnected(); - sendEvent(m_events->forIStream().outputError()); - result = InverseClientSocket::EJobResult::kNew; - } - } - - if (read && m_readable) { - try { - result = doRead(); - } - catch (const XArchNetworkDisconnected&) { - // stream hungup - onDisconnected(); - result = InverseClientSocket::EJobResult::kNew; - } - catch (const XArchNetwork& e) { - // ignore other read error - LOG((CLOG_WARN "error reading socket: %s", e.what())); - } - } - - if (result == InverseClientSocket::EJobResult::kBreak) { - return nullptr; - } - - return result == InverseClientSocket::EJobResult::kNew ? newJob(m_socket.getRawSocket()) : job; + } + + if (read && m_readable) { + try { + result = doRead(); + } catch (const XArchNetworkDisconnected &) { + // stream hungup + onDisconnected(); + result = InverseClientSocket::EJobResult::kNew; + } catch (const XArchNetwork &e) { + // ignore other read error + LOG((CLOG_WARN "error reading socket: %s", e.what())); + } + } + + if (result == InverseClientSocket::EJobResult::kBreak) { + return nullptr; + } + + return result == InverseClientSocket::EJobResult::kNew + ? newJob(m_socket.getRawSocket()) + : job; } diff --git a/src/lib/net/InverseSockets/InverseClientSocket.h b/src/lib/net/InverseSockets/InverseClientSocket.h index 458f9c7ab..4136f1677 100644 --- a/src/lib/net/InverseSockets/InverseClientSocket.h +++ b/src/lib/net/InverseSockets/InverseClientSocket.h @@ -18,12 +18,12 @@ #pragma once -#include "net/IDataSocket.h" +#include "AutoArchSocket.h" +#include "arch/IArchNetwork.h" #include "io/StreamBuffer.h" #include "mt/CondVar.h" #include "mt/Mutex.h" -#include "arch/IArchNetwork.h" -#include "AutoArchSocket.h" +#include "net/IDataSocket.h" class ISocketMultiplexerJob; class IEventQueue; @@ -31,82 +31,80 @@ class SocketMultiplexer; class InverseClientSocket : public IDataSocket { public: - InverseClientSocket(IEventQueue* events, SocketMultiplexer* socketMultiplexer, IArchNetwork::EAddressFamily family = IArchNetwork::kINET); - InverseClientSocket(InverseClientSocket const &) =delete; - InverseClientSocket(InverseClientSocket &&) =delete; - ~InverseClientSocket() override; + InverseClientSocket( + IEventQueue *events, SocketMultiplexer *socketMultiplexer, + IArchNetwork::EAddressFamily family = IArchNetwork::kINET); + InverseClientSocket(InverseClientSocket const &) = delete; + InverseClientSocket(InverseClientSocket &&) = delete; + ~InverseClientSocket() override; - InverseClientSocket& operator=(InverseClientSocket const &) =delete; - InverseClientSocket& operator=(InverseClientSocket &&) =delete; + InverseClientSocket &operator=(InverseClientSocket const &) = delete; + InverseClientSocket &operator=(InverseClientSocket &&) = delete; - // ISocket overrides - void bind(const NetworkAddress&) override; - void close() override; - void* getEventTarget() const override; + // ISocket overrides + void bind(const NetworkAddress &) override; + void close() override; + void *getEventTarget() const override; - // IStream overrides - UInt32 read(void* buffer, UInt32 n) override; - void write(const void* buffer, UInt32 n) override; - void flush() override; - void shutdownInput() override; - void shutdownOutput() override; - bool isReady() const override; - bool isFatal() const override; - UInt32 getSize() const override; + // IStream overrides + UInt32 read(void *buffer, UInt32 n) override; + void write(const void *buffer, UInt32 n) override; + void flush() override; + void shutdownInput() override; + void shutdownOutput() override; + bool isReady() const override; + bool isFatal() const override; + UInt32 getSize() const override; - // IDataSocket overrides - void connect(const NetworkAddress&) override; + // IDataSocket overrides + void connect(const NetworkAddress &) override; - - virtual ISocketMultiplexerJob* - newJob(ArchSocket socket); + virtual ISocketMultiplexerJob *newJob(ArchSocket socket); protected: - enum class EJobResult { - kBreak = -1, //!< Break the Job chain - kRetry, //!< Retry the same job - kNew //!< Require a new job - }; + enum class EJobResult { + kBreak = -1, //!< Break the Job chain + kRetry, //!< Retry the same job + kNew //!< Require a new job + }; - ArchSocket getSocket() { return m_socket.getRawSocket(); } - IEventQueue* getEvents() { return m_events; } - virtual EJobResult doRead(); - virtual EJobResult doWrite(); + ArchSocket getSocket() { return m_socket.getRawSocket(); } + IEventQueue *getEvents() { return m_events; } + virtual EJobResult doRead(); + virtual EJobResult doWrite(); - void setJob(ISocketMultiplexerJob*); + void setJob(ISocketMultiplexerJob *); - bool isReadable() const { return m_readable; } - bool isWritable() const { return m_writable; } + bool isReadable() const { return m_readable; } + bool isWritable() const { return m_writable; } - Mutex& getMutex() { return m_mutex; } + Mutex &getMutex() { return m_mutex; } - void sendEvent(Event::Type); - void discardWrittenData(int bytesWrote); + void sendEvent(Event::Type); + void discardWrittenData(int bytesWrote); private: - void sendConnectionFailedEvent(const char*); - void onConnected(); - void onInputShutdown(); - void onOutputShutdown(); - void onDisconnected(); + void sendConnectionFailedEvent(const char *); + void onConnected(); + void onInputShutdown(); + void onOutputShutdown(); + void onDisconnected(); - ISocketMultiplexerJob* - serviceConnecting(ISocketMultiplexerJob*, - bool, bool, bool); - ISocketMultiplexerJob* - serviceConnected(ISocketMultiplexerJob*, - bool, bool, bool); + ISocketMultiplexerJob *serviceConnecting(ISocketMultiplexerJob *, bool, bool, + bool); + ISocketMultiplexerJob *serviceConnected(ISocketMultiplexerJob *, bool, bool, + bool); protected: - bool m_readable = false; - bool m_writable = false; - bool m_connected = false; - IEventQueue* m_events; - StreamBuffer m_inputBuffer; - StreamBuffer m_outputBuffer; - Mutex m_mutex; - AutoArchSocket m_socket; - AutoArchSocket m_listener; - CondVar m_flushed; - SocketMultiplexer* m_socketMultiplexer; + bool m_readable = false; + bool m_writable = false; + bool m_connected = false; + IEventQueue *m_events; + StreamBuffer m_inputBuffer; + StreamBuffer m_outputBuffer; + Mutex m_mutex; + AutoArchSocket m_socket; + AutoArchSocket m_listener; + CondVar m_flushed; + SocketMultiplexer *m_socketMultiplexer; }; diff --git a/src/lib/net/InverseSockets/InverseServerSocket.cpp b/src/lib/net/InverseSockets/InverseServerSocket.cpp index d31eddf35..09e43c7fd 100644 --- a/src/lib/net/InverseSockets/InverseServerSocket.cpp +++ b/src/lib/net/InverseSockets/InverseServerSocket.cpp @@ -18,106 +18,92 @@ #include "InverseServerSocket.h" +#include "arch/Arch.h" +#include "arch/XArch.h" +#include "base/IEventQueue.h" +#include "base/Log.h" +#include "io/XIO.h" +#include "mt/Lock.h" +#include "mt/Mutex.h" #include "net/NetworkAddress.h" #include "net/SocketMultiplexer.h" #include "net/TCPSocket.h" #include "net/TSocketMultiplexerMethodJob.h" #include "net/XSocket.h" -#include "io/XIO.h" -#include "mt/Lock.h" -#include "mt/Mutex.h" -#include "arch/Arch.h" -#include "arch/XArch.h" -#include "base/Log.h" -#include "base/IEventQueue.h" // // InverseServerSocket // -InverseServerSocket::InverseServerSocket(IEventQueue* events, SocketMultiplexer* socketMultiplexer, IArchNetwork::EAddressFamily family) : - m_socket(family), - m_events(events), - m_socketMultiplexer(socketMultiplexer) -{ +InverseServerSocket::InverseServerSocket(IEventQueue *events, + SocketMultiplexer *socketMultiplexer, + IArchNetwork::EAddressFamily family) + : m_socket(family), m_events(events), + m_socketMultiplexer(socketMultiplexer) {} + +InverseServerSocket::~InverseServerSocket() { + m_socketMultiplexer->removeSocket(this); } -InverseServerSocket::~InverseServerSocket() -{ - m_socketMultiplexer->removeSocket(this); +void InverseServerSocket::bind(const NetworkAddress &addr) { + Lock lock(&m_mutex); + m_address = addr; + m_socket.connectSocket(m_address); + setListeningJob(true); } -void -InverseServerSocket::bind(const NetworkAddress& addr) -{ - Lock lock(&m_mutex); - m_address = addr; +void InverseServerSocket::close() { + Lock lock(&m_mutex); + m_socketMultiplexer->removeSocket(this); + m_socket.closeSocket(); +} + +void *InverseServerSocket::getEventTarget() const { + return const_cast(static_cast(this)); +} + +IDataSocket *InverseServerSocket::accept() { + IDataSocket *socket = nullptr; + try { + socket = + new TCPSocket(m_events, m_socketMultiplexer, m_socket.getRawSocket()); + if (socket != nullptr) { + setListeningJob(); + } + return socket; + } catch (const XArchNetwork &) { + if (socket != nullptr) { + delete socket; + setListeningJob(); + } + return nullptr; + } catch (const std::exception &) { + if (socket != nullptr) { + delete socket; + setListeningJob(); + } + throw; + } +} + +void InverseServerSocket::setListeningJob(bool read) { + m_socketMultiplexer->addSocket( + this, new TSocketMultiplexerMethodJob( + this, &InverseServerSocket::serviceListening, + m_socket.getRawSocket(), true, read)); +} + +ISocketMultiplexerJob * +InverseServerSocket::serviceListening(ISocketMultiplexerJob *job, bool, + bool write, bool error) { + if (error) { m_socket.connectSocket(m_address); - setListeningJob(true); -} - -void -InverseServerSocket::close() -{ - Lock lock(&m_mutex); - m_socketMultiplexer->removeSocket(this); - m_socket.closeSocket(); -} - -void* -InverseServerSocket::getEventTarget() const -{ - return const_cast(static_cast(this)); -} - -IDataSocket* -InverseServerSocket::accept() -{ - IDataSocket* socket = nullptr; - try { - socket = new TCPSocket(m_events, m_socketMultiplexer, m_socket.getRawSocket()); - if (socket != nullptr) { - setListeningJob(); - } - return socket; - } - catch (const XArchNetwork&) { - if (socket != nullptr) { - delete socket; - setListeningJob(); - } - return nullptr; - } - catch (const std::exception&) { - if (socket != nullptr) { - delete socket; - setListeningJob(); - } - throw; - } -} - -void -InverseServerSocket::setListeningJob(bool read) -{ - m_socketMultiplexer->addSocket(this, - new TSocketMultiplexerMethodJob( - this, &InverseServerSocket::serviceListening, - m_socket.getRawSocket(), true, read)); -} - -ISocketMultiplexerJob* -InverseServerSocket::serviceListening(ISocketMultiplexerJob* job, - bool, bool write, bool error) -{ - if (error) { - m_socket.connectSocket(m_address); - return job; - } - if (write) { - m_events->addEvent(Event(m_events->forIListenSocket().connecting(), this)); - // stop polling on this socket until the client accepts - return nullptr; - } return job; + } + if (write) { + m_events->addEvent(Event(m_events->forIListenSocket().connecting(), this)); + // stop polling on this socket until the client accepts + return nullptr; + } + return job; } diff --git a/src/lib/net/InverseSockets/InverseServerSocket.h b/src/lib/net/InverseSockets/InverseServerSocket.h index 7e0d09cc8..a0fceb2b5 100644 --- a/src/lib/net/InverseSockets/InverseServerSocket.h +++ b/src/lib/net/InverseSockets/InverseServerSocket.h @@ -18,10 +18,10 @@ #pragma once -#include "net/IListenSocket.h" +#include "AutoArchSocket.h" #include "arch/IArchNetwork.h" #include "mt/Mutex.h" -#include "AutoArchSocket.h" +#include "net/IListenSocket.h" class ISocketMultiplexerJob; class IEventQueue; @@ -29,36 +29,36 @@ class SocketMultiplexer; class InverseServerSocket : public IListenSocket { public: - InverseServerSocket(IEventQueue* events, SocketMultiplexer* socketMultiplexer, IArchNetwork::EAddressFamily family); - InverseServerSocket(InverseServerSocket const &) =delete; - InverseServerSocket(InverseServerSocket &&) =delete; - ~InverseServerSocket() override; + InverseServerSocket(IEventQueue *events, SocketMultiplexer *socketMultiplexer, + IArchNetwork::EAddressFamily family); + InverseServerSocket(InverseServerSocket const &) = delete; + InverseServerSocket(InverseServerSocket &&) = delete; + ~InverseServerSocket() override; - InverseServerSocket& operator=(InverseServerSocket const &) =delete; - InverseServerSocket& operator=(InverseServerSocket &&) =delete; + InverseServerSocket &operator=(InverseServerSocket const &) = delete; + InverseServerSocket &operator=(InverseServerSocket &&) = delete; - // ISocket overrides - void bind(const NetworkAddress&) override; - void close() override; - void* getEventTarget() const override; + // ISocket overrides + void bind(const NetworkAddress &) override; + void close() override; + void *getEventTarget() const override; - // IListenSocket overrides - IDataSocket* accept() override; + // IListenSocket overrides + IDataSocket *accept() override; protected: - void setListeningJob(bool read = false); + void setListeningJob(bool read = false); public: - ISocketMultiplexerJob* - serviceListening(ISocketMultiplexerJob*, - bool, bool, bool); + ISocketMultiplexerJob *serviceListening(ISocketMultiplexerJob *, bool, bool, + bool); protected: - AutoArchSocket m_socket; - Mutex m_mutex; - IEventQueue* m_events; - SocketMultiplexer* m_socketMultiplexer; + AutoArchSocket m_socket; + Mutex m_mutex; + IEventQueue *m_events; + SocketMultiplexer *m_socketMultiplexer; private: - NetworkAddress m_address; + NetworkAddress m_address; }; diff --git a/src/lib/net/InverseSockets/InverseSocketFactory.cpp b/src/lib/net/InverseSockets/InverseSocketFactory.cpp index 2c2f54fca..8840da937 100644 --- a/src/lib/net/InverseSockets/InverseSocketFactory.cpp +++ b/src/lib/net/InverseSockets/InverseSocketFactory.cpp @@ -24,35 +24,32 @@ // InverseSocketFactory // -InverseSocketFactory::InverseSocketFactory(IEventQueue* events, SocketMultiplexer* socketMultiplexer) : - m_events(events), - m_socketMultiplexer(socketMultiplexer) -{ +InverseSocketFactory::InverseSocketFactory(IEventQueue *events, + SocketMultiplexer *socketMultiplexer) + : m_events(events), m_socketMultiplexer(socketMultiplexer) {} + +IDataSocket * +InverseSocketFactory::create(bool secure, + IArchNetwork::EAddressFamily family) const { + if (secure) { + auto secureSocket = + new SecureClientSocket(m_events, m_socketMultiplexer, family); + return secureSocket; + } else { + return new InverseClientSocket(m_events, m_socketMultiplexer, family); + } } -IDataSocket* -InverseSocketFactory::create(bool secure, IArchNetwork::EAddressFamily family) const -{ - if (secure) { - auto secureSocket = new SecureClientSocket(m_events, m_socketMultiplexer, family); - return secureSocket; - } - else { - return new InverseClientSocket(m_events, m_socketMultiplexer, family); - } -} - -IListenSocket* -InverseSocketFactory::createListen(bool secure, IArchNetwork::EAddressFamily family) const -{ - IListenSocket* socket = nullptr; - - if (secure) { - socket = new SecureServerSocket(m_events, m_socketMultiplexer, family); - } - else { - socket = new InverseServerSocket(m_events, m_socketMultiplexer, family); - } - - return socket; +IListenSocket * +InverseSocketFactory::createListen(bool secure, + IArchNetwork::EAddressFamily family) const { + IListenSocket *socket = nullptr; + + if (secure) { + socket = new SecureServerSocket(m_events, m_socketMultiplexer, family); + } else { + socket = new InverseServerSocket(m_events, m_socketMultiplexer, family); + } + + return socket; } diff --git a/src/lib/net/InverseSockets/InverseSocketFactory.h b/src/lib/net/InverseSockets/InverseSocketFactory.h index 64f92d7a5..4526eacfb 100644 --- a/src/lib/net/InverseSockets/InverseSocketFactory.h +++ b/src/lib/net/InverseSockets/InverseSocketFactory.h @@ -22,13 +22,17 @@ class SocketMultiplexer; class InverseSocketFactory : public ISocketFactory { public: - InverseSocketFactory(IEventQueue* events, SocketMultiplexer* socketMultiplexer); + InverseSocketFactory(IEventQueue *events, + SocketMultiplexer *socketMultiplexer); - // ISocketFactory overrides - IDataSocket* create(bool secure, IArchNetwork::EAddressFamily family = IArchNetwork::kINET) const override; - IListenSocket* createListen(bool secure, IArchNetwork::EAddressFamily family = IArchNetwork::kINET) const override; + // ISocketFactory overrides + IDataSocket *create(bool secure, IArchNetwork::EAddressFamily family = + IArchNetwork::kINET) const override; + IListenSocket *createListen( + bool secure, + IArchNetwork::EAddressFamily family = IArchNetwork::kINET) const override; private: - IEventQueue* m_events = nullptr; - SocketMultiplexer* m_socketMultiplexer = nullptr; + IEventQueue *m_events = nullptr; + SocketMultiplexer *m_socketMultiplexer = nullptr; }; diff --git a/src/lib/net/InverseSockets/SecureClientSocket.cpp b/src/lib/net/InverseSockets/SecureClientSocket.cpp index 4a90dfbdc..83e1b1d84 100644 --- a/src/lib/net/InverseSockets/SecureClientSocket.cpp +++ b/src/lib/net/InverseSockets/SecureClientSocket.cpp @@ -18,19 +18,19 @@ #include "SecureClientSocket.h" #include "SslLogger.h" +#include #include #include -#include #include #include #include -#include #include +#include -#include #include +#include #include #include @@ -40,453 +40,395 @@ // constexpr float s_retryDelay = 0.01f; -SecureClientSocket::SecureClientSocket(IEventQueue* events, - SocketMultiplexer* socketMultiplexer, IArchNetwork::EAddressFamily family) : - InverseClientSocket(events, socketMultiplexer, family) -{ +SecureClientSocket::SecureClientSocket(IEventQueue *events, + SocketMultiplexer *socketMultiplexer, + IArchNetwork::EAddressFamily family) + : InverseClientSocket(events, socketMultiplexer, family) {} + +void SecureClientSocket::connect(const NetworkAddress &addr) { + m_events->adoptHandler(m_events->forIDataSocket().connected(), + getEventTarget(), + new TMethodEventJob( + this, &SecureClientSocket::handleTCPConnected)); + + InverseClientSocket::connect(addr); } -void -SecureClientSocket::connect(const NetworkAddress& addr) -{ - m_events->adoptHandler(m_events->forIDataSocket().connected(), - getEventTarget(), - new TMethodEventJob(this, - &SecureClientSocket::handleTCPConnected)); +ISocketMultiplexerJob *SecureClientSocket::newJob() { + // after TCP connection is established, SecureClientSocket will pick up + // connected event and do secureConnect + if (m_connected && !m_secureReady) { + return nullptr; + } - InverseClientSocket::connect(addr); + return InverseClientSocket::newJob(getSocket()); } -ISocketMultiplexerJob* -SecureClientSocket::newJob() -{ - // after TCP connection is established, SecureClientSocket will pick up - // connected event and do secureConnect - if (m_connected && !m_secureReady) { - return nullptr; - } - - return InverseClientSocket::newJob(getSocket()); +void SecureClientSocket::secureConnect() { + setJob(new TSocketMultiplexerMethodJob( + this, &SecureClientSocket::serviceConnect, getSocket(), isReadable(), + isWritable())); } - -void -SecureClientSocket::secureConnect() -{ - setJob(new TSocketMultiplexerMethodJob( - this, &SecureClientSocket::serviceConnect, - getSocket(), isReadable(), isWritable())); +void SecureClientSocket::secureAccept() { + setJob(new TSocketMultiplexerMethodJob( + this, &SecureClientSocket::serviceAccept, getSocket(), isReadable(), + isWritable())); } -void -SecureClientSocket::secureAccept() -{ - setJob(new TSocketMultiplexerMethodJob( - this, &SecureClientSocket::serviceAccept, - getSocket(), isReadable(), isWritable())); -} +InverseClientSocket::EJobResult SecureClientSocket::doRead() { + UInt8 buffer[4096] = {0}; + int bytesRead = 0; + int status = 0; -InverseClientSocket::EJobResult -SecureClientSocket::doRead() -{ - UInt8 buffer[4096] = {0}; - int bytesRead = 0; - int status = 0; + if (isSecureReady()) { + status = secureRead(buffer, sizeof(buffer), bytesRead); - if (isSecureReady()) { - status = secureRead(buffer, sizeof(buffer), bytesRead); - - if (status < 0) { - return InverseClientSocket::EJobResult::kBreak; - } - else if (status == 0) { - return InverseClientSocket::EJobResult::kNew; - } + if (status < 0) { + return InverseClientSocket::EJobResult::kBreak; + } else if (status == 0) { + return InverseClientSocket::EJobResult::kNew; } - else { - return InverseClientSocket::EJobResult::kRetry; - } - - if (bytesRead > 0) { - bool wasEmpty = (m_inputBuffer.getSize() == 0); - - // slurp up as much as possible - do { - m_inputBuffer.write(buffer, bytesRead); - - status = secureRead(buffer, sizeof(buffer), bytesRead); - if (status < 0) { - return InverseClientSocket::EJobResult::kBreak; - } - } while (bytesRead > 0 || status > 0); - - // send input ready if input buffer was empty - if (wasEmpty) { - sendEvent(m_events->forIStream().inputReady()); - } - } - else { - // remote write end of stream hungup. our input side - // has therefore shutdown but don't flush our buffer - // since there's still data to be read. - sendEvent(m_events->forIStream().inputShutdown()); - if (!m_writable && m_inputBuffer.getSize() == 0) { - sendEvent(m_events->forISocket().disconnected()); - m_connected = false; - } - m_readable = false; - return InverseClientSocket::EJobResult::kNew; - } - + } else { return InverseClientSocket::EJobResult::kRetry; + } + + if (bytesRead > 0) { + bool wasEmpty = (m_inputBuffer.getSize() == 0); + + // slurp up as much as possible + do { + m_inputBuffer.write(buffer, bytesRead); + + status = secureRead(buffer, sizeof(buffer), bytesRead); + if (status < 0) { + return InverseClientSocket::EJobResult::kBreak; + } + } while (bytesRead > 0 || status > 0); + + // send input ready if input buffer was empty + if (wasEmpty) { + sendEvent(m_events->forIStream().inputReady()); + } + } else { + // remote write end of stream hungup. our input side + // has therefore shutdown but don't flush our buffer + // since there's still data to be read. + sendEvent(m_events->forIStream().inputShutdown()); + if (!m_writable && m_inputBuffer.getSize() == 0) { + sendEvent(m_events->forISocket().disconnected()); + m_connected = false; + } + m_readable = false; + return InverseClientSocket::EJobResult::kNew; + } + + return InverseClientSocket::EJobResult::kRetry; } -InverseClientSocket::EJobResult -SecureClientSocket::doWrite() -{ - static bool s_retry = false; - static int s_retrySize = 0; - static int s_staticBufferSize = 0; - static void* s_staticBuffer = nullptr; +InverseClientSocket::EJobResult SecureClientSocket::doWrite() { + static bool s_retry = false; + static int s_retrySize = 0; + static int s_staticBufferSize = 0; + static void *s_staticBuffer = nullptr; - // write data - int bufferSize = 0; - int bytesWrote = 0; - int status = 0; + // write data + int bufferSize = 0; + int bytesWrote = 0; + int status = 0; - if (s_retry) { - bufferSize = s_retrySize; - } - else { - bufferSize = m_outputBuffer.getSize(); - if (bufferSize != 0) { - if (bufferSize > s_staticBufferSize) { - s_staticBuffer = realloc(s_staticBuffer, bufferSize); - s_staticBufferSize = bufferSize; - } - memcpy(s_staticBuffer, m_outputBuffer.peek(bufferSize), bufferSize); - } - } - - if (bufferSize == 0) { - return InverseClientSocket::EJobResult::kRetry; - } - - if (isSecureReady()) { - status = secureWrite(s_staticBuffer, bufferSize, bytesWrote); - if (status > 0) { - s_retry = false; - } - else if (status < 0) { - return InverseClientSocket::EJobResult::kBreak; - } - else if (status == 0) { - s_retry = true; - s_retrySize = bufferSize; - return InverseClientSocket::EJobResult::kNew; - } - } - else { - return InverseClientSocket::EJobResult::kRetry; - } - - if (bytesWrote > 0) { - discardWrittenData(bytesWrote); - return InverseClientSocket::EJobResult::kNew; + if (s_retry) { + bufferSize = s_retrySize; + } else { + bufferSize = m_outputBuffer.getSize(); + if (bufferSize != 0) { + if (bufferSize > s_staticBufferSize) { + s_staticBuffer = realloc(s_staticBuffer, bufferSize); + s_staticBufferSize = bufferSize; + } + memcpy(s_staticBuffer, m_outputBuffer.peek(bufferSize), bufferSize); } + } + if (bufferSize == 0) { return InverseClientSocket::EJobResult::kRetry; + } + + if (isSecureReady()) { + status = secureWrite(s_staticBuffer, bufferSize, bytesWrote); + if (status > 0) { + s_retry = false; + } else if (status < 0) { + return InverseClientSocket::EJobResult::kBreak; + } else if (status == 0) { + s_retry = true; + s_retrySize = bufferSize; + return InverseClientSocket::EJobResult::kNew; + } + } else { + return InverseClientSocket::EJobResult::kRetry; + } + + if (bytesWrote > 0) { + discardWrittenData(bytesWrote); + return InverseClientSocket::EJobResult::kNew; + } + + return InverseClientSocket::EJobResult::kRetry; } -int -SecureClientSocket::secureRead(void* buffer, int size, int& read) -{ - LOG((CLOG_DEBUG2 "reading secure socket")); - read = m_ssl.read(static_cast(buffer), size); +int SecureClientSocket::secureRead(void *buffer, int size, int &read) { + LOG((CLOG_DEBUG2 "reading secure socket")); + read = m_ssl.read(static_cast(buffer), size); - static int retry = 0; + static int retry = 0; - // Check result will cleanup the connection in the case of a fatal - checkResult(read, retry); + // Check result will cleanup the connection in the case of a fatal + checkResult(read, retry); - if (retry) { - return 0; - } + if (retry) { + return 0; + } - if (isFatal()) { - return -1; - } - // According to SSL spec, the number of bytes read must not be negative and - // not have an error code from SSL_get_error(). If this happens, it is - // itself an error. Let the parent handle the case - return read; -} - -int -SecureClientSocket::secureWrite(const void* buffer, int size, int& wrote) -{ - LOG((CLOG_DEBUG2 "writing secure socket: %p", this)); - wrote = m_ssl.write(static_cast(buffer), size); - - static int retry = 0; - - // Check result will cleanup the connection in the case of a fatal - checkResult(wrote, retry); - - if (retry) { - return 0; - } - - if (isFatal()) { - return -1; - } - - // According to SSL spec, r must not be negative and not have an error code - // from SSL_get_error(). If this happens, it is itself an error. Let the - // parent handle the case - return wrote; -} - -bool -SecureClientSocket::isSecureReady() const -{ - return m_secureReady; -} - -bool -SecureClientSocket::loadCertificates(const std::string& filename) -{ - return m_ssl.loadCertificate(filename); -} - -int -SecureClientSocket::secureAccept(int socket) -{ - LOG((CLOG_DEBUG2 "accepting secure socket")); - static int retry = 0; - checkResult(m_ssl.accept(socket), retry); - - if (isFatal()) { - // tell user and sleep so the socket isn't hammered. - LOG((CLOG_ERR "failed to accept secure socket")); - LOG((CLOG_WARN "client connection may not be secure")); - m_secureReady = false; - ARCH->sleep(1); - retry = 0; - return -1; // Failed, error out - } - - // If not fatal and no retry, state is good - if (retry == 0) { - m_secureReady = true; - LOG((CLOG_INFO "accepted secure socket")); - m_ssl.logSecureInfo(); - return 1; - } - - // If not fatal and retry is set, not ready, and return retry - if (retry > 0) { - LOG((CLOG_DEBUG2 "retry accepting secure socket")); - m_secureReady = false; - ARCH->sleep(s_retryDelay); - return 0; - } - - // no good state exists here - LOG((CLOG_ERR "unexpected state attempting to accept connection")); + if (isFatal()) { return -1; + } + // According to SSL spec, the number of bytes read must not be negative and + // not have an error code from SSL_get_error(). If this happens, it is + // itself an error. Let the parent handle the case + return read; } -int -SecureClientSocket::secureConnect(int socket) -{ - LOG((CLOG_DEBUG2 "connecting secure socket")); - static int retry = 0; - checkResult(m_ssl.connect(socket), retry); +int SecureClientSocket::secureWrite(const void *buffer, int size, int &wrote) { + LOG((CLOG_DEBUG2 "writing secure socket: %p", this)); + wrote = m_ssl.write(static_cast(buffer), size); - if (isFatal()) { - LOG((CLOG_ERR "failed to connect secure socket")); - retry = 0; - return -1; - } + static int retry = 0; - // If we should retry, not ready and return 0 - if (retry > 0) { - LOG((CLOG_DEBUG2 "retry connect secure socket")); - m_secureReady = false; - ARCH->sleep(s_retryDelay); - return 0; - } + // Check result will cleanup the connection in the case of a fatal + checkResult(wrote, retry); + if (retry) { + return 0; + } + + if (isFatal()) { + return -1; + } + + // According to SSL spec, r must not be negative and not have an error code + // from SSL_get_error(). If this happens, it is itself an error. Let the + // parent handle the case + return wrote; +} + +bool SecureClientSocket::isSecureReady() const { return m_secureReady; } + +bool SecureClientSocket::loadCertificates(const std::string &filename) { + return m_ssl.loadCertificate(filename); +} + +int SecureClientSocket::secureAccept(int socket) { + LOG((CLOG_DEBUG2 "accepting secure socket")); + static int retry = 0; + checkResult(m_ssl.accept(socket), retry); + + if (isFatal()) { + // tell user and sleep so the socket isn't hammered. + LOG((CLOG_ERR "failed to accept secure socket")); + LOG((CLOG_WARN "client connection may not be secure")); + m_secureReady = false; + ARCH->sleep(1); retry = 0; - // No error, set ready, process and return ok + return -1; // Failed, error out + } + + // If not fatal and no retry, state is good + if (retry == 0) { m_secureReady = true; + LOG((CLOG_INFO "accepted secure socket")); + m_ssl.logSecureInfo(); + return 1; + } + + // If not fatal and retry is set, not ready, and return retry + if (retry > 0) { + LOG((CLOG_DEBUG2 "retry accepting secure socket")); + m_secureReady = false; + ARCH->sleep(s_retryDelay); + return 0; + } + + // no good state exists here + LOG((CLOG_ERR "unexpected state attempting to accept connection")); + return -1; +} + +int SecureClientSocket::secureConnect(int socket) { + LOG((CLOG_DEBUG2 "connecting secure socket")); + static int retry = 0; + checkResult(m_ssl.connect(socket), retry); + + if (isFatal()) { + LOG((CLOG_ERR "failed to connect secure socket")); + retry = 0; + return -1; + } + + // If we should retry, not ready and return 0 + if (retry > 0) { + LOG((CLOG_DEBUG2 "retry connect secure socket")); + m_secureReady = false; + ARCH->sleep(s_retryDelay); + return 0; + } + + retry = 0; + // No error, set ready, process and return ok + m_secureReady = true; + sendEvent(m_events->forIDataSocket().secureConnected()); + + auto fingerprint = m_ssl.getFingerprint(); + LOG((CLOG_NOTE "server fingerprint: %s", fingerprint.c_str())); + + if (m_ssl.isTrustedFingerprint(fingerprint)) { + LOG((CLOG_INFO "connected to secure socket")); + m_ssl.logSecureInfo(); + return 1; + } else { + LOG((CLOG_ERR "failed to verify server certificate fingerprint")); + disconnect(); + return -1; // Fingerprint failed, error + } +} + +void SecureClientSocket::setFatal(int code) { + const std::set nonFatal{SSL_ERROR_NONE, SSL_ERROR_WANT_READ, + SSL_ERROR_WANT_WRITE, SSL_ERROR_WANT_CONNECT, + SSL_ERROR_WANT_ACCEPT}; + m_fatal = nonFatal.find(code) == nonFatal.end(); +} + +int SecureClientSocket::getRetry(int errorCode, int retry) const { + const std::set retryCodes{SSL_ERROR_WANT_READ, SSL_ERROR_WANT_WRITE, + SSL_ERROR_WANT_CONNECT, SSL_ERROR_WANT_ACCEPT}; + + if (errorCode == SSL_ERROR_NONE || isFatal()) { + retry = 0; + } else if (retryCodes.find(errorCode) != retryCodes.end()) { + ++retry; + } + + return retry; +} + +void SecureClientSocket::checkResult(int status, int &retry) { + // ssl errors are a little quirky. the "want" errors are normal and + // should result in a retry. + int errorCode = m_ssl.getErrorCode(status); + setFatal(errorCode); + retry = getRetry(errorCode, retry); + + switch (errorCode) { + case SSL_ERROR_WANT_WRITE: + // Need to make sure the socket is known to be writable so the impending + // select action actually triggers on a write. This isn't necessary for + // m_readable because the socket logic is always readable + m_writable = true; + break; + + case SSL_ERROR_SYSCALL: + if (ERR_peek_error() == 0) { + if (status == 0) { + LOG((CLOG_ERR "eof violates tls protocol")); + } else if (status == -1) { + // underlying socket I/O reproted an error + try { + ARCH->throwErrorOnSocket(getSocket()); + } catch (const XArchNetwork &e) { + LOG((CLOG_ERR "%s", e.what())); + } + } + } + break; + default: + break; + } + + SslLogger::logErrorByCode(errorCode, retry); + + if (isFatal()) { + SslLogger::logError(); + disconnect(); + } +} + +void SecureClientSocket::disconnect() { + sendEvent(getEvents()->forISocket().stopRetry()); + sendEvent(getEvents()->forISocket().disconnected()); + sendEvent(getEvents()->forIStream().inputShutdown()); +} + +ISocketMultiplexerJob * +SecureClientSocket::serviceConnect(ISocketMultiplexerJob *, bool, bool, bool) { + Lock lock(&getMutex()); + + int status = 0; + +#ifdef SYSAPI_WIN32 + status = secureConnect(static_cast(getSocket()->m_socket)); +#elif SYSAPI_UNIX + status = secureConnect(getSocket()->m_fd); +#endif + + // If status < 0, error happened + if (status < 0) { + return nullptr; + } + + // If status > 0, success + if (status > 0) { sendEvent(m_events->forIDataSocket().secureConnected()); + return newJob(); + } - auto fingerprint = m_ssl.getFingerprint(); - LOG((CLOG_NOTE "server fingerprint: %s", fingerprint.c_str())); - - if (m_ssl.isTrustedFingerprint(fingerprint)) { - LOG((CLOG_INFO "connected to secure socket")); - m_ssl.logSecureInfo(); - return 1; - } - else { - LOG((CLOG_ERR "failed to verify server certificate fingerprint")); - disconnect(); - return -1; // Fingerprint failed, error - } + // Retry case + return new TSocketMultiplexerMethodJob( + this, &SecureClientSocket::serviceConnect, getSocket(), isReadable(), + isWritable()); } -void SecureClientSocket::setFatal(int code) -{ - const std::set nonFatal { - SSL_ERROR_NONE, - SSL_ERROR_WANT_READ, - SSL_ERROR_WANT_WRITE, - SSL_ERROR_WANT_CONNECT, - SSL_ERROR_WANT_ACCEPT - }; - m_fatal = nonFatal.find(code) == nonFatal.end(); -} - -int SecureClientSocket::getRetry(int errorCode, int retry) const -{ - const std::set retryCodes { - SSL_ERROR_WANT_READ, - SSL_ERROR_WANT_WRITE, - SSL_ERROR_WANT_CONNECT, - SSL_ERROR_WANT_ACCEPT - }; - - if (errorCode == SSL_ERROR_NONE || isFatal()) { - retry = 0; - } - else if (retryCodes.find(errorCode) != retryCodes.end()) { - ++retry; - } - - return retry; -} - -void -SecureClientSocket::checkResult(int status, int& retry) -{ - // ssl errors are a little quirky. the "want" errors are normal and - // should result in a retry. - int errorCode = m_ssl.getErrorCode(status); - setFatal(errorCode); - retry = getRetry(errorCode, retry); - - switch (errorCode) { - case SSL_ERROR_WANT_WRITE: - // Need to make sure the socket is known to be writable so the impending - // select action actually triggers on a write. This isn't necessary for - // m_readable because the socket logic is always readable - m_writable = true; - break; - - case SSL_ERROR_SYSCALL: - if (ERR_peek_error() == 0) { - if (status == 0) { - LOG((CLOG_ERR "eof violates tls protocol")); - } - else if (status == -1) { - // underlying socket I/O reproted an error - try { - ARCH->throwErrorOnSocket(getSocket()); - } - catch (const XArchNetwork& e) { - LOG((CLOG_ERR "%s", e.what())); - } - } - } - break; - default: - break; - } - - SslLogger::logErrorByCode(errorCode, retry); - - if (isFatal()) { - SslLogger::logError(); - disconnect(); - } -} - -void -SecureClientSocket::disconnect() -{ - sendEvent(getEvents()->forISocket().stopRetry()); - sendEvent(getEvents()->forISocket().disconnected()); - sendEvent(getEvents()->forIStream().inputShutdown()); -} - -ISocketMultiplexerJob* -SecureClientSocket::serviceConnect(ISocketMultiplexerJob*, bool, bool, bool) -{ - Lock lock(&getMutex()); - - int status = 0; +ISocketMultiplexerJob * +SecureClientSocket::serviceAccept(ISocketMultiplexerJob *, bool, bool, bool) { + Lock lock(&getMutex()); + int status = 0; #ifdef SYSAPI_WIN32 - status = secureConnect(static_cast(getSocket()->m_socket)); + status = secureAccept(static_cast(getSocket()->m_socket)); #elif SYSAPI_UNIX - status = secureConnect(getSocket()->m_fd); + status = secureAccept(getSocket()->m_fd); #endif + // If status < 0, error happened + if (status < 0) { + return nullptr; + } - // If status < 0, error happened - if (status < 0) { - return nullptr; - } + // If status > 0, success + if (status > 0) { + sendEvent(m_events->forClientListener().accepted()); + return newJob(); + } - // If status > 0, success - if (status > 0) { - sendEvent(m_events->forIDataSocket().secureConnected()); - return newJob(); - } - - // Retry case - return new TSocketMultiplexerMethodJob( - this, &SecureClientSocket::serviceConnect, - getSocket(), isReadable(), isWritable()); + // Retry case + return new TSocketMultiplexerMethodJob( + this, &SecureClientSocket::serviceAccept, getSocket(), isReadable(), + isWritable()); } -ISocketMultiplexerJob* -SecureClientSocket::serviceAccept(ISocketMultiplexerJob*, bool, bool, bool) -{ - Lock lock(&getMutex()); - - int status = 0; -#ifdef SYSAPI_WIN32 - status = secureAccept(static_cast(getSocket()->m_socket)); -#elif SYSAPI_UNIX - status = secureAccept(getSocket()->m_fd); -#endif - // If status < 0, error happened - if (status < 0) { - return nullptr; - } - - // If status > 0, success - if (status > 0) { - sendEvent(m_events->forClientListener().accepted()); - return newJob(); - } - - // Retry case - return new TSocketMultiplexerMethodJob( - this, &SecureClientSocket::serviceAccept, - getSocket(), isReadable(), isWritable()); -} - -void -SecureClientSocket::handleTCPConnected(const Event&, void*) -{ - if (getSocket()) { - secureConnect(); - } - else { - LOG((CLOG_DEBUG "disregarding stale connect event")); - } +void SecureClientSocket::handleTCPConnected(const Event &, void *) { + if (getSocket()) { + secureConnect(); + } else { + LOG((CLOG_DEBUG "disregarding stale connect event")); + } } diff --git a/src/lib/net/InverseSockets/SecureClientSocket.h b/src/lib/net/InverseSockets/SecureClientSocket.h index 8bf1ffb4b..4c343f10c 100644 --- a/src/lib/net/InverseSockets/SecureClientSocket.h +++ b/src/lib/net/InverseSockets/SecureClientSocket.h @@ -15,8 +15,8 @@ * along with this program. If not, see . */ #pragma once -#include "SslApi.h" #include "InverseClientSocket.h" +#include "SslApi.h" //! Secure socket /*! @@ -24,48 +24,47 @@ A secure socket using SSL. */ class SecureClientSocket : public InverseClientSocket { public: - SecureClientSocket(IEventQueue* events, SocketMultiplexer* socketMultiplexer, IArchNetwork::EAddressFamily family); - SecureClientSocket(SecureClientSocket const &) =delete; - SecureClientSocket(SecureClientSocket &&) =delete; + SecureClientSocket(IEventQueue *events, SocketMultiplexer *socketMultiplexer, + IArchNetwork::EAddressFamily family); + SecureClientSocket(SecureClientSocket const &) = delete; + SecureClientSocket(SecureClientSocket &&) = delete; - SecureClientSocket& operator=(SecureClientSocket const &) =delete; - SecureClientSocket& operator=(SecureClientSocket &&) =delete; + SecureClientSocket &operator=(SecureClientSocket const &) = delete; + SecureClientSocket &operator=(SecureClientSocket &&) = delete; - // IDataSocket overrides - void connect(const NetworkAddress&) override; + // IDataSocket overrides + void connect(const NetworkAddress &) override; - ISocketMultiplexerJob* newJob(); - bool isFatal() const { return m_fatal; } - void setFatal(int code); - int getRetry(int errorCode, int retry) const; - bool isSecureReady() const; - void secureConnect(); - void secureAccept(); - int secureRead(void* buffer, int size, int& read); - int secureWrite(const void* buffer, int size, int& wrote); - EJobResult doRead() override; - EJobResult doWrite() override; - bool loadCertificates(const std::string& CertFile); + ISocketMultiplexerJob *newJob(); + bool isFatal() const { return m_fatal; } + void setFatal(int code); + int getRetry(int errorCode, int retry) const; + bool isSecureReady() const; + void secureConnect(); + void secureAccept(); + int secureRead(void *buffer, int size, int &read); + int secureWrite(const void *buffer, int size, int &wrote); + EJobResult doRead() override; + EJobResult doWrite() override; + bool loadCertificates(const std::string &CertFile); private: - // SSL - void initContext(bool server); - int secureAccept(int s); - int secureConnect(int s); - void checkResult(int n, int& retry); - void disconnect(); + // SSL + void initContext(bool server); + int secureAccept(int s); + int secureConnect(int s); + void checkResult(int n, int &retry); + void disconnect(); - ISocketMultiplexerJob* - serviceConnect(ISocketMultiplexerJob*, - bool, bool, bool); + ISocketMultiplexerJob *serviceConnect(ISocketMultiplexerJob *, bool, bool, + bool); - ISocketMultiplexerJob* - serviceAccept(ISocketMultiplexerJob*, - bool, bool, bool); + ISocketMultiplexerJob *serviceAccept(ISocketMultiplexerJob *, bool, bool, + bool); - void handleTCPConnected(const Event&, void*); + void handleTCPConnected(const Event &, void *); - synergy::ssl::SslApi m_ssl{false}; - bool m_secureReady = false; - bool m_fatal = false; + synergy::ssl::SslApi m_ssl{false}; + bool m_secureReady = false; + bool m_fatal = false; }; diff --git a/src/lib/net/InverseSockets/SecureServerSocket.cpp b/src/lib/net/InverseSockets/SecureServerSocket.cpp index d62b97ce5..62149ba67 100644 --- a/src/lib/net/InverseSockets/SecureServerSocket.cpp +++ b/src/lib/net/InverseSockets/SecureServerSocket.cpp @@ -17,70 +17,62 @@ #include "SecureServerSocket.h" +#include #include #include -#include #include #include // // SecureServerSocket // -SecureServerSocket::SecureServerSocket( - IEventQueue* events, - SocketMultiplexer* socketMultiplexer, - IArchNetwork::EAddressFamily family) : - InverseServerSocket(events, socketMultiplexer, family) -{ +SecureServerSocket::SecureServerSocket(IEventQueue *events, + SocketMultiplexer *socketMultiplexer, + IArchNetwork::EAddressFamily family) + : InverseServerSocket(events, socketMultiplexer, family) {} + +IDataSocket *SecureServerSocket::accept() { + SecureSocket *socket = nullptr; + + try { + socket = new SecureSocket(m_events, m_socketMultiplexer, + m_socket.getRawSocket()); + socket->initSsl(true); + setListeningJob(); + + auto certificateFilename = getCertifcateFileName(); + if (socket->loadCertificates(certificateFilename)) { + socket->secureAccept(); + } else { + delete socket; + socket = nullptr; + } + } catch (const XArchNetwork &) { + if (socket) { + delete socket; + socket = nullptr; + setListeningJob(); + } + } catch (const std::exception &) { + if (socket) { + delete socket; + setListeningJob(); + } + throw; + } + + return dynamic_cast(socket); } -IDataSocket* -SecureServerSocket::accept() -{ - SecureSocket* socket = nullptr; +std::string SecureServerSocket::getCertifcateFileName() const { + // if the tls cert option is set use that for the certificate file + auto certificateFilename = ArgParser::argsBase().m_tlsCertFile; - try { - socket = new SecureSocket(m_events, m_socketMultiplexer, m_socket.getRawSocket()); - socket->initSsl(true); - setListeningJob(); + if (certificateFilename.empty()) { + // default location of the TLS cert file in users dir + certificateFilename = synergy::string::sprintf( + "%s/SSL/Synergy.pem", ARCH->getProfileDirectory().c_str()); + } - auto certificateFilename = getCertifcateFileName(); - if (socket->loadCertificates(certificateFilename)) { - socket->secureAccept(); - } - else { - delete socket; - socket = nullptr; - } - } - catch (const XArchNetwork&) { - if (socket) { - delete socket; - socket = nullptr; - setListeningJob(); - } - } - catch (const std::exception&) { - if (socket) { - delete socket; - setListeningJob(); - } - throw; - } - - return dynamic_cast(socket); -} - -std::string -SecureServerSocket::getCertifcateFileName() const -{ - //if the tls cert option is set use that for the certificate file - auto certificateFilename = ArgParser::argsBase().m_tlsCertFile; - - if (certificateFilename.empty()) { - //default location of the TLS cert file in users dir - certificateFilename = synergy::string::sprintf("%s/SSL/Synergy.pem", ARCH->getProfileDirectory().c_str()); - } - - return certificateFilename; + return certificateFilename; } diff --git a/src/lib/net/InverseSockets/SecureServerSocket.h b/src/lib/net/InverseSockets/SecureServerSocket.h index 6e808f310..1bec6dcd9 100644 --- a/src/lib/net/InverseSockets/SecureServerSocket.h +++ b/src/lib/net/InverseSockets/SecureServerSocket.h @@ -19,12 +19,12 @@ class SecureServerSocket : public InverseServerSocket { public: - SecureServerSocket(IEventQueue* events, - SocketMultiplexer* socketMultiplexer, IArchNetwork::EAddressFamily family); + SecureServerSocket(IEventQueue *events, SocketMultiplexer *socketMultiplexer, + IArchNetwork::EAddressFamily family); - // IListenSocket overrides - IDataSocket* accept() override; + // IListenSocket overrides + IDataSocket *accept() override; private: - std::string getCertifcateFileName() const; + std::string getCertifcateFileName() const; }; diff --git a/src/lib/net/InverseSockets/SslApi.cpp b/src/lib/net/InverseSockets/SslApi.cpp index aa3f0c4b9..719b848aa 100644 --- a/src/lib/net/InverseSockets/SslApi.cpp +++ b/src/lib/net/InverseSockets/SslApi.cpp @@ -1,8 +1,8 @@ #include "SslApi.h" #include "SslLogger.h" -#include #include +#include #include #include @@ -13,248 +13,235 @@ namespace ssl { using AutoX509 = std::unique_ptr; -SslApi::SslApi(bool isServer) -{ - SSL_library_init(); - // load & register all cryptos, etc. - OpenSSL_add_all_algorithms(); - // load all error messages - SSL_load_error_strings(); - createContext(isServer); - SslLogger::logSecureLibInfo(); +SslApi::SslApi(bool isServer) { + SSL_library_init(); + // load & register all cryptos, etc. + OpenSSL_add_all_algorithms(); + // load all error messages + SSL_load_error_strings(); + createContext(isServer); + SslLogger::logSecureLibInfo(); } -SslApi::~SslApi() -{ - if (m_ssl) { - SSL_shutdown(m_ssl); - SSL_free(m_ssl); - m_ssl = nullptr; - } +SslApi::~SslApi() { + if (m_ssl) { + SSL_shutdown(m_ssl); + SSL_free(m_ssl); + m_ssl = nullptr; + } - if (m_context) { - SSL_CTX_free(m_context); - m_context = nullptr; - } + if (m_context) { + SSL_CTX_free(m_context); + m_context = nullptr; + } } -int SslApi::read(char* buffer, int size) -{ - auto read = 0; +int SslApi::read(char *buffer, int size) { + auto read = 0; - if (m_ssl) { - read = SSL_read(m_ssl, buffer, size); - } + if (m_ssl) { + read = SSL_read(m_ssl, buffer, size); + } - return read; + return read; } -int SslApi::write(const char* buffer, int size) -{ - auto wrote = 0; +int SslApi::write(const char *buffer, int size) { + auto wrote = 0; - if (m_ssl) { - wrote = SSL_write(m_ssl, buffer, size); - } + if (m_ssl) { + wrote = SSL_write(m_ssl, buffer, size); + } - return wrote; + return wrote; } -int SslApi::accept(int socket) -{ - int result = 0; +int SslApi::accept(int socket) { + int result = 0; - if (m_ssl) { - // set connection socket to SSL state - SSL_set_fd(m_ssl, socket); - result = SSL_accept(m_ssl); - } + if (m_ssl) { + // set connection socket to SSL state + SSL_set_fd(m_ssl, socket); + result = SSL_accept(m_ssl); + } - return result; + return result; } -int SslApi::connect(int socket) -{ - auto result = 0; +int SslApi::connect(int socket) { + auto result = 0; - if (m_ssl) { - // attach the socket descriptor - SSL_set_fd(m_ssl, socket); - result = SSL_connect(m_ssl); - } + if (m_ssl) { + // attach the socket descriptor + SSL_set_fd(m_ssl, socket); + result = SSL_connect(m_ssl); + } - return result; + return result; } -void SslApi::createSSL() -{ - if (m_ssl == nullptr && m_context != nullptr) { - m_ssl = SSL_new(m_context); - } +void SslApi::createSSL() { + if (m_ssl == nullptr && m_context != nullptr) { + m_ssl = SSL_new(m_context); + } } -bool SslApi::loadCertificate(const std::string& filename) -{ - bool result = false; +bool SslApi::loadCertificate(const std::string &filename) { + bool result = false; - if (isCertificateExists(filename)) { - auto r = SSL_CTX_use_certificate_file(m_context, filename.c_str(), SSL_FILETYPE_PEM); - if (r <= 0) { - SslLogger::logError("could not use tls certificate"); - return false; - } - - r = SSL_CTX_use_PrivateKey_file(m_context, filename.c_str(), SSL_FILETYPE_PEM); - if (r <= 0) { - SslLogger::logError("could not use tls private key"); - return false; - } - - r = SSL_CTX_check_private_key(m_context); - if (!r) { - SslLogger::logError("could not verify tls private key"); - return false; - } + if (isCertificateExists(filename)) { + auto r = SSL_CTX_use_certificate_file(m_context, filename.c_str(), + SSL_FILETYPE_PEM); + if (r <= 0) { + SslLogger::logError("could not use tls certificate"); + return false; } - return result; -} - -bool SslApi::showCertificate() const -{ - bool result = false; - - if (m_ssl) { - // get the server's certificate - AutoX509 cert(SSL_get_peer_certificate(m_ssl), &X509_free); - if (cert) { - auto line = X509_NAME_oneline(X509_get_subject_name(cert.get()), nullptr, 0); - LOG((CLOG_INFO "server tls certificate info: %s", line)); - OPENSSL_free(line); - result = true; - } - else { - SslLogger::logError("server has no tls certificate"); - } + r = SSL_CTX_use_PrivateKey_file(m_context, filename.c_str(), + SSL_FILETYPE_PEM); + if (r <= 0) { + SslLogger::logError("could not use tls private key"); + return false; } - return result; + r = SSL_CTX_check_private_key(m_context); + if (!r) { + SslLogger::logError("could not verify tls private key"); + return false; + } + } + + return result; } -std::string SslApi::getFingerprint() const -{ - // calculate received certificate fingerprint +bool SslApi::showCertificate() const { + bool result = false; + + if (m_ssl) { + // get the server's certificate AutoX509 cert(SSL_get_peer_certificate(m_ssl), &X509_free); - unsigned int tempFingerprintLen = 0; - unsigned char tempFingerprint[EVP_MAX_MD_SIZE] = {0}; - int digestResult = X509_digest(cert.get(), EVP_sha256(), tempFingerprint, &tempFingerprintLen); - - if (digestResult <= 0) { - LOG((CLOG_ERR "failed to calculate fingerprint, digest result: %d", digestResult)); - return ""; + if (cert) { + auto line = + X509_NAME_oneline(X509_get_subject_name(cert.get()), nullptr, 0); + LOG((CLOG_INFO "server tls certificate info: %s", line)); + OPENSSL_free(line); + result = true; + } else { + SslLogger::logError("server has no tls certificate"); } + } - // format fingerprint into hexdecimal format with colon separator - std::string fingerprint(static_cast(static_cast(tempFingerprint)), tempFingerprintLen); - formatFingerprint(fingerprint); - - return fingerprint; + return result; } -bool SslApi::isTrustedFingerprint(const std::string& fingerprint) const -{ - auto trustedServersFilename = synergy::string::sprintf( - "%s/SSL/Fingerprints/TrustedServers.txt", - ARCH->getProfileDirectory().c_str()); +std::string SslApi::getFingerprint() const { + // calculate received certificate fingerprint + AutoX509 cert(SSL_get_peer_certificate(m_ssl), &X509_free); + unsigned int tempFingerprintLen = 0; + unsigned char tempFingerprint[EVP_MAX_MD_SIZE] = {0}; + int digestResult = X509_digest(cert.get(), EVP_sha256(), tempFingerprint, + &tempFingerprintLen); - // check if this fingerprint exist - std::ifstream file; - file.open(synergy::filesystem::path(trustedServersFilename)); + if (digestResult <= 0) { + LOG((CLOG_ERR "failed to calculate fingerprint, digest result: %d", + digestResult)); + return ""; + } - bool isValid = false; - if (file.is_open()) { - while (!file.eof()) { - std::string fileLine; - getline(file, fileLine); - if (!fileLine.empty() && !fileLine.compare(fingerprint)) { - isValid = true; - break; - } - } - } - else { - LOG((CLOG_ERR "failed to open trusted fingerprints file: %s", trustedServersFilename.c_str())); - } + // format fingerprint into hexdecimal format with colon separator + std::string fingerprint( + static_cast(static_cast(tempFingerprint)), + tempFingerprintLen); + formatFingerprint(fingerprint); - return (isValid && showCertificate()); + return fingerprint; } +bool SslApi::isTrustedFingerprint(const std::string &fingerprint) const { + auto trustedServersFilename = + synergy::string::sprintf("%s/SSL/Fingerprints/TrustedServers.txt", + ARCH->getProfileDirectory().c_str()); -void SslApi::createContext(bool isServer) -{ - // create new context from method - if (isServer) { - m_context = SSL_CTX_new(SSLv23_server_method()); - } - else { - m_context = SSL_CTX_new(SSLv23_client_method()); - } - //Prevent the usage of of all version prior to TLSv1.2 as they are known to be vulnerable - SSL_CTX_set_options(m_context, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1); + // check if this fingerprint exist + std::ifstream file; + file.open(synergy::filesystem::path(trustedServersFilename)); - if (m_context) { - m_ssl = SSL_new(m_context); - } - else { - SslLogger::logError(); + bool isValid = false; + if (file.is_open()) { + while (!file.eof()) { + std::string fileLine; + getline(file, fileLine); + if (!fileLine.empty() && !fileLine.compare(fingerprint)) { + isValid = true; + break; + } } + } else { + LOG((CLOG_ERR "failed to open trusted fingerprints file: %s", + trustedServersFilename.c_str())); + } + + return (isValid && showCertificate()); } -void SslApi::logSecureInfo() const -{ - SslLogger::logSecureCipherInfo(m_ssl); - SslLogger::logSecureConnectInfo(m_ssl); +void SslApi::createContext(bool isServer) { + // create new context from method + if (isServer) { + m_context = SSL_CTX_new(SSLv23_server_method()); + } else { + m_context = SSL_CTX_new(SSLv23_client_method()); + } + // Prevent the usage of of all version prior to TLSv1.2 as they are known to + // be vulnerable + SSL_CTX_set_options(m_context, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | + SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1); + if (m_context) { + m_ssl = SSL_new(m_context); + } else { + SslLogger::logError(); + } } -int SslApi::getErrorCode(int status) const -{ - return SSL_get_error(m_ssl, status); +void SslApi::logSecureInfo() const { + SslLogger::logSecureCipherInfo(m_ssl); + SslLogger::logSecureConnectInfo(m_ssl); } -void SslApi::formatFingerprint(std::string &fingerprint) const -{ - // to hexidecimal - synergy::string::toHex(fingerprint, 2); - // all uppercase - synergy::string::uppercase(fingerprint); - // add colon to separate each 2 charactors - size_t separators = fingerprint.size() / 2; - for (size_t i = 1; i < separators; i++) { - fingerprint.insert(i * 3 - 1, ":"); +int SslApi::getErrorCode(int status) const { + return SSL_get_error(m_ssl, status); +} + +void SslApi::formatFingerprint(std::string &fingerprint) const { + // to hexidecimal + synergy::string::toHex(fingerprint, 2); + // all uppercase + synergy::string::uppercase(fingerprint); + // add colon to separate each 2 charactors + size_t separators = fingerprint.size() / 2; + for (size_t i = 1; i < separators; i++) { + fingerprint.insert(i * 3 - 1, ":"); + } +} + +bool SslApi::isCertificateExists(const std::string &filename) const { + bool result = (!filename.empty()); + + if (result) { + std::ifstream file(synergy::filesystem::path(filename)); + result = file.good(); + + if (!result) { + std::string errorMsg("tls certificate doesn't exist: "); + errorMsg.append(filename); + SslLogger::logError(errorMsg.c_str()); } + } else { + SslLogger::logError("tls certificate is not specified"); + } + + return result; } -bool SslApi::isCertificateExists(const std::string &filename) const -{ - bool result = (!filename.empty()); - - if (result) { - std::ifstream file(synergy::filesystem::path(filename)); - result = file.good(); - - if (!result) { - std::string errorMsg("tls certificate doesn't exist: "); - errorMsg.append(filename); - SslLogger::logError(errorMsg.c_str()); - } - } - else { - SslLogger::logError("tls certificate is not specified"); - } - - return result; -} - -} //namespace ssl -} //namespace synergy +} // namespace ssl +} // namespace synergy diff --git a/src/lib/net/InverseSockets/SslApi.h b/src/lib/net/InverseSockets/SslApi.h index d9110ef25..8a8e82266 100644 --- a/src/lib/net/InverseSockets/SslApi.h +++ b/src/lib/net/InverseSockets/SslApi.h @@ -15,42 +15,41 @@ * along with this program. If not, see . */ #pragma once -#include #include +#include namespace synergy { namespace ssl { -class SslApi -{ +class SslApi { public: - explicit SslApi(bool isServer = false); - SslApi(SslApi const &) =delete; - SslApi& operator=(SslApi const &) =delete; - ~SslApi(); + explicit SslApi(bool isServer = false); + SslApi(SslApi const &) = delete; + SslApi &operator=(SslApi const &) = delete; + ~SslApi(); - int read(char* buffer, int size); - int write(const char* buffer, int size); - int accept(int socket); - int connect(int socket); + int read(char *buffer, int size); + int write(const char *buffer, int size); + int accept(int socket); + int connect(int socket); - bool loadCertificate(const std::string& filename); - bool showCertificate() const; - std::string getFingerprint() const; - bool isTrustedFingerprint(const std::string& fingerprint) const; + bool loadCertificate(const std::string &filename); + bool showCertificate() const; + std::string getFingerprint() const; + bool isTrustedFingerprint(const std::string &fingerprint) const; - void logSecureInfo() const; - int getErrorCode(int status) const; + void logSecureInfo() const; + int getErrorCode(int status) const; private: - void createSSL(); - void formatFingerprint(std::string& fingerprint) const; - bool isCertificateExists(const std::string& filename) const; - void createContext(bool isServer = false); + void createSSL(); + void formatFingerprint(std::string &fingerprint) const; + bool isCertificateExists(const std::string &filename) const; + void createContext(bool isServer = false); - SSL* m_ssl = nullptr; - SSL_CTX* m_context = nullptr; + SSL *m_ssl = nullptr; + SSL_CTX *m_context = nullptr; }; -} //namespace ssl -} //namespace synergy +} // namespace ssl +} // namespace synergy diff --git a/src/lib/net/InverseSockets/SslLogger.cpp b/src/lib/net/InverseSockets/SslLogger.cpp index 23f9ac340..dcb3d7ea3 100644 --- a/src/lib/net/InverseSockets/SslLogger.cpp +++ b/src/lib/net/InverseSockets/SslLogger.cpp @@ -15,8 +15,8 @@ * along with this program. If not, see . */ #include "SslLogger.h" -#include #include +#include #include #include @@ -24,164 +24,154 @@ namespace { -void showCipherStackDesc(STACK_OF(SSL_CIPHER)* stack) -{ - char msg[128] = {0}; - for (int i = 0; i < sk_SSL_CIPHER_num(stack); ++i) { - auto cipher = sk_SSL_CIPHER_value(stack, i); - SSL_CIPHER_description(cipher, msg, sizeof(msg)); +void showCipherStackDesc(STACK_OF(SSL_CIPHER) * stack) { + char msg[128] = {0}; + for (int i = 0; i < sk_SSL_CIPHER_num(stack); ++i) { + auto cipher = sk_SSL_CIPHER_value(stack, i); + SSL_CIPHER_description(cipher, msg, sizeof(msg)); - // SSL puts a newline in the description - auto pos = strnlen(msg, sizeof(msg)) - 1; - if (msg[pos] == '\n') { - msg[pos] = '\0'; - } - - LOG((CLOG_DEBUG1 "%s", msg)); + // SSL puts a newline in the description + auto pos = strnlen(msg, sizeof(msg)) - 1; + if (msg[pos] == '\n') { + msg[pos] = '\0'; } + + LOG((CLOG_DEBUG1 "%s", msg)); + } } -void logLocalSecureCipherInfo(const SSL* ssl) -{ - auto sStack = SSL_get_ciphers(ssl); +void logLocalSecureCipherInfo(const SSL *ssl) { + auto sStack = SSL_get_ciphers(ssl); - if (sStack) { - LOG((CLOG_DEBUG1 "available local ciphers:")); - showCipherStackDesc(sStack); - } - else { - LOG((CLOG_DEBUG1 "local cipher list not available")); - } + if (sStack) { + LOG((CLOG_DEBUG1 "available local ciphers:")); + showCipherStackDesc(sStack); + } else { + LOG((CLOG_DEBUG1 "local cipher list not available")); + } } -void logRemoteSecureCipherInfo(const SSL* ssl) -{ +void logRemoteSecureCipherInfo(const SSL *ssl) { #if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) - // ssl->session->ciphers is not forward compatable, - // In future release of OpenSSL, it's not visible, - // however, LibreSSL still uses this. - auto cStack = ssl->session->ciphers; + // ssl->session->ciphers is not forward compatable, + // In future release of OpenSSL, it's not visible, + // however, LibreSSL still uses this. + auto cStack = ssl->session->ciphers; #else - // Use SSL_get_client_ciphers() for newer versions of OpenSSL. - auto cStack = SSL_get_client_ciphers(ssl); + // Use SSL_get_client_ciphers() for newer versions of OpenSSL. + auto cStack = SSL_get_client_ciphers(ssl); #endif - if (cStack) { - LOG((CLOG_DEBUG1 "available remote ciphers:")); - showCipherStackDesc(cStack); - } - else { - LOG((CLOG_DEBUG1 "remote cipher list not available")); - } + if (cStack) { + LOG((CLOG_DEBUG1 "available remote ciphers:")); + showCipherStackDesc(cStack); + } else { + LOG((CLOG_DEBUG1 "remote cipher list not available")); + } } -}// namespace +} // namespace -void SslLogger::logSecureLibInfo() -{ - if (CLOG->getFilter() >= kDEBUG) { - LOG((CLOG_DEBUG "openssl version: %s", SSLeay_version(SSLEAY_VERSION))); - LOG((CLOG_DEBUG1 "openssl flags: %s", SSLeay_version(SSLEAY_CFLAGS))); - LOG((CLOG_DEBUG1 "openssl built on: %s", SSLeay_version(SSLEAY_BUILT_ON))); - LOG((CLOG_DEBUG1 "openssl platform: %s", SSLeay_version(SSLEAY_PLATFORM))); - LOG((CLOG_DEBUG1 "openssl dir: %s", SSLeay_version(SSLEAY_DIR))); - } +void SslLogger::logSecureLibInfo() { + if (CLOG->getFilter() >= kDEBUG) { + LOG((CLOG_DEBUG "openssl version: %s", SSLeay_version(SSLEAY_VERSION))); + LOG((CLOG_DEBUG1 "openssl flags: %s", SSLeay_version(SSLEAY_CFLAGS))); + LOG((CLOG_DEBUG1 "openssl built on: %s", SSLeay_version(SSLEAY_BUILT_ON))); + LOG((CLOG_DEBUG1 "openssl platform: %s", SSLeay_version(SSLEAY_PLATFORM))); + LOG((CLOG_DEBUG1 "openssl dir: %s", SSLeay_version(SSLEAY_DIR))); + } } -void SslLogger::logSecureCipherInfo(const SSL* ssl) -{ - if (ssl && CLOG->getFilter() >= kDEBUG1) { - logLocalSecureCipherInfo(ssl); - logRemoteSecureCipherInfo(ssl); - } +void SslLogger::logSecureCipherInfo(const SSL *ssl) { + if (ssl && CLOG->getFilter() >= kDEBUG1) { + logLocalSecureCipherInfo(ssl); + logRemoteSecureCipherInfo(ssl); + } } -void SslLogger::logSecureConnectInfo(const SSL* ssl) -{ - if (ssl) { - auto cipher = SSL_get_current_cipher(ssl); +void SslLogger::logSecureConnectInfo(const SSL *ssl) { + if (ssl) { + auto cipher = SSL_get_current_cipher(ssl); - if (cipher) { - char msg[128] = {0}; - SSL_CIPHER_description(cipher, msg, sizeof(msg)); - LOG((CLOG_DEBUG "openssl cipher: %s", msg)); + if (cipher) { + char msg[128] = {0}; + SSL_CIPHER_description(cipher, msg, sizeof(msg)); + LOG((CLOG_DEBUG "openssl cipher: %s", msg)); - //For some reason SSL_get_version is return mismatching information to SSL_CIPHER_description - // so grab the version out the description instead, This seems like a hacky way of doing it. - // But when the cipher says "TLSv1.2" but the get_version returns "TLSv1/SSLv3" we it doesn't look right - // For some reason macOS hates regex's so stringstream is used - std::istringstream iss(msg); + // For some reason SSL_get_version is return mismatching information to + // SSL_CIPHER_description + // so grab the version out the description instead, This seems like a + // hacky way of doing it. But when the cipher says "TLSv1.2" but the + // get_version returns "TLSv1/SSLv3" we it doesn't look right For some + // reason macOS hates regex's so stringstream is used + std::istringstream iss(msg); - //Take the stream input and splits it into a vetor directly - const std::vector parts{std::istream_iterator{iss}, - std::istream_iterator{}}; - if (parts.size() > 2) - { - //log the section containing the protocol version - LOG((CLOG_INFO "network encryption protocol: %s", parts[1].c_str())); - } - else - { - //log the error in spliting then display the whole description rather then nothing - LOG((CLOG_ERR "could not split cipher for protocol")); - LOG((CLOG_INFO "network encryption protocol: %s", msg)); - } - } - else { - LOG((CLOG_ERR "could not get secure socket cipher")); - } + // Take the stream input and splits it into a vetor directly + const std::vector parts{ + std::istream_iterator{iss}, + std::istream_iterator{}}; + if (parts.size() > 2) { + // log the section containing the protocol version + LOG((CLOG_INFO "network encryption protocol: %s", parts[1].c_str())); + } else { + // log the error in spliting then display the whole description rather + // then nothing + LOG((CLOG_ERR "could not split cipher for protocol")); + LOG((CLOG_INFO "network encryption protocol: %s", msg)); + } + } else { + LOG((CLOG_ERR "could not get secure socket cipher")); } + } } -void SslLogger::logError(const std::string &reason) -{ - if (!reason.empty()) { - LOG((CLOG_ERR "secure socket error: %s", reason.c_str())); - } +void SslLogger::logError(const std::string &reason) { + if (!reason.empty()) { + LOG((CLOG_ERR "secure socket error: %s", reason.c_str())); + } - auto id = ERR_get_error(); - if (id) { - char error[65535] = {0}; - ERR_error_string_n(id, error, sizeof(error)); - LOG((CLOG_ERR "openssl error: %s", error)); - } + auto id = ERR_get_error(); + if (id) { + char error[65535] = {0}; + ERR_error_string_n(id, error, sizeof(error)); + LOG((CLOG_ERR "openssl error: %s", error)); + } } -void SslLogger::logErrorByCode(int code, int retry) -{ - switch (code) { - case SSL_ERROR_NONE: - break; +void SslLogger::logErrorByCode(int code, int retry) { + switch (code) { + case SSL_ERROR_NONE: + break; - case SSL_ERROR_ZERO_RETURN: - LOG((CLOG_DEBUG "tls connection closed")); - break; + case SSL_ERROR_ZERO_RETURN: + LOG((CLOG_DEBUG "tls connection closed")); + break; - case SSL_ERROR_WANT_READ: - LOG((CLOG_DEBUG2 "want to read, error=%d, attempt=%d", code, retry)); - break; + case SSL_ERROR_WANT_READ: + LOG((CLOG_DEBUG2 "want to read, error=%d, attempt=%d", code, retry)); + break; - case SSL_ERROR_WANT_WRITE: - LOG((CLOG_DEBUG2 "want to write, error=%d, attempt=%d", code, retry)); - break; + case SSL_ERROR_WANT_WRITE: + LOG((CLOG_DEBUG2 "want to write, error=%d, attempt=%d", code, retry)); + break; - case SSL_ERROR_WANT_CONNECT: - LOG((CLOG_DEBUG2 "want to connect, error=%d, attempt=%d", code, retry)); - break; + case SSL_ERROR_WANT_CONNECT: + LOG((CLOG_DEBUG2 "want to connect, error=%d, attempt=%d", code, retry)); + break; - case SSL_ERROR_WANT_ACCEPT: - LOG((CLOG_DEBUG2 "want to accept, error=%d, attempt=%d", code, retry)); - break; + case SSL_ERROR_WANT_ACCEPT: + LOG((CLOG_DEBUG2 "want to accept, error=%d, attempt=%d", code, retry)); + break; - case SSL_ERROR_SYSCALL: - LOG((CLOG_ERR "tls error occurred (system call failure)")); - break; + case SSL_ERROR_SYSCALL: + LOG((CLOG_ERR "tls error occurred (system call failure)")); + break; - case SSL_ERROR_SSL: - LOG((CLOG_ERR "tls error occurred (generic failure)")); - break; + case SSL_ERROR_SSL: + LOG((CLOG_ERR "tls error occurred (generic failure)")); + break; - default: - LOG((CLOG_ERR "tls error occurred (unknown failure)")); - break; - } + default: + LOG((CLOG_ERR "tls error occurred (unknown failure)")); + break; + } } diff --git a/src/lib/net/InverseSockets/SslLogger.h b/src/lib/net/InverseSockets/SslLogger.h index 328bc8d0f..a5fb2466e 100644 --- a/src/lib/net/InverseSockets/SslLogger.h +++ b/src/lib/net/InverseSockets/SslLogger.h @@ -15,15 +15,14 @@ * along with this program. If not, see . */ #pragma once -#include #include +#include -class SslLogger -{ +class SslLogger { public: - static void logSecureLibInfo(); - static void logSecureCipherInfo(const SSL* ssl); - static void logSecureConnectInfo(const SSL* ssl); - static void logError(const std::string& reason = ""); - static void logErrorByCode(int code, int retry); + static void logSecureLibInfo(); + static void logSecureCipherInfo(const SSL *ssl); + static void logSecureConnectInfo(const SSL *ssl); + static void logError(const std::string &reason = ""); + static void logErrorByCode(int code, int retry); }; diff --git a/src/lib/net/NetworkAddress.cpp b/src/lib/net/NetworkAddress.cpp index ca44be813..568dbbfc9 100644 --- a/src/lib/net/NetworkAddress.cpp +++ b/src/lib/net/NetworkAddress.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -18,9 +18,9 @@ #include "net/NetworkAddress.h" -#include "net/XSocket.h" #include "arch/Arch.h" #include "arch/XArch.h" +#include "net/XSocket.h" #include #include @@ -31,214 +31,176 @@ // name re-resolution adapted from a patch by Brent Priddy. -NetworkAddress::NetworkAddress(int port) : - m_port(port) -{ - checkPort(); - m_address = ARCH->newAnyAddr(IArchNetwork::kINET); - ARCH->setAddrPort(m_address, m_port); +NetworkAddress::NetworkAddress(int port) : m_port(port) { + checkPort(); + m_address = ARCH->newAnyAddr(IArchNetwork::kINET); + ARCH->setAddrPort(m_address, m_port); } -NetworkAddress::NetworkAddress(const NetworkAddress& addr) : - m_hostname(addr.m_hostname), - m_port(addr.m_port) -{ - *this = addr; +NetworkAddress::NetworkAddress(const NetworkAddress &addr) + : m_hostname(addr.m_hostname), m_port(addr.m_port) { + *this = addr; } -NetworkAddress::NetworkAddress(const String& hostname, int port) : - m_hostname(hostname), - m_port(port) -{ - //detect internet protocol version with colom count - auto isColomPredicate = [](char c){return c == ':';}; - auto colomCount = std::count_if(m_hostname.begin(), m_hostname.end(), isColomPredicate); - - if(colomCount == 1) { - //ipv4 with port part - auto hostIt = m_hostname.find(':'); - try { - m_port = std::stoi(m_hostname.substr(hostIt + 1)); - } catch(...) { - throw XSocketAddress(XSocketAddress::kBadPort, m_hostname, m_port); - } - - auto endHostnameIt = static_cast(hostIt); - m_hostname = m_hostname.substr(0, endHostnameIt > 0 ? endHostnameIt : 0); - } - else if (colomCount > 1) { - //ipv6 part - if (m_hostname[0] == '[') { - //ipv6 with port part - String portDelimeter = "]:"; - auto hostIt = m_hostname.find(portDelimeter); - - //bad syntax of ipv6 with port - if (hostIt == String::npos) { - throw XSocketAddress(XSocketAddress::kUnknown, m_hostname, m_port); - } - - auto portSuffix = m_hostname.substr(hostIt + portDelimeter.size()); - //port is implied but omitted - if (portSuffix.empty()) { - throw XSocketAddress(XSocketAddress::kBadPort, m_hostname, m_port); - } - try { - m_port = std::stoi(portSuffix); - } catch(...) { - //port is not a number - throw XSocketAddress(XSocketAddress::kBadPort, m_hostname, m_port); - } - - auto endHostnameIt = static_cast(hostIt) - 1; - m_hostname = m_hostname.substr(1, endHostnameIt > 0 ? endHostnameIt : 0); - } - - // ensure that ipv6 link-local adress ended with scope id - if (m_hostname.rfind("fe80:", 0) == 0 && m_hostname.find('%') == String::npos) { - throw XSocketAddress(XSocketAddress::kUnknown, m_hostname, m_port); - } - } - - // check port number - checkPort(); -} - -NetworkAddress::~NetworkAddress() -{ - if (m_address != nullptr) { - ARCH->closeAddr(m_address); - m_address = nullptr; - } -} - -NetworkAddress& -NetworkAddress::operator=(const NetworkAddress& addr) -{ - if (m_address != nullptr) { - ARCH->closeAddr(m_address); - m_address = nullptr; - } - - ArchNetAddress newAddr = nullptr; - if (addr.m_address != nullptr) { - newAddr = ARCH->copyAddr(addr.m_address); - } - m_address = newAddr; - - m_hostname = addr.m_hostname; - m_port = addr.m_port; - return *this; -} - -size_t -NetworkAddress::resolve(size_t index) -{ - size_t resolvedAddressesCount = 0; - // discard previous address - if (m_address != nullptr) { - ARCH->closeAddr(m_address); - m_address = nullptr; - } +NetworkAddress::NetworkAddress(const String &hostname, int port) + : m_hostname(hostname), m_port(port) { + // detect internet protocol version with colom count + auto isColomPredicate = [](char c) { return c == ':'; }; + auto colomCount = + std::count_if(m_hostname.begin(), m_hostname.end(), isColomPredicate); + if (colomCount == 1) { + // ipv4 with port part + auto hostIt = m_hostname.find(':'); try { - // if hostname is empty then use wildcard address otherwise look - // up the name. - if (m_hostname.empty()) { - m_address = ARCH->newAnyAddr(IArchNetwork::kINET); - resolvedAddressesCount = 1; - } - else { - // Logic for temporary filtring only ipv4 addresses - std::vector ipv4OnlyAddresses; - { - auto addresses = ARCH->nameToAddr(m_hostname); - for (auto address : addresses) { - if (ARCH->getAddrFamily(address) == IArchNetwork::kINET) { - ipv4OnlyAddresses.emplace_back(address); - } - else { - ARCH->closeAddr(address); - } - } - } + m_port = std::stoi(m_hostname.substr(hostIt + 1)); + } catch (...) { + throw XSocketAddress(XSocketAddress::kBadPort, m_hostname, m_port); + } - resolvedAddressesCount = ipv4OnlyAddresses.size(); - assert(resolvedAddressesCount > 0); - if (index < resolvedAddressesCount - 1) { - m_address = ipv4OnlyAddresses[index]; - } - else { - m_address = ipv4OnlyAddresses[resolvedAddressesCount - 1]; - } + auto endHostnameIt = static_cast(hostIt); + m_hostname = m_hostname.substr(0, endHostnameIt > 0 ? endHostnameIt : 0); + } else if (colomCount > 1) { + // ipv6 part + if (m_hostname[0] == '[') { + // ipv6 with port part + String portDelimeter = "]:"; + auto hostIt = m_hostname.find(portDelimeter); - for(auto address : ipv4OnlyAddresses) { - if(m_address != address) { - ARCH->closeAddr(address); - } - } - } - } - catch (XArchNetworkNameUnknown&) { - throw XSocketAddress(XSocketAddress::kNotFound, m_hostname, m_port); - } - catch (XArchNetworkNameNoAddress&) { - throw XSocketAddress(XSocketAddress::kNoAddress, m_hostname, m_port); - } - catch (XArchNetworkNameUnsupported&) { - throw XSocketAddress(XSocketAddress::kUnsupported, m_hostname, m_port); - } - catch (XArchNetworkName&) { + // bad syntax of ipv6 with port + if (hostIt == String::npos) { throw XSocketAddress(XSocketAddress::kUnknown, m_hostname, m_port); - } + } - // set port in address - ARCH->setAddrPort(m_address, m_port); - - return resolvedAddressesCount; -} - -bool -NetworkAddress::operator==(const NetworkAddress& addr) const -{ - return m_address == addr.m_address || ARCH->isEqualAddr(m_address, addr.m_address); -} - -bool -NetworkAddress::operator!=(const NetworkAddress& addr) const -{ - return !operator==(addr); -} - -bool -NetworkAddress::isValid() const -{ - return (m_address != nullptr); -} - -const ArchNetAddress& -NetworkAddress::getAddress() const -{ - return m_address; -} - -int -NetworkAddress::getPort() const -{ - return m_port; -} - -String -NetworkAddress::getHostname() const -{ - return m_hostname; -} - -void -NetworkAddress::checkPort() -{ - // check port number - if (m_port < 0 || m_port > 65535) { + auto portSuffix = m_hostname.substr(hostIt + portDelimeter.size()); + // port is implied but omitted + if (portSuffix.empty()) { throw XSocketAddress(XSocketAddress::kBadPort, m_hostname, m_port); + } + try { + m_port = std::stoi(portSuffix); + } catch (...) { + // port is not a number + throw XSocketAddress(XSocketAddress::kBadPort, m_hostname, m_port); + } + + auto endHostnameIt = static_cast(hostIt) - 1; + m_hostname = m_hostname.substr(1, endHostnameIt > 0 ? endHostnameIt : 0); } + + // ensure that ipv6 link-local adress ended with scope id + if (m_hostname.rfind("fe80:", 0) == 0 && + m_hostname.find('%') == String::npos) { + throw XSocketAddress(XSocketAddress::kUnknown, m_hostname, m_port); + } + } + + // check port number + checkPort(); +} + +NetworkAddress::~NetworkAddress() { + if (m_address != nullptr) { + ARCH->closeAddr(m_address); + m_address = nullptr; + } +} + +NetworkAddress &NetworkAddress::operator=(const NetworkAddress &addr) { + if (m_address != nullptr) { + ARCH->closeAddr(m_address); + m_address = nullptr; + } + + ArchNetAddress newAddr = nullptr; + if (addr.m_address != nullptr) { + newAddr = ARCH->copyAddr(addr.m_address); + } + m_address = newAddr; + + m_hostname = addr.m_hostname; + m_port = addr.m_port; + return *this; +} + +size_t NetworkAddress::resolve(size_t index) { + size_t resolvedAddressesCount = 0; + // discard previous address + if (m_address != nullptr) { + ARCH->closeAddr(m_address); + m_address = nullptr; + } + + try { + // if hostname is empty then use wildcard address otherwise look + // up the name. + if (m_hostname.empty()) { + m_address = ARCH->newAnyAddr(IArchNetwork::kINET); + resolvedAddressesCount = 1; + } else { + // Logic for temporary filtring only ipv4 addresses + std::vector ipv4OnlyAddresses; + { + auto addresses = ARCH->nameToAddr(m_hostname); + for (auto address : addresses) { + if (ARCH->getAddrFamily(address) == IArchNetwork::kINET) { + ipv4OnlyAddresses.emplace_back(address); + } else { + ARCH->closeAddr(address); + } + } + } + + resolvedAddressesCount = ipv4OnlyAddresses.size(); + assert(resolvedAddressesCount > 0); + if (index < resolvedAddressesCount - 1) { + m_address = ipv4OnlyAddresses[index]; + } else { + m_address = ipv4OnlyAddresses[resolvedAddressesCount - 1]; + } + + for (auto address : ipv4OnlyAddresses) { + if (m_address != address) { + ARCH->closeAddr(address); + } + } + } + } catch (XArchNetworkNameUnknown &) { + throw XSocketAddress(XSocketAddress::kNotFound, m_hostname, m_port); + } catch (XArchNetworkNameNoAddress &) { + throw XSocketAddress(XSocketAddress::kNoAddress, m_hostname, m_port); + } catch (XArchNetworkNameUnsupported &) { + throw XSocketAddress(XSocketAddress::kUnsupported, m_hostname, m_port); + } catch (XArchNetworkName &) { + throw XSocketAddress(XSocketAddress::kUnknown, m_hostname, m_port); + } + + // set port in address + ARCH->setAddrPort(m_address, m_port); + + return resolvedAddressesCount; +} + +bool NetworkAddress::operator==(const NetworkAddress &addr) const { + return m_address == addr.m_address || + ARCH->isEqualAddr(m_address, addr.m_address); +} + +bool NetworkAddress::operator!=(const NetworkAddress &addr) const { + return !operator==(addr); +} + +bool NetworkAddress::isValid() const { return (m_address != nullptr); } + +const ArchNetAddress &NetworkAddress::getAddress() const { return m_address; } + +int NetworkAddress::getPort() const { return m_port; } + +String NetworkAddress::getHostname() const { return m_hostname; } + +void NetworkAddress::checkPort() { + // check port number + if (m_port < 0 || m_port > 65535) { + throw XSocketAddress(XSocketAddress::kBadPort, m_hostname, m_port); + } } diff --git a/src/lib/net/NetworkAddress.h b/src/lib/net/NetworkAddress.h index 129d883ee..708c77bdd 100644 --- a/src/lib/net/NetworkAddress.h +++ b/src/lib/net/NetworkAddress.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -18,9 +18,9 @@ #pragma once -#include "base/String.h" -#include "base/EventTypes.h" #include "arch/IArchNetwork.h" +#include "base/EventTypes.h" +#include "base/String.h" //! Network address type /*! @@ -28,98 +28,98 @@ This class represents a network address. */ class NetworkAddress { public: - /*! - Constructs the invalid address - */ - NetworkAddress() = default; + /*! + Constructs the invalid address + */ + NetworkAddress() = default; - /*! - Construct the wildcard address with the given port. \c port must - not be zero. - */ - NetworkAddress(int port); + /*! + Construct the wildcard address with the given port. \c port must + not be zero. + */ + NetworkAddress(int port); - /*! - Construct the network address for the given \c hostname and \c port. - If \c hostname can be parsed as a numerical address then that's how - it's used, otherwise it's used as a host name. If \c hostname ends - in ":[0-9]+" then that suffix is extracted and used as the port, - overridding the port parameter. The resulting port must be a valid - port number (zero is not a valid port number) otherwise \c XSocketAddress - is thrown with an error of \c XSocketAddress::kBadPort. The hostname - is not resolved by the c'tor; use \c resolve to do that. - */ - NetworkAddress(const String& hostname, int port = 0); + /*! + Construct the network address for the given \c hostname and \c port. + If \c hostname can be parsed as a numerical address then that's how + it's used, otherwise it's used as a host name. If \c hostname ends + in ":[0-9]+" then that suffix is extracted and used as the port, + overridding the port parameter. The resulting port must be a valid + port number (zero is not a valid port number) otherwise \c XSocketAddress + is thrown with an error of \c XSocketAddress::kBadPort. The hostname + is not resolved by the c'tor; use \c resolve to do that. + */ + NetworkAddress(const String &hostname, int port = 0); - NetworkAddress(const NetworkAddress&); + NetworkAddress(const NetworkAddress &); - ~NetworkAddress(); + ~NetworkAddress(); - NetworkAddress& operator=(const NetworkAddress&); + NetworkAddress &operator=(const NetworkAddress &); - //! @name manipulators - //@{ + //! @name manipulators + //@{ - //! Resolve address - /*! - Resolves the hostname to an address. This can be done any number of - times and is done automatically by the c'tor taking a hostname. - Throws XSocketAddress if resolution is unsuccessful, after which - \c isValid returns false until the next call to this method. - index - determine index of IP we would like to use from resolved addresses - Returns count of successfully resolved addressed. - */ - size_t resolve(size_t index = 0); + //! Resolve address + /*! + Resolves the hostname to an address. This can be done any number of + times and is done automatically by the c'tor taking a hostname. + Throws XSocketAddress if resolution is unsuccessful, after which + \c isValid returns false until the next call to this method. + index - determine index of IP we would like to use from resolved addresses + Returns count of successfully resolved addressed. + */ + size_t resolve(size_t index = 0); - //@} - //! @name accessors - //@{ + //@} + //! @name accessors + //@{ - //! Check address equality - /*! - Returns true if this address is equal to \p address. - */ - bool operator==(const NetworkAddress& address) const; + //! Check address equality + /*! + Returns true if this address is equal to \p address. + */ + bool operator==(const NetworkAddress &address) const; - //! Check address inequality - /*! - Returns true if this address is not equal to \p address. - */ - bool operator!=(const NetworkAddress& address) const; + //! Check address inequality + /*! + Returns true if this address is not equal to \p address. + */ + bool operator!=(const NetworkAddress &address) const; - //! Check address validity - /*! - Returns true if this is not the invalid address. - */ - bool isValid() const; + //! Check address validity + /*! + Returns true if this is not the invalid address. + */ + bool isValid() const; - //! Get address - /*! - Returns the address in the platform's native network address - structure. - */ - const ArchNetAddress& getAddress() const; + //! Get address + /*! + Returns the address in the platform's native network address + structure. + */ + const ArchNetAddress &getAddress() const; - //! Get port - /*! - Returns the port passed to the c'tor as a suffix to the hostname, - if that existed, otherwise as passed directly to the c'tor. - */ - int getPort() const; + //! Get port + /*! + Returns the port passed to the c'tor as a suffix to the hostname, + if that existed, otherwise as passed directly to the c'tor. + */ + int getPort() const; - //! Get hostname - /*! - Returns the hostname passed to the c'tor sans any port suffix. - */ - String getHostname() const; + //! Get hostname + /*! + Returns the hostname passed to the c'tor sans any port suffix. + */ + String getHostname() const; - //@} + //@} private: - void checkPort(); + void checkPort(); private: - ArchNetAddress m_address = nullptr; - String m_hostname; - int m_port = 0; + ArchNetAddress m_address = nullptr; + String m_hostname; + int m_port = 0; }; diff --git a/src/lib/net/SecureListenSocket.cpp b/src/lib/net/SecureListenSocket.cpp index dc3098e87..6e7096b25 100644 --- a/src/lib/net/SecureListenSocket.cpp +++ b/src/lib/net/SecureListenSocket.cpp @@ -1,11 +1,11 @@ /* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2015-2016 Symless Ltd. - * + * * 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 LICENSE 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 @@ -18,76 +18,66 @@ #include "SecureListenSocket.h" #include "SecureSocket.h" +#include "arch/XArch.h" #include "net/NetworkAddress.h" #include "net/SocketMultiplexer.h" #include "net/TSocketMultiplexerMethodJob.h" -#include "arch/XArch.h" #include "synergy/ArgParser.h" #include "synergy/ArgsBase.h" -static const char s_certificateDir[] = { "SSL" }; -static const char s_certificateFilename[] = { "Synergy.pem" }; +static const char s_certificateDir[] = {"SSL"}; +static const char s_certificateFilename[] = {"Synergy.pem"}; // // SecureListenSocket // -SecureListenSocket::SecureListenSocket( - IEventQueue* events, - SocketMultiplexer* socketMultiplexer, - IArchNetwork::EAddressFamily family) : - TCPListenSocket(events, socketMultiplexer, family) -{ -} - -IDataSocket* -SecureListenSocket::accept() -{ - SecureSocket* socket = NULL; - try { - socket = new SecureSocket( - m_events, - m_socketMultiplexer, - ARCH->acceptSocket(m_socket, NULL)); - socket->initSsl(true); - - if (socket != NULL) { - setListeningJob(); - } - - //default location of the TLS cert file in users dir - String certificateFilename = synergy::string::sprintf("%s/%s/%s", - ARCH->getProfileDirectory().c_str(), - s_certificateDir, - s_certificateFilename); - - //if the tls cert option is set use that for the certificate file - if (!ArgParser::argsBase().m_tlsCertFile.empty()) { - certificateFilename = ArgParser::argsBase().m_tlsCertFile; - } - - bool loaded = socket->loadCertificates(certificateFilename); - if (!loaded) { - delete socket; - return NULL; - } - - socket->secureAccept(); - - return dynamic_cast(socket); - } - catch (XArchNetwork&) { - if (socket != NULL) { - delete socket; - setListeningJob(); - } - return NULL; - } - catch (std::exception &ex) { - if (socket != NULL) { - delete socket; - setListeningJob(); - } - throw ex; - } +SecureListenSocket::SecureListenSocket(IEventQueue *events, + SocketMultiplexer *socketMultiplexer, + IArchNetwork::EAddressFamily family) + : TCPListenSocket(events, socketMultiplexer, family) {} + +IDataSocket *SecureListenSocket::accept() { + SecureSocket *socket = NULL; + try { + socket = new SecureSocket(m_events, m_socketMultiplexer, + ARCH->acceptSocket(m_socket, NULL)); + socket->initSsl(true); + + if (socket != NULL) { + setListeningJob(); + } + + // default location of the TLS cert file in users dir + String certificateFilename = synergy::string::sprintf( + "%s/%s/%s", ARCH->getProfileDirectory().c_str(), s_certificateDir, + s_certificateFilename); + + // if the tls cert option is set use that for the certificate file + if (!ArgParser::argsBase().m_tlsCertFile.empty()) { + certificateFilename = ArgParser::argsBase().m_tlsCertFile; + } + + bool loaded = socket->loadCertificates(certificateFilename); + if (!loaded) { + delete socket; + return NULL; + } + + socket->secureAccept(); + + return dynamic_cast(socket); + } catch (XArchNetwork &) { + if (socket != NULL) { + delete socket; + setListeningJob(); + } + return NULL; + } catch (std::exception &ex) { + if (socket != NULL) { + delete socket; + setListeningJob(); + } + throw ex; + } } diff --git a/src/lib/net/SecureListenSocket.h b/src/lib/net/SecureListenSocket.h index ba295eff5..0bfc05586 100644 --- a/src/lib/net/SecureListenSocket.h +++ b/src/lib/net/SecureListenSocket.h @@ -1,11 +1,11 @@ /* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2015-2016 Symless Ltd. - * + * * 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 LICENSE 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 @@ -17,20 +17,18 @@ #pragma once -#include "net/TCPListenSocket.h" #include "common/stdset.h" +#include "net/TCPListenSocket.h" class IEventQueue; class SocketMultiplexer; class IDataSocket; -class SecureListenSocket : public TCPListenSocket{ +class SecureListenSocket : public TCPListenSocket { public: - SecureListenSocket(IEventQueue* events, - SocketMultiplexer* socketMultiplexer, IArchNetwork::EAddressFamily family); + SecureListenSocket(IEventQueue *events, SocketMultiplexer *socketMultiplexer, + IArchNetwork::EAddressFamily family); - - // IListenSocket overrides - virtual IDataSocket* - accept(); + // IListenSocket overrides + virtual IDataSocket *accept(); }; diff --git a/src/lib/net/SecureSocket.cpp b/src/lib/net/SecureSocket.cpp index bc63ddf0a..2480b1b5e 100644 --- a/src/lib/net/SecureSocket.cpp +++ b/src/lib/net/SecureSocket.cpp @@ -1,11 +1,11 @@ /* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2015-2016 Symless Ltd. - * + * * 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 LICENSE 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 @@ -17,23 +17,23 @@ #include "SecureSocket.h" -#include "net/TSocketMultiplexerMethodJob.h" -#include "base/TMethodEventJob.h" -#include "net/TCPSocket.h" -#include -#include "mt/Lock.h" #include "arch/XArch.h" #include "base/Log.h" #include "base/Path.h" +#include "base/TMethodEventJob.h" +#include "mt/Lock.h" +#include "net/TCPSocket.h" +#include "net/TSocketMultiplexerMethodJob.h" +#include -#include -#include -#include -#include -#include #include -#include +#include #include +#include +#include +#include +#include +#include // // SecureSocket @@ -43,727 +43,661 @@ static const float s_retryDelay = 0.01f; -enum { - kMsgSize = 128 -}; +enum { kMsgSize = 128 }; static const char kFingerprintDirName[] = "SSL/Fingerprints"; -//static const char kFingerprintLocalFilename[] = "Local.txt"; +// static const char kFingerprintLocalFilename[] = "Local.txt"; static const char kFingerprintTrustedServersFilename[] = "TrustedServers.txt"; -//static const char kFingerprintTrustedClientsFilename[] = "TrustedClients.txt"; +// static const char kFingerprintTrustedClientsFilename[] = +// "TrustedClients.txt"; struct Ssl { - SSL_CTX* m_context; - SSL* m_ssl; + SSL_CTX *m_context; + SSL *m_ssl; }; -SecureSocket::SecureSocket(IEventQueue* events, - SocketMultiplexer* socketMultiplexer, IArchNetwork::EAddressFamily family) : - TCPSocket(events, socketMultiplexer, family), - m_ssl(nullptr), - m_secureReady(false), - m_fatal(false) -{ +SecureSocket::SecureSocket(IEventQueue *events, + SocketMultiplexer *socketMultiplexer, + IArchNetwork::EAddressFamily family) + : TCPSocket(events, socketMultiplexer, family), m_ssl(nullptr), + m_secureReady(false), m_fatal(false) {} + +SecureSocket::SecureSocket(IEventQueue *events, + SocketMultiplexer *socketMultiplexer, + ArchSocket socket) + : TCPSocket(events, socketMultiplexer, socket), m_ssl(nullptr), + m_secureReady(false), m_fatal(false) {} + +SecureSocket::~SecureSocket() { freeSSL(); } + +void SecureSocket::close() { + freeSSL(); + TCPSocket::close(); } -SecureSocket::SecureSocket(IEventQueue* events, - SocketMultiplexer* socketMultiplexer, - ArchSocket socket) : - TCPSocket(events, socketMultiplexer, socket), - m_ssl(nullptr), - m_secureReady(false), - m_fatal(false) -{ +void SecureSocket::connect(const NetworkAddress &addr) { + m_events->adoptHandler(m_events->forIDataSocket().connected(), + getEventTarget(), + new TMethodEventJob( + this, &SecureSocket::handleTCPConnected)); + + TCPSocket::connect(addr); } -SecureSocket::~SecureSocket() -{ - freeSSL(); +ISocketMultiplexerJob *SecureSocket::newJob() { + // after TCP connection is established, SecureSocket will pick up + // connected event and do secureConnect + if (m_connected && !m_secureReady) { + return NULL; + } + + return TCPSocket::newJob(); } -void -SecureSocket::close() -{ - freeSSL(); - TCPSocket::close(); +void SecureSocket::secureConnect() { + setJob(new TSocketMultiplexerMethodJob( + this, &SecureSocket::serviceConnect, getSocket(), isReadable(), + isWritable())); } -void -SecureSocket::connect(const NetworkAddress& addr) -{ - m_events->adoptHandler(m_events->forIDataSocket().connected(), - getEventTarget(), - new TMethodEventJob(this, - &SecureSocket::handleTCPConnected)); - - TCPSocket::connect(addr); +void SecureSocket::secureAccept() { + setJob(new TSocketMultiplexerMethodJob( + this, &SecureSocket::serviceAccept, getSocket(), isReadable(), + isWritable())); } -ISocketMultiplexerJob* -SecureSocket::newJob() -{ - // after TCP connection is established, SecureSocket will pick up - // connected event and do secureConnect - if (m_connected && !m_secureReady) { - return NULL; +TCPSocket::EJobResult SecureSocket::doRead() { + static UInt8 buffer[4096]; + memset(buffer, 0, sizeof(buffer)); + int bytesRead = 0; + int status = 0; + + if (isSecureReady()) { + status = secureRead(buffer, sizeof(buffer), bytesRead); + if (status < 0) { + return kBreak; + } else if (status == 0) { + return kNew; } - - return TCPSocket::newJob(); -} - -void -SecureSocket::secureConnect() -{ - setJob(new TSocketMultiplexerMethodJob( - this, &SecureSocket::serviceConnect, - getSocket(), isReadable(), isWritable())); -} - -void -SecureSocket::secureAccept() -{ - setJob(new TSocketMultiplexerMethodJob( - this, &SecureSocket::serviceAccept, - getSocket(), isReadable(), isWritable())); -} - -TCPSocket::EJobResult -SecureSocket::doRead() -{ - static UInt8 buffer[4096]; - memset(buffer, 0, sizeof(buffer)); - int bytesRead = 0; - int status = 0; - - if (isSecureReady()) { - status = secureRead(buffer, sizeof(buffer), bytesRead); - if (status < 0) { - return kBreak; - } - else if (status == 0) { - return kNew; - } - } - else { - return kRetry; - } - - if (bytesRead > 0) { - bool wasEmpty = (m_inputBuffer.getSize() == 0); - - // slurp up as much as possible - do { - m_inputBuffer.write(buffer, bytesRead); - - status = secureRead(buffer, sizeof(buffer), bytesRead); - if (status < 0) { - return kBreak; - } - } while (bytesRead > 0 || status > 0); - - // send input ready if input buffer was empty - if (wasEmpty) { - sendEvent(m_events->forIStream().inputReady()); - } - } - else { - // remote write end of stream hungup. our input side - // has therefore shutdown but don't flush our buffer - // since there's still data to be read. - sendEvent(m_events->forIStream().inputShutdown()); - if (!m_writable && m_inputBuffer.getSize() == 0) { - sendEvent(m_events->forISocket().disconnected()); - m_connected = false; - } - m_readable = false; - return kNew; - } - + } else { return kRetry; + } + + if (bytesRead > 0) { + bool wasEmpty = (m_inputBuffer.getSize() == 0); + + // slurp up as much as possible + do { + m_inputBuffer.write(buffer, bytesRead); + + status = secureRead(buffer, sizeof(buffer), bytesRead); + if (status < 0) { + return kBreak; + } + } while (bytesRead > 0 || status > 0); + + // send input ready if input buffer was empty + if (wasEmpty) { + sendEvent(m_events->forIStream().inputReady()); + } + } else { + // remote write end of stream hungup. our input side + // has therefore shutdown but don't flush our buffer + // since there's still data to be read. + sendEvent(m_events->forIStream().inputShutdown()); + if (!m_writable && m_inputBuffer.getSize() == 0) { + sendEvent(m_events->forISocket().disconnected()); + m_connected = false; + } + m_readable = false; + return kNew; + } + + return kRetry; } -TCPSocket::EJobResult -SecureSocket::doWrite() -{ - static bool s_retry = false; - static int s_retrySize = 0; - static int s_staticBufferSize = 0; - static void* s_staticBuffer = NULL; +TCPSocket::EJobResult SecureSocket::doWrite() { + static bool s_retry = false; + static int s_retrySize = 0; + static int s_staticBufferSize = 0; + static void *s_staticBuffer = NULL; - // write data - int bufferSize = 0; - int bytesWrote = 0; - int status = 0; - - if (s_retry) { - bufferSize = s_retrySize; - } - else { - bufferSize = m_outputBuffer.getSize(); - if (bufferSize != 0) { - if (bufferSize > s_staticBufferSize) { - s_staticBuffer = realloc(s_staticBuffer, bufferSize); - s_staticBufferSize = bufferSize; - } - memcpy(s_staticBuffer, m_outputBuffer.peek(bufferSize), bufferSize); - } - } - - if (bufferSize == 0) { - return kRetry; - } + // write data + int bufferSize = 0; + int bytesWrote = 0; + int status = 0; - if (isSecureReady()) { - status = secureWrite(s_staticBuffer, bufferSize, bytesWrote); - if (status > 0) { - s_retry = false; - bufferSize = 0; - } - else if (status < 0) { - return kBreak; - } - else if (status == 0) { - s_retry = true; - s_retrySize = bufferSize; - return kNew; - } - } - else { - return kRetry; - } - - if (bytesWrote > 0) { - discardWrittenData(bytesWrote); - return kNew; + if (s_retry) { + bufferSize = s_retrySize; + } else { + bufferSize = m_outputBuffer.getSize(); + if (bufferSize != 0) { + if (bufferSize > s_staticBufferSize) { + s_staticBuffer = realloc(s_staticBuffer, bufferSize); + s_staticBufferSize = bufferSize; + } + memcpy(s_staticBuffer, m_outputBuffer.peek(bufferSize), bufferSize); } + } + if (bufferSize == 0) { return kRetry; + } + + if (isSecureReady()) { + status = secureWrite(s_staticBuffer, bufferSize, bytesWrote); + if (status > 0) { + s_retry = false; + bufferSize = 0; + } else if (status < 0) { + return kBreak; + } else if (status == 0) { + s_retry = true; + s_retrySize = bufferSize; + return kNew; + } + } else { + return kRetry; + } + + if (bytesWrote > 0) { + discardWrittenData(bytesWrote); + return kNew; + } + + return kRetry; } -int -SecureSocket::secureRead(void* buffer, int size, int& read) -{ - if (m_ssl->m_ssl != NULL) { - LOG((CLOG_DEBUG2 "reading secure socket")); - read = SSL_read(m_ssl->m_ssl, buffer, size); - - static int retry; +int SecureSocket::secureRead(void *buffer, int size, int &read) { + if (m_ssl->m_ssl != NULL) { + LOG((CLOG_DEBUG2 "reading secure socket")); + read = SSL_read(m_ssl->m_ssl, buffer, size); - // Check result will cleanup the connection in the case of a fatal - checkResult(read, retry); - - if (retry) { - return 0; - } - - if (isFatal()) { - return -1; - } - } - // According to SSL spec, the number of bytes read must not be negative and - // not have an error code from SSL_get_error(). If this happens, it is - // itself an error. Let the parent handle the case - return read; -} - -int -SecureSocket::secureWrite(const void* buffer, int size, int& wrote) -{ - if (m_ssl->m_ssl != NULL) { - LOG((CLOG_DEBUG2 "writing secure socket: %p", this)); - - wrote = SSL_write(m_ssl->m_ssl, buffer, size); - - static int retry; - - // Check result will cleanup the connection in the case of a fatal - checkResult(wrote, retry); - - if (retry) { - return 0; - } - - if (isFatal()) { - return -1; - } - } - // According to SSL spec, r must not be negative and not have an error code - // from SSL_get_error(). If this happens, it is itself an error. Let the - // parent handle the case - return wrote; -} - -bool -SecureSocket::isSecureReady() -{ - return m_secureReady; -} - -void -SecureSocket::initSsl(bool server) -{ - m_ssl = new Ssl(); - m_ssl->m_context = NULL; - m_ssl->m_ssl = NULL; - - initContext(server); -} - -bool -SecureSocket::loadCertificates(String& filename) -{ - if (filename.empty()) { - SslLogger::logError("tls certificate is not specified"); - return false; - } - else { - std::ifstream file(synergy::filesystem::path(filename)); - bool exist = file.good(); - file.close(); - - if (!exist) { - String errorMsg("tls certificate doesn't exist: "); - errorMsg.append(filename); - SslLogger::logError(errorMsg.c_str()); - return false; - } - } - - int r = 0; - r = SSL_CTX_use_certificate_file(m_ssl->m_context, filename.c_str(), SSL_FILETYPE_PEM); - if (r <= 0) { - SslLogger::logError("could not use tls certificate"); - return false; - } - - r = SSL_CTX_use_PrivateKey_file(m_ssl->m_context, filename.c_str(), SSL_FILETYPE_PEM); - if (r <= 0) { - SslLogger::logError("could not use tls private key"); - return false; - } - - r = SSL_CTX_check_private_key(m_ssl->m_context); - if (!r) { - SslLogger::logError("could not verify tls private key"); - return false; - } - - return true; -} - -void -SecureSocket::initContext(bool server) -{ - SSL_library_init(); - - const SSL_METHOD* method; - - // load & register all cryptos, etc. - OpenSSL_add_all_algorithms(); - - // load all error messages - SSL_load_error_strings(); - SslLogger::logSecureLibInfo(); - - if (server) { - method = SSLv23_server_method(); - } - else { - method = SSLv23_client_method(); - } - - // create new context from method - SSL_METHOD* m = const_cast(method); - m_ssl->m_context = SSL_CTX_new(m); - - //Prevent the usage of of all version prior to TLSv1.2 as they are known to be vulnerable - SSL_CTX_set_options(m_ssl->m_context, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1); - - if (m_ssl->m_context == NULL) { - SslLogger::logError(); - } -} - -void -SecureSocket::createSSL() -{ - // I assume just one instance is needed - // get new SSL state with context - if (m_ssl->m_ssl == NULL) { - assert(m_ssl->m_context != NULL); - m_ssl->m_ssl = SSL_new(m_ssl->m_context); - } -} - -void -SecureSocket::freeSSL() -{ - isFatal(true); - // take socket from multiplexer ASAP otherwise the race condition - // could cause events to get called on a dead object. TCPSocket - // will do this, too, but the double-call is harmless - setJob(NULL); - if (m_ssl) { - if (m_ssl->m_ssl != NULL) { - SSL_shutdown(m_ssl->m_ssl); - - SSL_free(m_ssl->m_ssl); - m_ssl->m_ssl = NULL; - } - if (m_ssl->m_context != NULL) { - SSL_CTX_free(m_ssl->m_context); - m_ssl->m_context = NULL; - } - delete m_ssl; - m_ssl = nullptr; - } -} - -int -SecureSocket::secureAccept(int socket) -{ - createSSL(); - - // set connection socket to SSL state - SSL_set_fd(m_ssl->m_ssl, socket); - - LOG((CLOG_DEBUG2 "accepting secure socket")); - int r = SSL_accept(m_ssl->m_ssl); - static int retry; - checkResult(r, retry); + // Check result will cleanup the connection in the case of a fatal + checkResult(read, retry); + + if (retry) { + return 0; + } if (isFatal()) { - // tell user and sleep so the socket isn't hammered. - LOG((CLOG_ERR "failed to accept secure socket")); - LOG((CLOG_WARN "client connection may not be secure")); - m_secureReady = false; - ARCH->sleep(1); - retry = 0; - return -1; // Failed, error out + return -1; } - - // If not fatal and no retry, state is good - if (retry == 0) { - m_secureReady = true; - LOG((CLOG_INFO "accepted secure socket")); - SslLogger::logSecureCipherInfo(m_ssl->m_ssl); - SslLogger::logSecureConnectInfo(m_ssl->m_ssl); - return 1; - } - - // If not fatal and retry is set, not ready, and return retry - if (retry > 0) { - LOG((CLOG_DEBUG2 "retry accepting secure socket")); - m_secureReady = false; - ARCH->sleep(s_retryDelay); - return 0; - } - - // no good state exists here - LOG((CLOG_ERR "unexpected state attempting to accept connection")); - return -1; + } + // According to SSL spec, the number of bytes read must not be negative and + // not have an error code from SSL_get_error(). If this happens, it is + // itself an error. Let the parent handle the case + return read; } -int -SecureSocket::secureConnect(int socket) -{ - createSSL(); +int SecureSocket::secureWrite(const void *buffer, int size, int &wrote) { + if (m_ssl->m_ssl != NULL) { + LOG((CLOG_DEBUG2 "writing secure socket: %p", this)); + + wrote = SSL_write(m_ssl->m_ssl, buffer, size); - // attach the socket descriptor - SSL_set_fd(m_ssl->m_ssl, socket); - - LOG((CLOG_DEBUG2 "connecting secure socket")); - int r = SSL_connect(m_ssl->m_ssl); - static int retry; - checkResult(r, retry); + // Check result will cleanup the connection in the case of a fatal + checkResult(wrote, retry); + + if (retry) { + return 0; + } if (isFatal()) { - LOG((CLOG_ERR "failed to connect secure socket")); - retry = 0; - return -1; + return -1; } + } + // According to SSL spec, r must not be negative and not have an error code + // from SSL_get_error(). If this happens, it is itself an error. Let the + // parent handle the case + return wrote; +} - // If we should retry, not ready and return 0 - if (retry > 0) { - LOG((CLOG_DEBUG2 "retry connect secure socket")); - m_secureReady = false; - ARCH->sleep(s_retryDelay); - return 0; +bool SecureSocket::isSecureReady() { return m_secureReady; } + +void SecureSocket::initSsl(bool server) { + m_ssl = new Ssl(); + m_ssl->m_context = NULL; + m_ssl->m_ssl = NULL; + + initContext(server); +} + +bool SecureSocket::loadCertificates(String &filename) { + if (filename.empty()) { + SslLogger::logError("tls certificate is not specified"); + return false; + } else { + std::ifstream file(synergy::filesystem::path(filename)); + bool exist = file.good(); + file.close(); + + if (!exist) { + String errorMsg("tls certificate doesn't exist: "); + errorMsg.append(filename); + SslLogger::logError(errorMsg.c_str()); + return false; } + } + int r = 0; + r = SSL_CTX_use_certificate_file(m_ssl->m_context, filename.c_str(), + SSL_FILETYPE_PEM); + if (r <= 0) { + SslLogger::logError("could not use tls certificate"); + return false; + } + + r = SSL_CTX_use_PrivateKey_file(m_ssl->m_context, filename.c_str(), + SSL_FILETYPE_PEM); + if (r <= 0) { + SslLogger::logError("could not use tls private key"); + return false; + } + + r = SSL_CTX_check_private_key(m_ssl->m_context); + if (!r) { + SslLogger::logError("could not verify tls private key"); + return false; + } + + return true; +} + +void SecureSocket::initContext(bool server) { + SSL_library_init(); + + const SSL_METHOD *method; + + // load & register all cryptos, etc. + OpenSSL_add_all_algorithms(); + + // load all error messages + SSL_load_error_strings(); + SslLogger::logSecureLibInfo(); + + if (server) { + method = SSLv23_server_method(); + } else { + method = SSLv23_client_method(); + } + + // create new context from method + SSL_METHOD *m = const_cast(method); + m_ssl->m_context = SSL_CTX_new(m); + + // Prevent the usage of of all version prior to TLSv1.2 as they are known to + // be vulnerable + SSL_CTX_set_options(m_ssl->m_context, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | + SSL_OP_NO_TLSv1 | + SSL_OP_NO_TLSv1_1); + + if (m_ssl->m_context == NULL) { + SslLogger::logError(); + } +} + +void SecureSocket::createSSL() { + // I assume just one instance is needed + // get new SSL state with context + if (m_ssl->m_ssl == NULL) { + assert(m_ssl->m_context != NULL); + m_ssl->m_ssl = SSL_new(m_ssl->m_context); + } +} + +void SecureSocket::freeSSL() { + isFatal(true); + // take socket from multiplexer ASAP otherwise the race condition + // could cause events to get called on a dead object. TCPSocket + // will do this, too, but the double-call is harmless + setJob(NULL); + if (m_ssl) { + if (m_ssl->m_ssl != NULL) { + SSL_shutdown(m_ssl->m_ssl); + + SSL_free(m_ssl->m_ssl); + m_ssl->m_ssl = NULL; + } + if (m_ssl->m_context != NULL) { + SSL_CTX_free(m_ssl->m_context); + m_ssl->m_context = NULL; + } + delete m_ssl; + m_ssl = nullptr; + } +} + +int SecureSocket::secureAccept(int socket) { + createSSL(); + + // set connection socket to SSL state + SSL_set_fd(m_ssl->m_ssl, socket); + + LOG((CLOG_DEBUG2 "accepting secure socket")); + int r = SSL_accept(m_ssl->m_ssl); + + static int retry; + + checkResult(r, retry); + + if (isFatal()) { + // tell user and sleep so the socket isn't hammered. + LOG((CLOG_ERR "failed to accept secure socket")); + LOG((CLOG_WARN "client connection may not be secure")); + m_secureReady = false; + ARCH->sleep(1); retry = 0; - // No error, set ready, process and return ok + return -1; // Failed, error out + } + + // If not fatal and no retry, state is good + if (retry == 0) { m_secureReady = true; - if (verifyCertFingerprint()) { - LOG((CLOG_INFO "connected to secure socket")); - if (!showCertificate()) { - disconnect(); - return -1;// Cert fail, error - } - } - else { - LOG((CLOG_ERR "failed to verify server certificate fingerprint")); - disconnect(); - return -1; // Fingerprint failed, error - } - LOG((CLOG_DEBUG2 "connected secure socket")); + LOG((CLOG_INFO "accepted secure socket")); SslLogger::logSecureCipherInfo(m_ssl->m_ssl); SslLogger::logSecureConnectInfo(m_ssl->m_ssl); return 1; + } + + // If not fatal and retry is set, not ready, and return retry + if (retry > 0) { + LOG((CLOG_DEBUG2 "retry accepting secure socket")); + m_secureReady = false; + ARCH->sleep(s_retryDelay); + return 0; + } + + // no good state exists here + LOG((CLOG_ERR "unexpected state attempting to accept connection")); + return -1; } -bool -SecureSocket::showCertificate() const -{ - X509* cert; - char* line; - - // get the server's certificate - cert = SSL_get_peer_certificate(m_ssl->m_ssl); - if (cert != NULL) { - line = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0); - LOG((CLOG_INFO "server tls certificate info: %s", line)); - OPENSSL_free(line); - X509_free(cert); - } - else { - SslLogger::logError("server has no tls certificate"); - return false; - } +int SecureSocket::secureConnect(int socket) { + createSSL(); - return true; + // attach the socket descriptor + SSL_set_fd(m_ssl->m_ssl, socket); + + LOG((CLOG_DEBUG2 "connecting secure socket")); + int r = SSL_connect(m_ssl->m_ssl); + + static int retry; + + checkResult(r, retry); + + if (isFatal()) { + LOG((CLOG_ERR "failed to connect secure socket")); + retry = 0; + return -1; + } + + // If we should retry, not ready and return 0 + if (retry > 0) { + LOG((CLOG_DEBUG2 "retry connect secure socket")); + m_secureReady = false; + ARCH->sleep(s_retryDelay); + return 0; + } + + retry = 0; + // No error, set ready, process and return ok + m_secureReady = true; + if (verifyCertFingerprint()) { + LOG((CLOG_INFO "connected to secure socket")); + if (!showCertificate()) { + disconnect(); + return -1; // Cert fail, error + } + } else { + LOG((CLOG_ERR "failed to verify server certificate fingerprint")); + disconnect(); + return -1; // Fingerprint failed, error + } + LOG((CLOG_DEBUG2 "connected secure socket")); + SslLogger::logSecureCipherInfo(m_ssl->m_ssl); + SslLogger::logSecureConnectInfo(m_ssl->m_ssl); + return 1; } -void -SecureSocket::checkResult(int status, int& retry) -{ - // ssl errors are a little quirky. the "want" errors are normal and - // should result in a retry. +bool SecureSocket::showCertificate() const { + X509 *cert; + char *line; - int errorCode = SSL_get_error(m_ssl->m_ssl, status); + // get the server's certificate + cert = SSL_get_peer_certificate(m_ssl->m_ssl); + if (cert != NULL) { + line = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0); + LOG((CLOG_INFO "server tls certificate info: %s", line)); + OPENSSL_free(line); + X509_free(cert); + } else { + SslLogger::logError("server has no tls certificate"); + return false; + } - switch (errorCode) { - case SSL_ERROR_NONE: - retry = 0; - // operation completed - break; + return true; +} - case SSL_ERROR_ZERO_RETURN: - // connection closed - isFatal(true); - LOG((CLOG_DEBUG "tls connection closed")); - break; +void SecureSocket::checkResult(int status, int &retry) { + // ssl errors are a little quirky. the "want" errors are normal and + // should result in a retry. - case SSL_ERROR_WANT_READ: - retry++; - LOG((CLOG_DEBUG2 "want to read, error=%d, attempt=%d", errorCode, retry)); - break; + int errorCode = SSL_get_error(m_ssl->m_ssl, status); - case SSL_ERROR_WANT_WRITE: - // Need to make sure the socket is known to be writable so the impending - // select action actually triggers on a write. This isn't necessary for - // m_readable because the socket logic is always readable - m_writable = true; - retry++; - LOG((CLOG_DEBUG2 "want to write, error=%d, attempt=%d", errorCode, retry)); - break; + switch (errorCode) { + case SSL_ERROR_NONE: + retry = 0; + // operation completed + break; - case SSL_ERROR_WANT_CONNECT: - retry++; - LOG((CLOG_DEBUG2 "want to connect, error=%d, attempt=%d", errorCode, retry)); - break; + case SSL_ERROR_ZERO_RETURN: + // connection closed + isFatal(true); + LOG((CLOG_DEBUG "tls connection closed")); + break; - case SSL_ERROR_WANT_ACCEPT: - retry++; - LOG((CLOG_DEBUG2 "want to accept, error=%d, attempt=%d", errorCode, retry)); - break; + case SSL_ERROR_WANT_READ: + retry++; + LOG((CLOG_DEBUG2 "want to read, error=%d, attempt=%d", errorCode, retry)); + break; - case SSL_ERROR_SYSCALL: - LOG((CLOG_ERR "tls error occurred (system call failure)")); - if (ERR_peek_error() == 0) { - if (status == 0) { - LOG((CLOG_ERR "eof violates tls protocol")); - } - else if (status == -1) { - // underlying socket I/O reproted an error - try { - ARCH->throwErrorOnSocket(getSocket()); - } - catch (XArchNetwork& e) { - LOG((CLOG_ERR "%s", e.what())); - } - } + case SSL_ERROR_WANT_WRITE: + // Need to make sure the socket is known to be writable so the impending + // select action actually triggers on a write. This isn't necessary for + // m_readable because the socket logic is always readable + m_writable = true; + retry++; + LOG((CLOG_DEBUG2 "want to write, error=%d, attempt=%d", errorCode, retry)); + break; + + case SSL_ERROR_WANT_CONNECT: + retry++; + LOG((CLOG_DEBUG2 "want to connect, error=%d, attempt=%d", errorCode, + retry)); + break; + + case SSL_ERROR_WANT_ACCEPT: + retry++; + LOG((CLOG_DEBUG2 "want to accept, error=%d, attempt=%d", errorCode, retry)); + break; + + case SSL_ERROR_SYSCALL: + LOG((CLOG_ERR "tls error occurred (system call failure)")); + if (ERR_peek_error() == 0) { + if (status == 0) { + LOG((CLOG_ERR "eof violates tls protocol")); + } else if (status == -1) { + // underlying socket I/O reproted an error + try { + ARCH->throwErrorOnSocket(getSocket()); + } catch (XArchNetwork &e) { + LOG((CLOG_ERR "%s", e.what())); } + } + } - isFatal(true); - break; - - case SSL_ERROR_SSL: - LOG((CLOG_ERR "tls error occurred (generic failure)")); - isFatal(true); - break; - - default: - LOG((CLOG_ERR "tls error occurred (unknown failure)")); - isFatal(true); + isFatal(true); + break; + + case SSL_ERROR_SSL: + LOG((CLOG_ERR "tls error occurred (generic failure)")); + isFatal(true); + break; + + default: + LOG((CLOG_ERR "tls error occurred (unknown failure)")); + isFatal(true); + break; + } + + if (isFatal()) { + retry = 0; + SslLogger::logError(); + disconnect(); + } +} + +void SecureSocket::disconnect() { + sendEvent(getEvents()->forISocket().stopRetry()); + sendEvent(getEvents()->forISocket().disconnected()); + sendEvent(getEvents()->forIStream().inputShutdown()); +} + +void SecureSocket::formatFingerprint(String &fingerprint, bool hex, + bool separator) { + if (hex) { + // to hexidecimal + synergy::string::toHex(fingerprint, 2); + } + + // all uppercase + synergy::string::uppercase(fingerprint); + + if (separator) { + // add colon to separate each 2 charactors + size_t separators = fingerprint.size() / 2; + for (size_t i = 1; i < separators; i++) { + fingerprint.insert(i * 3 - 1, ":"); + } + } +} + +bool SecureSocket::verifyCertFingerprint() { + // calculate received certificate fingerprint + using AutoX509 = std::unique_ptr; + AutoX509 cert(SSL_get_peer_certificate(m_ssl->m_ssl), &X509_free); + + unsigned char tempFingerprint[EVP_MAX_MD_SIZE]; + unsigned int tempFingerprintLen; + int digestResult = X509_digest(cert.get(), EVP_sha256(), tempFingerprint, + &tempFingerprintLen); + + if (digestResult <= 0) { + LOG((CLOG_ERR "failed to calculate fingerprint, digest result: %d", + digestResult)); + return false; + } + + // format fingerprint into hexdecimal format with colon separator + String fingerprint(static_cast(static_cast(tempFingerprint)), + tempFingerprintLen); + formatFingerprint(fingerprint); + LOG((CLOG_NOTE "server fingerprint: %s", fingerprint.c_str())); + + String trustedServersFilename; + trustedServersFilename = synergy::string::sprintf( + "%s/%s/%s", ARCH->getProfileDirectory().c_str(), kFingerprintDirName, + kFingerprintTrustedServersFilename); + + // check if this fingerprint exist + String fileLine; + std::ifstream file; + file.open(synergy::filesystem::path(trustedServersFilename)); + + bool isValid = false; + if (file.is_open()) { + while (!file.eof()) { + getline(file, fileLine); + if (!fileLine.empty() && !fileLine.compare(fingerprint)) { + isValid = true; break; + } } + } else { + LOG((CLOG_ERR "fail to open trusted fingerprints file: %s", + trustedServersFilename.c_str())); + } - if (isFatal()) { - retry = 0; - SslLogger::logError(); - disconnect(); - } + file.close(); + return isValid; } -void -SecureSocket::disconnect() -{ - sendEvent(getEvents()->forISocket().stopRetry()); - sendEvent(getEvents()->forISocket().disconnected()); - sendEvent(getEvents()->forIStream().inputShutdown()); -} +ISocketMultiplexerJob *SecureSocket::serviceConnect(ISocketMultiplexerJob *job, + bool, bool write, + bool error) { + Lock lock(&getMutex()); -void -SecureSocket::formatFingerprint(String& fingerprint, bool hex, bool separator) -{ - if (hex) { - // to hexidecimal - synergy::string::toHex(fingerprint, 2); - } - - // all uppercase - synergy::string::uppercase(fingerprint); - - if (separator) { - // add colon to separate each 2 charactors - size_t separators = fingerprint.size() / 2; - for (size_t i = 1; i < separators; i++) { - fingerprint.insert(i * 3 - 1, ":"); - } - } -} - -bool -SecureSocket::verifyCertFingerprint() -{ - // calculate received certificate fingerprint - using AutoX509 = std::unique_ptr; - AutoX509 cert(SSL_get_peer_certificate(m_ssl->m_ssl), &X509_free); - - unsigned char tempFingerprint[EVP_MAX_MD_SIZE]; - unsigned int tempFingerprintLen; - int digestResult = X509_digest(cert.get(), EVP_sha256(), tempFingerprint, &tempFingerprintLen); - - if (digestResult <= 0) { - LOG((CLOG_ERR "failed to calculate fingerprint, digest result: %d", digestResult)); - return false; - } - - // format fingerprint into hexdecimal format with colon separator - String fingerprint(static_cast(static_cast(tempFingerprint)), tempFingerprintLen); - formatFingerprint(fingerprint); - LOG((CLOG_NOTE "server fingerprint: %s", fingerprint.c_str())); - - String trustedServersFilename; - trustedServersFilename = synergy::string::sprintf( - "%s/%s/%s", - ARCH->getProfileDirectory().c_str(), - kFingerprintDirName, - kFingerprintTrustedServersFilename); - - // check if this fingerprint exist - String fileLine; - std::ifstream file; - file.open(synergy::filesystem::path(trustedServersFilename)); - - bool isValid = false; - if (file.is_open()) { - while (!file.eof()) { - getline(file,fileLine); - if (!fileLine.empty() && !fileLine.compare(fingerprint)) { - isValid = true; - break; - } - } - } - else { - LOG((CLOG_ERR "fail to open trusted fingerprints file: %s", trustedServersFilename.c_str())); - } - - file.close(); - return isValid; -} - -ISocketMultiplexerJob* -SecureSocket::serviceConnect(ISocketMultiplexerJob* job, - bool, bool write, bool error) -{ - Lock lock(&getMutex()); - - int status = 0; + int status = 0; #ifdef SYSAPI_WIN32 - status = secureConnect(static_cast(getSocket()->m_socket)); + status = secureConnect(static_cast(getSocket()->m_socket)); #elif SYSAPI_UNIX - status = secureConnect(getSocket()->m_fd); + status = secureConnect(getSocket()->m_fd); #endif - // If status < 0, error happened - if (status < 0) { - return NULL; - } + // If status < 0, error happened + if (status < 0) { + return NULL; + } - // If status > 0, success - if (status > 0) { - sendEvent(m_events->forIDataSocket().secureConnected()); - return newJob(); - } + // If status > 0, success + if (status > 0) { + sendEvent(m_events->forIDataSocket().secureConnected()); + return newJob(); + } - // Retry case - return new TSocketMultiplexerMethodJob( - this, &SecureSocket::serviceConnect, - getSocket(), isReadable(), isWritable()); + // Retry case + return new TSocketMultiplexerMethodJob( + this, &SecureSocket::serviceConnect, getSocket(), isReadable(), + isWritable()); } -ISocketMultiplexerJob* -SecureSocket::serviceAccept(ISocketMultiplexerJob* job, - bool, bool write, bool error) -{ - Lock lock(&getMutex()); +ISocketMultiplexerJob *SecureSocket::serviceAccept(ISocketMultiplexerJob *job, + bool, bool write, + bool error) { + Lock lock(&getMutex()); - int status = 0; + int status = 0; #ifdef SYSAPI_WIN32 - status = secureAccept(static_cast(getSocket()->m_socket)); + status = secureAccept(static_cast(getSocket()->m_socket)); #elif SYSAPI_UNIX - status = secureAccept(getSocket()->m_fd); + status = secureAccept(getSocket()->m_fd); #endif - // If status < 0, error happened - if (status < 0) { - return NULL; - } + // If status < 0, error happened + if (status < 0) { + return NULL; + } - // If status > 0, success - if (status > 0) { - sendEvent(m_events->forClientListener().accepted()); - return newJob(); - } + // If status > 0, success + if (status > 0) { + sendEvent(m_events->forClientListener().accepted()); + return newJob(); + } - // Retry case - return new TSocketMultiplexerMethodJob( - this, &SecureSocket::serviceAccept, - getSocket(), isReadable(), isWritable()); + // Retry case + return new TSocketMultiplexerMethodJob( + this, &SecureSocket::serviceAccept, getSocket(), isReadable(), + isWritable()); } -void -SecureSocket::handleTCPConnected(const Event&, void*) -{ - if (getSocket() == nullptr) { - LOG((CLOG_DEBUG "disregarding stale connect event")); - return; - } - secureConnect(); +void SecureSocket::handleTCPConnected(const Event &, void *) { + if (getSocket() == nullptr) { + LOG((CLOG_DEBUG "disregarding stale connect event")); + return; + } + secureConnect(); } diff --git a/src/lib/net/SecureSocket.h b/src/lib/net/SecureSocket.h index 1dba8c48e..12fe432b8 100644 --- a/src/lib/net/SecureSocket.h +++ b/src/lib/net/SecureSocket.h @@ -1,11 +1,11 @@ /* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2015-2016 Symless Ltd. - * + * * 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 LICENSE 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 @@ -32,64 +32,60 @@ A secure socket using SSL. */ class SecureSocket : public TCPSocket { public: - SecureSocket(IEventQueue* events, SocketMultiplexer* socketMultiplexer, IArchNetwork::EAddressFamily family); - SecureSocket(IEventQueue* events, - SocketMultiplexer* socketMultiplexer, - ArchSocket socket); - SecureSocket(SecureSocket const &) =delete; - SecureSocket(SecureSocket &&) =delete; - ~SecureSocket(); + SecureSocket(IEventQueue *events, SocketMultiplexer *socketMultiplexer, + IArchNetwork::EAddressFamily family); + SecureSocket(IEventQueue *events, SocketMultiplexer *socketMultiplexer, + ArchSocket socket); + SecureSocket(SecureSocket const &) = delete; + SecureSocket(SecureSocket &&) = delete; + ~SecureSocket(); - SecureSocket& operator=(SecureSocket const &) =delete; - SecureSocket& operator=(SecureSocket &&) =delete; + SecureSocket &operator=(SecureSocket const &) = delete; + SecureSocket &operator=(SecureSocket &&) = delete; - // ISocket overrides - void close() override; + // ISocket overrides + void close() override; - // IDataSocket overrides - virtual void connect(const NetworkAddress&); - - ISocketMultiplexerJob* - newJob(); - bool isFatal() const { return m_fatal; } - void isFatal(bool b) { m_fatal = b; } - bool isSecureReady(); - void secureConnect(); - void secureAccept(); - int secureRead(void* buffer, int size, int& read); - int secureWrite(const void* buffer, int size, int& wrote); - EJobResult doRead(); - EJobResult doWrite(); - void initSsl(bool server); - bool loadCertificates(String& CertFile); + // IDataSocket overrides + virtual void connect(const NetworkAddress &); + + ISocketMultiplexerJob *newJob(); + bool isFatal() const { return m_fatal; } + void isFatal(bool b) { m_fatal = b; } + bool isSecureReady(); + void secureConnect(); + void secureAccept(); + int secureRead(void *buffer, int size, int &read); + int secureWrite(const void *buffer, int size, int &wrote); + EJobResult doRead(); + EJobResult doWrite(); + void initSsl(bool server); + bool loadCertificates(String &CertFile); private: - // SSL - void initContext(bool server); - void createSSL(); - void freeSSL(); - int secureAccept(int s); - int secureConnect(int s); - bool showCertificate() const; - void checkResult(int n, int& retry); - void disconnect(); - void formatFingerprint(String& fingerprint, - bool hex = true, - bool separator = true); - bool verifyCertFingerprint(); + // SSL + void initContext(bool server); + void createSSL(); + void freeSSL(); + int secureAccept(int s); + int secureConnect(int s); + bool showCertificate() const; + void checkResult(int n, int &retry); + void disconnect(); + void formatFingerprint(String &fingerprint, bool hex = true, + bool separator = true); + bool verifyCertFingerprint(); - ISocketMultiplexerJob* - serviceConnect(ISocketMultiplexerJob*, - bool, bool, bool); + ISocketMultiplexerJob *serviceConnect(ISocketMultiplexerJob *, bool, bool, + bool); - ISocketMultiplexerJob* - serviceAccept(ISocketMultiplexerJob*, - bool, bool, bool); + ISocketMultiplexerJob *serviceAccept(ISocketMultiplexerJob *, bool, bool, + bool); - void handleTCPConnected(const Event& event, void*); + void handleTCPConnected(const Event &event, void *); private: - Ssl* m_ssl; - bool m_secureReady; - bool m_fatal; + Ssl *m_ssl; + bool m_secureReady; + bool m_fatal; }; diff --git a/src/lib/net/SocketMultiplexer.cpp b/src/lib/net/SocketMultiplexer.cpp index 77b5f0dd7..115dfe45e 100644 --- a/src/lib/net/SocketMultiplexer.cpp +++ b/src/lib/net/SocketMultiplexer.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 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 LICENSE 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 @@ -18,335 +18,309 @@ #include "net/SocketMultiplexer.h" -#include "net/ISocketMultiplexerJob.h" -#include "mt/CondVar.h" -#include "mt/Lock.h" -#include "mt/Mutex.h" -#include "mt/Thread.h" #include "arch/Arch.h" #include "arch/XArch.h" #include "base/Log.h" #include "base/TMethodJob.h" #include "common/stdvector.h" +#include "mt/CondVar.h" +#include "mt/Lock.h" +#include "mt/Mutex.h" +#include "mt/Thread.h" +#include "net/ISocketMultiplexerJob.h" // // SocketMultiplexer // -SocketMultiplexer::SocketMultiplexer() : - m_mutex(new Mutex), - m_thread(NULL), - m_update(false), - m_jobsReady(new CondVar(m_mutex, false)), - m_jobListLock(new CondVar(m_mutex, false)), - m_jobListLockLocked(new CondVar(m_mutex, false)), - m_jobListLocker(NULL), - m_jobListLockLocker(NULL) -{ - // this pointer just has to be unique and not NULL. it will - // never be dereferenced. it's used to identify cursor nodes - // in the jobs list. - // TODO: Remove this evilness - m_cursorMark = reinterpret_cast(this); +SocketMultiplexer::SocketMultiplexer() + : m_mutex(new Mutex), m_thread(NULL), m_update(false), + m_jobsReady(new CondVar(m_mutex, false)), + m_jobListLock(new CondVar(m_mutex, false)), + m_jobListLockLocked(new CondVar(m_mutex, false)), + m_jobListLocker(NULL), m_jobListLockLocker(NULL) { + // this pointer just has to be unique and not NULL. it will + // never be dereferenced. it's used to identify cursor nodes + // in the jobs list. + // TODO: Remove this evilness + m_cursorMark = reinterpret_cast(this); - // start thread - m_thread = new Thread(new TMethodJob( - this, &SocketMultiplexer::serviceThread)); + // start thread + m_thread = new Thread(new TMethodJob( + this, &SocketMultiplexer::serviceThread)); } -SocketMultiplexer::~SocketMultiplexer() -{ - m_thread->cancel(); - m_thread->unblockPollSocket(); - m_thread->wait(); - delete m_thread; - delete m_jobsReady; - delete m_jobListLock; - delete m_jobListLockLocked; - delete m_jobListLocker; - delete m_jobListLockLocker; - delete m_mutex; +SocketMultiplexer::~SocketMultiplexer() { + m_thread->cancel(); + m_thread->unblockPollSocket(); + m_thread->wait(); + delete m_thread; + delete m_jobsReady; + delete m_jobListLock; + delete m_jobListLockLocked; + delete m_jobListLocker; + delete m_jobListLockLocker; + delete m_mutex; - // clean up jobs - for (SocketJobMap::iterator i = m_socketJobMap.begin(); - i != m_socketJobMap.end(); ++i) { - delete *(i->second); + // clean up jobs + for (SocketJobMap::iterator i = m_socketJobMap.begin(); + i != m_socketJobMap.end(); ++i) { + delete *(i->second); + } +} + +void SocketMultiplexer::addSocket(ISocket *socket, ISocketMultiplexerJob *job) { + assert(socket != NULL); + assert(job != NULL); + + // prevent other threads from locking the job list + lockJobListLock(); + + // break thread out of poll + m_thread->unblockPollSocket(); + + // lock the job list + lockJobList(); + + // insert/replace job + SocketJobMap::iterator i = m_socketJobMap.find(socket); + if (i == m_socketJobMap.end()) { + // we *must* put the job at the end so the order of jobs in + // the list continue to match the order of jobs in pfds in + // serviceThread(). + JobCursor j = m_socketJobs.insert(m_socketJobs.end(), job); + m_update = true; + m_socketJobMap.insert(std::make_pair(socket, j)); + } else { + JobCursor j = i->second; + if (*j != job) { + delete *j; + *j = job; } + m_update = true; + } + + // unlock the job list + unlockJobList(); } -void -SocketMultiplexer::addSocket(ISocket* socket, ISocketMultiplexerJob* job) -{ - assert(socket != NULL); - assert(job != NULL); +void SocketMultiplexer::removeSocket(ISocket *socket) { + assert(socket != NULL); - // prevent other threads from locking the job list - lockJobListLock(); + // prevent other threads from locking the job list + lockJobListLock(); - // break thread out of poll - m_thread->unblockPollSocket(); + // break thread out of poll + m_thread->unblockPollSocket(); + + // lock the job list + lockJobList(); + + // remove job. rather than removing it from the map we put NULL + // in the list instead so the order of jobs in the list continues + // to match the order of jobs in pfds in serviceThread(). + SocketJobMap::iterator i = m_socketJobMap.find(socket); + if (i != m_socketJobMap.end()) { + if (*(i->second) != NULL) { + delete *(i->second); + *(i->second) = NULL; + m_update = true; + } + } + + // unlock the job list + unlockJobList(); +} + +void SocketMultiplexer::serviceThread(void *) { + std::vector pfds; + IArchNetwork::PollEntry pfd; + + // service the connections + for (;;) { + Thread::testCancel(); + + // wait until there are jobs to handle + { + Lock lock(m_mutex); + while (!(bool)*m_jobsReady) { + m_jobsReady->wait(); + } + } // lock the job list - lockJobList(); - - // insert/replace job - SocketJobMap::iterator i = m_socketJobMap.find(socket); - if (i == m_socketJobMap.end()) { - // we *must* put the job at the end so the order of jobs in - // the list continue to match the order of jobs in pfds in - // serviceThread(). - JobCursor j = m_socketJobs.insert(m_socketJobs.end(), job); - m_update = true; - m_socketJobMap.insert(std::make_pair(socket, j)); - } - else { - JobCursor j = i->second; - if (*j != job) { - delete *j; - *j = job; - } - m_update = true; - } - - // unlock the job list - unlockJobList(); -} - -void -SocketMultiplexer::removeSocket(ISocket* socket) -{ - assert(socket != NULL); - - // prevent other threads from locking the job list lockJobListLock(); - - // break thread out of poll - m_thread->unblockPollSocket(); - - // lock the job list lockJobList(); - // remove job. rather than removing it from the map we put NULL - // in the list instead so the order of jobs in the list continues - // to match the order of jobs in pfds in serviceThread(). - SocketJobMap::iterator i = m_socketJobMap.find(socket); - if (i != m_socketJobMap.end()) { - if (*(i->second) != NULL) { - delete *(i->second); - *(i->second) = NULL; - m_update = true; + // collect poll entries + if (m_update) { + m_update = false; + pfds.clear(); + pfds.reserve(m_socketJobMap.size()); + + JobCursor cursor = newCursor(); + JobCursor jobCursor = nextCursor(cursor); + while (jobCursor != m_socketJobs.end()) { + ISocketMultiplexerJob *job = *jobCursor; + if (job != NULL) { + pfd.m_socket = job->getSocket(); + pfd.m_events = 0; + if (job->isReadable()) { + pfd.m_events |= IArchNetwork::kPOLLIN; + } + if (job->isWritable()) { + pfd.m_events |= IArchNetwork::kPOLLOUT; + } + pfds.push_back(pfd); } + jobCursor = nextCursor(cursor); + } + deleteCursor(cursor); } - // unlock the job list - unlockJobList(); -} + int status; + try { + // check for status + if (!pfds.empty()) { + status = ARCH->pollSocket(&pfds[0], (int)pfds.size(), -1); + } else { + status = 0; + } + } catch (XArchNetwork &e) { + LOG((CLOG_WARN "error in socket multiplexer: %s", e.what())); + status = 0; + } -void -SocketMultiplexer::serviceThread(void*) -{ - std::vector pfds; - IArchNetwork::PollEntry pfd; + if (status != 0) { + // iterate over socket jobs, invoking each and saving the + // new job. + UInt32 i = 0; + JobCursor cursor = newCursor(); + JobCursor jobCursor = nextCursor(cursor); + while (i < pfds.size() && jobCursor != m_socketJobs.end()) { + if (*jobCursor != NULL) { + // get poll state + unsigned short revents = pfds[i].m_revents; + bool read = ((revents & IArchNetwork::kPOLLIN) != 0); + bool write = ((revents & IArchNetwork::kPOLLOUT) != 0); + bool error = + ((revents & (IArchNetwork::kPOLLERR | IArchNetwork::kPOLLNVAL)) != + 0); - // service the connections - for (;;) { - Thread::testCancel(); + // run job + ISocketMultiplexerJob *job = *jobCursor; + ISocketMultiplexerJob *newJob = job->run(read, write, error); - // wait until there are jobs to handle - { + // save job, if different + if (newJob != job) { Lock lock(m_mutex); - while (!(bool)*m_jobsReady) { - m_jobsReady->wait(); - } + delete job; + *jobCursor = newJob; + m_update = true; + } + ++i; } - // lock the job list - lockJobListLock(); - lockJobList(); - - // collect poll entries - if (m_update) { - m_update = false; - pfds.clear(); - pfds.reserve(m_socketJobMap.size()); - - JobCursor cursor = newCursor(); - JobCursor jobCursor = nextCursor(cursor); - while (jobCursor != m_socketJobs.end()) { - ISocketMultiplexerJob* job = *jobCursor; - if (job != NULL) { - pfd.m_socket = job->getSocket(); - pfd.m_events = 0; - if (job->isReadable()) { - pfd.m_events |= IArchNetwork::kPOLLIN; - } - if (job->isWritable()) { - pfd.m_events |= IArchNetwork::kPOLLOUT; - } - pfds.push_back(pfd); - } - jobCursor = nextCursor(cursor); - } - deleteCursor(cursor); - } - - int status; - try { - // check for status - if (!pfds.empty()) { - status = ARCH->pollSocket(&pfds[0], (int)pfds.size(), -1); - } - else { - status = 0; - } - } - catch (XArchNetwork& e) { - LOG((CLOG_WARN "error in socket multiplexer: %s", e.what())); - status = 0; - } - - if (status != 0) { - // iterate over socket jobs, invoking each and saving the - // new job. - UInt32 i = 0; - JobCursor cursor = newCursor(); - JobCursor jobCursor = nextCursor(cursor); - while (i < pfds.size() && jobCursor != m_socketJobs.end()) { - if (*jobCursor != NULL) { - // get poll state - unsigned short revents = pfds[i].m_revents; - bool read = ((revents & IArchNetwork::kPOLLIN) != 0); - bool write = ((revents & IArchNetwork::kPOLLOUT) != 0); - bool error = ((revents & (IArchNetwork::kPOLLERR | - IArchNetwork::kPOLLNVAL)) != 0); - - // run job - ISocketMultiplexerJob* job = *jobCursor; - ISocketMultiplexerJob* newJob = job->run(read, write, error); - - // save job, if different - if (newJob != job) { - Lock lock(m_mutex); - delete job; - *jobCursor = newJob; - m_update = true; - } - ++i; - } - - // next job - jobCursor = nextCursor(cursor); - } - deleteCursor(cursor); - } - - // delete any removed socket jobs - for (SocketJobMap::iterator i = m_socketJobMap.begin(); - i != m_socketJobMap.end();) { - if (*(i->second) == NULL) { - m_socketJobs.erase(i->second); - m_socketJobMap.erase(i++); - m_update = true; - } - else { - ++i; - } - } - - // unlock the job list - unlockJobList(); - } -} - -SocketMultiplexer::JobCursor -SocketMultiplexer::newCursor() -{ - Lock lock(m_mutex); - return m_socketJobs.insert(m_socketJobs.begin(), m_cursorMark); -} - -SocketMultiplexer::JobCursor -SocketMultiplexer::nextCursor(JobCursor cursor) -{ - Lock lock(m_mutex); - JobCursor j = m_socketJobs.end(); - JobCursor i = cursor; - while (++i != m_socketJobs.end()) { - if (*i != m_cursorMark) { - // found a real job (as opposed to a cursor) - j = i; - - // move our cursor just past the job - m_socketJobs.splice(++i, m_socketJobs, cursor); - break; - } - } - return j; -} - -void -SocketMultiplexer::deleteCursor(JobCursor cursor) -{ - Lock lock(m_mutex); - m_socketJobs.erase(cursor); -} - -void -SocketMultiplexer::lockJobListLock() -{ - Lock lock(m_mutex); - - // wait for the lock on the lock - while (*m_jobListLockLocked) { - m_jobListLockLocked->wait(); + // next job + jobCursor = nextCursor(cursor); + } + deleteCursor(cursor); } - // take ownership of the lock on the lock - *m_jobListLockLocked = true; - m_jobListLockLocker = new Thread(Thread::getCurrentThread()); -} - -void -SocketMultiplexer::lockJobList() -{ - Lock lock(m_mutex); - - // make sure we're the one that called lockJobListLock() - assert(*m_jobListLockLocker == Thread::getCurrentThread()); - - // wait for the job list lock - while (*m_jobListLock) { - m_jobListLock->wait(); + // delete any removed socket jobs + for (SocketJobMap::iterator i = m_socketJobMap.begin(); + i != m_socketJobMap.end();) { + if (*(i->second) == NULL) { + m_socketJobs.erase(i->second); + m_socketJobMap.erase(i++); + m_update = true; + } else { + ++i; + } } - // take ownership of the lock - *m_jobListLock = true; - m_jobListLocker = m_jobListLockLocker; - m_jobListLockLocker = NULL; - - // release the lock on the lock - *m_jobListLockLocked = false; - m_jobListLockLocked->broadcast(); + // unlock the job list + unlockJobList(); + } } -void -SocketMultiplexer::unlockJobList() -{ - Lock lock(m_mutex); +SocketMultiplexer::JobCursor SocketMultiplexer::newCursor() { + Lock lock(m_mutex); + return m_socketJobs.insert(m_socketJobs.begin(), m_cursorMark); +} - // make sure we're the one that called lockJobList() - assert(*m_jobListLocker == Thread::getCurrentThread()); +SocketMultiplexer::JobCursor SocketMultiplexer::nextCursor(JobCursor cursor) { + Lock lock(m_mutex); + JobCursor j = m_socketJobs.end(); + JobCursor i = cursor; + while (++i != m_socketJobs.end()) { + if (*i != m_cursorMark) { + // found a real job (as opposed to a cursor) + j = i; - // release the lock - delete m_jobListLocker; - m_jobListLocker = NULL; - *m_jobListLock = false; - m_jobListLock->signal(); - - // set new jobs ready state - bool isReady = !m_socketJobMap.empty(); - if (*m_jobsReady != isReady) { - *m_jobsReady = isReady; - m_jobsReady->signal(); + // move our cursor just past the job + m_socketJobs.splice(++i, m_socketJobs, cursor); + break; } + } + return j; +} + +void SocketMultiplexer::deleteCursor(JobCursor cursor) { + Lock lock(m_mutex); + m_socketJobs.erase(cursor); +} + +void SocketMultiplexer::lockJobListLock() { + Lock lock(m_mutex); + + // wait for the lock on the lock + while (*m_jobListLockLocked) { + m_jobListLockLocked->wait(); + } + + // take ownership of the lock on the lock + *m_jobListLockLocked = true; + m_jobListLockLocker = new Thread(Thread::getCurrentThread()); +} + +void SocketMultiplexer::lockJobList() { + Lock lock(m_mutex); + + // make sure we're the one that called lockJobListLock() + assert(*m_jobListLockLocker == Thread::getCurrentThread()); + + // wait for the job list lock + while (*m_jobListLock) { + m_jobListLock->wait(); + } + + // take ownership of the lock + *m_jobListLock = true; + m_jobListLocker = m_jobListLockLocker; + m_jobListLockLocker = NULL; + + // release the lock on the lock + *m_jobListLockLocked = false; + m_jobListLockLocked->broadcast(); +} + +void SocketMultiplexer::unlockJobList() { + Lock lock(m_mutex); + + // make sure we're the one that called lockJobList() + assert(*m_jobListLocker == Thread::getCurrentThread()); + + // release the lock + delete m_jobListLocker; + m_jobListLocker = NULL; + *m_jobListLock = false; + m_jobListLock->signal(); + + // set new jobs ready state + bool isReady = !m_socketJobMap.empty(); + if (*m_jobsReady != isReady) { + *m_jobsReady = isReady; + m_jobsReady->signal(); + } } diff --git a/src/lib/net/SocketMultiplexer.h b/src/lib/net/SocketMultiplexer.h index 9863f4888..70f8d291b 100644 --- a/src/lib/net/SocketMultiplexer.h +++ b/src/lib/net/SocketMultiplexer.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 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 LICENSE 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 @@ -22,8 +22,7 @@ #include "common/stdlist.h" #include "common/stdmap.h" -template -class CondVar; +template class CondVar; class Mutex; class Thread; class ISocket; @@ -35,82 +34,80 @@ A socket multiplexer services multiple sockets simultaneously. */ class SocketMultiplexer { public: - SocketMultiplexer(); - SocketMultiplexer(SocketMultiplexer const &) =delete; - SocketMultiplexer(SocketMultiplexer &&) =delete; - ~SocketMultiplexer(); + SocketMultiplexer(); + SocketMultiplexer(SocketMultiplexer const &) = delete; + SocketMultiplexer(SocketMultiplexer &&) = delete; + ~SocketMultiplexer(); - SocketMultiplexer& operator=(SocketMultiplexer const &) =delete; - SocketMultiplexer& operator=(SocketMultiplexer &&) =delete; + SocketMultiplexer &operator=(SocketMultiplexer const &) = delete; + SocketMultiplexer &operator=(SocketMultiplexer &&) = delete; - //! @name manipulators - //@{ + //! @name manipulators + //@{ - void addSocket(ISocket*, ISocketMultiplexerJob*); + void addSocket(ISocket *, ISocketMultiplexerJob *); - void removeSocket(ISocket*); + void removeSocket(ISocket *); - //@} - //! @name accessors - //@{ + //@} + //! @name accessors + //@{ - // maybe belongs on ISocketMultiplexer - static SocketMultiplexer* - getInstance(); + // maybe belongs on ISocketMultiplexer + static SocketMultiplexer *getInstance(); - //@} + //@} private: - // list of jobs. we use a list so we can safely iterate over it - // while other threads modify it. - typedef std::list SocketJobs; - typedef SocketJobs::iterator JobCursor; - typedef std::map SocketJobMap; + // list of jobs. we use a list so we can safely iterate over it + // while other threads modify it. + typedef std::list SocketJobs; + typedef SocketJobs::iterator JobCursor; + typedef std::map SocketJobMap; - // service sockets. the service thread will only access m_sockets - // and m_update while m_pollable and m_polling are true. all other - // threads must only modify these when m_pollable and m_polling are - // false. only the service thread sets m_polling. - void serviceThread(void*); + // service sockets. the service thread will only access m_sockets + // and m_update while m_pollable and m_polling are true. all other + // threads must only modify these when m_pollable and m_polling are + // false. only the service thread sets m_polling. + void serviceThread(void *); - // create, iterate, and destroy a cursor. a cursor is used to - // safely iterate through the job list while other threads modify - // the list. it works by inserting a dummy item in the list and - // moving that item through the list. the dummy item will never - // be removed by other edits so an iterator pointing at the item - // remains valid until we remove the dummy item in deleteCursor(). - // nextCursor() finds the next non-dummy item, moves our dummy - // item just past it, and returns an iterator for the non-dummy - // item. all cursor calls lock the mutex for their duration. - JobCursor newCursor(); - JobCursor nextCursor(JobCursor); - void deleteCursor(JobCursor); + // create, iterate, and destroy a cursor. a cursor is used to + // safely iterate through the job list while other threads modify + // the list. it works by inserting a dummy item in the list and + // moving that item through the list. the dummy item will never + // be removed by other edits so an iterator pointing at the item + // remains valid until we remove the dummy item in deleteCursor(). + // nextCursor() finds the next non-dummy item, moves our dummy + // item just past it, and returns an iterator for the non-dummy + // item. all cursor calls lock the mutex for their duration. + JobCursor newCursor(); + JobCursor nextCursor(JobCursor); + void deleteCursor(JobCursor); - // lock out locking the job list. this blocks if another thread - // has already locked out locking. once it returns, only the - // calling thread will be able to lock the job list after any - // current lock is released. - void lockJobListLock(); + // lock out locking the job list. this blocks if another thread + // has already locked out locking. once it returns, only the + // calling thread will be able to lock the job list after any + // current lock is released. + void lockJobListLock(); - // lock the job list. this blocks if the job list is already - // locked. the calling thread must have called requestJobLock. - void lockJobList(); + // lock the job list. this blocks if the job list is already + // locked. the calling thread must have called requestJobLock. + void lockJobList(); - // unlock the job list and the lock out on locking. - void unlockJobList(); + // unlock the job list and the lock out on locking. + void unlockJobList(); private: - Mutex* m_mutex; - Thread* m_thread; - bool m_update; - CondVar* m_jobsReady; - CondVar* m_jobListLock; - CondVar* m_jobListLockLocked; - Thread* m_jobListLocker; - Thread* m_jobListLockLocker; + Mutex *m_mutex; + Thread *m_thread; + bool m_update; + CondVar *m_jobsReady; + CondVar *m_jobListLock; + CondVar *m_jobListLockLocked; + Thread *m_jobListLocker; + Thread *m_jobListLockLocker; - SocketJobs m_socketJobs; - SocketJobMap m_socketJobMap; - ISocketMultiplexerJob* - m_cursorMark; + SocketJobs m_socketJobs; + SocketJobMap m_socketJobMap; + ISocketMultiplexerJob *m_cursorMark; }; diff --git a/src/lib/net/TCPListenSocket.cpp b/src/lib/net/TCPListenSocket.cpp index 069d5798b..32aab23d3 100644 --- a/src/lib/net/TCPListenSocket.cpp +++ b/src/lib/net/TCPListenSocket.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -18,143 +18,125 @@ #include "net/TCPListenSocket.h" +#include "arch/Arch.h" +#include "arch/XArch.h" +#include "base/IEventQueue.h" +#include "base/Log.h" +#include "io/XIO.h" +#include "mt/Lock.h" +#include "mt/Mutex.h" #include "net/NetworkAddress.h" #include "net/SocketMultiplexer.h" #include "net/TCPSocket.h" #include "net/TSocketMultiplexerMethodJob.h" #include "net/XSocket.h" -#include "io/XIO.h" -#include "mt/Lock.h" -#include "mt/Mutex.h" -#include "arch/Arch.h" -#include "arch/XArch.h" -#include "base/Log.h" -#include "base/IEventQueue.h" // // TCPListenSocket // -TCPListenSocket::TCPListenSocket(IEventQueue* events, SocketMultiplexer* socketMultiplexer, IArchNetwork::EAddressFamily family) : - m_events(events), - m_socketMultiplexer(socketMultiplexer) -{ - m_mutex = new Mutex; - try { - m_socket = ARCH->newSocket(family, IArchNetwork::kSTREAM); - } - catch (XArchNetwork& e) { - throw XSocketCreate(e.what()); - } +TCPListenSocket::TCPListenSocket(IEventQueue *events, + SocketMultiplexer *socketMultiplexer, + IArchNetwork::EAddressFamily family) + : m_events(events), m_socketMultiplexer(socketMultiplexer) { + m_mutex = new Mutex; + try { + m_socket = ARCH->newSocket(family, IArchNetwork::kSTREAM); + } catch (XArchNetwork &e) { + throw XSocketCreate(e.what()); + } } -TCPListenSocket::~TCPListenSocket() -{ - try { - if (m_socket != NULL) { - m_socketMultiplexer->removeSocket(this); - ARCH->closeSocket(m_socket); - } +TCPListenSocket::~TCPListenSocket() { + try { + if (m_socket != NULL) { + m_socketMultiplexer->removeSocket(this); + ARCH->closeSocket(m_socket); } - catch (...) { - // ignore - LOG((CLOG_WARN "error while closing TCP socket")); - } - delete m_mutex; + } catch (...) { + // ignore + LOG((CLOG_WARN "error while closing TCP socket")); + } + delete m_mutex; } -void -TCPListenSocket::bind(const NetworkAddress& addr) -{ - try { - Lock lock(m_mutex); - ARCH->setReuseAddrOnSocket(m_socket, true); - ARCH->bindSocket(m_socket, addr.getAddress()); - ARCH->listenOnSocket(m_socket); - m_socketMultiplexer->addSocket(this, - new TSocketMultiplexerMethodJob( - this, &TCPListenSocket::serviceListening, - m_socket, true, false)); - } - catch (XArchNetworkAddressInUse& e) { - throw XSocketAddressInUse(e.what()); - } - catch (XArchNetwork& e) { - throw XSocketBind(e.what()); - } -} - -void -TCPListenSocket::close() -{ +void TCPListenSocket::bind(const NetworkAddress &addr) { + try { Lock lock(m_mutex); - if (m_socket == NULL) { - throw XIOClosed(); - } - try { - m_socketMultiplexer->removeSocket(this); - ARCH->closeSocket(m_socket); - m_socket = NULL; - } - catch (XArchNetwork& e) { - throw XSocketIOClose(e.what()); - } + ARCH->setReuseAddrOnSocket(m_socket, true); + ARCH->bindSocket(m_socket, addr.getAddress()); + ARCH->listenOnSocket(m_socket); + m_socketMultiplexer->addSocket( + this, + new TSocketMultiplexerMethodJob( + this, &TCPListenSocket::serviceListening, m_socket, true, false)); + } catch (XArchNetworkAddressInUse &e) { + throw XSocketAddressInUse(e.what()); + } catch (XArchNetwork &e) { + throw XSocketBind(e.what()); + } } -void* -TCPListenSocket::getEventTarget() const -{ - return const_cast(static_cast(this)); +void TCPListenSocket::close() { + Lock lock(m_mutex); + if (m_socket == NULL) { + throw XIOClosed(); + } + try { + m_socketMultiplexer->removeSocket(this); + ARCH->closeSocket(m_socket); + m_socket = NULL; + } catch (XArchNetwork &e) { + throw XSocketIOClose(e.what()); + } } -IDataSocket* -TCPListenSocket::accept() -{ - IDataSocket* socket = NULL; - try { - socket = new TCPSocket(m_events, m_socketMultiplexer, ARCH->acceptSocket(m_socket, NULL)); - if (socket != NULL) { - setListeningJob(); - } - return socket; - } - catch (XArchNetwork&) { - if (socket != NULL) { - delete socket; - setListeningJob(); - } - return NULL; - } - catch (std::exception &ex) { - if (socket != NULL) { - delete socket; - setListeningJob(); - } - throw ex; - } +void *TCPListenSocket::getEventTarget() const { + return const_cast(static_cast(this)); } -void -TCPListenSocket::setListeningJob() -{ - m_socketMultiplexer->addSocket(this, - new TSocketMultiplexerMethodJob( - this, &TCPListenSocket::serviceListening, - m_socket, true, false)); +IDataSocket *TCPListenSocket::accept() { + IDataSocket *socket = NULL; + try { + socket = new TCPSocket(m_events, m_socketMultiplexer, + ARCH->acceptSocket(m_socket, NULL)); + if (socket != NULL) { + setListeningJob(); + } + return socket; + } catch (XArchNetwork &) { + if (socket != NULL) { + delete socket; + setListeningJob(); + } + return NULL; + } catch (std::exception &ex) { + if (socket != NULL) { + delete socket; + setListeningJob(); + } + throw ex; + } } -ISocketMultiplexerJob* -TCPListenSocket::serviceListening(ISocketMultiplexerJob* job, - bool read, bool, bool error) -{ - if (error) { - close(); - return NULL; - } - if (read) { - m_events->addEvent(Event(m_events->forIListenSocket().connecting(), this)); - // stop polling on this socket until the client accepts - return NULL; - } - return job; +void TCPListenSocket::setListeningJob() { + m_socketMultiplexer->addSocket( + this, + new TSocketMultiplexerMethodJob( + this, &TCPListenSocket::serviceListening, m_socket, true, false)); +} + +ISocketMultiplexerJob * +TCPListenSocket::serviceListening(ISocketMultiplexerJob *job, bool read, bool, + bool error) { + if (error) { + close(); + return NULL; + } + if (read) { + m_events->addEvent(Event(m_events->forIListenSocket().connecting(), this)); + // stop polling on this socket until the client accepts + return NULL; + } + return job; } diff --git a/src/lib/net/TCPListenSocket.h b/src/lib/net/TCPListenSocket.h index b576055c8..021b61957 100644 --- a/src/lib/net/TCPListenSocket.h +++ b/src/lib/net/TCPListenSocket.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -18,8 +18,8 @@ #pragma once -#include "net/IListenSocket.h" #include "arch/IArchNetwork.h" +#include "net/IListenSocket.h" class Mutex; class ISocketMultiplexerJob; @@ -32,34 +32,33 @@ A listen socket using TCP. */ class TCPListenSocket : public IListenSocket { public: - TCPListenSocket(IEventQueue* events, SocketMultiplexer* socketMultiplexer, IArchNetwork::EAddressFamily family); - TCPListenSocket(TCPListenSocket const &) =delete; - TCPListenSocket(TCPListenSocket &&) =delete; - virtual ~TCPListenSocket(); + TCPListenSocket(IEventQueue *events, SocketMultiplexer *socketMultiplexer, + IArchNetwork::EAddressFamily family); + TCPListenSocket(TCPListenSocket const &) = delete; + TCPListenSocket(TCPListenSocket &&) = delete; + virtual ~TCPListenSocket(); - TCPListenSocket& operator=(TCPListenSocket const &) =delete; - TCPListenSocket& operator=(TCPListenSocket &&) =delete; + TCPListenSocket &operator=(TCPListenSocket const &) = delete; + TCPListenSocket &operator=(TCPListenSocket &&) = delete; - // ISocket overrides - virtual void bind(const NetworkAddress&); - virtual void close(); - virtual void* getEventTarget() const; + // ISocket overrides + virtual void bind(const NetworkAddress &); + virtual void close(); + virtual void *getEventTarget() const; - // IListenSocket overrides - virtual IDataSocket* - accept(); + // IListenSocket overrides + virtual IDataSocket *accept(); protected: - void setListeningJob(); + void setListeningJob(); public: - ISocketMultiplexerJob* - serviceListening(ISocketMultiplexerJob*, - bool, bool, bool); + ISocketMultiplexerJob *serviceListening(ISocketMultiplexerJob *, bool, bool, + bool); protected: - ArchSocket m_socket; - Mutex* m_mutex; - IEventQueue* m_events; - SocketMultiplexer* m_socketMultiplexer; + ArchSocket m_socket; + Mutex *m_mutex; + IEventQueue *m_events; + SocketMultiplexer *m_socketMultiplexer; }; diff --git a/src/lib/net/TCPSocket.cpp b/src/lib/net/TCPSocket.cpp index 431a65472..4b136d579 100644 --- a/src/lib/net/TCPSocket.cpp +++ b/src/lib/net/TCPSocket.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -18,587 +18,506 @@ #include "net/TCPSocket.h" +#include "arch/Arch.h" +#include "arch/XArch.h" +#include "base/IEventJob.h" +#include "base/IEventQueue.h" +#include "base/Log.h" +#include "mt/Lock.h" #include "net/NetworkAddress.h" #include "net/SocketMultiplexer.h" #include "net/TSocketMultiplexerMethodJob.h" #include "net/XSocket.h" -#include "mt/Lock.h" -#include "arch/Arch.h" -#include "arch/XArch.h" -#include "base/Log.h" -#include "base/IEventQueue.h" -#include "base/IEventJob.h" -#include #include +#include #include // // TCPSocket // -TCPSocket::TCPSocket(IEventQueue* events, SocketMultiplexer* socketMultiplexer, IArchNetwork::EAddressFamily family) : - IDataSocket(events), - m_events(events), - m_mutex(), - m_flushed(&m_mutex, true), - m_socketMultiplexer(socketMultiplexer) -{ +TCPSocket::TCPSocket(IEventQueue *events, SocketMultiplexer *socketMultiplexer, + IArchNetwork::EAddressFamily family) + : IDataSocket(events), m_events(events), m_mutex(), + m_flushed(&m_mutex, true), m_socketMultiplexer(socketMultiplexer) { + try { + m_socket = ARCH->newSocket(family, IArchNetwork::kSTREAM); + } catch (const XArchNetwork &e) { + throw XSocketCreate(e.what()); + } + + LOG((CLOG_DEBUG "opening new socket: %08X", m_socket)); + + init(); +} + +TCPSocket::TCPSocket(IEventQueue *events, SocketMultiplexer *socketMultiplexer, + ArchSocket socket) + : IDataSocket(events), m_events(events), m_mutex(), m_socket(socket), + m_flushed(&m_mutex, true), m_socketMultiplexer(socketMultiplexer) { + assert(m_socket != nullptr); + + LOG((CLOG_DEBUG "opening new socket: %08X", m_socket)); + + // socket starts in connected state + init(); + onConnected(); + setJob(newJob()); +} + +TCPSocket::~TCPSocket() { + try { + // warning virtual function in destructor is very danger practice + close(); + } catch (...) { + LOG((CLOG_DEBUG "error while TCP socket destruction")); + } +} + +void TCPSocket::bind(const NetworkAddress &addr) { + try { + ARCH->bindSocket(m_socket, addr.getAddress()); + } catch (const XArchNetworkAddressInUse &e) { + throw XSocketAddressInUse(e.what()); + } catch (const XArchNetwork &e) { + throw XSocketBind(e.what()); + } +} + +void TCPSocket::close() { + LOG((CLOG_DEBUG "closing socket: %08X", m_socket)); + + // remove ourself from the multiplexer + setJob(nullptr); + + Lock lock(&m_mutex); + + // clear buffers and enter disconnected state + if (m_connected) { + sendEvent(m_events->forISocket().disconnected()); + } + onDisconnected(); + + // close the socket + if (m_socket != nullptr) { + ArchSocket socket = m_socket; + m_socket = nullptr; try { - m_socket = ARCH->newSocket(family, IArchNetwork::kSTREAM); + ARCH->closeSocket(socket); + } catch (const XArchNetwork &e) { + // ignore, there's not much we can do + LOG((CLOG_WARN "error closing socket: %s", e.what())); } - catch (const XArchNetwork& e) { - throw XSocketCreate(e.what()); - } - - LOG((CLOG_DEBUG "opening new socket: %08X", m_socket)); - - init(); + } } -TCPSocket::TCPSocket(IEventQueue* events, SocketMultiplexer* socketMultiplexer, ArchSocket socket) : - IDataSocket(events), - m_events(events), - m_mutex(), - m_socket(socket), - m_flushed(&m_mutex, true), - m_socketMultiplexer(socketMultiplexer) -{ - assert(m_socket != nullptr); - - LOG((CLOG_DEBUG "opening new socket: %08X", m_socket)); - - // socket starts in connected state - init(); - onConnected(); - setJob(newJob()); +void *TCPSocket::getEventTarget() const { + return const_cast(static_cast(this)); } -TCPSocket::~TCPSocket() -{ - try { - // warning virtual function in destructor is very danger practice - close(); - } - catch (...) { - LOG((CLOG_DEBUG "error while TCP socket destruction")); - } -} +UInt32 TCPSocket::read(void *buffer, UInt32 n) { + // copy data directly from our input buffer + Lock lock(&m_mutex); + UInt32 size = m_inputBuffer.getSize(); + if (n > size) { + n = size; + } + if (buffer != nullptr && n != 0) { + memcpy(buffer, m_inputBuffer.peek(n), n); + } + m_inputBuffer.pop(n); -void -TCPSocket::bind(const NetworkAddress& addr) -{ - try { - ARCH->bindSocket(m_socket, addr.getAddress()); - } - catch (const XArchNetworkAddressInUse& e) { - throw XSocketAddressInUse(e.what()); - } - catch (const XArchNetwork& e) { - throw XSocketBind(e.what()); - } -} - -void -TCPSocket::close() -{ - LOG((CLOG_DEBUG "closing socket: %08X", m_socket)); - - // remove ourself from the multiplexer - setJob(nullptr); - - Lock lock(&m_mutex); - - // clear buffers and enter disconnected state - if (m_connected) { - sendEvent(m_events->forISocket().disconnected()); - } - onDisconnected(); - - // close the socket - if (m_socket != nullptr) { - ArchSocket socket = m_socket; - m_socket = nullptr; - try { - ARCH->closeSocket(socket); - } - catch (const XArchNetwork& e) { - // ignore, there's not much we can do - LOG((CLOG_WARN "error closing socket: %s", e.what())); - } - } -} - -void* -TCPSocket::getEventTarget() const -{ - return const_cast(static_cast(this)); -} - -UInt32 -TCPSocket::read(void* buffer, UInt32 n) -{ - // copy data directly from our input buffer - Lock lock(&m_mutex); - UInt32 size = m_inputBuffer.getSize(); - if (n > size) { - n = size; - } - if (buffer != nullptr && n != 0) { - memcpy(buffer, m_inputBuffer.peek(n), n); - } - m_inputBuffer.pop(n); - - // if no more data and we cannot read or write then send disconnected - if (n > 0 && m_inputBuffer.getSize() == 0 && !m_readable && !m_writable) { - sendEvent(m_events->forISocket().disconnected()); - m_connected = false; - } - - return n; -} - -void -TCPSocket::write(const void* buffer, UInt32 n) -{ - bool wasEmpty; - { - Lock lock(&m_mutex); - - // must not have shutdown output - if (!m_writable) { - sendEvent(m_events->forIStream().outputError()); - return; - } - - // ignore empty writes - if (n == 0) { - return; - } - - // copy data to the output buffer - wasEmpty = (m_outputBuffer.getSize() == 0); - m_outputBuffer.write(buffer, n); - - // there's data to write - m_flushed = false; - } - - // make sure we're waiting to write - if (wasEmpty) { - setJob(newJob()); - } -} - -void -TCPSocket::flush() -{ - Lock lock(&m_mutex); - while (m_flushed == false) { - m_flushed.wait(); - } -} - -void -TCPSocket::shutdownInput() -{ - bool useNewJob = false; - { - Lock lock(&m_mutex); - - // shutdown socket for reading - try { - ARCH->closeSocketForRead(m_socket); - } - catch (const XArchNetwork& e) { - // ignore, there's not much we can do - LOG((CLOG_WARN "error closing socket: %s", e.what())); - } - - // shutdown buffer for reading - if (m_readable) { - sendEvent(m_events->forIStream().inputShutdown()); - onInputShutdown(); - useNewJob = true; - } - } - if (useNewJob) { - setJob(newJob()); - } -} - -void -TCPSocket::shutdownOutput() -{ - bool useNewJob = false; - { - Lock lock(&m_mutex); - - // shutdown socket for writing - try { - ARCH->closeSocketForWrite(m_socket); - } - catch (const XArchNetwork& e) { - // ignore, there's not much we can do - LOG((CLOG_WARN "error closing socket: %s", e.what())); - } - - // shutdown buffer for writing - if (m_writable) { - sendEvent(m_events->forIStream().outputShutdown()); - onOutputShutdown(); - useNewJob = true; - } - } - if (useNewJob) { - setJob(newJob()); - } -} - -bool -TCPSocket::isReady() const -{ - Lock lock(&m_mutex); - return (m_inputBuffer.getSize() > 0); -} - -bool -TCPSocket::isFatal() const -{ - // TCP sockets aren't ever left in a fatal state. - LOG((CLOG_ERR "isFatal() not valid for non-secure connections")); - return false; -} - -UInt32 -TCPSocket::getSize() const -{ - Lock lock(&m_mutex); - return m_inputBuffer.getSize(); -} - -void -TCPSocket::connect(const NetworkAddress& addr) -{ - { - Lock lock(&m_mutex); - - // fail on attempts to reconnect - if (m_socket == nullptr || m_connected) { - sendConnectionFailedEvent("busy"); - return; - } - - try { - if (ARCH->connectSocket(m_socket, addr.getAddress())) { - sendEvent(m_events->forIDataSocket().connected()); - onConnected(); - } - else { - // connection is in progress - m_writable = true; - } - } - catch (const XArchNetwork& e) { - throw XSocketConnect(e.what()); - } - } - setJob(newJob()); -} - -void -TCPSocket::init() -{ - // default state + // if no more data and we cannot read or write then send disconnected + if (n > 0 && m_inputBuffer.getSize() == 0 && !m_readable && !m_writable) { + sendEvent(m_events->forISocket().disconnected()); m_connected = false; - m_readable = false; - m_writable = false; + } - try { - // turn off Nagle algorithm. we send lots of very short messages - // that should be sent without (much) delay. for example, the - // mouse motion messages are much less useful if they're delayed. - ARCH->setNoDelayOnSocket(m_socket, true); - } - catch (const XArchNetwork& e) { - try { - ARCH->closeSocket(m_socket); - m_socket = nullptr; - } - catch (const XArchNetwork& e) { - // ignore, there's not much we can do - LOG((CLOG_WARN "error closing socket: %s", e.what())); - } - throw XSocketCreate(e.what()); - } + return n; } -TCPSocket::EJobResult -TCPSocket::doRead() -{ - UInt8 buffer[4096]; - memset(buffer, 0, sizeof(buffer)); - size_t bytesRead = 0; - - bytesRead = ARCH->readSocket(m_socket, buffer, sizeof(buffer)); - - if (bytesRead > 0) { - bool wasEmpty = (m_inputBuffer.getSize() == 0); - - // slurp up as much as possible - do { - m_inputBuffer.write(buffer, static_cast(bytesRead)); - - bytesRead = ARCH->readSocket(m_socket, buffer, sizeof(buffer)); - } while (bytesRead > 0); - - // send input ready if input buffer was empty - if (wasEmpty) { - sendEvent(m_events->forIStream().inputReady()); - } - } - else { - // remote write end of stream hungup. our input side - // has therefore shutdown but don't flush our buffer - // since there's still data to be read. - sendEvent(m_events->forIStream().inputShutdown()); - if (!m_writable && m_inputBuffer.getSize() == 0) { - sendEvent(m_events->forISocket().disconnected()); - m_connected = false; - } - m_readable = false; - return kNew; - } - - return kRetry; -} - -TCPSocket::EJobResult -TCPSocket::doWrite() -{ - // write data - UInt32 bufferSize = 0; - int bytesWrote = 0; - - bufferSize = m_outputBuffer.getSize(); - const void* buffer = m_outputBuffer.peek(bufferSize); - bytesWrote = (UInt32)ARCH->writeSocket(m_socket, buffer, bufferSize); - - if (bytesWrote > 0) { - discardWrittenData(bytesWrote); - return kNew; - } - - return kRetry; -} - -void -TCPSocket::setJob(ISocketMultiplexerJob* job) -{ - // multiplexer will delete the old job - if (job == nullptr) { - m_socketMultiplexer->removeSocket(this); - } - else { - m_socketMultiplexer->addSocket(this, job); - } -} - -ISocketMultiplexerJob* -TCPSocket::newJob() -{ - // note -- must have m_mutex locked on entry - - if (m_socket == nullptr) { - return nullptr; - } - else if (!m_connected) { - assert(!m_readable); - if (!(m_readable || m_writable)) { - return nullptr; - } - return new TSocketMultiplexerMethodJob( - this, &TCPSocket::serviceConnecting, - m_socket, m_readable, m_writable); - } - else { - if (!(m_readable || (m_writable && (m_outputBuffer.getSize() > 0)))) { - return nullptr; - } - return new TSocketMultiplexerMethodJob( - this, &TCPSocket::serviceConnected, - m_socket, m_readable, - m_writable && (m_outputBuffer.getSize() > 0)); - } -} - -void -TCPSocket::sendConnectionFailedEvent(const char* msg) -{ - ConnectionFailedInfo* info = new ConnectionFailedInfo(msg); - m_events->addEvent(Event(m_events->forIDataSocket().connectionFailed(), - getEventTarget(), info, Event::kDontFreeData)); -} - -void -TCPSocket::sendEvent(Event::Type type) -{ - m_events->addEvent(Event(type, getEventTarget())); -} - -void -TCPSocket::discardWrittenData(int bytesWrote) -{ - m_outputBuffer.pop(bytesWrote); - if (m_outputBuffer.getSize() == 0) { - sendEvent(m_events->forIStream().outputFlushed()); - m_flushed = true; - m_flushed.broadcast(); - } -} - -void -TCPSocket::onConnected() -{ - m_connected = true; - m_readable = true; - m_writable = true; -} - -void -TCPSocket::onInputShutdown() -{ - m_inputBuffer.pop(m_inputBuffer.getSize()); - m_readable = false; -} - -void -TCPSocket::onOutputShutdown() -{ - m_outputBuffer.pop(m_outputBuffer.getSize()); - m_writable = false; - - // we're now flushed - m_flushed = true; - m_flushed.broadcast(); -} - -void -TCPSocket::onDisconnected() -{ - // disconnected - onInputShutdown(); - onOutputShutdown(); - m_connected = false; -} - -ISocketMultiplexerJob* -TCPSocket::serviceConnecting(ISocketMultiplexerJob* job, - bool, bool write, bool error) -{ +void TCPSocket::write(const void *buffer, UInt32 n) { + bool wasEmpty; + { Lock lock(&m_mutex); - // should only check for errors if error is true but checking a new - // socket (and a socket that's connecting should be new) for errors - // should be safe and Mac OS X appears to have a bug where a - // non-blocking stream socket that fails to connect immediately is - // reported by select as being writable (i.e. connected) even when - // the connection has failed. this is easily demonstrated on OS X - // 10.3.4 by starting a synergy client and telling to connect to - // another system that's not running a synergy server. it will - // claim to have connected then quickly disconnect (i guess because - // read returns 0 bytes). unfortunately, synergy attempts to - // reconnect immediately, the process repeats and we end up - // spinning the CPU. luckily, OS X does set SO_ERROR on the - // socket correctly when the connection has failed so checking for - // errors works. (curiously, sometimes OS X doesn't report - // connection refused. when that happens it at least doesn't - // report the socket as being writable so synergy is able to time - // out the attempt.) - if (error || true) { - try { - // connection may have failed or succeeded - ARCH->throwErrorOnSocket(m_socket); - } - catch (const XArchNetwork& e) { - sendConnectionFailedEvent(e.what()); - onDisconnected(); - return newJob(); - } + // must not have shutdown output + if (!m_writable) { + sendEvent(m_events->forIStream().outputError()); + return; } - if (write) { + // ignore empty writes + if (n == 0) { + return; + } + + // copy data to the output buffer + wasEmpty = (m_outputBuffer.getSize() == 0); + m_outputBuffer.write(buffer, n); + + // there's data to write + m_flushed = false; + } + + // make sure we're waiting to write + if (wasEmpty) { + setJob(newJob()); + } +} + +void TCPSocket::flush() { + Lock lock(&m_mutex); + while (m_flushed == false) { + m_flushed.wait(); + } +} + +void TCPSocket::shutdownInput() { + bool useNewJob = false; + { + Lock lock(&m_mutex); + + // shutdown socket for reading + try { + ARCH->closeSocketForRead(m_socket); + } catch (const XArchNetwork &e) { + // ignore, there's not much we can do + LOG((CLOG_WARN "error closing socket: %s", e.what())); + } + + // shutdown buffer for reading + if (m_readable) { + sendEvent(m_events->forIStream().inputShutdown()); + onInputShutdown(); + useNewJob = true; + } + } + if (useNewJob) { + setJob(newJob()); + } +} + +void TCPSocket::shutdownOutput() { + bool useNewJob = false; + { + Lock lock(&m_mutex); + + // shutdown socket for writing + try { + ARCH->closeSocketForWrite(m_socket); + } catch (const XArchNetwork &e) { + // ignore, there's not much we can do + LOG((CLOG_WARN "error closing socket: %s", e.what())); + } + + // shutdown buffer for writing + if (m_writable) { + sendEvent(m_events->forIStream().outputShutdown()); + onOutputShutdown(); + useNewJob = true; + } + } + if (useNewJob) { + setJob(newJob()); + } +} + +bool TCPSocket::isReady() const { + Lock lock(&m_mutex); + return (m_inputBuffer.getSize() > 0); +} + +bool TCPSocket::isFatal() const { + // TCP sockets aren't ever left in a fatal state. + LOG((CLOG_ERR "isFatal() not valid for non-secure connections")); + return false; +} + +UInt32 TCPSocket::getSize() const { + Lock lock(&m_mutex); + return m_inputBuffer.getSize(); +} + +void TCPSocket::connect(const NetworkAddress &addr) { + { + Lock lock(&m_mutex); + + // fail on attempts to reconnect + if (m_socket == nullptr || m_connected) { + sendConnectionFailedEvent("busy"); + return; + } + + try { + if (ARCH->connectSocket(m_socket, addr.getAddress())) { sendEvent(m_events->forIDataSocket().connected()); onConnected(); - return newJob(); + } else { + // connection is in progress + m_writable = true; + } + } catch (const XArchNetwork &e) { + throw XSocketConnect(e.what()); } - - return job; + } + setJob(newJob()); } -ISocketMultiplexerJob* -TCPSocket::serviceConnected(ISocketMultiplexerJob* job, - bool read, bool write, bool error) -{ - Lock lock(&m_mutex); +void TCPSocket::init() { + // default state + m_connected = false; + m_readable = false; + m_writable = false; - if (error) { + try { + // turn off Nagle algorithm. we send lots of very short messages + // that should be sent without (much) delay. for example, the + // mouse motion messages are much less useful if they're delayed. + ARCH->setNoDelayOnSocket(m_socket, true); + } catch (const XArchNetwork &e) { + try { + ARCH->closeSocket(m_socket); + m_socket = nullptr; + } catch (const XArchNetwork &e) { + // ignore, there's not much we can do + LOG((CLOG_WARN "error closing socket: %s", e.what())); + } + throw XSocketCreate(e.what()); + } +} + +TCPSocket::EJobResult TCPSocket::doRead() { + UInt8 buffer[4096]; + memset(buffer, 0, sizeof(buffer)); + size_t bytesRead = 0; + + bytesRead = ARCH->readSocket(m_socket, buffer, sizeof(buffer)); + + if (bytesRead > 0) { + bool wasEmpty = (m_inputBuffer.getSize() == 0); + + // slurp up as much as possible + do { + m_inputBuffer.write(buffer, static_cast(bytesRead)); + + bytesRead = ARCH->readSocket(m_socket, buffer, sizeof(buffer)); + } while (bytesRead > 0); + + // send input ready if input buffer was empty + if (wasEmpty) { + sendEvent(m_events->forIStream().inputReady()); + } + } else { + // remote write end of stream hungup. our input side + // has therefore shutdown but don't flush our buffer + // since there's still data to be read. + sendEvent(m_events->forIStream().inputShutdown()); + if (!m_writable && m_inputBuffer.getSize() == 0) { + sendEvent(m_events->forISocket().disconnected()); + m_connected = false; + } + m_readable = false; + return kNew; + } + + return kRetry; +} + +TCPSocket::EJobResult TCPSocket::doWrite() { + // write data + UInt32 bufferSize = 0; + int bytesWrote = 0; + + bufferSize = m_outputBuffer.getSize(); + const void *buffer = m_outputBuffer.peek(bufferSize); + bytesWrote = (UInt32)ARCH->writeSocket(m_socket, buffer, bufferSize); + + if (bytesWrote > 0) { + discardWrittenData(bytesWrote); + return kNew; + } + + return kRetry; +} + +void TCPSocket::setJob(ISocketMultiplexerJob *job) { + // multiplexer will delete the old job + if (job == nullptr) { + m_socketMultiplexer->removeSocket(this); + } else { + m_socketMultiplexer->addSocket(this, job); + } +} + +ISocketMultiplexerJob *TCPSocket::newJob() { + // note -- must have m_mutex locked on entry + + if (m_socket == nullptr) { + return nullptr; + } else if (!m_connected) { + assert(!m_readable); + if (!(m_readable || m_writable)) { + return nullptr; + } + return new TSocketMultiplexerMethodJob( + this, &TCPSocket::serviceConnecting, m_socket, m_readable, m_writable); + } else { + if (!(m_readable || (m_writable && (m_outputBuffer.getSize() > 0)))) { + return nullptr; + } + return new TSocketMultiplexerMethodJob( + this, &TCPSocket::serviceConnected, m_socket, m_readable, + m_writable && (m_outputBuffer.getSize() > 0)); + } +} + +void TCPSocket::sendConnectionFailedEvent(const char *msg) { + ConnectionFailedInfo *info = new ConnectionFailedInfo(msg); + m_events->addEvent(Event(m_events->forIDataSocket().connectionFailed(), + getEventTarget(), info, Event::kDontFreeData)); +} + +void TCPSocket::sendEvent(Event::Type type) { + m_events->addEvent(Event(type, getEventTarget())); +} + +void TCPSocket::discardWrittenData(int bytesWrote) { + m_outputBuffer.pop(bytesWrote); + if (m_outputBuffer.getSize() == 0) { + sendEvent(m_events->forIStream().outputFlushed()); + m_flushed = true; + m_flushed.broadcast(); + } +} + +void TCPSocket::onConnected() { + m_connected = true; + m_readable = true; + m_writable = true; +} + +void TCPSocket::onInputShutdown() { + m_inputBuffer.pop(m_inputBuffer.getSize()); + m_readable = false; +} + +void TCPSocket::onOutputShutdown() { + m_outputBuffer.pop(m_outputBuffer.getSize()); + m_writable = false; + + // we're now flushed + m_flushed = true; + m_flushed.broadcast(); +} + +void TCPSocket::onDisconnected() { + // disconnected + onInputShutdown(); + onOutputShutdown(); + m_connected = false; +} + +ISocketMultiplexerJob *TCPSocket::serviceConnecting(ISocketMultiplexerJob *job, + bool, bool write, + bool error) { + Lock lock(&m_mutex); + + // should only check for errors if error is true but checking a new + // socket (and a socket that's connecting should be new) for errors + // should be safe and Mac OS X appears to have a bug where a + // non-blocking stream socket that fails to connect immediately is + // reported by select as being writable (i.e. connected) even when + // the connection has failed. this is easily demonstrated on OS X + // 10.3.4 by starting a synergy client and telling to connect to + // another system that's not running a synergy server. it will + // claim to have connected then quickly disconnect (i guess because + // read returns 0 bytes). unfortunately, synergy attempts to + // reconnect immediately, the process repeats and we end up + // spinning the CPU. luckily, OS X does set SO_ERROR on the + // socket correctly when the connection has failed so checking for + // errors works. (curiously, sometimes OS X doesn't report + // connection refused. when that happens it at least doesn't + // report the socket as being writable so synergy is able to time + // out the attempt.) + if (error || true) { + try { + // connection may have failed or succeeded + ARCH->throwErrorOnSocket(m_socket); + } catch (const XArchNetwork &e) { + sendConnectionFailedEvent(e.what()); + onDisconnected(); + return newJob(); + } + } + + if (write) { + sendEvent(m_events->forIDataSocket().connected()); + onConnected(); + return newJob(); + } + + return job; +} + +ISocketMultiplexerJob *TCPSocket::serviceConnected(ISocketMultiplexerJob *job, + bool read, bool write, + bool error) { + Lock lock(&m_mutex); + + if (error) { + sendEvent(m_events->forISocket().disconnected()); + onDisconnected(); + return newJob(); + } + + EJobResult result = kRetry; + if (write) { + try { + result = doWrite(); + } catch (XArchNetworkShutdown &) { + // remote read end of stream hungup. our output side + // has therefore shutdown. + onOutputShutdown(); + sendEvent(m_events->forIStream().outputShutdown()); + if (!m_readable && m_inputBuffer.getSize() == 0) { sendEvent(m_events->forISocket().disconnected()); - onDisconnected(); - return newJob(); + m_connected = false; + } + result = kNew; + } catch (XArchNetworkDisconnected &) { + // stream hungup + onDisconnected(); + sendEvent(m_events->forISocket().disconnected()); + result = kNew; + } catch (XArchNetwork &e) { + // other write error + LOG((CLOG_WARN "error writing socket: %s", e.what())); + onDisconnected(); + sendEvent(m_events->forIStream().outputError()); + sendEvent(m_events->forISocket().disconnected()); + result = kNew; } + } - EJobResult result = kRetry; - if (write) { - try { - result = doWrite(); - } - catch (XArchNetworkShutdown&) { - // remote read end of stream hungup. our output side - // has therefore shutdown. - onOutputShutdown(); - sendEvent(m_events->forIStream().outputShutdown()); - if (!m_readable && m_inputBuffer.getSize() == 0) { - sendEvent(m_events->forISocket().disconnected()); - m_connected = false; - } - result = kNew; - } - catch (XArchNetworkDisconnected&) { - // stream hungup - onDisconnected(); - sendEvent(m_events->forISocket().disconnected()); - result = kNew; - } - catch (XArchNetwork& e) { - // other write error - LOG((CLOG_WARN "error writing socket: %s", e.what())); - onDisconnected(); - sendEvent(m_events->forIStream().outputError()); - sendEvent(m_events->forISocket().disconnected()); - result = kNew; - } + if (read && m_readable) { + try { + result = doRead(); + } catch (XArchNetworkDisconnected &) { + // stream hungup + sendEvent(m_events->forISocket().disconnected()); + onDisconnected(); + result = kNew; + } catch (XArchNetwork &e) { + // ignore other read error + LOG((CLOG_WARN "error reading socket: %s", e.what())); } + } - if (read && m_readable) { - try { - result = doRead(); - } - catch (XArchNetworkDisconnected&) { - // stream hungup - sendEvent(m_events->forISocket().disconnected()); - onDisconnected(); - result = kNew; - } - catch (XArchNetwork& e) { - // ignore other read error - LOG((CLOG_WARN "error reading socket: %s", e.what())); - } - } + if (result == kBreak) { + return nullptr; + } - if (result == kBreak) { - return nullptr; - } - - return result == kNew ? newJob() : job; + return result == kNew ? newJob() : job; } diff --git a/src/lib/net/TCPSocket.h b/src/lib/net/TCPSocket.h index 93049f7c9..13c06436c 100644 --- a/src/lib/net/TCPSocket.h +++ b/src/lib/net/TCPSocket.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -18,11 +18,11 @@ #pragma once -#include "net/IDataSocket.h" +#include "arch/IArchNetwork.h" #include "io/StreamBuffer.h" #include "mt/CondVar.h" #include "mt/Mutex.h" -#include "arch/IArchNetwork.h" +#include "net/IDataSocket.h" class Mutex; class Thread; @@ -36,86 +36,84 @@ A data socket using TCP. */ class TCPSocket : public IDataSocket { public: - TCPSocket(IEventQueue* events, SocketMultiplexer* socketMultiplexer, IArchNetwork::EAddressFamily family = IArchNetwork::kINET); - TCPSocket(IEventQueue* events, SocketMultiplexer* socketMultiplexer, ArchSocket socket); - TCPSocket(TCPSocket const &) =delete; - TCPSocket(TCPSocket &&) =delete; - virtual ~TCPSocket(); + TCPSocket(IEventQueue *events, SocketMultiplexer *socketMultiplexer, + IArchNetwork::EAddressFamily family = IArchNetwork::kINET); + TCPSocket(IEventQueue *events, SocketMultiplexer *socketMultiplexer, + ArchSocket socket); + TCPSocket(TCPSocket const &) = delete; + TCPSocket(TCPSocket &&) = delete; + virtual ~TCPSocket(); - TCPSocket& operator=(TCPSocket const &) =delete; - TCPSocket& operator=(TCPSocket &&) =delete; + TCPSocket &operator=(TCPSocket const &) = delete; + TCPSocket &operator=(TCPSocket &&) = delete; - // ISocket overrides - virtual void bind(const NetworkAddress&); - virtual void close(); - virtual void* getEventTarget() const; + // ISocket overrides + virtual void bind(const NetworkAddress &); + virtual void close(); + virtual void *getEventTarget() const; - // IStream overrides - virtual UInt32 read(void* buffer, UInt32 n); - virtual void write(const void* buffer, UInt32 n); - virtual void flush(); - virtual void shutdownInput(); - virtual void shutdownOutput(); - virtual bool isReady() const; - virtual bool isFatal() const; - virtual UInt32 getSize() const; + // IStream overrides + virtual UInt32 read(void *buffer, UInt32 n); + virtual void write(const void *buffer, UInt32 n); + virtual void flush(); + virtual void shutdownInput(); + virtual void shutdownOutput(); + virtual bool isReady() const; + virtual bool isFatal() const; + virtual UInt32 getSize() const; - // IDataSocket overrides - virtual void connect(const NetworkAddress&); + // IDataSocket overrides + virtual void connect(const NetworkAddress &); - - virtual ISocketMultiplexerJob* - newJob(); + virtual ISocketMultiplexerJob *newJob(); protected: - enum EJobResult { - kBreak = -1, //!< Break the Job chain - kRetry, //!< Retry the same job - kNew //!< Require a new job - }; - - ArchSocket getSocket() { return m_socket; } - IEventQueue* getEvents() { return m_events; } - virtual EJobResult doRead(); - virtual EJobResult doWrite(); + enum EJobResult { + kBreak = -1, //!< Break the Job chain + kRetry, //!< Retry the same job + kNew //!< Require a new job + }; - void setJob(ISocketMultiplexerJob*); - - bool isReadable() { return m_readable; } - bool isWritable() { return m_writable; } + ArchSocket getSocket() { return m_socket; } + IEventQueue *getEvents() { return m_events; } + virtual EJobResult doRead(); + virtual EJobResult doWrite(); - Mutex& getMutex() { return m_mutex; } + void setJob(ISocketMultiplexerJob *); - void sendEvent(Event::Type); - void discardWrittenData(int bytesWrote); + bool isReadable() { return m_readable; } + bool isWritable() { return m_writable; } + + Mutex &getMutex() { return m_mutex; } + + void sendEvent(Event::Type); + void discardWrittenData(int bytesWrote); private: - void init(); + void init(); - void sendConnectionFailedEvent(const char*); - void onConnected(); - void onInputShutdown(); - void onOutputShutdown(); - void onDisconnected(); + void sendConnectionFailedEvent(const char *); + void onConnected(); + void onInputShutdown(); + void onOutputShutdown(); + void onDisconnected(); - ISocketMultiplexerJob* - serviceConnecting(ISocketMultiplexerJob*, - bool, bool, bool); - ISocketMultiplexerJob* - serviceConnected(ISocketMultiplexerJob*, - bool, bool, bool); + ISocketMultiplexerJob *serviceConnecting(ISocketMultiplexerJob *, bool, bool, + bool); + ISocketMultiplexerJob *serviceConnected(ISocketMultiplexerJob *, bool, bool, + bool); protected: - bool m_readable; - bool m_writable; - bool m_connected; - IEventQueue* m_events; - StreamBuffer m_inputBuffer; - StreamBuffer m_outputBuffer; - + bool m_readable; + bool m_writable; + bool m_connected; + IEventQueue *m_events; + StreamBuffer m_inputBuffer; + StreamBuffer m_outputBuffer; + private: - Mutex m_mutex; - ArchSocket m_socket; - CondVar m_flushed; - SocketMultiplexer* m_socketMultiplexer; + Mutex m_mutex; + ArchSocket m_socket; + CondVar m_flushed; + SocketMultiplexer *m_socketMultiplexer; }; diff --git a/src/lib/net/TCPSocketFactory.cpp b/src/lib/net/TCPSocketFactory.cpp index d365101c8..269efd5b8 100644 --- a/src/lib/net/TCPSocketFactory.cpp +++ b/src/lib/net/TCPSocketFactory.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -17,52 +17,49 @@ */ #include "net/TCPSocketFactory.h" -#include "net/TCPSocket.h" -#include "net/TCPListenSocket.h" -#include "net/SecureSocket.h" -#include "net/SecureListenSocket.h" #include "arch/Arch.h" #include "base/Log.h" +#include "net/SecureListenSocket.h" +#include "net/SecureSocket.h" +#include "net/TCPListenSocket.h" +#include "net/TCPSocket.h" // // TCPSocketFactory // -TCPSocketFactory::TCPSocketFactory(IEventQueue* events, SocketMultiplexer* socketMultiplexer) : - m_events(events), - m_socketMultiplexer(socketMultiplexer) -{ - // do nothing +TCPSocketFactory::TCPSocketFactory(IEventQueue *events, + SocketMultiplexer *socketMultiplexer) + : m_events(events), m_socketMultiplexer(socketMultiplexer) { + // do nothing } -TCPSocketFactory::~TCPSocketFactory() -{ - // do nothing +TCPSocketFactory::~TCPSocketFactory() { + // do nothing } -IDataSocket* -TCPSocketFactory::create(bool secure, IArchNetwork::EAddressFamily family) const -{ - if (secure) { - SecureSocket* secureSocket = new SecureSocket(m_events, m_socketMultiplexer, family); - secureSocket->initSsl (false); - return secureSocket; - } - else { - return new TCPSocket(m_events, m_socketMultiplexer, family); - } +IDataSocket * +TCPSocketFactory::create(bool secure, + IArchNetwork::EAddressFamily family) const { + if (secure) { + SecureSocket *secureSocket = + new SecureSocket(m_events, m_socketMultiplexer, family); + secureSocket->initSsl(false); + return secureSocket; + } else { + return new TCPSocket(m_events, m_socketMultiplexer, family); + } } -IListenSocket* -TCPSocketFactory::createListen(bool secure, IArchNetwork::EAddressFamily family) const -{ - IListenSocket* socket = NULL; - if (secure) { - socket = new SecureListenSocket(m_events, m_socketMultiplexer, family); - } - else { - socket = new TCPListenSocket(m_events, m_socketMultiplexer, family); - } +IListenSocket * +TCPSocketFactory::createListen(bool secure, + IArchNetwork::EAddressFamily family) const { + IListenSocket *socket = NULL; + if (secure) { + socket = new SecureListenSocket(m_events, m_socketMultiplexer, family); + } else { + socket = new TCPListenSocket(m_events, m_socketMultiplexer, family); + } - return socket; + return socket; } diff --git a/src/lib/net/TCPSocketFactory.h b/src/lib/net/TCPSocketFactory.h index 65c15a6ee..13a27bb7d 100644 --- a/src/lib/net/TCPSocketFactory.h +++ b/src/lib/net/TCPSocketFactory.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -18,8 +18,8 @@ #pragma once -#include "net/ISocketFactory.h" #include "arch/IArchNetwork.h" +#include "net/ISocketFactory.h" class IEventQueue; class SocketMultiplexer; @@ -27,16 +27,18 @@ class SocketMultiplexer; //! Socket factory for TCP sockets class TCPSocketFactory : public ISocketFactory { public: - TCPSocketFactory(IEventQueue* events, SocketMultiplexer* socketMultiplexer); - virtual ~TCPSocketFactory(); + TCPSocketFactory(IEventQueue *events, SocketMultiplexer *socketMultiplexer); + virtual ~TCPSocketFactory(); - // ISocketFactory overrides - virtual IDataSocket* - create(bool secure, IArchNetwork::EAddressFamily family = IArchNetwork::kINET) const; - virtual IListenSocket* - createListen(bool secure, IArchNetwork::EAddressFamily family = IArchNetwork::kINET) const; + // ISocketFactory overrides + virtual IDataSocket * + create(bool secure, + IArchNetwork::EAddressFamily family = IArchNetwork::kINET) const; + virtual IListenSocket * + createListen(bool secure, + IArchNetwork::EAddressFamily family = IArchNetwork::kINET) const; private: - IEventQueue* m_events; - SocketMultiplexer* m_socketMultiplexer; + IEventQueue *m_events; + SocketMultiplexer *m_socketMultiplexer; }; diff --git a/src/lib/net/TSocketMultiplexerMethodJob.h b/src/lib/net/TSocketMultiplexerMethodJob.h index e458958d4..47e9b48ae 100644 --- a/src/lib/net/TSocketMultiplexerMethodJob.h +++ b/src/lib/net/TSocketMultiplexerMethodJob.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 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 LICENSE 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 @@ -18,8 +18,8 @@ #pragma once -#include "net/ISocketMultiplexerJob.h" #include "arch/Arch.h" +#include "net/ISocketMultiplexerJob.h" //! Use a method as a socket multiplexer job /*! @@ -28,87 +28,69 @@ A socket multiplexer job class that invokes a member function. template class TSocketMultiplexerMethodJob : public ISocketMultiplexerJob { public: - typedef ISocketMultiplexerJob* - (T::*Method)(ISocketMultiplexerJob*, bool, bool, bool); + typedef ISocketMultiplexerJob *(T::*Method)(ISocketMultiplexerJob *, bool, + bool, bool); - //! run() invokes \c object->method(arg) - TSocketMultiplexerMethodJob(T* object, Method method, - ArchSocket socket, bool readable, bool writeable); - TSocketMultiplexerMethodJob(TSocketMultiplexerMethodJob const &) =delete; - TSocketMultiplexerMethodJob(TSocketMultiplexerMethodJob &&) =delete; - virtual ~TSocketMultiplexerMethodJob(); + //! run() invokes \c object->method(arg) + TSocketMultiplexerMethodJob(T *object, Method method, ArchSocket socket, + bool readable, bool writeable); + TSocketMultiplexerMethodJob(TSocketMultiplexerMethodJob const &) = delete; + TSocketMultiplexerMethodJob(TSocketMultiplexerMethodJob &&) = delete; + virtual ~TSocketMultiplexerMethodJob(); - TSocketMultiplexerMethodJob& operator=(TSocketMultiplexerMethodJob const &) =delete; - TSocketMultiplexerMethodJob& operator=(TSocketMultiplexerMethodJob &&) =delete; + TSocketMultiplexerMethodJob & + operator=(TSocketMultiplexerMethodJob const &) = delete; + TSocketMultiplexerMethodJob & + operator=(TSocketMultiplexerMethodJob &&) = delete; - // IJob overrides - virtual ISocketMultiplexerJob* - run(bool readable, bool writable, bool error); - virtual ArchSocket getSocket() const; - virtual bool isReadable() const; - virtual bool isWritable() const; + // IJob overrides + virtual ISocketMultiplexerJob *run(bool readable, bool writable, bool error); + virtual ArchSocket getSocket() const; + virtual bool isReadable() const; + virtual bool isWritable() const; private: - T* m_object; - Method m_method; - ArchSocket m_socket; - bool m_readable; - bool m_writable; - void* m_arg; + T *m_object; + Method m_method; + ArchSocket m_socket; + bool m_readable; + bool m_writable; + void *m_arg; }; template -inline -TSocketMultiplexerMethodJob::TSocketMultiplexerMethodJob(T* object, - Method method, ArchSocket socket, - bool readable, bool writable) : - m_object(object), - m_method(method), - m_socket(ARCH->copySocket(socket)), - m_readable(readable), - m_writable(writable) -{ - // do nothing +inline TSocketMultiplexerMethodJob::TSocketMultiplexerMethodJob( + T *object, Method method, ArchSocket socket, bool readable, bool writable) + : m_object(object), m_method(method), m_socket(ARCH->copySocket(socket)), + m_readable(readable), m_writable(writable) { + // do nothing } template -inline -TSocketMultiplexerMethodJob::~TSocketMultiplexerMethodJob() -{ - ARCH->closeSocket(m_socket); +inline TSocketMultiplexerMethodJob::~TSocketMultiplexerMethodJob() { + ARCH->closeSocket(m_socket); } template -inline -ISocketMultiplexerJob* -TSocketMultiplexerMethodJob::run(bool read, bool write, bool error) -{ - if (m_object != NULL) { - return (m_object->*m_method)(this, read, write, error); - } - return NULL; +inline ISocketMultiplexerJob * +TSocketMultiplexerMethodJob::run(bool read, bool write, bool error) { + if (m_object != NULL) { + return (m_object->*m_method)(this, read, write, error); + } + return NULL; } template -inline -ArchSocket -TSocketMultiplexerMethodJob::getSocket() const -{ - return m_socket; +inline ArchSocket TSocketMultiplexerMethodJob::getSocket() const { + return m_socket; } template -inline -bool -TSocketMultiplexerMethodJob::isReadable() const -{ - return m_readable; +inline bool TSocketMultiplexerMethodJob::isReadable() const { + return m_readable; } template -inline -bool -TSocketMultiplexerMethodJob::isWritable() const -{ - return m_writable; +inline bool TSocketMultiplexerMethodJob::isWritable() const { + return m_writable; } diff --git a/src/lib/net/XSocket.cpp b/src/lib/net/XSocket.cpp index 77c9ea16b..151dfb68b 100644 --- a/src/lib/net/XSocket.cpp +++ b/src/lib/net/XSocket.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -23,95 +23,63 @@ // XSocketAddress // -XSocketAddress::XSocketAddress(EError error, - const String& hostname, int port) _NOEXCEPT : - m_error(error), - m_hostname(hostname), - m_port(port) -{ - // do nothing +XSocketAddress::XSocketAddress(EError error, const String &hostname, + int port) _NOEXCEPT : m_error(error), + m_hostname(hostname), + m_port(port) { + // do nothing } -XSocketAddress::EError -XSocketAddress::getError() const throw() -{ - return m_error; +XSocketAddress::EError XSocketAddress::getError() const throw() { + return m_error; } -String -XSocketAddress::getHostname() const throw() -{ - return m_hostname; -} +String XSocketAddress::getHostname() const throw() { return m_hostname; } -int -XSocketAddress::getPort() const throw() -{ - return m_port; -} +int XSocketAddress::getPort() const throw() { return m_port; } -String -XSocketAddress::getWhat() const throw() -{ - static const char* s_errorID[] = { - "XSocketAddressUnknown", - "XSocketAddressNotFound", - "XSocketAddressNoAddress", - "XSocketAddressUnsupported", - "XSocketAddressBadPort" - }; - static const char* s_errorMsg[] = { - "unknown error for: %{1}:%{2}", - "address not found for: %{1}", - "no address for: %{1}", - "unsupported address for: %{1}", - "invalid port" // m_port may not be set to the bad port - }; - return format(s_errorID[m_error], s_errorMsg[m_error], - m_hostname.c_str(), - synergy::string::sprintf("%d", m_port).c_str()); +String XSocketAddress::getWhat() const throw() { + static const char *s_errorID[] = { + "XSocketAddressUnknown", "XSocketAddressNotFound", + "XSocketAddressNoAddress", "XSocketAddressUnsupported", + "XSocketAddressBadPort"}; + static const char *s_errorMsg[] = { + "unknown error for: %{1}:%{2}", "address not found for: %{1}", + "no address for: %{1}", "unsupported address for: %{1}", + "invalid port" // m_port may not be set to the bad port + }; + return format(s_errorID[m_error], s_errorMsg[m_error], m_hostname.c_str(), + synergy::string::sprintf("%d", m_port).c_str()); } - // // XSocketIOClose // -String -XSocketIOClose::getWhat() const throw() -{ - return format("XSocketIOClose", "close: %{1}", what()); +String XSocketIOClose::getWhat() const throw() { + return format("XSocketIOClose", "close: %{1}", what()); } - // // XSocketBind // -String -XSocketBind::getWhat() const throw() -{ - return format("XSocketBind", "cannot bind address: %{1}", what()); +String XSocketBind::getWhat() const throw() { + return format("XSocketBind", "cannot bind address: %{1}", what()); } - // // XSocketConnect // -String -XSocketConnect::getWhat() const throw() -{ - return format("XSocketConnect", "cannot connect socket: %{1}", what()); +String XSocketConnect::getWhat() const throw() { + return format("XSocketConnect", "cannot connect socket: %{1}", what()); } - // // XSocketCreate // -String -XSocketCreate::getWhat() const throw() -{ - return format("XSocketCreate", "cannot create socket: %{1}", what()); +String XSocketCreate::getWhat() const throw() { + return format("XSocketCreate", "cannot create socket: %{1}", what()); } diff --git a/src/lib/net/XSocket.h b/src/lib/net/XSocket.h index f6e3ca9f2..5d5c2147c 100644 --- a/src/lib/net/XSocket.h +++ b/src/lib/net/XSocket.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -18,10 +18,10 @@ #pragma once -#include "io/XIO.h" -#include "base/XBase.h" #include "base/String.h" +#include "base/XBase.h" #include "common/basic_types.h" +#include "io/XIO.h" //! Generic socket exception XBASE_SUBCLASS(XSocket, XBase); @@ -32,38 +32,38 @@ Thrown when attempting to create an invalid network address. */ class XSocketAddress : public XSocket { public: - //! Failure codes - enum EError { - kUnknown, //!< Unknown error - kNotFound, //!< The hostname is unknown - kNoAddress, //!< The hostname is valid but has no IP address - kUnsupported, //!< The hostname is valid but has no supported address - kBadPort //!< The port is invalid - }; + //! Failure codes + enum EError { + kUnknown, //!< Unknown error + kNotFound, //!< The hostname is unknown + kNoAddress, //!< The hostname is valid but has no IP address + kUnsupported, //!< The hostname is valid but has no supported address + kBadPort //!< The port is invalid + }; - XSocketAddress(EError, const String& hostname, int port) _NOEXCEPT; - virtual ~XSocketAddress() _NOEXCEPT { } + XSocketAddress(EError, const String &hostname, int port) _NOEXCEPT; + virtual ~XSocketAddress() _NOEXCEPT {} - //! @name accessors - //@{ + //! @name accessors + //@{ - //! Get the error code - EError getError() const throw(); - //! Get the hostname - String getHostname() const throw(); - //! Get the port - int getPort() const throw(); + //! Get the error code + EError getError() const throw(); + //! Get the hostname + String getHostname() const throw(); + //! Get the port + int getPort() const throw(); - //@} + //@} protected: - // XBase overrides - virtual String getWhat() const throw(); + // XBase overrides + virtual String getWhat() const throw(); private: - EError m_error; - String m_hostname; - int m_port; + EError m_error; + String m_hostname; + int m_port; }; //! I/O closing exception diff --git a/src/lib/platform/IMSWindowsClipboardFacade.h b/src/lib/platform/IMSWindowsClipboardFacade.h index 2eca023d0..f815af811 100644 --- a/src/lib/platform/IMSWindowsClipboardFacade.h +++ b/src/lib/platform/IMSWindowsClipboardFacade.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -26,11 +26,10 @@ class IMSWindowsClipboardConverter; -class IMSWindowsClipboardFacade : public IInterface -{ +class IMSWindowsClipboardFacade : public IInterface { public: - virtual void write(HANDLE win32Data, UINT win32Format) = 0; - virtual ~IMSWindowsClipboardFacade() { } + virtual void write(HANDLE win32Data, UINT win32Format) = 0; + virtual ~IMSWindowsClipboardFacade() {} }; #endif \ No newline at end of file diff --git a/src/lib/platform/IOSXKeyResource.cpp b/src/lib/platform/IOSXKeyResource.cpp index b887fc59e..1e010b35d 100644 --- a/src/lib/platform/IOSXKeyResource.cpp +++ b/src/lib/platform/IOSXKeyResource.cpp @@ -1,11 +1,11 @@ /* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2016 Symless Ltd. - * + * * 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 LICENSE 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 @@ -19,171 +19,165 @@ #include -KeyID -IOSXKeyResource::getKeyID(UInt8 c) -{ - if (c == 0) { - return kKeyNone; - } - else if (c >= 32 && c < 127) { - // ASCII - return static_cast(c); - } - else { - // handle special keys - switch (c) { - case 0x01: - return kKeyHome; - - case 0x02: - return kKeyKP_Enter; - - case 0x03: - return kKeyKP_Enter; - - case 0x04: - return kKeyEnd; - - case 0x05: - return kKeyHelp; - - case 0x08: - return kKeyBackSpace; - - case 0x09: - return kKeyTab; - - case 0x0b: - return kKeyPageUp; - - case 0x0c: - return kKeyPageDown; - - case 0x0d: - return kKeyReturn; - - case 0x10: - // OS X maps all the function keys (F1, etc) to this one key. - // we can't determine the right key here so we have to do it - // some other way. - return kKeyNone; - - case 0x1b: - return kKeyEscape; - - case 0x1c: - return kKeyLeft; - - case 0x1d: - return kKeyRight; - - case 0x1e: - return kKeyUp; - - case 0x1f: - return kKeyDown; - - case 0x7f: - return kKeyDelete; - - case 0x06: - case 0x07: - case 0x0a: - case 0x0e: - case 0x0f: - case 0x11: - case 0x12: - case 0x13: - case 0x14: - case 0x15: - case 0x16: - case 0x17: - case 0x18: - case 0x19: - case 0x1a: - // discard other control characters - return kKeyNone; - - default: - // not special or unknown - break; - } - - // create string with character - char str[2]; - str[0] = static_cast(c); - str[1] = 0; - - // get current keyboard script - TISInputSourceRef isref = TISCopyCurrentKeyboardInputSource(); - CFArrayRef langs = (CFArrayRef) TISGetInputSourceProperty(isref, kTISPropertyInputSourceLanguages); - CFStringEncoding encoding = CFStringConvertIANACharSetNameToEncoding( - (CFStringRef)CFArrayGetValueAtIndex(langs, 0)); - // convert to unicode - CFStringRef cfString = - CFStringCreateWithCStringNoCopy( - kCFAllocatorDefault, str, encoding, kCFAllocatorNull); - - // sometimes CFStringCreate...() returns NULL (e.g. Apple Korean - // encoding with char value 214). if it did then make no key, - // otherwise CFStringCreateMutableCopy() will crash. - if (cfString == NULL) { - return kKeyNone; - } - - // convert to precomposed - CFMutableStringRef mcfString = - CFStringCreateMutableCopy(kCFAllocatorDefault, 0, cfString); - CFRelease(cfString); - CFStringNormalize(mcfString, kCFStringNormalizationFormC); - - // check result - int unicodeLength = CFStringGetLength(mcfString); - if (unicodeLength == 0) { - CFRelease(mcfString); - return kKeyNone; - } - if (unicodeLength > 1) { - // FIXME -- more than one character, we should handle this - CFRelease(mcfString); - return kKeyNone; - } - - // get unicode character - UniChar uc = CFStringGetCharacterAtIndex(mcfString, 0); - CFRelease(mcfString); - - // convert to KeyID - return static_cast(uc); - } -} - -KeyID -IOSXKeyResource::unicharToKeyID(UniChar c) -{ +KeyID IOSXKeyResource::getKeyID(UInt8 c) { + if (c == 0) { + return kKeyNone; + } else if (c >= 32 && c < 127) { + // ASCII + return static_cast(c); + } else { + // handle special keys switch (c) { - case 3: - return kKeyKP_Enter; + case 0x01: + return kKeyHome; - case 8: - return kKeyBackSpace; + case 0x02: + return kKeyKP_Enter; - case 9: - return kKeyTab; + case 0x03: + return kKeyKP_Enter; - case 13: - return kKeyReturn; + case 0x04: + return kKeyEnd; - case 27: - return kKeyEscape; + case 0x05: + return kKeyHelp; - case 127: - return kKeyDelete; + case 0x08: + return kKeyBackSpace; + + case 0x09: + return kKeyTab; + + case 0x0b: + return kKeyPageUp; + + case 0x0c: + return kKeyPageDown; + + case 0x0d: + return kKeyReturn; + + case 0x10: + // OS X maps all the function keys (F1, etc) to this one key. + // we can't determine the right key here so we have to do it + // some other way. + return kKeyNone; + + case 0x1b: + return kKeyEscape; + + case 0x1c: + return kKeyLeft; + + case 0x1d: + return kKeyRight; + + case 0x1e: + return kKeyUp; + + case 0x1f: + return kKeyDown; + + case 0x7f: + return kKeyDelete; + + case 0x06: + case 0x07: + case 0x0a: + case 0x0e: + case 0x0f: + case 0x11: + case 0x12: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + case 0x18: + case 0x19: + case 0x1a: + // discard other control characters + return kKeyNone; default: - if (c < 32) { - return kKeyNone; - } - return static_cast(c); + // not special or unknown + break; } + + // create string with character + char str[2]; + str[0] = static_cast(c); + str[1] = 0; + + // get current keyboard script + TISInputSourceRef isref = TISCopyCurrentKeyboardInputSource(); + CFArrayRef langs = (CFArrayRef)TISGetInputSourceProperty( + isref, kTISPropertyInputSourceLanguages); + CFStringEncoding encoding = CFStringConvertIANACharSetNameToEncoding( + (CFStringRef)CFArrayGetValueAtIndex(langs, 0)); + // convert to unicode + CFStringRef cfString = CFStringCreateWithCStringNoCopy( + kCFAllocatorDefault, str, encoding, kCFAllocatorNull); + + // sometimes CFStringCreate...() returns NULL (e.g. Apple Korean + // encoding with char value 214). if it did then make no key, + // otherwise CFStringCreateMutableCopy() will crash. + if (cfString == NULL) { + return kKeyNone; + } + + // convert to precomposed + CFMutableStringRef mcfString = + CFStringCreateMutableCopy(kCFAllocatorDefault, 0, cfString); + CFRelease(cfString); + CFStringNormalize(mcfString, kCFStringNormalizationFormC); + + // check result + int unicodeLength = CFStringGetLength(mcfString); + if (unicodeLength == 0) { + CFRelease(mcfString); + return kKeyNone; + } + if (unicodeLength > 1) { + // FIXME -- more than one character, we should handle this + CFRelease(mcfString); + return kKeyNone; + } + + // get unicode character + UniChar uc = CFStringGetCharacterAtIndex(mcfString, 0); + CFRelease(mcfString); + + // convert to KeyID + return static_cast(uc); + } +} + +KeyID IOSXKeyResource::unicharToKeyID(UniChar c) { + switch (c) { + case 3: + return kKeyKP_Enter; + + case 8: + return kKeyBackSpace; + + case 9: + return kKeyTab; + + case 13: + return kKeyReturn; + + case 27: + return kKeyEscape; + + case 127: + return kKeyDelete; + + default: + if (c < 32) { + return kKeyNone; + } + return static_cast(c); + } } diff --git a/src/lib/platform/IOSXKeyResource.h b/src/lib/platform/IOSXKeyResource.h index 717708286..6f0a07159 100644 --- a/src/lib/platform/IOSXKeyResource.h +++ b/src/lib/platform/IOSXKeyResource.h @@ -1,11 +1,11 @@ /* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2016 Symless Ltd. - * + * * 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 LICENSE 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 @@ -21,16 +21,16 @@ class IOSXKeyResource : public IInterface { public: - virtual bool isValid() const = 0; - virtual UInt32 getNumModifierCombinations() const = 0; - virtual UInt32 getNumTables() const = 0; - virtual UInt32 getNumButtons() const = 0; - virtual UInt32 getTableForModifier(UInt32 mask) const = 0; - virtual KeyID getKey(UInt32 table, UInt32 button) const = 0; - - // Convert a character in the current script to the equivalent KeyID - static KeyID getKeyID(UInt8); - - // Convert a unicode character to the equivalent KeyID. - static KeyID unicharToKeyID(UniChar); + virtual bool isValid() const = 0; + virtual UInt32 getNumModifierCombinations() const = 0; + virtual UInt32 getNumTables() const = 0; + virtual UInt32 getNumButtons() const = 0; + virtual UInt32 getTableForModifier(UInt32 mask) const = 0; + virtual KeyID getKey(UInt32 table, UInt32 button) const = 0; + + // Convert a character in the current script to the equivalent KeyID + static KeyID getKeyID(UInt8); + + // Convert a unicode character to the equivalent KeyID. + static KeyID unicharToKeyID(UniChar); }; diff --git a/src/lib/platform/MSWindowsClipboard.cpp b/src/lib/platform/MSWindowsClipboard.cpp index 1764b8764..d2cd2d89c 100644 --- a/src/lib/platform/MSWindowsClipboard.cpp +++ b/src/lib/platform/MSWindowsClipboard.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -18,223 +18,193 @@ #include "platform/MSWindowsClipboard.h" -#include "platform/MSWindowsClipboardTextConverter.h" -#include "platform/MSWindowsClipboardUTF16Converter.h" -#include "platform/MSWindowsClipboardBitmapConverter.h" -#include "platform/MSWindowsClipboardHTMLConverter.h" -#include "platform/MSWindowsClipboardFacade.h" #include "arch/win32/ArchMiscWindows.h" #include "base/Log.h" +#include "platform/MSWindowsClipboardBitmapConverter.h" +#include "platform/MSWindowsClipboardFacade.h" +#include "platform/MSWindowsClipboardHTMLConverter.h" +#include "platform/MSWindowsClipboardTextConverter.h" +#include "platform/MSWindowsClipboardUTF16Converter.h" // // MSWindowsClipboard // -UINT MSWindowsClipboard::s_ownershipFormat = 0; +UINT MSWindowsClipboard::s_ownershipFormat = 0; -MSWindowsClipboard::MSWindowsClipboard(HWND window) : - m_window(window), - m_time(0), - m_facade(new MSWindowsClipboardFacade()), - m_deleteFacade(true) -{ - // add converters, most desired first - m_converters.push_back(new MSWindowsClipboardUTF16Converter); - m_converters.push_back(new MSWindowsClipboardBitmapConverter); - m_converters.push_back(new MSWindowsClipboardHTMLConverter); +MSWindowsClipboard::MSWindowsClipboard(HWND window) + : m_window(window), m_time(0), m_facade(new MSWindowsClipboardFacade()), + m_deleteFacade(true) { + // add converters, most desired first + m_converters.push_back(new MSWindowsClipboardUTF16Converter); + m_converters.push_back(new MSWindowsClipboardBitmapConverter); + m_converters.push_back(new MSWindowsClipboardHTMLConverter); } -MSWindowsClipboard::~MSWindowsClipboard() -{ - clearConverters(); +MSWindowsClipboard::~MSWindowsClipboard() { + clearConverters(); - // dependency injection causes confusion over ownership, so we need - // logic to decide whether or not we delete the facade. there must - // be a more elegant way of doing this. - if (m_deleteFacade) - delete m_facade; -} - -void -MSWindowsClipboard::setFacade(IMSWindowsClipboardFacade& facade) -{ + // dependency injection causes confusion over ownership, so we need + // logic to decide whether or not we delete the facade. there must + // be a more elegant way of doing this. + if (m_deleteFacade) delete m_facade; - m_facade = &facade; - m_deleteFacade = false; } -bool -MSWindowsClipboard::emptyUnowned() -{ - LOG((CLOG_DEBUG "empty clipboard")); - - // empty the clipboard (and take ownership) - if (!EmptyClipboard()) { - // unable to cause this in integ tests, but this error has never - // actually been reported by users. - LOG((CLOG_DEBUG "failed to grab clipboard")); - return false; - } - - return true; +void MSWindowsClipboard::setFacade(IMSWindowsClipboardFacade &facade) { + delete m_facade; + m_facade = &facade; + m_deleteFacade = false; } -bool -MSWindowsClipboard::empty() -{ - if (!emptyUnowned()) { - return false; - } +bool MSWindowsClipboard::emptyUnowned() { + LOG((CLOG_DEBUG "empty clipboard")); - // mark clipboard as being owned by synergy - HGLOBAL data = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, 1); - if (NULL == SetClipboardData(getOwnershipFormat(), data)) { - LOG((CLOG_DEBUG "failed to set clipboard data")); - GlobalFree(data); - return false; - } - - return true; -} - -void -MSWindowsClipboard::add(EFormat format, const String& data) -{ - bool isSucceeded = false; - // convert data to win32 form - for (ConverterList::const_iterator index = m_converters.begin(); - index != m_converters.end(); ++index) { - IMSWindowsClipboardConverter* converter = *index; - - // skip converters for other formats - if (converter->getFormat() == format) { - HANDLE win32Data = converter->fromIClipboard(data); - if (win32Data != NULL) { - LOG((CLOG_DEBUG "add %d bytes to clipboard format: %d", data.size(), format)); - m_facade->write(win32Data, converter->getWin32Format()); - isSucceeded = true; - break; - } - else { - LOG((CLOG_DEBUG "failed to convert clipboard data to platform format")); - } - } - } - - if(!isSucceeded){ - LOG((CLOG_DEBUG "missed clipboard data convert for format: %d", format)); - } -} - -bool -MSWindowsClipboard::open(Time time) const -{ - LOG((CLOG_DEBUG "open clipboard")); - - if (!OpenClipboard(m_window)) { - // unable to cause this in integ tests; but this can happen! - // * http://symless.com/pm/issues/86 - // * http://symless.com/pm/issues/1256 - // logging improved to see if we can catch more info next time. - LOG((CLOG_WARN "failed to open clipboard: %d", GetLastError())); - return false; - } - - m_time = time; - - return true; -} - -void -MSWindowsClipboard::close() const -{ - LOG((CLOG_DEBUG "close clipboard")); - CloseClipboard(); -} - -IClipboard::Time -MSWindowsClipboard::getTime() const -{ - return m_time; -} - -bool -MSWindowsClipboard::has(EFormat format) const -{ - for (ConverterList::const_iterator index = m_converters.begin(); - index != m_converters.end(); ++index) { - IMSWindowsClipboardConverter* converter = *index; - if (converter->getFormat() == format) { - if (IsClipboardFormatAvailable(converter->getWin32Format())) { - return true; - } - } - } + // empty the clipboard (and take ownership) + if (!EmptyClipboard()) { + // unable to cause this in integ tests, but this error has never + // actually been reported by users. + LOG((CLOG_DEBUG "failed to grab clipboard")); return false; + } + + return true; } -String -MSWindowsClipboard::get(EFormat format) const -{ - // find the converter for the first clipboard format we can handle - IMSWindowsClipboardConverter* converter = NULL; - for (ConverterList::const_iterator index = m_converters.begin(); - index != m_converters.end(); ++index) { +bool MSWindowsClipboard::empty() { + if (!emptyUnowned()) { + return false; + } - converter = *index; - if (converter->getFormat() == format) { - break; - } - converter = NULL; - } + // mark clipboard as being owned by synergy + HGLOBAL data = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, 1); + if (NULL == SetClipboardData(getOwnershipFormat(), data)) { + LOG((CLOG_DEBUG "failed to set clipboard data")); + GlobalFree(data); + return false; + } - // if no converter then we don't recognize any formats - if (converter == NULL) { - LOG((CLOG_WARN "no converter for format %d", format)); - return String(); - } - - // get a handle to the clipboard data - HANDLE win32Data = GetClipboardData(converter->getWin32Format()); - if (win32Data == NULL) { - // nb: can't cause this using integ tests; this is only caused when - // the selected converter returns an invalid format -- which you - // cannot cause using public functions. - return String(); - } - - // convert - return converter->toIClipboard(win32Data); + return true; } -void -MSWindowsClipboard::clearConverters() -{ - for (ConverterList::iterator index = m_converters.begin(); - index != m_converters.end(); ++index) { - delete *index; +void MSWindowsClipboard::add(EFormat format, const String &data) { + bool isSucceeded = false; + // convert data to win32 form + for (ConverterList::const_iterator index = m_converters.begin(); + index != m_converters.end(); ++index) { + IMSWindowsClipboardConverter *converter = *index; + + // skip converters for other formats + if (converter->getFormat() == format) { + HANDLE win32Data = converter->fromIClipboard(data); + if (win32Data != NULL) { + LOG((CLOG_DEBUG "add %d bytes to clipboard format: %d", data.size(), + format)); + m_facade->write(win32Data, converter->getWin32Format()); + isSucceeded = true; + break; + } else { + LOG((CLOG_DEBUG "failed to convert clipboard data to platform format")); + } } - m_converters.clear(); + } + + if (!isSucceeded) { + LOG((CLOG_DEBUG "missed clipboard data convert for format: %d", format)); + } } -bool -MSWindowsClipboard::isOwnedBySynergy() -{ - // create ownership format if we haven't yet - if (s_ownershipFormat == 0) { - s_ownershipFormat = RegisterClipboardFormat(TEXT("SynergyOwnership")); - } - return (IsClipboardFormatAvailable(getOwnershipFormat()) != 0); +bool MSWindowsClipboard::open(Time time) const { + LOG((CLOG_DEBUG "open clipboard")); + + if (!OpenClipboard(m_window)) { + // unable to cause this in integ tests; but this can happen! + // * http://symless.com/pm/issues/86 + // * http://symless.com/pm/issues/1256 + // logging improved to see if we can catch more info next time. + LOG((CLOG_WARN "failed to open clipboard: %d", GetLastError())); + return false; + } + + m_time = time; + + return true; } -UINT -MSWindowsClipboard::getOwnershipFormat() -{ - // create ownership format if we haven't yet - if (s_ownershipFormat == 0) { - s_ownershipFormat = RegisterClipboardFormat(TEXT("SynergyOwnership")); - } - - // return the format - return s_ownershipFormat; +void MSWindowsClipboard::close() const { + LOG((CLOG_DEBUG "close clipboard")); + CloseClipboard(); +} + +IClipboard::Time MSWindowsClipboard::getTime() const { return m_time; } + +bool MSWindowsClipboard::has(EFormat format) const { + for (ConverterList::const_iterator index = m_converters.begin(); + index != m_converters.end(); ++index) { + IMSWindowsClipboardConverter *converter = *index; + if (converter->getFormat() == format) { + if (IsClipboardFormatAvailable(converter->getWin32Format())) { + return true; + } + } + } + return false; +} + +String MSWindowsClipboard::get(EFormat format) const { + // find the converter for the first clipboard format we can handle + IMSWindowsClipboardConverter *converter = NULL; + for (ConverterList::const_iterator index = m_converters.begin(); + index != m_converters.end(); ++index) { + + converter = *index; + if (converter->getFormat() == format) { + break; + } + converter = NULL; + } + + // if no converter then we don't recognize any formats + if (converter == NULL) { + LOG((CLOG_WARN "no converter for format %d", format)); + return String(); + } + + // get a handle to the clipboard data + HANDLE win32Data = GetClipboardData(converter->getWin32Format()); + if (win32Data == NULL) { + // nb: can't cause this using integ tests; this is only caused when + // the selected converter returns an invalid format -- which you + // cannot cause using public functions. + return String(); + } + + // convert + return converter->toIClipboard(win32Data); +} + +void MSWindowsClipboard::clearConverters() { + for (ConverterList::iterator index = m_converters.begin(); + index != m_converters.end(); ++index) { + delete *index; + } + m_converters.clear(); +} + +bool MSWindowsClipboard::isOwnedBySynergy() { + // create ownership format if we haven't yet + if (s_ownershipFormat == 0) { + s_ownershipFormat = RegisterClipboardFormat(TEXT("SynergyOwnership")); + } + return (IsClipboardFormatAvailable(getOwnershipFormat()) != 0); +} + +UINT MSWindowsClipboard::getOwnershipFormat() { + // create ownership format if we haven't yet + if (s_ownershipFormat == 0) { + s_ownershipFormat = RegisterClipboardFormat(TEXT("SynergyOwnership")); + } + + // return the format + return s_ownershipFormat; } diff --git a/src/lib/platform/MSWindowsClipboard.h b/src/lib/platform/MSWindowsClipboard.h index c0f47cc15..b96716cd8 100644 --- a/src/lib/platform/MSWindowsClipboard.h +++ b/src/lib/platform/MSWindowsClipboard.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -18,9 +18,9 @@ #pragma once +#include "common/stdvector.h" #include "platform/MSWindowsClipboardFacade.h" #include "synergy/IClipboard.h" -#include "common/stdvector.h" #define WIN32_LEAN_AND_MEAN #include @@ -31,57 +31,57 @@ class IMSWindowsClipboardFacade; //! Microsoft windows clipboard implementation class MSWindowsClipboard : public IClipboard { public: - MSWindowsClipboard(HWND window); - MSWindowsClipboard(HWND window, IMSWindowsClipboardFacade &facade); - virtual ~MSWindowsClipboard(); + MSWindowsClipboard(HWND window); + MSWindowsClipboard(HWND window, IMSWindowsClipboardFacade &facade); + virtual ~MSWindowsClipboard(); - //! Empty clipboard without ownership - /*! - Take ownership of the clipboard and clear all data from it. - This must be called between a successful open() and close(). - Return false if the clipboard ownership could not be taken; - the clipboard should not be emptied in this case. Unlike - empty(), isOwnedBySynergy() will return false when emptied - this way. This is useful when synergy wants to put data on - clipboard but pretend (to itself) that some other app did it. - When using empty(), synergy assumes the data came from the - server and doesn't need to be sent back. emptyUnowned() - makes synergy send the data to the server. - */ - bool emptyUnowned(); + //! Empty clipboard without ownership + /*! + Take ownership of the clipboard and clear all data from it. + This must be called between a successful open() and close(). + Return false if the clipboard ownership could not be taken; + the clipboard should not be emptied in this case. Unlike + empty(), isOwnedBySynergy() will return false when emptied + this way. This is useful when synergy wants to put data on + clipboard but pretend (to itself) that some other app did it. + When using empty(), synergy assumes the data came from the + server and doesn't need to be sent back. emptyUnowned() + makes synergy send the data to the server. + */ + bool emptyUnowned(); - //! Test if clipboard is owned by synergy - static bool isOwnedBySynergy(); + //! Test if clipboard is owned by synergy + static bool isOwnedBySynergy(); - // IClipboard overrides - virtual bool empty(); - virtual void add(EFormat, const String& data); - virtual bool open(Time) const; - virtual void close() const; - virtual Time getTime() const; - virtual bool has(EFormat) const; - virtual String get(EFormat) const; + // IClipboard overrides + virtual bool empty(); + virtual void add(EFormat, const String &data); + virtual bool open(Time) const; + virtual void close() const; + virtual Time getTime() const; + virtual bool has(EFormat) const; + virtual String get(EFormat) const; - void setFacade(IMSWindowsClipboardFacade& facade); + void setFacade(IMSWindowsClipboardFacade &facade); private: - void clearConverters(); + void clearConverters(); - UINT convertFormatToWin32(EFormat) const; - HANDLE convertTextToWin32(const String& data) const; - String convertTextFromWin32(HANDLE) const; + UINT convertFormatToWin32(EFormat) const; + HANDLE convertTextToWin32(const String &data) const; + String convertTextFromWin32(HANDLE) const; - static UINT getOwnershipFormat(); + static UINT getOwnershipFormat(); private: - typedef std::vector ConverterList; + typedef std::vector ConverterList; - HWND m_window; - mutable Time m_time; - ConverterList m_converters; - static UINT s_ownershipFormat; - IMSWindowsClipboardFacade* m_facade; - bool m_deleteFacade; + HWND m_window; + mutable Time m_time; + ConverterList m_converters; + static UINT s_ownershipFormat; + IMSWindowsClipboardFacade *m_facade; + bool m_deleteFacade; }; //! Clipboard format converter interface @@ -91,23 +91,22 @@ converters. */ class IMSWindowsClipboardConverter : public IInterface { public: - // accessors + // accessors - // return the clipboard format this object converts from/to - virtual IClipboard::EFormat - getFormat() const = 0; + // return the clipboard format this object converts from/to + virtual IClipboard::EFormat getFormat() const = 0; - // return the atom representing the win32 clipboard format that - // this object converts from/to - virtual UINT getWin32Format() const = 0; + // return the atom representing the win32 clipboard format that + // this object converts from/to + virtual UINT getWin32Format() const = 0; - // convert from the IClipboard format to the win32 clipboard format. - // the input data must be in the IClipboard format returned by - // getFormat(). the return data will be in the win32 clipboard - // format returned by getWin32Format(), allocated by GlobalAlloc(). - virtual HANDLE fromIClipboard(const String&) const = 0; + // convert from the IClipboard format to the win32 clipboard format. + // the input data must be in the IClipboard format returned by + // getFormat(). the return data will be in the win32 clipboard + // format returned by getWin32Format(), allocated by GlobalAlloc(). + virtual HANDLE fromIClipboard(const String &) const = 0; - // convert from the win32 clipboard format to the IClipboard format - // (i.e., the reverse of fromIClipboard()). - virtual String toIClipboard(HANDLE data) const = 0; + // convert from the win32 clipboard format to the IClipboard format + // (i.e., the reverse of fromIClipboard()). + virtual String toIClipboard(HANDLE data) const = 0; }; diff --git a/src/lib/platform/MSWindowsClipboardAnyTextConverter.cpp b/src/lib/platform/MSWindowsClipboardAnyTextConverter.cpp index b28b69744..8d5d77065 100644 --- a/src/lib/platform/MSWindowsClipboardAnyTextConverter.cpp +++ b/src/lib/platform/MSWindowsClipboardAnyTextConverter.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -22,128 +22,116 @@ // MSWindowsClipboardAnyTextConverter // -MSWindowsClipboardAnyTextConverter::MSWindowsClipboardAnyTextConverter() -{ - // do nothing +MSWindowsClipboardAnyTextConverter::MSWindowsClipboardAnyTextConverter() { + // do nothing } -MSWindowsClipboardAnyTextConverter::~MSWindowsClipboardAnyTextConverter() -{ - // do nothing +MSWindowsClipboardAnyTextConverter::~MSWindowsClipboardAnyTextConverter() { + // do nothing } -IClipboard::EFormat -MSWindowsClipboardAnyTextConverter::getFormat() const -{ - return IClipboard::kText; +IClipboard::EFormat MSWindowsClipboardAnyTextConverter::getFormat() const { + return IClipboard::kText; } HANDLE -MSWindowsClipboardAnyTextConverter::fromIClipboard(const String& data) const -{ - // convert linefeeds and then convert to desired encoding - String text = doFromIClipboard(convertLinefeedToWin32(data)); - UInt32 size = (UInt32)text.size(); +MSWindowsClipboardAnyTextConverter::fromIClipboard(const String &data) const { + // convert linefeeds and then convert to desired encoding + String text = doFromIClipboard(convertLinefeedToWin32(data)); + UInt32 size = (UInt32)text.size(); - // copy to memory handle - HGLOBAL gData = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, size); - if (gData != NULL) { - // get a pointer to the allocated memory - char* dst = (char*)GlobalLock(gData); - if (dst != NULL) { - memcpy(dst, text.data(), size); - GlobalUnlock(gData); - } - else { - GlobalFree(gData); - gData = NULL; - } + // copy to memory handle + HGLOBAL gData = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, size); + if (gData != NULL) { + // get a pointer to the allocated memory + char *dst = (char *)GlobalLock(gData); + if (dst != NULL) { + memcpy(dst, text.data(), size); + GlobalUnlock(gData); + } else { + GlobalFree(gData); + gData = NULL; } + } - return gData; + return gData; } -String -MSWindowsClipboardAnyTextConverter::toIClipboard(HANDLE data) const -{ - // get datator - const char* src = (const char*)GlobalLock(data); - UInt32 srcSize = (UInt32)GlobalSize(data); - if (src == NULL || srcSize <= 1) { - return String(); - } +String MSWindowsClipboardAnyTextConverter::toIClipboard(HANDLE data) const { + // get datator + const char *src = (const char *)GlobalLock(data); + UInt32 srcSize = (UInt32)GlobalSize(data); + if (src == NULL || srcSize <= 1) { + return String(); + } - // convert text - String text = doToIClipboard(String(src, srcSize)); + // convert text + String text = doToIClipboard(String(src, srcSize)); - // release handle - GlobalUnlock(data); + // release handle + GlobalUnlock(data); - // convert newlines - return convertLinefeedToUnix(text); + // convert newlines + return convertLinefeedToUnix(text); } -String -MSWindowsClipboardAnyTextConverter::convertLinefeedToWin32( - const String& src) const -{ - // note -- we assume src is a valid UTF-8 string +String MSWindowsClipboardAnyTextConverter::convertLinefeedToWin32( + const String &src) const { + // note -- we assume src is a valid UTF-8 string - // count newlines in string - UInt32 numNewlines = 0; - UInt32 n = (UInt32)src.size(); - for (const char* scan = src.c_str(); n > 0; ++scan, --n) { - if (*scan == '\n') { - ++numNewlines; - } + // count newlines in string + UInt32 numNewlines = 0; + UInt32 n = (UInt32)src.size(); + for (const char *scan = src.c_str(); n > 0; ++scan, --n) { + if (*scan == '\n') { + ++numNewlines; } - if (numNewlines == 0) { - return src; + } + if (numNewlines == 0) { + return src; + } + + // allocate new string + String dst; + dst.reserve(src.size() + numNewlines); + + // copy string, converting newlines + n = (UInt32)src.size(); + for (const char *scan = src.c_str(); n > 0; ++scan, --n) { + if (scan[0] == '\n') { + dst += '\r'; } + dst += scan[0]; + } - // allocate new string - String dst; - dst.reserve(src.size() + numNewlines); - - // copy string, converting newlines - n = (UInt32)src.size(); - for (const char* scan = src.c_str(); n > 0; ++scan, --n) { - if (scan[0] == '\n') { - dst += '\r'; - } - dst += scan[0]; - } - - return dst; + return dst; } -String -MSWindowsClipboardAnyTextConverter::convertLinefeedToUnix( - const String& src) const -{ - // count newlines in string - UInt32 numNewlines = 0; - UInt32 n = (UInt32)src.size(); - for (const char* scan = src.c_str(); n > 0; ++scan, --n) { - if (scan[0] == '\r' && scan[1] == '\n') { - ++numNewlines; - } +String MSWindowsClipboardAnyTextConverter::convertLinefeedToUnix( + const String &src) const { + // count newlines in string + UInt32 numNewlines = 0; + UInt32 n = (UInt32)src.size(); + for (const char *scan = src.c_str(); n > 0; ++scan, --n) { + if (scan[0] == '\r' && scan[1] == '\n') { + ++numNewlines; } - if (numNewlines == 0) { - return src; + } + if (numNewlines == 0) { + return src; + } + + // allocate new string + String dst; + dst.reserve(src.size()); + + // copy string, converting newlines + n = (UInt32)src.size(); + for (const char *scan = src.c_str(); n > 0; ++scan, --n) { + if (scan[0] != '\r' || scan[1] != '\n') { + dst += scan[0]; } + } - // allocate new string - String dst; - dst.reserve(src.size()); - - // copy string, converting newlines - n = (UInt32)src.size(); - for (const char* scan = src.c_str(); n > 0; ++scan, --n) { - if (scan[0] != '\r' || scan[1] != '\n') { - dst += scan[0]; - } - } - - return dst; + return dst; } diff --git a/src/lib/platform/MSWindowsClipboardAnyTextConverter.h b/src/lib/platform/MSWindowsClipboardAnyTextConverter.h index c0942839d..6fccd01f0 100644 --- a/src/lib/platform/MSWindowsClipboardAnyTextConverter.h +++ b/src/lib/platform/MSWindowsClipboardAnyTextConverter.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -21,37 +21,35 @@ #include "platform/MSWindowsClipboard.h" //! Convert to/from some text encoding -class MSWindowsClipboardAnyTextConverter : - public IMSWindowsClipboardConverter { +class MSWindowsClipboardAnyTextConverter : public IMSWindowsClipboardConverter { public: - MSWindowsClipboardAnyTextConverter(); - virtual ~MSWindowsClipboardAnyTextConverter(); + MSWindowsClipboardAnyTextConverter(); + virtual ~MSWindowsClipboardAnyTextConverter(); - // IMSWindowsClipboardConverter overrides - virtual IClipboard::EFormat - getFormat() const; - virtual UINT getWin32Format() const = 0; - virtual HANDLE fromIClipboard(const String&) const; - virtual String toIClipboard(HANDLE) const; + // IMSWindowsClipboardConverter overrides + virtual IClipboard::EFormat getFormat() const; + virtual UINT getWin32Format() const = 0; + virtual HANDLE fromIClipboard(const String &) const; + virtual String toIClipboard(HANDLE) const; protected: - //! Convert from IClipboard format - /*! - Do UTF-8 conversion only. Memory handle allocation and - linefeed conversion is done by this class. doFromIClipboard() - must include the nul terminator in the returned string (not - including the String's nul terminator). - */ - virtual String doFromIClipboard(const String&) const = 0; + //! Convert from IClipboard format + /*! + Do UTF-8 conversion only. Memory handle allocation and + linefeed conversion is done by this class. doFromIClipboard() + must include the nul terminator in the returned string (not + including the String's nul terminator). + */ + virtual String doFromIClipboard(const String &) const = 0; - //! Convert to IClipboard format - /*! - Do UTF-8 conversion only. Memory handle allocation and - linefeed conversion is done by this class. - */ - virtual String doToIClipboard(const String&) const = 0; + //! Convert to IClipboard format + /*! + Do UTF-8 conversion only. Memory handle allocation and + linefeed conversion is done by this class. + */ + virtual String doToIClipboard(const String &) const = 0; private: - String convertLinefeedToWin32(const String&) const; - String convertLinefeedToUnix(const String&) const; + String convertLinefeedToWin32(const String &) const; + String convertLinefeedToUnix(const String &) const; }; diff --git a/src/lib/platform/MSWindowsClipboardBitmapConverter.cpp b/src/lib/platform/MSWindowsClipboardBitmapConverter.cpp index 94ef10888..d2e883b37 100644 --- a/src/lib/platform/MSWindowsClipboardBitmapConverter.cpp +++ b/src/lib/platform/MSWindowsClipboardBitmapConverter.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 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 LICENSE 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 @@ -24,129 +24,119 @@ // MSWindowsClipboardBitmapConverter // -MSWindowsClipboardBitmapConverter::MSWindowsClipboardBitmapConverter() -{ - // do nothing +MSWindowsClipboardBitmapConverter::MSWindowsClipboardBitmapConverter() { + // do nothing } -MSWindowsClipboardBitmapConverter::~MSWindowsClipboardBitmapConverter() -{ - // do nothing +MSWindowsClipboardBitmapConverter::~MSWindowsClipboardBitmapConverter() { + // do nothing } -IClipboard::EFormat -MSWindowsClipboardBitmapConverter::getFormat() const -{ - return IClipboard::kBitmap; +IClipboard::EFormat MSWindowsClipboardBitmapConverter::getFormat() const { + return IClipboard::kBitmap; } -UINT -MSWindowsClipboardBitmapConverter::getWin32Format() const -{ - return CF_DIB; +UINT MSWindowsClipboardBitmapConverter::getWin32Format() const { + return CF_DIB; } HANDLE -MSWindowsClipboardBitmapConverter::fromIClipboard(const String& data) const -{ - // copy to memory handle - HGLOBAL gData = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, data.size()); - if (gData != NULL) { - // get a pointer to the allocated memory - char* dst = (char*)GlobalLock(gData); - if (dst != NULL) { - memcpy(dst, data.data(), data.size()); - GlobalUnlock(gData); - } - else { - GlobalFree(gData); - gData = NULL; - } +MSWindowsClipboardBitmapConverter::fromIClipboard(const String &data) const { + // copy to memory handle + HGLOBAL gData = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, data.size()); + if (gData != NULL) { + // get a pointer to the allocated memory + char *dst = (char *)GlobalLock(gData); + if (dst != NULL) { + memcpy(dst, data.data(), data.size()); + GlobalUnlock(gData); + } else { + GlobalFree(gData); + gData = NULL; } + } - return gData; + return gData; } -String -MSWindowsClipboardBitmapConverter::toIClipboard(HANDLE data) const -{ - // get datator - LPVOID src = GlobalLock(data); - if (src == NULL) { - return String(); - } - UInt32 srcSize = (UInt32)GlobalSize(data); +String MSWindowsClipboardBitmapConverter::toIClipboard(HANDLE data) const { + // get datator + LPVOID src = GlobalLock(data); + if (src == NULL) { + return String(); + } + UInt32 srcSize = (UInt32)GlobalSize(data); - // check image type - const BITMAPINFO* bitmap = static_cast(src); - LOG((CLOG_INFO "bitmap: %dx%d %d", bitmap->bmiHeader.biWidth, bitmap->bmiHeader.biHeight, (int)bitmap->bmiHeader.biBitCount)); - if (bitmap->bmiHeader.biPlanes == 1 && - (bitmap->bmiHeader.biBitCount == 24 || - bitmap->bmiHeader.biBitCount == 32) && - bitmap->bmiHeader.biCompression == BI_RGB) { - // already in canonical form - String image(static_cast(src), srcSize); - GlobalUnlock(data); - return image; - } - - // create a destination DIB section - LOG((CLOG_INFO "convert image from: depth=%d comp=%d", bitmap->bmiHeader.biBitCount, bitmap->bmiHeader.biCompression)); - void* raw; - BITMAPINFOHEADER info; - LONG w = bitmap->bmiHeader.biWidth; - LONG h = bitmap->bmiHeader.biHeight; - info.biSize = sizeof(BITMAPINFOHEADER); - info.biWidth = w; - info.biHeight = h; - info.biPlanes = 1; - info.biBitCount = 32; - info.biCompression = BI_RGB; - info.biSizeImage = 0; - info.biXPelsPerMeter = 1000; - info.biYPelsPerMeter = 1000; - info.biClrUsed = 0; - info.biClrImportant = 0; - HDC dc = GetDC(NULL); - HBITMAP dst = CreateDIBSection(dc, (BITMAPINFO*)&info, - DIB_RGB_COLORS, &raw, NULL, 0); - - // find the start of the pixel data - const char* srcBits = (const char*)bitmap + bitmap->bmiHeader.biSize; - if (bitmap->bmiHeader.biBitCount >= 16) { - if (bitmap->bmiHeader.biCompression == BI_BITFIELDS && - (bitmap->bmiHeader.biBitCount == 16 || - bitmap->bmiHeader.biBitCount == 32)) { - srcBits += 3 * sizeof(DWORD); - } - } - else if (bitmap->bmiHeader.biClrUsed != 0) { - srcBits += bitmap->bmiHeader.biClrUsed * sizeof(RGBQUAD); - } - else { - //http://msdn.microsoft.com/en-us/library/ke55d167(VS.80).aspx - srcBits += (1i64 << bitmap->bmiHeader.biBitCount) * sizeof(RGBQUAD); - } - - // copy source image to destination image - HDC dstDC = CreateCompatibleDC(dc); - HGDIOBJ oldBitmap = SelectObject(dstDC, dst); - SetDIBitsToDevice(dstDC, 0, 0, w, h, 0, 0, 0, h, - srcBits, bitmap, DIB_RGB_COLORS); - SelectObject(dstDC, oldBitmap); - DeleteDC(dstDC); - GdiFlush(); - - // extract data - String image((const char*)&info, info.biSize); - image.append((const char*)raw, 4 * w * h); - - // clean up GDI - DeleteObject(dst); - ReleaseDC(NULL, dc); - - // release handle + // check image type + const BITMAPINFO *bitmap = static_cast(src); + LOG((CLOG_INFO "bitmap: %dx%d %d", bitmap->bmiHeader.biWidth, + bitmap->bmiHeader.biHeight, (int)bitmap->bmiHeader.biBitCount)); + if (bitmap->bmiHeader.biPlanes == 1 && + (bitmap->bmiHeader.biBitCount == 24 || + bitmap->bmiHeader.biBitCount == 32) && + bitmap->bmiHeader.biCompression == BI_RGB) { + // already in canonical form + String image(static_cast(src), srcSize); GlobalUnlock(data); - return image; + } + + // create a destination DIB section + LOG((CLOG_INFO "convert image from: depth=%d comp=%d", + bitmap->bmiHeader.biBitCount, bitmap->bmiHeader.biCompression)); + void *raw; + BITMAPINFOHEADER info; + LONG w = bitmap->bmiHeader.biWidth; + LONG h = bitmap->bmiHeader.biHeight; + info.biSize = sizeof(BITMAPINFOHEADER); + info.biWidth = w; + info.biHeight = h; + info.biPlanes = 1; + info.biBitCount = 32; + info.biCompression = BI_RGB; + info.biSizeImage = 0; + info.biXPelsPerMeter = 1000; + info.biYPelsPerMeter = 1000; + info.biClrUsed = 0; + info.biClrImportant = 0; + HDC dc = GetDC(NULL); + HBITMAP dst = + CreateDIBSection(dc, (BITMAPINFO *)&info, DIB_RGB_COLORS, &raw, NULL, 0); + + // find the start of the pixel data + const char *srcBits = (const char *)bitmap + bitmap->bmiHeader.biSize; + if (bitmap->bmiHeader.biBitCount >= 16) { + if (bitmap->bmiHeader.biCompression == BI_BITFIELDS && + (bitmap->bmiHeader.biBitCount == 16 || + bitmap->bmiHeader.biBitCount == 32)) { + srcBits += 3 * sizeof(DWORD); + } + } else if (bitmap->bmiHeader.biClrUsed != 0) { + srcBits += bitmap->bmiHeader.biClrUsed * sizeof(RGBQUAD); + } else { + // http://msdn.microsoft.com/en-us/library/ke55d167(VS.80).aspx + srcBits += (1i64 << bitmap->bmiHeader.biBitCount) * sizeof(RGBQUAD); + } + + // copy source image to destination image + HDC dstDC = CreateCompatibleDC(dc); + HGDIOBJ oldBitmap = SelectObject(dstDC, dst); + SetDIBitsToDevice(dstDC, 0, 0, w, h, 0, 0, 0, h, srcBits, bitmap, + DIB_RGB_COLORS); + SelectObject(dstDC, oldBitmap); + DeleteDC(dstDC); + GdiFlush(); + + // extract data + String image((const char *)&info, info.biSize); + image.append((const char *)raw, 4 * w * h); + + // clean up GDI + DeleteObject(dst); + ReleaseDC(NULL, dc); + + // release handle + GlobalUnlock(data); + + return image; } diff --git a/src/lib/platform/MSWindowsClipboardBitmapConverter.h b/src/lib/platform/MSWindowsClipboardBitmapConverter.h index 4a0c8ec78..4863bfba3 100644 --- a/src/lib/platform/MSWindowsClipboardBitmapConverter.h +++ b/src/lib/platform/MSWindowsClipboardBitmapConverter.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 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 LICENSE 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 @@ -21,16 +21,14 @@ #include "platform/MSWindowsClipboard.h" //! Convert to/from some text encoding -class MSWindowsClipboardBitmapConverter : - public IMSWindowsClipboardConverter { +class MSWindowsClipboardBitmapConverter : public IMSWindowsClipboardConverter { public: - MSWindowsClipboardBitmapConverter(); - virtual ~MSWindowsClipboardBitmapConverter(); + MSWindowsClipboardBitmapConverter(); + virtual ~MSWindowsClipboardBitmapConverter(); - // IMSWindowsClipboardConverter overrides - virtual IClipboard::EFormat - getFormat() const; - virtual UINT getWin32Format() const; - virtual HANDLE fromIClipboard(const String&) const; - virtual String toIClipboard(HANDLE) const; + // IMSWindowsClipboardConverter overrides + virtual IClipboard::EFormat getFormat() const; + virtual UINT getWin32Format() const; + virtual HANDLE fromIClipboard(const String &) const; + virtual String toIClipboard(HANDLE) const; }; diff --git a/src/lib/platform/MSWindowsClipboardFacade.cpp b/src/lib/platform/MSWindowsClipboardFacade.cpp index e69bb1894..f57d65691 100644 --- a/src/lib/platform/MSWindowsClipboardFacade.cpp +++ b/src/lib/platform/MSWindowsClipboardFacade.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -20,12 +20,11 @@ #include "platform/MSWindowsClipboard.h" -void MSWindowsClipboardFacade::write(HANDLE win32Data, UINT win32Format) -{ - if (SetClipboardData(win32Format, win32Data) == NULL) { - // free converted data if we couldn't put it on - // the clipboard. - // nb: couldn't cause this in integ tests. - GlobalFree(win32Data); - } +void MSWindowsClipboardFacade::write(HANDLE win32Data, UINT win32Format) { + if (SetClipboardData(win32Format, win32Data) == NULL) { + // free converted data if we couldn't put it on + // the clipboard. + // nb: couldn't cause this in integ tests. + GlobalFree(win32Data); + } } diff --git a/src/lib/platform/MSWindowsClipboardFacade.h b/src/lib/platform/MSWindowsClipboardFacade.h index a256dacee..82a517328 100644 --- a/src/lib/platform/MSWindowsClipboardFacade.h +++ b/src/lib/platform/MSWindowsClipboardFacade.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -22,8 +22,7 @@ #include "synergy/IClipboard.h" -class MSWindowsClipboardFacade : public IMSWindowsClipboardFacade -{ +class MSWindowsClipboardFacade : public IMSWindowsClipboardFacade { public: - virtual void write(HANDLE win32Data, UINT win32Format); + virtual void write(HANDLE win32Data, UINT win32Format); }; diff --git a/src/lib/platform/MSWindowsClipboardHTMLConverter.cpp b/src/lib/platform/MSWindowsClipboardHTMLConverter.cpp index 534040584..607e8a28d 100644 --- a/src/lib/platform/MSWindowsClipboardHTMLConverter.cpp +++ b/src/lib/platform/MSWindowsClipboardHTMLConverter.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 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 LICENSE 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 @@ -24,97 +24,87 @@ // MSWindowsClipboardHTMLConverter // -MSWindowsClipboardHTMLConverter::MSWindowsClipboardHTMLConverter() -{ - m_format = RegisterClipboardFormat("HTML Format"); +MSWindowsClipboardHTMLConverter::MSWindowsClipboardHTMLConverter() { + m_format = RegisterClipboardFormat("HTML Format"); } -MSWindowsClipboardHTMLConverter::~MSWindowsClipboardHTMLConverter() -{ - // do nothing +MSWindowsClipboardHTMLConverter::~MSWindowsClipboardHTMLConverter() { + // do nothing } -IClipboard::EFormat -MSWindowsClipboardHTMLConverter::getFormat() const -{ - return IClipboard::kHTML; +IClipboard::EFormat MSWindowsClipboardHTMLConverter::getFormat() const { + return IClipboard::kHTML; } -UINT -MSWindowsClipboardHTMLConverter::getWin32Format() const -{ - return m_format; +UINT MSWindowsClipboardHTMLConverter::getWin32Format() const { + return m_format; } String -MSWindowsClipboardHTMLConverter::doFromIClipboard(const String& data) const -{ - // prepare to CF_HTML format prefix and suffix - String prefix("Version:0.9\r\nStartHTML:0000000105\r\n" - "EndHTML:ZZZZZZZZZZ\r\n" - "StartFragment:XXXXXXXXXX\r\nEndFragment:YYYYYYYYYY\r\n" - ""); - String suffix("\r\n"); +MSWindowsClipboardHTMLConverter::doFromIClipboard(const String &data) const { + // prepare to CF_HTML format prefix and suffix + String prefix("Version:0.9\r\nStartHTML:0000000105\r\n" + "EndHTML:ZZZZZZZZZZ\r\n" + "StartFragment:XXXXXXXXXX\r\nEndFragment:YYYYYYYYYY\r\n" + ""); + String suffix("\r\n"); - // Get byte offsets for header - UInt32 StartFragment = (UInt32)prefix.size(); - UInt32 EndFragment = StartFragment + (UInt32)data.size(); - // StartHTML is constant by the design of the prefix - UInt32 EndHTML = EndFragment + (UInt32)suffix.size(); + // Get byte offsets for header + UInt32 StartFragment = (UInt32)prefix.size(); + UInt32 EndFragment = StartFragment + (UInt32)data.size(); + // StartHTML is constant by the design of the prefix + UInt32 EndHTML = EndFragment + (UInt32)suffix.size(); - prefix.replace(prefix.find("XXXXXXXXXX"), 10, - synergy::string::sprintf("%010u", StartFragment)); - prefix.replace(prefix.find("YYYYYYYYYY"), 10, - synergy::string::sprintf("%010u", EndFragment)); - prefix.replace(prefix.find("ZZZZZZZZZZ"), 10, - synergy::string::sprintf("%010u", EndHTML)); + prefix.replace(prefix.find("XXXXXXXXXX"), 10, + synergy::string::sprintf("%010u", StartFragment)); + prefix.replace(prefix.find("YYYYYYYYYY"), 10, + synergy::string::sprintf("%010u", EndFragment)); + prefix.replace(prefix.find("ZZZZZZZZZZ"), 10, + synergy::string::sprintf("%010u", EndHTML)); - // concatenate - prefix += data; - prefix += suffix; - return prefix; + // concatenate + prefix += data; + prefix += suffix; + return prefix; } String -MSWindowsClipboardHTMLConverter::doToIClipboard(const String& data) const -{ - // get fragment start/end args - String startArg = findArg(data, "StartFragment"); - String endArg = findArg(data, "EndFragment"); - if (startArg.empty() || endArg.empty()) { - return String(); - } +MSWindowsClipboardHTMLConverter::doToIClipboard(const String &data) const { + // get fragment start/end args + String startArg = findArg(data, "StartFragment"); + String endArg = findArg(data, "EndFragment"); + if (startArg.empty() || endArg.empty()) { + return String(); + } - // convert args to integers - SInt32 start = (SInt32)atoi(startArg.c_str()); - SInt32 end = (SInt32)atoi(endArg.c_str()); - if (start <= 0 || end <= 0 || start >= end) { - return String(); - } + // convert args to integers + SInt32 start = (SInt32)atoi(startArg.c_str()); + SInt32 end = (SInt32)atoi(endArg.c_str()); + if (start <= 0 || end <= 0 || start >= end) { + return String(); + } - // extract the fragment - return data.substr(start, end - start); + // extract the fragment + return data.substr(start, end - start); } -String -MSWindowsClipboardHTMLConverter::findArg( - const String& data, const String& name) const -{ - String::size_type i = data.find(name); - if (i == String::npos) { - return String(); - } - i = data.find_first_of(":\r\n", i); - if (i == String::npos || data[i] != ':') { - return String(); - } - i = data.find_first_of("0123456789\r\n", i + 1); - if (i == String::npos || data[i] == '\r' || data[i] == '\n') { - return String(); - } - String::size_type j = data.find_first_not_of("0123456789", i); - if (j == String::npos) { - j = data.size(); - } - return data.substr(i, j - i); +String MSWindowsClipboardHTMLConverter::findArg(const String &data, + const String &name) const { + String::size_type i = data.find(name); + if (i == String::npos) { + return String(); + } + i = data.find_first_of(":\r\n", i); + if (i == String::npos || data[i] != ':') { + return String(); + } + i = data.find_first_of("0123456789\r\n", i + 1); + if (i == String::npos || data[i] == '\r' || data[i] == '\n') { + return String(); + } + String::size_type j = data.find_first_not_of("0123456789", i); + if (j == String::npos) { + j = data.size(); + } + return data.substr(i, j - i); } diff --git a/src/lib/platform/MSWindowsClipboardHTMLConverter.h b/src/lib/platform/MSWindowsClipboardHTMLConverter.h index 9ca767c9e..75b5a343e 100644 --- a/src/lib/platform/MSWindowsClipboardHTMLConverter.h +++ b/src/lib/platform/MSWindowsClipboardHTMLConverter.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 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 LICENSE 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 @@ -21,25 +21,24 @@ #include "platform/MSWindowsClipboardAnyTextConverter.h" //! Convert to/from HTML encoding -class MSWindowsClipboardHTMLConverter : - public MSWindowsClipboardAnyTextConverter { +class MSWindowsClipboardHTMLConverter + : public MSWindowsClipboardAnyTextConverter { public: - MSWindowsClipboardHTMLConverter(); - virtual ~MSWindowsClipboardHTMLConverter(); + MSWindowsClipboardHTMLConverter(); + virtual ~MSWindowsClipboardHTMLConverter(); - // IMSWindowsClipboardConverter overrides - virtual IClipboard::EFormat - getFormat() const; - virtual UINT getWin32Format() const; + // IMSWindowsClipboardConverter overrides + virtual IClipboard::EFormat getFormat() const; + virtual UINT getWin32Format() const; protected: - // MSWindowsClipboardAnyTextConverter overrides - virtual String doFromIClipboard(const String&) const; - virtual String doToIClipboard(const String&) const; + // MSWindowsClipboardAnyTextConverter overrides + virtual String doFromIClipboard(const String &) const; + virtual String doToIClipboard(const String &) const; private: - String findArg(const String& data, const String& name) const; + String findArg(const String &data, const String &name) const; private: - UINT m_format; + UINT m_format; }; diff --git a/src/lib/platform/MSWindowsClipboardTextConverter.cpp b/src/lib/platform/MSWindowsClipboardTextConverter.cpp index 9fbec0020..0d04692a1 100644 --- a/src/lib/platform/MSWindowsClipboardTextConverter.cpp +++ b/src/lib/platform/MSWindowsClipboardTextConverter.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -24,37 +24,29 @@ // MSWindowsClipboardTextConverter // -MSWindowsClipboardTextConverter::MSWindowsClipboardTextConverter() -{ - // do nothing +MSWindowsClipboardTextConverter::MSWindowsClipboardTextConverter() { + // do nothing } -MSWindowsClipboardTextConverter::~MSWindowsClipboardTextConverter() -{ - // do nothing +MSWindowsClipboardTextConverter::~MSWindowsClipboardTextConverter() { + // do nothing } -UINT -MSWindowsClipboardTextConverter::getWin32Format() const -{ - return CF_TEXT; +UINT MSWindowsClipboardTextConverter::getWin32Format() const { return CF_TEXT; } + +String +MSWindowsClipboardTextConverter::doFromIClipboard(const String &data) const { + // convert and add nul terminator + return Unicode::UTF8ToText(data) += '\0'; } String -MSWindowsClipboardTextConverter::doFromIClipboard(const String& data) const -{ - // convert and add nul terminator - return Unicode::UTF8ToText(data) += '\0'; -} - -String -MSWindowsClipboardTextConverter::doToIClipboard(const String& data) const -{ - // convert and truncate at first nul terminator - String dst = Unicode::textToUTF8(data); - String::size_type n = dst.find('\0'); - if (n != String::npos) { - dst.erase(n); - } - return dst; +MSWindowsClipboardTextConverter::doToIClipboard(const String &data) const { + // convert and truncate at first nul terminator + String dst = Unicode::textToUTF8(data); + String::size_type n = dst.find('\0'); + if (n != String::npos) { + dst.erase(n); + } + return dst; } diff --git a/src/lib/platform/MSWindowsClipboardTextConverter.h b/src/lib/platform/MSWindowsClipboardTextConverter.h index 2b534acd1..6b1e9dd0d 100644 --- a/src/lib/platform/MSWindowsClipboardTextConverter.h +++ b/src/lib/platform/MSWindowsClipboardTextConverter.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -21,17 +21,17 @@ #include "platform/MSWindowsClipboardAnyTextConverter.h" //! Convert to/from locale text encoding -class MSWindowsClipboardTextConverter : - public MSWindowsClipboardAnyTextConverter { +class MSWindowsClipboardTextConverter + : public MSWindowsClipboardAnyTextConverter { public: - MSWindowsClipboardTextConverter(); - virtual ~MSWindowsClipboardTextConverter(); + MSWindowsClipboardTextConverter(); + virtual ~MSWindowsClipboardTextConverter(); - // IMSWindowsClipboardConverter overrides - virtual UINT getWin32Format() const; + // IMSWindowsClipboardConverter overrides + virtual UINT getWin32Format() const; protected: - // MSWindowsClipboardAnyTextConverter overrides - virtual String doFromIClipboard(const String&) const; - virtual String doToIClipboard(const String&) const; + // MSWindowsClipboardAnyTextConverter overrides + virtual String doFromIClipboard(const String &) const; + virtual String doToIClipboard(const String &) const; }; diff --git a/src/lib/platform/MSWindowsClipboardUTF16Converter.cpp b/src/lib/platform/MSWindowsClipboardUTF16Converter.cpp index eee17af79..b41f9bc17 100644 --- a/src/lib/platform/MSWindowsClipboardUTF16Converter.cpp +++ b/src/lib/platform/MSWindowsClipboardUTF16Converter.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -24,37 +24,31 @@ // MSWindowsClipboardUTF16Converter // -MSWindowsClipboardUTF16Converter::MSWindowsClipboardUTF16Converter() -{ - // do nothing +MSWindowsClipboardUTF16Converter::MSWindowsClipboardUTF16Converter() { + // do nothing } -MSWindowsClipboardUTF16Converter::~MSWindowsClipboardUTF16Converter() -{ - // do nothing +MSWindowsClipboardUTF16Converter::~MSWindowsClipboardUTF16Converter() { + // do nothing } -UINT -MSWindowsClipboardUTF16Converter::getWin32Format() const -{ - return CF_UNICODETEXT; +UINT MSWindowsClipboardUTF16Converter::getWin32Format() const { + return CF_UNICODETEXT; } String -MSWindowsClipboardUTF16Converter::doFromIClipboard(const String& data) const -{ - // convert and add nul terminator - return Unicode::UTF8ToUTF16(data).append(sizeof(wchar_t), 0); +MSWindowsClipboardUTF16Converter::doFromIClipboard(const String &data) const { + // convert and add nul terminator + return Unicode::UTF8ToUTF16(data).append(sizeof(wchar_t), 0); } String -MSWindowsClipboardUTF16Converter::doToIClipboard(const String& data) const -{ - // convert and strip nul terminator - String dst = Unicode::UTF16ToUTF8(data); - String::size_type n = dst.find('\0'); - if (n != String::npos) { - dst.erase(n); - } - return dst; +MSWindowsClipboardUTF16Converter::doToIClipboard(const String &data) const { + // convert and strip nul terminator + String dst = Unicode::UTF16ToUTF8(data); + String::size_type n = dst.find('\0'); + if (n != String::npos) { + dst.erase(n); + } + return dst; } diff --git a/src/lib/platform/MSWindowsClipboardUTF16Converter.h b/src/lib/platform/MSWindowsClipboardUTF16Converter.h index 8c9d8ceb5..f80e733a1 100644 --- a/src/lib/platform/MSWindowsClipboardUTF16Converter.h +++ b/src/lib/platform/MSWindowsClipboardUTF16Converter.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -21,17 +21,17 @@ #include "platform/MSWindowsClipboardAnyTextConverter.h" //! Convert to/from UTF-16 encoding -class MSWindowsClipboardUTF16Converter : - public MSWindowsClipboardAnyTextConverter { +class MSWindowsClipboardUTF16Converter + : public MSWindowsClipboardAnyTextConverter { public: - MSWindowsClipboardUTF16Converter(); - virtual ~MSWindowsClipboardUTF16Converter(); + MSWindowsClipboardUTF16Converter(); + virtual ~MSWindowsClipboardUTF16Converter(); - // IMSWindowsClipboardConverter overrides - virtual UINT getWin32Format() const; + // IMSWindowsClipboardConverter overrides + virtual UINT getWin32Format() const; protected: - // MSWindowsClipboardAnyTextConverter overrides - virtual String doFromIClipboard(const String&) const; - virtual String doToIClipboard(const String&) const; + // MSWindowsClipboardAnyTextConverter overrides + virtual String doFromIClipboard(const String &) const; + virtual String doToIClipboard(const String &) const; }; diff --git a/src/lib/platform/MSWindowsDebugOutputter.cpp b/src/lib/platform/MSWindowsDebugOutputter.cpp index 9d9f43445..f5730e8ab 100644 --- a/src/lib/platform/MSWindowsDebugOutputter.cpp +++ b/src/lib/platform/MSWindowsDebugOutputter.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2012 Nick Bolton - * + * * 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 LICENSE 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 @@ -22,37 +22,19 @@ #include #include -MSWindowsDebugOutputter::MSWindowsDebugOutputter() -{ +MSWindowsDebugOutputter::MSWindowsDebugOutputter() {} + +MSWindowsDebugOutputter::~MSWindowsDebugOutputter() {} + +void MSWindowsDebugOutputter::open(const char *title) {} + +void MSWindowsDebugOutputter::close() {} + +void MSWindowsDebugOutputter::show(bool showIfEmpty) {} + +bool MSWindowsDebugOutputter::write(ELevel level, const char *msg) { + OutputDebugString((std::string(msg) + "\n").c_str()); + return true; } -MSWindowsDebugOutputter::~MSWindowsDebugOutputter() -{ -} - -void -MSWindowsDebugOutputter::open(const char* title) -{ -} - -void -MSWindowsDebugOutputter::close() -{ -} - -void -MSWindowsDebugOutputter::show(bool showIfEmpty) -{ -} - -bool -MSWindowsDebugOutputter::write(ELevel level, const char* msg) -{ - OutputDebugString((std::string(msg) + "\n").c_str()); - return true; -} - -void -MSWindowsDebugOutputter::flush() -{ -} +void MSWindowsDebugOutputter::flush() {} diff --git a/src/lib/platform/MSWindowsDebugOutputter.h b/src/lib/platform/MSWindowsDebugOutputter.h index 3ce8c4e5b..84a94b140 100644 --- a/src/lib/platform/MSWindowsDebugOutputter.h +++ b/src/lib/platform/MSWindowsDebugOutputter.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2012 Nick Bolton - * + * * 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 LICENSE 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 @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + #pragma once #include "base/ILogOutputter.h" @@ -27,13 +27,13 @@ can be seen in the Output window. */ class MSWindowsDebugOutputter : public ILogOutputter { public: - MSWindowsDebugOutputter(); - virtual ~MSWindowsDebugOutputter(); + MSWindowsDebugOutputter(); + virtual ~MSWindowsDebugOutputter(); - // ILogOutputter overrides - virtual void open(const char* title); - virtual void close(); - virtual void show(bool showIfEmpty); - virtual bool write(ELevel level, const char* message); - virtual void flush(); + // ILogOutputter overrides + virtual void open(const char *title); + virtual void close(); + virtual void show(bool showIfEmpty); + virtual bool write(ELevel level, const char *message); + virtual void flush(); }; diff --git a/src/lib/platform/MSWindowsDesks.cpp b/src/lib/platform/MSWindowsDesks.cpp index 73ad36ed1..20f8ed1f0 100644 --- a/src/lib/platform/MSWindowsDesks.cpp +++ b/src/lib/platform/MSWindowsDesks.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 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 LICENSE 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 @@ -18,19 +18,18 @@ #include "platform/MSWindowsDesks.h" -#include "platform/synwinhk.h" -#include "platform/MSWindowsScreen.h" -#include "synergy/IScreenSaver.h" -#include "synergy/XScreen.h" -#include "mt/Lock.h" -#include "mt/Thread.h" #include "arch/win32/ArchMiscWindows.h" -#include "base/Log.h" #include "base/IEventQueue.h" #include "base/IJob.h" +#include "base/Log.h" #include "base/TMethodEventJob.h" #include "base/TMethodJob.h" -#include "base/IEventQueue.h" +#include "mt/Lock.h" +#include "mt/Thread.h" +#include "platform/MSWindowsScreen.h" +#include "platform/synwinhk.h" +#include "synergy/IScreenSaver.h" +#include "synergy/XScreen.h" #include "synergy/win32/AppUtilWindows.h" #include @@ -48,932 +47,807 @@ // X button stuff #if !defined(WM_XBUTTONDOWN) -#define WM_XBUTTONDOWN 0x020B -#define WM_XBUTTONUP 0x020C -#define WM_XBUTTONDBLCLK 0x020D -#define WM_NCXBUTTONDOWN 0x00AB -#define WM_NCXBUTTONUP 0x00AC -#define WM_NCXBUTTONDBLCLK 0x00AD -#define MOUSEEVENTF_XDOWN 0x0080 -#define MOUSEEVENTF_XUP 0x0100 -#define XBUTTON1 0x0001 -#define XBUTTON2 0x0002 +#define WM_XBUTTONDOWN 0x020B +#define WM_XBUTTONUP 0x020C +#define WM_XBUTTONDBLCLK 0x020D +#define WM_NCXBUTTONDOWN 0x00AB +#define WM_NCXBUTTONUP 0x00AC +#define WM_NCXBUTTONDBLCLK 0x00AD +#define MOUSEEVENTF_XDOWN 0x0080 +#define MOUSEEVENTF_XUP 0x0100 +#define XBUTTON1 0x0001 +#define XBUTTON2 0x0002 #endif #if !defined(VK_XBUTTON1) -#define VK_XBUTTON1 0x05 -#define VK_XBUTTON2 0x06 +#define VK_XBUTTON1 0x05 +#define VK_XBUTTON2 0x06 #endif // ; -#define SYNERGY_MSG_SWITCH SYNERGY_HOOK_LAST_MSG + 1 +#define SYNERGY_MSG_SWITCH SYNERGY_HOOK_LAST_MSG + 1 // ; -#define SYNERGY_MSG_ENTER SYNERGY_HOOK_LAST_MSG + 2 +#define SYNERGY_MSG_ENTER SYNERGY_HOOK_LAST_MSG + 2 // ; -#define SYNERGY_MSG_LEAVE SYNERGY_HOOK_LAST_MSG + 3 +#define SYNERGY_MSG_LEAVE SYNERGY_HOOK_LAST_MSG + 3 // wParam = flags, HIBYTE(lParam) = virtual key, LOBYTE(lParam) = scan code -#define SYNERGY_MSG_FAKE_KEY SYNERGY_HOOK_LAST_MSG + 4 - // flags, XBUTTON id -#define SYNERGY_MSG_FAKE_BUTTON SYNERGY_HOOK_LAST_MSG + 5 +#define SYNERGY_MSG_FAKE_KEY SYNERGY_HOOK_LAST_MSG + 4 +// flags, XBUTTON id +#define SYNERGY_MSG_FAKE_BUTTON SYNERGY_HOOK_LAST_MSG + 5 // x; y -#define SYNERGY_MSG_FAKE_MOVE SYNERGY_HOOK_LAST_MSG + 6 +#define SYNERGY_MSG_FAKE_MOVE SYNERGY_HOOK_LAST_MSG + 6 // xDelta; yDelta -#define SYNERGY_MSG_FAKE_WHEEL SYNERGY_HOOK_LAST_MSG + 7 +#define SYNERGY_MSG_FAKE_WHEEL SYNERGY_HOOK_LAST_MSG + 7 // POINT*; -#define SYNERGY_MSG_CURSOR_POS SYNERGY_HOOK_LAST_MSG + 8 +#define SYNERGY_MSG_CURSOR_POS SYNERGY_HOOK_LAST_MSG + 8 // IKeyState*; -#define SYNERGY_MSG_SYNC_KEYS SYNERGY_HOOK_LAST_MSG + 9 +#define SYNERGY_MSG_SYNC_KEYS SYNERGY_HOOK_LAST_MSG + 9 // install; -#define SYNERGY_MSG_SCREENSAVER SYNERGY_HOOK_LAST_MSG + 10 +#define SYNERGY_MSG_SCREENSAVER SYNERGY_HOOK_LAST_MSG + 10 // dx; dy -#define SYNERGY_MSG_FAKE_REL_MOVE SYNERGY_HOOK_LAST_MSG + 11 +#define SYNERGY_MSG_FAKE_REL_MOVE SYNERGY_HOOK_LAST_MSG + 11 // enable; -#define SYNERGY_MSG_FAKE_INPUT SYNERGY_HOOK_LAST_MSG + 12 +#define SYNERGY_MSG_FAKE_INPUT SYNERGY_HOOK_LAST_MSG + 12 - -static void -send_keyboard_input(WORD wVk, WORD wScan, DWORD dwFlags) -{ - INPUT inp; - inp.type = INPUT_KEYBOARD; - inp.ki.wVk = (dwFlags & KEYEVENTF_UNICODE) ? 0 : wVk; // 1..254 inclusive otherwise - inp.ki.wScan = wScan; - inp.ki.dwFlags = dwFlags & 0xF; - inp.ki.time = 0; - inp.ki.dwExtraInfo = 0; - SendInput(1, &inp, sizeof(inp)); +static void send_keyboard_input(WORD wVk, WORD wScan, DWORD dwFlags) { + INPUT inp; + inp.type = INPUT_KEYBOARD; + inp.ki.wVk = + (dwFlags & KEYEVENTF_UNICODE) ? 0 : wVk; // 1..254 inclusive otherwise + inp.ki.wScan = wScan; + inp.ki.dwFlags = dwFlags & 0xF; + inp.ki.time = 0; + inp.ki.dwExtraInfo = 0; + SendInput(1, &inp, sizeof(inp)); } -static void -send_mouse_input(DWORD dwFlags, DWORD dx, DWORD dy, DWORD dwData) -{ - INPUT inp; - inp.type = INPUT_MOUSE; - inp.mi.dwFlags = dwFlags; - inp.mi.dx = dx; - inp.mi.dy = dy; - inp.mi.mouseData = dwData; - inp.mi.time = 0; - inp.mi.dwExtraInfo = 0; - SendInput(1, &inp, sizeof(inp)); +static void send_mouse_input(DWORD dwFlags, DWORD dx, DWORD dy, DWORD dwData) { + INPUT inp; + inp.type = INPUT_MOUSE; + inp.mi.dwFlags = dwFlags; + inp.mi.dx = dx; + inp.mi.dy = dy; + inp.mi.mouseData = dwData; + inp.mi.time = 0; + inp.mi.dwExtraInfo = 0; + SendInput(1, &inp, sizeof(inp)); } // // MSWindowsDesks // -MSWindowsDesks::MSWindowsDesks( - bool isPrimary, bool noHooks, - const IScreenSaver* screensaver, IEventQueue* events, - IJob* updateKeys, bool stopOnDeskSwitch) : - m_isPrimary(isPrimary), - m_noHooks(noHooks), - m_isOnScreen(m_isPrimary), - m_x(0), m_y(0), - m_w(0), m_h(0), - m_xCenter(0), m_yCenter(0), - m_multimon(false), - m_timer(NULL), - m_screensaver(screensaver), - m_screensaverNotify(false), - m_activeDesk(NULL), - m_activeDeskName(), - m_mutex(), - m_deskReady(&m_mutex, false), - m_updateKeys(updateKeys), - m_events(events), - m_stopOnDeskSwitch(stopOnDeskSwitch) -{ +MSWindowsDesks::MSWindowsDesks(bool isPrimary, bool noHooks, + const IScreenSaver *screensaver, + IEventQueue *events, IJob *updateKeys, + bool stopOnDeskSwitch) + : m_isPrimary(isPrimary), m_noHooks(noHooks), m_isOnScreen(m_isPrimary), + m_x(0), m_y(0), m_w(0), m_h(0), m_xCenter(0), m_yCenter(0), + m_multimon(false), m_timer(NULL), m_screensaver(screensaver), + m_screensaverNotify(false), m_activeDesk(NULL), m_activeDeskName(), + m_mutex(), m_deskReady(&m_mutex, false), m_updateKeys(updateKeys), + m_events(events), m_stopOnDeskSwitch(stopOnDeskSwitch) { - m_cursor = createBlankCursor(); - m_deskClass = createDeskWindowClass(m_isPrimary); - m_keyLayout = AppUtilWindows::instance().getCurrentKeyboardLayout(); - resetOptions(); + m_cursor = createBlankCursor(); + m_deskClass = createDeskWindowClass(m_isPrimary); + m_keyLayout = AppUtilWindows::instance().getCurrentKeyboardLayout(); + resetOptions(); } -MSWindowsDesks::~MSWindowsDesks() -{ - disable(); - destroyClass(m_deskClass); - destroyCursor(m_cursor); - delete m_updateKeys; +MSWindowsDesks::~MSWindowsDesks() { + disable(); + destroyClass(m_deskClass); + destroyCursor(m_cursor); + delete m_updateKeys; } -void -MSWindowsDesks::enable() -{ - m_threadID = GetCurrentThreadId(); +void MSWindowsDesks::enable() { + m_threadID = GetCurrentThreadId(); - // set the active desk and (re)install the hooks - checkDesk(); + // set the active desk and (re)install the hooks + checkDesk(); - // install the desk timer. this timer periodically checks - // which desk is active and reinstalls the hooks as necessary. - // we wouldn't need this if windows notified us of a desktop - // change but as far as i can tell it doesn't. - m_timer = m_events->newTimer(0.2, NULL); - m_events->adoptHandler(Event::kTimer, m_timer, - new TMethodEventJob( - this, &MSWindowsDesks::handleCheckDesk)); + // install the desk timer. this timer periodically checks + // which desk is active and reinstalls the hooks as necessary. + // we wouldn't need this if windows notified us of a desktop + // change but as far as i can tell it doesn't. + m_timer = m_events->newTimer(0.2, NULL); + m_events->adoptHandler(Event::kTimer, m_timer, + new TMethodEventJob( + this, &MSWindowsDesks::handleCheckDesk)); - updateKeys(); + updateKeys(); } -void -MSWindowsDesks::disable() -{ - // remove timer - if (m_timer != NULL) { - m_events->removeHandler(Event::kTimer, m_timer); - m_events->deleteTimer(m_timer); - m_timer = NULL; +void MSWindowsDesks::disable() { + // remove timer + if (m_timer != NULL) { + m_events->removeHandler(Event::kTimer, m_timer); + m_events->deleteTimer(m_timer); + m_timer = NULL; + } + + // destroy desks + removeDesks(); + + m_isOnScreen = m_isPrimary; +} + +void MSWindowsDesks::enter() { sendMessage(SYNERGY_MSG_ENTER, 0, 0); } + +void MSWindowsDesks::leave(HKL keyLayout) { + sendMessage(SYNERGY_MSG_LEAVE, (WPARAM)keyLayout, 0); +} + +void MSWindowsDesks::resetOptions() { m_leaveForegroundOption = false; } + +void MSWindowsDesks::setOptions(const OptionsList &options) { + for (UInt32 i = 0, n = (UInt32)options.size(); i < n; i += 2) { + if (options[i] == kOptionWin32KeepForeground) { + m_leaveForegroundOption = (options[i + 1] != 0); + LOG((CLOG_DEBUG1 "%s the foreground window", + m_leaveForegroundOption ? "don\'t grab" : "grab")); } - - // destroy desks - removeDesks(); - - m_isOnScreen = m_isPrimary; + } } -void -MSWindowsDesks::enter() -{ - sendMessage(SYNERGY_MSG_ENTER, 0, 0); +void MSWindowsDesks::updateKeys() { sendMessage(SYNERGY_MSG_SYNC_KEYS, 0, 0); } + +void MSWindowsDesks::setShape(SInt32 x, SInt32 y, SInt32 width, SInt32 height, + SInt32 xCenter, SInt32 yCenter, bool isMultimon) { + m_x = x; + m_y = y; + m_w = width; + m_h = height; + m_xCenter = xCenter; + m_yCenter = yCenter; + m_multimon = isMultimon; } -void -MSWindowsDesks::leave(HKL keyLayout) -{ - sendMessage(SYNERGY_MSG_LEAVE, (WPARAM)keyLayout, 0); +void MSWindowsDesks::installScreensaverHooks(bool install) { + if (m_isPrimary && m_screensaverNotify != install) { + m_screensaverNotify = install; + sendMessage(SYNERGY_MSG_SCREENSAVER, install, 0); + } } -void -MSWindowsDesks::resetOptions() -{ - m_leaveForegroundOption = false; +void MSWindowsDesks::fakeInputBegin() { + sendMessage(SYNERGY_MSG_FAKE_INPUT, 1, 0); } -void -MSWindowsDesks::setOptions(const OptionsList& options) -{ - for (UInt32 i = 0, n = (UInt32)options.size(); i < n; i += 2) { - if (options[i] == kOptionWin32KeepForeground) { - m_leaveForegroundOption = (options[i + 1] != 0); - LOG((CLOG_DEBUG1 "%s the foreground window", m_leaveForegroundOption ? "don\'t grab" : "grab")); - } - } +void MSWindowsDesks::fakeInputEnd() { + sendMessage(SYNERGY_MSG_FAKE_INPUT, 0, 0); } -void -MSWindowsDesks::updateKeys() -{ - sendMessage(SYNERGY_MSG_SYNC_KEYS, 0, 0); +void MSWindowsDesks::getCursorPos(SInt32 &x, SInt32 &y) const { + POINT pos; + sendMessage(SYNERGY_MSG_CURSOR_POS, reinterpret_cast(&pos), 0); + x = pos.x; + y = pos.y; } -void -MSWindowsDesks::setShape(SInt32 x, SInt32 y, - SInt32 width, SInt32 height, - SInt32 xCenter, SInt32 yCenter, bool isMultimon) -{ - m_x = x; - m_y = y; - m_w = width; - m_h = height; - m_xCenter = xCenter; - m_yCenter = yCenter; - m_multimon = isMultimon; +void MSWindowsDesks::fakeKeyEvent(WORD virtualKey, WORD scanCode, DWORD flags, + bool /*isAutoRepeat*/) const { + sendMessage(SYNERGY_MSG_FAKE_KEY, flags, MAKELPARAM(scanCode, virtualKey)); } -void -MSWindowsDesks::installScreensaverHooks(bool install) -{ - if (m_isPrimary && m_screensaverNotify != install) { - m_screensaverNotify = install; - sendMessage(SYNERGY_MSG_SCREENSAVER, install, 0); - } -} - -void -MSWindowsDesks::fakeInputBegin() -{ - sendMessage(SYNERGY_MSG_FAKE_INPUT, 1, 0); -} - -void -MSWindowsDesks::fakeInputEnd() -{ - sendMessage(SYNERGY_MSG_FAKE_INPUT, 0, 0); -} - -void -MSWindowsDesks::getCursorPos(SInt32& x, SInt32& y) const -{ - POINT pos; - sendMessage(SYNERGY_MSG_CURSOR_POS, reinterpret_cast(&pos), 0); - x = pos.x; - y = pos.y; -} - -void -MSWindowsDesks::fakeKeyEvent(WORD virtualKey, WORD scanCode, DWORD flags, bool /*isAutoRepeat*/) const -{ - sendMessage(SYNERGY_MSG_FAKE_KEY, flags, MAKELPARAM(scanCode, virtualKey)); -} - -void -MSWindowsDesks::fakeMouseButton(ButtonID button, bool press) -{ - // the system will swap the meaning of left/right for us if - // the user has configured a left-handed mouse but we don't - // want it to swap since we want the handedness of the - // server's mouse. so pre-swap for a left-handed mouse. - if (GetSystemMetrics(SM_SWAPBUTTON)) { - switch (button) { - case kButtonLeft: - button = kButtonRight; - break; - - case kButtonRight: - button = kButtonLeft; - break; - } - } - - // map button id to button flag and button data - DWORD data = 0; - DWORD flags; +void MSWindowsDesks::fakeMouseButton(ButtonID button, bool press) { + // the system will swap the meaning of left/right for us if + // the user has configured a left-handed mouse but we don't + // want it to swap since we want the handedness of the + // server's mouse. so pre-swap for a left-handed mouse. + if (GetSystemMetrics(SM_SWAPBUTTON)) { switch (button) { case kButtonLeft: - flags = press ? MOUSEEVENTF_LEFTDOWN : MOUSEEVENTF_LEFTUP; - break; - - case kButtonMiddle: - flags = press ? MOUSEEVENTF_MIDDLEDOWN : MOUSEEVENTF_MIDDLEUP; - break; + button = kButtonRight; + break; case kButtonRight: - flags = press ? MOUSEEVENTF_RIGHTDOWN : MOUSEEVENTF_RIGHTUP; - break; - - case kButtonExtra0 + 0: - data = XBUTTON1; - flags = press ? MOUSEEVENTF_XDOWN : MOUSEEVENTF_XUP; - break; - - case kButtonExtra0 + 1: - data = XBUTTON2; - flags = press ? MOUSEEVENTF_XDOWN : MOUSEEVENTF_XUP; - break; - - default: - return; + button = kButtonLeft; + break; } + } - // do it - sendMessage(SYNERGY_MSG_FAKE_BUTTON, flags, data); + // map button id to button flag and button data + DWORD data = 0; + DWORD flags; + switch (button) { + case kButtonLeft: + flags = press ? MOUSEEVENTF_LEFTDOWN : MOUSEEVENTF_LEFTUP; + break; + + case kButtonMiddle: + flags = press ? MOUSEEVENTF_MIDDLEDOWN : MOUSEEVENTF_MIDDLEUP; + break; + + case kButtonRight: + flags = press ? MOUSEEVENTF_RIGHTDOWN : MOUSEEVENTF_RIGHTUP; + break; + + case kButtonExtra0 + 0: + data = XBUTTON1; + flags = press ? MOUSEEVENTF_XDOWN : MOUSEEVENTF_XUP; + break; + + case kButtonExtra0 + 1: + data = XBUTTON2; + flags = press ? MOUSEEVENTF_XDOWN : MOUSEEVENTF_XUP; + break; + + default: + return; + } + + // do it + sendMessage(SYNERGY_MSG_FAKE_BUTTON, flags, data); } -void -MSWindowsDesks::fakeMouseMove(SInt32 x, SInt32 y) const -{ - sendMessage(SYNERGY_MSG_FAKE_MOVE, - static_cast(x), - static_cast(y)); +void MSWindowsDesks::fakeMouseMove(SInt32 x, SInt32 y) const { + sendMessage(SYNERGY_MSG_FAKE_MOVE, static_cast(x), + static_cast(y)); } -void -MSWindowsDesks::fakeMouseRelativeMove(SInt32 dx, SInt32 dy) const -{ - sendMessage(SYNERGY_MSG_FAKE_REL_MOVE, - static_cast(dx), - static_cast(dy)); +void MSWindowsDesks::fakeMouseRelativeMove(SInt32 dx, SInt32 dy) const { + sendMessage(SYNERGY_MSG_FAKE_REL_MOVE, static_cast(dx), + static_cast(dy)); } -void -MSWindowsDesks::fakeMouseWheel(SInt32 xDelta, SInt32 yDelta) const -{ - sendMessage(SYNERGY_MSG_FAKE_WHEEL, xDelta, yDelta); +void MSWindowsDesks::fakeMouseWheel(SInt32 xDelta, SInt32 yDelta) const { + sendMessage(SYNERGY_MSG_FAKE_WHEEL, xDelta, yDelta); } -void -MSWindowsDesks::sendMessage(UINT msg, WPARAM wParam, LPARAM lParam) const -{ - if (m_activeDesk != NULL && m_activeDesk->m_window != NULL) { - PostThreadMessage(m_activeDesk->m_threadID, msg, wParam, lParam); - waitForDesk(); - } +void MSWindowsDesks::sendMessage(UINT msg, WPARAM wParam, LPARAM lParam) const { + if (m_activeDesk != NULL && m_activeDesk->m_window != NULL) { + PostThreadMessage(m_activeDesk->m_threadID, msg, wParam, lParam); + waitForDesk(); + } } HCURSOR -MSWindowsDesks::createBlankCursor() const -{ - // create a transparent cursor - int cw = GetSystemMetrics(SM_CXCURSOR); - int ch = GetSystemMetrics(SM_CYCURSOR); - UInt8* cursorAND = new UInt8[ch * ((cw + 31) >> 2)]; - UInt8* cursorXOR = new UInt8[ch * ((cw + 31) >> 2)]; - memset(cursorAND, 0xff, ch * ((cw + 31) >> 2)); - memset(cursorXOR, 0x00, ch * ((cw + 31) >> 2)); - HCURSOR c = CreateCursor(MSWindowsScreen::getWindowInstance(), - 0, 0, cw, ch, cursorAND, cursorXOR); - delete[] cursorXOR; - delete[] cursorAND; - return c; +MSWindowsDesks::createBlankCursor() const { + // create a transparent cursor + int cw = GetSystemMetrics(SM_CXCURSOR); + int ch = GetSystemMetrics(SM_CYCURSOR); + UInt8 *cursorAND = new UInt8[ch * ((cw + 31) >> 2)]; + UInt8 *cursorXOR = new UInt8[ch * ((cw + 31) >> 2)]; + memset(cursorAND, 0xff, ch * ((cw + 31) >> 2)); + memset(cursorXOR, 0x00, ch * ((cw + 31) >> 2)); + HCURSOR c = CreateCursor(MSWindowsScreen::getWindowInstance(), 0, 0, cw, ch, + cursorAND, cursorXOR); + delete[] cursorXOR; + delete[] cursorAND; + return c; } -void -MSWindowsDesks::destroyCursor(HCURSOR cursor) const -{ - if (cursor != NULL) { - DestroyCursor(cursor); +void MSWindowsDesks::destroyCursor(HCURSOR cursor) const { + if (cursor != NULL) { + DestroyCursor(cursor); + } +} + +ATOM MSWindowsDesks::createDeskWindowClass(bool isPrimary) const { + WNDCLASSEX classInfo; + classInfo.cbSize = sizeof(classInfo); + classInfo.style = CS_DBLCLKS | CS_NOCLOSE; + classInfo.lpfnWndProc = isPrimary ? &MSWindowsDesks::primaryDeskProc + : &MSWindowsDesks::secondaryDeskProc; + classInfo.cbClsExtra = 0; + classInfo.cbWndExtra = 0; + classInfo.hInstance = MSWindowsScreen::getWindowInstance(); + classInfo.hIcon = NULL; + classInfo.hCursor = m_cursor; + classInfo.hbrBackground = NULL; + classInfo.lpszMenuName = NULL; + classInfo.lpszClassName = "SynergyDesk"; + classInfo.hIconSm = NULL; + return RegisterClassEx(&classInfo); +} + +void MSWindowsDesks::destroyClass(ATOM windowClass) const { + if (windowClass != 0) { + UnregisterClass(MAKEINTATOM(windowClass), + MSWindowsScreen::getWindowInstance()); + } +} + +HWND MSWindowsDesks::createWindow(ATOM windowClass, const char *name) const { + HWND window = + CreateWindowEx(WS_EX_TRANSPARENT | WS_EX_TOOLWINDOW, + MAKEINTATOM(windowClass), name, WS_POPUP, 0, 0, 1, 1, NULL, + NULL, MSWindowsScreen::getWindowInstance(), NULL); + if (window == NULL) { + LOG((CLOG_ERR "failed to create window: %d", GetLastError())); + throw XScreenOpenFailure(); + } + return window; +} + +void MSWindowsDesks::destroyWindow(HWND hwnd) const { + if (hwnd != NULL) { + DestroyWindow(hwnd); + } +} + +LRESULT CALLBACK MSWindowsDesks::primaryDeskProc(HWND hwnd, UINT msg, + WPARAM wParam, LPARAM lParam) { + return DefWindowProc(hwnd, msg, wParam, lParam); +} + +LRESULT CALLBACK MSWindowsDesks::secondaryDeskProc(HWND hwnd, UINT msg, + WPARAM wParam, + LPARAM lParam) { + // would like to detect any local user input and hide the hider + // window but for now we just detect mouse motion. + bool hide = false; + switch (msg) { + case WM_MOUSEMOVE: + if (LOWORD(lParam) != 0 || HIWORD(lParam) != 0) { + hide = true; } + break; + } + + if (hide && IsWindowVisible(hwnd)) { + ReleaseCapture(); + SetWindowPos(hwnd, HWND_BOTTOM, 0, 0, 0, 0, + SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_HIDEWINDOW); + } + + return DefWindowProc(hwnd, msg, wParam, lParam); } -ATOM -MSWindowsDesks::createDeskWindowClass(bool isPrimary) const -{ - WNDCLASSEX classInfo; - classInfo.cbSize = sizeof(classInfo); - classInfo.style = CS_DBLCLKS | CS_NOCLOSE; - classInfo.lpfnWndProc = isPrimary ? - &MSWindowsDesks::primaryDeskProc : - &MSWindowsDesks::secondaryDeskProc; - classInfo.cbClsExtra = 0; - classInfo.cbWndExtra = 0; - classInfo.hInstance = MSWindowsScreen::getWindowInstance(); - classInfo.hIcon = NULL; - classInfo.hCursor = m_cursor; - classInfo.hbrBackground = NULL; - classInfo.lpszMenuName = NULL; - classInfo.lpszClassName = "SynergyDesk"; - classInfo.hIconSm = NULL; - return RegisterClassEx(&classInfo); +void MSWindowsDesks::deskMouseMove(SInt32 x, SInt32 y) const { + // when using absolute positioning with mouse_event(), + // the normalized device coordinates range over only + // the primary screen. + SInt32 w = GetSystemMetrics(SM_CXSCREEN); + SInt32 h = GetSystemMetrics(SM_CYSCREEN); + send_mouse_input(MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE, + (DWORD)((65535.0f * x) / (w - 1) + 0.5f), + (DWORD)((65535.0f * y) / (h - 1) + 0.5f), 0); } -void -MSWindowsDesks::destroyClass(ATOM windowClass) const -{ - if (windowClass != 0) { - UnregisterClass(MAKEINTATOM(windowClass), - MSWindowsScreen::getWindowInstance()); +void MSWindowsDesks::deskMouseRelativeMove(SInt32 dx, SInt32 dy) const { + // relative moves are subject to cursor acceleration which we don't + // want.so we disable acceleration, do the relative move, then + // restore acceleration. there's a slight chance we'll end up in + // the wrong place if the user moves the cursor using this system's + // mouse while simultaneously moving the mouse on the server + // system. that defeats the purpose of synergy so we'll assume + // that won't happen. even if it does, the next mouse move will + // correct the position. + + // save mouse speed & acceleration + int oldSpeed[4]; + bool accelChanged = + SystemParametersInfo(SPI_GETMOUSE, 0, oldSpeed, 0) && + SystemParametersInfo(SPI_GETMOUSESPEED, 0, oldSpeed + 3, 0); + + // use 1:1 motion + if (accelChanged) { + int newSpeed[4] = {0, 0, 0, 1}; + accelChanged = SystemParametersInfo(SPI_SETMOUSE, 0, newSpeed, 0) || + SystemParametersInfo(SPI_SETMOUSESPEED, 0, newSpeed + 3, 0); + } + + // move relative to mouse position + send_mouse_input(MOUSEEVENTF_MOVE, dx, dy, 0); + + // restore mouse speed & acceleration + if (accelChanged) { + SystemParametersInfo(SPI_SETMOUSE, 0, oldSpeed, 0); + SystemParametersInfo(SPI_SETMOUSESPEED, 0, oldSpeed + 3, 0); + } +} + +void MSWindowsDesks::deskEnter(Desk *desk) { + if (!m_isPrimary) { + ReleaseCapture(); + } + ShowCursor(TRUE); + SetWindowPos(desk->m_window, HWND_BOTTOM, 0, 0, 0, 0, + SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_HIDEWINDOW); + + // restore the foreground window + // XXX -- this raises the window to the top of the Z-order. we + // want it to stay wherever it was to properly support X-mouse + // (mouse over activation) but i've no idea how to do that. + // the obvious workaround of using SetWindowPos() to move it back + // after being raised doesn't work. + DWORD thisThread = GetWindowThreadProcessId(desk->m_window, NULL); + DWORD thatThread = GetWindowThreadProcessId(desk->m_foregroundWindow, NULL); + AttachThreadInput(thatThread, thisThread, TRUE); + SetForegroundWindow(desk->m_foregroundWindow); + AttachThreadInput(thatThread, thisThread, FALSE); + EnableWindow(desk->m_window, desk->m_lowLevel ? FALSE : TRUE); + desk->m_foregroundWindow = NULL; +} + +void MSWindowsDesks::deskLeave(Desk *desk, HKL keyLayout) { + ShowCursor(FALSE); + if (m_isPrimary) { + // map a window to hide the cursor and to use whatever keyboard + // layout we choose rather than the keyboard layout of the last + // active window. + int x, y, w, h; + if (desk->m_lowLevel) { + // with a low level hook the cursor will never budge so + // just a 1x1 window is sufficient. + x = m_xCenter; + y = m_yCenter; + w = 1; + h = 1; + } else { + // with regular hooks the cursor will jitter as it's moved + // by the user then back to the center by us. to be sure + // we never lose it, cover all the monitors with the window. + x = m_x; + y = m_y; + w = m_w; + h = m_h; } -} + SetWindowPos(desk->m_window, HWND_TOP, x, y, w, h, + SWP_NOACTIVATE | SWP_SHOWWINDOW); -HWND -MSWindowsDesks::createWindow(ATOM windowClass, const char* name) const -{ - HWND window = CreateWindowEx(WS_EX_TRANSPARENT | - WS_EX_TOOLWINDOW, - MAKEINTATOM(windowClass), - name, - WS_POPUP, - 0, 0, 1, 1, - NULL, NULL, - MSWindowsScreen::getWindowInstance(), - NULL); - if (window == NULL) { - LOG((CLOG_ERR "failed to create window: %d", GetLastError())); - throw XScreenOpenFailure(); - } - return window; -} + // switch to requested keyboard layout + ActivateKeyboardLayout(keyLayout, 0); -void -MSWindowsDesks::destroyWindow(HWND hwnd) const -{ - if (hwnd != NULL) { - DestroyWindow(hwnd); - } -} - -LRESULT CALLBACK -MSWindowsDesks::primaryDeskProc( - HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - return DefWindowProc(hwnd, msg, wParam, lParam); -} - -LRESULT CALLBACK -MSWindowsDesks::secondaryDeskProc( - HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - // would like to detect any local user input and hide the hider - // window but for now we just detect mouse motion. - bool hide = false; - switch (msg) { - case WM_MOUSEMOVE: - if (LOWORD(lParam) != 0 || HIWORD(lParam) != 0) { - hide = true; - } - break; + // if not using low-level hooks we have to also activate the + // window to ensure we don't lose keyboard focus. + // FIXME -- see if this can be avoided. if so then always + // disable the window (see handling of SYNERGY_MSG_SWITCH). + if (!desk->m_lowLevel) { + SetActiveWindow(desk->m_window); } - if (hide && IsWindowVisible(hwnd)) { - ReleaseCapture(); - SetWindowPos(hwnd, HWND_BOTTOM, 0, 0, 0, 0, - SWP_NOMOVE | SWP_NOSIZE | - SWP_NOACTIVATE | SWP_HIDEWINDOW); - } - - return DefWindowProc(hwnd, msg, wParam, lParam); -} - -void -MSWindowsDesks::deskMouseMove(SInt32 x, SInt32 y) const -{ - // when using absolute positioning with mouse_event(), - // the normalized device coordinates range over only - // the primary screen. - SInt32 w = GetSystemMetrics(SM_CXSCREEN); - SInt32 h = GetSystemMetrics(SM_CYSCREEN); - send_mouse_input(MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE, - (DWORD)((65535.0f * x) / (w - 1) + 0.5f), - (DWORD)((65535.0f * y) / (h - 1) + 0.5f), - 0); -} - -void -MSWindowsDesks::deskMouseRelativeMove(SInt32 dx, SInt32 dy) const -{ - // relative moves are subject to cursor acceleration which we don't - // want.so we disable acceleration, do the relative move, then - // restore acceleration. there's a slight chance we'll end up in - // the wrong place if the user moves the cursor using this system's - // mouse while simultaneously moving the mouse on the server - // system. that defeats the purpose of synergy so we'll assume - // that won't happen. even if it does, the next mouse move will - // correct the position. - - // save mouse speed & acceleration - int oldSpeed[4]; - bool accelChanged = - SystemParametersInfo(SPI_GETMOUSE,0, oldSpeed, 0) && - SystemParametersInfo(SPI_GETMOUSESPEED, 0, oldSpeed + 3, 0); - - // use 1:1 motion - if (accelChanged) { - int newSpeed[4] = { 0, 0, 0, 1 }; - accelChanged = - SystemParametersInfo(SPI_SETMOUSE, 0, newSpeed, 0) || - SystemParametersInfo(SPI_SETMOUSESPEED, 0, newSpeed + 3, 0); - } - - // move relative to mouse position - send_mouse_input(MOUSEEVENTF_MOVE, dx, dy, 0); - - // restore mouse speed & acceleration - if (accelChanged) { - SystemParametersInfo(SPI_SETMOUSE, 0, oldSpeed, 0); - SystemParametersInfo(SPI_SETMOUSESPEED, 0, oldSpeed + 3, 0); - } -} - -void -MSWindowsDesks::deskEnter(Desk* desk) -{ - if (!m_isPrimary) { - ReleaseCapture(); - } - ShowCursor(TRUE); - SetWindowPos(desk->m_window, HWND_BOTTOM, 0, 0, 0, 0, - SWP_NOMOVE | SWP_NOSIZE | - SWP_NOACTIVATE | SWP_HIDEWINDOW); - - // restore the foreground window - // XXX -- this raises the window to the top of the Z-order. we - // want it to stay wherever it was to properly support X-mouse - // (mouse over activation) but i've no idea how to do that. - // the obvious workaround of using SetWindowPos() to move it back - // after being raised doesn't work. - DWORD thisThread = - GetWindowThreadProcessId(desk->m_window, NULL); - DWORD thatThread = - GetWindowThreadProcessId(desk->m_foregroundWindow, NULL); - AttachThreadInput(thatThread, thisThread, TRUE); - SetForegroundWindow(desk->m_foregroundWindow); - AttachThreadInput(thatThread, thisThread, FALSE); - EnableWindow(desk->m_window, desk->m_lowLevel ? FALSE : TRUE); - desk->m_foregroundWindow = NULL; -} - -void -MSWindowsDesks::deskLeave(Desk* desk, HKL keyLayout) -{ - ShowCursor(FALSE); - if (m_isPrimary) { - // map a window to hide the cursor and to use whatever keyboard - // layout we choose rather than the keyboard layout of the last - // active window. - int x, y, w, h; - if (desk->m_lowLevel) { - // with a low level hook the cursor will never budge so - // just a 1x1 window is sufficient. - x = m_xCenter; - y = m_yCenter; - w = 1; - h = 1; - } - else { - // with regular hooks the cursor will jitter as it's moved - // by the user then back to the center by us. to be sure - // we never lose it, cover all the monitors with the window. - x = m_x; - y = m_y; - w = m_w; - h = m_h; - } - SetWindowPos(desk->m_window, HWND_TOP, x, y, w, h, - SWP_NOACTIVATE | SWP_SHOWWINDOW); - - // switch to requested keyboard layout - ActivateKeyboardLayout(keyLayout, 0); - - // if not using low-level hooks we have to also activate the - // window to ensure we don't lose keyboard focus. - // FIXME -- see if this can be avoided. if so then always - // disable the window (see handling of SYNERGY_MSG_SWITCH). - if (!desk->m_lowLevel) { - SetActiveWindow(desk->m_window); - } - - // if using low-level hooks then disable the foreground window - // so it can't mess up any of our keyboard events. the console - // program, for example, will cause characters to be reported as - // unshifted, regardless of the shift key state. interestingly - // we do see the shift key go down and up. - // - // note that we must enable the window to activate it and we - // need to disable the window on deskEnter. - else { - desk->m_foregroundWindow = getForegroundWindow(); - if (desk->m_foregroundWindow != NULL) { - EnableWindow(desk->m_window, TRUE); - SetActiveWindow(desk->m_window); - DWORD thisThread = - GetWindowThreadProcessId(desk->m_window, NULL); - DWORD thatThread = - GetWindowThreadProcessId(desk->m_foregroundWindow, NULL); - - AttachThreadInput(thatThread, thisThread, TRUE); - SetForegroundWindow(desk->m_window); - AttachThreadInput(thatThread, thisThread, FALSE); - } - } - } + // if using low-level hooks then disable the foreground window + // so it can't mess up any of our keyboard events. the console + // program, for example, will cause characters to be reported as + // unshifted, regardless of the shift key state. interestingly + // we do see the shift key go down and up. + // + // note that we must enable the window to activate it and we + // need to disable the window on deskEnter. else { - // move hider window under the cursor center, raise, and show it - SetWindowPos(desk->m_window, HWND_TOP, - m_xCenter, m_yCenter, 1, 1, - SWP_NOACTIVATE | SWP_SHOWWINDOW); + desk->m_foregroundWindow = getForegroundWindow(); + if (desk->m_foregroundWindow != NULL) { + EnableWindow(desk->m_window, TRUE); + SetActiveWindow(desk->m_window); + DWORD thisThread = GetWindowThreadProcessId(desk->m_window, NULL); + DWORD thatThread = + GetWindowThreadProcessId(desk->m_foregroundWindow, NULL); - // watch for mouse motion. if we see any then we hide the - // hider window so the user can use the physically attached - // mouse if desired. we'd rather not capture the mouse but - // we aren't notified when the mouse leaves our window. - SetCapture(desk->m_window); - - // warp the mouse to the cursor center - LOG((CLOG_DEBUG2 "warping cursor to center: %+d,%+d", m_xCenter, m_yCenter)); - deskMouseMove(m_xCenter, m_yCenter); + AttachThreadInput(thatThread, thisThread, TRUE); + SetForegroundWindow(desk->m_window); + AttachThreadInput(thatThread, thisThread, FALSE); + } } + } else { + // move hider window under the cursor center, raise, and show it + SetWindowPos(desk->m_window, HWND_TOP, m_xCenter, m_yCenter, 1, 1, + SWP_NOACTIVATE | SWP_SHOWWINDOW); + + // watch for mouse motion. if we see any then we hide the + // hider window so the user can use the physically attached + // mouse if desired. we'd rather not capture the mouse but + // we aren't notified when the mouse leaves our window. + SetCapture(desk->m_window); + + // warp the mouse to the cursor center + LOG((CLOG_DEBUG2 "warping cursor to center: %+d,%+d", m_xCenter, + m_yCenter)); + deskMouseMove(m_xCenter, m_yCenter); + } } -void -MSWindowsDesks::deskThread(void* vdesk) -{ - MSG msg; +void MSWindowsDesks::deskThread(void *vdesk) { + MSG msg; - // use given desktop for this thread - Desk* desk = static_cast(vdesk); - desk->m_threadID = GetCurrentThreadId(); - desk->m_window = NULL; - desk->m_foregroundWindow = NULL; - if (desk->m_desk != NULL && SetThreadDesktop(desk->m_desk) != 0) { - // create a message queue - PeekMessage(&msg, NULL, 0,0, PM_NOREMOVE); + // use given desktop for this thread + Desk *desk = static_cast(vdesk); + desk->m_threadID = GetCurrentThreadId(); + desk->m_window = NULL; + desk->m_foregroundWindow = NULL; + if (desk->m_desk != NULL && SetThreadDesktop(desk->m_desk) != 0) { + // create a message queue + PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE); - // create a window. we use this window to hide the cursor. - try { - desk->m_window = createWindow(m_deskClass, "SynergyDesk"); - LOG((CLOG_DEBUG "desk %s window is 0x%08x", desk->m_name.c_str(), desk->m_window)); - } - catch (...) { - // ignore - LOG((CLOG_DEBUG "can't create desk window for %s", desk->m_name.c_str())); - } + // create a window. we use this window to hide the cursor. + try { + desk->m_window = createWindow(m_deskClass, "SynergyDesk"); + LOG((CLOG_DEBUG "desk %s window is 0x%08x", desk->m_name.c_str(), + desk->m_window)); + } catch (...) { + // ignore + LOG((CLOG_DEBUG "can't create desk window for %s", desk->m_name.c_str())); } + } - // tell main thread that we're ready - { - Lock lock(&m_mutex); - m_deskReady = true; - m_deskReady.broadcast(); - } - - while (GetMessage(&msg, NULL, 0, 0)) { - switch (msg.message) { - default: - TranslateMessage(&msg); - DispatchMessage(&msg); - continue; - - case SYNERGY_MSG_SWITCH: - if (!m_noHooks) { - MSWindowsHook::uninstall(); - if (m_screensaverNotify) { - MSWindowsHook::uninstallScreenSaver(); - MSWindowsHook::installScreenSaver(); - } - switch (MSWindowsHook::install()) { - case kHOOK_FAILED: - // we won't work on this desk - desk->m_lowLevel = false; - break; - - case kHOOK_OKAY: - desk->m_lowLevel = false; - break; - - case kHOOK_OKAY_LL: - desk->m_lowLevel = true; - break; - } - - // a window on the primary screen with low-level hooks - // should never activate. - if (desk->m_window) - EnableWindow(desk->m_window, desk->m_lowLevel ? FALSE : TRUE); - } - break; - - case SYNERGY_MSG_ENTER: - m_isOnScreen = true; - deskEnter(desk); - break; - - case SYNERGY_MSG_LEAVE: - m_isOnScreen = false; - m_keyLayout = (HKL)msg.wParam; - deskLeave(desk, m_keyLayout); - break; - - case SYNERGY_MSG_FAKE_KEY: - // Note, this is intended to be HI/LOWORD and not HI/LOBYTE - send_keyboard_input( - HIWORD(msg.lParam), - LOWORD(msg.lParam), - (DWORD)msg.wParam); - break; - - case SYNERGY_MSG_FAKE_BUTTON: - if (msg.wParam != 0) { - send_mouse_input((DWORD)msg.wParam, 0, 0, (DWORD)msg.lParam); - } - break; - - case SYNERGY_MSG_FAKE_MOVE: - deskMouseMove(static_cast(msg.wParam), - static_cast(msg.lParam)); - break; - - case SYNERGY_MSG_FAKE_REL_MOVE: - deskMouseRelativeMove(static_cast(msg.wParam), - static_cast(msg.lParam)); - break; - - case SYNERGY_MSG_FAKE_WHEEL: - // XXX -- add support for x-axis scrolling - if (msg.lParam != 0) { - send_mouse_input(MOUSEEVENTF_WHEEL, 0, 0, (DWORD)msg.lParam); - } - break; - - case SYNERGY_MSG_CURSOR_POS: { - POINT* pos = reinterpret_cast(msg.wParam); - if (!GetCursorPos(pos)) { - pos->x = m_xCenter; - pos->y = m_yCenter; - } - break; - } - - case SYNERGY_MSG_SYNC_KEYS: - m_updateKeys->run(); - break; - - case SYNERGY_MSG_SCREENSAVER: - if (!m_noHooks) { - if (msg.wParam != 0) { - MSWindowsHook::installScreenSaver(); - } - else { - MSWindowsHook::uninstallScreenSaver(); - } - } - break; - - case SYNERGY_MSG_FAKE_INPUT: - send_keyboard_input( - SYNERGY_HOOK_FAKE_INPUT_VIRTUAL_KEY, - SYNERGY_HOOK_FAKE_INPUT_SCANCODE, - msg.wParam ? 0 : KEYEVENTF_KEYUP); - break; - } - - // notify that message was processed - Lock lock(&m_mutex); - m_deskReady = true; - m_deskReady.broadcast(); - } - - // clean up - deskEnter(desk); - if (desk->m_window != NULL) { - DestroyWindow(desk->m_window); - } - if (desk->m_desk != NULL) { - closeDesktop(desk->m_desk); - } -} - -MSWindowsDesks::Desk* -MSWindowsDesks::addDesk(const String& name, HDESK hdesk) -{ - Desk* desk = new Desk; - desk->m_name = name; - desk->m_desk = hdesk; - desk->m_targetID = GetCurrentThreadId(); - desk->m_thread = new Thread(new TMethodJob( - this, &MSWindowsDesks::deskThread, desk)); - waitForDesk(); - m_desks.insert(std::make_pair(name, desk)); - return desk; -} - -void -MSWindowsDesks::removeDesks() -{ - for (Desks::iterator index = m_desks.begin(); - index != m_desks.end(); ++index) { - Desk* desk = index->second; - PostThreadMessage(desk->m_threadID, WM_QUIT, 0, 0); - desk->m_thread->wait(); - delete desk->m_thread; - delete desk; - } - m_desks.clear(); - m_activeDesk = NULL; - m_activeDeskName = ""; -} - -void -MSWindowsDesks::checkDesk() -{ - // get current desktop. if we already know about it then return. - Desk* desk; - HDESK hdesk = openInputDesktop(); - String name = getDesktopName(hdesk); - Desks::const_iterator index = m_desks.find(name); - if (index == m_desks.end()) { - desk = addDesk(name, hdesk); - // hold on to hdesk until thread exits so the desk can't - // be removed by the system - } - else { - closeDesktop(hdesk); - desk = index->second; - } - - // if we are told to shut down on desk switch, and this is not the - // first switch, then shut down. - if (m_stopOnDeskSwitch && m_activeDesk != NULL && name != m_activeDeskName) { - LOG((CLOG_DEBUG "shutting down because of desk switch to \"%s\"", name.c_str())); - m_events->addEvent(Event(Event::kQuit)); - return; - } - - // if active desktop changed then tell the old and new desk threads - // about the change. don't switch desktops when the screensaver is - // active becaue we'd most likely switch to the screensaver desktop - // which would have the side effect of forcing the screensaver to - // stop. - if (name != m_activeDeskName && !m_screensaver->isActive()) { - // show cursor on previous desk - bool wasOnScreen = m_isOnScreen; - if (!wasOnScreen) { - sendMessage(SYNERGY_MSG_ENTER, 0, 0); - } - - // check for desk accessibility change. we don't get events - // from an inaccessible desktop so when we switch from an - // inaccessible desktop to an accessible one we have to - // update the keyboard state. - LOG((CLOG_DEBUG "switched to desk \"%s\"", name.c_str())); - bool syncKeys = false; - bool isAccessible = isDeskAccessible(desk); - if (isDeskAccessible(m_activeDesk) != isAccessible) { - if (isAccessible) { - LOG((CLOG_DEBUG "desktop is now accessible")); - syncKeys = true; - } - else { - LOG((CLOG_DEBUG "desktop is now inaccessible")); - } - } - - // switch desk - m_activeDesk = desk; - m_activeDeskName = name; - sendMessage(SYNERGY_MSG_SWITCH, 0, 0); - - // hide cursor on new desk - if (!wasOnScreen) { - sendMessage(SYNERGY_MSG_LEAVE, (WPARAM)m_keyLayout, 0); - } - - // update keys if necessary - if (syncKeys) { - updateKeys(); - } - } - else if (name != m_activeDeskName) { - // screen saver might have started - PostThreadMessage(m_threadID, SYNERGY_MSG_SCREEN_SAVER, TRUE, 0); - } -} - -bool -MSWindowsDesks::isDeskAccessible(const Desk* desk) const -{ - return (desk != NULL && desk->m_desk != NULL); -} - -void -MSWindowsDesks::waitForDesk() const -{ - MSWindowsDesks* self = const_cast(this); - + // tell main thread that we're ready + { Lock lock(&m_mutex); - while (!(bool)m_deskReady) { - m_deskReady.wait(); + m_deskReady = true; + m_deskReady.broadcast(); + } + + while (GetMessage(&msg, NULL, 0, 0)) { + switch (msg.message) { + default: + TranslateMessage(&msg); + DispatchMessage(&msg); + continue; + + case SYNERGY_MSG_SWITCH: + if (!m_noHooks) { + MSWindowsHook::uninstall(); + if (m_screensaverNotify) { + MSWindowsHook::uninstallScreenSaver(); + MSWindowsHook::installScreenSaver(); + } + switch (MSWindowsHook::install()) { + case kHOOK_FAILED: + // we won't work on this desk + desk->m_lowLevel = false; + break; + + case kHOOK_OKAY: + desk->m_lowLevel = false; + break; + + case kHOOK_OKAY_LL: + desk->m_lowLevel = true; + break; + } + + // a window on the primary screen with low-level hooks + // should never activate. + if (desk->m_window) + EnableWindow(desk->m_window, desk->m_lowLevel ? FALSE : TRUE); + } + break; + + case SYNERGY_MSG_ENTER: + m_isOnScreen = true; + deskEnter(desk); + break; + + case SYNERGY_MSG_LEAVE: + m_isOnScreen = false; + m_keyLayout = (HKL)msg.wParam; + deskLeave(desk, m_keyLayout); + break; + + case SYNERGY_MSG_FAKE_KEY: + // Note, this is intended to be HI/LOWORD and not HI/LOBYTE + send_keyboard_input(HIWORD(msg.lParam), LOWORD(msg.lParam), + (DWORD)msg.wParam); + break; + + case SYNERGY_MSG_FAKE_BUTTON: + if (msg.wParam != 0) { + send_mouse_input((DWORD)msg.wParam, 0, 0, (DWORD)msg.lParam); + } + break; + + case SYNERGY_MSG_FAKE_MOVE: + deskMouseMove(static_cast(msg.wParam), + static_cast(msg.lParam)); + break; + + case SYNERGY_MSG_FAKE_REL_MOVE: + deskMouseRelativeMove(static_cast(msg.wParam), + static_cast(msg.lParam)); + break; + + case SYNERGY_MSG_FAKE_WHEEL: + // XXX -- add support for x-axis scrolling + if (msg.lParam != 0) { + send_mouse_input(MOUSEEVENTF_WHEEL, 0, 0, (DWORD)msg.lParam); + } + break; + + case SYNERGY_MSG_CURSOR_POS: { + POINT *pos = reinterpret_cast(msg.wParam); + if (!GetCursorPos(pos)) { + pos->x = m_xCenter; + pos->y = m_yCenter; + } + break; } - self->m_deskReady = false; + + case SYNERGY_MSG_SYNC_KEYS: + m_updateKeys->run(); + break; + + case SYNERGY_MSG_SCREENSAVER: + if (!m_noHooks) { + if (msg.wParam != 0) { + MSWindowsHook::installScreenSaver(); + } else { + MSWindowsHook::uninstallScreenSaver(); + } + } + break; + + case SYNERGY_MSG_FAKE_INPUT: + send_keyboard_input(SYNERGY_HOOK_FAKE_INPUT_VIRTUAL_KEY, + SYNERGY_HOOK_FAKE_INPUT_SCANCODE, + msg.wParam ? 0 : KEYEVENTF_KEYUP); + break; + } + + // notify that message was processed + Lock lock(&m_mutex); + m_deskReady = true; + m_deskReady.broadcast(); + } + + // clean up + deskEnter(desk); + if (desk->m_window != NULL) { + DestroyWindow(desk->m_window); + } + if (desk->m_desk != NULL) { + closeDesktop(desk->m_desk); + } } -void -MSWindowsDesks::handleCheckDesk(const Event&, void*) -{ - checkDesk(); +MSWindowsDesks::Desk *MSWindowsDesks::addDesk(const String &name, HDESK hdesk) { + Desk *desk = new Desk; + desk->m_name = name; + desk->m_desk = hdesk; + desk->m_targetID = GetCurrentThreadId(); + desk->m_thread = new Thread( + new TMethodJob(this, &MSWindowsDesks::deskThread, desk)); + waitForDesk(); + m_desks.insert(std::make_pair(name, desk)); + return desk; +} - // also check if screen saver is running if on a modern OS and - // this is the primary screen. - if (m_isPrimary) { - BOOL running; - SystemParametersInfo(SPI_GETSCREENSAVERRUNNING, 0, &running, FALSE); - PostThreadMessage(m_threadID, SYNERGY_MSG_SCREEN_SAVER, running, 0); +void MSWindowsDesks::removeDesks() { + for (Desks::iterator index = m_desks.begin(); index != m_desks.end(); + ++index) { + Desk *desk = index->second; + PostThreadMessage(desk->m_threadID, WM_QUIT, 0, 0); + desk->m_thread->wait(); + delete desk->m_thread; + delete desk; + } + m_desks.clear(); + m_activeDesk = NULL; + m_activeDeskName = ""; +} + +void MSWindowsDesks::checkDesk() { + // get current desktop. if we already know about it then return. + Desk *desk; + HDESK hdesk = openInputDesktop(); + String name = getDesktopName(hdesk); + Desks::const_iterator index = m_desks.find(name); + if (index == m_desks.end()) { + desk = addDesk(name, hdesk); + // hold on to hdesk until thread exits so the desk can't + // be removed by the system + } else { + closeDesktop(hdesk); + desk = index->second; + } + + // if we are told to shut down on desk switch, and this is not the + // first switch, then shut down. + if (m_stopOnDeskSwitch && m_activeDesk != NULL && name != m_activeDeskName) { + LOG((CLOG_DEBUG "shutting down because of desk switch to \"%s\"", + name.c_str())); + m_events->addEvent(Event(Event::kQuit)); + return; + } + + // if active desktop changed then tell the old and new desk threads + // about the change. don't switch desktops when the screensaver is + // active becaue we'd most likely switch to the screensaver desktop + // which would have the side effect of forcing the screensaver to + // stop. + if (name != m_activeDeskName && !m_screensaver->isActive()) { + // show cursor on previous desk + bool wasOnScreen = m_isOnScreen; + if (!wasOnScreen) { + sendMessage(SYNERGY_MSG_ENTER, 0, 0); } + + // check for desk accessibility change. we don't get events + // from an inaccessible desktop so when we switch from an + // inaccessible desktop to an accessible one we have to + // update the keyboard state. + LOG((CLOG_DEBUG "switched to desk \"%s\"", name.c_str())); + bool syncKeys = false; + bool isAccessible = isDeskAccessible(desk); + if (isDeskAccessible(m_activeDesk) != isAccessible) { + if (isAccessible) { + LOG((CLOG_DEBUG "desktop is now accessible")); + syncKeys = true; + } else { + LOG((CLOG_DEBUG "desktop is now inaccessible")); + } + } + + // switch desk + m_activeDesk = desk; + m_activeDeskName = name; + sendMessage(SYNERGY_MSG_SWITCH, 0, 0); + + // hide cursor on new desk + if (!wasOnScreen) { + sendMessage(SYNERGY_MSG_LEAVE, (WPARAM)m_keyLayout, 0); + } + + // update keys if necessary + if (syncKeys) { + updateKeys(); + } + } else if (name != m_activeDeskName) { + // screen saver might have started + PostThreadMessage(m_threadID, SYNERGY_MSG_SCREEN_SAVER, TRUE, 0); + } +} + +bool MSWindowsDesks::isDeskAccessible(const Desk *desk) const { + return (desk != NULL && desk->m_desk != NULL); +} + +void MSWindowsDesks::waitForDesk() const { + MSWindowsDesks *self = const_cast(this); + + Lock lock(&m_mutex); + while (!(bool)m_deskReady) { + m_deskReady.wait(); + } + self->m_deskReady = false; +} + +void MSWindowsDesks::handleCheckDesk(const Event &, void *) { + checkDesk(); + + // also check if screen saver is running if on a modern OS and + // this is the primary screen. + if (m_isPrimary) { + BOOL running; + SystemParametersInfo(SPI_GETSCREENSAVERRUNNING, 0, &running, FALSE); + PostThreadMessage(m_threadID, SYNERGY_MSG_SCREEN_SAVER, running, 0); + } } HDESK -MSWindowsDesks::openInputDesktop() -{ - return OpenInputDesktop( - DF_ALLOWOTHERACCOUNTHOOK, TRUE, - DESKTOP_CREATEWINDOW | DESKTOP_HOOKCONTROL | GENERIC_WRITE); +MSWindowsDesks::openInputDesktop() { + return OpenInputDesktop(DF_ALLOWOTHERACCOUNTHOOK, TRUE, + DESKTOP_CREATEWINDOW | DESKTOP_HOOKCONTROL | + GENERIC_WRITE); } -void -MSWindowsDesks::closeDesktop(HDESK desk) -{ - if (desk != NULL) { - CloseDesktop(desk); - } +void MSWindowsDesks::closeDesktop(HDESK desk) { + if (desk != NULL) { + CloseDesktop(desk); + } } -String -MSWindowsDesks::getDesktopName(HDESK desk) -{ - if (desk == NULL) { - return String(); - } - else { - DWORD size; - GetUserObjectInformation(desk, UOI_NAME, NULL, 0, &size); - TCHAR* name = (TCHAR*)alloca(size + sizeof(TCHAR)); - GetUserObjectInformation(desk, UOI_NAME, name, size, &size); - String result(name); - return result; - } +String MSWindowsDesks::getDesktopName(HDESK desk) { + if (desk == NULL) { + return String(); + } else { + DWORD size; + GetUserObjectInformation(desk, UOI_NAME, NULL, 0, &size); + TCHAR *name = (TCHAR *)alloca(size + sizeof(TCHAR)); + GetUserObjectInformation(desk, UOI_NAME, name, size, &size); + String result(name); + return result; + } } -HWND -MSWindowsDesks::getForegroundWindow() const -{ - // Ideally we'd return NULL as much as possible, only returning - // the actual foreground window when we know it's going to mess - // up our keyboard input. For now we'll just let the user - // decide. - if (m_leaveForegroundOption) { - return NULL; - } - return GetForegroundWindow(); +HWND MSWindowsDesks::getForegroundWindow() const { + // Ideally we'd return NULL as much as possible, only returning + // the actual foreground window when we know it's going to mess + // up our keyboard input. For now we'll just let the user + // decide. + if (m_leaveForegroundOption) { + return NULL; + } + return GetForegroundWindow(); } diff --git a/src/lib/platform/MSWindowsDesks.h b/src/lib/platform/MSWindowsDesks.h index e608080b7..eea2538f6 100644 --- a/src/lib/platform/MSWindowsDesks.h +++ b/src/lib/platform/MSWindowsDesks.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 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 LICENSE 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 @@ -18,14 +18,14 @@ #pragma once +#include "base/String.h" +#include "common/stdmap.h" +#include "mt/CondVar.h" +#include "mt/Mutex.h" #include "platform/synwinhk.h" #include "synergy/key_types.h" #include "synergy/mouse_types.h" #include "synergy/option_types.h" -#include "mt/CondVar.h" -#include "mt/Mutex.h" -#include "base/String.h" -#include "common/stdmap.h" #define WIN32_LEAN_AND_MEAN #include @@ -55,242 +55,239 @@ object don't have to know anything about desks. */ class MSWindowsDesks { public: - //! Constructor - /*! - \p isPrimary is true iff the desk is for a primary screen. - \p screensaver points to a screensaver object and it's used - only to check if the screensaver is active. The \p updateKeys - job is adopted and is called when the key state should be - updated in a thread attached to the current desk. - \p hookLibrary must be a handle to the hook library. - */ - MSWindowsDesks( - bool isPrimary, bool noHooks, - const IScreenSaver* screensaver, IEventQueue* events, - IJob* updateKeys, bool stopOnDeskSwitch); - ~MSWindowsDesks(); + //! Constructor + /*! + \p isPrimary is true iff the desk is for a primary screen. + \p screensaver points to a screensaver object and it's used + only to check if the screensaver is active. The \p updateKeys + job is adopted and is called when the key state should be + updated in a thread attached to the current desk. + \p hookLibrary must be a handle to the hook library. + */ + MSWindowsDesks(bool isPrimary, bool noHooks, const IScreenSaver *screensaver, + IEventQueue *events, IJob *updateKeys, bool stopOnDeskSwitch); + ~MSWindowsDesks(); - //! @name manipulators - //@{ + //! @name manipulators + //@{ - //! Enable desk tracking - /*! - Enables desk tracking. While enabled, this object checks to see - if the desk has changed and ensures that the hooks are installed - on the new desk. \c setShape should be called at least once - before calling \c enable. - */ - void enable(); + //! Enable desk tracking + /*! + Enables desk tracking. While enabled, this object checks to see + if the desk has changed and ensures that the hooks are installed + on the new desk. \c setShape should be called at least once + before calling \c enable. + */ + void enable(); - //! Disable desk tracking - /*! - Disables desk tracking. \sa enable. - */ - void disable(); + //! Disable desk tracking + /*! + Disables desk tracking. \sa enable. + */ + void disable(); - //! Notify of entering a desk - /*! - Prepares a desk for when the cursor enters it. - */ - void enter(); + //! Notify of entering a desk + /*! + Prepares a desk for when the cursor enters it. + */ + void enter(); - //! Notify of leaving a desk - /*! - Prepares a desk for when the cursor leaves it. - */ - void leave(HKL keyLayout); + //! Notify of leaving a desk + /*! + Prepares a desk for when the cursor leaves it. + */ + void leave(HKL keyLayout); - //! Notify of options changes - /*! - Resets all options to their default values. - */ - void resetOptions(); + //! Notify of options changes + /*! + Resets all options to their default values. + */ + void resetOptions(); - //! Notify of options changes - /*! - Set options to given values. Ignores unknown options and doesn't - modify options that aren't given in \c options. - */ - void setOptions(const OptionsList& options); + //! Notify of options changes + /*! + Set options to given values. Ignores unknown options and doesn't + modify options that aren't given in \c options. + */ + void setOptions(const OptionsList &options); - //! Update the key state - /*! - Causes the key state to get updated to reflect the physical keyboard - state and current keyboard mapping. - */ - void updateKeys(); + //! Update the key state + /*! + Causes the key state to get updated to reflect the physical keyboard + state and current keyboard mapping. + */ + void updateKeys(); - //! Tell desk about new size - /*! - This tells the desks that the display size has changed. - */ - void setShape(SInt32 x, SInt32 y, - SInt32 width, SInt32 height, - SInt32 xCenter, SInt32 yCenter, bool isMultimon); + //! Tell desk about new size + /*! + This tells the desks that the display size has changed. + */ + void setShape(SInt32 x, SInt32 y, SInt32 width, SInt32 height, SInt32 xCenter, + SInt32 yCenter, bool isMultimon); - //! Install/uninstall screensaver hooks - /*! - If \p install is true then the screensaver hooks are installed and, - if desk tracking is enabled, updated whenever the desk changes. If - \p install is false then the screensaver hooks are uninstalled. - */ - void installScreensaverHooks(bool install); + //! Install/uninstall screensaver hooks + /*! + If \p install is true then the screensaver hooks are installed and, + if desk tracking is enabled, updated whenever the desk changes. If + \p install is false then the screensaver hooks are uninstalled. + */ + void installScreensaverHooks(bool install); - //! Start ignoring user input - /*! - Starts ignoring user input so we don't pick up our own synthesized events. - */ - void fakeInputBegin(); + //! Start ignoring user input + /*! + Starts ignoring user input so we don't pick up our own synthesized events. + */ + void fakeInputBegin(); - //! Stop ignoring user input - /*! - Undoes whatever \c fakeInputBegin() did. - */ - void fakeInputEnd(); + //! Stop ignoring user input + /*! + Undoes whatever \c fakeInputBegin() did. + */ + void fakeInputEnd(); - //@} - //! @name accessors - //@{ + //@} + //! @name accessors + //@{ - //! Get cursor position - /*! - Return the current position of the cursor in \c x and \c y. - */ - void getCursorPos(SInt32& x, SInt32& y) const; + //! Get cursor position + /*! + Return the current position of the cursor in \c x and \c y. + */ + void getCursorPos(SInt32 &x, SInt32 &y) const; - //! Fake key press/release - /*! - Synthesize a press or release of key \c button. - */ - void fakeKeyEvent(WORD virtualKey, WORD scanCode, - DWORD flags, bool isAutoRepeat) const; + //! Fake key press/release + /*! + Synthesize a press or release of key \c button. + */ + void fakeKeyEvent(WORD virtualKey, WORD scanCode, DWORD flags, + bool isAutoRepeat) const; - //! Fake mouse press/release - /*! - Synthesize a press or release of mouse button \c id. - */ - void fakeMouseButton(ButtonID id, bool press); + //! Fake mouse press/release + /*! + Synthesize a press or release of mouse button \c id. + */ + void fakeMouseButton(ButtonID id, bool press); - //! Fake mouse move - /*! - Synthesize a mouse move to the absolute coordinates \c x,y. - */ - void fakeMouseMove(SInt32 x, SInt32 y) const; + //! Fake mouse move + /*! + Synthesize a mouse move to the absolute coordinates \c x,y. + */ + void fakeMouseMove(SInt32 x, SInt32 y) const; - //! Fake mouse move - /*! - Synthesize a mouse move to the relative coordinates \c dx,dy. - */ - void fakeMouseRelativeMove(SInt32 dx, SInt32 dy) const; + //! Fake mouse move + /*! + Synthesize a mouse move to the relative coordinates \c dx,dy. + */ + void fakeMouseRelativeMove(SInt32 dx, SInt32 dy) const; - //! Fake mouse wheel - /*! - Synthesize a mouse wheel event of amount \c delta in direction \c axis. - */ - void fakeMouseWheel(SInt32 xDelta, SInt32 yDelta) const; + //! Fake mouse wheel + /*! + Synthesize a mouse wheel event of amount \c delta in direction \c axis. + */ + void fakeMouseWheel(SInt32 xDelta, SInt32 yDelta) const; - //@} + //@} private: - class Desk { - public: - String m_name; - Thread* m_thread; - DWORD m_threadID; - DWORD m_targetID; - HDESK m_desk; - HWND m_window; - HWND m_foregroundWindow; - bool m_lowLevel; - }; - typedef std::map Desks; + class Desk { + public: + String m_name; + Thread *m_thread; + DWORD m_threadID; + DWORD m_targetID; + HDESK m_desk; + HWND m_window; + HWND m_foregroundWindow; + bool m_lowLevel; + }; + typedef std::map Desks; - // initialization and shutdown operations - HCURSOR createBlankCursor() const; - void destroyCursor(HCURSOR cursor) const; - ATOM createDeskWindowClass(bool isPrimary) const; - void destroyClass(ATOM windowClass) const; - HWND createWindow(ATOM windowClass, const char* name) const; - void destroyWindow(HWND) const; + // initialization and shutdown operations + HCURSOR createBlankCursor() const; + void destroyCursor(HCURSOR cursor) const; + ATOM createDeskWindowClass(bool isPrimary) const; + void destroyClass(ATOM windowClass) const; + HWND createWindow(ATOM windowClass, const char *name) const; + void destroyWindow(HWND) const; - // message handlers - void deskMouseMove(SInt32 x, SInt32 y) const; - void deskMouseRelativeMove(SInt32 dx, SInt32 dy) const; - void deskEnter(Desk* desk); - void deskLeave(Desk* desk, HKL keyLayout); - void deskThread(void* vdesk); + // message handlers + void deskMouseMove(SInt32 x, SInt32 y) const; + void deskMouseRelativeMove(SInt32 dx, SInt32 dy) const; + void deskEnter(Desk *desk); + void deskLeave(Desk *desk, HKL keyLayout); + void deskThread(void *vdesk); - // desk switch checking and handling - Desk* addDesk(const String& name, HDESK hdesk); - void removeDesks(); - void checkDesk(); - bool isDeskAccessible(const Desk* desk) const; - void handleCheckDesk(const Event& event, void*); + // desk switch checking and handling + Desk *addDesk(const String &name, HDESK hdesk); + void removeDesks(); + void checkDesk(); + bool isDeskAccessible(const Desk *desk) const; + void handleCheckDesk(const Event &event, void *); - // communication with desk threads - void waitForDesk() const; - void sendMessage(UINT, WPARAM, LPARAM) const; + // communication with desk threads + void waitForDesk() const; + void sendMessage(UINT, WPARAM, LPARAM) const; - // work around for messed up keyboard events from low-level hooks - HWND getForegroundWindow() const; + // work around for messed up keyboard events from low-level hooks + HWND getForegroundWindow() const; - // desk API wrappers - HDESK openInputDesktop(); - void closeDesktop(HDESK); - String getDesktopName(HDESK); + // desk API wrappers + HDESK openInputDesktop(); + void closeDesktop(HDESK); + String getDesktopName(HDESK); - // our desk window procs - static LRESULT CALLBACK primaryDeskProc(HWND, UINT, WPARAM, LPARAM); - static LRESULT CALLBACK secondaryDeskProc(HWND, UINT, WPARAM, LPARAM); + // our desk window procs + static LRESULT CALLBACK primaryDeskProc(HWND, UINT, WPARAM, LPARAM); + static LRESULT CALLBACK secondaryDeskProc(HWND, UINT, WPARAM, LPARAM); private: - // true if screen is being used as a primary screen, false otherwise - bool m_isPrimary; + // true if screen is being used as a primary screen, false otherwise + bool m_isPrimary; - // true if hooks are not to be installed (useful for debugging) - bool m_noHooks; + // true if hooks are not to be installed (useful for debugging) + bool m_noHooks; - // true if mouse has entered the screen - bool m_isOnScreen; + // true if mouse has entered the screen + bool m_isOnScreen; - // our resources - ATOM m_deskClass; - HCURSOR m_cursor; + // our resources + ATOM m_deskClass; + HCURSOR m_cursor; - // screen shape stuff - SInt32 m_x, m_y; - SInt32 m_w, m_h; - SInt32 m_xCenter, m_yCenter; + // screen shape stuff + SInt32 m_x, m_y; + SInt32 m_w, m_h; + SInt32 m_xCenter, m_yCenter; - // true if system appears to have multiple monitors - bool m_multimon; + // true if system appears to have multiple monitors + bool m_multimon; - // the timer used to check for desktop switching - EventQueueTimer* m_timer; + // the timer used to check for desktop switching + EventQueueTimer *m_timer; - // screen saver stuff - DWORD m_threadID; - const IScreenSaver* m_screensaver; - bool m_screensaverNotify; + // screen saver stuff + DWORD m_threadID; + const IScreenSaver *m_screensaver; + bool m_screensaverNotify; - // the current desk and it's name - Desk* m_activeDesk; - String m_activeDeskName; + // the current desk and it's name + Desk *m_activeDesk; + String m_activeDeskName; - // one desk per desktop and a cond var to communicate with it - Mutex m_mutex; - CondVar m_deskReady; - Desks m_desks; + // one desk per desktop and a cond var to communicate with it + Mutex m_mutex; + CondVar m_deskReady; + Desks m_desks; - // keyboard stuff - IJob* m_updateKeys; - HKL m_keyLayout; + // keyboard stuff + IJob *m_updateKeys; + HKL m_keyLayout; - // options - bool m_leaveForegroundOption; + // options + bool m_leaveForegroundOption; - IEventQueue* m_events; + IEventQueue *m_events; - // true if program should stop on desk switch. - bool m_stopOnDeskSwitch; + // true if program should stop on desk switch. + bool m_stopOnDeskSwitch; }; diff --git a/src/lib/platform/MSWindowsDropTarget.cpp b/src/lib/platform/MSWindowsDropTarget.cpp index 3c9f7ccdf..bcae720d2 100644 --- a/src/lib/platform/MSWindowsDropTarget.cpp +++ b/src/lib/platform/MSWindowsDropTarget.cpp @@ -1,11 +1,11 @@ /* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2014-2016 Symless Ltd. - * + * * 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 LICENSE 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 @@ -20,159 +20,129 @@ #include "base/Log.h" #include "common/common.h" -#include #include +#include void getDropData(IDataObject *pDataObject); -MSWindowsDropTarget* MSWindowsDropTarget::s_instance = NULL; +MSWindowsDropTarget *MSWindowsDropTarget::s_instance = NULL; -MSWindowsDropTarget::MSWindowsDropTarget() : - m_refCount(1), - m_allowDrop(false) -{ - s_instance = this; +MSWindowsDropTarget::MSWindowsDropTarget() : m_refCount(1), m_allowDrop(false) { + s_instance = this; } -MSWindowsDropTarget::~MSWindowsDropTarget() -{ -} +MSWindowsDropTarget::~MSWindowsDropTarget() {} -MSWindowsDropTarget& -MSWindowsDropTarget::instance() -{ - assert(s_instance != NULL); - return *s_instance; +MSWindowsDropTarget &MSWindowsDropTarget::instance() { + assert(s_instance != NULL); + return *s_instance; } HRESULT -MSWindowsDropTarget::DragEnter(IDataObject* dataObject, DWORD keyState, POINTL point, DWORD* effect) -{ - // check if data object contain drop - m_allowDrop = queryDataObject(dataObject); - if (m_allowDrop) { - getDropData(dataObject); - } - - *effect = DROPEFFECT_NONE; +MSWindowsDropTarget::DragEnter(IDataObject *dataObject, DWORD keyState, + POINTL point, DWORD *effect) { + // check if data object contain drop + m_allowDrop = queryDataObject(dataObject); + if (m_allowDrop) { + getDropData(dataObject); + } - return S_OK; + *effect = DROPEFFECT_NONE; + + return S_OK; } HRESULT -MSWindowsDropTarget::DragOver(DWORD keyState, POINTL point, DWORD* effect) -{ - *effect = DROPEFFECT_NONE; +MSWindowsDropTarget::DragOver(DWORD keyState, POINTL point, DWORD *effect) { + *effect = DROPEFFECT_NONE; - return S_OK; + return S_OK; } HRESULT -MSWindowsDropTarget::DragLeave(void) -{ - return S_OK; -} +MSWindowsDropTarget::DragLeave(void) { return S_OK; } HRESULT -MSWindowsDropTarget::Drop(IDataObject* dataObject, DWORD keyState, POINTL point, DWORD* effect) -{ - *effect = DROPEFFECT_NONE; +MSWindowsDropTarget::Drop(IDataObject *dataObject, DWORD keyState, POINTL point, + DWORD *effect) { + *effect = DROPEFFECT_NONE; + return S_OK; +} + +bool MSWindowsDropTarget::queryDataObject(IDataObject *dataObject) { + // check if it supports CF_HDROP using a HGLOBAL + FORMATETC fmtetc = {CF_HDROP, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; + + return dataObject->QueryGetData(&fmtetc) == S_OK ? true : false; +} + +void MSWindowsDropTarget::setDraggingFilename(char *const filename) { + m_dragFilename = filename; +} + +std::string MSWindowsDropTarget::getDraggingFilename() { + return m_dragFilename; +} + +void MSWindowsDropTarget::clearDraggingFilename() { m_dragFilename.clear(); } + +void getDropData(IDataObject *dataObject) { + // construct a FORMATETC object + FORMATETC fmtEtc = {CF_HDROP, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; + STGMEDIUM stgMed; + + // See if the dataobject contains any DROP stored as a HGLOBAL + if (dataObject->QueryGetData(&fmtEtc) == S_OK) { + if (dataObject->GetData(&fmtEtc, &stgMed) == S_OK) { + // get data here + PVOID data = GlobalLock(stgMed.hGlobal); + + // data object global handler contains: + // DROPFILESfilename1 filename2 two spaces as the end + // TODO: get multiple filenames + wchar_t *wcData = (wchar_t *)((LPBYTE)data + sizeof(DROPFILES)); + + // convert wchar to char + char *filename = new char[wcslen(wcData) + 1]; + filename[wcslen(wcData)] = '\0'; + wcstombs(filename, wcData, wcslen(wcData)); + + MSWindowsDropTarget::instance().setDraggingFilename(filename); + + GlobalUnlock(stgMed.hGlobal); + + // release the data using the COM API + ReleaseStgMedium(&stgMed); + + delete[] filename; + } + } +} + +HRESULT __stdcall MSWindowsDropTarget::QueryInterface(REFIID iid, + void **object) { + if (iid == IID_IDropTarget || iid == IID_IUnknown) { + AddRef(); + *object = this; return S_OK; + } else { + *object = 0; + return E_NOINTERFACE; + } } -bool -MSWindowsDropTarget::queryDataObject(IDataObject* dataObject) -{ - // check if it supports CF_HDROP using a HGLOBAL - FORMATETC fmtetc = { CF_HDROP, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; - - return dataObject->QueryGetData(&fmtetc) == S_OK ? true : false; +ULONG __stdcall MSWindowsDropTarget::AddRef(void) { + return InterlockedIncrement(&m_refCount); } -void -MSWindowsDropTarget::setDraggingFilename(char* const filename) -{ - m_dragFilename = filename; -} - -std::string -MSWindowsDropTarget::getDraggingFilename() -{ - return m_dragFilename; -} - -void -MSWindowsDropTarget::clearDraggingFilename() -{ - m_dragFilename.clear(); -} - -void -getDropData(IDataObject* dataObject) -{ - // construct a FORMATETC object - FORMATETC fmtEtc = { CF_HDROP, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; - STGMEDIUM stgMed; - - // See if the dataobject contains any DROP stored as a HGLOBAL - if (dataObject->QueryGetData(&fmtEtc) == S_OK) { - if (dataObject->GetData(&fmtEtc, &stgMed) == S_OK) { - // get data here - PVOID data = GlobalLock(stgMed.hGlobal); - - // data object global handler contains: - // DROPFILESfilename1 filename2 two spaces as the end - // TODO: get multiple filenames - wchar_t* wcData = (wchar_t*)((LPBYTE)data + sizeof(DROPFILES)); - - // convert wchar to char - char* filename = new char[wcslen(wcData) + 1]; - filename[wcslen(wcData)] = '\0'; - wcstombs(filename, wcData, wcslen(wcData)); - - MSWindowsDropTarget::instance().setDraggingFilename(filename); - - GlobalUnlock(stgMed.hGlobal); - - // release the data using the COM API - ReleaseStgMedium(&stgMed); - - delete[] filename; - } - } -} - -HRESULT __stdcall -MSWindowsDropTarget::QueryInterface (REFIID iid, void ** object) -{ - if (iid == IID_IDropTarget || iid == IID_IUnknown) { - AddRef(); - *object = this; - return S_OK; - } - else { - *object = 0; - return E_NOINTERFACE; - } -} - -ULONG __stdcall -MSWindowsDropTarget::AddRef(void) -{ - return InterlockedIncrement(&m_refCount); -} - -ULONG __stdcall -MSWindowsDropTarget::Release(void) -{ - LONG count = InterlockedDecrement(&m_refCount); - - if (count == 0) { - delete this; - return 0; - } - else { - return count; - } +ULONG __stdcall MSWindowsDropTarget::Release(void) { + LONG count = InterlockedDecrement(&m_refCount); + + if (count == 0) { + delete this; + return 0; + } else { + return count; + } } diff --git a/src/lib/platform/MSWindowsDropTarget.h b/src/lib/platform/MSWindowsDropTarget.h index cf60480a9..12b1cb9f9 100644 --- a/src/lib/platform/MSWindowsDropTarget.h +++ b/src/lib/platform/MSWindowsDropTarget.h @@ -1,11 +1,11 @@ /* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2014-2016 Symless Ltd. - * + * * 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 LICENSE 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 @@ -26,34 +26,34 @@ class MSWindowsScreen; class MSWindowsDropTarget : public IDropTarget { public: - MSWindowsDropTarget(); - ~MSWindowsDropTarget(); + MSWindowsDropTarget(); + ~MSWindowsDropTarget(); - // IUnknown implementation - HRESULT __stdcall QueryInterface(REFIID iid, void** object); - ULONG __stdcall AddRef(void); - ULONG __stdcall Release(void); + // IUnknown implementation + HRESULT __stdcall QueryInterface(REFIID iid, void **object); + ULONG __stdcall AddRef(void); + ULONG __stdcall Release(void); - // IDropTarget implementation - HRESULT __stdcall DragEnter(IDataObject* dataObject, DWORD keyState, POINTL point, DWORD* effect); - HRESULT __stdcall DragOver(DWORD keyState, POINTL point, DWORD* effect); - HRESULT __stdcall DragLeave(void); - HRESULT __stdcall Drop(IDataObject* dataObject, DWORD keyState, POINTL point, DWORD* effect); + // IDropTarget implementation + HRESULT __stdcall DragEnter(IDataObject *dataObject, DWORD keyState, + POINTL point, DWORD *effect); + HRESULT __stdcall DragOver(DWORD keyState, POINTL point, DWORD *effect); + HRESULT __stdcall DragLeave(void); + HRESULT __stdcall Drop(IDataObject *dataObject, DWORD keyState, POINTL point, + DWORD *effect); - void setDraggingFilename(char* const); - std::string getDraggingFilename(); - void clearDraggingFilename(); + void setDraggingFilename(char *const); + std::string getDraggingFilename(); + void clearDraggingFilename(); - static MSWindowsDropTarget& - instance(); + static MSWindowsDropTarget &instance(); private: - bool queryDataObject(IDataObject* dataObject); + bool queryDataObject(IDataObject *dataObject); - long m_refCount; - bool m_allowDrop; - std::string m_dragFilename; - - static MSWindowsDropTarget* - s_instance; + long m_refCount; + bool m_allowDrop; + std::string m_dragFilename; + + static MSWindowsDropTarget *s_instance; }; diff --git a/src/lib/platform/MSWindowsEventQueueBuffer.cpp b/src/lib/platform/MSWindowsEventQueueBuffer.cpp index 8cc70a82e..9c90506f6 100644 --- a/src/lib/platform/MSWindowsEventQueueBuffer.cpp +++ b/src/lib/platform/MSWindowsEventQueueBuffer.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 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 LICENSE 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 @@ -19,128 +19,108 @@ #include "platform/MSWindowsEventQueueBuffer.h" #include "arch/win32/ArchMiscWindows.h" -#include "mt/Thread.h" #include "base/IEventQueue.h" +#include "mt/Thread.h" // // EventQueueTimer // -class EventQueueTimer { }; - +class EventQueueTimer {}; // // MSWindowsEventQueueBuffer // -MSWindowsEventQueueBuffer::MSWindowsEventQueueBuffer(IEventQueue* events) : - m_events(events) -{ - // remember thread. we'll be posting messages to it. - m_thread = GetCurrentThreadId(); +MSWindowsEventQueueBuffer::MSWindowsEventQueueBuffer(IEventQueue *events) + : m_events(events) { + // remember thread. we'll be posting messages to it. + m_thread = GetCurrentThreadId(); - // create a message type for custom events - m_userEvent = RegisterWindowMessage("SYNERGY_USER_EVENT"); + // create a message type for custom events + m_userEvent = RegisterWindowMessage("SYNERGY_USER_EVENT"); - // get message type for daemon quit - m_daemonQuit = ArchMiscWindows::getDaemonQuitMessage(); + // get message type for daemon quit + m_daemonQuit = ArchMiscWindows::getDaemonQuitMessage(); - // make sure this thread has a message queue - MSG dummy; - PeekMessage(&dummy, NULL, WM_USER, WM_USER, PM_NOREMOVE); + // make sure this thread has a message queue + MSG dummy; + PeekMessage(&dummy, NULL, WM_USER, WM_USER, PM_NOREMOVE); } -MSWindowsEventQueueBuffer::~MSWindowsEventQueueBuffer() -{ - // do nothing +MSWindowsEventQueueBuffer::~MSWindowsEventQueueBuffer() { + // do nothing } -void -MSWindowsEventQueueBuffer::waitForEvent(double timeout) -{ - // check if messages are available first. if we don't do this then - // MsgWaitForMultipleObjects() will block even if the queue isn't - // empty if the messages in the queue were there before the last - // call to GetMessage()/PeekMessage(). - if (HIWORD(GetQueueStatus(QS_ALLPOSTMESSAGE)) != 0) { - return; - } +void MSWindowsEventQueueBuffer::waitForEvent(double timeout) { + // check if messages are available first. if we don't do this then + // MsgWaitForMultipleObjects() will block even if the queue isn't + // empty if the messages in the queue were there before the last + // call to GetMessage()/PeekMessage(). + if (HIWORD(GetQueueStatus(QS_ALLPOSTMESSAGE)) != 0) { + return; + } - // convert timeout - DWORD t; - if (timeout < 0.0) { - t = INFINITE; - } - else { - t = (DWORD)(1000.0 * timeout); - } + // convert timeout + DWORD t; + if (timeout < 0.0) { + t = INFINITE; + } else { + t = (DWORD)(1000.0 * timeout); + } - // wait for a message. we cannot be interrupted by thread - // cancellation but that's okay because we're run in the main - // thread and we never cancel that thread. - HANDLE dummy[1]; - MsgWaitForMultipleObjects(0, dummy, FALSE, t, QS_ALLPOSTMESSAGE); + // wait for a message. we cannot be interrupted by thread + // cancellation but that's okay because we're run in the main + // thread and we never cancel that thread. + HANDLE dummy[1]; + MsgWaitForMultipleObjects(0, dummy, FALSE, t, QS_ALLPOSTMESSAGE); } -IEventQueueBuffer::Type -MSWindowsEventQueueBuffer::getEvent(Event& event, UInt32& dataID) -{ - // NOTE: QS_ALLINPUT was replaced with QS_ALLPOSTMESSAGE. - // - // peek at messages first. waiting for QS_ALLINPUT will return - // if a message has been sent to our window but GetMessage will - // dispatch that message behind our backs and block. PeekMessage - // will also dispatch behind our backs but won't block. - if (!PeekMessage(&m_event, NULL, 0, 0, PM_NOREMOVE) && - !PeekMessage(&m_event, (HWND)-1, 0, 0, PM_NOREMOVE)) { - return kNone; - } +IEventQueueBuffer::Type MSWindowsEventQueueBuffer::getEvent(Event &event, + UInt32 &dataID) { + // NOTE: QS_ALLINPUT was replaced with QS_ALLPOSTMESSAGE. + // + // peek at messages first. waiting for QS_ALLINPUT will return + // if a message has been sent to our window but GetMessage will + // dispatch that message behind our backs and block. PeekMessage + // will also dispatch behind our backs but won't block. + if (!PeekMessage(&m_event, NULL, 0, 0, PM_NOREMOVE) && + !PeekMessage(&m_event, (HWND)-1, 0, 0, PM_NOREMOVE)) { + return kNone; + } - // BOOL. yeah, right. - BOOL result = GetMessage(&m_event, NULL, 0, 0); - if (result == -1) { - return kNone; - } - else if (result == 0) { - event = Event(Event::kQuit); - return kSystem; - } - else if (m_daemonQuit != 0 && m_event.message == m_daemonQuit) { - event = Event(Event::kQuit); - return kSystem; - } - else if (m_event.message == m_userEvent) { - dataID = static_cast(m_event.wParam); - return kUser; - } - else { - event = Event(Event::kSystem, - m_events->getSystemTarget(), &m_event); - return kSystem; - } + // BOOL. yeah, right. + BOOL result = GetMessage(&m_event, NULL, 0, 0); + if (result == -1) { + return kNone; + } else if (result == 0) { + event = Event(Event::kQuit); + return kSystem; + } else if (m_daemonQuit != 0 && m_event.message == m_daemonQuit) { + event = Event(Event::kQuit); + return kSystem; + } else if (m_event.message == m_userEvent) { + dataID = static_cast(m_event.wParam); + return kUser; + } else { + event = Event(Event::kSystem, m_events->getSystemTarget(), &m_event); + return kSystem; + } } -bool -MSWindowsEventQueueBuffer::addEvent(UInt32 dataID) -{ - return (PostThreadMessage(m_thread, m_userEvent, - static_cast(dataID), 0) != 0); +bool MSWindowsEventQueueBuffer::addEvent(UInt32 dataID) { + return (PostThreadMessage(m_thread, m_userEvent, static_cast(dataID), + 0) != 0); } -bool -MSWindowsEventQueueBuffer::isEmpty() const -{ - return (HIWORD(GetQueueStatus(QS_ALLPOSTMESSAGE)) == 0); +bool MSWindowsEventQueueBuffer::isEmpty() const { + return (HIWORD(GetQueueStatus(QS_ALLPOSTMESSAGE)) == 0); } -EventQueueTimer* -MSWindowsEventQueueBuffer::newTimer(double, bool) const -{ - return new EventQueueTimer; +EventQueueTimer *MSWindowsEventQueueBuffer::newTimer(double, bool) const { + return new EventQueueTimer; } -void -MSWindowsEventQueueBuffer::deleteTimer(EventQueueTimer* timer) const -{ - delete timer; +void MSWindowsEventQueueBuffer::deleteTimer(EventQueueTimer *timer) const { + delete timer; } diff --git a/src/lib/platform/MSWindowsEventQueueBuffer.h b/src/lib/platform/MSWindowsEventQueueBuffer.h index 872684e43..e87c81271 100644 --- a/src/lib/platform/MSWindowsEventQueueBuffer.h +++ b/src/lib/platform/MSWindowsEventQueueBuffer.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 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 LICENSE 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 @@ -28,23 +28,22 @@ class IEventQueue; //! Event queue buffer for Win32 class MSWindowsEventQueueBuffer : public IEventQueueBuffer { public: - MSWindowsEventQueueBuffer(IEventQueue* events); - virtual ~MSWindowsEventQueueBuffer(); + MSWindowsEventQueueBuffer(IEventQueue *events); + virtual ~MSWindowsEventQueueBuffer(); - // IEventQueueBuffer overrides - virtual void init() { } - virtual void waitForEvent(double timeout); - virtual Type getEvent(Event& event, UInt32& dataID); - virtual bool addEvent(UInt32 dataID); - virtual bool isEmpty() const; - virtual EventQueueTimer* - newTimer(double duration, bool oneShot) const; - virtual void deleteTimer(EventQueueTimer*) const; + // IEventQueueBuffer overrides + virtual void init() {} + virtual void waitForEvent(double timeout); + virtual Type getEvent(Event &event, UInt32 &dataID); + virtual bool addEvent(UInt32 dataID); + virtual bool isEmpty() const; + virtual EventQueueTimer *newTimer(double duration, bool oneShot) const; + virtual void deleteTimer(EventQueueTimer *) const; private: - DWORD m_thread; - UINT m_userEvent; - MSG m_event; - UINT m_daemonQuit; - IEventQueue* m_events; + DWORD m_thread; + UINT m_userEvent; + MSG m_event; + UINT m_daemonQuit; + IEventQueue *m_events; }; diff --git a/src/lib/platform/MSWindowsHook.cpp b/src/lib/platform/MSWindowsHook.cpp index bde7d9ad4..da5181528 100644 --- a/src/lib/platform/MSWindowsHook.cpp +++ b/src/lib/platform/MSWindowsHook.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2011 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 LICENSE 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 @@ -17,487 +17,454 @@ */ #include "platform/MSWindowsHook.h" -#include "synergy/protocol_types.h" -#include "synergy/XScreen.h" #include "base/Log.h" +#include "synergy/XScreen.h" +#include "synergy/protocol_types.h" -static const char* g_name = "synwinhk"; +static const char *g_name = "synwinhk"; -static DWORD g_processID = 0; -static DWORD g_threadID = 0; -static HHOOK g_getMessage = NULL; -static HHOOK g_keyboardLL = NULL; -static HHOOK g_mouseLL = NULL; -static bool g_screenSaver = false; -static EHookMode g_mode = kHOOK_DISABLE; -static UInt32 g_zoneSides = 0; -static SInt32 g_zoneSize = 0; -static SInt32 g_xScreen = 0; -static SInt32 g_yScreen = 0; -static SInt32 g_wScreen = 0; -static SInt32 g_hScreen = 0; -static WPARAM g_deadVirtKey = 0; -static WPARAM g_deadRelease = 0; -static LPARAM g_deadLParam = 0; -static BYTE g_deadKeyState[256] = { 0 }; -static BYTE g_keyState[256] = { 0 }; -static DWORD g_hookThread = 0; -static bool g_fakeServerInput = false; -static BOOL g_isPrimary = TRUE; +static DWORD g_processID = 0; +static DWORD g_threadID = 0; +static HHOOK g_getMessage = NULL; +static HHOOK g_keyboardLL = NULL; +static HHOOK g_mouseLL = NULL; +static bool g_screenSaver = false; +static EHookMode g_mode = kHOOK_DISABLE; +static UInt32 g_zoneSides = 0; +static SInt32 g_zoneSize = 0; +static SInt32 g_xScreen = 0; +static SInt32 g_yScreen = 0; +static SInt32 g_wScreen = 0; +static SInt32 g_hScreen = 0; +static WPARAM g_deadVirtKey = 0; +static WPARAM g_deadRelease = 0; +static LPARAM g_deadLParam = 0; +static BYTE g_deadKeyState[256] = {0}; +static BYTE g_keyState[256] = {0}; +static DWORD g_hookThread = 0; +static bool g_fakeServerInput = false; +static BOOL g_isPrimary = TRUE; -MSWindowsHook::MSWindowsHook() -{ +MSWindowsHook::MSWindowsHook() {} + +MSWindowsHook::~MSWindowsHook() { + cleanup(); + + if (g_processID == GetCurrentProcessId()) { + uninstall(); + uninstallScreenSaver(); + g_processID = 0; + } } -MSWindowsHook::~MSWindowsHook() -{ - cleanup(); +void MSWindowsHook::loadLibrary() { + if (g_processID == 0) { + g_processID = GetCurrentProcessId(); + } - if (g_processID == GetCurrentProcessId()) { - uninstall(); - uninstallScreenSaver(); - g_processID = 0; - } + // initialize library + if (init(GetCurrentThreadId()) == 0) { + LOG((CLOG_ERR "failed to init %s.dll, another program may be using it", + g_name)); + LOG((CLOG_INFO "restarting your computer may solve this error")); + throw XScreenOpenFailure(); + } } -void -MSWindowsHook::loadLibrary() -{ - if (g_processID == 0) { - g_processID = GetCurrentProcessId(); +int MSWindowsHook::init(DWORD threadID) { + // try to open process that last called init() to see if it's + // still running or if it died without cleaning up. + if (g_processID != 0 && g_processID != GetCurrentProcessId()) { + HANDLE process = OpenProcess(STANDARD_RIGHTS_REQUIRED, FALSE, g_processID); + if (process != NULL) { + // old process (probably) still exists so refuse to + // reinitialize this DLL (and thus steal it from the + // old process). + int result = CloseHandle(process); + if (result == false) { + return 0; + } } - // initialize library - if (init(GetCurrentThreadId()) == 0) { - LOG((CLOG_ERR "failed to init %s.dll, another program may be using it", g_name)); - LOG((CLOG_INFO "restarting your computer may solve this error")); - throw XScreenOpenFailure(); - } + // clean up after old process. the system should've already + // removed the hooks so we just need to reset our state. + g_processID = GetCurrentProcessId(); + g_threadID = 0; + g_getMessage = NULL; + g_keyboardLL = NULL; + g_mouseLL = NULL; + g_screenSaver = false; + } + + // save thread id. we'll post messages to this thread's + // message queue. + g_threadID = threadID; + + // set defaults + g_mode = kHOOK_DISABLE; + g_zoneSides = 0; + g_zoneSize = 0; + g_xScreen = 0; + g_yScreen = 0; + g_wScreen = 0; + g_hScreen = 0; + + return 1; } -int -MSWindowsHook::init(DWORD threadID) -{ - // try to open process that last called init() to see if it's - // still running or if it died without cleaning up. - if (g_processID != 0 && g_processID != GetCurrentProcessId()) { - HANDLE process = OpenProcess(STANDARD_RIGHTS_REQUIRED, - FALSE, g_processID); - if (process != NULL) { - // old process (probably) still exists so refuse to - // reinitialize this DLL (and thus steal it from the - // old process). - int result = CloseHandle(process); - if (result == false) { - return 0; - } - } +int MSWindowsHook::cleanup() { + if (g_processID == GetCurrentProcessId()) { + g_threadID = 0; + } - // clean up after old process. the system should've already - // removed the hooks so we just need to reset our state. - g_processID = GetCurrentProcessId(); - g_threadID = 0; - g_getMessage = NULL; - g_keyboardLL = NULL; - g_mouseLL = NULL; - g_screenSaver = false; - } - - // save thread id. we'll post messages to this thread's - // message queue. - g_threadID = threadID; - - // set defaults - g_mode = kHOOK_DISABLE; - g_zoneSides = 0; - g_zoneSize = 0; - g_xScreen = 0; - g_yScreen = 0; - g_wScreen = 0; - g_hScreen = 0; - - return 1; + return 1; } -int -MSWindowsHook::cleanup() -{ - if (g_processID == GetCurrentProcessId()) { - g_threadID = 0; - } +void MSWindowsHook::setSides(UInt32 sides) { g_zoneSides = sides; } - return 1; +void MSWindowsHook::setZone(SInt32 x, SInt32 y, SInt32 w, SInt32 h, + SInt32 jumpZoneSize) { + g_zoneSize = jumpZoneSize; + g_xScreen = x; + g_yScreen = y; + g_wScreen = w; + g_hScreen = h; } -void -MSWindowsHook::setSides(UInt32 sides) -{ - g_zoneSides = sides; +void MSWindowsHook::setMode(EHookMode mode) { + if (mode == g_mode) { + // no change + return; + } + g_mode = mode; } -void -MSWindowsHook::setZone(SInt32 x, SInt32 y, SInt32 w, SInt32 h, SInt32 jumpZoneSize) -{ - g_zoneSize = jumpZoneSize; - g_xScreen = x; - g_yScreen = y; - g_wScreen = w; - g_hScreen = h; -} +static void keyboardGetState(BYTE keys[256], DWORD vkCode, bool kf_up) { + // we have to use GetAsyncKeyState() rather than GetKeyState() because + // we don't pass through most keys so the event synchronous state + // doesn't get updated. we do that because certain modifier keys have + // side effects, like alt and the windows key. + if (vkCode < 0 || vkCode >= 256) { + return; + } -void -MSWindowsHook::setMode(EHookMode mode) -{ - if (mode == g_mode) { - // no change - return; - } - g_mode = mode; -} + // Keep track of key state on our own in case GetAsyncKeyState() fails + g_keyState[vkCode] = kf_up ? 0 : 0x80; + g_keyState[VK_SHIFT] = g_keyState[VK_LSHIFT] | g_keyState[VK_RSHIFT]; -static -void -keyboardGetState(BYTE keys[256], DWORD vkCode, bool kf_up) -{ - // we have to use GetAsyncKeyState() rather than GetKeyState() because - // we don't pass through most keys so the event synchronous state - // doesn't get updated. we do that because certain modifier keys have - // side effects, like alt and the windows key. - if (vkCode < 0 || vkCode >= 256) { - return; - } + SHORT key; + // Test whether GetAsyncKeyState() is being honest with us + key = GetAsyncKeyState(vkCode); - // Keep track of key state on our own in case GetAsyncKeyState() fails - g_keyState[vkCode] = kf_up ? 0 : 0x80; - g_keyState[VK_SHIFT] = g_keyState[VK_LSHIFT] | g_keyState[VK_RSHIFT]; + if (key & 0x80) { + // The only time we know for sure that GetAsyncKeyState() is working + // is when it tells us that the current key is down. + // In this case, update g_keyState to reflect what GetAsyncKeyState() + // is telling us, just in case we have gotten out of sync - SHORT key; - // Test whether GetAsyncKeyState() is being honest with us - key = GetAsyncKeyState(vkCode); - - if (key & 0x80) { - // The only time we know for sure that GetAsyncKeyState() is working - // is when it tells us that the current key is down. - // In this case, update g_keyState to reflect what GetAsyncKeyState() - // is telling us, just in case we have gotten out of sync - - for (int i = 0; i < 256; ++i) { - key = GetAsyncKeyState(i); - g_keyState[i] = (BYTE)((key < 0) ? 0x80u : 0); - } - } - - // copy g_keyState to keys for (int i = 0; i < 256; ++i) { - keys[i] = g_keyState[i]; + key = GetAsyncKeyState(i); + g_keyState[i] = (BYTE)((key < 0) ? 0x80u : 0); } + } - key = GetKeyState(VK_CAPITAL); - keys[VK_CAPITAL] = (BYTE)(((key < 0) ? 0x80 : 0) | (key & 1)); + // copy g_keyState to keys + for (int i = 0; i < 256; ++i) { + keys[i] = g_keyState[i]; + } + + key = GetKeyState(VK_CAPITAL); + keys[VK_CAPITAL] = (BYTE)(((key < 0) ? 0x80 : 0) | (key & 1)); } -static -WPARAM -makeKeyMsg(UINT virtKey, WCHAR wc, bool noAltGr) -{ - return MAKEWPARAM((WORD)wc, MAKEWORD(virtKey & 0xff, noAltGr ? 1 : 0)); +static WPARAM makeKeyMsg(UINT virtKey, WCHAR wc, bool noAltGr) { + return MAKEWPARAM((WORD)wc, MAKEWORD(virtKey & 0xff, noAltGr ? 1 : 0)); } -static -void setDeadKey(WCHAR wc[], int size, UINT flags) -{ - if (g_deadVirtKey != 0) { - auto virtualKey = static_cast(g_deadVirtKey); - auto scanCode = static_cast((g_deadLParam & 0x10ff0000u) >> 16); - if (ToUnicode(virtualKey, scanCode, g_deadKeyState, wc, size, flags) >= 2) { - // If ToUnicode returned >=2, it means that we accidentally removed - // a double dead key instead of restoring it. Thus, we call - // ToUnicode again with the same parameters to restore the - // internal dead key state. - ToUnicode(virtualKey, scanCode, g_deadKeyState, wc, size, flags); +static void setDeadKey(WCHAR wc[], int size, UINT flags) { + if (g_deadVirtKey != 0) { + auto virtualKey = static_cast(g_deadVirtKey); + auto scanCode = static_cast((g_deadLParam & 0x10ff0000u) >> 16); + if (ToUnicode(virtualKey, scanCode, g_deadKeyState, wc, size, flags) >= 2) { + // If ToUnicode returned >=2, it means that we accidentally removed + // a double dead key instead of restoring it. Thus, we call + // ToUnicode again with the same parameters to restore the + // internal dead key state. + ToUnicode(virtualKey, scanCode, g_deadKeyState, wc, size, flags); - // We need to keep track of this because g_deadVirtKey will be - // cleared later on; this would cause the dead key release to - // incorrectly restore the dead key state. - g_deadRelease = g_deadVirtKey; - } + // We need to keep track of this because g_deadVirtKey will be + // cleared later on; this would cause the dead key release to + // incorrectly restore the dead key state. + g_deadRelease = g_deadVirtKey; } + } } -static -bool -keyboardHookHandler(WPARAM wParam, LPARAM lParam) -{ - DWORD vkCode = static_cast(wParam); - bool kf_up = (lParam & (KF_UP << 16)) != 0; +static bool keyboardHookHandler(WPARAM wParam, LPARAM lParam) { + DWORD vkCode = static_cast(wParam); + bool kf_up = (lParam & (KF_UP << 16)) != 0; - // check for special events indicating if we should start or stop - // passing events through and not report them to the server. this - // is used to allow the server to synthesize events locally but - // not pick them up as user events. - if (wParam == SYNERGY_HOOK_FAKE_INPUT_VIRTUAL_KEY && - ((lParam >> 16) & 0xffu) == SYNERGY_HOOK_FAKE_INPUT_SCANCODE) { - // update flag - g_fakeServerInput = ((lParam & 0x80000000u) == 0); - PostThreadMessage(g_threadID, SYNERGY_MSG_DEBUG, - 0xff000000u | wParam, lParam); + // check for special events indicating if we should start or stop + // passing events through and not report them to the server. this + // is used to allow the server to synthesize events locally but + // not pick them up as user events. + if (wParam == SYNERGY_HOOK_FAKE_INPUT_VIRTUAL_KEY && + ((lParam >> 16) & 0xffu) == SYNERGY_HOOK_FAKE_INPUT_SCANCODE) { + // update flag + g_fakeServerInput = ((lParam & 0x80000000u) == 0); + PostThreadMessage(g_threadID, SYNERGY_MSG_DEBUG, 0xff000000u | wParam, + lParam); - // discard event - return true; + // discard event + return true; + } + + // if we're expecting fake input then just pass the event through + // and do not forward to the server + if (g_fakeServerInput) { + PostThreadMessage(g_threadID, SYNERGY_MSG_DEBUG, 0xfe000000u | wParam, + lParam); + return false; + } + + // VK_RSHIFT may be sent with an extended scan code but right shift + // is not an extended key so we reset that bit. + if (wParam == VK_RSHIFT) { + lParam &= ~0x01000000u; + } + + // tell server about event + PostThreadMessage(g_threadID, SYNERGY_MSG_DEBUG, wParam, lParam); + + // ignore dead key release + if ((g_deadVirtKey == wParam || g_deadRelease == wParam) && + (lParam & 0x80000000u) != 0) { + g_deadRelease = 0; + PostThreadMessage(g_threadID, SYNERGY_MSG_DEBUG, wParam | 0x04000000, + lParam); + return false; + } + + // we need the keyboard state for ToAscii() + BYTE keys[256]; + keyboardGetState(keys, vkCode, kf_up); + + // ToAscii() maps ctrl+letter to the corresponding control code + // and ctrl+backspace to delete. we don't want those translations + // so clear the control modifier state. however, if we want to + // simulate AltGr (which is ctrl+alt) then we must not clear it. + UINT control = keys[VK_CONTROL] | keys[VK_LCONTROL] | keys[VK_RCONTROL]; + UINT menu = keys[VK_MENU] | keys[VK_LMENU] | keys[VK_RMENU]; + if ((control & 0x80) == 0 || (menu & 0x80) == 0) { + keys[VK_LCONTROL] = 0; + keys[VK_RCONTROL] = 0; + keys[VK_CONTROL] = 0; + } else { + keys[VK_LCONTROL] = 0x80; + keys[VK_RCONTROL] = 0x80; + keys[VK_CONTROL] = 0x80; + keys[VK_LMENU] = 0x80; + keys[VK_RMENU] = 0x80; + keys[VK_MENU] = 0x80; + } + + // ToAscii() needs to know if a menu is active for some reason. + // we don't know and there doesn't appear to be any way to find + // out. so we'll just assume a menu is active if the menu key + // is down. + // FIXME -- figure out some way to check if a menu is active + UINT flags = 0; + if ((menu & 0x80) != 0) + flags |= 1; + + // if we're on the server screen then just pass numpad keys with alt + // key down as-is. we won't pick up the resulting character but the + // local app will. if on a client screen then grab keys as usual; + // if the client is a windows system it'll synthesize the expected + // character. if not then it'll probably just do nothing. + if (g_mode != kHOOK_RELAY_EVENTS) { + // we don't use virtual keys because we don't know what the + // state of the numlock key is. we'll hard code the scan codes + // instead. hopefully this works across all keyboards. + UINT sc = (lParam & 0x01ff0000u) >> 16; + if (menu && (sc >= 0x47u && sc <= 0x52u && sc != 0x4au && sc != 0x4eu)) { + return false; } + } - // if we're expecting fake input then just pass the event through - // and do not forward to the server - if (g_fakeServerInput) { - PostThreadMessage(g_threadID, SYNERGY_MSG_DEBUG, - 0xfe000000u | wParam, lParam); - return false; - } + // map the key event to a character. we have to put the dead + // key back first and this has the side effect of removing it. + WCHAR wc[] = {0, 0}; + setDeadKey(wc, 2, flags); - // VK_RSHIFT may be sent with an extended scan code but right shift - // is not an extended key so we reset that bit. - if (wParam == VK_RSHIFT) { - lParam &= ~0x01000000u; - } + UINT scanCode = ((lParam & 0x10ff0000u) >> 16); + int n = ToUnicode((UINT)wParam, scanCode, keys, wc, 2, flags); - // tell server about event - PostThreadMessage(g_threadID, SYNERGY_MSG_DEBUG, wParam, lParam); - - // ignore dead key release - if ((g_deadVirtKey == wParam || g_deadRelease == wParam) && - (lParam & 0x80000000u) != 0) { - g_deadRelease = 0; - PostThreadMessage(g_threadID, SYNERGY_MSG_DEBUG, - wParam | 0x04000000, lParam); - return false; - } - - // we need the keyboard state for ToAscii() - BYTE keys[256]; - keyboardGetState(keys, vkCode, kf_up); - - // ToAscii() maps ctrl+letter to the corresponding control code - // and ctrl+backspace to delete. we don't want those translations - // so clear the control modifier state. however, if we want to - // simulate AltGr (which is ctrl+alt) then we must not clear it. - UINT control = keys[VK_CONTROL] | keys[VK_LCONTROL] | keys[VK_RCONTROL]; - UINT menu = keys[VK_MENU] | keys[VK_LMENU] | keys[VK_RMENU]; - if ((control & 0x80) == 0 || (menu & 0x80) == 0) { - keys[VK_LCONTROL] = 0; - keys[VK_RCONTROL] = 0; - keys[VK_CONTROL] = 0; - } - else { - keys[VK_LCONTROL] = 0x80; - keys[VK_RCONTROL] = 0x80; - keys[VK_CONTROL] = 0x80; - keys[VK_LMENU] = 0x80; - keys[VK_RMENU] = 0x80; - keys[VK_MENU] = 0x80; - } - - // ToAscii() needs to know if a menu is active for some reason. - // we don't know and there doesn't appear to be any way to find - // out. so we'll just assume a menu is active if the menu key - // is down. - // FIXME -- figure out some way to check if a menu is active - UINT flags = 0; - if ((menu & 0x80) != 0) - flags |= 1; - - // if we're on the server screen then just pass numpad keys with alt - // key down as-is. we won't pick up the resulting character but the - // local app will. if on a client screen then grab keys as usual; - // if the client is a windows system it'll synthesize the expected - // character. if not then it'll probably just do nothing. - if (g_mode != kHOOK_RELAY_EVENTS) { - // we don't use virtual keys because we don't know what the - // state of the numlock key is. we'll hard code the scan codes - // instead. hopefully this works across all keyboards. - UINT sc = (lParam & 0x01ff0000u) >> 16; - if (menu && - (sc >= 0x47u && sc <= 0x52u && sc != 0x4au && sc != 0x4eu)) { - return false; - } - } - - // map the key event to a character. we have to put the dead - // key back first and this has the side effect of removing it. - WCHAR wc[] = {0, 0}; + // if mapping failed and ctrl and alt are pressed then try again + // with both not pressed. this handles the case where ctrl and + // alt are being used as individual modifiers rather than AltGr. + // we note that's the case in the message sent back to synergy + // because there's no simple way to deduce it after the fact. + // we have to put the dead key back first, if there was one. + bool noAltGr = false; + if (n == 0 && (control & 0x80) != 0 && (menu & 0x80) != 0) { + noAltGr = true; + PostThreadMessage(g_threadID, SYNERGY_MSG_DEBUG, wParam | 0x05000000, + lParam); setDeadKey(wc, 2, flags); - UINT scanCode = ((lParam & 0x10ff0000u) >> 16); - int n = ToUnicode((UINT)wParam, scanCode, keys, wc, 2, flags); - - // if mapping failed and ctrl and alt are pressed then try again - // with both not pressed. this handles the case where ctrl and - // alt are being used as individual modifiers rather than AltGr. - // we note that's the case in the message sent back to synergy - // because there's no simple way to deduce it after the fact. - // we have to put the dead key back first, if there was one. - bool noAltGr = false; - if (n == 0 && (control & 0x80) != 0 && (menu & 0x80) != 0) { - noAltGr = true; - PostThreadMessage(g_threadID, SYNERGY_MSG_DEBUG, wParam | 0x05000000, lParam); - setDeadKey(wc, 2, flags); - - BYTE keys2[256]; - for (size_t i = 0; i < sizeof(keys) / sizeof(keys[0]); ++i) { - keys2[i] = keys[i]; - } - keys2[VK_LCONTROL] = 0; - keys2[VK_RCONTROL] = 0; - keys2[VK_CONTROL] = 0; - keys2[VK_LMENU] = 0; - keys2[VK_RMENU] = 0; - keys2[VK_MENU] = 0; - n = ToUnicode((UINT)wParam, scanCode, keys2, wc, 2, flags); + BYTE keys2[256]; + for (size_t i = 0; i < sizeof(keys) / sizeof(keys[0]); ++i) { + keys2[i] = keys[i]; } + keys2[VK_LCONTROL] = 0; + keys2[VK_RCONTROL] = 0; + keys2[VK_CONTROL] = 0; + keys2[VK_LMENU] = 0; + keys2[VK_RMENU] = 0; + keys2[VK_MENU] = 0; + n = ToUnicode((UINT)wParam, scanCode, keys2, wc, 2, flags); + } + PostThreadMessage(g_threadID, SYNERGY_MSG_DEBUG, + (wc[0] & 0xffff) | ((wParam & 0xff) << 16) | + ((n & 0xf) << 24) | 0x60000000, + lParam); + WPARAM charAndVirtKey = 0; + bool clearDeadKey = false; + switch (n) { + default: + // key is a dead key + + if (lParam & 0x80000000u) + // This handles the obscure situation where a key has been + // pressed which is both a dead key and a normal character + // depending on which modifiers have been pressed. We + // break here to prevent it from being considered a dead + // key. + break; + + g_deadVirtKey = wParam; + g_deadLParam = lParam; + for (size_t i = 0; i < sizeof(keys) / sizeof(keys[0]); ++i) { + g_deadKeyState[i] = keys[i]; + } + break; + + case 0: + // key doesn't map to a character. this can happen if + // non-character keys are pressed after a dead key. + charAndVirtKey = makeKeyMsg((UINT)wParam, 0, noAltGr); + break; + + case 1: + // key maps to a character composed with dead key + charAndVirtKey = makeKeyMsg((UINT)wParam, wc[0], noAltGr); + clearDeadKey = true; + break; + + case 2: { + // previous dead key not composed. send a fake key press + // and release for the dead key to our window. + WPARAM deadCharAndVirtKey = makeKeyMsg((UINT)g_deadVirtKey, wc[0], noAltGr); + PostThreadMessage(g_threadID, SYNERGY_MSG_KEY, deadCharAndVirtKey, + g_deadLParam & 0x7fffffffu); + PostThreadMessage(g_threadID, SYNERGY_MSG_KEY, deadCharAndVirtKey, + g_deadLParam | 0x80000000u); + + // use uncomposed character + charAndVirtKey = makeKeyMsg((UINT)wParam, wc[1], noAltGr); + clearDeadKey = true; + break; + } + } + + // put back the dead key, if any, for the application to use + if (g_deadVirtKey != 0) { + ToUnicode((UINT)g_deadVirtKey, (g_deadLParam & 0x10ff0000u) >> 16, + g_deadKeyState, wc, 2, flags); + } + + // clear out old dead key state + if (clearDeadKey) { + g_deadVirtKey = 0; + g_deadLParam = 0; + } + + // forward message to our window. do this whether or not we're + // forwarding events to clients because this'll keep our thread's + // key state table up to date. that's important for querying + // the scroll lock toggle state. + // XXX -- with hot keys for actions we may only need to do this when + // forwarding. + if (charAndVirtKey != 0) { PostThreadMessage(g_threadID, SYNERGY_MSG_DEBUG, - (wc[0] & 0xffff) | ((wParam & 0xff) << 16) | - ((n & 0xf) << 24) | 0x60000000, - lParam); - WPARAM charAndVirtKey = 0; - bool clearDeadKey = false; - switch (n) { + charAndVirtKey | 0x07000000, lParam); + PostThreadMessage(g_threadID, SYNERGY_MSG_KEY, charAndVirtKey, lParam); + } + + if (g_mode == kHOOK_RELAY_EVENTS) { + // let certain keys pass through + switch (wParam) { + case VK_CAPITAL: + case VK_NUMLOCK: + case VK_SCROLL: + // pass event on. we want to let these through to + // the window proc because otherwise the keyboard + // lights may not stay synchronized. + break; + + case VK_HANGUL: + // pass these modifiers if using a low level hook, discard + // them if not. + if (g_hookThread == 0) { + return true; + } + break; + default: - // key is a dead key - - if (lParam & 0x80000000u) - // This handles the obscure situation where a key has been - // pressed which is both a dead key and a normal character - // depending on which modifiers have been pressed. We - // break here to prevent it from being considered a dead - // key. - break; - - g_deadVirtKey = wParam; - g_deadLParam = lParam; - for (size_t i = 0; i < sizeof(keys) / sizeof(keys[0]); ++i) { - g_deadKeyState[i] = keys[i]; - } - break; - - case 0: - // key doesn't map to a character. this can happen if - // non-character keys are pressed after a dead key. - charAndVirtKey = makeKeyMsg((UINT)wParam, 0, noAltGr); - break; - - case 1: - // key maps to a character composed with dead key - charAndVirtKey = makeKeyMsg((UINT)wParam, wc[0], noAltGr); - clearDeadKey = true; - break; - - case 2: { - // previous dead key not composed. send a fake key press - // and release for the dead key to our window. - WPARAM deadCharAndVirtKey = - makeKeyMsg((UINT)g_deadVirtKey, wc[0], noAltGr); - PostThreadMessage(g_threadID, SYNERGY_MSG_KEY, - deadCharAndVirtKey, g_deadLParam & 0x7fffffffu); - PostThreadMessage(g_threadID, SYNERGY_MSG_KEY, - deadCharAndVirtKey, g_deadLParam | 0x80000000u); - - // use uncomposed character - charAndVirtKey = makeKeyMsg((UINT)wParam, wc[1], noAltGr); - clearDeadKey = true; - break; - } + // discard + return true; } + } - // put back the dead key, if any, for the application to use - if (g_deadVirtKey != 0) { - ToUnicode((UINT)g_deadVirtKey, (g_deadLParam & 0x10ff0000u) >> 16, - g_deadKeyState, wc, 2, flags); - } - - // clear out old dead key state - if (clearDeadKey) { - g_deadVirtKey = 0; - g_deadLParam = 0; - } - - // forward message to our window. do this whether or not we're - // forwarding events to clients because this'll keep our thread's - // key state table up to date. that's important for querying - // the scroll lock toggle state. - // XXX -- with hot keys for actions we may only need to do this when - // forwarding. - if (charAndVirtKey != 0) { - PostThreadMessage(g_threadID, SYNERGY_MSG_DEBUG, - charAndVirtKey | 0x07000000, lParam); - PostThreadMessage(g_threadID, SYNERGY_MSG_KEY, charAndVirtKey, lParam); - } - - if (g_mode == kHOOK_RELAY_EVENTS) { - // let certain keys pass through - switch (wParam) { - case VK_CAPITAL: - case VK_NUMLOCK: - case VK_SCROLL: - // pass event on. we want to let these through to - // the window proc because otherwise the keyboard - // lights may not stay synchronized. - break; - - case VK_HANGUL: - // pass these modifiers if using a low level hook, discard - // them if not. - if (g_hookThread == 0) { - return true; - } - break; - - default: - // discard - return true; - } - } - - return false; + return false; } - #if !NO_GRAB_KEYBOARD -static -LRESULT CALLBACK -keyboardLLHook(int code, WPARAM wParam, LPARAM lParam) -{ - if (code >= 0) { - // decode the message - KBDLLHOOKSTRUCT* info = reinterpret_cast(lParam); +static LRESULT CALLBACK keyboardLLHook(int code, WPARAM wParam, LPARAM lParam) { + if (code >= 0) { + // decode the message + KBDLLHOOKSTRUCT *info = reinterpret_cast(lParam); - bool const injected = info->flags & LLKHF_INJECTED; - if (!g_isPrimary && injected) { - return CallNextHookEx (g_keyboardLL, code, wParam, lParam); - } - - WPARAM wParam = info->vkCode; - LPARAM lParam = 1; // repeat code - lParam |= (info->scanCode << 16); // scan code - if (info->flags & LLKHF_EXTENDED) { - lParam |= (1lu << 24); // extended key - } - if (info->flags & LLKHF_ALTDOWN) { - lParam |= (1lu << 29); // context code - } - if (info->flags & LLKHF_UP) { - lParam |= (1lu << 31); // transition - } - // FIXME -- bit 30 should be set if key was already down but - // we don't know that info. as a result we'll never generate - // key repeat events. - - // handle the message - if (keyboardHookHandler(wParam, lParam)) { - return 1; - } + bool const injected = info->flags & LLKHF_INJECTED; + if (!g_isPrimary && injected) { + return CallNextHookEx(g_keyboardLL, code, wParam, lParam); } - return CallNextHookEx(g_keyboardLL, code, wParam, lParam); + WPARAM wParam = info->vkCode; + LPARAM lParam = 1; // repeat code + lParam |= (info->scanCode << 16); // scan code + if (info->flags & LLKHF_EXTENDED) { + lParam |= (1lu << 24); // extended key + } + if (info->flags & LLKHF_ALTDOWN) { + lParam |= (1lu << 29); // context code + } + if (info->flags & LLKHF_UP) { + lParam |= (1lu << 31); // transition + } + // FIXME -- bit 30 should be set if key was already down but + // we don't know that info. as a result we'll never generate + // key repeat events. + + // handle the message + if (keyboardHookHandler(wParam, lParam)) { + return 1; + } + } + + return CallNextHookEx(g_keyboardLL, code, wParam, lParam); } #endif @@ -506,268 +473,236 @@ keyboardLLHook(int code, WPARAM wParam, LPARAM lParam) // events very early. the earlier the better. // -static -bool -mouseHookHandler(WPARAM wParam, SInt32 x, SInt32 y, SInt32 data) -{ - switch (wParam) { - case WM_LBUTTONDOWN: - case WM_MBUTTONDOWN: - case WM_RBUTTONDOWN: - case WM_XBUTTONDOWN: - case WM_LBUTTONDBLCLK: - case WM_MBUTTONDBLCLK: - case WM_RBUTTONDBLCLK: - case WM_XBUTTONDBLCLK: - case WM_LBUTTONUP: - case WM_MBUTTONUP: - case WM_RBUTTONUP: - case WM_XBUTTONUP: - case WM_NCLBUTTONDOWN: - case WM_NCMBUTTONDOWN: - case WM_NCRBUTTONDOWN: - case WM_NCXBUTTONDOWN: - case WM_NCLBUTTONDBLCLK: - case WM_NCMBUTTONDBLCLK: - case WM_NCRBUTTONDBLCLK: - case WM_NCXBUTTONDBLCLK: - case WM_NCLBUTTONUP: - case WM_NCMBUTTONUP: - case WM_NCRBUTTONUP: - case WM_NCXBUTTONUP: - // always relay the event. eat it if relaying. - PostThreadMessage(g_threadID, SYNERGY_MSG_MOUSE_BUTTON, wParam, data); - return (g_mode == kHOOK_RELAY_EVENTS); +static bool mouseHookHandler(WPARAM wParam, SInt32 x, SInt32 y, SInt32 data) { + switch (wParam) { + case WM_LBUTTONDOWN: + case WM_MBUTTONDOWN: + case WM_RBUTTONDOWN: + case WM_XBUTTONDOWN: + case WM_LBUTTONDBLCLK: + case WM_MBUTTONDBLCLK: + case WM_RBUTTONDBLCLK: + case WM_XBUTTONDBLCLK: + case WM_LBUTTONUP: + case WM_MBUTTONUP: + case WM_RBUTTONUP: + case WM_XBUTTONUP: + case WM_NCLBUTTONDOWN: + case WM_NCMBUTTONDOWN: + case WM_NCRBUTTONDOWN: + case WM_NCXBUTTONDOWN: + case WM_NCLBUTTONDBLCLK: + case WM_NCMBUTTONDBLCLK: + case WM_NCRBUTTONDBLCLK: + case WM_NCXBUTTONDBLCLK: + case WM_NCLBUTTONUP: + case WM_NCMBUTTONUP: + case WM_NCRBUTTONUP: + case WM_NCXBUTTONUP: + // always relay the event. eat it if relaying. + PostThreadMessage(g_threadID, SYNERGY_MSG_MOUSE_BUTTON, wParam, data); + return (g_mode == kHOOK_RELAY_EVENTS); - case WM_MOUSEWHEEL: - if (g_mode == kHOOK_RELAY_EVENTS) { - // relay event - PostThreadMessage(g_threadID, SYNERGY_MSG_MOUSE_WHEEL, data, 0); - } - return (g_mode == kHOOK_RELAY_EVENTS); - - case WM_NCMOUSEMOVE: - case WM_MOUSEMOVE: - if (g_mode == kHOOK_RELAY_EVENTS) { - // relay and eat event - PostThreadMessage(g_threadID, SYNERGY_MSG_MOUSE_MOVE, x, y); - return true; - } - else if (g_mode == kHOOK_WATCH_JUMP_ZONE) { - // low level hooks can report bogus mouse positions that are - // outside of the screen. jeez. naturally we end up getting - // fake motion in the other direction to get the position back - // on the screen, which plays havoc with switch on double tap. - // Server deals with that. we'll clamp positions onto the - // screen. also, if we discard events for positions outside - // of the screen then the mouse appears to get a bit jerky - // near the edge. we can either accept that or pass the bogus - // events. we'll try passing the events. - bool bogus = false; - if (x < g_xScreen) { - x = g_xScreen; - bogus = true; - } - else if (x >= g_xScreen + g_wScreen) { - x = g_xScreen + g_wScreen - 1; - bogus = true; - } - if (y < g_yScreen) { - y = g_yScreen; - bogus = true; - } - else if (y >= g_yScreen + g_hScreen) { - y = g_yScreen + g_hScreen - 1; - bogus = true; - } - - // check for mouse inside jump zone - bool inside = false; - if (!inside && (g_zoneSides & kLeftMask) != 0) { - inside = (x < g_xScreen + g_zoneSize); - } - if (!inside && (g_zoneSides & kRightMask) != 0) { - inside = (x >= g_xScreen + g_wScreen - g_zoneSize); - } - if (!inside && (g_zoneSides & kTopMask) != 0) { - inside = (y < g_yScreen + g_zoneSize); - } - if (!inside && (g_zoneSides & kBottomMask) != 0) { - inside = (y >= g_yScreen + g_hScreen - g_zoneSize); - } - - // relay the event - PostThreadMessage(g_threadID, SYNERGY_MSG_MOUSE_MOVE, x, y); - - // if inside and not bogus then eat the event - return inside && !bogus; - } + case WM_MOUSEWHEEL: + if (g_mode == kHOOK_RELAY_EVENTS) { + // relay event + PostThreadMessage(g_threadID, SYNERGY_MSG_MOUSE_WHEEL, data, 0); } + return (g_mode == kHOOK_RELAY_EVENTS); - // pass the event - return false; + case WM_NCMOUSEMOVE: + case WM_MOUSEMOVE: + if (g_mode == kHOOK_RELAY_EVENTS) { + // relay and eat event + PostThreadMessage(g_threadID, SYNERGY_MSG_MOUSE_MOVE, x, y); + return true; + } else if (g_mode == kHOOK_WATCH_JUMP_ZONE) { + // low level hooks can report bogus mouse positions that are + // outside of the screen. jeez. naturally we end up getting + // fake motion in the other direction to get the position back + // on the screen, which plays havoc with switch on double tap. + // Server deals with that. we'll clamp positions onto the + // screen. also, if we discard events for positions outside + // of the screen then the mouse appears to get a bit jerky + // near the edge. we can either accept that or pass the bogus + // events. we'll try passing the events. + bool bogus = false; + if (x < g_xScreen) { + x = g_xScreen; + bogus = true; + } else if (x >= g_xScreen + g_wScreen) { + x = g_xScreen + g_wScreen - 1; + bogus = true; + } + if (y < g_yScreen) { + y = g_yScreen; + bogus = true; + } else if (y >= g_yScreen + g_hScreen) { + y = g_yScreen + g_hScreen - 1; + bogus = true; + } + + // check for mouse inside jump zone + bool inside = false; + if (!inside && (g_zoneSides & kLeftMask) != 0) { + inside = (x < g_xScreen + g_zoneSize); + } + if (!inside && (g_zoneSides & kRightMask) != 0) { + inside = (x >= g_xScreen + g_wScreen - g_zoneSize); + } + if (!inside && (g_zoneSides & kTopMask) != 0) { + inside = (y < g_yScreen + g_zoneSize); + } + if (!inside && (g_zoneSides & kBottomMask) != 0) { + inside = (y >= g_yScreen + g_hScreen - g_zoneSize); + } + + // relay the event + PostThreadMessage(g_threadID, SYNERGY_MSG_MOUSE_MOVE, x, y); + + // if inside and not bogus then eat the event + return inside && !bogus; + } + } + + // pass the event + return false; } +static LRESULT CALLBACK mouseLLHook(int code, WPARAM wParam, LPARAM lParam) { + if (code >= 0) { + // decode the message + MSLLHOOKSTRUCT *info = reinterpret_cast(lParam); -static -LRESULT CALLBACK -mouseLLHook(int code, WPARAM wParam, LPARAM lParam) -{ - if (code >= 0) { - // decode the message - MSLLHOOKSTRUCT* info = reinterpret_cast(lParam); - - bool const injected = info->flags & LLMHF_INJECTED; - if (!g_isPrimary && injected) { - return CallNextHookEx(g_mouseLL, code, wParam, lParam); - } - - SInt32 x = static_cast(info->pt.x); - SInt32 y = static_cast(info->pt.y); - SInt32 w = static_cast(HIWORD(info->mouseData)); - - // handle the message - if (mouseHookHandler(wParam, x, y, w)) { - return 1; - } + bool const injected = info->flags & LLMHF_INJECTED; + if (!g_isPrimary && injected) { + return CallNextHookEx(g_mouseLL, code, wParam, lParam); } - return CallNextHookEx(g_mouseLL, code, wParam, lParam); + SInt32 x = static_cast(info->pt.x); + SInt32 y = static_cast(info->pt.y); + SInt32 w = static_cast(HIWORD(info->mouseData)); + + // handle the message + if (mouseHookHandler(wParam, x, y, w)) { + return 1; + } + } + + return CallNextHookEx(g_mouseLL, code, wParam, lParam); } -EHookResult -MSWindowsHook::install() -{ - assert(g_getMessage == NULL || g_screenSaver); +EHookResult MSWindowsHook::install() { + assert(g_getMessage == NULL || g_screenSaver); - // must be initialized - if (g_threadID == 0) { - return kHOOK_FAILED; - } + // must be initialized + if (g_threadID == 0) { + return kHOOK_FAILED; + } - // discard old dead keys - g_deadVirtKey = 0; - g_deadLParam = 0; + // discard old dead keys + g_deadVirtKey = 0; + g_deadLParam = 0; - // reset fake input flag - g_fakeServerInput = false; + // reset fake input flag + g_fakeServerInput = false; - // install low-level hooks. we require that they both get installed. - g_mouseLL = SetWindowsHookEx(WH_MOUSE_LL, - &mouseLLHook, - NULL, - 0); + // install low-level hooks. we require that they both get installed. + g_mouseLL = SetWindowsHookEx(WH_MOUSE_LL, &mouseLLHook, NULL, 0); #if !NO_GRAB_KEYBOARD - g_keyboardLL = SetWindowsHookEx(WH_KEYBOARD_LL, - &keyboardLLHook, - NULL, - 0); - if (g_mouseLL == NULL || g_keyboardLL == NULL) { - if (g_keyboardLL != NULL) { - UnhookWindowsHookEx(g_keyboardLL); - g_keyboardLL = NULL; - } - if (g_mouseLL != NULL) { - UnhookWindowsHookEx(g_mouseLL); - g_mouseLL = NULL; - } - } -#endif - - // check that we got all the hooks we wanted - if ((g_mouseLL == NULL) || -#if !NO_GRAB_KEYBOARD - (g_keyboardLL == NULL) -#endif - ) { - uninstall(); - return kHOOK_FAILED; - } - - if (g_keyboardLL != NULL || g_mouseLL != NULL) { - g_hookThread = GetCurrentThreadId(); - return kHOOK_OKAY_LL; - } - - return kHOOK_OKAY; -} - -int -MSWindowsHook::uninstall() -{ - // discard old dead keys - g_deadVirtKey = 0; - g_deadLParam = 0; - - // uninstall hooks + g_keyboardLL = SetWindowsHookEx(WH_KEYBOARD_LL, &keyboardLLHook, NULL, 0); + if (g_mouseLL == NULL || g_keyboardLL == NULL) { if (g_keyboardLL != NULL) { - UnhookWindowsHookEx(g_keyboardLL); - g_keyboardLL = NULL; + UnhookWindowsHookEx(g_keyboardLL); + g_keyboardLL = NULL; } if (g_mouseLL != NULL) { - UnhookWindowsHookEx(g_mouseLL); - g_mouseLL = NULL; - } - if (g_getMessage != NULL && !g_screenSaver) { - UnhookWindowsHookEx(g_getMessage); - g_getMessage = NULL; + UnhookWindowsHookEx(g_mouseLL); + g_mouseLL = NULL; } + } +#endif - return 1; + // check that we got all the hooks we wanted + if ((g_mouseLL == NULL) || +#if !NO_GRAB_KEYBOARD + (g_keyboardLL == NULL) +#endif + ) { + uninstall(); + return kHOOK_FAILED; + } + + if (g_keyboardLL != NULL || g_mouseLL != NULL) { + g_hookThread = GetCurrentThreadId(); + return kHOOK_OKAY_LL; + } + + return kHOOK_OKAY; } -static -LRESULT CALLBACK -getMessageHook(int code, WPARAM wParam, LPARAM lParam) -{ - if (code >= 0) { - if (g_screenSaver) { - MSG* msg = reinterpret_cast(lParam); - if (msg->message == WM_SYSCOMMAND && - msg->wParam == SC_SCREENSAVE) { - // broadcast screen saver started message - PostThreadMessage(g_threadID, - SYNERGY_MSG_SCREEN_SAVER, TRUE, 0); - } - } - } +int MSWindowsHook::uninstall() { + // discard old dead keys + g_deadVirtKey = 0; + g_deadLParam = 0; - return CallNextHookEx(g_getMessage, code, wParam, lParam); + // uninstall hooks + if (g_keyboardLL != NULL) { + UnhookWindowsHookEx(g_keyboardLL); + g_keyboardLL = NULL; + } + if (g_mouseLL != NULL) { + UnhookWindowsHookEx(g_mouseLL); + g_mouseLL = NULL; + } + if (g_getMessage != NULL && !g_screenSaver) { + UnhookWindowsHookEx(g_getMessage); + g_getMessage = NULL; + } + + return 1; } -int -MSWindowsHook::installScreenSaver() -{ - // must be initialized - if (g_threadID == 0) { - return 0; +static LRESULT CALLBACK getMessageHook(int code, WPARAM wParam, LPARAM lParam) { + if (code >= 0) { + if (g_screenSaver) { + MSG *msg = reinterpret_cast(lParam); + if (msg->message == WM_SYSCOMMAND && msg->wParam == SC_SCREENSAVE) { + // broadcast screen saver started message + PostThreadMessage(g_threadID, SYNERGY_MSG_SCREEN_SAVER, TRUE, 0); + } } + } - // generate screen saver messages - g_screenSaver = true; - - // install hook unless it's already installed - if (g_getMessage == NULL) { - g_getMessage = SetWindowsHookEx(WH_GETMESSAGE, - &getMessageHook, - NULL, - 0); - } - - return (g_getMessage != NULL) ? 1 : 0; + return CallNextHookEx(g_getMessage, code, wParam, lParam); } -int -MSWindowsHook::uninstallScreenSaver() -{ - // uninstall hook unless the mouse wheel hook is installed - if (g_getMessage != NULL) { - UnhookWindowsHookEx(g_getMessage); - g_getMessage = NULL; - } +int MSWindowsHook::installScreenSaver() { + // must be initialized + if (g_threadID == 0) { + return 0; + } - // screen saver hook is no longer installed - g_screenSaver = false; + // generate screen saver messages + g_screenSaver = true; - return 1; + // install hook unless it's already installed + if (g_getMessage == NULL) { + g_getMessage = SetWindowsHookEx(WH_GETMESSAGE, &getMessageHook, NULL, 0); + } + + return (g_getMessage != NULL) ? 1 : 0; +} + +int MSWindowsHook::uninstallScreenSaver() { + // uninstall hook unless the mouse wheel hook is installed + if (g_getMessage != NULL) { + UnhookWindowsHookEx(g_getMessage); + g_getMessage = NULL; + } + + // screen saver hook is no longer installed + g_screenSaver = false; + + return 1; } diff --git a/src/lib/platform/MSWindowsHook.h b/src/lib/platform/MSWindowsHook.h index cb61c6b10..36d1aa262 100644 --- a/src/lib/platform/MSWindowsHook.h +++ b/src/lib/platform/MSWindowsHook.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2011 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 LICENSE 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 @@ -24,29 +24,28 @@ #include //! Loads and provides functions for the Windows hook -class MSWindowsHook -{ +class MSWindowsHook { public: - MSWindowsHook(); - virtual ~MSWindowsHook(); + MSWindowsHook(); + virtual ~MSWindowsHook(); - void loadLibrary(); + void loadLibrary(); - int init(DWORD threadID); + int init(DWORD threadID); - int cleanup(); + int cleanup(); - void setSides(UInt32 sides); + void setSides(UInt32 sides); - void setZone(SInt32 x, SInt32 y, SInt32 w, SInt32 h, SInt32 jumpZoneSize); + void setZone(SInt32 x, SInt32 y, SInt32 w, SInt32 h, SInt32 jumpZoneSize); - void setMode(EHookMode mode); + void setMode(EHookMode mode); - static EHookResult install(); + static EHookResult install(); - static int uninstall(); + static int uninstall(); - static int installScreenSaver(); + static int installScreenSaver(); - static int uninstallScreenSaver(); + static int uninstallScreenSaver(); }; diff --git a/src/lib/platform/MSWindowsKeyState.cpp b/src/lib/platform/MSWindowsKeyState.cpp index f46bad239..36bf6e80d 100644 --- a/src/lib/platform/MSWindowsKeyState.cpp +++ b/src/lib/platform/MSWindowsKeyState.cpp @@ -18,19 +18,19 @@ #include "platform/MSWindowsKeyState.h" -#include "platform/MSWindowsDesks.h" -#include "mt/Thread.h" #include "arch/win32/ArchMiscWindows.h" #include "base/FunctionJob.h" +#include "base/IEventQueue.h" #include "base/Log.h" #include "base/String.h" -#include "base/IEventQueue.h" #include "base/TMethodEventJob.h" +#include "mt/Thread.h" +#include "platform/MSWindowsDesks.h" // extended mouse buttons #if !defined(VK_XBUTTON1) -#define VK_XBUTTON1 0x05 -#define VK_XBUTTON2 0x06 +#define VK_XBUTTON1 0x05 +#define VK_XBUTTON2 0x06 #endif // @@ -38,1372 +38,1286 @@ // // map virtual keys to synergy key enumeration -const KeyID MSWindowsKeyState::s_virtualKey[] = -{ - /* 0x000 */ { kKeyNone }, // reserved - /* 0x001 */ { kKeyNone }, // VK_LBUTTON - /* 0x002 */ { kKeyNone }, // VK_RBUTTON - /* 0x003 */ { kKeyNone }, // VK_CANCEL - /* 0x004 */ { kKeyNone }, // VK_MBUTTON - /* 0x005 */ { kKeyNone }, // VK_XBUTTON1 - /* 0x006 */ { kKeyNone }, // VK_XBUTTON2 - /* 0x007 */ { kKeyNone }, // undefined - /* 0x008 */ { kKeyBackSpace }, // VK_BACK - /* 0x009 */ { kKeyTab }, // VK_TAB - /* 0x00a */ { kKeyNone }, // undefined - /* 0x00b */ { kKeyNone }, // undefined - /* 0x00c */ { kKeyClear }, // VK_CLEAR - /* 0x00d */ { kKeyReturn }, // VK_RETURN - /* 0x00e */ { kKeyNone }, // undefined - /* 0x00f */ { kKeyNone }, // undefined - /* 0x010 */ { kKeyShift_L }, // VK_SHIFT - /* 0x011 */ { kKeyControl_L }, // VK_CONTROL - /* 0x012 */ { kKeyAlt_L }, // VK_MENU - /* 0x013 */ { kKeyPause }, // VK_PAUSE - /* 0x014 */ { kKeyCapsLock }, // VK_CAPITAL - /* 0x015 */ { kKeyKana }, // VK_HANGUL, VK_KANA - /* 0x016 */ { kKeyNone }, // undefined - /* 0x017 */ { kKeyNone }, // VK_JUNJA - /* 0x018 */ { kKeyNone }, // VK_FINAL - /* 0x019 */ { kKeyKanzi }, // VK_HANJA, VK_KANJI - /* 0x01a */ { kKeyNone }, // undefined - /* 0x01b */ { kKeyEscape }, // VK_ESCAPE - /* 0x01c */ { kKeyHenkan }, // VK_CONVERT - /* 0x01d */ { kKeyNone }, // VK_NONCONVERT - /* 0x01e */ { kKeyNone }, // VK_ACCEPT - /* 0x01f */ { kKeyNone }, // VK_MODECHANGE - /* 0x020 */ { kKeyNone }, // VK_SPACE - /* 0x021 */ { kKeyKP_PageUp }, // VK_PRIOR - /* 0x022 */ { kKeyKP_PageDown },// VK_NEXT - /* 0x023 */ { kKeyKP_End }, // VK_END - /* 0x024 */ { kKeyKP_Home }, // VK_HOME - /* 0x025 */ { kKeyKP_Left }, // VK_LEFT - /* 0x026 */ { kKeyKP_Up }, // VK_UP - /* 0x027 */ { kKeyKP_Right }, // VK_RIGHT - /* 0x028 */ { kKeyKP_Down }, // VK_DOWN - /* 0x029 */ { kKeySelect }, // VK_SELECT - /* 0x02a */ { kKeyNone }, // VK_PRINT - /* 0x02b */ { kKeyExecute }, // VK_EXECUTE - /* 0x02c */ { kKeyPrint }, // VK_SNAPSHOT - /* 0x02d */ { kKeyKP_Insert }, // VK_INSERT - /* 0x02e */ { kKeyKP_Delete }, // VK_DELETE - /* 0x02f */ { kKeyHelp }, // VK_HELP - /* 0x030 */ { kKeyNone }, // VK_0 - /* 0x031 */ { kKeyNone }, // VK_1 - /* 0x032 */ { kKeyNone }, // VK_2 - /* 0x033 */ { kKeyNone }, // VK_3 - /* 0x034 */ { kKeyNone }, // VK_4 - /* 0x035 */ { kKeyNone }, // VK_5 - /* 0x036 */ { kKeyNone }, // VK_6 - /* 0x037 */ { kKeyNone }, // VK_7 - /* 0x038 */ { kKeyNone }, // VK_8 - /* 0x039 */ { kKeyNone }, // VK_9 - /* 0x03a */ { kKeyNone }, // undefined - /* 0x03b */ { kKeyNone }, // undefined - /* 0x03c */ { kKeyNone }, // undefined - /* 0x03d */ { kKeyNone }, // undefined - /* 0x03e */ { kKeyNone }, // undefined - /* 0x03f */ { kKeyNone }, // undefined - /* 0x040 */ { kKeyNone }, // undefined - /* 0x041 */ { kKeyNone }, // VK_A - /* 0x042 */ { kKeyNone }, // VK_B - /* 0x043 */ { kKeyNone }, // VK_C - /* 0x044 */ { kKeyNone }, // VK_D - /* 0x045 */ { kKeyNone }, // VK_E - /* 0x046 */ { kKeyNone }, // VK_F - /* 0x047 */ { kKeyNone }, // VK_G - /* 0x048 */ { kKeyNone }, // VK_H - /* 0x049 */ { kKeyNone }, // VK_I - /* 0x04a */ { kKeyNone }, // VK_J - /* 0x04b */ { kKeyNone }, // VK_K - /* 0x04c */ { kKeyNone }, // VK_L - /* 0x04d */ { kKeyNone }, // VK_M - /* 0x04e */ { kKeyNone }, // VK_N - /* 0x04f */ { kKeyNone }, // VK_O - /* 0x050 */ { kKeyNone }, // VK_P - /* 0x051 */ { kKeyNone }, // VK_Q - /* 0x052 */ { kKeyNone }, // VK_R - /* 0x053 */ { kKeyNone }, // VK_S - /* 0x054 */ { kKeyNone }, // VK_T - /* 0x055 */ { kKeyNone }, // VK_U - /* 0x056 */ { kKeyNone }, // VK_V - /* 0x057 */ { kKeyNone }, // VK_W - /* 0x058 */ { kKeyNone }, // VK_X - /* 0x059 */ { kKeyNone }, // VK_Y - /* 0x05a */ { kKeyNone }, // VK_Z - /* 0x05b */ { kKeySuper_L }, // VK_LWIN - /* 0x05c */ { kKeySuper_R }, // VK_RWIN - /* 0x05d */ { kKeyMenu }, // VK_APPS - /* 0x05e */ { kKeyNone }, // undefined - /* 0x05f */ { kKeySleep }, // VK_SLEEP - /* 0x060 */ { kKeyKP_0 }, // VK_NUMPAD0 - /* 0x061 */ { kKeyKP_1 }, // VK_NUMPAD1 - /* 0x062 */ { kKeyKP_2 }, // VK_NUMPAD2 - /* 0x063 */ { kKeyKP_3 }, // VK_NUMPAD3 - /* 0x064 */ { kKeyKP_4 }, // VK_NUMPAD4 - /* 0x065 */ { kKeyKP_5 }, // VK_NUMPAD5 - /* 0x066 */ { kKeyKP_6 }, // VK_NUMPAD6 - /* 0x067 */ { kKeyKP_7 }, // VK_NUMPAD7 - /* 0x068 */ { kKeyKP_8 }, // VK_NUMPAD8 - /* 0x069 */ { kKeyKP_9 }, // VK_NUMPAD9 - /* 0x06a */ { kKeyKP_Multiply },// VK_MULTIPLY - /* 0x06b */ { kKeyKP_Add }, // VK_ADD - /* 0x06c */ { kKeyKP_Separator },// VK_SEPARATOR - /* 0x06d */ { kKeyKP_Subtract },// VK_SUBTRACT - /* 0x06e */ { kKeyKP_Decimal }, // VK_DECIMAL - /* 0x06f */ { kKeyNone }, // VK_DIVIDE - /* 0x070 */ { kKeyF1 }, // VK_F1 - /* 0x071 */ { kKeyF2 }, // VK_F2 - /* 0x072 */ { kKeyF3 }, // VK_F3 - /* 0x073 */ { kKeyF4 }, // VK_F4 - /* 0x074 */ { kKeyF5 }, // VK_F5 - /* 0x075 */ { kKeyF6 }, // VK_F6 - /* 0x076 */ { kKeyF7 }, // VK_F7 - /* 0x077 */ { kKeyF8 }, // VK_F8 - /* 0x078 */ { kKeyF9 }, // VK_F9 - /* 0x079 */ { kKeyF10 }, // VK_F10 - /* 0x07a */ { kKeyF11 }, // VK_F11 - /* 0x07b */ { kKeyF12 }, // VK_F12 - /* 0x07c */ { kKeyF13 }, // VK_F13 - /* 0x07d */ { kKeyF14 }, // VK_F14 - /* 0x07e */ { kKeyF15 }, // VK_F15 - /* 0x07f */ { kKeyF16 }, // VK_F16 - /* 0x080 */ { kKeyF17 }, // VK_F17 - /* 0x081 */ { kKeyF18 }, // VK_F18 - /* 0x082 */ { kKeyF19 }, // VK_F19 - /* 0x083 */ { kKeyF20 }, // VK_F20 - /* 0x084 */ { kKeyF21 }, // VK_F21 - /* 0x085 */ { kKeyF22 }, // VK_F22 - /* 0x086 */ { kKeyF23 }, // VK_F23 - /* 0x087 */ { kKeyF24 }, // VK_F24 - /* 0x088 */ { kKeyNone }, // unassigned - /* 0x089 */ { kKeyNone }, // unassigned - /* 0x08a */ { kKeyNone }, // unassigned - /* 0x08b */ { kKeyNone }, // unassigned - /* 0x08c */ { kKeyNone }, // unassigned - /* 0x08d */ { kKeyNone }, // unassigned - /* 0x08e */ { kKeyNone }, // unassigned - /* 0x08f */ { kKeyNone }, // unassigned - /* 0x090 */ { kKeyNumLock }, // VK_NUMLOCK - /* 0x091 */ { kKeyScrollLock }, // VK_SCROLL - /* 0x092 */ { kKeyNone }, // unassigned - /* 0x093 */ { kKeyNone }, // unassigned - /* 0x094 */ { kKeyNone }, // unassigned - /* 0x095 */ { kKeyNone }, // unassigned - /* 0x096 */ { kKeyNone }, // unassigned - /* 0x097 */ { kKeyNone }, // unassigned - /* 0x098 */ { kKeyNone }, // unassigned - /* 0x099 */ { kKeyNone }, // unassigned - /* 0x09a */ { kKeyNone }, // unassigned - /* 0x09b */ { kKeyNone }, // unassigned - /* 0x09c */ { kKeyNone }, // unassigned - /* 0x09d */ { kKeyNone }, // unassigned - /* 0x09e */ { kKeyNone }, // unassigned - /* 0x09f */ { kKeyNone }, // unassigned - /* 0x0a0 */ { kKeyShift_L }, // VK_LSHIFT - /* 0x0a1 */ { kKeyShift_R }, // VK_RSHIFT - /* 0x0a2 */ { kKeyControl_L }, // VK_LCONTROL - /* 0x0a3 */ { kKeyControl_R }, // VK_RCONTROL - /* 0x0a4 */ { kKeyAlt_L }, // VK_LMENU - /* 0x0a5 */ { kKeyAlt_R }, // VK_RMENU - /* 0x0a6 */ { kKeyNone }, // VK_BROWSER_BACK - /* 0x0a7 */ { kKeyNone }, // VK_BROWSER_FORWARD - /* 0x0a8 */ { kKeyNone }, // VK_BROWSER_REFRESH - /* 0x0a9 */ { kKeyNone }, // VK_BROWSER_STOP - /* 0x0aa */ { kKeyNone }, // VK_BROWSER_SEARCH - /* 0x0ab */ { kKeyNone }, // VK_BROWSER_FAVORITES - /* 0x0ac */ { kKeyNone }, // VK_BROWSER_HOME - /* 0x0ad */ { kKeyNone }, // VK_VOLUME_MUTE - /* 0x0ae */ { kKeyNone }, // VK_VOLUME_DOWN - /* 0x0af */ { kKeyNone }, // VK_VOLUME_UP - /* 0x0b0 */ { kKeyNone }, // VK_MEDIA_NEXT_TRACK - /* 0x0b1 */ { kKeyNone }, // VK_MEDIA_PREV_TRACK - /* 0x0b2 */ { kKeyNone }, // VK_MEDIA_STOP - /* 0x0b3 */ { kKeyNone }, // VK_MEDIA_PLAY_PAUSE - /* 0x0b4 */ { kKeyNone }, // VK_LAUNCH_MAIL - /* 0x0b5 */ { kKeyNone }, // VK_LAUNCH_MEDIA_SELECT - /* 0x0b6 */ { kKeyNone }, // VK_LAUNCH_APP1 - /* 0x0b7 */ { kKeyNone }, // VK_LAUNCH_APP2 - /* 0x0b8 */ { kKeyNone }, // unassigned - /* 0x0b9 */ { kKeyNone }, // unassigned - /* 0x0ba */ { kKeyNone }, // OEM specific - /* 0x0bb */ { kKeyNone }, // OEM specific - /* 0x0bc */ { kKeyNone }, // OEM specific - /* 0x0bd */ { kKeyNone }, // OEM specific - /* 0x0be */ { kKeyNone }, // OEM specific - /* 0x0bf */ { kKeyNone }, // OEM specific - /* 0x0c0 */ { kKeyNone }, // OEM specific - /* 0x0c1 */ { kKeyNone }, // unassigned - /* 0x0c2 */ { kKeyNone }, // unassigned - /* 0x0c3 */ { kKeyNone }, // unassigned - /* 0x0c4 */ { kKeyNone }, // unassigned - /* 0x0c5 */ { kKeyNone }, // unassigned - /* 0x0c6 */ { kKeyNone }, // unassigned - /* 0x0c7 */ { kKeyNone }, // unassigned - /* 0x0c8 */ { kKeyNone }, // unassigned - /* 0x0c9 */ { kKeyNone }, // unassigned - /* 0x0ca */ { kKeyNone }, // unassigned - /* 0x0cb */ { kKeyNone }, // unassigned - /* 0x0cc */ { kKeyNone }, // unassigned - /* 0x0cd */ { kKeyNone }, // unassigned - /* 0x0ce */ { kKeyNone }, // unassigned - /* 0x0cf */ { kKeyNone }, // unassigned - /* 0x0d0 */ { kKeyNone }, // unassigned - /* 0x0d1 */ { kKeyNone }, // unassigned - /* 0x0d2 */ { kKeyNone }, // unassigned - /* 0x0d3 */ { kKeyNone }, // unassigned - /* 0x0d4 */ { kKeyNone }, // unassigned - /* 0x0d5 */ { kKeyNone }, // unassigned - /* 0x0d6 */ { kKeyNone }, // unassigned - /* 0x0d7 */ { kKeyNone }, // unassigned - /* 0x0d8 */ { kKeyNone }, // unassigned - /* 0x0d9 */ { kKeyNone }, // unassigned - /* 0x0da */ { kKeyNone }, // unassigned - /* 0x0db */ { kKeyNone }, // OEM specific - /* 0x0dc */ { kKeyNone }, // OEM specific - /* 0x0dd */ { kKeyNone }, // OEM specific - /* 0x0de */ { kKeyNone }, // OEM specific - /* 0x0df */ { kKeyNone }, // OEM specific - /* 0x0e0 */ { kKeyNone }, // OEM specific - /* 0x0e1 */ { kKeyNone }, // OEM specific - /* 0x0e2 */ { kKeyNone }, // OEM specific - /* 0x0e3 */ { kKeyNone }, // OEM specific - /* 0x0e4 */ { kKeyNone }, // OEM specific - /* 0x0e5 */ { kKeyNone }, // unassigned - /* 0x0e6 */ { kKeyNone }, // OEM specific - /* 0x0e7 */ { kKeyNone }, // unassigned - /* 0x0e8 */ { kKeyNone }, // unassigned - /* 0x0e9 */ { kKeyNone }, // OEM specific - /* 0x0ea */ { kKeyNone }, // OEM specific - /* 0x0eb */ { kKeyNone }, // OEM specific - /* 0x0ec */ { kKeyNone }, // OEM specific - /* 0x0ed */ { kKeyNone }, // OEM specific - /* 0x0ee */ { kKeyNone }, // OEM specific - /* 0x0ef */ { kKeyNone }, // OEM specific - /* 0x0f0 */ { kKeyNone }, // OEM specific - /* 0x0f1 */ { kKeyNone }, // OEM specific - /* 0x0f2 */ { kKeyHiraganaKatakana }, // VK_OEM_COPY - /* 0x0f3 */ { kKeyZenkaku }, // VK_OEM_AUTO - /* 0x0f4 */ { kKeyZenkaku }, // VK_OEM_ENLW - /* 0x0f5 */ { kKeyNone }, // OEM specific - /* 0x0f6 */ { kKeyNone }, // VK_ATTN - /* 0x0f7 */ { kKeyNone }, // VK_CRSEL - /* 0x0f8 */ { kKeyNone }, // VK_EXSEL - /* 0x0f9 */ { kKeyNone }, // VK_EREOF - /* 0x0fa */ { kKeyNone }, // VK_PLAY - /* 0x0fb */ { kKeyNone }, // VK_ZOOM - /* 0x0fc */ { kKeyNone }, // reserved - /* 0x0fd */ { kKeyNone }, // VK_PA1 - /* 0x0fe */ { kKeyNone }, // VK_OEM_CLEAR - /* 0x0ff */ { kKeyNone }, // reserved +const KeyID MSWindowsKeyState::s_virtualKey[] = { + /* 0x000 */ {kKeyNone}, // reserved + /* 0x001 */ {kKeyNone}, // VK_LBUTTON + /* 0x002 */ {kKeyNone}, // VK_RBUTTON + /* 0x003 */ {kKeyNone}, // VK_CANCEL + /* 0x004 */ {kKeyNone}, // VK_MBUTTON + /* 0x005 */ {kKeyNone}, // VK_XBUTTON1 + /* 0x006 */ {kKeyNone}, // VK_XBUTTON2 + /* 0x007 */ {kKeyNone}, // undefined + /* 0x008 */ {kKeyBackSpace}, // VK_BACK + /* 0x009 */ {kKeyTab}, // VK_TAB + /* 0x00a */ {kKeyNone}, // undefined + /* 0x00b */ {kKeyNone}, // undefined + /* 0x00c */ {kKeyClear}, // VK_CLEAR + /* 0x00d */ {kKeyReturn}, // VK_RETURN + /* 0x00e */ {kKeyNone}, // undefined + /* 0x00f */ {kKeyNone}, // undefined + /* 0x010 */ {kKeyShift_L}, // VK_SHIFT + /* 0x011 */ {kKeyControl_L}, // VK_CONTROL + /* 0x012 */ {kKeyAlt_L}, // VK_MENU + /* 0x013 */ {kKeyPause}, // VK_PAUSE + /* 0x014 */ {kKeyCapsLock}, // VK_CAPITAL + /* 0x015 */ {kKeyKana}, // VK_HANGUL, VK_KANA + /* 0x016 */ {kKeyNone}, // undefined + /* 0x017 */ {kKeyNone}, // VK_JUNJA + /* 0x018 */ {kKeyNone}, // VK_FINAL + /* 0x019 */ {kKeyKanzi}, // VK_HANJA, VK_KANJI + /* 0x01a */ {kKeyNone}, // undefined + /* 0x01b */ {kKeyEscape}, // VK_ESCAPE + /* 0x01c */ {kKeyHenkan}, // VK_CONVERT + /* 0x01d */ {kKeyNone}, // VK_NONCONVERT + /* 0x01e */ {kKeyNone}, // VK_ACCEPT + /* 0x01f */ {kKeyNone}, // VK_MODECHANGE + /* 0x020 */ {kKeyNone}, // VK_SPACE + /* 0x021 */ {kKeyKP_PageUp}, // VK_PRIOR + /* 0x022 */ {kKeyKP_PageDown}, // VK_NEXT + /* 0x023 */ {kKeyKP_End}, // VK_END + /* 0x024 */ {kKeyKP_Home}, // VK_HOME + /* 0x025 */ {kKeyKP_Left}, // VK_LEFT + /* 0x026 */ {kKeyKP_Up}, // VK_UP + /* 0x027 */ {kKeyKP_Right}, // VK_RIGHT + /* 0x028 */ {kKeyKP_Down}, // VK_DOWN + /* 0x029 */ {kKeySelect}, // VK_SELECT + /* 0x02a */ {kKeyNone}, // VK_PRINT + /* 0x02b */ {kKeyExecute}, // VK_EXECUTE + /* 0x02c */ {kKeyPrint}, // VK_SNAPSHOT + /* 0x02d */ {kKeyKP_Insert}, // VK_INSERT + /* 0x02e */ {kKeyKP_Delete}, // VK_DELETE + /* 0x02f */ {kKeyHelp}, // VK_HELP + /* 0x030 */ {kKeyNone}, // VK_0 + /* 0x031 */ {kKeyNone}, // VK_1 + /* 0x032 */ {kKeyNone}, // VK_2 + /* 0x033 */ {kKeyNone}, // VK_3 + /* 0x034 */ {kKeyNone}, // VK_4 + /* 0x035 */ {kKeyNone}, // VK_5 + /* 0x036 */ {kKeyNone}, // VK_6 + /* 0x037 */ {kKeyNone}, // VK_7 + /* 0x038 */ {kKeyNone}, // VK_8 + /* 0x039 */ {kKeyNone}, // VK_9 + /* 0x03a */ {kKeyNone}, // undefined + /* 0x03b */ {kKeyNone}, // undefined + /* 0x03c */ {kKeyNone}, // undefined + /* 0x03d */ {kKeyNone}, // undefined + /* 0x03e */ {kKeyNone}, // undefined + /* 0x03f */ {kKeyNone}, // undefined + /* 0x040 */ {kKeyNone}, // undefined + /* 0x041 */ {kKeyNone}, // VK_A + /* 0x042 */ {kKeyNone}, // VK_B + /* 0x043 */ {kKeyNone}, // VK_C + /* 0x044 */ {kKeyNone}, // VK_D + /* 0x045 */ {kKeyNone}, // VK_E + /* 0x046 */ {kKeyNone}, // VK_F + /* 0x047 */ {kKeyNone}, // VK_G + /* 0x048 */ {kKeyNone}, // VK_H + /* 0x049 */ {kKeyNone}, // VK_I + /* 0x04a */ {kKeyNone}, // VK_J + /* 0x04b */ {kKeyNone}, // VK_K + /* 0x04c */ {kKeyNone}, // VK_L + /* 0x04d */ {kKeyNone}, // VK_M + /* 0x04e */ {kKeyNone}, // VK_N + /* 0x04f */ {kKeyNone}, // VK_O + /* 0x050 */ {kKeyNone}, // VK_P + /* 0x051 */ {kKeyNone}, // VK_Q + /* 0x052 */ {kKeyNone}, // VK_R + /* 0x053 */ {kKeyNone}, // VK_S + /* 0x054 */ {kKeyNone}, // VK_T + /* 0x055 */ {kKeyNone}, // VK_U + /* 0x056 */ {kKeyNone}, // VK_V + /* 0x057 */ {kKeyNone}, // VK_W + /* 0x058 */ {kKeyNone}, // VK_X + /* 0x059 */ {kKeyNone}, // VK_Y + /* 0x05a */ {kKeyNone}, // VK_Z + /* 0x05b */ {kKeySuper_L}, // VK_LWIN + /* 0x05c */ {kKeySuper_R}, // VK_RWIN + /* 0x05d */ {kKeyMenu}, // VK_APPS + /* 0x05e */ {kKeyNone}, // undefined + /* 0x05f */ {kKeySleep}, // VK_SLEEP + /* 0x060 */ {kKeyKP_0}, // VK_NUMPAD0 + /* 0x061 */ {kKeyKP_1}, // VK_NUMPAD1 + /* 0x062 */ {kKeyKP_2}, // VK_NUMPAD2 + /* 0x063 */ {kKeyKP_3}, // VK_NUMPAD3 + /* 0x064 */ {kKeyKP_4}, // VK_NUMPAD4 + /* 0x065 */ {kKeyKP_5}, // VK_NUMPAD5 + /* 0x066 */ {kKeyKP_6}, // VK_NUMPAD6 + /* 0x067 */ {kKeyKP_7}, // VK_NUMPAD7 + /* 0x068 */ {kKeyKP_8}, // VK_NUMPAD8 + /* 0x069 */ {kKeyKP_9}, // VK_NUMPAD9 + /* 0x06a */ {kKeyKP_Multiply}, // VK_MULTIPLY + /* 0x06b */ {kKeyKP_Add}, // VK_ADD + /* 0x06c */ {kKeyKP_Separator}, // VK_SEPARATOR + /* 0x06d */ {kKeyKP_Subtract}, // VK_SUBTRACT + /* 0x06e */ {kKeyKP_Decimal}, // VK_DECIMAL + /* 0x06f */ {kKeyNone}, // VK_DIVIDE + /* 0x070 */ {kKeyF1}, // VK_F1 + /* 0x071 */ {kKeyF2}, // VK_F2 + /* 0x072 */ {kKeyF3}, // VK_F3 + /* 0x073 */ {kKeyF4}, // VK_F4 + /* 0x074 */ {kKeyF5}, // VK_F5 + /* 0x075 */ {kKeyF6}, // VK_F6 + /* 0x076 */ {kKeyF7}, // VK_F7 + /* 0x077 */ {kKeyF8}, // VK_F8 + /* 0x078 */ {kKeyF9}, // VK_F9 + /* 0x079 */ {kKeyF10}, // VK_F10 + /* 0x07a */ {kKeyF11}, // VK_F11 + /* 0x07b */ {kKeyF12}, // VK_F12 + /* 0x07c */ {kKeyF13}, // VK_F13 + /* 0x07d */ {kKeyF14}, // VK_F14 + /* 0x07e */ {kKeyF15}, // VK_F15 + /* 0x07f */ {kKeyF16}, // VK_F16 + /* 0x080 */ {kKeyF17}, // VK_F17 + /* 0x081 */ {kKeyF18}, // VK_F18 + /* 0x082 */ {kKeyF19}, // VK_F19 + /* 0x083 */ {kKeyF20}, // VK_F20 + /* 0x084 */ {kKeyF21}, // VK_F21 + /* 0x085 */ {kKeyF22}, // VK_F22 + /* 0x086 */ {kKeyF23}, // VK_F23 + /* 0x087 */ {kKeyF24}, // VK_F24 + /* 0x088 */ {kKeyNone}, // unassigned + /* 0x089 */ {kKeyNone}, // unassigned + /* 0x08a */ {kKeyNone}, // unassigned + /* 0x08b */ {kKeyNone}, // unassigned + /* 0x08c */ {kKeyNone}, // unassigned + /* 0x08d */ {kKeyNone}, // unassigned + /* 0x08e */ {kKeyNone}, // unassigned + /* 0x08f */ {kKeyNone}, // unassigned + /* 0x090 */ {kKeyNumLock}, // VK_NUMLOCK + /* 0x091 */ {kKeyScrollLock}, // VK_SCROLL + /* 0x092 */ {kKeyNone}, // unassigned + /* 0x093 */ {kKeyNone}, // unassigned + /* 0x094 */ {kKeyNone}, // unassigned + /* 0x095 */ {kKeyNone}, // unassigned + /* 0x096 */ {kKeyNone}, // unassigned + /* 0x097 */ {kKeyNone}, // unassigned + /* 0x098 */ {kKeyNone}, // unassigned + /* 0x099 */ {kKeyNone}, // unassigned + /* 0x09a */ {kKeyNone}, // unassigned + /* 0x09b */ {kKeyNone}, // unassigned + /* 0x09c */ {kKeyNone}, // unassigned + /* 0x09d */ {kKeyNone}, // unassigned + /* 0x09e */ {kKeyNone}, // unassigned + /* 0x09f */ {kKeyNone}, // unassigned + /* 0x0a0 */ {kKeyShift_L}, // VK_LSHIFT + /* 0x0a1 */ {kKeyShift_R}, // VK_RSHIFT + /* 0x0a2 */ {kKeyControl_L}, // VK_LCONTROL + /* 0x0a3 */ {kKeyControl_R}, // VK_RCONTROL + /* 0x0a4 */ {kKeyAlt_L}, // VK_LMENU + /* 0x0a5 */ {kKeyAlt_R}, // VK_RMENU + /* 0x0a6 */ {kKeyNone}, // VK_BROWSER_BACK + /* 0x0a7 */ {kKeyNone}, // VK_BROWSER_FORWARD + /* 0x0a8 */ {kKeyNone}, // VK_BROWSER_REFRESH + /* 0x0a9 */ {kKeyNone}, // VK_BROWSER_STOP + /* 0x0aa */ {kKeyNone}, // VK_BROWSER_SEARCH + /* 0x0ab */ {kKeyNone}, // VK_BROWSER_FAVORITES + /* 0x0ac */ {kKeyNone}, // VK_BROWSER_HOME + /* 0x0ad */ {kKeyNone}, // VK_VOLUME_MUTE + /* 0x0ae */ {kKeyNone}, // VK_VOLUME_DOWN + /* 0x0af */ {kKeyNone}, // VK_VOLUME_UP + /* 0x0b0 */ {kKeyNone}, // VK_MEDIA_NEXT_TRACK + /* 0x0b1 */ {kKeyNone}, // VK_MEDIA_PREV_TRACK + /* 0x0b2 */ {kKeyNone}, // VK_MEDIA_STOP + /* 0x0b3 */ {kKeyNone}, // VK_MEDIA_PLAY_PAUSE + /* 0x0b4 */ {kKeyNone}, // VK_LAUNCH_MAIL + /* 0x0b5 */ {kKeyNone}, // VK_LAUNCH_MEDIA_SELECT + /* 0x0b6 */ {kKeyNone}, // VK_LAUNCH_APP1 + /* 0x0b7 */ {kKeyNone}, // VK_LAUNCH_APP2 + /* 0x0b8 */ {kKeyNone}, // unassigned + /* 0x0b9 */ {kKeyNone}, // unassigned + /* 0x0ba */ {kKeyNone}, // OEM specific + /* 0x0bb */ {kKeyNone}, // OEM specific + /* 0x0bc */ {kKeyNone}, // OEM specific + /* 0x0bd */ {kKeyNone}, // OEM specific + /* 0x0be */ {kKeyNone}, // OEM specific + /* 0x0bf */ {kKeyNone}, // OEM specific + /* 0x0c0 */ {kKeyNone}, // OEM specific + /* 0x0c1 */ {kKeyNone}, // unassigned + /* 0x0c2 */ {kKeyNone}, // unassigned + /* 0x0c3 */ {kKeyNone}, // unassigned + /* 0x0c4 */ {kKeyNone}, // unassigned + /* 0x0c5 */ {kKeyNone}, // unassigned + /* 0x0c6 */ {kKeyNone}, // unassigned + /* 0x0c7 */ {kKeyNone}, // unassigned + /* 0x0c8 */ {kKeyNone}, // unassigned + /* 0x0c9 */ {kKeyNone}, // unassigned + /* 0x0ca */ {kKeyNone}, // unassigned + /* 0x0cb */ {kKeyNone}, // unassigned + /* 0x0cc */ {kKeyNone}, // unassigned + /* 0x0cd */ {kKeyNone}, // unassigned + /* 0x0ce */ {kKeyNone}, // unassigned + /* 0x0cf */ {kKeyNone}, // unassigned + /* 0x0d0 */ {kKeyNone}, // unassigned + /* 0x0d1 */ {kKeyNone}, // unassigned + /* 0x0d2 */ {kKeyNone}, // unassigned + /* 0x0d3 */ {kKeyNone}, // unassigned + /* 0x0d4 */ {kKeyNone}, // unassigned + /* 0x0d5 */ {kKeyNone}, // unassigned + /* 0x0d6 */ {kKeyNone}, // unassigned + /* 0x0d7 */ {kKeyNone}, // unassigned + /* 0x0d8 */ {kKeyNone}, // unassigned + /* 0x0d9 */ {kKeyNone}, // unassigned + /* 0x0da */ {kKeyNone}, // unassigned + /* 0x0db */ {kKeyNone}, // OEM specific + /* 0x0dc */ {kKeyNone}, // OEM specific + /* 0x0dd */ {kKeyNone}, // OEM specific + /* 0x0de */ {kKeyNone}, // OEM specific + /* 0x0df */ {kKeyNone}, // OEM specific + /* 0x0e0 */ {kKeyNone}, // OEM specific + /* 0x0e1 */ {kKeyNone}, // OEM specific + /* 0x0e2 */ {kKeyNone}, // OEM specific + /* 0x0e3 */ {kKeyNone}, // OEM specific + /* 0x0e4 */ {kKeyNone}, // OEM specific + /* 0x0e5 */ {kKeyNone}, // unassigned + /* 0x0e6 */ {kKeyNone}, // OEM specific + /* 0x0e7 */ {kKeyNone}, // unassigned + /* 0x0e8 */ {kKeyNone}, // unassigned + /* 0x0e9 */ {kKeyNone}, // OEM specific + /* 0x0ea */ {kKeyNone}, // OEM specific + /* 0x0eb */ {kKeyNone}, // OEM specific + /* 0x0ec */ {kKeyNone}, // OEM specific + /* 0x0ed */ {kKeyNone}, // OEM specific + /* 0x0ee */ {kKeyNone}, // OEM specific + /* 0x0ef */ {kKeyNone}, // OEM specific + /* 0x0f0 */ {kKeyNone}, // OEM specific + /* 0x0f1 */ {kKeyNone}, // OEM specific + /* 0x0f2 */ {kKeyHiraganaKatakana}, // VK_OEM_COPY + /* 0x0f3 */ {kKeyZenkaku}, // VK_OEM_AUTO + /* 0x0f4 */ {kKeyZenkaku}, // VK_OEM_ENLW + /* 0x0f5 */ {kKeyNone}, // OEM specific + /* 0x0f6 */ {kKeyNone}, // VK_ATTN + /* 0x0f7 */ {kKeyNone}, // VK_CRSEL + /* 0x0f8 */ {kKeyNone}, // VK_EXSEL + /* 0x0f9 */ {kKeyNone}, // VK_EREOF + /* 0x0fa */ {kKeyNone}, // VK_PLAY + /* 0x0fb */ {kKeyNone}, // VK_ZOOM + /* 0x0fc */ {kKeyNone}, // reserved + /* 0x0fd */ {kKeyNone}, // VK_PA1 + /* 0x0fe */ {kKeyNone}, // VK_OEM_CLEAR + /* 0x0ff */ {kKeyNone}, // reserved - /* 0x100 */ { kKeyNone }, // reserved - /* 0x101 */ { kKeyNone }, // VK_LBUTTON - /* 0x102 */ { kKeyNone }, // VK_RBUTTON - /* 0x103 */ { kKeyBreak }, // VK_CANCEL - /* 0x104 */ { kKeyNone }, // VK_MBUTTON - /* 0x105 */ { kKeyNone }, // VK_XBUTTON1 - /* 0x106 */ { kKeyNone }, // VK_XBUTTON2 - /* 0x107 */ { kKeyNone }, // undefined - /* 0x108 */ { kKeyNone }, // VK_BACK - /* 0x109 */ { kKeyNone }, // VK_TAB - /* 0x10a */ { kKeyNone }, // undefined - /* 0x10b */ { kKeyNone }, // undefined - /* 0x10c */ { kKeyClear }, // VK_CLEAR - /* 0x10d */ { kKeyKP_Enter }, // VK_RETURN - /* 0x10e */ { kKeyNone }, // undefined - /* 0x10f */ { kKeyNone }, // undefined - /* 0x110 */ { kKeyShift_R }, // VK_SHIFT - /* 0x111 */ { kKeyControl_R }, // VK_CONTROL - /* 0x112 */ { kKeyAlt_R }, // VK_MENU - /* 0x113 */ { kKeyNone }, // VK_PAUSE - /* 0x114 */ { kKeyNone }, // VK_CAPITAL - /* 0x115 */ { kKeyHangul }, // VK_HANGUL - /* 0x116 */ { kKeyNone }, // undefined - /* 0x117 */ { kKeyNone }, // VK_JUNJA - /* 0x118 */ { kKeyNone }, // VK_FINAL - /* 0x119 */ { kKeyHanja }, // VK_HANJA - /* 0x11a */ { kKeyNone }, // undefined - /* 0x11b */ { kKeyNone }, // VK_ESCAPE - /* 0x11c */ { kKeyNone }, // VK_CONVERT - /* 0x11d */ { kKeyNone }, // VK_NONCONVERT - /* 0x11e */ { kKeyNone }, // VK_ACCEPT - /* 0x11f */ { kKeyNone }, // VK_MODECHANGE - /* 0x120 */ { kKeyNone }, // VK_SPACE - /* 0x121 */ { kKeyPageUp }, // VK_PRIOR - /* 0x122 */ { kKeyPageDown }, // VK_NEXT - /* 0x123 */ { kKeyEnd }, // VK_END - /* 0x124 */ { kKeyHome }, // VK_HOME - /* 0x125 */ { kKeyLeft }, // VK_LEFT - /* 0x126 */ { kKeyUp }, // VK_UP - /* 0x127 */ { kKeyRight }, // VK_RIGHT - /* 0x128 */ { kKeyDown }, // VK_DOWN - /* 0x129 */ { kKeySelect }, // VK_SELECT - /* 0x12a */ { kKeyNone }, // VK_PRINT - /* 0x12b */ { kKeyExecute }, // VK_EXECUTE - /* 0x12c */ { kKeyPrint }, // VK_SNAPSHOT - /* 0x12d */ { kKeyInsert }, // VK_INSERT - /* 0x12e */ { kKeyDelete }, // VK_DELETE - /* 0x12f */ { kKeyHelp }, // VK_HELP - /* 0x130 */ { kKeyNone }, // VK_0 - /* 0x131 */ { kKeyNone }, // VK_1 - /* 0x132 */ { kKeyNone }, // VK_2 - /* 0x133 */ { kKeyNone }, // VK_3 - /* 0x134 */ { kKeyNone }, // VK_4 - /* 0x135 */ { kKeyNone }, // VK_5 - /* 0x136 */ { kKeyNone }, // VK_6 - /* 0x137 */ { kKeyNone }, // VK_7 - /* 0x138 */ { kKeyNone }, // VK_8 - /* 0x139 */ { kKeyNone }, // VK_9 - /* 0x13a */ { kKeyNone }, // undefined - /* 0x13b */ { kKeyNone }, // undefined - /* 0x13c */ { kKeyNone }, // undefined - /* 0x13d */ { kKeyNone }, // undefined - /* 0x13e */ { kKeyNone }, // undefined - /* 0x13f */ { kKeyNone }, // undefined - /* 0x140 */ { kKeyNone }, // undefined - /* 0x141 */ { kKeyNone }, // VK_A - /* 0x142 */ { kKeyNone }, // VK_B - /* 0x143 */ { kKeyNone }, // VK_C - /* 0x144 */ { kKeyNone }, // VK_D - /* 0x145 */ { kKeyNone }, // VK_E - /* 0x146 */ { kKeyNone }, // VK_F - /* 0x147 */ { kKeyNone }, // VK_G - /* 0x148 */ { kKeyNone }, // VK_H - /* 0x149 */ { kKeyNone }, // VK_I - /* 0x14a */ { kKeyNone }, // VK_J - /* 0x14b */ { kKeyNone }, // VK_K - /* 0x14c */ { kKeyNone }, // VK_L - /* 0x14d */ { kKeyNone }, // VK_M - /* 0x14e */ { kKeyNone }, // VK_N - /* 0x14f */ { kKeyNone }, // VK_O - /* 0x150 */ { kKeyNone }, // VK_P - /* 0x151 */ { kKeyNone }, // VK_Q - /* 0x152 */ { kKeyNone }, // VK_R - /* 0x153 */ { kKeyNone }, // VK_S - /* 0x154 */ { kKeyNone }, // VK_T - /* 0x155 */ { kKeyNone }, // VK_U - /* 0x156 */ { kKeyNone }, // VK_V - /* 0x157 */ { kKeyNone }, // VK_W - /* 0x158 */ { kKeyNone }, // VK_X - /* 0x159 */ { kKeyNone }, // VK_Y - /* 0x15a */ { kKeyNone }, // VK_Z - /* 0x15b */ { kKeySuper_L }, // VK_LWIN - /* 0x15c */ { kKeySuper_R }, // VK_RWIN - /* 0x15d */ { kKeyMenu }, // VK_APPS - /* 0x15e */ { kKeyNone }, // undefined - /* 0x15f */ { kKeyNone }, // VK_SLEEP - /* 0x160 */ { kKeyNone }, // VK_NUMPAD0 - /* 0x161 */ { kKeyNone }, // VK_NUMPAD1 - /* 0x162 */ { kKeyNone }, // VK_NUMPAD2 - /* 0x163 */ { kKeyNone }, // VK_NUMPAD3 - /* 0x164 */ { kKeyNone }, // VK_NUMPAD4 - /* 0x165 */ { kKeyNone }, // VK_NUMPAD5 - /* 0x166 */ { kKeyNone }, // VK_NUMPAD6 - /* 0x167 */ { kKeyNone }, // VK_NUMPAD7 - /* 0x168 */ { kKeyNone }, // VK_NUMPAD8 - /* 0x169 */ { kKeyNone }, // VK_NUMPAD9 - /* 0x16a */ { kKeyNone }, // VK_MULTIPLY - /* 0x16b */ { kKeyNone }, // VK_ADD - /* 0x16c */ { kKeyKP_Separator },// VK_SEPARATOR - /* 0x16d */ { kKeyNone }, // VK_SUBTRACT - /* 0x16e */ { kKeyNone }, // VK_DECIMAL - /* 0x16f */ { kKeyKP_Divide }, // VK_DIVIDE - /* 0x170 */ { kKeyNone }, // VK_F1 - /* 0x171 */ { kKeyNone }, // VK_F2 - /* 0x172 */ { kKeyNone }, // VK_F3 - /* 0x173 */ { kKeyNone }, // VK_F4 - /* 0x174 */ { kKeyNone }, // VK_F5 - /* 0x175 */ { kKeyNone }, // VK_F6 - /* 0x176 */ { kKeyNone }, // VK_F7 - /* 0x177 */ { kKeyNone }, // VK_F8 - /* 0x178 */ { kKeyNone }, // VK_F9 - /* 0x179 */ { kKeyNone }, // VK_F10 - /* 0x17a */ { kKeyNone }, // VK_F11 - /* 0x17b */ { kKeyNone }, // VK_F12 - /* 0x17c */ { kKeyF13 }, // VK_F13 - /* 0x17d */ { kKeyF14 }, // VK_F14 - /* 0x17e */ { kKeyF15 }, // VK_F15 - /* 0x17f */ { kKeyF16 }, // VK_F16 - /* 0x180 */ { kKeyF17 }, // VK_F17 - /* 0x181 */ { kKeyF18 }, // VK_F18 - /* 0x182 */ { kKeyF19 }, // VK_F19 - /* 0x183 */ { kKeyF20 }, // VK_F20 - /* 0x184 */ { kKeyF21 }, // VK_F21 - /* 0x185 */ { kKeyF22 }, // VK_F22 - /* 0x186 */ { kKeyF23 }, // VK_F23 - /* 0x187 */ { kKeyF24 }, // VK_F24 - /* 0x188 */ { kKeyNone }, // unassigned - /* 0x189 */ { kKeyNone }, // unassigned - /* 0x18a */ { kKeyNone }, // unassigned - /* 0x18b */ { kKeyNone }, // unassigned - /* 0x18c */ { kKeyNone }, // unassigned - /* 0x18d */ { kKeyNone }, // unassigned - /* 0x18e */ { kKeyNone }, // unassigned - /* 0x18f */ { kKeyNone }, // unassigned - /* 0x190 */ { kKeyNumLock }, // VK_NUMLOCK - /* 0x191 */ { kKeyNone }, // VK_SCROLL - /* 0x192 */ { kKeyNone }, // unassigned - /* 0x193 */ { kKeyNone }, // unassigned - /* 0x194 */ { kKeyNone }, // unassigned - /* 0x195 */ { kKeyNone }, // unassigned - /* 0x196 */ { kKeyNone }, // unassigned - /* 0x197 */ { kKeyNone }, // unassigned - /* 0x198 */ { kKeyNone }, // unassigned - /* 0x199 */ { kKeyNone }, // unassigned - /* 0x19a */ { kKeyNone }, // unassigned - /* 0x19b */ { kKeyNone }, // unassigned - /* 0x19c */ { kKeyNone }, // unassigned - /* 0x19d */ { kKeyNone }, // unassigned - /* 0x19e */ { kKeyNone }, // unassigned - /* 0x19f */ { kKeyNone }, // unassigned - /* 0x1a0 */ { kKeyShift_L }, // VK_LSHIFT - /* 0x1a1 */ { kKeyShift_R }, // VK_RSHIFT - /* 0x1a2 */ { kKeyControl_L }, // VK_LCONTROL - /* 0x1a3 */ { kKeyControl_R }, // VK_RCONTROL - /* 0x1a4 */ { kKeyAlt_L }, // VK_LMENU - /* 0x1a5 */ { kKeyAlt_R }, // VK_RMENU - /* 0x1a6 */ { kKeyWWWBack }, // VK_BROWSER_BACK - /* 0x1a7 */ { kKeyWWWForward }, // VK_BROWSER_FORWARD - /* 0x1a8 */ { kKeyWWWRefresh }, // VK_BROWSER_REFRESH - /* 0x1a9 */ { kKeyWWWStop }, // VK_BROWSER_STOP - /* 0x1aa */ { kKeyWWWSearch }, // VK_BROWSER_SEARCH - /* 0x1ab */ { kKeyWWWFavorites },// VK_BROWSER_FAVORITES - /* 0x1ac */ { kKeyWWWHome }, // VK_BROWSER_HOME - /* 0x1ad */ { kKeyAudioMute }, // VK_VOLUME_MUTE - /* 0x1ae */ { kKeyAudioDown }, // VK_VOLUME_DOWN - /* 0x1af */ { kKeyAudioUp }, // VK_VOLUME_UP - /* 0x1b0 */ { kKeyAudioNext }, // VK_MEDIA_NEXT_TRACK - /* 0x1b1 */ { kKeyAudioPrev }, // VK_MEDIA_PREV_TRACK - /* 0x1b2 */ { kKeyAudioStop }, // VK_MEDIA_STOP - /* 0x1b3 */ { kKeyAudioPlay }, // VK_MEDIA_PLAY_PAUSE - /* 0x1b4 */ { kKeyAppMail }, // VK_LAUNCH_MAIL - /* 0x1b5 */ { kKeyAppMedia }, // VK_LAUNCH_MEDIA_SELECT - /* 0x1b6 */ { kKeyAppUser1 }, // VK_LAUNCH_APP1 - /* 0x1b7 */ { kKeyAppUser2 }, // VK_LAUNCH_APP2 - /* 0x1b8 */ { kKeyNone }, // unassigned - /* 0x1b9 */ { kKeyNone }, // unassigned - /* 0x1ba */ { kKeyNone }, // OEM specific - /* 0x1bb */ { kKeyNone }, // OEM specific - /* 0x1bc */ { kKeyNone }, // OEM specific - /* 0x1bd */ { kKeyNone }, // OEM specific - /* 0x1be */ { kKeyNone }, // OEM specific - /* 0x1bf */ { kKeyNone }, // OEM specific - /* 0x1c0 */ { kKeyNone }, // OEM specific - /* 0x1c1 */ { kKeyNone }, // unassigned - /* 0x1c2 */ { kKeyNone }, // unassigned - /* 0x1c3 */ { kKeyNone }, // unassigned - /* 0x1c4 */ { kKeyNone }, // unassigned - /* 0x1c5 */ { kKeyNone }, // unassigned - /* 0x1c6 */ { kKeyNone }, // unassigned - /* 0x1c7 */ { kKeyNone }, // unassigned - /* 0x1c8 */ { kKeyNone }, // unassigned - /* 0x1c9 */ { kKeyNone }, // unassigned - /* 0x1ca */ { kKeyNone }, // unassigned - /* 0x1cb */ { kKeyNone }, // unassigned - /* 0x1cc */ { kKeyNone }, // unassigned - /* 0x1cd */ { kKeyNone }, // unassigned - /* 0x1ce */ { kKeyNone }, // unassigned - /* 0x1cf */ { kKeyNone }, // unassigned - /* 0x1d0 */ { kKeyNone }, // unassigned - /* 0x1d1 */ { kKeyNone }, // unassigned - /* 0x1d2 */ { kKeyNone }, // unassigned - /* 0x1d3 */ { kKeyNone }, // unassigned - /* 0x1d4 */ { kKeyNone }, // unassigned - /* 0x1d5 */ { kKeyNone }, // unassigned - /* 0x1d6 */ { kKeyNone }, // unassigned - /* 0x1d7 */ { kKeyNone }, // unassigned - /* 0x1d8 */ { kKeyNone }, // unassigned - /* 0x1d9 */ { kKeyNone }, // unassigned - /* 0x1da */ { kKeyNone }, // unassigned - /* 0x1db */ { kKeyNone }, // OEM specific - /* 0x1dc */ { kKeyNone }, // OEM specific - /* 0x1dd */ { kKeyNone }, // OEM specific - /* 0x1de */ { kKeyNone }, // OEM specific - /* 0x1df */ { kKeyNone }, // OEM specific - /* 0x1e0 */ { kKeyNone }, // OEM specific - /* 0x1e1 */ { kKeyNone }, // OEM specific - /* 0x1e2 */ { kKeyNone }, // OEM specific - /* 0x1e3 */ { kKeyNone }, // OEM specific - /* 0x1e4 */ { kKeyNone }, // OEM specific - /* 0x1e5 */ { kKeyNone }, // unassigned - /* 0x1e6 */ { kKeyNone }, // OEM specific - /* 0x1e7 */ { kKeyNone }, // unassigned - /* 0x1e8 */ { kKeyNone }, // unassigned - /* 0x1e9 */ { kKeyNone }, // OEM specific - /* 0x1ea */ { kKeyNone }, // OEM specific - /* 0x1eb */ { kKeyNone }, // OEM specific - /* 0x1ec */ { kKeyNone }, // OEM specific - /* 0x1ed */ { kKeyNone }, // OEM specific - /* 0x1ee */ { kKeyNone }, // OEM specific - /* 0x1ef */ { kKeyNone }, // OEM specific - /* 0x1f0 */ { kKeyNone }, // OEM specific - /* 0x1f1 */ { kKeyNone }, // OEM specific - /* 0x1f2 */ { kKeyNone }, // VK_OEM_COPY - /* 0x1f3 */ { kKeyNone }, // VK_OEM_AUTO - /* 0x1f4 */ { kKeyNone }, // VK_OEM_ENLW - /* 0x1f5 */ { kKeyNone }, // OEM specific - /* 0x1f6 */ { kKeyNone }, // VK_ATTN - /* 0x1f7 */ { kKeyNone }, // VK_CRSEL - /* 0x1f8 */ { kKeyNone }, // VK_EXSEL - /* 0x1f9 */ { kKeyNone }, // VK_EREOF - /* 0x1fa */ { kKeyNone }, // VK_PLAY - /* 0x1fb */ { kKeyNone }, // VK_ZOOM - /* 0x1fc */ { kKeyNone }, // reserved - /* 0x1fd */ { kKeyNone }, // VK_PA1 - /* 0x1fe */ { kKeyNone }, // VK_OEM_CLEAR - /* 0x1ff */ { kKeyNone } // reserved + /* 0x100 */ {kKeyNone}, // reserved + /* 0x101 */ {kKeyNone}, // VK_LBUTTON + /* 0x102 */ {kKeyNone}, // VK_RBUTTON + /* 0x103 */ {kKeyBreak}, // VK_CANCEL + /* 0x104 */ {kKeyNone}, // VK_MBUTTON + /* 0x105 */ {kKeyNone}, // VK_XBUTTON1 + /* 0x106 */ {kKeyNone}, // VK_XBUTTON2 + /* 0x107 */ {kKeyNone}, // undefined + /* 0x108 */ {kKeyNone}, // VK_BACK + /* 0x109 */ {kKeyNone}, // VK_TAB + /* 0x10a */ {kKeyNone}, // undefined + /* 0x10b */ {kKeyNone}, // undefined + /* 0x10c */ {kKeyClear}, // VK_CLEAR + /* 0x10d */ {kKeyKP_Enter}, // VK_RETURN + /* 0x10e */ {kKeyNone}, // undefined + /* 0x10f */ {kKeyNone}, // undefined + /* 0x110 */ {kKeyShift_R}, // VK_SHIFT + /* 0x111 */ {kKeyControl_R}, // VK_CONTROL + /* 0x112 */ {kKeyAlt_R}, // VK_MENU + /* 0x113 */ {kKeyNone}, // VK_PAUSE + /* 0x114 */ {kKeyNone}, // VK_CAPITAL + /* 0x115 */ {kKeyHangul}, // VK_HANGUL + /* 0x116 */ {kKeyNone}, // undefined + /* 0x117 */ {kKeyNone}, // VK_JUNJA + /* 0x118 */ {kKeyNone}, // VK_FINAL + /* 0x119 */ {kKeyHanja}, // VK_HANJA + /* 0x11a */ {kKeyNone}, // undefined + /* 0x11b */ {kKeyNone}, // VK_ESCAPE + /* 0x11c */ {kKeyNone}, // VK_CONVERT + /* 0x11d */ {kKeyNone}, // VK_NONCONVERT + /* 0x11e */ {kKeyNone}, // VK_ACCEPT + /* 0x11f */ {kKeyNone}, // VK_MODECHANGE + /* 0x120 */ {kKeyNone}, // VK_SPACE + /* 0x121 */ {kKeyPageUp}, // VK_PRIOR + /* 0x122 */ {kKeyPageDown}, // VK_NEXT + /* 0x123 */ {kKeyEnd}, // VK_END + /* 0x124 */ {kKeyHome}, // VK_HOME + /* 0x125 */ {kKeyLeft}, // VK_LEFT + /* 0x126 */ {kKeyUp}, // VK_UP + /* 0x127 */ {kKeyRight}, // VK_RIGHT + /* 0x128 */ {kKeyDown}, // VK_DOWN + /* 0x129 */ {kKeySelect}, // VK_SELECT + /* 0x12a */ {kKeyNone}, // VK_PRINT + /* 0x12b */ {kKeyExecute}, // VK_EXECUTE + /* 0x12c */ {kKeyPrint}, // VK_SNAPSHOT + /* 0x12d */ {kKeyInsert}, // VK_INSERT + /* 0x12e */ {kKeyDelete}, // VK_DELETE + /* 0x12f */ {kKeyHelp}, // VK_HELP + /* 0x130 */ {kKeyNone}, // VK_0 + /* 0x131 */ {kKeyNone}, // VK_1 + /* 0x132 */ {kKeyNone}, // VK_2 + /* 0x133 */ {kKeyNone}, // VK_3 + /* 0x134 */ {kKeyNone}, // VK_4 + /* 0x135 */ {kKeyNone}, // VK_5 + /* 0x136 */ {kKeyNone}, // VK_6 + /* 0x137 */ {kKeyNone}, // VK_7 + /* 0x138 */ {kKeyNone}, // VK_8 + /* 0x139 */ {kKeyNone}, // VK_9 + /* 0x13a */ {kKeyNone}, // undefined + /* 0x13b */ {kKeyNone}, // undefined + /* 0x13c */ {kKeyNone}, // undefined + /* 0x13d */ {kKeyNone}, // undefined + /* 0x13e */ {kKeyNone}, // undefined + /* 0x13f */ {kKeyNone}, // undefined + /* 0x140 */ {kKeyNone}, // undefined + /* 0x141 */ {kKeyNone}, // VK_A + /* 0x142 */ {kKeyNone}, // VK_B + /* 0x143 */ {kKeyNone}, // VK_C + /* 0x144 */ {kKeyNone}, // VK_D + /* 0x145 */ {kKeyNone}, // VK_E + /* 0x146 */ {kKeyNone}, // VK_F + /* 0x147 */ {kKeyNone}, // VK_G + /* 0x148 */ {kKeyNone}, // VK_H + /* 0x149 */ {kKeyNone}, // VK_I + /* 0x14a */ {kKeyNone}, // VK_J + /* 0x14b */ {kKeyNone}, // VK_K + /* 0x14c */ {kKeyNone}, // VK_L + /* 0x14d */ {kKeyNone}, // VK_M + /* 0x14e */ {kKeyNone}, // VK_N + /* 0x14f */ {kKeyNone}, // VK_O + /* 0x150 */ {kKeyNone}, // VK_P + /* 0x151 */ {kKeyNone}, // VK_Q + /* 0x152 */ {kKeyNone}, // VK_R + /* 0x153 */ {kKeyNone}, // VK_S + /* 0x154 */ {kKeyNone}, // VK_T + /* 0x155 */ {kKeyNone}, // VK_U + /* 0x156 */ {kKeyNone}, // VK_V + /* 0x157 */ {kKeyNone}, // VK_W + /* 0x158 */ {kKeyNone}, // VK_X + /* 0x159 */ {kKeyNone}, // VK_Y + /* 0x15a */ {kKeyNone}, // VK_Z + /* 0x15b */ {kKeySuper_L}, // VK_LWIN + /* 0x15c */ {kKeySuper_R}, // VK_RWIN + /* 0x15d */ {kKeyMenu}, // VK_APPS + /* 0x15e */ {kKeyNone}, // undefined + /* 0x15f */ {kKeyNone}, // VK_SLEEP + /* 0x160 */ {kKeyNone}, // VK_NUMPAD0 + /* 0x161 */ {kKeyNone}, // VK_NUMPAD1 + /* 0x162 */ {kKeyNone}, // VK_NUMPAD2 + /* 0x163 */ {kKeyNone}, // VK_NUMPAD3 + /* 0x164 */ {kKeyNone}, // VK_NUMPAD4 + /* 0x165 */ {kKeyNone}, // VK_NUMPAD5 + /* 0x166 */ {kKeyNone}, // VK_NUMPAD6 + /* 0x167 */ {kKeyNone}, // VK_NUMPAD7 + /* 0x168 */ {kKeyNone}, // VK_NUMPAD8 + /* 0x169 */ {kKeyNone}, // VK_NUMPAD9 + /* 0x16a */ {kKeyNone}, // VK_MULTIPLY + /* 0x16b */ {kKeyNone}, // VK_ADD + /* 0x16c */ {kKeyKP_Separator}, // VK_SEPARATOR + /* 0x16d */ {kKeyNone}, // VK_SUBTRACT + /* 0x16e */ {kKeyNone}, // VK_DECIMAL + /* 0x16f */ {kKeyKP_Divide}, // VK_DIVIDE + /* 0x170 */ {kKeyNone}, // VK_F1 + /* 0x171 */ {kKeyNone}, // VK_F2 + /* 0x172 */ {kKeyNone}, // VK_F3 + /* 0x173 */ {kKeyNone}, // VK_F4 + /* 0x174 */ {kKeyNone}, // VK_F5 + /* 0x175 */ {kKeyNone}, // VK_F6 + /* 0x176 */ {kKeyNone}, // VK_F7 + /* 0x177 */ {kKeyNone}, // VK_F8 + /* 0x178 */ {kKeyNone}, // VK_F9 + /* 0x179 */ {kKeyNone}, // VK_F10 + /* 0x17a */ {kKeyNone}, // VK_F11 + /* 0x17b */ {kKeyNone}, // VK_F12 + /* 0x17c */ {kKeyF13}, // VK_F13 + /* 0x17d */ {kKeyF14}, // VK_F14 + /* 0x17e */ {kKeyF15}, // VK_F15 + /* 0x17f */ {kKeyF16}, // VK_F16 + /* 0x180 */ {kKeyF17}, // VK_F17 + /* 0x181 */ {kKeyF18}, // VK_F18 + /* 0x182 */ {kKeyF19}, // VK_F19 + /* 0x183 */ {kKeyF20}, // VK_F20 + /* 0x184 */ {kKeyF21}, // VK_F21 + /* 0x185 */ {kKeyF22}, // VK_F22 + /* 0x186 */ {kKeyF23}, // VK_F23 + /* 0x187 */ {kKeyF24}, // VK_F24 + /* 0x188 */ {kKeyNone}, // unassigned + /* 0x189 */ {kKeyNone}, // unassigned + /* 0x18a */ {kKeyNone}, // unassigned + /* 0x18b */ {kKeyNone}, // unassigned + /* 0x18c */ {kKeyNone}, // unassigned + /* 0x18d */ {kKeyNone}, // unassigned + /* 0x18e */ {kKeyNone}, // unassigned + /* 0x18f */ {kKeyNone}, // unassigned + /* 0x190 */ {kKeyNumLock}, // VK_NUMLOCK + /* 0x191 */ {kKeyNone}, // VK_SCROLL + /* 0x192 */ {kKeyNone}, // unassigned + /* 0x193 */ {kKeyNone}, // unassigned + /* 0x194 */ {kKeyNone}, // unassigned + /* 0x195 */ {kKeyNone}, // unassigned + /* 0x196 */ {kKeyNone}, // unassigned + /* 0x197 */ {kKeyNone}, // unassigned + /* 0x198 */ {kKeyNone}, // unassigned + /* 0x199 */ {kKeyNone}, // unassigned + /* 0x19a */ {kKeyNone}, // unassigned + /* 0x19b */ {kKeyNone}, // unassigned + /* 0x19c */ {kKeyNone}, // unassigned + /* 0x19d */ {kKeyNone}, // unassigned + /* 0x19e */ {kKeyNone}, // unassigned + /* 0x19f */ {kKeyNone}, // unassigned + /* 0x1a0 */ {kKeyShift_L}, // VK_LSHIFT + /* 0x1a1 */ {kKeyShift_R}, // VK_RSHIFT + /* 0x1a2 */ {kKeyControl_L}, // VK_LCONTROL + /* 0x1a3 */ {kKeyControl_R}, // VK_RCONTROL + /* 0x1a4 */ {kKeyAlt_L}, // VK_LMENU + /* 0x1a5 */ {kKeyAlt_R}, // VK_RMENU + /* 0x1a6 */ {kKeyWWWBack}, // VK_BROWSER_BACK + /* 0x1a7 */ {kKeyWWWForward}, // VK_BROWSER_FORWARD + /* 0x1a8 */ {kKeyWWWRefresh}, // VK_BROWSER_REFRESH + /* 0x1a9 */ {kKeyWWWStop}, // VK_BROWSER_STOP + /* 0x1aa */ {kKeyWWWSearch}, // VK_BROWSER_SEARCH + /* 0x1ab */ {kKeyWWWFavorites}, // VK_BROWSER_FAVORITES + /* 0x1ac */ {kKeyWWWHome}, // VK_BROWSER_HOME + /* 0x1ad */ {kKeyAudioMute}, // VK_VOLUME_MUTE + /* 0x1ae */ {kKeyAudioDown}, // VK_VOLUME_DOWN + /* 0x1af */ {kKeyAudioUp}, // VK_VOLUME_UP + /* 0x1b0 */ {kKeyAudioNext}, // VK_MEDIA_NEXT_TRACK + /* 0x1b1 */ {kKeyAudioPrev}, // VK_MEDIA_PREV_TRACK + /* 0x1b2 */ {kKeyAudioStop}, // VK_MEDIA_STOP + /* 0x1b3 */ {kKeyAudioPlay}, // VK_MEDIA_PLAY_PAUSE + /* 0x1b4 */ {kKeyAppMail}, // VK_LAUNCH_MAIL + /* 0x1b5 */ {kKeyAppMedia}, // VK_LAUNCH_MEDIA_SELECT + /* 0x1b6 */ {kKeyAppUser1}, // VK_LAUNCH_APP1 + /* 0x1b7 */ {kKeyAppUser2}, // VK_LAUNCH_APP2 + /* 0x1b8 */ {kKeyNone}, // unassigned + /* 0x1b9 */ {kKeyNone}, // unassigned + /* 0x1ba */ {kKeyNone}, // OEM specific + /* 0x1bb */ {kKeyNone}, // OEM specific + /* 0x1bc */ {kKeyNone}, // OEM specific + /* 0x1bd */ {kKeyNone}, // OEM specific + /* 0x1be */ {kKeyNone}, // OEM specific + /* 0x1bf */ {kKeyNone}, // OEM specific + /* 0x1c0 */ {kKeyNone}, // OEM specific + /* 0x1c1 */ {kKeyNone}, // unassigned + /* 0x1c2 */ {kKeyNone}, // unassigned + /* 0x1c3 */ {kKeyNone}, // unassigned + /* 0x1c4 */ {kKeyNone}, // unassigned + /* 0x1c5 */ {kKeyNone}, // unassigned + /* 0x1c6 */ {kKeyNone}, // unassigned + /* 0x1c7 */ {kKeyNone}, // unassigned + /* 0x1c8 */ {kKeyNone}, // unassigned + /* 0x1c9 */ {kKeyNone}, // unassigned + /* 0x1ca */ {kKeyNone}, // unassigned + /* 0x1cb */ {kKeyNone}, // unassigned + /* 0x1cc */ {kKeyNone}, // unassigned + /* 0x1cd */ {kKeyNone}, // unassigned + /* 0x1ce */ {kKeyNone}, // unassigned + /* 0x1cf */ {kKeyNone}, // unassigned + /* 0x1d0 */ {kKeyNone}, // unassigned + /* 0x1d1 */ {kKeyNone}, // unassigned + /* 0x1d2 */ {kKeyNone}, // unassigned + /* 0x1d3 */ {kKeyNone}, // unassigned + /* 0x1d4 */ {kKeyNone}, // unassigned + /* 0x1d5 */ {kKeyNone}, // unassigned + /* 0x1d6 */ {kKeyNone}, // unassigned + /* 0x1d7 */ {kKeyNone}, // unassigned + /* 0x1d8 */ {kKeyNone}, // unassigned + /* 0x1d9 */ {kKeyNone}, // unassigned + /* 0x1da */ {kKeyNone}, // unassigned + /* 0x1db */ {kKeyNone}, // OEM specific + /* 0x1dc */ {kKeyNone}, // OEM specific + /* 0x1dd */ {kKeyNone}, // OEM specific + /* 0x1de */ {kKeyNone}, // OEM specific + /* 0x1df */ {kKeyNone}, // OEM specific + /* 0x1e0 */ {kKeyNone}, // OEM specific + /* 0x1e1 */ {kKeyNone}, // OEM specific + /* 0x1e2 */ {kKeyNone}, // OEM specific + /* 0x1e3 */ {kKeyNone}, // OEM specific + /* 0x1e4 */ {kKeyNone}, // OEM specific + /* 0x1e5 */ {kKeyNone}, // unassigned + /* 0x1e6 */ {kKeyNone}, // OEM specific + /* 0x1e7 */ {kKeyNone}, // unassigned + /* 0x1e8 */ {kKeyNone}, // unassigned + /* 0x1e9 */ {kKeyNone}, // OEM specific + /* 0x1ea */ {kKeyNone}, // OEM specific + /* 0x1eb */ {kKeyNone}, // OEM specific + /* 0x1ec */ {kKeyNone}, // OEM specific + /* 0x1ed */ {kKeyNone}, // OEM specific + /* 0x1ee */ {kKeyNone}, // OEM specific + /* 0x1ef */ {kKeyNone}, // OEM specific + /* 0x1f0 */ {kKeyNone}, // OEM specific + /* 0x1f1 */ {kKeyNone}, // OEM specific + /* 0x1f2 */ {kKeyNone}, // VK_OEM_COPY + /* 0x1f3 */ {kKeyNone}, // VK_OEM_AUTO + /* 0x1f4 */ {kKeyNone}, // VK_OEM_ENLW + /* 0x1f5 */ {kKeyNone}, // OEM specific + /* 0x1f6 */ {kKeyNone}, // VK_ATTN + /* 0x1f7 */ {kKeyNone}, // VK_CRSEL + /* 0x1f8 */ {kKeyNone}, // VK_EXSEL + /* 0x1f9 */ {kKeyNone}, // VK_EREOF + /* 0x1fa */ {kKeyNone}, // VK_PLAY + /* 0x1fb */ {kKeyNone}, // VK_ZOOM + /* 0x1fc */ {kKeyNone}, // reserved + /* 0x1fd */ {kKeyNone}, // VK_PA1 + /* 0x1fe */ {kKeyNone}, // VK_OEM_CLEAR + /* 0x1ff */ {kKeyNone} // reserved }; struct Win32Modifiers { public: - UINT m_vk; - KeyModifierMask m_mask; + UINT m_vk; + KeyModifierMask m_mask; }; -static const Win32Modifiers s_modifiers[] = -{ - { VK_SHIFT, KeyModifierShift }, - { VK_LSHIFT, KeyModifierShift }, - { VK_RSHIFT, KeyModifierShift }, - { VK_CONTROL, KeyModifierControl }, - { VK_LCONTROL, KeyModifierControl }, - { VK_RCONTROL, KeyModifierControl }, - { VK_MENU, KeyModifierAlt }, - { VK_LMENU, KeyModifierAlt }, - { VK_RMENU, KeyModifierAlt }, - { VK_LWIN, KeyModifierSuper }, - { VK_RWIN, KeyModifierSuper } -}; +static const Win32Modifiers s_modifiers[] = { + {VK_SHIFT, KeyModifierShift}, {VK_LSHIFT, KeyModifierShift}, + {VK_RSHIFT, KeyModifierShift}, {VK_CONTROL, KeyModifierControl}, + {VK_LCONTROL, KeyModifierControl}, {VK_RCONTROL, KeyModifierControl}, + {VK_MENU, KeyModifierAlt}, {VK_LMENU, KeyModifierAlt}, + {VK_RMENU, KeyModifierAlt}, {VK_LWIN, KeyModifierSuper}, + {VK_RWIN, KeyModifierSuper}}; -MSWindowsKeyState::MSWindowsKeyState( - MSWindowsDesks* desks, void* eventTarget, IEventQueue* events, - std::vector layouts, bool isLangSyncEnabled) : - KeyState(events, std::move(layouts), isLangSyncEnabled), - m_eventTarget(eventTarget), - m_desks(desks), - m_keyLayout(GetKeyboardLayout(0)), - m_fixTimer(NULL), - m_lastDown(0), - m_useSavedModifiers(false), - m_savedModifiers(0), - m_originalSavedModifiers(0), - m_events(events) -{ - init(); +MSWindowsKeyState::MSWindowsKeyState(MSWindowsDesks *desks, void *eventTarget, + IEventQueue *events, + std::vector layouts, + bool isLangSyncEnabled) + : KeyState(events, std::move(layouts), isLangSyncEnabled), + m_eventTarget(eventTarget), m_desks(desks), + m_keyLayout(GetKeyboardLayout(0)), m_fixTimer(NULL), m_lastDown(0), + m_useSavedModifiers(false), m_savedModifiers(0), + m_originalSavedModifiers(0), m_events(events) { + init(); } -MSWindowsKeyState::MSWindowsKeyState( - MSWindowsDesks* desks, void* eventTarget, IEventQueue* events, synergy::KeyMap& keyMap, - std::vector layouts, bool isLangSyncEnabled) : - KeyState(events, keyMap, std::move(layouts), isLangSyncEnabled), - m_eventTarget(eventTarget), - m_desks(desks), - m_keyLayout(GetKeyboardLayout(0)), - m_fixTimer(NULL), - m_lastDown(0), - m_useSavedModifiers(false), - m_savedModifiers(0), - m_originalSavedModifiers(0), - m_events(events) -{ - init(); +MSWindowsKeyState::MSWindowsKeyState(MSWindowsDesks *desks, void *eventTarget, + IEventQueue *events, + synergy::KeyMap &keyMap, + std::vector layouts, + bool isLangSyncEnabled) + : KeyState(events, keyMap, std::move(layouts), isLangSyncEnabled), + m_eventTarget(eventTarget), m_desks(desks), + m_keyLayout(GetKeyboardLayout(0)), m_fixTimer(NULL), m_lastDown(0), + m_useSavedModifiers(false), m_savedModifiers(0), + m_originalSavedModifiers(0), m_events(events) { + init(); } -MSWindowsKeyState::~MSWindowsKeyState() -{ - disable(); +MSWindowsKeyState::~MSWindowsKeyState() { disable(); } + +void MSWindowsKeyState::init() { + // look up symbol that's available on winNT family but not win95 + HMODULE userModule = GetModuleHandle("user32.dll"); + m_ToUnicodeEx = (ToUnicodeEx_t)GetProcAddress(userModule, "ToUnicodeEx"); } -void -MSWindowsKeyState::init() -{ - // look up symbol that's available on winNT family but not win95 - HMODULE userModule = GetModuleHandle("user32.dll"); - m_ToUnicodeEx = (ToUnicodeEx_t)GetProcAddress(userModule, "ToUnicodeEx"); +void MSWindowsKeyState::disable() { + if (m_fixTimer != NULL) { + m_events->removeHandler(Event::kTimer, m_fixTimer); + m_events->deleteTimer(m_fixTimer); + m_fixTimer = NULL; + } + m_lastDown = 0; } -void -MSWindowsKeyState::disable() -{ - if (m_fixTimer != NULL) { - m_events->removeHandler(Event::kTimer, m_fixTimer); - m_events->deleteTimer(m_fixTimer); - m_fixTimer = NULL; - } - m_lastDown = 0; +KeyButton MSWindowsKeyState::virtualKeyToButton(UINT virtualKey) const { + return m_virtualKeyToButton[virtualKey & 0xffu]; } -KeyButton -MSWindowsKeyState::virtualKeyToButton(UINT virtualKey) const -{ - return m_virtualKeyToButton[virtualKey & 0xffu]; +void MSWindowsKeyState::setKeyLayout(HKL keyLayout) { m_keyLayout = keyLayout; } + +bool MSWindowsKeyState::testAutoRepeat(bool press, bool isRepeat, + KeyButton button) { + if (!isRepeat) { + isRepeat = (press && m_lastDown != 0 && button == m_lastDown); + } + if (press) { + m_lastDown = button; + } else { + m_lastDown = 0; + } + return isRepeat; } -void -MSWindowsKeyState::setKeyLayout(HKL keyLayout) -{ - m_keyLayout = keyLayout; +void MSWindowsKeyState::saveModifiers() { + m_savedModifiers = getActiveModifiers(); + m_originalSavedModifiers = m_savedModifiers; } -bool -MSWindowsKeyState::testAutoRepeat(bool press, bool isRepeat, KeyButton button) -{ - if (!isRepeat) { - isRepeat = (press && m_lastDown != 0 && button == m_lastDown); - } - if (press) { - m_lastDown = button; - } - else { - m_lastDown = 0; - } - return isRepeat; +void MSWindowsKeyState::useSavedModifiers(bool enable) { + if (enable != m_useSavedModifiers) { + m_useSavedModifiers = enable; + if (!m_useSavedModifiers) { + // transfer any modifier state changes to KeyState's state + KeyModifierMask mask = m_originalSavedModifiers ^ m_savedModifiers; + getActiveModifiersRValue() = + (getActiveModifiers() & ~mask) | (m_savedModifiers & mask); + } + } } -void -MSWindowsKeyState::saveModifiers() -{ - m_savedModifiers = getActiveModifiers(); - m_originalSavedModifiers = m_savedModifiers; +KeyID MSWindowsKeyState::mapKeyFromEvent(WPARAM charAndVirtKey, LPARAM info, + KeyModifierMask *maskOut) const { + static const KeyModifierMask s_controlAlt = + KeyModifierControl | KeyModifierAlt; + + // extract character, virtual key, and if we didn't use AltGr + auto wc = static_cast((charAndVirtKey & 0xffffu)); + UINT vkCode = ((charAndVirtKey >> 16) & 0xffu); + bool noAltGr = ((charAndVirtKey & 0xff000000u) != 0); + + // handle some keys via table lookup + KeyID id = getKeyID(vkCode, (KeyButton)((info >> 16) & 0x1ffu)); + + // check if not in table; map character to key id + if (id == kKeyNone && wc != 0) { + // UTF16 + id = static_cast(wc) & 0xffffu; + } + + // set modifier mask + if (maskOut != NULL) { + KeyModifierMask active = getActiveModifiers(); + if (!noAltGr && (active & s_controlAlt) == s_controlAlt) { + // if !noAltGr then we're only interested in matching the + // key, not the AltGr. AltGr is down (i.e. control and alt + // are down) but we don't want the client to have to match + // that so we clear it. + active &= ~s_controlAlt; + } + if (id == kKeyHangul) { + // If shift-space is used to change input mode, clear shift modifier. + active &= ~KeyModifierShift; + } + *maskOut = active; + } + + return id; } -void -MSWindowsKeyState::useSavedModifiers(bool enable) -{ - if (enable != m_useSavedModifiers) { - m_useSavedModifiers = enable; - if (!m_useSavedModifiers) { - // transfer any modifier state changes to KeyState's state - KeyModifierMask mask = m_originalSavedModifiers ^ m_savedModifiers; - getActiveModifiersRValue() = - (getActiveModifiers() & ~mask) | (m_savedModifiers & mask); - } - } +bool MSWindowsKeyState::didGroupsChange() const { + GroupList groups; + return (getGroups(groups) && groups != m_groups); } -KeyID -MSWindowsKeyState::mapKeyFromEvent(WPARAM charAndVirtKey, - LPARAM info, KeyModifierMask* maskOut) const -{ - static const KeyModifierMask s_controlAlt = - KeyModifierControl | KeyModifierAlt; - - // extract character, virtual key, and if we didn't use AltGr - auto wc = static_cast((charAndVirtKey & 0xffffu)); - UINT vkCode = ((charAndVirtKey >> 16) & 0xffu); - bool noAltGr = ((charAndVirtKey & 0xff000000u) != 0); - - // handle some keys via table lookup - KeyID id = getKeyID(vkCode, (KeyButton)((info >> 16) & 0x1ffu)); - - // check if not in table; map character to key id - if (id == kKeyNone && wc != 0) { - // UTF16 - id = static_cast(wc) & 0xffffu; - } - - // set modifier mask - if (maskOut != NULL) { - KeyModifierMask active = getActiveModifiers(); - if (!noAltGr && (active & s_controlAlt) == s_controlAlt) { - // if !noAltGr then we're only interested in matching the - // key, not the AltGr. AltGr is down (i.e. control and alt - // are down) but we don't want the client to have to match - // that so we clear it. - active &= ~s_controlAlt; - } - if (id == kKeyHangul) { - // If shift-space is used to change input mode, clear shift modifier. - active &= ~KeyModifierShift; - } - *maskOut = active; - } - - return id; +UINT MSWindowsKeyState::mapKeyToVirtualKey(KeyID key) const { + if (key == kKeyNone) { + return 0; + } + KeyToVKMap::const_iterator i = m_keyToVKMap.find(key); + if (i == m_keyToVKMap.end()) { + return 0; + } else { + return i->second; + } } -bool -MSWindowsKeyState::didGroupsChange() const -{ - GroupList groups; - return (getGroups(groups) && groups != m_groups); +void MSWindowsKeyState::onKey(KeyButton button, bool down, + KeyModifierMask newState) { + KeyState::onKey(button, down, newState); } -UINT -MSWindowsKeyState::mapKeyToVirtualKey(KeyID key) const -{ - if (key == kKeyNone) { - return 0; - } - KeyToVKMap::const_iterator i = m_keyToVKMap.find(key); - if (i == m_keyToVKMap.end()) { - return 0; - } - else { - return i->second; - } +void MSWindowsKeyState::sendKeyEvent(void *target, bool press, + bool isAutoRepeat, KeyID key, + KeyModifierMask mask, SInt32 count, + KeyButton button) { + if (press || isAutoRepeat) { + // send key + if (press && !isAutoRepeat) { + KeyState::sendKeyEvent(target, true, false, key, mask, 1, button); + if (count > 0) { + --count; + } + } + if (count >= 1) { + KeyState::sendKeyEvent(target, true, true, key, mask, count, button); + } + } else { + // do key up + KeyState::sendKeyEvent(target, false, false, key, mask, 1, button); + } } -void -MSWindowsKeyState::onKey(KeyButton button, bool down, KeyModifierMask newState) -{ - KeyState::onKey(button, down, newState); +void MSWindowsKeyState::fakeKeyDown(KeyID id, KeyModifierMask mask, + KeyButton button, const String &lang) { + KeyState::fakeKeyDown(id, mask, button, lang); } -void -MSWindowsKeyState::sendKeyEvent(void* target, - bool press, bool isAutoRepeat, - KeyID key, KeyModifierMask mask, - SInt32 count, KeyButton button) -{ - if (press || isAutoRepeat) { - // send key - if (press && !isAutoRepeat) { - KeyState::sendKeyEvent(target, true, false, - key, mask, 1, button); - if (count > 0) { - --count; - } - } - if (count >= 1) { - KeyState::sendKeyEvent(target, true, true, - key, mask, count, button); - } - } - else { - // do key up - KeyState::sendKeyEvent(target, false, false, key, mask, 1, button); - } +bool MSWindowsKeyState::fakeKeyRepeat(KeyID id, KeyModifierMask mask, + SInt32 count, KeyButton button, + const String &lang) { + return KeyState::fakeKeyRepeat(id, mask, count, button, lang); } -void -MSWindowsKeyState::fakeKeyDown(KeyID id, KeyModifierMask mask, - KeyButton button, const String& lang) -{ - KeyState::fakeKeyDown(id, mask, button, lang); +bool MSWindowsKeyState::fakeCtrlAltDel() { + // to fake ctrl+alt+del on the NT family we broadcast a suitable + // hotkey to all windows on the winlogon desktop. however, the + // current thread must be on that desktop to do the broadcast + // and we can't switch just any thread because some own windows + // or hooks. so start a new thread to do the real work. + HANDLE hEvtSendSas = OpenEvent(EVENT_MODIFY_STATE, FALSE, "Global\\SendSAS"); + if (hEvtSendSas) { + LOG((CLOG_DEBUG "found the SendSAS event - signaling my launcher to " + "simulate ctrl+alt+del")); + SetEvent(hEvtSendSas); + CloseHandle(hEvtSendSas); + } else { + Thread cad(new FunctionJob(&MSWindowsKeyState::ctrlAltDelThread)); + cad.wait(); + } + + return true; } -bool -MSWindowsKeyState::fakeKeyRepeat(KeyID id, KeyModifierMask mask, - SInt32 count, KeyButton button, const String& lang) -{ - return KeyState::fakeKeyRepeat(id, mask, count, button, lang); +void MSWindowsKeyState::ctrlAltDelThread(void *) { + // get the Winlogon desktop at whatever privilege we can + HDESK desk = OpenDesktop("Winlogon", 0, FALSE, MAXIMUM_ALLOWED); + if (desk != NULL) { + if (SetThreadDesktop(desk)) { + PostMessage(HWND_BROADCAST, WM_HOTKEY, 0, + MAKELPARAM(MOD_CONTROL | MOD_ALT, VK_DELETE)); + } else { + LOG((CLOG_DEBUG "can't switch to Winlogon desk: %d", GetLastError())); + } + CloseDesktop(desk); + } else { + LOG((CLOG_DEBUG "can't open Winlogon desk: %d", GetLastError())); + } } -bool -MSWindowsKeyState::fakeCtrlAltDel() -{ - // to fake ctrl+alt+del on the NT family we broadcast a suitable - // hotkey to all windows on the winlogon desktop. however, the - // current thread must be on that desktop to do the broadcast - // and we can't switch just any thread because some own windows - // or hooks. so start a new thread to do the real work. - HANDLE hEvtSendSas = OpenEvent(EVENT_MODIFY_STATE, FALSE, "Global\\SendSAS"); - if (hEvtSendSas) { - LOG((CLOG_DEBUG "found the SendSAS event - signaling my launcher to simulate ctrl+alt+del")); - SetEvent(hEvtSendSas); - CloseHandle(hEvtSendSas); - } - else { - Thread cad(new FunctionJob(&MSWindowsKeyState::ctrlAltDelThread)); - cad.wait(); - } +KeyModifierMask MSWindowsKeyState::pollActiveModifiers() const { + KeyModifierMask state = 0; - return true; + // get non-toggle modifiers from our own shadow key state + for (size_t i = 0; i < sizeof(s_modifiers) / sizeof(s_modifiers[0]); ++i) { + KeyButton button = virtualKeyToButton(s_modifiers[i].m_vk); + if (button != 0 && isKeyDown(button)) { + state |= s_modifiers[i].m_mask; + } + } + + // we can get toggle modifiers from the system + if ((GetKeyState(VK_CAPITAL) & 0x01) != 0) { + state |= KeyModifierCapsLock; + } + if ((GetKeyState(VK_NUMLOCK) & 0x01) != 0) { + state |= KeyModifierNumLock; + } + if ((GetKeyState(VK_SCROLL) & 0x01) != 0) { + state |= KeyModifierScrollLock; + } + + return state; } -void -MSWindowsKeyState::ctrlAltDelThread(void*) -{ - // get the Winlogon desktop at whatever privilege we can - HDESK desk = OpenDesktop("Winlogon", 0, FALSE, MAXIMUM_ALLOWED); - if (desk != NULL) { - if (SetThreadDesktop(desk)) { - PostMessage(HWND_BROADCAST, WM_HOTKEY, 0, - MAKELPARAM(MOD_CONTROL | MOD_ALT, VK_DELETE)); - } - else { - LOG((CLOG_DEBUG "can't switch to Winlogon desk: %d", GetLastError())); - } - CloseDesktop(desk); - } - else { - LOG((CLOG_DEBUG "can't open Winlogon desk: %d", GetLastError())); - } +SInt32 MSWindowsKeyState::pollActiveGroup() const { + // determine the thread that'll receive this event + HWND targetWindow = GetForegroundWindow(); + DWORD targetThread = GetWindowThreadProcessId(targetWindow, NULL); + + // get keyboard layout for the thread + HKL hkl = GetKeyboardLayout(targetThread); + + if (!hkl) { + // GetKeyboardLayout failed. Maybe targetWindow is a console window. + // We're getting the keyboard layout of the desktop instead. + targetWindow = GetDesktopWindow(); + targetThread = GetWindowThreadProcessId(targetWindow, NULL); + hkl = GetKeyboardLayout(targetThread); + } + + // get group + GroupMap::const_iterator i = m_groupMap.find(hkl); + if (i == m_groupMap.end()) { + LOG((CLOG_DEBUG1 "can't find keyboard layout %08x", hkl)); + return 0; + } + + return i->second; } -KeyModifierMask -MSWindowsKeyState::pollActiveModifiers() const -{ - KeyModifierMask state = 0; - - // get non-toggle modifiers from our own shadow key state - for (size_t i = 0; i < sizeof(s_modifiers) / sizeof(s_modifiers[0]); ++i) { - KeyButton button = virtualKeyToButton(s_modifiers[i].m_vk); - if (button != 0 && isKeyDown(button)) { - state |= s_modifiers[i].m_mask; - } - } - - // we can get toggle modifiers from the system - if ((GetKeyState(VK_CAPITAL) & 0x01) != 0) { - state |= KeyModifierCapsLock; - } - if ((GetKeyState(VK_NUMLOCK) & 0x01) != 0) { - state |= KeyModifierNumLock; - } - if ((GetKeyState(VK_SCROLL) & 0x01) != 0) { - state |= KeyModifierScrollLock; - } - - return state; +void MSWindowsKeyState::pollPressedKeys(KeyButtonSet &pressedKeys) const { + BYTE keyState[256]; + if (!GetKeyboardState(keyState)) { + LOG((CLOG_WARN "keyboard state is unexpected")); + LOG((CLOG_DEBUG + "function 'GetKeyboardState' returned false on 'pollPressedKeys'")); + return; + } + for (KeyButton i = 1; i < 256; ++i) { + if ((keyState[i] & 0x80) != 0) { + KeyButton keyButton = virtualKeyToButton(i); + if (keyButton != 0) { + pressedKeys.insert(keyButton); + } + } + } } -SInt32 -MSWindowsKeyState::pollActiveGroup() const -{ - // determine the thread that'll receive this event - HWND targetWindow = GetForegroundWindow(); - DWORD targetThread = GetWindowThreadProcessId(targetWindow, NULL); +void MSWindowsKeyState::getKeyMap(synergy::KeyMap &keyMap) { + // update keyboard groups + if (getGroups(m_groups)) { + m_groupMap.clear(); + SInt32 numGroups = (SInt32)m_groups.size(); + for (SInt32 g = 0; g < numGroups; ++g) { + m_groupMap[m_groups[g]] = g; + } + } + HKL activeLayout = GetKeyboardLayout(0); - // get keyboard layout for the thread - HKL hkl = GetKeyboardLayout(targetThread); + // clear table + memset(m_virtualKeyToButton, 0, sizeof(m_virtualKeyToButton)); + m_keyToVKMap.clear(); - if (!hkl) { - // GetKeyboardLayout failed. Maybe targetWindow is a console window. - // We're getting the keyboard layout of the desktop instead. - targetWindow = GetDesktopWindow(); - targetThread = GetWindowThreadProcessId(targetWindow, NULL); - hkl = GetKeyboardLayout(targetThread); - } + synergy::KeyMap::KeyItem item; + SInt32 numGroups = (SInt32)m_groups.size(); + for (SInt32 g = 0; g < numGroups; ++g) { + item.m_group = g; + ActivateKeyboardLayout(m_groups[g], 0); - // get group - GroupMap::const_iterator i = m_groupMap.find(hkl); - if (i == m_groupMap.end()) { - LOG((CLOG_DEBUG1 "can't find keyboard layout %08x", hkl)); - return 0; - } + // clear tables + memset(m_buttonToVK, 0, sizeof(m_buttonToVK)); + memset(m_buttonToNumpadVK, 0, sizeof(m_buttonToNumpadVK)); - return i->second; -} + // map buttons (scancodes) to virtual keys + for (KeyButton i = 1; i < 256; ++i) { + UINT vk = MapVirtualKey(i, 1); + if (vk == 0) { + // unmapped + continue; + } -void -MSWindowsKeyState::pollPressedKeys(KeyButtonSet& pressedKeys) const -{ - BYTE keyState[256]; - if (!GetKeyboardState(keyState)) { - LOG((CLOG_WARN "keyboard state is unexpected")); - LOG((CLOG_DEBUG "function 'GetKeyboardState' returned false on 'pollPressedKeys'")); - return; - } - for (KeyButton i = 1; i < 256; ++i) { - if ((keyState[i] & 0x80) != 0) { - KeyButton keyButton = virtualKeyToButton(i); - if (keyButton != 0) { - pressedKeys.insert(keyButton); - } - } - } -} + // deal with certain virtual keys specially + switch (vk) { + case VK_SHIFT: + // this is important for sending the correct modifier to the + // client, a patch from bug #242 (right shift broken for ms + // remote desktop) removed this to just use left shift, which + // caused bug #2799 (right shift broken for osx). + // we must not repeat this same mistake and must fix platform + // specific bugs in code that only affects that platform. + if (MapVirtualKey(VK_RSHIFT, 0) == i) { + vk = VK_RSHIFT; + } else { + vk = VK_LSHIFT; + } + break; -void -MSWindowsKeyState::getKeyMap(synergy::KeyMap& keyMap) -{ - // update keyboard groups - if (getGroups(m_groups)) { - m_groupMap.clear(); - SInt32 numGroups = (SInt32)m_groups.size(); - for (SInt32 g = 0; g < numGroups; ++g) { - m_groupMap[m_groups[g]] = g; - } - } - HKL activeLayout = GetKeyboardLayout(0); + case VK_CONTROL: + vk = VK_LCONTROL; + break; - // clear table - memset(m_virtualKeyToButton, 0, sizeof(m_virtualKeyToButton)); - m_keyToVKMap.clear(); + case VK_MENU: + vk = VK_LMENU; + break; - synergy::KeyMap::KeyItem item; - SInt32 numGroups = (SInt32)m_groups.size(); - for (SInt32 g = 0; g < numGroups; ++g) { - item.m_group = g; - ActivateKeyboardLayout(m_groups[g], 0); + case VK_NUMLOCK: + vk = VK_PAUSE; + break; - // clear tables - memset(m_buttonToVK, 0, sizeof(m_buttonToVK)); - memset(m_buttonToNumpadVK, 0, sizeof(m_buttonToNumpadVK)); + case VK_NUMPAD0: + case VK_NUMPAD1: + case VK_NUMPAD2: + case VK_NUMPAD3: + case VK_NUMPAD4: + case VK_NUMPAD5: + case VK_NUMPAD6: + case VK_NUMPAD7: + case VK_NUMPAD8: + case VK_NUMPAD9: + case VK_DECIMAL: + // numpad keys are saved in their own table + m_buttonToNumpadVK[i] = vk; + continue; - // map buttons (scancodes) to virtual keys - for (KeyButton i = 1; i < 256; ++i) { - UINT vk = MapVirtualKey(i, 1); - if (vk == 0) { - // unmapped - continue; - } + case VK_LWIN: + case VK_RWIN: + break; - // deal with certain virtual keys specially - switch (vk) { - case VK_SHIFT: - // this is important for sending the correct modifier to the - // client, a patch from bug #242 (right shift broken for ms - // remote desktop) removed this to just use left shift, which - // caused bug #2799 (right shift broken for osx). - // we must not repeat this same mistake and must fix platform - // specific bugs in code that only affects that platform. - if (MapVirtualKey(VK_RSHIFT, 0) == i) { - vk = VK_RSHIFT; - } - else { - vk = VK_LSHIFT; - } - break; + case VK_RETURN: + case VK_PRIOR: + case VK_NEXT: + case VK_END: + case VK_HOME: + case VK_LEFT: + case VK_UP: + case VK_RIGHT: + case VK_DOWN: + case VK_INSERT: + case VK_DELETE: + // also add extended key for these + m_buttonToVK[i | 0x100u] = vk; + break; + } - case VK_CONTROL: - vk = VK_LCONTROL; - break; - - case VK_MENU: - vk = VK_LMENU; - break; - - case VK_NUMLOCK: - vk = VK_PAUSE; - break; - - case VK_NUMPAD0: - case VK_NUMPAD1: - case VK_NUMPAD2: - case VK_NUMPAD3: - case VK_NUMPAD4: - case VK_NUMPAD5: - case VK_NUMPAD6: - case VK_NUMPAD7: - case VK_NUMPAD8: - case VK_NUMPAD9: - case VK_DECIMAL: - // numpad keys are saved in their own table - m_buttonToNumpadVK[i] = vk; - continue; - - case VK_LWIN: - case VK_RWIN: - break; - - case VK_RETURN: - case VK_PRIOR: - case VK_NEXT: - case VK_END: - case VK_HOME: - case VK_LEFT: - case VK_UP: - case VK_RIGHT: - case VK_DOWN: - case VK_INSERT: - case VK_DELETE: - // also add extended key for these - m_buttonToVK[i | 0x100u] = vk; - break; - } - - if (m_buttonToVK[i] == 0) { - m_buttonToVK[i] = vk; - } - } - - // now map virtual keys to buttons. multiple virtual keys may map - // to a single button. if the virtual key matches the one in - // m_buttonToVK then we use the button as is. if not then it's - // either a numpad key and we use the button as is or it's an - // extended button. - for (UINT i = 1; i < 255; ++i) { - // skip virtual keys we don't want - switch (i) { - case VK_LBUTTON: - case VK_RBUTTON: - case VK_MBUTTON: - case VK_XBUTTON1: - case VK_XBUTTON2: - case VK_SHIFT: - case VK_CONTROL: - case VK_MENU: - continue; - } - - // get the button - KeyButton button = static_cast(MapVirtualKey(i, 0)); - if (button == 0) { - continue; - } - - // deal with certain virtual keys specially - switch (i) { - case VK_NUMPAD0: - case VK_NUMPAD1: - case VK_NUMPAD2: - case VK_NUMPAD3: - case VK_NUMPAD4: - case VK_NUMPAD5: - case VK_NUMPAD6: - case VK_NUMPAD7: - case VK_NUMPAD8: - case VK_NUMPAD9: - case VK_DECIMAL: - m_buttonToNumpadVK[button] = i; - break; - - default: - // add extended key if virtual keys don't match - if (m_buttonToVK[button] != i) { - m_buttonToVK[button | 0x100u] = i; - } - break; - } - } - - // add the extended printscreen (alt+printscreen) - // or maybe it's the non-extended printscreen? - // scancodes and keyboard inputs are complicated - if (m_buttonToVK[0x54u] == 0) { - m_buttonToVK[0x54u] = VK_SNAPSHOT; - } - - // set virtual key to button table - if (activeLayout == m_groups[g]) { - for (KeyButton i = 0; i < 512; ++i) { - if (m_buttonToVK[i] != 0) { - if (m_virtualKeyToButton[m_buttonToVK[i]] == 0) { - m_virtualKeyToButton[m_buttonToVK[i]] = i; - } - } - if (m_buttonToNumpadVK[i] != 0) { - if (m_virtualKeyToButton[m_buttonToNumpadVK[i]] == 0) { - m_virtualKeyToButton[m_buttonToNumpadVK[i]] = i; - } - } - } - } - - // add numpad keys - for (KeyButton i = 0; i < 512; ++i) { - if (m_buttonToNumpadVK[i] != 0) { - item.m_id = getKeyID(m_buttonToNumpadVK[i], i); - item.m_button = i; - item.m_required = KeyModifierNumLock; - item.m_sensitive = KeyModifierNumLock | KeyModifierShift; - item.m_generates = 0; - item.m_client = m_buttonToNumpadVK[i]; - addKeyEntry(keyMap, item); - } - } - - // add other keys - BYTE keys[256]; - memset(keys, 0, sizeof(keys)); - for (KeyButton i = 0; i < 512; ++i) { - if (m_buttonToVK[i] != 0) { - // initialize item - item.m_id = getKeyID(m_buttonToVK[i], i); - item.m_button = i; - item.m_required = 0; - item.m_sensitive = 0; - item.m_client = m_buttonToVK[i]; - - // get flags for modifier keys - synergy::KeyMap::initModifierKey(item); - - if (item.m_id == 0) { - // translate virtual key to a character with and without - // shift, caps lock, and AltGr. - struct Modifier { - UINT m_vk1; - UINT m_vk2; - BYTE m_state; - KeyModifierMask m_mask; - }; - static const Modifier modifiers[] = { - { VK_SHIFT, VK_SHIFT, 0x80u, KeyModifierShift }, - { VK_CAPITAL, VK_CAPITAL, 0x01u, KeyModifierCapsLock }, - { VK_CONTROL, VK_MENU, 0x80u, KeyModifierControl | - KeyModifierAlt } - }; - static const size_t s_numModifiers = - sizeof(modifiers) / sizeof(modifiers[0]); - static const size_t s_numCombinations = 1 << s_numModifiers; - KeyID id[s_numCombinations]; - - bool anyFound = false; - KeyButton button = static_cast(i & 0xffu); - for (size_t j = 0; j < s_numCombinations; ++j) { - for (size_t k = 0; k < s_numModifiers; ++k) { - //if ((j & (1 << k)) != 0) { - // http://msdn.microsoft.com/en-us/library/ke55d167.aspx - if ((j & (1i64 << k)) != 0) { - keys[modifiers[k].m_vk1] = modifiers[k].m_state; - keys[modifiers[k].m_vk2] = modifiers[k].m_state; - } - else { - keys[modifiers[k].m_vk1] = 0; - keys[modifiers[k].m_vk2] = 0; - } - } - id[j] = getIDForKey(item, button, - m_buttonToVK[i], keys, m_groups[g]); - if (id[j] != 0) { - anyFound = true; - } - } - - if (anyFound) { - // determine what modifiers we're sensitive to. - // we're sensitive if the KeyID changes when the - // modifier does. - item.m_sensitive = 0; - for (size_t k = 0; k < s_numModifiers; ++k) { - for (size_t j = 0; j < s_numCombinations; ++j) { - //if (id[j] != id[j ^ (1u << k)]) { - // http://msdn.microsoft.com/en-us/library/ke55d167.aspx - if (id[j] != id[j ^ (1ui64 << k)]) { - item.m_sensitive |= modifiers[k].m_mask; - break; - } - } - } - - // save each key. the map will automatically discard - // duplicates, like an unshift and shifted version of - // a key that's insensitive to shift. - for (size_t j = 0; j < s_numCombinations; ++j) { - item.m_id = id[j]; - item.m_required = 0; - for (size_t k = 0; k < s_numModifiers; ++k) { - if ((j & (1i64 << k)) != 0) { - item.m_required |= modifiers[k].m_mask; - } - } - addKeyEntry(keyMap, item); - } - } - } - else { - // found in table - switch (m_buttonToVK[i]) { - case VK_TAB: - // add kKeyLeftTab, too - item.m_id = kKeyLeftTab; - item.m_required |= KeyModifierShift; - item.m_sensitive |= KeyModifierShift; - addKeyEntry(keyMap, item); - item.m_id = kKeyTab; - item.m_required &= ~KeyModifierShift; - break; - - case VK_CANCEL: - item.m_required |= KeyModifierControl; - item.m_sensitive |= KeyModifierControl; - break; - - } - - addKeyEntry(keyMap, item); - } - } - } - } - - // restore keyboard layout - ActivateKeyboardLayout(activeLayout, 0); -} - -void -MSWindowsKeyState::fakeKey(const Keystroke& keystroke) -{ - switch (keystroke.m_type) { - case Keystroke::kButton: { - LOG((CLOG_DEBUG1 " %03x (%08x) %s", keystroke.m_data.m_button.m_button, keystroke.m_data.m_button.m_client, keystroke.m_data.m_button.m_press ? "down" : "up")); - KeyButton scanCode = keystroke.m_data.m_button.m_button; - - // windows doesn't send key ups for key repeats - if (keystroke.m_data.m_button.m_repeat && - !keystroke.m_data.m_button.m_press) { - LOG((CLOG_DEBUG1 " discard key repeat release")); - break; - } - - // get the virtual key for the button - WORD vk = (WORD)keystroke.m_data.m_button.m_client; - DWORD flags = 0; - - if (keystroke.m_data.m_button.m_press == false) - flags |= KEYEVENTF_KEYUP; - - // special handling of VK_SNAPSHOT - if (vk == VK_SNAPSHOT) - scanCode = (getActiveModifiers() & KeyModifierAlt) ? 0x54 : 0x137; - - if (scanCode & 0x100) - flags |= KEYEVENTF_EXTENDEDKEY; - - //vk,sc,flags,keystroke.m_data.m_button.m_repeat - - m_desks->fakeKeyEvent(vk, scanCode, flags, keystroke.m_data.m_button.m_repeat); - - // synthesize event - //m_desks->fakeKeyEvent(button, vk, - // keystroke.m_data.m_button.m_press, - // keystroke.m_data.m_button.m_repeat); - break; - } - - case Keystroke::kGroup: - // we don't restore the group. we'd like to but we can't be - // sure the restoring group change will be processed after the - // key events. - if (!keystroke.m_data.m_group.m_restore) { - if (keystroke.m_data.m_group.m_absolute) { - LOG((CLOG_DEBUG1 " group %d", keystroke.m_data.m_group.m_group)); - setWindowGroup(keystroke.m_data.m_group.m_group); - } - else { - LOG((CLOG_DEBUG1 " group %+d", keystroke.m_data.m_group.m_group)); - setWindowGroup(getEffectiveGroup(pollActiveGroup(), - keystroke.m_data.m_group.m_group)); - } - } - break; - } -} - -KeyModifierMask& -MSWindowsKeyState::getActiveModifiersRValue() -{ - if (m_useSavedModifiers) { - return m_savedModifiers; - } - else { - return KeyState::getActiveModifiersRValue(); - } -} - -bool -MSWindowsKeyState::getGroups(GroupList& groups) const -{ - // get keyboard layouts - UInt32 newNumLayouts = GetKeyboardLayoutList(0, NULL); - if (newNumLayouts == 0) { - LOG((CLOG_DEBUG1 "can't get keyboard layouts")); - return false; - } - HKL* newLayouts = new HKL[newNumLayouts]; - newNumLayouts = GetKeyboardLayoutList(newNumLayouts, newLayouts); - if (newNumLayouts == 0) { - LOG((CLOG_DEBUG1 "can't get keyboard layouts")); - delete[] newLayouts; - return false; - } - - groups.clear(); - groups.insert(groups.end(), newLayouts, newLayouts + newNumLayouts); - delete[] newLayouts; - return true; -} - -void -MSWindowsKeyState::setWindowGroup(SInt32 group) -{ - HWND targetWindow = GetForegroundWindow(); - - bool sysCharSet = true; - // XXX -- determine if m_groups[group] can be used with the system - // character set. - - if(!PostMessage(targetWindow, WM_INPUTLANGCHANGEREQUEST, - sysCharSet ? 1 : 0, (LPARAM)m_groups[group])) { - LOG((CLOG_WARN "failed to post change language message")); + if (m_buttonToVK[i] == 0) { + m_buttonToVK[i] = vk; + } } - // XXX -- use a short delay to let the target window process the message - // before it sees the keyboard events. i'm not sure why this is - // necessary since the messages should arrive in order. if we don't - // delay, though, some of our keyboard events may disappear. - Sleep(100); + // now map virtual keys to buttons. multiple virtual keys may map + // to a single button. if the virtual key matches the one in + // m_buttonToVK then we use the button as is. if not then it's + // either a numpad key and we use the button as is or it's an + // extended button. + for (UINT i = 1; i < 255; ++i) { + // skip virtual keys we don't want + switch (i) { + case VK_LBUTTON: + case VK_RBUTTON: + case VK_MBUTTON: + case VK_XBUTTON1: + case VK_XBUTTON2: + case VK_SHIFT: + case VK_CONTROL: + case VK_MENU: + continue; + } + + // get the button + KeyButton button = static_cast(MapVirtualKey(i, 0)); + if (button == 0) { + continue; + } + + // deal with certain virtual keys specially + switch (i) { + case VK_NUMPAD0: + case VK_NUMPAD1: + case VK_NUMPAD2: + case VK_NUMPAD3: + case VK_NUMPAD4: + case VK_NUMPAD5: + case VK_NUMPAD6: + case VK_NUMPAD7: + case VK_NUMPAD8: + case VK_NUMPAD9: + case VK_DECIMAL: + m_buttonToNumpadVK[button] = i; + break; + + default: + // add extended key if virtual keys don't match + if (m_buttonToVK[button] != i) { + m_buttonToVK[button | 0x100u] = i; + } + break; + } + } + + // add the extended printscreen (alt+printscreen) + // or maybe it's the non-extended printscreen? + // scancodes and keyboard inputs are complicated + if (m_buttonToVK[0x54u] == 0) { + m_buttonToVK[0x54u] = VK_SNAPSHOT; + } + + // set virtual key to button table + if (activeLayout == m_groups[g]) { + for (KeyButton i = 0; i < 512; ++i) { + if (m_buttonToVK[i] != 0) { + if (m_virtualKeyToButton[m_buttonToVK[i]] == 0) { + m_virtualKeyToButton[m_buttonToVK[i]] = i; + } + } + if (m_buttonToNumpadVK[i] != 0) { + if (m_virtualKeyToButton[m_buttonToNumpadVK[i]] == 0) { + m_virtualKeyToButton[m_buttonToNumpadVK[i]] = i; + } + } + } + } + + // add numpad keys + for (KeyButton i = 0; i < 512; ++i) { + if (m_buttonToNumpadVK[i] != 0) { + item.m_id = getKeyID(m_buttonToNumpadVK[i], i); + item.m_button = i; + item.m_required = KeyModifierNumLock; + item.m_sensitive = KeyModifierNumLock | KeyModifierShift; + item.m_generates = 0; + item.m_client = m_buttonToNumpadVK[i]; + addKeyEntry(keyMap, item); + } + } + + // add other keys + BYTE keys[256]; + memset(keys, 0, sizeof(keys)); + for (KeyButton i = 0; i < 512; ++i) { + if (m_buttonToVK[i] != 0) { + // initialize item + item.m_id = getKeyID(m_buttonToVK[i], i); + item.m_button = i; + item.m_required = 0; + item.m_sensitive = 0; + item.m_client = m_buttonToVK[i]; + + // get flags for modifier keys + synergy::KeyMap::initModifierKey(item); + + if (item.m_id == 0) { + // translate virtual key to a character with and without + // shift, caps lock, and AltGr. + struct Modifier { + UINT m_vk1; + UINT m_vk2; + BYTE m_state; + KeyModifierMask m_mask; + }; + static const Modifier modifiers[] = { + {VK_SHIFT, VK_SHIFT, 0x80u, KeyModifierShift}, + {VK_CAPITAL, VK_CAPITAL, 0x01u, KeyModifierCapsLock}, + {VK_CONTROL, VK_MENU, 0x80u, + KeyModifierControl | KeyModifierAlt}}; + static const size_t s_numModifiers = + sizeof(modifiers) / sizeof(modifiers[0]); + static const size_t s_numCombinations = 1 << s_numModifiers; + KeyID id[s_numCombinations]; + + bool anyFound = false; + KeyButton button = static_cast(i & 0xffu); + for (size_t j = 0; j < s_numCombinations; ++j) { + for (size_t k = 0; k < s_numModifiers; ++k) { + // if ((j & (1 << k)) != 0) { + // http://msdn.microsoft.com/en-us/library/ke55d167.aspx + if ((j & (1i64 << k)) != 0) { + keys[modifiers[k].m_vk1] = modifiers[k].m_state; + keys[modifiers[k].m_vk2] = modifiers[k].m_state; + } else { + keys[modifiers[k].m_vk1] = 0; + keys[modifiers[k].m_vk2] = 0; + } + } + id[j] = + getIDForKey(item, button, m_buttonToVK[i], keys, m_groups[g]); + if (id[j] != 0) { + anyFound = true; + } + } + + if (anyFound) { + // determine what modifiers we're sensitive to. + // we're sensitive if the KeyID changes when the + // modifier does. + item.m_sensitive = 0; + for (size_t k = 0; k < s_numModifiers; ++k) { + for (size_t j = 0; j < s_numCombinations; ++j) { + // if (id[j] != id[j ^ (1u << k)]) { + // http://msdn.microsoft.com/en-us/library/ke55d167.aspx + if (id[j] != id[j ^ (1ui64 << k)]) { + item.m_sensitive |= modifiers[k].m_mask; + break; + } + } + } + + // save each key. the map will automatically discard + // duplicates, like an unshift and shifted version of + // a key that's insensitive to shift. + for (size_t j = 0; j < s_numCombinations; ++j) { + item.m_id = id[j]; + item.m_required = 0; + for (size_t k = 0; k < s_numModifiers; ++k) { + if ((j & (1i64 << k)) != 0) { + item.m_required |= modifiers[k].m_mask; + } + } + addKeyEntry(keyMap, item); + } + } + } else { + // found in table + switch (m_buttonToVK[i]) { + case VK_TAB: + // add kKeyLeftTab, too + item.m_id = kKeyLeftTab; + item.m_required |= KeyModifierShift; + item.m_sensitive |= KeyModifierShift; + addKeyEntry(keyMap, item); + item.m_id = kKeyTab; + item.m_required &= ~KeyModifierShift; + break; + + case VK_CANCEL: + item.m_required |= KeyModifierControl; + item.m_sensitive |= KeyModifierControl; + break; + } + + addKeyEntry(keyMap, item); + } + } + } + } + + // restore keyboard layout + ActivateKeyboardLayout(activeLayout, 0); } -KeyID -MSWindowsKeyState::getKeyID(UINT virtualKey, KeyButton button) const -{ - // Some virtual keycodes have same values. - // VK_HANGUL == VK_KANA, VK_HANJA == NK_KANJI - // which are used to change the input mode of IME. - // But they have different X11 keysym. So we should distinguish them. - if ((LOWORD(m_keyLayout) & 0xffffu) == 0x0412u) { // 0x0412 : Korean Locale ID - if (virtualKey == VK_HANGUL || virtualKey == VK_HANJA) { - // If shift-space is used to change the input mode, - // the extented bit is not set. So add it to get right key id. - button |= 0x100u; - } - } +void MSWindowsKeyState::fakeKey(const Keystroke &keystroke) { + switch (keystroke.m_type) { + case Keystroke::kButton: { + LOG((CLOG_DEBUG1 " %03x (%08x) %s", keystroke.m_data.m_button.m_button, + keystroke.m_data.m_button.m_client, + keystroke.m_data.m_button.m_press ? "down" : "up")); + KeyButton scanCode = keystroke.m_data.m_button.m_button; - if ((button & 0x100u) != 0) { - virtualKey += 0x100u; - } - return s_virtualKey[virtualKey]; + // windows doesn't send key ups for key repeats + if (keystroke.m_data.m_button.m_repeat && + !keystroke.m_data.m_button.m_press) { + LOG((CLOG_DEBUG1 " discard key repeat release")); + break; + } + + // get the virtual key for the button + WORD vk = (WORD)keystroke.m_data.m_button.m_client; + DWORD flags = 0; + + if (keystroke.m_data.m_button.m_press == false) + flags |= KEYEVENTF_KEYUP; + + // special handling of VK_SNAPSHOT + if (vk == VK_SNAPSHOT) + scanCode = (getActiveModifiers() & KeyModifierAlt) ? 0x54 : 0x137; + + if (scanCode & 0x100) + flags |= KEYEVENTF_EXTENDEDKEY; + + // vk,sc,flags,keystroke.m_data.m_button.m_repeat + + m_desks->fakeKeyEvent(vk, scanCode, flags, + keystroke.m_data.m_button.m_repeat); + + // synthesize event + // m_desks->fakeKeyEvent(button, vk, + // keystroke.m_data.m_button.m_press, + // keystroke.m_data.m_button.m_repeat); + break; + } + + case Keystroke::kGroup: + // we don't restore the group. we'd like to but we can't be + // sure the restoring group change will be processed after the + // key events. + if (!keystroke.m_data.m_group.m_restore) { + if (keystroke.m_data.m_group.m_absolute) { + LOG((CLOG_DEBUG1 " group %d", keystroke.m_data.m_group.m_group)); + setWindowGroup(keystroke.m_data.m_group.m_group); + } else { + LOG((CLOG_DEBUG1 " group %+d", keystroke.m_data.m_group.m_group)); + setWindowGroup(getEffectiveGroup(pollActiveGroup(), + keystroke.m_data.m_group.m_group)); + } + } + break; + } } -UINT -MSWindowsKeyState::mapButtonToVirtualKey(KeyButton button) const -{ - return m_buttonToVK[button]; +KeyModifierMask &MSWindowsKeyState::getActiveModifiersRValue() { + if (m_useSavedModifiers) { + return m_savedModifiers; + } else { + return KeyState::getActiveModifiersRValue(); + } } -KeyID -MSWindowsKeyState::getIDForKey(synergy::KeyMap::KeyItem& item, - KeyButton button, UINT virtualKey, - PBYTE keyState, HKL hkl) const -{ - WCHAR unicode[2]; - int n = m_ToUnicodeEx( - virtualKey, button, keyState, unicode, - sizeof(unicode) / sizeof(unicode[0]), 0, hkl); - KeyID id = static_cast(unicode[0]); +bool MSWindowsKeyState::getGroups(GroupList &groups) const { + // get keyboard layouts + UInt32 newNumLayouts = GetKeyboardLayoutList(0, NULL); + if (newNumLayouts == 0) { + LOG((CLOG_DEBUG1 "can't get keyboard layouts")); + return false; + } + HKL *newLayouts = new HKL[newNumLayouts]; + newNumLayouts = GetKeyboardLayoutList(newNumLayouts, newLayouts); + if (newNumLayouts == 0) { + LOG((CLOG_DEBUG1 "can't get keyboard layouts")); + delete[] newLayouts; + return false; + } - switch (n) { - case -1: { - // dead key. add an space to the keyboard so we exit - // the dead key mode and future calls to this function - // with different modifiers are not affected. - - BYTE emptyState[256] = { }; - n = m_ToUnicodeEx(VK_SPACE, 0, emptyState, unicode, - sizeof(unicode) / sizeof(unicode[0]), 0, hkl); - - // as an alternative, we could use the returned - // buffer in unicode to look at the dead key character - // and not rely on getDeadKey to provide the mapping - return synergy::KeyMap::getDeadKey(id); - } - default: - case 0: - // unmapped - return kKeyNone; - - case 1: - return id; - - case 2: - // left over dead key in buffer. this used to recurse, - // but apparently this causes a stack overflow, so just - // return no key instead. - return kKeyNone; - } + groups.clear(); + groups.insert(groups.end(), newLayouts, newLayouts + newNumLayouts); + delete[] newLayouts; + return true; } -void -MSWindowsKeyState::addKeyEntry(synergy::KeyMap& keyMap, synergy::KeyMap::KeyItem& item) -{ - keyMap.addKeyEntry(item); - if (item.m_group == 0) { - m_keyToVKMap[item.m_id] = static_cast(item.m_client); - } +void MSWindowsKeyState::setWindowGroup(SInt32 group) { + HWND targetWindow = GetForegroundWindow(); + + bool sysCharSet = true; + // XXX -- determine if m_groups[group] can be used with the system + // character set. + + if (!PostMessage(targetWindow, WM_INPUTLANGCHANGEREQUEST, sysCharSet ? 1 : 0, + (LPARAM)m_groups[group])) { + LOG((CLOG_WARN "failed to post change language message")); + } + + // XXX -- use a short delay to let the target window process the message + // before it sees the keyboard events. i'm not sure why this is + // necessary since the messages should arrive in order. if we don't + // delay, though, some of our keyboard events may disappear. + Sleep(100); } +KeyID MSWindowsKeyState::getKeyID(UINT virtualKey, KeyButton button) const { + // Some virtual keycodes have same values. + // VK_HANGUL == VK_KANA, VK_HANJA == NK_KANJI + // which are used to change the input mode of IME. + // But they have different X11 keysym. So we should distinguish them. + if ((LOWORD(m_keyLayout) & 0xffffu) == 0x0412u) { // 0x0412 : Korean Locale ID + if (virtualKey == VK_HANGUL || virtualKey == VK_HANJA) { + // If shift-space is used to change the input mode, + // the extented bit is not set. So add it to get right key id. + button |= 0x100u; + } + } + + if ((button & 0x100u) != 0) { + virtualKey += 0x100u; + } + return s_virtualKey[virtualKey]; +} + +UINT MSWindowsKeyState::mapButtonToVirtualKey(KeyButton button) const { + return m_buttonToVK[button]; +} + +KeyID MSWindowsKeyState::getIDForKey(synergy::KeyMap::KeyItem &item, + KeyButton button, UINT virtualKey, + PBYTE keyState, HKL hkl) const { + WCHAR unicode[2]; + int n = m_ToUnicodeEx(virtualKey, button, keyState, unicode, + sizeof(unicode) / sizeof(unicode[0]), 0, hkl); + KeyID id = static_cast(unicode[0]); + + switch (n) { + case -1: { + // dead key. add an space to the keyboard so we exit + // the dead key mode and future calls to this function + // with different modifiers are not affected. + + BYTE emptyState[256] = {}; + n = m_ToUnicodeEx(VK_SPACE, 0, emptyState, unicode, + sizeof(unicode) / sizeof(unicode[0]), 0, hkl); + + // as an alternative, we could use the returned + // buffer in unicode to look at the dead key character + // and not rely on getDeadKey to provide the mapping + return synergy::KeyMap::getDeadKey(id); + } + default: + case 0: + // unmapped + return kKeyNone; + + case 1: + return id; + + case 2: + // left over dead key in buffer. this used to recurse, + // but apparently this causes a stack overflow, so just + // return no key instead. + return kKeyNone; + } +} + +void MSWindowsKeyState::addKeyEntry(synergy::KeyMap &keyMap, + synergy::KeyMap::KeyItem &item) { + keyMap.addKeyEntry(item); + if (item.m_group == 0) { + m_keyToVKMap[item.m_id] = static_cast(item.m_client); + } +} diff --git a/src/lib/platform/MSWindowsKeyState.h b/src/lib/platform/MSWindowsKeyState.h index ceef7fc4e..b833a21c5 100644 --- a/src/lib/platform/MSWindowsKeyState.h +++ b/src/lib/platform/MSWindowsKeyState.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2003 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 LICENSE 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 @@ -18,9 +18,9 @@ #pragma once -#include "synergy/KeyState.h" #include "base/String.h" #include "common/stdvector.h" +#include "synergy/KeyState.h" #define WIN32_LEAN_AND_MEAN #include @@ -36,200 +36,193 @@ This class maps KeyIDs to keystrokes. */ class MSWindowsKeyState : public KeyState { public: - MSWindowsKeyState(MSWindowsDesks* desks, void* eventTarget, IEventQueue* events, - std::vector layouts, bool isLangSyncEnabled); - MSWindowsKeyState(MSWindowsDesks* desks, void* eventTarget, IEventQueue* events, synergy::KeyMap& keyMap, - std::vector layouts, bool isLangSyncEnabled); - virtual ~MSWindowsKeyState(); + MSWindowsKeyState(MSWindowsDesks *desks, void *eventTarget, + IEventQueue *events, std::vector layouts, + bool isLangSyncEnabled); + MSWindowsKeyState(MSWindowsDesks *desks, void *eventTarget, + IEventQueue *events, synergy::KeyMap &keyMap, + std::vector layouts, bool isLangSyncEnabled); + virtual ~MSWindowsKeyState(); - //! @name manipulators - //@{ + //! @name manipulators + //@{ - //! Handle screen disabling - /*! - Called when screen is disabled. This is needed to deal with platform - brokenness. - */ - void disable(); + //! Handle screen disabling + /*! + Called when screen is disabled. This is needed to deal with platform + brokenness. + */ + void disable(); - //! Set the active keyboard layout - /*! - Uses \p keyLayout when querying the keyboard. - */ - void setKeyLayout(HKL keyLayout); + //! Set the active keyboard layout + /*! + Uses \p keyLayout when querying the keyboard. + */ + void setKeyLayout(HKL keyLayout); - //! Test and set autorepeat state - /*! - Returns true if the given button is autorepeating and updates internal - state. - */ - bool testAutoRepeat(bool press, bool isRepeat, KeyButton); + //! Test and set autorepeat state + /*! + Returns true if the given button is autorepeating and updates internal + state. + */ + bool testAutoRepeat(bool press, bool isRepeat, KeyButton); - //! Remember modifier state - /*! - Records the current non-toggle modifier state. - */ - void saveModifiers(); + //! Remember modifier state + /*! + Records the current non-toggle modifier state. + */ + void saveModifiers(); - //! Set effective modifier state - /*! - Temporarily sets the non-toggle modifier state to those saved by the - last call to \c saveModifiers if \p enable is \c true. Restores the - modifier state to the current modifier state if \p enable is \c false. - This is for synthesizing keystrokes on the primary screen when the - cursor is on a secondary screen. When on a secondary screen we capture - all non-toggle modifier state, track the state internally and do not - pass it on. So if Alt+F1 synthesizes Alt+X we need to synthesize - not just X but also Alt, despite the fact that our internal modifier - state indicates Alt is down, because local apps never saw the Alt down - event. - */ - void useSavedModifiers(bool enable); + //! Set effective modifier state + /*! + Temporarily sets the non-toggle modifier state to those saved by the + last call to \c saveModifiers if \p enable is \c true. Restores the + modifier state to the current modifier state if \p enable is \c false. + This is for synthesizing keystrokes on the primary screen when the + cursor is on a secondary screen. When on a secondary screen we capture + all non-toggle modifier state, track the state internally and do not + pass it on. So if Alt+F1 synthesizes Alt+X we need to synthesize + not just X but also Alt, despite the fact that our internal modifier + state indicates Alt is down, because local apps never saw the Alt down + event. + */ + void useSavedModifiers(bool enable); - //@} - //! @name accessors - //@{ + //@} + //! @name accessors + //@{ - //! Map a virtual key to a button - /*! - Returns the button for the \p virtualKey. - */ - KeyButton virtualKeyToButton(UINT virtualKey) const; + //! Map a virtual key to a button + /*! + Returns the button for the \p virtualKey. + */ + KeyButton virtualKeyToButton(UINT virtualKey) const; - //! Map key event to a key - /*! - Converts a key event into a KeyID and the shadow modifier state - to a modifier mask. - */ - KeyID mapKeyFromEvent(WPARAM charAndVirtKey, - LPARAM info, KeyModifierMask* maskOut) const; + //! Map key event to a key + /*! + Converts a key event into a KeyID and the shadow modifier state + to a modifier mask. + */ + KeyID mapKeyFromEvent(WPARAM charAndVirtKey, LPARAM info, + KeyModifierMask *maskOut) const; - //! Check if keyboard groups have changed - /*! - Returns true iff the number or order of the keyboard groups have - changed since the last call to updateKeys(). - */ - bool didGroupsChange() const; + //! Check if keyboard groups have changed + /*! + Returns true iff the number or order of the keyboard groups have + changed since the last call to updateKeys(). + */ + bool didGroupsChange() const; - //! Map key to virtual key - /*! - Returns the virtual key for key \p key or 0 if there's no such virtual - key. - */ - UINT mapKeyToVirtualKey(KeyID key) const; + //! Map key to virtual key + /*! + Returns the virtual key for key \p key or 0 if there's no such virtual + key. + */ + UINT mapKeyToVirtualKey(KeyID key) const; - //! Map virtual key and button to KeyID - /*! - Returns the KeyID for virtual key \p virtualKey and button \p button - (button should include the extended key bit), or kKeyNone if there is - no such key. - */ - KeyID getKeyID(UINT virtualKey, KeyButton button) const; + //! Map virtual key and button to KeyID + /*! + Returns the KeyID for virtual key \p virtualKey and button \p button + (button should include the extended key bit), or kKeyNone if there is + no such key. + */ + KeyID getKeyID(UINT virtualKey, KeyButton button) const; - //! Map button to virtual key - /*! - Returns the virtual key for button \p button - (button should include the extended key bit), or kKeyNone if there is - no such key. - */ - UINT mapButtonToVirtualKey(KeyButton button) const; + //! Map button to virtual key + /*! + Returns the virtual key for button \p button + (button should include the extended key bit), or kKeyNone if there is + no such key. + */ + UINT mapButtonToVirtualKey(KeyButton button) const; - //@} + //@} - // IKeyState overrides - virtual void fakeKeyDown(KeyID id, KeyModifierMask mask, - KeyButton button, const String& lang); - virtual bool fakeKeyRepeat(KeyID id, KeyModifierMask mask, - SInt32 count, KeyButton button, const String& lang); - virtual bool fakeCtrlAltDel(); - virtual KeyModifierMask - pollActiveModifiers() const; - virtual SInt32 pollActiveGroup() const; - virtual void pollPressedKeys(KeyButtonSet& pressedKeys) const; + // IKeyState overrides + virtual void fakeKeyDown(KeyID id, KeyModifierMask mask, KeyButton button, + const String &lang); + virtual bool fakeKeyRepeat(KeyID id, KeyModifierMask mask, SInt32 count, + KeyButton button, const String &lang); + virtual bool fakeCtrlAltDel(); + virtual KeyModifierMask pollActiveModifiers() const; + virtual SInt32 pollActiveGroup() const; + virtual void pollPressedKeys(KeyButtonSet &pressedKeys) const; - // KeyState overrides - virtual void onKey(KeyButton button, bool down, - KeyModifierMask newState); - virtual void sendKeyEvent(void* target, - bool press, bool isAutoRepeat, - KeyID key, KeyModifierMask mask, - SInt32 count, KeyButton button); + // KeyState overrides + virtual void onKey(KeyButton button, bool down, KeyModifierMask newState); + virtual void sendKeyEvent(void *target, bool press, bool isAutoRepeat, + KeyID key, KeyModifierMask mask, SInt32 count, + KeyButton button); - // Unit test accessors - KeyButton getLastDown() const { return m_lastDown; } - void setLastDown(KeyButton value) { m_lastDown = value; } - KeyModifierMask getSavedModifiers() const { return m_savedModifiers; } - void setSavedModifiers(KeyModifierMask value) { m_savedModifiers = value; } + // Unit test accessors + KeyButton getLastDown() const { return m_lastDown; } + void setLastDown(KeyButton value) { m_lastDown = value; } + KeyModifierMask getSavedModifiers() const { return m_savedModifiers; } + void setSavedModifiers(KeyModifierMask value) { m_savedModifiers = value; } protected: - // KeyState overrides - virtual void getKeyMap(synergy::KeyMap& keyMap); - virtual void fakeKey(const Keystroke& keystroke); - virtual KeyModifierMask& - getActiveModifiersRValue(); + // KeyState overrides + virtual void getKeyMap(synergy::KeyMap &keyMap); + virtual void fakeKey(const Keystroke &keystroke); + virtual KeyModifierMask &getActiveModifiersRValue(); private: - typedef std::vector GroupList; + typedef std::vector GroupList; - // send ctrl+alt+del hotkey event on NT family - static void ctrlAltDelThread(void*); + // send ctrl+alt+del hotkey event on NT family + static void ctrlAltDelThread(void *); - bool getGroups(GroupList&) const; - void setWindowGroup(SInt32 group); + bool getGroups(GroupList &) const; + void setWindowGroup(SInt32 group); - KeyID getIDForKey(synergy::KeyMap::KeyItem& item, - KeyButton button, UINT virtualKey, - PBYTE keyState, HKL hkl) const; + KeyID getIDForKey(synergy::KeyMap::KeyItem &item, KeyButton button, + UINT virtualKey, PBYTE keyState, HKL hkl) const; - void addKeyEntry(synergy::KeyMap& keyMap, synergy::KeyMap::KeyItem& item); + void addKeyEntry(synergy::KeyMap &keyMap, synergy::KeyMap::KeyItem &item); - void init(); + void init(); private: - // not implemented - MSWindowsKeyState(const MSWindowsKeyState&); - MSWindowsKeyState& operator=(const MSWindowsKeyState&); + // not implemented + MSWindowsKeyState(const MSWindowsKeyState &); + MSWindowsKeyState &operator=(const MSWindowsKeyState &); private: - typedef std::map GroupMap; - typedef std::map KeyToVKMap; + typedef std::map GroupMap; + typedef std::map KeyToVKMap; - void* m_eventTarget; - MSWindowsDesks* m_desks; - HKL m_keyLayout; - UINT m_buttonToVK[512]; - UINT m_buttonToNumpadVK[512]; - KeyButton m_virtualKeyToButton[256]; - KeyToVKMap m_keyToVKMap; - IEventQueue* m_events; + void *m_eventTarget; + MSWindowsDesks *m_desks; + HKL m_keyLayout; + UINT m_buttonToVK[512]; + UINT m_buttonToNumpadVK[512]; + KeyButton m_virtualKeyToButton[256]; + KeyToVKMap m_keyToVKMap; + IEventQueue *m_events; - // the timer used to check for fixing key state - EventQueueTimer* m_fixTimer; + // the timer used to check for fixing key state + EventQueueTimer *m_fixTimer; - // the groups (keyboard layouts) - GroupList m_groups; - GroupMap m_groupMap; + // the groups (keyboard layouts) + GroupList m_groups; + GroupMap m_groupMap; - // the last button that we generated a key down event for. this - // is zero if the last key event was a key up. we use this to - // synthesize key repeats since the low level keyboard hook can't - // tell us if an event is a key repeat. - KeyButton m_lastDown; + // the last button that we generated a key down event for. this + // is zero if the last key event was a key up. we use this to + // synthesize key repeats since the low level keyboard hook can't + // tell us if an event is a key repeat. + KeyButton m_lastDown; - // modifier tracking - bool m_useSavedModifiers; - KeyModifierMask m_savedModifiers; - KeyModifierMask m_originalSavedModifiers; + // modifier tracking + bool m_useSavedModifiers; + KeyModifierMask m_savedModifiers; + KeyModifierMask m_originalSavedModifiers; - // pointer to ToUnicodeEx. on win95 family this will be NULL. - typedef int (WINAPI *ToUnicodeEx_t)(UINT wVirtKey, - UINT wScanCode, - PBYTE lpKeyState, - LPWSTR pwszBuff, - int cchBuff, - UINT wFlags, - HKL dwhkl); - ToUnicodeEx_t m_ToUnicodeEx; + // pointer to ToUnicodeEx. on win95 family this will be NULL. + typedef int(WINAPI *ToUnicodeEx_t)(UINT wVirtKey, UINT wScanCode, + PBYTE lpKeyState, LPWSTR pwszBuff, + int cchBuff, UINT wFlags, HKL dwhkl); + ToUnicodeEx_t m_ToUnicodeEx; - static const KeyID s_virtualKey[]; + static const KeyID s_virtualKey[]; }; diff --git a/src/lib/platform/MSWindowsPowerManager.cpp b/src/lib/platform/MSWindowsPowerManager.cpp index 4d0b24eab..dee434d78 100644 --- a/src/lib/platform/MSWindowsPowerManager.cpp +++ b/src/lib/platform/MSWindowsPowerManager.cpp @@ -18,20 +18,15 @@ #include "MSWindowsPowerManager.h" #include "arch/win32/ArchMiscWindows.h" -MSWindowsPowerManager::~MSWindowsPowerManager() -{ - enableSleep(); +MSWindowsPowerManager::~MSWindowsPowerManager() { enableSleep(); } + +void MSWindowsPowerManager::disableSleep() { + ArchMiscWindows::addBusyState(ArchMiscWindows::kSYSTEM); + ArchMiscWindows::addBusyState(ArchMiscWindows::kDISPLAY); } -void MSWindowsPowerManager::disableSleep() -{ - ArchMiscWindows::addBusyState(ArchMiscWindows::kSYSTEM); - ArchMiscWindows::addBusyState(ArchMiscWindows::kDISPLAY); -} - -void MSWindowsPowerManager::enableSleep() -{ - // allow the system to enter power saving mode - ArchMiscWindows::removeBusyState(ArchMiscWindows::kSYSTEM); - ArchMiscWindows::removeBusyState(ArchMiscWindows::kDISPLAY); +void MSWindowsPowerManager::enableSleep() { + // allow the system to enter power saving mode + ArchMiscWindows::removeBusyState(ArchMiscWindows::kSYSTEM); + ArchMiscWindows::removeBusyState(ArchMiscWindows::kDISPLAY); } diff --git a/src/lib/platform/MSWindowsPowerManager.h b/src/lib/platform/MSWindowsPowerManager.h index 42eaa9ede..fcc843b39 100644 --- a/src/lib/platform/MSWindowsPowerManager.h +++ b/src/lib/platform/MSWindowsPowerManager.h @@ -18,21 +18,19 @@ #ifndef MSWINDOWSPOWERMANAGER_H #define MSWINDOWSPOWERMANAGER_H - -class MSWindowsPowerManager -{ +class MSWindowsPowerManager { public: - ~MSWindowsPowerManager(); + ~MSWindowsPowerManager(); - /** - * @brief Prevents the system from sleep automatically - */ - void disableSleep(); + /** + * @brief Prevents the system from sleep automatically + */ + void disableSleep(); - /** - * @brief Enable automatically sleeping - */ - void enableSleep(); + /** + * @brief Enable automatically sleeping + */ + void enableSleep(); }; #endif // MSWINDOWSPOWERMANAGER_H diff --git a/src/lib/platform/MSWindowsScreen.cpp b/src/lib/platform/MSWindowsScreen.cpp index bcdcc7c1b..6a63c592e 100644 --- a/src/lib/platform/MSWindowsScreen.cpp +++ b/src/lib/platform/MSWindowsScreen.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -18,37 +18,36 @@ #include "platform/MSWindowsScreen.h" -#include "platform/MSWindowsDropTarget.h" +#include "arch/Arch.h" +#include "arch/win32/ArchMiscWindows.h" +#include "base/IEventQueue.h" +#include "base/Log.h" +#include "base/String.h" +#include "base/TMethodEventJob.h" +#include "base/TMethodJob.h" #include "client/Client.h" +#include "mt/Thread.h" #include "platform/MSWindowsClipboard.h" #include "platform/MSWindowsDesks.h" +#include "platform/MSWindowsDropTarget.h" #include "platform/MSWindowsEventQueueBuffer.h" #include "platform/MSWindowsKeyState.h" #include "platform/MSWindowsScreenSaver.h" -#include "synergy/Clipboard.h" -#include "synergy/KeyMap.h" -#include "synergy/XScreen.h" #include "synergy/App.h" #include "synergy/ArgsBase.h" #include "synergy/ClientApp.h" -#include "mt/Lock.h" -#include "mt/Thread.h" -#include "arch/win32/ArchMiscWindows.h" -#include "arch/Arch.h" -#include "base/FunctionJob.h" -#include "base/Log.h" -#include "base/String.h" -#include "base/IEventQueue.h" -#include "base/TMethodEventJob.h" -#include "base/TMethodJob.h" +#include "synergy/Clipboard.h" +#include "synergy/KeyMap.h" +#include "synergy/XScreen.h" -#include #include -#include #include +#include +#include -// suppress warning about GetVersionEx, which is used indirectly in this compilation unit. -#pragma warning(disable: 4996) +// suppress warning about GetVersionEx, which is used indirectly in this +// compilation unit. +#pragma warning(disable : 4996) // // add backwards compatible multihead support (and suppress bogus warning). @@ -56,7 +55,7 @@ // #if defined(_MSC_VER) #pragma warning(push) -#pragma warning(disable: 4706) // assignment within conditional +#pragma warning(disable : 4706) // assignment within conditional #define COMPILE_MULTIMON_STUBS #include #pragma warning(pop) @@ -64,1343 +63,1168 @@ // X button stuff #if !defined(WM_XBUTTONDOWN) -#define WM_XBUTTONDOWN 0x020B -#define WM_XBUTTONUP 0x020C -#define WM_XBUTTONDBLCLK 0x020D -#define WM_NCXBUTTONDOWN 0x00AB -#define WM_NCXBUTTONUP 0x00AC -#define WM_NCXBUTTONDBLCLK 0x00AD -#define MOUSEEVENTF_XDOWN 0x0080 -#define MOUSEEVENTF_XUP 0x0100 -#define XBUTTON1 0x0001 -#define XBUTTON2 0x0002 +#define WM_XBUTTONDOWN 0x020B +#define WM_XBUTTONUP 0x020C +#define WM_XBUTTONDBLCLK 0x020D +#define WM_NCXBUTTONDOWN 0x00AB +#define WM_NCXBUTTONUP 0x00AC +#define WM_NCXBUTTONDBLCLK 0x00AD +#define MOUSEEVENTF_XDOWN 0x0080 +#define MOUSEEVENTF_XUP 0x0100 +#define XBUTTON1 0x0001 +#define XBUTTON2 0x0002 #endif #if !defined(VK_XBUTTON1) -#define VK_XBUTTON1 0x05 -#define VK_XBUTTON2 0x06 +#define VK_XBUTTON1 0x05 +#define VK_XBUTTON2 0x06 #endif // WM_POWERBROADCAST stuff #if !defined(PBT_APMRESUMEAUTOMATIC) -#define PBT_APMRESUMEAUTOMATIC 0x0012 +#define PBT_APMRESUMEAUTOMATIC 0x0012 #endif // // MSWindowsScreen // -HINSTANCE MSWindowsScreen::s_windowInstance = NULL; -MSWindowsScreen* MSWindowsScreen::s_screen = NULL; +HINSTANCE MSWindowsScreen::s_windowInstance = NULL; +MSWindowsScreen *MSWindowsScreen::s_screen = NULL; MSWindowsScreen::MSWindowsScreen( - bool isPrimary, - bool noHooks, - bool stopOnDeskSwitch, - IEventQueue* events, - bool enableLangSync, - lib::synergy::ClientScrollDirection scrollDirection) : - PlatformScreen(events, scrollDirection), - m_isPrimary(isPrimary), - m_noHooks(noHooks), - m_isOnScreen(m_isPrimary), - m_class(0), - m_x(0), m_y(0), - m_w(0), m_h(0), - m_xCenter(0), m_yCenter(0), - m_multimon(false), - m_xCursor(0), m_yCursor(0), - m_sequenceNumber(0), - m_mark(0), - m_markReceived(0), - m_fixTimer(NULL), - m_keyLayout(NULL), - m_screensaver(NULL), - m_screensaverNotify(false), - m_screensaverActive(false), - m_window(NULL), - m_nextClipboardWindow(NULL), - m_ownClipboard(false), - m_desks(NULL), - m_keyState(NULL), - m_hasMouse(GetSystemMetrics(SM_MOUSEPRESENT) != 0), - m_showingMouse(false), - m_events(events), - m_dropWindow(NULL), - m_dropWindowSize(20) -{ - assert(s_windowInstance != NULL); - assert(s_screen == NULL); + bool isPrimary, bool noHooks, bool stopOnDeskSwitch, IEventQueue *events, + bool enableLangSync, lib::synergy::ClientScrollDirection scrollDirection) + : PlatformScreen(events, scrollDirection), m_isPrimary(isPrimary), + m_noHooks(noHooks), m_isOnScreen(m_isPrimary), m_class(0), m_x(0), m_y(0), + m_w(0), m_h(0), m_xCenter(0), m_yCenter(0), m_multimon(false), + m_xCursor(0), m_yCursor(0), m_sequenceNumber(0), m_mark(0), + m_markReceived(0), m_fixTimer(NULL), m_keyLayout(NULL), + m_screensaver(NULL), m_screensaverNotify(false), + m_screensaverActive(false), m_window(NULL), m_nextClipboardWindow(NULL), + m_ownClipboard(false), m_desks(NULL), m_keyState(NULL), + m_hasMouse(GetSystemMetrics(SM_MOUSEPRESENT) != 0), m_showingMouse(false), + m_events(events), m_dropWindow(NULL), m_dropWindowSize(20) { + assert(s_windowInstance != NULL); + assert(s_screen == NULL); - s_screen = this; - try { - if (m_isPrimary && !m_noHooks) { - m_hook.loadLibrary(); - } - - m_screensaver = new MSWindowsScreenSaver(); - m_desks = new MSWindowsDesks( - m_isPrimary, - m_noHooks, - m_screensaver, - m_events, - new TMethodJob( - this, &MSWindowsScreen::updateKeysCB), - stopOnDeskSwitch); - m_keyState = new MSWindowsKeyState(m_desks, getEventTarget(), m_events, - AppUtil::instance().getKeyboardLayoutList(), - enableLangSync); - - updateScreenShape(); - m_class = createWindowClass(); - m_window = createWindow(m_class, "Synergy"); - forceShowCursor(); - LOG((CLOG_DEBUG "screen shape: %d,%d %dx%d %s", m_x, m_y, m_w, m_h, m_multimon ? "(multi-monitor)" : "")); - LOG((CLOG_DEBUG "window is 0x%08x", m_window)); - - // SHGetFolderPath is deprecated in vista, but use it for xp support. - char desktopPath[MAX_PATH]; - if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_DESKTOP, NULL, 0, desktopPath))) { - m_desktopPath = String(desktopPath); - LOG((CLOG_DEBUG "using desktop for file drag-drop target: %s", m_desktopPath.c_str())); - } - else { - LOG((CLOG_DEBUG "unable to use desktop as file drag-drop target, code=%d", GetLastError())); - } - - if (App::instance().argsBase().m_preventSleep) { - m_powerManager.disableSleep(); - } - - OleInitialize(0); - m_dropWindow = createDropWindow(m_class, "DropWindow"); - m_dropTarget = new MSWindowsDropTarget(); - RegisterDragDrop(m_dropWindow, m_dropTarget); - } - catch (...) { - delete m_keyState; - delete m_desks; - delete m_screensaver; - destroyWindow(m_window); - destroyClass(m_class); - s_screen = NULL; - throw; + s_screen = this; + try { + if (m_isPrimary && !m_noHooks) { + m_hook.loadLibrary(); } - // install event handlers - m_events->adoptHandler(Event::kSystem, m_events->getSystemTarget(), - new TMethodEventJob(this, - &MSWindowsScreen::handleSystemEvent)); + m_screensaver = new MSWindowsScreenSaver(); + m_desks = new MSWindowsDesks( + m_isPrimary, m_noHooks, m_screensaver, m_events, + new TMethodJob(this, &MSWindowsScreen::updateKeysCB), + stopOnDeskSwitch); + m_keyState = new MSWindowsKeyState( + m_desks, getEventTarget(), m_events, + AppUtil::instance().getKeyboardLayoutList(), enableLangSync); - // install the platform event queue - m_events->adoptBuffer(new MSWindowsEventQueueBuffer(m_events)); -} + updateScreenShape(); + m_class = createWindowClass(); + m_window = createWindow(m_class, "Synergy"); + forceShowCursor(); + LOG((CLOG_DEBUG "screen shape: %d,%d %dx%d %s", m_x, m_y, m_w, m_h, + m_multimon ? "(multi-monitor)" : "")); + LOG((CLOG_DEBUG "window is 0x%08x", m_window)); -MSWindowsScreen::~MSWindowsScreen() -{ - assert(s_screen != NULL); + // SHGetFolderPath is deprecated in vista, but use it for xp support. + char desktopPath[MAX_PATH]; + if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_DESKTOP, NULL, 0, desktopPath))) { + m_desktopPath = String(desktopPath); + LOG((CLOG_DEBUG "using desktop for file drag-drop target: %s", + m_desktopPath.c_str())); + } else { + LOG((CLOG_DEBUG "unable to use desktop as file drag-drop target, code=%d", + GetLastError())); + } - disable(); - m_events->adoptBuffer(NULL); - m_events->removeHandler(Event::kSystem, m_events->getSystemTarget()); + if (App::instance().argsBase().m_preventSleep) { + m_powerManager.disableSleep(); + } + + OleInitialize(0); + m_dropWindow = createDropWindow(m_class, "DropWindow"); + m_dropTarget = new MSWindowsDropTarget(); + RegisterDragDrop(m_dropWindow, m_dropTarget); + } catch (...) { delete m_keyState; delete m_desks; delete m_screensaver; destroyWindow(m_window); destroyClass(m_class); - - RevokeDragDrop(m_dropWindow); - m_dropTarget->Release(); - OleUninitialize(); - destroyWindow(m_dropWindow); - s_screen = NULL; + throw; + } + + // install event handlers + m_events->adoptHandler(Event::kSystem, m_events->getSystemTarget(), + new TMethodEventJob( + this, &MSWindowsScreen::handleSystemEvent)); + + // install the platform event queue + m_events->adoptBuffer(new MSWindowsEventQueueBuffer(m_events)); } -void -MSWindowsScreen::init(HINSTANCE windowInstance) -{ - assert(s_windowInstance == NULL); - assert(windowInstance != NULL); +MSWindowsScreen::~MSWindowsScreen() { + assert(s_screen != NULL); - s_windowInstance = windowInstance; + disable(); + m_events->adoptBuffer(NULL); + m_events->removeHandler(Event::kSystem, m_events->getSystemTarget()); + delete m_keyState; + delete m_desks; + delete m_screensaver; + destroyWindow(m_window); + destroyClass(m_class); + + RevokeDragDrop(m_dropWindow); + m_dropTarget->Release(); + OleUninitialize(); + destroyWindow(m_dropWindow); + + s_screen = NULL; +} + +void MSWindowsScreen::init(HINSTANCE windowInstance) { + assert(s_windowInstance == NULL); + assert(windowInstance != NULL); + + s_windowInstance = windowInstance; } HINSTANCE -MSWindowsScreen::getWindowInstance() -{ - return s_windowInstance; +MSWindowsScreen::getWindowInstance() { return s_windowInstance; } + +void MSWindowsScreen::enable() { + assert(m_isOnScreen == m_isPrimary); + + // we need to poll some things to fix them + m_fixTimer = m_events->newTimer(1.0, NULL); + m_events->adoptHandler(Event::kTimer, m_fixTimer, + new TMethodEventJob( + this, &MSWindowsScreen::handleFixes)); + + // install our clipboard snooper + m_nextClipboardWindow = SetClipboardViewer(m_window); + + // track the active desk and (re)install the hooks + m_desks->enable(); + + if (m_isPrimary) { + // set jump zones + m_hook.setZone(m_x, m_y, m_w, m_h, getJumpZoneSize()); + + // watch jump zones + m_hook.setMode(kHOOK_WATCH_JUMP_ZONE); + } } -void -MSWindowsScreen::enable() -{ - assert(m_isOnScreen == m_isPrimary); +void MSWindowsScreen::disable() { + // stop tracking the active desk + m_desks->disable(); - // we need to poll some things to fix them - m_fixTimer = m_events->newTimer(1.0, NULL); - m_events->adoptHandler(Event::kTimer, m_fixTimer, - new TMethodEventJob(this, - &MSWindowsScreen::handleFixes)); + if (m_isPrimary) { + // disable hooks + m_hook.setMode(kHOOK_DISABLE); - // install our clipboard snooper - m_nextClipboardWindow = SetClipboardViewer(m_window); + // enable special key sequences on win95 family + enableSpecialKeys(true); + } - // track the active desk and (re)install the hooks - m_desks->enable(); + // tell key state + m_keyState->disable(); - if (m_isPrimary) { - // set jump zones - m_hook.setZone(m_x, m_y, m_w, m_h, getJumpZoneSize()); + // stop snooping the clipboard + ChangeClipboardChain(m_window, m_nextClipboardWindow); + m_nextClipboardWindow = NULL; - // watch jump zones - m_hook.setMode(kHOOK_WATCH_JUMP_ZONE); - } + // uninstall fix timer + if (m_fixTimer != NULL) { + m_events->removeHandler(Event::kTimer, m_fixTimer); + m_events->deleteTimer(m_fixTimer); + m_fixTimer = NULL; + } + + m_isOnScreen = m_isPrimary; + forceShowCursor(); } -void -MSWindowsScreen::disable() -{ - // stop tracking the active desk - m_desks->disable(); +void MSWindowsScreen::enter() { + m_desks->enter(); + if (m_isPrimary) { + // enable special key sequences on win95 family + enableSpecialKeys(true); - if (m_isPrimary) { - // disable hooks - m_hook.setMode(kHOOK_DISABLE); + // watch jump zones + m_hook.setMode(kHOOK_WATCH_JUMP_ZONE); - // enable special key sequences on win95 family - enableSpecialKeys(true); + // all messages prior to now are invalid + nextMark(); + + m_primaryKeyDownList.clear(); + } else { + // Entering a secondary screen. Ensure that no screensaver is active + // and that the screen is not in powersave mode. + ArchMiscWindows::wakeupDisplay(); + + if (m_screensaver != NULL && m_screensaverActive) { + m_screensaver->deactivate(); + m_screensaverActive = 0; } + } - // tell key state - m_keyState->disable(); - - // stop snooping the clipboard - ChangeClipboardChain(m_window, m_nextClipboardWindow); - m_nextClipboardWindow = NULL; - - // uninstall fix timer - if (m_fixTimer != NULL) { - m_events->removeHandler(Event::kTimer, m_fixTimer); - m_events->deleteTimer(m_fixTimer); - m_fixTimer = NULL; - } - - m_isOnScreen = m_isPrimary; - forceShowCursor(); + // now on screen + m_isOnScreen = true; + forceShowCursor(); } -void -MSWindowsScreen::enter() -{ - m_desks->enter(); - if (m_isPrimary) { - // enable special key sequences on win95 family - enableSpecialKeys(true); +bool MSWindowsScreen::leave() { + POINT pos; + if (!getThisCursorPos(&pos)) { + LOG((CLOG_DEBUG "unable to leave screen as windows security has disabled " + "critical functions")); + // unable to get position this means synergy will break if the cursor leaves + // the screen + return false; + } + // get keyboard layout of foreground window. we'll use this + // keyboard layout for translating keys sent to clients. + m_keyLayout = AppUtilWindows::instance().getCurrentKeyboardLayout(); - // watch jump zones - m_hook.setMode(kHOOK_WATCH_JUMP_ZONE); + // tell the key mapper about the keyboard layout + m_keyState->setKeyLayout(m_keyLayout); - // all messages prior to now are invalid - nextMark(); + // tell desk that we're leaving and tell it the keyboard layout + m_desks->leave(m_keyLayout); - m_primaryKeyDownList.clear(); + if (m_isPrimary) { + + // warp to center + LOG((CLOG_DEBUG1 "warping cursor to center: %+d, %+d", m_xCenter, + m_yCenter)); + warpCursor(m_xCenter, m_yCenter); + + // disable special key sequences on win95 family + enableSpecialKeys(false); + + // all messages prior to now are invalid + nextMark(); + + // remember the modifier state. this is the modifier state + // reflected in the internal keyboard state. + m_keyState->saveModifiers(); + + m_hook.setMode(kHOOK_RELAY_EVENTS); + + m_primaryKeyDownList.clear(); + for (KeyButton i = 0; i < IKeyState::kNumButtons; ++i) { + if (m_keyState->isKeyDown(i)) { + m_primaryKeyDownList.push_back(i); + LOG((CLOG_DEBUG1 + "key button %d is down before leaving to another screen", + i)); + } } - else { - // Entering a secondary screen. Ensure that no screensaver is active - // and that the screen is not in powersave mode. - ArchMiscWindows::wakeupDisplay(); + } - if (m_screensaver != NULL && m_screensaverActive) - { - m_screensaver->deactivate(); - m_screensaverActive = 0; - } - } + // now off screen + m_isOnScreen = false; + forceShowCursor(); - // now on screen - m_isOnScreen = true; - forceShowCursor(); + if (isDraggingStarted() && !m_isPrimary) { + m_sendDragThread = new Thread(new TMethodJob( + this, &MSWindowsScreen::sendDragThread)); + } + + return true; } -bool -MSWindowsScreen::leave() -{ - POINT pos; - if (!getThisCursorPos(&pos)) - { - LOG((CLOG_DEBUG "unable to leave screen as windows security has disabled critical functions")); - //unable to get position this means synergy will break if the cursor leaves the screen - return false; +void MSWindowsScreen::sendDragThread(void *) { + String &draggingFilename = getDraggingFilename(); + size_t size = draggingFilename.size(); + + if (draggingFilename.empty() == false) { + ClientApp &app = ClientApp::instance(); + Client *client = app.getClientPtr(); + UInt32 fileCount = 1; + LOG((CLOG_DEBUG "send dragging info to server: %s", + draggingFilename.c_str())); + client->sendDragInfo(fileCount, draggingFilename, size); + LOG((CLOG_DEBUG "send dragging file to server")); + client->sendFileToServer(draggingFilename.c_str()); + } + + m_draggingStarted = false; +} + +bool MSWindowsScreen::setClipboard(ClipboardID, const IClipboard *src) { + MSWindowsClipboard dst(m_window); + if (src != NULL) { + // save clipboard data + return Clipboard::copy(&dst, src); + } else { + // assert clipboard ownership + if (!dst.open(0)) { + return false; } - // get keyboard layout of foreground window. we'll use this - // keyboard layout for translating keys sent to clients. - m_keyLayout = AppUtilWindows::instance().getCurrentKeyboardLayout(); - - // tell the key mapper about the keyboard layout - m_keyState->setKeyLayout(m_keyLayout); - - // tell desk that we're leaving and tell it the keyboard layout - m_desks->leave(m_keyLayout); - - if (m_isPrimary) { - - // warp to center - LOG((CLOG_DEBUG1 "warping cursor to center: %+d, %+d", m_xCenter, m_yCenter)); - warpCursor(m_xCenter, m_yCenter); - - // disable special key sequences on win95 family - enableSpecialKeys(false); - - // all messages prior to now are invalid - nextMark(); - - // remember the modifier state. this is the modifier state - // reflected in the internal keyboard state. - m_keyState->saveModifiers(); - - m_hook.setMode(kHOOK_RELAY_EVENTS); - - m_primaryKeyDownList.clear(); - for (KeyButton i = 0; i < IKeyState::kNumButtons; ++i) { - if (m_keyState->isKeyDown(i)) { - m_primaryKeyDownList.push_back(i); - LOG((CLOG_DEBUG1 "key button %d is down before leaving to another screen", i)); - } - } - } - - // now off screen - m_isOnScreen = false; - forceShowCursor(); - - if (isDraggingStarted() && !m_isPrimary) { - m_sendDragThread = new Thread( - new TMethodJob( - this, - &MSWindowsScreen::sendDragThread)); - } - + dst.empty(); + dst.close(); return true; + } } -void -MSWindowsScreen::sendDragThread(void*) -{ - String& draggingFilename = getDraggingFilename(); - size_t size = draggingFilename.size(); - - if (draggingFilename.empty() == false) { - ClientApp& app = ClientApp::instance(); - Client* client = app.getClientPtr(); - UInt32 fileCount = 1; - LOG((CLOG_DEBUG "send dragging info to server: %s", draggingFilename.c_str())); - client->sendDragInfo(fileCount, draggingFilename, size); - LOG((CLOG_DEBUG "send dragging file to server")); - client->sendFileToServer(draggingFilename.c_str()); - } - - m_draggingStarted = false; +void MSWindowsScreen::checkClipboards() { + // if we think we own the clipboard but we don't then somebody + // grabbed the clipboard on this screen without us knowing. + // tell the server that this screen grabbed the clipboard. + // + // this works around bugs in the clipboard viewer chain. + // sometimes NT will simply never send WM_DRAWCLIPBOARD + // messages for no apparent reason and rebooting fixes the + // problem. since we don't want a broken clipboard until the + // next reboot we do this double check. clipboard ownership + // won't be reflected on other screens until we leave but at + // least the clipboard itself will work. + if (m_ownClipboard && !MSWindowsClipboard::isOwnedBySynergy()) { + LOG((CLOG_DEBUG + "clipboard changed: lost ownership and no notification received")); + m_ownClipboard = false; + sendClipboardEvent(m_events->forClipboard().clipboardGrabbed(), + kClipboardClipboard); + sendClipboardEvent(m_events->forClipboard().clipboardGrabbed(), + kClipboardSelection); + } } -bool -MSWindowsScreen::setClipboard(ClipboardID, const IClipboard* src) -{ - MSWindowsClipboard dst(m_window); - if (src != NULL) { - // save clipboard data - return Clipboard::copy(&dst, src); - } - else { - // assert clipboard ownership - if (!dst.open(0)) { - return false; - } - dst.empty(); - dst.close(); - return true; - } +void MSWindowsScreen::openScreensaver(bool notify) { + assert(m_screensaver != NULL); + + m_screensaverNotify = notify; + if (m_screensaverNotify) { + m_desks->installScreensaverHooks(true); + } else if (m_screensaver) { + m_screensaver->disable(); + } } -void -MSWindowsScreen::checkClipboards() -{ - // if we think we own the clipboard but we don't then somebody - // grabbed the clipboard on this screen without us knowing. - // tell the server that this screen grabbed the clipboard. - // - // this works around bugs in the clipboard viewer chain. - // sometimes NT will simply never send WM_DRAWCLIPBOARD - // messages for no apparent reason and rebooting fixes the - // problem. since we don't want a broken clipboard until the - // next reboot we do this double check. clipboard ownership - // won't be reflected on other screens until we leave but at - // least the clipboard itself will work. - if (m_ownClipboard && !MSWindowsClipboard::isOwnedBySynergy()) { - LOG((CLOG_DEBUG "clipboard changed: lost ownership and no notification received")); - m_ownClipboard = false; - sendClipboardEvent(m_events->forClipboard().clipboardGrabbed(), kClipboardClipboard); - sendClipboardEvent(m_events->forClipboard().clipboardGrabbed(), kClipboardSelection); - } -} - -void -MSWindowsScreen::openScreensaver(bool notify) -{ - assert(m_screensaver != NULL); - - m_screensaverNotify = notify; +void MSWindowsScreen::closeScreensaver() { + if (m_screensaver != NULL) { if (m_screensaverNotify) { - m_desks->installScreensaverHooks(true); - } - else if (m_screensaver) { - m_screensaver->disable(); + m_desks->installScreensaverHooks(false); + } else { + m_screensaver->enable(); } + } + m_screensaverNotify = false; } -void -MSWindowsScreen::closeScreensaver() -{ - if (m_screensaver != NULL) { - if (m_screensaverNotify) { - m_desks->installScreensaverHooks(false); - } - else { - m_screensaver->enable(); - } - } - m_screensaverNotify = false; +void MSWindowsScreen::screensaver(bool activate) { + assert(m_screensaver != NULL); + if (m_screensaver == NULL) + return; + + if (activate) { + m_screensaver->activate(); + } else { + m_screensaver->deactivate(); + } } -void -MSWindowsScreen::screensaver(bool activate) -{ - assert(m_screensaver != NULL); - if (m_screensaver==NULL) return; +void MSWindowsScreen::resetOptions() { m_desks->resetOptions(); } - if (activate) { - m_screensaver->activate(); - } - else { - m_screensaver->deactivate(); - } +void MSWindowsScreen::setOptions(const OptionsList &options) { + m_desks->setOptions(options); } -void -MSWindowsScreen::resetOptions() -{ - m_desks->resetOptions(); +void MSWindowsScreen::setSequenceNumber(UInt32 seqNum) { + m_sequenceNumber = seqNum; } -void -MSWindowsScreen::setOptions(const OptionsList& options) -{ - m_desks->setOptions(options); +bool MSWindowsScreen::isPrimary() const { return m_isPrimary; } + +void *MSWindowsScreen::getEventTarget() const { + return const_cast(this); } -void -MSWindowsScreen::setSequenceNumber(UInt32 seqNum) -{ - m_sequenceNumber = seqNum; +bool MSWindowsScreen::getClipboard(ClipboardID, IClipboard *dst) const { + MSWindowsClipboard src(m_window); + Clipboard::copy(dst, &src); + return true; } -bool -MSWindowsScreen::isPrimary() const -{ - return m_isPrimary; +void MSWindowsScreen::getShape(SInt32 &x, SInt32 &y, SInt32 &w, + SInt32 &h) const { + assert(m_class != 0); + + x = m_x; + y = m_y; + w = m_w; + h = m_h; } -void* -MSWindowsScreen::getEventTarget() const -{ - return const_cast(this); -} - -bool -MSWindowsScreen::getClipboard(ClipboardID, IClipboard* dst) const -{ - MSWindowsClipboard src(m_window); - Clipboard::copy(dst, &src); - return true; -} - -void -MSWindowsScreen::getShape(SInt32& x, SInt32& y, SInt32& w, SInt32& h) const -{ - assert(m_class != 0); - - x = m_x; - y = m_y; - w = m_w; - h = m_h; -} - -void -MSWindowsScreen::getCursorPos(SInt32& x, SInt32& y) const -{ - m_desks->getCursorPos(x, y); +void MSWindowsScreen::getCursorPos(SInt32 &x, SInt32 &y) const { + m_desks->getCursorPos(x, y); } /* - * getThisCursorPos and setThisCursorPos will attempt to negotiate with the system - * to try get the and set the mouse position, however on the logon screen due to - * hooks this process has it may unable to work around the problem. Although these - * functions did not fix the issue at hand (#5294) its worth keeping them here anyway. + * getThisCursorPos and setThisCursorPos will attempt to negotiate with the + * system to try get the and set the mouse position, however on the logon screen + * due to hooks this process has it may unable to work around the problem. + * Although these functions did not fix the issue at hand (#5294) its worth + * keeping them here anyway. */ -bool MSWindowsScreen::getThisCursorPos(LPPOINT pos) -{ - auto result = GetCursorPos(pos); - auto error = GetLastError(); - LOG((CLOG_DEBUG3 "%s Attempt: 1 , status %d, code: %d Pos {%d, %d}", __func__, result, error, pos->x, pos->y)); - if (!result) - { - result = GetCursorPos(pos); - error = GetLastError(); - LOG((CLOG_DEBUG3 "%s Attempt: 2, status %d, code: %d Pos {%d, %d}", __func__, result, error, pos->x, pos->y)); - updateDesktopThread(); - } - return result; -} - -bool MSWindowsScreen::setThisCursorPos(int x, int y) -{ - auto result = SetCursorPos(x, y); - auto error = GetLastError(); - LOG((CLOG_DEBUG3 "%s Attempt: 1, status %d, code: %d", __func__, result, error)); - if (!result) - { - result = SetCursorPos(x, y); - error = GetLastError(); - LOG((CLOG_DEBUG3 "%s Attempt: 2, status %d, code: %d", __func__, result, error)); - updateDesktopThread(); - } - - return result; -} - -void MSWindowsScreen::updateDesktopThread() -{ - LOG((CLOG_DEBUG3 "failed to set cursor while attempting to switch desktop")); - SetLastError(0); - HDESK cur_hdesk = OpenInputDesktop(0, true, GENERIC_ALL); - - auto error = GetLastError(); - LOG((CLOG_DEBUG3 "current desktop, handle=%p code=%d", cur_hdesk, error)); - +bool MSWindowsScreen::getThisCursorPos(LPPOINT pos) { + auto result = GetCursorPos(pos); + auto error = GetLastError(); + LOG((CLOG_DEBUG3 "%s Attempt: 1 , status %d, code: %d Pos {%d, %d}", __func__, + result, error, pos->x, pos->y)); + if (!result) { + result = GetCursorPos(pos); error = GetLastError(); - LOG((CLOG_DEBUG3 "setting desktop, return=%d code=%d", SetThreadDesktop(cur_hdesk), GetLastError())); - - CloseDesktop(cur_hdesk); - + LOG((CLOG_DEBUG3 "%s Attempt: 2, status %d, code: %d Pos {%d, %d}", + __func__, result, error, pos->x, pos->y)); + updateDesktopThread(); + } + return result; } -void -MSWindowsScreen::reconfigure(UInt32 activeSides) -{ - assert(m_isPrimary); +bool MSWindowsScreen::setThisCursorPos(int x, int y) { + auto result = SetCursorPos(x, y); + auto error = GetLastError(); + LOG((CLOG_DEBUG3 "%s Attempt: 1, status %d, code: %d", __func__, result, + error)); + if (!result) { + result = SetCursorPos(x, y); + error = GetLastError(); + LOG((CLOG_DEBUG3 "%s Attempt: 2, status %d, code: %d", __func__, result, + error)); + updateDesktopThread(); + } - LOG((CLOG_DEBUG "active sides: %x", activeSides)); - m_hook.setSides(activeSides); + return result; } -void -MSWindowsScreen::warpCursor(SInt32 x, SInt32 y) -{ - // warp mouse - warpCursorNoFlush(x, y); +void MSWindowsScreen::updateDesktopThread() { + LOG((CLOG_DEBUG3 "failed to set cursor while attempting to switch desktop")); + SetLastError(0); + HDESK cur_hdesk = OpenInputDesktop(0, true, GENERIC_ALL); - // remove all input events before and including warp - MSG msg; - while (PeekMessage(&msg, NULL, SYNERGY_MSG_INPUT_FIRST, - SYNERGY_MSG_INPUT_LAST, PM_REMOVE)) { - // do nothing - } + auto error = GetLastError(); + LOG((CLOG_DEBUG3 "current desktop, handle=%p code=%d", cur_hdesk, error)); - // save position to compute delta of next motion - saveMousePosition(x, y); + error = GetLastError(); + LOG((CLOG_DEBUG3 "setting desktop, return=%d code=%d", + SetThreadDesktop(cur_hdesk), GetLastError())); + + CloseDesktop(cur_hdesk); +} + +void MSWindowsScreen::reconfigure(UInt32 activeSides) { + assert(m_isPrimary); + + LOG((CLOG_DEBUG "active sides: %x", activeSides)); + m_hook.setSides(activeSides); +} + +void MSWindowsScreen::warpCursor(SInt32 x, SInt32 y) { + // warp mouse + warpCursorNoFlush(x, y); + + // remove all input events before and including warp + MSG msg; + while (PeekMessage(&msg, NULL, SYNERGY_MSG_INPUT_FIRST, + SYNERGY_MSG_INPUT_LAST, PM_REMOVE)) { + // do nothing + } + + // save position to compute delta of next motion + saveMousePosition(x, y); } void MSWindowsScreen::saveMousePosition(SInt32 x, SInt32 y) { - m_xCursor = x; - m_yCursor = y; + m_xCursor = x; + m_yCursor = y; - LOG((CLOG_DEBUG5 "saved mouse position for next delta: %+d,%+d", x,y)); + LOG((CLOG_DEBUG5 "saved mouse position for next delta: %+d,%+d", x, y)); } -UInt32 -MSWindowsScreen::registerHotKey(KeyID key, KeyModifierMask mask) -{ - // only allow certain modifiers - if ((mask & ~(KeyModifierShift | KeyModifierControl | - KeyModifierAlt | KeyModifierSuper)) != 0) { - // this should be a warning, but this can confuse users, - // as this warning happens almost always. - LOG((CLOG_DEBUG "could not map hotkey id=%04x mask=%04x", key, mask)); - return 0; - } +UInt32 MSWindowsScreen::registerHotKey(KeyID key, KeyModifierMask mask) { + // only allow certain modifiers + if ((mask & ~(KeyModifierShift | KeyModifierControl | KeyModifierAlt | + KeyModifierSuper)) != 0) { + // this should be a warning, but this can confuse users, + // as this warning happens almost always. + LOG((CLOG_DEBUG "could not map hotkey id=%04x mask=%04x", key, mask)); + return 0; + } - // fail if no keys - if (key == kKeyNone && mask == 0) { - return 0; - } + // fail if no keys + if (key == kKeyNone && mask == 0) { + return 0; + } - // convert to win32 - UINT modifiers = 0; - if ((mask & KeyModifierShift) != 0) { - modifiers |= MOD_SHIFT; - } - if ((mask & KeyModifierControl) != 0) { - modifiers |= MOD_CONTROL; - } - if ((mask & KeyModifierAlt) != 0) { - modifiers |= MOD_ALT; - } - if ((mask & KeyModifierSuper) != 0) { - modifiers |= MOD_WIN; - } - UINT vk = m_keyState->mapKeyToVirtualKey(key); - if (key != kKeyNone && vk == 0) { - // can't map key - // this should be a warning, but this can confuse users, - // as this warning happens almost always. - LOG((CLOG_DEBUG "could not map hotkey id=%04x mask=%04x", key, mask)); - return 0; - } + // convert to win32 + UINT modifiers = 0; + if ((mask & KeyModifierShift) != 0) { + modifiers |= MOD_SHIFT; + } + if ((mask & KeyModifierControl) != 0) { + modifiers |= MOD_CONTROL; + } + if ((mask & KeyModifierAlt) != 0) { + modifiers |= MOD_ALT; + } + if ((mask & KeyModifierSuper) != 0) { + modifiers |= MOD_WIN; + } + UINT vk = m_keyState->mapKeyToVirtualKey(key); + if (key != kKeyNone && vk == 0) { + // can't map key + // this should be a warning, but this can confuse users, + // as this warning happens almost always. + LOG((CLOG_DEBUG "could not map hotkey id=%04x mask=%04x", key, mask)); + return 0; + } - // choose hotkey id - UInt32 id; - if (!m_oldHotKeyIDs.empty()) { - id = m_oldHotKeyIDs.back(); - m_oldHotKeyIDs.pop_back(); - } - else { - //id = m_hotKeys.size() + 1; - id = (UInt32)m_hotKeys.size() + 1; - } + // choose hotkey id + UInt32 id; + if (!m_oldHotKeyIDs.empty()) { + id = m_oldHotKeyIDs.back(); + m_oldHotKeyIDs.pop_back(); + } else { + // id = m_hotKeys.size() + 1; + id = (UInt32)m_hotKeys.size() + 1; + } - // if this hot key has modifiers only then we'll handle it specially - bool err; - if (key == kKeyNone) { - // check if already registered - err = (m_hotKeyToIDMap.count(HotKeyItem(vk, modifiers)) > 0); - } - else { - // register with OS - err = (RegisterHotKey(NULL, id, modifiers, vk) == 0); - } + // if this hot key has modifiers only then we'll handle it specially + bool err; + if (key == kKeyNone) { + // check if already registered + err = (m_hotKeyToIDMap.count(HotKeyItem(vk, modifiers)) > 0); + } else { + // register with OS + err = (RegisterHotKey(NULL, id, modifiers, vk) == 0); + } - if (!err) { - m_hotKeys.insert(std::make_pair(id, HotKeyItem(vk, modifiers))); - m_hotKeyToIDMap[HotKeyItem(vk, modifiers)] = id; - } - else { - m_oldHotKeyIDs.push_back(id); - m_hotKeys.erase(id); - LOG((CLOG_WARN "failed to register hotkey %s (id=%04x mask=%04x)", synergy::KeyMap::formatKey(key, mask).c_str(), key, mask)); - return 0; - } - - LOG((CLOG_DEBUG "registered hotkey %s (id=%04x mask=%04x) as id=%d", synergy::KeyMap::formatKey(key, mask).c_str(), key, mask, id)); - return id; -} - -void -MSWindowsScreen::unregisterHotKey(UInt32 id) -{ - // look up hotkey - HotKeyMap::iterator i = m_hotKeys.find(id); - if (i == m_hotKeys.end()) { - return; - } - - // unregister with OS - bool err; - if (i->second.getVirtualKey() != 0) { - err = !UnregisterHotKey(NULL, id); - } - else { - err = false; - } - if (err) { - LOG((CLOG_WARN "failed to unregister hotkey id=%d", id)); - } - else { - LOG((CLOG_DEBUG "unregistered hotkey id=%d", id)); - } - - // discard hot key from map and record old id for reuse - m_hotKeyToIDMap.erase(i->second); - m_hotKeys.erase(i); + if (!err) { + m_hotKeys.insert(std::make_pair(id, HotKeyItem(vk, modifiers))); + m_hotKeyToIDMap[HotKeyItem(vk, modifiers)] = id; + } else { m_oldHotKeyIDs.push_back(id); + m_hotKeys.erase(id); + LOG((CLOG_WARN "failed to register hotkey %s (id=%04x mask=%04x)", + synergy::KeyMap::formatKey(key, mask).c_str(), key, mask)); + return 0; + } + + LOG((CLOG_DEBUG "registered hotkey %s (id=%04x mask=%04x) as id=%d", + synergy::KeyMap::formatKey(key, mask).c_str(), key, mask, id)); + return id; } -void -MSWindowsScreen::fakeInputBegin() -{ - assert(m_isPrimary); +void MSWindowsScreen::unregisterHotKey(UInt32 id) { + // look up hotkey + HotKeyMap::iterator i = m_hotKeys.find(id); + if (i == m_hotKeys.end()) { + return; + } - if (!m_isOnScreen) { - m_keyState->useSavedModifiers(true); + // unregister with OS + bool err; + if (i->second.getVirtualKey() != 0) { + err = !UnregisterHotKey(NULL, id); + } else { + err = false; + } + if (err) { + LOG((CLOG_WARN "failed to unregister hotkey id=%d", id)); + } else { + LOG((CLOG_DEBUG "unregistered hotkey id=%d", id)); + } + + // discard hot key from map and record old id for reuse + m_hotKeyToIDMap.erase(i->second); + m_hotKeys.erase(i); + m_oldHotKeyIDs.push_back(id); +} + +void MSWindowsScreen::fakeInputBegin() { + assert(m_isPrimary); + + if (!m_isOnScreen) { + m_keyState->useSavedModifiers(true); + } + m_desks->fakeInputBegin(); +} + +void MSWindowsScreen::fakeInputEnd() { + assert(m_isPrimary); + + m_desks->fakeInputEnd(); + if (!m_isOnScreen) { + m_keyState->useSavedModifiers(false); + } +} + +SInt32 MSWindowsScreen::getJumpZoneSize() const { return 1; } + +bool MSWindowsScreen::isAnyMouseButtonDown(UInt32 &buttonID) const { + static const char *buttonToName[] = {"", "Left Button", + "Middle Button", "Right Button", + "X Button 1", "X Button 2"}; + + for (UInt32 i = 1; i < sizeof(m_buttons) / sizeof(m_buttons[0]); ++i) { + if (m_buttons[i]) { + buttonID = i; + LOG((CLOG_DEBUG "locked by \"%s\"", buttonToName[i])); + return true; } - m_desks->fakeInputBegin(); + } + + return false; } -void -MSWindowsScreen::fakeInputEnd() -{ - assert(m_isPrimary); +void MSWindowsScreen::getCursorCenter(SInt32 &x, SInt32 &y) const { + x = m_xCenter; + y = m_yCenter; +} - m_desks->fakeInputEnd(); - if (!m_isOnScreen) { - m_keyState->useSavedModifiers(false); +void MSWindowsScreen::fakeMouseButton(ButtonID id, bool press) { + m_desks->fakeMouseButton(id, press); + + if (id == kButtonLeft) { + if (press) { + m_buttons[kButtonLeft] = true; + } else { + m_buttons[kButtonLeft] = false; + m_fakeDraggingStarted = false; + m_draggingStarted = false; } + } } -SInt32 -MSWindowsScreen::getJumpZoneSize() const -{ - return 1; +void MSWindowsScreen::fakeMouseMove(SInt32 x, SInt32 y) { + m_desks->fakeMouseMove(x, y); + if (m_buttons[kButtonLeft]) { + m_draggingStarted = true; + } } -bool -MSWindowsScreen::isAnyMouseButtonDown(UInt32& buttonID) const -{ - static const char* buttonToName[] = { - "", - "Left Button", - "Middle Button", - "Right Button", - "X Button 1", - "X Button 2" - }; - - for (UInt32 i = 1; i < sizeof(m_buttons) / sizeof(m_buttons[0]); ++i) { - if (m_buttons[i]) { - buttonID = i; - LOG((CLOG_DEBUG "locked by \"%s\"", buttonToName[i])); - return true; - } - } - - return false; +void MSWindowsScreen::fakeMouseRelativeMove(SInt32 dx, SInt32 dy) const { + m_desks->fakeMouseRelativeMove(dx, dy); } -void -MSWindowsScreen::getCursorCenter(SInt32& x, SInt32& y) const -{ - x = m_xCenter; - y = m_yCenter; +void MSWindowsScreen::fakeMouseWheel(SInt32 xDelta, SInt32 yDelta) const { + xDelta = mapClientScrollDirection(xDelta); + yDelta = mapClientScrollDirection(yDelta); + m_desks->fakeMouseWheel(xDelta, yDelta); } -void -MSWindowsScreen::fakeMouseButton(ButtonID id, bool press) -{ - m_desks->fakeMouseButton(id, press); +void MSWindowsScreen::updateKeys() { m_desks->updateKeys(); } - if (id == kButtonLeft) { - if (press) { - m_buttons[kButtonLeft] = true; - } - else { - m_buttons[kButtonLeft] = false; - m_fakeDraggingStarted = false; - m_draggingStarted = false; - } - } +void MSWindowsScreen::fakeKeyDown(KeyID id, KeyModifierMask mask, + KeyButton button, const String &lang) { + PlatformScreen::fakeKeyDown(id, mask, button, lang); + updateForceShowCursor(); } -void -MSWindowsScreen::fakeMouseMove(SInt32 x, SInt32 y) -{ - m_desks->fakeMouseMove(x, y); - if (m_buttons[kButtonLeft]) { - m_draggingStarted = true; - } +bool MSWindowsScreen::fakeKeyRepeat(KeyID id, KeyModifierMask mask, + SInt32 count, KeyButton button, + const String &lang) { + bool result = PlatformScreen::fakeKeyRepeat(id, mask, count, button, lang); + updateForceShowCursor(); + return result; } -void -MSWindowsScreen::fakeMouseRelativeMove(SInt32 dx, SInt32 dy) const -{ - m_desks->fakeMouseRelativeMove(dx, dy); +bool MSWindowsScreen::fakeKeyUp(KeyButton button) { + bool result = PlatformScreen::fakeKeyUp(button); + updateForceShowCursor(); + return result; } -void -MSWindowsScreen::fakeMouseWheel(SInt32 xDelta, SInt32 yDelta) const -{ - xDelta = mapClientScrollDirection(xDelta); - yDelta = mapClientScrollDirection(yDelta); - m_desks->fakeMouseWheel(xDelta, yDelta); -} - -void -MSWindowsScreen::updateKeys() -{ - m_desks->updateKeys(); -} - -void -MSWindowsScreen::fakeKeyDown(KeyID id, KeyModifierMask mask, - KeyButton button, const String& lang) -{ - PlatformScreen::fakeKeyDown(id, mask, button, lang); - updateForceShowCursor(); -} - -bool -MSWindowsScreen::fakeKeyRepeat(KeyID id, KeyModifierMask mask, - SInt32 count, KeyButton button, const String& lang) -{ - bool result = PlatformScreen::fakeKeyRepeat(id, mask, count, button, lang); - updateForceShowCursor(); - return result; -} - -bool -MSWindowsScreen::fakeKeyUp(KeyButton button) -{ - bool result = PlatformScreen::fakeKeyUp(button); - updateForceShowCursor(); - return result; -} - -void -MSWindowsScreen::fakeAllKeysUp() -{ - PlatformScreen::fakeAllKeysUp(); - updateForceShowCursor(); +void MSWindowsScreen::fakeAllKeysUp() { + PlatformScreen::fakeAllKeysUp(); + updateForceShowCursor(); } HCURSOR -MSWindowsScreen::createBlankCursor() const -{ - // create a transparent cursor - int cw = GetSystemMetrics(SM_CXCURSOR); - int ch = GetSystemMetrics(SM_CYCURSOR); +MSWindowsScreen::createBlankCursor() const { + // create a transparent cursor + int cw = GetSystemMetrics(SM_CXCURSOR); + int ch = GetSystemMetrics(SM_CYCURSOR); - UInt8* cursorAND = new UInt8[ch * ((cw + 31) >> 2)]; - UInt8* cursorXOR = new UInt8[ch * ((cw + 31) >> 2)]; - memset(cursorAND, 0xff, ch * ((cw + 31) >> 2)); - memset(cursorXOR, 0x00, ch * ((cw + 31) >> 2)); - HCURSOR c = CreateCursor(s_windowInstance, 0, 0, cw, ch, cursorAND, cursorXOR); - delete[] cursorXOR; - delete[] cursorAND; - return c; + UInt8 *cursorAND = new UInt8[ch * ((cw + 31) >> 2)]; + UInt8 *cursorXOR = new UInt8[ch * ((cw + 31) >> 2)]; + memset(cursorAND, 0xff, ch * ((cw + 31) >> 2)); + memset(cursorXOR, 0x00, ch * ((cw + 31) >> 2)); + HCURSOR c = + CreateCursor(s_windowInstance, 0, 0, cw, ch, cursorAND, cursorXOR); + delete[] cursorXOR; + delete[] cursorAND; + return c; } -void -MSWindowsScreen::destroyCursor(HCURSOR cursor) const -{ - if (cursor != NULL) { - DestroyCursor(cursor); - } +void MSWindowsScreen::destroyCursor(HCURSOR cursor) const { + if (cursor != NULL) { + DestroyCursor(cursor); + } } -ATOM -MSWindowsScreen::createWindowClass() const -{ - WNDCLASSEX classInfo; - classInfo.cbSize = sizeof(classInfo); - classInfo.style = CS_DBLCLKS | CS_NOCLOSE; - classInfo.lpfnWndProc = &MSWindowsScreen::wndProc; - classInfo.cbClsExtra = 0; - classInfo.cbWndExtra = 0; - classInfo.hInstance = s_windowInstance; - classInfo.hIcon = NULL; - classInfo.hCursor = NULL; - classInfo.hbrBackground = NULL; - classInfo.lpszMenuName = NULL; - classInfo.lpszClassName = "Synergy"; - classInfo.hIconSm = NULL; - return RegisterClassEx(&classInfo); +ATOM MSWindowsScreen::createWindowClass() const { + WNDCLASSEX classInfo; + classInfo.cbSize = sizeof(classInfo); + classInfo.style = CS_DBLCLKS | CS_NOCLOSE; + classInfo.lpfnWndProc = &MSWindowsScreen::wndProc; + classInfo.cbClsExtra = 0; + classInfo.cbWndExtra = 0; + classInfo.hInstance = s_windowInstance; + classInfo.hIcon = NULL; + classInfo.hCursor = NULL; + classInfo.hbrBackground = NULL; + classInfo.lpszMenuName = NULL; + classInfo.lpszClassName = "Synergy"; + classInfo.hIconSm = NULL; + return RegisterClassEx(&classInfo); } -void -MSWindowsScreen::destroyClass(ATOM windowClass) const -{ - if (windowClass != 0) { - UnregisterClass(MAKEINTATOM(windowClass), s_windowInstance); - } +void MSWindowsScreen::destroyClass(ATOM windowClass) const { + if (windowClass != 0) { + UnregisterClass(MAKEINTATOM(windowClass), s_windowInstance); + } } -HWND -MSWindowsScreen::createWindow(ATOM windowClass, const char* name) const -{ - HWND window = CreateWindowEx(WS_EX_TOPMOST | - WS_EX_TRANSPARENT | - WS_EX_TOOLWINDOW, - MAKEINTATOM(windowClass), - name, - WS_POPUP, - 0, 0, 1, 1, - NULL, NULL, - s_windowInstance, - NULL); - if (window == NULL) { - LOG((CLOG_ERR "failed to create window: %d", GetLastError())); - throw XScreenOpenFailure(); - } - return window; +HWND MSWindowsScreen::createWindow(ATOM windowClass, const char *name) const { + HWND window = + CreateWindowEx(WS_EX_TOPMOST | WS_EX_TRANSPARENT | WS_EX_TOOLWINDOW, + MAKEINTATOM(windowClass), name, WS_POPUP, 0, 0, 1, 1, NULL, + NULL, s_windowInstance, NULL); + if (window == NULL) { + LOG((CLOG_ERR "failed to create window: %d", GetLastError())); + throw XScreenOpenFailure(); + } + return window; } -HWND -MSWindowsScreen::createDropWindow(ATOM windowClass, const char* name) const -{ - HWND window = CreateWindowEx( - WS_EX_TOPMOST | - WS_EX_TRANSPARENT | - WS_EX_ACCEPTFILES, - MAKEINTATOM(m_class), - name, - WS_POPUP, - 0, 0, m_dropWindowSize, m_dropWindowSize, - NULL, NULL, - s_windowInstance, - NULL); +HWND MSWindowsScreen::createDropWindow(ATOM windowClass, + const char *name) const { + HWND window = CreateWindowEx( + WS_EX_TOPMOST | WS_EX_TRANSPARENT | WS_EX_ACCEPTFILES, + MAKEINTATOM(m_class), name, WS_POPUP, 0, 0, m_dropWindowSize, + m_dropWindowSize, NULL, NULL, s_windowInstance, NULL); - if (window == NULL) { - LOG((CLOG_ERR "failed to create drop window: %d", GetLastError())); - throw XScreenOpenFailure(); - } + if (window == NULL) { + LOG((CLOG_ERR "failed to create drop window: %d", GetLastError())); + throw XScreenOpenFailure(); + } - return window; + return window; } -void -MSWindowsScreen::destroyWindow(HWND hwnd) const -{ - if (hwnd != NULL) { - DestroyWindow(hwnd); - } +void MSWindowsScreen::destroyWindow(HWND hwnd) const { + if (hwnd != NULL) { + DestroyWindow(hwnd); + } } -void -MSWindowsScreen::sendEvent(Event::Type type, void* data) -{ - m_events->addEvent(Event(type, getEventTarget(), data)); +void MSWindowsScreen::sendEvent(Event::Type type, void *data) { + m_events->addEvent(Event(type, getEventTarget(), data)); } -void -MSWindowsScreen::sendClipboardEvent(Event::Type type, ClipboardID id) -{ - ClipboardInfo* info = (ClipboardInfo*)malloc(sizeof(ClipboardInfo)); - if (info == NULL) { - LOG((CLOG_ERR "malloc failed on %s:%s", __FILE__, __LINE__ )); - return; - } - info->m_id = id; - info->m_sequenceNumber = m_sequenceNumber; - sendEvent(type, info); +void MSWindowsScreen::sendClipboardEvent(Event::Type type, ClipboardID id) { + ClipboardInfo *info = (ClipboardInfo *)malloc(sizeof(ClipboardInfo)); + if (info == NULL) { + LOG((CLOG_ERR "malloc failed on %s:%s", __FILE__, __LINE__)); + return; + } + info->m_id = id; + info->m_sequenceNumber = m_sequenceNumber; + sendEvent(type, info); } -void -MSWindowsScreen::handleSystemEvent(const Event& event, void*) -{ - MSG* msg = static_cast(event.getData()); - assert(msg != NULL); +void MSWindowsScreen::handleSystemEvent(const Event &event, void *) { + MSG *msg = static_cast(event.getData()); + assert(msg != NULL); - if (ArchMiscWindows::processDialog(msg)) { - return; - } - if (onPreDispatch(msg->hwnd, msg->message, msg->wParam, msg->lParam)) { - return; - } - TranslateMessage(msg); - DispatchMessage(msg); + if (ArchMiscWindows::processDialog(msg)) { + return; + } + if (onPreDispatch(msg->hwnd, msg->message, msg->wParam, msg->lParam)) { + return; + } + TranslateMessage(msg); + DispatchMessage(msg); } -void -MSWindowsScreen::updateButtons() -{ - int numButtons = GetSystemMetrics(SM_CMOUSEBUTTONS); - m_buttons[kButtonNone] = false; - m_buttons[kButtonLeft] = (GetKeyState(VK_LBUTTON) < 0); - m_buttons[kButtonRight] = (GetKeyState(VK_RBUTTON) < 0); - m_buttons[kButtonMiddle] = (GetKeyState(VK_MBUTTON) < 0); - m_buttons[kButtonExtra0 + 0] = (numButtons >= 4) && - (GetKeyState(VK_XBUTTON1) < 0); - m_buttons[kButtonExtra0 + 1] = (numButtons >= 5) && - (GetKeyState(VK_XBUTTON2) < 0); +void MSWindowsScreen::updateButtons() { + int numButtons = GetSystemMetrics(SM_CMOUSEBUTTONS); + m_buttons[kButtonNone] = false; + m_buttons[kButtonLeft] = (GetKeyState(VK_LBUTTON) < 0); + m_buttons[kButtonRight] = (GetKeyState(VK_RBUTTON) < 0); + m_buttons[kButtonMiddle] = (GetKeyState(VK_MBUTTON) < 0); + m_buttons[kButtonExtra0 + 0] = + (numButtons >= 4) && (GetKeyState(VK_XBUTTON1) < 0); + m_buttons[kButtonExtra0 + 1] = + (numButtons >= 5) && (GetKeyState(VK_XBUTTON2) < 0); } -IKeyState* -MSWindowsScreen::getKeyState() const -{ - return m_keyState; -} +IKeyState *MSWindowsScreen::getKeyState() const { return m_keyState; } -bool -MSWindowsScreen::onPreDispatch(HWND hwnd, - UINT message, WPARAM wParam, LPARAM lParam) -{ - // handle event - switch (message) { - case SYNERGY_MSG_SCREEN_SAVER: - return onScreensaver(wParam != 0); +bool MSWindowsScreen::onPreDispatch(HWND hwnd, UINT message, WPARAM wParam, + LPARAM lParam) { + // handle event + switch (message) { + case SYNERGY_MSG_SCREEN_SAVER: + return onScreensaver(wParam != 0); - case SYNERGY_MSG_DEBUG: - LOG((CLOG_DEBUG1 "hook: 0x%08x 0x%08x", wParam, lParam)); - return true; - } - - if (m_isPrimary) { - return onPreDispatchPrimary(hwnd, message, wParam, lParam); - } - - return false; -} - -bool -MSWindowsScreen::onPreDispatchPrimary(HWND, - UINT message, WPARAM wParam, LPARAM lParam) -{ - LOG((CLOG_DEBUG5 "handling pre-dispatch primary")); - - // handle event - switch (message) { - case SYNERGY_MSG_MARK: - return onMark(static_cast(wParam)); - - case SYNERGY_MSG_KEY: - return onKey(wParam, lParam); - - case SYNERGY_MSG_MOUSE_BUTTON: - return onMouseButton(wParam, lParam); - - case SYNERGY_MSG_MOUSE_MOVE: - return onMouseMove(static_cast(wParam), - static_cast(lParam)); - - case SYNERGY_MSG_MOUSE_WHEEL: - // XXX -- support x-axis scrolling - return onMouseWheel(0, static_cast(wParam)); - - case SYNERGY_MSG_PRE_WARP: - { - // save position to compute delta of next motion - saveMousePosition(static_cast(wParam), static_cast(lParam)); - - // we warped the mouse. discard events until we find the - // matching post warp event. see warpCursorNoFlush() for - // where the events are sent. we discard the matching - // post warp event and can be sure we've skipped the warp - // event. - MSG msg; - do { - GetMessage(&msg, NULL, SYNERGY_MSG_MOUSE_MOVE, - SYNERGY_MSG_POST_WARP); - } while (msg.message != SYNERGY_MSG_POST_WARP); - } - return true; - - case SYNERGY_MSG_POST_WARP: - LOG((CLOG_WARN "unmatched post warp")); - return true; - - case WM_HOTKEY: - // we discard these messages. we'll catch the hot key in the - // regular key event handling, where we can detect both key - // press and release. we only register the hot key so no other - // app will act on the key combination. - break; - } - - return false; -} - -bool -MSWindowsScreen::onEvent(HWND, UINT msg, - WPARAM wParam, LPARAM lParam, LRESULT* result) -{ - switch (msg) { - case WM_DRAWCLIPBOARD: - // first pass on the message - if (m_nextClipboardWindow != NULL) { - SendMessage(m_nextClipboardWindow, msg, wParam, lParam); - } - - // now handle the message - return onClipboardChange(); - - case WM_CHANGECBCHAIN: - if (m_nextClipboardWindow == (HWND)wParam) { - m_nextClipboardWindow = (HWND)lParam; - LOG((CLOG_DEBUG "clipboard chain: new next: 0x%08x", m_nextClipboardWindow)); - } - else if (m_nextClipboardWindow != NULL) { - SendMessage(m_nextClipboardWindow, msg, wParam, lParam); - } - return true; - - case WM_DISPLAYCHANGE: - return onDisplayChange(); - - /* On windows 10 we don't receive WM_POWERBROADCAST after sleep. - We receive only WM_TIMECHANGE hence this message is used to resume.*/ - case WM_TIMECHANGE: - m_events->addEvent(Event(m_events->forIScreen().resume(), - getEventTarget(), NULL, - Event::kDeliverImmediately)); - break; - - case WM_POWERBROADCAST: - switch (wParam) { - case PBT_APMRESUMEAUTOMATIC: - case PBT_APMRESUMECRITICAL: - case PBT_APMRESUMESUSPEND: - m_events->addEvent(Event(m_events->forIScreen().resume(), - getEventTarget(), NULL, - Event::kDeliverImmediately)); - break; - - case PBT_APMSUSPEND: - m_events->addEvent(Event(m_events->forIScreen().suspend(), - getEventTarget(), NULL, - Event::kDeliverImmediately)); - break; - } - *result = TRUE; - return true; - - case WM_DEVICECHANGE: - forceShowCursor(); - break; - - case WM_SETTINGCHANGE: - if (wParam == SPI_SETMOUSEKEYS) { - forceShowCursor(); - } - break; - } - - return false; -} - -bool -MSWindowsScreen::onMark(UInt32 mark) -{ - m_markReceived = mark; + case SYNERGY_MSG_DEBUG: + LOG((CLOG_DEBUG1 "hook: 0x%08x 0x%08x", wParam, lParam)); return true; + } + + if (m_isPrimary) { + return onPreDispatchPrimary(hwnd, message, wParam, lParam); + } + + return false; } -bool -MSWindowsScreen::onKey(WPARAM wParam, LPARAM lParam) -{ - static const KeyModifierMask s_ctrlAlt = - KeyModifierControl | KeyModifierAlt; +bool MSWindowsScreen::onPreDispatchPrimary(HWND, UINT message, WPARAM wParam, + LPARAM lParam) { + LOG((CLOG_DEBUG5 "handling pre-dispatch primary")); - LOG((CLOG_DEBUG1 "event: Key char=%d, vk=0x%02x, nagr=%d, lParam=0x%08x", (wParam & 0xffffu), (wParam >> 16) & 0xffu, (wParam & 0x1000000u) ? 1 : 0, lParam)); + // handle event + switch (message) { + case SYNERGY_MSG_MARK: + return onMark(static_cast(wParam)); - // get event info - KeyButton button = (KeyButton)((lParam & 0x01ff0000) >> 16); - bool down = ((lParam & 0x80000000u) == 0x00000000u); - bool wasDown = isKeyDown(button); - KeyModifierMask oldState = pollActiveModifiers(); + case SYNERGY_MSG_KEY: + return onKey(wParam, lParam); - // check for autorepeat - if (m_keyState->testAutoRepeat(down, (lParam & 0x40000000u), button)) { - lParam |= 0x40000000u; + case SYNERGY_MSG_MOUSE_BUTTON: + return onMouseButton(wParam, lParam); + + case SYNERGY_MSG_MOUSE_MOVE: + return onMouseMove(static_cast(wParam), + static_cast(lParam)); + + case SYNERGY_MSG_MOUSE_WHEEL: + // XXX -- support x-axis scrolling + return onMouseWheel(0, static_cast(wParam)); + + case SYNERGY_MSG_PRE_WARP: { + // save position to compute delta of next motion + saveMousePosition(static_cast(wParam), static_cast(lParam)); + + // we warped the mouse. discard events until we find the + // matching post warp event. see warpCursorNoFlush() for + // where the events are sent. we discard the matching + // post warp event and can be sure we've skipped the warp + // event. + MSG msg; + do { + GetMessage(&msg, NULL, SYNERGY_MSG_MOUSE_MOVE, SYNERGY_MSG_POST_WARP); + } while (msg.message != SYNERGY_MSG_POST_WARP); + } + return true; + + case SYNERGY_MSG_POST_WARP: + LOG((CLOG_WARN "unmatched post warp")); + return true; + + case WM_HOTKEY: + // we discard these messages. we'll catch the hot key in the + // regular key event handling, where we can detect both key + // press and release. we only register the hot key so no other + // app will act on the key combination. + break; + } + + return false; +} + +bool MSWindowsScreen::onEvent(HWND, UINT msg, WPARAM wParam, LPARAM lParam, + LRESULT *result) { + switch (msg) { + case WM_DRAWCLIPBOARD: + // first pass on the message + if (m_nextClipboardWindow != NULL) { + SendMessage(m_nextClipboardWindow, msg, wParam, lParam); } - // if the button is zero then guess what the button should be. - // these are badly synthesized key events and logitech software - // that maps mouse buttons to keys is known to do this. - // alternatively, we could just throw these events out. + // now handle the message + return onClipboardChange(); + + case WM_CHANGECBCHAIN: + if (m_nextClipboardWindow == (HWND)wParam) { + m_nextClipboardWindow = (HWND)lParam; + LOG((CLOG_DEBUG "clipboard chain: new next: 0x%08x", + m_nextClipboardWindow)); + } else if (m_nextClipboardWindow != NULL) { + SendMessage(m_nextClipboardWindow, msg, wParam, lParam); + } + return true; + + case WM_DISPLAYCHANGE: + return onDisplayChange(); + + /* On windows 10 we don't receive WM_POWERBROADCAST after sleep. + We receive only WM_TIMECHANGE hence this message is used to resume.*/ + case WM_TIMECHANGE: + m_events->addEvent(Event(m_events->forIScreen().resume(), getEventTarget(), + NULL, Event::kDeliverImmediately)); + break; + + case WM_POWERBROADCAST: + switch (wParam) { + case PBT_APMRESUMEAUTOMATIC: + case PBT_APMRESUMECRITICAL: + case PBT_APMRESUMESUSPEND: + m_events->addEvent(Event(m_events->forIScreen().resume(), + getEventTarget(), NULL, + Event::kDeliverImmediately)); + break; + + case PBT_APMSUSPEND: + m_events->addEvent(Event(m_events->forIScreen().suspend(), + getEventTarget(), NULL, + Event::kDeliverImmediately)); + break; + } + *result = TRUE; + return true; + + case WM_DEVICECHANGE: + forceShowCursor(); + break; + + case WM_SETTINGCHANGE: + if (wParam == SPI_SETMOUSEKEYS) { + forceShowCursor(); + } + break; + } + + return false; +} + +bool MSWindowsScreen::onMark(UInt32 mark) { + m_markReceived = mark; + return true; +} + +bool MSWindowsScreen::onKey(WPARAM wParam, LPARAM lParam) { + static const KeyModifierMask s_ctrlAlt = KeyModifierControl | KeyModifierAlt; + + LOG((CLOG_DEBUG1 "event: Key char=%d, vk=0x%02x, nagr=%d, lParam=0x%08x", + (wParam & 0xffffu), (wParam >> 16) & 0xffu, + (wParam & 0x1000000u) ? 1 : 0, lParam)); + + // get event info + KeyButton button = (KeyButton)((lParam & 0x01ff0000) >> 16); + bool down = ((lParam & 0x80000000u) == 0x00000000u); + bool wasDown = isKeyDown(button); + KeyModifierMask oldState = pollActiveModifiers(); + + // check for autorepeat + if (m_keyState->testAutoRepeat(down, (lParam & 0x40000000u), button)) { + lParam |= 0x40000000u; + } + + // if the button is zero then guess what the button should be. + // these are badly synthesized key events and logitech software + // that maps mouse buttons to keys is known to do this. + // alternatively, we could just throw these events out. + if (button == 0) { + button = m_keyState->virtualKeyToButton((wParam >> 16) & 0xffu); if (button == 0) { - button = m_keyState->virtualKeyToButton((wParam >> 16) & 0xffu); - if (button == 0) { - return true; - } - wasDown = isKeyDown(button); + return true; } + wasDown = isKeyDown(button); + } - // record keyboard state - m_keyState->onKey(button, down, oldState); + // record keyboard state + m_keyState->onKey(button, down, oldState); - if (!down && m_isPrimary && !m_isOnScreen) { - PrimaryKeyDownList::iterator find = std::find(m_primaryKeyDownList.begin(), m_primaryKeyDownList.end(), button); - if (find != m_primaryKeyDownList.end()) { - LOG((CLOG_DEBUG1 "release key button %d on primary", *find)); - m_hook.setMode(kHOOK_WATCH_JUMP_ZONE); - fakeLocalKey(*find, false); - m_primaryKeyDownList.erase(find); - m_hook.setMode(kHOOK_RELAY_EVENTS); - return true; - } + if (!down && m_isPrimary && !m_isOnScreen) { + PrimaryKeyDownList::iterator find = std::find( + m_primaryKeyDownList.begin(), m_primaryKeyDownList.end(), button); + if (find != m_primaryKeyDownList.end()) { + LOG((CLOG_DEBUG1 "release key button %d on primary", *find)); + m_hook.setMode(kHOOK_WATCH_JUMP_ZONE); + fakeLocalKey(*find, false); + m_primaryKeyDownList.erase(find); + m_hook.setMode(kHOOK_RELAY_EVENTS); + return true; } + } - // windows doesn't tell us the modifier key state on mouse or key - // events so we have to figure it out. most apps would use - // GetKeyState() or even GetAsyncKeyState() for that but we can't - // because our hook doesn't pass on key events for several modifiers. - // it can't otherwise the system would interpret them normally on - // the primary screen even when on a secondary screen. so tapping - // alt would activate menus and tapping the windows key would open - // the start menu. if you don't pass those events on in the hook - // then GetKeyState() understandably doesn't reflect the effect of - // the event. curiously, neither does GetAsyncKeyState(), which is - // surprising. - // - // so anyway, we have to track the modifier state ourselves for - // at least those modifiers we don't pass on. pollActiveModifiers() - // does that but we have to update the keyboard state before calling - // pollActiveModifiers() to get the right answer. but the only way - // to set the modifier state or to set the up/down state of a key - // is via onKey(). so we have to call onKey() twice. - KeyModifierMask state = pollActiveModifiers(); - m_keyState->onKey(button, down, state); + // windows doesn't tell us the modifier key state on mouse or key + // events so we have to figure it out. most apps would use + // GetKeyState() or even GetAsyncKeyState() for that but we can't + // because our hook doesn't pass on key events for several modifiers. + // it can't otherwise the system would interpret them normally on + // the primary screen even when on a secondary screen. so tapping + // alt would activate menus and tapping the windows key would open + // the start menu. if you don't pass those events on in the hook + // then GetKeyState() understandably doesn't reflect the effect of + // the event. curiously, neither does GetAsyncKeyState(), which is + // surprising. + // + // so anyway, we have to track the modifier state ourselves for + // at least those modifiers we don't pass on. pollActiveModifiers() + // does that but we have to update the keyboard state before calling + // pollActiveModifiers() to get the right answer. but the only way + // to set the modifier state or to set the up/down state of a key + // is via onKey(). so we have to call onKey() twice. + KeyModifierMask state = pollActiveModifiers(); + m_keyState->onKey(button, down, state); - // check for hot keys - if (oldState != state) { - // modifier key was pressed/released - if (onHotKey(0, lParam)) { - return true; - } + // check for hot keys + if (oldState != state) { + // modifier key was pressed/released + if (onHotKey(0, lParam)) { + return true; } - else { - // non-modifier was pressed/released - if (onHotKey(wParam, lParam)) { - return true; - } - } - - // stop sending modifier keys over and over again - if (isModifierRepeat(oldState, state, wParam)) { - return true; - } - - // ignore message if posted prior to last mark change - if (!ignore()) { - // check for ctrl+alt+del. we do not want to pass that to the - // client. the user can use ctrl+alt+pause to emulate it. - UINT virtKey = ((wParam >> 16) & 0xffu); - if (virtKey == VK_DELETE && (state & s_ctrlAlt) == s_ctrlAlt) { - LOG((CLOG_DEBUG "discard ctrl+alt+del")); - return true; - } - - // check for ctrl+alt+del emulation - if ((virtKey == VK_PAUSE || virtKey == VK_CANCEL) && - (state & s_ctrlAlt) == s_ctrlAlt) { - LOG((CLOG_DEBUG "emulate ctrl+alt+del")); - // switch wParam and lParam to be as if VK_DELETE was - // pressed or released. when mapping the key we require that - // we not use AltGr (the 0x10000 flag in wParam) and we not - // use the keypad delete key (the 0x01000000 flag in lParam). - wParam = (VK_DELETE << 16) | 0x01000000u; - lParam &= 0xfe000000; - lParam |= m_keyState->virtualKeyToButton(VK_DELETE) << 16; - lParam |= 0x01000001; - } - - // process key - KeyModifierMask mask; - KeyID key = m_keyState->mapKeyFromEvent(wParam, lParam, &mask); - button = static_cast((lParam & 0x01ff0000u) >> 16); - if (key != kKeyNone) { - // do it - m_keyState->sendKeyEvent(getEventTarget(), - ((lParam & 0x80000000u) == 0), - ((lParam & 0x40000000u) != 0), - key, mask, (SInt32)(lParam & 0xffff), button); - } - else { - LOG((CLOG_DEBUG1 "cannot map key")); - } + } else { + // non-modifier was pressed/released + if (onHotKey(wParam, lParam)) { + return true; } + } + // stop sending modifier keys over and over again + if (isModifierRepeat(oldState, state, wParam)) { return true; + } + + // ignore message if posted prior to last mark change + if (!ignore()) { + // check for ctrl+alt+del. we do not want to pass that to the + // client. the user can use ctrl+alt+pause to emulate it. + UINT virtKey = ((wParam >> 16) & 0xffu); + if (virtKey == VK_DELETE && (state & s_ctrlAlt) == s_ctrlAlt) { + LOG((CLOG_DEBUG "discard ctrl+alt+del")); + return true; + } + + // check for ctrl+alt+del emulation + if ((virtKey == VK_PAUSE || virtKey == VK_CANCEL) && + (state & s_ctrlAlt) == s_ctrlAlt) { + LOG((CLOG_DEBUG "emulate ctrl+alt+del")); + // switch wParam and lParam to be as if VK_DELETE was + // pressed or released. when mapping the key we require that + // we not use AltGr (the 0x10000 flag in wParam) and we not + // use the keypad delete key (the 0x01000000 flag in lParam). + wParam = (VK_DELETE << 16) | 0x01000000u; + lParam &= 0xfe000000; + lParam |= m_keyState->virtualKeyToButton(VK_DELETE) << 16; + lParam |= 0x01000001; + } + + // process key + KeyModifierMask mask; + KeyID key = m_keyState->mapKeyFromEvent(wParam, lParam, &mask); + button = static_cast((lParam & 0x01ff0000u) >> 16); + if (key != kKeyNone) { + // do it + m_keyState->sendKeyEvent(getEventTarget(), ((lParam & 0x80000000u) == 0), + ((lParam & 0x40000000u) != 0), key, mask, + (SInt32)(lParam & 0xffff), button); + } else { + LOG((CLOG_DEBUG1 "cannot map key")); + } + } + + return true; } -bool -MSWindowsScreen::onHotKey(WPARAM wParam, LPARAM lParam) -{ - // get the key info - KeyModifierMask state = getActiveModifiers(); - UINT virtKey = ((wParam >> 16) & 0xffu); - UINT modifiers = 0; - if ((state & KeyModifierShift) != 0) { - modifiers |= MOD_SHIFT; - } - if ((state & KeyModifierControl) != 0) { - modifiers |= MOD_CONTROL; - } - if ((state & KeyModifierAlt) != 0) { - modifiers |= MOD_ALT; - } - if ((state & KeyModifierSuper) != 0) { - modifiers |= MOD_WIN; - } +bool MSWindowsScreen::onHotKey(WPARAM wParam, LPARAM lParam) { + // get the key info + KeyModifierMask state = getActiveModifiers(); + UINT virtKey = ((wParam >> 16) & 0xffu); + UINT modifiers = 0; + if ((state & KeyModifierShift) != 0) { + modifiers |= MOD_SHIFT; + } + if ((state & KeyModifierControl) != 0) { + modifiers |= MOD_CONTROL; + } + if ((state & KeyModifierAlt) != 0) { + modifiers |= MOD_ALT; + } + if ((state & KeyModifierSuper) != 0) { + modifiers |= MOD_WIN; + } - // find the hot key id - HotKeyToIDMap::const_iterator i = - m_hotKeyToIDMap.find(HotKeyItem(virtKey, modifiers)); - if (i == m_hotKeyToIDMap.end()) { - return false; - } + // find the hot key id + HotKeyToIDMap::const_iterator i = + m_hotKeyToIDMap.find(HotKeyItem(virtKey, modifiers)); + if (i == m_hotKeyToIDMap.end()) { + return false; + } - // find what kind of event - Event::Type type; - if ((lParam & 0x80000000u) == 0u) { - if ((lParam & 0x40000000u) != 0u) { - // ignore key repeats but it counts as a hot key - return true; - } - type = m_events->forIPrimaryScreen().hotKeyDown(); - } - else { - type = m_events->forIPrimaryScreen().hotKeyUp(); + // find what kind of event + Event::Type type; + if ((lParam & 0x80000000u) == 0u) { + if ((lParam & 0x40000000u) != 0u) { + // ignore key repeats but it counts as a hot key + return true; } + type = m_events->forIPrimaryScreen().hotKeyDown(); + } else { + type = m_events->forIPrimaryScreen().hotKeyUp(); + } - // generate event - m_events->addEvent(Event(type, getEventTarget(), - HotKeyInfo::alloc(i->second))); + // generate event + m_events->addEvent( + Event(type, getEventTarget(), HotKeyInfo::alloc(i->second))); - return true; + return true; } -bool -MSWindowsScreen::onMouseButton(WPARAM wParam, LPARAM lParam) -{ - // get which button - bool pressed = mapPressFromEvent(wParam, lParam); - ButtonID button = mapButtonFromEvent(wParam, lParam); +bool MSWindowsScreen::onMouseButton(WPARAM wParam, LPARAM lParam) { + // get which button + bool pressed = mapPressFromEvent(wParam, lParam); + ButtonID button = mapButtonFromEvent(wParam, lParam); - // keep our shadow key state up to date - if (button >= kButtonLeft && button <= kButtonExtra0 + 1) { - if (pressed) { - m_buttons[button] = true; - if (button == kButtonLeft) { - m_draggingFilename.clear(); - LOG((CLOG_DEBUG2 "dragging filename is cleared")); - } - } - else { - m_buttons[button] = false; - if (m_draggingStarted && button == kButtonLeft) { - m_draggingStarted = false; - } - } + // keep our shadow key state up to date + if (button >= kButtonLeft && button <= kButtonExtra0 + 1) { + if (pressed) { + m_buttons[button] = true; + if (button == kButtonLeft) { + m_draggingFilename.clear(); + LOG((CLOG_DEBUG2 "dragging filename is cleared")); + } + } else { + m_buttons[button] = false; + if (m_draggingStarted && button == kButtonLeft) { + m_draggingStarted = false; + } } + } - // ignore message if posted prior to last mark change - if (!ignore()) { - KeyModifierMask mask = m_keyState->getActiveModifiers(); - if (pressed) { - LOG((CLOG_DEBUG1 "event: button press button=%d", button)); - if (button != kButtonNone) { - sendEvent(m_events->forIPrimaryScreen().buttonDown(), - ButtonInfo::alloc(button, mask)); - } - } - else { - LOG((CLOG_DEBUG1 "event: button release button=%d", button)); - if (button != kButtonNone) { - sendEvent(m_events->forIPrimaryScreen().buttonUp(), - ButtonInfo::alloc(button, mask)); - } - } + // ignore message if posted prior to last mark change + if (!ignore()) { + KeyModifierMask mask = m_keyState->getActiveModifiers(); + if (pressed) { + LOG((CLOG_DEBUG1 "event: button press button=%d", button)); + if (button != kButtonNone) { + sendEvent(m_events->forIPrimaryScreen().buttonDown(), + ButtonInfo::alloc(button, mask)); + } + } else { + LOG((CLOG_DEBUG1 "event: button release button=%d", button)); + if (button != kButtonNone) { + sendEvent(m_events->forIPrimaryScreen().buttonUp(), + ButtonInfo::alloc(button, mask)); + } } + } - return true; + return true; } // here's how mouse movements are sent across the network to a client: @@ -1409,623 +1233,560 @@ MSWindowsScreen::onMouseButton(WPARAM wParam, LPARAM lParam) // 3. records the current x,y as "last" (so we can calc delta next time) // 4. on the server, puts the cursor back to the center of the screen // - remember the cursor is hidden on the server at this point -// - this actually records the current x,y as "last" a second time (it seems) -// 5. sends the delta movement to the client (could be +1,+1 or -1,+4 for example) -bool -MSWindowsScreen::onMouseMove(SInt32 mx, SInt32 my) -{ - // compute motion delta (relative to the last known - // mouse position) - SInt32 x = mx - m_xCursor; - SInt32 y = my - m_yCursor; +// - this actually records the current x,y as "last" a second time (it +// seems) +// 5. sends the delta movement to the client (could be +1,+1 or -1,+4 for +// example) +bool MSWindowsScreen::onMouseMove(SInt32 mx, SInt32 my) { + // compute motion delta (relative to the last known + // mouse position) + SInt32 x = mx - m_xCursor; + SInt32 y = my - m_yCursor; - LOG((CLOG_DEBUG3 - "mouse move - motion delta: %+d=(%+d - %+d),%+d=(%+d - %+d)", - x, mx, m_xCursor, y, my, m_yCursor)); - - // ignore if the mouse didn't move or if message posted prior - // to last mark change. - if (ignore() || (x == 0 && y == 0)) { - return true; - } - - // save position to compute delta of next motion - saveMousePosition(mx, my); - - if (m_isOnScreen) { - - // motion on primary screen - sendEvent( - m_events->forIPrimaryScreen().motionOnPrimary(), - MotionInfo::alloc(m_xCursor, m_yCursor)); - - if (m_buttons[kButtonLeft] == true && m_draggingStarted == false) { - m_draggingStarted = true; - } - } - else - { - // the motion is on the secondary screen, so we warp mouse back to - // center on the server screen. if we don't do this, then the mouse - // will always try to return to the original entry point on the - // secondary screen. - LOG((CLOG_DEBUG5 "warping server cursor to center: %+d,%+d", m_xCenter, m_yCenter)); - warpCursorNoFlush(m_xCenter, m_yCenter); - - // examine the motion. if it's about the distance - // from the center of the screen to an edge then - // it's probably a bogus motion that we want to - // ignore (see warpCursorNoFlush() for a further - // description). - static SInt32 bogusZoneSize = 10; - if (-x + bogusZoneSize > m_xCenter - m_x || - x + bogusZoneSize > m_x + m_w - m_xCenter || - -y + bogusZoneSize > m_yCenter - m_y || - y + bogusZoneSize > m_y + m_h - m_yCenter) { - - LOG((CLOG_DEBUG "dropped bogus delta motion: %+d,%+d", x, y)); - } - else { - // send motion - sendEvent(m_events->forIPrimaryScreen().motionOnSecondary(), MotionInfo::alloc(x, y)); - } - } + LOG((CLOG_DEBUG3 "mouse move - motion delta: %+d=(%+d - %+d),%+d=(%+d - %+d)", + x, mx, m_xCursor, y, my, m_yCursor)); + // ignore if the mouse didn't move or if message posted prior + // to last mark change. + if (ignore() || (x == 0 && y == 0)) { return true; + } + + // save position to compute delta of next motion + saveMousePosition(mx, my); + + if (m_isOnScreen) { + + // motion on primary screen + sendEvent(m_events->forIPrimaryScreen().motionOnPrimary(), + MotionInfo::alloc(m_xCursor, m_yCursor)); + + if (m_buttons[kButtonLeft] == true && m_draggingStarted == false) { + m_draggingStarted = true; + } + } else { + // the motion is on the secondary screen, so we warp mouse back to + // center on the server screen. if we don't do this, then the mouse + // will always try to return to the original entry point on the + // secondary screen. + LOG((CLOG_DEBUG5 "warping server cursor to center: %+d,%+d", m_xCenter, + m_yCenter)); + warpCursorNoFlush(m_xCenter, m_yCenter); + + // examine the motion. if it's about the distance + // from the center of the screen to an edge then + // it's probably a bogus motion that we want to + // ignore (see warpCursorNoFlush() for a further + // description). + static SInt32 bogusZoneSize = 10; + if (-x + bogusZoneSize > m_xCenter - m_x || + x + bogusZoneSize > m_x + m_w - m_xCenter || + -y + bogusZoneSize > m_yCenter - m_y || + y + bogusZoneSize > m_y + m_h - m_yCenter) { + + LOG((CLOG_DEBUG "dropped bogus delta motion: %+d,%+d", x, y)); + } else { + // send motion + sendEvent(m_events->forIPrimaryScreen().motionOnSecondary(), + MotionInfo::alloc(x, y)); + } + } + + return true; } -bool -MSWindowsScreen::onMouseWheel(SInt32 xDelta, SInt32 yDelta) -{ - // ignore message if posted prior to last mark change - if (!ignore()) { - LOG((CLOG_DEBUG1 "event: button wheel delta=%+d,%+d", xDelta, yDelta)); - sendEvent(m_events->forIPrimaryScreen().wheel(), WheelInfo::alloc(xDelta, yDelta)); - } +bool MSWindowsScreen::onMouseWheel(SInt32 xDelta, SInt32 yDelta) { + // ignore message if posted prior to last mark change + if (!ignore()) { + LOG((CLOG_DEBUG1 "event: button wheel delta=%+d,%+d", xDelta, yDelta)); + sendEvent(m_events->forIPrimaryScreen().wheel(), + WheelInfo::alloc(xDelta, yDelta)); + } + return true; +} + +bool MSWindowsScreen::onScreensaver(bool activated) { + // ignore this message if there are any other screen saver + // messages already in the queue. this is important because + // our checkStarted() function has a deliberate delay, so it + // can't respond to events at full CPU speed and will fall + // behind if a lot of screen saver events are generated. + // that can easily happen because windows will continually + // send SC_SCREENSAVE until the screen saver starts, even if + // the screen saver is disabled! + MSG msg; + if (PeekMessage(&msg, NULL, SYNERGY_MSG_SCREEN_SAVER, + SYNERGY_MSG_SCREEN_SAVER, PM_NOREMOVE)) { return true; + } + + if (activated) { + if (!m_screensaverActive && + m_screensaver->checkStarted(SYNERGY_MSG_SCREEN_SAVER, FALSE, 0)) { + m_screensaverActive = true; + sendEvent(m_events->forIPrimaryScreen().screensaverActivated()); + } + } else { + if (m_screensaverActive) { + m_screensaverActive = false; + sendEvent(m_events->forIPrimaryScreen().screensaverDeactivated()); + } + } + + return true; } -bool -MSWindowsScreen::onScreensaver(bool activated) -{ - // ignore this message if there are any other screen saver - // messages already in the queue. this is important because - // our checkStarted() function has a deliberate delay, so it - // can't respond to events at full CPU speed and will fall - // behind if a lot of screen saver events are generated. - // that can easily happen because windows will continually - // send SC_SCREENSAVE until the screen saver starts, even if - // the screen saver is disabled! - MSG msg; - if (PeekMessage(&msg, NULL, SYNERGY_MSG_SCREEN_SAVER, - SYNERGY_MSG_SCREEN_SAVER, PM_NOREMOVE)) { - return true; +bool MSWindowsScreen::onDisplayChange() { + // screen resolution may have changed. save old shape. + SInt32 xOld = m_x, yOld = m_y, wOld = m_w, hOld = m_h; + + // update shape + updateScreenShape(); + + // do nothing if resolution hasn't changed + if (xOld != m_x || yOld != m_y || wOld != m_w || hOld != m_h) { + if (m_isPrimary) { + // warp mouse to center if off screen + if (!m_isOnScreen) { + + LOG((CLOG_DEBUG1 "warping cursor to center: %+d, %+d", m_xCenter, + m_yCenter)); + warpCursor(m_xCenter, m_yCenter); + } + + // tell hook about resize if on screen + else { + m_hook.setZone(m_x, m_y, m_w, m_h, getJumpZoneSize()); + } } - if (activated) { - if (!m_screensaverActive && - m_screensaver->checkStarted(SYNERGY_MSG_SCREEN_SAVER, FALSE, 0)) { - m_screensaverActive = true; - sendEvent(m_events->forIPrimaryScreen().screensaverActivated()); - } - } - else { - if (m_screensaverActive) { - m_screensaverActive = false; - sendEvent(m_events->forIPrimaryScreen().screensaverDeactivated()); - } - } + // send new screen info + sendEvent(m_events->forIScreen().shapeChanged()); + LOG((CLOG_DEBUG "screen shape: %d,%d %dx%d %s", m_x, m_y, m_w, m_h, + m_multimon ? "(multi-monitor)" : "")); + } + + return true; +} + +bool MSWindowsScreen::onClipboardChange() { + // now notify client that somebody changed the clipboard (unless + // we're the owner). + if (!MSWindowsClipboard::isOwnedBySynergy()) { + if (m_ownClipboard) { + LOG((CLOG_DEBUG "clipboard changed: lost ownership")); + m_ownClipboard = false; + sendClipboardEvent(m_events->forClipboard().clipboardGrabbed(), + kClipboardClipboard); + sendClipboardEvent(m_events->forClipboard().clipboardGrabbed(), + kClipboardSelection); + } + } else if (!m_ownClipboard) { + LOG((CLOG_DEBUG "clipboard changed: synergy owned")); + m_ownClipboard = true; + } + + return true; +} + +void MSWindowsScreen::warpCursorNoFlush(SInt32 x, SInt32 y) { + // send an event that we can recognize before the mouse warp + PostThreadMessage(GetCurrentThreadId(), SYNERGY_MSG_PRE_WARP, x, y); + + // warp mouse. hopefully this inserts a mouse motion event + // between the previous message and the following message. + setThisCursorPos(x, y); + + // check to see if the mouse pos was set correctly + POINT cursorPos; + getThisCursorPos(&cursorPos); + + // there is a bug or round error in SetCursorPos and GetCursorPos on + // a high DPI setting. The check here is for Vista/7 login screen. + // since this feature is mainly for client, so only check on client. + if (!isPrimary()) { + if ((cursorPos.x != x) && (cursorPos.y != y)) { + LOG((CLOG_DEBUG + "function 'SetCursorPos' failed; trying 'fakeMouseMove'")); + LOG((CLOG_DEBUG "cursor pos %d, %d expected pos %d, %d", cursorPos.x, + cursorPos.y, x, y)); + // when at Vista/7 login screen, SetCursorPos does not work (which could + // be an MS security feature). instead we can use fakeMouseMove, which + // calls mouse_event. IMPORTANT: as of implementing this function, it has + // an annoying side effect; instead of the mouse returning to the correct + // exit point, it returns to the center of the screen. this could have + // something to do with the center screen warping technique used (see + // comments for onMouseMove definition). + fakeMouseMove(x, y); + } + } + + // yield the CPU. there's a race condition when warping: + // a hardware mouse event occurs + // the mouse hook is not called because that process doesn't have the CPU + // we send PRE_WARP, SetCursorPos(), send POST_WARP + // we process all of those events and update m_x, m_y + // we finish our time slice + // the hook is called + // the hook sends us a mouse event from the pre-warp position + // we get the CPU + // we compute a bogus warp + // we need the hook to process all mouse events that occur + // before we warp before we do the warp but i'm not sure how + // to guarantee that. yielding the CPU here may reduce the + // chance of undesired behavior. we'll also check for very + // large motions that look suspiciously like about half width + // or height of the screen. + ARCH->sleep(0.0); + + // send an event that we can recognize after the mouse warp + PostThreadMessage(GetCurrentThreadId(), SYNERGY_MSG_POST_WARP, 0, 0); +} + +void MSWindowsScreen::nextMark() { + // next mark + ++m_mark; + + // mark point in message queue where the mark was changed + PostThreadMessage(GetCurrentThreadId(), SYNERGY_MSG_MARK, m_mark, 0); +} + +bool MSWindowsScreen::ignore() const { return (m_mark != m_markReceived); } + +void MSWindowsScreen::updateScreenShape() { + // get shape and center + m_w = GetSystemMetrics(SM_CXVIRTUALSCREEN); + m_h = GetSystemMetrics(SM_CYVIRTUALSCREEN); + m_x = GetSystemMetrics(SM_XVIRTUALSCREEN); + m_y = GetSystemMetrics(SM_YVIRTUALSCREEN); + m_xCenter = GetSystemMetrics(SM_CXSCREEN) >> 1; + m_yCenter = GetSystemMetrics(SM_CYSCREEN) >> 1; + + // check for multiple monitors + m_multimon = (m_w != GetSystemMetrics(SM_CXSCREEN) || + m_h != GetSystemMetrics(SM_CYSCREEN)); + + // tell the desks + m_desks->setShape(m_x, m_y, m_w, m_h, m_xCenter, m_yCenter, m_multimon); +} + +void MSWindowsScreen::handleFixes(const Event &, void *) { + // fix clipboard chain + fixClipboardViewer(); + + // update keys if keyboard layouts have changed + if (m_keyState->didGroupsChange()) { + updateKeys(); + } +} + +void MSWindowsScreen::fixClipboardViewer() { + // XXX -- disable this code for now. somehow it can cause an infinite + // recursion in the WM_DRAWCLIPBOARD handler. either we're sending + // the message to our own window or some window farther down the chain + // forwards the message to our window or a window farther up the chain. + // i'm not sure how that could happen. the m_nextClipboardWindow = NULL + // was not in the code that infinite loops and may fix the bug but i + // doubt it. + /* + ChangeClipboardChain(m_window, m_nextClipboardWindow); + m_nextClipboardWindow = NULL; + m_nextClipboardWindow = SetClipboardViewer(m_window); + */ +} + +void MSWindowsScreen::enableSpecialKeys(bool enable) const {} + +ButtonID MSWindowsScreen::mapButtonFromEvent(WPARAM msg, LPARAM button) const { + switch (msg) { + case WM_LBUTTONDOWN: + case WM_LBUTTONDBLCLK: + case WM_LBUTTONUP: + case WM_NCLBUTTONDOWN: + case WM_NCLBUTTONDBLCLK: + case WM_NCLBUTTONUP: + return kButtonLeft; + + case WM_MBUTTONDOWN: + case WM_MBUTTONDBLCLK: + case WM_MBUTTONUP: + case WM_NCMBUTTONDOWN: + case WM_NCMBUTTONDBLCLK: + case WM_NCMBUTTONUP: + return kButtonMiddle; + + case WM_RBUTTONDOWN: + case WM_RBUTTONDBLCLK: + case WM_RBUTTONUP: + case WM_NCRBUTTONDOWN: + case WM_NCRBUTTONDBLCLK: + case WM_NCRBUTTONUP: + return kButtonRight; + + case WM_XBUTTONDOWN: + case WM_XBUTTONDBLCLK: + case WM_XBUTTONUP: + case WM_NCXBUTTONDOWN: + case WM_NCXBUTTONDBLCLK: + case WM_NCXBUTTONUP: + switch (button) { + case XBUTTON1: + if (GetSystemMetrics(SM_CMOUSEBUTTONS) >= 4) { + return kButtonExtra0 + 0; + } + break; + + case XBUTTON2: + if (GetSystemMetrics(SM_CMOUSEBUTTONS) >= 5) { + return kButtonExtra0 + 1; + } + break; + } + return kButtonNone; + + default: + return kButtonNone; + } +} + +bool MSWindowsScreen::mapPressFromEvent(WPARAM msg, LPARAM) const { + switch (msg) { + case WM_LBUTTONDOWN: + case WM_MBUTTONDOWN: + case WM_RBUTTONDOWN: + case WM_XBUTTONDOWN: + case WM_LBUTTONDBLCLK: + case WM_MBUTTONDBLCLK: + case WM_RBUTTONDBLCLK: + case WM_XBUTTONDBLCLK: + case WM_NCLBUTTONDOWN: + case WM_NCMBUTTONDOWN: + case WM_NCRBUTTONDOWN: + case WM_NCXBUTTONDOWN: + case WM_NCLBUTTONDBLCLK: + case WM_NCMBUTTONDBLCLK: + case WM_NCRBUTTONDBLCLK: + case WM_NCXBUTTONDBLCLK: return true; + + case WM_LBUTTONUP: + case WM_MBUTTONUP: + case WM_RBUTTONUP: + case WM_XBUTTONUP: + case WM_NCLBUTTONUP: + case WM_NCMBUTTONUP: + case WM_NCRBUTTONUP: + case WM_NCXBUTTONUP: + return false; + + default: + return false; + } } -bool -MSWindowsScreen::onDisplayChange() -{ - // screen resolution may have changed. save old shape. - SInt32 xOld = m_x, yOld = m_y, wOld = m_w, hOld = m_h; - - // update shape - updateScreenShape(); - - // do nothing if resolution hasn't changed - if (xOld != m_x || yOld != m_y || wOld != m_w || hOld != m_h) { - if (m_isPrimary) { - // warp mouse to center if off screen - if (!m_isOnScreen) { - - LOG((CLOG_DEBUG1 "warping cursor to center: %+d, %+d", m_xCenter, m_yCenter)); - warpCursor(m_xCenter, m_yCenter); - } - - // tell hook about resize if on screen - else { - m_hook.setZone(m_x, m_y, m_w, m_h, getJumpZoneSize()); - } - } - - // send new screen info - sendEvent(m_events->forIScreen().shapeChanged()); - - LOG((CLOG_DEBUG "screen shape: %d,%d %dx%d %s", m_x, m_y, m_w, m_h, m_multimon ? "(multi-monitor)" : "")); +void MSWindowsScreen::updateKeysCB(void *) { + // record which keys we think are down + bool down[IKeyState::kNumButtons]; + bool sendFixes = (isPrimary() && !m_isOnScreen); + if (sendFixes) { + for (KeyButton i = 0; i < IKeyState::kNumButtons; ++i) { + down[i] = m_keyState->isKeyDown(i); } + } - return true; -} + // update layouts if necessary + if (m_keyState->didGroupsChange()) { + PlatformScreen::updateKeyMap(); + } -bool -MSWindowsScreen::onClipboardChange() -{ - // now notify client that somebody changed the clipboard (unless - // we're the owner). - if (!MSWindowsClipboard::isOwnedBySynergy()) { - if (m_ownClipboard) { - LOG((CLOG_DEBUG "clipboard changed: lost ownership")); - m_ownClipboard = false; - sendClipboardEvent(m_events->forClipboard().clipboardGrabbed(), kClipboardClipboard); - sendClipboardEvent(m_events->forClipboard().clipboardGrabbed(), kClipboardSelection); - } + // now update the keyboard state + PlatformScreen::updateKeyState(); + + // now see which keys we thought were down but now think are up. + // send key releases for these keys to the active client. + if (sendFixes) { + KeyModifierMask mask = pollActiveModifiers(); + for (KeyButton i = 0; i < IKeyState::kNumButtons; ++i) { + if (down[i] && !m_keyState->isKeyDown(i)) { + m_keyState->sendKeyEvent(getEventTarget(), false, false, kKeyNone, mask, + 1, i); + } } - else if (!m_ownClipboard) { - LOG((CLOG_DEBUG "clipboard changed: synergy owned")); - m_ownClipboard = true; + } +} + +void MSWindowsScreen::forceShowCursor() { + // check for mouse + m_hasMouse = (GetSystemMetrics(SM_MOUSEPRESENT) != 0); + + // decide if we should show the mouse + bool showMouse = (!m_hasMouse && !m_isPrimary && m_isOnScreen); + + // show/hide the mouse + if (showMouse != m_showingMouse) { + if (showMouse) { + m_oldMouseKeys.cbSize = sizeof(m_oldMouseKeys); + m_gotOldMouseKeys = + (SystemParametersInfo(SPI_GETMOUSEKEYS, m_oldMouseKeys.cbSize, + &m_oldMouseKeys, 0) != 0); + if (m_gotOldMouseKeys) { + m_mouseKeys = m_oldMouseKeys; + m_showingMouse = true; + updateForceShowCursor(); + } + } else { + if (m_gotOldMouseKeys) { + SystemParametersInfo(SPI_SETMOUSEKEYS, m_oldMouseKeys.cbSize, + &m_oldMouseKeys, SPIF_SENDCHANGE); + m_showingMouse = false; + } } - - return true; + } } -void -MSWindowsScreen::warpCursorNoFlush(SInt32 x, SInt32 y) -{ - // send an event that we can recognize before the mouse warp - PostThreadMessage(GetCurrentThreadId(), SYNERGY_MSG_PRE_WARP, x, y); +void MSWindowsScreen::updateForceShowCursor() { + DWORD oldFlags = m_mouseKeys.dwFlags; - // warp mouse. hopefully this inserts a mouse motion event - // between the previous message and the following message. - setThisCursorPos(x, y); + // turn on MouseKeys + m_mouseKeys.dwFlags = MKF_AVAILABLE | MKF_MOUSEKEYSON; - // check to see if the mouse pos was set correctly - POINT cursorPos; - getThisCursorPos(&cursorPos); - - // there is a bug or round error in SetCursorPos and GetCursorPos on - // a high DPI setting. The check here is for Vista/7 login screen. - // since this feature is mainly for client, so only check on client. - if (!isPrimary()) { - if ((cursorPos.x != x) && (cursorPos.y != y)) { - LOG((CLOG_DEBUG "function 'SetCursorPos' failed; trying 'fakeMouseMove'")); - LOG((CLOG_DEBUG "cursor pos %d, %d expected pos %d, %d", cursorPos.x, cursorPos.y, x, y)); - // when at Vista/7 login screen, SetCursorPos does not work (which could be - // an MS security feature). instead we can use fakeMouseMove, which calls - // mouse_event. - // IMPORTANT: as of implementing this function, it has an annoying side - // effect; instead of the mouse returning to the correct exit point, it - // returns to the center of the screen. this could have something to do with - // the center screen warping technique used (see comments for onMouseMove - // definition). - fakeMouseMove(x, y); - } - } + // make sure MouseKeys is active in whatever state the NumLock is + // not currently in. + if ((m_keyState->getActiveModifiers() & KeyModifierNumLock) != 0) { + m_mouseKeys.dwFlags |= MKF_REPLACENUMBERS; + } - // yield the CPU. there's a race condition when warping: - // a hardware mouse event occurs - // the mouse hook is not called because that process doesn't have the CPU - // we send PRE_WARP, SetCursorPos(), send POST_WARP - // we process all of those events and update m_x, m_y - // we finish our time slice - // the hook is called - // the hook sends us a mouse event from the pre-warp position - // we get the CPU - // we compute a bogus warp - // we need the hook to process all mouse events that occur - // before we warp before we do the warp but i'm not sure how - // to guarantee that. yielding the CPU here may reduce the - // chance of undesired behavior. we'll also check for very - // large motions that look suspiciously like about half width - // or height of the screen. - ARCH->sleep(0.0); - - // send an event that we can recognize after the mouse warp - PostThreadMessage(GetCurrentThreadId(), SYNERGY_MSG_POST_WARP, 0, 0); + // update MouseKeys + if (oldFlags != m_mouseKeys.dwFlags) { + SystemParametersInfo(SPI_SETMOUSEKEYS, m_mouseKeys.cbSize, &m_mouseKeys, + SPIF_SENDCHANGE); + } } -void -MSWindowsScreen::nextMark() -{ - // next mark - ++m_mark; +LRESULT CALLBACK MSWindowsScreen::wndProc(HWND hwnd, UINT msg, WPARAM wParam, + LPARAM lParam) { + assert(s_screen != NULL); - // mark point in message queue where the mark was changed - PostThreadMessage(GetCurrentThreadId(), SYNERGY_MSG_MARK, m_mark, 0); + LRESULT result = 0; + if (!s_screen->onEvent(hwnd, msg, wParam, lParam, &result)) { + result = DefWindowProc(hwnd, msg, wParam, lParam); + } + + return result; } -bool -MSWindowsScreen::ignore() const -{ - return (m_mark != m_markReceived); -} - -void -MSWindowsScreen::updateScreenShape() -{ - // get shape and center - m_w = GetSystemMetrics(SM_CXVIRTUALSCREEN); - m_h = GetSystemMetrics(SM_CYVIRTUALSCREEN); - m_x = GetSystemMetrics(SM_XVIRTUALSCREEN); - m_y = GetSystemMetrics(SM_YVIRTUALSCREEN); - m_xCenter = GetSystemMetrics(SM_CXSCREEN) >> 1; - m_yCenter = GetSystemMetrics(SM_CYSCREEN) >> 1; - - // check for multiple monitors - m_multimon = (m_w != GetSystemMetrics(SM_CXSCREEN) || - m_h != GetSystemMetrics(SM_CYSCREEN)); - - // tell the desks - m_desks->setShape(m_x, m_y, m_w, m_h, m_xCenter, m_yCenter, m_multimon); -} - -void -MSWindowsScreen::handleFixes(const Event&, void*) -{ - // fix clipboard chain - fixClipboardViewer(); - - // update keys if keyboard layouts have changed - if (m_keyState->didGroupsChange()) { - updateKeys(); - } -} - -void -MSWindowsScreen::fixClipboardViewer() -{ - // XXX -- disable this code for now. somehow it can cause an infinite - // recursion in the WM_DRAWCLIPBOARD handler. either we're sending - // the message to our own window or some window farther down the chain - // forwards the message to our window or a window farther up the chain. - // i'm not sure how that could happen. the m_nextClipboardWindow = NULL - // was not in the code that infinite loops and may fix the bug but i - // doubt it. -/* - ChangeClipboardChain(m_window, m_nextClipboardWindow); - m_nextClipboardWindow = NULL; - m_nextClipboardWindow = SetClipboardViewer(m_window); -*/ -} - -void -MSWindowsScreen::enableSpecialKeys(bool enable) const -{ -} - -ButtonID -MSWindowsScreen::mapButtonFromEvent(WPARAM msg, LPARAM button) const -{ - switch (msg) { - case WM_LBUTTONDOWN: - case WM_LBUTTONDBLCLK: - case WM_LBUTTONUP: - case WM_NCLBUTTONDOWN: - case WM_NCLBUTTONDBLCLK: - case WM_NCLBUTTONUP: - return kButtonLeft; - - case WM_MBUTTONDOWN: - case WM_MBUTTONDBLCLK: - case WM_MBUTTONUP: - case WM_NCMBUTTONDOWN: - case WM_NCMBUTTONDBLCLK: - case WM_NCMBUTTONUP: - return kButtonMiddle; - - case WM_RBUTTONDOWN: - case WM_RBUTTONDBLCLK: - case WM_RBUTTONUP: - case WM_NCRBUTTONDOWN: - case WM_NCRBUTTONDBLCLK: - case WM_NCRBUTTONUP: - return kButtonRight; - - case WM_XBUTTONDOWN: - case WM_XBUTTONDBLCLK: - case WM_XBUTTONUP: - case WM_NCXBUTTONDOWN: - case WM_NCXBUTTONDBLCLK: - case WM_NCXBUTTONUP: - switch (button) { - case XBUTTON1: - if (GetSystemMetrics(SM_CMOUSEBUTTONS) >= 4) { - return kButtonExtra0 + 0; - } - break; - - case XBUTTON2: - if (GetSystemMetrics(SM_CMOUSEBUTTONS) >= 5) { - return kButtonExtra0 + 1; - } - break; - } - return kButtonNone; - - default: - return kButtonNone; - } -} - -bool -MSWindowsScreen::mapPressFromEvent(WPARAM msg, LPARAM) const -{ - switch (msg) { - case WM_LBUTTONDOWN: - case WM_MBUTTONDOWN: - case WM_RBUTTONDOWN: - case WM_XBUTTONDOWN: - case WM_LBUTTONDBLCLK: - case WM_MBUTTONDBLCLK: - case WM_RBUTTONDBLCLK: - case WM_XBUTTONDBLCLK: - case WM_NCLBUTTONDOWN: - case WM_NCMBUTTONDOWN: - case WM_NCRBUTTONDOWN: - case WM_NCXBUTTONDOWN: - case WM_NCLBUTTONDBLCLK: - case WM_NCMBUTTONDBLCLK: - case WM_NCRBUTTONDBLCLK: - case WM_NCXBUTTONDBLCLK: - return true; - - case WM_LBUTTONUP: - case WM_MBUTTONUP: - case WM_RBUTTONUP: - case WM_XBUTTONUP: - case WM_NCLBUTTONUP: - case WM_NCMBUTTONUP: - case WM_NCRBUTTONUP: - case WM_NCXBUTTONUP: - return false; - - default: - return false; - } -} - -void -MSWindowsScreen::updateKeysCB(void*) -{ - // record which keys we think are down - bool down[IKeyState::kNumButtons]; - bool sendFixes = (isPrimary() && !m_isOnScreen); - if (sendFixes) { - for (KeyButton i = 0; i < IKeyState::kNumButtons; ++i) { - down[i] = m_keyState->isKeyDown(i); - } - } - - // update layouts if necessary - if (m_keyState->didGroupsChange()) { - PlatformScreen::updateKeyMap(); - } - - // now update the keyboard state - PlatformScreen::updateKeyState(); - - // now see which keys we thought were down but now think are up. - // send key releases for these keys to the active client. - if (sendFixes) { - KeyModifierMask mask = pollActiveModifiers(); - for (KeyButton i = 0; i < IKeyState::kNumButtons; ++i) { - if (down[i] && !m_keyState->isKeyDown(i)) { - m_keyState->sendKeyEvent(getEventTarget(), - false, false, kKeyNone, mask, 1, i); - } - } - } -} - -void -MSWindowsScreen::forceShowCursor() -{ - // check for mouse - m_hasMouse = (GetSystemMetrics(SM_MOUSEPRESENT) != 0); - - // decide if we should show the mouse - bool showMouse = (!m_hasMouse && !m_isPrimary && m_isOnScreen); - - // show/hide the mouse - if (showMouse != m_showingMouse) { - if (showMouse) { - m_oldMouseKeys.cbSize = sizeof(m_oldMouseKeys); - m_gotOldMouseKeys = - (SystemParametersInfo(SPI_GETMOUSEKEYS, - m_oldMouseKeys.cbSize, &m_oldMouseKeys, 0) != 0); - if (m_gotOldMouseKeys) { - m_mouseKeys = m_oldMouseKeys; - m_showingMouse = true; - updateForceShowCursor(); - } - } - else { - if (m_gotOldMouseKeys) { - SystemParametersInfo(SPI_SETMOUSEKEYS, - m_oldMouseKeys.cbSize, - &m_oldMouseKeys, SPIF_SENDCHANGE); - m_showingMouse = false; - } - } - } -} - -void -MSWindowsScreen::updateForceShowCursor() -{ - DWORD oldFlags = m_mouseKeys.dwFlags; - - // turn on MouseKeys - m_mouseKeys.dwFlags = MKF_AVAILABLE | MKF_MOUSEKEYSON; - - // make sure MouseKeys is active in whatever state the NumLock is - // not currently in. - if ((m_keyState->getActiveModifiers() & KeyModifierNumLock) != 0) { - m_mouseKeys.dwFlags |= MKF_REPLACENUMBERS; - } - - // update MouseKeys - if (oldFlags != m_mouseKeys.dwFlags) { - SystemParametersInfo(SPI_SETMOUSEKEYS, - m_mouseKeys.cbSize, &m_mouseKeys, SPIF_SENDCHANGE); - } -} - -LRESULT CALLBACK -MSWindowsScreen::wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - assert(s_screen != NULL); - - LRESULT result = 0; - if (!s_screen->onEvent(hwnd, msg, wParam, lParam, &result)) { - result = DefWindowProc(hwnd, msg, wParam, lParam); - } - - return result; -} - -void -MSWindowsScreen::fakeLocalKey(KeyButton button, bool press) const -{ - INPUT input; - input.type = INPUT_KEYBOARD; - input.ki.wVk = m_keyState->mapButtonToVirtualKey(button); - DWORD pressFlag = press ? KEYEVENTF_EXTENDEDKEY : KEYEVENTF_KEYUP; - input.ki.dwFlags = pressFlag; - input.ki.time = 0; - input.ki.dwExtraInfo = 0; - SendInput(1,&input,sizeof(input)); +void MSWindowsScreen::fakeLocalKey(KeyButton button, bool press) const { + INPUT input; + input.type = INPUT_KEYBOARD; + input.ki.wVk = m_keyState->mapButtonToVirtualKey(button); + DWORD pressFlag = press ? KEYEVENTF_EXTENDEDKEY : KEYEVENTF_KEYUP; + input.ki.dwFlags = pressFlag; + input.ki.time = 0; + input.ki.dwExtraInfo = 0; + SendInput(1, &input, sizeof(input)); } // // MSWindowsScreen::HotKeyItem // -MSWindowsScreen::HotKeyItem::HotKeyItem(UINT keycode, UINT mask) : - m_keycode(keycode), - m_mask(mask) -{ - // do nothing +MSWindowsScreen::HotKeyItem::HotKeyItem(UINT keycode, UINT mask) + : m_keycode(keycode), m_mask(mask) { + // do nothing } -UINT -MSWindowsScreen::HotKeyItem::getVirtualKey() const -{ - return m_keycode; +UINT MSWindowsScreen::HotKeyItem::getVirtualKey() const { return m_keycode; } + +bool MSWindowsScreen::HotKeyItem::operator<(const HotKeyItem &x) const { + return (m_keycode < x.m_keycode || + (m_keycode == x.m_keycode && m_mask < x.m_mask)); } -bool -MSWindowsScreen::HotKeyItem::operator<(const HotKeyItem& x) const -{ - return (m_keycode < x.m_keycode || - (m_keycode == x.m_keycode && m_mask < x.m_mask)); +void MSWindowsScreen::fakeDraggingFiles(DragFileList fileList) { + // possible design flaw: this function stops a "not implemented" + // exception from being thrown. } -void -MSWindowsScreen::fakeDraggingFiles(DragFileList fileList) -{ - // possible design flaw: this function stops a "not implemented" - // exception from being thrown. -} +String &MSWindowsScreen::getDraggingFilename() { + if (m_draggingStarted) { + m_dropTarget->clearDraggingFilename(); + m_draggingFilename.clear(); -String& -MSWindowsScreen::getDraggingFilename() -{ - if (m_draggingStarted) { - m_dropTarget->clearDraggingFilename(); - m_draggingFilename.clear(); + int halfSize = m_dropWindowSize / 2; - int halfSize = m_dropWindowSize / 2; + SInt32 xPos = m_isPrimary ? m_xCursor : m_xCenter; + SInt32 yPos = m_isPrimary ? m_yCursor : m_yCenter; + xPos = (xPos - halfSize) < 0 ? 0 : xPos - halfSize; + yPos = (yPos - halfSize) < 0 ? 0 : yPos - halfSize; + SetWindowPos(m_dropWindow, HWND_TOPMOST, xPos, yPos, m_dropWindowSize, + m_dropWindowSize, SWP_SHOWWINDOW); - SInt32 xPos = m_isPrimary ? m_xCursor : m_xCenter; - SInt32 yPos = m_isPrimary ? m_yCursor : m_yCenter; - xPos = (xPos - halfSize) < 0 ? 0 : xPos - halfSize; - yPos = (yPos - halfSize) < 0 ? 0 : yPos - halfSize; - SetWindowPos( - m_dropWindow, - HWND_TOPMOST, - xPos, - yPos, - m_dropWindowSize, - m_dropWindowSize, - SWP_SHOWWINDOW); + // TODO: fake these keys properly + fakeKeyDown(kKeyEscape, 8192, 1, + AppUtil::instance().getCurrentLanguageCode()); + fakeKeyUp(1); + fakeMouseButton(kButtonLeft, false); - // TODO: fake these keys properly - fakeKeyDown(kKeyEscape, 8192, 1, AppUtil::instance().getCurrentLanguageCode()); - fakeKeyUp(1); - fakeMouseButton(kButtonLeft, false); - - String filename; - DOUBLE timeout = ARCH->time() + .5f; - while (ARCH->time() < timeout) { - ARCH->sleep(.05f); - filename = m_dropTarget->getDraggingFilename(); - if (!filename.empty()) { - break; - } - } - - ShowWindow(m_dropWindow, SW_HIDE); - - if (!filename.empty()) { - if (DragInformation::isFileValid(filename)) { - m_draggingFilename = filename; - } - else { - LOG((CLOG_DEBUG "drag file name is invalid: %s", filename.c_str())); - } - } - - if (m_draggingFilename.empty()) { - LOG((CLOG_DEBUG "failed to get drag file name from OLE")); - } + String filename; + DOUBLE timeout = ARCH->time() + .5f; + while (ARCH->time() < timeout) { + ARCH->sleep(.05f); + filename = m_dropTarget->getDraggingFilename(); + if (!filename.empty()) { + break; + } } - return m_draggingFilename; -} + ShowWindow(m_dropWindow, SW_HIDE); -const String& -MSWindowsScreen::getDropTarget() const -{ - return m_desktopPath; -} - -String -MSWindowsScreen::getSecureInputApp() const -{ - // ignore on Windows - return ""; -} - -bool -MSWindowsScreen::isModifierRepeat(KeyModifierMask oldState, KeyModifierMask state, WPARAM wParam) const -{ - bool result = false; - - if (oldState == state && state != 0) { - UINT virtKey = ((wParam >> 16) & 0xffu); - if ((state & KeyModifierShift) != 0 - && (virtKey == VK_LSHIFT || virtKey == VK_RSHIFT)) { - result = true; - } - if ((state & KeyModifierControl) != 0 - && (virtKey == VK_LCONTROL || virtKey == VK_RCONTROL)) { - result = true; - } - if ((state & KeyModifierAlt) != 0 - && (virtKey == VK_LMENU || virtKey == VK_RMENU)) { - result = true; - } - if ((state & KeyModifierSuper) != 0 - && (virtKey == VK_LWIN || virtKey == VK_RWIN)) { - result = true; - } + if (!filename.empty()) { + if (DragInformation::isFileValid(filename)) { + m_draggingFilename = filename; + } else { + LOG((CLOG_DEBUG "drag file name is invalid: %s", filename.c_str())); + } } - return result; + if (m_draggingFilename.empty()) { + LOG((CLOG_DEBUG "failed to get drag file name from OLE")); + } + } + + return m_draggingFilename; +} + +const String &MSWindowsScreen::getDropTarget() const { return m_desktopPath; } + +String MSWindowsScreen::getSecureInputApp() const { + // ignore on Windows + return ""; +} + +bool MSWindowsScreen::isModifierRepeat(KeyModifierMask oldState, + KeyModifierMask state, + WPARAM wParam) const { + bool result = false; + + if (oldState == state && state != 0) { + UINT virtKey = ((wParam >> 16) & 0xffu); + if ((state & KeyModifierShift) != 0 && + (virtKey == VK_LSHIFT || virtKey == VK_RSHIFT)) { + result = true; + } + if ((state & KeyModifierControl) != 0 && + (virtKey == VK_LCONTROL || virtKey == VK_RCONTROL)) { + result = true; + } + if ((state & KeyModifierAlt) != 0 && + (virtKey == VK_LMENU || virtKey == VK_RMENU)) { + result = true; + } + if ((state & KeyModifierSuper) != 0 && + (virtKey == VK_LWIN || virtKey == VK_RWIN)) { + result = true; + } + } + + return result; } diff --git a/src/lib/platform/MSWindowsScreen.h b/src/lib/platform/MSWindowsScreen.h index 450068e22..56d5ec7a9 100644 --- a/src/lib/platform/MSWindowsScreen.h +++ b/src/lib/platform/MSWindowsScreen.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -18,15 +18,15 @@ #pragma once -#include "platform/MSWindowsHook.h" -#include "platform/MSWindowsPowerManager.h" -#include "synergy/PlatformScreen.h" -#include "synergy/DragInformation.h" -#include "synergy/ClientArgs.h" -#include "platform/synwinhk.h" +#include "base/String.h" #include "mt/CondVar.h" #include "mt/Mutex.h" -#include "base/String.h" +#include "platform/MSWindowsHook.h" +#include "platform/MSWindowsPowerManager.h" +#include "platform/synwinhk.h" +#include "synergy/ClientArgs.h" +#include "synergy/DragInformation.h" +#include "synergy/PlatformScreen.h" #define WIN32_LEAN_AND_MEAN #include @@ -41,334 +41,328 @@ class MSWindowsDropTarget; //! Implementation of IPlatformScreen for Microsoft Windows class MSWindowsScreen : public PlatformScreen { public: - MSWindowsScreen( - bool isPrimary, - bool noHooks, - bool stopOnDeskSwitch, - IEventQueue* events, - bool enableLangSync = false, - lib::synergy::ClientScrollDirection scrollDirection = lib::synergy::ClientScrollDirection::SERVER); - virtual ~MSWindowsScreen(); + MSWindowsScreen(bool isPrimary, bool noHooks, bool stopOnDeskSwitch, + IEventQueue *events, bool enableLangSync = false, + lib::synergy::ClientScrollDirection scrollDirection = + lib::synergy::ClientScrollDirection::SERVER); + virtual ~MSWindowsScreen(); - //! @name manipulators - //@{ + //! @name manipulators + //@{ - //! Initialize - /*! - Saves the application's HINSTANCE. This \b must be called by - WinMain with the HINSTANCE it was passed. - */ - static void init(HINSTANCE); + //! Initialize + /*! + Saves the application's HINSTANCE. This \b must be called by + WinMain with the HINSTANCE it was passed. + */ + static void init(HINSTANCE); - //@} - //! @name accessors - //@{ + //@} + //! @name accessors + //@{ - //! Get instance - /*! - Returns the application instance handle passed to init(). - */ - static HINSTANCE getWindowInstance(); + //! Get instance + /*! + Returns the application instance handle passed to init(). + */ + static HINSTANCE getWindowInstance(); - //@} + //@} - // IScreen overrides - virtual void* getEventTarget() const; - virtual bool getClipboard(ClipboardID id, IClipboard*) const; - virtual void getShape(SInt32& x, SInt32& y, - SInt32& width, SInt32& height) const; - virtual void getCursorPos(SInt32& x, SInt32& y) const; + // IScreen overrides + virtual void *getEventTarget() const; + virtual bool getClipboard(ClipboardID id, IClipboard *) const; + virtual void getShape(SInt32 &x, SInt32 &y, SInt32 &width, + SInt32 &height) const; + virtual void getCursorPos(SInt32 &x, SInt32 &y) const; - /** - * \brief Get the position of the cursor on the current machine - * \param pos the object that the function will use to store the position of the cursor - * \return true if the function was successful - */ - virtual bool getThisCursorPos(LPPOINT pos); - /** - * \brief Sets the cursor position on the current machine - * \param x The x coordinate of the cursor - * \param y The Y coordinate of the cursor - * \return True is successful - */ - virtual bool setThisCursorPos(int x, int y); + /** + * \brief Get the position of the cursor on the current machine + * \param pos the object that the function will use to store the position of + * the cursor \return true if the function was successful + */ + virtual bool getThisCursorPos(LPPOINT pos); + /** + * \brief Sets the cursor position on the current machine + * \param x The x coordinate of the cursor + * \param y The Y coordinate of the cursor + * \return True is successful + */ + virtual bool setThisCursorPos(int x, int y); - /** - * \brief This function will attempt to switch to the current desktop the mouse is located on - */ - virtual void updateDesktopThread(); + /** + * \brief This function will attempt to switch to the current desktop the + * mouse is located on + */ + virtual void updateDesktopThread(); - // IPrimaryScreen overrides - virtual void reconfigure(UInt32 activeSides); - virtual void warpCursor(SInt32 x, SInt32 y); - virtual UInt32 registerHotKey(KeyID key, - KeyModifierMask mask); - virtual void unregisterHotKey(UInt32 id); - virtual void fakeInputBegin(); - virtual void fakeInputEnd(); - virtual SInt32 getJumpZoneSize() const; - virtual bool isAnyMouseButtonDown(UInt32& buttonID) const; - virtual void getCursorCenter(SInt32& x, SInt32& y) const; + // IPrimaryScreen overrides + virtual void reconfigure(UInt32 activeSides); + virtual void warpCursor(SInt32 x, SInt32 y); + virtual UInt32 registerHotKey(KeyID key, KeyModifierMask mask); + virtual void unregisterHotKey(UInt32 id); + virtual void fakeInputBegin(); + virtual void fakeInputEnd(); + virtual SInt32 getJumpZoneSize() const; + virtual bool isAnyMouseButtonDown(UInt32 &buttonID) const; + virtual void getCursorCenter(SInt32 &x, SInt32 &y) const; - // ISecondaryScreen overrides - virtual void fakeMouseButton(ButtonID id, bool press); - virtual void fakeMouseMove(SInt32 x, SInt32 y); - virtual void fakeMouseRelativeMove(SInt32 dx, SInt32 dy) const; - virtual void fakeMouseWheel(SInt32 xDelta, SInt32 yDelta) const; + // ISecondaryScreen overrides + virtual void fakeMouseButton(ButtonID id, bool press); + virtual void fakeMouseMove(SInt32 x, SInt32 y); + virtual void fakeMouseRelativeMove(SInt32 dx, SInt32 dy) const; + virtual void fakeMouseWheel(SInt32 xDelta, SInt32 yDelta) const; - // IKeyState overrides - virtual void updateKeys(); - virtual void fakeKeyDown(KeyID id, KeyModifierMask mask, - KeyButton button, const String& lang); - virtual bool fakeKeyRepeat(KeyID id, KeyModifierMask mask, - SInt32 count, KeyButton button, const String& lang); - virtual bool fakeKeyUp(KeyButton button); - virtual void fakeAllKeysUp(); + // IKeyState overrides + virtual void updateKeys(); + virtual void fakeKeyDown(KeyID id, KeyModifierMask mask, KeyButton button, + const String &lang); + virtual bool fakeKeyRepeat(KeyID id, KeyModifierMask mask, SInt32 count, + KeyButton button, const String &lang); + virtual bool fakeKeyUp(KeyButton button); + virtual void fakeAllKeysUp(); - // IPlatformScreen overrides - virtual void enable(); - virtual void disable(); - virtual void enter(); - virtual bool leave(); - virtual bool setClipboard(ClipboardID, const IClipboard*); - virtual void checkClipboards(); - virtual void openScreensaver(bool notify); - virtual void closeScreensaver(); - virtual void screensaver(bool activate); - virtual void resetOptions(); - virtual void setOptions(const OptionsList& options); - virtual void setSequenceNumber(UInt32); - virtual bool isPrimary() const; - virtual void fakeDraggingFiles(DragFileList fileList); - virtual String& getDraggingFilename(); - virtual const String& - getDropTarget() const; - String getSecureInputApp() const override; + // IPlatformScreen overrides + virtual void enable(); + virtual void disable(); + virtual void enter(); + virtual bool leave(); + virtual bool setClipboard(ClipboardID, const IClipboard *); + virtual void checkClipboards(); + virtual void openScreensaver(bool notify); + virtual void closeScreensaver(); + virtual void screensaver(bool activate); + virtual void resetOptions(); + virtual void setOptions(const OptionsList &options); + virtual void setSequenceNumber(UInt32); + virtual bool isPrimary() const; + virtual void fakeDraggingFiles(DragFileList fileList); + virtual String &getDraggingFilename(); + virtual const String &getDropTarget() const; + String getSecureInputApp() const override; protected: - // IPlatformScreen overrides - virtual void handleSystemEvent(const Event&, void*); - virtual void updateButtons(); - virtual IKeyState* getKeyState() const; + // IPlatformScreen overrides + virtual void handleSystemEvent(const Event &, void *); + virtual void updateButtons(); + virtual IKeyState *getKeyState() const; - // simulate a local key to the system directly - void fakeLocalKey(KeyButton button, bool press) const; + // simulate a local key to the system directly + void fakeLocalKey(KeyButton button, bool press) const; private: - // initialization and shutdown operations - HCURSOR createBlankCursor() const; - void destroyCursor(HCURSOR cursor) const; - ATOM createWindowClass() const; - ATOM createDeskWindowClass(bool isPrimary) const; - void destroyClass(ATOM windowClass) const; - HWND createWindow(ATOM windowClass, const char* name) const; - HWND createDropWindow(ATOM windowClass, const char* name) const; - void destroyWindow(HWND) const; + // initialization and shutdown operations + HCURSOR createBlankCursor() const; + void destroyCursor(HCURSOR cursor) const; + ATOM createWindowClass() const; + ATOM createDeskWindowClass(bool isPrimary) const; + void destroyClass(ATOM windowClass) const; + HWND createWindow(ATOM windowClass, const char *name) const; + HWND createDropWindow(ATOM windowClass, const char *name) const; + void destroyWindow(HWND) const; - // convenience function to send events + // convenience function to send events public: // HACK - void sendEvent(Event::Type type, void* = NULL); + void sendEvent(Event::Type type, void * = NULL); + private: // HACK - void sendClipboardEvent(Event::Type type, ClipboardID id); + void sendClipboardEvent(Event::Type type, ClipboardID id); - // handle message before it gets dispatched. returns true iff - // the message should not be dispatched. - bool onPreDispatch(HWND, UINT, WPARAM, LPARAM); + // handle message before it gets dispatched. returns true iff + // the message should not be dispatched. + bool onPreDispatch(HWND, UINT, WPARAM, LPARAM); - // handle message before it gets dispatched. returns true iff - // the message should not be dispatched. - bool onPreDispatchPrimary(HWND, UINT, WPARAM, LPARAM); + // handle message before it gets dispatched. returns true iff + // the message should not be dispatched. + bool onPreDispatchPrimary(HWND, UINT, WPARAM, LPARAM); - // handle secondary message before it gets dispatched. returns true iff - // the message should not be dispatched. - bool onPreDispatchSecondary(HWND, UINT, WPARAM, LPARAM); + // handle secondary message before it gets dispatched. returns true iff + // the message should not be dispatched. + bool onPreDispatchSecondary(HWND, UINT, WPARAM, LPARAM); - // handle message. returns true iff handled and optionally sets - // \c *result (which defaults to 0). - bool onEvent(HWND, UINT, WPARAM, LPARAM, LRESULT* result); + // handle message. returns true iff handled and optionally sets + // \c *result (which defaults to 0). + bool onEvent(HWND, UINT, WPARAM, LPARAM, LRESULT *result); - // message handlers - bool onMark(UInt32 mark); - bool onKey(WPARAM, LPARAM); - bool onHotKey(WPARAM, LPARAM); - bool onMouseButton(WPARAM, LPARAM); - bool onMouseMove(SInt32 x, SInt32 y); - bool onMouseWheel(SInt32 xDelta, SInt32 yDelta); - bool onScreensaver(bool activated); - bool onDisplayChange(); - bool onClipboardChange(); + // message handlers + bool onMark(UInt32 mark); + bool onKey(WPARAM, LPARAM); + bool onHotKey(WPARAM, LPARAM); + bool onMouseButton(WPARAM, LPARAM); + bool onMouseMove(SInt32 x, SInt32 y); + bool onMouseWheel(SInt32 xDelta, SInt32 yDelta); + bool onScreensaver(bool activated); + bool onDisplayChange(); + bool onClipboardChange(); - // warp cursor without discarding queued events - void warpCursorNoFlush(SInt32 x, SInt32 y); + // warp cursor without discarding queued events + void warpCursorNoFlush(SInt32 x, SInt32 y); - // discard posted messages - void nextMark(); + // discard posted messages + void nextMark(); - // test if event should be ignored - bool ignore() const; + // test if event should be ignored + bool ignore() const; - // update screen size cache - void updateScreenShape(); + // update screen size cache + void updateScreenShape(); - // fix timer callback - void handleFixes(const Event&, void*); + // fix timer callback + void handleFixes(const Event &, void *); - // fix the clipboard viewer chain - void fixClipboardViewer(); + // fix the clipboard viewer chain + void fixClipboardViewer(); - // enable/disable special key combinations so we can catch/pass them - void enableSpecialKeys(bool) const; + // enable/disable special key combinations so we can catch/pass them + void enableSpecialKeys(bool) const; - // map a button event to a button ID - ButtonID mapButtonFromEvent(WPARAM msg, LPARAM button) const; + // map a button event to a button ID + ButtonID mapButtonFromEvent(WPARAM msg, LPARAM button) const; - // map a button event to a press (true) or release (false) - bool mapPressFromEvent(WPARAM msg, LPARAM button) const; + // map a button event to a press (true) or release (false) + bool mapPressFromEvent(WPARAM msg, LPARAM button) const; - // job to update the key state - void updateKeysCB(void*); + // job to update the key state + void updateKeysCB(void *); - // determine whether the mouse is hidden by the system and force - // it to be displayed if user has entered this secondary screen. - void forceShowCursor(); + // determine whether the mouse is hidden by the system and force + // it to be displayed if user has entered this secondary screen. + void forceShowCursor(); - // forceShowCursor uses MouseKeys to show the cursor. since we - // don't actually want MouseKeys behavior we have to make sure - // it applies when NumLock is in whatever state it's not in now. - // this method does that. - void updateForceShowCursor(); + // forceShowCursor uses MouseKeys to show the cursor. since we + // don't actually want MouseKeys behavior we have to make sure + // it applies when NumLock is in whatever state it's not in now. + // this method does that. + void updateForceShowCursor(); - // our window proc - static LRESULT CALLBACK wndProc(HWND, UINT, WPARAM, LPARAM); - - // save last position of mouse to compute next delta movement - void saveMousePosition(SInt32 x, SInt32 y); + // our window proc + static LRESULT CALLBACK wndProc(HWND, UINT, WPARAM, LPARAM); - // check if it is a modifier key repeating message - bool isModifierRepeat(KeyModifierMask oldState, - KeyModifierMask state, WPARAM wParam) const; + // save last position of mouse to compute next delta movement + void saveMousePosition(SInt32 x, SInt32 y); - // send drag info and data back to server - void sendDragThread(void*); + // check if it is a modifier key repeating message + bool isModifierRepeat(KeyModifierMask oldState, KeyModifierMask state, + WPARAM wParam) const; + + // send drag info and data back to server + void sendDragThread(void *); private: - struct HotKeyItem { - public: - HotKeyItem(UINT vk, UINT modifiers); + struct HotKeyItem { + public: + HotKeyItem(UINT vk, UINT modifiers); - UINT getVirtualKey() const; + UINT getVirtualKey() const; - bool operator<(const HotKeyItem&) const; + bool operator<(const HotKeyItem &) const; - private: - UINT m_keycode; - UINT m_mask; - }; - typedef std::map HotKeyMap; - typedef std::vector HotKeyIDList; - typedef std::map HotKeyToIDMap; - typedef std::vector PrimaryKeyDownList; + private: + UINT m_keycode; + UINT m_mask; + }; + typedef std::map HotKeyMap; + typedef std::vector HotKeyIDList; + typedef std::map HotKeyToIDMap; + typedef std::vector PrimaryKeyDownList; - static HINSTANCE s_windowInstance; + static HINSTANCE s_windowInstance; - // true if screen is being used as a primary screen, false otherwise - bool m_isPrimary; + // true if screen is being used as a primary screen, false otherwise + bool m_isPrimary; - // true if hooks are not to be installed (useful for debugging) - bool m_noHooks; + // true if hooks are not to be installed (useful for debugging) + bool m_noHooks; - // true if mouse has entered the screen - bool m_isOnScreen; + // true if mouse has entered the screen + bool m_isOnScreen; - // our resources - ATOM m_class; + // our resources + ATOM m_class; - // screen shape stuff - SInt32 m_x, m_y; - SInt32 m_w, m_h; - SInt32 m_xCenter, m_yCenter; + // screen shape stuff + SInt32 m_x, m_y; + SInt32 m_w, m_h; + SInt32 m_xCenter, m_yCenter; - // true if system appears to have multiple monitors - bool m_multimon; + // true if system appears to have multiple monitors + bool m_multimon; - // last mouse position - SInt32 m_xCursor, m_yCursor; + // last mouse position + SInt32 m_xCursor, m_yCursor; - // last clipboard - UInt32 m_sequenceNumber; + // last clipboard + UInt32 m_sequenceNumber; - // used to discard queued messages that are no longer needed - UInt32 m_mark; - UInt32 m_markReceived; + // used to discard queued messages that are no longer needed + UInt32 m_mark; + UInt32 m_markReceived; - // the main loop's thread id - DWORD m_threadID; + // the main loop's thread id + DWORD m_threadID; - // timer for periodically checking stuff that requires polling - EventQueueTimer* m_fixTimer; + // timer for periodically checking stuff that requires polling + EventQueueTimer *m_fixTimer; - // the keyboard layout to use when off primary screen - HKL m_keyLayout; + // the keyboard layout to use when off primary screen + HKL m_keyLayout; - // screen saver stuff - MSWindowsScreenSaver* - m_screensaver; - bool m_screensaverNotify; - bool m_screensaverActive; + // screen saver stuff + MSWindowsScreenSaver *m_screensaver; + bool m_screensaverNotify; + bool m_screensaverActive; - // clipboard stuff. our window is used mainly as a clipboard - // owner and as a link in the clipboard viewer chain. - HWND m_window; - HWND m_nextClipboardWindow; - bool m_ownClipboard; + // clipboard stuff. our window is used mainly as a clipboard + // owner and as a link in the clipboard viewer chain. + HWND m_window; + HWND m_nextClipboardWindow; + bool m_ownClipboard; - // one desk per desktop and a cond var to communicate with it - MSWindowsDesks* m_desks; + // one desk per desktop and a cond var to communicate with it + MSWindowsDesks *m_desks; - // keyboard stuff - MSWindowsKeyState* m_keyState; + // keyboard stuff + MSWindowsKeyState *m_keyState; - // hot key stuff - HotKeyMap m_hotKeys; - HotKeyIDList m_oldHotKeyIDs; - HotKeyToIDMap m_hotKeyToIDMap; + // hot key stuff + HotKeyMap m_hotKeys; + HotKeyIDList m_oldHotKeyIDs; + HotKeyToIDMap m_hotKeyToIDMap; - // map of button state - bool m_buttons[1 + kButtonExtra0 + 1]; + // map of button state + bool m_buttons[1 + kButtonExtra0 + 1]; - // the system shows the mouse cursor when an internal display count - // is >= 0. this count is maintained per application but there's - // apparently a system wide count added to the application's count. - // this system count is 0 if there's a mouse attached to the system - // and -1 otherwise. the MouseKeys accessibility feature can modify - // this system count by making the system appear to have a mouse. - // - // m_hasMouse is true iff there's a mouse attached to the system or - // MouseKeys is simulating one. we track this so we can force the - // cursor to be displayed when the user has entered this screen. - // m_showingMouse is true when we're doing that. - bool m_hasMouse; - bool m_showingMouse; - bool m_gotOldMouseKeys; - MOUSEKEYS m_mouseKeys; - MOUSEKEYS m_oldMouseKeys; - - MSWindowsHook m_hook; + // the system shows the mouse cursor when an internal display count + // is >= 0. this count is maintained per application but there's + // apparently a system wide count added to the application's count. + // this system count is 0 if there's a mouse attached to the system + // and -1 otherwise. the MouseKeys accessibility feature can modify + // this system count by making the system appear to have a mouse. + // + // m_hasMouse is true iff there's a mouse attached to the system or + // MouseKeys is simulating one. we track this so we can force the + // cursor to be displayed when the user has entered this screen. + // m_showingMouse is true when we're doing that. + bool m_hasMouse; + bool m_showingMouse; + bool m_gotOldMouseKeys; + MOUSEKEYS m_mouseKeys; + MOUSEKEYS m_oldMouseKeys; - static MSWindowsScreen* - s_screen; - - IEventQueue* m_events; + MSWindowsHook m_hook; - String m_desktopPath; + static MSWindowsScreen *s_screen; - MSWindowsDropTarget* - m_dropTarget; - HWND m_dropWindow; - const int m_dropWindowSize; + IEventQueue *m_events; - Thread* m_sendDragThread; + String m_desktopPath; - PrimaryKeyDownList m_primaryKeyDownList; - MSWindowsPowerManager m_powerManager; + MSWindowsDropTarget *m_dropTarget; + HWND m_dropWindow; + const int m_dropWindowSize; + + Thread *m_sendDragThread; + + PrimaryKeyDownList m_primaryKeyDownList; + MSWindowsPowerManager m_powerManager; }; diff --git a/src/lib/platform/MSWindowsScreenSaver.cpp b/src/lib/platform/MSWindowsScreenSaver.cpp index ea6a0ab03..a411eea57 100644 --- a/src/lib/platform/MSWindowsScreenSaver.cpp +++ b/src/lib/platform/MSWindowsScreenSaver.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -18,12 +18,12 @@ #include "platform/MSWindowsScreenSaver.h" -#include "platform/MSWindowsScreen.h" -#include "mt/Thread.h" #include "arch/Arch.h" #include "arch/win32/ArchMiscWindows.h" #include "base/Log.h" #include "base/TMethodJob.h" +#include "mt/Thread.h" +#include "platform/MSWindowsScreen.h" #include #include @@ -32,316 +32,271 @@ #define SPI_GETSCREENSAVERRUNNING 114 #endif -static const TCHAR* g_isSecureNT = "ScreenSaverIsSecure"; -static const TCHAR* g_isSecure9x = "ScreenSaveUsePassword"; -static const TCHAR* const g_pathScreenSaverIsSecure[] = { - "Control Panel", - "Desktop", - NULL -}; +static const TCHAR *g_isSecureNT = "ScreenSaverIsSecure"; +static const TCHAR *g_isSecure9x = "ScreenSaveUsePassword"; +static const TCHAR *const g_pathScreenSaverIsSecure[] = {"Control Panel", + "Desktop", NULL}; // // MSWindowsScreenSaver // -MSWindowsScreenSaver::MSWindowsScreenSaver() : - m_wasSecure(false), - m_wasSecureAnInt(false), - m_process(NULL), - m_watch(NULL), - m_threadID(0), - m_msg(0), - m_wParam(0), - m_lParam(0), - m_active(false) -{ - // check if screen saver is enabled - SystemParametersInfo(SPI_GETSCREENSAVEACTIVE, 0, &m_wasEnabled, 0); +MSWindowsScreenSaver::MSWindowsScreenSaver() + : m_wasSecure(false), m_wasSecureAnInt(false), m_process(NULL), + m_watch(NULL), m_threadID(0), m_msg(0), m_wParam(0), m_lParam(0), + m_active(false) { + // check if screen saver is enabled + SystemParametersInfo(SPI_GETSCREENSAVEACTIVE, 0, &m_wasEnabled, 0); } -MSWindowsScreenSaver::~MSWindowsScreenSaver() -{ - unwatchProcess(); +MSWindowsScreenSaver::~MSWindowsScreenSaver() { unwatchProcess(); } + +bool MSWindowsScreenSaver::checkStarted(UINT msg, WPARAM wParam, + LPARAM lParam) { + // if already started then say it didn't just start + if (m_active) { + return false; + } + + // screen saver may have started. look for it and get + // the process. if we can't find it then assume it + // didn't really start. we wait a moment before + // looking to give the screen saver a chance to start. + // this shouldn't be a problem since we only get here + // if the screen saver wants to kick in, meaning that + // the system is idle or the user deliberately started + // the screen saver. + Sleep(250); + + // set parameters common to all screen saver handling + m_threadID = GetCurrentThreadId(); + m_msg = msg; + m_wParam = wParam; + m_lParam = lParam; + + // on the windows nt family we wait for the desktop to + // change until it's neither the Screen-Saver desktop + // nor a desktop we can't open (the login desktop). + // since windows will send the request-to-start-screen- + // saver message even when the screen saver is disabled + // we first check that the screen saver is indeed active + // before watching for it to stop. + if (!isActive()) { + LOG((CLOG_DEBUG2 "can't open screen saver desktop")); + return false; + } + + watchDesktop(); + return true; } -bool -MSWindowsScreenSaver::checkStarted(UINT msg, WPARAM wParam, LPARAM lParam) -{ - // if already started then say it didn't just start - if (m_active) { - return false; - } +void MSWindowsScreenSaver::enable() { + SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, m_wasEnabled, 0, 0); - // screen saver may have started. look for it and get - // the process. if we can't find it then assume it - // didn't really start. we wait a moment before - // looking to give the screen saver a chance to start. - // this shouldn't be a problem since we only get here - // if the screen saver wants to kick in, meaning that - // the system is idle or the user deliberately started - // the screen saver. - Sleep(250); - - // set parameters common to all screen saver handling - m_threadID = GetCurrentThreadId(); - m_msg = msg; - m_wParam = wParam; - m_lParam = lParam; - - // on the windows nt family we wait for the desktop to - // change until it's neither the Screen-Saver desktop - // nor a desktop we can't open (the login desktop). - // since windows will send the request-to-start-screen- - // saver message even when the screen saver is disabled - // we first check that the screen saver is indeed active - // before watching for it to stop. - if (!isActive()) { - LOG((CLOG_DEBUG2 "can't open screen saver desktop")); - return false; - } - - watchDesktop(); - return true; + // restore password protection + if (m_wasSecure) { + setSecure(true, m_wasSecureAnInt); + } } -void -MSWindowsScreenSaver::enable() -{ - SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, m_wasEnabled, 0, 0); +void MSWindowsScreenSaver::disable() { + SystemParametersInfo(SPI_GETSCREENSAVEACTIVE, 0, &m_wasEnabled, 0); + SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, FALSE, 0, 0); - // restore password protection - if (m_wasSecure) { - setSecure(true, m_wasSecureAnInt); - } + // disable password protected screensaver + m_wasSecure = isSecure(&m_wasSecureAnInt); + if (m_wasSecure) { + setSecure(false, m_wasSecureAnInt); + } } -void -MSWindowsScreenSaver::disable() -{ - SystemParametersInfo(SPI_GETSCREENSAVEACTIVE, 0, &m_wasEnabled, 0); - SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, FALSE, 0, 0); - - // disable password protected screensaver - m_wasSecure = isSecure(&m_wasSecureAnInt); - if (m_wasSecure) { - setSecure(false, m_wasSecureAnInt); +void MSWindowsScreenSaver::activate() { + // don't activate if already active + if (!isActive()) { + // activate + HWND hwnd = GetForegroundWindow(); + if (hwnd != NULL) { + PostMessage(hwnd, WM_SYSCOMMAND, SC_SCREENSAVE, 0); + } else { + // no foreground window. pretend we got the event instead. + DefWindowProc(NULL, WM_SYSCOMMAND, SC_SCREENSAVE, 0); } + } } -void -MSWindowsScreenSaver::activate() -{ - // don't activate if already active - if (!isActive()) { - // activate - HWND hwnd = GetForegroundWindow(); - if (hwnd != NULL) { - PostMessage(hwnd, WM_SYSCOMMAND, SC_SCREENSAVE, 0); - } - else { - // no foreground window. pretend we got the event instead. - DefWindowProc(NULL, WM_SYSCOMMAND, SC_SCREENSAVE, 0); - } +void MSWindowsScreenSaver::deactivate() { + bool killed = false; + + // NT runs screen saver in another desktop + HDESK desktop = OpenDesktop("Screen-saver", 0, FALSE, + DESKTOP_READOBJECTS | DESKTOP_WRITEOBJECTS); + if (desktop != NULL) { + EnumDesktopWindows(desktop, &MSWindowsScreenSaver::killScreenSaverFunc, + reinterpret_cast(&killed)); + CloseDesktop(desktop); + } + + // if above failed or wasn't tried, try the windows 95 way + if (!killed) { + // find screen saver window and close it + HWND hwnd = FindWindow("WindowsScreenSaverClass", NULL); + if (hwnd == NULL) { + // win2k may use a different class + hwnd = FindWindow("Default Screen Saver", NULL); } + if (hwnd != NULL) { + PostMessage(hwnd, WM_CLOSE, 0, 0); + } + } + + // force timer to restart + SystemParametersInfo(SPI_GETSCREENSAVEACTIVE, 0, &m_wasEnabled, 0); + SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, !m_wasEnabled, 0, + SPIF_SENDWININICHANGE); + SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, m_wasEnabled, 0, + SPIF_SENDWININICHANGE); } -void -MSWindowsScreenSaver::deactivate() -{ - bool killed = false; - - // NT runs screen saver in another desktop - HDESK desktop = OpenDesktop("Screen-saver", 0, FALSE, - DESKTOP_READOBJECTS | DESKTOP_WRITEOBJECTS); - if (desktop != NULL) { - EnumDesktopWindows(desktop, - &MSWindowsScreenSaver::killScreenSaverFunc, - reinterpret_cast(&killed)); - CloseDesktop(desktop); - } - - // if above failed or wasn't tried, try the windows 95 way - if (!killed) { - // find screen saver window and close it - HWND hwnd = FindWindow("WindowsScreenSaverClass", NULL); - if (hwnd == NULL) { - // win2k may use a different class - hwnd = FindWindow("Default Screen Saver", NULL); - } - if (hwnd != NULL) { - PostMessage(hwnd, WM_CLOSE, 0, 0); - } - } - - // force timer to restart - SystemParametersInfo(SPI_GETSCREENSAVEACTIVE, 0, &m_wasEnabled, 0); - SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, - !m_wasEnabled, 0, SPIF_SENDWININICHANGE); - SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, - m_wasEnabled, 0, SPIF_SENDWININICHANGE); +bool MSWindowsScreenSaver::isActive() const { + BOOL running; + SystemParametersInfo(SPI_GETSCREENSAVERRUNNING, 0, &running, 0); + return (running != FALSE); } -bool -MSWindowsScreenSaver::isActive() const -{ +BOOL CALLBACK MSWindowsScreenSaver::killScreenSaverFunc(HWND hwnd, LPARAM arg) { + if (IsWindowVisible(hwnd)) { + HINSTANCE instance = (HINSTANCE)GetWindowLongPtr(hwnd, GWLP_HINSTANCE); + if (instance != MSWindowsScreen::getWindowInstance()) { + PostMessage(hwnd, WM_CLOSE, 0, 0); + *reinterpret_cast(arg) = true; + } + } + return TRUE; +} + +void MSWindowsScreenSaver::watchDesktop() { + // stop watching previous process/desktop + unwatchProcess(); + + // watch desktop in another thread + LOG((CLOG_DEBUG "watching screen saver desktop")); + m_active = true; + m_watch = new Thread(new TMethodJob( + this, &MSWindowsScreenSaver::watchDesktopThread)); +} + +void MSWindowsScreenSaver::watchProcess(HANDLE process) { + // stop watching previous process/desktop + unwatchProcess(); + + // watch new process in another thread + if (process != NULL) { + LOG((CLOG_DEBUG "watching screen saver process")); + m_process = process; + m_active = true; + m_watch = new Thread(new TMethodJob( + this, &MSWindowsScreenSaver::watchProcessThread)); + } +} + +void MSWindowsScreenSaver::unwatchProcess() { + if (m_watch != NULL) { + LOG((CLOG_DEBUG "stopped watching screen saver process/desktop")); + m_watch->cancel(); + m_watch->wait(); + delete m_watch; + m_watch = NULL; + m_active = false; + } + if (m_process != NULL) { + CloseHandle(m_process); + m_process = NULL; + } +} + +void MSWindowsScreenSaver::watchDesktopThread(void *) { + DWORD reserved = 0; + TCHAR *name = NULL; + + for (;;) { + // wait a bit + ARCH->sleep(0.2); + BOOL running; SystemParametersInfo(SPI_GETSCREENSAVERRUNNING, 0, &running, 0); - return (running != FALSE); + if (running) { + continue; + } + + // send screen saver deactivation message + m_active = false; + PostThreadMessage(m_threadID, m_msg, m_wParam, m_lParam); + return; + } } -BOOL CALLBACK -MSWindowsScreenSaver::killScreenSaverFunc(HWND hwnd, LPARAM arg) -{ - if (IsWindowVisible(hwnd)) { - HINSTANCE instance = (HINSTANCE)GetWindowLongPtr(hwnd, GWLP_HINSTANCE); - if (instance != MSWindowsScreen::getWindowInstance()) { - PostMessage(hwnd, WM_CLOSE, 0, 0); - *reinterpret_cast(arg) = true; - } +void MSWindowsScreenSaver::watchProcessThread(void *) { + for (;;) { + Thread::testCancel(); + if (WaitForSingleObject(m_process, 50) == WAIT_OBJECT_0) { + // process terminated + LOG((CLOG_DEBUG "screen saver died")); + + // send screen saver deactivation message + m_active = false; + PostThreadMessage(m_threadID, m_msg, m_wParam, m_lParam); + return; } - return TRUE; + } } -void -MSWindowsScreenSaver::watchDesktop() -{ - // stop watching previous process/desktop - unwatchProcess(); +void MSWindowsScreenSaver::setSecure(bool secure, bool saveSecureAsInt) { + HKEY hkey = + ArchMiscWindows::addKey(HKEY_CURRENT_USER, g_pathScreenSaverIsSecure); + if (hkey == NULL) { + return; + } - // watch desktop in another thread - LOG((CLOG_DEBUG "watching screen saver desktop")); - m_active = true; - m_watch = new Thread(new TMethodJob(this, - &MSWindowsScreenSaver::watchDesktopThread)); + if (saveSecureAsInt) { + ArchMiscWindows::setValue(hkey, g_isSecureNT, secure ? 1 : 0); + } else { + ArchMiscWindows::setValue(hkey, g_isSecureNT, secure ? "1" : "0"); + } + + ArchMiscWindows::closeKey(hkey); } -void -MSWindowsScreenSaver::watchProcess(HANDLE process) -{ - // stop watching previous process/desktop - unwatchProcess(); +bool MSWindowsScreenSaver::isSecure(bool *wasSecureFlagAnInt) const { + // get the password protection setting key + HKEY hkey = + ArchMiscWindows::openKey(HKEY_CURRENT_USER, g_pathScreenSaverIsSecure); + if (hkey == NULL) { + return false; + } - // watch new process in another thread - if (process != NULL) { - LOG((CLOG_DEBUG "watching screen saver process")); - m_process = process; - m_active = true; - m_watch = new Thread(new TMethodJob(this, - &MSWindowsScreenSaver::watchProcessThread)); - } -} - -void -MSWindowsScreenSaver::unwatchProcess() -{ - if (m_watch != NULL) { - LOG((CLOG_DEBUG "stopped watching screen saver process/desktop")); - m_watch->cancel(); - m_watch->wait(); - delete m_watch; - m_watch = NULL; - m_active = false; - } - if (m_process != NULL) { - CloseHandle(m_process); - m_process = NULL; - } -} - -void -MSWindowsScreenSaver::watchDesktopThread(void*) -{ - DWORD reserved = 0; - TCHAR* name = NULL; - - for (;;) { - // wait a bit - ARCH->sleep(0.2); - - BOOL running; - SystemParametersInfo(SPI_GETSCREENSAVERRUNNING, 0, &running, 0); - if (running) { - continue; - } - - // send screen saver deactivation message - m_active = false; - PostThreadMessage(m_threadID, m_msg, m_wParam, m_lParam); - return; - } -} - -void -MSWindowsScreenSaver::watchProcessThread(void*) -{ - for (;;) { - Thread::testCancel(); - if (WaitForSingleObject(m_process, 50) == WAIT_OBJECT_0) { - // process terminated - LOG((CLOG_DEBUG "screen saver died")); - - // send screen saver deactivation message - m_active = false; - PostThreadMessage(m_threadID, m_msg, m_wParam, m_lParam); - return; - } - } -} - -void -MSWindowsScreenSaver::setSecure(bool secure, bool saveSecureAsInt) -{ - HKEY hkey = - ArchMiscWindows::addKey(HKEY_CURRENT_USER, g_pathScreenSaverIsSecure); - if (hkey == NULL) { - return; - } - - if (saveSecureAsInt) { - ArchMiscWindows::setValue(hkey, g_isSecureNT, secure ? 1 : 0); - } - else { - ArchMiscWindows::setValue(hkey, g_isSecureNT, secure ? "1" : "0"); - } - - ArchMiscWindows::closeKey(hkey); -} - -bool -MSWindowsScreenSaver::isSecure(bool* wasSecureFlagAnInt) const -{ - // get the password protection setting key - HKEY hkey = - ArchMiscWindows::openKey(HKEY_CURRENT_USER, g_pathScreenSaverIsSecure); - if (hkey == NULL) { - return false; - } - - // get the value. the value may be an int or a string, depending - // on the version of windows. - bool result; - switch (ArchMiscWindows::typeOfValue(hkey, g_isSecureNT)) { - default: - result = false; - break; - - case ArchMiscWindows::kUINT: { - DWORD value = - ArchMiscWindows::readValueInt(hkey, g_isSecureNT); - *wasSecureFlagAnInt = true; - result = (value != 0); - break; - } - - case ArchMiscWindows::kSTRING: { - std::string value = - ArchMiscWindows::readValueString(hkey, g_isSecureNT); - *wasSecureFlagAnInt = false; - result = (value != "0"); - break; - } - } - - ArchMiscWindows::closeKey(hkey); - return result; + // get the value. the value may be an int or a string, depending + // on the version of windows. + bool result; + switch (ArchMiscWindows::typeOfValue(hkey, g_isSecureNT)) { + default: + result = false; + break; + + case ArchMiscWindows::kUINT: { + DWORD value = ArchMiscWindows::readValueInt(hkey, g_isSecureNT); + *wasSecureFlagAnInt = true; + result = (value != 0); + break; + } + + case ArchMiscWindows::kSTRING: { + std::string value = ArchMiscWindows::readValueString(hkey, g_isSecureNT); + *wasSecureFlagAnInt = false; + result = (value != "0"); + break; + } + } + + ArchMiscWindows::closeKey(hkey); + return result; } diff --git a/src/lib/platform/MSWindowsScreenSaver.h b/src/lib/platform/MSWindowsScreenSaver.h index c74412837..825c4b184 100644 --- a/src/lib/platform/MSWindowsScreenSaver.h +++ b/src/lib/platform/MSWindowsScreenSaver.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -18,8 +18,8 @@ #pragma once -#include "synergy/IScreenSaver.h" #include "base/String.h" +#include "synergy/IScreenSaver.h" #define WIN32_LEAN_AND_MEAN #include @@ -29,61 +29,61 @@ class Thread; //! Microsoft windows screen saver implementation class MSWindowsScreenSaver : public IScreenSaver { public: - MSWindowsScreenSaver(); - virtual ~MSWindowsScreenSaver(); + MSWindowsScreenSaver(); + virtual ~MSWindowsScreenSaver(); - //! @name manipulators - //@{ + //! @name manipulators + //@{ - //! Check if screen saver started - /*! - Check if the screen saver really started. Returns false if it - hasn't, true otherwise. When the screen saver stops, \c msg will - be posted to the current thread's message queue with the given - parameters. - */ - bool checkStarted(UINT msg, WPARAM, LPARAM); + //! Check if screen saver started + /*! + Check if the screen saver really started. Returns false if it + hasn't, true otherwise. When the screen saver stops, \c msg will + be posted to the current thread's message queue with the given + parameters. + */ + bool checkStarted(UINT msg, WPARAM, LPARAM); - //@} + //@} - // IScreenSaver overrides - virtual void enable(); - virtual void disable(); - virtual void activate(); - virtual void deactivate(); - virtual bool isActive() const; + // IScreenSaver overrides + virtual void enable(); + virtual void disable(); + virtual void activate(); + virtual void deactivate(); + virtual bool isActive() const; private: - class FindScreenSaverInfo { - public: - HDESK m_desktop; - HWND m_window; - }; + class FindScreenSaverInfo { + public: + HDESK m_desktop; + HWND m_window; + }; - static BOOL CALLBACK killScreenSaverFunc(HWND hwnd, LPARAM lParam); + static BOOL CALLBACK killScreenSaverFunc(HWND hwnd, LPARAM lParam); - void watchDesktop(); - void watchProcess(HANDLE process); - void unwatchProcess(); - void watchDesktopThread(void*); - void watchProcessThread(void*); + void watchDesktop(); + void watchProcess(HANDLE process); + void unwatchProcess(); + void watchDesktopThread(void *); + void watchProcessThread(void *); - void setSecure(bool secure, bool saveSecureAsInt); - bool isSecure(bool* wasSecureAnInt) const; + void setSecure(bool secure, bool saveSecureAsInt); + bool isSecure(bool *wasSecureAnInt) const; private: - BOOL m_wasEnabled; - bool m_wasSecure; - bool m_wasSecureAnInt; + BOOL m_wasEnabled; + bool m_wasSecure; + bool m_wasSecureAnInt; - HANDLE m_process; - Thread* m_watch; - DWORD m_threadID; - UINT m_msg; - WPARAM m_wParam; - LPARAM m_lParam; + HANDLE m_process; + Thread *m_watch; + DWORD m_threadID; + UINT m_msg; + WPARAM m_wParam; + LPARAM m_lParam; - // checkActive state. true if the screen saver is being watched - // for deactivation (and is therefore active). - bool m_active; + // checkActive state. true if the screen saver is being watched + // for deactivation (and is therefore active). + bool m_active; }; diff --git a/src/lib/platform/MSWindowsSession.cpp b/src/lib/platform/MSWindowsSession.cpp index 6370d8c73..0a5af2664 100644 --- a/src/lib/platform/MSWindowsSession.cpp +++ b/src/lib/platform/MSWindowsSession.cpp @@ -1,11 +1,11 @@ /* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2013-2016 Symless Ltd. - * + * * 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 LICENSE 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 @@ -18,186 +18,167 @@ #include "platform/MSWindowsSession.h" #include "arch/win32/XArchWindows.h" -#include "synergy/XSynergy.h" #include "base/Log.h" +#include "synergy/XSynergy.h" #include -MSWindowsSession::MSWindowsSession() : - m_activeSessionId(-1) -{ -} +MSWindowsSession::MSWindowsSession() : m_activeSessionId(-1) {} -MSWindowsSession::~MSWindowsSession() -{ -} +MSWindowsSession::~MSWindowsSession() {} -bool -MSWindowsSession::isProcessInSession(const char* name, PHANDLE process = NULL) -{ - // first we need to take a snapshot of the running processes - HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); - if (snapshot == INVALID_HANDLE_VALUE) { - LOG((CLOG_ERR "could not get process snapshot")); - throw XArch(new XArchEvalWindows()); - } +bool MSWindowsSession::isProcessInSession(const char *name, + PHANDLE process = NULL) { + // first we need to take a snapshot of the running processes + HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); + if (snapshot == INVALID_HANDLE_VALUE) { + LOG((CLOG_ERR "could not get process snapshot")); + throw XArch(new XArchEvalWindows()); + } - PROCESSENTRY32 entry; - entry.dwSize = sizeof(PROCESSENTRY32); + PROCESSENTRY32 entry; + entry.dwSize = sizeof(PROCESSENTRY32); - // get the first process, and if we can't do that then it's - // unlikely we can go any further - BOOL gotEntry = Process32First(snapshot, &entry); - if (!gotEntry) { - LOG((CLOG_ERR "could not get first process entry")); - throw XArch(new XArchEvalWindows()); - } + // get the first process, and if we can't do that then it's + // unlikely we can go any further + BOOL gotEntry = Process32First(snapshot, &entry); + if (!gotEntry) { + LOG((CLOG_ERR "could not get first process entry")); + throw XArch(new XArchEvalWindows()); + } - // used to record process names for debug info - std::list nameList; + // used to record process names for debug info + std::list nameList; - // now just iterate until we can find winlogon.exe pid - DWORD pid = 0; - while(gotEntry) { + // now just iterate until we can find winlogon.exe pid + DWORD pid = 0; + while (gotEntry) { - // make sure we're not checking the system process - if (entry.th32ProcessID != 0) { + // make sure we're not checking the system process + if (entry.th32ProcessID != 0) { - DWORD processSessionId; - BOOL pidToSidRet = ProcessIdToSessionId( - entry.th32ProcessID, &processSessionId); + DWORD processSessionId; + BOOL pidToSidRet = + ProcessIdToSessionId(entry.th32ProcessID, &processSessionId); - if (!pidToSidRet) { - // if we can not acquire session associated with a specified process, - // simply ignore it - LOG((CLOG_DEBUG2 "could not get session id for process: %i %s, code=%i", - entry.th32ProcessID, entry.szExeFile, GetLastError())); - gotEntry = nextProcessEntry(snapshot, &entry); - continue; - } - else { - // only pay attention to processes in the active session - if (processSessionId == m_activeSessionId) { - - // store the names so we can record them for debug - nameList.push_back(entry.szExeFile); - - if (_stricmp(entry.szExeFile, name) == 0) { - pid = entry.th32ProcessID; - } - } - } - - } - - // now move on to the next entry (if we're not at the end) + if (!pidToSidRet) { + // if we can not acquire session associated with a specified process, + // simply ignore it + LOG((CLOG_DEBUG2 "could not get session id for process: %i %s, code=%i", + entry.th32ProcessID, entry.szExeFile, GetLastError())); gotEntry = nextProcessEntry(snapshot, &entry); - } + continue; + } else { + // only pay attention to processes in the active session + if (processSessionId == m_activeSessionId) { - std::string nameListJoin; - for(std::list::iterator it = nameList.begin(); - it != nameList.end(); it++) { - nameListJoin.append(*it); - nameListJoin.append(", "); - } + // store the names so we can record them for debug + nameList.push_back(entry.szExeFile); - LOG((CLOG_DEBUG2 "processes in session %d: %s", - m_activeSessionId, nameListJoin.c_str())); - - CloseHandle(snapshot); - - if (pid) { - if (process != NULL) { - // now get the process, which we'll use to get the process token. - LOG((CLOG_DEBUG "found %s in session %i", name, m_activeSessionId)); - *process = OpenProcess(MAXIMUM_ALLOWED, FALSE, pid); + if (_stricmp(entry.szExeFile, name) == 0) { + pid = entry.th32ProcessID; + } } - return true; + } } - else { - LOG((CLOG_DEBUG "did not find %s in session %i", name, m_activeSessionId)); - return false; + + // now move on to the next entry (if we're not at the end) + gotEntry = nextProcessEntry(snapshot, &entry); + } + + std::string nameListJoin; + for (std::list::iterator it = nameList.begin(); + it != nameList.end(); it++) { + nameListJoin.append(*it); + nameListJoin.append(", "); + } + + LOG((CLOG_DEBUG2 "processes in session %d: %s", m_activeSessionId, + nameListJoin.c_str())); + + CloseHandle(snapshot); + + if (pid) { + if (process != NULL) { + // now get the process, which we'll use to get the process token. + LOG((CLOG_DEBUG "found %s in session %i", name, m_activeSessionId)); + *process = OpenProcess(MAXIMUM_ALLOWED, FALSE, pid); } + return true; + } else { + LOG((CLOG_DEBUG "did not find %s in session %i", name, m_activeSessionId)); + return false; + } } -HANDLE -MSWindowsSession::getUserToken(LPSECURITY_ATTRIBUTES security) -{ - HANDLE sourceToken; - if (!WTSQueryUserToken(m_activeSessionId, &sourceToken)) { - LOG((CLOG_ERR "could not get token from session %d", m_activeSessionId)); - throw XArch(new XArchEvalWindows); - } - - HANDLE newToken; - if (!DuplicateTokenEx( - sourceToken, TOKEN_ASSIGN_PRIMARY | TOKEN_ALL_ACCESS, security, - SecurityImpersonation, TokenPrimary, &newToken)) { +HANDLE +MSWindowsSession::getUserToken(LPSECURITY_ATTRIBUTES security) { + HANDLE sourceToken; + if (!WTSQueryUserToken(m_activeSessionId, &sourceToken)) { + LOG((CLOG_ERR "could not get token from session %d", m_activeSessionId)); + throw XArch(new XArchEvalWindows); + } - LOG((CLOG_ERR "could not duplicate token")); - throw XArch(new XArchEvalWindows); - } - - LOG((CLOG_DEBUG "duplicated, new token: %i", newToken)); - return newToken; + HANDLE newToken; + if (!DuplicateTokenEx(sourceToken, TOKEN_ASSIGN_PRIMARY | TOKEN_ALL_ACCESS, + security, SecurityImpersonation, TokenPrimary, + &newToken)) { + + LOG((CLOG_ERR "could not duplicate token")); + throw XArch(new XArchEvalWindows); + } + + LOG((CLOG_DEBUG "duplicated, new token: %i", newToken)); + return newToken; } -BOOL -MSWindowsSession::hasChanged() -{ - return (m_activeSessionId != WTSGetActiveConsoleSessionId()); +BOOL MSWindowsSession::hasChanged() { + return (m_activeSessionId != WTSGetActiveConsoleSessionId()); } -void -MSWindowsSession::updateActiveSession() -{ - m_activeSessionId = WTSGetActiveConsoleSessionId(); +void MSWindowsSession::updateActiveSession() { + m_activeSessionId = WTSGetActiveConsoleSessionId(); } +BOOL MSWindowsSession::nextProcessEntry(HANDLE snapshot, + LPPROCESSENTRY32 entry) { + // TODO: issue S3-2021 + // resetting the error state here is acceptable, but having to do so indicates + // that a different win32 function call has failed beforehand. we should + // always check for errors after each win32 function call. + SetLastError(0); -BOOL -MSWindowsSession::nextProcessEntry(HANDLE snapshot, LPPROCESSENTRY32 entry) -{ - // TODO: issue S3-2021 - // resetting the error state here is acceptable, but having to do so indicates that a - // different win32 function call has failed beforehand. we should always check for errors - // after each win32 function call. - SetLastError(0); + BOOL gotEntry = Process32Next(snapshot, entry); + if (!gotEntry) { - BOOL gotEntry = Process32Next(snapshot, entry); - if (!gotEntry) { + DWORD err = GetLastError(); - DWORD err = GetLastError(); - - // only throw if it's not the end of the snapshot, if not the 'no more files' error - // then it's probably something serious. - if (err != ERROR_NO_MORE_FILES) { - LOG((CLOG_ERR "could not get next process entry")); - throw XArch(new XArchEvalWindows()); - } + // only throw if it's not the end of the snapshot, if not the 'no more + // files' error then it's probably something serious. + if (err != ERROR_NO_MORE_FILES) { + LOG((CLOG_ERR "could not get next process entry")); + throw XArch(new XArchEvalWindows()); } + } - return gotEntry; + return gotEntry; } -String -MSWindowsSession::getActiveDesktopName() -{ - String result; - try { - HDESK hd = OpenInputDesktop(0, TRUE, GENERIC_READ); - if (hd != NULL) { - DWORD size; - GetUserObjectInformation(hd, UOI_NAME, NULL, 0, &size); - TCHAR* name = (TCHAR*)alloca(size + sizeof(TCHAR)); - GetUserObjectInformation(hd, UOI_NAME, name, size, &size); - result = name; - CloseDesktop(hd); - } - } - catch (std::exception& error) { - LOG((CLOG_ERR "failed to get active desktop name: %s", error.what())); +String MSWindowsSession::getActiveDesktopName() { + String result; + try { + HDESK hd = OpenInputDesktop(0, TRUE, GENERIC_READ); + if (hd != NULL) { + DWORD size; + GetUserObjectInformation(hd, UOI_NAME, NULL, 0, &size); + TCHAR *name = (TCHAR *)alloca(size + sizeof(TCHAR)); + GetUserObjectInformation(hd, UOI_NAME, name, size, &size); + result = name; + CloseDesktop(hd); } + } catch (std::exception &error) { + LOG((CLOG_ERR "failed to get active desktop name: %s", error.what())); + } - return result; + return result; } diff --git a/src/lib/platform/MSWindowsSession.h b/src/lib/platform/MSWindowsSession.h index 8c48117d4..03a86d343 100644 --- a/src/lib/platform/MSWindowsSession.h +++ b/src/lib/platform/MSWindowsSession.h @@ -1,11 +1,11 @@ /* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2013-2016 Symless Ltd. - * + * * 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 LICENSE 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 @@ -21,32 +21,34 @@ #define WIN32_LEAN_AND_MEAN #include + #include class MSWindowsSession { public: - MSWindowsSession(); - ~MSWindowsSession(); + MSWindowsSession(); + ~MSWindowsSession(); - //! - /*! - Returns true if the session ID has changed since updateActiveSession was called. - */ - BOOL hasChanged(); - - bool isProcessInSession(const char* name, PHANDLE process); + //! + /*! + Returns true if the session ID has changed since updateActiveSession was + called. + */ + BOOL hasChanged(); - HANDLE getUserToken(LPSECURITY_ATTRIBUTES security); + bool isProcessInSession(const char *name, PHANDLE process); - DWORD getActiveSessionId() { return m_activeSessionId; } + HANDLE getUserToken(LPSECURITY_ATTRIBUTES security); - void updateActiveSession(); + DWORD getActiveSessionId() { return m_activeSessionId; } - String getActiveDesktopName(); + void updateActiveSession(); + + String getActiveDesktopName(); private: - BOOL nextProcessEntry(HANDLE snapshot, LPPROCESSENTRY32 entry); + BOOL nextProcessEntry(HANDLE snapshot, LPPROCESSENTRY32 entry); private: - DWORD m_activeSessionId; + DWORD m_activeSessionId; }; diff --git a/src/lib/platform/MSWindowsUtil.cpp b/src/lib/platform/MSWindowsUtil.cpp index 7ce6e2dcd..3a6bdf102 100644 --- a/src/lib/platform/MSWindowsUtil.cpp +++ b/src/lib/platform/MSWindowsUtil.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 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 LICENSE 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 @@ -26,39 +26,31 @@ // MSWindowsUtil // -String -MSWindowsUtil::getString(HINSTANCE instance, DWORD id) -{ - char* msg = NULL; - int n = LoadString(instance, id, reinterpret_cast(&msg), 0); +String MSWindowsUtil::getString(HINSTANCE instance, DWORD id) { + char *msg = NULL; + int n = LoadString(instance, id, reinterpret_cast(&msg), 0); - if (n <= 0) { - return String(); - } + if (n <= 0) { + return String(); + } - return String (msg, n); + return String(msg, n); } -String -MSWindowsUtil::getErrorString(HINSTANCE hinstance, DWORD error, DWORD id) -{ - char* buffer; - if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_IGNORE_INSERTS | - FORMAT_MESSAGE_FROM_SYSTEM, - 0, - error, - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - (LPTSTR)&buffer, - 0, - NULL) == 0) { - String errorString = synergy::string::sprintf("%d", error); - return synergy::string::format(getString(hinstance, id).c_str(), - errorString.c_str()); - } - else { - String result(buffer); - LocalFree(buffer); - return result; - } +String MSWindowsUtil::getErrorString(HINSTANCE hinstance, DWORD error, + DWORD id) { + char *buffer; + if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_IGNORE_INSERTS | + FORMAT_MESSAGE_FROM_SYSTEM, + 0, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR)&buffer, 0, NULL) == 0) { + String errorString = synergy::string::sprintf("%d", error); + return synergy::string::format(getString(hinstance, id).c_str(), + errorString.c_str()); + } else { + String result(buffer); + LocalFree(buffer); + return result; + } } diff --git a/src/lib/platform/MSWindowsUtil.h b/src/lib/platform/MSWindowsUtil.h index 275288b41..986913fe9 100644 --- a/src/lib/platform/MSWindowsUtil.h +++ b/src/lib/platform/MSWindowsUtil.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 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 LICENSE 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 @@ -25,16 +25,16 @@ class MSWindowsUtil { public: - //! Get message string - /*! - Gets a string for \p id from the string table of \p instance. - */ - static String getString(HINSTANCE instance, DWORD id); + //! Get message string + /*! + Gets a string for \p id from the string table of \p instance. + */ + static String getString(HINSTANCE instance, DWORD id); - //! Get error string - /*! - Gets a system error message for \p error. If the error cannot be - found return the string for \p id, replacing ${1} with \p error. - */ - static String getErrorString(HINSTANCE, DWORD error, DWORD id); + //! Get error string + /*! + Gets a system error message for \p error. If the error cannot be + found return the string for \p id, replacing ${1} with \p error. + */ + static String getErrorString(HINSTANCE, DWORD error, DWORD id); }; diff --git a/src/lib/platform/MSWindowsWatchdog.cpp b/src/lib/platform/MSWindowsWatchdog.cpp index b4a0e10ce..7d1a90d53 100644 --- a/src/lib/platform/MSWindowsWatchdog.cpp +++ b/src/lib/platform/MSWindowsWatchdog.cpp @@ -6,7 +6,7 @@ * 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 LICENSE 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 @@ -18,24 +18,25 @@ #include "platform/MSWindowsWatchdog.h" -#include "ipc/IpcLogOutputter.h" -#include "ipc/IpcServer.h" -#include "ipc/IpcMessage.h" +#include "arch/Arch.h" +#include "arch/win32/XArchWindows.h" +#include "base/Log.h" +#include "base/TMethodJob.h" +#include "base/log_outputters.h" #include "ipc/Ipc.h" +#include "ipc/IpcLogOutputter.h" +#include "ipc/IpcMessage.h" +#include "ipc/IpcServer.h" +#include "mt/Thread.h" #include "synergy/App.h" #include "synergy/ArgsBase.h" -#include "mt/Thread.h" -#include "arch/win32/ArchDaemonWindows.h" -#include "arch/win32/XArchWindows.h" -#include "arch/Arch.h" -#include "base/log_outputters.h" -#include "base/TMethodJob.h" -#include "base/Log.h" -#include "common/Version.h" -#include -#include #include +#include +#include + +#define WIN32_LEAN_AND_MEAN +#include #define CURRENT_PROCESS_ID 0 #define MAXIMUM_WAIT_TIME 3 @@ -44,681 +45,622 @@ static char g_desktopName[] = "winsta0\\Default"; namespace { -std::string -trimDesktopName(const std::string& nameFromTraces) -{ - std::string name; +std::string trimDesktopName(const std::string &nameFromTraces) { + std::string name; - for (const auto& symbol : nameFromTraces) { - if (std::isalpha(symbol)) { - name.push_back(symbol); - } - else { - break; - } + for (const auto &symbol : nameFromTraces) { + if (std::isalpha(symbol)) { + name.push_back(symbol); + } else { + break; } + } - return name; + return name; } -bool -isDesktopRunnable(const std::string& desktopName) -{ - const std::string winlogon = "Winlogon"; - bool isNotLoginScreen = std::strncmp(desktopName.c_str(), - winlogon.c_str(), - winlogon.length()); +bool isDesktopRunnable(const std::string &desktopName) { + const std::string winlogon = "Winlogon"; + bool isNotLoginScreen = + std::strncmp(desktopName.c_str(), winlogon.c_str(), winlogon.length()); - const auto setting = ARCH->setting("runOnLoginScreen"); - bool runOnLoginScreen = (setting.empty() || setting == "true"); + const auto setting = ARCH->setting("runOnLoginScreen"); + bool runOnLoginScreen = (setting.empty() || setting == "true"); - return (runOnLoginScreen || isNotLoginScreen); + return (runOnLoginScreen || isNotLoginScreen); } -}//namespace +} // namespace +enum { kOutputBufferSize = 4096 }; -enum { - kOutputBufferSize = 4096 -}; - -typedef VOID (WINAPI *SendSas)(BOOL asUser); +typedef VOID(WINAPI *SendSas)(BOOL asUser); const char g_activeDesktop[] = {"activeDesktop:"}; -MSWindowsWatchdog::MSWindowsWatchdog( - bool autoDetectCommand, - IpcServer& ipcServer, - IpcLogOutputter& ipcLogOutputter, - bool foreground) : - m_thread(NULL), - m_autoDetectCommand(autoDetectCommand), - m_monitoring(true), - m_commandChanged(false), - m_stdOutWrite(NULL), - m_stdOutRead(NULL), - m_ipcServer(ipcServer), - m_ipcLogOutputter(ipcLogOutputter), - m_elevateProcess(false), - m_processFailures(0), - m_processRunning(false), - m_fileLogOutputter(NULL), - m_autoElevated(false), - m_ready(false), - m_foreground(foreground) -{ - m_mutex = ARCH->newMutex(); - m_condVar = ARCH->newCondVar(); +MSWindowsWatchdog::MSWindowsWatchdog(bool autoDetectCommand, + IpcServer &ipcServer, + IpcLogOutputter &ipcLogOutputter, + bool foreground) + : m_thread(NULL), m_autoDetectCommand(autoDetectCommand), + m_monitoring(true), m_commandChanged(false), m_stdOutWrite(NULL), + m_stdOutRead(NULL), m_ipcServer(ipcServer), + m_ipcLogOutputter(ipcLogOutputter), m_elevateProcess(false), + m_processFailures(0), m_processRunning(false), m_fileLogOutputter(NULL), + m_autoElevated(false), m_ready(false), m_foreground(foreground) { + m_mutex = ARCH->newMutex(); + m_condVar = ARCH->newCondVar(); } -MSWindowsWatchdog::~MSWindowsWatchdog() -{ - if (m_condVar != NULL) { - ARCH->closeCondVar(m_condVar); - } +MSWindowsWatchdog::~MSWindowsWatchdog() { + if (m_condVar != NULL) { + ARCH->closeCondVar(m_condVar); + } - if (m_mutex != NULL) { - ARCH->closeMutex(m_mutex); - } + if (m_mutex != NULL) { + ARCH->closeMutex(m_mutex); + } } -void -MSWindowsWatchdog::startAsync() -{ - m_thread = new Thread(new TMethodJob( - this, &MSWindowsWatchdog::mainLoop, nullptr)); +void MSWindowsWatchdog::startAsync() { + m_thread = new Thread(new TMethodJob( + this, &MSWindowsWatchdog::mainLoop, nullptr)); - m_outputThread = new Thread(new TMethodJob( - this, &MSWindowsWatchdog::outputLoop, nullptr)); + m_outputThread = new Thread(new TMethodJob( + this, &MSWindowsWatchdog::outputLoop, nullptr)); } -void -MSWindowsWatchdog::stop() -{ - m_monitoring = false; - - m_thread->wait(5); - delete m_thread; +void MSWindowsWatchdog::stop() { + m_monitoring = false; - m_outputThread->wait(5); - delete m_outputThread; + m_thread->wait(5); + delete m_thread; + + m_outputThread->wait(5); + delete m_outputThread; } HANDLE -MSWindowsWatchdog::duplicateProcessToken(HANDLE process, LPSECURITY_ATTRIBUTES security) -{ - HANDLE sourceToken; +MSWindowsWatchdog::duplicateProcessToken(HANDLE process, + LPSECURITY_ATTRIBUTES security) { + HANDLE sourceToken; - BOOL tokenRet = OpenProcessToken( - process, - TOKEN_ASSIGN_PRIMARY | TOKEN_ALL_ACCESS, - &sourceToken); + BOOL tokenRet = OpenProcessToken( + process, TOKEN_ASSIGN_PRIMARY | TOKEN_ALL_ACCESS, &sourceToken); - if (!tokenRet) { - LOG((CLOG_ERR "could not open token, process handle: %d", process)); - throw XArch(new XArchEvalWindows()); - } + if (!tokenRet) { + LOG((CLOG_ERR "could not open token, process handle: %d", process)); + throw XArch(new XArchEvalWindows()); + } - LOG((CLOG_DEBUG "got token %i, duplicating", sourceToken)); + LOG((CLOG_DEBUG "got token %i, duplicating", sourceToken)); - HANDLE newToken; - BOOL duplicateRet = DuplicateTokenEx( - sourceToken, TOKEN_ASSIGN_PRIMARY | TOKEN_ALL_ACCESS, security, - SecurityImpersonation, TokenPrimary, &newToken); + HANDLE newToken; + BOOL duplicateRet = DuplicateTokenEx( + sourceToken, TOKEN_ASSIGN_PRIMARY | TOKEN_ALL_ACCESS, security, + SecurityImpersonation, TokenPrimary, &newToken); - if (!duplicateRet) { - LOG((CLOG_ERR "could not duplicate token %i", sourceToken)); - throw XArch(new XArchEvalWindows()); - } + if (!duplicateRet) { + LOG((CLOG_ERR "could not duplicate token %i", sourceToken)); + throw XArch(new XArchEvalWindows()); + } - LOG((CLOG_DEBUG "duplicated, new token: %i", newToken)); - return newToken; + LOG((CLOG_DEBUG "duplicated, new token: %i", newToken)); + return newToken; } HANDLE -MSWindowsWatchdog::getUserToken(LPSECURITY_ATTRIBUTES security) -{ - // always elevate if we are at the vista/7 login screen. we could also - // elevate for the uac dialog (consent.exe) but this would be pointless, - // since synergy would re-launch as non-elevated after the desk switch, - // and so would be unusable with the new elevated process taking focus. - if (m_elevateProcess - || m_autoElevated - || m_session.isProcessInSession("logonui.exe", NULL)) { +MSWindowsWatchdog::getUserToken(LPSECURITY_ATTRIBUTES security) { + // always elevate if we are at the vista/7 login screen. we could also + // elevate for the uac dialog (consent.exe) but this would be pointless, + // since synergy would re-launch as non-elevated after the desk switch, + // and so would be unusable with the new elevated process taking focus. + if (m_elevateProcess || m_autoElevated || + m_session.isProcessInSession("logonui.exe", NULL)) { - LOG((CLOG_DEBUG "getting elevated token, %s", - (m_elevateProcess ? "elevation required" : "at login screen"))); + LOG((CLOG_DEBUG "getting elevated token, %s", + (m_elevateProcess ? "elevation required" : "at login screen"))); - HANDLE process; - if (!m_session.isProcessInSession("winlogon.exe", &process)) { - throw XMSWindowsWatchdogError("cannot get user token without winlogon.exe"); - } - - return duplicateProcessToken(process, security); - } - else { - LOG((CLOG_DEBUG "getting non-elevated token")); - return m_session.getUserToken(security); - } -} - -void -MSWindowsWatchdog::mainLoop(void*) -{ - shutdownExistingProcesses(); - - SendSas sendSasFunc = NULL; - HINSTANCE sasLib = LoadLibrary("sas.dll"); - if (sasLib) { - LOG((CLOG_DEBUG "found sas.dll")); - sendSasFunc = (SendSas)GetProcAddress(sasLib, "SendSAS"); - } - - SECURITY_ATTRIBUTES saAttr; - saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); - saAttr.bInheritHandle = TRUE; - saAttr.lpSecurityDescriptor = NULL; - - if (!CreatePipe(&m_stdOutRead, &m_stdOutWrite, &saAttr, 0)) { - throw XArch(new XArchEvalWindows()); - } - - ZeroMemory(&m_processInfo, sizeof(PROCESS_INFORMATION)); - - while (m_monitoring) { - try { - - if (m_processRunning && getCommand().empty()) { - LOG((CLOG_INFO "process started but command is empty, shutting down")); - shutdownExistingProcesses(); - m_processRunning = false; - continue; - } - - if (m_processFailures != 0) { - // increasing backoff period, maximum of 10 seconds. - int timeout = (m_processFailures * 2) < 10 ? (m_processFailures * 2) : 10; - LOG((CLOG_INFO "backing off, wait=%ds, failures=%d", timeout, m_processFailures)); - ARCH->sleep(timeout); - } - - if (!getCommand().empty()) { - bool startNeeded = false; - - if (m_processFailures != 0) { - startNeeded = true; - } - else if (!m_foreground && m_session.hasChanged()) { - startNeeded = true; - } - else if (m_commandChanged) { - startNeeded = true; - } - - if (startNeeded) { - startProcess(); - } - } - - if (m_processRunning && !isProcessActive()) { - - m_processFailures++; - m_processRunning = false; - - LOG((CLOG_WARN "detected application not running, pid=%d", - m_processInfo.dwProcessId)); - } - - if (sendSasFunc != NULL) { - - HANDLE sendSasEvent = CreateEvent(NULL, FALSE, FALSE, "Global\\SendSAS"); - if (sendSasEvent != NULL) { - - // use SendSAS event to wait for next session (timeout 1 second). - if (WaitForSingleObject(sendSasEvent, 1000) == WAIT_OBJECT_0) { - LOG((CLOG_DEBUG "calling SendSAS")); - sendSasFunc(FALSE); - } - - CloseHandle(sendSasEvent); - continue; - } - } - - // if the sas event failed, wait by sleeping. - ARCH->sleep(1); - - } - catch (std::exception& e) { - LOG((CLOG_CRIT "failed to launch, error: %s", e.what())); - m_processFailures++; - m_processRunning = false; - continue; - } - catch (...) { - LOG((CLOG_CRIT "failed to launch, unknown error.")); - m_processFailures++; - m_processRunning = false; - continue; - } + HANDLE process; + if (!m_session.isProcessInSession("winlogon.exe", &process)) { + throw XMSWindowsWatchdogError( + "cannot get user token without winlogon.exe"); } - if (m_processRunning) { - LOG((CLOG_DEBUG "terminated running process on exit")); - shutdownProcess(m_processInfo.hProcess, m_processInfo.dwProcessId, 20); - } - - LOG((CLOG_DEBUG "watchdog main thread finished")); + return duplicateProcessToken(process, security); + } else { + LOG((CLOG_DEBUG "getting non-elevated token")); + return m_session.getUserToken(security); + } } -bool -MSWindowsWatchdog::isProcessActive() -{ - DWORD exitCode; - GetExitCodeProcess(m_processInfo.hProcess, &exitCode); - return exitCode == STILL_ACTIVE; -} +void MSWindowsWatchdog::mainLoop(void *) { + shutdownExistingProcesses(); -void -MSWindowsWatchdog::setFileLogOutputter(FileLogOutputter* outputter) -{ - m_fileLogOutputter = outputter; -} + SendSas sendSasFunc = NULL; + HINSTANCE sasLib = LoadLibrary("sas.dll"); + if (sasLib) { + LOG((CLOG_DEBUG "found sas.dll")); + sendSasFunc = (SendSas)GetProcAddress(sasLib, "SendSAS"); + } -void -MSWindowsWatchdog::startProcess() -{ - if (m_command.empty()) { - throw XMSWindowsWatchdogError("cannot start process, command is empty"); - } + SECURITY_ATTRIBUTES saAttr; + saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); + saAttr.bInheritHandle = TRUE; + saAttr.lpSecurityDescriptor = NULL; - m_commandChanged = false; + if (!CreatePipe(&m_stdOutRead, &m_stdOutWrite, &saAttr, 0)) { + throw XArch(new XArchEvalWindows()); + } - if (m_processRunning) { - LOG((CLOG_DEBUG "closing existing process to make way for new one")); - shutdownProcess(m_processInfo.hProcess, m_processInfo.dwProcessId, 20); + ZeroMemory(&m_processInfo, sizeof(PROCESS_INFORMATION)); + + while (m_monitoring) { + try { + + if (m_processRunning && getCommand().empty()) { + LOG((CLOG_INFO "process started but command is empty, shutting down")); + shutdownExistingProcesses(); m_processRunning = false; - } + continue; + } - BOOL createRet; - if (m_foreground) { - LOG((CLOG_DEBUG "starting command in foreground")); - createRet = startProcessInForeground(m_command); - } - else { - LOG((CLOG_DEBUG "starting command as session user")); - m_session.updateActiveSession(); + if (m_processFailures != 0) { + // increasing backoff period, maximum of 10 seconds. + int timeout = + (m_processFailures * 2) < 10 ? (m_processFailures * 2) : 10; + LOG((CLOG_INFO "backing off, wait=%ds, failures=%d", timeout, + m_processFailures)); + ARCH->sleep(timeout); + } - SECURITY_ATTRIBUTES sa; - ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES)); + if (!getCommand().empty()) { + bool startNeeded = false; - getActiveDesktop(&sa); - - if (!isDesktopRunnable(m_activeDesktop)) { - LOG((CLOG_INFO, "starting on the login screen is disabled")); - return; + if (m_processFailures != 0) { + startNeeded = true; + } else if (!m_foreground && m_session.hasChanged()) { + startNeeded = true; + } else if (m_commandChanged) { + startNeeded = true; } - ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES)); - HANDLE userToken = getUserToken(&sa); - m_elevateProcess = m_autoElevated ? m_autoElevated : m_elevateProcess; - m_autoElevated = false; - - // patch by Jack Zhou and Henry Tung - // set UIAccess to fix Windows 8 GUI interaction - DWORD uiAccess = 1; - SetTokenInformation(userToken, TokenUIAccess, &uiAccess, sizeof(DWORD)); - - createRet = startProcessAsUser(m_command, userToken, &sa); - } - - if (!createRet) { - LOG((CLOG_CRIT "could not launch command")); - DWORD exitCode = 0; - GetExitCodeProcess(m_processInfo.hProcess, &exitCode); - LOG((CLOG_ERR "exit code: %d", exitCode)); - throw XArch(new XArchEvalWindows); - } - else { - // wait for program to fail. - ARCH->sleep(1); - if (!isProcessActive()) { - closeProcessHandles(m_processInfo.dwProcessId); - throw XMSWindowsWatchdogError("process immediately stopped"); + if (startNeeded) { + startProcess(); } + } - m_processRunning = true; - m_processFailures = 0; + if (m_processRunning && !isProcessActive()) { - LOG((CLOG_DEBUG "started core process from daemon")); - LOG((CLOG_DEBUG2 "process info, session=%i, elevated: %s, command=%s", - m_session.getActiveSessionId(), - m_elevateProcess ? "yes" : "no", - m_command.c_str())); + m_processFailures++; + m_processRunning = false; + + LOG((CLOG_WARN "detected application not running, pid=%d", + m_processInfo.dwProcessId)); + } + + if (sendSasFunc != NULL) { + + HANDLE sendSasEvent = + CreateEvent(NULL, FALSE, FALSE, "Global\\SendSAS"); + if (sendSasEvent != NULL) { + + // use SendSAS event to wait for next session (timeout 1 second). + if (WaitForSingleObject(sendSasEvent, 1000) == WAIT_OBJECT_0) { + LOG((CLOG_DEBUG "calling SendSAS")); + sendSasFunc(FALSE); + } + + CloseHandle(sendSasEvent); + continue; + } + } + + // if the sas event failed, wait by sleeping. + ARCH->sleep(1); + + } catch (std::exception &e) { + LOG((CLOG_CRIT "failed to launch, error: %s", e.what())); + m_processFailures++; + m_processRunning = false; + continue; + } catch (...) { + LOG((CLOG_CRIT "failed to launch, unknown error.")); + m_processFailures++; + m_processRunning = false; + continue; } + } + + if (m_processRunning) { + LOG((CLOG_DEBUG "terminated running process on exit")); + shutdownProcess(m_processInfo.hProcess, m_processInfo.dwProcessId, 20); + } + + LOG((CLOG_DEBUG "watchdog main thread finished")); } -void -MSWindowsWatchdog::setStartupInfo(STARTUPINFO& si) -{ - ZeroMemory(&si, sizeof(STARTUPINFO)); - si.cb = sizeof(STARTUPINFO); - si.lpDesktop = g_desktopName; - si.hStdError = m_stdOutWrite; - si.hStdOutput = m_stdOutWrite; - si.dwFlags |= STARTF_USESTDHANDLES; +bool MSWindowsWatchdog::isProcessActive() { + DWORD exitCode; + GetExitCodeProcess(m_processInfo.hProcess, &exitCode); + return exitCode == STILL_ACTIVE; } -BOOL -MSWindowsWatchdog::startProcessInForeground(String& command) -{ - // clear, as we're reusing process info struct - ZeroMemory(&m_processInfo, sizeof(PROCESS_INFORMATION)); - - // show the console window when in foreground mode, - // so we can close it gracefully, but minimize it - // so it doesn't get in the way. - STARTUPINFO si; - setStartupInfo(si); - si.dwFlags |= STARTF_USESHOWWINDOW; - si.wShowWindow = SW_MINIMIZE; - - BOOL result = CreateProcess( - NULL, LPSTR(command.c_str()), NULL, NULL, - TRUE, 0, NULL, NULL, &si, &m_processInfo); - - m_children.insert(std::make_pair(m_processInfo.dwProcessId, m_processInfo)); - - return result; +void MSWindowsWatchdog::setFileLogOutputter(FileLogOutputter *outputter) { + m_fileLogOutputter = outputter; } -BOOL -MSWindowsWatchdog::startProcessAsUser(String& command, HANDLE userToken, LPSECURITY_ATTRIBUTES sa) -{ - // clear, as we're reusing process info struct - ZeroMemory(&m_processInfo, sizeof(PROCESS_INFORMATION)); +void MSWindowsWatchdog::startProcess() { + if (m_command.empty()) { + throw XMSWindowsWatchdogError("cannot start process, command is empty"); + } - STARTUPINFO si; - setStartupInfo(si); + m_commandChanged = false; - LPVOID environment; - BOOL blockRet = CreateEnvironmentBlock(&environment, userToken, FALSE); - if (!blockRet) { - LOG((CLOG_ERR "could not create environment block")); - throw XArch(new XArchEvalWindows); + if (m_processRunning) { + LOG((CLOG_DEBUG "closing existing process to make way for new one")); + shutdownProcess(m_processInfo.hProcess, m_processInfo.dwProcessId, 20); + m_processRunning = false; + } + + BOOL createRet; + if (m_foreground) { + LOG((CLOG_DEBUG "starting command in foreground")); + createRet = startProcessInForeground(m_command); + } else { + LOG((CLOG_DEBUG "starting command as session user")); + m_session.updateActiveSession(); + + SECURITY_ATTRIBUTES sa; + ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES)); + + getActiveDesktop(&sa); + + if (!isDesktopRunnable(m_activeDesktop)) { + LOG((CLOG_INFO, "starting on the login screen is disabled")); + return; } - DWORD creationFlags = - NORMAL_PRIORITY_CLASS | - CREATE_NO_WINDOW | - CREATE_UNICODE_ENVIRONMENT; + ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES)); + HANDLE userToken = getUserToken(&sa); + m_elevateProcess = m_autoElevated ? m_autoElevated : m_elevateProcess; + m_autoElevated = false; - // re-launch in current active user session - LOG((CLOG_INFO "starting new process")); - BOOL createRet = CreateProcessAsUser( - userToken, NULL, LPSTR(command.c_str()), - sa, NULL, TRUE, creationFlags, - environment, NULL, &si, &m_processInfo); + // patch by Jack Zhou and Henry Tung + // set UIAccess to fix Windows 8 GUI interaction + DWORD uiAccess = 1; + SetTokenInformation(userToken, TokenUIAccess, &uiAccess, sizeof(DWORD)); - m_children.insert(std::make_pair(m_processInfo.dwProcessId, m_processInfo)); + createRet = startProcessAsUser(m_command, userToken, &sa); + } - DestroyEnvironmentBlock(environment); - CloseHandle(userToken); + if (!createRet) { + LOG((CLOG_CRIT "could not launch command")); + DWORD exitCode = 0; + GetExitCodeProcess(m_processInfo.hProcess, &exitCode); + LOG((CLOG_ERR "exit code: %d", exitCode)); + throw XArch(new XArchEvalWindows); + } else { + // wait for program to fail. + ARCH->sleep(1); + if (!isProcessActive()) { + closeProcessHandles(m_processInfo.dwProcessId); + throw XMSWindowsWatchdogError("process immediately stopped"); + } - return createRet; -} - -void -MSWindowsWatchdog::setCommand(const std::string& command, bool elevate) -{ - LOG((CLOG_INFO "service command updated")); - m_command = command; - m_elevateProcess = elevate; - m_commandChanged = true; + m_processRunning = true; m_processFailures = 0; + + LOG((CLOG_DEBUG "started core process from daemon")); + LOG((CLOG_DEBUG2 "process info, session=%i, elevated: %s, command=%s", + m_session.getActiveSessionId(), m_elevateProcess ? "yes" : "no", + m_command.c_str())); + } } -std::string -MSWindowsWatchdog::getCommand() const -{ - if (!m_autoDetectCommand) { - return m_command; - } - - // seems like a fairly convoluted way to get the process name - const char* launchName = App::instance().argsBase().m_pname; - std::string args = ARCH->commandLine(); - - // build up a full command line - std::stringstream cmdTemp; - cmdTemp << launchName << args; - - std::string cmd = cmdTemp.str(); - - size_t i; - std::string find = "--relaunch"; - while ((i = cmd.find(find)) != std::string::npos) { - cmd.replace(i, find.length(), ""); - } - - return cmd; +void MSWindowsWatchdog::setStartupInfo(STARTUPINFO &si) { + ZeroMemory(&si, sizeof(STARTUPINFO)); + si.cb = sizeof(STARTUPINFO); + si.lpDesktop = g_desktopName; + si.hStdError = m_stdOutWrite; + si.hStdOutput = m_stdOutWrite; + si.dwFlags |= STARTF_USESTDHANDLES; } -void -MSWindowsWatchdog::outputLoop(void*) -{ - // +1 char for \0 - CHAR buffer[kOutputBufferSize + 1]; +BOOL MSWindowsWatchdog::startProcessInForeground(String &command) { + // clear, as we're reusing process info struct + ZeroMemory(&m_processInfo, sizeof(PROCESS_INFORMATION)); - while (m_monitoring) { - - DWORD bytesRead; - BOOL success = ReadFile(m_stdOutRead, buffer, kOutputBufferSize, &bytesRead, NULL); + // show the console window when in foreground mode, + // so we can close it gracefully, but minimize it + // so it doesn't get in the way. + STARTUPINFO si; + setStartupInfo(si); + si.dwFlags |= STARTF_USESHOWWINDOW; + si.wShowWindow = SW_MINIMIZE; - // assume the process has gone away? slow down - // the reads until another one turns up. - if (!success || bytesRead == 0) { - ARCH->sleep(1); - } - else { - buffer[bytesRead] = '\0'; + BOOL result = CreateProcess(NULL, LPSTR(command.c_str()), NULL, NULL, TRUE, 0, + NULL, NULL, &si, &m_processInfo); - testOutput(buffer); + m_children.insert(std::make_pair(m_processInfo.dwProcessId, m_processInfo)); - m_ipcLogOutputter.write(kINFO, buffer); + return result; +} - if (m_fileLogOutputter != NULL) { - m_fileLogOutputter->write(kINFO, buffer); - } +BOOL MSWindowsWatchdog::startProcessAsUser(String &command, HANDLE userToken, + LPSECURITY_ATTRIBUTES sa) { + // clear, as we're reusing process info struct + ZeroMemory(&m_processInfo, sizeof(PROCESS_INFORMATION)); + + STARTUPINFO si; + setStartupInfo(si); + + LPVOID environment; + BOOL blockRet = CreateEnvironmentBlock(&environment, userToken, FALSE); + if (!blockRet) { + LOG((CLOG_ERR "could not create environment block")); + throw XArch(new XArchEvalWindows); + } + + DWORD creationFlags = + NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW | CREATE_UNICODE_ENVIRONMENT; + + // re-launch in current active user session + LOG((CLOG_INFO "starting new process")); + BOOL createRet = CreateProcessAsUser(userToken, NULL, LPSTR(command.c_str()), + sa, NULL, TRUE, creationFlags, + environment, NULL, &si, &m_processInfo); + + m_children.insert(std::make_pair(m_processInfo.dwProcessId, m_processInfo)); + + DestroyEnvironmentBlock(environment); + CloseHandle(userToken); + + return createRet; +} + +void MSWindowsWatchdog::setCommand(const std::string &command, bool elevate) { + LOG((CLOG_INFO "service command updated")); + m_command = command; + m_elevateProcess = elevate; + m_commandChanged = true; + m_processFailures = 0; +} + +std::string MSWindowsWatchdog::getCommand() const { + if (!m_autoDetectCommand) { + return m_command; + } + + // seems like a fairly convoluted way to get the process name + const char *launchName = App::instance().argsBase().m_pname; + std::string args = ARCH->commandLine(); + + // build up a full command line + std::stringstream cmdTemp; + cmdTemp << launchName << args; + + std::string cmd = cmdTemp.str(); + + size_t i; + std::string find = "--relaunch"; + while ((i = cmd.find(find)) != std::string::npos) { + cmd.replace(i, find.length(), ""); + } + + return cmd; +} + +void MSWindowsWatchdog::outputLoop(void *) { + // +1 char for \0 + CHAR buffer[kOutputBufferSize + 1]; + + while (m_monitoring) { + + DWORD bytesRead; + BOOL success = + ReadFile(m_stdOutRead, buffer, kOutputBufferSize, &bytesRead, NULL); + + // assume the process has gone away? slow down + // the reads until another one turns up. + if (!success || bytesRead == 0) { + ARCH->sleep(1); + } else { + buffer[bytesRead] = '\0'; + + testOutput(buffer); + + m_ipcLogOutputter.write(kINFO, buffer); + + if (m_fileLogOutputter != NULL) { + m_fileLogOutputter->write(kINFO, buffer); + } #if SYSAPI_WIN32 - if (m_foreground) { - // when in foreground mode (useful for debugging), send the core - // process output to the VS debug output window. - // we could use the MSWindowsDebugOutputter, but it's really fiddly to so, - // and there doesn't seem to be an advantage of doing that. - OutputDebugString(buffer); - } + if (m_foreground) { + // when in foreground mode (useful for debugging), send the core + // process output to the VS debug output window. + // we could use the MSWindowsDebugOutputter, but it's really fiddly to + // so, and there doesn't seem to be an advantage of doing that. + OutputDebugString(buffer); + } #endif - } } + } } -void -MSWindowsWatchdog::shutdownProcess(HANDLE handle, DWORD pid, int timeout) -{ - DWORD exitCode; +void MSWindowsWatchdog::shutdownProcess(HANDLE handle, DWORD pid, int timeout) { + DWORD exitCode; + GetExitCodeProcess(handle, &exitCode); + if (exitCode != STILL_ACTIVE) { + return; + } + + IpcShutdownMessage shutdown; + m_ipcServer.send(shutdown, kIpcClientNode); + + // wait for process to exit gracefully. + double start = ARCH->time(); + while (true) { + GetExitCodeProcess(handle, &exitCode); if (exitCode != STILL_ACTIVE) { - return; + // yay, we got a graceful shutdown. there should be no hook in use errors! + LOG((CLOG_DEBUG "process %d was shutdown gracefully", pid)); + break; + } else { + + double elapsed = (ARCH->time() - start); + if (elapsed > timeout) { + // if timeout reached, kill forcefully. + // calling TerminateProcess on synergy is very bad! + // it causes the hook DLL to stay loaded in some apps, + // making it impossible to start synergy again. + LOG((CLOG_WARN + "shutdown timed out after %d secs, forcefully terminating", + (int)elapsed)); + TerminateProcess(handle, kExitSuccess); + break; + } + + ARCH->sleep(1); } + } - IpcShutdownMessage shutdown; - m_ipcServer.send(shutdown, kIpcClientNode); - - // wait for process to exit gracefully. - double start = ARCH->time(); - while (true) { - - GetExitCodeProcess(handle, &exitCode); - if (exitCode != STILL_ACTIVE) { - // yay, we got a graceful shutdown. there should be no hook in use errors! - LOG((CLOG_DEBUG "process %d was shutdown gracefully", pid)); - break; - } - else { - - double elapsed = (ARCH->time() - start); - if (elapsed > timeout) { - // if timeout reached, kill forcefully. - // calling TerminateProcess on synergy is very bad! - // it causes the hook DLL to stay loaded in some apps, - // making it impossible to start synergy again. - LOG((CLOG_WARN "shutdown timed out after %d secs, forcefully terminating", (int)elapsed)); - TerminateProcess(handle, kExitSuccess); - break; - } - - ARCH->sleep(1); - } - } - - closeProcessHandles(pid); + closeProcessHandles(pid); } -void -MSWindowsWatchdog::shutdownExistingProcesses() -{ - // first we need to take a snapshot of the running processes - HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, CURRENT_PROCESS_ID); - if (snapshot == INVALID_HANDLE_VALUE) { - LOG((CLOG_ERR "could not get process snapshot")); - throw XArch(new XArchEvalWindows); +void MSWindowsWatchdog::shutdownExistingProcesses() { + // first we need to take a snapshot of the running processes + HANDLE snapshot = + CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, CURRENT_PROCESS_ID); + if (snapshot == INVALID_HANDLE_VALUE) { + LOG((CLOG_ERR "could not get process snapshot")); + throw XArch(new XArchEvalWindows); + } + + PROCESSENTRY32 entry; + entry.dwSize = sizeof(PROCESSENTRY32); + + // get the first process, and if we can't do that then it's + // unlikely we can go any further + BOOL gotEntry = Process32First(snapshot, &entry); + if (!gotEntry) { + LOG((CLOG_ERR "could not get first process entry")); + throw XArch(new XArchEvalWindows); + } + + // now just iterate until we can find winlogon.exe pid + DWORD pid = 0; + while (gotEntry) { + + // make sure we're not checking the system process + if (entry.th32ProcessID != 0) { + + if (_stricmp(entry.szExeFile, "synergyc.exe") == 0 || + _stricmp(entry.szExeFile, "synergys.exe") == 0 || + _stricmp(entry.szExeFile, "synergy-core.exe") == 0) { + + HANDLE handle = + OpenProcess(PROCESS_ALL_ACCESS, FALSE, entry.th32ProcessID); + shutdownProcess(handle, entry.th32ProcessID, 10); + CloseHandle(handle); + } } - PROCESSENTRY32 entry; - entry.dwSize = sizeof(PROCESSENTRY32); - - // get the first process, and if we can't do that then it's - // unlikely we can go any further - BOOL gotEntry = Process32First(snapshot, &entry); + // now move on to the next entry (if we're not at the end) + gotEntry = Process32Next(snapshot, &entry); if (!gotEntry) { - LOG((CLOG_ERR "could not get first process entry")); + + DWORD err = GetLastError(); + if (err != ERROR_NO_MORE_FILES) { + + // only worry about error if it's not the end of the snapshot + LOG((CLOG_ERR "could not get subsiquent process entry")); throw XArch(new XArchEvalWindows); + } } + } - // now just iterate until we can find winlogon.exe pid - DWORD pid = 0; - while (gotEntry) { - - // make sure we're not checking the system process - if (entry.th32ProcessID != 0) { - - if (_stricmp(entry.szExeFile, "synergyc.exe") == 0 || - _stricmp(entry.szExeFile, "synergys.exe") == 0 || - _stricmp(entry.szExeFile, "synergy-core.exe") == 0) { - - HANDLE handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, entry.th32ProcessID); - shutdownProcess(handle, entry.th32ProcessID, 10); - CloseHandle(handle); - } - } - - // now move on to the next entry (if we're not at the end) - gotEntry = Process32Next(snapshot, &entry); - if (!gotEntry) { - - DWORD err = GetLastError(); - if (err != ERROR_NO_MORE_FILES) { - - // only worry about error if it's not the end of the snapshot - LOG((CLOG_ERR "could not get subsiquent process entry")); - throw XArch(new XArchEvalWindows); - } - } - } - - clearAllChildren(); - CloseHandle(snapshot); - m_processRunning = false; + clearAllChildren(); + CloseHandle(snapshot); + m_processRunning = false; } -void -MSWindowsWatchdog::getActiveDesktop(LPSECURITY_ATTRIBUTES security) -{ - String installedDir = ARCH->getInstalledDirectory(); - if (!installedDir.empty()) { - String syntoolCommand; - syntoolCommand.append("\"").append(installedDir).append("\\").append("syntool").append("\""); - syntoolCommand.append(" --get-active-desktop"); +void MSWindowsWatchdog::getActiveDesktop(LPSECURITY_ATTRIBUTES security) { + String installedDir = ARCH->getInstalledDirectory(); + if (!installedDir.empty()) { + String syntoolCommand; + syntoolCommand.append("\"") + .append(installedDir) + .append("\\") + .append("syntool") + .append("\""); + syntoolCommand.append(" --get-active-desktop"); - m_session.updateActiveSession(); - bool elevateProcess = m_elevateProcess; - m_elevateProcess = true; - HANDLE userToken = getUserToken(security); - m_elevateProcess = elevateProcess; + m_session.updateActiveSession(); + bool elevateProcess = m_elevateProcess; + m_elevateProcess = true; + HANDLE userToken = getUserToken(security); + m_elevateProcess = elevateProcess; - BOOL createRet = startProcessAsUser(syntoolCommand, userToken, security); - auto pid = m_processInfo.dwProcessId; - if (!createRet) { - DWORD rc = GetLastError(); - RevertToSelf(); - } - else { - LOG((CLOG_DEBUG "launched syntool to check active desktop")); - } - - ARCH->lockMutex(m_mutex); - int waitTime = 0; - while (!m_ready) { - if (waitTime >= MAXIMUM_WAIT_TIME) { - break; - } - - ARCH->waitCondVar(m_condVar, m_mutex, 1.0); - waitTime++; - } - m_ready = false; - ARCH->unlockMutex(m_mutex); - closeProcessHandles(pid); + BOOL createRet = startProcessAsUser(syntoolCommand, userToken, security); + auto pid = m_processInfo.dwProcessId; + if (!createRet) { + DWORD rc = GetLastError(); + RevertToSelf(); + } else { + LOG((CLOG_DEBUG "launched syntool to check active desktop")); } + + ARCH->lockMutex(m_mutex); + int waitTime = 0; + while (!m_ready) { + if (waitTime >= MAXIMUM_WAIT_TIME) { + break; + } + + ARCH->waitCondVar(m_condVar, m_mutex, 1.0); + waitTime++; + } + m_ready = false; + ARCH->unlockMutex(m_mutex); + closeProcessHandles(pid); + } } -void -MSWindowsWatchdog::testOutput(String buffer) -{ - // HACK: check standard output seems hacky. - size_t i = buffer.find(g_activeDesktop); - if (i != String::npos) { - size_t s = sizeof(g_activeDesktop); - std::string defaultScreen = "Default"; - m_activeDesktop = trimDesktopName(buffer.substr(i + s - 1)); - m_autoElevated = std::strncmp(m_activeDesktop.c_str(), - defaultScreen.c_str(), - defaultScreen.length()); +void MSWindowsWatchdog::testOutput(String buffer) { + // HACK: check standard output seems hacky. + size_t i = buffer.find(g_activeDesktop); + if (i != String::npos) { + size_t s = sizeof(g_activeDesktop); + std::string defaultScreen = "Default"; + m_activeDesktop = trimDesktopName(buffer.substr(i + s - 1)); + m_autoElevated = std::strncmp( + m_activeDesktop.c_str(), defaultScreen.c_str(), defaultScreen.length()); - ARCH->lockMutex(m_mutex); - m_ready = true; - ARCH->broadcastCondVar(m_condVar); - ARCH->unlockMutex(m_mutex); - } + ARCH->lockMutex(m_mutex); + m_ready = true; + ARCH->broadcastCondVar(m_condVar); + ARCH->unlockMutex(m_mutex); + } } -void MSWindowsWatchdog::closeProcessHandles(unsigned long pid, bool removeFromMap) { - auto processInfo = m_children.find(pid); - if (processInfo != m_children.end()) { - CloseHandle(processInfo->second.hProcess); - CloseHandle(processInfo->second.hThread); - if(removeFromMap) { - m_children.erase(processInfo); - } +void MSWindowsWatchdog::closeProcessHandles(unsigned long pid, + bool removeFromMap) { + auto processInfo = m_children.find(pid); + if (processInfo != m_children.end()) { + CloseHandle(processInfo->second.hProcess); + CloseHandle(processInfo->second.hThread); + if (removeFromMap) { + m_children.erase(processInfo); } + } } void MSWindowsWatchdog::clearAllChildren() { - for (auto it = m_children.begin(); it != m_children.end(); ++it) - { - closeProcessHandles(it->second.dwThreadId, false); - } - m_children.clear(); + for (auto it = m_children.begin(); it != m_children.end(); ++it) { + closeProcessHandles(it->second.dwThreadId, false); + } + m_children.clear(); } diff --git a/src/lib/platform/MSWindowsWatchdog.h b/src/lib/platform/MSWindowsWatchdog.h index 2b9ad3d98..5be658b99 100644 --- a/src/lib/platform/MSWindowsWatchdog.h +++ b/src/lib/platform/MSWindowsWatchdog.h @@ -6,7 +6,7 @@ * 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 LICENSE 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 @@ -18,15 +18,15 @@ #pragma once +#include "arch/IArchMultithread.h" #include "platform/MSWindowsSession.h" #include "synergy/XSynergy.h" -#include "arch/IArchMultithread.h" + +#include +#include #define WIN32_LEAN_AND_MEAN #include -#include -#include -#include class Thread; class IpcLogOutputter; @@ -35,74 +35,74 @@ class FileLogOutputter; class MSWindowsWatchdog { public: - MSWindowsWatchdog( - bool autoDetectCommand, - IpcServer& ipcServer, - IpcLogOutputter& ipcLogOutputter, - bool foreground); - virtual ~MSWindowsWatchdog(); + MSWindowsWatchdog(bool autoDetectCommand, IpcServer &ipcServer, + IpcLogOutputter &ipcLogOutputter, bool foreground); + virtual ~MSWindowsWatchdog(); - void startAsync(); - std::string getCommand() const; - void setCommand(const std::string& command, bool elevate); - void stop(); - bool isProcessActive(); - void setFileLogOutputter(FileLogOutputter* outputter); + void startAsync(); + std::string getCommand() const; + void setCommand(const std::string &command, bool elevate); + void stop(); + bool isProcessActive(); + void setFileLogOutputter(FileLogOutputter *outputter); private: - void mainLoop(void*); - void outputLoop(void*); - void shutdownProcess(HANDLE handle, DWORD pid, int timeout); - void shutdownExistingProcesses(); - HANDLE duplicateProcessToken(HANDLE process, LPSECURITY_ATTRIBUTES security); - HANDLE getUserToken(LPSECURITY_ATTRIBUTES security); - void startProcess(); - BOOL startProcessAsUser(String& command, HANDLE userToken, LPSECURITY_ATTRIBUTES sa); - BOOL startProcessInForeground(String& command); - void sendSas(); - void getActiveDesktop(LPSECURITY_ATTRIBUTES security); - void testOutput(String buffer); - void setStartupInfo(STARTUPINFO& si); - void checkChildren(); - /** - * @brief This closes the handles held to a child thread - * @param pid the ID of the process to kill, will do nothing if PID is not a valid child - * @param removeFromMap should the function remove the item from the children map - */ - void closeProcessHandles(unsigned long pid, bool removeFromMap = true); - /** - * @brief This kills off all children's handles created by this process - */ - void clearAllChildren(); + void mainLoop(void *); + void outputLoop(void *); + void shutdownProcess(HANDLE handle, DWORD pid, int timeout); + void shutdownExistingProcesses(); + HANDLE duplicateProcessToken(HANDLE process, LPSECURITY_ATTRIBUTES security); + HANDLE getUserToken(LPSECURITY_ATTRIBUTES security); + void startProcess(); + BOOL startProcessAsUser(String &command, HANDLE userToken, + LPSECURITY_ATTRIBUTES sa); + BOOL startProcessInForeground(String &command); + void sendSas(); + void getActiveDesktop(LPSECURITY_ATTRIBUTES security); + void testOutput(String buffer); + void setStartupInfo(STARTUPINFO &si); + void checkChildren(); + /** + * @brief This closes the handles held to a child thread + * @param pid the ID of the process to kill, will do nothing if PID is not a + * valid child + * @param removeFromMap should the function remove the item from the children + * map + */ + void closeProcessHandles(unsigned long pid, bool removeFromMap = true); + /** + * @brief This kills off all children's handles created by this process + */ + void clearAllChildren(); private: - Thread* m_thread; - bool m_autoDetectCommand; - std::string m_command; - bool m_monitoring; - bool m_commandChanged; - HANDLE m_stdOutWrite; - HANDLE m_stdOutRead; - Thread* m_outputThread; - IpcServer& m_ipcServer; - IpcLogOutputter& m_ipcLogOutputter; - bool m_elevateProcess; - MSWindowsSession m_session; - PROCESS_INFORMATION m_processInfo; - int m_processFailures; - bool m_processRunning; - FileLogOutputter* m_fileLogOutputter; - bool m_autoElevated; - ArchMutex m_mutex; - ArchCond m_condVar; - bool m_ready; - bool m_foreground; - std::string m_activeDesktop; + Thread *m_thread; + bool m_autoDetectCommand; + std::string m_command; + bool m_monitoring; + bool m_commandChanged; + HANDLE m_stdOutWrite; + HANDLE m_stdOutRead; + Thread *m_outputThread; + IpcServer &m_ipcServer; + IpcLogOutputter &m_ipcLogOutputter; + bool m_elevateProcess; + MSWindowsSession m_session; + PROCESS_INFORMATION m_processInfo; + int m_processFailures; + bool m_processRunning; + FileLogOutputter *m_fileLogOutputter; + bool m_autoElevated; + ArchMutex m_mutex; + ArchCond m_condVar; + bool m_ready; + bool m_foreground; + std::string m_activeDesktop; - /// @brief Save the info of all process made - /// We will use this to track all processes we make and - /// kill off handels and children that we no longer need - std::map m_children; + /// @brief Save the info of all process made + /// We will use this to track all processes we make and + /// kill off handels and children that we no longer need + std::map m_children; }; //! Relauncher error @@ -111,8 +111,8 @@ An error occured in the process watchdog. */ class XMSWindowsWatchdogError : public XSynergy { public: - XMSWindowsWatchdogError(const String& msg) : XSynergy(msg) { } + XMSWindowsWatchdogError(const String &msg) : XSynergy(msg) {} - // XBase overrides - virtual String getWhat() const throw() { return what(); } + // XBase overrides + virtual String getWhat() const throw() { return what(); } }; diff --git a/src/lib/platform/OSXAutoTypes.h b/src/lib/platform/OSXAutoTypes.h index fae0a1dc2..2868e6ec6 100644 --- a/src/lib/platform/OSXAutoTypes.h +++ b/src/lib/platform/OSXAutoTypes.h @@ -17,8 +17,8 @@ #pragma once #if WINAPI_CARBON -#include #include +#include using CFDeallocator = decltype(&CFRelease); using AutoCFArray = std::unique_ptr; diff --git a/src/lib/platform/OSXClipboard.cpp b/src/lib/platform/OSXClipboard.cpp index 9a4c18507..dbdb9f07b 100644 --- a/src/lib/platform/OSXClipboard.cpp +++ b/src/lib/platform/OSXClipboard.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 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 LICENSE 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 @@ -18,244 +18,214 @@ #include "platform/OSXClipboard.h" -#include "synergy/Clipboard.h" -#include "platform/OSXClipboardUTF8Converter.h" -#include "platform/OSXClipboardUTF16Converter.h" -#include "platform/OSXClipboardTextConverter.h" +#include "arch/XArch.h" +#include "base/Log.h" #include "platform/OSXClipboardBMPConverter.h" #include "platform/OSXClipboardHTMLConverter.h" -#include "base/Log.h" -#include "arch/XArch.h" +#include "platform/OSXClipboardTextConverter.h" +#include "platform/OSXClipboardUTF16Converter.h" +#include "platform/OSXClipboardUTF8Converter.h" +#include "synergy/Clipboard.h" // // OSXClipboard // -OSXClipboard::OSXClipboard() : - m_time(0), - m_pboard(NULL) -{ - m_converters.push_back(new OSXClipboardHTMLConverter); - m_converters.push_back(new OSXClipboardBMPConverter); - m_converters.push_back(new OSXClipboardUTF8Converter); - m_converters.push_back(new OSXClipboardUTF16Converter); - m_converters.push_back(new OSXClipboardTextConverter); +OSXClipboard::OSXClipboard() : m_time(0), m_pboard(NULL) { + m_converters.push_back(new OSXClipboardHTMLConverter); + m_converters.push_back(new OSXClipboardBMPConverter); + m_converters.push_back(new OSXClipboardUTF8Converter); + m_converters.push_back(new OSXClipboardUTF16Converter); + m_converters.push_back(new OSXClipboardTextConverter); - OSStatus createErr = PasteboardCreate(kPasteboardClipboard, &m_pboard); - if (createErr != noErr) { - LOG((CLOG_DEBUG "failed to create clipboard reference: error %i", createErr)); - LOG((CLOG_ERR "unable to connect to pasteboard, clipboard sharing disabled", createErr)); - m_pboard = NULL; - return; + OSStatus createErr = PasteboardCreate(kPasteboardClipboard, &m_pboard); + if (createErr != noErr) { + LOG((CLOG_DEBUG "failed to create clipboard reference: error %i", + createErr)); + LOG((CLOG_ERR "unable to connect to pasteboard, clipboard sharing disabled", + createErr)); + m_pboard = NULL; + return; + } - } - - OSStatus syncErr = PasteboardSynchronize(m_pboard); - if (syncErr != noErr) { - LOG((CLOG_DEBUG "failed to syncronize clipboard: error %i", syncErr)); - } + OSStatus syncErr = PasteboardSynchronize(m_pboard); + if (syncErr != noErr) { + LOG((CLOG_DEBUG "failed to syncronize clipboard: error %i", syncErr)); + } } -OSXClipboard::~OSXClipboard() -{ - clearConverters(); +OSXClipboard::~OSXClipboard() { clearConverters(); } + +bool OSXClipboard::empty() { + LOG((CLOG_DEBUG "emptying clipboard")); + if (m_pboard == NULL) + return false; + + OSStatus err = PasteboardClear(m_pboard); + if (err != noErr) { + LOG((CLOG_DEBUG "failed to clear clipboard: error %i", err)); + return false; + } + + return true; } - bool -OSXClipboard::empty() -{ - LOG((CLOG_DEBUG "emptying clipboard")); - if (m_pboard == NULL) - return false; +bool OSXClipboard::synchronize() { + if (m_pboard == NULL) + return false; - OSStatus err = PasteboardClear(m_pboard); - if (err != noErr) { - LOG((CLOG_DEBUG "failed to clear clipboard: error %i", err)); - return false; - } + PasteboardSyncFlags flags = PasteboardSynchronize(m_pboard); + LOG((CLOG_DEBUG2 "flags: %x", flags)); + if (flags & kPasteboardModified) { return true; + } + return false; } - bool -OSXClipboard::synchronize() -{ - if (m_pboard == NULL) - return false; +void OSXClipboard::add(EFormat format, const String &data) { + if (m_pboard == NULL) + return; - PasteboardSyncFlags flags = PasteboardSynchronize(m_pboard); - LOG((CLOG_DEBUG2 "flags: %x", flags)); + LOG((CLOG_DEBUG "add %d bytes to clipboard format: %d", data.size(), format)); + if (format == IClipboard::kText) { + LOG((CLOG_DEBUG "format of data to be added to clipboard was kText")); + } else if (format == IClipboard::kBitmap) { + LOG((CLOG_DEBUG "format of data to be added to clipboard was kBitmap")); + } else if (format == IClipboard::kHTML) { + LOG((CLOG_DEBUG "format of data to be added to clipboard was kHTML")); + } - if (flags & kPasteboardModified) { + for (ConverterList::const_iterator index = m_converters.begin(); + index != m_converters.end(); ++index) { + + IOSXClipboardConverter *converter = *index; + + // skip converters for other formats + if (converter->getFormat() == format) { + String osXData = converter->fromIClipboard(data); + CFStringRef flavorType = converter->getOSXFormat(); + CFDataRef dataRef = CFDataCreate(kCFAllocatorDefault, + (UInt8 *)osXData.data(), osXData.size()); + PasteboardItemID itemID = 0; + + if (dataRef) { + PasteboardPutItemFlavor(m_pboard, itemID, flavorType, dataRef, + kPasteboardFlavorNoFlags); + + CFRelease(dataRef); + LOG((CLOG_DEBUG "added %d bytes to clipboard format: %d", data.size(), + format)); + } + } + } +} + +bool OSXClipboard::open(Time time) const { + if (m_pboard == NULL) + return false; + + LOG((CLOG_DEBUG "opening clipboard")); + m_time = time; + return true; +} + +void OSXClipboard::close() const { + LOG((CLOG_DEBUG "closing clipboard")); + /* not needed */ +} + +IClipboard::Time OSXClipboard::getTime() const { return m_time; } + +bool OSXClipboard::has(EFormat format) const { + if (m_pboard == NULL) + return false; + + PasteboardItemID item; + PasteboardGetItemIdentifier(m_pboard, (CFIndex)1, &item); + + for (ConverterList::const_iterator index = m_converters.begin(); + index != m_converters.end(); ++index) { + IOSXClipboardConverter *converter = *index; + if (converter->getFormat() == format) { + PasteboardFlavorFlags flags; + CFStringRef type = converter->getOSXFormat(); + + OSStatus res; + + if ((res = PasteboardGetItemFlavorFlags(m_pboard, item, type, &flags)) == + noErr) { return true; + } } - return false; -} + } - void -OSXClipboard::add(EFormat format, const String & data) -{ - if (m_pboard == NULL) - return; - - LOG((CLOG_DEBUG "add %d bytes to clipboard format: %d", data.size(), format)); - if (format == IClipboard::kText) { - LOG((CLOG_DEBUG "format of data to be added to clipboard was kText")); - } - else if (format == IClipboard::kBitmap) { - LOG((CLOG_DEBUG "format of data to be added to clipboard was kBitmap")); - } - else if (format == IClipboard::kHTML) { - LOG((CLOG_DEBUG "format of data to be added to clipboard was kHTML")); - } - - for (ConverterList::const_iterator index = m_converters.begin(); - index != m_converters.end(); ++index) { - - IOSXClipboardConverter* converter = *index; - - // skip converters for other formats - if (converter->getFormat() == format) { - String osXData = converter->fromIClipboard(data); - CFStringRef flavorType = converter->getOSXFormat(); - CFDataRef dataRef = CFDataCreate(kCFAllocatorDefault, (UInt8 *)osXData.data(), osXData.size()); - PasteboardItemID itemID = 0; - - if (dataRef) { - PasteboardPutItemFlavor( - m_pboard, - itemID, - flavorType, - dataRef, - kPasteboardFlavorNoFlags); - - CFRelease(dataRef); - LOG((CLOG_DEBUG "added %d bytes to clipboard format: %d", data.size(), format)); - } - } - } + return false; } -bool -OSXClipboard::open(Time time) const -{ - if (m_pboard == NULL) - return false; +String OSXClipboard::get(EFormat format) const { + CFStringRef type; + PasteboardItemID item; + String result; - LOG((CLOG_DEBUG "opening clipboard")); - m_time = time; - return true; + if (m_pboard == NULL) + return result; + + PasteboardGetItemIdentifier(m_pboard, (CFIndex)1, &item); + + // find the converter for the first clipboard format we can handle + IOSXClipboardConverter *converter = NULL; + for (ConverterList::const_iterator index = m_converters.begin(); + index != m_converters.end(); ++index) { + converter = *index; + + PasteboardFlavorFlags flags; + type = converter->getOSXFormat(); + + if (converter->getFormat() == format && + PasteboardGetItemFlavorFlags(m_pboard, item, type, &flags) == noErr) { + break; + } + converter = NULL; + } + + // if no converter then we don't recognize any formats + if (converter == NULL) { + LOG((CLOG_DEBUG "unable to find converter for data")); + return result; + } + + // get the clipboard data. + CFDataRef buffer = NULL; + try { + OSStatus err = PasteboardCopyItemFlavorData(m_pboard, item, type, &buffer); + + if (err != noErr) { + throw err; + } + + result = String((char *)CFDataGetBytePtr(buffer), CFDataGetLength(buffer)); + } catch (OSStatus err) { + LOG((CLOG_DEBUG "exception thrown in OSXClipboard::get MacError (%d)", + err)); + } catch (...) { + LOG((CLOG_DEBUG "unknown exception in OSXClipboard::get")); + RETHROW_XTHREAD + } + + if (buffer != NULL) + CFRelease(buffer); + + return converter->toIClipboard(result); } -void -OSXClipboard::close() const -{ - LOG((CLOG_DEBUG "closing clipboard")); - /* not needed */ -} - -IClipboard::Time -OSXClipboard::getTime() const -{ - return m_time; -} - -bool -OSXClipboard::has(EFormat format) const -{ - if (m_pboard == NULL) - return false; - - PasteboardItemID item; - PasteboardGetItemIdentifier(m_pboard, (CFIndex) 1, &item); - - for (ConverterList::const_iterator index = m_converters.begin(); - index != m_converters.end(); ++index) { - IOSXClipboardConverter* converter = *index; - if (converter->getFormat() == format) { - PasteboardFlavorFlags flags; - CFStringRef type = converter->getOSXFormat(); - - OSStatus res; - - if ((res = PasteboardGetItemFlavorFlags(m_pboard, item, type, &flags)) == noErr) { - return true; - } - } - } - - return false; -} - -String -OSXClipboard::get(EFormat format) const -{ - CFStringRef type; - PasteboardItemID item; - String result; - - if (m_pboard == NULL) - return result; - - PasteboardGetItemIdentifier(m_pboard, (CFIndex) 1, &item); - - - // find the converter for the first clipboard format we can handle - IOSXClipboardConverter* converter = NULL; - for (ConverterList::const_iterator index = m_converters.begin(); - index != m_converters.end(); ++index) { - converter = *index; - - PasteboardFlavorFlags flags; - type = converter->getOSXFormat(); - - if (converter->getFormat() == format && - PasteboardGetItemFlavorFlags(m_pboard, item, type, &flags) == noErr) { - break; - } - converter = NULL; - } - - // if no converter then we don't recognize any formats - if (converter == NULL) { - LOG((CLOG_DEBUG "unable to find converter for data")); - return result; - } - - // get the clipboard data. - CFDataRef buffer = NULL; - try { - OSStatus err = PasteboardCopyItemFlavorData(m_pboard, item, type, &buffer); - - if (err != noErr) { - throw err; - } - - result = String((char *) CFDataGetBytePtr(buffer), CFDataGetLength(buffer)); - } - catch (OSStatus err) { - LOG((CLOG_DEBUG "exception thrown in OSXClipboard::get MacError (%d)", err)); - } - catch (...) { - LOG((CLOG_DEBUG "unknown exception in OSXClipboard::get")); - RETHROW_XTHREAD - } - - if (buffer != NULL) - CFRelease(buffer); - - return converter->toIClipboard(result); -} - - void -OSXClipboard::clearConverters() -{ - if (m_pboard == NULL) - return; - - for (ConverterList::iterator index = m_converters.begin(); - index != m_converters.end(); ++index) { - delete *index; - } - m_converters.clear(); +void OSXClipboard::clearConverters() { + if (m_pboard == NULL) + return; + + for (ConverterList::iterator index = m_converters.begin(); + index != m_converters.end(); ++index) { + delete *index; + } + m_converters.clear(); } diff --git a/src/lib/platform/OSXClipboard.h b/src/lib/platform/OSXClipboard.h index e9d01a703..4833f3c6a 100644 --- a/src/lib/platform/OSXClipboard.h +++ b/src/lib/platform/OSXClipboard.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 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 LICENSE 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 @@ -28,31 +28,32 @@ class IOSXClipboardConverter; //! OS X clipboard implementation class OSXClipboard : public IClipboard { public: - OSXClipboard(); - virtual ~OSXClipboard(); + OSXClipboard(); + virtual ~OSXClipboard(); - //! Test if clipboard is owned by synergy - static bool isOwnedBySynergy(); + //! Test if clipboard is owned by synergy + static bool isOwnedBySynergy(); - // IClipboard overrides - virtual bool empty(); - virtual void add(EFormat, const String& data); - virtual bool open(Time) const; - virtual void close() const; - virtual Time getTime() const; - virtual bool has(EFormat) const; - virtual String get(EFormat) const; + // IClipboard overrides + virtual bool empty(); + virtual void add(EFormat, const String &data); + virtual bool open(Time) const; + virtual void close() const; + virtual Time getTime() const; + virtual bool has(EFormat) const; + virtual String get(EFormat) const; - bool synchronize(); -private: - void clearConverters(); + bool synchronize(); private: - typedef std::vector ConverterList; + void clearConverters(); - mutable Time m_time; - ConverterList m_converters; - PasteboardRef m_pboard; +private: + typedef std::vector ConverterList; + + mutable Time m_time; + ConverterList m_converters; + PasteboardRef m_pboard; }; //! Clipboard format converter interface @@ -61,35 +62,33 @@ This interface defines the methods common to all Scrap book format */ class IOSXClipboardConverter : public IInterface { public: - //! @name accessors - //@{ + //! @name accessors + //@{ - //! Get clipboard format - /*! - Return the clipboard format this object converts from/to. - */ - virtual IClipboard::EFormat - getFormat() const = 0; + //! Get clipboard format + /*! + Return the clipboard format this object converts from/to. + */ + virtual IClipboard::EFormat getFormat() const = 0; - //! returns the scrap flavor type that this object converts from/to - virtual CFStringRef - getOSXFormat() const = 0; + //! returns the scrap flavor type that this object converts from/to + virtual CFStringRef getOSXFormat() const = 0; - //! Convert from IClipboard format - /*! - Convert from the IClipboard format to the Carbon scrap format. - The input data must be in the IClipboard format returned by - getFormat(). The return data will be in the scrap - format returned by getOSXFormat(). - */ - virtual String fromIClipboard(const String&) const = 0; + //! Convert from IClipboard format + /*! + Convert from the IClipboard format to the Carbon scrap format. + The input data must be in the IClipboard format returned by + getFormat(). The return data will be in the scrap + format returned by getOSXFormat(). + */ + virtual String fromIClipboard(const String &) const = 0; - //! Convert to IClipboard format - /*! - Convert from the carbon scrap format to the IClipboard format - (i.e., the reverse of fromIClipboard()). - */ - virtual String toIClipboard(const String&) const = 0; + //! Convert to IClipboard format + /*! + Convert from the carbon scrap format to the IClipboard format + (i.e., the reverse of fromIClipboard()). + */ + virtual String toIClipboard(const String &) const = 0; - //@} + //@} }; diff --git a/src/lib/platform/OSXClipboardAnyBitmapConverter.cpp b/src/lib/platform/OSXClipboardAnyBitmapConverter.cpp index bab48a0f7..e21f9c07b 100644 --- a/src/lib/platform/OSXClipboardAnyBitmapConverter.cpp +++ b/src/lib/platform/OSXClipboardAnyBitmapConverter.cpp @@ -19,30 +19,23 @@ #include "platform/OSXClipboardAnyBitmapConverter.h" #include -OSXClipboardAnyBitmapConverter::OSXClipboardAnyBitmapConverter() -{ - // do nothing +OSXClipboardAnyBitmapConverter::OSXClipboardAnyBitmapConverter() { + // do nothing } -OSXClipboardAnyBitmapConverter::~OSXClipboardAnyBitmapConverter() -{ - // do nothing +OSXClipboardAnyBitmapConverter::~OSXClipboardAnyBitmapConverter() { + // do nothing } -IClipboard::EFormat -OSXClipboardAnyBitmapConverter::getFormat() const -{ - return IClipboard::kBitmap; +IClipboard::EFormat OSXClipboardAnyBitmapConverter::getFormat() const { + return IClipboard::kBitmap; } String -OSXClipboardAnyBitmapConverter::fromIClipboard(const String& data) const -{ - return doFromIClipboard(data); +OSXClipboardAnyBitmapConverter::fromIClipboard(const String &data) const { + return doFromIClipboard(data); } -String -OSXClipboardAnyBitmapConverter::toIClipboard(const String& data) const -{ - return doToIClipboard(data); +String OSXClipboardAnyBitmapConverter::toIClipboard(const String &data) const { + return doToIClipboard(data); } diff --git a/src/lib/platform/OSXClipboardAnyBitmapConverter.h b/src/lib/platform/OSXClipboardAnyBitmapConverter.h index c54a4a8b5..79c611b34 100644 --- a/src/lib/platform/OSXClipboardAnyBitmapConverter.h +++ b/src/lib/platform/OSXClipboardAnyBitmapConverter.h @@ -23,26 +23,25 @@ //! Convert to/from some text encoding class OSXClipboardAnyBitmapConverter : public IOSXClipboardConverter { public: - OSXClipboardAnyBitmapConverter(); - virtual ~OSXClipboardAnyBitmapConverter(); + OSXClipboardAnyBitmapConverter(); + virtual ~OSXClipboardAnyBitmapConverter(); - // IOSXClipboardConverter overrides - virtual IClipboard::EFormat - getFormat() const; - virtual CFStringRef getOSXFormat() const = 0; - virtual String fromIClipboard(const String &) const; - virtual String toIClipboard(const String &) const; + // IOSXClipboardConverter overrides + virtual IClipboard::EFormat getFormat() const; + virtual CFStringRef getOSXFormat() const = 0; + virtual String fromIClipboard(const String &) const; + virtual String toIClipboard(const String &) const; protected: - //! Convert from IClipboard format - /*! - Do UTF-8 conversion and linefeed conversion. - */ - virtual String doFromIClipboard(const String&) const = 0; + //! Convert from IClipboard format + /*! + Do UTF-8 conversion and linefeed conversion. + */ + virtual String doFromIClipboard(const String &) const = 0; - //! Convert to IClipboard format - /*! - Do UTF-8 conversion and Linefeed conversion. - */ - virtual String doToIClipboard(const String&) const = 0; + //! Convert to IClipboard format + /*! + Do UTF-8 conversion and Linefeed conversion. + */ + virtual String doToIClipboard(const String &) const = 0; }; diff --git a/src/lib/platform/OSXClipboardAnyTextConverter.cpp b/src/lib/platform/OSXClipboardAnyTextConverter.cpp index 27711bc4c..74538e0df 100644 --- a/src/lib/platform/OSXClipboardAnyTextConverter.cpp +++ b/src/lib/platform/OSXClipboardAnyTextConverter.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 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 LICENSE 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 @@ -24,67 +24,45 @@ // OSXClipboardAnyTextConverter // -OSXClipboardAnyTextConverter::OSXClipboardAnyTextConverter() -{ - // do nothing +OSXClipboardAnyTextConverter::OSXClipboardAnyTextConverter() { + // do nothing } -OSXClipboardAnyTextConverter::~OSXClipboardAnyTextConverter() -{ - // do nothing +OSXClipboardAnyTextConverter::~OSXClipboardAnyTextConverter() { + // do nothing } -IClipboard::EFormat -OSXClipboardAnyTextConverter::getFormat() const -{ - return IClipboard::kText; +IClipboard::EFormat OSXClipboardAnyTextConverter::getFormat() const { + return IClipboard::kText; } -String -OSXClipboardAnyTextConverter::fromIClipboard(const String& data) const -{ - // convert linefeeds and then convert to desired encoding - return doFromIClipboard(convertLinefeedToMacOS(data)); +String OSXClipboardAnyTextConverter::fromIClipboard(const String &data) const { + // convert linefeeds and then convert to desired encoding + return doFromIClipboard(convertLinefeedToMacOS(data)); } -String -OSXClipboardAnyTextConverter::toIClipboard(const String& data) const -{ - // convert text then newlines - return convertLinefeedToUnix(doToIClipboard(data)); +String OSXClipboardAnyTextConverter::toIClipboard(const String &data) const { + // convert text then newlines + return convertLinefeedToUnix(doToIClipboard(data)); } -static -bool -isLF(char ch) -{ - return (ch == '\n'); +static bool isLF(char ch) { return (ch == '\n'); } + +static bool isCR(char ch) { return (ch == '\r'); } + +String OSXClipboardAnyTextConverter::convertLinefeedToMacOS(const String &src) { + // note -- we assume src is a valid UTF-8 string + String copy = src; + + std::replace_if(copy.begin(), copy.end(), isLF, '\r'); + + return copy; } -static -bool -isCR(char ch) -{ - return (ch == '\r'); -} - -String -OSXClipboardAnyTextConverter::convertLinefeedToMacOS(const String& src) -{ - // note -- we assume src is a valid UTF-8 string - String copy = src; - - std::replace_if(copy.begin(), copy.end(), isLF, '\r'); - - return copy; -} - -String -OSXClipboardAnyTextConverter::convertLinefeedToUnix(const String& src) -{ - String copy = src; - - std::replace_if(copy.begin(), copy.end(), isCR, '\n'); - - return copy; +String OSXClipboardAnyTextConverter::convertLinefeedToUnix(const String &src) { + String copy = src; + + std::replace_if(copy.begin(), copy.end(), isCR, '\n'); + + return copy; } diff --git a/src/lib/platform/OSXClipboardAnyTextConverter.h b/src/lib/platform/OSXClipboardAnyTextConverter.h index 3a95d496a..b4ea04402 100644 --- a/src/lib/platform/OSXClipboardAnyTextConverter.h +++ b/src/lib/platform/OSXClipboardAnyTextConverter.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 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 LICENSE 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 @@ -23,31 +23,29 @@ //! Convert to/from some text encoding class OSXClipboardAnyTextConverter : public IOSXClipboardConverter { public: - OSXClipboardAnyTextConverter(); - virtual ~OSXClipboardAnyTextConverter(); + OSXClipboardAnyTextConverter(); + virtual ~OSXClipboardAnyTextConverter(); - // IOSXClipboardConverter overrides - virtual IClipboard::EFormat - getFormat() const; - virtual CFStringRef - getOSXFormat() const = 0; - virtual String fromIClipboard(const String &) const; - virtual String toIClipboard(const String &) const; + // IOSXClipboardConverter overrides + virtual IClipboard::EFormat getFormat() const; + virtual CFStringRef getOSXFormat() const = 0; + virtual String fromIClipboard(const String &) const; + virtual String toIClipboard(const String &) const; protected: - //! Convert from IClipboard format - /*! - Do UTF-8 conversion and linefeed conversion. - */ - virtual String doFromIClipboard(const String&) const = 0; + //! Convert from IClipboard format + /*! + Do UTF-8 conversion and linefeed conversion. + */ + virtual String doFromIClipboard(const String &) const = 0; - //! Convert to IClipboard format - /*! - Do UTF-8 conversion and Linefeed conversion. - */ - virtual String doToIClipboard(const String&) const = 0; + //! Convert to IClipboard format + /*! + Do UTF-8 conversion and Linefeed conversion. + */ + virtual String doToIClipboard(const String &) const = 0; private: - static String convertLinefeedToMacOS(const String&); - static String convertLinefeedToUnix(const String&); + static String convertLinefeedToMacOS(const String &); + static String convertLinefeedToUnix(const String &); }; diff --git a/src/lib/platform/OSXClipboardBMPConverter.cpp b/src/lib/platform/OSXClipboardBMPConverter.cpp index f049514d7..6a8409c29 100644 --- a/src/lib/platform/OSXClipboardBMPConverter.cpp +++ b/src/lib/platform/OSXClipboardBMPConverter.cpp @@ -22,113 +22,89 @@ // BMP file header structure struct CBMPHeader { public: - UInt16 type; - UInt32 size; - UInt16 reserved1; - UInt16 reserved2; - UInt32 offset; + UInt16 type; + UInt32 size; + UInt16 reserved1; + UInt16 reserved2; + UInt32 offset; }; // BMP is little-endian -static inline -UInt32 -fromLEU32(const UInt8* data) -{ - return static_cast(data[0]) | - (static_cast(data[1]) << 8) | - (static_cast(data[2]) << 16) | - (static_cast(data[3]) << 24); +static inline UInt32 fromLEU32(const UInt8 *data) { + return static_cast(data[0]) | (static_cast(data[1]) << 8) | + (static_cast(data[2]) << 16) | + (static_cast(data[3]) << 24); } -static -void -toLE(UInt8*& dst, char src) -{ - dst[0] = static_cast(src); - dst += 1; +static void toLE(UInt8 *&dst, char src) { + dst[0] = static_cast(src); + dst += 1; } -static -void -toLE(UInt8*& dst, UInt16 src) -{ - dst[0] = static_cast(src & 0xffu); - dst[1] = static_cast((src >> 8) & 0xffu); - dst += 2; +static void toLE(UInt8 *&dst, UInt16 src) { + dst[0] = static_cast(src & 0xffu); + dst[1] = static_cast((src >> 8) & 0xffu); + dst += 2; } -static -void -toLE(UInt8*& dst, UInt32 src) -{ - dst[0] = static_cast(src & 0xffu); - dst[1] = static_cast((src >> 8) & 0xffu); - dst[2] = static_cast((src >> 16) & 0xffu); - dst[3] = static_cast((src >> 24) & 0xffu); - dst += 4; +static void toLE(UInt8 *&dst, UInt32 src) { + dst[0] = static_cast(src & 0xffu); + dst[1] = static_cast((src >> 8) & 0xffu); + dst[2] = static_cast((src >> 16) & 0xffu); + dst[3] = static_cast((src >> 24) & 0xffu); + dst += 4; } -OSXClipboardBMPConverter::OSXClipboardBMPConverter() -{ - // do nothing +OSXClipboardBMPConverter::OSXClipboardBMPConverter() { + // do nothing } -OSXClipboardBMPConverter::~OSXClipboardBMPConverter() -{ - // do nothing +OSXClipboardBMPConverter::~OSXClipboardBMPConverter() { + // do nothing } -IClipboard::EFormat -OSXClipboardBMPConverter::getFormat() const -{ - return IClipboard::kBitmap; +IClipboard::EFormat OSXClipboardBMPConverter::getFormat() const { + return IClipboard::kBitmap; } -CFStringRef -OSXClipboardBMPConverter::getOSXFormat() const -{ - // TODO: does this only work with Windows? - return CFSTR("com.microsoft.bmp"); +CFStringRef OSXClipboardBMPConverter::getOSXFormat() const { + // TODO: does this only work with Windows? + return CFSTR("com.microsoft.bmp"); } -String -OSXClipboardBMPConverter::fromIClipboard(const String& bmp) const -{ - LOG((CLOG_DEBUG1 "getting data from clipboard")); - // create BMP image - UInt8 header[14]; - UInt8* dst = header; - toLE(dst, 'B'); - toLE(dst, 'M'); - toLE(dst, static_cast(14 + bmp.size())); - toLE(dst, static_cast(0)); - toLE(dst, static_cast(0)); - toLE(dst, static_cast(14 + 40)); - return String(reinterpret_cast(header), 14) + bmp; +String OSXClipboardBMPConverter::fromIClipboard(const String &bmp) const { + LOG((CLOG_DEBUG1 "getting data from clipboard")); + // create BMP image + UInt8 header[14]; + UInt8 *dst = header; + toLE(dst, 'B'); + toLE(dst, 'M'); + toLE(dst, static_cast(14 + bmp.size())); + toLE(dst, static_cast(0)); + toLE(dst, static_cast(0)); + toLE(dst, static_cast(14 + 40)); + return String(reinterpret_cast(header), 14) + bmp; } -String -OSXClipboardBMPConverter::toIClipboard(const String& bmp) const -{ - // make sure data is big enough for a BMP file - if (bmp.size() <= 14 + 40) { - return String(); - } +String OSXClipboardBMPConverter::toIClipboard(const String &bmp) const { + // make sure data is big enough for a BMP file + if (bmp.size() <= 14 + 40) { + return String(); + } - // check BMP file header - const UInt8* rawBMPHeader = reinterpret_cast(bmp.data()); - if (rawBMPHeader[0] != 'B' || rawBMPHeader[1] != 'M') { - return String(); - } + // check BMP file header + const UInt8 *rawBMPHeader = reinterpret_cast(bmp.data()); + if (rawBMPHeader[0] != 'B' || rawBMPHeader[1] != 'M') { + return String(); + } - // get offset to image data - UInt32 offset = fromLEU32(rawBMPHeader + 10); + // get offset to image data + UInt32 offset = fromLEU32(rawBMPHeader + 10); - // construct BMP - if (offset == 14 + 40) { - return bmp.substr(14); - } - else { - return bmp.substr(14, 40) + bmp.substr(offset, bmp.size() - offset); - } + // construct BMP + if (offset == 14 + 40) { + return bmp.substr(14); + } else { + return bmp.substr(14, 40) + bmp.substr(offset, bmp.size() - offset); + } } diff --git a/src/lib/platform/OSXClipboardBMPConverter.h b/src/lib/platform/OSXClipboardBMPConverter.h index 48f888aaa..249cec868 100644 --- a/src/lib/platform/OSXClipboardBMPConverter.h +++ b/src/lib/platform/OSXClipboardBMPConverter.h @@ -23,22 +23,19 @@ //! Convert to/from some text encoding class OSXClipboardBMPConverter : public IOSXClipboardConverter { public: - OSXClipboardBMPConverter(); - virtual ~OSXClipboardBMPConverter(); + OSXClipboardBMPConverter(); + virtual ~OSXClipboardBMPConverter(); - // IMSWindowsClipboardConverter overrides - virtual IClipboard::EFormat - getFormat() const; + // IMSWindowsClipboardConverter overrides + virtual IClipboard::EFormat getFormat() const; - virtual CFStringRef - getOSXFormat() const; + virtual CFStringRef getOSXFormat() const; - // OSXClipboardAnyBMPConverter overrides - virtual String fromIClipboard(const String&) const; - virtual String toIClipboard(const String&) const; + // OSXClipboardAnyBMPConverter overrides + virtual String fromIClipboard(const String &) const; + virtual String toIClipboard(const String &) const; - // generic encoding converter - static String convertString(const String& data, - CFStringEncoding fromEncoding, - CFStringEncoding toEncoding); + // generic encoding converter + static String convertString(const String &data, CFStringEncoding fromEncoding, + CFStringEncoding toEncoding); }; diff --git a/src/lib/platform/OSXClipboardHTMLConverter.cpp b/src/lib/platform/OSXClipboardHTMLConverter.cpp index 462bb93fd..972354aff 100644 --- a/src/lib/platform/OSXClipboardHTMLConverter.cpp +++ b/src/lib/platform/OSXClipboardHTMLConverter.cpp @@ -20,81 +20,65 @@ #include "base/Unicode.h" -OSXClipboardHTMLConverter::OSXClipboardHTMLConverter() -{ - // do nothing +OSXClipboardHTMLConverter::OSXClipboardHTMLConverter() { + // do nothing } -OSXClipboardHTMLConverter::~OSXClipboardHTMLConverter() -{ - // do nothing +OSXClipboardHTMLConverter::~OSXClipboardHTMLConverter() { + // do nothing } -IClipboard::EFormat -OSXClipboardHTMLConverter::getFormat() const -{ - return IClipboard::kHTML; +IClipboard::EFormat OSXClipboardHTMLConverter::getFormat() const { + return IClipboard::kHTML; } -CFStringRef -OSXClipboardHTMLConverter::getOSXFormat() const -{ - return CFSTR("public.html"); +CFStringRef OSXClipboardHTMLConverter::getOSXFormat() const { + return CFSTR("public.html"); } -String -OSXClipboardHTMLConverter::convertString( - const String& data, - CFStringEncoding fromEncoding, - CFStringEncoding toEncoding) -{ - CFStringRef stringRef = CFStringCreateWithCString( - kCFAllocatorDefault, - data.c_str(), fromEncoding); +String OSXClipboardHTMLConverter::convertString(const String &data, + CFStringEncoding fromEncoding, + CFStringEncoding toEncoding) { + CFStringRef stringRef = CFStringCreateWithCString(kCFAllocatorDefault, + data.c_str(), fromEncoding); - if (stringRef == NULL) { - return String(); - } + if (stringRef == NULL) { + return String(); + } - CFIndex buffSize; - CFRange entireString = CFRangeMake(0, CFStringGetLength(stringRef)); + CFIndex buffSize; + CFRange entireString = CFRangeMake(0, CFStringGetLength(stringRef)); - CFStringGetBytes(stringRef, entireString, toEncoding, - 0, false, NULL, 0, &buffSize); + CFStringGetBytes(stringRef, entireString, toEncoding, 0, false, NULL, 0, + &buffSize); - char* buffer = new char[buffSize]; + char *buffer = new char[buffSize]; - if (buffer == NULL) { - CFRelease(stringRef); - return String(); - } - - CFStringGetBytes(stringRef, entireString, toEncoding, - 0, false, (UInt8*)buffer, buffSize, NULL); - - String result(buffer, buffSize); - - delete[] buffer; + if (buffer == NULL) { CFRelease(stringRef); + return String(); + } - return result; + CFStringGetBytes(stringRef, entireString, toEncoding, 0, false, + (UInt8 *)buffer, buffSize, NULL); + + String result(buffer, buffSize); + + delete[] buffer; + CFRelease(stringRef); + + return result; } -String -OSXClipboardHTMLConverter::doFromIClipboard(const String& data) const -{ +String OSXClipboardHTMLConverter::doFromIClipboard(const String &data) const { + return data; +} + +String OSXClipboardHTMLConverter::doToIClipboard(const String &data) const { + if (Unicode::isUTF8(data)) { return data; -} - -String -OSXClipboardHTMLConverter::doToIClipboard(const String& data) const -{ - if (Unicode::isUTF8(data)) - { - return data; - } - else - { - return convertString(data, CFStringGetSystemEncoding(), kCFStringEncodingUTF8); - } + } else { + return convertString(data, CFStringGetSystemEncoding(), + kCFStringEncodingUTF8); + } } diff --git a/src/lib/platform/OSXClipboardHTMLConverter.h b/src/lib/platform/OSXClipboardHTMLConverter.h index 058f0d89d..d3df617f1 100644 --- a/src/lib/platform/OSXClipboardHTMLConverter.h +++ b/src/lib/platform/OSXClipboardHTMLConverter.h @@ -23,22 +23,20 @@ //! Convert to/from HTML encoding class OSXClipboardHTMLConverter : public OSXClipboardAnyTextConverter { public: - OSXClipboardHTMLConverter(); - virtual ~OSXClipboardHTMLConverter(); + OSXClipboardHTMLConverter(); + virtual ~OSXClipboardHTMLConverter(); - // IMSWindowsClipboardConverter overrides - virtual IClipboard::EFormat - getFormat() const; + // IMSWindowsClipboardConverter overrides + virtual IClipboard::EFormat getFormat() const; - virtual CFStringRef getOSXFormat() const; + virtual CFStringRef getOSXFormat() const; protected: - // OSXClipboardAnyTextConverter overrides - virtual String doFromIClipboard(const String&) const; - virtual String doToIClipboard(const String&) const; + // OSXClipboardAnyTextConverter overrides + virtual String doFromIClipboard(const String &) const; + virtual String doToIClipboard(const String &) const; - // generic encoding converter - static String convertString(const String& data, - CFStringEncoding fromEncoding, - CFStringEncoding toEncoding); + // generic encoding converter + static String convertString(const String &data, CFStringEncoding fromEncoding, + CFStringEncoding toEncoding); }; diff --git a/src/lib/platform/OSXClipboardTextConverter.cpp b/src/lib/platform/OSXClipboardTextConverter.cpp index 4c8bf66fb..4b3bd804e 100644 --- a/src/lib/platform/OSXClipboardTextConverter.cpp +++ b/src/lib/platform/OSXClipboardTextConverter.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 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 LICENSE 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 @@ -24,70 +24,58 @@ // OSXClipboardTextConverter // -OSXClipboardTextConverter::OSXClipboardTextConverter() -{ - // do nothing +OSXClipboardTextConverter::OSXClipboardTextConverter() { + // do nothing } -OSXClipboardTextConverter::~OSXClipboardTextConverter() -{ - // do nothing +OSXClipboardTextConverter::~OSXClipboardTextConverter() { + // do nothing } -CFStringRef -OSXClipboardTextConverter::getOSXFormat() const -{ - return CFSTR("public.plain-text"); +CFStringRef OSXClipboardTextConverter::getOSXFormat() const { + return CFSTR("public.plain-text"); } -String -OSXClipboardTextConverter::convertString( - const String& data, - CFStringEncoding fromEncoding, - CFStringEncoding toEncoding) -{ - CFStringRef stringRef = - CFStringCreateWithCString(kCFAllocatorDefault, - data.c_str(), fromEncoding); +String OSXClipboardTextConverter::convertString(const String &data, + CFStringEncoding fromEncoding, + CFStringEncoding toEncoding) { + CFStringRef stringRef = CFStringCreateWithCString(kCFAllocatorDefault, + data.c_str(), fromEncoding); - if (stringRef == NULL) { - return String(); - } + if (stringRef == NULL) { + return String(); + } - CFIndex buffSize; - CFRange entireString = CFRangeMake(0, CFStringGetLength(stringRef)); + CFIndex buffSize; + CFRange entireString = CFRangeMake(0, CFStringGetLength(stringRef)); - CFStringGetBytes(stringRef, entireString, toEncoding, - 0, false, NULL, 0, &buffSize); + CFStringGetBytes(stringRef, entireString, toEncoding, 0, false, NULL, 0, + &buffSize); - char* buffer = new char[buffSize]; - - if (buffer == NULL) { - CFRelease(stringRef); - return String(); - } - - CFStringGetBytes(stringRef, entireString, toEncoding, - 0, false, (UInt8*)buffer, buffSize, NULL); + char *buffer = new char[buffSize]; - String result(buffer, buffSize); - - delete[] buffer; + if (buffer == NULL) { CFRelease(stringRef); - - return result; + return String(); + } + + CFStringGetBytes(stringRef, entireString, toEncoding, 0, false, + (UInt8 *)buffer, buffSize, NULL); + + String result(buffer, buffSize); + + delete[] buffer; + CFRelease(stringRef); + + return result; } -String -OSXClipboardTextConverter::doFromIClipboard(const String& data) const -{ - return convertString(data, kCFStringEncodingUTF8, - CFStringGetSystemEncoding()); +String OSXClipboardTextConverter::doFromIClipboard(const String &data) const { + return convertString(data, kCFStringEncodingUTF8, + CFStringGetSystemEncoding()); } -String -OSXClipboardTextConverter::doToIClipboard(const String& data) const -{ - return convertString(data, CFStringGetSystemEncoding(), - kCFStringEncodingUTF8); +String OSXClipboardTextConverter::doToIClipboard(const String &data) const { + return convertString(data, CFStringGetSystemEncoding(), + kCFStringEncodingUTF8); } diff --git a/src/lib/platform/OSXClipboardTextConverter.h b/src/lib/platform/OSXClipboardTextConverter.h index fd4f5c223..d4adc6560 100644 --- a/src/lib/platform/OSXClipboardTextConverter.h +++ b/src/lib/platform/OSXClipboardTextConverter.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 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 LICENSE 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 @@ -23,20 +23,18 @@ //! Convert to/from locale text encoding class OSXClipboardTextConverter : public OSXClipboardAnyTextConverter { public: - OSXClipboardTextConverter(); - virtual ~OSXClipboardTextConverter(); + OSXClipboardTextConverter(); + virtual ~OSXClipboardTextConverter(); - // IOSXClipboardAnyTextConverter overrides - virtual CFStringRef - getOSXFormat() const; + // IOSXClipboardAnyTextConverter overrides + virtual CFStringRef getOSXFormat() const; protected: - // OSXClipboardAnyTextConverter overrides - virtual String doFromIClipboard(const String&) const; - virtual String doToIClipboard(const String&) const; + // OSXClipboardAnyTextConverter overrides + virtual String doFromIClipboard(const String &) const; + virtual String doToIClipboard(const String &) const; - // generic encoding converter - static String convertString(const String& data, - CFStringEncoding fromEncoding, - CFStringEncoding toEncoding); + // generic encoding converter + static String convertString(const String &data, CFStringEncoding fromEncoding, + CFStringEncoding toEncoding); }; diff --git a/src/lib/platform/OSXClipboardUTF16Converter.cpp b/src/lib/platform/OSXClipboardUTF16Converter.cpp index d2f07c276..cce024d08 100644 --- a/src/lib/platform/OSXClipboardUTF16Converter.cpp +++ b/src/lib/platform/OSXClipboardUTF16Converter.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 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 LICENSE 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 @@ -24,32 +24,24 @@ // OSXClipboardUTF16Converter // -OSXClipboardUTF16Converter::OSXClipboardUTF16Converter() -{ - // do nothing +OSXClipboardUTF16Converter::OSXClipboardUTF16Converter() { + // do nothing } -OSXClipboardUTF16Converter::~OSXClipboardUTF16Converter() -{ - // do nothing +OSXClipboardUTF16Converter::~OSXClipboardUTF16Converter() { + // do nothing } -CFStringRef -OSXClipboardUTF16Converter::getOSXFormat() const -{ - return CFSTR("public.utf16-plain-text"); +CFStringRef OSXClipboardUTF16Converter::getOSXFormat() const { + return CFSTR("public.utf16-plain-text"); } -String -OSXClipboardUTF16Converter::doFromIClipboard(const String& data) const -{ - // convert and add nul terminator - return Unicode::UTF8ToUTF16(data); +String OSXClipboardUTF16Converter::doFromIClipboard(const String &data) const { + // convert and add nul terminator + return Unicode::UTF8ToUTF16(data); } -String -OSXClipboardUTF16Converter::doToIClipboard(const String& data) const -{ - // convert and strip nul terminator - return Unicode::UTF16ToUTF8(data); +String OSXClipboardUTF16Converter::doToIClipboard(const String &data) const { + // convert and strip nul terminator + return Unicode::UTF16ToUTF8(data); } diff --git a/src/lib/platform/OSXClipboardUTF16Converter.h b/src/lib/platform/OSXClipboardUTF16Converter.h index da52f1eaf..63810fc1b 100644 --- a/src/lib/platform/OSXClipboardUTF16Converter.h +++ b/src/lib/platform/OSXClipboardUTF16Converter.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 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 LICENSE 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 @@ -23,15 +23,14 @@ //! Convert to/from UTF-16 encoding class OSXClipboardUTF16Converter : public OSXClipboardAnyTextConverter { public: - OSXClipboardUTF16Converter(); - virtual ~OSXClipboardUTF16Converter(); + OSXClipboardUTF16Converter(); + virtual ~OSXClipboardUTF16Converter(); - // IOSXClipboardAnyTextConverter overrides - virtual CFStringRef - getOSXFormat() const; + // IOSXClipboardAnyTextConverter overrides + virtual CFStringRef getOSXFormat() const; protected: - // OSXClipboardAnyTextConverter overrides - virtual String doFromIClipboard(const String&) const; - virtual String doToIClipboard(const String&) const; + // OSXClipboardAnyTextConverter overrides + virtual String doFromIClipboard(const String &) const; + virtual String doToIClipboard(const String &) const; }; diff --git a/src/lib/platform/OSXClipboardUTF8Converter.cpp b/src/lib/platform/OSXClipboardUTF8Converter.cpp index ca6f5684a..e5abf1a81 100644 --- a/src/lib/platform/OSXClipboardUTF8Converter.cpp +++ b/src/lib/platform/OSXClipboardUTF8Converter.cpp @@ -1,19 +1,13 @@ #include "OSXClipboardUTF8Converter.h" -CFStringRef -OSXClipboardUTF8Converter::getOSXFormat() const -{ - return CFSTR("public.utf8-plain-text"); +CFStringRef OSXClipboardUTF8Converter::getOSXFormat() const { + return CFSTR("public.utf8-plain-text"); } -String -OSXClipboardUTF8Converter::doFromIClipboard(const String& data) const -{ - return data; +String OSXClipboardUTF8Converter::doFromIClipboard(const String &data) const { + return data; } -String -OSXClipboardUTF8Converter::doToIClipboard(const String& data) const -{ - return data; +String OSXClipboardUTF8Converter::doToIClipboard(const String &data) const { + return data; } diff --git a/src/lib/platform/OSXClipboardUTF8Converter.h b/src/lib/platform/OSXClipboardUTF8Converter.h index 29e0a8a3f..cc3373178 100644 --- a/src/lib/platform/OSXClipboardUTF8Converter.h +++ b/src/lib/platform/OSXClipboardUTF8Converter.h @@ -19,12 +19,11 @@ #include "platform/OSXClipboardAnyTextConverter.h" -class OSXClipboardUTF8Converter : public OSXClipboardAnyTextConverter -{ +class OSXClipboardUTF8Converter : public OSXClipboardAnyTextConverter { public: - virtual CFStringRef getOSXFormat() const; -private: - virtual String doFromIClipboard(const String&) const; - virtual String doToIClipboard(const String&) const; -}; + virtual CFStringRef getOSXFormat() const; +private: + virtual String doFromIClipboard(const String &) const; + virtual String doToIClipboard(const String &) const; +}; diff --git a/src/lib/platform/OSXDragSimulator.h b/src/lib/platform/OSXDragSimulator.h index 148fca041..71b001ebe 100644 --- a/src/lib/platform/OSXDragSimulator.h +++ b/src/lib/platform/OSXDragSimulator.h @@ -24,11 +24,11 @@ #if defined(__cplusplus) extern "C" { #endif -void runCocoaApp(); -void stopCocoaLoop(); -void fakeDragging(const char* str, int cursorX, int cursorY); -CFStringRef getCocoaDropTarget(); - +void runCocoaApp(); +void stopCocoaLoop(); +void fakeDragging(const char *str, int cursorX, int cursorY); +CFStringRef getCocoaDropTarget(); + #if defined(__cplusplus) } #endif diff --git a/src/lib/platform/OSXDragView.h b/src/lib/platform/OSXDragView.h index 9e706c58e..15c073d74 100644 --- a/src/lib/platform/OSXDragView.h +++ b/src/lib/platform/OSXDragView.h @@ -19,15 +19,14 @@ #ifdef MAC_OS_X_VERSION_10_7 -@interface OSXDragView : NSView -{ - NSMutableString* m_dropTarget; - NSString* m_dragFileExt; +@interface OSXDragView : NSView { + NSMutableString *m_dropTarget; + NSString *m_dragFileExt; } - (CFStringRef)getDropTarget; - (void)clearDropTarget; -- (void)setFileExt:(NSString*) ext; +- (void)setFileExt:(NSString *)ext; @end diff --git a/src/lib/platform/OSXEventQueueBuffer.cpp b/src/lib/platform/OSXEventQueueBuffer.cpp index 2a5bd2200..3452c4371 100644 --- a/src/lib/platform/OSXEventQueueBuffer.cpp +++ b/src/lib/platform/OSXEventQueueBuffer.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 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 LICENSE 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 @@ -25,119 +25,91 @@ // EventQueueTimer // -class EventQueueTimer { }; +class EventQueueTimer {}; // // OSXEventQueueBuffer // -OSXEventQueueBuffer::OSXEventQueueBuffer(IEventQueue* events) : - m_event(NULL), - m_eventQueue(events), - m_carbonEventQueue(NULL) -{ - // do nothing +OSXEventQueueBuffer::OSXEventQueueBuffer(IEventQueue *events) + : m_event(NULL), m_eventQueue(events), m_carbonEventQueue(NULL) { + // do nothing } -OSXEventQueueBuffer::~OSXEventQueueBuffer() -{ - // release the last event - if (m_event != NULL) { - ReleaseEvent(m_event); +OSXEventQueueBuffer::~OSXEventQueueBuffer() { + // release the last event + if (m_event != NULL) { + ReleaseEvent(m_event); + } +} + +void OSXEventQueueBuffer::init() { + m_carbonEventQueue = GetCurrentEventQueue(); +} + +void OSXEventQueueBuffer::waitForEvent(double timeout) { + EventRef event; + ReceiveNextEvent(0, NULL, timeout, false, &event); +} + +IEventQueueBuffer::Type OSXEventQueueBuffer::getEvent(Event &event, + UInt32 &dataID) { + // release the previous event + if (m_event != NULL) { + ReleaseEvent(m_event); + m_event = NULL; + } + + // get the next event + OSStatus error = ReceiveNextEvent(0, NULL, 0.0, true, &m_event); + + // handle the event + if (error == eventLoopQuitErr) { + event = Event(Event::kQuit); + return kSystem; + } else if (error != noErr) { + return kNone; + } else { + UInt32 eventClass = GetEventClass(m_event); + switch (eventClass) { + case 'Syne': + dataID = GetEventKind(m_event); + return kUser; + + default: + event = Event(Event::kSystem, m_eventQueue->getSystemTarget(), &m_event); + return kSystem; } + } } -void -OSXEventQueueBuffer::init() -{ - m_carbonEventQueue = GetCurrentEventQueue(); +bool OSXEventQueueBuffer::addEvent(UInt32 dataID) { + EventRef event; + OSStatus error = CreateEvent(kCFAllocatorDefault, 'Syne', dataID, 0, + kEventAttributeNone, &event); + + if (error == noErr) { + + assert(m_carbonEventQueue != NULL); + + error = PostEventToQueue(m_carbonEventQueue, event, kEventPriorityStandard); + + ReleaseEvent(event); + } + + return (error == noErr); } -void -OSXEventQueueBuffer::waitForEvent(double timeout) -{ - EventRef event; - ReceiveNextEvent(0, NULL, timeout, false, &event); +bool OSXEventQueueBuffer::isEmpty() const { + EventRef event; + OSStatus status = ReceiveNextEvent(0, NULL, 0.0, false, &event); + return (status == eventLoopTimedOutErr); } -IEventQueueBuffer::Type -OSXEventQueueBuffer::getEvent(Event& event, UInt32& dataID) -{ - // release the previous event - if (m_event != NULL) { - ReleaseEvent(m_event); - m_event = NULL; - } - - // get the next event - OSStatus error = ReceiveNextEvent(0, NULL, 0.0, true, &m_event); - - // handle the event - if (error == eventLoopQuitErr) { - event = Event(Event::kQuit); - return kSystem; - } - else if (error != noErr) { - return kNone; - } - else { - UInt32 eventClass = GetEventClass(m_event); - switch (eventClass) { - case 'Syne': - dataID = GetEventKind(m_event); - return kUser; - - default: - event = Event(Event::kSystem, - m_eventQueue->getSystemTarget(), &m_event); - return kSystem; - } - } +EventQueueTimer *OSXEventQueueBuffer::newTimer(double, bool) const { + return new EventQueueTimer; } -bool -OSXEventQueueBuffer::addEvent(UInt32 dataID) -{ - EventRef event; - OSStatus error = CreateEvent( - kCFAllocatorDefault, - 'Syne', - dataID, - 0, - kEventAttributeNone, - &event); - - if (error == noErr) { - - assert(m_carbonEventQueue != NULL); - - error = PostEventToQueue( - m_carbonEventQueue, - event, - kEventPriorityStandard); - - ReleaseEvent(event); - } - - return (error == noErr); -} - -bool -OSXEventQueueBuffer::isEmpty() const -{ - EventRef event; - OSStatus status = ReceiveNextEvent(0, NULL, 0.0, false, &event); - return (status == eventLoopTimedOutErr); -} - -EventQueueTimer* -OSXEventQueueBuffer::newTimer(double, bool) const -{ - return new EventQueueTimer; -} - -void -OSXEventQueueBuffer::deleteTimer(EventQueueTimer* timer) const -{ - delete timer; +void OSXEventQueueBuffer::deleteTimer(EventQueueTimer *timer) const { + delete timer; } diff --git a/src/lib/platform/OSXEventQueueBuffer.h b/src/lib/platform/OSXEventQueueBuffer.h index d2e46b8b1..b0ea0d796 100644 --- a/src/lib/platform/OSXEventQueueBuffer.h +++ b/src/lib/platform/OSXEventQueueBuffer.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 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 LICENSE 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 @@ -27,21 +27,20 @@ class IEventQueue; //! Event queue buffer for OS X class OSXEventQueueBuffer : public IEventQueueBuffer { public: - OSXEventQueueBuffer(IEventQueue* eventQueue); - virtual ~OSXEventQueueBuffer(); + OSXEventQueueBuffer(IEventQueue *eventQueue); + virtual ~OSXEventQueueBuffer(); - // IEventQueueBuffer overrides - virtual void init(); - virtual void waitForEvent(double timeout); - virtual Type getEvent(Event& event, UInt32& dataID); - virtual bool addEvent(UInt32 dataID); - virtual bool isEmpty() const; - virtual EventQueueTimer* - newTimer(double duration, bool oneShot) const; - virtual void deleteTimer(EventQueueTimer*) const; + // IEventQueueBuffer overrides + virtual void init(); + virtual void waitForEvent(double timeout); + virtual Type getEvent(Event &event, UInt32 &dataID); + virtual bool addEvent(UInt32 dataID); + virtual bool isEmpty() const; + virtual EventQueueTimer *newTimer(double duration, bool oneShot) const; + virtual void deleteTimer(EventQueueTimer *) const; private: - EventRef m_event; - IEventQueue* m_eventQueue; - EventQueueRef m_carbonEventQueue; + EventRef m_event; + IEventQueue *m_eventQueue; + EventQueueRef m_carbonEventQueue; }; diff --git a/src/lib/platform/OSXKeyState.cpp b/src/lib/platform/OSXKeyState.cpp index 10c69b615..d20c5f6da 100644 --- a/src/lib/platform/OSXKeyState.cpp +++ b/src/lib/platform/OSXKeyState.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 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 LICENSE 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 @@ -17,10 +17,10 @@ */ #include "platform/OSXKeyState.h" -#include "platform/OSXUchrKeyResource.h" -#include "platform/OSXMediaKeySupport.h" #include "arch/Arch.h" #include "base/Log.h" +#include "platform/OSXMediaKeySupport.h" +#include "platform/OSXUchrKeyResource.h" #include #include @@ -29,12 +29,12 @@ // first instance of a virtual key code maps to the KeyID that we // want to generate for that code. The others are for mapping // different KeyIDs to a single key code. -static const UInt32 s_shiftVK = kVK_Shift; -static const UInt32 s_controlVK = kVK_Control; -static const UInt32 s_altVK = kVK_Option; -static const UInt32 s_superVK = kVK_Command; +static const UInt32 s_shiftVK = kVK_Shift; +static const UInt32 s_controlVK = kVK_Control; +static const UInt32 s_altVK = kVK_Option; +static const UInt32 s_superVK = kVK_Command; static const UInt32 s_capsLockVK = kVK_CapsLock; -static const UInt32 s_numLockVK = kVK_ANSI_KeypadClear; // 71 +static const UInt32 s_numLockVK = kVK_ANSI_KeypadClear; // 71 static const UInt32 s_brightnessUp = 144; static const UInt32 s_brightnessDown = 145; @@ -45,945 +45,882 @@ static const UInt32 s_osxNumLock = 1 << 16; struct KeyEntry { public: - KeyID m_keyID; - UInt32 m_virtualKey; + KeyID m_keyID; + UInt32 m_virtualKey; }; -static const KeyEntry s_controlKeys[] = { +static const KeyEntry s_controlKeys[] = { // cursor keys. if we don't do this we'll may still get these from // the keyboard resource but they may not correspond to the arrow // keys. - { kKeyLeft, kVK_LeftArrow }, - { kKeyRight, kVK_RightArrow }, - { kKeyUp, kVK_UpArrow }, - { kKeyDown, kVK_DownArrow }, - { kKeyHome, kVK_Home }, - { kKeyEnd, kVK_End }, - { kKeyPageUp, kVK_PageUp }, - { kKeyPageDown, kVK_PageDown }, - { kKeyInsert, kVK_Help }, // Mac Keyboards have 'Help' on 'Insert' + {kKeyLeft, kVK_LeftArrow}, + {kKeyRight, kVK_RightArrow}, + {kKeyUp, kVK_UpArrow}, + {kKeyDown, kVK_DownArrow}, + {kKeyHome, kVK_Home}, + {kKeyEnd, kVK_End}, + {kKeyPageUp, kVK_PageUp}, + {kKeyPageDown, kVK_PageDown}, + {kKeyInsert, kVK_Help}, // Mac Keyboards have 'Help' on 'Insert' // function keys - { kKeyF1, kVK_F1 }, - { kKeyF2, kVK_F2 }, - { kKeyF3, kVK_F3 }, - { kKeyF4, kVK_F4 }, - { kKeyF5, kVK_F5 }, - { kKeyF6, kVK_F6 }, - { kKeyF7, kVK_F7 }, - { kKeyF8, kVK_F8 }, - { kKeyF9, kVK_F9 }, - { kKeyF10, kVK_F10 }, - { kKeyF11, kVK_F11 }, - { kKeyF12, kVK_F12 }, - { kKeyF13, kVK_F13 }, - { kKeyF14, kVK_F14 }, - { kKeyF15, kVK_F15 }, - { kKeyF16, kVK_F16 }, + {kKeyF1, kVK_F1}, + {kKeyF2, kVK_F2}, + {kKeyF3, kVK_F3}, + {kKeyF4, kVK_F4}, + {kKeyF5, kVK_F5}, + {kKeyF6, kVK_F6}, + {kKeyF7, kVK_F7}, + {kKeyF8, kVK_F8}, + {kKeyF9, kVK_F9}, + {kKeyF10, kVK_F10}, + {kKeyF11, kVK_F11}, + {kKeyF12, kVK_F12}, + {kKeyF13, kVK_F13}, + {kKeyF14, kVK_F14}, + {kKeyF15, kVK_F15}, + {kKeyF16, kVK_F16}, + + {kKeyKP_0, kVK_ANSI_Keypad0}, + {kKeyKP_1, kVK_ANSI_Keypad1}, + {kKeyKP_2, kVK_ANSI_Keypad2}, + {kKeyKP_3, kVK_ANSI_Keypad3}, + {kKeyKP_4, kVK_ANSI_Keypad4}, + {kKeyKP_5, kVK_ANSI_Keypad5}, + {kKeyKP_6, kVK_ANSI_Keypad6}, + {kKeyKP_7, kVK_ANSI_Keypad7}, + {kKeyKP_8, kVK_ANSI_Keypad8}, + {kKeyKP_9, kVK_ANSI_Keypad9}, + {kKeyKP_Decimal, kVK_ANSI_KeypadDecimal}, + {kKeyKP_Equal, kVK_ANSI_KeypadEquals}, + {kKeyKP_Multiply, kVK_ANSI_KeypadMultiply}, + {kKeyKP_Add, kVK_ANSI_KeypadPlus}, + {kKeyKP_Divide, kVK_ANSI_KeypadDivide}, + {kKeyKP_Subtract, kVK_ANSI_KeypadMinus}, + {kKeyKP_Enter, kVK_ANSI_KeypadEnter}, - { kKeyKP_0, kVK_ANSI_Keypad0 }, - { kKeyKP_1, kVK_ANSI_Keypad1 }, - { kKeyKP_2, kVK_ANSI_Keypad2 }, - { kKeyKP_3, kVK_ANSI_Keypad3 }, - { kKeyKP_4, kVK_ANSI_Keypad4 }, - { kKeyKP_5, kVK_ANSI_Keypad5 }, - { kKeyKP_6, kVK_ANSI_Keypad6 }, - { kKeyKP_7, kVK_ANSI_Keypad7 }, - { kKeyKP_8, kVK_ANSI_Keypad8 }, - { kKeyKP_9, kVK_ANSI_Keypad9 }, - { kKeyKP_Decimal, kVK_ANSI_KeypadDecimal }, - { kKeyKP_Equal, kVK_ANSI_KeypadEquals }, - { kKeyKP_Multiply, kVK_ANSI_KeypadMultiply }, - { kKeyKP_Add, kVK_ANSI_KeypadPlus }, - { kKeyKP_Divide, kVK_ANSI_KeypadDivide }, - { kKeyKP_Subtract, kVK_ANSI_KeypadMinus }, - { kKeyKP_Enter, kVK_ANSI_KeypadEnter }, - // virtual key 110 is fn+enter and i have no idea what that's supposed // to map to. also the enter key with numlock on is a modifier but i // don't know which. // modifier keys. OS X doesn't seem to support right handed versions // of modifier keys so we map them to the left handed versions. - { kKeyShift_L, s_shiftVK }, - { kKeyShift_R, s_shiftVK }, // 60 - { kKeyControl_L, s_controlVK }, - { kKeyControl_R, s_controlVK }, // 62 - { kKeyAlt_L, s_altVK }, - { kKeyAlt_R, s_altVK }, - { kKeySuper_L, s_superVK }, - { kKeySuper_R, s_superVK }, // 61 - { kKeyMeta_L, s_superVK }, - { kKeyMeta_R, s_superVK }, // 61 + {kKeyShift_L, s_shiftVK}, + {kKeyShift_R, s_shiftVK}, // 60 + {kKeyControl_L, s_controlVK}, + {kKeyControl_R, s_controlVK}, // 62 + {kKeyAlt_L, s_altVK}, + {kKeyAlt_R, s_altVK}, + {kKeySuper_L, s_superVK}, + {kKeySuper_R, s_superVK}, // 61 + {kKeyMeta_L, s_superVK}, + {kKeyMeta_R, s_superVK}, // 61 // toggle modifiers - { kKeyNumLock, s_numLockVK }, - { kKeyCapsLock, s_capsLockVK }, + {kKeyNumLock, s_numLockVK}, + {kKeyCapsLock, s_capsLockVK}, - // for Apple Pro JIS Keyboard, map Kana (IME activate) to Henkan (show next IME conversion), and - // Eisu (IME deactivate) to Zenkaku (IME activation toggle) on Windows Japanese keyboard (OADG109A) - { kKeyHenkan, kVK_JIS_Kana }, - { kKeyZenkaku, kVK_JIS_Eisu }, - - { kKeyMissionControl, s_missionControlVK }, - { kKeyLaunchpad, s_launchpadVK }, - { kKeyBrightnessUp, s_brightnessUp }, - { kKeyBrightnessDown, s_brightnessDown } -}; + // for Apple Pro JIS Keyboard, map Kana (IME activate) to Henkan (show next + // IME conversion), and + // Eisu (IME deactivate) to Zenkaku (IME activation toggle) on Windows + // Japanese keyboard (OADG109A) + {kKeyHenkan, kVK_JIS_Kana}, + {kKeyZenkaku, kVK_JIS_Eisu}, + + {kKeyMissionControl, s_missionControlVK}, + {kKeyLaunchpad, s_launchpadVK}, + {kKeyBrightnessUp, s_brightnessUp}, + {kKeyBrightnessDown, s_brightnessDown}}; namespace { -io_connect_t -getService(io_iterator_t iter) { - io_connect_t service = 0; - auto nextIterator = IOIteratorNext(iter); +io_connect_t getService(io_iterator_t iter) { + io_connect_t service = 0; + auto nextIterator = IOIteratorNext(iter); - if (nextIterator) { - IOServiceOpen(nextIterator, mach_task_self(), kIOHIDParamConnectType, &service); - IOObjectRelease(nextIterator); + if (nextIterator) { + IOServiceOpen(nextIterator, mach_task_self(), kIOHIDParamConnectType, + &service); + IOObjectRelease(nextIterator); + } + + return service; +} + +io_connect_t getEventDriver() { + static io_connect_t sEventDrvrRef = 0; + + if (!sEventDrvrRef) { + // Get master device port + mach_port_t masterPort = 0; + if (!IOMasterPort(bootstrap_port, &masterPort)) { + io_iterator_t iter = 0; + auto dict = IOServiceMatching(kIOHIDSystemClass); + + if (!IOServiceGetMatchingServices(masterPort, dict, &iter)) { + sEventDrvrRef = getService(iter); + } else { + LOG((CLOG_WARN, "io service not found")); + } + + IOObjectRelease(iter); + } else { + LOG((CLOG_WARN, "couldn't get io master port")); } + } - return service; + return sEventDrvrRef; } -io_connect_t -getEventDriver() -{ - static io_connect_t sEventDrvrRef = 0; +bool isModifier(UInt8 virtualKey) { + static std::set modifiers{s_shiftVK, s_superVK, s_altVK, s_controlVK, + s_capsLockVK}; - if (!sEventDrvrRef) { - // Get master device port - mach_port_t masterPort = 0; - if (!IOMasterPort(bootstrap_port, &masterPort)) { - io_iterator_t iter = 0; - auto dict = IOServiceMatching(kIOHIDSystemClass); - - if (!IOServiceGetMatchingServices(masterPort, dict, &iter)) { - sEventDrvrRef = getService(iter); - } - else { - LOG((CLOG_WARN, "io service not found")); - } - - IOObjectRelease(iter); - } - else { - LOG((CLOG_WARN, "couldn't get io master port")); - } - } - - return sEventDrvrRef; + return (modifiers.find(virtualKey) != modifiers.end()); } -bool -isModifier(UInt8 virtualKey) { - static std::set modifiers { - s_shiftVK, - s_superVK, - s_altVK, - s_controlVK, - s_capsLockVK - }; - - return (modifiers.find(virtualKey) != modifiers.end()); -} - -} //namespace - +} // namespace // // OSXKeyState // -OSXKeyState::OSXKeyState(IEventQueue* events, std::vector layouts, bool isLangSyncEnabled) : - KeyState(events, std::move(layouts), isLangSyncEnabled) -{ - init(); +OSXKeyState::OSXKeyState(IEventQueue *events, std::vector layouts, + bool isLangSyncEnabled) + : KeyState(events, std::move(layouts), isLangSyncEnabled) { + init(); } -OSXKeyState::OSXKeyState(IEventQueue* events, synergy::KeyMap& keyMap, - std::vector layouts, bool isLangSyncEnabled) : - KeyState(events, keyMap, std::move(layouts), isLangSyncEnabled) -{ - init(); +OSXKeyState::OSXKeyState(IEventQueue *events, synergy::KeyMap &keyMap, + std::vector layouts, bool isLangSyncEnabled) + : KeyState(events, keyMap, std::move(layouts), isLangSyncEnabled) { + init(); } -OSXKeyState::~OSXKeyState() -{ +OSXKeyState::~OSXKeyState() {} + +void OSXKeyState::init() { + m_deadKeyState = 0; + m_shiftPressed = false; + m_controlPressed = false; + m_altPressed = false; + m_superPressed = false; + m_capsPressed = false; + + // build virtual key map + for (size_t i = 0; i < sizeof(s_controlKeys) / sizeof(s_controlKeys[0]); + ++i) { + + m_virtualKeyMap[s_controlKeys[i].m_virtualKey] = s_controlKeys[i].m_keyID; + } } -void -OSXKeyState::init() -{ +KeyModifierMask OSXKeyState::mapModifiersFromOSX(UInt32 mask) const { + KeyModifierMask outMask = 0; + if ((mask & kCGEventFlagMaskShift) != 0) { + outMask |= KeyModifierShift; + } + if ((mask & kCGEventFlagMaskControl) != 0) { + outMask |= KeyModifierControl; + } + if ((mask & kCGEventFlagMaskAlternate) != 0) { + outMask |= KeyModifierAlt; + } + if ((mask & kCGEventFlagMaskCommand) != 0) { + outMask |= KeyModifierSuper; + } + if ((mask & kCGEventFlagMaskAlphaShift) != 0) { + outMask |= KeyModifierCapsLock; + } + if ((mask & kCGEventFlagMaskNumericPad) != 0) { + outMask |= KeyModifierNumLock; + } + + LOG((CLOG_DEBUG1 "mask=%04x outMask=%04x", mask, outMask)); + return outMask; +} + +KeyModifierMask OSXKeyState::mapModifiersToCarbon(UInt32 mask) const { + KeyModifierMask outMask = 0; + if ((mask & kCGEventFlagMaskShift) != 0) { + outMask |= shiftKey; + } + if ((mask & kCGEventFlagMaskControl) != 0) { + outMask |= controlKey; + } + if ((mask & kCGEventFlagMaskCommand) != 0) { + outMask |= cmdKey; + } + if ((mask & kCGEventFlagMaskAlternate) != 0) { + outMask |= optionKey; + } + if ((mask & kCGEventFlagMaskAlphaShift) != 0) { + outMask |= alphaLock; + } + if ((mask & kCGEventFlagMaskNumericPad) != 0) { + outMask |= s_osxNumLock; + } + + return outMask; +} + +KeyButton OSXKeyState::mapKeyFromEvent(KeyIDs &ids, KeyModifierMask *maskOut, + CGEventRef event) const { + ids.clear(); + + // map modifier key + if (maskOut != NULL) { + KeyModifierMask activeMask = getActiveModifiers(); + activeMask &= ~KeyModifierAltGr; + *maskOut = activeMask; + } + + // get virtual key + UInt32 vkCode = CGEventGetIntegerValueField(event, kCGKeyboardEventKeycode); + + // handle up events + UInt32 eventKind = CGEventGetType(event); + if (eventKind == kCGEventKeyUp) { + // the id isn't used. we just need the same button we used on + // the key press. note that we don't use or reset the dead key + // state; up events should not affect the dead key state. + ids.push_back(kKeyNone); + return mapVirtualKeyToKeyButton(vkCode); + } + + // check for special keys + VirtualKeyMap::const_iterator i = m_virtualKeyMap.find(vkCode); + if (i != m_virtualKeyMap.end()) { m_deadKeyState = 0; - m_shiftPressed = false; - m_controlPressed = false; - m_altPressed = false; - m_superPressed = false; - m_capsPressed = false; + ids.push_back(i->second); + return mapVirtualKeyToKeyButton(vkCode); + } - // build virtual key map - for (size_t i = 0; i < sizeof(s_controlKeys) / sizeof(s_controlKeys[0]); - ++i) { - - m_virtualKeyMap[s_controlKeys[i].m_virtualKey] = - s_controlKeys[i].m_keyID; - } -} + // get keyboard info + AutoTISInputSourceRef currentKeyboardLayout( + TISCopyCurrentKeyboardLayoutInputSource(), CFRelease); -KeyModifierMask -OSXKeyState::mapModifiersFromOSX(UInt32 mask) const -{ - KeyModifierMask outMask = 0; - if ((mask & kCGEventFlagMaskShift) != 0) { - outMask |= KeyModifierShift; - } - if ((mask & kCGEventFlagMaskControl) != 0) { - outMask |= KeyModifierControl; - } - if ((mask & kCGEventFlagMaskAlternate) != 0) { - outMask |= KeyModifierAlt; - } - if ((mask & kCGEventFlagMaskCommand) != 0) { - outMask |= KeyModifierSuper; - } - if ((mask & kCGEventFlagMaskAlphaShift) != 0) { - outMask |= KeyModifierCapsLock; - } - if ((mask & kCGEventFlagMaskNumericPad) != 0) { - outMask |= KeyModifierNumLock; - } + if (!currentKeyboardLayout) { + return kKeyNone; + } - LOG((CLOG_DEBUG1 "mask=%04x outMask=%04x", mask, outMask)); - return outMask; -} + // get the event modifiers and remove the command and control + // keys. note if we used them though. + // UCKeyTranslate expects old-style Carbon modifiers, so convert. + UInt32 modifiers; + modifiers = mapModifiersToCarbon(CGEventGetFlags(event)); + static const UInt32 s_commandModifiers = + cmdKey | controlKey | rightControlKey; + bool isCommand = ((modifiers & s_commandModifiers) != 0); + modifiers &= ~s_commandModifiers; -KeyModifierMask -OSXKeyState::mapModifiersToCarbon(UInt32 mask) const -{ - KeyModifierMask outMask = 0; - if ((mask & kCGEventFlagMaskShift) != 0) { - outMask |= shiftKey; - } - if ((mask & kCGEventFlagMaskControl) != 0) { - outMask |= controlKey; - } - if ((mask & kCGEventFlagMaskCommand) != 0) { - outMask |= cmdKey; - } - if ((mask & kCGEventFlagMaskAlternate) != 0) { - outMask |= optionKey; - } - if ((mask & kCGEventFlagMaskAlphaShift) != 0) { - outMask |= alphaLock; - } - if ((mask & kCGEventFlagMaskNumericPad) != 0) { - outMask |= s_osxNumLock; - } - - return outMask; -} + // if we've used a command key then we want the glyph produced without + // the option key (i.e. the base glyph). + // if (isCommand) { + modifiers &= ~optionKey; + //} -KeyButton -OSXKeyState::mapKeyFromEvent(KeyIDs& ids, - KeyModifierMask* maskOut, CGEventRef event) const -{ - ids.clear(); + // choose action + UInt16 action; + if (eventKind == kCGEventKeyDown) { + action = kUCKeyActionDown; + } else if (CGEventGetIntegerValueField(event, kCGKeyboardEventAutorepeat) == + 1) { + action = kUCKeyActionAutoKey; + } else { + return 0; + } - // map modifier key - if (maskOut != NULL) { - KeyModifierMask activeMask = getActiveModifiers(); - activeMask &= ~KeyModifierAltGr; - *maskOut = activeMask; - } + // translate via uchr resource + CFDataRef ref = (CFDataRef)TISGetInputSourceProperty( + currentKeyboardLayout.get(), kTISPropertyUnicodeKeyLayoutData); + const UCKeyboardLayout *layout = + (const UCKeyboardLayout *)CFDataGetBytePtr(ref); + const bool layoutValid = (layout != NULL); - // get virtual key - UInt32 vkCode = CGEventGetIntegerValueField(event, kCGKeyboardEventKeycode); + if (layoutValid) { + // translate key + UniCharCount count; + UniChar chars[2]; + LOG((CLOG_DEBUG2 "modifiers: %08x", modifiers & 0xffu)); + OSStatus status = + UCKeyTranslate(layout, vkCode & 0xffu, action, (modifiers >> 8) & 0xffu, + LMGetKbdType(), 0, &m_deadKeyState, + sizeof(chars) / sizeof(chars[0]), &count, chars); - // handle up events - UInt32 eventKind = CGEventGetType(event); - if (eventKind == kCGEventKeyUp) { - // the id isn't used. we just need the same button we used on - // the key press. note that we don't use or reset the dead key - // state; up events should not affect the dead key state. - ids.push_back(kKeyNone); - return mapVirtualKeyToKeyButton(vkCode); - } - - // check for special keys - VirtualKeyMap::const_iterator i = m_virtualKeyMap.find(vkCode); - if (i != m_virtualKeyMap.end()) { + // get the characters + if (status == 0) { + if (count != 0 || m_deadKeyState == 0) { m_deadKeyState = 0; - ids.push_back(i->second); + for (UniCharCount i = 0; i < count; ++i) { + ids.push_back(IOSXKeyResource::unicharToKeyID(chars[i])); + } + adjustAltGrModifier(ids, maskOut, isCommand); return mapVirtualKeyToKeyButton(vkCode); + } + return 0; } + } - // get keyboard info - AutoTISInputSourceRef currentKeyboardLayout(TISCopyCurrentKeyboardLayoutInputSource(), CFRelease); + return 0; +} - if (!currentKeyboardLayout) { - return kKeyNone; +bool OSXKeyState::fakeCtrlAltDel() { + // pass keys through unchanged + return false; +} + +bool OSXKeyState::fakeMediaKey(KeyID id) { return fakeNativeMediaKey(id); } + +CGEventFlags OSXKeyState::getModifierStateAsOSXFlags() const { + CGEventFlags modifiers = 0; + + if (m_shiftPressed) { + modifiers |= kCGEventFlagMaskShift; + } + + if (m_controlPressed) { + modifiers |= kCGEventFlagMaskControl; + } + + if (m_altPressed) { + modifiers |= kCGEventFlagMaskAlternate; + } + + if (m_superPressed) { + modifiers |= kCGEventFlagMaskCommand; + } + + if (m_capsPressed) { + modifiers |= kCGEventFlagMaskAlphaShift; + } + + return modifiers; +} + +KeyModifierMask OSXKeyState::pollActiveModifiers() const { + // falsely assumed that the mask returned by GetCurrentKeyModifiers() + // was the same as a CGEventFlags (which is what mapModifiersFromOSX + // expects). patch by Marc + UInt32 mask = GetCurrentKeyModifiers(); + KeyModifierMask outMask = 0; + + if ((mask & shiftKey) != 0) { + outMask |= KeyModifierShift; + } + if ((mask & controlKey) != 0) { + outMask |= KeyModifierControl; + } + if ((mask & optionKey) != 0) { + outMask |= KeyModifierAlt; + } + if ((mask & cmdKey) != 0) { + outMask |= KeyModifierSuper; + } + if ((mask & alphaLock) != 0) { + outMask |= KeyModifierCapsLock; + } + if ((mask & s_osxNumLock) != 0) { + outMask |= KeyModifierNumLock; + } + + LOG((CLOG_DEBUG1 "mask=%04x outMask=%04x", mask, outMask)); + return outMask; +} + +SInt32 OSXKeyState::pollActiveGroup() const { + AutoTISInputSourceRef keyboardLayout( + TISCopyCurrentKeyboardLayoutInputSource(), CFRelease); + CFDataRef id = (CFDataRef)TISGetInputSourceProperty( + keyboardLayout.get(), kTISPropertyInputSourceID); + + GroupMap::const_iterator i = m_groupMap.find(id); + if (i != m_groupMap.end()) { + return i->second; + } + + LOG((CLOG_WARN "can't get the active group, use the first group instead")); + + return 0; +} + +void OSXKeyState::pollPressedKeys(KeyButtonSet &pressedKeys) const { + ::KeyMap km; + GetKeys(km); + const UInt8 *m = reinterpret_cast(km); + for (UInt32 i = 0; i < 16; ++i) { + for (UInt32 j = 0; j < 8; ++j) { + if ((m[i] & (1u << j)) != 0) { + pressedKeys.insert(mapVirtualKeyToKeyButton(8 * i + j)); + } } + } +} - // get the event modifiers and remove the command and control - // keys. note if we used them though. - // UCKeyTranslate expects old-style Carbon modifiers, so convert. - UInt32 modifiers; - modifiers = mapModifiersToCarbon(CGEventGetFlags(event)); - static const UInt32 s_commandModifiers = - cmdKey | controlKey | rightControlKey; - bool isCommand = ((modifiers & s_commandModifiers) != 0); - modifiers &= ~s_commandModifiers; - - // if we've used a command key then we want the glyph produced without - // the option key (i.e. the base glyph). - //if (isCommand) { - modifiers &= ~optionKey; - //} - - // choose action - UInt16 action; - if (eventKind==kCGEventKeyDown) { - action = kUCKeyActionDown; - } - else if (CGEventGetIntegerValueField(event, kCGKeyboardEventAutorepeat)==1) { - action = kUCKeyActionAutoKey; - } - else { - return 0; +void OSXKeyState::getKeyMap(synergy::KeyMap &keyMap) { + // update keyboard groups + SInt32 numGroups{0}; + if (getGroups(m_groups)) { + m_groupMap.clear(); + numGroups = CFArrayGetCount(m_groups.get()); + for (SInt32 g = 0; g < numGroups; ++g) { + TISInputSourceRef keyboardLayout = + (TISInputSourceRef)CFArrayGetValueAtIndex(m_groups.get(), g); + CFDataRef id = (CFDataRef)TISGetInputSourceProperty( + keyboardLayout, kTISPropertyInputSourceID); + m_groupMap[id] = g; } + } - // translate via uchr resource - CFDataRef ref = (CFDataRef) TISGetInputSourceProperty(currentKeyboardLayout.get(), - kTISPropertyUnicodeKeyLayoutData); - const UCKeyboardLayout* layout = (const UCKeyboardLayout*) CFDataGetBytePtr(ref); - const bool layoutValid = (layout != NULL); + UInt32 keyboardType = LMGetKbdType(); + for (SInt32 g = 0; g < numGroups; ++g) { + // add special keys + getKeyMapForSpecialKeys(keyMap, g); + + const void *resource; + bool layoutValid = false; + + // add regular keys + // try uchr resource first + TISInputSourceRef keyboardLayout = + (TISInputSourceRef)CFArrayGetValueAtIndex(m_groups.get(), g); + CFDataRef resourceRef = (CFDataRef)TISGetInputSourceProperty( + keyboardLayout, kTISPropertyUnicodeKeyLayoutData); + + layoutValid = resourceRef != NULL; + if (layoutValid) + resource = CFDataGetBytePtr(resourceRef); if (layoutValid) { - // translate key - UniCharCount count; - UniChar chars[2]; - LOG((CLOG_DEBUG2 "modifiers: %08x", modifiers & 0xffu)); - OSStatus status = UCKeyTranslate(layout, - vkCode & 0xffu, action, - (modifiers >> 8) & 0xffu, - LMGetKbdType(), 0, &m_deadKeyState, - sizeof(chars) / sizeof(chars[0]), &count, chars); - - // get the characters - if (status == 0) { - if (count != 0 || m_deadKeyState == 0) { - m_deadKeyState = 0; - for (UniCharCount i = 0; i < count; ++i) { - ids.push_back(IOSXKeyResource::unicharToKeyID(chars[i])); - } - adjustAltGrModifier(ids, maskOut, isCommand); - return mapVirtualKeyToKeyButton(vkCode); - } - return 0; - } + OSXUchrKeyResource uchr(resource, keyboardType); + if (uchr.isValid()) { + LOG((CLOG_DEBUG1 "using uchr resource for group %d", g)); + getKeyMap(keyMap, g, uchr); + continue; + } } - return 0; + LOG((CLOG_DEBUG1 "no keyboard resource for group %d", g)); + } } -bool -OSXKeyState::fakeCtrlAltDel() -{ - // pass keys through unchanged +CGEventFlags OSXKeyState::getDeviceDependedFlags() const { + CGEventFlags modifiers = 0; + + if (m_shiftPressed) { + modifiers |= NX_DEVICELSHIFTKEYMASK; + } + + if (m_controlPressed) { + modifiers |= NX_DEVICELCTLKEYMASK; + } + + if (m_altPressed) { + modifiers |= NX_DEVICELALTKEYMASK; + } + + if (m_superPressed) { + modifiers |= NX_DEVICELCMDKEYMASK; + } + + return modifiers; +} + +CGEventFlags OSXKeyState::getKeyboardEventFlags() const { + // set the event flags for special keys + // http://tinyurl.com/pxl742y + CGEventFlags modifiers = getModifierStateAsOSXFlags(); + + if (!m_capsPressed) { + modifiers |= getDeviceDependedFlags(); + } + + return modifiers; +} + +void OSXKeyState::setKeyboardModifiers(CGKeyCode virtualKey, bool keyDown) { + switch (virtualKey) { + case s_shiftVK: + m_shiftPressed = keyDown; + break; + case s_controlVK: + m_controlPressed = keyDown; + break; + case s_altVK: + m_altPressed = keyDown; + break; + case s_superVK: + m_superPressed = keyDown; + break; + case s_capsLockVK: + m_capsPressed = keyDown; + break; + default: + LOG((CLOG_DEBUG1 "the key is not a modifier")); + break; + } +} + +kern_return_t OSXKeyState::postHIDVirtualKey(UInt8 virtualKey, bool postDown) { + NXEventData event; + bzero(&event, sizeof(NXEventData)); + auto driver = getEventDriver(); + kern_return_t result = KERN_FAILURE; + + if (driver) { + if (isModifier(virtualKey)) { + result = + IOHIDPostEvent(driver, NX_FLAGSCHANGED, {0, 0}, &event, + kNXEventDataVersion, getKeyboardEventFlags(), true); + } else { + event.key.keyCode = virtualKey; + const auto eventType = postDown ? NX_KEYDOWN : NX_KEYUP; + result = IOHIDPostEvent(driver, eventType, {0, 0}, &event, + kNXEventDataVersion, 0, false); + } + } + + return result; +} + +void OSXKeyState::postKeyboardKey(CGKeyCode virtualKey, bool keyDown) { + CGEventRef event = CGEventCreateKeyboardEvent(nullptr, virtualKey, keyDown); + if (event) { + CGEventSetFlags(event, getKeyboardEventFlags()); + CGEventPost(kCGHIDEventTap, event); + CFRelease(event); + } else { + LOG((CLOG_CRIT "unable to create keyboard event for keystroke")); + } +} + +void OSXKeyState::fakeKey(const Keystroke &keystroke) { + switch (keystroke.m_type) { + case Keystroke::kButton: { + bool keyDown = keystroke.m_data.m_button.m_press; + UInt32 client = keystroke.m_data.m_button.m_client; + KeyButton button = keystroke.m_data.m_button.m_button; + CGKeyCode virtualKey = mapKeyButtonToVirtualKey(button); + + LOG((CLOG_DEBUG1 + " button=0x%04x virtualKey=0x%04x keyDown=%s client=0x%04x", + button, virtualKey, keyDown ? "down" : "up", client)); + + setKeyboardModifiers(virtualKey, keyDown); + if (postHIDVirtualKey(virtualKey, keyDown) != KERN_SUCCESS) { + LOG((CLOG_WARN, "fail to post hid event")); + postKeyboardKey(virtualKey, keyDown); + } + + break; + } + + case Keystroke::kGroup: { + SInt32 group = keystroke.m_data.m_group.m_group; + if (!keystroke.m_data.m_group.m_restore) { + if (keystroke.m_data.m_group.m_absolute) { + LOG((CLOG_DEBUG1 " group %d", group)); + setGroup(group); + } else { + LOG((CLOG_DEBUG1 " group %+d", group)); + setGroup(getEffectiveGroup(pollActiveGroup(), group)); + } + + if (pollActiveGroup() != group) { + LOG((CLOG_WARN "failed to set new keyboard layout")); + } + } + break; + } + } +} + +void OSXKeyState::getKeyMapForSpecialKeys(synergy::KeyMap &keyMap, + SInt32 group) const { + // special keys are insensitive to modifers and none are dead keys + synergy::KeyMap::KeyItem item; + for (size_t i = 0; i < sizeof(s_controlKeys) / sizeof(s_controlKeys[0]); + ++i) { + const KeyEntry &entry = s_controlKeys[i]; + item.m_id = entry.m_keyID; + item.m_group = group; + item.m_button = mapVirtualKeyToKeyButton(entry.m_virtualKey); + item.m_required = 0; + item.m_sensitive = 0; + item.m_dead = false; + item.m_client = 0; + synergy::KeyMap::initModifierKey(item); + keyMap.addKeyEntry(item); + + if (item.m_lock) { + // all locking keys are half duplex on OS X + keyMap.addHalfDuplexButton(item.m_button); + } + } + + // note: we don't special case the number pad keys. querying the + // mac keyboard returns the non-keypad version of those keys but + // a KeyState always provides a mapping from keypad keys to + // non-keypad keys so we'll be able to generate the characters + // anyway. +} + +bool OSXKeyState::getKeyMap(synergy::KeyMap &keyMap, SInt32 group, + const IOSXKeyResource &r) const { + if (!r.isValid()) { return false; -} + } -bool -OSXKeyState::fakeMediaKey(KeyID id) -{ - return fakeNativeMediaKey(id); -} + // space for all possible modifier combinations + std::vector modifiers(r.getNumModifierCombinations()); -CGEventFlags -OSXKeyState::getModifierStateAsOSXFlags() const -{ - CGEventFlags modifiers = 0; + // make space for the keys that any single button can synthesize + std::vector> buttonKeys(r.getNumTables()); - if (m_shiftPressed) { - modifiers |= kCGEventFlagMaskShift; + // iterate over each button + synergy::KeyMap::KeyItem item; + for (UInt32 i = 0; i < r.getNumButtons(); ++i) { + item.m_button = mapVirtualKeyToKeyButton(i); + + // the KeyIDs we've already handled + std::set keys; + + // convert the entry in each table for this button to a KeyID + for (UInt32 j = 0; j < r.getNumTables(); ++j) { + buttonKeys[j].first = r.getKey(j, i); + buttonKeys[j].second = synergy::KeyMap::isDeadKey(buttonKeys[j].first); } - if (m_controlPressed) { - modifiers |= kCGEventFlagMaskControl; - } + // iterate over each character table + for (UInt32 j = 0; j < r.getNumTables(); ++j) { + // get the KeyID for the button/table + KeyID id = buttonKeys[j].first; + if (id == kKeyNone) { + continue; + } - if (m_altPressed) { - modifiers |= kCGEventFlagMaskAlternate; - } + // if we've already handled the KeyID in the table then + // move on to the next table + if (keys.count(id) > 0) { + continue; + } + keys.insert(id); - if (m_superPressed) { - modifiers |= kCGEventFlagMaskCommand; - } - - if (m_capsPressed) { - modifiers |= kCGEventFlagMaskAlphaShift; - } + // prepare item. the client state is 1 for dead keys. + item.m_id = id; + item.m_group = group; + item.m_dead = buttonKeys[j].second; + item.m_client = buttonKeys[j].second ? 1 : 0; + synergy::KeyMap::initModifierKey(item); + if (item.m_lock) { + // all locking keys are half duplex on OS X + keyMap.addHalfDuplexButton(i); + } - return modifiers; -} - -KeyModifierMask -OSXKeyState::pollActiveModifiers() const -{ - // falsely assumed that the mask returned by GetCurrentKeyModifiers() - // was the same as a CGEventFlags (which is what mapModifiersFromOSX - // expects). patch by Marc - UInt32 mask = GetCurrentKeyModifiers(); - KeyModifierMask outMask = 0; - - if ((mask & shiftKey) != 0) { - outMask |= KeyModifierShift; - } - if ((mask & controlKey) != 0) { - outMask |= KeyModifierControl; - } - if ((mask & optionKey) != 0) { - outMask |= KeyModifierAlt; - } - if ((mask & cmdKey) != 0) { - outMask |= KeyModifierSuper; - } - if ((mask & alphaLock) != 0) { - outMask |= KeyModifierCapsLock; - } - if ((mask & s_osxNumLock) != 0) { - outMask |= KeyModifierNumLock; - } - - LOG((CLOG_DEBUG1 "mask=%04x outMask=%04x", mask, outMask)); - return outMask; -} - -SInt32 -OSXKeyState::pollActiveGroup() const -{ - AutoTISInputSourceRef keyboardLayout(TISCopyCurrentKeyboardLayoutInputSource(), CFRelease); - CFDataRef id = (CFDataRef)TISGetInputSourceProperty( - keyboardLayout.get(), kTISPropertyInputSourceID); - - GroupMap::const_iterator i = m_groupMap.find(id); - if (i != m_groupMap.end()) { - return i->second; - } - - LOG((CLOG_WARN "can't get the active group, use the first group instead")); - - return 0; -} - -void -OSXKeyState::pollPressedKeys(KeyButtonSet& pressedKeys) const -{ - ::KeyMap km; - GetKeys(km); - const UInt8* m = reinterpret_cast(km); - for (UInt32 i = 0; i < 16; ++i) { - for (UInt32 j = 0; j < 8; ++j) { - if ((m[i] & (1u << j)) != 0) { - pressedKeys.insert(mapVirtualKeyToKeyButton(8 * i + j)); - } + // collect the tables that map to the same KeyID. we know it + // can't be any earlier tables because of the check above. + std::set tables; + tables.insert(static_cast(j)); + for (UInt32 k = j + 1; k < r.getNumTables(); ++k) { + if (buttonKeys[k].first == id) { + tables.insert(static_cast(k)); } - } -} + } -void -OSXKeyState::getKeyMap(synergy::KeyMap& keyMap) -{ - // update keyboard groups - SInt32 numGroups {0}; - if (getGroups(m_groups)) { - m_groupMap.clear(); - numGroups = CFArrayGetCount(m_groups.get()); - for (SInt32 g = 0; g < numGroups; ++g) { - TISInputSourceRef keyboardLayout = (TISInputSourceRef)CFArrayGetValueAtIndex(m_groups.get(), g); - CFDataRef id = (CFDataRef)TISGetInputSourceProperty(keyboardLayout, kTISPropertyInputSourceID); - m_groupMap[id] = g; + // collect the modifier combinations that map to any of the + // tables we just collected + for (UInt32 k = 0; k < r.getNumModifierCombinations(); ++k) { + modifiers[k] = (tables.count(r.getTableForModifier(k)) > 0); + } + + // figure out which modifiers the key is sensitive to. the + // key is insensitive to a modifier if for every modifier mask + // with the modifier bit unset in the modifiers we also find + // the same mask with the bit set. + // + // we ignore a few modifiers that we know aren't important + // for generating characters. in fact, we want to ignore any + // characters generated by the control key. we don't map + // those and instead expect the control modifier plus a key. + UInt32 sensitive = 0; + for (UInt32 k = 0; (1u << k) < r.getNumModifierCombinations(); ++k) { + UInt32 bit = (1u << k); + if ((bit << 8) == cmdKey || (bit << 8) == controlKey || + (bit << 8) == rightControlKey) { + continue; } - } - - UInt32 keyboardType = LMGetKbdType(); - for (SInt32 g = 0; g < numGroups; ++g) { - // add special keys - getKeyMapForSpecialKeys(keyMap, g); - - const void* resource; - bool layoutValid = false; - - // add regular keys - // try uchr resource first - TISInputSourceRef keyboardLayout = (TISInputSourceRef)CFArrayGetValueAtIndex(m_groups.get(), g); - CFDataRef resourceRef = (CFDataRef)TISGetInputSourceProperty(keyboardLayout, kTISPropertyUnicodeKeyLayoutData); - - layoutValid = resourceRef != NULL; - if (layoutValid) - resource = CFDataGetBytePtr(resourceRef); - - if (layoutValid) { - OSXUchrKeyResource uchr(resource, keyboardType); - if (uchr.isValid()) { - LOG((CLOG_DEBUG1 "using uchr resource for group %d", g)); - getKeyMap(keyMap, g, uchr); - continue; - } + for (UInt32 m = 0; m < r.getNumModifierCombinations(); ++m) { + if (modifiers[m] != modifiers[m ^ bit]) { + sensitive |= bit; + break; + } } + } - LOG((CLOG_DEBUG1 "no keyboard resource for group %d", g)); - } -} - -CGEventFlags -OSXKeyState::getDeviceDependedFlags() const -{ - CGEventFlags modifiers = 0; - - if (m_shiftPressed) { - modifiers |= NX_DEVICELSHIFTKEYMASK; - } - - if (m_controlPressed) { - modifiers |= NX_DEVICELCTLKEYMASK; - } - - if (m_altPressed) { - modifiers |= NX_DEVICELALTKEYMASK; - } - - if (m_superPressed) { - modifiers |= NX_DEVICELCMDKEYMASK; - } - - return modifiers; -} - - -CGEventFlags -OSXKeyState::getKeyboardEventFlags() const -{ - // set the event flags for special keys - // http://tinyurl.com/pxl742y - CGEventFlags modifiers = getModifierStateAsOSXFlags(); - - if (!m_capsPressed) { - modifiers |= getDeviceDependedFlags(); - } - - return modifiers; -} - -void -OSXKeyState::setKeyboardModifiers(CGKeyCode virtualKey, bool keyDown) -{ - switch(virtualKey) { - case s_shiftVK: - m_shiftPressed = keyDown; - break; - case s_controlVK: - m_controlPressed = keyDown; - break; - case s_altVK: - m_altPressed = keyDown; - break; - case s_superVK: - m_superPressed = keyDown; - break; - case s_capsLockVK: - m_capsPressed = keyDown; - break; - default: - LOG((CLOG_DEBUG1 "the key is not a modifier")); - break; - } -} - -kern_return_t -OSXKeyState::postHIDVirtualKey(UInt8 virtualKey, bool postDown) -{ - NXEventData event; - bzero(&event, sizeof(NXEventData)); - auto driver = getEventDriver(); - kern_return_t result = KERN_FAILURE; - - if (driver) { - if (isModifier(virtualKey)) { - result = IOHIDPostEvent(driver, NX_FLAGSCHANGED, {0,0}, &event, kNXEventDataVersion, getKeyboardEventFlags(), true); - } - else { - event.key.keyCode = virtualKey; - const auto eventType = postDown ? NX_KEYDOWN : NX_KEYUP; - result = IOHIDPostEvent(driver, eventType, {0,0}, &event, kNXEventDataVersion, 0, false); + // find each required modifier mask. the key can be synthesized + // using any of the masks. + std::set required; + for (UInt32 k = 0; k < r.getNumModifierCombinations(); ++k) { + if ((k & sensitive) == k && modifiers[k & sensitive]) { + required.insert(k); } + } - } - - return result; -} - -void -OSXKeyState::postKeyboardKey(CGKeyCode virtualKey, bool keyDown) -{ - CGEventRef event = CGEventCreateKeyboardEvent(nullptr, virtualKey, keyDown); - if (event) { - CGEventSetFlags(event, getKeyboardEventFlags()); - CGEventPost(kCGHIDEventTap, event); - CFRelease(event); - } - else { - LOG((CLOG_CRIT "unable to create keyboard event for keystroke")); - } -} - -void -OSXKeyState::fakeKey(const Keystroke& keystroke) -{ - switch (keystroke.m_type) { - case Keystroke::kButton: { - bool keyDown = keystroke.m_data.m_button.m_press; - UInt32 client = keystroke.m_data.m_button.m_client; - KeyButton button = keystroke.m_data.m_button.m_button; - CGKeyCode virtualKey = mapKeyButtonToVirtualKey(button); - - LOG((CLOG_DEBUG1 - " button=0x%04x virtualKey=0x%04x keyDown=%s client=0x%04x", - button, virtualKey, keyDown ? "down" : "up", client)); - - setKeyboardModifiers(virtualKey, keyDown); - if (postHIDVirtualKey(virtualKey, keyDown) != KERN_SUCCESS) { - LOG((CLOG_WARN, "fail to post hid event")); - postKeyboardKey(virtualKey, keyDown); - } - - break; - } - - case Keystroke::kGroup: { - SInt32 group = keystroke.m_data.m_group.m_group; - if (!keystroke.m_data.m_group.m_restore) { - if (keystroke.m_data.m_group.m_absolute) { - LOG((CLOG_DEBUG1 " group %d", group)); - setGroup(group); - } - else { - LOG((CLOG_DEBUG1 " group %+d", group)); - setGroup(getEffectiveGroup(pollActiveGroup(), group)); - } - - if(pollActiveGroup() != group) { - LOG((CLOG_WARN "failed to set new keyboard layout")); - } - } - break; - } - } -} - -void -OSXKeyState::getKeyMapForSpecialKeys(synergy::KeyMap& keyMap, SInt32 group) const -{ - // special keys are insensitive to modifers and none are dead keys - synergy::KeyMap::KeyItem item; - for (size_t i = 0; i < sizeof(s_controlKeys) / - sizeof(s_controlKeys[0]); ++i) { - const KeyEntry& entry = s_controlKeys[i]; - item.m_id = entry.m_keyID; - item.m_group = group; - item.m_button = mapVirtualKeyToKeyButton(entry.m_virtualKey); - item.m_required = 0; - item.m_sensitive = 0; - item.m_dead = false; - item.m_client = 0; - synergy::KeyMap::initModifierKey(item); + // now add a key entry for each key/required modifier pair. + item.m_sensitive = mapModifiersFromOSX(sensitive << 16); + for (std::set::iterator k = required.begin(); k != required.end(); + ++k) { + item.m_required = mapModifiersFromOSX(*k << 16); keyMap.addKeyEntry(item); - - if (item.m_lock) { - // all locking keys are half duplex on OS X - keyMap.addHalfDuplexButton(item.m_button); - } + } } + } - // note: we don't special case the number pad keys. querying the - // mac keyboard returns the non-keypad version of those keys but - // a KeyState always provides a mapping from keypad keys to - // non-keypad keys so we'll be able to generate the characters - // anyway. + return true; } -bool -OSXKeyState::getKeyMap(synergy::KeyMap& keyMap, - SInt32 group, const IOSXKeyResource& r) const -{ - if (!r.isValid()) { - return false; - } +bool OSXKeyState::mapSynergyHotKeyToMac(KeyID key, KeyModifierMask mask, + UInt32 &macVirtualKey, + UInt32 &macModifierMask) const { + // look up button for key + KeyButton button = getButton(key, pollActiveGroup()); + if (button == 0 && key != kKeyNone) { + return false; + } + macVirtualKey = mapKeyButtonToVirtualKey(button); - // space for all possible modifier combinations - std::vector modifiers(r.getNumModifierCombinations()); + // calculate modifier mask + macModifierMask = 0; + if ((mask & KeyModifierShift) != 0) { + macModifierMask |= shiftKey; + } + if ((mask & KeyModifierControl) != 0) { + macModifierMask |= controlKey; + } + if ((mask & KeyModifierAlt) != 0) { + macModifierMask |= cmdKey; + } + if ((mask & KeyModifierSuper) != 0) { + macModifierMask |= optionKey; + } + if ((mask & KeyModifierCapsLock) != 0) { + macModifierMask |= alphaLock; + } + if ((mask & KeyModifierNumLock) != 0) { + macModifierMask |= s_osxNumLock; + } - // make space for the keys that any single button can synthesize - std::vector > buttonKeys(r.getNumTables()); - - // iterate over each button - synergy::KeyMap::KeyItem item; - for (UInt32 i = 0; i < r.getNumButtons(); ++i) { - item.m_button = mapVirtualKeyToKeyButton(i); - - // the KeyIDs we've already handled - std::set keys; - - // convert the entry in each table for this button to a KeyID - for (UInt32 j = 0; j < r.getNumTables(); ++j) { - buttonKeys[j].first = r.getKey(j, i); - buttonKeys[j].second = synergy::KeyMap::isDeadKey(buttonKeys[j].first); - } - - // iterate over each character table - for (UInt32 j = 0; j < r.getNumTables(); ++j) { - // get the KeyID for the button/table - KeyID id = buttonKeys[j].first; - if (id == kKeyNone) { - continue; - } - - // if we've already handled the KeyID in the table then - // move on to the next table - if (keys.count(id) > 0) { - continue; - } - keys.insert(id); - - // prepare item. the client state is 1 for dead keys. - item.m_id = id; - item.m_group = group; - item.m_dead = buttonKeys[j].second; - item.m_client = buttonKeys[j].second ? 1 : 0; - synergy::KeyMap::initModifierKey(item); - if (item.m_lock) { - // all locking keys are half duplex on OS X - keyMap.addHalfDuplexButton(i); - } - - // collect the tables that map to the same KeyID. we know it - // can't be any earlier tables because of the check above. - std::set tables; - tables.insert(static_cast(j)); - for (UInt32 k = j + 1; k < r.getNumTables(); ++k) { - if (buttonKeys[k].first == id) { - tables.insert(static_cast(k)); - } - } - - // collect the modifier combinations that map to any of the - // tables we just collected - for (UInt32 k = 0; k < r.getNumModifierCombinations(); ++k) { - modifiers[k] = (tables.count(r.getTableForModifier(k)) > 0); - } - - // figure out which modifiers the key is sensitive to. the - // key is insensitive to a modifier if for every modifier mask - // with the modifier bit unset in the modifiers we also find - // the same mask with the bit set. - // - // we ignore a few modifiers that we know aren't important - // for generating characters. in fact, we want to ignore any - // characters generated by the control key. we don't map - // those and instead expect the control modifier plus a key. - UInt32 sensitive = 0; - for (UInt32 k = 0; (1u << k) < - r.getNumModifierCombinations(); ++k) { - UInt32 bit = (1u << k); - if ((bit << 8) == cmdKey || - (bit << 8) == controlKey || - (bit << 8) == rightControlKey) { - continue; - } - for (UInt32 m = 0; m < r.getNumModifierCombinations(); ++m) { - if (modifiers[m] != modifiers[m ^ bit]) { - sensitive |= bit; - break; - } - } - } - - // find each required modifier mask. the key can be synthesized - // using any of the masks. - std::set required; - for (UInt32 k = 0; k < r.getNumModifierCombinations(); ++k) { - if ((k & sensitive) == k && modifiers[k & sensitive]) { - required.insert(k); - } - } - - // now add a key entry for each key/required modifier pair. - item.m_sensitive = mapModifiersFromOSX(sensitive << 16); - for (std::set::iterator k = required.begin(); - k != required.end(); ++k) { - item.m_required = mapModifiersFromOSX(*k << 16); - keyMap.addKeyEntry(item); - } - } - } - - return true; + return true; } -bool -OSXKeyState::mapSynergyHotKeyToMac(KeyID key, KeyModifierMask mask, - UInt32 &macVirtualKey, UInt32 &macModifierMask) const -{ - // look up button for key - KeyButton button = getButton(key, pollActiveGroup()); - if (button == 0 && key != kKeyNone) { - return false; - } - macVirtualKey = mapKeyButtonToVirtualKey(button); - - // calculate modifier mask - macModifierMask = 0; - if ((mask & KeyModifierShift) != 0) { - macModifierMask |= shiftKey; - } - if ((mask & KeyModifierControl) != 0) { - macModifierMask |= controlKey; - } - if ((mask & KeyModifierAlt) != 0) { - macModifierMask |= cmdKey; - } - if ((mask & KeyModifierSuper) != 0) { - macModifierMask |= optionKey; - } - if ((mask & KeyModifierCapsLock) != 0) { - macModifierMask |= alphaLock; - } - if ((mask & KeyModifierNumLock) != 0) { - macModifierMask |= s_osxNumLock; - } - - return true; -} - -void -OSXKeyState::handleModifierKeys(void* target, - KeyModifierMask oldMask, KeyModifierMask newMask) -{ - // compute changed modifiers - KeyModifierMask changed = (oldMask ^ newMask); +void OSXKeyState::handleModifierKeys(void *target, KeyModifierMask oldMask, + KeyModifierMask newMask) { + // compute changed modifiers + KeyModifierMask changed = (oldMask ^ newMask); - // synthesize changed modifier keys - if ((changed & KeyModifierShift) != 0) { - handleModifierKey(target, s_shiftVK, kKeyShift_L, - (newMask & KeyModifierShift) != 0, newMask); - } - if ((changed & KeyModifierControl) != 0) { - handleModifierKey(target, s_controlVK, kKeyControl_L, - (newMask & KeyModifierControl) != 0, newMask); - } - if ((changed & KeyModifierAlt) != 0) { - handleModifierKey(target, s_altVK, kKeyAlt_L, - (newMask & KeyModifierAlt) != 0, newMask); - } - if ((changed & KeyModifierSuper) != 0) { - handleModifierKey(target, s_superVK, kKeySuper_L, - (newMask & KeyModifierSuper) != 0, newMask); - } - if ((changed & KeyModifierCapsLock) != 0) { - handleModifierKey(target, s_capsLockVK, kKeyCapsLock, - (newMask & KeyModifierCapsLock) != 0, newMask); - } - if ((changed & KeyModifierNumLock) != 0) { - handleModifierKey(target, s_numLockVK, kKeyNumLock, - (newMask & KeyModifierNumLock) != 0, newMask); - } + // synthesize changed modifier keys + if ((changed & KeyModifierShift) != 0) { + handleModifierKey(target, s_shiftVK, kKeyShift_L, + (newMask & KeyModifierShift) != 0, newMask); + } + if ((changed & KeyModifierControl) != 0) { + handleModifierKey(target, s_controlVK, kKeyControl_L, + (newMask & KeyModifierControl) != 0, newMask); + } + if ((changed & KeyModifierAlt) != 0) { + handleModifierKey(target, s_altVK, kKeyAlt_L, + (newMask & KeyModifierAlt) != 0, newMask); + } + if ((changed & KeyModifierSuper) != 0) { + handleModifierKey(target, s_superVK, kKeySuper_L, + (newMask & KeyModifierSuper) != 0, newMask); + } + if ((changed & KeyModifierCapsLock) != 0) { + handleModifierKey(target, s_capsLockVK, kKeyCapsLock, + (newMask & KeyModifierCapsLock) != 0, newMask); + } + if ((changed & KeyModifierNumLock) != 0) { + handleModifierKey(target, s_numLockVK, kKeyNumLock, + (newMask & KeyModifierNumLock) != 0, newMask); + } } -void -OSXKeyState::handleModifierKey(void* target, - UInt32 virtualKey, KeyID id, - bool down, KeyModifierMask newMask) -{ - KeyButton button = mapVirtualKeyToKeyButton(virtualKey); - onKey(button, down, newMask); - sendKeyEvent(target, down, false, id, newMask, 0, button); +void OSXKeyState::handleModifierKey(void *target, UInt32 virtualKey, KeyID id, + bool down, KeyModifierMask newMask) { + KeyButton button = mapVirtualKeyToKeyButton(virtualKey); + onKey(button, down, newMask); + sendKeyEvent(target, down, false, id, newMask, 0, button); } -bool -OSXKeyState::getGroups(AutoCFArray& groups) const -{ - // get number of layouts - CFStringRef keys[] = { kTISPropertyInputSourceCategory }; - CFStringRef values[] = { kTISCategoryKeyboardInputSource }; - AutoCFDictionary dict(CFDictionaryCreate(NULL, (const void **)keys, (const void **)values, 1, NULL, NULL), CFRelease); - AutoCFArray kbds(TISCreateInputSourceList(dict.get(), false), CFRelease); +bool OSXKeyState::getGroups(AutoCFArray &groups) const { + // get number of layouts + CFStringRef keys[] = {kTISPropertyInputSourceCategory}; + CFStringRef values[] = {kTISCategoryKeyboardInputSource}; + AutoCFDictionary dict(CFDictionaryCreate(NULL, (const void **)keys, + (const void **)values, 1, NULL, + NULL), + CFRelease); + AutoCFArray kbds(TISCreateInputSourceList(dict.get(), false), CFRelease); - if (CFArrayGetCount(kbds.get()) > 0) { - groups = std::move(kbds); - } - else{ - LOG((CLOG_DEBUG1 "can't get keyboard layouts")); - return false; - } + if (CFArrayGetCount(kbds.get()) > 0) { + groups = std::move(kbds); + } else { + LOG((CLOG_DEBUG1 "can't get keyboard layouts")); + return false; + } - return true; + return true; } -void -OSXKeyState::setGroup(SInt32 group) -{ - TISInputSourceRef keyboardLayout = (TISInputSourceRef)CFArrayGetValueAtIndex(m_groups.get(), group); - if(!keyboardLayout) { - LOG((CLOG_WARN "nedeed keyboard layout is null")); +void OSXKeyState::setGroup(SInt32 group) { + TISInputSourceRef keyboardLayout = + (TISInputSourceRef)CFArrayGetValueAtIndex(m_groups.get(), group); + if (!keyboardLayout) { + LOG((CLOG_WARN "nedeed keyboard layout is null")); + return; + } + auto canBeSetted = (CFBooleanRef)TISGetInputSourceProperty( + TISCopyCurrentKeyboardInputSource(), + kTISPropertyInputSourceIsEnableCapable); + if (!canBeSetted) { + LOG((CLOG_WARN + "nedeed keyboard layout is disabled for programmatically selection")); + return; + } + + if (TISSelectInputSource(keyboardLayout) != noErr) { + LOG((CLOG_WARN "failed to set nedeed keyboard layout")); + } + + LOG((CLOG_DEBUG1 "keyboard layout change to %d", group)); + + // A minimal delay is needed after a group change because the + // keyboard key event often happens immediately after. + // Language (TIS) and event (CG) systems are not in the mutual + // event queue and without a delay the subsequent key press + // event could be applied before the keyboard layout would + // actually be changed. + ARCH->sleep(.01); +} + +void OSXKeyState::adjustAltGrModifier(const KeyIDs &ids, KeyModifierMask *mask, + bool isCommand) const { + if (!isCommand) { + for (KeyIDs::const_iterator i = ids.begin(); i != ids.end(); ++i) { + KeyID id = *i; + if (id != kKeyNone && ((id < 0xe000u || id > 0xefffu) || + (id >= kKeyKP_Equal && id <= kKeyKP_9))) { + *mask |= KeyModifierAltGr; return; + } } - auto canBeSetted = (CFBooleanRef)TISGetInputSourceProperty(TISCopyCurrentKeyboardInputSource(), kTISPropertyInputSourceIsEnableCapable); - if(!canBeSetted) { - LOG((CLOG_WARN "nedeed keyboard layout is disabled for programmatically selection")); - return; - } - - if(TISSelectInputSource(keyboardLayout) != noErr) { - LOG((CLOG_WARN "failed to set nedeed keyboard layout")); - } - - LOG((CLOG_DEBUG1 "keyboard layout change to %d", group)); - - //A minimal delay is needed after a group change because the - //keyboard key event often happens immediately after. - //Language (TIS) and event (CG) systems are not in the mutual - //event queue and without a delay the subsequent key press - //event could be applied before the keyboard layout would - //actually be changed. - ARCH->sleep(.01); + } } -void -OSXKeyState::adjustAltGrModifier(const KeyIDs& ids, - KeyModifierMask* mask, bool isCommand) const -{ - if (!isCommand) { - for (KeyIDs::const_iterator i = ids.begin(); i != ids.end(); ++i) { - KeyID id = *i; - if (id != kKeyNone && - ((id < 0xe000u || id > 0xefffu) || - (id >= kKeyKP_Equal && id <= kKeyKP_9))) { - *mask |= KeyModifierAltGr; - return; - } - } - } +KeyButton OSXKeyState::mapVirtualKeyToKeyButton(UInt32 keyCode) { + // 'A' maps to 0 so shift every id + return static_cast(keyCode + KeyButtonOffset); } -KeyButton -OSXKeyState::mapVirtualKeyToKeyButton(UInt32 keyCode) -{ - // 'A' maps to 0 so shift every id - return static_cast(keyCode + KeyButtonOffset); -} - -UInt32 -OSXKeyState::mapKeyButtonToVirtualKey(KeyButton keyButton) -{ - return static_cast(keyButton - KeyButtonOffset); +UInt32 OSXKeyState::mapKeyButtonToVirtualKey(KeyButton keyButton) { + return static_cast(keyButton - KeyButtonOffset); } diff --git a/src/lib/platform/OSXKeyState.h b/src/lib/platform/OSXKeyState.h index 20edea1ff..b395a0cc1 100644 --- a/src/lib/platform/OSXKeyState.h +++ b/src/lib/platform/OSXKeyState.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 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 LICENSE 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 @@ -18,167 +18,163 @@ #pragma once -#include "synergy/KeyState.h" +#include "OSXAutoTypes.h" #include "common/stdmap.h" #include "common/stdset.h" #include "common/stdvector.h" -#include "OSXAutoTypes.h" +#include "synergy/KeyState.h" #include class IOSXKeyResource; - //! OS X key state /*! A key state for OS X. */ class OSXKeyState : public KeyState { public: - typedef std::vector KeyIDs; + typedef std::vector KeyIDs; - OSXKeyState(IEventQueue* events, std::vector layouts, bool isLangSyncEnabled); - OSXKeyState(IEventQueue* events, synergy::KeyMap& keyMap, - std::vector layouts, bool isLangSyncEnabled); - virtual ~OSXKeyState(); + OSXKeyState(IEventQueue *events, std::vector layouts, + bool isLangSyncEnabled); + OSXKeyState(IEventQueue *events, synergy::KeyMap &keyMap, + std::vector layouts, bool isLangSyncEnabled); + virtual ~OSXKeyState(); - //! @name modifiers - //@{ + //! @name modifiers + //@{ - //! Handle modifier key change - /*! - Determines which modifier keys have changed and updates the modifier - state and sends key events as appropriate. - */ - void handleModifierKeys(void* target, - KeyModifierMask oldMask, KeyModifierMask newMask); + //! Handle modifier key change + /*! + Determines which modifier keys have changed and updates the modifier + state and sends key events as appropriate. + */ + void handleModifierKeys(void *target, KeyModifierMask oldMask, + KeyModifierMask newMask); - //@} - //! @name accessors - //@{ + //@} + //! @name accessors + //@{ - //! Convert OS X modifier mask to synergy mask - /*! - Returns the synergy modifier mask corresponding to the OS X modifier - mask in \p mask. - */ - KeyModifierMask mapModifiersFromOSX(UInt32 mask) const; + //! Convert OS X modifier mask to synergy mask + /*! + Returns the synergy modifier mask corresponding to the OS X modifier + mask in \p mask. + */ + KeyModifierMask mapModifiersFromOSX(UInt32 mask) const; - //! Convert CG flags-style modifier mask to old-style Carbon - /*! - Still required in a few places for translation calls. - */ - KeyModifierMask mapModifiersToCarbon(UInt32 mask) const; - - //! Map key event to keys - /*! - Converts a key event into a sequence of KeyIDs and the shadow modifier - state to a modifier mask. The KeyIDs list, in order, the characters - generated by the key press/release. It returns the id of the button - that was pressed or released, or 0 if the button doesn't map to a known - KeyID. - */ - KeyButton mapKeyFromEvent(KeyIDs& ids, - KeyModifierMask* maskOut, CGEventRef event) const; + //! Convert CG flags-style modifier mask to old-style Carbon + /*! + Still required in a few places for translation calls. + */ + KeyModifierMask mapModifiersToCarbon(UInt32 mask) const; - //! Map key and mask to native values - /*! - Calculates mac virtual key and mask for a key \p key and modifiers - \p mask. Returns \c true if the key can be mapped, \c false otherwise. - */ - bool mapSynergyHotKeyToMac(KeyID key, KeyModifierMask mask, - UInt32& macVirtualKey, - UInt32& macModifierMask) const; + //! Map key event to keys + /*! + Converts a key event into a sequence of KeyIDs and the shadow modifier + state to a modifier mask. The KeyIDs list, in order, the characters + generated by the key press/release. It returns the id of the button + that was pressed or released, or 0 if the button doesn't map to a known + KeyID. + */ + KeyButton mapKeyFromEvent(KeyIDs &ids, KeyModifierMask *maskOut, + CGEventRef event) const; - //@} + //! Map key and mask to native values + /*! + Calculates mac virtual key and mask for a key \p key and modifiers + \p mask. Returns \c true if the key can be mapped, \c false otherwise. + */ + bool mapSynergyHotKeyToMac(KeyID key, KeyModifierMask mask, + UInt32 &macVirtualKey, + UInt32 &macModifierMask) const; - // IKeyState overrides - virtual bool fakeCtrlAltDel(); - virtual bool fakeMediaKey(KeyID id); - virtual KeyModifierMask - pollActiveModifiers() const; - virtual SInt32 pollActiveGroup() const; - virtual void pollPressedKeys(KeyButtonSet& pressedKeys) const; + //@} + + // IKeyState overrides + virtual bool fakeCtrlAltDel(); + virtual bool fakeMediaKey(KeyID id); + virtual KeyModifierMask pollActiveModifiers() const; + virtual SInt32 pollActiveGroup() const; + virtual void pollPressedKeys(KeyButtonSet &pressedKeys) const; + + CGEventFlags getModifierStateAsOSXFlags() const; - CGEventFlags getModifierStateAsOSXFlags() const; protected: - // KeyState overrides - virtual void getKeyMap(synergy::KeyMap& keyMap); - virtual void fakeKey(const Keystroke& keystroke); + // KeyState overrides + virtual void getKeyMap(synergy::KeyMap &keyMap); + virtual void fakeKey(const Keystroke &keystroke); private: - class KeyResource; + class KeyResource; - // Add hard coded special keys to a synergy::KeyMap. - void getKeyMapForSpecialKeys( - synergy::KeyMap& keyMap, SInt32 group) const; + // Add hard coded special keys to a synergy::KeyMap. + void getKeyMapForSpecialKeys(synergy::KeyMap &keyMap, SInt32 group) const; - // Convert keyboard resource to a key map - bool getKeyMap(synergy::KeyMap& keyMap, - SInt32 group, const IOSXKeyResource& r) const; + // Convert keyboard resource to a key map + bool getKeyMap(synergy::KeyMap &keyMap, SInt32 group, + const IOSXKeyResource &r) const; - // Get the available keyboard groups - bool getGroups(AutoCFArray&) const; + // Get the available keyboard groups + bool getGroups(AutoCFArray &) const; - // Change active keyboard group to group - void setGroup(SInt32 group); + // Change active keyboard group to group + void setGroup(SInt32 group); - // Send an event for the given modifier key - void handleModifierKey(void* target, - UInt32 virtualKey, KeyID id, - bool down, KeyModifierMask newMask); + // Send an event for the given modifier key + void handleModifierKey(void *target, UInt32 virtualKey, KeyID id, bool down, + KeyModifierMask newMask); - // Checks if any in \p ids is a glyph key and if \p isCommand is false. - // If so it adds the AltGr modifier to \p mask. This allows OS X - // servers to use the option key both as AltGr and as a modifier. If - // option is acting as AltGr (i.e. it generates a glyph and there are - // no command modifiers active) then we don't send the super modifier - // to clients because they'd try to match it as a command modifier. - void adjustAltGrModifier(const KeyIDs& ids, - KeyModifierMask* mask, bool isCommand) const; + // Checks if any in \p ids is a glyph key and if \p isCommand is false. + // If so it adds the AltGr modifier to \p mask. This allows OS X + // servers to use the option key both as AltGr and as a modifier. If + // option is acting as AltGr (i.e. it generates a glyph and there are + // no command modifiers active) then we don't send the super modifier + // to clients because they'd try to match it as a command modifier. + void adjustAltGrModifier(const KeyIDs &ids, KeyModifierMask *mask, + bool isCommand) const; - // Maps an OS X virtual key id to a KeyButton. This simply remaps - // the ids so we don't use KeyButton 0. - static KeyButton mapVirtualKeyToKeyButton(UInt32 keyCode); + // Maps an OS X virtual key id to a KeyButton. This simply remaps + // the ids so we don't use KeyButton 0. + static KeyButton mapVirtualKeyToKeyButton(UInt32 keyCode); - // Maps a KeyButton to an OS X key code. This is the inverse of - // mapVirtualKeyToKeyButton. - static UInt32 mapKeyButtonToVirtualKey(KeyButton keyButton); + // Maps a KeyButton to an OS X key code. This is the inverse of + // mapVirtualKeyToKeyButton. + static UInt32 mapKeyButtonToVirtualKey(KeyButton keyButton); - void init(); + void init(); - // Post a key event to HID manager. It posts an event to HID client, a - // much lower level than window manager which's the target from carbon - // CGEventPost - kern_return_t postHIDVirtualKey(UInt8 virtualKeyCode, bool postDown); + // Post a key event to HID manager. It posts an event to HID client, a + // much lower level than window manager which's the target from carbon + // CGEventPost + kern_return_t postHIDVirtualKey(UInt8 virtualKeyCode, bool postDown); - // Get keyboard event flags accorfing to keyboard modifiers - CGEventFlags getKeyboardEventFlags() const; - CGEventFlags getDeviceDependedFlags() const; + // Get keyboard event flags accorfing to keyboard modifiers + CGEventFlags getKeyboardEventFlags() const; + CGEventFlags getDeviceDependedFlags() const; - void setKeyboardModifiers(CGKeyCode virtualKey, bool keyDown); + void setKeyboardModifiers(CGKeyCode virtualKey, bool keyDown); - void postKeyboardKey(CGKeyCode virtualKey, bool keyDown); + void postKeyboardKey(CGKeyCode virtualKey, bool keyDown); private: - // OS X uses a physical key if 0 for the 'A' key. synergy reserves - // KeyButton 0 so we offset all OS X physical key ids by this much - // when used as a KeyButton and by minus this much to map a KeyButton - // to a physical button. - enum { - KeyButtonOffset = 1 - }; + // OS X uses a physical key if 0 for the 'A' key. synergy reserves + // KeyButton 0 so we offset all OS X physical key ids by this much + // when used as a KeyButton and by minus this much to map a KeyButton + // to a physical button. + enum { KeyButtonOffset = 1 }; - typedef std::map GroupMap; - typedef std::map VirtualKeyMap; + typedef std::map GroupMap; + typedef std::map VirtualKeyMap; - VirtualKeyMap m_virtualKeyMap; - mutable UInt32 m_deadKeyState; - AutoCFArray m_groups{nullptr, CFRelease}; - GroupMap m_groupMap; - bool m_shiftPressed; - bool m_controlPressed; - bool m_altPressed; - bool m_superPressed; - bool m_capsPressed; + VirtualKeyMap m_virtualKeyMap; + mutable UInt32 m_deadKeyState; + AutoCFArray m_groups{nullptr, CFRelease}; + GroupMap m_groupMap; + bool m_shiftPressed; + bool m_controlPressed; + bool m_altPressed; + bool m_superPressed; + bool m_capsPressed; }; diff --git a/src/lib/platform/OSXMediaKeySupport.h b/src/lib/platform/OSXMediaKeySupport.h index 3cecaacfc..8971cbbc8 100644 --- a/src/lib/platform/OSXMediaKeySupport.h +++ b/src/lib/platform/OSXMediaKeySupport.h @@ -17,17 +17,18 @@ #pragma once -#import #import +#import #include "synergy/key_types.h" #if defined(__cplusplus) extern "C" { #endif -bool fakeNativeMediaKey(KeyID id); -bool isMediaKeyEvent(CGEventRef event); -bool getMediaKeyEventInfo(CGEventRef event, KeyID* keyId, bool* down, bool* isRepeat); +bool fakeNativeMediaKey(KeyID id); +bool isMediaKeyEvent(CGEventRef event); +bool getMediaKeyEventInfo(CGEventRef event, KeyID *keyId, bool *down, + bool *isRepeat); #if defined(__cplusplus) } #endif diff --git a/src/lib/platform/OSXPasteboardPeeker.h b/src/lib/platform/OSXPasteboardPeeker.h index 7d368a7e1..c7971b09b 100644 --- a/src/lib/platform/OSXPasteboardPeeker.h +++ b/src/lib/platform/OSXPasteboardPeeker.h @@ -25,8 +25,8 @@ extern "C" { #endif -CFStringRef getDraggedFileURL(); - +CFStringRef getDraggedFileURL(); + #if defined(__cplusplus) } #endif diff --git a/src/lib/platform/OSXPowerManager.cpp b/src/lib/platform/OSXPowerManager.cpp index 734b2a81d..c17a3b722 100644 --- a/src/lib/platform/OSXPowerManager.cpp +++ b/src/lib/platform/OSXPowerManager.cpp @@ -19,32 +19,25 @@ #include "OSXPowerManager.h" #include "base/Log.h" -OSXPowerManager::OSXPowerManager() -{ -} +OSXPowerManager::OSXPowerManager() {} -OSXPowerManager::~OSXPowerManager() -{ - enableSleep(); -} +OSXPowerManager::~OSXPowerManager() { enableSleep(); } -void OSXPowerManager::disableSleep() -{ - if (!m_sleepPreventionAssertionID) { - CFStringRef reasonForActivity = CFSTR("Synergy application"); - IOReturn result = IOPMAssertionCreateWithName(kIOPMAssertPreventUserIdleDisplaySleep, - kIOPMAssertionLevelOn, reasonForActivity, - &m_sleepPreventionAssertionID); - if (result != kIOReturnSuccess) { - m_sleepPreventionAssertionID = 0; - LOG((CLOG_ERR "failed to disable system idle sleep")); - } +void OSXPowerManager::disableSleep() { + if (!m_sleepPreventionAssertionID) { + CFStringRef reasonForActivity = CFSTR("Synergy application"); + IOReturn result = IOPMAssertionCreateWithName( + kIOPMAssertPreventUserIdleDisplaySleep, kIOPMAssertionLevelOn, + reasonForActivity, &m_sleepPreventionAssertionID); + if (result != kIOReturnSuccess) { + m_sleepPreventionAssertionID = 0; + LOG((CLOG_ERR "failed to disable system idle sleep")); } + } } -void OSXPowerManager::enableSleep() -{ - if (m_sleepPreventionAssertionID) { - IOPMAssertionRelease(m_sleepPreventionAssertionID); - } +void OSXPowerManager::enableSleep() { + if (m_sleepPreventionAssertionID) { + IOPMAssertionRelease(m_sleepPreventionAssertionID); + } } diff --git a/src/lib/platform/OSXPowerManager.h b/src/lib/platform/OSXPowerManager.h index 0babc1dc3..c1168f8fe 100644 --- a/src/lib/platform/OSXPowerManager.h +++ b/src/lib/platform/OSXPowerManager.h @@ -21,28 +21,27 @@ #include -class OSXPowerManager -{ +class OSXPowerManager { public: - OSXPowerManager(); - ~OSXPowerManager(); + OSXPowerManager(); + ~OSXPowerManager(); - /** - * @brief Prevents the system from sleep automatically - */ - void disableSleep(); + /** + * @brief Prevents the system from sleep automatically + */ + void disableSleep(); - /** - * @brief Enable automatically sleeping - */ - void enableSleep(); + /** + * @brief Enable automatically sleeping + */ + void enableSleep(); - OSXPowerManager(const OSXPowerManager&) = delete; - OSXPowerManager& operator=(const OSXPowerManager&) = delete; + OSXPowerManager(const OSXPowerManager &) = delete; + OSXPowerManager &operator=(const OSXPowerManager &) = delete; private: - // handler for assertion preventing the system from going to sleep - IOPMAssertionID m_sleepPreventionAssertionID = 0; + // handler for assertion preventing the system from going to sleep + IOPMAssertionID m_sleepPreventionAssertionID = 0; }; #endif // OSXPOWERMANAGER_H diff --git a/src/lib/platform/OSXScreen.h b/src/lib/platform/OSXScreen.h index 432100f41..c7a1a7d95 100644 --- a/src/lib/platform/OSXScreen.h +++ b/src/lib/platform/OSXScreen.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 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 LICENSE 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 @@ -18,31 +18,30 @@ #pragma once -#include "platform/OSXClipboard.h" -#include "platform/OSXPowerManager.h" -#include "synergy/PlatformScreen.h" -#include "synergy/DragInformation.h" #include "base/EventTypes.h" #include "common/stdmap.h" #include "common/stdvector.h" +#include "platform/OSXClipboard.h" +#include "platform/OSXPowerManager.h" +#include "synergy/DragInformation.h" +#include "synergy/PlatformScreen.h" -#include #include -#include -#include -#include #include +#include +#include +#include +#include #include extern "C" { - typedef int CGSConnectionID; - CGError CGSSetConnectionProperty(CGSConnectionID cid, CGSConnectionID targetCID, CFStringRef key, CFTypeRef value); - int _CGSDefaultConnection(); -} +typedef int CGSConnectionID; +CGError CGSSetConnectionProperty(CGSConnectionID cid, CGSConnectionID targetCID, + CFStringRef key, CFTypeRef value); +int _CGSDefaultConnection(); +} - -template -class CondVar; +template class CondVar; class EventQueueTimer; class Mutex; class Thread; @@ -54,298 +53,295 @@ class Mutex; //! Implementation of IPlatformScreen for OS X class OSXScreen : public PlatformScreen { public: - OSXScreen(IEventQueue* events, - bool isPrimary, - bool enableLangSync = false, - lib::synergy::ClientScrollDirection scrollDirection = lib::synergy::ClientScrollDirection::SERVER); + OSXScreen(IEventQueue *events, bool isPrimary, bool enableLangSync = false, + lib::synergy::ClientScrollDirection scrollDirection = + lib::synergy::ClientScrollDirection::SERVER); - virtual ~OSXScreen(); + virtual ~OSXScreen(); - IEventQueue* getEvents() const { return m_events; } + IEventQueue *getEvents() const { return m_events; } - // IScreen overrides - void* getEventTarget() const override; - bool getClipboard(ClipboardID id, IClipboard*) const override; - void getShape(SInt32& x, SInt32& y, - SInt32& width, SInt32& height) const override; - void getCursorPos(SInt32& x, SInt32& y) const override; + // IScreen overrides + void *getEventTarget() const override; + bool getClipboard(ClipboardID id, IClipboard *) const override; + void getShape(SInt32 &x, SInt32 &y, SInt32 &width, + SInt32 &height) const override; + void getCursorPos(SInt32 &x, SInt32 &y) const override; - // IPrimaryScreen overrides - void reconfigure(UInt32 activeSides) override; - void warpCursor(SInt32 x, SInt32 y) override; - UInt32 registerHotKey(KeyID key, KeyModifierMask mask) override; - void unregisterHotKey(UInt32 id) override; - void fakeInputBegin() override; - void fakeInputEnd() override; - SInt32 getJumpZoneSize() const override; - bool isAnyMouseButtonDown(UInt32& buttonID) const override; - void getCursorCenter(SInt32& x, SInt32& y) const override; + // IPrimaryScreen overrides + void reconfigure(UInt32 activeSides) override; + void warpCursor(SInt32 x, SInt32 y) override; + UInt32 registerHotKey(KeyID key, KeyModifierMask mask) override; + void unregisterHotKey(UInt32 id) override; + void fakeInputBegin() override; + void fakeInputEnd() override; + SInt32 getJumpZoneSize() const override; + bool isAnyMouseButtonDown(UInt32 &buttonID) const override; + void getCursorCenter(SInt32 &x, SInt32 &y) const override; - // ISecondaryScreen overrides - void fakeMouseButton(ButtonID id, bool press) override; - void fakeMouseMove(SInt32 x, SInt32 y) override; - void fakeMouseRelativeMove(SInt32 dx, SInt32 dy) const override; - void fakeMouseWheel(SInt32 xDelta, SInt32 yDelta) const override; + // ISecondaryScreen overrides + void fakeMouseButton(ButtonID id, bool press) override; + void fakeMouseMove(SInt32 x, SInt32 y) override; + void fakeMouseRelativeMove(SInt32 dx, SInt32 dy) const override; + void fakeMouseWheel(SInt32 xDelta, SInt32 yDelta) const override; + + // IPlatformScreen overrides + void enable() override; + void disable() override; + void enter() override; + bool leave() override; + bool setClipboard(ClipboardID, const IClipboard *) override; + void checkClipboards() override; + void openScreensaver(bool notify) override; + void closeScreensaver() override; + void screensaver(bool activate) override; + void resetOptions() override; + void setOptions(const OptionsList &options) override; + void setSequenceNumber(UInt32) override; + bool isPrimary() const override; + void fakeDraggingFiles(DragFileList fileList) override; + String &getDraggingFilename() override; + String getSecureInputApp() const override; + + const String &getDropTarget() const override { return m_dropTarget; } + void waitForCarbonLoop() const; - // IPlatformScreen overrides - void enable() override; - void disable() override; - void enter() override; - bool leave() override; - bool setClipboard(ClipboardID, const IClipboard*) override; - void checkClipboards() override; - void openScreensaver(bool notify) override; - void closeScreensaver() override; - void screensaver(bool activate) override; - void resetOptions() override; - void setOptions(const OptionsList& options) override; - void setSequenceNumber(UInt32) override; - bool isPrimary() const override; - void fakeDraggingFiles(DragFileList fileList) override; - String& getDraggingFilename() override; - String getSecureInputApp() const override; - - const String& getDropTarget() const override { return m_dropTarget; } - void waitForCarbonLoop() const; - protected: - // IPlatformScreen overrides - void handleSystemEvent(const Event&, void*) override; - void updateButtons() override; - IKeyState* getKeyState() const override; + // IPlatformScreen overrides + void handleSystemEvent(const Event &, void *) override; + void updateButtons() override; + IKeyState *getKeyState() const override; private: - bool updateScreenShape(); - bool updateScreenShape(const CGDirectDisplayID, const CGDisplayChangeSummaryFlags); - void postMouseEvent(CGPoint&) const; - - // convenience function to send events - void sendEvent(Event::Type type, void* = NULL) const; - void sendClipboardEvent(Event::Type type, ClipboardID id) const; + bool updateScreenShape(); + bool updateScreenShape(const CGDirectDisplayID, + const CGDisplayChangeSummaryFlags); + void postMouseEvent(CGPoint &) const; - // message handlers - bool onMouseMove(CGFloat mx, CGFloat my); - // mouse button handler. pressed is true if this is a mousedown - // event, false if it is a mouseup event. macButton is the index - // of the button pressed using the mac button mapping. - bool onMouseButton(bool pressed, UInt16 macButton); - bool onMouseWheel(SInt32 xDelta, SInt32 yDelta) const; - - void constructMouseButtonEventMap(); + // convenience function to send events + void sendEvent(Event::Type type, void * = NULL) const; + void sendClipboardEvent(Event::Type type, ClipboardID id) const; - bool onKey(CGEventRef event); + // message handlers + bool onMouseMove(CGFloat mx, CGFloat my); + // mouse button handler. pressed is true if this is a mousedown + // event, false if it is a mouseup event. macButton is the index + // of the button pressed using the mac button mapping. + bool onMouseButton(bool pressed, UInt16 macButton); + bool onMouseWheel(SInt32 xDelta, SInt32 yDelta) const; - void onMediaKey(CGEventRef event); - - bool onHotKey(EventRef event) const; - - // Added here to allow the carbon cursor hack to be called. - void showCursor(); - void hideCursor(); + void constructMouseButtonEventMap(); - // map synergy mouse button to mac buttons - ButtonID mapSynergyButtonToMac(UInt16) const; + bool onKey(CGEventRef event); - // map mac mouse button to synergy buttons - ButtonID mapMacButtonToSynergy(UInt16) const; + void onMediaKey(CGEventRef event); - // map mac scroll wheel value to a synergy scroll wheel value - SInt32 mapScrollWheelToSynergy(SInt32) const; + bool onHotKey(EventRef event) const; - // map synergy scroll wheel value to a mac scroll wheel value - SInt32 mapScrollWheelFromSynergy(SInt32) const; + // Added here to allow the carbon cursor hack to be called. + void showCursor(); + void hideCursor(); - // get the current scroll wheel speed - double getScrollSpeed() const; + // map synergy mouse button to mac buttons + ButtonID mapSynergyButtonToMac(UInt16) const; - // enable/disable drag handling for buttons 3 and up - void enableDragTimer(bool enable); + // map mac mouse button to synergy buttons + ButtonID mapMacButtonToSynergy(UInt16) const; - // drag timer handler - void handleDrag(const Event&, void*); + // map mac scroll wheel value to a synergy scroll wheel value + SInt32 mapScrollWheelToSynergy(SInt32) const; - // clipboard check timer handler - void handleClipboardCheck(const Event&, void*); + // map synergy scroll wheel value to a mac scroll wheel value + SInt32 mapScrollWheelFromSynergy(SInt32) const; - // Resolution switch callback - static void displayReconfigurationCallback(CGDirectDisplayID, - CGDisplayChangeSummaryFlags, void*); + // get the current scroll wheel speed + double getScrollSpeed() const; - // fast user switch callback - static pascal OSStatus - userSwitchCallback(EventHandlerCallRef nextHandler, - EventRef theEvent, void* inUserData); - - // sleep / wakeup support - void watchSystemPowerThread(void*); - static void testCanceled(CFRunLoopTimerRef timer, void*info); - static void powerChangeCallback(void* refcon, io_service_t service, - natural_t messageType, void* messageArgument); - void handlePowerChangeRequest(natural_t messageType, - void* messageArgument); + // enable/disable drag handling for buttons 3 and up + void enableDragTimer(bool enable); + + // drag timer handler + void handleDrag(const Event &, void *); + + // clipboard check timer handler + void handleClipboardCheck(const Event &, void *); + + // Resolution switch callback + static void displayReconfigurationCallback(CGDirectDisplayID, + CGDisplayChangeSummaryFlags, + void *); + + // fast user switch callback + static pascal OSStatus userSwitchCallback(EventHandlerCallRef nextHandler, + EventRef theEvent, + void *inUserData); + + // sleep / wakeup support + void watchSystemPowerThread(void *); + static void testCanceled(CFRunLoopTimerRef timer, void *info); + static void powerChangeCallback(void *refcon, io_service_t service, + natural_t messageType, void *messageArgument); + void handlePowerChangeRequest(natural_t messageType, void *messageArgument); + + void handleConfirmSleep(const Event &event, void *); + + // global hotkey operating mode + static bool isGlobalHotKeyOperatingModeAvailable(); + static void setGlobalHotKeysEnabled(bool enabled); + static bool getGlobalHotKeysEnabled(); + + // Quartz event tap support + static CGEventRef handleCGInputEvent(CGEventTapProxy proxy, CGEventType type, + CGEventRef event, void *refcon); + static CGEventRef handleCGInputEventSecondary(CGEventTapProxy proxy, + CGEventType type, + CGEventRef event, void *refcon); + + // convert CFString to char* + static char *CFStringRefToUTF8String(CFStringRef aString); + + void getDropTargetThread(void *); - void handleConfirmSleep(const Event& event, void*); - - // global hotkey operating mode - static bool isGlobalHotKeyOperatingModeAvailable(); - static void setGlobalHotKeysEnabled(bool enabled); - static bool getGlobalHotKeysEnabled(); - - // Quartz event tap support - static CGEventRef handleCGInputEvent(CGEventTapProxy proxy, - CGEventType type, - CGEventRef event, - void* refcon); - static CGEventRef handleCGInputEventSecondary(CGEventTapProxy proxy, - CGEventType type, - CGEventRef event, - void* refcon); - - // convert CFString to char* - static char* CFStringRefToUTF8String(CFStringRef aString); - - void getDropTargetThread(void*); - private: - struct HotKeyItem { - public: - HotKeyItem(UInt32, UInt32); - HotKeyItem(EventHotKeyRef, UInt32, UInt32); + struct HotKeyItem { + public: + HotKeyItem(UInt32, UInt32); + HotKeyItem(EventHotKeyRef, UInt32, UInt32); - EventHotKeyRef getRef() const; + EventHotKeyRef getRef() const; - bool operator<(const HotKeyItem&) const; + bool operator<(const HotKeyItem &) const; - private: - EventHotKeyRef m_ref; - UInt32 m_keycode; - UInt32 m_mask; - }; + private: + EventHotKeyRef m_ref; + UInt32 m_keycode; + UInt32 m_mask; + }; - enum EMouseButtonState { - kMouseButtonUp = 0, - kMouseButtonDragged, - kMouseButtonDown, - kMouseButtonStateMax - }; - + enum EMouseButtonState { + kMouseButtonUp = 0, + kMouseButtonDragged, + kMouseButtonDown, + kMouseButtonStateMax + }; - class MouseButtonState { - public: - void set(UInt32 button, EMouseButtonState state); - bool any(); - void reset(); - void overwrite(UInt32 buttons); + class MouseButtonState { + public: + void set(UInt32 button, EMouseButtonState state); + bool any(); + void reset(); + void overwrite(UInt32 buttons); - bool test(UInt32 button) const; - SInt8 getFirstButtonDown() const; - private: - std::bitset m_buttons; - }; + bool test(UInt32 button) const; + SInt8 getFirstButtonDown() const; - typedef std::map HotKeyMap; - typedef std::vector HotKeyIDList; - typedef std::map ModifierHotKeyMap; - typedef std::map HotKeyToIDMap; + private: + std::bitset m_buttons; + }; - // true if screen is being used as a primary screen, false otherwise - bool m_isPrimary; + typedef std::map HotKeyMap; + typedef std::vector HotKeyIDList; + typedef std::map ModifierHotKeyMap; + typedef std::map HotKeyToIDMap; - // true if mouse has entered the screen - bool m_isOnScreen; + // true if screen is being used as a primary screen, false otherwise + bool m_isPrimary; - // the display - CGDirectDisplayID m_displayID; + // true if mouse has entered the screen + bool m_isOnScreen; - // screen shape stuff - SInt32 m_x, m_y; - SInt32 m_w, m_h; - SInt32 m_xCenter, m_yCenter; + // the display + CGDirectDisplayID m_displayID; - // mouse state - mutable SInt32 m_xCursor, m_yCursor; - mutable bool m_cursorPosValid; - - /* FIXME: this data structure is explicitly marked mutable due - to a need to track the state of buttons since the remote - side only lets us know of change events, and because the - fakeMouseButton button method is marked 'const'. This is - Evil, and this should be moved to a place where it need not - be mutable as soon as possible. */ - mutable MouseButtonState m_buttonState; - typedef std::map MouseButtonEventMapType; - std::vector MouseButtonEventMap; + // screen shape stuff + SInt32 m_x, m_y; + SInt32 m_w, m_h; + SInt32 m_xCenter, m_yCenter; - bool m_cursorHidden; - SInt32 m_dragNumButtonsDown; - Point m_dragLastPoint; - EventQueueTimer* m_dragTimer; + // mouse state + mutable SInt32 m_xCursor, m_yCursor; + mutable bool m_cursorPosValid; - // keyboard stuff - OSXKeyState* m_keyState; + /* FIXME: this data structure is explicitly marked mutable due + to a need to track the state of buttons since the remote + side only lets us know of change events, and because the + fakeMouseButton button method is marked 'const'. This is + Evil, and this should be moved to a place where it need not + be mutable as soon as possible. */ + mutable MouseButtonState m_buttonState; + typedef std::map MouseButtonEventMapType; + std::vector MouseButtonEventMap; - // clipboards - OSXClipboard m_pasteboard; - UInt32 m_sequenceNumber; + bool m_cursorHidden; + SInt32 m_dragNumButtonsDown; + Point m_dragLastPoint; + EventQueueTimer *m_dragTimer; - // screen saver stuff - OSXScreenSaver* m_screensaver; - bool m_screensaverNotify; + // keyboard stuff + OSXKeyState *m_keyState; - // clipboard stuff - bool m_ownClipboard; - EventQueueTimer* m_clipboardTimer; + // clipboards + OSXClipboard m_pasteboard; + UInt32 m_sequenceNumber; - // window object that gets user input events when the server - // has focus. - WindowRef m_hiddenWindow; - // window object that gets user input events when the server - // does not have focus. - WindowRef m_userInputWindow; + // screen saver stuff + OSXScreenSaver *m_screensaver; + bool m_screensaverNotify; - // fast user switching - EventHandlerRef m_switchEventHandlerRef; + // clipboard stuff + bool m_ownClipboard; + EventQueueTimer *m_clipboardTimer; - // sleep / wakeup - Mutex* m_pmMutex; - Thread* m_pmWatchThread; - CondVar* m_pmThreadReady; - CFRunLoopRef m_pmRunloop; - io_connect_t m_pmRootPort; + // window object that gets user input events when the server + // has focus. + WindowRef m_hiddenWindow; + // window object that gets user input events when the server + // does not have focus. + WindowRef m_userInputWindow; - // hot key stuff - HotKeyMap m_hotKeys; - HotKeyIDList m_oldHotKeyIDs; - ModifierHotKeyMap m_modifierHotKeys; - UInt32 m_activeModifierHotKey; - KeyModifierMask m_activeModifierHotKeyMask; - HotKeyToIDMap m_hotKeyToIDMap; + // fast user switching + EventHandlerRef m_switchEventHandlerRef; - // global hotkey operating mode - static bool s_testedForGHOM; - static bool s_hasGHOM; - - // Quartz input event support - CFMachPortRef m_eventTapPort; - CFRunLoopSourceRef m_eventTapRLSR; + // sleep / wakeup + Mutex *m_pmMutex; + Thread *m_pmWatchThread; + CondVar *m_pmThreadReady; + CFRunLoopRef m_pmRunloop; + io_connect_t m_pmRootPort; - // for double click coalescing. - double m_lastClickTime; - int m_clickState; - SInt32 m_lastSingleClickXCursor; - SInt32 m_lastSingleClickYCursor; + // hot key stuff + HotKeyMap m_hotKeys; + HotKeyIDList m_oldHotKeyIDs; + ModifierHotKeyMap m_modifierHotKeys; + UInt32 m_activeModifierHotKey; + KeyModifierMask m_activeModifierHotKeyMask; + HotKeyToIDMap m_hotKeyToIDMap; - IEventQueue* m_events; - - std::unique_ptr m_getDropTargetThread; - String m_dropTarget; + // global hotkey operating mode + static bool s_testedForGHOM; + static bool s_hasGHOM; + + // Quartz input event support + CFMachPortRef m_eventTapPort; + CFRunLoopSourceRef m_eventTapRLSR; + + // for double click coalescing. + double m_lastClickTime; + int m_clickState; + SInt32 m_lastSingleClickXCursor; + SInt32 m_lastSingleClickYCursor; + + IEventQueue *m_events; + + std::unique_ptr m_getDropTargetThread; + String m_dropTarget; #if defined(MAC_OS_X_VERSION_10_7) - Mutex* m_carbonLoopMutex; - CondVar* m_carbonLoopReady; + Mutex *m_carbonLoopMutex; + CondVar *m_carbonLoopReady; #endif - OSXPowerManager m_powerManager; + OSXPowerManager m_powerManager; - class OSXScreenImpl* m_impl; + class OSXScreenImpl *m_impl; }; diff --git a/src/lib/platform/OSXScreenSaver.cpp b/src/lib/platform/OSXScreenSaver.cpp index 608febd38..ec43589f3 100644 --- a/src/lib/platform/OSXScreenSaver.cpp +++ b/src/lib/platform/OSXScreenSaver.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 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 LICENSE 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 @@ -18,187 +18,159 @@ #import "platform/OSXScreenSaver.h" +#import "base/IEventQueue.h" +#import "base/Log.h" #import "platform/OSXScreenSaverUtil.h" #import "synergy/IPrimaryScreen.h" -#import "base/Log.h" -#import "base/IEventQueue.h" #import #import // TODO: upgrade deprecated function usage in these functions. -void getProcessSerialNumber(const char* name, ProcessSerialNumber& psn); -bool isScreenSaverEngine(const ProcessSerialNumber& psn); +void getProcessSerialNumber(const char *name, ProcessSerialNumber &psn); +bool isScreenSaverEngine(const ProcessSerialNumber &psn); // // OSXScreenSaver // -OSXScreenSaver::OSXScreenSaver(IEventQueue* events, void* eventTarget) : - m_eventTarget(eventTarget), - m_enabled(true), - m_events(events) -{ - m_autoReleasePool = screenSaverUtilCreatePool(); - m_screenSaverController = screenSaverUtilCreateController(); +OSXScreenSaver::OSXScreenSaver(IEventQueue *events, void *eventTarget) + : m_eventTarget(eventTarget), m_enabled(true), m_events(events) { + m_autoReleasePool = screenSaverUtilCreatePool(); + m_screenSaverController = screenSaverUtilCreateController(); + + // install launch/termination event handlers + EventTypeSpec launchEventTypes[2]; + launchEventTypes[0].eventClass = kEventClassApplication; + launchEventTypes[0].eventKind = kEventAppLaunched; + launchEventTypes[1].eventClass = kEventClassApplication; + launchEventTypes[1].eventKind = kEventAppTerminated; + + EventHandlerUPP launchTerminationEventHandler = + NewEventHandlerUPP(launchTerminationCallback); + InstallApplicationEventHandler(launchTerminationEventHandler, 2, + launchEventTypes, this, + &m_launchTerminationEventHandlerRef); + DisposeEventHandlerUPP(launchTerminationEventHandler); + + m_screenSaverPSN.highLongOfPSN = 0; + m_screenSaverPSN.lowLongOfPSN = 0; + + if (isActive()) { + getProcessSerialNumber("ScreenSaverEngine", m_screenSaverPSN); + } +} + +OSXScreenSaver::~OSXScreenSaver() { + RemoveEventHandler(m_launchTerminationEventHandlerRef); + // screenSaverUtilReleaseController(m_screenSaverController); + screenSaverUtilReleasePool(m_autoReleasePool); +} + +void OSXScreenSaver::enable() { + m_enabled = true; + screenSaverUtilEnable(m_screenSaverController); +} + +void OSXScreenSaver::disable() { + m_enabled = false; + screenSaverUtilDisable(m_screenSaverController); +} + +void OSXScreenSaver::activate() { + screenSaverUtilActivate(m_screenSaverController); +} + +void OSXScreenSaver::deactivate() { + screenSaverUtilDeactivate(m_screenSaverController, m_enabled); +} + +bool OSXScreenSaver::isActive() const { + return (screenSaverUtilIsActive(m_screenSaverController) != 0); +} + +void OSXScreenSaver::processLaunched(ProcessSerialNumber psn) { + if (isScreenSaverEngine(psn)) { + m_screenSaverPSN = psn; + LOG((CLOG_DEBUG1 "screen saver engine launched, enabled=%d", m_enabled)); + if (m_enabled) { + m_events->addEvent(Event( + m_events->forIPrimaryScreen().screensaverActivated(), m_eventTarget)); + } + } +} + +void OSXScreenSaver::processTerminated(ProcessSerialNumber psn) { + if (m_screenSaverPSN.highLongOfPSN == psn.highLongOfPSN && + m_screenSaverPSN.lowLongOfPSN == psn.lowLongOfPSN) { + LOG((CLOG_DEBUG1 "screen saver engine terminated, enabled=%d", m_enabled)); + if (m_enabled) { + m_events->addEvent( + Event(m_events->forIPrimaryScreen().screensaverDeactivated(), + m_eventTarget)); + } - // install launch/termination event handlers - EventTypeSpec launchEventTypes[2]; - launchEventTypes[0].eventClass = kEventClassApplication; - launchEventTypes[0].eventKind = kEventAppLaunched; - launchEventTypes[1].eventClass = kEventClassApplication; - launchEventTypes[1].eventKind = kEventAppTerminated; - - EventHandlerUPP launchTerminationEventHandler = - NewEventHandlerUPP(launchTerminationCallback); - InstallApplicationEventHandler(launchTerminationEventHandler, 2, - launchEventTypes, this, - &m_launchTerminationEventHandlerRef); - DisposeEventHandlerUPP(launchTerminationEventHandler); - m_screenSaverPSN.highLongOfPSN = 0; - m_screenSaverPSN.lowLongOfPSN = 0; - - if (isActive()) { - getProcessSerialNumber("ScreenSaverEngine", m_screenSaverPSN); + m_screenSaverPSN.lowLongOfPSN = 0; + } +} + +pascal OSStatus OSXScreenSaver::launchTerminationCallback( + EventHandlerCallRef nextHandler, EventRef theEvent, void *userData) { + OSStatus result; + ProcessSerialNumber psn; + EventParamType actualType; + ByteCount actualSize; + + result = + GetEventParameter(theEvent, kEventParamProcessID, typeProcessSerialNumber, + &actualType, sizeof(psn), &actualSize, &psn); + + if ((result == noErr) && (actualSize > 0) && + (actualType == typeProcessSerialNumber)) { + OSXScreenSaver *screenSaver = (OSXScreenSaver *)userData; + UInt32 eventKind = GetEventKind(theEvent); + if (eventKind == kEventAppLaunched) { + screenSaver->processLaunched(psn); + } else if (eventKind == kEventAppTerminated) { + screenSaver->processTerminated(psn); } -} - -OSXScreenSaver::~OSXScreenSaver() -{ - RemoveEventHandler(m_launchTerminationEventHandlerRef); -// screenSaverUtilReleaseController(m_screenSaverController); - screenSaverUtilReleasePool(m_autoReleasePool); -} - -void -OSXScreenSaver::enable() -{ - m_enabled = true; - screenSaverUtilEnable(m_screenSaverController); -} - -void -OSXScreenSaver::disable() -{ - m_enabled = false; - screenSaverUtilDisable(m_screenSaverController); -} - -void -OSXScreenSaver::activate() -{ - screenSaverUtilActivate(m_screenSaverController); -} - -void -OSXScreenSaver::deactivate() -{ - screenSaverUtilDeactivate(m_screenSaverController, m_enabled); -} - -bool -OSXScreenSaver::isActive() const -{ - return (screenSaverUtilIsActive(m_screenSaverController) != 0); -} - -void -OSXScreenSaver::processLaunched(ProcessSerialNumber psn) -{ - if (isScreenSaverEngine(psn)) { - m_screenSaverPSN = psn; - LOG((CLOG_DEBUG1 "screen saver engine launched, enabled=%d", m_enabled)); - if (m_enabled) { - m_events->addEvent( - Event(m_events->forIPrimaryScreen().screensaverActivated(), - m_eventTarget)); - } - } -} - -void -OSXScreenSaver::processTerminated(ProcessSerialNumber psn) -{ - if (m_screenSaverPSN.highLongOfPSN == psn.highLongOfPSN && - m_screenSaverPSN.lowLongOfPSN == psn.lowLongOfPSN) { - LOG((CLOG_DEBUG1 "screen saver engine terminated, enabled=%d", m_enabled)); - if (m_enabled) { - m_events->addEvent( - Event(m_events->forIPrimaryScreen().screensaverDeactivated(), - m_eventTarget)); - } - - m_screenSaverPSN.highLongOfPSN = 0; - m_screenSaverPSN.lowLongOfPSN = 0; - } -} - -pascal OSStatus -OSXScreenSaver::launchTerminationCallback( - EventHandlerCallRef nextHandler, - EventRef theEvent, void* userData) -{ - OSStatus result; - ProcessSerialNumber psn; - EventParamType actualType; - ByteCount actualSize; - - result = GetEventParameter(theEvent, kEventParamProcessID, - typeProcessSerialNumber, &actualType, - sizeof(psn), &actualSize, &psn); - - if ((result == noErr) && - (actualSize > 0) && - (actualType == typeProcessSerialNumber)) { - OSXScreenSaver* screenSaver = (OSXScreenSaver*)userData; - UInt32 eventKind = GetEventKind(theEvent); - if (eventKind == kEventAppLaunched) { - screenSaver->processLaunched(psn); - } - else if (eventKind == kEventAppTerminated) { - screenSaver->processTerminated(psn); - } - } - return (CallNextEventHandler(nextHandler, theEvent)); + } + return (CallNextEventHandler(nextHandler, theEvent)); } #pragma GCC diagnostic ignored "-Wdeprecated-declarations" -void -getProcessSerialNumber(const char* name, ProcessSerialNumber& psn) -{ - ProcessInfoRec procInfo; - Str31 procName; // pascal string. first byte holds length. - memset(&procInfo, 0, sizeof(procInfo)); - procInfo.processName = procName; - procInfo.processInfoLength = sizeof(ProcessInfoRec); +void getProcessSerialNumber(const char *name, ProcessSerialNumber &psn) { + ProcessInfoRec procInfo; + Str31 procName; // pascal string. first byte holds length. + memset(&procInfo, 0, sizeof(procInfo)); + procInfo.processName = procName; + procInfo.processInfoLength = sizeof(ProcessInfoRec); - ProcessSerialNumber checkPsn; - OSErr err = GetNextProcess(&checkPsn); - while (err == 0) { - memset(procName, 0, sizeof(procName)); - err = GetProcessInformation(&checkPsn, &procInfo); - if (err != 0) { - break; - } - if (strcmp(name, (const char*)&procName[1]) == 0) { - psn = checkPsn; - break; - } - err = GetNextProcess(&checkPsn); + ProcessSerialNumber checkPsn; + OSErr err = GetNextProcess(&checkPsn); + while (err == 0) { + memset(procName, 0, sizeof(procName)); + err = GetProcessInformation(&checkPsn, &procInfo); + if (err != 0) { + break; } + if (strcmp(name, (const char *)&procName[1]) == 0) { + psn = checkPsn; + break; + } + err = GetNextProcess(&checkPsn); + } } -bool -isScreenSaverEngine(const ProcessSerialNumber& psn) -{ - CFStringRef processName; - OSStatus err = CopyProcessName(&psn, &processName); - bool result = (err == 0 && CFEqual(CFSTR("ScreenSaverEngine"), processName)); - CFRelease(processName); +bool isScreenSaverEngine(const ProcessSerialNumber &psn) { + CFStringRef processName; + OSStatus err = CopyProcessName(&psn, &processName); + bool result = (err == 0 && CFEqual(CFSTR("ScreenSaverEngine"), processName)); + CFRelease(processName); - return result; + return result; } #pragma GCC diagnostic error "-Wdeprecated-declarations" diff --git a/src/lib/platform/OSXScreenSaver.h b/src/lib/platform/OSXScreenSaver.h index 2427ba8d4..518e9e120 100644 --- a/src/lib/platform/OSXScreenSaver.h +++ b/src/lib/platform/OSXScreenSaver.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -27,33 +27,31 @@ class IEventQueue; //! OSX screen saver implementation class OSXScreenSaver : public IScreenSaver { public: - OSXScreenSaver(IEventQueue* events, void* eventTarget); - virtual ~OSXScreenSaver(); + OSXScreenSaver(IEventQueue *events, void *eventTarget); + virtual ~OSXScreenSaver(); - // IScreenSaver overrides - virtual void enable(); - virtual void disable(); - virtual void activate(); - virtual void deactivate(); - virtual bool isActive() const; - -private: - void processLaunched(ProcessSerialNumber psn); - void processTerminated(ProcessSerialNumber psn); - - static pascal OSStatus - launchTerminationCallback( - EventHandlerCallRef nextHandler, - EventRef theEvent, void* userData); + // IScreenSaver overrides + virtual void enable(); + virtual void disable(); + virtual void activate(); + virtual void deactivate(); + virtual bool isActive() const; private: - // the target for the events we generate - void* m_eventTarget; + void processLaunched(ProcessSerialNumber psn); + void processTerminated(ProcessSerialNumber psn); - bool m_enabled; - void* m_screenSaverController; - void* m_autoReleasePool; - EventHandlerRef m_launchTerminationEventHandlerRef; - ProcessSerialNumber m_screenSaverPSN; - IEventQueue* m_events; + static pascal OSStatus launchTerminationCallback( + EventHandlerCallRef nextHandler, EventRef theEvent, void *userData); + +private: + // the target for the events we generate + void *m_eventTarget; + + bool m_enabled; + void *m_screenSaverController; + void *m_autoReleasePool; + EventHandlerRef m_launchTerminationEventHandlerRef; + ProcessSerialNumber m_screenSaverPSN; + IEventQueue *m_events; }; diff --git a/src/lib/platform/OSXScreenSaverControl.h b/src/lib/platform/OSXScreenSaverControl.h index 01608c676..f9dd6a0a0 100644 --- a/src/lib/platform/OSXScreenSaverControl.h +++ b/src/lib/platform/OSXScreenSaverControl.h @@ -6,7 +6,7 @@ * 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 LICENSE 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 @@ -31,8 +31,7 @@ - (BOOL)screenSaverIsRunning; @end - -@interface ScreenSaverController:NSObject +@interface ScreenSaverController : NSObject + controller; + monitor; @@ -51,4 +50,3 @@ - (double)screenSaverTimeRemaining; @end - diff --git a/src/lib/platform/OSXScreenSaverUtil.h b/src/lib/platform/OSXScreenSaverUtil.h index 0fa5727de..10aed7c9f 100644 --- a/src/lib/platform/OSXScreenSaverUtil.h +++ b/src/lib/platform/OSXScreenSaverUtil.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -24,16 +24,16 @@ extern "C" { #endif -void* screenSaverUtilCreatePool(); -void screenSaverUtilReleasePool(void*); +void *screenSaverUtilCreatePool(); +void screenSaverUtilReleasePool(void *); -void* screenSaverUtilCreateController(); -void screenSaverUtilReleaseController(void*); -void screenSaverUtilEnable(void*); -void screenSaverUtilDisable(void*); -void screenSaverUtilActivate(void*); -void screenSaverUtilDeactivate(void*, int isEnabled); -int screenSaverUtilIsActive(void*); +void *screenSaverUtilCreateController(); +void screenSaverUtilReleaseController(void *); +void screenSaverUtilEnable(void *); +void screenSaverUtilDisable(void *); +void screenSaverUtilActivate(void *); +void screenSaverUtilDeactivate(void *, int isEnabled); +int screenSaverUtilIsActive(void *); #if defined(__cplusplus) } diff --git a/src/lib/platform/OSXUchrKeyResource.cpp b/src/lib/platform/OSXUchrKeyResource.cpp index 4d2ca7e35..baf0350ba 100644 --- a/src/lib/platform/OSXUchrKeyResource.cpp +++ b/src/lib/platform/OSXUchrKeyResource.cpp @@ -1,11 +1,11 @@ /* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2016 Symless Ltd. - * + * * 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 LICENSE 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 @@ -23,274 +23,242 @@ // OSXUchrKeyResource // -OSXUchrKeyResource::OSXUchrKeyResource(const void* resource, - UInt32 keyboardType) : - m_m(NULL), - m_cti(NULL), - m_sdi(NULL), - m_sri(NULL), - m_st(NULL) -{ - m_resource = static_cast(resource); - if (m_resource == NULL) { - return; - } +OSXUchrKeyResource::OSXUchrKeyResource(const void *resource, + UInt32 keyboardType) + : m_m(NULL), m_cti(NULL), m_sdi(NULL), m_sri(NULL), m_st(NULL) { + m_resource = static_cast(resource); + if (m_resource == NULL) { + return; + } - // find the keyboard info for the current keyboard type - const UCKeyboardTypeHeader* th = NULL; - const UCKeyboardLayout* r = m_resource; - for (ItemCount i = 0; i < r->keyboardTypeCount; ++i) { - if (keyboardType >= r->keyboardTypeList[i].keyboardTypeFirst && - keyboardType <= r->keyboardTypeList[i].keyboardTypeLast) { - th = r->keyboardTypeList + i; - break; - } - if (r->keyboardTypeList[i].keyboardTypeFirst == 0) { - // found the default. use it unless we find a match. - th = r->keyboardTypeList + i; - } + // find the keyboard info for the current keyboard type + const UCKeyboardTypeHeader *th = NULL; + const UCKeyboardLayout *r = m_resource; + for (ItemCount i = 0; i < r->keyboardTypeCount; ++i) { + if (keyboardType >= r->keyboardTypeList[i].keyboardTypeFirst && + keyboardType <= r->keyboardTypeList[i].keyboardTypeLast) { + th = r->keyboardTypeList + i; + break; } - if (th == NULL) { - // cannot find a suitable keyboard type - return; + if (r->keyboardTypeList[i].keyboardTypeFirst == 0) { + // found the default. use it unless we find a match. + th = r->keyboardTypeList + i; } + } + if (th == NULL) { + // cannot find a suitable keyboard type + return; + } - // get tables for keyboard type - const UInt8* const base = reinterpret_cast(m_resource); - m_m = reinterpret_cast(base + - th->keyModifiersToTableNumOffset); - m_cti = reinterpret_cast(base + - th->keyToCharTableIndexOffset); - m_sdi = reinterpret_cast(base + - th->keySequenceDataIndexOffset); - if (th->keyStateRecordsIndexOffset != 0) { - m_sri = reinterpret_cast(base + - th->keyStateRecordsIndexOffset); - } - if (th->keyStateTerminatorsOffset != 0) { - m_st = reinterpret_cast(base + - th->keyStateTerminatorsOffset); - } + // get tables for keyboard type + const UInt8 *const base = reinterpret_cast(m_resource); + m_m = reinterpret_cast( + base + th->keyModifiersToTableNumOffset); + m_cti = reinterpret_cast( + base + th->keyToCharTableIndexOffset); + m_sdi = reinterpret_cast( + base + th->keySequenceDataIndexOffset); + if (th->keyStateRecordsIndexOffset != 0) { + m_sri = reinterpret_cast( + base + th->keyStateRecordsIndexOffset); + } + if (th->keyStateTerminatorsOffset != 0) { + m_st = reinterpret_cast( + base + th->keyStateTerminatorsOffset); + } - // find the space key, but only if it can combine with dead keys. - // a dead key followed by a space yields the non-dead version of - // the dead key. - m_spaceOutput = 0xffffu; - UInt32 table = getTableForModifier(0); - for (UInt32 button = 0, n = getNumButtons(); button < n; ++button) { - KeyID id = getKey(table, button); - if (id == 0x20) { - UCKeyOutput c = - reinterpret_cast(base + - m_cti->keyToCharTableOffsets[table])[button]; - if ((c & kUCKeyOutputTestForIndexMask) == - kUCKeyOutputStateIndexMask) { - m_spaceOutput = (c & kUCKeyOutputGetIndexMask); - break; - } - } + // find the space key, but only if it can combine with dead keys. + // a dead key followed by a space yields the non-dead version of + // the dead key. + m_spaceOutput = 0xffffu; + UInt32 table = getTableForModifier(0); + for (UInt32 button = 0, n = getNumButtons(); button < n; ++button) { + KeyID id = getKey(table, button); + if (id == 0x20) { + UCKeyOutput c = reinterpret_cast( + base + m_cti->keyToCharTableOffsets[table])[button]; + if ((c & kUCKeyOutputTestForIndexMask) == kUCKeyOutputStateIndexMask) { + m_spaceOutput = (c & kUCKeyOutputGetIndexMask); + break; + } } + } } -bool -OSXUchrKeyResource::isValid() const -{ - return (m_m != NULL); +bool OSXUchrKeyResource::isValid() const { return (m_m != NULL); } + +UInt32 OSXUchrKeyResource::getNumModifierCombinations() const { + // only 32 (not 256) because the righthanded modifier bits are ignored + return 32; } -UInt32 -OSXUchrKeyResource::getNumModifierCombinations() const -{ - // only 32 (not 256) because the righthanded modifier bits are ignored - return 32; +UInt32 OSXUchrKeyResource::getNumTables() const { + return m_cti->keyToCharTableCount; } -UInt32 -OSXUchrKeyResource::getNumTables() const -{ - return m_cti->keyToCharTableCount; +UInt32 OSXUchrKeyResource::getNumButtons() const { + return m_cti->keyToCharTableSize; } -UInt32 -OSXUchrKeyResource::getNumButtons() const -{ - return m_cti->keyToCharTableSize; +UInt32 OSXUchrKeyResource::getTableForModifier(UInt32 mask) const { + if (mask >= m_m->modifiersCount) { + return m_m->defaultTableNum; + } else { + return m_m->tableNum[mask]; + } } -UInt32 -OSXUchrKeyResource::getTableForModifier(UInt32 mask) const -{ - if (mask >= m_m->modifiersCount) { - return m_m->defaultTableNum; - } - else { - return m_m->tableNum[mask]; - } -} +KeyID OSXUchrKeyResource::getKey(UInt32 table, UInt32 button) const { + assert(table < getNumTables()); + assert(button < getNumButtons()); -KeyID -OSXUchrKeyResource::getKey(UInt32 table, UInt32 button) const -{ - assert(table < getNumTables()); - assert(button < getNumButtons()); - - const UInt8* const base = reinterpret_cast(m_resource); - const UCKeyOutput* cPtr = reinterpret_cast(base + - m_cti->keyToCharTableOffsets[table]); + const UInt8 *const base = reinterpret_cast(m_resource); + const UCKeyOutput *cPtr = reinterpret_cast( + base + m_cti->keyToCharTableOffsets[table]); const UCKeyOutput c = cPtr[button]; - KeySequence keys; - switch (c & kUCKeyOutputTestForIndexMask) { - case kUCKeyOutputStateIndexMask: - if (!getDeadKey(keys, c & kUCKeyOutputGetIndexMask)) { - return kKeyNone; - } - break; + KeySequence keys; + switch (c & kUCKeyOutputTestForIndexMask) { + case kUCKeyOutputStateIndexMask: + if (!getDeadKey(keys, c & kUCKeyOutputGetIndexMask)) { + return kKeyNone; + } + break; + + case kUCKeyOutputSequenceIndexMask: + default: + if (!addSequence(keys, c)) { + return kKeyNone; + } + break; + } + + // XXX -- no support for multiple characters + if (keys.size() != 1) { + return kKeyNone; + } + + return keys.front(); +} + +bool OSXUchrKeyResource::getDeadKey(KeySequence &keys, UInt16 index) const { + if (m_sri == NULL || index >= m_sri->keyStateRecordCount) { + // XXX -- should we be using some other fallback? + return false; + } + + UInt16 state = 0; + if (!getKeyRecord(keys, index, state)) { + return false; + } + if (state == 0) { + // not a dead key + return true; + } + + // no dead keys if we couldn't find the space key + if (m_spaceOutput == 0xffffu) { + return false; + } + + // the dead key should not have put anything in the key list + if (!keys.empty()) { + return false; + } + + // get the character generated by pressing the space key after the + // dead key. if we're still in a compose state afterwards then we're + // confused so we bail. + if (!getKeyRecord(keys, m_spaceOutput, state) || state != 0) { + return false; + } + + // convert keys to their dead counterparts + for (KeySequence::iterator i = keys.begin(); i != keys.end(); ++i) { + *i = synergy::KeyMap::getDeadKey(*i); + } + + return true; +} + +bool OSXUchrKeyResource::getKeyRecord(KeySequence &keys, UInt16 index, + UInt16 &state) const { + const UInt8 *const base = reinterpret_cast(m_resource); + const UCKeyStateRecord *sr = reinterpret_cast( + base + m_sri->keyStateRecordOffsets[index]); + const UCKeyStateEntryTerminal *kset = + reinterpret_cast(sr->stateEntryData); + + UInt16 nextState = 0; + bool found = false; + if (state == 0) { + found = true; + nextState = sr->stateZeroNextState; + if (!addSequence(keys, sr->stateZeroCharData)) { + return false; + } + } else { + // we have a next entry + switch (sr->stateEntryFormat) { + case kUCKeyStateEntryTerminalFormat: + for (UInt16 j = 0; j < sr->stateEntryCount; ++j) { + if (kset[j].curState == state) { + if (!addSequence(keys, kset[j].charData)) { + return false; + } + nextState = 0; + found = true; + break; + } + } + break; + + case kUCKeyStateEntryRangeFormat: + // XXX -- not supported yet + break; - case kUCKeyOutputSequenceIndexMask: default: - if (!addSequence(keys, c)) { - return kKeyNone; - } - break; + // XXX -- unknown format + return false; } - - // XXX -- no support for multiple characters - if (keys.size() != 1) { - return kKeyNone; + } + if (!found) { + // use a terminator + if (m_st != NULL && state < m_st->keyStateTerminatorCount) { + if (!addSequence(keys, m_st->keyStateTerminators[state - 1])) { + return false; + } } + nextState = sr->stateZeroNextState; + if (!addSequence(keys, sr->stateZeroCharData)) { + return false; + } + } - return keys.front(); + // next + state = nextState; + + return true; } -bool -OSXUchrKeyResource::getDeadKey( - KeySequence& keys, UInt16 index) const -{ - if (m_sri == NULL || index >= m_sri->keyStateRecordCount) { - // XXX -- should we be using some other fallback? - return false; +bool OSXUchrKeyResource::addSequence(KeySequence &keys, UCKeyCharSeq c) const { + if ((c & kUCKeyOutputTestForIndexMask) == kUCKeyOutputSequenceIndexMask) { + UInt16 index = (c & kUCKeyOutputGetIndexMask); + if (index < m_sdi->charSequenceCount && + m_sdi->charSequenceOffsets[index] != + m_sdi->charSequenceOffsets[index + 1]) { + // XXX -- sequences not supported yet + return false; } + } - UInt16 state = 0; - if (!getKeyRecord(keys, index, state)) { - return false; - } - if (state == 0) { - // not a dead key - return true; + if (c != 0xfffe && c != 0xffff) { + KeyID id = unicharToKeyID(c); + if (id != kKeyNone) { + keys.push_back(id); } + } - // no dead keys if we couldn't find the space key - if (m_spaceOutput == 0xffffu) { - return false; - } - - // the dead key should not have put anything in the key list - if (!keys.empty()) { - return false; - } - - // get the character generated by pressing the space key after the - // dead key. if we're still in a compose state afterwards then we're - // confused so we bail. - if (!getKeyRecord(keys, m_spaceOutput, state) || state != 0) { - return false; - } - - // convert keys to their dead counterparts - for (KeySequence::iterator i = keys.begin(); i != keys.end(); ++i) { - *i = synergy::KeyMap::getDeadKey(*i); - } - - return true; -} - -bool -OSXUchrKeyResource::getKeyRecord( - KeySequence& keys, UInt16 index, UInt16& state) const -{ - const UInt8* const base = reinterpret_cast(m_resource); - const UCKeyStateRecord* sr = - reinterpret_cast(base + - m_sri->keyStateRecordOffsets[index]); - const UCKeyStateEntryTerminal* kset = - reinterpret_cast(sr->stateEntryData); - - UInt16 nextState = 0; - bool found = false; - if (state == 0) { - found = true; - nextState = sr->stateZeroNextState; - if (!addSequence(keys, sr->stateZeroCharData)) { - return false; - } - } - else { - // we have a next entry - switch (sr->stateEntryFormat) { - case kUCKeyStateEntryTerminalFormat: - for (UInt16 j = 0; j < sr->stateEntryCount; ++j) { - if (kset[j].curState == state) { - if (!addSequence(keys, kset[j].charData)) { - return false; - } - nextState = 0; - found = true; - break; - } - } - break; - - case kUCKeyStateEntryRangeFormat: - // XXX -- not supported yet - break; - - default: - // XXX -- unknown format - return false; - } - } - if (!found) { - // use a terminator - if (m_st != NULL && state < m_st->keyStateTerminatorCount) { - if (!addSequence(keys, m_st->keyStateTerminators[state - 1])) { - return false; - } - } - nextState = sr->stateZeroNextState; - if (!addSequence(keys, sr->stateZeroCharData)) { - return false; - } - } - - // next - state = nextState; - - return true; -} - -bool -OSXUchrKeyResource::addSequence( - KeySequence& keys, UCKeyCharSeq c) const -{ - if ((c & kUCKeyOutputTestForIndexMask) == kUCKeyOutputSequenceIndexMask) { - UInt16 index = (c & kUCKeyOutputGetIndexMask); - if (index < m_sdi->charSequenceCount && - m_sdi->charSequenceOffsets[index] != - m_sdi->charSequenceOffsets[index + 1]) { - // XXX -- sequences not supported yet - return false; - } - } - - if (c != 0xfffe && c != 0xffff) { - KeyID id = unicharToKeyID(c); - if (id != kKeyNone) { - keys.push_back(id); - } - } - - return true; + return true; } diff --git a/src/lib/platform/OSXUchrKeyResource.h b/src/lib/platform/OSXUchrKeyResource.h index bbb8fd2b7..677e7d8bd 100644 --- a/src/lib/platform/OSXUchrKeyResource.h +++ b/src/lib/platform/OSXUchrKeyResource.h @@ -1,11 +1,11 @@ /* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2016 Symless Ltd. - * + * * 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 LICENSE 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 @@ -17,8 +17,8 @@ #pragma once -#include "synergy/KeyState.h" #include "platform/IOSXKeyResource.h" +#include "synergy/KeyState.h" #include @@ -26,30 +26,29 @@ typedef TISInputSourceRef KeyLayout; class OSXUchrKeyResource : public IOSXKeyResource { public: - OSXUchrKeyResource(const void*, UInt32 keyboardType); - - // KeyResource overrides - virtual bool isValid() const; - virtual UInt32 getNumModifierCombinations() const; - virtual UInt32 getNumTables() const; - virtual UInt32 getNumButtons() const; - virtual UInt32 getTableForModifier(UInt32 mask) const; - virtual KeyID getKey(UInt32 table, UInt32 button) const; - + OSXUchrKeyResource(const void *, UInt32 keyboardType); + + // KeyResource overrides + virtual bool isValid() const; + virtual UInt32 getNumModifierCombinations() const; + virtual UInt32 getNumTables() const; + virtual UInt32 getNumButtons() const; + virtual UInt32 getTableForModifier(UInt32 mask) const; + virtual KeyID getKey(UInt32 table, UInt32 button) const; + private: - typedef std::vector KeySequence; - - bool getDeadKey(KeySequence& keys, UInt16 index) const; - bool getKeyRecord(KeySequence& keys, - UInt16 index, UInt16& state) const; - bool addSequence(KeySequence& keys, UCKeyCharSeq c) const; - + typedef std::vector KeySequence; + + bool getDeadKey(KeySequence &keys, UInt16 index) const; + bool getKeyRecord(KeySequence &keys, UInt16 index, UInt16 &state) const; + bool addSequence(KeySequence &keys, UCKeyCharSeq c) const; + private: - const UCKeyboardLayout* m_resource; - const UCKeyModifiersToTableNum* m_m; - const UCKeyToCharTableIndex* m_cti; - const UCKeySequenceDataIndex* m_sdi; - const UCKeyStateRecordsIndex* m_sri; - const UCKeyStateTerminators* m_st; - UInt16 m_spaceOutput; + const UCKeyboardLayout *m_resource; + const UCKeyModifiersToTableNum *m_m; + const UCKeyToCharTableIndex *m_cti; + const UCKeySequenceDataIndex *m_sdi; + const UCKeyStateRecordsIndex *m_sri; + const UCKeyStateTerminators *m_st; + UInt16 m_spaceOutput; }; diff --git a/src/lib/platform/XWindowsClipboard.cpp b/src/lib/platform/XWindowsClipboard.cpp index 17967dea3..e085cff5b 100644 --- a/src/lib/platform/XWindowsClipboard.cpp +++ b/src/lib/platform/XWindowsClipboard.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -18,1519 +18,1395 @@ #include "platform/XWindowsClipboard.h" -#include "platform/XWindowsClipboardTextConverter.h" -#include "platform/XWindowsClipboardUCS2Converter.h" -#include "platform/XWindowsClipboardUTF8Converter.h" -#include "platform/XWindowsClipboardHTMLConverter.h" -#include "platform/XWindowsClipboardBMPConverter.h" -#include "platform/XWindowsUtil.h" -#include "mt/Thread.h" #include "arch/Arch.h" #include "base/Log.h" #include "base/Stopwatch.h" #include "common/stdvector.h" +#include "mt/Thread.h" +#include "platform/XWindowsClipboardBMPConverter.h" +#include "platform/XWindowsClipboardHTMLConverter.h" +#include "platform/XWindowsClipboardTextConverter.h" +#include "platform/XWindowsClipboardUCS2Converter.h" +#include "platform/XWindowsClipboardUTF8Converter.h" +#include "platform/XWindowsUtil.h" +#include #include #include #include -#include // // XWindowsClipboard // -XWindowsClipboard::XWindowsClipboard(Display* display, - Window window, ClipboardID id) : - m_display(display), - m_window(window), - m_id(id), - m_open(false), - m_time(0), - m_owner(false), - m_timeOwned(0), - m_timeLost(0) -{ - // get some atoms - m_atomTargets = XInternAtom(m_display, "TARGETS", False); - m_atomMultiple = XInternAtom(m_display, "MULTIPLE", False); - m_atomTimestamp = XInternAtom(m_display, "TIMESTAMP", False); - m_atomInteger = XInternAtom(m_display, "INTEGER", False); - m_atomAtom = XInternAtom(m_display, "ATOM", False); - m_atomAtomPair = XInternAtom(m_display, "ATOM_PAIR", False); - m_atomData = XInternAtom(m_display, "CLIP_TEMPORARY", False); - m_atomINCR = XInternAtom(m_display, "INCR", False); - m_atomMotifClipLock = XInternAtom(m_display, "_MOTIF_CLIP_LOCK", False); - m_atomMotifClipHeader = XInternAtom(m_display, "_MOTIF_CLIP_HEADER", False); - m_atomMotifClipAccess = XInternAtom(m_display, - "_MOTIF_CLIP_LOCK_ACCESS_VALID", False); - m_atomGDKSelection = XInternAtom(m_display, "GDK_SELECTION", False); +XWindowsClipboard::XWindowsClipboard(Display *display, Window window, + ClipboardID id) + : m_display(display), m_window(window), m_id(id), m_open(false), m_time(0), + m_owner(false), m_timeOwned(0), m_timeLost(0) { + // get some atoms + m_atomTargets = XInternAtom(m_display, "TARGETS", False); + m_atomMultiple = XInternAtom(m_display, "MULTIPLE", False); + m_atomTimestamp = XInternAtom(m_display, "TIMESTAMP", False); + m_atomInteger = XInternAtom(m_display, "INTEGER", False); + m_atomAtom = XInternAtom(m_display, "ATOM", False); + m_atomAtomPair = XInternAtom(m_display, "ATOM_PAIR", False); + m_atomData = XInternAtom(m_display, "CLIP_TEMPORARY", False); + m_atomINCR = XInternAtom(m_display, "INCR", False); + m_atomMotifClipLock = XInternAtom(m_display, "_MOTIF_CLIP_LOCK", False); + m_atomMotifClipHeader = XInternAtom(m_display, "_MOTIF_CLIP_HEADER", False); + m_atomMotifClipAccess = + XInternAtom(m_display, "_MOTIF_CLIP_LOCK_ACCESS_VALID", False); + m_atomGDKSelection = XInternAtom(m_display, "GDK_SELECTION", False); - // set selection atom based on clipboard id - switch (id) { - case kClipboardClipboard: - m_selection = XInternAtom(m_display, "CLIPBOARD", False); - break; + // set selection atom based on clipboard id + switch (id) { + case kClipboardClipboard: + m_selection = XInternAtom(m_display, "CLIPBOARD", False); + break; - default: - m_selection = XA_PRIMARY; - break; - } + default: + m_selection = XA_PRIMARY; + break; + } - // add converters, most desired first - m_converters.push_back(new XWindowsClipboardHTMLConverter(m_display, - "text/html")); - m_converters.push_back(new XWindowsClipboardHTMLConverter(m_display, - "application/x-moz-nativehtml")); - m_converters.push_back(new XWindowsClipboardBMPConverter(m_display)); - m_converters.push_back(new XWindowsClipboardUTF8Converter(m_display, - "text/plain;charset=UTF-8", true)); - m_converters.push_back(new XWindowsClipboardUTF8Converter(m_display, - "text/plain;charset=utf-8", true)); - m_converters.push_back(new XWindowsClipboardUTF8Converter(m_display, - "UTF8_STRING")); - m_converters.push_back(new XWindowsClipboardUCS2Converter(m_display, - "text/plain;charset=ISO-10646-UCS-2")); - m_converters.push_back(new XWindowsClipboardUCS2Converter(m_display, - "text/unicode")); - m_converters.push_back(new XWindowsClipboardTextConverter(m_display, - "text/plain")); - m_converters.push_back(new XWindowsClipboardTextConverter(m_display, - "STRING")); + // add converters, most desired first + m_converters.push_back( + new XWindowsClipboardHTMLConverter(m_display, "text/html")); + m_converters.push_back(new XWindowsClipboardHTMLConverter( + m_display, "application/x-moz-nativehtml")); + m_converters.push_back(new XWindowsClipboardBMPConverter(m_display)); + m_converters.push_back(new XWindowsClipboardUTF8Converter( + m_display, "text/plain;charset=UTF-8", true)); + m_converters.push_back(new XWindowsClipboardUTF8Converter( + m_display, "text/plain;charset=utf-8", true)); + m_converters.push_back( + new XWindowsClipboardUTF8Converter(m_display, "UTF8_STRING")); + m_converters.push_back(new XWindowsClipboardUCS2Converter( + m_display, "text/plain;charset=ISO-10646-UCS-2")); + m_converters.push_back( + new XWindowsClipboardUCS2Converter(m_display, "text/unicode")); + m_converters.push_back( + new XWindowsClipboardTextConverter(m_display, "text/plain")); + m_converters.push_back( + new XWindowsClipboardTextConverter(m_display, "STRING")); - // we have no data + // we have no data + clearCache(); +} + +XWindowsClipboard::~XWindowsClipboard() { + clearReplies(); + clearConverters(); +} + +void XWindowsClipboard::lost(Time time) { + LOG((CLOG_DEBUG "lost clipboard %d ownership at %d", m_id, time)); + if (m_owner) { + m_owner = false; + m_timeLost = time; clearCache(); + } } -XWindowsClipboard::~XWindowsClipboard() -{ - clearReplies(); - clearConverters(); -} +void XWindowsClipboard::addRequest(Window owner, Window requestor, Atom target, + ::Time time, Atom property) { + // must be for our window and we must have owned the selection + // at the given time. + bool success = false; + if (owner == m_window) { + LOG((CLOG_DEBUG1 + "request for clipboard %d, target %s by 0x%08x (property=%s)", + m_selection, XWindowsUtil::atomToString(m_display, target).c_str(), + requestor, XWindowsUtil::atomToString(m_display, property).c_str())); + if (wasOwnedAtTime(time)) { + if (target == m_atomMultiple && property != None) { + // add a multiple request. property may not be None + // according to ICCCM. + success = insertMultipleReply(requestor, time, property); + } else { + addSimpleRequest(requestor, target, time, property); -void -XWindowsClipboard::lost(Time time) -{ - LOG((CLOG_DEBUG "lost clipboard %d ownership at %d", m_id, time)); - if (m_owner) { - m_owner = false; - m_timeLost = time; - clearCache(); + // addSimpleRequest() will have already handled failure + success = true; + } + } else { + LOG((CLOG_DEBUG1 "failed, not owned at time %d", time)); } + } + + if (!success) { + // send failure + LOG((CLOG_DEBUG1 "failed")); + insertReply(new Reply(requestor, target, time)); + } + + // send notifications that are pending + pushReplies(); } -void -XWindowsClipboard::addRequest(Window owner, Window requestor, - Atom target, ::Time time, Atom property) -{ - // must be for our window and we must have owned the selection - // at the given time. - bool success = false; - if (owner == m_window) { - LOG((CLOG_DEBUG1 "request for clipboard %d, target %s by 0x%08x (property=%s)", m_selection, XWindowsUtil::atomToString(m_display, target).c_str(), requestor, XWindowsUtil::atomToString(m_display, property).c_str())); - if (wasOwnedAtTime(time)) { - if (target == m_atomMultiple && property != None) { - // add a multiple request. property may not be None - // according to ICCCM. - success = insertMultipleReply(requestor, time, property); - } - else { - addSimpleRequest(requestor, target, time, property); +bool XWindowsClipboard::addSimpleRequest(Window requestor, Atom target, + ::Time time, Atom property) { + // obsolete requestors may supply a None property. in + // that case we use the target as the property to store + // the conversion. + if (property == None) { + property = target; + } - // addSimpleRequest() will have already handled failure - success = true; - } - } - else { - LOG((CLOG_DEBUG1 "failed, not owned at time %d", time)); + // handle targets + String data; + Atom type = None; + int format = 0; + if (target == m_atomTargets) { + type = getTargetsData(data, &format); + } else if (target == m_atomTimestamp) { + type = getTimestampData(data, &format); + } else { + IXWindowsClipboardConverter *converter = getConverter(target); + if (converter != nullptr) { + IClipboard::EFormat clipboardFormat = converter->getFormat(); + if (m_added[clipboardFormat]) { + try { + data = converter->fromIClipboard(m_data[clipboardFormat]); + format = converter->getDataSize(); + type = converter->getAtom(); + } catch (...) { + // ignore -- cannot convert + LOG((CLOG_WARN "error while converting clipboard data")); } + } } + } - if (!success) { - // send failure - LOG((CLOG_DEBUG1 "failed")); - insertReply(new Reply(requestor, target, time)); - } - - // send notifications that are pending - pushReplies(); -} - -bool -XWindowsClipboard::addSimpleRequest(Window requestor, - Atom target, ::Time time, Atom property) -{ - // obsolete requestors may supply a None property. in - // that case we use the target as the property to store - // the conversion. - if (property == None) { - property = target; - } - - // handle targets - String data; - Atom type = None; - int format = 0; - if (target == m_atomTargets) { - type = getTargetsData(data, &format); - } - else if (target == m_atomTimestamp) { - type = getTimestampData(data, &format); - } - else { - IXWindowsClipboardConverter* converter = getConverter(target); - if (converter != nullptr) { - IClipboard::EFormat clipboardFormat = converter->getFormat(); - if (m_added[clipboardFormat]) { - try { - data = converter->fromIClipboard(m_data[clipboardFormat]); - format = converter->getDataSize(); - type = converter->getAtom(); - } - catch (...) { - // ignore -- cannot convert - LOG((CLOG_WARN "error while converting clipboard data")); - } - } - } - } - - if (type != None) { - // success - LOG((CLOG_DEBUG1 "success")); - insertReply(new Reply(requestor, target, time, - property, data, type, format)); - return true; - } - else { - // failure - LOG((CLOG_DEBUG1 "failed")); - insertReply(new Reply(requestor, target, time)); - return false; - } -} - -bool -XWindowsClipboard::processRequest(Window requestor, - ::Time /*time*/, Atom property) -{ - ReplyMap::iterator index = m_replies.find(requestor); - if (index == m_replies.end()) { - // unknown requestor window - return false; - } - LOG((CLOG_DEBUG1 "received property %s delete from 0x08%x", XWindowsUtil::atomToString(m_display, property).c_str(), requestor)); - - // find the property in the known requests. it should be the - // first property but we'll check 'em all if we have to. - ReplyList& replies = index->second; - for (ReplyList::iterator index2 = replies.begin(); - index2 != replies.end(); ++index2) { - Reply* reply = *index2; - if (reply->m_replied && reply->m_property == property) { - // if reply is complete then remove it and start the - // next one. - pushReplies(index, replies, index2); - return true; - } - } - - return false; -} - -bool -XWindowsClipboard::destroyRequest(Window requestor) -{ - ReplyMap::iterator index = m_replies.find(requestor); - if (index == m_replies.end()) { - // unknown requestor window - return false; - } - - // destroy all replies for this window - clearReplies(index->second); - m_replies.erase(index); - - // note -- we don't stop watching the window for events because - // we're called in response to the window being destroyed. - + if (type != None) { + // success + LOG((CLOG_DEBUG1 "success")); + insertReply( + new Reply(requestor, target, time, property, data, type, format)); return true; + } else { + // failure + LOG((CLOG_DEBUG1 "failed")); + insertReply(new Reply(requestor, target, time)); + return false; + } } -Window -XWindowsClipboard::getWindow() const -{ - return m_window; +bool XWindowsClipboard::processRequest(Window requestor, ::Time /*time*/, + Atom property) { + ReplyMap::iterator index = m_replies.find(requestor); + if (index == m_replies.end()) { + // unknown requestor window + return false; + } + LOG((CLOG_DEBUG1 "received property %s delete from 0x08%x", + XWindowsUtil::atomToString(m_display, property).c_str(), requestor)); + + // find the property in the known requests. it should be the + // first property but we'll check 'em all if we have to. + ReplyList &replies = index->second; + for (ReplyList::iterator index2 = replies.begin(); index2 != replies.end(); + ++index2) { + Reply *reply = *index2; + if (reply->m_replied && reply->m_property == property) { + // if reply is complete then remove it and start the + // next one. + pushReplies(index, replies, index2); + return true; + } + } + + return false; } -Atom -XWindowsClipboard::getSelection() const -{ - return m_selection; +bool XWindowsClipboard::destroyRequest(Window requestor) { + ReplyMap::iterator index = m_replies.find(requestor); + if (index == m_replies.end()) { + // unknown requestor window + return false; + } + + // destroy all replies for this window + clearReplies(index->second); + m_replies.erase(index); + + // note -- we don't stop watching the window for events because + // we're called in response to the window being destroyed. + + return true; } -bool -XWindowsClipboard::empty() -{ - assert(m_open); +Window XWindowsClipboard::getWindow() const { return m_window; } - LOG((CLOG_DEBUG "empty clipboard %d", m_id)); +Atom XWindowsClipboard::getSelection() const { return m_selection; } - // assert ownership of clipboard - XSetSelectionOwner(m_display, m_selection, m_window, m_time); - if (XGetSelectionOwner(m_display, m_selection) != m_window) { - LOG((CLOG_DEBUG "failed to grab clipboard %d", m_id)); - return false; +bool XWindowsClipboard::empty() { + assert(m_open); + + LOG((CLOG_DEBUG "empty clipboard %d", m_id)); + + // assert ownership of clipboard + XSetSelectionOwner(m_display, m_selection, m_window, m_time); + if (XGetSelectionOwner(m_display, m_selection) != m_window) { + LOG((CLOG_DEBUG "failed to grab clipboard %d", m_id)); + return false; + } + + // clear all data. since we own the data now, the cache is up + // to date. + clearCache(); + m_cached = true; + + // FIXME -- actually delete motif clipboard items? + // FIXME -- do anything to motif clipboard properties? + + // save time + m_timeOwned = m_time; + m_timeLost = 0; + + // we're the owner now + m_owner = true; + LOG((CLOG_DEBUG "grabbed clipboard %d", m_id)); + + return true; +} + +void XWindowsClipboard::add(EFormat format, const String &data) { + assert(m_open); + assert(m_owner); + + LOG((CLOG_DEBUG "add %d bytes to clipboard %d format: %d", data.size(), m_id, + format)); + + m_data[format] = data; + m_added[format] = true; + + // FIXME -- set motif clipboard item? +} + +bool XWindowsClipboard::open(Time time) const { + if (m_open) { + LOG((CLOG_DEBUG "failed to open clipboard: already opened")); + return false; + } + + LOG((CLOG_DEBUG "open clipboard %d", m_id)); + + // assume not motif + m_motif = false; + + // lock clipboard + if (m_id == kClipboardClipboard) { + if (!motifLockClipboard()) { + return false; } - // clear all data. since we own the data now, the cache is up - // to date. - clearCache(); - m_cached = true; + // check if motif owns the selection. unlock motif clipboard + // if it does not. + m_motif = motifOwnsClipboard(); + LOG((CLOG_DEBUG1 "motif does %sown clipboard", m_motif ? "" : "not ")); + if (!m_motif) { + motifUnlockClipboard(); + } + } - // FIXME -- actually delete motif clipboard items? - // FIXME -- do anything to motif clipboard properties? + // now open + m_open = true; + m_time = time; - // save time + // be sure to flush the cache later if it's dirty + m_checkCache = true; + + return true; +} + +void XWindowsClipboard::close() const { + assert(m_open); + + LOG((CLOG_DEBUG "close clipboard %d", m_id)); + + // unlock clipboard + if (m_motif) { + motifUnlockClipboard(); + } + + m_motif = false; + m_open = false; +} + +IClipboard::Time XWindowsClipboard::getTime() const { + checkCache(); + return m_timeOwned; +} + +bool XWindowsClipboard::has(EFormat format) const { + assert(m_open); + + fillCache(); + return m_added[format]; +} + +String XWindowsClipboard::get(EFormat format) const { + assert(m_open); + + fillCache(); + return m_data[format]; +} + +void XWindowsClipboard::clearConverters() { + for (ConverterList::iterator index = m_converters.begin(); + index != m_converters.end(); ++index) { + delete *index; + } + m_converters.clear(); +} + +IXWindowsClipboardConverter * +XWindowsClipboard::getConverter(Atom target, bool onlyIfNotAdded) const { + IXWindowsClipboardConverter *converter = nullptr; + for (ConverterList::const_iterator index = m_converters.begin(); + index != m_converters.end(); ++index) { + converter = *index; + if (converter->getAtom() == target) { + break; + } + } + if (converter == nullptr) { + LOG((CLOG_DEBUG1 " no converter for target %s", + XWindowsUtil::atomToString(m_display, target).c_str())); + return nullptr; + } + + // optionally skip already handled targets + if (onlyIfNotAdded && m_added[converter->getFormat()]) { + LOG((CLOG_DEBUG1 " skipping handled format %d", converter->getFormat())); + return nullptr; + } + + return converter; +} + +void XWindowsClipboard::checkCache() const { + if (!m_checkCache) { + return; + } + m_checkCache = false; + + // get the time the clipboard ownership was taken by the current + // owner. + if (m_motif) { + m_timeOwned = motifGetTime(); + } else { + m_timeOwned = icccmGetTime(); + } + + // if we can't get the time then use the time passed to us + if (m_timeOwned == 0) { m_timeOwned = m_time; - m_timeLost = 0; + } - // we're the owner now - m_owner = true; - LOG((CLOG_DEBUG "grabbed clipboard %d", m_id)); - - return true; + // if the cache is dirty then flush it + if (m_timeOwned != m_cacheTime) { + clearCache(); + } } -void -XWindowsClipboard::add(EFormat format, const String& data) -{ - assert(m_open); - assert(m_owner); - - LOG((CLOG_DEBUG "add %d bytes to clipboard %d format: %d", data.size(), m_id, format)); - - m_data[format] = data; - m_added[format] = true; - - // FIXME -- set motif clipboard item? +void XWindowsClipboard::clearCache() const { + const_cast(this)->doClearCache(); } -bool -XWindowsClipboard::open(Time time) const -{ - if (m_open) { - LOG((CLOG_DEBUG "failed to open clipboard: already opened")); - return false; - } - - LOG((CLOG_DEBUG "open clipboard %d", m_id)); - - // assume not motif - m_motif = false; - - // lock clipboard - if (m_id == kClipboardClipboard) { - if (!motifLockClipboard()) { - return false; - } - - // check if motif owns the selection. unlock motif clipboard - // if it does not. - m_motif = motifOwnsClipboard(); - LOG((CLOG_DEBUG1 "motif does %sown clipboard", m_motif ? "" : "not ")); - if (!m_motif) { - motifUnlockClipboard(); - } - } - - // now open - m_open = true; - m_time = time; - - // be sure to flush the cache later if it's dirty - m_checkCache = true; - - return true; +void XWindowsClipboard::doClearCache() { + m_checkCache = false; + m_cached = false; + for (SInt32 index = 0; index < kNumFormats; ++index) { + m_data[index] = ""; + m_added[index] = false; + } } -void -XWindowsClipboard::close() const -{ - assert(m_open); - - LOG((CLOG_DEBUG "close clipboard %d", m_id)); - - // unlock clipboard - if (m_motif) { - motifUnlockClipboard(); - } - - m_motif = false; - m_open = false; +void XWindowsClipboard::fillCache() const { + // get the selection data if not already cached + checkCache(); + if (!m_cached) { + const_cast(this)->doFillCache(); + } } -IClipboard::Time -XWindowsClipboard::getTime() const -{ - checkCache(); - return m_timeOwned; +void XWindowsClipboard::doFillCache() { + if (m_motif) { + motifFillCache(); + } else { + icccmFillCache(); + } + m_checkCache = false; + m_cached = true; + m_cacheTime = m_timeOwned; } -bool -XWindowsClipboard::has(EFormat format) const -{ - assert(m_open); +void XWindowsClipboard::icccmFillCache() { + LOG((CLOG_DEBUG "icccm fill clipboard %d", m_id)); - fillCache(); - return m_added[format]; -} - -String -XWindowsClipboard::get(EFormat format) const -{ - assert(m_open); - - fillCache(); - return m_data[format]; -} - -void -XWindowsClipboard::clearConverters() -{ - for (ConverterList::iterator index = m_converters.begin(); - index != m_converters.end(); ++index) { - delete *index; - } - m_converters.clear(); -} - -IXWindowsClipboardConverter* -XWindowsClipboard::getConverter(Atom target, bool onlyIfNotAdded) const -{ - IXWindowsClipboardConverter* converter = nullptr; - for (ConverterList::const_iterator index = m_converters.begin(); - index != m_converters.end(); ++index) { - converter = *index; - if (converter->getAtom() == target) { - break; - } - } - if (converter == nullptr) { - LOG((CLOG_DEBUG1 " no converter for target %s", XWindowsUtil::atomToString(m_display, target).c_str())); - return nullptr; - } - - // optionally skip already handled targets - if (onlyIfNotAdded && m_added[converter->getFormat()]) { - LOG((CLOG_DEBUG1 " skipping handled format %d", converter->getFormat())); - return nullptr; - } - - return converter; -} - -void -XWindowsClipboard::checkCache() const -{ - if (!m_checkCache) { - return; - } - m_checkCache = false; - - // get the time the clipboard ownership was taken by the current - // owner. - if (m_motif) { - m_timeOwned = motifGetTime(); - } - else { - m_timeOwned = icccmGetTime(); - } - - // if we can't get the time then use the time passed to us - if (m_timeOwned == 0) { - m_timeOwned = m_time; - } - - // if the cache is dirty then flush it - if (m_timeOwned != m_cacheTime) { - clearCache(); - } -} - -void -XWindowsClipboard::clearCache() const -{ - const_cast(this)->doClearCache(); -} - -void -XWindowsClipboard::doClearCache() -{ - m_checkCache = false; - m_cached = false; - for (SInt32 index = 0; index < kNumFormats; ++index) { - m_data[index] = ""; - m_added[index] = false; - } -} - -void -XWindowsClipboard::fillCache() const -{ - // get the selection data if not already cached - checkCache(); - if (!m_cached) { - const_cast(this)->doFillCache(); - } -} - -void -XWindowsClipboard::doFillCache() -{ - if (m_motif) { - motifFillCache(); - } - else { - icccmFillCache(); - } - m_checkCache = false; - m_cached = true; - m_cacheTime = m_timeOwned; -} - -void -XWindowsClipboard::icccmFillCache() -{ - LOG((CLOG_DEBUG "icccm fill clipboard %d", m_id)); - - // see if we can get the list of available formats from the selection. - // if not then use a default list of formats. note that some clipboard - // owners are broken and report TARGETS as the type of the TARGETS data - // instead of the correct type ATOM; allow either. - const Atom atomTargets = m_atomTargets; - Atom target; - String data; - if (!icccmGetSelection(atomTargets, &target, &data) || - (target != m_atomAtom && target != m_atomTargets)) { - LOG((CLOG_DEBUG1 "selection doesn't support TARGETS")); - data = ""; - XWindowsUtil::appendAtomData(data, XA_STRING); - } - - XWindowsUtil::convertAtomProperty(data); - auto targets = static_cast(static_cast(data.data())); - const UInt32 numTargets = data.size() / sizeof(Atom); - LOG((CLOG_DEBUG " available targets: %s", XWindowsUtil::atomsToString(m_display, targets, numTargets).c_str())); - - // try each converter in order (because they're in order of - // preference). - for (ConverterList::const_iterator index = m_converters.begin(); - index != m_converters.end(); ++index) { - IXWindowsClipboardConverter* converter = *index; - - // skip already handled targets - if (m_added[converter->getFormat()]) { - continue; - } - - // see if atom is in target list - Atom target = None; - // XXX -- just ask for the converter's target to see if it's - // available rather than checking TARGETS. i've seen clipboard - // owners that don't report all the targets they support. - target = converter->getAtom(); - /* - for (UInt32 i = 0; i < numTargets; ++i) { - if (converter->getAtom() == targets[i]) { - target = targets[i]; - break; - } - } - */ - if (target == None) { - continue; - } - - // get the data - Atom actualTarget; - String targetData; - if (!icccmGetSelection(target, &actualTarget, &targetData)) { - LOG((CLOG_DEBUG1 " no data for target %s", XWindowsUtil::atomToString(m_display, target).c_str())); - continue; - } - - // add to clipboard and note we've done it - IClipboard::EFormat format = converter->getFormat(); - m_data[format] = converter->toIClipboard(targetData); - m_added[format] = true; - LOG((CLOG_DEBUG "added format %d for target %s (%u %s)", format, XWindowsUtil::atomToString(m_display, target).c_str(), targetData.size(), targetData.size() == 1 ? "byte" : "bytes")); - } -} - -bool -XWindowsClipboard::icccmGetSelection(Atom target, - Atom* actualTarget, String* data) const -{ - assert(actualTarget != nullptr); - assert(data != nullptr); - - // request data conversion - CICCCMGetClipboard getter(m_window, m_time, m_atomData); - if (!getter.readClipboard(m_display, m_selection, - target, actualTarget, data)) { - LOG((CLOG_DEBUG1 "can't get data for selection target %s", XWindowsUtil::atomToString(m_display, target).c_str())); - LOGC(getter.m_error, (CLOG_WARN "icccm violation by clipboard owner")); - return false; - } - else if (*actualTarget == None) { - LOG((CLOG_DEBUG1 "selection conversion failed for target %s", XWindowsUtil::atomToString(m_display, target).c_str())); - return false; - } - return true; -} - -IClipboard::Time -XWindowsClipboard::icccmGetTime() const -{ - Atom actualTarget; - String data; - if (icccmGetSelection(m_atomTimestamp, &actualTarget, &data) && - actualTarget == m_atomInteger) { - Time time = *static_cast(static_cast(data.data())); - LOG((CLOG_DEBUG1 "got ICCCM time %d", time)); - return time; - } - else { - // no timestamp - LOG((CLOG_DEBUG1 "can't get ICCCM time")); - return 0; - } -} - -bool -XWindowsClipboard::motifLockClipboard() const -{ - // fail if anybody owns the lock (even us, so this is non-recursive) - Window lockOwner = XGetSelectionOwner(m_display, m_atomMotifClipLock); - if (lockOwner != None) { - LOG((CLOG_DEBUG1 "motif lock owner 0x%08x", lockOwner)); - return false; - } - - // try to grab the lock - // FIXME -- is this right? there's a race condition here -- - // A grabs successfully, B grabs successfully, A thinks it - // still has the grab until it gets a SelectionClear. - Time time = XWindowsUtil::getCurrentTime(m_display, m_window); - XSetSelectionOwner(m_display, m_atomMotifClipLock, m_window, time); - lockOwner = XGetSelectionOwner(m_display, m_atomMotifClipLock); - if (lockOwner != m_window) { - LOG((CLOG_DEBUG1 "motif lock owner 0x%08x", lockOwner)); - return false; - } - - LOG((CLOG_DEBUG1 "locked motif clipboard")); - return true; -} - -void -XWindowsClipboard::motifUnlockClipboard() const -{ - LOG((CLOG_DEBUG1 "unlocked motif clipboard")); - - // fail if we don't own the lock - Window lockOwner = XGetSelectionOwner(m_display, m_atomMotifClipLock); - if (lockOwner != m_window) { - return; - } - - // release lock - Time time = XWindowsUtil::getCurrentTime(m_display, m_window); - XSetSelectionOwner(m_display, m_atomMotifClipLock, None, time); -} - -bool -XWindowsClipboard::motifOwnsClipboard() const -{ - // get the current selection owner - // FIXME -- this can't be right. even if the window is destroyed - // Motif will still have a valid clipboard. how can we tell if - // some other client owns CLIPBOARD? - Window owner = XGetSelectionOwner(m_display, m_selection); - if (owner == None) { - return false; - } - - // get the Motif clipboard header property from the root window - Atom target; - SInt32 format; - String data; - Window root = RootWindow(m_display, DefaultScreen(m_display)); - if (!XWindowsUtil::getWindowProperty(m_display, root, - m_atomMotifClipHeader, - &data, &target, &format, False)) { - return false; - } - - // check the owner window against the current clipboard owner - if (data.size() >= sizeof(MotifClipHeader)) { - MotifClipHeader header; - std::memcpy (&header, data.data(), sizeof(header)); - if ((header.m_id == kMotifClipHeader) && - (static_cast(header.m_selectionOwner) == owner)) { - return true; - } - } - - return false; -} - -void -XWindowsClipboard::motifFillCache() -{ - LOG((CLOG_DEBUG "motif fill clipboard %d", m_id)); - - // get the Motif clipboard header property from the root window - Atom target; - SInt32 format; - String data; - Window root = RootWindow(m_display, DefaultScreen(m_display)); - if (!XWindowsUtil::getWindowProperty(m_display, root, - m_atomMotifClipHeader, - &data, &target, &format, False)) { - return; - } - - MotifClipHeader header; - if (data.size() < sizeof(header)) { // check that the header is okay - return; - } - std::memcpy (&header, data.data(), sizeof(header)); - if (header.m_id != kMotifClipHeader || header.m_numItems < 1) { - return; - } - - // get the Motif item property from the root window - static const int buffer_size = 18 + 20; - char name[buffer_size]; - snprintf(name, buffer_size, "_MOTIF_CLIP_ITEM_%d", header.m_item); - Atom atomItem = XInternAtom(m_display, name, False); + // see if we can get the list of available formats from the selection. + // if not then use a default list of formats. note that some clipboard + // owners are broken and report TARGETS as the type of the TARGETS data + // instead of the correct type ATOM; allow either. + const Atom atomTargets = m_atomTargets; + Atom target; + String data; + if (!icccmGetSelection(atomTargets, &target, &data) || + (target != m_atomAtom && target != m_atomTargets)) { + LOG((CLOG_DEBUG1 "selection doesn't support TARGETS")); data = ""; - if (!XWindowsUtil::getWindowProperty(m_display, root, - atomItem, &data, - &target, &format, False)) { - return; + XWindowsUtil::appendAtomData(data, XA_STRING); + } + + XWindowsUtil::convertAtomProperty(data); + auto targets = + static_cast(static_cast(data.data())); + const UInt32 numTargets = data.size() / sizeof(Atom); + LOG((CLOG_DEBUG " available targets: %s", + XWindowsUtil::atomsToString(m_display, targets, numTargets).c_str())); + + // try each converter in order (because they're in order of + // preference). + for (ConverterList::const_iterator index = m_converters.begin(); + index != m_converters.end(); ++index) { + IXWindowsClipboardConverter *converter = *index; + + // skip already handled targets + if (m_added[converter->getFormat()]) { + continue; } - MotifClipItem item; - if (data.size() < sizeof(item)) { // check that the item is okay - return; - } - std::memcpy (&item, data.data(), sizeof(item)); - if (item.m_id != kMotifClipItem || - item.m_numFormats - item.m_numDeletedFormats < 1) { - return; - } - - // format list is after static item structure elements - const SInt32 numFormats = item.m_numFormats - item.m_numDeletedFormats; - auto formats = static_cast(static_cast(item.m_size + data.data())); - - // get the available formats - typedef std::map MotifFormatMap; - MotifFormatMap motifFormats; - for (SInt32 i = 0; i < numFormats; ++i) { - // get Motif format property from the root window - snprintf(name, buffer_size, "_MOTIF_CLIP_ITEM_%d", formats[i]); - Atom atomFormat = XInternAtom(m_display, name, False); - String data; - if (!XWindowsUtil::getWindowProperty(m_display, root, - atomFormat, &data, - &target, &format, False)) { - continue; - } - - // check that the format is okay - MotifClipFormat motifFormat; - if (data.size() < sizeof(motifFormat)) { - continue; - } - std::memcpy (&motifFormat, data.data(), sizeof(motifFormat)); - if (motifFormat.m_id != kMotifClipFormat || - motifFormat.m_length < 0 || - motifFormat.m_type == None || - motifFormat.m_deleted != 0) { - continue; - } - - // save it - motifFormats.insert(std::make_pair(motifFormat.m_type, data)); - } - //const UInt32 numMotifFormats = motifFormats.size(); - - // try each converter in order (because they're in order of - // preference). - for (ConverterList::const_iterator index = m_converters.begin(); - index != m_converters.end(); ++index) { - IXWindowsClipboardConverter* converter = *index; - - // skip already handled targets - if (m_added[converter->getFormat()]) { - continue; - } - - // see if atom is in target list - MotifFormatMap::const_iterator index2 = - motifFormats.find(converter->getAtom()); - if (index2 == motifFormats.end()) { - continue; - } - - // get format - MotifClipFormat motifFormat; - std::memcpy (&motifFormat, index2->second.data(), sizeof(motifFormat)); - const Atom target = motifFormat.m_type; - - // get the data (finally) - Atom actualTarget; - String targetData; - if (!motifGetSelection(&motifFormat, &actualTarget, &targetData)) { - LOG((CLOG_DEBUG1 " no data for target %s", XWindowsUtil::atomToString(m_display, target).c_str())); - continue; - } - - // add to clipboard and note we've done it - IClipboard::EFormat format = converter->getFormat(); - m_data[format] = converter->toIClipboard(targetData); - m_added[format] = true; - LOG((CLOG_DEBUG "added format %d for target %s", format, XWindowsUtil::atomToString(m_display, target).c_str())); - } -} - -bool -XWindowsClipboard::motifGetSelection(const MotifClipFormat* format, - Atom* actualTarget, String* data) const -{ - // if the current clipboard owner and the owner indicated by the - // motif clip header are the same then transfer via a property on - // the root window, otherwise transfer as a normal ICCCM client. - if (!motifOwnsClipboard()) { - return icccmGetSelection(format->m_type, actualTarget, data); - } - - // use motif way - // FIXME -- this isn't right. it'll only work if the data is - // already stored on the root window and only if it fits in a - // property. motif has some scheme for transferring part by - // part that i don't know. - static const int buffer_size = 18+20; - char name[buffer_size]; - snprintf(name, buffer_size, "_MOTIF_CLIP_ITEM_%d", format->m_data); - Atom target = XInternAtom(m_display, name, False); - Window root = RootWindow(m_display, DefaultScreen(m_display)); - return XWindowsUtil::getWindowProperty(m_display, root, - target, data, - actualTarget, nullptr, False); -} - -IClipboard::Time -XWindowsClipboard::motifGetTime() const -{ - return icccmGetTime(); -} - -bool -XWindowsClipboard::insertMultipleReply(Window requestor, - ::Time time, Atom property) -{ - // get the requested targets - Atom target; - SInt32 format; - String data; - if (!XWindowsUtil::getWindowProperty(m_display, requestor, - property, &data, &target, &format, False)) { - // can't get the requested targets - return false; - } - - // fail if the requested targets isn't of the correct form - if (format != 32 || target != m_atomAtomPair) { - return false; - } - - // data is a list of atom pairs: target, property - XWindowsUtil::convertAtomProperty(data); - auto targets = static_cast(static_cast(data.data())); - const UInt32 numTargets = data.size() / sizeof(Atom); - - // add replies for each target - bool changed = false; - for (UInt32 i = 0; i < numTargets; i += 2) { - const Atom target = targets[i + 0]; - const Atom property = targets[i + 1]; - if (!addSimpleRequest(requestor, target, time, property)) { - // note that we can't perform the requested conversion - XWindowsUtil::replaceAtomData(data, i, None); - changed = true; - } - } - - // update the targets property if we changed it - if (changed) { - XWindowsUtil::setWindowProperty(m_display, requestor, - property, data.data(), data.size(), - target, format); - } - - // add reply for MULTIPLE request - insertReply(new Reply(requestor, m_atomMultiple, - time, property, String(), None, 32)); - - return true; -} - -void -XWindowsClipboard::insertReply(Reply* reply) -{ - assert(reply != nullptr); - - // note -- we must respond to requests in order if requestor,target,time - // are the same, otherwise we can use whatever order we like with one - // exception: each reply in a MULTIPLE reply must be handled in order - // as well. those replies will almost certainly not share targets so - // we can't simply use requestor,target,time as map index. - // - // instead we'll use just the requestor. that's more restrictive than - // necessary but we're guaranteed to do things in the right order. - // note that we could also include the time in the map index and still - // ensure the right order. but since that'll just make it harder to - // find the right reply when handling property notify events we stick - // to just the requestor. - - const bool newWindow = (m_replies.count(reply->m_requestor) == 0); - m_replies[reply->m_requestor].push_back(reply); - - // adjust requestor's event mask if we haven't done so already. we - // want events in case the window is destroyed or any of its - // properties change. - if (newWindow) { - // note errors while we adjust event masks - bool error = false; - { - XWindowsUtil::ErrorLock lock(m_display, &error); - - // get and save the current event mask - XWindowAttributes attr; - XGetWindowAttributes(m_display, reply->m_requestor, &attr); - m_eventMasks[reply->m_requestor] = attr.your_event_mask; - - // add the events we want - XSelectInput(m_display, reply->m_requestor, attr.your_event_mask | - StructureNotifyMask | PropertyChangeMask); - } - - // if we failed then the window has already been destroyed - if (error) { - m_replies.erase(reply->m_requestor); - delete reply; - } - } -} - -void -XWindowsClipboard::pushReplies() -{ - // send the first reply for each window if that reply hasn't - // been sent yet. - for (ReplyMap::iterator index = m_replies.begin(); - index != m_replies.end(); ) { - assert(!index->second.empty()); - ReplyList::iterator listit = index->second.begin(); - while (listit != index->second.end()) { - if (!(*listit)->m_replied) - break; - ++listit; - } - if (listit != index->second.end() && !(*listit)->m_replied) { - pushReplies(index, index->second, listit); - } - else { - ++index; - } - } -} - -void -XWindowsClipboard::pushReplies(ReplyMap::iterator& mapIndex, - ReplyList& replies, ReplyList::iterator index) -{ - Reply* reply = *index; - while (sendReply(reply)) { - // reply is complete. discard it and send the next reply, - // if any. - index = replies.erase(index); - delete reply; - if (index == replies.end()) { + // see if atom is in target list + Atom target = None; + // XXX -- just ask for the converter's target to see if it's + // available rather than checking TARGETS. i've seen clipboard + // owners that don't report all the targets they support. + target = converter->getAtom(); + /* + for (UInt32 i = 0; i < numTargets; ++i) { + if (converter->getAtom() == targets[i]) { + target = targets[i]; break; } - reply = *index; + } + */ + if (target == None) { + continue; } - // if there are no more replies in the list then remove the list - // and stop watching the requestor for events. - if (replies.empty()) { - XWindowsUtil::ErrorLock lock(m_display); - Window requestor = mapIndex->first; - XSelectInput(m_display, requestor, m_eventMasks[requestor]); - m_replies.erase(mapIndex++); - m_eventMasks.erase(requestor); - } - else { - ++mapIndex; + // get the data + Atom actualTarget; + String targetData; + if (!icccmGetSelection(target, &actualTarget, &targetData)) { + LOG((CLOG_DEBUG1 " no data for target %s", + XWindowsUtil::atomToString(m_display, target).c_str())); + continue; } + + // add to clipboard and note we've done it + IClipboard::EFormat format = converter->getFormat(); + m_data[format] = converter->toIClipboard(targetData); + m_added[format] = true; + LOG((CLOG_DEBUG "added format %d for target %s (%u %s)", format, + XWindowsUtil::atomToString(m_display, target).c_str(), + targetData.size(), targetData.size() == 1 ? "byte" : "bytes")); + } } -bool -XWindowsClipboard::sendReply(Reply* reply) -{ - assert(reply != nullptr); +bool XWindowsClipboard::icccmGetSelection(Atom target, Atom *actualTarget, + String *data) const { + assert(actualTarget != nullptr); + assert(data != nullptr); - // bail out immediately if reply is done - if (reply->m_done) { - LOG((CLOG_DEBUG1 "clipboard: finished reply to 0x%08x,%d,%d", reply->m_requestor, reply->m_target, reply->m_property)); - return true; + // request data conversion + CICCCMGetClipboard getter(m_window, m_time, m_atomData); + if (!getter.readClipboard(m_display, m_selection, target, actualTarget, + data)) { + LOG((CLOG_DEBUG1 "can't get data for selection target %s", + XWindowsUtil::atomToString(m_display, target).c_str())); + LOGC(getter.m_error, (CLOG_WARN "icccm violation by clipboard owner")); + return false; + } else if (*actualTarget == None) { + LOG((CLOG_DEBUG1 "selection conversion failed for target %s", + XWindowsUtil::atomToString(m_display, target).c_str())); + return false; + } + return true; +} + +IClipboard::Time XWindowsClipboard::icccmGetTime() const { + Atom actualTarget; + String data; + if (icccmGetSelection(m_atomTimestamp, &actualTarget, &data) && + actualTarget == m_atomInteger) { + Time time = + *static_cast(static_cast(data.data())); + LOG((CLOG_DEBUG1 "got ICCCM time %d", time)); + return time; + } else { + // no timestamp + LOG((CLOG_DEBUG1 "can't get ICCCM time")); + return 0; + } +} + +bool XWindowsClipboard::motifLockClipboard() const { + // fail if anybody owns the lock (even us, so this is non-recursive) + Window lockOwner = XGetSelectionOwner(m_display, m_atomMotifClipLock); + if (lockOwner != None) { + LOG((CLOG_DEBUG1 "motif lock owner 0x%08x", lockOwner)); + return false; + } + + // try to grab the lock + // FIXME -- is this right? there's a race condition here -- + // A grabs successfully, B grabs successfully, A thinks it + // still has the grab until it gets a SelectionClear. + Time time = XWindowsUtil::getCurrentTime(m_display, m_window); + XSetSelectionOwner(m_display, m_atomMotifClipLock, m_window, time); + lockOwner = XGetSelectionOwner(m_display, m_atomMotifClipLock); + if (lockOwner != m_window) { + LOG((CLOG_DEBUG1 "motif lock owner 0x%08x", lockOwner)); + return false; + } + + LOG((CLOG_DEBUG1 "locked motif clipboard")); + return true; +} + +void XWindowsClipboard::motifUnlockClipboard() const { + LOG((CLOG_DEBUG1 "unlocked motif clipboard")); + + // fail if we don't own the lock + Window lockOwner = XGetSelectionOwner(m_display, m_atomMotifClipLock); + if (lockOwner != m_window) { + return; + } + + // release lock + Time time = XWindowsUtil::getCurrentTime(m_display, m_window); + XSetSelectionOwner(m_display, m_atomMotifClipLock, None, time); +} + +bool XWindowsClipboard::motifOwnsClipboard() const { + // get the current selection owner + // FIXME -- this can't be right. even if the window is destroyed + // Motif will still have a valid clipboard. how can we tell if + // some other client owns CLIPBOARD? + Window owner = XGetSelectionOwner(m_display, m_selection); + if (owner == None) { + return false; + } + + // get the Motif clipboard header property from the root window + Atom target; + SInt32 format; + String data; + Window root = RootWindow(m_display, DefaultScreen(m_display)); + if (!XWindowsUtil::getWindowProperty(m_display, root, m_atomMotifClipHeader, + &data, &target, &format, False)) { + return false; + } + + // check the owner window against the current clipboard owner + if (data.size() >= sizeof(MotifClipHeader)) { + MotifClipHeader header; + std::memcpy(&header, data.data(), sizeof(header)); + if ((header.m_id == kMotifClipHeader) && + (static_cast(header.m_selectionOwner) == owner)) { + return true; + } + } + + return false; +} + +void XWindowsClipboard::motifFillCache() { + LOG((CLOG_DEBUG "motif fill clipboard %d", m_id)); + + // get the Motif clipboard header property from the root window + Atom target; + SInt32 format; + String data; + Window root = RootWindow(m_display, DefaultScreen(m_display)); + if (!XWindowsUtil::getWindowProperty(m_display, root, m_atomMotifClipHeader, + &data, &target, &format, False)) { + return; + } + + MotifClipHeader header; + if (data.size() < sizeof(header)) { // check that the header is okay + return; + } + std::memcpy(&header, data.data(), sizeof(header)); + if (header.m_id != kMotifClipHeader || header.m_numItems < 1) { + return; + } + + // get the Motif item property from the root window + static const int buffer_size = 18 + 20; + char name[buffer_size]; + snprintf(name, buffer_size, "_MOTIF_CLIP_ITEM_%d", header.m_item); + Atom atomItem = XInternAtom(m_display, name, False); + data = ""; + if (!XWindowsUtil::getWindowProperty(m_display, root, atomItem, &data, + &target, &format, False)) { + return; + } + + MotifClipItem item; + if (data.size() < sizeof(item)) { // check that the item is okay + return; + } + std::memcpy(&item, data.data(), sizeof(item)); + if (item.m_id != kMotifClipItem || + item.m_numFormats - item.m_numDeletedFormats < 1) { + return; + } + + // format list is after static item structure elements + const SInt32 numFormats = item.m_numFormats - item.m_numDeletedFormats; + auto formats = static_cast( + static_cast(item.m_size + data.data())); + + // get the available formats + typedef std::map MotifFormatMap; + MotifFormatMap motifFormats; + for (SInt32 i = 0; i < numFormats; ++i) { + // get Motif format property from the root window + snprintf(name, buffer_size, "_MOTIF_CLIP_ITEM_%d", formats[i]); + Atom atomFormat = XInternAtom(m_display, name, False); + String data; + if (!XWindowsUtil::getWindowProperty(m_display, root, atomFormat, &data, + &target, &format, False)) { + continue; } - // start in failed state if property is None - bool failed = (reply->m_property == None); - if (!failed) { - LOG((CLOG_DEBUG1 "clipboard: setting property on 0x%08x,%d,%d", reply->m_requestor, reply->m_target, reply->m_property)); - - // send using INCR if already sending incrementally or if reply - // is too large, otherwise just send it. - const UInt32 maxRequestSize = 3 * XMaxRequestSize(m_display); - const bool useINCR = (reply->m_data.size() > maxRequestSize); - - // send INCR reply if incremental and we haven't replied yet - if (useINCR && !reply->m_replied) { - UInt32 size = reply->m_data.size(); - if (!XWindowsUtil::setWindowProperty(m_display, - reply->m_requestor, reply->m_property, - &size, 4, m_atomINCR, 32)) { - failed = true; - } - } - - // send more INCR reply or entire non-incremental reply - else { - // how much more data should we send? - UInt32 size = reply->m_data.size() - reply->m_ptr; - if (size > maxRequestSize) - size = maxRequestSize; - - // send it - if (!XWindowsUtil::setWindowProperty(m_display, - reply->m_requestor, reply->m_property, - reply->m_data.data() + reply->m_ptr, - size, - reply->m_type, reply->m_format)) { - failed = true; - } - else { - reply->m_ptr += size; - - // we've finished the reply if we just sent the zero - // size incremental chunk or if we're not incremental. - reply->m_done = (size == 0 || !useINCR); - } - } + // check that the format is okay + MotifClipFormat motifFormat; + if (data.size() < sizeof(motifFormat)) { + continue; + } + std::memcpy(&motifFormat, data.data(), sizeof(motifFormat)); + if (motifFormat.m_id != kMotifClipFormat || motifFormat.m_length < 0 || + motifFormat.m_type == None || motifFormat.m_deleted != 0) { + continue; } - // if we've failed then delete the property and say we're done. - // if we haven't replied yet then we can send a failure notify, - // otherwise we've failed in the middle of an incremental - // transfer; i don't know how to cancel that so i'll just send - // the final zero-length property. - // FIXME -- how do you gracefully cancel an incremental transfer? - if (failed) { - LOG((CLOG_DEBUG1 "clipboard: sending failure to 0x%08x,%d,%d", reply->m_requestor, reply->m_target, reply->m_property)); - reply->m_done = true; - if (reply->m_property != None) { - XWindowsUtil::ErrorLock lock(m_display); - XDeleteProperty(m_display, reply->m_requestor, reply->m_property); - } + // save it + motifFormats.insert(std::make_pair(motifFormat.m_type, data)); + } + // const UInt32 numMotifFormats = motifFormats.size(); - if (!reply->m_replied) { - sendNotify(reply->m_requestor, m_selection, - reply->m_target, None, - reply->m_time); + // try each converter in order (because they're in order of + // preference). + for (ConverterList::const_iterator index = m_converters.begin(); + index != m_converters.end(); ++index) { + IXWindowsClipboardConverter *converter = *index; - // don't wait for any reply (because we're not expecting one) - return true; - } - else { - static const char dummy = 0; - XWindowsUtil::setWindowProperty(m_display, - reply->m_requestor, reply->m_property, - &dummy, - 0, - reply->m_type, reply->m_format); - - // wait for delete notify - return false; - } + // skip already handled targets + if (m_added[converter->getFormat()]) { + continue; } - // notification already sended - if (reply->m_replied) { - return false; - + // see if atom is in target list + MotifFormatMap::const_iterator index2 = + motifFormats.find(converter->getAtom()); + if (index2 == motifFormats.end()) { + continue; } - LOG((CLOG_DEBUG1 "clipboard: sending notify to 0x%08x,%d,%d", reply->m_requestor, reply->m_target, reply->m_property)); - reply->m_replied = true; + // get format + MotifClipFormat motifFormat; + std::memcpy(&motifFormat, index2->second.data(), sizeof(motifFormat)); + const Atom target = motifFormat.m_type; - // nothing to log - if (CLOG->getFilter() < kDEBUG2) { - sendNotify(reply->m_requestor, m_selection, - reply->m_target, reply->m_property, - static_cast(reply->m_time)); - - // wait for delete notify - return false; - + // get the data (finally) + Atom actualTarget; + String targetData; + if (!motifGetSelection(&motifFormat, &actualTarget, &targetData)) { + LOG((CLOG_DEBUG1 " no data for target %s", + XWindowsUtil::atomToString(m_display, target).c_str())); + continue; } - // dump every property on the requestor window to the debug2 - // log. we've seen what appears to be a bug in lesstif and - // knowing the properties may help design a workaround, if - // it becomes necessary. + // add to clipboard and note we've done it + IClipboard::EFormat format = converter->getFormat(); + m_data[format] = converter->toIClipboard(targetData); + m_added[format] = true; + LOG((CLOG_DEBUG "added format %d for target %s", format, + XWindowsUtil::atomToString(m_display, target).c_str())); + } +} + +bool XWindowsClipboard::motifGetSelection(const MotifClipFormat *format, + Atom *actualTarget, + String *data) const { + // if the current clipboard owner and the owner indicated by the + // motif clip header are the same then transfer via a property on + // the root window, otherwise transfer as a normal ICCCM client. + if (!motifOwnsClipboard()) { + return icccmGetSelection(format->m_type, actualTarget, data); + } + + // use motif way + // FIXME -- this isn't right. it'll only work if the data is + // already stored on the root window and only if it fits in a + // property. motif has some scheme for transferring part by + // part that i don't know. + static const int buffer_size = 18 + 20; + char name[buffer_size]; + snprintf(name, buffer_size, "_MOTIF_CLIP_ITEM_%d", format->m_data); + Atom target = XInternAtom(m_display, name, False); + Window root = RootWindow(m_display, DefaultScreen(m_display)); + return XWindowsUtil::getWindowProperty(m_display, root, target, data, + actualTarget, nullptr, False); +} + +IClipboard::Time XWindowsClipboard::motifGetTime() const { + return icccmGetTime(); +} + +bool XWindowsClipboard::insertMultipleReply(Window requestor, ::Time time, + Atom property) { + // get the requested targets + Atom target; + SInt32 format; + String data; + if (!XWindowsUtil::getWindowProperty(m_display, requestor, property, &data, + &target, &format, False)) { + // can't get the requested targets + return false; + } + + // fail if the requested targets isn't of the correct form + if (format != 32 || target != m_atomAtomPair) { + return false; + } + + // data is a list of atom pairs: target, property + XWindowsUtil::convertAtomProperty(data); + auto targets = + static_cast(static_cast(data.data())); + const UInt32 numTargets = data.size() / sizeof(Atom); + + // add replies for each target + bool changed = false; + for (UInt32 i = 0; i < numTargets; i += 2) { + const Atom target = targets[i + 0]; + const Atom property = targets[i + 1]; + if (!addSimpleRequest(requestor, target, time, property)) { + // note that we can't perform the requested conversion + XWindowsUtil::replaceAtomData(data, i, None); + changed = true; + } + } + + // update the targets property if we changed it + if (changed) { + XWindowsUtil::setWindowProperty(m_display, requestor, property, data.data(), + data.size(), target, format); + } + + // add reply for MULTIPLE request + insertReply( + new Reply(requestor, m_atomMultiple, time, property, String(), None, 32)); + + return true; +} + +void XWindowsClipboard::insertReply(Reply *reply) { + assert(reply != nullptr); + + // note -- we must respond to requests in order if requestor,target,time + // are the same, otherwise we can use whatever order we like with one + // exception: each reply in a MULTIPLE reply must be handled in order + // as well. those replies will almost certainly not share targets so + // we can't simply use requestor,target,time as map index. + // + // instead we'll use just the requestor. that's more restrictive than + // necessary but we're guaranteed to do things in the right order. + // note that we could also include the time in the map index and still + // ensure the right order. but since that'll just make it harder to + // find the right reply when handling property notify events we stick + // to just the requestor. + + const bool newWindow = (m_replies.count(reply->m_requestor) == 0); + m_replies[reply->m_requestor].push_back(reply); + + // adjust requestor's event mask if we haven't done so already. we + // want events in case the window is destroyed or any of its + // properties change. + if (newWindow) { + // note errors while we adjust event masks + bool error = false; + { + XWindowsUtil::ErrorLock lock(m_display, &error); + + // get and save the current event mask + XWindowAttributes attr; + XGetWindowAttributes(m_display, reply->m_requestor, &attr); + m_eventMasks[reply->m_requestor] = attr.your_event_mask; + + // add the events we want + XSelectInput(m_display, reply->m_requestor, + attr.your_event_mask | StructureNotifyMask | + PropertyChangeMask); + } + + // if we failed then the window has already been destroyed + if (error) { + m_replies.erase(reply->m_requestor); + delete reply; + } + } +} + +void XWindowsClipboard::pushReplies() { + // send the first reply for each window if that reply hasn't + // been sent yet. + for (ReplyMap::iterator index = m_replies.begin(); + index != m_replies.end();) { + assert(!index->second.empty()); + ReplyList::iterator listit = index->second.begin(); + while (listit != index->second.end()) { + if (!(*listit)->m_replied) + break; + ++listit; + } + if (listit != index->second.end() && !(*listit)->m_replied) { + pushReplies(index, index->second, listit); + } else { + ++index; + } + } +} + +void XWindowsClipboard::pushReplies(ReplyMap::iterator &mapIndex, + ReplyList &replies, + ReplyList::iterator index) { + Reply *reply = *index; + while (sendReply(reply)) { + // reply is complete. discard it and send the next reply, + // if any. + index = replies.erase(index); + delete reply; + if (index == replies.end()) { + break; + } + reply = *index; + } + + // if there are no more replies in the list then remove the list + // and stop watching the requestor for events. + if (replies.empty()) { XWindowsUtil::ErrorLock lock(m_display); - int n; - Atom* props = XListProperties(m_display, reply->m_requestor, &n); - LOG((CLOG_DEBUG2 "properties of 0x%08x:", reply->m_requestor)); - for (int i = 0; i < n; ++i) { - Atom target; - String data; - char* name = XGetAtomName(m_display, props[i]); - if (!XWindowsUtil::getWindowProperty(m_display, - reply->m_requestor, - props[i], &data, &target, nullptr, False)) { - LOG((CLOG_DEBUG2 " %s: ", name)); - } - else { - // convert to hex if contains non ascii symbols - if (std::find_if(data.begin(), data.end(), - [](const unsigned char& c) { return c < 32 || c > 126; }) != data.end()) { - const String hex_digits = "0123456789abcdef"; - String tmp; - tmp.reserve(data.length() * 3); - std::for_each(data.begin(), data.end(), [hex_digits, &tmp](const unsigned char& c) - { - tmp += hex_digits[c >> 16]; - tmp += hex_digits[c & 15]; - tmp += ' '; - }); - data = tmp; - } - char* type = XGetAtomName(m_display, target); - LOG((CLOG_DEBUG2 " %s (%s): %s", name, type, data.c_str())); - if (type != nullptr) { - XFree(type); - } - } - if (name != nullptr) { - XFree(name); - } - } - if (props != nullptr) { - XFree(props); + Window requestor = mapIndex->first; + XSelectInput(m_display, requestor, m_eventMasks[requestor]); + m_replies.erase(mapIndex++); + m_eventMasks.erase(requestor); + } else { + ++mapIndex; + } +} + +bool XWindowsClipboard::sendReply(Reply *reply) { + assert(reply != nullptr); + + // bail out immediately if reply is done + if (reply->m_done) { + LOG((CLOG_DEBUG1 "clipboard: finished reply to 0x%08x,%d,%d", + reply->m_requestor, reply->m_target, reply->m_property)); + return true; + } + + // start in failed state if property is None + bool failed = (reply->m_property == None); + if (!failed) { + LOG((CLOG_DEBUG1 "clipboard: setting property on 0x%08x,%d,%d", + reply->m_requestor, reply->m_target, reply->m_property)); + + // send using INCR if already sending incrementally or if reply + // is too large, otherwise just send it. + const UInt32 maxRequestSize = 3 * XMaxRequestSize(m_display); + const bool useINCR = (reply->m_data.size() > maxRequestSize); + + // send INCR reply if incremental and we haven't replied yet + if (useINCR && !reply->m_replied) { + UInt32 size = reply->m_data.size(); + if (!XWindowsUtil::setWindowProperty(m_display, reply->m_requestor, + reply->m_property, &size, 4, + m_atomINCR, 32)) { + failed = true; + } } - sendNotify(reply->m_requestor, m_selection, - reply->m_target, reply->m_property, - reply->m_time); + // send more INCR reply or entire non-incremental reply + else { + // how much more data should we send? + UInt32 size = reply->m_data.size() - reply->m_ptr; + if (size > maxRequestSize) + size = maxRequestSize; + + // send it + if (!XWindowsUtil::setWindowProperty( + m_display, reply->m_requestor, reply->m_property, + reply->m_data.data() + reply->m_ptr, size, reply->m_type, + reply->m_format)) { + failed = true; + } else { + reply->m_ptr += size; + + // we've finished the reply if we just sent the zero + // size incremental chunk or if we're not incremental. + reply->m_done = (size == 0 || !useINCR); + } + } + } + + // if we've failed then delete the property and say we're done. + // if we haven't replied yet then we can send a failure notify, + // otherwise we've failed in the middle of an incremental + // transfer; i don't know how to cancel that so i'll just send + // the final zero-length property. + // FIXME -- how do you gracefully cancel an incremental transfer? + if (failed) { + LOG((CLOG_DEBUG1 "clipboard: sending failure to 0x%08x,%d,%d", + reply->m_requestor, reply->m_target, reply->m_property)); + reply->m_done = true; + if (reply->m_property != None) { + XWindowsUtil::ErrorLock lock(m_display); + XDeleteProperty(m_display, reply->m_requestor, reply->m_property); + } + + if (!reply->m_replied) { + sendNotify(reply->m_requestor, m_selection, reply->m_target, None, + reply->m_time); + + // don't wait for any reply (because we're not expecting one) + return true; + } else { + static const char dummy = 0; + XWindowsUtil::setWindowProperty(m_display, reply->m_requestor, + reply->m_property, &dummy, 0, + reply->m_type, reply->m_format); + + // wait for delete notify + return false; + } + } + + // notification already sended + if (reply->m_replied) { + return false; + } + + LOG((CLOG_DEBUG1 "clipboard: sending notify to 0x%08x,%d,%d", + reply->m_requestor, reply->m_target, reply->m_property)); + reply->m_replied = true; + + // nothing to log + if (CLOG->getFilter() < kDEBUG2) { + sendNotify(reply->m_requestor, m_selection, reply->m_target, + reply->m_property, static_cast(reply->m_time)); // wait for delete notify return false; -} + } -void -XWindowsClipboard::clearReplies() -{ - for (ReplyMap::iterator index = m_replies.begin(); - index != m_replies.end(); ++index) { - clearReplies(index->second); + // dump every property on the requestor window to the debug2 + // log. we've seen what appears to be a bug in lesstif and + // knowing the properties may help design a workaround, if + // it becomes necessary. + XWindowsUtil::ErrorLock lock(m_display); + int n; + Atom *props = XListProperties(m_display, reply->m_requestor, &n); + LOG((CLOG_DEBUG2 "properties of 0x%08x:", reply->m_requestor)); + for (int i = 0; i < n; ++i) { + Atom target; + String data; + char *name = XGetAtomName(m_display, props[i]); + if (!XWindowsUtil::getWindowProperty(m_display, reply->m_requestor, + props[i], &data, &target, nullptr, + False)) { + LOG((CLOG_DEBUG2 " %s: ", name)); + } else { + // convert to hex if contains non ascii symbols + if (std::find_if(data.begin(), data.end(), [](const unsigned char &c) { + return c < 32 || c > 126; + }) != data.end()) { + const String hex_digits = "0123456789abcdef"; + String tmp; + tmp.reserve(data.length() * 3); + std::for_each(data.begin(), data.end(), + [hex_digits, &tmp](const unsigned char &c) { + tmp += hex_digits[c >> 16]; + tmp += hex_digits[c & 15]; + tmp += ' '; + }); + data = tmp; + } + char *type = XGetAtomName(m_display, target); + LOG((CLOG_DEBUG2 " %s (%s): %s", name, type, data.c_str())); + if (type != nullptr) { + XFree(type); + } } - m_replies.clear(); - m_eventMasks.clear(); -} - -void -XWindowsClipboard::clearReplies(ReplyList& replies) -{ - for (ReplyList::iterator index = replies.begin(); - index != replies.end(); ++index) { - delete *index; + if (name != nullptr) { + XFree(name); } - replies.clear(); + } + if (props != nullptr) { + XFree(props); + } + + sendNotify(reply->m_requestor, m_selection, reply->m_target, + reply->m_property, reply->m_time); + + // wait for delete notify + return false; } -void -XWindowsClipboard::sendNotify(Window requestor, - Atom selection, Atom target, Atom property, Time time) -{ - XEvent event; - event.xselection.type = SelectionNotify; - event.xselection.display = m_display; - event.xselection.requestor = requestor; - event.xselection.selection = selection; - event.xselection.target = target; - event.xselection.property = property; - event.xselection.time = time; - XWindowsUtil::ErrorLock lock(m_display); - XSendEvent(m_display, requestor, False, 0, &event); +void XWindowsClipboard::clearReplies() { + for (ReplyMap::iterator index = m_replies.begin(); index != m_replies.end(); + ++index) { + clearReplies(index->second); + } + m_replies.clear(); + m_eventMasks.clear(); } -bool -XWindowsClipboard::wasOwnedAtTime(::Time time) const -{ - // not owned if we've never owned the selection - checkCache(); - if (m_timeOwned == 0) { - return false; +void XWindowsClipboard::clearReplies(ReplyList &replies) { + for (ReplyList::iterator index = replies.begin(); index != replies.end(); + ++index) { + delete *index; + } + replies.clear(); +} + +void XWindowsClipboard::sendNotify(Window requestor, Atom selection, + Atom target, Atom property, Time time) { + XEvent event; + event.xselection.type = SelectionNotify; + event.xselection.display = m_display; + event.xselection.requestor = requestor; + event.xselection.selection = selection; + event.xselection.target = target; + event.xselection.property = property; + event.xselection.time = time; + XWindowsUtil::ErrorLock lock(m_display); + XSendEvent(m_display, requestor, False, 0, &event); +} + +bool XWindowsClipboard::wasOwnedAtTime(::Time time) const { + // not owned if we've never owned the selection + checkCache(); + if (m_timeOwned == 0) { + return false; + } + + // if time is CurrentTime then return true if we still own the + // selection and false if we do not. else if we still own the + // selection then get the current time, otherwise use + // m_timeLost as the end time. + Time lost = m_timeLost; + if (m_timeLost == 0) { + if (time == CurrentTime) { + return true; + } else { + lost = XWindowsUtil::getCurrentTime(m_display, m_window); } - - // if time is CurrentTime then return true if we still own the - // selection and false if we do not. else if we still own the - // selection then get the current time, otherwise use - // m_timeLost as the end time. - Time lost = m_timeLost; - if (m_timeLost == 0) { - if (time == CurrentTime) { - return true; - } - else { - lost = XWindowsUtil::getCurrentTime(m_display, m_window); - } - } - else { - if (time == CurrentTime) { - return false; - } + } else { + if (time == CurrentTime) { + return false; } + } - // compare time to range - Time duration = lost - m_timeOwned; - Time when = time - m_timeOwned; - return (/*when >= 0 &&*/ when <= duration); + // compare time to range + Time duration = lost - m_timeOwned; + Time when = time - m_timeOwned; + return (/*when >= 0 &&*/ when <= duration); } -Atom -XWindowsClipboard::getTargetsData(String& data, int* format) const -{ - assert(format != nullptr); +Atom XWindowsClipboard::getTargetsData(String &data, int *format) const { + assert(format != nullptr); - // add standard targets - XWindowsUtil::appendAtomData(data, m_atomTargets); - XWindowsUtil::appendAtomData(data, m_atomMultiple); - XWindowsUtil::appendAtomData(data, m_atomTimestamp); + // add standard targets + XWindowsUtil::appendAtomData(data, m_atomTargets); + XWindowsUtil::appendAtomData(data, m_atomMultiple); + XWindowsUtil::appendAtomData(data, m_atomTimestamp); - // add targets we can convert to - for (ConverterList::const_iterator index = m_converters.begin(); - index != m_converters.end(); ++index) { - IXWindowsClipboardConverter* converter = *index; + // add targets we can convert to + for (ConverterList::const_iterator index = m_converters.begin(); + index != m_converters.end(); ++index) { + IXWindowsClipboardConverter *converter = *index; - // skip formats we don't have - if (m_added[converter->getFormat()]) { - XWindowsUtil::appendAtomData(data, converter->getAtom()); - } + // skip formats we don't have + if (m_added[converter->getFormat()]) { + XWindowsUtil::appendAtomData(data, converter->getAtom()); } + } - *format = 32; - return m_atomAtom; + *format = 32; + return m_atomAtom; } -Atom -XWindowsClipboard::getTimestampData(String& data, int* format) const -{ - assert(format != nullptr); +Atom XWindowsClipboard::getTimestampData(String &data, int *format) const { + assert(format != nullptr); - checkCache(); - XWindowsUtil::appendTimeData(data, m_timeOwned); - *format = 32; - return m_atomInteger; + checkCache(); + XWindowsUtil::appendTimeData(data, m_timeOwned); + *format = 32; + return m_atomInteger; } - // // XWindowsClipboard::CICCCMGetClipboard // -XWindowsClipboard::CICCCMGetClipboard::CICCCMGetClipboard( - Window requestor, Time time, Atom property) : - m_requestor(requestor), - m_time(time), - m_property(property), - m_incr(false), - m_failed(false), - m_done(false), - m_reading(false), - m_error(false) -{ - // do nothing +XWindowsClipboard::CICCCMGetClipboard::CICCCMGetClipboard(Window requestor, + Time time, + Atom property) + : m_requestor(requestor), m_time(time), m_property(property), m_incr(false), + m_failed(false), m_done(false), m_reading(false), m_error(false) { + // do nothing } -XWindowsClipboard::CICCCMGetClipboard::~CICCCMGetClipboard() -{ - // do nothing +XWindowsClipboard::CICCCMGetClipboard::~CICCCMGetClipboard() { + // do nothing } -bool -XWindowsClipboard::CICCCMGetClipboard::readClipboard(Display* display, - Atom selection, Atom target, Atom* actualTarget, String* data) -{ - assert(actualTarget != nullptr); - assert(data != nullptr); +bool XWindowsClipboard::CICCCMGetClipboard::readClipboard(Display *display, + Atom selection, + Atom target, + Atom *actualTarget, + String *data) { + assert(actualTarget != nullptr); + assert(data != nullptr); - LOG((CLOG_DEBUG1 "request selection=%s, target=%s, window=%x", XWindowsUtil::atomToString(display, selection).c_str(), XWindowsUtil::atomToString(display, target).c_str(), m_requestor)); + LOG((CLOG_DEBUG1 "request selection=%s, target=%s, window=%x", + XWindowsUtil::atomToString(display, selection).c_str(), + XWindowsUtil::atomToString(display, target).c_str(), m_requestor)); - m_atomNone = XInternAtom(display, "NONE", False); - m_atomIncr = XInternAtom(display, "INCR", False); + m_atomNone = XInternAtom(display, "NONE", False); + m_atomIncr = XInternAtom(display, "INCR", False); - // save output pointers - m_actualTarget = actualTarget; - m_data = data; + // save output pointers + m_actualTarget = actualTarget; + m_data = data; - // assume failure - *m_actualTarget = None; - *m_data = ""; + // assume failure + *m_actualTarget = None; + *m_data = ""; - // delete target property - XDeleteProperty(display, m_requestor, m_property); + // delete target property + XDeleteProperty(display, m_requestor, m_property); - // select window for property changes - XWindowAttributes attr; - XGetWindowAttributes(display, m_requestor, &attr); - XSelectInput(display, m_requestor, - attr.your_event_mask | PropertyChangeMask); + // select window for property changes + XWindowAttributes attr; + XGetWindowAttributes(display, m_requestor, &attr); + XSelectInput(display, m_requestor, attr.your_event_mask | PropertyChangeMask); - // request data conversion - XConvertSelection(display, selection, target, - m_property, m_requestor, m_time); + // request data conversion + XConvertSelection(display, selection, target, m_property, m_requestor, + m_time); - // synchronize with server before we start following timeout countdown - XSync(display, False); + // synchronize with server before we start following timeout countdown + XSync(display, False); - // Xlib inexplicably omits the ability to wait for an event with - // a timeout. (it's inexplicable because there's no portable way - // to do it.) we'll poll until we have what we're looking for or - // a timeout expires. we use a timeout so we don't get locked up - // by badly behaved selection owners. - XEvent xevent; - std::vector events; - Stopwatch timeout(false); // timer not stopped, not triggered - static const double s_timeout = 0.25; // FIXME -- is this too short? - bool noWait = false; - while (!m_done && !m_failed) { + // Xlib inexplicably omits the ability to wait for an event with + // a timeout. (it's inexplicable because there's no portable way + // to do it.) we'll poll until we have what we're looking for or + // a timeout expires. we use a timeout so we don't get locked up + // by badly behaved selection owners. + XEvent xevent; + std::vector events; + Stopwatch timeout(false); // timer not stopped, not triggered + static const double s_timeout = 0.25; // FIXME -- is this too short? + bool noWait = false; + while (!m_done && !m_failed) { + // fail if timeout has expired + if (timeout.getTime() >= s_timeout) { + m_failed = true; + break; + } + + // process events if any otherwise sleep + if (noWait || XPending(display) > 0) { + while (!m_done && !m_failed && (noWait || XPending(display) > 0)) { // fail if timeout has expired if (timeout.getTime() >= s_timeout) { - m_failed = true; - break; + m_failed = true; + break; } - // process events if any otherwise sleep - if (noWait || XPending(display) > 0) { - while (!m_done && !m_failed && (noWait || XPending(display) > 0)) { - // fail if timeout has expired - if (timeout.getTime() >= s_timeout) { - m_failed = true; - break; - } + XNextEvent(display, &xevent); + if (!processEvent(display, &xevent)) { + // not processed so save it + events.push_back(xevent); + } else { + // reset timer since we've made some progress + timeout.reset(); - XNextEvent(display, &xevent); - if (!processEvent(display, &xevent)) { - // not processed so save it - events.push_back(xevent); - } - else { - // reset timer since we've made some progress - timeout.reset(); - - // don't sleep anymore, just block waiting for events. - // we're assuming here that the clipboard owner will - // complete the protocol correctly. if we continue to - // sleep we'll get very bad performance. - noWait = true; - } - } - } - else { - ARCH->sleep(0.01); + // don't sleep anymore, just block waiting for events. + // we're assuming here that the clipboard owner will + // complete the protocol correctly. if we continue to + // sleep we'll get very bad performance. + noWait = true; } + } + } else { + ARCH->sleep(0.01); } + } - // put unprocessed events back - for (UInt32 i = events.size(); i > 0; --i) { - XPutBackEvent(display, &events[i - 1]); - } + // put unprocessed events back + for (UInt32 i = events.size(); i > 0; --i) { + XPutBackEvent(display, &events[i - 1]); + } - // restore mask - XSelectInput(display, m_requestor, attr.your_event_mask); + // restore mask + XSelectInput(display, m_requestor, attr.your_event_mask); - // return success or failure - LOG((CLOG_DEBUG1 "request %s after %fs", m_failed ? "failed" : "succeeded", timeout.getTime())); - return !m_failed; + // return success or failure + LOG((CLOG_DEBUG1 "request %s after %fs", m_failed ? "failed" : "succeeded", + timeout.getTime())); + return !m_failed; } -bool -XWindowsClipboard::CICCCMGetClipboard::processEvent( - Display* display, XEvent* xevent) -{ - // process event - switch (xevent->type) { - case DestroyNotify: - if (xevent->xdestroywindow.window == m_requestor) { - m_failed = true; - return true; - } - - // not interested - return false; - - case SelectionNotify: - if (xevent->xselection.requestor == m_requestor) { - // done if we can't convert - if (xevent->xselection.property == None || - xevent->xselection.property == m_atomNone) { - m_done = true; - return true; - } - - // proceed if conversion successful - else if (xevent->xselection.property == m_property) { - m_reading = true; - break; - } - } - - // otherwise not interested - return false; - - case PropertyNotify: - // proceed if conversion successful and we're receiving more data - if (xevent->xproperty.window == m_requestor && - xevent->xproperty.atom == m_property && - xevent->xproperty.state == PropertyNewValue) { - if (!m_reading) { - // we haven't gotten the SelectionNotify yet - return true; - } - break; - } - - // otherwise not interested - return false; - - default: - // not interested - return false; +bool XWindowsClipboard::CICCCMGetClipboard::processEvent(Display *display, + XEvent *xevent) { + // process event + switch (xevent->type) { + case DestroyNotify: + if (xevent->xdestroywindow.window == m_requestor) { + m_failed = true; + return true; } - // get the data from the property - Atom target; - const String::size_type oldSize = m_data->size(); - if (!XWindowsUtil::getWindowProperty(display, m_requestor, - m_property, m_data, &target, nullptr, True)) { - // unable to read property - m_failed = true; + // not interested + return false; + + case SelectionNotify: + if (xevent->xselection.requestor == m_requestor) { + // done if we can't convert + if (xevent->xselection.property == None || + xevent->xselection.property == m_atomNone) { + m_done = true; return true; + } + + // proceed if conversion successful + else if (xevent->xselection.property == m_property) { + m_reading = true; + break; + } } - // note if incremental. if we're already incremental then the - // selection owner is busted. if the INCR property has no size - // then the selection owner is busted. - if (target == m_atomIncr) { - if (m_incr || m_data->size() == oldSize) { - m_failed = true; - m_error = true; - } - else { - m_incr = true; + // otherwise not interested + return false; - // discard INCR data - *m_data = ""; - } + case PropertyNotify: + // proceed if conversion successful and we're receiving more data + if (xevent->xproperty.window == m_requestor && + xevent->xproperty.atom == m_property && + xevent->xproperty.state == PropertyNewValue) { + if (!m_reading) { + // we haven't gotten the SelectionNotify yet + return true; + } + break; } - // handle incremental chunks - else if (m_incr) { - // if first incremental chunk then save target - if (oldSize == 0) { - LOG((CLOG_DEBUG1 " INCR first chunk, target %s", XWindowsUtil::atomToString(display, target).c_str())); - *m_actualTarget = target; - } + // otherwise not interested + return false; - // secondary chunks must have the same target - else { - if (target != *m_actualTarget) { - LOG((CLOG_WARN " INCR target mismatch")); - m_failed = true; - m_error = true; - } - } + default: + // not interested + return false; + } - // note if this is the final chunk - if (m_data->size() == oldSize) { - LOG((CLOG_DEBUG1 " INCR final chunk: %d bytes total", m_data->size())); - m_done = true; - } - } - - // not incremental; save the target. - else { - LOG((CLOG_DEBUG1 " target %s", XWindowsUtil::atomToString(display, target).c_str())); - *m_actualTarget = target; - m_done = true; - } - - // this event has been processed - LOGC(!m_incr, (CLOG_DEBUG1 " got data, %d bytes", m_data->size())); + // get the data from the property + Atom target; + const String::size_type oldSize = m_data->size(); + if (!XWindowsUtil::getWindowProperty(display, m_requestor, m_property, m_data, + &target, nullptr, True)) { + // unable to read property + m_failed = true; return true; -} + } + // note if incremental. if we're already incremental then the + // selection owner is busted. if the INCR property has no size + // then the selection owner is busted. + if (target == m_atomIncr) { + if (m_incr || m_data->size() == oldSize) { + m_failed = true; + m_error = true; + } else { + m_incr = true; + + // discard INCR data + *m_data = ""; + } + } + + // handle incremental chunks + else if (m_incr) { + // if first incremental chunk then save target + if (oldSize == 0) { + LOG((CLOG_DEBUG1 " INCR first chunk, target %s", + XWindowsUtil::atomToString(display, target).c_str())); + *m_actualTarget = target; + } + + // secondary chunks must have the same target + else { + if (target != *m_actualTarget) { + LOG((CLOG_WARN " INCR target mismatch")); + m_failed = true; + m_error = true; + } + } + + // note if this is the final chunk + if (m_data->size() == oldSize) { + LOG((CLOG_DEBUG1 " INCR final chunk: %d bytes total", m_data->size())); + m_done = true; + } + } + + // not incremental; save the target. + else { + LOG((CLOG_DEBUG1 " target %s", + XWindowsUtil::atomToString(display, target).c_str())); + *m_actualTarget = target; + m_done = true; + } + + // this event has been processed + LOGC(!m_incr, (CLOG_DEBUG1 " got data, %d bytes", m_data->size())); + return true; +} // // XWindowsClipboard::Reply // -XWindowsClipboard::Reply::Reply(Window requestor, Atom target, ::Time time) : - m_requestor(requestor), - m_target(target), - m_time(time), - m_property(None), - m_replied(false), - m_done(false), - m_data(), - m_type(None), - m_format(32), - m_ptr(0) -{ - // do nothing +XWindowsClipboard::Reply::Reply(Window requestor, Atom target, ::Time time) + : m_requestor(requestor), m_target(target), m_time(time), m_property(None), + m_replied(false), m_done(false), m_data(), m_type(None), m_format(32), + m_ptr(0) { + // do nothing } XWindowsClipboard::Reply::Reply(Window requestor, Atom target, ::Time time, - Atom property, const String& data, Atom type, int format) : - m_requestor(requestor), - m_target(target), - m_time(time), - m_property(property), - m_replied(false), - m_done(false), - m_data(data), - m_type(type), - m_format(format), - m_ptr(0) -{ - // do nothing + Atom property, const String &data, Atom type, + int format) + : m_requestor(requestor), m_target(target), m_time(time), + m_property(property), m_replied(false), m_done(false), m_data(data), + m_type(type), m_format(format), m_ptr(0) { + // do nothing } diff --git a/src/lib/platform/XWindowsClipboard.h b/src/lib/platform/XWindowsClipboard.h index fe088ffd2..c67d446df 100644 --- a/src/lib/platform/XWindowsClipboard.h +++ b/src/lib/platform/XWindowsClipboard.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -18,16 +18,16 @@ #pragma once -#include "synergy/clipboard_types.h" -#include "synergy/IClipboard.h" -#include "common/stdmap.h" #include "common/stdlist.h" +#include "common/stdmap.h" #include "common/stdvector.h" +#include "synergy/IClipboard.h" +#include "synergy/clipboard_types.h" #if X_DISPLAY_MISSING -# error X11 is required to build synergy +#error X11 is required to build synergy #else -# include +#include #endif class IXWindowsClipboardConverter; @@ -35,301 +35,294 @@ class IXWindowsClipboardConverter; //! X11 clipboard implementation class XWindowsClipboard : public IClipboard { public: - /*! - Use \c window as the window that owns or interacts with the - clipboard identified by \c id. - */ - XWindowsClipboard(Display*, Window window, ClipboardID id); - XWindowsClipboard(XWindowsClipboard const &) =delete; - XWindowsClipboard(XWindowsClipboard &&) =delete; - virtual ~XWindowsClipboard(); + /*! + Use \c window as the window that owns or interacts with the + clipboard identified by \c id. + */ + XWindowsClipboard(Display *, Window window, ClipboardID id); + XWindowsClipboard(XWindowsClipboard const &) = delete; + XWindowsClipboard(XWindowsClipboard &&) = delete; + virtual ~XWindowsClipboard(); - XWindowsClipboard& operator=(XWindowsClipboard const &) =delete; - XWindowsClipboard& operator=(XWindowsClipboard &&) =delete; + XWindowsClipboard &operator=(XWindowsClipboard const &) = delete; + XWindowsClipboard &operator=(XWindowsClipboard &&) = delete; - //! Notify clipboard was lost - /*! - Tells clipboard it lost ownership at the given time. - */ - void lost(Time); + //! Notify clipboard was lost + /*! + Tells clipboard it lost ownership at the given time. + */ + void lost(Time); - //! Add clipboard request - /*! - Adds a selection request to the request list. If the given - owner window isn't this clipboard's window then this simply - sends a failure event to the requestor. - */ - void addRequest(Window owner, - Window requestor, Atom target, - ::Time time, Atom property); + //! Add clipboard request + /*! + Adds a selection request to the request list. If the given + owner window isn't this clipboard's window then this simply + sends a failure event to the requestor. + */ + void addRequest(Window owner, Window requestor, Atom target, ::Time time, + Atom property); - //! Process clipboard request - /*! - Continues processing a selection request. Returns true if the - request was handled, false if the request was unknown. - */ - bool processRequest(Window requestor, - ::Time time, Atom property); + //! Process clipboard request + /*! + Continues processing a selection request. Returns true if the + request was handled, false if the request was unknown. + */ + bool processRequest(Window requestor, ::Time time, Atom property); - //! Cancel clipboard request - /*! - Terminate a selection request. Returns true iff the request - was known and handled. - */ - bool destroyRequest(Window requestor); + //! Cancel clipboard request + /*! + Terminate a selection request. Returns true iff the request + was known and handled. + */ + bool destroyRequest(Window requestor); - //! Get window - /*! - Returns the clipboard's window (passed the c'tor). - */ - Window getWindow() const; + //! Get window + /*! + Returns the clipboard's window (passed the c'tor). + */ + Window getWindow() const; - //! Get selection atom - /*! - Returns the selection atom that identifies the clipboard to X11 - (e.g. XA_PRIMARY). - */ - Atom getSelection() const; + //! Get selection atom + /*! + Returns the selection atom that identifies the clipboard to X11 + (e.g. XA_PRIMARY). + */ + Atom getSelection() const; - // IClipboard overrides - virtual bool empty(); - virtual void add(EFormat, const String& data); - virtual bool open(Time) const; - virtual void close() const; - virtual Time getTime() const; - virtual bool has(EFormat) const; - virtual String get(EFormat) const; + // IClipboard overrides + virtual bool empty(); + virtual void add(EFormat, const String &data); + virtual bool open(Time) const; + virtual void close() const; + virtual Time getTime() const; + virtual bool has(EFormat) const; + virtual String get(EFormat) const; private: - // remove all converters from our list - void clearConverters(); + // remove all converters from our list + void clearConverters(); - // get the converter for a clipboard format. returns NULL if no - // suitable converter. iff onlyIfNotAdded is true then also - // return NULL if a suitable converter was found but we already - // have data of the converter's clipboard format. - IXWindowsClipboardConverter* - getConverter(Atom target, - bool onlyIfNotAdded = false) const; + // get the converter for a clipboard format. returns NULL if no + // suitable converter. iff onlyIfNotAdded is true then also + // return NULL if a suitable converter was found but we already + // have data of the converter's clipboard format. + IXWindowsClipboardConverter *getConverter(Atom target, + bool onlyIfNotAdded = false) const; - // convert target atom to clipboard format - EFormat getFormat(Atom target) const; + // convert target atom to clipboard format + EFormat getFormat(Atom target) const; - // add a non-MULTIPLE request. does not verify that the selection - // was owned at the given time. returns true if the conversion - // could be performed, false otherwise. in either case, the - // reply is inserted. - bool addSimpleRequest( - Window requestor, Atom target, - ::Time time, Atom property); + // add a non-MULTIPLE request. does not verify that the selection + // was owned at the given time. returns true if the conversion + // could be performed, false otherwise. in either case, the + // reply is inserted. + bool addSimpleRequest(Window requestor, Atom target, ::Time time, + Atom property); - // if not already checked then see if the cache is stale and, if so, - // clear it. this has the side effect of updating m_timeOwned. - void checkCache() const; + // if not already checked then see if the cache is stale and, if so, + // clear it. this has the side effect of updating m_timeOwned. + void checkCache() const; - // clear the cache, resetting the cached flag and the added flag for - // each format. - void clearCache() const; - void doClearCache(); + // clear the cache, resetting the cached flag and the added flag for + // each format. + void clearCache() const; + void doClearCache(); - // cache all formats of the selection - void fillCache() const; - void doFillCache(); + // cache all formats of the selection + void fillCache() const; + void doFillCache(); - // - // helper classes - // + // + // helper classes + // - // read an ICCCM conforming selection - class CICCCMGetClipboard { - public: - CICCCMGetClipboard(Window requestor, Time time, Atom property); - ~CICCCMGetClipboard(); + // read an ICCCM conforming selection + class CICCCMGetClipboard { + public: + CICCCMGetClipboard(Window requestor, Time time, Atom property); + ~CICCCMGetClipboard(); - // convert the given selection to the given type. returns - // true iff the conversion was successful or the conversion - // cannot be performed (in which case *actualTarget == None). - bool readClipboard(Display* display, - Atom selection, Atom target, - Atom* actualTarget, String* data); + // convert the given selection to the given type. returns + // true iff the conversion was successful or the conversion + // cannot be performed (in which case *actualTarget == None). + bool readClipboard(Display *display, Atom selection, Atom target, + Atom *actualTarget, String *data); - private: - bool processEvent(Display* display, XEvent* event); + private: + bool processEvent(Display *display, XEvent *event); - private: - Window m_requestor; - Time m_time; - Atom m_property; - bool m_incr; - bool m_failed; - bool m_done; + private: + Window m_requestor; + Time m_time; + Atom m_property; + bool m_incr; + bool m_failed; + bool m_done; - // atoms needed for the protocol - Atom m_atomNone; // NONE, not None - Atom m_atomIncr; + // atoms needed for the protocol + Atom m_atomNone; // NONE, not None + Atom m_atomIncr; - // true iff we've received the selection notify - bool m_reading; + // true iff we've received the selection notify + bool m_reading; - // the converted selection data - String* m_data = nullptr; + // the converted selection data + String *m_data = nullptr; - // the actual type of the data. if this is None then the - // selection owner cannot convert to the requested type. - Atom* m_actualTarget = nullptr; + // the actual type of the data. if this is None then the + // selection owner cannot convert to the requested type. + Atom *m_actualTarget = nullptr; - public: - // true iff the selection owner didn't follow ICCCM conventions - bool m_error; - }; + public: + // true iff the selection owner didn't follow ICCCM conventions + bool m_error; + }; - // Motif structure IDs - enum { kMotifClipFormat = 1, kMotifClipItem, kMotifClipHeader }; + // Motif structure IDs + enum { kMotifClipFormat = 1, kMotifClipItem, kMotifClipHeader }; - // _MOTIF_CLIP_HEADER structure - class MotifClipHeader { - public: - SInt32 m_id; // kMotifClipHeader - SInt32 m_pad1[3]; - SInt32 m_item; - SInt32 m_pad2[4]; - SInt32 m_numItems; - SInt32 m_pad3[3]; - SInt32 m_selectionOwner; // a Window - SInt32 m_pad4[2]; - }; + // _MOTIF_CLIP_HEADER structure + class MotifClipHeader { + public: + SInt32 m_id; // kMotifClipHeader + SInt32 m_pad1[3]; + SInt32 m_item; + SInt32 m_pad2[4]; + SInt32 m_numItems; + SInt32 m_pad3[3]; + SInt32 m_selectionOwner; // a Window + SInt32 m_pad4[2]; + }; - // Motif clip item structure - class MotifClipItem { - public: - SInt32 m_id; // kMotifClipItem - SInt32 m_pad1[5]; - SInt32 m_size; - SInt32 m_numFormats; - SInt32 m_numDeletedFormats; - SInt32 m_pad2[6]; - }; + // Motif clip item structure + class MotifClipItem { + public: + SInt32 m_id; // kMotifClipItem + SInt32 m_pad1[5]; + SInt32 m_size; + SInt32 m_numFormats; + SInt32 m_numDeletedFormats; + SInt32 m_pad2[6]; + }; - // Motif clip format structure - class MotifClipFormat { - public: - SInt32 m_id; // kMotifClipFormat - SInt32 m_pad1[6]; - SInt32 m_length; - SInt32 m_data; - SInt32 m_type; // an Atom - SInt32 m_pad2[1]; - SInt32 m_deleted; - SInt32 m_pad3[4]; - }; + // Motif clip format structure + class MotifClipFormat { + public: + SInt32 m_id; // kMotifClipFormat + SInt32 m_pad1[6]; + SInt32 m_length; + SInt32 m_data; + SInt32 m_type; // an Atom + SInt32 m_pad2[1]; + SInt32 m_deleted; + SInt32 m_pad3[4]; + }; - // stores data needed to respond to a selection request - class Reply { - public: - Reply(Window, Atom target, ::Time); - Reply(Window, Atom target, ::Time, Atom property, - const String& data, Atom type, int format); + // stores data needed to respond to a selection request + class Reply { + public: + Reply(Window, Atom target, ::Time); + Reply(Window, Atom target, ::Time, Atom property, const String &data, + Atom type, int format); - public: - // information about the request - Window m_requestor; - Atom m_target; - ::Time m_time; - Atom m_property; + public: + // information about the request + Window m_requestor; + Atom m_target; + ::Time m_time; + Atom m_property; - // true iff we've sent the notification for this reply - bool m_replied; + // true iff we've sent the notification for this reply + bool m_replied; - // true iff the reply has sent its last message - bool m_done; + // true iff the reply has sent its last message + bool m_done; - // the data to send and its type and format - String m_data; - Atom m_type; - int m_format; + // the data to send and its type and format + String m_data; + Atom m_type; + int m_format; - // index of next byte in m_data to send - UInt32 m_ptr; - }; - typedef std::list ReplyList; - typedef std::map ReplyMap; - typedef std::map ReplyEventMask; + // index of next byte in m_data to send + UInt32 m_ptr; + }; + typedef std::list ReplyList; + typedef std::map ReplyMap; + typedef std::map ReplyEventMask; - // ICCCM interoperability methods - void icccmFillCache(); - bool icccmGetSelection(Atom target, - Atom* actualTarget, String* data) const; - Time icccmGetTime() const; + // ICCCM interoperability methods + void icccmFillCache(); + bool icccmGetSelection(Atom target, Atom *actualTarget, String *data) const; + Time icccmGetTime() const; - // motif interoperability methods - bool motifLockClipboard() const; - void motifUnlockClipboard() const; - bool motifOwnsClipboard() const; - void motifFillCache(); - bool motifGetSelection(const MotifClipFormat*, - Atom* actualTarget, String* data) const; - Time motifGetTime() const; + // motif interoperability methods + bool motifLockClipboard() const; + void motifUnlockClipboard() const; + bool motifOwnsClipboard() const; + void motifFillCache(); + bool motifGetSelection(const MotifClipFormat *, Atom *actualTarget, + String *data) const; + Time motifGetTime() const; - // reply methods - bool insertMultipleReply(Window, ::Time, Atom); - void insertReply(Reply*); - void pushReplies(); - void pushReplies(ReplyMap::iterator&, - ReplyList&, ReplyList::iterator); - bool sendReply(Reply*); - void clearReplies(); - void clearReplies(ReplyList&); - void sendNotify(Window requestor, Atom selection, - Atom target, Atom property, Time time); - bool wasOwnedAtTime(::Time) const; + // reply methods + bool insertMultipleReply(Window, ::Time, Atom); + void insertReply(Reply *); + void pushReplies(); + void pushReplies(ReplyMap::iterator &, ReplyList &, ReplyList::iterator); + bool sendReply(Reply *); + void clearReplies(); + void clearReplies(ReplyList &); + void sendNotify(Window requestor, Atom selection, Atom target, Atom property, + Time time); + bool wasOwnedAtTime(::Time) const; - // data conversion methods - Atom getTargetsData(String&, int* format) const; - Atom getTimestampData(String&, int* format) const; + // data conversion methods + Atom getTargetsData(String &, int *format) const; + Atom getTimestampData(String &, int *format) const; private: - typedef std::vector ConverterList; + typedef std::vector ConverterList; - Display* m_display; - Window m_window; - ClipboardID m_id; - Atom m_selection; - mutable bool m_open; - mutable Time m_time; - bool m_owner; - mutable Time m_timeOwned; - Time m_timeLost; + Display *m_display; + Window m_window; + ClipboardID m_id; + Atom m_selection; + mutable bool m_open; + mutable Time m_time; + bool m_owner; + mutable Time m_timeOwned; + Time m_timeLost; - // true iff open and clipboard owned by a motif app - mutable bool m_motif; + // true iff open and clipboard owned by a motif app + mutable bool m_motif; - // the added/cached clipboard data - mutable bool m_checkCache; - bool m_cached; - Time m_cacheTime; - bool m_added[kNumFormats]; - String m_data[kNumFormats]; + // the added/cached clipboard data + mutable bool m_checkCache; + bool m_cached; + Time m_cacheTime; + bool m_added[kNumFormats]; + String m_data[kNumFormats]; - // conversion request replies - ReplyMap m_replies; - ReplyEventMask m_eventMasks; + // conversion request replies + ReplyMap m_replies; + ReplyEventMask m_eventMasks; - // clipboard format converters - ConverterList m_converters; + // clipboard format converters + ConverterList m_converters; - // atoms we'll need - Atom m_atomTargets; - Atom m_atomMultiple; - Atom m_atomTimestamp; - Atom m_atomInteger; - Atom m_atomAtom; - Atom m_atomAtomPair; - Atom m_atomData; - Atom m_atomINCR; - Atom m_atomMotifClipLock; - Atom m_atomMotifClipHeader; - Atom m_atomMotifClipAccess; - Atom m_atomGDKSelection; + // atoms we'll need + Atom m_atomTargets; + Atom m_atomMultiple; + Atom m_atomTimestamp; + Atom m_atomInteger; + Atom m_atomAtom; + Atom m_atomAtomPair; + Atom m_atomData; + Atom m_atomINCR; + Atom m_atomMotifClipLock; + Atom m_atomMotifClipHeader; + Atom m_atomMotifClipAccess; + Atom m_atomGDKSelection; }; //! Clipboard format converter interface @@ -339,45 +332,44 @@ converters. */ class IXWindowsClipboardConverter : public IInterface { public: - //! @name accessors - //@{ + //! @name accessors + //@{ - //! Get clipboard format - /*! - Return the clipboard format this object converts from/to. - */ - virtual IClipboard::EFormat - getFormat() const = 0; + //! Get clipboard format + /*! + Return the clipboard format this object converts from/to. + */ + virtual IClipboard::EFormat getFormat() const = 0; - //! Get X11 format atom - /*! - Return the atom representing the X selection format that - this object converts from/to. - */ - virtual Atom getAtom() const = 0; + //! Get X11 format atom + /*! + Return the atom representing the X selection format that + this object converts from/to. + */ + virtual Atom getAtom() const = 0; - //! Get X11 property datum size - /*! - Return the size (in bits) of data elements returned by - toIClipboard(). - */ - virtual int getDataSize() const = 0; + //! Get X11 property datum size + /*! + Return the size (in bits) of data elements returned by + toIClipboard(). + */ + virtual int getDataSize() const = 0; - //! Convert from IClipboard format - /*! - Convert from the IClipboard format to the X selection format. - The input data must be in the IClipboard format returned by - getFormat(). The return data will be in the X selection - format returned by getAtom(). - */ - virtual String fromIClipboard(const String&) const = 0; + //! Convert from IClipboard format + /*! + Convert from the IClipboard format to the X selection format. + The input data must be in the IClipboard format returned by + getFormat(). The return data will be in the X selection + format returned by getAtom(). + */ + virtual String fromIClipboard(const String &) const = 0; - //! Convert to IClipboard format - /*! - Convert from the X selection format to the IClipboard format - (i.e., the reverse of fromIClipboard()). - */ - virtual String toIClipboard(const String&) const = 0; + //! Convert to IClipboard format + /*! + Convert from the X selection format to the IClipboard format + (i.e., the reverse of fromIClipboard()). + */ + virtual String toIClipboard(const String &) const = 0; - //@} + //@} }; diff --git a/src/lib/platform/XWindowsClipboardAnyBitmapConverter.cpp b/src/lib/platform/XWindowsClipboardAnyBitmapConverter.cpp index 4c18b5374..431147fcd 100644 --- a/src/lib/platform/XWindowsClipboardAnyBitmapConverter.cpp +++ b/src/lib/platform/XWindowsClipboardAnyBitmapConverter.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 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 LICENSE 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 @@ -21,171 +21,140 @@ // BMP info header structure struct CBMPInfoHeader { public: - UInt32 biSize; - SInt32 biWidth; - SInt32 biHeight; - UInt16 biPlanes; - UInt16 biBitCount; - UInt32 biCompression; - UInt32 biSizeImage; - SInt32 biXPelsPerMeter; - SInt32 biYPelsPerMeter; - UInt32 biClrUsed; - UInt32 biClrImportant; + UInt32 biSize; + SInt32 biWidth; + SInt32 biHeight; + UInt16 biPlanes; + UInt16 biBitCount; + UInt32 biCompression; + UInt32 biSizeImage; + SInt32 biXPelsPerMeter; + SInt32 biYPelsPerMeter; + UInt32 biClrUsed; + UInt32 biClrImportant; }; // BMP is little-endian -static -void -toLE(UInt8*& dst, UInt16 src) -{ - dst[0] = static_cast(src & 0xffu); - dst[1] = static_cast((src >> 8) & 0xffu); - dst += 2; +static void toLE(UInt8 *&dst, UInt16 src) { + dst[0] = static_cast(src & 0xffu); + dst[1] = static_cast((src >> 8) & 0xffu); + dst += 2; } -static -void -toLE(UInt8*& dst, SInt32 src) -{ - dst[0] = static_cast(src & 0xffu); - dst[1] = static_cast((src >> 8) & 0xffu); - dst[2] = static_cast((src >> 16) & 0xffu); - dst[3] = static_cast((src >> 24) & 0xffu); - dst += 4; +static void toLE(UInt8 *&dst, SInt32 src) { + dst[0] = static_cast(src & 0xffu); + dst[1] = static_cast((src >> 8) & 0xffu); + dst[2] = static_cast((src >> 16) & 0xffu); + dst[3] = static_cast((src >> 24) & 0xffu); + dst += 4; } -static -void -toLE(UInt8*& dst, UInt32 src) -{ - dst[0] = static_cast(src & 0xffu); - dst[1] = static_cast((src >> 8) & 0xffu); - dst[2] = static_cast((src >> 16) & 0xffu); - dst[3] = static_cast((src >> 24) & 0xffu); - dst += 4; +static void toLE(UInt8 *&dst, UInt32 src) { + dst[0] = static_cast(src & 0xffu); + dst[1] = static_cast((src >> 8) & 0xffu); + dst[2] = static_cast((src >> 16) & 0xffu); + dst[3] = static_cast((src >> 24) & 0xffu); + dst += 4; } -static inline -UInt16 -fromLEU16(const UInt8* data) -{ - return static_cast(data[0]) | - (static_cast(data[1]) << 8); +static inline UInt16 fromLEU16(const UInt8 *data) { + return static_cast(data[0]) | (static_cast(data[1]) << 8); } -static inline -SInt32 -fromLES32(const UInt8* data) -{ - return static_cast(static_cast(data[0]) | - (static_cast(data[1]) << 8) | - (static_cast(data[2]) << 16) | - (static_cast(data[3]) << 24)); +static inline SInt32 fromLES32(const UInt8 *data) { + return static_cast(static_cast(data[0]) | + (static_cast(data[1]) << 8) | + (static_cast(data[2]) << 16) | + (static_cast(data[3]) << 24)); } -static inline -UInt32 -fromLEU32(const UInt8* data) -{ - return static_cast(data[0]) | - (static_cast(data[1]) << 8) | - (static_cast(data[2]) << 16) | - (static_cast(data[3]) << 24); +static inline UInt32 fromLEU32(const UInt8 *data) { + return static_cast(data[0]) | (static_cast(data[1]) << 8) | + (static_cast(data[2]) << 16) | + (static_cast(data[3]) << 24); } - // // XWindowsClipboardAnyBitmapConverter // -XWindowsClipboardAnyBitmapConverter::XWindowsClipboardAnyBitmapConverter() -{ - // do nothing +XWindowsClipboardAnyBitmapConverter::XWindowsClipboardAnyBitmapConverter() { + // do nothing } -XWindowsClipboardAnyBitmapConverter::~XWindowsClipboardAnyBitmapConverter() -{ - // do nothing +XWindowsClipboardAnyBitmapConverter::~XWindowsClipboardAnyBitmapConverter() { + // do nothing } -IClipboard::EFormat -XWindowsClipboardAnyBitmapConverter::getFormat() const -{ - return IClipboard::kBitmap; +IClipboard::EFormat XWindowsClipboardAnyBitmapConverter::getFormat() const { + return IClipboard::kBitmap; } -int -XWindowsClipboardAnyBitmapConverter::getDataSize() const -{ - return 8; +int XWindowsClipboardAnyBitmapConverter::getDataSize() const { return 8; } + +String +XWindowsClipboardAnyBitmapConverter::fromIClipboard(const String &bmp) const { + // fill BMP info header with native-endian data + CBMPInfoHeader infoHeader; + const UInt8 *rawBMPInfoHeader = reinterpret_cast(bmp.data()); + infoHeader.biSize = fromLEU32(rawBMPInfoHeader + 0); + infoHeader.biWidth = fromLES32(rawBMPInfoHeader + 4); + infoHeader.biHeight = fromLES32(rawBMPInfoHeader + 8); + infoHeader.biPlanes = fromLEU16(rawBMPInfoHeader + 12); + infoHeader.biBitCount = fromLEU16(rawBMPInfoHeader + 14); + infoHeader.biCompression = fromLEU32(rawBMPInfoHeader + 16); + infoHeader.biSizeImage = fromLEU32(rawBMPInfoHeader + 20); + infoHeader.biXPelsPerMeter = fromLES32(rawBMPInfoHeader + 24); + infoHeader.biYPelsPerMeter = fromLES32(rawBMPInfoHeader + 28); + infoHeader.biClrUsed = fromLEU32(rawBMPInfoHeader + 32); + infoHeader.biClrImportant = fromLEU32(rawBMPInfoHeader + 36); + + // check that format is acceptable + if (infoHeader.biSize != 40 || infoHeader.biWidth == 0 || + infoHeader.biHeight == 0 || infoHeader.biPlanes != 0 || + infoHeader.biCompression != 0 || + (infoHeader.biBitCount != 24 && infoHeader.biBitCount != 32)) { + return String(); + } + + // convert to image format + const UInt8 *rawBMPPixels = rawBMPInfoHeader + 40; + if (infoHeader.biBitCount == 24) { + return doBGRFromIClipboard(rawBMPPixels, infoHeader.biWidth, + infoHeader.biHeight); + } else { + return doBGRAFromIClipboard(rawBMPPixels, infoHeader.biWidth, + infoHeader.biHeight); + } } String -XWindowsClipboardAnyBitmapConverter::fromIClipboard(const String& bmp) const -{ - // fill BMP info header with native-endian data - CBMPInfoHeader infoHeader; - const UInt8* rawBMPInfoHeader = reinterpret_cast(bmp.data()); - infoHeader.biSize = fromLEU32(rawBMPInfoHeader + 0); - infoHeader.biWidth = fromLES32(rawBMPInfoHeader + 4); - infoHeader.biHeight = fromLES32(rawBMPInfoHeader + 8); - infoHeader.biPlanes = fromLEU16(rawBMPInfoHeader + 12); - infoHeader.biBitCount = fromLEU16(rawBMPInfoHeader + 14); - infoHeader.biCompression = fromLEU32(rawBMPInfoHeader + 16); - infoHeader.biSizeImage = fromLEU32(rawBMPInfoHeader + 20); - infoHeader.biXPelsPerMeter = fromLES32(rawBMPInfoHeader + 24); - infoHeader.biYPelsPerMeter = fromLES32(rawBMPInfoHeader + 28); - infoHeader.biClrUsed = fromLEU32(rawBMPInfoHeader + 32); - infoHeader.biClrImportant = fromLEU32(rawBMPInfoHeader + 36); +XWindowsClipboardAnyBitmapConverter::toIClipboard(const String &image) const { + // convert to raw BMP data + UInt32 w, h, depth; + String rawBMP = doToIClipboard(image, w, h, depth); + if (rawBMP.empty() || w == 0 || h == 0 || (depth != 24 && depth != 32)) { + return String(); + } - // check that format is acceptable - if (infoHeader.biSize != 40 || - infoHeader.biWidth == 0 || infoHeader.biHeight == 0 || - infoHeader.biPlanes != 0 || infoHeader.biCompression != 0 || - (infoHeader.biBitCount != 24 && infoHeader.biBitCount != 32)) { - return String(); - } + // fill BMP info header with little-endian data + UInt8 infoHeader[40]; + UInt8 *dst = infoHeader; + toLE(dst, static_cast(40)); + toLE(dst, static_cast(w)); + toLE(dst, static_cast(h)); + toLE(dst, static_cast(1)); + toLE(dst, static_cast(depth)); + toLE(dst, static_cast(0)); // BI_RGB + toLE(dst, static_cast(image.size())); + toLE(dst, static_cast(2834)); // 72 dpi + toLE(dst, static_cast(2834)); // 72 dpi + toLE(dst, static_cast(0)); + toLE(dst, static_cast(0)); - // convert to image format - const UInt8* rawBMPPixels = rawBMPInfoHeader + 40; - if (infoHeader.biBitCount == 24) { - return doBGRFromIClipboard(rawBMPPixels, - infoHeader.biWidth, infoHeader.biHeight); - } - else { - return doBGRAFromIClipboard(rawBMPPixels, - infoHeader.biWidth, infoHeader.biHeight); - } -} - -String -XWindowsClipboardAnyBitmapConverter::toIClipboard(const String& image) const -{ - // convert to raw BMP data - UInt32 w, h, depth; - String rawBMP = doToIClipboard(image, w, h, depth); - if (rawBMP.empty() || w == 0 || h == 0 || (depth != 24 && depth != 32)) { - return String(); - } - - // fill BMP info header with little-endian data - UInt8 infoHeader[40]; - UInt8* dst = infoHeader; - toLE(dst, static_cast(40)); - toLE(dst, static_cast(w)); - toLE(dst, static_cast(h)); - toLE(dst, static_cast(1)); - toLE(dst, static_cast(depth)); - toLE(dst, static_cast(0)); // BI_RGB - toLE(dst, static_cast(image.size())); - toLE(dst, static_cast(2834)); // 72 dpi - toLE(dst, static_cast(2834)); // 72 dpi - toLE(dst, static_cast(0)); - toLE(dst, static_cast(0)); - - // construct image - return String(reinterpret_cast(infoHeader), - sizeof(infoHeader)) + rawBMP; + // construct image + return String(reinterpret_cast(infoHeader), + sizeof(infoHeader)) + + rawBMP; } diff --git a/src/lib/platform/XWindowsClipboardAnyBitmapConverter.h b/src/lib/platform/XWindowsClipboardAnyBitmapConverter.h index e99d7dc51..8fa072def 100644 --- a/src/lib/platform/XWindowsClipboardAnyBitmapConverter.h +++ b/src/lib/platform/XWindowsClipboardAnyBitmapConverter.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 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 LICENSE 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 @@ -21,40 +21,38 @@ #include "platform/XWindowsClipboard.h" //! Convert to/from some text encoding -class XWindowsClipboardAnyBitmapConverter : - public IXWindowsClipboardConverter { +class XWindowsClipboardAnyBitmapConverter : public IXWindowsClipboardConverter { public: - XWindowsClipboardAnyBitmapConverter(); - virtual ~XWindowsClipboardAnyBitmapConverter(); + XWindowsClipboardAnyBitmapConverter(); + virtual ~XWindowsClipboardAnyBitmapConverter(); - // IXWindowsClipboardConverter overrides - virtual IClipboard::EFormat - getFormat() const; - virtual Atom getAtom() const = 0; - virtual int getDataSize() const; - virtual String fromIClipboard(const String&) const; - virtual String toIClipboard(const String&) const; + // IXWindowsClipboardConverter overrides + virtual IClipboard::EFormat getFormat() const; + virtual Atom getAtom() const = 0; + virtual int getDataSize() const; + virtual String fromIClipboard(const String &) const; + virtual String toIClipboard(const String &) const; protected: - //! Convert from IClipboard format - /*! - Convert raw BGR pixel data to another image format. - */ - virtual String doBGRFromIClipboard(const UInt8* bgrData, - UInt32 w, UInt32 h) const = 0; + //! Convert from IClipboard format + /*! + Convert raw BGR pixel data to another image format. + */ + virtual String doBGRFromIClipboard(const UInt8 *bgrData, UInt32 w, + UInt32 h) const = 0; - //! Convert from IClipboard format - /*! - Convert raw BGRA pixel data to another image format. - */ - virtual String doBGRAFromIClipboard(const UInt8* bgrData, - UInt32 w, UInt32 h) const = 0; + //! Convert from IClipboard format + /*! + Convert raw BGRA pixel data to another image format. + */ + virtual String doBGRAFromIClipboard(const UInt8 *bgrData, UInt32 w, + UInt32 h) const = 0; - //! Convert to IClipboard format - /*! - Convert an image into raw BGR or BGRA image data and store the - width, height, and image depth (24 or 32). - */ - virtual String doToIClipboard(const String&, - UInt32& w, UInt32& h, UInt32& depth) const = 0; + //! Convert to IClipboard format + /*! + Convert an image into raw BGR or BGRA image data and store the + width, height, and image depth (24 or 32). + */ + virtual String doToIClipboard(const String &, UInt32 &w, UInt32 &h, + UInt32 &depth) const = 0; }; diff --git a/src/lib/platform/XWindowsClipboardBMPConverter.cpp b/src/lib/platform/XWindowsClipboardBMPConverter.cpp index 22c6dcbe1..844875788 100644 --- a/src/lib/platform/XWindowsClipboardBMPConverter.cpp +++ b/src/lib/platform/XWindowsClipboardBMPConverter.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 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 LICENSE 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 @@ -21,123 +21,92 @@ // BMP file header structure struct CBMPHeader { public: - UInt16 type; - UInt32 size; - UInt16 reserved1; - UInt16 reserved2; - UInt32 offset; + UInt16 type; + UInt32 size; + UInt16 reserved1; + UInt16 reserved2; + UInt32 offset; }; // BMP is little-endian -static inline -UInt32 -fromLEU32(const UInt8* data) -{ - return static_cast(data[0]) | - (static_cast(data[1]) << 8) | - (static_cast(data[2]) << 16) | - (static_cast(data[3]) << 24); +static inline UInt32 fromLEU32(const UInt8 *data) { + return static_cast(data[0]) | (static_cast(data[1]) << 8) | + (static_cast(data[2]) << 16) | + (static_cast(data[3]) << 24); } -static -void -toLE(UInt8*& dst, char src) -{ - dst[0] = static_cast(src); - dst += 1; +static void toLE(UInt8 *&dst, char src) { + dst[0] = static_cast(src); + dst += 1; } -static -void -toLE(UInt8*& dst, UInt16 src) -{ - dst[0] = static_cast(src & 0xffu); - dst[1] = static_cast((src >> 8) & 0xffu); - dst += 2; +static void toLE(UInt8 *&dst, UInt16 src) { + dst[0] = static_cast(src & 0xffu); + dst[1] = static_cast((src >> 8) & 0xffu); + dst += 2; } -static -void -toLE(UInt8*& dst, UInt32 src) -{ - dst[0] = static_cast(src & 0xffu); - dst[1] = static_cast((src >> 8) & 0xffu); - dst[2] = static_cast((src >> 16) & 0xffu); - dst[3] = static_cast((src >> 24) & 0xffu); - dst += 4; +static void toLE(UInt8 *&dst, UInt32 src) { + dst[0] = static_cast(src & 0xffu); + dst[1] = static_cast((src >> 8) & 0xffu); + dst[2] = static_cast((src >> 16) & 0xffu); + dst[3] = static_cast((src >> 24) & 0xffu); + dst += 4; } // // XWindowsClipboardBMPConverter // -XWindowsClipboardBMPConverter::XWindowsClipboardBMPConverter( - Display* display) : - m_atom(XInternAtom(display, "image/bmp", False)) -{ - // do nothing +XWindowsClipboardBMPConverter::XWindowsClipboardBMPConverter(Display *display) + : m_atom(XInternAtom(display, "image/bmp", False)) { + // do nothing } -XWindowsClipboardBMPConverter::~XWindowsClipboardBMPConverter() -{ - // do nothing +XWindowsClipboardBMPConverter::~XWindowsClipboardBMPConverter() { + // do nothing } -IClipboard::EFormat -XWindowsClipboardBMPConverter::getFormat() const -{ - return IClipboard::kBitmap; +IClipboard::EFormat XWindowsClipboardBMPConverter::getFormat() const { + return IClipboard::kBitmap; } -Atom -XWindowsClipboardBMPConverter::getAtom() const -{ - return m_atom; +Atom XWindowsClipboardBMPConverter::getAtom() const { return m_atom; } + +int XWindowsClipboardBMPConverter::getDataSize() const { return 8; } + +String XWindowsClipboardBMPConverter::fromIClipboard(const String &bmp) const { + // create BMP image + UInt8 header[14]; + UInt8 *dst = header; + toLE(dst, 'B'); + toLE(dst, 'M'); + toLE(dst, static_cast(14 + bmp.size())); + toLE(dst, static_cast(0)); + toLE(dst, static_cast(0)); + toLE(dst, static_cast(14 + 40)); + return String(reinterpret_cast(header), 14) + bmp; } -int -XWindowsClipboardBMPConverter::getDataSize() const -{ - return 8; -} - -String -XWindowsClipboardBMPConverter::fromIClipboard(const String& bmp) const -{ - // create BMP image - UInt8 header[14]; - UInt8* dst = header; - toLE(dst, 'B'); - toLE(dst, 'M'); - toLE(dst, static_cast(14 + bmp.size())); - toLE(dst, static_cast(0)); - toLE(dst, static_cast(0)); - toLE(dst, static_cast(14 + 40)); - return String(reinterpret_cast(header), 14) + bmp; -} - -String -XWindowsClipboardBMPConverter::toIClipboard(const String& bmp) const -{ - // make sure data is big enough for a BMP file - if (bmp.size() <= 14 + 40) { - return String(); - } - - // check BMP file header - const UInt8* rawBMPHeader = reinterpret_cast(bmp.data()); - if (rawBMPHeader[0] != 'B' || rawBMPHeader[1] != 'M') { - return String(); - } - - // get offset to image data - UInt32 offset = fromLEU32(rawBMPHeader + 10); - - // construct BMP - if (offset == 14 + 40) { - return bmp.substr(14); - } - else { - return bmp.substr(14, 40) + bmp.substr(offset, bmp.size() - offset); - } +String XWindowsClipboardBMPConverter::toIClipboard(const String &bmp) const { + // make sure data is big enough for a BMP file + if (bmp.size() <= 14 + 40) { + return String(); + } + + // check BMP file header + const UInt8 *rawBMPHeader = reinterpret_cast(bmp.data()); + if (rawBMPHeader[0] != 'B' || rawBMPHeader[1] != 'M') { + return String(); + } + + // get offset to image data + UInt32 offset = fromLEU32(rawBMPHeader + 10); + + // construct BMP + if (offset == 14 + 40) { + return bmp.substr(14); + } else { + return bmp.substr(14, 40) + bmp.substr(offset, bmp.size() - offset); + } } diff --git a/src/lib/platform/XWindowsClipboardBMPConverter.h b/src/lib/platform/XWindowsClipboardBMPConverter.h index 0f99a32ab..37f8555a1 100644 --- a/src/lib/platform/XWindowsClipboardBMPConverter.h +++ b/src/lib/platform/XWindowsClipboardBMPConverter.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 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 LICENSE 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 @@ -21,20 +21,18 @@ #include "platform/XWindowsClipboard.h" //! Convert to/from some text encoding -class XWindowsClipboardBMPConverter : - public IXWindowsClipboardConverter { +class XWindowsClipboardBMPConverter : public IXWindowsClipboardConverter { public: - XWindowsClipboardBMPConverter(Display* display); - virtual ~XWindowsClipboardBMPConverter(); + XWindowsClipboardBMPConverter(Display *display); + virtual ~XWindowsClipboardBMPConverter(); - // IXWindowsClipboardConverter overrides - virtual IClipboard::EFormat - getFormat() const; - virtual Atom getAtom() const; - virtual int getDataSize() const; - virtual String fromIClipboard(const String&) const; - virtual String toIClipboard(const String&) const; + // IXWindowsClipboardConverter overrides + virtual IClipboard::EFormat getFormat() const; + virtual Atom getAtom() const; + virtual int getDataSize() const; + virtual String fromIClipboard(const String &) const; + virtual String toIClipboard(const String &) const; private: - Atom m_atom; + Atom m_atom; }; diff --git a/src/lib/platform/XWindowsClipboardHTMLConverter.cpp b/src/lib/platform/XWindowsClipboardHTMLConverter.cpp index fb7cbdde4..7cb074759 100644 --- a/src/lib/platform/XWindowsClipboardHTMLConverter.cpp +++ b/src/lib/platform/XWindowsClipboardHTMLConverter.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 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 LICENSE 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 @@ -24,51 +24,33 @@ // XWindowsClipboardHTMLConverter // -XWindowsClipboardHTMLConverter::XWindowsClipboardHTMLConverter( - Display* display, const char* name) : - m_atom(XInternAtom(display, name, False)) -{ - // do nothing +XWindowsClipboardHTMLConverter::XWindowsClipboardHTMLConverter(Display *display, + const char *name) + : m_atom(XInternAtom(display, name, False)) { + // do nothing } -XWindowsClipboardHTMLConverter::~XWindowsClipboardHTMLConverter() -{ - // do nothing +XWindowsClipboardHTMLConverter::~XWindowsClipboardHTMLConverter() { + // do nothing } -IClipboard::EFormat -XWindowsClipboardHTMLConverter::getFormat() const -{ - return IClipboard::kHTML; +IClipboard::EFormat XWindowsClipboardHTMLConverter::getFormat() const { + return IClipboard::kHTML; } -Atom -XWindowsClipboardHTMLConverter::getAtom() const -{ - return m_atom; -} +Atom XWindowsClipboardHTMLConverter::getAtom() const { return m_atom; } -int -XWindowsClipboardHTMLConverter::getDataSize() const -{ - return 8; -} +int XWindowsClipboardHTMLConverter::getDataSize() const { return 8; } String -XWindowsClipboardHTMLConverter::fromIClipboard(const String& data) const -{ +XWindowsClipboardHTMLConverter::fromIClipboard(const String &data) const { + return data; +} + +String XWindowsClipboardHTMLConverter::toIClipboard(const String &data) const { + if (Unicode::isUTF8(data)) { return data; -} - -String -XWindowsClipboardHTMLConverter::toIClipboard(const String& data) const -{ - if (Unicode::isUTF8(data)) - { - return data; - } - else - { - return Unicode::UTF16ToUTF8(data); - } + } else { + return Unicode::UTF16ToUTF8(data); + } } diff --git a/src/lib/platform/XWindowsClipboardHTMLConverter.h b/src/lib/platform/XWindowsClipboardHTMLConverter.h index 32e5bdd8a..93ae704b0 100644 --- a/src/lib/platform/XWindowsClipboardHTMLConverter.h +++ b/src/lib/platform/XWindowsClipboardHTMLConverter.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 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 LICENSE 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 @@ -23,20 +23,19 @@ //! Convert to/from HTML encoding class XWindowsClipboardHTMLConverter : public IXWindowsClipboardConverter { public: - /*! - \c name is converted to an atom and that is reported by getAtom(). - */ - XWindowsClipboardHTMLConverter(Display* display, const char* name); - virtual ~XWindowsClipboardHTMLConverter(); + /*! + \c name is converted to an atom and that is reported by getAtom(). + */ + XWindowsClipboardHTMLConverter(Display *display, const char *name); + virtual ~XWindowsClipboardHTMLConverter(); - // IXWindowsClipboardConverter overrides - virtual IClipboard::EFormat - getFormat() const; - virtual Atom getAtom() const; - virtual int getDataSize() const; - virtual String fromIClipboard(const String&) const; - virtual String toIClipboard(const String&) const; + // IXWindowsClipboardConverter overrides + virtual IClipboard::EFormat getFormat() const; + virtual Atom getAtom() const; + virtual int getDataSize() const; + virtual String fromIClipboard(const String &) const; + virtual String toIClipboard(const String &) const; private: - Atom m_atom; + Atom m_atom; }; diff --git a/src/lib/platform/XWindowsClipboardTextConverter.cpp b/src/lib/platform/XWindowsClipboardTextConverter.cpp index 7d055f10c..dedfd714b 100644 --- a/src/lib/platform/XWindowsClipboardTextConverter.cpp +++ b/src/lib/platform/XWindowsClipboardTextConverter.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -24,56 +24,41 @@ // XWindowsClipboardTextConverter // -XWindowsClipboardTextConverter::XWindowsClipboardTextConverter( - Display* display, const char* name) : - m_atom(XInternAtom(display, name, False)) -{ - // do nothing +XWindowsClipboardTextConverter::XWindowsClipboardTextConverter(Display *display, + const char *name) + : m_atom(XInternAtom(display, name, False)) { + // do nothing } -XWindowsClipboardTextConverter::~XWindowsClipboardTextConverter() -{ - // do nothing +XWindowsClipboardTextConverter::~XWindowsClipboardTextConverter() { + // do nothing } -IClipboard::EFormat -XWindowsClipboardTextConverter::getFormat() const -{ - return IClipboard::kText; +IClipboard::EFormat XWindowsClipboardTextConverter::getFormat() const { + return IClipboard::kText; } -Atom -XWindowsClipboardTextConverter::getAtom() const -{ - return m_atom; -} +Atom XWindowsClipboardTextConverter::getAtom() const { return m_atom; } -int -XWindowsClipboardTextConverter::getDataSize() const -{ - return 8; -} +int XWindowsClipboardTextConverter::getDataSize() const { return 8; } String -XWindowsClipboardTextConverter::fromIClipboard(const String& data) const -{ - return Unicode::UTF8ToText(data); +XWindowsClipboardTextConverter::fromIClipboard(const String &data) const { + return Unicode::UTF8ToText(data); } -String -XWindowsClipboardTextConverter::toIClipboard(const String& data) const -{ - // convert to UTF-8 - bool errors; - String utf8 = Unicode::textToUTF8(data, &errors); +String XWindowsClipboardTextConverter::toIClipboard(const String &data) const { + // convert to UTF-8 + bool errors; + String utf8 = Unicode::textToUTF8(data, &errors); - // if there were decoding errors then, to support old applications - // that don't understand UTF-8 but can report the exact binary - // UTF-8 representation, see if the data appears to be UTF-8. if - // so then use it as is. - if (errors && Unicode::isUTF8(data)) { - return data; - } + // if there were decoding errors then, to support old applications + // that don't understand UTF-8 but can report the exact binary + // UTF-8 representation, see if the data appears to be UTF-8. if + // so then use it as is. + if (errors && Unicode::isUTF8(data)) { + return data; + } - return utf8; + return utf8; } diff --git a/src/lib/platform/XWindowsClipboardTextConverter.h b/src/lib/platform/XWindowsClipboardTextConverter.h index 0ad87ceba..6c7b789b0 100644 --- a/src/lib/platform/XWindowsClipboardTextConverter.h +++ b/src/lib/platform/XWindowsClipboardTextConverter.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -23,20 +23,19 @@ //! Convert to/from locale text encoding class XWindowsClipboardTextConverter : public IXWindowsClipboardConverter { public: - /*! - \c name is converted to an atom and that is reported by getAtom(). - */ - XWindowsClipboardTextConverter(Display* display, const char* name); - virtual ~XWindowsClipboardTextConverter(); + /*! + \c name is converted to an atom and that is reported by getAtom(). + */ + XWindowsClipboardTextConverter(Display *display, const char *name); + virtual ~XWindowsClipboardTextConverter(); - // IXWindowsClipboardConverter overrides - virtual IClipboard::EFormat - getFormat() const; - virtual Atom getAtom() const; - virtual int getDataSize() const; - virtual String fromIClipboard(const String&) const; - virtual String toIClipboard(const String&) const; + // IXWindowsClipboardConverter overrides + virtual IClipboard::EFormat getFormat() const; + virtual Atom getAtom() const; + virtual int getDataSize() const; + virtual String fromIClipboard(const String &) const; + virtual String toIClipboard(const String &) const; private: - Atom m_atom; + Atom m_atom; }; diff --git a/src/lib/platform/XWindowsClipboardUCS2Converter.cpp b/src/lib/platform/XWindowsClipboardUCS2Converter.cpp index 82bebbdb5..73bdd7e39 100644 --- a/src/lib/platform/XWindowsClipboardUCS2Converter.cpp +++ b/src/lib/platform/XWindowsClipboardUCS2Converter.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -24,44 +24,29 @@ // XWindowsClipboardUCS2Converter // -XWindowsClipboardUCS2Converter::XWindowsClipboardUCS2Converter( - Display* display, const char* name) : - m_atom(XInternAtom(display, name, False)) -{ - // do nothing +XWindowsClipboardUCS2Converter::XWindowsClipboardUCS2Converter(Display *display, + const char *name) + : m_atom(XInternAtom(display, name, False)) { + // do nothing } -XWindowsClipboardUCS2Converter::~XWindowsClipboardUCS2Converter() -{ - // do nothing +XWindowsClipboardUCS2Converter::~XWindowsClipboardUCS2Converter() { + // do nothing } -IClipboard::EFormat -XWindowsClipboardUCS2Converter::getFormat() const -{ - return IClipboard::kText; +IClipboard::EFormat XWindowsClipboardUCS2Converter::getFormat() const { + return IClipboard::kText; } -Atom -XWindowsClipboardUCS2Converter::getAtom() const -{ - return m_atom; -} +Atom XWindowsClipboardUCS2Converter::getAtom() const { return m_atom; } -int -XWindowsClipboardUCS2Converter::getDataSize() const -{ - return 16; -} +int XWindowsClipboardUCS2Converter::getDataSize() const { return 16; } String -XWindowsClipboardUCS2Converter::fromIClipboard(const String& data) const -{ - return Unicode::UTF8ToUCS2(data); +XWindowsClipboardUCS2Converter::fromIClipboard(const String &data) const { + return Unicode::UTF8ToUCS2(data); } -String -XWindowsClipboardUCS2Converter::toIClipboard(const String& data) const -{ - return Unicode::UCS2ToUTF8(data); +String XWindowsClipboardUCS2Converter::toIClipboard(const String &data) const { + return Unicode::UCS2ToUTF8(data); } diff --git a/src/lib/platform/XWindowsClipboardUCS2Converter.h b/src/lib/platform/XWindowsClipboardUCS2Converter.h index f57ad1e23..7d7b77be9 100644 --- a/src/lib/platform/XWindowsClipboardUCS2Converter.h +++ b/src/lib/platform/XWindowsClipboardUCS2Converter.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -23,20 +23,19 @@ //! Convert to/from UCS-2 encoding class XWindowsClipboardUCS2Converter : public IXWindowsClipboardConverter { public: - /*! - \c name is converted to an atom and that is reported by getAtom(). - */ - XWindowsClipboardUCS2Converter(Display* display, const char* name); - virtual ~XWindowsClipboardUCS2Converter(); + /*! + \c name is converted to an atom and that is reported by getAtom(). + */ + XWindowsClipboardUCS2Converter(Display *display, const char *name); + virtual ~XWindowsClipboardUCS2Converter(); - // IXWindowsClipboardConverter overrides - virtual IClipboard::EFormat - getFormat() const; - virtual Atom getAtom() const; - virtual int getDataSize() const; - virtual String fromIClipboard(const String&) const; - virtual String toIClipboard(const String&) const; + // IXWindowsClipboardConverter overrides + virtual IClipboard::EFormat getFormat() const; + virtual Atom getAtom() const; + virtual int getDataSize() const; + virtual String fromIClipboard(const String &) const; + virtual String toIClipboard(const String &) const; private: - Atom m_atom; + Atom m_atom; }; diff --git a/src/lib/platform/XWindowsClipboardUTF8Converter.cpp b/src/lib/platform/XWindowsClipboardUTF8Converter.cpp index 506a5354a..db5582539 100644 --- a/src/lib/platform/XWindowsClipboardUTF8Converter.cpp +++ b/src/lib/platform/XWindowsClipboardUTF8Converter.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -24,68 +24,49 @@ // XWindowsClipboardUTF8Converter // -XWindowsClipboardUTF8Converter::XWindowsClipboardUTF8Converter( - Display* display, const char* name, bool normalize) : - m_atom(XInternAtom(display, name, False)), m_normalize(normalize) -{ - // do nothing +XWindowsClipboardUTF8Converter::XWindowsClipboardUTF8Converter(Display *display, + const char *name, + bool normalize) + : m_atom(XInternAtom(display, name, False)), m_normalize(normalize) { + // do nothing } -XWindowsClipboardUTF8Converter::~XWindowsClipboardUTF8Converter() -{ - // do nothing +XWindowsClipboardUTF8Converter::~XWindowsClipboardUTF8Converter() { + // do nothing } -IClipboard::EFormat -XWindowsClipboardUTF8Converter::getFormat() const -{ - return IClipboard::kText; +IClipboard::EFormat XWindowsClipboardUTF8Converter::getFormat() const { + return IClipboard::kText; } -Atom -XWindowsClipboardUTF8Converter::getAtom() const -{ - return m_atom; -} +Atom XWindowsClipboardUTF8Converter::getAtom() const { return m_atom; } -int -XWindowsClipboardUTF8Converter::getDataSize() const -{ - return 8; -} +int XWindowsClipboardUTF8Converter::getDataSize() const { return 8; } -static -bool -isCR(char ch) -{ - return (ch == '\r'); -} +static bool isCR(char ch) { return (ch == '\r'); } String -XWindowsClipboardUTF8Converter::fromIClipboard(const String& data) const -{ - return data; +XWindowsClipboardUTF8Converter::fromIClipboard(const String &data) const { + return data; } -String -XWindowsClipboardUTF8Converter::toIClipboard(const String& data) const -{ - // https://bugzilla.mozilla.org/show_bug.cgi?id=1547595 - // GTK normalizes the clipboard's line endings to CRLF (\r\n) internally. - // When sending the raw data to other systems, like Windows, where \n is - // converted to \r\n we end up with \r\r\n, resulting in double lines when - // pasting. - // - // This seems to happen only when the clipboard format is - // text/plain;charset=utf8 and not when it's UTF8_STRING. - // When normalize clipboard is set, any \r present in the string is removed +String XWindowsClipboardUTF8Converter::toIClipboard(const String &data) const { + // https://bugzilla.mozilla.org/show_bug.cgi?id=1547595 + // GTK normalizes the clipboard's line endings to CRLF (\r\n) internally. + // When sending the raw data to other systems, like Windows, where \n is + // converted to \r\n we end up with \r\r\n, resulting in double lines when + // pasting. + // + // This seems to happen only when the clipboard format is + // text/plain;charset=utf8 and not when it's UTF8_STRING. + // When normalize clipboard is set, any \r present in the string is removed - if (m_normalize) { - String copy = data; + if (m_normalize) { + String copy = data; - copy.erase(std::remove_if(copy.begin(), copy.end(), isCR), copy.end()); - return copy; - } + copy.erase(std::remove_if(copy.begin(), copy.end(), isCR), copy.end()); + return copy; + } - return data; + return data; } diff --git a/src/lib/platform/XWindowsClipboardUTF8Converter.h b/src/lib/platform/XWindowsClipboardUTF8Converter.h index 29a45a471..ea45fd929 100644 --- a/src/lib/platform/XWindowsClipboardUTF8Converter.h +++ b/src/lib/platform/XWindowsClipboardUTF8Converter.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -23,21 +23,21 @@ //! Convert to/from UTF-8 encoding class XWindowsClipboardUTF8Converter : public IXWindowsClipboardConverter { public: - /*! - \c name is converted to an atom and that is reported by getAtom(). - */ - XWindowsClipboardUTF8Converter(Display* display, const char* name, bool normalize = false); - virtual ~XWindowsClipboardUTF8Converter(); + /*! + \c name is converted to an atom and that is reported by getAtom(). + */ + XWindowsClipboardUTF8Converter(Display *display, const char *name, + bool normalize = false); + virtual ~XWindowsClipboardUTF8Converter(); - // IXWindowsClipboardConverter overrides - virtual IClipboard::EFormat - getFormat() const; - virtual Atom getAtom() const; - virtual int getDataSize() const; - virtual String fromIClipboard(const String&) const; - virtual String toIClipboard(const String&) const; + // IXWindowsClipboardConverter overrides + virtual IClipboard::EFormat getFormat() const; + virtual Atom getAtom() const; + virtual int getDataSize() const; + virtual String fromIClipboard(const String &) const; + virtual String toIClipboard(const String &) const; private: - Atom m_atom; - bool m_normalize; + Atom m_atom; + bool m_normalize; }; diff --git a/src/lib/platform/XWindowsEventQueueBuffer.cpp b/src/lib/platform/XWindowsEventQueueBuffer.cpp index eb0ec53f1..932e06166 100644 --- a/src/lib/platform/XWindowsEventQueueBuffer.cpp +++ b/src/lib/platform/XWindowsEventQueueBuffer.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 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 LICENSE 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 @@ -18,280 +18,250 @@ #include "platform/XWindowsEventQueueBuffer.h" -#include "mt/Lock.h" -#include "mt/Thread.h" #include "base/Event.h" #include "base/IEventQueue.h" +#include "mt/Lock.h" +#include "mt/Thread.h" #include #if HAVE_UNISTD_H -# include +#include #endif #if HAVE_POLL -# include +#include #else -# if HAVE_SYS_SELECT_H -# include -# endif -# if HAVE_SYS_TIME_H -# include -# endif -# if HAVE_SYS_TYPES_H -# include -# endif +#if HAVE_SYS_SELECT_H +#include +#endif +#if HAVE_SYS_TIME_H +#include +#endif +#if HAVE_SYS_TYPES_H +#include +#endif #endif // // EventQueueTimer // -class EventQueueTimer { }; - +class EventQueueTimer {}; // // XWindowsEventQueueBuffer // -XWindowsEventQueueBuffer::XWindowsEventQueueBuffer( - Display* display, Window window, IEventQueue* events) : - m_events(events), - m_display(display), - m_window(window), - m_waiting(false) -{ - assert(m_display != NULL); - assert(m_window != None); +XWindowsEventQueueBuffer::XWindowsEventQueueBuffer(Display *display, + Window window, + IEventQueue *events) + : m_events(events), m_display(display), m_window(window), m_waiting(false) { + assert(m_display != NULL); + assert(m_window != None); - m_userEvent = XInternAtom(m_display, "SYNERGY_USER_EVENT", False); - // set up for pipe hack - int result = pipe(m_pipefd); - assert(result == 0); + m_userEvent = XInternAtom(m_display, "SYNERGY_USER_EVENT", False); + // set up for pipe hack + int result = pipe(m_pipefd); + assert(result == 0); - int pipeflags; - pipeflags = fcntl(m_pipefd[0], F_GETFL); - fcntl(m_pipefd[0], F_SETFL, pipeflags | O_NONBLOCK); - pipeflags = fcntl(m_pipefd[1], F_GETFL); - fcntl(m_pipefd[1], F_SETFL, pipeflags | O_NONBLOCK); + int pipeflags; + pipeflags = fcntl(m_pipefd[0], F_GETFL); + fcntl(m_pipefd[0], F_SETFL, pipeflags | O_NONBLOCK); + pipeflags = fcntl(m_pipefd[1], F_GETFL); + fcntl(m_pipefd[1], F_SETFL, pipeflags | O_NONBLOCK); } -XWindowsEventQueueBuffer::~XWindowsEventQueueBuffer() -{ - // release pipe hack resources - close(m_pipefd[0]); - close(m_pipefd[1]); +XWindowsEventQueueBuffer::~XWindowsEventQueueBuffer() { + // release pipe hack resources + close(m_pipefd[0]); + close(m_pipefd[1]); } -int XWindowsEventQueueBuffer::getPendingCountLocked() -{ - Lock lock(&m_mutex); - return XPending(m_display); -} - -void -XWindowsEventQueueBuffer::waitForEvent(double dtimeout) -{ - Thread::testCancel(); - - // clear out the pipe in preparation for waiting. - - char buf[16]; - ssize_t read_response = read(m_pipefd[0], buf, 15); - - // with linux automake, warnings are treated as errors by default - if (read_response < 0) - { - // todo: handle read response - } - - { - Lock lock(&m_mutex); - // we're now waiting for events - m_waiting = true; - - // push out pending events - flush(); - } - // calling flush may have queued up a new event. - if (!XWindowsEventQueueBuffer::isEmpty()) { - Thread::testCancel(); - return; - } - - // use poll() to wait for a message from the X server or for timeout. - // this is a good deal more efficient than polling and sleeping. -#if HAVE_POLL - struct pollfd pfds[2]; - pfds[0].fd = ConnectionNumber(m_display); - pfds[0].events = POLLIN; - pfds[1].fd = m_pipefd[0]; - pfds[1].events = POLLIN; - int timeout = (dtimeout < 0.0) ? -1 : - static_cast(1000.0 * dtimeout); - int remaining = timeout; - int retval = 0; -#else - struct timeval timeout; - struct timeval* timeoutPtr; - if (dtimeout < 0.0) { - timeoutPtr = NULL; - } - else { - timeout.tv_sec = static_cast(dtimeout); - timeout.tv_usec = static_cast(1.0e+6 * - (dtimeout - timeout.tv_sec)); - timeoutPtr = &timeout; - } - - // initialize file descriptor sets - fd_set rfds; - FD_ZERO(&rfds); - FD_SET(ConnectionNumber(m_display), &rfds); - FD_SET(m_pipefd[0], &rfds); - int nfds; - if (ConnectionNumber(m_display) > m_pipefd[0]) { - nfds = ConnectionNumber(m_display) + 1; - } - else { - nfds = m_pipefd[0] + 1; - } -#endif - // It's possible that the X server has queued events locally - // in xlib's event buffer and not pushed on to the fd. Hence we - // can't simply monitor the fd as we may never be woken up. - // ie addEvent calls flush, XFlush may not send via the fd hence - // there is an event waiting to be sent but we must exit the poll - // before it can. - // Instead we poll for a brief period of time (so if events - // queued locally in the xlib buffer can be processed) - // and continue doing this until timeout is reached. - // The human eye can notice 60hz (ansi) which is 16ms, however - // we want to give the cpu a chance s owe up this to 25ms -#define TIMEOUT_DELAY 25 - - while (((dtimeout < 0.0) || (remaining > 0)) && getPendingCountLocked() == 0 && retval == 0) { -#if HAVE_POLL - retval = poll(pfds, 2, TIMEOUT_DELAY); //16ms = 60hz, but we make it > to play nicely with the cpu - if (pfds[1].revents & POLLIN) { - ssize_t read_response = read(m_pipefd[0], buf, 15); - - // with linux automake, warnings are treated as errors by default - if (read_response < 0) - { - // todo: handle read response - } - - } -#else - retval = select(nfds, - SELECT_TYPE_ARG234 &rfds, - SELECT_TYPE_ARG234 NULL, - SELECT_TYPE_ARG234 NULL, - SELECT_TYPE_ARG5 TIMEOUT_DELAY); - if (FD_SET(m_pipefd[0], &rfds)) { - read(m_pipefd[0], buf, 15); - } -#endif - remaining-=TIMEOUT_DELAY; - } - - { - // we're no longer waiting for events - Lock lock(&m_mutex); - m_waiting = false; - } - - Thread::testCancel(); -} - -IEventQueueBuffer::Type -XWindowsEventQueueBuffer::getEvent(Event& event, UInt32& dataID) -{ +int XWindowsEventQueueBuffer::getPendingCountLocked() { + Lock lock(&m_mutex); + return XPending(m_display); +} + +void XWindowsEventQueueBuffer::waitForEvent(double dtimeout) { + Thread::testCancel(); + + // clear out the pipe in preparation for waiting. + + char buf[16]; + ssize_t read_response = read(m_pipefd[0], buf, 15); + + // with linux automake, warnings are treated as errors by default + if (read_response < 0) { + // todo: handle read response + } + + { Lock lock(&m_mutex); + // we're now waiting for events + m_waiting = true; // push out pending events flush(); + } + // calling flush may have queued up a new event. + if (!XWindowsEventQueueBuffer::isEmpty()) { + Thread::testCancel(); + return; + } - // get next event - XNextEvent(m_display, &m_event); + // use poll() to wait for a message from the X server or for timeout. + // this is a good deal more efficient than polling and sleeping. +#if HAVE_POLL + struct pollfd pfds[2]; + pfds[0].fd = ConnectionNumber(m_display); + pfds[0].events = POLLIN; + pfds[1].fd = m_pipefd[0]; + pfds[1].events = POLLIN; + int timeout = (dtimeout < 0.0) ? -1 : static_cast(1000.0 * dtimeout); + int remaining = timeout; + int retval = 0; +#else + struct timeval timeout; + struct timeval *timeoutPtr; + if (dtimeout < 0.0) { + timeoutPtr = NULL; + } else { + timeout.tv_sec = static_cast(dtimeout); + timeout.tv_usec = static_cast(1.0e+6 * (dtimeout - timeout.tv_sec)); + timeoutPtr = &timeout; + } - // process event - if (m_event.xany.type == ClientMessage && - m_event.xclient.message_type == m_userEvent) { - dataID = static_cast(m_event.xclient.data.l[0]); - return kUser; + // initialize file descriptor sets + fd_set rfds; + FD_ZERO(&rfds); + FD_SET(ConnectionNumber(m_display), &rfds); + FD_SET(m_pipefd[0], &rfds); + int nfds; + if (ConnectionNumber(m_display) > m_pipefd[0]) { + nfds = ConnectionNumber(m_display) + 1; + } else { + nfds = m_pipefd[0] + 1; + } +#endif + // It's possible that the X server has queued events locally + // in xlib's event buffer and not pushed on to the fd. Hence we + // can't simply monitor the fd as we may never be woken up. + // ie addEvent calls flush, XFlush may not send via the fd hence + // there is an event waiting to be sent but we must exit the poll + // before it can. + // Instead we poll for a brief period of time (so if events + // queued locally in the xlib buffer can be processed) + // and continue doing this until timeout is reached. + // The human eye can notice 60hz (ansi) which is 16ms, however + // we want to give the cpu a chance s owe up this to 25ms +#define TIMEOUT_DELAY 25 + + while (((dtimeout < 0.0) || (remaining > 0)) && + getPendingCountLocked() == 0 && retval == 0) { +#if HAVE_POLL + retval = poll(pfds, 2, TIMEOUT_DELAY); // 16ms = 60hz, but we make it > to + // play nicely with the cpu + if (pfds[1].revents & POLLIN) { + ssize_t read_response = read(m_pipefd[0], buf, 15); + + // with linux automake, warnings are treated as errors by default + if (read_response < 0) { + // todo: handle read response + } } - else { - event = Event(Event::kSystem, - m_events->getSystemTarget(), &m_event); - return kSystem; +#else + retval = select(nfds, SELECT_TYPE_ARG234 & rfds, SELECT_TYPE_ARG234 NULL, + SELECT_TYPE_ARG234 NULL, SELECT_TYPE_ARG5 TIMEOUT_DELAY); + if (FD_SET(m_pipefd[0], &rfds)) { + read(m_pipefd[0], buf, 15); } -} +#endif + remaining -= TIMEOUT_DELAY; + } -bool -XWindowsEventQueueBuffer::addEvent(UInt32 dataID) -{ - // prepare a message - XEvent xevent; - xevent.xclient.type = ClientMessage; - xevent.xclient.window = m_window; - xevent.xclient.message_type = m_userEvent; - xevent.xclient.format = 32; - xevent.xclient.data.l[0] = static_cast(dataID); - - // save the message + { + // we're no longer waiting for events Lock lock(&m_mutex); - m_postedEvents.push_back(xevent); + m_waiting = false; + } - // if we're currently waiting for an event then send saved events to - // the X server now. if we're not waiting then some other thread - // might be using the display connection so we can't safely use it - // too. - if (m_waiting) { - flush(); - // Send a character through the round-trip pipe to wake a thread - // that is waiting for a ConnectionNumber() socket to be readable. - // The flush call can read incoming data from the socket and put - // it in Xlib's input buffer. That sneaks it past the other thread. - ssize_t write_response = write(m_pipefd[1], "!", 1); + Thread::testCancel(); +} - // with linux automake, warnings are treated as errors by default - if (write_response < 0) - { - // todo: handle read response - } +IEventQueueBuffer::Type XWindowsEventQueueBuffer::getEvent(Event &event, + UInt32 &dataID) { + Lock lock(&m_mutex); + + // push out pending events + flush(); + + // get next event + XNextEvent(m_display, &m_event); + + // process event + if (m_event.xany.type == ClientMessage && + m_event.xclient.message_type == m_userEvent) { + dataID = static_cast(m_event.xclient.data.l[0]); + return kUser; + } else { + event = Event(Event::kSystem, m_events->getSystemTarget(), &m_event); + return kSystem; + } +} + +bool XWindowsEventQueueBuffer::addEvent(UInt32 dataID) { + // prepare a message + XEvent xevent; + xevent.xclient.type = ClientMessage; + xevent.xclient.window = m_window; + xevent.xclient.message_type = m_userEvent; + xevent.xclient.format = 32; + xevent.xclient.data.l[0] = static_cast(dataID); + + // save the message + Lock lock(&m_mutex); + m_postedEvents.push_back(xevent); + + // if we're currently waiting for an event then send saved events to + // the X server now. if we're not waiting then some other thread + // might be using the display connection so we can't safely use it + // too. + if (m_waiting) { + flush(); + // Send a character through the round-trip pipe to wake a thread + // that is waiting for a ConnectionNumber() socket to be readable. + // The flush call can read incoming data from the socket and put + // it in Xlib's input buffer. That sneaks it past the other thread. + ssize_t write_response = write(m_pipefd[1], "!", 1); + + // with linux automake, warnings are treated as errors by default + if (write_response < 0) { + // todo: handle read response } + } - return true; + return true; } -bool -XWindowsEventQueueBuffer::isEmpty() const -{ - Lock lock(&m_mutex); - return (XPending(m_display) == 0 ); +bool XWindowsEventQueueBuffer::isEmpty() const { + Lock lock(&m_mutex); + return (XPending(m_display) == 0); } -EventQueueTimer* -XWindowsEventQueueBuffer::newTimer(double, bool) const -{ - return new EventQueueTimer; +EventQueueTimer *XWindowsEventQueueBuffer::newTimer(double, bool) const { + return new EventQueueTimer; } -void -XWindowsEventQueueBuffer::deleteTimer(EventQueueTimer* timer) const -{ - delete timer; +void XWindowsEventQueueBuffer::deleteTimer(EventQueueTimer *timer) const { + delete timer; } -void -XWindowsEventQueueBuffer::flush() -{ - // note -- m_mutex must be locked on entry +void XWindowsEventQueueBuffer::flush() { + // note -- m_mutex must be locked on entry - // flush the posted event list to the X server - for (size_t i = 0; i < m_postedEvents.size(); ++i) { - XSendEvent(m_display, m_window, False, 0, &m_postedEvents[i]); - } - XFlush(m_display); - m_postedEvents.clear(); + // flush the posted event list to the X server + for (size_t i = 0; i < m_postedEvents.size(); ++i) { + XSendEvent(m_display, m_window, False, 0, &m_postedEvents[i]); + } + XFlush(m_display); + m_postedEvents.clear(); } diff --git a/src/lib/platform/XWindowsEventQueueBuffer.h b/src/lib/platform/XWindowsEventQueueBuffer.h index 9cedcc48e..b3d093145 100644 --- a/src/lib/platform/XWindowsEventQueueBuffer.h +++ b/src/lib/platform/XWindowsEventQueueBuffer.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 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 LICENSE 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 @@ -18,14 +18,14 @@ #pragma once -#include "mt/Mutex.h" #include "base/IEventQueueBuffer.h" #include "common/stdvector.h" +#include "mt/Mutex.h" #if X_DISPLAY_MISSING -# error X11 is required to build synergy +#error X11 is required to build synergy #else -# include +#include #endif class IEventQueue; @@ -33,39 +33,39 @@ class IEventQueue; //! Event queue buffer for X11 class XWindowsEventQueueBuffer : public IEventQueueBuffer { public: - XWindowsEventQueueBuffer(Display*, Window, IEventQueue* events); - XWindowsEventQueueBuffer(XWindowsEventQueueBuffer const &) =delete; - XWindowsEventQueueBuffer(XWindowsEventQueueBuffer &&) =delete; - virtual ~XWindowsEventQueueBuffer(); + XWindowsEventQueueBuffer(Display *, Window, IEventQueue *events); + XWindowsEventQueueBuffer(XWindowsEventQueueBuffer const &) = delete; + XWindowsEventQueueBuffer(XWindowsEventQueueBuffer &&) = delete; + virtual ~XWindowsEventQueueBuffer(); - XWindowsEventQueueBuffer& operator=(XWindowsEventQueueBuffer const &) =delete; - XWindowsEventQueueBuffer& operator=(XWindowsEventQueueBuffer &&) =delete; + XWindowsEventQueueBuffer & + operator=(XWindowsEventQueueBuffer const &) = delete; + XWindowsEventQueueBuffer &operator=(XWindowsEventQueueBuffer &&) = delete; - // IEventQueueBuffer overrides - virtual void init() { } - virtual void waitForEvent(double timeout); - virtual Type getEvent(Event& event, UInt32& dataID); - virtual bool addEvent(UInt32 dataID); - virtual bool isEmpty() const; - virtual EventQueueTimer* - newTimer(double duration, bool oneShot) const; - virtual void deleteTimer(EventQueueTimer*) const; + // IEventQueueBuffer overrides + virtual void init() {} + virtual void waitForEvent(double timeout); + virtual Type getEvent(Event &event, UInt32 &dataID); + virtual bool addEvent(UInt32 dataID); + virtual bool isEmpty() const; + virtual EventQueueTimer *newTimer(double duration, bool oneShot) const; + virtual void deleteTimer(EventQueueTimer *) const; private: - void flush(); + void flush(); - int getPendingCountLocked(); + int getPendingCountLocked(); private: - typedef std::vector EventList; + typedef std::vector EventList; - Mutex m_mutex; - Display* m_display; - Window m_window; - Atom m_userEvent; - XEvent m_event; - EventList m_postedEvents; - bool m_waiting; - int m_pipefd[2]; - IEventQueue* m_events; + Mutex m_mutex; + Display *m_display; + Window m_window; + Atom m_userEvent; + XEvent m_event; + EventList m_postedEvents; + bool m_waiting; + int m_pipefd[2]; + IEventQueue *m_events; }; diff --git a/src/lib/platform/XWindowsKeyState.cpp b/src/lib/platform/XWindowsKeyState.cpp index 73568dfd8..f254720a7 100644 --- a/src/lib/platform/XWindowsKeyState.cpp +++ b/src/lib/platform/XWindowsKeyState.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2003 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 LICENSE 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 @@ -22,913 +22,852 @@ #include "platform/XWindowsKeyState.h" -#include "platform/XWindowsUtil.h" #include "base/Log.h" #include "base/String.h" #include "common/stdmap.h" +#include "platform/XWindowsUtil.h" #include "synergy/AppUtil.h" #include "synergy/ClientApp.h" #include "synergy/ClientArgs.h" -#include #include +#include #if X_DISPLAY_MISSING -# error X11 is required to build synergy +#error X11 is required to build synergy #else -# include -# include -# define XK_MISCELLANY -# define XK_XKB_KEYS -# include +#include +#include +#define XK_MISCELLANY +#define XK_XKB_KEYS +#include #if HAVE_XKB_EXTENSION -# include +#include #endif #endif static const size_t ModifiersFromXDefaultSize = 32; -XWindowsKeyState::XWindowsKeyState( - Display* display, bool useXKB, - IEventQueue* events) : - KeyState(events, AppUtil::instance().getKeyboardLayoutList(), ClientApp::instance().args().m_enableLangSync), - m_display(display), - m_modifierFromX(ModifiersFromXDefaultSize) -{ - init(display, useXKB); +XWindowsKeyState::XWindowsKeyState(Display *display, bool useXKB, + IEventQueue *events) + : KeyState(events, AppUtil::instance().getKeyboardLayoutList(), + ClientApp::instance().args().m_enableLangSync), + m_display(display), m_modifierFromX(ModifiersFromXDefaultSize) { + init(display, useXKB); } -XWindowsKeyState::XWindowsKeyState( - Display* display, bool useXKB, - IEventQueue* events, synergy::KeyMap& keyMap) : - KeyState(events, keyMap, AppUtil::instance().getKeyboardLayoutList(), ClientApp::instance().args().m_enableLangSync), - m_display(display), - m_modifierFromX(ModifiersFromXDefaultSize) -{ - init(display, useXKB); +XWindowsKeyState::XWindowsKeyState(Display *display, bool useXKB, + IEventQueue *events, synergy::KeyMap &keyMap) + : KeyState(events, keyMap, AppUtil::instance().getKeyboardLayoutList(), + ClientApp::instance().args().m_enableLangSync), + m_display(display), m_modifierFromX(ModifiersFromXDefaultSize) { + init(display, useXKB); } -XWindowsKeyState::~XWindowsKeyState() -{ +XWindowsKeyState::~XWindowsKeyState() { #if HAVE_XKB_EXTENSION - if (m_xkb != NULL) { - XkbFreeKeyboard(m_xkb, 0, True); - } + if (m_xkb != NULL) { + XkbFreeKeyboard(m_xkb, 0, True); + } #endif } -void -XWindowsKeyState::init(Display* display, bool useXKB) -{ - XGetKeyboardControl(m_display, &m_keyboardState); +void XWindowsKeyState::init(Display *display, bool useXKB) { + XGetKeyboardControl(m_display, &m_keyboardState); #if HAVE_XKB_EXTENSION - if (useXKB) { - m_xkb = XkbGetMap(m_display, XkbKeyActionsMask | XkbKeyBehaviorsMask | - XkbAllClientInfoMask, XkbUseCoreKbd); - } - else { - m_xkb = NULL; - } + if (useXKB) { + m_xkb = XkbGetMap(m_display, + XkbKeyActionsMask | XkbKeyBehaviorsMask | + XkbAllClientInfoMask, + XkbUseCoreKbd); + } else { + m_xkb = NULL; + } #endif - setActiveGroup(kGroupPoll); + setActiveGroup(kGroupPoll); } -void -XWindowsKeyState::setActiveGroup(SInt32 group) -{ - if (group == kGroupPollAndSet) { - // we need to set the group to -1 in order for pollActiveGroup() to - // actually poll for the group - m_group = -1; - m_group = pollActiveGroup(); - } - else if (group == kGroupPoll) { - m_group = -1; - } - else { - assert(group >= 0); - m_group = group; - } +void XWindowsKeyState::setActiveGroup(SInt32 group) { + if (group == kGroupPollAndSet) { + // we need to set the group to -1 in order for pollActiveGroup() to + // actually poll for the group + m_group = -1; + m_group = pollActiveGroup(); + } else if (group == kGroupPoll) { + m_group = -1; + } else { + assert(group >= 0); + m_group = group; + } } -void -XWindowsKeyState::setAutoRepeat(const XKeyboardState& state) -{ - m_keyboardState = state; +void XWindowsKeyState::setAutoRepeat(const XKeyboardState &state) { + m_keyboardState = state; } -KeyModifierMask -XWindowsKeyState::mapModifiersFromX(unsigned int state) const -{ - LOG((CLOG_DEBUG2 "mapping state: %i", state)); - UInt32 offset = 8 * getGroupFromState(state); - KeyModifierMask mask = 0; - for (int i = 0; i < 8; ++i) { - if ((state & (1u << i)) != 0) { - LOG((CLOG_DEBUG2 "|= modifier: %i", offset + i)); - if (offset + i >= m_modifierFromX.size()) { - LOG((CLOG_ERR "m_modifierFromX is too small (%d) for the " - "requested offset (%d)", m_modifierFromX.size(), offset+i)); - } else { - mask |= m_modifierFromX[offset + i]; - } - } +KeyModifierMask XWindowsKeyState::mapModifiersFromX(unsigned int state) const { + LOG((CLOG_DEBUG2 "mapping state: %i", state)); + UInt32 offset = 8 * getGroupFromState(state); + KeyModifierMask mask = 0; + for (int i = 0; i < 8; ++i) { + if ((state & (1u << i)) != 0) { + LOG((CLOG_DEBUG2 "|= modifier: %i", offset + i)); + if (offset + i >= m_modifierFromX.size()) { + LOG((CLOG_ERR "m_modifierFromX is too small (%d) for the " + "requested offset (%d)", + m_modifierFromX.size(), offset + i)); + } else { + mask |= m_modifierFromX[offset + i]; + } } - return mask; + } + return mask; } -bool -XWindowsKeyState::mapModifiersToX(KeyModifierMask mask, - unsigned int& modifiers) const -{ - modifiers = 0; +bool XWindowsKeyState::mapModifiersToX(KeyModifierMask mask, + unsigned int &modifiers) const { + modifiers = 0; - for (SInt32 i = 0; i < kKeyModifierNumBits; ++i) { - KeyModifierMask bit = (1u << i); - if ((mask & bit) != 0) { - KeyModifierToXMask::const_iterator j = m_modifierToX.find(bit); - if (j == m_modifierToX.end()) { - return false; - } - else { - modifiers |= j->second; - } - } + for (SInt32 i = 0; i < kKeyModifierNumBits; ++i) { + KeyModifierMask bit = (1u << i); + if ((mask & bit) != 0) { + KeyModifierToXMask::const_iterator j = m_modifierToX.find(bit); + if (j == m_modifierToX.end()) { + return false; + } else { + modifiers |= j->second; + } + } + } + + return true; +} + +void XWindowsKeyState::mapKeyToKeycodes(KeyID key, + KeycodeList &keycodes) const { + keycodes.clear(); + std::pair + range = m_keyCodeFromKey.equal_range(key); + for (KeyToKeyCodeMap::const_iterator i = range.first; i != range.second; + ++i) { + keycodes.push_back(i->second); + } +} + +bool XWindowsKeyState::fakeCtrlAltDel() { + // pass keys through unchanged + return false; +} + +KeyModifierMask XWindowsKeyState::pollActiveModifiers() const { + Window root = DefaultRootWindow(m_display), window; + int xRoot, yRoot, xWindow, yWindow; + unsigned int state = 0; + if (XQueryPointer(m_display, root, &root, &window, &xRoot, &yRoot, &xWindow, + &yWindow, &state) == False) { + state = 0; + } + return mapModifiersFromX(state); +} + +SInt32 XWindowsKeyState::pollActiveGroup() const { + // fixed condition where any group < -1 would have undetermined behaviour + if (m_group >= 0) { + return m_group; + } + +#if HAVE_XKB_EXTENSION + if (m_xkb != NULL) { + XkbStateRec state; + XSync(m_display, False); + if (XkbGetState(m_display, XkbUseCoreKbd, &state) == Success) { + return state.group; } - return true; + LOG((CLOG_WARN "failed to poll active group")); + } +#endif + return 0; } -void -XWindowsKeyState::mapKeyToKeycodes(KeyID key, KeycodeList& keycodes) const -{ - keycodes.clear(); - std::pair range = - m_keyCodeFromKey.equal_range(key); - for (KeyToKeyCodeMap::const_iterator i = range.first; - i != range.second; ++i) { - keycodes.push_back(i->second); +void XWindowsKeyState::pollPressedKeys(KeyButtonSet &pressedKeys) const { + char keys[32]; + XQueryKeymap(m_display, keys); + for (UInt32 i = 0; i < 32; ++i) { + for (UInt32 j = 0; j < 8; ++j) { + if ((keys[i] & (1u << j)) != 0) { + pressedKeys.insert(8 * i + j); + } } + } } -bool -XWindowsKeyState::fakeCtrlAltDel() -{ - // pass keys through unchanged +void XWindowsKeyState::getKeyMap(synergy::KeyMap &keyMap) { + // get autorepeat info. we must use the global_auto_repeat told to + // us because it may have modified by synergy. + int oldGlobalAutoRepeat = m_keyboardState.global_auto_repeat; + XGetKeyboardControl(m_display, &m_keyboardState); + m_keyboardState.global_auto_repeat = oldGlobalAutoRepeat; + +#if HAVE_XKB_EXTENSION + if (m_xkb != NULL) { + if (XkbGetUpdatedMap(m_display, + XkbKeyActionsMask | XkbKeyBehaviorsMask | + XkbAllClientInfoMask, + m_xkb) == Success) { + updateKeysymMapXKB(keyMap); + return; + } + } +#endif + updateKeysymMap(keyMap); +} + +bool XWindowsKeyState::setCurrentLanguageWithDBus(SInt32 group) const { + QString service = "org.gnome.Shell"; + QString path = "/org/gnome/Shell"; + QString method = "Eval"; + QString param = + "imports.ui.status.keyboard.getInputSourceManager().inputSources[" + + QString::number(group) + "].activate()"; + + auto bus = QDBusConnection::sessionBus(); + if (!bus.isConnected()) { return false; -} + } -KeyModifierMask -XWindowsKeyState::pollActiveModifiers() const -{ - Window root = DefaultRootWindow(m_display), window; - int xRoot, yRoot, xWindow, yWindow; - unsigned int state = 0; - if (XQueryPointer(m_display, root, &root, &window, - &xRoot, &yRoot, &xWindow, &yWindow, &state) == False) { - state = 0; - } - return mapModifiersFromX(state); -} + QDBusInterface screenSaverInterface(service, path, service, bus); + if (!screenSaverInterface.isValid()) { + LOG((CLOG_WARN "keyboard layout fail. dbus interface is invalid")); + return false; + } -SInt32 -XWindowsKeyState::pollActiveGroup() const -{ - // fixed condition where any group < -1 would have undetermined behaviour - if (m_group >= 0) { - return m_group; - } - -#if HAVE_XKB_EXTENSION - if (m_xkb != NULL) { - XkbStateRec state; - XSync(m_display, False); - if (XkbGetState(m_display, XkbUseCoreKbd, &state) == Success) { - return state.group; - } - - LOG((CLOG_WARN "failed to poll active group")); - } -#endif - return 0; -} - -void -XWindowsKeyState::pollPressedKeys(KeyButtonSet& pressedKeys) const -{ - char keys[32]; - XQueryKeymap(m_display, keys); - for (UInt32 i = 0; i < 32; ++i) { - for (UInt32 j = 0; j < 8; ++j) { - if ((keys[i] & (1u << j)) != 0) { - pressedKeys.insert(8 * i + j); - } - } - } -} - -void -XWindowsKeyState::getKeyMap(synergy::KeyMap& keyMap) -{ - // get autorepeat info. we must use the global_auto_repeat told to - // us because it may have modified by synergy. - int oldGlobalAutoRepeat = m_keyboardState.global_auto_repeat; - XGetKeyboardControl(m_display, &m_keyboardState); - m_keyboardState.global_auto_repeat = oldGlobalAutoRepeat; - -#if HAVE_XKB_EXTENSION - if (m_xkb != NULL) { - if (XkbGetUpdatedMap(m_display, XkbKeyActionsMask | - XkbKeyBehaviorsMask | XkbAllClientInfoMask, m_xkb) == Success) { - updateKeysymMapXKB(keyMap); - return; - } - } -#endif - updateKeysymMap(keyMap); -} - -bool XWindowsKeyState::setCurrentLanguageWithDBus(SInt32 group) const -{ - QString service = "org.gnome.Shell"; - QString path = "/org/gnome/Shell"; - QString method = "Eval"; - QString param = "imports.ui.status.keyboard.getInputSourceManager().inputSources[" + - QString::number(group) + "].activate()"; - - auto bus = QDBusConnection::sessionBus(); - if (!bus.isConnected()) { - return false; - } - - QDBusInterface screenSaverInterface(service, path, service, bus); - if (!screenSaverInterface.isValid()) { - LOG((CLOG_WARN "keyboard layout fail. dbus interface is invalid")); - return false; - } - - QDBusPendingReply reply = screenSaverInterface.call(method, param); - reply.waitForFinished(); - - if(!reply.isValid()) { - auto qerror = reply.error(); - LOG((CLOG_WARN "keyboard layout fail %s : %s", - qerror.name().toStdString().c_str(), - qerror.message().toStdString().c_str())); - return true; - } - - if(reply.isError()) { - LOG((CLOG_WARN "keyboard layout fail. reply contains error")); - return true; - } - - if(!reply.argumentAt<0>() || reply.argumentAt<1>() != QString("")) { - LOG((CLOG_WARN "keyboard layout fail. Reply is unexpected!")); - return true; - } + QDBusPendingReply reply = + screenSaverInterface.call(method, param); + reply.waitForFinished(); + if (!reply.isValid()) { + auto qerror = reply.error(); + LOG((CLOG_WARN "keyboard layout fail %s : %s", + qerror.name().toStdString().c_str(), + qerror.message().toStdString().c_str())); return true; + } + + if (reply.isError()) { + LOG((CLOG_WARN "keyboard layout fail. reply contains error")); + return true; + } + + if (!reply.argumentAt<0>() || reply.argumentAt<1>() != QString("")) { + LOG((CLOG_WARN "keyboard layout fail. Reply is unexpected!")); + return true; + } + + return true; } -void -XWindowsKeyState::fakeKey(const Keystroke& keystroke) -{ - switch (keystroke.m_type) { - case Keystroke::kButton: - if (keystroke.m_data.m_button.m_repeat) { - int c = keystroke.m_data.m_button.m_button; - int i = (c >> 3); - int b = 1 << (c & 7); - if (m_keyboardState.global_auto_repeat == AutoRepeatModeOff || - (c!=113 && c!=116 && (m_keyboardState.auto_repeats[i] & b) == 0)) { - LOG((CLOG_DEBUG1 " discard autorepeat")); - break; - } - } - XTestFakeKeyEvent(m_display, keystroke.m_data.m_button.m_button, - keystroke.m_data.m_button.m_press ? True : False, - CurrentTime); - break; - - case Keystroke::kGroup: - if (keystroke.m_data.m_group.m_restore) { - break; - } - - if (keystroke.m_data.m_group.m_absolute) { - -#ifndef __APPLE__ - if(setCurrentLanguageWithDBus(keystroke.m_data.m_group.m_group)) { - break; - } -#endif -#if HAVE_XKB_EXTENSION - if (m_xkb != NULL) { - if (XkbLockGroup(m_display, XkbUseCoreKbd, - keystroke.m_data.m_group.m_group) == False) { - LOG((CLOG_DEBUG1 "xkb lock group request not sent")); - } - } - else -#endif - { - LOG((CLOG_DEBUG1 " ignored")); - } - } - else { - -#ifndef __APPLE__ - if(setCurrentLanguageWithDBus(keystroke.m_data.m_group.m_group)) { - break; - } -#endif -#if HAVE_XKB_EXTENSION - if (m_xkb != NULL) { - if (XkbLockGroup(m_display, XkbUseCoreKbd, - getEffectiveGroup(pollActiveGroup(), - keystroke.m_data.m_group.m_group)) == False) { - LOG((CLOG_DEBUG1 "xkb lock group request not sent")); - } - } - else -#endif - { - LOG((CLOG_DEBUG1 " ignored")); - } - } - +void XWindowsKeyState::fakeKey(const Keystroke &keystroke) { + switch (keystroke.m_type) { + case Keystroke::kButton: + if (keystroke.m_data.m_button.m_repeat) { + int c = keystroke.m_data.m_button.m_button; + int i = (c >> 3); + int b = 1 << (c & 7); + if (m_keyboardState.global_auto_repeat == AutoRepeatModeOff || + (c != 113 && c != 116 && + (m_keyboardState.auto_repeats[i] & b) == 0)) { + LOG((CLOG_DEBUG1 " discard autorepeat")); break; + } } - XFlush(m_display); + XTestFakeKeyEvent(m_display, keystroke.m_data.m_button.m_button, + keystroke.m_data.m_button.m_press ? True : False, + CurrentTime); + break; + + case Keystroke::kGroup: + if (keystroke.m_data.m_group.m_restore) { + break; + } + + if (keystroke.m_data.m_group.m_absolute) { + +#ifndef __APPLE__ + if (setCurrentLanguageWithDBus(keystroke.m_data.m_group.m_group)) { + break; + } +#endif +#if HAVE_XKB_EXTENSION + if (m_xkb != NULL) { + if (XkbLockGroup(m_display, XkbUseCoreKbd, + keystroke.m_data.m_group.m_group) == False) { + LOG((CLOG_DEBUG1 "xkb lock group request not sent")); + } + } else +#endif + { + LOG((CLOG_DEBUG1 " ignored")); + } + } else { + +#ifndef __APPLE__ + if (setCurrentLanguageWithDBus(keystroke.m_data.m_group.m_group)) { + break; + } +#endif +#if HAVE_XKB_EXTENSION + if (m_xkb != NULL) { + if (XkbLockGroup(m_display, XkbUseCoreKbd, + getEffectiveGroup(pollActiveGroup(), + keystroke.m_data.m_group.m_group)) == + False) { + LOG((CLOG_DEBUG1 "xkb lock group request not sent")); + } + } else +#endif + { + LOG((CLOG_DEBUG1 " ignored")); + } + } + + break; + } + XFlush(m_display); } -void -XWindowsKeyState::updateKeysymMap(synergy::KeyMap& keyMap) -{ - // there are up to 4 keysyms per keycode - static const int maxKeysyms = 4; +void XWindowsKeyState::updateKeysymMap(synergy::KeyMap &keyMap) { + // there are up to 4 keysyms per keycode + static const int maxKeysyms = 4; - LOG((CLOG_DEBUG1 "non-XKB mapping")); + LOG((CLOG_DEBUG1 "non-XKB mapping")); - // prepare map from X modifier to KeyModifierMask. certain bits - // are predefined. - std::fill(m_modifierFromX.begin(), m_modifierFromX.end(), 0); - m_modifierFromX[ShiftMapIndex] = KeyModifierShift; - m_modifierFromX[LockMapIndex] = KeyModifierCapsLock; - m_modifierFromX[ControlMapIndex] = KeyModifierControl; - m_modifierToX.clear(); - m_modifierToX[KeyModifierShift] = ShiftMask; - m_modifierToX[KeyModifierCapsLock] = LockMask; - m_modifierToX[KeyModifierControl] = ControlMask; + // prepare map from X modifier to KeyModifierMask. certain bits + // are predefined. + std::fill(m_modifierFromX.begin(), m_modifierFromX.end(), 0); + m_modifierFromX[ShiftMapIndex] = KeyModifierShift; + m_modifierFromX[LockMapIndex] = KeyModifierCapsLock; + m_modifierFromX[ControlMapIndex] = KeyModifierControl; + m_modifierToX.clear(); + m_modifierToX[KeyModifierShift] = ShiftMask; + m_modifierToX[KeyModifierCapsLock] = LockMask; + m_modifierToX[KeyModifierControl] = ControlMask; - // prepare map from KeyID to KeyCode - m_keyCodeFromKey.clear(); + // prepare map from KeyID to KeyCode + m_keyCodeFromKey.clear(); - // get the number of keycodes - int minKeycode, maxKeycode; - XDisplayKeycodes(m_display, &minKeycode, &maxKeycode); - int numKeycodes = maxKeycode - minKeycode + 1; + // get the number of keycodes + int minKeycode, maxKeycode; + XDisplayKeycodes(m_display, &minKeycode, &maxKeycode); + int numKeycodes = maxKeycode - minKeycode + 1; - // get the keyboard mapping for all keys - int keysymsPerKeycode; - KeySym* allKeysyms = XGetKeyboardMapping(m_display, - minKeycode, numKeycodes, - &keysymsPerKeycode); + // get the keyboard mapping for all keys + int keysymsPerKeycode; + KeySym *allKeysyms = XGetKeyboardMapping(m_display, minKeycode, numKeycodes, + &keysymsPerKeycode); - // it's more convenient to always have maxKeysyms KeySyms per key - { - KeySym* tmpKeysyms = new KeySym[maxKeysyms * numKeycodes]; - for (int i = 0; i < numKeycodes; ++i) { - for (int j = 0; j < maxKeysyms; ++j) { - if (j < keysymsPerKeycode) { - tmpKeysyms[maxKeysyms * i + j] = - allKeysyms[keysymsPerKeycode * i + j]; - } - else { - tmpKeysyms[maxKeysyms * i + j] = NoSymbol; - } - } - } - XFree(allKeysyms); - allKeysyms = tmpKeysyms; - } - - // get the buttons assigned to modifiers. X11 does not predefine - // the meaning of any modifiers except shift, caps lock, and the - // control key. the meaning of a modifier bit (other than those) - // depends entirely on the KeySyms mapped to that bit. unfortunately - // you cannot map a bit back to the KeySym used to produce it. - // for example, let's say button 1 maps to Alt_L without shift and - // Meta_L with shift. now if mod1 is mapped to button 1 that could - // mean the user used Alt or Meta to turn on that modifier and there's - // no way to know which. it's also possible for one button to be - // mapped to multiple bits so both mod1 and mod2 could be generated - // by button 1. - // - // we're going to ignore any modifier for a button except the first. - // with the above example, that means we'll ignore the mod2 modifier - // bit unless it's also mapped to some other button. we're also - // going to ignore all KeySyms except the first modifier KeySym, - // which means button 1 above won't map to Meta, just Alt. - std::map modifierButtons; - XModifierKeymap* modifiers = XGetModifierMapping(m_display); - for (unsigned int i = 0; i < 8; ++i) { - const KeyCode* buttons = - modifiers->modifiermap + i * modifiers->max_keypermod; - for (int j = 0; j < modifiers->max_keypermod; ++j) { - modifierButtons.insert(std::make_pair(buttons[j], i)); - } - } - XFreeModifiermap(modifiers); - modifierButtons.erase(0); - - // Hack to deal with VMware. When a VMware client grabs input the - // player clears out the X modifier map for whatever reason. We're - // notified of the change and arrive here to discover that there - // are no modifiers at all. Since this prevents the modifiers from - // working in the VMware client we'll use the last known good set - // of modifiers when there are no modifiers. If there are modifiers - // we update the last known good set. - if (!modifierButtons.empty()) { - m_lastGoodNonXKBModifiers = modifierButtons; - } - else { - modifierButtons = m_lastGoodNonXKBModifiers; - } - - // add entries for each keycode - synergy::KeyMap::KeyItem item; + // it's more convenient to always have maxKeysyms KeySyms per key + { + KeySym *tmpKeysyms = new KeySym[maxKeysyms * numKeycodes]; for (int i = 0; i < numKeycodes; ++i) { - KeySym* keysyms = allKeysyms + maxKeysyms * i; - KeyCode keycode = static_cast(i + minKeycode); - item.m_button = static_cast(keycode); - item.m_client = 0; - - // determine modifier sensitivity - item.m_sensitive = 0; - - // if the keysyms in levels 2 or 3 exist and differ from levels - // 0 and 1 then the key is sensitive AltGr (Mode_switch) - if ((keysyms[2] != NoSymbol && keysyms[2] != keysyms[0]) || - (keysyms[3] != NoSymbol && keysyms[2] != keysyms[1])) { - item.m_sensitive |= KeyModifierAltGr; + for (int j = 0; j < maxKeysyms; ++j) { + if (j < keysymsPerKeycode) { + tmpKeysyms[maxKeysyms * i + j] = + allKeysyms[keysymsPerKeycode * i + j]; + } else { + tmpKeysyms[maxKeysyms * i + j] = NoSymbol; } + } + } + XFree(allKeysyms); + allKeysyms = tmpKeysyms; + } - // check if the key is caps-lock sensitive. some systems only - // provide one keysym for keys sensitive to caps-lock. if we - // find that then fill in the missing keysym. - if (keysyms[0] != NoSymbol && keysyms[1] == NoSymbol && - keysyms[2] == NoSymbol && keysyms[3] == NoSymbol) { - KeySym lKeysym, uKeysym; - XConvertCase(keysyms[0], &lKeysym, &uKeysym); - if (lKeysym != uKeysym) { - keysyms[0] = lKeysym; - keysyms[1] = uKeysym; - item.m_sensitive |= KeyModifierCapsLock; - } - } - else if (keysyms[0] != NoSymbol && keysyms[1] != NoSymbol) { - KeySym lKeysym, uKeysym; - XConvertCase(keysyms[0], &lKeysym, &uKeysym); - if (lKeysym != uKeysym && - lKeysym == keysyms[0] && - uKeysym == keysyms[1]) { - item.m_sensitive |= KeyModifierCapsLock; - } - else if (keysyms[2] != NoSymbol && keysyms[3] != NoSymbol) { - XConvertCase(keysyms[2], &lKeysym, &uKeysym); - if (lKeysym != uKeysym && - lKeysym == keysyms[2] && - uKeysym == keysyms[3]) { - item.m_sensitive |= KeyModifierCapsLock; - } - } - } + // get the buttons assigned to modifiers. X11 does not predefine + // the meaning of any modifiers except shift, caps lock, and the + // control key. the meaning of a modifier bit (other than those) + // depends entirely on the KeySyms mapped to that bit. unfortunately + // you cannot map a bit back to the KeySym used to produce it. + // for example, let's say button 1 maps to Alt_L without shift and + // Meta_L with shift. now if mod1 is mapped to button 1 that could + // mean the user used Alt or Meta to turn on that modifier and there's + // no way to know which. it's also possible for one button to be + // mapped to multiple bits so both mod1 and mod2 could be generated + // by button 1. + // + // we're going to ignore any modifier for a button except the first. + // with the above example, that means we'll ignore the mod2 modifier + // bit unless it's also mapped to some other button. we're also + // going to ignore all KeySyms except the first modifier KeySym, + // which means button 1 above won't map to Meta, just Alt. + std::map modifierButtons; + XModifierKeymap *modifiers = XGetModifierMapping(m_display); + for (unsigned int i = 0; i < 8; ++i) { + const KeyCode *buttons = + modifiers->modifiermap + i * modifiers->max_keypermod; + for (int j = 0; j < modifiers->max_keypermod; ++j) { + modifierButtons.insert(std::make_pair(buttons[j], i)); + } + } + XFreeModifiermap(modifiers); + modifierButtons.erase(0); - // key is sensitive to shift if keysyms in levels 0 and 1 or - // levels 2 and 3 don't match. it's also sensitive to shift - // if it's sensitive to caps-lock. - if ((item.m_sensitive & KeyModifierCapsLock) != 0) { - item.m_sensitive |= KeyModifierShift; + // Hack to deal with VMware. When a VMware client grabs input the + // player clears out the X modifier map for whatever reason. We're + // notified of the change and arrive here to discover that there + // are no modifiers at all. Since this prevents the modifiers from + // working in the VMware client we'll use the last known good set + // of modifiers when there are no modifiers. If there are modifiers + // we update the last known good set. + if (!modifierButtons.empty()) { + m_lastGoodNonXKBModifiers = modifierButtons; + } else { + modifierButtons = m_lastGoodNonXKBModifiers; + } + + // add entries for each keycode + synergy::KeyMap::KeyItem item; + for (int i = 0; i < numKeycodes; ++i) { + KeySym *keysyms = allKeysyms + maxKeysyms * i; + KeyCode keycode = static_cast(i + minKeycode); + item.m_button = static_cast(keycode); + item.m_client = 0; + + // determine modifier sensitivity + item.m_sensitive = 0; + + // if the keysyms in levels 2 or 3 exist and differ from levels + // 0 and 1 then the key is sensitive AltGr (Mode_switch) + if ((keysyms[2] != NoSymbol && keysyms[2] != keysyms[0]) || + (keysyms[3] != NoSymbol && keysyms[2] != keysyms[1])) { + item.m_sensitive |= KeyModifierAltGr; + } + + // check if the key is caps-lock sensitive. some systems only + // provide one keysym for keys sensitive to caps-lock. if we + // find that then fill in the missing keysym. + if (keysyms[0] != NoSymbol && keysyms[1] == NoSymbol && + keysyms[2] == NoSymbol && keysyms[3] == NoSymbol) { + KeySym lKeysym, uKeysym; + XConvertCase(keysyms[0], &lKeysym, &uKeysym); + if (lKeysym != uKeysym) { + keysyms[0] = lKeysym; + keysyms[1] = uKeysym; + item.m_sensitive |= KeyModifierCapsLock; + } + } else if (keysyms[0] != NoSymbol && keysyms[1] != NoSymbol) { + KeySym lKeysym, uKeysym; + XConvertCase(keysyms[0], &lKeysym, &uKeysym); + if (lKeysym != uKeysym && lKeysym == keysyms[0] && + uKeysym == keysyms[1]) { + item.m_sensitive |= KeyModifierCapsLock; + } else if (keysyms[2] != NoSymbol && keysyms[3] != NoSymbol) { + XConvertCase(keysyms[2], &lKeysym, &uKeysym); + if (lKeysym != uKeysym && lKeysym == keysyms[2] && + uKeysym == keysyms[3]) { + item.m_sensitive |= KeyModifierCapsLock; } - else if ((keysyms[0] != NoSymbol && keysyms[1] != NoSymbol && + } + } + + // key is sensitive to shift if keysyms in levels 0 and 1 or + // levels 2 and 3 don't match. it's also sensitive to shift + // if it's sensitive to caps-lock. + if ((item.m_sensitive & KeyModifierCapsLock) != 0) { + item.m_sensitive |= KeyModifierShift; + } else if ((keysyms[0] != NoSymbol && keysyms[1] != NoSymbol && keysyms[0] != keysyms[1]) || - (keysyms[2] != NoSymbol && keysyms[3] != NoSymbol && + (keysyms[2] != NoSymbol && keysyms[3] != NoSymbol && keysyms[2] != keysyms[3])) { - item.m_sensitive |= KeyModifierShift; - } - - // key is sensitive to numlock if any keysym on it is - if (IsKeypadKey(keysyms[0]) || IsPrivateKeypadKey(keysyms[0]) || - IsKeypadKey(keysyms[1]) || IsPrivateKeypadKey(keysyms[1]) || - IsKeypadKey(keysyms[2]) || IsPrivateKeypadKey(keysyms[2]) || - IsKeypadKey(keysyms[3]) || IsPrivateKeypadKey(keysyms[3])) { - item.m_sensitive |= KeyModifierNumLock; - } - - // do each keysym (shift level) - for (int j = 0; j < maxKeysyms; ++j) { - item.m_id = XWindowsUtil::mapKeySymToKeyID(keysyms[j]); - if (item.m_id == kKeyNone) { - if (j != 0 && modifierButtons.count(keycode) > 0) { - // pretend the modifier works in other shift levels - // because it probably does. - if (keysyms[1] == NoSymbol || j != 3) { - item.m_id = XWindowsUtil::mapKeySymToKeyID(keysyms[0]); - } - else { - item.m_id = XWindowsUtil::mapKeySymToKeyID(keysyms[1]); - } - } - if (item.m_id == kKeyNone) { - continue; - } - } - - // group is 0 for levels 0 and 1 and 1 for levels 2 and 3 - item.m_group = (j >= 2) ? 1 : 0; - - // compute required modifiers - item.m_required = 0; - if ((j & 1) != 0) { - item.m_required |= KeyModifierShift; - } - if ((j & 2) != 0) { - item.m_required |= KeyModifierAltGr; - } - - item.m_generates = 0; - item.m_lock = false; - if (modifierButtons.count(keycode) > 0) { - // get flags for modifier keys - synergy::KeyMap::initModifierKey(item); - - // add mapping from X (unless we already have) - if (item.m_generates != 0) { - unsigned int bit = modifierButtons[keycode]; - if (m_modifierFromX[bit] == 0) { - m_modifierFromX[bit] = item.m_generates; - m_modifierToX[item.m_generates] = (1u << bit); - } - } - } - - // add key - keyMap.addKeyEntry(item); - m_keyCodeFromKey.insert(std::make_pair(item.m_id, keycode)); - - // add other ways to synthesize the key - if ((j & 1) != 0) { - // add capslock version of key is sensitive to capslock - KeySym lKeysym, uKeysym; - XConvertCase(keysyms[j], &lKeysym, &uKeysym); - if (lKeysym != uKeysym && - lKeysym == keysyms[j - 1] && - uKeysym == keysyms[j]) { - item.m_required &= ~KeyModifierShift; - item.m_required |= KeyModifierCapsLock; - keyMap.addKeyEntry(item); - item.m_required |= KeyModifierShift; - item.m_required &= ~KeyModifierCapsLock; - } - - // add numlock version of key if sensitive to numlock - if (IsKeypadKey(keysyms[j]) || IsPrivateKeypadKey(keysyms[j])) { - item.m_required &= ~KeyModifierShift; - item.m_required |= KeyModifierNumLock; - keyMap.addKeyEntry(item); - item.m_required |= KeyModifierShift; - item.m_required &= ~KeyModifierNumLock; - } - } - } + item.m_sensitive |= KeyModifierShift; } - delete[] allKeysyms; + // key is sensitive to numlock if any keysym on it is + if (IsKeypadKey(keysyms[0]) || IsPrivateKeypadKey(keysyms[0]) || + IsKeypadKey(keysyms[1]) || IsPrivateKeypadKey(keysyms[1]) || + IsKeypadKey(keysyms[2]) || IsPrivateKeypadKey(keysyms[2]) || + IsKeypadKey(keysyms[3]) || IsPrivateKeypadKey(keysyms[3])) { + item.m_sensitive |= KeyModifierNumLock; + } + + // do each keysym (shift level) + for (int j = 0; j < maxKeysyms; ++j) { + item.m_id = XWindowsUtil::mapKeySymToKeyID(keysyms[j]); + if (item.m_id == kKeyNone) { + if (j != 0 && modifierButtons.count(keycode) > 0) { + // pretend the modifier works in other shift levels + // because it probably does. + if (keysyms[1] == NoSymbol || j != 3) { + item.m_id = XWindowsUtil::mapKeySymToKeyID(keysyms[0]); + } else { + item.m_id = XWindowsUtil::mapKeySymToKeyID(keysyms[1]); + } + } + if (item.m_id == kKeyNone) { + continue; + } + } + + // group is 0 for levels 0 and 1 and 1 for levels 2 and 3 + item.m_group = (j >= 2) ? 1 : 0; + + // compute required modifiers + item.m_required = 0; + if ((j & 1) != 0) { + item.m_required |= KeyModifierShift; + } + if ((j & 2) != 0) { + item.m_required |= KeyModifierAltGr; + } + + item.m_generates = 0; + item.m_lock = false; + if (modifierButtons.count(keycode) > 0) { + // get flags for modifier keys + synergy::KeyMap::initModifierKey(item); + + // add mapping from X (unless we already have) + if (item.m_generates != 0) { + unsigned int bit = modifierButtons[keycode]; + if (m_modifierFromX[bit] == 0) { + m_modifierFromX[bit] = item.m_generates; + m_modifierToX[item.m_generates] = (1u << bit); + } + } + } + + // add key + keyMap.addKeyEntry(item); + m_keyCodeFromKey.insert(std::make_pair(item.m_id, keycode)); + + // add other ways to synthesize the key + if ((j & 1) != 0) { + // add capslock version of key is sensitive to capslock + KeySym lKeysym, uKeysym; + XConvertCase(keysyms[j], &lKeysym, &uKeysym); + if (lKeysym != uKeysym && lKeysym == keysyms[j - 1] && + uKeysym == keysyms[j]) { + item.m_required &= ~KeyModifierShift; + item.m_required |= KeyModifierCapsLock; + keyMap.addKeyEntry(item); + item.m_required |= KeyModifierShift; + item.m_required &= ~KeyModifierCapsLock; + } + + // add numlock version of key if sensitive to numlock + if (IsKeypadKey(keysyms[j]) || IsPrivateKeypadKey(keysyms[j])) { + item.m_required &= ~KeyModifierShift; + item.m_required |= KeyModifierNumLock; + keyMap.addKeyEntry(item); + item.m_required |= KeyModifierShift; + item.m_required &= ~KeyModifierNumLock; + } + } + } + } + + delete[] allKeysyms; } #if HAVE_XKB_EXTENSION -void -XWindowsKeyState::updateKeysymMapXKB(synergy::KeyMap& keyMap) -{ - static const XkbKTMapEntryRec defMapEntry = { - True, // active - 0, // level - { - 0, // mods.mask - 0, // mods.real_mods - 0 // mods.vmods - } - }; +void XWindowsKeyState::updateKeysymMapXKB(synergy::KeyMap &keyMap) { + static const XkbKTMapEntryRec defMapEntry = {True, // active + 0, // level + { + 0, // mods.mask + 0, // mods.real_mods + 0 // mods.vmods + }}; - LOG((CLOG_DEBUG1 "xkb mapping")); + LOG((CLOG_DEBUG1 "xkb mapping")); - // find the number of groups - int maxNumGroups = 0; - for (int i = m_xkb->min_key_code; i <= m_xkb->max_key_code; ++i) { - int numGroups = XkbKeyNumGroups(m_xkb, static_cast(i)); - if (numGroups > maxNumGroups) { - maxNumGroups = numGroups; - } + // find the number of groups + int maxNumGroups = 0; + for (int i = m_xkb->min_key_code; i <= m_xkb->max_key_code; ++i) { + int numGroups = XkbKeyNumGroups(m_xkb, static_cast(i)); + if (numGroups > maxNumGroups) { + maxNumGroups = numGroups; + } + } + + // prepare map from X modifier to KeyModifierMask + std::vector modifierLevel(maxNumGroups * 8, 4); + m_modifierFromX.clear(); + m_modifierFromX.resize(maxNumGroups * 8); + m_modifierToX.clear(); + + // prepare map from KeyID to KeyCode + m_keyCodeFromKey.clear(); + + // Hack to deal with VMware. When a VMware client grabs input the + // player clears out the X modifier map for whatever reason. We're + // notified of the change and arrive here to discover that there + // are no modifiers at all. Since this prevents the modifiers from + // working in the VMware client we'll use the last known good set + // of modifiers when there are no modifiers. If there are modifiers + // we update the last known good set. + bool useLastGoodModifiers = !hasModifiersXKB(); + if (!useLastGoodModifiers) { + m_lastGoodXKBModifiers.clear(); + } + + // check every button. on this pass we save all modifiers as native + // X modifier masks. + synergy::KeyMap::KeyItem item; + for (int i = m_xkb->min_key_code; i <= m_xkb->max_key_code; ++i) { + KeyCode keycode = static_cast(i); + item.m_button = static_cast(keycode); + item.m_client = 0; + + // skip keys with no groups (they generate no symbols) + if (XkbKeyNumGroups(m_xkb, keycode) == 0) { + continue; } - // prepare map from X modifier to KeyModifierMask - std::vector modifierLevel(maxNumGroups * 8, 4); - m_modifierFromX.clear(); - m_modifierFromX.resize(maxNumGroups * 8); - m_modifierToX.clear(); - - // prepare map from KeyID to KeyCode - m_keyCodeFromKey.clear(); - - // Hack to deal with VMware. When a VMware client grabs input the - // player clears out the X modifier map for whatever reason. We're - // notified of the change and arrive here to discover that there - // are no modifiers at all. Since this prevents the modifiers from - // working in the VMware client we'll use the last known good set - // of modifiers when there are no modifiers. If there are modifiers - // we update the last known good set. - bool useLastGoodModifiers = !hasModifiersXKB(); - if (!useLastGoodModifiers) { - m_lastGoodXKBModifiers.clear(); + // note half-duplex keys + const XkbBehavior &b = m_xkb->server->behaviors[keycode]; + if ((b.type & XkbKB_OpMask) == XkbKB_Lock) { + keyMap.addHalfDuplexButton(item.m_button); } - // check every button. on this pass we save all modifiers as native - // X modifier masks. - synergy::KeyMap::KeyItem item; - for (int i = m_xkb->min_key_code; i <= m_xkb->max_key_code; ++i) { - KeyCode keycode = static_cast(i); - item.m_button = static_cast(keycode); - item.m_client = 0; + // iterate over all groups + for (int group = 0; group < maxNumGroups; ++group) { + item.m_group = group; + int eGroup = getEffectiveGroup(keycode, group); - // skip keys with no groups (they generate no symbols) - if (XkbKeyNumGroups(m_xkb, keycode) == 0) { - continue; + // get key info + XkbKeyTypePtr type = XkbKeyKeyType(m_xkb, keycode, eGroup); + + // set modifiers the item is sensitive to + item.m_sensitive = type->mods.mask; + + // iterate over all shift levels for the button (including none) + for (int j = -1; j < type->map_count; ++j) { + const XkbKTMapEntryRec *mapEntry = + ((j == -1) ? &defMapEntry : type->map + j); + if (!mapEntry->active) { + continue; + } + int level = mapEntry->level; + + // set required modifiers for this item + item.m_required = mapEntry->mods.mask; + if ((item.m_required & LockMask) != 0 && j != -1 && + type->preserve != NULL && + (type->preserve[j].mask & LockMask) != 0) { + // sensitive caps lock and we preserve caps-lock. + // preserving caps-lock means we Xlib functions would + // yield the capitialized KeySym so we'll adjust the + // level accordingly. + if ((level ^ 1) < type->num_levels) { + level ^= 1; + } } - // note half-duplex keys - const XkbBehavior& b = m_xkb->server->behaviors[keycode]; - if ((b.type & XkbKB_OpMask) == XkbKB_Lock) { - keyMap.addHalfDuplexButton(item.m_button); - } + // get the keysym for this item + KeySym keysym = XkbKeySymEntry(m_xkb, keycode, level, eGroup); - // iterate over all groups - for (int group = 0; group < maxNumGroups; ++group) { - item.m_group = group; - int eGroup = getEffectiveGroup(keycode, group); - - // get key info - XkbKeyTypePtr type = XkbKeyKeyType(m_xkb, keycode, eGroup); - - // set modifiers the item is sensitive to - item.m_sensitive = type->mods.mask; - - // iterate over all shift levels for the button (including none) - for (int j = -1; j < type->map_count; ++j) { - const XkbKTMapEntryRec* mapEntry = - ((j == -1) ? &defMapEntry : type->map + j); - if (!mapEntry->active) { - continue; - } - int level = mapEntry->level; - - // set required modifiers for this item - item.m_required = mapEntry->mods.mask; - if ((item.m_required & LockMask) != 0 && - j != -1 && type->preserve != NULL && - (type->preserve[j].mask & LockMask) != 0) { - // sensitive caps lock and we preserve caps-lock. - // preserving caps-lock means we Xlib functions would - // yield the capitialized KeySym so we'll adjust the - // level accordingly. - if ((level ^ 1) < type->num_levels) { - level ^= 1; - } - } - - // get the keysym for this item - KeySym keysym = XkbKeySymEntry(m_xkb, keycode, level, eGroup); - - // check for group change actions, locking modifiers, and - // modifier masks. - item.m_lock = false; - bool isModifier = false; - UInt32 modifierMask = m_xkb->map->modmap[keycode]; - if (XkbKeyHasActions(m_xkb, keycode) == True) { - XkbAction* action = - XkbKeyActionEntry(m_xkb, keycode, level, eGroup); - if (action->type == XkbSA_SetMods || - action->type == XkbSA_LockMods) { - isModifier = true; - - // note toggles - item.m_lock = (action->type == XkbSA_LockMods); - - // maybe use action's mask - if ((action->mods.flags & XkbSA_UseModMapMods) == 0) { - modifierMask = action->mods.mask; - } - } - else if (action->type == XkbSA_SetGroup || - action->type == XkbSA_LatchGroup || - action->type == XkbSA_LockGroup) { - // ignore group change key - continue; - } - } - level = mapEntry->level; - - // VMware modifier hack - if (useLastGoodModifiers) { - XKBModifierMap::const_iterator k = - m_lastGoodXKBModifiers.find(eGroup * 256 + keycode); - if (k != m_lastGoodXKBModifiers.end()) { - // Use last known good modifier - isModifier = true; - level = k->second.m_level; - modifierMask = k->second.m_mask; - item.m_lock = k->second.m_lock; - } - } - else if (isModifier) { - // Save known good modifier - XKBModifierInfo& info = - m_lastGoodXKBModifiers[eGroup * 256 + keycode]; - info.m_level = level; - info.m_mask = modifierMask; - info.m_lock = item.m_lock; - } - - // record the modifier mask for this key. don't bother - // for keys that change the group. - item.m_generates = 0; - UInt32 modifierBit = - XWindowsUtil::getModifierBitForKeySym(keysym); - if (isModifier && modifierBit != kKeyModifierBitNone) { - item.m_generates = (1u << modifierBit); - for (SInt32 j = 0; j < 8; ++j) { - // skip modifiers this key doesn't generate - if ((modifierMask & (1u << j)) == 0) { - continue; - } - - // skip keys that map to a modifier that we've - // already seen using fewer modifiers. that is - // if this key must combine with other modifiers - // and we know of a key that combines with fewer - // modifiers (or no modifiers) then prefer the - // other key. - if (level >= modifierLevel[8 * group + j]) { - continue; - } - modifierLevel[8 * group + j] = level; - - // save modifier - m_modifierFromX[8 * group + j] |= (1u << modifierBit); - m_modifierToX.insert(std::make_pair( - 1u << modifierBit, 1u << j)); - } - } - - // handle special cases of just one keysym for the keycode - if (type->num_levels == 1) { - // if there are upper- and lowercase versions of the - // keysym then add both. - KeySym lKeysym, uKeysym; - XConvertCase(keysym, &lKeysym, &uKeysym); - if (lKeysym != uKeysym) { - if (j != -1) { - continue; - } - - item.m_sensitive |= ShiftMask | LockMask; - - KeyID lKeyID = XWindowsUtil::mapKeySymToKeyID(lKeysym); - KeyID uKeyID = XWindowsUtil::mapKeySymToKeyID(uKeysym); - if (lKeyID == kKeyNone || uKeyID == kKeyNone) { - continue; - } - - item.m_id = lKeyID; - item.m_required = 0; - keyMap.addKeyEntry(item); - - item.m_id = uKeyID; - item.m_required = ShiftMask; - keyMap.addKeyEntry(item); - item.m_required = LockMask; - keyMap.addKeyEntry(item); - - if (group == 0) { - m_keyCodeFromKey.insert( - std::make_pair(lKeyID, keycode)); - m_keyCodeFromKey.insert( - std::make_pair(uKeyID, keycode)); - } - continue; - } - } - - // add entry - item.m_id = XWindowsUtil::mapKeySymToKeyID(keysym); - keyMap.addKeyEntry(item); - if (group == 0) { - m_keyCodeFromKey.insert(std::make_pair(item.m_id, keycode)); - } - } - } - } - - // change all modifier masks to synergy masks from X masks - keyMap.foreachKey(&XWindowsKeyState::remapKeyModifiers, this); - - // allow composition across groups - keyMap.allowGroupSwitchDuringCompose(); -} -#endif - -void -XWindowsKeyState::remapKeyModifiers(KeyID id, SInt32 group, - synergy::KeyMap::KeyItem& item, void* vself) -{ - XWindowsKeyState* self = static_cast(vself); - item.m_required = - self->mapModifiersFromX(XkbBuildCoreState(item.m_required, group)); - item.m_sensitive = - self->mapModifiersFromX(XkbBuildCoreState(item.m_sensitive, group)); -} - -bool -XWindowsKeyState::hasModifiersXKB() const -{ -#if HAVE_XKB_EXTENSION - // iterate over all keycodes - for (int i = m_xkb->min_key_code; i <= m_xkb->max_key_code; ++i) { - KeyCode keycode = static_cast(i); + // check for group change actions, locking modifiers, and + // modifier masks. + item.m_lock = false; + bool isModifier = false; + UInt32 modifierMask = m_xkb->map->modmap[keycode]; if (XkbKeyHasActions(m_xkb, keycode) == True) { - // iterate over all groups - int numGroups = XkbKeyNumGroups(m_xkb, keycode); - for (int group = 0; group < numGroups; ++group) { - // iterate over all shift levels for the button (including none) - XkbKeyTypePtr type = XkbKeyKeyType(m_xkb, keycode, group); - for (int j = -1; j < type->map_count; ++j) { - if (j != -1 && !type->map[j].active) { - continue; - } - int level = ((j == -1) ? 0 : type->map[j].level); - XkbAction* action = - XkbKeyActionEntry(m_xkb, keycode, level, group); - if (action->type == XkbSA_SetMods || - action->type == XkbSA_LockMods) { - return true; - } - } + XkbAction *action = XkbKeyActionEntry(m_xkb, keycode, level, eGroup); + if (action->type == XkbSA_SetMods || action->type == XkbSA_LockMods) { + isModifier = true; + + // note toggles + item.m_lock = (action->type == XkbSA_LockMods); + + // maybe use action's mask + if ((action->mods.flags & XkbSA_UseModMapMods) == 0) { + modifierMask = action->mods.mask; } + } else if (action->type == XkbSA_SetGroup || + action->type == XkbSA_LatchGroup || + action->type == XkbSA_LockGroup) { + // ignore group change key + continue; + } } - } -#endif - return false; -} + level = mapEntry->level; -int -XWindowsKeyState::getEffectiveGroup(KeyCode keycode, int group) const -{ - (void)keycode; -#if HAVE_XKB_EXTENSION - // get effective group for key - int numGroups = XkbKeyNumGroups(m_xkb, keycode); - if (group >= numGroups) { - unsigned char groupInfo = XkbKeyGroupInfo(m_xkb, keycode); - switch (XkbOutOfRangeGroupAction(groupInfo)) { - case XkbClampIntoRange: - group = numGroups - 1; - break; + // VMware modifier hack + if (useLastGoodModifiers) { + XKBModifierMap::const_iterator k = + m_lastGoodXKBModifiers.find(eGroup * 256 + keycode); + if (k != m_lastGoodXKBModifiers.end()) { + // Use last known good modifier + isModifier = true; + level = k->second.m_level; + modifierMask = k->second.m_mask; + item.m_lock = k->second.m_lock; + } + } else if (isModifier) { + // Save known good modifier + XKBModifierInfo &info = + m_lastGoodXKBModifiers[eGroup * 256 + keycode]; + info.m_level = level; + info.m_mask = modifierMask; + info.m_lock = item.m_lock; + } - case XkbRedirectIntoRange: - group = XkbOutOfRangeGroupNumber(groupInfo); - if (group >= numGroups) { - group = 0; + // record the modifier mask for this key. don't bother + // for keys that change the group. + item.m_generates = 0; + UInt32 modifierBit = XWindowsUtil::getModifierBitForKeySym(keysym); + if (isModifier && modifierBit != kKeyModifierBitNone) { + item.m_generates = (1u << modifierBit); + for (SInt32 j = 0; j < 8; ++j) { + // skip modifiers this key doesn't generate + if ((modifierMask & (1u << j)) == 0) { + continue; } - break; - default: - // wrap - group %= numGroups; - break; + // skip keys that map to a modifier that we've + // already seen using fewer modifiers. that is + // if this key must combine with other modifiers + // and we know of a key that combines with fewer + // modifiers (or no modifiers) then prefer the + // other key. + if (level >= modifierLevel[8 * group + j]) { + continue; + } + modifierLevel[8 * group + j] = level; + + // save modifier + m_modifierFromX[8 * group + j] |= (1u << modifierBit); + m_modifierToX.insert(std::make_pair(1u << modifierBit, 1u << j)); + } } + + // handle special cases of just one keysym for the keycode + if (type->num_levels == 1) { + // if there are upper- and lowercase versions of the + // keysym then add both. + KeySym lKeysym, uKeysym; + XConvertCase(keysym, &lKeysym, &uKeysym); + if (lKeysym != uKeysym) { + if (j != -1) { + continue; + } + + item.m_sensitive |= ShiftMask | LockMask; + + KeyID lKeyID = XWindowsUtil::mapKeySymToKeyID(lKeysym); + KeyID uKeyID = XWindowsUtil::mapKeySymToKeyID(uKeysym); + if (lKeyID == kKeyNone || uKeyID == kKeyNone) { + continue; + } + + item.m_id = lKeyID; + item.m_required = 0; + keyMap.addKeyEntry(item); + + item.m_id = uKeyID; + item.m_required = ShiftMask; + keyMap.addKeyEntry(item); + item.m_required = LockMask; + keyMap.addKeyEntry(item); + + if (group == 0) { + m_keyCodeFromKey.insert(std::make_pair(lKeyID, keycode)); + m_keyCodeFromKey.insert(std::make_pair(uKeyID, keycode)); + } + continue; + } + } + + // add entry + item.m_id = XWindowsUtil::mapKeySymToKeyID(keysym); + keyMap.addKeyEntry(item); + if (group == 0) { + m_keyCodeFromKey.insert(std::make_pair(item.m_id, keycode)); + } + } } + } + + // change all modifier masks to synergy masks from X masks + keyMap.foreachKey(&XWindowsKeyState::remapKeyModifiers, this); + + // allow composition across groups + keyMap.allowGroupSwitchDuringCompose(); +} #endif - return group; + +void XWindowsKeyState::remapKeyModifiers(KeyID id, SInt32 group, + synergy::KeyMap::KeyItem &item, + void *vself) { + XWindowsKeyState *self = static_cast(vself); + item.m_required = + self->mapModifiersFromX(XkbBuildCoreState(item.m_required, group)); + item.m_sensitive = + self->mapModifiersFromX(XkbBuildCoreState(item.m_sensitive, group)); } -UInt32 -XWindowsKeyState::getGroupFromState(unsigned int state) const -{ +bool XWindowsKeyState::hasModifiersXKB() const { #if HAVE_XKB_EXTENSION - if (m_xkb != NULL) { - return XkbGroupForCoreState(state); + // iterate over all keycodes + for (int i = m_xkb->min_key_code; i <= m_xkb->max_key_code; ++i) { + KeyCode keycode = static_cast(i); + if (XkbKeyHasActions(m_xkb, keycode) == True) { + // iterate over all groups + int numGroups = XkbKeyNumGroups(m_xkb, keycode); + for (int group = 0; group < numGroups; ++group) { + // iterate over all shift levels for the button (including none) + XkbKeyTypePtr type = XkbKeyKeyType(m_xkb, keycode, group); + for (int j = -1; j < type->map_count; ++j) { + if (j != -1 && !type->map[j].active) { + continue; + } + int level = ((j == -1) ? 0 : type->map[j].level); + XkbAction *action = XkbKeyActionEntry(m_xkb, keycode, level, group); + if (action->type == XkbSA_SetMods || action->type == XkbSA_LockMods) { + return true; + } + } + } } + } #endif - return 0; + return false; +} + +int XWindowsKeyState::getEffectiveGroup(KeyCode keycode, int group) const { + (void)keycode; +#if HAVE_XKB_EXTENSION + // get effective group for key + int numGroups = XkbKeyNumGroups(m_xkb, keycode); + if (group >= numGroups) { + unsigned char groupInfo = XkbKeyGroupInfo(m_xkb, keycode); + switch (XkbOutOfRangeGroupAction(groupInfo)) { + case XkbClampIntoRange: + group = numGroups - 1; + break; + + case XkbRedirectIntoRange: + group = XkbOutOfRangeGroupNumber(groupInfo); + if (group >= numGroups) { + group = 0; + } + break; + + default: + // wrap + group %= numGroups; + break; + } + } +#endif + return group; +} + +UInt32 XWindowsKeyState::getGroupFromState(unsigned int state) const { +#if HAVE_XKB_EXTENSION + if (m_xkb != NULL) { + return XkbGroupForCoreState(state); + } +#endif + return 0; } diff --git a/src/lib/platform/XWindowsKeyState.h b/src/lib/platform/XWindowsKeyState.h index da1183ce8..a16c2da4a 100644 --- a/src/lib/platform/XWindowsKeyState.h +++ b/src/lib/platform/XWindowsKeyState.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2003 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 LICENSE 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 @@ -18,22 +18,22 @@ #pragma once -#include "synergy/KeyState.h" #include "common/stdmap.h" #include "common/stdvector.h" +#include "synergy/KeyState.h" #if X_DISPLAY_MISSING -# error X11 is required to build synergy +#error X11 is required to build synergy #else -# include -# if HAVE_X11_EXTENSIONS_XTEST_H -# include -# else -# error The XTest extension is required to build synergy -# endif -# if HAVE_XKB_EXTENSION -# include -# endif +#include +#if HAVE_X11_EXTENSIONS_XTEST_H +#include +#else +#error The XTest extension is required to build synergy +#endif +#if HAVE_XKB_EXTENSION +#include +#endif #endif class IEventQueue; @@ -44,137 +44,132 @@ A key state for X Windows. */ class XWindowsKeyState : public KeyState { public: - typedef std::vector KeycodeList; - enum { - kGroupPoll = -1, - kGroupPollAndSet = -2 - }; + typedef std::vector KeycodeList; + enum { kGroupPoll = -1, kGroupPollAndSet = -2 }; - XWindowsKeyState(Display*, bool useXKB, IEventQueue* events); - XWindowsKeyState(Display*, bool useXKB, - IEventQueue* events, synergy::KeyMap& keyMap); - ~XWindowsKeyState(); + XWindowsKeyState(Display *, bool useXKB, IEventQueue *events); + XWindowsKeyState(Display *, bool useXKB, IEventQueue *events, + synergy::KeyMap &keyMap); + ~XWindowsKeyState(); - //! @name modifiers - //@{ + //! @name modifiers + //@{ - //! Set active group - /*! - Sets the active group to \p group. This is the group returned by - \c pollActiveGroup(). If \p group is \c kGroupPoll then - \c pollActiveGroup() will really poll, but that's a slow operation - on X11. If \p group is \c kGroupPollAndSet then this will poll the - active group now and use it for future calls to \c pollActiveGroup(). - */ - void setActiveGroup(SInt32 group); + //! Set active group + /*! + Sets the active group to \p group. This is the group returned by + \c pollActiveGroup(). If \p group is \c kGroupPoll then + \c pollActiveGroup() will really poll, but that's a slow operation + on X11. If \p group is \c kGroupPollAndSet then this will poll the + active group now and use it for future calls to \c pollActiveGroup(). + */ + void setActiveGroup(SInt32 group); - //! Set the auto-repeat state - /*! - Sets the auto-repeat state. - */ - void setAutoRepeat(const XKeyboardState&); + //! Set the auto-repeat state + /*! + Sets the auto-repeat state. + */ + void setAutoRepeat(const XKeyboardState &); - //@} - //! @name accessors - //@{ + //@} + //! @name accessors + //@{ - //! Convert X modifier mask to synergy mask - /*! - Returns the synergy modifier mask corresponding to the X modifier - mask in \p state. - */ - KeyModifierMask mapModifiersFromX(unsigned int state) const; + //! Convert X modifier mask to synergy mask + /*! + Returns the synergy modifier mask corresponding to the X modifier + mask in \p state. + */ + KeyModifierMask mapModifiersFromX(unsigned int state) const; - //! Convert synergy modifier mask to X mask - /*! - Converts the synergy modifier mask to the corresponding X modifier - mask. Returns \c true if successful and \c false if any modifier - could not be converted. - */ - bool mapModifiersToX(KeyModifierMask, unsigned int&) const; + //! Convert synergy modifier mask to X mask + /*! + Converts the synergy modifier mask to the corresponding X modifier + mask. Returns \c true if successful and \c false if any modifier + could not be converted. + */ + bool mapModifiersToX(KeyModifierMask, unsigned int &) const; - //! Convert synergy key to all corresponding X keycodes - /*! - Converts the synergy key \p key to all of the keycodes that map to - that key. - */ - void mapKeyToKeycodes(KeyID key, - KeycodeList& keycodes) const; + //! Convert synergy key to all corresponding X keycodes + /*! + Converts the synergy key \p key to all of the keycodes that map to + that key. + */ + void mapKeyToKeycodes(KeyID key, KeycodeList &keycodes) const; - //@} + //@} - // IKeyState overrides - virtual bool fakeCtrlAltDel(); - virtual KeyModifierMask - pollActiveModifiers() const; - virtual SInt32 pollActiveGroup() const; - virtual void pollPressedKeys(KeyButtonSet& pressedKeys) const; + // IKeyState overrides + virtual bool fakeCtrlAltDel(); + virtual KeyModifierMask pollActiveModifiers() const; + virtual SInt32 pollActiveGroup() const; + virtual void pollPressedKeys(KeyButtonSet &pressedKeys) const; protected: - // KeyState overrides - virtual void getKeyMap(synergy::KeyMap& keyMap); - virtual void fakeKey(const Keystroke& keystroke); + // KeyState overrides + virtual void getKeyMap(synergy::KeyMap &keyMap); + virtual void fakeKey(const Keystroke &keystroke); private: - void init(Display* display, bool useXKB); - void updateKeysymMap(synergy::KeyMap&); - void updateKeysymMapXKB(synergy::KeyMap&); - bool hasModifiersXKB() const; - int getEffectiveGroup(KeyCode, int group) const; - UInt32 getGroupFromState(unsigned int state) const; + void init(Display *display, bool useXKB); + void updateKeysymMap(synergy::KeyMap &); + void updateKeysymMapXKB(synergy::KeyMap &); + bool hasModifiersXKB() const; + int getEffectiveGroup(KeyCode, int group) const; + UInt32 getGroupFromState(unsigned int state) const; - //! Create and send language change request to \p group by DBus interface - /*! - Returns the existance of nedeed DBus interface. - */ - bool setCurrentLanguageWithDBus(SInt32 group) const; + //! Create and send language change request to \p group by DBus interface + /*! + Returns the existance of nedeed DBus interface. + */ + bool setCurrentLanguageWithDBus(SInt32 group) const; - static void remapKeyModifiers(KeyID, SInt32, - synergy::KeyMap::KeyItem&, void*); + static void remapKeyModifiers(KeyID, SInt32, synergy::KeyMap::KeyItem &, + void *); private: - struct XKBModifierInfo { - public: - unsigned char m_level; - UInt32 m_mask; - bool m_lock; - }; + struct XKBModifierInfo { + public: + unsigned char m_level; + UInt32 m_mask; + bool m_lock; + }; #ifdef TEST_ENV public: // yuck #endif - typedef std::vector KeyModifierMaskList; + typedef std::vector KeyModifierMaskList; private: - typedef std::map KeyModifierToXMask; - typedef std::multimap KeyToKeyCodeMap; - typedef std::map NonXKBModifierMap; - typedef std::map XKBModifierMap; + typedef std::map KeyModifierToXMask; + typedef std::multimap KeyToKeyCodeMap; + typedef std::map NonXKBModifierMap; + typedef std::map XKBModifierMap; - Display* m_display; + Display *m_display; #if HAVE_XKB_EXTENSION - XkbDescPtr m_xkb; + XkbDescPtr m_xkb; #endif - SInt32 m_group; - XKBModifierMap m_lastGoodXKBModifiers; - NonXKBModifierMap m_lastGoodNonXKBModifiers; + SInt32 m_group; + XKBModifierMap m_lastGoodXKBModifiers; + NonXKBModifierMap m_lastGoodNonXKBModifiers; - // X modifier (bit number) to synergy modifier (mask) mapping - KeyModifierMaskList m_modifierFromX; + // X modifier (bit number) to synergy modifier (mask) mapping + KeyModifierMaskList m_modifierFromX; - // synergy modifier (mask) to X modifier (mask) - KeyModifierToXMask m_modifierToX; + // synergy modifier (mask) to X modifier (mask) + KeyModifierToXMask m_modifierToX; - // map KeyID to all keycodes that can synthesize that KeyID - KeyToKeyCodeMap m_keyCodeFromKey; + // map KeyID to all keycodes that can synthesize that KeyID + KeyToKeyCodeMap m_keyCodeFromKey; - // autorepeat state - XKeyboardState m_keyboardState; + // autorepeat state + XKeyboardState m_keyboardState; #ifdef TEST_ENV public: - SInt32 group() const { return m_group; } - void group(const SInt32& group) { m_group = group; } - KeyModifierMaskList modifierFromX() const { return m_modifierFromX; } + SInt32 group() const { return m_group; } + void group(const SInt32 &group) { m_group = group; } + KeyModifierMaskList modifierFromX() const { return m_modifierFromX; } #endif }; diff --git a/src/lib/platform/XWindowsPowerManager.cpp b/src/lib/platform/XWindowsPowerManager.cpp index c3754c5dd..697749aad 100644 --- a/src/lib/platform/XWindowsPowerManager.cpp +++ b/src/lib/platform/XWindowsPowerManager.cpp @@ -19,42 +19,38 @@ #include "arch/Arch.h" #include "base/Log.h" -namespace{ +namespace { -bool sleepInhibitCall(bool state, ArchSystemUnix::InhibitScreenServices serviceID) -{ - std::string error; +bool sleepInhibitCall(bool state, + ArchSystemUnix::InhibitScreenServices serviceID) { + std::string error; - if (!ArchSystemUnix::DBusInhibitScreenCall(serviceID, state, error)) - { - LOG((CLOG_DEBUG "dbus inhibit error %s", error.c_str())); - return false; - } + if (!ArchSystemUnix::DBusInhibitScreenCall(serviceID, state, error)) { + LOG((CLOG_DEBUG "dbus inhibit error %s", error.c_str())); + return false; + } - return true; + return true; } +} // namespace + +XWindowsPowerManager::~XWindowsPowerManager() { enableSleep(); } + +void XWindowsPowerManager::disableSleep() const { + if (!sleepInhibitCall(true, + ArchSystemUnix::InhibitScreenServices::kScreenSaver) && + !sleepInhibitCall( + true, ArchSystemUnix::InhibitScreenServices::kSessionManager)) { + LOG((CLOG_INFO "failed to prevent system from going to sleep")); + } } -XWindowsPowerManager::~XWindowsPowerManager() -{ - enableSleep(); -} - -void XWindowsPowerManager::disableSleep() const -{ - if (!sleepInhibitCall(true, ArchSystemUnix::InhibitScreenServices::kScreenSaver) && - !sleepInhibitCall(true, ArchSystemUnix::InhibitScreenServices::kSessionManager)) - { - LOG((CLOG_INFO "failed to prevent system from going to sleep")); - } -} - -void XWindowsPowerManager::enableSleep() const -{ - if (!sleepInhibitCall(false, ArchSystemUnix::InhibitScreenServices::kScreenSaver) && - !sleepInhibitCall(false, ArchSystemUnix::InhibitScreenServices::kSessionManager)) - { - LOG((CLOG_INFO "failed to enable system idle sleep")); - } +void XWindowsPowerManager::enableSleep() const { + if (!sleepInhibitCall(false, + ArchSystemUnix::InhibitScreenServices::kScreenSaver) && + !sleepInhibitCall( + false, ArchSystemUnix::InhibitScreenServices::kSessionManager)) { + LOG((CLOG_INFO "failed to enable system idle sleep")); + } } diff --git a/src/lib/platform/XWindowsPowerManager.h b/src/lib/platform/XWindowsPowerManager.h index dc03af6e5..17bfdb198 100644 --- a/src/lib/platform/XWindowsPowerManager.h +++ b/src/lib/platform/XWindowsPowerManager.h @@ -18,25 +18,23 @@ #ifndef XWINDOWSPOWERMANAGER_H #define XWINDOWSPOWERMANAGER_H - -class XWindowsPowerManager -{ +class XWindowsPowerManager { public: - XWindowsPowerManager() = default; - ~XWindowsPowerManager(); + XWindowsPowerManager() = default; + ~XWindowsPowerManager(); - /** - * @brief Prevent the system from sleep - */ - void disableSleep() const; + /** + * @brief Prevent the system from sleep + */ + void disableSleep() const; - /** - * @brief Enables automatical sleep - */ - void enableSleep() const; + /** + * @brief Enables automatical sleep + */ + void enableSleep() const; - XWindowsPowerManager(const XWindowsPowerManager&) = delete; - XWindowsPowerManager& operator=(const XWindowsPowerManager&) = delete; + XWindowsPowerManager(const XWindowsPowerManager &) = delete; + XWindowsPowerManager &operator=(const XWindowsPowerManager &) = delete; }; #endif // XWINDOWSPOWERMANAGER_H diff --git a/src/lib/platform/XWindowsScreen.cpp b/src/lib/platform/XWindowsScreen.cpp index af1d10946..fd3b8cb15 100644 --- a/src/lib/platform/XWindowsScreen.cpp +++ b/src/lib/platform/XWindowsScreen.cpp @@ -18,62 +18,62 @@ #include "platform/XWindowsScreen.h" +#include "arch/Arch.h" +#include "arch/XArch.h" +#include "base/IEventQueue.h" +#include "base/Log.h" +#include "base/Stopwatch.h" +#include "base/String.h" +#include "base/TMethodEventJob.h" #include "platform/XWindowsClipboard.h" #include "platform/XWindowsEventQueueBuffer.h" #include "platform/XWindowsKeyState.h" #include "platform/XWindowsScreenSaver.h" #include "platform/XWindowsUtil.h" -#include "synergy/Clipboard.h" -#include "synergy/KeyMap.h" +#include "synergy/App.h" +#include "synergy/ArgsBase.h" #include "synergy/ClientApp.h" #include "synergy/ClientArgs.h" +#include "synergy/Clipboard.h" +#include "synergy/KeyMap.h" #include "synergy/XScreen.h" -#include "synergy/ArgsBase.h" -#include "synergy/App.h" -#include "arch/XArch.h" -#include "arch/Arch.h" -#include "base/Log.h" -#include "base/Stopwatch.h" -#include "base/String.h" -#include "base/IEventQueue.h" -#include "base/TMethodEventJob.h" -#include -#include #include +#include +#include #if X_DISPLAY_MISSING -# error X11 is required to build synergy +#error X11 is required to build synergy #else -# include -# include -# define XK_MISCELLANY -# define XK_XKB_KEYS -# include -# if HAVE_X11_EXTENSIONS_DPMS_H - extern "C" { -# include - } -# endif -# if HAVE_X11_EXTENSIONS_XTEST_H -# include -# else -# error The XTest extension is required to build synergy -# endif -# if HAVE_X11_EXTENSIONS_XINERAMA_H - // Xinerama.h may lack extern "C" for inclusion by C++ - extern "C" { -# include - } -# endif -# if HAVE_X11_EXTENSIONS_XRANDR_H -# include -# endif -# if HAVE_XKB_EXTENSION -# include -# endif -# ifdef HAVE_XI2 -# include -# endif +#include +#include +#define XK_MISCELLANY +#define XK_XKB_KEYS +#include +#if HAVE_X11_EXTENSIONS_DPMS_H +extern "C" { +#include +} +#endif +#if HAVE_X11_EXTENSIONS_XTEST_H +#include +#else +#error The XTest extension is required to build synergy +#endif +#if HAVE_X11_EXTENSIONS_XINERAMA_H +// Xinerama.h may lack extern "C" for inclusion by C++ +extern "C" { +#include +} +#endif +#if HAVE_X11_EXTENSIONS_XRANDR_H +#include +#endif +#if HAVE_XKB_EXTENSION +#include +#endif +#ifdef HAVE_XI2 +#include +#endif #endif static int xi_opcode; @@ -93,2075 +93,1884 @@ static int xi_opcode; // display and the X11 event queue buffer, ignore any calls that try // to use the display, and wait to be destroyed. -XWindowsScreen* XWindowsScreen::s_screen = NULL; +XWindowsScreen *XWindowsScreen::s_screen = NULL; XWindowsScreen::XWindowsScreen( - const char* displayName, - bool isPrimary, - bool disableXInitThreads, - int mouseScrollDelta, - IEventQueue* events, - lib::synergy::ClientScrollDirection scrollDirection) : - PlatformScreen(events, scrollDirection), - m_isPrimary(isPrimary), - m_mouseScrollDelta(mouseScrollDelta), - m_display(NULL), - m_root(None), - m_window(None), - m_isOnScreen(m_isPrimary), - m_x(0), m_y(0), - m_w(0), m_h(0), - m_xCenter(0), m_yCenter(0), - m_xCursor(0), m_yCursor(0), - m_keyState(NULL), - m_lastFocus(None), - m_lastFocusRevert(RevertToNone), - m_im(NULL), - m_ic(NULL), - m_lastKeycode(0), - m_sequenceNumber(0), - m_screensaver(NULL), - m_screensaverNotify(false), - m_xtestIsXineramaUnaware(true), - m_preserveFocus(false), - m_xkb(false), - m_xi2detected(false), - m_xrandr(false), - m_events(events) -{ - assert(s_screen == NULL); + const char *displayName, bool isPrimary, bool disableXInitThreads, + int mouseScrollDelta, IEventQueue *events, + lib::synergy::ClientScrollDirection scrollDirection) + : PlatformScreen(events, scrollDirection), m_isPrimary(isPrimary), + m_mouseScrollDelta(mouseScrollDelta), m_display(NULL), m_root(None), + m_window(None), m_isOnScreen(m_isPrimary), m_x(0), m_y(0), m_w(0), m_h(0), + m_xCenter(0), m_yCenter(0), m_xCursor(0), m_yCursor(0), m_keyState(NULL), + m_lastFocus(None), m_lastFocusRevert(RevertToNone), m_im(NULL), + m_ic(NULL), m_lastKeycode(0), m_sequenceNumber(0), m_screensaver(NULL), + m_screensaverNotify(false), m_xtestIsXineramaUnaware(true), + m_preserveFocus(false), m_xkb(false), m_xi2detected(false), + m_xrandr(false), m_events(events) { + assert(s_screen == NULL); - if (mouseScrollDelta==0) m_mouseScrollDelta=120; - s_screen = this; + if (mouseScrollDelta == 0) + m_mouseScrollDelta = 120; + s_screen = this; - if (!disableXInitThreads) { - // initializes Xlib support for concurrent threads. - if (XInitThreads() == 0) - throw XArch("XInitThreads() returned zero"); - } else { - LOG((CLOG_DEBUG "skipping XInitThreads()")); - } + if (!disableXInitThreads) { + // initializes Xlib support for concurrent threads. + if (XInitThreads() == 0) + throw XArch("XInitThreads() returned zero"); + } else { + LOG((CLOG_DEBUG "skipping XInitThreads()")); + } - // set the X I/O error handler so we catch the display disconnecting - XSetIOErrorHandler(&XWindowsScreen::ioErrorHandler); + // set the X I/O error handler so we catch the display disconnecting + XSetIOErrorHandler(&XWindowsScreen::ioErrorHandler); - try { - m_display = openDisplay(displayName); - m_root = DefaultRootWindow(m_display); - saveShape(); - m_window = openWindow(); - m_screensaver = new XWindowsScreenSaver(m_display, - m_window, getEventTarget(), events); - m_keyState = new XWindowsKeyState(m_display, m_xkb, events, m_keyMap); - LOG((CLOG_DEBUG "screen shape: %d,%d %dx%d %s", m_x, m_y, m_w, m_h, m_xinerama ? "(xinerama)" : "")); - LOG((CLOG_DEBUG "window is 0x%08x", m_window)); - } - catch (...) { - if (m_display != NULL) { - XCloseDisplay(m_display); - } - throw; - } + try { + m_display = openDisplay(displayName); + m_root = DefaultRootWindow(m_display); + saveShape(); + m_window = openWindow(); + m_screensaver = + new XWindowsScreenSaver(m_display, m_window, getEventTarget(), events); + m_keyState = new XWindowsKeyState(m_display, m_xkb, events, m_keyMap); + LOG((CLOG_DEBUG "screen shape: %d,%d %dx%d %s", m_x, m_y, m_w, m_h, + m_xinerama ? "(xinerama)" : "")); + LOG((CLOG_DEBUG "window is 0x%08x", m_window)); + } catch (...) { + if (m_display != NULL) { + XCloseDisplay(m_display); + } + throw; + } - // primary/secondary screen only initialization - if (m_isPrimary) { + // primary/secondary screen only initialization + if (m_isPrimary) { #ifdef HAVE_XI2 - m_xi2detected = detectXI2(); - if (m_xi2detected) { - selectXIRawMotion(); - } else + m_xi2detected = detectXI2(); + if (m_xi2detected) { + selectXIRawMotion(); + } else #endif - { - // start watching for events on other windows - selectEvents(m_root); - } - - // prepare to use input methods - openIM(); - } - else { - // become impervious to server grabs - XTestGrabControl(m_display, True); - } - - // disable sleep if the flag is set - if (App::instance().argsBase().m_preventSleep) { - m_powerManager.disableSleep(); + { + // start watching for events on other windows + selectEvents(m_root); } - // initialize the clipboards - for (ClipboardID id = 0; id < kClipboardEnd; ++id) { - m_clipboard[id] = new XWindowsClipboard(m_display, m_window, id); - } + // prepare to use input methods + openIM(); + } else { + // become impervious to server grabs + XTestGrabControl(m_display, True); + } - // install event handlers - m_events->adoptHandler(Event::kSystem, m_events->getSystemTarget(), - new TMethodEventJob(this, - &XWindowsScreen::handleSystemEvent)); + // disable sleep if the flag is set + if (App::instance().argsBase().m_preventSleep) { + m_powerManager.disableSleep(); + } - // install the platform event queue - m_events->adoptBuffer(new XWindowsEventQueueBuffer( - m_display, m_window, m_events)); + // initialize the clipboards + for (ClipboardID id = 0; id < kClipboardEnd; ++id) { + m_clipboard[id] = new XWindowsClipboard(m_display, m_window, id); + } + + // install event handlers + m_events->adoptHandler(Event::kSystem, m_events->getSystemTarget(), + new TMethodEventJob( + this, &XWindowsScreen::handleSystemEvent)); + + // install the platform event queue + m_events->adoptBuffer( + new XWindowsEventQueueBuffer(m_display, m_window, m_events)); } -XWindowsScreen::~XWindowsScreen() -{ - assert(s_screen != NULL); - assert(m_display != NULL); +XWindowsScreen::~XWindowsScreen() { + assert(s_screen != NULL); + assert(m_display != NULL); - m_events->adoptBuffer(NULL); - m_events->removeHandler(Event::kSystem, m_events->getSystemTarget()); - for (ClipboardID id = 0; id < kClipboardEnd; ++id) { - delete m_clipboard[id]; - } - delete m_keyState; - delete m_screensaver; - m_keyState = NULL; - m_screensaver = NULL; - if (m_display != NULL) { - // FIXME -- is it safe to clean up the IC and IM without a display? - if (m_ic != NULL) { - XDestroyIC(m_ic); - } - if (m_im != NULL) { - XCloseIM(m_im); - } - XDestroyWindow(m_display, m_window); - XCloseDisplay(m_display); - } - XSetIOErrorHandler(NULL); + m_events->adoptBuffer(NULL); + m_events->removeHandler(Event::kSystem, m_events->getSystemTarget()); + for (ClipboardID id = 0; id < kClipboardEnd; ++id) { + delete m_clipboard[id]; + } + delete m_keyState; + delete m_screensaver; + m_keyState = NULL; + m_screensaver = NULL; + if (m_display != NULL) { + // FIXME -- is it safe to clean up the IC and IM without a display? + if (m_ic != NULL) { + XDestroyIC(m_ic); + } + if (m_im != NULL) { + XCloseIM(m_im); + } + XDestroyWindow(m_display, m_window); + XCloseDisplay(m_display); + } + XSetIOErrorHandler(NULL); - s_screen = NULL; + s_screen = NULL; } -void -XWindowsScreen::enable() -{ - if (!m_isPrimary) { - // get the keyboard control state - XKeyboardState keyControl; - XGetKeyboardControl(m_display, &keyControl); - m_autoRepeat = (keyControl.global_auto_repeat == AutoRepeatModeOn); - m_keyState->setAutoRepeat(keyControl); +void XWindowsScreen::enable() { + if (!m_isPrimary) { + // get the keyboard control state + XKeyboardState keyControl; + XGetKeyboardControl(m_display, &keyControl); + m_autoRepeat = (keyControl.global_auto_repeat == AutoRepeatModeOn); + m_keyState->setAutoRepeat(keyControl); - // move hider window under the cursor center - XMoveWindow(m_display, m_window, m_xCenter, m_yCenter); + // move hider window under the cursor center + XMoveWindow(m_display, m_window, m_xCenter, m_yCenter); - // raise and show the window - // FIXME -- take focus? - XMapRaised(m_display, m_window); + // raise and show the window + // FIXME -- take focus? + XMapRaised(m_display, m_window); - // warp the mouse to the cursor center - fakeMouseMove(m_xCenter, m_yCenter); - } + // warp the mouse to the cursor center + fakeMouseMove(m_xCenter, m_yCenter); + } } -void -XWindowsScreen::disable() -{ - // release input context focus - if (m_ic != NULL) { - XUnsetICFocus(m_ic); - } +void XWindowsScreen::disable() { + // release input context focus + if (m_ic != NULL) { + XUnsetICFocus(m_ic); + } - // unmap the hider/grab window. this also ungrabs the mouse and - // keyboard if they're grabbed. - XUnmapWindow(m_display, m_window); + // unmap the hider/grab window. this also ungrabs the mouse and + // keyboard if they're grabbed. + XUnmapWindow(m_display, m_window); - // restore auto-repeat state - if (!m_isPrimary && m_autoRepeat) { - //XAutoRepeatOn(m_display); - } + // restore auto-repeat state + if (!m_isPrimary && m_autoRepeat) { + // XAutoRepeatOn(m_display); + } } -void -XWindowsScreen::enter() -{ - screensaver(false); +void XWindowsScreen::enter() { + screensaver(false); - // release input context focus - if (m_ic != NULL) { - XUnsetICFocus(m_ic); - } + // release input context focus + if (m_ic != NULL) { + XUnsetICFocus(m_ic); + } - // set the input focus to what it had been when we took it - if (m_lastFocus != None) { - // the window may not exist anymore so ignore errors - XWindowsUtil::ErrorLock lock(m_display); - XSetInputFocus(m_display, m_lastFocus, m_lastFocusRevert, CurrentTime); - } + // set the input focus to what it had been when we took it + if (m_lastFocus != None) { + // the window may not exist anymore so ignore errors + XWindowsUtil::ErrorLock lock(m_display); + XSetInputFocus(m_display, m_lastFocus, m_lastFocusRevert, CurrentTime); + } - #if HAVE_X11_EXTENSIONS_DPMS_H - // Force the DPMS to turn screen back on since we don't - // actually cause physical hardware input to trigger it - int dummy; - CARD16 powerlevel; - BOOL enabled; - if (DPMSQueryExtension(m_display, &dummy, &dummy) && - DPMSCapable(m_display) && - DPMSInfo(m_display, &powerlevel, &enabled)) - { - if (enabled && powerlevel != DPMSModeOn) - DPMSForceLevel(m_display, DPMSModeOn); - } - #endif +#if HAVE_X11_EXTENSIONS_DPMS_H + // Force the DPMS to turn screen back on since we don't + // actually cause physical hardware input to trigger it + int dummy; + CARD16 powerlevel; + BOOL enabled; + if (DPMSQueryExtension(m_display, &dummy, &dummy) && DPMSCapable(m_display) && + DPMSInfo(m_display, &powerlevel, &enabled)) { + if (enabled && powerlevel != DPMSModeOn) + DPMSForceLevel(m_display, DPMSModeOn); + } +#endif - // unmap the hider/grab window. this also ungrabs the mouse and - // keyboard if they're grabbed. - XUnmapWindow(m_display, m_window); + // unmap the hider/grab window. this also ungrabs the mouse and + // keyboard if they're grabbed. + XUnmapWindow(m_display, m_window); -/* maybe call this if entering for the screensaver - // set keyboard focus to root window. the screensaver should then - // pick up key events for when the user enters a password to unlock. - XSetInputFocus(m_display, PointerRoot, PointerRoot, CurrentTime); -*/ + /* maybe call this if entering for the screensaver + // set keyboard focus to root window. the screensaver should then + // pick up key events for when the user enters a password to unlock. + XSetInputFocus(m_display, PointerRoot, PointerRoot, CurrentTime); + */ - if (!m_isPrimary) { - // get the keyboard control state - XKeyboardState keyControl; - XGetKeyboardControl(m_display, &keyControl); - m_autoRepeat = (keyControl.global_auto_repeat == AutoRepeatModeOn); - m_keyState->setAutoRepeat(keyControl); + if (!m_isPrimary) { + // get the keyboard control state + XKeyboardState keyControl; + XGetKeyboardControl(m_display, &keyControl); + m_autoRepeat = (keyControl.global_auto_repeat == AutoRepeatModeOn); + m_keyState->setAutoRepeat(keyControl); - // turn off auto-repeat. we do this so fake key press events don't - // cause the local server to generate their own auto-repeats of - // those keys. - //XAutoRepeatOff(m_display); - } + // turn off auto-repeat. we do this so fake key press events don't + // cause the local server to generate their own auto-repeats of + // those keys. + // XAutoRepeatOff(m_display); + } - // now on screen - m_isOnScreen = true; + // now on screen + m_isOnScreen = true; } -bool -XWindowsScreen::leave() -{ - if (!m_isPrimary) { - // restore the previous keyboard auto-repeat state. if the user - // changed the auto-repeat configuration while on the client then - // that state is lost. that's because we can't get notified by - // the X server when the auto-repeat configuration is changed so - // we can't track the desired configuration. - if (m_autoRepeat) { - //XAutoRepeatOn(m_display); - } +bool XWindowsScreen::leave() { + if (!m_isPrimary) { + // restore the previous keyboard auto-repeat state. if the user + // changed the auto-repeat configuration while on the client then + // that state is lost. that's because we can't get notified by + // the X server when the auto-repeat configuration is changed so + // we can't track the desired configuration. + if (m_autoRepeat) { + // XAutoRepeatOn(m_display); + } - // move hider window under the cursor center - XMoveWindow(m_display, m_window, m_xCenter, m_yCenter); - } + // move hider window under the cursor center + XMoveWindow(m_display, m_window, m_xCenter, m_yCenter); + } - // raise and show the window - XMapRaised(m_display, m_window); + // raise and show the window + XMapRaised(m_display, m_window); - // grab the mouse and keyboard, if primary and possible - if (m_isPrimary && !grabMouseAndKeyboard()) { - XUnmapWindow(m_display, m_window); - return false; - } + // grab the mouse and keyboard, if primary and possible + if (m_isPrimary && !grabMouseAndKeyboard()) { + XUnmapWindow(m_display, m_window); + return false; + } - // save current focus - XGetInputFocus(m_display, &m_lastFocus, &m_lastFocusRevert); + // save current focus + XGetInputFocus(m_display, &m_lastFocus, &m_lastFocusRevert); - // take focus - if (m_isPrimary || !m_preserveFocus) { - XSetInputFocus(m_display, m_window, RevertToPointerRoot, CurrentTime); - } + // take focus + if (m_isPrimary || !m_preserveFocus) { + XSetInputFocus(m_display, m_window, RevertToPointerRoot, CurrentTime); + } - // now warp the mouse. we warp after showing the window so we're - // guaranteed to get the mouse leave event and to prevent the - // keyboard focus from changing under point-to-focus policies. - if (m_isPrimary) { - warpCursor(m_xCenter, m_yCenter); - } - else { - fakeMouseMove(m_xCenter, m_yCenter); - } + // now warp the mouse. we warp after showing the window so we're + // guaranteed to get the mouse leave event and to prevent the + // keyboard focus from changing under point-to-focus policies. + if (m_isPrimary) { + warpCursor(m_xCenter, m_yCenter); + } else { + fakeMouseMove(m_xCenter, m_yCenter); + } - // set input context focus to our window - if (m_ic != NULL) { - XmbResetIC(m_ic); - XSetICFocus(m_ic); - m_filtered.clear(); - } + // set input context focus to our window + if (m_ic != NULL) { + XmbResetIC(m_ic); + XSetICFocus(m_ic); + m_filtered.clear(); + } - // now off screen - m_isOnScreen = false; + // now off screen + m_isOnScreen = false; - return true; + return true; } -bool -XWindowsScreen::setClipboard(ClipboardID id, const IClipboard* clipboard) -{ - // fail if we don't have the requested clipboard - if (m_clipboard[id] == NULL) { - return false; - } +bool XWindowsScreen::setClipboard(ClipboardID id, const IClipboard *clipboard) { + // fail if we don't have the requested clipboard + if (m_clipboard[id] == NULL) { + return false; + } - // get the actual time. ICCCM does not allow CurrentTime. - Time timestamp = XWindowsUtil::getCurrentTime( - m_display, m_clipboard[id]->getWindow()); + // get the actual time. ICCCM does not allow CurrentTime. + Time timestamp = + XWindowsUtil::getCurrentTime(m_display, m_clipboard[id]->getWindow()); - if (clipboard != NULL) { - // save clipboard data - return Clipboard::copy(m_clipboard[id], clipboard, timestamp); - } - else { - // assert clipboard ownership - if (!m_clipboard[id]->open(timestamp)) { - return false; - } - m_clipboard[id]->empty(); - m_clipboard[id]->close(); - return true; - } + if (clipboard != NULL) { + // save clipboard data + return Clipboard::copy(m_clipboard[id], clipboard, timestamp); + } else { + // assert clipboard ownership + if (!m_clipboard[id]->open(timestamp)) { + return false; + } + m_clipboard[id]->empty(); + m_clipboard[id]->close(); + return true; + } } -void -XWindowsScreen::checkClipboards() -{ - // do nothing, we're always up to date +void XWindowsScreen::checkClipboards() { + // do nothing, we're always up to date } -void -XWindowsScreen::openScreensaver(bool notify) -{ - m_screensaverNotify = notify; - if (!m_screensaverNotify) { - m_screensaver->disable(); - } +void XWindowsScreen::openScreensaver(bool notify) { + m_screensaverNotify = notify; + if (!m_screensaverNotify) { + m_screensaver->disable(); + } } -void -XWindowsScreen::closeScreensaver() -{ - if (!m_screensaverNotify) { - m_screensaver->enable(); - } +void XWindowsScreen::closeScreensaver() { + if (!m_screensaverNotify) { + m_screensaver->enable(); + } } -void -XWindowsScreen::screensaver(bool activate) -{ - if (activate) { - m_screensaver->activate(); - } - else { - m_screensaver->deactivate(); - } +void XWindowsScreen::screensaver(bool activate) { + if (activate) { + m_screensaver->activate(); + } else { + m_screensaver->deactivate(); + } } -void -XWindowsScreen::resetOptions() -{ - m_xtestIsXineramaUnaware = true; - m_preserveFocus = false; +void XWindowsScreen::resetOptions() { + m_xtestIsXineramaUnaware = true; + m_preserveFocus = false; } -void -XWindowsScreen::setOptions(const OptionsList& options) -{ - for (UInt32 i = 0, n = options.size(); i < n; i += 2) { - if (options[i] == kOptionXTestXineramaUnaware) { - m_xtestIsXineramaUnaware = (options[i + 1] != 0); - LOG((CLOG_DEBUG1 "library, XTest is Xinerama unaware %s", m_xtestIsXineramaUnaware ? "true" : "false")); - } - else if (options[i] == kOptionScreenPreserveFocus) { - m_preserveFocus = (options[i + 1] != 0); - LOG((CLOG_DEBUG1 "preserve focus: %s", m_preserveFocus ? "true" : "false")); - } - } +void XWindowsScreen::setOptions(const OptionsList &options) { + for (UInt32 i = 0, n = options.size(); i < n; i += 2) { + if (options[i] == kOptionXTestXineramaUnaware) { + m_xtestIsXineramaUnaware = (options[i + 1] != 0); + LOG((CLOG_DEBUG1 "library, XTest is Xinerama unaware %s", + m_xtestIsXineramaUnaware ? "true" : "false")); + } else if (options[i] == kOptionScreenPreserveFocus) { + m_preserveFocus = (options[i + 1] != 0); + LOG((CLOG_DEBUG1 "preserve focus: %s", + m_preserveFocus ? "true" : "false")); + } + } } -void -XWindowsScreen::setSequenceNumber(UInt32 seqNum) -{ - m_sequenceNumber = seqNum; +void XWindowsScreen::setSequenceNumber(UInt32 seqNum) { + m_sequenceNumber = seqNum; } -bool -XWindowsScreen::isPrimary() const -{ - return m_isPrimary; +bool XWindowsScreen::isPrimary() const { return m_isPrimary; } + +String XWindowsScreen::getSecureInputApp() const { + // ignore on Linux + return ""; } -String -XWindowsScreen::getSecureInputApp() const -{ - // ignore on Linux - return ""; +void *XWindowsScreen::getEventTarget() const { + return const_cast(this); } -void* -XWindowsScreen::getEventTarget() const -{ - return const_cast(this); +bool XWindowsScreen::getClipboard(ClipboardID id, IClipboard *clipboard) const { + assert(clipboard != NULL); + + // fail if we don't have the requested clipboard + if (m_clipboard[id] == NULL) { + return false; + } + + // get the actual time. ICCCM does not allow CurrentTime. + Time timestamp = + XWindowsUtil::getCurrentTime(m_display, m_clipboard[id]->getWindow()); + + // copy the clipboard + return Clipboard::copy(clipboard, m_clipboard[id], timestamp); } -bool -XWindowsScreen::getClipboard(ClipboardID id, IClipboard* clipboard) const -{ - assert(clipboard != NULL); - - // fail if we don't have the requested clipboard - if (m_clipboard[id] == NULL) { - return false; - } - - // get the actual time. ICCCM does not allow CurrentTime. - Time timestamp = XWindowsUtil::getCurrentTime( - m_display, m_clipboard[id]->getWindow()); - - // copy the clipboard - return Clipboard::copy(clipboard, m_clipboard[id], timestamp); +void XWindowsScreen::getShape(SInt32 &x, SInt32 &y, SInt32 &w, + SInt32 &h) const { + x = m_x; + y = m_y; + w = m_w; + h = m_h; } -void -XWindowsScreen::getShape(SInt32& x, SInt32& y, SInt32& w, SInt32& h) const -{ - x = m_x; - y = m_y; - w = m_w; - h = m_h; +void XWindowsScreen::getCursorPos(SInt32 &x, SInt32 &y) const { + Window root, window; + int mx, my, xWindow, yWindow; + unsigned int mask; + if (XQueryPointer(m_display, m_root, &root, &window, &mx, &my, &xWindow, + &yWindow, &mask)) { + x = mx; + y = my; + } else { + x = m_xCenter; + y = m_yCenter; + } } -void -XWindowsScreen::getCursorPos(SInt32& x, SInt32& y) const -{ - Window root, window; - int mx, my, xWindow, yWindow; - unsigned int mask; - if (XQueryPointer(m_display, m_root, &root, &window, - &mx, &my, &xWindow, &yWindow, &mask)) { - x = mx; - y = my; - } - else { - x = m_xCenter; - y = m_yCenter; - } +void XWindowsScreen::reconfigure(UInt32) { + // do nothing } -void -XWindowsScreen::reconfigure(UInt32) -{ - // do nothing +void XWindowsScreen::warpCursor(SInt32 x, SInt32 y) { + // warp mouse + warpCursorNoFlush(x, y); + + // remove all input events before and including warp + XEvent event; + while (XCheckMaskEvent(m_display, + PointerMotionMask | ButtonPressMask | + ButtonReleaseMask | KeyPressMask | KeyReleaseMask | + KeymapStateMask, + &event)) { + // do nothing + } + + // save position as last position + m_xCursor = x; + m_yCursor = y; } -void -XWindowsScreen::warpCursor(SInt32 x, SInt32 y) -{ - // warp mouse - warpCursorNoFlush(x, y); +UInt32 XWindowsScreen::registerHotKey(KeyID key, KeyModifierMask mask) { + // only allow certain modifiers + if ((mask & ~(KeyModifierShift | KeyModifierControl | KeyModifierAlt | + KeyModifierSuper)) != 0) { + LOG((CLOG_DEBUG "could not map hotkey id=%04x mask=%04x", key, mask)); + return 0; + } - // remove all input events before and including warp - XEvent event; - while (XCheckMaskEvent(m_display, PointerMotionMask | - ButtonPressMask | ButtonReleaseMask | - KeyPressMask | KeyReleaseMask | - KeymapStateMask, - &event)) { - // do nothing - } + // fail if no keys + if (key == kKeyNone && mask == 0) { + return 0; + } - // save position as last position - m_xCursor = x; - m_yCursor = y; + // convert to X + unsigned int modifiers; + if (!m_keyState->mapModifiersToX(mask, modifiers)) { + // can't map all modifiers + LOG((CLOG_DEBUG "could not map hotkey id=%04x mask=%04x", key, mask)); + return 0; + } + XWindowsKeyState::KeycodeList keycodes; + m_keyState->mapKeyToKeycodes(key, keycodes); + if (key != kKeyNone && keycodes.empty()) { + // can't map key + LOG((CLOG_DEBUG "could not map hotkey id=%04x mask=%04x", key, mask)); + return 0; + } + + // choose hotkey id + UInt32 id; + if (!m_oldHotKeyIDs.empty()) { + id = m_oldHotKeyIDs.back(); + m_oldHotKeyIDs.pop_back(); + } else { + id = m_hotKeys.size() + 1; + } + HotKeyList &hotKeys = m_hotKeys[id]; + + // all modifier hotkey must be treated specially. for each modifier + // we need to grab the modifier key in combination with all the other + // requested modifiers. + bool err = false; + { + XWindowsUtil::ErrorLock lock(m_display, &err); + if (key == kKeyNone) { + static const KeyModifierMask s_hotKeyModifiers[] = { + KeyModifierShift, KeyModifierControl, KeyModifierAlt, KeyModifierMeta, + KeyModifierSuper}; + + XModifierKeymap *modKeymap = XGetModifierMapping(m_display); + for (size_t j = 0; + j < sizeof(s_hotKeyModifiers) / sizeof(s_hotKeyModifiers[0]) && !err; + ++j) { + // skip modifier if not in mask + if ((mask & s_hotKeyModifiers[j]) == 0) { + continue; + } + + // skip with error if we can't map remaining modifiers + unsigned int modifiers2; + KeyModifierMask mask2 = (mask & ~s_hotKeyModifiers[j]); + if (!m_keyState->mapModifiersToX(mask2, modifiers2)) { + err = true; + continue; + } + + // compute modifier index for modifier. there should be + // exactly one X modifier missing + int index; + switch (modifiers ^ modifiers2) { + case ShiftMask: + index = ShiftMapIndex; + break; + + case LockMask: + index = LockMapIndex; + break; + + case ControlMask: + index = ControlMapIndex; + break; + + case Mod1Mask: + index = Mod1MapIndex; + break; + + case Mod2Mask: + index = Mod2MapIndex; + break; + + case Mod3Mask: + index = Mod3MapIndex; + break; + + case Mod4Mask: + index = Mod4MapIndex; + break; + + case Mod5Mask: + index = Mod5MapIndex; + break; + + default: + err = true; + continue; + } + + // grab each key for the modifier + const KeyCode *modifiermap = + modKeymap->modifiermap + index * modKeymap->max_keypermod; + for (int k = 0; k < modKeymap->max_keypermod && !err; ++k) { + KeyCode code = modifiermap[k]; + if (modifiermap[k] != 0) { + XGrabKey(m_display, code, modifiers2, m_root, False, GrabModeAsync, + GrabModeAsync); + if (!err) { + hotKeys.push_back(std::make_pair(code, modifiers2)); + m_hotKeyToIDMap[HotKeyItem(code, modifiers2)] = id; + } + } + } + } + XFreeModifiermap(modKeymap); + } + + // a non-modifier key must be insensitive to CapsLock, NumLock and + // ScrollLock, so we have to grab the key with every combination of + // those. + else { + // collect available toggle modifiers + unsigned int modifier; + unsigned int toggleModifiers[3]; + size_t numToggleModifiers = 0; + if (m_keyState->mapModifiersToX(KeyModifierCapsLock, modifier)) { + toggleModifiers[numToggleModifiers++] = modifier; + } + if (m_keyState->mapModifiersToX(KeyModifierNumLock, modifier)) { + toggleModifiers[numToggleModifiers++] = modifier; + } + if (m_keyState->mapModifiersToX(KeyModifierScrollLock, modifier)) { + toggleModifiers[numToggleModifiers++] = modifier; + } + + for (XWindowsKeyState::KeycodeList::iterator j = keycodes.begin(); + j != keycodes.end() && !err; ++j) { + for (size_t i = 0; i < (1u << numToggleModifiers); ++i) { + // add toggle modifiers for index i + unsigned int tmpModifiers = modifiers; + if ((i & 1) != 0) { + tmpModifiers |= toggleModifiers[0]; + } + if ((i & 2) != 0) { + tmpModifiers |= toggleModifiers[1]; + } + if ((i & 4) != 0) { + tmpModifiers |= toggleModifiers[2]; + } + + // add grab + XGrabKey(m_display, *j, tmpModifiers, m_root, False, GrabModeAsync, + GrabModeAsync); + if (!err) { + hotKeys.push_back(std::make_pair(*j, tmpModifiers)); + m_hotKeyToIDMap[HotKeyItem(*j, tmpModifiers)] = id; + } + } + } + } + } + + if (err) { + // if any failed then unregister any we did get + for (HotKeyList::iterator j = hotKeys.begin(); j != hotKeys.end(); ++j) { + XUngrabKey(m_display, j->first, j->second, m_root); + m_hotKeyToIDMap.erase(HotKeyItem(j->first, j->second)); + } + + m_oldHotKeyIDs.push_back(id); + m_hotKeys.erase(id); + LOG((CLOG_WARN "failed to register hotkey %s (id=%04x mask=%04x)", + synergy::KeyMap::formatKey(key, mask).c_str(), key, mask)); + return 0; + } + + LOG((CLOG_DEBUG "registered hotkey %s (id=%04x mask=%04x) as id=%d", + synergy::KeyMap::formatKey(key, mask).c_str(), key, mask, id)); + return id; } -UInt32 -XWindowsScreen::registerHotKey(KeyID key, KeyModifierMask mask) -{ - // only allow certain modifiers - if ((mask & ~(KeyModifierShift | KeyModifierControl | - KeyModifierAlt | KeyModifierSuper)) != 0) { - LOG((CLOG_DEBUG "could not map hotkey id=%04x mask=%04x", key, mask)); - return 0; - } +void XWindowsScreen::unregisterHotKey(UInt32 id) { + // look up hotkey + HotKeyMap::iterator i = m_hotKeys.find(id); + if (i == m_hotKeys.end()) { + return; + } - // fail if no keys - if (key == kKeyNone && mask == 0) { - return 0; - } + // unregister with OS + bool err = false; + { + XWindowsUtil::ErrorLock lock(m_display, &err); + HotKeyList &hotKeys = i->second; + for (HotKeyList::iterator j = hotKeys.begin(); j != hotKeys.end(); ++j) { + XUngrabKey(m_display, j->first, j->second, m_root); + m_hotKeyToIDMap.erase(HotKeyItem(j->first, j->second)); + } + } + if (err) { + LOG((CLOG_WARN "failed to unregister hotkey id=%d", id)); + } else { + LOG((CLOG_DEBUG "unregistered hotkey id=%d", id)); + } - // convert to X - unsigned int modifiers; - if (!m_keyState->mapModifiersToX(mask, modifiers)) { - // can't map all modifiers - LOG((CLOG_DEBUG "could not map hotkey id=%04x mask=%04x", key, mask)); - return 0; - } - XWindowsKeyState::KeycodeList keycodes; - m_keyState->mapKeyToKeycodes(key, keycodes); - if (key != kKeyNone && keycodes.empty()) { - // can't map key - LOG((CLOG_DEBUG "could not map hotkey id=%04x mask=%04x", key, mask)); - return 0; - } - - // choose hotkey id - UInt32 id; - if (!m_oldHotKeyIDs.empty()) { - id = m_oldHotKeyIDs.back(); - m_oldHotKeyIDs.pop_back(); - } - else { - id = m_hotKeys.size() + 1; - } - HotKeyList& hotKeys = m_hotKeys[id]; - - // all modifier hotkey must be treated specially. for each modifier - // we need to grab the modifier key in combination with all the other - // requested modifiers. - bool err = false; - { - XWindowsUtil::ErrorLock lock(m_display, &err); - if (key == kKeyNone) { - static const KeyModifierMask s_hotKeyModifiers[] = { - KeyModifierShift, - KeyModifierControl, - KeyModifierAlt, - KeyModifierMeta, - KeyModifierSuper - }; - - XModifierKeymap* modKeymap = XGetModifierMapping(m_display); - for (size_t j = 0; j < sizeof(s_hotKeyModifiers) / - sizeof(s_hotKeyModifiers[0]) && !err; ++j) { - // skip modifier if not in mask - if ((mask & s_hotKeyModifiers[j]) == 0) { - continue; - } - - // skip with error if we can't map remaining modifiers - unsigned int modifiers2; - KeyModifierMask mask2 = (mask & ~s_hotKeyModifiers[j]); - if (!m_keyState->mapModifiersToX(mask2, modifiers2)) { - err = true; - continue; - } - - // compute modifier index for modifier. there should be - // exactly one X modifier missing - int index; - switch (modifiers ^ modifiers2) { - case ShiftMask: - index = ShiftMapIndex; - break; - - case LockMask: - index = LockMapIndex; - break; - - case ControlMask: - index = ControlMapIndex; - break; - - case Mod1Mask: - index = Mod1MapIndex; - break; - - case Mod2Mask: - index = Mod2MapIndex; - break; - - case Mod3Mask: - index = Mod3MapIndex; - break; - - case Mod4Mask: - index = Mod4MapIndex; - break; - - case Mod5Mask: - index = Mod5MapIndex; - break; - - default: - err = true; - continue; - } - - // grab each key for the modifier - const KeyCode* modifiermap = - modKeymap->modifiermap + index * modKeymap->max_keypermod; - for (int k = 0; k < modKeymap->max_keypermod && !err; ++k) { - KeyCode code = modifiermap[k]; - if (modifiermap[k] != 0) { - XGrabKey(m_display, code, modifiers2, m_root, - False, GrabModeAsync, GrabModeAsync); - if (!err) { - hotKeys.push_back(std::make_pair(code, modifiers2)); - m_hotKeyToIDMap[HotKeyItem(code, modifiers2)] = id; - } - } - } - } - XFreeModifiermap(modKeymap); - } - - // a non-modifier key must be insensitive to CapsLock, NumLock and - // ScrollLock, so we have to grab the key with every combination of - // those. - else { - // collect available toggle modifiers - unsigned int modifier; - unsigned int toggleModifiers[3]; - size_t numToggleModifiers = 0; - if (m_keyState->mapModifiersToX(KeyModifierCapsLock, modifier)) { - toggleModifiers[numToggleModifiers++] = modifier; - } - if (m_keyState->mapModifiersToX(KeyModifierNumLock, modifier)) { - toggleModifiers[numToggleModifiers++] = modifier; - } - if (m_keyState->mapModifiersToX(KeyModifierScrollLock, modifier)) { - toggleModifiers[numToggleModifiers++] = modifier; - } - - - for (XWindowsKeyState::KeycodeList::iterator j = keycodes.begin(); - j != keycodes.end() && !err; ++j) { - for (size_t i = 0; i < (1u << numToggleModifiers); ++i) { - // add toggle modifiers for index i - unsigned int tmpModifiers = modifiers; - if ((i & 1) != 0) { - tmpModifiers |= toggleModifiers[0]; - } - if ((i & 2) != 0) { - tmpModifiers |= toggleModifiers[1]; - } - if ((i & 4) != 0) { - tmpModifiers |= toggleModifiers[2]; - } - - // add grab - XGrabKey(m_display, *j, tmpModifiers, m_root, - False, GrabModeAsync, GrabModeAsync); - if (!err) { - hotKeys.push_back(std::make_pair(*j, tmpModifiers)); - m_hotKeyToIDMap[HotKeyItem(*j, tmpModifiers)] = id; - } - } - } - } - } - - if (err) { - // if any failed then unregister any we did get - for (HotKeyList::iterator j = hotKeys.begin(); - j != hotKeys.end(); ++j) { - XUngrabKey(m_display, j->first, j->second, m_root); - m_hotKeyToIDMap.erase(HotKeyItem(j->first, j->second)); - } - - m_oldHotKeyIDs.push_back(id); - m_hotKeys.erase(id); - LOG((CLOG_WARN "failed to register hotkey %s (id=%04x mask=%04x)", synergy::KeyMap::formatKey(key, mask).c_str(), key, mask)); - return 0; - } - - LOG((CLOG_DEBUG "registered hotkey %s (id=%04x mask=%04x) as id=%d", synergy::KeyMap::formatKey(key, mask).c_str(), key, mask, id)); - return id; + // discard hot key from map and record old id for reuse + m_hotKeys.erase(i); + m_oldHotKeyIDs.push_back(id); } -void -XWindowsScreen::unregisterHotKey(UInt32 id) -{ - // look up hotkey - HotKeyMap::iterator i = m_hotKeys.find(id); - if (i == m_hotKeys.end()) { - return; - } - - // unregister with OS - bool err = false; - { - XWindowsUtil::ErrorLock lock(m_display, &err); - HotKeyList& hotKeys = i->second; - for (HotKeyList::iterator j = hotKeys.begin(); - j != hotKeys.end(); ++j) { - XUngrabKey(m_display, j->first, j->second, m_root); - m_hotKeyToIDMap.erase(HotKeyItem(j->first, j->second)); - } - } - if (err) { - LOG((CLOG_WARN "failed to unregister hotkey id=%d", id)); - } - else { - LOG((CLOG_DEBUG "unregistered hotkey id=%d", id)); - } - - // discard hot key from map and record old id for reuse - m_hotKeys.erase(i); - m_oldHotKeyIDs.push_back(id); +void XWindowsScreen::fakeInputBegin() { + // FIXME -- not implemented } -void -XWindowsScreen::fakeInputBegin() -{ - // FIXME -- not implemented +void XWindowsScreen::fakeInputEnd() { + // FIXME -- not implemented } -void -XWindowsScreen::fakeInputEnd() -{ - // FIXME -- not implemented +SInt32 XWindowsScreen::getJumpZoneSize() const { return 1; } + +bool XWindowsScreen::isAnyMouseButtonDown(UInt32 &buttonID) const { + // query the pointer to get the button state + Window root, window; + int xRoot, yRoot, xWindow, yWindow; + unsigned int state; + if (XQueryPointer(m_display, m_root, &root, &window, &xRoot, &yRoot, &xWindow, + &yWindow, &state)) { + return ((state & (Button1Mask | Button2Mask | Button3Mask | Button4Mask | + Button5Mask)) != 0); + } + + return false; } -SInt32 -XWindowsScreen::getJumpZoneSize() const -{ - return 1; +void XWindowsScreen::getCursorCenter(SInt32 &x, SInt32 &y) const { + x = m_xCenter; + y = m_yCenter; } -bool -XWindowsScreen::isAnyMouseButtonDown(UInt32& buttonID) const -{ - // query the pointer to get the button state - Window root, window; - int xRoot, yRoot, xWindow, yWindow; - unsigned int state; - if (XQueryPointer(m_display, m_root, &root, &window, - &xRoot, &yRoot, &xWindow, &yWindow, &state)) { - return ((state & (Button1Mask | Button2Mask | Button3Mask | - Button4Mask | Button5Mask)) != 0); - } - - return false; +void XWindowsScreen::fakeMouseButton(ButtonID button, bool press) { + const unsigned int xButton = mapButtonToX(button); + if (xButton > 0 && xButton < 11) { + XTestFakeButtonEvent(m_display, xButton, press ? True : False, CurrentTime); + XFlush(m_display); + } } -void -XWindowsScreen::getCursorCenter(SInt32& x, SInt32& y) const -{ - x = m_xCenter; - y = m_yCenter; +void XWindowsScreen::fakeMouseMove(SInt32 x, SInt32 y) { + if (m_xinerama && m_xtestIsXineramaUnaware) { + XWarpPointer(m_display, None, m_root, 0, 0, 0, 0, x, y); + } else { + XTestFakeMotionEvent(m_display, DefaultScreen(m_display), x, y, + CurrentTime); + } + XFlush(m_display); } -void -XWindowsScreen::fakeMouseButton(ButtonID button, bool press) -{ - const unsigned int xButton = mapButtonToX(button); - if (xButton > 0 && xButton < 11) { - XTestFakeButtonEvent(m_display, xButton, - press ? True : False, CurrentTime); - XFlush(m_display); - } +void XWindowsScreen::fakeMouseRelativeMove(SInt32 dx, SInt32 dy) const { + // FIXME -- ignore xinerama for now + XTestFakeRelativeMotionEvent(m_display, dx, dy, CurrentTime); + XFlush(m_display); } -void -XWindowsScreen::fakeMouseMove(SInt32 x, SInt32 y) -{ - if (m_xinerama && m_xtestIsXineramaUnaware) { - XWarpPointer(m_display, None, m_root, 0, 0, 0, 0, x, y); - } - else { - XTestFakeMotionEvent(m_display, DefaultScreen(m_display), - x, y, CurrentTime); - } - XFlush(m_display); +void XWindowsScreen::fakeMouseWheel(SInt32, SInt32 yDelta) const { + // XXX -- support x-axis scrolling + if (yDelta == 0) { + return; + } + + yDelta = mapClientScrollDirection(yDelta); + + // choose button depending on rotation direction + const unsigned int xButton = + mapButtonToX(static_cast((yDelta >= 0) ? -1 : -2)); + if (xButton == 0) { + // If we get here, then the XServer does not support the scroll + // wheel buttons, so send PageUp/PageDown keystrokes instead. + // Patch by Tom Chadwick. + KeyCode keycode = 0; + if (yDelta >= 0) { + keycode = XKeysymToKeycode(m_display, XK_Page_Up); + } else { + keycode = XKeysymToKeycode(m_display, XK_Page_Down); + } + if (keycode != 0) { + XTestFakeKeyEvent(m_display, keycode, True, CurrentTime); + XTestFakeKeyEvent(m_display, keycode, False, CurrentTime); + } + return; + } + + // now use absolute value of delta + if (yDelta < 0) { + yDelta = -yDelta; + } + + if (yDelta < m_mouseScrollDelta) { + LOG((CLOG_WARN "wheel scroll delta (%d) smaller than threshold (%d)", + yDelta, m_mouseScrollDelta)); + } + + // send as many clicks as necessary + for (; yDelta >= m_mouseScrollDelta; yDelta -= m_mouseScrollDelta) { + XTestFakeButtonEvent(m_display, xButton, True, CurrentTime); + XTestFakeButtonEvent(m_display, xButton, False, CurrentTime); + } + XFlush(m_display); } -void -XWindowsScreen::fakeMouseRelativeMove(SInt32 dx, SInt32 dy) const -{ - // FIXME -- ignore xinerama for now - XTestFakeRelativeMotionEvent(m_display, dx, dy, CurrentTime); - XFlush(m_display); -} +Display *XWindowsScreen::openDisplay(const char *displayName) { + // get the DISPLAY + if (displayName == NULL) { + displayName = getenv("DISPLAY"); + if (displayName == NULL) { + displayName = ":0.0"; + } + } -void -XWindowsScreen::fakeMouseWheel(SInt32, SInt32 yDelta) const -{ - // XXX -- support x-axis scrolling - if (yDelta == 0) { - return; - } + // open the display + LOG((CLOG_DEBUG3 "calling XOpenDisplay(\"%s\")", displayName)); + Display *display = XOpenDisplay(displayName); + if (display == NULL) { + throw XScreenUnavailable(60.0); + } - yDelta = mapClientScrollDirection(yDelta); - - // choose button depending on rotation direction - const unsigned int xButton = mapButtonToX(static_cast( - (yDelta >= 0) ? -1 : -2)); - if (xButton == 0) { - // If we get here, then the XServer does not support the scroll - // wheel buttons, so send PageUp/PageDown keystrokes instead. - // Patch by Tom Chadwick. - KeyCode keycode = 0; - if (yDelta >= 0) { - keycode = XKeysymToKeycode(m_display, XK_Page_Up); - } - else { - keycode = XKeysymToKeycode(m_display, XK_Page_Down); - } - if (keycode != 0) { - XTestFakeKeyEvent(m_display, keycode, True, CurrentTime); - XTestFakeKeyEvent(m_display, keycode, False, CurrentTime); - } - return; - } - - // now use absolute value of delta - if (yDelta < 0) { - yDelta = -yDelta; - } - - if (yDelta < m_mouseScrollDelta) { - LOG((CLOG_WARN "wheel scroll delta (%d) smaller than threshold (%d)", yDelta, m_mouseScrollDelta)); - } - - // send as many clicks as necessary - for (; yDelta >= m_mouseScrollDelta; yDelta -= m_mouseScrollDelta) { - XTestFakeButtonEvent(m_display, xButton, True, CurrentTime); - XTestFakeButtonEvent(m_display, xButton, False, CurrentTime); - } - XFlush(m_display); -} - -Display* -XWindowsScreen::openDisplay(const char* displayName) -{ - // get the DISPLAY - if (displayName == NULL) { - displayName = getenv("DISPLAY"); - if (displayName == NULL) { - displayName = ":0.0"; - } - } - - // open the display - LOG((CLOG_DEBUG3 "calling XOpenDisplay(\"%s\")", displayName)); - Display* display = XOpenDisplay(displayName); - if (display == NULL) { - throw XScreenUnavailable(60.0); - } - - // verify the availability of the XTest extension - if (!m_isPrimary) { - int majorOpcode, firstEvent, firstError; - if (!XQueryExtension(display, XTestExtensionName, - &majorOpcode, &firstEvent, &firstError)) { - LOG((CLOG_ERR "the XTest extension is not available")); - XCloseDisplay(display); - throw XScreenOpenFailure(); - } - } + // verify the availability of the XTest extension + if (!m_isPrimary) { + int majorOpcode, firstEvent, firstError; + if (!XQueryExtension(display, XTestExtensionName, &majorOpcode, &firstEvent, + &firstError)) { + LOG((CLOG_ERR "the XTest extension is not available")); + XCloseDisplay(display); + throw XScreenOpenFailure(); + } + } #if HAVE_XKB_EXTENSION - { - m_xkb = false; - int major = XkbMajorVersion, minor = XkbMinorVersion; - if (XkbLibraryVersion(&major, &minor)) { - int opcode, firstError; - if (XkbQueryExtension(display, &opcode, &m_xkbEventBase, - &firstError, &major, &minor)) { - m_xkb = true; - XkbSelectEvents(display, XkbUseCoreKbd, - XkbMapNotifyMask, XkbMapNotifyMask); - XkbSelectEventDetails(display, XkbUseCoreKbd, - XkbStateNotifyMask, - XkbGroupStateMask, XkbGroupStateMask); - } - } - } + { + m_xkb = false; + int major = XkbMajorVersion, minor = XkbMinorVersion; + if (XkbLibraryVersion(&major, &minor)) { + int opcode, firstError; + if (XkbQueryExtension(display, &opcode, &m_xkbEventBase, &firstError, + &major, &minor)) { + m_xkb = true; + XkbSelectEvents(display, XkbUseCoreKbd, XkbMapNotifyMask, + XkbMapNotifyMask); + XkbSelectEventDetails(display, XkbUseCoreKbd, XkbStateNotifyMask, + XkbGroupStateMask, XkbGroupStateMask); + } + } + } #endif #if HAVE_X11_EXTENSIONS_XRANDR_H - // query for XRandR extension - int dummyError; - m_xrandr = XRRQueryExtension(display, &m_xrandrEventBase, &dummyError); - if (m_xrandr) { - // enable XRRScreenChangeNotifyEvent - XRRSelectInput(display, DefaultRootWindow(display), RRScreenChangeNotifyMask | RRCrtcChangeNotifyMask); - } + // query for XRandR extension + int dummyError; + m_xrandr = XRRQueryExtension(display, &m_xrandrEventBase, &dummyError); + if (m_xrandr) { + // enable XRRScreenChangeNotifyEvent + XRRSelectInput(display, DefaultRootWindow(display), + RRScreenChangeNotifyMask | RRCrtcChangeNotifyMask); + } #endif - return display; + return display; } -void -XWindowsScreen::saveShape() -{ - // get shape of default screen - m_x = 0; - m_y = 0; +void XWindowsScreen::saveShape() { + // get shape of default screen + m_x = 0; + m_y = 0; - m_w = WidthOfScreen(DefaultScreenOfDisplay(m_display)); - m_h = HeightOfScreen(DefaultScreenOfDisplay(m_display)); + m_w = WidthOfScreen(DefaultScreenOfDisplay(m_display)); + m_h = HeightOfScreen(DefaultScreenOfDisplay(m_display)); - // get center of default screen - m_xCenter = m_x + (m_w >> 1); - m_yCenter = m_y + (m_h >> 1); + // get center of default screen + m_xCenter = m_x + (m_w >> 1); + m_yCenter = m_y + (m_h >> 1); - // check if xinerama is enabled and there is more than one screen. - // get center of first Xinerama screen. Xinerama appears to have - // a bug when XWarpPointer() is used in combination with - // XGrabPointer(). in that case, the warp is successful but the - // next pointer motion warps the pointer again, apparently to - // constrain it to some unknown region, possibly the region from - // 0,0 to Wm,Hm where Wm (Hm) is the minimum width (height) over - // all physical screens. this warp only seems to happen if the - // pointer wasn't in that region before the XWarpPointer(). the - // second (unexpected) warp causes synergy to think the pointer - // has been moved when it hasn't. to work around the problem, - // we warp the pointer to the center of the first physical - // screen instead of the logical screen. - m_xinerama = false; + // check if xinerama is enabled and there is more than one screen. + // get center of first Xinerama screen. Xinerama appears to have + // a bug when XWarpPointer() is used in combination with + // XGrabPointer(). in that case, the warp is successful but the + // next pointer motion warps the pointer again, apparently to + // constrain it to some unknown region, possibly the region from + // 0,0 to Wm,Hm where Wm (Hm) is the minimum width (height) over + // all physical screens. this warp only seems to happen if the + // pointer wasn't in that region before the XWarpPointer(). the + // second (unexpected) warp causes synergy to think the pointer + // has been moved when it hasn't. to work around the problem, + // we warp the pointer to the center of the first physical + // screen instead of the logical screen. + m_xinerama = false; #if HAVE_X11_EXTENSIONS_XINERAMA_H - int eventBase, errorBase; - if (XineramaQueryExtension(m_display, &eventBase, &errorBase) && - XineramaIsActive(m_display)) { - int numScreens; - XineramaScreenInfo* screens; - screens = XineramaQueryScreens(m_display, &numScreens); - if (screens != NULL) { - if (numScreens > 1) { - m_xinerama = true; - m_xCenter = screens[0].x_org + (screens[0].width >> 1); - m_yCenter = screens[0].y_org + (screens[0].height >> 1); - } - XFree(screens); - } - } + int eventBase, errorBase; + if (XineramaQueryExtension(m_display, &eventBase, &errorBase) && + XineramaIsActive(m_display)) { + int numScreens; + XineramaScreenInfo *screens; + screens = XineramaQueryScreens(m_display, &numScreens); + if (screens != NULL) { + if (numScreens > 1) { + m_xinerama = true; + m_xCenter = screens[0].x_org + (screens[0].width >> 1); + m_yCenter = screens[0].y_org + (screens[0].height >> 1); + } + XFree(screens); + } + } #endif } -void -XWindowsScreen::setShape(SInt32 width, SInt32 height) -{ - // set shape - m_x = 0; - m_y = 0; +void XWindowsScreen::setShape(SInt32 width, SInt32 height) { + // set shape + m_x = 0; + m_y = 0; - m_w = width; - m_h = height; + m_w = width; + m_h = height; - // get center of default screen - m_xCenter = m_x + (m_w >> 1); - m_yCenter = m_y + (m_h >> 1); + // get center of default screen + m_xCenter = m_x + (m_w >> 1); + m_yCenter = m_y + (m_h >> 1); - // check if xinerama is enabled and there is more than one screen. - // get center of first Xinerama screen. Xinerama appears to have - // a bug when XWarpPointer() is used in combination with - // XGrabPointer(). in that case, the warp is successful but the - // next pointer motion warps the pointer again, apparently to - // constrain it to some unknown region, possibly the region from - // 0,0 to Wm,Hm where Wm (Hm) is the minimum width (height) over - // all physical screens. this warp only seems to happen if the - // pointer wasn't in that region before the XWarpPointer(). the - // second (unexpected) warp causes synergy to think the pointer - // has been moved when it hasn't. to work around the problem, - // we warp the pointer to the center of the first physical - // screen instead of the logical screen. - m_xinerama = false; + // check if xinerama is enabled and there is more than one screen. + // get center of first Xinerama screen. Xinerama appears to have + // a bug when XWarpPointer() is used in combination with + // XGrabPointer(). in that case, the warp is successful but the + // next pointer motion warps the pointer again, apparently to + // constrain it to some unknown region, possibly the region from + // 0,0 to Wm,Hm where Wm (Hm) is the minimum width (height) over + // all physical screens. this warp only seems to happen if the + // pointer wasn't in that region before the XWarpPointer(). the + // second (unexpected) warp causes synergy to think the pointer + // has been moved when it hasn't. to work around the problem, + // we warp the pointer to the center of the first physical + // screen instead of the logical screen. + m_xinerama = false; #if HAVE_X11_EXTENSIONS_XINERAMA_H - int eventBase, errorBase; - if ((XineramaQueryExtension(m_display, &eventBase, &errorBase) != 0) && - (XineramaIsActive(m_display) != 0)) { - int numScreens; - XineramaScreenInfo* screens; - screens = XineramaQueryScreens(m_display, &numScreens); - if (screens != nullptr) { - if (numScreens > 1) { - m_xinerama = true; - m_xCenter = screens[0].x_org + (screens[0].width >> 1); - m_yCenter = screens[0].y_org + (screens[0].height >> 1); - } - XFree(screens); - } - } + int eventBase, errorBase; + if ((XineramaQueryExtension(m_display, &eventBase, &errorBase) != 0) && + (XineramaIsActive(m_display) != 0)) { + int numScreens; + XineramaScreenInfo *screens; + screens = XineramaQueryScreens(m_display, &numScreens); + if (screens != nullptr) { + if (numScreens > 1) { + m_xinerama = true; + m_xCenter = screens[0].x_org + (screens[0].width >> 1); + m_yCenter = screens[0].y_org + (screens[0].height >> 1); + } + XFree(screens); + } + } #endif } -Window -XWindowsScreen::openWindow() const -{ - // default window attributes. we don't want the window manager - // messing with our window and we don't want the cursor to be - // visible inside the window. - XSetWindowAttributes attr; - attr.do_not_propagate_mask = 0; - attr.override_redirect = True; - attr.cursor = createBlankCursor(); +Window XWindowsScreen::openWindow() const { + // default window attributes. we don't want the window manager + // messing with our window and we don't want the cursor to be + // visible inside the window. + XSetWindowAttributes attr; + attr.do_not_propagate_mask = 0; + attr.override_redirect = True; + attr.cursor = createBlankCursor(); - // adjust attributes and get size and shape - SInt32 x, y, w, h; - if (m_isPrimary) { - // grab window attributes. this window is used to capture user - // input when the user is focused on another client. it covers - // the whole screen. - attr.event_mask = PointerMotionMask | - ButtonPressMask | ButtonReleaseMask | - KeyPressMask | KeyReleaseMask | - KeymapStateMask | PropertyChangeMask; - x = m_x; - y = m_y; - w = m_w; - h = m_h; - } - else { - // cursor hider window attributes. this window is used to hide the - // cursor when it's not on the screen. the window is hidden as soon - // as the cursor enters the screen or the display's real mouse is - // moved. we'll reposition the window as necessary so its - // position here doesn't matter. it only needs to be 1x1 because - // it only needs to contain the cursor's hotspot. - attr.event_mask = LeaveWindowMask; - x = 0; - y = 0; - w = 1; - h = 1; - } + // adjust attributes and get size and shape + SInt32 x, y, w, h; + if (m_isPrimary) { + // grab window attributes. this window is used to capture user + // input when the user is focused on another client. it covers + // the whole screen. + attr.event_mask = PointerMotionMask | ButtonPressMask | ButtonReleaseMask | + KeyPressMask | KeyReleaseMask | KeymapStateMask | + PropertyChangeMask; + x = m_x; + y = m_y; + w = m_w; + h = m_h; + } else { + // cursor hider window attributes. this window is used to hide the + // cursor when it's not on the screen. the window is hidden as soon + // as the cursor enters the screen or the display's real mouse is + // moved. we'll reposition the window as necessary so its + // position here doesn't matter. it only needs to be 1x1 because + // it only needs to contain the cursor's hotspot. + attr.event_mask = LeaveWindowMask; + x = 0; + y = 0; + w = 1; + h = 1; + } - // create and return the window - Window window = XCreateWindow(m_display, m_root, x, y, w, h, 0, 0, - InputOnly, CopyFromParent, - CWDontPropagate | CWEventMask | - CWOverrideRedirect | CWCursor, - &attr); - if (window == None) { - throw XScreenOpenFailure(); - } - return window; + // create and return the window + Window window = XCreateWindow( + m_display, m_root, x, y, w, h, 0, 0, InputOnly, CopyFromParent, + CWDontPropagate | CWEventMask | CWOverrideRedirect | CWCursor, &attr); + if (window == None) { + throw XScreenOpenFailure(); + } + return window; } -void -XWindowsScreen::openIM() -{ - // open the input methods - XIM im = XOpenIM(m_display, NULL, NULL, NULL); - if (im == NULL) { - LOG((CLOG_INFO "no support for IM")); - return; - } +void XWindowsScreen::openIM() { + // open the input methods + XIM im = XOpenIM(m_display, NULL, NULL, NULL); + if (im == NULL) { + LOG((CLOG_INFO "no support for IM")); + return; + } - // find the appropriate style. synergy supports XIMPreeditNothing - // only at the moment. - XIMStyles* styles; - if (XGetIMValues(im, XNQueryInputStyle, &styles, NULL) != NULL || - styles == NULL) { - LOG((CLOG_WARN "cannot get IM styles")); - XCloseIM(im); - return; - } - XIMStyle style = 0; - for (unsigned short i = 0; i < styles->count_styles; ++i) { - style = styles->supported_styles[i]; - if ((style & XIMPreeditNothing) != 0) { - if ((style & (XIMStatusNothing | XIMStatusNone)) != 0) { - break; - } - } - } - XFree(styles); - if (style == 0) { - LOG((CLOG_INFO "no supported IM styles")); - XCloseIM(im); - return; - } + // find the appropriate style. synergy supports XIMPreeditNothing + // only at the moment. + XIMStyles *styles; + if (XGetIMValues(im, XNQueryInputStyle, &styles, NULL) != NULL || + styles == NULL) { + LOG((CLOG_WARN "cannot get IM styles")); + XCloseIM(im); + return; + } + XIMStyle style = 0; + for (unsigned short i = 0; i < styles->count_styles; ++i) { + style = styles->supported_styles[i]; + if ((style & XIMPreeditNothing) != 0) { + if ((style & (XIMStatusNothing | XIMStatusNone)) != 0) { + break; + } + } + } + XFree(styles); + if (style == 0) { + LOG((CLOG_INFO "no supported IM styles")); + XCloseIM(im); + return; + } - // create an input context for the style and tell it about our window - XIC ic = XCreateIC(im, XNInputStyle, style, XNClientWindow, m_window, NULL); - if (ic == NULL) { - LOG((CLOG_WARN "cannot create IC")); - XCloseIM(im); - return; - } + // create an input context for the style and tell it about our window + XIC ic = XCreateIC(im, XNInputStyle, style, XNClientWindow, m_window, NULL); + if (ic == NULL) { + LOG((CLOG_WARN "cannot create IC")); + XCloseIM(im); + return; + } - // find out the events we must select for and do so - unsigned long mask; - if (XGetICValues(ic, XNFilterEvents, &mask, NULL) != NULL) { - LOG((CLOG_WARN "cannot get IC filter events")); - XDestroyIC(ic); - XCloseIM(im); - return; - } + // find out the events we must select for and do so + unsigned long mask; + if (XGetICValues(ic, XNFilterEvents, &mask, NULL) != NULL) { + LOG((CLOG_WARN "cannot get IC filter events")); + XDestroyIC(ic); + XCloseIM(im); + return; + } - // we have IM - m_im = im; - m_ic = ic; - m_lastKeycode = 0; + // we have IM + m_im = im; + m_ic = ic; + m_lastKeycode = 0; - // select events on our window that IM requires - XWindowAttributes attr; - XGetWindowAttributes(m_display, m_window, &attr); - XSelectInput(m_display, m_window, attr.your_event_mask | mask); + // select events on our window that IM requires + XWindowAttributes attr; + XGetWindowAttributes(m_display, m_window, &attr); + XSelectInput(m_display, m_window, attr.your_event_mask | mask); - // listen for screen-resize messages - XSelectInput (m_display, m_root, StructureNotifyMask); + // listen for screen-resize messages + XSelectInput(m_display, m_root, StructureNotifyMask); } -void -XWindowsScreen::sendEvent(Event::Type type, void* data) -{ - m_events->addEvent(Event(type, getEventTarget(), data)); +void XWindowsScreen::sendEvent(Event::Type type, void *data) { + m_events->addEvent(Event(type, getEventTarget(), data)); } -void -XWindowsScreen::sendClipboardEvent(Event::Type type, ClipboardID id) -{ - ClipboardInfo* info = (ClipboardInfo*)malloc(sizeof(ClipboardInfo)); - info->m_id = id; - info->m_sequenceNumber = m_sequenceNumber; - sendEvent(type, info); +void XWindowsScreen::sendClipboardEvent(Event::Type type, ClipboardID id) { + ClipboardInfo *info = (ClipboardInfo *)malloc(sizeof(ClipboardInfo)); + info->m_id = id; + info->m_sequenceNumber = m_sequenceNumber; + sendEvent(type, info); } -IKeyState* -XWindowsScreen::getKeyState() const -{ - return m_keyState; +IKeyState *XWindowsScreen::getKeyState() const { return m_keyState; } + +Bool XWindowsScreen::findKeyEvent(Display *, XEvent *xevent, XPointer arg) { + KeyEventFilter *filter = reinterpret_cast(arg); + return (xevent->type == filter->m_event && + xevent->xkey.window == filter->m_window && + xevent->xkey.time == filter->m_time && + xevent->xkey.keycode == filter->m_keycode) + ? True + : False; } -Bool -XWindowsScreen::findKeyEvent(Display*, XEvent* xevent, XPointer arg) -{ - KeyEventFilter* filter = reinterpret_cast(arg); - return (xevent->type == filter->m_event && - xevent->xkey.window == filter->m_window && - xevent->xkey.time == filter->m_time && - xevent->xkey.keycode == filter->m_keycode) ? True : False; -} +void XWindowsScreen::handleSystemEvent(const Event &event, void *) { + XEvent *xevent = static_cast(event.getData()); + assert(xevent != NULL); -void -XWindowsScreen::handleSystemEvent(const Event& event, void*) -{ - XEvent* xevent = static_cast(event.getData()); - assert(xevent != NULL); + // update key state + bool isRepeat = false; + if (m_isPrimary) { + if (xevent->type == KeyRelease) { + // check if this is a key repeat by getting the next + // KeyPress event that has the same key and time as + // this release event, if any. first prepare the + // filter info. + KeyEventFilter filter; + filter.m_event = KeyPress; + filter.m_window = xevent->xkey.window; + filter.m_time = xevent->xkey.time; + filter.m_keycode = xevent->xkey.keycode; + XEvent xevent2; + isRepeat = + (XCheckIfEvent(m_display, &xevent2, &XWindowsScreen::findKeyEvent, + (XPointer)&filter) == True); + } - // update key state - bool isRepeat = false; - if (m_isPrimary) { - if (xevent->type == KeyRelease) { - // check if this is a key repeat by getting the next - // KeyPress event that has the same key and time as - // this release event, if any. first prepare the - // filter info. - KeyEventFilter filter; - filter.m_event = KeyPress; - filter.m_window = xevent->xkey.window; - filter.m_time = xevent->xkey.time; - filter.m_keycode = xevent->xkey.keycode; - XEvent xevent2; - isRepeat = (XCheckIfEvent(m_display, &xevent2, - &XWindowsScreen::findKeyEvent, - (XPointer)&filter) == True); - } + if (xevent->type == KeyPress || xevent->type == KeyRelease) { + if (xevent->xkey.window == m_root) { + // this is a hot key + onHotKey(xevent->xkey, isRepeat); + return; + } else if (!m_isOnScreen) { + // this might be a hot key + if (onHotKey(xevent->xkey, isRepeat)) { + return; + } + } - if (xevent->type == KeyPress || xevent->type == KeyRelease) { - if (xevent->xkey.window == m_root) { - // this is a hot key - onHotKey(xevent->xkey, isRepeat); - return; - } - else if (!m_isOnScreen) { - // this might be a hot key - if (onHotKey(xevent->xkey, isRepeat)) { - return; - } - } + bool down = (isRepeat || xevent->type == KeyPress); + KeyModifierMask state = m_keyState->mapModifiersFromX(xevent->xkey.state); + m_keyState->onKey(xevent->xkey.keycode, down, state); + } + } - bool down = (isRepeat || xevent->type == KeyPress); - KeyModifierMask state = - m_keyState->mapModifiersFromX(xevent->xkey.state); - m_keyState->onKey(xevent->xkey.keycode, down, state); - } - } + // let input methods try to handle event first + if (m_ic != NULL) { + // XFilterEvent() may eat the event and generate a new KeyPress + // event with a keycode of 0 because there isn't an actual key + // associated with the keysym. but the KeyRelease may pass + // through XFilterEvent() and keep its keycode. this means + // there's a mismatch between KeyPress and KeyRelease keycodes. + // since we use the keycode on the client to detect when a key + // is released this won't do. so we remember the keycode on + // the most recent KeyPress (and clear it on a matching + // KeyRelease) so we have a keycode for a synthesized KeyPress. + if (xevent->type == KeyPress && xevent->xkey.keycode != 0) { + m_lastKeycode = xevent->xkey.keycode; + } else if (xevent->type == KeyRelease && + xevent->xkey.keycode == m_lastKeycode) { + m_lastKeycode = 0; + } - // let input methods try to handle event first - if (m_ic != NULL) { - // XFilterEvent() may eat the event and generate a new KeyPress - // event with a keycode of 0 because there isn't an actual key - // associated with the keysym. but the KeyRelease may pass - // through XFilterEvent() and keep its keycode. this means - // there's a mismatch between KeyPress and KeyRelease keycodes. - // since we use the keycode on the client to detect when a key - // is released this won't do. so we remember the keycode on - // the most recent KeyPress (and clear it on a matching - // KeyRelease) so we have a keycode for a synthesized KeyPress. - if (xevent->type == KeyPress && xevent->xkey.keycode != 0) { - m_lastKeycode = xevent->xkey.keycode; - } - else if (xevent->type == KeyRelease && - xevent->xkey.keycode == m_lastKeycode) { - m_lastKeycode = 0; - } + // now filter the event + if (XFilterEvent(xevent, DefaultRootWindow(m_display))) { + if (xevent->type == KeyPress) { + // add filtered presses to the filtered list + m_filtered.insert(m_lastKeycode); + } + return; + } - // now filter the event - if (XFilterEvent(xevent, DefaultRootWindow(m_display))) { - if (xevent->type == KeyPress) { - // add filtered presses to the filtered list - m_filtered.insert(m_lastKeycode); - } - return; - } + // discard matching key releases for key presses that were + // filtered and remove them from our filtered list. + else if (xevent->type == KeyRelease && + m_filtered.count(xevent->xkey.keycode) > 0) { + m_filtered.erase(xevent->xkey.keycode); + return; + } + } - // discard matching key releases for key presses that were - // filtered and remove them from our filtered list. - else if (xevent->type == KeyRelease && - m_filtered.count(xevent->xkey.keycode) > 0) { - m_filtered.erase(xevent->xkey.keycode); - return; - } - } - - // let screen saver have a go - if (m_screensaver->handleXEvent(xevent)) { - // screen saver handled it - return; - } + // let screen saver have a go + if (m_screensaver->handleXEvent(xevent)) { + // screen saver handled it + return; + } #ifdef HAVE_XI2 - if (m_xi2detected) { - // Process RawMotion - XGenericEventCookie *cookie = (XGenericEventCookie*)&xevent->xcookie; - if (XGetEventData(m_display, cookie) && - cookie->type == GenericEvent && - cookie->extension == xi_opcode) { - if (cookie->evtype == XI_RawMotion) { - // Get current pointer's position - Window root, child; - XMotionEvent xmotion; - xmotion.type = MotionNotify; - xmotion.send_event = False; // Raw motion - xmotion.display = m_display; - xmotion.window = m_window; - /* xmotion's time, state and is_hint are not used */ - unsigned int msk; - xmotion.same_screen = XQueryPointer( - m_display, m_root, &xmotion.root, &xmotion.subwindow, - &xmotion.x_root, - &xmotion.y_root, - &xmotion.x, - &xmotion.y, - &msk); - onMouseMove(xmotion); - XFreeEventData(m_display, cookie); - return; - } - XFreeEventData(m_display, cookie); - } - } + if (m_xi2detected) { + // Process RawMotion + XGenericEventCookie *cookie = (XGenericEventCookie *)&xevent->xcookie; + if (XGetEventData(m_display, cookie) && cookie->type == GenericEvent && + cookie->extension == xi_opcode) { + if (cookie->evtype == XI_RawMotion) { + // Get current pointer's position + Window root, child; + XMotionEvent xmotion; + xmotion.type = MotionNotify; + xmotion.send_event = False; // Raw motion + xmotion.display = m_display; + xmotion.window = m_window; + /* xmotion's time, state and is_hint are not used */ + unsigned int msk; + xmotion.same_screen = XQueryPointer( + m_display, m_root, &xmotion.root, &xmotion.subwindow, + &xmotion.x_root, &xmotion.y_root, &xmotion.x, &xmotion.y, &msk); + onMouseMove(xmotion); + XFreeEventData(m_display, cookie); + return; + } + XFreeEventData(m_display, cookie); + } + } #endif - // handle the event ourself - switch (xevent->type) { - case CreateNotify: - if (m_isPrimary && !m_xi2detected) { - // select events on new window - selectEvents(xevent->xcreatewindow.window); - } - break; + // handle the event ourself + switch (xevent->type) { + case CreateNotify: + if (m_isPrimary && !m_xi2detected) { + // select events on new window + selectEvents(xevent->xcreatewindow.window); + } + break; - case MappingNotify: - refreshKeyboard(xevent); - break; + case MappingNotify: + refreshKeyboard(xevent); + break; - case LeaveNotify: - if (!m_isPrimary) { - // mouse moved out of hider window somehow. hide the window. - XUnmapWindow(m_display, m_window); - } - break; + case LeaveNotify: + if (!m_isPrimary) { + // mouse moved out of hider window somehow. hide the window. + XUnmapWindow(m_display, m_window); + } + break; - case SelectionClear: - { - // we just lost the selection. that means someone else - // grabbed the selection so this screen is now the - // selection owner. report that to the receiver. - ClipboardID id = getClipboardID(xevent->xselectionclear.selection); - if (id != kClipboardEnd) { - m_clipboard[id]->lost(xevent->xselectionclear.time); - sendClipboardEvent(m_events->forClipboard().clipboardGrabbed(), id); - return; - } - } - break; + case SelectionClear: { + // we just lost the selection. that means someone else + // grabbed the selection so this screen is now the + // selection owner. report that to the receiver. + ClipboardID id = getClipboardID(xevent->xselectionclear.selection); + if (id != kClipboardEnd) { + m_clipboard[id]->lost(xevent->xselectionclear.time); + sendClipboardEvent(m_events->forClipboard().clipboardGrabbed(), id); + return; + } + } break; - case SelectionNotify: - // notification of selection transferred. we shouldn't - // get this here because we handle them in the selection - // retrieval methods. we'll just delete the property - // with the data (satisfying the usual ICCCM protocol). - if (xevent->xselection.property != None) { - XDeleteProperty(m_display, - xevent->xselection.requestor, - xevent->xselection.property); - } - break; + case SelectionNotify: + // notification of selection transferred. we shouldn't + // get this here because we handle them in the selection + // retrieval methods. we'll just delete the property + // with the data (satisfying the usual ICCCM protocol). + if (xevent->xselection.property != None) { + XDeleteProperty(m_display, xevent->xselection.requestor, + xevent->xselection.property); + } + break; - case SelectionRequest: - { - // somebody is asking for clipboard data - ClipboardID id = getClipboardID( - xevent->xselectionrequest.selection); - if (id != kClipboardEnd) { - m_clipboard[id]->addRequest( - xevent->xselectionrequest.owner, - xevent->xselectionrequest.requestor, - xevent->xselectionrequest.target, - xevent->xselectionrequest.time, - xevent->xselectionrequest.property); - return; - } - } - break; + case SelectionRequest: { + // somebody is asking for clipboard data + ClipboardID id = getClipboardID(xevent->xselectionrequest.selection); + if (id != kClipboardEnd) { + m_clipboard[id]->addRequest( + xevent->xselectionrequest.owner, xevent->xselectionrequest.requestor, + xevent->xselectionrequest.target, xevent->xselectionrequest.time, + xevent->xselectionrequest.property); + return; + } + } break; - case PropertyNotify: - // property delete may be part of a selection conversion - if (xevent->xproperty.state == PropertyDelete) { - processClipboardRequest(xevent->xproperty.window, - xevent->xproperty.time, - xevent->xproperty.atom); - } - break; + case PropertyNotify: + // property delete may be part of a selection conversion + if (xevent->xproperty.state == PropertyDelete) { + processClipboardRequest(xevent->xproperty.window, xevent->xproperty.time, + xevent->xproperty.atom); + } + break; - case DestroyNotify: - // looks like one of the windows that requested a clipboard - // transfer has gone bye-bye. - destroyClipboardRequest(xevent->xdestroywindow.window); - break; + case DestroyNotify: + // looks like one of the windows that requested a clipboard + // transfer has gone bye-bye. + destroyClipboardRequest(xevent->xdestroywindow.window); + break; - case KeyPress: - if (m_isPrimary) { - onKeyPress(xevent->xkey); - } - return; + case KeyPress: + if (m_isPrimary) { + onKeyPress(xevent->xkey); + } + return; - case KeyRelease: - if (m_isPrimary) { - onKeyRelease(xevent->xkey, isRepeat); - } - return; + case KeyRelease: + if (m_isPrimary) { + onKeyRelease(xevent->xkey, isRepeat); + } + return; - case ButtonPress: - if (m_isPrimary) { - onMousePress(xevent->xbutton); - } - return; + case ButtonPress: + if (m_isPrimary) { + onMousePress(xevent->xbutton); + } + return; - case ButtonRelease: - if (m_isPrimary) { - onMouseRelease(xevent->xbutton); - } - return; + case ButtonRelease: + if (m_isPrimary) { + onMouseRelease(xevent->xbutton); + } + return; - case MotionNotify: - if (m_isPrimary) { - onMouseMove(xevent->xmotion); - } - return; + case MotionNotify: + if (m_isPrimary) { + onMouseMove(xevent->xmotion); + } + return; - case ConfigureNotify: - if (!m_isPrimary && xevent->xconfigure.window == m_root) { - setShape(xevent->xconfigure.width, xevent->xconfigure.height); - sendEvent(m_events->forIScreen().shapeChanged()); - } - return; + case ConfigureNotify: + if (!m_isPrimary && xevent->xconfigure.window == m_root) { + setShape(xevent->xconfigure.width, xevent->xconfigure.height); + sendEvent(m_events->forIScreen().shapeChanged()); + } + return; - default: + default: #if HAVE_XKB_EXTENSION - if (m_xkb && xevent->type == m_xkbEventBase) { - XkbEvent* xkbEvent = reinterpret_cast(xevent); - switch (xkbEvent->any.xkb_type) { - case XkbMapNotify: - refreshKeyboard(xevent); - return; + if (m_xkb && xevent->type == m_xkbEventBase) { + XkbEvent *xkbEvent = reinterpret_cast(xevent); + switch (xkbEvent->any.xkb_type) { + case XkbMapNotify: + refreshKeyboard(xevent); + return; - case XkbStateNotify: - LOG((CLOG_INFO "group change: %d", xkbEvent->state.group)); - m_keyState->setActiveGroup((SInt32)xkbEvent->state.group); - return; - } - } + case XkbStateNotify: + LOG((CLOG_INFO "group change: %d", xkbEvent->state.group)); + m_keyState->setActiveGroup((SInt32)xkbEvent->state.group); + return; + } + } #endif #if HAVE_X11_EXTENSIONS_XRANDR_H - if (m_xrandr) { - if (xevent->type == m_xrandrEventBase + RRScreenChangeNotify - || xevent->type == m_xrandrEventBase + RRNotify - && reinterpret_cast(xevent)->subtype == RRNotify_CrtcChange) { - LOG((CLOG_INFO "either XRRScreenChangeNotifyEvent or RRNotify_CrtcChange received")); + if (m_xrandr) { + if (xevent->type == m_xrandrEventBase + RRScreenChangeNotify || + xevent->type == m_xrandrEventBase + RRNotify && + reinterpret_cast(xevent)->subtype == + RRNotify_CrtcChange) { + LOG((CLOG_INFO "either XRRScreenChangeNotifyEvent or " + "RRNotify_CrtcChange received")); - // we're required to call back into XLib so XLib can update its internal state - XRRUpdateConfiguration(xevent); + // we're required to call back into XLib so XLib can update its internal + // state + XRRUpdateConfiguration(xevent); - // requery/recalculate the screen shape - saveShape(); + // requery/recalculate the screen shape + saveShape(); - // we need to resize m_window, otherwise we'll get a weird problem where moving - // off the server onto the client causes the pointer to warp to the - // center of the server (so you can't move the pointer off the server) - if (m_isPrimary) { - XMoveWindow(m_display, m_window, m_x, m_y); - XResizeWindow(m_display, m_window, m_w, m_h); - } + // we need to resize m_window, otherwise we'll get a weird problem where + // moving off the server onto the client causes the pointer to warp to + // the center of the server (so you can't move the pointer off the + // server) + if (m_isPrimary) { + XMoveWindow(m_display, m_window, m_x, m_y); + XResizeWindow(m_display, m_window, m_w, m_h); + } - sendEvent(m_events->forIScreen().shapeChanged()); - } - } + sendEvent(m_events->forIScreen().shapeChanged()); + } + } #endif - break; - } + break; + } } -void -XWindowsScreen::onKeyPress(XKeyEvent& xkey) -{ - LOG((CLOG_DEBUG1 "event: KeyPress code=%d, state=0x%04x", xkey.keycode, xkey.state)); - const KeyModifierMask mask = m_keyState->mapModifiersFromX(xkey.state); - KeyID key = mapKeyFromX(&xkey); - if (key != kKeyNone) { - // check for ctrl+alt+del emulation - if ((key == kKeyPause || key == kKeyBreak) && - (mask & (KeyModifierControl | KeyModifierAlt)) == - (KeyModifierControl | KeyModifierAlt)) { - // pretend it's ctrl+alt+del - LOG((CLOG_DEBUG "emulate ctrl+alt+del")); - key = kKeyDelete; - } +void XWindowsScreen::onKeyPress(XKeyEvent &xkey) { + LOG((CLOG_DEBUG1 "event: KeyPress code=%d, state=0x%04x", xkey.keycode, + xkey.state)); + const KeyModifierMask mask = m_keyState->mapModifiersFromX(xkey.state); + KeyID key = mapKeyFromX(&xkey); + if (key != kKeyNone) { + // check for ctrl+alt+del emulation + if ((key == kKeyPause || key == kKeyBreak) && + (mask & (KeyModifierControl | KeyModifierAlt)) == + (KeyModifierControl | KeyModifierAlt)) { + // pretend it's ctrl+alt+del + LOG((CLOG_DEBUG "emulate ctrl+alt+del")); + key = kKeyDelete; + } - // get which button. see call to XFilterEvent() in onEvent() - // for more info. - bool isFake = false; - KeyButton keycode = static_cast(xkey.keycode); - if (keycode == 0) { - isFake = true; - keycode = static_cast(m_lastKeycode); - if (keycode == 0) { - // no keycode - LOG((CLOG_DEBUG1 "event: KeyPress no keycode")); - return; - } - } + // get which button. see call to XFilterEvent() in onEvent() + // for more info. + bool isFake = false; + KeyButton keycode = static_cast(xkey.keycode); + if (keycode == 0) { + isFake = true; + keycode = static_cast(m_lastKeycode); + if (keycode == 0) { + // no keycode + LOG((CLOG_DEBUG1 "event: KeyPress no keycode")); + return; + } + } - // handle key - m_keyState->sendKeyEvent(getEventTarget(), - true, false, key, mask, 1, keycode); + // handle key + m_keyState->sendKeyEvent(getEventTarget(), true, false, key, mask, 1, + keycode); - // do fake release if this is a fake press - if (isFake) { - m_keyState->sendKeyEvent(getEventTarget(), - false, false, key, mask, 1, keycode); - } - } - else { - LOG((CLOG_DEBUG1 "can't map keycode to key id")); - } + // do fake release if this is a fake press + if (isFake) { + m_keyState->sendKeyEvent(getEventTarget(), false, false, key, mask, 1, + keycode); + } + } else { + LOG((CLOG_DEBUG1 "can't map keycode to key id")); + } } -void -XWindowsScreen::onKeyRelease(XKeyEvent& xkey, bool isRepeat) -{ - const KeyModifierMask mask = m_keyState->mapModifiersFromX(xkey.state); - KeyID key = mapKeyFromX(&xkey); - if (key != kKeyNone) { - // check for ctrl+alt+del emulation - if ((key == kKeyPause || key == kKeyBreak) && - (mask & (KeyModifierControl | KeyModifierAlt)) == - (KeyModifierControl | KeyModifierAlt)) { - // pretend it's ctrl+alt+del and ignore autorepeat - LOG((CLOG_DEBUG "emulate ctrl+alt+del")); - key = kKeyDelete; - isRepeat = false; - } +void XWindowsScreen::onKeyRelease(XKeyEvent &xkey, bool isRepeat) { + const KeyModifierMask mask = m_keyState->mapModifiersFromX(xkey.state); + KeyID key = mapKeyFromX(&xkey); + if (key != kKeyNone) { + // check for ctrl+alt+del emulation + if ((key == kKeyPause || key == kKeyBreak) && + (mask & (KeyModifierControl | KeyModifierAlt)) == + (KeyModifierControl | KeyModifierAlt)) { + // pretend it's ctrl+alt+del and ignore autorepeat + LOG((CLOG_DEBUG "emulate ctrl+alt+del")); + key = kKeyDelete; + isRepeat = false; + } - KeyButton keycode = static_cast(xkey.keycode); - if (!isRepeat) { - // no press event follows so it's a plain release - LOG((CLOG_DEBUG1 "event: KeyRelease code=%d, state=0x%04x", keycode, xkey.state)); - m_keyState->sendKeyEvent(getEventTarget(), - false, false, key, mask, 1, keycode); - } - else { - // found a press event following so it's a repeat. - // we could attempt to count the already queued - // repeats but we'll just send a repeat of 1. - // note that we discard the press event. - LOG((CLOG_DEBUG1 "event: repeat code=%d, state=0x%04x", keycode, xkey.state)); - m_keyState->sendKeyEvent(getEventTarget(), - false, true, key, mask, 1, keycode); - } - } + KeyButton keycode = static_cast(xkey.keycode); + if (!isRepeat) { + // no press event follows so it's a plain release + LOG((CLOG_DEBUG1 "event: KeyRelease code=%d, state=0x%04x", keycode, + xkey.state)); + m_keyState->sendKeyEvent(getEventTarget(), false, false, key, mask, 1, + keycode); + } else { + // found a press event following so it's a repeat. + // we could attempt to count the already queued + // repeats but we'll just send a repeat of 1. + // note that we discard the press event. + LOG((CLOG_DEBUG1 "event: repeat code=%d, state=0x%04x", keycode, + xkey.state)); + m_keyState->sendKeyEvent(getEventTarget(), false, true, key, mask, 1, + keycode); + } + } } -bool -XWindowsScreen::onHotKey(XKeyEvent& xkey, bool isRepeat) -{ - // find the hot key id - HotKeyToIDMap::const_iterator i = - m_hotKeyToIDMap.find(HotKeyItem(xkey.keycode, xkey.state)); - if (i == m_hotKeyToIDMap.end()) { - return false; - } +bool XWindowsScreen::onHotKey(XKeyEvent &xkey, bool isRepeat) { + // find the hot key id + HotKeyToIDMap::const_iterator i = + m_hotKeyToIDMap.find(HotKeyItem(xkey.keycode, xkey.state)); + if (i == m_hotKeyToIDMap.end()) { + return false; + } - // find what kind of event - Event::Type type; - if (xkey.type == KeyPress) { - type = m_events->forIPrimaryScreen().hotKeyDown(); - } - else if (xkey.type == KeyRelease) { - type = m_events->forIPrimaryScreen().hotKeyUp(); - } - else { - return false; - } + // find what kind of event + Event::Type type; + if (xkey.type == KeyPress) { + type = m_events->forIPrimaryScreen().hotKeyDown(); + } else if (xkey.type == KeyRelease) { + type = m_events->forIPrimaryScreen().hotKeyUp(); + } else { + return false; + } - // generate event (ignore key repeats) - if (!isRepeat) { - m_events->addEvent(Event(type, getEventTarget(), - HotKeyInfo::alloc(i->second))); - } - return true; + // generate event (ignore key repeats) + if (!isRepeat) { + m_events->addEvent( + Event(type, getEventTarget(), HotKeyInfo::alloc(i->second))); + } + return true; } -void -XWindowsScreen::onMousePress(const XButtonEvent& xbutton) -{ - LOG((CLOG_DEBUG1 "event: ButtonPress button=%d", xbutton.button)); - ButtonID button = mapButtonFromX(&xbutton); - KeyModifierMask mask = m_keyState->mapModifiersFromX(xbutton.state); - if (button != kButtonNone) { - sendEvent(m_events->forIPrimaryScreen().buttonDown(), ButtonInfo::alloc(button, mask)); - } +void XWindowsScreen::onMousePress(const XButtonEvent &xbutton) { + LOG((CLOG_DEBUG1 "event: ButtonPress button=%d", xbutton.button)); + ButtonID button = mapButtonFromX(&xbutton); + KeyModifierMask mask = m_keyState->mapModifiersFromX(xbutton.state); + if (button != kButtonNone) { + sendEvent(m_events->forIPrimaryScreen().buttonDown(), + ButtonInfo::alloc(button, mask)); + } } -void -XWindowsScreen::onMouseRelease(const XButtonEvent& xbutton) -{ - LOG((CLOG_DEBUG1 "event: ButtonRelease button=%d", xbutton.button)); - ButtonID button = mapButtonFromX(&xbutton); - KeyModifierMask mask = m_keyState->mapModifiersFromX(xbutton.state); - if (button != kButtonNone) { - sendEvent(m_events->forIPrimaryScreen().buttonUp(), ButtonInfo::alloc(button, mask)); - } - else if (xbutton.button == 4) { - // wheel forward (away from user) - sendEvent(m_events->forIPrimaryScreen().wheel(), WheelInfo::alloc(0, 120)); - } - else if (xbutton.button == 5) { - // wheel backward (toward user) - sendEvent(m_events->forIPrimaryScreen().wheel(), WheelInfo::alloc(0, -120)); - } - // XXX -- support x-axis scrolling +void XWindowsScreen::onMouseRelease(const XButtonEvent &xbutton) { + LOG((CLOG_DEBUG1 "event: ButtonRelease button=%d", xbutton.button)); + ButtonID button = mapButtonFromX(&xbutton); + KeyModifierMask mask = m_keyState->mapModifiersFromX(xbutton.state); + if (button != kButtonNone) { + sendEvent(m_events->forIPrimaryScreen().buttonUp(), + ButtonInfo::alloc(button, mask)); + } else if (xbutton.button == 4) { + // wheel forward (away from user) + sendEvent(m_events->forIPrimaryScreen().wheel(), WheelInfo::alloc(0, 120)); + } else if (xbutton.button == 5) { + // wheel backward (toward user) + sendEvent(m_events->forIPrimaryScreen().wheel(), WheelInfo::alloc(0, -120)); + } + // XXX -- support x-axis scrolling } -void -XWindowsScreen::onMouseMove(const XMotionEvent& xmotion) -{ - LOG((CLOG_DEBUG2 "event: MotionNotify %d,%d", xmotion.x_root, xmotion.y_root)); +void XWindowsScreen::onMouseMove(const XMotionEvent &xmotion) { + LOG((CLOG_DEBUG2 "event: MotionNotify %d,%d", xmotion.x_root, + xmotion.y_root)); - // compute motion delta (relative to the last known - // mouse position) - SInt32 x = xmotion.x_root - m_xCursor; - SInt32 y = xmotion.y_root - m_yCursor; + // compute motion delta (relative to the last known + // mouse position) + SInt32 x = xmotion.x_root - m_xCursor; + SInt32 y = xmotion.y_root - m_yCursor; - // save position to compute delta of next motion - m_xCursor = xmotion.x_root; - m_yCursor = xmotion.y_root; + // save position to compute delta of next motion + m_xCursor = xmotion.x_root; + m_yCursor = xmotion.y_root; - if (xmotion.send_event) { - // we warped the mouse. discard events until we - // find the matching sent event. see - // warpCursorNoFlush() for where the events are - // sent. we discard the matching sent event and - // can be sure we've skipped the warp event. - XEvent xevent; - char cntr = 0; - do { - XMaskEvent(m_display, PointerMotionMask, &xevent); - if (cntr++ > 10) { - LOG((CLOG_WARN "too many discarded events! %d", cntr)); - break; - } - } while (!xevent.xany.send_event); - cntr = 0; - } - else if (m_isOnScreen) { - // motion on primary screen - sendEvent(m_events->forIPrimaryScreen().motionOnPrimary(), - MotionInfo::alloc(m_xCursor, m_yCursor)); - } - else { - // motion on secondary screen. warp mouse back to - // center. - // - // my lombard (powerbook g3) running linux and - // using the adbmouse driver has two problems: - // first, the driver only sends motions of +/-2 - // pixels and, second, it seems to discard some - // physical input after a warp. the former isn't a - // big deal (we're just limited to every other - // pixel) but the latter is a PITA. to work around - // it we only warp when the mouse has moved more - // than s_size pixels from the center. - static const SInt32 s_size = 32; - if (xmotion.x_root - m_xCenter < -s_size || - xmotion.x_root - m_xCenter > s_size || - xmotion.y_root - m_yCenter < -s_size || - xmotion.y_root - m_yCenter > s_size) { - warpCursorNoFlush(m_xCenter, m_yCenter); - } + if (xmotion.send_event) { + // we warped the mouse. discard events until we + // find the matching sent event. see + // warpCursorNoFlush() for where the events are + // sent. we discard the matching sent event and + // can be sure we've skipped the warp event. + XEvent xevent; + char cntr = 0; + do { + XMaskEvent(m_display, PointerMotionMask, &xevent); + if (cntr++ > 10) { + LOG((CLOG_WARN "too many discarded events! %d", cntr)); + break; + } + } while (!xevent.xany.send_event); + cntr = 0; + } else if (m_isOnScreen) { + // motion on primary screen + sendEvent(m_events->forIPrimaryScreen().motionOnPrimary(), + MotionInfo::alloc(m_xCursor, m_yCursor)); + } else { + // motion on secondary screen. warp mouse back to + // center. + // + // my lombard (powerbook g3) running linux and + // using the adbmouse driver has two problems: + // first, the driver only sends motions of +/-2 + // pixels and, second, it seems to discard some + // physical input after a warp. the former isn't a + // big deal (we're just limited to every other + // pixel) but the latter is a PITA. to work around + // it we only warp when the mouse has moved more + // than s_size pixels from the center. + static const SInt32 s_size = 32; + if (xmotion.x_root - m_xCenter < -s_size || + xmotion.x_root - m_xCenter > s_size || + xmotion.y_root - m_yCenter < -s_size || + xmotion.y_root - m_yCenter > s_size) { + warpCursorNoFlush(m_xCenter, m_yCenter); + } - // send event if mouse moved. do this after warping - // back to center in case the motion takes us onto - // the primary screen. if we sent the event first - // in that case then the warp would happen after - // warping to the primary screen's enter position, - // effectively overriding it. - if (x != 0 || y != 0) { - sendEvent(m_events->forIPrimaryScreen().motionOnSecondary(), MotionInfo::alloc(x, y)); - } - } + // send event if mouse moved. do this after warping + // back to center in case the motion takes us onto + // the primary screen. if we sent the event first + // in that case then the warp would happen after + // warping to the primary screen's enter position, + // effectively overriding it. + if (x != 0 || y != 0) { + sendEvent(m_events->forIPrimaryScreen().motionOnSecondary(), + MotionInfo::alloc(x, y)); + } + } } -Cursor -XWindowsScreen::createBlankCursor() const -{ - // this seems just a bit more complicated than really necessary +Cursor XWindowsScreen::createBlankCursor() const { + // this seems just a bit more complicated than really necessary - // get the closet cursor size to 1x1 - unsigned int w = 0, h = 0; - XQueryBestCursor(m_display, m_root, 1, 1, &w, &h); - w = std::max(1u, w); - h = std::max(1u, h); + // get the closet cursor size to 1x1 + unsigned int w = 0, h = 0; + XQueryBestCursor(m_display, m_root, 1, 1, &w, &h); + w = std::max(1u, w); + h = std::max(1u, h); - // make bitmap data for cursor of closet size. since the cursor - // is blank we can use the same bitmap for shape and mask: all - // zeros. - const int size = ((w + 7) >> 3) * h; - char* data = new char[size]; - memset(data, 0, size); + // make bitmap data for cursor of closet size. since the cursor + // is blank we can use the same bitmap for shape and mask: all + // zeros. + const int size = ((w + 7) >> 3) * h; + char *data = new char[size]; + memset(data, 0, size); - // make bitmap - Pixmap bitmap = XCreateBitmapFromData(m_display, m_root, data, w, h); + // make bitmap + Pixmap bitmap = XCreateBitmapFromData(m_display, m_root, data, w, h); - // need an arbitrary color for the cursor - XColor color; - color.pixel = 0; - color.red = color.green = color.blue = 0; - color.flags = DoRed | DoGreen | DoBlue; + // need an arbitrary color for the cursor + XColor color; + color.pixel = 0; + color.red = color.green = color.blue = 0; + color.flags = DoRed | DoGreen | DoBlue; - // make cursor from bitmap - Cursor cursor = XCreatePixmapCursor(m_display, bitmap, bitmap, - &color, &color, 0, 0); + // make cursor from bitmap + Cursor cursor = + XCreatePixmapCursor(m_display, bitmap, bitmap, &color, &color, 0, 0); - // don't need bitmap or the data anymore - delete[] data; - XFreePixmap(m_display, bitmap); + // don't need bitmap or the data anymore + delete[] data; + XFreePixmap(m_display, bitmap); - return cursor; + return cursor; } -ClipboardID -XWindowsScreen::getClipboardID(Atom selection) const -{ - for (ClipboardID id = 0; id < kClipboardEnd; ++id) { - if (m_clipboard[id] != NULL && - m_clipboard[id]->getSelection() == selection) { - return id; - } - } - return kClipboardEnd; +ClipboardID XWindowsScreen::getClipboardID(Atom selection) const { + for (ClipboardID id = 0; id < kClipboardEnd; ++id) { + if (m_clipboard[id] != NULL && + m_clipboard[id]->getSelection() == selection) { + return id; + } + } + return kClipboardEnd; } -void -XWindowsScreen::processClipboardRequest(Window requestor, - Time time, Atom property) -{ - // check every clipboard until one returns success - for (ClipboardID id = 0; id < kClipboardEnd; ++id) { - if (m_clipboard[id] != NULL && - m_clipboard[id]->processRequest(requestor, time, property)) { - break; - } - } +void XWindowsScreen::processClipboardRequest(Window requestor, Time time, + Atom property) { + // check every clipboard until one returns success + for (ClipboardID id = 0; id < kClipboardEnd; ++id) { + if (m_clipboard[id] != NULL && + m_clipboard[id]->processRequest(requestor, time, property)) { + break; + } + } } -void -XWindowsScreen::destroyClipboardRequest(Window requestor) -{ - // check every clipboard until one returns success - for (ClipboardID id = 0; id < kClipboardEnd; ++id) { - if (m_clipboard[id] != NULL && - m_clipboard[id]->destroyRequest(requestor)) { - break; - } - } +void XWindowsScreen::destroyClipboardRequest(Window requestor) { + // check every clipboard until one returns success + for (ClipboardID id = 0; id < kClipboardEnd; ++id) { + if (m_clipboard[id] != NULL && m_clipboard[id]->destroyRequest(requestor)) { + break; + } + } } -void -XWindowsScreen::onError() -{ - // prevent further access to the X display - m_events->adoptBuffer(NULL); - m_screensaver->destroy(); - m_screensaver = NULL; - m_display = NULL; +void XWindowsScreen::onError() { + // prevent further access to the X display + m_events->adoptBuffer(NULL); + m_screensaver->destroy(); + m_screensaver = NULL; + m_display = NULL; - // notify of failure - sendEvent(m_events->forIScreen().error(), NULL); + // notify of failure + sendEvent(m_events->forIScreen().error(), NULL); - // FIXME -- should ensure that we ignore operations that involve - // m_display from now on. however, Xlib will simply exit the - // application in response to the X I/O error so there's no - // point in trying to really handle the error. if we did want - // to handle the error, it'd probably be easiest to delegate to - // one of two objects. one object would take the implementation - // from this class. the other object would be stub methods that - // don't use X11. on error, we'd switch to the latter. + // FIXME -- should ensure that we ignore operations that involve + // m_display from now on. however, Xlib will simply exit the + // application in response to the X I/O error so there's no + // point in trying to really handle the error. if we did want + // to handle the error, it'd probably be easiest to delegate to + // one of two objects. one object would take the implementation + // from this class. the other object would be stub methods that + // don't use X11. on error, we'd switch to the latter. } -int -XWindowsScreen::ioErrorHandler(Display*) -{ - // the display has disconnected, probably because X is shutting - // down. X forces us to exit at this point which is annoying. - // we'll pretend as if we won't exit so we try to make sure we - // don't access the display anymore. - LOG((CLOG_CRIT "x display has unexpectedly disconnected")); - s_screen->onError(); - return 0; +int XWindowsScreen::ioErrorHandler(Display *) { + // the display has disconnected, probably because X is shutting + // down. X forces us to exit at this point which is annoying. + // we'll pretend as if we won't exit so we try to make sure we + // don't access the display anymore. + LOG((CLOG_CRIT "x display has unexpectedly disconnected")); + s_screen->onError(); + return 0; } -void -XWindowsScreen::selectEvents(Window w) const -{ - // ignore errors while we adjust event masks. windows could be - // destroyed at any time after the XQueryTree() in doSelectEvents() - // so we must ignore BadWindow errors. - XWindowsUtil::ErrorLock lock(m_display); +void XWindowsScreen::selectEvents(Window w) const { + // ignore errors while we adjust event masks. windows could be + // destroyed at any time after the XQueryTree() in doSelectEvents() + // so we must ignore BadWindow errors. + XWindowsUtil::ErrorLock lock(m_display); - // adjust event masks - doSelectEvents(w); + // adjust event masks + doSelectEvents(w); } -void -XWindowsScreen::doSelectEvents(Window w) const -{ - // we want to track the mouse everywhere on the display. to achieve - // that we select PointerMotionMask on every window. we also select - // SubstructureNotifyMask in order to get CreateNotify events so we - // select events on new windows too. +void XWindowsScreen::doSelectEvents(Window w) const { + // we want to track the mouse everywhere on the display. to achieve + // that we select PointerMotionMask on every window. we also select + // SubstructureNotifyMask in order to get CreateNotify events so we + // select events on new windows too. - // we don't want to adjust our grab window - if (w == m_window) { - return; - } + // we don't want to adjust our grab window + if (w == m_window) { + return; + } - // X11 has a design flaw. If *no* client selected PointerMotionMask for - // a window, motion events will be delivered to that window's parent. - // If *any* client, not necessarily the owner, selects PointerMotionMask - // on such a window, X will stop propagating motion events to its - // parent. This breaks applications that rely on event propagation - // behavior. - // - // Avoid selecting PointerMotionMask unless some other client selected - // it already. - long mask = SubstructureNotifyMask; - XWindowAttributes attr; - XGetWindowAttributes(m_display, w, &attr); - if ((attr.all_event_masks & PointerMotionMask) == PointerMotionMask) { - mask |= PointerMotionMask; - } + // X11 has a design flaw. If *no* client selected PointerMotionMask for + // a window, motion events will be delivered to that window's parent. + // If *any* client, not necessarily the owner, selects PointerMotionMask + // on such a window, X will stop propagating motion events to its + // parent. This breaks applications that rely on event propagation + // behavior. + // + // Avoid selecting PointerMotionMask unless some other client selected + // it already. + long mask = SubstructureNotifyMask; + XWindowAttributes attr; + XGetWindowAttributes(m_display, w, &attr); + if ((attr.all_event_masks & PointerMotionMask) == PointerMotionMask) { + mask |= PointerMotionMask; + } - // select events of interest. do this before querying the tree so - // we'll get notifications of children created after the XQueryTree() - // so we won't miss them. - XSelectInput(m_display, w, mask); + // select events of interest. do this before querying the tree so + // we'll get notifications of children created after the XQueryTree() + // so we won't miss them. + XSelectInput(m_display, w, mask); - // recurse on child windows - Window rw, pw, *cw; - unsigned int nc; - if (XQueryTree(m_display, w, &rw, &pw, &cw, &nc)) { - for (unsigned int i = 0; i < nc; ++i) { - doSelectEvents(cw[i]); - } - XFree(cw); - } + // recurse on child windows + Window rw, pw, *cw; + unsigned int nc; + if (XQueryTree(m_display, w, &rw, &pw, &cw, &nc)) { + for (unsigned int i = 0; i < nc; ++i) { + doSelectEvents(cw[i]); + } + XFree(cw); + } } -KeyID -XWindowsScreen::mapKeyFromX(XKeyEvent* event) const -{ - // convert to a keysym - KeySym keysym; - if (event->type == KeyPress && m_ic != NULL) { - // do multibyte lookup. can only call XmbLookupString with a - // key press event and a valid XIC so we checked those above. - char scratch[32]; - int n = sizeof(scratch) / sizeof(scratch[0]); - char* buffer = scratch; - int status; - n = XmbLookupString(m_ic, event, buffer, n, &keysym, &status); - if (status == XBufferOverflow) { - // not enough space. grow buffer and try again. - buffer = new char[n]; - n = XmbLookupString(m_ic, event, buffer, n, &keysym, &status); - delete[] buffer; - } +KeyID XWindowsScreen::mapKeyFromX(XKeyEvent *event) const { + // convert to a keysym + KeySym keysym; + if (event->type == KeyPress && m_ic != NULL) { + // do multibyte lookup. can only call XmbLookupString with a + // key press event and a valid XIC so we checked those above. + char scratch[32]; + int n = sizeof(scratch) / sizeof(scratch[0]); + char *buffer = scratch; + int status; + n = XmbLookupString(m_ic, event, buffer, n, &keysym, &status); + if (status == XBufferOverflow) { + // not enough space. grow buffer and try again. + buffer = new char[n]; + n = XmbLookupString(m_ic, event, buffer, n, &keysym, &status); + delete[] buffer; + } - // see what we got. since we don't care about the string - // we'll just look for a keysym. - switch (status) { - default: - case XLookupNone: - case XLookupChars: - keysym = 0; - break; + // see what we got. since we don't care about the string + // we'll just look for a keysym. + switch (status) { + default: + case XLookupNone: + case XLookupChars: + keysym = 0; + break; - case XLookupKeySym: - case XLookupBoth: - break; - } - } - else { - // plain old lookup - char dummy[1]; - XLookupString(event, dummy, 0, &keysym, NULL); - } + case XLookupKeySym: + case XLookupBoth: + break; + } + } else { + // plain old lookup + char dummy[1]; + XLookupString(event, dummy, 0, &keysym, NULL); + } - LOG((CLOG_DEBUG2 "mapped code=%d to keysym=0x%04x", event->keycode, keysym)); + LOG((CLOG_DEBUG2 "mapped code=%d to keysym=0x%04x", event->keycode, keysym)); - // convert key - KeyID result = XWindowsUtil::mapKeySymToKeyID(keysym); - LOG((CLOG_DEBUG2 "mapped keysym=0x%04x to keyID=%d", keysym, result)); - return result; + // convert key + KeyID result = XWindowsUtil::mapKeySymToKeyID(keysym); + LOG((CLOG_DEBUG2 "mapped keysym=0x%04x to keyID=%d", keysym, result)); + return result; } -ButtonID -XWindowsScreen::mapButtonFromX(const XButtonEvent* event) const -{ - unsigned int button = event->button; +ButtonID XWindowsScreen::mapButtonFromX(const XButtonEvent *event) const { + unsigned int button = event->button; - // first three buttons map to 1, 2, 3 (kButtonLeft, Middle, Right) - if (button >= 1 && button <= 3) { - return static_cast(button); - } + // first three buttons map to 1, 2, 3 (kButtonLeft, Middle, Right) + if (button >= 1 && button <= 3) { + return static_cast(button); + } - // buttons 4 and 5 are ignored here. they're used for the wheel. - // buttons 6, 7, etc and up map to 4, 5, etc. - else if (button >= 6) { - return static_cast(button - 2); - } + // buttons 4 and 5 are ignored here. they're used for the wheel. + // buttons 6, 7, etc and up map to 4, 5, etc. + else if (button >= 6) { + return static_cast(button - 2); + } - // unknown button - else { - return kButtonNone; - } + // unknown button + else { + return kButtonNone; + } } -unsigned int -XWindowsScreen::mapButtonToX(ButtonID id) const -{ - // map button -1 to button 4 (+wheel) - if (id == static_cast(-1)) { - id = 4; - } +unsigned int XWindowsScreen::mapButtonToX(ButtonID id) const { + // map button -1 to button 4 (+wheel) + if (id == static_cast(-1)) { + id = 4; + } - // map button -2 to button 5 (-wheel) - else if (id == static_cast(-2)) { - id = 5; - } + // map button -2 to button 5 (-wheel) + else if (id == static_cast(-2)) { + id = 5; + } - // map buttons 4, 5, etc. to 6, 7, etc. to make room for buttons - // 4 and 5 used to simulate the mouse wheel. - else if (id >= 4) { - id += 2; - } + // map buttons 4, 5, etc. to 6, 7, etc. to make room for buttons + // 4 and 5 used to simulate the mouse wheel. + else if (id >= 4) { + id += 2; + } - // check button is in legal range - if (id < 1 || id > m_buttons.size()) { - // out of range - return 0; - } + // check button is in legal range + if (id < 1 || id > m_buttons.size()) { + // out of range + return 0; + } - // map button - return static_cast(id); + // map button + return static_cast(id); } -void -XWindowsScreen::warpCursorNoFlush(SInt32 x, SInt32 y) -{ - assert(m_window != None); +void XWindowsScreen::warpCursorNoFlush(SInt32 x, SInt32 y) { + assert(m_window != None); - // send an event that we can recognize before the mouse warp - XEvent eventBefore; - eventBefore.type = MotionNotify; - eventBefore.xmotion.display = m_display; - eventBefore.xmotion.window = m_window; - eventBefore.xmotion.root = m_root; - eventBefore.xmotion.subwindow = m_window; - eventBefore.xmotion.time = CurrentTime; - eventBefore.xmotion.x = x; - eventBefore.xmotion.y = y; - eventBefore.xmotion.x_root = x; - eventBefore.xmotion.y_root = y; - eventBefore.xmotion.state = 0; - eventBefore.xmotion.is_hint = NotifyNormal; - eventBefore.xmotion.same_screen = True; - XEvent eventAfter = eventBefore; - XSendEvent(m_display, m_window, False, 0, &eventBefore); + // send an event that we can recognize before the mouse warp + XEvent eventBefore; + eventBefore.type = MotionNotify; + eventBefore.xmotion.display = m_display; + eventBefore.xmotion.window = m_window; + eventBefore.xmotion.root = m_root; + eventBefore.xmotion.subwindow = m_window; + eventBefore.xmotion.time = CurrentTime; + eventBefore.xmotion.x = x; + eventBefore.xmotion.y = y; + eventBefore.xmotion.x_root = x; + eventBefore.xmotion.y_root = y; + eventBefore.xmotion.state = 0; + eventBefore.xmotion.is_hint = NotifyNormal; + eventBefore.xmotion.same_screen = True; + XEvent eventAfter = eventBefore; + XSendEvent(m_display, m_window, False, 0, &eventBefore); - // warp mouse - XWarpPointer(m_display, None, m_root, 0, 0, 0, 0, x, y); + // warp mouse + XWarpPointer(m_display, None, m_root, 0, 0, 0, 0, x, y); - // send an event that we can recognize after the mouse warp - XSendEvent(m_display, m_window, False, 0, &eventAfter); - XSync(m_display, False); + // send an event that we can recognize after the mouse warp + XSendEvent(m_display, m_window, False, 0, &eventAfter); + XSync(m_display, False); - LOG((CLOG_DEBUG2 "warped to %d,%d", x, y)); + LOG((CLOG_DEBUG2 "warped to %d,%d", x, y)); } -void -XWindowsScreen::updateButtons() -{ - // query the button mapping - UInt32 numButtons = XGetPointerMapping(m_display, NULL, 0); - unsigned char* tmpButtons = new unsigned char[numButtons]; - XGetPointerMapping(m_display, tmpButtons, numButtons); +void XWindowsScreen::updateButtons() { + // query the button mapping + UInt32 numButtons = XGetPointerMapping(m_display, NULL, 0); + unsigned char *tmpButtons = new unsigned char[numButtons]; + XGetPointerMapping(m_display, tmpButtons, numButtons); - // find the largest logical button id - unsigned char maxButton = 0; - for (UInt32 i = 0; i < numButtons; ++i) { - if (tmpButtons[i] > maxButton) { - maxButton = tmpButtons[i]; - } - } + // find the largest logical button id + unsigned char maxButton = 0; + for (UInt32 i = 0; i < numButtons; ++i) { + if (tmpButtons[i] > maxButton) { + maxButton = tmpButtons[i]; + } + } - // allocate button array - m_buttons.resize(maxButton); + // allocate button array + m_buttons.resize(maxButton); - // fill in button array values. m_buttons[i] is the physical - // button number for logical button i+1. - for (UInt32 i = 0; i < numButtons; ++i) { - m_buttons[i] = 0; - } - for (UInt32 i = 0; i < numButtons; ++i) { - m_buttons[tmpButtons[i] - 1] = i + 1; - } + // fill in button array values. m_buttons[i] is the physical + // button number for logical button i+1. + for (UInt32 i = 0; i < numButtons; ++i) { + m_buttons[i] = 0; + } + for (UInt32 i = 0; i < numButtons; ++i) { + m_buttons[tmpButtons[i] - 1] = i + 1; + } - // clean up - delete[] tmpButtons; + // clean up + delete[] tmpButtons; } -bool -XWindowsScreen::grabMouseAndKeyboard() -{ - unsigned int event_mask = ButtonPressMask | ButtonReleaseMask | EnterWindowMask | LeaveWindowMask | PointerMotionMask; +bool XWindowsScreen::grabMouseAndKeyboard() { + unsigned int event_mask = ButtonPressMask | ButtonReleaseMask | + EnterWindowMask | LeaveWindowMask | + PointerMotionMask; - // grab the mouse and keyboard. keep trying until we get them. - // if we can't grab one after grabbing the other then ungrab - // and wait before retrying. give up after s_timeout seconds. - static const double s_timeout = 1.0; - int result; - Stopwatch timer; - do { - // keyboard first - do { - result = XGrabKeyboard(m_display, m_window, True, - GrabModeAsync, GrabModeAsync, CurrentTime); - assert(result != GrabNotViewable); - if (result != GrabSuccess) { - LOG((CLOG_DEBUG2 "waiting to grab keyboard")); - ARCH->sleep(0.05); - if (timer.getTime() >= s_timeout) { - LOG((CLOG_DEBUG2 "grab keyboard timed out")); - return false; - } - } - } while (result != GrabSuccess); - LOG((CLOG_DEBUG2 "grabbed keyboard")); + // grab the mouse and keyboard. keep trying until we get them. + // if we can't grab one after grabbing the other then ungrab + // and wait before retrying. give up after s_timeout seconds. + static const double s_timeout = 1.0; + int result; + Stopwatch timer; + do { + // keyboard first + do { + result = XGrabKeyboard(m_display, m_window, True, GrabModeAsync, + GrabModeAsync, CurrentTime); + assert(result != GrabNotViewable); + if (result != GrabSuccess) { + LOG((CLOG_DEBUG2 "waiting to grab keyboard")); + ARCH->sleep(0.05); + if (timer.getTime() >= s_timeout) { + LOG((CLOG_DEBUG2 "grab keyboard timed out")); + return false; + } + } + } while (result != GrabSuccess); + LOG((CLOG_DEBUG2 "grabbed keyboard")); - // now the mouse --- use event_mask to get EnterNotify, LeaveNotify events - result = XGrabPointer(m_display, m_window, False, event_mask, - GrabModeAsync, GrabModeAsync, - m_window, None, CurrentTime); - assert(result != GrabNotViewable); - if (result != GrabSuccess) { - // back off to avoid grab deadlock - XUngrabKeyboard(m_display, CurrentTime); - LOG((CLOG_DEBUG2 "ungrabbed keyboard, waiting to grab pointer")); - ARCH->sleep(0.05); - if (timer.getTime() >= s_timeout) { - LOG((CLOG_DEBUG2 "grab pointer timed out")); - return false; - } - } - } while (result != GrabSuccess); + // now the mouse --- use event_mask to get EnterNotify, LeaveNotify events + result = XGrabPointer(m_display, m_window, False, event_mask, GrabModeAsync, + GrabModeAsync, m_window, None, CurrentTime); + assert(result != GrabNotViewable); + if (result != GrabSuccess) { + // back off to avoid grab deadlock + XUngrabKeyboard(m_display, CurrentTime); + LOG((CLOG_DEBUG2 "ungrabbed keyboard, waiting to grab pointer")); + ARCH->sleep(0.05); + if (timer.getTime() >= s_timeout) { + LOG((CLOG_DEBUG2 "grab pointer timed out")); + return false; + } + } + } while (result != GrabSuccess); - LOG((CLOG_DEBUG1 "grabbed pointer and keyboard")); - return true; + LOG((CLOG_DEBUG1 "grabbed pointer and keyboard")); + return true; } -void -XWindowsScreen::refreshKeyboard(XEvent* event) -{ - if (XPending(m_display) > 0) { - XEvent tmpEvent; - XPeekEvent(m_display, &tmpEvent); - if (tmpEvent.type == MappingNotify) { - // discard this event since another follows. - // we tend to get a bunch of these in a row. - return; - } - } +void XWindowsScreen::refreshKeyboard(XEvent *event) { + if (XPending(m_display) > 0) { + XEvent tmpEvent; + XPeekEvent(m_display, &tmpEvent); + if (tmpEvent.type == MappingNotify) { + // discard this event since another follows. + // we tend to get a bunch of these in a row. + return; + } + } - // keyboard mapping changed + // keyboard mapping changed #if HAVE_XKB_EXTENSION - if (m_xkb && event->type == m_xkbEventBase) { - XkbRefreshKeyboardMapping((XkbMapNotifyEvent*)event); - } - else + if (m_xkb && event->type == m_xkbEventBase) { + XkbRefreshKeyboardMapping((XkbMapNotifyEvent *)event); + } else #else - { - XRefreshKeyboardMapping(&event->xmapping); - } + { + XRefreshKeyboardMapping(&event->xmapping); + } #endif - m_keyState->updateKeyMap(); - m_keyState->updateKeyState(); + m_keyState->updateKeyMap(); + m_keyState->updateKeyState(); } - // // XWindowsScreen::HotKeyItem // -XWindowsScreen::HotKeyItem::HotKeyItem(int keycode, unsigned int mask) : - m_keycode(keycode), - m_mask(mask) -{ - // do nothing +XWindowsScreen::HotKeyItem::HotKeyItem(int keycode, unsigned int mask) + : m_keycode(keycode), m_mask(mask) { + // do nothing } -bool -XWindowsScreen::HotKeyItem::operator<(const HotKeyItem& x) const -{ - return (m_keycode < x.m_keycode || - (m_keycode == x.m_keycode && m_mask < x.m_mask)); +bool XWindowsScreen::HotKeyItem::operator<(const HotKeyItem &x) const { + return (m_keycode < x.m_keycode || + (m_keycode == x.m_keycode && m_mask < x.m_mask)); } -bool -XWindowsScreen::detectXI2() -{ - int event, error; - return XQueryExtension(m_display, - "XInputExtension", &xi_opcode, &event, &error); +bool XWindowsScreen::detectXI2() { + int event, error; + return XQueryExtension(m_display, "XInputExtension", &xi_opcode, &event, + &error); } #ifdef HAVE_XI2 -void -XWindowsScreen::selectXIRawMotion() -{ - XIEventMask mask; +void XWindowsScreen::selectXIRawMotion() { + XIEventMask mask; - mask.deviceid = XIAllDevices; - mask.mask_len = XIMaskLen(XI_RawMotion); - mask.mask = (unsigned char*)calloc(mask.mask_len, sizeof(char)); - mask.deviceid = XIAllMasterDevices; - memset(mask.mask, 0, 2); - XISetMask(mask.mask, XI_RawKeyRelease); - XISetMask(mask.mask, XI_RawMotion); - XISelectEvents(m_display, DefaultRootWindow(m_display), &mask, 1); - free(mask.mask); + mask.deviceid = XIAllDevices; + mask.mask_len = XIMaskLen(XI_RawMotion); + mask.mask = (unsigned char *)calloc(mask.mask_len, sizeof(char)); + mask.deviceid = XIAllMasterDevices; + memset(mask.mask, 0, 2); + XISetMask(mask.mask, XI_RawKeyRelease); + XISetMask(mask.mask, XI_RawMotion); + XISelectEvents(m_display, DefaultRootWindow(m_display), &mask, 1); + free(mask.mask); } #endif diff --git a/src/lib/platform/XWindowsScreen.h b/src/lib/platform/XWindowsScreen.h index 6a7be0ed5..4c7a3b2c1 100644 --- a/src/lib/platform/XWindowsScreen.h +++ b/src/lib/platform/XWindowsScreen.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -19,17 +19,17 @@ #pragma once #include "arch/Arch.h" -#include "synergy/PlatformScreen.h" -#include "synergy/KeyMap.h" -#include "synergy/ClientArgs.h" #include "common/stdset.h" #include "common/stdvector.h" #include "platform/XWindowsPowerManager.h" +#include "synergy/ClientArgs.h" +#include "synergy/KeyMap.h" +#include "synergy/PlatformScreen.h" #if X_DISPLAY_MISSING -# error X11 is required to build synergy +#error X11 is required to build synergy #else -# include +#include #endif class XWindowsClipboard; @@ -39,221 +39,221 @@ class XWindowsScreenSaver; //! Implementation of IPlatformScreen for X11 class XWindowsScreen : public PlatformScreen { public: - XWindowsScreen(const char* displayName, bool isPrimary, - bool disableXInitThreads, int mouseScrollDelta, - IEventQueue* events, - lib::synergy::ClientScrollDirection m_clientScrollDirection = lib::synergy::ClientScrollDirection::SERVER); - virtual ~XWindowsScreen(); + XWindowsScreen(const char *displayName, bool isPrimary, + bool disableXInitThreads, int mouseScrollDelta, + IEventQueue *events, + lib::synergy::ClientScrollDirection m_clientScrollDirection = + lib::synergy::ClientScrollDirection::SERVER); + virtual ~XWindowsScreen(); - //! @name manipulators - //@{ + //! @name manipulators + //@{ - //@} + //@} - // IScreen overrides - virtual void* getEventTarget() const; - virtual bool getClipboard(ClipboardID id, IClipboard*) const; - virtual void getShape(SInt32& x, SInt32& y, - SInt32& width, SInt32& height) const; - virtual void getCursorPos(SInt32& x, SInt32& y) const; + // IScreen overrides + virtual void *getEventTarget() const; + virtual bool getClipboard(ClipboardID id, IClipboard *) const; + virtual void getShape(SInt32 &x, SInt32 &y, SInt32 &width, + SInt32 &height) const; + virtual void getCursorPos(SInt32 &x, SInt32 &y) const; - // IPrimaryScreen overrides - virtual void reconfigure(UInt32 activeSides); - virtual void warpCursor(SInt32 x, SInt32 y); - virtual UInt32 registerHotKey(KeyID key, KeyModifierMask mask); - virtual void unregisterHotKey(UInt32 id); - virtual void fakeInputBegin(); - virtual void fakeInputEnd(); - virtual SInt32 getJumpZoneSize() const; - virtual bool isAnyMouseButtonDown(UInt32& buttonID) const; - virtual void getCursorCenter(SInt32& x, SInt32& y) const; + // IPrimaryScreen overrides + virtual void reconfigure(UInt32 activeSides); + virtual void warpCursor(SInt32 x, SInt32 y); + virtual UInt32 registerHotKey(KeyID key, KeyModifierMask mask); + virtual void unregisterHotKey(UInt32 id); + virtual void fakeInputBegin(); + virtual void fakeInputEnd(); + virtual SInt32 getJumpZoneSize() const; + virtual bool isAnyMouseButtonDown(UInt32 &buttonID) const; + virtual void getCursorCenter(SInt32 &x, SInt32 &y) const; - // ISecondaryScreen overrides - virtual void fakeMouseButton(ButtonID id, bool press); - virtual void fakeMouseMove(SInt32 x, SInt32 y); - virtual void fakeMouseRelativeMove(SInt32 dx, SInt32 dy) const; - virtual void fakeMouseWheel(SInt32 xDelta, SInt32 yDelta) const; + // ISecondaryScreen overrides + virtual void fakeMouseButton(ButtonID id, bool press); + virtual void fakeMouseMove(SInt32 x, SInt32 y); + virtual void fakeMouseRelativeMove(SInt32 dx, SInt32 dy) const; + virtual void fakeMouseWheel(SInt32 xDelta, SInt32 yDelta) const; - // IPlatformScreen overrides - virtual void enable(); - virtual void disable(); - virtual void enter(); - virtual bool leave(); - virtual bool setClipboard(ClipboardID, const IClipboard*); - virtual void checkClipboards(); - virtual void openScreensaver(bool notify); - virtual void closeScreensaver(); - virtual void screensaver(bool activate); - virtual void resetOptions(); - virtual void setOptions(const OptionsList& options); - virtual void setSequenceNumber(UInt32); - virtual bool isPrimary() const; - String getSecureInputApp() const override; + // IPlatformScreen overrides + virtual void enable(); + virtual void disable(); + virtual void enter(); + virtual bool leave(); + virtual bool setClipboard(ClipboardID, const IClipboard *); + virtual void checkClipboards(); + virtual void openScreensaver(bool notify); + virtual void closeScreensaver(); + virtual void screensaver(bool activate); + virtual void resetOptions(); + virtual void setOptions(const OptionsList &options); + virtual void setSequenceNumber(UInt32); + virtual bool isPrimary() const; + String getSecureInputApp() const override; protected: - // IPlatformScreen overrides - virtual void handleSystemEvent(const Event&, void*); - virtual void updateButtons(); - virtual IKeyState* getKeyState() const; + // IPlatformScreen overrides + virtual void handleSystemEvent(const Event &, void *); + virtual void updateButtons(); + virtual IKeyState *getKeyState() const; private: - // event sending - void sendEvent(Event::Type, void* = NULL); - void sendClipboardEvent(Event::Type, ClipboardID); + // event sending + void sendEvent(Event::Type, void * = NULL); + void sendClipboardEvent(Event::Type, ClipboardID); - // create the transparent cursor - Cursor createBlankCursor() const; + // create the transparent cursor + Cursor createBlankCursor() const; - // determine the clipboard from the X selection. returns - // kClipboardEnd if no such clipboard. - ClipboardID getClipboardID(Atom selection) const; + // determine the clipboard from the X selection. returns + // kClipboardEnd if no such clipboard. + ClipboardID getClipboardID(Atom selection) const; - // continue processing a selection request - void processClipboardRequest(Window window, - Time time, Atom property); + // continue processing a selection request + void processClipboardRequest(Window window, Time time, Atom property); - // terminate a selection request - void destroyClipboardRequest(Window window); + // terminate a selection request + void destroyClipboardRequest(Window window); - // X I/O error handler - void onError(); - static int ioErrorHandler(Display*); + // X I/O error handler + void onError(); + static int ioErrorHandler(Display *); private: - class KeyEventFilter { - public: - int m_event; - Window m_window; - Time m_time; - KeyCode m_keycode; - }; + class KeyEventFilter { + public: + int m_event; + Window m_window; + Time m_time; + KeyCode m_keycode; + }; - Display* openDisplay(const char* displayName); - void saveShape(); - void setShape(SInt32 width, SInt32 height); - Window openWindow() const; - void openIM(); + Display *openDisplay(const char *displayName); + void saveShape(); + void setShape(SInt32 width, SInt32 height); + Window openWindow() const; + void openIM(); - bool grabMouseAndKeyboard(); - void onKeyPress(XKeyEvent&); - void onKeyRelease(XKeyEvent&, bool isRepeat); - bool onHotKey(XKeyEvent&, bool isRepeat); - void onMousePress(const XButtonEvent&); - void onMouseRelease(const XButtonEvent&); - void onMouseMove(const XMotionEvent&); + bool grabMouseAndKeyboard(); + void onKeyPress(XKeyEvent &); + void onKeyRelease(XKeyEvent &, bool isRepeat); + bool onHotKey(XKeyEvent &, bool isRepeat); + void onMousePress(const XButtonEvent &); + void onMouseRelease(const XButtonEvent &); + void onMouseMove(const XMotionEvent &); - bool detectXI2(); + bool detectXI2(); #ifdef HAVE_XI2 - void selectXIRawMotion(); + void selectXIRawMotion(); #endif - void selectEvents(Window) const; - void doSelectEvents(Window) const; + void selectEvents(Window) const; + void doSelectEvents(Window) const; - KeyID mapKeyFromX(XKeyEvent*) const; - ButtonID mapButtonFromX(const XButtonEvent*) const; - unsigned int mapButtonToX(ButtonID id) const; + KeyID mapKeyFromX(XKeyEvent *) const; + ButtonID mapButtonFromX(const XButtonEvent *) const; + unsigned int mapButtonToX(ButtonID id) const; - void warpCursorNoFlush(SInt32 x, SInt32 y); + void warpCursorNoFlush(SInt32 x, SInt32 y); - void refreshKeyboard(XEvent*); + void refreshKeyboard(XEvent *); - static Bool findKeyEvent(Display*, XEvent* xevent, XPointer arg); + static Bool findKeyEvent(Display *, XEvent *xevent, XPointer arg); private: - struct HotKeyItem { - public: - HotKeyItem(int, unsigned int); + struct HotKeyItem { + public: + HotKeyItem(int, unsigned int); - bool operator<(const HotKeyItem&) const; + bool operator<(const HotKeyItem &) const; - private: - int m_keycode; - unsigned int m_mask; - }; - typedef std::set FilteredKeycodes; - typedef std::vector > HotKeyList; - typedef std::map HotKeyMap; - typedef std::vector HotKeyIDList; - typedef std::map HotKeyToIDMap; + private: + int m_keycode; + unsigned int m_mask; + }; + typedef std::set FilteredKeycodes; + typedef std::vector> HotKeyList; + typedef std::map HotKeyMap; + typedef std::vector HotKeyIDList; + typedef std::map HotKeyToIDMap; - // true if screen is being used as a primary screen, false otherwise - bool m_isPrimary; - int m_mouseScrollDelta; + // true if screen is being used as a primary screen, false otherwise + bool m_isPrimary; + int m_mouseScrollDelta; - Display* m_display; - Window m_root; - Window m_window; + Display *m_display; + Window m_root; + Window m_window; - // true if mouse has entered the screen - bool m_isOnScreen; + // true if mouse has entered the screen + bool m_isOnScreen; - // screen shape stuff - SInt32 m_x, m_y; - SInt32 m_w, m_h; - SInt32 m_xCenter, m_yCenter; + // screen shape stuff + SInt32 m_x, m_y; + SInt32 m_w, m_h; + SInt32 m_xCenter, m_yCenter; - // last mouse position - SInt32 m_xCursor, m_yCursor; + // last mouse position + SInt32 m_xCursor, m_yCursor; - // keyboard stuff - XWindowsKeyState* m_keyState; + // keyboard stuff + XWindowsKeyState *m_keyState; - // hot key stuff - HotKeyMap m_hotKeys; - HotKeyIDList m_oldHotKeyIDs; - HotKeyToIDMap m_hotKeyToIDMap; + // hot key stuff + HotKeyMap m_hotKeys; + HotKeyIDList m_oldHotKeyIDs; + HotKeyToIDMap m_hotKeyToIDMap; - // input focus stuff - Window m_lastFocus; - int m_lastFocusRevert; + // input focus stuff + Window m_lastFocus; + int m_lastFocusRevert; - // input method stuff - XIM m_im; - XIC m_ic; - KeyCode m_lastKeycode; - FilteredKeycodes m_filtered; + // input method stuff + XIM m_im; + XIC m_ic; + KeyCode m_lastKeycode; + FilteredKeycodes m_filtered; - // clipboards - XWindowsClipboard* m_clipboard[kClipboardEnd]; - UInt32 m_sequenceNumber; + // clipboards + XWindowsClipboard *m_clipboard[kClipboardEnd]; + UInt32 m_sequenceNumber; - // screen saver stuff - XWindowsScreenSaver* m_screensaver; - bool m_screensaverNotify; + // screen saver stuff + XWindowsScreenSaver *m_screensaver; + bool m_screensaverNotify; - // logical to physical button mapping. m_buttons[i] gives the - // physical button for logical button i+1. - std::vector m_buttons; + // logical to physical button mapping. m_buttons[i] gives the + // physical button for logical button i+1. + std::vector m_buttons; - // true if global auto-repeat was enabled before we turned it off - bool m_autoRepeat; + // true if global auto-repeat was enabled before we turned it off + bool m_autoRepeat; - // stuff to workaround xtest being xinerama unaware. attempting - // to fake a mouse motion under xinerama may behave strangely, - // especially if screen 0 is not at 0,0 or if faking a motion on - // a screen other than screen 0. - bool m_xtestIsXineramaUnaware; - bool m_xinerama; + // stuff to workaround xtest being xinerama unaware. attempting + // to fake a mouse motion under xinerama may behave strangely, + // especially if screen 0 is not at 0,0 or if faking a motion on + // a screen other than screen 0. + bool m_xtestIsXineramaUnaware; + bool m_xinerama; - // stuff to work around lost focus issues on certain systems - // (ie: a MythTV front-end). - bool m_preserveFocus; + // stuff to work around lost focus issues on certain systems + // (ie: a MythTV front-end). + bool m_preserveFocus; - // XKB extension stuff - bool m_xkb; - int m_xkbEventBase; + // XKB extension stuff + bool m_xkb; + int m_xkbEventBase; - bool m_xi2detected; + bool m_xi2detected; - // XRandR extension stuff - bool m_xrandr; - int m_xrandrEventBase; + // XRandR extension stuff + bool m_xrandr; + int m_xrandrEventBase; - IEventQueue* m_events; - synergy::KeyMap m_keyMap; + IEventQueue *m_events; + synergy::KeyMap m_keyMap; - // pointer to (singleton) screen. this is only needed by - // ioErrorHandler(). - static XWindowsScreen* s_screen; - XWindowsPowerManager m_powerManager; + // pointer to (singleton) screen. this is only needed by + // ioErrorHandler(). + static XWindowsScreen *s_screen; + XWindowsPowerManager m_powerManager; }; diff --git a/src/lib/platform/XWindowsScreenSaver.cpp b/src/lib/platform/XWindowsScreenSaver.cpp index 239ddc141..07f03db9c 100644 --- a/src/lib/platform/XWindowsScreenSaver.cpp +++ b/src/lib/platform/XWindowsScreenSaver.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -18,39 +18,39 @@ #include "platform/XWindowsScreenSaver.h" -#include "platform/XWindowsUtil.h" -#include "synergy/IPlatformScreen.h" -#include "base/Log.h" #include "base/Event.h" #include "base/IEventQueue.h" +#include "base/Log.h" #include "base/TMethodEventJob.h" +#include "platform/XWindowsUtil.h" +#include "synergy/IPlatformScreen.h" #include #if HAVE_X11_EXTENSIONS_XTEST_H -# include +#include #else -# error The XTest extension is required to build synergy +#error The XTest extension is required to build synergy #endif #if HAVE_X11_EXTENSIONS_DPMS_H extern "C" { -# include -# include -# if !HAVE_DPMS_PROTOTYPES -# undef DPMSModeOn -# undef DPMSModeStandby -# undef DPMSModeSuspend -# undef DPMSModeOff -# define DPMSModeOn 0 -# define DPMSModeStandby 1 -# define DPMSModeSuspend 2 -# define DPMSModeOff 3 +#include +#include +#if !HAVE_DPMS_PROTOTYPES +#undef DPMSModeOn +#undef DPMSModeStandby +#undef DPMSModeSuspend +#undef DPMSModeOff +#define DPMSModeOn 0 +#define DPMSModeStandby 1 +#define DPMSModeSuspend 2 +#define DPMSModeOff 3 extern Bool DPMSQueryExtension(Display *, int *, int *); extern Bool DPMSCapable(Display *); extern Status DPMSEnable(Display *); extern Status DPMSDisable(Display *); extern Status DPMSForceLevel(Display *, CARD16); extern Status DPMSInfo(Display *, CARD16 *, BOOL *); -# endif +#endif } #endif @@ -58,548 +58,489 @@ extern Status DPMSInfo(Display *, CARD16 *, BOOL *); // XWindowsScreenSaver // -XWindowsScreenSaver::XWindowsScreenSaver( - Display* display, Window window, void* eventTarget, IEventQueue* events) : - m_display(display), - m_xscreensaverSink(window), - m_eventTarget(eventTarget), - m_xscreensaver(None), - m_xscreensaverActive(false), - m_dpms(false), - m_disabled(false), - m_suppressDisable(false), - m_disableTimer(NULL), - m_disablePos(0), - m_events(events) -{ - // get atoms - m_atomScreenSaver = XInternAtom(m_display, - "SCREENSAVER", False); - m_atomScreenSaverVersion = XInternAtom(m_display, - "_SCREENSAVER_VERSION", False); - m_atomScreenSaverActivate = XInternAtom(m_display, - "ACTIVATE", False); - m_atomScreenSaverDeactivate = XInternAtom(m_display, - "DEACTIVATE", False); +XWindowsScreenSaver::XWindowsScreenSaver(Display *display, Window window, + void *eventTarget, IEventQueue *events) + : m_display(display), m_xscreensaverSink(window), + m_eventTarget(eventTarget), m_xscreensaver(None), + m_xscreensaverActive(false), m_dpms(false), m_disabled(false), + m_suppressDisable(false), m_disableTimer(NULL), m_disablePos(0), + m_events(events) { + // get atoms + m_atomScreenSaver = XInternAtom(m_display, "SCREENSAVER", False); + m_atomScreenSaverVersion = + XInternAtom(m_display, "_SCREENSAVER_VERSION", False); + m_atomScreenSaverActivate = XInternAtom(m_display, "ACTIVATE", False); + m_atomScreenSaverDeactivate = XInternAtom(m_display, "DEACTIVATE", False); - // check for DPMS extension. this is an alternative screen saver - // that powers down the display. + // check for DPMS extension. this is an alternative screen saver + // that powers down the display. #if HAVE_X11_EXTENSIONS_DPMS_H - int eventBase, errorBase; - if (DPMSQueryExtension(m_display, &eventBase, &errorBase)) { - if (DPMSCapable(m_display)) { - // we have DPMS - m_dpms = true; - } + int eventBase, errorBase; + if (DPMSQueryExtension(m_display, &eventBase, &errorBase)) { + if (DPMSCapable(m_display)) { + // we have DPMS + m_dpms = true; } + } #endif - // watch top-level windows for changes - bool error = false; - { - XWindowsUtil::ErrorLock lock(m_display, &error); - Window root = DefaultRootWindow(m_display); - XWindowAttributes attr; - XGetWindowAttributes(m_display, root, &attr); - m_rootEventMask = attr.your_event_mask; - XSelectInput(m_display, root, m_rootEventMask | SubstructureNotifyMask); - } - if (error) { - LOG((CLOG_DEBUG "didn't set root event mask")); - m_rootEventMask = 0; - } + // watch top-level windows for changes + bool error = false; + { + XWindowsUtil::ErrorLock lock(m_display, &error); + Window root = DefaultRootWindow(m_display); + XWindowAttributes attr; + XGetWindowAttributes(m_display, root, &attr); + m_rootEventMask = attr.your_event_mask; + XSelectInput(m_display, root, m_rootEventMask | SubstructureNotifyMask); + } + if (error) { + LOG((CLOG_DEBUG "didn't set root event mask")); + m_rootEventMask = 0; + } - // get the built-in settings - XGetScreenSaver(m_display, &m_timeout, &m_interval, - &m_preferBlanking, &m_allowExposures); + // get the built-in settings + XGetScreenSaver(m_display, &m_timeout, &m_interval, &m_preferBlanking, + &m_allowExposures); - // get the DPMS settings - m_dpmsEnabled = isDPMSEnabled(); + // get the DPMS settings + m_dpmsEnabled = isDPMSEnabled(); - // get the xscreensaver window, if any - if (!findXScreenSaver()) { - setXScreenSaver(None); - } + // get the xscreensaver window, if any + if (!findXScreenSaver()) { + setXScreenSaver(None); + } - // install disable timer event handler - m_events->adoptHandler(Event::kTimer, this, - new TMethodEventJob(this, - &XWindowsScreenSaver::handleDisableTimer)); + // install disable timer event handler + m_events->adoptHandler(Event::kTimer, this, + new TMethodEventJob( + this, &XWindowsScreenSaver::handleDisableTimer)); } -XWindowsScreenSaver::~XWindowsScreenSaver() -{ - // done with disable job - if (m_disableTimer != NULL) { - m_events->deleteTimer(m_disableTimer); - } - m_events->removeHandler(Event::kTimer, this); +XWindowsScreenSaver::~XWindowsScreenSaver() { + // done with disable job + if (m_disableTimer != NULL) { + m_events->deleteTimer(m_disableTimer); + } + m_events->removeHandler(Event::kTimer, this); - if (m_display != NULL) { - enableDPMS(m_dpmsEnabled); - XSetScreenSaver(m_display, m_timeout, m_interval, - m_preferBlanking, m_allowExposures); - clearWatchForXScreenSaver(); - XWindowsUtil::ErrorLock lock(m_display); - XSelectInput(m_display, DefaultRootWindow(m_display), m_rootEventMask); - } -} - -void -XWindowsScreenSaver::destroy() -{ - m_display = NULL; - delete this; -} - -bool -XWindowsScreenSaver::handleXEvent(const XEvent* xevent) -{ - switch (xevent->type) { - case CreateNotify: - if (m_xscreensaver == None) { - if (isXScreenSaver(xevent->xcreatewindow.window)) { - // found the xscreensaver - setXScreenSaver(xevent->xcreatewindow.window); - } - else { - // another window to watch. to detect the xscreensaver - // window we look for a property but that property may - // not yet exist by the time we get this event so we - // have to watch the window for property changes. - // this would be so much easier if xscreensaver did the - // smart thing and stored its window in a property on - // the root window. - addWatchXScreenSaver(xevent->xcreatewindow.window); - } - } - break; - - case DestroyNotify: - if (xevent->xdestroywindow.window == m_xscreensaver) { - // xscreensaver is gone - LOG((CLOG_DEBUG "xscreensaver died")); - setXScreenSaver(None); - return true; - } - break; - - case PropertyNotify: - if (xevent->xproperty.state == PropertyNewValue) { - if (isXScreenSaver(xevent->xproperty.window)) { - // found the xscreensaver - setXScreenSaver(xevent->xcreatewindow.window); - } - } - break; - - case MapNotify: - if (xevent->xmap.window == m_xscreensaver) { - // xscreensaver has activated - setXScreenSaverActive(true); - return true; - } - break; - - case UnmapNotify: - if (xevent->xunmap.window == m_xscreensaver) { - // xscreensaver has deactivated - setXScreenSaverActive(false); - return true; - } - break; - } - - return false; -} - -void -XWindowsScreenSaver::enable() -{ - // for xscreensaver - m_disabled = false; - updateDisableTimer(); - - // for built-in X screen saver - XSetScreenSaver(m_display, m_timeout, m_interval, - m_preferBlanking, m_allowExposures); - - // for DPMS + if (m_display != NULL) { enableDPMS(m_dpmsEnabled); -} - -void -XWindowsScreenSaver::disable() -{ - // for xscreensaver - m_disabled = true; - updateDisableTimer(); - - // use built-in X screen saver - XGetScreenSaver(m_display, &m_timeout, &m_interval, - &m_preferBlanking, &m_allowExposures); - XSetScreenSaver(m_display, 0, m_interval, - m_preferBlanking, m_allowExposures); - - // for DPMS - m_dpmsEnabled = isDPMSEnabled(); - enableDPMS(false); - - // FIXME -- now deactivate? -} - -void -XWindowsScreenSaver::activate() -{ - // remove disable job timer - m_suppressDisable = true; - updateDisableTimer(); - - // enable DPMS if it was enabled - enableDPMS(m_dpmsEnabled); - - // try xscreensaver - findXScreenSaver(); - if (m_xscreensaver != None) { - sendXScreenSaverCommand(m_atomScreenSaverActivate); - return; - } - - // try built-in X screen saver - if (m_timeout != 0) { - XForceScreenSaver(m_display, ScreenSaverActive); - } - - // try DPMS - activateDPMS(true); -} - -void -XWindowsScreenSaver::deactivate() -{ - // reinstall disable job timer - m_suppressDisable = false; - updateDisableTimer(); - - // try DPMS - activateDPMS(false); - - // disable DPMS if screen saver is disabled - if (m_disabled) { - enableDPMS(false); - } - - // try xscreensaver - findXScreenSaver(); - if (m_xscreensaver != None) { - sendXScreenSaverCommand(m_atomScreenSaverDeactivate); - return; - } - - // use built-in X screen saver - XForceScreenSaver(m_display, ScreenSaverReset); -} - -bool -XWindowsScreenSaver::isActive() const -{ - // check xscreensaver - if (m_xscreensaver != None) { - return m_xscreensaverActive; - } - - // check DPMS - if (isDPMSActivated()) { - return true; - } - - // can't check built-in X screen saver activity - return false; -} - -bool -XWindowsScreenSaver::findXScreenSaver() -{ - // do nothing if we've already got the xscreensaver window - if (m_xscreensaver == None) { - // find top-level window xscreensaver window - Window root = DefaultRootWindow(m_display); - Window rw, pw, *cw; - unsigned int nc; - if (XQueryTree(m_display, root, &rw, &pw, &cw, &nc)) { - for (unsigned int i = 0; i < nc; ++i) { - if (isXScreenSaver(cw[i])) { - setXScreenSaver(cw[i]); - break; - } - } - XFree(cw); - } - } - - return (m_xscreensaver != None); -} - -void -XWindowsScreenSaver::setXScreenSaver(Window window) -{ - LOG((CLOG_DEBUG "xscreensaver window: 0x%08x", window)); - - // save window - m_xscreensaver = window; - - if (m_xscreensaver != None) { - // clear old watch list - clearWatchForXScreenSaver(); - - // see if xscreensaver is active - bool error = false; - XWindowAttributes attr; - { - XWindowsUtil::ErrorLock lock(m_display, &error); - XGetWindowAttributes(m_display, m_xscreensaver, &attr); - } - setXScreenSaverActive(!error && attr.map_state != IsUnmapped); - - // save current DPMS state; xscreensaver may have changed it. - m_dpmsEnabled = isDPMSEnabled(); - } - else { - // screen saver can't be active if it doesn't exist - setXScreenSaverActive(false); - - // start watching for xscreensaver - watchForXScreenSaver(); - } -} - -bool -XWindowsScreenSaver::isXScreenSaver(Window w) const -{ - // check for m_atomScreenSaverVersion string property - Atom type; - return (XWindowsUtil::getWindowProperty(m_display, w, - m_atomScreenSaverVersion, - NULL, &type, NULL, False) && - type == XA_STRING); -} - -void -XWindowsScreenSaver::setXScreenSaverActive(bool activated) -{ - if (m_xscreensaverActive != activated) { - LOG((CLOG_DEBUG "xscreensaver %s on window 0x%08x", activated ? "activated" : "deactivated", m_xscreensaver)); - m_xscreensaverActive = activated; - - // if screen saver was activated forcefully (i.e. against - // our will) then just accept it. don't try to keep it - // from activating since that'll just pop up the password - // dialog if locking is enabled. - m_suppressDisable = activated; - updateDisableTimer(); - - if (activated) { - m_events->addEvent(Event( - m_events->forIPrimaryScreen().screensaverActivated(), - m_eventTarget)); - } - else { - m_events->addEvent(Event( - m_events->forIPrimaryScreen().screensaverDeactivated(), - m_eventTarget)); - } - } -} - -void -XWindowsScreenSaver::sendXScreenSaverCommand(Atom cmd, long arg1, long arg2) -{ - XEvent event; - event.xclient.type = ClientMessage; - event.xclient.display = m_display; - event.xclient.window = m_xscreensaverSink; - event.xclient.message_type = m_atomScreenSaver; - event.xclient.format = 32; - event.xclient.data.l[0] = static_cast(cmd); - event.xclient.data.l[1] = arg1; - event.xclient.data.l[2] = arg2; - event.xclient.data.l[3] = 0; - event.xclient.data.l[4] = 0; - - LOG((CLOG_DEBUG "send xscreensaver command: %d %d %d", (long)cmd, arg1, arg2)); - bool error = false; - { - XWindowsUtil::ErrorLock lock(m_display, &error); - XSendEvent(m_display, m_xscreensaver, False, 0, &event); - } - if (error) { - findXScreenSaver(); - } -} - -void -XWindowsScreenSaver::watchForXScreenSaver() -{ - // clear old watch list + XSetScreenSaver(m_display, m_timeout, m_interval, m_preferBlanking, + m_allowExposures); clearWatchForXScreenSaver(); + XWindowsUtil::ErrorLock lock(m_display); + XSelectInput(m_display, DefaultRootWindow(m_display), m_rootEventMask); + } +} - // add every child of the root to the list of windows to watch +void XWindowsScreenSaver::destroy() { + m_display = NULL; + delete this; +} + +bool XWindowsScreenSaver::handleXEvent(const XEvent *xevent) { + switch (xevent->type) { + case CreateNotify: + if (m_xscreensaver == None) { + if (isXScreenSaver(xevent->xcreatewindow.window)) { + // found the xscreensaver + setXScreenSaver(xevent->xcreatewindow.window); + } else { + // another window to watch. to detect the xscreensaver + // window we look for a property but that property may + // not yet exist by the time we get this event so we + // have to watch the window for property changes. + // this would be so much easier if xscreensaver did the + // smart thing and stored its window in a property on + // the root window. + addWatchXScreenSaver(xevent->xcreatewindow.window); + } + } + break; + + case DestroyNotify: + if (xevent->xdestroywindow.window == m_xscreensaver) { + // xscreensaver is gone + LOG((CLOG_DEBUG "xscreensaver died")); + setXScreenSaver(None); + return true; + } + break; + + case PropertyNotify: + if (xevent->xproperty.state == PropertyNewValue) { + if (isXScreenSaver(xevent->xproperty.window)) { + // found the xscreensaver + setXScreenSaver(xevent->xcreatewindow.window); + } + } + break; + + case MapNotify: + if (xevent->xmap.window == m_xscreensaver) { + // xscreensaver has activated + setXScreenSaverActive(true); + return true; + } + break; + + case UnmapNotify: + if (xevent->xunmap.window == m_xscreensaver) { + // xscreensaver has deactivated + setXScreenSaverActive(false); + return true; + } + break; + } + + return false; +} + +void XWindowsScreenSaver::enable() { + // for xscreensaver + m_disabled = false; + updateDisableTimer(); + + // for built-in X screen saver + XSetScreenSaver(m_display, m_timeout, m_interval, m_preferBlanking, + m_allowExposures); + + // for DPMS + enableDPMS(m_dpmsEnabled); +} + +void XWindowsScreenSaver::disable() { + // for xscreensaver + m_disabled = true; + updateDisableTimer(); + + // use built-in X screen saver + XGetScreenSaver(m_display, &m_timeout, &m_interval, &m_preferBlanking, + &m_allowExposures); + XSetScreenSaver(m_display, 0, m_interval, m_preferBlanking, m_allowExposures); + + // for DPMS + m_dpmsEnabled = isDPMSEnabled(); + enableDPMS(false); + + // FIXME -- now deactivate? +} + +void XWindowsScreenSaver::activate() { + // remove disable job timer + m_suppressDisable = true; + updateDisableTimer(); + + // enable DPMS if it was enabled + enableDPMS(m_dpmsEnabled); + + // try xscreensaver + findXScreenSaver(); + if (m_xscreensaver != None) { + sendXScreenSaverCommand(m_atomScreenSaverActivate); + return; + } + + // try built-in X screen saver + if (m_timeout != 0) { + XForceScreenSaver(m_display, ScreenSaverActive); + } + + // try DPMS + activateDPMS(true); +} + +void XWindowsScreenSaver::deactivate() { + // reinstall disable job timer + m_suppressDisable = false; + updateDisableTimer(); + + // try DPMS + activateDPMS(false); + + // disable DPMS if screen saver is disabled + if (m_disabled) { + enableDPMS(false); + } + + // try xscreensaver + findXScreenSaver(); + if (m_xscreensaver != None) { + sendXScreenSaverCommand(m_atomScreenSaverDeactivate); + return; + } + + // use built-in X screen saver + XForceScreenSaver(m_display, ScreenSaverReset); +} + +bool XWindowsScreenSaver::isActive() const { + // check xscreensaver + if (m_xscreensaver != None) { + return m_xscreensaverActive; + } + + // check DPMS + if (isDPMSActivated()) { + return true; + } + + // can't check built-in X screen saver activity + return false; +} + +bool XWindowsScreenSaver::findXScreenSaver() { + // do nothing if we've already got the xscreensaver window + if (m_xscreensaver == None) { + // find top-level window xscreensaver window Window root = DefaultRootWindow(m_display); Window rw, pw, *cw; unsigned int nc; if (XQueryTree(m_display, root, &rw, &pw, &cw, &nc)) { - for (unsigned int i = 0; i < nc; ++i) { - addWatchXScreenSaver(cw[i]); + for (unsigned int i = 0; i < nc; ++i) { + if (isXScreenSaver(cw[i])) { + setXScreenSaver(cw[i]); + break; } - XFree(cw); + } + XFree(cw); } + } - // now check for xscreensaver window in case it set the property - // before we could request property change events. - if (findXScreenSaver()) { - // found it so clear out our watch list - clearWatchForXScreenSaver(); - } + return (m_xscreensaver != None); } -void -XWindowsScreenSaver::clearWatchForXScreenSaver() -{ - // stop watching all windows - XWindowsUtil::ErrorLock lock(m_display); - for (WatchList::iterator index = m_watchWindows.begin(); - index != m_watchWindows.end(); ++index) { - XSelectInput(m_display, index->first, index->second); - } - m_watchWindows.clear(); -} +void XWindowsScreenSaver::setXScreenSaver(Window window) { + LOG((CLOG_DEBUG "xscreensaver window: 0x%08x", window)); -void -XWindowsScreenSaver::addWatchXScreenSaver(Window window) -{ - // get window attributes + // save window + m_xscreensaver = window; + + if (m_xscreensaver != None) { + // clear old watch list + clearWatchForXScreenSaver(); + + // see if xscreensaver is active bool error = false; XWindowAttributes attr; { - XWindowsUtil::ErrorLock lock(m_display, &error); - XGetWindowAttributes(m_display, window, &attr); + XWindowsUtil::ErrorLock lock(m_display, &error); + XGetWindowAttributes(m_display, m_xscreensaver, &attr); } + setXScreenSaverActive(!error && attr.map_state != IsUnmapped); - // if successful and window uses override_redirect (like xscreensaver - // does) then watch it for property changes. - if (!error && attr.override_redirect == True) { - error = false; - { - XWindowsUtil::ErrorLock lock(m_display, &error); - XSelectInput(m_display, window, - attr.your_event_mask | PropertyChangeMask); - } - if (!error) { - // if successful then add the window to our list - m_watchWindows.insert(std::make_pair(window, attr.your_event_mask)); - } - } + // save current DPMS state; xscreensaver may have changed it. + m_dpmsEnabled = isDPMSEnabled(); + } else { + // screen saver can't be active if it doesn't exist + setXScreenSaverActive(false); + + // start watching for xscreensaver + watchForXScreenSaver(); + } } -void -XWindowsScreenSaver::updateDisableTimer() -{ - if (m_disabled && !m_suppressDisable && m_disableTimer == NULL) { - // 5 seconds should be plenty often to suppress the screen saver - m_disableTimer = m_events->newTimer(5.0, this); - } - else if ((!m_disabled || m_suppressDisable) && m_disableTimer != NULL) { - m_events->deleteTimer(m_disableTimer); - m_disableTimer = NULL; - } +bool XWindowsScreenSaver::isXScreenSaver(Window w) const { + // check for m_atomScreenSaverVersion string property + Atom type; + return (XWindowsUtil::getWindowProperty(m_display, w, + m_atomScreenSaverVersion, NULL, &type, + NULL, False) && + type == XA_STRING); } -void -XWindowsScreenSaver::handleDisableTimer(const Event&, void*) -{ - // send fake mouse motion directly to xscreensaver - if (m_xscreensaver != None) { - XEvent event; - event.xmotion.type = MotionNotify; - event.xmotion.display = m_display; - event.xmotion.window = m_xscreensaver; - event.xmotion.root = DefaultRootWindow(m_display); - event.xmotion.subwindow = None; - event.xmotion.time = CurrentTime; - event.xmotion.x = m_disablePos; - event.xmotion.y = 0; - event.xmotion.x_root = m_disablePos; - event.xmotion.y_root = 0; - event.xmotion.state = 0; - event.xmotion.is_hint = NotifyNormal; - event.xmotion.same_screen = True; +void XWindowsScreenSaver::setXScreenSaverActive(bool activated) { + if (m_xscreensaverActive != activated) { + LOG((CLOG_DEBUG "xscreensaver %s on window 0x%08x", + activated ? "activated" : "deactivated", m_xscreensaver)); + m_xscreensaverActive = activated; - XWindowsUtil::ErrorLock lock(m_display); - XSendEvent(m_display, m_xscreensaver, False, 0, &event); + // if screen saver was activated forcefully (i.e. against + // our will) then just accept it. don't try to keep it + // from activating since that'll just pop up the password + // dialog if locking is enabled. + m_suppressDisable = activated; + updateDisableTimer(); - m_disablePos = 20 - m_disablePos; + if (activated) { + m_events->addEvent(Event( + m_events->forIPrimaryScreen().screensaverActivated(), m_eventTarget)); + } else { + m_events->addEvent( + Event(m_events->forIPrimaryScreen().screensaverDeactivated(), + m_eventTarget)); } + } } -void -XWindowsScreenSaver::activateDPMS(bool activate) -{ +void XWindowsScreenSaver::sendXScreenSaverCommand(Atom cmd, long arg1, + long arg2) { + XEvent event; + event.xclient.type = ClientMessage; + event.xclient.display = m_display; + event.xclient.window = m_xscreensaverSink; + event.xclient.message_type = m_atomScreenSaver; + event.xclient.format = 32; + event.xclient.data.l[0] = static_cast(cmd); + event.xclient.data.l[1] = arg1; + event.xclient.data.l[2] = arg2; + event.xclient.data.l[3] = 0; + event.xclient.data.l[4] = 0; + + LOG((CLOG_DEBUG "send xscreensaver command: %d %d %d", (long)cmd, arg1, + arg2)); + bool error = false; + { + XWindowsUtil::ErrorLock lock(m_display, &error); + XSendEvent(m_display, m_xscreensaver, False, 0, &event); + } + if (error) { + findXScreenSaver(); + } +} + +void XWindowsScreenSaver::watchForXScreenSaver() { + // clear old watch list + clearWatchForXScreenSaver(); + + // add every child of the root to the list of windows to watch + Window root = DefaultRootWindow(m_display); + Window rw, pw, *cw; + unsigned int nc; + if (XQueryTree(m_display, root, &rw, &pw, &cw, &nc)) { + for (unsigned int i = 0; i < nc; ++i) { + addWatchXScreenSaver(cw[i]); + } + XFree(cw); + } + + // now check for xscreensaver window in case it set the property + // before we could request property change events. + if (findXScreenSaver()) { + // found it so clear out our watch list + clearWatchForXScreenSaver(); + } +} + +void XWindowsScreenSaver::clearWatchForXScreenSaver() { + // stop watching all windows + XWindowsUtil::ErrorLock lock(m_display); + for (WatchList::iterator index = m_watchWindows.begin(); + index != m_watchWindows.end(); ++index) { + XSelectInput(m_display, index->first, index->second); + } + m_watchWindows.clear(); +} + +void XWindowsScreenSaver::addWatchXScreenSaver(Window window) { + // get window attributes + bool error = false; + XWindowAttributes attr; + { + XWindowsUtil::ErrorLock lock(m_display, &error); + XGetWindowAttributes(m_display, window, &attr); + } + + // if successful and window uses override_redirect (like xscreensaver + // does) then watch it for property changes. + if (!error && attr.override_redirect == True) { + error = false; + { + XWindowsUtil::ErrorLock lock(m_display, &error); + XSelectInput(m_display, window, + attr.your_event_mask | PropertyChangeMask); + } + if (!error) { + // if successful then add the window to our list + m_watchWindows.insert(std::make_pair(window, attr.your_event_mask)); + } + } +} + +void XWindowsScreenSaver::updateDisableTimer() { + if (m_disabled && !m_suppressDisable && m_disableTimer == NULL) { + // 5 seconds should be plenty often to suppress the screen saver + m_disableTimer = m_events->newTimer(5.0, this); + } else if ((!m_disabled || m_suppressDisable) && m_disableTimer != NULL) { + m_events->deleteTimer(m_disableTimer); + m_disableTimer = NULL; + } +} + +void XWindowsScreenSaver::handleDisableTimer(const Event &, void *) { + // send fake mouse motion directly to xscreensaver + if (m_xscreensaver != None) { + XEvent event; + event.xmotion.type = MotionNotify; + event.xmotion.display = m_display; + event.xmotion.window = m_xscreensaver; + event.xmotion.root = DefaultRootWindow(m_display); + event.xmotion.subwindow = None; + event.xmotion.time = CurrentTime; + event.xmotion.x = m_disablePos; + event.xmotion.y = 0; + event.xmotion.x_root = m_disablePos; + event.xmotion.y_root = 0; + event.xmotion.state = 0; + event.xmotion.is_hint = NotifyNormal; + event.xmotion.same_screen = True; + + XWindowsUtil::ErrorLock lock(m_display); + XSendEvent(m_display, m_xscreensaver, False, 0, &event); + + m_disablePos = 20 - m_disablePos; + } +} + +void XWindowsScreenSaver::activateDPMS(bool activate) { #if HAVE_X11_EXTENSIONS_DPMS_H - if (m_dpms) { - // DPMSForceLevel will generate a BadMatch if DPMS is disabled - XWindowsUtil::ErrorLock lock(m_display); - DPMSForceLevel(m_display, activate ? DPMSModeStandby : DPMSModeOn); - } + if (m_dpms) { + // DPMSForceLevel will generate a BadMatch if DPMS is disabled + XWindowsUtil::ErrorLock lock(m_display); + DPMSForceLevel(m_display, activate ? DPMSModeStandby : DPMSModeOn); + } #endif } -void -XWindowsScreenSaver::enableDPMS(bool enable) -{ +void XWindowsScreenSaver::enableDPMS(bool enable) { #if HAVE_X11_EXTENSIONS_DPMS_H - if (m_dpms) { - if (enable) { - DPMSEnable(m_display); - } - else { - DPMSDisable(m_display); - } + if (m_dpms) { + if (enable) { + DPMSEnable(m_display); + } else { + DPMSDisable(m_display); } + } #endif } -bool -XWindowsScreenSaver::isDPMSEnabled() const -{ +bool XWindowsScreenSaver::isDPMSEnabled() const { #if HAVE_X11_EXTENSIONS_DPMS_H - if (m_dpms) { - CARD16 level; - BOOL state; - DPMSInfo(m_display, &level, &state); - return (state != False); - } - else { - return false; - } -#else + if (m_dpms) { + CARD16 level; + BOOL state; + DPMSInfo(m_display, &level, &state); + return (state != False); + } else { return false; + } +#else + return false; #endif } -bool -XWindowsScreenSaver::isDPMSActivated() const -{ +bool XWindowsScreenSaver::isDPMSActivated() const { #if HAVE_X11_EXTENSIONS_DPMS_H - if (m_dpms) { - CARD16 level; - BOOL state; - DPMSInfo(m_display, &level, &state); - return (level != DPMSModeOn); - } - else { - return false; - } -#else + if (m_dpms) { + CARD16 level; + BOOL state; + DPMSInfo(m_display, &level, &state); + return (level != DPMSModeOn); + } else { return false; + } +#else + return false; #endif } diff --git a/src/lib/platform/XWindowsScreenSaver.h b/src/lib/platform/XWindowsScreenSaver.h index 0255363d1..4c05d30c1 100644 --- a/src/lib/platform/XWindowsScreenSaver.h +++ b/src/lib/platform/XWindowsScreenSaver.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -18,14 +18,14 @@ #pragma once -#include "synergy/IScreenSaver.h" #include "base/IEventQueue.h" #include "common/stdmap.h" +#include "synergy/IScreenSaver.h" #if X_DISPLAY_MISSING -# error X11 is required to build synergy +#error X11 is required to build synergy #else -# include +#include #endif class Event; @@ -34,141 +34,142 @@ class EventQueueTimer; //! X11 screen saver implementation class XWindowsScreenSaver : public IScreenSaver { public: - XWindowsScreenSaver(Display*, Window, void* eventTarget, IEventQueue* events); - XWindowsScreenSaver(XWindowsScreenSaver const &) =delete; - XWindowsScreenSaver(XWindowsScreenSaver &&) =delete; - virtual ~XWindowsScreenSaver(); + XWindowsScreenSaver(Display *, Window, void *eventTarget, + IEventQueue *events); + XWindowsScreenSaver(XWindowsScreenSaver const &) = delete; + XWindowsScreenSaver(XWindowsScreenSaver &&) = delete; + virtual ~XWindowsScreenSaver(); - XWindowsScreenSaver& operator=(XWindowsScreenSaver const &) =delete; - XWindowsScreenSaver& operator=(XWindowsScreenSaver &&) =delete; + XWindowsScreenSaver &operator=(XWindowsScreenSaver const &) = delete; + XWindowsScreenSaver &operator=(XWindowsScreenSaver &&) = delete; - //! @name manipulators - //@{ + //! @name manipulators + //@{ - //! Event filtering - /*! - Should be called for each system event before event translation and - dispatch. Returns true to skip translation and dispatch. - */ - bool handleXEvent(const XEvent*); + //! Event filtering + /*! + Should be called for each system event before event translation and + dispatch. Returns true to skip translation and dispatch. + */ + bool handleXEvent(const XEvent *); - //! Destroy without the display - /*! - Tells this object to delete itself without using the X11 display. - It may leak some resources as a result. - */ - void destroy(); + //! Destroy without the display + /*! + Tells this object to delete itself without using the X11 display. + It may leak some resources as a result. + */ + void destroy(); - //@} + //@} - // IScreenSaver overrides - virtual void enable(); - virtual void disable(); - virtual void activate(); - virtual void deactivate(); - virtual bool isActive() const; + // IScreenSaver overrides + virtual void enable(); + virtual void disable(); + virtual void activate(); + virtual void deactivate(); + virtual bool isActive() const; private: - // find and set the running xscreensaver's window. returns true iff - // found. - bool findXScreenSaver(); + // find and set the running xscreensaver's window. returns true iff + // found. + bool findXScreenSaver(); - // set the xscreensaver's window, updating the activation state flag - void setXScreenSaver(Window); + // set the xscreensaver's window, updating the activation state flag + void setXScreenSaver(Window); - // returns true if the window appears to be the xscreensaver window - bool isXScreenSaver(Window) const; + // returns true if the window appears to be the xscreensaver window + bool isXScreenSaver(Window) const; - // set xscreensaver's activation state flag. sends notification - // if the state has changed. - void setXScreenSaverActive(bool activated); + // set xscreensaver's activation state flag. sends notification + // if the state has changed. + void setXScreenSaverActive(bool activated); - // send a command to xscreensaver - void sendXScreenSaverCommand(Atom, long = 0, long = 0); + // send a command to xscreensaver + void sendXScreenSaverCommand(Atom, long = 0, long = 0); - // watch all windows that could potentially be the xscreensaver for - // the events that will confirm it. - void watchForXScreenSaver(); + // watch all windows that could potentially be the xscreensaver for + // the events that will confirm it. + void watchForXScreenSaver(); - // stop watching all watched windows - void clearWatchForXScreenSaver(); + // stop watching all watched windows + void clearWatchForXScreenSaver(); - // add window to the watch list - void addWatchXScreenSaver(Window window); + // add window to the watch list + void addWatchXScreenSaver(Window window); - // install/uninstall the job used to suppress the screensaver - void updateDisableTimer(); + // install/uninstall the job used to suppress the screensaver + void updateDisableTimer(); - // called periodically to prevent the screen saver from starting - void handleDisableTimer(const Event&, void*); + // called periodically to prevent the screen saver from starting + void handleDisableTimer(const Event &, void *); - // force DPMS to activate or deactivate - void activateDPMS(bool activate); + // force DPMS to activate or deactivate + void activateDPMS(bool activate); - // enable/disable DPMS screen saver - void enableDPMS(bool); + // enable/disable DPMS screen saver + void enableDPMS(bool); - // check if DPMS is enabled - bool isDPMSEnabled() const; + // check if DPMS is enabled + bool isDPMSEnabled() const; - // check if DPMS is activate - bool isDPMSActivated() const; + // check if DPMS is activate + bool isDPMSActivated() const; private: - typedef std::map WatchList; + typedef std::map WatchList; - // the X display - Display* m_display; + // the X display + Display *m_display; - // window to receive xscreensaver responses - Window m_xscreensaverSink; + // window to receive xscreensaver responses + Window m_xscreensaverSink; - // the target for the events we generate - void* m_eventTarget; + // the target for the events we generate + void *m_eventTarget; - // xscreensaver's window - Window m_xscreensaver; + // xscreensaver's window + Window m_xscreensaver; - // xscreensaver activation state - bool m_xscreensaverActive; + // xscreensaver activation state + bool m_xscreensaverActive; - // old event mask on root window - long m_rootEventMask; + // old event mask on root window + long m_rootEventMask; - // potential xscreensaver windows being watched - WatchList m_watchWindows; + // potential xscreensaver windows being watched + WatchList m_watchWindows; - // atoms used to communicate with xscreensaver's window - Atom m_atomScreenSaver; - Atom m_atomScreenSaverVersion; - Atom m_atomScreenSaverActivate; - Atom m_atomScreenSaverDeactivate; + // atoms used to communicate with xscreensaver's window + Atom m_atomScreenSaver; + Atom m_atomScreenSaverVersion; + Atom m_atomScreenSaverActivate; + Atom m_atomScreenSaverDeactivate; - // built-in screen saver settings - int m_timeout; - int m_interval; - int m_preferBlanking; - int m_allowExposures; + // built-in screen saver settings + int m_timeout; + int m_interval; + int m_preferBlanking; + int m_allowExposures; - // DPMS screen saver settings - bool m_dpms; - bool m_dpmsEnabled; + // DPMS screen saver settings + bool m_dpms; + bool m_dpmsEnabled; - // true iff the client wants the screen saver suppressed - bool m_disabled; + // true iff the client wants the screen saver suppressed + bool m_disabled; - // true iff we're ignoring m_disabled. this is true, for example, - // when the client has called activate() and so presumably wants - // to activate the screen saver even if disabled. - bool m_suppressDisable; + // true iff we're ignoring m_disabled. this is true, for example, + // when the client has called activate() and so presumably wants + // to activate the screen saver even if disabled. + bool m_suppressDisable; - // the disable timer (NULL if not installed) - EventQueueTimer* m_disableTimer; + // the disable timer (NULL if not installed) + EventQueueTimer *m_disableTimer; - // fake mouse motion position for suppressing the screen saver. - // xscreensaver since 2.21 requires the mouse to move more than 10 - // pixels to be considered significant. - SInt32 m_disablePos; + // fake mouse motion position for suppressing the screen saver. + // xscreensaver since 2.21 requires the mouse to move more than 10 + // pixels to be considered significant. + SInt32 m_disablePos; - IEventQueue* m_events; + IEventQueue *m_events; }; diff --git a/src/lib/platform/XWindowsUtil.cpp b/src/lib/platform/XWindowsUtil.cpp index 10cd36754..ceb412439 100644 --- a/src/lib/platform/XWindowsUtil.cpp +++ b/src/lib/platform/XWindowsUtil.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -18,10 +18,10 @@ #include "platform/XWindowsUtil.h" -#include "synergy/key_types.h" -#include "mt/Thread.h" #include "base/Log.h" #include "base/String.h" +#include "mt/Thread.h" +#include "synergy/key_types.h" #include #define XK_APL @@ -51,13 +51,13 @@ #include #if !defined(XK_OE) -#define XK_OE 0x13bc +#define XK_OE 0x13bc #endif #if !defined(XK_oe) -#define XK_oe 0x13bd +#define XK_oe 0x13bd #endif #if !defined(XK_Ydiaeresis) -#define XK_Ydiaeresis 0x13be +#define XK_Ydiaeresis 0x13be #endif /* @@ -77,877 +77,898 @@ */ struct codepair { - KeySym keysym; - UInt32 ucs4; + KeySym keysym; + UInt32 ucs4; } s_keymap[] = { -{ XK_Aogonek, 0x0104 }, /* LATIN CAPITAL LETTER A WITH OGONEK */ -{ XK_breve, 0x02d8 }, /* BREVE */ -{ XK_Lstroke, 0x0141 }, /* LATIN CAPITAL LETTER L WITH STROKE */ -{ XK_Lcaron, 0x013d }, /* LATIN CAPITAL LETTER L WITH CARON */ -{ XK_Sacute, 0x015a }, /* LATIN CAPITAL LETTER S WITH ACUTE */ -{ XK_Scaron, 0x0160 }, /* LATIN CAPITAL LETTER S WITH CARON */ -{ XK_Scedilla, 0x015e }, /* LATIN CAPITAL LETTER S WITH CEDILLA */ -{ XK_Tcaron, 0x0164 }, /* LATIN CAPITAL LETTER T WITH CARON */ -{ XK_Zacute, 0x0179 }, /* LATIN CAPITAL LETTER Z WITH ACUTE */ -{ XK_Zcaron, 0x017d }, /* LATIN CAPITAL LETTER Z WITH CARON */ -{ XK_Zabovedot, 0x017b }, /* LATIN CAPITAL LETTER Z WITH DOT ABOVE */ -{ XK_aogonek, 0x0105 }, /* LATIN SMALL LETTER A WITH OGONEK */ -{ XK_ogonek, 0x02db }, /* OGONEK */ -{ XK_lstroke, 0x0142 }, /* LATIN SMALL LETTER L WITH STROKE */ -{ XK_lcaron, 0x013e }, /* LATIN SMALL LETTER L WITH CARON */ -{ XK_sacute, 0x015b }, /* LATIN SMALL LETTER S WITH ACUTE */ -{ XK_caron, 0x02c7 }, /* CARON */ -{ XK_scaron, 0x0161 }, /* LATIN SMALL LETTER S WITH CARON */ -{ XK_scedilla, 0x015f }, /* LATIN SMALL LETTER S WITH CEDILLA */ -{ XK_tcaron, 0x0165 }, /* LATIN SMALL LETTER T WITH CARON */ -{ XK_zacute, 0x017a }, /* LATIN SMALL LETTER Z WITH ACUTE */ -{ XK_doubleacute, 0x02dd }, /* DOUBLE ACUTE ACCENT */ -{ XK_zcaron, 0x017e }, /* LATIN SMALL LETTER Z WITH CARON */ -{ XK_zabovedot, 0x017c }, /* LATIN SMALL LETTER Z WITH DOT ABOVE */ -{ XK_Racute, 0x0154 }, /* LATIN CAPITAL LETTER R WITH ACUTE */ -{ XK_Abreve, 0x0102 }, /* LATIN CAPITAL LETTER A WITH BREVE */ -{ XK_Lacute, 0x0139 }, /* LATIN CAPITAL LETTER L WITH ACUTE */ -{ XK_Cacute, 0x0106 }, /* LATIN CAPITAL LETTER C WITH ACUTE */ -{ XK_Ccaron, 0x010c }, /* LATIN CAPITAL LETTER C WITH CARON */ -{ XK_Eogonek, 0x0118 }, /* LATIN CAPITAL LETTER E WITH OGONEK */ -{ XK_Ecaron, 0x011a }, /* LATIN CAPITAL LETTER E WITH CARON */ -{ XK_Dcaron, 0x010e }, /* LATIN CAPITAL LETTER D WITH CARON */ -{ XK_Dstroke, 0x0110 }, /* LATIN CAPITAL LETTER D WITH STROKE */ -{ XK_Nacute, 0x0143 }, /* LATIN CAPITAL LETTER N WITH ACUTE */ -{ XK_Ncaron, 0x0147 }, /* LATIN CAPITAL LETTER N WITH CARON */ -{ XK_Odoubleacute, 0x0150 }, /* LATIN CAPITAL LETTER O WITH DOUBLE ACUTE */ -{ XK_Rcaron, 0x0158 }, /* LATIN CAPITAL LETTER R WITH CARON */ -{ XK_Uring, 0x016e }, /* LATIN CAPITAL LETTER U WITH RING ABOVE */ -{ XK_Udoubleacute, 0x0170 }, /* LATIN CAPITAL LETTER U WITH DOUBLE ACUTE */ -{ XK_Tcedilla, 0x0162 }, /* LATIN CAPITAL LETTER T WITH CEDILLA */ -{ XK_racute, 0x0155 }, /* LATIN SMALL LETTER R WITH ACUTE */ -{ XK_abreve, 0x0103 }, /* LATIN SMALL LETTER A WITH BREVE */ -{ XK_lacute, 0x013a }, /* LATIN SMALL LETTER L WITH ACUTE */ -{ XK_cacute, 0x0107 }, /* LATIN SMALL LETTER C WITH ACUTE */ -{ XK_ccaron, 0x010d }, /* LATIN SMALL LETTER C WITH CARON */ -{ XK_eogonek, 0x0119 }, /* LATIN SMALL LETTER E WITH OGONEK */ -{ XK_ecaron, 0x011b }, /* LATIN SMALL LETTER E WITH CARON */ -{ XK_dcaron, 0x010f }, /* LATIN SMALL LETTER D WITH CARON */ -{ XK_dstroke, 0x0111 }, /* LATIN SMALL LETTER D WITH STROKE */ -{ XK_nacute, 0x0144 }, /* LATIN SMALL LETTER N WITH ACUTE */ -{ XK_ncaron, 0x0148 }, /* LATIN SMALL LETTER N WITH CARON */ -{ XK_odoubleacute, 0x0151 }, /* LATIN SMALL LETTER O WITH DOUBLE ACUTE */ -{ XK_rcaron, 0x0159 }, /* LATIN SMALL LETTER R WITH CARON */ -{ XK_uring, 0x016f }, /* LATIN SMALL LETTER U WITH RING ABOVE */ -{ XK_udoubleacute, 0x0171 }, /* LATIN SMALL LETTER U WITH DOUBLE ACUTE */ -{ XK_tcedilla, 0x0163 }, /* LATIN SMALL LETTER T WITH CEDILLA */ -{ XK_abovedot, 0x02d9 }, /* DOT ABOVE */ -{ XK_Hstroke, 0x0126 }, /* LATIN CAPITAL LETTER H WITH STROKE */ -{ XK_Hcircumflex, 0x0124 }, /* LATIN CAPITAL LETTER H WITH CIRCUMFLEX */ -{ XK_Iabovedot, 0x0130 }, /* LATIN CAPITAL LETTER I WITH DOT ABOVE */ -{ XK_Gbreve, 0x011e }, /* LATIN CAPITAL LETTER G WITH BREVE */ -{ XK_Jcircumflex, 0x0134 }, /* LATIN CAPITAL LETTER J WITH CIRCUMFLEX */ -{ XK_hstroke, 0x0127 }, /* LATIN SMALL LETTER H WITH STROKE */ -{ XK_hcircumflex, 0x0125 }, /* LATIN SMALL LETTER H WITH CIRCUMFLEX */ -{ XK_idotless, 0x0131 }, /* LATIN SMALL LETTER DOTLESS I */ -{ XK_gbreve, 0x011f }, /* LATIN SMALL LETTER G WITH BREVE */ -{ XK_jcircumflex, 0x0135 }, /* LATIN SMALL LETTER J WITH CIRCUMFLEX */ -{ XK_Cabovedot, 0x010a }, /* LATIN CAPITAL LETTER C WITH DOT ABOVE */ -{ XK_Ccircumflex, 0x0108 }, /* LATIN CAPITAL LETTER C WITH CIRCUMFLEX */ -{ XK_Gabovedot, 0x0120 }, /* LATIN CAPITAL LETTER G WITH DOT ABOVE */ -{ XK_Gcircumflex, 0x011c }, /* LATIN CAPITAL LETTER G WITH CIRCUMFLEX */ -{ XK_Ubreve, 0x016c }, /* LATIN CAPITAL LETTER U WITH BREVE */ -{ XK_Scircumflex, 0x015c }, /* LATIN CAPITAL LETTER S WITH CIRCUMFLEX */ -{ XK_cabovedot, 0x010b }, /* LATIN SMALL LETTER C WITH DOT ABOVE */ -{ XK_ccircumflex, 0x0109 }, /* LATIN SMALL LETTER C WITH CIRCUMFLEX */ -{ XK_gabovedot, 0x0121 }, /* LATIN SMALL LETTER G WITH DOT ABOVE */ -{ XK_gcircumflex, 0x011d }, /* LATIN SMALL LETTER G WITH CIRCUMFLEX */ -{ XK_ubreve, 0x016d }, /* LATIN SMALL LETTER U WITH BREVE */ -{ XK_scircumflex, 0x015d }, /* LATIN SMALL LETTER S WITH CIRCUMFLEX */ -{ XK_kra, 0x0138 }, /* LATIN SMALL LETTER KRA */ -{ XK_Rcedilla, 0x0156 }, /* LATIN CAPITAL LETTER R WITH CEDILLA */ -{ XK_Itilde, 0x0128 }, /* LATIN CAPITAL LETTER I WITH TILDE */ -{ XK_Lcedilla, 0x013b }, /* LATIN CAPITAL LETTER L WITH CEDILLA */ -{ XK_Emacron, 0x0112 }, /* LATIN CAPITAL LETTER E WITH MACRON */ -{ XK_Gcedilla, 0x0122 }, /* LATIN CAPITAL LETTER G WITH CEDILLA */ -{ XK_Tslash, 0x0166 }, /* LATIN CAPITAL LETTER T WITH STROKE */ -{ XK_rcedilla, 0x0157 }, /* LATIN SMALL LETTER R WITH CEDILLA */ -{ XK_itilde, 0x0129 }, /* LATIN SMALL LETTER I WITH TILDE */ -{ XK_lcedilla, 0x013c }, /* LATIN SMALL LETTER L WITH CEDILLA */ -{ XK_emacron, 0x0113 }, /* LATIN SMALL LETTER E WITH MACRON */ -{ XK_gcedilla, 0x0123 }, /* LATIN SMALL LETTER G WITH CEDILLA */ -{ XK_tslash, 0x0167 }, /* LATIN SMALL LETTER T WITH STROKE */ -{ XK_ENG, 0x014a }, /* LATIN CAPITAL LETTER ENG */ -{ XK_eng, 0x014b }, /* LATIN SMALL LETTER ENG */ -{ XK_Amacron, 0x0100 }, /* LATIN CAPITAL LETTER A WITH MACRON */ -{ XK_Iogonek, 0x012e }, /* LATIN CAPITAL LETTER I WITH OGONEK */ -{ XK_Eabovedot, 0x0116 }, /* LATIN CAPITAL LETTER E WITH DOT ABOVE */ -{ XK_Imacron, 0x012a }, /* LATIN CAPITAL LETTER I WITH MACRON */ -{ XK_Ncedilla, 0x0145 }, /* LATIN CAPITAL LETTER N WITH CEDILLA */ -{ XK_Omacron, 0x014c }, /* LATIN CAPITAL LETTER O WITH MACRON */ -{ XK_Kcedilla, 0x0136 }, /* LATIN CAPITAL LETTER K WITH CEDILLA */ -{ XK_Uogonek, 0x0172 }, /* LATIN CAPITAL LETTER U WITH OGONEK */ -{ XK_Utilde, 0x0168 }, /* LATIN CAPITAL LETTER U WITH TILDE */ -{ XK_Umacron, 0x016a }, /* LATIN CAPITAL LETTER U WITH MACRON */ -{ XK_amacron, 0x0101 }, /* LATIN SMALL LETTER A WITH MACRON */ -{ XK_iogonek, 0x012f }, /* LATIN SMALL LETTER I WITH OGONEK */ -{ XK_eabovedot, 0x0117 }, /* LATIN SMALL LETTER E WITH DOT ABOVE */ -{ XK_imacron, 0x012b }, /* LATIN SMALL LETTER I WITH MACRON */ -{ XK_ncedilla, 0x0146 }, /* LATIN SMALL LETTER N WITH CEDILLA */ -{ XK_omacron, 0x014d }, /* LATIN SMALL LETTER O WITH MACRON */ -{ XK_kcedilla, 0x0137 }, /* LATIN SMALL LETTER K WITH CEDILLA */ -{ XK_uogonek, 0x0173 }, /* LATIN SMALL LETTER U WITH OGONEK */ -{ XK_utilde, 0x0169 }, /* LATIN SMALL LETTER U WITH TILDE */ -{ XK_umacron, 0x016b }, /* LATIN SMALL LETTER U WITH MACRON */ + {XK_Aogonek, 0x0104}, /* LATIN CAPITAL LETTER A WITH OGONEK */ + {XK_breve, 0x02d8}, /* BREVE */ + {XK_Lstroke, 0x0141}, /* LATIN CAPITAL LETTER L WITH STROKE */ + {XK_Lcaron, 0x013d}, /* LATIN CAPITAL LETTER L WITH CARON */ + {XK_Sacute, 0x015a}, /* LATIN CAPITAL LETTER S WITH ACUTE */ + {XK_Scaron, 0x0160}, /* LATIN CAPITAL LETTER S WITH CARON */ + {XK_Scedilla, 0x015e}, /* LATIN CAPITAL LETTER S WITH CEDILLA */ + {XK_Tcaron, 0x0164}, /* LATIN CAPITAL LETTER T WITH CARON */ + {XK_Zacute, 0x0179}, /* LATIN CAPITAL LETTER Z WITH ACUTE */ + {XK_Zcaron, 0x017d}, /* LATIN CAPITAL LETTER Z WITH CARON */ + {XK_Zabovedot, 0x017b}, /* LATIN CAPITAL LETTER Z WITH DOT ABOVE */ + {XK_aogonek, 0x0105}, /* LATIN SMALL LETTER A WITH OGONEK */ + {XK_ogonek, 0x02db}, /* OGONEK */ + {XK_lstroke, 0x0142}, /* LATIN SMALL LETTER L WITH STROKE */ + {XK_lcaron, 0x013e}, /* LATIN SMALL LETTER L WITH CARON */ + {XK_sacute, 0x015b}, /* LATIN SMALL LETTER S WITH ACUTE */ + {XK_caron, 0x02c7}, /* CARON */ + {XK_scaron, 0x0161}, /* LATIN SMALL LETTER S WITH CARON */ + {XK_scedilla, 0x015f}, /* LATIN SMALL LETTER S WITH CEDILLA */ + {XK_tcaron, 0x0165}, /* LATIN SMALL LETTER T WITH CARON */ + {XK_zacute, 0x017a}, /* LATIN SMALL LETTER Z WITH ACUTE */ + {XK_doubleacute, 0x02dd}, /* DOUBLE ACUTE ACCENT */ + {XK_zcaron, 0x017e}, /* LATIN SMALL LETTER Z WITH CARON */ + {XK_zabovedot, 0x017c}, /* LATIN SMALL LETTER Z WITH DOT ABOVE */ + {XK_Racute, 0x0154}, /* LATIN CAPITAL LETTER R WITH ACUTE */ + {XK_Abreve, 0x0102}, /* LATIN CAPITAL LETTER A WITH BREVE */ + {XK_Lacute, 0x0139}, /* LATIN CAPITAL LETTER L WITH ACUTE */ + {XK_Cacute, 0x0106}, /* LATIN CAPITAL LETTER C WITH ACUTE */ + {XK_Ccaron, 0x010c}, /* LATIN CAPITAL LETTER C WITH CARON */ + {XK_Eogonek, 0x0118}, /* LATIN CAPITAL LETTER E WITH OGONEK */ + {XK_Ecaron, 0x011a}, /* LATIN CAPITAL LETTER E WITH CARON */ + {XK_Dcaron, 0x010e}, /* LATIN CAPITAL LETTER D WITH CARON */ + {XK_Dstroke, 0x0110}, /* LATIN CAPITAL LETTER D WITH STROKE */ + {XK_Nacute, 0x0143}, /* LATIN CAPITAL LETTER N WITH ACUTE */ + {XK_Ncaron, 0x0147}, /* LATIN CAPITAL LETTER N WITH CARON */ + {XK_Odoubleacute, 0x0150}, /* LATIN CAPITAL LETTER O WITH DOUBLE ACUTE */ + {XK_Rcaron, 0x0158}, /* LATIN CAPITAL LETTER R WITH CARON */ + {XK_Uring, 0x016e}, /* LATIN CAPITAL LETTER U WITH RING ABOVE */ + {XK_Udoubleacute, 0x0170}, /* LATIN CAPITAL LETTER U WITH DOUBLE ACUTE */ + {XK_Tcedilla, 0x0162}, /* LATIN CAPITAL LETTER T WITH CEDILLA */ + {XK_racute, 0x0155}, /* LATIN SMALL LETTER R WITH ACUTE */ + {XK_abreve, 0x0103}, /* LATIN SMALL LETTER A WITH BREVE */ + {XK_lacute, 0x013a}, /* LATIN SMALL LETTER L WITH ACUTE */ + {XK_cacute, 0x0107}, /* LATIN SMALL LETTER C WITH ACUTE */ + {XK_ccaron, 0x010d}, /* LATIN SMALL LETTER C WITH CARON */ + {XK_eogonek, 0x0119}, /* LATIN SMALL LETTER E WITH OGONEK */ + {XK_ecaron, 0x011b}, /* LATIN SMALL LETTER E WITH CARON */ + {XK_dcaron, 0x010f}, /* LATIN SMALL LETTER D WITH CARON */ + {XK_dstroke, 0x0111}, /* LATIN SMALL LETTER D WITH STROKE */ + {XK_nacute, 0x0144}, /* LATIN SMALL LETTER N WITH ACUTE */ + {XK_ncaron, 0x0148}, /* LATIN SMALL LETTER N WITH CARON */ + {XK_odoubleacute, 0x0151}, /* LATIN SMALL LETTER O WITH DOUBLE ACUTE */ + {XK_rcaron, 0x0159}, /* LATIN SMALL LETTER R WITH CARON */ + {XK_uring, 0x016f}, /* LATIN SMALL LETTER U WITH RING ABOVE */ + {XK_udoubleacute, 0x0171}, /* LATIN SMALL LETTER U WITH DOUBLE ACUTE */ + {XK_tcedilla, 0x0163}, /* LATIN SMALL LETTER T WITH CEDILLA */ + {XK_abovedot, 0x02d9}, /* DOT ABOVE */ + {XK_Hstroke, 0x0126}, /* LATIN CAPITAL LETTER H WITH STROKE */ + {XK_Hcircumflex, 0x0124}, /* LATIN CAPITAL LETTER H WITH CIRCUMFLEX */ + {XK_Iabovedot, 0x0130}, /* LATIN CAPITAL LETTER I WITH DOT ABOVE */ + {XK_Gbreve, 0x011e}, /* LATIN CAPITAL LETTER G WITH BREVE */ + {XK_Jcircumflex, 0x0134}, /* LATIN CAPITAL LETTER J WITH CIRCUMFLEX */ + {XK_hstroke, 0x0127}, /* LATIN SMALL LETTER H WITH STROKE */ + {XK_hcircumflex, 0x0125}, /* LATIN SMALL LETTER H WITH CIRCUMFLEX */ + {XK_idotless, 0x0131}, /* LATIN SMALL LETTER DOTLESS I */ + {XK_gbreve, 0x011f}, /* LATIN SMALL LETTER G WITH BREVE */ + {XK_jcircumflex, 0x0135}, /* LATIN SMALL LETTER J WITH CIRCUMFLEX */ + {XK_Cabovedot, 0x010a}, /* LATIN CAPITAL LETTER C WITH DOT ABOVE */ + {XK_Ccircumflex, 0x0108}, /* LATIN CAPITAL LETTER C WITH CIRCUMFLEX */ + {XK_Gabovedot, 0x0120}, /* LATIN CAPITAL LETTER G WITH DOT ABOVE */ + {XK_Gcircumflex, 0x011c}, /* LATIN CAPITAL LETTER G WITH CIRCUMFLEX */ + {XK_Ubreve, 0x016c}, /* LATIN CAPITAL LETTER U WITH BREVE */ + {XK_Scircumflex, 0x015c}, /* LATIN CAPITAL LETTER S WITH CIRCUMFLEX */ + {XK_cabovedot, 0x010b}, /* LATIN SMALL LETTER C WITH DOT ABOVE */ + {XK_ccircumflex, 0x0109}, /* LATIN SMALL LETTER C WITH CIRCUMFLEX */ + {XK_gabovedot, 0x0121}, /* LATIN SMALL LETTER G WITH DOT ABOVE */ + {XK_gcircumflex, 0x011d}, /* LATIN SMALL LETTER G WITH CIRCUMFLEX */ + {XK_ubreve, 0x016d}, /* LATIN SMALL LETTER U WITH BREVE */ + {XK_scircumflex, 0x015d}, /* LATIN SMALL LETTER S WITH CIRCUMFLEX */ + {XK_kra, 0x0138}, /* LATIN SMALL LETTER KRA */ + {XK_Rcedilla, 0x0156}, /* LATIN CAPITAL LETTER R WITH CEDILLA */ + {XK_Itilde, 0x0128}, /* LATIN CAPITAL LETTER I WITH TILDE */ + {XK_Lcedilla, 0x013b}, /* LATIN CAPITAL LETTER L WITH CEDILLA */ + {XK_Emacron, 0x0112}, /* LATIN CAPITAL LETTER E WITH MACRON */ + {XK_Gcedilla, 0x0122}, /* LATIN CAPITAL LETTER G WITH CEDILLA */ + {XK_Tslash, 0x0166}, /* LATIN CAPITAL LETTER T WITH STROKE */ + {XK_rcedilla, 0x0157}, /* LATIN SMALL LETTER R WITH CEDILLA */ + {XK_itilde, 0x0129}, /* LATIN SMALL LETTER I WITH TILDE */ + {XK_lcedilla, 0x013c}, /* LATIN SMALL LETTER L WITH CEDILLA */ + {XK_emacron, 0x0113}, /* LATIN SMALL LETTER E WITH MACRON */ + {XK_gcedilla, 0x0123}, /* LATIN SMALL LETTER G WITH CEDILLA */ + {XK_tslash, 0x0167}, /* LATIN SMALL LETTER T WITH STROKE */ + {XK_ENG, 0x014a}, /* LATIN CAPITAL LETTER ENG */ + {XK_eng, 0x014b}, /* LATIN SMALL LETTER ENG */ + {XK_Amacron, 0x0100}, /* LATIN CAPITAL LETTER A WITH MACRON */ + {XK_Iogonek, 0x012e}, /* LATIN CAPITAL LETTER I WITH OGONEK */ + {XK_Eabovedot, 0x0116}, /* LATIN CAPITAL LETTER E WITH DOT ABOVE */ + {XK_Imacron, 0x012a}, /* LATIN CAPITAL LETTER I WITH MACRON */ + {XK_Ncedilla, 0x0145}, /* LATIN CAPITAL LETTER N WITH CEDILLA */ + {XK_Omacron, 0x014c}, /* LATIN CAPITAL LETTER O WITH MACRON */ + {XK_Kcedilla, 0x0136}, /* LATIN CAPITAL LETTER K WITH CEDILLA */ + {XK_Uogonek, 0x0172}, /* LATIN CAPITAL LETTER U WITH OGONEK */ + {XK_Utilde, 0x0168}, /* LATIN CAPITAL LETTER U WITH TILDE */ + {XK_Umacron, 0x016a}, /* LATIN CAPITAL LETTER U WITH MACRON */ + {XK_amacron, 0x0101}, /* LATIN SMALL LETTER A WITH MACRON */ + {XK_iogonek, 0x012f}, /* LATIN SMALL LETTER I WITH OGONEK */ + {XK_eabovedot, 0x0117}, /* LATIN SMALL LETTER E WITH DOT ABOVE */ + {XK_imacron, 0x012b}, /* LATIN SMALL LETTER I WITH MACRON */ + {XK_ncedilla, 0x0146}, /* LATIN SMALL LETTER N WITH CEDILLA */ + {XK_omacron, 0x014d}, /* LATIN SMALL LETTER O WITH MACRON */ + {XK_kcedilla, 0x0137}, /* LATIN SMALL LETTER K WITH CEDILLA */ + {XK_uogonek, 0x0173}, /* LATIN SMALL LETTER U WITH OGONEK */ + {XK_utilde, 0x0169}, /* LATIN SMALL LETTER U WITH TILDE */ + {XK_umacron, 0x016b}, /* LATIN SMALL LETTER U WITH MACRON */ #if defined(XK_Babovedot) -{ XK_Babovedot, 0x1e02 }, /* LATIN CAPITAL LETTER B WITH DOT ABOVE */ -{ XK_babovedot, 0x1e03 }, /* LATIN SMALL LETTER B WITH DOT ABOVE */ -{ XK_Dabovedot, 0x1e0a }, /* LATIN CAPITAL LETTER D WITH DOT ABOVE */ -{ XK_Wgrave, 0x1e80 }, /* LATIN CAPITAL LETTER W WITH GRAVE */ -{ XK_Wacute, 0x1e82 }, /* LATIN CAPITAL LETTER W WITH ACUTE */ -{ XK_dabovedot, 0x1e0b }, /* LATIN SMALL LETTER D WITH DOT ABOVE */ -{ XK_Ygrave, 0x1ef2 }, /* LATIN CAPITAL LETTER Y WITH GRAVE */ -{ XK_Fabovedot, 0x1e1e }, /* LATIN CAPITAL LETTER F WITH DOT ABOVE */ -{ XK_fabovedot, 0x1e1f }, /* LATIN SMALL LETTER F WITH DOT ABOVE */ -{ XK_Mabovedot, 0x1e40 }, /* LATIN CAPITAL LETTER M WITH DOT ABOVE */ -{ XK_mabovedot, 0x1e41 }, /* LATIN SMALL LETTER M WITH DOT ABOVE */ -{ XK_Pabovedot, 0x1e56 }, /* LATIN CAPITAL LETTER P WITH DOT ABOVE */ -{ XK_wgrave, 0x1e81 }, /* LATIN SMALL LETTER W WITH GRAVE */ -{ XK_pabovedot, 0x1e57 }, /* LATIN SMALL LETTER P WITH DOT ABOVE */ -{ XK_wacute, 0x1e83 }, /* LATIN SMALL LETTER W WITH ACUTE */ -{ XK_Sabovedot, 0x1e60 }, /* LATIN CAPITAL LETTER S WITH DOT ABOVE */ -{ XK_ygrave, 0x1ef3 }, /* LATIN SMALL LETTER Y WITH GRAVE */ -{ XK_Wdiaeresis, 0x1e84 }, /* LATIN CAPITAL LETTER W WITH DIAERESIS */ -{ XK_wdiaeresis, 0x1e85 }, /* LATIN SMALL LETTER W WITH DIAERESIS */ -{ XK_sabovedot, 0x1e61 }, /* LATIN SMALL LETTER S WITH DOT ABOVE */ -{ XK_Wcircumflex, 0x0174 }, /* LATIN CAPITAL LETTER W WITH CIRCUMFLEX */ -{ XK_Tabovedot, 0x1e6a }, /* LATIN CAPITAL LETTER T WITH DOT ABOVE */ -{ XK_Ycircumflex, 0x0176 }, /* LATIN CAPITAL LETTER Y WITH CIRCUMFLEX */ -{ XK_wcircumflex, 0x0175 }, /* LATIN SMALL LETTER W WITH CIRCUMFLEX */ -{ XK_tabovedot, 0x1e6b }, /* LATIN SMALL LETTER T WITH DOT ABOVE */ -{ XK_ycircumflex, 0x0177 }, /* LATIN SMALL LETTER Y WITH CIRCUMFLEX */ -#endif // defined(XK_Babovedot) + {XK_Babovedot, 0x1e02}, /* LATIN CAPITAL LETTER B WITH DOT ABOVE */ + {XK_babovedot, 0x1e03}, /* LATIN SMALL LETTER B WITH DOT ABOVE */ + {XK_Dabovedot, 0x1e0a}, /* LATIN CAPITAL LETTER D WITH DOT ABOVE */ + {XK_Wgrave, 0x1e80}, /* LATIN CAPITAL LETTER W WITH GRAVE */ + {XK_Wacute, 0x1e82}, /* LATIN CAPITAL LETTER W WITH ACUTE */ + {XK_dabovedot, 0x1e0b}, /* LATIN SMALL LETTER D WITH DOT ABOVE */ + {XK_Ygrave, 0x1ef2}, /* LATIN CAPITAL LETTER Y WITH GRAVE */ + {XK_Fabovedot, 0x1e1e}, /* LATIN CAPITAL LETTER F WITH DOT ABOVE */ + {XK_fabovedot, 0x1e1f}, /* LATIN SMALL LETTER F WITH DOT ABOVE */ + {XK_Mabovedot, 0x1e40}, /* LATIN CAPITAL LETTER M WITH DOT ABOVE */ + {XK_mabovedot, 0x1e41}, /* LATIN SMALL LETTER M WITH DOT ABOVE */ + {XK_Pabovedot, 0x1e56}, /* LATIN CAPITAL LETTER P WITH DOT ABOVE */ + {XK_wgrave, 0x1e81}, /* LATIN SMALL LETTER W WITH GRAVE */ + {XK_pabovedot, 0x1e57}, /* LATIN SMALL LETTER P WITH DOT ABOVE */ + {XK_wacute, 0x1e83}, /* LATIN SMALL LETTER W WITH ACUTE */ + {XK_Sabovedot, 0x1e60}, /* LATIN CAPITAL LETTER S WITH DOT ABOVE */ + {XK_ygrave, 0x1ef3}, /* LATIN SMALL LETTER Y WITH GRAVE */ + {XK_Wdiaeresis, 0x1e84}, /* LATIN CAPITAL LETTER W WITH DIAERESIS */ + {XK_wdiaeresis, 0x1e85}, /* LATIN SMALL LETTER W WITH DIAERESIS */ + {XK_sabovedot, 0x1e61}, /* LATIN SMALL LETTER S WITH DOT ABOVE */ + {XK_Wcircumflex, 0x0174}, /* LATIN CAPITAL LETTER W WITH CIRCUMFLEX */ + {XK_Tabovedot, 0x1e6a}, /* LATIN CAPITAL LETTER T WITH DOT ABOVE */ + {XK_Ycircumflex, 0x0176}, /* LATIN CAPITAL LETTER Y WITH CIRCUMFLEX */ + {XK_wcircumflex, 0x0175}, /* LATIN SMALL LETTER W WITH CIRCUMFLEX */ + {XK_tabovedot, 0x1e6b}, /* LATIN SMALL LETTER T WITH DOT ABOVE */ + {XK_ycircumflex, 0x0177}, /* LATIN SMALL LETTER Y WITH CIRCUMFLEX */ +#endif // defined(XK_Babovedot) #if defined(XK_overline) -{ XK_overline, 0x203e }, /* OVERLINE */ -{ XK_kana_fullstop, 0x3002 }, /* IDEOGRAPHIC FULL STOP */ -{ XK_kana_openingbracket, 0x300c }, /* LEFT CORNER BRACKET */ -{ XK_kana_closingbracket, 0x300d }, /* RIGHT CORNER BRACKET */ -{ XK_kana_comma, 0x3001 }, /* IDEOGRAPHIC COMMA */ -{ XK_kana_conjunctive, 0x30fb }, /* KATAKANA MIDDLE DOT */ -{ XK_kana_WO, 0x30f2 }, /* KATAKANA LETTER WO */ -{ XK_kana_a, 0x30a1 }, /* KATAKANA LETTER SMALL A */ -{ XK_kana_i, 0x30a3 }, /* KATAKANA LETTER SMALL I */ -{ XK_kana_u, 0x30a5 }, /* KATAKANA LETTER SMALL U */ -{ XK_kana_e, 0x30a7 }, /* KATAKANA LETTER SMALL E */ -{ XK_kana_o, 0x30a9 }, /* KATAKANA LETTER SMALL O */ -{ XK_kana_ya, 0x30e3 }, /* KATAKANA LETTER SMALL YA */ -{ XK_kana_yu, 0x30e5 }, /* KATAKANA LETTER SMALL YU */ -{ XK_kana_yo, 0x30e7 }, /* KATAKANA LETTER SMALL YO */ -{ XK_kana_tsu, 0x30c3 }, /* KATAKANA LETTER SMALL TU */ -{ XK_prolongedsound, 0x30fc }, /* KATAKANA-HIRAGANA PROLONGED SOUND MARK */ -{ XK_kana_A, 0x30a2 }, /* KATAKANA LETTER A */ -{ XK_kana_I, 0x30a4 }, /* KATAKANA LETTER I */ -{ XK_kana_U, 0x30a6 }, /* KATAKANA LETTER U */ -{ XK_kana_E, 0x30a8 }, /* KATAKANA LETTER E */ -{ XK_kana_O, 0x30aa }, /* KATAKANA LETTER O */ -{ XK_kana_KA, 0x30ab }, /* KATAKANA LETTER KA */ -{ XK_kana_KI, 0x30ad }, /* KATAKANA LETTER KI */ -{ XK_kana_KU, 0x30af }, /* KATAKANA LETTER KU */ -{ XK_kana_KE, 0x30b1 }, /* KATAKANA LETTER KE */ -{ XK_kana_KO, 0x30b3 }, /* KATAKANA LETTER KO */ -{ XK_kana_SA, 0x30b5 }, /* KATAKANA LETTER SA */ -{ XK_kana_SHI, 0x30b7 }, /* KATAKANA LETTER SI */ -{ XK_kana_SU, 0x30b9 }, /* KATAKANA LETTER SU */ -{ XK_kana_SE, 0x30bb }, /* KATAKANA LETTER SE */ -{ XK_kana_SO, 0x30bd }, /* KATAKANA LETTER SO */ -{ XK_kana_TA, 0x30bf }, /* KATAKANA LETTER TA */ -{ XK_kana_CHI, 0x30c1 }, /* KATAKANA LETTER TI */ -{ XK_kana_TSU, 0x30c4 }, /* KATAKANA LETTER TU */ -{ XK_kana_TE, 0x30c6 }, /* KATAKANA LETTER TE */ -{ XK_kana_TO, 0x30c8 }, /* KATAKANA LETTER TO */ -{ XK_kana_NA, 0x30ca }, /* KATAKANA LETTER NA */ -{ XK_kana_NI, 0x30cb }, /* KATAKANA LETTER NI */ -{ XK_kana_NU, 0x30cc }, /* KATAKANA LETTER NU */ -{ XK_kana_NE, 0x30cd }, /* KATAKANA LETTER NE */ -{ XK_kana_NO, 0x30ce }, /* KATAKANA LETTER NO */ -{ XK_kana_HA, 0x30cf }, /* KATAKANA LETTER HA */ -{ XK_kana_HI, 0x30d2 }, /* KATAKANA LETTER HI */ -{ XK_kana_FU, 0x30d5 }, /* KATAKANA LETTER HU */ -{ XK_kana_HE, 0x30d8 }, /* KATAKANA LETTER HE */ -{ XK_kana_HO, 0x30db }, /* KATAKANA LETTER HO */ -{ XK_kana_MA, 0x30de }, /* KATAKANA LETTER MA */ -{ XK_kana_MI, 0x30df }, /* KATAKANA LETTER MI */ -{ XK_kana_MU, 0x30e0 }, /* KATAKANA LETTER MU */ -{ XK_kana_ME, 0x30e1 }, /* KATAKANA LETTER ME */ -{ XK_kana_MO, 0x30e2 }, /* KATAKANA LETTER MO */ -{ XK_kana_YA, 0x30e4 }, /* KATAKANA LETTER YA */ -{ XK_kana_YU, 0x30e6 }, /* KATAKANA LETTER YU */ -{ XK_kana_YO, 0x30e8 }, /* KATAKANA LETTER YO */ -{ XK_kana_RA, 0x30e9 }, /* KATAKANA LETTER RA */ -{ XK_kana_RI, 0x30ea }, /* KATAKANA LETTER RI */ -{ XK_kana_RU, 0x30eb }, /* KATAKANA LETTER RU */ -{ XK_kana_RE, 0x30ec }, /* KATAKANA LETTER RE */ -{ XK_kana_RO, 0x30ed }, /* KATAKANA LETTER RO */ -{ XK_kana_WA, 0x30ef }, /* KATAKANA LETTER WA */ -{ XK_kana_N, 0x30f3 }, /* KATAKANA LETTER N */ -{ XK_voicedsound, 0x309b }, /* KATAKANA-HIRAGANA VOICED SOUND MARK */ -{ XK_semivoicedsound, 0x309c }, /* KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK */ -#endif // defined(XK_overline) + {XK_overline, 0x203e}, /* OVERLINE */ + {XK_kana_fullstop, 0x3002}, /* IDEOGRAPHIC FULL STOP */ + {XK_kana_openingbracket, 0x300c}, /* LEFT CORNER BRACKET */ + {XK_kana_closingbracket, 0x300d}, /* RIGHT CORNER BRACKET */ + {XK_kana_comma, 0x3001}, /* IDEOGRAPHIC COMMA */ + {XK_kana_conjunctive, 0x30fb}, /* KATAKANA MIDDLE DOT */ + {XK_kana_WO, 0x30f2}, /* KATAKANA LETTER WO */ + {XK_kana_a, 0x30a1}, /* KATAKANA LETTER SMALL A */ + {XK_kana_i, 0x30a3}, /* KATAKANA LETTER SMALL I */ + {XK_kana_u, 0x30a5}, /* KATAKANA LETTER SMALL U */ + {XK_kana_e, 0x30a7}, /* KATAKANA LETTER SMALL E */ + {XK_kana_o, 0x30a9}, /* KATAKANA LETTER SMALL O */ + {XK_kana_ya, 0x30e3}, /* KATAKANA LETTER SMALL YA */ + {XK_kana_yu, 0x30e5}, /* KATAKANA LETTER SMALL YU */ + {XK_kana_yo, 0x30e7}, /* KATAKANA LETTER SMALL YO */ + {XK_kana_tsu, 0x30c3}, /* KATAKANA LETTER SMALL TU */ + {XK_prolongedsound, 0x30fc}, /* KATAKANA-HIRAGANA PROLONGED SOUND MARK */ + {XK_kana_A, 0x30a2}, /* KATAKANA LETTER A */ + {XK_kana_I, 0x30a4}, /* KATAKANA LETTER I */ + {XK_kana_U, 0x30a6}, /* KATAKANA LETTER U */ + {XK_kana_E, 0x30a8}, /* KATAKANA LETTER E */ + {XK_kana_O, 0x30aa}, /* KATAKANA LETTER O */ + {XK_kana_KA, 0x30ab}, /* KATAKANA LETTER KA */ + {XK_kana_KI, 0x30ad}, /* KATAKANA LETTER KI */ + {XK_kana_KU, 0x30af}, /* KATAKANA LETTER KU */ + {XK_kana_KE, 0x30b1}, /* KATAKANA LETTER KE */ + {XK_kana_KO, 0x30b3}, /* KATAKANA LETTER KO */ + {XK_kana_SA, 0x30b5}, /* KATAKANA LETTER SA */ + {XK_kana_SHI, 0x30b7}, /* KATAKANA LETTER SI */ + {XK_kana_SU, 0x30b9}, /* KATAKANA LETTER SU */ + {XK_kana_SE, 0x30bb}, /* KATAKANA LETTER SE */ + {XK_kana_SO, 0x30bd}, /* KATAKANA LETTER SO */ + {XK_kana_TA, 0x30bf}, /* KATAKANA LETTER TA */ + {XK_kana_CHI, 0x30c1}, /* KATAKANA LETTER TI */ + {XK_kana_TSU, 0x30c4}, /* KATAKANA LETTER TU */ + {XK_kana_TE, 0x30c6}, /* KATAKANA LETTER TE */ + {XK_kana_TO, 0x30c8}, /* KATAKANA LETTER TO */ + {XK_kana_NA, 0x30ca}, /* KATAKANA LETTER NA */ + {XK_kana_NI, 0x30cb}, /* KATAKANA LETTER NI */ + {XK_kana_NU, 0x30cc}, /* KATAKANA LETTER NU */ + {XK_kana_NE, 0x30cd}, /* KATAKANA LETTER NE */ + {XK_kana_NO, 0x30ce}, /* KATAKANA LETTER NO */ + {XK_kana_HA, 0x30cf}, /* KATAKANA LETTER HA */ + {XK_kana_HI, 0x30d2}, /* KATAKANA LETTER HI */ + {XK_kana_FU, 0x30d5}, /* KATAKANA LETTER HU */ + {XK_kana_HE, 0x30d8}, /* KATAKANA LETTER HE */ + {XK_kana_HO, 0x30db}, /* KATAKANA LETTER HO */ + {XK_kana_MA, 0x30de}, /* KATAKANA LETTER MA */ + {XK_kana_MI, 0x30df}, /* KATAKANA LETTER MI */ + {XK_kana_MU, 0x30e0}, /* KATAKANA LETTER MU */ + {XK_kana_ME, 0x30e1}, /* KATAKANA LETTER ME */ + {XK_kana_MO, 0x30e2}, /* KATAKANA LETTER MO */ + {XK_kana_YA, 0x30e4}, /* KATAKANA LETTER YA */ + {XK_kana_YU, 0x30e6}, /* KATAKANA LETTER YU */ + {XK_kana_YO, 0x30e8}, /* KATAKANA LETTER YO */ + {XK_kana_RA, 0x30e9}, /* KATAKANA LETTER RA */ + {XK_kana_RI, 0x30ea}, /* KATAKANA LETTER RI */ + {XK_kana_RU, 0x30eb}, /* KATAKANA LETTER RU */ + {XK_kana_RE, 0x30ec}, /* KATAKANA LETTER RE */ + {XK_kana_RO, 0x30ed}, /* KATAKANA LETTER RO */ + {XK_kana_WA, 0x30ef}, /* KATAKANA LETTER WA */ + {XK_kana_N, 0x30f3}, /* KATAKANA LETTER N */ + {XK_voicedsound, 0x309b}, /* KATAKANA-HIRAGANA VOICED SOUND MARK */ + {XK_semivoicedsound, 0x309c}, /* KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK */ +#endif // defined(XK_overline) #if defined(XK_Farsi_0) -{ XK_Farsi_0, 0x06f0 }, /* EXTENDED ARABIC-INDIC DIGIT 0 */ -{ XK_Farsi_1, 0x06f1 }, /* EXTENDED ARABIC-INDIC DIGIT 1 */ -{ XK_Farsi_2, 0x06f2 }, /* EXTENDED ARABIC-INDIC DIGIT 2 */ -{ XK_Farsi_3, 0x06f3 }, /* EXTENDED ARABIC-INDIC DIGIT 3 */ -{ XK_Farsi_4, 0x06f4 }, /* EXTENDED ARABIC-INDIC DIGIT 4 */ -{ XK_Farsi_5, 0x06f5 }, /* EXTENDED ARABIC-INDIC DIGIT 5 */ -{ XK_Farsi_6, 0x06f6 }, /* EXTENDED ARABIC-INDIC DIGIT 6 */ -{ XK_Farsi_7, 0x06f7 }, /* EXTENDED ARABIC-INDIC DIGIT 7 */ -{ XK_Farsi_8, 0x06f8 }, /* EXTENDED ARABIC-INDIC DIGIT 8 */ -{ XK_Farsi_9, 0x06f9 }, /* EXTENDED ARABIC-INDIC DIGIT 9 */ -{ XK_Arabic_percent, 0x066a }, /* ARABIC PERCENT */ -{ XK_Arabic_superscript_alef, 0x0670 }, /* ARABIC LETTER SUPERSCRIPT ALEF */ -{ XK_Arabic_tteh, 0x0679 }, /* ARABIC LETTER TTEH */ -{ XK_Arabic_peh, 0x067e }, /* ARABIC LETTER PEH */ -{ XK_Arabic_tcheh, 0x0686 }, /* ARABIC LETTER TCHEH */ -{ XK_Arabic_ddal, 0x0688 }, /* ARABIC LETTER DDAL */ -{ XK_Arabic_rreh, 0x0691 }, /* ARABIC LETTER RREH */ -{ XK_Arabic_comma, 0x060c }, /* ARABIC COMMA */ -{ XK_Arabic_fullstop, 0x06d4 }, /* ARABIC FULLSTOP */ -{ XK_Arabic_semicolon, 0x061b }, /* ARABIC SEMICOLON */ -{ XK_Arabic_0, 0x0660 }, /* ARABIC 0 */ -{ XK_Arabic_1, 0x0661 }, /* ARABIC 1 */ -{ XK_Arabic_2, 0x0662 }, /* ARABIC 2 */ -{ XK_Arabic_3, 0x0663 }, /* ARABIC 3 */ -{ XK_Arabic_4, 0x0664 }, /* ARABIC 4 */ -{ XK_Arabic_5, 0x0665 }, /* ARABIC 5 */ -{ XK_Arabic_6, 0x0666 }, /* ARABIC 6 */ -{ XK_Arabic_7, 0x0667 }, /* ARABIC 7 */ -{ XK_Arabic_8, 0x0668 }, /* ARABIC 8 */ -{ XK_Arabic_9, 0x0669 }, /* ARABIC 9 */ -{ XK_Arabic_question_mark, 0x061f }, /* ARABIC QUESTION MARK */ -{ XK_Arabic_hamza, 0x0621 }, /* ARABIC LETTER HAMZA */ -{ XK_Arabic_maddaonalef, 0x0622 }, /* ARABIC LETTER ALEF WITH MADDA ABOVE */ -{ XK_Arabic_hamzaonalef, 0x0623 }, /* ARABIC LETTER ALEF WITH HAMZA ABOVE */ -{ XK_Arabic_hamzaonwaw, 0x0624 }, /* ARABIC LETTER WAW WITH HAMZA ABOVE */ -{ XK_Arabic_hamzaunderalef, 0x0625 }, /* ARABIC LETTER ALEF WITH HAMZA BELOW */ -{ XK_Arabic_hamzaonyeh, 0x0626 }, /* ARABIC LETTER YEH WITH HAMZA ABOVE */ -{ XK_Arabic_alef, 0x0627 }, /* ARABIC LETTER ALEF */ -{ XK_Arabic_beh, 0x0628 }, /* ARABIC LETTER BEH */ -{ XK_Arabic_tehmarbuta, 0x0629 }, /* ARABIC LETTER TEH MARBUTA */ -{ XK_Arabic_teh, 0x062a }, /* ARABIC LETTER TEH */ -{ XK_Arabic_theh, 0x062b }, /* ARABIC LETTER THEH */ -{ XK_Arabic_jeem, 0x062c }, /* ARABIC LETTER JEEM */ -{ XK_Arabic_hah, 0x062d }, /* ARABIC LETTER HAH */ -{ XK_Arabic_khah, 0x062e }, /* ARABIC LETTER KHAH */ -{ XK_Arabic_dal, 0x062f }, /* ARABIC LETTER DAL */ -{ XK_Arabic_thal, 0x0630 }, /* ARABIC LETTER THAL */ -{ XK_Arabic_ra, 0x0631 }, /* ARABIC LETTER REH */ -{ XK_Arabic_zain, 0x0632 }, /* ARABIC LETTER ZAIN */ -{ XK_Arabic_seen, 0x0633 }, /* ARABIC LETTER SEEN */ -{ XK_Arabic_sheen, 0x0634 }, /* ARABIC LETTER SHEEN */ -{ XK_Arabic_sad, 0x0635 }, /* ARABIC LETTER SAD */ -{ XK_Arabic_dad, 0x0636 }, /* ARABIC LETTER DAD */ -{ XK_Arabic_tah, 0x0637 }, /* ARABIC LETTER TAH */ -{ XK_Arabic_zah, 0x0638 }, /* ARABIC LETTER ZAH */ -{ XK_Arabic_ain, 0x0639 }, /* ARABIC LETTER AIN */ -{ XK_Arabic_ghain, 0x063a }, /* ARABIC LETTER GHAIN */ -{ XK_Arabic_tatweel, 0x0640 }, /* ARABIC TATWEEL */ -{ XK_Arabic_feh, 0x0641 }, /* ARABIC LETTER FEH */ -{ XK_Arabic_qaf, 0x0642 }, /* ARABIC LETTER QAF */ -{ XK_Arabic_kaf, 0x0643 }, /* ARABIC LETTER KAF */ -{ XK_Arabic_lam, 0x0644 }, /* ARABIC LETTER LAM */ -{ XK_Arabic_meem, 0x0645 }, /* ARABIC LETTER MEEM */ -{ XK_Arabic_noon, 0x0646 }, /* ARABIC LETTER NOON */ -{ XK_Arabic_ha, 0x0647 }, /* ARABIC LETTER HEH */ -{ XK_Arabic_waw, 0x0648 }, /* ARABIC LETTER WAW */ -{ XK_Arabic_alefmaksura, 0x0649 }, /* ARABIC LETTER ALEF MAKSURA */ -{ XK_Arabic_yeh, 0x064a }, /* ARABIC LETTER YEH */ -{ XK_Arabic_fathatan, 0x064b }, /* ARABIC FATHATAN */ -{ XK_Arabic_dammatan, 0x064c }, /* ARABIC DAMMATAN */ -{ XK_Arabic_kasratan, 0x064d }, /* ARABIC KASRATAN */ -{ XK_Arabic_fatha, 0x064e }, /* ARABIC FATHA */ -{ XK_Arabic_damma, 0x064f }, /* ARABIC DAMMA */ -{ XK_Arabic_kasra, 0x0650 }, /* ARABIC KASRA */ -{ XK_Arabic_shadda, 0x0651 }, /* ARABIC SHADDA */ -{ XK_Arabic_sukun, 0x0652 }, /* ARABIC SUKUN */ -{ XK_Arabic_madda_above, 0x0653 }, /* ARABIC MADDA ABOVE */ -{ XK_Arabic_hamza_above, 0x0654 }, /* ARABIC HAMZA ABOVE */ -{ XK_Arabic_hamza_below, 0x0655 }, /* ARABIC HAMZA BELOW */ -{ XK_Arabic_jeh, 0x0698 }, /* ARABIC LETTER JEH */ -{ XK_Arabic_veh, 0x06a4 }, /* ARABIC LETTER VEH */ -{ XK_Arabic_keheh, 0x06a9 }, /* ARABIC LETTER KEHEH */ -{ XK_Arabic_gaf, 0x06af }, /* ARABIC LETTER GAF */ -{ XK_Arabic_noon_ghunna, 0x06ba }, /* ARABIC LETTER NOON GHUNNA */ -{ XK_Arabic_heh_doachashmee, 0x06be }, /* ARABIC LETTER HEH DOACHASHMEE */ -{ XK_Arabic_farsi_yeh, 0x06cc }, /* ARABIC LETTER FARSI YEH */ -{ XK_Arabic_yeh_baree, 0x06d2 }, /* ARABIC LETTER YEH BAREE */ -{ XK_Arabic_heh_goal, 0x06c1 }, /* ARABIC LETTER HEH GOAL */ -#endif // defined(XK_Farsi_0) + {XK_Farsi_0, 0x06f0}, /* EXTENDED ARABIC-INDIC DIGIT 0 */ + {XK_Farsi_1, 0x06f1}, /* EXTENDED ARABIC-INDIC DIGIT 1 */ + {XK_Farsi_2, 0x06f2}, /* EXTENDED ARABIC-INDIC DIGIT 2 */ + {XK_Farsi_3, 0x06f3}, /* EXTENDED ARABIC-INDIC DIGIT 3 */ + {XK_Farsi_4, 0x06f4}, /* EXTENDED ARABIC-INDIC DIGIT 4 */ + {XK_Farsi_5, 0x06f5}, /* EXTENDED ARABIC-INDIC DIGIT 5 */ + {XK_Farsi_6, 0x06f6}, /* EXTENDED ARABIC-INDIC DIGIT 6 */ + {XK_Farsi_7, 0x06f7}, /* EXTENDED ARABIC-INDIC DIGIT 7 */ + {XK_Farsi_8, 0x06f8}, /* EXTENDED ARABIC-INDIC DIGIT 8 */ + {XK_Farsi_9, 0x06f9}, /* EXTENDED ARABIC-INDIC DIGIT 9 */ + {XK_Arabic_percent, 0x066a}, /* ARABIC PERCENT */ + {XK_Arabic_superscript_alef, 0x0670}, /* ARABIC LETTER SUPERSCRIPT ALEF */ + {XK_Arabic_tteh, 0x0679}, /* ARABIC LETTER TTEH */ + {XK_Arabic_peh, 0x067e}, /* ARABIC LETTER PEH */ + {XK_Arabic_tcheh, 0x0686}, /* ARABIC LETTER TCHEH */ + {XK_Arabic_ddal, 0x0688}, /* ARABIC LETTER DDAL */ + {XK_Arabic_rreh, 0x0691}, /* ARABIC LETTER RREH */ + {XK_Arabic_comma, 0x060c}, /* ARABIC COMMA */ + {XK_Arabic_fullstop, 0x06d4}, /* ARABIC FULLSTOP */ + {XK_Arabic_semicolon, 0x061b}, /* ARABIC SEMICOLON */ + {XK_Arabic_0, 0x0660}, /* ARABIC 0 */ + {XK_Arabic_1, 0x0661}, /* ARABIC 1 */ + {XK_Arabic_2, 0x0662}, /* ARABIC 2 */ + {XK_Arabic_3, 0x0663}, /* ARABIC 3 */ + {XK_Arabic_4, 0x0664}, /* ARABIC 4 */ + {XK_Arabic_5, 0x0665}, /* ARABIC 5 */ + {XK_Arabic_6, 0x0666}, /* ARABIC 6 */ + {XK_Arabic_7, 0x0667}, /* ARABIC 7 */ + {XK_Arabic_8, 0x0668}, /* ARABIC 8 */ + {XK_Arabic_9, 0x0669}, /* ARABIC 9 */ + {XK_Arabic_question_mark, 0x061f}, /* ARABIC QUESTION MARK */ + {XK_Arabic_hamza, 0x0621}, /* ARABIC LETTER HAMZA */ + {XK_Arabic_maddaonalef, 0x0622}, /* ARABIC LETTER ALEF WITH MADDA ABOVE */ + {XK_Arabic_hamzaonalef, 0x0623}, /* ARABIC LETTER ALEF WITH HAMZA ABOVE */ + {XK_Arabic_hamzaonwaw, 0x0624}, /* ARABIC LETTER WAW WITH HAMZA ABOVE */ + {XK_Arabic_hamzaunderalef, + 0x0625}, /* ARABIC LETTER ALEF WITH HAMZA BELOW */ + {XK_Arabic_hamzaonyeh, 0x0626}, /* ARABIC LETTER YEH WITH HAMZA ABOVE */ + {XK_Arabic_alef, 0x0627}, /* ARABIC LETTER ALEF */ + {XK_Arabic_beh, 0x0628}, /* ARABIC LETTER BEH */ + {XK_Arabic_tehmarbuta, 0x0629}, /* ARABIC LETTER TEH MARBUTA */ + {XK_Arabic_teh, 0x062a}, /* ARABIC LETTER TEH */ + {XK_Arabic_theh, 0x062b}, /* ARABIC LETTER THEH */ + {XK_Arabic_jeem, 0x062c}, /* ARABIC LETTER JEEM */ + {XK_Arabic_hah, 0x062d}, /* ARABIC LETTER HAH */ + {XK_Arabic_khah, 0x062e}, /* ARABIC LETTER KHAH */ + {XK_Arabic_dal, 0x062f}, /* ARABIC LETTER DAL */ + {XK_Arabic_thal, 0x0630}, /* ARABIC LETTER THAL */ + {XK_Arabic_ra, 0x0631}, /* ARABIC LETTER REH */ + {XK_Arabic_zain, 0x0632}, /* ARABIC LETTER ZAIN */ + {XK_Arabic_seen, 0x0633}, /* ARABIC LETTER SEEN */ + {XK_Arabic_sheen, 0x0634}, /* ARABIC LETTER SHEEN */ + {XK_Arabic_sad, 0x0635}, /* ARABIC LETTER SAD */ + {XK_Arabic_dad, 0x0636}, /* ARABIC LETTER DAD */ + {XK_Arabic_tah, 0x0637}, /* ARABIC LETTER TAH */ + {XK_Arabic_zah, 0x0638}, /* ARABIC LETTER ZAH */ + {XK_Arabic_ain, 0x0639}, /* ARABIC LETTER AIN */ + {XK_Arabic_ghain, 0x063a}, /* ARABIC LETTER GHAIN */ + {XK_Arabic_tatweel, 0x0640}, /* ARABIC TATWEEL */ + {XK_Arabic_feh, 0x0641}, /* ARABIC LETTER FEH */ + {XK_Arabic_qaf, 0x0642}, /* ARABIC LETTER QAF */ + {XK_Arabic_kaf, 0x0643}, /* ARABIC LETTER KAF */ + {XK_Arabic_lam, 0x0644}, /* ARABIC LETTER LAM */ + {XK_Arabic_meem, 0x0645}, /* ARABIC LETTER MEEM */ + {XK_Arabic_noon, 0x0646}, /* ARABIC LETTER NOON */ + {XK_Arabic_ha, 0x0647}, /* ARABIC LETTER HEH */ + {XK_Arabic_waw, 0x0648}, /* ARABIC LETTER WAW */ + {XK_Arabic_alefmaksura, 0x0649}, /* ARABIC LETTER ALEF MAKSURA */ + {XK_Arabic_yeh, 0x064a}, /* ARABIC LETTER YEH */ + {XK_Arabic_fathatan, 0x064b}, /* ARABIC FATHATAN */ + {XK_Arabic_dammatan, 0x064c}, /* ARABIC DAMMATAN */ + {XK_Arabic_kasratan, 0x064d}, /* ARABIC KASRATAN */ + {XK_Arabic_fatha, 0x064e}, /* ARABIC FATHA */ + {XK_Arabic_damma, 0x064f}, /* ARABIC DAMMA */ + {XK_Arabic_kasra, 0x0650}, /* ARABIC KASRA */ + {XK_Arabic_shadda, 0x0651}, /* ARABIC SHADDA */ + {XK_Arabic_sukun, 0x0652}, /* ARABIC SUKUN */ + {XK_Arabic_madda_above, 0x0653}, /* ARABIC MADDA ABOVE */ + {XK_Arabic_hamza_above, 0x0654}, /* ARABIC HAMZA ABOVE */ + {XK_Arabic_hamza_below, 0x0655}, /* ARABIC HAMZA BELOW */ + {XK_Arabic_jeh, 0x0698}, /* ARABIC LETTER JEH */ + {XK_Arabic_veh, 0x06a4}, /* ARABIC LETTER VEH */ + {XK_Arabic_keheh, 0x06a9}, /* ARABIC LETTER KEHEH */ + {XK_Arabic_gaf, 0x06af}, /* ARABIC LETTER GAF */ + {XK_Arabic_noon_ghunna, 0x06ba}, /* ARABIC LETTER NOON GHUNNA */ + {XK_Arabic_heh_doachashmee, 0x06be}, /* ARABIC LETTER HEH DOACHASHMEE */ + {XK_Arabic_farsi_yeh, 0x06cc}, /* ARABIC LETTER FARSI YEH */ + {XK_Arabic_yeh_baree, 0x06d2}, /* ARABIC LETTER YEH BAREE */ + {XK_Arabic_heh_goal, 0x06c1}, /* ARABIC LETTER HEH GOAL */ +#endif // defined(XK_Farsi_0) #if defined(XK_Serbian_dje) -{ XK_Serbian_dje, 0x0452 }, /* CYRILLIC SMALL LETTER DJE */ -{ XK_Macedonia_gje, 0x0453 }, /* CYRILLIC SMALL LETTER GJE */ -{ XK_Cyrillic_io, 0x0451 }, /* CYRILLIC SMALL LETTER IO */ -{ XK_Ukrainian_ie, 0x0454 }, /* CYRILLIC SMALL LETTER UKRAINIAN IE */ -{ XK_Macedonia_dse, 0x0455 }, /* CYRILLIC SMALL LETTER DZE */ -{ XK_Ukrainian_i, 0x0456 }, /* CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I */ -{ XK_Ukrainian_yi, 0x0457 }, /* CYRILLIC SMALL LETTER YI */ -{ XK_Cyrillic_je, 0x0458 }, /* CYRILLIC SMALL LETTER JE */ -{ XK_Cyrillic_lje, 0x0459 }, /* CYRILLIC SMALL LETTER LJE */ -{ XK_Cyrillic_nje, 0x045a }, /* CYRILLIC SMALL LETTER NJE */ -{ XK_Serbian_tshe, 0x045b }, /* CYRILLIC SMALL LETTER TSHE */ -{ XK_Macedonia_kje, 0x045c }, /* CYRILLIC SMALL LETTER KJE */ + {XK_Serbian_dje, 0x0452}, /* CYRILLIC SMALL LETTER DJE */ + {XK_Macedonia_gje, 0x0453}, /* CYRILLIC SMALL LETTER GJE */ + {XK_Cyrillic_io, 0x0451}, /* CYRILLIC SMALL LETTER IO */ + {XK_Ukrainian_ie, 0x0454}, /* CYRILLIC SMALL LETTER UKRAINIAN IE */ + {XK_Macedonia_dse, 0x0455}, /* CYRILLIC SMALL LETTER DZE */ + {XK_Ukrainian_i, + 0x0456}, /* CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I */ + {XK_Ukrainian_yi, 0x0457}, /* CYRILLIC SMALL LETTER YI */ + {XK_Cyrillic_je, 0x0458}, /* CYRILLIC SMALL LETTER JE */ + {XK_Cyrillic_lje, 0x0459}, /* CYRILLIC SMALL LETTER LJE */ + {XK_Cyrillic_nje, 0x045a}, /* CYRILLIC SMALL LETTER NJE */ + {XK_Serbian_tshe, 0x045b}, /* CYRILLIC SMALL LETTER TSHE */ + {XK_Macedonia_kje, 0x045c}, /* CYRILLIC SMALL LETTER KJE */ #if defined(XK_Ukrainian_ghe_with_upturn) -{ XK_Ukrainian_ghe_with_upturn, 0x0491 }, /* CYRILLIC SMALL LETTER GHE WITH UPTURN */ + {XK_Ukrainian_ghe_with_upturn, + 0x0491}, /* CYRILLIC SMALL LETTER GHE WITH UPTURN */ #endif -{ XK_Byelorussian_shortu, 0x045e }, /* CYRILLIC SMALL LETTER SHORT U */ -{ XK_Cyrillic_dzhe, 0x045f }, /* CYRILLIC SMALL LETTER DZHE */ -{ XK_numerosign, 0x2116 }, /* NUMERO SIGN */ -{ XK_Serbian_DJE, 0x0402 }, /* CYRILLIC CAPITAL LETTER DJE */ -{ XK_Macedonia_GJE, 0x0403 }, /* CYRILLIC CAPITAL LETTER GJE */ -{ XK_Cyrillic_IO, 0x0401 }, /* CYRILLIC CAPITAL LETTER IO */ -{ XK_Ukrainian_IE, 0x0404 }, /* CYRILLIC CAPITAL LETTER UKRAINIAN IE */ -{ XK_Macedonia_DSE, 0x0405 }, /* CYRILLIC CAPITAL LETTER DZE */ -{ XK_Ukrainian_I, 0x0406 }, /* CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I */ -{ XK_Ukrainian_YI, 0x0407 }, /* CYRILLIC CAPITAL LETTER YI */ -{ XK_Cyrillic_JE, 0x0408 }, /* CYRILLIC CAPITAL LETTER JE */ -{ XK_Cyrillic_LJE, 0x0409 }, /* CYRILLIC CAPITAL LETTER LJE */ -{ XK_Cyrillic_NJE, 0x040a }, /* CYRILLIC CAPITAL LETTER NJE */ -{ XK_Serbian_TSHE, 0x040b }, /* CYRILLIC CAPITAL LETTER TSHE */ -{ XK_Macedonia_KJE, 0x040c }, /* CYRILLIC CAPITAL LETTER KJE */ + {XK_Byelorussian_shortu, 0x045e}, /* CYRILLIC SMALL LETTER SHORT U */ + {XK_Cyrillic_dzhe, 0x045f}, /* CYRILLIC SMALL LETTER DZHE */ + {XK_numerosign, 0x2116}, /* NUMERO SIGN */ + {XK_Serbian_DJE, 0x0402}, /* CYRILLIC CAPITAL LETTER DJE */ + {XK_Macedonia_GJE, 0x0403}, /* CYRILLIC CAPITAL LETTER GJE */ + {XK_Cyrillic_IO, 0x0401}, /* CYRILLIC CAPITAL LETTER IO */ + {XK_Ukrainian_IE, 0x0404}, /* CYRILLIC CAPITAL LETTER UKRAINIAN IE */ + {XK_Macedonia_DSE, 0x0405}, /* CYRILLIC CAPITAL LETTER DZE */ + {XK_Ukrainian_I, + 0x0406}, /* CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I */ + {XK_Ukrainian_YI, 0x0407}, /* CYRILLIC CAPITAL LETTER YI */ + {XK_Cyrillic_JE, 0x0408}, /* CYRILLIC CAPITAL LETTER JE */ + {XK_Cyrillic_LJE, 0x0409}, /* CYRILLIC CAPITAL LETTER LJE */ + {XK_Cyrillic_NJE, 0x040a}, /* CYRILLIC CAPITAL LETTER NJE */ + {XK_Serbian_TSHE, 0x040b}, /* CYRILLIC CAPITAL LETTER TSHE */ + {XK_Macedonia_KJE, 0x040c}, /* CYRILLIC CAPITAL LETTER KJE */ #if defined(XK_Ukrainian_GHE_WITH_UPTURN) -{ XK_Ukrainian_GHE_WITH_UPTURN, 0x0490 }, /* CYRILLIC CAPITAL LETTER GHE WITH UPTURN */ + {XK_Ukrainian_GHE_WITH_UPTURN, + 0x0490}, /* CYRILLIC CAPITAL LETTER GHE WITH UPTURN */ #endif -{ XK_Byelorussian_SHORTU, 0x040e }, /* CYRILLIC CAPITAL LETTER SHORT U */ -{ XK_Cyrillic_DZHE, 0x040f }, /* CYRILLIC CAPITAL LETTER DZHE */ -{ XK_Cyrillic_yu, 0x044e }, /* CYRILLIC SMALL LETTER YU */ -{ XK_Cyrillic_a, 0x0430 }, /* CYRILLIC SMALL LETTER A */ -{ XK_Cyrillic_be, 0x0431 }, /* CYRILLIC SMALL LETTER BE */ -{ XK_Cyrillic_tse, 0x0446 }, /* CYRILLIC SMALL LETTER TSE */ -{ XK_Cyrillic_de, 0x0434 }, /* CYRILLIC SMALL LETTER DE */ -{ XK_Cyrillic_ie, 0x0435 }, /* CYRILLIC SMALL LETTER IE */ -{ XK_Cyrillic_ef, 0x0444 }, /* CYRILLIC SMALL LETTER EF */ -{ XK_Cyrillic_ghe, 0x0433 }, /* CYRILLIC SMALL LETTER GHE */ -{ XK_Cyrillic_ha, 0x0445 }, /* CYRILLIC SMALL LETTER HA */ -{ XK_Cyrillic_i, 0x0438 }, /* CYRILLIC SMALL LETTER I */ -{ XK_Cyrillic_shorti, 0x0439 }, /* CYRILLIC SMALL LETTER SHORT I */ -{ XK_Cyrillic_ka, 0x043a }, /* CYRILLIC SMALL LETTER KA */ -{ XK_Cyrillic_el, 0x043b }, /* CYRILLIC SMALL LETTER EL */ -{ XK_Cyrillic_em, 0x043c }, /* CYRILLIC SMALL LETTER EM */ -{ XK_Cyrillic_en, 0x043d }, /* CYRILLIC SMALL LETTER EN */ -{ XK_Cyrillic_o, 0x043e }, /* CYRILLIC SMALL LETTER O */ -{ XK_Cyrillic_pe, 0x043f }, /* CYRILLIC SMALL LETTER PE */ -{ XK_Cyrillic_ya, 0x044f }, /* CYRILLIC SMALL LETTER YA */ -{ XK_Cyrillic_er, 0x0440 }, /* CYRILLIC SMALL LETTER ER */ -{ XK_Cyrillic_es, 0x0441 }, /* CYRILLIC SMALL LETTER ES */ -{ XK_Cyrillic_te, 0x0442 }, /* CYRILLIC SMALL LETTER TE */ -{ XK_Cyrillic_u, 0x0443 }, /* CYRILLIC SMALL LETTER U */ -{ XK_Cyrillic_zhe, 0x0436 }, /* CYRILLIC SMALL LETTER ZHE */ -{ XK_Cyrillic_ve, 0x0432 }, /* CYRILLIC SMALL LETTER VE */ -{ XK_Cyrillic_softsign, 0x044c }, /* CYRILLIC SMALL LETTER SOFT SIGN */ -{ XK_Cyrillic_yeru, 0x044b }, /* CYRILLIC SMALL LETTER YERU */ -{ XK_Cyrillic_ze, 0x0437 }, /* CYRILLIC SMALL LETTER ZE */ -{ XK_Cyrillic_sha, 0x0448 }, /* CYRILLIC SMALL LETTER SHA */ -{ XK_Cyrillic_e, 0x044d }, /* CYRILLIC SMALL LETTER E */ -{ XK_Cyrillic_shcha, 0x0449 }, /* CYRILLIC SMALL LETTER SHCHA */ -{ XK_Cyrillic_che, 0x0447 }, /* CYRILLIC SMALL LETTER CHE */ -{ XK_Cyrillic_hardsign, 0x044a }, /* CYRILLIC SMALL LETTER HARD SIGN */ -{ XK_Cyrillic_YU, 0x042e }, /* CYRILLIC CAPITAL LETTER YU */ -{ XK_Cyrillic_A, 0x0410 }, /* CYRILLIC CAPITAL LETTER A */ -{ XK_Cyrillic_BE, 0x0411 }, /* CYRILLIC CAPITAL LETTER BE */ -{ XK_Cyrillic_TSE, 0x0426 }, /* CYRILLIC CAPITAL LETTER TSE */ -{ XK_Cyrillic_DE, 0x0414 }, /* CYRILLIC CAPITAL LETTER DE */ -{ XK_Cyrillic_IE, 0x0415 }, /* CYRILLIC CAPITAL LETTER IE */ -{ XK_Cyrillic_EF, 0x0424 }, /* CYRILLIC CAPITAL LETTER EF */ -{ XK_Cyrillic_GHE, 0x0413 }, /* CYRILLIC CAPITAL LETTER GHE */ -{ XK_Cyrillic_HA, 0x0425 }, /* CYRILLIC CAPITAL LETTER HA */ -{ XK_Cyrillic_I, 0x0418 }, /* CYRILLIC CAPITAL LETTER I */ -{ XK_Cyrillic_SHORTI, 0x0419 }, /* CYRILLIC CAPITAL LETTER SHORT I */ -{ XK_Cyrillic_KA, 0x041a }, /* CYRILLIC CAPITAL LETTER KA */ -{ XK_Cyrillic_EL, 0x041b }, /* CYRILLIC CAPITAL LETTER EL */ -{ XK_Cyrillic_EM, 0x041c }, /* CYRILLIC CAPITAL LETTER EM */ -{ XK_Cyrillic_EN, 0x041d }, /* CYRILLIC CAPITAL LETTER EN */ -{ XK_Cyrillic_O, 0x041e }, /* CYRILLIC CAPITAL LETTER O */ -{ XK_Cyrillic_PE, 0x041f }, /* CYRILLIC CAPITAL LETTER PE */ -{ XK_Cyrillic_YA, 0x042f }, /* CYRILLIC CAPITAL LETTER YA */ -{ XK_Cyrillic_ER, 0x0420 }, /* CYRILLIC CAPITAL LETTER ER */ -{ XK_Cyrillic_ES, 0x0421 }, /* CYRILLIC CAPITAL LETTER ES */ -{ XK_Cyrillic_TE, 0x0422 }, /* CYRILLIC CAPITAL LETTER TE */ -{ XK_Cyrillic_U, 0x0423 }, /* CYRILLIC CAPITAL LETTER U */ -{ XK_Cyrillic_ZHE, 0x0416 }, /* CYRILLIC CAPITAL LETTER ZHE */ -{ XK_Cyrillic_VE, 0x0412 }, /* CYRILLIC CAPITAL LETTER VE */ -{ XK_Cyrillic_SOFTSIGN, 0x042c }, /* CYRILLIC CAPITAL LETTER SOFT SIGN */ -{ XK_Cyrillic_YERU, 0x042b }, /* CYRILLIC CAPITAL LETTER YERU */ -{ XK_Cyrillic_ZE, 0x0417 }, /* CYRILLIC CAPITAL LETTER ZE */ -{ XK_Cyrillic_SHA, 0x0428 }, /* CYRILLIC CAPITAL LETTER SHA */ -{ XK_Cyrillic_E, 0x042d }, /* CYRILLIC CAPITAL LETTER E */ -{ XK_Cyrillic_SHCHA, 0x0429 }, /* CYRILLIC CAPITAL LETTER SHCHA */ -{ XK_Cyrillic_CHE, 0x0427 }, /* CYRILLIC CAPITAL LETTER CHE */ -{ XK_Cyrillic_HARDSIGN, 0x042a }, /* CYRILLIC CAPITAL LETTER HARD SIGN */ -#endif // defined(XK_Serbian_dje) + {XK_Byelorussian_SHORTU, 0x040e}, /* CYRILLIC CAPITAL LETTER SHORT U */ + {XK_Cyrillic_DZHE, 0x040f}, /* CYRILLIC CAPITAL LETTER DZHE */ + {XK_Cyrillic_yu, 0x044e}, /* CYRILLIC SMALL LETTER YU */ + {XK_Cyrillic_a, 0x0430}, /* CYRILLIC SMALL LETTER A */ + {XK_Cyrillic_be, 0x0431}, /* CYRILLIC SMALL LETTER BE */ + {XK_Cyrillic_tse, 0x0446}, /* CYRILLIC SMALL LETTER TSE */ + {XK_Cyrillic_de, 0x0434}, /* CYRILLIC SMALL LETTER DE */ + {XK_Cyrillic_ie, 0x0435}, /* CYRILLIC SMALL LETTER IE */ + {XK_Cyrillic_ef, 0x0444}, /* CYRILLIC SMALL LETTER EF */ + {XK_Cyrillic_ghe, 0x0433}, /* CYRILLIC SMALL LETTER GHE */ + {XK_Cyrillic_ha, 0x0445}, /* CYRILLIC SMALL LETTER HA */ + {XK_Cyrillic_i, 0x0438}, /* CYRILLIC SMALL LETTER I */ + {XK_Cyrillic_shorti, 0x0439}, /* CYRILLIC SMALL LETTER SHORT I */ + {XK_Cyrillic_ka, 0x043a}, /* CYRILLIC SMALL LETTER KA */ + {XK_Cyrillic_el, 0x043b}, /* CYRILLIC SMALL LETTER EL */ + {XK_Cyrillic_em, 0x043c}, /* CYRILLIC SMALL LETTER EM */ + {XK_Cyrillic_en, 0x043d}, /* CYRILLIC SMALL LETTER EN */ + {XK_Cyrillic_o, 0x043e}, /* CYRILLIC SMALL LETTER O */ + {XK_Cyrillic_pe, 0x043f}, /* CYRILLIC SMALL LETTER PE */ + {XK_Cyrillic_ya, 0x044f}, /* CYRILLIC SMALL LETTER YA */ + {XK_Cyrillic_er, 0x0440}, /* CYRILLIC SMALL LETTER ER */ + {XK_Cyrillic_es, 0x0441}, /* CYRILLIC SMALL LETTER ES */ + {XK_Cyrillic_te, 0x0442}, /* CYRILLIC SMALL LETTER TE */ + {XK_Cyrillic_u, 0x0443}, /* CYRILLIC SMALL LETTER U */ + {XK_Cyrillic_zhe, 0x0436}, /* CYRILLIC SMALL LETTER ZHE */ + {XK_Cyrillic_ve, 0x0432}, /* CYRILLIC SMALL LETTER VE */ + {XK_Cyrillic_softsign, 0x044c}, /* CYRILLIC SMALL LETTER SOFT SIGN */ + {XK_Cyrillic_yeru, 0x044b}, /* CYRILLIC SMALL LETTER YERU */ + {XK_Cyrillic_ze, 0x0437}, /* CYRILLIC SMALL LETTER ZE */ + {XK_Cyrillic_sha, 0x0448}, /* CYRILLIC SMALL LETTER SHA */ + {XK_Cyrillic_e, 0x044d}, /* CYRILLIC SMALL LETTER E */ + {XK_Cyrillic_shcha, 0x0449}, /* CYRILLIC SMALL LETTER SHCHA */ + {XK_Cyrillic_che, 0x0447}, /* CYRILLIC SMALL LETTER CHE */ + {XK_Cyrillic_hardsign, 0x044a}, /* CYRILLIC SMALL LETTER HARD SIGN */ + {XK_Cyrillic_YU, 0x042e}, /* CYRILLIC CAPITAL LETTER YU */ + {XK_Cyrillic_A, 0x0410}, /* CYRILLIC CAPITAL LETTER A */ + {XK_Cyrillic_BE, 0x0411}, /* CYRILLIC CAPITAL LETTER BE */ + {XK_Cyrillic_TSE, 0x0426}, /* CYRILLIC CAPITAL LETTER TSE */ + {XK_Cyrillic_DE, 0x0414}, /* CYRILLIC CAPITAL LETTER DE */ + {XK_Cyrillic_IE, 0x0415}, /* CYRILLIC CAPITAL LETTER IE */ + {XK_Cyrillic_EF, 0x0424}, /* CYRILLIC CAPITAL LETTER EF */ + {XK_Cyrillic_GHE, 0x0413}, /* CYRILLIC CAPITAL LETTER GHE */ + {XK_Cyrillic_HA, 0x0425}, /* CYRILLIC CAPITAL LETTER HA */ + {XK_Cyrillic_I, 0x0418}, /* CYRILLIC CAPITAL LETTER I */ + {XK_Cyrillic_SHORTI, 0x0419}, /* CYRILLIC CAPITAL LETTER SHORT I */ + {XK_Cyrillic_KA, 0x041a}, /* CYRILLIC CAPITAL LETTER KA */ + {XK_Cyrillic_EL, 0x041b}, /* CYRILLIC CAPITAL LETTER EL */ + {XK_Cyrillic_EM, 0x041c}, /* CYRILLIC CAPITAL LETTER EM */ + {XK_Cyrillic_EN, 0x041d}, /* CYRILLIC CAPITAL LETTER EN */ + {XK_Cyrillic_O, 0x041e}, /* CYRILLIC CAPITAL LETTER O */ + {XK_Cyrillic_PE, 0x041f}, /* CYRILLIC CAPITAL LETTER PE */ + {XK_Cyrillic_YA, 0x042f}, /* CYRILLIC CAPITAL LETTER YA */ + {XK_Cyrillic_ER, 0x0420}, /* CYRILLIC CAPITAL LETTER ER */ + {XK_Cyrillic_ES, 0x0421}, /* CYRILLIC CAPITAL LETTER ES */ + {XK_Cyrillic_TE, 0x0422}, /* CYRILLIC CAPITAL LETTER TE */ + {XK_Cyrillic_U, 0x0423}, /* CYRILLIC CAPITAL LETTER U */ + {XK_Cyrillic_ZHE, 0x0416}, /* CYRILLIC CAPITAL LETTER ZHE */ + {XK_Cyrillic_VE, 0x0412}, /* CYRILLIC CAPITAL LETTER VE */ + {XK_Cyrillic_SOFTSIGN, 0x042c}, /* CYRILLIC CAPITAL LETTER SOFT SIGN */ + {XK_Cyrillic_YERU, 0x042b}, /* CYRILLIC CAPITAL LETTER YERU */ + {XK_Cyrillic_ZE, 0x0417}, /* CYRILLIC CAPITAL LETTER ZE */ + {XK_Cyrillic_SHA, 0x0428}, /* CYRILLIC CAPITAL LETTER SHA */ + {XK_Cyrillic_E, 0x042d}, /* CYRILLIC CAPITAL LETTER E */ + {XK_Cyrillic_SHCHA, 0x0429}, /* CYRILLIC CAPITAL LETTER SHCHA */ + {XK_Cyrillic_CHE, 0x0427}, /* CYRILLIC CAPITAL LETTER CHE */ + {XK_Cyrillic_HARDSIGN, 0x042a}, /* CYRILLIC CAPITAL LETTER HARD SIGN */ +#endif // defined(XK_Serbian_dje) #if defined(XK_Greek_ALPHAaccent) -{ XK_Greek_ALPHAaccent, 0x0386 }, /* GREEK CAPITAL LETTER ALPHA WITH TONOS */ -{ XK_Greek_EPSILONaccent, 0x0388 }, /* GREEK CAPITAL LETTER EPSILON WITH TONOS */ -{ XK_Greek_ETAaccent, 0x0389 }, /* GREEK CAPITAL LETTER ETA WITH TONOS */ -{ XK_Greek_IOTAaccent, 0x038a }, /* GREEK CAPITAL LETTER IOTA WITH TONOS */ -{ XK_Greek_IOTAdiaeresis, 0x03aa }, /* GREEK CAPITAL LETTER IOTA WITH DIALYTIKA */ -{ XK_Greek_OMICRONaccent, 0x038c }, /* GREEK CAPITAL LETTER OMICRON WITH TONOS */ -{ XK_Greek_UPSILONaccent, 0x038e }, /* GREEK CAPITAL LETTER UPSILON WITH TONOS */ -{ XK_Greek_UPSILONdieresis, 0x03ab }, /* GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA */ -{ XK_Greek_OMEGAaccent, 0x038f }, /* GREEK CAPITAL LETTER OMEGA WITH TONOS */ -{ XK_Greek_accentdieresis, 0x0385 }, /* GREEK DIALYTIKA TONOS */ -{ XK_Greek_horizbar, 0x2015 }, /* HORIZONTAL BAR */ -{ XK_Greek_alphaaccent, 0x03ac }, /* GREEK SMALL LETTER ALPHA WITH TONOS */ -{ XK_Greek_epsilonaccent, 0x03ad }, /* GREEK SMALL LETTER EPSILON WITH TONOS */ -{ XK_Greek_etaaccent, 0x03ae }, /* GREEK SMALL LETTER ETA WITH TONOS */ -{ XK_Greek_iotaaccent, 0x03af }, /* GREEK SMALL LETTER IOTA WITH TONOS */ -{ XK_Greek_iotadieresis, 0x03ca }, /* GREEK SMALL LETTER IOTA WITH DIALYTIKA */ -{ XK_Greek_iotaaccentdieresis, 0x0390 }, /* GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS */ -{ XK_Greek_omicronaccent, 0x03cc }, /* GREEK SMALL LETTER OMICRON WITH TONOS */ -{ XK_Greek_upsilonaccent, 0x03cd }, /* GREEK SMALL LETTER UPSILON WITH TONOS */ -{ XK_Greek_upsilondieresis, 0x03cb }, /* GREEK SMALL LETTER UPSILON WITH DIALYTIKA */ -{ XK_Greek_upsilonaccentdieresis, 0x03b0 }, /* GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS */ -{ XK_Greek_omegaaccent, 0x03ce }, /* GREEK SMALL LETTER OMEGA WITH TONOS */ -{ XK_Greek_ALPHA, 0x0391 }, /* GREEK CAPITAL LETTER ALPHA */ -{ XK_Greek_BETA, 0x0392 }, /* GREEK CAPITAL LETTER BETA */ -{ XK_Greek_GAMMA, 0x0393 }, /* GREEK CAPITAL LETTER GAMMA */ -{ XK_Greek_DELTA, 0x0394 }, /* GREEK CAPITAL LETTER DELTA */ -{ XK_Greek_EPSILON, 0x0395 }, /* GREEK CAPITAL LETTER EPSILON */ -{ XK_Greek_ZETA, 0x0396 }, /* GREEK CAPITAL LETTER ZETA */ -{ XK_Greek_ETA, 0x0397 }, /* GREEK CAPITAL LETTER ETA */ -{ XK_Greek_THETA, 0x0398 }, /* GREEK CAPITAL LETTER THETA */ -{ XK_Greek_IOTA, 0x0399 }, /* GREEK CAPITAL LETTER IOTA */ -{ XK_Greek_KAPPA, 0x039a }, /* GREEK CAPITAL LETTER KAPPA */ -{ XK_Greek_LAMBDA, 0x039b }, /* GREEK CAPITAL LETTER LAMDA */ -{ XK_Greek_MU, 0x039c }, /* GREEK CAPITAL LETTER MU */ -{ XK_Greek_NU, 0x039d }, /* GREEK CAPITAL LETTER NU */ -{ XK_Greek_XI, 0x039e }, /* GREEK CAPITAL LETTER XI */ -{ XK_Greek_OMICRON, 0x039f }, /* GREEK CAPITAL LETTER OMICRON */ -{ XK_Greek_PI, 0x03a0 }, /* GREEK CAPITAL LETTER PI */ -{ XK_Greek_RHO, 0x03a1 }, /* GREEK CAPITAL LETTER RHO */ -{ XK_Greek_SIGMA, 0x03a3 }, /* GREEK CAPITAL LETTER SIGMA */ -{ XK_Greek_TAU, 0x03a4 }, /* GREEK CAPITAL LETTER TAU */ -{ XK_Greek_UPSILON, 0x03a5 }, /* GREEK CAPITAL LETTER UPSILON */ -{ XK_Greek_PHI, 0x03a6 }, /* GREEK CAPITAL LETTER PHI */ -{ XK_Greek_CHI, 0x03a7 }, /* GREEK CAPITAL LETTER CHI */ -{ XK_Greek_PSI, 0x03a8 }, /* GREEK CAPITAL LETTER PSI */ -{ XK_Greek_OMEGA, 0x03a9 }, /* GREEK CAPITAL LETTER OMEGA */ -{ XK_Greek_alpha, 0x03b1 }, /* GREEK SMALL LETTER ALPHA */ -{ XK_Greek_beta, 0x03b2 }, /* GREEK SMALL LETTER BETA */ -{ XK_Greek_gamma, 0x03b3 }, /* GREEK SMALL LETTER GAMMA */ -{ XK_Greek_delta, 0x03b4 }, /* GREEK SMALL LETTER DELTA */ -{ XK_Greek_epsilon, 0x03b5 }, /* GREEK SMALL LETTER EPSILON */ -{ XK_Greek_zeta, 0x03b6 }, /* GREEK SMALL LETTER ZETA */ -{ XK_Greek_eta, 0x03b7 }, /* GREEK SMALL LETTER ETA */ -{ XK_Greek_theta, 0x03b8 }, /* GREEK SMALL LETTER THETA */ -{ XK_Greek_iota, 0x03b9 }, /* GREEK SMALL LETTER IOTA */ -{ XK_Greek_kappa, 0x03ba }, /* GREEK SMALL LETTER KAPPA */ -{ XK_Greek_lambda, 0x03bb }, /* GREEK SMALL LETTER LAMDA */ -{ XK_Greek_mu, 0x03bc }, /* GREEK SMALL LETTER MU */ -{ XK_Greek_nu, 0x03bd }, /* GREEK SMALL LETTER NU */ -{ XK_Greek_xi, 0x03be }, /* GREEK SMALL LETTER XI */ -{ XK_Greek_omicron, 0x03bf }, /* GREEK SMALL LETTER OMICRON */ -{ XK_Greek_pi, 0x03c0 }, /* GREEK SMALL LETTER PI */ -{ XK_Greek_rho, 0x03c1 }, /* GREEK SMALL LETTER RHO */ -{ XK_Greek_sigma, 0x03c3 }, /* GREEK SMALL LETTER SIGMA */ -{ XK_Greek_finalsmallsigma, 0x03c2 }, /* GREEK SMALL LETTER FINAL SIGMA */ -{ XK_Greek_tau, 0x03c4 }, /* GREEK SMALL LETTER TAU */ -{ XK_Greek_upsilon, 0x03c5 }, /* GREEK SMALL LETTER UPSILON */ -{ XK_Greek_phi, 0x03c6 }, /* GREEK SMALL LETTER PHI */ -{ XK_Greek_chi, 0x03c7 }, /* GREEK SMALL LETTER CHI */ -{ XK_Greek_psi, 0x03c8 }, /* GREEK SMALL LETTER PSI */ -{ XK_Greek_omega, 0x03c9 }, /* GREEK SMALL LETTER OMEGA */ -#endif // defined(XK_Greek_ALPHAaccent) -{ XK_leftradical, 0x23b7 }, /* ??? */ -{ XK_topleftradical, 0x250c }, /* BOX DRAWINGS LIGHT DOWN AND RIGHT */ -{ XK_horizconnector, 0x2500 }, /* BOX DRAWINGS LIGHT HORIZONTAL */ -{ XK_topintegral, 0x2320 }, /* TOP HALF INTEGRAL */ -{ XK_botintegral, 0x2321 }, /* BOTTOM HALF INTEGRAL */ -{ XK_vertconnector, 0x2502 }, /* BOX DRAWINGS LIGHT VERTICAL */ -{ XK_topleftsqbracket, 0x23a1 }, /* ??? */ -{ XK_botleftsqbracket, 0x23a3 }, /* ??? */ -{ XK_toprightsqbracket, 0x23a4 }, /* ??? */ -{ XK_botrightsqbracket, 0x23a6 }, /* ??? */ -{ XK_topleftparens, 0x239b }, /* ??? */ -{ XK_botleftparens, 0x239d }, /* ??? */ -{ XK_toprightparens, 0x239e }, /* ??? */ -{ XK_botrightparens, 0x23a0 }, /* ??? */ -{ XK_leftmiddlecurlybrace, 0x23a8 }, /* ??? */ -{ XK_rightmiddlecurlybrace, 0x23ac }, /* ??? */ -{ XK_lessthanequal, 0x2264 }, /* LESS-THAN OR EQUAL TO */ -{ XK_notequal, 0x2260 }, /* NOT EQUAL TO */ -{ XK_greaterthanequal, 0x2265 }, /* GREATER-THAN OR EQUAL TO */ -{ XK_integral, 0x222b }, /* INTEGRAL */ -{ XK_therefore, 0x2234 }, /* THEREFORE */ -{ XK_variation, 0x221d }, /* PROPORTIONAL TO */ -{ XK_infinity, 0x221e }, /* INFINITY */ -{ XK_nabla, 0x2207 }, /* NABLA */ -{ XK_approximate, 0x223c }, /* TILDE OPERATOR */ -{ XK_similarequal, 0x2243 }, /* ASYMPTOTICALLY EQUAL TO */ -{ XK_ifonlyif, 0x21d4 }, /* LEFT RIGHT DOUBLE ARROW */ -{ XK_implies, 0x21d2 }, /* RIGHTWARDS DOUBLE ARROW */ -{ XK_identical, 0x2261 }, /* IDENTICAL TO */ -{ XK_radical, 0x221a }, /* SQUARE ROOT */ -{ XK_includedin, 0x2282 }, /* SUBSET OF */ -{ XK_includes, 0x2283 }, /* SUPERSET OF */ -{ XK_intersection, 0x2229 }, /* INTERSECTION */ -{ XK_union, 0x222a }, /* UNION */ -{ XK_logicaland, 0x2227 }, /* LOGICAL AND */ -{ XK_logicalor, 0x2228 }, /* LOGICAL OR */ -{ XK_partialderivative, 0x2202 }, /* PARTIAL DIFFERENTIAL */ -{ XK_function, 0x0192 }, /* LATIN SMALL LETTER F WITH HOOK */ -{ XK_leftarrow, 0x2190 }, /* LEFTWARDS ARROW */ -{ XK_uparrow, 0x2191 }, /* UPWARDS ARROW */ -{ XK_rightarrow, 0x2192 }, /* RIGHTWARDS ARROW */ -{ XK_downarrow, 0x2193 }, /* DOWNWARDS ARROW */ -/*{ XK_blank, ??? }, */ -{ XK_soliddiamond, 0x25c6 }, /* BLACK DIAMOND */ -{ XK_checkerboard, 0x2592 }, /* MEDIUM SHADE */ -{ XK_ht, 0x2409 }, /* SYMBOL FOR HORIZONTAL TABULATION */ -{ XK_ff, 0x240c }, /* SYMBOL FOR FORM FEED */ -{ XK_cr, 0x240d }, /* SYMBOL FOR CARRIAGE RETURN */ -{ XK_lf, 0x240a }, /* SYMBOL FOR LINE FEED */ -{ XK_nl, 0x2424 }, /* SYMBOL FOR NEWLINE */ -{ XK_vt, 0x240b }, /* SYMBOL FOR VERTICAL TABULATION */ -{ XK_lowrightcorner, 0x2518 }, /* BOX DRAWINGS LIGHT UP AND LEFT */ -{ XK_uprightcorner, 0x2510 }, /* BOX DRAWINGS LIGHT DOWN AND LEFT */ -{ XK_upleftcorner, 0x250c }, /* BOX DRAWINGS LIGHT DOWN AND RIGHT */ -{ XK_lowleftcorner, 0x2514 }, /* BOX DRAWINGS LIGHT UP AND RIGHT */ -{ XK_crossinglines, 0x253c }, /* BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL */ -{ XK_horizlinescan1, 0x23ba }, /* HORIZONTAL SCAN LINE-1 (Unicode 3.2 draft) */ -{ XK_horizlinescan3, 0x23bb }, /* HORIZONTAL SCAN LINE-3 (Unicode 3.2 draft) */ -{ XK_horizlinescan5, 0x2500 }, /* BOX DRAWINGS LIGHT HORIZONTAL */ -{ XK_horizlinescan7, 0x23bc }, /* HORIZONTAL SCAN LINE-7 (Unicode 3.2 draft) */ -{ XK_horizlinescan9, 0x23bd }, /* HORIZONTAL SCAN LINE-9 (Unicode 3.2 draft) */ -{ XK_leftt, 0x251c }, /* BOX DRAWINGS LIGHT VERTICAL AND RIGHT */ -{ XK_rightt, 0x2524 }, /* BOX DRAWINGS LIGHT VERTICAL AND LEFT */ -{ XK_bott, 0x2534 }, /* BOX DRAWINGS LIGHT UP AND HORIZONTAL */ -{ XK_topt, 0x252c }, /* BOX DRAWINGS LIGHT DOWN AND HORIZONTAL */ -{ XK_vertbar, 0x2502 }, /* BOX DRAWINGS LIGHT VERTICAL */ -{ XK_emspace, 0x2003 }, /* EM SPACE */ -{ XK_enspace, 0x2002 }, /* EN SPACE */ -{ XK_em3space, 0x2004 }, /* THREE-PER-EM SPACE */ -{ XK_em4space, 0x2005 }, /* FOUR-PER-EM SPACE */ -{ XK_digitspace, 0x2007 }, /* FIGURE SPACE */ -{ XK_punctspace, 0x2008 }, /* PUNCTUATION SPACE */ -{ XK_thinspace, 0x2009 }, /* THIN SPACE */ -{ XK_hairspace, 0x200a }, /* HAIR SPACE */ -{ XK_emdash, 0x2014 }, /* EM DASH */ -{ XK_endash, 0x2013 }, /* EN DASH */ -/*{ XK_signifblank, ??? }, */ -{ XK_ellipsis, 0x2026 }, /* HORIZONTAL ELLIPSIS */ -{ XK_doubbaselinedot, 0x2025 }, /* TWO DOT LEADER */ -{ XK_onethird, 0x2153 }, /* VULGAR FRACTION ONE THIRD */ -{ XK_twothirds, 0x2154 }, /* VULGAR FRACTION TWO THIRDS */ -{ XK_onefifth, 0x2155 }, /* VULGAR FRACTION ONE FIFTH */ -{ XK_twofifths, 0x2156 }, /* VULGAR FRACTION TWO FIFTHS */ -{ XK_threefifths, 0x2157 }, /* VULGAR FRACTION THREE FIFTHS */ -{ XK_fourfifths, 0x2158 }, /* VULGAR FRACTION FOUR FIFTHS */ -{ XK_onesixth, 0x2159 }, /* VULGAR FRACTION ONE SIXTH */ -{ XK_fivesixths, 0x215a }, /* VULGAR FRACTION FIVE SIXTHS */ -{ XK_careof, 0x2105 }, /* CARE OF */ -{ XK_figdash, 0x2012 }, /* FIGURE DASH */ -{ XK_leftanglebracket, 0x2329 }, /* LEFT-POINTING ANGLE BRACKET */ -/*{ XK_decimalpoint, ??? }, */ -{ XK_rightanglebracket, 0x232a }, /* RIGHT-POINTING ANGLE BRACKET */ -/*{ XK_marker, ??? }, */ -{ XK_oneeighth, 0x215b }, /* VULGAR FRACTION ONE EIGHTH */ -{ XK_threeeighths, 0x215c }, /* VULGAR FRACTION THREE EIGHTHS */ -{ XK_fiveeighths, 0x215d }, /* VULGAR FRACTION FIVE EIGHTHS */ -{ XK_seveneighths, 0x215e }, /* VULGAR FRACTION SEVEN EIGHTHS */ -{ XK_trademark, 0x2122 }, /* TRADE MARK SIGN */ -{ XK_signaturemark, 0x2613 }, /* SALTIRE */ -/*{ XK_trademarkincircle, ??? }, */ -{ XK_leftopentriangle, 0x25c1 }, /* WHITE LEFT-POINTING TRIANGLE */ -{ XK_rightopentriangle, 0x25b7 }, /* WHITE RIGHT-POINTING TRIANGLE */ -{ XK_emopencircle, 0x25cb }, /* WHITE CIRCLE */ -{ XK_emopenrectangle, 0x25af }, /* WHITE VERTICAL RECTANGLE */ -{ XK_leftsinglequotemark, 0x2018 }, /* LEFT SINGLE QUOTATION MARK */ -{ XK_rightsinglequotemark, 0x2019 }, /* RIGHT SINGLE QUOTATION MARK */ -{ XK_leftdoublequotemark, 0x201c }, /* LEFT DOUBLE QUOTATION MARK */ -{ XK_rightdoublequotemark, 0x201d }, /* RIGHT DOUBLE QUOTATION MARK */ -{ XK_prescription, 0x211e }, /* PRESCRIPTION TAKE */ -{ XK_minutes, 0x2032 }, /* PRIME */ -{ XK_seconds, 0x2033 }, /* DOUBLE PRIME */ -{ XK_latincross, 0x271d }, /* LATIN CROSS */ -/*{ XK_hexagram, ??? }, */ -{ XK_filledrectbullet, 0x25ac }, /* BLACK RECTANGLE */ -{ XK_filledlefttribullet, 0x25c0 }, /* BLACK LEFT-POINTING TRIANGLE */ -{ XK_filledrighttribullet, 0x25b6 }, /* BLACK RIGHT-POINTING TRIANGLE */ -{ XK_emfilledcircle, 0x25cf }, /* BLACK CIRCLE */ -{ XK_emfilledrect, 0x25ae }, /* BLACK VERTICAL RECTANGLE */ -{ XK_enopencircbullet, 0x25e6 }, /* WHITE BULLET */ -{ XK_enopensquarebullet, 0x25ab }, /* WHITE SMALL SQUARE */ -{ XK_openrectbullet, 0x25ad }, /* WHITE RECTANGLE */ -{ XK_opentribulletup, 0x25b3 }, /* WHITE UP-POINTING TRIANGLE */ -{ XK_opentribulletdown, 0x25bd }, /* WHITE DOWN-POINTING TRIANGLE */ -{ XK_openstar, 0x2606 }, /* WHITE STAR */ -{ XK_enfilledcircbullet, 0x2022 }, /* BULLET */ -{ XK_enfilledsqbullet, 0x25aa }, /* BLACK SMALL SQUARE */ -{ XK_filledtribulletup, 0x25b2 }, /* BLACK UP-POINTING TRIANGLE */ -{ XK_filledtribulletdown, 0x25bc }, /* BLACK DOWN-POINTING TRIANGLE */ -{ XK_leftpointer, 0x261c }, /* WHITE LEFT POINTING INDEX */ -{ XK_rightpointer, 0x261e }, /* WHITE RIGHT POINTING INDEX */ -{ XK_club, 0x2663 }, /* BLACK CLUB SUIT */ -{ XK_diamond, 0x2666 }, /* BLACK DIAMOND SUIT */ -{ XK_heart, 0x2665 }, /* BLACK HEART SUIT */ -{ XK_maltesecross, 0x2720 }, /* MALTESE CROSS */ -{ XK_dagger, 0x2020 }, /* DAGGER */ -{ XK_doubledagger, 0x2021 }, /* DOUBLE DAGGER */ -{ XK_checkmark, 0x2713 }, /* CHECK MARK */ -{ XK_ballotcross, 0x2717 }, /* BALLOT X */ -{ XK_musicalsharp, 0x266f }, /* MUSIC SHARP SIGN */ -{ XK_musicalflat, 0x266d }, /* MUSIC FLAT SIGN */ -{ XK_malesymbol, 0x2642 }, /* MALE SIGN */ -{ XK_femalesymbol, 0x2640 }, /* FEMALE SIGN */ -{ XK_telephone, 0x260e }, /* BLACK TELEPHONE */ -{ XK_telephonerecorder, 0x2315 }, /* TELEPHONE RECORDER */ -{ XK_phonographcopyright, 0x2117 }, /* SOUND RECORDING COPYRIGHT */ -{ XK_caret, 0x2038 }, /* CARET */ -{ XK_singlelowquotemark, 0x201a }, /* SINGLE LOW-9 QUOTATION MARK */ -{ XK_doublelowquotemark, 0x201e }, /* DOUBLE LOW-9 QUOTATION MARK */ -/*{ XK_cursor, ??? }, */ -{ XK_leftcaret, 0x003c }, /* LESS-THAN SIGN */ -{ XK_rightcaret, 0x003e }, /* GREATER-THAN SIGN */ -{ XK_downcaret, 0x2228 }, /* LOGICAL OR */ -{ XK_upcaret, 0x2227 }, /* LOGICAL AND */ -{ XK_overbar, 0x00af }, /* MACRON */ -{ XK_downtack, 0x22a5 }, /* UP TACK */ -{ XK_upshoe, 0x2229 }, /* INTERSECTION */ -{ XK_downstile, 0x230a }, /* LEFT FLOOR */ -{ XK_underbar, 0x005f }, /* LOW LINE */ -{ XK_jot, 0x2218 }, /* RING OPERATOR */ -{ XK_quad, 0x2395 }, /* APL FUNCTIONAL SYMBOL QUAD */ -{ XK_uptack, 0x22a4 }, /* DOWN TACK */ -{ XK_circle, 0x25cb }, /* WHITE CIRCLE */ -{ XK_upstile, 0x2308 }, /* LEFT CEILING */ -{ XK_downshoe, 0x222a }, /* UNION */ -{ XK_rightshoe, 0x2283 }, /* SUPERSET OF */ -{ XK_leftshoe, 0x2282 }, /* SUBSET OF */ -{ XK_lefttack, 0x22a2 }, /* RIGHT TACK */ -{ XK_righttack, 0x22a3 }, /* LEFT TACK */ + {XK_Greek_ALPHAaccent, 0x0386}, /* GREEK CAPITAL LETTER ALPHA WITH TONOS */ + {XK_Greek_EPSILONaccent, + 0x0388}, /* GREEK CAPITAL LETTER EPSILON WITH TONOS */ + {XK_Greek_ETAaccent, 0x0389}, /* GREEK CAPITAL LETTER ETA WITH TONOS */ + {XK_Greek_IOTAaccent, 0x038a}, /* GREEK CAPITAL LETTER IOTA WITH TONOS */ + {XK_Greek_IOTAdiaeresis, + 0x03aa}, /* GREEK CAPITAL LETTER IOTA WITH DIALYTIKA */ + {XK_Greek_OMICRONaccent, + 0x038c}, /* GREEK CAPITAL LETTER OMICRON WITH TONOS */ + {XK_Greek_UPSILONaccent, + 0x038e}, /* GREEK CAPITAL LETTER UPSILON WITH TONOS */ + {XK_Greek_UPSILONdieresis, + 0x03ab}, /* GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA */ + {XK_Greek_OMEGAaccent, 0x038f}, /* GREEK CAPITAL LETTER OMEGA WITH TONOS */ + {XK_Greek_accentdieresis, 0x0385}, /* GREEK DIALYTIKA TONOS */ + {XK_Greek_horizbar, 0x2015}, /* HORIZONTAL BAR */ + {XK_Greek_alphaaccent, 0x03ac}, /* GREEK SMALL LETTER ALPHA WITH TONOS */ + {XK_Greek_epsilonaccent, + 0x03ad}, /* GREEK SMALL LETTER EPSILON WITH TONOS */ + {XK_Greek_etaaccent, 0x03ae}, /* GREEK SMALL LETTER ETA WITH TONOS */ + {XK_Greek_iotaaccent, 0x03af}, /* GREEK SMALL LETTER IOTA WITH TONOS */ + {XK_Greek_iotadieresis, + 0x03ca}, /* GREEK SMALL LETTER IOTA WITH DIALYTIKA */ + {XK_Greek_iotaaccentdieresis, + 0x0390}, /* GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS */ + {XK_Greek_omicronaccent, + 0x03cc}, /* GREEK SMALL LETTER OMICRON WITH TONOS */ + {XK_Greek_upsilonaccent, + 0x03cd}, /* GREEK SMALL LETTER UPSILON WITH TONOS */ + {XK_Greek_upsilondieresis, + 0x03cb}, /* GREEK SMALL LETTER UPSILON WITH DIALYTIKA */ + {XK_Greek_upsilonaccentdieresis, + 0x03b0}, /* GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS */ + {XK_Greek_omegaaccent, 0x03ce}, /* GREEK SMALL LETTER OMEGA WITH TONOS */ + {XK_Greek_ALPHA, 0x0391}, /* GREEK CAPITAL LETTER ALPHA */ + {XK_Greek_BETA, 0x0392}, /* GREEK CAPITAL LETTER BETA */ + {XK_Greek_GAMMA, 0x0393}, /* GREEK CAPITAL LETTER GAMMA */ + {XK_Greek_DELTA, 0x0394}, /* GREEK CAPITAL LETTER DELTA */ + {XK_Greek_EPSILON, 0x0395}, /* GREEK CAPITAL LETTER EPSILON */ + {XK_Greek_ZETA, 0x0396}, /* GREEK CAPITAL LETTER ZETA */ + {XK_Greek_ETA, 0x0397}, /* GREEK CAPITAL LETTER ETA */ + {XK_Greek_THETA, 0x0398}, /* GREEK CAPITAL LETTER THETA */ + {XK_Greek_IOTA, 0x0399}, /* GREEK CAPITAL LETTER IOTA */ + {XK_Greek_KAPPA, 0x039a}, /* GREEK CAPITAL LETTER KAPPA */ + {XK_Greek_LAMBDA, 0x039b}, /* GREEK CAPITAL LETTER LAMDA */ + {XK_Greek_MU, 0x039c}, /* GREEK CAPITAL LETTER MU */ + {XK_Greek_NU, 0x039d}, /* GREEK CAPITAL LETTER NU */ + {XK_Greek_XI, 0x039e}, /* GREEK CAPITAL LETTER XI */ + {XK_Greek_OMICRON, 0x039f}, /* GREEK CAPITAL LETTER OMICRON */ + {XK_Greek_PI, 0x03a0}, /* GREEK CAPITAL LETTER PI */ + {XK_Greek_RHO, 0x03a1}, /* GREEK CAPITAL LETTER RHO */ + {XK_Greek_SIGMA, 0x03a3}, /* GREEK CAPITAL LETTER SIGMA */ + {XK_Greek_TAU, 0x03a4}, /* GREEK CAPITAL LETTER TAU */ + {XK_Greek_UPSILON, 0x03a5}, /* GREEK CAPITAL LETTER UPSILON */ + {XK_Greek_PHI, 0x03a6}, /* GREEK CAPITAL LETTER PHI */ + {XK_Greek_CHI, 0x03a7}, /* GREEK CAPITAL LETTER CHI */ + {XK_Greek_PSI, 0x03a8}, /* GREEK CAPITAL LETTER PSI */ + {XK_Greek_OMEGA, 0x03a9}, /* GREEK CAPITAL LETTER OMEGA */ + {XK_Greek_alpha, 0x03b1}, /* GREEK SMALL LETTER ALPHA */ + {XK_Greek_beta, 0x03b2}, /* GREEK SMALL LETTER BETA */ + {XK_Greek_gamma, 0x03b3}, /* GREEK SMALL LETTER GAMMA */ + {XK_Greek_delta, 0x03b4}, /* GREEK SMALL LETTER DELTA */ + {XK_Greek_epsilon, 0x03b5}, /* GREEK SMALL LETTER EPSILON */ + {XK_Greek_zeta, 0x03b6}, /* GREEK SMALL LETTER ZETA */ + {XK_Greek_eta, 0x03b7}, /* GREEK SMALL LETTER ETA */ + {XK_Greek_theta, 0x03b8}, /* GREEK SMALL LETTER THETA */ + {XK_Greek_iota, 0x03b9}, /* GREEK SMALL LETTER IOTA */ + {XK_Greek_kappa, 0x03ba}, /* GREEK SMALL LETTER KAPPA */ + {XK_Greek_lambda, 0x03bb}, /* GREEK SMALL LETTER LAMDA */ + {XK_Greek_mu, 0x03bc}, /* GREEK SMALL LETTER MU */ + {XK_Greek_nu, 0x03bd}, /* GREEK SMALL LETTER NU */ + {XK_Greek_xi, 0x03be}, /* GREEK SMALL LETTER XI */ + {XK_Greek_omicron, 0x03bf}, /* GREEK SMALL LETTER OMICRON */ + {XK_Greek_pi, 0x03c0}, /* GREEK SMALL LETTER PI */ + {XK_Greek_rho, 0x03c1}, /* GREEK SMALL LETTER RHO */ + {XK_Greek_sigma, 0x03c3}, /* GREEK SMALL LETTER SIGMA */ + {XK_Greek_finalsmallsigma, 0x03c2}, /* GREEK SMALL LETTER FINAL SIGMA */ + {XK_Greek_tau, 0x03c4}, /* GREEK SMALL LETTER TAU */ + {XK_Greek_upsilon, 0x03c5}, /* GREEK SMALL LETTER UPSILON */ + {XK_Greek_phi, 0x03c6}, /* GREEK SMALL LETTER PHI */ + {XK_Greek_chi, 0x03c7}, /* GREEK SMALL LETTER CHI */ + {XK_Greek_psi, 0x03c8}, /* GREEK SMALL LETTER PSI */ + {XK_Greek_omega, 0x03c9}, /* GREEK SMALL LETTER OMEGA */ +#endif // defined(XK_Greek_ALPHAaccent) + {XK_leftradical, 0x23b7}, /* ??? */ + {XK_topleftradical, 0x250c}, /* BOX DRAWINGS LIGHT DOWN AND RIGHT */ + {XK_horizconnector, 0x2500}, /* BOX DRAWINGS LIGHT HORIZONTAL */ + {XK_topintegral, 0x2320}, /* TOP HALF INTEGRAL */ + {XK_botintegral, 0x2321}, /* BOTTOM HALF INTEGRAL */ + {XK_vertconnector, 0x2502}, /* BOX DRAWINGS LIGHT VERTICAL */ + {XK_topleftsqbracket, 0x23a1}, /* ??? */ + {XK_botleftsqbracket, 0x23a3}, /* ??? */ + {XK_toprightsqbracket, 0x23a4}, /* ??? */ + {XK_botrightsqbracket, 0x23a6}, /* ??? */ + {XK_topleftparens, 0x239b}, /* ??? */ + {XK_botleftparens, 0x239d}, /* ??? */ + {XK_toprightparens, 0x239e}, /* ??? */ + {XK_botrightparens, 0x23a0}, /* ??? */ + {XK_leftmiddlecurlybrace, 0x23a8}, /* ??? */ + {XK_rightmiddlecurlybrace, 0x23ac}, /* ??? */ + {XK_lessthanequal, 0x2264}, /* LESS-THAN OR EQUAL TO */ + {XK_notequal, 0x2260}, /* NOT EQUAL TO */ + {XK_greaterthanequal, 0x2265}, /* GREATER-THAN OR EQUAL TO */ + {XK_integral, 0x222b}, /* INTEGRAL */ + {XK_therefore, 0x2234}, /* THEREFORE */ + {XK_variation, 0x221d}, /* PROPORTIONAL TO */ + {XK_infinity, 0x221e}, /* INFINITY */ + {XK_nabla, 0x2207}, /* NABLA */ + {XK_approximate, 0x223c}, /* TILDE OPERATOR */ + {XK_similarequal, 0x2243}, /* ASYMPTOTICALLY EQUAL TO */ + {XK_ifonlyif, 0x21d4}, /* LEFT RIGHT DOUBLE ARROW */ + {XK_implies, 0x21d2}, /* RIGHTWARDS DOUBLE ARROW */ + {XK_identical, 0x2261}, /* IDENTICAL TO */ + {XK_radical, 0x221a}, /* SQUARE ROOT */ + {XK_includedin, 0x2282}, /* SUBSET OF */ + {XK_includes, 0x2283}, /* SUPERSET OF */ + {XK_intersection, 0x2229}, /* INTERSECTION */ + {XK_union, 0x222a}, /* UNION */ + {XK_logicaland, 0x2227}, /* LOGICAL AND */ + {XK_logicalor, 0x2228}, /* LOGICAL OR */ + {XK_partialderivative, 0x2202}, /* PARTIAL DIFFERENTIAL */ + {XK_function, 0x0192}, /* LATIN SMALL LETTER F WITH HOOK */ + {XK_leftarrow, 0x2190}, /* LEFTWARDS ARROW */ + {XK_uparrow, 0x2191}, /* UPWARDS ARROW */ + {XK_rightarrow, 0x2192}, /* RIGHTWARDS ARROW */ + {XK_downarrow, 0x2193}, /* DOWNWARDS ARROW */ + /*{ XK_blank, ??? }, */ + {XK_soliddiamond, 0x25c6}, /* BLACK DIAMOND */ + {XK_checkerboard, 0x2592}, /* MEDIUM SHADE */ + {XK_ht, 0x2409}, /* SYMBOL FOR HORIZONTAL TABULATION */ + {XK_ff, 0x240c}, /* SYMBOL FOR FORM FEED */ + {XK_cr, 0x240d}, /* SYMBOL FOR CARRIAGE RETURN */ + {XK_lf, 0x240a}, /* SYMBOL FOR LINE FEED */ + {XK_nl, 0x2424}, /* SYMBOL FOR NEWLINE */ + {XK_vt, 0x240b}, /* SYMBOL FOR VERTICAL TABULATION */ + {XK_lowrightcorner, 0x2518}, /* BOX DRAWINGS LIGHT UP AND LEFT */ + {XK_uprightcorner, 0x2510}, /* BOX DRAWINGS LIGHT DOWN AND LEFT */ + {XK_upleftcorner, 0x250c}, /* BOX DRAWINGS LIGHT DOWN AND RIGHT */ + {XK_lowleftcorner, 0x2514}, /* BOX DRAWINGS LIGHT UP AND RIGHT */ + {XK_crossinglines, 0x253c}, /* BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL */ + {XK_horizlinescan1, + 0x23ba}, /* HORIZONTAL SCAN LINE-1 (Unicode 3.2 draft) */ + {XK_horizlinescan3, + 0x23bb}, /* HORIZONTAL SCAN LINE-3 (Unicode 3.2 draft) */ + {XK_horizlinescan5, 0x2500}, /* BOX DRAWINGS LIGHT HORIZONTAL */ + {XK_horizlinescan7, + 0x23bc}, /* HORIZONTAL SCAN LINE-7 (Unicode 3.2 draft) */ + {XK_horizlinescan9, + 0x23bd}, /* HORIZONTAL SCAN LINE-9 (Unicode 3.2 draft) */ + {XK_leftt, 0x251c}, /* BOX DRAWINGS LIGHT VERTICAL AND RIGHT */ + {XK_rightt, 0x2524}, /* BOX DRAWINGS LIGHT VERTICAL AND LEFT */ + {XK_bott, 0x2534}, /* BOX DRAWINGS LIGHT UP AND HORIZONTAL */ + {XK_topt, 0x252c}, /* BOX DRAWINGS LIGHT DOWN AND HORIZONTAL */ + {XK_vertbar, 0x2502}, /* BOX DRAWINGS LIGHT VERTICAL */ + {XK_emspace, 0x2003}, /* EM SPACE */ + {XK_enspace, 0x2002}, /* EN SPACE */ + {XK_em3space, 0x2004}, /* THREE-PER-EM SPACE */ + {XK_em4space, 0x2005}, /* FOUR-PER-EM SPACE */ + {XK_digitspace, 0x2007}, /* FIGURE SPACE */ + {XK_punctspace, 0x2008}, /* PUNCTUATION SPACE */ + {XK_thinspace, 0x2009}, /* THIN SPACE */ + {XK_hairspace, 0x200a}, /* HAIR SPACE */ + {XK_emdash, 0x2014}, /* EM DASH */ + {XK_endash, 0x2013}, /* EN DASH */ + /*{ XK_signifblank, ??? }, */ + {XK_ellipsis, 0x2026}, /* HORIZONTAL ELLIPSIS */ + {XK_doubbaselinedot, 0x2025}, /* TWO DOT LEADER */ + {XK_onethird, 0x2153}, /* VULGAR FRACTION ONE THIRD */ + {XK_twothirds, 0x2154}, /* VULGAR FRACTION TWO THIRDS */ + {XK_onefifth, 0x2155}, /* VULGAR FRACTION ONE FIFTH */ + {XK_twofifths, 0x2156}, /* VULGAR FRACTION TWO FIFTHS */ + {XK_threefifths, 0x2157}, /* VULGAR FRACTION THREE FIFTHS */ + {XK_fourfifths, 0x2158}, /* VULGAR FRACTION FOUR FIFTHS */ + {XK_onesixth, 0x2159}, /* VULGAR FRACTION ONE SIXTH */ + {XK_fivesixths, 0x215a}, /* VULGAR FRACTION FIVE SIXTHS */ + {XK_careof, 0x2105}, /* CARE OF */ + {XK_figdash, 0x2012}, /* FIGURE DASH */ + {XK_leftanglebracket, 0x2329}, /* LEFT-POINTING ANGLE BRACKET */ + /*{ XK_decimalpoint, ??? }, */ + {XK_rightanglebracket, 0x232a}, /* RIGHT-POINTING ANGLE BRACKET */ + /*{ XK_marker, ??? }, */ + {XK_oneeighth, 0x215b}, /* VULGAR FRACTION ONE EIGHTH */ + {XK_threeeighths, 0x215c}, /* VULGAR FRACTION THREE EIGHTHS */ + {XK_fiveeighths, 0x215d}, /* VULGAR FRACTION FIVE EIGHTHS */ + {XK_seveneighths, 0x215e}, /* VULGAR FRACTION SEVEN EIGHTHS */ + {XK_trademark, 0x2122}, /* TRADE MARK SIGN */ + {XK_signaturemark, 0x2613}, /* SALTIRE */ + /*{ XK_trademarkincircle, ??? }, */ + {XK_leftopentriangle, 0x25c1}, /* WHITE LEFT-POINTING TRIANGLE */ + {XK_rightopentriangle, 0x25b7}, /* WHITE RIGHT-POINTING TRIANGLE */ + {XK_emopencircle, 0x25cb}, /* WHITE CIRCLE */ + {XK_emopenrectangle, 0x25af}, /* WHITE VERTICAL RECTANGLE */ + {XK_leftsinglequotemark, 0x2018}, /* LEFT SINGLE QUOTATION MARK */ + {XK_rightsinglequotemark, 0x2019}, /* RIGHT SINGLE QUOTATION MARK */ + {XK_leftdoublequotemark, 0x201c}, /* LEFT DOUBLE QUOTATION MARK */ + {XK_rightdoublequotemark, 0x201d}, /* RIGHT DOUBLE QUOTATION MARK */ + {XK_prescription, 0x211e}, /* PRESCRIPTION TAKE */ + {XK_minutes, 0x2032}, /* PRIME */ + {XK_seconds, 0x2033}, /* DOUBLE PRIME */ + {XK_latincross, 0x271d}, /* LATIN CROSS */ + /*{ XK_hexagram, ??? }, */ + {XK_filledrectbullet, 0x25ac}, /* BLACK RECTANGLE */ + {XK_filledlefttribullet, 0x25c0}, /* BLACK LEFT-POINTING TRIANGLE */ + {XK_filledrighttribullet, 0x25b6}, /* BLACK RIGHT-POINTING TRIANGLE */ + {XK_emfilledcircle, 0x25cf}, /* BLACK CIRCLE */ + {XK_emfilledrect, 0x25ae}, /* BLACK VERTICAL RECTANGLE */ + {XK_enopencircbullet, 0x25e6}, /* WHITE BULLET */ + {XK_enopensquarebullet, 0x25ab}, /* WHITE SMALL SQUARE */ + {XK_openrectbullet, 0x25ad}, /* WHITE RECTANGLE */ + {XK_opentribulletup, 0x25b3}, /* WHITE UP-POINTING TRIANGLE */ + {XK_opentribulletdown, 0x25bd}, /* WHITE DOWN-POINTING TRIANGLE */ + {XK_openstar, 0x2606}, /* WHITE STAR */ + {XK_enfilledcircbullet, 0x2022}, /* BULLET */ + {XK_enfilledsqbullet, 0x25aa}, /* BLACK SMALL SQUARE */ + {XK_filledtribulletup, 0x25b2}, /* BLACK UP-POINTING TRIANGLE */ + {XK_filledtribulletdown, 0x25bc}, /* BLACK DOWN-POINTING TRIANGLE */ + {XK_leftpointer, 0x261c}, /* WHITE LEFT POINTING INDEX */ + {XK_rightpointer, 0x261e}, /* WHITE RIGHT POINTING INDEX */ + {XK_club, 0x2663}, /* BLACK CLUB SUIT */ + {XK_diamond, 0x2666}, /* BLACK DIAMOND SUIT */ + {XK_heart, 0x2665}, /* BLACK HEART SUIT */ + {XK_maltesecross, 0x2720}, /* MALTESE CROSS */ + {XK_dagger, 0x2020}, /* DAGGER */ + {XK_doubledagger, 0x2021}, /* DOUBLE DAGGER */ + {XK_checkmark, 0x2713}, /* CHECK MARK */ + {XK_ballotcross, 0x2717}, /* BALLOT X */ + {XK_musicalsharp, 0x266f}, /* MUSIC SHARP SIGN */ + {XK_musicalflat, 0x266d}, /* MUSIC FLAT SIGN */ + {XK_malesymbol, 0x2642}, /* MALE SIGN */ + {XK_femalesymbol, 0x2640}, /* FEMALE SIGN */ + {XK_telephone, 0x260e}, /* BLACK TELEPHONE */ + {XK_telephonerecorder, 0x2315}, /* TELEPHONE RECORDER */ + {XK_phonographcopyright, 0x2117}, /* SOUND RECORDING COPYRIGHT */ + {XK_caret, 0x2038}, /* CARET */ + {XK_singlelowquotemark, 0x201a}, /* SINGLE LOW-9 QUOTATION MARK */ + {XK_doublelowquotemark, 0x201e}, /* DOUBLE LOW-9 QUOTATION MARK */ + /*{ XK_cursor, ??? }, */ + {XK_leftcaret, 0x003c}, /* LESS-THAN SIGN */ + {XK_rightcaret, 0x003e}, /* GREATER-THAN SIGN */ + {XK_downcaret, 0x2228}, /* LOGICAL OR */ + {XK_upcaret, 0x2227}, /* LOGICAL AND */ + {XK_overbar, 0x00af}, /* MACRON */ + {XK_downtack, 0x22a5}, /* UP TACK */ + {XK_upshoe, 0x2229}, /* INTERSECTION */ + {XK_downstile, 0x230a}, /* LEFT FLOOR */ + {XK_underbar, 0x005f}, /* LOW LINE */ + {XK_jot, 0x2218}, /* RING OPERATOR */ + {XK_quad, 0x2395}, /* APL FUNCTIONAL SYMBOL QUAD */ + {XK_uptack, 0x22a4}, /* DOWN TACK */ + {XK_circle, 0x25cb}, /* WHITE CIRCLE */ + {XK_upstile, 0x2308}, /* LEFT CEILING */ + {XK_downshoe, 0x222a}, /* UNION */ + {XK_rightshoe, 0x2283}, /* SUPERSET OF */ + {XK_leftshoe, 0x2282}, /* SUBSET OF */ + {XK_lefttack, 0x22a2}, /* RIGHT TACK */ + {XK_righttack, 0x22a3}, /* LEFT TACK */ #if defined(XK_hebrew_doublelowline) -{ XK_hebrew_doublelowline, 0x2017 }, /* DOUBLE LOW LINE */ -{ XK_hebrew_aleph, 0x05d0 }, /* HEBREW LETTER ALEF */ -{ XK_hebrew_bet, 0x05d1 }, /* HEBREW LETTER BET */ -{ XK_hebrew_gimel, 0x05d2 }, /* HEBREW LETTER GIMEL */ -{ XK_hebrew_dalet, 0x05d3 }, /* HEBREW LETTER DALET */ -{ XK_hebrew_he, 0x05d4 }, /* HEBREW LETTER HE */ -{ XK_hebrew_waw, 0x05d5 }, /* HEBREW LETTER VAV */ -{ XK_hebrew_zain, 0x05d6 }, /* HEBREW LETTER ZAYIN */ -{ XK_hebrew_chet, 0x05d7 }, /* HEBREW LETTER HET */ -{ XK_hebrew_tet, 0x05d8 }, /* HEBREW LETTER TET */ -{ XK_hebrew_yod, 0x05d9 }, /* HEBREW LETTER YOD */ -{ XK_hebrew_finalkaph, 0x05da }, /* HEBREW LETTER FINAL KAF */ -{ XK_hebrew_kaph, 0x05db }, /* HEBREW LETTER KAF */ -{ XK_hebrew_lamed, 0x05dc }, /* HEBREW LETTER LAMED */ -{ XK_hebrew_finalmem, 0x05dd }, /* HEBREW LETTER FINAL MEM */ -{ XK_hebrew_mem, 0x05de }, /* HEBREW LETTER MEM */ -{ XK_hebrew_finalnun, 0x05df }, /* HEBREW LETTER FINAL NUN */ -{ XK_hebrew_nun, 0x05e0 }, /* HEBREW LETTER NUN */ -{ XK_hebrew_samech, 0x05e1 }, /* HEBREW LETTER SAMEKH */ -{ XK_hebrew_ayin, 0x05e2 }, /* HEBREW LETTER AYIN */ -{ XK_hebrew_finalpe, 0x05e3 }, /* HEBREW LETTER FINAL PE */ -{ XK_hebrew_pe, 0x05e4 }, /* HEBREW LETTER PE */ -{ XK_hebrew_finalzade, 0x05e5 }, /* HEBREW LETTER FINAL TSADI */ -{ XK_hebrew_zade, 0x05e6 }, /* HEBREW LETTER TSADI */ -{ XK_hebrew_qoph, 0x05e7 }, /* HEBREW LETTER QOF */ -{ XK_hebrew_resh, 0x05e8 }, /* HEBREW LETTER RESH */ -{ XK_hebrew_shin, 0x05e9 }, /* HEBREW LETTER SHIN */ -{ XK_hebrew_taw, 0x05ea }, /* HEBREW LETTER TAV */ -#endif // defined(XK_hebrew_doublelowline) + {XK_hebrew_doublelowline, 0x2017}, /* DOUBLE LOW LINE */ + {XK_hebrew_aleph, 0x05d0}, /* HEBREW LETTER ALEF */ + {XK_hebrew_bet, 0x05d1}, /* HEBREW LETTER BET */ + {XK_hebrew_gimel, 0x05d2}, /* HEBREW LETTER GIMEL */ + {XK_hebrew_dalet, 0x05d3}, /* HEBREW LETTER DALET */ + {XK_hebrew_he, 0x05d4}, /* HEBREW LETTER HE */ + {XK_hebrew_waw, 0x05d5}, /* HEBREW LETTER VAV */ + {XK_hebrew_zain, 0x05d6}, /* HEBREW LETTER ZAYIN */ + {XK_hebrew_chet, 0x05d7}, /* HEBREW LETTER HET */ + {XK_hebrew_tet, 0x05d8}, /* HEBREW LETTER TET */ + {XK_hebrew_yod, 0x05d9}, /* HEBREW LETTER YOD */ + {XK_hebrew_finalkaph, 0x05da}, /* HEBREW LETTER FINAL KAF */ + {XK_hebrew_kaph, 0x05db}, /* HEBREW LETTER KAF */ + {XK_hebrew_lamed, 0x05dc}, /* HEBREW LETTER LAMED */ + {XK_hebrew_finalmem, 0x05dd}, /* HEBREW LETTER FINAL MEM */ + {XK_hebrew_mem, 0x05de}, /* HEBREW LETTER MEM */ + {XK_hebrew_finalnun, 0x05df}, /* HEBREW LETTER FINAL NUN */ + {XK_hebrew_nun, 0x05e0}, /* HEBREW LETTER NUN */ + {XK_hebrew_samech, 0x05e1}, /* HEBREW LETTER SAMEKH */ + {XK_hebrew_ayin, 0x05e2}, /* HEBREW LETTER AYIN */ + {XK_hebrew_finalpe, 0x05e3}, /* HEBREW LETTER FINAL PE */ + {XK_hebrew_pe, 0x05e4}, /* HEBREW LETTER PE */ + {XK_hebrew_finalzade, 0x05e5}, /* HEBREW LETTER FINAL TSADI */ + {XK_hebrew_zade, 0x05e6}, /* HEBREW LETTER TSADI */ + {XK_hebrew_qoph, 0x05e7}, /* HEBREW LETTER QOF */ + {XK_hebrew_resh, 0x05e8}, /* HEBREW LETTER RESH */ + {XK_hebrew_shin, 0x05e9}, /* HEBREW LETTER SHIN */ + {XK_hebrew_taw, 0x05ea}, /* HEBREW LETTER TAV */ +#endif // defined(XK_hebrew_doublelowline) #if defined(XK_Thai_kokai) -{ XK_Thai_kokai, 0x0e01 }, /* THAI CHARACTER KO KAI */ -{ XK_Thai_khokhai, 0x0e02 }, /* THAI CHARACTER KHO KHAI */ -{ XK_Thai_khokhuat, 0x0e03 }, /* THAI CHARACTER KHO KHUAT */ -{ XK_Thai_khokhwai, 0x0e04 }, /* THAI CHARACTER KHO KHWAI */ -{ XK_Thai_khokhon, 0x0e05 }, /* THAI CHARACTER KHO KHON */ -{ XK_Thai_khorakhang, 0x0e06 }, /* THAI CHARACTER KHO RAKHANG */ -{ XK_Thai_ngongu, 0x0e07 }, /* THAI CHARACTER NGO NGU */ -{ XK_Thai_chochan, 0x0e08 }, /* THAI CHARACTER CHO CHAN */ -{ XK_Thai_choching, 0x0e09 }, /* THAI CHARACTER CHO CHING */ -{ XK_Thai_chochang, 0x0e0a }, /* THAI CHARACTER CHO CHANG */ -{ XK_Thai_soso, 0x0e0b }, /* THAI CHARACTER SO SO */ -{ XK_Thai_chochoe, 0x0e0c }, /* THAI CHARACTER CHO CHOE */ -{ XK_Thai_yoying, 0x0e0d }, /* THAI CHARACTER YO YING */ -{ XK_Thai_dochada, 0x0e0e }, /* THAI CHARACTER DO CHADA */ -{ XK_Thai_topatak, 0x0e0f }, /* THAI CHARACTER TO PATAK */ -{ XK_Thai_thothan, 0x0e10 }, /* THAI CHARACTER THO THAN */ -{ XK_Thai_thonangmontho, 0x0e11 }, /* THAI CHARACTER THO NANGMONTHO */ -{ XK_Thai_thophuthao, 0x0e12 }, /* THAI CHARACTER THO PHUTHAO */ -{ XK_Thai_nonen, 0x0e13 }, /* THAI CHARACTER NO NEN */ -{ XK_Thai_dodek, 0x0e14 }, /* THAI CHARACTER DO DEK */ -{ XK_Thai_totao, 0x0e15 }, /* THAI CHARACTER TO TAO */ -{ XK_Thai_thothung, 0x0e16 }, /* THAI CHARACTER THO THUNG */ -{ XK_Thai_thothahan, 0x0e17 }, /* THAI CHARACTER THO THAHAN */ -{ XK_Thai_thothong, 0x0e18 }, /* THAI CHARACTER THO THONG */ -{ XK_Thai_nonu, 0x0e19 }, /* THAI CHARACTER NO NU */ -{ XK_Thai_bobaimai, 0x0e1a }, /* THAI CHARACTER BO BAIMAI */ -{ XK_Thai_popla, 0x0e1b }, /* THAI CHARACTER PO PLA */ -{ XK_Thai_phophung, 0x0e1c }, /* THAI CHARACTER PHO PHUNG */ -{ XK_Thai_fofa, 0x0e1d }, /* THAI CHARACTER FO FA */ -{ XK_Thai_phophan, 0x0e1e }, /* THAI CHARACTER PHO PHAN */ -{ XK_Thai_fofan, 0x0e1f }, /* THAI CHARACTER FO FAN */ -{ XK_Thai_phosamphao, 0x0e20 }, /* THAI CHARACTER PHO SAMPHAO */ -{ XK_Thai_moma, 0x0e21 }, /* THAI CHARACTER MO MA */ -{ XK_Thai_yoyak, 0x0e22 }, /* THAI CHARACTER YO YAK */ -{ XK_Thai_rorua, 0x0e23 }, /* THAI CHARACTER RO RUA */ -{ XK_Thai_ru, 0x0e24 }, /* THAI CHARACTER RU */ -{ XK_Thai_loling, 0x0e25 }, /* THAI CHARACTER LO LING */ -{ XK_Thai_lu, 0x0e26 }, /* THAI CHARACTER LU */ -{ XK_Thai_wowaen, 0x0e27 }, /* THAI CHARACTER WO WAEN */ -{ XK_Thai_sosala, 0x0e28 }, /* THAI CHARACTER SO SALA */ -{ XK_Thai_sorusi, 0x0e29 }, /* THAI CHARACTER SO RUSI */ -{ XK_Thai_sosua, 0x0e2a }, /* THAI CHARACTER SO SUA */ -{ XK_Thai_hohip, 0x0e2b }, /* THAI CHARACTER HO HIP */ -{ XK_Thai_lochula, 0x0e2c }, /* THAI CHARACTER LO CHULA */ -{ XK_Thai_oang, 0x0e2d }, /* THAI CHARACTER O ANG */ -{ XK_Thai_honokhuk, 0x0e2e }, /* THAI CHARACTER HO NOKHUK */ -{ XK_Thai_paiyannoi, 0x0e2f }, /* THAI CHARACTER PAIYANNOI */ -{ XK_Thai_saraa, 0x0e30 }, /* THAI CHARACTER SARA A */ -{ XK_Thai_maihanakat, 0x0e31 }, /* THAI CHARACTER MAI HAN-AKAT */ -{ XK_Thai_saraaa, 0x0e32 }, /* THAI CHARACTER SARA AA */ -{ XK_Thai_saraam, 0x0e33 }, /* THAI CHARACTER SARA AM */ -{ XK_Thai_sarai, 0x0e34 }, /* THAI CHARACTER SARA I */ -{ XK_Thai_saraii, 0x0e35 }, /* THAI CHARACTER SARA II */ -{ XK_Thai_saraue, 0x0e36 }, /* THAI CHARACTER SARA UE */ -{ XK_Thai_sarauee, 0x0e37 }, /* THAI CHARACTER SARA UEE */ -{ XK_Thai_sarau, 0x0e38 }, /* THAI CHARACTER SARA U */ -{ XK_Thai_sarauu, 0x0e39 }, /* THAI CHARACTER SARA UU */ -{ XK_Thai_phinthu, 0x0e3a }, /* THAI CHARACTER PHINTHU */ -/*{ XK_Thai_maihanakat_maitho, ??? }, */ -{ XK_Thai_baht, 0x0e3f }, /* THAI CURRENCY SYMBOL BAHT */ -{ XK_Thai_sarae, 0x0e40 }, /* THAI CHARACTER SARA E */ -{ XK_Thai_saraae, 0x0e41 }, /* THAI CHARACTER SARA AE */ -{ XK_Thai_sarao, 0x0e42 }, /* THAI CHARACTER SARA O */ -{ XK_Thai_saraaimaimuan, 0x0e43 }, /* THAI CHARACTER SARA AI MAIMUAN */ -{ XK_Thai_saraaimaimalai, 0x0e44 }, /* THAI CHARACTER SARA AI MAIMALAI */ -{ XK_Thai_lakkhangyao, 0x0e45 }, /* THAI CHARACTER LAKKHANGYAO */ -{ XK_Thai_maiyamok, 0x0e46 }, /* THAI CHARACTER MAIYAMOK */ -{ XK_Thai_maitaikhu, 0x0e47 }, /* THAI CHARACTER MAITAIKHU */ -{ XK_Thai_maiek, 0x0e48 }, /* THAI CHARACTER MAI EK */ -{ XK_Thai_maitho, 0x0e49 }, /* THAI CHARACTER MAI THO */ -{ XK_Thai_maitri, 0x0e4a }, /* THAI CHARACTER MAI TRI */ -{ XK_Thai_maichattawa, 0x0e4b }, /* THAI CHARACTER MAI CHATTAWA */ -{ XK_Thai_thanthakhat, 0x0e4c }, /* THAI CHARACTER THANTHAKHAT */ -{ XK_Thai_nikhahit, 0x0e4d }, /* THAI CHARACTER NIKHAHIT */ -{ XK_Thai_leksun, 0x0e50 }, /* THAI DIGIT ZERO */ -{ XK_Thai_leknung, 0x0e51 }, /* THAI DIGIT ONE */ -{ XK_Thai_leksong, 0x0e52 }, /* THAI DIGIT TWO */ -{ XK_Thai_leksam, 0x0e53 }, /* THAI DIGIT THREE */ -{ XK_Thai_leksi, 0x0e54 }, /* THAI DIGIT FOUR */ -{ XK_Thai_lekha, 0x0e55 }, /* THAI DIGIT FIVE */ -{ XK_Thai_lekhok, 0x0e56 }, /* THAI DIGIT SIX */ -{ XK_Thai_lekchet, 0x0e57 }, /* THAI DIGIT SEVEN */ -{ XK_Thai_lekpaet, 0x0e58 }, /* THAI DIGIT EIGHT */ -{ XK_Thai_lekkao, 0x0e59 }, /* THAI DIGIT NINE */ -#endif // defined(XK_Thai_kokai) + {XK_Thai_kokai, 0x0e01}, /* THAI CHARACTER KO KAI */ + {XK_Thai_khokhai, 0x0e02}, /* THAI CHARACTER KHO KHAI */ + {XK_Thai_khokhuat, 0x0e03}, /* THAI CHARACTER KHO KHUAT */ + {XK_Thai_khokhwai, 0x0e04}, /* THAI CHARACTER KHO KHWAI */ + {XK_Thai_khokhon, 0x0e05}, /* THAI CHARACTER KHO KHON */ + {XK_Thai_khorakhang, 0x0e06}, /* THAI CHARACTER KHO RAKHANG */ + {XK_Thai_ngongu, 0x0e07}, /* THAI CHARACTER NGO NGU */ + {XK_Thai_chochan, 0x0e08}, /* THAI CHARACTER CHO CHAN */ + {XK_Thai_choching, 0x0e09}, /* THAI CHARACTER CHO CHING */ + {XK_Thai_chochang, 0x0e0a}, /* THAI CHARACTER CHO CHANG */ + {XK_Thai_soso, 0x0e0b}, /* THAI CHARACTER SO SO */ + {XK_Thai_chochoe, 0x0e0c}, /* THAI CHARACTER CHO CHOE */ + {XK_Thai_yoying, 0x0e0d}, /* THAI CHARACTER YO YING */ + {XK_Thai_dochada, 0x0e0e}, /* THAI CHARACTER DO CHADA */ + {XK_Thai_topatak, 0x0e0f}, /* THAI CHARACTER TO PATAK */ + {XK_Thai_thothan, 0x0e10}, /* THAI CHARACTER THO THAN */ + {XK_Thai_thonangmontho, 0x0e11}, /* THAI CHARACTER THO NANGMONTHO */ + {XK_Thai_thophuthao, 0x0e12}, /* THAI CHARACTER THO PHUTHAO */ + {XK_Thai_nonen, 0x0e13}, /* THAI CHARACTER NO NEN */ + {XK_Thai_dodek, 0x0e14}, /* THAI CHARACTER DO DEK */ + {XK_Thai_totao, 0x0e15}, /* THAI CHARACTER TO TAO */ + {XK_Thai_thothung, 0x0e16}, /* THAI CHARACTER THO THUNG */ + {XK_Thai_thothahan, 0x0e17}, /* THAI CHARACTER THO THAHAN */ + {XK_Thai_thothong, 0x0e18}, /* THAI CHARACTER THO THONG */ + {XK_Thai_nonu, 0x0e19}, /* THAI CHARACTER NO NU */ + {XK_Thai_bobaimai, 0x0e1a}, /* THAI CHARACTER BO BAIMAI */ + {XK_Thai_popla, 0x0e1b}, /* THAI CHARACTER PO PLA */ + {XK_Thai_phophung, 0x0e1c}, /* THAI CHARACTER PHO PHUNG */ + {XK_Thai_fofa, 0x0e1d}, /* THAI CHARACTER FO FA */ + {XK_Thai_phophan, 0x0e1e}, /* THAI CHARACTER PHO PHAN */ + {XK_Thai_fofan, 0x0e1f}, /* THAI CHARACTER FO FAN */ + {XK_Thai_phosamphao, 0x0e20}, /* THAI CHARACTER PHO SAMPHAO */ + {XK_Thai_moma, 0x0e21}, /* THAI CHARACTER MO MA */ + {XK_Thai_yoyak, 0x0e22}, /* THAI CHARACTER YO YAK */ + {XK_Thai_rorua, 0x0e23}, /* THAI CHARACTER RO RUA */ + {XK_Thai_ru, 0x0e24}, /* THAI CHARACTER RU */ + {XK_Thai_loling, 0x0e25}, /* THAI CHARACTER LO LING */ + {XK_Thai_lu, 0x0e26}, /* THAI CHARACTER LU */ + {XK_Thai_wowaen, 0x0e27}, /* THAI CHARACTER WO WAEN */ + {XK_Thai_sosala, 0x0e28}, /* THAI CHARACTER SO SALA */ + {XK_Thai_sorusi, 0x0e29}, /* THAI CHARACTER SO RUSI */ + {XK_Thai_sosua, 0x0e2a}, /* THAI CHARACTER SO SUA */ + {XK_Thai_hohip, 0x0e2b}, /* THAI CHARACTER HO HIP */ + {XK_Thai_lochula, 0x0e2c}, /* THAI CHARACTER LO CHULA */ + {XK_Thai_oang, 0x0e2d}, /* THAI CHARACTER O ANG */ + {XK_Thai_honokhuk, 0x0e2e}, /* THAI CHARACTER HO NOKHUK */ + {XK_Thai_paiyannoi, 0x0e2f}, /* THAI CHARACTER PAIYANNOI */ + {XK_Thai_saraa, 0x0e30}, /* THAI CHARACTER SARA A */ + {XK_Thai_maihanakat, 0x0e31}, /* THAI CHARACTER MAI HAN-AKAT */ + {XK_Thai_saraaa, 0x0e32}, /* THAI CHARACTER SARA AA */ + {XK_Thai_saraam, 0x0e33}, /* THAI CHARACTER SARA AM */ + {XK_Thai_sarai, 0x0e34}, /* THAI CHARACTER SARA I */ + {XK_Thai_saraii, 0x0e35}, /* THAI CHARACTER SARA II */ + {XK_Thai_saraue, 0x0e36}, /* THAI CHARACTER SARA UE */ + {XK_Thai_sarauee, 0x0e37}, /* THAI CHARACTER SARA UEE */ + {XK_Thai_sarau, 0x0e38}, /* THAI CHARACTER SARA U */ + {XK_Thai_sarauu, 0x0e39}, /* THAI CHARACTER SARA UU */ + {XK_Thai_phinthu, 0x0e3a}, /* THAI CHARACTER PHINTHU */ + /*{ XK_Thai_maihanakat_maitho, ??? }, */ + {XK_Thai_baht, 0x0e3f}, /* THAI CURRENCY SYMBOL BAHT */ + {XK_Thai_sarae, 0x0e40}, /* THAI CHARACTER SARA E */ + {XK_Thai_saraae, 0x0e41}, /* THAI CHARACTER SARA AE */ + {XK_Thai_sarao, 0x0e42}, /* THAI CHARACTER SARA O */ + {XK_Thai_saraaimaimuan, 0x0e43}, /* THAI CHARACTER SARA AI MAIMUAN */ + {XK_Thai_saraaimaimalai, 0x0e44}, /* THAI CHARACTER SARA AI MAIMALAI */ + {XK_Thai_lakkhangyao, 0x0e45}, /* THAI CHARACTER LAKKHANGYAO */ + {XK_Thai_maiyamok, 0x0e46}, /* THAI CHARACTER MAIYAMOK */ + {XK_Thai_maitaikhu, 0x0e47}, /* THAI CHARACTER MAITAIKHU */ + {XK_Thai_maiek, 0x0e48}, /* THAI CHARACTER MAI EK */ + {XK_Thai_maitho, 0x0e49}, /* THAI CHARACTER MAI THO */ + {XK_Thai_maitri, 0x0e4a}, /* THAI CHARACTER MAI TRI */ + {XK_Thai_maichattawa, 0x0e4b}, /* THAI CHARACTER MAI CHATTAWA */ + {XK_Thai_thanthakhat, 0x0e4c}, /* THAI CHARACTER THANTHAKHAT */ + {XK_Thai_nikhahit, 0x0e4d}, /* THAI CHARACTER NIKHAHIT */ + {XK_Thai_leksun, 0x0e50}, /* THAI DIGIT ZERO */ + {XK_Thai_leknung, 0x0e51}, /* THAI DIGIT ONE */ + {XK_Thai_leksong, 0x0e52}, /* THAI DIGIT TWO */ + {XK_Thai_leksam, 0x0e53}, /* THAI DIGIT THREE */ + {XK_Thai_leksi, 0x0e54}, /* THAI DIGIT FOUR */ + {XK_Thai_lekha, 0x0e55}, /* THAI DIGIT FIVE */ + {XK_Thai_lekhok, 0x0e56}, /* THAI DIGIT SIX */ + {XK_Thai_lekchet, 0x0e57}, /* THAI DIGIT SEVEN */ + {XK_Thai_lekpaet, 0x0e58}, /* THAI DIGIT EIGHT */ + {XK_Thai_lekkao, 0x0e59}, /* THAI DIGIT NINE */ +#endif // defined(XK_Thai_kokai) #if defined(XK_Hangul_Kiyeog) -{ XK_Hangul_Kiyeog, 0x3131 }, /* HANGUL LETTER KIYEOK */ -{ XK_Hangul_SsangKiyeog, 0x3132 }, /* HANGUL LETTER SSANGKIYEOK */ -{ XK_Hangul_KiyeogSios, 0x3133 }, /* HANGUL LETTER KIYEOK-SIOS */ -{ XK_Hangul_Nieun, 0x3134 }, /* HANGUL LETTER NIEUN */ -{ XK_Hangul_NieunJieuj, 0x3135 }, /* HANGUL LETTER NIEUN-CIEUC */ -{ XK_Hangul_NieunHieuh, 0x3136 }, /* HANGUL LETTER NIEUN-HIEUH */ -{ XK_Hangul_Dikeud, 0x3137 }, /* HANGUL LETTER TIKEUT */ -{ XK_Hangul_SsangDikeud, 0x3138 }, /* HANGUL LETTER SSANGTIKEUT */ -{ XK_Hangul_Rieul, 0x3139 }, /* HANGUL LETTER RIEUL */ -{ XK_Hangul_RieulKiyeog, 0x313a }, /* HANGUL LETTER RIEUL-KIYEOK */ -{ XK_Hangul_RieulMieum, 0x313b }, /* HANGUL LETTER RIEUL-MIEUM */ -{ XK_Hangul_RieulPieub, 0x313c }, /* HANGUL LETTER RIEUL-PIEUP */ -{ XK_Hangul_RieulSios, 0x313d }, /* HANGUL LETTER RIEUL-SIOS */ -{ XK_Hangul_RieulTieut, 0x313e }, /* HANGUL LETTER RIEUL-THIEUTH */ -{ XK_Hangul_RieulPhieuf, 0x313f }, /* HANGUL LETTER RIEUL-PHIEUPH */ -{ XK_Hangul_RieulHieuh, 0x3140 }, /* HANGUL LETTER RIEUL-HIEUH */ -{ XK_Hangul_Mieum, 0x3141 }, /* HANGUL LETTER MIEUM */ -{ XK_Hangul_Pieub, 0x3142 }, /* HANGUL LETTER PIEUP */ -{ XK_Hangul_SsangPieub, 0x3143 }, /* HANGUL LETTER SSANGPIEUP */ -{ XK_Hangul_PieubSios, 0x3144 }, /* HANGUL LETTER PIEUP-SIOS */ -{ XK_Hangul_Sios, 0x3145 }, /* HANGUL LETTER SIOS */ -{ XK_Hangul_SsangSios, 0x3146 }, /* HANGUL LETTER SSANGSIOS */ -{ XK_Hangul_Ieung, 0x3147 }, /* HANGUL LETTER IEUNG */ -{ XK_Hangul_Jieuj, 0x3148 }, /* HANGUL LETTER CIEUC */ -{ XK_Hangul_SsangJieuj, 0x3149 }, /* HANGUL LETTER SSANGCIEUC */ -{ XK_Hangul_Cieuc, 0x314a }, /* HANGUL LETTER CHIEUCH */ -{ XK_Hangul_Khieuq, 0x314b }, /* HANGUL LETTER KHIEUKH */ -{ XK_Hangul_Tieut, 0x314c }, /* HANGUL LETTER THIEUTH */ -{ XK_Hangul_Phieuf, 0x314d }, /* HANGUL LETTER PHIEUPH */ -{ XK_Hangul_Hieuh, 0x314e }, /* HANGUL LETTER HIEUH */ -{ XK_Hangul_A, 0x314f }, /* HANGUL LETTER A */ -{ XK_Hangul_AE, 0x3150 }, /* HANGUL LETTER AE */ -{ XK_Hangul_YA, 0x3151 }, /* HANGUL LETTER YA */ -{ XK_Hangul_YAE, 0x3152 }, /* HANGUL LETTER YAE */ -{ XK_Hangul_EO, 0x3153 }, /* HANGUL LETTER EO */ -{ XK_Hangul_E, 0x3154 }, /* HANGUL LETTER E */ -{ XK_Hangul_YEO, 0x3155 }, /* HANGUL LETTER YEO */ -{ XK_Hangul_YE, 0x3156 }, /* HANGUL LETTER YE */ -{ XK_Hangul_O, 0x3157 }, /* HANGUL LETTER O */ -{ XK_Hangul_WA, 0x3158 }, /* HANGUL LETTER WA */ -{ XK_Hangul_WAE, 0x3159 }, /* HANGUL LETTER WAE */ -{ XK_Hangul_OE, 0x315a }, /* HANGUL LETTER OE */ -{ XK_Hangul_YO, 0x315b }, /* HANGUL LETTER YO */ -{ XK_Hangul_U, 0x315c }, /* HANGUL LETTER U */ -{ XK_Hangul_WEO, 0x315d }, /* HANGUL LETTER WEO */ -{ XK_Hangul_WE, 0x315e }, /* HANGUL LETTER WE */ -{ XK_Hangul_WI, 0x315f }, /* HANGUL LETTER WI */ -{ XK_Hangul_YU, 0x3160 }, /* HANGUL LETTER YU */ -{ XK_Hangul_EU, 0x3161 }, /* HANGUL LETTER EU */ -{ XK_Hangul_YI, 0x3162 }, /* HANGUL LETTER YI */ -{ XK_Hangul_I, 0x3163 }, /* HANGUL LETTER I */ -{ XK_Hangul_J_Kiyeog, 0x11a8 }, /* HANGUL JONGSEONG KIYEOK */ -{ XK_Hangul_J_SsangKiyeog, 0x11a9 }, /* HANGUL JONGSEONG SSANGKIYEOK */ -{ XK_Hangul_J_KiyeogSios, 0x11aa }, /* HANGUL JONGSEONG KIYEOK-SIOS */ -{ XK_Hangul_J_Nieun, 0x11ab }, /* HANGUL JONGSEONG NIEUN */ -{ XK_Hangul_J_NieunJieuj, 0x11ac }, /* HANGUL JONGSEONG NIEUN-CIEUC */ -{ XK_Hangul_J_NieunHieuh, 0x11ad }, /* HANGUL JONGSEONG NIEUN-HIEUH */ -{ XK_Hangul_J_Dikeud, 0x11ae }, /* HANGUL JONGSEONG TIKEUT */ -{ XK_Hangul_J_Rieul, 0x11af }, /* HANGUL JONGSEONG RIEUL */ -{ XK_Hangul_J_RieulKiyeog, 0x11b0 }, /* HANGUL JONGSEONG RIEUL-KIYEOK */ -{ XK_Hangul_J_RieulMieum, 0x11b1 }, /* HANGUL JONGSEONG RIEUL-MIEUM */ -{ XK_Hangul_J_RieulPieub, 0x11b2 }, /* HANGUL JONGSEONG RIEUL-PIEUP */ -{ XK_Hangul_J_RieulSios, 0x11b3 }, /* HANGUL JONGSEONG RIEUL-SIOS */ -{ XK_Hangul_J_RieulTieut, 0x11b4 }, /* HANGUL JONGSEONG RIEUL-THIEUTH */ -{ XK_Hangul_J_RieulPhieuf, 0x11b5 }, /* HANGUL JONGSEONG RIEUL-PHIEUPH */ -{ XK_Hangul_J_RieulHieuh, 0x11b6 }, /* HANGUL JONGSEONG RIEUL-HIEUH */ -{ XK_Hangul_J_Mieum, 0x11b7 }, /* HANGUL JONGSEONG MIEUM */ -{ XK_Hangul_J_Pieub, 0x11b8 }, /* HANGUL JONGSEONG PIEUP */ -{ XK_Hangul_J_PieubSios, 0x11b9 }, /* HANGUL JONGSEONG PIEUP-SIOS */ -{ XK_Hangul_J_Sios, 0x11ba }, /* HANGUL JONGSEONG SIOS */ -{ XK_Hangul_J_SsangSios, 0x11bb }, /* HANGUL JONGSEONG SSANGSIOS */ -{ XK_Hangul_J_Ieung, 0x11bc }, /* HANGUL JONGSEONG IEUNG */ -{ XK_Hangul_J_Jieuj, 0x11bd }, /* HANGUL JONGSEONG CIEUC */ -{ XK_Hangul_J_Cieuc, 0x11be }, /* HANGUL JONGSEONG CHIEUCH */ -{ XK_Hangul_J_Khieuq, 0x11bf }, /* HANGUL JONGSEONG KHIEUKH */ -{ XK_Hangul_J_Tieut, 0x11c0 }, /* HANGUL JONGSEONG THIEUTH */ -{ XK_Hangul_J_Phieuf, 0x11c1 }, /* HANGUL JONGSEONG PHIEUPH */ -{ XK_Hangul_J_Hieuh, 0x11c2 }, /* HANGUL JONGSEONG HIEUH */ -{ XK_Hangul_RieulYeorinHieuh, 0x316d }, /* HANGUL LETTER RIEUL-YEORINHIEUH */ -{ XK_Hangul_SunkyeongeumMieum, 0x3171 }, /* HANGUL LETTER KAPYEOUNMIEUM */ -{ XK_Hangul_SunkyeongeumPieub, 0x3178 }, /* HANGUL LETTER KAPYEOUNPIEUP */ -{ XK_Hangul_PanSios, 0x317f }, /* HANGUL LETTER PANSIOS */ -{ XK_Hangul_KkogjiDalrinIeung, 0x3181 }, /* HANGUL LETTER YESIEUNG */ -{ XK_Hangul_SunkyeongeumPhieuf, 0x3184 }, /* HANGUL LETTER KAPYEOUNPHIEUPH */ -{ XK_Hangul_YeorinHieuh, 0x3186 }, /* HANGUL LETTER YEORINHIEUH */ -{ XK_Hangul_AraeA, 0x318d }, /* HANGUL LETTER ARAEA */ -{ XK_Hangul_AraeAE, 0x318e }, /* HANGUL LETTER ARAEAE */ -{ XK_Hangul_J_PanSios, 0x11eb }, /* HANGUL JONGSEONG PANSIOS */ -{ XK_Hangul_J_KkogjiDalrinIeung, 0x11f0 }, /* HANGUL JONGSEONG YESIEUNG */ -{ XK_Hangul_J_YeorinHieuh, 0x11f9 }, /* HANGUL JONGSEONG YEORINHIEUH */ -{ XK_Korean_Won, 0x20a9 }, /* WON SIGN */ -#endif // defined(XK_Hangul_Kiyeog) -{ XK_OE, 0x0152 }, /* LATIN CAPITAL LIGATURE OE */ -{ XK_oe, 0x0153 }, /* LATIN SMALL LIGATURE OE */ -{ XK_Ydiaeresis, 0x0178 }, /* LATIN CAPITAL LETTER Y WITH DIAERESIS */ -{ XK_EuroSign, 0x20ac }, /* EURO SIGN */ + {XK_Hangul_Kiyeog, 0x3131}, /* HANGUL LETTER KIYEOK */ + {XK_Hangul_SsangKiyeog, 0x3132}, /* HANGUL LETTER SSANGKIYEOK */ + {XK_Hangul_KiyeogSios, 0x3133}, /* HANGUL LETTER KIYEOK-SIOS */ + {XK_Hangul_Nieun, 0x3134}, /* HANGUL LETTER NIEUN */ + {XK_Hangul_NieunJieuj, 0x3135}, /* HANGUL LETTER NIEUN-CIEUC */ + {XK_Hangul_NieunHieuh, 0x3136}, /* HANGUL LETTER NIEUN-HIEUH */ + {XK_Hangul_Dikeud, 0x3137}, /* HANGUL LETTER TIKEUT */ + {XK_Hangul_SsangDikeud, 0x3138}, /* HANGUL LETTER SSANGTIKEUT */ + {XK_Hangul_Rieul, 0x3139}, /* HANGUL LETTER RIEUL */ + {XK_Hangul_RieulKiyeog, 0x313a}, /* HANGUL LETTER RIEUL-KIYEOK */ + {XK_Hangul_RieulMieum, 0x313b}, /* HANGUL LETTER RIEUL-MIEUM */ + {XK_Hangul_RieulPieub, 0x313c}, /* HANGUL LETTER RIEUL-PIEUP */ + {XK_Hangul_RieulSios, 0x313d}, /* HANGUL LETTER RIEUL-SIOS */ + {XK_Hangul_RieulTieut, 0x313e}, /* HANGUL LETTER RIEUL-THIEUTH */ + {XK_Hangul_RieulPhieuf, 0x313f}, /* HANGUL LETTER RIEUL-PHIEUPH */ + {XK_Hangul_RieulHieuh, 0x3140}, /* HANGUL LETTER RIEUL-HIEUH */ + {XK_Hangul_Mieum, 0x3141}, /* HANGUL LETTER MIEUM */ + {XK_Hangul_Pieub, 0x3142}, /* HANGUL LETTER PIEUP */ + {XK_Hangul_SsangPieub, 0x3143}, /* HANGUL LETTER SSANGPIEUP */ + {XK_Hangul_PieubSios, 0x3144}, /* HANGUL LETTER PIEUP-SIOS */ + {XK_Hangul_Sios, 0x3145}, /* HANGUL LETTER SIOS */ + {XK_Hangul_SsangSios, 0x3146}, /* HANGUL LETTER SSANGSIOS */ + {XK_Hangul_Ieung, 0x3147}, /* HANGUL LETTER IEUNG */ + {XK_Hangul_Jieuj, 0x3148}, /* HANGUL LETTER CIEUC */ + {XK_Hangul_SsangJieuj, 0x3149}, /* HANGUL LETTER SSANGCIEUC */ + {XK_Hangul_Cieuc, 0x314a}, /* HANGUL LETTER CHIEUCH */ + {XK_Hangul_Khieuq, 0x314b}, /* HANGUL LETTER KHIEUKH */ + {XK_Hangul_Tieut, 0x314c}, /* HANGUL LETTER THIEUTH */ + {XK_Hangul_Phieuf, 0x314d}, /* HANGUL LETTER PHIEUPH */ + {XK_Hangul_Hieuh, 0x314e}, /* HANGUL LETTER HIEUH */ + {XK_Hangul_A, 0x314f}, /* HANGUL LETTER A */ + {XK_Hangul_AE, 0x3150}, /* HANGUL LETTER AE */ + {XK_Hangul_YA, 0x3151}, /* HANGUL LETTER YA */ + {XK_Hangul_YAE, 0x3152}, /* HANGUL LETTER YAE */ + {XK_Hangul_EO, 0x3153}, /* HANGUL LETTER EO */ + {XK_Hangul_E, 0x3154}, /* HANGUL LETTER E */ + {XK_Hangul_YEO, 0x3155}, /* HANGUL LETTER YEO */ + {XK_Hangul_YE, 0x3156}, /* HANGUL LETTER YE */ + {XK_Hangul_O, 0x3157}, /* HANGUL LETTER O */ + {XK_Hangul_WA, 0x3158}, /* HANGUL LETTER WA */ + {XK_Hangul_WAE, 0x3159}, /* HANGUL LETTER WAE */ + {XK_Hangul_OE, 0x315a}, /* HANGUL LETTER OE */ + {XK_Hangul_YO, 0x315b}, /* HANGUL LETTER YO */ + {XK_Hangul_U, 0x315c}, /* HANGUL LETTER U */ + {XK_Hangul_WEO, 0x315d}, /* HANGUL LETTER WEO */ + {XK_Hangul_WE, 0x315e}, /* HANGUL LETTER WE */ + {XK_Hangul_WI, 0x315f}, /* HANGUL LETTER WI */ + {XK_Hangul_YU, 0x3160}, /* HANGUL LETTER YU */ + {XK_Hangul_EU, 0x3161}, /* HANGUL LETTER EU */ + {XK_Hangul_YI, 0x3162}, /* HANGUL LETTER YI */ + {XK_Hangul_I, 0x3163}, /* HANGUL LETTER I */ + {XK_Hangul_J_Kiyeog, 0x11a8}, /* HANGUL JONGSEONG KIYEOK */ + {XK_Hangul_J_SsangKiyeog, 0x11a9}, /* HANGUL JONGSEONG SSANGKIYEOK */ + {XK_Hangul_J_KiyeogSios, 0x11aa}, /* HANGUL JONGSEONG KIYEOK-SIOS */ + {XK_Hangul_J_Nieun, 0x11ab}, /* HANGUL JONGSEONG NIEUN */ + {XK_Hangul_J_NieunJieuj, 0x11ac}, /* HANGUL JONGSEONG NIEUN-CIEUC */ + {XK_Hangul_J_NieunHieuh, 0x11ad}, /* HANGUL JONGSEONG NIEUN-HIEUH */ + {XK_Hangul_J_Dikeud, 0x11ae}, /* HANGUL JONGSEONG TIKEUT */ + {XK_Hangul_J_Rieul, 0x11af}, /* HANGUL JONGSEONG RIEUL */ + {XK_Hangul_J_RieulKiyeog, 0x11b0}, /* HANGUL JONGSEONG RIEUL-KIYEOK */ + {XK_Hangul_J_RieulMieum, 0x11b1}, /* HANGUL JONGSEONG RIEUL-MIEUM */ + {XK_Hangul_J_RieulPieub, 0x11b2}, /* HANGUL JONGSEONG RIEUL-PIEUP */ + {XK_Hangul_J_RieulSios, 0x11b3}, /* HANGUL JONGSEONG RIEUL-SIOS */ + {XK_Hangul_J_RieulTieut, 0x11b4}, /* HANGUL JONGSEONG RIEUL-THIEUTH */ + {XK_Hangul_J_RieulPhieuf, 0x11b5}, /* HANGUL JONGSEONG RIEUL-PHIEUPH */ + {XK_Hangul_J_RieulHieuh, 0x11b6}, /* HANGUL JONGSEONG RIEUL-HIEUH */ + {XK_Hangul_J_Mieum, 0x11b7}, /* HANGUL JONGSEONG MIEUM */ + {XK_Hangul_J_Pieub, 0x11b8}, /* HANGUL JONGSEONG PIEUP */ + {XK_Hangul_J_PieubSios, 0x11b9}, /* HANGUL JONGSEONG PIEUP-SIOS */ + {XK_Hangul_J_Sios, 0x11ba}, /* HANGUL JONGSEONG SIOS */ + {XK_Hangul_J_SsangSios, 0x11bb}, /* HANGUL JONGSEONG SSANGSIOS */ + {XK_Hangul_J_Ieung, 0x11bc}, /* HANGUL JONGSEONG IEUNG */ + {XK_Hangul_J_Jieuj, 0x11bd}, /* HANGUL JONGSEONG CIEUC */ + {XK_Hangul_J_Cieuc, 0x11be}, /* HANGUL JONGSEONG CHIEUCH */ + {XK_Hangul_J_Khieuq, 0x11bf}, /* HANGUL JONGSEONG KHIEUKH */ + {XK_Hangul_J_Tieut, 0x11c0}, /* HANGUL JONGSEONG THIEUTH */ + {XK_Hangul_J_Phieuf, 0x11c1}, /* HANGUL JONGSEONG PHIEUPH */ + {XK_Hangul_J_Hieuh, 0x11c2}, /* HANGUL JONGSEONG HIEUH */ + {XK_Hangul_RieulYeorinHieuh, 0x316d}, /* HANGUL LETTER RIEUL-YEORINHIEUH */ + {XK_Hangul_SunkyeongeumMieum, 0x3171}, /* HANGUL LETTER KAPYEOUNMIEUM */ + {XK_Hangul_SunkyeongeumPieub, 0x3178}, /* HANGUL LETTER KAPYEOUNPIEUP */ + {XK_Hangul_PanSios, 0x317f}, /* HANGUL LETTER PANSIOS */ + {XK_Hangul_KkogjiDalrinIeung, 0x3181}, /* HANGUL LETTER YESIEUNG */ + {XK_Hangul_SunkyeongeumPhieuf, 0x3184}, /* HANGUL LETTER KAPYEOUNPHIEUPH */ + {XK_Hangul_YeorinHieuh, 0x3186}, /* HANGUL LETTER YEORINHIEUH */ + {XK_Hangul_AraeA, 0x318d}, /* HANGUL LETTER ARAEA */ + {XK_Hangul_AraeAE, 0x318e}, /* HANGUL LETTER ARAEAE */ + {XK_Hangul_J_PanSios, 0x11eb}, /* HANGUL JONGSEONG PANSIOS */ + {XK_Hangul_J_KkogjiDalrinIeung, 0x11f0}, /* HANGUL JONGSEONG YESIEUNG */ + {XK_Hangul_J_YeorinHieuh, 0x11f9}, /* HANGUL JONGSEONG YEORINHIEUH */ + {XK_Korean_Won, 0x20a9}, /* WON SIGN */ +#endif // defined(XK_Hangul_Kiyeog) + {XK_OE, 0x0152}, /* LATIN CAPITAL LIGATURE OE */ + {XK_oe, 0x0153}, /* LATIN SMALL LIGATURE OE */ + {XK_Ydiaeresis, 0x0178}, /* LATIN CAPITAL LETTER Y WITH DIAERESIS */ + {XK_EuroSign, 0x20ac}, /* EURO SIGN */ -/* combining dead keys */ -{ XK_dead_abovedot, 0x0307 }, /* COMBINING DOT ABOVE */ -{ XK_dead_abovering, 0x030a }, /* COMBINING RING ABOVE */ -{ XK_dead_acute, 0x0301 }, /* COMBINING ACUTE ACCENT */ -{ XK_dead_breve, 0x0306 }, /* COMBINING BREVE */ -{ XK_dead_caron, 0x030c }, /* COMBINING CARON */ -{ XK_dead_cedilla, 0x0327 }, /* COMBINING CEDILLA */ -{ XK_dead_circumflex, 0x0302 }, /* COMBINING CIRCUMFLEX ACCENT */ -{ XK_dead_diaeresis, 0x0308 }, /* COMBINING DIAERESIS */ -{ XK_dead_doubleacute, 0x030b }, /* COMBINING DOUBLE ACUTE ACCENT */ -{ XK_dead_grave, 0x0300 }, /* COMBINING GRAVE ACCENT */ -{ XK_dead_macron, 0x0304 }, /* COMBINING MACRON */ -{ XK_dead_ogonek, 0x0328 }, /* COMBINING OGONEK */ -{ XK_dead_tilde, 0x0303 } /* COMBINING TILDE */ + /* combining dead keys */ + {XK_dead_abovedot, 0x0307}, /* COMBINING DOT ABOVE */ + {XK_dead_abovering, 0x030a}, /* COMBINING RING ABOVE */ + {XK_dead_acute, 0x0301}, /* COMBINING ACUTE ACCENT */ + {XK_dead_breve, 0x0306}, /* COMBINING BREVE */ + {XK_dead_caron, 0x030c}, /* COMBINING CARON */ + {XK_dead_cedilla, 0x0327}, /* COMBINING CEDILLA */ + {XK_dead_circumflex, 0x0302}, /* COMBINING CIRCUMFLEX ACCENT */ + {XK_dead_diaeresis, 0x0308}, /* COMBINING DIAERESIS */ + {XK_dead_doubleacute, 0x030b}, /* COMBINING DOUBLE ACUTE ACCENT */ + {XK_dead_grave, 0x0300}, /* COMBINING GRAVE ACCENT */ + {XK_dead_macron, 0x0304}, /* COMBINING MACRON */ + {XK_dead_ogonek, 0x0328}, /* COMBINING OGONEK */ + {XK_dead_tilde, 0x0303} /* COMBINING TILDE */ }; /* XXX -- map these too XK_Cyrillic_GHE_bar @@ -1248,543 +1269,720 @@ XK_uhorn */ // map "Internet" keys to KeyIDs -static const KeySym s_map1008FF[] = -{ - /* 0x00 */ 0, 0, kKeyBrightnessUp, kKeyBrightnessDown, 0, 0, 0, 0, - /* 0x08 */ 0, 0, 0, 0, 0, 0, 0, 0, - /* 0x10 */ 0, kKeyAudioDown, kKeyAudioMute, kKeyAudioUp, - /* 0x14 */ kKeyAudioPlay, kKeyAudioStop, kKeyAudioPrev, kKeyAudioNext, - /* 0x18 */ kKeyWWWHome, kKeyAppMail, 0, kKeyWWWSearch, 0, 0, 0, 0, - /* 0x20 */ 0, 0, 0, 0, 0, 0, kKeyWWWBack, kKeyWWWForward, - /* 0x28 */ kKeyWWWStop, kKeyWWWRefresh, 0, 0, kKeyEject, 0, 0, 0, - /* 0x30 */ kKeyWWWFavorites, 0, kKeyAppMedia, 0, 0, 0, 0, 0, - /* 0x38 */ 0, 0, 0, 0, 0, 0, 0, 0, - /* 0x40 */ kKeyAppUser1, kKeyAppUser2, 0, 0, 0, 0, 0, 0, - /* 0x48 */ 0, 0, kKeyMissionControl, kKeyLaunchpad, 0, 0, 0, 0, - /* 0x50 */ 0, 0, 0, 0, 0, 0, 0, 0, - /* 0x58 */ 0, 0, 0, 0, 0, 0, 0, 0, - /* 0x60 */ 0, 0, 0, 0, 0, 0, 0, 0, - /* 0x68 */ 0, 0, 0, 0, 0, 0, 0, 0, - /* 0x70 */ 0, 0, 0, 0, 0, 0, 0, 0, - /* 0x78 */ 0, 0, 0, 0, 0, 0, 0, 0, - /* 0x80 */ 0, 0, 0, 0, 0, 0, 0, 0, - /* 0x88 */ 0, 0, 0, 0, 0, 0, 0, 0, - /* 0x90 */ 0, 0, 0, 0, 0, 0, 0, 0, - /* 0x98 */ 0, 0, 0, 0, 0, 0, 0, 0, - /* 0xa0 */ 0, 0, 0, 0, 0, 0, 0, 0, - /* 0xa8 */ 0, 0, 0, 0, 0, 0, 0, 0, - /* 0xb0 */ 0, 0, 0, 0, 0, 0, 0, 0, - /* 0xb8 */ 0, 0, 0, 0, 0, 0, 0, 0, - /* 0xc0 */ 0, 0, 0, 0, 0, 0, 0, 0, - /* 0xc8 */ 0, 0, 0, 0, 0, 0, 0, 0, - /* 0xd0 */ 0, 0, 0, 0, 0, 0, 0, 0, - /* 0xd8 */ 0, 0, 0, 0, 0, 0, 0, 0, - /* 0xe0 */ 0, 0, 0, 0, 0, 0, 0, 0, - /* 0xe8 */ 0, 0, 0, 0, 0, 0, 0, 0, - /* 0xf0 */ 0, 0, 0, 0, 0, 0, 0, 0, - /* 0xf8 */ 0, 0, 0, 0, 0, 0, 0, 0 -}; - +static const KeySym s_map1008FF[] = { + /* 0x00 */ 0, + 0, + kKeyBrightnessUp, + kKeyBrightnessDown, + 0, + 0, + 0, + 0, + /* 0x08 */ 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + /* 0x10 */ 0, + kKeyAudioDown, + kKeyAudioMute, + kKeyAudioUp, + /* 0x14 */ kKeyAudioPlay, + kKeyAudioStop, + kKeyAudioPrev, + kKeyAudioNext, + /* 0x18 */ kKeyWWWHome, + kKeyAppMail, + 0, + kKeyWWWSearch, + 0, + 0, + 0, + 0, + /* 0x20 */ 0, + 0, + 0, + 0, + 0, + 0, + kKeyWWWBack, + kKeyWWWForward, + /* 0x28 */ kKeyWWWStop, + kKeyWWWRefresh, + 0, + 0, + kKeyEject, + 0, + 0, + 0, + /* 0x30 */ kKeyWWWFavorites, + 0, + kKeyAppMedia, + 0, + 0, + 0, + 0, + 0, + /* 0x38 */ 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + /* 0x40 */ kKeyAppUser1, + kKeyAppUser2, + 0, + 0, + 0, + 0, + 0, + 0, + /* 0x48 */ 0, + 0, + kKeyMissionControl, + kKeyLaunchpad, + 0, + 0, + 0, + 0, + /* 0x50 */ 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + /* 0x58 */ 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + /* 0x60 */ 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + /* 0x68 */ 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + /* 0x70 */ 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + /* 0x78 */ 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + /* 0x80 */ 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + /* 0x88 */ 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + /* 0x90 */ 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + /* 0x98 */ 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + /* 0xa0 */ 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + /* 0xa8 */ 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + /* 0xb0 */ 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + /* 0xb8 */ 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + /* 0xc0 */ 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + /* 0xc8 */ 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + /* 0xd0 */ 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + /* 0xd8 */ 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + /* 0xe0 */ 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + /* 0xe8 */ 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + /* 0xf0 */ 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + /* 0xf8 */ 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0}; // // XWindowsUtil // -XWindowsUtil::KeySymMap XWindowsUtil::s_keySymToUCS4; +XWindowsUtil::KeySymMap XWindowsUtil::s_keySymToUCS4; -bool -XWindowsUtil::getWindowProperty(Display* display, Window window, - Atom property, String* data, Atom* type, - SInt32* format, bool deleteProperty) -{ - assert(display != NULL); +bool XWindowsUtil::getWindowProperty(Display *display, Window window, + Atom property, String *data, Atom *type, + SInt32 *format, bool deleteProperty) { + assert(display != NULL); - Atom actualType; - int actualDatumSize; + Atom actualType; + int actualDatumSize; - // ignore errors. XGetWindowProperty() will report failure. - XWindowsUtil::ErrorLock lock(display); + // ignore errors. XGetWindowProperty() will report failure. + XWindowsUtil::ErrorLock lock(display); - // read the property - bool okay = true; - const long length = XMaxRequestSize(display); - long offset = 0; - unsigned long bytesLeft = 1; - while (bytesLeft != 0) { - // get more data - unsigned long numItems; - unsigned char* rawData; - if (XGetWindowProperty(display, window, property, - offset, length, False, AnyPropertyType, - &actualType, &actualDatumSize, - &numItems, &bytesLeft, &rawData) != Success || - actualType == None || actualDatumSize == 0) { - // failed - okay = false; - break; - } - - // compute bytes read and advance offset - unsigned long numBytes; - switch (actualDatumSize) { - case 8: - default: - numBytes = numItems; - offset += numItems / 4; - break; - - case 16: - numBytes = 2 * numItems; - offset += numItems / 2; - break; - - case 32: - numBytes = 4 * numItems; - offset += numItems; - break; - } - - // append data - if (data != NULL) { - data->append((char*)rawData, numBytes); - } - else { - // data is not required so don't try to get any more - bytesLeft = 0; - } - - // done with returned data - XFree(rawData); + // read the property + bool okay = true; + const long length = XMaxRequestSize(display); + long offset = 0; + unsigned long bytesLeft = 1; + while (bytesLeft != 0) { + // get more data + unsigned long numItems; + unsigned char *rawData; + if (XGetWindowProperty(display, window, property, offset, length, False, + AnyPropertyType, &actualType, &actualDatumSize, + &numItems, &bytesLeft, &rawData) != Success || + actualType == None || actualDatumSize == 0) { + // failed + okay = false; + break; } - // delete the property if requested - if (deleteProperty) { - XDeleteProperty(display, window, property); + // compute bytes read and advance offset + unsigned long numBytes; + switch (actualDatumSize) { + case 8: + default: + numBytes = numItems; + offset += numItems / 4; + break; + + case 16: + numBytes = 2 * numItems; + offset += numItems / 2; + break; + + case 32: + numBytes = 4 * numItems; + offset += numItems; + break; } - // save property info - if (type != NULL) { - *type = actualType; - } - if (format != NULL) { - *format = static_cast(actualDatumSize); + // append data + if (data != NULL) { + data->append((char *)rawData, numBytes); + } else { + // data is not required so don't try to get any more + bytesLeft = 0; } - if (okay) { - LOG((CLOG_DEBUG2 "read property %d on window 0x%08x: bytes=%d", property, window, (data == NULL) ? 0 : data->size())); - return true; - } - else { - LOG((CLOG_DEBUG2 "can't read property %d on window 0x%08x", property, window)); - return false; - } + // done with returned data + XFree(rawData); + } + + // delete the property if requested + if (deleteProperty) { + XDeleteProperty(display, window, property); + } + + // save property info + if (type != NULL) { + *type = actualType; + } + if (format != NULL) { + *format = static_cast(actualDatumSize); + } + + if (okay) { + LOG((CLOG_DEBUG2 "read property %d on window 0x%08x: bytes=%d", property, + window, (data == NULL) ? 0 : data->size())); + return true; + } else { + LOG((CLOG_DEBUG2 "can't read property %d on window 0x%08x", property, + window)); + return false; + } } -bool -XWindowsUtil::setWindowProperty(Display* display, Window window, - Atom property, const void* vdata, UInt32 size, - Atom type, SInt32 format) -{ - const UInt32 length = 4 * XMaxRequestSize(display); - const unsigned char* data = static_cast(vdata); - UInt32 datumSize = static_cast(format / 8); - // format 32 on 64bit systems is 8 bytes not 4. - if (format == 32) { - datumSize = sizeof(Atom); - } +bool XWindowsUtil::setWindowProperty(Display *display, Window window, + Atom property, const void *vdata, + UInt32 size, Atom type, SInt32 format) { + const UInt32 length = 4 * XMaxRequestSize(display); + const unsigned char *data = static_cast(vdata); + UInt32 datumSize = static_cast(format / 8); + // format 32 on 64bit systems is 8 bytes not 4. + if (format == 32) { + datumSize = sizeof(Atom); + } - // save errors - bool error = false; - XWindowsUtil::ErrorLock lock(display, &error); + // save errors + bool error = false; + XWindowsUtil::ErrorLock lock(display, &error); - // how much data to send in first chunk? - UInt32 chunkSize = size; + // how much data to send in first chunk? + UInt32 chunkSize = size; + if (chunkSize > length) { + chunkSize = length; + } + + // send first chunk + XChangeProperty(display, window, property, type, format, PropModeReplace, + data, chunkSize / datumSize); + + // append remaining chunks + data += chunkSize; + size -= chunkSize; + while (!error && size > 0) { + chunkSize = size; if (chunkSize > length) { - chunkSize = length; + chunkSize = length; } - - // send first chunk - XChangeProperty(display, window, property, - type, format, PropModeReplace, - data, chunkSize / datumSize); - - // append remaining chunks + XChangeProperty(display, window, property, type, format, PropModeAppend, + data, chunkSize / datumSize); data += chunkSize; size -= chunkSize; - while (!error && size > 0) { - chunkSize = size; - if (chunkSize > length) { - chunkSize = length; - } - XChangeProperty(display, window, property, - type, format, PropModeAppend, - data, chunkSize / datumSize); - data += chunkSize; - size -= chunkSize; - } + } - return !error; + return !error; } -Time -XWindowsUtil::getCurrentTime(Display* display, Window window) -{ - XLockDisplay(display); - // select property events on window - XWindowAttributes attr; - XGetWindowAttributes(display, window, &attr); - XSelectInput(display, window, attr.your_event_mask | PropertyChangeMask); +Time XWindowsUtil::getCurrentTime(Display *display, Window window) { + XLockDisplay(display); + // select property events on window + XWindowAttributes attr; + XGetWindowAttributes(display, window, &attr); + XSelectInput(display, window, attr.your_event_mask | PropertyChangeMask); - // make a property name to receive dummy change - Atom atom = XInternAtom(display, "TIMESTAMP", False); + // make a property name to receive dummy change + Atom atom = XInternAtom(display, "TIMESTAMP", False); - // do a zero-length append to get the current time - unsigned char dummy; - XChangeProperty(display, window, atom, - XA_INTEGER, 8, - PropModeAppend, - &dummy, 0); + // do a zero-length append to get the current time + unsigned char dummy; + XChangeProperty(display, window, atom, XA_INTEGER, 8, PropModeAppend, &dummy, + 0); - // look for property notify events with the following - PropertyNotifyPredicateInfo filter; - filter.m_window = window; - filter.m_property = atom; + // look for property notify events with the following + PropertyNotifyPredicateInfo filter; + filter.m_window = window; + filter.m_property = atom; - // wait for reply - XEvent xevent; - XIfEvent(display, &xevent, &XWindowsUtil::propertyNotifyPredicate, - (XPointer)&filter); - assert(xevent.type == PropertyNotify); - assert(xevent.xproperty.window == window); - assert(xevent.xproperty.atom == atom); + // wait for reply + XEvent xevent; + XIfEvent(display, &xevent, &XWindowsUtil::propertyNotifyPredicate, + (XPointer)&filter); + assert(xevent.type == PropertyNotify); + assert(xevent.xproperty.window == window); + assert(xevent.xproperty.atom == atom); - // restore event mask - XSelectInput(display, window, attr.your_event_mask); - XUnlockDisplay(display); + // restore event mask + XSelectInput(display, window, attr.your_event_mask); + XUnlockDisplay(display); - return xevent.xproperty.time; + return xevent.xproperty.time; } -KeyID -XWindowsUtil::mapKeySymToKeyID(KeySym k) -{ - initKeyMaps(); +KeyID XWindowsUtil::mapKeySymToKeyID(KeySym k) { + initKeyMaps(); - switch (k & 0xffffff00) { - case 0x0000: - // Latin-1 - return static_cast(k); + switch (k & 0xffffff00) { + case 0x0000: + // Latin-1 + return static_cast(k); - case 0xfe00: - // ISO 9995 Function and Modifier Keys - switch (k) { - case XK_ISO_Left_Tab: - return kKeyLeftTab; + case 0xfe00: + // ISO 9995 Function and Modifier Keys + switch (k) { + case XK_ISO_Left_Tab: + return kKeyLeftTab; - case XK_ISO_Level3_Shift: - return kKeyAltGr; - -#ifdef XK_ISO_Level5_Shift - case XK_ISO_Level5_Shift: - return XK_ISO_Level5_Shift; //FIXME: there is no "usual" key for this... -#endif - - case XK_ISO_Next_Group: - return kKeyNextGroup; - - case XK_ISO_Prev_Group: - return kKeyPrevGroup; - - case XK_dead_grave: - return kKeyDeadGrave; - - case XK_dead_acute: - return kKeyDeadAcute; - - case XK_dead_circumflex: - return kKeyDeadCircumflex; - - case XK_dead_tilde: - return kKeyDeadTilde; - - case XK_dead_macron: - return kKeyDeadMacron; - - case XK_dead_breve: - return kKeyDeadBreve; - - case XK_dead_abovedot: - return kKeyDeadAbovedot; - - case XK_dead_diaeresis: - return kKeyDeadDiaeresis; - - case XK_dead_abovering: - return kKeyDeadAbovering; - - case XK_dead_doubleacute: - return kKeyDeadDoubleacute; - - case XK_dead_caron: - return kKeyDeadCaron; - - case XK_dead_cedilla: - return kKeyDeadCedilla; - - case XK_dead_ogonek: - return kKeyDeadOgonek; - - default: - return kKeyNone; - } - - case 0xff00: - // MISCELLANY - return static_cast(k - 0xff00 + 0xef00); - - case 0x1008ff00: - // "Internet" keys - return s_map1008FF[k & 0xff]; - - default: { - // lookup character in table - KeySymMap::const_iterator index = s_keySymToUCS4.find(k); - if (index != s_keySymToUCS4.end()) { - return static_cast(index->second); - } - - // unknown character - return kKeyNone; - } - } -} - -UInt32 -XWindowsUtil::getModifierBitForKeySym(KeySym keysym) -{ - switch (keysym) { - case XK_Shift_L: - case XK_Shift_R: - return kKeyModifierBitShift; - - case XK_Control_L: - case XK_Control_R: - return kKeyModifierBitControl; - - case XK_Alt_L: - case XK_Alt_R: - return kKeyModifierBitAlt; - - case XK_Meta_L: - case XK_Meta_R: - return kKeyModifierBitMeta; - - case XK_Super_L: - case XK_Super_R: - case XK_Hyper_L: - case XK_Hyper_R: - return kKeyModifierBitSuper; - - case XK_Mode_switch: case XK_ISO_Level3_Shift: - return kKeyModifierBitAltGr; + return kKeyAltGr; #ifdef XK_ISO_Level5_Shift case XK_ISO_Level5_Shift: - return kKeyModifierBitLevel5Lock; + return XK_ISO_Level5_Shift; // FIXME: there is no "usual" key for this... #endif - case XK_Caps_Lock: - return kKeyModifierBitCapsLock; + case XK_ISO_Next_Group: + return kKeyNextGroup; - case XK_Num_Lock: - return kKeyModifierBitNumLock; + case XK_ISO_Prev_Group: + return kKeyPrevGroup; - case XK_Scroll_Lock: - return kKeyModifierBitScrollLock; + case XK_dead_grave: + return kKeyDeadGrave; + + case XK_dead_acute: + return kKeyDeadAcute; + + case XK_dead_circumflex: + return kKeyDeadCircumflex; + + case XK_dead_tilde: + return kKeyDeadTilde; + + case XK_dead_macron: + return kKeyDeadMacron; + + case XK_dead_breve: + return kKeyDeadBreve; + + case XK_dead_abovedot: + return kKeyDeadAbovedot; + + case XK_dead_diaeresis: + return kKeyDeadDiaeresis; + + case XK_dead_abovering: + return kKeyDeadAbovering; + + case XK_dead_doubleacute: + return kKeyDeadDoubleacute; + + case XK_dead_caron: + return kKeyDeadCaron; + + case XK_dead_cedilla: + return kKeyDeadCedilla; + + case XK_dead_ogonek: + return kKeyDeadOgonek; default: - return kKeyModifierBitNone; + return kKeyNone; } + + case 0xff00: + // MISCELLANY + return static_cast(k - 0xff00 + 0xef00); + + case 0x1008ff00: + // "Internet" keys + return s_map1008FF[k & 0xff]; + + default: { + // lookup character in table + KeySymMap::const_iterator index = s_keySymToUCS4.find(k); + if (index != s_keySymToUCS4.end()) { + return static_cast(index->second); + } + + // unknown character + return kKeyNone; + } + } } -String -XWindowsUtil::atomToString(Display* display, Atom atom) -{ - if (atom == 0) { - return "None"; - } +UInt32 XWindowsUtil::getModifierBitForKeySym(KeySym keysym) { + switch (keysym) { + case XK_Shift_L: + case XK_Shift_R: + return kKeyModifierBitShift; - bool error = false; - XWindowsUtil::ErrorLock lock(display, &error); - char* name = XGetAtomName(display, atom); - if (error) { - return synergy::string::sprintf(" (%d)", (int)atom); - } - else { - String msg = synergy::string::sprintf("%s (%d)", name, (int)atom); - XFree(name); - return msg; - } + case XK_Control_L: + case XK_Control_R: + return kKeyModifierBitControl; + + case XK_Alt_L: + case XK_Alt_R: + return kKeyModifierBitAlt; + + case XK_Meta_L: + case XK_Meta_R: + return kKeyModifierBitMeta; + + case XK_Super_L: + case XK_Super_R: + case XK_Hyper_L: + case XK_Hyper_R: + return kKeyModifierBitSuper; + + case XK_Mode_switch: + case XK_ISO_Level3_Shift: + return kKeyModifierBitAltGr; + +#ifdef XK_ISO_Level5_Shift + case XK_ISO_Level5_Shift: + return kKeyModifierBitLevel5Lock; +#endif + + case XK_Caps_Lock: + return kKeyModifierBitCapsLock; + + case XK_Num_Lock: + return kKeyModifierBitNumLock; + + case XK_Scroll_Lock: + return kKeyModifierBitScrollLock; + + default: + return kKeyModifierBitNone; + } } -String -XWindowsUtil::atomsToString(Display* display, const Atom* atom, UInt32 num) -{ - char** names = new char*[num]; - bool error = false; - XWindowsUtil::ErrorLock lock(display, &error); - XGetAtomNames(display, const_cast(atom), (int)num, names); - String msg; - if (error) { - for (UInt32 i = 0; i < num; ++i) { - msg += synergy::string::sprintf(" (%d), ", (int)atom[i]); - } - } - else { - for (UInt32 i = 0; i < num; ++i) { - msg += synergy::string::sprintf("%s (%d), ", names[i], (int)atom[i]); - XFree(names[i]); - } - } - delete[] names; - if (msg.size() > 2) { - msg.erase(msg.size() - 2); - } +String XWindowsUtil::atomToString(Display *display, Atom atom) { + if (atom == 0) { + return "None"; + } + + bool error = false; + XWindowsUtil::ErrorLock lock(display, &error); + char *name = XGetAtomName(display, atom); + if (error) { + return synergy::string::sprintf(" (%d)", (int)atom); + } else { + String msg = synergy::string::sprintf("%s (%d)", name, (int)atom); + XFree(name); return msg; + } } -void -XWindowsUtil::convertAtomProperty(String& data) -{ - // as best i can tell, 64-bit systems don't pack Atoms into properties - // as 32-bit numbers but rather as the 64-bit numbers they are. that - // seems wrong but we have to cope. sometimes we'll get a list of - // atoms that's 8*n+4 bytes long, missing the trailing 4 bytes which - // should all be 0. since we're going to reference the Atoms as - // 64-bit numbers we have to ensure the last number is a full 64 bits. - if (sizeof(Atom) != 4 && ((data.size() / 4) & 1) != 0) { - UInt32 zero = 0; - data.append(reinterpret_cast(&zero), sizeof(zero)); +String XWindowsUtil::atomsToString(Display *display, const Atom *atom, + UInt32 num) { + char **names = new char *[num]; + bool error = false; + XWindowsUtil::ErrorLock lock(display, &error); + XGetAtomNames(display, const_cast(atom), (int)num, names); + String msg; + if (error) { + for (UInt32 i = 0; i < num; ++i) { + msg += synergy::string::sprintf(" (%d), ", (int)atom[i]); } -} - -void -XWindowsUtil::appendAtomData(String& data, Atom atom) -{ - data.append(reinterpret_cast(&atom), sizeof(Atom)); -} - -void -XWindowsUtil::replaceAtomData(String& data, UInt32 index, Atom atom) -{ - data.replace(index * sizeof(Atom), sizeof(Atom), - reinterpret_cast(&atom), - sizeof(Atom)); -} - -void -XWindowsUtil::appendTimeData(String& data, Time time) -{ - data.append(reinterpret_cast(&time), sizeof(Time)); -} - -Bool -XWindowsUtil::propertyNotifyPredicate(Display*, XEvent* xevent, XPointer arg) -{ - PropertyNotifyPredicateInfo* filter = - reinterpret_cast(arg); - return (xevent->type == PropertyNotify && - xevent->xproperty.window == filter->m_window && - xevent->xproperty.atom == filter->m_property && - xevent->xproperty.state == PropertyNewValue) ? True : False; -} - -void -XWindowsUtil::initKeyMaps() -{ - if (s_keySymToUCS4.empty()) { - for (size_t i =0; i < sizeof(s_keymap) / sizeof(s_keymap[0]); ++i) { - s_keySymToUCS4[s_keymap[i].keysym] = s_keymap[i].ucs4; - } + } else { + for (UInt32 i = 0; i < num; ++i) { + msg += synergy::string::sprintf("%s (%d), ", names[i], (int)atom[i]); + XFree(names[i]); } + } + delete[] names; + if (msg.size() > 2) { + msg.erase(msg.size() - 2); + } + return msg; } +void XWindowsUtil::convertAtomProperty(String &data) { + // as best i can tell, 64-bit systems don't pack Atoms into properties + // as 32-bit numbers but rather as the 64-bit numbers they are. that + // seems wrong but we have to cope. sometimes we'll get a list of + // atoms that's 8*n+4 bytes long, missing the trailing 4 bytes which + // should all be 0. since we're going to reference the Atoms as + // 64-bit numbers we have to ensure the last number is a full 64 bits. + if (sizeof(Atom) != 4 && ((data.size() / 4) & 1) != 0) { + UInt32 zero = 0; + data.append(reinterpret_cast(&zero), sizeof(zero)); + } +} + +void XWindowsUtil::appendAtomData(String &data, Atom atom) { + data.append(reinterpret_cast(&atom), sizeof(Atom)); +} + +void XWindowsUtil::replaceAtomData(String &data, UInt32 index, Atom atom) { + data.replace(index * sizeof(Atom), sizeof(Atom), + reinterpret_cast(&atom), sizeof(Atom)); +} + +void XWindowsUtil::appendTimeData(String &data, Time time) { + data.append(reinterpret_cast(&time), sizeof(Time)); +} + +Bool XWindowsUtil::propertyNotifyPredicate(Display *, XEvent *xevent, + XPointer arg) { + PropertyNotifyPredicateInfo *filter = + reinterpret_cast(arg); + return (xevent->type == PropertyNotify && + xevent->xproperty.window == filter->m_window && + xevent->xproperty.atom == filter->m_property && + xevent->xproperty.state == PropertyNewValue) + ? True + : False; +} + +void XWindowsUtil::initKeyMaps() { + if (s_keySymToUCS4.empty()) { + for (size_t i = 0; i < sizeof(s_keymap) / sizeof(s_keymap[0]); ++i) { + s_keySymToUCS4[s_keymap[i].keysym] = s_keymap[i].ucs4; + } + } +} // // XWindowsUtil::ErrorLock // -XWindowsUtil::ErrorLock* XWindowsUtil::ErrorLock::s_top = NULL; +XWindowsUtil::ErrorLock *XWindowsUtil::ErrorLock::s_top = NULL; -XWindowsUtil::ErrorLock::ErrorLock(Display* display) : - m_display(display) -{ - install(&XWindowsUtil::ErrorLock::ignoreHandler, NULL); +XWindowsUtil::ErrorLock::ErrorLock(Display *display) : m_display(display) { + install(&XWindowsUtil::ErrorLock::ignoreHandler, NULL); } -XWindowsUtil::ErrorLock::ErrorLock(Display* display, bool* flag) : - m_display(display) -{ - install(&XWindowsUtil::ErrorLock::saveHandler, flag); +XWindowsUtil::ErrorLock::ErrorLock(Display *display, bool *flag) + : m_display(display) { + install(&XWindowsUtil::ErrorLock::saveHandler, flag); } -XWindowsUtil::ErrorLock::ErrorLock(Display* display, - ErrorHandler handler, void* data) : - m_display(display) -{ - install(handler, data); +XWindowsUtil::ErrorLock::ErrorLock(Display *display, ErrorHandler handler, + void *data) + : m_display(display) { + install(handler, data); } -XWindowsUtil::ErrorLock::~ErrorLock() -{ - // make sure everything finishes before uninstalling handler - if (m_display != NULL) { - XSync(m_display, False); - } +XWindowsUtil::ErrorLock::~ErrorLock() { + // make sure everything finishes before uninstalling handler + if (m_display != NULL) { + XSync(m_display, False); + } - // restore old handler - XSetErrorHandler(m_oldXHandler); - s_top = m_next; + // restore old handler + XSetErrorHandler(m_oldXHandler); + s_top = m_next; } -void -XWindowsUtil::ErrorLock::install(ErrorHandler handler, void* data) -{ - // make sure everything finishes before installing handler - if (m_display != NULL) { - XSync(m_display, False); - } +void XWindowsUtil::ErrorLock::install(ErrorHandler handler, void *data) { + // make sure everything finishes before installing handler + if (m_display != NULL) { + XSync(m_display, False); + } - // install handler - m_handler = handler; - m_userData = data; - m_oldXHandler = XSetErrorHandler( - &XWindowsUtil::ErrorLock::internalHandler); - m_next = s_top; - s_top = this; + // install handler + m_handler = handler; + m_userData = data; + m_oldXHandler = XSetErrorHandler(&XWindowsUtil::ErrorLock::internalHandler); + m_next = s_top; + s_top = this; } -int -XWindowsUtil::ErrorLock::internalHandler(Display* display, XErrorEvent* event) -{ - if (s_top != NULL && s_top->m_handler != NULL) { - s_top->m_handler(display, event, s_top->m_userData); - } - return 0; +int XWindowsUtil::ErrorLock::internalHandler(Display *display, + XErrorEvent *event) { + if (s_top != NULL && s_top->m_handler != NULL) { + s_top->m_handler(display, event, s_top->m_userData); + } + return 0; } -void -XWindowsUtil::ErrorLock::ignoreHandler(Display*, XErrorEvent* e, void*) -{ - LOG((CLOG_DEBUG1 "ignoring X error: %d", e->error_code)); +void XWindowsUtil::ErrorLock::ignoreHandler(Display *, XErrorEvent *e, void *) { + LOG((CLOG_DEBUG1 "ignoring X error: %d", e->error_code)); } -void -XWindowsUtil::ErrorLock::saveHandler(Display* display, XErrorEvent* e, void* flag) -{ - char errtxt[1024]; - XGetErrorText(display, e->error_code, errtxt, 1023); - LOG((CLOG_DEBUG1 "flagging X error: %d - %.1023s", e->error_code, errtxt)); - *static_cast(flag) = true; +void XWindowsUtil::ErrorLock::saveHandler(Display *display, XErrorEvent *e, + void *flag) { + char errtxt[1024]; + XGetErrorText(display, e->error_code, errtxt, 1023); + LOG((CLOG_DEBUG1 "flagging X error: %d - %.1023s", e->error_code, errtxt)); + *static_cast(flag) = true; } diff --git a/src/lib/platform/XWindowsUtil.h b/src/lib/platform/XWindowsUtil.h index 52e7e74ab..47a1ff8a4 100644 --- a/src/lib/platform/XWindowsUtil.h +++ b/src/lib/platform/XWindowsUtil.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -18,175 +18,170 @@ #pragma once -#include "base/String.h" #include "base/EventTypes.h" +#include "base/String.h" #include "common/stdmap.h" #include "common/stdvector.h" #if X_DISPLAY_MISSING -# error X11 is required to build synergy +#error X11 is required to build synergy #else -# include +#include #endif //! X11 utility functions class XWindowsUtil { public: - typedef std::vector KeySyms; + typedef std::vector KeySyms; + + //! Get property + /*! + Gets property \c property on \c window. \b Appends the data to + \c *data if \c data is not NULL, saves the property type in \c *type + if \c type is not NULL, and saves the property format in \c *format + if \c format is not NULL. If \c deleteProperty is true then the + property is deleted after being read. + */ + static bool getWindowProperty(Display *, Window window, Atom property, + String *data, Atom *type, SInt32 *format, + bool deleteProperty); + + //! Set property + /*! + Sets property \c property on \c window to \c size bytes of data from + \c data. + */ + static bool setWindowProperty(Display *, Window window, Atom property, + const void *data, UInt32 size, Atom type, + SInt32 format); + + //! Get X server time + /*! + Returns the current X server time. + */ + static Time getCurrentTime(Display *, Window); + + //! Convert KeySym to KeyID + /*! + Converts a KeySym to the equivalent KeyID. Returns kKeyNone if the + KeySym cannot be mapped. + */ + static UInt32 mapKeySymToKeyID(KeySym); + + //! Convert KeySym to corresponding KeyModifierMask + /*! + Converts a KeySym to the corresponding KeyModifierMask, or 0 if the + KeySym is not a modifier. + */ + static UInt32 getModifierBitForKeySym(KeySym keysym); + + //! Convert Atom to its string + /*! + Converts \p atom to its string representation. + */ + static String atomToString(Display *, Atom atom); + + //! Convert several Atoms to a string + /*! + Converts each atom in \p atoms to its string representation and + concatenates the results. + */ + static String atomsToString(Display *display, const Atom *atom, UInt32 num); + + //! Prepare a property of atoms for use + /*! + 64-bit systems may need to modify a property's data if it's a + list of Atoms before using it. + */ + static void convertAtomProperty(String &data); + + //! Append an Atom to property data + /*! + Converts \p atom to a 32-bit on-the-wire format and appends it to + \p data. + */ + static void appendAtomData(String &data, Atom atom); + + //! Replace an Atom in property data + /*! + Converts \p atom to a 32-bit on-the-wire format and replaces the atom + at index \p index in \p data. + */ + static void replaceAtomData(String &data, UInt32 index, Atom atom); + + //! Append an Time to property data + /*! + Converts \p time to a 32-bit on-the-wire format and appends it to + \p data. + */ + static void appendTimeData(String &data, Time time); + + //! X11 error handler + /*! + This class sets an X error handler in the c'tor and restores the + previous error handler in the d'tor. A lock should only be + installed while the display is locked by the thread. + + ErrorLock() ignores errors + ErrorLock(bool* flag) sets *flag to true if any error occurs + */ + class ErrorLock { + public: + //! Error handler type + typedef void (*ErrorHandler)(Display *, XErrorEvent *, void *userData); - //! Get property /*! - Gets property \c property on \c window. \b Appends the data to - \c *data if \c data is not NULL, saves the property type in \c *type - if \c type is not NULL, and saves the property format in \c *format - if \c format is not NULL. If \c deleteProperty is true then the - property is deleted after being read. + Ignore X11 errors. */ - static bool getWindowProperty(Display*, - Window window, Atom property, - String* data, Atom* type, - SInt32* format, bool deleteProperty); + ErrorLock(Display *); + ErrorLock(ErrorLock const &) = delete; + ErrorLock(ErrorLock &&) = delete; + + ErrorLock &operator=(ErrorLock const &) = delete; + ErrorLock &operator=(ErrorLock &&) = delete; - //! Set property /*! - Sets property \c property on \c window to \c size bytes of data from - \c data. + Set \c *errorFlag if any error occurs. */ - static bool setWindowProperty(Display*, - Window window, Atom property, - const void* data, UInt32 size, - Atom type, SInt32 format); + ErrorLock(Display *, bool *errorFlag); - //! Get X server time /*! - Returns the current X server time. + Call \c handler on each error. */ - static Time getCurrentTime(Display*, Window); + ErrorLock(Display *, ErrorHandler handler, void *userData); - //! Convert KeySym to KeyID - /*! - Converts a KeySym to the equivalent KeyID. Returns kKeyNone if the - KeySym cannot be mapped. - */ - static UInt32 mapKeySymToKeyID(KeySym); + ~ErrorLock(); - //! Convert KeySym to corresponding KeyModifierMask - /*! - Converts a KeySym to the corresponding KeyModifierMask, or 0 if the - KeySym is not a modifier. - */ - static UInt32 getModifierBitForKeySym(KeySym keysym); + private: + void install(ErrorHandler, void *); + static int internalHandler(Display *, XErrorEvent *); + static void ignoreHandler(Display *, XErrorEvent *, void *); + static void saveHandler(Display *, XErrorEvent *, void *); - //! Convert Atom to its string - /*! - Converts \p atom to its string representation. - */ - static String atomToString(Display*, Atom atom); + private: + typedef int (*XErrorHandler)(Display *, XErrorEvent *); - //! Convert several Atoms to a string - /*! - Converts each atom in \p atoms to its string representation and - concatenates the results. - */ - static String atomsToString(Display* display, - const Atom* atom, UInt32 num); - - //! Prepare a property of atoms for use - /*! - 64-bit systems may need to modify a property's data if it's a - list of Atoms before using it. - */ - static void convertAtomProperty(String& data); - - //! Append an Atom to property data - /*! - Converts \p atom to a 32-bit on-the-wire format and appends it to - \p data. - */ - static void appendAtomData(String& data, Atom atom); - - //! Replace an Atom in property data - /*! - Converts \p atom to a 32-bit on-the-wire format and replaces the atom - at index \p index in \p data. - */ - static void replaceAtomData(String& data, - UInt32 index, Atom atom); - - //! Append an Time to property data - /*! - Converts \p time to a 32-bit on-the-wire format and appends it to - \p data. - */ - static void appendTimeData(String& data, Time time); - - //! X11 error handler - /*! - This class sets an X error handler in the c'tor and restores the - previous error handler in the d'tor. A lock should only be - installed while the display is locked by the thread. - - ErrorLock() ignores errors - ErrorLock(bool* flag) sets *flag to true if any error occurs - */ - class ErrorLock { - public: - //! Error handler type - typedef void (*ErrorHandler)(Display*, XErrorEvent*, void* userData); - - /*! - Ignore X11 errors. - */ - ErrorLock(Display*); - ErrorLock(ErrorLock const &) =delete; - ErrorLock(ErrorLock &&) =delete; - - ErrorLock& operator=(ErrorLock const &) =delete; - ErrorLock& operator=(ErrorLock &&) =delete; - - /*! - Set \c *errorFlag if any error occurs. - */ - ErrorLock(Display*, bool* errorFlag); - - /*! - Call \c handler on each error. - */ - ErrorLock(Display*, ErrorHandler handler, void* userData); - - ~ErrorLock(); - - private: - void install(ErrorHandler, void*); - static int internalHandler(Display*, XErrorEvent*); - static void ignoreHandler(Display*, XErrorEvent*, void*); - static void saveHandler(Display*, XErrorEvent*, void*); - - private: - typedef int (*XErrorHandler)(Display*, XErrorEvent*); - - Display* m_display; - ErrorHandler m_handler; - void* m_userData; - XErrorHandler m_oldXHandler; - ErrorLock* m_next; - static ErrorLock* s_top; - }; + Display *m_display; + ErrorHandler m_handler; + void *m_userData; + XErrorHandler m_oldXHandler; + ErrorLock *m_next; + static ErrorLock *s_top; + }; private: - class PropertyNotifyPredicateInfo { - public: - Window m_window; - Atom m_property; - }; + class PropertyNotifyPredicateInfo { + public: + Window m_window; + Atom m_property; + }; - static Bool propertyNotifyPredicate(Display*, - XEvent* xevent, XPointer arg); + static Bool propertyNotifyPredicate(Display *, XEvent *xevent, XPointer arg); - static void initKeyMaps(); + static void initKeyMaps(); private: - typedef std::map KeySymMap; + typedef std::map KeySymMap; - static KeySymMap s_keySymToUCS4; + static KeySymMap s_keySymToUCS4; }; diff --git a/src/lib/platform/synwinhk.h b/src/lib/platform/synwinhk.h index 056561766..bc3c4f898 100644 --- a/src/lib/platform/synwinhk.h +++ b/src/lib/platform/synwinhk.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -37,34 +37,25 @@ #define CSYNERGYHOOK_API __declspec(dllimport) #endif -#define SYNERGY_MSG_MARK WM_APP + 0x0011 // mark id; -#define SYNERGY_MSG_KEY WM_APP + 0x0012 // vk code; key data -#define SYNERGY_MSG_MOUSE_BUTTON WM_APP + 0x0013 // button msg; -#define SYNERGY_MSG_MOUSE_WHEEL WM_APP + 0x0014 // delta; -#define SYNERGY_MSG_MOUSE_MOVE WM_APP + 0x0015 // x; y -#define SYNERGY_MSG_POST_WARP WM_APP + 0x0016 // ; -#define SYNERGY_MSG_PRE_WARP WM_APP + 0x0017 // x; y -#define SYNERGY_MSG_SCREEN_SAVER WM_APP + 0x0018 // activated; -#define SYNERGY_MSG_DEBUG WM_APP + 0x0019 // data, data -#define SYNERGY_MSG_INPUT_FIRST SYNERGY_MSG_KEY -#define SYNERGY_MSG_INPUT_LAST SYNERGY_MSG_PRE_WARP -#define SYNERGY_HOOK_LAST_MSG SYNERGY_MSG_DEBUG +#define SYNERGY_MSG_MARK WM_APP + 0x0011 // mark id; +#define SYNERGY_MSG_KEY WM_APP + 0x0012 // vk code; key data +#define SYNERGY_MSG_MOUSE_BUTTON WM_APP + 0x0013 // button msg; +#define SYNERGY_MSG_MOUSE_WHEEL WM_APP + 0x0014 // delta; +#define SYNERGY_MSG_MOUSE_MOVE WM_APP + 0x0015 // x; y +#define SYNERGY_MSG_POST_WARP WM_APP + 0x0016 // ; +#define SYNERGY_MSG_PRE_WARP WM_APP + 0x0017 // x; y +#define SYNERGY_MSG_SCREEN_SAVER WM_APP + 0x0018 // activated; +#define SYNERGY_MSG_DEBUG WM_APP + 0x0019 // data, data +#define SYNERGY_MSG_INPUT_FIRST SYNERGY_MSG_KEY +#define SYNERGY_MSG_INPUT_LAST SYNERGY_MSG_PRE_WARP +#define SYNERGY_HOOK_LAST_MSG SYNERGY_MSG_DEBUG -#define SYNERGY_HOOK_FAKE_INPUT_VIRTUAL_KEY VK_CANCEL -#define SYNERGY_HOOK_FAKE_INPUT_SCANCODE 0 +#define SYNERGY_HOOK_FAKE_INPUT_VIRTUAL_KEY VK_CANCEL +#define SYNERGY_HOOK_FAKE_INPUT_SCANCODE 0 extern "C" { -enum EHookResult { - kHOOK_FAILED, - kHOOK_OKAY, - kHOOK_OKAY_LL -}; - -enum EHookMode { - kHOOK_DISABLE, - kHOOK_WATCH_JUMP_ZONE, - kHOOK_RELAY_EVENTS -}; +enum EHookResult { kHOOK_FAILED, kHOOK_OKAY, kHOOK_OKAY_LL }; +enum EHookMode { kHOOK_DISABLE, kHOOK_WATCH_JUMP_ZONE, kHOOK_RELAY_EVENTS }; } diff --git a/src/lib/server/BaseClientProxy.cpp b/src/lib/server/BaseClientProxy.cpp index 029f999fb..20f65fa0c 100644 --- a/src/lib/server/BaseClientProxy.cpp +++ b/src/lib/server/BaseClientProxy.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2006 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 LICENSE 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 @@ -22,35 +22,23 @@ // BaseClientProxy // -BaseClientProxy::BaseClientProxy(const String& name) : - m_name(name), - m_x(0), - m_y(0) -{ - // do nothing +BaseClientProxy::BaseClientProxy(const String &name) + : m_name(name), m_x(0), m_y(0) { + // do nothing } -BaseClientProxy::~BaseClientProxy() -{ - // do nothing +BaseClientProxy::~BaseClientProxy() { + // do nothing } -void -BaseClientProxy::setJumpCursorPos(SInt32 x, SInt32 y) -{ - m_x = x; - m_y = y; +void BaseClientProxy::setJumpCursorPos(SInt32 x, SInt32 y) { + m_x = x; + m_y = y; } -void -BaseClientProxy::getJumpCursorPos(SInt32& x, SInt32& y) const -{ - x = m_x; - y = m_y; +void BaseClientProxy::getJumpCursorPos(SInt32 &x, SInt32 &y) const { + x = m_x; + y = m_y; } -String -BaseClientProxy::getName() const -{ - return m_name; -} +String BaseClientProxy::getName() const { return m_name; } diff --git a/src/lib/server/BaseClientProxy.h b/src/lib/server/BaseClientProxy.h index 80b42eec9..7a703b89e 100644 --- a/src/lib/server/BaseClientProxy.h +++ b/src/lib/server/BaseClientProxy.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -18,84 +18,84 @@ #pragma once -#include "synergy/IClient.h" #include "base/String.h" +#include "synergy/IClient.h" -namespace synergy { class IStream; } +namespace synergy { +class IStream; +} //! Generic proxy for client or primary class BaseClientProxy : public IClient { public: - /*! - \c name is the name of the client. - */ - BaseClientProxy(const String& name); - ~BaseClientProxy(); + /*! + \c name is the name of the client. + */ + BaseClientProxy(const String &name); + ~BaseClientProxy(); - //! @name manipulators - //@{ + //! @name manipulators + //@{ - //! Save cursor position - /*! - Save the position of the cursor when jumping from client. - */ - void setJumpCursorPos(SInt32 x, SInt32 y); + //! Save cursor position + /*! + Save the position of the cursor when jumping from client. + */ + void setJumpCursorPos(SInt32 x, SInt32 y); - //@} - //! @name accessors - //@{ + //@} + //! @name accessors + //@{ - //! Get cursor position - /*! - Get the position of the cursor when last jumping from client. - */ - void getJumpCursorPos(SInt32& x, SInt32& y) const; + //! Get cursor position + /*! + Get the position of the cursor when last jumping from client. + */ + void getJumpCursorPos(SInt32 &x, SInt32 &y) const; - //! Get cursor position - /*! - Return if this proxy is for client or primary. - */ - virtual bool isPrimary() const { return false; } + //! Get cursor position + /*! + Return if this proxy is for client or primary. + */ + virtual bool isPrimary() const { return false; } - //@} + //@} - // IScreen - virtual void* getEventTarget() const = 0; - virtual bool getClipboard(ClipboardID id, IClipboard*) const = 0; - virtual void getShape(SInt32& x, SInt32& y, - SInt32& width, SInt32& height) const = 0; - virtual void getCursorPos(SInt32& x, SInt32& y) const = 0; + // IScreen + virtual void *getEventTarget() const = 0; + virtual bool getClipboard(ClipboardID id, IClipboard *) const = 0; + virtual void getShape(SInt32 &x, SInt32 &y, SInt32 &width, + SInt32 &height) const = 0; + virtual void getCursorPos(SInt32 &x, SInt32 &y) const = 0; - // IClient overrides - virtual void enter(SInt32 xAbs, SInt32 yAbs, - UInt32 seqNum, KeyModifierMask mask, - bool forScreensaver) = 0; - virtual bool leave() = 0; - virtual void setClipboard(ClipboardID, const IClipboard*) = 0; - virtual void grabClipboard(ClipboardID) = 0; - virtual void setClipboardDirty(ClipboardID, bool) = 0; - virtual void keyDown(KeyID, KeyModifierMask, KeyButton, const String&) = 0; - virtual void keyRepeat(KeyID, KeyModifierMask, - SInt32 count, KeyButton, const String& lang) = 0; - virtual void keyUp(KeyID, KeyModifierMask, KeyButton) = 0; - virtual void mouseDown(ButtonID) = 0; - virtual void mouseUp(ButtonID) = 0; - virtual void mouseMove(SInt32 xAbs, SInt32 yAbs) = 0; - virtual void mouseRelativeMove(SInt32 xRel, SInt32 yRel) = 0; - virtual void mouseWheel(SInt32 xDelta, SInt32 yDelta) = 0; - virtual void screensaver(bool activate) = 0; - virtual void resetOptions() = 0; - virtual void setOptions(const OptionsList& options) = 0; - virtual void sendDragInfo(UInt32 fileCount, const char* info, + // IClient overrides + virtual void enter(SInt32 xAbs, SInt32 yAbs, UInt32 seqNum, + KeyModifierMask mask, bool forScreensaver) = 0; + virtual bool leave() = 0; + virtual void setClipboard(ClipboardID, const IClipboard *) = 0; + virtual void grabClipboard(ClipboardID) = 0; + virtual void setClipboardDirty(ClipboardID, bool) = 0; + virtual void keyDown(KeyID, KeyModifierMask, KeyButton, const String &) = 0; + virtual void keyRepeat(KeyID, KeyModifierMask, SInt32 count, KeyButton, + const String &lang) = 0; + virtual void keyUp(KeyID, KeyModifierMask, KeyButton) = 0; + virtual void mouseDown(ButtonID) = 0; + virtual void mouseUp(ButtonID) = 0; + virtual void mouseMove(SInt32 xAbs, SInt32 yAbs) = 0; + virtual void mouseRelativeMove(SInt32 xRel, SInt32 yRel) = 0; + virtual void mouseWheel(SInt32 xDelta, SInt32 yDelta) = 0; + virtual void screensaver(bool activate) = 0; + virtual void resetOptions() = 0; + virtual void setOptions(const OptionsList &options) = 0; + virtual void sendDragInfo(UInt32 fileCount, const char *info, size_t size) = 0; - virtual void fileChunkSending(UInt8 mark, char* data, size_t dataSize) = 0; - virtual String getSecureInputApp() const = 0; - virtual void secureInputNotification(const String& app) const = 0; - virtual String getName() const; - virtual synergy::IStream* - getStream() const = 0; + virtual void fileChunkSending(UInt8 mark, char *data, size_t dataSize) = 0; + virtual String getSecureInputApp() const = 0; + virtual void secureInputNotification(const String &app) const = 0; + virtual String getName() const; + virtual synergy::IStream *getStream() const = 0; private: - String m_name; - SInt32 m_x, m_y; + String m_name; + SInt32 m_x, m_y; }; diff --git a/src/lib/server/ClientListener.cpp b/src/lib/server/ClientListener.cpp index c89f93ad5..c2148d96e 100644 --- a/src/lib/server/ClientListener.cpp +++ b/src/lib/server/ClientListener.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 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 LICENSE 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 @@ -19,259 +19,230 @@ #include "server/ClientListener.h" #include "server/Server.h" -#include "server/ClientProxy.h" -#include "server/ClientProxyUnknown.h" -#include "synergy/PacketStreamFilter.h" +#include "base/IEventQueue.h" +#include "base/Log.h" +#include "base/TMethodEventJob.h" #include "net/IDataSocket.h" #include "net/IListenSocket.h" #include "net/ISocketFactory.h" #include "net/XSocket.h" -#include "base/Log.h" -#include "base/IEventQueue.h" -#include "base/TMethodEventJob.h" +#include "server/ClientProxy.h" +#include "server/ClientProxyUnknown.h" +#include "synergy/PacketStreamFilter.h" // // ClientListener // -ClientListener::ClientListener(const NetworkAddress& address, - ISocketFactory* socketFactory, - IEventQueue* events, - bool enableCrypto) : - m_socketFactory(socketFactory), - m_server(NULL), - m_events(events), - m_useSecureNetwork(enableCrypto), - m_address(address) -{ - assert(m_socketFactory != NULL); +ClientListener::ClientListener(const NetworkAddress &address, + ISocketFactory *socketFactory, + IEventQueue *events, bool enableCrypto) + : m_socketFactory(socketFactory), m_server(NULL), m_events(events), + m_useSecureNetwork(enableCrypto), m_address(address) { + assert(m_socketFactory != NULL); - try { - start(); - } - catch (XSocketAddressInUse&) { - cleanupListenSocket(); - delete m_socketFactory; - throw; - } - catch (XBase&) { - cleanupListenSocket(); - delete m_socketFactory; - throw; - } - LOG((CLOG_DEBUG1 "listening for clients")); -} - -ClientListener::~ClientListener() -{ - stop(); - delete m_socketFactory; -} - -void -ClientListener::setServer(Server* server) -{ - assert(server != NULL); - m_server = server; -} - -ClientProxy* -ClientListener::getNextClient() -{ - ClientProxy* client = NULL; - if (!m_waitingClients.empty()) { - client = m_waitingClients.front(); - m_waitingClients.pop_front(); - m_events->removeHandler(m_events->forClientProxy().disconnected(), client); - } - return client; -} - -void ClientListener::start() -{ - m_listen = m_socketFactory->createListen(m_useSecureNetwork, ARCH->getAddrFamily(m_address.getAddress())); - - // setup event handler - m_events->adoptHandler(m_events->forIListenSocket().connecting(), - m_listen, - new TMethodEventJob(this, - &ClientListener::handleClientConnecting)); - - // bind listen address - LOG((CLOG_DEBUG1 "binding listen socket")); - m_listen->bind(m_address); -} - -void ClientListener::stop() -{ - LOG((CLOG_DEBUG1 "stop listening for clients")); - - // discard already connected clients - for (NewClients::iterator index = m_newClients.begin(); - index != m_newClients.end(); ++index) { - ClientProxyUnknown* client = *index; - m_events->removeHandler( - m_events->forClientProxyUnknown().success(), client); - m_events->removeHandler( - m_events->forClientProxyUnknown().failure(), client); - m_events->removeHandler( - m_events->forClientProxy().disconnected(), client); - delete client; - } - - // discard waiting clients - ClientProxy* client = getNextClient(); - while (client != nullptr) { - delete client; - client = getNextClient(); - } - - m_events->removeHandler(m_events->forIListenSocket().connecting(), m_listen); + try { + start(); + } catch (XSocketAddressInUse &) { cleanupListenSocket(); - cleanupClientSockets(); + delete m_socketFactory; + throw; + } catch (XBase &) { + cleanupListenSocket(); + delete m_socketFactory; + throw; + } + LOG((CLOG_DEBUG1 "listening for clients")); } -void ClientListener::removeUnknownClient(ClientProxyUnknown* unknownClient) -{ - if (unknownClient) { - m_events->removeHandler(m_events->forClientProxyUnknown().success(), unknownClient); - m_events->removeHandler(m_events->forClientProxyUnknown().failure(), unknownClient); - m_newClients.erase(unknownClient); - delete unknownClient; - } +ClientListener::~ClientListener() { + stop(); + delete m_socketFactory; } -void ClientListener::restart() -{ - if (m_server && m_server->isClientMode()){ - stop(); - start(); - } +void ClientListener::setServer(Server *server) { + assert(server != NULL); + m_server = server; } -void -ClientListener::handleClientConnecting(const Event&, void*) -{ - // accept client connection - IDataSocket* socket = m_listen->accept(); - - if (socket == NULL) { - return; - } - - m_clientSockets.insert(socket); - - m_events->adoptHandler(m_events->forClientListener().accepted(), - socket->getEventTarget(), - new TMethodEventJob(this, - &ClientListener::handleClientAccepted, socket)); - - // When using non SSL, server accepts clients immediately, while SSL - // has to call secure accept which may require retry - if (!m_useSecureNetwork) { - m_events->addEvent(Event(m_events->forClientListener().accepted(), - socket->getEventTarget())); - } +ClientProxy *ClientListener::getNextClient() { + ClientProxy *client = NULL; + if (!m_waitingClients.empty()) { + client = m_waitingClients.front(); + m_waitingClients.pop_front(); + m_events->removeHandler(m_events->forClientProxy().disconnected(), client); + } + return client; } -void -ClientListener::handleClientAccepted(const Event&, void* vsocket) -{ - LOG((CLOG_NOTE "accepted client connection")); +void ClientListener::start() { + m_listen = m_socketFactory->createListen( + m_useSecureNetwork, ARCH->getAddrFamily(m_address.getAddress())); - IDataSocket* socket = static_cast(vsocket); - - // filter socket messages, including a packetizing filter - synergy::IStream* stream = new PacketStreamFilter(m_events, socket, false); - assert(m_server != NULL); + // setup event handler + m_events->adoptHandler(m_events->forIListenSocket().connecting(), m_listen, + new TMethodEventJob( + this, &ClientListener::handleClientConnecting)); - // create proxy for unknown client - ClientProxyUnknown* client = new ClientProxyUnknown(stream, 30.0, m_server, m_events); - - m_newClients.insert(client); - - // watch for events from unknown client - m_events->adoptHandler(m_events->forClientProxyUnknown().success(), - client, - new TMethodEventJob(this, - &ClientListener::handleUnknownClient, client)); - m_events->adoptHandler(m_events->forClientProxyUnknown().failure(), - client, - new TMethodEventJob(this, - &ClientListener::handleUnknownClientFailure, client)); + // bind listen address + LOG((CLOG_DEBUG1 "binding listen socket")); + m_listen->bind(m_address); } -void -ClientListener::handleUnknownClient(const Event&, void* vclient) -{ - auto unknownClient = static_cast(vclient); +void ClientListener::stop() { + LOG((CLOG_DEBUG1 "stop listening for clients")); - // we should have the client in our new client list - assert(m_newClients.count(unknownClient) == 1); - - // get the real client proxy and install it - auto client = unknownClient->orphanClientProxy(); - if (client) { - // handshake was successful - m_waitingClients.push_back(client); - m_events->addEvent(Event(m_events->forClientListener().connected(), - this)); - - // watch for client to disconnect while it's in our queue - m_events->adoptHandler(m_events->forClientProxy().disconnected(), client, - new TMethodEventJob(this, - &ClientListener::handleClientDisconnected, - client)); - } - - // now finished with unknown client - removeUnknownClient(unknownClient); -} - -void ClientListener::handleUnknownClientFailure(const Event &, void* vclient) -{ - auto unknownClient = static_cast(vclient); - removeUnknownClient(unknownClient); - restart(); -} - -void -ClientListener::handleClientDisconnected(const Event&, void* vclient) -{ - ClientProxy* client = static_cast(vclient); - - // find client in waiting clients queue - for (WaitingClients::iterator i = m_waitingClients.begin(), - n = m_waitingClients.end(); i != n; ++i) { - if (*i == client) { - m_waitingClients.erase(i); - m_events->removeHandler(m_events->forClientProxy().disconnected(), + // discard already connected clients + for (NewClients::iterator index = m_newClients.begin(); + index != m_newClients.end(); ++index) { + ClientProxyUnknown *client = *index; + m_events->removeHandler(m_events->forClientProxyUnknown().success(), client); + m_events->removeHandler(m_events->forClientProxyUnknown().failure(), + client); + m_events->removeHandler(m_events->forClientProxy().disconnected(), client); + delete client; + } - // pull out the socket before deleting the client so - // we know which socket we no longer need - IDataSocket* socket = static_cast(client->getStream()); - delete client; - m_clientSockets.erase(socket); - delete socket; + // discard waiting clients + ClientProxy *client = getNextClient(); + while (client != nullptr) { + delete client; + client = getNextClient(); + } - break; - } + m_events->removeHandler(m_events->forIListenSocket().connecting(), m_listen); + cleanupListenSocket(); + cleanupClientSockets(); +} + +void ClientListener::removeUnknownClient(ClientProxyUnknown *unknownClient) { + if (unknownClient) { + m_events->removeHandler(m_events->forClientProxyUnknown().success(), + unknownClient); + m_events->removeHandler(m_events->forClientProxyUnknown().failure(), + unknownClient); + m_newClients.erase(unknownClient); + delete unknownClient; + } +} + +void ClientListener::restart() { + if (m_server && m_server->isClientMode()) { + stop(); + start(); + } +} + +void ClientListener::handleClientConnecting(const Event &, void *) { + // accept client connection + IDataSocket *socket = m_listen->accept(); + + if (socket == NULL) { + return; + } + + m_clientSockets.insert(socket); + + m_events->adoptHandler( + m_events->forClientListener().accepted(), socket->getEventTarget(), + new TMethodEventJob( + this, &ClientListener::handleClientAccepted, socket)); + + // When using non SSL, server accepts clients immediately, while SSL + // has to call secure accept which may require retry + if (!m_useSecureNetwork) { + m_events->addEvent(Event(m_events->forClientListener().accepted(), + socket->getEventTarget())); + } +} + +void ClientListener::handleClientAccepted(const Event &, void *vsocket) { + LOG((CLOG_NOTE "accepted client connection")); + + IDataSocket *socket = static_cast(vsocket); + + // filter socket messages, including a packetizing filter + synergy::IStream *stream = new PacketStreamFilter(m_events, socket, false); + assert(m_server != NULL); + + // create proxy for unknown client + ClientProxyUnknown *client = + new ClientProxyUnknown(stream, 30.0, m_server, m_events); + + m_newClients.insert(client); + + // watch for events from unknown client + m_events->adoptHandler( + m_events->forClientProxyUnknown().success(), client, + new TMethodEventJob( + this, &ClientListener::handleUnknownClient, client)); + m_events->adoptHandler( + m_events->forClientProxyUnknown().failure(), client, + new TMethodEventJob( + this, &ClientListener::handleUnknownClientFailure, client)); +} + +void ClientListener::handleUnknownClient(const Event &, void *vclient) { + auto unknownClient = static_cast(vclient); + + // we should have the client in our new client list + assert(m_newClients.count(unknownClient) == 1); + + // get the real client proxy and install it + auto client = unknownClient->orphanClientProxy(); + if (client) { + // handshake was successful + m_waitingClients.push_back(client); + m_events->addEvent(Event(m_events->forClientListener().connected(), this)); + + // watch for client to disconnect while it's in our queue + m_events->adoptHandler( + m_events->forClientProxy().disconnected(), client, + new TMethodEventJob( + this, &ClientListener::handleClientDisconnected, client)); + } + + // now finished with unknown client + removeUnknownClient(unknownClient); +} + +void ClientListener::handleUnknownClientFailure(const Event &, void *vclient) { + auto unknownClient = static_cast(vclient); + removeUnknownClient(unknownClient); + restart(); +} + +void ClientListener::handleClientDisconnected(const Event &, void *vclient) { + ClientProxy *client = static_cast(vclient); + + // find client in waiting clients queue + for (WaitingClients::iterator i = m_waitingClients.begin(), + n = m_waitingClients.end(); + i != n; ++i) { + if (*i == client) { + m_waitingClients.erase(i); + m_events->removeHandler(m_events->forClientProxy().disconnected(), + client); + + // pull out the socket before deleting the client so + // we know which socket we no longer need + IDataSocket *socket = static_cast(client->getStream()); + delete client; + m_clientSockets.erase(socket); + delete socket; + + break; } + } } -void -ClientListener::cleanupListenSocket() -{ - delete m_listen; -} +void ClientListener::cleanupListenSocket() { delete m_listen; } -void -ClientListener::cleanupClientSockets() -{ - ClientSockets::iterator it; - for (it = m_clientSockets.begin(); it != m_clientSockets.end(); it++) { - delete *it; - } - m_clientSockets.clear(); +void ClientListener::cleanupClientSockets() { + ClientSockets::iterator it; + for (it = m_clientSockets.begin(); it != m_clientSockets.end(); it++) { + delete *it; + } + m_clientSockets.clear(); } diff --git a/src/lib/server/ClientListener.h b/src/lib/server/ClientListener.h index f5345d2d8..8d93e646d 100644 --- a/src/lib/server/ClientListener.h +++ b/src/lib/server/ClientListener.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 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 LICENSE 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 @@ -18,11 +18,11 @@ #pragma once -#include "server/Config.h" -#include "base/EventTypes.h" #include "base/Event.h" +#include "base/EventTypes.h" #include "common/stddeque.h" #include "common/stdset.h" +#include "server/Config.h" class ClientProxy; class ClientProxyUnknown; @@ -35,70 +35,68 @@ class IDataSocket; class ClientListener { public: - // The factories are adopted. - ClientListener(const NetworkAddress&, - ISocketFactory*, - IEventQueue* events, - bool enableCrypto); - ClientListener(ClientListener const &) =delete; - ClientListener(ClientListener &&) =delete; - ~ClientListener(); + // The factories are adopted. + ClientListener(const NetworkAddress &, ISocketFactory *, IEventQueue *events, + bool enableCrypto); + ClientListener(ClientListener const &) = delete; + ClientListener(ClientListener &&) = delete; + ~ClientListener(); - ClientListener& operator=(ClientListener const &) =delete; - ClientListener& operator=(ClientListener &&) =delete; + ClientListener &operator=(ClientListener const &) = delete; + ClientListener &operator=(ClientListener &&) = delete; - //! @name manipulators - //@{ + //! @name manipulators + //@{ - void setServer(Server* server); + void setServer(Server *server); - //@} + //@} - //! @name accessors - //@{ + //! @name accessors + //@{ - //! Get next connected client - /*! - Returns the next connected client and removes it from the internal - list. The client is responsible for deleting the returned client. - Returns NULL if no clients are available. - */ - ClientProxy* getNextClient(); + //! Get next connected client + /*! + Returns the next connected client and removes it from the internal + list. The client is responsible for deleting the returned client. + Returns NULL if no clients are available. + */ + ClientProxy *getNextClient(); - //! Get server which owns this listener - Server* getServer() { return m_server; } + //! Get server which owns this listener + Server *getServer() { return m_server; } - //! This method restarts the listener - void restart(); + //! This method restarts the listener + void restart(); - //@} + //@} private: - // client connection event handlers - void handleClientConnecting(const Event&, void*); - void handleClientAccepted(const Event&, void*); - void handleUnknownClient(const Event&, void*); - void handleUnknownClientFailure(const Event&, void*); - void handleClientDisconnected(const Event&, void*); + // client connection event handlers + void handleClientConnecting(const Event &, void *); + void handleClientAccepted(const Event &, void *); + void handleUnknownClient(const Event &, void *); + void handleUnknownClientFailure(const Event &, void *); + void handleClientDisconnected(const Event &, void *); - void cleanupListenSocket(); - void cleanupClientSockets(); - void start(); - void stop(); - void removeUnknownClient(ClientProxyUnknown* unknownClient); + void cleanupListenSocket(); + void cleanupClientSockets(); + void start(); + void stop(); + void removeUnknownClient(ClientProxyUnknown *unknownClient); private: - typedef std::set NewClients; - typedef std::deque WaitingClients; - typedef std::set ClientSockets; + typedef std::set NewClients; + typedef std::deque WaitingClients; + typedef std::set ClientSockets; - IListenSocket* m_listen; - ISocketFactory* m_socketFactory; - NewClients m_newClients; - WaitingClients m_waitingClients; - Server* m_server; - IEventQueue* m_events; - bool m_useSecureNetwork; - ClientSockets m_clientSockets; - NetworkAddress m_address; + IListenSocket *m_listen; + ISocketFactory *m_socketFactory; + NewClients m_newClients; + WaitingClients m_waitingClients; + Server *m_server; + IEventQueue *m_events; + bool m_useSecureNetwork; + ClientSockets m_clientSockets; + NetworkAddress m_address; }; diff --git a/src/lib/server/ClientProxy.cpp b/src/lib/server/ClientProxy.cpp index 404ce2c6b..b6644b073 100644 --- a/src/lib/server/ClientProxy.cpp +++ b/src/lib/server/ClientProxy.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -18,44 +18,30 @@ #include "server/ClientProxy.h" -#include "synergy/ProtocolUtil.h" -#include "io/IStream.h" -#include "base/Log.h" #include "base/EventQueue.h" +#include "base/Log.h" +#include "io/IStream.h" +#include "synergy/ProtocolUtil.h" // // ClientProxy // -ClientProxy::ClientProxy(const String& name, synergy::IStream* stream) : - BaseClientProxy(name), - m_stream(stream) -{ +ClientProxy::ClientProxy(const String &name, synergy::IStream *stream) + : BaseClientProxy(name), m_stream(stream) {} + +ClientProxy::~ClientProxy() { delete m_stream; } + +void ClientProxy::close(const char *msg) { + LOG((CLOG_DEBUG1 "send close \"%s\" to \"%s\"", msg, getName().c_str())); + ProtocolUtil::writef(getStream(), msg); + + // force the close to be sent before we return + getStream()->flush(); } -ClientProxy::~ClientProxy() -{ - delete m_stream; -} +synergy::IStream *ClientProxy::getStream() const { return m_stream; } -void -ClientProxy::close(const char* msg) -{ - LOG((CLOG_DEBUG1 "send close \"%s\" to \"%s\"", msg, getName().c_str())); - ProtocolUtil::writef(getStream(), msg); - - // force the close to be sent before we return - getStream()->flush(); -} - -synergy::IStream* -ClientProxy::getStream() const -{ - return m_stream; -} - -void* -ClientProxy::getEventTarget() const -{ - return static_cast(const_cast(this)); +void *ClientProxy::getEventTarget() const { + return static_cast(const_cast(this)); } diff --git a/src/lib/server/ClientProxy.h b/src/lib/server/ClientProxy.h index 7e4e20f8d..4dfa3181c 100644 --- a/src/lib/server/ClientProxy.h +++ b/src/lib/server/ClientProxy.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -18,80 +18,81 @@ #pragma once -#include "server/BaseClientProxy.h" #include "base/Event.h" -#include "base/String.h" #include "base/EventTypes.h" +#include "base/String.h" +#include "server/BaseClientProxy.h" -namespace synergy { class IStream; } +namespace synergy { +class IStream; +} //! Generic proxy for client class ClientProxy : public BaseClientProxy { public: - /*! - \c name is the name of the client. - */ - ClientProxy(const String& name, synergy::IStream* adoptedStream); - ClientProxy(ClientProxy const &) =delete; - ClientProxy(ClientProxy &&) =delete; - ~ClientProxy(); + /*! + \c name is the name of the client. + */ + ClientProxy(const String &name, synergy::IStream *adoptedStream); + ClientProxy(ClientProxy const &) = delete; + ClientProxy(ClientProxy &&) = delete; + ~ClientProxy(); - ClientProxy& operator=(ClientProxy const &) =delete; - ClientProxy& operator=(ClientProxy &&) =delete; + ClientProxy &operator=(ClientProxy const &) = delete; + ClientProxy &operator=(ClientProxy &&) = delete; - //! @name manipulators - //@{ + //! @name manipulators + //@{ - //! Disconnect - /*! - Ask the client to disconnect, using \p msg as the reason. - */ - void close(const char* msg); + //! Disconnect + /*! + Ask the client to disconnect, using \p msg as the reason. + */ + void close(const char *msg); - //@} - //! @name accessors - //@{ + //@} + //! @name accessors + //@{ - //! Get stream - /*! - Returns the original stream passed to the c'tor. - */ - synergy::IStream* getStream() const override; + //! Get stream + /*! + Returns the original stream passed to the c'tor. + */ + synergy::IStream *getStream() const override; - //@} + //@} - // IScreen - void* getEventTarget() const override; - bool getClipboard(ClipboardID id, IClipboard*) const override = 0; - void getShape(SInt32& x, SInt32& y, - SInt32& width, SInt32& height) const override = 0; - void getCursorPos(SInt32& x, SInt32& y) const override = 0; + // IScreen + void *getEventTarget() const override; + bool getClipboard(ClipboardID id, IClipboard *) const override = 0; + void getShape(SInt32 &x, SInt32 &y, SInt32 &width, + SInt32 &height) const override = 0; + void getCursorPos(SInt32 &x, SInt32 &y) const override = 0; - // IClient overrides - void enter(SInt32 xAbs, SInt32 yAbs, - UInt32 seqNum, KeyModifierMask mask, - bool forScreensaver) override = 0; - bool leave() override = 0; - void setClipboard(ClipboardID, const IClipboard*) override = 0; - void grabClipboard(ClipboardID) override = 0; - void setClipboardDirty(ClipboardID, bool) override = 0; - void keyDown(KeyID, KeyModifierMask, KeyButton, const String&) override = 0; - void keyRepeat(KeyID, KeyModifierMask, - SInt32 count, KeyButton, const String& lang) override = 0; - void keyUp(KeyID, KeyModifierMask, KeyButton) override = 0; - void mouseDown(ButtonID) override = 0; - void mouseUp(ButtonID) override = 0; - void mouseMove(SInt32 xAbs, SInt32 yAbs) override = 0; - void mouseRelativeMove(SInt32 xRel, SInt32 yRel) override = 0; - void mouseWheel(SInt32 xDelta, SInt32 yDelta) override = 0; - void screensaver(bool activate) override = 0; - void resetOptions() override = 0; - void setOptions(const OptionsList& options) override = 0; - void sendDragInfo(UInt32 fileCount, const char* info, - size_t size) override = 0; - void fileChunkSending(UInt8 mark, char* data, size_t dataSize) override = 0; - void secureInputNotification(const String& app) const override = 0; + // IClient overrides + void enter(SInt32 xAbs, SInt32 yAbs, UInt32 seqNum, KeyModifierMask mask, + bool forScreensaver) override = 0; + bool leave() override = 0; + void setClipboard(ClipboardID, const IClipboard *) override = 0; + void grabClipboard(ClipboardID) override = 0; + void setClipboardDirty(ClipboardID, bool) override = 0; + void keyDown(KeyID, KeyModifierMask, KeyButton, const String &) override = 0; + void keyRepeat(KeyID, KeyModifierMask, SInt32 count, KeyButton, + const String &lang) override = 0; + void keyUp(KeyID, KeyModifierMask, KeyButton) override = 0; + void mouseDown(ButtonID) override = 0; + void mouseUp(ButtonID) override = 0; + void mouseMove(SInt32 xAbs, SInt32 yAbs) override = 0; + void mouseRelativeMove(SInt32 xRel, SInt32 yRel) override = 0; + void mouseWheel(SInt32 xDelta, SInt32 yDelta) override = 0; + void screensaver(bool activate) override = 0; + void resetOptions() override = 0; + void setOptions(const OptionsList &options) override = 0; + void sendDragInfo(UInt32 fileCount, const char *info, + size_t size) override = 0; + void fileChunkSending(UInt8 mark, char *data, size_t dataSize) override = 0; + void secureInputNotification(const String &app) const override = 0; private: - synergy::IStream* m_stream; + synergy::IStream *m_stream; }; diff --git a/src/lib/server/ClientProxy1_0.cpp b/src/lib/server/ClientProxy1_0.cpp index 20da3515f..50b3c78d4 100644 --- a/src/lib/server/ClientProxy1_0.cpp +++ b/src/lib/server/ClientProxy1_0.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -18,12 +18,12 @@ #include "server/ClientProxy1_0.h" +#include "base/IEventQueue.h" +#include "base/Log.h" +#include "base/TMethodEventJob.h" +#include "io/IStream.h" #include "synergy/ProtocolUtil.h" #include "synergy/XSynergy.h" -#include "io/IStream.h" -#include "base/Log.h" -#include "base/IEventQueue.h" -#include "base/TMethodEventJob.h" #include @@ -31,470 +31,399 @@ // ClientProxy1_0 // -ClientProxy1_0::ClientProxy1_0(const String& name, synergy::IStream* stream, IEventQueue* events) : - ClientProxy(name, stream), - m_heartbeatTimer(NULL), - m_parser(&ClientProxy1_0::parseHandshakeMessage), - m_events(events) -{ - // install event handlers - m_events->adoptHandler(m_events->forIStream().inputReady(), - stream->getEventTarget(), - new TMethodEventJob(this, - &ClientProxy1_0::handleData, NULL)); - m_events->adoptHandler(m_events->forIStream().outputError(), - stream->getEventTarget(), - new TMethodEventJob(this, - &ClientProxy1_0::handleWriteError, NULL)); - m_events->adoptHandler(m_events->forIStream().inputShutdown(), - stream->getEventTarget(), - new TMethodEventJob(this, - &ClientProxy1_0::handleDisconnect, NULL)); - m_events->adoptHandler(m_events->forIStream().outputShutdown(), - stream->getEventTarget(), - new TMethodEventJob(this, - &ClientProxy1_0::handleWriteError, NULL)); - m_events->adoptHandler(Event::kTimer, this, - new TMethodEventJob(this, - &ClientProxy1_0::handleFlatline, NULL)); +ClientProxy1_0::ClientProxy1_0(const String &name, synergy::IStream *stream, + IEventQueue *events) + : ClientProxy(name, stream), m_heartbeatTimer(NULL), + m_parser(&ClientProxy1_0::parseHandshakeMessage), m_events(events) { + // install event handlers + m_events->adoptHandler(m_events->forIStream().inputReady(), + stream->getEventTarget(), + new TMethodEventJob( + this, &ClientProxy1_0::handleData, NULL)); + m_events->adoptHandler(m_events->forIStream().outputError(), + stream->getEventTarget(), + new TMethodEventJob( + this, &ClientProxy1_0::handleWriteError, NULL)); + m_events->adoptHandler(m_events->forIStream().inputShutdown(), + stream->getEventTarget(), + new TMethodEventJob( + this, &ClientProxy1_0::handleDisconnect, NULL)); + m_events->adoptHandler(m_events->forIStream().outputShutdown(), + stream->getEventTarget(), + new TMethodEventJob( + this, &ClientProxy1_0::handleWriteError, NULL)); + m_events->adoptHandler(Event::kTimer, this, + new TMethodEventJob( + this, &ClientProxy1_0::handleFlatline, NULL)); - setHeartbeatRate(kHeartRate, kHeartRate * kHeartBeatsUntilDeath); + setHeartbeatRate(kHeartRate, kHeartRate * kHeartBeatsUntilDeath); - LOG((CLOG_DEBUG1 "querying client \"%s\" info", getName().c_str())); - ProtocolUtil::writef(getStream(), kMsgQInfo); + LOG((CLOG_DEBUG1 "querying client \"%s\" info", getName().c_str())); + ProtocolUtil::writef(getStream(), kMsgQInfo); } -ClientProxy1_0::~ClientProxy1_0() -{ - removeHandlers(); +ClientProxy1_0::~ClientProxy1_0() { removeHandlers(); } + +void ClientProxy1_0::disconnect() { + removeHandlers(); + getStream()->close(); + m_events->addEvent( + Event(m_events->forClientProxy().disconnected(), getEventTarget())); } -void -ClientProxy1_0::disconnect() -{ - removeHandlers(); - getStream()->close(); - m_events->addEvent(Event(m_events->forClientProxy().disconnected(), getEventTarget())); +void ClientProxy1_0::removeHandlers() { + // uninstall event handlers + m_events->removeHandler(m_events->forIStream().inputReady(), + getStream()->getEventTarget()); + m_events->removeHandler(m_events->forIStream().outputError(), + getStream()->getEventTarget()); + m_events->removeHandler(m_events->forIStream().inputShutdown(), + getStream()->getEventTarget()); + m_events->removeHandler(m_events->forIStream().outputShutdown(), + getStream()->getEventTarget()); + m_events->removeHandler(Event::kTimer, this); + + // remove timer + removeHeartbeatTimer(); } -void -ClientProxy1_0::removeHandlers() -{ - // uninstall event handlers - m_events->removeHandler(m_events->forIStream().inputReady(), - getStream()->getEventTarget()); - m_events->removeHandler(m_events->forIStream().outputError(), - getStream()->getEventTarget()); - m_events->removeHandler(m_events->forIStream().inputShutdown(), - getStream()->getEventTarget()); - m_events->removeHandler(m_events->forIStream().outputShutdown(), - getStream()->getEventTarget()); - m_events->removeHandler(Event::kTimer, this); - - // remove timer - removeHeartbeatTimer(); +void ClientProxy1_0::addHeartbeatTimer() { + if (m_heartbeatAlarm > 0.0) { + m_heartbeatTimer = m_events->newOneShotTimer(m_heartbeatAlarm, this); + } } -void -ClientProxy1_0::addHeartbeatTimer() -{ - if (m_heartbeatAlarm > 0.0) { - m_heartbeatTimer = m_events->newOneShotTimer(m_heartbeatAlarm, this); - } +void ClientProxy1_0::removeHeartbeatTimer() { + if (m_heartbeatTimer != NULL) { + m_events->deleteTimer(m_heartbeatTimer); + m_heartbeatTimer = NULL; + } } -void -ClientProxy1_0::removeHeartbeatTimer() -{ - if (m_heartbeatTimer != NULL) { - m_events->deleteTimer(m_heartbeatTimer); - m_heartbeatTimer = NULL; - } +void ClientProxy1_0::resetHeartbeatTimer() { + // reset the alarm + removeHeartbeatTimer(); + addHeartbeatTimer(); } -void -ClientProxy1_0::resetHeartbeatTimer() -{ - // reset the alarm - removeHeartbeatTimer(); - addHeartbeatTimer(); +void ClientProxy1_0::resetHeartbeatRate() { + setHeartbeatRate(kHeartRate, kHeartRate * kHeartBeatsUntilDeath); } -void -ClientProxy1_0::resetHeartbeatRate() -{ - setHeartbeatRate(kHeartRate, kHeartRate * kHeartBeatsUntilDeath); +void ClientProxy1_0::setHeartbeatRate(double, double alarm) { + m_heartbeatAlarm = alarm; } -void -ClientProxy1_0::setHeartbeatRate(double, double alarm) -{ - m_heartbeatAlarm = alarm; -} - -void -ClientProxy1_0::handleData(const Event&, void*) -{ - // handle messages until there are no more. first read message code. - UInt8 code[4]; - UInt32 n = getStream()->read(code, 4); - while (n != 0) { - // verify we got an entire code - if (n != 4) { - LOG((CLOG_ERR "incomplete message from \"%s\": %d bytes", getName().c_str(), n)); - disconnect(); - return; - } - - // parse message - LOG((CLOG_DEBUG2 "msg from \"%s\": %c%c%c%c", getName().c_str(), code[0], code[1], code[2], code[3])); - if (!(this->*m_parser)(code)) { - LOG((CLOG_ERR "invalid message from client \"%s\": %c%c%c%c", getName().c_str(), code[0], code[1], code[2], code[3])); - // not possible to determine message boundaries - // read the whole stream to discard unkonwn data - while (getStream()->read(nullptr, 4)); - } - - // next message - n = getStream()->read(code, 4); +void ClientProxy1_0::handleData(const Event &, void *) { + // handle messages until there are no more. first read message code. + UInt8 code[4]; + UInt32 n = getStream()->read(code, 4); + while (n != 0) { + // verify we got an entire code + if (n != 4) { + LOG((CLOG_ERR "incomplete message from \"%s\": %d bytes", + getName().c_str(), n)); + disconnect(); + return; } - // restart heartbeat timer - resetHeartbeatTimer(); -} - -bool -ClientProxy1_0::parseHandshakeMessage(const UInt8* code) -{ - if (memcmp(code, kMsgCNoop, 4) == 0) { - // discard no-ops - LOG((CLOG_DEBUG2 "no-op from", getName().c_str())); - return true; - } - else if (memcmp(code, kMsgDInfo, 4) == 0) { - // future messages get parsed by parseMessage - m_parser = &ClientProxy1_0::parseMessage; - if (recvInfo()) { - m_events->addEvent(Event(m_events->forClientProxy().ready(), getEventTarget())); - addHeartbeatTimer(); - return true; - } - } - return false; -} - -bool -ClientProxy1_0::parseMessage(const UInt8* code) -{ - if (memcmp(code, kMsgDInfo, 4) == 0) { - if (recvInfo()) { - m_events->addEvent( - Event(m_events->forIScreen().shapeChanged(), getEventTarget())); - return true; - } - return false; - } - else if (memcmp(code, kMsgCNoop, 4) == 0) { - // discard no-ops - LOG((CLOG_DEBUG2 "no-op from", getName().c_str())); - return true; - } - else if (memcmp(code, kMsgCClipboard, 4) == 0) { - return recvGrabClipboard(); - } - else if (memcmp(code, kMsgDClipboard, 4) == 0) { - return recvClipboard(); - } - return false; -} - -void -ClientProxy1_0::handleDisconnect(const Event&, void*) -{ - LOG((CLOG_NOTE "client \"%s\" has disconnected", getName().c_str())); - disconnect(); -} - -void -ClientProxy1_0::handleWriteError(const Event&, void*) -{ - LOG((CLOG_WARN "error writing to client \"%s\"", getName().c_str())); - disconnect(); -} - -void -ClientProxy1_0::handleFlatline(const Event&, void*) -{ - // didn't get a heartbeat fast enough. assume client is dead. - LOG((CLOG_NOTE "client \"%s\" is dead", getName().c_str())); - disconnect(); -} - -bool -ClientProxy1_0::getClipboard(ClipboardID id, IClipboard* clipboard) const -{ - Clipboard::copy(clipboard, &m_clipboard[id].m_clipboard); - return true; -} - -void -ClientProxy1_0::getShape(SInt32& x, SInt32& y, SInt32& w, SInt32& h) const -{ - x = m_info.m_x; - y = m_info.m_y; - w = m_info.m_w; - h = m_info.m_h; -} - -void -ClientProxy1_0::getCursorPos(SInt32& x, SInt32& y) const -{ - // note -- this returns the cursor pos from when we last got client info - x = m_info.m_mx; - y = m_info.m_my; -} - -void -ClientProxy1_0::enter(SInt32 xAbs, SInt32 yAbs, - UInt32 seqNum, KeyModifierMask mask, bool) -{ - LOG((CLOG_DEBUG1 "send enter to \"%s\", %d,%d %d %04x", getName().c_str(), xAbs, yAbs, seqNum, mask)); - ProtocolUtil::writef(getStream(), kMsgCEnter, - xAbs, yAbs, seqNum, mask); -} - -bool -ClientProxy1_0::leave() -{ - LOG((CLOG_DEBUG1 "send leave to \"%s\"", getName().c_str())); - ProtocolUtil::writef(getStream(), kMsgCLeave); - - // we can never prevent the user from leaving - return true; -} - -void -ClientProxy1_0::setClipboard(ClipboardID id, const IClipboard* clipboard) -{ - // ignore -- deprecated in protocol 1.0 -} - -void -ClientProxy1_0::grabClipboard(ClipboardID id) -{ - LOG((CLOG_DEBUG "send grab clipboard %d to \"%s\"", id, getName().c_str())); - ProtocolUtil::writef(getStream(), kMsgCClipboard, id, 0); - - // this clipboard is now dirty - m_clipboard[id].m_dirty = true; -} - -void -ClientProxy1_0::setClipboardDirty(ClipboardID id, bool dirty) -{ - m_clipboard[id].m_dirty = dirty; -} - -void -ClientProxy1_0::keyDown(KeyID key, KeyModifierMask mask, KeyButton, const String&) -{ - LOG((CLOG_DEBUG1 "send key down to \"%s\" id=%d, mask=0x%04x", getName().c_str(), key, mask)); - ProtocolUtil::writef(getStream(), kMsgDKeyDown1_0, key, mask); -} - -void -ClientProxy1_0::keyRepeat(KeyID key, KeyModifierMask mask, - SInt32 count, KeyButton, const String&) -{ - LOG((CLOG_DEBUG1 "send key repeat to \"%s\" id=%d, mask=0x%04x, count=%d", getName().c_str(), key, mask, count)); - ProtocolUtil::writef(getStream(), kMsgDKeyRepeat1_0, key, mask, count); -} - -void -ClientProxy1_0::keyUp(KeyID key, KeyModifierMask mask, KeyButton) -{ - LOG((CLOG_DEBUG1 "send key up to \"%s\" id=%d, mask=0x%04x", getName().c_str(), key, mask)); - ProtocolUtil::writef(getStream(), kMsgDKeyUp1_0, key, mask); -} - -void -ClientProxy1_0::mouseDown(ButtonID button) -{ - LOG((CLOG_DEBUG1 "send mouse down to \"%s\" id=%d", getName().c_str(), button)); - ProtocolUtil::writef(getStream(), kMsgDMouseDown, button); -} - -void -ClientProxy1_0::mouseUp(ButtonID button) -{ - LOG((CLOG_DEBUG1 "send mouse up to \"%s\" id=%d", getName().c_str(), button)); - ProtocolUtil::writef(getStream(), kMsgDMouseUp, button); -} - -void -ClientProxy1_0::mouseMove(SInt32 xAbs, SInt32 yAbs) -{ - LOG((CLOG_DEBUG2 "send mouse move to \"%s\" %d,%d", getName().c_str(), xAbs, yAbs)); - ProtocolUtil::writef(getStream(), kMsgDMouseMove, xAbs, yAbs); -} - -void -ClientProxy1_0::mouseRelativeMove(SInt32, SInt32) -{ - // ignore -- not supported in protocol 1.0 -} - -void -ClientProxy1_0::mouseWheel(SInt32, SInt32 yDelta) -{ - // clients prior to 1.3 only support the y axis - LOG((CLOG_DEBUG2 "send mouse wheel to \"%s\" %+d", getName().c_str(), yDelta)); - ProtocolUtil::writef(getStream(), kMsgDMouseWheel1_0, yDelta); -} - -void -ClientProxy1_0::sendDragInfo(UInt32 fileCount, const char* info, size_t size) -{ - // ignore -- not supported in protocol 1.0 - LOG((CLOG_DEBUG "draggingInfoSending not supported")); -} - -void -ClientProxy1_0::fileChunkSending(UInt8 mark, char* data, size_t dataSize) -{ - // ignore -- not supported in protocol 1.0 - LOG((CLOG_DEBUG "fileChunkSending not supported")); -} - -String -ClientProxy1_0::getSecureInputApp() const -{ - // ignore -- not supported on clients - LOG((CLOG_DEBUG "getSecureInputApp not supported")); - return ""; -} - -void -ClientProxy1_0::secureInputNotification(const String& app) const -{ - // ignore -- not supported in protocol 1.0 - LOG((CLOG_DEBUG "secureInputNotification not supported")); -} - -void -ClientProxy1_0::screensaver(bool on) -{ - LOG((CLOG_DEBUG1 "send screen saver to \"%s\" on=%d", getName().c_str(), on ? 1 : 0)); - ProtocolUtil::writef(getStream(), kMsgCScreenSaver, on ? 1 : 0); -} - -void -ClientProxy1_0::resetOptions() -{ - LOG((CLOG_DEBUG1 "send reset options to \"%s\"", getName().c_str())); - ProtocolUtil::writef(getStream(), kMsgCResetOptions); - - // reset heart rate and death - resetHeartbeatRate(); - removeHeartbeatTimer(); - addHeartbeatTimer(); -} - -void -ClientProxy1_0::setOptions(const OptionsList& options) -{ - LOG((CLOG_DEBUG1 "send set options to \"%s\" size=%d", getName().c_str(), options.size())); - ProtocolUtil::writef(getStream(), kMsgDSetOptions, &options); - - // check options - for (UInt32 i = 0, n = (UInt32)options.size(); i < n; i += 2) { - if (options[i] == kOptionHeartbeat) { - double rate = 1.0e-3 * static_cast(options[i + 1]); - if (rate <= 0.0) { - rate = -1.0; - } - setHeartbeatRate(rate, rate * kHeartBeatsUntilDeath); - removeHeartbeatTimer(); - addHeartbeatTimer(); - } - } -} - -bool -ClientProxy1_0::recvInfo() -{ - // parse the message - SInt16 x, y, w, h, dummy1, mx, my; - if (!ProtocolUtil::readf(getStream(), kMsgDInfo + 4, - &x, &y, &w, &h, &dummy1, &mx, &my)) { - return false; - } - LOG((CLOG_DEBUG "received client \"%s\" info shape=%d,%d %dx%d at %d,%d", getName().c_str(), x, y, w, h, mx, my)); - - // validate - if (w <= 0 || h <= 0) { - return false; - } - if (mx < x || mx >= x + w || my < y || my >= y + h) { - mx = x + w / 2; - my = y + h / 2; - } - - // save - m_info.m_x = x; - m_info.m_y = y; - m_info.m_w = w; - m_info.m_h = h; - m_info.m_mx = mx; - m_info.m_my = my; - - // acknowledge receipt - LOG((CLOG_DEBUG1 "send info ack to \"%s\"", getName().c_str())); - ProtocolUtil::writef(getStream(), kMsgCInfoAck); - return true; -} - -bool -ClientProxy1_0::recvClipboard() -{ - // deprecated in protocol 1.0 - return false; -} - -bool -ClientProxy1_0::recvGrabClipboard() -{ // parse message - ClipboardID id; - UInt32 seqNum; - if (!ProtocolUtil::readf(getStream(), kMsgCClipboard + 4, &id, &seqNum)) { - return false; - } - LOG((CLOG_DEBUG "received client \"%s\" grabbed clipboard %d seqnum=%d", getName().c_str(), id, seqNum)); - - // validate - if (id >= kClipboardEnd) { - return false; + LOG((CLOG_DEBUG2 "msg from \"%s\": %c%c%c%c", getName().c_str(), code[0], + code[1], code[2], code[3])); + if (!(this->*m_parser)(code)) { + LOG((CLOG_ERR "invalid message from client \"%s\": %c%c%c%c", + getName().c_str(), code[0], code[1], code[2], code[3])); + // not possible to determine message boundaries + // read the whole stream to discard unkonwn data + while (getStream()->read(nullptr, 4)) + ; } - // notify - ClipboardInfo* info = new ClipboardInfo; - info->m_id = id; - info->m_sequenceNumber = seqNum; - m_events->addEvent(Event(m_events->forClipboard().clipboardGrabbed(), - getEventTarget(), info)); + // next message + n = getStream()->read(code, 4); + } + // restart heartbeat timer + resetHeartbeatTimer(); +} + +bool ClientProxy1_0::parseHandshakeMessage(const UInt8 *code) { + if (memcmp(code, kMsgCNoop, 4) == 0) { + // discard no-ops + LOG((CLOG_DEBUG2 "no-op from", getName().c_str())); return true; + } else if (memcmp(code, kMsgDInfo, 4) == 0) { + // future messages get parsed by parseMessage + m_parser = &ClientProxy1_0::parseMessage; + if (recvInfo()) { + m_events->addEvent( + Event(m_events->forClientProxy().ready(), getEventTarget())); + addHeartbeatTimer(); + return true; + } + } + return false; +} + +bool ClientProxy1_0::parseMessage(const UInt8 *code) { + if (memcmp(code, kMsgDInfo, 4) == 0) { + if (recvInfo()) { + m_events->addEvent( + Event(m_events->forIScreen().shapeChanged(), getEventTarget())); + return true; + } + return false; + } else if (memcmp(code, kMsgCNoop, 4) == 0) { + // discard no-ops + LOG((CLOG_DEBUG2 "no-op from", getName().c_str())); + return true; + } else if (memcmp(code, kMsgCClipboard, 4) == 0) { + return recvGrabClipboard(); + } else if (memcmp(code, kMsgDClipboard, 4) == 0) { + return recvClipboard(); + } + return false; +} + +void ClientProxy1_0::handleDisconnect(const Event &, void *) { + LOG((CLOG_NOTE "client \"%s\" has disconnected", getName().c_str())); + disconnect(); +} + +void ClientProxy1_0::handleWriteError(const Event &, void *) { + LOG((CLOG_WARN "error writing to client \"%s\"", getName().c_str())); + disconnect(); +} + +void ClientProxy1_0::handleFlatline(const Event &, void *) { + // didn't get a heartbeat fast enough. assume client is dead. + LOG((CLOG_NOTE "client \"%s\" is dead", getName().c_str())); + disconnect(); +} + +bool ClientProxy1_0::getClipboard(ClipboardID id, IClipboard *clipboard) const { + Clipboard::copy(clipboard, &m_clipboard[id].m_clipboard); + return true; +} + +void ClientProxy1_0::getShape(SInt32 &x, SInt32 &y, SInt32 &w, + SInt32 &h) const { + x = m_info.m_x; + y = m_info.m_y; + w = m_info.m_w; + h = m_info.m_h; +} + +void ClientProxy1_0::getCursorPos(SInt32 &x, SInt32 &y) const { + // note -- this returns the cursor pos from when we last got client info + x = m_info.m_mx; + y = m_info.m_my; +} + +void ClientProxy1_0::enter(SInt32 xAbs, SInt32 yAbs, UInt32 seqNum, + KeyModifierMask mask, bool) { + LOG((CLOG_DEBUG1 "send enter to \"%s\", %d,%d %d %04x", getName().c_str(), + xAbs, yAbs, seqNum, mask)); + ProtocolUtil::writef(getStream(), kMsgCEnter, xAbs, yAbs, seqNum, mask); +} + +bool ClientProxy1_0::leave() { + LOG((CLOG_DEBUG1 "send leave to \"%s\"", getName().c_str())); + ProtocolUtil::writef(getStream(), kMsgCLeave); + + // we can never prevent the user from leaving + return true; +} + +void ClientProxy1_0::setClipboard(ClipboardID id, const IClipboard *clipboard) { + // ignore -- deprecated in protocol 1.0 +} + +void ClientProxy1_0::grabClipboard(ClipboardID id) { + LOG((CLOG_DEBUG "send grab clipboard %d to \"%s\"", id, getName().c_str())); + ProtocolUtil::writef(getStream(), kMsgCClipboard, id, 0); + + // this clipboard is now dirty + m_clipboard[id].m_dirty = true; +} + +void ClientProxy1_0::setClipboardDirty(ClipboardID id, bool dirty) { + m_clipboard[id].m_dirty = dirty; +} + +void ClientProxy1_0::keyDown(KeyID key, KeyModifierMask mask, KeyButton, + const String &) { + LOG((CLOG_DEBUG1 "send key down to \"%s\" id=%d, mask=0x%04x", + getName().c_str(), key, mask)); + ProtocolUtil::writef(getStream(), kMsgDKeyDown1_0, key, mask); +} + +void ClientProxy1_0::keyRepeat(KeyID key, KeyModifierMask mask, SInt32 count, + KeyButton, const String &) { + LOG((CLOG_DEBUG1 "send key repeat to \"%s\" id=%d, mask=0x%04x, count=%d", + getName().c_str(), key, mask, count)); + ProtocolUtil::writef(getStream(), kMsgDKeyRepeat1_0, key, mask, count); +} + +void ClientProxy1_0::keyUp(KeyID key, KeyModifierMask mask, KeyButton) { + LOG((CLOG_DEBUG1 "send key up to \"%s\" id=%d, mask=0x%04x", + getName().c_str(), key, mask)); + ProtocolUtil::writef(getStream(), kMsgDKeyUp1_0, key, mask); +} + +void ClientProxy1_0::mouseDown(ButtonID button) { + LOG((CLOG_DEBUG1 "send mouse down to \"%s\" id=%d", getName().c_str(), + button)); + ProtocolUtil::writef(getStream(), kMsgDMouseDown, button); +} + +void ClientProxy1_0::mouseUp(ButtonID button) { + LOG((CLOG_DEBUG1 "send mouse up to \"%s\" id=%d", getName().c_str(), button)); + ProtocolUtil::writef(getStream(), kMsgDMouseUp, button); +} + +void ClientProxy1_0::mouseMove(SInt32 xAbs, SInt32 yAbs) { + LOG((CLOG_DEBUG2 "send mouse move to \"%s\" %d,%d", getName().c_str(), xAbs, + yAbs)); + ProtocolUtil::writef(getStream(), kMsgDMouseMove, xAbs, yAbs); +} + +void ClientProxy1_0::mouseRelativeMove(SInt32, SInt32) { + // ignore -- not supported in protocol 1.0 +} + +void ClientProxy1_0::mouseWheel(SInt32, SInt32 yDelta) { + // clients prior to 1.3 only support the y axis + LOG((CLOG_DEBUG2 "send mouse wheel to \"%s\" %+d", getName().c_str(), + yDelta)); + ProtocolUtil::writef(getStream(), kMsgDMouseWheel1_0, yDelta); +} + +void ClientProxy1_0::sendDragInfo(UInt32 fileCount, const char *info, + size_t size) { + // ignore -- not supported in protocol 1.0 + LOG((CLOG_DEBUG "draggingInfoSending not supported")); +} + +void ClientProxy1_0::fileChunkSending(UInt8 mark, char *data, size_t dataSize) { + // ignore -- not supported in protocol 1.0 + LOG((CLOG_DEBUG "fileChunkSending not supported")); +} + +String ClientProxy1_0::getSecureInputApp() const { + // ignore -- not supported on clients + LOG((CLOG_DEBUG "getSecureInputApp not supported")); + return ""; +} + +void ClientProxy1_0::secureInputNotification(const String &app) const { + // ignore -- not supported in protocol 1.0 + LOG((CLOG_DEBUG "secureInputNotification not supported")); +} + +void ClientProxy1_0::screensaver(bool on) { + LOG((CLOG_DEBUG1 "send screen saver to \"%s\" on=%d", getName().c_str(), + on ? 1 : 0)); + ProtocolUtil::writef(getStream(), kMsgCScreenSaver, on ? 1 : 0); +} + +void ClientProxy1_0::resetOptions() { + LOG((CLOG_DEBUG1 "send reset options to \"%s\"", getName().c_str())); + ProtocolUtil::writef(getStream(), kMsgCResetOptions); + + // reset heart rate and death + resetHeartbeatRate(); + removeHeartbeatTimer(); + addHeartbeatTimer(); +} + +void ClientProxy1_0::setOptions(const OptionsList &options) { + LOG((CLOG_DEBUG1 "send set options to \"%s\" size=%d", getName().c_str(), + options.size())); + ProtocolUtil::writef(getStream(), kMsgDSetOptions, &options); + + // check options + for (UInt32 i = 0, n = (UInt32)options.size(); i < n; i += 2) { + if (options[i] == kOptionHeartbeat) { + double rate = 1.0e-3 * static_cast(options[i + 1]); + if (rate <= 0.0) { + rate = -1.0; + } + setHeartbeatRate(rate, rate * kHeartBeatsUntilDeath); + removeHeartbeatTimer(); + addHeartbeatTimer(); + } + } +} + +bool ClientProxy1_0::recvInfo() { + // parse the message + SInt16 x, y, w, h, dummy1, mx, my; + if (!ProtocolUtil::readf(getStream(), kMsgDInfo + 4, &x, &y, &w, &h, &dummy1, + &mx, &my)) { + return false; + } + LOG((CLOG_DEBUG "received client \"%s\" info shape=%d,%d %dx%d at %d,%d", + getName().c_str(), x, y, w, h, mx, my)); + + // validate + if (w <= 0 || h <= 0) { + return false; + } + if (mx < x || mx >= x + w || my < y || my >= y + h) { + mx = x + w / 2; + my = y + h / 2; + } + + // save + m_info.m_x = x; + m_info.m_y = y; + m_info.m_w = w; + m_info.m_h = h; + m_info.m_mx = mx; + m_info.m_my = my; + + // acknowledge receipt + LOG((CLOG_DEBUG1 "send info ack to \"%s\"", getName().c_str())); + ProtocolUtil::writef(getStream(), kMsgCInfoAck); + return true; +} + +bool ClientProxy1_0::recvClipboard() { + // deprecated in protocol 1.0 + return false; +} + +bool ClientProxy1_0::recvGrabClipboard() { + // parse message + ClipboardID id; + UInt32 seqNum; + if (!ProtocolUtil::readf(getStream(), kMsgCClipboard + 4, &id, &seqNum)) { + return false; + } + LOG((CLOG_DEBUG "received client \"%s\" grabbed clipboard %d seqnum=%d", + getName().c_str(), id, seqNum)); + + // validate + if (id >= kClipboardEnd) { + return false; + } + + // notify + ClipboardInfo *info = new ClipboardInfo; + info->m_id = id; + info->m_sequenceNumber = seqNum; + m_events->addEvent(Event(m_events->forClipboard().clipboardGrabbed(), + getEventTarget(), info)); + + return true; } // // ClientProxy1_0::ClientClipboard // -ClientProxy1_0::ClientClipboard::ClientClipboard() : - m_clipboard(), - m_sequenceNumber(0), - m_dirty(true) -{ - // do nothing +ClientProxy1_0::ClientClipboard::ClientClipboard() + : m_clipboard(), m_sequenceNumber(0), m_dirty(true) { + // do nothing } diff --git a/src/lib/server/ClientProxy1_0.h b/src/lib/server/ClientProxy1_0.h index 408a24ad8..5c189b45f 100644 --- a/src/lib/server/ClientProxy1_0.h +++ b/src/lib/server/ClientProxy1_0.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -29,86 +29,87 @@ class IEventQueue; //! Proxy for client implementing protocol version 1.0 class ClientProxy1_0 : public ClientProxy { public: - ClientProxy1_0(const String& name, synergy::IStream* adoptedStream, IEventQueue* events); - ClientProxy1_0(ClientProxy1_0 const &) =delete; - ClientProxy1_0(ClientProxy1_0 &&) =delete; - ~ClientProxy1_0(); + ClientProxy1_0(const String &name, synergy::IStream *adoptedStream, + IEventQueue *events); + ClientProxy1_0(ClientProxy1_0 const &) = delete; + ClientProxy1_0(ClientProxy1_0 &&) = delete; + ~ClientProxy1_0(); - ClientProxy1_0& operator=(ClientProxy1_0 const &) =delete; - ClientProxy1_0& operator=(ClientProxy1_0 &&) =delete; + ClientProxy1_0 &operator=(ClientProxy1_0 const &) = delete; + ClientProxy1_0 &operator=(ClientProxy1_0 &&) = delete; - // IScreen - bool getClipboard(ClipboardID id, IClipboard*) const override; - void getShape(SInt32& x, SInt32& y, - SInt32& width, SInt32& height) const override; - void getCursorPos(SInt32& x, SInt32& y) const override; + // IScreen + bool getClipboard(ClipboardID id, IClipboard *) const override; + void getShape(SInt32 &x, SInt32 &y, SInt32 &width, + SInt32 &height) const override; + void getCursorPos(SInt32 &x, SInt32 &y) const override; - // IClient overrides - void enter(SInt32 xAbs, SInt32 yAbs, - UInt32 seqNum, KeyModifierMask mask, - bool forScreensaver) override; - bool leave() override; - void setClipboard(ClipboardID, const IClipboard*) override; - void grabClipboard(ClipboardID) override; - void setClipboardDirty(ClipboardID, bool) override; - void keyDown(KeyID, KeyModifierMask, KeyButton, const String&) override; - void keyRepeat(KeyID, KeyModifierMask, - SInt32 count, KeyButton, const String&) override; - void keyUp(KeyID, KeyModifierMask, KeyButton) override; - void mouseDown(ButtonID) override; - void mouseUp(ButtonID) override; - void mouseMove(SInt32 xAbs, SInt32 yAbs) override; - void mouseRelativeMove(SInt32 xRel, SInt32 yRel) override; - void mouseWheel(SInt32 xDelta, SInt32 yDelta) override; - void screensaver(bool activate) override; - void resetOptions() override; - void setOptions(const OptionsList& options) override; - void sendDragInfo(UInt32 fileCount, const char* info, size_t size) override; - void fileChunkSending(UInt8 mark, char* data, size_t dataSize) override; - String getSecureInputApp() const override; - void secureInputNotification(const String& app) const override; + // IClient overrides + void enter(SInt32 xAbs, SInt32 yAbs, UInt32 seqNum, KeyModifierMask mask, + bool forScreensaver) override; + bool leave() override; + void setClipboard(ClipboardID, const IClipboard *) override; + void grabClipboard(ClipboardID) override; + void setClipboardDirty(ClipboardID, bool) override; + void keyDown(KeyID, KeyModifierMask, KeyButton, const String &) override; + void keyRepeat(KeyID, KeyModifierMask, SInt32 count, KeyButton, + const String &) override; + void keyUp(KeyID, KeyModifierMask, KeyButton) override; + void mouseDown(ButtonID) override; + void mouseUp(ButtonID) override; + void mouseMove(SInt32 xAbs, SInt32 yAbs) override; + void mouseRelativeMove(SInt32 xRel, SInt32 yRel) override; + void mouseWheel(SInt32 xDelta, SInt32 yDelta) override; + void screensaver(bool activate) override; + void resetOptions() override; + void setOptions(const OptionsList &options) override; + void sendDragInfo(UInt32 fileCount, const char *info, size_t size) override; + void fileChunkSending(UInt8 mark, char *data, size_t dataSize) override; + String getSecureInputApp() const override; + void secureInputNotification(const String &app) const override; protected: - virtual bool parseHandshakeMessage(const UInt8* code); - virtual bool parseMessage(const UInt8* code); + virtual bool parseHandshakeMessage(const UInt8 *code); + virtual bool parseMessage(const UInt8 *code); + + virtual void resetHeartbeatRate(); + virtual void setHeartbeatRate(double rate, double alarm); + virtual void resetHeartbeatTimer(); + virtual void addHeartbeatTimer(); + virtual void removeHeartbeatTimer(); + virtual bool recvClipboard(); - virtual void resetHeartbeatRate(); - virtual void setHeartbeatRate(double rate, double alarm); - virtual void resetHeartbeatTimer(); - virtual void addHeartbeatTimer(); - virtual void removeHeartbeatTimer(); - virtual bool recvClipboard(); private: - void disconnect(); - void removeHandlers(); + void disconnect(); + void removeHandlers(); - void handleData(const Event&, void*); - void handleDisconnect(const Event&, void*); - void handleWriteError(const Event&, void*); - void handleFlatline(const Event&, void*); + void handleData(const Event &, void *); + void handleDisconnect(const Event &, void *); + void handleWriteError(const Event &, void *); + void handleFlatline(const Event &, void *); - bool recvInfo(); - bool recvGrabClipboard(); + bool recvInfo(); + bool recvGrabClipboard(); protected: - struct ClientClipboard { - public: - ClientClipboard(); + struct ClientClipboard { + public: + ClientClipboard(); - public: - Clipboard m_clipboard; - UInt32 m_sequenceNumber; - bool m_dirty; - }; + public: + Clipboard m_clipboard; + UInt32 m_sequenceNumber; + bool m_dirty; + }; - ClientClipboard m_clipboard[kClipboardEnd]; + ClientClipboard m_clipboard[kClipboardEnd]; private: - typedef bool (ClientProxy1_0::*MessageParser)(const UInt8*); + typedef bool (ClientProxy1_0::*MessageParser)(const UInt8 *); - ClientInfo m_info; - double m_heartbeatAlarm; - EventQueueTimer* m_heartbeatTimer; - MessageParser m_parser; - IEventQueue* m_events; + ClientInfo m_info; + double m_heartbeatAlarm; + EventQueueTimer *m_heartbeatTimer; + MessageParser m_parser; + IEventQueue *m_events; }; diff --git a/src/lib/server/ClientProxy1_1.cpp b/src/lib/server/ClientProxy1_1.cpp index 5aaa41bae..f1ea0d30a 100644 --- a/src/lib/server/ClientProxy1_1.cpp +++ b/src/lib/server/ClientProxy1_1.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -16,11 +16,11 @@ * along with this program. If not, see . */ -#include "synergy/AppUtil.h" #include "server/ClientProxy1_1.h" +#include "synergy/AppUtil.h" -#include "synergy/ProtocolUtil.h" #include "base/Log.h" +#include "synergy/ProtocolUtil.h" #include @@ -28,35 +28,34 @@ // ClientProxy1_1 // -ClientProxy1_1::ClientProxy1_1(const String& name, synergy::IStream* stream, IEventQueue* events) : - ClientProxy1_0(name, stream, events) -{ - // do nothing +ClientProxy1_1::ClientProxy1_1(const String &name, synergy::IStream *stream, + IEventQueue *events) + : ClientProxy1_0(name, stream, events) { + // do nothing } -ClientProxy1_1::~ClientProxy1_1() -{ - // do nothing +ClientProxy1_1::~ClientProxy1_1() { + // do nothing } -void -ClientProxy1_1::keyDown(KeyID key, KeyModifierMask mask, KeyButton button, const String&) -{ - LOG((CLOG_DEBUG1 "send key down to \"%s\" id=%d, mask=0x%04x, button=0x%04x", getName().c_str(), key, mask, button)); - ProtocolUtil::writef(getStream(), kMsgDKeyDown, key, mask, button); +void ClientProxy1_1::keyDown(KeyID key, KeyModifierMask mask, KeyButton button, + const String &) { + LOG((CLOG_DEBUG1 "send key down to \"%s\" id=%d, mask=0x%04x, button=0x%04x", + getName().c_str(), key, mask, button)); + ProtocolUtil::writef(getStream(), kMsgDKeyDown, key, mask, button); } -void -ClientProxy1_1::keyRepeat(KeyID key, KeyModifierMask mask, - SInt32 count, KeyButton button, const String& lang) -{ - LOG((CLOG_DEBUG1 "send key repeat to \"%s\" id=%d, mask=0x%04x, count=%d, button=0x%04x, lang=\"%s\"", getName().c_str(), key, mask, count, button, lang.c_str())); - ProtocolUtil::writef(getStream(), kMsgDKeyRepeat, key, mask, count, button, &lang); +void ClientProxy1_1::keyRepeat(KeyID key, KeyModifierMask mask, SInt32 count, + KeyButton button, const String &lang) { + LOG((CLOG_DEBUG1 "send key repeat to \"%s\" id=%d, mask=0x%04x, count=%d, " + "button=0x%04x, lang=\"%s\"", + getName().c_str(), key, mask, count, button, lang.c_str())); + ProtocolUtil::writef(getStream(), kMsgDKeyRepeat, key, mask, count, button, + &lang); } -void -ClientProxy1_1::keyUp(KeyID key, KeyModifierMask mask, KeyButton button) -{ - LOG((CLOG_DEBUG1 "send key up to \"%s\" id=%d, mask=0x%04x, button=0x%04x", getName().c_str(), key, mask, button)); - ProtocolUtil::writef(getStream(), kMsgDKeyUp, key, mask, button); +void ClientProxy1_1::keyUp(KeyID key, KeyModifierMask mask, KeyButton button) { + LOG((CLOG_DEBUG1 "send key up to \"%s\" id=%d, mask=0x%04x, button=0x%04x", + getName().c_str(), key, mask, button)); + ProtocolUtil::writef(getStream(), kMsgDKeyUp, key, mask, button); } diff --git a/src/lib/server/ClientProxy1_1.h b/src/lib/server/ClientProxy1_1.h index 8e026ed64..9c07f5ff7 100644 --- a/src/lib/server/ClientProxy1_1.h +++ b/src/lib/server/ClientProxy1_1.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -23,12 +23,13 @@ //! Proxy for client implementing protocol version 1.1 class ClientProxy1_1 : public ClientProxy1_0 { public: - ClientProxy1_1(const String& name, synergy::IStream* adoptedStream, IEventQueue* events); - ~ClientProxy1_1(); + ClientProxy1_1(const String &name, synergy::IStream *adoptedStream, + IEventQueue *events); + ~ClientProxy1_1(); - // IClient overrides - virtual void keyDown(KeyID, KeyModifierMask, KeyButton, const String&); - virtual void keyRepeat(KeyID, KeyModifierMask, - SInt32 count, KeyButton, const String&); - virtual void keyUp(KeyID, KeyModifierMask, KeyButton); + // IClient overrides + virtual void keyDown(KeyID, KeyModifierMask, KeyButton, const String &); + virtual void keyRepeat(KeyID, KeyModifierMask, SInt32 count, KeyButton, + const String &); + virtual void keyUp(KeyID, KeyModifierMask, KeyButton); }; diff --git a/src/lib/server/ClientProxy1_2.cpp b/src/lib/server/ClientProxy1_2.cpp index d6aca0f41..24bedc684 100644 --- a/src/lib/server/ClientProxy1_2.cpp +++ b/src/lib/server/ClientProxy1_2.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -18,27 +18,25 @@ #include "server/ClientProxy1_2.h" -#include "synergy/ProtocolUtil.h" #include "base/Log.h" +#include "synergy/ProtocolUtil.h" // // ClientProxy1_1 // -ClientProxy1_2::ClientProxy1_2(const String& name, synergy::IStream* stream, IEventQueue* events) : - ClientProxy1_1(name, stream, events) -{ - // do nothing +ClientProxy1_2::ClientProxy1_2(const String &name, synergy::IStream *stream, + IEventQueue *events) + : ClientProxy1_1(name, stream, events) { + // do nothing } -ClientProxy1_2::~ClientProxy1_2() -{ - // do nothing +ClientProxy1_2::~ClientProxy1_2() { + // do nothing } -void -ClientProxy1_2::mouseRelativeMove(SInt32 xRel, SInt32 yRel) -{ - LOG((CLOG_DEBUG2 "send mouse relative move to \"%s\" %d,%d", getName().c_str(), xRel, yRel)); - ProtocolUtil::writef(getStream(), kMsgDMouseRelMove, xRel, yRel); +void ClientProxy1_2::mouseRelativeMove(SInt32 xRel, SInt32 yRel) { + LOG((CLOG_DEBUG2 "send mouse relative move to \"%s\" %d,%d", + getName().c_str(), xRel, yRel)); + ProtocolUtil::writef(getStream(), kMsgDMouseRelMove, xRel, yRel); } diff --git a/src/lib/server/ClientProxy1_2.h b/src/lib/server/ClientProxy1_2.h index c54b90d2e..6e7dcef40 100644 --- a/src/lib/server/ClientProxy1_2.h +++ b/src/lib/server/ClientProxy1_2.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 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 LICENSE 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 @@ -25,9 +25,10 @@ class IEventQueue; //! Proxy for client implementing protocol version 1.2 class ClientProxy1_2 : public ClientProxy1_1 { public: - ClientProxy1_2(const String& name, synergy::IStream* adoptedStream, IEventQueue* events); - ~ClientProxy1_2(); + ClientProxy1_2(const String &name, synergy::IStream *adoptedStream, + IEventQueue *events); + ~ClientProxy1_2(); - // IClient overrides - virtual void mouseRelativeMove(SInt32 xRel, SInt32 yRel); + // IClient overrides + virtual void mouseRelativeMove(SInt32 xRel, SInt32 yRel); }; diff --git a/src/lib/server/ClientProxy1_3.cpp b/src/lib/server/ClientProxy1_3.cpp index 9f923595e..dc383bed4 100644 --- a/src/lib/server/ClientProxy1_3.cpp +++ b/src/lib/server/ClientProxy1_3.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2006 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 LICENSE 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 @@ -18,10 +18,10 @@ #include "server/ClientProxy1_3.h" -#include "synergy/ProtocolUtil.h" -#include "base/Log.h" #include "base/IEventQueue.h" +#include "base/Log.h" #include "base/TMethodEventJob.h" +#include "synergy/ProtocolUtil.h" #include #include @@ -30,100 +30,77 @@ // ClientProxy1_3 // -ClientProxy1_3::ClientProxy1_3(const String& name, synergy::IStream* stream, IEventQueue* events) : - ClientProxy1_2(name, stream, events), - m_keepAliveRate(kKeepAliveRate), - m_keepAliveTimer(NULL), - m_events(events) -{ - setHeartbeatRate(kKeepAliveRate, kKeepAliveRate * kKeepAlivesUntilDeath); +ClientProxy1_3::ClientProxy1_3(const String &name, synergy::IStream *stream, + IEventQueue *events) + : ClientProxy1_2(name, stream, events), m_keepAliveRate(kKeepAliveRate), + m_keepAliveTimer(NULL), m_events(events) { + setHeartbeatRate(kKeepAliveRate, kKeepAliveRate * kKeepAlivesUntilDeath); } -ClientProxy1_3::~ClientProxy1_3() -{ - // cannot do this in superclass or our override wouldn't get called - removeHeartbeatTimer(); +ClientProxy1_3::~ClientProxy1_3() { + // cannot do this in superclass or our override wouldn't get called + removeHeartbeatTimer(); } -void -ClientProxy1_3::mouseWheel(SInt32 xDelta, SInt32 yDelta) -{ - LOG((CLOG_DEBUG2 "send mouse wheel to \"%s\" %+d,%+d", getName().c_str(), xDelta, yDelta)); - ProtocolUtil::writef(getStream(), kMsgDMouseWheel, xDelta, yDelta); +void ClientProxy1_3::mouseWheel(SInt32 xDelta, SInt32 yDelta) { + LOG((CLOG_DEBUG2 "send mouse wheel to \"%s\" %+d,%+d", getName().c_str(), + xDelta, yDelta)); + ProtocolUtil::writef(getStream(), kMsgDMouseWheel, xDelta, yDelta); } -bool -ClientProxy1_3::parseMessage(const UInt8* code) -{ - // process message - if (memcmp(code, kMsgCKeepAlive, 4) == 0) { - // reset alarm - resetHeartbeatTimer(); - return true; - } - else { - return ClientProxy1_2::parseMessage(code); - } +bool ClientProxy1_3::parseMessage(const UInt8 *code) { + // process message + if (memcmp(code, kMsgCKeepAlive, 4) == 0) { + // reset alarm + resetHeartbeatTimer(); + return true; + } else { + return ClientProxy1_2::parseMessage(code); + } } -void -ClientProxy1_3::resetHeartbeatRate() -{ - setHeartbeatRate(kKeepAliveRate, kKeepAliveRate * kKeepAlivesUntilDeath); +void ClientProxy1_3::resetHeartbeatRate() { + setHeartbeatRate(kKeepAliveRate, kKeepAliveRate * kKeepAlivesUntilDeath); } -void -ClientProxy1_3::setHeartbeatRate(double rate, double) -{ - m_keepAliveRate = rate; - ClientProxy1_2::setHeartbeatRate(rate, rate * kKeepAlivesUntilDeath); +void ClientProxy1_3::setHeartbeatRate(double rate, double) { + m_keepAliveRate = rate; + ClientProxy1_2::setHeartbeatRate(rate, rate * kKeepAlivesUntilDeath); } -void -ClientProxy1_3::resetHeartbeatTimer() -{ - // reset the alarm but not the keep alive timer - ClientProxy1_2::removeHeartbeatTimer(); - ClientProxy1_2::addHeartbeatTimer(); +void ClientProxy1_3::resetHeartbeatTimer() { + // reset the alarm but not the keep alive timer + ClientProxy1_2::removeHeartbeatTimer(); + ClientProxy1_2::addHeartbeatTimer(); } -void -ClientProxy1_3::addHeartbeatTimer() -{ - // create and install a timer to periodically send keep alives - if (m_keepAliveRate > 0.0) { - m_keepAliveTimer = m_events->newTimer(m_keepAliveRate, NULL); - m_events->adoptHandler(Event::kTimer, m_keepAliveTimer, - new TMethodEventJob(this, - &ClientProxy1_3::handleKeepAlive, NULL)); - } +void ClientProxy1_3::addHeartbeatTimer() { + // create and install a timer to periodically send keep alives + if (m_keepAliveRate > 0.0) { + m_keepAliveTimer = m_events->newTimer(m_keepAliveRate, NULL); + m_events->adoptHandler(Event::kTimer, m_keepAliveTimer, + new TMethodEventJob( + this, &ClientProxy1_3::handleKeepAlive, NULL)); + } - // superclass does the alarm - ClientProxy1_2::addHeartbeatTimer(); + // superclass does the alarm + ClientProxy1_2::addHeartbeatTimer(); } -void -ClientProxy1_3::removeHeartbeatTimer() -{ - // remove the timer that sends keep alives periodically - if (m_keepAliveTimer != NULL) { - m_events->removeHandler(Event::kTimer, m_keepAliveTimer); - m_events->deleteTimer(m_keepAliveTimer); - m_keepAliveTimer = NULL; - } +void ClientProxy1_3::removeHeartbeatTimer() { + // remove the timer that sends keep alives periodically + if (m_keepAliveTimer != NULL) { + m_events->removeHandler(Event::kTimer, m_keepAliveTimer); + m_events->deleteTimer(m_keepAliveTimer); + m_keepAliveTimer = NULL; + } - // superclass does the alarm - ClientProxy1_2::removeHeartbeatTimer(); + // superclass does the alarm + ClientProxy1_2::removeHeartbeatTimer(); } -void -ClientProxy1_3::handleKeepAlive(const Event&, void*) -{ - keepAlive(); -} +void ClientProxy1_3::handleKeepAlive(const Event &, void *) { keepAlive(); } -void -ClientProxy1_3::keepAlive() -{ - ProtocolUtil::writef(getStream(), kMsgCKeepAlive); +void ClientProxy1_3::keepAlive() { + ProtocolUtil::writef(getStream(), kMsgCKeepAlive); } diff --git a/src/lib/server/ClientProxy1_3.h b/src/lib/server/ClientProxy1_3.h index b6e6d1da5..69a778905 100644 --- a/src/lib/server/ClientProxy1_3.h +++ b/src/lib/server/ClientProxy1_3.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2006 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 LICENSE 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 @@ -23,31 +23,32 @@ //! Proxy for client implementing protocol version 1.3 class ClientProxy1_3 : public ClientProxy1_2 { public: - ClientProxy1_3(const String& name, synergy::IStream* adoptedStream, IEventQueue* events); - ClientProxy1_3(ClientProxy1_3 const &) =delete; - ClientProxy1_3(ClientProxy1_3 &&) =delete; - ~ClientProxy1_3(); + ClientProxy1_3(const String &name, synergy::IStream *adoptedStream, + IEventQueue *events); + ClientProxy1_3(ClientProxy1_3 const &) = delete; + ClientProxy1_3(ClientProxy1_3 &&) = delete; + ~ClientProxy1_3(); - ClientProxy1_3& operator=(ClientProxy1_3 const &) =delete; - ClientProxy1_3& operator=(ClientProxy1_3 &&) =delete; + ClientProxy1_3 &operator=(ClientProxy1_3 const &) = delete; + ClientProxy1_3 &operator=(ClientProxy1_3 &&) = delete; - // IClient overrides - virtual void mouseWheel(SInt32 xDelta, SInt32 yDelta); + // IClient overrides + virtual void mouseWheel(SInt32 xDelta, SInt32 yDelta); - void handleKeepAlive(const Event&, void*); + void handleKeepAlive(const Event &, void *); protected: - // ClientProxy overrides - virtual bool parseMessage(const UInt8* code); - virtual void resetHeartbeatRate(); - virtual void setHeartbeatRate(double rate, double alarm); - virtual void resetHeartbeatTimer(); - virtual void addHeartbeatTimer(); - virtual void removeHeartbeatTimer(); - virtual void keepAlive(); + // ClientProxy overrides + virtual bool parseMessage(const UInt8 *code); + virtual void resetHeartbeatRate(); + virtual void setHeartbeatRate(double rate, double alarm); + virtual void resetHeartbeatTimer(); + virtual void addHeartbeatTimer(); + virtual void removeHeartbeatTimer(); + virtual void keepAlive(); private: - double m_keepAliveRate; - EventQueueTimer* m_keepAliveTimer; - IEventQueue* m_events; + double m_keepAliveRate; + EventQueueTimer *m_keepAliveTimer; + IEventQueue *m_events; }; diff --git a/src/lib/server/ClientProxy1_4.cpp b/src/lib/server/ClientProxy1_4.cpp index 7cfa2042e..c4e9d1bad 100644 --- a/src/lib/server/ClientProxy1_4.cpp +++ b/src/lib/server/ClientProxy1_4.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2011 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 LICENSE 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 @@ -18,11 +18,11 @@ #include "server/ClientProxy1_4.h" +#include "base/IEventQueue.h" +#include "base/Log.h" +#include "base/TMethodEventJob.h" #include "server/Server.h" #include "synergy/ProtocolUtil.h" -#include "base/Log.h" -#include "base/IEventQueue.h" -#include "base/TMethodEventJob.h" #include #include @@ -31,36 +31,26 @@ // ClientProxy1_4 // -ClientProxy1_4::ClientProxy1_4(const String& name, synergy::IStream* stream, Server* server, IEventQueue* events) : - ClientProxy1_3(name, stream, events), m_server(server) -{ - assert(m_server != NULL); +ClientProxy1_4::ClientProxy1_4(const String &name, synergy::IStream *stream, + Server *server, IEventQueue *events) + : ClientProxy1_3(name, stream, events), m_server(server) { + assert(m_server != NULL); } -ClientProxy1_4::~ClientProxy1_4() -{ +ClientProxy1_4::~ClientProxy1_4() {} + +void ClientProxy1_4::keyDown(KeyID key, KeyModifierMask mask, KeyButton button, + const String &lang) { + ClientProxy1_3::keyDown(key, mask, button, lang); } -void -ClientProxy1_4::keyDown(KeyID key, KeyModifierMask mask, KeyButton button, const String& lang) -{ - ClientProxy1_3::keyDown(key, mask, button, lang); +void ClientProxy1_4::keyRepeat(KeyID key, KeyModifierMask mask, SInt32 count, + KeyButton button, const String &lang) { + ClientProxy1_3::keyRepeat(key, mask, count, button, lang); } -void -ClientProxy1_4::keyRepeat(KeyID key, KeyModifierMask mask, SInt32 count, KeyButton button, const String& lang) -{ - ClientProxy1_3::keyRepeat(key, mask, count, button, lang); +void ClientProxy1_4::keyUp(KeyID key, KeyModifierMask mask, KeyButton button) { + ClientProxy1_3::keyUp(key, mask, button); } -void -ClientProxy1_4::keyUp(KeyID key, KeyModifierMask mask, KeyButton button) -{ - ClientProxy1_3::keyUp(key, mask, button); -} - -void -ClientProxy1_4::keepAlive() -{ - ClientProxy1_3::keepAlive(); -} +void ClientProxy1_4::keepAlive() { ClientProxy1_3::keepAlive(); } diff --git a/src/lib/server/ClientProxy1_4.h b/src/lib/server/ClientProxy1_4.h index 6265a7dd5..7fb120d7c 100644 --- a/src/lib/server/ClientProxy1_4.h +++ b/src/lib/server/ClientProxy1_4.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2011 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 LICENSE 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 @@ -25,23 +25,25 @@ class Server; //! Proxy for client implementing protocol version 1.4 class ClientProxy1_4 : public ClientProxy1_3 { public: - ClientProxy1_4(const String& name, synergy::IStream* adoptedStream, Server* server, IEventQueue* events); - ~ClientProxy1_4(); + ClientProxy1_4(const String &name, synergy::IStream *adoptedStream, + Server *server, IEventQueue *events); + ~ClientProxy1_4(); - //! @name accessors - //@{ + //! @name accessors + //@{ - //! get server pointer - Server* getServer() { return m_server; } + //! get server pointer + Server *getServer() { return m_server; } - //@} + //@} - // IClient overrides - virtual void keyDown(KeyID key, KeyModifierMask mask, KeyButton button, const String&); - virtual void keyRepeat(KeyID key, KeyModifierMask mask, SInt32 count, KeyButton button, - const String& lang); - virtual void keyUp(KeyID key, KeyModifierMask mask, KeyButton button); - virtual void keepAlive(); + // IClient overrides + virtual void keyDown(KeyID key, KeyModifierMask mask, KeyButton button, + const String &); + virtual void keyRepeat(KeyID key, KeyModifierMask mask, SInt32 count, + KeyButton button, const String &lang); + virtual void keyUp(KeyID key, KeyModifierMask mask, KeyButton button); + virtual void keepAlive(); - Server* m_server; + Server *m_server; }; diff --git a/src/lib/server/ClientProxy1_5.cpp b/src/lib/server/ClientProxy1_5.cpp index 91560c084..912f29434 100644 --- a/src/lib/server/ClientProxy1_5.cpp +++ b/src/lib/server/ClientProxy1_5.cpp @@ -1,11 +1,11 @@ /* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2013-2016 Symless Ltd. - * + * * 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 LICENSE 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 @@ -17,13 +17,13 @@ #include "server/ClientProxy1_5.h" +#include "base/Log.h" +#include "base/TMethodEventJob.h" +#include "io/IStream.h" #include "server/Server.h" #include "synergy/FileChunk.h" -#include "synergy/StreamChunker.h" #include "synergy/ProtocolUtil.h" -#include "io/IStream.h" -#include "base/TMethodEventJob.h" -#include "base/Log.h" +#include "synergy/StreamChunker.h" #include @@ -31,80 +31,63 @@ // ClientProxy1_5 // -ClientProxy1_5::ClientProxy1_5(const String& name, synergy::IStream* stream, Server* server, IEventQueue* events) : - ClientProxy1_4(name, stream, server, events), - m_events(events) -{ +ClientProxy1_5::ClientProxy1_5(const String &name, synergy::IStream *stream, + Server *server, IEventQueue *events) + : ClientProxy1_4(name, stream, server, events), m_events(events) { - m_events->adoptHandler(m_events->forFile().keepAlive(), - this, - new TMethodEventJob(this, - &ClientProxy1_3::handleKeepAlive, NULL)); + m_events->adoptHandler(m_events->forFile().keepAlive(), this, + new TMethodEventJob( + this, &ClientProxy1_3::handleKeepAlive, NULL)); } -ClientProxy1_5::~ClientProxy1_5() -{ - m_events->removeHandler(m_events->forFile().keepAlive(), this); +ClientProxy1_5::~ClientProxy1_5() { + m_events->removeHandler(m_events->forFile().keepAlive(), this); } -void -ClientProxy1_5::sendDragInfo(UInt32 fileCount, const char* info, size_t size) -{ - String data(info, size); +void ClientProxy1_5::sendDragInfo(UInt32 fileCount, const char *info, + size_t size) { + String data(info, size); - ProtocolUtil::writef(getStream(), kMsgDDragInfo, fileCount, &data); + ProtocolUtil::writef(getStream(), kMsgDDragInfo, fileCount, &data); } -void -ClientProxy1_5::fileChunkSending(UInt8 mark, char* data, size_t dataSize) -{ - FileChunk::send(getStream(), mark, data, dataSize); +void ClientProxy1_5::fileChunkSending(UInt8 mark, char *data, size_t dataSize) { + FileChunk::send(getStream(), mark, data, dataSize); } -bool -ClientProxy1_5::parseMessage(const UInt8* code) -{ - if (memcmp(code, kMsgDFileTransfer, 4) == 0) { - fileChunkReceived(); +bool ClientProxy1_5::parseMessage(const UInt8 *code) { + if (memcmp(code, kMsgDFileTransfer, 4) == 0) { + fileChunkReceived(); + } else if (memcmp(code, kMsgDDragInfo, 4) == 0) { + dragInfoReceived(); + } else { + return ClientProxy1_4::parseMessage(code); + } + + return true; +} + +void ClientProxy1_5::fileChunkReceived() { + Server *server = getServer(); + int result = FileChunk::assemble(getStream(), server->getReceivedFileData(), + server->getExpectedFileSize()); + + if (result == kFinish) { + m_events->addEvent( + Event(m_events->forFile().fileRecieveCompleted(), server)); + } else if (result == kStart) { + if (server->getFakeDragFileList().size() > 0) { + String filename = server->getFakeDragFileList().at(0).getFilename(); + LOG((CLOG_DEBUG "start receiving %s", filename.c_str())); } - else if (memcmp(code, kMsgDDragInfo, 4) == 0) { - dragInfoReceived(); - } - else { - return ClientProxy1_4::parseMessage(code); - } - - return true; + } } -void -ClientProxy1_5::fileChunkReceived() -{ - Server* server = getServer(); - int result = FileChunk::assemble( - getStream(), - server->getReceivedFileData(), - server->getExpectedFileSize()); - +void ClientProxy1_5::dragInfoReceived() { + // parse + UInt32 fileNum = 0; + String content; + ProtocolUtil::readf(getStream(), kMsgDDragInfo + 4, &fileNum, &content); - if (result == kFinish) { - m_events->addEvent(Event(m_events->forFile().fileRecieveCompleted(), server)); - } - else if (result == kStart) { - if (server->getFakeDragFileList().size() > 0) { - String filename = server->getFakeDragFileList().at(0).getFilename(); - LOG((CLOG_DEBUG "start receiving %s", filename.c_str())); - } - } -} - -void -ClientProxy1_5::dragInfoReceived() -{ - // parse - UInt32 fileNum = 0; - String content; - ProtocolUtil::readf(getStream(), kMsgDDragInfo + 4, &fileNum, &content); - - m_server->dragInfoReceived(fileNum, content); + m_server->dragInfoReceived(fileNum, content); } diff --git a/src/lib/server/ClientProxy1_5.h b/src/lib/server/ClientProxy1_5.h index 9a63f059a..587ab0f9e 100644 --- a/src/lib/server/ClientProxy1_5.h +++ b/src/lib/server/ClientProxy1_5.h @@ -1,11 +1,11 @@ /* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2013-2016 Symless Ltd. - * + * * 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 LICENSE 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 @@ -17,9 +17,9 @@ #pragma once -#include "server/ClientProxy1_4.h" #include "base/Stopwatch.h" #include "common/stdvector.h" +#include "server/ClientProxy1_4.h" class Server; class IEventQueue; @@ -27,20 +27,21 @@ class IEventQueue; //! Proxy for client implementing protocol version 1.5 class ClientProxy1_5 : public ClientProxy1_4 { public: - ClientProxy1_5(const String& name, synergy::IStream* adoptedStream, Server* server, IEventQueue* events); - ClientProxy1_5(ClientProxy1_5 const &) =delete; - ClientProxy1_5(ClientProxy1_5 &&) =delete; - ~ClientProxy1_5(); + ClientProxy1_5(const String &name, synergy::IStream *adoptedStream, + Server *server, IEventQueue *events); + ClientProxy1_5(ClientProxy1_5 const &) = delete; + ClientProxy1_5(ClientProxy1_5 &&) = delete; + ~ClientProxy1_5(); - ClientProxy1_5& operator=(ClientProxy1_5 const &) =delete; - ClientProxy1_5& operator=(ClientProxy1_5 &&) =delete; + ClientProxy1_5 &operator=(ClientProxy1_5 const &) = delete; + ClientProxy1_5 &operator=(ClientProxy1_5 &&) = delete; - virtual void sendDragInfo(UInt32 fileCount, const char* info, size_t size); - virtual void fileChunkSending(UInt8 mark, char* data, size_t dataSize); - virtual bool parseMessage(const UInt8* code); - void fileChunkReceived(); - void dragInfoReceived(); + virtual void sendDragInfo(UInt32 fileCount, const char *info, size_t size); + virtual void fileChunkSending(UInt8 mark, char *data, size_t dataSize); + virtual bool parseMessage(const UInt8 *code); + void fileChunkReceived(); + void dragInfoReceived(); private: - IEventQueue* m_events; + IEventQueue *m_events; }; diff --git a/src/lib/server/ClientProxy1_6.cpp b/src/lib/server/ClientProxy1_6.cpp index 6e649fe86..805d90fb1 100644 --- a/src/lib/server/ClientProxy1_6.cpp +++ b/src/lib/server/ClientProxy1_6.cpp @@ -1,11 +1,11 @@ /* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2015-2016 Symless Ltd. - * + * * 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 LICENSE 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 @@ -17,84 +17,74 @@ #include "server/ClientProxy1_6.h" +#include "base/Log.h" +#include "base/TMethodEventJob.h" +#include "io/IStream.h" #include "server/Server.h" +#include "synergy/ClipboardChunk.h" #include "synergy/ProtocolUtil.h" #include "synergy/StreamChunker.h" -#include "synergy/ClipboardChunk.h" -#include "io/IStream.h" -#include "base/TMethodEventJob.h" -#include "base/Log.h" // // ClientProxy1_6 // -ClientProxy1_6::ClientProxy1_6(const String& name, synergy::IStream* stream, Server* server, IEventQueue* events) : - ClientProxy1_5(name, stream, server, events), - m_events(events) -{ - m_events->adoptHandler(m_events->forClipboard().clipboardSending(), - this, - new TMethodEventJob(this, - &ClientProxy1_6::handleClipboardSendingEvent)); +ClientProxy1_6::ClientProxy1_6(const String &name, synergy::IStream *stream, + Server *server, IEventQueue *events) + : ClientProxy1_5(name, stream, server, events), m_events(events) { + m_events->adoptHandler( + m_events->forClipboard().clipboardSending(), this, + new TMethodEventJob( + this, &ClientProxy1_6::handleClipboardSendingEvent)); } -ClientProxy1_6::~ClientProxy1_6() -{ +ClientProxy1_6::~ClientProxy1_6() {} + +void ClientProxy1_6::setClipboard(ClipboardID id, const IClipboard *clipboard) { + // ignore if this clipboard is already clean + if (m_clipboard[id].m_dirty) { + // this clipboard is now clean + m_clipboard[id].m_dirty = false; + Clipboard::copy(&m_clipboard[id].m_clipboard, clipboard); + + String data = m_clipboard[id].m_clipboard.marshall(); + + size_t size = data.size(); + LOG((CLOG_DEBUG "sending clipboard %d to \"%s\"", id, getName().c_str())); + + StreamChunker::sendClipboard(data, size, id, 0, m_events, this); + } } -void -ClientProxy1_6::setClipboard(ClipboardID id, const IClipboard* clipboard) -{ - // ignore if this clipboard is already clean - if (m_clipboard[id].m_dirty) { - // this clipboard is now clean - m_clipboard[id].m_dirty = false; - Clipboard::copy(&m_clipboard[id].m_clipboard, clipboard); - - String data = m_clipboard[id].m_clipboard.marshall(); - - size_t size = data.size(); - LOG((CLOG_DEBUG "sending clipboard %d to \"%s\"", id, getName().c_str())); - - StreamChunker::sendClipboard(data, size, id, 0, m_events, this); - } +void ClientProxy1_6::handleClipboardSendingEvent(const Event &event, void *) { + ClipboardChunk::send(getStream(), event.getDataObject()); } -void -ClientProxy1_6::handleClipboardSendingEvent(const Event& event, void*) -{ - ClipboardChunk::send(getStream(), event.getDataObject()); -} - -bool -ClientProxy1_6::recvClipboard() -{ - // parse message - static String dataCached; - ClipboardID id; - UInt32 seq; - - int r = ClipboardChunk::assemble(getStream(), dataCached, id, seq); - - if (r == kStart) { - size_t size = ClipboardChunk::getExpectedSize(); - LOG((CLOG_DEBUG "receiving clipboard %d size=%d", id, size)); - } - else if (r == kFinish) { - LOG((CLOG_DEBUG "received client \"%s\" clipboard %d seqnum=%d, size=%d", - getName().c_str(), id, seq, dataCached.size())); - // save clipboard - m_clipboard[id].m_clipboard.unmarshall(dataCached, 0); - m_clipboard[id].m_sequenceNumber = seq; - - // notify - ClipboardInfo* info = new ClipboardInfo; - info->m_id = id; - info->m_sequenceNumber = seq; - m_events->addEvent(Event(m_events->forClipboard().clipboardChanged(), - getEventTarget(), info)); - } - - return true; +bool ClientProxy1_6::recvClipboard() { + // parse message + static String dataCached; + ClipboardID id; + UInt32 seq; + + int r = ClipboardChunk::assemble(getStream(), dataCached, id, seq); + + if (r == kStart) { + size_t size = ClipboardChunk::getExpectedSize(); + LOG((CLOG_DEBUG "receiving clipboard %d size=%d", id, size)); + } else if (r == kFinish) { + LOG((CLOG_DEBUG "received client \"%s\" clipboard %d seqnum=%d, size=%d", + getName().c_str(), id, seq, dataCached.size())); + // save clipboard + m_clipboard[id].m_clipboard.unmarshall(dataCached, 0); + m_clipboard[id].m_sequenceNumber = seq; + + // notify + ClipboardInfo *info = new ClipboardInfo; + info->m_id = id; + info->m_sequenceNumber = seq; + m_events->addEvent(Event(m_events->forClipboard().clipboardChanged(), + getEventTarget(), info)); + } + + return true; } diff --git a/src/lib/server/ClientProxy1_6.h b/src/lib/server/ClientProxy1_6.h index 395365e6b..5e11a20f3 100644 --- a/src/lib/server/ClientProxy1_6.h +++ b/src/lib/server/ClientProxy1_6.h @@ -1,11 +1,11 @@ /* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2015-2016 Symless Ltd. - * + * * 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 LICENSE 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 @@ -25,15 +25,16 @@ class IEventQueue; //! Proxy for client implementing protocol version 1.6 class ClientProxy1_6 : public ClientProxy1_5 { public: - ClientProxy1_6(const String& name, synergy::IStream* adoptedStream, Server* server, IEventQueue* events); - ~ClientProxy1_6(); + ClientProxy1_6(const String &name, synergy::IStream *adoptedStream, + Server *server, IEventQueue *events); + ~ClientProxy1_6(); - virtual void setClipboard(ClipboardID id, const IClipboard* clipboard); - virtual bool recvClipboard(); + virtual void setClipboard(ClipboardID id, const IClipboard *clipboard); + virtual bool recvClipboard(); private: - void handleClipboardSendingEvent(const Event&, void*); + void handleClipboardSendingEvent(const Event &, void *); private: - IEventQueue* m_events; + IEventQueue *m_events; }; diff --git a/src/lib/server/ClientProxy1_7.cpp b/src/lib/server/ClientProxy1_7.cpp index bd51778e8..445473a94 100644 --- a/src/lib/server/ClientProxy1_7.cpp +++ b/src/lib/server/ClientProxy1_7.cpp @@ -1,11 +1,11 @@ /* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2015-2016 Symless Ltd. - * + * * 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 LICENSE 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 @@ -16,26 +16,22 @@ */ #include "server/ClientProxy1_7.h" +#include "base/Log.h" +#include "base/TMethodEventJob.h" #include "server/Server.h" #include "synergy/AppUtil.h" #include "synergy/ProtocolUtil.h" -#include "base/TMethodEventJob.h" -#include "base/Log.h" // // ClientProxy1_7 // -ClientProxy1_7::ClientProxy1_7(const String& name, synergy::IStream* stream, Server* server, IEventQueue* events) : - ClientProxy1_6(name, stream, server, events), - m_events(events) -{ +ClientProxy1_7::ClientProxy1_7(const String &name, synergy::IStream *stream, + Server *server, IEventQueue *events) + : ClientProxy1_6(name, stream, server, events), m_events(events) {} -} - -void -ClientProxy1_7::secureInputNotification(const String& app) const -{ - LOG((CLOG_DEBUG2 "send secure input notification to \"%s\" %s", getName().c_str(), app.c_str())); - ProtocolUtil::writef(getStream(), kMsgDSecureInputNotification, &app); +void ClientProxy1_7::secureInputNotification(const String &app) const { + LOG((CLOG_DEBUG2 "send secure input notification to \"%s\" %s", + getName().c_str(), app.c_str())); + ProtocolUtil::writef(getStream(), kMsgDSecureInputNotification, &app); } diff --git a/src/lib/server/ClientProxy1_7.h b/src/lib/server/ClientProxy1_7.h index 04343edb7..f525dcc5f 100644 --- a/src/lib/server/ClientProxy1_7.h +++ b/src/lib/server/ClientProxy1_7.h @@ -1,11 +1,11 @@ /* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2015-2016 Symless Ltd. - * + * * 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 LICENSE 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 @@ -22,12 +22,12 @@ //! Proxy for client implementing protocol version 1.7 class ClientProxy1_7 : public ClientProxy1_6 { public: - ClientProxy1_7(const String& name, synergy::IStream* adoptedStream, Server* server, IEventQueue* events); - ~ClientProxy1_7() override = default; + ClientProxy1_7(const String &name, synergy::IStream *adoptedStream, + Server *server, IEventQueue *events); + ~ClientProxy1_7() override = default; - void secureInputNotification(const String& app) const override; + void secureInputNotification(const String &app) const override; private: - - IEventQueue* m_events; + IEventQueue *m_events; }; diff --git a/src/lib/server/ClientProxy1_8.cpp b/src/lib/server/ClientProxy1_8.cpp index 296fa974d..4a8496d12 100644 --- a/src/lib/server/ClientProxy1_8.cpp +++ b/src/lib/server/ClientProxy1_8.cpp @@ -20,30 +20,31 @@ #include "ClientProxy1_8.h" - -ClientProxy1_8::ClientProxy1_8(const String& name, synergy::IStream* adoptedStream, Server* server, IEventQueue* events) : - ClientProxy1_7(name, adoptedStream, server, events) -{ - synchronizeLanguages(); +ClientProxy1_8::ClientProxy1_8(const String &name, + synergy::IStream *adoptedStream, Server *server, + IEventQueue *events) + : ClientProxy1_7(name, adoptedStream, server, events) { + synchronizeLanguages(); } -void ClientProxy1_8::synchronizeLanguages() const -{ - synergy::languages::LanguageManager languageManager; - auto localLanguages = languageManager.getSerializedLocalLanguages(); - if (!localLanguages.empty()) { - LOG((CLOG_DEBUG1 "send server languages to the client: %s", localLanguages.c_str())); - ProtocolUtil::writef(getStream(), kMsgDLanguageSynchronisation, &localLanguages); - } - else { - LOG((CLOG_ERR "failed to read server languages")); - } +void ClientProxy1_8::synchronizeLanguages() const { + synergy::languages::LanguageManager languageManager; + auto localLanguages = languageManager.getSerializedLocalLanguages(); + if (!localLanguages.empty()) { + LOG((CLOG_DEBUG1 "send server languages to the client: %s", + localLanguages.c_str())); + ProtocolUtil::writef(getStream(), kMsgDLanguageSynchronisation, + &localLanguages); + } else { + LOG((CLOG_ERR "failed to read server languages")); + } } -void -ClientProxy1_8::keyDown(KeyID key, KeyModifierMask mask, KeyButton button, const String& language) -{ - LOG((CLOG_DEBUG1 "send key down to \"%s\" id=%d, mask=0x%04x, button=0x%04x, language=%s", getName().c_str(), key, mask, button, language.c_str())); - ProtocolUtil::writef(getStream(), kMsgDKeyDownLang, key, mask, button, &language); +void ClientProxy1_8::keyDown(KeyID key, KeyModifierMask mask, KeyButton button, + const String &language) { + LOG((CLOG_DEBUG1 + "send key down to \"%s\" id=%d, mask=0x%04x, button=0x%04x, language=%s", + getName().c_str(), key, mask, button, language.c_str())); + ProtocolUtil::writef(getStream(), kMsgDKeyDownLang, key, mask, button, + &language); } - diff --git a/src/lib/server/ClientProxy1_8.h b/src/lib/server/ClientProxy1_8.h index 2598bfa25..2777b90e2 100644 --- a/src/lib/server/ClientProxy1_8.h +++ b/src/lib/server/ClientProxy1_8.h @@ -19,17 +19,16 @@ #include "server/ClientProxy1_7.h" -class ClientProxy1_8 : public ClientProxy1_7 -{ +class ClientProxy1_8 : public ClientProxy1_7 { public: - ClientProxy1_8(const String& name, synergy::IStream* adoptedStream, Server* server, IEventQueue* events); - ~ClientProxy1_8() override = default; + ClientProxy1_8(const String &name, synergy::IStream *adoptedStream, + Server *server, IEventQueue *events); + ~ClientProxy1_8() override = default; - void keyDown(KeyID, KeyModifierMask, KeyButton, const String&) override; + void keyDown(KeyID, KeyModifierMask, KeyButton, const String &) override; private: - void synchronizeLanguages() const; - + void synchronizeLanguages() const; }; #endif // SERVER_CLIENTPROXY1_8_H diff --git a/src/lib/server/ClientProxyUnknown.cpp b/src/lib/server/ClientProxyUnknown.cpp index 12d8eb23b..809264b9d 100644 --- a/src/lib/server/ClientProxyUnknown.cpp +++ b/src/lib/server/ClientProxyUnknown.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 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 LICENSE 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 @@ -18,7 +18,11 @@ #include "server/ClientProxyUnknown.h" -#include "server/Server.h" +#include "base/IEventQueue.h" +#include "base/Log.h" +#include "base/TMethodEventJob.h" +#include "io/IStream.h" +#include "io/XIO.h" #include "server/ClientProxy1_0.h" #include "server/ClientProxy1_1.h" #include "server/ClientProxy1_2.h" @@ -28,285 +32,244 @@ #include "server/ClientProxy1_6.h" #include "server/ClientProxy1_7.h" #include "server/ClientProxy1_8.h" -#include "synergy/protocol_types.h" -#include "synergy/ProtocolUtil.h" +#include "server/Server.h" #include "synergy/AppUtil.h" +#include "synergy/ProtocolUtil.h" #include "synergy/XSynergy.h" -#include "io/IStream.h" -#include "io/XIO.h" -#include "base/Log.h" -#include "base/IEventQueue.h" -#include "base/TMethodEventJob.h" +#include "synergy/protocol_types.h" -#include #include +#include // // ClientProxyUnknown // -ClientProxyUnknown::ClientProxyUnknown(synergy::IStream* stream, double timeout, Server* server, IEventQueue* events) : - m_stream(stream), - m_proxy(NULL), - m_ready(false), - m_server(server), - m_events(events) -{ - assert(m_server != NULL); +ClientProxyUnknown::ClientProxyUnknown(synergy::IStream *stream, double timeout, + Server *server, IEventQueue *events) + : m_stream(stream), m_proxy(NULL), m_ready(false), m_server(server), + m_events(events) { + assert(m_server != NULL); - m_events->adoptHandler(Event::kTimer, this, - new TMethodEventJob(this, - &ClientProxyUnknown::handleTimeout, NULL)); - m_timer = m_events->newOneShotTimer(timeout, this); - addStreamHandlers(); + m_events->adoptHandler(Event::kTimer, this, + new TMethodEventJob( + this, &ClientProxyUnknown::handleTimeout, NULL)); + m_timer = m_events->newOneShotTimer(timeout, this); + addStreamHandlers(); - LOG((CLOG_DEBUG1 "saying hello")); - ProtocolUtil::writef(m_stream, kMsgHello, kProtocolMajorVersion, kProtocolMinorVersion); + LOG((CLOG_DEBUG1 "saying hello")); + ProtocolUtil::writef(m_stream, kMsgHello, kProtocolMajorVersion, + kProtocolMinorVersion); } -ClientProxyUnknown::~ClientProxyUnknown() -{ +ClientProxyUnknown::~ClientProxyUnknown() { + removeHandlers(); + removeTimer(); + delete m_stream; + delete m_proxy; +} + +ClientProxy *ClientProxyUnknown::orphanClientProxy() { + if (m_ready) { removeHandlers(); - removeTimer(); - delete m_stream; - delete m_proxy; -} - -ClientProxy* -ClientProxyUnknown::orphanClientProxy() -{ - if (m_ready) { - removeHandlers(); - ClientProxy* proxy = m_proxy; - m_proxy = NULL; - return proxy; - } - else { - return NULL; - } -} - -void -ClientProxyUnknown::sendSuccess() -{ - m_ready = true; - removeTimer(); - m_events->addEvent(Event(m_events->forClientProxyUnknown().success(), this)); -} - -void -ClientProxyUnknown::sendFailure() -{ - delete m_proxy; + ClientProxy *proxy = m_proxy; m_proxy = NULL; - m_ready = false; + return proxy; + } else { + return NULL; + } +} + +void ClientProxyUnknown::sendSuccess() { + m_ready = true; + removeTimer(); + m_events->addEvent(Event(m_events->forClientProxyUnknown().success(), this)); +} + +void ClientProxyUnknown::sendFailure() { + delete m_proxy; + m_proxy = NULL; + m_ready = false; + removeHandlers(); + removeTimer(); + m_events->addEvent(Event(m_events->forClientProxyUnknown().failure(), this)); +} + +void ClientProxyUnknown::addStreamHandlers() { + assert(m_stream != NULL); + + m_events->adoptHandler(m_events->forIStream().inputReady(), + m_stream->getEventTarget(), + new TMethodEventJob( + this, &ClientProxyUnknown::handleData)); + m_events->adoptHandler(m_events->forIStream().outputError(), + m_stream->getEventTarget(), + new TMethodEventJob( + this, &ClientProxyUnknown::handleWriteError)); + m_events->adoptHandler(m_events->forIStream().inputShutdown(), + m_stream->getEventTarget(), + new TMethodEventJob( + this, &ClientProxyUnknown::handleDisconnect)); + m_events->adoptHandler(m_events->forIStream().outputShutdown(), + m_stream->getEventTarget(), + new TMethodEventJob( + this, &ClientProxyUnknown::handleWriteError)); +} + +void ClientProxyUnknown::addProxyHandlers() { + assert(m_proxy != NULL); + + m_events->adoptHandler(m_events->forClientProxy().ready(), m_proxy, + new TMethodEventJob( + this, &ClientProxyUnknown::handleReady)); + m_events->adoptHandler(m_events->forClientProxy().disconnected(), m_proxy, + new TMethodEventJob( + this, &ClientProxyUnknown::handleDisconnect)); +} + +void ClientProxyUnknown::removeHandlers() { + if (m_stream != NULL) { + m_events->removeHandler(m_events->forIStream().inputReady(), + m_stream->getEventTarget()); + m_events->removeHandler(m_events->forIStream().outputError(), + m_stream->getEventTarget()); + m_events->removeHandler(m_events->forIStream().inputShutdown(), + m_stream->getEventTarget()); + m_events->removeHandler(m_events->forIStream().outputShutdown(), + m_stream->getEventTarget()); + } + if (m_proxy != NULL) { + m_events->removeHandler(m_events->forClientProxy().ready(), m_proxy); + m_events->removeHandler(m_events->forClientProxy().disconnected(), m_proxy); + } +} + +void ClientProxyUnknown::removeTimer() { + if (m_timer != NULL) { + m_events->deleteTimer(m_timer); + m_events->removeHandler(Event::kTimer, this); + m_timer = NULL; + } +} + +void ClientProxyUnknown::initProxy(const String &name, int major, int minor) { + if (major == 1) { + switch (minor) { + case 0: + m_proxy = new ClientProxy1_0(name, m_stream, m_events); + break; + + case 1: + m_proxy = new ClientProxy1_1(name, m_stream, m_events); + break; + + case 2: + m_proxy = new ClientProxy1_2(name, m_stream, m_events); + break; + + case 3: + m_proxy = new ClientProxy1_3(name, m_stream, m_events); + break; + + case 4: + m_proxy = new ClientProxy1_4(name, m_stream, m_server, m_events); + break; + + case 5: + m_proxy = new ClientProxy1_5(name, m_stream, m_server, m_events); + break; + + case 6: + m_proxy = new ClientProxy1_6(name, m_stream, m_server, m_events); + break; + + case 7: + m_proxy = new ClientProxy1_7(name, m_stream, m_server, m_events); + break; + + case 8: + m_proxy = new ClientProxy1_8(name, m_stream, m_server, m_events); + break; + } + } + + // hangup (with error) if version isn't supported + if (m_proxy == NULL) { + throw XIncompatibleClient(major, minor); + } +} + +void ClientProxyUnknown::handleData(const Event &, void *) { + LOG((CLOG_DEBUG1 "parsing hello reply")); + + String name(""); + + try { + // limit the maximum length of the hello + UInt32 n = m_stream->getSize(); + if (n > kMaxHelloLength) { + LOG((CLOG_DEBUG1 "hello reply too long")); + throw XBadClient(); + } + + // parse the reply to hello + SInt16 major, minor; + if (!ProtocolUtil::readf(m_stream, kMsgHelloBack, &major, &minor, &name)) { + throw XBadClient(); + } + + // disallow invalid version numbers + if (major <= 0 || minor < 0) { + throw XIncompatibleClient(major, minor); + } + + // remove stream event handlers. the proxy we're about to create + // may install its own handlers and we don't want to accidentally + // remove those later. removeHandlers(); - removeTimer(); - m_events->addEvent(Event(m_events->forClientProxyUnknown().failure(), this)); + + // create client proxy for highest version supported by the client + initProxy(name, major, minor); + + // the proxy is created and now proxy now owns the stream + LOG((CLOG_DEBUG1 "created proxy for client \"%s\" version %d.%d", + name.c_str(), major, minor)); + m_stream = NULL; + + // wait until the proxy signals that it's ready or has disconnected + addProxyHandlers(); + return; + } catch (XIncompatibleClient &e) { + // client is incompatible + LOG((CLOG_WARN "client \"%s\" has incompatible version %d.%d)", + name.c_str(), e.getMajor(), e.getMinor())); + ProtocolUtil::writef(m_stream, kMsgEIncompatible, kProtocolMajorVersion, + kProtocolMinorVersion); + } catch (XBadClient &) { + // client not behaving + LOG((CLOG_WARN "protocol error from client \"%s\"", name.c_str())); + ProtocolUtil::writef(m_stream, kMsgEBad); + } catch (XBase &e) { + // misc error + LOG((CLOG_WARN "error communicating with client \"%s\": %s", name.c_str(), + e.what())); + } + sendFailure(); } -void -ClientProxyUnknown::addStreamHandlers() -{ - assert(m_stream != NULL); - - m_events->adoptHandler(m_events->forIStream().inputReady(), - m_stream->getEventTarget(), - new TMethodEventJob(this, - &ClientProxyUnknown::handleData)); - m_events->adoptHandler(m_events->forIStream().outputError(), - m_stream->getEventTarget(), - new TMethodEventJob(this, - &ClientProxyUnknown::handleWriteError)); - m_events->adoptHandler(m_events->forIStream().inputShutdown(), - m_stream->getEventTarget(), - new TMethodEventJob(this, - &ClientProxyUnknown::handleDisconnect)); - m_events->adoptHandler(m_events->forIStream().outputShutdown(), - m_stream->getEventTarget(), - new TMethodEventJob(this, - &ClientProxyUnknown::handleWriteError)); +void ClientProxyUnknown::handleWriteError(const Event &, void *) { + LOG((CLOG_NOTE "error communicating with new client")); + sendFailure(); } -void -ClientProxyUnknown::addProxyHandlers() -{ - assert(m_proxy != NULL); - - m_events->adoptHandler(m_events->forClientProxy().ready(), - m_proxy, - new TMethodEventJob(this, - &ClientProxyUnknown::handleReady)); - m_events->adoptHandler(m_events->forClientProxy().disconnected(), - m_proxy, - new TMethodEventJob(this, - &ClientProxyUnknown::handleDisconnect)); +void ClientProxyUnknown::handleTimeout(const Event &, void *) { + LOG((CLOG_NOTE "new client is unresponsive")); + sendFailure(); } -void -ClientProxyUnknown::removeHandlers() -{ - if (m_stream != NULL) { - m_events->removeHandler(m_events->forIStream().inputReady(), - m_stream->getEventTarget()); - m_events->removeHandler(m_events->forIStream().outputError(), - m_stream->getEventTarget()); - m_events->removeHandler(m_events->forIStream().inputShutdown(), - m_stream->getEventTarget()); - m_events->removeHandler(m_events->forIStream().outputShutdown(), - m_stream->getEventTarget()); - } - if (m_proxy != NULL) { - m_events->removeHandler(m_events->forClientProxy().ready(), - m_proxy); - m_events->removeHandler(m_events->forClientProxy().disconnected(), - m_proxy); - } +void ClientProxyUnknown::handleDisconnect(const Event &, void *) { + LOG((CLOG_NOTE "new client disconnected")); + sendFailure(); } -void -ClientProxyUnknown::removeTimer() -{ - if (m_timer != NULL) { - m_events->deleteTimer(m_timer); - m_events->removeHandler(Event::kTimer, this); - m_timer = NULL; - } -} - -void -ClientProxyUnknown::initProxy(const String& name, int major, int minor) -{ - if (major == 1) { - switch (minor) { - case 0: - m_proxy = new ClientProxy1_0(name, m_stream, m_events); - break; - - case 1: - m_proxy = new ClientProxy1_1(name, m_stream, m_events); - break; - - case 2: - m_proxy = new ClientProxy1_2(name, m_stream, m_events); - break; - - case 3: - m_proxy = new ClientProxy1_3(name, m_stream, m_events); - break; - - case 4: - m_proxy = new ClientProxy1_4(name, m_stream, m_server, m_events); - break; - - case 5: - m_proxy = new ClientProxy1_5(name, m_stream, m_server, m_events); - break; - - case 6: - m_proxy = new ClientProxy1_6(name, m_stream, m_server, m_events); - break; - - case 7: - m_proxy = new ClientProxy1_7(name, m_stream, m_server, m_events); - break; - - case 8: - m_proxy = new ClientProxy1_8(name, m_stream, m_server, m_events); - break; - } - } - - // hangup (with error) if version isn't supported - if (m_proxy == NULL) { - throw XIncompatibleClient(major, minor); - } -} - -void -ClientProxyUnknown::handleData(const Event&, void*) -{ - LOG((CLOG_DEBUG1 "parsing hello reply")); - - String name(""); - - try { - // limit the maximum length of the hello - UInt32 n = m_stream->getSize(); - if (n > kMaxHelloLength) { - LOG((CLOG_DEBUG1 "hello reply too long")); - throw XBadClient(); - } - - // parse the reply to hello - SInt16 major, minor; - if (!ProtocolUtil::readf(m_stream, kMsgHelloBack, &major, &minor, &name)) { - throw XBadClient(); - } - - // disallow invalid version numbers - if (major <= 0 || minor < 0) { - throw XIncompatibleClient(major, minor); - } - - // remove stream event handlers. the proxy we're about to create - // may install its own handlers and we don't want to accidentally - // remove those later. - removeHandlers(); - - // create client proxy for highest version supported by the client - initProxy(name, major, minor); - - // the proxy is created and now proxy now owns the stream - LOG((CLOG_DEBUG1 "created proxy for client \"%s\" version %d.%d", name.c_str(), major, minor)); - m_stream = NULL; - - // wait until the proxy signals that it's ready or has disconnected - addProxyHandlers(); - return; - } - catch (XIncompatibleClient& e) { - // client is incompatible - LOG((CLOG_WARN "client \"%s\" has incompatible version %d.%d)", name.c_str(), e.getMajor(), e.getMinor())); - ProtocolUtil::writef(m_stream, - kMsgEIncompatible, - kProtocolMajorVersion, kProtocolMinorVersion); - } - catch (XBadClient&) { - // client not behaving - LOG((CLOG_WARN "protocol error from client \"%s\"", name.c_str())); - ProtocolUtil::writef(m_stream, kMsgEBad); - } - catch (XBase& e) { - // misc error - LOG((CLOG_WARN "error communicating with client \"%s\": %s", name.c_str(), e.what())); - } - sendFailure(); -} - -void -ClientProxyUnknown::handleWriteError(const Event&, void*) -{ - LOG((CLOG_NOTE "error communicating with new client")); - sendFailure(); -} - -void -ClientProxyUnknown::handleTimeout(const Event&, void*) -{ - LOG((CLOG_NOTE "new client is unresponsive")); - sendFailure(); -} - -void -ClientProxyUnknown::handleDisconnect(const Event&, void*) -{ - LOG((CLOG_NOTE "new client disconnected")); - sendFailure(); -} - -void -ClientProxyUnknown::handleReady(const Event&, void*) -{ - sendSuccess(); -} +void ClientProxyUnknown::handleReady(const Event &, void *) { sendSuccess(); } diff --git a/src/lib/server/ClientProxyUnknown.h b/src/lib/server/ClientProxyUnknown.h index bd243de49..452d674f9 100644 --- a/src/lib/server/ClientProxyUnknown.h +++ b/src/lib/server/ClientProxyUnknown.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 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 LICENSE 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 @@ -19,60 +19,63 @@ #pragma once #include "base/Event.h" -#include "base/String.h" #include "base/EventTypes.h" +#include "base/String.h" class ClientProxy; class EventQueueTimer; -namespace synergy { class IStream; } +namespace synergy { +class IStream; +} class Server; class IEventQueue; class ClientProxyUnknown { public: - ClientProxyUnknown(synergy::IStream* stream, double timeout, Server* server, IEventQueue* events); - ClientProxyUnknown(ClientProxyUnknown const &) =delete; - ClientProxyUnknown(ClientProxyUnknown &&) =delete; - ~ClientProxyUnknown(); + ClientProxyUnknown(synergy::IStream *stream, double timeout, Server *server, + IEventQueue *events); + ClientProxyUnknown(ClientProxyUnknown const &) = delete; + ClientProxyUnknown(ClientProxyUnknown &&) = delete; + ~ClientProxyUnknown(); - ClientProxyUnknown& operator=(ClientProxyUnknown const &) =delete; - ClientProxyUnknown& operator=(ClientProxyUnknown &&) =delete; + ClientProxyUnknown &operator=(ClientProxyUnknown const &) = delete; + ClientProxyUnknown &operator=(ClientProxyUnknown &&) = delete; - //! @name manipulators - //@{ + //! @name manipulators + //@{ - //! Get the client proxy - /*! - Returns the client proxy created after a successful handshake - (i.e. when this object sends a success event). Returns NULL - if the handshake is unsuccessful or incomplete. - */ - ClientProxy* orphanClientProxy(); + //! Get the client proxy + /*! + Returns the client proxy created after a successful handshake + (i.e. when this object sends a success event). Returns NULL + if the handshake is unsuccessful or incomplete. + */ + ClientProxy *orphanClientProxy(); - //! Get the stream - synergy::IStream* getStream() { return m_stream; } + //! Get the stream + synergy::IStream *getStream() { return m_stream; } - //@} + //@} private: - void sendSuccess(); - void sendFailure(); - void addStreamHandlers(); - void addProxyHandlers(); - void removeHandlers(); - void initProxy(const String& name, int major, int minor); - void removeTimer(); - void handleData(const Event&, void*); - void handleWriteError(const Event&, void*); - void handleTimeout(const Event&, void*); - void handleDisconnect(const Event&, void*); - void handleReady(const Event&, void*); + void sendSuccess(); + void sendFailure(); + void addStreamHandlers(); + void addProxyHandlers(); + void removeHandlers(); + void initProxy(const String &name, int major, int minor); + void removeTimer(); + void handleData(const Event &, void *); + void handleWriteError(const Event &, void *); + void handleTimeout(const Event &, void *); + void handleDisconnect(const Event &, void *); + void handleReady(const Event &, void *); private: - synergy::IStream* m_stream; - EventQueueTimer* m_timer; - ClientProxy* m_proxy; - bool m_ready; - Server* m_server; - IEventQueue* m_events; + synergy::IStream *m_stream; + EventQueueTimer *m_timer; + ClientProxy *m_proxy; + bool m_ready; + Server *m_server; + IEventQueue *m_events; }; diff --git a/src/lib/server/Config.cpp b/src/lib/server/Config.cpp index be36199e0..5610b99a0 100644 --- a/src/lib/server/Config.cpp +++ b/src/lib/server/Config.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -18,13 +18,13 @@ #include "server/Config.h" -#include "server/Server.h" -#include "synergy/KeyMap.h" -#include "synergy/key_types.h" -#include "net/XSocket.h" #include "base/IEventQueue.h" #include "common/stdistream.h" #include "common/stdostream.h" +#include "net/XSocket.h" +#include "server/Server.h" +#include "synergy/KeyMap.h" +#include "synergy/key_types.h" #include @@ -34,2345 +34,1999 @@ using namespace synergy::string; // Config // -Config::Config(IEventQueue* events) : - m_inputFilter(events), - m_hasLockToScreenAction(false), - m_events(events) -{ - // do nothing +Config::Config(IEventQueue *events) + : m_inputFilter(events), m_hasLockToScreenAction(false), m_events(events) { + // do nothing } -Config::~Config() -{ - // do nothing +Config::~Config() { + // do nothing } -bool -Config::addScreen(const String& name) -{ - // alias name must not exist - if (m_nameToCanonicalName.find(name) != m_nameToCanonicalName.end()) { - return false; - } +bool Config::addScreen(const String &name) { + // alias name must not exist + if (m_nameToCanonicalName.find(name) != m_nameToCanonicalName.end()) { + return false; + } - // add cell - m_map.insert(std::make_pair(name, Cell())); + // add cell + m_map.insert(std::make_pair(name, Cell())); - // add name - m_nameToCanonicalName.insert(std::make_pair(name, name)); + // add name + m_nameToCanonicalName.insert(std::make_pair(name, name)); - return true; + return true; } -bool -Config::renameScreen(const String& oldName, - const String& newName) -{ - // get canonical name and find cell - String oldCanonical = getCanonicalName(oldName); - CellMap::iterator index = m_map.find(oldCanonical); - if (index == m_map.end()) { - return false; - } +bool Config::renameScreen(const String &oldName, const String &newName) { + // get canonical name and find cell + String oldCanonical = getCanonicalName(oldName); + CellMap::iterator index = m_map.find(oldCanonical); + if (index == m_map.end()) { + return false; + } - // accept if names are equal but replace with new name to maintain - // case. otherwise, the new name must not exist. - if (!CaselessCmp::equal(oldName, newName) && - m_nameToCanonicalName.find(newName) != m_nameToCanonicalName.end()) { - return false; - } + // accept if names are equal but replace with new name to maintain + // case. otherwise, the new name must not exist. + if (!CaselessCmp::equal(oldName, newName) && + m_nameToCanonicalName.find(newName) != m_nameToCanonicalName.end()) { + return false; + } - // update cell - Cell tmpCell = index->second; - m_map.erase(index); - m_map.insert(std::make_pair(newName, tmpCell)); + // update cell + Cell tmpCell = index->second; + m_map.erase(index); + m_map.insert(std::make_pair(newName, tmpCell)); - // update name - m_nameToCanonicalName.erase(oldCanonical); - m_nameToCanonicalName.insert(std::make_pair(newName, newName)); + // update name + m_nameToCanonicalName.erase(oldCanonical); + m_nameToCanonicalName.insert(std::make_pair(newName, newName)); - // update connections - Name oldNameObj(this, oldName); - for (index = m_map.begin(); index != m_map.end(); ++index) { - index->second.rename(oldNameObj, newName); - } + // update connections + Name oldNameObj(this, oldName); + for (index = m_map.begin(); index != m_map.end(); ++index) { + index->second.rename(oldNameObj, newName); + } - // update alias targets - if (CaselessCmp::equal(oldName, oldCanonical)) { - for (NameMap::iterator iter = m_nameToCanonicalName.begin(); - iter != m_nameToCanonicalName.end(); ++iter) { - if (CaselessCmp::equal( - iter->second, oldCanonical)) { - iter->second = newName; - } - } - } - - return true; -} - -void -Config::removeScreen(const String& name) -{ - // get canonical name and find cell - String canonical = getCanonicalName(name); - CellMap::iterator index = m_map.find(canonical); - if (index == m_map.end()) { - return; - } - - // remove from map - m_map.erase(index); - - // disconnect - Name nameObj(this, name); - for (index = m_map.begin(); index != m_map.end(); ++index) { - index->second.remove(nameObj); - } - - // remove aliases (and canonical name) - for (NameMap::iterator iter = m_nameToCanonicalName.begin(); - iter != m_nameToCanonicalName.end(); ) { - if (iter->second == canonical) { - m_nameToCanonicalName.erase(iter++); - } - else { - ++iter; - } + // update alias targets + if (CaselessCmp::equal(oldName, oldCanonical)) { + for (NameMap::iterator iter = m_nameToCanonicalName.begin(); + iter != m_nameToCanonicalName.end(); ++iter) { + if (CaselessCmp::equal(iter->second, oldCanonical)) { + iter->second = newName; + } } + } + + return true; } -void -Config::removeAllScreens() -{ - m_map.clear(); - m_nameToCanonicalName.clear(); +void Config::removeScreen(const String &name) { + // get canonical name and find cell + String canonical = getCanonicalName(name); + CellMap::iterator index = m_map.find(canonical); + if (index == m_map.end()) { + return; + } + + // remove from map + m_map.erase(index); + + // disconnect + Name nameObj(this, name); + for (index = m_map.begin(); index != m_map.end(); ++index) { + index->second.remove(nameObj); + } + + // remove aliases (and canonical name) + for (NameMap::iterator iter = m_nameToCanonicalName.begin(); + iter != m_nameToCanonicalName.end();) { + if (iter->second == canonical) { + m_nameToCanonicalName.erase(iter++); + } else { + ++iter; + } + } } -bool -Config::addAlias(const String& canonical, const String& alias) -{ - // alias name must not exist - if (m_nameToCanonicalName.find(alias) != m_nameToCanonicalName.end()) { - return false; - } - - // canonical name must be known - if (m_map.find(canonical) == m_map.end()) { - return false; - } - - // insert alias - m_nameToCanonicalName.insert(std::make_pair(alias, canonical)); - - return true; +void Config::removeAllScreens() { + m_map.clear(); + m_nameToCanonicalName.clear(); } -bool -Config::removeAlias(const String& alias) -{ - // must not be a canonical name - if (m_map.find(alias) != m_map.end()) { - return false; - } +bool Config::addAlias(const String &canonical, const String &alias) { + // alias name must not exist + if (m_nameToCanonicalName.find(alias) != m_nameToCanonicalName.end()) { + return false; + } - // find alias - NameMap::iterator index = m_nameToCanonicalName.find(alias); - if (index == m_nameToCanonicalName.end()) { - return false; - } + // canonical name must be known + if (m_map.find(canonical) == m_map.end()) { + return false; + } - // remove alias - m_nameToCanonicalName.erase(index); + // insert alias + m_nameToCanonicalName.insert(std::make_pair(alias, canonical)); - return true; + return true; } -bool -Config::removeAliases(const String& canonical) -{ - // must be a canonical name - if (m_map.find(canonical) == m_map.end()) { - return false; - } +bool Config::removeAlias(const String &alias) { + // must not be a canonical name + if (m_map.find(alias) != m_map.end()) { + return false; + } - // find and removing matching aliases - for (NameMap::iterator index = m_nameToCanonicalName.begin(); - index != m_nameToCanonicalName.end(); ) { - if (index->second == canonical && index->first != canonical) { - m_nameToCanonicalName.erase(index++); - } - else { - ++index; - } - } + // find alias + NameMap::iterator index = m_nameToCanonicalName.find(alias); + if (index == m_nameToCanonicalName.end()) { + return false; + } - return true; + // remove alias + m_nameToCanonicalName.erase(index); + + return true; } -void -Config::removeAllAliases() -{ - // remove all names - m_nameToCanonicalName.clear(); +bool Config::removeAliases(const String &canonical) { + // must be a canonical name + if (m_map.find(canonical) == m_map.end()) { + return false; + } - // put the canonical names back in - for (CellMap::iterator index = m_map.begin(); - index != m_map.end(); ++index) { - m_nameToCanonicalName.insert( - std::make_pair(index->first, index->first)); - } + // find and removing matching aliases + for (NameMap::iterator index = m_nameToCanonicalName.begin(); + index != m_nameToCanonicalName.end();) { + if (index->second == canonical && index->first != canonical) { + m_nameToCanonicalName.erase(index++); + } else { + ++index; + } + } + + return true; } -bool -Config::connect(const String& srcName, - EDirection srcSide, - float srcStart, float srcEnd, - const String& dstName, - float dstStart, float dstEnd) -{ - assert(srcSide >= kFirstDirection && srcSide <= kLastDirection); +void Config::removeAllAliases() { + // remove all names + m_nameToCanonicalName.clear(); - // find source cell - CellMap::iterator index = m_map.find(getCanonicalName(srcName)); - if (index == m_map.end()) { - return false; - } - - // add link - CellEdge srcEdge(srcSide, Interval(srcStart, srcEnd)); - CellEdge dstEdge(dstName, srcSide, Interval(dstStart, dstEnd)); - return index->second.add(srcEdge, dstEdge); + // put the canonical names back in + for (CellMap::iterator index = m_map.begin(); index != m_map.end(); ++index) { + m_nameToCanonicalName.insert(std::make_pair(index->first, index->first)); + } } -bool -Config::disconnect(const String& srcName, EDirection srcSide) -{ - assert(srcSide >= kFirstDirection && srcSide <= kLastDirection); +bool Config::connect(const String &srcName, EDirection srcSide, float srcStart, + float srcEnd, const String &dstName, float dstStart, + float dstEnd) { + assert(srcSide >= kFirstDirection && srcSide <= kLastDirection); - // find source cell - CellMap::iterator index = m_map.find(srcName); - if (index == m_map.end()) { - return false; - } + // find source cell + CellMap::iterator index = m_map.find(getCanonicalName(srcName)); + if (index == m_map.end()) { + return false; + } - // disconnect side - index->second.remove(srcSide); - - return true; + // add link + CellEdge srcEdge(srcSide, Interval(srcStart, srcEnd)); + CellEdge dstEdge(dstName, srcSide, Interval(dstStart, dstEnd)); + return index->second.add(srcEdge, dstEdge); } -bool -Config::disconnect(const String& srcName, EDirection srcSide, float position) -{ - assert(srcSide >= kFirstDirection && srcSide <= kLastDirection); +bool Config::disconnect(const String &srcName, EDirection srcSide) { + assert(srcSide >= kFirstDirection && srcSide <= kLastDirection); - // find source cell - CellMap::iterator index = m_map.find(srcName); - if (index == m_map.end()) { - return false; - } + // find source cell + CellMap::iterator index = m_map.find(srcName); + if (index == m_map.end()) { + return false; + } - // disconnect side - index->second.remove(srcSide, position); + // disconnect side + index->second.remove(srcSide); - return true; + return true; } -void -Config::setSynergyAddress(const NetworkAddress& addr) -{ - m_synergyAddress = addr; +bool Config::disconnect(const String &srcName, EDirection srcSide, + float position) { + assert(srcSide >= kFirstDirection && srcSide <= kLastDirection); + + // find source cell + CellMap::iterator index = m_map.find(srcName); + if (index == m_map.end()) { + return false; + } + + // disconnect side + index->second.remove(srcSide, position); + + return true; } -bool -Config::addOption(const String& name, OptionID option, OptionValue value) -{ - // find options - ScreenOptions* options = NULL; - if (name.empty()) { - options = &m_globalOptions; - } - else { - CellMap::iterator index = m_map.find(name); - if (index != m_map.end()) { - options = &index->second.m_options; - } - } - if (options == NULL) { - return false; - } - - // add option - options->insert(std::make_pair(option, value)); - return true; +void Config::setSynergyAddress(const NetworkAddress &addr) { + m_synergyAddress = addr; } -bool -Config::removeOption(const String& name, OptionID option) -{ - // find options - ScreenOptions* options = NULL; - if (name.empty()) { - options = &m_globalOptions; - } - else { - CellMap::iterator index = m_map.find(name); - if (index != m_map.end()) { - options = &index->second.m_options; - } - } - if (options == NULL) { - return false; - } +bool Config::addOption(const String &name, OptionID option, OptionValue value) { + // find options + ScreenOptions *options = NULL; + if (name.empty()) { + options = &m_globalOptions; + } else { + CellMap::iterator index = m_map.find(name); + if (index != m_map.end()) { + options = &index->second.m_options; + } + } + if (options == NULL) { + return false; + } - // remove option - options->erase(option); - return true; + // add option + options->insert(std::make_pair(option, value)); + return true; } -bool -Config::removeOptions(const String& name) -{ - // find options - ScreenOptions* options = NULL; - if (name.empty()) { - options = &m_globalOptions; - } - else { - CellMap::iterator index = m_map.find(name); - if (index != m_map.end()) { - options = &index->second.m_options; - } - } - if (options == NULL) { - return false; - } +bool Config::removeOption(const String &name, OptionID option) { + // find options + ScreenOptions *options = NULL; + if (name.empty()) { + options = &m_globalOptions; + } else { + CellMap::iterator index = m_map.find(name); + if (index != m_map.end()) { + options = &index->second.m_options; + } + } + if (options == NULL) { + return false; + } - // remove options - options->clear(); - return true; + // remove option + options->erase(option); + return true; } -bool -Config::isValidScreenName(const String& name) const -{ - // name is valid if matches validname - // name ::= [_A-Za-z0-9] | [_A-Za-z0-9][-_A-Za-z0-9]*[_A-Za-z0-9] - // domain ::= . name - // validname ::= name domain* - // we also accept names ending in . because many OS X users have - // so misconfigured their systems. +bool Config::removeOptions(const String &name) { + // find options + ScreenOptions *options = NULL; + if (name.empty()) { + options = &m_globalOptions; + } else { + CellMap::iterator index = m_map.find(name); + if (index != m_map.end()) { + options = &index->second.m_options; + } + } + if (options == NULL) { + return false; + } - // empty name is invalid - if (name.empty()) { - return false; - } - - // check each dot separated part - String::size_type b = 0; - for (;;) { - // accept trailing . - if (b == name.size()) { - break; - } - - // find end of part - String::size_type e = name.find('.', b); - if (e == String::npos) { - e = name.size(); - } - - // part may not be empty - if (e - b < 1) { - return false; - } - - // check first and last characters - if (!(isalnum(name[b]) || name[b] == '_') || - !(isalnum(name[e - 1]) || name[e - 1] == '_')) { - return false; - } - - // check interior characters - for (String::size_type i = b; i < e; ++i) { - if (!isalnum(name[i]) && name[i] != '_' && name[i] != '-') { - return false; - } - } - - // next part - if (e == name.size()) { - // no more parts - break; - } - b = e + 1; - } - - return true; + // remove options + options->clear(); + return true; } -Config::const_iterator -Config::begin() const -{ - return const_iterator(m_map.begin()); -} - -Config::const_iterator -Config::end() const -{ - return const_iterator(m_map.end()); -} - -Config::all_const_iterator -Config::beginAll() const -{ - return m_nameToCanonicalName.begin(); -} - -Config::all_const_iterator -Config::endAll() const -{ - return m_nameToCanonicalName.end(); -} - -bool -Config::isScreen(const String& name) const -{ - return (m_nameToCanonicalName.count(name) > 0); -} - -bool -Config::isCanonicalName(const String& name) const -{ - return (!name.empty() && - CaselessCmp::equal(getCanonicalName(name), name)); -} - -String -Config::getCanonicalName(const String& name) const -{ - NameMap::const_iterator index = m_nameToCanonicalName.find(name); - if (index == m_nameToCanonicalName.end()) { - return String(); - } - else { - return index->second; - } -} - -String -Config::getNeighbor(const String& srcName, EDirection srcSide, - float position, float* positionOut) const -{ - assert(srcSide >= kFirstDirection && srcSide <= kLastDirection); - - // find source cell - CellMap::const_iterator index = m_map.find(getCanonicalName(srcName)); - if (index == m_map.end()) { - return String(); - } - - // find edge - const CellEdge* srcEdge, *dstEdge; - if (!index->second.getLink(srcSide, position, srcEdge, dstEdge)) { - // no neighbor - return ""; - } - else { - // compute position on neighbor - if (positionOut != NULL) { - *positionOut = - dstEdge->inverseTransform(srcEdge->transform(position)); - } - - // return neighbor's name - return getCanonicalName(dstEdge->getName()); - } -} - -bool -Config::hasNeighbor(const String& srcName, EDirection srcSide) const -{ - return hasNeighbor(srcName, srcSide, 0.0f, 1.0f); -} - -bool -Config::hasNeighbor(const String& srcName, EDirection srcSide, - float start, float end) const -{ - assert(srcSide >= kFirstDirection && srcSide <= kLastDirection); - - // find source cell - CellMap::const_iterator index = m_map.find(getCanonicalName(srcName)); - if (index == m_map.end()) { - return false; - } - - return index->second.overlaps(CellEdge(srcSide, Interval(start, end))); -} - -Config::link_const_iterator -Config::beginNeighbor(const String& srcName) const -{ - CellMap::const_iterator index = m_map.find(getCanonicalName(srcName)); - assert(index != m_map.end()); - return index->second.begin(); -} - -Config::link_const_iterator -Config::endNeighbor(const String& srcName) const -{ - CellMap::const_iterator index = m_map.find(getCanonicalName(srcName)); - assert(index != m_map.end()); - return index->second.end(); -} - -const NetworkAddress& -Config::getSynergyAddress() const -{ - return m_synergyAddress; -} - -const Config::ScreenOptions* -Config::getOptions(const String& name) const -{ - // find options - const ScreenOptions* options = NULL; - if (name.empty()) { - options = &m_globalOptions; - } - else { - CellMap::const_iterator index = m_map.find(name); - if (index != m_map.end()) { - options = &index->second.m_options; - } - } - - // return options - return options; -} - -bool -Config::hasLockToScreenAction() const -{ - return m_hasLockToScreenAction; -} - -bool -Config::operator==(const Config& x) const -{ - if (m_synergyAddress != x.m_synergyAddress) { - return false; - } - if (m_map.size() != x.m_map.size()) { - return false; - } - if (m_nameToCanonicalName.size() != x.m_nameToCanonicalName.size()) { - return false; - } - - // compare global options - if (m_globalOptions != x.m_globalOptions) { - return false; - } - - auto index2map = x.m_map.cbegin(); - for (auto const &index1: m_map) { - // compare names - if (!CaselessCmp::equal(index1.first, index2map->first)) { - return false; - } - - // compare cells - if (index1.second != index2map->second) { - return false; - } - ++index2map; - } - - auto index2 = x.m_nameToCanonicalName.cbegin(); - for (auto const &index1: m_nameToCanonicalName) { - if (index2 == x.m_nameToCanonicalName.cend()) { - return false; // second source ended - } - if (!CaselessCmp::equal(index1.first, index2->first) || - !CaselessCmp::equal(index1.second, index2->second)) { - return false; - } - ++index2; - } - - // compare input filters - if (m_inputFilter != x.m_inputFilter) { - return false; - } - - return true; -} - -bool -Config::operator!=(const Config& x) const -{ - return !operator==(x); -} - -void -Config::read(ConfigReadContext& context) -{ - Config tmp(m_events); - while (context.getStream()) { - tmp.readSection(context); - } - *this = tmp; -} - -const char* -Config::dirName(EDirection dir) -{ - static const char* s_name[] = { "left", "right", "up", "down" }; - - assert(dir >= kFirstDirection && dir <= kLastDirection); - - return s_name[dir - kFirstDirection]; -} - -InputFilter* -Config::getInputFilter() -{ - return &m_inputFilter; -} - -String -Config::formatInterval(const Interval& x) -{ - if (x.first == 0.0f && x.second == 1.0f) { - return ""; - } - return synergy::string::sprintf("(%d,%d)", (int)(x.first * 100.0f + 0.5f), - (int)(x.second * 100.0f + 0.5f)); -} - -String Config::getClientAddress() const -{ - return m_clientAddress; -} - -bool Config::isClientMode() const -{ - return (!m_clientAddress.empty()); -} - -void -Config::readSection(ConfigReadContext& s) -{ - static const char s_section[] = "section:"; - static const char s_options[] = "options"; - static const char s_screens[] = "screens"; - static const char s_links[] = "links"; - static const char s_aliases[] = "aliases"; - - String line; - if (!s.readLine(line)) { - // no more sections - return; - } - - // should be a section header - if (line.find(s_section) != 0) { - throw XConfigRead(s, "found data outside section"); - } - - // get section name - String::size_type i = line.find_first_not_of(" \t", sizeof(s_section) - 1); - if (i == String::npos) { - throw XConfigRead(s, "section name is missing"); - } - String name = line.substr(i); - i = name.find_first_of(" \t"); - if (i != String::npos) { - throw XConfigRead(s, "unexpected data after section name"); - } - - // read section - if (name == s_options) { - readSectionOptions(s); - } - else if (name == s_screens) { - readSectionScreens(s); - } - else if (name == s_links) { - readSectionLinks(s); - } - else if (name == s_aliases) { - readSectionAliases(s); - } - else { - throw XConfigRead(s, "unknown section name \"%{1}\"", name); - } -} - -void -Config::readSectionOptions(ConfigReadContext& s) -{ - String line; - while (s.readLine(line)) { - // check for end of section - if (line == "end") { - return; - } - - // parse argument: `nameAndArgs = [values][;[values]]' - // nameAndArgs := [(arg[,...])] - // values := valueAndArgs[,valueAndArgs]... - // valueAndArgs := [(arg[,...])] - String::size_type i = 0; - String name, value; - ConfigReadContext::ArgList nameArgs, valueArgs; - s.parseNameWithArgs("name", line, "=", i, name, nameArgs); - ++i; - s.parseNameWithArgs("value", line, ",;\n", i, value, valueArgs); - - bool handled = true; - if (name == "address") { - try { - m_synergyAddress = NetworkAddress(value, kDefaultPort); - m_synergyAddress.resolve(); - } - catch (XSocketAddress& e) { - throw XConfigRead(s, - String("invalid address argument ") + e.what()); - } - } - else if (name == "heartbeat") { - addOption("", kOptionHeartbeat, s.parseInt(value)); - } - else if (name == "switchCorners") { - addOption("", kOptionScreenSwitchCorners, s.parseCorners(value)); - } - else if (name == "switchCornerSize") { - addOption("", kOptionScreenSwitchCornerSize, s.parseInt(value)); - } - else if (name == "switchDelay") { - addOption("", kOptionScreenSwitchDelay, s.parseInt(value)); - } - else if (name == "switchDoubleTap") { - addOption("", kOptionScreenSwitchTwoTap, s.parseInt(value)); - } - else if (name == "switchNeedsShift") { - addOption("", kOptionScreenSwitchNeedsShift, s.parseBoolean(value)); - } - else if (name == "switchNeedsControl") { - addOption("", kOptionScreenSwitchNeedsControl, s.parseBoolean(value)); - } - else if (name == "switchNeedsAlt") { - addOption("", kOptionScreenSwitchNeedsAlt, s.parseBoolean(value)); - } - else if (name == "relativeMouseMoves") { - addOption("", kOptionRelativeMouseMoves, s.parseBoolean(value)); - } - else if (name == "win32KeepForeground") { - addOption("", kOptionWin32KeepForeground, s.parseBoolean(value)); - } - else if (name == "disableLockToScreen") { - addOption("", kOptionDisableLockToScreen, s.parseBoolean(value)); - } - else if (name == "clipboardSharing") { - addOption("", kOptionClipboardSharing, s.parseBoolean(value)); - } - else if (name == "clipboardSharingSize") { - addOption("", kOptionClipboardSharingSize, s.parseInt(value)); - } - else if (name == "clientAddress") { - m_clientAddress = value; - } - else { - handled = false; - } - - if (handled) { - // make sure handled options aren't followed by more values - if (i < line.size() && (line[i] == ',' || line[i] == ';')) { - throw XConfigRead(s, "to many arguments to %s", name.c_str()); - } - } - else { - // make filter rule - InputFilter::Rule rule(parseCondition(s, name, nameArgs)); - - // save first action (if any) - if (!value.empty() || line[i] != ';') { - parseAction(s, value, valueArgs, rule, true); - } - - // get remaining activate actions - while (i < line.length() && line[i] != ';') { - ++i; - s.parseNameWithArgs("value", line, ",;\n", i, value, valueArgs); - parseAction(s, value, valueArgs, rule, true); - } - - // get deactivate actions - if (i < line.length() && line[i] == ';') { - // allow trailing ';' - i = line.find_first_not_of(" \t", i + 1); - if (i == String::npos) { - i = line.length(); - } - else { - --i; - } - - // get actions - while (i < line.length()) { - ++i; - s.parseNameWithArgs("value", line, ",\n", - i, value, valueArgs); - parseAction(s, value, valueArgs, rule, false); - } - } - - // add rule - m_inputFilter.addFilterRule(rule); - } - } - throw XConfigRead(s, "unexpected end of options section"); -} - -void -Config::readSectionScreens(ConfigReadContext& s) -{ - String line; - String screen; - while (s.readLine(line)) { - // check for end of section - if (line == "end") { - return; - } - - // see if it's the next screen - if (line[line.size() - 1] == ':') { - // strip : - screen = line.substr(0, line.size() - 1); - - // verify validity of screen name - if (!isValidScreenName(screen)) { - throw XConfigRead(s, "invalid screen name \"%{1}\"", screen); - } - - // add the screen to the configuration - if (!addScreen(screen)) { - throw XConfigRead(s, "duplicate screen name \"%{1}\"", screen); - } - } - else if (screen.empty()) { - throw XConfigRead(s, "argument before first screen"); - } - else { - // parse argument: `=' - String::size_type i = line.find_first_of(" \t="); - if (i == 0) { - throw XConfigRead(s, "missing argument name"); - } - if (i == String::npos) { - throw XConfigRead(s, "missing ="); - } - String name = line.substr(0, i); - i = line.find_first_not_of(" \t", i); - if (i == String::npos || line[i] != '=') { - throw XConfigRead(s, "missing ="); - } - i = line.find_first_not_of(" \t", i + 1); - String value; - if (i != String::npos) { - value = line.substr(i); - } - - // handle argument - if (name == "halfDuplexCapsLock") { - addOption(screen, kOptionHalfDuplexCapsLock, - s.parseBoolean(value)); - } - else if (name == "halfDuplexNumLock") { - addOption(screen, kOptionHalfDuplexNumLock, - s.parseBoolean(value)); - } - else if (name == "halfDuplexScrollLock") { - addOption(screen, kOptionHalfDuplexScrollLock, - s.parseBoolean(value)); - } - else if (name == "shift") { - addOption(screen, kOptionModifierMapForShift, - s.parseModifierKey(value)); - } - else if (name == "ctrl") { - addOption(screen, kOptionModifierMapForControl, - s.parseModifierKey(value)); - } - else if (name == "alt") { - addOption(screen, kOptionModifierMapForAlt, - s.parseModifierKey(value)); - } - else if (name == "altgr") { - addOption(screen, kOptionModifierMapForAltGr, - s.parseModifierKey(value)); - } - else if (name == "meta") { - addOption(screen, kOptionModifierMapForMeta, - s.parseModifierKey(value)); - } - else if (name == "super") { - addOption(screen, kOptionModifierMapForSuper, - s.parseModifierKey(value)); - } - else if (name == "xtestIsXineramaUnaware") { - addOption(screen, kOptionXTestXineramaUnaware, - s.parseBoolean(value)); - } - else if (name == "switchCorners") { - addOption(screen, kOptionScreenSwitchCorners, - s.parseCorners(value)); - } - else if (name == "switchCornerSize") { - addOption(screen, kOptionScreenSwitchCornerSize, - s.parseInt(value)); - } - else if (name == "preserveFocus") { - addOption(screen, kOptionScreenPreserveFocus, - s.parseBoolean(value)); - } - else { - // unknown argument - throw XConfigRead(s, "unknown argument \"%{1}\"", name); - } - } - } - throw XConfigRead(s, "unexpected end of screens section"); -} - -void -Config::readSectionLinks(ConfigReadContext& s) -{ - String line; - String screen; - while (s.readLine(line)) { - // check for end of section - if (line == "end") { - return; - } - - // see if it's the next screen - if (line[line.size() - 1] == ':') { - // strip : - screen = line.substr(0, line.size() - 1); - - // verify we know about the screen - if (!isScreen(screen)) { - throw XConfigRead(s, "unknown screen name \"%{1}\"", screen); - } - if (!isCanonicalName(screen)) { - throw XConfigRead(s, "cannot use screen name alias here"); - } - } - else if (screen.empty()) { - throw XConfigRead(s, "argument before first screen"); - } - else { - // parse argument: `[(,)]=[(,)]' - // the stuff in brackets is optional. interval values must be - // in the range [0,100] and start < end. if not given the - // interval is taken to be (0,100). - String::size_type i = 0; - String side, dstScreen, srcArgString, dstArgString; - ConfigReadContext::ArgList srcArgs, dstArgs; - s.parseNameWithArgs("link", line, "=", i, side, srcArgs); - ++i; - s.parseNameWithArgs("screen", line, "", i, dstScreen, dstArgs); - Interval srcInterval(s.parseInterval(srcArgs)); - Interval dstInterval(s.parseInterval(dstArgs)); - - // handle argument - EDirection dir; - if (side == "left") { - dir = kLeft; - } - else if (side == "right") { - dir = kRight; - } - else if (side == "up") { - dir = kTop; - } - else if (side == "down") { - dir = kBottom; - } - else { - // unknown argument - throw XConfigRead(s, "unknown side \"%{1}\" in link", side); - } - if (!isScreen(dstScreen)) { - throw XConfigRead(s, "unknown screen name \"%{1}\"", dstScreen); - } - if (!connect(screen, dir, - srcInterval.first, srcInterval.second, - dstScreen, - dstInterval.first, dstInterval.second)) { - throw XConfigRead(s, "overlapping range"); - } - } - } - throw XConfigRead(s, "unexpected end of links section"); -} - -void -Config::readSectionAliases(ConfigReadContext& s) -{ - String line; - String screen; - while (s.readLine(line)) { - // check for end of section - if (line == "end") { - return; - } - - // see if it's the next screen - if (line[line.size() - 1] == ':') { - // strip : - screen = line.substr(0, line.size() - 1); - - // verify we know about the screen - if (!isScreen(screen)) { - throw XConfigRead(s, "unknown screen name \"%{1}\"", screen); - } - if (!isCanonicalName(screen)) { - throw XConfigRead(s, "cannot use screen name alias here"); - } - } - else if (screen.empty()) { - throw XConfigRead(s, "argument before first screen"); - } - else { - // verify validity of screen name - if (!isValidScreenName(line)) { - throw XConfigRead(s, "invalid screen alias \"%{1}\"", line); - } - - // add alias - if (!addAlias(screen, line)) { - throw XConfigRead(s, "alias \"%{1}\" is already used", line); - } - } - } - throw XConfigRead(s, "unexpected end of aliases section"); -} - - -InputFilter::Condition* -Config::parseCondition(ConfigReadContext& s, - const String& name, const std::vector& args) -{ - if (name == "keystroke") { - if (args.size() != 1) { - throw XConfigRead(s, "syntax for condition: keystroke(modifiers+key)"); - } - - IPlatformScreen::KeyInfo* keyInfo = s.parseKeystroke(args[0]); - - return new InputFilter::KeystrokeCondition(m_events, keyInfo); - } - - if (name == "mousebutton") { - if (args.size() != 1) { - throw XConfigRead(s, "syntax for condition: mousebutton(modifiers+button)"); - } - - IPlatformScreen::ButtonInfo* mouseInfo = s.parseMouse(args[0]); - - return new InputFilter::MouseButtonCondition(m_events, mouseInfo); - } - - if (name == "connect") { - if (args.size() != 1) { - throw XConfigRead(s, "syntax for condition: connect([screen])"); - } - - String screen = args[0]; - if (isScreen(screen)) { - screen = getCanonicalName(screen); - } - else if (!screen.empty()) { - throw XConfigRead(s, "unknown screen name \"%{1}\" in connect", screen); - } - - return new InputFilter::ScreenConnectedCondition(m_events, screen); - } - - throw XConfigRead(s, "unknown argument \"%{1}\"", name); -} - -void -Config::parseAction(ConfigReadContext& s, - const String& name, const std::vector& args, - InputFilter::Rule& rule, bool activate) -{ - InputFilter::Action* action; - - if (name == "keystroke" || name == "keyDown" || name == "keyUp") { - if (args.size() < 1 || args.size() > 2) { - throw XConfigRead(s, "syntax for action: keystroke(modifiers+key[,screens])"); - } - - IPlatformScreen::KeyInfo* keyInfo; - if (args.size() == 1) { - keyInfo = s.parseKeystroke(args[0]); - } - else { - std::set screens; - parseScreens(s, args[1], screens); - keyInfo = s.parseKeystroke(args[0], screens); - } - - if (name == "keystroke") { - IPlatformScreen::KeyInfo* keyInfo2 = - IKeyState::KeyInfo::alloc(*keyInfo); - action = new InputFilter::KeystrokeAction(m_events, keyInfo2, true); - rule.adoptAction(action, true); - action = new InputFilter::KeystrokeAction(m_events, keyInfo, false); - activate = false; - } - else if (name == "keyDown") { - action = new InputFilter::KeystrokeAction(m_events, keyInfo, true); - } - else { - action = new InputFilter::KeystrokeAction(m_events, keyInfo, false); - } - } - - else if (name == "mousebutton" || - name == "mouseDown" || name == "mouseUp") { - if (args.size() != 1) { - throw XConfigRead(s, "syntax for action: mousebutton(modifiers+button)"); - } - - IPlatformScreen::ButtonInfo* mouseInfo = s.parseMouse(args[0]); - - if (name == "mousebutton") { - IPlatformScreen::ButtonInfo* mouseInfo2 = - IPlatformScreen::ButtonInfo::alloc(*mouseInfo); - action = new InputFilter::MouseButtonAction(m_events, mouseInfo2, true); - rule.adoptAction(action, true); - action = new InputFilter::MouseButtonAction(m_events, mouseInfo, false); - activate = false; - } - else if (name == "mouseDown") { - action = new InputFilter::MouseButtonAction(m_events, mouseInfo, true); - } - else { - action = new InputFilter::MouseButtonAction(m_events, mouseInfo, false); - } - } - -/* XXX -- not supported - else if (name == "modifier") { - if (args.size() != 1) { - throw XConfigRead(s, "syntax for action: modifier(modifiers)"); - } - - KeyModifierMask mask = s.parseModifier(args[0]); - - action = new InputFilter::ModifierAction(mask, ~mask); - } -*/ - - else if (name == "switchToScreen") { - if (args.size() != 1) { - throw XConfigRead(s, "syntax for action: switchToScreen(name)"); - } - - String screen = args[0]; - if (isScreen(screen)) { - screen = getCanonicalName(screen); - } - else if (!screen.empty()) { - throw XConfigRead(s, "unknown screen name in switchToScreen"); - } - - action = new InputFilter::SwitchToScreenAction(m_events, screen); - } - - else if (name == "switchInDirection") { - if (args.size() != 1) { - throw XConfigRead(s, "syntax for action: switchInDirection()"); - } - - EDirection direction; - if (args[0] == "left") { - direction = kLeft; - } - else if (args[0] == "right") { - direction = kRight; - } - else if (args[0] == "up") { - direction = kTop; - } - else if (args[0] == "down") { - direction = kBottom; - } - else { - throw XConfigRead(s, "unknown direction \"%{1}\" in switchToScreen", args[0]); - } - - action = new InputFilter::SwitchInDirectionAction(m_events, direction); - } - - else if (name == "lockCursorToScreen") { - if (args.size() > 1) { - throw XConfigRead(s, "syntax for action: lockCursorToScreen([{off|on|toggle}])"); - } - - InputFilter::LockCursorToScreenAction::Mode mode = - InputFilter::LockCursorToScreenAction::kToggle; - if (args.size() == 1) { - if (args[0] == "off") { - mode = InputFilter::LockCursorToScreenAction::kOff; - } - else if (args[0] == "on") { - mode = InputFilter::LockCursorToScreenAction::kOn; - } - else if (args[0] == "toggle") { - mode = InputFilter::LockCursorToScreenAction::kToggle; - } - else { - throw XConfigRead(s, "syntax for action: lockCursorToScreen([{off|on|toggle}])"); - } - } - - if (mode != InputFilter::LockCursorToScreenAction::kOff) { - m_hasLockToScreenAction = true; - } - - action = new InputFilter::LockCursorToScreenAction(m_events, mode); - } - - else if (name == "restartServer") { - if (args.size() > 1) { - throw XConfigRead(s, "syntax for action: restartServer([{{restart}}])"); - } - - InputFilter::RestartServer::Mode mode = - InputFilter::RestartServer::restart; - - if (args.size() == 1) { - if (args[0] == "restart") { - mode = InputFilter::RestartServer::restart; - } - else { - throw XConfigRead(s, "syntax for action: restartServer([{restart}])"); - } - } - - action = new InputFilter::RestartServer(m_events, mode); +bool Config::isValidScreenName(const String &name) const { + // name is valid if matches validname + // name ::= [_A-Za-z0-9] | [_A-Za-z0-9][-_A-Za-z0-9]*[_A-Za-z0-9] + // domain ::= . name + // validname ::= name domain* + // we also accept names ending in . because many OS X users have + // so misconfigured their systems. + + // empty name is invalid + if (name.empty()) { + return false; + } + + // check each dot separated part + String::size_type b = 0; + for (;;) { + // accept trailing . + if (b == name.size()) { + break; } - else if (name == "keyboardBroadcast") { - if (args.size() > 2) { - throw XConfigRead(s, "syntax for action: keyboardBroadcast([{off|on|toggle}[,screens]])"); - } + // find end of part + String::size_type e = name.find('.', b); + if (e == String::npos) { + e = name.size(); + } - InputFilter::KeyboardBroadcastAction::Mode mode = - InputFilter::KeyboardBroadcastAction::kToggle; - if (args.size() >= 1) { - if (args[0] == "off") { - mode = InputFilter::KeyboardBroadcastAction::kOff; - } - else if (args[0] == "on") { - mode = InputFilter::KeyboardBroadcastAction::kOn; - } - else if (args[0] == "toggle") { - mode = InputFilter::KeyboardBroadcastAction::kToggle; - } - else { - throw XConfigRead(s, "syntax for action: keyboardBroadcast([{off|on|toggle}[,screens]])"); - } - } + // part may not be empty + if (e - b < 1) { + return false; + } - std::set screens; - if (args.size() >= 2) { - parseScreens(s, args[1], screens); - } + // check first and last characters + if (!(isalnum(name[b]) || name[b] == '_') || + !(isalnum(name[e - 1]) || name[e - 1] == '_')) { + return false; + } - action = new InputFilter::KeyboardBroadcastAction(m_events, mode, screens); - } + // check interior characters + for (String::size_type i = b; i < e; ++i) { + if (!isalnum(name[i]) && name[i] != '_' && name[i] != '-') { + return false; + } + } - else { - throw XConfigRead(s, "unknown action argument \"%{1}\"", name); - } + // next part + if (e == name.size()) { + // no more parts + break; + } + b = e + 1; + } - rule.adoptAction(action, activate); + return true; } -void -Config::parseScreens(ConfigReadContext& c, - const String& s, std::set& screens) const -{ - screens.clear(); - - String::size_type i = 0; - while (i < s.size()) { - // find end of next screen name - String::size_type j = s.find(':', i); - if (j == String::npos) { - j = s.size(); - } - - // extract name - String rawName; - i = s.find_first_not_of(" \t", i); - if (i < j) { - rawName = s.substr(i, s.find_last_not_of(" \t", j - 1) - i + 1); - } - - // add name - if (rawName == "*") { - screens.insert("*"); - } - else if (!rawName.empty()) { - String name = getCanonicalName(rawName); - if (name.empty()) { - throw XConfigRead(c, "unknown screen name \"%{1}\"", rawName); - } - screens.insert(name); - } - - // next - i = j + 1; - } +Config::const_iterator Config::begin() const { + return const_iterator(m_map.begin()); } -const char* -Config::getOptionName(OptionID id) -{ - if (id == kOptionHalfDuplexCapsLock) { - return "halfDuplexCapsLock"; - } - if (id == kOptionHalfDuplexNumLock) { - return "halfDuplexNumLock"; - } - if (id == kOptionHalfDuplexScrollLock) { - return "halfDuplexScrollLock"; - } - if (id == kOptionModifierMapForShift) { - return "shift"; - } - if (id == kOptionModifierMapForControl) { - return "ctrl"; - } - if (id == kOptionModifierMapForAlt) { - return "alt"; - } - if (id == kOptionModifierMapForAltGr) { - return "altgr"; - } - if (id == kOptionModifierMapForMeta) { - return "meta"; - } - if (id == kOptionModifierMapForSuper) { - return "super"; - } - if (id == kOptionHeartbeat) { - return "heartbeat"; - } - if (id == kOptionScreenSwitchCorners) { - return "switchCorners"; - } - if (id == kOptionScreenSwitchCornerSize) { - return "switchCornerSize"; - } - if (id == kOptionScreenSwitchDelay) { - return "switchDelay"; - } - if (id == kOptionScreenSwitchTwoTap) { - return "switchDoubleTap"; - } - if (id == kOptionScreenSwitchNeedsShift) { - return "switchNeedsShift"; - } - if (id == kOptionScreenSwitchNeedsControl) { - return "switchNeedsControl"; - } - if (id == kOptionScreenSwitchNeedsAlt) { - return "switchNeedsAlt"; - } - if (id == kOptionXTestXineramaUnaware) { - return "xtestIsXineramaUnaware"; - } - if (id == kOptionRelativeMouseMoves) { - return "relativeMouseMoves"; - } - if (id == kOptionWin32KeepForeground) { - return "win32KeepForeground"; - } - if (id == kOptionScreenPreserveFocus) { - return "preserveFocus"; - } - if (id == kOptionDisableLockToScreen) { - return "disableLockToScreen"; - } - if (id == kOptionClipboardSharing) { - return "clipboardSharing"; - } - if (id == kOptionClipboardSharingSize) { - return "clipboardSharingSize"; - } - return NULL; +Config::const_iterator Config::end() const { + return const_iterator(m_map.end()); } -String -Config::getOptionValue(OptionID id, OptionValue value) -{ - if (id == kOptionHalfDuplexCapsLock || - id == kOptionHalfDuplexNumLock || - id == kOptionHalfDuplexScrollLock || - id == kOptionScreenSwitchNeedsShift || - id == kOptionScreenSwitchNeedsControl || - id == kOptionScreenSwitchNeedsAlt || - id == kOptionXTestXineramaUnaware || - id == kOptionRelativeMouseMoves || - id == kOptionWin32KeepForeground || - id == kOptionScreenPreserveFocus || - id == kOptionClipboardSharing || - id == kOptionClipboardSharingSize) { - return (value != 0) ? "true" : "false"; - } - if (id == kOptionModifierMapForShift || - id == kOptionModifierMapForControl || - id == kOptionModifierMapForAlt || - id == kOptionModifierMapForAltGr || - id == kOptionModifierMapForMeta || - id == kOptionModifierMapForSuper) { - switch (value) { - case kKeyModifierIDShift: - return "shift"; - - case kKeyModifierIDControl: - return "ctrl"; - - case kKeyModifierIDAlt: - return "alt"; - - case kKeyModifierIDAltGr: - return "altgr"; - - case kKeyModifierIDMeta: - return "meta"; - - case kKeyModifierIDSuper: - return "super"; - - default: - return "none"; - } - } - if (id == kOptionHeartbeat || - id == kOptionScreenSwitchCornerSize || - id == kOptionScreenSwitchDelay || - id == kOptionScreenSwitchTwoTap) { - return synergy::string::sprintf("%d", value); - } - if (id == kOptionScreenSwitchCorners) { - std::string result("none"); - if ((value & kTopLeftMask) != 0) { - result += " +top-left"; - } - if ((value & kTopRightMask) != 0) { - result += " +top-right"; - } - if ((value & kBottomLeftMask) != 0) { - result += " +bottom-left"; - } - if ((value & kBottomRightMask) != 0) { - result += " +bottom-right"; - } - return result; - } - - return ""; +Config::all_const_iterator Config::beginAll() const { + return m_nameToCanonicalName.begin(); } +Config::all_const_iterator Config::endAll() const { + return m_nameToCanonicalName.end(); +} + +bool Config::isScreen(const String &name) const { + return (m_nameToCanonicalName.count(name) > 0); +} + +bool Config::isCanonicalName(const String &name) const { + return (!name.empty() && CaselessCmp::equal(getCanonicalName(name), name)); +} + +String Config::getCanonicalName(const String &name) const { + NameMap::const_iterator index = m_nameToCanonicalName.find(name); + if (index == m_nameToCanonicalName.end()) { + return String(); + } else { + return index->second; + } +} + +String Config::getNeighbor(const String &srcName, EDirection srcSide, + float position, float *positionOut) const { + assert(srcSide >= kFirstDirection && srcSide <= kLastDirection); + + // find source cell + CellMap::const_iterator index = m_map.find(getCanonicalName(srcName)); + if (index == m_map.end()) { + return String(); + } + + // find edge + const CellEdge *srcEdge, *dstEdge; + if (!index->second.getLink(srcSide, position, srcEdge, dstEdge)) { + // no neighbor + return ""; + } else { + // compute position on neighbor + if (positionOut != NULL) { + *positionOut = dstEdge->inverseTransform(srcEdge->transform(position)); + } + + // return neighbor's name + return getCanonicalName(dstEdge->getName()); + } +} + +bool Config::hasNeighbor(const String &srcName, EDirection srcSide) const { + return hasNeighbor(srcName, srcSide, 0.0f, 1.0f); +} + +bool Config::hasNeighbor(const String &srcName, EDirection srcSide, float start, + float end) const { + assert(srcSide >= kFirstDirection && srcSide <= kLastDirection); + + // find source cell + CellMap::const_iterator index = m_map.find(getCanonicalName(srcName)); + if (index == m_map.end()) { + return false; + } + + return index->second.overlaps(CellEdge(srcSide, Interval(start, end))); +} + +Config::link_const_iterator Config::beginNeighbor(const String &srcName) const { + CellMap::const_iterator index = m_map.find(getCanonicalName(srcName)); + assert(index != m_map.end()); + return index->second.begin(); +} + +Config::link_const_iterator Config::endNeighbor(const String &srcName) const { + CellMap::const_iterator index = m_map.find(getCanonicalName(srcName)); + assert(index != m_map.end()); + return index->second.end(); +} + +const NetworkAddress &Config::getSynergyAddress() const { + return m_synergyAddress; +} + +const Config::ScreenOptions *Config::getOptions(const String &name) const { + // find options + const ScreenOptions *options = NULL; + if (name.empty()) { + options = &m_globalOptions; + } else { + CellMap::const_iterator index = m_map.find(name); + if (index != m_map.end()) { + options = &index->second.m_options; + } + } + + // return options + return options; +} + +bool Config::hasLockToScreenAction() const { return m_hasLockToScreenAction; } + +bool Config::operator==(const Config &x) const { + if (m_synergyAddress != x.m_synergyAddress) { + return false; + } + if (m_map.size() != x.m_map.size()) { + return false; + } + if (m_nameToCanonicalName.size() != x.m_nameToCanonicalName.size()) { + return false; + } + + // compare global options + if (m_globalOptions != x.m_globalOptions) { + return false; + } + + auto index2map = x.m_map.cbegin(); + for (auto const &index1 : m_map) { + // compare names + if (!CaselessCmp::equal(index1.first, index2map->first)) { + return false; + } + + // compare cells + if (index1.second != index2map->second) { + return false; + } + ++index2map; + } + + auto index2 = x.m_nameToCanonicalName.cbegin(); + for (auto const &index1 : m_nameToCanonicalName) { + if (index2 == x.m_nameToCanonicalName.cend()) { + return false; // second source ended + } + if (!CaselessCmp::equal(index1.first, index2->first) || + !CaselessCmp::equal(index1.second, index2->second)) { + return false; + } + ++index2; + } + + // compare input filters + if (m_inputFilter != x.m_inputFilter) { + return false; + } + + return true; +} + +bool Config::operator!=(const Config &x) const { return !operator==(x); } + +void Config::read(ConfigReadContext &context) { + Config tmp(m_events); + while (context.getStream()) { + tmp.readSection(context); + } + *this = tmp; +} + +const char *Config::dirName(EDirection dir) { + static const char *s_name[] = {"left", "right", "up", "down"}; + + assert(dir >= kFirstDirection && dir <= kLastDirection); + + return s_name[dir - kFirstDirection]; +} + +InputFilter *Config::getInputFilter() { return &m_inputFilter; } + +String Config::formatInterval(const Interval &x) { + if (x.first == 0.0f && x.second == 1.0f) { + return ""; + } + return synergy::string::sprintf("(%d,%d)", (int)(x.first * 100.0f + 0.5f), + (int)(x.second * 100.0f + 0.5f)); +} + +String Config::getClientAddress() const { return m_clientAddress; } + +bool Config::isClientMode() const { return (!m_clientAddress.empty()); } + +void Config::readSection(ConfigReadContext &s) { + static const char s_section[] = "section:"; + static const char s_options[] = "options"; + static const char s_screens[] = "screens"; + static const char s_links[] = "links"; + static const char s_aliases[] = "aliases"; + + String line; + if (!s.readLine(line)) { + // no more sections + return; + } + + // should be a section header + if (line.find(s_section) != 0) { + throw XConfigRead(s, "found data outside section"); + } + + // get section name + String::size_type i = line.find_first_not_of(" \t", sizeof(s_section) - 1); + if (i == String::npos) { + throw XConfigRead(s, "section name is missing"); + } + String name = line.substr(i); + i = name.find_first_of(" \t"); + if (i != String::npos) { + throw XConfigRead(s, "unexpected data after section name"); + } + + // read section + if (name == s_options) { + readSectionOptions(s); + } else if (name == s_screens) { + readSectionScreens(s); + } else if (name == s_links) { + readSectionLinks(s); + } else if (name == s_aliases) { + readSectionAliases(s); + } else { + throw XConfigRead(s, "unknown section name \"%{1}\"", name); + } +} + +void Config::readSectionOptions(ConfigReadContext &s) { + String line; + while (s.readLine(line)) { + // check for end of section + if (line == "end") { + return; + } + + // parse argument: `nameAndArgs = [values][;[values]]' + // nameAndArgs := [(arg[,...])] + // values := valueAndArgs[,valueAndArgs]... + // valueAndArgs := [(arg[,...])] + String::size_type i = 0; + String name, value; + ConfigReadContext::ArgList nameArgs, valueArgs; + s.parseNameWithArgs("name", line, "=", i, name, nameArgs); + ++i; + s.parseNameWithArgs("value", line, ",;\n", i, value, valueArgs); + + bool handled = true; + if (name == "address") { + try { + m_synergyAddress = NetworkAddress(value, kDefaultPort); + m_synergyAddress.resolve(); + } catch (XSocketAddress &e) { + throw XConfigRead(s, String("invalid address argument ") + e.what()); + } + } else if (name == "heartbeat") { + addOption("", kOptionHeartbeat, s.parseInt(value)); + } else if (name == "switchCorners") { + addOption("", kOptionScreenSwitchCorners, s.parseCorners(value)); + } else if (name == "switchCornerSize") { + addOption("", kOptionScreenSwitchCornerSize, s.parseInt(value)); + } else if (name == "switchDelay") { + addOption("", kOptionScreenSwitchDelay, s.parseInt(value)); + } else if (name == "switchDoubleTap") { + addOption("", kOptionScreenSwitchTwoTap, s.parseInt(value)); + } else if (name == "switchNeedsShift") { + addOption("", kOptionScreenSwitchNeedsShift, s.parseBoolean(value)); + } else if (name == "switchNeedsControl") { + addOption("", kOptionScreenSwitchNeedsControl, s.parseBoolean(value)); + } else if (name == "switchNeedsAlt") { + addOption("", kOptionScreenSwitchNeedsAlt, s.parseBoolean(value)); + } else if (name == "relativeMouseMoves") { + addOption("", kOptionRelativeMouseMoves, s.parseBoolean(value)); + } else if (name == "win32KeepForeground") { + addOption("", kOptionWin32KeepForeground, s.parseBoolean(value)); + } else if (name == "disableLockToScreen") { + addOption("", kOptionDisableLockToScreen, s.parseBoolean(value)); + } else if (name == "clipboardSharing") { + addOption("", kOptionClipboardSharing, s.parseBoolean(value)); + } else if (name == "clipboardSharingSize") { + addOption("", kOptionClipboardSharingSize, s.parseInt(value)); + } else if (name == "clientAddress") { + m_clientAddress = value; + } else { + handled = false; + } + + if (handled) { + // make sure handled options aren't followed by more values + if (i < line.size() && (line[i] == ',' || line[i] == ';')) { + throw XConfigRead(s, "to many arguments to %s", name.c_str()); + } + } else { + // make filter rule + InputFilter::Rule rule(parseCondition(s, name, nameArgs)); + + // save first action (if any) + if (!value.empty() || line[i] != ';') { + parseAction(s, value, valueArgs, rule, true); + } + + // get remaining activate actions + while (i < line.length() && line[i] != ';') { + ++i; + s.parseNameWithArgs("value", line, ",;\n", i, value, valueArgs); + parseAction(s, value, valueArgs, rule, true); + } + + // get deactivate actions + if (i < line.length() && line[i] == ';') { + // allow trailing ';' + i = line.find_first_not_of(" \t", i + 1); + if (i == String::npos) { + i = line.length(); + } else { + --i; + } + + // get actions + while (i < line.length()) { + ++i; + s.parseNameWithArgs("value", line, ",\n", i, value, valueArgs); + parseAction(s, value, valueArgs, rule, false); + } + } + + // add rule + m_inputFilter.addFilterRule(rule); + } + } + throw XConfigRead(s, "unexpected end of options section"); +} + +void Config::readSectionScreens(ConfigReadContext &s) { + String line; + String screen; + while (s.readLine(line)) { + // check for end of section + if (line == "end") { + return; + } + + // see if it's the next screen + if (line[line.size() - 1] == ':') { + // strip : + screen = line.substr(0, line.size() - 1); + + // verify validity of screen name + if (!isValidScreenName(screen)) { + throw XConfigRead(s, "invalid screen name \"%{1}\"", screen); + } + + // add the screen to the configuration + if (!addScreen(screen)) { + throw XConfigRead(s, "duplicate screen name \"%{1}\"", screen); + } + } else if (screen.empty()) { + throw XConfigRead(s, "argument before first screen"); + } else { + // parse argument: `=' + String::size_type i = line.find_first_of(" \t="); + if (i == 0) { + throw XConfigRead(s, "missing argument name"); + } + if (i == String::npos) { + throw XConfigRead(s, "missing ="); + } + String name = line.substr(0, i); + i = line.find_first_not_of(" \t", i); + if (i == String::npos || line[i] != '=') { + throw XConfigRead(s, "missing ="); + } + i = line.find_first_not_of(" \t", i + 1); + String value; + if (i != String::npos) { + value = line.substr(i); + } + + // handle argument + if (name == "halfDuplexCapsLock") { + addOption(screen, kOptionHalfDuplexCapsLock, s.parseBoolean(value)); + } else if (name == "halfDuplexNumLock") { + addOption(screen, kOptionHalfDuplexNumLock, s.parseBoolean(value)); + } else if (name == "halfDuplexScrollLock") { + addOption(screen, kOptionHalfDuplexScrollLock, s.parseBoolean(value)); + } else if (name == "shift") { + addOption(screen, kOptionModifierMapForShift, + s.parseModifierKey(value)); + } else if (name == "ctrl") { + addOption(screen, kOptionModifierMapForControl, + s.parseModifierKey(value)); + } else if (name == "alt") { + addOption(screen, kOptionModifierMapForAlt, s.parseModifierKey(value)); + } else if (name == "altgr") { + addOption(screen, kOptionModifierMapForAltGr, + s.parseModifierKey(value)); + } else if (name == "meta") { + addOption(screen, kOptionModifierMapForMeta, s.parseModifierKey(value)); + } else if (name == "super") { + addOption(screen, kOptionModifierMapForSuper, + s.parseModifierKey(value)); + } else if (name == "xtestIsXineramaUnaware") { + addOption(screen, kOptionXTestXineramaUnaware, s.parseBoolean(value)); + } else if (name == "switchCorners") { + addOption(screen, kOptionScreenSwitchCorners, s.parseCorners(value)); + } else if (name == "switchCornerSize") { + addOption(screen, kOptionScreenSwitchCornerSize, s.parseInt(value)); + } else if (name == "preserveFocus") { + addOption(screen, kOptionScreenPreserveFocus, s.parseBoolean(value)); + } else { + // unknown argument + throw XConfigRead(s, "unknown argument \"%{1}\"", name); + } + } + } + throw XConfigRead(s, "unexpected end of screens section"); +} + +void Config::readSectionLinks(ConfigReadContext &s) { + String line; + String screen; + while (s.readLine(line)) { + // check for end of section + if (line == "end") { + return; + } + + // see if it's the next screen + if (line[line.size() - 1] == ':') { + // strip : + screen = line.substr(0, line.size() - 1); + + // verify we know about the screen + if (!isScreen(screen)) { + throw XConfigRead(s, "unknown screen name \"%{1}\"", screen); + } + if (!isCanonicalName(screen)) { + throw XConfigRead(s, "cannot use screen name alias here"); + } + } else if (screen.empty()) { + throw XConfigRead(s, "argument before first screen"); + } else { + // parse argument: `[(,)]=[(,)]' + // the stuff in brackets is optional. interval values must be + // in the range [0,100] and start < end. if not given the + // interval is taken to be (0,100). + String::size_type i = 0; + String side, dstScreen, srcArgString, dstArgString; + ConfigReadContext::ArgList srcArgs, dstArgs; + s.parseNameWithArgs("link", line, "=", i, side, srcArgs); + ++i; + s.parseNameWithArgs("screen", line, "", i, dstScreen, dstArgs); + Interval srcInterval(s.parseInterval(srcArgs)); + Interval dstInterval(s.parseInterval(dstArgs)); + + // handle argument + EDirection dir; + if (side == "left") { + dir = kLeft; + } else if (side == "right") { + dir = kRight; + } else if (side == "up") { + dir = kTop; + } else if (side == "down") { + dir = kBottom; + } else { + // unknown argument + throw XConfigRead(s, "unknown side \"%{1}\" in link", side); + } + if (!isScreen(dstScreen)) { + throw XConfigRead(s, "unknown screen name \"%{1}\"", dstScreen); + } + if (!connect(screen, dir, srcInterval.first, srcInterval.second, + dstScreen, dstInterval.first, dstInterval.second)) { + throw XConfigRead(s, "overlapping range"); + } + } + } + throw XConfigRead(s, "unexpected end of links section"); +} + +void Config::readSectionAliases(ConfigReadContext &s) { + String line; + String screen; + while (s.readLine(line)) { + // check for end of section + if (line == "end") { + return; + } + + // see if it's the next screen + if (line[line.size() - 1] == ':') { + // strip : + screen = line.substr(0, line.size() - 1); + + // verify we know about the screen + if (!isScreen(screen)) { + throw XConfigRead(s, "unknown screen name \"%{1}\"", screen); + } + if (!isCanonicalName(screen)) { + throw XConfigRead(s, "cannot use screen name alias here"); + } + } else if (screen.empty()) { + throw XConfigRead(s, "argument before first screen"); + } else { + // verify validity of screen name + if (!isValidScreenName(line)) { + throw XConfigRead(s, "invalid screen alias \"%{1}\"", line); + } + + // add alias + if (!addAlias(screen, line)) { + throw XConfigRead(s, "alias \"%{1}\" is already used", line); + } + } + } + throw XConfigRead(s, "unexpected end of aliases section"); +} + +InputFilter::Condition * +Config::parseCondition(ConfigReadContext &s, const String &name, + const std::vector &args) { + if (name == "keystroke") { + if (args.size() != 1) { + throw XConfigRead(s, "syntax for condition: keystroke(modifiers+key)"); + } + + IPlatformScreen::KeyInfo *keyInfo = s.parseKeystroke(args[0]); + + return new InputFilter::KeystrokeCondition(m_events, keyInfo); + } + + if (name == "mousebutton") { + if (args.size() != 1) { + throw XConfigRead(s, + "syntax for condition: mousebutton(modifiers+button)"); + } + + IPlatformScreen::ButtonInfo *mouseInfo = s.parseMouse(args[0]); + + return new InputFilter::MouseButtonCondition(m_events, mouseInfo); + } + + if (name == "connect") { + if (args.size() != 1) { + throw XConfigRead(s, "syntax for condition: connect([screen])"); + } + + String screen = args[0]; + if (isScreen(screen)) { + screen = getCanonicalName(screen); + } else if (!screen.empty()) { + throw XConfigRead(s, "unknown screen name \"%{1}\" in connect", screen); + } + + return new InputFilter::ScreenConnectedCondition(m_events, screen); + } + + throw XConfigRead(s, "unknown argument \"%{1}\"", name); +} + +void Config::parseAction(ConfigReadContext &s, const String &name, + const std::vector &args, + InputFilter::Rule &rule, bool activate) { + InputFilter::Action *action; + + if (name == "keystroke" || name == "keyDown" || name == "keyUp") { + if (args.size() < 1 || args.size() > 2) { + throw XConfigRead( + s, "syntax for action: keystroke(modifiers+key[,screens])"); + } + + IPlatformScreen::KeyInfo *keyInfo; + if (args.size() == 1) { + keyInfo = s.parseKeystroke(args[0]); + } else { + std::set screens; + parseScreens(s, args[1], screens); + keyInfo = s.parseKeystroke(args[0], screens); + } + + if (name == "keystroke") { + IPlatformScreen::KeyInfo *keyInfo2 = IKeyState::KeyInfo::alloc(*keyInfo); + action = new InputFilter::KeystrokeAction(m_events, keyInfo2, true); + rule.adoptAction(action, true); + action = new InputFilter::KeystrokeAction(m_events, keyInfo, false); + activate = false; + } else if (name == "keyDown") { + action = new InputFilter::KeystrokeAction(m_events, keyInfo, true); + } else { + action = new InputFilter::KeystrokeAction(m_events, keyInfo, false); + } + } + + else if (name == "mousebutton" || name == "mouseDown" || name == "mouseUp") { + if (args.size() != 1) { + throw XConfigRead(s, "syntax for action: mousebutton(modifiers+button)"); + } + + IPlatformScreen::ButtonInfo *mouseInfo = s.parseMouse(args[0]); + + if (name == "mousebutton") { + IPlatformScreen::ButtonInfo *mouseInfo2 = + IPlatformScreen::ButtonInfo::alloc(*mouseInfo); + action = new InputFilter::MouseButtonAction(m_events, mouseInfo2, true); + rule.adoptAction(action, true); + action = new InputFilter::MouseButtonAction(m_events, mouseInfo, false); + activate = false; + } else if (name == "mouseDown") { + action = new InputFilter::MouseButtonAction(m_events, mouseInfo, true); + } else { + action = new InputFilter::MouseButtonAction(m_events, mouseInfo, false); + } + } + + /* XXX -- not supported + else if (name == "modifier") { + if (args.size() != 1) { + throw XConfigRead(s, "syntax for action: + modifier(modifiers)"); + } + + KeyModifierMask mask = s.parseModifier(args[0]); + + action = new InputFilter::ModifierAction(mask, ~mask); + } + */ + + else if (name == "switchToScreen") { + if (args.size() != 1) { + throw XConfigRead(s, "syntax for action: switchToScreen(name)"); + } + + String screen = args[0]; + if (isScreen(screen)) { + screen = getCanonicalName(screen); + } else if (!screen.empty()) { + throw XConfigRead(s, "unknown screen name in switchToScreen"); + } + + action = new InputFilter::SwitchToScreenAction(m_events, screen); + } + + else if (name == "switchInDirection") { + if (args.size() != 1) { + throw XConfigRead( + s, "syntax for action: switchInDirection()"); + } + + EDirection direction; + if (args[0] == "left") { + direction = kLeft; + } else if (args[0] == "right") { + direction = kRight; + } else if (args[0] == "up") { + direction = kTop; + } else if (args[0] == "down") { + direction = kBottom; + } else { + throw XConfigRead(s, "unknown direction \"%{1}\" in switchToScreen", + args[0]); + } + + action = new InputFilter::SwitchInDirectionAction(m_events, direction); + } + + else if (name == "lockCursorToScreen") { + if (args.size() > 1) { + throw XConfigRead( + s, "syntax for action: lockCursorToScreen([{off|on|toggle}])"); + } + + InputFilter::LockCursorToScreenAction::Mode mode = + InputFilter::LockCursorToScreenAction::kToggle; + if (args.size() == 1) { + if (args[0] == "off") { + mode = InputFilter::LockCursorToScreenAction::kOff; + } else if (args[0] == "on") { + mode = InputFilter::LockCursorToScreenAction::kOn; + } else if (args[0] == "toggle") { + mode = InputFilter::LockCursorToScreenAction::kToggle; + } else { + throw XConfigRead( + s, "syntax for action: lockCursorToScreen([{off|on|toggle}])"); + } + } + + if (mode != InputFilter::LockCursorToScreenAction::kOff) { + m_hasLockToScreenAction = true; + } + + action = new InputFilter::LockCursorToScreenAction(m_events, mode); + } + + else if (name == "restartServer") { + if (args.size() > 1) { + throw XConfigRead(s, "syntax for action: restartServer([{{restart}}])"); + } + + InputFilter::RestartServer::Mode mode = InputFilter::RestartServer::restart; + + if (args.size() == 1) { + if (args[0] == "restart") { + mode = InputFilter::RestartServer::restart; + } else { + throw XConfigRead(s, "syntax for action: restartServer([{restart}])"); + } + } + + action = new InputFilter::RestartServer(m_events, mode); + } + + else if (name == "keyboardBroadcast") { + if (args.size() > 2) { + throw XConfigRead( + s, + "syntax for action: keyboardBroadcast([{off|on|toggle}[,screens]])"); + } + + InputFilter::KeyboardBroadcastAction::Mode mode = + InputFilter::KeyboardBroadcastAction::kToggle; + if (args.size() >= 1) { + if (args[0] == "off") { + mode = InputFilter::KeyboardBroadcastAction::kOff; + } else if (args[0] == "on") { + mode = InputFilter::KeyboardBroadcastAction::kOn; + } else if (args[0] == "toggle") { + mode = InputFilter::KeyboardBroadcastAction::kToggle; + } else { + throw XConfigRead(s, "syntax for action: " + "keyboardBroadcast([{off|on|toggle}[,screens]])"); + } + } + + std::set screens; + if (args.size() >= 2) { + parseScreens(s, args[1], screens); + } + + action = new InputFilter::KeyboardBroadcastAction(m_events, mode, screens); + } + + else { + throw XConfigRead(s, "unknown action argument \"%{1}\"", name); + } + + rule.adoptAction(action, activate); +} + +void Config::parseScreens(ConfigReadContext &c, const String &s, + std::set &screens) const { + screens.clear(); + + String::size_type i = 0; + while (i < s.size()) { + // find end of next screen name + String::size_type j = s.find(':', i); + if (j == String::npos) { + j = s.size(); + } + + // extract name + String rawName; + i = s.find_first_not_of(" \t", i); + if (i < j) { + rawName = s.substr(i, s.find_last_not_of(" \t", j - 1) - i + 1); + } + + // add name + if (rawName == "*") { + screens.insert("*"); + } else if (!rawName.empty()) { + String name = getCanonicalName(rawName); + if (name.empty()) { + throw XConfigRead(c, "unknown screen name \"%{1}\"", rawName); + } + screens.insert(name); + } + + // next + i = j + 1; + } +} + +const char *Config::getOptionName(OptionID id) { + if (id == kOptionHalfDuplexCapsLock) { + return "halfDuplexCapsLock"; + } + if (id == kOptionHalfDuplexNumLock) { + return "halfDuplexNumLock"; + } + if (id == kOptionHalfDuplexScrollLock) { + return "halfDuplexScrollLock"; + } + if (id == kOptionModifierMapForShift) { + return "shift"; + } + if (id == kOptionModifierMapForControl) { + return "ctrl"; + } + if (id == kOptionModifierMapForAlt) { + return "alt"; + } + if (id == kOptionModifierMapForAltGr) { + return "altgr"; + } + if (id == kOptionModifierMapForMeta) { + return "meta"; + } + if (id == kOptionModifierMapForSuper) { + return "super"; + } + if (id == kOptionHeartbeat) { + return "heartbeat"; + } + if (id == kOptionScreenSwitchCorners) { + return "switchCorners"; + } + if (id == kOptionScreenSwitchCornerSize) { + return "switchCornerSize"; + } + if (id == kOptionScreenSwitchDelay) { + return "switchDelay"; + } + if (id == kOptionScreenSwitchTwoTap) { + return "switchDoubleTap"; + } + if (id == kOptionScreenSwitchNeedsShift) { + return "switchNeedsShift"; + } + if (id == kOptionScreenSwitchNeedsControl) { + return "switchNeedsControl"; + } + if (id == kOptionScreenSwitchNeedsAlt) { + return "switchNeedsAlt"; + } + if (id == kOptionXTestXineramaUnaware) { + return "xtestIsXineramaUnaware"; + } + if (id == kOptionRelativeMouseMoves) { + return "relativeMouseMoves"; + } + if (id == kOptionWin32KeepForeground) { + return "win32KeepForeground"; + } + if (id == kOptionScreenPreserveFocus) { + return "preserveFocus"; + } + if (id == kOptionDisableLockToScreen) { + return "disableLockToScreen"; + } + if (id == kOptionClipboardSharing) { + return "clipboardSharing"; + } + if (id == kOptionClipboardSharingSize) { + return "clipboardSharingSize"; + } + return NULL; +} + +String Config::getOptionValue(OptionID id, OptionValue value) { + if (id == kOptionHalfDuplexCapsLock || id == kOptionHalfDuplexNumLock || + id == kOptionHalfDuplexScrollLock || + id == kOptionScreenSwitchNeedsShift || + id == kOptionScreenSwitchNeedsControl || + id == kOptionScreenSwitchNeedsAlt || id == kOptionXTestXineramaUnaware || + id == kOptionRelativeMouseMoves || id == kOptionWin32KeepForeground || + id == kOptionScreenPreserveFocus || id == kOptionClipboardSharing || + id == kOptionClipboardSharingSize) { + return (value != 0) ? "true" : "false"; + } + if (id == kOptionModifierMapForShift || id == kOptionModifierMapForControl || + id == kOptionModifierMapForAlt || id == kOptionModifierMapForAltGr || + id == kOptionModifierMapForMeta || id == kOptionModifierMapForSuper) { + switch (value) { + case kKeyModifierIDShift: + return "shift"; + + case kKeyModifierIDControl: + return "ctrl"; + + case kKeyModifierIDAlt: + return "alt"; + + case kKeyModifierIDAltGr: + return "altgr"; + + case kKeyModifierIDMeta: + return "meta"; + + case kKeyModifierIDSuper: + return "super"; + + default: + return "none"; + } + } + if (id == kOptionHeartbeat || id == kOptionScreenSwitchCornerSize || + id == kOptionScreenSwitchDelay || id == kOptionScreenSwitchTwoTap) { + return synergy::string::sprintf("%d", value); + } + if (id == kOptionScreenSwitchCorners) { + std::string result("none"); + if ((value & kTopLeftMask) != 0) { + result += " +top-left"; + } + if ((value & kTopRightMask) != 0) { + result += " +top-right"; + } + if ((value & kBottomLeftMask) != 0) { + result += " +bottom-left"; + } + if ((value & kBottomRightMask) != 0) { + result += " +bottom-right"; + } + return result; + } + + return ""; +} // // Config::Name // -Config::Name::Name(Config* config, const String& name) : - m_config(config), - m_name(config->getCanonicalName(name)) -{ - // do nothing +Config::Name::Name(Config *config, const String &name) + : m_config(config), m_name(config->getCanonicalName(name)) { + // do nothing } -bool -Config::Name::operator==(const String& name) const -{ - String canonical = m_config->getCanonicalName(name); - return CaselessCmp::equal(canonical, m_name); +bool Config::Name::operator==(const String &name) const { + String canonical = m_config->getCanonicalName(name); + return CaselessCmp::equal(canonical, m_name); } - // // Config::CellEdge // -Config::CellEdge::CellEdge(EDirection side, float position) -{ - init("", side, Interval(position, position)); +Config::CellEdge::CellEdge(EDirection side, float position) { + init("", side, Interval(position, position)); } -Config::CellEdge::CellEdge(EDirection side, const Interval& interval) -{ - assert(interval.first >= 0.0f); - assert(interval.second <= 1.0f); - assert(interval.first < interval.second); +Config::CellEdge::CellEdge(EDirection side, const Interval &interval) { + assert(interval.first >= 0.0f); + assert(interval.second <= 1.0f); + assert(interval.first < interval.second); - init("", side, interval); + init("", side, interval); } -Config::CellEdge::CellEdge(const String& name, - EDirection side, const Interval& interval) -{ - assert(interval.first >= 0.0f); - assert(interval.second <= 1.0f); - assert(interval.first < interval.second); +Config::CellEdge::CellEdge(const String &name, EDirection side, + const Interval &interval) { + assert(interval.first >= 0.0f); + assert(interval.second <= 1.0f); + assert(interval.first < interval.second); - init(name, side, interval); + init(name, side, interval); } -Config::CellEdge::~CellEdge() -{ - // do nothing +Config::CellEdge::~CellEdge() { + // do nothing } -void -Config::CellEdge::init(const String& name, EDirection side, - const Interval& interval) -{ - assert(side != kNoDirection); +void Config::CellEdge::init(const String &name, EDirection side, + const Interval &interval) { + assert(side != kNoDirection); - m_name = name; - m_side = side; - m_interval = interval; + m_name = name; + m_side = side; + m_interval = interval; } -Config::Interval -Config::CellEdge::getInterval() const -{ - return m_interval; +Config::Interval Config::CellEdge::getInterval() const { return m_interval; } + +void Config::CellEdge::setName(const String &newName) { m_name = newName; } + +String Config::CellEdge::getName() const { return m_name; } + +EDirection Config::CellEdge::getSide() const { return m_side; } + +bool Config::CellEdge::overlaps(const CellEdge &edge) const { + const Interval &x = m_interval; + const Interval &y = edge.m_interval; + if (m_side != edge.m_side) { + return false; + } + return (x.first >= y.first && x.first < y.second) || + (x.second > y.first && x.second <= y.second) || + (y.first >= x.first && y.first < x.second) || + (y.second > x.first && y.second <= x.second); } -void -Config::CellEdge::setName(const String& newName) -{ - m_name = newName; +bool Config::CellEdge::isInside(float x) const { + return (x >= m_interval.first && x < m_interval.second); } -String -Config::CellEdge::getName() const -{ - return m_name; +float Config::CellEdge::transform(float x) const { + return (x - m_interval.first) / (m_interval.second - m_interval.first); } -EDirection -Config::CellEdge::getSide() const -{ - return m_side; +float Config::CellEdge::inverseTransform(float x) const { + return x * (m_interval.second - m_interval.first) + m_interval.first; } -bool -Config::CellEdge::overlaps(const CellEdge& edge) const -{ - const Interval& x = m_interval; - const Interval& y = edge.m_interval; - if (m_side != edge.m_side) { - return false; - } - return (x.first >= y.first && x.first < y.second) || - (x.second > y.first && x.second <= y.second) || - (y.first >= x.first && y.first < x.second) || - (y.second > x.first && y.second <= x.second); +bool Config::CellEdge::operator<(const CellEdge &o) const { + if (static_cast(m_side) < static_cast(o.m_side)) { + return true; + } else if (static_cast(m_side) > static_cast(o.m_side)) { + return false; + } + + return (m_interval.first < o.m_interval.first); } -bool -Config::CellEdge::isInside(float x) const -{ - return (x >= m_interval.first && x < m_interval.second); +bool Config::CellEdge::operator==(const CellEdge &x) const { + return (m_side == x.m_side && m_interval == x.m_interval); } -float -Config::CellEdge::transform(float x) const -{ - return (x - m_interval.first) / (m_interval.second - m_interval.first); +bool Config::CellEdge::operator!=(const CellEdge &x) const { + return !operator==(x); } - -float -Config::CellEdge::inverseTransform(float x) const -{ - return x * (m_interval.second - m_interval.first) + m_interval.first; -} - -bool -Config::CellEdge::operator<(const CellEdge& o) const -{ - if (static_cast(m_side) < static_cast(o.m_side)) { - return true; - } - else if (static_cast(m_side) > static_cast(o.m_side)) { - return false; - } - - return (m_interval.first < o.m_interval.first); -} - -bool -Config::CellEdge::operator==(const CellEdge& x) const -{ - return (m_side == x.m_side && m_interval == x.m_interval); -} - -bool -Config::CellEdge::operator!=(const CellEdge& x) const -{ - return !operator==(x); -} - - // // Config::Cell // -bool -Config::Cell::add(const CellEdge& src, const CellEdge& dst) -{ - // cannot add an edge that overlaps other existing edges but we - // can exactly replace an edge. - if (!hasEdge(src) && overlaps(src)) { - return false; - } +bool Config::Cell::add(const CellEdge &src, const CellEdge &dst) { + // cannot add an edge that overlaps other existing edges but we + // can exactly replace an edge. + if (!hasEdge(src) && overlaps(src)) { + return false; + } - m_neighbors.erase(src); - m_neighbors.insert(std::make_pair(src, dst)); - return true; + m_neighbors.erase(src); + m_neighbors.insert(std::make_pair(src, dst)); + return true; } -void -Config::Cell::remove(EDirection side) -{ - for (EdgeLinks::iterator j = m_neighbors.begin(); - j != m_neighbors.end(); ) { - if (j->first.getSide() == side) { - m_neighbors.erase(j++); - } - else { - ++j; - } - } +void Config::Cell::remove(EDirection side) { + for (EdgeLinks::iterator j = m_neighbors.begin(); j != m_neighbors.end();) { + if (j->first.getSide() == side) { + m_neighbors.erase(j++); + } else { + ++j; + } + } } -void -Config::Cell::remove(EDirection side, float position) -{ - for (EdgeLinks::iterator j = m_neighbors.begin(); - j != m_neighbors.end(); ++j) { - if (j->first.getSide() == side && j->first.isInside(position)) { - m_neighbors.erase(j); - break; - } - } +void Config::Cell::remove(EDirection side, float position) { + for (EdgeLinks::iterator j = m_neighbors.begin(); j != m_neighbors.end(); + ++j) { + if (j->first.getSide() == side && j->first.isInside(position)) { + m_neighbors.erase(j); + break; + } + } } -void -Config::Cell::remove(const Name& name) -{ - for (EdgeLinks::iterator j = m_neighbors.begin(); - j != m_neighbors.end(); ) { - if (name == j->second.getName()) { - m_neighbors.erase(j++); - } - else { - ++j; - } - } +void Config::Cell::remove(const Name &name) { + for (EdgeLinks::iterator j = m_neighbors.begin(); j != m_neighbors.end();) { + if (name == j->second.getName()) { + m_neighbors.erase(j++); + } else { + ++j; + } + } } -void -Config::Cell::rename(const Name& oldName, const String& newName) -{ - for (EdgeLinks::iterator j = m_neighbors.begin(); - j != m_neighbors.end(); ++j) { - if (oldName == j->second.getName()) { - j->second.setName(newName); - } - } +void Config::Cell::rename(const Name &oldName, const String &newName) { + for (EdgeLinks::iterator j = m_neighbors.begin(); j != m_neighbors.end(); + ++j) { + if (oldName == j->second.getName()) { + j->second.setName(newName); + } + } } -bool -Config::Cell::hasEdge(const CellEdge& edge) const -{ - EdgeLinks::const_iterator i = m_neighbors.find(edge); - return (i != m_neighbors.end() && i->first == edge); +bool Config::Cell::hasEdge(const CellEdge &edge) const { + EdgeLinks::const_iterator i = m_neighbors.find(edge); + return (i != m_neighbors.end() && i->first == edge); } -bool -Config::Cell::overlaps(const CellEdge& edge) const -{ - EdgeLinks::const_iterator i = m_neighbors.upper_bound(edge); - if (i != m_neighbors.end() && i->first.overlaps(edge)) { - return true; - } - if (i != m_neighbors.begin() && (--i)->first.overlaps(edge)) { - return true; - } - return false; +bool Config::Cell::overlaps(const CellEdge &edge) const { + EdgeLinks::const_iterator i = m_neighbors.upper_bound(edge); + if (i != m_neighbors.end() && i->first.overlaps(edge)) { + return true; + } + if (i != m_neighbors.begin() && (--i)->first.overlaps(edge)) { + return true; + } + return false; } -bool -Config::Cell::getLink(EDirection side, float position, - const CellEdge*& src, const CellEdge*& dst) const -{ - CellEdge edge(side, position); - EdgeLinks::const_iterator i = m_neighbors.upper_bound(edge); - if (i == m_neighbors.begin()) { - return false; - } - --i; - if (i->first.getSide() == side && i->first.isInside(position)) { - src = &i->first; - dst = &i->second; - return true; - } - return false; +bool Config::Cell::getLink(EDirection side, float position, + const CellEdge *&src, const CellEdge *&dst) const { + CellEdge edge(side, position); + EdgeLinks::const_iterator i = m_neighbors.upper_bound(edge); + if (i == m_neighbors.begin()) { + return false; + } + --i; + if (i->first.getSide() == side && i->first.isInside(position)) { + src = &i->first; + dst = &i->second; + return true; + } + return false; } -bool -Config::Cell::operator==(const Cell& x) const -{ - // compare options - if (m_options != x.m_options) { - return false; - } +bool Config::Cell::operator==(const Cell &x) const { + // compare options + if (m_options != x.m_options) { + return false; + } - // compare links - if (m_neighbors.size() != x.m_neighbors.size()) { - return false; - } + // compare links + if (m_neighbors.size() != x.m_neighbors.size()) { + return false; + } - auto index2neighbors = x.m_neighbors.cbegin(); - for (auto const &index1: m_neighbors) { - if (index1.first != index2neighbors->first) { - return false; - } - if (index1.second != index2neighbors->second) { - return false; - } + auto index2neighbors = x.m_neighbors.cbegin(); + for (auto const &index1 : m_neighbors) { + if (index1.first != index2neighbors->first) { + return false; + } + if (index1.second != index2neighbors->second) { + return false; + } - // operator== doesn't compare names. only compare destination - // names. - if (!CaselessCmp::equal(index1.second.getName(), - index2neighbors->second.getName())) { - return false; - } - ++index2neighbors; - } + // operator== doesn't compare names. only compare destination + // names. + if (!CaselessCmp::equal(index1.second.getName(), + index2neighbors->second.getName())) { + return false; + } + ++index2neighbors; + } - return true; + return true; } -bool -Config::Cell::operator!=(const Cell& x) const -{ - return !operator==(x); +bool Config::Cell::operator!=(const Cell &x) const { return !operator==(x); } + +Config::Cell::const_iterator Config::Cell::begin() const { + return m_neighbors.begin(); } -Config::Cell::const_iterator -Config::Cell::begin() const -{ - return m_neighbors.begin(); +Config::Cell::const_iterator Config::Cell::end() const { + return m_neighbors.end(); } -Config::Cell::const_iterator -Config::Cell::end() const -{ - return m_neighbors.end(); -} - - // // Config I/O // -std::istream& -operator>>(std::istream& s, Config& config) -{ - ConfigReadContext context(s); - config.read(context); - return s; +std::istream &operator>>(std::istream &s, Config &config) { + ConfigReadContext context(s); + config.read(context); + return s; } -std::ostream& -operator<<(std::ostream& s, const Config& config) -{ - // screens section - s << "section: screens" << std::endl; - for (Config::const_iterator screen = config.begin(); - screen != config.end(); ++screen) { - s << "\t" << screen->c_str() << ":" << std::endl; - const Config::ScreenOptions* options = config.getOptions(*screen); - if (options != NULL && options->size() > 0) { - for (Config::ScreenOptions::const_iterator - option = options->begin(); - option != options->end(); ++option) { - const char* name = Config::getOptionName(option->first); - String value = Config::getOptionValue(option->first, - option->second); - if (name != NULL && !value.empty()) { - s << "\t\t" << name << " = " << value << std::endl; - } - } - } - } - s << "end" << std::endl; +std::ostream &operator<<(std::ostream &s, const Config &config) { + // screens section + s << "section: screens" << std::endl; + for (Config::const_iterator screen = config.begin(); screen != config.end(); + ++screen) { + s << "\t" << screen->c_str() << ":" << std::endl; + const Config::ScreenOptions *options = config.getOptions(*screen); + if (options != NULL && options->size() > 0) { + for (Config::ScreenOptions::const_iterator option = options->begin(); + option != options->end(); ++option) { + const char *name = Config::getOptionName(option->first); + String value = Config::getOptionValue(option->first, option->second); + if (name != NULL && !value.empty()) { + s << "\t\t" << name << " = " << value << std::endl; + } + } + } + } + s << "end" << std::endl; - // links section - String neighbor; - s << "section: links" << std::endl; - for (Config::const_iterator screen = config.begin(); - screen != config.end(); ++screen) { - s << "\t" << screen->c_str() << ":" << std::endl; + // links section + String neighbor; + s << "section: links" << std::endl; + for (Config::const_iterator screen = config.begin(); screen != config.end(); + ++screen) { + s << "\t" << screen->c_str() << ":" << std::endl; - for (Config::link_const_iterator - link = config.beginNeighbor(*screen), - nend = config.endNeighbor(*screen); link != nend; ++link) { - s << "\t\t" << Config::dirName(link->first.getSide()) << - Config::formatInterval(link->first.getInterval()) << - " = " << link->second.getName().c_str() << - Config::formatInterval(link->second.getInterval()) << - std::endl; - } - } - s << "end" << std::endl; + for (Config::link_const_iterator link = config.beginNeighbor(*screen), + nend = config.endNeighbor(*screen); + link != nend; ++link) { + s << "\t\t" << Config::dirName(link->first.getSide()) + << Config::formatInterval(link->first.getInterval()) << " = " + << link->second.getName().c_str() + << Config::formatInterval(link->second.getInterval()) << std::endl; + } + } + s << "end" << std::endl; - // aliases section (if there are any) - if (config.m_map.size() != config.m_nameToCanonicalName.size()) { - // map canonical to alias - typedef std::multimap CMNameMap; - CMNameMap aliases; - for (Config::NameMap::const_iterator - index = config.m_nameToCanonicalName.begin(); - index != config.m_nameToCanonicalName.end(); - ++index) { - if (index->first != index->second) { - aliases.insert(std::make_pair(index->second, index->first)); - } - } + // aliases section (if there are any) + if (config.m_map.size() != config.m_nameToCanonicalName.size()) { + // map canonical to alias + typedef std::multimap CMNameMap; + CMNameMap aliases; + for (Config::NameMap::const_iterator index = + config.m_nameToCanonicalName.begin(); + index != config.m_nameToCanonicalName.end(); ++index) { + if (index->first != index->second) { + aliases.insert(std::make_pair(index->second, index->first)); + } + } - // dump it - String screen; - s << "section: aliases" << std::endl; - for (CMNameMap::const_iterator index = aliases.begin(); - index != aliases.end(); ++index) { - if (index->first != screen) { - screen = index->first; - s << "\t" << screen.c_str() << ":" << std::endl; - } - s << "\t\t" << index->second.c_str() << std::endl; - } - s << "end" << std::endl; - } + // dump it + String screen; + s << "section: aliases" << std::endl; + for (CMNameMap::const_iterator index = aliases.begin(); + index != aliases.end(); ++index) { + if (index->first != screen) { + screen = index->first; + s << "\t" << screen.c_str() << ":" << std::endl; + } + s << "\t\t" << index->second.c_str() << std::endl; + } + s << "end" << std::endl; + } - // options section - s << "section: options" << std::endl; - const Config::ScreenOptions* options = config.getOptions(""); - if (options != NULL && options->size() > 0) { - for (Config::ScreenOptions::const_iterator - option = options->begin(); - option != options->end(); ++option) { - const char* name = Config::getOptionName(option->first); - String value = Config::getOptionValue(option->first, - option->second); - if (name != NULL && !value.empty()) { - s << "\t" << name << " = " << value << std::endl; - } - } - } - if (config.m_synergyAddress.isValid()) { - s << "\taddress = " << - config.m_synergyAddress.getHostname().c_str() << std::endl; - } - s << config.m_inputFilter.format("\t"); - s << "end" << std::endl; + // options section + s << "section: options" << std::endl; + const Config::ScreenOptions *options = config.getOptions(""); + if (options != NULL && options->size() > 0) { + for (Config::ScreenOptions::const_iterator option = options->begin(); + option != options->end(); ++option) { + const char *name = Config::getOptionName(option->first); + String value = Config::getOptionValue(option->first, option->second); + if (name != NULL && !value.empty()) { + s << "\t" << name << " = " << value << std::endl; + } + } + } + if (config.m_synergyAddress.isValid()) { + s << "\taddress = " << config.m_synergyAddress.getHostname().c_str() + << std::endl; + } + s << config.m_inputFilter.format("\t"); + s << "end" << std::endl; - return s; + return s; } - // // ConfigReadContext // -ConfigReadContext::ConfigReadContext(std::istream& s, SInt32 firstLine) : - m_stream(s), - m_line(firstLine - 1) -{ - // do nothing +ConfigReadContext::ConfigReadContext(std::istream &s, SInt32 firstLine) + : m_stream(s), m_line(firstLine - 1) { + // do nothing } -ConfigReadContext::~ConfigReadContext() -{ - // do nothing +ConfigReadContext::~ConfigReadContext() { + // do nothing } -bool -ConfigReadContext::readLine(String& line) -{ - ++m_line; - while (std::getline(m_stream, line)) { - // strip leading whitespace - String::size_type i = line.find_first_not_of(" \t"); - if (i != String::npos) { - line.erase(0, i); - } +bool ConfigReadContext::readLine(String &line) { + ++m_line; + while (std::getline(m_stream, line)) { + // strip leading whitespace + String::size_type i = line.find_first_not_of(" \t"); + if (i != String::npos) { + line.erase(0, i); + } - // strip comments and then trailing whitespace - i = line.find('#'); - if (i != String::npos) { - line.erase(i); - } - i = line.find_last_not_of(" \r\t"); - if (i != String::npos) { - line.erase(i + 1); - } + // strip comments and then trailing whitespace + i = line.find('#'); + if (i != String::npos) { + line.erase(i); + } + i = line.find_last_not_of(" \r\t"); + if (i != String::npos) { + line.erase(i + 1); + } - // return non empty line - if (!line.empty()) { - // make sure there are no invalid characters - for (i = 0; i < line.length(); ++i) { - if (!isgraph(line[i]) && line[i] != ' ' && line[i] != '\t') { - throw XConfigRead(*this, - "invalid character %{1}", - synergy::string::sprintf("%#2x", line[i])); - } - } + // return non empty line + if (!line.empty()) { + // make sure there are no invalid characters + for (i = 0; i < line.length(); ++i) { + if (!isgraph(line[i]) && line[i] != ' ' && line[i] != '\t') { + throw XConfigRead(*this, "invalid character %{1}", + synergy::string::sprintf("%#2x", line[i])); + } + } - return true; - } + return true; + } - // next line - ++m_line; - } - return false; + // next line + ++m_line; + } + return false; } -UInt32 -ConfigReadContext::getLineNumber() const -{ - return m_line; +UInt32 ConfigReadContext::getLineNumber() const { return m_line; } + +bool ConfigReadContext::operator!() const { return !m_stream; } + +OptionValue ConfigReadContext::parseBoolean(const String &arg) const { + if (CaselessCmp::equal(arg, "true")) { + return static_cast(true); + } + if (CaselessCmp::equal(arg, "false")) { + return static_cast(false); + } + throw XConfigRead(*this, "invalid boolean argument \"%{1}\"", arg); } -bool -ConfigReadContext::operator!() const -{ - return !m_stream; +OptionValue ConfigReadContext::parseInt(const String &arg) const { + const char *s = arg.c_str(); + char *end; + long tmp = strtol(s, &end, 10); + if (*end != '\0') { + // invalid characters + throw XConfigRead(*this, "invalid integer argument \"%{1}\"", arg); + } + OptionValue value = static_cast(tmp); + if (value != tmp) { + // out of range + throw XConfigRead(*this, "integer argument \"%{1}\" out of range", arg); + } + return value; } -OptionValue -ConfigReadContext::parseBoolean(const String& arg) const -{ - if (CaselessCmp::equal(arg, "true")) { - return static_cast(true); - } - if (CaselessCmp::equal(arg, "false")) { - return static_cast(false); - } - throw XConfigRead(*this, "invalid boolean argument \"%{1}\"", arg); +OptionValue ConfigReadContext::parseModifierKey(const String &arg) const { + if (CaselessCmp::equal(arg, "shift")) { + return static_cast(kKeyModifierIDShift); + } + if (CaselessCmp::equal(arg, "ctrl")) { + return static_cast(kKeyModifierIDControl); + } + if (CaselessCmp::equal(arg, "alt")) { + return static_cast(kKeyModifierIDAlt); + } + if (CaselessCmp::equal(arg, "altgr")) { + return static_cast(kKeyModifierIDAltGr); + } + if (CaselessCmp::equal(arg, "meta")) { + return static_cast(kKeyModifierIDMeta); + } + if (CaselessCmp::equal(arg, "super")) { + return static_cast(kKeyModifierIDSuper); + } + if (CaselessCmp::equal(arg, "none")) { + return static_cast(kKeyModifierIDNull); + } + throw XConfigRead(*this, "invalid argument \"%{1}\"", arg); } -OptionValue -ConfigReadContext::parseInt(const String& arg) const -{ - const char* s = arg.c_str(); - char* end; - long tmp = strtol(s, &end, 10); - if (*end != '\0') { - // invalid characters - throw XConfigRead(*this, "invalid integer argument \"%{1}\"", arg); - } - OptionValue value = static_cast(tmp); - if (value != tmp) { - // out of range - throw XConfigRead(*this, "integer argument \"%{1}\" out of range", arg); - } - return value; +OptionValue ConfigReadContext::parseCorner(const String &arg) const { + if (CaselessCmp::equal(arg, "left")) { + return kTopLeftMask | kBottomLeftMask; + } else if (CaselessCmp::equal(arg, "right")) { + return kTopRightMask | kBottomRightMask; + } else if (CaselessCmp::equal(arg, "top")) { + return kTopLeftMask | kTopRightMask; + } else if (CaselessCmp::equal(arg, "bottom")) { + return kBottomLeftMask | kBottomRightMask; + } else if (CaselessCmp::equal(arg, "top-left")) { + return kTopLeftMask; + } else if (CaselessCmp::equal(arg, "top-right")) { + return kTopRightMask; + } else if (CaselessCmp::equal(arg, "bottom-left")) { + return kBottomLeftMask; + } else if (CaselessCmp::equal(arg, "bottom-right")) { + return kBottomRightMask; + } else if (CaselessCmp::equal(arg, "none")) { + return kNoCornerMask; + } else if (CaselessCmp::equal(arg, "all")) { + return kAllCornersMask; + } + throw XConfigRead(*this, "invalid argument \"%{1}\"", arg); } -OptionValue -ConfigReadContext::parseModifierKey(const String& arg) const -{ - if (CaselessCmp::equal(arg, "shift")) { - return static_cast(kKeyModifierIDShift); - } - if (CaselessCmp::equal(arg, "ctrl")) { - return static_cast(kKeyModifierIDControl); - } - if (CaselessCmp::equal(arg, "alt")) { - return static_cast(kKeyModifierIDAlt); - } - if (CaselessCmp::equal(arg, "altgr")) { - return static_cast(kKeyModifierIDAltGr); - } - if (CaselessCmp::equal(arg, "meta")) { - return static_cast(kKeyModifierIDMeta); - } - if (CaselessCmp::equal(arg, "super")) { - return static_cast(kKeyModifierIDSuper); - } - if (CaselessCmp::equal(arg, "none")) { - return static_cast(kKeyModifierIDNull); - } - throw XConfigRead(*this, "invalid argument \"%{1}\"", arg); +OptionValue ConfigReadContext::parseCorners(const String &args) const { + // find first token + String::size_type i = args.find_first_not_of(" \t", 0); + if (i == String::npos) { + throw XConfigRead(*this, "missing corner argument"); + } + String::size_type j = args.find_first_of(" \t", i); + + // parse first corner token + OptionValue corners = parseCorner(args.substr(i, j - i)); + + // get +/- + i = args.find_first_not_of(" \t", j); + while (i != String::npos) { + // parse +/- + bool add; + if (args[i] == '-') { + add = false; + } else if (args[i] == '+') { + add = true; + } else { + throw XConfigRead(*this, "invalid corner operator \"%{1}\"", + String(args.c_str() + i, 1)); + } + + // get next corner token + i = args.find_first_not_of(" \t", i + 1); + j = args.find_first_of(" \t", i); + if (i == String::npos) { + throw XConfigRead(*this, "missing corner argument"); + } + + // parse next corner token + if (add) { + corners |= parseCorner(args.substr(i, j - i)); + } else { + corners &= ~parseCorner(args.substr(i, j - i)); + } + i = args.find_first_not_of(" \t", j); + } + + return corners; } -OptionValue -ConfigReadContext::parseCorner(const String& arg) const -{ - if (CaselessCmp::equal(arg, "left")) { - return kTopLeftMask | kBottomLeftMask; - } - else if (CaselessCmp::equal(arg, "right")) { - return kTopRightMask | kBottomRightMask; - } - else if (CaselessCmp::equal(arg, "top")) { - return kTopLeftMask | kTopRightMask; - } - else if (CaselessCmp::equal(arg, "bottom")) { - return kBottomLeftMask | kBottomRightMask; - } - else if (CaselessCmp::equal(arg, "top-left")) { - return kTopLeftMask; - } - else if (CaselessCmp::equal(arg, "top-right")) { - return kTopRightMask; - } - else if (CaselessCmp::equal(arg, "bottom-left")) { - return kBottomLeftMask; - } - else if (CaselessCmp::equal(arg, "bottom-right")) { - return kBottomRightMask; - } - else if (CaselessCmp::equal(arg, "none")) { - return kNoCornerMask; - } - else if (CaselessCmp::equal(arg, "all")) { - return kAllCornersMask; - } - throw XConfigRead(*this, "invalid argument \"%{1}\"", arg); +Config::Interval ConfigReadContext::parseInterval(const ArgList &args) const { + if (args.size() == 0) { + return Config::Interval(0.0f, 1.0f); + } + if (args.size() != 2 || args[0].empty() || args[1].empty()) { + throw XConfigRead(*this, "invalid interval \"%{1}\"", concatArgs(args)); + } + + char *end; + double startValue = strtod(args[0].c_str(), &end); + if (end[0] != '\0') { + throw XConfigRead(*this, "invalid interval \"%{1}\"", concatArgs(args)); + } + double endValue = strtod(args[1].c_str(), &end); + if (end[0] != '\0') { + throw XConfigRead(*this, "invalid interval \"%{1}\"", concatArgs(args)); + } + + if (startValue < 0 || startValue > 100 || endValue < 0 || endValue > 100 || + startValue >= endValue) { + throw XConfigRead(*this, "invalid interval \"%{1}\"", concatArgs(args)); + } + + float startInterval = static_cast(startValue / 100.0f); + float endInterval = static_cast(endValue / 100.0f); + return Config::Interval(startInterval, endInterval); } -OptionValue -ConfigReadContext::parseCorners(const String& args) const -{ - // find first token - String::size_type i = args.find_first_not_of(" \t", 0); - if (i == String::npos) { - throw XConfigRead(*this, "missing corner argument"); - } - String::size_type j = args.find_first_of(" \t", i); +void ConfigReadContext::parseNameWithArgs(const String &type, + const String &line, + const String &delim, + String::size_type &index, + String &name, ArgList &args) const { + // skip leading whitespace + String::size_type i = line.find_first_not_of(" \t", index); + if (i == String::npos) { + throw XConfigRead(*this, String("missing ") + type); + } - // parse first corner token - OptionValue corners = parseCorner(args.substr(i, j - i)); + // find end of name + String::size_type j = line.find_first_of(" \t(" + delim, i); + if (j == String::npos) { + j = line.length(); + } - // get +/- - i = args.find_first_not_of(" \t", j); - while (i != String::npos) { - // parse +/- - bool add; - if (args[i] == '-') { - add = false; - } - else if (args[i] == '+') { - add = true; - } - else { - throw XConfigRead(*this, - "invalid corner operator \"%{1}\"", - String(args.c_str() + i, 1)); - } + // save name + name = line.substr(i, j - i); + args.clear(); - // get next corner token - i = args.find_first_not_of(" \t", i + 1); - j = args.find_first_of(" \t", i); - if (i == String::npos) { - throw XConfigRead(*this, "missing corner argument"); - } + // is it okay to not find a delimiter? + bool needDelim = (!delim.empty() && delim.find('\n') == String::npos); - // parse next corner token - if (add) { - corners |= parseCorner(args.substr(i, j - i)); - } - else { - corners &= ~parseCorner(args.substr(i, j - i)); - } - i = args.find_first_not_of(" \t", j); - } + // skip whitespace + i = line.find_first_not_of(" \t", j); + if (i == String::npos && needDelim) { + // expected delimiter but didn't find it + throw XConfigRead(*this, String("missing ") + delim[0]); + } + if (i == String::npos) { + // no arguments + index = line.length(); + return; + } + if (line[i] != '(') { + // no arguments + index = i; + return; + } - return corners; + // eat '(' + ++i; + + // parse arguments + j = line.find_first_of(",)", i); + while (j != String::npos) { + // extract arg + String arg(line.substr(i, j - i)); + i = j; + + // trim whitespace + j = arg.find_first_not_of(" \t"); + if (j != String::npos) { + arg.erase(0, j); + } + j = arg.find_last_not_of(" \t"); + if (j != String::npos) { + arg.erase(j + 1); + } + + // save arg + args.push_back(arg); + + // exit loop at end of arguments + if (line[i] == ')') { + break; + } + + // eat ',' + ++i; + + // next + j = line.find_first_of(",)", i); + } + + // verify ')' + if (j == String::npos) { + // expected ) + throw XConfigRead(*this, "missing )"); + } + + // eat ')' + ++i; + + // skip whitespace + j = line.find_first_not_of(" \t", i); + if (j == String::npos && needDelim) { + // expected delimiter but didn't find it + throw XConfigRead(*this, String("missing ") + delim[0]); + } + + // verify delimiter + if (needDelim && delim.find(line[j]) == String::npos) { + throw XConfigRead(*this, String("expected ") + delim[0]); + } + + if (j == String::npos) { + j = line.length(); + } + + index = j; + return; } -Config::Interval -ConfigReadContext::parseInterval(const ArgList& args) const -{ - if (args.size() == 0) { - return Config::Interval(0.0f, 1.0f); - } - if (args.size() != 2 || args[0].empty() || args[1].empty()) { - throw XConfigRead(*this, "invalid interval \"%{1}\"", concatArgs(args)); - } - - char* end; - double startValue = strtod(args[0].c_str(), &end); - if (end[0] != '\0') { - throw XConfigRead(*this, "invalid interval \"%{1}\"", concatArgs(args)); - } - double endValue = strtod(args[1].c_str(), &end); - if (end[0] != '\0') { - throw XConfigRead(*this, "invalid interval \"%{1}\"", concatArgs(args)); - } - - if (startValue < 0 || startValue > 100 || - endValue < 0 || endValue > 100 || - startValue >= endValue) { - throw XConfigRead(*this, "invalid interval \"%{1}\"", concatArgs(args)); - } - - float startInterval = static_cast(startValue / 100.0f); - float endInterval = static_cast(endValue / 100.0f); - return Config::Interval(startInterval, endInterval); +IPlatformScreen::KeyInfo * +ConfigReadContext::parseKeystroke(const String &keystroke) const { + return parseKeystroke(keystroke, std::set()); } -void -ConfigReadContext::parseNameWithArgs( - const String& type, const String& line, - const String& delim, String::size_type& index, - String& name, ArgList& args) const -{ - // skip leading whitespace - String::size_type i = line.find_first_not_of(" \t", index); - if (i == String::npos) { - throw XConfigRead(*this, String("missing ") + type); - } +IPlatformScreen::KeyInfo * +ConfigReadContext::parseKeystroke(const String &keystroke, + const std::set &screens) const { + String s = keystroke; - // find end of name - String::size_type j = line.find_first_of(" \t(" + delim, i); - if (j == String::npos) { - j = line.length(); - } + KeyModifierMask mask; + if (!synergy::KeyMap::parseModifiers(s, mask)) { + throw XConfigRead(*this, "unable to parse key modifiers"); + } - // save name - name = line.substr(i, j - i); - args.clear(); + KeyID key; + if (!synergy::KeyMap::parseKey(s, key)) { + throw XConfigRead(*this, "unable to parse key"); + } - // is it okay to not find a delimiter? - bool needDelim = (!delim.empty() && delim.find('\n') == String::npos); + if (key == kKeyNone && mask == 0) { + throw XConfigRead(*this, "missing key and/or modifiers in keystroke"); + } - // skip whitespace - i = line.find_first_not_of(" \t", j); - if (i == String::npos && needDelim) { - // expected delimiter but didn't find it - throw XConfigRead(*this, String("missing ") + delim[0]); - } - if (i == String::npos) { - // no arguments - index = line.length(); - return; - } - if (line[i] != '(') { - // no arguments - index = i; - return; - } - - // eat '(' - ++i; - - // parse arguments - j = line.find_first_of(",)", i); - while (j != String::npos) { - // extract arg - String arg(line.substr(i, j - i)); - i = j; - - // trim whitespace - j = arg.find_first_not_of(" \t"); - if (j != String::npos) { - arg.erase(0, j); - } - j = arg.find_last_not_of(" \t"); - if (j != String::npos) { - arg.erase(j + 1); - } - - // save arg - args.push_back(arg); - - // exit loop at end of arguments - if (line[i] == ')') { - break; - } - - // eat ',' - ++i; - - // next - j = line.find_first_of(",)", i); - } - - // verify ')' - if (j == String::npos) { - // expected ) - throw XConfigRead(*this, "missing )"); - } - - // eat ')' - ++i; - - // skip whitespace - j = line.find_first_not_of(" \t", i); - if (j == String::npos && needDelim) { - // expected delimiter but didn't find it - throw XConfigRead(*this, String("missing ") + delim[0]); - } - - // verify delimiter - if (needDelim && delim.find(line[j]) == String::npos) { - throw XConfigRead(*this, String("expected ") + delim[0]); - } - - if (j == String::npos) { - j = line.length(); - } - - index = j; - return; + return IPlatformScreen::KeyInfo::alloc(key, mask, 0, 0, screens); } -IPlatformScreen::KeyInfo* -ConfigReadContext::parseKeystroke(const String& keystroke) const -{ - return parseKeystroke(keystroke, std::set()); -} +IPlatformScreen::ButtonInfo * +ConfigReadContext::parseMouse(const String &mouse) const { + String s = mouse; -IPlatformScreen::KeyInfo* -ConfigReadContext::parseKeystroke(const String& keystroke, - const std::set& screens) const -{ - String s = keystroke; + KeyModifierMask mask; + if (!synergy::KeyMap::parseModifiers(s, mask)) { + throw XConfigRead(*this, "unable to parse button modifiers"); + } - KeyModifierMask mask; - if (!synergy::KeyMap::parseModifiers(s, mask)) { - throw XConfigRead(*this, "unable to parse key modifiers"); - } + char *end; + ButtonID button = (ButtonID)strtol(s.c_str(), &end, 10); + if (*end != '\0') { + throw XConfigRead(*this, "unable to parse button"); + } + if (s.empty() || button <= 0) { + throw XConfigRead(*this, "invalid button"); + } - KeyID key; - if (!synergy::KeyMap::parseKey(s, key)) { - throw XConfigRead(*this, "unable to parse key"); - } - - if (key == kKeyNone && mask == 0) { - throw XConfigRead(*this, "missing key and/or modifiers in keystroke"); - } - - return IPlatformScreen::KeyInfo::alloc(key, mask, 0, 0, screens); -} - -IPlatformScreen::ButtonInfo* -ConfigReadContext::parseMouse(const String& mouse) const -{ - String s = mouse; - - KeyModifierMask mask; - if (!synergy::KeyMap::parseModifiers(s, mask)) { - throw XConfigRead(*this, "unable to parse button modifiers"); - } - - char* end; - ButtonID button = (ButtonID)strtol(s.c_str(), &end, 10); - if (*end != '\0') { - throw XConfigRead(*this, "unable to parse button"); - } - if (s.empty() || button <= 0) { - throw XConfigRead(*this, "invalid button"); - } - - return IPlatformScreen::ButtonInfo::alloc(button, mask); + return IPlatformScreen::ButtonInfo::alloc(button, mask); } KeyModifierMask -ConfigReadContext::parseModifier(const String& modifiers) const -{ - String s = modifiers; +ConfigReadContext::parseModifier(const String &modifiers) const { + String s = modifiers; - KeyModifierMask mask; - if (!synergy::KeyMap::parseModifiers(s, mask)) { - throw XConfigRead(*this, "unable to parse modifiers"); - } + KeyModifierMask mask; + if (!synergy::KeyMap::parseModifiers(s, mask)) { + throw XConfigRead(*this, "unable to parse modifiers"); + } - if (mask == 0) { - throw XConfigRead(*this, "no modifiers specified"); - } + if (mask == 0) { + throw XConfigRead(*this, "no modifiers specified"); + } - return mask; + return mask; } -String -ConfigReadContext::concatArgs(const ArgList& args) -{ - String s("("); - for (size_t i = 0; i < args.size(); ++i) { - if (i != 0) { - s += ","; - } - s += args[i]; - } - s += ")"; - return s; +String ConfigReadContext::concatArgs(const ArgList &args) { + String s("("); + for (size_t i = 0; i < args.size(); ++i) { + if (i != 0) { + s += ","; + } + s += args[i]; + } + s += ")"; + return s; } - // // Config I/O exceptions // -XConfigRead::XConfigRead(const ConfigReadContext& context, - const String& error) : - m_error(synergy::string::sprintf("line %d: %s", - context.getLineNumber(), error.c_str())) -{ - // do nothing +XConfigRead::XConfigRead(const ConfigReadContext &context, const String &error) + : m_error(synergy::string::sprintf("line %d: %s", context.getLineNumber(), + error.c_str())) { + // do nothing } -XConfigRead::XConfigRead(const ConfigReadContext& context, - const char* errorFmt, const String& arg) : - m_error(synergy::string::sprintf("line %d: ", context.getLineNumber()) + - synergy::string::format(errorFmt, arg.c_str())) -{ - // do nothing +XConfigRead::XConfigRead(const ConfigReadContext &context, const char *errorFmt, + const String &arg) + : m_error(synergy::string::sprintf("line %d: ", context.getLineNumber()) + + synergy::string::format(errorFmt, arg.c_str())) { + // do nothing } -XConfigRead::~XConfigRead() _NOEXCEPT -{ - // do nothing +XConfigRead::~XConfigRead() _NOEXCEPT { + // do nothing } -String -XConfigRead::getWhat() const throw() -{ - return format("XConfigRead", "read error: %{1}", m_error.c_str()); +String XConfigRead::getWhat() const throw() { + return format("XConfigRead", "read error: %{1}", m_error.c_str()); } diff --git a/src/lib/server/Config.h b/src/lib/server/Config.h index aeb7bb46c..0919815d5 100644 --- a/src/lib/server/Config.h +++ b/src/lib/server/Config.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -18,15 +18,15 @@ #pragma once -#include "server/InputFilter.h" -#include "synergy/option_types.h" -#include "synergy/protocol_types.h" -#include "synergy/IPlatformScreen.h" -#include "net/NetworkAddress.h" #include "base/String.h" #include "base/XBase.h" #include "common/stdmap.h" #include "common/stdset.h" +#include "net/NetworkAddress.h" +#include "server/InputFilter.h" +#include "synergy/IPlatformScreen.h" +#include "synergy/option_types.h" +#include "synergy/protocol_types.h" #include @@ -35,15 +35,14 @@ class ConfigReadContext; class IEventQueue; namespace std { -template <> -struct iterator_traits { - typedef String value_type; - typedef ptrdiff_t difference_type; - typedef bidirectional_iterator_tag iterator_category; - typedef String* pointer; - typedef String& reference; -}; +template <> struct iterator_traits { + typedef String value_type; + typedef ptrdiff_t difference_type; + typedef bidirectional_iterator_tag iterator_category; + typedef String *pointer; + typedef String &reference; }; +}; // namespace std //! Server configuration /*! @@ -57,443 +56,429 @@ namespace and must be unique. */ class Config { public: - typedef std::map ScreenOptions; - typedef std::pair Interval; + typedef std::map ScreenOptions; + typedef std::pair Interval; - class CellEdge { - public: - CellEdge(EDirection side, float position); - CellEdge(EDirection side, const Interval&); - CellEdge(const String& name, EDirection side, const Interval&); - ~CellEdge(); + class CellEdge { + public: + CellEdge(EDirection side, float position); + CellEdge(EDirection side, const Interval &); + CellEdge(const String &name, EDirection side, const Interval &); + ~CellEdge(); - Interval getInterval() const; - void setName(const String& newName); - String getName() const; - EDirection getSide() const; - bool overlaps(const CellEdge&) const; - bool isInside(float x) const; + Interval getInterval() const; + void setName(const String &newName); + String getName() const; + EDirection getSide() const; + bool overlaps(const CellEdge &) const; + bool isInside(float x) const; - // transform position to [0,1] - float transform(float x) const; + // transform position to [0,1] + float transform(float x) const; - // transform [0,1] to position - float inverseTransform(float x) const; + // transform [0,1] to position + float inverseTransform(float x) const; - // compares side and start of interval - bool operator<(const CellEdge&) const; + // compares side and start of interval + bool operator<(const CellEdge &) const; - // compares side and interval - bool operator==(const CellEdge&) const; - bool operator!=(const CellEdge&) const; + // compares side and interval + bool operator==(const CellEdge &) const; + bool operator!=(const CellEdge &) const; - private: - void init(const String& name, EDirection side, - const Interval&); + private: + void init(const String &name, EDirection side, const Interval &); - private: - String m_name; - EDirection m_side; - Interval m_interval; - }; + private: + String m_name; + EDirection m_side; + Interval m_interval; + }; private: - class Name { - public: - Name(Config*, const String& name); + class Name { + public: + Name(Config *, const String &name); - bool operator==(const String& name) const; + bool operator==(const String &name) const; - private: - Config* m_config; - String m_name; - }; + private: + Config *m_config; + String m_name; + }; - class Cell { - private: - typedef std::map EdgeLinks; + class Cell { + private: + typedef std::map EdgeLinks; - public: - typedef EdgeLinks::const_iterator const_iterator; + public: + typedef EdgeLinks::const_iterator const_iterator; - bool add(const CellEdge& src, const CellEdge& dst); - void remove(EDirection side); - void remove(EDirection side, float position); - void remove(const Name& destinationName); - void rename(const Name& oldName, const String& newName); + bool add(const CellEdge &src, const CellEdge &dst); + void remove(EDirection side); + void remove(EDirection side, float position); + void remove(const Name &destinationName); + void rename(const Name &oldName, const String &newName); - bool hasEdge(const CellEdge&) const; - bool overlaps(const CellEdge&) const; + bool hasEdge(const CellEdge &) const; + bool overlaps(const CellEdge &) const; - bool getLink(EDirection side, float position, - const CellEdge*& src, const CellEdge*& dst) const; + bool getLink(EDirection side, float position, const CellEdge *&src, + const CellEdge *&dst) const; - bool operator==(const Cell&) const; - bool operator!=(const Cell&) const; + bool operator==(const Cell &) const; + bool operator!=(const Cell &) const; - const_iterator begin() const; - const_iterator end() const; + const_iterator begin() const; + const_iterator end() const; - private: - EdgeLinks m_neighbors; + private: + EdgeLinks m_neighbors; - public: - ScreenOptions m_options; - }; - typedef std::map CellMap; - typedef std::map NameMap; + public: + ScreenOptions m_options; + }; + typedef std::map CellMap; + typedef std::map NameMap; public: - typedef Cell::const_iterator link_const_iterator; - typedef CellMap::const_iterator internal_const_iterator; - typedef NameMap::const_iterator all_const_iterator; - class const_iterator : std::iterator_traits { - public: - explicit const_iterator() : m_i() { } - explicit const_iterator(const internal_const_iterator& i) : m_i(i) { } - const_iterator(const const_iterator &src) =default; - ~const_iterator() =default; + typedef Cell::const_iterator link_const_iterator; + typedef CellMap::const_iterator internal_const_iterator; + typedef NameMap::const_iterator all_const_iterator; + class const_iterator : std::iterator_traits { + public: + explicit const_iterator() : m_i() {} + explicit const_iterator(const internal_const_iterator &i) : m_i(i) {} + const_iterator(const const_iterator &src) = default; + ~const_iterator() = default; - const_iterator& operator=(const const_iterator& i) { - m_i = i.m_i; - return *this; - } - String operator*() { return m_i->first; } - const String* operator->() { return &(m_i->first); } - const_iterator& operator++() { ++m_i; return *this; } - const_iterator operator++(int) { return const_iterator(m_i++); } - const_iterator& operator--() { --m_i; return *this; } - const_iterator operator--(int) { return const_iterator(m_i--); } - bool operator==(const const_iterator& i) const { - return (m_i == i.m_i); - } - bool operator!=(const const_iterator& i) const { - return (m_i != i.m_i); - } + const_iterator &operator=(const const_iterator &i) { + m_i = i.m_i; + return *this; + } + String operator*() { return m_i->first; } + const String *operator->() { return &(m_i->first); } + const_iterator &operator++() { + ++m_i; + return *this; + } + const_iterator operator++(int) { return const_iterator(m_i++); } + const_iterator &operator--() { + --m_i; + return *this; + } + const_iterator operator--(int) { return const_iterator(m_i--); } + bool operator==(const const_iterator &i) const { return (m_i == i.m_i); } + bool operator!=(const const_iterator &i) const { return (m_i != i.m_i); } - private: - internal_const_iterator m_i; - }; + private: + internal_const_iterator m_i; + }; - Config(IEventQueue* events); - virtual ~Config(); + Config(IEventQueue *events); + virtual ~Config(); #ifdef TEST_ENV - Config() : m_inputFilter(NULL) { } + Config() : m_inputFilter(NULL) {} #endif - //! @name manipulators - //@{ + //! @name manipulators + //@{ - //! Add screen - /*! - Adds a screen, returning true iff successful. If a screen or - alias with the given name exists then it fails. - */ - bool addScreen(const String& name); + //! Add screen + /*! + Adds a screen, returning true iff successful. If a screen or + alias with the given name exists then it fails. + */ + bool addScreen(const String &name); - //! Rename screen - /*! - Renames a screen. All references to the name are updated. - Returns true iff successful. - */ - bool renameScreen(const String& oldName, - const String& newName); + //! Rename screen + /*! + Renames a screen. All references to the name are updated. + Returns true iff successful. + */ + bool renameScreen(const String &oldName, const String &newName); - //! Remove screen - /*! - Removes a screen. This also removes aliases for the screen and - disconnects any connections to the screen. \c name may be an - alias. - */ - void removeScreen(const String& name); + //! Remove screen + /*! + Removes a screen. This also removes aliases for the screen and + disconnects any connections to the screen. \c name may be an + alias. + */ + void removeScreen(const String &name); - //! Remove all screens - /*! - Removes all screens, aliases, and connections. - */ - void removeAllScreens(); + //! Remove all screens + /*! + Removes all screens, aliases, and connections. + */ + void removeAllScreens(); - //! Add alias - /*! - Adds an alias for a screen name. An alias can be used - any place the canonical screen name can (except addScreen()). - Returns false if the alias name already exists or the canonical - name is unknown, otherwise returns true. - */ - bool addAlias(const String& canonical, - const String& alias); + //! Add alias + /*! + Adds an alias for a screen name. An alias can be used + any place the canonical screen name can (except addScreen()). + Returns false if the alias name already exists or the canonical + name is unknown, otherwise returns true. + */ + bool addAlias(const String &canonical, const String &alias); - //! Remove alias - /*! - Removes an alias for a screen name. It returns false if the - alias is unknown or a canonical name, otherwise returns true. - */ - bool removeAlias(const String& alias); + //! Remove alias + /*! + Removes an alias for a screen name. It returns false if the + alias is unknown or a canonical name, otherwise returns true. + */ + bool removeAlias(const String &alias); - //! Remove aliases - /*! - Removes all aliases for a canonical screen name. It returns false - if the canonical name is unknown, otherwise returns true. - */ - bool removeAliases(const String& canonical); + //! Remove aliases + /*! + Removes all aliases for a canonical screen name. It returns false + if the canonical name is unknown, otherwise returns true. + */ + bool removeAliases(const String &canonical); - //! Remove all aliases - /*! - This removes all aliases but not the screens. - */ - void removeAllAliases(); + //! Remove all aliases + /*! + This removes all aliases but not the screens. + */ + void removeAllAliases(); - //! Connect screens - /*! - Establishes a one-way connection between portions of opposite edges - of two screens. Each portion is described by an interval defined - by two numbers, the start and end of the interval half-open on the - end. The numbers range from 0 to 1, inclusive, for the left/top - to the right/bottom. The user will be able to jump from the - \c srcStart to \c srcSend interval of \c srcSide of screen - \c srcName to the opposite side of screen \c dstName in the interval - \c dstStart and \c dstEnd when both screens are connected to the - server and the user isn't locked to a screen. Returns false if - \c srcName is unknown. \c srcStart must be less than or equal to - \c srcEnd and \c dstStart must be less then or equal to \c dstEnd - and all of \c srcStart, \c srcEnd, \c dstStart, or \c dstEnd must - be inside the range [0,1]. - */ - bool connect(const String& srcName, - EDirection srcSide, - float srcStart, float srcEnd, - const String& dstName, - float dstStart, float dstEnd); + //! Connect screens + /*! + Establishes a one-way connection between portions of opposite edges + of two screens. Each portion is described by an interval defined + by two numbers, the start and end of the interval half-open on the + end. The numbers range from 0 to 1, inclusive, for the left/top + to the right/bottom. The user will be able to jump from the + \c srcStart to \c srcSend interval of \c srcSide of screen + \c srcName to the opposite side of screen \c dstName in the interval + \c dstStart and \c dstEnd when both screens are connected to the + server and the user isn't locked to a screen. Returns false if + \c srcName is unknown. \c srcStart must be less than or equal to + \c srcEnd and \c dstStart must be less then or equal to \c dstEnd + and all of \c srcStart, \c srcEnd, \c dstStart, or \c dstEnd must + be inside the range [0,1]. + */ + bool connect(const String &srcName, EDirection srcSide, float srcStart, + float srcEnd, const String &dstName, float dstStart, + float dstEnd); - //! Disconnect screens - /*! - Removes all connections created by connect() on side \c srcSide. - Returns false if \c srcName is unknown. - */ - bool disconnect(const String& srcName, - EDirection srcSide); + //! Disconnect screens + /*! + Removes all connections created by connect() on side \c srcSide. + Returns false if \c srcName is unknown. + */ + bool disconnect(const String &srcName, EDirection srcSide); - //! Disconnect screens - /*! - Removes the connections created by connect() on side \c srcSide - covering position \c position. Returns false if \c srcName is - unknown. - */ - bool disconnect(const String& srcName, - EDirection srcSide, float position); + //! Disconnect screens + /*! + Removes the connections created by connect() on side \c srcSide + covering position \c position. Returns false if \c srcName is + unknown. + */ + bool disconnect(const String &srcName, EDirection srcSide, float position); - //! Set server address - /*! - Set the synergy listen addresses. There is no default address so - this must be called to run a server using this configuration. - */ - void setSynergyAddress(const NetworkAddress&); + //! Set server address + /*! + Set the synergy listen addresses. There is no default address so + this must be called to run a server using this configuration. + */ + void setSynergyAddress(const NetworkAddress &); - //! Add a screen option - /*! - Adds an option and its value to the named screen. Replaces the - existing option's value if there is one. Returns true iff \c name - is a known screen. - */ - bool addOption(const String& name, - OptionID option, OptionValue value); + //! Add a screen option + /*! + Adds an option and its value to the named screen. Replaces the + existing option's value if there is one. Returns true iff \c name + is a known screen. + */ + bool addOption(const String &name, OptionID option, OptionValue value); - //! Remove a screen option - /*! - Removes an option and its value from the named screen. Does - nothing if the option doesn't exist on the screen. Returns true - iff \c name is a known screen. - */ - bool removeOption(const String& name, OptionID option); + //! Remove a screen option + /*! + Removes an option and its value from the named screen. Does + nothing if the option doesn't exist on the screen. Returns true + iff \c name is a known screen. + */ + bool removeOption(const String &name, OptionID option); - //! Remove a screen options - /*! - Removes all options and values from the named screen. Returns true - iff \c name is a known screen. - */ - bool removeOptions(const String& name); + //! Remove a screen options + /*! + Removes all options and values from the named screen. Returns true + iff \c name is a known screen. + */ + bool removeOptions(const String &name); - //! Get the hot key input filter - /*! - Returns the hot key input filter. Clients can modify hotkeys using - that object. - */ - virtual InputFilter* - getInputFilter(); + //! Get the hot key input filter + /*! + Returns the hot key input filter. Clients can modify hotkeys using + that object. + */ + virtual InputFilter *getInputFilter(); - //@} - //! @name accessors - //@{ + //@} + //! @name accessors + //@{ - //! Test screen name validity - /*! - Returns true iff \c name is a valid screen name. - */ - bool isValidScreenName(const String& name) const; + //! Test screen name validity + /*! + Returns true iff \c name is a valid screen name. + */ + bool isValidScreenName(const String &name) const; - //! Get beginning (canonical) screen name iterator - const_iterator begin() const; - //! Get ending (canonical) screen name iterator - const_iterator end() const; + //! Get beginning (canonical) screen name iterator + const_iterator begin() const; + //! Get ending (canonical) screen name iterator + const_iterator end() const; - //! Get beginning screen name iterator - all_const_iterator beginAll() const; - //! Get ending screen name iterator - all_const_iterator endAll() const; + //! Get beginning screen name iterator + all_const_iterator beginAll() const; + //! Get ending screen name iterator + all_const_iterator endAll() const; - //! Test for screen name - /*! - Returns true iff \c name names a screen. - */ - virtual bool isScreen(const String& name) const; + //! Test for screen name + /*! + Returns true iff \c name names a screen. + */ + virtual bool isScreen(const String &name) const; - //! Test for canonical screen name - /*! - Returns true iff \c name is the canonical name of a screen. - */ - bool isCanonicalName(const String& name) const; + //! Test for canonical screen name + /*! + Returns true iff \c name is the canonical name of a screen. + */ + bool isCanonicalName(const String &name) const; - //! Get canonical name - /*! - Returns the canonical name of a screen or the empty string if - the name is unknown. Returns the canonical name if one is given. - */ - String getCanonicalName(const String& name) const; + //! Get canonical name + /*! + Returns the canonical name of a screen or the empty string if + the name is unknown. Returns the canonical name if one is given. + */ + String getCanonicalName(const String &name) const; - //! Get neighbor - /*! - Returns the canonical screen name of the neighbor in the given - direction (set through connect()) at position \c position. Returns - the empty string if there is no neighbor in that direction, otherwise - saves the position on the neighbor in \c positionOut if it's not - \c NULL. - */ - String getNeighbor(const String&, EDirection, - float position, float* positionOut) const; + //! Get neighbor + /*! + Returns the canonical screen name of the neighbor in the given + direction (set through connect()) at position \c position. Returns + the empty string if there is no neighbor in that direction, otherwise + saves the position on the neighbor in \c positionOut if it's not + \c NULL. + */ + String getNeighbor(const String &, EDirection, float position, + float *positionOut) const; - //! Check for neighbor - /*! - Returns \c true if the screen has a neighbor anywhere along the edge - given by the direction. - */ - bool hasNeighbor(const String&, EDirection) const; + //! Check for neighbor + /*! + Returns \c true if the screen has a neighbor anywhere along the edge + given by the direction. + */ + bool hasNeighbor(const String &, EDirection) const; - //! Check for neighbor - /*! - Returns \c true if the screen has a neighbor in the given range along - the edge given by the direction. - */ - bool hasNeighbor(const String&, EDirection, - float start, float end) const; + //! Check for neighbor + /*! + Returns \c true if the screen has a neighbor in the given range along + the edge given by the direction. + */ + bool hasNeighbor(const String &, EDirection, float start, float end) const; - //! Get beginning neighbor iterator - link_const_iterator beginNeighbor(const String&) const; - //! Get ending neighbor iterator - link_const_iterator endNeighbor(const String&) const; + //! Get beginning neighbor iterator + link_const_iterator beginNeighbor(const String &) const; + //! Get ending neighbor iterator + link_const_iterator endNeighbor(const String &) const; - //! Get the server address - const NetworkAddress& - getSynergyAddress() const; + //! Get the server address + const NetworkAddress &getSynergyAddress() const; - //! Get the screen options - /*! - Returns all the added options for the named screen. Returns NULL - if the screen is unknown and an empty collection if there are no - options. - */ - const ScreenOptions* - getOptions(const String& name) const; + //! Get the screen options + /*! + Returns all the added options for the named screen. Returns NULL + if the screen is unknown and an empty collection if there are no + options. + */ + const ScreenOptions *getOptions(const String &name) const; - //! Check for lock to screen action - /*! - Returns \c true if this configuration has a lock to screen action. - This is for backwards compatible support of ScrollLock locking. - */ - bool hasLockToScreenAction() const; + //! Check for lock to screen action + /*! + Returns \c true if this configuration has a lock to screen action. + This is for backwards compatible support of ScrollLock locking. + */ + bool hasLockToScreenAction() const; - //! Compare configurations - bool operator==(const Config&) const; - //! Compare configurations - bool operator!=(const Config&) const; + //! Compare configurations + bool operator==(const Config &) const; + //! Compare configurations + bool operator!=(const Config &) const; - //! Read configuration - /*! - Reads a configuration from a context. Throws XConfigRead on error - and context is unchanged. - */ - void read(ConfigReadContext& context); + //! Read configuration + /*! + Reads a configuration from a context. Throws XConfigRead on error + and context is unchanged. + */ + void read(ConfigReadContext &context); - //! Read configuration - /*! - Reads a configuration from a stream. Throws XConfigRead on error. - */ - friend std::istream& - operator>>(std::istream&, Config&); + //! Read configuration + /*! + Reads a configuration from a stream. Throws XConfigRead on error. + */ + friend std::istream &operator>>(std::istream &, Config &); - //! Write configuration - /*! - Writes a configuration to a stream. - */ - friend std::ostream& - operator<<(std::ostream&, const Config&); + //! Write configuration + /*! + Writes a configuration to a stream. + */ + friend std::ostream &operator<<(std::ostream &, const Config &); - //! Get direction name - /*! - Returns the name of a direction (for debugging). - */ - static const char* dirName(EDirection); + //! Get direction name + /*! + Returns the name of a direction (for debugging). + */ + static const char *dirName(EDirection); - //! Get interval as string - /*! - Returns an interval as a parseable string. - */ - static String formatInterval(const Interval&); + //! Get interval as string + /*! + Returns an interval as a parseable string. + */ + static String formatInterval(const Interval &); - //! Get client address as a string - /*! - * Return client address a string. - */ - String getClientAddress() const; + //! Get client address as a string + /*! + * Return client address a string. + */ + String getClientAddress() const; - //! Return true if server started in client mode - /*! - * In client mode the server initiates connection to client - */ - bool isClientMode() const; + //! Return true if server started in client mode + /*! + * In client mode the server initiates connection to client + */ + bool isClientMode() const; - //@} + //@} private: - void readSection(ConfigReadContext&); - void readSectionOptions(ConfigReadContext&); - void readSectionScreens(ConfigReadContext&); - void readSectionLinks(ConfigReadContext&); - void readSectionAliases(ConfigReadContext&); + void readSection(ConfigReadContext &); + void readSectionOptions(ConfigReadContext &); + void readSectionScreens(ConfigReadContext &); + void readSectionLinks(ConfigReadContext &); + void readSectionAliases(ConfigReadContext &); - InputFilter::Condition* - parseCondition(ConfigReadContext&, - const String& condition, - const std::vector& args); - void parseAction(ConfigReadContext&, - const String& action, - const std::vector& args, - InputFilter::Rule&, bool activate); + InputFilter::Condition *parseCondition(ConfigReadContext &, + const String &condition, + const std::vector &args); + void parseAction(ConfigReadContext &, const String &action, + const std::vector &args, InputFilter::Rule &, + bool activate); - void parseScreens(ConfigReadContext&, const String&, - std::set& screens) const; - static const char* getOptionName(OptionID); - static String getOptionValue(OptionID, OptionValue); + void parseScreens(ConfigReadContext &, const String &, + std::set &screens) const; + static const char *getOptionName(OptionID); + static String getOptionValue(OptionID, OptionValue); private: - CellMap m_map; - NameMap m_nameToCanonicalName; - NetworkAddress m_synergyAddress; - ScreenOptions m_globalOptions; - InputFilter m_inputFilter; - bool m_hasLockToScreenAction; - IEventQueue* m_events; - String m_clientAddress; + CellMap m_map; + NameMap m_nameToCanonicalName; + NetworkAddress m_synergyAddress; + ScreenOptions m_globalOptions; + InputFilter m_inputFilter; + bool m_hasLockToScreenAction; + IEventQueue *m_events; + String m_clientAddress; }; //! Configuration read context @@ -502,46 +487,42 @@ Maintains a context when reading a configuration from a stream. */ class ConfigReadContext { public: - typedef std::vector ArgList; + typedef std::vector ArgList; - ConfigReadContext(std::istream&, SInt32 firstLine = 1); - ~ConfigReadContext(); + ConfigReadContext(std::istream &, SInt32 firstLine = 1); + ~ConfigReadContext(); - bool readLine(String&); - UInt32 getLineNumber() const; + bool readLine(String &); + UInt32 getLineNumber() const; - bool operator!() const; + bool operator!() const; - OptionValue parseBoolean(const String&) const; - OptionValue parseInt(const String&) const; - OptionValue parseModifierKey(const String&) const; - OptionValue parseCorner(const String&) const; - OptionValue parseCorners(const String&) const; - Config::Interval - parseInterval(const ArgList& args) const; - void parseNameWithArgs( - const String& type, const String& line, - const String& delim, String::size_type& index, - String& name, ArgList& args) const; - IPlatformScreen::KeyInfo* - parseKeystroke(const String& keystroke) const; - IPlatformScreen::KeyInfo* - parseKeystroke(const String& keystroke, - const std::set& screens) const; - IPlatformScreen::ButtonInfo* - parseMouse(const String& mouse) const; - KeyModifierMask parseModifier(const String& modifiers) const; - std::istream& getStream() const { return m_stream; }; + OptionValue parseBoolean(const String &) const; + OptionValue parseInt(const String &) const; + OptionValue parseModifierKey(const String &) const; + OptionValue parseCorner(const String &) const; + OptionValue parseCorners(const String &) const; + Config::Interval parseInterval(const ArgList &args) const; + void parseNameWithArgs(const String &type, const String &line, + const String &delim, String::size_type &index, + String &name, ArgList &args) const; + IPlatformScreen::KeyInfo *parseKeystroke(const String &keystroke) const; + IPlatformScreen::KeyInfo * + parseKeystroke(const String &keystroke, + const std::set &screens) const; + IPlatformScreen::ButtonInfo *parseMouse(const String &mouse) const; + KeyModifierMask parseModifier(const String &modifiers) const; + std::istream &getStream() const { return m_stream; }; private: - // not implemented - ConfigReadContext& operator=(const ConfigReadContext&); + // not implemented + ConfigReadContext &operator=(const ConfigReadContext &); - static String concatArgs(const ArgList& args); + static String concatArgs(const ArgList &args); private: - std::istream& m_stream; - SInt32 m_line; + std::istream &m_stream; + SInt32 m_line; }; //! Configuration stream read exception @@ -550,15 +531,15 @@ Thrown when a configuration stream cannot be parsed. */ class XConfigRead : public XBase { public: - XConfigRead(const ConfigReadContext& context, const String&); - XConfigRead(const ConfigReadContext& context, - const char* errorFmt, const String& arg); - virtual ~XConfigRead() _NOEXCEPT; + XConfigRead(const ConfigReadContext &context, const String &); + XConfigRead(const ConfigReadContext &context, const char *errorFmt, + const String &arg); + virtual ~XConfigRead() _NOEXCEPT; protected: - // XBase overrides - virtual String getWhat() const throw(); + // XBase overrides + virtual String getWhat() const throw(); private: - String m_error; + String m_error; }; diff --git a/src/lib/server/InputFilter.cpp b/src/lib/server/InputFilter.cpp index da29f5bd8..99af5fc31 100644 --- a/src/lib/server/InputFilter.cpp +++ b/src/lib/server/InputFilter.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2005 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 LICENSE 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 @@ -17,12 +17,12 @@ */ #include "server/InputFilter.h" -#include "server/Server.h" -#include "server/PrimaryClient.h" -#include "synergy/KeyMap.h" #include "base/EventQueue.h" #include "base/Log.h" #include "base/TMethodEventJob.h" +#include "server/PrimaryClient.h" +#include "server/Server.h" +#include "synergy/KeyMap.h" #include #include @@ -30,1096 +30,852 @@ // ----------------------------------------------------------------------------- // Input Filter Condition Classes // ----------------------------------------------------------------------------- -InputFilter::Condition::Condition() -{ - // do nothing +InputFilter::Condition::Condition() { + // do nothing } -InputFilter::Condition::~Condition() -{ - // do nothing +InputFilter::Condition::~Condition() { + // do nothing } -void -InputFilter::Condition::enablePrimary(PrimaryClient*) -{ - // do nothing +void InputFilter::Condition::enablePrimary(PrimaryClient *) { + // do nothing } -void -InputFilter::Condition::disablePrimary(PrimaryClient*) -{ - // do nothing +void InputFilter::Condition::disablePrimary(PrimaryClient *) { + // do nothing } InputFilter::KeystrokeCondition::KeystrokeCondition( - IEventQueue* events, IPlatformScreen::KeyInfo* info) : - m_id(0), - m_key(info->m_key), - m_mask(info->m_mask), - m_events(events) -{ - free(info); + IEventQueue *events, IPlatformScreen::KeyInfo *info) + : m_id(0), m_key(info->m_key), m_mask(info->m_mask), m_events(events) { + free(info); } -InputFilter::KeystrokeCondition::KeystrokeCondition( - IEventQueue* events, KeyID key, KeyModifierMask mask) : - m_id(0), - m_key(key), - m_mask(mask), - m_events(events) -{ - // do nothing +InputFilter::KeystrokeCondition::KeystrokeCondition(IEventQueue *events, + KeyID key, + KeyModifierMask mask) + : m_id(0), m_key(key), m_mask(mask), m_events(events) { + // do nothing } -InputFilter::KeystrokeCondition::~KeystrokeCondition() -{ - // do nothing +InputFilter::KeystrokeCondition::~KeystrokeCondition() { + // do nothing } -KeyID -InputFilter::KeystrokeCondition::getKey() const -{ - return m_key; +KeyID InputFilter::KeystrokeCondition::getKey() const { return m_key; } + +KeyModifierMask InputFilter::KeystrokeCondition::getMask() const { + return m_mask; } -KeyModifierMask -InputFilter::KeystrokeCondition::getMask() const -{ - return m_mask; +InputFilter::Condition *InputFilter::KeystrokeCondition::clone() const { + return new KeystrokeCondition(m_events, m_key, m_mask); } -InputFilter::Condition* -InputFilter::KeystrokeCondition::clone() const -{ - return new KeystrokeCondition(m_events, m_key, m_mask); -} - -String -InputFilter::KeystrokeCondition::format() const -{ - return synergy::string::sprintf("keystroke(%s)", - synergy::KeyMap::formatKey(m_key, m_mask).c_str()); +String InputFilter::KeystrokeCondition::format() const { + return synergy::string::sprintf( + "keystroke(%s)", synergy::KeyMap::formatKey(m_key, m_mask).c_str()); } InputFilter::EFilterStatus -InputFilter::KeystrokeCondition::match(const Event& event) -{ - EFilterStatus status; +InputFilter::KeystrokeCondition::match(const Event &event) { + EFilterStatus status; - // check for hotkey events - Event::Type type = event.getType(); - if (type == m_events->forIPrimaryScreen().hotKeyDown()) { - status = kActivate; - } - else if (type == m_events->forIPrimaryScreen().hotKeyUp()) { - status = kDeactivate; - } - else { - return kNoMatch; - } + // check for hotkey events + Event::Type type = event.getType(); + if (type == m_events->forIPrimaryScreen().hotKeyDown()) { + status = kActivate; + } else if (type == m_events->forIPrimaryScreen().hotKeyUp()) { + status = kDeactivate; + } else { + return kNoMatch; + } - // check if it's our hotkey - IPrimaryScreen::HotKeyInfo* kinfo = - static_cast(event.getData()); - if (kinfo->m_id != m_id) { - return kNoMatch; - } + // check if it's our hotkey + IPrimaryScreen::HotKeyInfo *kinfo = + static_cast(event.getData()); + if (kinfo->m_id != m_id) { + return kNoMatch; + } - return status; + return status; } -void -InputFilter::KeystrokeCondition::enablePrimary(PrimaryClient* primary) -{ - m_id = primary->registerHotKey(m_key, m_mask); +void InputFilter::KeystrokeCondition::enablePrimary(PrimaryClient *primary) { + m_id = primary->registerHotKey(m_key, m_mask); } -void -InputFilter::KeystrokeCondition::disablePrimary(PrimaryClient* primary) -{ - primary->unregisterHotKey(m_id); - m_id = 0; +void InputFilter::KeystrokeCondition::disablePrimary(PrimaryClient *primary) { + primary->unregisterHotKey(m_id); + m_id = 0; } InputFilter::MouseButtonCondition::MouseButtonCondition( - IEventQueue* events, IPlatformScreen::ButtonInfo* info) : - m_button(info->m_button), - m_mask(info->m_mask), - m_events(events) -{ - free(info); + IEventQueue *events, IPlatformScreen::ButtonInfo *info) + : m_button(info->m_button), m_mask(info->m_mask), m_events(events) { + free(info); } -InputFilter::MouseButtonCondition::MouseButtonCondition( - IEventQueue* events, ButtonID button, KeyModifierMask mask) : - m_button(button), - m_mask(mask), - m_events(events) -{ - // do nothing +InputFilter::MouseButtonCondition::MouseButtonCondition(IEventQueue *events, + ButtonID button, + KeyModifierMask mask) + : m_button(button), m_mask(mask), m_events(events) { + // do nothing } -InputFilter::MouseButtonCondition::~MouseButtonCondition() -{ - // do nothing +InputFilter::MouseButtonCondition::~MouseButtonCondition() { + // do nothing } -ButtonID -InputFilter::MouseButtonCondition::getButton() const -{ - return m_button; +ButtonID InputFilter::MouseButtonCondition::getButton() const { + return m_button; } -KeyModifierMask -InputFilter::MouseButtonCondition::getMask() const -{ - return m_mask; +KeyModifierMask InputFilter::MouseButtonCondition::getMask() const { + return m_mask; } -InputFilter::Condition* -InputFilter::MouseButtonCondition::clone() const -{ - return new MouseButtonCondition(m_events, m_button, m_mask); +InputFilter::Condition *InputFilter::MouseButtonCondition::clone() const { + return new MouseButtonCondition(m_events, m_button, m_mask); } -String -InputFilter::MouseButtonCondition::format() const -{ - String key = synergy::KeyMap::formatKey(kKeyNone, m_mask); - if (!key.empty()) { - key += "+"; - } - return synergy::string::sprintf("mousebutton(%s%d)", key.c_str(), m_button); +String InputFilter::MouseButtonCondition::format() const { + String key = synergy::KeyMap::formatKey(kKeyNone, m_mask); + if (!key.empty()) { + key += "+"; + } + return synergy::string::sprintf("mousebutton(%s%d)", key.c_str(), m_button); } -InputFilter::EFilterStatus -InputFilter::MouseButtonCondition::match(const Event& event) -{ - static const KeyModifierMask s_ignoreMask = - KeyModifierAltGr | KeyModifierCapsLock | - KeyModifierNumLock | KeyModifierScrollLock; +InputFilter::EFilterStatus +InputFilter::MouseButtonCondition::match(const Event &event) { + static const KeyModifierMask s_ignoreMask = + KeyModifierAltGr | KeyModifierCapsLock | KeyModifierNumLock | + KeyModifierScrollLock; - EFilterStatus status; + EFilterStatus status; - // check for hotkey events - Event::Type type = event.getType(); - if (type == m_events->forIPrimaryScreen().buttonDown()) { - status = kActivate; - } - else if (type == m_events->forIPrimaryScreen().buttonUp()) { - status = kDeactivate; - } - else { - return kNoMatch; - } + // check for hotkey events + Event::Type type = event.getType(); + if (type == m_events->forIPrimaryScreen().buttonDown()) { + status = kActivate; + } else if (type == m_events->forIPrimaryScreen().buttonUp()) { + 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::ButtonInfo* minfo = - static_cast(event.getData()); - if (minfo->m_button != m_button || - (minfo->m_mask & ~s_ignoreMask) != m_mask) { - return kNoMatch; - } + // check if it's the right button and modifiers. ignore modifiers + // that cannot be combined with a mouse button. + IPlatformScreen::ButtonInfo *minfo = + static_cast(event.getData()); + if (minfo->m_button != m_button || + (minfo->m_mask & ~s_ignoreMask) != m_mask) { + return kNoMatch; + } - return status; + return status; } InputFilter::ScreenConnectedCondition::ScreenConnectedCondition( - IEventQueue* events, const String& screen) : - m_screen(screen), - m_events(events) -{ - // do nothing + IEventQueue *events, const String &screen) + : m_screen(screen), m_events(events) { + // do nothing } -InputFilter::ScreenConnectedCondition::~ScreenConnectedCondition() -{ - // do nothing +InputFilter::ScreenConnectedCondition::~ScreenConnectedCondition() { + // do nothing } -InputFilter::Condition* -InputFilter::ScreenConnectedCondition::clone() const -{ - return new ScreenConnectedCondition(m_events, m_screen); +InputFilter::Condition *InputFilter::ScreenConnectedCondition::clone() const { + return new ScreenConnectedCondition(m_events, m_screen); } -String -InputFilter::ScreenConnectedCondition::format() const -{ - return synergy::string::sprintf("connect(%s)", m_screen.c_str()); +String InputFilter::ScreenConnectedCondition::format() const { + return synergy::string::sprintf("connect(%s)", m_screen.c_str()); } InputFilter::EFilterStatus -InputFilter::ScreenConnectedCondition::match(const Event& event) -{ - if (event.getType() == m_events->forServer().connected()) { - Server::ScreenConnectedInfo* info = - static_cast(event.getData()); - if (m_screen == info->m_screen || m_screen.empty()) { - return kActivate; - } +InputFilter::ScreenConnectedCondition::match(const Event &event) { + if (event.getType() == m_events->forServer().connected()) { + Server::ScreenConnectedInfo *info = + static_cast(event.getData()); + if (m_screen == info->m_screen || m_screen.empty()) { + return kActivate; } + } - return kNoMatch; + return kNoMatch; } // ----------------------------------------------------------------------------- // Input Filter Action Classes // ----------------------------------------------------------------------------- -InputFilter::Action::Action() -{ - // do nothing +InputFilter::Action::Action() { + // do nothing } -InputFilter::Action::~Action() -{ - // do nothing +InputFilter::Action::~Action() { + // do nothing } InputFilter::LockCursorToScreenAction::LockCursorToScreenAction( - IEventQueue* events, Mode mode) : - m_mode(mode), - m_events(events) -{ - // do nothing + IEventQueue *events, Mode mode) + : m_mode(mode), m_events(events) { + // do nothing } InputFilter::LockCursorToScreenAction::Mode -InputFilter::LockCursorToScreenAction::getMode() const -{ - return m_mode; +InputFilter::LockCursorToScreenAction::getMode() const { + return m_mode; } -InputFilter::Action* -InputFilter::LockCursorToScreenAction::clone() const -{ - return new LockCursorToScreenAction(*this); +InputFilter::Action *InputFilter::LockCursorToScreenAction::clone() const { + return new LockCursorToScreenAction(*this); } -String -InputFilter::LockCursorToScreenAction::format() const -{ - static const char* s_mode[] = { "off", "on", "toggle" }; +String InputFilter::LockCursorToScreenAction::format() const { + static const char *s_mode[] = {"off", "on", "toggle"}; - return synergy::string::sprintf("lockCursorToScreen(%s)", s_mode[m_mode]); + return synergy::string::sprintf("lockCursorToScreen(%s)", s_mode[m_mode]); } -void -InputFilter::LockCursorToScreenAction::perform(const Event& event) -{ - static const Server::LockCursorToScreenInfo::State s_state[] = { - Server::LockCursorToScreenInfo::kOff, - Server::LockCursorToScreenInfo::kOn, - Server::LockCursorToScreenInfo::kToggle - }; +void InputFilter::LockCursorToScreenAction::perform(const Event &event) { + static const Server::LockCursorToScreenInfo::State s_state[] = { + Server::LockCursorToScreenInfo::kOff, Server::LockCursorToScreenInfo::kOn, + Server::LockCursorToScreenInfo::kToggle}; - // send event - Server::LockCursorToScreenInfo* info = - Server::LockCursorToScreenInfo::alloc(s_state[m_mode]); - m_events->addEvent(Event(m_events->forServer().lockCursorToScreen(), - event.getTarget(), info, - Event::kDeliverImmediately)); + // send event + Server::LockCursorToScreenInfo *info = + Server::LockCursorToScreenInfo::alloc(s_state[m_mode]); + m_events->addEvent(Event(m_events->forServer().lockCursorToScreen(), + event.getTarget(), info, + Event::kDeliverImmediately)); } - -InputFilter::RestartServer::RestartServer( - IEventQueue* events, Mode mode) : - m_mode(mode), - m_events(events) -{ - // do nothing +InputFilter::RestartServer::RestartServer(IEventQueue *events, Mode mode) + : m_mode(mode), m_events(events) { + // do nothing } -InputFilter::RestartServer::Mode -InputFilter::RestartServer::getMode() const -{ - return m_mode; +InputFilter::RestartServer::Mode InputFilter::RestartServer::getMode() const { + return m_mode; } InputFilter::Action *InputFilter::RestartServer::clone() const { - return new RestartServer(*this); + return new RestartServer(*this); } -String -InputFilter::RestartServer::format() const -{ - static const char* s_mode[] = { "restart" }; +String InputFilter::RestartServer::format() const { + static const char *s_mode[] = {"restart"}; - return synergy::string::sprintf("restartServer(%s)", s_mode[m_mode]); + return synergy::string::sprintf("restartServer(%s)", s_mode[m_mode]); } -void -InputFilter::RestartServer::perform(const Event& event) -{ - //HACK Super hack we should gracefully exit - exit(0); +void InputFilter::RestartServer::perform(const Event &event) { + // HACK Super hack we should gracefully exit + exit(0); } -InputFilter::SwitchToScreenAction::SwitchToScreenAction( - IEventQueue* events, const String& screen) : - m_screen(screen), - m_events(events) -{ - // do nothing +InputFilter::SwitchToScreenAction::SwitchToScreenAction(IEventQueue *events, + const String &screen) + : m_screen(screen), m_events(events) { + // do nothing } -String -InputFilter::SwitchToScreenAction::getScreen() const -{ - return m_screen; +String InputFilter::SwitchToScreenAction::getScreen() const { return m_screen; } + +InputFilter::Action *InputFilter::SwitchToScreenAction::clone() const { + return new SwitchToScreenAction(*this); } -InputFilter::Action* -InputFilter::SwitchToScreenAction::clone() const -{ - return new SwitchToScreenAction(*this); +String InputFilter::SwitchToScreenAction::format() const { + return synergy::string::sprintf("switchToScreen(%s)", m_screen.c_str()); } -String -InputFilter::SwitchToScreenAction::format() const -{ - return synergy::string::sprintf("switchToScreen(%s)", m_screen.c_str()); -} +void InputFilter::SwitchToScreenAction::perform(const Event &event) { + // pick screen name. if m_screen is empty then use the screen from + // event if it has one. + String screen = m_screen; + if (screen.empty() && event.getType() == m_events->forServer().connected()) { + Server::ScreenConnectedInfo *info = + static_cast(event.getData()); + screen = info->m_screen; + } -void -InputFilter::SwitchToScreenAction::perform(const Event& event) -{ - // pick screen name. if m_screen is empty then use the screen from - // event if it has one. - String screen = m_screen; - if (screen.empty() && event.getType() == m_events->forServer().connected()) { - Server::ScreenConnectedInfo* info = - static_cast(event.getData()); - screen = info->m_screen; - } - - // send event - Server::SwitchToScreenInfo* info = - Server::SwitchToScreenInfo::alloc(screen); - m_events->addEvent(Event(m_events->forServer().switchToScreen(), - event.getTarget(), info, - Event::kDeliverImmediately)); + // send event + Server::SwitchToScreenInfo *info = Server::SwitchToScreenInfo::alloc(screen); + m_events->addEvent(Event(m_events->forServer().switchToScreen(), + event.getTarget(), info, + Event::kDeliverImmediately)); } InputFilter::SwitchInDirectionAction::SwitchInDirectionAction( - IEventQueue* events, EDirection direction) : - m_direction(direction), - m_events(events) -{ - // do nothing + IEventQueue *events, EDirection direction) + : m_direction(direction), m_events(events) { + // do nothing } -EDirection -InputFilter::SwitchInDirectionAction::getDirection() const -{ - return m_direction; +EDirection InputFilter::SwitchInDirectionAction::getDirection() const { + return m_direction; } -InputFilter::Action* -InputFilter::SwitchInDirectionAction::clone() const -{ - return new SwitchInDirectionAction(*this); +InputFilter::Action *InputFilter::SwitchInDirectionAction::clone() const { + return new SwitchInDirectionAction(*this); } -String -InputFilter::SwitchInDirectionAction::format() const -{ - static const char* s_names[] = { - "", - "left", - "right", - "up", - "down" - }; +String InputFilter::SwitchInDirectionAction::format() const { + static const char *s_names[] = {"", "left", "right", "up", "down"}; - return synergy::string::sprintf("switchInDirection(%s)", s_names[m_direction]); + return synergy::string::sprintf("switchInDirection(%s)", + s_names[m_direction]); } -void -InputFilter::SwitchInDirectionAction::perform(const Event& event) -{ - Server::SwitchInDirectionInfo* info = - Server::SwitchInDirectionInfo::alloc(m_direction); - m_events->addEvent(Event(m_events->forServer().switchInDirection(), - event.getTarget(), info, - Event::kDeliverImmediately)); +void InputFilter::SwitchInDirectionAction::perform(const Event &event) { + Server::SwitchInDirectionInfo *info = + Server::SwitchInDirectionInfo::alloc(m_direction); + m_events->addEvent(Event(m_events->forServer().switchInDirection(), + event.getTarget(), info, + Event::kDeliverImmediately)); } InputFilter::KeyboardBroadcastAction::KeyboardBroadcastAction( - IEventQueue* events, Mode mode) : - m_mode(mode), - m_events(events) -{ - // do nothing + IEventQueue *events, Mode mode) + : m_mode(mode), m_events(events) { + // do nothing } InputFilter::KeyboardBroadcastAction::KeyboardBroadcastAction( - IEventQueue* events, - Mode mode, - const std::set& screens) : - m_mode(mode), - m_screens(IKeyState::KeyInfo::join(screens)), - m_events(events) -{ - // do nothing + IEventQueue *events, Mode mode, const std::set &screens) + : m_mode(mode), m_screens(IKeyState::KeyInfo::join(screens)), + m_events(events) { + // do nothing } InputFilter::KeyboardBroadcastAction::Mode -InputFilter::KeyboardBroadcastAction::getMode() const -{ - return m_mode; +InputFilter::KeyboardBroadcastAction::getMode() const { + return m_mode; } -std::set -InputFilter::KeyboardBroadcastAction::getScreens() const -{ - std::set screens; - IKeyState::KeyInfo::split(m_screens.c_str(), screens); - return screens; +std::set InputFilter::KeyboardBroadcastAction::getScreens() const { + std::set screens; + IKeyState::KeyInfo::split(m_screens.c_str(), screens); + return screens; } -InputFilter::Action* -InputFilter::KeyboardBroadcastAction::clone() const -{ - return new KeyboardBroadcastAction(*this); +InputFilter::Action *InputFilter::KeyboardBroadcastAction::clone() const { + return new KeyboardBroadcastAction(*this); } -String -InputFilter::KeyboardBroadcastAction::format() const -{ - static const char* s_mode[] = { "off", "on", "toggle" }; - static const char* s_name = "keyboardBroadcast"; +String InputFilter::KeyboardBroadcastAction::format() const { + static const char *s_mode[] = {"off", "on", "toggle"}; + static const char *s_name = "keyboardBroadcast"; - if (m_screens.empty() || m_screens[0] == '*') { - return synergy::string::sprintf("%s(%s)", s_name, s_mode[m_mode]); - } - else { - return synergy::string::sprintf("%s(%s,%.*s)", s_name, s_mode[m_mode], - static_cast(m_screens.size() >= 2 ? m_screens.size() - 2 : 0), - m_screens.c_str() + 1); - } + if (m_screens.empty() || m_screens[0] == '*') { + return synergy::string::sprintf("%s(%s)", s_name, s_mode[m_mode]); + } else { + return synergy::string::sprintf( + "%s(%s,%.*s)", s_name, s_mode[m_mode], + static_cast(m_screens.size() >= 2 ? m_screens.size() - 2 : 0), + m_screens.c_str() + 1); + } } -void -InputFilter::KeyboardBroadcastAction::perform(const Event& event) -{ - static const Server::KeyboardBroadcastInfo::State s_state[] = { - Server::KeyboardBroadcastInfo::kOff, - Server::KeyboardBroadcastInfo::kOn, - Server::KeyboardBroadcastInfo::kToggle - }; +void InputFilter::KeyboardBroadcastAction::perform(const Event &event) { + static const Server::KeyboardBroadcastInfo::State s_state[] = { + Server::KeyboardBroadcastInfo::kOff, Server::KeyboardBroadcastInfo::kOn, + Server::KeyboardBroadcastInfo::kToggle}; - // send event - Server::KeyboardBroadcastInfo* info = - Server::KeyboardBroadcastInfo::alloc(s_state[m_mode], m_screens); - m_events->addEvent(Event(m_events->forServer().keyboardBroadcast(), - event.getTarget(), info, - Event::kDeliverImmediately)); + // send event + Server::KeyboardBroadcastInfo *info = + Server::KeyboardBroadcastInfo::alloc(s_state[m_mode], m_screens); + m_events->addEvent(Event(m_events->forServer().keyboardBroadcast(), + event.getTarget(), info, + Event::kDeliverImmediately)); } -InputFilter::KeystrokeAction::KeystrokeAction( - IEventQueue* events, IPlatformScreen::KeyInfo* info, bool press) : - m_keyInfo(info), - m_press(press), - m_events(events) -{ - // do nothing +InputFilter::KeystrokeAction::KeystrokeAction(IEventQueue *events, + IPlatformScreen::KeyInfo *info, + bool press) + : m_keyInfo(info), m_press(press), m_events(events) { + // do nothing } -InputFilter::KeystrokeAction::~KeystrokeAction() -{ - free(m_keyInfo); +InputFilter::KeystrokeAction::~KeystrokeAction() { free(m_keyInfo); } + +void InputFilter::KeystrokeAction::adoptInfo(IPlatformScreen::KeyInfo *info) { + free(m_keyInfo); + m_keyInfo = info; } -void -InputFilter::KeystrokeAction::adoptInfo(IPlatformScreen::KeyInfo* info) -{ - free(m_keyInfo); - m_keyInfo = info; +const IPlatformScreen::KeyInfo *InputFilter::KeystrokeAction::getInfo() const { + return m_keyInfo; } -const IPlatformScreen::KeyInfo* -InputFilter::KeystrokeAction::getInfo() const -{ - return m_keyInfo; +bool InputFilter::KeystrokeAction::isOnPress() const { return m_press; } + +InputFilter::Action *InputFilter::KeystrokeAction::clone() const { + IKeyState::KeyInfo *info = IKeyState::KeyInfo::alloc(*m_keyInfo); + return new KeystrokeAction(m_events, info, m_press); } -bool -InputFilter::KeystrokeAction::isOnPress() const -{ - return m_press; +String InputFilter::KeystrokeAction::format() const { + const char *type = formatName(); + + if (m_keyInfo->m_screens[0] == '\0') { + return synergy::string::sprintf( + "%s(%s)", type, + synergy::KeyMap::formatKey(m_keyInfo->m_key, m_keyInfo->m_mask) + .c_str()); + } else if (m_keyInfo->m_screens[0] == '*') { + return synergy::string::sprintf( + "%s(%s,*)", type, + synergy::KeyMap::formatKey(m_keyInfo->m_key, m_keyInfo->m_mask) + .c_str()); + } else { + return synergy::string::sprintf( + "%s(%s,%.*s)", type, + synergy::KeyMap::formatKey(m_keyInfo->m_key, m_keyInfo->m_mask).c_str(), + strnlen(m_keyInfo->m_screens + 1, SIZE_MAX) - 1, + m_keyInfo->m_screens + 1); + } } -InputFilter::Action* -InputFilter::KeystrokeAction::clone() const -{ - IKeyState::KeyInfo* info = IKeyState::KeyInfo::alloc(*m_keyInfo); - return new KeystrokeAction(m_events, info, m_press); +void InputFilter::KeystrokeAction::perform(const Event &event) { + Event::Type type = m_press ? m_events->forIKeyState().keyDown() + : m_events->forIKeyState().keyUp(); + + m_events->addEvent(Event(m_events->forIPrimaryScreen().fakeInputBegin(), + event.getTarget(), NULL, + Event::kDeliverImmediately)); + m_events->addEvent(Event(type, event.getTarget(), m_keyInfo, + Event::kDeliverImmediately | Event::kDontFreeData)); + m_events->addEvent(Event(m_events->forIPrimaryScreen().fakeInputEnd(), + event.getTarget(), NULL, + Event::kDeliverImmediately)); } -String -InputFilter::KeystrokeAction::format() const -{ - const char* type = formatName(); - - if (m_keyInfo->m_screens[0] == '\0') { - return synergy::string::sprintf("%s(%s)", type, - synergy::KeyMap::formatKey(m_keyInfo->m_key, - m_keyInfo->m_mask).c_str()); - } - else if (m_keyInfo->m_screens[0] == '*') { - return synergy::string::sprintf("%s(%s,*)", type, - synergy::KeyMap::formatKey(m_keyInfo->m_key, - m_keyInfo->m_mask).c_str()); - } - else { - return synergy::string::sprintf("%s(%s,%.*s)", type, - synergy::KeyMap::formatKey(m_keyInfo->m_key, - m_keyInfo->m_mask).c_str(), - strnlen(m_keyInfo->m_screens + 1, SIZE_MAX) - 1, - m_keyInfo->m_screens + 1); - } -} - -void -InputFilter::KeystrokeAction::perform(const Event& event) -{ - Event::Type type = m_press ? - m_events->forIKeyState().keyDown() : - m_events->forIKeyState().keyUp(); - - m_events->addEvent(Event(m_events->forIPrimaryScreen().fakeInputBegin(), - event.getTarget(), NULL, - Event::kDeliverImmediately)); - m_events->addEvent(Event(type, event.getTarget(), m_keyInfo, - Event::kDeliverImmediately | - Event::kDontFreeData)); - m_events->addEvent(Event(m_events->forIPrimaryScreen().fakeInputEnd(), - event.getTarget(), NULL, - Event::kDeliverImmediately)); -} - -const char* -InputFilter::KeystrokeAction::formatName() const -{ - return (m_press ? "keyDown" : "keyUp"); +const char *InputFilter::KeystrokeAction::formatName() const { + return (m_press ? "keyDown" : "keyUp"); } InputFilter::MouseButtonAction::MouseButtonAction( - IEventQueue* events, IPlatformScreen::ButtonInfo* info, bool press) : - m_buttonInfo(info), - m_press(press), - m_events(events) -{ - // do nothing + IEventQueue *events, IPlatformScreen::ButtonInfo *info, bool press) + : m_buttonInfo(info), m_press(press), m_events(events) { + // do nothing } -InputFilter::MouseButtonAction::~MouseButtonAction() -{ - free(m_buttonInfo); +InputFilter::MouseButtonAction::~MouseButtonAction() { free(m_buttonInfo); } + +const IPlatformScreen::ButtonInfo * +InputFilter::MouseButtonAction::getInfo() const { + return m_buttonInfo; } -const IPlatformScreen::ButtonInfo* -InputFilter::MouseButtonAction::getInfo() const -{ - return m_buttonInfo; +bool InputFilter::MouseButtonAction::isOnPress() const { return m_press; } + +InputFilter::Action *InputFilter::MouseButtonAction::clone() const { + IPlatformScreen::ButtonInfo *info = + IPrimaryScreen::ButtonInfo::alloc(*m_buttonInfo); + return new MouseButtonAction(m_events, info, m_press); } -bool -InputFilter::MouseButtonAction::isOnPress() const -{ - return m_press; +String InputFilter::MouseButtonAction::format() const { + const char *type = formatName(); + + String key = synergy::KeyMap::formatKey(kKeyNone, m_buttonInfo->m_mask); + return synergy::string::sprintf("%s(%s%s%d)", type, key.c_str(), + key.empty() ? "" : "+", + m_buttonInfo->m_button); } -InputFilter::Action* -InputFilter::MouseButtonAction::clone() const +void InputFilter::MouseButtonAction::perform(const Event &event) + { - IPlatformScreen::ButtonInfo* info = - IPrimaryScreen::ButtonInfo::alloc(*m_buttonInfo); - return new MouseButtonAction(m_events, info, m_press); + // send modifiers + IPlatformScreen::KeyInfo *modifierInfo = NULL; + if (m_buttonInfo->m_mask != 0) { + KeyID key = m_press ? kKeySetModifiers : kKeyClearModifiers; + modifierInfo = IKeyState::KeyInfo::alloc(key, m_buttonInfo->m_mask, 0, 1); + m_events->addEvent(Event(m_events->forIKeyState().keyDown(), + event.getTarget(), modifierInfo, + Event::kDeliverImmediately)); + } + + // send button + Event::Type type = m_press ? m_events->forIPrimaryScreen().buttonDown() + : m_events->forIPrimaryScreen().buttonUp(); + m_events->addEvent(Event(type, event.getTarget(), m_buttonInfo, + Event::kDeliverImmediately | Event::kDontFreeData)); } -String -InputFilter::MouseButtonAction::format() const -{ - const char* type = formatName(); - - String key = synergy::KeyMap::formatKey(kKeyNone, m_buttonInfo->m_mask); - return synergy::string::sprintf("%s(%s%s%d)", type, - key.c_str(), key.empty() ? "" : "+", - m_buttonInfo->m_button); -} - -void -InputFilter::MouseButtonAction::perform(const Event& event) - -{ - // send modifiers - IPlatformScreen::KeyInfo* modifierInfo = NULL; - if (m_buttonInfo->m_mask != 0) { - KeyID key = m_press ? kKeySetModifiers : kKeyClearModifiers; - modifierInfo = - IKeyState::KeyInfo::alloc(key, m_buttonInfo->m_mask, 0, 1); - m_events->addEvent(Event(m_events->forIKeyState().keyDown(), - event.getTarget(), modifierInfo, - Event::kDeliverImmediately)); - } - - // send button - Event::Type type = m_press ? m_events->forIPrimaryScreen().buttonDown() : - m_events->forIPrimaryScreen().buttonUp(); - m_events->addEvent(Event(type, event.getTarget(), m_buttonInfo, - Event::kDeliverImmediately | - Event::kDontFreeData)); -} - -const char* -InputFilter::MouseButtonAction::formatName() const -{ - return (m_press ? "mouseDown" : "mouseUp"); +const char *InputFilter::MouseButtonAction::formatName() const { + return (m_press ? "mouseDown" : "mouseUp"); } // // InputFilter::Rule // -InputFilter::Rule::Rule() : - m_condition(NULL) -{ - // do nothing +InputFilter::Rule::Rule() : m_condition(NULL) { + // do nothing } -InputFilter::Rule::Rule(Condition* adoptedCondition) : - m_condition(adoptedCondition) -{ - // do nothing +InputFilter::Rule::Rule(Condition *adoptedCondition) + : m_condition(adoptedCondition) { + // do nothing } -InputFilter::Rule::Rule(const Rule& rule) : - m_condition(NULL) -{ +InputFilter::Rule::Rule(const Rule &rule) : m_condition(NULL) { copy(rule); } + +InputFilter::Rule::~Rule() { clear(); } + +InputFilter::Rule &InputFilter::Rule::operator=(const Rule &rule) { + if (&rule != this) { copy(rule); + } + return *this; } -InputFilter::Rule::~Rule() -{ - clear(); +void InputFilter::Rule::clear() { + delete m_condition; + for (ActionList::iterator i = m_activateActions.begin(); + i != m_activateActions.end(); ++i) { + delete *i; + } + for (ActionList::iterator i = m_deactivateActions.begin(); + i != m_deactivateActions.end(); ++i) { + delete *i; + } + + m_condition = NULL; + m_activateActions.clear(); + m_deactivateActions.clear(); } -InputFilter::Rule& -InputFilter::Rule::operator=(const Rule& rule) -{ - if (&rule != this) { - copy(rule); - } - return *this; +void InputFilter::Rule::copy(const Rule &rule) { + clear(); + if (rule.m_condition != NULL) { + m_condition = rule.m_condition->clone(); + } + for (ActionList::const_iterator i = rule.m_activateActions.begin(); + i != rule.m_activateActions.end(); ++i) { + m_activateActions.push_back((*i)->clone()); + } + for (ActionList::const_iterator i = rule.m_deactivateActions.begin(); + i != rule.m_deactivateActions.end(); ++i) { + m_deactivateActions.push_back((*i)->clone()); + } } -void -InputFilter::Rule::clear() -{ - delete m_condition; - for (ActionList::iterator i = m_activateActions.begin(); - i != m_activateActions.end(); ++i) { - delete *i; - } - for (ActionList::iterator i = m_deactivateActions.begin(); - i != m_deactivateActions.end(); ++i) { - delete *i; - } - - m_condition = NULL; - m_activateActions.clear(); - m_deactivateActions.clear(); +void InputFilter::Rule::setCondition(Condition *adopted) { + delete m_condition; + m_condition = adopted; } -void -InputFilter::Rule::copy(const Rule& rule) -{ - clear(); - if (rule.m_condition != NULL) { - m_condition = rule.m_condition->clone(); - } - for (ActionList::const_iterator i = rule.m_activateActions.begin(); - i != rule.m_activateActions.end(); ++i) { - m_activateActions.push_back((*i)->clone()); - } - for (ActionList::const_iterator i = rule.m_deactivateActions.begin(); - i != rule.m_deactivateActions.end(); ++i) { - m_deactivateActions.push_back((*i)->clone()); - } -} - -void -InputFilter::Rule::setCondition(Condition* adopted) -{ - delete m_condition; - m_condition = adopted; -} - -void -InputFilter::Rule::adoptAction(Action* action, bool onActivation) -{ - if (action != NULL) { - if (onActivation) { - m_activateActions.push_back(action); - } - else { - m_deactivateActions.push_back(action); - } - } -} - -void -InputFilter::Rule::removeAction(bool onActivation, UInt32 index) -{ +void InputFilter::Rule::adoptAction(Action *action, bool onActivation) { + if (action != NULL) { if (onActivation) { - delete m_activateActions[index]; - m_activateActions.erase(m_activateActions.begin() + index); - } - else { - delete m_deactivateActions[index]; - m_deactivateActions.erase(m_deactivateActions.begin() + index); + m_activateActions.push_back(action); + } else { + m_deactivateActions.push_back(action); } + } } -void -InputFilter::Rule::replaceAction(Action* adopted, - bool onActivation, UInt32 index) -{ - if (adopted == NULL) { - removeAction(onActivation, index); - } - else if (onActivation) { - delete m_activateActions[index]; - m_activateActions[index] = adopted; - } - else { - delete m_deactivateActions[index]; - m_deactivateActions[index] = adopted; - } +void InputFilter::Rule::removeAction(bool onActivation, UInt32 index) { + if (onActivation) { + delete m_activateActions[index]; + m_activateActions.erase(m_activateActions.begin() + index); + } else { + delete m_deactivateActions[index]; + m_deactivateActions.erase(m_deactivateActions.begin() + index); + } } -void -InputFilter::Rule::enable(PrimaryClient* primaryClient) -{ - if (m_condition != NULL) { - m_condition->enablePrimary(primaryClient); - } +void InputFilter::Rule::replaceAction(Action *adopted, bool onActivation, + UInt32 index) { + if (adopted == NULL) { + removeAction(onActivation, index); + } else if (onActivation) { + delete m_activateActions[index]; + m_activateActions[index] = adopted; + } else { + delete m_deactivateActions[index]; + m_deactivateActions[index] = adopted; + } } -void -InputFilter::Rule::disable(PrimaryClient* primaryClient) -{ - if (m_condition != NULL) { - m_condition->disablePrimary(primaryClient); - } +void InputFilter::Rule::enable(PrimaryClient *primaryClient) { + if (m_condition != NULL) { + m_condition->enablePrimary(primaryClient); + } } -bool -InputFilter::Rule::handleEvent(const Event& event) -{ - // NULL condition never matches - if (m_condition == NULL) { - return false; - } - - // match - const ActionList* actions; - switch (m_condition->match(event)) { - default: - // not handled - return false; - - case kActivate: - actions = &m_activateActions; - LOG((CLOG_DEBUG1 "activate actions")); - break; - - case kDeactivate: - actions = &m_deactivateActions; - LOG((CLOG_DEBUG1 "deactivate actions")); - break; - } - - // perform actions - for (ActionList::const_iterator i = actions->begin(); - i != actions->end(); ++i) { - LOG((CLOG_DEBUG1 "hotkey: %s", (*i)->format().c_str())); - (*i)->perform(event); - } - - return true; +void InputFilter::Rule::disable(PrimaryClient *primaryClient) { + if (m_condition != NULL) { + m_condition->disablePrimary(primaryClient); + } } -String -InputFilter::Rule::format() const -{ - String s; - if (m_condition != NULL) { - // condition - s += m_condition->format(); - s += " = "; +bool InputFilter::Rule::handleEvent(const Event &event) { + // NULL condition never matches + if (m_condition == NULL) { + return false; + } - // activate actions - ActionList::const_iterator i = m_activateActions.begin(); - if (i != m_activateActions.end()) { - s += (*i)->format(); - while (++i != m_activateActions.end()) { - s += ", "; - s += (*i)->format(); - } - } - - // deactivate actions - if (!m_deactivateActions.empty()) { - s += "; "; - i = m_deactivateActions.begin(); - if (i != m_deactivateActions.end()) { - s += (*i)->format(); - while (++i != m_deactivateActions.end()) { - s += ", "; - s += (*i)->format(); - } - } + // match + const ActionList *actions; + switch (m_condition->match(event)) { + default: + // not handled + return false; + + case kActivate: + actions = &m_activateActions; + LOG((CLOG_DEBUG1 "activate actions")); + break; + + case kDeactivate: + actions = &m_deactivateActions; + LOG((CLOG_DEBUG1 "deactivate actions")); + break; + } + + // perform actions + for (ActionList::const_iterator i = actions->begin(); i != actions->end(); + ++i) { + LOG((CLOG_DEBUG1 "hotkey: %s", (*i)->format().c_str())); + (*i)->perform(event); + } + + return true; +} + +String InputFilter::Rule::format() const { + String s; + if (m_condition != NULL) { + // condition + s += m_condition->format(); + s += " = "; + + // activate actions + ActionList::const_iterator i = m_activateActions.begin(); + if (i != m_activateActions.end()) { + s += (*i)->format(); + while (++i != m_activateActions.end()) { + s += ", "; + s += (*i)->format(); + } + } + + // deactivate actions + if (!m_deactivateActions.empty()) { + s += "; "; + i = m_deactivateActions.begin(); + if (i != m_deactivateActions.end()) { + s += (*i)->format(); + while (++i != m_deactivateActions.end()) { + s += ", "; + s += (*i)->format(); } + } } - return s; + } + return s; } -const InputFilter::Condition* -InputFilter::Rule::getCondition() const -{ - return m_condition; +const InputFilter::Condition *InputFilter::Rule::getCondition() const { + return m_condition; } -UInt32 -InputFilter::Rule::getNumActions(bool onActivation) const -{ - if (onActivation) { - return static_cast(m_activateActions.size()); - } - else { - return static_cast(m_deactivateActions.size()); - } +UInt32 InputFilter::Rule::getNumActions(bool onActivation) const { + if (onActivation) { + return static_cast(m_activateActions.size()); + } else { + return static_cast(m_deactivateActions.size()); + } } -const InputFilter::Action& -InputFilter::Rule::getAction(bool onActivation, UInt32 index) const -{ - if (onActivation) { - return *m_activateActions[index]; - } - else { - return *m_deactivateActions[index]; - } +const InputFilter::Action &InputFilter::Rule::getAction(bool onActivation, + UInt32 index) const { + if (onActivation) { + return *m_activateActions[index]; + } else { + return *m_deactivateActions[index]; + } } - // ----------------------------------------------------------------------------- // Input Filter Class // ----------------------------------------------------------------------------- -InputFilter::InputFilter(IEventQueue* events) : - m_primaryClient(NULL), - m_events(events) -{ - // do nothing +InputFilter::InputFilter(IEventQueue *events) + : m_primaryClient(NULL), m_events(events) { + // do nothing } -InputFilter::InputFilter(const InputFilter& x) : - m_ruleList(x.m_ruleList), - m_primaryClient(NULL), - m_events(x.m_events) -{ - setPrimaryClient(x.m_primaryClient); +InputFilter::InputFilter(const InputFilter &x) + : m_ruleList(x.m_ruleList), m_primaryClient(NULL), m_events(x.m_events) { + setPrimaryClient(x.m_primaryClient); } -InputFilter::~InputFilter() -{ +InputFilter::~InputFilter() { setPrimaryClient(NULL); } + +InputFilter &InputFilter::operator=(const InputFilter &x) { + if (&x != this) { + PrimaryClient *oldClient = m_primaryClient; setPrimaryClient(NULL); + + m_ruleList = x.m_ruleList; + + setPrimaryClient(oldClient); + } + return *this; } -InputFilter& -InputFilter::operator=(const InputFilter& x) -{ - if (&x != this) { - PrimaryClient* oldClient = m_primaryClient; - setPrimaryClient(NULL); - - m_ruleList = x.m_ruleList; - - setPrimaryClient(oldClient); - } - return *this; +void InputFilter::addFilterRule(const Rule &rule) { + m_ruleList.push_back(rule); + if (m_primaryClient != NULL) { + m_ruleList.back().enable(m_primaryClient); + } } -void -InputFilter::addFilterRule(const Rule& rule) -{ - m_ruleList.push_back(rule); - if (m_primaryClient != NULL) { - m_ruleList.back().enable(m_primaryClient); - } +void InputFilter::removeFilterRule(UInt32 index) { + if (m_primaryClient != NULL) { + m_ruleList[index].disable(m_primaryClient); + } + m_ruleList.erase(m_ruleList.begin() + index); } -void -InputFilter::removeFilterRule(UInt32 index) -{ - if (m_primaryClient != NULL) { - m_ruleList[index].disable(m_primaryClient); - } - m_ruleList.erase(m_ruleList.begin() + index); +InputFilter::Rule &InputFilter::getRule(UInt32 index) { + return m_ruleList[index]; } -InputFilter::Rule& -InputFilter::getRule(UInt32 index) -{ - return m_ruleList[index]; -} +void InputFilter::setPrimaryClient(PrimaryClient *client) { + if (m_primaryClient == client) { + return; + } -void -InputFilter::setPrimaryClient(PrimaryClient* client) -{ - if (m_primaryClient == client) { - return; + if (m_primaryClient != NULL) { + for (RuleList::iterator rule = m_ruleList.begin(); rule != m_ruleList.end(); + ++rule) { + rule->disable(m_primaryClient); } - if (m_primaryClient != NULL) { - for (RuleList::iterator rule = m_ruleList.begin(); - rule != m_ruleList.end(); ++rule) { - rule->disable(m_primaryClient); - } - - m_events->removeHandler(m_events->forIKeyState().keyDown(), + m_events->removeHandler(m_events->forIKeyState().keyDown(), m_primaryClient->getEventTarget()); - m_events->removeHandler(m_events->forIKeyState().keyUp(), + m_events->removeHandler(m_events->forIKeyState().keyUp(), m_primaryClient->getEventTarget()); - m_events->removeHandler(m_events->forIKeyState().keyRepeat(), + m_events->removeHandler(m_events->forIKeyState().keyRepeat(), m_primaryClient->getEventTarget()); - m_events->removeHandler(m_events->forIPrimaryScreen().buttonDown(), + m_events->removeHandler(m_events->forIPrimaryScreen().buttonDown(), m_primaryClient->getEventTarget()); - m_events->removeHandler(m_events->forIPrimaryScreen().buttonUp(), + m_events->removeHandler(m_events->forIPrimaryScreen().buttonUp(), m_primaryClient->getEventTarget()); - m_events->removeHandler(m_events->forIPrimaryScreen().hotKeyDown(), + m_events->removeHandler(m_events->forIPrimaryScreen().hotKeyDown(), m_primaryClient->getEventTarget()); - m_events->removeHandler(m_events->forIPrimaryScreen().hotKeyUp(), + m_events->removeHandler(m_events->forIPrimaryScreen().hotKeyUp(), m_primaryClient->getEventTarget()); - m_events->removeHandler(m_events->forServer().connected(), + m_events->removeHandler(m_events->forServer().connected(), m_primaryClient->getEventTarget()); + } + + m_primaryClient = client; + + if (m_primaryClient != NULL) { + m_events->adoptHandler( + m_events->forIKeyState().keyDown(), m_primaryClient->getEventTarget(), + new TMethodEventJob(this, &InputFilter::handleEvent)); + m_events->adoptHandler( + m_events->forIKeyState().keyUp(), m_primaryClient->getEventTarget(), + new TMethodEventJob(this, &InputFilter::handleEvent)); + m_events->adoptHandler( + m_events->forIKeyState().keyRepeat(), m_primaryClient->getEventTarget(), + new TMethodEventJob(this, &InputFilter::handleEvent)); + m_events->adoptHandler( + m_events->forIPrimaryScreen().buttonDown(), + m_primaryClient->getEventTarget(), + new TMethodEventJob(this, &InputFilter::handleEvent)); + m_events->adoptHandler( + m_events->forIPrimaryScreen().buttonUp(), + m_primaryClient->getEventTarget(), + new TMethodEventJob(this, &InputFilter::handleEvent)); + m_events->adoptHandler( + m_events->forIPrimaryScreen().hotKeyDown(), + m_primaryClient->getEventTarget(), + new TMethodEventJob(this, &InputFilter::handleEvent)); + m_events->adoptHandler( + m_events->forIPrimaryScreen().hotKeyUp(), + m_primaryClient->getEventTarget(), + new TMethodEventJob(this, &InputFilter::handleEvent)); + m_events->adoptHandler( + m_events->forServer().connected(), m_primaryClient->getEventTarget(), + new TMethodEventJob(this, &InputFilter::handleEvent)); + + for (RuleList::iterator rule = m_ruleList.begin(); rule != m_ruleList.end(); + ++rule) { + rule->enable(m_primaryClient); } - - m_primaryClient = client; - - if (m_primaryClient != NULL) { - m_events->adoptHandler(m_events->forIKeyState().keyDown(), - m_primaryClient->getEventTarget(), - new TMethodEventJob(this, - &InputFilter::handleEvent)); - m_events->adoptHandler(m_events->forIKeyState().keyUp(), - m_primaryClient->getEventTarget(), - new TMethodEventJob(this, - &InputFilter::handleEvent)); - m_events->adoptHandler(m_events->forIKeyState().keyRepeat(), - m_primaryClient->getEventTarget(), - new TMethodEventJob(this, - &InputFilter::handleEvent)); - m_events->adoptHandler(m_events->forIPrimaryScreen().buttonDown(), - m_primaryClient->getEventTarget(), - new TMethodEventJob(this, - &InputFilter::handleEvent)); - m_events->adoptHandler(m_events->forIPrimaryScreen().buttonUp(), - m_primaryClient->getEventTarget(), - new TMethodEventJob(this, - &InputFilter::handleEvent)); - m_events->adoptHandler(m_events->forIPrimaryScreen().hotKeyDown(), - m_primaryClient->getEventTarget(), - new TMethodEventJob(this, - &InputFilter::handleEvent)); - m_events->adoptHandler(m_events->forIPrimaryScreen().hotKeyUp(), - m_primaryClient->getEventTarget(), - new TMethodEventJob(this, - &InputFilter::handleEvent)); - m_events->adoptHandler(m_events->forServer().connected(), - m_primaryClient->getEventTarget(), - new TMethodEventJob(this, - &InputFilter::handleEvent)); - - for (RuleList::iterator rule = m_ruleList.begin(); - rule != m_ruleList.end(); ++rule) { - rule->enable(m_primaryClient); - } - } + } } -String -InputFilter::format(const String& linePrefix) const -{ - String s; - for (RuleList::const_iterator i = m_ruleList.begin(); - i != m_ruleList.end(); ++i) { - s += linePrefix; - s += i->format(); - s += "\n"; - } - return s; +String InputFilter::format(const String &linePrefix) const { + String s; + for (RuleList::const_iterator i = m_ruleList.begin(); i != m_ruleList.end(); + ++i) { + s += linePrefix; + s += i->format(); + s += "\n"; + } + return s; } -UInt32 -InputFilter::getNumRules() const -{ - return static_cast(m_ruleList.size()); +UInt32 InputFilter::getNumRules() const { + return static_cast(m_ruleList.size()); } -bool -InputFilter::operator==(const InputFilter& x) const -{ - // if there are different numbers of rules then we can't be equal - if (m_ruleList.size() != x.m_ruleList.size()) { - return false; - } +bool InputFilter::operator==(const InputFilter &x) const { + // if there are different numbers of rules then we can't be equal + if (m_ruleList.size() != x.m_ruleList.size()) { + return false; + } - // compare rule lists. the easiest way to do that is to format each - // rule into a string, sort the strings, then compare the results. - std::vector aList, bList; - for (RuleList::const_iterator i = m_ruleList.begin(); - i != m_ruleList.end(); ++i) { - aList.push_back(i->format()); - } - for (RuleList::const_iterator i = x.m_ruleList.begin(); - i != x.m_ruleList.end(); ++i) { - bList.push_back(i->format()); - } - std::partial_sort(aList.begin(), aList.end(), aList.end()); - std::partial_sort(bList.begin(), bList.end(), bList.end()); - return (aList == bList); + // compare rule lists. the easiest way to do that is to format each + // rule into a string, sort the strings, then compare the results. + std::vector aList, bList; + for (RuleList::const_iterator i = m_ruleList.begin(); i != m_ruleList.end(); + ++i) { + aList.push_back(i->format()); + } + for (RuleList::const_iterator i = x.m_ruleList.begin(); + i != x.m_ruleList.end(); ++i) { + bList.push_back(i->format()); + } + std::partial_sort(aList.begin(), aList.end(), aList.end()); + std::partial_sort(bList.begin(), bList.end(), bList.end()); + return (aList == bList); } -bool -InputFilter::operator!=(const InputFilter& x) const -{ - return !operator==(x); +bool InputFilter::operator!=(const InputFilter &x) const { + return !operator==(x); } -void -InputFilter::handleEvent(const Event& event, void*) -{ - // copy event and adjust target - Event myEvent(event.getType(), this, event.getData(), - event.getFlags() | Event::kDontFreeData | - Event::kDeliverImmediately); +void InputFilter::handleEvent(const Event &event, void *) { + // copy event and adjust target + Event myEvent(event.getType(), this, event.getData(), + event.getFlags() | Event::kDontFreeData | + Event::kDeliverImmediately); - // let each rule try to match the event until one does - for (RuleList::iterator rule = m_ruleList.begin(); - rule != m_ruleList.end(); ++rule) { - if (rule->handleEvent(myEvent)) { - // handled - return; - } + // let each rule try to match the event until one does + for (RuleList::iterator rule = m_ruleList.begin(); rule != m_ruleList.end(); + ++rule) { + if (rule->handleEvent(myEvent)) { + // handled + return; } + } - // not handled so pass through - m_events->addEvent(myEvent); + // not handled so pass through + m_events->addEvent(myEvent); } - diff --git a/src/lib/server/InputFilter.h b/src/lib/server/InputFilter.h index f00932281..2de5566ba 100644 --- a/src/lib/server/InputFilter.h +++ b/src/lib/server/InputFilter.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2005 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 LICENSE 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 @@ -18,13 +18,13 @@ #pragma once -#include "synergy/key_types.h" -#include "synergy/mouse_types.h" -#include "synergy/protocol_types.h" -#include "synergy/IPlatformScreen.h" #include "base/String.h" #include "common/stdmap.h" #include "common/stdset.h" +#include "synergy/IPlatformScreen.h" +#include "synergy/key_types.h" +#include "synergy/mouse_types.h" +#include "synergy/protocol_types.h" class PrimaryClient; class Event; @@ -32,358 +32,351 @@ class IEventQueue; class InputFilter { public: - // ------------------------------------------------------------------------- - // Input Filter Condition Classes - // ------------------------------------------------------------------------- - enum EFilterStatus { - kNoMatch, - kActivate, - kDeactivate - }; - - class Condition { - public: - Condition(); - virtual ~Condition(); - - virtual Condition* clone() const = 0; - virtual String format() const = 0; - - virtual EFilterStatus match(const Event&) = 0; - - virtual void enablePrimary(PrimaryClient*); - virtual void disablePrimary(PrimaryClient*); - }; - - // KeystrokeCondition - class KeystrokeCondition : public Condition { - public: - KeystrokeCondition(IEventQueue* events, IPlatformScreen::KeyInfo*); - KeystrokeCondition(IEventQueue* events, KeyID key, KeyModifierMask mask); - virtual ~KeystrokeCondition(); - - KeyID getKey() const; - KeyModifierMask getMask() const; - - // Condition overrides - virtual Condition* clone() const; - virtual String format() const; - virtual EFilterStatus match(const Event&); - virtual void enablePrimary(PrimaryClient*); - virtual void disablePrimary(PrimaryClient*); - - private: - UInt32 m_id; - KeyID m_key; - KeyModifierMask m_mask; - IEventQueue* m_events; - }; - - // MouseButtonCondition - class MouseButtonCondition : public Condition { - public: - MouseButtonCondition(IEventQueue* events, IPlatformScreen::ButtonInfo*); - MouseButtonCondition(IEventQueue* events, ButtonID, KeyModifierMask mask); - virtual ~MouseButtonCondition(); - - ButtonID getButton() const; - KeyModifierMask getMask() const; - - // Condition overrides - virtual Condition* clone() const; - virtual String format() const; - virtual EFilterStatus match(const Event&); - - private: - ButtonID m_button; - KeyModifierMask m_mask; - IEventQueue* m_events; - }; - - // ScreenConnectedCondition - class ScreenConnectedCondition : public Condition { - public: - ScreenConnectedCondition(IEventQueue* events, const String& screen); - virtual ~ScreenConnectedCondition(); - - // Condition overrides - virtual Condition* clone() const; - virtual String format() const; - virtual EFilterStatus match(const Event&); - - private: - String m_screen; - IEventQueue* m_events; - }; - - // ------------------------------------------------------------------------- - // Input Filter Action Classes - // ------------------------------------------------------------------------- - - class Action { - public: - Action(); - virtual ~Action(); - - virtual Action* clone() const = 0; - virtual String format() const = 0; - - virtual void perform(const Event&) = 0; - }; - - // LockCursorToScreenAction - class LockCursorToScreenAction : public Action { - public: - enum Mode { kOff, kOn, kToggle }; - - LockCursorToScreenAction(IEventQueue* events, Mode = kToggle); - - Mode getMode() const; - - // Action overrides - virtual Action* clone() const; - virtual String format() const; - virtual void perform(const Event&); - - private: - Mode m_mode; - IEventQueue* m_events; - }; - - class RestartServer : public Action { - public: - enum Mode { restart }; - - RestartServer(IEventQueue* events, Mode = restart); - - Mode getMode() const; - - // Action overrides - virtual Action* clone() const; - virtual String format() const; - virtual void perform(const Event&); - - private: - Mode m_mode; - IEventQueue* m_events; - }; - - // SwitchToScreenAction - class SwitchToScreenAction : public Action { - public: - SwitchToScreenAction(IEventQueue* events, const String& screen); - - String getScreen() const; - - // Action overrides - virtual Action* clone() const; - virtual String format() const; - virtual void perform(const Event&); - - private: - String m_screen; - IEventQueue* m_events; - }; - - // SwitchInDirectionAction - class SwitchInDirectionAction : public Action { - public: - SwitchInDirectionAction(IEventQueue* events, EDirection); - - EDirection getDirection() const; - - // Action overrides - virtual Action* clone() const; - virtual String format() const; - virtual void perform(const Event&); - - private: - EDirection m_direction; - IEventQueue* m_events; - }; - - // KeyboardBroadcastAction - class KeyboardBroadcastAction : public Action { - public: - enum Mode { kOff, kOn, kToggle }; - - KeyboardBroadcastAction(IEventQueue* events, Mode = kToggle); - KeyboardBroadcastAction(IEventQueue* events, Mode, const std::set& screens); - - Mode getMode() const; - std::set getScreens() const; - - // Action overrides - virtual Action* clone() const; - virtual String format() const; - virtual void perform(const Event&); - - private: - Mode m_mode; - String m_screens; - IEventQueue* m_events; - }; - - // KeystrokeAction - class KeystrokeAction : public Action { - public: - KeystrokeAction(IEventQueue* events, IPlatformScreen::KeyInfo* adoptedInfo, bool press); - KeystrokeAction(KeystrokeAction const &) =delete; - KeystrokeAction(KeystrokeAction &&) =delete; - ~KeystrokeAction(); - - KeystrokeAction& operator=(KeystrokeAction const &) =delete; - KeystrokeAction& operator=(KeystrokeAction &&) =delete; - - void adoptInfo(IPlatformScreen::KeyInfo*); - const IPlatformScreen::KeyInfo* - getInfo() const; - bool isOnPress() const; - - // Action overrides - virtual Action* clone() const; - virtual String format() const; - virtual void perform(const Event&); - - protected: - virtual const char* formatName() const; - - private: - IPlatformScreen::KeyInfo* m_keyInfo; - bool m_press; - IEventQueue* m_events; - }; - - // MouseButtonAction -- modifier combinations not implemented yet - class MouseButtonAction : public Action { - public: - MouseButtonAction(IEventQueue* events, - IPlatformScreen::ButtonInfo* adoptedInfo, - bool press); - MouseButtonAction(MouseButtonAction const &) =delete; - MouseButtonAction(MouseButtonAction &&) =delete; - ~MouseButtonAction(); - - MouseButtonAction& operator=(MouseButtonAction const &) =delete; - MouseButtonAction& operator=(MouseButtonAction &&) =delete; - - const IPlatformScreen::ButtonInfo* - getInfo() const; - bool isOnPress() const; - - // Action overrides - virtual Action* clone() const; - virtual String format() const; - virtual void perform(const Event&); - - protected: - virtual const char* formatName() const; - - private: - IPlatformScreen::ButtonInfo* m_buttonInfo; - bool m_press; - IEventQueue* m_events; - }; - - class Rule { - public: - Rule(); - Rule(Condition* adopted); - Rule(const Rule&); - ~Rule(); - - Rule& operator=(const Rule&); - - // replace the condition - void setCondition(Condition* adopted); - - // add an action to the rule - void adoptAction(Action*, bool onActivation); - - // remove an action from the rule - void removeAction(bool onActivation, UInt32 index); - - // replace an action in the rule - void replaceAction(Action* adopted, - bool onActivation, UInt32 index); - - // enable/disable - void enable(PrimaryClient*); - void disable(PrimaryClient*); - - // event handling - bool handleEvent(const Event&); - - // convert rule to a string - String format() const; - - // get the rule's condition - const Condition* - getCondition() const; - - // get number of actions - UInt32 getNumActions(bool onActivation) const; - - // get action by index - const Action& getAction(bool onActivation, UInt32 index) const; - - private: - void clear(); - void copy(const Rule&); - - private: - typedef std::vector ActionList; - - Condition* m_condition; - ActionList m_activateActions; - ActionList m_deactivateActions; - }; - - // ------------------------------------------------------------------------- - // Input Filter Class - // ------------------------------------------------------------------------- - typedef std::vector RuleList; - - InputFilter(IEventQueue* events); - InputFilter(const InputFilter&); - virtual ~InputFilter(); + // ------------------------------------------------------------------------- + // Input Filter Condition Classes + // ------------------------------------------------------------------------- + enum EFilterStatus { kNoMatch, kActivate, kDeactivate }; + + class Condition { + public: + Condition(); + virtual ~Condition(); + + virtual Condition *clone() const = 0; + virtual String format() const = 0; + + virtual EFilterStatus match(const Event &) = 0; + + virtual void enablePrimary(PrimaryClient *); + virtual void disablePrimary(PrimaryClient *); + }; + + // KeystrokeCondition + class KeystrokeCondition : public Condition { + public: + KeystrokeCondition(IEventQueue *events, IPlatformScreen::KeyInfo *); + KeystrokeCondition(IEventQueue *events, KeyID key, KeyModifierMask mask); + virtual ~KeystrokeCondition(); + + KeyID getKey() const; + KeyModifierMask getMask() const; + + // Condition overrides + virtual Condition *clone() const; + virtual String format() const; + virtual EFilterStatus match(const Event &); + virtual void enablePrimary(PrimaryClient *); + virtual void disablePrimary(PrimaryClient *); + + private: + UInt32 m_id; + KeyID m_key; + KeyModifierMask m_mask; + IEventQueue *m_events; + }; + + // MouseButtonCondition + class MouseButtonCondition : public Condition { + public: + MouseButtonCondition(IEventQueue *events, IPlatformScreen::ButtonInfo *); + MouseButtonCondition(IEventQueue *events, ButtonID, KeyModifierMask mask); + virtual ~MouseButtonCondition(); + + ButtonID getButton() const; + KeyModifierMask getMask() const; + + // Condition overrides + virtual Condition *clone() const; + virtual String format() const; + virtual EFilterStatus match(const Event &); + + private: + ButtonID m_button; + KeyModifierMask m_mask; + IEventQueue *m_events; + }; + + // ScreenConnectedCondition + class ScreenConnectedCondition : public Condition { + public: + ScreenConnectedCondition(IEventQueue *events, const String &screen); + virtual ~ScreenConnectedCondition(); + + // Condition overrides + virtual Condition *clone() const; + virtual String format() const; + virtual EFilterStatus match(const Event &); + + private: + String m_screen; + IEventQueue *m_events; + }; + + // ------------------------------------------------------------------------- + // Input Filter Action Classes + // ------------------------------------------------------------------------- + + class Action { + public: + Action(); + virtual ~Action(); + + virtual Action *clone() const = 0; + virtual String format() const = 0; + + virtual void perform(const Event &) = 0; + }; + + // LockCursorToScreenAction + class LockCursorToScreenAction : public Action { + public: + enum Mode { kOff, kOn, kToggle }; + + LockCursorToScreenAction(IEventQueue *events, Mode = kToggle); + + Mode getMode() const; + + // Action overrides + virtual Action *clone() const; + virtual String format() const; + virtual void perform(const Event &); + + private: + Mode m_mode; + IEventQueue *m_events; + }; + + class RestartServer : public Action { + public: + enum Mode { restart }; + + RestartServer(IEventQueue *events, Mode = restart); + + Mode getMode() const; + + // Action overrides + virtual Action *clone() const; + virtual String format() const; + virtual void perform(const Event &); + + private: + Mode m_mode; + IEventQueue *m_events; + }; + + // SwitchToScreenAction + class SwitchToScreenAction : public Action { + public: + SwitchToScreenAction(IEventQueue *events, const String &screen); + + String getScreen() const; + + // Action overrides + virtual Action *clone() const; + virtual String format() const; + virtual void perform(const Event &); + + private: + String m_screen; + IEventQueue *m_events; + }; + + // SwitchInDirectionAction + class SwitchInDirectionAction : public Action { + public: + SwitchInDirectionAction(IEventQueue *events, EDirection); + + EDirection getDirection() const; + + // Action overrides + virtual Action *clone() const; + virtual String format() const; + virtual void perform(const Event &); + + private: + EDirection m_direction; + IEventQueue *m_events; + }; + + // KeyboardBroadcastAction + class KeyboardBroadcastAction : public Action { + public: + enum Mode { kOff, kOn, kToggle }; + + KeyboardBroadcastAction(IEventQueue *events, Mode = kToggle); + KeyboardBroadcastAction(IEventQueue *events, Mode, + const std::set &screens); + + Mode getMode() const; + std::set getScreens() const; + + // Action overrides + virtual Action *clone() const; + virtual String format() const; + virtual void perform(const Event &); + + private: + Mode m_mode; + String m_screens; + IEventQueue *m_events; + }; + + // KeystrokeAction + class KeystrokeAction : public Action { + public: + KeystrokeAction(IEventQueue *events, IPlatformScreen::KeyInfo *adoptedInfo, + bool press); + KeystrokeAction(KeystrokeAction const &) = delete; + KeystrokeAction(KeystrokeAction &&) = delete; + ~KeystrokeAction(); + + KeystrokeAction &operator=(KeystrokeAction const &) = delete; + KeystrokeAction &operator=(KeystrokeAction &&) = delete; + + void adoptInfo(IPlatformScreen::KeyInfo *); + const IPlatformScreen::KeyInfo *getInfo() const; + bool isOnPress() const; + + // Action overrides + virtual Action *clone() const; + virtual String format() const; + virtual void perform(const Event &); + + protected: + virtual const char *formatName() const; + + private: + IPlatformScreen::KeyInfo *m_keyInfo; + bool m_press; + IEventQueue *m_events; + }; + + // MouseButtonAction -- modifier combinations not implemented yet + class MouseButtonAction : public Action { + public: + MouseButtonAction(IEventQueue *events, + IPlatformScreen::ButtonInfo *adoptedInfo, bool press); + MouseButtonAction(MouseButtonAction const &) = delete; + MouseButtonAction(MouseButtonAction &&) = delete; + ~MouseButtonAction(); + + MouseButtonAction &operator=(MouseButtonAction const &) = delete; + MouseButtonAction &operator=(MouseButtonAction &&) = delete; + + const IPlatformScreen::ButtonInfo *getInfo() const; + bool isOnPress() const; + + // Action overrides + virtual Action *clone() const; + virtual String format() const; + virtual void perform(const Event &); + + protected: + virtual const char *formatName() const; + + private: + IPlatformScreen::ButtonInfo *m_buttonInfo; + bool m_press; + IEventQueue *m_events; + }; + + class Rule { + public: + Rule(); + Rule(Condition *adopted); + Rule(const Rule &); + ~Rule(); + + Rule &operator=(const Rule &); + + // replace the condition + void setCondition(Condition *adopted); + + // add an action to the rule + void adoptAction(Action *, bool onActivation); + + // remove an action from the rule + void removeAction(bool onActivation, UInt32 index); + + // replace an action in the rule + void replaceAction(Action *adopted, bool onActivation, UInt32 index); + + // enable/disable + void enable(PrimaryClient *); + void disable(PrimaryClient *); + + // event handling + bool handleEvent(const Event &); + + // convert rule to a string + String format() const; + + // get the rule's condition + const Condition *getCondition() const; + + // get number of actions + UInt32 getNumActions(bool onActivation) const; + + // get action by index + const Action &getAction(bool onActivation, UInt32 index) const; + + private: + void clear(); + void copy(const Rule &); + + private: + typedef std::vector ActionList; + + Condition *m_condition; + ActionList m_activateActions; + ActionList m_deactivateActions; + }; + + // ------------------------------------------------------------------------- + // Input Filter Class + // ------------------------------------------------------------------------- + typedef std::vector RuleList; + + InputFilter(IEventQueue *events); + InputFilter(const InputFilter &); + virtual ~InputFilter(); #ifdef TEST_ENV - InputFilter() : m_primaryClient(NULL) { } + InputFilter() : m_primaryClient(NULL) {} #endif - InputFilter& operator=(const InputFilter&); + InputFilter &operator=(const InputFilter &); - // add rule, adopting the condition and the actions - void addFilterRule(const Rule& rule); + // add rule, adopting the condition and the actions + void addFilterRule(const Rule &rule); - // remove a rule - void removeFilterRule(UInt32 index); + // remove a rule + void removeFilterRule(UInt32 index); - // get rule by index - Rule& getRule(UInt32 index); + // get rule by index + Rule &getRule(UInt32 index); - // enable event filtering using the given primary client. disable - // if client is NULL. - virtual void setPrimaryClient(PrimaryClient* client); + // enable event filtering using the given primary client. disable + // if client is NULL. + virtual void setPrimaryClient(PrimaryClient *client); - // convert rules to a string - String format(const String& linePrefix) const; + // convert rules to a string + String format(const String &linePrefix) const; - // get number of rules - UInt32 getNumRules() const; + // get number of rules + UInt32 getNumRules() const; - //! Compare filters - bool operator==(const InputFilter&) const; - //! Compare filters - bool operator!=(const InputFilter&) const; + //! Compare filters + bool operator==(const InputFilter &) const; + //! Compare filters + bool operator!=(const InputFilter &) const; private: - // event handling - void handleEvent(const Event&, void*); + // event handling + void handleEvent(const Event &, void *); private: - RuleList m_ruleList; - PrimaryClient* m_primaryClient; - IEventQueue* m_events; + RuleList m_ruleList; + PrimaryClient *m_primaryClient; + IEventQueue *m_events; }; diff --git a/src/lib/server/PrimaryClient.cpp b/src/lib/server/PrimaryClient.cpp index 9c56b0812..8e5841d28 100644 --- a/src/lib/server/PrimaryClient.cpp +++ b/src/lib/server/PrimaryClient.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -18,280 +18,202 @@ #include "server/PrimaryClient.h" -#include "synergy/Screen.h" -#include "synergy/Clipboard.h" #include "base/Log.h" #include "synergy/AppUtil.h" +#include "synergy/Clipboard.h" +#include "synergy/Screen.h" // // PrimaryClient // -PrimaryClient::PrimaryClient(const String& name, synergy::Screen* screen) : - BaseClientProxy(name), - m_screen(screen), - m_fakeInputCount(0) -{ - // all clipboards are clean - for (UInt32 i = 0; i < kClipboardEnd; ++i) { - m_clipboardDirty[i] = false; - } +PrimaryClient::PrimaryClient(const String &name, synergy::Screen *screen) + : BaseClientProxy(name), m_screen(screen), m_fakeInputCount(0) { + // all clipboards are clean + for (UInt32 i = 0; i < kClipboardEnd; ++i) { + m_clipboardDirty[i] = false; + } } -PrimaryClient::~PrimaryClient() -{ - // do nothing +PrimaryClient::~PrimaryClient() { + // do nothing } -void -PrimaryClient::reconfigure(UInt32 activeSides) -{ - m_screen->reconfigure(activeSides); +void PrimaryClient::reconfigure(UInt32 activeSides) { + m_screen->reconfigure(activeSides); } -UInt32 -PrimaryClient::registerHotKey(KeyID key, KeyModifierMask mask) -{ - return m_screen->registerHotKey(key, mask); +UInt32 PrimaryClient::registerHotKey(KeyID key, KeyModifierMask mask) { + return m_screen->registerHotKey(key, mask); } -void -PrimaryClient::unregisterHotKey(UInt32 id) -{ - m_screen->unregisterHotKey(id); +void PrimaryClient::unregisterHotKey(UInt32 id) { + m_screen->unregisterHotKey(id); } -void -PrimaryClient::fakeInputBegin() -{ - if (++m_fakeInputCount == 1) { - m_screen->fakeInputBegin(); - } +void PrimaryClient::fakeInputBegin() { + if (++m_fakeInputCount == 1) { + m_screen->fakeInputBegin(); + } } -void -PrimaryClient::fakeInputEnd() -{ - if (--m_fakeInputCount == 0) { - m_screen->fakeInputEnd(); - } +void PrimaryClient::fakeInputEnd() { + if (--m_fakeInputCount == 0) { + m_screen->fakeInputEnd(); + } } -SInt32 -PrimaryClient::getJumpZoneSize() const -{ - return m_screen->getJumpZoneSize(); +SInt32 PrimaryClient::getJumpZoneSize() const { + return m_screen->getJumpZoneSize(); } -void -PrimaryClient::getCursorCenter(SInt32& x, SInt32& y) const -{ - m_screen->getCursorCenter(x, y); +void PrimaryClient::getCursorCenter(SInt32 &x, SInt32 &y) const { + m_screen->getCursorCenter(x, y); } -KeyModifierMask -PrimaryClient::getToggleMask() const -{ - return m_screen->pollActiveModifiers(); +KeyModifierMask PrimaryClient::getToggleMask() const { + return m_screen->pollActiveModifiers(); } -bool -PrimaryClient::isLockedToScreen() const -{ - return m_screen->isLockedToScreen(); +bool PrimaryClient::isLockedToScreen() const { + return m_screen->isLockedToScreen(); } -void* -PrimaryClient::getEventTarget() const -{ - return m_screen->getEventTarget(); +void *PrimaryClient::getEventTarget() const { + return m_screen->getEventTarget(); } -bool -PrimaryClient::getClipboard(ClipboardID id, IClipboard* clipboard) const -{ - return m_screen->getClipboard(id, clipboard); +bool PrimaryClient::getClipboard(ClipboardID id, IClipboard *clipboard) const { + return m_screen->getClipboard(id, clipboard); } -void -PrimaryClient::getShape(SInt32& x, SInt32& y, - SInt32& width, SInt32& height) const -{ - m_screen->getShape(x, y, width, height); +void PrimaryClient::getShape(SInt32 &x, SInt32 &y, SInt32 &width, + SInt32 &height) const { + m_screen->getShape(x, y, width, height); } -void -PrimaryClient::getCursorPos(SInt32& x, SInt32& y) const -{ - m_screen->getCursorPos(x, y); +void PrimaryClient::getCursorPos(SInt32 &x, SInt32 &y) const { + m_screen->getCursorPos(x, y); } -void -PrimaryClient::enable() -{ - m_screen->enable(); +void PrimaryClient::enable() { m_screen->enable(); } + +void PrimaryClient::disable() { m_screen->disable(); } + +void PrimaryClient::enter(SInt32 xAbs, SInt32 yAbs, UInt32 seqNum, + KeyModifierMask mask, bool screensaver) { + m_screen->setSequenceNumber(seqNum); + if (!screensaver) { + m_screen->warpCursor(xAbs, yAbs); + } + m_screen->enter(mask); } -void -PrimaryClient::disable() -{ - m_screen->disable(); +bool PrimaryClient::leave() { return m_screen->leave(); } + +void PrimaryClient::setClipboard(ClipboardID id, const IClipboard *clipboard) { + // ignore if this clipboard is already clean + if (m_clipboardDirty[id]) { + // this clipboard is now clean + m_clipboardDirty[id] = false; + + // set clipboard + m_screen->setClipboard(id, clipboard); + } } -void -PrimaryClient::enter(SInt32 xAbs, SInt32 yAbs, - UInt32 seqNum, KeyModifierMask mask, bool screensaver) -{ - m_screen->setSequenceNumber(seqNum); - if (!screensaver) { - m_screen->warpCursor(xAbs, yAbs); - } - m_screen->enter(mask); +void PrimaryClient::grabClipboard(ClipboardID id) { + // grab clipboard + m_screen->grabClipboard(id); + + // clipboard is dirty (because someone else owns it now) + m_clipboardDirty[id] = true; } -bool -PrimaryClient::leave() -{ - return m_screen->leave(); +void PrimaryClient::setClipboardDirty(ClipboardID id, bool dirty) { + m_clipboardDirty[id] = dirty; } -void -PrimaryClient::setClipboard(ClipboardID id, const IClipboard* clipboard) -{ - // ignore if this clipboard is already clean - if (m_clipboardDirty[id]) { - // this clipboard is now clean - m_clipboardDirty[id] = false; - - // set clipboard - m_screen->setClipboard(id, clipboard); - } +void PrimaryClient::keyDown(KeyID key, KeyModifierMask mask, KeyButton button, + const String &) { + if (m_fakeInputCount > 0) { + // XXX -- don't forward keystrokes to primary screen for now + (void)key; + (void)mask; + (void)button; + // m_screen->keyDown(key, mask, button); + } } -void -PrimaryClient::grabClipboard(ClipboardID id) -{ - // grab clipboard - m_screen->grabClipboard(id); - - // clipboard is dirty (because someone else owns it now) - m_clipboardDirty[id] = true; +void PrimaryClient::keyRepeat(KeyID, KeyModifierMask, SInt32, KeyButton, + const String &) { + // ignore } -void -PrimaryClient::setClipboardDirty(ClipboardID id, bool dirty) -{ - m_clipboardDirty[id] = dirty; +void PrimaryClient::keyUp(KeyID key, KeyModifierMask mask, KeyButton button) { + if (m_fakeInputCount > 0) { + // XXX -- don't forward keystrokes to primary screen for now + (void)key; + (void)mask; + (void)button; + // m_screen->keyUp(key, mask, button); + } } -void -PrimaryClient::keyDown(KeyID key, KeyModifierMask mask, KeyButton button, const String&) -{ - if (m_fakeInputCount > 0) { -// XXX -- don't forward keystrokes to primary screen for now - (void)key; - (void)mask; - (void)button; -// m_screen->keyDown(key, mask, button); - } +void PrimaryClient::mouseDown(ButtonID) { + // ignore } -void -PrimaryClient::keyRepeat(KeyID, KeyModifierMask, SInt32, KeyButton, const String&) -{ - // ignore +void PrimaryClient::mouseUp(ButtonID) { + // ignore } -void -PrimaryClient::keyUp(KeyID key, KeyModifierMask mask, KeyButton button) -{ - if (m_fakeInputCount > 0) { -// XXX -- don't forward keystrokes to primary screen for now - (void)key; - (void)mask; - (void)button; -// m_screen->keyUp(key, mask, button); - } +void PrimaryClient::mouseMove(SInt32 x, SInt32 y) { + m_screen->warpCursor(x, y); } -void -PrimaryClient::mouseDown(ButtonID) -{ - // ignore +void PrimaryClient::mouseRelativeMove(SInt32, SInt32) { + // ignore } -void -PrimaryClient::mouseUp(ButtonID) -{ - // ignore +void PrimaryClient::mouseWheel(SInt32, SInt32) { + // ignore } -void -PrimaryClient::mouseMove(SInt32 x, SInt32 y) -{ - m_screen->warpCursor(x, y); +void PrimaryClient::screensaver(bool) { + // ignore } -void -PrimaryClient::mouseRelativeMove(SInt32, SInt32) -{ - // ignore +void PrimaryClient::sendDragInfo(UInt32 fileCount, const char *info, + size_t size) { + // ignore } -void -PrimaryClient::mouseWheel(SInt32, SInt32) -{ - // ignore +void PrimaryClient::fileChunkSending(UInt8 mark, char *data, size_t dataSize) { + // ignore } -void -PrimaryClient::screensaver(bool) -{ - // ignore +String PrimaryClient::getSecureInputApp() const { + return m_screen->getSecureInputApp(); } -void -PrimaryClient::sendDragInfo(UInt32 fileCount, const char* info, size_t size) -{ - // ignore +void PrimaryClient::secureInputNotification(const String &app) const { + if (app != "unknown") { + AppUtil::instance().showNotification( + "The client keyboards may stop working.", + "'Secure input' enabled by " + app + + ". " + "Close " + + app + " to continue using keyboards on the clients."); + } else { + AppUtil::instance().showNotification( + "The client keyboards may stop working.", + "'Secure input' enabled by an application. " + "Close the application to continue using keyboards on the clients."); + } } -void -PrimaryClient::fileChunkSending(UInt8 mark, char* data, size_t dataSize) -{ - // ignore -} +void PrimaryClient::resetOptions() { m_screen->resetOptions(); } -String -PrimaryClient::getSecureInputApp() const -{ - return m_screen->getSecureInputApp(); -} - -void -PrimaryClient::secureInputNotification(const String& app) const -{ - if (app != "unknown") { - AppUtil::instance().showNotification( - "The client keyboards may stop working.", - "'Secure input' enabled by " + app + ". " \ - "Close " + app + " to continue using keyboards on the clients."); - } - else { - AppUtil::instance().showNotification( - "The client keyboards may stop working.", - "'Secure input' enabled by an application. " \ - "Close the application to continue using keyboards on the clients."); - } -} - -void -PrimaryClient::resetOptions() -{ - m_screen->resetOptions(); -} - -void -PrimaryClient::setOptions(const OptionsList& options) -{ - m_screen->setOptions(options); +void PrimaryClient::setOptions(const OptionsList &options) { + m_screen->setOptions(options); } diff --git a/src/lib/server/PrimaryClient.h b/src/lib/server/PrimaryClient.h index aad050ce8..3bcb38006 100644 --- a/src/lib/server/PrimaryClient.h +++ b/src/lib/server/PrimaryClient.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -21,7 +21,9 @@ #include "server/BaseClientProxy.h" #include "synergy/protocol_types.h" -namespace synergy { class Screen; } +namespace synergy { +class Screen; +} //! Primary screen as pseudo-client /*! @@ -31,128 +33,126 @@ treated as if it was a client. */ class PrimaryClient : public BaseClientProxy { public: - /*! - \c name is the name of the server and \p screen is primary screen. - */ - PrimaryClient(const String& name, synergy::Screen* screen); - ~PrimaryClient(); + /*! + \c name is the name of the server and \p screen is primary screen. + */ + PrimaryClient(const String &name, synergy::Screen *screen); + ~PrimaryClient(); #ifdef TEST_ENV - PrimaryClient() : BaseClientProxy("") { } + PrimaryClient() : BaseClientProxy("") {} #endif - //! @name manipulators - //@{ + //! @name manipulators + //@{ - //! Update configuration - /*! - Handles reconfiguration of jump zones. - */ - virtual void reconfigure(UInt32 activeSides); + //! Update configuration + /*! + Handles reconfiguration of jump zones. + */ + virtual void reconfigure(UInt32 activeSides); - //! Register a system hotkey - /*! - Registers a system-wide hotkey for key \p key with modifiers \p mask. - Returns an id used to unregister the hotkey. - */ - virtual UInt32 registerHotKey(KeyID key, KeyModifierMask mask); + //! Register a system hotkey + /*! + Registers a system-wide hotkey for key \p key with modifiers \p mask. + Returns an id used to unregister the hotkey. + */ + virtual UInt32 registerHotKey(KeyID key, KeyModifierMask mask); - //! Unregister a system hotkey - /*! - Unregisters a previously registered hot key. - */ - virtual void unregisterHotKey(UInt32 id); + //! Unregister a system hotkey + /*! + Unregisters a previously registered hot key. + */ + virtual void unregisterHotKey(UInt32 id); - //! Prepare to synthesize input on primary screen - /*! - Prepares the primary screen to receive synthesized input. We do not - want to receive this synthesized input as user input so this method - ensures that we ignore it. Calls to \c fakeInputBegin() and - \c fakeInputEnd() may be nested; only the outermost have an effect. - */ - void fakeInputBegin(); + //! Prepare to synthesize input on primary screen + /*! + Prepares the primary screen to receive synthesized input. We do not + want to receive this synthesized input as user input so this method + ensures that we ignore it. Calls to \c fakeInputBegin() and + \c fakeInputEnd() may be nested; only the outermost have an effect. + */ + void fakeInputBegin(); - //! Done synthesizing input on primary screen - /*! - Undoes whatever \c fakeInputBegin() did. - */ - void fakeInputEnd(); + //! Done synthesizing input on primary screen + /*! + Undoes whatever \c fakeInputBegin() did. + */ + void fakeInputEnd(); - //@} - //! @name accessors - //@{ + //@} + //! @name accessors + //@{ - //! Get jump zone size - /*! - Return the jump zone size, the size of the regions on the edges of - the screen that cause the cursor to jump to another screen. - */ - SInt32 getJumpZoneSize() const; + //! Get jump zone size + /*! + Return the jump zone size, the size of the regions on the edges of + the screen that cause the cursor to jump to another screen. + */ + SInt32 getJumpZoneSize() const; - //! Get cursor center position - /*! - Return the cursor center position which is where we park the - cursor to compute cursor motion deltas and should be far from - the edges of the screen, typically the center. - */ - void getCursorCenter(SInt32& x, SInt32& y) const; - - //! Get toggle key state - /*! - Returns the primary screen's current toggle modifier key state. - */ - virtual KeyModifierMask - getToggleMask() const; + //! Get cursor center position + /*! + Return the cursor center position which is where we park the + cursor to compute cursor motion deltas and should be far from + the edges of the screen, typically the center. + */ + void getCursorCenter(SInt32 &x, SInt32 &y) const; - //! Get screen lock state - /*! - Returns true if the user is locked to the screen. - */ - bool isLockedToScreen() const; + //! Get toggle key state + /*! + Returns the primary screen's current toggle modifier key state. + */ + virtual KeyModifierMask getToggleMask() const; - //@} + //! Get screen lock state + /*! + Returns true if the user is locked to the screen. + */ + bool isLockedToScreen() const; - // FIXME -- these probably belong on IScreen - virtual void enable(); - virtual void disable(); + //@} - // IScreen overrides - void* getEventTarget() const override; - bool getClipboard(ClipboardID id, IClipboard*) const override; - void getShape(SInt32& x, SInt32& y, - SInt32& width, SInt32& height) const override; - void getCursorPos(SInt32& x, SInt32& y) const override; + // FIXME -- these probably belong on IScreen + virtual void enable(); + virtual void disable(); - // IClient overrides - void enter(SInt32 xAbs, SInt32 yAbs, - UInt32 seqNum, KeyModifierMask mask, - bool forScreensaver) override; - bool leave() override; - void setClipboard(ClipboardID, const IClipboard*) override; - void grabClipboard(ClipboardID) override; - void setClipboardDirty(ClipboardID, bool) override; - void keyDown(KeyID, KeyModifierMask, KeyButton, const String&) override; - void keyRepeat(KeyID, KeyModifierMask, - SInt32 count, KeyButton, const String&) override; - void keyUp(KeyID, KeyModifierMask, KeyButton) override; - void mouseDown(ButtonID) override; - void mouseUp(ButtonID) override; - void mouseMove(SInt32 xAbs, SInt32 yAbs) override; - void mouseRelativeMove(SInt32 xRel, SInt32 yRel) override; - void mouseWheel(SInt32 xDelta, SInt32 yDelta) override; - void screensaver(bool activate) override; - void resetOptions() override; - void setOptions(const OptionsList& options) override; - void sendDragInfo(UInt32 fileCount, const char* info, size_t size) override; - void fileChunkSending(UInt8 mark, char* data, size_t dataSize) override; - String getSecureInputApp() const override; - void secureInputNotification(const String& app) const override; + // IScreen overrides + void *getEventTarget() const override; + bool getClipboard(ClipboardID id, IClipboard *) const override; + void getShape(SInt32 &x, SInt32 &y, SInt32 &width, + SInt32 &height) const override; + void getCursorPos(SInt32 &x, SInt32 &y) const override; + + // IClient overrides + void enter(SInt32 xAbs, SInt32 yAbs, UInt32 seqNum, KeyModifierMask mask, + bool forScreensaver) override; + bool leave() override; + void setClipboard(ClipboardID, const IClipboard *) override; + void grabClipboard(ClipboardID) override; + void setClipboardDirty(ClipboardID, bool) override; + void keyDown(KeyID, KeyModifierMask, KeyButton, const String &) override; + void keyRepeat(KeyID, KeyModifierMask, SInt32 count, KeyButton, + const String &) override; + void keyUp(KeyID, KeyModifierMask, KeyButton) override; + void mouseDown(ButtonID) override; + void mouseUp(ButtonID) override; + void mouseMove(SInt32 xAbs, SInt32 yAbs) override; + void mouseRelativeMove(SInt32 xRel, SInt32 yRel) override; + void mouseWheel(SInt32 xDelta, SInt32 yDelta) override; + void screensaver(bool activate) override; + void resetOptions() override; + void setOptions(const OptionsList &options) override; + void sendDragInfo(UInt32 fileCount, const char *info, size_t size) override; + void fileChunkSending(UInt8 mark, char *data, size_t dataSize) override; + String getSecureInputApp() const override; + void secureInputNotification(const String &app) const override; + + synergy::IStream *getStream() const override { return nullptr; } + bool isPrimary() const override { return true; } - synergy::IStream* - getStream() const override { return nullptr; } - bool isPrimary() const override { return true; } private: - synergy::Screen* m_screen; - bool m_clipboardDirty[kClipboardEnd]; - SInt32 m_fakeInputCount; + synergy::Screen *m_screen; + bool m_clipboardDirty[kClipboardEnd]; + SInt32 m_fakeInputCount; }; diff --git a/src/lib/server/Server.cpp b/src/lib/server/Server.cpp index 08c9b09dc..fe91a6e8b 100644 --- a/src/lib/server/Server.cpp +++ b/src/lib/server/Server.cpp @@ -18,2447 +18,2194 @@ #include "server/Server.h" -#include "server/ClientProxy.h" -#include "server/ClientProxyUnknown.h" -#include "server/PrimaryClient.h" -#include "server/ClientListener.h" -#include "synergy/FileChunk.h" -#include "synergy/IPlatformScreen.h" -#include "synergy/DropHelper.h" -#include "synergy/option_types.h" -#include "synergy/protocol_types.h" -#include "synergy/XScreen.h" -#include "synergy/XSynergy.h" -#include "synergy/StreamChunker.h" -#include "synergy/KeyState.h" -#include "synergy/Screen.h" -#include "synergy/PacketStreamFilter.h" -#include "synergy/AppUtil.h" -#include "net/TCPSocket.h" -#include "net/IDataSocket.h" -#include "net/IListenSocket.h" -#include "net/XSocket.h" -#include "mt/Thread.h" #include "arch/Arch.h" -#include "base/TMethodJob.h" #include "base/IEventQueue.h" #include "base/Log.h" #include "base/TMethodEventJob.h" +#include "base/TMethodJob.h" #include "common/stdexcept.h" +#include "mt/Thread.h" +#include "net/IDataSocket.h" +#include "net/IListenSocket.h" +#include "net/TCPSocket.h" +#include "net/XSocket.h" +#include "server/ClientListener.h" +#include "server/ClientProxy.h" +#include "server/ClientProxyUnknown.h" +#include "server/PrimaryClient.h" #include "shared/SerialKey.h" +#include "synergy/AppUtil.h" +#include "synergy/DropHelper.h" +#include "synergy/FileChunk.h" +#include "synergy/IPlatformScreen.h" +#include "synergy/KeyState.h" +#include "synergy/PacketStreamFilter.h" +#include "synergy/Screen.h" +#include "synergy/StreamChunker.h" +#include "synergy/XScreen.h" +#include "synergy/XSynergy.h" +#include "synergy/option_types.h" +#include "synergy/protocol_types.h" -#include -#include -#include -#include -#include #include +#include +#include +#include +#include +#include // // Server // -Server::Server( - Config& config, - PrimaryClient* primaryClient, - synergy::Screen* screen, - IEventQueue* events, - lib::synergy::ServerArgs const& args) : - m_mock(false), - m_primaryClient(primaryClient), - m_active(primaryClient), - m_seqNum(0), - m_xDelta(0), - m_yDelta(0), - m_xDelta2(0), - m_yDelta2(0), - m_config(&config), - m_inputFilter(config.getInputFilter()), - m_activeSaver(NULL), - m_switchDir(kNoDirection), - m_switchScreen(NULL), - m_switchWaitDelay(0.0), - m_switchWaitTimer(NULL), - m_switchTwoTapDelay(0.0), - m_switchTwoTapEngaged(false), - m_switchTwoTapArmed(false), - m_switchTwoTapZone(3), - m_switchNeedsShift(false), - m_switchNeedsControl(false), - m_switchNeedsAlt(false), - m_relativeMoves(false), - m_keyboardBroadcasting(false), - m_lockedToScreen(false), - m_screen(screen), - m_events(events), - m_sendFileThread(nullptr), - m_writeToDropDirThread(nullptr), - m_ignoreFileTransfer(false), - m_disableLockToScreen(false), - m_enableClipboard(true), - m_maximumClipboardSize(INT_MAX), - m_sendDragInfoThread(nullptr), - m_waitDragInfoThread(true), - m_args(args) -{ - // must have a primary client and it must have a canonical name - assert(m_primaryClient != NULL); - assert(config.isScreen(primaryClient->getName())); - assert(m_screen != NULL); +Server::Server(Config &config, PrimaryClient *primaryClient, + synergy::Screen *screen, IEventQueue *events, + lib::synergy::ServerArgs const &args) + : m_mock(false), m_primaryClient(primaryClient), m_active(primaryClient), + m_seqNum(0), m_xDelta(0), m_yDelta(0), m_xDelta2(0), m_yDelta2(0), + m_config(&config), m_inputFilter(config.getInputFilter()), + m_activeSaver(NULL), m_switchDir(kNoDirection), m_switchScreen(NULL), + m_switchWaitDelay(0.0), m_switchWaitTimer(NULL), m_switchTwoTapDelay(0.0), + m_switchTwoTapEngaged(false), m_switchTwoTapArmed(false), + m_switchTwoTapZone(3), m_switchNeedsShift(false), + m_switchNeedsControl(false), m_switchNeedsAlt(false), + m_relativeMoves(false), m_keyboardBroadcasting(false), + m_lockedToScreen(false), m_screen(screen), m_events(events), + m_sendFileThread(nullptr), m_writeToDropDirThread(nullptr), + m_ignoreFileTransfer(false), m_disableLockToScreen(false), + m_enableClipboard(true), m_maximumClipboardSize(INT_MAX), + m_sendDragInfoThread(nullptr), m_waitDragInfoThread(true), m_args(args) { + // must have a primary client and it must have a canonical name + assert(m_primaryClient != NULL); + assert(config.isScreen(primaryClient->getName())); + assert(m_screen != NULL); - String primaryName = getName(primaryClient); + String primaryName = getName(primaryClient); - // clear clipboards - for (ClipboardID id = 0; id < kClipboardEnd; ++id) { - ClipboardInfo& clipboard = m_clipboards[id]; - clipboard.m_clipboardOwner = primaryName; - clipboard.m_clipboardSeqNum = m_seqNum; - if (clipboard.m_clipboard.open(0)) { - clipboard.m_clipboard.empty(); - clipboard.m_clipboard.close(); - } - clipboard.m_clipboardData = clipboard.m_clipboard.marshall(); - } + // clear clipboards + for (ClipboardID id = 0; id < kClipboardEnd; ++id) { + ClipboardInfo &clipboard = m_clipboards[id]; + clipboard.m_clipboardOwner = primaryName; + clipboard.m_clipboardSeqNum = m_seqNum; + if (clipboard.m_clipboard.open(0)) { + clipboard.m_clipboard.empty(); + clipboard.m_clipboard.close(); + } + clipboard.m_clipboardData = clipboard.m_clipboard.marshall(); + } - // install event handlers - m_events->adoptHandler(Event::kTimer, this, - new TMethodEventJob(this, - &Server::handleSwitchWaitTimeout)); - m_events->adoptHandler(m_events->forIKeyState().keyDown(), - m_inputFilter, - new TMethodEventJob(this, - &Server::handleKeyDownEvent)); - m_events->adoptHandler(m_events->forIKeyState().keyUp(), - m_inputFilter, - new TMethodEventJob(this, - &Server::handleKeyUpEvent)); - m_events->adoptHandler(m_events->forIKeyState().keyRepeat(), - m_inputFilter, - new TMethodEventJob(this, - &Server::handleKeyRepeatEvent)); - m_events->adoptHandler(m_events->forIPrimaryScreen().buttonDown(), - m_inputFilter, - new TMethodEventJob(this, - &Server::handleButtonDownEvent)); - m_events->adoptHandler(m_events->forIPrimaryScreen().buttonUp(), - m_inputFilter, - new TMethodEventJob(this, - &Server::handleButtonUpEvent)); - m_events->adoptHandler(m_events->forIPrimaryScreen().motionOnPrimary(), - m_primaryClient->getEventTarget(), - new TMethodEventJob(this, - &Server::handleMotionPrimaryEvent)); - m_events->adoptHandler(m_events->forIPrimaryScreen().motionOnSecondary(), - m_primaryClient->getEventTarget(), - new TMethodEventJob(this, - &Server::handleMotionSecondaryEvent)); - m_events->adoptHandler(m_events->forIPrimaryScreen().wheel(), - m_primaryClient->getEventTarget(), - new TMethodEventJob(this, - &Server::handleWheelEvent)); - m_events->adoptHandler(m_events->forIPrimaryScreen().screensaverActivated(), - m_primaryClient->getEventTarget(), - new TMethodEventJob(this, - &Server::handleScreensaverActivatedEvent)); - m_events->adoptHandler(m_events->forIPrimaryScreen().screensaverDeactivated(), - m_primaryClient->getEventTarget(), - new TMethodEventJob(this, - &Server::handleScreensaverDeactivatedEvent)); - m_events->adoptHandler(m_events->forServer().switchToScreen(), - m_inputFilter, - new TMethodEventJob(this, - &Server::handleSwitchToScreenEvent)); - m_events->adoptHandler(m_events->forServer().switchInDirection(), - m_inputFilter, - new TMethodEventJob(this, - &Server::handleSwitchInDirectionEvent)); - m_events->adoptHandler(m_events->forServer().keyboardBroadcast(), - m_inputFilter, - new TMethodEventJob(this, - &Server::handleKeyboardBroadcastEvent)); - m_events->adoptHandler(m_events->forServer().lockCursorToScreen(), - m_inputFilter, - new TMethodEventJob(this, - &Server::handleLockCursorToScreenEvent)); - m_events->adoptHandler(m_events->forIPrimaryScreen().fakeInputBegin(), - m_inputFilter, - new TMethodEventJob(this, - &Server::handleFakeInputBeginEvent)); - m_events->adoptHandler(m_events->forIPrimaryScreen().fakeInputEnd(), - m_inputFilter, - new TMethodEventJob(this, - &Server::handleFakeInputEndEvent)); + // install event handlers + m_events->adoptHandler( + Event::kTimer, this, + new TMethodEventJob(this, &Server::handleSwitchWaitTimeout)); + m_events->adoptHandler( + m_events->forIKeyState().keyDown(), m_inputFilter, + new TMethodEventJob(this, &Server::handleKeyDownEvent)); + m_events->adoptHandler( + m_events->forIKeyState().keyUp(), m_inputFilter, + new TMethodEventJob(this, &Server::handleKeyUpEvent)); + m_events->adoptHandler( + m_events->forIKeyState().keyRepeat(), m_inputFilter, + new TMethodEventJob(this, &Server::handleKeyRepeatEvent)); + m_events->adoptHandler( + m_events->forIPrimaryScreen().buttonDown(), m_inputFilter, + new TMethodEventJob(this, &Server::handleButtonDownEvent)); + m_events->adoptHandler( + m_events->forIPrimaryScreen().buttonUp(), m_inputFilter, + new TMethodEventJob(this, &Server::handleButtonUpEvent)); + m_events->adoptHandler( + m_events->forIPrimaryScreen().motionOnPrimary(), + m_primaryClient->getEventTarget(), + new TMethodEventJob(this, &Server::handleMotionPrimaryEvent)); + m_events->adoptHandler( + m_events->forIPrimaryScreen().motionOnSecondary(), + m_primaryClient->getEventTarget(), + new TMethodEventJob(this, &Server::handleMotionSecondaryEvent)); + m_events->adoptHandler( + m_events->forIPrimaryScreen().wheel(), m_primaryClient->getEventTarget(), + new TMethodEventJob(this, &Server::handleWheelEvent)); + m_events->adoptHandler(m_events->forIPrimaryScreen().screensaverActivated(), + m_primaryClient->getEventTarget(), + new TMethodEventJob( + this, &Server::handleScreensaverActivatedEvent)); + m_events->adoptHandler(m_events->forIPrimaryScreen().screensaverDeactivated(), + m_primaryClient->getEventTarget(), + new TMethodEventJob( + this, &Server::handleScreensaverDeactivatedEvent)); + m_events->adoptHandler( + m_events->forServer().switchToScreen(), m_inputFilter, + new TMethodEventJob(this, &Server::handleSwitchToScreenEvent)); + m_events->adoptHandler( + m_events->forServer().switchInDirection(), m_inputFilter, + new TMethodEventJob(this, &Server::handleSwitchInDirectionEvent)); + m_events->adoptHandler( + m_events->forServer().keyboardBroadcast(), m_inputFilter, + new TMethodEventJob(this, &Server::handleKeyboardBroadcastEvent)); + m_events->adoptHandler(m_events->forServer().lockCursorToScreen(), + m_inputFilter, + new TMethodEventJob( + this, &Server::handleLockCursorToScreenEvent)); + m_events->adoptHandler( + m_events->forIPrimaryScreen().fakeInputBegin(), m_inputFilter, + new TMethodEventJob(this, &Server::handleFakeInputBeginEvent)); + m_events->adoptHandler( + m_events->forIPrimaryScreen().fakeInputEnd(), m_inputFilter, + new TMethodEventJob(this, &Server::handleFakeInputEndEvent)); - if (m_args.m_enableDragDrop) { - m_events->adoptHandler(m_events->forFile().fileChunkSending(), - this, - new TMethodEventJob(this, - &Server::handleFileChunkSendingEvent)); - m_events->adoptHandler(m_events->forFile().fileRecieveCompleted(), - this, - new TMethodEventJob(this, - &Server::handleFileRecieveCompletedEvent)); - } + if (m_args.m_enableDragDrop) { + m_events->adoptHandler(m_events->forFile().fileChunkSending(), this, + new TMethodEventJob( + this, &Server::handleFileChunkSendingEvent)); + m_events->adoptHandler(m_events->forFile().fileRecieveCompleted(), this, + new TMethodEventJob( + this, &Server::handleFileRecieveCompletedEvent)); + } - // add connection - addClient(m_primaryClient); + // add connection + addClient(m_primaryClient); - // set initial configuration - setConfig(config); + // set initial configuration + setConfig(config); - // enable primary client - m_primaryClient->enable(); - m_inputFilter->setPrimaryClient(m_primaryClient); - - // Determine if scroll lock is already set. If so, lock the cursor to the primary screen - if (m_primaryClient->getToggleMask() & KeyModifierScrollLock) { - LOG((CLOG_NOTE "scroll lock is on, locking cursor to screen")); - m_lockedToScreen = true; - } + // enable primary client + m_primaryClient->enable(); + m_inputFilter->setPrimaryClient(m_primaryClient); + // Determine if scroll lock is already set. If so, lock the cursor to the + // primary screen + if (m_primaryClient->getToggleMask() & KeyModifierScrollLock) { + LOG((CLOG_NOTE "scroll lock is on, locking cursor to screen")); + m_lockedToScreen = true; + } } -Server::~Server() -{ - if (m_mock) { - return; - } +Server::~Server() { + if (m_mock) { + return; + } - // remove event handlers and timers - m_events->removeHandler(m_events->forIKeyState().keyDown(), - m_inputFilter); - m_events->removeHandler(m_events->forIKeyState().keyUp(), - m_inputFilter); - m_events->removeHandler(m_events->forIKeyState().keyRepeat(), - m_inputFilter); - m_events->removeHandler(m_events->forIPrimaryScreen().buttonDown(), - m_inputFilter); - m_events->removeHandler(m_events->forIPrimaryScreen().buttonUp(), - m_inputFilter); - m_events->removeHandler(m_events->forIPrimaryScreen().motionOnPrimary(), - m_primaryClient->getEventTarget()); - m_events->removeHandler(m_events->forIPrimaryScreen().motionOnSecondary(), - m_primaryClient->getEventTarget()); - m_events->removeHandler(m_events->forIPrimaryScreen().wheel(), - m_primaryClient->getEventTarget()); - m_events->removeHandler(m_events->forIPrimaryScreen().screensaverActivated(), - m_primaryClient->getEventTarget()); - m_events->removeHandler(m_events->forIPrimaryScreen().screensaverDeactivated(), - m_primaryClient->getEventTarget()); - m_events->removeHandler(m_events->forIPrimaryScreen().fakeInputBegin(), - m_inputFilter); - m_events->removeHandler(m_events->forIPrimaryScreen().fakeInputEnd(), - m_inputFilter); - m_events->removeHandler(Event::kTimer, this); - stopSwitch(); + // remove event handlers and timers + m_events->removeHandler(m_events->forIKeyState().keyDown(), m_inputFilter); + m_events->removeHandler(m_events->forIKeyState().keyUp(), m_inputFilter); + m_events->removeHandler(m_events->forIKeyState().keyRepeat(), m_inputFilter); + m_events->removeHandler(m_events->forIPrimaryScreen().buttonDown(), + m_inputFilter); + m_events->removeHandler(m_events->forIPrimaryScreen().buttonUp(), + m_inputFilter); + m_events->removeHandler(m_events->forIPrimaryScreen().motionOnPrimary(), + m_primaryClient->getEventTarget()); + m_events->removeHandler(m_events->forIPrimaryScreen().motionOnSecondary(), + m_primaryClient->getEventTarget()); + m_events->removeHandler(m_events->forIPrimaryScreen().wheel(), + m_primaryClient->getEventTarget()); + m_events->removeHandler(m_events->forIPrimaryScreen().screensaverActivated(), + m_primaryClient->getEventTarget()); + m_events->removeHandler( + m_events->forIPrimaryScreen().screensaverDeactivated(), + m_primaryClient->getEventTarget()); + m_events->removeHandler(m_events->forIPrimaryScreen().fakeInputBegin(), + m_inputFilter); + m_events->removeHandler(m_events->forIPrimaryScreen().fakeInputEnd(), + m_inputFilter); + m_events->removeHandler(Event::kTimer, this); + stopSwitch(); - // force immediate disconnection of secondary clients - disconnect(); - for (OldClients::iterator index = m_oldClients.begin(); - index != m_oldClients.end(); ++index) { - BaseClientProxy* client = index->first; - m_events->deleteTimer(index->second); - m_events->removeHandler(Event::kTimer, client); - m_events->removeHandler(m_events->forClientProxy().disconnected(), client); - delete client; - } + // force immediate disconnection of secondary clients + disconnect(); + for (OldClients::iterator index = m_oldClients.begin(); + index != m_oldClients.end(); ++index) { + BaseClientProxy *client = index->first; + m_events->deleteTimer(index->second); + m_events->removeHandler(Event::kTimer, client); + m_events->removeHandler(m_events->forClientProxy().disconnected(), client); + delete client; + } - // remove input filter - m_inputFilter->setPrimaryClient(NULL); + // remove input filter + m_inputFilter->setPrimaryClient(NULL); - // disable and disconnect primary client - m_primaryClient->disable(); - removeClient(m_primaryClient); + // disable and disconnect primary client + m_primaryClient->disable(); + removeClient(m_primaryClient); } -bool -Server::setConfig(const Config& config) -{ - // refuse configuration if it doesn't include the primary screen - if (!config.isScreen(m_primaryClient->getName())) { - return false; - } +bool Server::setConfig(const Config &config) { + // refuse configuration if it doesn't include the primary screen + if (!config.isScreen(m_primaryClient->getName())) { + return false; + } - // close clients that are connected but being dropped from the - // configuration. - closeClients(config); + // close clients that are connected but being dropped from the + // configuration. + closeClients(config); - // cut over - processOptions(); + // cut over + processOptions(); - // add ScrollLock as a hotkey to lock to the screen. this was a - // built-in feature in earlier releases and is now supported via - // the user configurable hotkey mechanism. if the user has already - // registered ScrollLock for something else then that will win but - // we will unfortunately generate a warning. if the user has - // configured a LockCursorToScreenAction then we don't add - // ScrollLock as a hotkey. - if (!m_disableLockToScreen && !m_config->hasLockToScreenAction()) { - IPlatformScreen::KeyInfo* key = - IPlatformScreen::KeyInfo::alloc(kKeyScrollLock, 0, 0, 0); - InputFilter::Rule rule(new InputFilter::KeystrokeCondition(m_events, key)); - rule.adoptAction(new InputFilter::LockCursorToScreenAction(m_events), true); - m_inputFilter->addFilterRule(rule); - } + // add ScrollLock as a hotkey to lock to the screen. this was a + // built-in feature in earlier releases and is now supported via + // the user configurable hotkey mechanism. if the user has already + // registered ScrollLock for something else then that will win but + // we will unfortunately generate a warning. if the user has + // configured a LockCursorToScreenAction then we don't add + // ScrollLock as a hotkey. + if (!m_disableLockToScreen && !m_config->hasLockToScreenAction()) { + IPlatformScreen::KeyInfo *key = + IPlatformScreen::KeyInfo::alloc(kKeyScrollLock, 0, 0, 0); + InputFilter::Rule rule(new InputFilter::KeystrokeCondition(m_events, key)); + rule.adoptAction(new InputFilter::LockCursorToScreenAction(m_events), true); + m_inputFilter->addFilterRule(rule); + } - // tell primary screen about reconfiguration - m_primaryClient->reconfigure(getActivePrimarySides()); + // tell primary screen about reconfiguration + m_primaryClient->reconfigure(getActivePrimarySides()); - // tell all (connected) clients about current options - for (ClientList::const_iterator index = m_clients.begin(); - index != m_clients.end(); ++index) { - BaseClientProxy* client = index->second; - sendOptions(client); - } + // tell all (connected) clients about current options + for (ClientList::const_iterator index = m_clients.begin(); + index != m_clients.end(); ++index) { + BaseClientProxy *client = index->second; + sendOptions(client); + } - return true; + return true; } -void -Server::adoptClient(BaseClientProxy* client) -{ - assert(client != NULL); +void Server::adoptClient(BaseClientProxy *client) { + assert(client != NULL); - // watch for client disconnection - m_events->adoptHandler(m_events->forClientProxy().disconnected(), client, - new TMethodEventJob(this, - &Server::handleClientDisconnected, client)); + // watch for client disconnection + m_events->adoptHandler(m_events->forClientProxy().disconnected(), client, + new TMethodEventJob( + this, &Server::handleClientDisconnected, client)); - // name must be in our configuration - if (!m_config->isScreen(client->getName())) { - LOG((CLOG_WARN "unrecognised client name \"%s\", check server config", client->getName().c_str())); - closeClient(client, kMsgEUnknown); - return; - } + // name must be in our configuration + if (!m_config->isScreen(client->getName())) { + LOG((CLOG_WARN "unrecognised client name \"%s\", check server config", + client->getName().c_str())); + closeClient(client, kMsgEUnknown); + return; + } - // add client to client list - if (!addClient(client)) { - // can only have one screen with a given name at any given time - LOG((CLOG_WARN "a client with name \"%s\" is already connected", getName(client).c_str())); - closeClient(client, kMsgEBusy); - return; - } - LOG((CLOG_NOTE "client \"%s\" has connected", getName(client).c_str())); + // add client to client list + if (!addClient(client)) { + // can only have one screen with a given name at any given time + LOG((CLOG_WARN "a client with name \"%s\" is already connected", + getName(client).c_str())); + closeClient(client, kMsgEBusy); + return; + } + LOG((CLOG_NOTE "client \"%s\" has connected", getName(client).c_str())); - // send configuration options to client - sendOptions(client); + // send configuration options to client + sendOptions(client); - // activate screen saver on new client if active on the primary screen - if (m_activeSaver != NULL) { - client->screensaver(true); - } + // activate screen saver on new client if active on the primary screen + if (m_activeSaver != NULL) { + client->screensaver(true); + } - // send notification - Server::ScreenConnectedInfo* info = - new Server::ScreenConnectedInfo(getName(client)); - m_events->addEvent(Event(m_events->forServer().connected(), - m_primaryClient->getEventTarget(), info)); + // send notification + Server::ScreenConnectedInfo *info = + new Server::ScreenConnectedInfo(getName(client)); + m_events->addEvent(Event(m_events->forServer().connected(), + m_primaryClient->getEventTarget(), info)); } -void -Server::disconnect() -{ - // close all secondary clients - if (m_clients.size() > 1 || !m_oldClients.empty()) { - Config emptyConfig(m_events); - closeClients(emptyConfig); - } - else { - m_events->addEvent(Event(m_events->forServer().disconnected(), this)); - } +void Server::disconnect() { + // close all secondary clients + if (m_clients.size() > 1 || !m_oldClients.empty()) { + Config emptyConfig(m_events); + closeClients(emptyConfig); + } else { + m_events->addEvent(Event(m_events->forServer().disconnected(), this)); + } } -UInt32 -Server::getNumClients() const -{ - return (SInt32)m_clients.size(); +UInt32 Server::getNumClients() const { return (SInt32)m_clients.size(); } + +void Server::getClients(std::vector &list) const { + list.clear(); + for (ClientList::const_iterator index = m_clients.begin(); + index != m_clients.end(); ++index) { + list.push_back(index->first); + } } -void -Server::getClients(std::vector& list) const -{ - list.clear(); - for (ClientList::const_iterator index = m_clients.begin(); - index != m_clients.end(); ++index) { - list.push_back(index->first); - } +String Server::getName(const BaseClientProxy *client) const { + String name = m_config->getCanonicalName(client->getName()); + if (name.empty()) { + name = client->getName(); + } + return name; } -String -Server::getName(const BaseClientProxy* client) const -{ - String name = m_config->getCanonicalName(client->getName()); - if (name.empty()) { - name = client->getName(); - } - return name; +UInt32 Server::getActivePrimarySides() const { + UInt32 sides = 0; + if (!isLockedToScreenServer()) { + if (hasAnyNeighbor(m_primaryClient, kLeft)) { + sides |= kLeftMask; + } + if (hasAnyNeighbor(m_primaryClient, kRight)) { + sides |= kRightMask; + } + if (hasAnyNeighbor(m_primaryClient, kTop)) { + sides |= kTopMask; + } + if (hasAnyNeighbor(m_primaryClient, kBottom)) { + sides |= kBottomMask; + } + } + return sides; } -UInt32 -Server::getActivePrimarySides() const -{ - UInt32 sides = 0; - if (!isLockedToScreenServer()) { - if (hasAnyNeighbor(m_primaryClient, kLeft)) { - sides |= kLeftMask; - } - if (hasAnyNeighbor(m_primaryClient, kRight)) { - sides |= kRightMask; - } - if (hasAnyNeighbor(m_primaryClient, kTop)) { - sides |= kTopMask; - } - if (hasAnyNeighbor(m_primaryClient, kBottom)) { - sides |= kBottomMask; - } - } - return sides; +bool Server::isLockedToScreenServer() const { + // locked if scroll-lock is toggled on + return m_lockedToScreen; } -bool -Server::isLockedToScreenServer() const -{ - // locked if scroll-lock is toggled on - return m_lockedToScreen; +bool Server::isLockedToScreen() const { + if (m_disableLockToScreen) { + return false; + } + + // locked if we say we're locked + if (isLockedToScreenServer()) { + LOG((CLOG_NOTE "cursor is locked to screen, check scroll lock key")); + return true; + } + + // locked if primary says we're locked + if (m_primaryClient->isLockedToScreen()) { + return true; + } + + // not locked + return false; } -bool -Server::isLockedToScreen() const -{ - if (m_disableLockToScreen) { - return false; - } - - // locked if we say we're locked - if (isLockedToScreenServer()) { - LOG((CLOG_NOTE "cursor is locked to screen, check scroll lock key")); - return true; - } - - // locked if primary says we're locked - if (m_primaryClient->isLockedToScreen()) { - return true; - } - - // not locked - return false; +SInt32 Server::getJumpZoneSize(BaseClientProxy *client) const { + if (client == m_primaryClient) { + return m_primaryClient->getJumpZoneSize(); + } else { + return 0; + } } -SInt32 -Server::getJumpZoneSize(BaseClientProxy* client) const -{ - if (client == m_primaryClient) { - return m_primaryClient->getJumpZoneSize(); - } - else { - return 0; - } -} +void Server::switchScreen(BaseClientProxy *dst, SInt32 x, SInt32 y, + bool forScreensaver) { + assert(dst != NULL); -void -Server::switchScreen(BaseClientProxy* dst, - SInt32 x, SInt32 y, bool forScreensaver) -{ - assert(dst != NULL); - - // if trial is expired, exit the process - if (m_args.m_serial.isExpired(std::time(0))) { - LOG((CLOG_ERR "trial has expired, aborting server")); - exit(kExitSuccess); - } + // if trial is expired, exit the process + if (m_args.m_serial.isExpired(std::time(0))) { + LOG((CLOG_ERR "trial has expired, aborting server")); + exit(kExitSuccess); + } #ifndef NDEBUG - { - SInt32 dx, dy, dw, dh; - dst->getShape(dx, dy, dw, dh); - assert(x >= dx && y >= dy && x < dx + dw && y < dy + dh); - } + { + SInt32 dx, dy, dw, dh; + dst->getShape(dx, dy, dw, dh); + assert(x >= dx && y >= dy && x < dx + dw && y < dy + dh); + } #endif - assert(m_active != NULL); - - LOG((CLOG_INFO "switch from \"%s\" to \"%s\" at %d,%d", getName(m_active).c_str(), getName(dst).c_str(), x, y)); - - // stop waiting to switch - stopSwitch(); - - // record new position - m_x = x; - m_y = y; - m_xDelta = 0; - m_yDelta = 0; - m_xDelta2 = 0; - m_yDelta2 = 0; - - // wrapping means leaving the active screen and entering it again. - // since that's a waste of time we skip that and just warp the - // mouse. - if (m_active != dst) { - // leave active screen - if (!m_active->leave()) { - // cannot leave screen - LOG((CLOG_WARN "can't leave screen")); - return; - } - - // update the primary client's clipboards if we're leaving the - // primary screen. - if (m_active == m_primaryClient && m_enableClipboard) { - for (ClipboardID id = 0; id < kClipboardEnd; ++id) { - ClipboardInfo& clipboard = m_clipboards[id]; - if (clipboard.m_clipboardOwner == getName(m_primaryClient)) { - onClipboardChanged(m_primaryClient, - id, clipboard.m_clipboardSeqNum); - } - } - } - - -#if defined(__APPLE__) - if (dst != m_primaryClient) { - String secureInputApplication = m_primaryClient->getSecureInputApp(); - if (secureInputApplication != "") { - // display notification on the server - m_primaryClient->secureInputNotification(secureInputApplication); - //display notification on the client - dst->secureInputNotification(secureInputApplication); - } - } -#endif - - // cut over - m_active = dst; - - // increment enter sequence number - ++m_seqNum; - - // enter new screen - m_active->enter(x, y, m_seqNum, - m_primaryClient->getToggleMask(), - forScreensaver); - - if (m_enableClipboard) { - // send the clipboard data to new active screen - for (ClipboardID id = 0; id < kClipboardEnd; ++id) { - // Hackity hackity hack - if (m_clipboards[id].m_clipboard.marshall().size() > (m_maximumClipboardSize * 1024)) { - continue; - } - m_active->setClipboard(id, &m_clipboards[id].m_clipboard); - } - } - - Server::SwitchToScreenInfo* info = - Server::SwitchToScreenInfo::alloc(m_active->getName()); - m_events->addEvent(Event(m_events->forServer().screenSwitched(), this, info)); - } - else { - m_active->mouseMove(x, y); - } -} - -void -Server::jumpToScreen(BaseClientProxy* newScreen) -{ - assert(newScreen != NULL); - - // record the current cursor position on the active screen - m_active->setJumpCursorPos(m_x, m_y); - - // get the last cursor position on the target screen - SInt32 x, y; - newScreen->getJumpCursorPos(x, y); - - switchScreen(newScreen, x, y, false); -} - -float -Server::mapToFraction(BaseClientProxy* client, - EDirection dir, SInt32 x, SInt32 y) const -{ - SInt32 sx, sy, sw, sh; - client->getShape(sx, sy, sw, sh); - switch (dir) { - case kLeft: - case kRight: - return static_cast(y - sy + 0.5f) / static_cast(sh); - - case kTop: - case kBottom: - return static_cast(x - sx + 0.5f) / static_cast(sw); - - case kNoDirection: - assert(0 && "bad direction"); - break; - } - return 0.0f; -} - -void -Server::mapToPixel(BaseClientProxy* client, - EDirection dir, float f, SInt32& x, SInt32& y) const -{ - SInt32 sx, sy, sw, sh; - client->getShape(sx, sy, sw, sh); - switch (dir) { - case kLeft: - case kRight: - y = static_cast(f * sh) + sy; - break; - - case kTop: - case kBottom: - x = static_cast(f * sw) + sx; - break; - - case kNoDirection: - assert(0 && "bad direction"); - break; - } -} - -bool -Server::hasAnyNeighbor(BaseClientProxy* client, EDirection dir) const -{ - assert(client != NULL); - - return m_config->hasNeighbor(getName(client), dir); -} - -BaseClientProxy* -Server::getNeighbor(BaseClientProxy* src, - EDirection dir, SInt32& x, SInt32& y) const -{ - // note -- must be locked on entry - - assert(src != NULL); - - // get source screen name - String srcName = getName(src); - assert(!srcName.empty()); - LOG((CLOG_DEBUG2 "find neighbor on %s of \"%s\"", Config::dirName(dir), srcName.c_str())); - - // convert position to fraction - float t = mapToFraction(src, dir, x, y); - - // search for the closest neighbor that exists in direction dir - float tTmp; - for (;;) { - String dstName(m_config->getNeighbor(srcName, dir, t, &tTmp)); - - // if nothing in that direction then return NULL. if the - // destination is the source then we can make no more - // progress in this direction. since we haven't found a - // connected neighbor we return NULL. - if (dstName.empty()) { - LOG((CLOG_DEBUG2 "no neighbor on %s of \"%s\"", Config::dirName(dir), srcName.c_str())); - return NULL; - } - - // look up neighbor cell. if the screen is connected and - // ready then we can stop. - ClientList::const_iterator index = m_clients.find(dstName); - if (index != m_clients.end()) { - LOG((CLOG_DEBUG2 "\"%s\" is on %s of \"%s\" at %f", dstName.c_str(), Config::dirName(dir), srcName.c_str(), t)); - mapToPixel(index->second, dir, tTmp, x, y); - return index->second; - } - - // skip over unconnected screen - LOG((CLOG_DEBUG2 "ignored \"%s\" on %s of \"%s\"", dstName.c_str(), Config::dirName(dir), srcName.c_str())); - srcName = dstName; - - // use position on skipped screen - t = tTmp; - } -} - -BaseClientProxy* -Server::mapToNeighbor(BaseClientProxy* src, - EDirection srcSide, SInt32& x, SInt32& y) const -{ - // note -- must be locked on entry - - assert(src != NULL); - - // get the first neighbor - BaseClientProxy* dst = getNeighbor(src, srcSide, x, y); - if (dst == NULL) { - return NULL; - } - - // get the source screen's size - SInt32 dx, dy, dw, dh; - BaseClientProxy* lastGoodScreen = src; - lastGoodScreen->getShape(dx, dy, dw, dh); - - // find destination screen, adjusting x or y (but not both). the - // searches are done in a sort of canonical screen space where - // the upper-left corner is 0,0 for each screen. we adjust from - // actual to canonical position on entry to and from canonical to - // actual on exit from the search. - switch (srcSide) { - case kLeft: - x -= dx; - while (dst != NULL) { - lastGoodScreen = dst; - lastGoodScreen->getShape(dx, dy, dw, dh); - x += dw; - if (x >= 0) { - break; - } - LOG((CLOG_DEBUG2 "skipping over screen %s", getName(dst).c_str())); - dst = getNeighbor(lastGoodScreen, srcSide, x, y); - } - assert(lastGoodScreen != NULL); - x += dx; - break; - - case kRight: - x -= dx; - while (dst != NULL) { - x -= dw; - lastGoodScreen = dst; - lastGoodScreen->getShape(dx, dy, dw, dh); - if (x < dw) { - break; - } - LOG((CLOG_DEBUG2 "skipping over screen %s", getName(dst).c_str())); - dst = getNeighbor(lastGoodScreen, srcSide, x, y); - } - assert(lastGoodScreen != NULL); - x += dx; - break; - - case kTop: - y -= dy; - while (dst != NULL) { - lastGoodScreen = dst; - lastGoodScreen->getShape(dx, dy, dw, dh); - y += dh; - if (y >= 0) { - break; - } - LOG((CLOG_DEBUG2 "skipping over screen %s", getName(dst).c_str())); - dst = getNeighbor(lastGoodScreen, srcSide, x, y); - } - assert(lastGoodScreen != NULL); - y += dy; - break; - - case kBottom: - y -= dy; - while (dst != NULL) { - y -= dh; - lastGoodScreen = dst; - lastGoodScreen->getShape(dx, dy, dw, dh); - if (y < dh) { - break; - } - LOG((CLOG_DEBUG2 "skipping over screen %s", getName(dst).c_str())); - dst = getNeighbor(lastGoodScreen, srcSide, x, y); - } - assert(lastGoodScreen != NULL); - y += dy; - break; - - case kNoDirection: - assert(0 && "bad direction"); - return NULL; - } - - // save destination screen - assert(lastGoodScreen != NULL); - dst = lastGoodScreen; - - // if entering primary screen then be sure to move in far enough - // to avoid the jump zone. if entering a side that doesn't have - // a neighbor (i.e. an asymmetrical side) then we don't need to - // move inwards because that side can't provoke a jump. - avoidJumpZone(dst, srcSide, x, y); - - return dst; -} - -void -Server::avoidJumpZone(BaseClientProxy* dst, - EDirection dir, SInt32& x, SInt32& y) const -{ - // we only need to avoid jump zones on the primary screen - if (dst != m_primaryClient) { - return; - } - - const String dstName(getName(dst)); - SInt32 dx, dy, dw, dh; - dst->getShape(dx, dy, dw, dh); - float t = mapToFraction(dst, dir, x, y); - SInt32 z = getJumpZoneSize(dst); - - // move in far enough to avoid the jump zone. if entering a side - // that doesn't have a neighbor (i.e. an asymmetrical side) then we - // don't need to move inwards because that side can't provoke a jump. - switch (dir) { - case kLeft: - if (!m_config->getNeighbor(dstName, kRight, t, NULL).empty() && - x > dx + dw - 1 - z) - x = dx + dw - 1 - z; - break; - - case kRight: - if (!m_config->getNeighbor(dstName, kLeft, t, NULL).empty() && - x < dx + z) - x = dx + z; - break; - - case kTop: - if (!m_config->getNeighbor(dstName, kBottom, t, NULL).empty() && - y > dy + dh - 1 - z) - y = dy + dh - 1 - z; - break; - - case kBottom: - if (!m_config->getNeighbor(dstName, kTop, t, NULL).empty() && - y < dy + z) - y = dy + z; - break; - - case kNoDirection: - assert(0 && "bad direction"); - } -} - -bool -Server::isSwitchOkay(BaseClientProxy* newScreen, - EDirection dir, SInt32 x, SInt32 y, - SInt32 xActive, SInt32 yActive) -{ - LOG((CLOG_DEBUG1 "try to leave \"%s\" on %s", getName(m_active).c_str(), Config::dirName(dir))); - - // is there a neighbor? - if (newScreen == NULL) { - // there's no neighbor. we don't want to switch and we don't - // want to try to switch later. - LOG((CLOG_DEBUG1 "no neighbor %s", Config::dirName(dir))); - stopSwitch(); - return false; - } - - // should we switch or not? - bool preventSwitch = false; - bool allowSwitch = false; - - // note if the switch direction has changed. save the new - // direction and screen if so. - bool isNewDirection = (dir != m_switchDir); - if (isNewDirection || m_switchScreen == NULL) { - m_switchDir = dir; - m_switchScreen = newScreen; - } - - // is this a double tap and do we care? - if (!allowSwitch && m_switchTwoTapDelay > 0.0) { - if (isNewDirection || - !isSwitchTwoTapStarted() || !shouldSwitchTwoTap()) { - // tapping a different or new edge or second tap not - // fast enough. prepare for second tap. - preventSwitch = true; - startSwitchTwoTap(); - } - else { - // got second tap - allowSwitch = true; - } - } - - // if waiting before a switch then prepare to switch later - if (!allowSwitch && m_switchWaitDelay > 0.0) { - if (isNewDirection || !isSwitchWaitStarted()) { - startSwitchWait(x, y); - } - preventSwitch = true; - } - - // are we in a locked corner? first check if screen has the option set - // and, if not, check the global options. - const Config::ScreenOptions* options = - m_config->getOptions(getName(m_active)); - if (options == NULL || options->count(kOptionScreenSwitchCorners) == 0) { - options = m_config->getOptions(""); - } - if (options != NULL && options->count(kOptionScreenSwitchCorners) > 0) { - // get corner mask and size - Config::ScreenOptions::const_iterator i = - options->find(kOptionScreenSwitchCorners); - UInt32 corners = static_cast(i->second); - i = options->find(kOptionScreenSwitchCornerSize); - SInt32 size = 0; - if (i != options->end()) { - size = i->second; - } - - // see if we're in a locked corner - if ((getCorner(m_active, xActive, yActive, size) & corners) != 0) { - // yep, no switching - LOG((CLOG_DEBUG1 "locked in corner")); - preventSwitch = true; - stopSwitch(); - } - } - - // ignore if mouse is locked to screen and don't try to switch later - if (!preventSwitch && isLockedToScreen()) { - LOG((CLOG_DEBUG1 "locked to screen")); - preventSwitch = true; - stopSwitch(); - } - - // check for optional needed modifiers - KeyModifierMask mods = this->m_primaryClient->getToggleMask(); - - if (!preventSwitch && ( - (this->m_switchNeedsShift && ((mods & KeyModifierShift) != KeyModifierShift)) || - (this->m_switchNeedsControl && ((mods & KeyModifierControl) != KeyModifierControl)) || - (this->m_switchNeedsAlt && ((mods & KeyModifierAlt) != KeyModifierAlt)) - )) { - LOG((CLOG_DEBUG1 "need modifiers to switch")); - preventSwitch = true; - stopSwitch(); - } - - return !preventSwitch; -} - -void -Server::noSwitch(SInt32 x, SInt32 y) -{ - armSwitchTwoTap(x, y); - stopSwitchWait(); -} - -void -Server::stopSwitch() -{ - if (m_switchScreen != NULL) { - m_switchScreen = NULL; - m_switchDir = kNoDirection; - stopSwitchTwoTap(); - stopSwitchWait(); - } -} - -void -Server::startSwitchTwoTap() -{ - m_switchTwoTapEngaged = true; - m_switchTwoTapArmed = false; - m_switchTwoTapTimer.reset(); - LOG((CLOG_DEBUG1 "waiting for second tap")); -} - -void -Server::armSwitchTwoTap(SInt32 x, SInt32 y) -{ - if (m_switchTwoTapEngaged) { - if (m_switchTwoTapTimer.getTime() > m_switchTwoTapDelay) { - // second tap took too long. disengage. - stopSwitchTwoTap(); - } - else if (!m_switchTwoTapArmed) { - // still time for a double tap. see if we left the tap - // zone and, if so, arm the two tap. - SInt32 ax, ay, aw, ah; - m_active->getShape(ax, ay, aw, ah); - SInt32 tapZone = m_primaryClient->getJumpZoneSize(); - if (tapZone < m_switchTwoTapZone) { - tapZone = m_switchTwoTapZone; - } - if (x >= ax + tapZone && x < ax + aw - tapZone && - y >= ay + tapZone && y < ay + ah - tapZone) { - // win32 can generate bogus mouse events that appear to - // move in the opposite direction that the mouse actually - // moved. try to ignore that crap here. - switch (m_switchDir) { - case kLeft: - m_switchTwoTapArmed = (m_xDelta > 0 && m_xDelta2 > 0); - break; - - case kRight: - m_switchTwoTapArmed = (m_xDelta < 0 && m_xDelta2 < 0); - break; - - case kTop: - m_switchTwoTapArmed = (m_yDelta > 0 && m_yDelta2 > 0); - break; - - case kBottom: - m_switchTwoTapArmed = (m_yDelta < 0 && m_yDelta2 < 0); - break; - - default: - break; - } - } - } - } -} - -void -Server::stopSwitchTwoTap() -{ - m_switchTwoTapEngaged = false; - m_switchTwoTapArmed = false; -} - -bool -Server::isSwitchTwoTapStarted() const -{ - return m_switchTwoTapEngaged; -} - -bool -Server::shouldSwitchTwoTap() const -{ - // this is the second tap if two-tap is armed and this tap - // came fast enough - return (m_switchTwoTapArmed && - m_switchTwoTapTimer.getTime() <= m_switchTwoTapDelay); -} - -void -Server::startSwitchWait(SInt32 x, SInt32 y) -{ - stopSwitchWait(); - m_switchWaitX = x; - m_switchWaitY = y; - m_switchWaitTimer = m_events->newOneShotTimer(m_switchWaitDelay, this); - LOG((CLOG_DEBUG1 "waiting to switch")); -} - -void -Server::stopSwitchWait() -{ - if (m_switchWaitTimer != NULL) { - m_events->deleteTimer(m_switchWaitTimer); - m_switchWaitTimer = NULL; - } -} - -bool -Server::isSwitchWaitStarted() const -{ - return (m_switchWaitTimer != NULL); -} - -UInt32 -Server::getCorner(BaseClientProxy* client, - SInt32 x, SInt32 y, SInt32 size) const -{ - assert(client != NULL); - - // get client screen shape - SInt32 ax, ay, aw, ah; - client->getShape(ax, ay, aw, ah); - - // check for x,y on the left or right - SInt32 xSide; - if (x <= ax) { - xSide = -1; - } - else if (x >= ax + aw - 1) { - xSide = 1; - } - else { - xSide = 0; - } - - // check for x,y on the top or bottom - SInt32 ySide; - if (y <= ay) { - ySide = -1; - } - else if (y >= ay + ah - 1) { - ySide = 1; - } - else { - ySide = 0; - } - - // if against the left or right then check if y is within size - if (xSide != 0) { - if (y < ay + size) { - return (xSide < 0) ? kTopLeftMask : kTopRightMask; - } - else if (y >= ay + ah - size) { - return (xSide < 0) ? kBottomLeftMask : kBottomRightMask; - } - } - - // if against the left or right then check if y is within size - if (ySide != 0) { - if (x < ax + size) { - return (ySide < 0) ? kTopLeftMask : kBottomLeftMask; - } - else if (x >= ax + aw - size) { - return (ySide < 0) ? kTopRightMask : kBottomRightMask; - } - } - - return kNoCornerMask; -} - -void -Server::stopRelativeMoves() -{ - if (m_relativeMoves && m_active != m_primaryClient) { - // warp to the center of the active client so we know where we are - SInt32 ax, ay, aw, ah; - m_active->getShape(ax, ay, aw, ah); - m_x = ax + (aw >> 1); - m_y = ay + (ah >> 1); - m_xDelta = 0; - m_yDelta = 0; - m_xDelta2 = 0; - m_yDelta2 = 0; - LOG((CLOG_DEBUG2 "synchronize move on %s by %d,%d", getName(m_active).c_str(), m_x, m_y)); - m_active->mouseMove(m_x, m_y); - } -} - -void -Server::sendOptions(BaseClientProxy* client) const -{ - OptionsList optionsList; - - // look up options for client - const Config::ScreenOptions* options = - m_config->getOptions(getName(client)); - if (options != NULL) { - // convert options to a more convenient form for sending - optionsList.reserve(2 * options->size()); - for (Config::ScreenOptions::const_iterator index = options->begin(); - index != options->end(); ++index) { - optionsList.push_back(index->first); - optionsList.push_back(static_cast(index->second)); - } - } - - // look up global options - options = m_config->getOptions(""); - if (options != NULL) { - // convert options to a more convenient form for sending - optionsList.reserve(optionsList.size() + 2 * options->size()); - for (Config::ScreenOptions::const_iterator index = options->begin(); - index != options->end(); ++index) { - optionsList.push_back(index->first); - optionsList.push_back(static_cast(index->second)); - } - } - - // send the options - client->resetOptions(); - client->setOptions(optionsList); -} - -void -Server::processOptions() -{ - const Config::ScreenOptions* options = m_config->getOptions(""); - if (options == NULL) { - return; - } - - m_switchNeedsShift = false; // it seems if i don't add these - m_switchNeedsControl = false; // lines, the 'reload config' option - m_switchNeedsAlt = false; // doesnt' work correct. - - bool newRelativeMoves = m_relativeMoves; - for (Config::ScreenOptions::const_iterator index = options->begin(); - index != options->end(); ++index) { - const OptionID id = index->first; - const OptionValue value = index->second; - if (id == kOptionScreenSwitchDelay) { - m_switchWaitDelay = 1.0e-3 * static_cast(value); - if (m_switchWaitDelay < 0.0) { - m_switchWaitDelay = 0.0; - } - stopSwitchWait(); - } - else if (id == kOptionScreenSwitchTwoTap) { - m_switchTwoTapDelay = 1.0e-3 * static_cast(value); - if (m_switchTwoTapDelay < 0.0) { - m_switchTwoTapDelay = 0.0; - } - stopSwitchTwoTap(); - } - else if (id == kOptionScreenSwitchNeedsControl) { - m_switchNeedsControl = (value != 0); - } - else if (id == kOptionScreenSwitchNeedsShift) { - m_switchNeedsShift = (value != 0); - } - else if (id == kOptionScreenSwitchNeedsAlt) { - m_switchNeedsAlt = (value != 0); - } - else if (id == kOptionRelativeMouseMoves) { - newRelativeMoves = (value != 0); - } - else if (id == kOptionDisableLockToScreen) { - m_disableLockToScreen = (value != 0); - } - else if (id == kOptionClipboardSharing) { - m_enableClipboard = value; - if (!m_enableClipboard) { - LOG((CLOG_NOTE "clipboard sharing is disabled")); - } - } - else if (id == kOptionClipboardSharingSize) { - if (value <= 0) { - m_maximumClipboardSize = 0; - LOG((CLOG_NOTE "clipboard sharing is disabled because the " - "maximum shared clipboard size is set to 0")); - } else { - m_maximumClipboardSize = static_cast(value); - } - } - } - if (m_relativeMoves && !newRelativeMoves) { - stopRelativeMoves(); - } - m_relativeMoves = newRelativeMoves; -} - -void -Server::handleShapeChanged(const Event&, void* vclient) -{ - // ignore events from unknown clients - BaseClientProxy* client = static_cast(vclient); - if (m_clientSet.count(client) == 0) { - return; - } - - LOG((CLOG_DEBUG "screen \"%s\" shape changed", getName(client).c_str())); - - // update jump coordinate - SInt32 x, y; - client->getCursorPos(x, y); - client->setJumpCursorPos(x, y); - - // update the mouse coordinates - if (client == m_active) { - m_x = x; - m_y = y; - } - - // handle resolution change to primary screen - if (client == m_primaryClient) { - if (client == m_active) { - onMouseMovePrimary(m_x, m_y); - } - else { - onMouseMoveSecondary(0, 0); - } - } -} - -void -Server::handleClipboardGrabbed(const Event& event, void* vclient) -{ - if (!m_enableClipboard || (m_maximumClipboardSize == 0)) { - return; - } - - // ignore events from unknown clients - BaseClientProxy* grabber = static_cast(vclient); - if (m_clientSet.count(grabber) == 0) { - return; - } - const IScreen::ClipboardInfo* info = - static_cast(event.getData()); - - // ignore grab if sequence number is old. always allow primary - // screen to grab. - ClipboardInfo& clipboard = m_clipboards[info->m_id]; - if (grabber != m_primaryClient && - info->m_sequenceNumber < clipboard.m_clipboardSeqNum) { - LOG((CLOG_INFO "ignored screen \"%s\" grab of clipboard %d", getName(grabber).c_str(), info->m_id)); - return; - } - - // mark screen as owning clipboard - LOG((CLOG_INFO "screen \"%s\" grabbed clipboard %d from \"%s\"", getName(grabber).c_str(), info->m_id, clipboard.m_clipboardOwner.c_str())); - clipboard.m_clipboardOwner = getName(grabber); - clipboard.m_clipboardSeqNum = info->m_sequenceNumber; - - // clear the clipboard data (since it's not known at this point) - if (clipboard.m_clipboard.open(0)) { - clipboard.m_clipboard.empty(); - clipboard.m_clipboard.close(); - } - clipboard.m_clipboardData = clipboard.m_clipboard.marshall(); - - // tell all other screens to take ownership of clipboard. tell the - // grabber that it's clipboard isn't dirty. - for (ClientList::iterator index = m_clients.begin(); - index != m_clients.end(); ++index) { - BaseClientProxy* client = index->second; - if (client == grabber) { - client->setClipboardDirty(info->m_id, false); - } - else { - client->grabClipboard(info->m_id); - } - } - - if (grabber == m_primaryClient && m_active != m_primaryClient) { - LOG((CLOG_INFO "clipboard grabbed, but we are already changed active screen. Resend clipboard data")); - for (ClipboardID id = 0; id < kClipboardEnd; ++id) { - onClipboardChanged(m_primaryClient, id, m_clipboards[id].m_clipboardSeqNum); - } + assert(m_active != NULL); + + LOG((CLOG_INFO "switch from \"%s\" to \"%s\" at %d,%d", + getName(m_active).c_str(), getName(dst).c_str(), x, y)); + + // stop waiting to switch + stopSwitch(); + + // record new position + m_x = x; + m_y = y; + m_xDelta = 0; + m_yDelta = 0; + m_xDelta2 = 0; + m_yDelta2 = 0; + + // wrapping means leaving the active screen and entering it again. + // since that's a waste of time we skip that and just warp the + // mouse. + if (m_active != dst) { + // leave active screen + if (!m_active->leave()) { + // cannot leave screen + LOG((CLOG_WARN "can't leave screen")); + return; } -} -void -Server::handleClipboardChanged(const Event& event, void* vclient) -{ - // ignore events from unknown clients - BaseClientProxy* sender = static_cast(vclient); - if (m_clientSet.count(sender) == 0) { - return; - } - const IScreen::ClipboardInfo* info = - static_cast(event.getData()); - onClipboardChanged(sender, info->m_id, info->m_sequenceNumber); -} - -void -Server::handleKeyDownEvent(const Event& event, void*) -{ - IPlatformScreen::KeyInfo* info = - static_cast(event.getData()); - auto lang = AppUtil::instance().getCurrentLanguageCode(); - onKeyDown(info->m_key, info->m_mask, info->m_button, lang, info->m_screens); -} - -void -Server::handleKeyUpEvent(const Event& event, void*) -{ - IPlatformScreen::KeyInfo* info = - static_cast(event.getData()); - onKeyUp(info->m_key, info->m_mask, info->m_button, info->m_screens); -} - -void -Server::handleKeyRepeatEvent(const Event& event, void*) -{ - IPlatformScreen::KeyInfo* info = - static_cast(event.getData()); - auto lang = AppUtil::instance().getCurrentLanguageCode(); - onKeyRepeat(info->m_key, info->m_mask, info->m_count, info->m_button, lang); -} - -void -Server::handleButtonDownEvent(const Event& event, void*) -{ - IPlatformScreen::ButtonInfo* info = - static_cast(event.getData()); - onMouseDown(info->m_button); -} - -void -Server::handleButtonUpEvent(const Event& event, void*) -{ - IPlatformScreen::ButtonInfo* info = - static_cast(event.getData()); - onMouseUp(info->m_button); -} - -void -Server::handleMotionPrimaryEvent(const Event& event, void*) -{ - IPlatformScreen::MotionInfo* info = - static_cast(event.getData()); - onMouseMovePrimary(info->m_x, info->m_y); -} - -void -Server::handleMotionSecondaryEvent(const Event& event, void*) -{ - IPlatformScreen::MotionInfo* info = - static_cast(event.getData()); - onMouseMoveSecondary(info->m_x, info->m_y); -} - -void -Server::handleWheelEvent(const Event& event, void*) -{ - IPlatformScreen::WheelInfo* info = - static_cast(event.getData()); - onMouseWheel(info->m_xDelta, info->m_yDelta); -} - -void -Server::handleScreensaverActivatedEvent(const Event&, void*) -{ - onScreensaver(true); -} - -void -Server::handleScreensaverDeactivatedEvent(const Event&, void*) -{ - onScreensaver(false); -} - -void -Server::handleSwitchWaitTimeout(const Event&, void*) -{ - // ignore if mouse is locked to screen - if (isLockedToScreen()) { - LOG((CLOG_DEBUG1 "locked to screen")); - stopSwitch(); - return; - } - - // switch screen - switchScreen(m_switchScreen, m_switchWaitX, m_switchWaitY, false); -} - -void -Server::handleClientDisconnected(const Event&, void* vclient) -{ - // client has disconnected. it might be an old client or an - // active client. we don't care so just handle it both ways. - BaseClientProxy* client = static_cast(vclient); - removeActiveClient(client); - removeOldClient(client); - - delete client; - m_clientListener->restart(); -} - -void -Server::handleClientCloseTimeout(const Event&, void* vclient) -{ - // client took too long to disconnect. just dump it. - BaseClientProxy* client = static_cast(vclient); - LOG((CLOG_NOTE "forced disconnection of client \"%s\"", getName(client).c_str())); - removeOldClient(client); - - delete client; -} - -void -Server::handleSwitchToScreenEvent(const Event& event, void*) -{ - SwitchToScreenInfo* info = - static_cast(event.getData()); - - ClientList::const_iterator index = m_clients.find(info->m_screen); - if (index == m_clients.end()) { - LOG((CLOG_DEBUG1 "screen \"%s\" not active", info->m_screen)); - } - else { - jumpToScreen(index->second); - } -} - -void -Server::handleSwitchInDirectionEvent(const Event& event, void*) -{ - SwitchInDirectionInfo* info = - static_cast(event.getData()); - - // jump to screen in chosen direction from center of this screen - SInt32 x = m_x, y = m_y; - BaseClientProxy* newScreen = - getNeighbor(m_active, info->m_direction, x, y); - if (newScreen == NULL) { - LOG((CLOG_DEBUG1 "no neighbor %s", Config::dirName(info->m_direction))); - } - else { - jumpToScreen(newScreen); - } -} - -void -Server::handleKeyboardBroadcastEvent(const Event& event, void*) -{ - KeyboardBroadcastInfo* info = (KeyboardBroadcastInfo*)event.getData(); - - // choose new state - bool newState; - switch (info->m_state) { - case KeyboardBroadcastInfo::kOff: - newState = false; - break; - - default: - case KeyboardBroadcastInfo::kOn: - newState = true; - break; - - case KeyboardBroadcastInfo::kToggle: - newState = !m_keyboardBroadcasting; - break; - } - - // enter new state - if (newState != m_keyboardBroadcasting || - info->m_screens != m_keyboardBroadcastingScreens) { - m_keyboardBroadcasting = newState; - m_keyboardBroadcastingScreens = info->m_screens; - LOG((CLOG_DEBUG "keyboard broadcasting %s: %s", m_keyboardBroadcasting ? "on" : "off", m_keyboardBroadcastingScreens.c_str())); - } -} - -void -Server::handleLockCursorToScreenEvent(const Event& event, void*) -{ - LockCursorToScreenInfo* info = (LockCursorToScreenInfo*)event.getData(); - - // choose new state - bool newState; - switch (info->m_state) { - case LockCursorToScreenInfo::kOff: - newState = false; - break; - - default: - case LockCursorToScreenInfo::kOn: - newState = true; - break; - - case LockCursorToScreenInfo::kToggle: - newState = !m_lockedToScreen; - break; - } - - // enter new state - if (newState != m_lockedToScreen) { - m_lockedToScreen = newState; - LOG((CLOG_NOTE "cursor %s current screen", m_lockedToScreen ? "locked to" : "unlocked from")); - - m_primaryClient->reconfigure(getActivePrimarySides()); - if (!isLockedToScreenServer()) { - stopRelativeMoves(); - } - } -} - -void -Server::handleFakeInputBeginEvent(const Event&, void*) -{ - m_primaryClient->fakeInputBegin(); -} - -void -Server::handleFakeInputEndEvent(const Event&, void*) -{ - m_primaryClient->fakeInputEnd(); -} - -void -Server::handleFileChunkSendingEvent(const Event& event, void*) -{ - onFileChunkSending(event.getDataObject()); -} - -void -Server::handleFileRecieveCompletedEvent(const Event& event, void*) -{ - onFileRecieveCompleted(); -} - -void -Server::onClipboardChanged(BaseClientProxy* sender, - ClipboardID id, UInt32 seqNum) -{ - ClipboardInfo& clipboard = m_clipboards[id]; - - // ignore update if sequence number is old - if (seqNum < clipboard.m_clipboardSeqNum) { - LOG((CLOG_INFO "ignored screen \"%s\" update of clipboard %d (missequenced)", getName(sender).c_str(), id)); - return; - } - - // should be the expected client - assert(sender == m_clients.find(clipboard.m_clipboardOwner)->second); - - // get data - sender->getClipboard(id, &clipboard.m_clipboard); - - String data = clipboard.m_clipboard.marshall(); - if (data.size() > m_maximumClipboardSize * 1024) { - LOG((CLOG_NOTE "not updating clipboard because it's over the size limit (%i KB) configured by the server", - m_maximumClipboardSize)); - return; - } - - // ignore if data hasn't changed - if (data == clipboard.m_clipboardData) { - LOG((CLOG_DEBUG "ignored screen \"%s\" update of clipboard %d (unchanged)", clipboard.m_clipboardOwner.c_str(), id)); - return; - } - - // got new data - LOG((CLOG_INFO "screen \"%s\" updated clipboard %d", clipboard.m_clipboardOwner.c_str(), id)); - clipboard.m_clipboardData = data; - - // tell all clients except the sender that the clipboard is dirty - for (ClientList::const_iterator index = m_clients.begin(); - index != m_clients.end(); ++index) { - BaseClientProxy* client = index->second; - client->setClipboardDirty(id, client != sender); - } - - // send the new clipboard to the active screen - m_active->setClipboard(id, &clipboard.m_clipboard); -} - -void -Server::onScreensaver(bool activated) -{ - LOG((CLOG_DEBUG "onScreenSaver %s", activated ? "activated" : "deactivated")); - - if (activated) { - // save current screen and position - m_activeSaver = m_active; - m_xSaver = m_x; - m_ySaver = m_y; - - // jump to primary screen - if (m_active != m_primaryClient) { - switchScreen(m_primaryClient, 0, 0, true); - } - } - else { - // jump back to previous screen and position. we must check - // that the position is still valid since the screen may have - // changed resolutions while the screen saver was running. - if (m_activeSaver != NULL && m_activeSaver != m_primaryClient) { - // check position - BaseClientProxy* screen = m_activeSaver; - SInt32 x, y, w, h; - screen->getShape(x, y, w, h); - SInt32 zoneSize = getJumpZoneSize(screen); - if (m_xSaver < x + zoneSize) { - m_xSaver = x + zoneSize; - } - else if (m_xSaver >= x + w - zoneSize) { - m_xSaver = x + w - zoneSize - 1; - } - if (m_ySaver < y + zoneSize) { - m_ySaver = y + zoneSize; - } - else if (m_ySaver >= y + h - zoneSize) { - m_ySaver = y + h - zoneSize - 1; - } - - // jump - switchScreen(screen, m_xSaver, m_ySaver, false); - } - - // reset state - m_activeSaver = NULL; - } - - // send message to all clients - for (ClientList::const_iterator index = m_clients.begin(); - index != m_clients.end(); ++index) { - BaseClientProxy* client = index->second; - client->screensaver(activated); - } -} - -void -Server::onKeyDown(KeyID id, KeyModifierMask mask, KeyButton button, const String& lang, - const char* screens) -{ - LOG((CLOG_DEBUG1 "onKeyDown id=%d mask=0x%04x button=0x%04x lang=%s", id, mask, button, lang.c_str())); - assert(m_active != NULL); - - // relay - if (!m_keyboardBroadcasting && IKeyState::KeyInfo::isDefault(screens)) { - m_active->keyDown(id, mask, button, lang); - } - else { - if (!screens && m_keyboardBroadcasting) { - screens = m_keyboardBroadcastingScreens.c_str(); - if (IKeyState::KeyInfo::isDefault(screens)) { - screens = "*"; - } - } - for (ClientList::const_iterator index = m_clients.begin(); - index != m_clients.end(); ++index) { - if (IKeyState::KeyInfo::contains(screens, index->first)) { - index->second->keyDown(id, mask, button, lang); - } - } - } -} - -void -Server::onKeyUp(KeyID id, KeyModifierMask mask, KeyButton button, - const char* screens) -{ - LOG((CLOG_DEBUG1 "onKeyUp id=%d mask=0x%04x button=0x%04x", id, mask, button)); - assert(m_active != NULL); - - // relay - if (!m_keyboardBroadcasting && IKeyState::KeyInfo::isDefault(screens)) { - m_active->keyUp(id, mask, button); - } - else { - if (!screens && m_keyboardBroadcasting) { - screens = m_keyboardBroadcastingScreens.c_str(); - if (IKeyState::KeyInfo::isDefault(screens)) { - screens = "*"; - } - } - for (ClientList::const_iterator index = m_clients.begin(); - index != m_clients.end(); ++index) { - if (IKeyState::KeyInfo::contains(screens, index->first)) { - index->second->keyUp(id, mask, button); - } - } - } -} - -void -Server::onKeyRepeat(KeyID id, KeyModifierMask mask, - SInt32 count, KeyButton button, const String& lang) -{ - LOG((CLOG_DEBUG1 "onKeyRepeat id=%d mask=0x%04x count=%d button=0x%04x lang=\"%s\"", id, mask, count, button, lang.c_str())); - assert(m_active != NULL); - - // relay - m_active->keyRepeat(id, mask, count, button, lang); -} - -void -Server::onMouseDown(ButtonID id) -{ - LOG((CLOG_DEBUG1 "onMouseDown id=%d", id)); - assert(m_active != NULL); - - // relay - m_active->mouseDown(id); - - // reset this variable back to default value true - m_waitDragInfoThread = true; -} - -void -Server::onMouseUp(ButtonID id) -{ - LOG((CLOG_DEBUG1 "onMouseUp id=%d", id)); - assert(m_active != NULL); - - // relay - m_active->mouseUp(id); - - if (m_ignoreFileTransfer) { - m_ignoreFileTransfer = false; - return; - } - - if (m_args.m_enableDragDrop) { - if (!m_screen->isOnScreen()) { - String& file = m_screen->getDraggingFilename(); - if (!file.empty()) { - sendFileToClient(file.c_str()); - } - } - - // always clear dragging filename - m_screen->clearDraggingFilename(); - } -} - -bool -Server::onMouseMovePrimary(SInt32 x, SInt32 y) -{ - LOG((CLOG_DEBUG4 "onMouseMovePrimary %d,%d", x, y)); - - // mouse move on primary (server's) screen - if (m_active != m_primaryClient) { - // stale event -- we're actually on a secondary screen - return false; - } - - // save last delta - m_xDelta2 = m_xDelta; - m_yDelta2 = m_yDelta; - - // save current delta - m_xDelta = x - m_x; - m_yDelta = y - m_y; - - // save position - m_x = x; - m_y = y; - - // get screen shape - SInt32 ax, ay, aw, ah; - m_active->getShape(ax, ay, aw, ah); - SInt32 zoneSize = getJumpZoneSize(m_active); - - // clamp position to screen - SInt32 xc = x, yc = y; - if (xc < ax + zoneSize) { - xc = ax; - } - else if (xc >= ax + aw - zoneSize) { - xc = ax + aw - 1; - } - if (yc < ay + zoneSize) { - yc = ay; - } - else if (yc >= ay + ah - zoneSize) { - yc = ay + ah - 1; - } - - // see if we should change screens - // when the cursor is in a corner, there may be a screen either - // horizontally or vertically. check both directions. - EDirection dirh = kNoDirection, dirv = kNoDirection; - SInt32 xh = x, yv = y; - if (x < ax + zoneSize) { - xh -= zoneSize; - dirh = kLeft; - } - else if (x >= ax + aw - zoneSize) { - xh += zoneSize; - dirh = kRight; - } - if (y < ay + zoneSize) { - yv -= zoneSize; - dirv = kTop; - } - else if (y >= ay + ah - zoneSize) { - yv += zoneSize; - dirv = kBottom; - } - if (dirh == kNoDirection && dirv == kNoDirection) { - // still on local screen - noSwitch(x, y); - return false; - } - - // check both horizontally and vertically - EDirection dirs[] = {dirh, dirv}; - SInt32 xs[] = {xh, x}, ys[] = {y, yv}; - for (int i = 0; i < 2; ++i) { - EDirection dir = dirs[i]; - if (dir == kNoDirection) { - continue; - } - x = xs[i], y = ys[i]; - - // get jump destination - BaseClientProxy* newScreen = mapToNeighbor(m_active, dir, x, y); - - // should we switch or not? - if (isSwitchOkay(newScreen, dir, x, y, xc, yc)) { - if (m_args.m_enableDragDrop - && m_screen->isDraggingStarted() - && m_active != newScreen - && m_waitDragInfoThread) { - if (!m_sendDragInfoThread) { - m_sendDragInfoThread.reset(new Thread( - new TMethodJob( - this, - &Server::sendDragInfoThread, newScreen))); - } - - return false; - } - - // switch screen - switchScreen(newScreen, x, y, false); - m_waitDragInfoThread = true; - return true; - } - } - - return false; -} - -void -Server::sendDragInfoThread(void* arg) -{ - BaseClientProxy* newScreen = static_cast(arg); - - m_dragFileList.clear(); - String& dragFileList = m_screen->getDraggingFilename(); - if (!dragFileList.empty()) { - DragInformation di; - di.setFilename(dragFileList); - m_dragFileList.push_back(di); - } + // update the primary client's clipboards if we're leaving the + // primary screen. + if (m_active == m_primaryClient && m_enableClipboard) { + for (ClipboardID id = 0; id < kClipboardEnd; ++id) { + ClipboardInfo &clipboard = m_clipboards[id]; + if (clipboard.m_clipboardOwner == getName(m_primaryClient)) { + onClipboardChanged(m_primaryClient, id, clipboard.m_clipboardSeqNum); + } + } + } #if defined(__APPLE__) - // on mac it seems that after faking a LMB up, system would signal back - // to synergy a mouse up event, which doesn't happen on windows. as a - // result, synergy would send dragging file to client twice. This variable - // is used to ignore the first file sending. - m_ignoreFileTransfer = true; + if (dst != m_primaryClient) { + String secureInputApplication = m_primaryClient->getSecureInputApp(); + if (secureInputApplication != "") { + // display notification on the server + m_primaryClient->secureInputNotification(secureInputApplication); + // display notification on the client + dst->secureInputNotification(secureInputApplication); + } + } #endif - // send drag file info to client if there is any - if (m_dragFileList.size() > 0) { - sendDragInfo(newScreen); - m_dragFileList.clear(); - } - m_waitDragInfoThread = false; - m_sendDragInfoThread.reset(nullptr); + // cut over + m_active = dst; + // increment enter sequence number + ++m_seqNum; + + // enter new screen + m_active->enter(x, y, m_seqNum, m_primaryClient->getToggleMask(), + forScreensaver); + + if (m_enableClipboard) { + // send the clipboard data to new active screen + for (ClipboardID id = 0; id < kClipboardEnd; ++id) { + // Hackity hackity hack + if (m_clipboards[id].m_clipboard.marshall().size() > + (m_maximumClipboardSize * 1024)) { + continue; + } + m_active->setClipboard(id, &m_clipboards[id].m_clipboard); + } + } + + Server::SwitchToScreenInfo *info = + Server::SwitchToScreenInfo::alloc(m_active->getName()); + m_events->addEvent( + Event(m_events->forServer().screenSwitched(), this, info)); + } else { + m_active->mouseMove(x, y); + } } -void -Server::sendDragInfo(BaseClientProxy* newScreen) -{ - String infoString; - UInt32 fileCount = DragInformation::setupDragInfo(m_dragFileList, infoString); +void Server::jumpToScreen(BaseClientProxy *newScreen) { + assert(newScreen != NULL); - if (fileCount > 0) { - LOG((CLOG_DEBUG2 "sending drag information to client")); - LOG((CLOG_DEBUG3 "dragging file list: %s", infoString.c_str())); - LOG((CLOG_DEBUG3 "dragging file list string size: %i", infoString.size())); - newScreen->sendDragInfo(fileCount, infoString.c_str(), infoString.size()); - } + // record the current cursor position on the active screen + m_active->setJumpCursorPos(m_x, m_y); + + // get the last cursor position on the target screen + SInt32 x, y; + newScreen->getJumpCursorPos(x, y); + + switchScreen(newScreen, x, y, false); } -void -Server::onMouseMoveSecondary(SInt32 dx, SInt32 dy) -{ - LOG((CLOG_DEBUG2 "onMouseMoveSecondary %+d,%+d", dx, dy)); +float Server::mapToFraction(BaseClientProxy *client, EDirection dir, SInt32 x, + SInt32 y) const { + SInt32 sx, sy, sw, sh; + client->getShape(sx, sy, sw, sh); + switch (dir) { + case kLeft: + case kRight: + return static_cast(y - sy + 0.5f) / static_cast(sh); - // mouse move on secondary (client's) screen - assert(m_active != NULL); - if (m_active == m_primaryClient) { - // stale event -- we're actually on the primary screen - return; - } + case kTop: + case kBottom: + return static_cast(x - sx + 0.5f) / static_cast(sw); - // if doing relative motion on secondary screens and we're locked - // to the screen (which activates relative moves) then send a - // relative mouse motion. when we're doing this we pretend as if - // the mouse isn't actually moving because we're expecting some - // program on the secondary screen to warp the mouse on us, so we - // have no idea where it really is. - if (m_relativeMoves && isLockedToScreenServer()) { - LOG((CLOG_DEBUG2 "relative move on %s by %d,%d", getName(m_active).c_str(), dx, dy)); - m_active->mouseRelativeMove(dx, dy); - return; - } - - // save old position - const SInt32 xOld = m_x; - const SInt32 yOld = m_y; - - // save last delta - m_xDelta2 = m_xDelta; - m_yDelta2 = m_yDelta; - - // save current delta - m_xDelta = dx; - m_yDelta = dy; - - // accumulate motion - m_x += dx; - m_y += dy; - - // get screen shape - SInt32 ax, ay, aw, ah; - m_active->getShape(ax, ay, aw, ah); - - // find direction of neighbor and get the neighbor - bool jump = true; - BaseClientProxy* newScreen; - do { - // clamp position to screen - SInt32 xc = m_x, yc = m_y; - if (xc < ax) { - xc = ax; - } - else if (xc >= ax + aw) { - xc = ax + aw - 1; - } - if (yc < ay) { - yc = ay; - } - else if (yc >= ay + ah) { - yc = ay + ah - 1; - } - - EDirection dir; - if (m_x < ax) { - dir = kLeft; - } - else if (m_x > ax + aw - 1) { - dir = kRight; - } - else if (m_y < ay) { - dir = kTop; - } - else if (m_y > ay + ah - 1) { - dir = kBottom; - } - else { - // we haven't left the screen - newScreen = m_active; - jump = false; - - // if waiting and mouse is not on the border we're waiting - // on then stop waiting. also if it's not on the border - // then arm the double tap. - if (m_switchScreen != NULL) { - bool clearWait; - SInt32 zoneSize = m_primaryClient->getJumpZoneSize(); - switch (m_switchDir) { - case kLeft: - clearWait = (m_x >= ax + zoneSize); - break; - - case kRight: - clearWait = (m_x <= ax + aw - 1 - zoneSize); - break; - - case kTop: - clearWait = (m_y >= ay + zoneSize); - break; - - case kBottom: - clearWait = (m_y <= ay + ah - 1 + zoneSize); - break; - - default: - clearWait = false; - break; - } - if (clearWait) { - // still on local screen - noSwitch(m_x, m_y); - } - } - - // skip rest of block - break; - } - - // try to switch screen. get the neighbor. - newScreen = mapToNeighbor(m_active, dir, m_x, m_y); - - // see if we should switch - if (!isSwitchOkay(newScreen, dir, m_x, m_y, xc, yc)) { - newScreen = m_active; - jump = false; - } - } while (false); - - if (jump) { - if (m_sendFileThread) { - StreamChunker::interruptFile(); - m_sendFileThread.reset(nullptr); - } - - SInt32 newX = m_x; - SInt32 newY = m_y; - - // switch screens - switchScreen(newScreen, newX, newY, false); - } - else { - // same screen. clamp mouse to edge. - m_x = xOld + dx; - m_y = yOld + dy; - if (m_x < ax) { - m_x = ax; - LOG((CLOG_DEBUG2 "clamp to left of \"%s\"", getName(m_active).c_str())); - } - else if (m_x > ax + aw - 1) { - m_x = ax + aw - 1; - LOG((CLOG_DEBUG2 "clamp to right of \"%s\"", getName(m_active).c_str())); - } - if (m_y < ay) { - m_y = ay; - LOG((CLOG_DEBUG2 "clamp to top of \"%s\"", getName(m_active).c_str())); - } - else if (m_y > ay + ah - 1) { - m_y = ay + ah - 1; - LOG((CLOG_DEBUG2 "clamp to bottom of \"%s\"", getName(m_active).c_str())); - } - - // warp cursor if it moved. - if (m_x != xOld || m_y != yOld) { - LOG((CLOG_DEBUG2 "move on %s to %d,%d", getName(m_active).c_str(), m_x, m_y)); - m_active->mouseMove(m_x, m_y); - } - } + case kNoDirection: + assert(0 && "bad direction"); + break; + } + return 0.0f; } -void -Server::onMouseWheel(SInt32 xDelta, SInt32 yDelta) -{ - LOG((CLOG_DEBUG1 "onMouseWheel %+d,%+d", xDelta, yDelta)); - assert(m_active != NULL); +void Server::mapToPixel(BaseClientProxy *client, EDirection dir, float f, + SInt32 &x, SInt32 &y) const { + SInt32 sx, sy, sw, sh; + client->getShape(sx, sy, sw, sh); + switch (dir) { + case kLeft: + case kRight: + y = static_cast(f * sh) + sy; + break; - // relay - m_active->mouseWheel(xDelta, yDelta); + case kTop: + case kBottom: + x = static_cast(f * sw) + sx; + break; + + case kNoDirection: + assert(0 && "bad direction"); + break; + } } -void -Server::onFileChunkSending(const void* data) -{ - FileChunk* chunk = static_cast(const_cast(data)); +bool Server::hasAnyNeighbor(BaseClientProxy *client, EDirection dir) const { + assert(client != NULL); - LOG((CLOG_DEBUG1 "sending file chunk")); - assert(m_active != NULL); - - // relay - m_active->fileChunkSending(chunk->m_chunk[0], &chunk->m_chunk[1], chunk->m_dataSize); + return m_config->hasNeighbor(getName(client), dir); } -void -Server::onFileRecieveCompleted() -{ - if (isReceivedFileSizeValid()) { - auto method = new TMethodJob(this, &Server::writeToDropDirThread); - m_writeToDropDirThread.reset(new Thread(method)); - } +BaseClientProxy *Server::getNeighbor(BaseClientProxy *src, EDirection dir, + SInt32 &x, SInt32 &y) const { + // note -- must be locked on entry + + assert(src != NULL); + + // get source screen name + String srcName = getName(src); + assert(!srcName.empty()); + LOG((CLOG_DEBUG2 "find neighbor on %s of \"%s\"", Config::dirName(dir), + srcName.c_str())); + + // convert position to fraction + float t = mapToFraction(src, dir, x, y); + + // search for the closest neighbor that exists in direction dir + float tTmp; + for (;;) { + String dstName(m_config->getNeighbor(srcName, dir, t, &tTmp)); + + // if nothing in that direction then return NULL. if the + // destination is the source then we can make no more + // progress in this direction. since we haven't found a + // connected neighbor we return NULL. + if (dstName.empty()) { + LOG((CLOG_DEBUG2 "no neighbor on %s of \"%s\"", Config::dirName(dir), + srcName.c_str())); + return NULL; + } + + // look up neighbor cell. if the screen is connected and + // ready then we can stop. + ClientList::const_iterator index = m_clients.find(dstName); + if (index != m_clients.end()) { + LOG((CLOG_DEBUG2 "\"%s\" is on %s of \"%s\" at %f", dstName.c_str(), + Config::dirName(dir), srcName.c_str(), t)); + mapToPixel(index->second, dir, tTmp, x, y); + return index->second; + } + + // skip over unconnected screen + LOG((CLOG_DEBUG2 "ignored \"%s\" on %s of \"%s\"", dstName.c_str(), + Config::dirName(dir), srcName.c_str())); + srcName = dstName; + + // use position on skipped screen + t = tTmp; + } } -void -Server::writeToDropDirThread(void*) -{ - LOG((CLOG_DEBUG "starting write to drop dir thread")); +BaseClientProxy *Server::mapToNeighbor(BaseClientProxy *src, EDirection srcSide, + SInt32 &x, SInt32 &y) const { + // note -- must be locked on entry - while (m_screen->isFakeDraggingStarted()) { - ARCH->sleep(.1f); - } + assert(src != NULL); - DropHelper::writeToDir(m_screen->getDropTarget(), m_fakeDragFileList, - m_receivedFileData); + // get the first neighbor + BaseClientProxy *dst = getNeighbor(src, srcSide, x, y); + if (dst == NULL) { + return NULL; + } + + // get the source screen's size + SInt32 dx, dy, dw, dh; + BaseClientProxy *lastGoodScreen = src; + lastGoodScreen->getShape(dx, dy, dw, dh); + + // find destination screen, adjusting x or y (but not both). the + // searches are done in a sort of canonical screen space where + // the upper-left corner is 0,0 for each screen. we adjust from + // actual to canonical position on entry to and from canonical to + // actual on exit from the search. + switch (srcSide) { + case kLeft: + x -= dx; + while (dst != NULL) { + lastGoodScreen = dst; + lastGoodScreen->getShape(dx, dy, dw, dh); + x += dw; + if (x >= 0) { + break; + } + LOG((CLOG_DEBUG2 "skipping over screen %s", getName(dst).c_str())); + dst = getNeighbor(lastGoodScreen, srcSide, x, y); + } + assert(lastGoodScreen != NULL); + x += dx; + break; + + case kRight: + x -= dx; + while (dst != NULL) { + x -= dw; + lastGoodScreen = dst; + lastGoodScreen->getShape(dx, dy, dw, dh); + if (x < dw) { + break; + } + LOG((CLOG_DEBUG2 "skipping over screen %s", getName(dst).c_str())); + dst = getNeighbor(lastGoodScreen, srcSide, x, y); + } + assert(lastGoodScreen != NULL); + x += dx; + break; + + case kTop: + y -= dy; + while (dst != NULL) { + lastGoodScreen = dst; + lastGoodScreen->getShape(dx, dy, dw, dh); + y += dh; + if (y >= 0) { + break; + } + LOG((CLOG_DEBUG2 "skipping over screen %s", getName(dst).c_str())); + dst = getNeighbor(lastGoodScreen, srcSide, x, y); + } + assert(lastGoodScreen != NULL); + y += dy; + break; + + case kBottom: + y -= dy; + while (dst != NULL) { + y -= dh; + lastGoodScreen = dst; + lastGoodScreen->getShape(dx, dy, dw, dh); + if (y < dh) { + break; + } + LOG((CLOG_DEBUG2 "skipping over screen %s", getName(dst).c_str())); + dst = getNeighbor(lastGoodScreen, srcSide, x, y); + } + assert(lastGoodScreen != NULL); + y += dy; + break; + + case kNoDirection: + assert(0 && "bad direction"); + return NULL; + } + + // save destination screen + assert(lastGoodScreen != NULL); + dst = lastGoodScreen; + + // if entering primary screen then be sure to move in far enough + // to avoid the jump zone. if entering a side that doesn't have + // a neighbor (i.e. an asymmetrical side) then we don't need to + // move inwards because that side can't provoke a jump. + avoidJumpZone(dst, srcSide, x, y); + + return dst; } -bool -Server::addClient(BaseClientProxy* client) -{ - String name = getName(client); - if (m_clients.count(name) != 0) { - return false; - } +void Server::avoidJumpZone(BaseClientProxy *dst, EDirection dir, SInt32 &x, + SInt32 &y) const { + // we only need to avoid jump zones on the primary screen + if (dst != m_primaryClient) { + return; + } - // add event handlers - m_events->adoptHandler(m_events->forIScreen().shapeChanged(), - client->getEventTarget(), - new TMethodEventJob(this, - &Server::handleShapeChanged, client)); - m_events->adoptHandler(m_events->forClipboard().clipboardGrabbed(), - client->getEventTarget(), - new TMethodEventJob(this, - &Server::handleClipboardGrabbed, client)); - m_events->adoptHandler(m_events->forClipboard().clipboardChanged(), - client->getEventTarget(), - new TMethodEventJob(this, - &Server::handleClipboardChanged, client)); + const String dstName(getName(dst)); + SInt32 dx, dy, dw, dh; + dst->getShape(dx, dy, dw, dh); + float t = mapToFraction(dst, dir, x, y); + SInt32 z = getJumpZoneSize(dst); - // add to list - m_clientSet.insert(client); - m_clients.insert(std::make_pair(name, client)); + // move in far enough to avoid the jump zone. if entering a side + // that doesn't have a neighbor (i.e. an asymmetrical side) then we + // don't need to move inwards because that side can't provoke a jump. + switch (dir) { + case kLeft: + if (!m_config->getNeighbor(dstName, kRight, t, NULL).empty() && + x > dx + dw - 1 - z) + x = dx + dw - 1 - z; + break; - // initialize client data - SInt32 x, y; - client->getCursorPos(x, y); - client->setJumpCursorPos(x, y); + case kRight: + if (!m_config->getNeighbor(dstName, kLeft, t, NULL).empty() && x < dx + z) + x = dx + z; + break; - // tell primary client about the active sides - m_primaryClient->reconfigure(getActivePrimarySides()); + case kTop: + if (!m_config->getNeighbor(dstName, kBottom, t, NULL).empty() && + y > dy + dh - 1 - z) + y = dy + dh - 1 - z; + break; - return true; + case kBottom: + if (!m_config->getNeighbor(dstName, kTop, t, NULL).empty() && y < dy + z) + y = dy + z; + break; + + case kNoDirection: + assert(0 && "bad direction"); + } } -bool -Server::removeClient(BaseClientProxy* client) -{ - // return false if not in list - ClientSet::iterator i = m_clientSet.find(client); - if (i == m_clientSet.end()) { - return false; - } +bool Server::isSwitchOkay(BaseClientProxy *newScreen, EDirection dir, SInt32 x, + SInt32 y, SInt32 xActive, SInt32 yActive) { + LOG((CLOG_DEBUG1 "try to leave \"%s\" on %s", getName(m_active).c_str(), + Config::dirName(dir))); - // remove event handlers - m_events->removeHandler(m_events->forIScreen().shapeChanged(), - client->getEventTarget()); - m_events->removeHandler(m_events->forClipboard().clipboardGrabbed(), - client->getEventTarget()); - m_events->removeHandler(m_events->forClipboard().clipboardChanged(), - client->getEventTarget()); + // is there a neighbor? + if (newScreen == NULL) { + // there's no neighbor. we don't want to switch and we don't + // want to try to switch later. + LOG((CLOG_DEBUG1 "no neighbor %s", Config::dirName(dir))); + stopSwitch(); + return false; + } - // remove from list - m_clients.erase(getName(client)); - m_clientSet.erase(i); + // should we switch or not? + bool preventSwitch = false; + bool allowSwitch = false; - return true; + // note if the switch direction has changed. save the new + // direction and screen if so. + bool isNewDirection = (dir != m_switchDir); + if (isNewDirection || m_switchScreen == NULL) { + m_switchDir = dir; + m_switchScreen = newScreen; + } + + // is this a double tap and do we care? + if (!allowSwitch && m_switchTwoTapDelay > 0.0) { + if (isNewDirection || !isSwitchTwoTapStarted() || !shouldSwitchTwoTap()) { + // tapping a different or new edge or second tap not + // fast enough. prepare for second tap. + preventSwitch = true; + startSwitchTwoTap(); + } else { + // got second tap + allowSwitch = true; + } + } + + // if waiting before a switch then prepare to switch later + if (!allowSwitch && m_switchWaitDelay > 0.0) { + if (isNewDirection || !isSwitchWaitStarted()) { + startSwitchWait(x, y); + } + preventSwitch = true; + } + + // are we in a locked corner? first check if screen has the option set + // and, if not, check the global options. + const Config::ScreenOptions *options = + m_config->getOptions(getName(m_active)); + if (options == NULL || options->count(kOptionScreenSwitchCorners) == 0) { + options = m_config->getOptions(""); + } + if (options != NULL && options->count(kOptionScreenSwitchCorners) > 0) { + // get corner mask and size + Config::ScreenOptions::const_iterator i = + options->find(kOptionScreenSwitchCorners); + UInt32 corners = static_cast(i->second); + i = options->find(kOptionScreenSwitchCornerSize); + SInt32 size = 0; + if (i != options->end()) { + size = i->second; + } + + // see if we're in a locked corner + if ((getCorner(m_active, xActive, yActive, size) & corners) != 0) { + // yep, no switching + LOG((CLOG_DEBUG1 "locked in corner")); + preventSwitch = true; + stopSwitch(); + } + } + + // ignore if mouse is locked to screen and don't try to switch later + if (!preventSwitch && isLockedToScreen()) { + LOG((CLOG_DEBUG1 "locked to screen")); + preventSwitch = true; + stopSwitch(); + } + + // check for optional needed modifiers + KeyModifierMask mods = this->m_primaryClient->getToggleMask(); + + if (!preventSwitch && + ((this->m_switchNeedsShift && + ((mods & KeyModifierShift) != KeyModifierShift)) || + (this->m_switchNeedsControl && + ((mods & KeyModifierControl) != KeyModifierControl)) || + (this->m_switchNeedsAlt && + ((mods & KeyModifierAlt) != KeyModifierAlt)))) { + LOG((CLOG_DEBUG1 "need modifiers to switch")); + preventSwitch = true; + stopSwitch(); + } + + return !preventSwitch; } -void -Server::closeClient(BaseClientProxy* client, const char* msg) -{ - assert(client != m_primaryClient); - assert(msg != NULL); - - // send message to client. this message should cause the client - // to disconnect. we add this client to the closed client list - // and install a timer to remove the client if it doesn't respond - // quickly enough. we also remove the client from the active - // client list since we're not going to listen to it anymore. - // note that this method also works on clients that are not in - // the m_clients list. adoptClient() may call us with such a - // client. - LOG((CLOG_NOTE "disconnecting client \"%s\"", getName(client).c_str())); - - // send message - // FIXME -- avoid type cast (kinda hard, though) - ((ClientProxy*)client)->close(msg); - - // install timer. wait timeout seconds for client to close. - double timeout = 5.0; - EventQueueTimer* timer = m_events->newOneShotTimer(timeout, NULL); - m_events->adoptHandler(Event::kTimer, timer, - new TMethodEventJob(this, - &Server::handleClientCloseTimeout, client)); - - // move client to closing list - removeClient(client); - m_oldClients.insert(std::make_pair(client, timer)); - - // if this client is the active screen then we have to - // jump off of it - forceLeaveClient(client); +void Server::noSwitch(SInt32 x, SInt32 y) { + armSwitchTwoTap(x, y); + stopSwitchWait(); } -void -Server::closeClients(const Config& config) -{ - // collect the clients that are connected but are being dropped - // from the configuration (or who's canonical name is changing). - typedef std::set RemovedClients; - RemovedClients removed; - for (ClientList::iterator index = m_clients.begin(); - index != m_clients.end(); ++index) { - if (!config.isCanonicalName(index->first)) { - removed.insert(index->second); - } - } - - // don't close the primary client - removed.erase(m_primaryClient); - - // now close them. we collect the list then close in two steps - // because closeClient() modifies the collection we iterate over. - for (RemovedClients::iterator index = removed.begin(); - index != removed.end(); ++index) { - closeClient(*index, kMsgCClose); - } +void Server::stopSwitch() { + if (m_switchScreen != NULL) { + m_switchScreen = NULL; + m_switchDir = kNoDirection; + stopSwitchTwoTap(); + stopSwitchWait(); + } } -void -Server::removeActiveClient(BaseClientProxy* client) -{ - if (removeClient(client)) { - forceLeaveClient(client); - m_events->removeHandler(m_events->forClientProxy().disconnected(), client); - if (m_clients.size() == 1 && m_oldClients.empty()) { - m_events->addEvent(Event(m_events->forServer().disconnected(), this)); - } - } +void Server::startSwitchTwoTap() { + m_switchTwoTapEngaged = true; + m_switchTwoTapArmed = false; + m_switchTwoTapTimer.reset(); + LOG((CLOG_DEBUG1 "waiting for second tap")); } -void -Server::removeOldClient(BaseClientProxy* client) -{ - OldClients::iterator i = m_oldClients.find(client); - if (i != m_oldClients.end()) { - m_events->removeHandler(m_events->forClientProxy().disconnected(), client); - m_events->removeHandler(Event::kTimer, i->second); - m_events->deleteTimer(i->second); - m_oldClients.erase(i); - if (m_clients.size() == 1 && m_oldClients.empty()) { - m_events->addEvent(Event(m_events->forServer().disconnected(), this)); - } - } +void Server::armSwitchTwoTap(SInt32 x, SInt32 y) { + if (m_switchTwoTapEngaged) { + if (m_switchTwoTapTimer.getTime() > m_switchTwoTapDelay) { + // second tap took too long. disengage. + stopSwitchTwoTap(); + } else if (!m_switchTwoTapArmed) { + // still time for a double tap. see if we left the tap + // zone and, if so, arm the two tap. + SInt32 ax, ay, aw, ah; + m_active->getShape(ax, ay, aw, ah); + SInt32 tapZone = m_primaryClient->getJumpZoneSize(); + if (tapZone < m_switchTwoTapZone) { + tapZone = m_switchTwoTapZone; + } + if (x >= ax + tapZone && x < ax + aw - tapZone && y >= ay + tapZone && + y < ay + ah - tapZone) { + // win32 can generate bogus mouse events that appear to + // move in the opposite direction that the mouse actually + // moved. try to ignore that crap here. + switch (m_switchDir) { + case kLeft: + m_switchTwoTapArmed = (m_xDelta > 0 && m_xDelta2 > 0); + break; + + case kRight: + m_switchTwoTapArmed = (m_xDelta < 0 && m_xDelta2 < 0); + break; + + case kTop: + m_switchTwoTapArmed = (m_yDelta > 0 && m_yDelta2 > 0); + break; + + case kBottom: + m_switchTwoTapArmed = (m_yDelta < 0 && m_yDelta2 < 0); + break; + + default: + break; + } + } + } + } } -void -Server::forceLeaveClient(BaseClientProxy* client) -{ - BaseClientProxy* active = - (m_activeSaver != NULL) ? m_activeSaver : m_active; - if (active == client) { - // record new position (center of primary screen) - m_primaryClient->getCursorCenter(m_x, m_y); - - // stop waiting to switch to this client - if (active == m_switchScreen) { - stopSwitch(); - } - - // don't notify active screen since it has probably already - // disconnected. - LOG((CLOG_INFO "jump from \"%s\" to \"%s\" at %d,%d", getName(active).c_str(), getName(m_primaryClient).c_str(), m_x, m_y)); - - // cut over - m_active = m_primaryClient; - - // enter new screen (unless we already have because of the - // screen saver) - if (m_activeSaver == NULL) { - m_primaryClient->enter(m_x, m_y, m_seqNum, - m_primaryClient->getToggleMask(), false); - } - } - - // if this screen had the cursor when the screen saver activated - // then we can't switch back to it when the screen saver - // deactivates. - if (m_activeSaver == client) { - m_activeSaver = NULL; - } - - // tell primary client about the active sides - m_primaryClient->reconfigure(getActivePrimarySides()); +void Server::stopSwitchTwoTap() { + m_switchTwoTapEngaged = false; + m_switchTwoTapArmed = false; } +bool Server::isSwitchTwoTapStarted() const { return m_switchTwoTapEngaged; } + +bool Server::shouldSwitchTwoTap() const { + // this is the second tap if two-tap is armed and this tap + // came fast enough + return (m_switchTwoTapArmed && + m_switchTwoTapTimer.getTime() <= m_switchTwoTapDelay); +} + +void Server::startSwitchWait(SInt32 x, SInt32 y) { + stopSwitchWait(); + m_switchWaitX = x; + m_switchWaitY = y; + m_switchWaitTimer = m_events->newOneShotTimer(m_switchWaitDelay, this); + LOG((CLOG_DEBUG1 "waiting to switch")); +} + +void Server::stopSwitchWait() { + if (m_switchWaitTimer != NULL) { + m_events->deleteTimer(m_switchWaitTimer); + m_switchWaitTimer = NULL; + } +} + +bool Server::isSwitchWaitStarted() const { return (m_switchWaitTimer != NULL); } + +UInt32 Server::getCorner(BaseClientProxy *client, SInt32 x, SInt32 y, + SInt32 size) const { + assert(client != NULL); + + // get client screen shape + SInt32 ax, ay, aw, ah; + client->getShape(ax, ay, aw, ah); + + // check for x,y on the left or right + SInt32 xSide; + if (x <= ax) { + xSide = -1; + } else if (x >= ax + aw - 1) { + xSide = 1; + } else { + xSide = 0; + } + + // check for x,y on the top or bottom + SInt32 ySide; + if (y <= ay) { + ySide = -1; + } else if (y >= ay + ah - 1) { + ySide = 1; + } else { + ySide = 0; + } + + // if against the left or right then check if y is within size + if (xSide != 0) { + if (y < ay + size) { + return (xSide < 0) ? kTopLeftMask : kTopRightMask; + } else if (y >= ay + ah - size) { + return (xSide < 0) ? kBottomLeftMask : kBottomRightMask; + } + } + + // if against the left or right then check if y is within size + if (ySide != 0) { + if (x < ax + size) { + return (ySide < 0) ? kTopLeftMask : kBottomLeftMask; + } else if (x >= ax + aw - size) { + return (ySide < 0) ? kTopRightMask : kBottomRightMask; + } + } + + return kNoCornerMask; +} + +void Server::stopRelativeMoves() { + if (m_relativeMoves && m_active != m_primaryClient) { + // warp to the center of the active client so we know where we are + SInt32 ax, ay, aw, ah; + m_active->getShape(ax, ay, aw, ah); + m_x = ax + (aw >> 1); + m_y = ay + (ah >> 1); + m_xDelta = 0; + m_yDelta = 0; + m_xDelta2 = 0; + m_yDelta2 = 0; + LOG((CLOG_DEBUG2 "synchronize move on %s by %d,%d", + getName(m_active).c_str(), m_x, m_y)); + m_active->mouseMove(m_x, m_y); + } +} + +void Server::sendOptions(BaseClientProxy *client) const { + OptionsList optionsList; + + // look up options for client + const Config::ScreenOptions *options = m_config->getOptions(getName(client)); + if (options != NULL) { + // convert options to a more convenient form for sending + optionsList.reserve(2 * options->size()); + for (Config::ScreenOptions::const_iterator index = options->begin(); + index != options->end(); ++index) { + optionsList.push_back(index->first); + optionsList.push_back(static_cast(index->second)); + } + } + + // look up global options + options = m_config->getOptions(""); + if (options != NULL) { + // convert options to a more convenient form for sending + optionsList.reserve(optionsList.size() + 2 * options->size()); + for (Config::ScreenOptions::const_iterator index = options->begin(); + index != options->end(); ++index) { + optionsList.push_back(index->first); + optionsList.push_back(static_cast(index->second)); + } + } + + // send the options + client->resetOptions(); + client->setOptions(optionsList); +} + +void Server::processOptions() { + const Config::ScreenOptions *options = m_config->getOptions(""); + if (options == NULL) { + return; + } + + m_switchNeedsShift = false; // it seems if i don't add these + m_switchNeedsControl = false; // lines, the 'reload config' option + m_switchNeedsAlt = false; // doesnt' work correct. + + bool newRelativeMoves = m_relativeMoves; + for (Config::ScreenOptions::const_iterator index = options->begin(); + index != options->end(); ++index) { + const OptionID id = index->first; + const OptionValue value = index->second; + if (id == kOptionScreenSwitchDelay) { + m_switchWaitDelay = 1.0e-3 * static_cast(value); + if (m_switchWaitDelay < 0.0) { + m_switchWaitDelay = 0.0; + } + stopSwitchWait(); + } else if (id == kOptionScreenSwitchTwoTap) { + m_switchTwoTapDelay = 1.0e-3 * static_cast(value); + if (m_switchTwoTapDelay < 0.0) { + m_switchTwoTapDelay = 0.0; + } + stopSwitchTwoTap(); + } else if (id == kOptionScreenSwitchNeedsControl) { + m_switchNeedsControl = (value != 0); + } else if (id == kOptionScreenSwitchNeedsShift) { + m_switchNeedsShift = (value != 0); + } else if (id == kOptionScreenSwitchNeedsAlt) { + m_switchNeedsAlt = (value != 0); + } else if (id == kOptionRelativeMouseMoves) { + newRelativeMoves = (value != 0); + } else if (id == kOptionDisableLockToScreen) { + m_disableLockToScreen = (value != 0); + } else if (id == kOptionClipboardSharing) { + m_enableClipboard = value; + if (!m_enableClipboard) { + LOG((CLOG_NOTE "clipboard sharing is disabled")); + } + } else if (id == kOptionClipboardSharingSize) { + if (value <= 0) { + m_maximumClipboardSize = 0; + LOG((CLOG_NOTE "clipboard sharing is disabled because the " + "maximum shared clipboard size is set to 0")); + } else { + m_maximumClipboardSize = static_cast(value); + } + } + } + if (m_relativeMoves && !newRelativeMoves) { + stopRelativeMoves(); + } + m_relativeMoves = newRelativeMoves; +} + +void Server::handleShapeChanged(const Event &, void *vclient) { + // ignore events from unknown clients + BaseClientProxy *client = static_cast(vclient); + if (m_clientSet.count(client) == 0) { + return; + } + + LOG((CLOG_DEBUG "screen \"%s\" shape changed", getName(client).c_str())); + + // update jump coordinate + SInt32 x, y; + client->getCursorPos(x, y); + client->setJumpCursorPos(x, y); + + // update the mouse coordinates + if (client == m_active) { + m_x = x; + m_y = y; + } + + // handle resolution change to primary screen + if (client == m_primaryClient) { + if (client == m_active) { + onMouseMovePrimary(m_x, m_y); + } else { + onMouseMoveSecondary(0, 0); + } + } +} + +void Server::handleClipboardGrabbed(const Event &event, void *vclient) { + if (!m_enableClipboard || (m_maximumClipboardSize == 0)) { + return; + } + + // ignore events from unknown clients + BaseClientProxy *grabber = static_cast(vclient); + if (m_clientSet.count(grabber) == 0) { + return; + } + const IScreen::ClipboardInfo *info = + static_cast(event.getData()); + + // ignore grab if sequence number is old. always allow primary + // screen to grab. + ClipboardInfo &clipboard = m_clipboards[info->m_id]; + if (grabber != m_primaryClient && + info->m_sequenceNumber < clipboard.m_clipboardSeqNum) { + LOG((CLOG_INFO "ignored screen \"%s\" grab of clipboard %d", + getName(grabber).c_str(), info->m_id)); + return; + } + + // mark screen as owning clipboard + LOG((CLOG_INFO "screen \"%s\" grabbed clipboard %d from \"%s\"", + getName(grabber).c_str(), info->m_id, + clipboard.m_clipboardOwner.c_str())); + clipboard.m_clipboardOwner = getName(grabber); + clipboard.m_clipboardSeqNum = info->m_sequenceNumber; + + // clear the clipboard data (since it's not known at this point) + if (clipboard.m_clipboard.open(0)) { + clipboard.m_clipboard.empty(); + clipboard.m_clipboard.close(); + } + clipboard.m_clipboardData = clipboard.m_clipboard.marshall(); + + // tell all other screens to take ownership of clipboard. tell the + // grabber that it's clipboard isn't dirty. + for (ClientList::iterator index = m_clients.begin(); index != m_clients.end(); + ++index) { + BaseClientProxy *client = index->second; + if (client == grabber) { + client->setClipboardDirty(info->m_id, false); + } else { + client->grabClipboard(info->m_id); + } + } + + if (grabber == m_primaryClient && m_active != m_primaryClient) { + LOG((CLOG_INFO "clipboard grabbed, but we are already changed active " + "screen. Resend clipboard data")); + for (ClipboardID id = 0; id < kClipboardEnd; ++id) { + onClipboardChanged(m_primaryClient, id, + m_clipboards[id].m_clipboardSeqNum); + } + } +} + +void Server::handleClipboardChanged(const Event &event, void *vclient) { + // ignore events from unknown clients + BaseClientProxy *sender = static_cast(vclient); + if (m_clientSet.count(sender) == 0) { + return; + } + const IScreen::ClipboardInfo *info = + static_cast(event.getData()); + onClipboardChanged(sender, info->m_id, info->m_sequenceNumber); +} + +void Server::handleKeyDownEvent(const Event &event, void *) { + IPlatformScreen::KeyInfo *info = + static_cast(event.getData()); + auto lang = AppUtil::instance().getCurrentLanguageCode(); + onKeyDown(info->m_key, info->m_mask, info->m_button, lang, info->m_screens); +} + +void Server::handleKeyUpEvent(const Event &event, void *) { + IPlatformScreen::KeyInfo *info = + static_cast(event.getData()); + onKeyUp(info->m_key, info->m_mask, info->m_button, info->m_screens); +} + +void Server::handleKeyRepeatEvent(const Event &event, void *) { + IPlatformScreen::KeyInfo *info = + static_cast(event.getData()); + auto lang = AppUtil::instance().getCurrentLanguageCode(); + onKeyRepeat(info->m_key, info->m_mask, info->m_count, info->m_button, lang); +} + +void Server::handleButtonDownEvent(const Event &event, void *) { + IPlatformScreen::ButtonInfo *info = + static_cast(event.getData()); + onMouseDown(info->m_button); +} + +void Server::handleButtonUpEvent(const Event &event, void *) { + IPlatformScreen::ButtonInfo *info = + static_cast(event.getData()); + onMouseUp(info->m_button); +} + +void Server::handleMotionPrimaryEvent(const Event &event, void *) { + IPlatformScreen::MotionInfo *info = + static_cast(event.getData()); + onMouseMovePrimary(info->m_x, info->m_y); +} + +void Server::handleMotionSecondaryEvent(const Event &event, void *) { + IPlatformScreen::MotionInfo *info = + static_cast(event.getData()); + onMouseMoveSecondary(info->m_x, info->m_y); +} + +void Server::handleWheelEvent(const Event &event, void *) { + IPlatformScreen::WheelInfo *info = + static_cast(event.getData()); + onMouseWheel(info->m_xDelta, info->m_yDelta); +} + +void Server::handleScreensaverActivatedEvent(const Event &, void *) { + onScreensaver(true); +} + +void Server::handleScreensaverDeactivatedEvent(const Event &, void *) { + onScreensaver(false); +} + +void Server::handleSwitchWaitTimeout(const Event &, void *) { + // ignore if mouse is locked to screen + if (isLockedToScreen()) { + LOG((CLOG_DEBUG1 "locked to screen")); + stopSwitch(); + return; + } + + // switch screen + switchScreen(m_switchScreen, m_switchWaitX, m_switchWaitY, false); +} + +void Server::handleClientDisconnected(const Event &, void *vclient) { + // client has disconnected. it might be an old client or an + // active client. we don't care so just handle it both ways. + BaseClientProxy *client = static_cast(vclient); + removeActiveClient(client); + removeOldClient(client); + + delete client; + m_clientListener->restart(); +} + +void Server::handleClientCloseTimeout(const Event &, void *vclient) { + // client took too long to disconnect. just dump it. + BaseClientProxy *client = static_cast(vclient); + LOG((CLOG_NOTE "forced disconnection of client \"%s\"", + getName(client).c_str())); + removeOldClient(client); + + delete client; +} + +void Server::handleSwitchToScreenEvent(const Event &event, void *) { + SwitchToScreenInfo *info = static_cast(event.getData()); + + ClientList::const_iterator index = m_clients.find(info->m_screen); + if (index == m_clients.end()) { + LOG((CLOG_DEBUG1 "screen \"%s\" not active", info->m_screen)); + } else { + jumpToScreen(index->second); + } +} + +void Server::handleSwitchInDirectionEvent(const Event &event, void *) { + SwitchInDirectionInfo *info = + static_cast(event.getData()); + + // jump to screen in chosen direction from center of this screen + SInt32 x = m_x, y = m_y; + BaseClientProxy *newScreen = getNeighbor(m_active, info->m_direction, x, y); + if (newScreen == NULL) { + LOG((CLOG_DEBUG1 "no neighbor %s", Config::dirName(info->m_direction))); + } else { + jumpToScreen(newScreen); + } +} + +void Server::handleKeyboardBroadcastEvent(const Event &event, void *) { + KeyboardBroadcastInfo *info = (KeyboardBroadcastInfo *)event.getData(); + + // choose new state + bool newState; + switch (info->m_state) { + case KeyboardBroadcastInfo::kOff: + newState = false; + break; + + default: + case KeyboardBroadcastInfo::kOn: + newState = true; + break; + + case KeyboardBroadcastInfo::kToggle: + newState = !m_keyboardBroadcasting; + break; + } + + // enter new state + if (newState != m_keyboardBroadcasting || + info->m_screens != m_keyboardBroadcastingScreens) { + m_keyboardBroadcasting = newState; + m_keyboardBroadcastingScreens = info->m_screens; + LOG((CLOG_DEBUG "keyboard broadcasting %s: %s", + m_keyboardBroadcasting ? "on" : "off", + m_keyboardBroadcastingScreens.c_str())); + } +} + +void Server::handleLockCursorToScreenEvent(const Event &event, void *) { + LockCursorToScreenInfo *info = (LockCursorToScreenInfo *)event.getData(); + + // choose new state + bool newState; + switch (info->m_state) { + case LockCursorToScreenInfo::kOff: + newState = false; + break; + + default: + case LockCursorToScreenInfo::kOn: + newState = true; + break; + + case LockCursorToScreenInfo::kToggle: + newState = !m_lockedToScreen; + break; + } + + // enter new state + if (newState != m_lockedToScreen) { + m_lockedToScreen = newState; + LOG((CLOG_NOTE "cursor %s current screen", + m_lockedToScreen ? "locked to" : "unlocked from")); + + m_primaryClient->reconfigure(getActivePrimarySides()); + if (!isLockedToScreenServer()) { + stopRelativeMoves(); + } + } +} + +void Server::handleFakeInputBeginEvent(const Event &, void *) { + m_primaryClient->fakeInputBegin(); +} + +void Server::handleFakeInputEndEvent(const Event &, void *) { + m_primaryClient->fakeInputEnd(); +} + +void Server::handleFileChunkSendingEvent(const Event &event, void *) { + onFileChunkSending(event.getDataObject()); +} + +void Server::handleFileRecieveCompletedEvent(const Event &event, void *) { + onFileRecieveCompleted(); +} + +void Server::onClipboardChanged(BaseClientProxy *sender, ClipboardID id, + UInt32 seqNum) { + ClipboardInfo &clipboard = m_clipboards[id]; + + // ignore update if sequence number is old + if (seqNum < clipboard.m_clipboardSeqNum) { + LOG((CLOG_INFO + "ignored screen \"%s\" update of clipboard %d (missequenced)", + getName(sender).c_str(), id)); + return; + } + + // should be the expected client + assert(sender == m_clients.find(clipboard.m_clipboardOwner)->second); + + // get data + sender->getClipboard(id, &clipboard.m_clipboard); + + String data = clipboard.m_clipboard.marshall(); + if (data.size() > m_maximumClipboardSize * 1024) { + LOG((CLOG_NOTE "not updating clipboard because it's over the size limit " + "(%i KB) configured by the server", + m_maximumClipboardSize)); + return; + } + + // ignore if data hasn't changed + if (data == clipboard.m_clipboardData) { + LOG((CLOG_DEBUG "ignored screen \"%s\" update of clipboard %d (unchanged)", + clipboard.m_clipboardOwner.c_str(), id)); + return; + } + + // got new data + LOG((CLOG_INFO "screen \"%s\" updated clipboard %d", + clipboard.m_clipboardOwner.c_str(), id)); + clipboard.m_clipboardData = data; + + // tell all clients except the sender that the clipboard is dirty + for (ClientList::const_iterator index = m_clients.begin(); + index != m_clients.end(); ++index) { + BaseClientProxy *client = index->second; + client->setClipboardDirty(id, client != sender); + } + + // send the new clipboard to the active screen + m_active->setClipboard(id, &clipboard.m_clipboard); +} + +void Server::onScreensaver(bool activated) { + LOG((CLOG_DEBUG "onScreenSaver %s", activated ? "activated" : "deactivated")); + + if (activated) { + // save current screen and position + m_activeSaver = m_active; + m_xSaver = m_x; + m_ySaver = m_y; + + // jump to primary screen + if (m_active != m_primaryClient) { + switchScreen(m_primaryClient, 0, 0, true); + } + } else { + // jump back to previous screen and position. we must check + // that the position is still valid since the screen may have + // changed resolutions while the screen saver was running. + if (m_activeSaver != NULL && m_activeSaver != m_primaryClient) { + // check position + BaseClientProxy *screen = m_activeSaver; + SInt32 x, y, w, h; + screen->getShape(x, y, w, h); + SInt32 zoneSize = getJumpZoneSize(screen); + if (m_xSaver < x + zoneSize) { + m_xSaver = x + zoneSize; + } else if (m_xSaver >= x + w - zoneSize) { + m_xSaver = x + w - zoneSize - 1; + } + if (m_ySaver < y + zoneSize) { + m_ySaver = y + zoneSize; + } else if (m_ySaver >= y + h - zoneSize) { + m_ySaver = y + h - zoneSize - 1; + } + + // jump + switchScreen(screen, m_xSaver, m_ySaver, false); + } + + // reset state + m_activeSaver = NULL; + } + + // send message to all clients + for (ClientList::const_iterator index = m_clients.begin(); + index != m_clients.end(); ++index) { + BaseClientProxy *client = index->second; + client->screensaver(activated); + } +} + +void Server::onKeyDown(KeyID id, KeyModifierMask mask, KeyButton button, + const String &lang, const char *screens) { + LOG((CLOG_DEBUG1 "onKeyDown id=%d mask=0x%04x button=0x%04x lang=%s", id, + mask, button, lang.c_str())); + assert(m_active != NULL); + + // relay + if (!m_keyboardBroadcasting && IKeyState::KeyInfo::isDefault(screens)) { + m_active->keyDown(id, mask, button, lang); + } else { + if (!screens && m_keyboardBroadcasting) { + screens = m_keyboardBroadcastingScreens.c_str(); + if (IKeyState::KeyInfo::isDefault(screens)) { + screens = "*"; + } + } + for (ClientList::const_iterator index = m_clients.begin(); + index != m_clients.end(); ++index) { + if (IKeyState::KeyInfo::contains(screens, index->first)) { + index->second->keyDown(id, mask, button, lang); + } + } + } +} + +void Server::onKeyUp(KeyID id, KeyModifierMask mask, KeyButton button, + const char *screens) { + LOG((CLOG_DEBUG1 "onKeyUp id=%d mask=0x%04x button=0x%04x", id, mask, + button)); + assert(m_active != NULL); + + // relay + if (!m_keyboardBroadcasting && IKeyState::KeyInfo::isDefault(screens)) { + m_active->keyUp(id, mask, button); + } else { + if (!screens && m_keyboardBroadcasting) { + screens = m_keyboardBroadcastingScreens.c_str(); + if (IKeyState::KeyInfo::isDefault(screens)) { + screens = "*"; + } + } + for (ClientList::const_iterator index = m_clients.begin(); + index != m_clients.end(); ++index) { + if (IKeyState::KeyInfo::contains(screens, index->first)) { + index->second->keyUp(id, mask, button); + } + } + } +} + +void Server::onKeyRepeat(KeyID id, KeyModifierMask mask, SInt32 count, + KeyButton button, const String &lang) { + LOG((CLOG_DEBUG1 + "onKeyRepeat id=%d mask=0x%04x count=%d button=0x%04x lang=\"%s\"", + id, mask, count, button, lang.c_str())); + assert(m_active != NULL); + + // relay + m_active->keyRepeat(id, mask, count, button, lang); +} + +void Server::onMouseDown(ButtonID id) { + LOG((CLOG_DEBUG1 "onMouseDown id=%d", id)); + assert(m_active != NULL); + + // relay + m_active->mouseDown(id); + + // reset this variable back to default value true + m_waitDragInfoThread = true; +} + +void Server::onMouseUp(ButtonID id) { + LOG((CLOG_DEBUG1 "onMouseUp id=%d", id)); + assert(m_active != NULL); + + // relay + m_active->mouseUp(id); + + if (m_ignoreFileTransfer) { + m_ignoreFileTransfer = false; + return; + } + + if (m_args.m_enableDragDrop) { + if (!m_screen->isOnScreen()) { + String &file = m_screen->getDraggingFilename(); + if (!file.empty()) { + sendFileToClient(file.c_str()); + } + } + + // always clear dragging filename + m_screen->clearDraggingFilename(); + } +} + +bool Server::onMouseMovePrimary(SInt32 x, SInt32 y) { + LOG((CLOG_DEBUG4 "onMouseMovePrimary %d,%d", x, y)); + + // mouse move on primary (server's) screen + if (m_active != m_primaryClient) { + // stale event -- we're actually on a secondary screen + return false; + } + + // save last delta + m_xDelta2 = m_xDelta; + m_yDelta2 = m_yDelta; + + // save current delta + m_xDelta = x - m_x; + m_yDelta = y - m_y; + + // save position + m_x = x; + m_y = y; + + // get screen shape + SInt32 ax, ay, aw, ah; + m_active->getShape(ax, ay, aw, ah); + SInt32 zoneSize = getJumpZoneSize(m_active); + + // clamp position to screen + SInt32 xc = x, yc = y; + if (xc < ax + zoneSize) { + xc = ax; + } else if (xc >= ax + aw - zoneSize) { + xc = ax + aw - 1; + } + if (yc < ay + zoneSize) { + yc = ay; + } else if (yc >= ay + ah - zoneSize) { + yc = ay + ah - 1; + } + + // see if we should change screens + // when the cursor is in a corner, there may be a screen either + // horizontally or vertically. check both directions. + EDirection dirh = kNoDirection, dirv = kNoDirection; + SInt32 xh = x, yv = y; + if (x < ax + zoneSize) { + xh -= zoneSize; + dirh = kLeft; + } else if (x >= ax + aw - zoneSize) { + xh += zoneSize; + dirh = kRight; + } + if (y < ay + zoneSize) { + yv -= zoneSize; + dirv = kTop; + } else if (y >= ay + ah - zoneSize) { + yv += zoneSize; + dirv = kBottom; + } + if (dirh == kNoDirection && dirv == kNoDirection) { + // still on local screen + noSwitch(x, y); + return false; + } + + // check both horizontally and vertically + EDirection dirs[] = {dirh, dirv}; + SInt32 xs[] = {xh, x}, ys[] = {y, yv}; + for (int i = 0; i < 2; ++i) { + EDirection dir = dirs[i]; + if (dir == kNoDirection) { + continue; + } + x = xs[i], y = ys[i]; + + // get jump destination + BaseClientProxy *newScreen = mapToNeighbor(m_active, dir, x, y); + + // should we switch or not? + if (isSwitchOkay(newScreen, dir, x, y, xc, yc)) { + if (m_args.m_enableDragDrop && m_screen->isDraggingStarted() && + m_active != newScreen && m_waitDragInfoThread) { + if (!m_sendDragInfoThread) { + m_sendDragInfoThread.reset(new Thread(new TMethodJob( + this, &Server::sendDragInfoThread, newScreen))); + } + + return false; + } + + // switch screen + switchScreen(newScreen, x, y, false); + m_waitDragInfoThread = true; + return true; + } + } + + return false; +} + +void Server::sendDragInfoThread(void *arg) { + BaseClientProxy *newScreen = static_cast(arg); + + m_dragFileList.clear(); + String &dragFileList = m_screen->getDraggingFilename(); + if (!dragFileList.empty()) { + DragInformation di; + di.setFilename(dragFileList); + m_dragFileList.push_back(di); + } + +#if defined(__APPLE__) + // on mac it seems that after faking a LMB up, system would signal back + // to synergy a mouse up event, which doesn't happen on windows. as a + // result, synergy would send dragging file to client twice. This variable + // is used to ignore the first file sending. + m_ignoreFileTransfer = true; +#endif + + // send drag file info to client if there is any + if (m_dragFileList.size() > 0) { + sendDragInfo(newScreen); + m_dragFileList.clear(); + } + m_waitDragInfoThread = false; + m_sendDragInfoThread.reset(nullptr); +} + +void Server::sendDragInfo(BaseClientProxy *newScreen) { + String infoString; + UInt32 fileCount = DragInformation::setupDragInfo(m_dragFileList, infoString); + + if (fileCount > 0) { + LOG((CLOG_DEBUG2 "sending drag information to client")); + LOG((CLOG_DEBUG3 "dragging file list: %s", infoString.c_str())); + LOG((CLOG_DEBUG3 "dragging file list string size: %i", infoString.size())); + newScreen->sendDragInfo(fileCount, infoString.c_str(), infoString.size()); + } +} + +void Server::onMouseMoveSecondary(SInt32 dx, SInt32 dy) { + LOG((CLOG_DEBUG2 "onMouseMoveSecondary %+d,%+d", dx, dy)); + + // mouse move on secondary (client's) screen + assert(m_active != NULL); + if (m_active == m_primaryClient) { + // stale event -- we're actually on the primary screen + return; + } + + // if doing relative motion on secondary screens and we're locked + // to the screen (which activates relative moves) then send a + // relative mouse motion. when we're doing this we pretend as if + // the mouse isn't actually moving because we're expecting some + // program on the secondary screen to warp the mouse on us, so we + // have no idea where it really is. + if (m_relativeMoves && isLockedToScreenServer()) { + LOG((CLOG_DEBUG2 "relative move on %s by %d,%d", getName(m_active).c_str(), + dx, dy)); + m_active->mouseRelativeMove(dx, dy); + return; + } + + // save old position + const SInt32 xOld = m_x; + const SInt32 yOld = m_y; + + // save last delta + m_xDelta2 = m_xDelta; + m_yDelta2 = m_yDelta; + + // save current delta + m_xDelta = dx; + m_yDelta = dy; + + // accumulate motion + m_x += dx; + m_y += dy; + + // get screen shape + SInt32 ax, ay, aw, ah; + m_active->getShape(ax, ay, aw, ah); + + // find direction of neighbor and get the neighbor + bool jump = true; + BaseClientProxy *newScreen; + do { + // clamp position to screen + SInt32 xc = m_x, yc = m_y; + if (xc < ax) { + xc = ax; + } else if (xc >= ax + aw) { + xc = ax + aw - 1; + } + if (yc < ay) { + yc = ay; + } else if (yc >= ay + ah) { + yc = ay + ah - 1; + } + + EDirection dir; + if (m_x < ax) { + dir = kLeft; + } else if (m_x > ax + aw - 1) { + dir = kRight; + } else if (m_y < ay) { + dir = kTop; + } else if (m_y > ay + ah - 1) { + dir = kBottom; + } else { + // we haven't left the screen + newScreen = m_active; + jump = false; + + // if waiting and mouse is not on the border we're waiting + // on then stop waiting. also if it's not on the border + // then arm the double tap. + if (m_switchScreen != NULL) { + bool clearWait; + SInt32 zoneSize = m_primaryClient->getJumpZoneSize(); + switch (m_switchDir) { + case kLeft: + clearWait = (m_x >= ax + zoneSize); + break; + + case kRight: + clearWait = (m_x <= ax + aw - 1 - zoneSize); + break; + + case kTop: + clearWait = (m_y >= ay + zoneSize); + break; + + case kBottom: + clearWait = (m_y <= ay + ah - 1 + zoneSize); + break; + + default: + clearWait = false; + break; + } + if (clearWait) { + // still on local screen + noSwitch(m_x, m_y); + } + } + + // skip rest of block + break; + } + + // try to switch screen. get the neighbor. + newScreen = mapToNeighbor(m_active, dir, m_x, m_y); + + // see if we should switch + if (!isSwitchOkay(newScreen, dir, m_x, m_y, xc, yc)) { + newScreen = m_active; + jump = false; + } + } while (false); + + if (jump) { + if (m_sendFileThread) { + StreamChunker::interruptFile(); + m_sendFileThread.reset(nullptr); + } + + SInt32 newX = m_x; + SInt32 newY = m_y; + + // switch screens + switchScreen(newScreen, newX, newY, false); + } else { + // same screen. clamp mouse to edge. + m_x = xOld + dx; + m_y = yOld + dy; + if (m_x < ax) { + m_x = ax; + LOG((CLOG_DEBUG2 "clamp to left of \"%s\"", getName(m_active).c_str())); + } else if (m_x > ax + aw - 1) { + m_x = ax + aw - 1; + LOG((CLOG_DEBUG2 "clamp to right of \"%s\"", getName(m_active).c_str())); + } + if (m_y < ay) { + m_y = ay; + LOG((CLOG_DEBUG2 "clamp to top of \"%s\"", getName(m_active).c_str())); + } else if (m_y > ay + ah - 1) { + m_y = ay + ah - 1; + LOG((CLOG_DEBUG2 "clamp to bottom of \"%s\"", getName(m_active).c_str())); + } + + // warp cursor if it moved. + if (m_x != xOld || m_y != yOld) { + LOG((CLOG_DEBUG2 "move on %s to %d,%d", getName(m_active).c_str(), m_x, + m_y)); + m_active->mouseMove(m_x, m_y); + } + } +} + +void Server::onMouseWheel(SInt32 xDelta, SInt32 yDelta) { + LOG((CLOG_DEBUG1 "onMouseWheel %+d,%+d", xDelta, yDelta)); + assert(m_active != NULL); + + // relay + m_active->mouseWheel(xDelta, yDelta); +} + +void Server::onFileChunkSending(const void *data) { + FileChunk *chunk = static_cast(const_cast(data)); + + LOG((CLOG_DEBUG1 "sending file chunk")); + assert(m_active != NULL); + + // relay + m_active->fileChunkSending(chunk->m_chunk[0], &chunk->m_chunk[1], + chunk->m_dataSize); +} + +void Server::onFileRecieveCompleted() { + if (isReceivedFileSizeValid()) { + auto method = new TMethodJob(this, &Server::writeToDropDirThread); + m_writeToDropDirThread.reset(new Thread(method)); + } +} + +void Server::writeToDropDirThread(void *) { + LOG((CLOG_DEBUG "starting write to drop dir thread")); + + while (m_screen->isFakeDraggingStarted()) { + ARCH->sleep(.1f); + } + + DropHelper::writeToDir(m_screen->getDropTarget(), m_fakeDragFileList, + m_receivedFileData); +} + +bool Server::addClient(BaseClientProxy *client) { + String name = getName(client); + if (m_clients.count(name) != 0) { + return false; + } + + // add event handlers + m_events->adoptHandler( + m_events->forIScreen().shapeChanged(), client->getEventTarget(), + new TMethodEventJob(this, &Server::handleShapeChanged, client)); + m_events->adoptHandler(m_events->forClipboard().clipboardGrabbed(), + client->getEventTarget(), + new TMethodEventJob( + this, &Server::handleClipboardGrabbed, client)); + m_events->adoptHandler(m_events->forClipboard().clipboardChanged(), + client->getEventTarget(), + new TMethodEventJob( + this, &Server::handleClipboardChanged, client)); + + // add to list + m_clientSet.insert(client); + m_clients.insert(std::make_pair(name, client)); + + // initialize client data + SInt32 x, y; + client->getCursorPos(x, y); + client->setJumpCursorPos(x, y); + + // tell primary client about the active sides + m_primaryClient->reconfigure(getActivePrimarySides()); + + return true; +} + +bool Server::removeClient(BaseClientProxy *client) { + // return false if not in list + ClientSet::iterator i = m_clientSet.find(client); + if (i == m_clientSet.end()) { + return false; + } + + // remove event handlers + m_events->removeHandler(m_events->forIScreen().shapeChanged(), + client->getEventTarget()); + m_events->removeHandler(m_events->forClipboard().clipboardGrabbed(), + client->getEventTarget()); + m_events->removeHandler(m_events->forClipboard().clipboardChanged(), + client->getEventTarget()); + + // remove from list + m_clients.erase(getName(client)); + m_clientSet.erase(i); + + return true; +} + +void Server::closeClient(BaseClientProxy *client, const char *msg) { + assert(client != m_primaryClient); + assert(msg != NULL); + + // send message to client. this message should cause the client + // to disconnect. we add this client to the closed client list + // and install a timer to remove the client if it doesn't respond + // quickly enough. we also remove the client from the active + // client list since we're not going to listen to it anymore. + // note that this method also works on clients that are not in + // the m_clients list. adoptClient() may call us with such a + // client. + LOG((CLOG_NOTE "disconnecting client \"%s\"", getName(client).c_str())); + + // send message + // FIXME -- avoid type cast (kinda hard, though) + ((ClientProxy *)client)->close(msg); + + // install timer. wait timeout seconds for client to close. + double timeout = 5.0; + EventQueueTimer *timer = m_events->newOneShotTimer(timeout, NULL); + m_events->adoptHandler(Event::kTimer, timer, + new TMethodEventJob( + this, &Server::handleClientCloseTimeout, client)); + + // move client to closing list + removeClient(client); + m_oldClients.insert(std::make_pair(client, timer)); + + // if this client is the active screen then we have to + // jump off of it + forceLeaveClient(client); +} + +void Server::closeClients(const Config &config) { + // collect the clients that are connected but are being dropped + // from the configuration (or who's canonical name is changing). + typedef std::set RemovedClients; + RemovedClients removed; + for (ClientList::iterator index = m_clients.begin(); index != m_clients.end(); + ++index) { + if (!config.isCanonicalName(index->first)) { + removed.insert(index->second); + } + } + + // don't close the primary client + removed.erase(m_primaryClient); + + // now close them. we collect the list then close in two steps + // because closeClient() modifies the collection we iterate over. + for (RemovedClients::iterator index = removed.begin(); index != removed.end(); + ++index) { + closeClient(*index, kMsgCClose); + } +} + +void Server::removeActiveClient(BaseClientProxy *client) { + if (removeClient(client)) { + forceLeaveClient(client); + m_events->removeHandler(m_events->forClientProxy().disconnected(), client); + if (m_clients.size() == 1 && m_oldClients.empty()) { + m_events->addEvent(Event(m_events->forServer().disconnected(), this)); + } + } +} + +void Server::removeOldClient(BaseClientProxy *client) { + OldClients::iterator i = m_oldClients.find(client); + if (i != m_oldClients.end()) { + m_events->removeHandler(m_events->forClientProxy().disconnected(), client); + m_events->removeHandler(Event::kTimer, i->second); + m_events->deleteTimer(i->second); + m_oldClients.erase(i); + if (m_clients.size() == 1 && m_oldClients.empty()) { + m_events->addEvent(Event(m_events->forServer().disconnected(), this)); + } + } +} + +void Server::forceLeaveClient(BaseClientProxy *client) { + BaseClientProxy *active = (m_activeSaver != NULL) ? m_activeSaver : m_active; + if (active == client) { + // record new position (center of primary screen) + m_primaryClient->getCursorCenter(m_x, m_y); + + // stop waiting to switch to this client + if (active == m_switchScreen) { + stopSwitch(); + } + + // don't notify active screen since it has probably already + // disconnected. + LOG((CLOG_INFO "jump from \"%s\" to \"%s\" at %d,%d", + getName(active).c_str(), getName(m_primaryClient).c_str(), m_x, m_y)); + + // cut over + m_active = m_primaryClient; + + // enter new screen (unless we already have because of the + // screen saver) + if (m_activeSaver == NULL) { + m_primaryClient->enter(m_x, m_y, m_seqNum, + m_primaryClient->getToggleMask(), false); + } + } + + // if this screen had the cursor when the screen saver activated + // then we can't switch back to it when the screen saver + // deactivates. + if (m_activeSaver == client) { + m_activeSaver = NULL; + } + + // tell primary client about the active sides + m_primaryClient->reconfigure(getActivePrimarySides()); +} // // Server::ClipboardInfo // -Server::ClipboardInfo::ClipboardInfo() : - m_clipboard(), - m_clipboardData(), - m_clipboardOwner(), - m_clipboardSeqNum(0) -{ - // do nothing +Server::ClipboardInfo::ClipboardInfo() + : m_clipboard(), m_clipboardData(), m_clipboardOwner(), + m_clipboardSeqNum(0) { + // do nothing } - // // Server::LockCursorToScreenInfo // -Server::LockCursorToScreenInfo* -Server::LockCursorToScreenInfo::alloc(State state) -{ - LockCursorToScreenInfo* info = - (LockCursorToScreenInfo*)malloc(sizeof(LockCursorToScreenInfo)); - info->m_state = state; - return info; +Server::LockCursorToScreenInfo * +Server::LockCursorToScreenInfo::alloc(State state) { + LockCursorToScreenInfo *info = + (LockCursorToScreenInfo *)malloc(sizeof(LockCursorToScreenInfo)); + info->m_state = state; + return info; } - // // Server::SwitchToScreenInfo // -Server::SwitchToScreenInfo* -Server::SwitchToScreenInfo::alloc(const String& screen) -{ - SwitchToScreenInfo* info = - (SwitchToScreenInfo*)malloc(sizeof(SwitchToScreenInfo) + - screen.size()); - strcpy(info->m_screen, screen.c_str()); // Compliant: we made sure the buffer is large enough - return info; +Server::SwitchToScreenInfo * +Server::SwitchToScreenInfo::alloc(const String &screen) { + SwitchToScreenInfo *info = + (SwitchToScreenInfo *)malloc(sizeof(SwitchToScreenInfo) + screen.size()); + strcpy(info->m_screen, + screen.c_str()); // Compliant: we made sure the buffer is large enough + return info; } - // // Server::SwitchInDirectionInfo // -Server::SwitchInDirectionInfo* -Server::SwitchInDirectionInfo::alloc(EDirection direction) -{ - SwitchInDirectionInfo* info = - (SwitchInDirectionInfo*)malloc(sizeof(SwitchInDirectionInfo)); - info->m_direction = direction; - return info; +Server::SwitchInDirectionInfo * +Server::SwitchInDirectionInfo::alloc(EDirection direction) { + SwitchInDirectionInfo *info = + (SwitchInDirectionInfo *)malloc(sizeof(SwitchInDirectionInfo)); + info->m_direction = direction; + return info; } // // Server::KeyboardBroadcastInfo // -Server::KeyboardBroadcastInfo* -Server::KeyboardBroadcastInfo::alloc(State state) -{ - KeyboardBroadcastInfo* info = - (KeyboardBroadcastInfo*)malloc(sizeof(KeyboardBroadcastInfo)); - info->m_state = state; - info->m_screens[0] = '\0'; - return info; +Server::KeyboardBroadcastInfo * +Server::KeyboardBroadcastInfo::alloc(State state) { + KeyboardBroadcastInfo *info = + (KeyboardBroadcastInfo *)malloc(sizeof(KeyboardBroadcastInfo)); + info->m_state = state; + info->m_screens[0] = '\0'; + return info; } -Server::KeyboardBroadcastInfo* -Server::KeyboardBroadcastInfo::alloc(State state, const String& screens) -{ - KeyboardBroadcastInfo* info = - (KeyboardBroadcastInfo*)malloc(sizeof(KeyboardBroadcastInfo) + - screens.size()); - info->m_state = state; - strcpy(info->m_screens, screens.c_str()); // Compliant: we made sure that screens variable ended with null - return info; +Server::KeyboardBroadcastInfo * +Server::KeyboardBroadcastInfo::alloc(State state, const String &screens) { + KeyboardBroadcastInfo *info = (KeyboardBroadcastInfo *)malloc( + sizeof(KeyboardBroadcastInfo) + screens.size()); + info->m_state = state; + strcpy(info->m_screens, screens.c_str()); // Compliant: we made sure that + // screens variable ended with null + return info; } -bool -Server::isReceivedFileSizeValid() -{ - return m_expectedFileSize == m_receivedFileData.size(); +bool Server::isReceivedFileSizeValid() { + return m_expectedFileSize == m_receivedFileData.size(); } -bool Server::isClientMode() const -{ - return m_args.m_config->isClientMode(); +bool Server::isClientMode() const { return m_args.m_config->isClientMode(); } + +void Server::sendFileToClient(const char *filename) { + if (m_sendFileThread != NULL) { + StreamChunker::interruptFile(); + } + + auto data = static_cast(const_cast(filename)); + auto method = new TMethodJob(this, &Server::sendFileThread, data); + m_sendFileThread.reset(new Thread(method)); } -void -Server::sendFileToClient(const char* filename) -{ - if (m_sendFileThread != NULL) { - StreamChunker::interruptFile(); - } +void Server::sendFileThread(void *data) { + try { + char *filename = static_cast(data); + LOG((CLOG_DEBUG "sending file to client, filename=%s", filename)); + StreamChunker::sendFile(filename, m_events, this); + } catch (std::runtime_error &error) { + LOG((CLOG_ERR "failed sending file chunks, error: %s", error.what())); + } - auto data = static_cast(const_cast(filename)); - auto method = new TMethodJob(this, &Server::sendFileThread, data); - m_sendFileThread.reset(new Thread(method)); + m_sendFileThread.reset(nullptr); } -void -Server::sendFileThread(void* data) -{ - try { - char* filename = static_cast(data); - LOG((CLOG_DEBUG "sending file to client, filename=%s", filename)); - StreamChunker::sendFile(filename, m_events, this); - } - catch (std::runtime_error &error) { - LOG((CLOG_ERR "failed sending file chunks, error: %s", error.what())); - } +void Server::dragInfoReceived(UInt32 fileNum, String content) { + if (!m_args.m_enableDragDrop) { + LOG((CLOG_DEBUG "drag drop not enabled, ignoring drag info.")); + return; + } - m_sendFileThread.reset(nullptr); -} - -void -Server::dragInfoReceived(UInt32 fileNum, String content) -{ - if (!m_args.m_enableDragDrop) { - LOG((CLOG_DEBUG "drag drop not enabled, ignoring drag info.")); - return; - } - - DragInformation::parseDragInfo(m_fakeDragFileList, fileNum, content); - - m_screen->startDraggingFiles(m_fakeDragFileList); + DragInformation::parseDragInfo(m_fakeDragFileList, fileNum, content); + + m_screen->startDraggingFiles(m_fakeDragFileList); } diff --git a/src/lib/server/Server.h b/src/lib/server/Server.h index baa16f65d..20852af78 100644 --- a/src/lib/server/Server.h +++ b/src/lib/server/Server.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -18,28 +18,30 @@ #pragma once -#include "server/Config.h" -#include "synergy/clipboard_types.h" -#include "synergy/Clipboard.h" -#include "synergy/key_types.h" -#include "synergy/mouse_types.h" -#include "synergy/INode.h" -#include "synergy/DragInformation.h" -#include "synergy/ServerArgs.h" -#include "synergy/languages/LanguageManager.h" #include "base/Event.h" -#include "base/Stopwatch.h" #include "base/EventTypes.h" +#include "base/Stopwatch.h" #include "common/stdmap.h" #include "common/stdset.h" #include "common/stdvector.h" +#include "server/Config.h" +#include "synergy/Clipboard.h" +#include "synergy/DragInformation.h" +#include "synergy/INode.h" +#include "synergy/ServerArgs.h" +#include "synergy/clipboard_types.h" +#include "synergy/key_types.h" +#include "synergy/languages/LanguageManager.h" +#include "synergy/mouse_types.h" #include class BaseClientProxy; class EventQueueTimer; class PrimaryClient; class InputFilter; -namespace synergy { class Screen; } +namespace synergy { +class Screen; +} class IEventQueue; class Thread; class ClientListener; @@ -50,447 +52,441 @@ This class implements the top-level server algorithms for synergy. */ class Server : public INode { public: - //! Lock cursor to screen data - class LockCursorToScreenInfo { - public: - enum State { kOff, kOn, kToggle }; + //! Lock cursor to screen data + class LockCursorToScreenInfo { + public: + enum State { kOff, kOn, kToggle }; - static LockCursorToScreenInfo* alloc(State state = kToggle); + static LockCursorToScreenInfo *alloc(State state = kToggle); - public: - State m_state; - }; + public: + State m_state; + }; - //! Switch to screen data - class SwitchToScreenInfo { - public: - static SwitchToScreenInfo* alloc(const String& screen); + //! Switch to screen data + class SwitchToScreenInfo { + public: + static SwitchToScreenInfo *alloc(const String &screen); - public: - // this is a C-string; this type is a variable size structure - char m_screen[1]; - }; + public: + // this is a C-string; this type is a variable size structure + char m_screen[1]; + }; - //! Switch in direction data - class SwitchInDirectionInfo { - public: - static SwitchInDirectionInfo* alloc(EDirection direction); + //! Switch in direction data + class SwitchInDirectionInfo { + public: + static SwitchInDirectionInfo *alloc(EDirection direction); - public: - EDirection m_direction; - }; + public: + EDirection m_direction; + }; - //! Screen connected data - class ScreenConnectedInfo { - public: - ScreenConnectedInfo(String screen) : m_screen(screen) { } + //! Screen connected data + class ScreenConnectedInfo { + public: + ScreenConnectedInfo(String screen) : m_screen(screen) {} - public: - String m_screen; // was char[1] - }; + public: + String m_screen; // was char[1] + }; - //! Keyboard broadcast data - class KeyboardBroadcastInfo { - public: - enum State { kOff, kOn, kToggle }; + //! Keyboard broadcast data + class KeyboardBroadcastInfo { + public: + enum State { kOff, kOn, kToggle }; - static KeyboardBroadcastInfo* alloc(State state = kToggle); - static KeyboardBroadcastInfo* alloc(State state, - const String& screens); + static KeyboardBroadcastInfo *alloc(State state = kToggle); + static KeyboardBroadcastInfo *alloc(State state, const String &screens); - public: - State m_state; - char m_screens[1]; - }; + public: + State m_state; + char m_screens[1]; + }; - /*! - Start the server with the configuration \p config and the primary - client (local screen) \p primaryClient. The client retains - ownership of \p primaryClient. - */ - Server(Config& config, PrimaryClient* primaryClient, - synergy::Screen* screen, IEventQueue* events, lib::synergy::ServerArgs const& args); - Server(Server const &) =delete; - Server(Server &&) =delete; - ~Server(); + /*! + Start the server with the configuration \p config and the primary + client (local screen) \p primaryClient. The client retains + ownership of \p primaryClient. + */ + Server(Config &config, PrimaryClient *primaryClient, synergy::Screen *screen, + IEventQueue *events, lib::synergy::ServerArgs const &args); + Server(Server const &) = delete; + Server(Server &&) = delete; + ~Server(); - Server& operator=(Server const &) =delete; - Server& operator=(Server &&) =delete; + Server &operator=(Server const &) = delete; + Server &operator=(Server &&) = delete; #ifdef TEST_ENV - Server() : m_mock(true), m_config(NULL) { } - void setActive(BaseClientProxy* active) { m_active = active; } + Server() : m_mock(true), m_config(NULL) {} + void setActive(BaseClientProxy *active) { m_active = active; } #endif - //! @name manipulators - //@{ + //! @name manipulators + //@{ - //! Set configuration - /*! - Change the server's configuration. Returns true iff the new - configuration was accepted (it must include the server's name). - This will disconnect any clients no longer in the configuration. - */ - bool setConfig(const Config&); + //! Set configuration + /*! + Change the server's configuration. Returns true iff the new + configuration was accepted (it must include the server's name). + This will disconnect any clients no longer in the configuration. + */ + bool setConfig(const Config &); - //! Add a client - /*! - Adds \p client to the server. The client is adopted and will be - destroyed when the client disconnects or is disconnected. - */ - void adoptClient(BaseClientProxy* client); + //! Add a client + /*! + Adds \p client to the server. The client is adopted and will be + destroyed when the client disconnects or is disconnected. + */ + void adoptClient(BaseClientProxy *client); - //! Disconnect clients - /*! - Disconnect clients. This tells them to disconnect but does not wait - for them to actually do so. The server sends the disconnected event - when they're all disconnected (or immediately if none are connected). - The caller can also just destroy this object to force the disconnection. - */ - void disconnect(); + //! Disconnect clients + /*! + Disconnect clients. This tells them to disconnect but does not wait + for them to actually do so. The server sends the disconnected event + when they're all disconnected (or immediately if none are connected). + The caller can also just destroy this object to force the disconnection. + */ + void disconnect(); - //! Create a new thread and use it to send file to client - void sendFileToClient(const char* filename); + //! Create a new thread and use it to send file to client + void sendFileToClient(const char *filename); - //! Received dragging information from client - void dragInfoReceived(UInt32 fileNum, String content); + //! Received dragging information from client + void dragInfoReceived(UInt32 fileNum, String content); - //! Store ClientListener pointer - void setListener(ClientListener* p) { m_clientListener = p; } + //! Store ClientListener pointer + void setListener(ClientListener *p) { m_clientListener = p; } - //@} - //! @name accessors - //@{ + //@} + //! @name accessors + //@{ - //! Get number of connected clients - /*! - Returns the number of connected clients, including the server itself. - */ - UInt32 getNumClients() const; + //! Get number of connected clients + /*! + Returns the number of connected clients, including the server itself. + */ + UInt32 getNumClients() const; - //! Get the list of connected clients - /*! - Set the \c list to the names of the currently connected clients. - */ - void getClients(std::vector& list) const; - - //! Return true if recieved file size is valid - bool isReceivedFileSizeValid(); + //! Get the list of connected clients + /*! + Set the \c list to the names of the currently connected clients. + */ + void getClients(std::vector &list) const; - //! Return expected file data size - size_t& getExpectedFileSize() { return m_expectedFileSize; } + //! Return true if recieved file size is valid + bool isReceivedFileSizeValid(); - //! Return received file data - String& getReceivedFileData() { return m_receivedFileData; } + //! Return expected file data size + size_t &getExpectedFileSize() { return m_expectedFileSize; } - //! Return fake drag file list - DragFileList getFakeDragFileList() { return m_fakeDragFileList; } + //! Return received file data + String &getReceivedFileData() { return m_receivedFileData; } - //! Returns true if it's client mode and server initiates connection - bool isClientMode() const; + //! Return fake drag file list + DragFileList getFakeDragFileList() { return m_fakeDragFileList; } - //@} + //! Returns true if it's client mode and server initiates connection + bool isClientMode() const; + + //@} private: - // get canonical name of client - String getName(const BaseClientProxy*) const; + // get canonical name of client + String getName(const BaseClientProxy *) const; - // get the sides of the primary screen that have neighbors - UInt32 getActivePrimarySides() const; + // get the sides of the primary screen that have neighbors + UInt32 getActivePrimarySides() const; - // returns true iff mouse should be locked to the current screen - // according to this object only, ignoring what the primary client - // says. - bool isLockedToScreenServer() const; + // returns true iff mouse should be locked to the current screen + // according to this object only, ignoring what the primary client + // says. + bool isLockedToScreenServer() const; - // returns true iff mouse should be locked to the current screen - // according to this object or the primary client. - bool isLockedToScreen() const; + // returns true iff mouse should be locked to the current screen + // according to this object or the primary client. + bool isLockedToScreen() const; - // returns the jump zone of the client - SInt32 getJumpZoneSize(BaseClientProxy*) const; + // returns the jump zone of the client + SInt32 getJumpZoneSize(BaseClientProxy *) const; - // change the active screen - void switchScreen(BaseClientProxy*, - SInt32 x, SInt32 y, bool forScreenSaver); + // change the active screen + void switchScreen(BaseClientProxy *, SInt32 x, SInt32 y, bool forScreenSaver); - // jump to screen - void jumpToScreen(BaseClientProxy*); + // jump to screen + void jumpToScreen(BaseClientProxy *); - // convert pixel position to fraction, using x or y depending on the - // direction. - float mapToFraction(BaseClientProxy*, EDirection, - SInt32 x, SInt32 y) const; + // convert pixel position to fraction, using x or y depending on the + // direction. + float mapToFraction(BaseClientProxy *, EDirection, SInt32 x, SInt32 y) const; - // convert fraction to pixel position, writing only x or y depending - // on the direction. - void mapToPixel(BaseClientProxy*, EDirection, float f, - SInt32& x, SInt32& y) const; + // convert fraction to pixel position, writing only x or y depending + // on the direction. + void mapToPixel(BaseClientProxy *, EDirection, float f, SInt32 &x, + SInt32 &y) const; - // returns true if the client has a neighbor anywhere along the edge - // indicated by the direction. - bool hasAnyNeighbor(BaseClientProxy*, EDirection) const; + // returns true if the client has a neighbor anywhere along the edge + // indicated by the direction. + bool hasAnyNeighbor(BaseClientProxy *, EDirection) const; - // lookup neighboring screen, mapping the coordinate independent of - // the direction to the neighbor's coordinate space. - BaseClientProxy* getNeighbor(BaseClientProxy*, EDirection, - SInt32& x, SInt32& y) const; + // lookup neighboring screen, mapping the coordinate independent of + // the direction to the neighbor's coordinate space. + BaseClientProxy *getNeighbor(BaseClientProxy *, EDirection, SInt32 &x, + SInt32 &y) const; - // lookup neighboring screen. given a position relative to the - // source screen, find the screen we should move onto and where. - // if the position is sufficiently far from the source then we - // cross multiple screens. if there is no suitable screen then - // return NULL and x,y are not modified. - BaseClientProxy* mapToNeighbor(BaseClientProxy*, EDirection, - SInt32& x, SInt32& y) const; + // lookup neighboring screen. given a position relative to the + // source screen, find the screen we should move onto and where. + // if the position is sufficiently far from the source then we + // cross multiple screens. if there is no suitable screen then + // return NULL and x,y are not modified. + BaseClientProxy *mapToNeighbor(BaseClientProxy *, EDirection, SInt32 &x, + SInt32 &y) const; - // adjusts x and y or neither to avoid ending up in a jump zone - // after entering the client in the given direction. - void avoidJumpZone(BaseClientProxy*, EDirection, - SInt32& x, SInt32& y) const; + // adjusts x and y or neither to avoid ending up in a jump zone + // after entering the client in the given direction. + void avoidJumpZone(BaseClientProxy *, EDirection, SInt32 &x, SInt32 &y) const; - // test if a switch is permitted. this includes testing user - // options like switch delay and tracking any state required to - // implement them. returns true iff a switch is permitted. - bool isSwitchOkay(BaseClientProxy* dst, EDirection, - SInt32 x, SInt32 y, SInt32 xActive, SInt32 yActive); + // test if a switch is permitted. this includes testing user + // options like switch delay and tracking any state required to + // implement them. returns true iff a switch is permitted. + bool isSwitchOkay(BaseClientProxy *dst, EDirection, SInt32 x, SInt32 y, + SInt32 xActive, SInt32 yActive); - // update switch state due to a mouse move at \p x, \p y that - // doesn't switch screens. - void noSwitch(SInt32 x, SInt32 y); + // update switch state due to a mouse move at \p x, \p y that + // doesn't switch screens. + void noSwitch(SInt32 x, SInt32 y); - // stop switch timers - void stopSwitch(); + // stop switch timers + void stopSwitch(); - // start two tap switch timer - void startSwitchTwoTap(); + // start two tap switch timer + void startSwitchTwoTap(); - // arm the two tap switch timer if \p x, \p y is outside the tap zone - void armSwitchTwoTap(SInt32 x, SInt32 y); + // arm the two tap switch timer if \p x, \p y is outside the tap zone + void armSwitchTwoTap(SInt32 x, SInt32 y); - // stop the two tap switch timer - void stopSwitchTwoTap(); + // stop the two tap switch timer + void stopSwitchTwoTap(); - // returns true iff the two tap switch timer is started - bool isSwitchTwoTapStarted() const; + // returns true iff the two tap switch timer is started + bool isSwitchTwoTapStarted() const; - // returns true iff should switch because of two tap - bool shouldSwitchTwoTap() const; + // returns true iff should switch because of two tap + bool shouldSwitchTwoTap() const; - // start delay switch timer - void startSwitchWait(SInt32 x, SInt32 y); + // start delay switch timer + void startSwitchWait(SInt32 x, SInt32 y); - // stop delay switch timer - void stopSwitchWait(); + // stop delay switch timer + void stopSwitchWait(); - // returns true iff the delay switch timer is started - bool isSwitchWaitStarted() const; + // returns true iff the delay switch timer is started + bool isSwitchWaitStarted() const; - // returns the corner (EScreenSwitchCornerMasks) where x,y is on the - // given client. corners have the given size. - UInt32 getCorner(BaseClientProxy*, - SInt32 x, SInt32 y, SInt32 size) const; + // returns the corner (EScreenSwitchCornerMasks) where x,y is on the + // given client. corners have the given size. + UInt32 getCorner(BaseClientProxy *, SInt32 x, SInt32 y, SInt32 size) const; - // stop relative mouse moves - void stopRelativeMoves(); + // stop relative mouse moves + void stopRelativeMoves(); - // send screen options to \c client - void sendOptions(BaseClientProxy* client) const; + // send screen options to \c client + void sendOptions(BaseClientProxy *client) const; - // process options from configuration - void processOptions(); + // process options from configuration + void processOptions(); - // event handlers - void handleShapeChanged(const Event&, void*); - void handleClipboardGrabbed(const Event&, void*); - void handleClipboardChanged(const Event&, void*); - void handleKeyDownEvent(const Event&, void*); - void handleKeyUpEvent(const Event&, void*); - void handleKeyRepeatEvent(const Event&, void*); - void handleButtonDownEvent(const Event&, void*); - void handleButtonUpEvent(const Event&, void*); - void handleMotionPrimaryEvent(const Event&, void*); - void handleMotionSecondaryEvent(const Event&, void*); - void handleWheelEvent(const Event&, void*); - void handleScreensaverActivatedEvent(const Event&, void*); - void handleScreensaverDeactivatedEvent(const Event&, void*); - void handleSwitchWaitTimeout(const Event&, void*); - void handleClientDisconnected(const Event&, void*); - void handleClientCloseTimeout(const Event&, void*); - void handleSwitchToScreenEvent(const Event&, void*); - void handleSwitchInDirectionEvent(const Event&, void*); - void handleKeyboardBroadcastEvent(const Event&,void*); - void handleLockCursorToScreenEvent(const Event&, void*); - void handleFakeInputBeginEvent(const Event&, void*); - void handleFakeInputEndEvent(const Event&, void*); - void handleFileChunkSendingEvent(const Event&, void*); - void handleFileRecieveCompletedEvent(const Event&, void*); + // event handlers + void handleShapeChanged(const Event &, void *); + void handleClipboardGrabbed(const Event &, void *); + void handleClipboardChanged(const Event &, void *); + void handleKeyDownEvent(const Event &, void *); + void handleKeyUpEvent(const Event &, void *); + void handleKeyRepeatEvent(const Event &, void *); + void handleButtonDownEvent(const Event &, void *); + void handleButtonUpEvent(const Event &, void *); + void handleMotionPrimaryEvent(const Event &, void *); + void handleMotionSecondaryEvent(const Event &, void *); + void handleWheelEvent(const Event &, void *); + void handleScreensaverActivatedEvent(const Event &, void *); + void handleScreensaverDeactivatedEvent(const Event &, void *); + void handleSwitchWaitTimeout(const Event &, void *); + void handleClientDisconnected(const Event &, void *); + void handleClientCloseTimeout(const Event &, void *); + void handleSwitchToScreenEvent(const Event &, void *); + void handleSwitchInDirectionEvent(const Event &, void *); + void handleKeyboardBroadcastEvent(const Event &, void *); + void handleLockCursorToScreenEvent(const Event &, void *); + void handleFakeInputBeginEvent(const Event &, void *); + void handleFakeInputEndEvent(const Event &, void *); + void handleFileChunkSendingEvent(const Event &, void *); + void handleFileRecieveCompletedEvent(const Event &, void *); - // event processing - void onClipboardChanged(BaseClientProxy* sender, - ClipboardID id, UInt32 seqNum); - void onScreensaver(bool activated); - void onKeyDown(KeyID, KeyModifierMask, KeyButton, const String&, - const char* screens); - void onKeyUp(KeyID, KeyModifierMask, KeyButton, - const char* screens); - void onKeyRepeat(KeyID, KeyModifierMask, SInt32, KeyButton, const String&); - void onMouseDown(ButtonID); - void onMouseUp(ButtonID); - bool onMouseMovePrimary(SInt32 x, SInt32 y); - void onMouseMoveSecondary(SInt32 dx, SInt32 dy); - void onMouseWheel(SInt32 xDelta, SInt32 yDelta); - void onFileChunkSending(const void* data); - void onFileRecieveCompleted(); + // event processing + void onClipboardChanged(BaseClientProxy *sender, ClipboardID id, + UInt32 seqNum); + void onScreensaver(bool activated); + void onKeyDown(KeyID, KeyModifierMask, KeyButton, const String &, + const char *screens); + void onKeyUp(KeyID, KeyModifierMask, KeyButton, const char *screens); + void onKeyRepeat(KeyID, KeyModifierMask, SInt32, KeyButton, const String &); + void onMouseDown(ButtonID); + void onMouseUp(ButtonID); + bool onMouseMovePrimary(SInt32 x, SInt32 y); + void onMouseMoveSecondary(SInt32 dx, SInt32 dy); + void onMouseWheel(SInt32 xDelta, SInt32 yDelta); + void onFileChunkSending(const void *data); + void onFileRecieveCompleted(); - // add client to list and attach event handlers for client - bool addClient(BaseClientProxy*); + // add client to list and attach event handlers for client + bool addClient(BaseClientProxy *); - // remove client from list and detach event handlers for client - bool removeClient(BaseClientProxy*); + // remove client from list and detach event handlers for client + bool removeClient(BaseClientProxy *); - // close a client - void closeClient(BaseClientProxy*, const char* msg); + // close a client + void closeClient(BaseClientProxy *, const char *msg); - // close clients not in \p config - void closeClients(const Config& config); + // close clients not in \p config + void closeClients(const Config &config); - // close all clients whether they've completed the handshake or not, - // except the primary client - void closeAllClients(); + // close all clients whether they've completed the handshake or not, + // except the primary client + void closeAllClients(); - // remove clients from internal state - void removeActiveClient(BaseClientProxy*); - void removeOldClient(BaseClientProxy*); + // remove clients from internal state + void removeActiveClient(BaseClientProxy *); + void removeOldClient(BaseClientProxy *); - // force the cursor off of \p client - void forceLeaveClient(BaseClientProxy* client); - - // thread funciton for sending file - void sendFileThread(void*); - - // thread function for writing file to drop directory - void writeToDropDirThread(void*); + // force the cursor off of \p client + void forceLeaveClient(BaseClientProxy *client); - // thread function for sending drag information - void sendDragInfoThread(void*); + // thread funciton for sending file + void sendFileThread(void *); - // send drag info to new client screen - void sendDragInfo(BaseClientProxy* newScreen); + // thread function for writing file to drop directory + void writeToDropDirThread(void *); + + // thread function for sending drag information + void sendDragInfoThread(void *); + + // send drag info to new client screen + void sendDragInfo(BaseClientProxy *newScreen); public: - bool m_mock; + bool m_mock; private: - class ClipboardInfo { - public: - ClipboardInfo(); + class ClipboardInfo { + public: + ClipboardInfo(); - public: - Clipboard m_clipboard; - String m_clipboardData; - String m_clipboardOwner; - UInt32 m_clipboardSeqNum; - }; + public: + Clipboard m_clipboard; + String m_clipboardData; + String m_clipboardOwner; + UInt32 m_clipboardSeqNum; + }; - // the primary screen client - PrimaryClient* m_primaryClient; + // the primary screen client + PrimaryClient *m_primaryClient; - // all clients (including the primary client) indexed by name - typedef std::map ClientList; - typedef std::set ClientSet; - ClientList m_clients; - ClientSet m_clientSet; + // all clients (including the primary client) indexed by name + typedef std::map ClientList; + typedef std::set ClientSet; + ClientList m_clients; + ClientSet m_clientSet; - // all old connections that we're waiting to hangup - typedef std::map OldClients; - OldClients m_oldClients; + // all old connections that we're waiting to hangup + typedef std::map OldClients; + OldClients m_oldClients; - // the client with focus - BaseClientProxy* m_active; + // the client with focus + BaseClientProxy *m_active; - // the sequence number of enter messages - UInt32 m_seqNum; + // the sequence number of enter messages + UInt32 m_seqNum; - // current mouse position (in absolute screen coordinates) on - // whichever screen is active - SInt32 m_x, m_y; + // current mouse position (in absolute screen coordinates) on + // whichever screen is active + SInt32 m_x, m_y; - // last mouse deltas. this is needed to smooth out double tap - // on win32 which reports bogus mouse motion at the edge of - // the screen when using low level hooks, synthesizing motion - // in the opposite direction the mouse actually moved. - SInt32 m_xDelta, m_yDelta; - SInt32 m_xDelta2, m_yDelta2; + // last mouse deltas. this is needed to smooth out double tap + // on win32 which reports bogus mouse motion at the edge of + // the screen when using low level hooks, synthesizing motion + // in the opposite direction the mouse actually moved. + SInt32 m_xDelta, m_yDelta; + SInt32 m_xDelta2, m_yDelta2; - // current configuration - Config* m_config; + // current configuration + Config *m_config; - // input filter (from m_config); - InputFilter* m_inputFilter; + // input filter (from m_config); + InputFilter *m_inputFilter; - // clipboard cache - ClipboardInfo m_clipboards[kClipboardEnd]; + // clipboard cache + ClipboardInfo m_clipboards[kClipboardEnd]; - // state saved when screen saver activates - BaseClientProxy* m_activeSaver; - SInt32 m_xSaver, m_ySaver; + // state saved when screen saver activates + BaseClientProxy *m_activeSaver; + SInt32 m_xSaver, m_ySaver; - // common state for screen switch tests. all tests are always - // trying to reach the same screen in the same direction. - EDirection m_switchDir; - BaseClientProxy* m_switchScreen; + // common state for screen switch tests. all tests are always + // trying to reach the same screen in the same direction. + EDirection m_switchDir; + BaseClientProxy *m_switchScreen; - // state for delayed screen switching - double m_switchWaitDelay; - EventQueueTimer* m_switchWaitTimer; - SInt32 m_switchWaitX, m_switchWaitY; + // state for delayed screen switching + double m_switchWaitDelay; + EventQueueTimer *m_switchWaitTimer; + SInt32 m_switchWaitX, m_switchWaitY; - // state for double-tap screen switching - double m_switchTwoTapDelay; - Stopwatch m_switchTwoTapTimer; - bool m_switchTwoTapEngaged; - bool m_switchTwoTapArmed; - SInt32 m_switchTwoTapZone; + // state for double-tap screen switching + double m_switchTwoTapDelay; + Stopwatch m_switchTwoTapTimer; + bool m_switchTwoTapEngaged; + bool m_switchTwoTapArmed; + SInt32 m_switchTwoTapZone; - // modifiers needed before switching - bool m_switchNeedsShift; - bool m_switchNeedsControl; - bool m_switchNeedsAlt; - - // relative mouse move option - bool m_relativeMoves; + // modifiers needed before switching + bool m_switchNeedsShift; + bool m_switchNeedsControl; + bool m_switchNeedsAlt; - // flag whether or not we have broadcasting enabled and the screens to - // which we should send broadcasted keys. - bool m_keyboardBroadcasting; - String m_keyboardBroadcastingScreens; + // relative mouse move option + bool m_relativeMoves; - // screen locking (former scroll lock) - bool m_lockedToScreen; + // flag whether or not we have broadcasting enabled and the screens to + // which we should send broadcasted keys. + bool m_keyboardBroadcasting; + String m_keyboardBroadcastingScreens; - // server screen - synergy::Screen* m_screen; + // screen locking (former scroll lock) + bool m_lockedToScreen; - IEventQueue* m_events; + // server screen + synergy::Screen *m_screen; - // file transfer - using AutoThread = std::unique_ptr; - size_t m_expectedFileSize; - String m_receivedFileData; - DragFileList m_dragFileList; - DragFileList m_fakeDragFileList; - AutoThread m_sendFileThread; - AutoThread m_writeToDropDirThread; - String m_dragFileExt; - bool m_ignoreFileTransfer; - bool m_disableLockToScreen; - bool m_enableClipboard; - size_t m_maximumClipboardSize; + IEventQueue *m_events; - AutoThread m_sendDragInfoThread; - bool m_waitDragInfoThread; + // file transfer + using AutoThread = std::unique_ptr; + size_t m_expectedFileSize; + String m_receivedFileData; + DragFileList m_dragFileList; + DragFileList m_fakeDragFileList; + AutoThread m_sendFileThread; + AutoThread m_writeToDropDirThread; + String m_dragFileExt; + bool m_ignoreFileTransfer; + bool m_disableLockToScreen; + bool m_enableClipboard; + size_t m_maximumClipboardSize; - ClientListener* m_clientListener; - lib::synergy::ServerArgs m_args; + AutoThread m_sendDragInfoThread; + bool m_waitDragInfoThread; + + ClientListener *m_clientListener; + lib::synergy::ServerArgs m_args; }; diff --git a/src/lib/shared/EditionType.h b/src/lib/shared/EditionType.h index 095a73d8f..859a9c151 100644 --- a/src/lib/shared/EditionType.h +++ b/src/lib/shared/EditionType.h @@ -21,15 +21,15 @@ /* Do not reorder these! */ enum Edition { - kBasic, - kPro, - Trial_DO_NOT_USE_OR_THERE_WILL_BE_PAIN, - kUnregistered, - kBusiness, - kBasic_China, - kPro_China, - kLite, - kUltimate + kBasic, + kPro, + Trial_DO_NOT_USE_OR_THERE_WILL_BE_PAIN, + kUnregistered, + kBusiness, + kBasic_China, + kPro_China, + kLite, + kUltimate }; #endif // EDITIONTYPE_H diff --git a/src/lib/shared/SerialKey.cpp b/src/lib/shared/SerialKey.cpp index 47e50c062..9017936ca 100644 --- a/src/lib/shared/SerialKey.cpp +++ b/src/lib/shared/SerialKey.cpp @@ -17,141 +17,107 @@ #include "SerialKey.h" -#include -#include -#include #include "SerialKeyEdition.h" #include "SerialKeyParser.h" +#include +#include +#include -SerialKey::SerialKey(Edition edition): - m_data(edition) -{ +SerialKey::SerialKey(Edition edition) : m_data(edition) {} + +SerialKey::SerialKey(const std::string &serial) : m_data(serial) { + SerialKeyParser parser; + + if (parser.parse(serial)) { + m_data = parser.getData(); + } else { + throw std::runtime_error("Invalid serial key"); + } } -SerialKey::SerialKey(const std::string& serial) : - m_data(serial) -{ - SerialKeyParser parser; +bool SerialKey::isExpiring(time_t currentTime) const { + bool result = false; - if (parser.parse(serial)) { - m_data = parser.getData(); + if (isTemporary()) { + unsigned long long currentTimeAsLL = + static_cast(currentTime); + if ((m_data.warnTime <= currentTimeAsLL) && + (currentTimeAsLL < m_data.expireTime)) { + result = true; } - else { - throw std::runtime_error ("Invalid serial key"); + } + + return result; +} + +bool SerialKey::isExpired(time_t currentTime) const { + bool result = false; + + if (isTemporary()) { + unsigned long long currentTimeAsLL = + static_cast(currentTime); + if (m_data.expireTime <= currentTimeAsLL) { + result = true; } + } + + return result; } -bool -SerialKey::isExpiring(time_t currentTime) const -{ - bool result = false; +bool SerialKey::isTrial() const { return m_data.keyType.isTrial(); } - if (isTemporary()) { - unsigned long long currentTimeAsLL = static_cast(currentTime); - if ((m_data.warnTime <= currentTimeAsLL) && (currentTimeAsLL < m_data.expireTime)) { - result = true; - } +bool SerialKey::isTemporary() const { + return (m_data.keyType.isTemporary() && !m_data.edition.isChina()); +} + +bool SerialKey::isMaintenance() const { + return (m_data.keyType.isMaintenance() || m_data.edition.isChina()); +} + +bool SerialKey::isValid() const { + bool Valid = true; + + if (!m_data.edition.isValid() || isExpired(::time(nullptr))) { + Valid = false; + } + + return Valid; +} + +Edition SerialKey::edition() const { return m_data.edition.getType(); } + +const std::string &SerialKey::toString() const { return m_data.key; } + +time_t SerialKey::daysLeft(time_t currentTime) const { + unsigned long long timeLeft = 0; + unsigned long long const day = 60 * 60 * 24; + + unsigned long long currentTimeAsLL = + static_cast(currentTime); + if (currentTimeAsLL < m_data.expireTime) { + timeLeft = m_data.expireTime - currentTimeAsLL; + } + + unsigned long long daysLeft = 0; + daysLeft = timeLeft % day != 0 ? 1 : 0; + + return timeLeft / day + daysLeft; +} + +time_t SerialKey::getExpiration() const { return m_data.expireTime; } + +int SerialKey::getSpanLeft(time_t time) const { + int result{-1}; + + if (isTemporary() && !isExpired(time)) { + auto timeLeft = (m_data.expireTime - time) * 1000; + + if (timeLeft < INT_MAX) { + result = static_cast(timeLeft); + } else { + result = INT_MAX; } + } - return result; -} - -bool -SerialKey::isExpired(time_t currentTime) const -{ - bool result = false; - - if (isTemporary()) { - unsigned long long currentTimeAsLL = static_cast(currentTime); - if (m_data.expireTime <= currentTimeAsLL) { - result = true; - } - } - - return result; -} - -bool -SerialKey::isTrial() const -{ - return m_data.keyType.isTrial(); -} - -bool -SerialKey::isTemporary() const -{ - return (m_data.keyType.isTemporary() && !m_data.edition.isChina()); -} - -bool -SerialKey::isMaintenance() const -{ - return (m_data.keyType.isMaintenance() || m_data.edition.isChina()); -} - -bool -SerialKey::isValid() const -{ - bool Valid = true; - - if (!m_data.edition.isValid() || isExpired(::time(nullptr))) - { - Valid = false; - } - - return Valid; -} - -Edition -SerialKey::edition() const -{ - return m_data.edition.getType(); -} - -const std::string& -SerialKey::toString() const -{ - return m_data.key; -} - -time_t -SerialKey::daysLeft(time_t currentTime) const -{ - unsigned long long timeLeft = 0; - unsigned long long const day = 60 * 60 * 24; - - unsigned long long currentTimeAsLL = static_cast(currentTime); - if (currentTimeAsLL < m_data.expireTime) { - timeLeft = m_data.expireTime - currentTimeAsLL; - } - - unsigned long long daysLeft = 0; - daysLeft = timeLeft % day != 0 ? 1 : 0; - - return timeLeft / day + daysLeft; -} - -time_t -SerialKey::getExpiration() const -{ - return m_data.expireTime; -} - -int -SerialKey::getSpanLeft(time_t time) const -{ - int result{-1}; - - if (isTemporary() && !isExpired(time)){ - auto timeLeft = (m_data.expireTime - time) * 1000; - - if (timeLeft < INT_MAX){ - result = static_cast(timeLeft); - } - else{ - result = INT_MAX; - } - } - - return result; + return result; } diff --git a/src/lib/shared/SerialKey.h b/src/lib/shared/SerialKey.h index f3f10d05b..f43d58cb5 100644 --- a/src/lib/shared/SerialKey.h +++ b/src/lib/shared/SerialKey.h @@ -17,41 +17,38 @@ #pragma once -#include -#include #include "SerialKeyData.h" #include "SerialKeyEdition.h" +#include +#include class SerialKey { - friend bool operator== (SerialKey const&, SerialKey const&); -public: - explicit SerialKey(Edition edition = kUnregistered); - explicit SerialKey(const std::string& serial); + friend bool operator==(SerialKey const &, SerialKey const &); - bool isExpiring(time_t currentTime) const; - bool isExpired(time_t currentTime) const; - bool isTrial() const; - bool isTemporary() const; - bool isMaintenance() const; - bool isValid() const; - time_t daysLeft(time_t currentTime) const; - time_t getExpiration() const; - int getSpanLeft(time_t time = ::time(0)) const; - Edition edition() const; - const std::string& toString() const; +public: + explicit SerialKey(Edition edition = kUnregistered); + explicit SerialKey(const std::string &serial); + + bool isExpiring(time_t currentTime) const; + bool isExpired(time_t currentTime) const; + bool isTrial() const; + bool isTemporary() const; + bool isMaintenance() const; + bool isValid() const; + time_t daysLeft(time_t currentTime) const; + time_t getExpiration() const; + int getSpanLeft(time_t time = ::time(0)) const; + Edition edition() const; + const std::string &toString() const; private: - SerialKeyData m_data; - + SerialKeyData m_data; }; - -inline bool -operator== (SerialKey const& lhs, SerialKey const& rhs) { - return (lhs.m_data == rhs.m_data); +inline bool operator==(SerialKey const &lhs, SerialKey const &rhs) { + return (lhs.m_data == rhs.m_data); } -inline bool -operator!= (SerialKey const& lhs, SerialKey const& rhs) { - return !(lhs == rhs); +inline bool operator!=(SerialKey const &lhs, SerialKey const &rhs) { + return !(lhs == rhs); } diff --git a/src/lib/shared/SerialKeyData.h b/src/lib/shared/SerialKeyData.h index 0c9cd7b24..2bdcb4a93 100644 --- a/src/lib/shared/SerialKeyData.h +++ b/src/lib/shared/SerialKeyData.h @@ -16,45 +16,36 @@ */ #pragma once -#include -#include "SerialKeyType.h" #include "SerialKeyEdition.h" +#include "SerialKeyType.h" +#include /** * @brief The SerialKeyData struct * This is DTO which stores key data */ struct SerialKeyData { - std::string key; // Encoded serial key as a string - SerialKeyEdition edition; // Serial key edition - SerialKeyType keyType; // Serial key type - unsigned long long warnTime = 0; // Warning time - unsigned long long expireTime = 0; // Expiration time + std::string key; // Encoded serial key as a string + SerialKeyEdition edition; // Serial key edition + SerialKeyType keyType; // Serial key type + unsigned long long warnTime = 0; // Warning time + unsigned long long expireTime = 0; // Expiration time - /** - * @brief SerialKeyData constructor - * @param key encoded key - */ - explicit SerialKeyData(const std::string& key) : - key(key) - { - } + /** + * @brief SerialKeyData constructor + * @param key encoded key + */ + explicit SerialKeyData(const std::string &key) : key(key) {} - /** - * @brief SerialKeyData default constructor - * @param key edition. Unregistered by default - */ - explicit SerialKeyData(Edition edition = kUnregistered) : - edition(edition) - { - } + /** + * @brief SerialKeyData default constructor + * @param key edition. Unregistered by default + */ + explicit SerialKeyData(Edition edition = kUnregistered) : edition(edition) {} }; -inline bool -operator== (SerialKeyData const& lhs, SerialKeyData const& rhs) { - return (lhs.key == rhs.key) && - (lhs.warnTime == rhs.warnTime) && - (lhs.expireTime == rhs.expireTime) && - (lhs.edition == rhs.edition) && - (lhs.keyType == rhs.keyType); +inline bool operator==(SerialKeyData const &lhs, SerialKeyData const &rhs) { + return (lhs.key == rhs.key) && (lhs.warnTime == rhs.warnTime) && + (lhs.expireTime == rhs.expireTime) && (lhs.edition == rhs.edition) && + (lhs.keyType == rhs.keyType); } diff --git a/src/lib/shared/SerialKeyEdition.cpp b/src/lib/shared/SerialKeyEdition.cpp index 4862afbe8..ecf1435f6 100644 --- a/src/lib/shared/SerialKeyEdition.cpp +++ b/src/lib/shared/SerialKeyEdition.cpp @@ -14,150 +14,120 @@ const std::string SerialKeyEdition::LITE = "lite"; namespace { -const std::map& getSerialTypes() -{ +const std::map &getSerialTypes() { #ifdef SYNERGY_BUSINESS - static const std::map serialTypes = { - {SerialKeyEdition::BUSINESS, kBusiness} - }; + static const std::map serialTypes = { + {SerialKeyEdition::BUSINESS, kBusiness}}; #else - static const std::map serialTypes { - {SerialKeyEdition::BASIC, kBasic}, - {SerialKeyEdition::PRO, kPro}, - {SerialKeyEdition::BASIC_CHINA, kBasic_China}, - {SerialKeyEdition::PRO_CHINA, kPro_China}, - {SerialKeyEdition::BUSINESS, kBusiness}, - {SerialKeyEdition::LITE, kLite}, - {SerialKeyEdition::ULTIMATE, kUltimate} - }; + static const std::map serialTypes{ + {SerialKeyEdition::BASIC, kBasic}, + {SerialKeyEdition::PRO, kPro}, + {SerialKeyEdition::BASIC_CHINA, kBasic_China}, + {SerialKeyEdition::PRO_CHINA, kPro_China}, + {SerialKeyEdition::BUSINESS, kBusiness}, + {SerialKeyEdition::LITE, kLite}, + {SerialKeyEdition::ULTIMATE, kUltimate}}; #endif - return serialTypes; + return serialTypes; } -} //namespace +} // namespace -SerialKeyEdition::SerialKeyEdition() -{ +SerialKeyEdition::SerialKeyEdition() {} +SerialKeyEdition::SerialKeyEdition(Edition type) : m_Type(type) {} + +SerialKeyEdition::SerialKeyEdition(const std::string &type) { setType(type); } + +Edition SerialKeyEdition::getType() const { return m_Type; } + +std::string SerialKeyEdition::getName() const { + std::string Name; + + switch (getType()) { + case kPro: + Name = PRO; + break; + case kBasic: + Name = BASIC; + break; + case kBusiness: + Name = BUSINESS; + break; + case kUnregistered: + Name = UNREGISTERED; + break; + case kBasic_China: + Name = BASIC_CHINA; + break; + case kPro_China: + Name = PRO_CHINA; + break; + case kLite: + Name = LITE; + break; + case kUltimate: + Name = ULTIMATE; + break; + default: + break; + } + + return Name; } -SerialKeyEdition::SerialKeyEdition(Edition type) : - m_Type(type) -{ +std::string SerialKeyEdition::getDisplayName() const { + const std::string ApplicationName = "Synergy 1 "; + std::string DisplayName(ApplicationName); -} - -SerialKeyEdition::SerialKeyEdition(const std::string &type) -{ - setType(type); -} - -Edition -SerialKeyEdition::getType() const -{ - return m_Type; -} - -std::string -SerialKeyEdition::getName() const -{ - std::string Name; - - switch(getType()){ - case kPro: - Name = PRO; - break; - case kBasic: - Name = BASIC; - break; - case kBusiness: - Name = BUSINESS; - break; - case kUnregistered: - Name = UNREGISTERED; - break; - case kBasic_China: - Name = BASIC_CHINA; - break; - case kPro_China: - Name = PRO_CHINA; - break; - case kLite: - Name = LITE; - break; - case kUltimate: - Name = ULTIMATE; - break; - default: - break; - } - - return Name; -} - -std::string -SerialKeyEdition::getDisplayName() const -{ - const std::string ApplicationName = "Synergy 1 "; - std::string DisplayName(ApplicationName); - - switch (getType()) - { - case kBasic_China: - DisplayName = "Synergy 中文版"; - break; - case kPro_China: - DisplayName = "Synergy Pro 中文版"; - break; - case kLite: - DisplayName = "Synergy 1"; - break; - default: - std::string EditionName = getName(); - if (!EditionName.empty()){ - if (EditionName == UNREGISTERED){ - std::transform(EditionName.begin(), EditionName.end(), EditionName.begin(), ::toupper); - EditionName = "(" + EditionName +")"; - } - else{ - EditionName[0] = static_cast(::toupper(EditionName[0])); - } - DisplayName = ApplicationName + EditionName; - } + switch (getType()) { + case kBasic_China: + DisplayName = "Synergy 中文版"; + break; + case kPro_China: + DisplayName = "Synergy Pro 中文版"; + break; + case kLite: + DisplayName = "Synergy 1"; + break; + default: + std::string EditionName = getName(); + if (!EditionName.empty()) { + if (EditionName == UNREGISTERED) { + std::transform(EditionName.begin(), EditionName.end(), + EditionName.begin(), ::toupper); + EditionName = "(" + EditionName + ")"; + } else { + EditionName[0] = static_cast(::toupper(EditionName[0])); + } + DisplayName = ApplicationName + EditionName; } + } - return DisplayName; + return DisplayName; } -void -SerialKeyEdition::setType(Edition type) -{ - m_Type = type; - setType(getName()); +void SerialKeyEdition::setType(Edition type) { + m_Type = type; + setType(getName()); } -void -SerialKeyEdition::setType(const std::string& type) -{ - auto types = getSerialTypes(); - const auto& pType = types.find(type); +void SerialKeyEdition::setType(const std::string &type) { + auto types = getSerialTypes(); + const auto &pType = types.find(type); - if (pType != types.end()) { - m_Type = pType->second; - } - else { - m_Type = kUnregistered; - } + if (pType != types.end()) { + m_Type = pType->second; + } else { + m_Type = kUnregistered; + } } -bool -SerialKeyEdition::isValid() const -{ - auto types = getSerialTypes(); - return (types.find(getName()) != types.end()); +bool SerialKeyEdition::isValid() const { + auto types = getSerialTypes(); + return (types.find(getName()) != types.end()); } -bool -SerialKeyEdition::isChina() const { - return ((m_Type == kBasic_China) || (m_Type == kPro_China)); +bool SerialKeyEdition::isChina() const { + return ((m_Type == kBasic_China) || (m_Type == kPro_China)); } diff --git a/src/lib/shared/SerialKeyEdition.h b/src/lib/shared/SerialKeyEdition.h index a69007846..76efe40fa 100644 --- a/src/lib/shared/SerialKeyEdition.h +++ b/src/lib/shared/SerialKeyEdition.h @@ -16,46 +16,46 @@ */ #pragma once -#include #include "EditionType.h" +#include + +class SerialKeyEdition { + friend bool operator==(SerialKeyEdition const &, SerialKeyEdition const &); -class SerialKeyEdition -{ - friend bool operator== (SerialKeyEdition const&, SerialKeyEdition const&); public: - SerialKeyEdition(); - explicit SerialKeyEdition(Edition type); - explicit SerialKeyEdition(const std::string& type); + SerialKeyEdition(); + explicit SerialKeyEdition(Edition type); + explicit SerialKeyEdition(const std::string &type); - Edition getType() const; - std::string getName() const; - std::string getDisplayName() const; + Edition getType() const; + std::string getName() const; + std::string getDisplayName() const; - void setType(Edition type); - void setType(const std::string& type); + void setType(Edition type); + void setType(const std::string &type); - bool isValid() const; - bool isChina() const; + bool isValid() const; + bool isChina() const; - static const std::string PRO; - static const std::string PRO_CHINA; - static const std::string BASIC; - static const std::string BASIC_CHINA; - static const std::string BUSINESS; - static const std::string UNREGISTERED; - static const std::string ULTIMATE; - static const std::string LITE; + static const std::string PRO; + static const std::string PRO_CHINA; + static const std::string BASIC; + static const std::string BASIC_CHINA; + static const std::string BUSINESS; + static const std::string UNREGISTERED; + static const std::string ULTIMATE; + static const std::string LITE; private: - Edition m_Type = kUnregistered; + Edition m_Type = kUnregistered; }; -inline bool -operator== (SerialKeyEdition const& lhs, SerialKeyEdition const& rhs) { - return (lhs.m_Type == rhs.m_Type); +inline bool operator==(SerialKeyEdition const &lhs, + SerialKeyEdition const &rhs) { + return (lhs.m_Type == rhs.m_Type); } -inline bool -operator!= (SerialKeyEdition const& lhs, SerialKeyEdition const& rhs) { - return !(lhs == rhs); +inline bool operator!=(SerialKeyEdition const &lhs, + SerialKeyEdition const &rhs) { + return !(lhs == rhs); } diff --git a/src/lib/shared/SerialKeyParser.cpp b/src/lib/shared/SerialKeyParser.cpp index 1e96f3844..01d887879 100644 --- a/src/lib/shared/SerialKeyParser.cpp +++ b/src/lib/shared/SerialKeyParser.cpp @@ -17,145 +17,121 @@ #include "SerialKeyParser.h" -void -SerialKeyParser::setKey(const std::string& key) -{ - m_data.key = key; +void SerialKeyParser::setKey(const std::string &key) { m_data.key = key; } + +void SerialKeyParser::setType(const std::string &type) { + m_data.keyType.setKeyType(type); } -void -SerialKeyParser::setType(const std::string& type) -{ - m_data.keyType.setKeyType(type); +void SerialKeyParser::setEdition(const std::string &edition) { + m_data.edition.setType(edition); + if (m_data.keyType.isMaintenance() && + m_data.edition.getType() == Edition::kBasic) { + m_data.edition.setType(kLite); + } else if (m_data.keyType.isMaintenance() && + m_data.edition.getType() == Edition::kPro) { + m_data.edition.setType(kUltimate); + } } -void -SerialKeyParser::setEdition(const std::string& edition) -{ - m_data.edition.setType(edition); - if (m_data.keyType.isMaintenance() && m_data.edition.getType() == Edition::kBasic) { - m_data.edition.setType(kLite); - } - else if (m_data.keyType.isMaintenance() && m_data.edition.getType() == Edition::kPro) { - m_data.edition.setType(kUltimate); - } +void SerialKeyParser::setWarningTime(const std::string &warnTime) { + sscanf(warnTime.c_str(), "%lld", &m_data.warnTime); } -void -SerialKeyParser::setWarningTime(const std::string& warnTime) -{ - sscanf(warnTime.c_str(), "%lld", &m_data.warnTime); +void SerialKeyParser::setExpirationTime(const std::string &expTime) { + sscanf(expTime.c_str(), "%lld", &m_data.expireTime); } -void -SerialKeyParser::setExpirationTime(const std::string& expTime) -{ - sscanf(expTime.c_str(), "%lld", &m_data.expireTime); -} - -std::string -SerialKeyParser::decode(const std::string& serial) const -{ - static const char* const lut = "0123456789ABCDEF"; - std::string output; - size_t len = serial.length(); - if (len & 1) { - return output; - } - - output.reserve(len / 2); - for (size_t i = 0; i < len; i += 2) { - - char a = serial[i]; - char b = serial[i + 1]; - - const auto p = std::lower_bound(lut, lut + 16, a); - const auto q = std::lower_bound(lut, lut + 16, b); - - if (*q != b || *p != a) { - return output; - } - - output.push_back(static_cast(((p - lut) << 4) | (q - lut))); - } - +std::string SerialKeyParser::decode(const std::string &serial) const { + static const char *const lut = "0123456789ABCDEF"; + std::string output; + size_t len = serial.length(); + if (len & 1) { return output; -} + } -bool -SerialKeyParser::parse(const std::string& plainSerial) -{ - bool valid = false; - auto key = decode(plainSerial); - const auto parts = splitToParts(key); + output.reserve(len / 2); + for (size_t i = 0; i < len; i += 2) { - if ((parts.size() == 8) && (parts.at(0).find("v1") != std::string::npos)) { - setKey(plainSerial); - parseV1(parts); - valid = true; - } - else if ((parts.size() == 9) && (parts.at(0).find("v2") != std::string::npos)) { - setKey(plainSerial); - parseV2(parts); - valid = true; + char a = serial[i]; + char b = serial[i + 1]; + + const auto p = std::lower_bound(lut, lut + 16, a); + const auto q = std::lower_bound(lut, lut + 16, b); + + if (*q != b || *p != a) { + return output; } - return valid; + output.push_back(static_cast(((p - lut) << 4) | (q - lut))); + } + + return output; } -const SerialKeyData& -SerialKeyParser::getData() const -{ - return m_data; +bool SerialKeyParser::parse(const std::string &plainSerial) { + bool valid = false; + auto key = decode(plainSerial); + const auto parts = splitToParts(key); + + if ((parts.size() == 8) && (parts.at(0).find("v1") != std::string::npos)) { + setKey(plainSerial); + parseV1(parts); + valid = true; + } else if ((parts.size() == 9) && + (parts.at(0).find("v2") != std::string::npos)) { + setKey(plainSerial); + parseV2(parts); + valid = true; + } + + return valid; } -void -SerialKeyParser::parseV1(const std::vector& parts) -{ - // e.g.: {v1;basic;Bob;1;email;company name;1398297600;1398384000} - setEdition(parts.at(1)); - setWarningTime(parts.at(6)); - setExpirationTime(parts.at(7)); +const SerialKeyData &SerialKeyParser::getData() const { return m_data; } + +void SerialKeyParser::parseV1(const std::vector &parts) { + // e.g.: {v1;basic;Bob;1;email;company name;1398297600;1398384000} + setEdition(parts.at(1)); + setWarningTime(parts.at(6)); + setExpirationTime(parts.at(7)); } -void -SerialKeyParser::parseV2(const std::vector& parts) -{ - // e.g.: {v2;trial;basic;Bob;1;email;company name;1398297600;1398384000} - setType(parts.at(1)); - setEdition(parts.at(2)); - setWarningTime(parts.at(7)); - setExpirationTime(parts.at(8)); +void SerialKeyParser::parseV2(const std::vector &parts) { + // e.g.: {v2;trial;basic;Bob;1;email;company name;1398297600;1398384000} + setType(parts.at(1)); + setEdition(parts.at(2)); + setWarningTime(parts.at(7)); + setExpirationTime(parts.at(8)); } std::vector -SerialKeyParser::splitToParts(const std::string& plainSerial) const -{ - // tokenize serialised subscription. - std::vector parts; +SerialKeyParser::splitToParts(const std::string &plainSerial) const { + // tokenize serialised subscription. + std::vector parts; - if (!plainSerial.empty()) { - std::string parityStart = plainSerial.substr(0, 1); - std::string parityEnd = plainSerial.substr(plainSerial.length() - 1, 1); + if (!plainSerial.empty()) { + std::string parityStart = plainSerial.substr(0, 1); + std::string parityEnd = plainSerial.substr(plainSerial.length() - 1, 1); - // check for parity chars { and }, record parity result, then remove them. - if (parityStart == "{" && parityEnd == "}") { - const auto serialData = plainSerial.substr(1, plainSerial.length() - 2); + // check for parity chars { and }, record parity result, then remove them. + if (parityStart == "{" && parityEnd == "}") { + const auto serialData = plainSerial.substr(1, plainSerial.length() - 2); - std::string::size_type pos = 0; - bool look = true; - while (look) { - std::string::size_type start = pos; - pos = serialData.find(";", pos); - if (pos == std::string::npos) { - pos = serialData.length(); - look = false; - } - parts.push_back(serialData.substr(start, pos - start)); - pos += 1; - } + std::string::size_type pos = 0; + bool look = true; + while (look) { + std::string::size_type start = pos; + pos = serialData.find(";", pos); + if (pos == std::string::npos) { + pos = serialData.length(); + look = false; } + parts.push_back(serialData.substr(start, pos - start)); + pos += 1; + } } + } - return parts; + return parts; } diff --git a/src/lib/shared/SerialKeyParser.h b/src/lib/shared/SerialKeyParser.h index f4e1e449c..0f1c033f1 100644 --- a/src/lib/shared/SerialKeyParser.h +++ b/src/lib/shared/SerialKeyParser.h @@ -16,86 +16,85 @@ */ #pragma once +#include "SerialKeyData.h" #include #include -#include "SerialKeyData.h" -class SerialKeyParser -{ +class SerialKeyParser { public: - /** - * @brief ~SerialKeyParser destructor - */ - virtual ~SerialKeyParser(){} - /** - * @brief parse serial key - * @param plainSerial encoded serial key - * @return true if parsed - */ - virtual bool parse(const std::string& plainSerial); + /** + * @brief ~SerialKeyParser destructor + */ + virtual ~SerialKeyParser() {} + /** + * @brief parse serial key + * @param plainSerial encoded serial key + * @return true if parsed + */ + virtual bool parse(const std::string &plainSerial); - /** - * @brief getData getter for serial key data - * @return serial key data as DTO - */ - const SerialKeyData& getData() const; + /** + * @brief getData getter for serial key data + * @return serial key data as DTO + */ + const SerialKeyData &getData() const; - /** - * @brief setKey setter to set encoded key - * @param key encoded serial key - */ - void setKey(const std::string& key); + /** + * @brief setKey setter to set encoded key + * @param key encoded serial key + */ + void setKey(const std::string &key); - /** - * @brief setType setter for serial type - * @param type serial key type - */ - void setType(const std::string& type); + /** + * @brief setType setter for serial type + * @param type serial key type + */ + void setType(const std::string &type); - /** - * @brief setEdition setter for serial edition - * @param edition serial key edition - */ - void setEdition(const std::string& edition); + /** + * @brief setEdition setter for serial edition + * @param edition serial key edition + */ + void setEdition(const std::string &edition); - /** - * @brief setWarningTime setter for warning time - * @param warnTime warning time for key as a string - */ - void setWarningTime(const std::string& warnTime); + /** + * @brief setWarningTime setter for warning time + * @param warnTime warning time for key as a string + */ + void setWarningTime(const std::string &warnTime); - /** - * @brief setExpirationTime setter for expiration date - * @param expTime expiration data as a string - */ - void setExpirationTime(const std::string& expTime); + /** + * @brief setExpirationTime setter for expiration date + * @param expTime expiration data as a string + */ + void setExpirationTime(const std::string &expTime); private: - /** - * @brief decode serial key from encoded string - * @param encoded serial key as a string - * @return decoded serial key as a string - */ - std::string decode(const std::string& serial) const; + /** + * @brief decode serial key from encoded string + * @param encoded serial key as a string + * @return decoded serial key as a string + */ + std::string decode(const std::string &serial) const; - /** - * @brief parseV1 parse serial key version 1 - * @param parts of serial key version 1 - */ - void parseV1(const std::vector& parts); + /** + * @brief parseV1 parse serial key version 1 + * @param parts of serial key version 1 + */ + void parseV1(const std::vector &parts); - /** - * @brief parseV2 parse serial key version 2 - * @param parts parts of serial key version 2 - */ - void parseV2(const std::vector& parts); + /** + * @brief parseV2 parse serial key version 2 + * @param parts parts of serial key version 2 + */ + void parseV2(const std::vector &parts); - /** - * @brief splitToParts splits decoded serial key to parts - * @param plainSerial decoded serial key as a string - * @return splitted serial key - */ - std::vector splitToParts(const std::string& plainSerial) const; + /** + * @brief splitToParts splits decoded serial key to parts + * @param plainSerial decoded serial key as a string + * @return splitted serial key + */ + std::vector splitToParts(const std::string &plainSerial) const; - SerialKeyData m_data{}; //serial key data + SerialKeyData m_data{}; // serial key data }; diff --git a/src/lib/shared/SerialKeyType.cpp b/src/lib/shared/SerialKeyType.cpp index c12336725..6f7e60f29 100644 --- a/src/lib/shared/SerialKeyType.cpp +++ b/src/lib/shared/SerialKeyType.cpp @@ -21,34 +21,16 @@ const std::string SerialKeyType::TRIAL = "trial"; const std::string SerialKeyType::SUBSCRIPTION = "subscription"; const std::string SerialKeyType::MAINTENANCE = "maintenance"; -SerialKeyType::SerialKeyType() -{ +SerialKeyType::SerialKeyType() {} +void SerialKeyType::setKeyType(const std::string &Type) { + m_isTrial = (Type == SerialKeyType::TRIAL); + m_isTemporary = (m_isTrial || (Type == SerialKeyType::SUBSCRIPTION)); + m_isMaintenance = (Type == SerialKeyType::MAINTENANCE); } -void -SerialKeyType::setKeyType(const std::string& Type) -{ - m_isTrial = (Type == SerialKeyType::TRIAL); - m_isTemporary = (m_isTrial || (Type == SerialKeyType::SUBSCRIPTION)); - m_isMaintenance = (Type == SerialKeyType::MAINTENANCE); -} +bool SerialKeyType::isTrial() const { return m_isTrial; } -bool -SerialKeyType::isTrial() const -{ - return m_isTrial; -} - -bool -SerialKeyType::isTemporary() const -{ - return m_isTemporary; -} - -bool -SerialKeyType::isMaintenance() const -{ - return m_isMaintenance; -} +bool SerialKeyType::isTemporary() const { return m_isTemporary; } +bool SerialKeyType::isMaintenance() const { return m_isMaintenance; } diff --git a/src/lib/shared/SerialKeyType.h b/src/lib/shared/SerialKeyType.h index aeed90cca..c7fedd951 100644 --- a/src/lib/shared/SerialKeyType.h +++ b/src/lib/shared/SerialKeyType.h @@ -18,35 +18,33 @@ #include -class SerialKeyType -{ +class SerialKeyType { private: - friend bool operator== (SerialKeyType const&, SerialKeyType const&); + friend bool operator==(SerialKeyType const &, SerialKeyType const &); + public: - static const std::string TRIAL; - static const std::string SUBSCRIPTION; - static const std::string MAINTENANCE; + static const std::string TRIAL; + static const std::string SUBSCRIPTION; + static const std::string MAINTENANCE; - SerialKeyType(); + SerialKeyType(); - void setKeyType(const std::string& Type); - bool isTrial() const; - bool isTemporary() const; - bool isMaintenance() const; + void setKeyType(const std::string &Type); + bool isTrial() const; + bool isTemporary() const; + bool isMaintenance() const; private: - bool m_isTrial = false; - bool m_isTemporary = false; - bool m_isMaintenance = false; + bool m_isTrial = false; + bool m_isTemporary = false; + bool m_isMaintenance = false; }; -inline bool -operator== (SerialKeyType const& lhs, SerialKeyType const& rhs) { - return (lhs.m_isTrial == rhs.m_isTrial) && (lhs.m_isTemporary == rhs.m_isTemporary); +inline bool operator==(SerialKeyType const &lhs, SerialKeyType const &rhs) { + return (lhs.m_isTrial == rhs.m_isTrial) && + (lhs.m_isTemporary == rhs.m_isTemporary); } -inline bool -operator!= (SerialKeyType const& lhs, SerialKeyType const& rhs) { - return !(lhs == rhs); +inline bool operator!=(SerialKeyType const &lhs, SerialKeyType const &rhs) { + return !(lhs == rhs); } - diff --git a/src/lib/synergy/App.cpp b/src/lib/synergy/App.cpp index 284e74882..8f3c15a12 100644 --- a/src/lib/synergy/App.cpp +++ b/src/lib/synergy/App.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -18,21 +18,21 @@ #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" #include "DisplayInvalidException.h" +#include "arch/Arch.h" +#include "arch/XArch.h" +#include "base/EventQueue.h" +#include "base/Log.h" +#include "base/TMethodEventJob.h" +#include "base/XBase.h" +#include "base/log_outputters.h" +#include "common/Version.h" +#include "ipc/Ipc.h" +#include "ipc/IpcMessage.h" +#include "ipc/IpcServerProxy.h" +#include "synergy/ArgsBase.h" +#include "synergy/XSynergy.h" +#include "synergy/protocol_types.h" #if SYSAPI_WIN32 #include "arch/win32/ArchMiscWindows.h" @@ -51,221 +51,180 @@ #include "platform/OSXDragSimulator.h" #endif - -App* App::s_instance = nullptr; +App *App::s_instance = nullptr; // // App // -App::App(IEventQueue* events, CreateTaskBarReceiverFunc createTaskBarReceiver, lib::synergy::ArgsBase* args) : - m_bye(&exit), - m_taskBarReceiver(NULL), - m_suspended(false), - m_events(events), - m_args(args), - m_fileLog(nullptr), - m_createTaskBarReceiver(createTaskBarReceiver), - m_appUtil(events), - m_ipcClient(nullptr), - m_socketMultiplexer(nullptr) -{ - assert(s_instance == nullptr); - s_instance = this; +App::App(IEventQueue *events, CreateTaskBarReceiverFunc createTaskBarReceiver, + lib::synergy::ArgsBase *args) + : m_bye(&exit), m_taskBarReceiver(NULL), m_suspended(false), + m_events(events), m_args(args), m_fileLog(nullptr), + m_createTaskBarReceiver(createTaskBarReceiver), m_appUtil(events), + m_ipcClient(nullptr), m_socketMultiplexer(nullptr) { + assert(s_instance == nullptr); + s_instance = this; } -App::~App() -{ - s_instance = nullptr; - delete m_args; +App::~App() { + s_instance = nullptr; + delete m_args; } -void -App::version() -{ - static const size_t buffer_size = 500; - static const size_t cpight_size = 200; +void App::version() { + static const size_t buffer_size = 500; + static const size_t cpight_size = 200; - char copyrightBuffer[cpight_size]; - snprintf( - copyrightBuffer, - cpight_size, - kCopyright, - kBuildYear - ); + char copyrightBuffer[cpight_size]; + snprintf(copyrightBuffer, cpight_size, kCopyright, kBuildYear); - char buffer[buffer_size]; - snprintf( - buffer, - buffer_size, - "%s %s, protocol version %d.%d\n%s", - argsBase().m_pname, - kVersion, - kProtocolMajorVersion, - kProtocolMinorVersion, - copyrightBuffer - ); + char buffer[buffer_size]; + snprintf(buffer, buffer_size, "%s %s, protocol version %d.%d\n%s", + argsBase().m_pname, kVersion, kProtocolMajorVersion, + kProtocolMinorVersion, copyrightBuffer); - std::cout << buffer << std::endl; + std::cout << buffer << std::endl; } -int -App::run(int argc, char** argv) -{ +int App::run(int argc, char **argv) { #if MAC_OS_X_VERSION_10_7 - // dock hide only supported on lion :( - ProcessSerialNumber psn = { 0, kCurrentProcess }; - + // dock hide only supported on lion :( + ProcessSerialNumber psn = {0, kCurrentProcess}; + #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdeprecated-declarations" - GetCurrentProcess(&psn); + GetCurrentProcess(&psn); #pragma GCC diagnostic pop - TransformProcessType(&psn, kProcessTransformToBackgroundApplication); + 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; + // install application in to arch + appUtil().adoptApp(this); - 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 (DisplayInvalidException& die) { - LOG((CLOG_CRIT "a display invalid exception error occurred: %s\n", die.what())); - // display invalid exceptions can occur when going to sleep. When this process exits, the - // UI will restart us instantly. We don't really want that behevior, so we quies for a bit - ARCH->sleep(10); - } - catch (std::runtime_error& re) { - LOG((CLOG_CRIT "a runtime error occurred: %s\n", re.what())); - } - catch (std::exception& e) { - LOG((CLOG_CRIT "an error occurred: %s\n", e.what())); - } - catch (...) { - LOG((CLOG_CRIT "an unknown error occurred\n")); - } + // HACK: fail by default (saves us setting result in each catch) + int result = kExitFailed; - appUtil().beforeAppExit(); - - return result; + 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 (DisplayInvalidException &die) { + LOG((CLOG_CRIT "a display invalid exception error occurred: %s\n", + die.what())); + // display invalid exceptions can occur when going to sleep. When this + // process exits, the UI will restart us instantly. We don't really want + // that behevior, so we quies for a bit + ARCH->sleep(10); + } catch (std::runtime_error &re) { + LOG((CLOG_CRIT "a runtime error occurred: %s\n", re.what())); + } 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**) -{ +int App::daemonMainLoop(int, const char **) { #if SYSAPI_WIN32 - SystemLogger sysLogger(daemonName(), false); + SystemLogger sysLogger(daemonName(), false); #else - SystemLogger sysLogger(daemonName(), true); + SystemLogger sysLogger(daemonName(), true); #endif - return mainLoop(); + 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::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::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); + + ARCH->setProfileDirectory(argsBase().m_profileDirectory); + ARCH->setPluginDirectory(argsBase().m_pluginDirectory); + + // set log filter + if (!CLOG->setFilter(argsBase().m_logFilter)) { + LOG((CLOG_CRIT "%s: unrecognized log level `%s'" BYE, argsBase().m_pname, + argsBase().m_logFilter, argsBase().m_pname)); + m_bye(kExitArgs); + } + loggingFilterWarning(); + + // setup file logging after parsing args + setupFileLogging(); + + // load configuration + loadConfig(); + + if (!argsBase().m_disableTray && m_createTaskBarReceiver) { + + // 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::initApp(int argc, const char** argv) -{ - // parse command line - parseArgs(argc, argv); - - ARCH->setProfileDirectory(argsBase().m_profileDirectory); - ARCH->setPluginDirectory(argsBase().m_pluginDirectory); +void App::initIpcClient() { + m_ipcClient = new IpcClient(m_events, m_socketMultiplexer); + m_ipcClient->connect(); - // set log filter - if (!CLOG->setFilter(argsBase().m_logFilter)) { - LOG((CLOG_CRIT "%s: unrecognized log level `%s'" BYE, - argsBase().m_pname, argsBase().m_logFilter, argsBase().m_pname)); - m_bye(kExitArgs); - } - loggingFilterWarning(); - - // setup file logging after parsing args - setupFileLogging(); - - // load configuration - loadConfig(); - - if (!argsBase().m_disableTray && m_createTaskBarReceiver) { - - // 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); - } + m_events->adoptHandler( + m_events->forIpcClient().messageReceived(), m_ipcClient, + new TMethodEventJob(this, &App::handleIpcMessage)); } -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::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::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(); -void -App::runEventsLoop(void*) -{ - m_events->loop(); - #if defined(MAC_OS_X_VERSION_10_7) - - stopCocoaLoop(); - + + stopCocoaLoop(); + #endif } @@ -273,76 +232,34 @@ App::runEventsLoop(void*) // MinimalApp // -MinimalApp::MinimalApp() : - App(NULL, NULL, new lib::synergy::ArgsBase()) -{ - m_arch.init(); - setEvents(m_events); +MinimalApp::MinimalApp() : App(NULL, NULL, new lib::synergy::ArgsBase()) { + m_arch.init(); + setEvents(m_events); } -MinimalApp::~MinimalApp() -{ +MinimalApp::~MinimalApp() {} + +int MinimalApp::standardStartup(int argc, char **argv) { return 0; } + +int MinimalApp::runInner(int argc, char **argv, ILogOutputter *outputter, + StartupFunc startup) { + return 0; } -int -MinimalApp::standardStartup(int argc, char** argv) -{ - return 0; -} +void MinimalApp::startNode() {} -int -MinimalApp::runInner(int argc, char** argv, ILogOutputter* outputter, StartupFunc startup) -{ - return 0; -} +int MinimalApp::mainLoop() { return 0; } -void -MinimalApp::startNode() -{ -} +int MinimalApp::foregroundStartup(int argc, char **argv) { return 0; } -int -MinimalApp::mainLoop() -{ - return 0; -} +synergy::Screen *MinimalApp::createScreen() { return NULL; } -int -MinimalApp::foregroundStartup(int argc, char** argv) -{ - return 0; -} +void MinimalApp::loadConfig() {} -synergy::Screen* -MinimalApp::createScreen() -{ - return NULL; -} +bool MinimalApp::loadConfig(const String &pathname) { return false; } -void -MinimalApp::loadConfig() -{ -} +const char *MinimalApp::daemonInfo() const { return ""; } -bool -MinimalApp::loadConfig(const String& pathname) -{ - return false; -} +const char *MinimalApp::daemonName() const { return ""; } -const char* -MinimalApp::daemonInfo() const -{ - return ""; -} - -const char* -MinimalApp::daemonName() const -{ - return ""; -} - -void -MinimalApp::parseArgs(int argc, const char* const* argv) -{ -} +void MinimalApp::parseArgs(int argc, const char *const *argv) {} diff --git a/src/lib/synergy/App.h b/src/lib/synergy/App.h index 8fd37b00f..c5cfd63ab 100644 --- a/src/lib/synergy/App.h +++ b/src/lib/synergy/App.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -18,12 +18,12 @@ #pragma once +#include "base/EventQueue.h" +#include "base/Log.h" +#include "base/String.h" +#include "common/common.h" #include "ipc/IpcClient.h" #include "synergy/IApp.h" -#include "base/String.h" -#include "base/Log.h" -#include "base/EventQueue.h" -#include "common/common.h" #if SYSAPI_WIN32 #include "synergy/win32/AppUtilWindows.h" @@ -35,121 +35,132 @@ class IArchTaskBarReceiver; class BufferedLogOutputter; class ILogOutputter; class FileLogOutputter; -namespace synergy { class Screen; } +namespace synergy { +class Screen; +} class IEventQueue; class SocketMultiplexer; -typedef IArchTaskBarReceiver* (*CreateTaskBarReceiverFunc)(const BufferedLogOutputter*, IEventQueue* events); +typedef IArchTaskBarReceiver *(*CreateTaskBarReceiverFunc)( + const BufferedLogOutputter *, IEventQueue *events); class App : public IApp { public: - App(IEventQueue* events, CreateTaskBarReceiverFunc createTaskBarReceiver, lib::synergy::ArgsBase* args); - App(App const &) =delete; - App(App &&) =delete; - virtual ~App(); + App(IEventQueue *events, CreateTaskBarReceiverFunc createTaskBarReceiver, + lib::synergy::ArgsBase *args); + App(App const &) = delete; + App(App &&) = delete; + virtual ~App(); - App& operator=(App const &) =delete; - App& operator=(App &&) =delete; + App &operator=(App const &) = delete; + App &operator=(App &&) = delete; - // Returns args that are common between server and client. - lib::synergy::ArgsBase& argsBase() const { return *m_args; } + // Returns args that are common between server and client. + lib::synergy::ArgsBase &argsBase() const { return *m_args; } - // Prints the current compiled version. - virtual void version(); + // Prints the current compiled version. + virtual void version(); - // Prints help specific to client or server. - virtual void help() = 0; + // Prints help specific to client or server. + virtual void help() = 0; - // Parse command line arguments. - virtual void parseArgs(int argc, const char* const* argv) = 0; - - int run(int argc, char** argv); + // Parse command line arguments. + virtual void parseArgs(int argc, const char *const *argv) = 0; - int daemonMainLoop(int, const char**); + int run(int argc, char **argv); - virtual void loadConfig() = 0; - virtual bool loadConfig(const String& pathname) = 0; + int daemonMainLoop(int, const char **); - // A description of the daemon (used only on Windows). - virtual const char* daemonInfo() const = 0; + virtual void loadConfig() = 0; + virtual bool loadConfig(const String &pathname) = 0; - // Function pointer for function to exit immediately. - // TODO: this is old C code - use inheritance to normalize - void (*m_bye)(int); + // A description of the daemon (used only on Windows). + virtual const char *daemonInfo() const = 0; - static App& instance() { assert(s_instance != nullptr); return *s_instance; } + // Function pointer for function to exit immediately. + // TODO: this is old C code - use inheritance to normalize + void (*m_bye)(int); - // If --log was specified in args, then add a file logger. - void setupFileLogging(); + static App &instance() { + assert(s_instance != nullptr); + return *s_instance; + } - // If messages will be hidden (to improve performance), warn user. - void loggingFilterWarning(); + // If --log was specified in args, then add a file logger. + void setupFileLogging(); - // Parses args, sets up file logging, and loads the config. - void initApp(int argc, const char** argv); + // If messages will be hidden (to improve performance), warn user. + void loggingFilterWarning(); - // HACK: accept non-const, but make it const anyway - void initApp(int argc, char** argv) { initApp(argc, (const char**)argv); } + // Parses args, sets up file logging, and loads the config. + void initApp(int argc, const char **argv); - ARCH_APP_UTIL& appUtil() { return m_appUtil; } + // HACK: accept non-const, but make it const anyway + void initApp(int argc, char **argv) { initApp(argc, (const char **)argv); } - virtual IArchTaskBarReceiver* taskBarReceiver() const { return m_taskBarReceiver; } + ARCH_APP_UTIL &appUtil() { return m_appUtil; } - virtual void setByeFunc(void(*bye)(int)) { m_bye = bye; } - virtual void bye(int error) { m_bye(error); } - - virtual IEventQueue* getEvents() const { return m_events; } + virtual IArchTaskBarReceiver *taskBarReceiver() const { + return m_taskBarReceiver; + } - void setSocketMultiplexer(SocketMultiplexer* sm) { m_socketMultiplexer = sm; } - SocketMultiplexer* getSocketMultiplexer() const { return m_socketMultiplexer; } + virtual void setByeFunc(void (*bye)(int)) { m_bye = bye; } + virtual void bye(int error) { m_bye(error); } - void setEvents(EventQueue& events) { m_events = &events; } + virtual IEventQueue *getEvents() const { return m_events; } + + void setSocketMultiplexer(SocketMultiplexer *sm) { m_socketMultiplexer = sm; } + SocketMultiplexer *getSocketMultiplexer() const { + return m_socketMultiplexer; + } + + void setEvents(EventQueue &events) { m_events = &events; } private: - void handleIpcMessage(const Event&, void*); + void handleIpcMessage(const Event &, void *); protected: - void initIpcClient(); - void cleanupIpcClient(); - void runEventsLoop(void*); + void initIpcClient(); + void cleanupIpcClient(); + void runEventsLoop(void *); - IArchTaskBarReceiver* m_taskBarReceiver; - bool m_suspended; - IEventQueue* m_events; + IArchTaskBarReceiver *m_taskBarReceiver; + bool m_suspended; + IEventQueue *m_events; private: - lib::synergy::ArgsBase* m_args; - static App* s_instance; - FileLogOutputter* m_fileLog; - CreateTaskBarReceiverFunc m_createTaskBarReceiver; - ARCH_APP_UTIL m_appUtil; - IpcClient* m_ipcClient; - SocketMultiplexer* m_socketMultiplexer; + lib::synergy::ArgsBase *m_args; + static App *s_instance; + FileLogOutputter *m_fileLog; + CreateTaskBarReceiverFunc m_createTaskBarReceiver; + ARCH_APP_UTIL m_appUtil; + IpcClient *m_ipcClient; + SocketMultiplexer *m_socketMultiplexer; }; class MinimalApp : public App { public: - MinimalApp(); - virtual ~MinimalApp(); + MinimalApp(); + virtual ~MinimalApp(); - // IApp overrides - virtual int standardStartup(int argc, char** argv); - virtual int runInner(int argc, char** argv, ILogOutputter* outputter, StartupFunc startup); - virtual void startNode(); - virtual int mainLoop(); - virtual int foregroundStartup(int argc, char** argv); - virtual synergy::Screen* - createScreen(); - virtual void loadConfig(); - virtual bool loadConfig(const String& pathname); - virtual const char* daemonInfo() const; - virtual const char* daemonName() const; - virtual void parseArgs(int argc, const char* const* argv); + // IApp overrides + virtual int standardStartup(int argc, char **argv); + virtual int runInner(int argc, char **argv, ILogOutputter *outputter, + StartupFunc startup); + virtual void startNode(); + virtual int mainLoop(); + virtual int foregroundStartup(int argc, char **argv); + virtual synergy::Screen *createScreen(); + virtual void loadConfig(); + virtual bool loadConfig(const String &pathname); + virtual const char *daemonInfo() const; + virtual const char *daemonName() const; + virtual void parseArgs(int argc, const char *const *argv); private: - Arch m_arch; - Log m_log; - EventQueue m_events; + Arch m_arch; + Log m_log; + EventQueue m_events; }; #if WINAPI_MSWINDOWS @@ -158,49 +169,52 @@ private: #define DAEMON_RUNNING(running_) #endif -#define HELP_COMMON_INFO_1 \ - " -d, --debug filter out log messages with priority below level.\n" \ - " level may be: FATAL, ERROR, WARNING, NOTE, INFO,\n" \ - " DEBUG, DEBUG1, DEBUG2.\n" \ - " -n, --name use screen-name instead the hostname to identify\n" \ - " this screen in the configuration.\n" \ - " -1, --no-restart do not try to restart on failure.\n" \ - "* --restart restart the server automatically if it fails.\n" \ - " -l --log write log messages to file.\n" \ - " --no-tray disable the system tray icon.\n" \ - " --enable-drag-drop enable file drag & drop.\n" \ - " --enable-crypto enable the crypto (ssl) plugin.\n" \ - " --tls-cert specify the path to the tls certificate file.\n" +#define HELP_COMMON_INFO_1 \ + " -d, --debug filter out log messages with priority below " \ + "level.\n" \ + " level may be: FATAL, ERROR, WARNING, NOTE, " \ + "INFO,\n" \ + " DEBUG, DEBUG1, DEBUG2.\n" \ + " -n, --name use screen-name instead the hostname to " \ + "identify\n" \ + " this screen in the configuration.\n" \ + " -1, --no-restart do not try to restart on failure.\n" \ + "* --restart restart the server automatically if it fails.\n" \ + " -l --log write log messages to file.\n" \ + " --no-tray disable the system tray icon.\n" \ + " --enable-drag-drop enable file drag & drop.\n" \ + " --enable-crypto enable the crypto (ssl) plugin.\n" \ + " --tls-cert specify the path to the tls certificate file.\n" -#define HELP_COMMON_INFO_2 \ - " -h, --help display this help and exit.\n" \ - " --version display version information and exit.\n" +#define HELP_COMMON_INFO_2 \ + " -h, --help display this help and exit.\n" \ + " --version display version information and exit.\n" -#define HELP_COMMON_ARGS \ - " [--name ]" \ - " [--restart|--no-restart]" \ - " [--debug ]" +#define HELP_COMMON_ARGS \ + " [--name ]" \ + " [--restart|--no-restart]" \ + " [--debug ]" // system args (windows/unix) #if SYSAPI_UNIX // unix daemon mode args -# define HELP_SYS_ARGS \ - " [--daemon|--no-daemon]" -# define HELP_SYS_INFO \ - " -f, --no-daemon run in the foreground.\n" \ - "* --daemon run as a daemon.\n" +#define HELP_SYS_ARGS " [--daemon|--no-daemon]" +#define HELP_SYS_INFO \ + " -f, --no-daemon run in the foreground.\n" \ + "* --daemon run as a daemon.\n" #elif SYSAPI_WIN32 // windows args -# define HELP_SYS_ARGS \ - " [--service ] [--relaunch] [--exit-pause]" -# define HELP_SYS_INFO \ - " --service manage the windows service, valid options are:\n" \ - " install/uninstall/start/stop\n" \ - " --relaunch persistently relaunches process in current user \n" \ - " session (useful for vista and upward).\n" \ - " --exit-pause wait for key press on exit, can be useful for\n" \ - " reading error messages that occur on exit.\n" +#define HELP_SYS_ARGS " [--service ] [--relaunch] [--exit-pause]" +#define HELP_SYS_INFO \ + " --service manage the windows service, valid options " \ + "are:\n" \ + " install/uninstall/start/stop\n" \ + " --relaunch persistently relaunches process in current " \ + "user \n" \ + " session (useful for vista and upward).\n" \ + " --exit-pause wait for key press on exit, can be useful for\n" \ + " reading error messages that occur on exit.\n" #endif diff --git a/src/lib/synergy/AppUtil.cpp b/src/lib/synergy/AppUtil.cpp index 52f121e98..95968283b 100644 --- a/src/lib/synergy/AppUtil.cpp +++ b/src/lib/synergy/AppUtil.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -15,40 +15,28 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + #include "synergy/AppUtil.h" #include "algorithm" -AppUtil* AppUtil::s_instance = nullptr; - -AppUtil::AppUtil() : -m_app(nullptr) -{ - s_instance = this; +AppUtil *AppUtil::s_instance = nullptr; + +AppUtil::AppUtil() : m_app(nullptr) { s_instance = this; } + +AppUtil::~AppUtil() {} + +void AppUtil::adoptApp(IApp *app) { + app->setByeFunc(&exitAppStatic); + m_app = app; } -AppUtil::~AppUtil() -{ +IApp &AppUtil::app() const { + assert(m_app != nullptr); + return *m_app; } -void -AppUtil::adoptApp(IApp* app) -{ - app->setByeFunc(&exitAppStatic); - m_app = app; -} - -IApp& -AppUtil::app() const -{ - assert(m_app != nullptr); - return *m_app; -} - -AppUtil& -AppUtil::instance() -{ - assert(s_instance != nullptr); - return *s_instance; +AppUtil &AppUtil::instance() { + assert(s_instance != nullptr); + return *s_instance; } diff --git a/src/lib/synergy/AppUtil.h b/src/lib/synergy/AppUtil.h index 05bd45d78..b8065f731 100644 --- a/src/lib/synergy/AppUtil.h +++ b/src/lib/synergy/AppUtil.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + #pragma once #include "synergy/IAppUtil.h" @@ -23,18 +23,18 @@ class AppUtil : public IAppUtil { public: - AppUtil(); - virtual ~AppUtil(); + AppUtil(); + virtual ~AppUtil(); - virtual void adoptApp(IApp* app); - IApp& app() const; - virtual void exitApp(int code) { throw XExitApp(code); } + virtual void adoptApp(IApp *app); + IApp &app() const; + virtual void exitApp(int code) { throw XExitApp(code); } - static AppUtil& instance(); - static void exitAppStatic(int code) { instance().exitApp(code); } - virtual void beforeAppExit() {} + static AppUtil &instance(); + static void exitAppStatic(int code) { instance().exitApp(code); } + virtual void beforeAppExit() {} private: - IApp* m_app; - static AppUtil* s_instance; + IApp *m_app; + static AppUtil *s_instance; }; diff --git a/src/lib/synergy/ArgParser.cpp b/src/lib/synergy/ArgParser.cpp index b78a70cea..863ed120a 100644 --- a/src/lib/synergy/ArgParser.cpp +++ b/src/lib/synergy/ArgParser.cpp @@ -17,504 +17,433 @@ #include "synergy/ArgParser.h" -#include "synergy/StreamChunker.h" -#include "synergy/App.h" -#include "synergy/ServerArgs.h" -#include "synergy/ClientArgs.h" -#include "synergy/ToolArgs.h" -#include "synergy/ArgsBase.h" #include "base/Log.h" #include "base/String.h" +#include "synergy/App.h" +#include "synergy/ArgsBase.h" +#include "synergy/ClientArgs.h" +#include "synergy/ServerArgs.h" +#include "synergy/StreamChunker.h" +#include "synergy/ToolArgs.h" #ifdef WINAPI_MSWINDOWS #include #endif -lib::synergy::ArgsBase* ArgParser::m_argsBase = NULL; +lib::synergy::ArgsBase *ArgParser::m_argsBase = NULL; -ArgParser::ArgParser(App* app) : - m_app(app) -{ -} +ArgParser::ArgParser(App *app) : m_app(app) {} -bool -ArgParser::parseServerArgs(lib::synergy::ServerArgs& args, int argc, const char* const* argv) -{ - setArgsBase(args); - updateCommonArgs(argv); - int i = 1; - while ( i < argc) { - if (parsePlatformArg(args, argc, argv, i)) { - ++i; - continue; - } - else if (parseGenericArgs(argc, argv, i)) { - ++i; - continue; - } - else if (parseDeprecatedArgs(argc, argv, i)) { - ++i; - continue; - } - else if (isArg(i, argc, argv, "-c", "--config", 1)) { - // save configuration file path - args.m_configFile = argv[++i]; - } - else if (isArg(i, argc, argv, "", "--serial-key", 1)) { - args.m_serial = SerialKey(argv[++i]); - } - else if (isArg(i, argc, argv, nullptr, "server")) { - ++i; - continue; - } - else { - LOG((CLOG_CRIT "%s: unrecognized option `%s'" BYE, args.m_pname, argv[i], args.m_pname)); - return false; - } - ++i; +bool ArgParser::parseServerArgs(lib::synergy::ServerArgs &args, int argc, + const char *const *argv) { + setArgsBase(args); + updateCommonArgs(argv); + int i = 1; + while (i < argc) { + if (parsePlatformArg(args, argc, argv, i)) { + ++i; + continue; + } else if (parseGenericArgs(argc, argv, i)) { + ++i; + continue; + } else if (parseDeprecatedArgs(argc, argv, i)) { + ++i; + continue; + } else if (isArg(i, argc, argv, "-c", "--config", 1)) { + // save configuration file path + args.m_configFile = argv[++i]; + } else if (isArg(i, argc, argv, "", "--serial-key", 1)) { + args.m_serial = SerialKey(argv[++i]); + } else if (isArg(i, argc, argv, nullptr, "server")) { + ++i; + continue; + } else { + LOG((CLOG_CRIT "%s: unrecognized option `%s'" BYE, args.m_pname, argv[i], + args.m_pname)); + return false; } + ++i; + } - if (checkUnexpectedArgs()) { - return false; - } - - return true; -} - -bool -ArgParser::parseClientArgs(lib::synergy::ClientArgs& args, int argc, const char* const* argv) -{ - setArgsBase(args); - updateCommonArgs(argv); - - int i {1}; - while (i < argc) { - if (parsePlatformArg(args, argc, argv, i)) { - ++i; - continue; - } - else if (parseGenericArgs(argc, argv, i)) { - ++i; - continue; - } - else if (parseDeprecatedArgs(argc, argv, i)) { - ++i; - continue; - } - else if (isArg(i, argc, argv, nullptr, "--camp")) { - // ignore -- included for backwards compatibility - } - else if (isArg(i, argc, argv, nullptr, "--no-camp")) { - // ignore -- included for backwards compatibility - } - else if (isArg(i, argc, argv, nullptr, "--yscroll", 1)) { - // define scroll - args.m_yscroll = atoi(argv[++i]); - } - else if (isArg(i, argc, argv, nullptr, "--sync-language")) { - args.m_enableLangSync = true; - } - else if (isArg(i, argc, argv, nullptr, "--invert-scroll")) { - args.m_clientScrollDirection = lib::synergy::ClientScrollDirection::INVERT_SERVER; - } - else if (isArg(i, argc, argv, nullptr, "--host")) { - args.m_hostMode = true; - } - else if (isArg(i, argc, argv, nullptr, "client")) { - ++i; - continue; - } - else { - if (i + 1 == argc) { - args.m_serverAddress = argv[i]; - return true; - } - - LOG((CLOG_CRIT "%s: unrecognized option `%s'" BYE, args.m_pname, argv[i], args.m_pname)); - return false; - } - ++i; - } - - // exactly one non-option argument (server-address) - if (i == argc) { - LOG((CLOG_CRIT "%s: a server address or name is required" BYE, - args.m_pname, args.m_pname)); - return false; - } - - if (checkUnexpectedArgs()) { - return false; - } - - return true; -} - -bool -ArgParser::parsePlatformArg(lib::synergy::ArgsBase& argsBase, const int& argc, const char* const* argv, int& i) -{ -#if WINAPI_MSWINDOWS - if (isArg(i, argc, argv, nullptr, "--service")) { - LOG((CLOG_WARN "obsolete argument --service, use synergyd instead.")); - argsBase.m_shouldExit = true; - } - else if (isArg(i, argc, argv, nullptr, "--exit-pause")) { - argsBase.m_pauseOnExit = true; - } - else if (isArg(i, argc, argv, nullptr, "--stop-on-desk-switch")) { - argsBase.m_stopOnDeskSwitch = true; - } - else { - // option not supported here - return false; - } - - return true; -#elif WINAPI_XWINDOWS - if (isArg(i, argc, argv, "-display", "--display", 1)) { - // use alternative display - argsBase.m_display = argv[++i]; - } - - else if (isArg(i, argc, argv, nullptr, "--no-xinitthreads")) { - argsBase.m_disableXInitThreads = true; - } - - else { - // option not supported here - return false; - } - - return true; -#elif WINAPI_CARBON - // no options for carbon + if (checkUnexpectedArgs()) { return false; + } + + return true; +} + +bool ArgParser::parseClientArgs(lib::synergy::ClientArgs &args, int argc, + const char *const *argv) { + setArgsBase(args); + updateCommonArgs(argv); + + int i{1}; + while (i < argc) { + if (parsePlatformArg(args, argc, argv, i)) { + ++i; + continue; + } else if (parseGenericArgs(argc, argv, i)) { + ++i; + continue; + } else if (parseDeprecatedArgs(argc, argv, i)) { + ++i; + continue; + } else if (isArg(i, argc, argv, nullptr, "--camp")) { + // ignore -- included for backwards compatibility + } else if (isArg(i, argc, argv, nullptr, "--no-camp")) { + // ignore -- included for backwards compatibility + } else if (isArg(i, argc, argv, nullptr, "--yscroll", 1)) { + // define scroll + args.m_yscroll = atoi(argv[++i]); + } else if (isArg(i, argc, argv, nullptr, "--sync-language")) { + args.m_enableLangSync = true; + } else if (isArg(i, argc, argv, nullptr, "--invert-scroll")) { + args.m_clientScrollDirection = + lib::synergy::ClientScrollDirection::INVERT_SERVER; + } else if (isArg(i, argc, argv, nullptr, "--host")) { + args.m_hostMode = true; + } else if (isArg(i, argc, argv, nullptr, "client")) { + ++i; + continue; + } else { + if (i + 1 == argc) { + args.m_serverAddress = argv[i]; + return true; + } + + LOG((CLOG_CRIT "%s: unrecognized option `%s'" BYE, args.m_pname, argv[i], + args.m_pname)); + return false; + } + ++i; + } + + // exactly one non-option argument (server-address) + if (i == argc) { + LOG((CLOG_CRIT "%s: a server address or name is required" BYE, args.m_pname, + args.m_pname)); + return false; + } + + if (checkUnexpectedArgs()) { + return false; + } + + return true; +} + +bool ArgParser::parsePlatformArg(lib::synergy::ArgsBase &argsBase, + const int &argc, const char *const *argv, + int &i) { +#if WINAPI_MSWINDOWS + if (isArg(i, argc, argv, nullptr, "--service")) { + LOG((CLOG_WARN "obsolete argument --service, use synergyd instead.")); + argsBase.m_shouldExit = true; + } else if (isArg(i, argc, argv, nullptr, "--exit-pause")) { + argsBase.m_pauseOnExit = true; + } else if (isArg(i, argc, argv, nullptr, "--stop-on-desk-switch")) { + argsBase.m_stopOnDeskSwitch = true; + } else { + // option not supported here + return false; + } + + return true; +#elif WINAPI_XWINDOWS + if (isArg(i, argc, argv, "-display", "--display", 1)) { + // use alternative display + argsBase.m_display = argv[++i]; + } + + else if (isArg(i, argc, argv, nullptr, "--no-xinitthreads")) { + argsBase.m_disableXInitThreads = true; + } + + else { + // option not supported here + return false; + } + + return true; +#elif WINAPI_CARBON + // no options for carbon + return false; #endif } -bool -ArgParser::parseToolArgs(ToolArgs& args, int argc, const char* const* argv) -{ - // We support exactly one argument at a fix position - static const int only_index {1}; - if (isArg(only_index, argc, argv, nullptr, "--get-active-desktop", 0)) { - args.m_printActiveDesktopName = true; - return true; - } - else if (isArg(only_index, argc, argv, nullptr, "--get-installed-dir", 0)) { - args.m_getInstalledDir = true; - return true; - } - else if (isArg(only_index, argc, argv, nullptr, "--get-profile-dir", 0)) { - args.m_getProfileDir = true; - return true; - } - else if (isArg(only_index, argc, argv, nullptr, "--get-arch", 0)) { - args.m_getArch = true; - return true; - } - return false; +bool ArgParser::parseToolArgs(ToolArgs &args, int argc, + const char *const *argv) { + // We support exactly one argument at a fix position + static const int only_index{1}; + if (isArg(only_index, argc, argv, nullptr, "--get-active-desktop", 0)) { + args.m_printActiveDesktopName = true; + return true; + } else if (isArg(only_index, argc, argv, nullptr, "--get-installed-dir", 0)) { + args.m_getInstalledDir = true; + return true; + } else if (isArg(only_index, argc, argv, nullptr, "--get-profile-dir", 0)) { + args.m_getProfileDir = true; + return true; + } else if (isArg(only_index, argc, argv, nullptr, "--get-arch", 0)) { + args.m_getArch = true; + return true; + } + return false; } -bool -ArgParser::parseGenericArgs(int argc, const char* const* argv, int& i) -{ - if (isArg(i, argc, argv, "-a", "--address", 1)) { - argsBase().m_synergyAddress = argv[++i]; +bool ArgParser::parseGenericArgs(int argc, const char *const *argv, int &i) { + if (isArg(i, argc, argv, "-a", "--address", 1)) { + argsBase().m_synergyAddress = argv[++i]; + } else if (isArg(i, argc, argv, "-d", "--debug", 1)) { + // change logging level + argsBase().m_logFilter = argv[++i]; + } else if (isArg(i, argc, argv, "-l", "--log", 1)) { + argsBase().m_logFile = argv[++i]; + } else if (isArg(i, argc, argv, "-f", "--no-daemon")) { + // not a daemon + argsBase().m_daemon = false; + } else if (isArg(i, argc, argv, nullptr, "--daemon")) { + // daemonize + argsBase().m_daemon = true; + } else if (isArg(i, argc, argv, "-n", "--name", 1)) { + // save screen name + argsBase().m_name = argv[++i]; + } else if (isArg(i, argc, argv, "-1", "--no-restart")) { + // don't try to restart + argsBase().m_restartable = false; + } else if (isArg(i, argc, argv, nullptr, "--restart")) { + // try to restart + argsBase().m_restartable = true; + } else if (isArg(i, argc, argv, nullptr, "--no-hooks")) { + argsBase().m_noHooks = true; + } else if (isArg(i, argc, argv, "-h", "--help")) { + if (m_app) { + m_app->help(); } - else if (isArg(i, argc, argv, "-d", "--debug", 1)) { - // change logging level - argsBase().m_logFilter = argv[++i]; + argsBase().m_shouldExit = true; + } else if (isArg(i, argc, argv, nullptr, "--version")) { + if (m_app) { + m_app->version(); } - else if (isArg(i, argc, argv, "-l", "--log", 1)) { - argsBase().m_logFile = argv[++i]; - } - else if (isArg(i, argc, argv, "-f", "--no-daemon")) { - // not a daemon - argsBase().m_daemon = false; - } - else if (isArg(i, argc, argv, nullptr, "--daemon")) { - // daemonize - argsBase().m_daemon = true; - } - else if (isArg(i, argc, argv, "-n", "--name", 1)) { - // save screen name - argsBase().m_name = argv[++i]; - } - else if (isArg(i, argc, argv, "-1", "--no-restart")) { - // don't try to restart - argsBase().m_restartable = false; - } - else if (isArg(i, argc, argv, nullptr, "--restart")) { - // try to restart - argsBase().m_restartable = true; - } - else if (isArg(i, argc, argv, nullptr, "--no-hooks")) { - argsBase().m_noHooks = true; - } - else if (isArg(i, argc, argv, "-h", "--help")) { - if (m_app) { - m_app->help(); - } - argsBase().m_shouldExit = true; - } - else if (isArg(i, argc, argv, nullptr, "--version")) { - if (m_app) { - m_app->version(); - } - argsBase().m_shouldExit = true; - } - else if (isArg(i, argc, argv, nullptr, "--no-tray")) { - argsBase().m_disableTray = true; - } - else if (isArg(i, argc, argv, nullptr, "--ipc")) { - argsBase().m_enableIpc = true; - } - else if (isArg(i, argc, argv, nullptr, "--server")) { - // HACK: stop error happening when using portable (synergyp) - } - else if (isArg(i, argc, argv, nullptr, "--client")) { - // HACK: stop error happening when using portable (synergyp) - } - else if (isArg(i, argc, argv, nullptr, "--enable-drag-drop")) { - bool useDragDrop = true; + argsBase().m_shouldExit = true; + } else if (isArg(i, argc, argv, nullptr, "--no-tray")) { + argsBase().m_disableTray = true; + } else if (isArg(i, argc, argv, nullptr, "--ipc")) { + argsBase().m_enableIpc = true; + } else if (isArg(i, argc, argv, nullptr, "--server")) { + // HACK: stop error happening when using portable (synergyp) + } else if (isArg(i, argc, argv, nullptr, "--client")) { + // HACK: stop error happening when using portable (synergyp) + } else if (isArg(i, argc, argv, nullptr, "--enable-drag-drop")) { + bool useDragDrop = true; #ifdef WINAPI_XWINDOWS - useDragDrop = false; - LOG((CLOG_INFO "ignoring --enable-drag-drop, not supported on linux.")); + useDragDrop = false; + LOG((CLOG_INFO "ignoring --enable-drag-drop, not supported on linux.")); #endif #ifdef WINAPI_MSWINDOWS - if (!IsWindowsVistaOrGreater()) { - useDragDrop = false; - LOG((CLOG_INFO "ignoring --enable-drag-drop, not supported below vista.")); - } + if (!IsWindowsVistaOrGreater()) { + useDragDrop = false; + LOG((CLOG_INFO + "ignoring --enable-drag-drop, not supported below vista.")); + } #endif - if (useDragDrop) { - argsBase().m_enableDragDrop = true; - } - } - else if (isArg(i, argc, argv, nullptr, "--enable-crypto")) { - argsBase().m_enableCrypto = true; - } - else if (isArg(i, argc, argv, nullptr, "--profile-dir", 1)) { - argsBase().m_profileDirectory = argv[++i]; - } - else if (isArg(i, argc, argv, nullptr, "--plugin-dir", 1)) { - argsBase().m_pluginDirectory = argv[++i]; - } - else if (isArg(i, argc, argv, nullptr, "--tls-cert", 1)) { - argsBase().m_tlsCertFile = argv[++i]; - } - else if (isArg(i, argc, argv, nullptr, "--prevent-sleep")) { - argsBase().m_preventSleep = true; - } - else { - // option not supported here - return false; + if (useDragDrop) { + argsBase().m_enableDragDrop = true; } + } else if (isArg(i, argc, argv, nullptr, "--enable-crypto")) { + argsBase().m_enableCrypto = true; + } else if (isArg(i, argc, argv, nullptr, "--profile-dir", 1)) { + argsBase().m_profileDirectory = argv[++i]; + } else if (isArg(i, argc, argv, nullptr, "--plugin-dir", 1)) { + argsBase().m_pluginDirectory = argv[++i]; + } else if (isArg(i, argc, argv, nullptr, "--tls-cert", 1)) { + argsBase().m_tlsCertFile = argv[++i]; + } else if (isArg(i, argc, argv, nullptr, "--prevent-sleep")) { + argsBase().m_preventSleep = true; + } else { + // option not supported here + return false; + } + return true; +} + +bool ArgParser::parseDeprecatedArgs(int argc, const char *const *argv, int &i) { + static const std::vector deprecatedArgs = { + "--crypto-pass", "--res-w", "--res-h", "--prm-wc", "--prm-hc"}; + + for (auto &arg : deprecatedArgs) { + if (isArg(i, argc, argv, nullptr, arg)) { + LOG((CLOG_NOTE "%s is deprecated", arg)); + i++; + return true; + } + } + + return false; +} + +bool ArgParser::isArg(int argi, int argc, const char *const *argv, + const char *name1, const char *name2, + int minRequiredParameters) { + if ((name1 != nullptr && strcmp(argv[argi], name1) == 0) || + (name2 != nullptr && strcmp(argv[argi], name2) == 0)) { + // match. check args left. + if (argi + minRequiredParameters >= argc) { + LOG((CLOG_PRINT "%s: missing arguments for `%s'" BYE, argsBase().m_pname, + argv[argi], argsBase().m_pname)); + argsBase().m_shouldExit = true; + return false; + } return true; + } + + // no match + return false; } -bool -ArgParser::parseDeprecatedArgs(int argc, const char* const* argv, int& i) -{ - static const std::vector deprecatedArgs = { - "--crypto-pass", - "--res-w", - "--res-h", - "--prm-wc", - "--prm-hc" - }; +void ArgParser::splitCommandString(String &command, std::vector &argv) { + if (command.empty()) { + return; + } - for (auto& arg : deprecatedArgs) { - if (isArg(i, argc, argv, nullptr, arg)) { - LOG((CLOG_NOTE "%s is deprecated", arg)); - i++; - return true; - } + size_t leftDoubleQuote = 0; + size_t rightDoubleQuote = 0; + searchDoubleQuotes(command, leftDoubleQuote, rightDoubleQuote); + + size_t startPos = 0; + size_t space = command.find(" ", startPos); + + while (space != String::npos) { + bool ignoreThisSpace = false; + + // check if the space is between two double quotes + if (space > leftDoubleQuote && space < rightDoubleQuote) { + ignoreThisSpace = true; + } else if (space > rightDoubleQuote) { + searchDoubleQuotes(command, leftDoubleQuote, rightDoubleQuote, + rightDoubleQuote + 1); } - return false; + if (!ignoreThisSpace) { + String subString = command.substr(startPos, space - startPos); + + removeDoubleQuotes(subString); + argv.push_back(subString); + } + + // find next space + if (ignoreThisSpace) { + space = command.find(" ", rightDoubleQuote + 1); + } else { + startPos = space + 1; + space = command.find(" ", startPos); + } + } + + String subString = command.substr(startPos, command.size()); + removeDoubleQuotes(subString); + argv.push_back(subString); } -bool -ArgParser::isArg( - int argi, int argc, const char* const* argv, - const char* name1, const char* name2, - int minRequiredParameters) -{ - if ((name1 != nullptr && strcmp(argv[argi], name1) == 0) || - (name2 != nullptr && strcmp(argv[argi], name2) == 0)) { - // match. check args left. - if (argi + minRequiredParameters >= argc) { - LOG((CLOG_PRINT "%s: missing arguments for `%s'" BYE, - argsBase().m_pname, argv[argi], argsBase().m_pname)); - argsBase().m_shouldExit = true; - return false; - } - return true; - } +bool ArgParser::searchDoubleQuotes(String &command, size_t &left, size_t &right, + size_t startPos) { + bool result = false; + left = String::npos; + right = String::npos; - // no match - return false; + left = command.find("\"", startPos); + if (left != String::npos) { + right = command.find("\"", left + 1); + if (right != String::npos) { + result = true; + } + } + + if (!result) { + left = 0; + right = 0; + } + + return result; } -void -ArgParser::splitCommandString(String& command, std::vector& argv) -{ - if (command.empty()) { - return ; - } - - size_t leftDoubleQuote = 0; - size_t rightDoubleQuote = 0; - searchDoubleQuotes(command, leftDoubleQuote, rightDoubleQuote); - - size_t startPos = 0; - size_t space = command.find(" ", startPos); - - while (space != String::npos) { - bool ignoreThisSpace = false; - - // check if the space is between two double quotes - if (space > leftDoubleQuote && space < rightDoubleQuote) { - ignoreThisSpace = true; - } - else if (space > rightDoubleQuote){ - searchDoubleQuotes(command, leftDoubleQuote, rightDoubleQuote, rightDoubleQuote + 1); - } - - if (!ignoreThisSpace) { - String subString = command.substr(startPos, space - startPos); - - removeDoubleQuotes(subString); - argv.push_back(subString); - } - - // find next space - if (ignoreThisSpace) { - space = command.find(" ", rightDoubleQuote + 1); - } - else { - startPos = space + 1; - space = command.find(" ", startPos); - } - } - - String subString = command.substr(startPos, command.size()); - removeDoubleQuotes(subString); - argv.push_back(subString); +void ArgParser::removeDoubleQuotes(String &arg) { + // if string is surrounded by double quotes, remove them + if (arg[0] == '\"' && arg[arg.size() - 1] == '\"') { + arg = arg.substr(1, arg.size() - 2); + } } -bool -ArgParser::searchDoubleQuotes(String& command, size_t& left, size_t& right, size_t startPos) -{ - bool result = false; - left = String::npos; - right = String::npos; +const char **ArgParser::getArgv(std::vector &argsArray) { + size_t argc = argsArray.size(); - left = command.find("\"", startPos); - if (left != String::npos) { - right = command.find("\"", left + 1); - if (right != String::npos) { - result = true; - } - } + // caller is responsible for deleting the outer array only + // we use the c string pointers from argsArray and assign + // them to the inner array. So caller only need to use + // delete[] to delete the outer array + const char **argv = new const char *[argc]; - if (!result) { - left = 0; - right = 0; - } + for (size_t i = 0; i < argc; i++) { + argv[i] = argsArray[i].c_str(); + } - return result; + return argv; } -void -ArgParser::removeDoubleQuotes(String& arg) -{ - // if string is surrounded by double quotes, remove them - if (arg[0] == '\"' && - arg[arg.size() - 1] == '\"') { - arg = arg.substr(1, arg.size() - 2); - } -} +String ArgParser::assembleCommand(std::vector &argsArray, + String ignoreArg, int parametersRequired) { + String result; -const char** -ArgParser::getArgv(std::vector& argsArray) -{ - size_t argc = argsArray.size(); - - // caller is responsible for deleting the outer array only - // we use the c string pointers from argsArray and assign - // them to the inner array. So caller only need to use - // delete[] to delete the outer array - const char** argv = new const char*[argc]; - - for (size_t i = 0; i < argc; i++) { - argv[i] = argsArray[i].c_str(); + for (std::vector::iterator it = argsArray.begin(); + it != argsArray.end(); ++it) { + if (it->compare(ignoreArg) == 0) { + it = it + parametersRequired; + continue; } - return argv; -} - -String -ArgParser::assembleCommand(std::vector& argsArray, String ignoreArg, int parametersRequired) -{ - String result; - - for (std::vector::iterator it = argsArray.begin(); it != argsArray.end(); ++it) { - if (it->compare(ignoreArg) == 0) { - it = it + parametersRequired; - continue; - } - - // if there is a space in this arg, use double quotes surround it - if ((*it).find(" ") != String::npos) { - (*it).insert(0, "\""); - (*it).push_back('\"'); - } - - result.append(*it); - // add space to saperate args - result.append(" "); + // if there is a space in this arg, use double quotes surround it + if ((*it).find(" ") != String::npos) { + (*it).insert(0, "\""); + (*it).push_back('\"'); } - if (!result.empty()) { - // remove the tail space - result = result.substr(0, result.size() - 1); - } + result.append(*it); + // add space to saperate args + result.append(" "); + } - return result; + if (!result.empty()) { + // remove the tail space + result = result.substr(0, result.size() - 1); + } + + return result; } -void -ArgParser::updateCommonArgs(const char* const* argv) -{ - argsBase().m_name = ARCH->getHostName(); - argsBase().m_pname = ARCH->getBasename(argv[0]); +void ArgParser::updateCommonArgs(const char *const *argv) { + argsBase().m_name = ARCH->getHostName(); + argsBase().m_pname = ARCH->getBasename(argv[0]); } -bool -ArgParser::checkUnexpectedArgs() -{ +bool ArgParser::checkUnexpectedArgs() { #if SYSAPI_WIN32 - // suggest that user installs as a windows service. when launched as - // service, process should automatically detect that it should run in - // daemon mode. - if (argsBase().m_daemon) { - LOG((CLOG_ERR - "the --daemon argument is not supported on windows. " - "instead, install %s as a service (--service install)", - argsBase().m_pname)); - return true; - } + // suggest that user installs as a windows service. when launched as + // service, process should automatically detect that it should run in + // daemon mode. + if (argsBase().m_daemon) { + LOG((CLOG_ERR "the --daemon argument is not supported on windows. " + "instead, install %s as a service (--service install)", + argsBase().m_pname)); + return true; + } #endif - return false; + return false; } diff --git a/src/lib/synergy/ArgParser.h b/src/lib/synergy/ArgParser.h index 1f5543dbd..b4bfc817e 100644 --- a/src/lib/synergy/ArgParser.h +++ b/src/lib/synergy/ArgParser.h @@ -1,11 +1,11 @@ /* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2014-2016 Symless Ltd. - * + * * 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 LICENSE 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 @@ -14,19 +14,19 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + #pragma once #include "base/String.h" #include "common/stdvector.h" namespace lib { - namespace synergy { - class ArgsBase; - class ServerArgs; - class ClientArgs; - } -} +namespace synergy { +class ArgsBase; +class ServerArgs; +class ClientArgs; +} // namespace synergy +} // namespace lib class ToolArgs; class App; @@ -34,36 +34,39 @@ class App; class ArgParser { public: - ArgParser(App* app); + ArgParser(App *app); - bool parseServerArgs(lib::synergy::ServerArgs& args, int argc, const char* const* argv); - bool parseClientArgs(lib::synergy::ClientArgs& args, int argc, const char* const* argv); - bool parsePlatformArg(lib::synergy::ArgsBase& argsBase, const int& argc, const char* const* argv, int& i); - bool parseToolArgs(ToolArgs& args, int argc, const char* const* argv); - bool parseGenericArgs(int argc, const char* const* argv, int& i); - bool parseDeprecatedArgs(int argc, const char* const* argv, int& i); - void setArgsBase(lib::synergy::ArgsBase& argsBase) { m_argsBase = &argsBase; } + bool parseServerArgs(lib::synergy::ServerArgs &args, int argc, + const char *const *argv); + bool parseClientArgs(lib::synergy::ClientArgs &args, int argc, + const char *const *argv); + bool parsePlatformArg(lib::synergy::ArgsBase &argsBase, const int &argc, + const char *const *argv, int &i); + bool parseToolArgs(ToolArgs &args, int argc, const char *const *argv); + bool parseGenericArgs(int argc, const char *const *argv, int &i); + bool parseDeprecatedArgs(int argc, const char *const *argv, int &i); + void setArgsBase(lib::synergy::ArgsBase &argsBase) { m_argsBase = &argsBase; } - static bool isArg(int argi, int argc, const char* const* argv, - const char* name1, const char* name2, - int minRequiredParameters = 0); - static void splitCommandString(String& command, std::vector& argv); - static bool searchDoubleQuotes(String& command, size_t& left, - size_t& right, size_t startPos = 0); - static void removeDoubleQuotes(String& arg); - static const char** getArgv(std::vector& argsArray); - static String assembleCommand(std::vector& argsArray, - String ignoreArg = "", int parametersRequired = 0); + static bool isArg(int argi, int argc, const char *const *argv, + const char *name1, const char *name2, + int minRequiredParameters = 0); + static void splitCommandString(String &command, std::vector &argv); + static bool searchDoubleQuotes(String &command, size_t &left, size_t &right, + size_t startPos = 0); + static void removeDoubleQuotes(String &arg); + static const char **getArgv(std::vector &argsArray); + static String assembleCommand(std::vector &argsArray, + String ignoreArg = "", + int parametersRequired = 0); - static lib::synergy::ArgsBase& argsBase() { return *m_argsBase; } + static lib::synergy::ArgsBase &argsBase() { return *m_argsBase; } private: - void updateCommonArgs(const char* const* argv); - bool checkUnexpectedArgs(); - + void updateCommonArgs(const char *const *argv); + bool checkUnexpectedArgs(); private: - App* m_app; - - static lib::synergy::ArgsBase* m_argsBase; + App *m_app; + + static lib::synergy::ArgsBase *m_argsBase; }; diff --git a/src/lib/synergy/ArgsBase.cpp b/src/lib/synergy/ArgsBase.cpp index 0f474a2e9..f7b055577 100644 --- a/src/lib/synergy/ArgsBase.cpp +++ b/src/lib/synergy/ArgsBase.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2020 Symless Ltd. * Copyright (C) 2012 Nick Bolton - * + * * 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 LICENSE 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 @@ -19,9 +19,9 @@ #include "ArgsBase.h" namespace lib { - namespace synergy { - ArgsBase::~ArgsBase() { - // - } - } -} \ No newline at end of file +namespace synergy { +ArgsBase::~ArgsBase() { + // +} +} // namespace synergy +} // namespace lib \ No newline at end of file diff --git a/src/lib/synergy/ArgsBase.h b/src/lib/synergy/ArgsBase.h index cb8a99ca0..3be1bd864 100644 --- a/src/lib/synergy/ArgsBase.h +++ b/src/lib/synergy/ArgsBase.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2020 Symless Ltd. * Copyright (C) 2012 Nick Bolton - * + * * 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 LICENSE 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 @@ -16,65 +16,73 @@ * along with this program. If not, see . */ - #ifndef SYNERGY_CORE_ARGSBASE_H #define SYNERGY_CORE_ARGSBASE_H #include "base/String.h" namespace lib { - namespace synergy { - /** - * @brief This is the base Argument class that will store the generic - * arguments passed into the applications this will be derived - * from and expanded to include application specific arguments - */ - class ArgsBase { - public: - ArgsBase() = default; - virtual ~ArgsBase(); +namespace synergy { +/** + * @brief This is the base Argument class that will store the generic + * arguments passed into the applications this will be derived + * from and expanded to include application specific arguments + */ +class ArgsBase { +public: + ArgsBase() = default; + virtual ~ArgsBase(); - /// @brief This sets the type of the derived class - enum Type { kBase, kServer, kClient }; + /// @brief This sets the type of the derived class + enum Type { kBase, kServer, kClient }; - Type m_classType = kBase; /// @brief Stores what type of object this is + Type m_classType = kBase; /// @brief Stores what type of object this is - bool m_daemon = true; /// @brief Should run as a daemon - bool m_restartable = true; /// @brief Should the app restart automatically - bool m_noHooks = false; /// @brief Should the app use hooks - const char* m_pname = nullptr; /// @brief The filename of the running process - const char* m_logFilter = nullptr; /// @brief The logging level of the application - const char* m_logFile = nullptr; /// @brief The full path to the logfile - const char* m_display = nullptr; /// @brief Contains the X-Server display to use - String m_name; /// @brief The name of the current computer - bool m_disableTray = false; /// @brief Should the app add a tray icon - bool m_enableIpc = false; /// @brief Tell the client to talk through IPC to the daemon - bool m_enableDragDrop = false; /// @brief Should drag drop support be enabled + bool m_daemon = true; /// @brief Should run as a daemon + bool m_restartable = true; /// @brief Should the app restart automatically + bool m_noHooks = false; /// @brief Should the app use hooks + const char *m_pname = nullptr; /// @brief The filename of the running process + const char *m_logFilter = + nullptr; /// @brief The logging level of the application + const char *m_logFile = nullptr; /// @brief The full path to the logfile + const char *m_display = + nullptr; /// @brief Contains the X-Server display to use + String m_name; /// @brief The name of the current computer + bool m_disableTray = false; /// @brief Should the app add a tray icon + bool m_enableIpc = + false; /// @brief Tell the client to talk through IPC to the daemon + bool m_enableDragDrop = false; /// @brief Should drag drop support be enabled - bool m_shouldExit = false; /// @brief Will cause the application to exit when set to true - String m_synergyAddress; /// @brief Bind to this address - bool m_enableCrypto = false; /// @brief Should the connections be TLS encrypted - String m_profileDirectory; /// @brief The profile DIR to use for the application - String m_pluginDirectory; /// @brief //TODO Plugins? Get set in ARCH but doesn't seem to get used - String m_tlsCertFile; /// @brief Contains the location of the TLS certificate file - bool m_preventSleep = false; /// @brief Stop this computer from sleeping + bool m_shouldExit = + false; /// @brief Will cause the application to exit when set to true + String m_synergyAddress; /// @brief Bind to this address + bool m_enableCrypto = + false; /// @brief Should the connections be TLS encrypted + String + m_profileDirectory; /// @brief The profile DIR to use for the application + String m_pluginDirectory; /// @brief //TODO Plugins? Get set in ARCH but + /// doesn't seem to get used + String m_tlsCertFile; /// @brief Contains the location of the TLS certificate + /// file + bool m_preventSleep = false; /// @brief Stop this computer from sleeping #if SYSAPI_WIN32 - bool m_debugServiceWait = false; - bool m_pauseOnExit = false; - bool m_stopOnDeskSwitch = false; + bool m_debugServiceWait = false; + bool m_pauseOnExit = false; + bool m_stopOnDeskSwitch = false; #endif #if WINAPI_XWINDOWS - bool m_disableXInitThreads = false; + bool m_disableXInitThreads = false; #endif - protected: +protected: + /// @brief deletes pointers and sets the value to null + template static inline void destroy(T *&p) { + delete p; + p = 0; + } +}; +} // namespace synergy +} // namespace lib - /// @brief deletes pointers and sets the value to null - template static inline void destroy(T*& p) { delete p; p = 0; } - - }; - } -} - -#endif //SYNERGY_CORE_ARGSBASE_H +#endif // SYNERGY_CORE_ARGSBASE_H diff --git a/src/lib/synergy/Chunk.cpp b/src/lib/synergy/Chunk.cpp index 71464f70b..28f3f0fd1 100644 --- a/src/lib/synergy/Chunk.cpp +++ b/src/lib/synergy/Chunk.cpp @@ -1,11 +1,11 @@ /* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2015-2016 Symless Ltd. - * + * * 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 LICENSE 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 @@ -18,13 +18,9 @@ #include "synergy/Chunk.h" #include "base/String.h" -Chunk::Chunk(size_t size): m_dataSize(0) -{ - m_chunk = new char[size]; - memset(m_chunk, 0, size); +Chunk::Chunk(size_t size) : m_dataSize(0) { + m_chunk = new char[size]; + memset(m_chunk, 0, size); } -Chunk::~Chunk() -{ - delete[] m_chunk; -} +Chunk::~Chunk() { delete[] m_chunk; } diff --git a/src/lib/synergy/Chunk.h b/src/lib/synergy/Chunk.h index 9ceaffec1..e6e2033dd 100644 --- a/src/lib/synergy/Chunk.h +++ b/src/lib/synergy/Chunk.h @@ -1,11 +1,11 @@ /* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2015-2016 Symless Ltd. - * + * * 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 LICENSE 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 @@ -22,15 +22,15 @@ class Chunk : public EventData { public: - Chunk(size_t size); - Chunk(Chunk const &) =delete; - Chunk(Chunk &&) =delete; - ~Chunk() override; + Chunk(size_t size); + Chunk(Chunk const &) = delete; + Chunk(Chunk &&) = delete; + ~Chunk() override; - Chunk& operator=(Chunk const &) =delete; - Chunk& operator=(Chunk &&) =delete; + Chunk &operator=(Chunk const &) = delete; + Chunk &operator=(Chunk &&) = delete; public: - size_t m_dataSize; - char* m_chunk; + size_t m_dataSize; + char *m_chunk; }; diff --git a/src/lib/synergy/ClientApp.cpp b/src/lib/synergy/ClientApp.cpp index aa262cd5e..0189ac4d4 100644 --- a/src/lib/synergy/ClientApp.cpp +++ b/src/lib/synergy/ClientApp.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -18,29 +18,29 @@ #include "synergy/ClientApp.h" +#include "arch/Arch.h" +#include "arch/IArchTaskBarReceiver.h" +#include "base/Event.h" +#include "base/EventQueue.h" +#include "base/IEventQueue.h" +#include "base/Log.h" +#include "base/String.h" +#include "base/TMethodEventJob.h" +#include "base/TMethodJob.h" +#include "base/log_outputters.h" #include "client/Client.h" +#include "common/Version.h" +#include "mt/Thread.h" +#include "net/InverseSockets/InverseSocketFactory.h" +#include "net/NetworkAddress.h" +#include "net/SocketMultiplexer.h" +#include "net/TCPSocketFactory.h" +#include "net/XSocket.h" #include "synergy/ArgParser.h" -#include "synergy/protocol_types.h" +#include "synergy/ClientArgs.h" #include "synergy/Screen.h" #include "synergy/XScreen.h" -#include "synergy/ClientArgs.h" -#include "net/NetworkAddress.h" -#include "net/TCPSocketFactory.h" -#include "net/InverseSockets/InverseSocketFactory.h" -#include "net/SocketMultiplexer.h" -#include "net/XSocket.h" -#include "mt/Thread.h" -#include "arch/IArchTaskBarReceiver.h" -#include "arch/Arch.h" -#include "base/String.h" -#include "base/Event.h" -#include "base/IEventQueue.h" -#include "base/TMethodEventJob.h" -#include "base/log_outputters.h" -#include "base/EventQueue.h" -#include "base/TMethodJob.h" -#include "base/Log.h" -#include "common/Version.h" +#include "synergy/protocol_types.h" #if SYSAPI_WIN32 #include "arch/win32/ArchMiscWindows.h" @@ -64,551 +64,454 @@ #define RETRY_TIME 1.0 -ClientApp::ClientApp(IEventQueue* events, CreateTaskBarReceiverFunc createTaskBarReceiver) : - App(events, createTaskBarReceiver, new lib::synergy::ClientArgs()), - m_client(NULL), - m_clientScreen(NULL), - m_serverAddress(NULL) -{ -} +ClientApp::ClientApp(IEventQueue *events, + CreateTaskBarReceiverFunc createTaskBarReceiver) + : App(events, createTaskBarReceiver, new lib::synergy::ClientArgs()), + m_client(NULL), m_clientScreen(NULL), m_serverAddress(NULL) {} -ClientApp::~ClientApp() -{ -} +ClientApp::~ClientApp() {} -void -ClientApp::parseArgs(int argc, const char* const* argv) -{ - ArgParser argParser(this); - bool result = argParser.parseClientArgs(args(), argc, argv); +void ClientApp::parseArgs(int argc, const char *const *argv) { + ArgParser argParser(this); + bool result = argParser.parseClientArgs(args(), argc, argv); - if (!result || args().m_shouldExit) { - m_bye(kExitArgs); - } - else { - // save server address - if (!args().m_serverAddress.empty()) { - try { - *m_serverAddress = NetworkAddress(args().m_serverAddress, kDefaultPort); - m_serverAddress->resolve(); - } - catch (XSocketAddress& e) { - // allow an address that we can't look up if we're restartable. - // we'll try to resolve the address each time we connect to the - // server. a bad port will never get better. patch by Brent - // Priddy. - if (!args().m_restartable || e.getError() == XSocketAddress::kBadPort) { - LOG((CLOG_CRIT "%s: %s" BYE, - args().m_pname, e.what(), args().m_pname)); - m_bye(kExitFailed); - } - } + if (!result || args().m_shouldExit) { + m_bye(kExitArgs); + } else { + // save server address + if (!args().m_serverAddress.empty()) { + try { + *m_serverAddress = NetworkAddress(args().m_serverAddress, kDefaultPort); + m_serverAddress->resolve(); + } catch (XSocketAddress &e) { + // allow an address that we can't look up if we're restartable. + // we'll try to resolve the address each time we connect to the + // server. a bad port will never get better. patch by Brent + // Priddy. + if (!args().m_restartable || e.getError() == XSocketAddress::kBadPort) { + LOG((CLOG_CRIT "%s: %s" BYE, args().m_pname, e.what(), + args().m_pname)); + m_bye(kExitFailed); } + } } + } } -void -ClientApp::help() -{ +void ClientApp::help() { #if WINAPI_XWINDOWS -# define WINAPI_ARG \ - " [--display ] [--no-xinitthreads]" -# define WINAPI_INFO \ - " --display connect to the X server at \n" \ - " --no-xinitthreads do not call XInitThreads()\n" +#define WINAPI_ARG " [--display ] [--no-xinitthreads]" +#define WINAPI_INFO \ + " --display connect to the X server at \n" \ + " --no-xinitthreads do not call XInitThreads()\n" #else -# define WINAPI_ARG "" -# define WINAPI_INFO "" +#define WINAPI_ARG "" +#define WINAPI_INFO "" #endif - std::stringstream help; - help<< "Usage: " << args().m_pname - <<" [--address
]" - <<" [--yscroll ]" - <<" [--sync-language]" - <<" [--invert-scroll]" - <<" [--host]" - <" - <<"\n\n" - <<"Connect to a synergy mouse/keyboard sharing server.\n" - <<"\n" - <<" -a, --address
local network interface address.\n" - < defines the vertical scrolling delta, which is\n" - <<" 120 by default.\n" - <<" --sync-language set this parameter to enable language synchronization.\n" - <<" --invert-scroll invert scroll direction on this computer.\n" - <<" --host client starts a listener and waits for a server connection.\n" - <][:]. The hostname\n" - <<"must be the address or hostname of the server. The port overrides the\n" - <<"default port, " << kDefaultPort <<".\n"; + std::stringstream help; + help << "Usage: " << args().m_pname << " [--address
]" + << " [--yscroll ]" + << " [--sync-language]" + << " [--invert-scroll]" + << " [--host]" << WINAPI_ARG << HELP_SYS_ARGS << HELP_COMMON_ARGS + << " " + << "\n\n" + << "Connect to a synergy mouse/keyboard sharing server.\n" + << "\n" + << " -a, --address
local network interface address.\n" + << HELP_COMMON_INFO_1 << WINAPI_INFO << HELP_SYS_INFO + << " --yscroll defines the vertical scrolling delta, " + "which is\n" + << " 120 by default.\n" + << " --sync-language set this parameter to enable language " + "synchronization.\n" + << " --invert-scroll invert scroll direction on this " + "computer.\n" + << " --host client starts a listener and waits for a " + "server connection.\n" + << HELP_COMMON_INFO_2 << "\n" + << "* marks defaults.\n" + << "\n" + << "The server address is of the form: [][:]. The " + "hostname\n" + << "must be the address or hostname of the server. The port overrides " + "the\n" + << "default port, " << kDefaultPort << ".\n"; - LOG((CLOG_PRINT "%s", help.str().c_str())); + LOG((CLOG_PRINT "%s", help.str().c_str())); } -const char* -ClientApp::daemonName() const -{ +const char *ClientApp::daemonName() const { #if SYSAPI_WIN32 - return "Synergy Client"; + return "Synergy Client"; #elif SYSAPI_UNIX - return "synergyc"; + return "synergyc"; #endif } -const char* -ClientApp::daemonInfo() const -{ +const char *ClientApp::daemonInfo() const { #if SYSAPI_WIN32 - return "Allows another computer to share it's keyboard and mouse with this computer."; + return "Allows another computer to share it's keyboard and mouse with this " + "computer."; #elif SYSAPI_UNIX - return ""; + return ""; #endif } -synergy::Screen* -ClientApp::createScreen() -{ +synergy::Screen *ClientApp::createScreen() { #if WINAPI_MSWINDOWS - return new synergy::Screen(new MSWindowsScreen( - false, args().m_noHooks, args().m_stopOnDeskSwitch, m_events, - args().m_enableLangSync, args().m_clientScrollDirection), m_events); + return new synergy::Screen( + new MSWindowsScreen(false, args().m_noHooks, args().m_stopOnDeskSwitch, + m_events, args().m_enableLangSync, + args().m_clientScrollDirection), + m_events); #elif WINAPI_XWINDOWS - return new synergy::Screen(new XWindowsScreen( - args().m_display, false, args().m_disableXInitThreads, - args().m_yscroll, m_events, args().m_clientScrollDirection), m_events); + return new synergy::Screen(new XWindowsScreen(args().m_display, false, + args().m_disableXInitThreads, + args().m_yscroll, m_events, + args().m_clientScrollDirection), + m_events); #elif WINAPI_CARBON - return new synergy::Screen(new OSXScreen(m_events, false, - args().m_enableLangSync, - args().m_clientScrollDirection), - m_events); + return new synergy::Screen(new OSXScreen(m_events, false, + args().m_enableLangSync, + args().m_clientScrollDirection), + m_events); #endif } -void -ClientApp::updateStatus() -{ - updateStatus(""); +void ClientApp::updateStatus() { updateStatus(""); } + +void ClientApp::updateStatus(const String &msg) { + if (m_taskBarReceiver) { + m_taskBarReceiver->updateStatus(m_client, msg); + } } - -void -ClientApp::updateStatus(const String& msg) -{ - if (m_taskBarReceiver) - { - m_taskBarReceiver->updateStatus(m_client, msg); - } +void ClientApp::resetRestartTimeout() { + // retry time can nolonger be changed + // s_retryTime = 0.0; } +double ClientApp::nextRestartTimeout() { + // retry at a constant rate (Issue 52) + return RETRY_TIME; -void -ClientApp::resetRestartTimeout() -{ - // retry time can nolonger be changed - //s_retryTime = 0.0; + /* + // choose next restart timeout. we start with rapid retries + // then slow down. + if (s_retryTime < 1.0) { + s_retryTime = 1.0; + } + else if (s_retryTime < 3.0) { + s_retryTime = 3.0; + } + else { + s_retryTime = 5.0; + } + return s_retryTime; + */ } - -double -ClientApp::nextRestartTimeout() -{ - // retry at a constant rate (Issue 52) - return RETRY_TIME; - - /* - // choose next restart timeout. we start with rapid retries - // then slow down. - if (s_retryTime < 1.0) { - s_retryTime = 1.0; - } - else if (s_retryTime < 3.0) { - s_retryTime = 3.0; - } - else { - s_retryTime = 5.0; - } - return s_retryTime; - */ +void ClientApp::handleScreenError(const Event &, void *) { + LOG((CLOG_CRIT "error on screen")); + m_events->addEvent(Event(Event::kQuit)); } +synergy::Screen *ClientApp::openClientScreen() { + synergy::Screen *screen = createScreen(); + screen->setEnableDragDrop(argsBase().m_enableDragDrop); + m_events->adoptHandler( + m_events->forIScreen().error(), screen->getEventTarget(), + new TMethodEventJob(this, &ClientApp::handleScreenError)); + return screen; +} -void -ClientApp::handleScreenError(const Event&, void*) -{ - LOG((CLOG_CRIT "error on screen")); +void ClientApp::closeClientScreen(synergy::Screen *screen) { + if (screen != NULL) { + m_events->removeHandler(m_events->forIScreen().error(), + screen->getEventTarget()); + delete screen; + } +} + +void ClientApp::handleClientRestart(const Event &, void *vtimer) { + // discard old timer + EventQueueTimer *timer = static_cast(vtimer); + m_events->deleteTimer(timer); + m_events->removeHandler(Event::kTimer, timer); + + // reconnect + startClient(); +} + +void ClientApp::scheduleClientRestart(double retryTime) { + // install a timer and handler to retry later + LOG((CLOG_DEBUG "retry in %.0f seconds", retryTime)); + EventQueueTimer *timer = m_events->newOneShotTimer(retryTime, NULL); + m_events->adoptHandler(Event::kTimer, timer, + new TMethodEventJob( + this, &ClientApp::handleClientRestart, timer)); +} + +void ClientApp::handleClientConnected(const Event &, void *) { + LOG((CLOG_NOTE "connected to server")); + resetRestartTimeout(); + updateStatus(); +} + +void ClientApp::handleClientFailed(const Event &e, void *) { + if ((++m_lastServerAddressIndex) < + m_client->getLastResolvedAddressesCount()) { + std::unique_ptr info( + static_cast(e.getData())); + + updateStatus(String("Failed to connect to server: ") + info->m_what + + " Trying next address..."); + LOG((CLOG_NOTE "failed to connect to server=%s, trying next address", + info->m_what.c_str())); + if (!m_suspended) { + scheduleClientRestart(nextRestartTimeout()); + } + } else { + m_lastServerAddressIndex = 0; + handleClientRefused(e, nullptr); + } +} + +void ClientApp::handleClientRefused(const Event &e, void *) { + std::unique_ptr info( + static_cast(e.getData())); + + updateStatus(String("Failed to connect to server: ") + info->m_what); + if (!args().m_restartable || !info->m_retry) { + LOG((CLOG_ERR "failed to connect to server: %s", info->m_what.c_str())); m_events->addEvent(Event(Event::kQuit)); -} - - -synergy::Screen* -ClientApp::openClientScreen() -{ - synergy::Screen* screen = createScreen(); - screen->setEnableDragDrop(argsBase().m_enableDragDrop); - m_events->adoptHandler(m_events->forIScreen().error(), - screen->getEventTarget(), - new TMethodEventJob( - this, &ClientApp::handleScreenError)); - return screen; -} - - -void -ClientApp::closeClientScreen(synergy::Screen* screen) -{ - if (screen != NULL) { - m_events->removeHandler(m_events->forIScreen().error(), - screen->getEventTarget()); - delete screen; + } else { + LOG((CLOG_WARN "failed to connect to server: %s", info->m_what.c_str())); + if (!m_suspended) { + scheduleClientRestart(nextRestartTimeout()); } + } } - -void -ClientApp::handleClientRestart(const Event&, void* vtimer) -{ - // discard old timer - EventQueueTimer* timer = static_cast(vtimer); - m_events->deleteTimer(timer); - m_events->removeHandler(Event::kTimer, timer); - - // reconnect - startClient(); +void ClientApp::handleClientDisconnected(const Event &, void *) { + LOG((CLOG_NOTE "disconnected from server")); + if (!args().m_restartable) { + m_events->addEvent(Event(Event::kQuit)); + } else if (!m_suspended) { + scheduleClientRestart(nextRestartTimeout()); + } + updateStatus(); } +Client *ClientApp::openClient(const String &name, const NetworkAddress &address, + synergy::Screen *screen) { + Client *client = + new Client(m_events, name, address, getSocketFactory(), screen, args()); -void -ClientApp::scheduleClientRestart(double retryTime) -{ - // install a timer and handler to retry later - LOG((CLOG_DEBUG "retry in %.0f seconds", retryTime)); - EventQueueTimer* timer = m_events->newOneShotTimer(retryTime, NULL); - m_events->adoptHandler(Event::kTimer, timer, - new TMethodEventJob(this, &ClientApp::handleClientRestart, timer)); -} + try { + m_events->adoptHandler(m_events->forClient().connected(), + client->getEventTarget(), + new TMethodEventJob( + this, &ClientApp::handleClientConnected)); + m_events->adoptHandler( + m_events->forClient().connectionFailed(), client->getEventTarget(), + new TMethodEventJob(this, &ClientApp::handleClientFailed)); -void -ClientApp::handleClientConnected(const Event&, void*) -{ - LOG((CLOG_NOTE "connected to server")); - resetRestartTimeout(); - updateStatus(); -} + m_events->adoptHandler( + m_events->forClient().connectionRefused(), client->getEventTarget(), + new TMethodEventJob(this, &ClientApp::handleClientRefused)); + m_events->adoptHandler(m_events->forClient().disconnected(), + client->getEventTarget(), + new TMethodEventJob( + this, &ClientApp::handleClientDisconnected)); -void -ClientApp::handleClientFailed(const Event& e, void*) -{ - if ( (++m_lastServerAddressIndex) < m_client->getLastResolvedAddressesCount()) { - std::unique_ptr info(static_cast(e.getData())); - - updateStatus(String("Failed to connect to server: ") + info->m_what + " Trying next address..."); - LOG((CLOG_NOTE "failed to connect to server=%s, trying next address", info->m_what.c_str())); - if (!m_suspended) { - scheduleClientRestart(nextRestartTimeout()); - } - } - else { - m_lastServerAddressIndex = 0; - handleClientRefused(e, nullptr); - } - -} - -void -ClientApp::handleClientRefused(const Event& e, void*) -{ - std::unique_ptr info(static_cast(e.getData())); - - updateStatus(String("Failed to connect to server: ") + info->m_what); - if (!args().m_restartable || !info->m_retry) { - LOG((CLOG_ERR "failed to connect to server: %s", info->m_what.c_str())); - m_events->addEvent(Event(Event::kQuit)); - } - else { - LOG((CLOG_WARN "failed to connect to server: %s", info->m_what.c_str())); - if (!m_suspended) { - scheduleClientRestart(nextRestartTimeout()); - } - } -} - - -void -ClientApp::handleClientDisconnected(const Event&, void*) -{ - LOG((CLOG_NOTE "disconnected from server")); - if (!args().m_restartable) { - m_events->addEvent(Event(Event::kQuit)); - } - else if (!m_suspended) { - scheduleClientRestart(nextRestartTimeout()); - } - updateStatus(); -} - -Client* -ClientApp::openClient(const String& name, const NetworkAddress& address, - synergy::Screen* screen) -{ - Client* client = new Client( - m_events, - name, - address, - getSocketFactory(), - screen, - args()); - - try { - m_events->adoptHandler( - m_events->forClient().connected(), - client->getEventTarget(), - new TMethodEventJob(this, &ClientApp::handleClientConnected)); - - m_events->adoptHandler( - m_events->forClient().connectionFailed(), - client->getEventTarget(), - new TMethodEventJob(this, &ClientApp::handleClientFailed)); - - m_events->adoptHandler( - m_events->forClient().connectionRefused(), - client->getEventTarget(), - new TMethodEventJob(this, &ClientApp::handleClientRefused)); - - m_events->adoptHandler( - m_events->forClient().disconnected(), - client->getEventTarget(), - new TMethodEventJob(this, &ClientApp::handleClientDisconnected)); - - } catch (std::bad_alloc &ba) { - delete client; - throw ba; - } - - return client; -} - - -void -ClientApp::closeClient(Client* client) -{ - if (client == NULL) { - return; - } - - m_events->removeHandler(m_events->forClient().connected(), client); - m_events->removeHandler(m_events->forClient().connectionFailed(), client); - m_events->removeHandler(m_events->forClient().connectionRefused(), client); - m_events->removeHandler(m_events->forClient().disconnected(), client); + } catch (std::bad_alloc &ba) { delete client; + throw ba; + } + + return client; } -int -ClientApp::foregroundStartup(int argc, char** argv) -{ - initApp(argc, argv); +void ClientApp::closeClient(Client *client) { + if (client == NULL) { + return; + } - // never daemonize - return mainLoop(); + m_events->removeHandler(m_events->forClient().connected(), client); + m_events->removeHandler(m_events->forClient().connectionFailed(), client); + m_events->removeHandler(m_events->forClient().connectionRefused(), client); + m_events->removeHandler(m_events->forClient().disconnected(), client); + delete client; } -bool -ClientApp::startClient() -{ - double retryTime; - synergy::Screen* clientScreen = NULL; - try { - if (m_clientScreen == NULL) { - clientScreen = openClientScreen(); - m_client = openClient(args().m_name, - *m_serverAddress, clientScreen); - m_clientScreen = clientScreen; - LOG((CLOG_NOTE "started client")); - } +int ClientApp::foregroundStartup(int argc, char **argv) { + initApp(argc, argv); - m_client->connect(m_lastServerAddressIndex); - - updateStatus(); - return true; - } - catch (XScreenUnavailable& e) { - LOG((CLOG_WARN "secondary screen unavailable: %s", e.what())); - closeClientScreen(clientScreen); - updateStatus(String("secondary screen unavailable: ") + e.what()); - retryTime = e.getRetryTime(); - } - catch (XScreenOpenFailure& e) { - LOG((CLOG_CRIT "failed to start client: %s", e.what())); - closeClientScreen(clientScreen); - return false; - } - catch (XBase& e) { - LOG((CLOG_CRIT "failed to start client: %s", e.what())); - closeClientScreen(clientScreen); - return false; - } - - if (args().m_restartable) { - scheduleClientRestart(retryTime); - return true; - } - else { - // don't try again - return false; - } + // never daemonize + return mainLoop(); } - -void -ClientApp::stopClient() -{ - closeClient(m_client); - closeClientScreen(m_clientScreen); - m_client = NULL; - m_clientScreen = NULL; -} - - -int -ClientApp::mainLoop() -{ - // create socket multiplexer. this must happen after daemonization - // on unix because threads evaporate across a fork(). - SocketMultiplexer multiplexer; - setSocketMultiplexer(&multiplexer); - - // start client, etc - appUtil().startNode(); - - // init ipc client after node start, since create a new screen wipes out - // the event queue (the screen ctors call adoptBuffer). - if (argsBase().m_enableIpc) { - initIpcClient(); +bool ClientApp::startClient() { + double retryTime; + synergy::Screen *clientScreen = NULL; + try { + if (m_clientScreen == NULL) { + clientScreen = openClientScreen(); + m_client = openClient(args().m_name, *m_serverAddress, clientScreen); + m_clientScreen = clientScreen; + LOG((CLOG_NOTE "started client")); } - // run event loop. if startClient() failed we're supposed to retry - // later. the timer installed by startClient() will take care of - // that. - DAEMON_RUNNING(true); - -#if defined(MAC_OS_X_VERSION_10_7) - - Thread thread( - new TMethodJob( - this, &ClientApp::runEventsLoop, - NULL)); - - // wait until carbon loop is ready - OSXScreen* screen = dynamic_cast( - m_clientScreen->getPlatformScreen()); - screen->waitForCarbonLoop(); - - runCocoaApp(); -#else - m_events->loop(); -#endif - - DAEMON_RUNNING(false); + m_client->connect(m_lastServerAddressIndex); - // close down - LOG((CLOG_DEBUG1 "stopping client")); - stopClient(); updateStatus(); - LOG((CLOG_NOTE "stopped client")); + return true; + } catch (XScreenUnavailable &e) { + LOG((CLOG_WARN "secondary screen unavailable: %s", e.what())); + closeClientScreen(clientScreen); + updateStatus(String("secondary screen unavailable: ") + e.what()); + retryTime = e.getRetryTime(); + } catch (XScreenOpenFailure &e) { + LOG((CLOG_CRIT "failed to start client: %s", e.what())); + closeClientScreen(clientScreen); + return false; + } catch (XBase &e) { + LOG((CLOG_CRIT "failed to start client: %s", e.what())); + closeClientScreen(clientScreen); + return false; + } - if (argsBase().m_enableIpc) { - cleanupIpcClient(); - } - - return kExitSuccess; + if (args().m_restartable) { + scheduleClientRestart(retryTime); + return true; + } else { + // don't try again + return false; + } } -static -int -daemonMainLoopStatic(int argc, const char** argv) -{ - return ClientApp::instance().daemonMainLoop(argc, argv); +void ClientApp::stopClient() { + closeClient(m_client); + closeClientScreen(m_clientScreen); + m_client = NULL; + m_clientScreen = NULL; } -int -ClientApp::standardStartup(int argc, char** argv) -{ - initApp(argc, argv); +int ClientApp::mainLoop() { + // create socket multiplexer. this must happen after daemonization + // on unix because threads evaporate across a fork(). + SocketMultiplexer multiplexer; + setSocketMultiplexer(&multiplexer); - // daemonize if requested - if (args().m_daemon) { - return ARCH->daemonize(daemonName(), &daemonMainLoopStatic); - } - else { - return mainLoop(); - } + // start client, etc + appUtil().startNode(); + + // init ipc client after node start, since create a new screen wipes out + // the event queue (the screen ctors call adoptBuffer). + if (argsBase().m_enableIpc) { + initIpcClient(); + } + + // run event loop. if startClient() failed we're supposed to retry + // later. the timer installed by startClient() will take care of + // that. + DAEMON_RUNNING(true); + +#if defined(MAC_OS_X_VERSION_10_7) + + Thread thread( + new TMethodJob(this, &ClientApp::runEventsLoop, NULL)); + + // wait until carbon loop is ready + OSXScreen *screen = + dynamic_cast(m_clientScreen->getPlatformScreen()); + screen->waitForCarbonLoop(); + + runCocoaApp(); +#else + m_events->loop(); +#endif + + DAEMON_RUNNING(false); + + // close down + LOG((CLOG_DEBUG1 "stopping client")); + stopClient(); + updateStatus(); + LOG((CLOG_NOTE "stopped client")); + + if (argsBase().m_enableIpc) { + cleanupIpcClient(); + } + + return kExitSuccess; } -int -ClientApp::runInner(int argc, char** argv, ILogOutputter* outputter, StartupFunc startup) -{ - // general initialization - m_serverAddress = new NetworkAddress; - args().m_pname = ARCH->getBasename(argv[0]); - - // install caller's output filter - if (outputter != NULL) { - CLOG->insert(outputter); - } - - int result; - try - { - // run - result = startup(argc, argv); - } - catch (...) - { - if (m_taskBarReceiver) - { - // done with task bar receiver - delete m_taskBarReceiver; - } - - delete m_serverAddress; - - throw; - } - - return result; +static int daemonMainLoopStatic(int argc, const char **argv) { + return ClientApp::instance().daemonMainLoop(argc, argv); } -void -ClientApp::startNode() -{ - // start the client. if this return false then we've failed and - // we shouldn't retry. - LOG((CLOG_DEBUG1 "starting client")); - if (!startClient()) { - m_bye(kExitFailed); - } +int ClientApp::standardStartup(int argc, char **argv) { + initApp(argc, argv); + + // daemonize if requested + if (args().m_daemon) { + return ARCH->daemonize(daemonName(), &daemonMainLoopStatic); + } else { + return mainLoop(); + } } -ISocketFactory* ClientApp::getSocketFactory() const -{ - ISocketFactory* socketFactory = nullptr; +int ClientApp::runInner(int argc, char **argv, ILogOutputter *outputter, + StartupFunc startup) { + // general initialization + m_serverAddress = new NetworkAddress; + args().m_pname = ARCH->getBasename(argv[0]); - if (args().m_hostMode) { - socketFactory = new InverseSocketFactory(m_events, getSocketMultiplexer()); - } - else { - socketFactory = new TCPSocketFactory(m_events, getSocketMultiplexer()); + // install caller's output filter + if (outputter != NULL) { + CLOG->insert(outputter); + } + + int result; + try { + // run + result = startup(argc, argv); + } catch (...) { + if (m_taskBarReceiver) { + // done with task bar receiver + delete m_taskBarReceiver; } - return socketFactory; + delete m_serverAddress; + + throw; + } + + return result; +} + +void ClientApp::startNode() { + // start the client. if this return false then we've failed and + // we shouldn't retry. + LOG((CLOG_DEBUG1 "starting client")); + if (!startClient()) { + m_bye(kExitFailed); + } +} + +ISocketFactory *ClientApp::getSocketFactory() const { + ISocketFactory *socketFactory = nullptr; + + if (args().m_hostMode) { + socketFactory = new InverseSocketFactory(m_events, getSocketMultiplexer()); + } else { + socketFactory = new TCPSocketFactory(m_events, getSocketMultiplexer()); + } + + return socketFactory; } diff --git a/src/lib/synergy/ClientApp.h b/src/lib/synergy/ClientApp.h index b1d6d3b8a..6229b84e9 100644 --- a/src/lib/synergy/ClientApp.h +++ b/src/lib/synergy/ClientApp.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -20,73 +20,79 @@ #include "synergy/App.h" -namespace synergy { class Screen; } +namespace synergy { +class Screen; +} class Event; class Client; class NetworkAddress; class Thread; class ISocketFactory; namespace lib { - namespace synergy { - class ClientArgs; - } +namespace synergy { +class ClientArgs; } +} // namespace lib class ClientApp : public App { public: - ClientApp(IEventQueue* events, CreateTaskBarReceiverFunc createTaskBarReceiver); - virtual ~ClientApp(); + ClientApp(IEventQueue *events, + CreateTaskBarReceiverFunc createTaskBarReceiver); + virtual ~ClientApp(); - // Parse client specific command line arguments. - void parseArgs(int argc, const char* const* argv); + // Parse client specific command line arguments. + void parseArgs(int argc, const char *const *argv); - // Prints help specific to client. - void help(); + // Prints help specific to client. + void help(); - // Returns arguments that are common and for client. - lib::synergy::ClientArgs& args() const { return (lib::synergy::ClientArgs&)argsBase(); } + // Returns arguments that are common and for client. + lib::synergy::ClientArgs &args() const { + return (lib::synergy::ClientArgs &)argsBase(); + } - const char* daemonName() const; - const char* daemonInfo() const; + const char *daemonName() const; + const char *daemonInfo() const; - // TODO: move to server only (not supported on client) - void loadConfig() { } - bool loadConfig(const String& pathname) { return false; } + // TODO: move to server only (not supported on client) + void loadConfig() {} + bool loadConfig(const String &pathname) { return false; } - int foregroundStartup(int argc, char** argv); - int standardStartup(int argc, char** argv); - int runInner(int argc, char** argv, ILogOutputter* outputter, StartupFunc startup); - synergy::Screen* createScreen(); - void updateStatus(); - void updateStatus(const String& msg); - void resetRestartTimeout(); - double nextRestartTimeout(); - void handleScreenError(const Event&, void*); - synergy::Screen* openClientScreen(); - void closeClientScreen(synergy::Screen* screen); - void handleClientRestart(const Event&, void* vtimer); - void scheduleClientRestart(double retryTime); - void handleClientConnected(const Event&, void*); - void handleClientFailed(const Event& e, void*); - void handleClientRefused(const Event& e, void*); - void handleClientDisconnected(const Event&, void*); - Client* openClient(const String& name, const NetworkAddress& address, - synergy::Screen* screen); - void closeClient(Client* client); - bool startClient(); - void stopClient(); - int mainLoop(); - void startNode(); + int foregroundStartup(int argc, char **argv); + int standardStartup(int argc, char **argv); + int runInner(int argc, char **argv, ILogOutputter *outputter, + StartupFunc startup); + synergy::Screen *createScreen(); + void updateStatus(); + void updateStatus(const String &msg); + void resetRestartTimeout(); + double nextRestartTimeout(); + void handleScreenError(const Event &, void *); + synergy::Screen *openClientScreen(); + void closeClientScreen(synergy::Screen *screen); + void handleClientRestart(const Event &, void *vtimer); + void scheduleClientRestart(double retryTime); + void handleClientConnected(const Event &, void *); + void handleClientFailed(const Event &e, void *); + void handleClientRefused(const Event &e, void *); + void handleClientDisconnected(const Event &, void *); + Client *openClient(const String &name, const NetworkAddress &address, + synergy::Screen *screen); + void closeClient(Client *client); + bool startClient(); + void stopClient(); + int mainLoop(); + void startNode(); - static ClientApp& instance() { return (ClientApp&)App::instance(); } + static ClientApp &instance() { return (ClientApp &)App::instance(); } - Client* getClientPtr() { return m_client; } + Client *getClientPtr() { return m_client; } private: - ISocketFactory* getSocketFactory() const; + ISocketFactory *getSocketFactory() const; - Client* m_client; - synergy::Screen* m_clientScreen; - NetworkAddress* m_serverAddress; - size_t m_lastServerAddressIndex = 0; + Client *m_client; + synergy::Screen *m_clientScreen; + NetworkAddress *m_serverAddress; + size_t m_lastServerAddressIndex = 0; }; diff --git a/src/lib/synergy/ClientArgs.cpp b/src/lib/synergy/ClientArgs.cpp index 67f75b46d..71b28bed7 100644 --- a/src/lib/synergy/ClientArgs.cpp +++ b/src/lib/synergy/ClientArgs.cpp @@ -1,11 +1,11 @@ /* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2014-2016 Symless Ltd. - * + * * 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 LICENSE 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 @@ -18,14 +18,10 @@ #include "ClientArgs.h" namespace lib { - namespace synergy { +namespace synergy { - ClientArgs::~ClientArgs() { +ClientArgs::~ClientArgs() {} - } - - ClientArgs::ClientArgs() { - m_classType = kClient; - } - } -} \ No newline at end of file +ClientArgs::ClientArgs() { m_classType = kClient; } +} // namespace synergy +} // namespace lib \ No newline at end of file diff --git a/src/lib/synergy/ClientArgs.h b/src/lib/synergy/ClientArgs.h index 3d59be399..5c8fe8750 100644 --- a/src/lib/synergy/ClientArgs.h +++ b/src/lib/synergy/ClientArgs.h @@ -1,11 +1,11 @@ /* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2014-2016 Symless Ltd. - * + * * 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 LICENSE 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 @@ -20,44 +20,40 @@ #include "ArgsBase.h" - namespace lib { - namespace synergy { - enum ClientScrollDirection { - SERVER = 1, - INVERT_SERVER = -1 - }; +namespace synergy { +enum ClientScrollDirection { SERVER = 1, INVERT_SERVER = -1 }; - class ClientArgs : public ArgsBase { +class ClientArgs : public ArgsBase { - /// Public functions - public: - ClientArgs(); + /// Public functions +public: + ClientArgs(); - ~ClientArgs() override; + ~ClientArgs() override; - public: - int m_yscroll = 0; - bool m_enableLangSync = false; /// @brief Should keyboard input be in same language as on server +public: + int m_yscroll = 0; + bool m_enableLangSync = + false; /// @brief Should keyboard input be in same language as on server - /** - * @brief m_clientScrollDirection - * This option is responcible for scroll direction on client side. - */ - ClientScrollDirection m_clientScrollDirection = ClientScrollDirection::SERVER; + /** + * @brief m_clientScrollDirection + * This option is responcible for scroll direction on client side. + */ + ClientScrollDirection m_clientScrollDirection = ClientScrollDirection::SERVER; - /** - * @brief m_hostMode - activates host mode. - * Client starts a listener and waits for a server connection. - */ - bool m_hostMode = false; + /** + * @brief m_hostMode - activates host mode. + * Client starts a listener and waits for a server connection. + */ + bool m_hostMode = false; - /** - * @brief m_serverAddress stores synergy server address - */ - std::string m_serverAddress; - - }; - } -} -#endif //SYNERGY_CORE_CLIENTARGS_H + /** + * @brief m_serverAddress stores synergy server address + */ + std::string m_serverAddress; +}; +} // namespace synergy +} // namespace lib +#endif // SYNERGY_CORE_CLIENTARGS_H diff --git a/src/lib/synergy/ClientTaskBarReceiver.cpp b/src/lib/synergy/ClientTaskBarReceiver.cpp index d49175dad..ecbaae628 100644 --- a/src/lib/synergy/ClientTaskBarReceiver.cpp +++ b/src/lib/synergy/ClientTaskBarReceiver.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2003 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 LICENSE 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 @@ -17,125 +17,101 @@ */ #include "synergy/ClientTaskBarReceiver.h" -#include "client/Client.h" -#include "mt/Lock.h" -#include "base/String.h" -#include "base/IEventQueue.h" #include "arch/Arch.h" +#include "base/IEventQueue.h" +#include "base/String.h" +#include "client/Client.h" #include "common/Version.h" +#include "mt/Lock.h" // // ClientTaskBarReceiver // -ClientTaskBarReceiver::ClientTaskBarReceiver(IEventQueue* events) : - m_state(kNotRunning), - m_events(events) -{ - // do nothing +ClientTaskBarReceiver::ClientTaskBarReceiver(IEventQueue *events) + : m_state(kNotRunning), m_events(events) { + // do nothing } -ClientTaskBarReceiver::~ClientTaskBarReceiver() -{ - // do nothing +ClientTaskBarReceiver::~ClientTaskBarReceiver() { + // do nothing } -void -ClientTaskBarReceiver::updateStatus(Client* client, const String& errorMsg) -{ - { - // update our status - m_errorMessage = errorMsg; - if (client == NULL) { - if (m_errorMessage.empty()) { - m_state = kNotRunning; - } - else { - m_state = kNotWorking; - } - } - else { - m_server = client->getServerAddress().getHostname(); +void ClientTaskBarReceiver::updateStatus(Client *client, + const String &errorMsg) { + { + // update our status + m_errorMessage = errorMsg; + if (client == NULL) { + if (m_errorMessage.empty()) { + m_state = kNotRunning; + } else { + m_state = kNotWorking; + } + } else { + m_server = client->getServerAddress().getHostname(); - if (client->isConnected()) { - m_state = kConnected; - } - else if (client->isConnecting()) { - m_state = kConnecting; - } - else { - m_state = kNotConnected; - } - } - - // let subclasses have a go - onStatusChanged(client); + if (client->isConnected()) { + m_state = kConnected; + } else if (client->isConnecting()) { + m_state = kConnecting; + } else { + m_state = kNotConnected; + } } - // tell task bar - ARCH->updateReceiver(this); + // let subclasses have a go + onStatusChanged(client); + } + + // tell task bar + ARCH->updateReceiver(this); } -ClientTaskBarReceiver::EState -ClientTaskBarReceiver::getStatus() const -{ - return m_state; +ClientTaskBarReceiver::EState ClientTaskBarReceiver::getStatus() const { + return m_state; } -const String& -ClientTaskBarReceiver::getErrorMessage() const -{ - return m_errorMessage; +const String &ClientTaskBarReceiver::getErrorMessage() const { + return m_errorMessage; } -void -ClientTaskBarReceiver::quit() -{ - m_events->addEvent(Event(Event::kQuit)); +void ClientTaskBarReceiver::quit() { m_events->addEvent(Event(Event::kQuit)); } + +void ClientTaskBarReceiver::onStatusChanged(Client *) { + // do nothing } -void -ClientTaskBarReceiver::onStatusChanged(Client*) -{ - // do nothing +void ClientTaskBarReceiver::lock() const { + // do nothing } -void -ClientTaskBarReceiver::lock() const -{ - // do nothing +void ClientTaskBarReceiver::unlock() const { + // do nothing } -void -ClientTaskBarReceiver::unlock() const -{ - // do nothing -} - -std::string -ClientTaskBarReceiver::getToolTip() const -{ - switch (m_state) { - case kNotRunning: - return synergy::string::sprintf("%s: Not running", kAppVersion); - - case kNotWorking: - return synergy::string::sprintf("%s: %s", - kAppVersion, m_errorMessage.c_str()); - - case kNotConnected: - return synergy::string::sprintf("%s: Not connected: %s", - kAppVersion, m_errorMessage.c_str()); - - case kConnecting: - return synergy::string::sprintf("%s: Connecting to %s...", - kAppVersion, m_server.c_str()); - - case kConnected: - return synergy::string::sprintf("%s: Connected to %s", - kAppVersion, m_server.c_str()); - - default: - return ""; - } +std::string ClientTaskBarReceiver::getToolTip() const { + switch (m_state) { + case kNotRunning: + return synergy::string::sprintf("%s: Not running", kAppVersion); + + case kNotWorking: + return synergy::string::sprintf("%s: %s", kAppVersion, + m_errorMessage.c_str()); + + case kNotConnected: + return synergy::string::sprintf("%s: Not connected: %s", kAppVersion, + m_errorMessage.c_str()); + + case kConnecting: + return synergy::string::sprintf("%s: Connecting to %s...", kAppVersion, + m_server.c_str()); + + case kConnected: + return synergy::string::sprintf("%s: Connected to %s", kAppVersion, + m_server.c_str()); + + default: + return ""; + } } diff --git a/src/lib/synergy/ClientTaskBarReceiver.h b/src/lib/synergy/ClientTaskBarReceiver.h index eae8e3b05..5e1d8b62d 100644 --- a/src/lib/synergy/ClientTaskBarReceiver.h +++ b/src/lib/synergy/ClientTaskBarReceiver.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2003 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 LICENSE 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 @@ -19,8 +19,8 @@ #ifndef CCLIENTTASKBARRECEIVER_H #define CCLIENTTASKBARRECEIVER_H -#include "base/String.h" #include "arch/IArchTaskBarReceiver.h" +#include "base/String.h" #include "base/log_outputters.h" #include "client/Client.h" @@ -29,67 +29,71 @@ class IEventQueue; //! Implementation of IArchTaskBarReceiver for the synergy server class ClientTaskBarReceiver : public IArchTaskBarReceiver { public: - ClientTaskBarReceiver(IEventQueue* events); - virtual ~ClientTaskBarReceiver(); + ClientTaskBarReceiver(IEventQueue *events); + virtual ~ClientTaskBarReceiver(); - //! @name manipulators - //@{ + //! @name manipulators + //@{ - //! Update status - /*! - Determine the status and query required information from the client. - */ - void updateStatus(Client*, const String& errorMsg); + //! Update status + /*! + Determine the status and query required information from the client. + */ + void updateStatus(Client *, const String &errorMsg); - void updateStatus(INode* n, const String& errorMsg) { updateStatus((Client*)n, errorMsg); } + void updateStatus(INode *n, const String &errorMsg) { + updateStatus((Client *)n, errorMsg); + } - //@} + //@} - // IArchTaskBarReceiver overrides - virtual void showStatus() = 0; - virtual void runMenu(int x, int y) = 0; - virtual void primaryAction() = 0; - virtual void lock() const; - virtual void unlock() const; - virtual const Icon getIcon() const = 0; - virtual std::string getToolTip() const; - virtual void cleanup() {} + // IArchTaskBarReceiver overrides + virtual void showStatus() = 0; + virtual void runMenu(int x, int y) = 0; + virtual void primaryAction() = 0; + virtual void lock() const; + virtual void unlock() const; + virtual const Icon getIcon() const = 0; + virtual std::string getToolTip() const; + virtual void cleanup() {} protected: - enum EState { - kNotRunning, - kNotWorking, - kNotConnected, - kConnecting, - kConnected, - kMaxState - }; + enum EState { + kNotRunning, + kNotWorking, + kNotConnected, + kConnecting, + kConnected, + kMaxState + }; - //! Get status - EState getStatus() const; + //! Get status + EState getStatus() const; - //! Get error message - const String& getErrorMessage() const; + //! Get error message + const String &getErrorMessage() const; - //! Quit app - /*! - Causes the application to quit gracefully - */ - void quit(); + //! Quit app + /*! + Causes the application to quit gracefully + */ + void quit(); - //! Status change notification - /*! - Called when status changes. The default implementation does nothing. - */ - virtual void onStatusChanged(Client* client); + //! Status change notification + /*! + Called when status changes. The default implementation does nothing. + */ + virtual void onStatusChanged(Client *client); private: - EState m_state; - String m_errorMessage; - String m_server; - IEventQueue* m_events; + EState m_state; + String m_errorMessage; + String m_server; + IEventQueue *m_events; }; -IArchTaskBarReceiver* createTaskBarReceiver(const BufferedLogOutputter* logBuffer, IEventQueue* events); +IArchTaskBarReceiver * +createTaskBarReceiver(const BufferedLogOutputter *logBuffer, + IEventQueue *events); #endif diff --git a/src/lib/synergy/Clipboard.cpp b/src/lib/synergy/Clipboard.cpp index 86bd37b60..70baacd46 100644 --- a/src/lib/synergy/Clipboard.cpp +++ b/src/lib/synergy/Clipboard.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -22,97 +22,71 @@ // Clipboard // -Clipboard::Clipboard() : - m_open(false), - m_owner(false) -{ - open(0); - empty(); - close(); +Clipboard::Clipboard() : m_open(false), m_owner(false) { + open(0); + empty(); + close(); } -Clipboard::~Clipboard() -{ - // do nothing +Clipboard::~Clipboard() { + // do nothing } -bool -Clipboard::empty() -{ - assert(m_open); +bool Clipboard::empty() { + assert(m_open); - // clear all data - for (SInt32 index = 0; index < kNumFormats; ++index) { - m_data[index] = ""; - m_added[index] = false; - } + // clear all data + for (SInt32 index = 0; index < kNumFormats; ++index) { + m_data[index] = ""; + m_added[index] = false; + } - // save time - m_timeOwned = m_time; + // save time + m_timeOwned = m_time; - // we're the owner now - m_owner = true; + // we're the owner now + m_owner = true; - return true; + return true; } -void -Clipboard::add(EFormat format, const String& data) -{ - assert(m_open); - assert(m_owner); +void Clipboard::add(EFormat format, const String &data) { + assert(m_open); + assert(m_owner); - m_data[format] = data; - m_added[format] = true; + m_data[format] = data; + m_added[format] = true; } -bool -Clipboard::open(Time time) const -{ - assert(!m_open); +bool Clipboard::open(Time time) const { + assert(!m_open); - m_open = true; - m_time = time; + m_open = true; + m_time = time; - return true; + return true; } -void -Clipboard::close() const -{ - assert(m_open); +void Clipboard::close() const { + assert(m_open); - m_open = false; + m_open = false; } -Clipboard::Time -Clipboard::getTime() const -{ - return m_timeOwned; +Clipboard::Time Clipboard::getTime() const { return m_timeOwned; } + +bool Clipboard::has(EFormat format) const { + assert(m_open); + return m_added[format]; } -bool -Clipboard::has(EFormat format) const -{ - assert(m_open); - return m_added[format]; +String Clipboard::get(EFormat format) const { + assert(m_open); + return m_data[format]; } -String -Clipboard::get(EFormat format) const -{ - assert(m_open); - return m_data[format]; +void Clipboard::unmarshall(const String &data, Time time) { + IClipboard::unmarshall(this, data, time); } -void -Clipboard::unmarshall(const String& data, Time time) -{ - IClipboard::unmarshall(this, data, time); -} - -String -Clipboard::marshall() const -{ - return IClipboard::marshall(this); -} +String Clipboard::marshall() const { return IClipboard::marshall(this); } diff --git a/src/lib/synergy/Clipboard.h b/src/lib/synergy/Clipboard.h index 81f070003..f4d2237ec 100644 --- a/src/lib/synergy/Clipboard.h +++ b/src/lib/synergy/Clipboard.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -26,46 +26,46 @@ This class implements a clipboard that stores data in memory. */ class Clipboard : public IClipboard { public: - Clipboard(); - virtual ~Clipboard(); + Clipboard(); + virtual ~Clipboard(); - //! @name manipulators - //@{ + //! @name manipulators + //@{ - //! Unmarshall clipboard data - /*! - Extract marshalled clipboard data and store it in this clipboard. - Sets the clipboard time to \c time. - */ - void unmarshall(const String& data, Time time); + //! Unmarshall clipboard data + /*! + Extract marshalled clipboard data and store it in this clipboard. + Sets the clipboard time to \c time. + */ + void unmarshall(const String &data, Time time); - //@} - //! @name accessors - //@{ + //@} + //! @name accessors + //@{ - //! Marshall clipboard data - /*! - Merge this clipboard's data into a single buffer that can be later - unmarshalled to restore the clipboard and return the buffer. - */ - String marshall() const; + //! Marshall clipboard data + /*! + Merge this clipboard's data into a single buffer that can be later + unmarshalled to restore the clipboard and return the buffer. + */ + String marshall() const; - //@} + //@} - // IClipboard overrides - virtual bool empty(); - virtual void add(EFormat, const String& data); - virtual bool open(Time) const; - virtual void close() const; - virtual Time getTime() const; - virtual bool has(EFormat) const; - virtual String get(EFormat) const; + // IClipboard overrides + virtual bool empty(); + virtual void add(EFormat, const String &data); + virtual bool open(Time) const; + virtual void close() const; + virtual Time getTime() const; + virtual bool has(EFormat) const; + virtual String get(EFormat) const; private: - mutable bool m_open; - mutable Time m_time; - bool m_owner; - Time m_timeOwned; - bool m_added[kNumFormats]; - String m_data[kNumFormats]; + mutable bool m_open; + mutable Time m_time; + bool m_owner; + Time m_timeOwned; + bool m_added[kNumFormats]; + String m_data[kNumFormats]; }; diff --git a/src/lib/synergy/ClipboardChunk.cpp b/src/lib/synergy/ClipboardChunk.cpp index 0cf0ffbcd..c812f04f2 100644 --- a/src/lib/synergy/ClipboardChunk.cpp +++ b/src/lib/synergy/ClipboardChunk.cpp @@ -1,11 +1,11 @@ /* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2015-2016 Symless Ltd. - * + * * 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 LICENSE 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 @@ -17,138 +17,123 @@ #include "synergy/ClipboardChunk.h" +#include "base/Log.h" +#include "io/IStream.h" #include "synergy/ProtocolUtil.h" #include "synergy/protocol_types.h" -#include "io/IStream.h" -#include "base/Log.h" #include size_t ClipboardChunk::s_expectedSize = 0; -ClipboardChunk::ClipboardChunk(size_t size) : - Chunk(size) -{ - m_dataSize = size - CLIPBOARD_CHUNK_META_SIZE; +ClipboardChunk::ClipboardChunk(size_t size) : Chunk(size) { + m_dataSize = size - CLIPBOARD_CHUNK_META_SIZE; } -ClipboardChunk* -ClipboardChunk::start( - ClipboardID id, - UInt32 sequence, - const String& size) -{ - size_t sizeLength = size.size(); - ClipboardChunk* start = new ClipboardChunk(sizeLength + CLIPBOARD_CHUNK_META_SIZE); - char* chunk = start->m_chunk; +ClipboardChunk *ClipboardChunk::start(ClipboardID id, UInt32 sequence, + const String &size) { + size_t sizeLength = size.size(); + ClipboardChunk *start = + new ClipboardChunk(sizeLength + CLIPBOARD_CHUNK_META_SIZE); + char *chunk = start->m_chunk; - chunk[0] = id; - std::memcpy (&chunk[1], &sequence, 4); - chunk[5] = kDataStart; - memcpy(&chunk[6], size.c_str(), sizeLength); - chunk[sizeLength + CLIPBOARD_CHUNK_META_SIZE - 1] = '\0'; + chunk[0] = id; + std::memcpy(&chunk[1], &sequence, 4); + chunk[5] = kDataStart; + memcpy(&chunk[6], size.c_str(), sizeLength); + chunk[sizeLength + CLIPBOARD_CHUNK_META_SIZE - 1] = '\0'; - return start; + return start; } -ClipboardChunk* -ClipboardChunk::data( - ClipboardID id, - UInt32 sequence, - const String& data) -{ - size_t dataSize = data.size(); - ClipboardChunk* chunk = new ClipboardChunk(dataSize + CLIPBOARD_CHUNK_META_SIZE); - char* chunkData = chunk->m_chunk; +ClipboardChunk *ClipboardChunk::data(ClipboardID id, UInt32 sequence, + const String &data) { + size_t dataSize = data.size(); + ClipboardChunk *chunk = + new ClipboardChunk(dataSize + CLIPBOARD_CHUNK_META_SIZE); + char *chunkData = chunk->m_chunk; - chunkData[0] = id; - std::memcpy (&chunkData[1], &sequence, 4); - chunkData[5] = kDataChunk; - memcpy(&chunkData[6], data.c_str(), dataSize); - chunkData[dataSize + CLIPBOARD_CHUNK_META_SIZE - 1] = '\0'; + chunkData[0] = id; + std::memcpy(&chunkData[1], &sequence, 4); + chunkData[5] = kDataChunk; + memcpy(&chunkData[6], data.c_str(), dataSize); + chunkData[dataSize + CLIPBOARD_CHUNK_META_SIZE - 1] = '\0'; - return chunk; + return chunk; } -ClipboardChunk* -ClipboardChunk::end(ClipboardID id, UInt32 sequence) -{ - ClipboardChunk* end = new ClipboardChunk(CLIPBOARD_CHUNK_META_SIZE); - char* chunk = end->m_chunk; - - chunk[0] = id; - std::memcpy (&chunk[1], &sequence, 4); - chunk[5] = kDataEnd; - chunk[CLIPBOARD_CHUNK_META_SIZE - 1] = '\0'; +ClipboardChunk *ClipboardChunk::end(ClipboardID id, UInt32 sequence) { + ClipboardChunk *end = new ClipboardChunk(CLIPBOARD_CHUNK_META_SIZE); + char *chunk = end->m_chunk; - return end; + chunk[0] = id; + std::memcpy(&chunk[1], &sequence, 4); + chunk[5] = kDataEnd; + chunk[CLIPBOARD_CHUNK_META_SIZE - 1] = '\0'; + + return end; } -int -ClipboardChunk::assemble(synergy::IStream* stream, - String& dataCached, - ClipboardID& id, - UInt32& sequence) -{ - UInt8 mark; - String data; +int ClipboardChunk::assemble(synergy::IStream *stream, String &dataCached, + ClipboardID &id, UInt32 &sequence) { + UInt8 mark; + String data; - if (!ProtocolUtil::readf(stream, kMsgDClipboard + 4, &id, &sequence, &mark, &data)) { - return kError; - } - - if (mark == kDataStart) { - s_expectedSize = synergy::string::stringToSizeType(data); - LOG((CLOG_DEBUG "start receiving clipboard data")); - dataCached.clear(); - return kStart; - } - else if (mark == kDataChunk) { - dataCached.append(data); - return kNotFinish; - } - else if (mark == kDataEnd) { - // validate - if (id >= kClipboardEnd) { - return kError; - } - else if (s_expectedSize != dataCached.size()) { - LOG((CLOG_ERR "corrupted clipboard data, expected size=%d actual size=%d", s_expectedSize, dataCached.size())); - return kError; - } - return kFinish; - } - - LOG((CLOG_ERR "clipboard transmission failed: unknown error")); + if (!ProtocolUtil::readf(stream, kMsgDClipboard + 4, &id, &sequence, &mark, + &data)) { return kError; -} + } -void -ClipboardChunk::send(synergy::IStream* stream, void* data) -{ - ClipboardChunk* clipboardData = static_cast(data); - - LOG((CLOG_DEBUG1 "sending clipboard chunk")); - - char* chunk = clipboardData->m_chunk; - ClipboardID id = chunk[0]; - UInt32 sequence; - std::memcpy (&sequence, &chunk[1], 4); - UInt8 mark = chunk[5]; - String dataChunk(&chunk[6], clipboardData->m_dataSize); - - switch (mark) { - case kDataStart: - LOG((CLOG_DEBUG2 "sending clipboard chunk start: size=%s", dataChunk.c_str())); - break; - - case kDataChunk: - LOG((CLOG_DEBUG2 "sending clipboard chunk data: size=%i", dataChunk.size())); - break; - - case kDataEnd: - LOG((CLOG_DEBUG2 "sending clipboard finished")); - break; + if (mark == kDataStart) { + s_expectedSize = synergy::string::stringToSizeType(data); + LOG((CLOG_DEBUG "start receiving clipboard data")); + dataCached.clear(); + return kStart; + } else if (mark == kDataChunk) { + dataCached.append(data); + return kNotFinish; + } else if (mark == kDataEnd) { + // validate + if (id >= kClipboardEnd) { + return kError; + } else if (s_expectedSize != dataCached.size()) { + LOG((CLOG_ERR "corrupted clipboard data, expected size=%d actual size=%d", + s_expectedSize, dataCached.size())); + return kError; } + return kFinish; + } - ProtocolUtil::writef(stream, kMsgDClipboard, id, sequence, mark, &dataChunk); + LOG((CLOG_ERR "clipboard transmission failed: unknown error")); + return kError; +} + +void ClipboardChunk::send(synergy::IStream *stream, void *data) { + ClipboardChunk *clipboardData = static_cast(data); + + LOG((CLOG_DEBUG1 "sending clipboard chunk")); + + char *chunk = clipboardData->m_chunk; + ClipboardID id = chunk[0]; + UInt32 sequence; + std::memcpy(&sequence, &chunk[1], 4); + UInt8 mark = chunk[5]; + String dataChunk(&chunk[6], clipboardData->m_dataSize); + + switch (mark) { + case kDataStart: + LOG((CLOG_DEBUG2 "sending clipboard chunk start: size=%s", + dataChunk.c_str())); + break; + + case kDataChunk: + LOG((CLOG_DEBUG2 "sending clipboard chunk data: size=%i", + dataChunk.size())); + break; + + case kDataEnd: + LOG((CLOG_DEBUG2 "sending clipboard finished")); + break; + } + + ProtocolUtil::writef(stream, kMsgDClipboard, id, sequence, mark, &dataChunk); } diff --git a/src/lib/synergy/ClipboardChunk.h b/src/lib/synergy/ClipboardChunk.h index 9bf4b7a4a..b7e99b6e2 100644 --- a/src/lib/synergy/ClipboardChunk.h +++ b/src/lib/synergy/ClipboardChunk.h @@ -1,11 +1,11 @@ /* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2015-2016 Symless Ltd. - * + * * 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 LICENSE 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 @@ -17,10 +17,10 @@ #pragma once -#include "synergy/Chunk.h" -#include "synergy/clipboard_types.h" #include "base/String.h" #include "common/basic_types.h" +#include "synergy/Chunk.h" +#include "synergy/clipboard_types.h" #define CLIPBOARD_CHUNK_META_SIZE 7 @@ -30,31 +30,21 @@ class IStream; class ClipboardChunk : public Chunk { public: - ClipboardChunk(size_t size); + ClipboardChunk(size_t size); - static ClipboardChunk* - start( - ClipboardID id, - UInt32 sequence, - const String& size); - static ClipboardChunk* - data( - ClipboardID id, - UInt32 sequence, - const String& data); - static ClipboardChunk* - end(ClipboardID id, UInt32 sequence); + static ClipboardChunk *start(ClipboardID id, UInt32 sequence, + const String &size); + static ClipboardChunk *data(ClipboardID id, UInt32 sequence, + const String &data); + static ClipboardChunk *end(ClipboardID id, UInt32 sequence); - static int assemble( - synergy::IStream* stream, - String& dataCached, - ClipboardID& id, - UInt32& sequence); + static int assemble(synergy::IStream *stream, String &dataCached, + ClipboardID &id, UInt32 &sequence); - static void send(synergy::IStream* stream, void* data); + static void send(synergy::IStream *stream, void *data); - static size_t getExpectedSize() { return s_expectedSize; } + static size_t getExpectedSize() { return s_expectedSize; } private: - static size_t s_expectedSize; + static size_t s_expectedSize; }; diff --git a/src/lib/synergy/DaemonApp.cpp b/src/lib/synergy/DaemonApp.cpp index 34a4f621f..29f8aa760 100644 --- a/src/lib/synergy/DaemonApp.cpp +++ b/src/lib/synergy/DaemonApp.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2012 Nick Bolton - * + * * 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 LICENSE 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 @@ -21,411 +21,378 @@ #include "synergy/DaemonApp.h" +#include "arch/XArch.h" +#include "base/EventQueue.h" +#include "base/Log.h" +#include "base/TMethodEventJob.h" +#include "base/TMethodJob.h" +#include "base/log_outputters.h" #include "ipc/Ipc.h" -#include "synergy/App.h" -#include "synergy/ArgParser.h" -#include "synergy/ServerArgs.h" -#include "synergy/ClientArgs.h" #include "ipc/IpcClientProxy.h" +#include "ipc/IpcLogOutputter.h" #include "ipc/IpcMessage.h" #include "ipc/IpcSettingMessage.h" -#include "ipc/IpcLogOutputter.h" #include "net/SocketMultiplexer.h" -#include "arch/XArch.h" -#include "base/Log.h" -#include "base/TMethodJob.h" -#include "base/TMethodEventJob.h" -#include "base/EventQueue.h" -#include "base/log_outputters.h" -#include "base/Log.h" +#include "synergy/App.h" +#include "synergy/ArgParser.h" +#include "synergy/ClientArgs.h" +#include "synergy/ServerArgs.h" #include "synergy/protocol_types.h" #if SYSAPI_WIN32 #include "arch/win32/ArchMiscWindows.h" #include "arch/win32/XArchWindows.h" -#include "synergy/Screen.h" -#include "platform/MSWindowsScreen.h" #include "platform/MSWindowsDebugOutputter.h" -#include "platform/MSWindowsWatchdog.h" #include "platform/MSWindowsEventQueueBuffer.h" +#include "platform/MSWindowsScreen.h" +#include "platform/MSWindowsWatchdog.h" +#include "synergy/Screen.h" #define WIN32_LEAN_AND_MEAN #include #endif -#include #include #include +#include using namespace std; namespace { -void -updateSetting(const IpcMessage& message) -{ - try { - auto setting = static_cast(message); - ARCH->setting(setting.getName(), setting.getValue()); - } - catch (const XArch& e) { - LOG((CLOG_ERR "failed to save setting: %s", e.what())); - } +void updateSetting(const IpcMessage &message) { + try { + auto setting = static_cast(message); + ARCH->setting(setting.getName(), setting.getValue()); + } catch (const XArch &e) { + LOG((CLOG_ERR "failed to save setting: %s", e.what())); + } } -bool -isServerCommandLine(const std::vector& cmd) -{ - auto isServer = false; +bool isServerCommandLine(const std::vector &cmd) { + auto isServer = false; - if (cmd.size() > 1) { - isServer = (cmd[0].find("synergys") != String::npos) || - (cmd[0].find("synergy-core") != String::npos && cmd[1] == "server"); - } + if (cmd.size() > 1) { + isServer = + (cmd[0].find("synergys") != String::npos) || + (cmd[0].find("synergy-core") != String::npos && cmd[1] == "server"); + } - return isServer; + return isServer; } -}//namespace +} // namespace -DaemonApp* DaemonApp::s_instance = NULL; +DaemonApp *DaemonApp::s_instance = NULL; -int -mainLoopStatic() -{ - DaemonApp::s_instance->mainLoop(true); - return kExitSuccess; +int mainLoopStatic() { + DaemonApp::s_instance->mainLoop(true); + return kExitSuccess; } -int -unixMainLoopStatic(int, const char**) -{ - return mainLoopStatic(); -} +int unixMainLoopStatic(int, const char **) { return mainLoopStatic(); } #if SYSAPI_WIN32 -int -winMainLoopStatic(int, const char**) -{ - return ArchMiscWindows::runDaemon(mainLoopStatic); +int winMainLoopStatic(int, const char **) { + return ArchMiscWindows::runDaemon(mainLoopStatic); } #endif -DaemonApp::DaemonApp() : - m_ipcServer(nullptr), - m_ipcLogOutputter(nullptr), - #if SYSAPI_WIN32 - m_watchdog(nullptr), - #endif - m_events(nullptr), - m_fileLogOutputter(nullptr) -{ - s_instance = this; +DaemonApp::DaemonApp() + : m_ipcServer(nullptr), m_ipcLogOutputter(nullptr), +#if SYSAPI_WIN32 + m_watchdog(nullptr), +#endif + m_events(nullptr), m_fileLogOutputter(nullptr) { + s_instance = this; } -DaemonApp::~DaemonApp() -{ -} +DaemonApp::~DaemonApp() {} -int -DaemonApp::run(int argc, char** argv) -{ +int DaemonApp::run(int argc, char **argv) { #if SYSAPI_WIN32 - // win32 instance needed for threading, etc. - ArchMiscWindows::setInstanceWin32(GetModuleHandle(NULL)); -#endif - - Arch arch; - arch.init(); - - Log log; - EventQueue events; - m_events = &events; - - bool uninstall = false; - try - { -#if SYSAPI_WIN32 - // TODO: maybe we should only add this if not using /f? - // sends debug messages to visual studio console window. - log.insert(new MSWindowsDebugOutputter()); + // win32 instance needed for threading, etc. + ArchMiscWindows::setInstanceWin32(GetModuleHandle(NULL)); #endif - // default log level to system setting. - string logLevel = arch.setting("LogLevel"); - if (logLevel != "") - log.setFilter(logLevel.c_str()); + Arch arch; + arch.init(); - bool foreground = false; + Log log; + EventQueue events; + m_events = &events; - for (int i = 1; i < argc; ++i) { - string arg(argv[i]); - - if (arg == "/f" || arg == "-f") { - foreground = true; - } + bool uninstall = false; + try { #if SYSAPI_WIN32 - else if (arg == "/install") { - LOG((CLOG_PRINT "installing windows daemon")); - uninstall = true; - arch.installDaemon(); - return kExitSuccess; - } - else if (arg == "/uninstall") { - LOG((CLOG_PRINT "uninstalling windows daemon")); - arch.uninstallDaemon(); - return kExitSuccess; - } + // TODO: maybe we should only add this if not using /f? + // sends debug messages to visual studio console window. + log.insert(new MSWindowsDebugOutputter()); #endif - else { - stringstream ss; - ss << "Unrecognized argument: " << arg; - foregroundError(ss.str().c_str()); - return kExitArgs; - } - } - if (foreground) { - LOG((CLOG_PRINT "starting daemon in foreground")); + // default log level to system setting. + string logLevel = arch.setting("LogLevel"); + if (logLevel != "") + log.setFilter(logLevel.c_str()); - // run process in foreground instead of daemonizing. - // useful for debugging. - mainLoop(false, foreground); - } - else { + bool foreground = false; + + for (int i = 1; i < argc; ++i) { + string arg(argv[i]); + + if (arg == "/f" || arg == "-f") { + foreground = true; + } #if SYSAPI_WIN32 - LOG((CLOG_PRINT "daemonizing windows service")); - arch.daemonize("Synergy", winMainLoopStatic); -#elif SYSAPI_UNIX - LOG((CLOG_PRINT "daemonizing unix service")); - arch.daemonize("Synergy", unixMainLoopStatic); -#endif - } - + else if (arg == "/install") { + LOG((CLOG_PRINT "installing windows daemon")); + uninstall = true; + arch.installDaemon(); return kExitSuccess; - } - catch (XArch& e) { - String message = e.what(); - if (uninstall && (message.find("The service has not been started") != String::npos)) { - // TODO: if we're keeping this use error code instead (what is it?!). - // HACK: this message happens intermittently, not sure where from but - // it's quite misleading for the user. they thing something has gone - // horribly wrong, but it's just the service manager reporting a false - // positive (the service has actually shut down in most cases). - } - else { - foregroundError(message.c_str()); - } - return kExitFailed; - } - catch (std::exception& e) { - foregroundError(e.what()); - return kExitFailed; - } - catch (...) { - foregroundError("Unrecognized error."); - return kExitFailed; - } -} - -void -DaemonApp::mainLoop(bool logToFile, bool foreground) -{ - try - { - DAEMON_RUNNING(true); - - if (logToFile) { - m_fileLogOutputter = new FileLogOutputter(logFilename().c_str()); - CLOG->insert(m_fileLogOutputter); - } - - // create socket multiplexer. this must happen after daemonization - // on unix because threads evaporate across a fork(). - SocketMultiplexer multiplexer; - - // uses event queue, must be created here. - m_ipcServer = new IpcServer(m_events, &multiplexer); - - // send logging to gui via ipc, log system adopts outputter. - m_ipcLogOutputter = new IpcLogOutputter(*m_ipcServer, kIpcClientGui, true); - CLOG->insert(m_ipcLogOutputter); - -#if SYSAPI_WIN32 - m_watchdog = new MSWindowsWatchdog(false, *m_ipcServer, *m_ipcLogOutputter, foreground); - m_watchdog->setFileLogOutputter(m_fileLogOutputter); + } else if (arg == "/uninstall") { + LOG((CLOG_PRINT "uninstalling windows daemon")); + arch.uninstallDaemon(); + return kExitSuccess; + } #endif - - m_events->adoptHandler( - m_events->forIpcServer().messageReceived(), m_ipcServer, - new TMethodEventJob(this, &DaemonApp::handleIpcMessage)); - - m_ipcServer->listen(); - -#if SYSAPI_WIN32 - - // install the platform event queue to handle service stop events. - m_events->adoptBuffer(new MSWindowsEventQueueBuffer(m_events)); - - String command = ARCH->setting("Command"); - bool elevate = ARCH->setting("Elevate") == "1"; - if (command != "") { - LOG((CLOG_INFO "using last known command: %s", command.c_str())); - m_watchdog->setCommand(command, elevate); - } - - m_watchdog->startAsync(); -#endif - m_events->loop(); - -#if SYSAPI_WIN32 - m_watchdog->stop(); - delete m_watchdog; -#endif - - m_events->removeHandler( - m_events->forIpcServer().messageReceived(), m_ipcServer); - - CLOG->remove(m_ipcLogOutputter); - delete m_ipcLogOutputter; - delete m_ipcServer; - - DAEMON_RUNNING(false); + else { + stringstream ss; + ss << "Unrecognized argument: " << arg; + foregroundError(ss.str().c_str()); + return kExitArgs; + } } - catch (std::exception& e) { - LOG((CLOG_CRIT "an error occurred: %s", e.what())); - } - catch (...) { - LOG((CLOG_CRIT "an unknown error occurred.\n")); - } -} -void -DaemonApp::foregroundError(const char* message) -{ + if (foreground) { + LOG((CLOG_PRINT "starting daemon in foreground")); + + // run process in foreground instead of daemonizing. + // useful for debugging. + mainLoop(false, foreground); + } else { #if SYSAPI_WIN32 - MessageBox(NULL, message, "Synergy Service", MB_OK | MB_ICONERROR); + LOG((CLOG_PRINT "daemonizing windows service")); + arch.daemonize("Synergy", winMainLoopStatic); #elif SYSAPI_UNIX - cerr << message << endl; + LOG((CLOG_PRINT "daemonizing unix service")); + arch.daemonize("Synergy", unixMainLoopStatic); #endif -} - -std::string -DaemonApp::logFilename() -{ - string logFilename; - logFilename = ARCH->setting("LogFilename"); - if (logFilename.empty()) { - logFilename = ARCH->getLogDirectory(); - logFilename.append("/"); - logFilename.append(LOG_FILENAME); } - return logFilename; -} - -void -DaemonApp::handleIpcMessage(const Event& e, void*) -{ - IpcMessage* m = static_cast(e.getDataObject()); - switch (m->type()) { - case kIpcCommand: { - IpcCommandMessage* cm = static_cast(m); - String command = cm->command(); - - // if empty quotes, clear. - if (command == "\"\"") { - command.clear(); - } - - if (!command.empty()) { - LOG((CLOG_DEBUG "daemon got new core command")); - LOG((CLOG_DEBUG2 "new command, elevate=%d command=%s", cm->elevate(), command.c_str())); - - std::vector argsArray; - ArgParser::splitCommandString(command, argsArray); - ArgParser argParser(NULL); - const char** argv = argParser.getArgv(argsArray); - int argc = static_cast(argsArray.size()); - - if (isServerCommandLine(argsArray)) { - auto serverArgs = new lib::synergy::ServerArgs(); - argParser.parseServerArgs(*serverArgs, argc, argv); - } - else { - auto clientArgs = new lib::synergy::ClientArgs(); - argParser.parseClientArgs(*clientArgs, argc, argv); - } - - delete[] argv; - String logLevel(ArgParser::argsBase().m_logFilter); - if (!logLevel.empty()) { - try { - // change log level based on that in the command string - // and change to that log level now. - ARCH->setting("LogLevel", logLevel); - CLOG->setFilter(logLevel.c_str()); - } - catch (XArch& e) { - LOG((CLOG_ERR "failed to save LogLevel setting, %s", e.what())); - } - } - } - else { - LOG((CLOG_DEBUG "empty command, elevate=%d", cm->elevate())); - } - - try { - // store command in system settings. this is used when the daemon - // next starts. - ARCH->setting("Command", command); - - // TODO: it would be nice to store bools/ints... - ARCH->setting("Elevate", String(cm->elevate() ? "1" : "0")); - } - catch (XArch& e) { - LOG((CLOG_ERR "failed to save settings, %s", e.what())); - } - -#if SYSAPI_WIN32 - // tell the relauncher about the new command. this causes the - // relauncher to stop the existing command and start the new - // command. - m_watchdog->setCommand(command, cm->elevate()); -#endif - break; - } - - case kIpcHello: { - IpcHelloMessage* hm = static_cast(m); - String type; - switch (hm->clientType()) { - case kIpcClientGui: type = "gui"; break; - case kIpcClientNode: type = "node"; break; - default: type = "unknown"; break; - } - - LOG((CLOG_DEBUG "ipc hello, type=%s", type.c_str())); - - // TODO: implement hello back handling in s1 gui and node (server/client). - if (hm->clientType() == kIpcClientGui) { - LOG((CLOG_DEBUG "sending ipc hello back")); - IpcHelloBackMessage hbm; - m_ipcServer->send(hbm, hm->clientType()); - } - -#if SYSAPI_WIN32 - String watchdogStatus = m_watchdog->isProcessActive() ? "active" : "idle"; - LOG((CLOG_INFO "service status: %s", watchdogStatus.c_str())); -#endif - - m_ipcLogOutputter->notifyBuffer(); - break; - } - - case kIpcSetting: - updateSetting(*m); - break; + return kExitSuccess; + } catch (XArch &e) { + String message = e.what(); + if (uninstall && + (message.find("The service has not been started") != String::npos)) { + // TODO: if we're keeping this use error code instead (what is it?!). + // HACK: this message happens intermittently, not sure where from but + // it's quite misleading for the user. they thing something has gone + // horribly wrong, but it's just the service manager reporting a false + // positive (the service has actually shut down in most cases). + } else { + foregroundError(message.c_str()); } + return kExitFailed; + } catch (std::exception &e) { + foregroundError(e.what()); + return kExitFailed; + } catch (...) { + foregroundError("Unrecognized error."); + return kExitFailed; + } +} + +void DaemonApp::mainLoop(bool logToFile, bool foreground) { + try { + DAEMON_RUNNING(true); + + if (logToFile) { + m_fileLogOutputter = new FileLogOutputter(logFilename().c_str()); + CLOG->insert(m_fileLogOutputter); + } + + // create socket multiplexer. this must happen after daemonization + // on unix because threads evaporate across a fork(). + SocketMultiplexer multiplexer; + + // uses event queue, must be created here. + m_ipcServer = new IpcServer(m_events, &multiplexer); + + // send logging to gui via ipc, log system adopts outputter. + m_ipcLogOutputter = new IpcLogOutputter(*m_ipcServer, kIpcClientGui, true); + CLOG->insert(m_ipcLogOutputter); + +#if SYSAPI_WIN32 + m_watchdog = new MSWindowsWatchdog(false, *m_ipcServer, *m_ipcLogOutputter, + foreground); + m_watchdog->setFileLogOutputter(m_fileLogOutputter); +#endif + + m_events->adoptHandler( + m_events->forIpcServer().messageReceived(), m_ipcServer, + new TMethodEventJob(this, &DaemonApp::handleIpcMessage)); + + m_ipcServer->listen(); + +#if SYSAPI_WIN32 + + // install the platform event queue to handle service stop events. + m_events->adoptBuffer(new MSWindowsEventQueueBuffer(m_events)); + + String command = ARCH->setting("Command"); + bool elevate = ARCH->setting("Elevate") == "1"; + if (command != "") { + LOG((CLOG_INFO "using last known command: %s", command.c_str())); + m_watchdog->setCommand(command, elevate); + } + + m_watchdog->startAsync(); +#endif + m_events->loop(); + +#if SYSAPI_WIN32 + m_watchdog->stop(); + delete m_watchdog; +#endif + + m_events->removeHandler(m_events->forIpcServer().messageReceived(), + m_ipcServer); + + CLOG->remove(m_ipcLogOutputter); + delete m_ipcLogOutputter; + delete m_ipcServer; + + DAEMON_RUNNING(false); + } catch (std::exception &e) { + LOG((CLOG_CRIT "an error occurred: %s", e.what())); + } catch (...) { + LOG((CLOG_CRIT "an unknown error occurred.\n")); + } +} + +void DaemonApp::foregroundError(const char *message) { +#if SYSAPI_WIN32 + MessageBox(NULL, message, "Synergy Service", MB_OK | MB_ICONERROR); +#elif SYSAPI_UNIX + cerr << message << endl; +#endif +} + +std::string DaemonApp::logFilename() { + string logFilename; + logFilename = ARCH->setting("LogFilename"); + if (logFilename.empty()) { + logFilename = ARCH->getLogDirectory(); + logFilename.append("/"); + logFilename.append(LOG_FILENAME); + } + + return logFilename; +} + +void DaemonApp::handleIpcMessage(const Event &e, void *) { + IpcMessage *m = static_cast(e.getDataObject()); + switch (m->type()) { + case kIpcCommand: { + IpcCommandMessage *cm = static_cast(m); + String command = cm->command(); + + // if empty quotes, clear. + if (command == "\"\"") { + command.clear(); + } + + if (!command.empty()) { + LOG((CLOG_DEBUG "daemon got new core command")); + LOG((CLOG_DEBUG2 "new command, elevate=%d command=%s", cm->elevate(), + command.c_str())); + + std::vector argsArray; + ArgParser::splitCommandString(command, argsArray); + ArgParser argParser(NULL); + const char **argv = argParser.getArgv(argsArray); + int argc = static_cast(argsArray.size()); + + if (isServerCommandLine(argsArray)) { + auto serverArgs = new lib::synergy::ServerArgs(); + argParser.parseServerArgs(*serverArgs, argc, argv); + } else { + auto clientArgs = new lib::synergy::ClientArgs(); + argParser.parseClientArgs(*clientArgs, argc, argv); + } + + delete[] argv; + String logLevel(ArgParser::argsBase().m_logFilter); + if (!logLevel.empty()) { + try { + // change log level based on that in the command string + // and change to that log level now. + ARCH->setting("LogLevel", logLevel); + CLOG->setFilter(logLevel.c_str()); + } catch (XArch &e) { + LOG((CLOG_ERR "failed to save LogLevel setting, %s", e.what())); + } + } + } else { + LOG((CLOG_DEBUG "empty command, elevate=%d", cm->elevate())); + } + + try { + // store command in system settings. this is used when the daemon + // next starts. + ARCH->setting("Command", command); + + // TODO: it would be nice to store bools/ints... + ARCH->setting("Elevate", String(cm->elevate() ? "1" : "0")); + } catch (XArch &e) { + LOG((CLOG_ERR "failed to save settings, %s", e.what())); + } + +#if SYSAPI_WIN32 + // tell the relauncher about the new command. this causes the + // relauncher to stop the existing command and start the new + // command. + m_watchdog->setCommand(command, cm->elevate()); +#endif + break; + } + + case kIpcHello: { + IpcHelloMessage *hm = static_cast(m); + String type; + switch (hm->clientType()) { + case kIpcClientGui: + type = "gui"; + break; + case kIpcClientNode: + type = "node"; + break; + default: + type = "unknown"; + break; + } + + LOG((CLOG_DEBUG "ipc hello, type=%s", type.c_str())); + + // TODO: implement hello back handling in s1 gui and node (server/client). + if (hm->clientType() == kIpcClientGui) { + LOG((CLOG_DEBUG "sending ipc hello back")); + IpcHelloBackMessage hbm; + m_ipcServer->send(hbm, hm->clientType()); + } + +#if SYSAPI_WIN32 + String watchdogStatus = m_watchdog->isProcessActive() ? "active" : "idle"; + LOG((CLOG_INFO "service status: %s", watchdogStatus.c_str())); +#endif + + m_ipcLogOutputter->notifyBuffer(); + break; + } + + case kIpcSetting: + updateSetting(*m); + break; + } } diff --git a/src/lib/synergy/DaemonApp.h b/src/lib/synergy/DaemonApp.h index 080c2b995..197c3e4ab 100644 --- a/src/lib/synergy/DaemonApp.h +++ b/src/lib/synergy/DaemonApp.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2012 Nick Bolton - * + * * 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 LICENSE 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 @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + #pragma once #include "arch/Arch.h" @@ -34,29 +34,29 @@ class MSWindowsWatchdog; class DaemonApp { public: - DaemonApp(); - virtual ~DaemonApp(); - int run(int argc, char** argv); - void mainLoop(bool logToFile, bool foreground = false); + DaemonApp(); + virtual ~DaemonApp(); + int run(int argc, char **argv); + void mainLoop(bool logToFile, bool foreground = false); private: - void daemonize(); - void foregroundError(const char* message); - std::string logFilename(); - void handleIpcMessage(const Event&, void*); + void daemonize(); + void foregroundError(const char *message); + std::string logFilename(); + void handleIpcMessage(const Event &, void *); public: - static DaemonApp* s_instance; + static DaemonApp *s_instance; #if SYSAPI_WIN32 - MSWindowsWatchdog* m_watchdog; + MSWindowsWatchdog *m_watchdog; #endif private: - IpcServer* m_ipcServer; - IpcLogOutputter* m_ipcLogOutputter; - IEventQueue* m_events; - FileLogOutputter* m_fileLogOutputter; + IpcServer *m_ipcServer; + IpcLogOutputter *m_ipcLogOutputter; + IEventQueue *m_events; + FileLogOutputter *m_fileLogOutputter; }; #define LOG_FILENAME "synergyd.log" diff --git a/src/lib/synergy/DisplayInvalidException.h b/src/lib/synergy/DisplayInvalidException.h index bdc328012..084213528 100644 --- a/src/lib/synergy/DisplayInvalidException.h +++ b/src/lib/synergy/DisplayInvalidException.h @@ -18,22 +18,14 @@ #ifndef SYNERGY_DISPLAYINVALIDEXCEPTION_H #define SYNERGY_DISPLAYINVALIDEXCEPTION_H - #include #include class DisplayInvalidException : public std::runtime_error { - public: - DisplayInvalidException(const char* msg): - std::runtime_error(msg) - { - } +public: + DisplayInvalidException(const char *msg) : std::runtime_error(msg) {} - DisplayInvalidException(std::string msg): - std::runtime_error(msg) - { - } + DisplayInvalidException(std::string msg) : std::runtime_error(msg) {} }; - -#endif //SYNERGY_DISPLAYINVALIDEXCEPTION_H +#endif // SYNERGY_DISPLAYINVALIDEXCEPTION_H diff --git a/src/lib/synergy/DragInformation.cpp b/src/lib/synergy/DragInformation.cpp index 59136516c..0782252ca 100644 --- a/src/lib/synergy/DragInformation.cpp +++ b/src/lib/synergy/DragInformation.cpp @@ -1,11 +1,11 @@ /* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2013-2016 Symless Ltd. - * + * * 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 LICENSE 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 @@ -24,135 +24,118 @@ using namespace std; -DragInformation::DragInformation() : - m_filename(), - m_filesize(0) -{ +DragInformation::DragInformation() : m_filename(), m_filesize(0) {} + +void DragInformation::parseDragInfo(DragFileList &dragFileList, UInt32 fileNum, + String data) { + size_t startPos = 0; + size_t findResult1 = 0; + size_t findResult2 = 0; + dragFileList.clear(); + String slash("\\"); + if (data.find("/", startPos) != string::npos) { + slash = "/"; + } + + UInt32 index = 0; + while (index < fileNum) { + findResult1 = data.find(',', startPos); + findResult2 = data.find_last_of(slash, findResult1); + + if (findResult1 == startPos) { + // TODO: file number does not match, something goes wrong + break; + } + + // set filename + if (findResult1 - findResult2 > 1) { + String filename = + data.substr(findResult2 + 1, findResult1 - findResult2 - 1); + DragInformation di; + di.setFilename(filename); + dragFileList.push_back(di); + } + startPos = findResult1 + 1; + + // set filesize + findResult2 = data.find(',', startPos); + if (findResult2 - findResult1 > 1) { + String filesize = + data.substr(findResult1 + 1, findResult2 - findResult1 - 1); + size_t size = stringToNum(filesize); + dragFileList.at(index).setFilesize(size); + } + startPos = findResult1 + 1; + + ++index; + } + + LOG((CLOG_DEBUG "drag info received, total drag file number: %i", + dragFileList.size())); + + for (size_t i = 0; i < dragFileList.size(); ++i) { + LOG((CLOG_DEBUG "dragging file %i name: %s", i + 1, + dragFileList.at(i).getFilename().c_str())); + } } -void -DragInformation::parseDragInfo(DragFileList& dragFileList, UInt32 fileNum, String data) -{ - size_t startPos = 0; - size_t findResult1 = 0; - size_t findResult2 = 0; - dragFileList.clear(); - String slash("\\"); - if (data.find("/", startPos) != string::npos) { - slash = "/"; - } - - UInt32 index = 0; - while (index < fileNum) { - findResult1 = data.find(',', startPos); - findResult2 = data.find_last_of(slash, findResult1); - - if (findResult1 == startPos) { - //TODO: file number does not match, something goes wrong - break; - } - - // set filename - if (findResult1 - findResult2 > 1) { - String filename = data.substr(findResult2 + 1, - findResult1 - findResult2 - 1); - DragInformation di; - di.setFilename(filename); - dragFileList.push_back(di); - } - startPos = findResult1 + 1; - - //set filesize - findResult2 = data.find(',', startPos); - if (findResult2 - findResult1 > 1) { - String filesize = data.substr(findResult1 + 1, - findResult2 - findResult1 - 1); - size_t size = stringToNum(filesize); - dragFileList.at(index).setFilesize(size); - } - startPos = findResult1 + 1; - - ++index; - } - - LOG((CLOG_DEBUG "drag info received, total drag file number: %i", - dragFileList.size())); - - for (size_t i = 0; i < dragFileList.size(); ++i) { - LOG((CLOG_DEBUG "dragging file %i name: %s", - i + 1, - dragFileList.at(i).getFilename().c_str())); - } +String DragInformation::getDragFileExtension(String filename) { + size_t findResult = string::npos; + findResult = filename.find_last_of(".", filename.size()); + if (findResult != string::npos) { + return filename.substr(findResult + 1, filename.size() - findResult - 1); + } else { + return ""; + } } -String -DragInformation::getDragFileExtension(String filename) -{ - size_t findResult = string::npos; - findResult = filename.find_last_of(".", filename.size()); - if (findResult != string::npos) { - return filename.substr(findResult + 1, filename.size() - findResult - 1); - } - else { - return ""; - } +int DragInformation::setupDragInfo(DragFileList &fileList, String &output) { + int size = static_cast(fileList.size()); + for (int i = 0; i < size; ++i) { + output.append(fileList.at(i).getFilename()); + output.append(","); + String filesize = getFileSize(fileList.at(i).getFilename()); + output.append(filesize); + output.append(","); + } + return size; } -int -DragInformation::setupDragInfo(DragFileList& fileList, String& output) -{ - int size = static_cast(fileList.size()); - for (int i = 0; i < size; ++i) { - output.append(fileList.at(i).getFilename()); - output.append(","); - String filesize = getFileSize(fileList.at(i).getFilename()); - output.append(filesize); - output.append(","); - } - return size; +bool DragInformation::isFileValid(String filename) { + bool result = false; + std::fstream file(filename.c_str(), ios::in | ios::binary); + + if (file.is_open()) { + result = true; + } + + file.close(); + + return result; } -bool -DragInformation::isFileValid(String filename) -{ - bool result = false; - std::fstream file(filename.c_str(), ios::in|ios::binary); - - if (file.is_open()) { - result = true; - } - - file. close(); - - return result; +size_t DragInformation::stringToNum(String &str) { + istringstream iss(str.c_str()); + size_t size; + iss >> size; + return size; } -size_t -DragInformation::stringToNum(String& str) -{ - istringstream iss(str.c_str()); - size_t size; - iss >> size; - return size; -} - -String -DragInformation::getFileSize(String& filename) -{ - std::fstream file(filename.c_str(), ios::in|ios::binary); - - if (!file.is_open()) { - throw std::runtime_error("failed to get file size"); - } - - // check file size - file.seekg (0, std::ios::end); - size_t size = (size_t)file.tellg(); - - stringstream ss; - ss << size; - - file. close(); - - return ss.str(); +String DragInformation::getFileSize(String &filename) { + std::fstream file(filename.c_str(), ios::in | ios::binary); + + if (!file.is_open()) { + throw std::runtime_error("failed to get file size"); + } + + // check file size + file.seekg(0, std::ios::end); + size_t size = (size_t)file.tellg(); + + stringstream ss; + ss << size; + + file.close(); + + return ss.str(); } diff --git a/src/lib/synergy/DragInformation.h b/src/lib/synergy/DragInformation.h index 470146cec..35034de77 100644 --- a/src/lib/synergy/DragInformation.h +++ b/src/lib/synergy/DragInformation.h @@ -1,11 +1,11 @@ /* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2013-2016 Symless Ltd. - * + * * 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 LICENSE 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 @@ -17,37 +17,38 @@ #pragma once -#include "common/stdvector.h" -#include "base/String.h" #include "base/EventTypes.h" +#include "base/String.h" +#include "common/stdvector.h" class DragInformation; typedef std::vector DragFileList; class DragInformation { public: - DragInformation(); - ~DragInformation() { } - - String& getFilename() { return m_filename; } - void setFilename(String& name) { m_filename = name; } - size_t getFilesize() { return m_filesize; } - void setFilesize(size_t size) { m_filesize = size; } - - static void parseDragInfo(DragFileList& dragFileList, UInt32 fileNum, String data); - static String getDragFileExtension(String filename); - // helper function to setup drag info - // example: filename1,filesize1,filename2,filesize2, - // return file count - static int setupDragInfo(DragFileList& fileList, String& output); + DragInformation(); + ~DragInformation() {} - static bool isFileValid(String filename); + String &getFilename() { return m_filename; } + void setFilename(String &name) { m_filename = name; } + size_t getFilesize() { return m_filesize; } + void setFilesize(size_t size) { m_filesize = size; } + + static void parseDragInfo(DragFileList &dragFileList, UInt32 fileNum, + String data); + static String getDragFileExtension(String filename); + // helper function to setup drag info + // example: filename1,filesize1,filename2,filesize2, + // return file count + static int setupDragInfo(DragFileList &fileList, String &output); + + static bool isFileValid(String filename); private: - static size_t stringToNum(String& str); - static String getFileSize(String& filename); + static size_t stringToNum(String &str); + static String getFileSize(String &filename); private: - String m_filename; - size_t m_filesize; + String m_filename; + size_t m_filesize; }; diff --git a/src/lib/synergy/DropHelper.cpp b/src/lib/synergy/DropHelper.cpp index a99d9f8a3..24216485b 100644 --- a/src/lib/synergy/DropHelper.cpp +++ b/src/lib/synergy/DropHelper.cpp @@ -1,11 +1,11 @@ /* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2014-2016 Symless Ltd. - * + * * 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 LICENSE 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 @@ -21,33 +21,33 @@ #include -void -DropHelper::writeToDir(const String& destination, DragFileList& fileList, String& data) -{ - LOG((CLOG_DEBUG "dropping file, files=%i target=%s", fileList.size(), destination.c_str())); +void DropHelper::writeToDir(const String &destination, DragFileList &fileList, + String &data) { + LOG((CLOG_DEBUG "dropping file, files=%i target=%s", fileList.size(), + destination.c_str())); - if (!destination.empty() && fileList.size() > 0) { - std::fstream file; - String dropTarget = destination; + if (!destination.empty() && fileList.size() > 0) { + std::fstream file; + String dropTarget = destination; #ifdef SYSAPI_WIN32 - dropTarget.append("\\"); + dropTarget.append("\\"); #else - dropTarget.append("/"); + dropTarget.append("/"); #endif - dropTarget.append(fileList.at(0).getFilename()); - file.open(dropTarget.c_str(), std::ios::out | std::ios::binary); - if (!file.is_open()) { - LOG((CLOG_ERR "drop file failed: can not open %s", dropTarget.c_str())); - } - - file.write(data.c_str(), data.size()); - file.close(); - - LOG((CLOG_DEBUG "%s is saved to %s", fileList.at(0).getFilename().c_str(), destination.c_str())); - - fileList.clear(); - } - else { - LOG((CLOG_ERR "drop file failed: drop target is empty")); + dropTarget.append(fileList.at(0).getFilename()); + file.open(dropTarget.c_str(), std::ios::out | std::ios::binary); + if (!file.is_open()) { + LOG((CLOG_ERR "drop file failed: can not open %s", dropTarget.c_str())); } + + file.write(data.c_str(), data.size()); + file.close(); + + LOG((CLOG_DEBUG "%s is saved to %s", fileList.at(0).getFilename().c_str(), + destination.c_str())); + + fileList.clear(); + } else { + LOG((CLOG_ERR "drop file failed: drop target is empty")); + } } diff --git a/src/lib/synergy/DropHelper.h b/src/lib/synergy/DropHelper.h index 021f2cc90..dff840c94 100644 --- a/src/lib/synergy/DropHelper.h +++ b/src/lib/synergy/DropHelper.h @@ -1,11 +1,11 @@ /* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2014-2016 Symless Ltd. - * + * * 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 LICENSE 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 @@ -17,11 +17,11 @@ #pragma once -#include "synergy/DragInformation.h" #include "base/String.h" +#include "synergy/DragInformation.h" class DropHelper { public: - static void writeToDir(const String& destination, - DragFileList& fileList, String& data); + static void writeToDir(const String &destination, DragFileList &fileList, + String &data); }; diff --git a/src/lib/synergy/FileChunk.cpp b/src/lib/synergy/FileChunk.cpp index 490112df8..beec6a390 100644 --- a/src/lib/synergy/FileChunk.cpp +++ b/src/lib/synergy/FileChunk.cpp @@ -1,11 +1,11 @@ /* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2015-2016 Symless Ltd. - * + * * 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 LICENSE 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 @@ -17,140 +17,134 @@ #include "synergy/FileChunk.h" +#include "base/Log.h" +#include "base/Stopwatch.h" +#include "io/IStream.h" #include "synergy/ProtocolUtil.h" #include "synergy/protocol_types.h" -#include "io/IStream.h" -#include "base/Stopwatch.h" -#include "base/Log.h" static const UInt16 kIntervalThreshold = 1; -FileChunk::FileChunk(size_t size) : - Chunk(size) -{ - m_dataSize = size - FILE_CHUNK_META_SIZE; +FileChunk::FileChunk(size_t size) : Chunk(size) { + m_dataSize = size - FILE_CHUNK_META_SIZE; } -FileChunk* -FileChunk::start(const String& size) -{ - size_t sizeLength = size.size(); - FileChunk* start = new FileChunk(sizeLength + FILE_CHUNK_META_SIZE); - char* chunk = start->m_chunk; - chunk[0] = kDataStart; - memcpy(&chunk[1], size.c_str(), sizeLength); - chunk[sizeLength + 1] = '\0'; +FileChunk *FileChunk::start(const String &size) { + size_t sizeLength = size.size(); + FileChunk *start = new FileChunk(sizeLength + FILE_CHUNK_META_SIZE); + char *chunk = start->m_chunk; + chunk[0] = kDataStart; + memcpy(&chunk[1], size.c_str(), sizeLength); + chunk[sizeLength + 1] = '\0'; - return start; + return start; } -FileChunk* -FileChunk::data(UInt8* data, size_t dataSize) -{ - FileChunk* chunk = new FileChunk(dataSize + FILE_CHUNK_META_SIZE); - char* chunkData = chunk->m_chunk; - chunkData[0] = kDataChunk; - memcpy(&chunkData[1], data, dataSize); - chunkData[dataSize + 1] = '\0'; +FileChunk *FileChunk::data(UInt8 *data, size_t dataSize) { + FileChunk *chunk = new FileChunk(dataSize + FILE_CHUNK_META_SIZE); + char *chunkData = chunk->m_chunk; + chunkData[0] = kDataChunk; + memcpy(&chunkData[1], data, dataSize); + chunkData[dataSize + 1] = '\0'; - return chunk; + return chunk; } -FileChunk* -FileChunk::end() -{ - FileChunk* end = new FileChunk(FILE_CHUNK_META_SIZE); - char* chunk = end->m_chunk; - chunk[0] = kDataEnd; - chunk[1] = '\0'; +FileChunk *FileChunk::end() { + FileChunk *end = new FileChunk(FILE_CHUNK_META_SIZE); + char *chunk = end->m_chunk; + chunk[0] = kDataEnd; + chunk[1] = '\0'; - return end; + return end; } -int -FileChunk::assemble(synergy::IStream* stream, String& dataReceived, size_t& expectedSize) -{ - // parse - UInt8 mark = 0; - String content; - static size_t receivedDataSize; - static double elapsedTime; - static Stopwatch stopwatch; - - if (!ProtocolUtil::readf(stream, kMsgDFileTransfer + 4, &mark, &content)) { - return kError; - } - - switch (mark) { - case kDataStart: - dataReceived.clear(); - expectedSize = synergy::string::stringToSizeType(content); - receivedDataSize = 0; - elapsedTime = 0; - stopwatch.reset(); - - if (CLOG->getFilter() >= kDEBUG2) { - LOG((CLOG_DEBUG2 "recv file size=%s", content.c_str())); - stopwatch.start(); - } - return kStart; - - case kDataChunk: - dataReceived.append(content); - if (CLOG->getFilter() >= kDEBUG2) { - LOG((CLOG_DEBUG2 "recv file chunck size=%i", content.size())); - double interval = stopwatch.getTime(); - receivedDataSize += content.size(); - LOG((CLOG_DEBUG2 "recv file interval=%f s", interval)); - if (interval >= kIntervalThreshold) { - double averageSpeed = receivedDataSize / interval / 1000; - LOG((CLOG_DEBUG2 "recv file average speed=%f kb/s", averageSpeed)); - - receivedDataSize = 0; - elapsedTime += interval; - stopwatch.reset(); - } - } - return kNotFinish; - - case kDataEnd: - if (expectedSize != dataReceived.size()) { - LOG((CLOG_ERR "corrupted clipboard data, expected size=%d actual size=%d", expectedSize, dataReceived.size())); - return kError; - } - - if (CLOG->getFilter() >= kDEBUG2) { - LOG((CLOG_DEBUG2 "file transfer finished")); - elapsedTime += stopwatch.getTime(); - double averageSpeed = expectedSize / elapsedTime / 1000; - LOG((CLOG_DEBUG2 "file transfer finished: total time consumed=%f s", elapsedTime)); - LOG((CLOG_DEBUG2 "file transfer finished: total data received=%i kb", expectedSize / 1000)); - LOG((CLOG_DEBUG2 "file transfer finished: total average speed=%f kb/s", averageSpeed)); - } - return kFinish; - } +int FileChunk::assemble(synergy::IStream *stream, String &dataReceived, + size_t &expectedSize) { + // parse + UInt8 mark = 0; + String content; + static size_t receivedDataSize; + static double elapsedTime; + static Stopwatch stopwatch; + if (!ProtocolUtil::readf(stream, kMsgDFileTransfer + 4, &mark, &content)) { return kError; -} + } -void -FileChunk::send(synergy::IStream* stream, UInt8 mark, char* data, size_t dataSize) -{ - String chunk(data, dataSize); + switch (mark) { + case kDataStart: + dataReceived.clear(); + expectedSize = synergy::string::stringToSizeType(content); + receivedDataSize = 0; + elapsedTime = 0; + stopwatch.reset(); - switch (mark) { - case kDataStart: - LOG((CLOG_DEBUG2 "sending file chunk start: size=%s", data)); - break; + if (CLOG->getFilter() >= kDEBUG2) { + LOG((CLOG_DEBUG2 "recv file size=%s", content.c_str())); + stopwatch.start(); + } + return kStart; - case kDataChunk: - LOG((CLOG_DEBUG2 "sending file chunk: size=%i", chunk.size())); - break; + case kDataChunk: + dataReceived.append(content); + if (CLOG->getFilter() >= kDEBUG2) { + LOG((CLOG_DEBUG2 "recv file chunck size=%i", content.size())); + double interval = stopwatch.getTime(); + receivedDataSize += content.size(); + LOG((CLOG_DEBUG2 "recv file interval=%f s", interval)); + if (interval >= kIntervalThreshold) { + double averageSpeed = receivedDataSize / interval / 1000; + LOG((CLOG_DEBUG2 "recv file average speed=%f kb/s", averageSpeed)); - case kDataEnd: - LOG((CLOG_DEBUG2 "sending file finished")); - break; + receivedDataSize = 0; + elapsedTime += interval; + stopwatch.reset(); + } + } + return kNotFinish; + + case kDataEnd: + if (expectedSize != dataReceived.size()) { + LOG((CLOG_ERR "corrupted clipboard data, expected size=%d actual size=%d", + expectedSize, dataReceived.size())); + return kError; } - ProtocolUtil::writef(stream, kMsgDFileTransfer, mark, &chunk); + if (CLOG->getFilter() >= kDEBUG2) { + LOG((CLOG_DEBUG2 "file transfer finished")); + elapsedTime += stopwatch.getTime(); + double averageSpeed = expectedSize / elapsedTime / 1000; + LOG((CLOG_DEBUG2 "file transfer finished: total time consumed=%f s", + elapsedTime)); + LOG((CLOG_DEBUG2 "file transfer finished: total data received=%i kb", + expectedSize / 1000)); + LOG((CLOG_DEBUG2 "file transfer finished: total average speed=%f kb/s", + averageSpeed)); + } + return kFinish; + } + + return kError; +} + +void FileChunk::send(synergy::IStream *stream, UInt8 mark, char *data, + size_t dataSize) { + String chunk(data, dataSize); + + switch (mark) { + case kDataStart: + LOG((CLOG_DEBUG2 "sending file chunk start: size=%s", data)); + break; + + case kDataChunk: + LOG((CLOG_DEBUG2 "sending file chunk: size=%i", chunk.size())); + break; + + case kDataEnd: + LOG((CLOG_DEBUG2 "sending file finished")); + break; + } + + ProtocolUtil::writef(stream, kMsgDFileTransfer, mark, &chunk); } diff --git a/src/lib/synergy/FileChunk.h b/src/lib/synergy/FileChunk.h index 12d02f9c7..574b79b84 100644 --- a/src/lib/synergy/FileChunk.h +++ b/src/lib/synergy/FileChunk.h @@ -1,11 +1,11 @@ /* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2015-2016 Symless Ltd. - * + * * 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 LICENSE 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 @@ -17,9 +17,9 @@ #pragma once -#include "synergy/Chunk.h" #include "base/String.h" #include "common/basic_types.h" +#include "synergy/Chunk.h" #define FILE_CHUNK_META_SIZE 2 @@ -29,18 +29,13 @@ class IStream; class FileChunk : public Chunk { public: - FileChunk(size_t size); + FileChunk(size_t size); - static FileChunk* start(const String& size); - static FileChunk* data(UInt8* data, size_t dataSize); - static FileChunk* end(); - static int assemble( - synergy::IStream* stream, - String& dataCached, - size_t& expectedSize); - static void send( - synergy::IStream* stream, - UInt8 mark, - char* data, - size_t dataSize); + static FileChunk *start(const String &size); + static FileChunk *data(UInt8 *data, size_t dataSize); + static FileChunk *end(); + static int assemble(synergy::IStream *stream, String &dataCached, + size_t &expectedSize); + static void send(synergy::IStream *stream, UInt8 mark, char *data, + size_t dataSize); }; diff --git a/src/lib/synergy/IApp.h b/src/lib/synergy/IApp.h index 82a07c841..441edea9c 100644 --- a/src/lib/synergy/IApp.h +++ b/src/lib/synergy/IApp.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2012 Nick Bolton - * + * * 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 LICENSE 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 @@ -20,33 +20,35 @@ #include "common/IInterface.h" -typedef int (*StartupFunc)(int, char**); +typedef int (*StartupFunc)(int, char **); namespace lib { - namespace synergy { - class ArgsBase; - } +namespace synergy { +class ArgsBase; } +} // namespace lib class ILogOutputter; class IArchTaskBarReceiver; -namespace synergy { class Screen; } +namespace synergy { +class Screen; +} class IEventQueue; -class IApp : public IInterface -{ +class IApp : public IInterface { public: - virtual void setByeFunc(void(*bye)(int)) = 0; - virtual lib::synergy::ArgsBase& argsBase() const = 0; - virtual int standardStartup(int argc, char** argv) = 0; - virtual int runInner(int argc, char** argv, ILogOutputter* outputter, StartupFunc startup) = 0; - virtual void startNode() = 0; - virtual IArchTaskBarReceiver* taskBarReceiver() const = 0; - virtual void bye(int error) = 0; - virtual int mainLoop() = 0; - virtual void initApp(int argc, const char** argv) = 0; - virtual const char* daemonName() const = 0; - virtual int foregroundStartup(int argc, char** argv) = 0; - virtual synergy::Screen* createScreen() = 0; - virtual IEventQueue* getEvents() const = 0; + virtual void setByeFunc(void (*bye)(int)) = 0; + virtual lib::synergy::ArgsBase &argsBase() const = 0; + virtual int standardStartup(int argc, char **argv) = 0; + virtual int runInner(int argc, char **argv, ILogOutputter *outputter, + StartupFunc startup) = 0; + virtual void startNode() = 0; + virtual IArchTaskBarReceiver *taskBarReceiver() const = 0; + virtual void bye(int error) = 0; + virtual int mainLoop() = 0; + virtual void initApp(int argc, const char **argv) = 0; + virtual const char *daemonName() const = 0; + virtual int foregroundStartup(int argc, char **argv) = 0; + virtual synergy::Screen *createScreen() = 0; + virtual IEventQueue *getEvents() const = 0; }; diff --git a/src/lib/synergy/IAppUtil.h b/src/lib/synergy/IAppUtil.h index d4fa1654b..d2be8014b 100644 --- a/src/lib/synergy/IAppUtil.h +++ b/src/lib/synergy/IAppUtil.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -15,21 +15,22 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + #pragma once +#include "base/String.h" #include "common/IInterface.h" #include "synergy/IApp.h" -#include "base/String.h" class IAppUtil : public IInterface { public: - virtual void adoptApp(IApp* app) = 0; - virtual IApp& app() const = 0; - virtual int run(int argc, char** argv) = 0; - virtual void beforeAppExit() = 0; - virtual void startNode() = 0; - virtual std::vector getKeyboardLayoutList() = 0; - virtual String getCurrentLanguageCode() = 0; - virtual void showNotification(const String& title, const String& text) const = 0; + virtual void adoptApp(IApp *app) = 0; + virtual IApp &app() const = 0; + virtual int run(int argc, char **argv) = 0; + virtual void beforeAppExit() = 0; + virtual void startNode() = 0; + virtual std::vector getKeyboardLayoutList() = 0; + virtual String getCurrentLanguageCode() = 0; + virtual void showNotification(const String &title, + const String &text) const = 0; }; diff --git a/src/lib/synergy/IClient.h b/src/lib/synergy/IClient.h index ad889f37d..a4a31afd9 100644 --- a/src/lib/synergy/IClient.h +++ b/src/lib/synergy/IClient.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -18,12 +18,12 @@ #pragma once -#include "synergy/clipboard_types.h" +#include "base/String.h" #include "synergy/IScreen.h" +#include "synergy/clipboard_types.h" #include "synergy/key_types.h" #include "synergy/mouse_types.h" #include "synergy/option_types.h" -#include "base/String.h" //! Client interface /*! @@ -32,145 +32,145 @@ communicate with a client. */ class IClient : public IScreen { public: - //! @name manipulators - //@{ + //! @name manipulators + //@{ - //! Enter screen - /*! - Enter the screen. The cursor should be warped to \p xAbs,yAbs. - \p mask is the expected toggle button state and the client should - update its state to match. \p forScreensaver is true iff the - screen is being entered because the screen saver is starting. - Subsequent clipboard events should report \p seqNum. - */ - virtual void enter(SInt32 xAbs, SInt32 yAbs, - UInt32 seqNum, KeyModifierMask mask, - bool forScreensaver) = 0; + //! Enter screen + /*! + Enter the screen. The cursor should be warped to \p xAbs,yAbs. + \p mask is the expected toggle button state and the client should + update its state to match. \p forScreensaver is true iff the + screen is being entered because the screen saver is starting. + Subsequent clipboard events should report \p seqNum. + */ + virtual void enter(SInt32 xAbs, SInt32 yAbs, UInt32 seqNum, + KeyModifierMask mask, bool forScreensaver) = 0; - //! Leave screen - /*! - Leave the screen. Return false iff the user may not leave the - client's screen (because, for example, a button is down). - */ - virtual bool leave() = 0; + //! Leave screen + /*! + Leave the screen. Return false iff the user may not leave the + client's screen (because, for example, a button is down). + */ + virtual bool leave() = 0; - //! Set clipboard - /*! - Update the client's clipboard. This implies that the client's - clipboard is now up to date. If the client's clipboard was - already known to be up to date then this may do nothing. \c data - has marshalled clipboard data. - */ - virtual void setClipboard(ClipboardID, const IClipboard*) = 0; + //! Set clipboard + /*! + Update the client's clipboard. This implies that the client's + clipboard is now up to date. If the client's clipboard was + already known to be up to date then this may do nothing. \c data + has marshalled clipboard data. + */ + virtual void setClipboard(ClipboardID, const IClipboard *) = 0; - //! Grab clipboard - /*! - Grab (i.e. take ownership of) the client's clipboard. Since this - is called when another client takes ownership of the clipboard it - implies that the client's clipboard is out of date. - */ - virtual void grabClipboard(ClipboardID) = 0; + //! Grab clipboard + /*! + Grab (i.e. take ownership of) the client's clipboard. Since this + is called when another client takes ownership of the clipboard it + implies that the client's clipboard is out of date. + */ + virtual void grabClipboard(ClipboardID) = 0; - //! Mark clipboard dirty - /*! - Mark the client's clipboard as dirty (out of date) or clean (up to - date). - */ - virtual void setClipboardDirty(ClipboardID, bool dirty) = 0; + //! Mark clipboard dirty + /*! + Mark the client's clipboard as dirty (out of date) or clean (up to + date). + */ + virtual void setClipboardDirty(ClipboardID, bool dirty) = 0; - //! Notify of key press - /*! - Synthesize key events to generate a press of key \c id. If possible - match the given modifier mask. The KeyButton identifies the physical - key on the server that generated this key down. The client must - ensure that a key up or key repeat that uses the same KeyButton will - synthesize an up or repeat for the same client key synthesized by - keyDown(). - */ - virtual void keyDown(KeyID id, KeyModifierMask, KeyButton, const String&) = 0; + //! Notify of key press + /*! + Synthesize key events to generate a press of key \c id. If possible + match the given modifier mask. The KeyButton identifies the physical + key on the server that generated this key down. The client must + ensure that a key up or key repeat that uses the same KeyButton will + synthesize an up or repeat for the same client key synthesized by + keyDown(). + */ + virtual void keyDown(KeyID id, KeyModifierMask, KeyButton, + const String &) = 0; - //! Notify of key repeat - /*! - Synthesize key events to generate a press and release of key \c id - \c count times. If possible match the given modifier mask. - */ - virtual void keyRepeat(KeyID id, KeyModifierMask, - SInt32 count, KeyButton, const String& lang) = 0; + //! Notify of key repeat + /*! + Synthesize key events to generate a press and release of key \c id + \c count times. If possible match the given modifier mask. + */ + virtual void keyRepeat(KeyID id, KeyModifierMask, SInt32 count, KeyButton, + const String &lang) = 0; - //! Notify of key release - /*! - Synthesize key events to generate a release of key \c id. If possible - match the given modifier mask. - */ - virtual void keyUp(KeyID id, KeyModifierMask, KeyButton) = 0; + //! Notify of key release + /*! + Synthesize key events to generate a release of key \c id. If possible + match the given modifier mask. + */ + virtual void keyUp(KeyID id, KeyModifierMask, KeyButton) = 0; - //! Notify of mouse press - /*! - Synthesize mouse events to generate a press of mouse button \c id. - */ - virtual void mouseDown(ButtonID id) = 0; + //! Notify of mouse press + /*! + Synthesize mouse events to generate a press of mouse button \c id. + */ + virtual void mouseDown(ButtonID id) = 0; - //! Notify of mouse release - /*! - Synthesize mouse events to generate a release of mouse button \c id. - */ - virtual void mouseUp(ButtonID id) = 0; + //! Notify of mouse release + /*! + Synthesize mouse events to generate a release of mouse button \c id. + */ + virtual void mouseUp(ButtonID id) = 0; - //! Notify of mouse motion - /*! - Synthesize mouse events to generate mouse motion to the absolute - screen position \c xAbs,yAbs. - */ - virtual void mouseMove(SInt32 xAbs, SInt32 yAbs) = 0; + //! Notify of mouse motion + /*! + Synthesize mouse events to generate mouse motion to the absolute + screen position \c xAbs,yAbs. + */ + virtual void mouseMove(SInt32 xAbs, SInt32 yAbs) = 0; - //! Notify of mouse motion - /*! - Synthesize mouse events to generate mouse motion by the relative - amount \c xRel,yRel. - */ - virtual void mouseRelativeMove(SInt32 xRel, SInt32 yRel) = 0; + //! Notify of mouse motion + /*! + Synthesize mouse events to generate mouse motion by the relative + amount \c xRel,yRel. + */ + virtual void mouseRelativeMove(SInt32 xRel, SInt32 yRel) = 0; - //! Notify of mouse wheel motion - /*! - Synthesize mouse events to generate mouse wheel motion of \c xDelta - and \c yDelta. Deltas are positive for motion away from the user or - to the right and negative for motion towards the user or to the left. - Each wheel click should generate a delta of +/-120. - */ - virtual void mouseWheel(SInt32 xDelta, SInt32 yDelta) = 0; + //! Notify of mouse wheel motion + /*! + Synthesize mouse events to generate mouse wheel motion of \c xDelta + and \c yDelta. Deltas are positive for motion away from the user or + to the right and negative for motion towards the user or to the left. + Each wheel click should generate a delta of +/-120. + */ + virtual void mouseWheel(SInt32 xDelta, SInt32 yDelta) = 0; - //! Notify of screen saver change - virtual void screensaver(bool activate) = 0; + //! Notify of screen saver change + virtual void screensaver(bool activate) = 0; - //! Notify of options changes - /*! - Reset all options to their default values. - */ - virtual void resetOptions() = 0; + //! Notify of options changes + /*! + Reset all options to their default values. + */ + virtual void resetOptions() = 0; - //! Notify of options changes - /*! - Set options to given values. Ignore unknown options and don't - modify our options that aren't given in \c options. - */ - virtual void setOptions(const OptionsList& options) = 0; + //! Notify of options changes + /*! + Set options to given values. Ignore unknown options and don't + modify our options that aren't given in \c options. + */ + virtual void setOptions(const OptionsList &options) = 0; - //@} - //! @name accessors - //@{ + //@} + //! @name accessors + //@{ - //! Get client name - /*! - Return the client's name. - */ - virtual String getName() const = 0; + //! Get client name + /*! + Return the client's name. + */ + virtual String getName() const = 0; - //@} + //@} - // IScreen overrides - virtual void* getEventTarget() const = 0; - virtual bool getClipboard(ClipboardID id, IClipboard*) const = 0; - virtual void getShape(SInt32& x, SInt32& y, - SInt32& width, SInt32& height) const = 0; - virtual void getCursorPos(SInt32& x, SInt32& y) const = 0; + // IScreen overrides + virtual void *getEventTarget() const = 0; + virtual bool getClipboard(ClipboardID id, IClipboard *) const = 0; + virtual void getShape(SInt32 &x, SInt32 &y, SInt32 &width, + SInt32 &height) const = 0; + virtual void getCursorPos(SInt32 &x, SInt32 &y) const = 0; }; diff --git a/src/lib/synergy/IClipboard.cpp b/src/lib/synergy/IClipboard.cpp index a554c9c18..264f5f7d3 100644 --- a/src/lib/synergy/IClipboard.cpp +++ b/src/lib/synergy/IClipboard.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 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 LICENSE 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 @@ -23,146 +23,133 @@ // IClipboard // -void -IClipboard::unmarshall(IClipboard* clipboard, const String& data, Time time) -{ - assert(clipboard != NULL); +void IClipboard::unmarshall(IClipboard *clipboard, const String &data, + Time time) { + assert(clipboard != NULL); - const char* index = data.data(); + const char *index = data.data(); - if (clipboard->open(time)) { - // clear existing data - clipboard->empty(); + if (clipboard->open(time)) { + // clear existing data + clipboard->empty(); - // read the number of formats - const UInt32 numFormats = readUInt32(index); - index += 4; + // read the number of formats + const UInt32 numFormats = readUInt32(index); + index += 4; - // read each format - for (UInt32 i = 0; i < numFormats; ++i) { - // get the format id - IClipboard::EFormat format = - static_cast(readUInt32(index)); - index += 4; + // read each format + for (UInt32 i = 0; i < numFormats; ++i) { + // get the format id + IClipboard::EFormat format = + static_cast(readUInt32(index)); + index += 4; - // get the size of the format data - UInt32 size = readUInt32(index); - index += 4; + // get the size of the format data + UInt32 size = readUInt32(index); + index += 4; - // save the data if it's a known format. if either the client - // or server supports more clipboard formats than the other - // then one of them will get a format >= kNumFormats here. - if (format add(format, String(index, size)); - } - index += size; - } - - // done - clipboard->close(); - } -} - -String -IClipboard::marshall(const IClipboard* clipboard) -{ - // return data format: - // 4 bytes => number of formats included - // 4 bytes => format enum - // 4 bytes => clipboard data size n - // n bytes => clipboard data - // back to the second 4 bytes if there is another format - - assert(clipboard != NULL); - - String data; - - std::vector formatData; - formatData.resize(IClipboard::kNumFormats); - // FIXME -- use current time - if (clipboard->open(0)) { - - // compute size of marshalled data - UInt32 size = 4; - UInt32 numFormats = 0; - for (UInt32 format = 0; format != IClipboard::kNumFormats; ++format) { - if (clipboard->has(static_cast(format))) { - ++numFormats; - formatData[format] = - clipboard->get(static_cast(format)); - size += 4 + 4 + (UInt32)formatData[format].size(); - } - } - - // allocate space - data.reserve(size); - - // marshall the data - writeUInt32(&data, numFormats); - for (UInt32 format = 0; format != IClipboard::kNumFormats; ++format) { - if (clipboard->has(static_cast(format))) { - writeUInt32(&data, format); - writeUInt32(&data, (UInt32)formatData[format].size()); - data += formatData[format]; - } - } - clipboard->close(); + // save the data if it's a known format. if either the client + // or server supports more clipboard formats than the other + // then one of them will get a format >= kNumFormats here. + if (format < IClipboard::kNumFormats) { + clipboard->add(format, String(index, size)); + } + index += size; } - return data; + // done + clipboard->close(); + } } -bool -IClipboard::copy(IClipboard* dst, const IClipboard* src) -{ - assert(dst != NULL); - assert(src != NULL); +String IClipboard::marshall(const IClipboard *clipboard) { + // return data format: + // 4 bytes => number of formats included + // 4 bytes => format enum + // 4 bytes => clipboard data size n + // n bytes => clipboard data + // back to the second 4 bytes if there is another format - return copy(dst, src, src->getTime()); -} + assert(clipboard != NULL); -bool -IClipboard::copy(IClipboard* dst, const IClipboard* src, Time time) -{ - assert(dst != NULL); - assert(src != NULL); + String data; - bool success = false; - if (src->open(time)) { - if (dst->open(time)) { - if (dst->empty()) { - for (SInt32 format = 0; - format != IClipboard::kNumFormats; ++format) { - IClipboard::EFormat eFormat = (IClipboard::EFormat)format; - if (src->has(eFormat)) { - dst->add(eFormat, src->get(eFormat)); - } - } - success = true; - } - dst->close(); - } - src->close(); + std::vector formatData; + formatData.resize(IClipboard::kNumFormats); + // FIXME -- use current time + if (clipboard->open(0)) { + + // compute size of marshalled data + UInt32 size = 4; + UInt32 numFormats = 0; + for (UInt32 format = 0; format != IClipboard::kNumFormats; ++format) { + if (clipboard->has(static_cast(format))) { + ++numFormats; + formatData[format] = + clipboard->get(static_cast(format)); + size += 4 + 4 + (UInt32)formatData[format].size(); + } } - return success; + // allocate space + data.reserve(size); + + // marshall the data + writeUInt32(&data, numFormats); + for (UInt32 format = 0; format != IClipboard::kNumFormats; ++format) { + if (clipboard->has(static_cast(format))) { + writeUInt32(&data, format); + writeUInt32(&data, (UInt32)formatData[format].size()); + data += formatData[format]; + } + } + clipboard->close(); + } + + return data; } -UInt32 -IClipboard::readUInt32(const char* buf) -{ - const unsigned char* ubuf = reinterpret_cast(buf); - return (static_cast(ubuf[0]) << 24) | - (static_cast(ubuf[1]) << 16) | - (static_cast(ubuf[2]) << 8) | - static_cast(ubuf[3]); +bool IClipboard::copy(IClipboard *dst, const IClipboard *src) { + assert(dst != NULL); + assert(src != NULL); + + return copy(dst, src, src->getTime()); } -void -IClipboard::writeUInt32(String* buf, UInt32 v) -{ - *buf += static_cast((v >> 24) & 0xff); - *buf += static_cast((v >> 16) & 0xff); - *buf += static_cast((v >> 8) & 0xff); - *buf += static_cast( v & 0xff); +bool IClipboard::copy(IClipboard *dst, const IClipboard *src, Time time) { + assert(dst != NULL); + assert(src != NULL); + + bool success = false; + if (src->open(time)) { + if (dst->open(time)) { + if (dst->empty()) { + for (SInt32 format = 0; format != IClipboard::kNumFormats; ++format) { + IClipboard::EFormat eFormat = (IClipboard::EFormat)format; + if (src->has(eFormat)) { + dst->add(eFormat, src->get(eFormat)); + } + } + success = true; + } + dst->close(); + } + src->close(); + } + + return success; +} + +UInt32 IClipboard::readUInt32(const char *buf) { + const unsigned char *ubuf = reinterpret_cast(buf); + return (static_cast(ubuf[0]) << 24) | + (static_cast(ubuf[1]) << 16) | + (static_cast(ubuf[2]) << 8) | static_cast(ubuf[3]); +} + +void IClipboard::writeUInt32(String *buf, UInt32 v) { + *buf += static_cast((v >> 24) & 0xff); + *buf += static_cast((v >> 16) & 0xff); + *buf += static_cast((v >> 8) & 0xff); + *buf += static_cast(v & 0xff); } diff --git a/src/lib/synergy/IClipboard.h b/src/lib/synergy/IClipboard.h index 13522634a..b4ecc2d7d 100644 --- a/src/lib/synergy/IClipboard.h +++ b/src/lib/synergy/IClipboard.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -18,8 +18,8 @@ #pragma once -#include "base/String.h" #include "base/EventTypes.h" +#include "base/String.h" #include "common/IInterface.h" //! Clipboard interface @@ -28,142 +28,141 @@ This interface defines the methods common to all clipboards. */ class IClipboard : public IInterface { public: - //! Timestamp type - /*! - Timestamp type. Timestamps are in milliseconds from some - arbitrary starting time. Timestamps will wrap around to 0 - after about 49 3/4 days. - */ - typedef UInt32 Time; + //! Timestamp type + /*! + Timestamp type. Timestamps are in milliseconds from some + arbitrary starting time. Timestamps will wrap around to 0 + after about 49 3/4 days. + */ + typedef UInt32 Time; - //! Clipboard formats - /*! - The list of known clipboard formats. kNumFormats must be last and - formats must be sequential starting from zero. Clipboard data set - via add() and retrieved via get() must be in one of these formats. - Platform dependent clipboard subclasses can and should present any - suitable formats derivable from these formats. + //! Clipboard formats + /*! + The list of known clipboard formats. kNumFormats must be last and + formats must be sequential starting from zero. Clipboard data set + via add() and retrieved via get() must be in one of these formats. + Platform dependent clipboard subclasses can and should present any + suitable formats derivable from these formats. - \c kText is a text format encoded in UTF-8. Newlines are LF (not - CR or LF/CR). + \c kText is a text format encoded in UTF-8. Newlines are LF (not + CR or LF/CR). - \c kBitmap is an image format. The data is a BMP file without the - 14 byte header (i.e. starting at the INFOHEADER) and with the image - data immediately following the 40 byte INFOHEADER. + \c kBitmap is an image format. The data is a BMP file without the + 14 byte header (i.e. starting at the INFOHEADER) and with the image + data immediately following the 40 byte INFOHEADER. - \c kHTML is a text format encoded in UTF-8 and containing a valid - HTML fragment (but not necessarily a complete HTML document). - Newlines are LF. - */ - enum EFormat { - kText, //!< Text format, UTF-8, newline is LF - kHTML, //!< HTML format, HTML fragment, UTF-8, newline is LF - kBitmap, //!< Bitmap format, BMP 24/32bpp, BI_RGB - kNumFormats //!< The number of clipboard formats - }; + \c kHTML is a text format encoded in UTF-8 and containing a valid + HTML fragment (but not necessarily a complete HTML document). + Newlines are LF. + */ + enum EFormat { + kText, //!< Text format, UTF-8, newline is LF + kHTML, //!< HTML format, HTML fragment, UTF-8, newline is LF + kBitmap, //!< Bitmap format, BMP 24/32bpp, BI_RGB + kNumFormats //!< The number of clipboard formats + }; - //! @name manipulators - //@{ + //! @name manipulators + //@{ - //! Empty clipboard - /*! - Take ownership of the clipboard and clear all data from it. - This must be called between a successful open() and close(). - Return false if the clipboard ownership could not be taken; - the clipboard should not be emptied in this case. - */ - virtual bool empty() = 0; + //! Empty clipboard + /*! + Take ownership of the clipboard and clear all data from it. + This must be called between a successful open() and close(). + Return false if the clipboard ownership could not be taken; + the clipboard should not be emptied in this case. + */ + virtual bool empty() = 0; - //! Add data - /*! - Add data in the given format to the clipboard. May only be - called after a successful empty(). - */ - virtual void add(EFormat, const String& data) = 0; + //! Add data + /*! + Add data in the given format to the clipboard. May only be + called after a successful empty(). + */ + virtual void add(EFormat, const String &data) = 0; - //@} - //! @name accessors - //@{ + //@} + //! @name accessors + //@{ - //! Open clipboard - /*! - Open the clipboard. Return true iff the clipboard could be - opened. If open() returns true then the client must call - close() at some later time; if it returns false then close() - must not be called. \c time should be the current time or - a time in the past when the open should effectively have taken - place. - */ - virtual bool open(Time time) const = 0; + //! Open clipboard + /*! + Open the clipboard. Return true iff the clipboard could be + opened. If open() returns true then the client must call + close() at some later time; if it returns false then close() + must not be called. \c time should be the current time or + a time in the past when the open should effectively have taken + place. + */ + virtual bool open(Time time) const = 0; - //! Close clipboard - /*! - Close the clipboard. close() must match a preceding successful - open(). This signals that the clipboard has been filled with - all the necessary data or all data has been read. It does not - mean the clipboard ownership should be released (if it was - taken). - */ - virtual void close() const = 0; + //! Close clipboard + /*! + Close the clipboard. close() must match a preceding successful + open(). This signals that the clipboard has been filled with + all the necessary data or all data has been read. It does not + mean the clipboard ownership should be released (if it was + taken). + */ + virtual void close() const = 0; - //! Get time - /*! - Return the timestamp passed to the last successful open(). - */ - virtual Time getTime() const = 0; + //! Get time + /*! + Return the timestamp passed to the last successful open(). + */ + virtual Time getTime() const = 0; - //! Check for data - /*! - Return true iff the clipboard contains data in the given - format. Must be called between a successful open() and close(). - */ - virtual bool has(EFormat) const = 0; + //! Check for data + /*! + Return true iff the clipboard contains data in the given + format. Must be called between a successful open() and close(). + */ + virtual bool has(EFormat) const = 0; - //! Get data - /*! - Return the data in the given format. Returns the empty string - if there is no data in that format. Must be called between - a successful open() and close(). - */ - virtual String get(EFormat) const = 0; + //! Get data + /*! + Return the data in the given format. Returns the empty string + if there is no data in that format. Must be called between + a successful open() and close(). + */ + virtual String get(EFormat) const = 0; - //! Marshall clipboard data - /*! - Merge \p clipboard's data into a single buffer that can be later - unmarshalled to restore the clipboard and return the buffer. - */ - static String marshall(const IClipboard* clipboard); + //! Marshall clipboard data + /*! + Merge \p clipboard's data into a single buffer that can be later + unmarshalled to restore the clipboard and return the buffer. + */ + static String marshall(const IClipboard *clipboard); - //! Unmarshall clipboard data - /*! - Extract marshalled clipboard data and store it in \p clipboard. - Sets the clipboard time to \c time. - */ - static void unmarshall(IClipboard* clipboard, - const String& data, Time time); + //! Unmarshall clipboard data + /*! + Extract marshalled clipboard data and store it in \p clipboard. + Sets the clipboard time to \c time. + */ + static void unmarshall(IClipboard *clipboard, const String &data, Time time); - //! Copy clipboard - /*! - Transfers all the data in one clipboard to another. The - clipboards can be of any concrete clipboard type (and - they don't have to be the same type). This also sets - the destination clipboard's timestamp to source clipboard's - timestamp. Returns true iff the copy succeeded. - */ - static bool copy(IClipboard* dst, const IClipboard* src); + //! Copy clipboard + /*! + Transfers all the data in one clipboard to another. The + clipboards can be of any concrete clipboard type (and + they don't have to be the same type). This also sets + the destination clipboard's timestamp to source clipboard's + timestamp. Returns true iff the copy succeeded. + */ + static bool copy(IClipboard *dst, const IClipboard *src); - //! Copy clipboard - /*! - Transfers all the data in one clipboard to another. The - clipboards can be of any concrete clipboard type (and they - don't have to be the same type). This also sets the - timestamp to \c time. Returns true iff the copy succeeded. - */ - static bool copy(IClipboard* dst, const IClipboard* src, Time); + //! Copy clipboard + /*! + Transfers all the data in one clipboard to another. The + clipboards can be of any concrete clipboard type (and they + don't have to be the same type). This also sets the + timestamp to \c time. Returns true iff the copy succeeded. + */ + static bool copy(IClipboard *dst, const IClipboard *src, Time); - //@} + //@} private: - static UInt32 readUInt32(const char*); - static void writeUInt32(String*, UInt32); + static UInt32 readUInt32(const char *); + static void writeUInt32(String *, UInt32); }; diff --git a/src/lib/synergy/IKeyState.cpp b/src/lib/synergy/IKeyState.cpp index 4b21fcb9f..43d4e1f0e 100644 --- a/src/lib/synergy/IKeyState.cpp +++ b/src/lib/synergy/IKeyState.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 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 LICENSE 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 @@ -20,143 +20,123 @@ #include "base/EventQueue.h" #include -#include #include +#include // // IKeyState // -IKeyState::IKeyState(IEventQueue* events) -{ -} +IKeyState::IKeyState(IEventQueue *events) {} // // IKeyState::KeyInfo // -IKeyState::KeyInfo* -IKeyState::KeyInfo::alloc(KeyID id, - KeyModifierMask mask, KeyButton button, SInt32 count) -{ - KeyInfo* info = (KeyInfo*)malloc(sizeof(KeyInfo)); - info->m_key = id; - info->m_mask = mask; - info->m_button = button; - info->m_count = count; - info->m_screens = NULL; - info->m_screensBuffer[0] = '\0'; - return info; +IKeyState::KeyInfo *IKeyState::KeyInfo::alloc(KeyID id, KeyModifierMask mask, + KeyButton button, SInt32 count) { + KeyInfo *info = (KeyInfo *)malloc(sizeof(KeyInfo)); + info->m_key = id; + info->m_mask = mask; + info->m_button = button; + info->m_count = count; + info->m_screens = NULL; + info->m_screensBuffer[0] = '\0'; + return info; } -IKeyState::KeyInfo* -IKeyState::KeyInfo::alloc(KeyID id, - KeyModifierMask mask, KeyButton button, SInt32 count, - const std::set& destinations) -{ - String screens = join(destinations); +IKeyState::KeyInfo * +IKeyState::KeyInfo::alloc(KeyID id, KeyModifierMask mask, KeyButton button, + SInt32 count, const std::set &destinations) { + String screens = join(destinations); - // build structure - KeyInfo* info = (KeyInfo*)malloc(sizeof(KeyInfo) + screens.size()); - info->m_key = id; - info->m_mask = mask; - info->m_button = button; - info->m_count = count; - info->m_screens = info->m_screensBuffer; - strcpy(info->m_screensBuffer, screens.c_str()); // Compliant: String type is safe - return info; + // build structure + KeyInfo *info = (KeyInfo *)malloc(sizeof(KeyInfo) + screens.size()); + info->m_key = id; + info->m_mask = mask; + info->m_button = button; + info->m_count = count; + info->m_screens = info->m_screensBuffer; + strcpy(info->m_screensBuffer, + screens.c_str()); // Compliant: String type is safe + return info; } -IKeyState::KeyInfo* -IKeyState::KeyInfo::alloc(const KeyInfo& x) -{ - auto bufferLen = strnlen(x.m_screensBuffer, SIZE_MAX); - auto info = (KeyInfo*)malloc(sizeof(KeyInfo) + bufferLen); - info->m_key = x.m_key; - info->m_mask = x.m_mask; - info->m_button = x.m_button; - info->m_count = x.m_count; - info->m_screens = x.m_screens ? info->m_screensBuffer : NULL; - memcpy(info->m_screensBuffer, x.m_screensBuffer, bufferLen + 1); - return info; +IKeyState::KeyInfo *IKeyState::KeyInfo::alloc(const KeyInfo &x) { + auto bufferLen = strnlen(x.m_screensBuffer, SIZE_MAX); + auto info = (KeyInfo *)malloc(sizeof(KeyInfo) + bufferLen); + info->m_key = x.m_key; + info->m_mask = x.m_mask; + info->m_button = x.m_button; + info->m_count = x.m_count; + info->m_screens = x.m_screens ? info->m_screensBuffer : NULL; + memcpy(info->m_screensBuffer, x.m_screensBuffer, bufferLen + 1); + return info; } -bool -IKeyState::KeyInfo::isDefault(const char* screens) -{ - return (screens == NULL || screens[0] == '\0'); +bool IKeyState::KeyInfo::isDefault(const char *screens) { + return (screens == NULL || screens[0] == '\0'); } -bool -IKeyState::KeyInfo::contains(const char* screens, const String& name) -{ - // special cases - if (isDefault(screens)) { - return false; +bool IKeyState::KeyInfo::contains(const char *screens, const String &name) { + // special cases + if (isDefault(screens)) { + return false; + } + if (screens[0] == '*') { + return true; + } + + // search + String match; + match.reserve(name.size() + 2); + match += ":"; + match += name; + match += ":"; + return (strstr(screens, match.c_str()) != NULL); +} + +bool IKeyState::KeyInfo::equal(const KeyInfo *a, const KeyInfo *b) { + return (a->m_key == b->m_key && a->m_mask == b->m_mask && + a->m_button == b->m_button && a->m_count == b->m_count && + strcmp(a->m_screensBuffer, b->m_screensBuffer) == 0); +} + +String IKeyState::KeyInfo::join(const std::set &destinations) { + // collect destinations into a string. names are surrounded by ':' + // which makes searching easy. the string is empty if there are no + // destinations and "*" means all destinations. + String screens; + for (std::set::const_iterator i = destinations.begin(); + i != destinations.end(); ++i) { + if (*i == "*") { + screens = "*"; + break; + } else { + if (screens.empty()) { + screens = ":"; + } + screens += *i; + screens += ":"; } - if (screens[0] == '*') { - return true; - } - - // search - String match; - match.reserve(name.size() + 2); - match += ":"; - match += name; - match += ":"; - return (strstr(screens, match.c_str()) != NULL); + } + return screens; } -bool -IKeyState::KeyInfo::equal(const KeyInfo* a, const KeyInfo* b) -{ - return (a->m_key == b->m_key && - a->m_mask == b->m_mask && - a->m_button == b->m_button && - a->m_count == b->m_count && - strcmp(a->m_screensBuffer, b->m_screensBuffer) == 0); -} +void IKeyState::KeyInfo::split(const char *screens, std::set &dst) { + dst.clear(); + if (isDefault(screens)) { + return; + } + if (screens[0] == '*') { + dst.insert("*"); + return; + } -String -IKeyState::KeyInfo::join(const std::set& destinations) -{ - // collect destinations into a string. names are surrounded by ':' - // which makes searching easy. the string is empty if there are no - // destinations and "*" means all destinations. - String screens; - for (std::set::const_iterator i = destinations.begin(); - i != destinations.end(); ++i) { - if (*i == "*") { - screens = "*"; - break; - } - else { - if (screens.empty()) { - screens = ":"; - } - screens += *i; - screens += ":"; - } - } - return screens; -} - -void -IKeyState::KeyInfo::split(const char* screens, std::set& dst) -{ - dst.clear(); - if (isDefault(screens)) { - return; - } - if (screens[0] == '*') { - dst.insert("*"); - return; - } - - const char* i = screens + 1; - while (*i != '\0') { - const char* j = strchr(i, ':'); - dst.insert(String(i, j - i)); - i = j + 1; - } + const char *i = screens + 1; + while (*i != '\0') { + const char *j = strchr(i, ':'); + dst.insert(String(i, j - i)); + i = j + 1; + } } diff --git a/src/lib/synergy/IKeyState.h b/src/lib/synergy/IKeyState.h index df995fa88..d56150ceb 100644 --- a/src/lib/synergy/IKeyState.h +++ b/src/lib/synergy/IKeyState.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2003 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 LICENSE 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 @@ -18,13 +18,13 @@ #pragma once -#include "synergy/key_types.h" #include "base/Event.h" -#include "base/String.h" -#include "base/IEventQueue.h" #include "base/EventTypes.h" -#include "common/stdset.h" +#include "base/IEventQueue.h" +#include "base/String.h" #include "common/IInterface.h" +#include "common/stdset.h" +#include "synergy/key_types.h" //! Key state interface /*! @@ -33,142 +33,138 @@ to synthesize key events. */ class IKeyState : public IInterface { public: - IKeyState(IEventQueue* events); + IKeyState(IEventQueue *events); - enum { - kNumButtons = 0x200 - }; + enum { kNumButtons = 0x200 }; - //! Key event data - class KeyInfo { - public: - static KeyInfo* alloc(KeyID, KeyModifierMask, KeyButton, SInt32 count); - static KeyInfo* alloc(KeyID, KeyModifierMask, KeyButton, SInt32 count, - const std::set& destinations); - static KeyInfo* alloc(const KeyInfo&); + //! Key event data + class KeyInfo { + public: + static KeyInfo *alloc(KeyID, KeyModifierMask, KeyButton, SInt32 count); + static KeyInfo *alloc(KeyID, KeyModifierMask, KeyButton, SInt32 count, + const std::set &destinations); + static KeyInfo *alloc(const KeyInfo &); - static bool isDefault(const char* screens); - static bool contains(const char* screens, const String& name); - static bool equal(const KeyInfo*, const KeyInfo*); - static String join(const std::set& destinations); - static void split(const char* screens, std::set&); + static bool isDefault(const char *screens); + static bool contains(const char *screens, const String &name); + static bool equal(const KeyInfo *, const KeyInfo *); + static String join(const std::set &destinations); + static void split(const char *screens, std::set &); - public: - KeyID m_key; - KeyModifierMask m_mask; - KeyButton m_button; - SInt32 m_count; - char* m_screens; - char m_screensBuffer[1]; - }; + public: + KeyID m_key; + KeyModifierMask m_mask; + KeyButton m_button; + SInt32 m_count; + char *m_screens; + char m_screensBuffer[1]; + }; - typedef std::set KeyButtonSet; + typedef std::set KeyButtonSet; - //! @name manipulators - //@{ + //! @name manipulators + //@{ - //! Update the keyboard map - /*! - Causes the key state to get updated to reflect the current keyboard - mapping. - */ - virtual void updateKeyMap() = 0; + //! Update the keyboard map + /*! + Causes the key state to get updated to reflect the current keyboard + mapping. + */ + virtual void updateKeyMap() = 0; - //! Update the key state - /*! - Causes the key state to get updated to reflect the physical keyboard - state. - */ - virtual void updateKeyState() = 0; + //! Update the key state + /*! + Causes the key state to get updated to reflect the physical keyboard + state. + */ + virtual void updateKeyState() = 0; - //! Set half-duplex mask - /*! - Sets which modifier toggle keys are half-duplex. A half-duplex - toggle key doesn't report a key release when toggled on and - doesn't report a key press when toggled off. - */ - virtual void setHalfDuplexMask(KeyModifierMask) = 0; + //! Set half-duplex mask + /*! + Sets which modifier toggle keys are half-duplex. A half-duplex + toggle key doesn't report a key release when toggled on and + doesn't report a key press when toggled off. + */ + virtual void setHalfDuplexMask(KeyModifierMask) = 0; - //! Fake a key press - /*! - Synthesizes a key press event and updates the key state. - */ - virtual void fakeKeyDown(KeyID id, KeyModifierMask mask, - KeyButton button, const String& lang) = 0; + //! Fake a key press + /*! + Synthesizes a key press event and updates the key state. + */ + virtual void fakeKeyDown(KeyID id, KeyModifierMask mask, KeyButton button, + const String &lang) = 0; - //! Fake a key repeat - /*! - Synthesizes a key repeat event and updates the key state. - */ - virtual bool fakeKeyRepeat(KeyID id, KeyModifierMask mask, - SInt32 count, KeyButton button, const String& lang) = 0; + //! Fake a key repeat + /*! + Synthesizes a key repeat event and updates the key state. + */ + virtual bool fakeKeyRepeat(KeyID id, KeyModifierMask mask, SInt32 count, + KeyButton button, const String &lang) = 0; - //! Fake a key release - /*! - Synthesizes a key release event and updates the key state. - */ - virtual bool fakeKeyUp(KeyButton button) = 0; + //! Fake a key release + /*! + Synthesizes a key release event and updates the key state. + */ + virtual bool fakeKeyUp(KeyButton button) = 0; - //! Fake key releases for all fake pressed keys - /*! - Synthesizes a key release event for every key that is synthetically - pressed and updates the key state. - */ - virtual void fakeAllKeysUp() = 0; + //! Fake key releases for all fake pressed keys + /*! + Synthesizes a key release event for every key that is synthetically + pressed and updates the key state. + */ + virtual void fakeAllKeysUp() = 0; - //! Fake ctrl+alt+del - /*! - Synthesize a press of ctrl+alt+del. Return true if processing is - complete and false if normal key processing should continue. - */ - virtual bool fakeCtrlAltDel() = 0; - - //! Fake a media key - /*! - Synthesizes a media key down and up. Only Mac would implement this by - use cocoa appkit framework. - */ - virtual bool fakeMediaKey(KeyID id) = 0; - - //@} - //! @name accessors - //@{ + //! Fake ctrl+alt+del + /*! + Synthesize a press of ctrl+alt+del. Return true if processing is + complete and false if normal key processing should continue. + */ + virtual bool fakeCtrlAltDel() = 0; - //! Test if key is pressed - /*! - Returns true iff the given key is down. Half-duplex toggles - always return false. - */ - virtual bool isKeyDown(KeyButton) const = 0; + //! Fake a media key + /*! + Synthesizes a media key down and up. Only Mac would implement this by + use cocoa appkit framework. + */ + virtual bool fakeMediaKey(KeyID id) = 0; - //! Get the active modifiers - /*! - Returns the modifiers that are currently active according to our - shadowed state. - */ - virtual KeyModifierMask - getActiveModifiers() const = 0; + //@} + //! @name accessors + //@{ - //! Get the active modifiers from OS - /*! - Returns the modifiers that are currently active according to the - operating system. - */ - virtual KeyModifierMask - pollActiveModifiers() const = 0; + //! Test if key is pressed + /*! + Returns true iff the given key is down. Half-duplex toggles + always return false. + */ + virtual bool isKeyDown(KeyButton) const = 0; - //! Get the active keyboard layout from OS - /*! - Returns the active keyboard layout according to the operating system. - */ - virtual SInt32 pollActiveGroup() const = 0; + //! Get the active modifiers + /*! + Returns the modifiers that are currently active according to our + shadowed state. + */ + virtual KeyModifierMask getActiveModifiers() const = 0; - //! Get the keys currently pressed from OS - /*! - Adds any keys that are currently pressed according to the operating - system to \p pressedKeys. - */ - virtual void pollPressedKeys(KeyButtonSet& pressedKeys) const = 0; + //! Get the active modifiers from OS + /*! + Returns the modifiers that are currently active according to the + operating system. + */ + virtual KeyModifierMask pollActiveModifiers() const = 0; - //@} + //! Get the active keyboard layout from OS + /*! + Returns the active keyboard layout according to the operating system. + */ + virtual SInt32 pollActiveGroup() const = 0; + + //! Get the keys currently pressed from OS + /*! + Adds any keys that are currently pressed according to the operating + system to \p pressedKeys. + */ + virtual void pollPressedKeys(KeyButtonSet &pressedKeys) const = 0; + + //@} }; diff --git a/src/lib/synergy/INode.h b/src/lib/synergy/INode.h index 159518442..6334c50a0 100644 --- a/src/lib/synergy/INode.h +++ b/src/lib/synergy/INode.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -20,6 +20,4 @@ #include "common/IInterface.h" -class INode : IInterface { - -}; +class INode : IInterface {}; diff --git a/src/lib/synergy/IPlatformScreen.cpp b/src/lib/synergy/IPlatformScreen.cpp index 844b34cc1..24476effc 100644 --- a/src/lib/synergy/IPlatformScreen.cpp +++ b/src/lib/synergy/IPlatformScreen.cpp @@ -1,11 +1,11 @@ /* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2016 Symless. - * + * * 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 @@ -17,8 +17,4 @@ #include "synergy/IPlatformScreen.h" -bool -IPlatformScreen::fakeMediaKey(KeyID id) -{ - return false; -} +bool IPlatformScreen::fakeMediaKey(KeyID id) { return false; } diff --git a/src/lib/synergy/IPlatformScreen.h b/src/lib/synergy/IPlatformScreen.h index c436e09b4..47a7c2fd9 100644 --- a/src/lib/synergy/IPlatformScreen.h +++ b/src/lib/synergy/IPlatformScreen.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -19,11 +19,11 @@ #pragma once #include "synergy/DragInformation.h" -#include "synergy/clipboard_types.h" -#include "synergy/IScreen.h" -#include "synergy/IPrimaryScreen.h" -#include "synergy/ISecondaryScreen.h" #include "synergy/IKeyState.h" +#include "synergy/IPrimaryScreen.h" +#include "synergy/IScreen.h" +#include "synergy/ISecondaryScreen.h" +#include "synergy/clipboard_types.h" #include "synergy/option_types.h" class IClipboard; @@ -35,199 +35,198 @@ screen implementations that are used by both primary and secondary screens. */ class IPlatformScreen : public IScreen, - public IPrimaryScreen, public ISecondaryScreen, - public IKeyState { + public IPrimaryScreen, + public ISecondaryScreen, + public IKeyState { public: - //! @name manipulators - //@{ + //! @name manipulators + //@{ - IPlatformScreen(IEventQueue* events) : IKeyState(events) { } + IPlatformScreen(IEventQueue *events) : IKeyState(events) {} - //! Enable screen - /*! - Enable the screen, preparing it to report system and user events. - For a secondary screen it also means preparing to synthesize events - and hiding the cursor. - */ - virtual void enable() = 0; + //! Enable screen + /*! + Enable the screen, preparing it to report system and user events. + For a secondary screen it also means preparing to synthesize events + and hiding the cursor. + */ + virtual void enable() = 0; - //! Disable screen - /*! - Undoes the operations in enable() and events should no longer - be reported. - */ - virtual void disable() = 0; + //! Disable screen + /*! + Undoes the operations in enable() and events should no longer + be reported. + */ + virtual void disable() = 0; - //! Enter screen - /*! - Called when the user navigates to this screen. - */ - virtual void enter() = 0; + //! Enter screen + /*! + Called when the user navigates to this screen. + */ + virtual void enter() = 0; - //! Leave screen - /*! - Called when the user navigates off the screen. Returns true on - success, false on failure. A typical reason for failure is being - unable to install the keyboard and mouse snoopers on a primary - screen. Secondary screens should not fail. - */ - virtual bool leave() = 0; + //! Leave screen + /*! + Called when the user navigates off the screen. Returns true on + success, false on failure. A typical reason for failure is being + unable to install the keyboard and mouse snoopers on a primary + screen. Secondary screens should not fail. + */ + virtual bool leave() = 0; - //! Set clipboard - /*! - Set the contents of the system clipboard indicated by \c id. - */ - virtual bool setClipboard(ClipboardID id, const IClipboard*) = 0; + //! Set clipboard + /*! + Set the contents of the system clipboard indicated by \c id. + */ + virtual bool setClipboard(ClipboardID id, const IClipboard *) = 0; - //! Check clipboard owner - /*! - Check ownership of all clipboards and post grab events for any that - have changed. This is used as a backup in case the system doesn't - reliably report clipboard ownership changes. - */ - virtual void checkClipboards() = 0; + //! Check clipboard owner + /*! + Check ownership of all clipboards and post grab events for any that + have changed. This is used as a backup in case the system doesn't + reliably report clipboard ownership changes. + */ + virtual void checkClipboards() = 0; - //! Open screen saver - /*! - Open the screen saver. If \c notify is true then this object must - send events when the screen saver activates or deactivates until - \c closeScreensaver() is called. If \c notify is false then the - screen saver is disabled and restored on \c closeScreensaver(). - */ - virtual void openScreensaver(bool notify) = 0; + //! Open screen saver + /*! + Open the screen saver. If \c notify is true then this object must + send events when the screen saver activates or deactivates until + \c closeScreensaver() is called. If \c notify is false then the + screen saver is disabled and restored on \c closeScreensaver(). + */ + virtual void openScreensaver(bool notify) = 0; - //! Close screen saver - /*! - // Close the screen saver. Stop reporting screen saver activation - and deactivation and, if the screen saver was disabled by - openScreensaver(), enable the screen saver. - */ - virtual void closeScreensaver() = 0; + //! Close screen saver + /*! + // Close the screen saver. Stop reporting screen saver activation + and deactivation and, if the screen saver was disabled by + openScreensaver(), enable the screen saver. + */ + virtual void closeScreensaver() = 0; - //! Activate/deactivate screen saver - /*! - Forcibly activate the screen saver if \c activate is true otherwise - forcibly deactivate it. - */ - virtual void screensaver(bool activate) = 0; + //! Activate/deactivate screen saver + /*! + Forcibly activate the screen saver if \c activate is true otherwise + forcibly deactivate it. + */ + virtual void screensaver(bool activate) = 0; - //! Notify of options changes - /*! - Reset all options to their default values. - */ - virtual void resetOptions() = 0; + //! Notify of options changes + /*! + Reset all options to their default values. + */ + virtual void resetOptions() = 0; - //! Notify of options changes - /*! - Set options to given values. Ignore unknown options and don't - modify options that aren't given in \c options. - */ - virtual void setOptions(const OptionsList& options) = 0; + //! Notify of options changes + /*! + Set options to given values. Ignore unknown options and don't + modify options that aren't given in \c options. + */ + virtual void setOptions(const OptionsList &options) = 0; - //! Set clipboard sequence number - /*! - Sets the sequence number to use in subsequent clipboard events. - */ - virtual void setSequenceNumber(UInt32) = 0; + //! Set clipboard sequence number + /*! + Sets the sequence number to use in subsequent clipboard events. + */ + virtual void setSequenceNumber(UInt32) = 0; - //! Change dragging status - virtual void setDraggingStarted(bool started) = 0; + //! Change dragging status + virtual void setDraggingStarted(bool started) = 0; - //! Determine the name of the app causing a secure input state - /*! - On MacOS check which app causes a secure input state to be enabled. No alternative on other platforms - */ - virtual String getSecureInputApp() const = 0; + //! Determine the name of the app causing a secure input state + /*! + On MacOS check which app causes a secure input state to be enabled. No + alternative on other platforms + */ + virtual String getSecureInputApp() const = 0; - //@} - //! @name accessors - //@{ + //@} + //! @name accessors + //@{ - //! Test if is primary screen - /*! - Return true iff this screen is a primary screen. - */ - virtual bool isPrimary() const = 0; + //! Test if is primary screen + /*! + Return true iff this screen is a primary screen. + */ + virtual bool isPrimary() const = 0; - //@} + //@} - // IScreen overrides - virtual void* getEventTarget() const = 0; - virtual bool getClipboard(ClipboardID id, IClipboard*) const = 0; - virtual void getShape(SInt32& x, SInt32& y, - SInt32& width, SInt32& height) const = 0; - virtual void getCursorPos(SInt32& x, SInt32& y) const = 0; + // IScreen overrides + virtual void *getEventTarget() const = 0; + virtual bool getClipboard(ClipboardID id, IClipboard *) const = 0; + virtual void getShape(SInt32 &x, SInt32 &y, SInt32 &width, + SInt32 &height) const = 0; + virtual void getCursorPos(SInt32 &x, SInt32 &y) const = 0; - // IPrimaryScreen overrides - virtual void reconfigure(UInt32 activeSides) = 0; - virtual void warpCursor(SInt32 x, SInt32 y) = 0; - virtual UInt32 registerHotKey(KeyID key, KeyModifierMask mask) = 0; - virtual void unregisterHotKey(UInt32 id) = 0; - virtual void fakeInputBegin() = 0; - virtual void fakeInputEnd() = 0; - virtual SInt32 getJumpZoneSize() const = 0; - virtual bool isAnyMouseButtonDown(UInt32& buttonID) const = 0; - virtual void getCursorCenter(SInt32& x, SInt32& y) const = 0; + // IPrimaryScreen overrides + virtual void reconfigure(UInt32 activeSides) = 0; + virtual void warpCursor(SInt32 x, SInt32 y) = 0; + virtual UInt32 registerHotKey(KeyID key, KeyModifierMask mask) = 0; + virtual void unregisterHotKey(UInt32 id) = 0; + virtual void fakeInputBegin() = 0; + virtual void fakeInputEnd() = 0; + virtual SInt32 getJumpZoneSize() const = 0; + virtual bool isAnyMouseButtonDown(UInt32 &buttonID) const = 0; + virtual void getCursorCenter(SInt32 &x, SInt32 &y) const = 0; - // ISecondaryScreen overrides - virtual void fakeMouseButton(ButtonID id, bool press) = 0; - virtual void fakeMouseMove(SInt32 x, SInt32 y) = 0; - virtual void fakeMouseRelativeMove(SInt32 dx, SInt32 dy) const = 0; - virtual void fakeMouseWheel(SInt32 xDelta, SInt32 yDelta) const = 0; + // ISecondaryScreen overrides + virtual void fakeMouseButton(ButtonID id, bool press) = 0; + virtual void fakeMouseMove(SInt32 x, SInt32 y) = 0; + virtual void fakeMouseRelativeMove(SInt32 dx, SInt32 dy) const = 0; + virtual void fakeMouseWheel(SInt32 xDelta, SInt32 yDelta) const = 0; - // IKeyState overrides - virtual void updateKeyMap() = 0; - virtual void updateKeyState() = 0; - virtual void setHalfDuplexMask(KeyModifierMask) = 0; - virtual void fakeKeyDown(KeyID id, KeyModifierMask mask, - KeyButton button, const String& lang) = 0; - virtual bool fakeKeyRepeat(KeyID id, KeyModifierMask mask, - SInt32 count, KeyButton button, const String& lang) = 0; - virtual bool fakeKeyUp(KeyButton button) = 0; - virtual void fakeAllKeysUp() = 0; - virtual bool fakeCtrlAltDel() = 0; - virtual bool fakeMediaKey(KeyID id); - virtual bool isKeyDown(KeyButton) const = 0; - virtual KeyModifierMask - getActiveModifiers() const = 0; - virtual KeyModifierMask - pollActiveModifiers() const = 0; - virtual SInt32 pollActiveGroup() const = 0; - virtual void pollPressedKeys(KeyButtonSet& pressedKeys) const = 0; + // IKeyState overrides + virtual void updateKeyMap() = 0; + virtual void updateKeyState() = 0; + virtual void setHalfDuplexMask(KeyModifierMask) = 0; + virtual void fakeKeyDown(KeyID id, KeyModifierMask mask, KeyButton button, + const String &lang) = 0; + virtual bool fakeKeyRepeat(KeyID id, KeyModifierMask mask, SInt32 count, + KeyButton button, const String &lang) = 0; + virtual bool fakeKeyUp(KeyButton button) = 0; + virtual void fakeAllKeysUp() = 0; + virtual bool fakeCtrlAltDel() = 0; + virtual bool fakeMediaKey(KeyID id); + virtual bool isKeyDown(KeyButton) const = 0; + virtual KeyModifierMask getActiveModifiers() const = 0; + virtual KeyModifierMask pollActiveModifiers() const = 0; + virtual SInt32 pollActiveGroup() const = 0; + virtual void pollPressedKeys(KeyButtonSet &pressedKeys) const = 0; - virtual String& getDraggingFilename() = 0; - virtual void clearDraggingFilename() = 0; - virtual bool isDraggingStarted() = 0; - virtual bool isFakeDraggingStarted() = 0; + virtual String &getDraggingFilename() = 0; + virtual void clearDraggingFilename() = 0; + virtual bool isDraggingStarted() = 0; + virtual bool isFakeDraggingStarted() = 0; + + virtual void fakeDraggingFiles(DragFileList fileList) = 0; + virtual const String &getDropTarget() const = 0; - virtual void fakeDraggingFiles(DragFileList fileList) = 0; - virtual const String& - getDropTarget() const = 0; - protected: - //! Handle system event - /*! - A platform screen is expected to install a handler for system - events in its c'tor like so: - \code - m_events->adoptHandler(Event::kSystem, - m_events->getSystemTarget(), - new TMethodEventJob(this, - &CXXXPlatformScreen::handleSystemEvent)); - \endcode - It should remove the handler in its d'tor. Override the - \c handleSystemEvent() method to process system events. - It should post the events \c IScreen as appropriate. + //! Handle system event + /*! + A platform screen is expected to install a handler for system + events in its c'tor like so: + \code + m_events->adoptHandler(Event::kSystem, + m_events->getSystemTarget(), + new TMethodEventJob(this, + &CXXXPlatformScreen::handleSystemEvent)); + \endcode + It should remove the handler in its d'tor. Override the + \c handleSystemEvent() method to process system events. + It should post the events \c IScreen as appropriate. - A primary screen has further responsibilities. It should post - the events in \c IPrimaryScreen as appropriate. It should also - call \c onKey() on its \c KeyState whenever a key is pressed - or released (but not for key repeats). And it should call - \c updateKeyMap() on its \c KeyState if necessary when the keyboard - mapping changes. + A primary screen has further responsibilities. It should post + the events in \c IPrimaryScreen as appropriate. It should also + call \c onKey() on its \c KeyState whenever a key is pressed + or released (but not for key repeats). And it should call + \c updateKeyMap() on its \c KeyState if necessary when the keyboard + mapping changes. - The target of all events should be the value returned by - \c getEventTarget(). - */ - virtual void handleSystemEvent(const Event& event, void*) = 0; + The target of all events should be the value returned by + \c getEventTarget(). + */ + virtual void handleSystemEvent(const Event &event, void *) = 0; }; diff --git a/src/lib/synergy/IPrimaryScreen.cpp b/src/lib/synergy/IPrimaryScreen.cpp index 94c58b721..2aec3dadc 100644 --- a/src/lib/synergy/IPrimaryScreen.cpp +++ b/src/lib/synergy/IPrimaryScreen.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 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 LICENSE 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 @@ -25,67 +25,57 @@ // IPrimaryScreen::ButtonInfo // -IPrimaryScreen::ButtonInfo* -IPrimaryScreen::ButtonInfo::alloc(ButtonID id, KeyModifierMask mask) -{ - ButtonInfo* info = (ButtonInfo*)malloc(sizeof(ButtonInfo)); - info->m_button = id; - info->m_mask = mask; - return info; +IPrimaryScreen::ButtonInfo * +IPrimaryScreen::ButtonInfo::alloc(ButtonID id, KeyModifierMask mask) { + ButtonInfo *info = (ButtonInfo *)malloc(sizeof(ButtonInfo)); + info->m_button = id; + info->m_mask = mask; + return info; } -IPrimaryScreen::ButtonInfo* -IPrimaryScreen::ButtonInfo::alloc(const ButtonInfo& x) -{ - ButtonInfo* info = (ButtonInfo*)malloc(sizeof(ButtonInfo)); - info->m_button = x.m_button; - info->m_mask = x.m_mask; - return info; +IPrimaryScreen::ButtonInfo * +IPrimaryScreen::ButtonInfo::alloc(const ButtonInfo &x) { + ButtonInfo *info = (ButtonInfo *)malloc(sizeof(ButtonInfo)); + info->m_button = x.m_button; + info->m_mask = x.m_mask; + return info; } -bool -IPrimaryScreen::ButtonInfo::equal(const ButtonInfo* a, const ButtonInfo* b) -{ - return (a->m_button == b->m_button && a->m_mask == b->m_mask); +bool IPrimaryScreen::ButtonInfo::equal(const ButtonInfo *a, + const ButtonInfo *b) { + return (a->m_button == b->m_button && a->m_mask == b->m_mask); } - // // IPrimaryScreen::MotionInfo // -IPrimaryScreen::MotionInfo* -IPrimaryScreen::MotionInfo::alloc(SInt32 x, SInt32 y) -{ - MotionInfo* info = (MotionInfo*)malloc(sizeof(MotionInfo)); - info->m_x = x; - info->m_y = y; - return info; +IPrimaryScreen::MotionInfo *IPrimaryScreen::MotionInfo::alloc(SInt32 x, + SInt32 y) { + MotionInfo *info = (MotionInfo *)malloc(sizeof(MotionInfo)); + info->m_x = x; + info->m_y = y; + return info; } - // // IPrimaryScreen::WheelInfo // -IPrimaryScreen::WheelInfo* -IPrimaryScreen::WheelInfo::alloc(SInt32 xDelta, SInt32 yDelta) -{ - WheelInfo* info = (WheelInfo*)malloc(sizeof(WheelInfo)); - info->m_xDelta = xDelta; - info->m_yDelta = yDelta; - return info; +IPrimaryScreen::WheelInfo *IPrimaryScreen::WheelInfo::alloc(SInt32 xDelta, + SInt32 yDelta) { + WheelInfo *info = (WheelInfo *)malloc(sizeof(WheelInfo)); + info->m_xDelta = xDelta; + info->m_yDelta = yDelta; + return info; } - // // IPrimaryScreen::HotKeyInfo // -IPrimaryScreen::HotKeyInfo* -IPrimaryScreen::HotKeyInfo::alloc(UInt32 id) -{ - HotKeyInfo* info = (HotKeyInfo*)malloc(sizeof(HotKeyInfo)); - info->m_id = id; - return info; +IPrimaryScreen::HotKeyInfo *IPrimaryScreen::HotKeyInfo::alloc(UInt32 id) { + HotKeyInfo *info = (HotKeyInfo *)malloc(sizeof(HotKeyInfo)); + info->m_id = id; + return info; } diff --git a/src/lib/synergy/IPrimaryScreen.h b/src/lib/synergy/IPrimaryScreen.h index c4ec04d31..a1ac72710 100644 --- a/src/lib/synergy/IPrimaryScreen.h +++ b/src/lib/synergy/IPrimaryScreen.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2003 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 LICENSE 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 @@ -18,11 +18,11 @@ #pragma once -#include "synergy/key_types.h" -#include "synergy/mouse_types.h" #include "base/Event.h" #include "base/EventTypes.h" #include "common/IInterface.h" +#include "synergy/key_types.h" +#include "synergy/mouse_types.h" //! Primary screen interface /*! @@ -31,135 +31,135 @@ primary screen implementations. */ class IPrimaryScreen : public IInterface { public: - //! Button event data - class ButtonInfo { - public: - static ButtonInfo* alloc(ButtonID, KeyModifierMask); - static ButtonInfo* alloc(const ButtonInfo&); + //! Button event data + class ButtonInfo { + public: + static ButtonInfo *alloc(ButtonID, KeyModifierMask); + static ButtonInfo *alloc(const ButtonInfo &); - static bool equal(const ButtonInfo*, const ButtonInfo*); + static bool equal(const ButtonInfo *, const ButtonInfo *); - public: - ButtonID m_button; - KeyModifierMask m_mask; - }; - //! Motion event data - class MotionInfo { - public: - static MotionInfo* alloc(SInt32 x, SInt32 y); + public: + ButtonID m_button; + KeyModifierMask m_mask; + }; + //! Motion event data + class MotionInfo { + public: + static MotionInfo *alloc(SInt32 x, SInt32 y); - public: - SInt32 m_x; - SInt32 m_y; - }; - //! Wheel motion event data - class WheelInfo { - public: - static WheelInfo* alloc(SInt32 xDelta, SInt32 yDelta); + public: + SInt32 m_x; + SInt32 m_y; + }; + //! Wheel motion event data + class WheelInfo { + public: + static WheelInfo *alloc(SInt32 xDelta, SInt32 yDelta); - public: - SInt32 m_xDelta; - SInt32 m_yDelta; - }; - //! Hot key event data - class HotKeyInfo { - public: - static HotKeyInfo* alloc(UInt32 id); + public: + SInt32 m_xDelta; + SInt32 m_yDelta; + }; + //! Hot key event data + class HotKeyInfo { + public: + static HotKeyInfo *alloc(UInt32 id); - public: - UInt32 m_id; - }; + public: + UInt32 m_id; + }; - //! @name manipulators - //@{ + //! @name manipulators + //@{ - //! Update configuration - /*! - This is called when the configuration has changed. \c activeSides - is a bitmask of EDirectionMask indicating which sides of the - primary screen are linked to clients. Override to handle the - possible change in jump zones. - */ - virtual void reconfigure(UInt32 activeSides) = 0; + //! Update configuration + /*! + This is called when the configuration has changed. \c activeSides + is a bitmask of EDirectionMask indicating which sides of the + primary screen are linked to clients. Override to handle the + possible change in jump zones. + */ + virtual void reconfigure(UInt32 activeSides) = 0; - //! Warp cursor - /*! - Warp the cursor to the absolute coordinates \c x,y. Also - discard input events up to and including the warp before - returning. - */ - virtual void warpCursor(SInt32 x, SInt32 y) = 0; + //! Warp cursor + /*! + Warp the cursor to the absolute coordinates \c x,y. Also + discard input events up to and including the warp before + returning. + */ + virtual void warpCursor(SInt32 x, SInt32 y) = 0; - //! Register a system hotkey - /*! - Registers a system-wide hotkey. The screen should arrange for an event - to be delivered to itself when the hot key is pressed or released. When - that happens the screen should post a \c getHotKeyDownEvent() or - \c getHotKeyUpEvent(), respectively. The hot key is key \p key with - exactly the modifiers \p mask. Returns 0 on failure otherwise an id - that can be used to unregister the hotkey. + //! Register a system hotkey + /*! + Registers a system-wide hotkey. The screen should arrange for an event + to be delivered to itself when the hot key is pressed or released. When + that happens the screen should post a \c getHotKeyDownEvent() or + \c getHotKeyUpEvent(), respectively. The hot key is key \p key with + exactly the modifiers \p mask. Returns 0 on failure otherwise an id + that can be used to unregister the hotkey. - A hot key is a set of modifiers and a key, which may itself be a modifier. - The hot key is pressed when the hot key's modifiers and only those - modifiers are logically down (active) and the key is pressed. The hot - key is released when the key is released, regardless of the modifiers. + A hot key is a set of modifiers and a key, which may itself be a modifier. + The hot key is pressed when the hot key's modifiers and only those + modifiers are logically down (active) and the key is pressed. The hot + key is released when the key is released, regardless of the modifiers. - The hot key event should be generated no matter what window or application - has the focus. No other window or application should receive the key - press or release events (they can and should see the modifier key events). - When the key is a modifier, it's acceptable to allow the user to press - the modifiers in any order or to require the user to press the given key - last. - */ - virtual UInt32 registerHotKey(KeyID key, KeyModifierMask mask) = 0; + The hot key event should be generated no matter what window or application + has the focus. No other window or application should receive the key + press or release events (they can and should see the modifier key events). + When the key is a modifier, it's acceptable to allow the user to press + the modifiers in any order or to require the user to press the given key + last. + */ + virtual UInt32 registerHotKey(KeyID key, KeyModifierMask mask) = 0; - //! Unregister a system hotkey - /*! - Unregisters a previously registered hot key. - */ - virtual void unregisterHotKey(UInt32 id) = 0; + //! Unregister a system hotkey + /*! + Unregisters a previously registered hot key. + */ + virtual void unregisterHotKey(UInt32 id) = 0; - //! Prepare to synthesize input on primary screen - /*! - Prepares the primary screen to receive synthesized input. We do not - want to receive this synthesized input as user input so this method - ensures that we ignore it. Calls to \c fakeInputBegin() may not be - nested. - */ - virtual void fakeInputBegin() = 0; + //! Prepare to synthesize input on primary screen + /*! + Prepares the primary screen to receive synthesized input. We do not + want to receive this synthesized input as user input so this method + ensures that we ignore it. Calls to \c fakeInputBegin() may not be + nested. + */ + virtual void fakeInputBegin() = 0; - //! Done synthesizing input on primary screen - /*! - Undoes whatever \c fakeInputBegin() did. - */ - virtual void fakeInputEnd() = 0; + //! Done synthesizing input on primary screen + /*! + Undoes whatever \c fakeInputBegin() did. + */ + virtual void fakeInputEnd() = 0; - //@} - //! @name accessors - //@{ + //@} + //! @name accessors + //@{ - //! Get jump zone size - /*! - Return the jump zone size, the size of the regions on the edges of - the screen that cause the cursor to jump to another screen. - */ - virtual SInt32 getJumpZoneSize() const = 0; + //! Get jump zone size + /*! + Return the jump zone size, the size of the regions on the edges of + the screen that cause the cursor to jump to another screen. + */ + virtual SInt32 getJumpZoneSize() const = 0; - //! Test if mouse is pressed - /*! - Return true if any mouse button is currently pressed. Ideally, - "current" means up to the last processed event but it can mean - the current physical mouse button state. - */ - virtual bool isAnyMouseButtonDown(UInt32& buttonID) const = 0; + //! Test if mouse is pressed + /*! + Return true if any mouse button is currently pressed. Ideally, + "current" means up to the last processed event but it can mean + the current physical mouse button state. + */ + virtual bool isAnyMouseButtonDown(UInt32 &buttonID) const = 0; - //! Get cursor center position - /*! - Return the cursor center position which is where we park the - cursor to compute cursor motion deltas and should be far from - the edges of the screen, typically the center. - */ - virtual void getCursorCenter(SInt32& x, SInt32& y) const = 0; + //! Get cursor center position + /*! + Return the cursor center position which is where we park the + cursor to compute cursor motion deltas and should be far from + the edges of the screen, typically the center. + */ + virtual void getCursorCenter(SInt32 &x, SInt32 &y) const = 0; - //@} + //@} }; diff --git a/src/lib/synergy/IScreen.h b/src/lib/synergy/IScreen.h index a55a238cc..9943c8983 100644 --- a/src/lib/synergy/IScreen.h +++ b/src/lib/synergy/IScreen.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2003 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 LICENSE 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 @@ -18,10 +18,10 @@ #pragma once -#include "synergy/clipboard_types.h" #include "base/Event.h" #include "base/EventTypes.h" #include "common/IInterface.h" +#include "synergy/clipboard_types.h" class IClipboard; @@ -31,41 +31,41 @@ This interface defines the methods common to all screens. */ class IScreen : public IInterface { public: - struct ClipboardInfo { - public: - ClipboardID m_id; - UInt32 m_sequenceNumber; - }; + struct ClipboardInfo { + public: + ClipboardID m_id; + UInt32 m_sequenceNumber; + }; - //! @name accessors - //@{ + //! @name accessors + //@{ - //! Get event target - /*! - Returns the target used for events created by this object. - */ - virtual void* getEventTarget() const = 0; + //! Get event target + /*! + Returns the target used for events created by this object. + */ + virtual void *getEventTarget() const = 0; - //! Get clipboard - /*! - Save the contents of the clipboard indicated by \c id and return - true iff successful. - */ - virtual bool getClipboard(ClipboardID id, IClipboard*) const = 0; + //! Get clipboard + /*! + Save the contents of the clipboard indicated by \c id and return + true iff successful. + */ + virtual bool getClipboard(ClipboardID id, IClipboard *) const = 0; - //! Get screen shape - /*! - Return the position of the upper-left corner of the screen in \c x and - \c y and the size of the screen in \c width and \c height. - */ - virtual void getShape(SInt32& x, SInt32& y, - SInt32& width, SInt32& height) const = 0; + //! Get screen shape + /*! + Return the position of the upper-left corner of the screen in \c x and + \c y and the size of the screen in \c width and \c height. + */ + virtual void getShape(SInt32 &x, SInt32 &y, SInt32 &width, + SInt32 &height) const = 0; - //! Get cursor position - /*! - Return the current position of the cursor in \c x and \c y. - */ - virtual void getCursorPos(SInt32& x, SInt32& y) const = 0; - - //@} + //! Get cursor position + /*! + Return the current position of the cursor in \c x and \c y. + */ + virtual void getCursorPos(SInt32 &x, SInt32 &y) const = 0; + + //@} }; diff --git a/src/lib/synergy/IScreenSaver.h b/src/lib/synergy/IScreenSaver.h index 1908c23d9..b009c78a2 100644 --- a/src/lib/synergy/IScreenSaver.h +++ b/src/lib/synergy/IScreenSaver.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -27,49 +27,49 @@ This interface defines the methods common to all screen savers. */ class IScreenSaver : public IInterface { public: - // note -- the c'tor/d'tor must *not* enable/disable the screen saver + // note -- the c'tor/d'tor must *not* enable/disable the screen saver - //! @name manipulators - //@{ + //! @name manipulators + //@{ - //! Enable screen saver - /*! - Enable the screen saver, restoring the screen saver settings to - what they were when disable() was previously called. If disable() - wasn't previously called then it should keep the current settings - or use reasonable defaults. - */ - virtual void enable() = 0; + //! Enable screen saver + /*! + Enable the screen saver, restoring the screen saver settings to + what they were when disable() was previously called. If disable() + wasn't previously called then it should keep the current settings + or use reasonable defaults. + */ + virtual void enable() = 0; - //! Disable screen saver - /*! - Disable the screen saver, saving the old settings for the next - call to enable(). - */ - virtual void disable() = 0; + //! Disable screen saver + /*! + Disable the screen saver, saving the old settings for the next + call to enable(). + */ + virtual void disable() = 0; - //! Activate screen saver - /*! - Activate (i.e. show) the screen saver. - */ - virtual void activate() = 0; + //! Activate screen saver + /*! + Activate (i.e. show) the screen saver. + */ + virtual void activate() = 0; - //! Deactivate screen saver - /*! - Deactivate (i.e. hide) the screen saver, reseting the screen saver - timer. - */ - virtual void deactivate() = 0; + //! Deactivate screen saver + /*! + Deactivate (i.e. hide) the screen saver, reseting the screen saver + timer. + */ + virtual void deactivate() = 0; - //@} - //! @name accessors - //@{ + //@} + //! @name accessors + //@{ - //! Test if screen saver on - /*! - Returns true iff the screen saver is currently active (showing). - */ - virtual bool isActive() const = 0; + //! Test if screen saver on + /*! + Returns true iff the screen saver is currently active (showing). + */ + virtual bool isActive() const = 0; - //@} + //@} }; diff --git a/src/lib/synergy/ISecondaryScreen.h b/src/lib/synergy/ISecondaryScreen.h index 1f4e25d5b..67f4e6c9a 100644 --- a/src/lib/synergy/ISecondaryScreen.h +++ b/src/lib/synergy/ISecondaryScreen.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2003 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 LICENSE 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 @@ -18,10 +18,10 @@ #pragma once -#include "synergy/mouse_types.h" #include "base/Event.h" #include "base/EventTypes.h" #include "common/IInterface.h" +#include "synergy/mouse_types.h" //! Secondary screen interface /*! @@ -30,32 +30,32 @@ secondary screen implementations. */ class ISecondaryScreen : public IInterface { public: - //! @name accessors - //@{ + //! @name accessors + //@{ - //! Fake mouse press/release - /*! - Synthesize a press or release of mouse button \c id. - */ - virtual void fakeMouseButton(ButtonID id, bool press) = 0; + //! Fake mouse press/release + /*! + Synthesize a press or release of mouse button \c id. + */ + virtual void fakeMouseButton(ButtonID id, bool press) = 0; - //! Fake mouse move - /*! - Synthesize a mouse move to the absolute coordinates \c x,y. - */ - virtual void fakeMouseMove(SInt32 x, SInt32 y) = 0; + //! Fake mouse move + /*! + Synthesize a mouse move to the absolute coordinates \c x,y. + */ + virtual void fakeMouseMove(SInt32 x, SInt32 y) = 0; - //! Fake mouse move - /*! - Synthesize a mouse move to the relative coordinates \c dx,dy. - */ - virtual void fakeMouseRelativeMove(SInt32 dx, SInt32 dy) const = 0; + //! Fake mouse move + /*! + Synthesize a mouse move to the relative coordinates \c dx,dy. + */ + virtual void fakeMouseRelativeMove(SInt32 dx, SInt32 dy) const = 0; - //! Fake mouse wheel - /*! - Synthesize a mouse wheel event of amount \c xDelta and \c yDelta. - */ - virtual void fakeMouseWheel(SInt32 xDelta, SInt32 yDelta) const = 0; + //! Fake mouse wheel + /*! + Synthesize a mouse wheel event of amount \c xDelta and \c yDelta. + */ + virtual void fakeMouseWheel(SInt32 xDelta, SInt32 yDelta) const = 0; - //@} + //@} }; diff --git a/src/lib/synergy/KeyMap.cpp b/src/lib/synergy/KeyMap.cpp index 4173eced1..fc5518673 100644 --- a/src/lib/synergy/KeyMap.cpp +++ b/src/lib/synergy/KeyMap.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2005 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 LICENSE 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 @@ -16,11 +16,11 @@ * along with this program. If not, see . */ +#include "synergy/KeyMap.h" +#include "base/Log.h" #include "synergy/App.h" #include "synergy/ArgsBase.h" -#include "synergy/KeyMap.h" #include "synergy/key_types.h" -#include "base/Log.h" #include #include @@ -28,1340 +28,1219 @@ namespace synergy { -KeyMap::NameToKeyMap* KeyMap::s_nameToKeyMap = NULL; -KeyMap::NameToModifierMap* KeyMap::s_nameToModifierMap = NULL; -KeyMap::KeyToNameMap* KeyMap::s_keyToNameMap = NULL; -KeyMap::ModifierToNameMap* KeyMap::s_modifierToNameMap = NULL; +KeyMap::NameToKeyMap *KeyMap::s_nameToKeyMap = NULL; +KeyMap::NameToModifierMap *KeyMap::s_nameToModifierMap = NULL; +KeyMap::KeyToNameMap *KeyMap::s_keyToNameMap = NULL; +KeyMap::ModifierToNameMap *KeyMap::s_modifierToNameMap = NULL; -KeyMap::KeyMap() : - m_numGroups(0), - m_composeAcrossGroups(false) -{ - m_modifierKeyItem.m_id = kKeyNone; - m_modifierKeyItem.m_group = 0; - m_modifierKeyItem.m_button = 0; - m_modifierKeyItem.m_required = 0; - m_modifierKeyItem.m_sensitive = 0; - m_modifierKeyItem.m_generates = 0; - m_modifierKeyItem.m_dead = false; - m_modifierKeyItem.m_lock = false; - m_modifierKeyItem.m_client = 0; +KeyMap::KeyMap() : m_numGroups(0), m_composeAcrossGroups(false) { + m_modifierKeyItem.m_id = kKeyNone; + m_modifierKeyItem.m_group = 0; + m_modifierKeyItem.m_button = 0; + m_modifierKeyItem.m_required = 0; + m_modifierKeyItem.m_sensitive = 0; + m_modifierKeyItem.m_generates = 0; + m_modifierKeyItem.m_dead = false; + m_modifierKeyItem.m_lock = false; + m_modifierKeyItem.m_client = 0; } -KeyMap::~KeyMap() -{ - // do nothing +KeyMap::~KeyMap() { + // do nothing } -void -KeyMap::swap(KeyMap& x) -{ - m_keyIDMap.swap(x.m_keyIDMap); - m_modifierKeys.swap(x.m_modifierKeys); - m_halfDuplex.swap(x.m_halfDuplex); - m_halfDuplexMods.swap(x.m_halfDuplexMods); - SInt32 tmp1 = m_numGroups; - m_numGroups = x.m_numGroups; - x.m_numGroups = tmp1; - bool tmp2 = m_composeAcrossGroups; - m_composeAcrossGroups = x.m_composeAcrossGroups; - x.m_composeAcrossGroups = tmp2; +void KeyMap::swap(KeyMap &x) { + m_keyIDMap.swap(x.m_keyIDMap); + m_modifierKeys.swap(x.m_modifierKeys); + m_halfDuplex.swap(x.m_halfDuplex); + m_halfDuplexMods.swap(x.m_halfDuplexMods); + SInt32 tmp1 = m_numGroups; + m_numGroups = x.m_numGroups; + x.m_numGroups = tmp1; + bool tmp2 = m_composeAcrossGroups; + m_composeAcrossGroups = x.m_composeAcrossGroups; + x.m_composeAcrossGroups = tmp2; } -void -KeyMap::addKeyEntry(const KeyItem& item) -{ - // ignore kKeyNone - if (item.m_id == kKeyNone) { - return; +void KeyMap::addKeyEntry(const KeyItem &item) { + // ignore kKeyNone + if (item.m_id == kKeyNone) { + return; + } + + // resize number of groups for key + SInt32 numGroups = item.m_group + 1; + if (getNumGroups() > numGroups) { + numGroups = getNumGroups(); + } + KeyGroupTable &groupTable = m_keyIDMap[item.m_id]; + if (groupTable.size() < static_cast(numGroups)) { + groupTable.resize(numGroups); + } + + // make a list from the item + KeyItemList items; + items.push_back(item); + + // set group and dead key flag on the item + KeyItem &newItem = items.back(); + newItem.m_dead = isDeadKey(item.m_id); + + // mask the required bits with the sensitive bits + newItem.m_required &= newItem.m_sensitive; + + // see if we already have this item; just return if so + KeyEntryList &entries = groupTable[item.m_group]; + for (size_t i = 0, n = entries.size(); i < n; ++i) { + if (entries[i].size() == 1 && newItem == entries[i][0]) { + return; + } + } + + // add item list + entries.push_back(items); + LOG((CLOG_DEBUG5 "add key: %04x %d %03x %04x (%04x %04x %04x)%s", + newItem.m_id, newItem.m_group, newItem.m_button, newItem.m_client, + newItem.m_required, newItem.m_sensitive, newItem.m_generates, + newItem.m_dead ? " dead" : "")); +} + +void KeyMap::addKeyAliasEntry(KeyID targetID, SInt32 group, + KeyModifierMask targetRequired, + KeyModifierMask targetSensitive, KeyID sourceID, + KeyModifierMask sourceRequired, + KeyModifierMask sourceSensitive) { + // if we can already generate the target as desired then we're done. + if (findCompatibleKey(targetID, group, targetRequired, targetSensitive) != + NULL) { + return; + } + + // find a compatible source, preferably in the same group + for (SInt32 gd = 0, n = getNumGroups(); gd < n; ++gd) { + SInt32 eg = getEffectiveGroup(group, gd); + const KeyItemList *sourceEntry = + findCompatibleKey(sourceID, eg, sourceRequired, sourceSensitive); + if (sourceEntry != NULL && sourceEntry->size() == 1) { + KeyMap::KeyItem targetItem = sourceEntry->back(); + targetItem.m_id = targetID; + targetItem.m_group = eg; + addKeyEntry(targetItem); + break; + } + } +} + +bool KeyMap::addKeyCombinationEntry(KeyID id, SInt32 group, const KeyID *keys, + UInt32 numKeys) { + // disallow kKeyNone + if (id == kKeyNone) { + return false; + } + + SInt32 numGroups = group + 1; + if (getNumGroups() > numGroups) { + numGroups = getNumGroups(); + } + KeyGroupTable &groupTable = m_keyIDMap[id]; + if (groupTable.size() < static_cast(numGroups)) { + groupTable.resize(numGroups); + } + if (!groupTable[group].empty()) { + // key is already in the table + return false; + } + + // convert to buttons + KeyItemList items; + for (UInt32 i = 0; i < numKeys; ++i) { + KeyIDMap::const_iterator gtIndex = m_keyIDMap.find(keys[i]); + if (gtIndex == m_keyIDMap.end()) { + return false; + } + const KeyGroupTable &groupTable = gtIndex->second; + + // if we allow group switching during composition then search all + // groups for keys, otherwise search just the given group. + SInt32 n = 1; + if (m_composeAcrossGroups) { + n = (SInt32)groupTable.size(); } - // resize number of groups for key - SInt32 numGroups = item.m_group + 1; - if (getNumGroups() > numGroups) { - numGroups = getNumGroups(); - } - KeyGroupTable& groupTable = m_keyIDMap[item.m_id]; - if (groupTable.size() < static_cast(numGroups)) { - groupTable.resize(numGroups); - } - - // make a list from the item - KeyItemList items; - items.push_back(item); - - // set group and dead key flag on the item - KeyItem& newItem = items.back(); - newItem.m_dead = isDeadKey(item.m_id); - - // mask the required bits with the sensitive bits - newItem.m_required &= newItem.m_sensitive; - - // see if we already have this item; just return if so - KeyEntryList& entries = groupTable[item.m_group]; - for (size_t i = 0, n = entries.size(); i < n; ++i) { - if (entries[i].size() == 1 && newItem == entries[i][0]) { - return; + bool found = false; + for (SInt32 gd = 0; gd < n && !found; ++gd) { + SInt32 eg = (group + gd) % getNumGroups(); + const KeyEntryList &entries = groupTable[eg]; + for (size_t j = 0; j < entries.size(); ++j) { + if (entries[j].size() == 1) { + found = true; + items.push_back(entries[j][0]); + break; } + } } + if (!found) { + // required key is not in keyboard group + return false; + } + } - // add item list - entries.push_back(items); - LOG((CLOG_DEBUG5 "add key: %04x %d %03x %04x (%04x %04x %04x)%s", newItem.m_id, newItem.m_group, newItem.m_button, newItem.m_client, newItem.m_required, newItem.m_sensitive, newItem.m_generates, newItem.m_dead ? " dead" : "")); + // add key + groupTable[group].push_back(items); + return true; } -void -KeyMap::addKeyAliasEntry(KeyID targetID, SInt32 group, - KeyModifierMask targetRequired, - KeyModifierMask targetSensitive, - KeyID sourceID, - KeyModifierMask sourceRequired, - KeyModifierMask sourceSensitive) -{ - // if we can already generate the target as desired then we're done. - if (findCompatibleKey(targetID, group, targetRequired, - targetSensitive) != NULL) { - return; - } +void KeyMap::allowGroupSwitchDuringCompose() { m_composeAcrossGroups = true; } - // find a compatible source, preferably in the same group - for (SInt32 gd = 0, n = getNumGroups(); gd < n; ++gd) { - SInt32 eg = getEffectiveGroup(group, gd); - const KeyItemList* sourceEntry = - findCompatibleKey(sourceID, eg, - sourceRequired, sourceSensitive); - if (sourceEntry != NULL && sourceEntry->size() == 1) { - KeyMap::KeyItem targetItem = sourceEntry->back(); - targetItem.m_id = targetID; - targetItem.m_group = eg; - addKeyEntry(targetItem); - break; +void KeyMap::addHalfDuplexButton(KeyButton button) { + m_halfDuplex.insert(button); +} + +void KeyMap::clearHalfDuplexModifiers() { m_halfDuplexMods.clear(); } + +void KeyMap::addHalfDuplexModifier(KeyID key) { m_halfDuplexMods.insert(key); } + +void KeyMap::finish() { + m_numGroups = findNumGroups(); + + // make sure every key has the same number of groups + for (KeyIDMap::iterator i = m_keyIDMap.begin(); i != m_keyIDMap.end(); ++i) { + i->second.resize(m_numGroups); + } + + // compute keys that generate each modifier + setModifierKeys(); +} + +void KeyMap::foreachKey(ForeachKeyCallback cb, void *userData) { + for (KeyIDMap::iterator i = m_keyIDMap.begin(); i != m_keyIDMap.end(); ++i) { + KeyGroupTable &groupTable = i->second; + for (size_t group = 0; group < groupTable.size(); ++group) { + KeyEntryList &entryList = groupTable[group]; + for (size_t j = 0; j < entryList.size(); ++j) { + KeyItemList &itemList = entryList[j]; + for (size_t k = 0; k < itemList.size(); ++k) { + (*cb)(i->first, static_cast(group), itemList[k], userData); } + } } + } } -bool -KeyMap::addKeyCombinationEntry(KeyID id, SInt32 group, - const KeyID* keys, UInt32 numKeys) -{ - // disallow kKeyNone - if (id == kKeyNone) { - return false; - } - - SInt32 numGroups = group + 1; - if (getNumGroups() > numGroups) { - numGroups = getNumGroups(); - } - KeyGroupTable& groupTable = m_keyIDMap[id]; - if (groupTable.size() < static_cast(numGroups)) { - groupTable.resize(numGroups); - } - if (!groupTable[group].empty()) { - // key is already in the table - return false; - } - - // convert to buttons - KeyItemList items; - for (UInt32 i = 0; i < numKeys; ++i) { - KeyIDMap::const_iterator gtIndex = m_keyIDMap.find(keys[i]); - if (gtIndex == m_keyIDMap.end()) { - return false; - } - const KeyGroupTable& groupTable = gtIndex->second; - - // if we allow group switching during composition then search all - // groups for keys, otherwise search just the given group. - SInt32 n = 1; - if (m_composeAcrossGroups) { - n = (SInt32)groupTable.size(); - } - - bool found = false; - for (SInt32 gd = 0; gd < n && !found; ++gd) { - SInt32 eg = (group + gd) % getNumGroups(); - const KeyEntryList& entries = groupTable[eg]; - for (size_t j = 0; j < entries.size(); ++j) { - if (entries[j].size() == 1) { - found = true; - items.push_back(entries[j][0]); - break; - } - } - } - if (!found) { - // required key is not in keyboard group - return false; - } - } - - // add key - groupTable[group].push_back(items); - return true; -} - -void -KeyMap::allowGroupSwitchDuringCompose() -{ - m_composeAcrossGroups = true; -} - -void -KeyMap::addHalfDuplexButton(KeyButton button) -{ - m_halfDuplex.insert(button); -} - -void -KeyMap::clearHalfDuplexModifiers() -{ - m_halfDuplexMods.clear(); -} - -void -KeyMap::addHalfDuplexModifier(KeyID key) -{ - m_halfDuplexMods.insert(key); -} - -void -KeyMap::finish() -{ - m_numGroups = findNumGroups(); - - // make sure every key has the same number of groups - for (KeyIDMap::iterator i = m_keyIDMap.begin(); - i != m_keyIDMap.end(); ++i) { - i->second.resize(m_numGroups); - } - - // compute keys that generate each modifier - setModifierKeys(); -} - -void -KeyMap::foreachKey(ForeachKeyCallback cb, void* userData) -{ - for (KeyIDMap::iterator i = m_keyIDMap.begin(); - i != m_keyIDMap.end(); ++i) { - KeyGroupTable& groupTable = i->second; - for (size_t group = 0; group < groupTable.size(); ++group) { - KeyEntryList& entryList = groupTable[group]; - for (size_t j = 0; j < entryList.size(); ++j) { - KeyItemList& itemList = entryList[j]; - for (size_t k = 0; k < itemList.size(); ++k) { - (*cb)(i->first, static_cast(group), - itemList[k], userData); - } - } - } - } -} - -const KeyMap::KeyItem* -KeyMap::mapKey(Keystrokes& keys, KeyID id, SInt32 group, - ModifierToKeys& activeModifiers, - KeyModifierMask& currentState, - KeyModifierMask desiredMask, - bool isAutoRepeat, const String& lang) const -{ - LOG((CLOG_DEBUG1 "mapKey %04x (%d) with mask %04x, start state: %04x, group: %d", - id, id, desiredMask, currentState, group)); - - // handle group change - if (id == kKeyNextGroup) { - keys.push_back(Keystroke(1, false, false)); - return NULL; - } - else if (id == kKeyPrevGroup) { - keys.push_back(Keystroke(-1, false, false)); - return NULL; - } - - const KeyItem* item; - switch (id) { - case kKeyShift_L: - case kKeyShift_R: - case kKeyControl_L: - case kKeyControl_R: - case kKeyAlt_L: - case kKeyAlt_R: - case kKeyMeta_L: - case kKeyMeta_R: - case kKeySuper_L: - case kKeySuper_R: - case kKeyAltGr: - case kKeyCapsLock: - case kKeyNumLock: - case kKeyScrollLock: - item = mapModifierKey(keys, id, group, activeModifiers, - currentState, desiredMask, isAutoRepeat, lang); - break; - - case kKeySetModifiers: - if (!keysForModifierState(0, group, activeModifiers, currentState, - desiredMask, desiredMask, 0, keys)) { - LOG((CLOG_DEBUG1 "unable to set modifiers %04x", desiredMask)); - return NULL; - } - return &m_modifierKeyItem; - - case kKeyClearModifiers: - if (!keysForModifierState(0, group, activeModifiers, currentState, - currentState & ~desiredMask, - desiredMask, 0, keys)) { - LOG((CLOG_DEBUG1 "unable to clear modifiers %04x", desiredMask)); - return NULL; - } - return &m_modifierKeyItem; - - default: - if (isCommand(desiredMask)) { - item = mapCommandKey(keys, id, group, activeModifiers, - currentState, desiredMask, isAutoRepeat, lang); - } - else { - item = mapCharacterKey(keys, id, group, activeModifiers, - currentState, desiredMask, isAutoRepeat, lang); - } - break; - } - - if (item != NULL) { - LOG((CLOG_DEBUG1 "mapped to %03x, new state %04x", item->m_button, currentState)); - } - return item; -} - -void KeyMap::setLanguageData(std::vector layouts) -{ - m_keyboardLayouts = std::move(layouts); -} - -SInt32 KeyMap::getLanguageGroupID(SInt32 group, const String& lang) const -{ - SInt32 id = group; - - auto it = std::find(m_keyboardLayouts.begin(), m_keyboardLayouts.end(), lang); - if (it != m_keyboardLayouts.end()) { - id = static_cast(std::distance(m_keyboardLayouts.begin(), it)); - LOG((CLOG_DEBUG1 "language %s has group id %d", lang.c_str(), id)); - } - else { - LOG((CLOG_DEBUG1 "could not found requested language")); - } - - return id; -} - -SInt32 -KeyMap::getNumGroups() const -{ - return m_numGroups; -} - -SInt32 -KeyMap::getEffectiveGroup(SInt32 group, SInt32 offset) const -{ - return (group + offset + getNumGroups()) % getNumGroups(); -} - -const KeyMap::KeyItemList* -KeyMap::findCompatibleKey(KeyID id, SInt32 group, - KeyModifierMask required, KeyModifierMask sensitive) const -{ - assert(group >= 0 && group < getNumGroups()); - - KeyIDMap::const_iterator i = m_keyIDMap.find(id); - if (i == m_keyIDMap.end()) { - return NULL; - } - - const KeyEntryList& entries = i->second[group]; - for (size_t j = 0; j < entries.size(); ++j) { - if ((entries[j].back().m_sensitive & sensitive) == 0 || - (entries[j].back().m_required & sensitive) == - (required & sensitive)) { - return &entries[j]; - } - } +const KeyMap::KeyItem *KeyMap::mapKey(Keystrokes &keys, KeyID id, SInt32 group, + ModifierToKeys &activeModifiers, + KeyModifierMask ¤tState, + KeyModifierMask desiredMask, + bool isAutoRepeat, + const String &lang) const { + LOG((CLOG_DEBUG1 + "mapKey %04x (%d) with mask %04x, start state: %04x, group: %d", + id, id, desiredMask, currentState, group)); + // handle group change + if (id == kKeyNextGroup) { + keys.push_back(Keystroke(1, false, false)); return NULL; + } else if (id == kKeyPrevGroup) { + keys.push_back(Keystroke(-1, false, false)); + return NULL; + } + + const KeyItem *item; + switch (id) { + case kKeyShift_L: + case kKeyShift_R: + case kKeyControl_L: + case kKeyControl_R: + case kKeyAlt_L: + case kKeyAlt_R: + case kKeyMeta_L: + case kKeyMeta_R: + case kKeySuper_L: + case kKeySuper_R: + case kKeyAltGr: + case kKeyCapsLock: + case kKeyNumLock: + case kKeyScrollLock: + item = mapModifierKey(keys, id, group, activeModifiers, currentState, + desiredMask, isAutoRepeat, lang); + break; + + case kKeySetModifiers: + if (!keysForModifierState(0, group, activeModifiers, currentState, + desiredMask, desiredMask, 0, keys)) { + LOG((CLOG_DEBUG1 "unable to set modifiers %04x", desiredMask)); + return NULL; + } + return &m_modifierKeyItem; + + case kKeyClearModifiers: + if (!keysForModifierState(0, group, activeModifiers, currentState, + currentState & ~desiredMask, desiredMask, 0, + keys)) { + LOG((CLOG_DEBUG1 "unable to clear modifiers %04x", desiredMask)); + return NULL; + } + return &m_modifierKeyItem; + + default: + if (isCommand(desiredMask)) { + item = mapCommandKey(keys, id, group, activeModifiers, currentState, + desiredMask, isAutoRepeat, lang); + } else { + item = mapCharacterKey(keys, id, group, activeModifiers, currentState, + desiredMask, isAutoRepeat, lang); + } + break; + } + + if (item != NULL) { + LOG((CLOG_DEBUG1 "mapped to %03x, new state %04x", item->m_button, + currentState)); + } + return item; } -bool -KeyMap::isHalfDuplex(KeyID key, KeyButton button) const -{ - return (m_halfDuplex.count(button) + m_halfDuplexMods.count(key) > 0); +void KeyMap::setLanguageData(std::vector layouts) { + m_keyboardLayouts = std::move(layouts); } -bool -KeyMap::isCommand(KeyModifierMask mask) const -{ - return ((mask & getCommandModifiers()) != 0); +SInt32 KeyMap::getLanguageGroupID(SInt32 group, const String &lang) const { + SInt32 id = group; + + auto it = std::find(m_keyboardLayouts.begin(), m_keyboardLayouts.end(), lang); + if (it != m_keyboardLayouts.end()) { + id = static_cast(std::distance(m_keyboardLayouts.begin(), it)); + LOG((CLOG_DEBUG1 "language %s has group id %d", lang.c_str(), id)); + } else { + LOG((CLOG_DEBUG1 "could not found requested language")); + } + + return id; } -KeyModifierMask -KeyMap::getCommandModifiers() const -{ - // we currently treat ctrl, alt, meta and super as command modifiers. - // some platforms may have a more limited set (OS X only needs Alt) - // but this works anyway. - return KeyModifierControl | - KeyModifierAlt | - KeyModifierAltGr | - KeyModifierMeta | - KeyModifierSuper; +SInt32 KeyMap::getNumGroups() const { return m_numGroups; } + +SInt32 KeyMap::getEffectiveGroup(SInt32 group, SInt32 offset) const { + return (group + offset + getNumGroups()) % getNumGroups(); } -void -KeyMap::collectButtons(const ModifierToKeys& mods, ButtonToKeyMap& keys) -{ +const KeyMap::KeyItemList * +KeyMap::findCompatibleKey(KeyID id, SInt32 group, KeyModifierMask required, + KeyModifierMask sensitive) const { + assert(group >= 0 && group < getNumGroups()); + + KeyIDMap::const_iterator i = m_keyIDMap.find(id); + if (i == m_keyIDMap.end()) { + return NULL; + } + + const KeyEntryList &entries = i->second[group]; + for (size_t j = 0; j < entries.size(); ++j) { + if ((entries[j].back().m_sensitive & sensitive) == 0 || + (entries[j].back().m_required & sensitive) == (required & sensitive)) { + return &entries[j]; + } + } + + return NULL; +} + +bool KeyMap::isHalfDuplex(KeyID key, KeyButton button) const { + return (m_halfDuplex.count(button) + m_halfDuplexMods.count(key) > 0); +} + +bool KeyMap::isCommand(KeyModifierMask mask) const { + return ((mask & getCommandModifiers()) != 0); +} + +KeyModifierMask KeyMap::getCommandModifiers() const { + // we currently treat ctrl, alt, meta and super as command modifiers. + // some platforms may have a more limited set (OS X only needs Alt) + // but this works anyway. + return KeyModifierControl | KeyModifierAlt | KeyModifierAltGr | + KeyModifierMeta | KeyModifierSuper; +} + +void KeyMap::collectButtons(const ModifierToKeys &mods, ButtonToKeyMap &keys) { + keys.clear(); + for (ModifierToKeys::const_iterator i = mods.begin(); i != mods.end(); ++i) { + keys.insert(std::make_pair(i->second.m_button, &i->second)); + } +} + +void KeyMap::initModifierKey(KeyItem &item) { + item.m_generates = 0; + item.m_lock = false; + switch (item.m_id) { + case kKeyShift_L: + case kKeyShift_R: + item.m_generates = KeyModifierShift; + break; + + case kKeyControl_L: + case kKeyControl_R: + item.m_generates = KeyModifierControl; + break; + + case kKeyAlt_L: + case kKeyAlt_R: + item.m_generates = KeyModifierAlt; + break; + + case kKeyMeta_L: + case kKeyMeta_R: + item.m_generates = KeyModifierMeta; + break; + + case kKeySuper_L: + case kKeySuper_R: + item.m_generates = KeyModifierSuper; + break; + + case kKeyAltGr: + item.m_generates = KeyModifierAltGr; + break; + + case kKeyCapsLock: + item.m_generates = KeyModifierCapsLock; + item.m_lock = true; + break; + + case kKeyNumLock: + item.m_generates = KeyModifierNumLock; + item.m_lock = true; + break; + + case kKeyScrollLock: + item.m_generates = KeyModifierScrollLock; + item.m_lock = true; + break; + + default: + // not a modifier + break; + } +} + +SInt32 KeyMap::findNumGroups() const { + size_t max = 0; + for (KeyIDMap::const_iterator i = m_keyIDMap.begin(); i != m_keyIDMap.end(); + ++i) { + if (i->second.size() > max) { + max = i->second.size(); + } + } + return static_cast(max); +} + +void KeyMap::setModifierKeys() { + m_modifierKeys.clear(); + m_modifierKeys.resize(kKeyModifierNumBits * getNumGroups()); + for (KeyIDMap::const_iterator i = m_keyIDMap.begin(); i != m_keyIDMap.end(); + ++i) { + const KeyGroupTable &groupTable = i->second; + for (size_t g = 0; g < groupTable.size(); ++g) { + const KeyEntryList &entries = groupTable[g]; + for (size_t j = 0; j < entries.size(); ++j) { + // skip multi-key sequences + if (entries[j].size() != 1) { + continue; + } + + // skip keys that don't generate a modifier + const KeyItem &item = entries[j].back(); + if (item.m_generates == 0) { + continue; + } + + // add key to each indicated modifier in this group + for (SInt32 b = 0; b < kKeyModifierNumBits; ++b) { + // skip if item doesn't generate bit b + if (((1u << b) & item.m_generates) != 0) { + SInt32 mIndex = (SInt32)g * kKeyModifierNumBits + b; + m_modifierKeys[mIndex].push_back(&item); + } + } + } + } + } +} + +const KeyMap::KeyItem *KeyMap::mapCommandKey( + Keystrokes &keys, KeyID id, SInt32 group, ModifierToKeys &activeModifiers, + KeyModifierMask ¤tState, KeyModifierMask desiredMask, + bool isAutoRepeat, const String &lang) const { + static const KeyModifierMask s_overrideModifiers = 0xffffu; + + // find KeySym in table + KeyIDMap::const_iterator i = m_keyIDMap.find(id); + if (i == m_keyIDMap.end()) { + // unknown key + LOG((CLOG_DEBUG1 "key %04x is not on keyboard", id)); + return NULL; + } + const KeyGroupTable &keyGroupTable = i->second; + + // find the first key that generates this KeyID + const KeyItem *keyItem = NULL; + SInt32 numGroups = getNumGroups(); + for (SInt32 groupOffset = 0; groupOffset < numGroups; ++groupOffset) { + SInt32 effectiveGroup = getEffectiveGroup(group, groupOffset); + const KeyEntryList &entryList = keyGroupTable[effectiveGroup]; + for (size_t i = 0; i < entryList.size(); ++i) { + if (entryList[i].size() != 1) { + // ignore multikey entries + continue; + } + + // match based on shift and make sure all required modifiers, + // except shift, are already in the desired mask; we're + // after the right button not the right character. + // we'll use desiredMask as-is, overriding the key's required + // modifiers, when synthesizing this button. + const KeyItem &item = entryList[i].back(); + KeyModifierMask desiredShiftMask = KeyModifierShift & desiredMask; + KeyModifierMask requiredIgnoreShiftMask = + item.m_required & ~KeyModifierShift; + if ((item.m_required & desiredShiftMask) == + (item.m_sensitive & desiredShiftMask) && + ((requiredIgnoreShiftMask & desiredMask) == + requiredIgnoreShiftMask)) { + LOG((CLOG_DEBUG1 "found key in group %d", effectiveGroup)); + keyItem = &item; + break; + } + } + if (keyItem != NULL) { + break; + } + } + if (keyItem == NULL) { + // no mapping for this keysym + LOG((CLOG_DEBUG1 "no mapping for key %04x", id)); + return NULL; + } + + // make working copy of modifiers + ModifierToKeys newModifiers = activeModifiers; + KeyModifierMask newState = currentState; + SInt32 newGroup = group; + + // don't try to change CapsLock + desiredMask = (desiredMask & ~KeyModifierCapsLock) | + (currentState & KeyModifierCapsLock); + + // add the key + if (!keysForKeyItem(*keyItem, newGroup, newModifiers, newState, desiredMask, + s_overrideModifiers, isAutoRepeat, keys, lang)) { + LOG((CLOG_DEBUG1 "can't map key")); keys.clear(); - for (ModifierToKeys::const_iterator i = mods.begin(); - i != mods.end(); ++i) { - keys.insert(std::make_pair(i->second.m_button, &i->second)); - } -} - -void -KeyMap::initModifierKey(KeyItem& item) -{ - item.m_generates = 0; - item.m_lock = false; - switch (item.m_id) { - case kKeyShift_L: - case kKeyShift_R: - item.m_generates = KeyModifierShift; - break; - - case kKeyControl_L: - case kKeyControl_R: - item.m_generates = KeyModifierControl; - break; - - case kKeyAlt_L: - case kKeyAlt_R: - item.m_generates = KeyModifierAlt; - break; - - case kKeyMeta_L: - case kKeyMeta_R: - item.m_generates = KeyModifierMeta; - break; - - case kKeySuper_L: - case kKeySuper_R: - item.m_generates = KeyModifierSuper; - break; - - case kKeyAltGr: - item.m_generates = KeyModifierAltGr; - break; - - case kKeyCapsLock: - item.m_generates = KeyModifierCapsLock; - item.m_lock = true; - break; - - case kKeyNumLock: - item.m_generates = KeyModifierNumLock; - item.m_lock = true; - break; - - case kKeyScrollLock: - item.m_generates = KeyModifierScrollLock; - item.m_lock = true; - break; - - default: - // not a modifier - break; - } -} - -SInt32 -KeyMap::findNumGroups() const -{ - size_t max = 0; - for (KeyIDMap::const_iterator i = m_keyIDMap.begin(); - i != m_keyIDMap.end(); ++i) { - if (i->second.size() > max) { - max = i->second.size(); - } - } - return static_cast(max); -} - -void -KeyMap::setModifierKeys() -{ - m_modifierKeys.clear(); - m_modifierKeys.resize(kKeyModifierNumBits * getNumGroups()); - for (KeyIDMap::const_iterator i = m_keyIDMap.begin(); - i != m_keyIDMap.end(); ++i) { - const KeyGroupTable& groupTable = i->second; - for (size_t g = 0; g < groupTable.size(); ++g) { - const KeyEntryList& entries = groupTable[g]; - for (size_t j = 0; j < entries.size(); ++j) { - // skip multi-key sequences - if (entries[j].size() != 1) { - continue; - } - - // skip keys that don't generate a modifier - const KeyItem& item = entries[j].back(); - if (item.m_generates == 0) { - continue; - } - - // add key to each indicated modifier in this group - for (SInt32 b = 0; b < kKeyModifierNumBits; ++b) { - // skip if item doesn't generate bit b - if (((1u << b) & item.m_generates) != 0) { - SInt32 mIndex = (SInt32)g * kKeyModifierNumBits + b; - m_modifierKeys[mIndex].push_back(&item); - } - } - } - } - } -} - -const KeyMap::KeyItem* -KeyMap::mapCommandKey(Keystrokes& keys, KeyID id, SInt32 group, - ModifierToKeys& activeModifiers, - KeyModifierMask& currentState, - KeyModifierMask desiredMask, - bool isAutoRepeat, const String& lang) const -{ - static const KeyModifierMask s_overrideModifiers = 0xffffu; - - // find KeySym in table - KeyIDMap::const_iterator i = m_keyIDMap.find(id); - if (i == m_keyIDMap.end()) { - // unknown key - LOG((CLOG_DEBUG1 "key %04x is not on keyboard", id)); - return NULL; - } - const KeyGroupTable& keyGroupTable = i->second; - - // find the first key that generates this KeyID - const KeyItem* keyItem = NULL; - SInt32 numGroups = getNumGroups(); - for (SInt32 groupOffset = 0; groupOffset < numGroups; ++groupOffset) { - SInt32 effectiveGroup = getEffectiveGroup(group, groupOffset); - const KeyEntryList& entryList = keyGroupTable[effectiveGroup]; - for (size_t i = 0; i < entryList.size(); ++i) { - if (entryList[i].size() != 1) { - // ignore multikey entries - continue; - } - - // match based on shift and make sure all required modifiers, - // except shift, are already in the desired mask; we're - // after the right button not the right character. - // we'll use desiredMask as-is, overriding the key's required - // modifiers, when synthesizing this button. - const KeyItem& item = entryList[i].back(); - KeyModifierMask desiredShiftMask = KeyModifierShift & desiredMask; - KeyModifierMask requiredIgnoreShiftMask = item.m_required & ~KeyModifierShift; - if ((item.m_required & desiredShiftMask) == (item.m_sensitive & desiredShiftMask) && - ((requiredIgnoreShiftMask & desiredMask) == requiredIgnoreShiftMask)) { - LOG((CLOG_DEBUG1 "found key in group %d", effectiveGroup)); - keyItem = &item; - break; - } - } - if (keyItem != NULL) { - break; - } - } - if (keyItem == NULL) { - // no mapping for this keysym - LOG((CLOG_DEBUG1 "no mapping for key %04x", id)); - return NULL; - } - - // make working copy of modifiers - ModifierToKeys newModifiers = activeModifiers; - KeyModifierMask newState = currentState; - SInt32 newGroup = group; - - // don't try to change CapsLock - desiredMask = (desiredMask & ~KeyModifierCapsLock) | - (currentState & KeyModifierCapsLock); - - // add the key - if (!keysForKeyItem(*keyItem, newGroup, newModifiers, - newState, desiredMask, - s_overrideModifiers, isAutoRepeat, keys, lang)) { - LOG((CLOG_DEBUG1 "can't map key")); - keys.clear(); - return NULL; - } - - // add keystrokes to restore modifier keys - if (!keysToRestoreModifiers(*keyItem, group, newModifiers, newState, - activeModifiers, keys)) { - LOG((CLOG_DEBUG1 "failed to restore modifiers")); - keys.clear(); - return NULL; - } - - // save new modifiers - activeModifiers = newModifiers; - currentState = newState; - - return keyItem; -} - -const KeyMap::KeyItemList* -KeyMap::getKeyItemList(const KeyMap::KeyGroupTable& keyGroupTable, SInt32 group, KeyModifierMask desiredMask) const -{ - const KeyItemList* itemList = nullptr; - - // find best key in any group, starting with the active group - for (SInt32 groupOffset = 0; groupOffset < getNumGroups(); ++groupOffset) { - auto effectiveGroup = getEffectiveGroup(group, groupOffset); - auto keyIndex = findBestKey(keyGroupTable[effectiveGroup], desiredMask); - if (keyIndex != -1) { - LOG((CLOG_DEBUG1 "found key in group %d", effectiveGroup)); - itemList = &keyGroupTable[effectiveGroup][keyIndex]; - break; - } - } - - return itemList; -} - -const KeyMap::KeyItem* -KeyMap::mapCharacterKey(Keystrokes& keys, KeyID id, SInt32 group, - ModifierToKeys& activeModifiers, - KeyModifierMask& currentState, - KeyModifierMask desiredMask, - bool isAutoRepeat, const String& lang) const -{ - // find KeySym in table - KeyIDMap::const_iterator i = m_keyIDMap.find(id); - if (i == m_keyIDMap.end()) { - // unknown key - LOG((CLOG_DEBUG1 "key %04x is not on keyboard", id)); - - return NULL; - } - - // get keys to press for key - auto itemList = getKeyItemList(i->second, getLanguageGroupID(group, lang), desiredMask); - if (!itemList || itemList->empty()) { - // no mapping for this keysym - LOG((CLOG_DEBUG1 "no mapping for key %04x", id)); - return NULL; - } - - const KeyItem& keyItem = itemList->back(); - - // make working copy of modifiers - ModifierToKeys newModifiers = activeModifiers; - KeyModifierMask newState = currentState; - SInt32 newGroup = group; - - // add each key - for (size_t j = 0; j < itemList->size(); ++j) { - if (!keysForKeyItem(itemList->at(j), newGroup, newModifiers, - newState, desiredMask, - 0, isAutoRepeat, keys, lang)) { - LOG((CLOG_DEBUG1 "can't map key")); - keys.clear(); - return NULL; - } - } - - // add keystrokes to restore modifier keys - if (!keysToRestoreModifiers(keyItem, group, newModifiers, newState, - activeModifiers, keys)) { - LOG((CLOG_DEBUG1 "failed to restore modifiers")); - keys.clear(); - return NULL; - } - - // save new modifiers - activeModifiers = newModifiers; - currentState = newState; - - return &keyItem; -} - -void -KeyMap::addGroupToKeystroke(Keystrokes& keys, SInt32& group, const String& lang) const -{ - group = getLanguageGroupID(group, lang); - keys.push_back(Keystroke(group, true, false)); -} - -const KeyMap::KeyItem* -KeyMap::mapModifierKey(Keystrokes& keys, KeyID id, SInt32 group, - ModifierToKeys& activeModifiers, - KeyModifierMask& currentState, - KeyModifierMask desiredMask, - bool isAutoRepeat, const String& lang) const -{ - return mapCharacterKey(keys, id, group, activeModifiers, - currentState, desiredMask, isAutoRepeat, lang); -} - -SInt32 -KeyMap::findBestKey(const KeyEntryList& entryList, KeyModifierMask desiredState) const -{ - // check for an item that can accommodate the desiredState exactly - for (SInt32 i = 0; i < (SInt32)entryList.size(); ++i) { - const KeyItem& item = entryList[i].back(); - if ((item.m_required & desiredState) == item.m_required && - (item.m_required & desiredState) == (item.m_sensitive & desiredState)) { - LOG((CLOG_DEBUG1 "best key index %d of %d (exact)", i + 1, entryList.size())); - return i; - } - } - - // choose the item that requires the fewest modifier changes - SInt32 bestCount = 32; - SInt32 bestIndex = -1; - for (SInt32 i = 0; i < (SInt32)entryList.size(); ++i) { - const KeyItem& item = entryList[i].back(); - KeyModifierMask change = - ((item.m_required ^ desiredState) & item.m_sensitive); - SInt32 n = getNumModifiers(change); - if (n < bestCount) { - bestCount = n; - bestIndex = i; - } - } - if (bestIndex != -1) { - LOG((CLOG_DEBUG1 "best key index %d of %d (%d modifiers)", - bestIndex + 1, entryList.size(), bestCount)); - } - - return bestIndex; -} - - -const KeyMap::KeyItem* -KeyMap::keyForModifier(KeyButton button, SInt32 group, - SInt32 modifierBit) const -{ - assert(modifierBit >= 0 && modifierBit < kKeyModifierNumBits); - assert(group >= 0 && group < getNumGroups()); - - // find a key that generates the given modifier in the given group - // but doesn't use the given button, presumably because we're trying - // to generate a KeyID that's only bound the the given button. - // this is important when a shift button is modified by shift; we - // must use the other shift button to do the shifting. - const ModifierKeyItemList& items = - m_modifierKeys[group * kKeyModifierNumBits + modifierBit]; - for (ModifierKeyItemList::const_iterator i = items.begin(); - i != items.end(); ++i) { - if ((*i)->m_button != button) { - return (*i); - } - } return NULL; + } + + // add keystrokes to restore modifier keys + if (!keysToRestoreModifiers(*keyItem, group, newModifiers, newState, + activeModifiers, keys)) { + LOG((CLOG_DEBUG1 "failed to restore modifiers")); + keys.clear(); + return NULL; + } + + // save new modifiers + activeModifiers = newModifiers; + currentState = newState; + + return keyItem; } -bool -KeyMap::keysForKeyItem(const KeyItem& keyItem, SInt32& group, - ModifierToKeys& activeModifiers, - KeyModifierMask& currentState, KeyModifierMask desiredState, - KeyModifierMask overrideModifiers, - bool isAutoRepeat, - Keystrokes& keystrokes, - const String& lang) const -{ - static const KeyModifierMask s_notRequiredMask = - KeyModifierAltGr | KeyModifierNumLock | KeyModifierScrollLock; +const KeyMap::KeyItemList * +KeyMap::getKeyItemList(const KeyMap::KeyGroupTable &keyGroupTable, SInt32 group, + KeyModifierMask desiredMask) const { + const KeyItemList *itemList = nullptr; - // add keystrokes to adjust the group - if (group != keyItem.m_group) { - group = keyItem.m_group; - addGroupToKeystroke(keystrokes, group, lang); + // find best key in any group, starting with the active group + for (SInt32 groupOffset = 0; groupOffset < getNumGroups(); ++groupOffset) { + auto effectiveGroup = getEffectiveGroup(group, groupOffset); + auto keyIndex = findBestKey(keyGroupTable[effectiveGroup], desiredMask); + if (keyIndex != -1) { + LOG((CLOG_DEBUG1 "found key in group %d", effectiveGroup)); + itemList = &keyGroupTable[effectiveGroup][keyIndex]; + break; + } + } + + return itemList; +} + +const KeyMap::KeyItem *KeyMap::mapCharacterKey( + Keystrokes &keys, KeyID id, SInt32 group, ModifierToKeys &activeModifiers, + KeyModifierMask ¤tState, KeyModifierMask desiredMask, + bool isAutoRepeat, const String &lang) const { + // find KeySym in table + KeyIDMap::const_iterator i = m_keyIDMap.find(id); + if (i == m_keyIDMap.end()) { + // unknown key + LOG((CLOG_DEBUG1 "key %04x is not on keyboard", id)); + + return NULL; + } + + // get keys to press for key + auto itemList = + getKeyItemList(i->second, getLanguageGroupID(group, lang), desiredMask); + if (!itemList || itemList->empty()) { + // no mapping for this keysym + LOG((CLOG_DEBUG1 "no mapping for key %04x", id)); + return NULL; + } + + const KeyItem &keyItem = itemList->back(); + + // make working copy of modifiers + ModifierToKeys newModifiers = activeModifiers; + KeyModifierMask newState = currentState; + SInt32 newGroup = group; + + // add each key + for (size_t j = 0; j < itemList->size(); ++j) { + if (!keysForKeyItem(itemList->at(j), newGroup, newModifiers, newState, + desiredMask, 0, isAutoRepeat, keys, lang)) { + LOG((CLOG_DEBUG1 "can't map key")); + keys.clear(); + return NULL; + } + } + + // add keystrokes to restore modifier keys + if (!keysToRestoreModifiers(keyItem, group, newModifiers, newState, + activeModifiers, keys)) { + LOG((CLOG_DEBUG1 "failed to restore modifiers")); + keys.clear(); + return NULL; + } + + // save new modifiers + activeModifiers = newModifiers; + currentState = newState; + + return &keyItem; +} + +void KeyMap::addGroupToKeystroke(Keystrokes &keys, SInt32 &group, + const String &lang) const { + group = getLanguageGroupID(group, lang); + keys.push_back(Keystroke(group, true, false)); +} + +const KeyMap::KeyItem *KeyMap::mapModifierKey( + Keystrokes &keys, KeyID id, SInt32 group, ModifierToKeys &activeModifiers, + KeyModifierMask ¤tState, KeyModifierMask desiredMask, + bool isAutoRepeat, const String &lang) const { + return mapCharacterKey(keys, id, group, activeModifiers, currentState, + desiredMask, isAutoRepeat, lang); +} + +SInt32 KeyMap::findBestKey(const KeyEntryList &entryList, + KeyModifierMask desiredState) const { + // check for an item that can accommodate the desiredState exactly + for (SInt32 i = 0; i < (SInt32)entryList.size(); ++i) { + const KeyItem &item = entryList[i].back(); + if ((item.m_required & desiredState) == item.m_required && + (item.m_required & desiredState) == (item.m_sensitive & desiredState)) { + LOG((CLOG_DEBUG1 "best key index %d of %d (exact)", i + 1, + entryList.size())); + return i; + } + } + + // choose the item that requires the fewest modifier changes + SInt32 bestCount = 32; + SInt32 bestIndex = -1; + for (SInt32 i = 0; i < (SInt32)entryList.size(); ++i) { + const KeyItem &item = entryList[i].back(); + KeyModifierMask change = + ((item.m_required ^ desiredState) & item.m_sensitive); + SInt32 n = getNumModifiers(change); + if (n < bestCount) { + bestCount = n; + bestIndex = i; + } + } + if (bestIndex != -1) { + LOG((CLOG_DEBUG1 "best key index %d of %d (%d modifiers)", bestIndex + 1, + entryList.size(), bestCount)); + } + + return bestIndex; +} + +const KeyMap::KeyItem *KeyMap::keyForModifier(KeyButton button, SInt32 group, + SInt32 modifierBit) const { + assert(modifierBit >= 0 && modifierBit < kKeyModifierNumBits); + assert(group >= 0 && group < getNumGroups()); + + // find a key that generates the given modifier in the given group + // but doesn't use the given button, presumably because we're trying + // to generate a KeyID that's only bound the the given button. + // this is important when a shift button is modified by shift; we + // must use the other shift button to do the shifting. + const ModifierKeyItemList &items = + m_modifierKeys[group * kKeyModifierNumBits + modifierBit]; + for (ModifierKeyItemList::const_iterator i = items.begin(); i != items.end(); + ++i) { + if ((*i)->m_button != button) { + return (*i); + } + } + return NULL; +} + +bool KeyMap::keysForKeyItem(const KeyItem &keyItem, SInt32 &group, + ModifierToKeys &activeModifiers, + KeyModifierMask ¤tState, + KeyModifierMask desiredState, + KeyModifierMask overrideModifiers, + bool isAutoRepeat, Keystrokes &keystrokes, + const String &lang) const { + static const KeyModifierMask s_notRequiredMask = + KeyModifierAltGr | KeyModifierNumLock | KeyModifierScrollLock; + + // add keystrokes to adjust the group + if (group != keyItem.m_group) { + group = keyItem.m_group; + addGroupToKeystroke(keystrokes, group, lang); + } + + EKeystroke type; + if (keyItem.m_dead) { + // adjust modifiers for dead key + if (!keysForModifierState(keyItem.m_button, group, activeModifiers, + currentState, keyItem.m_required, + keyItem.m_sensitive, 0, keystrokes)) { + LOG((CLOG_DEBUG1 "unable to match modifier state for dead key %d", + keyItem.m_button)); + return false; } - EKeystroke type; - if (keyItem.m_dead) { - // adjust modifiers for dead key - if (!keysForModifierState(keyItem.m_button, group, - activeModifiers, currentState, - keyItem.m_required, keyItem.m_sensitive, - 0, keystrokes)) { - LOG((CLOG_DEBUG1 "unable to match modifier state for dead key %d", keyItem.m_button)); - return false; - } + // press and release the dead key + type = kKeystrokeClick; + } else { + // if this a command key then we don't have to match some of the + // key's required modifiers. + KeyModifierMask sensitive = keyItem.m_sensitive & ~overrideModifiers; - // press and release the dead key - type = kKeystrokeClick; + // XXX -- must handle pressing a modifier. in particular, if we want + // to synthesize a KeyID on level 1 of a KeyButton that has Shift_L + // mapped to level 0 then we must release that button if it's down + // (in order to satisfy a shift modifier) then press a different + // button (any other button) mapped to the shift modifier and then + // the Shift_L button. + // match key's required state + LOG((CLOG_DEBUG1 "state: %04x,%04x,%04x", currentState, keyItem.m_required, + sensitive)); + if (!keysForModifierState(keyItem.m_button, group, activeModifiers, + currentState, keyItem.m_required, sensitive, 0, + keystrokes)) { + LOG((CLOG_DEBUG1 "unable to match modifier state (%04x,%04x) for key %d", + keyItem.m_required, keyItem.m_sensitive, keyItem.m_button)); + return false; } - else { - // if this a command key then we don't have to match some of the - // key's required modifiers. - KeyModifierMask sensitive = keyItem.m_sensitive & ~overrideModifiers; - // XXX -- must handle pressing a modifier. in particular, if we want - // to synthesize a KeyID on level 1 of a KeyButton that has Shift_L - // mapped to level 0 then we must release that button if it's down - // (in order to satisfy a shift modifier) then press a different - // button (any other button) mapped to the shift modifier and then - // the Shift_L button. - // match key's required state - LOG((CLOG_DEBUG1 "state: %04x,%04x,%04x", currentState, keyItem.m_required, sensitive)); - if (!keysForModifierState(keyItem.m_button, group, - activeModifiers, currentState, - keyItem.m_required, sensitive, - 0, keystrokes)) { - LOG((CLOG_DEBUG1 "unable to match modifier state (%04x,%04x) for key %d", keyItem.m_required, keyItem.m_sensitive, keyItem.m_button)); - return false; - } - - // match desiredState as closely as possible. we must not - // change any modifiers in keyItem.m_sensitive. and if the key - // is a modifier, we don't want to change that modifier. - LOG((CLOG_DEBUG1 "desired state: %04x %04x,%04x,%04x", desiredState, currentState, keyItem.m_required, keyItem.m_sensitive)); - if (!keysForModifierState(keyItem.m_button, group, - activeModifiers, currentState, - desiredState, - ~(sensitive | keyItem.m_generates), - s_notRequiredMask, keystrokes)) { - LOG((CLOG_DEBUG1 "unable to match desired modifier state (%04x,%04x) for key %d", desiredState, ~keyItem.m_sensitive & 0xffffu, keyItem.m_button)); - return false; - } - - // repeat or press of key - type = isAutoRepeat ? kKeystrokeRepeat : kKeystrokePress; + // match desiredState as closely as possible. we must not + // change any modifiers in keyItem.m_sensitive. and if the key + // is a modifier, we don't want to change that modifier. + LOG((CLOG_DEBUG1 "desired state: %04x %04x,%04x,%04x", desiredState, + currentState, keyItem.m_required, keyItem.m_sensitive)); + if (!keysForModifierState(keyItem.m_button, group, activeModifiers, + currentState, desiredState, + ~(sensitive | keyItem.m_generates), + s_notRequiredMask, keystrokes)) { + LOG((CLOG_DEBUG1 + "unable to match desired modifier state (%04x,%04x) for key %d", + desiredState, ~keyItem.m_sensitive & 0xffffu, keyItem.m_button)); + return false; } - addKeystrokes(type, keyItem, activeModifiers, currentState, keystrokes); + // repeat or press of key + type = isAutoRepeat ? kKeystrokeRepeat : kKeystrokePress; + } + addKeystrokes(type, keyItem, activeModifiers, currentState, keystrokes); + + return true; +} + +bool KeyMap::keysToRestoreModifiers(const KeyItem &keyItem, SInt32, + ModifierToKeys &activeModifiers, + KeyModifierMask ¤tState, + const ModifierToKeys &desiredModifiers, + Keystrokes &keystrokes) const { + // XXX -- we're not considering modified modifiers here + + ModifierToKeys oldModifiers = activeModifiers; + + // get the pressed modifier buttons before and after + ButtonToKeyMap oldKeys, newKeys; + collectButtons(oldModifiers, oldKeys); + collectButtons(desiredModifiers, newKeys); + + // release unwanted keys + for (ModifierToKeys::const_iterator i = oldModifiers.begin(); + i != oldModifiers.end(); ++i) { + KeyButton button = i->second.m_button; + if (button != keyItem.m_button && newKeys.count(button) == 0) { + EKeystroke type = kKeystrokeRelease; + if (i->second.m_lock) { + type = kKeystrokeUnmodify; + } + addKeystrokes(type, i->second, activeModifiers, currentState, keystrokes); + } + } + + // press wanted keys + for (ModifierToKeys::const_iterator i = desiredModifiers.begin(); + i != desiredModifiers.end(); ++i) { + KeyButton button = i->second.m_button; + if (button != keyItem.m_button && oldKeys.count(button) == 0) { + EKeystroke type = kKeystrokePress; + if (i->second.m_lock) { + type = kKeystrokeModify; + } + addKeystrokes(type, i->second, activeModifiers, currentState, keystrokes); + } + } + + return true; +} + +bool KeyMap::keysForModifierState(KeyButton button, SInt32 group, + ModifierToKeys &activeModifiers, + KeyModifierMask ¤tState, + KeyModifierMask requiredState, + KeyModifierMask sensitiveMask, + KeyModifierMask notRequiredMask, + Keystrokes &keystrokes) const { + // compute which modifiers need changing + KeyModifierMask flipMask = ((currentState ^ requiredState) & sensitiveMask); + // if a modifier is not required then don't even try to match it. if + // we don't mask out notRequiredMask then we'll try to match those + // modifiers but succeed if we can't. however, this is known not + // to work if the key itself is a modifier (the numlock toggle can + // interfere) so we don't try to match at all. + flipMask &= ~notRequiredMask; + LOG((CLOG_DEBUG1 "flip: %04x (%04x vs %04x in %04x - %04x)", flipMask, + currentState, requiredState, sensitiveMask & 0xffffu, + notRequiredMask & 0xffffu)); + if (flipMask == 0) { return true; -} + } -bool -KeyMap::keysToRestoreModifiers(const KeyItem& keyItem, SInt32, - ModifierToKeys& activeModifiers, - KeyModifierMask& currentState, - const ModifierToKeys& desiredModifiers, - Keystrokes& keystrokes) const -{ - // XXX -- we're not considering modified modifiers here - - ModifierToKeys oldModifiers = activeModifiers; - - // get the pressed modifier buttons before and after - ButtonToKeyMap oldKeys, newKeys; - collectButtons(oldModifiers, oldKeys); - collectButtons(desiredModifiers, newKeys); - - // release unwanted keys - for (ModifierToKeys::const_iterator i = oldModifiers.begin(); - i != oldModifiers.end(); ++i) { - KeyButton button = i->second.m_button; - if (button != keyItem.m_button && newKeys.count(button) == 0) { - EKeystroke type = kKeystrokeRelease; - if (i->second.m_lock) { - type = kKeystrokeUnmodify; - } - addKeystrokes(type, i->second, - activeModifiers, currentState, keystrokes); - } + // fix modifiers. this is complicated by the fact that a modifier may + // be sensitive to other modifiers! (who thought that up?) + // + // we'll assume that modifiers with higher bits are affected by modifiers + // with lower bits. there's not much basis for that assumption except + // that we're pretty sure shift isn't changed by other modifiers. + SInt32 bit = kKeyModifierNumBits; + while (bit-- > 0) { + KeyModifierMask mask = (1u << bit); + if ((flipMask & mask) == 0) { + // modifier is already correct + continue; } - // press wanted keys - for (ModifierToKeys::const_iterator i = desiredModifiers.begin(); - i != desiredModifiers.end(); ++i) { - KeyButton button = i->second.m_button; - if (button != keyItem.m_button && oldKeys.count(button) == 0) { - EKeystroke type = kKeystrokePress; - if (i->second.m_lock) { - type = kKeystrokeModify; - } - addKeystrokes(type, i->second, - activeModifiers, currentState, keystrokes); - } - } + // do we want the modifier active or inactive? + bool active = ((requiredState & mask) != 0); - return true; -} - -bool -KeyMap::keysForModifierState(KeyButton button, SInt32 group, - ModifierToKeys& activeModifiers, - KeyModifierMask& currentState, - KeyModifierMask requiredState, KeyModifierMask sensitiveMask, - KeyModifierMask notRequiredMask, - Keystrokes& keystrokes) const -{ - // compute which modifiers need changing - KeyModifierMask flipMask = ((currentState ^ requiredState) & sensitiveMask); - // if a modifier is not required then don't even try to match it. if - // we don't mask out notRequiredMask then we'll try to match those - // modifiers but succeed if we can't. however, this is known not - // to work if the key itself is a modifier (the numlock toggle can - // interfere) so we don't try to match at all. - flipMask &= ~notRequiredMask; - LOG((CLOG_DEBUG1 "flip: %04x (%04x vs %04x in %04x - %04x)", flipMask, currentState, requiredState, sensitiveMask & 0xffffu, notRequiredMask & 0xffffu)); - if (flipMask == 0) { - return true; - } - - // fix modifiers. this is complicated by the fact that a modifier may - // be sensitive to other modifiers! (who thought that up?) - // - // we'll assume that modifiers with higher bits are affected by modifiers - // with lower bits. there's not much basis for that assumption except - // that we're pretty sure shift isn't changed by other modifiers. - SInt32 bit = kKeyModifierNumBits; - while (bit-- > 0) { - KeyModifierMask mask = (1u << bit); - if ((flipMask & mask) == 0) { - // modifier is already correct - continue; - } - - // do we want the modifier active or inactive? - bool active = ((requiredState & mask) != 0); - - // get the KeyItem for the modifier in the group - const KeyItem* keyItem = keyForModifier(button, group, bit); - if (keyItem == NULL) { - if ((mask & notRequiredMask) == 0) { - LOG((CLOG_DEBUG1 "no key for modifier %04x", mask)); - return false; - } - else { - continue; - } - } - - // if this modifier is sensitive to modifiers then adjust those - // modifiers. also check if our assumption was correct. note - // that we only need to adjust the modifiers on key down. - KeyModifierMask sensitive = keyItem->m_sensitive; - if ((sensitive & mask) != 0) { - // modifier is sensitive to itself. that makes no sense - // so ignore it. - LOG((CLOG_DEBUG1 "modifier %04x modified by itself", mask)); - sensitive &= ~mask; - } - if (sensitive != 0) { - if (sensitive > mask) { - // our assumption is incorrect - LOG((CLOG_DEBUG1 "modifier %04x modified by %04x", mask, sensitive)); - return false; - } - if (active && !keysForModifierState(button, group, - activeModifiers, currentState, - keyItem->m_required, sensitive, - notRequiredMask, keystrokes)) { - return false; - } - else if (!active) { - // release the modifier - // XXX -- this doesn't work! if Alt and Meta are mapped - // to one key and we want to release Meta we can't do - // that without also releasing Alt. - // need to think about support for modified modifiers. - } - } - - // current state should match required state - if ((currentState & sensitive) != (keyItem->m_required & sensitive)) { - LOG((CLOG_DEBUG1 "unable to match modifier state for modifier %04x (%04x vs %04x in %04x)", mask, currentState, keyItem->m_required, sensitive)); - return false; - } - - // add keystrokes - EKeystroke type = active ? kKeystrokeModify : kKeystrokeUnmodify; - addKeystrokes(type, *keyItem, activeModifiers, currentState, - keystrokes); - } - - return true; -} - -void -KeyMap::addKeystrokes(EKeystroke type, const KeyItem& keyItem, - ModifierToKeys& activeModifiers, - KeyModifierMask& currentState, - Keystrokes& keystrokes) const -{ - KeyButton button = keyItem.m_button; - UInt32 data = keyItem.m_client; - switch (type) { - case kKeystrokePress: - keystrokes.push_back(Keystroke(button, true, false, data)); - if (keyItem.m_generates != 0) { - if (!keyItem.m_lock || (currentState & keyItem.m_generates) == 0) { - // add modifier key and activate modifier - activeModifiers.insert(std::make_pair( - keyItem.m_generates, keyItem)); - currentState |= keyItem.m_generates; - } - else { - // deactivate locking modifier - activeModifiers.erase(keyItem.m_generates); - currentState &= ~keyItem.m_generates; - } - } - break; - - case kKeystrokeRelease: - keystrokes.push_back(Keystroke(button, false, false, data)); - if (keyItem.m_generates != 0 && !keyItem.m_lock) { - // remove key from active modifiers - std::pair range = - activeModifiers.equal_range(keyItem.m_generates); - for (ModifierToKeys::iterator i = range.first; - i != range.second; ++i) { - if (i->second.m_button == button) { - activeModifiers.erase(i); - break; - } - } - - // if no more keys for this modifier then deactivate modifier - if (activeModifiers.count(keyItem.m_generates) == 0) { - currentState &= ~keyItem.m_generates; - } - } - break; - - case kKeystrokeRepeat: - keystrokes.push_back(Keystroke(button, false, true, data)); - keystrokes.push_back(Keystroke(button, true, true, data)); - // no modifier changes on key repeat - break; - - case kKeystrokeClick: - keystrokes.push_back(Keystroke(button, true, false, data)); - keystrokes.push_back(Keystroke(button, false, false, data)); - // no modifier changes on key click - break; - - case kKeystrokeModify: - case kKeystrokeUnmodify: - if (keyItem.m_lock) { - // we assume there's just one button for this modifier - if (m_halfDuplex.count(button) > 0) { - if (type == kKeystrokeModify) { - // turn half-duplex toggle on (press) - keystrokes.push_back(Keystroke(button, true, false, data)); - } - else { - // turn half-duplex toggle off (release) - keystrokes.push_back(Keystroke(button, false, false, data)); - } - } - else { - // toggle (click) - keystrokes.push_back(Keystroke(button, true, false, data)); - keystrokes.push_back(Keystroke(button, false, false, data)); - } - } - else if (type == kKeystrokeModify) { - // press modifier - keystrokes.push_back(Keystroke(button, true, false, data)); - } - else { - // release all the keys that generate the modifier that are - // currently down - std::pair range = - activeModifiers.equal_range(keyItem.m_generates); - for (ModifierToKeys::const_iterator i = range.first; - i != range.second; ++i) { - keystrokes.push_back(Keystroke(i->second.m_button, - false, false, i->second.m_client)); - } - } - - if (type == kKeystrokeModify) { - activeModifiers.insert(std::make_pair( - keyItem.m_generates, keyItem)); - currentState |= keyItem.m_generates; - } - else { - activeModifiers.erase(keyItem.m_generates); - currentState &= ~keyItem.m_generates; - } - break; - } -} - -SInt32 -KeyMap::getNumModifiers(KeyModifierMask state) -{ - SInt32 n = 0; - for (; state != 0; state >>= 1) { - if ((state & 1) != 0) { - ++n; - } - } - return n; -} - -bool -KeyMap::isDeadKey(KeyID key) -{ - return (key == kKeyCompose || (key >= 0x0300 && key <= 0x036f)); -} - -KeyID -KeyMap::getDeadKey(KeyID key) -{ - if (isDeadKey(key)) { - // already dead - return key; - } - - switch (key) { - case '`': - return kKeyDeadGrave; - - case '\'': - case 0xb4u: - return kKeyDeadAcute; - - case '^': - case 0x2c6: - return kKeyDeadCircumflex; - - case '~': - case 0x2dcu: - return kKeyDeadTilde; - - case 0xafu: - return kKeyDeadMacron; - - case 0x2d8u: - return kKeyDeadBreve; - - case 0x2d9u: - return kKeyDeadAbovedot; - - case 0xa8u: - return kKeyDeadDiaeresis; - - case 0xb0u: - case 0x2dau: - return kKeyDeadAbovering; - - case '\"': - case 0x2ddu: - return kKeyDeadDoubleacute; - - case 0x2c7u: - return kKeyDeadCaron; - - case 0xb8u: - return kKeyDeadCedilla; - - case 0x2dbu: - return kKeyDeadOgonek; - - default: - // unknown - return kKeyNone; - } -} - -String -KeyMap::formatKey(KeyID key, KeyModifierMask mask) -{ - // initialize tables - initKeyNameMaps(); - - String x; - for (SInt32 i = 0; i < kKeyModifierNumBits; ++i) { - KeyModifierMask mod = (1u << i); - if ((mask & mod) != 0 && s_modifierToNameMap->count(mod) > 0) { - x += s_modifierToNameMap->find(mod)->second; - x += "+"; - } - } - if (key != kKeyNone) { - if (s_keyToNameMap->count(key) > 0) { - x += s_keyToNameMap->find(key)->second; - } - // XXX -- we're assuming ASCII here - else if (key >= 33 && key < 127) { - x += (char)key; - } - else { - x += synergy::string::sprintf("\\u%04x", key); - } - } - else if (!x.empty()) { - // remove trailing '+' - x.erase(x.size() - 1); - } - return x; -} - -bool -KeyMap::parseKey(const String& x, KeyID& key) -{ - // initialize tables - initKeyNameMaps(); - - // parse the key - key = kKeyNone; - if (s_nameToKeyMap->count(x) > 0) { - key = s_nameToKeyMap->find(x)->second; - } - // XXX -- we're assuming ASCII encoding here - else if (x.size() == 1) { - if (!isgraph(x[0])) { - // unknown key - return false; - } - key = (KeyID)x[0]; - } - else if (x.size() == 6 && x[0] == '\\' && x[1] == 'u') { - // escaped unicode (\uXXXX where XXXX is a hex number) - char* end; - key = (KeyID)strtol(x.c_str() + 2, &end, 16); - if (*end != '\0') { - return false; - } - } - else if (!x.empty()) { - // unknown key + // get the KeyItem for the modifier in the group + const KeyItem *keyItem = keyForModifier(button, group, bit); + if (keyItem == NULL) { + if ((mask & notRequiredMask) == 0) { + LOG((CLOG_DEBUG1 "no key for modifier %04x", mask)); return false; + } else { + continue; + } } - return true; + // if this modifier is sensitive to modifiers then adjust those + // modifiers. also check if our assumption was correct. note + // that we only need to adjust the modifiers on key down. + KeyModifierMask sensitive = keyItem->m_sensitive; + if ((sensitive & mask) != 0) { + // modifier is sensitive to itself. that makes no sense + // so ignore it. + LOG((CLOG_DEBUG1 "modifier %04x modified by itself", mask)); + sensitive &= ~mask; + } + if (sensitive != 0) { + if (sensitive > mask) { + // our assumption is incorrect + LOG((CLOG_DEBUG1 "modifier %04x modified by %04x", mask, sensitive)); + return false; + } + if (active && + !keysForModifierState(button, group, activeModifiers, currentState, + keyItem->m_required, sensitive, notRequiredMask, + keystrokes)) { + return false; + } else if (!active) { + // release the modifier + // XXX -- this doesn't work! if Alt and Meta are mapped + // to one key and we want to release Meta we can't do + // that without also releasing Alt. + // need to think about support for modified modifiers. + } + } + + // current state should match required state + if ((currentState & sensitive) != (keyItem->m_required & sensitive)) { + LOG((CLOG_DEBUG1 "unable to match modifier state for modifier %04x (%04x " + "vs %04x in %04x)", + mask, currentState, keyItem->m_required, sensitive)); + return false; + } + + // add keystrokes + EKeystroke type = active ? kKeystrokeModify : kKeystrokeUnmodify; + addKeystrokes(type, *keyItem, activeModifiers, currentState, keystrokes); + } + + return true; } -bool -KeyMap::parseModifiers(String& x, KeyModifierMask& mask) -{ - // initialize tables - initKeyNameMaps(); +void KeyMap::addKeystrokes(EKeystroke type, const KeyItem &keyItem, + ModifierToKeys &activeModifiers, + KeyModifierMask ¤tState, + Keystrokes &keystrokes) const { + KeyButton button = keyItem.m_button; + UInt32 data = keyItem.m_client; + switch (type) { + case kKeystrokePress: + keystrokes.push_back(Keystroke(button, true, false, data)); + if (keyItem.m_generates != 0) { + if (!keyItem.m_lock || (currentState & keyItem.m_generates) == 0) { + // add modifier key and activate modifier + activeModifiers.insert(std::make_pair(keyItem.m_generates, keyItem)); + currentState |= keyItem.m_generates; + } else { + // deactivate locking modifier + activeModifiers.erase(keyItem.m_generates); + currentState &= ~keyItem.m_generates; + } + } + break; - mask = 0; - String::size_type tb = x.find_first_not_of(" \t", 0); - while (tb != String::npos) { - // get next component - String::size_type te = x.find_first_of(" \t+)", tb); - if (te == String::npos) { - te = x.size(); - } - String c = x.substr(tb, te - tb); - if (c.empty()) { - // missing component - return false; + case kKeystrokeRelease: + keystrokes.push_back(Keystroke(button, false, false, data)); + if (keyItem.m_generates != 0 && !keyItem.m_lock) { + // remove key from active modifiers + std::pair range = + activeModifiers.equal_range(keyItem.m_generates); + for (ModifierToKeys::iterator i = range.first; i != range.second; ++i) { + if (i->second.m_button == button) { + activeModifiers.erase(i); + break; } + } - if (s_nameToModifierMap->count(c) > 0) { - KeyModifierMask mod = s_nameToModifierMap->find(c)->second; - if ((mask & mod) != 0) { - // modifier appears twice - return false; - } - mask |= mod; - } - else { - // unknown string - x.erase(0, tb); - String::size_type tb = x.find_first_not_of(" \t"); - String::size_type te = x.find_last_not_of(" \t"); - if (tb == String::npos) { - x = ""; - } - else { - x = x.substr(tb, te - tb + 1); - } - return true; - } + // if no more keys for this modifier then deactivate modifier + if (activeModifiers.count(keyItem.m_generates) == 0) { + currentState &= ~keyItem.m_generates; + } + } + break; - // check for '+' or end of string - tb = x.find_first_not_of(" \t", te); - if (tb != String::npos) { - if (x[tb] != '+') { - // expected '+' - return false; - } - tb = x.find_first_not_of(" \t", tb + 1); + case kKeystrokeRepeat: + keystrokes.push_back(Keystroke(button, false, true, data)); + keystrokes.push_back(Keystroke(button, true, true, data)); + // no modifier changes on key repeat + break; + + case kKeystrokeClick: + keystrokes.push_back(Keystroke(button, true, false, data)); + keystrokes.push_back(Keystroke(button, false, false, data)); + // no modifier changes on key click + break; + + case kKeystrokeModify: + case kKeystrokeUnmodify: + if (keyItem.m_lock) { + // we assume there's just one button for this modifier + if (m_halfDuplex.count(button) > 0) { + if (type == kKeystrokeModify) { + // turn half-duplex toggle on (press) + keystrokes.push_back(Keystroke(button, true, false, data)); + } else { + // turn half-duplex toggle off (release) + keystrokes.push_back(Keystroke(button, false, false, data)); } + } else { + // toggle (click) + keystrokes.push_back(Keystroke(button, true, false, data)); + keystrokes.push_back(Keystroke(button, false, false, data)); + } + } else if (type == kKeystrokeModify) { + // press modifier + keystrokes.push_back(Keystroke(button, true, false, data)); + } else { + // release all the keys that generate the modifier that are + // currently down + std::pair + range = activeModifiers.equal_range(keyItem.m_generates); + for (ModifierToKeys::const_iterator i = range.first; i != range.second; + ++i) { + keystrokes.push_back( + Keystroke(i->second.m_button, false, false, i->second.m_client)); + } } - // parsed the whole thing - x = ""; - return true; + if (type == kKeystrokeModify) { + activeModifiers.insert(std::make_pair(keyItem.m_generates, keyItem)); + currentState |= keyItem.m_generates; + } else { + activeModifiers.erase(keyItem.m_generates); + currentState &= ~keyItem.m_generates; + } + break; + } } -void -KeyMap::initKeyNameMaps() -{ - // initialize tables - if (s_nameToKeyMap == NULL) { - s_nameToKeyMap = new NameToKeyMap; - s_keyToNameMap = new KeyToNameMap; - for (const KeyNameMapEntry* i = kKeyNameMap; i->m_name != NULL; ++i) { - (*s_nameToKeyMap)[i->m_name] = i->m_id; - (*s_keyToNameMap)[i->m_id] = i->m_name; - } - } - if (s_nameToModifierMap == NULL) { - s_nameToModifierMap = new NameToModifierMap; - s_modifierToNameMap = new ModifierToNameMap; - for (const KeyModifierNameMapEntry* i = kModifierNameMap; - i->m_name != NULL; ++i) { - (*s_nameToModifierMap)[i->m_name] = i->m_mask; - (*s_modifierToNameMap)[i->m_mask] = i->m_name; - } +SInt32 KeyMap::getNumModifiers(KeyModifierMask state) { + SInt32 n = 0; + for (; state != 0; state >>= 1) { + if ((state & 1) != 0) { + ++n; } + } + return n; } +bool KeyMap::isDeadKey(KeyID key) { + return (key == kKeyCompose || (key >= 0x0300 && key <= 0x036f)); +} + +KeyID KeyMap::getDeadKey(KeyID key) { + if (isDeadKey(key)) { + // already dead + return key; + } + + switch (key) { + case '`': + return kKeyDeadGrave; + + case '\'': + case 0xb4u: + return kKeyDeadAcute; + + case '^': + case 0x2c6: + return kKeyDeadCircumflex; + + case '~': + case 0x2dcu: + return kKeyDeadTilde; + + case 0xafu: + return kKeyDeadMacron; + + case 0x2d8u: + return kKeyDeadBreve; + + case 0x2d9u: + return kKeyDeadAbovedot; + + case 0xa8u: + return kKeyDeadDiaeresis; + + case 0xb0u: + case 0x2dau: + return kKeyDeadAbovering; + + case '\"': + case 0x2ddu: + return kKeyDeadDoubleacute; + + case 0x2c7u: + return kKeyDeadCaron; + + case 0xb8u: + return kKeyDeadCedilla; + + case 0x2dbu: + return kKeyDeadOgonek; + + default: + // unknown + return kKeyNone; + } +} + +String KeyMap::formatKey(KeyID key, KeyModifierMask mask) { + // initialize tables + initKeyNameMaps(); + + String x; + for (SInt32 i = 0; i < kKeyModifierNumBits; ++i) { + KeyModifierMask mod = (1u << i); + if ((mask & mod) != 0 && s_modifierToNameMap->count(mod) > 0) { + x += s_modifierToNameMap->find(mod)->second; + x += "+"; + } + } + if (key != kKeyNone) { + if (s_keyToNameMap->count(key) > 0) { + x += s_keyToNameMap->find(key)->second; + } + // XXX -- we're assuming ASCII here + else if (key >= 33 && key < 127) { + x += (char)key; + } else { + x += synergy::string::sprintf("\\u%04x", key); + } + } else if (!x.empty()) { + // remove trailing '+' + x.erase(x.size() - 1); + } + return x; +} + +bool KeyMap::parseKey(const String &x, KeyID &key) { + // initialize tables + initKeyNameMaps(); + + // parse the key + key = kKeyNone; + if (s_nameToKeyMap->count(x) > 0) { + key = s_nameToKeyMap->find(x)->second; + } + // XXX -- we're assuming ASCII encoding here + else if (x.size() == 1) { + if (!isgraph(x[0])) { + // unknown key + return false; + } + key = (KeyID)x[0]; + } else if (x.size() == 6 && x[0] == '\\' && x[1] == 'u') { + // escaped unicode (\uXXXX where XXXX is a hex number) + char *end; + key = (KeyID)strtol(x.c_str() + 2, &end, 16); + if (*end != '\0') { + return false; + } + } else if (!x.empty()) { + // unknown key + return false; + } + + return true; +} + +bool KeyMap::parseModifiers(String &x, KeyModifierMask &mask) { + // initialize tables + initKeyNameMaps(); + + mask = 0; + String::size_type tb = x.find_first_not_of(" \t", 0); + while (tb != String::npos) { + // get next component + String::size_type te = x.find_first_of(" \t+)", tb); + if (te == String::npos) { + te = x.size(); + } + String c = x.substr(tb, te - tb); + if (c.empty()) { + // missing component + return false; + } + + if (s_nameToModifierMap->count(c) > 0) { + KeyModifierMask mod = s_nameToModifierMap->find(c)->second; + if ((mask & mod) != 0) { + // modifier appears twice + return false; + } + mask |= mod; + } else { + // unknown string + x.erase(0, tb); + String::size_type tb = x.find_first_not_of(" \t"); + String::size_type te = x.find_last_not_of(" \t"); + if (tb == String::npos) { + x = ""; + } else { + x = x.substr(tb, te - tb + 1); + } + return true; + } + + // check for '+' or end of string + tb = x.find_first_not_of(" \t", te); + if (tb != String::npos) { + if (x[tb] != '+') { + // expected '+' + return false; + } + tb = x.find_first_not_of(" \t", tb + 1); + } + } + + // parsed the whole thing + x = ""; + return true; +} + +void KeyMap::initKeyNameMaps() { + // initialize tables + if (s_nameToKeyMap == NULL) { + s_nameToKeyMap = new NameToKeyMap; + s_keyToNameMap = new KeyToNameMap; + for (const KeyNameMapEntry *i = kKeyNameMap; i->m_name != NULL; ++i) { + (*s_nameToKeyMap)[i->m_name] = i->m_id; + (*s_keyToNameMap)[i->m_id] = i->m_name; + } + } + if (s_nameToModifierMap == NULL) { + s_nameToModifierMap = new NameToModifierMap; + s_modifierToNameMap = new ModifierToNameMap; + for (const KeyModifierNameMapEntry *i = kModifierNameMap; i->m_name != NULL; + ++i) { + (*s_nameToModifierMap)[i->m_name] = i->m_mask; + (*s_modifierToNameMap)[i->m_mask] = i->m_name; + } + } +} // // KeyMap::KeyItem // -bool -KeyMap::KeyItem::operator==(const KeyItem& x) const -{ - return (m_id == x.m_id && - m_group == x.m_group && - m_button == x.m_button && - m_required == x.m_required && - m_sensitive == x.m_sensitive && - m_generates == x.m_generates && - m_dead == x.m_dead && - m_lock == x.m_lock && - m_client == x.m_client); +bool KeyMap::KeyItem::operator==(const KeyItem &x) const { + return (m_id == x.m_id && m_group == x.m_group && m_button == x.m_button && + m_required == x.m_required && m_sensitive == x.m_sensitive && + m_generates == x.m_generates && m_dead == x.m_dead && + m_lock == x.m_lock && m_client == x.m_client); } - // // KeyMap::Keystroke // -KeyMap::Keystroke::Keystroke(KeyButton button, - bool press, bool repeat, UInt32 data) : - m_type(kButton) -{ - m_data.m_button.m_button = button; - m_data.m_button.m_press = press; - m_data.m_button.m_repeat = repeat; - m_data.m_button.m_client = data; +KeyMap::Keystroke::Keystroke(KeyButton button, bool press, bool repeat, + UInt32 data) + : m_type(kButton) { + m_data.m_button.m_button = button; + m_data.m_button.m_press = press; + m_data.m_button.m_repeat = repeat; + m_data.m_button.m_client = data; } -KeyMap::Keystroke::Keystroke(SInt32 group, bool absolute, bool restore) : - m_type(kGroup) -{ - m_data.m_group.m_group = group; - m_data.m_group.m_absolute = absolute; - m_data.m_group.m_restore = restore; +KeyMap::Keystroke::Keystroke(SInt32 group, bool absolute, bool restore) + : m_type(kGroup) { + m_data.m_group.m_group = group; + m_data.m_group.m_absolute = absolute; + m_data.m_group.m_restore = restore; } -} +} // namespace synergy diff --git a/src/lib/synergy/KeyMap.h b/src/lib/synergy/KeyMap.h index 0753bd7a9..ee8101c56 100644 --- a/src/lib/synergy/KeyMap.h +++ b/src/lib/synergy/KeyMap.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2005 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 LICENSE 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 @@ -18,11 +18,11 @@ #pragma once -#include "synergy/key_types.h" #include "base/String.h" #include "common/stdmap.h" #include "common/stdset.h" #include "common/stdvector.h" +#include "synergy/key_types.h" #ifdef TEST_ENV #include "gtest/gtest_prod.h" @@ -36,492 +36,481 @@ This class provides a keyboard mapping. */ class KeyMap { public: - KeyMap(); - virtual ~KeyMap(); + KeyMap(); + virtual ~KeyMap(); - //! KeyID synthesis info - /*! - This structure contains the information necessary to synthesize a - keystroke that generates a KeyID (stored elsewhere). \c m_sensitive - lists the modifiers that the key is affected by and must therefore - be in the correct state, which is listed in \c m_required. If the - key is mapped to a modifier, that modifier is in \c m_generates and - is not in \c m_sensitive. - */ - struct KeyItem { - public: - KeyID m_id {}; //!< KeyID - SInt32 m_group {}; //!< Group for key - KeyButton m_button {}; //!< Button to generate KeyID - KeyModifierMask m_required {}; //!< Modifiers required for KeyID - KeyModifierMask m_sensitive {}; //!< Modifiers key is sensitive to - KeyModifierMask m_generates {}; //!< Modifiers key is mapped to - bool m_dead {}; //!< \c true if this is a dead KeyID - bool m_lock {}; //!< \c true if this locks a modifier - UInt32 m_client {}; //!< Client data + //! KeyID synthesis info + /*! + This structure contains the information necessary to synthesize a + keystroke that generates a KeyID (stored elsewhere). \c m_sensitive + lists the modifiers that the key is affected by and must therefore + be in the correct state, which is listed in \c m_required. If the + key is mapped to a modifier, that modifier is in \c m_generates and + is not in \c m_sensitive. + */ + struct KeyItem { + public: + KeyID m_id{}; //!< KeyID + SInt32 m_group{}; //!< Group for key + KeyButton m_button{}; //!< Button to generate KeyID + KeyModifierMask m_required{}; //!< Modifiers required for KeyID + KeyModifierMask m_sensitive{}; //!< Modifiers key is sensitive to + KeyModifierMask m_generates{}; //!< Modifiers key is mapped to + bool m_dead{}; //!< \c true if this is a dead KeyID + bool m_lock{}; //!< \c true if this locks a modifier + UInt32 m_client{}; //!< Client data - public: - bool operator==(const KeyItem&) const; - }; + public: + bool operator==(const KeyItem &) const; + }; - //! The KeyButtons needed to synthesize a KeyID - /*! - An ordered list of \c KeyItems produces a particular KeyID. If - the KeyID can be synthesized directly then there is one entry in - the list. If dead keys are required then they're listed first. - A list is the minimal set of keystrokes necessary to synthesize - the KeyID, so it doesn't include no-ops. A list does not include - any modifier keys unless the KeyID is a modifier, in which case - it has exactly one KeyItem for the modifier itself. - */ - typedef std::vector KeyItemList; + //! The KeyButtons needed to synthesize a KeyID + /*! + An ordered list of \c KeyItems produces a particular KeyID. If + the KeyID can be synthesized directly then there is one entry in + the list. If dead keys are required then they're listed first. + A list is the minimal set of keystrokes necessary to synthesize + the KeyID, so it doesn't include no-ops. A list does not include + any modifier keys unless the KeyID is a modifier, in which case + it has exactly one KeyItem for the modifier itself. + */ + typedef std::vector KeyItemList; - //! A keystroke - class Keystroke { - public: - enum EType { - kButton, //!< Synthesize button - kGroup //!< Set new group - }; + //! A keystroke + class Keystroke { + public: + enum EType { + kButton, //!< Synthesize button + kGroup //!< Set new group + }; - Keystroke(KeyButton, bool press, bool repeat, UInt32 clientData); - Keystroke(SInt32 group, bool absolute, bool restore); + Keystroke(KeyButton, bool press, bool repeat, UInt32 clientData); + Keystroke(SInt32 group, bool absolute, bool restore); - public: - struct Button { - public: - KeyButton m_button {}; //!< Button to synthesize - bool m_press {}; //!< \c true iff press - bool m_repeat {}; //!< \c true iff for an autorepeat - UInt32 m_client{}; //!< Client data - }; - struct Group { - public: - SInt32 m_group {}; //!< Group/offset to change to/by - bool m_absolute {}; //!< \c true iff change to, else by - bool m_restore {}; //!< \c true iff for restoring state - }; - union Data { - public: - Button m_button; - Group m_group; - }; + public: + struct Button { + public: + KeyButton m_button{}; //!< Button to synthesize + bool m_press{}; //!< \c true iff press + bool m_repeat{}; //!< \c true iff for an autorepeat + UInt32 m_client{}; //!< Client data + }; + struct Group { + public: + SInt32 m_group{}; //!< Group/offset to change to/by + bool m_absolute{}; //!< \c true iff change to, else by + bool m_restore{}; //!< \c true iff for restoring state + }; + union Data { + public: + Button m_button; + Group m_group; + }; - EType m_type {}; - Data m_data {}; - }; + EType m_type{}; + Data m_data{}; + }; - //! A sequence of keystrokes - typedef std::vector Keystrokes; + //! A sequence of keystrokes + typedef std::vector Keystrokes; - //! A mapping of a modifier to keys for that modifier - typedef std::multimap ModifierToKeys; + //! A mapping of a modifier to keys for that modifier + typedef std::multimap ModifierToKeys; - //! A set of buttons - typedef std::map ButtonToKeyMap; + //! A set of buttons + typedef std::map ButtonToKeyMap; - //! Callback type for \c foreachKey - typedef void (*ForeachKeyCallback)(KeyID, SInt32 group, - KeyItem&, void* userData); + //! Callback type for \c foreachKey + typedef void (*ForeachKeyCallback)(KeyID, SInt32 group, KeyItem &, + void *userData); - //! @name manipulators - //@{ + //! @name manipulators + //@{ - //! Swap with another \c KeyMap - virtual void swap(KeyMap&); + //! Swap with another \c KeyMap + virtual void swap(KeyMap &); - //! Add a key entry - /*! - Adds \p item to the entries for the item's id and group. The - \c m_dead member is set automatically. - */ - void addKeyEntry(const KeyItem& item); + //! Add a key entry + /*! + Adds \p item to the entries for the item's id and group. The + \c m_dead member is set automatically. + */ + void addKeyEntry(const KeyItem &item); - //! Add an alias key entry - /*! - If \p targetID with the modifiers given by \p targetRequired and - \p targetSensitive is not available in group \p group then find an - entry for \p sourceID with modifiers given by \p sourceRequired and - \p sourceSensitive in any group with exactly one item and, if found, - add a new item just like it except using id \p targetID. This - effectively makes the \p sourceID an alias for \p targetID (i.e. we - can generate \p targetID using \p sourceID). - */ - void addKeyAliasEntry(KeyID targetID, SInt32 group, - KeyModifierMask targetRequired, - KeyModifierMask targetSensitive, - KeyID sourceID, - KeyModifierMask sourceRequired, - KeyModifierMask sourceSensitive); + //! Add an alias key entry + /*! + If \p targetID with the modifiers given by \p targetRequired and + \p targetSensitive is not available in group \p group then find an + entry for \p sourceID with modifiers given by \p sourceRequired and + \p sourceSensitive in any group with exactly one item and, if found, + add a new item just like it except using id \p targetID. This + effectively makes the \p sourceID an alias for \p targetID (i.e. we + can generate \p targetID using \p sourceID). + */ + void addKeyAliasEntry(KeyID targetID, SInt32 group, + KeyModifierMask targetRequired, + KeyModifierMask targetSensitive, KeyID sourceID, + KeyModifierMask sourceRequired, + KeyModifierMask sourceSensitive); - //! Add a key sequence entry - /*! - Adds the sequence of keys \p keys (\p numKeys elements long) to - synthesize key \p id in group \p group. This looks up in the - map each key in \p keys. If all are found then each key is - converted to the button for that key and the buttons are added - as the entry for \p id. If \p id is already in the map or at - least one key in \p keys is not in the map then nothing is added - and this returns \c false, otherwise it returns \c true. - */ - bool addKeyCombinationEntry(KeyID id, SInt32 group, - const KeyID* keys, UInt32 numKeys); + //! Add a key sequence entry + /*! + Adds the sequence of keys \p keys (\p numKeys elements long) to + synthesize key \p id in group \p group. This looks up in the + map each key in \p keys. If all are found then each key is + converted to the button for that key and the buttons are added + as the entry for \p id. If \p id is already in the map or at + least one key in \p keys is not in the map then nothing is added + and this returns \c false, otherwise it returns \c true. + */ + bool addKeyCombinationEntry(KeyID id, SInt32 group, const KeyID *keys, + UInt32 numKeys); - //! Enable composition across groups - /*! - If called then the keyboard map will allow switching between groups - during key composition. Not all systems allow that. - */ - void allowGroupSwitchDuringCompose(); + //! Enable composition across groups + /*! + If called then the keyboard map will allow switching between groups + during key composition. Not all systems allow that. + */ + void allowGroupSwitchDuringCompose(); - //! Add a half-duplex button - /*! - Records that button \p button is a half-duplex key. This is called - when translating the system's keyboard map. It's independent of the - half-duplex modifier calls. - */ - void addHalfDuplexButton(KeyButton button); + //! Add a half-duplex button + /*! + Records that button \p button is a half-duplex key. This is called + when translating the system's keyboard map. It's independent of the + half-duplex modifier calls. + */ + void addHalfDuplexButton(KeyButton button); - //! Remove all half-duplex modifiers - /*! - Removes all half-duplex modifiers. This is called to set user - configurable half-duplex settings. - */ - void clearHalfDuplexModifiers(); + //! Remove all half-duplex modifiers + /*! + Removes all half-duplex modifiers. This is called to set user + configurable half-duplex settings. + */ + void clearHalfDuplexModifiers(); - //! Add a half-duplex modifier - /*! - Records that modifier key \p key is half-duplex. This is called to - set user configurable half-duplex settings. - */ - virtual void addHalfDuplexModifier(KeyID key); + //! Add a half-duplex modifier + /*! + Records that modifier key \p key is half-duplex. This is called to + set user configurable half-duplex settings. + */ + virtual void addHalfDuplexModifier(KeyID key); - //! Finish adding entries - /*! - Called after adding entries, this does some internal housekeeping. - */ - virtual void finish(); + //! Finish adding entries + /*! + Called after adding entries, this does some internal housekeeping. + */ + virtual void finish(); - //! Iterate over all added keys items - /*! - Calls \p cb for every key item. - */ - virtual void foreachKey(ForeachKeyCallback cb, void* userData); + //! Iterate over all added keys items + /*! + Calls \p cb for every key item. + */ + virtual void foreachKey(ForeachKeyCallback cb, void *userData); - //@} - //! @name accessors - //@{ + //@} + //! @name accessors + //@{ - //! Map key press/repeat to keystrokes. - /*! - Converts press/repeat of key \p id in group \p group with current - modifiers as given in \p currentState and the desired modifiers in - \p desiredMask into the keystrokes necessary to synthesize that key - event in \p keys. It returns the \c KeyItem of the key being - pressed/repeated, or NULL if the key cannot be mapped. - */ - virtual const KeyItem* mapKey(Keystrokes& keys, KeyID id, SInt32 group, - ModifierToKeys& activeModifiers, - KeyModifierMask& currentState, - KeyModifierMask desiredMask, - bool isAutoRepeat, const String& lang) const; + //! Map key press/repeat to keystrokes. + /*! + Converts press/repeat of key \p id in group \p group with current + modifiers as given in \p currentState and the desired modifiers in + \p desiredMask into the keystrokes necessary to synthesize that key + event in \p keys. It returns the \c KeyItem of the key being + pressed/repeated, or NULL if the key cannot be mapped. + */ + virtual const KeyItem *mapKey(Keystrokes &keys, KeyID id, SInt32 group, + ModifierToKeys &activeModifiers, + KeyModifierMask ¤tState, + KeyModifierMask desiredMask, bool isAutoRepeat, + const String &lang) const; - void setLanguageData(std::vector layouts); + void setLanguageData(std::vector layouts); - //! Get number of groups - /*! - Returns the number of keyboard groups (independent layouts) in the map. - */ - SInt32 getNumGroups() const; + //! Get number of groups + /*! + Returns the number of keyboard groups (independent layouts) in the map. + */ + SInt32 getNumGroups() const; - //! Compute a group number - /*! - Returns the number of the group \p offset groups after group \p group. - */ - SInt32 getEffectiveGroup(SInt32 group, SInt32 offset) const; + //! Compute a group number + /*! + Returns the number of the group \p offset groups after group \p group. + */ + SInt32 getEffectiveGroup(SInt32 group, SInt32 offset) const; - //! Find key entry compatible with modifiers - /*! - Returns the \c KeyItemList for the first entry for \p id in group - \p group that is compatible with the given modifiers, or NULL - if there isn't one. A button list is compatible with a modifiers - if it is either insensitive to all modifiers in \p sensitive or - it requires the modifiers to be in the state indicated by \p required - for every modifier indicated by \p sensitive. - */ - const KeyItemList* findCompatibleKey(KeyID id, SInt32 group, - KeyModifierMask required, - KeyModifierMask sensitive) const; + //! Find key entry compatible with modifiers + /*! + Returns the \c KeyItemList for the first entry for \p id in group + \p group that is compatible with the given modifiers, or NULL + if there isn't one. A button list is compatible with a modifiers + if it is either insensitive to all modifiers in \p sensitive or + it requires the modifiers to be in the state indicated by \p required + for every modifier indicated by \p sensitive. + */ + const KeyItemList *findCompatibleKey(KeyID id, SInt32 group, + KeyModifierMask required, + KeyModifierMask sensitive) const; - //! Test if modifier is half-duplex - /*! - Returns \c true iff modifier key \p key or button \p button is - half-duplex. - */ - virtual bool isHalfDuplex(KeyID key, KeyButton button) const; + //! Test if modifier is half-duplex + /*! + Returns \c true iff modifier key \p key or button \p button is + half-duplex. + */ + virtual bool isHalfDuplex(KeyID key, KeyButton button) const; - //! Test if modifiers indicate a command - /*! - Returns \c true iff the modifiers in \p mask contain any command - modifiers. A command modifier is used for keyboard shortcuts and - hotkeys, Rather than trying to synthesize a character, a command - is trying to synthesize a particular set of buttons. So it's not - important to match the shift or AltGr state to achieve a character - but it is important to match the modifier state exactly. - */ - bool isCommand(KeyModifierMask mask) const; + //! Test if modifiers indicate a command + /*! + Returns \c true iff the modifiers in \p mask contain any command + modifiers. A command modifier is used for keyboard shortcuts and + hotkeys, Rather than trying to synthesize a character, a command + is trying to synthesize a particular set of buttons. So it's not + important to match the shift or AltGr state to achieve a character + but it is important to match the modifier state exactly. + */ + bool isCommand(KeyModifierMask mask) const; - // Get the modifiers that indicate a command - /*! - Returns the modifiers that when combined with other keys indicate - a command (e.g. shortcut or hotkey). - */ - KeyModifierMask getCommandModifiers() const; + // Get the modifiers that indicate a command + /*! + Returns the modifiers that when combined with other keys indicate + a command (e.g. shortcut or hotkey). + */ + KeyModifierMask getCommandModifiers() const; - //! Get buttons from modifier map - /*! - Put all the keys in \p modifiers into \p keys. - */ - static void collectButtons(const ModifierToKeys& modifiers, - ButtonToKeyMap& keys); + //! Get buttons from modifier map + /*! + Put all the keys in \p modifiers into \p keys. + */ + static void collectButtons(const ModifierToKeys &modifiers, + ButtonToKeyMap &keys); - //! Set modifier key state - /*! - Sets the modifier key state (\c m_generates and \c m_lock) in \p item - based on the \c m_id in \p item. - */ - static void initModifierKey(KeyItem& item); + //! Set modifier key state + /*! + Sets the modifier key state (\c m_generates and \c m_lock) in \p item + based on the \c m_id in \p item. + */ + static void initModifierKey(KeyItem &item); - //! Test for a dead key - /*! - Returns \c true if \p key is a dead key. - */ - static bool isDeadKey(KeyID key); + //! Test for a dead key + /*! + Returns \c true if \p key is a dead key. + */ + static bool isDeadKey(KeyID key); - //! Get corresponding dead key - /*! - Returns the dead key corresponding to \p key if one exists, otherwise - return \c kKeyNone. This returns \p key if it's already a dead key. - */ - static KeyID getDeadKey(KeyID key); + //! Get corresponding dead key + /*! + Returns the dead key corresponding to \p key if one exists, otherwise + return \c kKeyNone. This returns \p key if it's already a dead key. + */ + static KeyID getDeadKey(KeyID key); - //! Get string for a key and modifier mask - /*! - Converts a key and modifier mask into a string representing the - combination. - */ - static String formatKey(KeyID key, KeyModifierMask); + //! Get string for a key and modifier mask + /*! + Converts a key and modifier mask into a string representing the + combination. + */ + static String formatKey(KeyID key, KeyModifierMask); - //! Parse a string into a key - /*! - Converts a string into a key. Returns \c true on success and \c false - if the string cannot be parsed. - */ - static bool parseKey(const String&, KeyID&); + //! Parse a string into a key + /*! + Converts a string into a key. Returns \c true on success and \c false + if the string cannot be parsed. + */ + static bool parseKey(const String &, KeyID &); - //! Parse a string into a modifier mask - /*! - Converts a string into a modifier mask. Returns \c true on success - and \c false if the string cannot be parsed. The modifiers plus any - remaining leading and trailing whitespace is stripped from the input - string. - */ - static bool parseModifiers(String&, KeyModifierMask&); + //! Parse a string into a modifier mask + /*! + Converts a string into a modifier mask. Returns \c true on success + and \c false if the string cannot be parsed. The modifiers plus any + remaining leading and trailing whitespace is stripped from the input + string. + */ + static bool parseModifiers(String &, KeyModifierMask &); - //@} + //@} #ifdef TEST_ENV private: - FRIEND_TEST(KeyMapTests, - findBestKey_requiredDown_matchExactFirstItem); - FRIEND_TEST(KeyMapTests, - findBestKey_requiredAndExtraSensitiveDown_matchExactFirstItem); - FRIEND_TEST(KeyMapTests, - findBestKey_requiredAndExtraSensitiveDown_matchExactSecondItem); - FRIEND_TEST(KeyMapTests, - findBestKey_extraSensitiveDown_matchExactSecondItem); - FRIEND_TEST(KeyMapTests, - findBestKey_noRequiredDown_matchOneRequiredChangeItem); - FRIEND_TEST(KeyMapTests, - findBestKey_onlyOneRequiredDown_matchTwoRequiredChangesItem); - FRIEND_TEST(KeyMapTests, findBestKey_noRequiredDown_cannotMatch); + FRIEND_TEST(KeyMapTests, findBestKey_requiredDown_matchExactFirstItem); + FRIEND_TEST(KeyMapTests, + findBestKey_requiredAndExtraSensitiveDown_matchExactFirstItem); + FRIEND_TEST(KeyMapTests, + findBestKey_requiredAndExtraSensitiveDown_matchExactSecondItem); + FRIEND_TEST(KeyMapTests, findBestKey_extraSensitiveDown_matchExactSecondItem); + FRIEND_TEST(KeyMapTests, + findBestKey_noRequiredDown_matchOneRequiredChangeItem); + FRIEND_TEST(KeyMapTests, + findBestKey_onlyOneRequiredDown_matchTwoRequiredChangesItem); + FRIEND_TEST(KeyMapTests, findBestKey_noRequiredDown_cannotMatch); #endif private: - //! Ways to synthesize a key - enum EKeystroke { - kKeystrokePress, //!< Synthesize a press - kKeystrokeRelease, //!< Synthesize a release - kKeystrokeRepeat, //!< Synthesize an autorepeat - kKeystrokeClick, //!< Synthesize a press and release - kKeystrokeModify, //!< Synthesize pressing a modifier - kKeystrokeUnmodify //!< Synthesize releasing a modifier - }; - - // A list of ways to synthesize a KeyID - typedef std::vector KeyEntryList; + //! Ways to synthesize a key + enum EKeystroke { + kKeystrokePress, //!< Synthesize a press + kKeystrokeRelease, //!< Synthesize a release + kKeystrokeRepeat, //!< Synthesize an autorepeat + kKeystrokeClick, //!< Synthesize a press and release + kKeystrokeModify, //!< Synthesize pressing a modifier + kKeystrokeUnmodify //!< Synthesize releasing a modifier + }; - // computes the number of groups - SInt32 findNumGroups() const; + // A list of ways to synthesize a KeyID + typedef std::vector KeyEntryList; - // computes the map of modifiers to the keys that generate the modifiers - void setModifierKeys(); + // computes the number of groups + SInt32 findNumGroups() const; - // maps a command key. a command key is a keyboard shortcut and we're - // trying to synthesize a button press with an exact sets of modifiers, - // not trying to synthesize a character. so we just need to find the - // right button and synthesize the requested modifiers without regard - // to what character they would synthesize. we disallow multikey - // entries since they don't make sense as hotkeys. - const KeyItem* mapCommandKey(Keystrokes& keys, - KeyID id, SInt32 group, - ModifierToKeys& activeModifiers, - KeyModifierMask& currentState, - KeyModifierMask desiredMask, - bool isAutoRepeat, - const String& lang) const; + // computes the map of modifiers to the keys that generate the modifiers + void setModifierKeys(); - // maps a character key. a character key is trying to synthesize a - // particular KeyID and isn't entirely concerned with the modifiers - // used to do it. - const KeyItem* mapCharacterKey(Keystrokes& keys, - KeyID id, SInt32 group, - ModifierToKeys& activeModifiers, - KeyModifierMask& currentState, - KeyModifierMask desiredMask, - bool isAutoRepeat, - const String& lang) const; + // maps a command key. a command key is a keyboard shortcut and we're + // trying to synthesize a button press with an exact sets of modifiers, + // not trying to synthesize a character. so we just need to find the + // right button and synthesize the requested modifiers without regard + // to what character they would synthesize. we disallow multikey + // entries since they don't make sense as hotkeys. + const KeyItem *mapCommandKey(Keystrokes &keys, KeyID id, SInt32 group, + ModifierToKeys &activeModifiers, + KeyModifierMask ¤tState, + KeyModifierMask desiredMask, bool isAutoRepeat, + const String &lang) const; - // maps a modifier key - const KeyItem* mapModifierKey(Keystrokes& keys, - KeyID id, SInt32 group, - ModifierToKeys& activeModifiers, - KeyModifierMask& currentState, - KeyModifierMask desiredMask, - bool isAutoRepeat, - const String& lang) const; + // maps a character key. a character key is trying to synthesize a + // particular KeyID and isn't entirely concerned with the modifiers + // used to do it. + const KeyItem *mapCharacterKey(Keystrokes &keys, KeyID id, SInt32 group, + ModifierToKeys &activeModifiers, + KeyModifierMask ¤tState, + KeyModifierMask desiredMask, bool isAutoRepeat, + const String &lang) const; - // returns the index into \p entryList of the KeyItemList requiring - // the fewest modifier changes between \p currentState and - // \p desiredState. - SInt32 findBestKey(const KeyEntryList& entryList, KeyModifierMask desiredState) const; + // maps a modifier key + const KeyItem *mapModifierKey(Keystrokes &keys, KeyID id, SInt32 group, + ModifierToKeys &activeModifiers, + KeyModifierMask ¤tState, + KeyModifierMask desiredMask, bool isAutoRepeat, + const String &lang) const; - // gets the \c KeyItem used to synthesize the modifier who's bit is - // given by \p modifierBit in group \p group and does not synthesize - // the key \p button. - const KeyItem* keyForModifier(KeyButton button, SInt32 group, - SInt32 modifierBit) const; + // returns the index into \p entryList of the KeyItemList requiring + // the fewest modifier changes between \p currentState and + // \p desiredState. + SInt32 findBestKey(const KeyEntryList &entryList, + KeyModifierMask desiredState) const; - // fills \p keystrokes with the keys to synthesize the key in - // \p keyItem taking the modifiers into account. returns \c true - // iff successful and sets \p currentState to the - // resulting modifier state. - bool keysForKeyItem(const KeyItem& keyItem, - SInt32& group, - ModifierToKeys& activeModifiers, - KeyModifierMask& currentState, - KeyModifierMask desiredState, - KeyModifierMask overrideModifiers, - bool isAutoRepeat, - Keystrokes& keystrokes, - const String& lang) const; + // gets the \c KeyItem used to synthesize the modifier who's bit is + // given by \p modifierBit in group \p group and does not synthesize + // the key \p button. + const KeyItem *keyForModifier(KeyButton button, SInt32 group, + SInt32 modifierBit) const; - // fills \p keystrokes with the keys to synthesize the modifiers - // in \p desiredModifiers from the active modifiers listed in - // \p activeModifiers not including the key in \p keyItem. - // returns \c true iff successful. - bool keysToRestoreModifiers(const KeyItem& keyItem, - SInt32 group, - ModifierToKeys& activeModifiers, - KeyModifierMask& currentState, - const ModifierToKeys& desiredModifiers, - Keystrokes& keystrokes) const; + // fills \p keystrokes with the keys to synthesize the key in + // \p keyItem taking the modifiers into account. returns \c true + // iff successful and sets \p currentState to the + // resulting modifier state. + bool keysForKeyItem(const KeyItem &keyItem, SInt32 &group, + ModifierToKeys &activeModifiers, + KeyModifierMask ¤tState, + KeyModifierMask desiredState, + KeyModifierMask overrideModifiers, bool isAutoRepeat, + Keystrokes &keystrokes, const String &lang) const; - // fills \p keystrokes and \p undo with the keys to change the - // current modifier state in \p currentState to match the state in - // \p requiredState for each modifier indicated in \p sensitiveMask. - // returns \c true iff successful and sets \p currentState to the - // resulting modifier state. - bool keysForModifierState(KeyButton button, SInt32 group, - ModifierToKeys& activeModifiers, - KeyModifierMask& currentState, - KeyModifierMask requiredState, - KeyModifierMask sensitiveMask, - KeyModifierMask notRequiredMask, - Keystrokes& keystrokes) const; + // fills \p keystrokes with the keys to synthesize the modifiers + // in \p desiredModifiers from the active modifiers listed in + // \p activeModifiers not including the key in \p keyItem. + // returns \c true iff successful. + bool keysToRestoreModifiers(const KeyItem &keyItem, SInt32 group, + ModifierToKeys &activeModifiers, + KeyModifierMask ¤tState, + const ModifierToKeys &desiredModifiers, + Keystrokes &keystrokes) const; - // Adds keystrokes to synthesize key \p keyItem in mode \p type to - // \p keystrokes and to undo the synthesis to \p undo. - void addKeystrokes(EKeystroke type, - const KeyItem& keyItem, - ModifierToKeys& activeModifiers, - KeyModifierMask& currentState, - Keystrokes& keystrokes) const; + // fills \p keystrokes and \p undo with the keys to change the + // current modifier state in \p currentState to match the state in + // \p requiredState for each modifier indicated in \p sensitiveMask. + // returns \c true iff successful and sets \p currentState to the + // resulting modifier state. + bool keysForModifierState(KeyButton button, SInt32 group, + ModifierToKeys &activeModifiers, + KeyModifierMask ¤tState, + KeyModifierMask requiredState, + KeyModifierMask sensitiveMask, + KeyModifierMask notRequiredMask, + Keystrokes &keystrokes) const; - // Returns the number of modifiers indicated in \p state. - static SInt32 getNumModifiers(KeyModifierMask state); + // Adds keystrokes to synthesize key \p keyItem in mode \p type to + // \p keystrokes and to undo the synthesis to \p undo. + void addKeystrokes(EKeystroke type, const KeyItem &keyItem, + ModifierToKeys &activeModifiers, + KeyModifierMask ¤tState, + Keystrokes &keystrokes) const; - // Initialize key name/id maps - static void initKeyNameMaps(); + // Returns the number of modifiers indicated in \p state. + static SInt32 getNumModifiers(KeyModifierMask state); - // Ways to synthesize a KeyID over multiple keyboard groups - typedef std::vector KeyGroupTable; + // Initialize key name/id maps + static void initKeyNameMaps(); - void addGroupToKeystroke(Keystrokes& keys, SInt32& group, const String& lang) const; + // Ways to synthesize a KeyID over multiple keyboard groups + typedef std::vector KeyGroupTable; - SInt32 getLanguageGroupID(SInt32 group, const String& lang) const; - const KeyItemList* getKeyItemList(const KeyGroupTable& keyGroupTable, SInt32 group, KeyModifierMask desiredMask) const; + void addGroupToKeystroke(Keystrokes &keys, SInt32 &group, + const String &lang) const; - // not implemented - KeyMap(const KeyMap&); - KeyMap& operator=(const KeyMap&); + SInt32 getLanguageGroupID(SInt32 group, const String &lang) const; + const KeyItemList *getKeyItemList(const KeyGroupTable &keyGroupTable, + SInt32 group, + KeyModifierMask desiredMask) const; + + // not implemented + KeyMap(const KeyMap &); + KeyMap &operator=(const KeyMap &); private: - // Table of KeyID to ways to synthesize that KeyID - typedef std::map KeyIDMap; + // Table of KeyID to ways to synthesize that KeyID + typedef std::map KeyIDMap; - // List of KeyItems that generate a particular modifier - typedef std::vector ModifierKeyItemList; + // List of KeyItems that generate a particular modifier + typedef std::vector ModifierKeyItemList; - // Map a modifier to the KeyItems that synthesize that modifier - typedef std::vector ModifierToKeyTable; + // Map a modifier to the KeyItems that synthesize that modifier + typedef std::vector ModifierToKeyTable; - // A set of keys - typedef std::set KeySet; + // A set of keys + typedef std::set KeySet; - // A set of buttons - typedef std::set KeyButtonSet; + // A set of buttons + typedef std::set KeyButtonSet; - // Key maps for parsing/formatting - typedef std::map NameToKeyMap; - typedef std::map NameToModifierMap; - typedef std::map KeyToNameMap; - typedef std::map ModifierToNameMap; + // Key maps for parsing/formatting + typedef std::map NameToKeyMap; + typedef std::map + NameToModifierMap; + typedef std::map KeyToNameMap; + typedef std::map ModifierToNameMap; - // KeyID info - KeyIDMap m_keyIDMap; - SInt32 m_numGroups; - ModifierToKeyTable m_modifierKeys; + // KeyID info + KeyIDMap m_keyIDMap; + SInt32 m_numGroups; + ModifierToKeyTable m_modifierKeys; - // composition info - bool m_composeAcrossGroups; + // composition info + bool m_composeAcrossGroups; - // half-duplex info - KeyButtonSet m_halfDuplex; // half-duplex set by synergy - KeySet m_halfDuplexMods; // half-duplex set by user + // half-duplex info + KeyButtonSet m_halfDuplex; // half-duplex set by synergy + KeySet m_halfDuplexMods; // half-duplex set by user - // dummy KeyItem for changing modifiers - KeyItem m_modifierKeyItem; + // dummy KeyItem for changing modifiers + KeyItem m_modifierKeyItem; - //Language sync data - std::vector m_keyboardLayouts; + // Language sync data + std::vector m_keyboardLayouts; - // parsing/formatting tables - static NameToKeyMap* s_nameToKeyMap; - static NameToModifierMap* s_nameToModifierMap; - static KeyToNameMap* s_keyToNameMap; - static ModifierToNameMap* s_modifierToNameMap; + // parsing/formatting tables + static NameToKeyMap *s_nameToKeyMap; + static NameToModifierMap *s_nameToModifierMap; + static KeyToNameMap *s_keyToNameMap; + static ModifierToNameMap *s_modifierToNameMap; }; -} +} // namespace synergy diff --git a/src/lib/synergy/KeyState.cpp b/src/lib/synergy/KeyState.cpp index 9774eaa49..1cabe9c0c 100644 --- a/src/lib/synergy/KeyState.cpp +++ b/src/lib/synergy/KeyState.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 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 LICENSE 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 @@ -21,8 +21,8 @@ #include "synergy/ClientApp.h" #include "synergy/ClientArgs.h" -#include #include +#include #include #include @@ -235,710 +235,619 @@ static const KeyID s_decomposeTable[] = { // Compose key sequences 0x00c6, kKeyCompose, 0x0041, 0x0045, 0, // AE, A, E - 0x00c1, kKeyCompose, 0x0041, 0x0027, 0, // Aacute, A, apostrophe - 0x00c2, kKeyCompose, 0x0041, 0x0053, 0, // Acircumflex, A, asciicircum - 0x00c3, kKeyCompose, 0x0041, 0x0022, 0, // Adiaeresis, A, quotedbl - 0x00c0, kKeyCompose, 0x0041, 0x0060, 0, // Agrave, A, grave - 0x00c5, kKeyCompose, 0x0041, 0x002a, 0, // Aring, A, asterisk - 0x00c3, kKeyCompose, 0x0041, 0x007e, 0, // Atilde, A, asciitilde - 0x00c7, kKeyCompose, 0x0043, 0x002c, 0, // Ccedilla, C, comma - 0x00d0, kKeyCompose, 0x0044, 0x002d, 0, // ETH, D, minus - 0x00c9, kKeyCompose, 0x0045, 0x0027, 0, // Eacute, E, apostrophe - 0x00ca, kKeyCompose, 0x0045, 0x0053, 0, // Ecircumflex, E, asciicircum - 0x00cb, kKeyCompose, 0x0045, 0x0022, 0, // Ediaeresis, E, quotedbl - 0x00c8, kKeyCompose, 0x0045, 0x0060, 0, // Egrave, E, grave - 0x00cd, kKeyCompose, 0x0049, 0x0027, 0, // Iacute, I, apostrophe - 0x00ce, kKeyCompose, 0x0049, 0x0053, 0, // Icircumflex, I, asciicircum - 0x00cf, kKeyCompose, 0x0049, 0x0022, 0, // Idiaeresis, I, quotedbl - 0x00cc, kKeyCompose, 0x0049, 0x0060, 0, // Igrave, I, grave - 0x00d1, kKeyCompose, 0x004e, 0x007e, 0, // Ntilde, N, asciitilde - 0x00d3, kKeyCompose, 0x004f, 0x0027, 0, // Oacute, O, apostrophe - 0x00d4, kKeyCompose, 0x004f, 0x0053, 0, // Ocircumflex, O, asciicircum - 0x00d6, kKeyCompose, 0x004f, 0x0022, 0, // Odiaeresis, O, quotedbl - 0x00d2, kKeyCompose, 0x004f, 0x0060, 0, // Ograve, O, grave - 0x00d8, kKeyCompose, 0x004f, 0x002f, 0, // Ooblique, O, slash - 0x00d5, kKeyCompose, 0x004f, 0x007e, 0, // Otilde, O, asciitilde + 0x00c1, kKeyCompose, 0x0041, 0x0027, 0, // Aacute, A, apostrophe + 0x00c2, kKeyCompose, 0x0041, 0x0053, 0, // Acircumflex, A, asciicircum + 0x00c3, kKeyCompose, 0x0041, 0x0022, 0, // Adiaeresis, A, quotedbl + 0x00c0, kKeyCompose, 0x0041, 0x0060, 0, // Agrave, A, grave + 0x00c5, kKeyCompose, 0x0041, 0x002a, 0, // Aring, A, asterisk + 0x00c3, kKeyCompose, 0x0041, 0x007e, 0, // Atilde, A, asciitilde + 0x00c7, kKeyCompose, 0x0043, 0x002c, 0, // Ccedilla, C, comma + 0x00d0, kKeyCompose, 0x0044, 0x002d, 0, // ETH, D, minus + 0x00c9, kKeyCompose, 0x0045, 0x0027, 0, // Eacute, E, apostrophe + 0x00ca, kKeyCompose, 0x0045, 0x0053, 0, // Ecircumflex, E, asciicircum + 0x00cb, kKeyCompose, 0x0045, 0x0022, 0, // Ediaeresis, E, quotedbl + 0x00c8, kKeyCompose, 0x0045, 0x0060, 0, // Egrave, E, grave + 0x00cd, kKeyCompose, 0x0049, 0x0027, 0, // Iacute, I, apostrophe + 0x00ce, kKeyCompose, 0x0049, 0x0053, 0, // Icircumflex, I, asciicircum + 0x00cf, kKeyCompose, 0x0049, 0x0022, 0, // Idiaeresis, I, quotedbl + 0x00cc, kKeyCompose, 0x0049, 0x0060, 0, // Igrave, I, grave + 0x00d1, kKeyCompose, 0x004e, 0x007e, 0, // Ntilde, N, asciitilde + 0x00d3, kKeyCompose, 0x004f, 0x0027, 0, // Oacute, O, apostrophe + 0x00d4, kKeyCompose, 0x004f, 0x0053, 0, // Ocircumflex, O, asciicircum + 0x00d6, kKeyCompose, 0x004f, 0x0022, 0, // Odiaeresis, O, quotedbl + 0x00d2, kKeyCompose, 0x004f, 0x0060, 0, // Ograve, O, grave + 0x00d8, kKeyCompose, 0x004f, 0x002f, 0, // Ooblique, O, slash + 0x00d5, kKeyCompose, 0x004f, 0x007e, 0, // Otilde, O, asciitilde 0x00de, kKeyCompose, 0x0054, 0x0048, 0, // THORN, T, H - 0x00da, kKeyCompose, 0x0055, 0x0027, 0, // Uacute, U, apostrophe - 0x00db, kKeyCompose, 0x0055, 0x0053, 0, // Ucircumflex, U, asciicircum - 0x00dc, kKeyCompose, 0x0055, 0x0022, 0, // Udiaeresis, U, quotedbl - 0x00d9, kKeyCompose, 0x0055, 0x0060, 0, // Ugrave, U, grave - 0x00dd, kKeyCompose, 0x0059, 0x0027, 0, // Yacute, Y, apostrophe - 0x00e1, kKeyCompose, 0x0061, 0x0027, 0, // aacute, a, apostrophe - 0x00e2, kKeyCompose, 0x0061, 0x0053, 0, // acircumflex, a, asciicircum - 0x00b4, kKeyCompose, 0x0027, 0x0027, 0, // acute, apostrophe, apostrophe - 0x00e4, kKeyCompose, 0x0061, 0x0022, 0, // adiaeresis, a, quotedbl + 0x00da, kKeyCompose, 0x0055, 0x0027, 0, // Uacute, U, apostrophe + 0x00db, kKeyCompose, 0x0055, 0x0053, 0, // Ucircumflex, U, asciicircum + 0x00dc, kKeyCompose, 0x0055, 0x0022, 0, // Udiaeresis, U, quotedbl + 0x00d9, kKeyCompose, 0x0055, 0x0060, 0, // Ugrave, U, grave + 0x00dd, kKeyCompose, 0x0059, 0x0027, 0, // Yacute, Y, apostrophe + 0x00e1, kKeyCompose, 0x0061, 0x0027, 0, // aacute, a, apostrophe + 0x00e2, kKeyCompose, 0x0061, 0x0053, 0, // acircumflex, a, asciicircum + 0x00b4, kKeyCompose, 0x0027, 0x0027, + 0, // acute, apostrophe, apostrophe + 0x00e4, kKeyCompose, 0x0061, 0x0022, 0, // adiaeresis, a, quotedbl 0x00e6, kKeyCompose, 0x0061, 0x0065, 0, // ae, a, e - 0x00e0, kKeyCompose, 0x0061, 0x0060, 0, // agrave, a, grave - 0x00e5, kKeyCompose, 0x0061, 0x002a, 0, // aring, a, asterisk + 0x00e0, kKeyCompose, 0x0061, 0x0060, 0, // agrave, a, grave + 0x00e5, kKeyCompose, 0x0061, 0x002a, 0, // aring, a, asterisk 0x0040, kKeyCompose, 0x0041, 0x0054, 0, // at, A, T - 0x00e3, kKeyCompose, 0x0061, 0x007e, 0, // atilde, a, asciitilde - 0x005c, kKeyCompose, 0x002f, 0x002f, 0, // backslash, slash, slash + 0x00e3, kKeyCompose, 0x0061, 0x007e, 0, // atilde, a, asciitilde + 0x005c, kKeyCompose, 0x002f, 0x002f, 0, // backslash, slash, slash 0x007c, kKeyCompose, 0x004c, 0x0056, 0, // bar, L, V - 0x007b, kKeyCompose, 0x0028, 0x002d, 0, // braceleft, parenleft, minus + 0x007b, kKeyCompose, 0x0028, 0x002d, 0, // braceleft, parenleft, minus 0x007d, kKeyCompose, 0x0029, 0x002d, 0, // braceright, parenright, minus - 0x005b, kKeyCompose, 0x0028, 0x0028, 0, // bracketleft, parenleft, parenleft - 0x005d, kKeyCompose, 0x0029, 0x0029, 0, // bracketright, parenright, parenright + 0x005b, kKeyCompose, 0x0028, 0x0028, + 0, // bracketleft, parenleft, parenleft + 0x005d, kKeyCompose, 0x0029, 0x0029, + 0, // bracketright, parenright, parenright 0x00a6, kKeyCompose, 0x0042, 0x0056, 0, // brokenbar, B, V - 0x00e7, kKeyCompose, 0x0063, 0x002c, 0, // ccedilla, c, comma - 0x00b8, kKeyCompose, 0x002c, 0x002c, 0, // cedilla, comma, comma - 0x00a2, kKeyCompose, 0x0063, 0x002f, 0, // cent, c, slash + 0x00e7, kKeyCompose, 0x0063, 0x002c, 0, // ccedilla, c, comma + 0x00b8, kKeyCompose, 0x002c, 0x002c, 0, // cedilla, comma, comma + 0x00a2, kKeyCompose, 0x0063, 0x002f, 0, // cent, c, slash 0x00a9, kKeyCompose, 0x0028, 0x0063, 0, // copyright, parenleft, c 0x00a4, kKeyCompose, 0x006f, 0x0078, 0, // currency, o, x - 0x00b0, kKeyCompose, 0x0030, 0x0053, 0, // degree, 0, asciicircum - 0x00a8, kKeyCompose, 0x0022, 0x0022, 0, // diaeresis, quotedbl, quotedbl - 0x00f7, kKeyCompose, 0x003a, 0x002d, 0, // division, colon, minus - 0x00e9, kKeyCompose, 0x0065, 0x0027, 0, // eacute, e, apostrophe - 0x00ea, kKeyCompose, 0x0065, 0x0053, 0, // ecircumflex, e, asciicircum - 0x00eb, kKeyCompose, 0x0065, 0x0022, 0, // ediaeresis, e, quotedbl - 0x00e8, kKeyCompose, 0x0065, 0x0060, 0, // egrave, e, grave - 0x00f0, kKeyCompose, 0x0064, 0x002d, 0, // eth, d, minus - 0x00a1, kKeyCompose, 0x0021, 0x0021, 0, // exclamdown, exclam, exclam + 0x00b0, kKeyCompose, 0x0030, 0x0053, 0, // degree, 0, asciicircum + 0x00a8, kKeyCompose, 0x0022, 0x0022, + 0, // diaeresis, quotedbl, quotedbl + 0x00f7, kKeyCompose, 0x003a, 0x002d, 0, // division, colon, minus + 0x00e9, kKeyCompose, 0x0065, 0x0027, 0, // eacute, e, apostrophe + 0x00ea, kKeyCompose, 0x0065, 0x0053, 0, // ecircumflex, e, asciicircum + 0x00eb, kKeyCompose, 0x0065, 0x0022, 0, // ediaeresis, e, quotedbl + 0x00e8, kKeyCompose, 0x0065, 0x0060, 0, // egrave, e, grave + 0x00f0, kKeyCompose, 0x0064, 0x002d, 0, // eth, d, minus + 0x00a1, kKeyCompose, 0x0021, 0x0021, 0, // exclamdown, exclam, exclam 0x00ab, kKeyCompose, 0x003c, 0x003c, 0, // guillemotleft, less, less - 0x00bb, kKeyCompose, 0x003e, 0x003e, 0, // guillemotright, greater, greater + 0x00bb, kKeyCompose, 0x003e, 0x003e, 0, // guillemotright, greater, greater 0x0023, kKeyCompose, 0x002b, 0x002b, 0, // numbersign, plus, plus - 0x00ad, kKeyCompose, 0x002d, 0x002d, 0, // hyphen, minus, minus - 0x00ed, kKeyCompose, 0x0069, 0x0027, 0, // iacute, i, apostrophe - 0x00ee, kKeyCompose, 0x0069, 0x0053, 0, // icircumflex, i, asciicircum - 0x00ef, kKeyCompose, 0x0069, 0x0022, 0, // idiaeresis, i, quotedbl - 0x00ec, kKeyCompose, 0x0069, 0x0060, 0, // igrave, i, grave - 0x00af, kKeyCompose, 0x002d, 0x0053, 0, // macron, minus, asciicircum - 0x00ba, kKeyCompose, 0x006f, 0x005f, 0, // masculine, o, underscore - 0x00b5, kKeyCompose, 0x0075, 0x002f, 0, // mu, u, slash + 0x00ad, kKeyCompose, 0x002d, 0x002d, 0, // hyphen, minus, minus + 0x00ed, kKeyCompose, 0x0069, 0x0027, 0, // iacute, i, apostrophe + 0x00ee, kKeyCompose, 0x0069, 0x0053, 0, // icircumflex, i, asciicircum + 0x00ef, kKeyCompose, 0x0069, 0x0022, 0, // idiaeresis, i, quotedbl + 0x00ec, kKeyCompose, 0x0069, 0x0060, 0, // igrave, i, grave + 0x00af, kKeyCompose, 0x002d, 0x0053, + 0, // macron, minus, asciicircum + 0x00ba, kKeyCompose, 0x006f, 0x005f, 0, // masculine, o, underscore + 0x00b5, kKeyCompose, 0x0075, 0x002f, 0, // mu, u, slash 0x00d7, kKeyCompose, 0x0078, 0x0078, 0, // multiply, x, x - 0x00a0, kKeyCompose, 0x0020, 0x0020, 0, // nobreakspace, space, space - 0x00ac, kKeyCompose, 0x002c, 0x002d, 0, // notsign, comma, minus - 0x00f1, kKeyCompose, 0x006e, 0x007e, 0, // ntilde, n, asciitilde - 0x00f3, kKeyCompose, 0x006f, 0x0027, 0, // oacute, o, apostrophe - 0x00f4, kKeyCompose, 0x006f, 0x0053, 0, // ocircumflex, o, asciicircum - 0x00f6, kKeyCompose, 0x006f, 0x0022, 0, // odiaeresis, o, quotedbl - 0x00f2, kKeyCompose, 0x006f, 0x0060, 0, // ograve, o, grave + 0x00a0, kKeyCompose, 0x0020, 0x0020, 0, // nobreakspace, space, space + 0x00ac, kKeyCompose, 0x002c, 0x002d, 0, // notsign, comma, minus + 0x00f1, kKeyCompose, 0x006e, 0x007e, 0, // ntilde, n, asciitilde + 0x00f3, kKeyCompose, 0x006f, 0x0027, 0, // oacute, o, apostrophe + 0x00f4, kKeyCompose, 0x006f, 0x0053, 0, // ocircumflex, o, asciicircum + 0x00f6, kKeyCompose, 0x006f, 0x0022, 0, // odiaeresis, o, quotedbl + 0x00f2, kKeyCompose, 0x006f, 0x0060, 0, // ograve, o, grave 0x00bd, kKeyCompose, 0x0031, 0x0032, 0, // onehalf, 1, 2 0x00bc, kKeyCompose, 0x0031, 0x0034, 0, // onequarter, 1, 4 - 0x00b9, kKeyCompose, 0x0031, 0x0053, 0, // onesuperior, 1, asciicircum - 0x00aa, kKeyCompose, 0x0061, 0x005f, 0, // ordfeminine, a, underscore - 0x00f8, kKeyCompose, 0x006f, 0x002f, 0, // oslash, o, slash - 0x00f5, kKeyCompose, 0x006f, 0x007e, 0, // otilde, o, asciitilde - 0x00b6, kKeyCompose, 0x0070, 0x0021, 0, // paragraph, p, exclam - 0x00b7, kKeyCompose, 0x002e, 0x002e, 0, // periodcentered, period, period - 0x00b1, kKeyCompose, 0x002b, 0x002d, 0, // plusminus, plus, minus - 0x00bf, kKeyCompose, 0x003f, 0x003f, 0, // questiondown, question, question + 0x00b9, kKeyCompose, 0x0031, 0x0053, 0, // onesuperior, 1, asciicircum + 0x00aa, kKeyCompose, 0x0061, 0x005f, 0, // ordfeminine, a, underscore + 0x00f8, kKeyCompose, 0x006f, 0x002f, 0, // oslash, o, slash + 0x00f5, kKeyCompose, 0x006f, 0x007e, 0, // otilde, o, asciitilde + 0x00b6, kKeyCompose, 0x0070, 0x0021, 0, // paragraph, p, exclam + 0x00b7, kKeyCompose, 0x002e, 0x002e, 0, // periodcentered, period, period + 0x00b1, kKeyCompose, 0x002b, 0x002d, 0, // plusminus, plus, minus + 0x00bf, kKeyCompose, 0x003f, 0x003f, + 0, // questiondown, question, question 0x00ae, kKeyCompose, 0x0028, 0x0072, 0, // registered, parenleft, r 0x00a7, kKeyCompose, 0x0073, 0x006f, 0, // section, s, o 0x00df, kKeyCompose, 0x0073, 0x0073, 0, // ssharp, s, s - 0x00a3, kKeyCompose, 0x004c, 0x002d, 0, // sterling, L, minus + 0x00a3, kKeyCompose, 0x004c, 0x002d, 0, // sterling, L, minus 0x00fe, kKeyCompose, 0x0074, 0x0068, 0, // thorn, t, h 0x00be, kKeyCompose, 0x0033, 0x0034, 0, // threequarters, 3, 4 - 0x00b3, kKeyCompose, 0x0033, 0x0053, 0, // threesuperior, 3, asciicircum - 0x00b2, kKeyCompose, 0x0032, 0x0053, 0, // twosuperior, 2, asciicircum - 0x00fa, kKeyCompose, 0x0075, 0x0027, 0, // uacute, u, apostrophe - 0x00fb, kKeyCompose, 0x0075, 0x0053, 0, // ucircumflex, u, asciicircum - 0x00fc, kKeyCompose, 0x0075, 0x0022, 0, // udiaeresis, u, quotedbl - 0x00f9, kKeyCompose, 0x0075, 0x0060, 0, // ugrave, u, grave - 0x00fd, kKeyCompose, 0x0079, 0x0027, 0, // yacute, y, apostrophe - 0x00ff, kKeyCompose, 0x0079, 0x0022, 0, // ydiaeresis, y, quotedbl - 0x00a5, kKeyCompose, 0x0079, 0x003d, 0, // yen, y, equal + 0x00b3, kKeyCompose, 0x0033, 0x0053, 0, // threesuperior, 3, asciicircum + 0x00b2, kKeyCompose, 0x0032, 0x0053, 0, // twosuperior, 2, asciicircum + 0x00fa, kKeyCompose, 0x0075, 0x0027, 0, // uacute, u, apostrophe + 0x00fb, kKeyCompose, 0x0075, 0x0053, 0, // ucircumflex, u, asciicircum + 0x00fc, kKeyCompose, 0x0075, 0x0022, 0, // udiaeresis, u, quotedbl + 0x00f9, kKeyCompose, 0x0075, 0x0060, 0, // ugrave, u, grave + 0x00fd, kKeyCompose, 0x0079, 0x0027, 0, // yacute, y, apostrophe + 0x00ff, kKeyCompose, 0x0079, 0x0022, 0, // ydiaeresis, y, quotedbl + 0x00a5, kKeyCompose, 0x0079, 0x003d, 0, // yen, y, equal // end of table - 0 -}; + 0}; static const KeyID s_numpadTable[] = { - kKeyKP_Space, 0x0020, - kKeyKP_Tab, kKeyTab, - kKeyKP_Enter, kKeyReturn, - kKeyKP_F1, kKeyF1, - kKeyKP_F2, kKeyF2, - kKeyKP_F3, kKeyF3, - kKeyKP_F4, kKeyF4, - kKeyKP_Home, kKeyHome, - kKeyKP_Left, kKeyLeft, - kKeyKP_Up, kKeyUp, - kKeyKP_Right, kKeyRight, - kKeyKP_Down, kKeyDown, - kKeyKP_PageUp, kKeyPageUp, - kKeyKP_PageDown, kKeyPageDown, - kKeyKP_End, kKeyEnd, - kKeyKP_Begin, kKeyBegin, - kKeyKP_Insert, kKeyInsert, - kKeyKP_Delete, kKeyDelete, - kKeyKP_Equal, 0x003d, - kKeyKP_Multiply, 0x002a, - kKeyKP_Add, 0x002b, - kKeyKP_Separator, 0x002c, - kKeyKP_Subtract, 0x002d, - kKeyKP_Decimal, 0x002e, - kKeyKP_Divide, 0x002f, - kKeyKP_0, 0x0030, - kKeyKP_1, 0x0031, - kKeyKP_2, 0x0032, - kKeyKP_3, 0x0033, - kKeyKP_4, 0x0034, - kKeyKP_5, 0x0035, - kKeyKP_6, 0x0036, - kKeyKP_7, 0x0037, - kKeyKP_8, 0x0038, - kKeyKP_9, 0x0039 -}; + kKeyKP_Space, 0x0020, kKeyKP_Tab, kKeyTab, + kKeyKP_Enter, kKeyReturn, kKeyKP_F1, kKeyF1, + kKeyKP_F2, kKeyF2, kKeyKP_F3, kKeyF3, + kKeyKP_F4, kKeyF4, kKeyKP_Home, kKeyHome, + kKeyKP_Left, kKeyLeft, kKeyKP_Up, kKeyUp, + kKeyKP_Right, kKeyRight, kKeyKP_Down, kKeyDown, + kKeyKP_PageUp, kKeyPageUp, kKeyKP_PageDown, kKeyPageDown, + kKeyKP_End, kKeyEnd, kKeyKP_Begin, kKeyBegin, + kKeyKP_Insert, kKeyInsert, kKeyKP_Delete, kKeyDelete, + kKeyKP_Equal, 0x003d, kKeyKP_Multiply, 0x002a, + kKeyKP_Add, 0x002b, kKeyKP_Separator, 0x002c, + kKeyKP_Subtract, 0x002d, kKeyKP_Decimal, 0x002e, + kKeyKP_Divide, 0x002f, kKeyKP_0, 0x0030, + kKeyKP_1, 0x0031, kKeyKP_2, 0x0032, + kKeyKP_3, 0x0033, kKeyKP_4, 0x0034, + kKeyKP_5, 0x0035, kKeyKP_6, 0x0036, + kKeyKP_7, 0x0037, kKeyKP_8, 0x0038, + kKeyKP_9, 0x0039}; // // KeyState // -KeyState::KeyState(IEventQueue* events, std::vector layouts, bool isLangSyncEnabled) : - IKeyState(events), - m_keyMapPtr(new synergy::KeyMap()), - m_keyMap(*m_keyMapPtr), - m_mask(0), - m_events(events), - m_isLangSyncEnabled(isLangSyncEnabled) -{ - m_keyMap.setLanguageData(std::move(layouts)); - init(); +KeyState::KeyState(IEventQueue *events, std::vector layouts, + bool isLangSyncEnabled) + : IKeyState(events), m_keyMapPtr(new synergy::KeyMap()), + m_keyMap(*m_keyMapPtr), m_mask(0), m_events(events), + m_isLangSyncEnabled(isLangSyncEnabled) { + m_keyMap.setLanguageData(std::move(layouts)); + init(); } -KeyState::KeyState(IEventQueue* events, synergy::KeyMap& keyMap, std::vector layouts, bool isLangSyncEnabled) : - IKeyState(events), - m_keyMapPtr(0), - m_keyMap(keyMap), - m_mask(0), - m_events(events), - m_isLangSyncEnabled(isLangSyncEnabled) -{ - m_keyMap.setLanguageData(std::move(layouts)); - init(); +KeyState::KeyState(IEventQueue *events, synergy::KeyMap &keyMap, + std::vector layouts, bool isLangSyncEnabled) + : IKeyState(events), m_keyMapPtr(0), m_keyMap(keyMap), m_mask(0), + m_events(events), m_isLangSyncEnabled(isLangSyncEnabled) { + m_keyMap.setLanguageData(std::move(layouts)); + init(); } -KeyState::~KeyState() -{ - if (m_keyMapPtr) - delete m_keyMapPtr; +KeyState::~KeyState() { + if (m_keyMapPtr) + delete m_keyMapPtr; } -void -KeyState::init() -{ - memset(&m_keys, 0, sizeof(m_keys)); - memset(&m_syntheticKeys, 0, sizeof(m_syntheticKeys)); - memset(&m_keyClientData, 0, sizeof(m_keyClientData)); - memset(&m_serverKeys, 0, sizeof(m_serverKeys)); +void KeyState::init() { + memset(&m_keys, 0, sizeof(m_keys)); + memset(&m_syntheticKeys, 0, sizeof(m_syntheticKeys)); + memset(&m_keyClientData, 0, sizeof(m_keyClientData)); + memset(&m_serverKeys, 0, sizeof(m_serverKeys)); } -void -KeyState::onKey(KeyButton button, bool down, KeyModifierMask newState) -{ - // update modifier state - m_mask = newState; - LOG((CLOG_DEBUG1 "new mask: 0x%04x", m_mask)); +void KeyState::onKey(KeyButton button, bool down, KeyModifierMask newState) { + // update modifier state + m_mask = newState; + LOG((CLOG_DEBUG1 "new mask: 0x%04x", m_mask)); - // ignore bogus buttons - button &= kButtonMask; - if (button == 0) { - return; - } + // ignore bogus buttons + button &= kButtonMask; + if (button == 0) { + return; + } - // update key state - if (down) { - m_keys[button] = 1; - m_syntheticKeys[button] = 1; - } - else { - m_keys[button] = 0; - m_syntheticKeys[button] = 0; - } + // update key state + if (down) { + m_keys[button] = 1; + m_syntheticKeys[button] = 1; + } else { + m_keys[button] = 0; + m_syntheticKeys[button] = 0; + } } -void -KeyState::sendKeyEvent( - void* target, bool press, bool isAutoRepeat, - KeyID key, KeyModifierMask mask, - SInt32 count, KeyButton button) -{ - if (m_keyMap.isHalfDuplex(key, button)) { - if (isAutoRepeat) { - // ignore auto-repeat on half-duplex keys - } - else { - m_events->addEvent(Event(m_events->forIKeyState().keyDown(), target, - KeyInfo::alloc(key, mask, button, 1))); - m_events->addEvent(Event(m_events->forIKeyState().keyUp(), target, - KeyInfo::alloc(key, mask, button, 1))); - } +void KeyState::sendKeyEvent(void *target, bool press, bool isAutoRepeat, + KeyID key, KeyModifierMask mask, SInt32 count, + KeyButton button) { + if (m_keyMap.isHalfDuplex(key, button)) { + if (isAutoRepeat) { + // ignore auto-repeat on half-duplex keys + } else { + m_events->addEvent(Event(m_events->forIKeyState().keyDown(), target, + KeyInfo::alloc(key, mask, button, 1))); + m_events->addEvent(Event(m_events->forIKeyState().keyUp(), target, + KeyInfo::alloc(key, mask, button, 1))); } - else { - if (isAutoRepeat) { - m_events->addEvent(Event(m_events->forIKeyState().keyRepeat(), target, - KeyInfo::alloc(key, mask, button, count))); - } - else if (press) { - m_events->addEvent(Event(m_events->forIKeyState().keyDown(), target, - KeyInfo::alloc(key, mask, button, 1))); - } - else { - m_events->addEvent(Event(m_events->forIKeyState().keyUp(), target, - KeyInfo::alloc(key, mask, button, 1))); - } + } else { + if (isAutoRepeat) { + m_events->addEvent(Event(m_events->forIKeyState().keyRepeat(), target, + KeyInfo::alloc(key, mask, button, count))); + } else if (press) { + m_events->addEvent(Event(m_events->forIKeyState().keyDown(), target, + KeyInfo::alloc(key, mask, button, 1))); + } else { + m_events->addEvent(Event(m_events->forIKeyState().keyUp(), target, + KeyInfo::alloc(key, mask, button, 1))); } + } } -void -KeyState::updateKeyMap(synergy::KeyMap* existing) -{ - if (existing) { - m_keyMap.swap(*existing); - } - else { - // get the current keyboard map - synergy::KeyMap keyMap; - getKeyMap(keyMap); - m_keyMap.swap(keyMap); - m_keyMap.finish(); - } +void KeyState::updateKeyMap(synergy::KeyMap *existing) { + if (existing) { + m_keyMap.swap(*existing); + } else { + // get the current keyboard map + synergy::KeyMap keyMap; + getKeyMap(keyMap); + m_keyMap.swap(keyMap); + m_keyMap.finish(); + } - // add special keys - addCombinationEntries(); - addKeypadEntries(); - addAliasEntries(); + // add special keys + addCombinationEntries(); + addKeypadEntries(); + addAliasEntries(); } -void -KeyState::updateKeyState() -{ - // reset our state - memset(&m_keys, 0, sizeof(m_keys)); - memset(&m_syntheticKeys, 0, sizeof(m_syntheticKeys)); - memset(&m_keyClientData, 0, sizeof(m_keyClientData)); - memset(&m_serverKeys, 0, sizeof(m_serverKeys)); - m_activeModifiers.clear(); +void KeyState::updateKeyState() { + // reset our state + memset(&m_keys, 0, sizeof(m_keys)); + memset(&m_syntheticKeys, 0, sizeof(m_syntheticKeys)); + memset(&m_keyClientData, 0, sizeof(m_keyClientData)); + memset(&m_serverKeys, 0, sizeof(m_serverKeys)); + m_activeModifiers.clear(); - // get the current keyboard state - KeyButtonSet keysDown; - pollPressedKeys(keysDown); - for (KeyButtonSet::const_iterator i = keysDown.begin(); - i != keysDown.end(); ++i) { - m_keys[*i] = 1; - } + // get the current keyboard state + KeyButtonSet keysDown; + pollPressedKeys(keysDown); + for (KeyButtonSet::const_iterator i = keysDown.begin(); i != keysDown.end(); + ++i) { + m_keys[*i] = 1; + } - // get the current modifier state - m_mask = pollActiveModifiers(); + // get the current modifier state + m_mask = pollActiveModifiers(); - // set active modifiers - AddActiveModifierContext addModifierContext(pollActiveGroup(), m_mask, - m_activeModifiers); - m_keyMap.foreachKey(&KeyState::addActiveModifierCB, &addModifierContext); + // set active modifiers + AddActiveModifierContext addModifierContext(pollActiveGroup(), m_mask, + m_activeModifiers); + m_keyMap.foreachKey(&KeyState::addActiveModifierCB, &addModifierContext); - LOG((CLOG_DEBUG1 "modifiers on update: 0x%04x", m_mask)); + LOG((CLOG_DEBUG1 "modifiers on update: 0x%04x", m_mask)); } -void -KeyState::addActiveModifierCB(KeyID, SInt32 group, - synergy::KeyMap::KeyItem& keyItem, void* vcontext) -{ - AddActiveModifierContext* context = - static_cast(vcontext); - if (group == context->m_activeGroup && - (keyItem.m_generates & context->m_mask) != 0) { - context->m_activeModifiers.insert(std::make_pair( - keyItem.m_generates, keyItem)); - } +void KeyState::addActiveModifierCB(KeyID, SInt32 group, + synergy::KeyMap::KeyItem &keyItem, + void *vcontext) { + AddActiveModifierContext *context = + static_cast(vcontext); + if (group == context->m_activeGroup && + (keyItem.m_generates & context->m_mask) != 0) { + context->m_activeModifiers.insert( + std::make_pair(keyItem.m_generates, keyItem)); + } } -void -KeyState::setHalfDuplexMask(KeyModifierMask mask) -{ - m_keyMap.clearHalfDuplexModifiers(); - if ((mask & KeyModifierCapsLock) != 0) { - m_keyMap.addHalfDuplexModifier(kKeyCapsLock); - } - if ((mask & KeyModifierNumLock) != 0) { - m_keyMap.addHalfDuplexModifier(kKeyNumLock); - } - if ((mask & KeyModifierScrollLock) != 0) { - m_keyMap.addHalfDuplexModifier(kKeyScrollLock); - } +void KeyState::setHalfDuplexMask(KeyModifierMask mask) { + m_keyMap.clearHalfDuplexModifiers(); + if ((mask & KeyModifierCapsLock) != 0) { + m_keyMap.addHalfDuplexModifier(kKeyCapsLock); + } + if ((mask & KeyModifierNumLock) != 0) { + m_keyMap.addHalfDuplexModifier(kKeyNumLock); + } + if ((mask & KeyModifierScrollLock) != 0) { + m_keyMap.addHalfDuplexModifier(kKeyScrollLock); + } } -void -KeyState::fakeKeyDown(KeyID id, KeyModifierMask mask, KeyButton serverID, const String& lang) -{ - // if this server key is already down then this is probably a - // mis-reported autorepeat. - serverID &= kButtonMask; - if (m_serverKeys[serverID] != 0) { - fakeKeyRepeat(id, mask, 1, serverID, lang); - return; +void KeyState::fakeKeyDown(KeyID id, KeyModifierMask mask, KeyButton serverID, + const String &lang) { + // if this server key is already down then this is probably a + // mis-reported autorepeat. + serverID &= kButtonMask; + if (m_serverKeys[serverID] != 0) { + fakeKeyRepeat(id, mask, 1, serverID, lang); + return; + } + + // ignore certain keys + if (isIgnoredKey(id, mask)) { + LOG((CLOG_DEBUG1 "ignored key %04x %04x", id, mask)); + return; + } + + Keystrokes keys; + ModifierToKeys oldActiveModifiers = m_activeModifiers; + const synergy::KeyMap::KeyItem *keyItem = + m_keyMap.mapKey(keys, id, pollActiveGroup(), m_activeModifiers, + getActiveModifiersRValue(), mask, false, lang); + + if (keyItem == nullptr) { + // a media key won't be mapped on mac, so we need to fake it in a + // special way + if (id == kKeyAudioDown || id == kKeyAudioUp || id == kKeyAudioMute || + id == kKeyAudioPlay || id == kKeyAudioPrev || id == kKeyAudioNext || + id == kKeyBrightnessDown || id == kKeyBrightnessUp) { + LOG((CLOG_DEBUG1 "emulating media key")); + fakeMediaKey(id); } - // ignore certain keys - if (isIgnoredKey(id, mask)) { - LOG((CLOG_DEBUG1 "ignored key %04x %04x", id, mask)); - return; - } + return; + } - Keystrokes keys; - ModifierToKeys oldActiveModifiers = m_activeModifiers; - const synergy::KeyMap::KeyItem* keyItem = - m_keyMap.mapKey(keys, id, pollActiveGroup(), m_activeModifiers, - getActiveModifiersRValue(), mask, false, lang); + KeyButton localID = (KeyButton)(keyItem->m_button & kButtonMask); + updateModifierKeyState(localID, oldActiveModifiers, m_activeModifiers); + if (localID != 0) { + // note keys down + ++m_keys[localID]; + ++m_syntheticKeys[localID]; + m_keyClientData[localID] = keyItem->m_client; + m_serverKeys[serverID] = localID; + } - if (keyItem == nullptr) { - // a media key won't be mapped on mac, so we need to fake it in a - // special way - if (id == kKeyAudioDown || id == kKeyAudioUp || - id == kKeyAudioMute || id == kKeyAudioPlay || - id == kKeyAudioPrev || id == kKeyAudioNext || - id == kKeyBrightnessDown || id == kKeyBrightnessUp - ) { - LOG((CLOG_DEBUG1 "emulating media key")); - fakeMediaKey(id); - } - - return; - } - - KeyButton localID = (KeyButton)(keyItem->m_button & kButtonMask); - updateModifierKeyState(localID, oldActiveModifiers, m_activeModifiers); - if (localID != 0) { - // note keys down - ++m_keys[localID]; - ++m_syntheticKeys[localID]; - m_keyClientData[localID] = keyItem->m_client; - m_serverKeys[serverID] = localID; - } - - // generate key events - fakeKeys(keys, 1); + // generate key events + fakeKeys(keys, 1); } -bool -KeyState::fakeKeyRepeat( - KeyID id, KeyModifierMask mask, - SInt32 count, KeyButton serverID, const String& lang) -{ - LOG((CLOG_DEBUG2 "fakeKeyRepeat")); - serverID &= kButtonMask; +bool KeyState::fakeKeyRepeat(KeyID id, KeyModifierMask mask, SInt32 count, + KeyButton serverID, const String &lang) { + LOG((CLOG_DEBUG2 "fakeKeyRepeat")); + serverID &= kButtonMask; - // if we haven't seen this button go down then ignore it - KeyButton oldLocalID = m_serverKeys[serverID]; - if (oldLocalID == 0) { - return false; + // if we haven't seen this button go down then ignore it + KeyButton oldLocalID = m_serverKeys[serverID]; + if (oldLocalID == 0) { + return false; + } + + // get keys for key repeat + Keystrokes keys; + ModifierToKeys oldActiveModifiers = m_activeModifiers; + const synergy::KeyMap::KeyItem *keyItem = + m_keyMap.mapKey(keys, id, pollActiveGroup(), m_activeModifiers, + getActiveModifiersRValue(), mask, true, lang); + if (keyItem == NULL) { + return false; + } + KeyButton localID = (KeyButton)(keyItem->m_button & kButtonMask); + if (localID == 0) { + return false; + } + + // if the KeyButton for the auto-repeat is not the same as for the + // initial press then mark the initial key as released and the new + // key as pressed. this can happen when we auto-repeat after a + // dead key. for example, a dead accent followed by 'a' will + // generate an 'a with accent' followed by a repeating 'a'. the + // KeyButtons for the two KeyIDs might be different. + if (localID != oldLocalID) { + // replace key up with previous KeyButton but leave key down + // alone so it uses the new KeyButton. + for (Keystrokes::iterator index = keys.begin(); index != keys.end(); + ++index) { + if (index->m_type == Keystroke::kButton && + index->m_data.m_button.m_button == localID) { + index->m_data.m_button.m_button = oldLocalID; + break; + } } - // get keys for key repeat - Keystrokes keys; - ModifierToKeys oldActiveModifiers = m_activeModifiers; - const synergy::KeyMap::KeyItem* keyItem = - m_keyMap.mapKey(keys, id, pollActiveGroup(), m_activeModifiers, - getActiveModifiersRValue(), mask, true, lang); - if (keyItem == NULL) { - return false; - } - KeyButton localID = (KeyButton)(keyItem->m_button & kButtonMask); - if (localID == 0) { - return false; - } - - // if the KeyButton for the auto-repeat is not the same as for the - // initial press then mark the initial key as released and the new - // key as pressed. this can happen when we auto-repeat after a - // dead key. for example, a dead accent followed by 'a' will - // generate an 'a with accent' followed by a repeating 'a'. the - // KeyButtons for the two KeyIDs might be different. - if (localID != oldLocalID) { - // replace key up with previous KeyButton but leave key down - // alone so it uses the new KeyButton. - for (Keystrokes::iterator index = keys.begin(); - index != keys.end(); ++index) { - if (index->m_type == Keystroke::kButton && - index->m_data.m_button.m_button == localID) { - index->m_data.m_button.m_button = oldLocalID; - break; - } - } - - // note that old key is now up - --m_keys[oldLocalID]; - --m_syntheticKeys[oldLocalID]; - - // note keys down - updateModifierKeyState(localID, oldActiveModifiers, m_activeModifiers); - ++m_keys[localID]; - ++m_syntheticKeys[localID]; - m_keyClientData[localID] = keyItem->m_client; - m_serverKeys[serverID] = localID; - } - - // generate key events - fakeKeys(keys, count); - return true; -} - -bool -KeyState::fakeKeyUp(KeyButton serverID) -{ - // if we haven't seen this button go down then ignore it - KeyButton localID = m_serverKeys[serverID & kButtonMask]; - if (localID == 0) { - return false; - } - - // get the sequence of keys to simulate key release - Keystrokes keys; - keys.push_back(Keystroke(localID, false, false, m_keyClientData[localID])); + // note that old key is now up + --m_keys[oldLocalID]; + --m_syntheticKeys[oldLocalID]; // note keys down - --m_keys[localID]; - --m_syntheticKeys[localID]; - m_serverKeys[serverID] = 0; + updateModifierKeyState(localID, oldActiveModifiers, m_activeModifiers); + ++m_keys[localID]; + ++m_syntheticKeys[localID]; + m_keyClientData[localID] = keyItem->m_client; + m_serverKeys[serverID] = localID; + } - // check if this is a modifier - ModifierToKeys::iterator i = m_activeModifiers.begin(); - while (i != m_activeModifiers.end()) { - if (i->second.m_button == localID && !i->second.m_lock) { - // modifier is no longer down - KeyModifierMask mask = i->first; - - ModifierToKeys::iterator tmp = i; - ++i; - m_activeModifiers.erase(tmp); - - if (m_activeModifiers.count(mask) == 0) { - // no key for modifier is down so deactivate modifier - m_mask &= ~mask; - LOG((CLOG_DEBUG1 "new state %04x", m_mask)); - } - } - else { - ++i; - } - } - - // generate key events - fakeKeys(keys, 1); - return true; + // generate key events + fakeKeys(keys, count); + return true; } -void -KeyState::fakeAllKeysUp() -{ - Keystrokes keys; - for (KeyButton i = 0; i < IKeyState::kNumButtons; ++i) { - if (m_syntheticKeys[i] > 0) { - keys.push_back(Keystroke(i, false, false, m_keyClientData[i])); - m_keys[i] = 0; - m_syntheticKeys[i] = 0; - } - } - fakeKeys(keys, 1); - memset(&m_serverKeys, 0, sizeof(m_serverKeys)); - m_activeModifiers.clear(); - m_mask = pollActiveModifiers(); -} - -bool -KeyState::fakeMediaKey(KeyID id) -{ +bool KeyState::fakeKeyUp(KeyButton serverID) { + // if we haven't seen this button go down then ignore it + KeyButton localID = m_serverKeys[serverID & kButtonMask]; + if (localID == 0) { return false; -} + } -bool -KeyState::isKeyDown(KeyButton button) const -{ - return (m_keys[button & kButtonMask] > 0); -} + // get the sequence of keys to simulate key release + Keystrokes keys; + keys.push_back(Keystroke(localID, false, false, m_keyClientData[localID])); -KeyModifierMask -KeyState::getActiveModifiers() const -{ - return m_mask; -} + // note keys down + --m_keys[localID]; + --m_syntheticKeys[localID]; + m_serverKeys[serverID] = 0; -KeyModifierMask& -KeyState::getActiveModifiersRValue() -{ - return m_mask; -} + // check if this is a modifier + ModifierToKeys::iterator i = m_activeModifiers.begin(); + while (i != m_activeModifiers.end()) { + if (i->second.m_button == localID && !i->second.m_lock) { + // modifier is no longer down + KeyModifierMask mask = i->first; -SInt32 -KeyState::getEffectiveGroup(SInt32 group, SInt32 offset) const -{ - return m_keyMap.getEffectiveGroup(group, offset); -} + ModifierToKeys::iterator tmp = i; + ++i; + m_activeModifiers.erase(tmp); -bool -KeyState::isIgnoredKey(KeyID key, KeyModifierMask) const -{ - switch (key) { - case kKeyCapsLock: - case kKeyNumLock: - case kKeyScrollLock: - return true; - - default: - return false; + if (m_activeModifiers.count(mask) == 0) { + // no key for modifier is down so deactivate modifier + m_mask &= ~mask; + LOG((CLOG_DEBUG1 "new state %04x", m_mask)); + } + } else { + ++i; } + } + + // generate key events + fakeKeys(keys, 1); + return true; } -KeyButton -KeyState::getButton(KeyID id, SInt32 group) const -{ - const synergy::KeyMap::KeyItemList* items = - m_keyMap.findCompatibleKey(id, group, 0, 0); - if (items == NULL) { - return 0; - } - else { - return items->back().m_button; +void KeyState::fakeAllKeysUp() { + Keystrokes keys; + for (KeyButton i = 0; i < IKeyState::kNumButtons; ++i) { + if (m_syntheticKeys[i] > 0) { + keys.push_back(Keystroke(i, false, false, m_keyClientData[i])); + m_keys[i] = 0; + m_syntheticKeys[i] = 0; } + } + fakeKeys(keys, 1); + memset(&m_serverKeys, 0, sizeof(m_serverKeys)); + m_activeModifiers.clear(); + m_mask = pollActiveModifiers(); } -void -KeyState::addAliasEntries() -{ - for (SInt32 g = 0, n = m_keyMap.getNumGroups(); g < n; ++g) { - // if we can't shift any kKeyTab key in a particular group but we can - // shift kKeyLeftTab then add a shifted kKeyTab entry that matches a - // shifted kKeyLeftTab entry. - m_keyMap.addKeyAliasEntry(kKeyTab, g, - KeyModifierShift, KeyModifierShift, - kKeyLeftTab, - KeyModifierShift, KeyModifierShift); +bool KeyState::fakeMediaKey(KeyID id) { return false; } - // if we have no kKeyLeftTab but we do have a kKeyTab that can be - // shifted then add kKeyLeftTab that matches a kKeyTab. - m_keyMap.addKeyAliasEntry(kKeyLeftTab, g, - KeyModifierShift, KeyModifierShift, - kKeyTab, - 0, KeyModifierShift); - - // map non-breaking space to space - m_keyMap.addKeyAliasEntry(0x20, g, 0, 0, 0xa0, 0, 0); - } +bool KeyState::isKeyDown(KeyButton button) const { + return (m_keys[button & kButtonMask] > 0); } -void -KeyState::addKeypadEntries() -{ - // map every numpad key to its equivalent non-numpad key if it's not - // on the keyboard. - for (SInt32 g = 0, n = m_keyMap.getNumGroups(); g < n; ++g) { - for (size_t i = 0; i < sizeof(s_numpadTable) / - sizeof(s_numpadTable[0]); i += 2) { - m_keyMap.addKeyCombinationEntry(s_numpadTable[i], g, - s_numpadTable + i + 1, 1); +KeyModifierMask KeyState::getActiveModifiers() const { return m_mask; } + +KeyModifierMask &KeyState::getActiveModifiersRValue() { return m_mask; } + +SInt32 KeyState::getEffectiveGroup(SInt32 group, SInt32 offset) const { + return m_keyMap.getEffectiveGroup(group, offset); +} + +bool KeyState::isIgnoredKey(KeyID key, KeyModifierMask) const { + switch (key) { + case kKeyCapsLock: + case kKeyNumLock: + case kKeyScrollLock: + return true; + + default: + return false; + } +} + +KeyButton KeyState::getButton(KeyID id, SInt32 group) const { + const synergy::KeyMap::KeyItemList *items = + m_keyMap.findCompatibleKey(id, group, 0, 0); + if (items == NULL) { + return 0; + } else { + return items->back().m_button; + } +} + +void KeyState::addAliasEntries() { + for (SInt32 g = 0, n = m_keyMap.getNumGroups(); g < n; ++g) { + // if we can't shift any kKeyTab key in a particular group but we can + // shift kKeyLeftTab then add a shifted kKeyTab entry that matches a + // shifted kKeyLeftTab entry. + m_keyMap.addKeyAliasEntry(kKeyTab, g, KeyModifierShift, KeyModifierShift, + kKeyLeftTab, KeyModifierShift, KeyModifierShift); + + // if we have no kKeyLeftTab but we do have a kKeyTab that can be + // shifted then add kKeyLeftTab that matches a kKeyTab. + m_keyMap.addKeyAliasEntry(kKeyLeftTab, g, KeyModifierShift, + KeyModifierShift, kKeyTab, 0, KeyModifierShift); + + // map non-breaking space to space + m_keyMap.addKeyAliasEntry(0x20, g, 0, 0, 0xa0, 0, 0); + } +} + +void KeyState::addKeypadEntries() { + // map every numpad key to its equivalent non-numpad key if it's not + // on the keyboard. + for (SInt32 g = 0, n = m_keyMap.getNumGroups(); g < n; ++g) { + for (size_t i = 0; i < sizeof(s_numpadTable) / sizeof(s_numpadTable[0]); + i += 2) { + m_keyMap.addKeyCombinationEntry(s_numpadTable[i], g, + s_numpadTable + i + 1, 1); + } + } +} + +void KeyState::addCombinationEntries() { + for (SInt32 g = 0, n = m_keyMap.getNumGroups(); g < n; ++g) { + // add dead and compose key composition sequences + const KeyID *i = s_decomposeTable; + while (*i != 0) { + // count the decomposed keys for this key + UInt32 numKeys = 0; + const KeyID *j = i; + while (*++j != 0) { + ++numKeys; + } + + // add an entry for this key + m_keyMap.addKeyCombinationEntry(*i, g, i + 1, numKeys); + + // next key + i += numKeys + 1; + ++i; + } + } +} + +void KeyState::fakeKeys(const Keystrokes &keys, UInt32 count) { + // do nothing if no keys or no repeats + if (count == 0 || keys.empty()) { + return; + } + + // generate key events + LOG((CLOG_DEBUG1 "keystrokes:")); + for (Keystrokes::const_iterator k = keys.begin(); k != keys.end();) { + if (k->m_type == Keystroke::kButton && k->m_data.m_button.m_repeat) { + // repeat from here up to but not including the next key + // with m_repeat == false count times. + Keystrokes::const_iterator start = k; + while (count-- > 0) { + // send repeating events + for (k = start; k != keys.end() && k->m_type == Keystroke::kButton && + k->m_data.m_button.m_repeat; + ++k) { + fakeKey(*k); } + } + + // note -- k is now on the first non-repeat key after the + // repeat keys, exactly where we'd like to continue from. + } else if (k->m_type != Keystroke::kGroup || + (!k->m_data.m_group.m_restore && m_isLangSyncEnabled)) { + // send event + fakeKey(*k); + + // next key + ++k; + } else { + LOG((CLOG_DEBUG1 "skipping keystroke, language sync is disabled")); + ++k; } + } } -void -KeyState::addCombinationEntries() -{ - for (SInt32 g = 0, n = m_keyMap.getNumGroups(); g < n; ++g) { - // add dead and compose key composition sequences - const KeyID* i = s_decomposeTable; - while (*i != 0) { - // count the decomposed keys for this key - UInt32 numKeys = 0; - const KeyID* j = i; - while (*++j != 0) { - ++numKeys; - } +void KeyState::updateModifierKeyState(KeyButton button, + const ModifierToKeys &oldModifiers, + const ModifierToKeys &newModifiers) { + // get the pressed modifier buttons before and after + synergy::KeyMap::ButtonToKeyMap oldKeys, newKeys; + for (ModifierToKeys::const_iterator i = oldModifiers.begin(); + i != oldModifiers.end(); ++i) { + oldKeys.insert(std::make_pair(i->second.m_button, &i->second)); + } + for (ModifierToKeys::const_iterator i = newModifiers.begin(); + i != newModifiers.end(); ++i) { + newKeys.insert(std::make_pair(i->second.m_button, &i->second)); + } - // add an entry for this key - m_keyMap.addKeyCombinationEntry(*i, g, i + 1, numKeys); + // get the modifier buttons that were pressed or released + synergy::KeyMap::ButtonToKeyMap pressed, released; + std::set_difference(oldKeys.begin(), oldKeys.end(), newKeys.begin(), + newKeys.end(), std::inserter(released, released.end()), + ButtonToKeyLess()); + std::set_difference(newKeys.begin(), newKeys.end(), oldKeys.begin(), + oldKeys.end(), std::inserter(pressed, pressed.end()), + ButtonToKeyLess()); - // next key - i += numKeys + 1; - ++i; - } + // update state + for (synergy::KeyMap::ButtonToKeyMap::const_iterator i = released.begin(); + i != released.end(); ++i) { + if (i->first != button) { + m_keys[i->first] = 0; + m_syntheticKeys[i->first] = 0; } -} - -void -KeyState::fakeKeys(const Keystrokes& keys, UInt32 count) -{ - // do nothing if no keys or no repeats - if (count == 0 || keys.empty()) { - return; - } - - // generate key events - LOG((CLOG_DEBUG1 "keystrokes:")); - for (Keystrokes::const_iterator k = keys.begin(); k != keys.end(); ) { - if (k->m_type == Keystroke::kButton && k->m_data.m_button.m_repeat) { - // repeat from here up to but not including the next key - // with m_repeat == false count times. - Keystrokes::const_iterator start = k; - while (count-- > 0) { - // send repeating events - for (k = start; k != keys.end() && - k->m_type == Keystroke::kButton && - k->m_data.m_button.m_repeat; ++k) { - fakeKey(*k); - } - } - - // note -- k is now on the first non-repeat key after the - // repeat keys, exactly where we'd like to continue from. - } - else if (k->m_type != Keystroke::kGroup || - (!k->m_data.m_group.m_restore && m_isLangSyncEnabled)) { - // send event - fakeKey(*k); - - // next key - ++k; - } - else { - LOG((CLOG_DEBUG1 "skipping keystroke, language sync is disabled")); - ++k; - } - } -} - -void -KeyState::updateModifierKeyState(KeyButton button, - const ModifierToKeys& oldModifiers, - const ModifierToKeys& newModifiers) -{ - // get the pressed modifier buttons before and after - synergy::KeyMap::ButtonToKeyMap oldKeys, newKeys; - for (ModifierToKeys::const_iterator i = oldModifiers.begin(); - i != oldModifiers.end(); ++i) { - oldKeys.insert(std::make_pair(i->second.m_button, &i->second)); - } - for (ModifierToKeys::const_iterator i = newModifiers.begin(); - i != newModifiers.end(); ++i) { - newKeys.insert(std::make_pair(i->second.m_button, &i->second)); - } - - // get the modifier buttons that were pressed or released - synergy::KeyMap::ButtonToKeyMap pressed, released; - std::set_difference(oldKeys.begin(), oldKeys.end(), - newKeys.begin(), newKeys.end(), - std::inserter(released, released.end()), - ButtonToKeyLess()); - std::set_difference(newKeys.begin(), newKeys.end(), - oldKeys.begin(), oldKeys.end(), - std::inserter(pressed, pressed.end()), - ButtonToKeyLess()); - - // update state - for (synergy::KeyMap::ButtonToKeyMap::const_iterator i = released.begin(); - i != released.end(); ++i) { - if (i->first != button) { - m_keys[i->first] = 0; - m_syntheticKeys[i->first] = 0; - } - } - for (synergy::KeyMap::ButtonToKeyMap::const_iterator i = pressed.begin(); - i != pressed.end(); ++i) { - if (i->first != button) { - m_keys[i->first] = 1; - m_syntheticKeys[i->first] = 1; - m_keyClientData[i->first] = i->second->m_client; - } + } + for (synergy::KeyMap::ButtonToKeyMap::const_iterator i = pressed.begin(); + i != pressed.end(); ++i) { + if (i->first != button) { + m_keys[i->first] = 1; + m_syntheticKeys[i->first] = 1; + m_keyClientData[i->first] = i->second->m_client; } + } } // @@ -946,11 +855,7 @@ KeyState::updateModifierKeyState(KeyButton button, // KeyState::AddActiveModifierContext::AddActiveModifierContext( - SInt32 group, KeyModifierMask mask, - ModifierToKeys& activeModifiers) : - m_activeGroup(group), - m_mask(mask), - m_activeModifiers(activeModifiers) -{ - // do nothing + SInt32 group, KeyModifierMask mask, ModifierToKeys &activeModifiers) + : m_activeGroup(group), m_mask(mask), m_activeModifiers(activeModifiers) { + // do nothing } diff --git a/src/lib/synergy/KeyState.h b/src/lib/synergy/KeyState.h index a817bacbf..dfb7b3226 100644 --- a/src/lib/synergy/KeyState.h +++ b/src/lib/synergy/KeyState.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 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 LICENSE 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 @@ -28,211 +28,207 @@ platform specific methods. */ class KeyState : public IKeyState { public: - KeyState(IEventQueue* events, std::vector layouts, bool isLangSyncEnabled); - KeyState(IEventQueue* events, synergy::KeyMap& keyMap, std::vector layouts, bool isLangSyncEnabled); - virtual ~KeyState(); + KeyState(IEventQueue *events, std::vector layouts, + bool isLangSyncEnabled); + KeyState(IEventQueue *events, synergy::KeyMap &keyMap, + std::vector layouts, bool isLangSyncEnabled); + virtual ~KeyState(); - //! @name manipulators - //@{ + //! @name manipulators + //@{ - //! Handle key event - /*! - Sets the state of \p button to down or up and updates the current - modifier state to \p newState. This method should be called by - primary screens only in response to local events. For auto-repeat - set \p down to \c true. Overrides must forward to the superclass. - */ - virtual void onKey(KeyButton button, bool down, - KeyModifierMask newState); + //! Handle key event + /*! + Sets the state of \p button to down or up and updates the current + modifier state to \p newState. This method should be called by + primary screens only in response to local events. For auto-repeat + set \p down to \c true. Overrides must forward to the superclass. + */ + virtual void onKey(KeyButton button, bool down, KeyModifierMask newState); - //! Post a key event - /*! - Posts a key event. This may adjust the event or post additional - events in some circumstances. If this is overridden it must forward - to the superclass. - */ - virtual void sendKeyEvent(void* target, - bool press, bool isAutoRepeat, - KeyID key, KeyModifierMask mask, - SInt32 count, KeyButton button); + //! Post a key event + /*! + Posts a key event. This may adjust the event or post additional + events in some circumstances. If this is overridden it must forward + to the superclass. + */ + virtual void sendKeyEvent(void *target, bool press, bool isAutoRepeat, + KeyID key, KeyModifierMask mask, SInt32 count, + KeyButton button); - //@} - //! @name accessors - //@{ + //@} + //! @name accessors + //@{ - //@} + //@} - void updateKeyMap(synergy::KeyMap* existing); - // IKeyState overrides - void updateKeyMap() override { - this->updateKeyMap(nullptr); - } - void updateKeyState() override; - void setHalfDuplexMask(KeyModifierMask) override; - void fakeKeyDown(KeyID id, KeyModifierMask mask, - KeyButton button, const String& lang) override; - bool fakeKeyRepeat(KeyID id, KeyModifierMask mask, - SInt32 count, KeyButton button, const String& lang) override; - bool fakeKeyUp(KeyButton button) override; - void fakeAllKeysUp() override; - bool fakeMediaKey(KeyID id) override; - - bool isKeyDown(KeyButton) const override; - KeyModifierMask - getActiveModifiers() const override; - // Left abstract - virtual bool fakeCtrlAltDel() = 0; - virtual KeyModifierMask - pollActiveModifiers() const = 0; - virtual SInt32 pollActiveGroup() const = 0; - virtual void pollPressedKeys(KeyButtonSet& pressedKeys) const = 0; + void updateKeyMap(synergy::KeyMap *existing); + // IKeyState overrides + void updateKeyMap() override { this->updateKeyMap(nullptr); } + void updateKeyState() override; + void setHalfDuplexMask(KeyModifierMask) override; + void fakeKeyDown(KeyID id, KeyModifierMask mask, KeyButton button, + const String &lang) override; + bool fakeKeyRepeat(KeyID id, KeyModifierMask mask, SInt32 count, + KeyButton button, const String &lang) override; + bool fakeKeyUp(KeyButton button) override; + void fakeAllKeysUp() override; + bool fakeMediaKey(KeyID id) override; - SInt32 getKeyState(KeyButton keyButton) { return m_keys[keyButton]; } + bool isKeyDown(KeyButton) const override; + KeyModifierMask getActiveModifiers() const override; + // Left abstract + virtual bool fakeCtrlAltDel() = 0; + virtual KeyModifierMask pollActiveModifiers() const = 0; + virtual SInt32 pollActiveGroup() const = 0; + virtual void pollPressedKeys(KeyButtonSet &pressedKeys) const = 0; + + SInt32 getKeyState(KeyButton keyButton) { return m_keys[keyButton]; } protected: - typedef synergy::KeyMap::Keystroke Keystroke; + typedef synergy::KeyMap::Keystroke Keystroke; - //! @name protected manipulators - //@{ + //! @name protected manipulators + //@{ - //! Get the keyboard map - /*! - Fills \p keyMap with the current keyboard map. - */ - virtual void getKeyMap(synergy::KeyMap& keyMap) = 0; + //! Get the keyboard map + /*! + Fills \p keyMap with the current keyboard map. + */ + virtual void getKeyMap(synergy::KeyMap &keyMap) = 0; - //! Fake a key event - /*! - Synthesize an event for \p keystroke. - */ - virtual void fakeKey(const Keystroke& keystroke) = 0; + //! Fake a key event + /*! + Synthesize an event for \p keystroke. + */ + virtual void fakeKey(const Keystroke &keystroke) = 0; - //! Get the active modifiers - /*! - Returns the modifiers that are currently active according to our - shadowed state. The state may be modified. - */ - virtual KeyModifierMask& - getActiveModifiersRValue(); + //! Get the active modifiers + /*! + Returns the modifiers that are currently active according to our + shadowed state. The state may be modified. + */ + virtual KeyModifierMask &getActiveModifiersRValue(); - //@} - //! @name protected accessors - //@{ + //@} + //! @name protected accessors + //@{ - //! Compute a group number - /*! - Returns the number of the group \p offset groups after group \p group. - */ - SInt32 getEffectiveGroup(SInt32 group, SInt32 offset) const; + //! Compute a group number + /*! + Returns the number of the group \p offset groups after group \p group. + */ + SInt32 getEffectiveGroup(SInt32 group, SInt32 offset) const; - //! Check if key is ignored - /*! - Returns \c true if and only if the key should always be ignored. - The default returns \c true only for the toggle keys. - */ - virtual bool isIgnoredKey(KeyID key, KeyModifierMask mask) const; + //! Check if key is ignored + /*! + Returns \c true if and only if the key should always be ignored. + The default returns \c true only for the toggle keys. + */ + virtual bool isIgnoredKey(KeyID key, KeyModifierMask mask) const; - //! Get button for a KeyID - /*! - Return the button mapped to key \p id in group \p group if any, - otherwise returns 0. - */ - KeyButton getButton(KeyID id, SInt32 group) const; + //! Get button for a KeyID + /*! + Return the button mapped to key \p id in group \p group if any, + otherwise returns 0. + */ + KeyButton getButton(KeyID id, SInt32 group) const; - //@} + //@} private: - typedef synergy::KeyMap::Keystrokes Keystrokes; - typedef synergy::KeyMap::ModifierToKeys ModifierToKeys; + typedef synergy::KeyMap::Keystrokes Keystrokes; + typedef synergy::KeyMap::ModifierToKeys ModifierToKeys; + public: - struct AddActiveModifierContext { - public: - AddActiveModifierContext(SInt32 group, KeyModifierMask mask, - ModifierToKeys& activeModifiers); + struct AddActiveModifierContext { + public: + AddActiveModifierContext(SInt32 group, KeyModifierMask mask, + ModifierToKeys &activeModifiers); - public: - SInt32 m_activeGroup; - KeyModifierMask m_mask; - ModifierToKeys& m_activeModifiers; - - private: - // not implemented - AddActiveModifierContext(const AddActiveModifierContext&); - AddActiveModifierContext& operator=(const AddActiveModifierContext&); - }; -private: - - class ButtonToKeyLess { - public: - bool operator()(const synergy::KeyMap::ButtonToKeyMap::value_type& a, - const synergy::KeyMap::ButtonToKeyMap::value_type b) const - { - return (a.first < b.first); - } - }; + public: + SInt32 m_activeGroup; + KeyModifierMask m_mask; + ModifierToKeys &m_activeModifiers; + private: // not implemented - KeyState(const KeyState&); - KeyState& operator=(const KeyState&); - - // called by all ctors. - void init(); - - // adds alias key sequences. these are sequences that are equivalent - // to other sequences. - void addAliasEntries(); - - // adds non-keypad key sequences for keypad KeyIDs - void addKeypadEntries(); - - // adds key sequences for combination KeyIDs (those built using - // dead keys) - void addCombinationEntries(); - - // synthesize key events. synthesize auto-repeat events count times. - void fakeKeys(const Keystrokes&, UInt32 count); - - // update key state to match changes to modifiers - void updateModifierKeyState(KeyButton button, - const ModifierToKeys& oldModifiers, - const ModifierToKeys& newModifiers); - - // active modifiers collection callback - static void addActiveModifierCB(KeyID id, SInt32 group, - synergy::KeyMap::KeyItem& keyItem, void* vcontext); + AddActiveModifierContext(const AddActiveModifierContext &); + AddActiveModifierContext &operator=(const AddActiveModifierContext &); + }; private: - // must be declared before m_keyMap. used when this class owns the key map. - synergy::KeyMap* m_keyMapPtr; + class ButtonToKeyLess { + public: + bool operator()(const synergy::KeyMap::ButtonToKeyMap::value_type &a, + const synergy::KeyMap::ButtonToKeyMap::value_type b) const { + return (a.first < b.first); + } + }; - // the keyboard map - synergy::KeyMap& m_keyMap; + // not implemented + KeyState(const KeyState &); + KeyState &operator=(const KeyState &); - // current modifier state - KeyModifierMask m_mask; + // called by all ctors. + void init(); - // the active modifiers and the buttons activating them - ModifierToKeys m_activeModifiers; + // adds alias key sequences. these are sequences that are equivalent + // to other sequences. + void addAliasEntries(); - // current keyboard state (> 0 if pressed, 0 otherwise). this is - // initialized to the keyboard state according to the system then - // it tracks synthesized events. - SInt32 m_keys[kNumButtons]; + // adds non-keypad key sequences for keypad KeyIDs + void addKeypadEntries(); - // synthetic keyboard state (> 0 if pressed, 0 otherwise). this - // tracks the synthesized keyboard state. if m_keys[n] > 0 but - // m_syntheticKeys[n] == 0 then the key was pressed locally and - // not synthesized yet. - SInt32 m_syntheticKeys[kNumButtons]; + // adds key sequences for combination KeyIDs (those built using + // dead keys) + void addCombinationEntries(); - // client data for each pressed key - UInt32 m_keyClientData[kNumButtons]; + // synthesize key events. synthesize auto-repeat events count times. + void fakeKeys(const Keystrokes &, UInt32 count); - // server keyboard state. an entry is 0 if not the key isn't pressed - // otherwise it's the local KeyButton synthesized for the server key. - KeyButton m_serverKeys[kNumButtons]; + // update key state to match changes to modifiers + void updateModifierKeyState(KeyButton button, + const ModifierToKeys &oldModifiers, + const ModifierToKeys &newModifiers); - IEventQueue* m_events; + // active modifiers collection callback + static void addActiveModifierCB(KeyID id, SInt32 group, + synergy::KeyMap::KeyItem &keyItem, + void *vcontext); - bool m_isLangSyncEnabled; +private: + // must be declared before m_keyMap. used when this class owns the key map. + synergy::KeyMap *m_keyMapPtr; + + // the keyboard map + synergy::KeyMap &m_keyMap; + + // current modifier state + KeyModifierMask m_mask; + + // the active modifiers and the buttons activating them + ModifierToKeys m_activeModifiers; + + // current keyboard state (> 0 if pressed, 0 otherwise). this is + // initialized to the keyboard state according to the system then + // it tracks synthesized events. + SInt32 m_keys[kNumButtons]; + + // synthetic keyboard state (> 0 if pressed, 0 otherwise). this + // tracks the synthesized keyboard state. if m_keys[n] > 0 but + // m_syntheticKeys[n] == 0 then the key was pressed locally and + // not synthesized yet. + SInt32 m_syntheticKeys[kNumButtons]; + + // client data for each pressed key + UInt32 m_keyClientData[kNumButtons]; + + // server keyboard state. an entry is 0 if not the key isn't pressed + // otherwise it's the local KeyButton synthesized for the server key. + KeyButton m_serverKeys[kNumButtons]; + + IEventQueue *m_events; + + bool m_isLangSyncEnabled; }; diff --git a/src/lib/synergy/PacketStreamFilter.cpp b/src/lib/synergy/PacketStreamFilter.cpp index 7f42e8c8d..c71920a87 100644 --- a/src/lib/synergy/PacketStreamFilter.cpp +++ b/src/lib/synergy/PacketStreamFilter.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 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 LICENSE 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 @@ -18,8 +18,8 @@ #include "synergy/PacketStreamFilter.h" #include "base/IEventQueue.h" -#include "mt/Lock.h" #include "base/TMethodEventJob.h" +#include "mt/Lock.h" #include #include @@ -28,171 +28,146 @@ // PacketStreamFilter // -PacketStreamFilter::PacketStreamFilter(IEventQueue* events, synergy::IStream* stream, bool adoptStream) : - StreamFilter(events, stream, adoptStream), - m_size(0), - m_inputShutdown(false), - m_events(events) -{ - // do nothing +PacketStreamFilter::PacketStreamFilter(IEventQueue *events, + synergy::IStream *stream, + bool adoptStream) + : StreamFilter(events, stream, adoptStream), m_size(0), + m_inputShutdown(false), m_events(events) { + // do nothing } -PacketStreamFilter::~PacketStreamFilter() -{ - // do nothing +PacketStreamFilter::~PacketStreamFilter() { + // do nothing } -void -PacketStreamFilter::close() -{ +void PacketStreamFilter::close() { + Lock lock(&m_mutex); + m_size = 0; + m_buffer.pop(m_buffer.getSize()); + StreamFilter::close(); +} + +UInt32 PacketStreamFilter::read(void *buffer, UInt32 n) { + if (n == 0) { + return 0; + } + + Lock lock(&m_mutex); + + // if not enough data yet then give up + if (!isReadyNoLock()) { + return 0; + } + + // read no more than what's left in the buffered packet + if (n > m_size) { + n = m_size; + } + + // read it + if (buffer != NULL) { + memcpy(buffer, m_buffer.peek(n), n); + } + m_buffer.pop(n); + m_size -= n; + + // get next packet's size if we've finished with this packet and + // there's enough data to do so. + readPacketSize(); + + if (m_inputShutdown && m_size == 0) { + m_events->addEvent( + Event(m_events->forIStream().inputShutdown(), getEventTarget())); + } + + return n; +} + +void PacketStreamFilter::write(const void *buffer, UInt32 count) { + // write the length of the payload + UInt8 length[4]; + length[0] = (UInt8)((count >> 24) & 0xff); + length[1] = (UInt8)((count >> 16) & 0xff); + length[2] = (UInt8)((count >> 8) & 0xff); + length[3] = (UInt8)(count & 0xff); + getStream()->write(length, sizeof(length)); + + // write the payload + getStream()->write(buffer, count); +} + +void PacketStreamFilter::shutdownInput() { + Lock lock(&m_mutex); + m_size = 0; + m_buffer.pop(m_buffer.getSize()); + StreamFilter::shutdownInput(); +} + +bool PacketStreamFilter::isReady() const { + Lock lock(&m_mutex); + return isReadyNoLock(); +} + +UInt32 PacketStreamFilter::getSize() const { + Lock lock(&m_mutex); + return isReadyNoLock() ? m_size : 0; +} + +bool PacketStreamFilter::isReadyNoLock() const { + return (m_size != 0 && m_buffer.getSize() >= m_size); +} + +void PacketStreamFilter::readPacketSize() { + // note -- m_mutex must be locked on entry + + if (m_size == 0 && m_buffer.getSize() >= 4) { + UInt8 buffer[4]; + memcpy(buffer, m_buffer.peek(sizeof(buffer)), sizeof(buffer)); + m_buffer.pop(sizeof(buffer)); + m_size = ((UInt32)buffer[0] << 24) | ((UInt32)buffer[1] << 16) | + ((UInt32)buffer[2] << 8) | (UInt32)buffer[3]; + } +} + +bool PacketStreamFilter::readMore() { + // note if we have whole packet + bool wasReady = isReadyNoLock(); + + // read more data + char buffer[4096]; + UInt32 n = getStream()->read(buffer, sizeof(buffer)); + while (n > 0) { + m_buffer.write(buffer, n); + n = getStream()->read(buffer, sizeof(buffer)); + } + + // if we don't yet have the next packet size then get it, + // if possible. + readPacketSize(); + + // note if we now have a whole packet + bool isReady = isReadyNoLock(); + + // if we weren't ready before but now we are then send a + // input ready event apparently from the filtered stream. + return (wasReady != isReady); +} + +void PacketStreamFilter::filterEvent(const Event &event) { + if (event.getType() == m_events->forIStream().inputReady()) { Lock lock(&m_mutex); - m_size = 0; - m_buffer.pop(m_buffer.getSize()); - StreamFilter::close(); -} - -UInt32 -PacketStreamFilter::read(void* buffer, UInt32 n) -{ - if (n == 0) { - return 0; + if (!readMore()) { + return; } - + } else if (event.getType() == m_events->forIStream().inputShutdown()) { + // discard this if we have buffered data Lock lock(&m_mutex); - - // if not enough data yet then give up - if (!isReadyNoLock()) { - return 0; + m_inputShutdown = true; + if (m_size != 0) { + return; } + } - // read no more than what's left in the buffered packet - if (n > m_size) { - n = m_size; - } - - // read it - if (buffer != NULL) { - memcpy(buffer, m_buffer.peek(n), n); - } - m_buffer.pop(n); - m_size -= n; - - // get next packet's size if we've finished with this packet and - // there's enough data to do so. - readPacketSize(); - - if (m_inputShutdown && m_size == 0) { - m_events->addEvent(Event(m_events->forIStream().inputShutdown(), - getEventTarget())); - } - - return n; -} - -void -PacketStreamFilter::write(const void* buffer, UInt32 count) -{ - // write the length of the payload - UInt8 length[4]; - length[0] = (UInt8)((count >> 24) & 0xff); - length[1] = (UInt8)((count >> 16) & 0xff); - length[2] = (UInt8)((count >> 8) & 0xff); - length[3] = (UInt8)( count & 0xff); - getStream()->write(length, sizeof(length)); - - // write the payload - getStream()->write(buffer, count); -} - -void -PacketStreamFilter::shutdownInput() -{ - Lock lock(&m_mutex); - m_size = 0; - m_buffer.pop(m_buffer.getSize()); - StreamFilter::shutdownInput(); -} - -bool -PacketStreamFilter::isReady() const -{ - Lock lock(&m_mutex); - return isReadyNoLock(); -} - -UInt32 -PacketStreamFilter::getSize() const -{ - Lock lock(&m_mutex); - return isReadyNoLock() ? m_size : 0; -} - -bool -PacketStreamFilter::isReadyNoLock() const -{ - return (m_size != 0 && m_buffer.getSize() >= m_size); -} - -void -PacketStreamFilter::readPacketSize() -{ - // note -- m_mutex must be locked on entry - - if (m_size == 0 && m_buffer.getSize() >= 4) { - UInt8 buffer[4]; - memcpy(buffer, m_buffer.peek(sizeof(buffer)), sizeof(buffer)); - m_buffer.pop(sizeof(buffer)); - m_size = ((UInt32)buffer[0] << 24) | - ((UInt32)buffer[1] << 16) | - ((UInt32)buffer[2] << 8) | - (UInt32)buffer[3]; - } -} - -bool -PacketStreamFilter::readMore() -{ - // note if we have whole packet - bool wasReady = isReadyNoLock(); - - // read more data - char buffer[4096]; - UInt32 n = getStream()->read(buffer, sizeof(buffer)); - while (n > 0) { - m_buffer.write(buffer, n); - n = getStream()->read(buffer, sizeof(buffer)); - } - - // if we don't yet have the next packet size then get it, - // if possible. - readPacketSize(); - - // note if we now have a whole packet - bool isReady = isReadyNoLock(); - - // if we weren't ready before but now we are then send a - // input ready event apparently from the filtered stream. - return (wasReady != isReady); -} - -void -PacketStreamFilter::filterEvent(const Event& event) -{ - if (event.getType() == m_events->forIStream().inputReady()) { - Lock lock(&m_mutex); - if (!readMore()) { - return; - } - } - else if (event.getType() == m_events->forIStream().inputShutdown()) { - // discard this if we have buffered data - Lock lock(&m_mutex); - m_inputShutdown = true; - if (m_size != 0) { - return; - } - } - - // pass event - StreamFilter::filterEvent(event); + // pass event + StreamFilter::filterEvent(event); } diff --git a/src/lib/synergy/PacketStreamFilter.h b/src/lib/synergy/PacketStreamFilter.h index e196235f6..c90bc98c8 100644 --- a/src/lib/synergy/PacketStreamFilter.h +++ b/src/lib/synergy/PacketStreamFilter.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 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 LICENSE 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 @@ -18,42 +18,43 @@ #pragma once -#include "io/StreamFilter.h" #include "io/StreamBuffer.h" +#include "io/StreamFilter.h" #include "mt/Mutex.h" class IEventQueue; -//! Packetizing stream filter +//! Packetizing stream filter /*! Filters a stream to read and write packets. */ class PacketStreamFilter : public StreamFilter { public: - PacketStreamFilter(IEventQueue* events, synergy::IStream* stream, bool adoptStream = true); - ~PacketStreamFilter(); + PacketStreamFilter(IEventQueue *events, synergy::IStream *stream, + bool adoptStream = true); + ~PacketStreamFilter(); - // IStream overrides - virtual void close(); - virtual UInt32 read(void* buffer, UInt32 n); - virtual void write(const void* buffer, UInt32 n); - virtual void shutdownInput(); - virtual bool isReady() const; - virtual UInt32 getSize() const; + // IStream overrides + virtual void close(); + virtual UInt32 read(void *buffer, UInt32 n); + virtual void write(const void *buffer, UInt32 n); + virtual void shutdownInput(); + virtual bool isReady() const; + virtual UInt32 getSize() const; protected: - // StreamFilter overrides - virtual void filterEvent(const Event&); + // StreamFilter overrides + virtual void filterEvent(const Event &); private: - bool isReadyNoLock() const; - void readPacketSize(); - bool readMore(); + bool isReadyNoLock() const; + void readPacketSize(); + bool readMore(); private: - Mutex m_mutex; - UInt32 m_size; - StreamBuffer m_buffer; - bool m_inputShutdown; - IEventQueue* m_events; + Mutex m_mutex; + UInt32 m_size; + StreamBuffer m_buffer; + bool m_inputShutdown; + IEventQueue *m_events; }; diff --git a/src/lib/synergy/PlatformScreen.cpp b/src/lib/synergy/PlatformScreen.cpp index 734d208af..0aca14a29 100644 --- a/src/lib/synergy/PlatformScreen.cpp +++ b/src/lib/synergy/PlatformScreen.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 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 LICENSE 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 @@ -20,112 +20,73 @@ #include "synergy/App.h" #include "synergy/ArgsBase.h" -PlatformScreen::PlatformScreen(IEventQueue* events, lib::synergy::ClientScrollDirection scrollDirection) : - IPlatformScreen(events), - m_draggingStarted(false), - m_fakeDraggingStarted(false), - m_clientScrollDirection(scrollDirection) -{ +PlatformScreen::PlatformScreen( + IEventQueue *events, lib::synergy::ClientScrollDirection scrollDirection) + : IPlatformScreen(events), m_draggingStarted(false), + m_fakeDraggingStarted(false), m_clientScrollDirection(scrollDirection) {} + +PlatformScreen::~PlatformScreen() { + // do nothing } -PlatformScreen::~PlatformScreen() -{ - // do nothing +void PlatformScreen::updateKeyMap() { getKeyState()->updateKeyMap(); } + +void PlatformScreen::updateKeyState() { + getKeyState()->updateKeyState(); + updateButtons(); } -void -PlatformScreen::updateKeyMap() -{ - getKeyState()->updateKeyMap(); +void PlatformScreen::setHalfDuplexMask(KeyModifierMask mask) { + getKeyState()->setHalfDuplexMask(mask); } -void -PlatformScreen::updateKeyState() -{ - getKeyState()->updateKeyState(); - updateButtons(); +void PlatformScreen::fakeKeyDown(KeyID id, KeyModifierMask mask, + KeyButton button, const String &lang) { + getKeyState()->fakeKeyDown(id, mask, button, lang); } -void -PlatformScreen::setHalfDuplexMask(KeyModifierMask mask) -{ - getKeyState()->setHalfDuplexMask(mask); +bool PlatformScreen::fakeKeyRepeat(KeyID id, KeyModifierMask mask, SInt32 count, + KeyButton button, const String &lang) { + return getKeyState()->fakeKeyRepeat(id, mask, count, button, lang); } -void -PlatformScreen::fakeKeyDown(KeyID id, KeyModifierMask mask, - KeyButton button, const String& lang) -{ - getKeyState()->fakeKeyDown(id, mask, button, lang); +bool PlatformScreen::fakeKeyUp(KeyButton button) { + return getKeyState()->fakeKeyUp(button); } -bool -PlatformScreen::fakeKeyRepeat(KeyID id, KeyModifierMask mask, - SInt32 count, KeyButton button, const String& lang) -{ - return getKeyState()->fakeKeyRepeat(id, mask, count, button, lang); +void PlatformScreen::fakeAllKeysUp() { getKeyState()->fakeAllKeysUp(); } + +bool PlatformScreen::fakeCtrlAltDel() { + return getKeyState()->fakeCtrlAltDel(); } -bool -PlatformScreen::fakeKeyUp(KeyButton button) -{ - return getKeyState()->fakeKeyUp(button); +bool PlatformScreen::isKeyDown(KeyButton button) const { + return getKeyState()->isKeyDown(button); } -void -PlatformScreen::fakeAllKeysUp() -{ - getKeyState()->fakeAllKeysUp(); +KeyModifierMask PlatformScreen::getActiveModifiers() const { + return getKeyState()->getActiveModifiers(); } -bool -PlatformScreen::fakeCtrlAltDel() -{ - return getKeyState()->fakeCtrlAltDel(); +KeyModifierMask PlatformScreen::pollActiveModifiers() const { + return getKeyState()->pollActiveModifiers(); } -bool -PlatformScreen::isKeyDown(KeyButton button) const -{ - return getKeyState()->isKeyDown(button); +SInt32 PlatformScreen::pollActiveGroup() const { + return getKeyState()->pollActiveGroup(); } -KeyModifierMask -PlatformScreen::getActiveModifiers() const -{ - return getKeyState()->getActiveModifiers(); +void PlatformScreen::pollPressedKeys(KeyButtonSet &pressedKeys) const { + getKeyState()->pollPressedKeys(pressedKeys); } -KeyModifierMask -PlatformScreen::pollActiveModifiers() const -{ - return getKeyState()->pollActiveModifiers(); +bool PlatformScreen::isDraggingStarted() { + if (App::instance().argsBase().m_enableDragDrop) { + return m_draggingStarted; + } + return false; } -SInt32 -PlatformScreen::pollActiveGroup() const -{ - return getKeyState()->pollActiveGroup(); +SInt32 PlatformScreen::mapClientScrollDirection(SInt32 x) const { + return (x * m_clientScrollDirection); } - -void -PlatformScreen::pollPressedKeys(KeyButtonSet& pressedKeys) const -{ - getKeyState()->pollPressedKeys(pressedKeys); -} - -bool -PlatformScreen::isDraggingStarted() -{ - if (App::instance().argsBase().m_enableDragDrop) { - return m_draggingStarted; - } - return false; -} - -SInt32 -PlatformScreen::mapClientScrollDirection(SInt32 x) const -{ - return (x * m_clientScrollDirection); -} - diff --git a/src/lib/synergy/PlatformScreen.h b/src/lib/synergy/PlatformScreen.h index d6f9c46e4..724a420ec 100644 --- a/src/lib/synergy/PlatformScreen.h +++ b/src/lib/synergy/PlatformScreen.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 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 LICENSE 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 @@ -18,10 +18,10 @@ #pragma once -#include "synergy/IPlatformScreen.h" -#include "synergy/DragInformation.h" -#include "synergy/ClientArgs.h" #include "common/stdexcept.h" +#include "synergy/ClientArgs.h" +#include "synergy/DragInformation.h" +#include "synergy/IPlatformScreen.h" //! Base screen implementation /*! @@ -31,113 +31,116 @@ subclasses to implement the rest. */ class PlatformScreen : public IPlatformScreen { public: - PlatformScreen(IEventQueue* events, lib::synergy::ClientScrollDirection scrollDirection = lib::synergy::ClientScrollDirection::SERVER); - virtual ~PlatformScreen(); + PlatformScreen(IEventQueue *events, + lib::synergy::ClientScrollDirection scrollDirection = + lib::synergy::ClientScrollDirection::SERVER); + virtual ~PlatformScreen(); - // IScreen overrides - virtual void* getEventTarget() const = 0; - virtual bool getClipboard(ClipboardID id, IClipboard*) const = 0; - virtual void getShape(SInt32& x, SInt32& y, - SInt32& width, SInt32& height) const = 0; - virtual void getCursorPos(SInt32& x, SInt32& y) const = 0; + // IScreen overrides + virtual void *getEventTarget() const = 0; + virtual bool getClipboard(ClipboardID id, IClipboard *) const = 0; + virtual void getShape(SInt32 &x, SInt32 &y, SInt32 &width, + SInt32 &height) const = 0; + virtual void getCursorPos(SInt32 &x, SInt32 &y) const = 0; - // IPrimaryScreen overrides - virtual void reconfigure(UInt32 activeSides) = 0; - virtual void warpCursor(SInt32 x, SInt32 y) = 0; - virtual UInt32 registerHotKey(KeyID key, - KeyModifierMask mask) = 0; - virtual void unregisterHotKey(UInt32 id) = 0; - virtual void fakeInputBegin() = 0; - virtual void fakeInputEnd() = 0; - virtual SInt32 getJumpZoneSize() const = 0; - virtual bool isAnyMouseButtonDown(UInt32& buttonID) const = 0; - virtual void getCursorCenter(SInt32& x, SInt32& y) const = 0; + // IPrimaryScreen overrides + virtual void reconfigure(UInt32 activeSides) = 0; + virtual void warpCursor(SInt32 x, SInt32 y) = 0; + virtual UInt32 registerHotKey(KeyID key, KeyModifierMask mask) = 0; + virtual void unregisterHotKey(UInt32 id) = 0; + virtual void fakeInputBegin() = 0; + virtual void fakeInputEnd() = 0; + virtual SInt32 getJumpZoneSize() const = 0; + virtual bool isAnyMouseButtonDown(UInt32 &buttonID) const = 0; + virtual void getCursorCenter(SInt32 &x, SInt32 &y) const = 0; - // ISecondaryScreen overrides - virtual void fakeMouseButton(ButtonID id, bool press) = 0; - virtual void fakeMouseMove(SInt32 x, SInt32 y) = 0; - virtual void fakeMouseRelativeMove(SInt32 dx, SInt32 dy) const = 0; - virtual void fakeMouseWheel(SInt32 xDelta, SInt32 yDelta) const = 0; + // ISecondaryScreen overrides + virtual void fakeMouseButton(ButtonID id, bool press) = 0; + virtual void fakeMouseMove(SInt32 x, SInt32 y) = 0; + virtual void fakeMouseRelativeMove(SInt32 dx, SInt32 dy) const = 0; + virtual void fakeMouseWheel(SInt32 xDelta, SInt32 yDelta) const = 0; - // IKeyState overrides - virtual void updateKeyMap(); - virtual void updateKeyState(); - virtual void setHalfDuplexMask(KeyModifierMask); - virtual void fakeKeyDown(KeyID id, KeyModifierMask mask, - KeyButton button, const String&); - virtual bool fakeKeyRepeat(KeyID id, KeyModifierMask mask, - SInt32 count, KeyButton button, const String& lang); - virtual bool fakeKeyUp(KeyButton button); - virtual void fakeAllKeysUp(); - virtual bool fakeCtrlAltDel(); - virtual bool isKeyDown(KeyButton) const; - virtual KeyModifierMask - getActiveModifiers() const; - virtual KeyModifierMask - pollActiveModifiers() const; - virtual SInt32 pollActiveGroup() const; - virtual void pollPressedKeys(KeyButtonSet& pressedKeys) const; + // IKeyState overrides + virtual void updateKeyMap(); + virtual void updateKeyState(); + virtual void setHalfDuplexMask(KeyModifierMask); + virtual void fakeKeyDown(KeyID id, KeyModifierMask mask, KeyButton button, + const String &); + virtual bool fakeKeyRepeat(KeyID id, KeyModifierMask mask, SInt32 count, + KeyButton button, const String &lang); + virtual bool fakeKeyUp(KeyButton button); + virtual void fakeAllKeysUp(); + virtual bool fakeCtrlAltDel(); + virtual bool isKeyDown(KeyButton) const; + virtual KeyModifierMask getActiveModifiers() const; + virtual KeyModifierMask pollActiveModifiers() const; + virtual SInt32 pollActiveGroup() const; + virtual void pollPressedKeys(KeyButtonSet &pressedKeys) const; - virtual void setDraggingStarted(bool started) { m_draggingStarted = started; } - virtual bool isDraggingStarted(); - virtual bool isFakeDraggingStarted() { return m_fakeDraggingStarted; } - virtual String& getDraggingFilename() { return m_draggingFilename; } - virtual void clearDraggingFilename() { } + virtual void setDraggingStarted(bool started) { m_draggingStarted = started; } + virtual bool isDraggingStarted(); + virtual bool isFakeDraggingStarted() { return m_fakeDraggingStarted; } + virtual String &getDraggingFilename() { return m_draggingFilename; } + virtual void clearDraggingFilename() {} - // IPlatformScreen overrides - virtual void enable() = 0; - virtual void disable() = 0; - virtual void enter() = 0; - virtual bool leave() = 0; - virtual bool setClipboard(ClipboardID, const IClipboard*) = 0; - virtual void checkClipboards() = 0; - virtual void openScreensaver(bool notify) = 0; - virtual void closeScreensaver() = 0; - virtual void screensaver(bool activate) = 0; - virtual void resetOptions() = 0; - virtual void setOptions(const OptionsList& options) = 0; - virtual void setSequenceNumber(UInt32) = 0; - virtual bool isPrimary() const = 0; - - virtual void fakeDraggingFiles(DragFileList fileList) { throw std::runtime_error("fakeDraggingFiles not implemented"); } - virtual const String& - getDropTarget() const { throw std::runtime_error("getDropTarget not implemented"); } + // IPlatformScreen overrides + virtual void enable() = 0; + virtual void disable() = 0; + virtual void enter() = 0; + virtual bool leave() = 0; + virtual bool setClipboard(ClipboardID, const IClipboard *) = 0; + virtual void checkClipboards() = 0; + virtual void openScreensaver(bool notify) = 0; + virtual void closeScreensaver() = 0; + virtual void screensaver(bool activate) = 0; + virtual void resetOptions() = 0; + virtual void setOptions(const OptionsList &options) = 0; + virtual void setSequenceNumber(UInt32) = 0; + virtual bool isPrimary() const = 0; + + virtual void fakeDraggingFiles(DragFileList fileList) { + throw std::runtime_error("fakeDraggingFiles not implemented"); + } + virtual const String &getDropTarget() const { + throw std::runtime_error("getDropTarget not implemented"); + } protected: - //! Update mouse buttons - /*! - Subclasses must implement this method to update their internal mouse - button mapping and, if desired, state tracking. - */ - virtual void updateButtons() = 0; + //! Update mouse buttons + /*! + Subclasses must implement this method to update their internal mouse + button mapping and, if desired, state tracking. + */ + virtual void updateButtons() = 0; - //! Get the key state - /*! - Subclasses must implement this method to return the platform specific - key state object that each subclass must have. - */ - virtual IKeyState* getKeyState() const = 0; + //! Get the key state + /*! + Subclasses must implement this method to return the platform specific + key state object that each subclass must have. + */ + virtual IKeyState *getKeyState() const = 0; - // IPlatformScreen overrides - virtual void handleSystemEvent(const Event& event, void*) = 0; + // IPlatformScreen overrides + virtual void handleSystemEvent(const Event &event, void *) = 0; - /*! - * \brief mapClientScrollDirection - * Convert scroll according to client scroll directio - * \return converted value according to the client scroll direction - */ - virtual SInt32 mapClientScrollDirection(SInt32) const; + /*! + * \brief mapClientScrollDirection + * Convert scroll according to client scroll directio + * \return converted value according to the client scroll direction + */ + virtual SInt32 mapClientScrollDirection(SInt32) const; protected: - String m_draggingFilename; - bool m_draggingStarted; - bool m_fakeDraggingStarted; + String m_draggingFilename; + bool m_draggingStarted; + bool m_fakeDraggingStarted; private: - /*! - * \brief m_clientScrollDirection - * This member contains client scroll direction. - * This member is used only on client side. - */ - lib::synergy::ClientScrollDirection m_clientScrollDirection = lib::synergy::ClientScrollDirection::SERVER; + /*! + * \brief m_clientScrollDirection + * This member contains client scroll direction. + * This member is used only on client side. + */ + lib::synergy::ClientScrollDirection m_clientScrollDirection = + lib::synergy::ClientScrollDirection::SERVER; }; diff --git a/src/lib/synergy/ProtocolUtil.cpp b/src/lib/synergy/ProtocolUtil.cpp index f850f92c8..a81406c35 100644 --- a/src/lib/synergy/ProtocolUtil.cpp +++ b/src/lib/synergy/ProtocolUtil.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -16,12 +16,12 @@ * along with this program. If not, see . */ -#include -#include #include "synergy/ProtocolUtil.h" -#include "io/IStream.h" #include "base/Log.h" #include "common/stdvector.h" +#include "io/IStream.h" +#include +#include #include #include @@ -30,533 +30,534 @@ // ProtocolUtil // -namespace { +namespace { -void -writeInt(UInt32 Value, UInt32 Length, std::vector& Buffer) -{ - switch(Length) - { - case 1: - Buffer.push_back(static_cast(Value & 0xffU)); - break; - case 4: - Buffer.push_back(static_cast((Value >> 24U) & 0xffU)); - Buffer.push_back(static_cast((Value >> 16U) & 0xffU)); - Buffer.push_back(static_cast((Value >> 8U) & 0xffU)); - Buffer.push_back(static_cast( Value & 0xffU)); - break; - case 2: - Buffer.push_back(static_cast((Value >> 8U) & 0xffU)); - Buffer.push_back(static_cast( Value & 0xffU)); - break; - default: - assert(0 && "invalid integer format length"); - return; - } +void writeInt(UInt32 Value, UInt32 Length, std::vector &Buffer) { + switch (Length) { + case 1: + Buffer.push_back(static_cast(Value & 0xffU)); + break; + case 4: + Buffer.push_back(static_cast((Value >> 24U) & 0xffU)); + Buffer.push_back(static_cast((Value >> 16U) & 0xffU)); + Buffer.push_back(static_cast((Value >> 8U) & 0xffU)); + Buffer.push_back(static_cast(Value & 0xffU)); + break; + case 2: + Buffer.push_back(static_cast((Value >> 8U) & 0xffU)); + Buffer.push_back(static_cast(Value & 0xffU)); + break; + default: + assert(0 && "invalid integer format length"); + return; + } } template -void -writeVectorInt(const std::vector* VectorData, std::vector& Buffer) -{ - if (VectorData) { - const std::vector& Vector = *VectorData; - writeInt((UInt32)Vector.size(), sizeof(UInt32), Buffer); - for (size_t i = 0; i < Vector.size(); ++i) { - writeInt(Vector[i], sizeof(T), Buffer); - } +void writeVectorInt(const std::vector *VectorData, + std::vector &Buffer) { + if (VectorData) { + const std::vector &Vector = *VectorData; + writeInt((UInt32)Vector.size(), sizeof(UInt32), Buffer); + for (size_t i = 0; i < Vector.size(); ++i) { + writeInt(Vector[i], sizeof(T), Buffer); } + } } -void -writeString(const String* StringData, std::vector& Buffer) -{ - const UInt32 len = (StringData != NULL) ? (UInt32)StringData->size() : 0; - writeInt(len, sizeof(len), Buffer); - if (len != 0) { - std::copy(StringData->begin(), StringData->end(), std::back_inserter(Buffer)); - } +void writeString(const String *StringData, std::vector &Buffer) { + const UInt32 len = (StringData != NULL) ? (UInt32)StringData->size() : 0; + writeInt(len, sizeof(len), Buffer); + if (len != 0) { + std::copy(StringData->begin(), StringData->end(), + std::back_inserter(Buffer)); + } } -} //namespace +} // namespace -void -ProtocolUtil::writef(synergy::IStream* stream, const char* fmt, ...) -{ - assert(stream != NULL); - assert(fmt != NULL); - LOG((CLOG_DEBUG2 "writef(%s)", fmt)); +void ProtocolUtil::writef(synergy::IStream *stream, const char *fmt, ...) { + assert(stream != NULL); + assert(fmt != NULL); + LOG((CLOG_DEBUG2 "writef(%s)", fmt)); + va_list args; + va_start(args, fmt); + UInt32 size = getLength(fmt, args); + va_end(args); + va_start(args, fmt); + vwritef(stream, fmt, size, args); + va_end(args); +} + +bool ProtocolUtil::readf(synergy::IStream *stream, const char *fmt, ...) { + bool result = false; + + if (stream && fmt) { + LOG((CLOG_DEBUG2 "readf(%s)", fmt)); va_list args; va_start(args, fmt); - UInt32 size = getLength(fmt, args); - va_end(args); - va_start(args, fmt); - vwritef(stream, fmt, size, args); - va_end(args); -} - -bool -ProtocolUtil::readf(synergy::IStream* stream, const char* fmt, ...) -{ - bool result = false; - - if (stream && fmt) { - LOG((CLOG_DEBUG2 "readf(%s)", fmt)); - va_list args; - va_start(args, fmt); - try { - vreadf(stream, fmt, args); - result = true; - } - catch (XIO&) { - result = false; - } - catch (const std::bad_alloc&) { - result = false; - } - va_end(args); - } - - return result; -} - -void -ProtocolUtil::vwritef(synergy::IStream* stream, - const char* fmt, UInt32 size, va_list args) -{ - assert(stream != NULL); - assert(fmt != NULL); - - // done if nothing to write - if (size == 0) { - return; - } - - // fill buffer - std::vector Buffer; - writef(Buffer, fmt, args); - try { - // write buffer - stream->write(Buffer.data(), size); - LOG((CLOG_DEBUG2 "wrote %d bytes", size)); - } - catch (const XBase& exception) { - LOG((CLOG_DEBUG2 "exception <%s> during wrote %d bytes into stream", exception.what(), size)); - throw; + vreadf(stream, fmt, args); + result = true; + } catch (XIO &) { + result = false; + } catch (const std::bad_alloc &) { + result = false; } + va_end(args); + } + + return result; } -void -ProtocolUtil::vreadf(synergy::IStream* stream, const char* fmt, va_list args) -{ - assert(stream != NULL); - assert(fmt != NULL); +void ProtocolUtil::vwritef(synergy::IStream *stream, const char *fmt, + UInt32 size, va_list args) { + assert(stream != NULL); + assert(fmt != NULL); - // begin scanning - while (*fmt) { - if (*fmt == '%') { - // format specifier. determine argument size. - ++fmt; - UInt32 len = eatLength(&fmt); - switch (*fmt) { - case 'i': { - void* destination = va_arg(args, void*); - switch (len) { - case 1: - // 1 byte integer - *static_cast(destination) = read1ByteInt(stream); - break; - case 2: - // 2 byte integer - *static_cast(destination) = read2BytesInt(stream); - break; - case 4: - // 4 byte integer - *static_cast(destination) = read4BytesInt(stream); - break; - default: - //the length is wrong - LOG((CLOG_ERR "read: length to be read is wrong: '%d' should be 1,2, or 4", len)); - assert(false); //assert for debugging - break; - } - break; - } + // done if nothing to write + if (size == 0) { + return; + } - case 'I': { - void* destination = va_arg(args, void*); - switch (len) { - case 1: - // 1 byte integer - readVector1ByteInt(stream, *static_cast*>(destination)); - break; - case 2: - // 2 byte integer - readVector2BytesInt(stream, *static_cast*>(destination)); - break; - case 4: - // 4 byte integer - readVector4BytesInt(stream, *static_cast*>(destination)); - break; - default: - //the length is wrong - LOG((CLOG_ERR "read: length to be read is wrong: '%d' should be 1,2, or 4", len)); - assert(false); //assert for debugging - break; - } - break; - } + // fill buffer + std::vector Buffer; + writef(Buffer, fmt, args); - case 's': { - String* destination = va_arg(args, String*); - readBytes(stream, len, destination); - break; - } - - case '%': - assert(len == 0); - break; - - default: - assert(0 && "invalid format specifier"); - } - - // next format character - ++fmt; - } - else { - // read next character - char buffer[1]; - read(stream, buffer, 1); - - // verify match - if (buffer[0] != *fmt) { - LOG((CLOG_DEBUG2 "readf: format mismatch: %c vs %c", *fmt, buffer[0])); - throw XIOReadMismatch(); - } - - // next format character - ++fmt; - } - } + try { + // write buffer + stream->write(Buffer.data(), size); + LOG((CLOG_DEBUG2 "wrote %d bytes", size)); + } catch (const XBase &exception) { + LOG((CLOG_DEBUG2 "exception <%s> during wrote %d bytes into stream", + exception.what(), size)); + throw; + } } -UInt32 -ProtocolUtil::getLength(const char* fmt, va_list args) -{ - UInt32 n = 0; - while (*fmt) { - if (*fmt == '%') { - // format specifier. determine argument size. - ++fmt; - UInt32 len = eatLength(&fmt); - switch (*fmt) { - case 'i': - assert(len == 1 || len == 2 || len == 4); - (void)va_arg(args, UInt32); - break; +void ProtocolUtil::vreadf(synergy::IStream *stream, const char *fmt, + va_list args) { + assert(stream != NULL); + assert(fmt != NULL); - case 'I': - assert(len == 1 || len == 2 || len == 4); - switch (len) { - case 1: - len = (UInt32)(va_arg(args, std::vector*))->size() + 4; - break; - - case 2: - len = 2 * (UInt32)(va_arg(args, std::vector*))->size() + 4; - break; - - case 4: - len = 4 * (UInt32)(va_arg(args, std::vector*))->size() + 4; - break; - } - break; - - case 's': - assert(len == 0); - len = (UInt32)(va_arg(args, String*))->size() + 4; - break; - - case 'S': - assert(len == 0); - len = va_arg(args, UInt32) + 4; - break; - - case '%': - assert(len == 0); - len = 1; - break; - - default: - assert(0 && "invalid format specifier"); - } - - // accumulate size - n += len; - ++fmt; + // begin scanning + while (*fmt) { + if (*fmt == '%') { + // format specifier. determine argument size. + ++fmt; + UInt32 len = eatLength(&fmt); + switch (*fmt) { + case 'i': { + void *destination = va_arg(args, void *); + switch (len) { + case 1: + // 1 byte integer + *static_cast(destination) = read1ByteInt(stream); + break; + case 2: + // 2 byte integer + *static_cast(destination) = read2BytesInt(stream); + break; + case 4: + // 4 byte integer + *static_cast(destination) = read4BytesInt(stream); + break; + default: + // the length is wrong + LOG((CLOG_ERR + "read: length to be read is wrong: '%d' should be 1,2, or 4", + len)); + assert(false); // assert for debugging + break; } - else { - // regular character - ++n; - ++fmt; + break; + } + + case 'I': { + void *destination = va_arg(args, void *); + switch (len) { + case 1: + // 1 byte integer + readVector1ByteInt(stream, + *static_cast *>(destination)); + break; + case 2: + // 2 byte integer + readVector2BytesInt(stream, + *static_cast *>(destination)); + break; + case 4: + // 4 byte integer + readVector4BytesInt(stream, + *static_cast *>(destination)); + break; + default: + // the length is wrong + LOG((CLOG_ERR + "read: length to be read is wrong: '%d' should be 1,2, or 4", + len)); + assert(false); // assert for debugging + break; } + break; + } + + case 's': { + String *destination = va_arg(args, String *); + readBytes(stream, len, destination); + break; + } + + case '%': + assert(len == 0); + break; + + default: + assert(0 && "invalid format specifier"); + } + + // next format character + ++fmt; + } else { + // read next character + char buffer[1]; + read(stream, buffer, 1); + + // verify match + if (buffer[0] != *fmt) { + LOG((CLOG_DEBUG2 "readf: format mismatch: %c vs %c", *fmt, buffer[0])); + throw XIOReadMismatch(); + } + + // next format character + ++fmt; } - return n; + } } +UInt32 ProtocolUtil::getLength(const char *fmt, va_list args) { + UInt32 n = 0; + while (*fmt) { + if (*fmt == '%') { + // format specifier. determine argument size. + ++fmt; + UInt32 len = eatLength(&fmt); + switch (*fmt) { + case 'i': + assert(len == 1 || len == 2 || len == 4); + (void)va_arg(args, UInt32); + break; + case 'I': + assert(len == 1 || len == 2 || len == 4); + switch (len) { + case 1: + len = (UInt32)(va_arg(args, std::vector *))->size() + 4; + break; -void -ProtocolUtil::writef(std::vector& buffer, const char* fmt, va_list args) -{ - while (*fmt) { - if (*fmt == '%') { - // format specifier. determine argument size. - ++fmt; - UInt32 len = eatLength(&fmt); - switch (*fmt) { - case 'i': { - const UInt32 v = va_arg(args, UInt32); - writeInt(v, len, buffer); - break; - } + case 2: + len = 2 * (UInt32)(va_arg(args, std::vector *))->size() + 4; + break; - case 'I': { - switch (len) { - case 1: { - // 1 byte integers - const std::vector* list = va_arg(args, const std::vector*); - writeVectorInt(list, buffer); - break; - } - - case 2: { - // 2 byte integers - const std::vector* list = va_arg(args, const std::vector*); - writeVectorInt(list, buffer); - break; - } - - case 4: { - // 4 byte integers - const std::vector* list = va_arg(args, const std::vector*); - writeVectorInt(list, buffer); - break; - } - - default: - assert(0 && "invalid integer vector format length"); - return; - } - break; - } - - case 's': { - assert(len == 0); - const String* src = va_arg(args, String*); - writeString(src, buffer); - break; - } - - case 'S': { - assert(len == 0); - const UInt32 len = va_arg(args, UInt32); - const UInt8* src = va_arg(args, UInt8*); - writeInt(len, sizeof(len), buffer); - std::copy(src, src + len, std::back_inserter(buffer)); - break; - } - - case '%': - assert(len == 0); - buffer.push_back('%'); - break; - - default: - assert(0 && "invalid format specifier"); - } - - // next format character - ++fmt; - } - else { - // copy regular character - buffer.push_back(*fmt++); + case 4: + len = 4 * (UInt32)(va_arg(args, std::vector *))->size() + 4; + break; } + break; + + case 's': + assert(len == 0); + len = (UInt32)(va_arg(args, String *))->size() + 4; + break; + + case 'S': + assert(len == 0); + len = va_arg(args, UInt32) + 4; + break; + + case '%': + assert(len == 0); + len = 1; + break; + + default: + assert(0 && "invalid format specifier"); + } + + // accumulate size + n += len; + ++fmt; + } else { + // regular character + ++n; + ++fmt; } + } + return n; } -UInt32 -ProtocolUtil::eatLength(const char** pfmt) -{ - const char* fmt = *pfmt; - UInt32 n = 0; - for (;;) { - UInt32 d; - switch (*fmt) { - case '0': d = 0; break; - case '1': d = 1; break; - case '2': d = 2; break; - case '3': d = 3; break; - case '4': d = 4; break; - case '5': d = 5; break; - case '6': d = 6; break; - case '7': d = 7; break; - case '8': d = 8; break; - case '9': d = 9; break; - default: *pfmt = fmt; return n; - } - n = 10 * n + d; - ++fmt; - } -} +void ProtocolUtil::writef(std::vector &buffer, const char *fmt, + va_list args) { + while (*fmt) { + if (*fmt == '%') { + // format specifier. determine argument size. + ++fmt; + UInt32 len = eatLength(&fmt); + switch (*fmt) { + case 'i': { + const UInt32 v = va_arg(args, UInt32); + writeInt(v, len, buffer); + break; + } -void -ProtocolUtil::read(synergy::IStream* stream, void* vbuffer, UInt32 count) -{ - assert(stream != NULL); - assert(vbuffer != NULL); - - UInt8* buffer = static_cast(vbuffer); - while (count > 0) { - // read more - UInt32 n = stream->read(buffer, count); - - // bail if stream has hungup - if (n == 0) { - LOG((CLOG_DEBUG2 "unexpected disconnect in readf(), %d bytes left", count)); - throw XIOEndOfStream(); + case 'I': { + switch (len) { + case 1: { + // 1 byte integers + const std::vector *list = + va_arg(args, const std::vector *); + writeVectorInt(list, buffer); + break; } - // prepare for next read - buffer += n; - count -= n; - } -} - -UInt8 ProtocolUtil::read1ByteInt(synergy::IStream * stream) -{ - const UInt32 BufferSize = 1; - std::array buffer = {}; - read(stream, buffer.data(), BufferSize); - - UInt8 Result = buffer[0]; - LOG((CLOG_DEBUG2 "readf: read 1 byte integer: %d (0x%x)", Result, Result)); - - return Result; -} - -UInt16 ProtocolUtil::read2BytesInt(synergy::IStream * stream) -{ - const UInt32 BufferSize = 2; - std::array buffer = {}; - read(stream, buffer.data(), BufferSize); - - UInt16 Result = static_cast((static_cast(buffer[0]) << 8) | static_cast(buffer[1])); - LOG((CLOG_DEBUG2 "readf: read 2 byte integer: %d (0x%x)", Result, Result)); - - return Result; -} - -UInt32 ProtocolUtil::read4BytesInt(synergy::IStream * stream) -{ - const int BufferSize = 4; - std::array buffer = {}; - read(stream, buffer.data(), BufferSize); - - UInt32 Result = (static_cast(buffer[0]) << 24) | - (static_cast(buffer[1]) << 16) | - (static_cast(buffer[2]) << 8) | - (static_cast(buffer[3])); - - LOG((CLOG_DEBUG2 "readf: read 4 byte integer: %d (0x%x)", Result, Result)); - - return Result; -} - -void ProtocolUtil::readVector1ByteInt(synergy::IStream* stream, std::vector& destination) -{ - UInt32 size = read4BytesInt(stream); - for (UInt32 i = 0; i < size; ++i) { - destination.push_back(read1ByteInt(stream)); - } -} - -void ProtocolUtil::readVector2BytesInt(synergy::IStream* stream, std::vector& destination) -{ - UInt32 size = read4BytesInt(stream); - for (UInt32 i = 0; i < size; ++i) { - destination.push_back(read2BytesInt(stream)); - } -} - -void ProtocolUtil::readVector4BytesInt(synergy::IStream* stream, std::vector& destination) -{ - UInt32 size = read4BytesInt(stream); - for (UInt32 i = 0; i < size; ++i) { - destination.push_back(read4BytesInt(stream)); - } -} - -void ProtocolUtil::readBytes(synergy::IStream * stream, UInt32 len, String* destination) { - assert(len == 0); - - // read the string length - UInt8 buffer[128]; - len = read4BytesInt(stream); - // use a fixed size buffer if its big enough - const bool useFixed = (len <= sizeof(buffer)); - - // allocate a buffer to read the data - UInt8* sBuffer = buffer; - if (!useFixed) { - try{ - sBuffer = new UInt8[len]; + case 2: { + // 2 byte integers + const std::vector *list = + va_arg(args, const std::vector *); + writeVectorInt(list, buffer); + break; } - catch (std::bad_alloc & exception) { - // Added try catch due to GHSA-chfm-333q-gfpp - LOG((CLOG_ERR "bad alloc, unable to allocate memory %d bytes", len)); - LOG((CLOG_DEBUG "bad_alloc detected: is there enough memory?")); - throw exception; + + case 4: { + // 4 byte integers + const std::vector *list = + va_arg(args, const std::vector *); + writeVectorInt(list, buffer); + break; } + + default: + assert(0 && "invalid integer vector format length"); + return; + } + break; + } + + case 's': { + assert(len == 0); + const String *src = va_arg(args, String *); + writeString(src, buffer); + break; + } + + case 'S': { + assert(len == 0); + const UInt32 len = va_arg(args, UInt32); + const UInt8 *src = va_arg(args, UInt8 *); + writeInt(len, sizeof(len), buffer); + std::copy(src, src + len, std::back_inserter(buffer)); + break; + } + + case '%': + assert(len == 0); + buffer.push_back('%'); + break; + + default: + assert(0 && "invalid format specifier"); + } + + // next format character + ++fmt; + } else { + // copy regular character + buffer.push_back(*fmt++); + } + } +} + +UInt32 ProtocolUtil::eatLength(const char **pfmt) { + const char *fmt = *pfmt; + UInt32 n = 0; + for (;;) { + UInt32 d; + switch (*fmt) { + case '0': + d = 0; + break; + case '1': + d = 1; + break; + case '2': + d = 2; + break; + case '3': + d = 3; + break; + case '4': + d = 4; + break; + case '5': + d = 5; + break; + case '6': + d = 6; + break; + case '7': + d = 7; + break; + case '8': + d = 8; + break; + case '9': + d = 9; + break; + default: + *pfmt = fmt; + return n; + } + n = 10 * n + d; + ++fmt; + } +} + +void ProtocolUtil::read(synergy::IStream *stream, void *vbuffer, UInt32 count) { + assert(stream != NULL); + assert(vbuffer != NULL); + + UInt8 *buffer = static_cast(vbuffer); + while (count > 0) { + // read more + UInt32 n = stream->read(buffer, count); + + // bail if stream has hungup + if (n == 0) { + LOG((CLOG_DEBUG2 "unexpected disconnect in readf(), %d bytes left", + count)); + throw XIOEndOfStream(); } - // read the data + // prepare for next read + buffer += n; + count -= n; + } +} + +UInt8 ProtocolUtil::read1ByteInt(synergy::IStream *stream) { + const UInt32 BufferSize = 1; + std::array buffer = {}; + read(stream, buffer.data(), BufferSize); + + UInt8 Result = buffer[0]; + LOG((CLOG_DEBUG2 "readf: read 1 byte integer: %d (0x%x)", Result, Result)); + + return Result; +} + +UInt16 ProtocolUtil::read2BytesInt(synergy::IStream *stream) { + const UInt32 BufferSize = 2; + std::array buffer = {}; + read(stream, buffer.data(), BufferSize); + + UInt16 Result = static_cast((static_cast(buffer[0]) << 8) | + static_cast(buffer[1])); + LOG((CLOG_DEBUG2 "readf: read 2 byte integer: %d (0x%x)", Result, Result)); + + return Result; +} + +UInt32 ProtocolUtil::read4BytesInt(synergy::IStream *stream) { + const int BufferSize = 4; + std::array buffer = {}; + read(stream, buffer.data(), BufferSize); + + UInt32 Result = (static_cast(buffer[0]) << 24) | + (static_cast(buffer[1]) << 16) | + (static_cast(buffer[2]) << 8) | + (static_cast(buffer[3])); + + LOG((CLOG_DEBUG2 "readf: read 4 byte integer: %d (0x%x)", Result, Result)); + + return Result; +} + +void ProtocolUtil::readVector1ByteInt(synergy::IStream *stream, + std::vector &destination) { + UInt32 size = read4BytesInt(stream); + for (UInt32 i = 0; i < size; ++i) { + destination.push_back(read1ByteInt(stream)); + } +} + +void ProtocolUtil::readVector2BytesInt(synergy::IStream *stream, + std::vector &destination) { + UInt32 size = read4BytesInt(stream); + for (UInt32 i = 0; i < size; ++i) { + destination.push_back(read2BytesInt(stream)); + } +} + +void ProtocolUtil::readVector4BytesInt(synergy::IStream *stream, + std::vector &destination) { + UInt32 size = read4BytesInt(stream); + for (UInt32 i = 0; i < size; ++i) { + destination.push_back(read4BytesInt(stream)); + } +} + +void ProtocolUtil::readBytes(synergy::IStream *stream, UInt32 len, + String *destination) { + assert(len == 0); + + // read the string length + UInt8 buffer[128]; + len = read4BytesInt(stream); + // use a fixed size buffer if its big enough + const bool useFixed = (len <= sizeof(buffer)); + + // allocate a buffer to read the data + UInt8 *sBuffer = buffer; + if (!useFixed) { try { - read(stream, sBuffer, len); - } - catch (...) { - if (!useFixed) { - delete[] sBuffer; - } - throw; + sBuffer = new UInt8[len]; + } catch (std::bad_alloc &exception) { + // Added try catch due to GHSA-chfm-333q-gfpp + LOG((CLOG_ERR "bad alloc, unable to allocate memory %d bytes", len)); + LOG((CLOG_DEBUG "bad_alloc detected: is there enough memory?")); + throw exception; } + } - LOG((CLOG_DEBUG2 "readf: read %d byte string", len)); - - // save the data - - if (destination){ - destination->assign((const char*)sBuffer, len); - } - - // release the buffer + // read the data + try { + read(stream, sBuffer, len); + } catch (...) { if (!useFixed) { - delete[] sBuffer; + delete[] sBuffer; } -} + throw; + } + LOG((CLOG_DEBUG2 "readf: read %d byte string", len)); + + // save the data + + if (destination) { + destination->assign((const char *)sBuffer, len); + } + + // release the buffer + if (!useFixed) { + delete[] sBuffer; + } +} // // XIOReadMismatch // -String -XIOReadMismatch::getWhat() const throw() -{ - return format("XIOReadMismatch", "ProtocolUtil::readf() mismatch"); +String XIOReadMismatch::getWhat() const throw() { + return format("XIOReadMismatch", "ProtocolUtil::readf() mismatch"); } diff --git a/src/lib/synergy/ProtocolUtil.h b/src/lib/synergy/ProtocolUtil.h index c903366ad..95dbcc265 100644 --- a/src/lib/synergy/ProtocolUtil.h +++ b/src/lib/synergy/ProtocolUtil.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -18,12 +18,14 @@ #pragma once -#include "io/XIO.h" #include "base/EventTypes.h" +#include "io/XIO.h" #include -namespace synergy { class IStream; } +namespace synergy { +class IStream; +} //! Synergy protocol utilities /*! @@ -32,75 +34,72 @@ protocol. */ class ProtocolUtil { public: - //! Write formatted data - /*! - Write formatted binary data to a stream. \c fmt consists of - regular characters and format specifiers. Format specifiers - begin with \%. All characters not part of a format specifier - are regular and are transmitted unchanged. - - Format specifiers are: - - \%\% -- literal `\%' - - \%1i -- converts integer argument to 1 byte integer - - \%2i -- converts integer argument to 2 byte integer in NBO - - \%4i -- converts integer argument to 4 byte integer in NBO - - \%1I -- converts std::vector* to 1 byte integers - - \%2I -- converts std::vector* to 2 byte integers in NBO - - \%4I -- converts std::vector* to 4 byte integers in NBO - - \%s -- converts String* to stream of bytes - - \%S -- converts integer N and const UInt8* to stream of N bytes - */ - static void writef(synergy::IStream*, - const char* fmt, ...); + //! Write formatted data + /*! + Write formatted binary data to a stream. \c fmt consists of + regular characters and format specifiers. Format specifiers + begin with \%. All characters not part of a format specifier + are regular and are transmitted unchanged. - //! Read formatted data - /*! - Read formatted binary data from a buffer. This performs the - reverse operation of writef(). Returns true if the entire - format was successfully parsed, false otherwise. - - Format specifiers are: - - \%\% -- read (and discard) a literal `\%' - - \%1i -- reads a 1 byte integer; argument is a SInt32* or UInt32* - - \%2i -- reads an NBO 2 byte integer; arg is SInt32* or UInt32* - - \%4i -- reads an NBO 4 byte integer; arg is SInt32* or UInt32* - - \%1I -- reads 1 byte integers; arg is std::vector* - - \%2I -- reads NBO 2 byte integers; arg is std::vector* - - \%4I -- reads NBO 4 byte integers; arg is std::vector* - - \%s -- reads bytes; argument must be a String*, \b not a char* - */ - static bool readf(synergy::IStream*, - const char* fmt, ...); + Format specifiers are: + - \%\% -- literal `\%' + - \%1i -- converts integer argument to 1 byte integer + - \%2i -- converts integer argument to 2 byte integer in NBO + - \%4i -- converts integer argument to 4 byte integer in NBO + - \%1I -- converts std::vector* to 1 byte integers + - \%2I -- converts std::vector* to 2 byte integers in NBO + - \%4I -- converts std::vector* to 4 byte integers in NBO + - \%s -- converts String* to stream of bytes + - \%S -- converts integer N and const UInt8* to stream of N bytes + */ + static void writef(synergy::IStream *, const char *fmt, ...); + + //! Read formatted data + /*! + Read formatted binary data from a buffer. This performs the + reverse operation of writef(). Returns true if the entire + format was successfully parsed, false otherwise. + + Format specifiers are: + - \%\% -- read (and discard) a literal `\%' + - \%1i -- reads a 1 byte integer; argument is a SInt32* or UInt32* + - \%2i -- reads an NBO 2 byte integer; arg is SInt32* or UInt32* + - \%4i -- reads an NBO 4 byte integer; arg is SInt32* or UInt32* + - \%1I -- reads 1 byte integers; arg is std::vector* + - \%2I -- reads NBO 2 byte integers; arg is std::vector* + - \%4I -- reads NBO 4 byte integers; arg is std::vector* + - \%s -- reads bytes; argument must be a String*, \b not a char* + */ + static bool readf(synergy::IStream *, const char *fmt, ...); private: - static void vwritef(synergy::IStream*, - const char* fmt, UInt32 size, va_list); - static void vreadf(synergy::IStream*, - const char* fmt, va_list); + static void vwritef(synergy::IStream *, const char *fmt, UInt32 size, + va_list); + static void vreadf(synergy::IStream *, const char *fmt, va_list); - static UInt32 getLength(const char* fmt, va_list); - static void writef(std::vector&, const char* fmt, va_list); - static UInt32 eatLength(const char** fmt); - static void read(synergy::IStream*, void*, UInt32); + static UInt32 getLength(const char *fmt, va_list); + static void writef(std::vector &, const char *fmt, va_list); + static UInt32 eatLength(const char **fmt); + static void read(synergy::IStream *, void *, UInt32); - /** - * @brief Handles 1,2, or 4 byte Integers - */ - static UInt8 read1ByteInt(synergy::IStream * stream); - static UInt16 read2BytesInt(synergy::IStream * stream); - static UInt32 read4BytesInt(synergy::IStream * stream); + /** + * @brief Handles 1,2, or 4 byte Integers + */ + static UInt8 read1ByteInt(synergy::IStream *stream); + static UInt16 read2BytesInt(synergy::IStream *stream); + static UInt32 read4BytesInt(synergy::IStream *stream); - /** - * @brief Handles a Vector of integers - */ - static void readVector1ByteInt(synergy::IStream*, std::vector&); - static void readVector2BytesInt(synergy::IStream*, std::vector&); - static void readVector4BytesInt(synergy::IStream*, std::vector&); + /** + * @brief Handles a Vector of integers + */ + static void readVector1ByteInt(synergy::IStream *, std::vector &); + static void readVector2BytesInt(synergy::IStream *, std::vector &); + static void readVector4BytesInt(synergy::IStream *, std::vector &); - /** - * @brief Handles an array of bytes - */ - static void readBytes(synergy::IStream*, UInt32, String*); + /** + * @brief Handles an array of bytes + */ + static void readBytes(synergy::IStream *, UInt32, String *); }; //! Mismatched read exception @@ -110,6 +109,6 @@ match the format. */ class XIOReadMismatch : public XIO { public: - // XBase overrides - virtual String getWhat() const throw(); + // XBase overrides + virtual String getWhat() const throw(); }; diff --git a/src/lib/synergy/Screen.cpp b/src/lib/synergy/Screen.cpp index b2ce9ef22..7fe21ef34 100644 --- a/src/lib/synergy/Screen.cpp +++ b/src/lib/synergy/Screen.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2003 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 LICENSE 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 @@ -17,12 +17,12 @@ */ #include "synergy/Screen.h" +#include "base/IEventQueue.h" +#include "base/Log.h" +#include "base/TMethodEventJob.h" +#include "server/ClientProxy.h" #include "synergy/IPlatformScreen.h" #include "synergy/protocol_types.h" -#include "base/Log.h" -#include "base/IEventQueue.h" -#include "server/ClientProxy.h" -#include "base/TMethodEventJob.h" namespace synergy { @@ -30,502 +30,370 @@ namespace synergy { // Screen // -Screen::Screen(IPlatformScreen* platformScreen, IEventQueue* events) : - m_screen(platformScreen), - m_isPrimary(platformScreen->isPrimary()), - m_enabled(false), - m_entered(m_isPrimary), - m_fakeInput(false), - m_events(events), - m_mock(false), - m_enableDragDrop(false) -{ - assert(m_screen != NULL); +Screen::Screen(IPlatformScreen *platformScreen, IEventQueue *events) + : m_screen(platformScreen), m_isPrimary(platformScreen->isPrimary()), + m_enabled(false), m_entered(m_isPrimary), m_fakeInput(false), + m_events(events), m_mock(false), m_enableDragDrop(false) { + assert(m_screen != NULL); - // reset options - resetOptions(); + // reset options + resetOptions(); - LOG((CLOG_DEBUG "opened display")); + LOG((CLOG_DEBUG "opened display")); } -Screen::~Screen() -{ - if (m_mock) { - return; - } +Screen::~Screen() { + if (m_mock) { + return; + } - if (m_enabled) { - disable(); - } - assert(!m_enabled); - assert(m_entered == m_isPrimary); - delete m_screen; - LOG((CLOG_DEBUG "closed display")); + if (m_enabled) { + disable(); + } + assert(!m_enabled); + assert(m_entered == m_isPrimary); + delete m_screen; + LOG((CLOG_DEBUG "closed display")); } -void -Screen::enable() -{ - assert(!m_enabled); +void Screen::enable() { + assert(!m_enabled); - m_screen->updateKeyMap(); - m_screen->updateKeyState(); - m_screen->enable(); - if (m_isPrimary) { - enablePrimary(); - } - else { - enableSecondary(); - } + m_screen->updateKeyMap(); + m_screen->updateKeyState(); + m_screen->enable(); + if (m_isPrimary) { + enablePrimary(); + } else { + enableSecondary(); + } - // note activation - m_enabled = true; + // note activation + m_enabled = true; } -void -Screen::disable() -{ - assert(m_enabled); +void Screen::disable() { + assert(m_enabled); - if (!m_isPrimary && m_entered) { - leave(); - } - else if (m_isPrimary && !m_entered) { - enter(0); - } - m_screen->disable(); - if (m_isPrimary) { - disablePrimary(); - } - else { - disableSecondary(); - } + if (!m_isPrimary && m_entered) { + leave(); + } else if (m_isPrimary && !m_entered) { + enter(0); + } + m_screen->disable(); + if (m_isPrimary) { + disablePrimary(); + } else { + disableSecondary(); + } - // note deactivation - m_enabled = false; + // note deactivation + m_enabled = false; } -void -Screen::enter(KeyModifierMask toggleMask) -{ - assert(m_entered == false); - LOG((CLOG_INFO "entering screen")); +void Screen::enter(KeyModifierMask toggleMask) { + assert(m_entered == false); + LOG((CLOG_INFO "entering screen")); - // now on screen - m_entered = true; + // now on screen + m_entered = true; - m_screen->enter(); - if (m_isPrimary) { - enterPrimary(); - } - else { - enterSecondary(toggleMask); - } + m_screen->enter(); + if (m_isPrimary) { + enterPrimary(); + } else { + enterSecondary(toggleMask); + } } -bool -Screen::leave() -{ - assert(m_entered == true); - LOG((CLOG_INFO "leaving screen")); +bool Screen::leave() { + assert(m_entered == true); + LOG((CLOG_INFO "leaving screen")); - if (!m_screen->leave()) { - return false; - } - if (m_isPrimary) { - leavePrimary(); - } - else { - leaveSecondary(); - } - - // make sure our idea of clipboard ownership is correct - m_screen->checkClipboards(); - - // now not on screen - m_entered = false; - - return true; -} - -void -Screen::reconfigure(UInt32 activeSides) -{ - assert(m_isPrimary); - m_screen->reconfigure(activeSides); -} - -void -Screen::warpCursor(SInt32 x, SInt32 y) -{ - assert(m_isPrimary); - m_screen->warpCursor(x, y); -} - -void -Screen::setClipboard(ClipboardID id, const IClipboard* clipboard) -{ - m_screen->setClipboard(id, clipboard); -} - -void -Screen::grabClipboard(ClipboardID id) -{ - m_screen->setClipboard(id, NULL); -} - -void -Screen::screensaver(bool) const -{ - // do nothing -} - -void -Screen::keyDown(KeyID id, KeyModifierMask mask, KeyButton button, const String &lang) -{ - // check for ctrl+alt+del emulation - if (id == kKeyDelete && - (mask & (KeyModifierControl | KeyModifierAlt)) == - (KeyModifierControl | KeyModifierAlt)) { - LOG((CLOG_DEBUG "emulating ctrl+alt+del press")); - if (m_screen->fakeCtrlAltDel()) { - return; - } - } - m_screen->fakeKeyDown(id, mask, button, lang); -} - -void -Screen::keyRepeat(KeyID id, - KeyModifierMask mask, SInt32 count, KeyButton button, const String& lang) -{ - assert(!m_isPrimary); - m_screen->fakeKeyRepeat(id, mask, count, button, lang); -} - -void -Screen::keyUp(KeyID, KeyModifierMask, KeyButton button) -{ - m_screen->fakeKeyUp(button); -} - -void -Screen::mouseDown(ButtonID button) -{ - m_screen->fakeMouseButton(button, true); -} - -void -Screen::mouseUp(ButtonID button) -{ - m_screen->fakeMouseButton(button, false); -} - -void -Screen::mouseMove(SInt32 x, SInt32 y) -{ - assert(!m_isPrimary); - m_screen->fakeMouseMove(x, y); -} - -void -Screen::mouseRelativeMove(SInt32 dx, SInt32 dy) -{ - assert(!m_isPrimary); - m_screen->fakeMouseRelativeMove(dx, dy); -} - -void -Screen::mouseWheel(SInt32 xDelta, SInt32 yDelta) const -{ - assert(!m_isPrimary); - m_screen->fakeMouseWheel(xDelta, yDelta); -} - -void -Screen::resetOptions() -{ - // reset options - m_halfDuplex = 0; - - // let screen handle its own options - m_screen->resetOptions(); -} - -void -Screen::setOptions(const OptionsList& options) -{ - // update options - for (UInt32 i = 0, n = (UInt32)options.size(); i < n; i += 2) { - if (options[i] == kOptionHalfDuplexCapsLock) { - if (options[i + 1] != 0) { - m_halfDuplex |= KeyModifierCapsLock; - } - else { - m_halfDuplex &= ~KeyModifierCapsLock; - } - LOG((CLOG_DEBUG1 "half-duplex caps-lock %s", ((m_halfDuplex & KeyModifierCapsLock) != 0) ? "on" : "off")); - } - else if (options[i] == kOptionHalfDuplexNumLock) { - if (options[i + 1] != 0) { - m_halfDuplex |= KeyModifierNumLock; - } - else { - m_halfDuplex &= ~KeyModifierNumLock; - } - LOG((CLOG_DEBUG1 "half-duplex num-lock %s", ((m_halfDuplex & KeyModifierNumLock) != 0) ? "on" : "off")); - } - else if (options[i] == kOptionHalfDuplexScrollLock) { - if (options[i + 1] != 0) { - m_halfDuplex |= KeyModifierScrollLock; - } - else { - m_halfDuplex &= ~KeyModifierScrollLock; - } - LOG((CLOG_DEBUG1 "half-duplex scroll-lock %s", ((m_halfDuplex & KeyModifierScrollLock) != 0) ? "on" : "off")); - } - } - - // update half-duplex options - m_screen->setHalfDuplexMask(m_halfDuplex); - - // let screen handle its own options - m_screen->setOptions(options); -} - -void -Screen::setSequenceNumber(UInt32 seqNum) -{ - m_screen->setSequenceNumber(seqNum); -} - -UInt32 -Screen::registerHotKey(KeyID key, KeyModifierMask mask) -{ - return m_screen->registerHotKey(key, mask); -} - -void -Screen::unregisterHotKey(UInt32 id) -{ - m_screen->unregisterHotKey(id); -} - -void -Screen::fakeInputBegin() -{ - assert(!m_fakeInput); - - m_fakeInput = true; - m_screen->fakeInputBegin(); -} - -void -Screen::fakeInputEnd() -{ - assert(m_fakeInput); - - m_fakeInput = false; - m_screen->fakeInputEnd(); -} - -bool -Screen::isOnScreen() const -{ - return m_entered; -} - -bool -Screen::isLockedToScreen() const -{ - // check for pressed mouse buttons - // HACK: commented out as it breaks new drag drop feature - UInt32 buttonID = 0; - - if (m_screen->isAnyMouseButtonDown(buttonID)) { - if (buttonID != kButtonLeft) { - LOG((CLOG_DEBUG "locked by mouse buttonID: %d", buttonID)); - } - - if (m_enableDragDrop) { - return (buttonID == kButtonLeft) ? false : true; - } - else { - return true; - } - } - - // not locked + if (!m_screen->leave()) { return false; + } + if (m_isPrimary) { + leavePrimary(); + } else { + leaveSecondary(); + } + + // make sure our idea of clipboard ownership is correct + m_screen->checkClipboards(); + + // now not on screen + m_entered = false; + + return true; } -SInt32 -Screen::getJumpZoneSize() const -{ - if (!m_isPrimary) { - return 0; +void Screen::reconfigure(UInt32 activeSides) { + assert(m_isPrimary); + m_screen->reconfigure(activeSides); +} + +void Screen::warpCursor(SInt32 x, SInt32 y) { + assert(m_isPrimary); + m_screen->warpCursor(x, y); +} + +void Screen::setClipboard(ClipboardID id, const IClipboard *clipboard) { + m_screen->setClipboard(id, clipboard); +} + +void Screen::grabClipboard(ClipboardID id) { m_screen->setClipboard(id, NULL); } + +void Screen::screensaver(bool) const { + // do nothing +} + +void Screen::keyDown(KeyID id, KeyModifierMask mask, KeyButton button, + const String &lang) { + // check for ctrl+alt+del emulation + if (id == kKeyDelete && (mask & (KeyModifierControl | KeyModifierAlt)) == + (KeyModifierControl | KeyModifierAlt)) { + LOG((CLOG_DEBUG "emulating ctrl+alt+del press")); + if (m_screen->fakeCtrlAltDel()) { + return; } - else { - return m_screen->getJumpZoneSize(); + } + m_screen->fakeKeyDown(id, mask, button, lang); +} + +void Screen::keyRepeat(KeyID id, KeyModifierMask mask, SInt32 count, + KeyButton button, const String &lang) { + assert(!m_isPrimary); + m_screen->fakeKeyRepeat(id, mask, count, button, lang); +} + +void Screen::keyUp(KeyID, KeyModifierMask, KeyButton button) { + m_screen->fakeKeyUp(button); +} + +void Screen::mouseDown(ButtonID button) { + m_screen->fakeMouseButton(button, true); +} + +void Screen::mouseUp(ButtonID button) { + m_screen->fakeMouseButton(button, false); +} + +void Screen::mouseMove(SInt32 x, SInt32 y) { + assert(!m_isPrimary); + m_screen->fakeMouseMove(x, y); +} + +void Screen::mouseRelativeMove(SInt32 dx, SInt32 dy) { + assert(!m_isPrimary); + m_screen->fakeMouseRelativeMove(dx, dy); +} + +void Screen::mouseWheel(SInt32 xDelta, SInt32 yDelta) const { + assert(!m_isPrimary); + m_screen->fakeMouseWheel(xDelta, yDelta); +} + +void Screen::resetOptions() { + // reset options + m_halfDuplex = 0; + + // let screen handle its own options + m_screen->resetOptions(); +} + +void Screen::setOptions(const OptionsList &options) { + // update options + for (UInt32 i = 0, n = (UInt32)options.size(); i < n; i += 2) { + if (options[i] == kOptionHalfDuplexCapsLock) { + if (options[i + 1] != 0) { + m_halfDuplex |= KeyModifierCapsLock; + } else { + m_halfDuplex &= ~KeyModifierCapsLock; + } + LOG((CLOG_DEBUG1 "half-duplex caps-lock %s", + ((m_halfDuplex & KeyModifierCapsLock) != 0) ? "on" : "off")); + } else if (options[i] == kOptionHalfDuplexNumLock) { + if (options[i + 1] != 0) { + m_halfDuplex |= KeyModifierNumLock; + } else { + m_halfDuplex &= ~KeyModifierNumLock; + } + LOG((CLOG_DEBUG1 "half-duplex num-lock %s", + ((m_halfDuplex & KeyModifierNumLock) != 0) ? "on" : "off")); + } else if (options[i] == kOptionHalfDuplexScrollLock) { + if (options[i + 1] != 0) { + m_halfDuplex |= KeyModifierScrollLock; + } else { + m_halfDuplex &= ~KeyModifierScrollLock; + } + LOG((CLOG_DEBUG1 "half-duplex scroll-lock %s", + ((m_halfDuplex & KeyModifierScrollLock) != 0) ? "on" : "off")); } + } + + // update half-duplex options + m_screen->setHalfDuplexMask(m_halfDuplex); + + // let screen handle its own options + m_screen->setOptions(options); } -void -Screen::getCursorCenter(SInt32& x, SInt32& y) const -{ - m_screen->getCursorCenter(x, y); +void Screen::setSequenceNumber(UInt32 seqNum) { + m_screen->setSequenceNumber(seqNum); } -KeyModifierMask -Screen::getActiveModifiers() const -{ - return m_screen->getActiveModifiers(); +UInt32 Screen::registerHotKey(KeyID key, KeyModifierMask mask) { + return m_screen->registerHotKey(key, mask); } -KeyModifierMask -Screen::pollActiveModifiers() const -{ - return m_screen->pollActiveModifiers(); +void Screen::unregisterHotKey(UInt32 id) { m_screen->unregisterHotKey(id); } + +void Screen::fakeInputBegin() { + assert(!m_fakeInput); + + m_fakeInput = true; + m_screen->fakeInputBegin(); } -bool -Screen::isDraggingStarted() const -{ - return m_screen->isDraggingStarted(); +void Screen::fakeInputEnd() { + assert(m_fakeInput); + + m_fakeInput = false; + m_screen->fakeInputEnd(); } -bool -Screen::isFakeDraggingStarted() const -{ - return m_screen->isFakeDraggingStarted(); -} +bool Screen::isOnScreen() const { return m_entered; } -void -Screen::setDraggingStarted(bool started) -{ - m_screen->setDraggingStarted(started); -} +bool Screen::isLockedToScreen() const { + // check for pressed mouse buttons + // HACK: commented out as it breaks new drag drop feature + UInt32 buttonID = 0; -void -Screen::startDraggingFiles(DragFileList& fileList) -{ - m_screen->fakeDraggingFiles(fileList); -} - -void -Screen::setEnableDragDrop(bool enabled) -{ - m_enableDragDrop = enabled; -} - -String& -Screen::getDraggingFilename() const -{ - return m_screen->getDraggingFilename(); -} - -void -Screen::clearDraggingFilename() -{ - m_screen->clearDraggingFilename(); -} - -const String& -Screen::getDropTarget() const -{ - return m_screen->getDropTarget(); -} - -void* -Screen::getEventTarget() const -{ - return m_screen; -} - -bool -Screen::getClipboard(ClipboardID id, IClipboard* clipboard) const -{ - return m_screen->getClipboard(id, clipboard); -} - -void -Screen::getShape(SInt32& x, SInt32& y, SInt32& w, SInt32& h) const -{ - m_screen->getShape(x, y, w, h); -} - -void -Screen::getCursorPos(SInt32& x, SInt32& y) const -{ - m_screen->getCursorPos(x, y); -} - -void -Screen::enablePrimary() -{ - // get notified of screen saver activation/deactivation - m_screen->openScreensaver(true); - - // claim screen changed size - m_events->addEvent(Event(m_events->forIScreen().shapeChanged(), getEventTarget())); -} - -void -Screen::enableSecondary() -{ - // assume primary has all clipboards - for (ClipboardID id = 0; id < kClipboardEnd; ++id) { - grabClipboard(id); + if (m_screen->isAnyMouseButtonDown(buttonID)) { + if (buttonID != kButtonLeft) { + LOG((CLOG_DEBUG "locked by mouse buttonID: %d", buttonID)); } + if (m_enableDragDrop) { + return (buttonID == kButtonLeft) ? false : true; + } else { + return true; + } + } + + // not locked + return false; } -void -Screen::disablePrimary() -{ - // done with screen saver - m_screen->closeScreensaver(); +SInt32 Screen::getJumpZoneSize() const { + if (!m_isPrimary) { + return 0; + } else { + return m_screen->getJumpZoneSize(); + } } -void -Screen::disableSecondary() -{ - // done with screen saver - m_screen->closeScreensaver(); +void Screen::getCursorCenter(SInt32 &x, SInt32 &y) const { + m_screen->getCursorCenter(x, y); } -void -Screen::enterPrimary() -{ - // do nothing +KeyModifierMask Screen::getActiveModifiers() const { + return m_screen->getActiveModifiers(); } -void -Screen::enterSecondary(KeyModifierMask) -{ - // do nothing +KeyModifierMask Screen::pollActiveModifiers() const { + return m_screen->pollActiveModifiers(); } -void -Screen::leavePrimary() -{ - // we don't track keys while on the primary screen so update our - // idea of them now. this is particularly to update the state of - // the toggle modifiers. - m_screen->updateKeyState(); +bool Screen::isDraggingStarted() const { return m_screen->isDraggingStarted(); } + +bool Screen::isFakeDraggingStarted() const { + return m_screen->isFakeDraggingStarted(); } -void -Screen::leaveSecondary() -{ - // release any keys we think are still down - m_screen->fakeAllKeysUp(); +void Screen::setDraggingStarted(bool started) { + m_screen->setDraggingStarted(started); } -String -Screen::getSecureInputApp() const -{ - return m_screen->getSecureInputApp(); +void Screen::startDraggingFiles(DragFileList &fileList) { + m_screen->fakeDraggingFiles(fileList); } +void Screen::setEnableDragDrop(bool enabled) { m_enableDragDrop = enabled; } + +String &Screen::getDraggingFilename() const { + return m_screen->getDraggingFilename(); } + +void Screen::clearDraggingFilename() { m_screen->clearDraggingFilename(); } + +const String &Screen::getDropTarget() const { + return m_screen->getDropTarget(); +} + +void *Screen::getEventTarget() const { return m_screen; } + +bool Screen::getClipboard(ClipboardID id, IClipboard *clipboard) const { + return m_screen->getClipboard(id, clipboard); +} + +void Screen::getShape(SInt32 &x, SInt32 &y, SInt32 &w, SInt32 &h) const { + m_screen->getShape(x, y, w, h); +} + +void Screen::getCursorPos(SInt32 &x, SInt32 &y) const { + m_screen->getCursorPos(x, y); +} + +void Screen::enablePrimary() { + // get notified of screen saver activation/deactivation + m_screen->openScreensaver(true); + + // claim screen changed size + m_events->addEvent( + Event(m_events->forIScreen().shapeChanged(), getEventTarget())); +} + +void Screen::enableSecondary() { + // assume primary has all clipboards + for (ClipboardID id = 0; id < kClipboardEnd; ++id) { + grabClipboard(id); + } +} + +void Screen::disablePrimary() { + // done with screen saver + m_screen->closeScreensaver(); +} + +void Screen::disableSecondary() { + // done with screen saver + m_screen->closeScreensaver(); +} + +void Screen::enterPrimary() { + // do nothing +} + +void Screen::enterSecondary(KeyModifierMask) { + // do nothing +} + +void Screen::leavePrimary() { + // we don't track keys while on the primary screen so update our + // idea of them now. this is particularly to update the state of + // the toggle modifiers. + m_screen->updateKeyState(); +} + +void Screen::leaveSecondary() { + // release any keys we think are still down + m_screen->fakeAllKeysUp(); +} + +String Screen::getSecureInputApp() const { + return m_screen->getSecureInputApp(); +} + +} // namespace synergy diff --git a/src/lib/synergy/Screen.h b/src/lib/synergy/Screen.h index 6ca5073c7..31b51c971 100644 --- a/src/lib/synergy/Screen.h +++ b/src/lib/synergy/Screen.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -18,13 +18,13 @@ #pragma once +#include "base/String.h" #include "synergy/DragInformation.h" -#include "synergy/clipboard_types.h" #include "synergy/IScreen.h" +#include "synergy/clipboard_types.h" #include "synergy/key_types.h" #include "synergy/mouse_types.h" #include "synergy/option_types.h" -#include "base/String.h" class IClipboard; class IPlatformScreen; @@ -39,316 +39,317 @@ primary or secondary screen. */ class Screen : public IScreen { public: - Screen(IPlatformScreen* platformScreen, IEventQueue* events); - Screen(Screen const &) =delete; - Screen(Screen &&) =delete; - virtual ~Screen(); + Screen(IPlatformScreen *platformScreen, IEventQueue *events); + Screen(Screen const &) = delete; + Screen(Screen &&) = delete; + virtual ~Screen(); - Screen& operator&(Screen const &) =delete; - Screen& operator&(Screen &&) =delete; + Screen &operator&(Screen const &) = delete; + Screen &operator&(Screen &&) = delete; #ifdef TEST_ENV - Screen() : m_mock(true) { } + Screen() : m_mock(true) {} #endif - //! @name manipulators - //@{ + //! @name manipulators + //@{ - //! Activate screen - /*! - Activate the screen, preparing it to report system and user events. - For a secondary screen it also means disabling the screen saver if - synchronizing it and preparing to synthesize events. - */ - virtual void enable(); + //! Activate screen + /*! + Activate the screen, preparing it to report system and user events. + For a secondary screen it also means disabling the screen saver if + synchronizing it and preparing to synthesize events. + */ + virtual void enable(); - //! Deactivate screen - /*! - Undoes the operations in activate() and events are no longer - reported. It also releases keys that are logically pressed. - */ - virtual void disable(); + //! Deactivate screen + /*! + Undoes the operations in activate() and events are no longer + reported. It also releases keys that are logically pressed. + */ + virtual void disable(); - //! Enter screen - /*! - Called when the user navigates to this screen. \p toggleMask has the - toggle keys that should be turned on on the secondary screen. - */ - void enter(KeyModifierMask toggleMask); + //! Enter screen + /*! + Called when the user navigates to this screen. \p toggleMask has the + toggle keys that should be turned on on the secondary screen. + */ + void enter(KeyModifierMask toggleMask); - //! Leave screen - /*! - Called when the user navigates off this screen. - */ - bool leave(); + //! Leave screen + /*! + Called when the user navigates off this screen. + */ + bool leave(); - //! Update configuration - /*! - This is called when the configuration has changed. \c activeSides - is a bitmask of EDirectionMask indicating which sides of the - primary screen are linked to clients. - */ - void reconfigure(UInt32 activeSides); + //! Update configuration + /*! + This is called when the configuration has changed. \c activeSides + is a bitmask of EDirectionMask indicating which sides of the + primary screen are linked to clients. + */ + void reconfigure(UInt32 activeSides); - //! Warp cursor - /*! - Warps the cursor to the absolute coordinates \c x,y. Also - discards input events up to and including the warp before - returning. - */ - void warpCursor(SInt32 x, SInt32 y); + //! Warp cursor + /*! + Warps the cursor to the absolute coordinates \c x,y. Also + discards input events up to and including the warp before + returning. + */ + void warpCursor(SInt32 x, SInt32 y); - //! Set clipboard - /*! - Sets the system's clipboard contents. This is usually called - soon after an enter(). - */ - void setClipboard(ClipboardID, const IClipboard*); + //! Set clipboard + /*! + Sets the system's clipboard contents. This is usually called + soon after an enter(). + */ + void setClipboard(ClipboardID, const IClipboard *); - //! Grab clipboard - /*! - Grabs (i.e. take ownership of) the system clipboard. - */ - void grabClipboard(ClipboardID); + //! Grab clipboard + /*! + Grabs (i.e. take ownership of) the system clipboard. + */ + void grabClipboard(ClipboardID); - //! Activate/deactivate screen saver - /*! - Forcibly activates the screen saver if \c activate is true otherwise - forcibly deactivates it. - */ - void screensaver(bool activate) const; + //! Activate/deactivate screen saver + /*! + Forcibly activates the screen saver if \c activate is true otherwise + forcibly deactivates it. + */ + void screensaver(bool activate) const; - //! Notify of key press - /*! - Synthesize key events to generate a press of key \c id. If possible - match the given modifier mask. The KeyButton identifies the physical - key on the server that generated this key down. The client must - ensure that a key up or key repeat that uses the same KeyButton will - synthesize an up or repeat for the same client key synthesized by - keyDown(). - */ - void keyDown(KeyID id, KeyModifierMask, KeyButton, const String&); + //! Notify of key press + /*! + Synthesize key events to generate a press of key \c id. If possible + match the given modifier mask. The KeyButton identifies the physical + key on the server that generated this key down. The client must + ensure that a key up or key repeat that uses the same KeyButton will + synthesize an up or repeat for the same client key synthesized by + keyDown(). + */ + void keyDown(KeyID id, KeyModifierMask, KeyButton, const String &); - //! Notify of key repeat - /*! - Synthesize key events to generate a press and release of key \c id - \c count times. If possible match the given modifier mask. - */ - void keyRepeat(KeyID id, KeyModifierMask, - SInt32 count, KeyButton, const String& lang); + //! Notify of key repeat + /*! + Synthesize key events to generate a press and release of key \c id + \c count times. If possible match the given modifier mask. + */ + void keyRepeat(KeyID id, KeyModifierMask, SInt32 count, KeyButton, + const String &lang); - //! Notify of key release - /*! - Synthesize key events to generate a release of key \c id. If possible - match the given modifier mask. - */ - void keyUp(KeyID id, KeyModifierMask, KeyButton); + //! Notify of key release + /*! + Synthesize key events to generate a release of key \c id. If possible + match the given modifier mask. + */ + void keyUp(KeyID id, KeyModifierMask, KeyButton); - //! Notify of mouse press - /*! - Synthesize mouse events to generate a press of mouse button \c id. - */ - void mouseDown(ButtonID id); + //! Notify of mouse press + /*! + Synthesize mouse events to generate a press of mouse button \c id. + */ + void mouseDown(ButtonID id); - //! Notify of mouse release - /*! - Synthesize mouse events to generate a release of mouse button \c id. - */ - void mouseUp(ButtonID id); + //! Notify of mouse release + /*! + Synthesize mouse events to generate a release of mouse button \c id. + */ + void mouseUp(ButtonID id); - //! Notify of mouse motion - /*! - Synthesize mouse events to generate mouse motion to the absolute - screen position \c xAbs,yAbs. - */ - void mouseMove(SInt32 xAbs, SInt32 yAbs); + //! Notify of mouse motion + /*! + Synthesize mouse events to generate mouse motion to the absolute + screen position \c xAbs,yAbs. + */ + void mouseMove(SInt32 xAbs, SInt32 yAbs); - //! Notify of mouse motion - /*! - Synthesize mouse events to generate mouse motion by the relative - amount \c xRel,yRel. - */ - void mouseRelativeMove(SInt32 xRel, SInt32 yRel); + //! Notify of mouse motion + /*! + Synthesize mouse events to generate mouse motion by the relative + amount \c xRel,yRel. + */ + void mouseRelativeMove(SInt32 xRel, SInt32 yRel); - //! Notify of mouse wheel motion - /*! - Synthesize mouse events to generate mouse wheel motion of \c xDelta - and \c yDelta. Deltas are positive for motion away from the user or - to the right and negative for motion towards the user or to the left. - Each wheel click should generate a delta of +/-120. - */ - void mouseWheel(SInt32 xDelta, SInt32 yDelta) const; + //! Notify of mouse wheel motion + /*! + Synthesize mouse events to generate mouse wheel motion of \c xDelta + and \c yDelta. Deltas are positive for motion away from the user or + to the right and negative for motion towards the user or to the left. + Each wheel click should generate a delta of +/-120. + */ + void mouseWheel(SInt32 xDelta, SInt32 yDelta) const; - //! Notify of options changes - /*! - Resets all options to their default values. - */ - virtual void resetOptions(); + //! Notify of options changes + /*! + Resets all options to their default values. + */ + virtual void resetOptions(); - //! Notify of options changes - /*! - Set options to given values. Ignores unknown options and doesn't - modify options that aren't given in \c options. - */ - virtual void setOptions(const OptionsList& options); + //! Notify of options changes + /*! + Set options to given values. Ignores unknown options and doesn't + modify options that aren't given in \c options. + */ + virtual void setOptions(const OptionsList &options); - //! Set clipboard sequence number - /*! - Sets the sequence number to use in subsequent clipboard events. - */ - void setSequenceNumber(UInt32); + //! Set clipboard sequence number + /*! + Sets the sequence number to use in subsequent clipboard events. + */ + void setSequenceNumber(UInt32); - //! Register a system hotkey - /*! - Registers a system-wide hotkey for key \p key with modifiers \p mask. - Returns an id used to unregister the hotkey. - */ - UInt32 registerHotKey(KeyID key, KeyModifierMask mask); + //! Register a system hotkey + /*! + Registers a system-wide hotkey for key \p key with modifiers \p mask. + Returns an id used to unregister the hotkey. + */ + UInt32 registerHotKey(KeyID key, KeyModifierMask mask); - //! Unregister a system hotkey - /*! - Unregisters a previously registered hot key. - */ - void unregisterHotKey(UInt32 id); + //! Unregister a system hotkey + /*! + Unregisters a previously registered hot key. + */ + void unregisterHotKey(UInt32 id); - //! Prepare to synthesize input on primary screen - /*! - Prepares the primary screen to receive synthesized input. We do not - want to receive this synthesized input as user input so this method - ensures that we ignore it. Calls to \c fakeInputBegin() may not be - nested. - */ - void fakeInputBegin(); + //! Prepare to synthesize input on primary screen + /*! + Prepares the primary screen to receive synthesized input. We do not + want to receive this synthesized input as user input so this method + ensures that we ignore it. Calls to \c fakeInputBegin() may not be + nested. + */ + void fakeInputBegin(); - //! Done synthesizing input on primary screen - /*! - Undoes whatever \c fakeInputBegin() did. - */ - void fakeInputEnd(); + //! Done synthesizing input on primary screen + /*! + Undoes whatever \c fakeInputBegin() did. + */ + void fakeInputEnd(); - //! Change dragging status - void setDraggingStarted(bool started); - - //! Fake a files dragging operation - void startDraggingFiles(DragFileList& fileList); + //! Change dragging status + void setDraggingStarted(bool started); - void setEnableDragDrop(bool enabled); + //! Fake a files dragging operation + void startDraggingFiles(DragFileList &fileList); - //! Determine the name of the app causing a secure input state - /*! - On MacOS check which app causes a secure input state to be enabled. No alternative on other platforms - */ - String getSecureInputApp() const; + void setEnableDragDrop(bool enabled); - //@} - //! @name accessors - //@{ + //! Determine the name of the app causing a secure input state + /*! + On MacOS check which app causes a secure input state to be enabled. No + alternative on other platforms + */ + String getSecureInputApp() const; - //! Test if cursor on screen - /*! - Returns true iff the cursor is on the screen. - */ - bool isOnScreen() const; + //@} + //! @name accessors + //@{ - //! Get screen lock state - /*! - Returns true if there's any reason that the user should not be - allowed to leave the screen (usually because a button or key is - pressed). If this method returns true it logs a message as to - why at the CLOG_DEBUG level. - */ - bool isLockedToScreen() const; + //! Test if cursor on screen + /*! + Returns true iff the cursor is on the screen. + */ + bool isOnScreen() const; - //! Get jump zone size - /*! - Return the jump zone size, the size of the regions on the edges of - the screen that cause the cursor to jump to another screen. - */ - SInt32 getJumpZoneSize() const; + //! Get screen lock state + /*! + Returns true if there's any reason that the user should not be + allowed to leave the screen (usually because a button or key is + pressed). If this method returns true it logs a message as to + why at the CLOG_DEBUG level. + */ + bool isLockedToScreen() const; - //! Get cursor center position - /*! - Return the cursor center position which is where we park the - cursor to compute cursor motion deltas and should be far from - the edges of the screen, typically the center. - */ - void getCursorCenter(SInt32& x, SInt32& y) const; + //! Get jump zone size + /*! + Return the jump zone size, the size of the regions on the edges of + the screen that cause the cursor to jump to another screen. + */ + SInt32 getJumpZoneSize() const; - //! Get the active modifiers - /*! - Returns the modifiers that are currently active according to our - shadowed state. - */ - KeyModifierMask getActiveModifiers() const; + //! Get cursor center position + /*! + Return the cursor center position which is where we park the + cursor to compute cursor motion deltas and should be far from + the edges of the screen, typically the center. + */ + void getCursorCenter(SInt32 &x, SInt32 &y) const; - //! Get the active modifiers from OS - /*! - Returns the modifiers that are currently active according to the - operating system. - */ - KeyModifierMask pollActiveModifiers() const; + //! Get the active modifiers + /*! + Returns the modifiers that are currently active according to our + shadowed state. + */ + KeyModifierMask getActiveModifiers() const; - //! Test if file is dragged on primary screen - bool isDraggingStarted() const; - - //! Test if file is dragged on secondary screen - bool isFakeDraggingStarted() const; + //! Get the active modifiers from OS + /*! + Returns the modifiers that are currently active according to the + operating system. + */ + KeyModifierMask pollActiveModifiers() const; - //! Get the filename of the file being dragged - String& getDraggingFilename() const; + //! Test if file is dragged on primary screen + bool isDraggingStarted() const; - //! Clear the filename of the file that was dragged - void clearDraggingFilename(); + //! Test if file is dragged on secondary screen + bool isFakeDraggingStarted() const; - //! Get the drop target directory - const String& getDropTarget() const; + //! Get the filename of the file being dragged + String &getDraggingFilename() const; - //@} + //! Clear the filename of the file that was dragged + void clearDraggingFilename(); - // IScreen overrides - virtual void* getEventTarget() const; - virtual bool getClipboard(ClipboardID id, IClipboard*) const; - virtual void getShape(SInt32& x, SInt32& y, - SInt32& width, SInt32& height) const; - virtual void getCursorPos(SInt32& x, SInt32& y) const; - - IPlatformScreen* getPlatformScreen() { return m_screen; } + //! Get the drop target directory + const String &getDropTarget() const; + + //@} + + // IScreen overrides + virtual void *getEventTarget() const; + virtual bool getClipboard(ClipboardID id, IClipboard *) const; + virtual void getShape(SInt32 &x, SInt32 &y, SInt32 &width, + SInt32 &height) const; + virtual void getCursorPos(SInt32 &x, SInt32 &y) const; + + IPlatformScreen *getPlatformScreen() { return m_screen; } protected: - void enablePrimary(); - void enableSecondary(); - void disablePrimary(); - void disableSecondary(); + void enablePrimary(); + void enableSecondary(); + void disablePrimary(); + void disableSecondary(); - void enterPrimary(); - void enterSecondary(KeyModifierMask toggleMask); - void leavePrimary(); - void leaveSecondary(); + void enterPrimary(); + void enterSecondary(KeyModifierMask toggleMask); + void leavePrimary(); + void leaveSecondary(); private: - // our platform dependent screen - IPlatformScreen* m_screen; + // our platform dependent screen + IPlatformScreen *m_screen; - // true if screen is being used as a primary screen, false otherwise - bool m_isPrimary; + // true if screen is being used as a primary screen, false otherwise + bool m_isPrimary; - // true if screen is enabled - bool m_enabled; + // true if screen is enabled + bool m_enabled; - // true if the cursor is on this screen - bool m_entered; + // true if the cursor is on this screen + bool m_entered; - // note toggle keys that toggles on up/down (false) or on - // transition (true) - KeyModifierMask m_halfDuplex; + // note toggle keys that toggles on up/down (false) or on + // transition (true) + KeyModifierMask m_halfDuplex; - // true if we're faking input on a primary screen - bool m_fakeInput; + // true if we're faking input on a primary screen + bool m_fakeInput; - IEventQueue* m_events; + IEventQueue *m_events; - bool m_mock; - bool m_enableDragDrop; + bool m_mock; + bool m_enableDragDrop; }; -} +} // namespace synergy diff --git a/src/lib/synergy/ServerApp.cpp b/src/lib/synergy/ServerApp.cpp index e3f4c9131..fa39bddf6 100644 --- a/src/lib/synergy/ServerApp.cpp +++ b/src/lib/synergy/ServerApp.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -18,29 +18,29 @@ #include "synergy/ServerApp.h" -#include "server/Server.h" +#include "arch/Arch.h" +#include "base/EventQueue.h" +#include "base/FunctionEventJob.h" +#include "base/IEventQueue.h" +#include "base/Log.h" +#include "base/Path.h" +#include "base/TMethodEventJob.h" +#include "base/TMethodJob.h" +#include "base/log_outputters.h" +#include "common/Version.h" +#include "net/InverseSockets/InverseSocketFactory.h" +#include "net/SocketMultiplexer.h" +#include "net/TCPSocketFactory.h" +#include "net/XSocket.h" #include "server/ClientListener.h" #include "server/ClientProxy.h" #include "server/PrimaryClient.h" +#include "server/Server.h" #include "synergy/ArgParser.h" #include "synergy/Screen.h" -#include "synergy/XScreen.h" -#include "synergy/ServerTaskBarReceiver.h" #include "synergy/ServerArgs.h" -#include "net/SocketMultiplexer.h" -#include "net/TCPSocketFactory.h" -#include "net/InverseSockets/InverseSocketFactory.h" -#include "net/XSocket.h" -#include "arch/Arch.h" -#include "base/EventQueue.h" -#include "base/log_outputters.h" -#include "base/FunctionEventJob.h" -#include "base/TMethodJob.h" -#include "base/IEventQueue.h" -#include "base/Log.h" -#include "base/TMethodEventJob.h" -#include "common/Version.h" -#include "base/Path.h" +#include "synergy/ServerTaskBarReceiver.h" +#include "synergy/XScreen.h" #if SYSAPI_WIN32 #include "arch/win32/ArchMiscWindows.h" @@ -58,845 +58,727 @@ #include "platform/OSXDragSimulator.h" #endif +#include #include #include -#include // // ServerApp // -ServerApp::ServerApp(IEventQueue* events, CreateTaskBarReceiverFunc createTaskBarReceiver) : - App(events, createTaskBarReceiver, new lib::synergy::ServerArgs()), - m_server(NULL), - m_serverState(kUninitialized), - m_serverScreen(NULL), - m_primaryClient(NULL), - m_listener(NULL), - m_timer(NULL), - m_synergyAddress(NULL) -{ -} +ServerApp::ServerApp(IEventQueue *events, + CreateTaskBarReceiverFunc createTaskBarReceiver) + : App(events, createTaskBarReceiver, new lib::synergy::ServerArgs()), + m_server(NULL), m_serverState(kUninitialized), m_serverScreen(NULL), + m_primaryClient(NULL), m_listener(NULL), m_timer(NULL), + m_synergyAddress(NULL) {} -ServerApp::~ServerApp() -{ -} +ServerApp::~ServerApp() {} -void -ServerApp::parseArgs(int argc, const char* const* argv) -{ - ArgParser argParser(this); - bool result = argParser.parseServerArgs(args(), argc, argv); +void ServerApp::parseArgs(int argc, const char *const *argv) { + ArgParser argParser(this); + bool result = argParser.parseServerArgs(args(), argc, argv); - if (!result || args().m_shouldExit) { + if (!result || args().m_shouldExit) { + m_bye(kExitArgs); + } else { + if (!args().m_synergyAddress.empty()) { + try { + *m_synergyAddress = + NetworkAddress(args().m_synergyAddress, kDefaultPort); + m_synergyAddress->resolve(); + } catch (XSocketAddress &e) { + LOG((CLOG_CRIT "%s: %s" BYE, args().m_pname, e.what(), args().m_pname)); m_bye(kExitArgs); + } } - else { - if (!args().m_synergyAddress.empty()) { - try { - *m_synergyAddress = NetworkAddress(args().m_synergyAddress, - kDefaultPort); - m_synergyAddress->resolve(); - } - catch (XSocketAddress& e) { - LOG((CLOG_CRIT "%s: %s" BYE, - args().m_pname, e.what(), args().m_pname)); - m_bye(kExitArgs); - } - } - } + } } -void -ServerApp::help() -{ - // window api args (windows/x-windows/carbon) +void ServerApp::help() { + // window api args (windows/x-windows/carbon) #if WINAPI_XWINDOWS -# define WINAPI_ARGS \ - " [--display ] [--no-xinitthreads]" -# define WINAPI_INFO \ - " --display connect to the X server at \n" \ - " --no-xinitthreads do not call XInitThreads()\n" +#define WINAPI_ARGS " [--display ] [--no-xinitthreads]" +#define WINAPI_INFO \ + " --display connect to the X server at \n" \ + " --no-xinitthreads do not call XInitThreads()\n" #else -# define WINAPI_ARGS -# define WINAPI_INFO +#define WINAPI_ARGS +#define WINAPI_INFO #endif - static const int buffer_size = 3000; - char buffer[buffer_size]; - snprintf( - buffer, - buffer_size, - "Usage: %s" - " [--address
]" - " [--config ]" - WINAPI_ARGS - HELP_SYS_ARGS - HELP_COMMON_ARGS - "\n\n" - "Start the synergy mouse/keyboard sharing server.\n" - "\n" - " -a, --address
listen for clients on the given address.\n" - " -c, --config use the named configuration file instead.\n" - HELP_COMMON_INFO_1 - WINAPI_INFO - HELP_SYS_INFO - HELP_COMMON_INFO_2 - "\n" - "* marks defaults.\n" - "\n" - "The argument for --address is of the form: [][:]. The\n" - "hostname must be the address or hostname of an interface on the system.\n" - "The default is to listen on all interfaces. The port overrides the\n" - "default port, %d.\n" - "\n" - "If no configuration file pathname is provided then the first of the\n" - "following to load successfully sets the configuration:\n" - " %s\n" - " %s\n", - args().m_pname, kDefaultPort, - ARCH->concatPath(ARCH->getUserDirectory(), USR_CONFIG_NAME).c_str(), - ARCH->concatPath(ARCH->getSystemDirectory(), SYS_CONFIG_NAME).c_str() - ); + static const int buffer_size = 3000; + char buffer[buffer_size]; + snprintf( + buffer, buffer_size, + "Usage: %s" + " [--address
]" + " [--config ]" WINAPI_ARGS HELP_SYS_ARGS HELP_COMMON_ARGS "\n\n" + "Start the synergy mouse/keyboard sharing server.\n" + "\n" + " -a, --address
listen for clients on the given address.\n" + " -c, --config use the named configuration file " + "instead.\n" HELP_COMMON_INFO_1 WINAPI_INFO + HELP_SYS_INFO HELP_COMMON_INFO_2 "\n" + "* marks defaults.\n" + "\n" + "The argument for --address is of the form: [][:]. The\n" + "hostname must be the address or hostname of an interface on the " + "system.\n" + "The default is to listen on all interfaces. The port overrides the\n" + "default port, %d.\n" + "\n" + "If no configuration file pathname is provided then the first of the\n" + "following to load successfully sets the configuration:\n" + " %s\n" + " %s\n", + args().m_pname, kDefaultPort, + ARCH->concatPath(ARCH->getUserDirectory(), USR_CONFIG_NAME).c_str(), + ARCH->concatPath(ARCH->getSystemDirectory(), SYS_CONFIG_NAME).c_str()); - LOG((CLOG_PRINT "%s", buffer)); + LOG((CLOG_PRINT "%s", buffer)); } -void -ServerApp::reloadSignalHandler(Arch::ESignal, void*) -{ - IEventQueue* events = App::instance().getEvents(); - events->addEvent(Event(events->forServerApp().reloadConfig(), - events->getSystemTarget())); +void ServerApp::reloadSignalHandler(Arch::ESignal, void *) { + IEventQueue *events = App::instance().getEvents(); + events->addEvent( + Event(events->forServerApp().reloadConfig(), events->getSystemTarget())); } -void -ServerApp::reloadConfig(const Event&, void*) -{ - LOG((CLOG_DEBUG "reload configuration")); - if (loadConfig(args().m_configFile)) { - if (m_server != NULL) { - m_server->setConfig(*args().m_config); - } - LOG((CLOG_NOTE "reloaded configuration")); - } -} - -void -ServerApp::loadConfig() -{ - bool loaded = false; - - // load the config file, if specified - if (!args().m_configFile.empty()) { - loaded = loadConfig(args().m_configFile); - } - - // load the default configuration if no explicit file given - else { - // get the user's home directory - String path = ARCH->getUserDirectory(); - if (!path.empty()) { - // complete path - path = ARCH->concatPath(path, USR_CONFIG_NAME); - - // now try loading the user's configuration - if (loadConfig(path)) { - loaded = true; - args().m_configFile = path; - } - } - if (!loaded) { - // try the system-wide config file - path = ARCH->getSystemDirectory(); - if (!path.empty()) { - path = ARCH->concatPath(path, SYS_CONFIG_NAME); - if (loadConfig(path)) { - loaded = true; - args().m_configFile = path; - } - } - } - } - - if (!loaded) { - LOG((CLOG_CRIT "%s: no configuration available", args().m_pname)); - m_bye(kExitConfig); - } -} - -bool -ServerApp::loadConfig(const String& pathname) -{ - try { - // load configuration - LOG((CLOG_DEBUG "opening configuration \"%s\"", pathname.c_str())); - std::ifstream configStream(synergy::filesystem::path(pathname)); - if (!configStream.is_open()) { - // report failure to open configuration as a debug message - // since we try several paths and we expect some to be - // missing. - LOG((CLOG_DEBUG "cannot open configuration \"%s\"", - pathname.c_str())); - return false; - } - configStream >> *args().m_config; - LOG((CLOG_DEBUG "configuration read successfully")); - return true; - } - catch (XConfigRead& e) { - // report error in configuration file - LOG((CLOG_ERR "cannot read configuration \"%s\": %s", - pathname.c_str(), e.what())); - } - return false; -} - -void -ServerApp::forceReconnect(const Event&, void*) -{ +void ServerApp::reloadConfig(const Event &, void *) { + LOG((CLOG_DEBUG "reload configuration")); + if (loadConfig(args().m_configFile)) { if (m_server != NULL) { - m_server->disconnect(); + m_server->setConfig(*args().m_config); } + LOG((CLOG_NOTE "reloaded configuration")); + } } -void -ServerApp::handleClientConnected(const Event&, void* vlistener) -{ - ClientListener* listener = static_cast(vlistener); - ClientProxy* client = listener->getNextClient(); - if (client != NULL) { - m_server->adoptClient(client); - updateStatus(); +void ServerApp::loadConfig() { + bool loaded = false; + + // load the config file, if specified + if (!args().m_configFile.empty()) { + loaded = loadConfig(args().m_configFile); + } + + // load the default configuration if no explicit file given + else { + // get the user's home directory + String path = ARCH->getUserDirectory(); + if (!path.empty()) { + // complete path + path = ARCH->concatPath(path, USR_CONFIG_NAME); + + // now try loading the user's configuration + if (loadConfig(path)) { + loaded = true; + args().m_configFile = path; + } } -} - -void -ServerApp::handleClientsDisconnected(const Event&, void*) -{ - m_events->addEvent(Event(Event::kQuit)); -} - -void -ServerApp::closeServer(Server* server) -{ - if (server == NULL) { - return; + if (!loaded) { + // try the system-wide config file + path = ARCH->getSystemDirectory(); + if (!path.empty()) { + path = ARCH->concatPath(path, SYS_CONFIG_NAME); + if (loadConfig(path)) { + loaded = true; + args().m_configFile = path; + } + } } + } - // tell all clients to disconnect - server->disconnect(); - - // wait for clients to disconnect for up to timeout seconds - double timeout = 3.0; - EventQueueTimer* timer = m_events->newOneShotTimer(timeout, NULL); - m_events->adoptHandler(Event::kTimer, timer, - new TMethodEventJob(this, &ServerApp::handleClientsDisconnected)); - m_events->adoptHandler(m_events->forServer().disconnected(), server, - new TMethodEventJob(this, &ServerApp::handleClientsDisconnected)); - - m_events->loop(); - - m_events->removeHandler(Event::kTimer, timer); - m_events->deleteTimer(timer); - m_events->removeHandler(m_events->forServer().disconnected(), server); - - // done with server - delete server; + if (!loaded) { + LOG((CLOG_CRIT "%s: no configuration available", args().m_pname)); + m_bye(kExitConfig); + } } -void -ServerApp::stopRetryTimer() -{ - if (m_timer != NULL) { - m_events->removeHandler(Event::kTimer, m_timer); - m_events->deleteTimer(m_timer); - m_timer = NULL; - } -} - -void -ServerApp::updateStatus() -{ - updateStatus(""); -} - -void ServerApp::updateStatus(const String& msg) -{ - if (m_taskBarReceiver) - { - m_taskBarReceiver->updateStatus(m_server, msg); +bool ServerApp::loadConfig(const String &pathname) { + try { + // load configuration + LOG((CLOG_DEBUG "opening configuration \"%s\"", pathname.c_str())); + std::ifstream configStream(synergy::filesystem::path(pathname)); + if (!configStream.is_open()) { + // report failure to open configuration as a debug message + // since we try several paths and we expect some to be + // missing. + LOG((CLOG_DEBUG "cannot open configuration \"%s\"", pathname.c_str())); + return false; } + configStream >> *args().m_config; + LOG((CLOG_DEBUG "configuration read successfully")); + return true; + } catch (XConfigRead &e) { + // report error in configuration file + LOG((CLOG_ERR "cannot read configuration \"%s\": %s", pathname.c_str(), + e.what())); + } + return false; } -void -ServerApp::closeClientListener(ClientListener* listen) -{ - if (listen != NULL) { - m_events->removeHandler(m_events->forClientListener().connected(), listen); - delete listen; - } +void ServerApp::forceReconnect(const Event &, void *) { + if (m_server != NULL) { + m_server->disconnect(); + } } -void -ServerApp::stopServer() -{ - if (m_serverState == kStarted) { - closeServer(m_server); - closeClientListener(m_listener); - m_server = NULL; - m_listener = NULL; - m_serverState = kInitialized; - } - else if (m_serverState == kStarting) { - stopRetryTimer(); - m_serverState = kInitialized; - } - assert(m_server == NULL); - assert(m_listener == NULL); +void ServerApp::handleClientConnected(const Event &, void *vlistener) { + ClientListener *listener = static_cast(vlistener); + ClientProxy *client = listener->getNextClient(); + if (client != NULL) { + m_server->adoptClient(client); + updateStatus(); + } } -void -ServerApp::closePrimaryClient(PrimaryClient* primaryClient) -{ - delete primaryClient; +void ServerApp::handleClientsDisconnected(const Event &, void *) { + m_events->addEvent(Event(Event::kQuit)); } -void -ServerApp::closeServerScreen(synergy::Screen* screen) -{ - if (screen != NULL) { - m_events->removeHandler(m_events->forIScreen().error(), - screen->getEventTarget()); - m_events->removeHandler(m_events->forIScreen().suspend(), - screen->getEventTarget()); - m_events->removeHandler(m_events->forIScreen().resume(), - screen->getEventTarget()); - delete screen; - } +void ServerApp::closeServer(Server *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; + EventQueueTimer *timer = m_events->newOneShotTimer(timeout, NULL); + m_events->adoptHandler(Event::kTimer, timer, + new TMethodEventJob( + this, &ServerApp::handleClientsDisconnected)); + m_events->adoptHandler(m_events->forServer().disconnected(), server, + new TMethodEventJob( + this, &ServerApp::handleClientsDisconnected)); + + m_events->loop(); + + m_events->removeHandler(Event::kTimer, timer); + m_events->deleteTimer(timer); + m_events->removeHandler(m_events->forServer().disconnected(), server); + + // done with server + delete server; } -void ServerApp::cleanupServer() -{ - stopServer(); - if (m_serverState == kInitialized) { - closePrimaryClient(m_primaryClient); - closeServerScreen(m_serverScreen); - m_primaryClient = NULL; - m_serverScreen = NULL; - m_serverState = kUninitialized; - } - else if (m_serverState == kInitializing || - m_serverState == kInitializingToStart) { - stopRetryTimer(); - m_serverState = kUninitialized; - } - assert(m_primaryClient == NULL); - assert(m_serverScreen == NULL); - assert(m_serverState == kUninitialized); +void ServerApp::stopRetryTimer() { + if (m_timer != NULL) { + m_events->removeHandler(Event::kTimer, m_timer); + m_events->deleteTimer(m_timer); + m_timer = NULL; + } } -void -ServerApp::retryHandler(const Event&, void*) -{ - // discard old timer - assert(m_timer != NULL); +void ServerApp::updateStatus() { updateStatus(""); } + +void ServerApp::updateStatus(const String &msg) { + if (m_taskBarReceiver) { + m_taskBarReceiver->updateStatus(m_server, msg); + } +} + +void ServerApp::closeClientListener(ClientListener *listen) { + if (listen != NULL) { + m_events->removeHandler(m_events->forClientListener().connected(), listen); + delete listen; + } +} + +void ServerApp::stopServer() { + if (m_serverState == kStarted) { + closeServer(m_server); + closeClientListener(m_listener); + m_server = NULL; + m_listener = NULL; + m_serverState = kInitialized; + } else if (m_serverState == kStarting) { stopRetryTimer(); - - // try initializing/starting the server again - switch (m_serverState) { - case kUninitialized: - case kInitialized: - case kStarted: - assert(0 && "bad internal server state"); - break; - - case kInitializing: - LOG((CLOG_DEBUG1 "retry server initialization")); - m_serverState = kUninitialized; - if (!initServer()) { - m_events->addEvent(Event(Event::kQuit)); - } - break; - - case kInitializingToStart: - LOG((CLOG_DEBUG1 "retry server initialization")); - m_serverState = kUninitialized; - if (!initServer()) { - m_events->addEvent(Event(Event::kQuit)); - } - else if (m_serverState == kInitialized) { - LOG((CLOG_DEBUG1 "starting server")); - if (!startServer()) { - m_events->addEvent(Event(Event::kQuit)); - } - } - break; - - case kStarting: - LOG((CLOG_DEBUG1 "retry starting server")); - m_serverState = kInitialized; - if (!startServer()) { - m_events->addEvent(Event(Event::kQuit)); - } - break; - } + m_serverState = kInitialized; + } + assert(m_server == NULL); + assert(m_listener == NULL); } -bool ServerApp::initServer() -{ - // skip if already initialized or initializing - if (m_serverState != kUninitialized) { - return true; - } - - double retryTime; - synergy::Screen* serverScreen = NULL; - PrimaryClient* primaryClient = NULL; - try { - String name = args().m_config->getCanonicalName(args().m_name); - serverScreen = openServerScreen(); - primaryClient = openPrimaryClient(name, serverScreen); - m_serverScreen = serverScreen; - m_primaryClient = primaryClient; - m_serverState = kInitialized; - updateStatus(); - return true; - } - catch (XScreenUnavailable& e) { - LOG((CLOG_WARN "primary screen unavailable: %s", e.what())); - closePrimaryClient(primaryClient); - closeServerScreen(serverScreen); - updateStatus(String("primary screen unavailable: ") + e.what()); - retryTime = e.getRetryTime(); - } - catch (XScreenOpenFailure& e) { - LOG((CLOG_CRIT "failed to start server: %s", e.what())); - closePrimaryClient(primaryClient); - closeServerScreen(serverScreen); - return false; - } - catch (XBase& e) { - LOG((CLOG_CRIT "failed to start server: %s", e.what())); - closePrimaryClient(primaryClient); - closeServerScreen(serverScreen); - return false; - } - - if (args().m_restartable) { - // install a timer and handler to retry later - assert(m_timer == NULL); - LOG((CLOG_DEBUG "retry in %.0f seconds", retryTime)); - m_timer = m_events->newOneShotTimer(retryTime, NULL); - m_events->adoptHandler(Event::kTimer, m_timer, - new TMethodEventJob(this, &ServerApp::retryHandler)); - m_serverState = kInitializing; - return true; - } - else { - // don't try again - return false; - } +void ServerApp::closePrimaryClient(PrimaryClient *primaryClient) { + delete primaryClient; } -synergy::Screen* -ServerApp::openServerScreen() -{ - synergy::Screen* screen = createScreen(); - screen->setEnableDragDrop(argsBase().m_enableDragDrop); - m_events->adoptHandler(m_events->forIScreen().error(), - screen->getEventTarget(), - new TMethodEventJob( - this, &ServerApp::handleScreenError)); - m_events->adoptHandler(m_events->forIScreen().suspend(), - screen->getEventTarget(), - new TMethodEventJob( - this, &ServerApp::handleSuspend)); - m_events->adoptHandler(m_events->forIScreen().resume(), - screen->getEventTarget(), - new TMethodEventJob( - this, &ServerApp::handleResume)); - return screen; +void ServerApp::closeServerScreen(synergy::Screen *screen) { + if (screen != NULL) { + m_events->removeHandler(m_events->forIScreen().error(), + screen->getEventTarget()); + m_events->removeHandler(m_events->forIScreen().suspend(), + screen->getEventTarget()); + m_events->removeHandler(m_events->forIScreen().resume(), + screen->getEventTarget()); + delete screen; + } } -bool -ServerApp::startServer() -{ - // skip if already started or starting - if (m_serverState == kStarting || m_serverState == kStarted) { - return true; - } - - // initialize if necessary - if (m_serverState != kInitialized) { - if (!initServer()) { - // hard initialization failure - return false; - } - if (m_serverState == kInitializing) { - // not ready to start - m_serverState = kInitializingToStart; - return true; - } - assert(m_serverState == kInitialized); - } - - ClientListener* listener = NULL; - try { - listener = openClientListener(args().m_config->getSynergyAddress()); - m_server = openServer(*args().m_config, m_primaryClient); - listener->setServer(m_server); - m_server->setListener(listener); - m_listener = listener; - updateStatus(); - LOG((CLOG_NOTE "started server, waiting for clients")); - m_serverState = kStarted; - return true; - } - catch (XSocketAddressInUse& e) { - if (args().m_restartable) { - LOG((CLOG_ERR "cannot listen for clients: %s", e.what())); - } - else { - LOG((CLOG_CRIT "cannot listen for clients: %s", e.what())); - } - closeClientListener(listener); - updateStatus(String("cannot listen for clients: ") + e.what()); - } - catch (XBase& e) { - LOG((CLOG_CRIT "failed to start server: %s", e.what())); - closeClientListener(listener); - return false; - } - - if (args().m_restartable) { - // install a timer and handler to retry later - assert(m_timer == NULL); - const auto retryTime = 10.0; - LOG((CLOG_DEBUG "retry in %.0f seconds", retryTime)); - m_timer = m_events->newOneShotTimer(retryTime, NULL); - m_events->adoptHandler(Event::kTimer, m_timer, - new TMethodEventJob(this, &ServerApp::retryHandler)); - m_serverState = kStarting; - return true; - } - else { - // don't try again - return false; - } +void ServerApp::cleanupServer() { + stopServer(); + if (m_serverState == kInitialized) { + closePrimaryClient(m_primaryClient); + closeServerScreen(m_serverScreen); + m_primaryClient = NULL; + m_serverScreen = NULL; + m_serverState = kUninitialized; + } else if (m_serverState == kInitializing || + m_serverState == kInitializingToStart) { + stopRetryTimer(); + m_serverState = kUninitialized; + } + assert(m_primaryClient == NULL); + assert(m_serverScreen == NULL); + assert(m_serverState == kUninitialized); } -synergy::Screen* -ServerApp::createScreen() -{ -#if WINAPI_MSWINDOWS - return new synergy::Screen(new MSWindowsScreen( - true, args().m_noHooks, args().m_stopOnDeskSwitch, m_events), m_events); -#elif WINAPI_XWINDOWS - return new synergy::Screen(new XWindowsScreen( - args().m_display, true, args().m_disableXInitThreads, 0, m_events), m_events); -#elif WINAPI_CARBON - return new synergy::Screen(new OSXScreen(m_events, true), m_events); -#endif -} +void ServerApp::retryHandler(const Event &, void *) { + // discard old timer + assert(m_timer != NULL); + stopRetryTimer(); -PrimaryClient* -ServerApp::openPrimaryClient(const String& name, synergy::Screen* screen) -{ - LOG((CLOG_DEBUG1 "creating primary screen")); - return new PrimaryClient(name, screen); + // try initializing/starting the server again + switch (m_serverState) { + case kUninitialized: + case kInitialized: + case kStarted: + assert(0 && "bad internal server state"); + break; -} - -void -ServerApp::handleScreenError(const Event&, void*) -{ - LOG((CLOG_CRIT "error on screen")); - m_events->addEvent(Event(Event::kQuit)); -} - -void -ServerApp::handleSuspend(const Event&, void*) -{ - if (!m_suspended) { - LOG((CLOG_INFO "suspend")); - stopServer(); - m_suspended = true; + case kInitializing: + LOG((CLOG_DEBUG1 "retry server initialization")); + m_serverState = kUninitialized; + if (!initServer()) { + m_events->addEvent(Event(Event::kQuit)); } -} + break; -void -ServerApp::handleResume(const Event&, void*) -{ - if (m_suspended) { - LOG((CLOG_INFO "resume")); - startServer(); - m_suspended = false; + case kInitializingToStart: + LOG((CLOG_DEBUG1 "retry server initialization")); + m_serverState = kUninitialized; + if (!initServer()) { + m_events->addEvent(Event(Event::kQuit)); + } else if (m_serverState == kInitialized) { + LOG((CLOG_DEBUG1 "starting server")); + if (!startServer()) { + m_events->addEvent(Event(Event::kQuit)); + } } -} + break; -ClientListener* -ServerApp::openClientListener(const NetworkAddress& address) -{ - ClientListener* listen = new ClientListener( - getAddress(address), - getSocketFactory(), - m_events, - args().m_enableCrypto); - - m_events->adoptHandler( - m_events->forClientListener().connected(), listen, - new TMethodEventJob( - this, &ServerApp::handleClientConnected, listen)); - - return listen; -} - -Server* -ServerApp::openServer(Config& config, PrimaryClient* primaryClient) -{ - Server* server = new Server(config, primaryClient, m_serverScreen, m_events, args()); - try { - m_events->adoptHandler( - m_events->forServer().disconnected(), server, - new TMethodEventJob(this, &ServerApp::handleNoClients)); - - m_events->adoptHandler( - m_events->forServer().screenSwitched(), server, - new TMethodEventJob(this, &ServerApp::handleScreenSwitched)); - - } catch (std::bad_alloc &ba) { - delete server; - throw ba; - } - - return server; -} - -void -ServerApp::handleNoClients(const Event&, void*) -{ - updateStatus(); -} - -void -ServerApp::handleScreenSwitched(const Event& e, void*) -{ -} - -ISocketFactory* ServerApp::getSocketFactory() const -{ - ISocketFactory* socketFactory = nullptr; - - if (args().m_config->isClientMode()) { - socketFactory = new InverseSocketFactory(m_events, getSocketMultiplexer()); - } - else { - socketFactory = new TCPSocketFactory(m_events, getSocketMultiplexer()); - } - - return socketFactory; -} - -NetworkAddress ServerApp::getAddress(const NetworkAddress& address) const -{ - if (args().m_config->isClientMode()) { - const auto clientAddress = args().m_config->getClientAddress(); - NetworkAddress addr(clientAddress.c_str(), kDefaultPort); - addr.resolve(); - return addr; - } - else { - return address; - } -} - -int -ServerApp::mainLoop() -{ - // create socket multiplexer. this must happen after daemonization - // on unix because threads evaporate across a fork(). - SocketMultiplexer multiplexer; - setSocketMultiplexer(&multiplexer); - - // 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 (m_synergyAddress->isValid()) { - args().m_config->setSynergyAddress(*m_synergyAddress); - } - else if (!args().m_config->getSynergyAddress().isValid()) { - args().m_config->setSynergyAddress(NetworkAddress(kDefaultPort)); - } - - // canonicalize the primary screen name - String 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 - appUtil().startNode(); - - // init ipc client after node start, since create a new screen wipes out - // the event queue (the screen ctors call adoptBuffer). - if (argsBase().m_enableIpc) { - initIpcClient(); - } - - // handle hangup signal by reloading the server's configuration - ARCH->setSignalHandler(Arch::kHANGUP, &reloadSignalHandler, NULL); - m_events->adoptHandler(m_events->forServerApp().reloadConfig(), - m_events->getSystemTarget(), - new TMethodEventJob(this, &ServerApp::reloadConfig)); - - // handle force reconnect event by disconnecting clients. they'll - // reconnect automatically. - m_events->adoptHandler(m_events->forServerApp().forceReconnect(), - m_events->getSystemTarget(), - new TMethodEventJob(this, &ServerApp::forceReconnect)); - - // to work around the sticky meta keys problem, we'll give users - // the option to reset the state of synergys - m_events->adoptHandler(m_events->forServerApp().resetServer(), - m_events->getSystemTarget(), - new TMethodEventJob(this, &ServerApp::resetServer)); - - // run event loop. if startServer() failed we're supposed to retry - // later. the timer installed by startServer() will take care of - // that. - DAEMON_RUNNING(true); - -#if defined(MAC_OS_X_VERSION_10_7) - - Thread thread( - new TMethodJob( - this, &ServerApp::runEventsLoop, - NULL)); - - // wait until carbon loop is ready - OSXScreen* screen = dynamic_cast( - m_serverScreen->getPlatformScreen()); - screen->waitForCarbonLoop(); - - runCocoaApp(); -#else - m_events->loop(); -#endif - - DAEMON_RUNNING(false); - - // close down - LOG((CLOG_DEBUG1 "stopping server")); - m_events->removeHandler(m_events->forServerApp().forceReconnect(), - m_events->getSystemTarget()); - m_events->removeHandler(m_events->forServerApp().reloadConfig(), - m_events->getSystemTarget()); - cleanupServer(); - updateStatus(); - LOG((CLOG_NOTE "stopped server")); - - if (argsBase().m_enableIpc) { - cleanupIpcClient(); - } - - return kExitSuccess; -} - -void ServerApp::resetServer(const Event&, void*) -{ - LOG((CLOG_DEBUG1 "resetting server")); - stopServer(); - cleanupServer(); - startServer(); -} - -int -ServerApp::runInner(int argc, char** argv, ILogOutputter* outputter, StartupFunc startup) -{ - // general initialization - m_synergyAddress = new NetworkAddress; - args().m_config = std::make_shared(m_events); - args().m_pname = ARCH->getBasename(argv[0]); - - // install caller's output filter - if (outputter != NULL) { - CLOG->insert(outputter); - } - - // run - int result = startup(argc, argv); - - if (m_taskBarReceiver) - { - // done with task bar receiver - delete m_taskBarReceiver; - } - - delete m_synergyAddress; - return result; -} - -int daemonMainLoopStatic(int argc, const char** argv) { - return ServerApp::instance().daemonMainLoop(argc, argv); -} - -int -ServerApp::standardStartup(int argc, char** argv) -{ - initApp(argc, argv); - - // daemonize if requested - if (args().m_daemon) { - return ARCH->daemonize(daemonName(), daemonMainLoopStatic); - } - else { - return mainLoop(); - } -} - -int -ServerApp::foregroundStartup(int argc, char** argv) -{ - initApp(argc, argv); - - // never daemonize - return mainLoop(); -} - -const char* -ServerApp::daemonName() const -{ -#if SYSAPI_WIN32 - return "Synergy Server"; -#elif SYSAPI_UNIX - return "synergys"; -#endif -} - -const char* -ServerApp::daemonInfo() const -{ -#if SYSAPI_WIN32 - return "Shares this computers mouse and keyboard with other computers."; -#elif SYSAPI_UNIX - return ""; -#endif -} - -void -ServerApp::startNode() -{ - // start the server. if this return false then we've failed and - // we shouldn't retry. - LOG((CLOG_DEBUG1 "starting server")); + case kStarting: + LOG((CLOG_DEBUG1 "retry starting server")); + m_serverState = kInitialized; if (!startServer()) { - m_bye(kExitFailed); + m_events->addEvent(Event(Event::kQuit)); } + break; + } +} + +bool ServerApp::initServer() { + // skip if already initialized or initializing + if (m_serverState != kUninitialized) { + return true; + } + + double retryTime; + synergy::Screen *serverScreen = NULL; + PrimaryClient *primaryClient = NULL; + try { + String name = args().m_config->getCanonicalName(args().m_name); + serverScreen = openServerScreen(); + primaryClient = openPrimaryClient(name, serverScreen); + m_serverScreen = serverScreen; + m_primaryClient = primaryClient; + m_serverState = kInitialized; + updateStatus(); + return true; + } catch (XScreenUnavailable &e) { + LOG((CLOG_WARN "primary screen unavailable: %s", e.what())); + closePrimaryClient(primaryClient); + closeServerScreen(serverScreen); + updateStatus(String("primary screen unavailable: ") + e.what()); + retryTime = e.getRetryTime(); + } catch (XScreenOpenFailure &e) { + LOG((CLOG_CRIT "failed to start server: %s", e.what())); + closePrimaryClient(primaryClient); + closeServerScreen(serverScreen); + return false; + } catch (XBase &e) { + LOG((CLOG_CRIT "failed to start server: %s", e.what())); + closePrimaryClient(primaryClient); + closeServerScreen(serverScreen); + return false; + } + + if (args().m_restartable) { + // install a timer and handler to retry later + assert(m_timer == NULL); + LOG((CLOG_DEBUG "retry in %.0f seconds", retryTime)); + m_timer = m_events->newOneShotTimer(retryTime, NULL); + m_events->adoptHandler( + Event::kTimer, m_timer, + new TMethodEventJob(this, &ServerApp::retryHandler)); + m_serverState = kInitializing; + return true; + } else { + // don't try again + return false; + } +} + +synergy::Screen *ServerApp::openServerScreen() { + synergy::Screen *screen = createScreen(); + screen->setEnableDragDrop(argsBase().m_enableDragDrop); + m_events->adoptHandler( + m_events->forIScreen().error(), screen->getEventTarget(), + new TMethodEventJob(this, &ServerApp::handleScreenError)); + m_events->adoptHandler( + m_events->forIScreen().suspend(), screen->getEventTarget(), + new TMethodEventJob(this, &ServerApp::handleSuspend)); + m_events->adoptHandler( + m_events->forIScreen().resume(), screen->getEventTarget(), + new TMethodEventJob(this, &ServerApp::handleResume)); + return screen; +} + +bool ServerApp::startServer() { + // skip if already started or starting + if (m_serverState == kStarting || m_serverState == kStarted) { + return true; + } + + // initialize if necessary + if (m_serverState != kInitialized) { + if (!initServer()) { + // hard initialization failure + return false; + } + if (m_serverState == kInitializing) { + // not ready to start + m_serverState = kInitializingToStart; + return true; + } + assert(m_serverState == kInitialized); + } + + ClientListener *listener = NULL; + try { + listener = openClientListener(args().m_config->getSynergyAddress()); + m_server = openServer(*args().m_config, m_primaryClient); + listener->setServer(m_server); + m_server->setListener(listener); + m_listener = listener; + updateStatus(); + LOG((CLOG_NOTE "started server, waiting for clients")); + m_serverState = kStarted; + return true; + } catch (XSocketAddressInUse &e) { + if (args().m_restartable) { + LOG((CLOG_ERR "cannot listen for clients: %s", e.what())); + } else { + LOG((CLOG_CRIT "cannot listen for clients: %s", e.what())); + } + closeClientListener(listener); + updateStatus(String("cannot listen for clients: ") + e.what()); + } catch (XBase &e) { + LOG((CLOG_CRIT "failed to start server: %s", e.what())); + closeClientListener(listener); + return false; + } + + if (args().m_restartable) { + // install a timer and handler to retry later + assert(m_timer == NULL); + const auto retryTime = 10.0; + LOG((CLOG_DEBUG "retry in %.0f seconds", retryTime)); + m_timer = m_events->newOneShotTimer(retryTime, NULL); + m_events->adoptHandler( + Event::kTimer, m_timer, + new TMethodEventJob(this, &ServerApp::retryHandler)); + m_serverState = kStarting; + return true; + } else { + // don't try again + return false; + } +} + +synergy::Screen *ServerApp::createScreen() { +#if WINAPI_MSWINDOWS + return new synergy::Screen(new MSWindowsScreen(true, args().m_noHooks, + args().m_stopOnDeskSwitch, + m_events), + m_events); +#elif WINAPI_XWINDOWS + return new synergy::Screen(new XWindowsScreen(args().m_display, true, + args().m_disableXInitThreads, 0, + m_events), + m_events); +#elif WINAPI_CARBON + return new synergy::Screen(new OSXScreen(m_events, true), m_events); +#endif +} + +PrimaryClient *ServerApp::openPrimaryClient(const String &name, + synergy::Screen *screen) { + LOG((CLOG_DEBUG1 "creating primary screen")); + return new PrimaryClient(name, screen); +} + +void ServerApp::handleScreenError(const Event &, void *) { + LOG((CLOG_CRIT "error on screen")); + m_events->addEvent(Event(Event::kQuit)); +} + +void ServerApp::handleSuspend(const Event &, void *) { + if (!m_suspended) { + LOG((CLOG_INFO "suspend")); + stopServer(); + m_suspended = true; + } +} + +void ServerApp::handleResume(const Event &, void *) { + if (m_suspended) { + LOG((CLOG_INFO "resume")); + startServer(); + m_suspended = false; + } +} + +ClientListener *ServerApp::openClientListener(const NetworkAddress &address) { + ClientListener *listen = new ClientListener( + getAddress(address), getSocketFactory(), m_events, args().m_enableCrypto); + + m_events->adoptHandler(m_events->forClientListener().connected(), listen, + new TMethodEventJob( + this, &ServerApp::handleClientConnected, listen)); + + return listen; +} + +Server *ServerApp::openServer(Config &config, PrimaryClient *primaryClient) { + Server *server = + new Server(config, primaryClient, m_serverScreen, m_events, args()); + try { + m_events->adoptHandler( + m_events->forServer().disconnected(), server, + new TMethodEventJob(this, &ServerApp::handleNoClients)); + + m_events->adoptHandler( + m_events->forServer().screenSwitched(), server, + new TMethodEventJob(this, &ServerApp::handleScreenSwitched)); + + } catch (std::bad_alloc &ba) { + delete server; + throw ba; + } + + return server; +} + +void ServerApp::handleNoClients(const Event &, void *) { updateStatus(); } + +void ServerApp::handleScreenSwitched(const Event &e, void *) {} + +ISocketFactory *ServerApp::getSocketFactory() const { + ISocketFactory *socketFactory = nullptr; + + if (args().m_config->isClientMode()) { + socketFactory = new InverseSocketFactory(m_events, getSocketMultiplexer()); + } else { + socketFactory = new TCPSocketFactory(m_events, getSocketMultiplexer()); + } + + return socketFactory; +} + +NetworkAddress ServerApp::getAddress(const NetworkAddress &address) const { + if (args().m_config->isClientMode()) { + const auto clientAddress = args().m_config->getClientAddress(); + NetworkAddress addr(clientAddress.c_str(), kDefaultPort); + addr.resolve(); + return addr; + } else { + return address; + } +} + +int ServerApp::mainLoop() { + // create socket multiplexer. this must happen after daemonization + // on unix because threads evaporate across a fork(). + SocketMultiplexer multiplexer; + setSocketMultiplexer(&multiplexer); + + // 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 (m_synergyAddress->isValid()) { + args().m_config->setSynergyAddress(*m_synergyAddress); + } else if (!args().m_config->getSynergyAddress().isValid()) { + args().m_config->setSynergyAddress(NetworkAddress(kDefaultPort)); + } + + // canonicalize the primary screen name + String 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 + appUtil().startNode(); + + // init ipc client after node start, since create a new screen wipes out + // the event queue (the screen ctors call adoptBuffer). + if (argsBase().m_enableIpc) { + initIpcClient(); + } + + // handle hangup signal by reloading the server's configuration + ARCH->setSignalHandler(Arch::kHANGUP, &reloadSignalHandler, NULL); + m_events->adoptHandler( + m_events->forServerApp().reloadConfig(), m_events->getSystemTarget(), + new TMethodEventJob(this, &ServerApp::reloadConfig)); + + // handle force reconnect event by disconnecting clients. they'll + // reconnect automatically. + m_events->adoptHandler( + m_events->forServerApp().forceReconnect(), m_events->getSystemTarget(), + new TMethodEventJob(this, &ServerApp::forceReconnect)); + + // to work around the sticky meta keys problem, we'll give users + // the option to reset the state of synergys + m_events->adoptHandler( + m_events->forServerApp().resetServer(), m_events->getSystemTarget(), + new TMethodEventJob(this, &ServerApp::resetServer)); + + // run event loop. if startServer() failed we're supposed to retry + // later. the timer installed by startServer() will take care of + // that. + DAEMON_RUNNING(true); + +#if defined(MAC_OS_X_VERSION_10_7) + + Thread thread( + new TMethodJob(this, &ServerApp::runEventsLoop, NULL)); + + // wait until carbon loop is ready + OSXScreen *screen = + dynamic_cast(m_serverScreen->getPlatformScreen()); + screen->waitForCarbonLoop(); + + runCocoaApp(); +#else + m_events->loop(); +#endif + + DAEMON_RUNNING(false); + + // close down + LOG((CLOG_DEBUG1 "stopping server")); + m_events->removeHandler(m_events->forServerApp().forceReconnect(), + m_events->getSystemTarget()); + m_events->removeHandler(m_events->forServerApp().reloadConfig(), + m_events->getSystemTarget()); + cleanupServer(); + updateStatus(); + LOG((CLOG_NOTE "stopped server")); + + if (argsBase().m_enableIpc) { + cleanupIpcClient(); + } + + return kExitSuccess; +} + +void ServerApp::resetServer(const Event &, void *) { + LOG((CLOG_DEBUG1 "resetting server")); + stopServer(); + cleanupServer(); + startServer(); +} + +int ServerApp::runInner(int argc, char **argv, ILogOutputter *outputter, + StartupFunc startup) { + // general initialization + m_synergyAddress = new NetworkAddress; + args().m_config = std::make_shared(m_events); + args().m_pname = ARCH->getBasename(argv[0]); + + // install caller's output filter + if (outputter != NULL) { + CLOG->insert(outputter); + } + + // run + int result = startup(argc, argv); + + if (m_taskBarReceiver) { + // done with task bar receiver + delete m_taskBarReceiver; + } + + delete m_synergyAddress; + return result; +} + +int daemonMainLoopStatic(int argc, const char **argv) { + return ServerApp::instance().daemonMainLoop(argc, argv); +} + +int ServerApp::standardStartup(int argc, char **argv) { + initApp(argc, argv); + + // daemonize if requested + if (args().m_daemon) { + return ARCH->daemonize(daemonName(), daemonMainLoopStatic); + } else { + return mainLoop(); + } +} + +int ServerApp::foregroundStartup(int argc, char **argv) { + initApp(argc, argv); + + // never daemonize + return mainLoop(); +} + +const char *ServerApp::daemonName() const { +#if SYSAPI_WIN32 + return "Synergy Server"; +#elif SYSAPI_UNIX + return "synergys"; +#endif +} + +const char *ServerApp::daemonInfo() const { +#if SYSAPI_WIN32 + return "Shares this computers mouse and keyboard with other computers."; +#elif SYSAPI_UNIX + return ""; +#endif +} + +void ServerApp::startNode() { + // start the server. if this return false then we've failed and + // we shouldn't retry. + LOG((CLOG_DEBUG1 "starting server")); + if (!startServer()) { + m_bye(kExitFailed); + } } diff --git a/src/lib/synergy/ServerApp.h b/src/lib/synergy/ServerApp.h index 1b9a17b25..5db675fcf 100644 --- a/src/lib/synergy/ServerApp.h +++ b/src/lib/synergy/ServerApp.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -18,110 +18,115 @@ #pragma once -#include "synergy/ArgsBase.h" -#include "synergy/App.h" -#include "base/String.h" -#include "server/Config.h" -#include "net/NetworkAddress.h" #include "arch/Arch.h" #include "arch/IArchMultithread.h" -#include "synergy/ArgsBase.h" #include "base/EventTypes.h" +#include "base/String.h" +#include "net/NetworkAddress.h" +#include "server/Config.h" +#include "synergy/App.h" +#include "synergy/ArgsBase.h" #include enum EServerState { - kUninitialized, - kInitializing, - kInitializingToStart, - kInitialized, - kStarting, - kStarted + kUninitialized, + kInitializing, + kInitializingToStart, + kInitialized, + kStarting, + kStarted }; class Server; -namespace synergy { class Screen; } +namespace synergy { +class Screen; +} class ClientListener; class EventQueueTimer; class ILogOutputter; class IEventQueue; class ISocketFactory; namespace lib { - namespace synergy{ - class ServerArgs; - } +namespace synergy { +class ServerArgs; } +} // namespace lib class ServerApp : public App { public: - ServerApp(IEventQueue* events, CreateTaskBarReceiverFunc createTaskBarReceiver); - virtual ~ServerApp(); - - // Parse server specific command line arguments. - void parseArgs(int argc, const char* const* argv); + ServerApp(IEventQueue *events, + CreateTaskBarReceiverFunc createTaskBarReceiver); + virtual ~ServerApp(); - // Prints help specific to server. - void help(); + // Parse server specific command line arguments. + void parseArgs(int argc, const char *const *argv); - // Returns arguments that are common and for server. - lib::synergy::ServerArgs& args() const { return (lib::synergy::ServerArgs&)argsBase(); } + // Prints help specific to server. + void help(); - const char* daemonName() const; - const char* daemonInfo() const; + // Returns arguments that are common and for server. + lib::synergy::ServerArgs &args() const { + return (lib::synergy::ServerArgs &)argsBase(); + } - // TODO: Document these functions. - static void reloadSignalHandler(Arch::ESignal, void*); + const char *daemonName() const; + const char *daemonInfo() const; - void reloadConfig(const Event&, void*); - void loadConfig(); - bool loadConfig(const String& pathname); - void forceReconnect(const Event&, void*); - void resetServer(const Event&, void*); - void handleClientConnected(const Event&, void* vlistener); - void handleClientsDisconnected(const Event&, void*); - void closeServer(Server* server); - void stopRetryTimer(); - void updateStatus(); - void updateStatus(const String& msg); - void closeClientListener(ClientListener* listen); - void stopServer(); - void closePrimaryClient(PrimaryClient* primaryClient); - void closeServerScreen(synergy::Screen* screen); - void cleanupServer(); - bool initServer(); - void retryHandler(const Event&, void*); - synergy::Screen* openServerScreen(); - synergy::Screen* createScreen(); - PrimaryClient* openPrimaryClient(const String& name, synergy::Screen* screen); - void handleScreenError(const Event&, void*); - void handleSuspend(const Event&, void*); - void handleResume(const Event&, void*); - ClientListener* openClientListener(const NetworkAddress& address); - Server* openServer(Config& config, PrimaryClient* primaryClient); - void handleNoClients(const Event&, void*); - bool startServer(); - int mainLoop(); - int runInner(int argc, char** argv, ILogOutputter* outputter, StartupFunc startup); - int standardStartup(int argc, char** argv); - int foregroundStartup(int argc, char** argv); - void startNode(); + // TODO: Document these functions. + static void reloadSignalHandler(Arch::ESignal, void *); - static ServerApp& instance() { return (ServerApp&)App::instance(); } + void reloadConfig(const Event &, void *); + void loadConfig(); + bool loadConfig(const String &pathname); + void forceReconnect(const Event &, void *); + void resetServer(const Event &, void *); + void handleClientConnected(const Event &, void *vlistener); + void handleClientsDisconnected(const Event &, void *); + void closeServer(Server *server); + void stopRetryTimer(); + void updateStatus(); + void updateStatus(const String &msg); + void closeClientListener(ClientListener *listen); + void stopServer(); + void closePrimaryClient(PrimaryClient *primaryClient); + void closeServerScreen(synergy::Screen *screen); + void cleanupServer(); + bool initServer(); + void retryHandler(const Event &, void *); + synergy::Screen *openServerScreen(); + synergy::Screen *createScreen(); + PrimaryClient *openPrimaryClient(const String &name, synergy::Screen *screen); + void handleScreenError(const Event &, void *); + void handleSuspend(const Event &, void *); + void handleResume(const Event &, void *); + ClientListener *openClientListener(const NetworkAddress &address); + Server *openServer(Config &config, PrimaryClient *primaryClient); + void handleNoClients(const Event &, void *); + bool startServer(); + int mainLoop(); + int runInner(int argc, char **argv, ILogOutputter *outputter, + StartupFunc startup); + int standardStartup(int argc, char **argv); + int foregroundStartup(int argc, char **argv); + void startNode(); - Server* getServerPtr() { return m_server; } - - Server* m_server; - EServerState m_serverState; - synergy::Screen* m_serverScreen; - PrimaryClient* m_primaryClient; - ClientListener* m_listener; - EventQueueTimer* m_timer; - NetworkAddress* m_synergyAddress; + static ServerApp &instance() { return (ServerApp &)App::instance(); } + + Server *getServerPtr() { return m_server; } + + Server *m_server; + EServerState m_serverState; + synergy::Screen *m_serverScreen; + PrimaryClient *m_primaryClient; + ClientListener *m_listener; + EventQueueTimer *m_timer; + NetworkAddress *m_synergyAddress; private: - void handleScreenSwitched(const Event&, void* data); - ISocketFactory* getSocketFactory() const; - NetworkAddress getAddress(const NetworkAddress& address) const; + void handleScreenSwitched(const Event &, void *data); + ISocketFactory *getSocketFactory() const; + NetworkAddress getAddress(const NetworkAddress &address) const; }; // configuration file name diff --git a/src/lib/synergy/ServerArgs.cpp b/src/lib/synergy/ServerArgs.cpp index 5d3ec5051..69c9400f4 100644 --- a/src/lib/synergy/ServerArgs.cpp +++ b/src/lib/synergy/ServerArgs.cpp @@ -1,11 +1,11 @@ /* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2014-2020 Symless Ltd. - * + * * 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 LICENSE 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 @@ -18,16 +18,10 @@ #include "ServerArgs.h" namespace lib { - namespace synergy { - - ServerArgs::~ServerArgs() { - } - - - ServerArgs::ServerArgs() { - m_classType = kServer; - } - } -} +namespace synergy { +ServerArgs::~ServerArgs() {} +ServerArgs::ServerArgs() { m_classType = kServer; } +} // namespace synergy +} // namespace lib diff --git a/src/lib/synergy/ServerArgs.h b/src/lib/synergy/ServerArgs.h index 310483bc7..cc3526c77 100644 --- a/src/lib/synergy/ServerArgs.h +++ b/src/lib/synergy/ServerArgs.h @@ -18,35 +18,34 @@ #ifndef SYNERGY_CORE_SERVERARGS_H #define SYNERGY_CORE_SERVERARGS_H -#include #include "ArgsBase.h" -#include "shared/SerialKey.h" #include "server/Config.h" +#include "shared/SerialKey.h" +#include namespace lib { - namespace synergy { - class ServerArgs : public ArgsBase { - /// Public Functions - public: - ServerArgs(); - ServerArgs(ServerArgs const &src) =default; - ServerArgs(ServerArgs &&) =default; - ~ServerArgs() override; +namespace synergy { +class ServerArgs : public ArgsBase { + /// Public Functions +public: + ServerArgs(); + ServerArgs(ServerArgs const &src) = default; + ServerArgs(ServerArgs &&) = default; + ~ServerArgs() override; - ServerArgs& operator=(ServerArgs const &) =default; - ServerArgs& operator=(ServerArgs &&) =default; + ServerArgs &operator=(ServerArgs const &) = default; + ServerArgs &operator=(ServerArgs &&) = default; - /// Public variables - public: - String m_configFile = ""; /// @brief Contains the path to the config file - SerialKey m_serial; /// @brief Contains the serial number and license info - std::shared_ptr m_config; /// @brief Contains the Parsed Configuration settings + /// Public variables +public: + String m_configFile = ""; /// @brief Contains the path to the config file + SerialKey m_serial; /// @brief Contains the serial number and license info + std::shared_ptr + m_config; /// @brief Contains the Parsed Configuration settings - /// Private Functions - private: - - - }; - } -} -#endif //SYNERGY_CORE_SERVERARGS_H \ No newline at end of file + /// Private Functions +private: +}; +} // namespace synergy +} // namespace lib +#endif // SYNERGY_CORE_SERVERARGS_H \ No newline at end of file diff --git a/src/lib/synergy/ServerTaskBarReceiver.cpp b/src/lib/synergy/ServerTaskBarReceiver.cpp index 8a53dc2ad..884fb7e6d 100644 --- a/src/lib/synergy/ServerTaskBarReceiver.cpp +++ b/src/lib/synergy/ServerTaskBarReceiver.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2003 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 LICENSE 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 @@ -17,122 +17,98 @@ */ #include "synergy/ServerTaskBarReceiver.h" -#include "server/Server.h" -#include "mt/Lock.h" -#include "base/String.h" -#include "base/IEventQueue.h" #include "arch/Arch.h" +#include "base/IEventQueue.h" +#include "base/String.h" #include "common/Version.h" +#include "mt/Lock.h" +#include "server/Server.h" // // ServerTaskBarReceiver // -ServerTaskBarReceiver::ServerTaskBarReceiver(IEventQueue* events) : - m_state(kNotRunning), - m_events(events) -{ - // do nothing +ServerTaskBarReceiver::ServerTaskBarReceiver(IEventQueue *events) + : m_state(kNotRunning), m_events(events) { + // do nothing } -ServerTaskBarReceiver::~ServerTaskBarReceiver() -{ - // do nothing +ServerTaskBarReceiver::~ServerTaskBarReceiver() { + // do nothing } -void -ServerTaskBarReceiver::updateStatus(Server* server, const String& errorMsg) -{ - { - // update our status - m_errorMessage = errorMsg; - if (server == NULL) { - if (m_errorMessage.empty()) { - m_state = kNotRunning; - } - else { - m_state = kNotWorking; - } - } - else { - m_clients.clear(); - server->getClients(m_clients); - if (m_clients.size() <= 1) { - m_state = kNotConnected; - } - else { - m_state = kConnected; - } - } - - // let subclasses have a go - onStatusChanged(server); +void ServerTaskBarReceiver::updateStatus(Server *server, + const String &errorMsg) { + { + // update our status + m_errorMessage = errorMsg; + if (server == NULL) { + if (m_errorMessage.empty()) { + m_state = kNotRunning; + } else { + m_state = kNotWorking; + } + } else { + m_clients.clear(); + server->getClients(m_clients); + if (m_clients.size() <= 1) { + m_state = kNotConnected; + } else { + m_state = kConnected; + } } - // tell task bar - ARCH->updateReceiver(this); + // let subclasses have a go + onStatusChanged(server); + } + + // tell task bar + ARCH->updateReceiver(this); } -ServerTaskBarReceiver::EState -ServerTaskBarReceiver::getStatus() const -{ - return m_state; +ServerTaskBarReceiver::EState ServerTaskBarReceiver::getStatus() const { + return m_state; } -const String& -ServerTaskBarReceiver::getErrorMessage() const -{ - return m_errorMessage; +const String &ServerTaskBarReceiver::getErrorMessage() const { + return m_errorMessage; } -const ServerTaskBarReceiver::Clients& -ServerTaskBarReceiver::getClients() const -{ - return m_clients; +const ServerTaskBarReceiver::Clients & +ServerTaskBarReceiver::getClients() const { + return m_clients; } -void -ServerTaskBarReceiver::quit() -{ - m_events->addEvent(Event(Event::kQuit)); +void ServerTaskBarReceiver::quit() { m_events->addEvent(Event(Event::kQuit)); } + +void ServerTaskBarReceiver::onStatusChanged(Server *) { + // do nothing } -void -ServerTaskBarReceiver::onStatusChanged(Server*) -{ - // do nothing +void ServerTaskBarReceiver::lock() const { + // do nothing } -void -ServerTaskBarReceiver::lock() const -{ - // do nothing +void ServerTaskBarReceiver::unlock() const { + // do nothing } -void -ServerTaskBarReceiver::unlock() const -{ - // do nothing -} - -std::string -ServerTaskBarReceiver::getToolTip() const -{ - switch (m_state) { - case kNotRunning: - return synergy::string::sprintf("%s: Not running", kAppVersion); - - case kNotWorking: - return synergy::string::sprintf("%s: %s", - kAppVersion, m_errorMessage.c_str()); - - case kNotConnected: - return synergy::string::sprintf("%s: Waiting for clients", kAppVersion); - - case kConnected: - return synergy::string::sprintf("%s: Connected", kAppVersion); - - default: - return ""; - } +std::string ServerTaskBarReceiver::getToolTip() const { + switch (m_state) { + case kNotRunning: + return synergy::string::sprintf("%s: Not running", kAppVersion); + + case kNotWorking: + return synergy::string::sprintf("%s: %s", kAppVersion, + m_errorMessage.c_str()); + + case kNotConnected: + return synergy::string::sprintf("%s: Waiting for clients", kAppVersion); + + case kConnected: + return synergy::string::sprintf("%s: Connected", kAppVersion); + + default: + return ""; + } } diff --git a/src/lib/synergy/ServerTaskBarReceiver.h b/src/lib/synergy/ServerTaskBarReceiver.h index 274fd54ec..0db53efe2 100644 --- a/src/lib/synergy/ServerTaskBarReceiver.h +++ b/src/lib/synergy/ServerTaskBarReceiver.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2003 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 LICENSE 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 @@ -18,81 +18,85 @@ #pragma once -#include "server/Server.h" -#include "synergy/ServerApp.h" #include "arch/IArchTaskBarReceiver.h" +#include "base/Event.h" #include "base/EventTypes.h" #include "base/String.h" -#include "base/Event.h" #include "common/stdvector.h" +#include "server/Server.h" +#include "synergy/ServerApp.h" class IEventQueue; //! Implementation of IArchTaskBarReceiver for the synergy server class ServerTaskBarReceiver : public IArchTaskBarReceiver { public: - ServerTaskBarReceiver(IEventQueue* events); - virtual ~ServerTaskBarReceiver(); + ServerTaskBarReceiver(IEventQueue *events); + virtual ~ServerTaskBarReceiver(); - //! @name manipulators - //@{ + //! @name manipulators + //@{ - //! Update status - /*! - Determine the status and query required information from the server. - */ - void updateStatus(Server*, const String& errorMsg); + //! Update status + /*! + Determine the status and query required information from the server. + */ + void updateStatus(Server *, const String &errorMsg); - void updateStatus(INode* n, const String& errorMsg) { updateStatus((Server*)n, errorMsg); } + void updateStatus(INode *n, const String &errorMsg) { + updateStatus((Server *)n, errorMsg); + } - //@} + //@} - // IArchTaskBarReceiver overrides - virtual void showStatus() = 0; - virtual void runMenu(int x, int y) = 0; - virtual void primaryAction() = 0; - virtual void lock() const; - virtual void unlock() const; - virtual const Icon getIcon() const = 0; - virtual std::string getToolTip() const; + // IArchTaskBarReceiver overrides + virtual void showStatus() = 0; + virtual void runMenu(int x, int y) = 0; + virtual void primaryAction() = 0; + virtual void lock() const; + virtual void unlock() const; + virtual const Icon getIcon() const = 0; + virtual std::string getToolTip() const; protected: - typedef std::vector Clients; - enum EState { - kNotRunning, - kNotWorking, - kNotConnected, - kConnected, - kMaxState - }; + typedef std::vector Clients; + enum EState { + kNotRunning, + kNotWorking, + kNotConnected, + kConnected, + kMaxState + }; - //! Get status - EState getStatus() const; + //! Get status + EState getStatus() const; - //! Get error message - const String& getErrorMessage() const; + //! Get error message + const String &getErrorMessage() const; - //! Get connected clients - const Clients& getClients() const; + //! Get connected clients + const Clients &getClients() const; - //! Quit app - /*! - Causes the application to quit gracefully - */ - void quit(); + //! Quit app + /*! + Causes the application to quit gracefully + */ + void quit(); - //! Status change notification - /*! - Called when status changes. The default implementation does - nothing. - */ - virtual void onStatusChanged(Server* server); + //! Status change notification + /*! + Called when status changes. The default implementation does + nothing. + */ + virtual void onStatusChanged(Server *server); private: - EState m_state; - String m_errorMessage; - Clients m_clients; - IEventQueue* m_events; + EState m_state; + String m_errorMessage; + Clients m_clients; + IEventQueue *m_events; }; -IArchTaskBarReceiver* createTaskBarReceiver(const BufferedLogOutputter* logBuffer, IEventQueue* events); +IArchTaskBarReceiver * +createTaskBarReceiver(const BufferedLogOutputter *logBuffer, + IEventQueue *events); diff --git a/src/lib/synergy/StreamChunker.cpp b/src/lib/synergy/StreamChunker.cpp index da5ba414b..52c313a3a 100644 --- a/src/lib/synergy/StreamChunker.cpp +++ b/src/lib/synergy/StreamChunker.cpp @@ -1,11 +1,11 @@ /* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2013-2016 Symless Ltd. - * + * * 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 LICENSE 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 @@ -17,150 +17,144 @@ #include "synergy/StreamChunker.h" -#include "mt/Lock.h" -#include "mt/Mutex.h" -#include "synergy/FileChunk.h" -#include "synergy/ClipboardChunk.h" -#include "synergy/protocol_types.h" -#include "base/EventTypes.h" #include "base/Event.h" -#include "base/IEventQueue.h" #include "base/EventTypes.h" +#include "base/IEventQueue.h" #include "base/Log.h" #include "base/Stopwatch.h" #include "base/String.h" #include "common/stdexcept.h" +#include "mt/Lock.h" +#include "mt/Mutex.h" +#include "synergy/ClipboardChunk.h" +#include "synergy/FileChunk.h" +#include "synergy/protocol_types.h" #include using namespace std; -static const size_t g_chunkSize = 512 * 1024; //512kb +static const size_t g_chunkSize = 512 * 1024; // 512kb bool StreamChunker::s_isChunkingFile = false; bool StreamChunker::s_interruptFile = false; -Mutex* StreamChunker::s_interruptMutex = NULL; +Mutex *StreamChunker::s_interruptMutex = NULL; -void -StreamChunker::sendFile( - char* filename, - IEventQueue* events, - void* eventTarget) -{ - s_isChunkingFile = true; - - std::fstream file(static_cast(filename), std::ios::in | std::ios::binary); +void StreamChunker::sendFile(char *filename, IEventQueue *events, + void *eventTarget) { + s_isChunkingFile = true; - if (!file.is_open()) { - throw runtime_error("failed to open file"); + std::fstream file(static_cast(filename), + std::ios::in | std::ios::binary); + + if (!file.is_open()) { + throw runtime_error("failed to open file"); + } + + // check file size + file.seekg(0, std::ios::end); + size_t size = (size_t)file.tellg(); + + // send first message (file size) + String fileSize = synergy::string::sizeTypeToString(size); + FileChunk *sizeMessage = FileChunk::start(fileSize); + + events->addEvent( + Event(events->forFile().fileChunkSending(), eventTarget, sizeMessage)); + + // send chunk messages with a fixed chunk size + size_t sentLength = 0; + size_t chunkSize = g_chunkSize; + file.seekg(0, std::ios::beg); + + while (true) { + if (s_interruptFile) { + s_interruptFile = false; + LOG((CLOG_DEBUG "file transmission interrupted")); + break; } - // check file size - file.seekg (0, std::ios::end); - size_t size = (size_t)file.tellg(); + events->addEvent(Event(events->forFile().keepAlive(), eventTarget)); - // send first message (file size) - String fileSize = synergy::string::sizeTypeToString(size); - FileChunk* sizeMessage = FileChunk::start(fileSize); - - events->addEvent(Event(events->forFile().fileChunkSending(), eventTarget, sizeMessage)); - - // send chunk messages with a fixed chunk size - size_t sentLength = 0; - size_t chunkSize = g_chunkSize; - file.seekg (0, std::ios::beg); - - while (true) { - if (s_interruptFile) { - s_interruptFile = false; - LOG((CLOG_DEBUG "file transmission interrupted")); - break; - } - - events->addEvent(Event(events->forFile().keepAlive(), eventTarget)); - - // make sure we don't read too much from the mock data. - if (sentLength + chunkSize > size) { - chunkSize = size - sentLength; - } - - char* chunkData = new char[chunkSize]; - file.read(chunkData, chunkSize); - UInt8* data = reinterpret_cast(chunkData); - FileChunk* fileChunk = FileChunk::data(data, chunkSize); - delete[] chunkData; - - events->addEvent(Event(events->forFile().fileChunkSending(), eventTarget, fileChunk)); - - sentLength += chunkSize; - file.seekg (sentLength, std::ios::beg); - - if (sentLength == size) { - break; - } + // make sure we don't read too much from the mock data. + if (sentLength + chunkSize > size) { + chunkSize = size - sentLength; } - // send last message - FileChunk* end = FileChunk::end(); + char *chunkData = new char[chunkSize]; + file.read(chunkData, chunkSize); + UInt8 *data = reinterpret_cast(chunkData); + FileChunk *fileChunk = FileChunk::data(data, chunkSize); + delete[] chunkData; - events->addEvent(Event(events->forFile().fileChunkSending(), eventTarget, end)); + events->addEvent( + Event(events->forFile().fileChunkSending(), eventTarget, fileChunk)); - file.close(); - - s_isChunkingFile = false; + sentLength += chunkSize; + file.seekg(sentLength, std::ios::beg); + + if (sentLength == size) { + break; + } + } + + // send last message + FileChunk *end = FileChunk::end(); + + events->addEvent( + Event(events->forFile().fileChunkSending(), eventTarget, end)); + + file.close(); + + s_isChunkingFile = false; } -void -StreamChunker::sendClipboard( - String& data, - size_t size, - ClipboardID id, - UInt32 sequence, - IEventQueue* events, - void* eventTarget) -{ - // send first message (data size) - String dataSize = synergy::string::sizeTypeToString(size); - ClipboardChunk* sizeMessage = ClipboardChunk::start(id, sequence, dataSize); - - events->addEvent(Event(events->forClipboard().clipboardSending(), eventTarget, sizeMessage)); +void StreamChunker::sendClipboard(String &data, size_t size, ClipboardID id, + UInt32 sequence, IEventQueue *events, + void *eventTarget) { + // send first message (data size) + String dataSize = synergy::string::sizeTypeToString(size); + ClipboardChunk *sizeMessage = ClipboardChunk::start(id, sequence, dataSize); - // send clipboard chunk with a fixed size - size_t sentLength = 0; - size_t chunkSize = g_chunkSize; - - while (true) { - events->addEvent(Event(events->forFile().keepAlive(), eventTarget)); - - // make sure we don't read too much from the mock data. - if (sentLength + chunkSize > size) { - chunkSize = size - sentLength; - } + events->addEvent(Event(events->forClipboard().clipboardSending(), eventTarget, + sizeMessage)); - String chunk(data.substr(sentLength, chunkSize).c_str(), chunkSize); - ClipboardChunk* dataChunk = ClipboardChunk::data(id, sequence, chunk); - - events->addEvent(Event(events->forClipboard().clipboardSending(), eventTarget, dataChunk)); + // send clipboard chunk with a fixed size + size_t sentLength = 0; + size_t chunkSize = g_chunkSize; - sentLength += chunkSize; - if (sentLength == size) { - break; - } + while (true) { + events->addEvent(Event(events->forFile().keepAlive(), eventTarget)); + + // make sure we don't read too much from the mock data. + if (sentLength + chunkSize > size) { + chunkSize = size - sentLength; } - // send last message - ClipboardChunk* end = ClipboardChunk::end(id, sequence); + String chunk(data.substr(sentLength, chunkSize).c_str(), chunkSize); + ClipboardChunk *dataChunk = ClipboardChunk::data(id, sequence, chunk); - events->addEvent(Event(events->forClipboard().clipboardSending(), eventTarget, end)); - - LOG((CLOG_DEBUG "sent clipboard size=%d", sentLength)); -} + events->addEvent(Event(events->forClipboard().clipboardSending(), + eventTarget, dataChunk)); -void -StreamChunker::interruptFile() -{ - if (s_isChunkingFile) { - s_interruptFile = true; - LOG((CLOG_INFO "previous dragged file has become invalid")); + sentLength += chunkSize; + if (sentLength == size) { + break; } + } + + // send last message + ClipboardChunk *end = ClipboardChunk::end(id, sequence); + + events->addEvent( + Event(events->forClipboard().clipboardSending(), eventTarget, end)); + + LOG((CLOG_DEBUG "sent clipboard size=%d", sentLength)); +} + +void StreamChunker::interruptFile() { + if (s_isChunkingFile) { + s_interruptFile = true; + LOG((CLOG_INFO "previous dragged file has become invalid")); + } } diff --git a/src/lib/synergy/StreamChunker.h b/src/lib/synergy/StreamChunker.h index a67d37778..5160842b8 100644 --- a/src/lib/synergy/StreamChunker.h +++ b/src/lib/synergy/StreamChunker.h @@ -1,11 +1,11 @@ /* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2013-2016 Symless Ltd. - * + * * 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 LICENSE 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 @@ -17,29 +17,22 @@ #pragma once -#include "synergy/clipboard_types.h" #include "base/String.h" +#include "synergy/clipboard_types.h" class IEventQueue; class Mutex; class StreamChunker { public: - static void sendFile( - char* filename, - IEventQueue* events, - void* eventTarget); - static void sendClipboard( - String& data, - size_t size, - ClipboardID id, - UInt32 sequence, - IEventQueue* events, - void* eventTarget); - static void interruptFile(); - + static void sendFile(char *filename, IEventQueue *events, void *eventTarget); + static void sendClipboard(String &data, size_t size, ClipboardID id, + UInt32 sequence, IEventQueue *events, + void *eventTarget); + static void interruptFile(); + private: - static bool s_isChunkingFile; - static bool s_interruptFile; - static Mutex* s_interruptMutex; + static bool s_isChunkingFile; + static bool s_interruptFile; + static Mutex *s_interruptMutex; }; diff --git a/src/lib/synergy/ToolApp.cpp b/src/lib/synergy/ToolApp.cpp index c1280c4a4..5af72edf8 100644 --- a/src/lib/synergy/ToolApp.cpp +++ b/src/lib/synergy/ToolApp.cpp @@ -17,10 +17,10 @@ #include "synergy/ToolApp.h" -#include "synergy/ArgParser.h" #include "arch/Arch.h" #include "base/Log.h" #include "base/String.h" +#include "synergy/ArgParser.h" #include #include @@ -31,74 +31,58 @@ #define JSON_URL "https://symless.com/account/json/" -enum { - kErrorOk, - kErrorArgs, - kErrorException, - kErrorUnknown -}; +enum { kErrorOk, kErrorArgs, kErrorException, kErrorUnknown }; -UInt32 -ToolApp::run(int argc, char** argv) -{ - if (argc <= 1) { - std::cerr << "no args" << std::endl; - return kErrorArgs; +UInt32 ToolApp::run(int argc, char **argv) { + if (argc <= 1) { + std::cerr << "no args" << std::endl; + return kErrorArgs; + } + + try { + ArgParser argParser(this); + bool result = argParser.parseToolArgs(m_args, argc, argv); + + if (!result) { + m_bye(kExitArgs); } - try { - ArgParser argParser(this); - bool result = argParser.parseToolArgs(m_args, argc, argv); - - if (!result) { - m_bye(kExitArgs); - } - - if (m_args.m_printActiveDesktopName) { + if (m_args.m_printActiveDesktopName) { #if SYSAPI_WIN32 - MSWindowsSession session; - String name = session.getActiveDesktopName(); - if (name.empty()) { - LOG((CLOG_CRIT "failed to get active desktop name")); - return kExitFailed; - } - else { - String output = synergy::string::sprintf("activeDesktop:%s", name.c_str()); - LOG((CLOG_INFO "%s", output.c_str())); - } + MSWindowsSession session; + String name = session.getActiveDesktopName(); + if (name.empty()) { + LOG((CLOG_CRIT "failed to get active desktop name")); + return kExitFailed; + } else { + String output = + synergy::string::sprintf("activeDesktop:%s", name.c_str()); + LOG((CLOG_INFO "%s", output.c_str())); + } #endif - } - else if (m_args.m_getInstalledDir) { - std::cout << ARCH->getInstalledDirectory() << std::endl; - } - else if (m_args.m_getProfileDir) { - std::cout << ARCH->getProfileDirectory() << std::endl; - } - else if (m_args.m_getArch) { - std::cout << ARCH->getPlatformName() << std::endl; - } - else { - throw XSynergy("Nothing to do"); - } - } - catch (std::exception& e) { - LOG((CLOG_CRIT "an error occurred: %s\n", e.what())); - return kExitFailed; - } - catch (...) { - LOG((CLOG_CRIT "an unknown error occurred\n")); - return kExitFailed; + } else if (m_args.m_getInstalledDir) { + std::cout << ARCH->getInstalledDirectory() << std::endl; + } else if (m_args.m_getProfileDir) { + std::cout << ARCH->getProfileDirectory() << std::endl; + } else if (m_args.m_getArch) { + std::cout << ARCH->getPlatformName() << std::endl; + } else { + throw XSynergy("Nothing to do"); } + } catch (std::exception &e) { + LOG((CLOG_CRIT "an error occurred: %s\n", e.what())); + return kExitFailed; + } catch (...) { + LOG((CLOG_CRIT "an unknown error occurred\n")); + return kExitFailed; + } #if WINAPI_XWINDOWS - // HACK: avoid sigsegv on linux - m_bye(kErrorOk); + // HACK: avoid sigsegv on linux + m_bye(kErrorOk); #endif - return kErrorOk; + return kErrorOk; } -void -ToolApp::help() -{ -} +void ToolApp::help() {} diff --git a/src/lib/synergy/ToolApp.h b/src/lib/synergy/ToolApp.h index d0eb6cb42..693cdaeb2 100644 --- a/src/lib/synergy/ToolApp.h +++ b/src/lib/synergy/ToolApp.h @@ -1,11 +1,11 @@ /* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2014-2016 Symless Ltd. - * + * * 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 LICENSE 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 @@ -17,21 +17,20 @@ #pragma once +#include "common/basic_types.h" #include "synergy/App.h" #include "synergy/ToolArgs.h" -#include "common/basic_types.h" -class ToolApp : public MinimalApp -{ +class ToolApp : public MinimalApp { public: - UInt32 run(int argc, char** argv); - void help(); + UInt32 run(int argc, char **argv); + void help(); private: - void loginAuth(); - void notifyActivation(); - void notifyUpdate(); + void loginAuth(); + void notifyActivation(); + void notifyUpdate(); private: - ToolArgs m_args; + ToolArgs m_args; }; diff --git a/src/lib/synergy/ToolArgs.cpp b/src/lib/synergy/ToolArgs.cpp index 8292005bc..48ae3071d 100644 --- a/src/lib/synergy/ToolArgs.cpp +++ b/src/lib/synergy/ToolArgs.cpp @@ -1,11 +1,11 @@ /* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2014-2016 Symless Ltd. - * + * * 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 LICENSE 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 @@ -17,10 +17,6 @@ #include "synergy/ToolArgs.h" -ToolArgs::ToolArgs() : - m_printActiveDesktopName(false), - m_getInstalledDir(false), - m_getProfileDir(false), - m_getArch(false) -{ -} +ToolArgs::ToolArgs() + : m_printActiveDesktopName(false), m_getInstalledDir(false), + m_getProfileDir(false), m_getArch(false) {} diff --git a/src/lib/synergy/ToolArgs.h b/src/lib/synergy/ToolArgs.h index 8a50da0d4..14337f309 100644 --- a/src/lib/synergy/ToolArgs.h +++ b/src/lib/synergy/ToolArgs.h @@ -1,11 +1,11 @@ /* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2014-2016 Symless Ltd. - * + * * 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 LICENSE 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 @@ -21,11 +21,11 @@ class ToolArgs { public: - ToolArgs(); + ToolArgs(); public: - bool m_printActiveDesktopName; - bool m_getInstalledDir; - bool m_getProfileDir; - bool m_getArch; + bool m_printActiveDesktopName; + bool m_getInstalledDir; + bool m_getProfileDir; + bool m_getArch; }; diff --git a/src/lib/synergy/XScreen.cpp b/src/lib/synergy/XScreen.cpp index 5e34ef63f..e822ba13d 100644 --- a/src/lib/synergy/XScreen.cpp +++ b/src/lib/synergy/XScreen.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -22,47 +22,31 @@ // XScreenOpenFailure // -String -XScreenOpenFailure::getWhat() const throw() -{ - return format("XScreenOpenFailure", "unable to open screen"); +String XScreenOpenFailure::getWhat() const throw() { + return format("XScreenOpenFailure", "unable to open screen"); } - // // XScreenXInputFailure // -String -XScreenXInputFailure::getWhat() const throw() -{ - return ""; -} - +String XScreenXInputFailure::getWhat() const throw() { return ""; } // // XScreenUnavailable // -XScreenUnavailable::XScreenUnavailable(double timeUntilRetry) : - m_timeUntilRetry(timeUntilRetry) -{ - // do nothing +XScreenUnavailable::XScreenUnavailable(double timeUntilRetry) + : m_timeUntilRetry(timeUntilRetry) { + // do nothing } -XScreenUnavailable::~XScreenUnavailable() _NOEXCEPT -{ - // do nothing +XScreenUnavailable::~XScreenUnavailable() _NOEXCEPT { + // do nothing } -double -XScreenUnavailable::getRetryTime() const -{ - return m_timeUntilRetry; -} +double XScreenUnavailable::getRetryTime() const { return m_timeUntilRetry; } -String -XScreenUnavailable::getWhat() const throw() -{ - return format("XScreenUnavailable", "unable to open screen"); +String XScreenUnavailable::getWhat() const throw() { + return format("XScreenUnavailable", "unable to open screen"); } diff --git a/src/lib/synergy/XScreen.h b/src/lib/synergy/XScreen.h index 6b5083163..001347126 100644 --- a/src/lib/synergy/XScreen.h +++ b/src/lib/synergy/XScreen.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -42,27 +42,27 @@ may be successful. */ class XScreenUnavailable : public XScreenOpenFailure { public: - /*! - \c timeUntilRetry is the suggested time the caller should wait until - trying to open the screen again. - */ - XScreenUnavailable(double timeUntilRetry); - virtual ~XScreenUnavailable() _NOEXCEPT; + /*! + \c timeUntilRetry is the suggested time the caller should wait until + trying to open the screen again. + */ + XScreenUnavailable(double timeUntilRetry); + virtual ~XScreenUnavailable() _NOEXCEPT; - //! @name manipulators - //@{ + //! @name manipulators + //@{ - //! Get retry time - /*! - Returns the suggested time to wait until retrying to open the screen. - */ - double getRetryTime() const; + //! Get retry time + /*! + Returns the suggested time to wait until retrying to open the screen. + */ + double getRetryTime() const; - //@} + //@} protected: - virtual String getWhat() const throw(); + virtual String getWhat() const throw(); private: - double m_timeUntilRetry; + double m_timeUntilRetry; }; diff --git a/src/lib/synergy/XSynergy.cpp b/src/lib/synergy/XSynergy.cpp index 77d044774..883e0201d 100644 --- a/src/lib/synergy/XSynergy.cpp +++ b/src/lib/synergy/XSynergy.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -23,111 +23,66 @@ // XBadClient // -String -XBadClient::getWhat() const throw() -{ - return "XBadClient"; -} - +String XBadClient::getWhat() const throw() { return "XBadClient"; } // // XIncompatibleClient // -XIncompatibleClient::XIncompatibleClient(int major, int minor) : - m_major(major), - m_minor(minor) -{ - // do nothing +XIncompatibleClient::XIncompatibleClient(int major, int minor) + : m_major(major), m_minor(minor) { + // do nothing } -int -XIncompatibleClient::getMajor() const throw() -{ - return m_major; -} +int XIncompatibleClient::getMajor() const throw() { return m_major; } -int -XIncompatibleClient::getMinor() const throw() -{ - return m_minor; -} +int XIncompatibleClient::getMinor() const throw() { return m_minor; } -String -XIncompatibleClient::getWhat() const throw() -{ - return format("XIncompatibleClient", "incompatible client %{1}.%{2}", - synergy::string::sprintf("%d", m_major).c_str(), - synergy::string::sprintf("%d", m_minor).c_str()); +String XIncompatibleClient::getWhat() const throw() { + return format("XIncompatibleClient", "incompatible client %{1}.%{2}", + synergy::string::sprintf("%d", m_major).c_str(), + synergy::string::sprintf("%d", m_minor).c_str()); } - // // XDuplicateClient // -XDuplicateClient::XDuplicateClient(const String& name) : - m_name(name) -{ - // do nothing +XDuplicateClient::XDuplicateClient(const String &name) : m_name(name) { + // do nothing } -const String& -XDuplicateClient::getName() const throw() -{ - return m_name; -} +const String &XDuplicateClient::getName() const throw() { return m_name; } -String -XDuplicateClient::getWhat() const throw() -{ - return format("XDuplicateClient", "duplicate client %{1}", m_name.c_str()); +String XDuplicateClient::getWhat() const throw() { + return format("XDuplicateClient", "duplicate client %{1}", m_name.c_str()); } - // // XUnknownClient // -XUnknownClient::XUnknownClient(const String& name) : - m_name(name) -{ - // do nothing +XUnknownClient::XUnknownClient(const String &name) : m_name(name) { + // do nothing } -const String& -XUnknownClient::getName() const throw() -{ - return m_name; -} +const String &XUnknownClient::getName() const throw() { return m_name; } -String -XUnknownClient::getWhat() const throw() -{ - return format("XUnknownClient", "unknown client %{1}", m_name.c_str()); +String XUnknownClient::getWhat() const throw() { + return format("XUnknownClient", "unknown client %{1}", m_name.c_str()); } - // // XExitApp // -XExitApp::XExitApp(int code) : - m_code(code) -{ - // do nothing +XExitApp::XExitApp(int code) : m_code(code) { + // do nothing } -int -XExitApp::getCode() const throw() -{ - return m_code; -} +int XExitApp::getCode() const throw() { return m_code; } -String -XExitApp::getWhat() const throw() -{ - return format( - "XExitApp", "exiting with code %{1}", - synergy::string::sprintf("%d", m_code).c_str()); +String XExitApp::getWhat() const throw() { + return format("XExitApp", "exiting with code %{1}", + synergy::string::sprintf("%d", m_code).c_str()); } diff --git a/src/lib/synergy/XSynergy.h b/src/lib/synergy/XSynergy.h index 20a974248..c8c17a133 100644 --- a/src/lib/synergy/XSynergy.h +++ b/src/lib/synergy/XSynergy.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -41,24 +41,24 @@ Thrown when a client attempting to connect has an incompatible version. */ class XIncompatibleClient : public XSynergy { public: - XIncompatibleClient(int major, int minor); + XIncompatibleClient(int major, int minor); - //! @name accessors - //@{ + //! @name accessors + //@{ - //! Get client's major version number - int getMajor() const throw(); - //! Get client's minor version number - int getMinor() const throw(); + //! Get client's major version number + int getMajor() const throw(); + //! Get client's minor version number + int getMinor() const throw(); - //@} + //@} protected: - virtual String getWhat() const throw(); + virtual String getWhat() const throw(); private: - int m_major; - int m_minor; + int m_major; + int m_minor; }; //! Client already connected exception @@ -68,23 +68,22 @@ a client that is already connected. */ class XDuplicateClient : public XSynergy { public: - XDuplicateClient(const String& name); - virtual ~XDuplicateClient() _NOEXCEPT { } + XDuplicateClient(const String &name); + virtual ~XDuplicateClient() _NOEXCEPT {} - //! @name accessors - //@{ + //! @name accessors + //@{ - //! Get client's name - virtual const String& - getName() const throw(); + //! Get client's name + virtual const String &getName() const throw(); - //@} + //@} protected: - virtual String getWhat() const throw(); + virtual String getWhat() const throw(); private: - String m_name; + String m_name; }; //! Client not in map exception @@ -94,42 +93,41 @@ unknown to the server. */ class XUnknownClient : public XSynergy { public: - XUnknownClient(const String& name); - virtual ~XUnknownClient() _NOEXCEPT { } + XUnknownClient(const String &name); + virtual ~XUnknownClient() _NOEXCEPT {} - //! @name accessors - //@{ + //! @name accessors + //@{ - //! Get the client's name - virtual const String& - getName() const throw(); + //! Get the client's name + virtual const String &getName() const throw(); - //@} + //@} protected: - virtual String getWhat() const throw(); + virtual String getWhat() const throw(); private: - String m_name; + String m_name; }; //! Generic exit eception /*! -Thrown when we want to abort, with the opportunity to clean up. This is a -little bit of a hack, but it's a better way of exiting, than just calling +Thrown when we want to abort, with the opportunity to clean up. This is a +little bit of a hack, but it's a better way of exiting, than just calling exit(int). */ class XExitApp : public XSynergy { public: - XExitApp(int code); - virtual ~XExitApp() _NOEXCEPT { } + XExitApp(int code); + virtual ~XExitApp() _NOEXCEPT {} - //! Get the exit code - int getCode() const throw(); + //! Get the exit code + int getCode() const throw(); protected: - virtual String getWhat() const throw(); - + virtual String getWhat() const throw(); + private: - int m_code; + int m_code; }; diff --git a/src/lib/synergy/clipboard_types.h b/src/lib/synergy/clipboard_types.h index d8275d1b1..3de4ebb09 100644 --- a/src/lib/synergy/clipboard_types.h +++ b/src/lib/synergy/clipboard_types.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -24,7 +24,7 @@ /*! Type to hold a clipboard identifier. */ -typedef UInt8 ClipboardID; +typedef UInt8 ClipboardID; //! @name Clipboard identifiers //@{ @@ -34,9 +34,9 @@ typedef UInt8 ClipboardID; // platforms that can treat the selection as a clipboard (e.g. X // windows). clipboard identifiers must be sequential starting // at zero. -static const ClipboardID kClipboardClipboard = 0; -static const ClipboardID kClipboardSelection = 1; +static const ClipboardID kClipboardClipboard = 0; +static const ClipboardID kClipboardSelection = 1; // the number of clipboards (i.e. one greater than the last clipboard id) -static const ClipboardID kClipboardEnd = 2; +static const ClipboardID kClipboardEnd = 2; //@} diff --git a/src/lib/synergy/key_types.cpp b/src/lib/synergy/key_types.cpp index e82feaaee..3da3162f9 100644 --- a/src/lib/synergy/key_types.cpp +++ b/src/lib/synergy/key_types.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -19,190 +19,190 @@ #include "synergy/key_types.h" const KeyNameMapEntry kKeyNameMap[] = { - { "AltGr", kKeyAltGr }, - { "Alt_L", kKeyAlt_L }, - { "Alt_R", kKeyAlt_R }, - { "AppMail", kKeyAppMail }, - { "AppMedia", kKeyAppMedia }, - { "AppUser1", kKeyAppUser1 }, - { "AppUser2", kKeyAppUser2 }, - { "AudioDown", kKeyAudioDown }, - { "AudioMute", kKeyAudioMute }, - { "AudioNext", kKeyAudioNext }, - { "AudioPlay", kKeyAudioPlay }, - { "AudioPrev", kKeyAudioPrev }, - { "AudioStop", kKeyAudioStop }, - { "AudioUp", kKeyAudioUp }, - { "BackSpace", kKeyBackSpace }, - { "Begin", kKeyBegin }, - { "Break", kKeyBreak }, - { "Cancel", kKeyCancel }, - { "CapsLock", kKeyCapsLock }, - { "Clear", kKeyClear }, - { "Control_L", kKeyControl_L }, - { "Control_R", kKeyControl_R }, - { "Delete", kKeyDelete }, - { "Down", kKeyDown }, - { "Eject", kKeyEject }, - { "End", kKeyEnd }, - { "Escape", kKeyEscape }, - { "Execute", kKeyExecute }, - { "F1", kKeyF1 }, - { "F2", kKeyF2 }, - { "F3", kKeyF3 }, - { "F4", kKeyF4 }, - { "F5", kKeyF5 }, - { "F6", kKeyF6 }, - { "F7", kKeyF7 }, - { "F8", kKeyF8 }, - { "F9", kKeyF9 }, - { "F10", kKeyF10 }, - { "F11", kKeyF11 }, - { "F12", kKeyF12 }, - { "F13", kKeyF13 }, - { "F14", kKeyF14 }, - { "F15", kKeyF15 }, - { "F16", kKeyF16 }, - { "F17", kKeyF17 }, - { "F18", kKeyF18 }, - { "F19", kKeyF19 }, - { "F20", kKeyF20 }, - { "F21", kKeyF21 }, - { "F22", kKeyF22 }, - { "F23", kKeyF23 }, - { "F24", kKeyF24 }, - { "F25", kKeyF25 }, - { "F26", kKeyF26 }, - { "F27", kKeyF27 }, - { "F28", kKeyF28 }, - { "F29", kKeyF29 }, - { "F30", kKeyF30 }, - { "F31", kKeyF31 }, - { "F32", kKeyF32 }, - { "F33", kKeyF33 }, - { "F34", kKeyF34 }, - { "F35", kKeyF35 }, - { "Find", kKeyFind }, - { "Help", kKeyHelp }, - { "Henkan", kKeyHenkan }, - { "Home", kKeyHome }, - { "Hyper_L", kKeyHyper_L }, - { "Hyper_R", kKeyHyper_R }, - { "Insert", kKeyInsert }, - { "KP_0", kKeyKP_0 }, - { "KP_1", kKeyKP_1 }, - { "KP_2", kKeyKP_2 }, - { "KP_3", kKeyKP_3 }, - { "KP_4", kKeyKP_4 }, - { "KP_5", kKeyKP_5 }, - { "KP_6", kKeyKP_6 }, - { "KP_7", kKeyKP_7 }, - { "KP_8", kKeyKP_8 }, - { "KP_9", kKeyKP_9 }, - { "KP_Add", kKeyKP_Add }, - { "KP_Begin", kKeyKP_Begin }, - { "KP_Decimal", kKeyKP_Decimal }, - { "KP_Delete", kKeyKP_Delete }, - { "KP_Divide", kKeyKP_Divide }, - { "KP_Down", kKeyKP_Down }, - { "KP_End", kKeyKP_End }, - { "KP_Enter", kKeyKP_Enter }, - { "KP_Equal", kKeyKP_Equal }, - { "KP_F1", kKeyKP_F1 }, - { "KP_F2", kKeyKP_F2 }, - { "KP_F3", kKeyKP_F3 }, - { "KP_F4", kKeyKP_F4 }, - { "KP_Home", kKeyKP_Home }, - { "KP_Insert", kKeyKP_Insert }, - { "KP_Left", kKeyKP_Left }, - { "KP_Multiply", kKeyKP_Multiply }, - { "KP_PageDown", kKeyKP_PageDown }, - { "KP_PageUp", kKeyKP_PageUp }, - { "KP_Right", kKeyKP_Right }, - { "KP_Separator", kKeyKP_Separator }, - { "KP_Space", kKeyKP_Space }, - { "KP_Subtract", kKeyKP_Subtract }, - { "KP_Tab", kKeyKP_Tab }, - { "KP_Up", kKeyKP_Up }, - { "Left", kKeyLeft }, - { "LeftTab", kKeyLeftTab }, - { "Linefeed", kKeyLinefeed }, - { "Menu", kKeyMenu }, - { "Meta_L", kKeyMeta_L }, - { "Meta_R", kKeyMeta_R }, - { "NumLock", kKeyNumLock }, - { "PageDown", kKeyPageDown }, - { "PageUp", kKeyPageUp }, - { "Pause", kKeyPause }, - { "Print", kKeyPrint }, - { "Redo", kKeyRedo }, - { "Return", kKeyReturn }, - { "Right", kKeyRight }, - { "ScrollLock", kKeyScrollLock }, - { "Select", kKeySelect }, - { "ShiftLock", kKeyShiftLock }, - { "Shift_L", kKeyShift_L }, - { "Shift_R", kKeyShift_R }, - { "Sleep", kKeySleep }, - { "Super_L", kKeySuper_L }, - { "Super_R", kKeySuper_R }, - { "SysReq", kKeySysReq }, - { "Tab", kKeyTab }, - { "Undo", kKeyUndo }, - { "Up", kKeyUp }, - { "WWWBack", kKeyWWWBack }, - { "WWWFavorites", kKeyWWWFavorites }, - { "WWWForward", kKeyWWWForward }, - { "WWWHome", kKeyWWWHome }, - { "WWWRefresh", kKeyWWWRefresh }, - { "WWWSearch", kKeyWWWSearch }, - { "WWWStop", kKeyWWWStop }, - { "Zenkaku", kKeyZenkaku }, - { "Space", 0x0020 }, - { "Exclaim", 0x0021 }, - { "DoubleQuote", 0x0022 }, - { "Number", 0x0023 }, - { "Dollar", 0x0024 }, - { "Percent", 0x0025 }, - { "Ampersand", 0x0026 }, - { "Apostrophe", 0x0027 }, - { "ParenthesisL", 0x0028 }, - { "ParenthesisR", 0x0029 }, - { "Asterisk", 0x002a }, - { "Plus", 0x002b }, - { "Comma", 0x002c }, - { "Minus", 0x002d }, - { "Period", 0x002e }, - { "Slash", 0x002f }, - { "Colon", 0x003a }, - { "Semicolon", 0x003b }, - { "Less", 0x003c }, - { "Equal", 0x003d }, - { "Greater", 0x003e }, - { "Question", 0x003f }, - { "At", 0x0040 }, - { "BracketL", 0x005b }, - { "Backslash", 0x005c }, - { "BracketR", 0x005d }, - { "Circumflex", 0x005e }, - { "Underscore", 0x005f }, - { "Grave", 0x0060 }, - { "BraceL", 0x007b }, - { "Bar", 0x007c }, - { "BraceR", 0x007d }, - { "Tilde", 0x007e }, - { NULL, 0 }, + {"AltGr", kKeyAltGr}, + {"Alt_L", kKeyAlt_L}, + {"Alt_R", kKeyAlt_R}, + {"AppMail", kKeyAppMail}, + {"AppMedia", kKeyAppMedia}, + {"AppUser1", kKeyAppUser1}, + {"AppUser2", kKeyAppUser2}, + {"AudioDown", kKeyAudioDown}, + {"AudioMute", kKeyAudioMute}, + {"AudioNext", kKeyAudioNext}, + {"AudioPlay", kKeyAudioPlay}, + {"AudioPrev", kKeyAudioPrev}, + {"AudioStop", kKeyAudioStop}, + {"AudioUp", kKeyAudioUp}, + {"BackSpace", kKeyBackSpace}, + {"Begin", kKeyBegin}, + {"Break", kKeyBreak}, + {"Cancel", kKeyCancel}, + {"CapsLock", kKeyCapsLock}, + {"Clear", kKeyClear}, + {"Control_L", kKeyControl_L}, + {"Control_R", kKeyControl_R}, + {"Delete", kKeyDelete}, + {"Down", kKeyDown}, + {"Eject", kKeyEject}, + {"End", kKeyEnd}, + {"Escape", kKeyEscape}, + {"Execute", kKeyExecute}, + {"F1", kKeyF1}, + {"F2", kKeyF2}, + {"F3", kKeyF3}, + {"F4", kKeyF4}, + {"F5", kKeyF5}, + {"F6", kKeyF6}, + {"F7", kKeyF7}, + {"F8", kKeyF8}, + {"F9", kKeyF9}, + {"F10", kKeyF10}, + {"F11", kKeyF11}, + {"F12", kKeyF12}, + {"F13", kKeyF13}, + {"F14", kKeyF14}, + {"F15", kKeyF15}, + {"F16", kKeyF16}, + {"F17", kKeyF17}, + {"F18", kKeyF18}, + {"F19", kKeyF19}, + {"F20", kKeyF20}, + {"F21", kKeyF21}, + {"F22", kKeyF22}, + {"F23", kKeyF23}, + {"F24", kKeyF24}, + {"F25", kKeyF25}, + {"F26", kKeyF26}, + {"F27", kKeyF27}, + {"F28", kKeyF28}, + {"F29", kKeyF29}, + {"F30", kKeyF30}, + {"F31", kKeyF31}, + {"F32", kKeyF32}, + {"F33", kKeyF33}, + {"F34", kKeyF34}, + {"F35", kKeyF35}, + {"Find", kKeyFind}, + {"Help", kKeyHelp}, + {"Henkan", kKeyHenkan}, + {"Home", kKeyHome}, + {"Hyper_L", kKeyHyper_L}, + {"Hyper_R", kKeyHyper_R}, + {"Insert", kKeyInsert}, + {"KP_0", kKeyKP_0}, + {"KP_1", kKeyKP_1}, + {"KP_2", kKeyKP_2}, + {"KP_3", kKeyKP_3}, + {"KP_4", kKeyKP_4}, + {"KP_5", kKeyKP_5}, + {"KP_6", kKeyKP_6}, + {"KP_7", kKeyKP_7}, + {"KP_8", kKeyKP_8}, + {"KP_9", kKeyKP_9}, + {"KP_Add", kKeyKP_Add}, + {"KP_Begin", kKeyKP_Begin}, + {"KP_Decimal", kKeyKP_Decimal}, + {"KP_Delete", kKeyKP_Delete}, + {"KP_Divide", kKeyKP_Divide}, + {"KP_Down", kKeyKP_Down}, + {"KP_End", kKeyKP_End}, + {"KP_Enter", kKeyKP_Enter}, + {"KP_Equal", kKeyKP_Equal}, + {"KP_F1", kKeyKP_F1}, + {"KP_F2", kKeyKP_F2}, + {"KP_F3", kKeyKP_F3}, + {"KP_F4", kKeyKP_F4}, + {"KP_Home", kKeyKP_Home}, + {"KP_Insert", kKeyKP_Insert}, + {"KP_Left", kKeyKP_Left}, + {"KP_Multiply", kKeyKP_Multiply}, + {"KP_PageDown", kKeyKP_PageDown}, + {"KP_PageUp", kKeyKP_PageUp}, + {"KP_Right", kKeyKP_Right}, + {"KP_Separator", kKeyKP_Separator}, + {"KP_Space", kKeyKP_Space}, + {"KP_Subtract", kKeyKP_Subtract}, + {"KP_Tab", kKeyKP_Tab}, + {"KP_Up", kKeyKP_Up}, + {"Left", kKeyLeft}, + {"LeftTab", kKeyLeftTab}, + {"Linefeed", kKeyLinefeed}, + {"Menu", kKeyMenu}, + {"Meta_L", kKeyMeta_L}, + {"Meta_R", kKeyMeta_R}, + {"NumLock", kKeyNumLock}, + {"PageDown", kKeyPageDown}, + {"PageUp", kKeyPageUp}, + {"Pause", kKeyPause}, + {"Print", kKeyPrint}, + {"Redo", kKeyRedo}, + {"Return", kKeyReturn}, + {"Right", kKeyRight}, + {"ScrollLock", kKeyScrollLock}, + {"Select", kKeySelect}, + {"ShiftLock", kKeyShiftLock}, + {"Shift_L", kKeyShift_L}, + {"Shift_R", kKeyShift_R}, + {"Sleep", kKeySleep}, + {"Super_L", kKeySuper_L}, + {"Super_R", kKeySuper_R}, + {"SysReq", kKeySysReq}, + {"Tab", kKeyTab}, + {"Undo", kKeyUndo}, + {"Up", kKeyUp}, + {"WWWBack", kKeyWWWBack}, + {"WWWFavorites", kKeyWWWFavorites}, + {"WWWForward", kKeyWWWForward}, + {"WWWHome", kKeyWWWHome}, + {"WWWRefresh", kKeyWWWRefresh}, + {"WWWSearch", kKeyWWWSearch}, + {"WWWStop", kKeyWWWStop}, + {"Zenkaku", kKeyZenkaku}, + {"Space", 0x0020}, + {"Exclaim", 0x0021}, + {"DoubleQuote", 0x0022}, + {"Number", 0x0023}, + {"Dollar", 0x0024}, + {"Percent", 0x0025}, + {"Ampersand", 0x0026}, + {"Apostrophe", 0x0027}, + {"ParenthesisL", 0x0028}, + {"ParenthesisR", 0x0029}, + {"Asterisk", 0x002a}, + {"Plus", 0x002b}, + {"Comma", 0x002c}, + {"Minus", 0x002d}, + {"Period", 0x002e}, + {"Slash", 0x002f}, + {"Colon", 0x003a}, + {"Semicolon", 0x003b}, + {"Less", 0x003c}, + {"Equal", 0x003d}, + {"Greater", 0x003e}, + {"Question", 0x003f}, + {"At", 0x0040}, + {"BracketL", 0x005b}, + {"Backslash", 0x005c}, + {"BracketR", 0x005d}, + {"Circumflex", 0x005e}, + {"Underscore", 0x005f}, + {"Grave", 0x0060}, + {"BraceL", 0x007b}, + {"Bar", 0x007c}, + {"BraceR", 0x007d}, + {"Tilde", 0x007e}, + {NULL, 0}, }; const KeyModifierNameMapEntry kModifierNameMap[] = { - { "Alt", KeyModifierAlt }, - { "AltGr", KeyModifierAltGr }, -// { "CapsLock", KeyModifierCapsLock }, - { "Control", KeyModifierControl }, - { "Meta", KeyModifierMeta }, -// { "NumLock", KeyModifierNumLock }, -// { "ScrollLock", KeyModifierScrollLock }, - { "Shift", KeyModifierShift }, - { "Super", KeyModifierSuper }, - { NULL, 0 }, + {"Alt", KeyModifierAlt}, + {"AltGr", KeyModifierAltGr}, + // { "CapsLock", KeyModifierCapsLock }, + {"Control", KeyModifierControl}, + {"Meta", KeyModifierMeta}, + // { "NumLock", KeyModifierNumLock }, + // { "ScrollLock", KeyModifierScrollLock }, + {"Shift", KeyModifierShift}, + {"Super", KeyModifierSuper}, + {NULL, 0}, }; diff --git a/src/lib/synergy/key_types.h b/src/lib/synergy/key_types.h index f45cea242..2dbcd12d1 100644 --- a/src/lib/synergy/key_types.h +++ b/src/lib/synergy/key_types.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -26,7 +26,7 @@ Type to hold a key symbol identifier. The encoding is UTF-32, using U+E000 through U+EFFF for the various control keys (e.g. arrow keys, function keys, modifier keys, etc). */ -typedef UInt32 KeyID; +typedef UInt32 KeyID; //! Key Code /*! @@ -35,60 +35,60 @@ physical key on the keyboard. KeyButton 0 is reserved to be an invalid key; platforms that use 0 as a physical key identifier will have to remap that value to some arbitrary unused id. */ -typedef UInt16 KeyButton; +typedef UInt16 KeyButton; //! Modifier key mask /*! Type to hold a bitmask of key modifiers (e.g. shift keys). */ -typedef UInt32 KeyModifierMask; +typedef UInt32 KeyModifierMask; //! Modifier key ID /*! Type to hold the id of a key modifier (e.g. a shift key). */ -typedef UInt32 KeyModifierID; +typedef UInt32 KeyModifierID; //! @name Modifier key masks //@{ -static const KeyModifierMask KeyModifierShift = 0x0001; -static const KeyModifierMask KeyModifierControl = 0x0002; -static const KeyModifierMask KeyModifierAlt = 0x0004; -static const KeyModifierMask KeyModifierMeta = 0x0008; -static const KeyModifierMask KeyModifierSuper = 0x0010; -static const KeyModifierMask KeyModifierAltGr = 0x0020; -static const KeyModifierMask KeyModifierLevel5Lock = 0x0040; -static const KeyModifierMask KeyModifierCapsLock = 0x1000; -static const KeyModifierMask KeyModifierNumLock = 0x2000; -static const KeyModifierMask KeyModifierScrollLock = 0x4000; +static const KeyModifierMask KeyModifierShift = 0x0001; +static const KeyModifierMask KeyModifierControl = 0x0002; +static const KeyModifierMask KeyModifierAlt = 0x0004; +static const KeyModifierMask KeyModifierMeta = 0x0008; +static const KeyModifierMask KeyModifierSuper = 0x0010; +static const KeyModifierMask KeyModifierAltGr = 0x0020; +static const KeyModifierMask KeyModifierLevel5Lock = 0x0040; +static const KeyModifierMask KeyModifierCapsLock = 0x1000; +static const KeyModifierMask KeyModifierNumLock = 0x2000; +static const KeyModifierMask KeyModifierScrollLock = 0x4000; //@} //! @name Modifier key bits //@{ -static const UInt32 kKeyModifierBitNone = 16; -static const UInt32 kKeyModifierBitShift = 0; -static const UInt32 kKeyModifierBitControl = 1; -static const UInt32 kKeyModifierBitAlt = 2; -static const UInt32 kKeyModifierBitMeta = 3; -static const UInt32 kKeyModifierBitSuper = 4; -static const UInt32 kKeyModifierBitAltGr = 5; -static const UInt32 kKeyModifierBitLevel5Lock = 6; -static const UInt32 kKeyModifierBitCapsLock = 12; -static const UInt32 kKeyModifierBitNumLock = 13; -static const UInt32 kKeyModifierBitScrollLock = 14; -static const SInt32 kKeyModifierNumBits = 16; +static const UInt32 kKeyModifierBitNone = 16; +static const UInt32 kKeyModifierBitShift = 0; +static const UInt32 kKeyModifierBitControl = 1; +static const UInt32 kKeyModifierBitAlt = 2; +static const UInt32 kKeyModifierBitMeta = 3; +static const UInt32 kKeyModifierBitSuper = 4; +static const UInt32 kKeyModifierBitAltGr = 5; +static const UInt32 kKeyModifierBitLevel5Lock = 6; +static const UInt32 kKeyModifierBitCapsLock = 12; +static const UInt32 kKeyModifierBitNumLock = 13; +static const UInt32 kKeyModifierBitScrollLock = 14; +static const SInt32 kKeyModifierNumBits = 16; //@} //! @name Modifier key identifiers //@{ -static const KeyModifierID kKeyModifierIDNull = 0; -static const KeyModifierID kKeyModifierIDShift = 1; -static const KeyModifierID kKeyModifierIDControl = 2; -static const KeyModifierID kKeyModifierIDAlt = 3; -static const KeyModifierID kKeyModifierIDMeta = 4; -static const KeyModifierID kKeyModifierIDSuper = 5; -static const KeyModifierID kKeyModifierIDAltGr = 6; -static const KeyModifierID kKeyModifierIDLast = 7; +static const KeyModifierID kKeyModifierIDNull = 0; +static const KeyModifierID kKeyModifierIDShift = 1; +static const KeyModifierID kKeyModifierIDControl = 2; +static const KeyModifierID kKeyModifierIDAlt = 3; +static const KeyModifierID kKeyModifierIDMeta = 4; +static const KeyModifierID kKeyModifierIDSuper = 5; +static const KeyModifierID kKeyModifierIDAltGr = 6; +static const KeyModifierID kKeyModifierIDLast = 7; //@} //! @name Key identifiers @@ -97,205 +97,205 @@ static const KeyModifierID kKeyModifierIDLast = 7; // inclusive are equal to the corresponding X11 keysym - 0x1000. // no key -static const KeyID kKeyNone = 0x0000; +static const KeyID kKeyNone = 0x0000; // TTY functions -static const KeyID kKeyBackSpace = 0xEF08; /* back space, back char */ -static const KeyID kKeyTab = 0xEF09; -static const KeyID kKeyLinefeed = 0xEF0A; /* Linefeed, LF */ -static const KeyID kKeyClear = 0xEF0B; -static const KeyID kKeyReturn = 0xEF0D; /* Return, enter */ -static const KeyID kKeyPause = 0xEF13; /* Pause, hold */ -static const KeyID kKeyScrollLock = 0xEF14; -static const KeyID kKeySysReq = 0xEF15; -static const KeyID kKeyEscape = 0xEF1B; -static const KeyID kKeyHenkan = 0xEF23; /* Start/Stop Conversion */ -static const KeyID kKeyKana = 0xEF26; /* Kana */ -static const KeyID kKeyHiraganaKatakana = 0xEF27; /* Hiragana/Katakana toggle */ -static const KeyID kKeyZenkaku = 0xEF2A; /* Zenkaku/Hankaku */ -static const KeyID kKeyKanzi = 0xEF2A; /* Kanzi */ -static const KeyID kKeyHangul = 0xEF31; /* Hangul */ -static const KeyID kKeyHanja = 0xEF34; /* Hanja */ -static const KeyID kKeyDelete = 0xEFFF; /* Delete, rubout */ +static const KeyID kKeyBackSpace = 0xEF08; /* back space, back char */ +static const KeyID kKeyTab = 0xEF09; +static const KeyID kKeyLinefeed = 0xEF0A; /* Linefeed, LF */ +static const KeyID kKeyClear = 0xEF0B; +static const KeyID kKeyReturn = 0xEF0D; /* Return, enter */ +static const KeyID kKeyPause = 0xEF13; /* Pause, hold */ +static const KeyID kKeyScrollLock = 0xEF14; +static const KeyID kKeySysReq = 0xEF15; +static const KeyID kKeyEscape = 0xEF1B; +static const KeyID kKeyHenkan = 0xEF23; /* Start/Stop Conversion */ +static const KeyID kKeyKana = 0xEF26; /* Kana */ +static const KeyID kKeyHiraganaKatakana = 0xEF27; /* Hiragana/Katakana toggle */ +static const KeyID kKeyZenkaku = 0xEF2A; /* Zenkaku/Hankaku */ +static const KeyID kKeyKanzi = 0xEF2A; /* Kanzi */ +static const KeyID kKeyHangul = 0xEF31; /* Hangul */ +static const KeyID kKeyHanja = 0xEF34; /* Hanja */ +static const KeyID kKeyDelete = 0xEFFF; /* Delete, rubout */ // cursor control -static const KeyID kKeyHome = 0xEF50; -static const KeyID kKeyLeft = 0xEF51; /* Move left, left arrow */ -static const KeyID kKeyUp = 0xEF52; /* Move up, up arrow */ -static const KeyID kKeyRight = 0xEF53; /* Move right, right arrow */ -static const KeyID kKeyDown = 0xEF54; /* Move down, down arrow */ -static const KeyID kKeyPageUp = 0xEF55; -static const KeyID kKeyPageDown = 0xEF56; -static const KeyID kKeyEnd = 0xEF57; /* EOL */ -static const KeyID kKeyBegin = 0xEF58; /* BOL */ +static const KeyID kKeyHome = 0xEF50; +static const KeyID kKeyLeft = 0xEF51; /* Move left, left arrow */ +static const KeyID kKeyUp = 0xEF52; /* Move up, up arrow */ +static const KeyID kKeyRight = 0xEF53; /* Move right, right arrow */ +static const KeyID kKeyDown = 0xEF54; /* Move down, down arrow */ +static const KeyID kKeyPageUp = 0xEF55; +static const KeyID kKeyPageDown = 0xEF56; +static const KeyID kKeyEnd = 0xEF57; /* EOL */ +static const KeyID kKeyBegin = 0xEF58; /* BOL */ // misc functions -static const KeyID kKeySelect = 0xEF60; /* Select, mark */ -static const KeyID kKeyPrint = 0xEF61; -static const KeyID kKeyExecute = 0xEF62; /* Execute, run, do */ -static const KeyID kKeyInsert = 0xEF63; /* Insert, insert here */ -static const KeyID kKeyUndo = 0xEF65; /* Undo, oops */ -static const KeyID kKeyRedo = 0xEF66; /* redo, again */ -static const KeyID kKeyMenu = 0xEF67; -static const KeyID kKeyFind = 0xEF68; /* Find, search */ -static const KeyID kKeyCancel = 0xEF69; /* Cancel, stop, abort, exit */ -static const KeyID kKeyHelp = 0xEF6A; /* Help */ -static const KeyID kKeyBreak = 0xEF6B; -static const KeyID kKeyAltGr = 0xEF7E; /* Character set switch */ -static const KeyID kKeyNumLock = 0xEF7F; +static const KeyID kKeySelect = 0xEF60; /* Select, mark */ +static const KeyID kKeyPrint = 0xEF61; +static const KeyID kKeyExecute = 0xEF62; /* Execute, run, do */ +static const KeyID kKeyInsert = 0xEF63; /* Insert, insert here */ +static const KeyID kKeyUndo = 0xEF65; /* Undo, oops */ +static const KeyID kKeyRedo = 0xEF66; /* redo, again */ +static const KeyID kKeyMenu = 0xEF67; +static const KeyID kKeyFind = 0xEF68; /* Find, search */ +static const KeyID kKeyCancel = 0xEF69; /* Cancel, stop, abort, exit */ +static const KeyID kKeyHelp = 0xEF6A; /* Help */ +static const KeyID kKeyBreak = 0xEF6B; +static const KeyID kKeyAltGr = 0xEF7E; /* Character set switch */ +static const KeyID kKeyNumLock = 0xEF7F; // keypad -static const KeyID kKeyKP_Space = 0xEF80; /* space */ -static const KeyID kKeyKP_Tab = 0xEF89; -static const KeyID kKeyKP_Enter = 0xEF8D; /* enter */ -static const KeyID kKeyKP_F1 = 0xEF91; /* PF1, KP_A, ... */ -static const KeyID kKeyKP_F2 = 0xEF92; -static const KeyID kKeyKP_F3 = 0xEF93; -static const KeyID kKeyKP_F4 = 0xEF94; -static const KeyID kKeyKP_Home = 0xEF95; -static const KeyID kKeyKP_Left = 0xEF96; -static const KeyID kKeyKP_Up = 0xEF97; -static const KeyID kKeyKP_Right = 0xEF98; -static const KeyID kKeyKP_Down = 0xEF99; -static const KeyID kKeyKP_PageUp = 0xEF9A; -static const KeyID kKeyKP_PageDown = 0xEF9B; -static const KeyID kKeyKP_End = 0xEF9C; -static const KeyID kKeyKP_Begin = 0xEF9D; -static const KeyID kKeyKP_Insert = 0xEF9E; -static const KeyID kKeyKP_Delete = 0xEF9F; -static const KeyID kKeyKP_Equal = 0xEFBD; /* equals */ -static const KeyID kKeyKP_Multiply = 0xEFAA; -static const KeyID kKeyKP_Add = 0xEFAB; -static const KeyID kKeyKP_Separator= 0xEFAC; /* separator, often comma */ -static const KeyID kKeyKP_Subtract = 0xEFAD; -static const KeyID kKeyKP_Decimal = 0xEFAE; -static const KeyID kKeyKP_Divide = 0xEFAF; -static const KeyID kKeyKP_0 = 0xEFB0; -static const KeyID kKeyKP_1 = 0xEFB1; -static const KeyID kKeyKP_2 = 0xEFB2; -static const KeyID kKeyKP_3 = 0xEFB3; -static const KeyID kKeyKP_4 = 0xEFB4; -static const KeyID kKeyKP_5 = 0xEFB5; -static const KeyID kKeyKP_6 = 0xEFB6; -static const KeyID kKeyKP_7 = 0xEFB7; -static const KeyID kKeyKP_8 = 0xEFB8; -static const KeyID kKeyKP_9 = 0xEFB9; +static const KeyID kKeyKP_Space = 0xEF80; /* space */ +static const KeyID kKeyKP_Tab = 0xEF89; +static const KeyID kKeyKP_Enter = 0xEF8D; /* enter */ +static const KeyID kKeyKP_F1 = 0xEF91; /* PF1, KP_A, ... */ +static const KeyID kKeyKP_F2 = 0xEF92; +static const KeyID kKeyKP_F3 = 0xEF93; +static const KeyID kKeyKP_F4 = 0xEF94; +static const KeyID kKeyKP_Home = 0xEF95; +static const KeyID kKeyKP_Left = 0xEF96; +static const KeyID kKeyKP_Up = 0xEF97; +static const KeyID kKeyKP_Right = 0xEF98; +static const KeyID kKeyKP_Down = 0xEF99; +static const KeyID kKeyKP_PageUp = 0xEF9A; +static const KeyID kKeyKP_PageDown = 0xEF9B; +static const KeyID kKeyKP_End = 0xEF9C; +static const KeyID kKeyKP_Begin = 0xEF9D; +static const KeyID kKeyKP_Insert = 0xEF9E; +static const KeyID kKeyKP_Delete = 0xEF9F; +static const KeyID kKeyKP_Equal = 0xEFBD; /* equals */ +static const KeyID kKeyKP_Multiply = 0xEFAA; +static const KeyID kKeyKP_Add = 0xEFAB; +static const KeyID kKeyKP_Separator = 0xEFAC; /* separator, often comma */ +static const KeyID kKeyKP_Subtract = 0xEFAD; +static const KeyID kKeyKP_Decimal = 0xEFAE; +static const KeyID kKeyKP_Divide = 0xEFAF; +static const KeyID kKeyKP_0 = 0xEFB0; +static const KeyID kKeyKP_1 = 0xEFB1; +static const KeyID kKeyKP_2 = 0xEFB2; +static const KeyID kKeyKP_3 = 0xEFB3; +static const KeyID kKeyKP_4 = 0xEFB4; +static const KeyID kKeyKP_5 = 0xEFB5; +static const KeyID kKeyKP_6 = 0xEFB6; +static const KeyID kKeyKP_7 = 0xEFB7; +static const KeyID kKeyKP_8 = 0xEFB8; +static const KeyID kKeyKP_9 = 0xEFB9; // function keys -static const KeyID kKeyF1 = 0xEFBE; -static const KeyID kKeyF2 = 0xEFBF; -static const KeyID kKeyF3 = 0xEFC0; -static const KeyID kKeyF4 = 0xEFC1; -static const KeyID kKeyF5 = 0xEFC2; -static const KeyID kKeyF6 = 0xEFC3; -static const KeyID kKeyF7 = 0xEFC4; -static const KeyID kKeyF8 = 0xEFC5; -static const KeyID kKeyF9 = 0xEFC6; -static const KeyID kKeyF10 = 0xEFC7; -static const KeyID kKeyF11 = 0xEFC8; -static const KeyID kKeyF12 = 0xEFC9; -static const KeyID kKeyF13 = 0xEFCA; -static const KeyID kKeyF14 = 0xEFCB; -static const KeyID kKeyF15 = 0xEFCC; -static const KeyID kKeyF16 = 0xEFCD; -static const KeyID kKeyF17 = 0xEFCE; -static const KeyID kKeyF18 = 0xEFCF; -static const KeyID kKeyF19 = 0xEFD0; -static const KeyID kKeyF20 = 0xEFD1; -static const KeyID kKeyF21 = 0xEFD2; -static const KeyID kKeyF22 = 0xEFD3; -static const KeyID kKeyF23 = 0xEFD4; -static const KeyID kKeyF24 = 0xEFD5; -static const KeyID kKeyF25 = 0xEFD6; -static const KeyID kKeyF26 = 0xEFD7; -static const KeyID kKeyF27 = 0xEFD8; -static const KeyID kKeyF28 = 0xEFD9; -static const KeyID kKeyF29 = 0xEFDA; -static const KeyID kKeyF30 = 0xEFDB; -static const KeyID kKeyF31 = 0xEFDC; -static const KeyID kKeyF32 = 0xEFDD; -static const KeyID kKeyF33 = 0xEFDE; -static const KeyID kKeyF34 = 0xEFDF; -static const KeyID kKeyF35 = 0xEFE0; +static const KeyID kKeyF1 = 0xEFBE; +static const KeyID kKeyF2 = 0xEFBF; +static const KeyID kKeyF3 = 0xEFC0; +static const KeyID kKeyF4 = 0xEFC1; +static const KeyID kKeyF5 = 0xEFC2; +static const KeyID kKeyF6 = 0xEFC3; +static const KeyID kKeyF7 = 0xEFC4; +static const KeyID kKeyF8 = 0xEFC5; +static const KeyID kKeyF9 = 0xEFC6; +static const KeyID kKeyF10 = 0xEFC7; +static const KeyID kKeyF11 = 0xEFC8; +static const KeyID kKeyF12 = 0xEFC9; +static const KeyID kKeyF13 = 0xEFCA; +static const KeyID kKeyF14 = 0xEFCB; +static const KeyID kKeyF15 = 0xEFCC; +static const KeyID kKeyF16 = 0xEFCD; +static const KeyID kKeyF17 = 0xEFCE; +static const KeyID kKeyF18 = 0xEFCF; +static const KeyID kKeyF19 = 0xEFD0; +static const KeyID kKeyF20 = 0xEFD1; +static const KeyID kKeyF21 = 0xEFD2; +static const KeyID kKeyF22 = 0xEFD3; +static const KeyID kKeyF23 = 0xEFD4; +static const KeyID kKeyF24 = 0xEFD5; +static const KeyID kKeyF25 = 0xEFD6; +static const KeyID kKeyF26 = 0xEFD7; +static const KeyID kKeyF27 = 0xEFD8; +static const KeyID kKeyF28 = 0xEFD9; +static const KeyID kKeyF29 = 0xEFDA; +static const KeyID kKeyF30 = 0xEFDB; +static const KeyID kKeyF31 = 0xEFDC; +static const KeyID kKeyF32 = 0xEFDD; +static const KeyID kKeyF33 = 0xEFDE; +static const KeyID kKeyF34 = 0xEFDF; +static const KeyID kKeyF35 = 0xEFE0; // modifiers -static const KeyID kKeyShift_L = 0xEFE1; /* Left shift */ -static const KeyID kKeyShift_R = 0xEFE2; /* Right shift */ -static const KeyID kKeyControl_L = 0xEFE3; /* Left control */ -static const KeyID kKeyControl_R = 0xEFE4; /* Right control */ -static const KeyID kKeyCapsLock = 0xEFE5; /* Caps lock */ -static const KeyID kKeyShiftLock = 0xEFE6; /* Shift lock */ -static const KeyID kKeyMeta_L = 0xEFE7; /* Left meta */ -static const KeyID kKeyMeta_R = 0xEFE8; /* Right meta */ -static const KeyID kKeyAlt_L = 0xEFE9; /* Left alt */ -static const KeyID kKeyAlt_R = 0xEFEA; /* Right alt */ -static const KeyID kKeySuper_L = 0xEFEB; /* Left super */ -static const KeyID kKeySuper_R = 0xEFEC; /* Right super */ -static const KeyID kKeyHyper_L = 0xEFED; /* Left hyper */ -static const KeyID kKeyHyper_R = 0xEFEE; /* Right hyper */ +static const KeyID kKeyShift_L = 0xEFE1; /* Left shift */ +static const KeyID kKeyShift_R = 0xEFE2; /* Right shift */ +static const KeyID kKeyControl_L = 0xEFE3; /* Left control */ +static const KeyID kKeyControl_R = 0xEFE4; /* Right control */ +static const KeyID kKeyCapsLock = 0xEFE5; /* Caps lock */ +static const KeyID kKeyShiftLock = 0xEFE6; /* Shift lock */ +static const KeyID kKeyMeta_L = 0xEFE7; /* Left meta */ +static const KeyID kKeyMeta_R = 0xEFE8; /* Right meta */ +static const KeyID kKeyAlt_L = 0xEFE9; /* Left alt */ +static const KeyID kKeyAlt_R = 0xEFEA; /* Right alt */ +static const KeyID kKeySuper_L = 0xEFEB; /* Left super */ +static const KeyID kKeySuper_R = 0xEFEC; /* Right super */ +static const KeyID kKeyHyper_L = 0xEFED; /* Left hyper */ +static const KeyID kKeyHyper_R = 0xEFEE; /* Right hyper */ // multi-key character composition -static const KeyID kKeyCompose = 0xEF20; -static const KeyID kKeyDeadGrave = 0x0300; -static const KeyID kKeyDeadAcute = 0x0301; -static const KeyID kKeyDeadCircumflex = 0x0302; -static const KeyID kKeyDeadTilde = 0x0303; -static const KeyID kKeyDeadMacron = 0x0304; -static const KeyID kKeyDeadBreve = 0x0306; -static const KeyID kKeyDeadAbovedot = 0x0307; -static const KeyID kKeyDeadDiaeresis = 0x0308; -static const KeyID kKeyDeadAbovering = 0x030a; -static const KeyID kKeyDeadDoubleacute = 0x030b; -static const KeyID kKeyDeadCaron = 0x030c; -static const KeyID kKeyDeadCedilla = 0x0327; -static const KeyID kKeyDeadOgonek = 0x0328; +static const KeyID kKeyCompose = 0xEF20; +static const KeyID kKeyDeadGrave = 0x0300; +static const KeyID kKeyDeadAcute = 0x0301; +static const KeyID kKeyDeadCircumflex = 0x0302; +static const KeyID kKeyDeadTilde = 0x0303; +static const KeyID kKeyDeadMacron = 0x0304; +static const KeyID kKeyDeadBreve = 0x0306; +static const KeyID kKeyDeadAbovedot = 0x0307; +static const KeyID kKeyDeadDiaeresis = 0x0308; +static const KeyID kKeyDeadAbovering = 0x030a; +static const KeyID kKeyDeadDoubleacute = 0x030b; +static const KeyID kKeyDeadCaron = 0x030c; +static const KeyID kKeyDeadCedilla = 0x0327; +static const KeyID kKeyDeadOgonek = 0x0328; // more function and modifier keys -static const KeyID kKeyLeftTab = 0xEE20; +static const KeyID kKeyLeftTab = 0xEE20; // update modifiers -static const KeyID kKeySetModifiers = 0xEE06; -static const KeyID kKeyClearModifiers = 0xEE07; +static const KeyID kKeySetModifiers = 0xEE06; +static const KeyID kKeyClearModifiers = 0xEE07; // group change -static const KeyID kKeyNextGroup = 0xEE08; -static const KeyID kKeyPrevGroup = 0xEE0A; +static const KeyID kKeyNextGroup = 0xEE08; +static const KeyID kKeyPrevGroup = 0xEE0A; // extended keys -static const KeyID kKeyEject = 0xE001; -static const KeyID kKeySleep = 0xE05F; -static const KeyID kKeyWWWBack = 0xE0A6; -static const KeyID kKeyWWWForward = 0xE0A7; -static const KeyID kKeyWWWRefresh = 0xE0A8; -static const KeyID kKeyWWWStop = 0xE0A9; -static const KeyID kKeyWWWSearch = 0xE0AA; -static const KeyID kKeyWWWFavorites = 0xE0AB; -static const KeyID kKeyWWWHome = 0xE0AC; -static const KeyID kKeyAudioMute = 0xE0AD; -static const KeyID kKeyAudioDown = 0xE0AE; -static const KeyID kKeyAudioUp = 0xE0AF; -static const KeyID kKeyAudioNext = 0xE0B0; -static const KeyID kKeyAudioPrev = 0xE0B1; -static const KeyID kKeyAudioStop = 0xE0B2; -static const KeyID kKeyAudioPlay = 0xE0B3; -static const KeyID kKeyAppMail = 0xE0B4; -static const KeyID kKeyAppMedia = 0xE0B5; -static const KeyID kKeyAppUser1 = 0xE0B6; -static const KeyID kKeyAppUser2 = 0xE0B7; -static const KeyID kKeyBrightnessDown = 0xE0B8; -static const KeyID kKeyBrightnessUp = 0xE0B9; -static const KeyID kKeyMissionControl = 0xE0C0; -static const KeyID kKeyLaunchpad = 0xE0C1; +static const KeyID kKeyEject = 0xE001; +static const KeyID kKeySleep = 0xE05F; +static const KeyID kKeyWWWBack = 0xE0A6; +static const KeyID kKeyWWWForward = 0xE0A7; +static const KeyID kKeyWWWRefresh = 0xE0A8; +static const KeyID kKeyWWWStop = 0xE0A9; +static const KeyID kKeyWWWSearch = 0xE0AA; +static const KeyID kKeyWWWFavorites = 0xE0AB; +static const KeyID kKeyWWWHome = 0xE0AC; +static const KeyID kKeyAudioMute = 0xE0AD; +static const KeyID kKeyAudioDown = 0xE0AE; +static const KeyID kKeyAudioUp = 0xE0AF; +static const KeyID kKeyAudioNext = 0xE0B0; +static const KeyID kKeyAudioPrev = 0xE0B1; +static const KeyID kKeyAudioStop = 0xE0B2; +static const KeyID kKeyAudioPlay = 0xE0B3; +static const KeyID kKeyAppMail = 0xE0B4; +static const KeyID kKeyAppMedia = 0xE0B5; +static const KeyID kKeyAppUser1 = 0xE0B6; +static const KeyID kKeyAppUser2 = 0xE0B7; +static const KeyID kKeyBrightnessDown = 0xE0B8; +static const KeyID kKeyBrightnessUp = 0xE0B9; +static const KeyID kKeyMissionControl = 0xE0C0; +static const KeyID kKeyLaunchpad = 0xE0C1; //@} struct KeyNameMapEntry { - const char* m_name; - KeyID m_id; + const char *m_name; + KeyID m_id; }; struct KeyModifierNameMapEntry { - const char* m_name; - KeyModifierMask m_mask; + const char *m_name; + KeyModifierMask m_mask; }; //! Key name to KeyID table diff --git a/src/lib/synergy/languages/LanguageManager.cpp b/src/lib/synergy/languages/LanguageManager.cpp index 11b4d5d8c..161faa76f 100644 --- a/src/lib/synergy/languages/LanguageManager.cpp +++ b/src/lib/synergy/languages/LanguageManager.cpp @@ -19,87 +19,81 @@ #include -namespace { +namespace { -String vectorToString(const std::vector& vector, const String& delimiter = "") -{ - String string; - for (const auto& item : vector) { - if (&item != &vector[0]) { - string += delimiter; - } - string += item; +String vectorToString(const std::vector &vector, + const String &delimiter = "") { + String string; + for (const auto &item : vector) { + if (&item != &vector[0]) { + string += delimiter; } - return string; + string += item; + } + return string; } -} //anonymous namespace +} // anonymous namespace namespace synergy { namespace languages { -LanguageManager::LanguageManager(const std::vector& localLanguages) : - m_localLanguages(localLanguages) -{ - LOG((CLOG_INFO "local languages: %s", vectorToString(m_localLanguages, ", ").c_str())); +LanguageManager::LanguageManager(const std::vector &localLanguages) + : m_localLanguages(localLanguages) { + LOG((CLOG_INFO "local languages: %s", + vectorToString(m_localLanguages, ", ").c_str())); } -void LanguageManager::setRemoteLanguages(const String& remoteLanguages) -{ - m_remoteLanguages.clear(); - if (!remoteLanguages.empty()) { - for (size_t i = 0; i <= remoteLanguages.size() - 2; i +=2) { - m_remoteLanguages.push_back(remoteLanguages.substr(i, 2)); - } +void LanguageManager::setRemoteLanguages(const String &remoteLanguages) { + m_remoteLanguages.clear(); + if (!remoteLanguages.empty()) { + for (size_t i = 0; i <= remoteLanguages.size() - 2; i += 2) { + m_remoteLanguages.push_back(remoteLanguages.substr(i, 2)); } - LOG((CLOG_INFO "remote languages: %s", vectorToString(m_remoteLanguages, ", ").c_str())); + } + LOG((CLOG_INFO "remote languages: %s", + vectorToString(m_remoteLanguages, ", ").c_str())); } -const std::vector& LanguageManager::getRemoteLanguages() const -{ - return m_remoteLanguages; +const std::vector &LanguageManager::getRemoteLanguages() const { + return m_remoteLanguages; } -const std::vector& LanguageManager::getLocalLanguages() const -{ - return m_localLanguages; +const std::vector &LanguageManager::getLocalLanguages() const { + return m_localLanguages; } -String LanguageManager::getMissedLanguages() const -{ - String missedLanguages; +String LanguageManager::getMissedLanguages() const { + String missedLanguages; - for (const auto& language : m_remoteLanguages) { - if (!isLanguageInstalled(language)) { - if (!missedLanguages.empty()) { - missedLanguages += ", "; - } - missedLanguages += language; - } + for (const auto &language : m_remoteLanguages) { + if (!isLanguageInstalled(language)) { + if (!missedLanguages.empty()) { + missedLanguages += ", "; + } + missedLanguages += language; } + } - return missedLanguages; + return missedLanguages; } -String LanguageManager::getSerializedLocalLanguages() const -{ - return vectorToString(m_localLanguages); +String LanguageManager::getSerializedLocalLanguages() const { + return vectorToString(m_localLanguages); } -bool LanguageManager::isLanguageInstalled(const String& language) const -{ - bool isInstalled = true; +bool LanguageManager::isLanguageInstalled(const String &language) const { + bool isInstalled = true; - if (!m_localLanguages.empty()) { - isInstalled = (std::find(m_localLanguages.begin(), m_localLanguages.end(), language) != m_localLanguages.end()); - } + if (!m_localLanguages.empty()) { + isInstalled = (std::find(m_localLanguages.begin(), m_localLanguages.end(), + language) != m_localLanguages.end()); + } - return isInstalled; + return isInstalled; } -} //namespace languages - -} //namespace synergy - +} // namespace languages +} // namespace synergy diff --git a/src/lib/synergy/languages/LanguageManager.h b/src/lib/synergy/languages/LanguageManager.h index cb225dddb..bc4b4906e 100644 --- a/src/lib/synergy/languages/LanguageManager.h +++ b/src/lib/synergy/languages/LanguageManager.h @@ -17,62 +17,63 @@ #ifndef SYNERGY_LANGUAGESLANGUAGEMANAGER_H #define SYNERGY_LANGUAGESLANGUAGEMANAGER_H -#include "synergy/AppUtil.h" #include "base/String.h" +#include "synergy/AppUtil.h" #include namespace synergy { namespace languages { -class LanguageManager -{ - std::vector m_remoteLanguages; - std::vector m_localLanguages; +class LanguageManager { + std::vector m_remoteLanguages; + std::vector m_localLanguages; public: - explicit LanguageManager(const std::vector& localLanguages = AppUtil::instance().getKeyboardLayoutList()); + explicit LanguageManager(const std::vector &localLanguages = + AppUtil::instance().getKeyboardLayoutList()); - /** - * @brief setRemoteLanguages sets remote languages - * @param remoteLanguages is a string with sericalized languages - */ - void setRemoteLanguages(const String& remoteLanguages); + /** + * @brief setRemoteLanguages sets remote languages + * @param remoteLanguages is a string with sericalized languages + */ + void setRemoteLanguages(const String &remoteLanguages); - /** - * @brief getRemoteLanguages getter for remote languages - * @return vector of remote languages - */ - const std::vector& getRemoteLanguages() const; + /** + * @brief getRemoteLanguages getter for remote languages + * @return vector of remote languages + */ + const std::vector &getRemoteLanguages() const; - /** - * @brief getLocalLanguages getter for local languages - * @return vector of local languages - */ - const std::vector& getLocalLanguages() const; + /** + * @brief getLocalLanguages getter for local languages + * @return vector of local languages + */ + const std::vector &getLocalLanguages() const; - /** - * @brief getMissedLanguages getter for missed languages on local machine - * @return difference between remote and local languages as a coma separated string - */ - String getMissedLanguages() const; + /** + * @brief getMissedLanguages getter for missed languages on local machine + * @return difference between remote and local languages as a coma separated + * string + */ + String getMissedLanguages() const; - /** - * @brief getSerializedLocalLanguages getter for local serialized languages - * @return serialized local languages as a string - */ - String getSerializedLocalLanguages() const; + /** + * @brief getSerializedLocalLanguages getter for local serialized languages + * @return serialized local languages as a string + */ + String getSerializedLocalLanguages() const; - /** - * @brief isLanguageInstalled checks if language is installed - * @param language which should be checked - * @return true if the specified language is installed - */ - bool isLanguageInstalled(const String& language) const; + /** + * @brief isLanguageInstalled checks if language is installed + * @param language which should be checked + * @return true if the specified language is installed + */ + bool isLanguageInstalled(const String &language) const; }; -} //namespace languages +} // namespace languages -} //namespace synergy +} // namespace synergy #endif // SYNERGY_LANGUAGESLANGUAGEMANAGER_H diff --git a/src/lib/synergy/mouse_types.h b/src/lib/synergy/mouse_types.h index 61c2c5a2f..bb509bb42 100644 --- a/src/lib/synergy/mouse_types.h +++ b/src/lib/synergy/mouse_types.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -24,18 +24,18 @@ /*! Type to hold a mouse button identifier. */ -typedef UInt8 ButtonID; +typedef UInt8 ButtonID; //! @name Mouse button identifiers //@{ -static const ButtonID kButtonNone = 0; -static const ButtonID kButtonLeft = 1; -static const ButtonID kButtonMiddle = 2; -static const ButtonID kButtonRight = 3; -static const ButtonID kButtonExtra0 = 4; +static const ButtonID kButtonNone = 0; +static const ButtonID kButtonLeft = 1; +static const ButtonID kButtonMiddle = 2; +static const ButtonID kButtonRight = 3; +static const ButtonID kButtonExtra0 = 4; -static const ButtonID kMacButtonRight = 2; -static const ButtonID kMacButtonMiddle = 3; +static const ButtonID kMacButtonRight = 2; +static const ButtonID kMacButtonMiddle = 3; //@} -static const UInt8 NumButtonIDs = 5; +static const UInt8 NumButtonIDs = 5; diff --git a/src/lib/synergy/option_types.h b/src/lib/synergy/option_types.h index 1d03d0281..4e2b16182 100644 --- a/src/lib/synergy/option_types.h +++ b/src/lib/synergy/option_types.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -25,75 +25,75 @@ /*! Type to hold an option identifier. */ -typedef UInt32 OptionID; +typedef UInt32 OptionID; //! Option Value /*! Type to hold an option value. */ -typedef SInt32 OptionValue; +typedef SInt32 OptionValue; // for now, options are just pairs of integers typedef std::vector OptionsList; // macro for packing 4 character strings into 4 byte integers -#define OPTION_CODE(_s) \ - (static_cast(static_cast(_s[0]) << 24) | \ - static_cast(static_cast(_s[1]) << 16) | \ - static_cast(static_cast(_s[2]) << 8) | \ - static_cast(static_cast(_s[3]) )) +#define OPTION_CODE(_s) \ + (static_cast(static_cast(_s[0]) << 24) | \ + static_cast(static_cast(_s[1]) << 16) | \ + static_cast(static_cast(_s[2]) << 8) | \ + static_cast(static_cast(_s[3]))) //! @name Option identifiers //@{ -static const OptionID kOptionHalfDuplexCapsLock = OPTION_CODE("HDCL"); -static const OptionID kOptionHalfDuplexNumLock = OPTION_CODE("HDNL"); -static const OptionID kOptionHalfDuplexScrollLock = OPTION_CODE("HDSL"); -static const OptionID kOptionModifierMapForShift = OPTION_CODE("MMFS"); -static const OptionID kOptionModifierMapForControl = OPTION_CODE("MMFC"); -static const OptionID kOptionModifierMapForAlt = OPTION_CODE("MMFA"); -static const OptionID kOptionModifierMapForAltGr = OPTION_CODE("MMFG"); -static const OptionID kOptionModifierMapForMeta = OPTION_CODE("MMFM"); -static const OptionID kOptionModifierMapForSuper = OPTION_CODE("MMFR"); -static const OptionID kOptionHeartbeat = OPTION_CODE("HART"); -static const OptionID kOptionScreenSwitchCorners = OPTION_CODE("SSCM"); -static const OptionID kOptionScreenSwitchCornerSize = OPTION_CODE("SSCS"); -static const OptionID kOptionScreenSwitchDelay = OPTION_CODE("SSWT"); -static const OptionID kOptionScreenSwitchTwoTap = OPTION_CODE("SSTT"); -static const OptionID kOptionScreenSwitchNeedsShift = OPTION_CODE("SSNS"); -static const OptionID kOptionScreenSwitchNeedsControl = OPTION_CODE("SSNC"); -static const OptionID kOptionScreenSwitchNeedsAlt = OPTION_CODE("SSNA"); -static const OptionID kOptionXTestXineramaUnaware = OPTION_CODE("XTXU"); -static const OptionID kOptionScreenPreserveFocus = OPTION_CODE("SFOC"); -static const OptionID kOptionRelativeMouseMoves = OPTION_CODE("MDLT"); -static const OptionID kOptionWin32KeepForeground = OPTION_CODE("_KFW"); -static const OptionID kOptionDisableLockToScreen = OPTION_CODE("DLTS"); -static const OptionID kOptionClipboardSharing = OPTION_CODE("CLPS"); -static const OptionID kOptionClipboardSharingSize = OPTION_CODE("CLSZ"); +static const OptionID kOptionHalfDuplexCapsLock = OPTION_CODE("HDCL"); +static const OptionID kOptionHalfDuplexNumLock = OPTION_CODE("HDNL"); +static const OptionID kOptionHalfDuplexScrollLock = OPTION_CODE("HDSL"); +static const OptionID kOptionModifierMapForShift = OPTION_CODE("MMFS"); +static const OptionID kOptionModifierMapForControl = OPTION_CODE("MMFC"); +static const OptionID kOptionModifierMapForAlt = OPTION_CODE("MMFA"); +static const OptionID kOptionModifierMapForAltGr = OPTION_CODE("MMFG"); +static const OptionID kOptionModifierMapForMeta = OPTION_CODE("MMFM"); +static const OptionID kOptionModifierMapForSuper = OPTION_CODE("MMFR"); +static const OptionID kOptionHeartbeat = OPTION_CODE("HART"); +static const OptionID kOptionScreenSwitchCorners = OPTION_CODE("SSCM"); +static const OptionID kOptionScreenSwitchCornerSize = OPTION_CODE("SSCS"); +static const OptionID kOptionScreenSwitchDelay = OPTION_CODE("SSWT"); +static const OptionID kOptionScreenSwitchTwoTap = OPTION_CODE("SSTT"); +static const OptionID kOptionScreenSwitchNeedsShift = OPTION_CODE("SSNS"); +static const OptionID kOptionScreenSwitchNeedsControl = OPTION_CODE("SSNC"); +static const OptionID kOptionScreenSwitchNeedsAlt = OPTION_CODE("SSNA"); +static const OptionID kOptionXTestXineramaUnaware = OPTION_CODE("XTXU"); +static const OptionID kOptionScreenPreserveFocus = OPTION_CODE("SFOC"); +static const OptionID kOptionRelativeMouseMoves = OPTION_CODE("MDLT"); +static const OptionID kOptionWin32KeepForeground = OPTION_CODE("_KFW"); +static const OptionID kOptionDisableLockToScreen = OPTION_CODE("DLTS"); +static const OptionID kOptionClipboardSharing = OPTION_CODE("CLPS"); +static const OptionID kOptionClipboardSharingSize = OPTION_CODE("CLSZ"); //@} //! @name Screen switch corner enumeration //@{ enum EScreenSwitchCorners { - kNoCorner, - kTopLeft, - kTopRight, - kBottomLeft, - kBottomRight, - kFirstCorner = kTopLeft, - kLastCorner = kBottomRight + kNoCorner, + kTopLeft, + kTopRight, + kBottomLeft, + kBottomRight, + kFirstCorner = kTopLeft, + kLastCorner = kBottomRight }; //@} //! @name Screen switch corner masks //@{ enum EScreenSwitchCornerMasks { - kNoCornerMask = 0, - kTopLeftMask = 1 << (kTopLeft - kFirstCorner), - kTopRightMask = 1 << (kTopRight - kFirstCorner), - kBottomLeftMask = 1 << (kBottomLeft - kFirstCorner), - kBottomRightMask = 1 << (kBottomRight - kFirstCorner), - kAllCornersMask = kTopLeftMask | kTopRightMask | - kBottomLeftMask | kBottomRightMask + kNoCornerMask = 0, + kTopLeftMask = 1 << (kTopLeft - kFirstCorner), + kTopRightMask = 1 << (kTopRight - kFirstCorner), + kBottomLeftMask = 1 << (kBottomLeft - kFirstCorner), + kBottomRightMask = 1 << (kBottomRight - kFirstCorner), + kAllCornersMask = + kTopLeftMask | kTopRightMask | kBottomLeftMask | kBottomRightMask }; //@} diff --git a/src/lib/synergy/protocol_types.cpp b/src/lib/synergy/protocol_types.cpp index c98e8efed..95b4ee950 100644 --- a/src/lib/synergy/protocol_types.cpp +++ b/src/lib/synergy/protocol_types.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -18,39 +18,39 @@ #include "synergy/protocol_types.h" -const char* const kMsgHello = "Synergy%2i%2i"; -const char* const kMsgHelloBack = "Synergy%2i%2i%s"; -const char* const kMsgCNoop = "CNOP"; -const char* const kMsgCClose = "CBYE"; -const char* const kMsgCEnter = "CINN%2i%2i%4i%2i"; -const char* const kMsgCLeave = "COUT"; -const char* const kMsgCClipboard = "CCLP%1i%4i"; -const char* const kMsgCScreenSaver = "CSEC%1i"; -const char* const kMsgCResetOptions = "CROP"; -const char* const kMsgCInfoAck = "CIAK"; -const char* const kMsgCKeepAlive = "CALV"; -const char* const kMsgDKeyDownLang = "DKDL%2i%2i%2i%s"; -const char* const kMsgDKeyDown = "DKDN%2i%2i%2i"; -const char* const kMsgDKeyDown1_0 = "DKDN%2i%2i"; -const char* const kMsgDKeyRepeat = "DKRP%2i%2i%2i%2i%s"; -const char* const kMsgDKeyRepeat1_0 = "DKRP%2i%2i%2i"; -const char* const kMsgDKeyUp = "DKUP%2i%2i%2i"; -const char* const kMsgDKeyUp1_0 = "DKUP%2i%2i"; -const char* const kMsgDMouseDown = "DMDN%1i"; -const char* const kMsgDMouseUp = "DMUP%1i"; -const char* const kMsgDMouseMove = "DMMV%2i%2i"; -const char* const kMsgDMouseRelMove = "DMRM%2i%2i"; -const char* const kMsgDMouseWheel = "DMWM%2i%2i"; -const char* const kMsgDMouseWheel1_0 = "DMWM%2i"; -const char* const kMsgDClipboard = "DCLP%1i%4i%1i%s"; -const char* const kMsgDInfo = "DINF%2i%2i%2i%2i%2i%2i%2i"; -const char* const kMsgDSetOptions = "DSOP%4I"; -const char* const kMsgDFileTransfer = "DFTR%1i%s"; -const char* const kMsgDDragInfo = "DDRG%2i%s"; -const char* const kMsgDSecureInputNotification = "SECN%s"; -const char* const kMsgDLanguageSynchronisation = "LSYN%s"; -const char* const kMsgQInfo = "QINF"; -const char* const kMsgEIncompatible = "EICV%2i%2i"; -const char* const kMsgEBusy = "EBSY"; -const char* const kMsgEUnknown = "EUNK"; -const char* const kMsgEBad = "EBAD"; +const char *const kMsgHello = "Synergy%2i%2i"; +const char *const kMsgHelloBack = "Synergy%2i%2i%s"; +const char *const kMsgCNoop = "CNOP"; +const char *const kMsgCClose = "CBYE"; +const char *const kMsgCEnter = "CINN%2i%2i%4i%2i"; +const char *const kMsgCLeave = "COUT"; +const char *const kMsgCClipboard = "CCLP%1i%4i"; +const char *const kMsgCScreenSaver = "CSEC%1i"; +const char *const kMsgCResetOptions = "CROP"; +const char *const kMsgCInfoAck = "CIAK"; +const char *const kMsgCKeepAlive = "CALV"; +const char *const kMsgDKeyDownLang = "DKDL%2i%2i%2i%s"; +const char *const kMsgDKeyDown = "DKDN%2i%2i%2i"; +const char *const kMsgDKeyDown1_0 = "DKDN%2i%2i"; +const char *const kMsgDKeyRepeat = "DKRP%2i%2i%2i%2i%s"; +const char *const kMsgDKeyRepeat1_0 = "DKRP%2i%2i%2i"; +const char *const kMsgDKeyUp = "DKUP%2i%2i%2i"; +const char *const kMsgDKeyUp1_0 = "DKUP%2i%2i"; +const char *const kMsgDMouseDown = "DMDN%1i"; +const char *const kMsgDMouseUp = "DMUP%1i"; +const char *const kMsgDMouseMove = "DMMV%2i%2i"; +const char *const kMsgDMouseRelMove = "DMRM%2i%2i"; +const char *const kMsgDMouseWheel = "DMWM%2i%2i"; +const char *const kMsgDMouseWheel1_0 = "DMWM%2i"; +const char *const kMsgDClipboard = "DCLP%1i%4i%1i%s"; +const char *const kMsgDInfo = "DINF%2i%2i%2i%2i%2i%2i%2i"; +const char *const kMsgDSetOptions = "DSOP%4I"; +const char *const kMsgDFileTransfer = "DFTR%1i%s"; +const char *const kMsgDDragInfo = "DDRG%2i%s"; +const char *const kMsgDSecureInputNotification = "SECN%s"; +const char *const kMsgDLanguageSynchronisation = "LSYN%s"; +const char *const kMsgQInfo = "QINF"; +const char *const kMsgEIncompatible = "EICV%2i%2i"; +const char *const kMsgEBusy = "EBSY"; +const char *const kMsgEUnknown = "EUNK"; +const char *const kMsgEBad = "EBAD"; diff --git a/src/lib/synergy/protocol_types.h b/src/lib/synergy/protocol_types.h index 5bd346078..95fc2ebec 100644 --- a/src/lib/synergy/protocol_types.h +++ b/src/lib/synergy/protocol_types.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -32,60 +32,51 @@ // 1.7 adds security input notifications // 1.8 adds language synchronization functionality // NOTE: with new version, synergy minor version should increment -static const SInt16 kProtocolMajorVersion = 1; -static const SInt16 kProtocolMinorVersion = 8; +static const SInt16 kProtocolMajorVersion = 1; +static const SInt16 kProtocolMinorVersion = 8; // default contact port number -static const UInt16 kDefaultPort = 24800; +static const UInt16 kDefaultPort = 24800; // maximum total length for greeting returned by client -static const UInt32 kMaxHelloLength = 1024; +static const UInt32 kMaxHelloLength = 1024; // time between kMsgCKeepAlive (in seconds). a non-positive value disables // keep alives. this is the default rate that can be overridden using an // option. -static const double kKeepAliveRate = 3.0; +static const double kKeepAliveRate = 3.0; // number of skipped kMsgCKeepAlive messages that indicates a problem -static const double kKeepAlivesUntilDeath = 3.0; +static const double kKeepAlivesUntilDeath = 3.0; // obsolete heartbeat stuff -static const double kHeartRate = -1.0; -static const double kHeartBeatsUntilDeath = 3.0; +static const double kHeartRate = -1.0; +static const double kHeartBeatsUntilDeath = 3.0; // direction constants enum EDirection { - kNoDirection, - kLeft, - kRight, - kTop, - kBottom, - kFirstDirection = kLeft, - kLastDirection = kBottom, - kNumDirections = kLastDirection - kFirstDirection + 1 + kNoDirection, + kLeft, + kRight, + kTop, + kBottom, + kFirstDirection = kLeft, + kLastDirection = kBottom, + kNumDirections = kLastDirection - kFirstDirection + 1 }; enum EDirectionMask { - kNoDirMask = 0, - kLeftMask = 1 << kLeft, - kRightMask = 1 << kRight, - kTopMask = 1 << kTop, - kBottomMask = 1 << kBottom + kNoDirMask = 0, + kLeftMask = 1 << kLeft, + kRightMask = 1 << kRight, + kTopMask = 1 << kTop, + kBottomMask = 1 << kBottom }; // Data transfer constants -enum EDataTransfer { - kDataStart = 1, - kDataChunk = 2, - kDataEnd = 3 -}; +enum EDataTransfer { kDataStart = 1, kDataChunk = 2, kDataEnd = 3 }; // Data received constants -enum EDataReceived { - kStart, - kNotFinish, - kFinish, - kError -}; +enum EDataReceived { kStart, kNotFinish, kFinish, kError }; // // message codes (trailing NUL is not part of code). in comments, $n @@ -106,24 +97,23 @@ enum EDataReceived { // $1 = protocol major version number supported by server. $2 = // protocol minor version number supported by server. $3 = server // keyboard layout list. -extern const char* const kMsgHello; +extern const char *const kMsgHello; // respond to hello from server; secondary -> primary // $1 = protocol major version number supported by client. $2 = // protocol minor version number supported by client. $3 = client // name. -extern const char* const kMsgHelloBack; - +extern const char *const kMsgHelloBack; // // command codes // // no operation; secondary -> primary -extern const char* const kMsgCNoop; +extern const char *const kMsgCNoop; // close connection; primary -> secondary -extern const char* const kMsgCClose; +extern const char *const kMsgCClose; // enter screen: primary -> secondary // entering screen at screen position $1 = x, $2 = y. x,y are @@ -133,7 +123,7 @@ extern const char* const kMsgCClose; // mask. this will have bits set for each toggle modifier key // that is activated on entry to the screen. the secondary screen // should adjust its toggle modifiers to reflect that state. -extern const char* const kMsgCEnter; +extern const char *const kMsgCEnter; // leave screen: primary -> secondary // leaving screen. the secondary screen should send clipboard @@ -142,28 +132,28 @@ extern const char* const kMsgCEnter; // not received a kMsgCClipboard for with a greater sequence // number) and that were grabbed or have changed since the // last leave. -extern const char* const kMsgCLeave; +extern const char *const kMsgCLeave; // grab clipboard: primary <-> secondary // sent by screen when some other app on that screen grabs a // clipboard. $1 = the clipboard identifier, $2 = sequence number. // secondary screens must use the sequence number passed in the // most recent kMsgCEnter. the primary always sends 0. -extern const char* const kMsgCClipboard; +extern const char *const kMsgCClipboard; // screensaver change: primary -> secondary // screensaver on primary has started ($1 == 1) or closed ($1 == 0) -extern const char* const kMsgCScreenSaver; +extern const char *const kMsgCScreenSaver; // reset options: primary -> secondary // client should reset all of its options to their defaults. -extern const char* const kMsgCResetOptions; +extern const char *const kMsgCResetOptions; // resolution change acknowledgment: primary -> secondary // sent by primary in response to a secondary screen's kMsgDInfo. // this is sent for every kMsgDInfo, whether or not the primary // had sent a kMsgQInfo. -extern const char* const kMsgCInfoAck; +extern const char *const kMsgCInfoAck; // keep connection alive: primary <-> secondary // sent by the server periodically to verify that connections are still @@ -173,14 +163,14 @@ extern const char* const kMsgCInfoAck; // client doesn't receive these (or any message) periodically then it // should disconnect from the server. the appropriate interval is // defined by an option. -extern const char* const kMsgCKeepAlive; +extern const char *const kMsgCKeepAlive; // // data codes // // The same as kMsgDKeyDown but with languageCode // $4 = languageCode -extern const char* const kMsgDKeyDownLang; +extern const char *const kMsgDKeyDownLang; // key pressed: primary -> secondary // $1 = KeyID, $2 = KeyModifierMask, $3 = KeyButton @@ -195,58 +185,58 @@ extern const char* const kMsgDKeyDownLang; // a modifier key before releasing the modified key. // languageCode is parameter which helps client to react on unknwon // language letters -extern const char* const kMsgDKeyDown; +extern const char *const kMsgDKeyDown; // key pressed 1.0: same as above but without KeyButton -extern const char* const kMsgDKeyDown1_0; +extern const char *const kMsgDKeyDown1_0; // key auto-repeat: primary -> secondary // $1 = KeyID, $2 = KeyModifierMask, $3 = number of repeats, $4 = KeyButton // $5 =language code -extern const char* const kMsgDKeyRepeat; +extern const char *const kMsgDKeyRepeat; // key auto-repeat 1.0: same as above but without KeyButton -extern const char* const kMsgDKeyRepeat1_0; +extern const char *const kMsgDKeyRepeat1_0; // key released: primary -> secondary // $1 = KeyID, $2 = KeyModifierMask, $3 = KeyButton -extern const char* const kMsgDKeyUp; +extern const char *const kMsgDKeyUp; // key released 1.0: same as above but without KeyButton -extern const char* const kMsgDKeyUp1_0; +extern const char *const kMsgDKeyUp1_0; // mouse button pressed: primary -> secondary // $1 = ButtonID -extern const char* const kMsgDMouseDown; +extern const char *const kMsgDMouseDown; // mouse button released: primary -> secondary // $1 = ButtonID -extern const char* const kMsgDMouseUp; +extern const char *const kMsgDMouseUp; // mouse moved: primary -> secondary // $1 = x, $2 = y. x,y are absolute screen coordinates. -extern const char* const kMsgDMouseMove; +extern const char *const kMsgDMouseMove; // relative mouse move: primary -> secondary // $1 = dx, $2 = dy. dx,dy are motion deltas. -extern const char* const kMsgDMouseRelMove; +extern const char *const kMsgDMouseRelMove; // mouse scroll: primary -> secondary // $1 = xDelta, $2 = yDelta. the delta should be +120 for one tick forward // (away from the user) or right and -120 for one tick backward (toward // the user) or left. -extern const char* const kMsgDMouseWheel; +extern const char *const kMsgDMouseWheel; // mouse vertical scroll: primary -> secondary // like as kMsgDMouseWheel except only sends $1 = yDelta. -extern const char* const kMsgDMouseWheel1_0; +extern const char *const kMsgDMouseWheel1_0; // clipboard data: primary <-> secondary // $2 = sequence number, $3 = mark $4 = clipboard data. the sequence number // is 0 when sent by the primary. secondary screens should use the // sequence number from the most recent kMsgCEnter. $1 = clipboard // identifier. -extern const char* const kMsgDClipboard; +extern const char *const kMsgDClipboard; // client data: secondary -> primary // $1 = coordinate of leftmost pixel on secondary screen, @@ -262,34 +252,34 @@ extern const char* const kMsgDClipboard; // should ignore any kMsgDMouseMove messages until it receives a // kMsgCInfoAck in order to prevent attempts to move the mouse off // the new screen area. -extern const char* const kMsgDInfo; +extern const char *const kMsgDInfo; // set options: primary -> secondary // client should set the given option/value pairs. $1 = option/value // pairs. -extern const char* const kMsgDSetOptions; +extern const char *const kMsgDSetOptions; // file data: primary <-> secondary // transfer file data. A mark is used in the first byte. // 0 means the content followed is the file size. // 1 means the content followed is the chunk data. // 2 means the file transfer is finished. -extern const char* const kMsgDFileTransfer; +extern const char *const kMsgDFileTransfer; // drag infomation: primary <-> secondary // transfer drag infomation. The first 2 bytes are used for storing // the number of dragging objects. Then the following string consists // of each object's directory. -extern const char* const kMsgDDragInfo; +extern const char *const kMsgDDragInfo; // secure input notification: primary -> secondary // $1 = app. app only obtainable on MacOS since that's the only // platform facing secure input problems -extern const char* const kMsgDSecureInputNotification; +extern const char *const kMsgDSecureInputNotification; // language synchronization: primary -> secondary // $1 = List of server languages -extern const char* const kMsgDLanguageSynchronisation; +extern const char *const kMsgDLanguageSynchronisation; // // query codes @@ -297,8 +287,7 @@ extern const char* const kMsgDLanguageSynchronisation; // query screen info: primary -> secondary // client should reply with a kMsgDInfo. -extern const char* const kMsgQInfo; - +extern const char *const kMsgQInfo; // // error codes @@ -306,20 +295,19 @@ extern const char* const kMsgQInfo; // incompatible versions: primary -> secondary // $1 = major version of primary, $2 = minor version of primary. -extern const char* const kMsgEIncompatible; +extern const char *const kMsgEIncompatible; // name provided when connecting is already in use: primary -> secondary -extern const char* const kMsgEBusy; +extern const char *const kMsgEBusy; // unknown client: primary -> secondary // name provided when connecting is not in primary's screen // configuration map. -extern const char* const kMsgEUnknown; +extern const char *const kMsgEUnknown; // protocol violation: primary -> secondary // primary should disconnect after sending this message. -extern const char* const kMsgEBad; - +extern const char *const kMsgEBad; // // structures @@ -331,25 +319,25 @@ This class contains information about a screen. */ class ClientInfo { public: - //! Screen position - /*! - The position of the upper-left corner of the screen. This is - typically 0,0. - */ - SInt32 m_x, m_y; + //! Screen position + /*! + The position of the upper-left corner of the screen. This is + typically 0,0. + */ + SInt32 m_x, m_y; - //! Screen size - /*! - The size of the screen in pixels. - */ - SInt32 m_w, m_h; + //! Screen size + /*! + The size of the screen in pixels. + */ + SInt32 m_w, m_h; - //! Obsolete (jump zone size) - SInt32 obsolete1; + //! Obsolete (jump zone size) + SInt32 obsolete1; - //! Mouse position - /*! - The current location of the mouse cursor. - */ - SInt32 m_mx, m_my; + //! Mouse position + /*! + The current location of the mouse cursor. + */ + SInt32 m_mx, m_my; }; diff --git a/src/lib/synergy/unix/AppUtilUnix.cpp b/src/lib/synergy/unix/AppUtilUnix.cpp index 5414de488..7d0272c73 100644 --- a/src/lib/synergy/unix/AppUtilUnix.cpp +++ b/src/lib/synergy/unix/AppUtilUnix.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -36,170 +36,167 @@ #include #endif -AppUtilUnix::AppUtilUnix(IEventQueue* events) -{ +AppUtilUnix::AppUtilUnix(IEventQueue *events) {} + +AppUtilUnix::~AppUtilUnix() {} + +int standardStartupStatic(int argc, char **argv) { + return AppUtil::instance().app().standardStartup(argc, argv); } -AppUtilUnix::~AppUtilUnix() -{ +int AppUtilUnix::run(int argc, char **argv) { + return app().runInner(argc, argv, NULL, &standardStartupStatic); } -int -standardStartupStatic(int argc, char** argv) -{ - return AppUtil::instance().app().standardStartup(argc, argv); -} +void AppUtilUnix::startNode() { app().startNode(); } -int -AppUtilUnix::run(int argc, char** argv) -{ - return app().runInner(argc, argv, NULL, &standardStartupStatic); -} - -void -AppUtilUnix::startNode() -{ - app().startNode(); -} - -std::vector -AppUtilUnix::getKeyboardLayoutList() -{ - std::vector layoutLangCodes; +std::vector AppUtilUnix::getKeyboardLayoutList() { + std::vector layoutLangCodes; #if WINAPI_XWINDOWS - layoutLangCodes = X11LayoutsParser::getX11LanguageList("/usr/share/X11/xkb/rules/evdev.xml"); + layoutLangCodes = X11LayoutsParser::getX11LanguageList( + "/usr/share/X11/xkb/rules/evdev.xml"); #elif WINAPI_CARBON - CFStringRef keys[] = { kTISPropertyInputSourceCategory }; - CFStringRef values[] = { kTISCategoryKeyboardInputSource }; - AutoCFDictionary dict(CFDictionaryCreate(NULL, (const void **)keys, (const void **)values, 1, NULL, NULL), CFRelease); - AutoCFArray kbds(TISCreateInputSourceList(dict.get(), false), CFRelease); + CFStringRef keys[] = {kTISPropertyInputSourceCategory}; + CFStringRef values[] = {kTISCategoryKeyboardInputSource}; + AutoCFDictionary dict(CFDictionaryCreate(NULL, (const void **)keys, + (const void **)values, 1, NULL, + NULL), + CFRelease); + AutoCFArray kbds(TISCreateInputSourceList(dict.get(), false), CFRelease); - for (CFIndex i = 0; i < CFArrayGetCount(kbds.get()); ++i) { - TISInputSourceRef keyboardLayout = (TISInputSourceRef)CFArrayGetValueAtIndex(kbds.get(), i); - auto layoutLanguages = (CFArrayRef)TISGetInputSourceProperty(keyboardLayout, kTISPropertyInputSourceLanguages); - char temporaryCString[128] = {0}; - for(CFIndex index = 0; index < CFArrayGetCount(layoutLanguages) && layoutLanguages; index++) { - auto languageCode = (CFStringRef)CFArrayGetValueAtIndex(layoutLanguages, index); - if(!languageCode || - !CFStringGetCString(languageCode, temporaryCString, 128, kCFStringEncodingUTF8)) { - continue; - } - - std::string langCode(temporaryCString); - if(langCode.size() == 2 && - std::find(layoutLangCodes.begin(), layoutLangCodes.end(), langCode) == layoutLangCodes.end()){ - layoutLangCodes.push_back(langCode); - } - - //Save only first language code - break; - } - } -#endif - - return layoutLangCodes; -} - -String -AppUtilUnix::getCurrentLanguageCode() -{ - String result = ""; -#if WINAPI_XWINDOWS - - auto display = XOpenDisplay(nullptr); - if (!display) { - LOG((CLOG_WARN "failed to open x11 default display")); - return result; - } - - auto kbdDescr= XkbAllocKeyboard(); - if (!kbdDescr) { - LOG((CLOG_WARN "failed to get x11 keyboard description")); - return result; - } - XkbGetNames(display, XkbSymbolsNameMask, kbdDescr); - - Atom symNameAtom = kbdDescr->names->symbols; - auto rawLayouts = std::string(XGetAtomName(display, symNameAtom)); - - XkbStateRec state; - XkbGetState(display, XkbUseCoreKbd, &state); - auto nedeedGroupIndex = static_cast(state.group); - - size_t groupIdx = 0; - size_t groupStartI = 0; - for(size_t strI = 0; strI < rawLayouts.size(); strI++) { - if(rawLayouts[strI] != '+') { - continue; - } - - auto group = rawLayouts.substr(groupStartI, strI - groupStartI); - if(group.find("group", 0, 5) == std::string::npos && - group.find("inet", 0, 4) == std::string::npos && - group.find("pc", 0, 2) == std::string::npos) { - if(nedeedGroupIndex == groupIdx) { - result = group.substr(0, std::min(group.find('(', 0), group.find(':', 0))); - break; - } - groupIdx++; - } - - groupStartI = strI + 1; - } - - XkbFreeNames(kbdDescr, XkbSymbolsNameMask, true); - XFree(kbdDescr); - XCloseDisplay(display); - - result = X11LayoutsParser::convertLayotToISO("/usr/share/X11/xkb/rules/evdev.xml", result); - -#elif WINAPI_CARBON - auto layoutLanguages = (CFArrayRef)TISGetInputSourceProperty(TISCopyCurrentKeyboardInputSource(), kTISPropertyInputSourceLanguages); + for (CFIndex i = 0; i < CFArrayGetCount(kbds.get()); ++i) { + TISInputSourceRef keyboardLayout = + (TISInputSourceRef)CFArrayGetValueAtIndex(kbds.get(), i); + auto layoutLanguages = (CFArrayRef)TISGetInputSourceProperty( + keyboardLayout, kTISPropertyInputSourceLanguages); char temporaryCString[128] = {0}; - for(CFIndex index = 0; index < CFArrayGetCount(layoutLanguages) && layoutLanguages; index++) { - auto languageCode = (CFStringRef)CFArrayGetValueAtIndex(layoutLanguages, index); - if(!languageCode || !CFStringGetCString(languageCode, temporaryCString, 128, kCFStringEncodingUTF8)) { - continue; - } + for (CFIndex index = 0; + index < CFArrayGetCount(layoutLanguages) && layoutLanguages; index++) { + auto languageCode = + (CFStringRef)CFArrayGetValueAtIndex(layoutLanguages, index); + if (!languageCode || !CFStringGetCString(languageCode, temporaryCString, + 128, kCFStringEncodingUTF8)) { + continue; + } - result = std::string(temporaryCString); - break; + std::string langCode(temporaryCString); + if (langCode.size() == 2 && + std::find(layoutLangCodes.begin(), layoutLangCodes.end(), langCode) == + layoutLangCodes.end()) { + layoutLangCodes.push_back(langCode); + } + + // Save only first language code + break; } + } #endif - return result; + + return layoutLangCodes; } - -void -AppUtilUnix::showNotification(const String & title, const String & text) const -{ + +String AppUtilUnix::getCurrentLanguageCode() { + String result = ""; #if WINAPI_XWINDOWS - LOG((CLOG_INFO "showing notification, title=\"%s\", text=\"%s\"", title.c_str(), text.c_str())); - if (!notify_init("Synergy")) - { - LOG((CLOG_INFO "failed to initialize libnotify")); - return; + + auto display = XOpenDisplay(nullptr); + if (!display) { + LOG((CLOG_WARN "failed to open x11 default display")); + return result; + } + + auto kbdDescr = XkbAllocKeyboard(); + if (!kbdDescr) { + LOG((CLOG_WARN "failed to get x11 keyboard description")); + return result; + } + XkbGetNames(display, XkbSymbolsNameMask, kbdDescr); + + Atom symNameAtom = kbdDescr->names->symbols; + auto rawLayouts = std::string(XGetAtomName(display, symNameAtom)); + + XkbStateRec state; + XkbGetState(display, XkbUseCoreKbd, &state); + auto nedeedGroupIndex = static_cast(state.group); + + size_t groupIdx = 0; + size_t groupStartI = 0; + for (size_t strI = 0; strI < rawLayouts.size(); strI++) { + if (rawLayouts[strI] != '+') { + continue; } - auto notification = notify_notification_new (title.c_str(), text.c_str(), nullptr); - if (notification == nullptr) - { - LOG((CLOG_INFO "failed to create notification")); - return; - } - notify_notification_set_timeout(notification, 10000); - - if (!notify_notification_show(notification, nullptr)) - { - LOG((CLOG_INFO "failed to show notification")); + auto group = rawLayouts.substr(groupStartI, strI - groupStartI); + if (group.find("group", 0, 5) == std::string::npos && + group.find("inet", 0, 4) == std::string::npos && + group.find("pc", 0, 2) == std::string::npos) { + if (nedeedGroupIndex == groupIdx) { + result = + group.substr(0, std::min(group.find('(', 0), group.find(':', 0))); + break; + } + groupIdx++; } - g_object_unref(G_OBJECT(notification)); - notify_uninit(); + groupStartI = strI + 1; + } + + XkbFreeNames(kbdDescr, XkbSymbolsNameMask, true); + XFree(kbdDescr); + XCloseDisplay(display); + + result = X11LayoutsParser::convertLayotToISO( + "/usr/share/X11/xkb/rules/evdev.xml", result); #elif WINAPI_CARBON - // synergys and synergyc are not allowed to send native notifications on MacOS - // instead ask main synergy process to show them instead - LOG((CLOG_INFO "mac notification: %s|%s", title.c_str(), text.c_str())); + auto layoutLanguages = (CFArrayRef)TISGetInputSourceProperty( + TISCopyCurrentKeyboardInputSource(), kTISPropertyInputSourceLanguages); + char temporaryCString[128] = {0}; + for (CFIndex index = 0; + index < CFArrayGetCount(layoutLanguages) && layoutLanguages; index++) { + auto languageCode = + (CFStringRef)CFArrayGetValueAtIndex(layoutLanguages, index); + if (!languageCode || !CFStringGetCString(languageCode, temporaryCString, + 128, kCFStringEncodingUTF8)) { + continue; + } + + result = std::string(temporaryCString); + break; + } +#endif + return result; +} + +void AppUtilUnix::showNotification(const String &title, + const String &text) const { +#if WINAPI_XWINDOWS + LOG((CLOG_INFO "showing notification, title=\"%s\", text=\"%s\"", + title.c_str(), text.c_str())); + if (!notify_init("Synergy")) { + LOG((CLOG_INFO "failed to initialize libnotify")); + return; + } + + auto notification = + notify_notification_new(title.c_str(), text.c_str(), nullptr); + if (notification == nullptr) { + LOG((CLOG_INFO "failed to create notification")); + return; + } + notify_notification_set_timeout(notification, 10000); + + if (!notify_notification_show(notification, nullptr)) { + LOG((CLOG_INFO "failed to show notification")); + } + + g_object_unref(G_OBJECT(notification)); + notify_uninit(); + +#elif WINAPI_CARBON + // synergys and synergyc are not allowed to send native notifications on MacOS + // instead ask main synergy process to show them instead + LOG((CLOG_INFO "mac notification: %s|%s", title.c_str(), text.c_str())); #endif } diff --git a/src/lib/synergy/unix/AppUtilUnix.h b/src/lib/synergy/unix/AppUtilUnix.h index 99c668781..4779e563d 100644 --- a/src/lib/synergy/unix/AppUtilUnix.h +++ b/src/lib/synergy/unix/AppUtilUnix.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -26,12 +26,12 @@ class IEventQueue; class AppUtilUnix : public AppUtil { public: - AppUtilUnix(IEventQueue* events); - virtual ~AppUtilUnix(); - - int run(int argc, char** argv); - void startNode(); - std::vector getKeyboardLayoutList() override; - String getCurrentLanguageCode() override; - void showNotification(const String& title, const String& text) const override; + AppUtilUnix(IEventQueue *events); + virtual ~AppUtilUnix(); + + int run(int argc, char **argv); + void startNode(); + std::vector getKeyboardLayoutList() override; + String getCurrentLanguageCode() override; + void showNotification(const String &title, const String &text) const override; }; diff --git a/src/lib/synergy/unix/ISO639Table.h b/src/lib/synergy/unix/ISO639Table.h index f45b812c7..d2ac6ebde 100644 --- a/src/lib/synergy/unix/ISO639Table.h +++ b/src/lib/synergy/unix/ISO639Table.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -20,213 +20,111 @@ #include "base/String.h" -//copy from -//https://www.loc.gov/standards/iso639-2/php/code_list.php -//10.06.2021 -//first param - ISO 639-2, second param - 639-1 +// copy from +// https://www.loc.gov/standards/iso639-2/php/code_list.php +// 10.06.2021 +// first param - ISO 639-2, second param - 639-1 const std::vector> ISO_Table = { - std::make_pair("aar", "aa"), - std::make_pair("abk", "ab"), - std::make_pair("afr", "af"), - std::make_pair("aka", "ak"), - std::make_pair("sqi", "sq"), - std::make_pair("amh", "am"), - std::make_pair("ara", "ar"), - std::make_pair("arg", "an"), - std::make_pair("hye", "hy"), - std::make_pair("asm", "as"), - std::make_pair("ava", "av"), - std::make_pair("ave", "ae"), - std::make_pair("aym", "ay"), - std::make_pair("aze", "az"), - std::make_pair("bak", "ba"), - std::make_pair("bam", "bm"), - std::make_pair("eus", "eu"), - std::make_pair("bel", "be"), - std::make_pair("ben", "bn"), - std::make_pair("bih", "bh"), - std::make_pair("bis", "bi"), - std::make_pair("bod", "bo"), - std::make_pair("bos", "bs"), - std::make_pair("bre", "br"), - std::make_pair("bul", "bg"), - std::make_pair("mya", "my"), - std::make_pair("cat", "ca"), - std::make_pair("ces", "cs"), - std::make_pair("cha", "ch"), - std::make_pair("che", "ce"), - std::make_pair("zho", "zh"), - std::make_pair("chu", "cu"), - std::make_pair("chv", "cv"), - std::make_pair("cor", "kw"), - std::make_pair("cos", "co"), - std::make_pair("cre", "cr"), - std::make_pair("cym", "cy"), - std::make_pair("ces", "cs"), - std::make_pair("dan", "da"), - std::make_pair("deu", "de"), - std::make_pair("div", "dv"), - std::make_pair("nld", "nl"), - std::make_pair("dzo", "dz"), - std::make_pair("ell", "el"), - std::make_pair("eng", "en"), - std::make_pair("epo", "eo"), - std::make_pair("est", "et"), - std::make_pair("eus", "eu"), - std::make_pair("ewe", "ee"), - std::make_pair("fao", "fo"), - std::make_pair("fas", "fa"), - std::make_pair("fij", "fj"), - std::make_pair("fin", "fi"), - std::make_pair("fra", "fr"), - std::make_pair("fra", "fr"), - std::make_pair("fry", "fy"), - std::make_pair("ful", "ff"), - std::make_pair("kat", "ka"), - std::make_pair("deu", "de"), - std::make_pair("gla", "gd"), - std::make_pair("gle", "ga"), - std::make_pair("glg", "gl"), - std::make_pair("glv", "gv"), - std::make_pair("ell", "el"), - std::make_pair("grn", "gn"), - std::make_pair("guj", "gu"), - std::make_pair("hat", "ht"), - std::make_pair("hau", "ha"), - std::make_pair("heb", "he"), - std::make_pair("her", "hz"), - std::make_pair("hin", "hi"), - std::make_pair("hmo", "ho"), - std::make_pair("hrv", "hr"), - std::make_pair("hun", "hu"), - std::make_pair("hye", "hy"), - std::make_pair("ibo", "ig"), - std::make_pair("isl", "is"), - std::make_pair("ido", "io"), - std::make_pair("iii", "ii"), - std::make_pair("iku", "iu"), - std::make_pair("ile", "ie"), - std::make_pair("ina", "ia"), - std::make_pair("ind", "id"), - std::make_pair("ipk", "ik"), - std::make_pair("isl", "is"), - std::make_pair("ita", "it"), - std::make_pair("jav", "jv"), - std::make_pair("jpn", "ja"), - std::make_pair("kal", "kl"), - std::make_pair("kan", "kn"), - std::make_pair("kas", "ks"), - std::make_pair("kat", "ka"), - std::make_pair("kau", "kr"), - std::make_pair("kaz", "kk"), - std::make_pair("khm", "km"), - std::make_pair("kik", "ki"), - std::make_pair("kin", "rw"), - std::make_pair("kir", "ky"), - std::make_pair("kom", "kv"), - std::make_pair("kon", "kg"), - std::make_pair("kor", "ko"), - std::make_pair("kua", "kj"), - std::make_pair("kur", "ku"), - std::make_pair("lao", "lo"), - std::make_pair("lat", "la"), - std::make_pair("lav", "lv"), - std::make_pair("lim", "li"), - std::make_pair("lin", "ln"), - std::make_pair("lit", "lt"), - std::make_pair("ltz", "lb"), - std::make_pair("lub", "lu"), - std::make_pair("lug", "lg"), - std::make_pair("mkd", "mk"), - std::make_pair("mah", "mh"), - std::make_pair("mal", "ml"), - std::make_pair("mri", "mi"), - std::make_pair("mar", "mr"), - std::make_pair("msa", "ms"), - std::make_pair("mkd", "mk"), - std::make_pair("mlg", "mg"), - std::make_pair("mlt", "mt"), - std::make_pair("mon", "mn"), - std::make_pair("mri", "mi"), - std::make_pair("msa", "ms"), - std::make_pair("mya", "my"), - std::make_pair("nau", "na"), - std::make_pair("nav", "nv"), - std::make_pair("nbl", "nr"), - std::make_pair("nde", "nd"), - std::make_pair("ndo", "ng"), - std::make_pair("nep", "ne"), - std::make_pair("nld", "nl"), - std::make_pair("nno", "nn"), - std::make_pair("nob", "nb"), - std::make_pair("nor", "no"), - std::make_pair("nya", "ny"), - std::make_pair("oci", "oc"), - std::make_pair("oji", "oj"), - std::make_pair("ori", "or"), - std::make_pair("orm", "om"), - std::make_pair("oss", "os"), - std::make_pair("pan", "pa"), - std::make_pair("fas", "fa"), - std::make_pair("pli", "pi"), - std::make_pair("pol", "pl"), - std::make_pair("por", "pt"), - std::make_pair("pus", "ps"), - std::make_pair("que", "qu"), - std::make_pair("roh", "rm"), - std::make_pair("ron", "ro"), - std::make_pair("ron", "ro"), - std::make_pair("run", "rn"), - std::make_pair("rus", "ru"), - std::make_pair("sag", "sg"), - std::make_pair("san", "sa"), - std::make_pair("sin", "si"), - std::make_pair("slk", "sk"), - std::make_pair("slk", "sk"), - std::make_pair("slv", "sl"), - std::make_pair("sme", "se"), - std::make_pair("smo", "sm"), - std::make_pair("sna", "sn"), - std::make_pair("snd", "sd"), - std::make_pair("som", "so"), - std::make_pair("sot", "st"), - std::make_pair("spa", "es"), - std::make_pair("sqi", "sq"), - std::make_pair("srd", "sc"), - std::make_pair("srp", "sr"), - std::make_pair("ssw", "ss"), - std::make_pair("sun", "su"), - std::make_pair("swa", "sw"), - std::make_pair("swe", "sv"), - std::make_pair("tah", "ty"), - std::make_pair("tam", "ta"), - std::make_pair("tat", "tt"), - std::make_pair("tel", "te"), - std::make_pair("tgk", "tg"), - std::make_pair("tgl", "tl"), - std::make_pair("tha", "th"), - std::make_pair("bod", "bo"), - std::make_pair("tir", "ti"), - std::make_pair("ton", "to"), - std::make_pair("tsn", "tn"), - std::make_pair("tso", "ts"), - std::make_pair("tuk", "tk"), - std::make_pair("tur", "tr"), - std::make_pair("twi", "tw"), - std::make_pair("uig", "ug"), - std::make_pair("ukr", "uk"), - std::make_pair("urd", "ur"), - std::make_pair("uzb", "uz"), - std::make_pair("ven", "ve"), - std::make_pair("vie", "vi"), - std::make_pair("vol", "vo"), - std::make_pair("cym", "cy"), - std::make_pair("wln", "wa"), - std::make_pair("wol", "wo"), - std::make_pair("xho", "xh"), - std::make_pair("yid", "yi"), - std::make_pair("yor", "yo"), - std::make_pair("zha", "za"), - std::make_pair("zho", "zh"), - std::make_pair("zul", "zu"), + std::make_pair("aar", "aa"), std::make_pair("abk", "ab"), + std::make_pair("afr", "af"), std::make_pair("aka", "ak"), + std::make_pair("sqi", "sq"), std::make_pair("amh", "am"), + std::make_pair("ara", "ar"), std::make_pair("arg", "an"), + std::make_pair("hye", "hy"), std::make_pair("asm", "as"), + std::make_pair("ava", "av"), std::make_pair("ave", "ae"), + std::make_pair("aym", "ay"), std::make_pair("aze", "az"), + std::make_pair("bak", "ba"), std::make_pair("bam", "bm"), + std::make_pair("eus", "eu"), std::make_pair("bel", "be"), + std::make_pair("ben", "bn"), std::make_pair("bih", "bh"), + std::make_pair("bis", "bi"), std::make_pair("bod", "bo"), + std::make_pair("bos", "bs"), std::make_pair("bre", "br"), + std::make_pair("bul", "bg"), std::make_pair("mya", "my"), + std::make_pair("cat", "ca"), std::make_pair("ces", "cs"), + std::make_pair("cha", "ch"), std::make_pair("che", "ce"), + std::make_pair("zho", "zh"), std::make_pair("chu", "cu"), + std::make_pair("chv", "cv"), std::make_pair("cor", "kw"), + std::make_pair("cos", "co"), std::make_pair("cre", "cr"), + std::make_pair("cym", "cy"), std::make_pair("ces", "cs"), + std::make_pair("dan", "da"), std::make_pair("deu", "de"), + std::make_pair("div", "dv"), std::make_pair("nld", "nl"), + std::make_pair("dzo", "dz"), std::make_pair("ell", "el"), + std::make_pair("eng", "en"), std::make_pair("epo", "eo"), + std::make_pair("est", "et"), std::make_pair("eus", "eu"), + std::make_pair("ewe", "ee"), std::make_pair("fao", "fo"), + std::make_pair("fas", "fa"), std::make_pair("fij", "fj"), + std::make_pair("fin", "fi"), std::make_pair("fra", "fr"), + std::make_pair("fra", "fr"), std::make_pair("fry", "fy"), + std::make_pair("ful", "ff"), std::make_pair("kat", "ka"), + std::make_pair("deu", "de"), std::make_pair("gla", "gd"), + std::make_pair("gle", "ga"), std::make_pair("glg", "gl"), + std::make_pair("glv", "gv"), std::make_pair("ell", "el"), + std::make_pair("grn", "gn"), std::make_pair("guj", "gu"), + std::make_pair("hat", "ht"), std::make_pair("hau", "ha"), + std::make_pair("heb", "he"), std::make_pair("her", "hz"), + std::make_pair("hin", "hi"), std::make_pair("hmo", "ho"), + std::make_pair("hrv", "hr"), std::make_pair("hun", "hu"), + std::make_pair("hye", "hy"), std::make_pair("ibo", "ig"), + std::make_pair("isl", "is"), std::make_pair("ido", "io"), + std::make_pair("iii", "ii"), std::make_pair("iku", "iu"), + std::make_pair("ile", "ie"), std::make_pair("ina", "ia"), + std::make_pair("ind", "id"), std::make_pair("ipk", "ik"), + std::make_pair("isl", "is"), std::make_pair("ita", "it"), + std::make_pair("jav", "jv"), std::make_pair("jpn", "ja"), + std::make_pair("kal", "kl"), std::make_pair("kan", "kn"), + std::make_pair("kas", "ks"), std::make_pair("kat", "ka"), + std::make_pair("kau", "kr"), std::make_pair("kaz", "kk"), + std::make_pair("khm", "km"), std::make_pair("kik", "ki"), + std::make_pair("kin", "rw"), std::make_pair("kir", "ky"), + std::make_pair("kom", "kv"), std::make_pair("kon", "kg"), + std::make_pair("kor", "ko"), std::make_pair("kua", "kj"), + std::make_pair("kur", "ku"), std::make_pair("lao", "lo"), + std::make_pair("lat", "la"), std::make_pair("lav", "lv"), + std::make_pair("lim", "li"), std::make_pair("lin", "ln"), + std::make_pair("lit", "lt"), std::make_pair("ltz", "lb"), + std::make_pair("lub", "lu"), std::make_pair("lug", "lg"), + std::make_pair("mkd", "mk"), std::make_pair("mah", "mh"), + std::make_pair("mal", "ml"), std::make_pair("mri", "mi"), + std::make_pair("mar", "mr"), std::make_pair("msa", "ms"), + std::make_pair("mkd", "mk"), std::make_pair("mlg", "mg"), + std::make_pair("mlt", "mt"), std::make_pair("mon", "mn"), + std::make_pair("mri", "mi"), std::make_pair("msa", "ms"), + std::make_pair("mya", "my"), std::make_pair("nau", "na"), + std::make_pair("nav", "nv"), std::make_pair("nbl", "nr"), + std::make_pair("nde", "nd"), std::make_pair("ndo", "ng"), + std::make_pair("nep", "ne"), std::make_pair("nld", "nl"), + std::make_pair("nno", "nn"), std::make_pair("nob", "nb"), + std::make_pair("nor", "no"), std::make_pair("nya", "ny"), + std::make_pair("oci", "oc"), std::make_pair("oji", "oj"), + std::make_pair("ori", "or"), std::make_pair("orm", "om"), + std::make_pair("oss", "os"), std::make_pair("pan", "pa"), + std::make_pair("fas", "fa"), std::make_pair("pli", "pi"), + std::make_pair("pol", "pl"), std::make_pair("por", "pt"), + std::make_pair("pus", "ps"), std::make_pair("que", "qu"), + std::make_pair("roh", "rm"), std::make_pair("ron", "ro"), + std::make_pair("ron", "ro"), std::make_pair("run", "rn"), + std::make_pair("rus", "ru"), std::make_pair("sag", "sg"), + std::make_pair("san", "sa"), std::make_pair("sin", "si"), + std::make_pair("slk", "sk"), std::make_pair("slk", "sk"), + std::make_pair("slv", "sl"), std::make_pair("sme", "se"), + std::make_pair("smo", "sm"), std::make_pair("sna", "sn"), + std::make_pair("snd", "sd"), std::make_pair("som", "so"), + std::make_pair("sot", "st"), std::make_pair("spa", "es"), + std::make_pair("sqi", "sq"), std::make_pair("srd", "sc"), + std::make_pair("srp", "sr"), std::make_pair("ssw", "ss"), + std::make_pair("sun", "su"), std::make_pair("swa", "sw"), + std::make_pair("swe", "sv"), std::make_pair("tah", "ty"), + std::make_pair("tam", "ta"), std::make_pair("tat", "tt"), + std::make_pair("tel", "te"), std::make_pair("tgk", "tg"), + std::make_pair("tgl", "tl"), std::make_pair("tha", "th"), + std::make_pair("bod", "bo"), std::make_pair("tir", "ti"), + std::make_pair("ton", "to"), std::make_pair("tsn", "tn"), + std::make_pair("tso", "ts"), std::make_pair("tuk", "tk"), + std::make_pair("tur", "tr"), std::make_pair("twi", "tw"), + std::make_pair("uig", "ug"), std::make_pair("ukr", "uk"), + std::make_pair("urd", "ur"), std::make_pair("uzb", "uz"), + std::make_pair("ven", "ve"), std::make_pair("vie", "vi"), + std::make_pair("vol", "vo"), std::make_pair("cym", "cy"), + std::make_pair("wln", "wa"), std::make_pair("wol", "wo"), + std::make_pair("xho", "xh"), std::make_pair("yid", "yi"), + std::make_pair("yor", "yo"), std::make_pair("zha", "za"), + std::make_pair("zho", "zh"), std::make_pair("zul", "zu"), }; diff --git a/src/lib/synergy/unix/SynergyXkbKeyboard.cpp b/src/lib/synergy/unix/SynergyXkbKeyboard.cpp index cb69c5fcb..ac21866fc 100644 --- a/src/lib/synergy/unix/SynergyXkbKeyboard.cpp +++ b/src/lib/synergy/unix/SynergyXkbKeyboard.cpp @@ -19,49 +19,45 @@ #if WINAPI_XWINDOWS #include -#include "base/Log.h" #include "SynergyXkbKeyboard.h" +#include "base/Log.h" namespace synergy { namespace linux { -SynergyXkbKeyboard::SynergyXkbKeyboard() -{ - using XkbDisplay = std::unique_ptr; - XkbDisplay display(XkbOpenDisplay(nullptr, nullptr, nullptr, nullptr, nullptr, nullptr), &XCloseDisplay); +SynergyXkbKeyboard::SynergyXkbKeyboard() { + using XkbDisplay = std::unique_ptr; + XkbDisplay display( + XkbOpenDisplay(nullptr, nullptr, nullptr, nullptr, nullptr, nullptr), + &XCloseDisplay); - if (display) { - if (!XkbRF_GetNamesProp(display.get(), nullptr, &m_data)) { - LOG((CLOG_WARN "error reading keyboard layouts")); - } - } - else { - LOG((CLOG_WARN "can't open xkb display during reading languages")); + if (display) { + if (!XkbRF_GetNamesProp(display.get(), nullptr, &m_data)) { + LOG((CLOG_WARN "error reading keyboard layouts")); } + } else { + LOG((CLOG_WARN "can't open xkb display during reading languages")); + } } -const char* SynergyXkbKeyboard::getLayout() const -{ - return m_data.layout ? m_data.layout : "us"; +const char *SynergyXkbKeyboard::getLayout() const { + return m_data.layout ? m_data.layout : "us"; } -const char* SynergyXkbKeyboard::getVariant() const -{ - return m_data.variant ? m_data.variant : ""; +const char *SynergyXkbKeyboard::getVariant() const { + return m_data.variant ? m_data.variant : ""; } -SynergyXkbKeyboard::~SynergyXkbKeyboard() -{ - std::free(m_data.model); - std::free(m_data.layout); - std::free(m_data.variant); - std::free(m_data.options); +SynergyXkbKeyboard::~SynergyXkbKeyboard() { + std::free(m_data.model); + std::free(m_data.layout); + std::free(m_data.variant); + std::free(m_data.options); } +} // namespace linux -} //namespace Unix +} // namespace synergy -} //namespace synergy - -#endif //WINAPI_XWINDOWS +#endif // WINAPI_XWINDOWS diff --git a/src/lib/synergy/unix/SynergyXkbKeyboard.h b/src/lib/synergy/unix/SynergyXkbKeyboard.h index fefd13334..ab31c11c9 100644 --- a/src/lib/synergy/unix/SynergyXkbKeyboard.h +++ b/src/lib/synergy/unix/SynergyXkbKeyboard.h @@ -20,36 +20,32 @@ #ifndef XKBKEYBOARD_H #define XKBKEYBOARD_H - -#include #include #include +#include namespace synergy { namespace linux { -class SynergyXkbKeyboard -{ - XkbRF_VarDefsRec m_data = {}; +class SynergyXkbKeyboard { + XkbRF_VarDefsRec m_data = {}; public: - SynergyXkbKeyboard(); - SynergyXkbKeyboard(const SynergyXkbKeyboard&) = delete; - SynergyXkbKeyboard& operator=(const SynergyXkbKeyboard&) = delete; + SynergyXkbKeyboard(); + SynergyXkbKeyboard(const SynergyXkbKeyboard &) = delete; + SynergyXkbKeyboard &operator=(const SynergyXkbKeyboard &) = delete; - const char* getLayout() const; - const char* getVariant() const; + const char *getLayout() const; + const char *getVariant() const; - ~SynergyXkbKeyboard(); + ~SynergyXkbKeyboard(); }; -} //namespace Unix +} // namespace linux -} //namespace synergy +} // namespace synergy #endif // XKBKEYBOARD_H -#endif //WINAPI_XWINDOWS - - +#endif // WINAPI_XWINDOWS diff --git a/src/lib/synergy/unix/X11LayoutsParser.cpp b/src/lib/synergy/unix/X11LayoutsParser.cpp index 5bac014e2..eced99f70 100644 --- a/src/lib/synergy/unix/X11LayoutsParser.cpp +++ b/src/lib/synergy/unix/X11LayoutsParser.cpp @@ -16,205 +16,211 @@ * along with this program. If not, see . */ #if WINAPI_XWINDOWS +#include #include #include -#include -#include "base/Log.h" -#include "X11LayoutsParser.h" #include "ISO639Table.h" -#include "pugixml.hpp" #include "SynergyXkbKeyboard.h" +#include "X11LayoutsParser.h" +#include "base/Log.h" +#include "pugixml.hpp" -namespace -{ +namespace { -void splitLine(std::vector& parts, const String& line, char delimiter) -{ - std::stringstream stream(line); - while (stream.good()) { - String part; - getline(stream, part, delimiter); - parts.push_back(part); - } +void splitLine(std::vector &parts, const String &line, char delimiter) { + std::stringstream stream(line); + while (stream.good()) { + String part; + getline(stream, part, delimiter); + parts.push_back(part); + } } -} //namespace +} // namespace -bool -X11LayoutsParser::readXMLConfigItemElem(const pugi::xml_node* root, std::vector& langList) -{ - auto configItemElem = root->child("configItem"); - if(!configItemElem) { - LOG((CLOG_WARN "failed to read \"configItem\" in xml file")); - return false; +bool X11LayoutsParser::readXMLConfigItemElem(const pugi::xml_node *root, + std::vector &langList) { + auto configItemElem = root->child("configItem"); + if (!configItemElem) { + LOG((CLOG_WARN "failed to read \"configItem\" in xml file")); + return false; + } + + langList.emplace_back(); + auto nameElem = configItemElem.child("name"); + if (nameElem) { + langList.back().name = nameElem.text().as_string(); + } + + auto languageListElem = configItemElem.child("languageList"); + if (languageListElem) { + for (pugi::xml_node isoElem : languageListElem.children("iso639Id")) { + langList.back().layoutBaseISO639_2.emplace_back( + isoElem.text().as_string()); } + } - langList.emplace_back(); - auto nameElem = configItemElem.child("name"); - if(nameElem) { - langList.back().name = nameElem.text().as_string(); - } - - auto languageListElem = configItemElem.child("languageList"); - if(languageListElem) { - for (pugi::xml_node isoElem : languageListElem.children("iso639Id")) { - langList.back().layoutBaseISO639_2.emplace_back(isoElem.text().as_string()); - } - } - - return true; + return true; } std::vector -X11LayoutsParser::getAllLanguageData(const String& pathToEvdevFile) -{ - std::vector allCodes; - pugi::xml_document doc; - if(!doc.load_file(pathToEvdevFile.c_str())) { - LOG((CLOG_WARN "failed to open %s", pathToEvdevFile.c_str())); - return allCodes; - } - - auto xkbConfigElem = doc.child("xkbConfigRegistry"); - if(!xkbConfigElem) { - LOG((CLOG_WARN "failed to read xkbConfigRegistry in %s", pathToEvdevFile.c_str())); - return allCodes; - } - - auto layoutListElem = xkbConfigElem.child("layoutList"); - if(!layoutListElem) { - LOG((CLOG_WARN "failed to read layoutList in %s", pathToEvdevFile.c_str())); - return allCodes; - } - - for (pugi::xml_node layoutElem : layoutListElem.children("layout")) { - if (!readXMLConfigItemElem(&layoutElem, allCodes)) { - continue; - } - - auto variantListElem = layoutElem.child("variantList"); - if (variantListElem) { - for (pugi::xml_node variantElem : variantListElem.children("variant")) { - readXMLConfigItemElem(&variantElem, allCodes.back().variants); - } - } - } - +X11LayoutsParser::getAllLanguageData(const String &pathToEvdevFile) { + std::vector allCodes; + pugi::xml_document doc; + if (!doc.load_file(pathToEvdevFile.c_str())) { + LOG((CLOG_WARN "failed to open %s", pathToEvdevFile.c_str())); return allCodes; + } + + auto xkbConfigElem = doc.child("xkbConfigRegistry"); + if (!xkbConfigElem) { + LOG((CLOG_WARN "failed to read xkbConfigRegistry in %s", + pathToEvdevFile.c_str())); + return allCodes; + } + + auto layoutListElem = xkbConfigElem.child("layoutList"); + if (!layoutListElem) { + LOG((CLOG_WARN "failed to read layoutList in %s", pathToEvdevFile.c_str())); + return allCodes; + } + + for (pugi::xml_node layoutElem : layoutListElem.children("layout")) { + if (!readXMLConfigItemElem(&layoutElem, allCodes)) { + continue; + } + + auto variantListElem = layoutElem.child("variantList"); + if (variantListElem) { + for (pugi::xml_node variantElem : variantListElem.children("variant")) { + readXMLConfigItemElem(&variantElem, allCodes.back().variants); + } + } + } + + return allCodes; } -void -X11LayoutsParser::appendVectorUniq(const std::vector& source, std::vector& dst) { - for(const auto& elem : source) { - if(std::find_if(dst.begin(), dst.end(), [elem](const String& s) {return s == elem;}) == dst.end()) { - dst.push_back(elem); - } +void X11LayoutsParser::appendVectorUniq(const std::vector &source, + std::vector &dst) { + for (const auto &elem : source) { + if (std::find_if(dst.begin(), dst.end(), [elem](const String &s) { + return s == elem; + }) == dst.end()) { + dst.push_back(elem); } + } }; -void -X11LayoutsParser::convertLayoutToISO639_2(const String& pathToEvdevFile, - bool needToReloadEvdev, - const std::vector& layoutNames, - const std::vector& layoutVariantNames, - std::vector& iso639_2Codes) -{ - if(layoutNames.size() != layoutVariantNames.size()) { - LOG((CLOG_WARN "error in language layout or language layout variants list")); - return; +void X11LayoutsParser::convertLayoutToISO639_2( + const String &pathToEvdevFile, bool needToReloadEvdev, + const std::vector &layoutNames, + const std::vector &layoutVariantNames, + std::vector &iso639_2Codes) { + if (layoutNames.size() != layoutVariantNames.size()) { + LOG((CLOG_WARN + "error in language layout or language layout variants list")); + return; + } + + static std::vector allLang; + if (allLang.empty() || needToReloadEvdev) { + allLang = getAllLanguageData(pathToEvdevFile); + } + for (size_t i = 0; i < layoutNames.size(); i++) { + const auto &layoutName = layoutNames[i]; + auto langIter = std::find_if( + allLang.begin(), allLang.end(), + [&layoutName](const Lang &l) { return l.name == layoutName; }); + if (langIter == allLang.end()) { + LOG((CLOG_WARN "language \"%s\" is unknown", layoutNames[i].c_str())); + continue; } - static std::vector allLang; - if(allLang.empty() || needToReloadEvdev) { - allLang = getAllLanguageData(pathToEvdevFile); + const std::vector *toCopy = nullptr; + if (layoutVariantNames[i].empty()) { + toCopy = &langIter->layoutBaseISO639_2; + } else { + const auto &variantName = layoutVariantNames[i]; + auto langVariantIter = std::find_if( + langIter->variants.begin(), langIter->variants.end(), + [&variantName](const Lang &l) { return l.name == variantName; }); + if (langVariantIter == langIter->variants.end()) { + LOG((CLOG_WARN "variant \"%s\" of language \"%s\" is unknown", + layoutVariantNames[i].c_str(), layoutNames[i].c_str())); + continue; + } + + if (langVariantIter->layoutBaseISO639_2.empty()) { + toCopy = &langIter->layoutBaseISO639_2; + } else { + toCopy = &langVariantIter->layoutBaseISO639_2; + } } - for (size_t i = 0; i < layoutNames.size(); i++) { - const auto& layoutName = layoutNames[i]; - auto langIter = std::find_if(allLang.begin(), allLang.end(), [&layoutName](const Lang& l) {return l.name == layoutName;}); - if(langIter == allLang.end()) { - LOG((CLOG_WARN "language \"%s\" is unknown", layoutNames[i].c_str())); - continue; - } - const std::vector* toCopy = nullptr; - if(layoutVariantNames[i].empty()) { - toCopy = &langIter->layoutBaseISO639_2; - } - else { - const auto& variantName = layoutVariantNames[i]; - auto langVariantIter = std::find_if(langIter->variants.begin(), langIter->variants.end(), - [&variantName](const Lang& l) {return l.name == variantName;}); - if(langVariantIter == langIter->variants.end()) { - LOG((CLOG_WARN "variant \"%s\" of language \"%s\" is unknown", layoutVariantNames[i].c_str(), layoutNames[i].c_str())); - continue; - } - - if(langVariantIter->layoutBaseISO639_2.empty()) { - toCopy = &langIter->layoutBaseISO639_2; - } - else { - toCopy = &langVariantIter->layoutBaseISO639_2; - } - } - - if(toCopy) { - appendVectorUniq(*toCopy, iso639_2Codes); - } + if (toCopy) { + appendVectorUniq(*toCopy, iso639_2Codes); } + } } std::vector -X11LayoutsParser::getX11LanguageList(const String& pathToEvdevFile) -{ - std::vector layoutNames; - std::vector layoutVariantNames; +X11LayoutsParser::getX11LanguageList(const String &pathToEvdevFile) { + std::vector layoutNames; + std::vector layoutVariantNames; - synergy::linux::SynergyXkbKeyboard keyboard; - splitLine(layoutNames, keyboard.getLayout(), ','); - splitLine(layoutVariantNames, keyboard.getVariant(), ','); + synergy::linux::SynergyXkbKeyboard keyboard; + splitLine(layoutNames, keyboard.getLayout(), ','); + splitLine(layoutVariantNames, keyboard.getVariant(), ','); - std::vector iso639_2Codes; - iso639_2Codes.reserve(layoutNames.size()); - convertLayoutToISO639_2(pathToEvdevFile, true, layoutNames, layoutVariantNames, iso639_2Codes); - return convertISO639_2ToISO639_1(iso639_2Codes); + std::vector iso639_2Codes; + iso639_2Codes.reserve(layoutNames.size()); + convertLayoutToISO639_2(pathToEvdevFile, true, layoutNames, + layoutVariantNames, iso639_2Codes); + return convertISO639_2ToISO639_1(iso639_2Codes); } -String -X11LayoutsParser::convertLayotToISO(const String& pathToEvdevFile, const String& layoutLangCode, bool needToReloadFiles) -{ - std::vector iso639_2Codes; - convertLayoutToISO639_2(pathToEvdevFile, needToReloadFiles, {layoutLangCode}, {""}, iso639_2Codes); - if(iso639_2Codes.empty()) { - LOG((CLOG_WARN "failed to convert layout lang code: \"%s\"", layoutLangCode.c_str())); - return ""; - } +String X11LayoutsParser::convertLayotToISO(const String &pathToEvdevFile, + const String &layoutLangCode, + bool needToReloadFiles) { + std::vector iso639_2Codes; + convertLayoutToISO639_2(pathToEvdevFile, needToReloadFiles, {layoutLangCode}, + {""}, iso639_2Codes); + if (iso639_2Codes.empty()) { + LOG((CLOG_WARN "failed to convert layout lang code: \"%s\"", + layoutLangCode.c_str())); + return ""; + } - auto iso639_1Codes = convertISO639_2ToISO639_1(iso639_2Codes); - if(iso639_1Codes.empty()) { - LOG((CLOG_WARN "failed to convert ISO639/2 lang code to ISO639/1")); - return ""; - } + auto iso639_1Codes = convertISO639_2ToISO639_1(iso639_2Codes); + if (iso639_1Codes.empty()) { + LOG((CLOG_WARN "failed to convert ISO639/2 lang code to ISO639/1")); + return ""; + } - return *iso639_1Codes.begin(); + return *iso639_1Codes.begin(); } -std::vector -X11LayoutsParser::convertISO639_2ToISO639_1(const std::vector& iso639_2Codes) -{ - std::vector result; - for (const auto& isoCode : iso639_2Codes) { - const auto& tableIter = std::find_if(ISO_Table.begin(), ISO_Table.end(), - [&isoCode](const std::pair& c) {return c.first == isoCode;}); - if(tableIter == ISO_Table.end()) { - LOG((CLOG_WARN "the ISO 639-2 code \"%s\" is missed in table", isoCode.c_str())); - continue; - } - - appendVectorUniq({tableIter->second}, result); +std::vector X11LayoutsParser::convertISO639_2ToISO639_1( + const std::vector &iso639_2Codes) { + std::vector result; + for (const auto &isoCode : iso639_2Codes) { + const auto &tableIter = + std::find_if(ISO_Table.begin(), ISO_Table.end(), + [&isoCode](const std::pair &c) { + return c.first == isoCode; + }); + if (tableIter == ISO_Table.end()) { + LOG((CLOG_WARN "the ISO 639-2 code \"%s\" is missed in table", + isoCode.c_str())); + continue; } - return result; + appendVectorUniq({tableIter->second}, result); + } + + return result; } -#endif //WINAPI_XWINDOWS +#endif // WINAPI_XWINDOWS diff --git a/src/lib/synergy/unix/X11LayoutsParser.h b/src/lib/synergy/unix/X11LayoutsParser.h index 57b84ccb7..83472ec8b 100644 --- a/src/lib/synergy/unix/X11LayoutsParser.h +++ b/src/lib/synergy/unix/X11LayoutsParser.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -20,38 +20,40 @@ #pragma once #include "base/String.h" -namespace pugi -{ - class xml_node; +namespace pugi { +class xml_node; } class X11LayoutsParser { public: - static std::vector getX11LanguageList(const String& pathToEvdevFile); - static String convertLayotToISO(const String& pathToEvdevFile, const String& layoutLangCode, bool needToReloadFiles = false); + static std::vector getX11LanguageList(const String &pathToEvdevFile); + static String convertLayotToISO(const String &pathToEvdevFile, + const String &layoutLangCode, + bool needToReloadFiles = false); private: - struct Lang { - String name = ""; - std::vector layoutBaseISO639_2; - std::vector variants; - }; + struct Lang { + String name = ""; + std::vector layoutBaseISO639_2; + std::vector variants; + }; - static bool readXMLConfigItemElem(const pugi::xml_node* root, - std::vector& langList); + static bool readXMLConfigItemElem(const pugi::xml_node *root, + std::vector &langList); - static std::vector getAllLanguageData(const String& pathToEvdevFile); + static std::vector getAllLanguageData(const String &pathToEvdevFile); - static void appendVectorUniq(const std::vector& source, - std::vector& dst); + static void appendVectorUniq(const std::vector &source, + std::vector &dst); - static void convertLayoutToISO639_2(const String& pathToEvdevFile, - bool needToReloadEvdev, - const std::vector& layoutNames, - const std::vector& layoutVariantNames, - std::vector& iso639_2Codes); + static void + convertLayoutToISO639_2(const String &pathToEvdevFile, bool needToReloadEvdev, + const std::vector &layoutNames, + const std::vector &layoutVariantNames, + std::vector &iso639_2Codes); - static std::vector convertISO639_2ToISO639_1(const std::vector& iso639_2Codes); + static std::vector + convertISO639_2ToISO639_1(const std::vector &iso639_2Codes); }; -#endif //WINAPI_XWINDOWS +#endif // WINAPI_XWINDOWS diff --git a/src/lib/synergy/win32/AppUtilWindows.cpp b/src/lib/synergy/win32/AppUtilWindows.cpp index d728e74a3..82e42f705 100644 --- a/src/lib/synergy/win32/AppUtilWindows.cpp +++ b/src/lib/synergy/win32/AppUtilWindows.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -17,266 +17,227 @@ */ #include "synergy/win32/AppUtilWindows.h" -#include "synergy/Screen.h" -#include "synergy/ArgsBase.h" -#include "synergy/App.h" -#include "synergy/XSynergy.h" -#include "platform/MSWindowsScreen.h" -#include "arch/win32/XArchWindows.h" -#include "arch/win32/ArchMiscWindows.h" #include "arch/IArchTaskBarReceiver.h" -#include "base/Log.h" -#include "base/log_outputters.h" -#include "base/IEventQueue.h" +#include "arch/win32/ArchMiscWindows.h" +#include "arch/win32/XArchWindows.h" #include "base/Event.h" #include "base/EventQueue.h" +#include "base/IEventQueue.h" +#include "base/Log.h" +#include "base/log_outputters.h" #include "common/Version.h" +#include "platform/MSWindowsScreen.h" +#include "synergy/App.h" +#include "synergy/ArgsBase.h" +#include "synergy/Screen.h" +#include "synergy/XSynergy.h" #include "wintoastlib.h" +#include +#include +#include #include #include -#include -#include -#include #include -AppUtilWindows::AppUtilWindows(IEventQueue* events) : - m_events(events), - m_exitMode(kExitModeNormal) -{ - if (SetConsoleCtrlHandler((PHANDLER_ROUTINE)consoleHandler, TRUE) == FALSE) - { - throw XArch(new XArchEvalWindows()); +AppUtilWindows::AppUtilWindows(IEventQueue *events) + : m_events(events), m_exitMode(kExitModeNormal) { + if (SetConsoleCtrlHandler((PHANDLER_ROUTINE)consoleHandler, TRUE) == FALSE) { + throw XArch(new XArchEvalWindows()); + } +} + +AppUtilWindows::~AppUtilWindows() {} + +BOOL WINAPI AppUtilWindows::consoleHandler(DWORD) { + LOG((CLOG_INFO "got shutdown signal")); + IEventQueue *events = AppUtil::instance().app().getEvents(); + events->addEvent(Event(Event::kQuit)); + return TRUE; +} + +static int mainLoopStatic() { return AppUtil::instance().app().mainLoop(); } + +int AppUtilWindows::daemonNTMainLoop(int argc, const char **argv) { + app().initApp(argc, argv); + debugServiceWait(); + + return ArchMiscWindows::runDaemon(mainLoopStatic); +} + +void AppUtilWindows::exitApp(int code) { + switch (m_exitMode) { + + case kExitModeDaemon: + ArchMiscWindows::daemonFailed(code); + break; + + default: + throw XExitApp(code); + } +} + +int daemonNTMainLoopStatic(int argc, const char **argv) { + return AppUtilWindows::instance().daemonNTMainLoop(argc, argv); +} + +int AppUtilWindows::daemonNTStartup(int, char **) { + SystemLogger sysLogger(app().daemonName(), false); + m_exitMode = kExitModeDaemon; + return ARCH->daemonize(app().daemonName(), daemonNTMainLoopStatic); +} + +static int daemonNTStartupStatic(int argc, char **argv) { + return AppUtilWindows::instance().daemonNTStartup(argc, argv); +} + +static int foregroundStartupStatic(int argc, char **argv) { + return AppUtil::instance().app().foregroundStartup(argc, argv); +} + +void AppUtilWindows::beforeAppExit() { + // this can be handy for debugging, since the application is launched in + // a new console window, and will normally close on exit (making it so + // that we can't see error messages). + if (app().argsBase().m_pauseOnExit) { + std::cout << std::endl << "press any key to exit..." << std::endl; + int c = _getch(); + } +} + +int AppUtilWindows::run(int argc, char **argv) { + if (!IsWindowsXPSP3OrGreater()) { + throw std::runtime_error("Synergy only supports Windows XP SP3 and above."); + } + + // record window instance for tray icon, etc + ArchMiscWindows::setInstanceWin32(GetModuleHandle(NULL)); + + MSWindowsScreen::init(ArchMiscWindows::instanceWin32()); + Thread::getCurrentThread().setPriority(-14); + + StartupFunc startup; + if (ArchMiscWindows::wasLaunchedAsService()) { + startup = &daemonNTStartupStatic; + } else { + startup = &foregroundStartupStatic; + app().argsBase().m_daemon = false; + } + + return app().runInner(argc, argv, NULL, startup); +} + +AppUtilWindows &AppUtilWindows::instance() { + return (AppUtilWindows &)AppUtil::instance(); +} + +void AppUtilWindows::debugServiceWait() { + if (app().argsBase().m_debugServiceWait) { + while (true) { + // this code is only executed when the process is launched via the + // windows service controller (and --debug-service-wait arg is + // used). to debug, set a breakpoint on this line so that + // execution is delayed until the debugger is attached. + ARCH->sleep(1); + LOG((CLOG_INFO "waiting for debugger to attach")); } + } } -AppUtilWindows::~AppUtilWindows() -{ -} +void AppUtilWindows::startNode() { app().startNode(); } -BOOL WINAPI AppUtilWindows::consoleHandler(DWORD) -{ - LOG((CLOG_INFO "got shutdown signal")); - IEventQueue* events = AppUtil::instance().app().getEvents(); - events->addEvent(Event(Event::kQuit)); - return TRUE; -} +std::vector AppUtilWindows::getKeyboardLayoutList() { + std::vector layoutLangCodes; + { + auto uLayouts = GetKeyboardLayoutList(0, NULL); + auto lpList = (HKL *)LocalAlloc(LPTR, (uLayouts * sizeof(HKL))); + uLayouts = GetKeyboardLayoutList(uLayouts, lpList); -static -int -mainLoopStatic() -{ - return AppUtil::instance().app().mainLoop(); -} - -int -AppUtilWindows::daemonNTMainLoop(int argc, const char** argv) -{ - app().initApp(argc, argv); - debugServiceWait(); - - return ArchMiscWindows::runDaemon(mainLoopStatic); -} - -void -AppUtilWindows::exitApp(int code) -{ - switch (m_exitMode) { - - case kExitModeDaemon: - ArchMiscWindows::daemonFailed(code); - break; - - default: - throw XExitApp(code); - } -} - -int daemonNTMainLoopStatic(int argc, const char** argv) -{ - return AppUtilWindows::instance().daemonNTMainLoop(argc, argv); -} - -int -AppUtilWindows::daemonNTStartup(int, char**) -{ - SystemLogger sysLogger(app().daemonName(), false); - m_exitMode = kExitModeDaemon; - return ARCH->daemonize(app().daemonName(), daemonNTMainLoopStatic); -} - -static -int -daemonNTStartupStatic(int argc, char** argv) -{ - return AppUtilWindows::instance().daemonNTStartup(argc, argv); -} - -static -int -foregroundStartupStatic(int argc, char** argv) -{ - return AppUtil::instance().app().foregroundStartup(argc, argv); -} - -void -AppUtilWindows::beforeAppExit() -{ - // this can be handy for debugging, since the application is launched in - // a new console window, and will normally close on exit (making it so - // that we can't see error messages). - if (app().argsBase().m_pauseOnExit) { - std::cout << std::endl << "press any key to exit..." << std::endl; - int c = _getch(); - } -} - -int -AppUtilWindows::run(int argc, char** argv) -{ - if (!IsWindowsXPSP3OrGreater()) { - throw std::runtime_error("Synergy only supports Windows XP SP3 and above."); + for (int i = 0; i < uLayouts; ++i) { + String code("", 2); + GetLocaleInfoA(MAKELCID(((UINT)lpList[i] & 0xffffffff), SORT_DEFAULT), + LOCALE_SISO639LANGNAME, &code[0], code.size()); + layoutLangCodes.push_back(code); } - // record window instance for tray icon, etc - ArchMiscWindows::setInstanceWin32(GetModuleHandle(NULL)); - - MSWindowsScreen::init(ArchMiscWindows::instanceWin32()); - Thread::getCurrentThread().setPriority(-14); - - StartupFunc startup; - if (ArchMiscWindows::wasLaunchedAsService()) { - startup = &daemonNTStartupStatic; - } else { - startup = &foregroundStartupStatic; - app().argsBase().m_daemon = false; + if (lpList) { + LocalFree(lpList); } - - return app().runInner(argc, argv, NULL, startup); + } + return layoutLangCodes; } -AppUtilWindows& -AppUtilWindows::instance() -{ - return (AppUtilWindows&)AppUtil::instance(); +String AppUtilWindows::getCurrentLanguageCode() { + String code("", 2); + + auto hklLayout = getCurrentKeyboardLayout(); + if (hklLayout) { + auto localLayoutID = MAKELCID(LOWORD(hklLayout), SORT_DEFAULT); + GetLocaleInfoA(localLayoutID, LOCALE_SISO639LANGNAME, &code[0], + code.size()); + } + + return code; } -void -AppUtilWindows::debugServiceWait() -{ - if (app().argsBase().m_debugServiceWait) - { - while(true) - { - // this code is only executed when the process is launched via the - // windows service controller (and --debug-service-wait arg is - // used). to debug, set a breakpoint on this line so that - // execution is delayed until the debugger is attached. - ARCH->sleep(1); - LOG((CLOG_INFO "waiting for debugger to attach")); - } - } -} +HKL AppUtilWindows::getCurrentKeyboardLayout() const { + HKL layout = nullptr; -void -AppUtilWindows::startNode() -{ - app().startNode(); -} + GUITHREADINFO gti = {sizeof(GUITHREADINFO)}; + if (GetGUIThreadInfo(0, >i) && gti.hwndActive) { + layout = GetKeyboardLayout(GetWindowThreadProcessId(gti.hwndActive, NULL)); + } else { + LOG((CLOG_WARN "failed to determine current keyboard layout")); + } -std::vector -AppUtilWindows::getKeyboardLayoutList() -{ - std::vector layoutLangCodes; - { - auto uLayouts = GetKeyboardLayoutList(0, NULL); - auto lpList = (HKL*)LocalAlloc(LPTR, (uLayouts * sizeof(HKL))); - uLayouts = GetKeyboardLayoutList(uLayouts, lpList); - - for (int i = 0; i < uLayouts; ++i){ - String code("", 2); - GetLocaleInfoA(MAKELCID(((UINT)lpList[i] & 0xffffffff), SORT_DEFAULT), LOCALE_SISO639LANGNAME, &code[0], code.size()); - layoutLangCodes.push_back(code); - } - - if (lpList) { - LocalFree(lpList); - } - } - return layoutLangCodes; -} - -String -AppUtilWindows::getCurrentLanguageCode() -{ - String code("", 2); - - auto hklLayout = getCurrentKeyboardLayout(); - if (hklLayout) { - auto localLayoutID = MAKELCID(LOWORD(hklLayout), SORT_DEFAULT); - GetLocaleInfoA(localLayoutID, LOCALE_SISO639LANGNAME, &code[0], code.size()); - } - - return code; -} - -HKL AppUtilWindows::getCurrentKeyboardLayout() const -{ - HKL layout = nullptr; - - GUITHREADINFO gti = {sizeof(GUITHREADINFO)}; - if (GetGUIThreadInfo(0, >i) && gti.hwndActive) { - layout = GetKeyboardLayout(GetWindowThreadProcessId(gti.hwndActive, NULL)); - } - else { - LOG((CLOG_WARN "failed to determine current keyboard layout")); - } - - return layout; + return layout; } class WinToastHandler : public WinToastLib::IWinToastHandler { public: - WinToastHandler() {} - // Public interfaces - void toastActivated() const override {} - void toastActivated(int actionIndex) const override {} - void toastDismissed(WinToastDismissalReason state) const override {} - void toastFailed() const override {} + WinToastHandler() {} + // Public interfaces + void toastActivated() const override {} + void toastActivated(int actionIndex) const override {} + void toastDismissed(WinToastDismissalReason state) const override {} + void toastFailed() const override {} }; -void -AppUtilWindows::showNotification(const String & title, const String & text) const -{ - LOG((CLOG_INFO "showing notification, title=\"%s\", text=\"%s\"", title.c_str(), text.c_str())); - if (!WinToastLib::WinToast::isCompatible()) { - LOG((CLOG_INFO "this system does not support toast notifications")); - return; - } - if (!WinToastLib::WinToast::instance()->isInitialized()) - { - WinToastLib::WinToast::instance()->setAppName(L"Synergy"); - const auto aumi = WinToastLib::WinToast::configureAUMI(L"Symless", L"Synergy", L"Synergy App", L"1.14.1+"); - WinToastLib::WinToast::instance()->setAppUserModelId(aumi); +void AppUtilWindows::showNotification(const String &title, + const String &text) const { + LOG((CLOG_INFO "showing notification, title=\"%s\", text=\"%s\"", + title.c_str(), text.c_str())); + if (!WinToastLib::WinToast::isCompatible()) { + LOG((CLOG_INFO "this system does not support toast notifications")); + return; + } + if (!WinToastLib::WinToast::instance()->isInitialized()) { + WinToastLib::WinToast::instance()->setAppName(L"Synergy"); + const auto aumi = WinToastLib::WinToast::configureAUMI( + L"Symless", L"Synergy", L"Synergy App", L"1.14.1+"); + WinToastLib::WinToast::instance()->setAppUserModelId(aumi); - if (!WinToastLib::WinToast::instance()->initialize()) - { - LOG((CLOG_DEBUG "failed to initialize toast notifications")); - return; - } + if (!WinToastLib::WinToast::instance()->initialize()) { + LOG((CLOG_DEBUG "failed to initialize toast notifications")); + return; } + } - WinToastLib::WinToast::WinToastError error; - auto handler = std::make_unique(); - WinToastLib::WinToastTemplate templ = WinToastLib::WinToastTemplate(WinToastLib::WinToastTemplate::Text02); - templ.setTextField(std::wstring(title.begin(), title.end()), WinToastLib::WinToastTemplate::FirstLine); - templ.setTextField(std::wstring(text.begin(), text.end()), WinToastLib::WinToastTemplate::SecondLine); + WinToastLib::WinToast::WinToastError error; + auto handler = std::make_unique(); + WinToastLib::WinToastTemplate templ = + WinToastLib::WinToastTemplate(WinToastLib::WinToastTemplate::Text02); + templ.setTextField(std::wstring(title.begin(), title.end()), + WinToastLib::WinToastTemplate::FirstLine); + templ.setTextField(std::wstring(text.begin(), text.end()), + WinToastLib::WinToastTemplate::SecondLine); - const bool launched = WinToastLib::WinToast::instance()->showToast(templ, handler.get(), &error); - if (!launched) { - LOG((CLOG_DEBUG "failed to show toast notification, error code: %d", error)); - return; - } + const bool launched = WinToastLib::WinToast::instance()->showToast( + templ, handler.get(), &error); + if (!launched) { + LOG((CLOG_DEBUG "failed to show toast notification, error code: %d", + error)); + return; + } } - diff --git a/src/lib/synergy/win32/AppUtilWindows.h b/src/lib/synergy/win32/AppUtilWindows.h index 5e0c0f884..b99a4688c 100644 --- a/src/lib/synergy/win32/AppUtilWindows.h +++ b/src/lib/synergy/win32/AppUtilWindows.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless 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 LICENSE 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 @@ -27,44 +27,40 @@ class IEventQueue; -enum AppExitMode { - kExitModeNormal, - kExitModeDaemon -}; +enum AppExitMode { kExitModeNormal, kExitModeDaemon }; class AppUtilWindows : public AppUtil { public: - AppUtilWindows(IEventQueue* events); - virtual ~AppUtilWindows(); + AppUtilWindows(IEventQueue *events); + virtual ~AppUtilWindows(); - int daemonNTStartup(int, char**); - - int daemonNTMainLoop(int argc, const char** argv); + int daemonNTStartup(int, char **); - void debugServiceWait(); + int daemonNTMainLoop(int argc, const char **argv); - int run(int argc, char** argv); + void debugServiceWait(); - void exitApp(int code); + int run(int argc, char **argv); - void beforeAppExit(); + void exitApp(int code); - static AppUtilWindows& instance(); + void beforeAppExit(); - void startNode(); + static AppUtilWindows &instance(); - std::vector getKeyboardLayoutList() override; + void startNode(); - String getCurrentLanguageCode() override; + std::vector getKeyboardLayoutList() override; - HKL getCurrentKeyboardLayout() const; + String getCurrentLanguageCode() override; - void showNotification(const String& title, const String& text) const override; + HKL getCurrentKeyboardLayout() const; + void showNotification(const String &title, const String &text) const override; private: - AppExitMode m_exitMode; - IEventQueue* m_events; + AppExitMode m_exitMode; + IEventQueue *m_events; - static BOOL WINAPI consoleHandler(DWORD Event); + static BOOL WINAPI consoleHandler(DWORD Event); }; diff --git a/src/test/global/TestEventQueue.cpp b/src/test/global/TestEventQueue.cpp index f28c46ddd..ab61af41e 100644 --- a/src/test/global/TestEventQueue.cpp +++ b/src/test/global/TestEventQueue.cpp @@ -1,11 +1,11 @@ /* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2013-2016 Symless Ltd. - * + * * 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 LICENSE 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 @@ -18,36 +18,26 @@ #include "test/global/TestEventQueue.h" #include "base/Log.h" -#include "base/TMethodEventJob.h" #include "base/SimpleEventQueueBuffer.h" +#include "base/TMethodEventJob.h" #include "common/stdexcept.h" -void -TestEventQueue::raiseQuitEvent() -{ - addEvent(Event(Event::kQuit)); +void TestEventQueue::raiseQuitEvent() { addEvent(Event(Event::kQuit)); } + +void TestEventQueue::initQuitTimeout(double timeout) { + assert(m_quitTimeoutTimer == nullptr); + m_quitTimeoutTimer = newOneShotTimer(timeout, NULL); + adoptHandler(Event::kTimer, m_quitTimeoutTimer, + new TMethodEventJob( + this, &TestEventQueue::handleQuitTimeout)); } -void -TestEventQueue::initQuitTimeout(double timeout) -{ - assert(m_quitTimeoutTimer == nullptr); - m_quitTimeoutTimer = newOneShotTimer(timeout, NULL); - adoptHandler(Event::kTimer, m_quitTimeoutTimer, - new TMethodEventJob( - this, &TestEventQueue::handleQuitTimeout)); +void TestEventQueue::cleanupQuitTimeout() { + removeHandler(Event::kTimer, m_quitTimeoutTimer); + delete m_quitTimeoutTimer; + m_quitTimeoutTimer = nullptr; } -void -TestEventQueue::cleanupQuitTimeout() -{ - removeHandler(Event::kTimer, m_quitTimeoutTimer); - delete m_quitTimeoutTimer; - m_quitTimeoutTimer = nullptr; -} - -void -TestEventQueue::handleQuitTimeout(const Event&, void* vclient) -{ - throw std::runtime_error("test event queue timeout"); +void TestEventQueue::handleQuitTimeout(const Event &, void *vclient) { + throw std::runtime_error("test event queue timeout"); } diff --git a/src/test/global/TestEventQueue.h b/src/test/global/TestEventQueue.h index 28a38758e..46fc6fb48 100644 --- a/src/test/global/TestEventQueue.h +++ b/src/test/global/TestEventQueue.h @@ -1,11 +1,11 @@ /* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2013-2016 Symless Ltd. - * + * * 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 LICENSE 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 @@ -23,16 +23,16 @@ class EventQueueTimer; class TestEventQueue : public EventQueue { public: - TestEventQueue() : m_quitTimeoutTimer(nullptr) { } + TestEventQueue() : m_quitTimeoutTimer(nullptr) {} - void handleQuitTimeout(const Event&, void* vclient); - void raiseQuitEvent(); - void initQuitTimeout(double timeout); - void cleanupQuitTimeout(); + void handleQuitTimeout(const Event &, void *vclient); + void raiseQuitEvent(); + void initQuitTimeout(double timeout); + void cleanupQuitTimeout(); private: - void timeoutThread(void*); + void timeoutThread(void *); private: - EventQueueTimer* m_quitTimeoutTimer; + EventQueueTimer *m_quitTimeoutTimer; }; diff --git a/src/test/global/gmock.h b/src/test/global/gmock.h index 5008c9b72..6a1072488 100644 --- a/src/test/global/gmock.h +++ b/src/test/global/gmock.h @@ -1,11 +1,11 @@ /* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2014-2016 Symless Ltd. - * + * * 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 LICENSE 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 @@ -22,7 +22,7 @@ // is that everything in the header file following this also has warnings // ignored, so we need to put it in a separate header file. #if __APPLE__ -# pragma GCC system_header +#pragma GCC system_header #endif // gmock includes gtest which has a warning on osx106 (signed/unsigned diff --git a/src/test/global/gtest.h b/src/test/global/gtest.h index 3c729eb0f..dbc9b7a09 100644 --- a/src/test/global/gtest.h +++ b/src/test/global/gtest.h @@ -1,11 +1,11 @@ /* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2014-2016 Symless Ltd. - * + * * 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 LICENSE 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 @@ -22,7 +22,7 @@ // is that everything in the header file following this also has warnings // ignored, so we need to put it in a separate header file. #if __APPLE__ -# pragma GCC system_header +#pragma GCC system_header #endif // gtest has a warning on osx106 (signed/unsigned int compare). diff --git a/src/test/guitests/src/VersionCheckerTests.cpp b/src/test/guitests/src/VersionCheckerTests.cpp index 350c3e906..df7190ae2 100644 --- a/src/test/guitests/src/VersionCheckerTests.cpp +++ b/src/test/guitests/src/VersionCheckerTests.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2012 Nick Bolton - * + * * 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 LICENSE 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 @@ -17,31 +17,30 @@ */ #include "VersionCheckerTests.h" -#include "VersionChecker.cpp" #include "../../gui/tmp/release/moc_VersionChecker.cpp" +#include "VersionChecker.cpp" #include -void VersionCheckerTests::compareVersions() -{ - VersionChecker versionChecker; +void VersionCheckerTests::compareVersions() { + VersionChecker versionChecker; - // compare majors - QCOMPARE(versionChecker.compareVersions("1.0.0", "2.0.0"), 1); - QCOMPARE(versionChecker.compareVersions("2.0.0", "1.0.0"), -1); - QCOMPARE(versionChecker.compareVersions("1.0.0", "1.0.0"), 0); - QCOMPARE(versionChecker.compareVersions("1.4.8", "2.4.7"), 1); - QCOMPARE(versionChecker.compareVersions("2.4.7", "1.4.8"), -1); + // compare majors + QCOMPARE(versionChecker.compareVersions("1.0.0", "2.0.0"), 1); + QCOMPARE(versionChecker.compareVersions("2.0.0", "1.0.0"), -1); + QCOMPARE(versionChecker.compareVersions("1.0.0", "1.0.0"), 0); + QCOMPARE(versionChecker.compareVersions("1.4.8", "2.4.7"), 1); + QCOMPARE(versionChecker.compareVersions("2.4.7", "1.4.8"), -1); - // compare minors - QCOMPARE(versionChecker.compareVersions("1.3.0", "1.4.0"), 1); - QCOMPARE(versionChecker.compareVersions("1.4.0", "1.3.0"), -1); - QCOMPARE(versionChecker.compareVersions("1.4.0", "1.4.0"), 0); - QCOMPARE(versionChecker.compareVersions("1.3.8", "1.4.7"), 1); - QCOMPARE(versionChecker.compareVersions("1.4.7", "1.3.8"), -1); + // compare minors + QCOMPARE(versionChecker.compareVersions("1.3.0", "1.4.0"), 1); + QCOMPARE(versionChecker.compareVersions("1.4.0", "1.3.0"), -1); + QCOMPARE(versionChecker.compareVersions("1.4.0", "1.4.0"), 0); + QCOMPARE(versionChecker.compareVersions("1.3.8", "1.4.7"), 1); + QCOMPARE(versionChecker.compareVersions("1.4.7", "1.3.8"), -1); - // compare revs - QCOMPARE(versionChecker.compareVersions("1.4.7", "1.4.8"), 1); - QCOMPARE(versionChecker.compareVersions("1.4.8", "1.4.7"), -1); - QCOMPARE(versionChecker.compareVersions("1.4.7", "1.4.7"), 0); + // compare revs + QCOMPARE(versionChecker.compareVersions("1.4.7", "1.4.8"), 1); + QCOMPARE(versionChecker.compareVersions("1.4.8", "1.4.7"), -1); + QCOMPARE(versionChecker.compareVersions("1.4.7", "1.4.7"), 0); } diff --git a/src/test/guitests/src/VersionCheckerTests.h b/src/test/guitests/src/VersionCheckerTests.h index 8d17af904..920b98e5f 100644 --- a/src/test/guitests/src/VersionCheckerTests.h +++ b/src/test/guitests/src/VersionCheckerTests.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2012 Nick Bolton - * + * * 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 LICENSE 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 @@ -20,9 +20,8 @@ #include "qobject.h" -class VersionCheckerTests : public QObject -{ - Q_OBJECT +class VersionCheckerTests : public QObject { + Q_OBJECT private slots: - void compareVersions(); + void compareVersions(); }; diff --git a/src/test/guitests/src/main.cpp b/src/test/guitests/src/main.cpp index 4ca2fb7fe..b10fa9237 100644 --- a/src/test/guitests/src/main.cpp +++ b/src/test/guitests/src/main.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2012 Nick Bolton - * + * * 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 LICENSE 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 @@ -16,11 +16,10 @@ * along with this program. If not, see . */ -#include #include "VersionCheckerTests.h" +#include -int main(int argc, char *argv[]) -{ - VersionCheckerTests versionCheckerTests; - QTest::qExec(&versionCheckerTests, argc, argv); +int main(int argc, char *argv[]) { + VersionCheckerTests versionCheckerTests; + QTest::qExec(&versionCheckerTests, argc, argv); } diff --git a/src/test/integtests/Main.cpp b/src/test/integtests/Main.cpp index 15598db24..f73d2736a 100644 --- a/src/test/integtests/Main.cpp +++ b/src/test/integtests/Main.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2011 Nick Bolton - * + * * 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 LICENSE 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 @@ -24,8 +24,8 @@ #endif #include "test/global/gtest.h" -#include #include +#include #define LOCK_TIMEOUT 30 @@ -34,40 +34,37 @@ using namespace std; void lock(string lockFile); void unlock(string lockFile); -int -main(int argc, char **argv) -{ +int main(int argc, char **argv) { #if SYSAPI_WIN32 - // record window instance for tray icon, etc - ArchMiscWindows::setInstanceWin32(GetModuleHandle(NULL)); + // record window instance for tray icon, etc + ArchMiscWindows::setInstanceWin32(GetModuleHandle(NULL)); #endif - Arch arch; - arch.init(); - - Log log; - log.setFilter(kDEBUG2); + Arch arch; + arch.init(); - string lockFile; - for (int i = 0; i < argc; i++) { - if (string(argv[i]).compare("--lock-file") == 0) { - lockFile = argv[i + 1]; - } + Log log; + log.setFilter(kDEBUG2); + + string lockFile; + for (int i = 0; i < argc; i++) { + if (string(argv[i]).compare("--lock-file") == 0) { + lockFile = argv[i + 1]; } + } - if (!lockFile.empty()) { - lock(lockFile); - } + if (!lockFile.empty()) { + lock(lockFile); + } + testing::InitGoogleTest(&argc, argv); - testing::InitGoogleTest(&argc, argv); + int result = RUN_ALL_TESTS(); - int result = RUN_ALL_TESTS(); + if (!lockFile.empty()) { + unlock(lockFile); + } - if (!lockFile.empty()) { - unlock(lockFile); - } - // gtest seems to randomly finish with error codes (e.g. -1, -1073741819) // even when no tests have failed. not sure what causes this, but it // happens on all platforms and keeps leading to false positives. @@ -76,33 +73,27 @@ main(int argc, char **argv) return (result == 1) ? 1 : 0; } -void -lock(string lockFile) -{ - double start = ARCH->time(); - - // keep checking until timeout is reached. - while ((ARCH->time() - start) < LOCK_TIMEOUT) { +void lock(string lockFile) { + double start = ARCH->time(); - ifstream is(lockFile.c_str()); - bool noLock = !is; - is.close(); + // keep checking until timeout is reached. + while ((ARCH->time() - start) < LOCK_TIMEOUT) { - if (noLock) { - break; - } + ifstream is(lockFile.c_str()); + bool noLock = !is; + is.close(); - // check every second if file has gone. - ARCH->sleep(1); + if (noLock) { + break; } - // write empty lock file. - ofstream os(lockFile.c_str()); - os.close(); + // check every second if file has gone. + ARCH->sleep(1); + } + + // write empty lock file. + ofstream os(lockFile.c_str()); + os.close(); } -void -unlock(string lockFile) -{ - remove(lockFile.c_str()); -} +void unlock(string lockFile) { remove(lockFile.c_str()); } diff --git a/src/test/integtests/ipc/IpcTests.cpp b/src/test/integtests/ipc/IpcTests.cpp index fc9ed8da6..44041f327 100644 --- a/src/test/integtests/ipc/IpcTests.cpp +++ b/src/test/integtests/ipc/IpcTests.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2012 Nick Bolton - * + * * 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 LICENSE 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 @@ -21,191 +21,175 @@ #define TEST_ENV -#include "test/global/TestEventQueue.h" -#include "ipc/IpcServer.h" -#include "ipc/IpcClient.h" -#include "ipc/IpcServerProxy.h" -#include "ipc/IpcMessage.h" -#include "ipc/IpcClientProxy.h" -#include "ipc/Ipc.h" -#include "net/SocketMultiplexer.h" -#include "mt/Thread.h" #include "arch/Arch.h" -#include "base/TMethodJob.h" -#include "base/String.h" -#include "base/Log.h" #include "base/EventQueue.h" +#include "base/Log.h" +#include "base/String.h" #include "base/TMethodEventJob.h" +#include "base/TMethodJob.h" +#include "ipc/Ipc.h" +#include "ipc/IpcClient.h" +#include "ipc/IpcClientProxy.h" +#include "ipc/IpcMessage.h" +#include "ipc/IpcServer.h" +#include "ipc/IpcServerProxy.h" +#include "mt/Thread.h" +#include "net/SocketMultiplexer.h" +#include "test/global/TestEventQueue.h" #include "test/global/gtest.h" #define TEST_IPC_PORT 24802 -class IpcTests : public ::testing::Test -{ +class IpcTests : public ::testing::Test { public: - IpcTests(); - virtual ~IpcTests(); - - void connectToServer_handleMessageReceived(const Event&, void*); - void sendMessageToServer_serverHandleMessageReceived(const Event&, void*); - void sendMessageToClient_serverHandleClientConnected(const Event&, void*); - void sendMessageToClient_clientHandleMessageReceived(const Event&, void*); + IpcTests(); + virtual ~IpcTests(); + + void connectToServer_handleMessageReceived(const Event &, void *); + void sendMessageToServer_serverHandleMessageReceived(const Event &, void *); + void sendMessageToClient_serverHandleClientConnected(const Event &, void *); + void sendMessageToClient_clientHandleMessageReceived(const Event &, void *); public: - SocketMultiplexer m_multiplexer; - bool m_connectToServer_helloMessageReceived; - bool m_connectToServer_hasClientNode; - IpcServer* m_connectToServer_server; - String m_sendMessageToServer_receivedString; - String m_sendMessageToClient_receivedString; - IpcClient* m_sendMessageToServer_client; - IpcServer* m_sendMessageToClient_server; - TestEventQueue m_events; - + SocketMultiplexer m_multiplexer; + bool m_connectToServer_helloMessageReceived; + bool m_connectToServer_hasClientNode; + IpcServer *m_connectToServer_server; + String m_sendMessageToServer_receivedString; + String m_sendMessageToClient_receivedString; + IpcClient *m_sendMessageToServer_client; + IpcServer *m_sendMessageToClient_server; + TestEventQueue m_events; }; -TEST_F(IpcTests, connectToServer) -{ - SocketMultiplexer socketMultiplexer; - IpcServer server(&m_events, &socketMultiplexer, TEST_IPC_PORT); - server.listen(); - m_connectToServer_server = &server; +TEST_F(IpcTests, connectToServer) { + SocketMultiplexer socketMultiplexer; + IpcServer server(&m_events, &socketMultiplexer, TEST_IPC_PORT); + server.listen(); + m_connectToServer_server = &server; - m_events.adoptHandler( - m_events.forIpcServer().messageReceived(), &server, - new TMethodEventJob( - this, &IpcTests::connectToServer_handleMessageReceived)); - - IpcClient client(&m_events, &socketMultiplexer, TEST_IPC_PORT); - client.connect(); - - m_events.initQuitTimeout(5); - m_events.loop(); - m_events.removeHandler(m_events.forIpcServer().messageReceived(), &server); - m_events.cleanupQuitTimeout(); - - EXPECT_EQ(true, m_connectToServer_helloMessageReceived); - EXPECT_EQ(true, m_connectToServer_hasClientNode); + m_events.adoptHandler( + m_events.forIpcServer().messageReceived(), &server, + new TMethodEventJob( + this, &IpcTests::connectToServer_handleMessageReceived)); + + IpcClient client(&m_events, &socketMultiplexer, TEST_IPC_PORT); + client.connect(); + + m_events.initQuitTimeout(5); + m_events.loop(); + m_events.removeHandler(m_events.forIpcServer().messageReceived(), &server); + m_events.cleanupQuitTimeout(); + + EXPECT_EQ(true, m_connectToServer_helloMessageReceived); + EXPECT_EQ(true, m_connectToServer_hasClientNode); } -TEST_F(IpcTests, sendMessageToServer) -{ - SocketMultiplexer socketMultiplexer; - IpcServer server(&m_events, &socketMultiplexer, TEST_IPC_PORT); - server.listen(); - - // event handler sends "test" command to server. - m_events.adoptHandler( - m_events.forIpcServer().messageReceived(), &server, - new TMethodEventJob( - this, &IpcTests::sendMessageToServer_serverHandleMessageReceived)); - - IpcClient client(&m_events, &socketMultiplexer, TEST_IPC_PORT); - client.connect(); - m_sendMessageToServer_client = &client; +TEST_F(IpcTests, sendMessageToServer) { + SocketMultiplexer socketMultiplexer; + IpcServer server(&m_events, &socketMultiplexer, TEST_IPC_PORT); + server.listen(); - m_events.initQuitTimeout(5); - m_events.loop(); - m_events.removeHandler(m_events.forIpcServer().messageReceived(), &server); - m_events.cleanupQuitTimeout(); + // event handler sends "test" command to server. + m_events.adoptHandler( + m_events.forIpcServer().messageReceived(), &server, + new TMethodEventJob( + this, &IpcTests::sendMessageToServer_serverHandleMessageReceived)); - EXPECT_EQ("test", m_sendMessageToServer_receivedString); + IpcClient client(&m_events, &socketMultiplexer, TEST_IPC_PORT); + client.connect(); + m_sendMessageToServer_client = &client; + + m_events.initQuitTimeout(5); + m_events.loop(); + m_events.removeHandler(m_events.forIpcServer().messageReceived(), &server); + m_events.cleanupQuitTimeout(); + + EXPECT_EQ("test", m_sendMessageToServer_receivedString); } -TEST_F(IpcTests, sendMessageToClient) -{ - SocketMultiplexer socketMultiplexer; - IpcServer server(&m_events, &socketMultiplexer, TEST_IPC_PORT); - server.listen(); - m_sendMessageToClient_server = &server; +TEST_F(IpcTests, sendMessageToClient) { + SocketMultiplexer socketMultiplexer; + IpcServer server(&m_events, &socketMultiplexer, TEST_IPC_PORT); + server.listen(); + m_sendMessageToClient_server = &server; - // event handler sends "test" log line to client. - m_events.adoptHandler( - m_events.forIpcServer().messageReceived(), &server, - new TMethodEventJob( - this, &IpcTests::sendMessageToClient_serverHandleClientConnected)); + // event handler sends "test" log line to client. + m_events.adoptHandler( + m_events.forIpcServer().messageReceived(), &server, + new TMethodEventJob( + this, &IpcTests::sendMessageToClient_serverHandleClientConnected)); - IpcClient client(&m_events, &socketMultiplexer, TEST_IPC_PORT); - client.connect(); - - m_events.adoptHandler( - m_events.forIpcClient().messageReceived(), &client, - new TMethodEventJob( - this, &IpcTests::sendMessageToClient_clientHandleMessageReceived)); + IpcClient client(&m_events, &socketMultiplexer, TEST_IPC_PORT); + client.connect(); - m_events.initQuitTimeout(5); - m_events.loop(); - m_events.removeHandler(m_events.forIpcServer().messageReceived(), &server); - m_events.removeHandler(m_events.forIpcClient().messageReceived(), &client); - m_events.cleanupQuitTimeout(); + m_events.adoptHandler( + m_events.forIpcClient().messageReceived(), &client, + new TMethodEventJob( + this, &IpcTests::sendMessageToClient_clientHandleMessageReceived)); - EXPECT_EQ("test", m_sendMessageToClient_receivedString); + m_events.initQuitTimeout(5); + m_events.loop(); + m_events.removeHandler(m_events.forIpcServer().messageReceived(), &server); + m_events.removeHandler(m_events.forIpcClient().messageReceived(), &client); + m_events.cleanupQuitTimeout(); + + EXPECT_EQ("test", m_sendMessageToClient_receivedString); } -IpcTests::IpcTests() : -m_connectToServer_helloMessageReceived(false), -m_connectToServer_hasClientNode(false), -m_connectToServer_server(nullptr), -m_sendMessageToClient_server(nullptr), -m_sendMessageToServer_client(nullptr) -{ +IpcTests::IpcTests() + : m_connectToServer_helloMessageReceived(false), + m_connectToServer_hasClientNode(false), m_connectToServer_server(nullptr), + m_sendMessageToClient_server(nullptr), + m_sendMessageToServer_client(nullptr) {} + +IpcTests::~IpcTests() {} + +void IpcTests::connectToServer_handleMessageReceived(const Event &e, void *) { + IpcMessage *m = static_cast(e.getDataObject()); + if (m->type() == kIpcHello) { + m_connectToServer_hasClientNode = + m_connectToServer_server->hasClients(kIpcClientNode); + m_connectToServer_helloMessageReceived = true; + m_events.raiseQuitEvent(); + } } -IpcTests::~IpcTests() -{ +void IpcTests::sendMessageToServer_serverHandleMessageReceived(const Event &e, + void *) { + IpcMessage *m = static_cast(e.getDataObject()); + if (m->type() == kIpcHello) { + LOG((CLOG_DEBUG "client said hello, sending test to server")); + IpcCommandMessage m("test", true); + m_sendMessageToServer_client->send(m); + } else if (m->type() == kIpcCommand) { + IpcCommandMessage *cm = static_cast(m); + LOG((CLOG_DEBUG "got ipc command message, %d", cm->command().c_str())); + m_sendMessageToServer_receivedString = cm->command(); + m_events.raiseQuitEvent(); + } } -void -IpcTests::connectToServer_handleMessageReceived(const Event& e, void*) -{ - IpcMessage* m = static_cast(e.getDataObject()); - if (m->type() == kIpcHello) { - m_connectToServer_hasClientNode = - m_connectToServer_server->hasClients(kIpcClientNode); - m_connectToServer_helloMessageReceived = true; - m_events.raiseQuitEvent(); - } +void IpcTests::sendMessageToClient_serverHandleClientConnected(const Event &e, + void *) { + IpcMessage *m = static_cast(e.getDataObject()); + if (m->type() == kIpcHello) { + LOG((CLOG_DEBUG "client said hello, sending test to client")); + IpcLogLineMessage m("test"); + m_sendMessageToClient_server->send(m, kIpcClientNode); + } } -void -IpcTests::sendMessageToServer_serverHandleMessageReceived(const Event& e, void*) -{ - IpcMessage* m = static_cast(e.getDataObject()); - if (m->type() == kIpcHello) { - LOG((CLOG_DEBUG "client said hello, sending test to server")); - IpcCommandMessage m("test", true); - m_sendMessageToServer_client->send(m); - } - else if (m->type() == kIpcCommand) { - IpcCommandMessage* cm = static_cast(m); - LOG((CLOG_DEBUG "got ipc command message, %d", cm->command().c_str())); - m_sendMessageToServer_receivedString = cm->command(); - m_events.raiseQuitEvent(); - } -} - -void -IpcTests::sendMessageToClient_serverHandleClientConnected(const Event& e, void*) -{ - IpcMessage* m = static_cast(e.getDataObject()); - if (m->type() == kIpcHello) { - LOG((CLOG_DEBUG "client said hello, sending test to client")); - IpcLogLineMessage m("test"); - m_sendMessageToClient_server->send(m, kIpcClientNode); - } -} - -void -IpcTests::sendMessageToClient_clientHandleMessageReceived(const Event& e, void*) -{ - IpcMessage* m = static_cast(e.getDataObject()); - if (m->type() == kIpcLogLine) { - IpcLogLineMessage* llm = static_cast(m); - LOG((CLOG_DEBUG "got ipc log message, %d", llm->logLine().c_str())); - m_sendMessageToClient_receivedString = llm->logLine(); - m_events.raiseQuitEvent(); - } +void IpcTests::sendMessageToClient_clientHandleMessageReceived(const Event &e, + void *) { + IpcMessage *m = static_cast(e.getDataObject()); + if (m->type() == kIpcLogLine) { + IpcLogLineMessage *llm = static_cast(m); + LOG((CLOG_DEBUG "got ipc log message, %d", llm->logLine().c_str())); + m_sendMessageToClient_receivedString = llm->logLine(); + m_events.raiseQuitEvent(); + } } #endif // WINAPI_CARBON diff --git a/src/test/integtests/net/NetworkTests.cpp b/src/test/integtests/net/NetworkTests.cpp index 936214a4e..156ad339b 100644 --- a/src/test/integtests/net/NetworkTests.cpp +++ b/src/test/integtests/net/NetworkTests.cpp @@ -1,11 +1,11 @@ /* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2013-2016 Symless Ltd. - * + * * 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 LICENSE 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 @@ -20,506 +20,510 @@ #define TEST_ENV -#include "test/mock/server/MockConfig.h" -#include "test/mock/server/MockPrimaryClient.h" -#include "test/mock/synergy/MockScreen.h" -#include "test/mock/server/MockInputFilter.h" -#include "test/global/TestEventQueue.h" -#include "server/Server.h" -#include "server/ClientListener.h" -#include "server/ClientProxy.h" -#include "client/Client.h" -#include "synergy/FileChunk.h" -#include "synergy/StreamChunker.h" -#include "net/SocketMultiplexer.h" -#include "net/NetworkAddress.h" -#include "net/TCPSocketFactory.h" -#include "mt/Thread.h" +#include "base/Log.h" #include "base/TMethodEventJob.h" #include "base/TMethodJob.h" -#include "base/Log.h" +#include "client/Client.h" #include "common/stdexcept.h" +#include "mt/Thread.h" +#include "net/NetworkAddress.h" +#include "net/SocketMultiplexer.h" +#include "net/TCPSocketFactory.h" +#include "server/ClientListener.h" +#include "server/ClientProxy.h" +#include "server/Server.h" +#include "synergy/FileChunk.h" +#include "synergy/StreamChunker.h" +#include "test/global/TestEventQueue.h" +#include "test/mock/server/MockConfig.h" +#include "test/mock/server/MockInputFilter.h" +#include "test/mock/server/MockPrimaryClient.h" +#include "test/mock/synergy/MockScreen.h" #include "test/global/gtest.h" -#include #include #include +#include #include using namespace std; using ::testing::_; +using ::testing::Invoke; using ::testing::NiceMock; using ::testing::Return; -using ::testing::Invoke; #define TEST_PORT 24803 #define TEST_HOST "localhost" const size_t kMockDataSize = 1024 * 1024 * 10; // 10MB -const UInt16 kMockDataChunkIncrement = 1024; // 1KB -const char* kMockFilename = "NetworkTests.mock"; +const UInt16 kMockDataChunkIncrement = 1024; // 1KB +const char *kMockFilename = "NetworkTests.mock"; const size_t kMockFileSize = 1024 * 1024 * 10; // 10MB -void getScreenShape(SInt32& x, SInt32& y, SInt32& w, SInt32& h); -void getCursorPos(SInt32& x, SInt32& y); -UInt8* newMockData(size_t size); -void createFile(fstream& file, const char* filename, size_t size); +void getScreenShape(SInt32 &x, SInt32 &y, SInt32 &w, SInt32 &h); +void getCursorPos(SInt32 &x, SInt32 &y); +UInt8 *newMockData(size_t size); +void createFile(fstream &file, const char *filename, size_t size); -class NetworkTests : public ::testing::Test -{ +class NetworkTests : public ::testing::Test { public: - NetworkTests() : - m_mockData(NULL), - m_mockDataSize(0), - m_mockFileSize(0) - { - m_mockData = newMockData(kMockDataSize); - createFile(m_mockFile, kMockFilename, kMockFileSize); - } + NetworkTests() : m_mockData(NULL), m_mockDataSize(0), m_mockFileSize(0) { + m_mockData = newMockData(kMockDataSize); + createFile(m_mockFile, kMockFilename, kMockFileSize); + } - ~NetworkTests() - { - remove(kMockFilename); - delete[] m_mockData; - } + ~NetworkTests() { + remove(kMockFilename); + delete[] m_mockData; + } - void sendMockData(void* eventTarget); - - void sendToClient_mockData_handleClientConnected(const Event&, void* vlistener); - void sendToClient_mockData_fileRecieveCompleted(const Event&, void*); - - void sendToClient_mockFile_handleClientConnected(const Event&, void* vlistener); - void sendToClient_mockFile_fileRecieveCompleted(const Event& event, void*); - - void sendToServer_mockData_handleClientConnected(const Event&, void* vlistener); - void sendToServer_mockData_fileRecieveCompleted(const Event& event, void*); + void sendMockData(void *eventTarget); + + void sendToClient_mockData_handleClientConnected(const Event &, + void *vlistener); + void sendToClient_mockData_fileRecieveCompleted(const Event &, void *); + + void sendToClient_mockFile_handleClientConnected(const Event &, + void *vlistener); + void sendToClient_mockFile_fileRecieveCompleted(const Event &event, void *); + + void sendToServer_mockData_handleClientConnected(const Event &, + void *vlistener); + void sendToServer_mockData_fileRecieveCompleted(const Event &event, void *); + + void sendToServer_mockFile_handleClientConnected(const Event &, + void *vlistener); + void sendToServer_mockFile_fileRecieveCompleted(const Event &event, void *); - void sendToServer_mockFile_handleClientConnected(const Event&, void* vlistener); - void sendToServer_mockFile_fileRecieveCompleted(const Event& event, void*); - public: - TestEventQueue m_events; - UInt8* m_mockData; - size_t m_mockDataSize; - fstream m_mockFile; - size_t m_mockFileSize; + TestEventQueue m_events; + UInt8 *m_mockData; + size_t m_mockDataSize; + fstream m_mockFile; + size_t m_mockFileSize; }; -TEST_F(NetworkTests, sendToClient_mockData) -{ - // server and client - NetworkAddress serverAddress(TEST_HOST, TEST_PORT); +TEST_F(NetworkTests, sendToClient_mockData) { + // server and client + NetworkAddress serverAddress(TEST_HOST, TEST_PORT); - serverAddress.resolve(); - - // server - SocketMultiplexer serverSocketMultiplexer; - TCPSocketFactory* serverSocketFactory = new TCPSocketFactory(&m_events, &serverSocketMultiplexer); - ClientListener listener(serverAddress, serverSocketFactory, &m_events, false); - NiceMock serverScreen; - NiceMock primaryClient; - NiceMock serverConfig; - NiceMock serverInputFilter; - - m_events.adoptHandler( - m_events.forClientListener().connected(), &listener, - new TMethodEventJob( - this, &NetworkTests::sendToClient_mockData_handleClientConnected, &listener)); + serverAddress.resolve(); - ON_CALL(serverConfig, isScreen(_)).WillByDefault(Return(true)); - ON_CALL(serverConfig, getInputFilter()).WillByDefault(Return(&serverInputFilter)); + // server + SocketMultiplexer serverSocketMultiplexer; + TCPSocketFactory *serverSocketFactory = + new TCPSocketFactory(&m_events, &serverSocketMultiplexer); + ClientListener listener(serverAddress, serverSocketFactory, &m_events, false); + NiceMock serverScreen; + NiceMock primaryClient; + NiceMock serverConfig; + NiceMock serverInputFilter; - lib::synergy::ServerArgs serverArgs; - serverArgs.m_enableDragDrop = true; - Server server(serverConfig, &primaryClient, &serverScreen, &m_events, serverArgs); - server.m_mock = true; - listener.setServer(&server); + m_events.adoptHandler( + m_events.forClientListener().connected(), &listener, + new TMethodEventJob( + this, &NetworkTests::sendToClient_mockData_handleClientConnected, + &listener)); - // client - NiceMock clientScreen; - SocketMultiplexer clientSocketMultiplexer; - TCPSocketFactory* clientSocketFactory = new TCPSocketFactory(&m_events, &clientSocketMultiplexer); - - ON_CALL(clientScreen, getShape(_, _, _, _)).WillByDefault(Invoke(getScreenShape)); - ON_CALL(clientScreen, getCursorPos(_, _)).WillByDefault(Invoke(getCursorPos)); + ON_CALL(serverConfig, isScreen(_)).WillByDefault(Return(true)); + ON_CALL(serverConfig, getInputFilter()) + .WillByDefault(Return(&serverInputFilter)); + lib::synergy::ServerArgs serverArgs; + serverArgs.m_enableDragDrop = true; + Server server(serverConfig, &primaryClient, &serverScreen, &m_events, + serverArgs); + server.m_mock = true; + listener.setServer(&server); - lib::synergy::ClientArgs clientArgs; - clientArgs.m_enableDragDrop = true; - clientArgs.m_enableCrypto = false; - Client client(&m_events, "stub", serverAddress, clientSocketFactory, &clientScreen, clientArgs); - - m_events.adoptHandler( - m_events.forFile().fileRecieveCompleted(), &client, - new TMethodEventJob( - this, &NetworkTests::sendToClient_mockData_fileRecieveCompleted)); + // client + NiceMock clientScreen; + SocketMultiplexer clientSocketMultiplexer; + TCPSocketFactory *clientSocketFactory = + new TCPSocketFactory(&m_events, &clientSocketMultiplexer); - client.connect(); + ON_CALL(clientScreen, getShape(_, _, _, _)) + .WillByDefault(Invoke(getScreenShape)); + ON_CALL(clientScreen, getCursorPos(_, _)).WillByDefault(Invoke(getCursorPos)); - m_events.initQuitTimeout(10); - m_events.loop(); - m_events.removeHandler(m_events.forClientListener().connected(), &listener); - m_events.removeHandler(m_events.forFile().fileRecieveCompleted(), &client); - m_events.cleanupQuitTimeout(); + lib::synergy::ClientArgs clientArgs; + clientArgs.m_enableDragDrop = true; + clientArgs.m_enableCrypto = false; + Client client(&m_events, "stub", serverAddress, clientSocketFactory, + &clientScreen, clientArgs); + + m_events.adoptHandler( + m_events.forFile().fileRecieveCompleted(), &client, + new TMethodEventJob( + this, &NetworkTests::sendToClient_mockData_fileRecieveCompleted)); + + client.connect(); + + m_events.initQuitTimeout(10); + m_events.loop(); + m_events.removeHandler(m_events.forClientListener().connected(), &listener); + m_events.removeHandler(m_events.forFile().fileRecieveCompleted(), &client); + m_events.cleanupQuitTimeout(); } -TEST_F(NetworkTests, sendToClient_mockFile) -{ - // server and client - NetworkAddress serverAddress(TEST_HOST, TEST_PORT); +TEST_F(NetworkTests, sendToClient_mockFile) { + // server and client + NetworkAddress serverAddress(TEST_HOST, TEST_PORT); - serverAddress.resolve(); - - // server - SocketMultiplexer serverSocketMultiplexer; - TCPSocketFactory* serverSocketFactory = new TCPSocketFactory(&m_events, &serverSocketMultiplexer); - ClientListener listener(serverAddress, serverSocketFactory, &m_events, false); - NiceMock serverScreen; - NiceMock primaryClient; - NiceMock serverConfig; - NiceMock serverInputFilter; - - m_events.adoptHandler( - m_events.forClientListener().connected(), &listener, - new TMethodEventJob( - this, &NetworkTests::sendToClient_mockFile_handleClientConnected, &listener)); + serverAddress.resolve(); - ON_CALL(serverConfig, isScreen(_)).WillByDefault(Return(true)); - ON_CALL(serverConfig, getInputFilter()).WillByDefault(Return(&serverInputFilter)); + // server + SocketMultiplexer serverSocketMultiplexer; + TCPSocketFactory *serverSocketFactory = + new TCPSocketFactory(&m_events, &serverSocketMultiplexer); + ClientListener listener(serverAddress, serverSocketFactory, &m_events, false); + NiceMock serverScreen; + NiceMock primaryClient; + NiceMock serverConfig; + NiceMock serverInputFilter; - lib::synergy::ServerArgs serverArgs; - serverArgs.m_enableDragDrop = true; - Server server(serverConfig, &primaryClient, &serverScreen, &m_events, serverArgs); - server.m_mock = true; - listener.setServer(&server); + m_events.adoptHandler( + m_events.forClientListener().connected(), &listener, + new TMethodEventJob( + this, &NetworkTests::sendToClient_mockFile_handleClientConnected, + &listener)); - // client - NiceMock clientScreen; - SocketMultiplexer clientSocketMultiplexer; - TCPSocketFactory* clientSocketFactory = new TCPSocketFactory(&m_events, &clientSocketMultiplexer); - - ON_CALL(clientScreen, getShape(_, _, _, _)).WillByDefault(Invoke(getScreenShape)); - ON_CALL(clientScreen, getCursorPos(_, _)).WillByDefault(Invoke(getCursorPos)); + ON_CALL(serverConfig, isScreen(_)).WillByDefault(Return(true)); + ON_CALL(serverConfig, getInputFilter()) + .WillByDefault(Return(&serverInputFilter)); + lib::synergy::ServerArgs serverArgs; + serverArgs.m_enableDragDrop = true; + Server server(serverConfig, &primaryClient, &serverScreen, &m_events, + serverArgs); + server.m_mock = true; + listener.setServer(&server); - lib::synergy::ClientArgs clientArgs; - clientArgs.m_enableDragDrop = true; - clientArgs.m_enableCrypto = false; - Client client(&m_events, "stub", serverAddress, clientSocketFactory, &clientScreen, clientArgs); - - m_events.adoptHandler( - m_events.forFile().fileRecieveCompleted(), &client, - new TMethodEventJob( - this, &NetworkTests::sendToClient_mockFile_fileRecieveCompleted)); + // client + NiceMock clientScreen; + SocketMultiplexer clientSocketMultiplexer; + TCPSocketFactory *clientSocketFactory = + new TCPSocketFactory(&m_events, &clientSocketMultiplexer); - client.connect(); + ON_CALL(clientScreen, getShape(_, _, _, _)) + .WillByDefault(Invoke(getScreenShape)); + ON_CALL(clientScreen, getCursorPos(_, _)).WillByDefault(Invoke(getCursorPos)); - m_events.initQuitTimeout(10); - m_events.loop(); - m_events.removeHandler(m_events.forClientListener().connected(), &listener); - m_events.removeHandler(m_events.forFile().fileRecieveCompleted(), &client); - m_events.cleanupQuitTimeout(); + lib::synergy::ClientArgs clientArgs; + clientArgs.m_enableDragDrop = true; + clientArgs.m_enableCrypto = false; + Client client(&m_events, "stub", serverAddress, clientSocketFactory, + &clientScreen, clientArgs); + + m_events.adoptHandler( + m_events.forFile().fileRecieveCompleted(), &client, + new TMethodEventJob( + this, &NetworkTests::sendToClient_mockFile_fileRecieveCompleted)); + + client.connect(); + + m_events.initQuitTimeout(10); + m_events.loop(); + m_events.removeHandler(m_events.forClientListener().connected(), &listener); + m_events.removeHandler(m_events.forFile().fileRecieveCompleted(), &client); + m_events.cleanupQuitTimeout(); } -TEST_F(NetworkTests, sendToServer_mockData) -{ - // server and client - NetworkAddress serverAddress(TEST_HOST, TEST_PORT); - serverAddress.resolve(); +TEST_F(NetworkTests, sendToServer_mockData) { + // server and client + NetworkAddress serverAddress(TEST_HOST, TEST_PORT); + serverAddress.resolve(); - // server - SocketMultiplexer serverSocketMultiplexer; - TCPSocketFactory* serverSocketFactory = new TCPSocketFactory(&m_events, &serverSocketMultiplexer); - ClientListener listener(serverAddress, serverSocketFactory, &m_events, false); - NiceMock serverScreen; - NiceMock primaryClient; - NiceMock serverConfig; - NiceMock serverInputFilter; + // server + SocketMultiplexer serverSocketMultiplexer; + TCPSocketFactory *serverSocketFactory = + new TCPSocketFactory(&m_events, &serverSocketMultiplexer); + ClientListener listener(serverAddress, serverSocketFactory, &m_events, false); + NiceMock serverScreen; + NiceMock primaryClient; + NiceMock serverConfig; + NiceMock serverInputFilter; - ON_CALL(serverConfig, isScreen(_)).WillByDefault(Return(true)); - ON_CALL(serverConfig, getInputFilter()).WillByDefault(Return(&serverInputFilter)); + ON_CALL(serverConfig, isScreen(_)).WillByDefault(Return(true)); + ON_CALL(serverConfig, getInputFilter()) + .WillByDefault(Return(&serverInputFilter)); - lib::synergy::ServerArgs serverArgs; - serverArgs.m_enableDragDrop = true; - Server server(serverConfig, &primaryClient, &serverScreen, &m_events, serverArgs); - server.m_mock = true; - listener.setServer(&server); + lib::synergy::ServerArgs serverArgs; + serverArgs.m_enableDragDrop = true; + Server server(serverConfig, &primaryClient, &serverScreen, &m_events, + serverArgs); + server.m_mock = true; + listener.setServer(&server); - // client - NiceMock clientScreen; - SocketMultiplexer clientSocketMultiplexer; - TCPSocketFactory* clientSocketFactory = new TCPSocketFactory(&m_events, &clientSocketMultiplexer); - - ON_CALL(clientScreen, getShape(_, _, _, _)).WillByDefault(Invoke(getScreenShape)); - ON_CALL(clientScreen, getCursorPos(_, _)).WillByDefault(Invoke(getCursorPos)); + // client + NiceMock clientScreen; + SocketMultiplexer clientSocketMultiplexer; + TCPSocketFactory *clientSocketFactory = + new TCPSocketFactory(&m_events, &clientSocketMultiplexer); - lib::synergy::ClientArgs clientArgs; - clientArgs.m_enableDragDrop = true; - clientArgs.m_enableCrypto = false; - Client client(&m_events, "stub", serverAddress, clientSocketFactory, &clientScreen, clientArgs); - - m_events.adoptHandler( - m_events.forClientListener().connected(), &listener, - new TMethodEventJob( - this, &NetworkTests::sendToServer_mockData_handleClientConnected, &client)); + ON_CALL(clientScreen, getShape(_, _, _, _)) + .WillByDefault(Invoke(getScreenShape)); + ON_CALL(clientScreen, getCursorPos(_, _)).WillByDefault(Invoke(getCursorPos)); - m_events.adoptHandler( - m_events.forFile().fileRecieveCompleted(), &server, - new TMethodEventJob( - this, &NetworkTests::sendToServer_mockData_fileRecieveCompleted)); + lib::synergy::ClientArgs clientArgs; + clientArgs.m_enableDragDrop = true; + clientArgs.m_enableCrypto = false; + Client client(&m_events, "stub", serverAddress, clientSocketFactory, + &clientScreen, clientArgs); - client.connect(); + m_events.adoptHandler( + m_events.forClientListener().connected(), &listener, + new TMethodEventJob( + this, &NetworkTests::sendToServer_mockData_handleClientConnected, + &client)); - m_events.initQuitTimeout(10); - m_events.loop(); - m_events.removeHandler(m_events.forClientListener().connected(), &listener); - m_events.removeHandler(m_events.forFile().fileRecieveCompleted(), &server); - m_events.cleanupQuitTimeout(); + m_events.adoptHandler( + m_events.forFile().fileRecieveCompleted(), &server, + new TMethodEventJob( + this, &NetworkTests::sendToServer_mockData_fileRecieveCompleted)); + + client.connect(); + + m_events.initQuitTimeout(10); + m_events.loop(); + m_events.removeHandler(m_events.forClientListener().connected(), &listener); + m_events.removeHandler(m_events.forFile().fileRecieveCompleted(), &server); + m_events.cleanupQuitTimeout(); } -TEST_F(NetworkTests, sendToServer_mockFile) -{ - // server and client - NetworkAddress serverAddress(TEST_HOST, TEST_PORT); +TEST_F(NetworkTests, sendToServer_mockFile) { + // server and client + NetworkAddress serverAddress(TEST_HOST, TEST_PORT); - serverAddress.resolve(); + serverAddress.resolve(); - // server - SocketMultiplexer serverSocketMultiplexer; - TCPSocketFactory* serverSocketFactory = new TCPSocketFactory(&m_events, &serverSocketMultiplexer); - ClientListener listener(serverAddress, serverSocketFactory, &m_events, false); - NiceMock serverScreen; - NiceMock primaryClient; - NiceMock serverConfig; - NiceMock serverInputFilter; + // server + SocketMultiplexer serverSocketMultiplexer; + TCPSocketFactory *serverSocketFactory = + new TCPSocketFactory(&m_events, &serverSocketMultiplexer); + ClientListener listener(serverAddress, serverSocketFactory, &m_events, false); + NiceMock serverScreen; + NiceMock primaryClient; + NiceMock serverConfig; + NiceMock serverInputFilter; - ON_CALL(serverConfig, isScreen(_)).WillByDefault(Return(true)); - ON_CALL(serverConfig, getInputFilter()).WillByDefault(Return(&serverInputFilter)); + ON_CALL(serverConfig, isScreen(_)).WillByDefault(Return(true)); + ON_CALL(serverConfig, getInputFilter()) + .WillByDefault(Return(&serverInputFilter)); - lib::synergy::ServerArgs serverArgs; - serverArgs.m_enableDragDrop = true; - Server server(serverConfig, &primaryClient, &serverScreen, &m_events, serverArgs); - server.m_mock = true; - listener.setServer(&server); + lib::synergy::ServerArgs serverArgs; + serverArgs.m_enableDragDrop = true; + Server server(serverConfig, &primaryClient, &serverScreen, &m_events, + serverArgs); + server.m_mock = true; + listener.setServer(&server); - // client - NiceMock clientScreen; - SocketMultiplexer clientSocketMultiplexer; - TCPSocketFactory* clientSocketFactory = new TCPSocketFactory(&m_events, &clientSocketMultiplexer); - - ON_CALL(clientScreen, getShape(_, _, _, _)).WillByDefault(Invoke(getScreenShape)); - ON_CALL(clientScreen, getCursorPos(_, _)).WillByDefault(Invoke(getCursorPos)); + // client + NiceMock clientScreen; + SocketMultiplexer clientSocketMultiplexer; + TCPSocketFactory *clientSocketFactory = + new TCPSocketFactory(&m_events, &clientSocketMultiplexer); - lib::synergy::ClientArgs clientArgs; - clientArgs.m_enableDragDrop = true; - clientArgs.m_enableCrypto = false; - Client client(&m_events, "stub", serverAddress, clientSocketFactory, &clientScreen, clientArgs); + ON_CALL(clientScreen, getShape(_, _, _, _)) + .WillByDefault(Invoke(getScreenShape)); + ON_CALL(clientScreen, getCursorPos(_, _)).WillByDefault(Invoke(getCursorPos)); - m_events.adoptHandler( - m_events.forClientListener().connected(), &listener, - new TMethodEventJob( - this, &NetworkTests::sendToServer_mockFile_handleClientConnected, &client)); + lib::synergy::ClientArgs clientArgs; + clientArgs.m_enableDragDrop = true; + clientArgs.m_enableCrypto = false; + Client client(&m_events, "stub", serverAddress, clientSocketFactory, + &clientScreen, clientArgs); - m_events.adoptHandler( - m_events.forFile().fileRecieveCompleted(), &server, - new TMethodEventJob( - this, &NetworkTests::sendToServer_mockFile_fileRecieveCompleted)); + m_events.adoptHandler( + m_events.forClientListener().connected(), &listener, + new TMethodEventJob( + this, &NetworkTests::sendToServer_mockFile_handleClientConnected, + &client)); - client.connect(); + m_events.adoptHandler( + m_events.forFile().fileRecieveCompleted(), &server, + new TMethodEventJob( + this, &NetworkTests::sendToServer_mockFile_fileRecieveCompleted)); - m_events.initQuitTimeout(10); - m_events.loop(); - m_events.removeHandler(m_events.forClientListener().connected(), &listener); - m_events.removeHandler(m_events.forFile().fileRecieveCompleted(), &server); - m_events.cleanupQuitTimeout(); + client.connect(); + + m_events.initQuitTimeout(10); + m_events.loop(); + m_events.removeHandler(m_events.forClientListener().connected(), &listener); + m_events.removeHandler(m_events.forFile().fileRecieveCompleted(), &server); + m_events.cleanupQuitTimeout(); } -void -NetworkTests::sendToClient_mockData_handleClientConnected(const Event&, void* vlistener) -{ - ClientListener* listener = static_cast(vlistener); - Server* server = listener->getServer(); +void NetworkTests::sendToClient_mockData_handleClientConnected( + const Event &, void *vlistener) { + ClientListener *listener = static_cast(vlistener); + Server *server = listener->getServer(); - ClientProxy* client = listener->getNextClient(); - if (client == NULL) { - throw runtime_error("client is null"); + ClientProxy *client = listener->getNextClient(); + if (client == NULL) { + throw runtime_error("client is null"); + } + + BaseClientProxy *bcp = client; + server->adoptClient(bcp); + server->setActive(bcp); + + sendMockData(server); +} + +void NetworkTests::sendToClient_mockData_fileRecieveCompleted( + const Event &event, void *) { + Client *client = static_cast(event.getTarget()); + EXPECT_TRUE(client->isReceivedFileSizeValid()); + + m_events.raiseQuitEvent(); +} + +void NetworkTests::sendToClient_mockFile_handleClientConnected( + const Event &, void *vlistener) { + ClientListener *listener = static_cast(vlistener); + Server *server = listener->getServer(); + + ClientProxy *client = listener->getNextClient(); + if (client == NULL) { + throw runtime_error("client is null"); + } + + BaseClientProxy *bcp = client; + server->adoptClient(bcp); + server->setActive(bcp); + + server->sendFileToClient(kMockFilename); +} + +void NetworkTests::sendToClient_mockFile_fileRecieveCompleted( + const Event &event, void *) { + Client *client = static_cast(event.getTarget()); + EXPECT_TRUE(client->isReceivedFileSizeValid()); + + m_events.raiseQuitEvent(); +} + +void NetworkTests::sendToServer_mockData_handleClientConnected(const Event &, + void *vclient) { + Client *client = static_cast(vclient); + sendMockData(client); +} + +void NetworkTests::sendToServer_mockData_fileRecieveCompleted( + const Event &event, void *) { + Server *server = static_cast(event.getTarget()); + EXPECT_TRUE(server->isReceivedFileSizeValid()); + + m_events.raiseQuitEvent(); +} + +void NetworkTests::sendToServer_mockFile_handleClientConnected(const Event &, + void *vclient) { + Client *client = static_cast(vclient); + client->sendFileToServer(kMockFilename); +} + +void NetworkTests::sendToServer_mockFile_fileRecieveCompleted( + const Event &event, void *) { + Server *server = static_cast(event.getTarget()); + EXPECT_TRUE(server->isReceivedFileSizeValid()); + + m_events.raiseQuitEvent(); +} + +void NetworkTests::sendMockData(void *eventTarget) { + // send first message (file size) + String size = synergy::string::sizeTypeToString(kMockDataSize); + FileChunk *sizeMessage = FileChunk::start(size); + + m_events.addEvent( + Event(m_events.forFile().fileChunkSending(), eventTarget, sizeMessage)); + + // send chunk messages with incrementing chunk size + size_t lastSize = 0; + size_t sentLength = 0; + while (true) { + size_t dataSize = lastSize + kMockDataChunkIncrement; + + // make sure we don't read too much from the mock data. + if (sentLength + dataSize > kMockDataSize) { + dataSize = kMockDataSize - sentLength; } - BaseClientProxy* bcp = client; - server->adoptClient(bcp); - server->setActive(bcp); + // first byte is the chunk mark, last is \0 + FileChunk *chunk = FileChunk::data(m_mockData, dataSize); + m_events.addEvent( + Event(m_events.forFile().fileChunkSending(), eventTarget, chunk)); - sendMockData(server); -} + sentLength += dataSize; + lastSize = dataSize; -void -NetworkTests::sendToClient_mockData_fileRecieveCompleted(const Event& event, void*) -{ - Client* client = static_cast(event.getTarget()); - EXPECT_TRUE(client->isReceivedFileSizeValid()); - - m_events.raiseQuitEvent(); -} - -void -NetworkTests::sendToClient_mockFile_handleClientConnected(const Event&, void* vlistener) -{ - ClientListener* listener = static_cast(vlistener); - Server* server = listener->getServer(); - - ClientProxy* client = listener->getNextClient(); - if (client == NULL) { - throw runtime_error("client is null"); + if (sentLength == kMockDataSize) { + break; } + } - BaseClientProxy* bcp = client; - server->adoptClient(bcp); - server->setActive(bcp); - - server->sendFileToClient(kMockFilename); + // send last message + FileChunk *transferFinished = FileChunk::end(); + m_events.addEvent(Event(m_events.forFile().fileChunkSending(), eventTarget, + transferFinished)); } -void -NetworkTests::sendToClient_mockFile_fileRecieveCompleted(const Event& event, void*) -{ - Client* client = static_cast(event.getTarget()); - EXPECT_TRUE(client->isReceivedFileSizeValid()); +UInt8 *newMockData(size_t size) { + UInt8 *buffer = new UInt8[size]; - m_events.raiseQuitEvent(); + UInt8 *data = buffer; + const UInt8 head[] = "mock head... "; + size_t headSize = sizeof(head) - 1; + const UInt8 tail[] = "... mock tail"; + size_t tailSize = sizeof(tail) - 1; + const UInt8 synergyRocks[] = "synergy\0 rocks! "; + size_t synergyRocksSize = sizeof(synergyRocks) - 1; + + memcpy(data, head, headSize); + data += headSize; + + size_t times = (size - headSize - tailSize) / synergyRocksSize; + for (size_t i = 0; i < times; ++i) { + memcpy(data, synergyRocks, synergyRocksSize); + data += synergyRocksSize; + } + + size_t remainder = (size - headSize - tailSize) % synergyRocksSize; + if (remainder != 0) { + memset(data, '.', remainder); + data += remainder; + } + + memcpy(data, tail, tailSize); + return buffer; } -void -NetworkTests::sendToServer_mockData_handleClientConnected(const Event&, void* vclient) -{ - Client* client = static_cast(vclient); - sendMockData(client); +void createFile(fstream &file, const char *filename, size_t size) { + UInt8 *buffer = newMockData(size); + + file.open(filename, ios::out | ios::binary); + if (!file.is_open()) { + throw runtime_error("file not open"); + } + + file.write(reinterpret_cast(buffer), size); + file.close(); + + delete[] buffer; } -void -NetworkTests::sendToServer_mockData_fileRecieveCompleted(const Event& event, void*) -{ - Server* server = static_cast(event.getTarget()); - EXPECT_TRUE(server->isReceivedFileSizeValid()); - - m_events.raiseQuitEvent(); +void getScreenShape(SInt32 &x, SInt32 &y, SInt32 &w, SInt32 &h) { + x = 0; + y = 0; + w = 1; + h = 1; } -void -NetworkTests::sendToServer_mockFile_handleClientConnected(const Event&, void* vclient) -{ - Client* client = static_cast(vclient); - client->sendFileToServer(kMockFilename); -} - -void -NetworkTests::sendToServer_mockFile_fileRecieveCompleted(const Event& event, void*) -{ - Server* server = static_cast(event.getTarget()); - EXPECT_TRUE(server->isReceivedFileSizeValid()); - - m_events.raiseQuitEvent(); -} - -void -NetworkTests::sendMockData(void* eventTarget) -{ - // send first message (file size) - String size = synergy::string::sizeTypeToString(kMockDataSize); - FileChunk* sizeMessage = FileChunk::start(size); - - m_events.addEvent(Event(m_events.forFile().fileChunkSending(), eventTarget, sizeMessage)); - - // send chunk messages with incrementing chunk size - size_t lastSize = 0; - size_t sentLength = 0; - while (true) { - size_t dataSize = lastSize + kMockDataChunkIncrement; - - // make sure we don't read too much from the mock data. - if (sentLength + dataSize > kMockDataSize) { - dataSize = kMockDataSize - sentLength; - } - - // first byte is the chunk mark, last is \0 - FileChunk* chunk = FileChunk::data(m_mockData, dataSize); - m_events.addEvent(Event(m_events.forFile().fileChunkSending(), eventTarget, chunk)); - - sentLength += dataSize; - lastSize = dataSize; - - if (sentLength == kMockDataSize) { - break; - } - - } - - // send last message - FileChunk* transferFinished = FileChunk::end(); - m_events.addEvent(Event(m_events.forFile().fileChunkSending(), eventTarget, transferFinished)); -} - -UInt8* -newMockData(size_t size) -{ - UInt8* buffer = new UInt8[size]; - - UInt8* data = buffer; - const UInt8 head[] = "mock head... "; - size_t headSize = sizeof(head) - 1; - const UInt8 tail[] = "... mock tail"; - size_t tailSize = sizeof(tail) - 1; - const UInt8 synergyRocks[] = "synergy\0 rocks! "; - size_t synergyRocksSize = sizeof(synergyRocks) - 1; - - memcpy(data, head, headSize); - data += headSize; - - size_t times = (size - headSize - tailSize) / synergyRocksSize; - for (size_t i = 0; i < times; ++i) { - memcpy(data, synergyRocks, synergyRocksSize); - data += synergyRocksSize; - } - - size_t remainder = (size - headSize - tailSize) % synergyRocksSize; - if (remainder != 0) { - memset(data, '.', remainder); - data += remainder; - } - - memcpy(data, tail, tailSize); - return buffer; -} - -void -createFile(fstream& file, const char* filename, size_t size) -{ - UInt8* buffer = newMockData(size); - - file.open(filename, ios::out | ios::binary); - if (!file.is_open()) { - throw runtime_error("file not open"); - } - - file.write(reinterpret_cast(buffer), size); - file.close(); - - delete[] buffer; -} - -void -getScreenShape(SInt32& x, SInt32& y, SInt32& w, SInt32& h) -{ - x = 0; - y = 0; - w = 1; - h = 1; -} - -void -getCursorPos(SInt32& x, SInt32& y) -{ - x = 0; - y = 0; +void getCursorPos(SInt32 &x, SInt32 &y) { + x = 0; + y = 0; } #endif // WINAPI_CARBON diff --git a/src/test/integtests/platform/MSWindowsClipboardTests.cpp b/src/test/integtests/platform/MSWindowsClipboardTests.cpp index bd5b7346b..da0c381f4 100644 --- a/src/test/integtests/platform/MSWindowsClipboardTests.cpp +++ b/src/test/integtests/platform/MSWindowsClipboardTests.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2011 Nick Bolton - * + * * 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 LICENSE 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 @@ -16,138 +16,120 @@ * along with this program. If not, see . */ -#include "platform/MSWindowsClipboard.h" #include "platform/IMSWindowsClipboardFacade.h" +#include "platform/MSWindowsClipboard.h" #include "test/global/gmock.h" #include "test/global/gtest.h" -class MSWindowsClipboardTests : public ::testing::Test -{ +class MSWindowsClipboardTests : public ::testing::Test { protected: - virtual void SetUp() - { - emptyClipboard(); - } + virtual void SetUp() { emptyClipboard(); } - virtual void TearDown() - { - emptyClipboard(); - } + virtual void TearDown() { emptyClipboard(); } private: - void emptyClipboard() - { - MSWindowsClipboard clipboard(NULL); - clipboard.open(0); - clipboard.empty(); - } -}; - -class MockFacade : public IMSWindowsClipboardFacade -{ -public: - MOCK_METHOD2(write, void(HANDLE, UINT)); -}; - -TEST_F(MSWindowsClipboardTests, emptyUnowned_openCalled_returnsTrue) -{ + void emptyClipboard() { MSWindowsClipboard clipboard(NULL); clipboard.open(0); - - bool actual = clipboard.emptyUnowned(); - - EXPECT_EQ(true, actual); -} - -TEST_F(MSWindowsClipboardTests, empty_openCalled_returnsTrue) -{ - MSWindowsClipboard clipboard(NULL); - clipboard.open(0); - - bool actual = clipboard.empty(); - - EXPECT_EQ(true, actual); -} - -TEST_F(MSWindowsClipboardTests, empty_singleFormat_hasReturnsFalse) -{ - MSWindowsClipboard clipboard(NULL); - clipboard.open(0); - clipboard.add(MSWindowsClipboard::kText, "synergy rocks!"); - clipboard.empty(); + } +}; - bool actual = clipboard.has(MSWindowsClipboard::kText); - EXPECT_EQ(false, actual); +class MockFacade : public IMSWindowsClipboardFacade { +public: + MOCK_METHOD2(write, void(HANDLE, UINT)); +}; + +TEST_F(MSWindowsClipboardTests, emptyUnowned_openCalled_returnsTrue) { + MSWindowsClipboard clipboard(NULL); + clipboard.open(0); + + bool actual = clipboard.emptyUnowned(); + + EXPECT_EQ(true, actual); } -TEST_F(MSWindowsClipboardTests, add_newValue_valueWasStored) -{ - MSWindowsClipboard clipboard(NULL); - clipboard.open(0); +TEST_F(MSWindowsClipboardTests, empty_openCalled_returnsTrue) { + MSWindowsClipboard clipboard(NULL); + clipboard.open(0); - clipboard.add(IClipboard::kText, "synergy rocks!"); + bool actual = clipboard.empty(); - String actual = clipboard.get(IClipboard::kText); - EXPECT_EQ("synergy rocks!", actual); + EXPECT_EQ(true, actual); } -TEST_F(MSWindowsClipboardTests, add_newValue_writeWasCalled) -{ - MockFacade facade; - EXPECT_CALL(facade, write(testing::_, testing::_)); +TEST_F(MSWindowsClipboardTests, empty_singleFormat_hasReturnsFalse) { + MSWindowsClipboard clipboard(NULL); + clipboard.open(0); + clipboard.add(MSWindowsClipboard::kText, "synergy rocks!"); - MSWindowsClipboard clipboard(NULL); - clipboard.setFacade(facade); - clipboard.open(0); + clipboard.empty(); - clipboard.add(IClipboard::kText, "synergy rocks!"); + bool actual = clipboard.has(MSWindowsClipboard::kText); + EXPECT_EQ(false, actual); } -TEST_F(MSWindowsClipboardTests, add_replaceValue_valueWasReplaced) -{ - MSWindowsClipboard clipboard(NULL); - clipboard.open(0); +TEST_F(MSWindowsClipboardTests, add_newValue_valueWasStored) { + MSWindowsClipboard clipboard(NULL); + clipboard.open(0); - clipboard.add(IClipboard::kText, "synergy rocks!"); - clipboard.add(IClipboard::kText, "maxivista sucks"); // haha, just kidding. + clipboard.add(IClipboard::kText, "synergy rocks!"); - String actual = clipboard.get(IClipboard::kText); - EXPECT_EQ("maxivista sucks", actual); + String actual = clipboard.get(IClipboard::kText); + EXPECT_EQ("synergy rocks!", actual); } -TEST_F(MSWindowsClipboardTests, open_timeIsZero_returnsTrue) -{ - MSWindowsClipboard clipboard(NULL); +TEST_F(MSWindowsClipboardTests, add_newValue_writeWasCalled) { + MockFacade facade; + EXPECT_CALL(facade, write(testing::_, testing::_)); - bool actual = clipboard.open(0); + MSWindowsClipboard clipboard(NULL); + clipboard.setFacade(facade); + clipboard.open(0); - EXPECT_EQ(true, actual); + clipboard.add(IClipboard::kText, "synergy rocks!"); } -TEST_F(MSWindowsClipboardTests, open_timeIsOne_returnsTrue) -{ - MSWindowsClipboard clipboard(NULL); +TEST_F(MSWindowsClipboardTests, add_replaceValue_valueWasReplaced) { + MSWindowsClipboard clipboard(NULL); + clipboard.open(0); - bool actual = clipboard.open(1); + clipboard.add(IClipboard::kText, "synergy rocks!"); + clipboard.add(IClipboard::kText, "maxivista sucks"); // haha, just kidding. - EXPECT_EQ(true, actual); + String actual = clipboard.get(IClipboard::kText); + EXPECT_EQ("maxivista sucks", actual); } -TEST_F(MSWindowsClipboardTests, close_isOpen_noErrors) -{ - MSWindowsClipboard clipboard(NULL); - clipboard.open(0); +TEST_F(MSWindowsClipboardTests, open_timeIsZero_returnsTrue) { + MSWindowsClipboard clipboard(NULL); - clipboard.close(); + bool actual = clipboard.open(0); - // can't assert anything + EXPECT_EQ(true, actual); } -// looks like this test may fail intermittently: -// * http://buildbot.symless.com:8000/builders/trunk-win32/builds/246/steps/shell_3/logs/stdio -/*TEST_F(MSWindowsClipboardTests, getTime_openWithNoEmpty_returnsOne) +TEST_F(MSWindowsClipboardTests, open_timeIsOne_returnsTrue) { + MSWindowsClipboard clipboard(NULL); + + bool actual = clipboard.open(1); + + EXPECT_EQ(true, actual); +} + +TEST_F(MSWindowsClipboardTests, close_isOpen_noErrors) { + MSWindowsClipboard clipboard(NULL); + clipboard.open(0); + + clipboard.close(); + + // can't assert anything +} + +// TODO: fix intermittently failing tests +#if 0 +TEST_F(MSWindowsClipboardTests, getTime_openWithNoEmpty_returnsOne) { MSWindowsClipboard clipboard(NULL); clipboard.open(1); @@ -157,11 +139,9 @@ TEST_F(MSWindowsClipboardTests, close_isOpen_noErrors) // this behavior is different to that of Clipboard which only // returns the value passed into open(t) after empty() is called. EXPECT_EQ(1, actual); -}*/ +} -// this also fails intermittently: -// http://buildbot.symless.com:8000/builders/trunk-win32/builds/266/steps/shell_3/logs/stdio -/*TEST_F(MSWindowsClipboardTests, getTime_openAndEmpty_returnsOne) +TEST_F(MSWindowsClipboardTests, getTime_openAndEmpty_returnsOne) { MSWindowsClipboard clipboard(NULL); clipboard.open(1); @@ -170,60 +150,56 @@ TEST_F(MSWindowsClipboardTests, close_isOpen_noErrors) MSWindowsClipboard::Time actual = clipboard.getTime(); EXPECT_EQ(1, actual); -}*/ +} +#endif -TEST_F(MSWindowsClipboardTests, has_withFormatAdded_returnsTrue) -{ - MSWindowsClipboard clipboard(NULL); - clipboard.open(0); - clipboard.empty(); - clipboard.add(IClipboard::kText, "synergy rocks!"); +TEST_F(MSWindowsClipboardTests, has_withFormatAdded_returnsTrue) { + MSWindowsClipboard clipboard(NULL); + clipboard.open(0); + clipboard.empty(); + clipboard.add(IClipboard::kText, "synergy rocks!"); - bool actual = clipboard.has(IClipboard::kText); + bool actual = clipboard.has(IClipboard::kText); - EXPECT_EQ(true, actual); + EXPECT_EQ(true, actual); } -TEST_F(MSWindowsClipboardTests, has_withNoFormats_returnsFalse) -{ - MSWindowsClipboard clipboard(NULL); - clipboard.open(0); - clipboard.empty(); +TEST_F(MSWindowsClipboardTests, has_withNoFormats_returnsFalse) { + MSWindowsClipboard clipboard(NULL); + clipboard.open(0); + clipboard.empty(); - bool actual = clipboard.has(IClipboard::kText); + bool actual = clipboard.has(IClipboard::kText); - EXPECT_EQ(false, actual); + EXPECT_EQ(false, actual); } -TEST_F(MSWindowsClipboardTests, get_withNoFormats_returnsEmpty) -{ - MSWindowsClipboard clipboard(NULL); - clipboard.open(0); - clipboard.empty(); +TEST_F(MSWindowsClipboardTests, get_withNoFormats_returnsEmpty) { + MSWindowsClipboard clipboard(NULL); + clipboard.open(0); + clipboard.empty(); - String actual = clipboard.get(IClipboard::kText); + String actual = clipboard.get(IClipboard::kText); - EXPECT_EQ("", actual); + EXPECT_EQ("", actual); } -TEST_F(MSWindowsClipboardTests, get_withFormatAdded_returnsExpected) -{ - MSWindowsClipboard clipboard(NULL); - clipboard.open(0); - clipboard.empty(); - clipboard.add(IClipboard::kText, "synergy rocks!"); +TEST_F(MSWindowsClipboardTests, get_withFormatAdded_returnsExpected) { + MSWindowsClipboard clipboard(NULL); + clipboard.open(0); + clipboard.empty(); + clipboard.add(IClipboard::kText, "synergy rocks!"); - String actual = clipboard.get(IClipboard::kText); + String actual = clipboard.get(IClipboard::kText); - EXPECT_EQ("synergy rocks!", actual); + EXPECT_EQ("synergy rocks!", actual); } -TEST_F(MSWindowsClipboardTests, isOwnedBySynergy_defaultState_noError) -{ - MSWindowsClipboard clipboard(NULL); - clipboard.open(0); +TEST_F(MSWindowsClipboardTests, isOwnedBySynergy_defaultState_noError) { + MSWindowsClipboard clipboard(NULL); + clipboard.open(0); - bool actual = clipboard.isOwnedBySynergy(); + bool actual = clipboard.isOwnedBySynergy(); - EXPECT_EQ(true, actual); + EXPECT_EQ(true, actual); } diff --git a/src/test/integtests/platform/MSWindowsKeyStateTests.cpp b/src/test/integtests/platform/MSWindowsKeyStateTests.cpp index 8556480f6..3f6af6560 100644 --- a/src/test/integtests/platform/MSWindowsKeyStateTests.cpp +++ b/src/test/integtests/platform/MSWindowsKeyStateTests.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2011 Nick Bolton - * + * * 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 LICENSE 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 @@ -18,127 +18,125 @@ #define TEST_ENV -#include "test/mock/synergy/MockEventQueue.h" -#include "test/mock/synergy/MockKeyMap.h" -#include "platform/MSWindowsKeyState.h" +#include "base/TMethodJob.h" #include "platform/MSWindowsDesks.h" +#include "platform/MSWindowsKeyState.h" #include "platform/MSWindowsScreen.h" #include "platform/MSWindowsScreenSaver.h" -#include "base/TMethodJob.h" +#include "test/mock/synergy/MockEventQueue.h" +#include "test/mock/synergy/MockKeyMap.h" -#include "test/global/gtest.h" #include "test/global/gmock.h" +#include "test/global/gtest.h" // wParam = flags, HIBYTE(lParam) = virtual key, LOBYTE(lParam) = scan code -#define SYNERGY_MSG_FAKE_KEY SYNERGY_HOOK_LAST_MSG + 4 +#define SYNERGY_MSG_FAKE_KEY SYNERGY_HOOK_LAST_MSG + 4 using ::testing::_; using ::testing::NiceMock; -class MSWindowsKeyStateTests : public ::testing::Test -{ +class MSWindowsKeyStateTests : public ::testing::Test { protected: - virtual void SetUp() - { - m_hook.loadLibrary(); - m_screensaver = new MSWindowsScreenSaver(); - } + virtual void SetUp() { + m_hook.loadLibrary(); + m_screensaver = new MSWindowsScreenSaver(); + } - virtual void TearDown() - { - delete m_screensaver; - } + virtual void TearDown() { delete m_screensaver; } - MSWindowsDesks* newDesks(IEventQueue* eventQueue) - { - return new MSWindowsDesks( - true, false, m_screensaver, eventQueue, - new TMethodJob( - this, &MSWindowsKeyStateTests::updateKeysCB), false); - } + MSWindowsDesks *newDesks(IEventQueue *eventQueue) { + return new MSWindowsDesks(true, false, m_screensaver, eventQueue, + new TMethodJob( + this, &MSWindowsKeyStateTests::updateKeysCB), + false); + } - void* getEventTarget() const - { - return const_cast(this); - } + void *getEventTarget() const { + return const_cast(this); + } private: - void updateKeysCB(void*) { } - IScreenSaver* m_screensaver; - MSWindowsHook m_hook; + void updateKeysCB(void *) {} + IScreenSaver *m_screensaver; + MSWindowsHook m_hook; }; -TEST_F(MSWindowsKeyStateTests, disable_eventQueueNotUsed) -{ - NiceMock eventQueue; - MSWindowsDesks* desks = newDesks(&eventQueue); - MockKeyMap keyMap; - MSWindowsKeyState keyState(desks, getEventTarget(), &eventQueue, keyMap, {"en"}, true); - - EXPECT_CALL(eventQueue, removeHandler(_, _)).Times(0); +TEST_F(MSWindowsKeyStateTests, disable_eventQueueNotUsed) { + NiceMock eventQueue; + MSWindowsDesks *desks = newDesks(&eventQueue); + MockKeyMap keyMap; + MSWindowsKeyState keyState(desks, getEventTarget(), &eventQueue, keyMap, + {"en"}, true); - keyState.disable(); - delete desks; + EXPECT_CALL(eventQueue, removeHandler(_, _)).Times(0); + + keyState.disable(); + delete desks; } -TEST_F(MSWindowsKeyStateTests, testAutoRepeat_noRepeatAndButtonIsZero_resultIsTrue) -{ - NiceMock eventQueue; - MSWindowsDesks* desks = newDesks(&eventQueue); - MockKeyMap keyMap; - MSWindowsKeyState keyState(desks, getEventTarget(), &eventQueue, keyMap, {"en"}, true); - keyState.setLastDown(1); +TEST_F(MSWindowsKeyStateTests, + testAutoRepeat_noRepeatAndButtonIsZero_resultIsTrue) { + NiceMock eventQueue; + MSWindowsDesks *desks = newDesks(&eventQueue); + MockKeyMap keyMap; + MSWindowsKeyState keyState(desks, getEventTarget(), &eventQueue, keyMap, + {"en"}, true); + keyState.setLastDown(1); - bool actual = keyState.testAutoRepeat(true, false, 1); + bool actual = keyState.testAutoRepeat(true, false, 1); - ASSERT_TRUE(actual); - delete desks; + ASSERT_TRUE(actual); + delete desks; } -TEST_F(MSWindowsKeyStateTests, testAutoRepeat_pressFalse_lastDownIsZero) -{ - NiceMock eventQueue; - MSWindowsDesks* desks = newDesks(&eventQueue); - MockKeyMap keyMap; - MSWindowsKeyState keyState(desks, getEventTarget(), &eventQueue, keyMap, {"en"}, true); - keyState.setLastDown(1); +TEST_F(MSWindowsKeyStateTests, testAutoRepeat_pressFalse_lastDownIsZero) { + NiceMock eventQueue; + MSWindowsDesks *desks = newDesks(&eventQueue); + MockKeyMap keyMap; + MSWindowsKeyState keyState(desks, getEventTarget(), &eventQueue, keyMap, + {"en"}, true); + keyState.setLastDown(1); - keyState.testAutoRepeat(false, false, 1); + keyState.testAutoRepeat(false, false, 1); - ASSERT_EQ(0, keyState.getLastDown()); - delete desks; + ASSERT_EQ(0, keyState.getLastDown()); + delete desks; } -TEST_F(MSWindowsKeyStateTests, saveModifiers_noModifiers_savedModifiers0) -{ - NiceMock eventQueue; - MSWindowsDesks* desks = newDesks(&eventQueue); - MockKeyMap keyMap; - MSWindowsKeyState keyState(desks, getEventTarget(), &eventQueue, keyMap, {"en"}, true); +TEST_F(MSWindowsKeyStateTests, saveModifiers_noModifiers_savedModifiers0) { + NiceMock eventQueue; + MSWindowsDesks *desks = newDesks(&eventQueue); + MockKeyMap keyMap; + MSWindowsKeyState keyState(desks, getEventTarget(), &eventQueue, keyMap, + {"en"}, true); - keyState.saveModifiers(); + keyState.saveModifiers(); - ASSERT_EQ(0, keyState.getSavedModifiers()); - delete desks; + ASSERT_EQ(0, keyState.getSavedModifiers()); + delete desks; } -TEST_F(MSWindowsKeyStateTests, testKoreanLocale_inputModeKey_resultCorrectKeyID) -{ - NiceMock eventQueue; - MSWindowsDesks* desks = newDesks(&eventQueue); - MockKeyMap keyMap; - MSWindowsKeyState keyState(desks, getEventTarget(), &eventQueue, keyMap, {"en"}, true); +TEST_F(MSWindowsKeyStateTests, + testKoreanLocale_inputModeKey_resultCorrectKeyID) { + NiceMock eventQueue; + MSWindowsDesks *desks = newDesks(&eventQueue); + MockKeyMap keyMap; + MSWindowsKeyState keyState(desks, getEventTarget(), &eventQueue, keyMap, + {"en"}, true); - keyState.setKeyLayout((HKL)0x00000412u); // for ko-KR local ID - ASSERT_EQ(0xEF31, keyState.getKeyID(0x15u, 0x1f2u)); // VK_HANGUL from Hangul key - ASSERT_EQ(0xEF34, keyState.getKeyID(0x19u, 0x1f1u)); // VK_HANJA from Hanja key - ASSERT_EQ(0xEF31, keyState.getKeyID(0x15u, 0x11du)); // VK_HANGUL from R-Alt key - ASSERT_EQ(0xEF34, keyState.getKeyID(0x19u, 0x138u)); // VK_HANJA from R-Ctrl key + keyState.setKeyLayout((HKL)0x00000412u); // for ko-KR local ID + ASSERT_EQ(0xEF31, + keyState.getKeyID(0x15u, 0x1f2u)); // VK_HANGUL from Hangul key + ASSERT_EQ(0xEF34, + keyState.getKeyID(0x19u, 0x1f1u)); // VK_HANJA from Hanja key + ASSERT_EQ(0xEF31, + keyState.getKeyID(0x15u, 0x11du)); // VK_HANGUL from R-Alt key + ASSERT_EQ(0xEF34, + keyState.getKeyID(0x19u, 0x138u)); // VK_HANJA from R-Ctrl key - keyState.setKeyLayout((HKL)0x00000411); // for ja-jp locale ID - ASSERT_EQ(0xEF26, keyState.getKeyID(0x15u, 0x1du)); // VK_KANA - ASSERT_EQ(0xEF2A, keyState.getKeyID(0x19u, 0x38u)); // VK_KANJI + keyState.setKeyLayout((HKL)0x00000411); // for ja-jp locale ID + ASSERT_EQ(0xEF26, keyState.getKeyID(0x15u, 0x1du)); // VK_KANA + ASSERT_EQ(0xEF2A, keyState.getKeyID(0x19u, 0x38u)); // VK_KANJI - delete desks; + delete desks; } - diff --git a/src/test/integtests/platform/OSXClipboardTests.cpp b/src/test/integtests/platform/OSXClipboardTests.cpp index c2222a5ba..e9cb23326 100644 --- a/src/test/integtests/platform/OSXClipboardTests.cpp +++ b/src/test/integtests/platform/OSXClipboardTests.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2011 Nick Bolton - * + * * 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 LICENSE 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 @@ -21,144 +21,131 @@ #include "test/global/gtest.h" #include -TEST(OSXClipboardTests, empty_openCalled_returnsTrue) -{ - OSXClipboard clipboard; - clipboard.open(0); - - bool actual = clipboard.empty(); - - EXPECT_EQ(true, actual); +TEST(OSXClipboardTests, empty_openCalled_returnsTrue) { + OSXClipboard clipboard; + clipboard.open(0); + + bool actual = clipboard.empty(); + + EXPECT_EQ(true, actual); } -TEST(OSXClipboardTests, empty_singleFormat_hasReturnsFalse) -{ - OSXClipboard clipboard; - clipboard.open(0); - clipboard.add(OSXClipboard::kText, "synergy rocks!"); - - clipboard.empty(); - - bool actual = clipboard.has(OSXClipboard::kText); - EXPECT_EQ(false, actual); +TEST(OSXClipboardTests, empty_singleFormat_hasReturnsFalse) { + OSXClipboard clipboard; + clipboard.open(0); + clipboard.add(OSXClipboard::kText, "synergy rocks!"); + + clipboard.empty(); + + bool actual = clipboard.has(OSXClipboard::kText); + EXPECT_EQ(false, actual); } -TEST(OSXClipboardTests, add_newValue_valueWasStored) -{ - OSXClipboard clipboard; - clipboard.open(0); - - clipboard.add(IClipboard::kText, "synergy rocks!"); - - String actual = clipboard.get(IClipboard::kText); - EXPECT_EQ("synergy rocks!", actual); +TEST(OSXClipboardTests, add_newValue_valueWasStored) { + OSXClipboard clipboard; + clipboard.open(0); + + clipboard.add(IClipboard::kText, "synergy rocks!"); + + String actual = clipboard.get(IClipboard::kText); + EXPECT_EQ("synergy rocks!", actual); } -TEST(OSXClipboardTests, add_replaceValue_valueWasReplaced) -{ - OSXClipboard clipboard; - clipboard.open(0); - - clipboard.add(IClipboard::kText, "synergy rocks!"); - clipboard.add(IClipboard::kText, "maxivista sucks"); // haha, just kidding. - - String actual = clipboard.get(IClipboard::kText); - EXPECT_EQ("maxivista sucks", actual); +TEST(OSXClipboardTests, add_replaceValue_valueWasReplaced) { + OSXClipboard clipboard; + clipboard.open(0); + + clipboard.add(IClipboard::kText, "synergy rocks!"); + clipboard.add(IClipboard::kText, "maxivista sucks"); // haha, just kidding. + + String actual = clipboard.get(IClipboard::kText); + EXPECT_EQ("maxivista sucks", actual); } -TEST(OSXClipboardTests, open_timeIsZero_returnsTrue) -{ - OSXClipboard clipboard; - - bool actual = clipboard.open(0); - - EXPECT_EQ(true, actual); +TEST(OSXClipboardTests, open_timeIsZero_returnsTrue) { + OSXClipboard clipboard; + + bool actual = clipboard.open(0); + + EXPECT_EQ(true, actual); } -TEST(OSXClipboardTests, open_timeIsOne_returnsTrue) -{ - OSXClipboard clipboard; - - bool actual = clipboard.open(1); - - EXPECT_EQ(true, actual); +TEST(OSXClipboardTests, open_timeIsOne_returnsTrue) { + OSXClipboard clipboard; + + bool actual = clipboard.open(1); + + EXPECT_EQ(true, actual); } -TEST(OSXClipboardTests, close_isOpen_noErrors) -{ - OSXClipboard clipboard; - clipboard.open(0); - - clipboard.close(); - - // can't assert anything +TEST(OSXClipboardTests, close_isOpen_noErrors) { + OSXClipboard clipboard; + clipboard.open(0); + + clipboard.close(); + + // can't assert anything } -TEST(OSXClipboardTests, getTime_openWithNoEmpty_returnsOne) -{ - OSXClipboard clipboard; - clipboard.open(1); - - OSXClipboard::Time actual = clipboard.getTime(); - - // this behavior is different to that of Clipboard which only - // returns the value passed into open(t) after empty() is called. - EXPECT_EQ((UInt32)1, actual); +TEST(OSXClipboardTests, getTime_openWithNoEmpty_returnsOne) { + OSXClipboard clipboard; + clipboard.open(1); + + OSXClipboard::Time actual = clipboard.getTime(); + + // this behavior is different to that of Clipboard which only + // returns the value passed into open(t) after empty() is called. + EXPECT_EQ((UInt32)1, actual); } -TEST(OSXClipboardTests, getTime_openAndEmpty_returnsOne) -{ - OSXClipboard clipboard; - clipboard.open(1); - clipboard.empty(); - - OSXClipboard::Time actual = clipboard.getTime(); - - EXPECT_EQ((UInt32)1, actual); +TEST(OSXClipboardTests, getTime_openAndEmpty_returnsOne) { + OSXClipboard clipboard; + clipboard.open(1); + clipboard.empty(); + + OSXClipboard::Time actual = clipboard.getTime(); + + EXPECT_EQ((UInt32)1, actual); } -TEST(OSXClipboardTests, has_withFormatAdded_returnsTrue) -{ - OSXClipboard clipboard; - clipboard.open(0); - clipboard.empty(); - clipboard.add(IClipboard::kText, "synergy rocks!"); - - bool actual = clipboard.has(IClipboard::kText); - - EXPECT_EQ(true, actual); +TEST(OSXClipboardTests, has_withFormatAdded_returnsTrue) { + OSXClipboard clipboard; + clipboard.open(0); + clipboard.empty(); + clipboard.add(IClipboard::kText, "synergy rocks!"); + + bool actual = clipboard.has(IClipboard::kText); + + EXPECT_EQ(true, actual); } -TEST(OSXClipboardTests, has_withNoFormats_returnsFalse) -{ - OSXClipboard clipboard; - clipboard.open(0); - clipboard.empty(); - - bool actual = clipboard.has(IClipboard::kText); - - EXPECT_EQ(false, actual); +TEST(OSXClipboardTests, has_withNoFormats_returnsFalse) { + OSXClipboard clipboard; + clipboard.open(0); + clipboard.empty(); + + bool actual = clipboard.has(IClipboard::kText); + + EXPECT_EQ(false, actual); } -TEST(OSXClipboardTests, get_withNoFormats_returnsEmpty) -{ - OSXClipboard clipboard; - clipboard.open(0); - clipboard.empty(); - - String actual = clipboard.get(IClipboard::kText); - - EXPECT_EQ("", actual); +TEST(OSXClipboardTests, get_withNoFormats_returnsEmpty) { + OSXClipboard clipboard; + clipboard.open(0); + clipboard.empty(); + + String actual = clipboard.get(IClipboard::kText); + + EXPECT_EQ("", actual); } -TEST(OSXClipboardTests, get_withFormatAdded_returnsExpected) -{ - OSXClipboard clipboard; - clipboard.open(0); - clipboard.empty(); - clipboard.add(IClipboard::kText, "synergy rocks!"); - - String actual = clipboard.get(IClipboard::kText); - - EXPECT_EQ("synergy rocks!", actual); +TEST(OSXClipboardTests, get_withFormatAdded_returnsExpected) { + OSXClipboard clipboard; + clipboard.open(0); + clipboard.empty(); + clipboard.add(IClipboard::kText, "synergy rocks!"); + + String actual = clipboard.get(IClipboard::kText); + + EXPECT_EQ("synergy rocks!", actual); } diff --git a/src/test/integtests/platform/OSXKeyStateTests.cpp b/src/test/integtests/platform/OSXKeyStateTests.cpp index 7e531bcdc..5311ff647 100644 --- a/src/test/integtests/platform/OSXKeyStateTests.cpp +++ b/src/test/integtests/platform/OSXKeyStateTests.cpp @@ -16,13 +16,13 @@ * along with this program. If not, see . */ -#include "test/mock/synergy/MockKeyMap.h" -#include "test/mock/synergy/MockEventQueue.h" -#include "platform/OSXKeyState.h" #include "base/Log.h" +#include "platform/OSXKeyState.h" +#include "test/mock/synergy/MockEventQueue.h" +#include "test/mock/synergy/MockKeyMap.h" -#include "test/global/gtest.h" #include "test/global/gmock.h" +#include "test/global/gtest.h" #define SHIFT_ID_L kKeyShift_L #define SHIFT_ID_R kKeyShift_R @@ -32,88 +32,83 @@ class OSXKeyStateTests : public ::testing::Test { public: - static bool isKeyPressed(const OSXKeyState& keyState, KeyButton button); + static bool isKeyPressed(const OSXKeyState &keyState, KeyButton button); }; // fakeAndPoll_shift seems to always fail on osx10.6 #if __MAC_OS_X_VERSION_MIN_REQUIRED > 1060 -TEST_F(OSXKeyStateTests, fakeAndPoll_shift) -{ - synergy::KeyMap keyMap; - MockEventQueue eventQueue; - OSXKeyState keyState(&eventQueue, keyMap, {"en"}, true); - keyState.updateKeyMap(); +TEST_F(OSXKeyStateTests, fakeAndPoll_shift) { + synergy::KeyMap keyMap; + MockEventQueue eventQueue; + OSXKeyState keyState(&eventQueue, keyMap, {"en"}, true); + keyState.updateKeyMap(); - keyState.fakeKeyDown(SHIFT_ID_L, 0, 1, "en"); - EXPECT_TRUE(isKeyPressed(keyState, SHIFT_BUTTON)); + keyState.fakeKeyDown(SHIFT_ID_L, 0, 1, "en"); + EXPECT_TRUE(isKeyPressed(keyState, SHIFT_BUTTON)); - keyState.fakeKeyUp(1); - EXPECT_TRUE(!isKeyPressed(keyState, SHIFT_BUTTON)); + keyState.fakeKeyUp(1); + EXPECT_TRUE(!isKeyPressed(keyState, SHIFT_BUTTON)); - keyState.fakeKeyDown(SHIFT_ID_R, 0, 2, "en"); - EXPECT_TRUE(isKeyPressed(keyState, SHIFT_BUTTON)); + keyState.fakeKeyDown(SHIFT_ID_R, 0, 2, "en"); + EXPECT_TRUE(isKeyPressed(keyState, SHIFT_BUTTON)); - keyState.fakeKeyUp(2); - EXPECT_TRUE(!isKeyPressed(keyState, SHIFT_BUTTON)); + keyState.fakeKeyUp(2); + EXPECT_TRUE(!isKeyPressed(keyState, SHIFT_BUTTON)); } -TEST_F(OSXKeyStateTests, fakeAndPoll_charKey) -{ - synergy::KeyMap keyMap; - MockEventQueue eventQueue; - OSXKeyState keyState(&eventQueue, keyMap, {"en"}, true); - keyState.updateKeyMap(); +TEST_F(OSXKeyStateTests, fakeAndPoll_charKey) { + synergy::KeyMap keyMap; + MockEventQueue eventQueue; + OSXKeyState keyState(&eventQueue, keyMap, {"en"}, true); + keyState.updateKeyMap(); - keyState.fakeKeyDown(A_CHAR_ID, 0, 1, "en"); - EXPECT_TRUE(isKeyPressed(keyState, A_CHAR_BUTTON)); + keyState.fakeKeyDown(A_CHAR_ID, 0, 1, "en"); + EXPECT_TRUE(isKeyPressed(keyState, A_CHAR_BUTTON)); - keyState.fakeKeyUp(1); - EXPECT_TRUE(!isKeyPressed(keyState, A_CHAR_BUTTON)); + keyState.fakeKeyUp(1); + EXPECT_TRUE(!isKeyPressed(keyState, A_CHAR_BUTTON)); - // HACK: delete the key in case it was typed into a text editor. - // we should really set focus to an invisible window. - keyState.fakeKeyDown(kKeyBackSpace, 0, 2, "en"); - keyState.fakeKeyUp(2); + // HACK: delete the key in case it was typed into a text editor. + // we should really set focus to an invisible window. + keyState.fakeKeyDown(kKeyBackSpace, 0, 2, "en"); + keyState.fakeKeyUp(2); } -TEST_F(OSXKeyStateTests, fakeAndPoll_charKeyAndModifier) -{ - synergy::KeyMap keyMap; - MockEventQueue eventQueue; - OSXKeyState keyState(&eventQueue, keyMap, {"en"}, true); - keyState.updateKeyMap(); +TEST_F(OSXKeyStateTests, fakeAndPoll_charKeyAndModifier) { + synergy::KeyMap keyMap; + MockEventQueue eventQueue; + OSXKeyState keyState(&eventQueue, keyMap, {"en"}, true); + keyState.updateKeyMap(); - keyState.fakeKeyDown(A_CHAR_ID, KeyModifierShift, 1, "en"); - EXPECT_TRUE(isKeyPressed(keyState, A_CHAR_BUTTON)); + keyState.fakeKeyDown(A_CHAR_ID, KeyModifierShift, 1, "en"); + EXPECT_TRUE(isKeyPressed(keyState, A_CHAR_BUTTON)); - keyState.fakeKeyUp(1); - EXPECT_TRUE(!isKeyPressed(keyState, A_CHAR_BUTTON)); + keyState.fakeKeyUp(1); + EXPECT_TRUE(!isKeyPressed(keyState, A_CHAR_BUTTON)); - // HACK: delete the key in case it was typed into a text editor. - // we should really set focus to an invisible window. - keyState.fakeKeyDown(kKeyBackSpace, 0, 2, "en"); - keyState.fakeKeyUp(2); + // HACK: delete the key in case it was typed into a text editor. + // we should really set focus to an invisible window. + keyState.fakeKeyDown(kKeyBackSpace, 0, 2, "en"); + keyState.fakeKeyUp(2); } -bool -OSXKeyStateTests::isKeyPressed(const OSXKeyState& keyState, KeyButton button) -{ - // HACK: allow os to realize key state changes. - ARCH->sleep(.2); +bool OSXKeyStateTests::isKeyPressed(const OSXKeyState &keyState, + KeyButton button) { + // HACK: allow os to realize key state changes. + ARCH->sleep(.2); - IKeyState::KeyButtonSet pressed; - keyState.pollPressedKeys(pressed); + IKeyState::KeyButtonSet pressed; + keyState.pollPressedKeys(pressed); - IKeyState::KeyButtonSet::const_iterator it; - for (it = pressed.begin(); it != pressed.end(); ++it) { - LOG((CLOG_DEBUG "checking key %d", *it)); - if (*it == button) { - return true; - } + IKeyState::KeyButtonSet::const_iterator it; + for (it = pressed.begin(); it != pressed.end(); ++it) { + LOG((CLOG_DEBUG "checking key %d", *it)); + if (*it == button) { + return true; } - return false; + } + return false; } #endif - diff --git a/src/test/integtests/platform/OSXScreenTests.cpp b/src/test/integtests/platform/OSXScreenTests.cpp index 66f37e099..0b501f7aa 100644 --- a/src/test/integtests/platform/OSXScreenTests.cpp +++ b/src/test/integtests/platform/OSXScreenTests.cpp @@ -1,11 +1,11 @@ /* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. - * + * * 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 LICENSE 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 @@ -15,14 +15,16 @@ * along with this program. If not, see . */ -#include "platform/OSXScreen.h" #include "arch/Arch.h" #include "base/EventQueue.h" +#include "platform/OSXScreen.h" #include "test/global/gtest.h" -// disabling these tests - the return value of CGCursorIsVisible is unreliable. -/* +// TODO: fix intermittently failing test +// return value of CGCursorIsVisible is unreliable +#if 0 + TEST(OSXScreenTests, hideCursor_notPrimary) { EventQueue queue; @@ -48,4 +50,5 @@ TEST(OSXScreenTests, showCursor_notPrimary) // workaround for screen class race condition. ARCH->sleep(.1f); } -*/ + +#endif diff --git a/src/test/integtests/platform/XWindowsClipboardTests.cpp b/src/test/integtests/platform/XWindowsClipboardTests.cpp index 0cd0f7102..a70c5dc1e 100644 --- a/src/test/integtests/platform/XWindowsClipboardTests.cpp +++ b/src/test/integtests/platform/XWindowsClipboardTests.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2011 Nick Bolton - * + * * 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 LICENSE 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 diff --git a/src/test/integtests/platform/XWindowsKeyStateTests.cpp b/src/test/integtests/platform/XWindowsKeyStateTests.cpp index 69fe64a9b..b52a1c1f7 100644 --- a/src/test/integtests/platform/XWindowsKeyStateTests.cpp +++ b/src/test/integtests/platform/XWindowsKeyStateTests.cpp @@ -18,143 +18,120 @@ #define TEST_ENV -#include "test/mock/synergy/MockKeyMap.h" #include "test/mock/synergy/MockEventQueue.h" -#include "platform/XWindowsKeyState.h" +#include "test/mock/synergy/MockKeyMap.h" + #include "base/Log.h" +#include "platform/XWindowsKeyState.h" #define XK_LATIN1 #define XK_MISCELLANY #include #if HAVE_XKB_EXTENSION -# include +#include #endif -#include "test/global/gtest.h" #include "test/global/gmock.h" +#include "test/global/gtest.h" #include -class XWindowsKeyStateTests : public ::testing::Test -{ +class XWindowsKeyStateTests : public ::testing::Test { protected: - XWindowsKeyStateTests() : - m_display(NULL) - { + XWindowsKeyStateTests() : m_display(NULL) {} + + ~XWindowsKeyStateTests() { + if (m_display != NULL) { + LOG((CLOG_DEBUG "closing display")); + XCloseDisplay(m_display); } + } - ~XWindowsKeyStateTests() - { - if (m_display != NULL) { - LOG((CLOG_DEBUG "closing display")); - XCloseDisplay(m_display); - } + virtual void SetUp() { + // open the display only once for the entire test suite + if (this->m_display == NULL) { + LOG((CLOG_DEBUG "opening display")); + this->m_display = XOpenDisplay(NULL); + + ASSERT_TRUE(this->m_display != NULL) + << "unable to open display: " << errno; } + } - virtual void - SetUp() - { - // open the display only once for the entire test suite - if (this->m_display == NULL) { - LOG((CLOG_DEBUG "opening display")); - this->m_display = XOpenDisplay(NULL); + virtual void TearDown() {} - ASSERT_TRUE(this->m_display != NULL) - << "unable to open display: " << errno; - } - } - - virtual void - TearDown() - { - } - - Display* m_display; + Display *m_display; }; -TEST_F(XWindowsKeyStateTests, setActiveGroup_pollAndSet_groupIsZero) -{ - MockKeyMap keyMap; - MockEventQueue eventQueue; - XWindowsKeyState keyState( - m_display, true, &eventQueue, keyMap); +TEST_F(XWindowsKeyStateTests, setActiveGroup_pollAndSet_groupIsZero) { + MockKeyMap keyMap; + MockEventQueue eventQueue; + XWindowsKeyState keyState(m_display, true, &eventQueue, keyMap); - keyState.setActiveGroup(XWindowsKeyState::kGroupPollAndSet); + keyState.setActiveGroup(XWindowsKeyState::kGroupPollAndSet); - ASSERT_EQ(0, keyState.group()); + ASSERT_EQ(0, keyState.group()); } -TEST_F(XWindowsKeyStateTests, setActiveGroup_poll_groupIsNotSet) -{ - MockKeyMap keyMap; - MockEventQueue eventQueue; - XWindowsKeyState keyState( - m_display, true, &eventQueue, keyMap); +TEST_F(XWindowsKeyStateTests, setActiveGroup_poll_groupIsNotSet) { + MockKeyMap keyMap; + MockEventQueue eventQueue; + XWindowsKeyState keyState(m_display, true, &eventQueue, keyMap); - keyState.setActiveGroup(XWindowsKeyState::kGroupPoll); + keyState.setActiveGroup(XWindowsKeyState::kGroupPoll); - ASSERT_LE(-1, keyState.group()); + ASSERT_LE(-1, keyState.group()); } -TEST_F(XWindowsKeyStateTests, setActiveGroup_customGroup_groupWasSet) -{ - MockKeyMap keyMap; - MockEventQueue eventQueue; - XWindowsKeyState keyState( - m_display, true, &eventQueue, keyMap); +TEST_F(XWindowsKeyStateTests, setActiveGroup_customGroup_groupWasSet) { + MockKeyMap keyMap; + MockEventQueue eventQueue; + XWindowsKeyState keyState(m_display, true, &eventQueue, keyMap); - keyState.setActiveGroup(1); + keyState.setActiveGroup(1); - ASSERT_EQ(1, keyState.group()); + ASSERT_EQ(1, keyState.group()); } -TEST_F(XWindowsKeyStateTests, mapModifiersFromX_zeroState_zeroMask) -{ - MockKeyMap keyMap; - MockEventQueue eventQueue; - XWindowsKeyState keyState( - m_display, true, &eventQueue, keyMap); +TEST_F(XWindowsKeyStateTests, mapModifiersFromX_zeroState_zeroMask) { + MockKeyMap keyMap; + MockEventQueue eventQueue; + XWindowsKeyState keyState(m_display, true, &eventQueue, keyMap); - int mask = keyState.mapModifiersFromX(0); + int mask = keyState.mapModifiersFromX(0); - ASSERT_EQ(0, mask); + ASSERT_EQ(0, mask); } -TEST_F(XWindowsKeyStateTests, mapModifiersToX_zeroMask_resultIsTrue) -{ - MockKeyMap keyMap; - MockEventQueue eventQueue; - XWindowsKeyState keyState( - m_display, true, &eventQueue, keyMap); +TEST_F(XWindowsKeyStateTests, mapModifiersToX_zeroMask_resultIsTrue) { + MockKeyMap keyMap; + MockEventQueue eventQueue; + XWindowsKeyState keyState(m_display, true, &eventQueue, keyMap); - unsigned int modifiers = 0; - bool result = keyState.mapModifiersToX(0, modifiers); + unsigned int modifiers = 0; + bool result = keyState.mapModifiersToX(0, modifiers); - ASSERT_TRUE(result); + ASSERT_TRUE(result); } -TEST_F(XWindowsKeyStateTests, fakeCtrlAltDel_default_returnsFalse) -{ - MockKeyMap keyMap; - MockEventQueue eventQueue; - XWindowsKeyState keyState( - m_display, true, &eventQueue, keyMap); +TEST_F(XWindowsKeyStateTests, fakeCtrlAltDel_default_returnsFalse) { + MockKeyMap keyMap; + MockEventQueue eventQueue; + XWindowsKeyState keyState(m_display, true, &eventQueue, keyMap); - bool result = keyState.fakeCtrlAltDel(); + bool result = keyState.fakeCtrlAltDel(); - ASSERT_FALSE(result); + ASSERT_FALSE(result); } -TEST_F(XWindowsKeyStateTests, pollActiveModifiers_defaultState_returnsZero) -{ - MockKeyMap keyMap; - MockEventQueue eventQueue; - XWindowsKeyState keyState( - m_display, true, &eventQueue, keyMap); +TEST_F(XWindowsKeyStateTests, pollActiveModifiers_defaultState_returnsZero) { + MockKeyMap keyMap; + MockEventQueue eventQueue; + XWindowsKeyState keyState(m_display, true, &eventQueue, keyMap); - KeyModifierMask actual = keyState.pollActiveModifiers(); + KeyModifierMask actual = keyState.pollActiveModifiers(); - ASSERT_EQ(0, actual); + ASSERT_EQ(0, actual); } #if 0 // TODO: fix, causes sigsegv @@ -191,56 +168,48 @@ TEST_F(XWindowsKeyStateTests, pollActiveModifiers_shiftKeyDownThenUp_masksAreCor } #endif -TEST_F(XWindowsKeyStateTests, pollActiveGroup_defaultState_returnsZero) -{ - MockKeyMap keyMap; - MockEventQueue eventQueue; - XWindowsKeyState keyState( - m_display, true, &eventQueue, keyMap); +TEST_F(XWindowsKeyStateTests, pollActiveGroup_defaultState_returnsZero) { + MockKeyMap keyMap; + MockEventQueue eventQueue; + XWindowsKeyState keyState(m_display, true, &eventQueue, keyMap); - SInt32 actual = keyState.pollActiveGroup(); + SInt32 actual = keyState.pollActiveGroup(); - ASSERT_EQ(0, actual); + ASSERT_EQ(0, actual); } -TEST_F(XWindowsKeyStateTests, pollActiveGroup_positiveGroup_returnsGroup) -{ - MockKeyMap keyMap; - MockEventQueue eventQueue; - XWindowsKeyState keyState( - m_display, true, &eventQueue, keyMap); +TEST_F(XWindowsKeyStateTests, pollActiveGroup_positiveGroup_returnsGroup) { + MockKeyMap keyMap; + MockEventQueue eventQueue; + XWindowsKeyState keyState(m_display, true, &eventQueue, keyMap); - keyState.group(3); + keyState.group(3); - SInt32 actual = keyState.pollActiveGroup(); + SInt32 actual = keyState.pollActiveGroup(); - ASSERT_EQ(3, actual); + ASSERT_EQ(3, actual); } -TEST_F(XWindowsKeyStateTests, pollActiveGroup_xkb_areEqual) -{ +TEST_F(XWindowsKeyStateTests, pollActiveGroup_xkb_areEqual) { #if HAVE_XKB_EXTENSION - MockKeyMap keyMap; - MockEventQueue eventQueue; - XWindowsKeyState keyState( - m_display, true, &eventQueue, keyMap); + MockKeyMap keyMap; + MockEventQueue eventQueue; + XWindowsKeyState keyState(m_display, true, &eventQueue, keyMap); - // reset the group - keyState.group(-1); + // reset the group + keyState.group(-1); - XkbStateRec state; + XkbStateRec state; - // compare pollActiveGroup() with XkbGetState() - if (XkbGetState(m_display, XkbUseCoreKbd, &state) == Success) { - SInt32 actual = keyState.pollActiveGroup(); + // compare pollActiveGroup() with XkbGetState() + if (XkbGetState(m_display, XkbUseCoreKbd, &state) == Success) { + SInt32 actual = keyState.pollActiveGroup(); - ASSERT_EQ(state.group, actual); - } - else { - FAIL() << "XkbGetState() returned error " << errno; - } + ASSERT_EQ(state.group, actual); + } else { + FAIL() << "XkbGetState() returned error " << errno; + } #else - SUCCEED() << "Xkb extension not installed"; + SUCCEED() << "Xkb extension not installed"; #endif } - diff --git a/src/test/integtests/platform/XWindowsScreenSaverTests.cpp b/src/test/integtests/platform/XWindowsScreenSaverTests.cpp index e9a5e937f..ddcf4d453 100644 --- a/src/test/integtests/platform/XWindowsScreenSaverTests.cpp +++ b/src/test/integtests/platform/XWindowsScreenSaverTests.cpp @@ -19,8 +19,8 @@ // TODO: fix tests #if 0 -#include "test/mock/synergy/MockEventQueue.h" #include "platform/XWindowsScreenSaver.h" +#include "test/mock/synergy/MockEventQueue.h" #include "test/global/gtest.h" #include diff --git a/src/test/integtests/platform/XWindowsScreenTests.cpp b/src/test/integtests/platform/XWindowsScreenTests.cpp index 6dd7f6146..435268632 100644 --- a/src/test/integtests/platform/XWindowsScreenTests.cpp +++ b/src/test/integtests/platform/XWindowsScreenTests.cpp @@ -16,27 +16,28 @@ * along with this program. If not, see . */ -#include "test/mock/synergy/MockEventQueue.h" -#include "platform/XWindowsScreen.h" - #include "test/global/gtest.h" +#include "test/mock/synergy/MockEventQueue.h" + +#include "platform/XWindowsScreen.h" using ::testing::_; -TEST(CXWindowsScreenTests, fakeMouseMove_nonPrimary_getCursorPosValuesCorrect) -{ - //TODO Fix this test -// MockEventQueue eventQueue; -// EXPECT_CALL(eventQueue, adoptHandler(_, _, _)).Times(2); -// EXPECT_CALL(eventQueue, adoptBuffer(_)).Times(2); -// EXPECT_CALL(eventQueue, removeHandler(_, _)).Times(2); -// XWindowsScreen screen( -// ":0.0", false, false, 0, &eventQueue); -// -// screen.fakeMouseMove(10, 20); -// -// int x, y; -// screen.getCursorPos(x, y); -// ASSERT_EQ(10, x); -// ASSERT_EQ(20, y); +// TODO: fix failing tests +#if 0 +TEST(CXWindowsScreenTests, fakeMouseMove_nonPrimary_getCursorPosValuesCorrect) { + MockEventQueue eventQueue; + EXPECT_CALL(eventQueue, adoptHandler(_, _, _)).Times(2); + EXPECT_CALL(eventQueue, adoptBuffer(_)).Times(2); + EXPECT_CALL(eventQueue, removeHandler(_, _)).Times(2); + XWindowsScreen screen( + ":0.0", false, false, 0, &eventQueue); + + screen.fakeMouseMove(10, 20); + + int x, y; + screen.getCursorPos(x, y); + ASSERT_EQ(10, x); + ASSERT_EQ(20, y); } +#endif diff --git a/src/test/mock/io/MockStream.h b/src/test/mock/io/MockStream.h index 028c61c9a..d294be99b 100644 --- a/src/test/mock/io/MockStream.h +++ b/src/test/mock/io/MockStream.h @@ -24,21 +24,20 @@ class IEventQueue; -class MockStream : public synergy::IStream -{ +class MockStream : public synergy::IStream { public: - MockStream() { } - MOCK_METHOD(void, close, (), (override)); - MOCK_METHOD(UInt32, read, (void*, UInt32), (override)); - MOCK_METHOD(void, write, (const void*, UInt32), (override)); - MOCK_METHOD(void, flush, (), (override)); - MOCK_METHOD(void, shutdownInput, (), (override)); - MOCK_METHOD(void, shutdownOutput, (), (override)); - MOCK_METHOD(Event::Type, getInputReadyEvent, ()); - MOCK_METHOD(Event::Type, getOutputErrorEvent, ()); - MOCK_METHOD(Event::Type, getInputShutdownEvent, ()); - MOCK_METHOD(Event::Type, getOutputShutdownEvent, ()); - MOCK_METHOD(void*, getEventTarget, (), (const, override)); - MOCK_METHOD(bool, isReady, (), (const, override)); - MOCK_METHOD(UInt32, getSize, (), (const, override)); + MockStream() {} + MOCK_METHOD(void, close, (), (override)); + MOCK_METHOD(UInt32, read, (void *, UInt32), (override)); + MOCK_METHOD(void, write, (const void *, UInt32), (override)); + MOCK_METHOD(void, flush, (), (override)); + MOCK_METHOD(void, shutdownInput, (), (override)); + MOCK_METHOD(void, shutdownOutput, (), (override)); + MOCK_METHOD(Event::Type, getInputReadyEvent, ()); + MOCK_METHOD(Event::Type, getOutputErrorEvent, ()); + MOCK_METHOD(Event::Type, getInputShutdownEvent, ()); + MOCK_METHOD(Event::Type, getOutputShutdownEvent, ()); + MOCK_METHOD(void *, getEventTarget, (), (const, override)); + MOCK_METHOD(bool, isReady, (), (const, override)); + MOCK_METHOD(UInt32, getSize, (), (const, override)); }; diff --git a/src/test/mock/ipc/MockIpcServer.h b/src/test/mock/ipc/MockIpcServer.h index 6e4f862bb..9edf0e9e2 100644 --- a/src/test/mock/ipc/MockIpcServer.h +++ b/src/test/mock/ipc/MockIpcServer.h @@ -17,9 +17,9 @@ #pragma once -#include "ipc/IpcServer.h" -#include "ipc/IpcMessage.h" #include "arch/Arch.h" +#include "ipc/IpcMessage.h" +#include "ipc/IpcServer.h" #include "test/global/gmock.h" @@ -28,41 +28,38 @@ using ::testing::Invoke; class IEventQueue; -class MockIpcServer : public IpcServer -{ +class MockIpcServer : public IpcServer { public: - MockIpcServer() : - m_sendCond(ARCH->newCondVar()), - m_sendMutex(ARCH->newMutex()) { } - - ~MockIpcServer() { - if (m_sendCond != NULL) { - ARCH->closeCondVar(m_sendCond); - } + MockIpcServer() + : m_sendCond(ARCH->newCondVar()), m_sendMutex(ARCH->newMutex()) {} - if (m_sendMutex != NULL) { - ARCH->closeMutex(m_sendMutex); - } + ~MockIpcServer() { + if (m_sendCond != NULL) { + ARCH->closeCondVar(m_sendCond); } - MOCK_METHOD(void, listen, (), (override)); - MOCK_METHOD(void, send, (const IpcMessage&, EIpcClientType), (override)); - MOCK_METHOD(bool, hasClients, (EIpcClientType), (const, override)); - - void delegateToFake() { - ON_CALL(*this, send(_, _)).WillByDefault(Invoke(this, &MockIpcServer::mockSend)); + if (m_sendMutex != NULL) { + ARCH->closeMutex(m_sendMutex); } + } - void waitForSend() { - ARCH->waitCondVar(m_sendCond, m_sendMutex, 5); - } + MOCK_METHOD(void, listen, (), (override)); + MOCK_METHOD(void, send, (const IpcMessage &, EIpcClientType), (override)); + MOCK_METHOD(bool, hasClients, (EIpcClientType), (const, override)); + + void delegateToFake() { + ON_CALL(*this, send(_, _)) + .WillByDefault(Invoke(this, &MockIpcServer::mockSend)); + } + + void waitForSend() { ARCH->waitCondVar(m_sendCond, m_sendMutex, 5); } private: - void mockSend(const IpcMessage&, EIpcClientType) { - ArchMutexLock lock(m_sendMutex); - ARCH->broadcastCondVar(m_sendCond); - } + void mockSend(const IpcMessage &, EIpcClientType) { + ArchMutexLock lock(m_sendMutex); + ARCH->broadcastCondVar(m_sendCond); + } - ArchCond m_sendCond; - ArchMutex m_sendMutex; + ArchCond m_sendCond; + ArchMutex m_sendMutex; }; diff --git a/src/test/mock/server/MockConfig.h b/src/test/mock/server/MockConfig.h index 76d3f1796..332318764 100644 --- a/src/test/mock/server/MockConfig.h +++ b/src/test/mock/server/MockConfig.h @@ -23,10 +23,9 @@ #include "test/global/gmock.h" -class MockConfig : public Config -{ +class MockConfig : public Config { public: - MockConfig() : Config() { } - MOCK_METHOD(InputFilter*, getInputFilter, (), (override)); - MOCK_METHOD(bool, isScreen, (const String&), (const, override)); + MockConfig() : Config() {} + MOCK_METHOD(InputFilter *, getInputFilter, (), (override)); + MOCK_METHOD(bool, isScreen, (const String &), (const, override)); }; diff --git a/src/test/mock/server/MockInputFilter.h b/src/test/mock/server/MockInputFilter.h index 3604b829d..443ab6ca8 100644 --- a/src/test/mock/server/MockInputFilter.h +++ b/src/test/mock/server/MockInputFilter.h @@ -23,8 +23,7 @@ #include "test/global/gmock.h" -class MockInputFilter : public InputFilter -{ +class MockInputFilter : public InputFilter { public: - MOCK_METHOD(void, setPrimaryClient, (PrimaryClient*), (override)); + MOCK_METHOD(void, setPrimaryClient, (PrimaryClient *), (override)); }; diff --git a/src/test/mock/server/MockPrimaryClient.h b/src/test/mock/server/MockPrimaryClient.h index c8a2f3e3a..318003a02 100644 --- a/src/test/mock/server/MockPrimaryClient.h +++ b/src/test/mock/server/MockPrimaryClient.h @@ -19,23 +19,22 @@ #define TEST_ENV -#include "server/PrimaryClient.h" #include "base/String.h" +#include "server/PrimaryClient.h" #include "test/global/gmock.h" -class MockPrimaryClient : public PrimaryClient -{ +class MockPrimaryClient : public PrimaryClient { public: - MOCK_METHOD(void*, getEventTarget, (), (const, override)); - MOCK_METHOD(void, getCursorPos, (SInt32&, SInt32&), (const, override)); - MOCK_METHOD(void, setJumpCursorPos, (SInt32, SInt32), (const)); - MOCK_METHOD(void, reconfigure, (UInt32), (override)); - MOCK_METHOD(void, resetOptions, (), (override)); - MOCK_METHOD(void, setOptions, (const OptionsList&), (override)); - MOCK_METHOD(void, enable, (), (override)); - MOCK_METHOD(void, disable, (), (override)); - MOCK_METHOD(UInt32, registerHotKey, (KeyID, KeyModifierMask), (override)); - MOCK_METHOD(KeyModifierMask, getToggleMask, (), (const, override)); - MOCK_METHOD(void, unregisterHotKey, (UInt32), (override)); + MOCK_METHOD(void *, getEventTarget, (), (const, override)); + MOCK_METHOD(void, getCursorPos, (SInt32 &, SInt32 &), (const, override)); + MOCK_METHOD(void, setJumpCursorPos, (SInt32, SInt32), (const)); + MOCK_METHOD(void, reconfigure, (UInt32), (override)); + MOCK_METHOD(void, resetOptions, (), (override)); + MOCK_METHOD(void, setOptions, (const OptionsList &), (override)); + MOCK_METHOD(void, enable, (), (override)); + MOCK_METHOD(void, disable, (), (override)); + MOCK_METHOD(UInt32, registerHotKey, (KeyID, KeyModifierMask), (override)); + MOCK_METHOD(KeyModifierMask, getToggleMask, (), (const, override)); + MOCK_METHOD(void, unregisterHotKey, (UInt32), (override)); }; diff --git a/src/test/mock/server/MockServer.h b/src/test/mock/server/MockServer.h index a2fa75b08..28cabfe05 100644 --- a/src/test/mock/server/MockServer.h +++ b/src/test/mock/server/MockServer.h @@ -25,8 +25,7 @@ class IEventQueue; -class MockServer : public Server -{ +class MockServer : public Server { public: - MockServer() : Server() { } + MockServer() : Server() {} }; diff --git a/src/test/mock/synergy/MockApp.h b/src/test/mock/synergy/MockApp.h index 94cfe844e..f2c199da3 100644 --- a/src/test/mock/synergy/MockApp.h +++ b/src/test/mock/synergy/MockApp.h @@ -23,22 +23,22 @@ #include "test/global/gmock.h" -class MockApp : public App -{ +class MockApp : public App { public: - MockApp() : App(NULL, NULL, NULL) { } + MockApp() : App(NULL, NULL, NULL) {} - MOCK_METHOD(void, help, (), (override)); - MOCK_METHOD(void, loadConfig, (), (override)); - MOCK_METHOD(bool, loadConfig, (const String&), (override)); - MOCK_METHOD(const char*, daemonInfo, (), (const, override)); - MOCK_METHOD(const char*, daemonName, (), (const, override)); - MOCK_METHOD(void, parseArgs, (int, const char* const*), (override)); - MOCK_METHOD(void, version, (), (override)); - MOCK_METHOD(int, standardStartup, (int, char**), (override)); - MOCK_METHOD(int, runInner, (int, char**, ILogOutputter*, StartupFunc), (override)); - MOCK_METHOD(void, startNode, (), (override)); - MOCK_METHOD(int, mainLoop, (), (override)); - MOCK_METHOD(int, foregroundStartup, (int, char**), (override)); - MOCK_METHOD(synergy::Screen*, createScreen, (), (override)); + MOCK_METHOD(void, help, (), (override)); + MOCK_METHOD(void, loadConfig, (), (override)); + MOCK_METHOD(bool, loadConfig, (const String &), (override)); + MOCK_METHOD(const char *, daemonInfo, (), (const, override)); + MOCK_METHOD(const char *, daemonName, (), (const, override)); + MOCK_METHOD(void, parseArgs, (int, const char *const *), (override)); + MOCK_METHOD(void, version, (), (override)); + MOCK_METHOD(int, standardStartup, (int, char **), (override)); + MOCK_METHOD(int, runInner, (int, char **, ILogOutputter *, StartupFunc), + (override)); + MOCK_METHOD(void, startNode, (), (override)); + MOCK_METHOD(int, mainLoop, (), (override)); + MOCK_METHOD(int, foregroundStartup, (int, char **), (override)); + MOCK_METHOD(synergy::Screen *, createScreen, (), (override)); }; diff --git a/src/test/mock/synergy/MockArgParser.h b/src/test/mock/synergy/MockArgParser.h index 9d34d3fe5..948fc56f7 100644 --- a/src/test/mock/synergy/MockArgParser.h +++ b/src/test/mock/synergy/MockArgParser.h @@ -23,11 +23,10 @@ #include "test/global/gmock.h" -class MockArgParser : public ArgParser -{ +class MockArgParser : public ArgParser { public: - MockArgParser() : ArgParser(NULL) { } + MockArgParser() : ArgParser(NULL) {} - MOCK_METHOD(bool, parseGenericArgs, (int, const char* const*, int&)); - MOCK_METHOD(bool, checkUnexpectedArgs, ()); + MOCK_METHOD(bool, parseGenericArgs, (int, const char *const *, int &)); + MOCK_METHOD(bool, checkUnexpectedArgs, ()); }; diff --git a/src/test/mock/synergy/MockEventQueue.h b/src/test/mock/synergy/MockEventQueue.h index 0e088df67..c1d1094ce 100644 --- a/src/test/mock/synergy/MockEventQueue.h +++ b/src/test/mock/synergy/MockEventQueue.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2011 Nick Bolton - * + * * 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 LICENSE 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 @@ -22,46 +22,50 @@ #include "test/global/gmock.h" -class MockEventQueue : public IEventQueue -{ +class MockEventQueue : public IEventQueue { public: - MOCK_METHOD(void, loop, (), (override)); - MOCK_METHOD(EventQueueTimer*, newOneShotTimer, (double, void*), (override)); - MOCK_METHOD(EventQueueTimer*, newTimer, (double, void*), (override)); - MOCK_METHOD(bool, getEvent, (Event&, double), (override)); - MOCK_METHOD(void, adoptBuffer, (IEventQueueBuffer*), (override)); - MOCK_METHOD(Event::Type, registerTypeOnce, (Event::Type&, const char*), (override)); - MOCK_METHOD(void, removeHandlers, (void*), (override)); - MOCK_METHOD(Event::Type, registerType, (const char*)); - MOCK_METHOD(bool, isEmpty, (), (const, override)); - MOCK_METHOD(void, adoptHandler, (Event::Type, void*, IEventJob*), (override)); - MOCK_METHOD(const char*, getTypeName, (Event::Type), (override)); - MOCK_METHOD(void, addEvent, (const Event&), (override)); - MOCK_METHOD(void, removeHandler, (Event::Type, void*), (override)); - MOCK_METHOD(bool, dispatchEvent, (const Event&), (override)); - MOCK_METHOD(IEventJob*, getHandler, (Event::Type, void*), (const, override)); - MOCK_METHOD(void, deleteTimer, (EventQueueTimer*), (override)); - MOCK_METHOD(Event::Type, getRegisteredType, (const String&), (const, override)); - MOCK_METHOD(void*, getSystemTarget, (), (override)); - MOCK_METHOD(ClientEvents&, forClient, (), (override)); - MOCK_METHOD(IStreamEvents&, forIStream, (), (override)); - MOCK_METHOD(IpcClientEvents&, forIpcClient, (), (override)); - MOCK_METHOD(IpcClientProxyEvents&, forIpcClientProxy, (), (override)); - MOCK_METHOD(IpcServerEvents&, forIpcServer, (), (override)); - MOCK_METHOD(IpcServerProxyEvents&, forIpcServerProxy, (), (override)); - MOCK_METHOD(IDataSocketEvents&, forIDataSocket, (), (override)); - MOCK_METHOD(IListenSocketEvents&, forIListenSocket, (), (override)); - MOCK_METHOD(ISocketEvents&, forISocket, (), (override)); - MOCK_METHOD(OSXScreenEvents&, forOSXScreen, (), (override)); - MOCK_METHOD(ClientListenerEvents&, forClientListener, (), (override)); - MOCK_METHOD(ClientProxyEvents&, forClientProxy, (), (override)); - MOCK_METHOD(ClientProxyUnknownEvents&, forClientProxyUnknown, (), (override)); - MOCK_METHOD(ServerEvents&, forServer, (), (override)); - MOCK_METHOD(ServerAppEvents&, forServerApp, (), (override)); - MOCK_METHOD(IKeyStateEvents&, forIKeyState, (), (override)); - MOCK_METHOD(IPrimaryScreenEvents&, forIPrimaryScreen, (), (override)); - MOCK_METHOD(IScreenEvents&, forIScreen, (), (override)); - MOCK_METHOD(ClipboardEvents&, forClipboard, (), (override)); - MOCK_METHOD(FileEvents&, forFile, (), (override)); - MOCK_METHOD(void, waitForReady, (), (const, override)); + MOCK_METHOD(void, loop, (), (override)); + MOCK_METHOD(EventQueueTimer *, newOneShotTimer, (double, void *), (override)); + MOCK_METHOD(EventQueueTimer *, newTimer, (double, void *), (override)); + MOCK_METHOD(bool, getEvent, (Event &, double), (override)); + MOCK_METHOD(void, adoptBuffer, (IEventQueueBuffer *), (override)); + MOCK_METHOD(Event::Type, registerTypeOnce, (Event::Type &, const char *), + (override)); + MOCK_METHOD(void, removeHandlers, (void *), (override)); + MOCK_METHOD(Event::Type, registerType, (const char *)); + MOCK_METHOD(bool, isEmpty, (), (const, override)); + MOCK_METHOD(void, adoptHandler, (Event::Type, void *, IEventJob *), + (override)); + MOCK_METHOD(const char *, getTypeName, (Event::Type), (override)); + MOCK_METHOD(void, addEvent, (const Event &), (override)); + MOCK_METHOD(void, removeHandler, (Event::Type, void *), (override)); + MOCK_METHOD(bool, dispatchEvent, (const Event &), (override)); + MOCK_METHOD(IEventJob *, getHandler, (Event::Type, void *), + (const, override)); + MOCK_METHOD(void, deleteTimer, (EventQueueTimer *), (override)); + MOCK_METHOD(Event::Type, getRegisteredType, (const String &), + (const, override)); + MOCK_METHOD(void *, getSystemTarget, (), (override)); + MOCK_METHOD(ClientEvents &, forClient, (), (override)); + MOCK_METHOD(IStreamEvents &, forIStream, (), (override)); + MOCK_METHOD(IpcClientEvents &, forIpcClient, (), (override)); + MOCK_METHOD(IpcClientProxyEvents &, forIpcClientProxy, (), (override)); + MOCK_METHOD(IpcServerEvents &, forIpcServer, (), (override)); + MOCK_METHOD(IpcServerProxyEvents &, forIpcServerProxy, (), (override)); + MOCK_METHOD(IDataSocketEvents &, forIDataSocket, (), (override)); + MOCK_METHOD(IListenSocketEvents &, forIListenSocket, (), (override)); + MOCK_METHOD(ISocketEvents &, forISocket, (), (override)); + MOCK_METHOD(OSXScreenEvents &, forOSXScreen, (), (override)); + MOCK_METHOD(ClientListenerEvents &, forClientListener, (), (override)); + MOCK_METHOD(ClientProxyEvents &, forClientProxy, (), (override)); + MOCK_METHOD(ClientProxyUnknownEvents &, forClientProxyUnknown, (), + (override)); + MOCK_METHOD(ServerEvents &, forServer, (), (override)); + MOCK_METHOD(ServerAppEvents &, forServerApp, (), (override)); + MOCK_METHOD(IKeyStateEvents &, forIKeyState, (), (override)); + MOCK_METHOD(IPrimaryScreenEvents &, forIPrimaryScreen, (), (override)); + MOCK_METHOD(IScreenEvents &, forIScreen, (), (override)); + MOCK_METHOD(ClipboardEvents &, forClipboard, (), (override)); + MOCK_METHOD(FileEvents &, forFile, (), (override)); + MOCK_METHOD(void, waitForReady, (), (const, override)); }; diff --git a/src/test/mock/synergy/MockKeyMap.h b/src/test/mock/synergy/MockKeyMap.h index 9ed60d6f2..3cb5a043d 100644 --- a/src/test/mock/synergy/MockKeyMap.h +++ b/src/test/mock/synergy/MockKeyMap.h @@ -22,14 +22,15 @@ #include "test/global/gmock.h" -class MockKeyMap : public synergy::KeyMap -{ +class MockKeyMap : public synergy::KeyMap { public: - MOCK_METHOD(void, swap, (KeyMap&), (override)); - MOCK_METHOD(void, finish, (), (override)); - MOCK_METHOD(void, foreachKey, (ForeachKeyCallback, void*), (override)); - MOCK_METHOD(void, addHalfDuplexModifier, (KeyID), (override)); - MOCK_METHOD(bool, isHalfDuplex, (KeyID, KeyButton), (const, override)); - MOCK_METHOD(const KeyMap::KeyItem*, mapKey, (Keystrokes&, KeyID, SInt32, ModifierToKeys&, KeyModifierMask&, - KeyModifierMask, bool, const String&), (const, override)); + MOCK_METHOD(void, swap, (KeyMap &), (override)); + MOCK_METHOD(void, finish, (), (override)); + MOCK_METHOD(void, foreachKey, (ForeachKeyCallback, void *), (override)); + MOCK_METHOD(void, addHalfDuplexModifier, (KeyID), (override)); + MOCK_METHOD(bool, isHalfDuplex, (KeyID, KeyButton), (const, override)); + MOCK_METHOD(const KeyMap::KeyItem *, mapKey, + (Keystrokes &, KeyID, SInt32, ModifierToKeys &, KeyModifierMask &, + KeyModifierMask, bool, const String &), + (const, override)); }; diff --git a/src/test/mock/synergy/MockKeyState.h b/src/test/mock/synergy/MockKeyState.h index 28cfff464..48e2d2e15 100644 --- a/src/test/mock/synergy/MockKeyState.h +++ b/src/test/mock/synergy/MockKeyState.h @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2011 Nick Bolton - * + * * 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 LICENSE 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 @@ -27,31 +27,27 @@ class MockEventQueue; // NOTE: do not mock methods that are not pure virtual. this mock exists only // to provide an implementation of the KeyState abstract class. -class MockKeyState : public KeyState -{ +class MockKeyState : public KeyState { public: - MockKeyState(const MockEventQueue& eventQueue) : - KeyState((IEventQueue*)&eventQueue, {"en"}, true) - { - } + MockKeyState(const MockEventQueue &eventQueue) + : KeyState((IEventQueue *)&eventQueue, {"en"}, true) {} - MockKeyState(const MockEventQueue& eventQueue, const synergy::KeyMap& keyMap) : - KeyState((IEventQueue*)&eventQueue, (synergy::KeyMap&)keyMap, {"en"}, true) - { - } + MockKeyState(const MockEventQueue &eventQueue, const synergy::KeyMap &keyMap) + : KeyState((IEventQueue *)&eventQueue, (synergy::KeyMap &)keyMap, {"en"}, + true) {} - MOCK_METHOD(SInt32, pollActiveGroup, (), (const, override)); - MOCK_METHOD(KeyModifierMask, pollActiveModifiers, (), (const, override)); - MOCK_METHOD(bool, fakeCtrlAltDel, (), (override)); - MOCK_METHOD(void, getKeyMap, (synergy::KeyMap&), (override)); - MOCK_METHOD(void, fakeKey, (const Keystroke&), (override)); - MOCK_METHOD(bool, fakeMediaKey, (KeyID), (override)); - MOCK_METHOD(void, pollPressedKeys, (KeyButtonSet&), (const, override)); + MOCK_METHOD(SInt32, pollActiveGroup, (), (const, override)); + MOCK_METHOD(KeyModifierMask, pollActiveModifiers, (), (const, override)); + MOCK_METHOD(bool, fakeCtrlAltDel, (), (override)); + MOCK_METHOD(void, getKeyMap, (synergy::KeyMap &), (override)); + MOCK_METHOD(void, fakeKey, (const Keystroke &), (override)); + MOCK_METHOD(bool, fakeMediaKey, (KeyID), (override)); + MOCK_METHOD(void, pollPressedKeys, (KeyButtonSet &), (const, override)); }; typedef ::testing::NiceMock KeyStateImpl; typedef UInt32 KeyID; -typedef void (*ForeachKeyCallback)( - KeyID, SInt32 group, synergy::KeyMap::KeyItem&, void* userData); +typedef void (*ForeachKeyCallback)(KeyID, SInt32 group, + synergy::KeyMap::KeyItem &, void *userData); diff --git a/src/test/mock/synergy/MockScreen.h b/src/test/mock/synergy/MockScreen.h index 653b3e9ed..cc3f7a647 100644 --- a/src/test/mock/synergy/MockScreen.h +++ b/src/test/mock/synergy/MockScreen.h @@ -23,14 +23,14 @@ #include "test/global/gmock.h" -class MockScreen : public synergy::Screen -{ +class MockScreen : public synergy::Screen { public: - MockScreen() : synergy::Screen() { } - MOCK_METHOD(void, disable, (), (override)); - MOCK_METHOD(void, getShape, (SInt32&, SInt32&, SInt32&, SInt32&), (const, override)); - MOCK_METHOD(void, getCursorPos, (SInt32&, SInt32&), (const, override)); - MOCK_METHOD(void, resetOptions, (), (override)); - MOCK_METHOD(void, setOptions, (const OptionsList&), (override)); - MOCK_METHOD(void, enable, (), (override)); + MockScreen() : synergy::Screen() {} + MOCK_METHOD(void, disable, (), (override)); + MOCK_METHOD(void, getShape, (SInt32 &, SInt32 &, SInt32 &, SInt32 &), + (const, override)); + MOCK_METHOD(void, getCursorPos, (SInt32 &, SInt32 &), (const, override)); + MOCK_METHOD(void, resetOptions, (), (override)); + MOCK_METHOD(void, setOptions, (const OptionsList &), (override)); + MOCK_METHOD(void, enable, (), (override)); }; diff --git a/src/test/unittests/Main.cpp b/src/test/unittests/Main.cpp index 46e586a5e..978196be9 100644 --- a/src/test/unittests/Main.cpp +++ b/src/test/unittests/Main.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2011 Nick Bolton - * + * * 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 LICENSE 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 @@ -25,22 +25,20 @@ #include "test/global/gtest.h" -int -main(int argc, char **argv) -{ +int main(int argc, char **argv) { #if SYSAPI_WIN32 - // HACK: shouldn't be needed, but logging fails without this. - ArchMiscWindows::setInstanceWin32(GetModuleHandle(NULL)); + // HACK: shouldn't be needed, but logging fails without this. + ArchMiscWindows::setInstanceWin32(GetModuleHandle(NULL)); #endif - Arch arch; - arch.init(); - - Log log; - log.setFilter(kDEBUG4); + Arch arch; + arch.init(); + + Log log; + log.setFilter(kDEBUG4); + + testing::InitGoogleTest(&argc, argv); - testing::InitGoogleTest(&argc, argv); - // gtest seems to randomly finish with error codes (e.g. -1, -1073741819) // even when no tests have failed. not sure what causes this, but it // happens on all platforms and keeps leading to false positives. diff --git a/src/test/unittests/arch/IArchStringTests.cpp b/src/test/unittests/arch/IArchStringTests.cpp index badcb20a0..0cd3f64da 100644 --- a/src/test/unittests/arch/IArchStringTests.cpp +++ b/src/test/unittests/arch/IArchStringTests.cpp @@ -1,11 +1,11 @@ /* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2014-2016 Symless Ltd. - * + * * 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 LICENSE 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 @@ -18,40 +18,36 @@ #include "lib/arch/IArchString.h" #include "test/global/gtest.h" -class SampleIArchString: public IArchString { +class SampleIArchString : public IArchString { public: - EWideCharEncoding getWideCharEncoding() override { - return kUTF16; - } + EWideCharEncoding getWideCharEncoding() override { return kUTF16; } }; -TEST(IArchStringTests, convStringWCToMB_will_work_do_simple_conversions) -{ - SampleIArchString as; - char buff[20]; - bool errors; - auto converted = as.convStringWCToMB(buff, L"Hello", 6, &errors); - EXPECT_STREQ(buff, "Hello"); - EXPECT_EQ(converted, 6); - EXPECT_EQ(errors, false); +TEST(IArchStringTests, convStringWCToMB_will_work_do_simple_conversions) { + SampleIArchString as; + char buff[20]; + bool errors; + auto converted = as.convStringWCToMB(buff, L"Hello", 6, &errors); + EXPECT_STREQ(buff, "Hello"); + EXPECT_EQ(converted, 6); + EXPECT_EQ(errors, false); } -TEST(IArchStringTests, convStringWCToMB_will_work_do_simple_conversions_noresult) -{ - SampleIArchString as; - bool errors; - auto converted = as.convStringWCToMB(nullptr, L"Hello", 6, &errors); - EXPECT_EQ(converted, 6); - EXPECT_EQ(errors, false); +TEST(IArchStringTests, + convStringWCToMB_will_work_do_simple_conversions_noresult) { + SampleIArchString as; + bool errors; + auto converted = as.convStringWCToMB(nullptr, L"Hello", 6, &errors); + EXPECT_EQ(converted, 6); + EXPECT_EQ(errors, false); } -TEST(IArchStringTests, convStringMBToWC_will_work_do_simple_conversions) -{ - SampleIArchString as; - wchar_t buff[20]; - bool errors; - auto converted = as.convStringMBToWC(buff, "Hello", 6, &errors); - EXPECT_STREQ(buff, L"Hello"); - EXPECT_EQ(converted, 6); - EXPECT_EQ(errors, false); +TEST(IArchStringTests, convStringMBToWC_will_work_do_simple_conversions) { + SampleIArchString as; + wchar_t buff[20]; + bool errors; + auto converted = as.convStringMBToWC(buff, "Hello", 6, &errors); + EXPECT_STREQ(buff, L"Hello"); + EXPECT_EQ(converted, 6); + EXPECT_EQ(errors, false); } diff --git a/src/test/unittests/arch/unix/ArchNetworkBSDTests.cpp b/src/test/unittests/arch/unix/ArchNetworkBSDTests.cpp index 496163bc8..82332f45c 100644 --- a/src/test/unittests/arch/unix/ArchNetworkBSDTests.cpp +++ b/src/test/unittests/arch/unix/ArchNetworkBSDTests.cpp @@ -1,11 +1,11 @@ /* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2014-2016 Symless Ltd. - * + * * 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 LICENSE 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 @@ -16,48 +16,46 @@ */ #ifndef _WIN32 -#include -#include +#include "lib/arch/XArch.h" +#include "lib/arch/unix/ArchNetworkBSD.h" +#include "test/global/gtest.h" #include #include -#include "lib/arch/unix/ArchNetworkBSD.h" -#include "lib/arch/XArch.h" -#include "test/global/gtest.h" +#include +#include -TEST(ArchNetworkBSDTests, pollSocket_errs_EACCES) -{ - ArchNetworkBSD networkBSD; - ArchNetworkBSD::s_connectors.poll_impl = [](struct pollfd *, nfds_t, int){ errno = EACCES; return -1; }; - try { - std::array pe {{nullptr,0,0}}; - networkBSD.pollSocket(pe.data(), pe.size(), 1); - FAIL() << "Expected to throw"; - } - catch(XArchNetworkAccess const &err) - { - EXPECT_STREQ(err.what(), "Permission denied"); - } - catch(std::runtime_error const &baseerr) { - FAIL() << "Expected to throw XArchNetworkAccess but got " << baseerr.what(); - } +TEST(ArchNetworkBSDTests, pollSocket_errs_EACCES) { + ArchNetworkBSD networkBSD; + ArchNetworkBSD::s_connectors.poll_impl = [](struct pollfd *, nfds_t, int) { + errno = EACCES; + return -1; + }; + try { + std::array pe{{nullptr, 0, 0}}; + networkBSD.pollSocket(pe.data(), pe.size(), 1); + FAIL() << "Expected to throw"; + } catch (XArchNetworkAccess const &err) { + EXPECT_STREQ(err.what(), "Permission denied"); + } catch (std::runtime_error const &baseerr) { + FAIL() << "Expected to throw XArchNetworkAccess but got " << baseerr.what(); + } } -TEST(ArchNetworkBSDTests, isAnyAddr_IP6) -{ - ArchNetworkBSD networkBSD; - std::unique_ptr addr; - addr.reset(networkBSD.newAnyAddr(IArchNetwork::kINET6)); - EXPECT_TRUE(networkBSD.isAnyAddr(addr.get())); +TEST(ArchNetworkBSDTests, isAnyAddr_IP6) { + ArchNetworkBSD networkBSD; + std::unique_ptr addr; + addr.reset(networkBSD.newAnyAddr(IArchNetwork::kINET6)); + EXPECT_TRUE(networkBSD.isAnyAddr(addr.get())); - auto scratch = (char *)&addr->m_addr; - scratch[2] = 'b'; - scratch[3] = 'a'; - scratch[4] = 'd'; - scratch[5] = 'a'; - scratch[6] = 'd'; - scratch[7] = 'd'; - scratch[8] = 'r'; - EXPECT_FALSE(networkBSD.isAnyAddr(addr.get())); + auto scratch = (char *)&addr->m_addr; + scratch[2] = 'b'; + scratch[3] = 'a'; + scratch[4] = 'd'; + scratch[5] = 'a'; + scratch[6] = 'd'; + scratch[7] = 'd'; + scratch[8] = 'r'; + EXPECT_FALSE(networkBSD.isAnyAddr(addr.get())); } #endif // #ifdnef _WIN32 diff --git a/src/test/unittests/base/PathTests.cpp b/src/test/unittests/base/PathTests.cpp index 0303009e5..35afd4beb 100644 --- a/src/test/unittests/base/PathTests.cpp +++ b/src/test/unittests/base/PathTests.cpp @@ -20,21 +20,19 @@ #include "test/global/gtest.h" - -TEST(PathTests, open_file_using_path) -{ - std::string utf8FileName = "тіás.txt"; +TEST(PathTests, open_file_using_path) { + std::string utf8FileName = "тіás.txt"; #if SYSAPI_WIN32 - //Windows uses UTF-16 for file path and names - std::wstring fileName = L"\x0442\x0456\x00E1\x0073\x002E\x0074\x0078\x0074"; + // Windows uses UTF-16 for file path and names + std::wstring fileName = L"\x0442\x0456\x00E1\x0073\x002E\x0074\x0078\x0074"; #else - std::string fileName = utf8FileName; + std::string fileName = utf8FileName; #endif - std::fstream file(fileName, std::fstream::out); - file << "test"; - file.close(); + std::fstream file(fileName, std::fstream::out); + file << "test"; + file.close(); - std::ifstream inFile(synergy::filesystem::path(utf8FileName)); - EXPECT_TRUE(inFile.is_open()); + std::ifstream inFile(synergy::filesystem::path(utf8FileName)); + EXPECT_TRUE(inFile.is_open()); } diff --git a/src/test/unittests/base/StringTests.cpp b/src/test/unittests/base/StringTests.cpp index 7d5e939ec..ee6bc1345 100644 --- a/src/test/unittests/base/StringTests.cpp +++ b/src/test/unittests/base/StringTests.cpp @@ -1,11 +1,11 @@ /* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2014-2016 Symless Ltd. - * + * * 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 LICENSE 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 @@ -21,157 +21,142 @@ using namespace synergy; -TEST(StringTests, format_formatWithArguments_formatedString) -{ - const char* format = "%%%{1}=%{2}"; - const char* arg1 = "answer"; - const char* arg2 = "42"; +TEST(StringTests, format_formatWithArguments_formatedString) { + const char *format = "%%%{1}=%{2}"; + const char *arg1 = "answer"; + const char *arg2 = "42"; - String result = string::format(format, arg1, arg2); + String result = string::format(format, arg1, arg2); - EXPECT_EQ("%answer=42", result); + EXPECT_EQ("%answer=42", result); } -TEST(StringTests, findReplaceAll_inputString_replacedString) -{ - String subject = "foobar"; - String find = "bar"; - String replace = "baz"; +TEST(StringTests, findReplaceAll_inputString_replacedString) { + String subject = "foobar"; + String find = "bar"; + String replace = "baz"; - string::findReplaceAll(subject, find, replace); + string::findReplaceAll(subject, find, replace); - EXPECT_EQ("foobaz", subject); + EXPECT_EQ("foobaz", subject); } -TEST(StringTests, sprintf_formatWithArgument_formatedString) -{ - const char* format = "%s=%d"; - const char* arg1 = "answer"; - int arg2 = 42; +TEST(StringTests, sprintf_formatWithArgument_formatedString) { + const char *format = "%s=%d"; + const char *arg1 = "answer"; + int arg2 = 42; - String result = string::sprintf(format, arg1, arg2); + String result = string::sprintf(format, arg1, arg2); - EXPECT_EQ("answer=42", result); + EXPECT_EQ("answer=42", result); } -TEST(StringTests, toHex_plaintext_hexString) -{ - String subject = "foobar"; - int width = 2; +TEST(StringTests, toHex_plaintext_hexString) { + String subject = "foobar"; + int width = 2; - string::toHex(subject, width); + string::toHex(subject, width); - EXPECT_EQ("666f6f626172", subject); + EXPECT_EQ("666f6f626172", subject); } -TEST(StringTests, uppercase_lowercaseInput_uppercaseOutput) -{ - String subject = "12foo3BaR"; +TEST(StringTests, uppercase_lowercaseInput_uppercaseOutput) { + String subject = "12foo3BaR"; - string::uppercase(subject); + string::uppercase(subject); - EXPECT_EQ("12FOO3BAR", subject); + EXPECT_EQ("12FOO3BAR", subject); } -TEST(StringTests, removeChar_inputString_removeAllSpecifiedCharactors) -{ - String subject = "foobar"; - const char c = 'o'; +TEST(StringTests, removeChar_inputString_removeAllSpecifiedCharactors) { + String subject = "foobar"; + const char c = 'o'; - string::removeChar(subject, c); + string::removeChar(subject, c); - EXPECT_EQ("fbar", subject); + EXPECT_EQ("fbar", subject); } -TEST(StringTests, intToString_inputInt_outputString) -{ - size_t value = 123; +TEST(StringTests, intToString_inputInt_outputString) { + size_t value = 123; - String number = string::sizeTypeToString(value); + String number = string::sizeTypeToString(value); - EXPECT_EQ("123", number); + EXPECT_EQ("123", number); } -TEST(StringTests, stringToUint_inputString_outputInt) -{ - String number = "123"; +TEST(StringTests, stringToUint_inputString_outputInt) { + String number = "123"; - size_t value = string::stringToSizeType(number); + size_t value = string::stringToSizeType(number); - EXPECT_EQ(123, value); + EXPECT_EQ(123, value); } -TEST(StringTests, splitString_twoSeparator_returnThreeParts) -{ - String string = "stub1:stub2:stub3"; +TEST(StringTests, splitString_twoSeparator_returnThreeParts) { + String string = "stub1:stub2:stub3"; - std::vector results = string::splitString(string, ':'); + std::vector results = string::splitString(string, ':'); - EXPECT_EQ(3, results.size()); - EXPECT_EQ("stub1", results[0]); - EXPECT_EQ("stub2", results[1]); - EXPECT_EQ("stub3", results[2]); + EXPECT_EQ(3, results.size()); + EXPECT_EQ("stub1", results[0]); + EXPECT_EQ("stub2", results[1]); + EXPECT_EQ("stub3", results[2]); } -TEST(StringTests, splitString_oneSeparator_returnTwoParts) -{ - String string = "stub1:stub2"; +TEST(StringTests, splitString_oneSeparator_returnTwoParts) { + String string = "stub1:stub2"; - std::vector results = string::splitString(string, ':'); + std::vector results = string::splitString(string, ':'); - EXPECT_EQ(2, results.size()); - EXPECT_EQ("stub1", results[0]); - EXPECT_EQ("stub2", results[1]); + EXPECT_EQ(2, results.size()); + EXPECT_EQ("stub1", results[0]); + EXPECT_EQ("stub2", results[1]); } -TEST(StringTests, splitString_noSeparator_returnOriginalString) -{ - String string = "stub1"; +TEST(StringTests, splitString_noSeparator_returnOriginalString) { + String string = "stub1"; - std::vector results = string::splitString(string, ':'); + std::vector results = string::splitString(string, ':'); - EXPECT_EQ(1, results.size()); - EXPECT_EQ("stub1", results[0]); + EXPECT_EQ(1, results.size()); + EXPECT_EQ("stub1", results[0]); } -TEST(StringTests, splitString_emptyString_returnEmptyVector) -{ - String string; +TEST(StringTests, splitString_emptyString_returnEmptyVector) { + String string; - std::vector results = string::splitString(string, ':'); + std::vector results = string::splitString(string, ':'); - EXPECT_EQ(0, results.size()); + EXPECT_EQ(0, results.size()); } -TEST(StringTests, splitString_tailSeparator_returnTwoParts) -{ - String string = "stub1:stub2:"; +TEST(StringTests, splitString_tailSeparator_returnTwoParts) { + String string = "stub1:stub2:"; - std::vector results = string::splitString(string, ':'); + std::vector results = string::splitString(string, ':'); - EXPECT_EQ(2, results.size()); - EXPECT_EQ("stub1", results[0]); - EXPECT_EQ("stub2", results[1]); + EXPECT_EQ(2, results.size()); + EXPECT_EQ("stub1", results[0]); + EXPECT_EQ("stub2", results[1]); } -TEST(StringTests, splitString_headSeparator_returnTwoParts) -{ - String string = ":stub1:stub2"; +TEST(StringTests, splitString_headSeparator_returnTwoParts) { + String string = ":stub1:stub2"; - std::vector results = string::splitString(string, ':'); + std::vector results = string::splitString(string, ':'); - EXPECT_EQ(2, results.size()); - EXPECT_EQ("stub1", results[0]); - EXPECT_EQ("stub2", results[1]); + EXPECT_EQ(2, results.size()); + EXPECT_EQ("stub1", results[0]); + EXPECT_EQ("stub2", results[1]); } -TEST(StringTests, splitString_headAndTailSeparators_returnTwoParts) -{ - String string = ":stub1:stub2:"; +TEST(StringTests, splitString_headAndTailSeparators_returnTwoParts) { + String string = ":stub1:stub2:"; - std::vector results = string::splitString(string, ':'); + std::vector results = string::splitString(string, ':'); - EXPECT_EQ(2, results.size()); - EXPECT_EQ("stub1", results[0]); - EXPECT_EQ("stub2", results[1]); + EXPECT_EQ(2, results.size()); + EXPECT_EQ("stub1", results[0]); + EXPECT_EQ("stub2", results[1]); } diff --git a/src/test/unittests/base/UnicodeTests.cpp b/src/test/unittests/base/UnicodeTests.cpp index 088b0a1bb..bea44cf74 100644 --- a/src/test/unittests/base/UnicodeTests.cpp +++ b/src/test/unittests/base/UnicodeTests.cpp @@ -1,11 +1,11 @@ /* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2014-2016 Symless Ltd. - * + * * 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 LICENSE 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 @@ -15,43 +15,40 @@ * along with this program. If not, see . */ -#include #include "arch/IArchString.h" #include "base/Unicode.h" #include "test/global/gtest.h" +#include -TEST(UnicodeTests, doUTF32ToUTF8_will_convert_simple_string) -{ - bool errors; - auto result = Unicode::UTF32ToUTF8(String("h\0\0\0e\0\0\0l\0\0\0l\0\0\0o\0\0\0", 20), &errors); - EXPECT_FALSE(errors); - EXPECT_STREQ(result.c_str(), "hello"); +TEST(UnicodeTests, doUTF32ToUTF8_will_convert_simple_string) { + bool errors; + auto result = Unicode::UTF32ToUTF8( + String("h\0\0\0e\0\0\0l\0\0\0l\0\0\0o\0\0\0", 20), &errors); + EXPECT_FALSE(errors); + EXPECT_STREQ(result.c_str(), "hello"); } -TEST(UnicodeTests, doUTF16ToUTF8_will_convert_simple_string) -{ - bool errors; - auto result = Unicode::UTF16ToUTF8(String("h\0e\0l\0l\0o\0", 10), &errors); - EXPECT_FALSE(errors); - EXPECT_STREQ(result.c_str(), "hello"); +TEST(UnicodeTests, doUTF16ToUTF8_will_convert_simple_string) { + bool errors; + auto result = Unicode::UTF16ToUTF8(String("h\0e\0l\0l\0o\0", 10), &errors); + EXPECT_FALSE(errors); + EXPECT_STREQ(result.c_str(), "hello"); } -TEST(UnicodeTests, doUCS2ToUTF8_will_convert_simple_string_kUCS2) -{ - bool errors; - auto result = Unicode::textToUTF8("hello", &errors, IArchString::kUCS2); - EXPECT_FALSE(errors); +TEST(UnicodeTests, doUCS2ToUTF8_will_convert_simple_string_kUCS2) { + bool errors; + auto result = Unicode::textToUTF8("hello", &errors, IArchString::kUCS2); + EXPECT_FALSE(errors); #ifdef _WIN32 - EXPECT_EQ(result, String("hello", 5)); // mixed-platform expected result + EXPECT_EQ(result, String("hello", 5)); // mixed-platform expected result #else - EXPECT_EQ(result, String("h\0e\0l", 5)); // mixed-platform expected result + EXPECT_EQ(result, String("h\0e\0l", 5)); // mixed-platform expected result #endif // _WIN32 } -TEST(UnicodeTests, doUCS2ToUTF8_will_convert_simple_string_any_platform) -{ - bool errors; - auto result = Unicode::textToUTF8("hello", &errors); - EXPECT_FALSE(errors); - EXPECT_EQ(result, String("hello", 5)); // mixed-platform expected result +TEST(UnicodeTests, doUCS2ToUTF8_will_convert_simple_string_any_platform) { + bool errors; + auto result = Unicode::textToUTF8("hello", &errors); + EXPECT_FALSE(errors); + EXPECT_EQ(result, String("hello", 5)); // mixed-platform expected result } diff --git a/src/test/unittests/ipc/IpcLogOutputterTests.cpp b/src/test/unittests/ipc/IpcLogOutputterTests.cpp index 328b8dc65..8adf67486 100644 --- a/src/test/unittests/ipc/IpcLogOutputterTests.cpp +++ b/src/test/unittests/ipc/IpcLogOutputterTests.cpp @@ -1,11 +1,11 @@ /* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2015-2016 Symless Ltd. - * + * * 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 LICENSE 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 @@ -19,10 +19,10 @@ #include "test/mock/ipc/MockIpcServer.h" -#include "mt/Thread.h" -#include "ipc/IpcLogOutputter.h" #include "base/String.h" #include "common/common.h" +#include "ipc/IpcLogOutputter.h" +#include "mt/Thread.h" #include "test/global/gmock.h" #include "test/global/gtest.h" @@ -31,138 +31,144 @@ #if WINAPI_MSWINDOWS using ::testing::_; -using ::testing::Return; +using ::testing::AtLeast; using ::testing::Matcher; using ::testing::MatcherCast; using ::testing::Property; +using ::testing::Return; using ::testing::StrEq; -using ::testing::AtLeast; using namespace synergy; -//TODO Fix the IPC Tests for windows, see #6709 -// Tests disabled due to gtest/gmock update causing build problems -// Decision to disable tests and create issue instead due to time constraints -//inline const Matcher IpcLogLineMessageEq(const String& s) { -// const Matcher m( -// Property(&IpcLogLineMessage::logLine, StrEq(s))); -// return MatcherCast(m); -//} +// TODO Fix the IPC Tests for windows, see #6709 +// Tests disabled due to gtest/gmock update causing build problems +// Decision to disable tests and create issue instead due to time constraints +// inline const Matcher IpcLogLineMessageEq(const String& s) +// { +// const Matcher m( +// Property(&IpcLogLineMessage::logLine, StrEq(s))); +// return MatcherCast(m); +// } // -//TEST(IpcLogOutputterTests, write_threadingEnabled_bufferIsSent) +// TEST(IpcLogOutputterTests, write_threadingEnabled_bufferIsSent) //{ -// MockIpcServer mockServer; -// mockServer.delegateToFake(); +// MockIpcServer mockServer; +// mockServer.delegateToFake(); // -// ON_CALL(mockServer, hasClients(_)).WillByDefault(Return(true)); +// ON_CALL(mockServer, hasClients(_)).WillByDefault(Return(true)); // -// EXPECT_CALL(mockServer, hasClients(_)).Times(AtLeast(3)); -// EXPECT_CALL(mockServer, send(IpcLogLineMessageEq("mock 1\n"), _)).Times(1); -// EXPECT_CALL(mockServer, send(IpcLogLineMessageEq("mock 2\n"), _)).Times(1); +// EXPECT_CALL(mockServer, hasClients(_)).Times(AtLeast(3)); +// EXPECT_CALL(mockServer, send(IpcLogLineMessageEq("mock 1\n"), +// _)).Times(1); EXPECT_CALL(mockServer, send(IpcLogLineMessageEq("mock +// 2\n"), _)).Times(1); // -// IpcLogOutputter outputter(mockServer, kIpcClientUnknown, true); -// outputter.write(kNOTE, "mock 1"); -// mockServer.waitForSend(); -// outputter.write(kNOTE, "mock 2"); -// mockServer.waitForSend(); -//} +// IpcLogOutputter outputter(mockServer, kIpcClientUnknown, true); +// outputter.write(kNOTE, "mock 1"); +// mockServer.waitForSend(); +// outputter.write(kNOTE, "mock 2"); +// mockServer.waitForSend(); +// } // -//TEST(IpcLogOutputterTests, write_overBufferMaxSize_firstLineTruncated) +// TEST(IpcLogOutputterTests, write_overBufferMaxSize_firstLineTruncated) //{ -// MockIpcServer mockServer; +// MockIpcServer mockServer; // -// ON_CALL(mockServer, hasClients(_)).WillByDefault(Return(true)); -// EXPECT_CALL(mockServer, hasClients(_)).Times(1); -// EXPECT_CALL(mockServer, send(IpcLogLineMessageEq("mock 2\nmock 3\n"), _)).Times(1); +// ON_CALL(mockServer, hasClients(_)).WillByDefault(Return(true)); +// EXPECT_CALL(mockServer, hasClients(_)).Times(1); +// EXPECT_CALL(mockServer, send(IpcLogLineMessageEq("mock 2\nmock 3\n"), +// _)).Times(1); // -// IpcLogOutputter outputter(mockServer, kIpcClientUnknown, false); -// outputter.bufferMaxSize(2); +// IpcLogOutputter outputter(mockServer, kIpcClientUnknown, false); +// outputter.bufferMaxSize(2); // -// // log more lines than the buffer can contain -// outputter.write(kNOTE, "mock 1"); -// outputter.write(kNOTE, "mock 2"); -// outputter.write(kNOTE, "mock 3"); -// outputter.sendBuffer(); -//} +// // log more lines than the buffer can contain +// outputter.write(kNOTE, "mock 1"); +// outputter.write(kNOTE, "mock 2"); +// outputter.write(kNOTE, "mock 3"); +// outputter.sendBuffer(); +// } // -//TEST(IpcLogOutputterTests, write_underBufferMaxSize_allLinesAreSent) +// TEST(IpcLogOutputterTests, write_underBufferMaxSize_allLinesAreSent) //{ -// MockIpcServer mockServer; +// MockIpcServer mockServer; // -// ON_CALL(mockServer, hasClients(_)).WillByDefault(Return(true)); +// ON_CALL(mockServer, hasClients(_)).WillByDefault(Return(true)); // -// EXPECT_CALL(mockServer, hasClients(_)).Times(1); -// EXPECT_CALL(mockServer, send(IpcLogLineMessageEq("mock 1\nmock 2\n"), _)).Times(1); +// EXPECT_CALL(mockServer, hasClients(_)).Times(1); +// EXPECT_CALL(mockServer, send(IpcLogLineMessageEq("mock 1\nmock 2\n"), +// _)).Times(1); // -// IpcLogOutputter outputter(mockServer, kIpcClientUnknown, false); -// outputter.bufferMaxSize(2); +// IpcLogOutputter outputter(mockServer, kIpcClientUnknown, false); +// outputter.bufferMaxSize(2); // -// // log more lines than the buffer can contain -// outputter.write(kNOTE, "mock 1"); -// outputter.write(kNOTE, "mock 2"); -// outputter.sendBuffer(); -//} +// // log more lines than the buffer can contain +// outputter.write(kNOTE, "mock 1"); +// outputter.write(kNOTE, "mock 2"); +// outputter.sendBuffer(); +// } // //// HACK: temporarily disable this intermittently failing unit test. //// when the build machine is under heavy load, a race condition //// usually happens. -//#if 0 -//TEST(IpcLogOutputterTests, write_overBufferRateLimit_lastLineTruncated) +// #if 0 +// TEST(IpcLogOutputterTests, write_overBufferRateLimit_lastLineTruncated) //{ -// MockIpcServer mockServer; +// MockIpcServer mockServer; // -// ON_CALL(mockServer, hasClients(_)).WillByDefault(Return(true)); +// ON_CALL(mockServer, hasClients(_)).WillByDefault(Return(true)); // -// EXPECT_CALL(mockServer, hasClients(_)).Times(2); -// EXPECT_CALL(mockServer, send(IpcLogLineMessageEq("mock 1\nmock 2\n"), _)).Times(1); -// EXPECT_CALL(mockServer, send(IpcLogLineMessageEq("mock 4\nmock 5\n"), _)).Times(1); +// EXPECT_CALL(mockServer, hasClients(_)).Times(2); +// EXPECT_CALL(mockServer, send(IpcLogLineMessageEq("mock 1\nmock 2\n"), +// _)).Times(1); EXPECT_CALL(mockServer, send(IpcLogLineMessageEq("mock +// 4\nmock 5\n"), _)).Times(1); // -// IpcLogOutputter outputter(mockServer, false); -// outputter.bufferRateLimit(2, 1); // 1s +// IpcLogOutputter outputter(mockServer, false); +// outputter.bufferRateLimit(2, 1); // 1s // -// // log 1 more line than the buffer can accept in time limit. -// outputter.write(kNOTE, "mock 1"); -// outputter.write(kNOTE, "mock 2"); -// outputter.write(kNOTE, "mock 3"); +// // log 1 more line than the buffer can accept in time limit. +// outputter.write(kNOTE, "mock 1"); +// outputter.write(kNOTE, "mock 2"); +// outputter.write(kNOTE, "mock 3"); // -// outputter.sendBuffer(); +// outputter.sendBuffer(); // -// // after waiting the time limit send another to make sure -// // we can log after the time limit passes. -// // HACK: sleep causes the unit test to fail intermittently, -// // so lets try 100ms (there must be a better way to solve this) -// ARCH->sleep(2); // 2s -// outputter.write(kNOTE, "mock 4"); -// outputter.write(kNOTE, "mock 5"); -// outputter.write(kNOTE, "mock 6"); +// // after waiting the time limit send another to make sure +// // we can log after the time limit passes. +// // HACK: sleep causes the unit test to fail intermittently, +// // so lets try 100ms (there must be a better way to solve this) +// ARCH->sleep(2); // 2s +// outputter.write(kNOTE, "mock 4"); +// outputter.write(kNOTE, "mock 5"); +// outputter.write(kNOTE, "mock 6"); // -// outputter.sendBuffer(); -//} -//#endif +// outputter.sendBuffer(); +// } +// #endif // -//TEST(IpcLogOutputterTests, write_underBufferRateLimit_allLinesAreSent) +// TEST(IpcLogOutputterTests, write_underBufferRateLimit_allLinesAreSent) //{ -// MockIpcServer mockServer; +// MockIpcServer mockServer; // -// ON_CALL(mockServer, hasClients(_)).WillByDefault(Return(true)); +// ON_CALL(mockServer, hasClients(_)).WillByDefault(Return(true)); // -// EXPECT_CALL(mockServer, hasClients(_)).Times(2); -// EXPECT_CALL(mockServer, send(IpcLogLineMessageEq("mock 1\nmock 2\n"), _)).Times(1); -// EXPECT_CALL(mockServer, send(IpcLogLineMessageEq("mock 3\nmock 4\n"), _)).Times(1); +// EXPECT_CALL(mockServer, hasClients(_)).Times(2); +// EXPECT_CALL(mockServer, send(IpcLogLineMessageEq("mock 1\nmock 2\n"), +// _)).Times(1); EXPECT_CALL(mockServer, send(IpcLogLineMessageEq("mock +// 3\nmock 4\n"), _)).Times(1); // -// IpcLogOutputter outputter(mockServer, kIpcClientUnknown, false); -// outputter.bufferRateLimit(4, 1); // 1s (should be plenty of time) +// IpcLogOutputter outputter(mockServer, kIpcClientUnknown, false); +// outputter.bufferRateLimit(4, 1); // 1s (should be plenty of time) // -// // log 1 more line than the buffer can accept in time limit. -// outputter.write(kNOTE, "mock 1"); -// outputter.write(kNOTE, "mock 2"); -// outputter.sendBuffer(); +// // log 1 more line than the buffer can accept in time limit. +// outputter.write(kNOTE, "mock 1"); +// outputter.write(kNOTE, "mock 2"); +// outputter.sendBuffer(); // -// // after waiting the time limit send another to make sure -// // we can log after the time limit passes. -// outputter.write(kNOTE, "mock 3"); -// outputter.write(kNOTE, "mock 4"); -// outputter.sendBuffer(); -//} +// // after waiting the time limit send another to make sure +// // we can log after the time limit passes. +// outputter.write(kNOTE, "mock 3"); +// outputter.write(kNOTE, "mock 4"); +// outputter.sendBuffer(); +// } #endif // WINAPI_MSWINDOWS diff --git a/src/test/unittests/ipc/IpcSettingMessageTests.cpp b/src/test/unittests/ipc/IpcSettingMessageTests.cpp index 7b42893f6..10aa1a084 100644 --- a/src/test/unittests/ipc/IpcSettingMessageTests.cpp +++ b/src/test/unittests/ipc/IpcSettingMessageTests.cpp @@ -21,11 +21,11 @@ #include "test/global/gtest.h" TEST(IpcSettingMessage, testIpcSettingMessage) { - const std::string expected_name = "test"; - const std::string expected_value = "test_value"; + const std::string expected_name = "test"; + const std::string expected_value = "test_value"; - IpcSettingMessage message("test", "test_value"); + IpcSettingMessage message("test", "test_value"); - EXPECT_EQ(expected_name, message.getName()); - EXPECT_EQ(expected_value, message.getValue()); + EXPECT_EQ(expected_name, message.getName()); + EXPECT_EQ(expected_value, message.getValue()); } diff --git a/src/test/unittests/platform/OSXClipboardUTF8ConverterTest.cpp b/src/test/unittests/platform/OSXClipboardUTF8ConverterTest.cpp index 941daae42..9a94f4204 100644 --- a/src/test/unittests/platform/OSXClipboardUTF8ConverterTest.cpp +++ b/src/test/unittests/platform/OSXClipboardUTF8ConverterTest.cpp @@ -19,16 +19,14 @@ #include "platform/OSXClipboardUTF8Converter.h" #include "test/global/gtest.h" -TEST(OSXClipboardUTF8ConverterTests, test_Format) -{ - OSXClipboardUTF8Converter converter; - EXPECT_EQ(IClipboard::kText, converter.getFormat()); - EXPECT_EQ(CFSTR("public.utf8-plain-text"), converter.getOSXFormat()); +TEST(OSXClipboardUTF8ConverterTests, test_Format) { + OSXClipboardUTF8Converter converter; + EXPECT_EQ(IClipboard::kText, converter.getFormat()); + EXPECT_EQ(CFSTR("public.utf8-plain-text"), converter.getOSXFormat()); } -TEST(OSXClipboardUTF8ConverterTests, test_readWriteClipboard) -{ - OSXClipboardUTF8Converter converter; - EXPECT_EQ("test data\r", converter.fromIClipboard("test data\n")); - EXPECT_EQ("test data\n", converter.toIClipboard("test data\r")); +TEST(OSXClipboardUTF8ConverterTests, test_readWriteClipboard) { + OSXClipboardUTF8Converter converter; + EXPECT_EQ("test data\r", converter.fromIClipboard("test data\n")); + EXPECT_EQ("test data\n", converter.toIClipboard("test data\r")); } diff --git a/src/test/unittests/platform/OSXKeyStateTests.cpp b/src/test/unittests/platform/OSXKeyStateTests.cpp index ed21f9212..d638f81c9 100644 --- a/src/test/unittests/platform/OSXKeyStateTests.cpp +++ b/src/test/unittests/platform/OSXKeyStateTests.cpp @@ -16,42 +16,41 @@ * along with this program. If not, see . */ -#include "test/mock/synergy/MockKeyMap.h" -#include "test/mock/synergy/MockEventQueue.h" #include "platform/OSXKeyState.h" +#include "test/mock/synergy/MockEventQueue.h" +#include "test/mock/synergy/MockKeyMap.h" -#include "test/global/gtest.h" #include "test/global/gmock.h" +#include "test/global/gtest.h" -TEST(OSXKeyStateTests, mapModifiersFromOSX_OSXMask_returnSynergyMask) -{ - synergy::KeyMap keyMap; - MockEventQueue eventQueue; - OSXKeyState keyState(&eventQueue, keyMap, { "en" }, true); +TEST(OSXKeyStateTests, mapModifiersFromOSX_OSXMask_returnSynergyMask) { + synergy::KeyMap keyMap; + MockEventQueue eventQueue; + OSXKeyState keyState(&eventQueue, keyMap, {"en"}, true); - KeyModifierMask outMask = 0; - - UInt32 shiftMask = 0 | kCGEventFlagMaskShift; - outMask = keyState.mapModifiersFromOSX(shiftMask); - EXPECT_EQ(KeyModifierShift, outMask); - - UInt32 ctrlMask = 0 | kCGEventFlagMaskControl; - outMask = keyState.mapModifiersFromOSX(ctrlMask); - EXPECT_EQ(KeyModifierControl, outMask); - - UInt32 altMask = 0 | kCGEventFlagMaskAlternate; - outMask = keyState.mapModifiersFromOSX(altMask); - EXPECT_EQ(KeyModifierAlt, outMask); - - UInt32 cmdMask = 0 | kCGEventFlagMaskCommand; - outMask = keyState.mapModifiersFromOSX(cmdMask); - EXPECT_EQ(KeyModifierSuper, outMask); - - UInt32 capsMask = 0 | kCGEventFlagMaskAlphaShift; - outMask = keyState.mapModifiersFromOSX(capsMask); - EXPECT_EQ(KeyModifierCapsLock, outMask); - - UInt32 numMask = 0 | kCGEventFlagMaskNumericPad; - outMask = keyState.mapModifiersFromOSX(numMask); - EXPECT_EQ(KeyModifierNumLock, outMask); + KeyModifierMask outMask = 0; + + UInt32 shiftMask = 0 | kCGEventFlagMaskShift; + outMask = keyState.mapModifiersFromOSX(shiftMask); + EXPECT_EQ(KeyModifierShift, outMask); + + UInt32 ctrlMask = 0 | kCGEventFlagMaskControl; + outMask = keyState.mapModifiersFromOSX(ctrlMask); + EXPECT_EQ(KeyModifierControl, outMask); + + UInt32 altMask = 0 | kCGEventFlagMaskAlternate; + outMask = keyState.mapModifiersFromOSX(altMask); + EXPECT_EQ(KeyModifierAlt, outMask); + + UInt32 cmdMask = 0 | kCGEventFlagMaskCommand; + outMask = keyState.mapModifiersFromOSX(cmdMask); + EXPECT_EQ(KeyModifierSuper, outMask); + + UInt32 capsMask = 0 | kCGEventFlagMaskAlphaShift; + outMask = keyState.mapModifiersFromOSX(capsMask); + EXPECT_EQ(KeyModifierCapsLock, outMask); + + UInt32 numMask = 0 | kCGEventFlagMaskNumericPad; + outMask = keyState.mapModifiersFromOSX(numMask); + EXPECT_EQ(KeyModifierNumLock, outMask); } diff --git a/src/test/unittests/server/ConfigTests.cpp b/src/test/unittests/server/ConfigTests.cpp index df15241df..ff631cb4b 100644 --- a/src/test/unittests/server/ConfigTests.cpp +++ b/src/test/unittests/server/ConfigTests.cpp @@ -1,11 +1,11 @@ /* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2014-2016 Symless Ltd. - * + * * 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 LICENSE 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 @@ -19,236 +19,244 @@ #include "net/XSocket.h" #include "test/global/gtest.h" -class OnlySystemFilter: public InputFilter::Condition { - public: - Condition* clone() const override { - return new OnlySystemFilter(); - } - String format() const override { - return ""; - } +class OnlySystemFilter : public InputFilter::Condition { +public: + Condition *clone() const override { return new OnlySystemFilter(); } + String format() const override { return ""; } - InputFilter::EFilterStatus match(const Event& ev) override { - return ev.getType() == Event::kSystem ? InputFilter::kActivate : InputFilter::kNoMatch; - } + InputFilter::EFilterStatus match(const Event &ev) override { + return ev.getType() == Event::kSystem ? InputFilter::kActivate + : InputFilter::kNoMatch; + } }; -TEST(ServerConfigTests, serverconfig_will_deem_inequal_configs_with_different_map_size) -{ - Config a(nullptr); - Config b(nullptr); - a.addScreen("screenA"); - EXPECT_FALSE(a == b); - EXPECT_FALSE(b == a); +TEST(ServerConfigTests, + serverconfig_will_deem_inequal_configs_with_different_map_size) { + Config a(nullptr); + Config b(nullptr); + a.addScreen("screenA"); + EXPECT_FALSE(a == b); + EXPECT_FALSE(b == a); } -TEST(ServerConfigTests, serverconfig_will_deem_inequal_configs_with_different_cell_names) -{ - Config a(nullptr); - Config b(nullptr); - a.addScreen("screenA"); - b.addScreen("screenB"); - EXPECT_FALSE(a == b); - EXPECT_FALSE(b == a); +TEST(ServerConfigTests, + serverconfig_will_deem_inequal_configs_with_different_cell_names) { + Config a(nullptr); + Config b(nullptr); + a.addScreen("screenA"); + b.addScreen("screenB"); + EXPECT_FALSE(a == b); + EXPECT_FALSE(b == a); } -TEST(ServerConfigTests, serverconfig_will_deem_equal_configs_with_same_cell_names) -{ - Config a(nullptr); - Config b(nullptr); - EXPECT_TRUE(a.addScreen("screenA")); - EXPECT_TRUE(a.addScreen("screenB")); - EXPECT_TRUE(a.addScreen("screenC")); - EXPECT_TRUE(a.connect("screenA", EDirection::kBottom, 0.0f, 0.5f, "screenB", 0.5f, 1.0f)); - EXPECT_TRUE(a.connect("screenB", EDirection::kLeft, 0.0f, 0.5f, "screenB", 0.5f, 1.0f)); - EXPECT_TRUE(b.addScreen("screenA")); - EXPECT_TRUE(b.addScreen("screenB")); - EXPECT_TRUE(b.addScreen("screenC")); - EXPECT_TRUE(b.connect("screenA", EDirection::kBottom, 0.0f, 0.5f, "screenB", 0.5f, 1.0f)); - EXPECT_TRUE(b.connect("screenB", EDirection::kLeft, 0.0f, 0.5f, "screenB", 0.5f, 1.0f)); - a.addOption("screenA", kOptionClipboardSharing, 1); - b.addOption("screenA", kOptionClipboardSharing, 1); - a.addOption(std::string(), kOptionClipboardSharing, 1); - b.addOption(std::string(), kOptionClipboardSharing, 1); - a.getInputFilter()->addFilterRule(InputFilter::Rule{new OnlySystemFilter()}); - b.getInputFilter()->addFilterRule(InputFilter::Rule{new OnlySystemFilter()}); - a.addAlias("screenA", "aliasA"); - b.addAlias("screenA", "aliasA"); - NetworkAddress addr1("localhost", 8080); - addr1.resolve(); - NetworkAddress addr2("localhost", 8080); - addr2.resolve(); - a.setSynergyAddress(addr1); - b.setSynergyAddress(addr2); +TEST(ServerConfigTests, + serverconfig_will_deem_equal_configs_with_same_cell_names) { + Config a(nullptr); + Config b(nullptr); + EXPECT_TRUE(a.addScreen("screenA")); + EXPECT_TRUE(a.addScreen("screenB")); + EXPECT_TRUE(a.addScreen("screenC")); + EXPECT_TRUE(a.connect("screenA", EDirection::kBottom, 0.0f, 0.5f, "screenB", + 0.5f, 1.0f)); + EXPECT_TRUE(a.connect("screenB", EDirection::kLeft, 0.0f, 0.5f, "screenB", + 0.5f, 1.0f)); + EXPECT_TRUE(b.addScreen("screenA")); + EXPECT_TRUE(b.addScreen("screenB")); + EXPECT_TRUE(b.addScreen("screenC")); + EXPECT_TRUE(b.connect("screenA", EDirection::kBottom, 0.0f, 0.5f, "screenB", + 0.5f, 1.0f)); + EXPECT_TRUE(b.connect("screenB", EDirection::kLeft, 0.0f, 0.5f, "screenB", + 0.5f, 1.0f)); + a.addOption("screenA", kOptionClipboardSharing, 1); + b.addOption("screenA", kOptionClipboardSharing, 1); + a.addOption(std::string(), kOptionClipboardSharing, 1); + b.addOption(std::string(), kOptionClipboardSharing, 1); + a.getInputFilter()->addFilterRule(InputFilter::Rule{new OnlySystemFilter()}); + b.getInputFilter()->addFilterRule(InputFilter::Rule{new OnlySystemFilter()}); + a.addAlias("screenA", "aliasA"); + b.addAlias("screenA", "aliasA"); + NetworkAddress addr1("localhost", 8080); + addr1.resolve(); + NetworkAddress addr2("localhost", 8080); + addr2.resolve(); + a.setSynergyAddress(addr1); + b.setSynergyAddress(addr2); - EXPECT_TRUE(a == b); - EXPECT_TRUE(b == a); + EXPECT_TRUE(a == b); + EXPECT_TRUE(b == a); } -TEST(NetworkAddress, hostname_valid_parsing) -{ - const int validPort = 24900; - const String portStr = std::to_string(validPort); +TEST(NetworkAddress, hostname_valid_parsing) { + const int validPort = 24900; + const String portStr = std::to_string(validPort); - //list of test cases. 1 param - hostname for parsing, 2 param - port, 3 param - expected hostname - const std::initializer_list> validTestCases = { - std::make_tuple(String("127.0.0.1"), validPort, "127.0.0.1"), - std::make_tuple(String("127.0.0.1:") + portStr, 0, "127.0.0.1"), - std::make_tuple(String("localhost"), validPort, "localhost"), - std::make_tuple(String("localhost:") + portStr, 0, "localhost"), - std::make_tuple(String(""), validPort, ""), - std::make_tuple(String(":") + portStr, 0, ""), - //Temporary disabled tests for ipv6 - //std::make_tuple(String("[::1]:") + portStr, 0, "::1"), - //std::make_tuple(String("[fe80::a156:9f36:793:7bfb%14]:") + portStr, 0, "fe80::a156:9f36:793:7bfb%14"), - //std::make_tuple(String("::1"), validPort, "::1"), - //std::make_tuple(String("fe80::a156:9f36:793:7bfb%14"), validPort, "fe80::a156:9f36:793:7bfb%14"), - //std::make_tuple(String("fe80:0000:0000:0000:a156:9f36:793:7bfb%14"), validPort, "fe80:0000:0000:0000:a156:9f36:793:7bfb%14"), - }; + // list of test cases. 1 param - hostname for parsing, 2 param - port, 3 param + // - expected hostname + const std::initializer_list> validTestCases = { + std::make_tuple(String("127.0.0.1"), validPort, "127.0.0.1"), + std::make_tuple(String("127.0.0.1:") + portStr, 0, "127.0.0.1"), + std::make_tuple(String("localhost"), validPort, "localhost"), + std::make_tuple(String("localhost:") + portStr, 0, "localhost"), + std::make_tuple(String(""), validPort, ""), + std::make_tuple(String(":") + portStr, 0, ""), + // Temporary disabled tests for ipv6 + // std::make_tuple(String("[::1]:") + portStr, 0, "::1"), + // std::make_tuple(String("[fe80::a156:9f36:793:7bfb%14]:") + portStr, + // 0, "fe80::a156:9f36:793:7bfb%14"), + // std::make_tuple(String("::1"), validPort, "::1"), + // std::make_tuple(String("fe80::a156:9f36:793:7bfb%14"), validPort, + // "fe80::a156:9f36:793:7bfb%14"), + // std::make_tuple(String("fe80:0000:0000:0000:a156:9f36:793:7bfb%14"), + // validPort, "fe80:0000:0000:0000:a156:9f36:793:7bfb%14"), + }; - for (const auto &caseParams : validTestCases) { - NetworkAddress addr(std::get<0>(caseParams), std::get<1>(caseParams)); - addr.resolve(); + for (const auto &caseParams : validTestCases) { + NetworkAddress addr(std::get<0>(caseParams), std::get<1>(caseParams)); + addr.resolve(); - EXPECT_TRUE(addr.getHostname() == std::get<2>(caseParams)); - EXPECT_TRUE(addr.getPort() == validPort); - EXPECT_TRUE(addr.getAddress() != nullptr); + EXPECT_TRUE(addr.getHostname() == std::get<2>(caseParams)); + EXPECT_TRUE(addr.getPort() == validPort); + EXPECT_TRUE(addr.getAddress() != nullptr); + } + + // list of non valid hostnames + const std::initializer_list nonValidTestCases = { + ":nonValidPort", ":", + // Temporary disabled tests for ipv6 + //"[::1]:", + //"[::1]:nonValidPort", + //"fe80::1", + //"[::1]:-1", + //"[::1]:65536" + }; + + for (const auto &caseParam : nonValidTestCases) { + bool flag = false; + try { + NetworkAddress addr(caseParam, validPort); + } catch (const XSocketAddress &) { + + flag = true; } - //list of non valid hostnames - const std::initializer_list nonValidTestCases = { - ":nonValidPort", - ":", - //Temporary disabled tests for ipv6 - //"[::1]:", - //"[::1]:nonValidPort", - //"fe80::1", - //"[::1]:-1", - //"[::1]:65536" - }; - - for (const auto &caseParam : nonValidTestCases) { - bool flag = false; - try { - NetworkAddress addr(caseParam, validPort); - } catch (const XSocketAddress&) { - - flag = true; - } - - EXPECT_TRUE(flag); - } + EXPECT_TRUE(flag); + } } -TEST(ServerConfigTests, serverconfig_will_deem_different_configs_with_same_cell_names_different_options) -{ - Config a(nullptr); - Config b(nullptr); - a.addScreen("screenA"); - b.addScreen("screenA"); - a.addOption("screenA", kOptionClipboardSharing, 0); - b.addOption("screenA", kOptionClipboardSharing, 1); - EXPECT_FALSE(a == b); - EXPECT_FALSE(b == a); +TEST( + ServerConfigTests, + serverconfig_will_deem_different_configs_with_same_cell_names_different_options) { + Config a(nullptr); + Config b(nullptr); + a.addScreen("screenA"); + b.addScreen("screenA"); + a.addOption("screenA", kOptionClipboardSharing, 0); + b.addOption("screenA", kOptionClipboardSharing, 1); + EXPECT_FALSE(a == b); + EXPECT_FALSE(b == a); } -TEST(ServerConfigTests, serverconfig_will_deem_different_configs_with_same_cell_names_different_aliases1) -{ - Config a(nullptr); - Config b(nullptr); - a.addScreen("screenA"); - b.addScreen("screenA"); - b.addAlias("screenA", "aliasA"); - EXPECT_FALSE(a == b); - EXPECT_FALSE(b == a); +TEST( + ServerConfigTests, + serverconfig_will_deem_different_configs_with_same_cell_names_different_aliases1) { + Config a(nullptr); + Config b(nullptr); + a.addScreen("screenA"); + b.addScreen("screenA"); + b.addAlias("screenA", "aliasA"); + EXPECT_FALSE(a == b); + EXPECT_FALSE(b == a); } -TEST(ServerConfigTests, serverconfig_will_deem_different_configs_with_same_cell_names_different_aliases2) -{ - Config a(nullptr); - Config b(nullptr); - a.addScreen("screenA"); - b.addScreen("screenA"); - a.addAlias("screenA", "aliasA"); - b.addAlias("screenA", "aliasB"); - EXPECT_FALSE(a == b); - EXPECT_FALSE(b == a); +TEST( + ServerConfigTests, + serverconfig_will_deem_different_configs_with_same_cell_names_different_aliases2) { + Config a(nullptr); + Config b(nullptr); + a.addScreen("screenA"); + b.addScreen("screenA"); + a.addAlias("screenA", "aliasA"); + b.addAlias("screenA", "aliasB"); + EXPECT_FALSE(a == b); + EXPECT_FALSE(b == a); } -TEST(ServerConfigTests, serverconfig_will_deem_different_configs_with_different_global_options) -{ - Config a(nullptr); - Config b(nullptr); - a.addScreen("screenA"); - b.addScreen("screenA"); - a.addOption(std::string(), kOptionClipboardSharing, 0); - b.addOption(std::string(), kOptionClipboardSharing, 1); - EXPECT_FALSE(a == b); - EXPECT_FALSE(b == a); +TEST(ServerConfigTests, + serverconfig_will_deem_different_configs_with_different_global_options) { + Config a(nullptr); + Config b(nullptr); + a.addScreen("screenA"); + b.addScreen("screenA"); + a.addOption(std::string(), kOptionClipboardSharing, 0); + b.addOption(std::string(), kOptionClipboardSharing, 1); + EXPECT_FALSE(a == b); + EXPECT_FALSE(b == a); } -TEST(ServerConfigTests, serverconfig_will_deem_different_configs_with_different_filters) -{ - Config a(nullptr); - Config b(nullptr); - a.addScreen("screenA"); - b.addScreen("screenA"); - a.getInputFilter()->addFilterRule(InputFilter::Rule{new OnlySystemFilter()}); - EXPECT_FALSE(a == b); - EXPECT_FALSE(b == a); +TEST(ServerConfigTests, + serverconfig_will_deem_different_configs_with_different_filters) { + Config a(nullptr); + Config b(nullptr); + a.addScreen("screenA"); + b.addScreen("screenA"); + a.getInputFilter()->addFilterRule(InputFilter::Rule{new OnlySystemFilter()}); + EXPECT_FALSE(a == b); + EXPECT_FALSE(b == a); } -TEST(ServerConfigTests, serverconfig_will_deem_different_configs_with_different_address) -{ - Config a(nullptr); - Config b(nullptr); - a.addScreen("screenA"); - b.addScreen("screenA"); - a.setSynergyAddress(NetworkAddress(8080)); - b.setSynergyAddress(NetworkAddress(1010)); - EXPECT_FALSE(a == b); - EXPECT_FALSE(b == a); +TEST(ServerConfigTests, + serverconfig_will_deem_different_configs_with_different_address) { + Config a(nullptr); + Config b(nullptr); + a.addScreen("screenA"); + b.addScreen("screenA"); + a.setSynergyAddress(NetworkAddress(8080)); + b.setSynergyAddress(NetworkAddress(1010)); + EXPECT_FALSE(a == b); + EXPECT_FALSE(b == a); } -TEST(ServerConfigTests, serverconfig_will_deem_different_cell_neighbours1) -{ - Config a(nullptr); - Config b(nullptr); - EXPECT_TRUE(a.addScreen("screenA")); - EXPECT_TRUE(a.addScreen("screenB")); - EXPECT_TRUE(a.connect("screenA", EDirection::kBottom, 0.0f, 0.5f, "screenB", 0.5f, 1.0f)); - EXPECT_TRUE(b.addScreen("screenA")); - EXPECT_TRUE(b.addScreen("screenB")); - EXPECT_FALSE(a == b); - EXPECT_FALSE(b == a); +TEST(ServerConfigTests, serverconfig_will_deem_different_cell_neighbours1) { + Config a(nullptr); + Config b(nullptr); + EXPECT_TRUE(a.addScreen("screenA")); + EXPECT_TRUE(a.addScreen("screenB")); + EXPECT_TRUE(a.connect("screenA", EDirection::kBottom, 0.0f, 0.5f, "screenB", + 0.5f, 1.0f)); + EXPECT_TRUE(b.addScreen("screenA")); + EXPECT_TRUE(b.addScreen("screenB")); + EXPECT_FALSE(a == b); + EXPECT_FALSE(b == a); } -TEST(ServerConfigTests, serverconfig_will_deem_different_cell_neighbours2) -{ - Config a(nullptr); - Config b(nullptr); - EXPECT_TRUE(a.addScreen("screenA")); - EXPECT_TRUE(a.addScreen("screenB")); - EXPECT_TRUE(a.connect("screenA", EDirection::kBottom, 0.0f, 0.5f, "screenB", 0.5f, 1.0f)); - EXPECT_TRUE(b.addScreen("screenA")); - EXPECT_TRUE(b.addScreen("screenB")); - EXPECT_TRUE(b.connect("screenA", EDirection::kBottom, 0.0f, 0.25f, "screenB", 0.25f, 1.0f)); - EXPECT_FALSE(a == b); - EXPECT_FALSE(b == a); +TEST(ServerConfigTests, serverconfig_will_deem_different_cell_neighbours2) { + Config a(nullptr); + Config b(nullptr); + EXPECT_TRUE(a.addScreen("screenA")); + EXPECT_TRUE(a.addScreen("screenB")); + EXPECT_TRUE(a.connect("screenA", EDirection::kBottom, 0.0f, 0.5f, "screenB", + 0.5f, 1.0f)); + EXPECT_TRUE(b.addScreen("screenA")); + EXPECT_TRUE(b.addScreen("screenB")); + EXPECT_TRUE(b.connect("screenA", EDirection::kBottom, 0.0f, 0.25f, "screenB", + 0.25f, 1.0f)); + EXPECT_FALSE(a == b); + EXPECT_FALSE(b == a); } -TEST(ServerConfigTests, serverconfig_will_deem_different_cell_neighbours3) -{ - Config a(nullptr); - Config b(nullptr); - EXPECT_TRUE(a.addScreen("screenA")); - EXPECT_TRUE(a.addScreen("screenB")); - EXPECT_TRUE(a.addScreen("screenC")); - EXPECT_TRUE(a.connect("screenA", EDirection::kBottom, 0.0f, 0.5f, "screenB", 0.5f, 1.0f)); - EXPECT_TRUE(b.addScreen("screenA")); - EXPECT_TRUE(b.addScreen("screenB")); - EXPECT_TRUE(b.addScreen("screenC")); - EXPECT_TRUE(b.connect("screenA", EDirection::kBottom, 0.0f, 0.5f, "screenC", 0.5f, 1.0f)); - EXPECT_FALSE(a == b); - EXPECT_FALSE(b == a); +TEST(ServerConfigTests, serverconfig_will_deem_different_cell_neighbours3) { + Config a(nullptr); + Config b(nullptr); + EXPECT_TRUE(a.addScreen("screenA")); + EXPECT_TRUE(a.addScreen("screenB")); + EXPECT_TRUE(a.addScreen("screenC")); + EXPECT_TRUE(a.connect("screenA", EDirection::kBottom, 0.0f, 0.5f, "screenB", + 0.5f, 1.0f)); + EXPECT_TRUE(b.addScreen("screenA")); + EXPECT_TRUE(b.addScreen("screenB")); + EXPECT_TRUE(b.addScreen("screenC")); + EXPECT_TRUE(b.connect("screenA", EDirection::kBottom, 0.0f, 0.5f, "screenC", + 0.5f, 1.0f)); + EXPECT_FALSE(a == b); + EXPECT_FALSE(b == a); } diff --git a/src/test/unittests/shared/SerialKeyEditionTests.cpp b/src/test/unittests/shared/SerialKeyEditionTests.cpp index 75d8ca8e4..176d6fe4d 100644 --- a/src/test/unittests/shared/SerialKeyEditionTests.cpp +++ b/src/test/unittests/shared/SerialKeyEditionTests.cpp @@ -20,88 +20,80 @@ #include "shared/SerialKeyEdition.h" #include "test/global/gtest.h" -TEST(SerialKeyEditionTests, DefaultEditionType_Unregistered) -{ - SerialKeyEdition edition; - EXPECT_EQ(kUnregistered, edition.getType()); - EXPECT_EQ(SerialKeyEdition::UNREGISTERED, edition.getName()); - EXPECT_EQ("Synergy 1 (UNREGISTERED)", edition.getDisplayName()); - EXPECT_FALSE(edition.isValid()); +TEST(SerialKeyEditionTests, DefaultEditionType_Unregistered) { + SerialKeyEdition edition; + EXPECT_EQ(kUnregistered, edition.getType()); + EXPECT_EQ(SerialKeyEdition::UNREGISTERED, edition.getName()); + EXPECT_EQ("Synergy 1 (UNREGISTERED)", edition.getDisplayName()); + EXPECT_FALSE(edition.isValid()); } -TEST(SerialKeyEditionTests, SetEditionType_edition) -{ - SerialKeyEdition edition; - edition.setType(kPro); - EXPECT_EQ(kPro, edition.getType()); - EXPECT_EQ(SerialKeyEdition::PRO, edition.getName()); - EXPECT_EQ("Synergy 1 Pro", edition.getDisplayName()); - EXPECT_TRUE(edition.isValid()); +TEST(SerialKeyEditionTests, SetEditionType_edition) { + SerialKeyEdition edition; + edition.setType(kPro); + EXPECT_EQ(kPro, edition.getType()); + EXPECT_EQ(SerialKeyEdition::PRO, edition.getName()); + EXPECT_EQ("Synergy 1 Pro", edition.getDisplayName()); + EXPECT_TRUE(edition.isValid()); } -TEST(SerialKeyEditionTests, SetEditionType_string) -{ - SerialKeyEdition edition; - edition.setType(SerialKeyEdition::BASIC); - EXPECT_EQ(kBasic, edition.getType()); - EXPECT_EQ(SerialKeyEdition::BASIC, edition.getName()); - EXPECT_EQ("Synergy 1 Basic", edition.getDisplayName()); +TEST(SerialKeyEditionTests, SetEditionType_string) { + SerialKeyEdition edition; + edition.setType(SerialKeyEdition::BASIC); + EXPECT_EQ(kBasic, edition.getType()); + EXPECT_EQ(SerialKeyEdition::BASIC, edition.getName()); + EXPECT_EQ("Synergy 1 Basic", edition.getDisplayName()); } -TEST(SerialKeyEditionTests, SetEditionBusiness) -{ - SerialKeyEdition edition; - edition.setType(kBusiness); - EXPECT_EQ(kBusiness, edition.getType()); - EXPECT_EQ(SerialKeyEdition::BUSINESS, edition.getName()); - EXPECT_EQ("Synergy 1 Business", edition.getDisplayName()); +TEST(SerialKeyEditionTests, SetEditionBusiness) { + SerialKeyEdition edition; + edition.setType(kBusiness); + EXPECT_EQ(kBusiness, edition.getType()); + EXPECT_EQ(SerialKeyEdition::BUSINESS, edition.getName()); + EXPECT_EQ("Synergy 1 Business", edition.getDisplayName()); } -TEST(SerialKeyEditionTests, SetEditionBasicChina) -{ - SerialKeyEdition edition; - edition.setType(kBasic_China); - EXPECT_EQ(kBasic_China, edition.getType()); - EXPECT_EQ(SerialKeyEdition::BASIC_CHINA, edition.getName()); - EXPECT_EQ("Synergy 中文版", edition.getDisplayName()); - EXPECT_TRUE(edition.isChina()); +TEST(SerialKeyEditionTests, SetEditionBasicChina) { + SerialKeyEdition edition; + edition.setType(kBasic_China); + EXPECT_EQ(kBasic_China, edition.getType()); + EXPECT_EQ(SerialKeyEdition::BASIC_CHINA, edition.getName()); + EXPECT_EQ("Synergy 中文版", edition.getDisplayName()); + EXPECT_TRUE(edition.isChina()); } -TEST(SerialKeyEditionTests, SetEditionProChina) -{ - SerialKeyEdition edition; - edition.setType(kPro_China); - EXPECT_EQ(kPro_China, edition.getType()); - EXPECT_EQ(SerialKeyEdition::PRO_CHINA, edition.getName()); - EXPECT_EQ("Synergy Pro 中文版", edition.getDisplayName()); - EXPECT_TRUE(edition.isChina()); +TEST(SerialKeyEditionTests, SetEditionProChina) { + SerialKeyEdition edition; + edition.setType(kPro_China); + EXPECT_EQ(kPro_China, edition.getType()); + EXPECT_EQ(SerialKeyEdition::PRO_CHINA, edition.getName()); + EXPECT_EQ("Synergy Pro 中文版", edition.getDisplayName()); + EXPECT_TRUE(edition.isChina()); } -TEST(SerialKeyEditionTests, NameConstructor) -{ - SerialKeyEdition edition(SerialKeyEdition::BUSINESS); - EXPECT_EQ(kBusiness, edition.getType()); - EXPECT_TRUE(edition.isValid()); +TEST(SerialKeyEditionTests, NameConstructor) { + SerialKeyEdition edition(SerialKeyEdition::BUSINESS); + EXPECT_EQ(kBusiness, edition.getType()); + EXPECT_TRUE(edition.isValid()); } -TEST(SerialKeyEditionTests, isValid) -{ - SerialKeyEdition edition; - edition.setType(Edition::kBasic); - EXPECT_TRUE(edition.isValid()); +TEST(SerialKeyEditionTests, isValid) { + SerialKeyEdition edition; + edition.setType(Edition::kBasic); + EXPECT_TRUE(edition.isValid()); - edition.setType(Edition::kBasic_China); - EXPECT_TRUE(edition.isValid()); + edition.setType(Edition::kBasic_China); + EXPECT_TRUE(edition.isValid()); - edition.setType(Edition::kBusiness); - EXPECT_TRUE(edition.isValid()); + edition.setType(Edition::kBusiness); + EXPECT_TRUE(edition.isValid()); - edition.setType(Edition::kPro); - EXPECT_TRUE(edition.isValid()); + edition.setType(Edition::kPro); + EXPECT_TRUE(edition.isValid()); - edition.setType(Edition::kPro_China); - EXPECT_TRUE(edition.isValid()); + edition.setType(Edition::kPro_China); + EXPECT_TRUE(edition.isValid()); - edition.setType(Edition::kUnregistered); - EXPECT_FALSE(edition.isValid()); + edition.setType(Edition::kUnregistered); + EXPECT_FALSE(edition.isValid()); } diff --git a/src/test/unittests/shared/SerialKeyTests.cpp b/src/test/unittests/shared/SerialKeyTests.cpp index eaf757115..9517aac9d 100644 --- a/src/test/unittests/shared/SerialKeyTests.cpp +++ b/src/test/unittests/shared/SerialKeyTests.cpp @@ -17,190 +17,188 @@ #define TEST_ENV -#include #include "shared/SerialKey.h" +#include #include "test/global/gtest.h" -TEST(SerialKeyTests, isExpiring_validV2TrialBasicSerial_returnFalse) -{ - // {v2;trial;basic;Bob;1;email;company name;1;86400} - SerialKey serial("7B76323B747269616C3B62617369633B426F623B313B656D61696C3B636F6D70616E79206E616D653B313B38363430307D"); - EXPECT_EQ(true, serial.isTrial()); - EXPECT_EQ(true, serial.isTemporary()); - EXPECT_FALSE(serial.isExpiring(0)); - EXPECT_EQ(kBasic, serial.edition()); +TEST(SerialKeyTests, isExpiring_validV2TrialBasicSerial_returnFalse) { + // {v2;trial;basic;Bob;1;email;company name;1;86400} + SerialKey serial("7B76323B747269616C3B62617369633B426F623B313B656D61696C3B636" + "F6D70616E79206E616D653B313B38363430307D"); + EXPECT_EQ(true, serial.isTrial()); + EXPECT_EQ(true, serial.isTemporary()); + EXPECT_FALSE(serial.isExpiring(0)); + EXPECT_EQ(kBasic, serial.edition()); } -TEST(SerialKeyTests, isExpiring_expiringV2TrialBasicSerial_returnTrue) -{ - // {v2;trial;basic;Bob;1;email;company name;0;86400} - SerialKey serial("7B76323B747269616C3B62617369633B426F623B313B656D61696C3B636F6D70616E79206E616D653B303B38363430307D"); - EXPECT_EQ(true, serial.isTrial()); - EXPECT_EQ(true, serial.isTemporary()); - EXPECT_EQ(true, serial.isExpiring(1)); +TEST(SerialKeyTests, isExpiring_expiringV2TrialBasicSerial_returnTrue) { + // {v2;trial;basic;Bob;1;email;company name;0;86400} + SerialKey serial("7B76323B747269616C3B62617369633B426F623B313B656D61696C3B636" + "F6D70616E79206E616D653B303B38363430307D"); + EXPECT_EQ(true, serial.isTrial()); + EXPECT_EQ(true, serial.isTemporary()); + EXPECT_EQ(true, serial.isExpiring(1)); } -TEST(SerialKeyTests, isExpiring_expiredV2TrialBasicSerial_returnFalse) -{ - // {v2;trial;basic;Bob;1;email;company name;0;86400} - SerialKey serial("7B76323B747269616C3B62617369633B426F623B313B656D61696C3B636F6D70616E79206E616D653B303B38363430307D"); - EXPECT_EQ(true, serial.isTrial()); - EXPECT_EQ(true, serial.isTemporary()); - EXPECT_FALSE(serial.isExpiring(86401)); +TEST(SerialKeyTests, isExpiring_expiredV2TrialBasicSerial_returnFalse) { + // {v2;trial;basic;Bob;1;email;company name;0;86400} + SerialKey serial("7B76323B747269616C3B62617369633B426F623B313B656D61696C3B636" + "F6D70616E79206E616D653B303B38363430307D"); + EXPECT_EQ(true, serial.isTrial()); + EXPECT_EQ(true, serial.isTemporary()); + EXPECT_FALSE(serial.isExpiring(86401)); } -TEST(SerialKeyTests, isExpired_validV2TrialBasicSerial_returnFalse) -{ - // {v2;trial;basic;Bob;1;email;company name;0;86400} - SerialKey serial("7B76323B747269616C3B62617369633B426F623B313B656D61696C3B636F6D70616E79206E616D653B303B38363430307D"); - EXPECT_EQ(true, serial.isTrial()); - EXPECT_EQ(true, serial.isTemporary()); - EXPECT_FALSE(serial.isExpired(0)); +TEST(SerialKeyTests, isExpired_validV2TrialBasicSerial_returnFalse) { + // {v2;trial;basic;Bob;1;email;company name;0;86400} + SerialKey serial("7B76323B747269616C3B62617369633B426F623B313B656D61696C3B636" + "F6D70616E79206E616D653B303B38363430307D"); + EXPECT_EQ(true, serial.isTrial()); + EXPECT_EQ(true, serial.isTemporary()); + EXPECT_FALSE(serial.isExpired(0)); } -TEST(SerialKeyTests, isExpired_expiringV2TrialBasicSerial_returnFalse) -{ - // {v2;trial;basic;Bob;1;email;company name;0;86400} - SerialKey serial("7B76323B747269616C3B62617369633B426F623B313B656D61696C3B636F6D70616E79206E616D653B303B38363430307D"); - EXPECT_EQ(true, serial.isTrial()); - EXPECT_EQ(true, serial.isTemporary()); - EXPECT_FALSE(serial.isExpired(1)); +TEST(SerialKeyTests, isExpired_expiringV2TrialBasicSerial_returnFalse) { + // {v2;trial;basic;Bob;1;email;company name;0;86400} + SerialKey serial("7B76323B747269616C3B62617369633B426F623B313B656D61696C3B636" + "F6D70616E79206E616D653B303B38363430307D"); + EXPECT_EQ(true, serial.isTrial()); + EXPECT_EQ(true, serial.isTemporary()); + EXPECT_FALSE(serial.isExpired(1)); } -TEST(SerialKeyTests, isExpired_expiredV2TrialBasicSerial_returnTrue) -{ - // {v2;trial;basic;Bob;1;email;company name;0;86400} - SerialKey serial("7B76323B747269616C3B62617369633B426F623B313B656D61696C3B636F6D70616E79206E616D653B303B38363430307D"); - EXPECT_EQ(true, serial.isTrial()); - EXPECT_EQ(true, serial.isTemporary()); - EXPECT_EQ(true, serial.isExpired(86401)); +TEST(SerialKeyTests, isExpired_expiredV2TrialBasicSerial_returnTrue) { + // {v2;trial;basic;Bob;1;email;company name;0;86400} + SerialKey serial("7B76323B747269616C3B62617369633B426F623B313B656D61696C3B636" + "F6D70616E79206E616D653B303B38363430307D"); + EXPECT_EQ(true, serial.isTrial()); + EXPECT_EQ(true, serial.isTemporary()); + EXPECT_EQ(true, serial.isExpired(86401)); } -TEST(SerialKeyTests, daysLeft_validExactlyOneDayV2TrialBasicSerial_returnOne) -{ - // {v2;trial;basic;Bob;1;email;company name;0;86400} - SerialKey serial("7B76323B747269616C3B62617369633B426F623B313B656D61696C3B636F6D70616E79206E616D653B303B38363430307D"); - EXPECT_EQ(1, serial.daysLeft(0)); +TEST(SerialKeyTests, daysLeft_validExactlyOneDayV2TrialBasicSerial_returnOne) { + // {v2;trial;basic;Bob;1;email;company name;0;86400} + SerialKey serial("7B76323B747269616C3B62617369633B426F623B313B656D61696C3B636" + "F6D70616E79206E616D653B303B38363430307D"); + EXPECT_EQ(1, serial.daysLeft(0)); } -TEST(SerialKeyTests, daysLeft_validWithinOneDayV2TrialBasicSerial_returnOne) -{ - // {v2;trial;basic;Bob;1;email;company name;0;86400} - SerialKey serial("7B76323B747269616C3B62617369633B426F623B313B656D61696C3B636F6D70616E79206E616D653B303B38363430307D"); - EXPECT_EQ(1, serial.daysLeft(1)); +TEST(SerialKeyTests, daysLeft_validWithinOneDayV2TrialBasicSerial_returnOne) { + // {v2;trial;basic;Bob;1;email;company name;0;86400} + SerialKey serial("7B76323B747269616C3B62617369633B426F623B313B656D61696C3B636" + "F6D70616E79206E616D653B303B38363430307D"); + EXPECT_EQ(1, serial.daysLeft(1)); } -TEST(SerialKeyTests, daysLeft_expiredV2TrialBasicSerial_returnZero) -{ - // {v2;trial;basic;Bob;1;email;company name;0;86400} - SerialKey serial("7B76323B747269616C3B62617369633B426F623B313B656D61696C3B636F6D70616E79206E616D653B303B38363430307D"); - EXPECT_EQ(0, serial.daysLeft(86401)); +TEST(SerialKeyTests, daysLeft_expiredV2TrialBasicSerial_returnZero) { + // {v2;trial;basic;Bob;1;email;company name;0;86400} + SerialKey serial("7B76323B747269616C3B62617369633B426F623B313B656D61696C3B636" + "F6D70616E79206E616D653B303B38363430307D"); + EXPECT_EQ(0, serial.daysLeft(86401)); } -//Subscription license tests -TEST(SerialKeyTests, isExpiring_validV2SubscriptionBasicSerial_returnFalse) -{ - // {v2;subscription;basic;Bob;1;email;company name;1;86400} - SerialKey serial("7B76323B737562736372697074696F6E3B62617369633B426F623B313B656D61696C3B636F6D70616E79206E616D653B313B38363430307D"); - EXPECT_EQ(false, serial.isTrial()); - EXPECT_EQ(true, serial.isTemporary()); - EXPECT_FALSE(serial.isExpiring(0)); - EXPECT_EQ(kBasic, serial.edition()); +// Subscription license tests +TEST(SerialKeyTests, isExpiring_validV2SubscriptionBasicSerial_returnFalse) { + // {v2;subscription;basic;Bob;1;email;company name;1;86400} + SerialKey serial("7B76323B737562736372697074696F6E3B62617369633B426F623B313B6" + "56D61696C3B636F6D70616E79206E616D653B313B38363430307D"); + EXPECT_EQ(false, serial.isTrial()); + EXPECT_EQ(true, serial.isTemporary()); + EXPECT_FALSE(serial.isExpiring(0)); + EXPECT_EQ(kBasic, serial.edition()); } -TEST(SerialKeyTests, isExpiring_expiringV2SubscriptionBasicSerial_returnTrue) -{ - // {v2;subscription;basic;Bob;1;email;company name;0;86400} - SerialKey serial("7B76323B737562736372697074696F6E3B62617369633B426F623B313B656D61696C3B636F6D70616E79206E616D653B303B38363430307D"); - EXPECT_EQ(false, serial.isTrial()); - EXPECT_EQ(true, serial.isTemporary()); - EXPECT_EQ(true, serial.isExpiring(1)); - EXPECT_FALSE(serial.isMaintenance()); +TEST(SerialKeyTests, isExpiring_expiringV2SubscriptionBasicSerial_returnTrue) { + // {v2;subscription;basic;Bob;1;email;company name;0;86400} + SerialKey serial("7B76323B737562736372697074696F6E3B62617369633B426F623B313B6" + "56D61696C3B636F6D70616E79206E616D653B303B38363430307D"); + EXPECT_EQ(false, serial.isTrial()); + EXPECT_EQ(true, serial.isTemporary()); + EXPECT_EQ(true, serial.isExpiring(1)); + EXPECT_FALSE(serial.isMaintenance()); } -TEST(SerialKeyTests, isExpiring_expiringV2MentenanceSerial_returnTrue) -{ - // {v2;maintenance;basic;Bob;1;email;company name;0;86400} - SerialKey serial("7B76323B6D61696E74656E616E63653B70726F3B736572686969206861647A68696C6F763B313B7365726869694073796D6C6573732E636F6D3B203B303B313635353132343139307D"); - EXPECT_FALSE(serial.isTrial()); - EXPECT_FALSE(serial.isTemporary()); - EXPECT_TRUE(serial.isMaintenance()); +TEST(SerialKeyTests, isExpiring_expiringV2MentenanceSerial_returnTrue) { + // {v2;maintenance;basic;Bob;1;email;company name;0;86400} + SerialKey serial("7B76323B6D61696E74656E616E63653B70726F3B7365726869692068616" + "47A68696C6F763B313B7365726869694073796D6C6573732E636F6D3B20" + "3B303B313635353132343139307D"); + EXPECT_FALSE(serial.isTrial()); + EXPECT_FALSE(serial.isTemporary()); + EXPECT_TRUE(serial.isMaintenance()); } -TEST(SerialKeyTests, isExpired_expiredV2SubscriptionBasicSerial_returnTrue) -{ - // {v2;subscription;basic;Bob;1;email;company name;0;86400} - SerialKey serial("7B76323B737562736372697074696F6E3B62617369633B426F623B313B656D61696C3B636F6D70616E79206E616D653B303B38363430307D"); - EXPECT_EQ(false, serial.isTrial()); - EXPECT_EQ(true, serial.isTemporary()); - EXPECT_EQ(true, serial.isExpired(86401)); +TEST(SerialKeyTests, isExpired_expiredV2SubscriptionBasicSerial_returnTrue) { + // {v2;subscription;basic;Bob;1;email;company name;0;86400} + SerialKey serial("7B76323B737562736372697074696F6E3B62617369633B426F623B313B6" + "56D61696C3B636F6D70616E79206E616D653B303B38363430307D"); + EXPECT_EQ(false, serial.isTrial()); + EXPECT_EQ(true, serial.isTemporary()); + EXPECT_EQ(true, serial.isExpired(86401)); } -//toString method tests -TEST(SerialKeyTests, toStringV2SubscriptionBasicSerialKey) -{ - //{v2;subscription;basic;Bob;1;email;company name;0;86400} - const std::string Expected = "7B76323B737562736372697074696F6E3B62617369633B426F623B313B656D61696C3B636F6D70616E79206E616D653B303B38363430307D"; - SerialKey serial(Expected); - EXPECT_EQ(Expected, serial.toString()); +// toString method tests +TEST(SerialKeyTests, toStringV2SubscriptionBasicSerialKey) { + //{v2;subscription;basic;Bob;1;email;company name;0;86400} + const std::string Expected = + "7B76323B737562736372697074696F6E3B62617369633B426F623B313B656D61696C3B63" + "6F6D70616E79206E616D653B303B38363430307D"; + SerialKey serial(Expected); + EXPECT_EQ(Expected, serial.toString()); } -TEST(SerialKeyTests, toStringV2TrialBasicSerialKey) -{ - //{v2;trial;basic;Bob;1;email;company name;0;86400} - const std::string Expected = "7B76323B747269616C3B62617369633B426F623B313B656D61696C3B636F6D70616E79206E616D653B303B38363430307D"; - SerialKey serial(Expected); - EXPECT_EQ(Expected, serial.toString()); +TEST(SerialKeyTests, toStringV2TrialBasicSerialKey) { + //{v2;trial;basic;Bob;1;email;company name;0;86400} + const std::string Expected = + "7B76323B747269616C3B62617369633B426F623B313B656D61696C3B636F6D70616E7920" + "6E616D653B303B38363430307D"; + SerialKey serial(Expected); + EXPECT_EQ(Expected, serial.toString()); } -TEST(SerialKeyTests, toStringV1BasicSerialKey) -{ - //{v1;basic;Bob;1;email;company name;0;0} - const std::string Expected = "7B76313B62617369633B426F623B313B656D61696C3B636F6D70616E79206E616D653B303B307D"; - SerialKey serial(Expected); - EXPECT_EQ(Expected, serial.toString()); +TEST(SerialKeyTests, toStringV1BasicSerialKey) { + //{v1;basic;Bob;1;email;company name;0;0} + const std::string Expected = "7B76313B62617369633B426F623B313B656D61696C3B636" + "F6D70616E79206E616D653B303B307D"; + SerialKey serial(Expected); + EXPECT_EQ(Expected, serial.toString()); } -TEST(SerialKeyTests, IsValidKey_false) -{ - //{v1;basic;Bob;1;email;company name;0;0} - SerialKey serial(kUnregistered); - EXPECT_EQ(false, serial.isValid()); +TEST(SerialKeyTests, IsValidKey_false) { + //{v1;basic;Bob;1;email;company name;0;0} + SerialKey serial(kUnregistered); + EXPECT_EQ(false, serial.isValid()); } -TEST(SerialKeyTests, IsValidKey_true) -{ - SerialKey serial(kBasic); - EXPECT_EQ(true, serial.isValid()); +TEST(SerialKeyTests, IsValidKey_true) { + SerialKey serial(kBasic); + EXPECT_EQ(true, serial.isValid()); } -TEST(SerialKeyTests, IsValidExpiredKey_false) -{ - SerialKey serial("7B76323B737562736372697074696F6E3B62617369633B426F623B313B656D61696C3B636F6D70616E79206E616D653B303B38363430307D"); - EXPECT_EQ(false, serial.isValid()); +TEST(SerialKeyTests, IsValidExpiredKey_false) { + SerialKey serial("7B76323B737562736372697074696F6E3B62617369633B426F623B313B6" + "56D61696C3B636F6D70616E79206E616D653B303B38363430307D"); + EXPECT_EQ(false, serial.isValid()); } -TEST(SerialKeyTests, test_getSpanLeft) -{ - SerialKey key; - int expected{-1}; - EXPECT_EQ(expected, key.getSpanLeft()); +TEST(SerialKeyTests, test_getSpanLeft) { + SerialKey key; + int expected{-1}; + EXPECT_EQ(expected, key.getSpanLeft()); } -TEST(SerialKeyTests, test_getSpanLeft_subscription) -{ - // {v2;subscription;basic;Bob;1;email;company name;0;86400} - SerialKey key("7B76323B737562736372697074696F6E3B62617369633B426F623B313B656D61696C3B636F6D70616E79206E616D653B303B38363430307D"); - EXPECT_EQ(1000, key.getSpanLeft(86399)); - EXPECT_EQ(-1, key.getSpanLeft(86401)); +TEST(SerialKeyTests, test_getSpanLeft_subscription) { + // {v2;subscription;basic;Bob;1;email;company name;0;86400} + SerialKey key("7B76323B737562736372697074696F6E3B62617369633B426F623B313B656D" + "61696C3B636F6D70616E79206E616D653B303B38363430307D"); + EXPECT_EQ(1000, key.getSpanLeft(86399)); + EXPECT_EQ(-1, key.getSpanLeft(86401)); } -TEST(SerialKeyTests, test_getSpanLeft_max_int) -{ - //"{v2;subscription;basic;Bob;1;email;company name;0;3147483647}" - SerialKey key("7B76323B737562736372697074696F6E3B62617369633B426F623B313B656D61696C3B636F6D70616E79206E616D653B303B333134373438333634377D"); - EXPECT_EQ(INT_MAX, key.getSpanLeft(1)); +TEST(SerialKeyTests, test_getSpanLeft_max_int) { + //"{v2;subscription;basic;Bob;1;email;company name;0;3147483647}" + SerialKey key("7B76323B737562736372697074696F6E3B62617369633B426F623B313B656D" + "61696C3B636F6D70616E79206E616D653B303B333134373438333634377D"); + EXPECT_EQ(INT_MAX, key.getSpanLeft(1)); } - - diff --git a/src/test/unittests/shared/SerialKeyTypeTests.cpp b/src/test/unittests/shared/SerialKeyTypeTests.cpp index a29cb631f..935286c8e 100644 --- a/src/test/unittests/shared/SerialKeyTypeTests.cpp +++ b/src/test/unittests/shared/SerialKeyTypeTests.cpp @@ -21,37 +21,33 @@ #include "test/global/gtest.h" -TEST(SerialKeyTypeTests, TrialTemporaryKeyType_false) -{ - SerialKeyType KeyType; - EXPECT_EQ(false, KeyType.isTrial()); - EXPECT_EQ(false, KeyType.isTemporary()); - EXPECT_FALSE(KeyType.isMaintenance()); +TEST(SerialKeyTypeTests, TrialTemporaryKeyType_false) { + SerialKeyType KeyType; + EXPECT_EQ(false, KeyType.isTrial()); + EXPECT_EQ(false, KeyType.isTemporary()); + EXPECT_FALSE(KeyType.isMaintenance()); } -TEST(SerialKeyTypeTests, TrialTemporaryKeyType_true) -{ - SerialKeyType KeyType; - KeyType.setKeyType("trial"); - EXPECT_EQ(true, KeyType.isTrial()); - EXPECT_EQ(true, KeyType.isTemporary()); - EXPECT_FALSE(KeyType.isMaintenance()); +TEST(SerialKeyTypeTests, TrialTemporaryKeyType_true) { + SerialKeyType KeyType; + KeyType.setKeyType("trial"); + EXPECT_EQ(true, KeyType.isTrial()); + EXPECT_EQ(true, KeyType.isTemporary()); + EXPECT_FALSE(KeyType.isMaintenance()); } -TEST(SerialKeyTypeTests, TemporaryKeyType_true) -{ - SerialKeyType KeyType; - KeyType.setKeyType("subscription"); - EXPECT_EQ(false, KeyType.isTrial()); - EXPECT_EQ(true, KeyType.isTemporary()); - EXPECT_FALSE(KeyType.isMaintenance()); +TEST(SerialKeyTypeTests, TemporaryKeyType_true) { + SerialKeyType KeyType; + KeyType.setKeyType("subscription"); + EXPECT_EQ(false, KeyType.isTrial()); + EXPECT_EQ(true, KeyType.isTemporary()); + EXPECT_FALSE(KeyType.isMaintenance()); } -TEST(SerialKeyTypeTests, MaintanenceKeyType_true) -{ - SerialKeyType KeyType; - KeyType.setKeyType("maintenance"); - EXPECT_EQ(false, KeyType.isTrial()); - EXPECT_EQ(false, KeyType.isTemporary()); - EXPECT_TRUE(KeyType.isMaintenance()); +TEST(SerialKeyTypeTests, MaintanenceKeyType_true) { + SerialKeyType KeyType; + KeyType.setKeyType("maintenance"); + EXPECT_EQ(false, KeyType.isTrial()); + EXPECT_EQ(false, KeyType.isTemporary()); + EXPECT_TRUE(KeyType.isMaintenance()); } diff --git a/src/test/unittests/synergy/ArgParserTests.cpp b/src/test/unittests/synergy/ArgParserTests.cpp index 2442dd7f2..9a6c01afa 100644 --- a/src/test/unittests/synergy/ArgParserTests.cpp +++ b/src/test/unittests/synergy/ArgParserTests.cpp @@ -1,11 +1,11 @@ /* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2014-2016 Symless Ltd. - * + * * 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 LICENSE 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 @@ -15,254 +15,247 @@ * along with this program. If not, see . */ -#include #include +#include #include "synergy/ArgParser.h" #include "synergy/ArgsBase.h" -#include "synergy/ToolArgs.h" -#include "synergy/ServerArgs.h" #include "synergy/ClientArgs.h" +#include "synergy/ServerArgs.h" +#include "synergy/ToolArgs.h" #include "test/global/gtest.h" -TEST(ArgParserTests, isArg_abbreviationsArg_returnTrue) -{ - int i = 1; - const int argc = 2; - const char* argv[argc] = { "stub", "-t" }; - bool result = ArgParser::isArg(i, argc, argv, "-t", NULL); +TEST(ArgParserTests, isArg_abbreviationsArg_returnTrue) { + int i = 1; + const int argc = 2; + const char *argv[argc] = {"stub", "-t"}; + bool result = ArgParser::isArg(i, argc, argv, "-t", NULL); - EXPECT_EQ(true, result); + EXPECT_EQ(true, result); } -TEST(ArgParserTests, isArg_fullArg_returnTrue) -{ - int i = 1; - const int argc = 2; - const char* argv[argc] = { "stub", "--test" }; - bool result = ArgParser::isArg(i, argc, argv, NULL, "--test"); +TEST(ArgParserTests, isArg_fullArg_returnTrue) { + int i = 1; + const int argc = 2; + const char *argv[argc] = {"stub", "--test"}; + bool result = ArgParser::isArg(i, argc, argv, NULL, "--test"); - EXPECT_EQ(true, result); + EXPECT_EQ(true, result); } -TEST(ArgParserTests, isArg_missingArgs_returnFalse) -{ - int i = 1; - const int argc = 2; - const char* argv[argc] = { "stub", "-t" }; - static lib::synergy::ArgsBase argsBase; - ArgParser argParser(NULL); - argParser.setArgsBase(argsBase); +TEST(ArgParserTests, isArg_missingArgs_returnFalse) { + int i = 1; + const int argc = 2; + const char *argv[argc] = {"stub", "-t"}; + static lib::synergy::ArgsBase argsBase; + ArgParser argParser(NULL); + argParser.setArgsBase(argsBase); - bool result = ArgParser::isArg(i, argc, argv, "-t", NULL, 1); + bool result = ArgParser::isArg(i, argc, argv, "-t", NULL, 1); - EXPECT_FALSE(result); - EXPECT_EQ(true, argsBase.m_shouldExit); + EXPECT_FALSE(result); + EXPECT_EQ(true, argsBase.m_shouldExit); } -TEST(ArgParserTests, searchDoubleQuotes_doubleQuotedArg_returnTrue) -{ - String command("\"stub\""); - size_t left = 0; - size_t right = 0; +TEST(ArgParserTests, searchDoubleQuotes_doubleQuotedArg_returnTrue) { + String command("\"stub\""); + size_t left = 0; + size_t right = 0; - bool result = ArgParser::searchDoubleQuotes(command, left, right); + bool result = ArgParser::searchDoubleQuotes(command, left, right); - EXPECT_EQ(true, result); - EXPECT_EQ(0, left); - EXPECT_EQ(5, right); + EXPECT_EQ(true, result); + EXPECT_EQ(0, left); + EXPECT_EQ(5, right); } -TEST(ArgParserTests, searchDoubleQuotes_noDoubleQuotedArg_returnfalse) -{ - String command("stub"); - size_t left = 0; - size_t right = 0; +TEST(ArgParserTests, searchDoubleQuotes_noDoubleQuotedArg_returnfalse) { + String command("stub"); + size_t left = 0; + size_t right = 0; - bool result = ArgParser::searchDoubleQuotes(command, left, right); + bool result = ArgParser::searchDoubleQuotes(command, left, right); - EXPECT_FALSE(result); - EXPECT_EQ(0, left); - EXPECT_EQ(0, right); + EXPECT_FALSE(result); + EXPECT_EQ(0, left); + EXPECT_EQ(0, right); } -TEST(ArgParserTests, searchDoubleQuotes_oneDoubleQuoteArg_returnfalse) -{ - String command("\"stub"); - size_t left = 0; - size_t right = 0; +TEST(ArgParserTests, searchDoubleQuotes_oneDoubleQuoteArg_returnfalse) { + String command("\"stub"); + size_t left = 0; + size_t right = 0; - bool result = ArgParser::searchDoubleQuotes(command, left, right); + bool result = ArgParser::searchDoubleQuotes(command, left, right); - EXPECT_FALSE(result); - EXPECT_EQ(0, left); - EXPECT_EQ(0, right); + EXPECT_FALSE(result); + EXPECT_EQ(0, left); + EXPECT_EQ(0, right); } -TEST(ArgParserTests, splitCommandString_oneArg_returnArgv) -{ - String command("stub"); - std::vector argv; +TEST(ArgParserTests, splitCommandString_oneArg_returnArgv) { + String command("stub"); + std::vector argv; - ArgParser::splitCommandString(command, argv); + ArgParser::splitCommandString(command, argv); - EXPECT_EQ(1, argv.size()); - EXPECT_EQ("stub", argv.at(0)); + EXPECT_EQ(1, argv.size()); + EXPECT_EQ("stub", argv.at(0)); } -TEST(ArgParserTests, splitCommandString_twoArgs_returnArgv) -{ - String command("stub1 stub2"); - std::vector argv; +TEST(ArgParserTests, splitCommandString_twoArgs_returnArgv) { + String command("stub1 stub2"); + std::vector argv; - ArgParser::splitCommandString(command, argv); + ArgParser::splitCommandString(command, argv); - EXPECT_EQ(2, argv.size()); - EXPECT_EQ("stub1", argv.at(0)); - EXPECT_EQ("stub2", argv.at(1)); + EXPECT_EQ(2, argv.size()); + EXPECT_EQ("stub1", argv.at(0)); + EXPECT_EQ("stub2", argv.at(1)); } -TEST(ArgParserTests, splitCommandString_doubleQuotedArgs_returnArgv) -{ - String command("\"stub1\" stub2 \"stub3\""); - std::vector argv; +TEST(ArgParserTests, splitCommandString_doubleQuotedArgs_returnArgv) { + String command("\"stub1\" stub2 \"stub3\""); + std::vector argv; - ArgParser::splitCommandString(command, argv); + ArgParser::splitCommandString(command, argv); - EXPECT_EQ(3, argv.size()); - EXPECT_EQ("stub1", argv.at(0)); - EXPECT_EQ("stub2", argv.at(1)); - EXPECT_EQ("stub3", argv.at(2)); + EXPECT_EQ(3, argv.size()); + EXPECT_EQ("stub1", argv.at(0)); + EXPECT_EQ("stub2", argv.at(1)); + EXPECT_EQ("stub3", argv.at(2)); } -TEST(ArgParserTests, splitCommandString_spaceDoubleQuotedArgs_returnArgv) -{ - String command("\"stub1\" stub2 \"stub3 space\""); - std::vector argv; +TEST(ArgParserTests, splitCommandString_spaceDoubleQuotedArgs_returnArgv) { + String command("\"stub1\" stub2 \"stub3 space\""); + std::vector argv; - ArgParser::splitCommandString(command, argv); + ArgParser::splitCommandString(command, argv); - EXPECT_EQ(3, argv.size()); - EXPECT_EQ("stub1", argv.at(0)); - EXPECT_EQ("stub2", argv.at(1)); - EXPECT_EQ("stub3 space", argv.at(2)); + EXPECT_EQ(3, argv.size()); + EXPECT_EQ("stub1", argv.at(0)); + EXPECT_EQ("stub2", argv.at(1)); + EXPECT_EQ("stub3 space", argv.at(2)); } -TEST(ArgParserTests, getArgv_stringArray_return2DArray) -{ - std::vector argArray; - argArray.push_back("stub1"); - argArray.push_back("stub2"); - argArray.push_back("stub3 space"); - const char** argv = ArgParser::getArgv(argArray); +TEST(ArgParserTests, getArgv_stringArray_return2DArray) { + std::vector argArray; + argArray.push_back("stub1"); + argArray.push_back("stub2"); + argArray.push_back("stub3 space"); + const char **argv = ArgParser::getArgv(argArray); - String row1(argv[0]); - String row2(argv[1]); - String row3(argv[2]); + String row1(argv[0]); + String row2(argv[1]); + String row3(argv[2]); - EXPECT_EQ("stub1", row1); - EXPECT_EQ("stub2", row2); - EXPECT_EQ("stub3 space", row3); + EXPECT_EQ("stub1", row1); + EXPECT_EQ("stub2", row2); + EXPECT_EQ("stub3 space", row3); - delete[] argv; + delete[] argv; } -TEST(ArgParserTests, assembleCommand_stringArray_returnCommand) -{ - std::vector argArray; - argArray.push_back("stub1"); - argArray.push_back("stub2"); - String command = ArgParser::assembleCommand(argArray); +TEST(ArgParserTests, assembleCommand_stringArray_returnCommand) { + std::vector argArray; + argArray.push_back("stub1"); + argArray.push_back("stub2"); + String command = ArgParser::assembleCommand(argArray); - EXPECT_EQ("stub1 stub2", command); + EXPECT_EQ("stub1 stub2", command); } -TEST(ArgParserTests, assembleCommand_ignoreSecondArg_returnCommand) -{ - std::vector argArray; - argArray.push_back("stub1"); - argArray.push_back("stub2"); - String command = ArgParser::assembleCommand(argArray, "stub2"); +TEST(ArgParserTests, assembleCommand_ignoreSecondArg_returnCommand) { + std::vector argArray; + argArray.push_back("stub1"); + argArray.push_back("stub2"); + String command = ArgParser::assembleCommand(argArray, "stub2"); - EXPECT_EQ("stub1", command); + EXPECT_EQ("stub1", command); } -TEST(ArgParserTests, assembleCommand_ignoreSecondArgWithOneParameter_returnCommand) -{ - std::vector argArray; - argArray.push_back("stub1"); - argArray.push_back("stub2"); - argArray.push_back("stub3"); - argArray.push_back("stub4"); - String command = ArgParser::assembleCommand(argArray, "stub2", 1); +TEST(ArgParserTests, + assembleCommand_ignoreSecondArgWithOneParameter_returnCommand) { + std::vector argArray; + argArray.push_back("stub1"); + argArray.push_back("stub2"); + argArray.push_back("stub3"); + argArray.push_back("stub4"); + String command = ArgParser::assembleCommand(argArray, "stub2", 1); - EXPECT_EQ("stub1 stub4", command); + EXPECT_EQ("stub1 stub4", command); } -TEST(ArgParserTests, assembleCommand_stringArrayWithSpace_returnCommand) -{ - std::vector argArray; - argArray.push_back("stub1 space"); - argArray.push_back("stub2"); - argArray.push_back("stub3 space"); - String command = ArgParser::assembleCommand(argArray); +TEST(ArgParserTests, assembleCommand_stringArrayWithSpace_returnCommand) { + std::vector argArray; + argArray.push_back("stub1 space"); + argArray.push_back("stub2"); + argArray.push_back("stub3 space"); + String command = ArgParser::assembleCommand(argArray); - EXPECT_EQ("\"stub1 space\" stub2 \"stub3 space\"", command); + EXPECT_EQ("\"stub1 space\" stub2 \"stub3 space\"", command); } -TEST(ArgParserTests, parseToolArgs_matches_correspondingly) -{ - ArgParser parser(nullptr); - std::map> tests = { - {"--get-active-desktop", [](ToolArgs const &a){ return a.m_printActiveDesktopName; }}, - {"--get-installed-dir", [](ToolArgs const &a){ return a.m_getInstalledDir; }}, - {"--get-profile-dir", [](ToolArgs const &a){ return a.m_getProfileDir; }}, - {"--get-arch", [](ToolArgs const &a){ return a.m_getArch; }} - }; - for (auto const &test: tests) { - ToolArgs toolArgs; - EXPECT_FALSE(test.second(toolArgs)); - std::array twoArgs {"syntool", test.first}; - EXPECT_TRUE(parser.parseToolArgs(toolArgs, 2, twoArgs.data())); - EXPECT_TRUE(test.second(toolArgs)); - } +TEST(ArgParserTests, parseToolArgs_matches_correspondingly) { + ArgParser parser(nullptr); + std::map> tests = { + {"--get-active-desktop", + [](ToolArgs const &a) { return a.m_printActiveDesktopName; }}, + {"--get-installed-dir", + [](ToolArgs const &a) { return a.m_getInstalledDir; }}, + {"--get-profile-dir", + [](ToolArgs const &a) { return a.m_getProfileDir; }}, + {"--get-arch", [](ToolArgs const &a) { return a.m_getArch; }}}; + for (auto const &test : tests) { ToolArgs toolArgs; - std::array twoArgs {"syntool", "--garbage"}; - EXPECT_FALSE(parser.parseToolArgs(toolArgs, 2, twoArgs.data())); + EXPECT_FALSE(test.second(toolArgs)); + std::array twoArgs{"syntool", test.first}; + EXPECT_TRUE(parser.parseToolArgs(toolArgs, 2, twoArgs.data())); + EXPECT_TRUE(test.second(toolArgs)); + } + ToolArgs toolArgs; + std::array twoArgs{"syntool", "--garbage"}; + EXPECT_FALSE(parser.parseToolArgs(toolArgs, 2, twoArgs.data())); } -TEST(ArgParserTests, parseServerArgs_parses_each_category) -{ - ArgParser parser(nullptr); - lib::synergy::ServerArgs args; - args.m_daemon = false; - char const *argv[] = {"synergy", "--help" +TEST(ArgParserTests, parseServerArgs_parses_each_category) { + ArgParser parser(nullptr); + lib::synergy::ServerArgs args; + args.m_daemon = false; + char const *argv[] = {"synergy", "--help" #if WINAPI_MSWINDOWS -,"--exit-pause" + , + "--exit-pause" #elif WINAPI_XWINDOWS -,"--no-xinitthreads" + , + "--no-xinitthreads" #endif -, "--res-w", "888" - }; - EXPECT_TRUE(parser.parseServerArgs(args, sizeof(argv)/sizeof(argv[0]), argv)); - EXPECT_EQ(args.m_shouldExit, true); + , + "--res-w", "888"}; + EXPECT_TRUE( + parser.parseServerArgs(args, sizeof(argv) / sizeof(argv[0]), argv)); + EXPECT_EQ(args.m_shouldExit, true); } -TEST(ArgParserTests, parseClientArgs_parses_single_help) -{ - ArgParser parser(nullptr); - lib::synergy::ClientArgs args; - args.m_daemon = false; - char const *argv[] = {"synergy", "--help" +TEST(ArgParserTests, parseClientArgs_parses_single_help) { + ArgParser parser(nullptr); + lib::synergy::ClientArgs args; + args.m_daemon = false; + char const *argv[] = {"synergy", + "--help" #if WINAPI_MSWINDOWS - ,"--exit-pause" + , + "--exit-pause" #elif WINAPI_XWINDOWS - ,"--no-xinitthreads" + , + "--no-xinitthreads" #endif - , "--res-w" - , "888" - , "127.0.0.1" }; - EXPECT_TRUE(parser.parseClientArgs(args, sizeof(argv)/sizeof(argv[0]), argv)); - EXPECT_EQ(args.m_shouldExit, true); + , + "--res-w", + "888", + "127.0.0.1"}; + EXPECT_TRUE( + parser.parseClientArgs(args, sizeof(argv) / sizeof(argv[0]), argv)); + EXPECT_EQ(args.m_shouldExit, true); } diff --git a/src/test/unittests/synergy/ClientArgsParsingTests.cpp b/src/test/unittests/synergy/ClientArgsParsingTests.cpp index f16e090e0..4c6981399 100644 --- a/src/test/unittests/synergy/ClientArgsParsingTests.cpp +++ b/src/test/unittests/synergy/ClientArgsParsingTests.cpp @@ -1,11 +1,11 @@ /* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2014-2016 Symless Ltd. - * + * * 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 LICENSE 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 @@ -27,118 +27,119 @@ using ::testing::_; using ::testing::Invoke; using ::testing::NiceMock; -bool -client_stubParseGenericArgs(int, const char* const*, int&) -{ - return false; +bool client_stubParseGenericArgs(int, const char *const *, int &) { + return false; } -bool -client_stubCheckUnexpectedArgs() -{ - return false; +bool client_stubCheckUnexpectedArgs() { return false; } + +TEST(ClientArgsParsingTests, parseClientArgs_yScrollArg_setYScroll) { + NiceMock argParser; + ON_CALL(argParser, parseGenericArgs(_, _, _)) + .WillByDefault(Invoke(client_stubParseGenericArgs)); + ON_CALL(argParser, checkUnexpectedArgs()) + .WillByDefault(Invoke(client_stubCheckUnexpectedArgs)); + lib::synergy::ClientArgs clientArgs; + const int argc = 3; + const char *kYScrollCmd[argc] = {"stub", "--yscroll", "1"}; + + argParser.parseClientArgs(clientArgs, argc, kYScrollCmd); + + EXPECT_EQ(1, clientArgs.m_yscroll); } -TEST(ClientArgsParsingTests, parseClientArgs_yScrollArg_setYScroll) -{ - NiceMock argParser; - ON_CALL(argParser, parseGenericArgs(_, _, _)).WillByDefault(Invoke(client_stubParseGenericArgs)); - ON_CALL(argParser, checkUnexpectedArgs()).WillByDefault(Invoke(client_stubCheckUnexpectedArgs)); - lib::synergy::ClientArgs clientArgs; - const int argc = 3; - const char* kYScrollCmd[argc] = { "stub", "--yscroll", "1" }; +TEST(ClientArgsParsingTests, parseClientArgs_setLangSync) { + NiceMock argParser; + ON_CALL(argParser, parseGenericArgs(_, _, _)) + .WillByDefault(Invoke(client_stubParseGenericArgs)); + ON_CALL(argParser, checkUnexpectedArgs()) + .WillByDefault(Invoke(client_stubCheckUnexpectedArgs)); + lib::synergy::ClientArgs clientArgs; + clientArgs.m_enableLangSync = false; + const int argc = 2; + std::array kLangCmd = {"stub", "--sync-language"}; - argParser.parseClientArgs(clientArgs, argc, kYScrollCmd); + argParser.parseClientArgs(clientArgs, argc, kLangCmd.data()); - EXPECT_EQ(1, clientArgs.m_yscroll); + EXPECT_TRUE(clientArgs.m_enableLangSync); } -TEST(ClientArgsParsingTests, parseClientArgs_setLangSync) -{ - NiceMock argParser; - ON_CALL(argParser, parseGenericArgs(_, _, _)).WillByDefault(Invoke(client_stubParseGenericArgs)); - ON_CALL(argParser, checkUnexpectedArgs()).WillByDefault(Invoke(client_stubCheckUnexpectedArgs)); - lib::synergy::ClientArgs clientArgs; - clientArgs.m_enableLangSync = false; - const int argc = 2; - std::array kLangCmd = { "stub", "--sync-language" }; +TEST(ClientArgsParsingTests, parseClientArgs_setInvertScroll) { + NiceMock argParser; + lib::synergy::ClientArgs clientArgs; + const int argc = 2; + std::array kLangCmd = {"stub", "--invert-scroll"}; - argParser.parseClientArgs(clientArgs, argc, kLangCmd.data()); - - EXPECT_TRUE(clientArgs.m_enableLangSync); + argParser.parseClientArgs(clientArgs, argc, kLangCmd.data()); + EXPECT_EQ(clientArgs.m_clientScrollDirection, + lib::synergy::ClientScrollDirection::INVERT_SERVER); } -TEST(ClientArgsParsingTests, parseClientArgs_setInvertScroll) -{ - NiceMock argParser; - lib::synergy::ClientArgs clientArgs; - const int argc = 2; - std::array kLangCmd = { "stub", "--invert-scroll" }; +TEST(ClientArgsParsingTests, parseClientArgs_setCommonArgs) { + NiceMock argParser; + ON_CALL(argParser, parseGenericArgs(_, _, _)) + .WillByDefault(Invoke(client_stubParseGenericArgs)); + ON_CALL(argParser, checkUnexpectedArgs()) + .WillByDefault(Invoke(client_stubCheckUnexpectedArgs)); + lib::synergy::ClientArgs clientArgs; + clientArgs.m_enableLangSync = false; + const int argc = 9; + std::array kLangCmd = { + "stub", "--enable-crypto", "--profile-dir", + "profileDir", "--plugin-dir", "pluginDir", + "--tls-cert", "tlsCertPath", "--prevent-sleep"}; - argParser.parseClientArgs(clientArgs, argc, kLangCmd.data()); - EXPECT_EQ(clientArgs.m_clientScrollDirection, lib::synergy::ClientScrollDirection::INVERT_SERVER); + argParser.parseClientArgs(clientArgs, argc, kLangCmd.data()); + + EXPECT_TRUE(clientArgs.m_enableCrypto); + EXPECT_EQ(clientArgs.m_profileDirectory, "profileDir"); + EXPECT_EQ(clientArgs.m_pluginDirectory, "pluginDir"); + EXPECT_EQ(clientArgs.m_tlsCertFile, "tlsCertPath"); + EXPECT_TRUE(clientArgs.m_preventSleep); } -TEST(ClientArgsParsingTests, parseClientArgs_setCommonArgs) -{ - NiceMock argParser; - ON_CALL(argParser, parseGenericArgs(_, _, _)).WillByDefault(Invoke(client_stubParseGenericArgs)); - ON_CALL(argParser, checkUnexpectedArgs()).WillByDefault(Invoke(client_stubCheckUnexpectedArgs)); - lib::synergy::ClientArgs clientArgs; - clientArgs.m_enableLangSync = false; - const int argc = 9; - std::array kLangCmd = { "stub", "--enable-crypto", "--profile-dir", "profileDir", - "--plugin-dir", "pluginDir", "--tls-cert", "tlsCertPath", - "--prevent-sleep" }; +TEST(ClientArgsParsingTests, parseClientArgs_addressArg_setSynergyAddress) { + NiceMock argParser; + ON_CALL(argParser, parseGenericArgs(_, _, _)) + .WillByDefault(Invoke(client_stubParseGenericArgs)); + ON_CALL(argParser, checkUnexpectedArgs()) + .WillByDefault(Invoke(client_stubCheckUnexpectedArgs)); + lib::synergy::ClientArgs clientArgs; + const int argc = 2; + const char *kAddressCmd[argc] = {"stub", "mock_address"}; - argParser.parseClientArgs(clientArgs, argc, kLangCmd.data()); + bool result = argParser.parseClientArgs(clientArgs, argc, kAddressCmd); - EXPECT_TRUE(clientArgs.m_enableCrypto); - EXPECT_EQ(clientArgs.m_profileDirectory, "profileDir"); - EXPECT_EQ(clientArgs.m_pluginDirectory, "pluginDir"); - EXPECT_EQ(clientArgs.m_tlsCertFile, "tlsCertPath"); - EXPECT_TRUE(clientArgs.m_preventSleep); + EXPECT_EQ("mock_address", clientArgs.m_serverAddress); + EXPECT_EQ(true, result); } -TEST(ClientArgsParsingTests, parseClientArgs_addressArg_setSynergyAddress) -{ - NiceMock argParser; - ON_CALL(argParser, parseGenericArgs(_, _, _)).WillByDefault(Invoke(client_stubParseGenericArgs)); - ON_CALL(argParser, checkUnexpectedArgs()).WillByDefault(Invoke(client_stubCheckUnexpectedArgs)); - lib::synergy::ClientArgs clientArgs; - const int argc = 2; - const char* kAddressCmd[argc] = { "stub", "mock_address" }; +TEST(ClientArgsParsingTests, parseClientArgs_noAddressArg_returnFalse) { + NiceMock argParser; + ON_CALL(argParser, parseGenericArgs(_, _, _)) + .WillByDefault(Invoke(client_stubParseGenericArgs)); + ON_CALL(argParser, checkUnexpectedArgs()) + .WillByDefault(Invoke(client_stubCheckUnexpectedArgs)); + lib::synergy::ClientArgs clientArgs; + const int argc = 1; + const char *kNoAddressCmd[argc] = {"stub"}; - bool result = argParser.parseClientArgs(clientArgs, argc, kAddressCmd); + bool result = argParser.parseClientArgs(clientArgs, argc, kNoAddressCmd); - EXPECT_EQ("mock_address", clientArgs.m_serverAddress); - EXPECT_EQ(true, result); + EXPECT_FALSE(result); } -TEST(ClientArgsParsingTests, parseClientArgs_noAddressArg_returnFalse) -{ - NiceMock argParser; - ON_CALL(argParser, parseGenericArgs(_, _, _)).WillByDefault(Invoke(client_stubParseGenericArgs)); - ON_CALL(argParser, checkUnexpectedArgs()).WillByDefault(Invoke(client_stubCheckUnexpectedArgs)); - lib::synergy::ClientArgs clientArgs; - const int argc = 1; - const char* kNoAddressCmd[argc] = { "stub" }; +TEST(ClientArgsParsingTests, parseClientArgs_unrecognizedArg_returnFalse) { + NiceMock argParser; + ON_CALL(argParser, parseGenericArgs(_, _, _)) + .WillByDefault(Invoke(client_stubParseGenericArgs)); + ON_CALL(argParser, checkUnexpectedArgs()) + .WillByDefault(Invoke(client_stubCheckUnexpectedArgs)); + lib::synergy::ClientArgs clientArgs; + const int argc = 3; + const char *kUnrecognizedCmd[argc] = {"stub", "mock_arg", "mock_address"}; - bool result = argParser.parseClientArgs(clientArgs, argc, kNoAddressCmd); + bool result = argParser.parseClientArgs(clientArgs, argc, kUnrecognizedCmd); - EXPECT_FALSE(result); -} - -TEST(ClientArgsParsingTests, parseClientArgs_unrecognizedArg_returnFalse) -{ - NiceMock argParser; - ON_CALL(argParser, parseGenericArgs(_, _, _)).WillByDefault(Invoke(client_stubParseGenericArgs)); - ON_CALL(argParser, checkUnexpectedArgs()).WillByDefault(Invoke(client_stubCheckUnexpectedArgs)); - lib::synergy::ClientArgs clientArgs; - const int argc = 3; - const char* kUnrecognizedCmd[argc] = { "stub", "mock_arg", "mock_address"}; - - bool result = argParser.parseClientArgs(clientArgs, argc, kUnrecognizedCmd); - - EXPECT_FALSE(result); + EXPECT_FALSE(result); } diff --git a/src/test/unittests/synergy/ClipboardChunkTests.cpp b/src/test/unittests/synergy/ClipboardChunkTests.cpp index b33d85f0a..e930e6d57 100644 --- a/src/test/unittests/synergy/ClipboardChunkTests.cpp +++ b/src/test/unittests/synergy/ClipboardChunkTests.cpp @@ -1,11 +1,11 @@ /* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2015-2016 Symless Ltd. - * + * * 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 LICENSE 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 @@ -20,59 +20,56 @@ #include "test/global/gtest.h" -TEST(ClipboardChunkTests, start_formatStartChunk) -{ - ClipboardID id = 0; - UInt32 sequence = 0; - String mockDataSize("10"); - ClipboardChunk* chunk = ClipboardChunk::start(id, sequence, mockDataSize); - UInt32 temp_m_chunk; - memcpy(&temp_m_chunk, &(chunk->m_chunk[1]), 4); +TEST(ClipboardChunkTests, start_formatStartChunk) { + ClipboardID id = 0; + UInt32 sequence = 0; + String mockDataSize("10"); + ClipboardChunk *chunk = ClipboardChunk::start(id, sequence, mockDataSize); + UInt32 temp_m_chunk; + memcpy(&temp_m_chunk, &(chunk->m_chunk[1]), 4); - EXPECT_EQ(id, chunk->m_chunk[0]); - EXPECT_EQ(sequence, temp_m_chunk); - EXPECT_EQ(kDataStart, chunk->m_chunk[5]); - EXPECT_EQ('1', chunk->m_chunk[6]); - EXPECT_EQ('0', chunk->m_chunk[7]); - EXPECT_EQ('\0', chunk->m_chunk[8]); + EXPECT_EQ(id, chunk->m_chunk[0]); + EXPECT_EQ(sequence, temp_m_chunk); + EXPECT_EQ(kDataStart, chunk->m_chunk[5]); + EXPECT_EQ('1', chunk->m_chunk[6]); + EXPECT_EQ('0', chunk->m_chunk[7]); + EXPECT_EQ('\0', chunk->m_chunk[8]); - delete chunk; + delete chunk; } -TEST(ClipboardChunkTests, data_formatDataChunk) -{ - ClipboardID id = 0; - UInt32 sequence = 1; - String mockData("mock data"); - ClipboardChunk* chunk = ClipboardChunk::data(id, sequence, mockData); +TEST(ClipboardChunkTests, data_formatDataChunk) { + ClipboardID id = 0; + UInt32 sequence = 1; + String mockData("mock data"); + ClipboardChunk *chunk = ClipboardChunk::data(id, sequence, mockData); - EXPECT_EQ(id, chunk->m_chunk[0]); - EXPECT_EQ(sequence, (UInt32)chunk->m_chunk[1]); - EXPECT_EQ(kDataChunk, chunk->m_chunk[5]); - EXPECT_EQ('m', chunk->m_chunk[6]); - EXPECT_EQ('o', chunk->m_chunk[7]); - EXPECT_EQ('c', chunk->m_chunk[8]); - EXPECT_EQ('k', chunk->m_chunk[9]); - EXPECT_EQ(' ', chunk->m_chunk[10]); - EXPECT_EQ('d', chunk->m_chunk[11]); - EXPECT_EQ('a', chunk->m_chunk[12]); - EXPECT_EQ('t', chunk->m_chunk[13]); - EXPECT_EQ('a', chunk->m_chunk[14]); - EXPECT_EQ('\0', chunk->m_chunk[15]); + EXPECT_EQ(id, chunk->m_chunk[0]); + EXPECT_EQ(sequence, (UInt32)chunk->m_chunk[1]); + EXPECT_EQ(kDataChunk, chunk->m_chunk[5]); + EXPECT_EQ('m', chunk->m_chunk[6]); + EXPECT_EQ('o', chunk->m_chunk[7]); + EXPECT_EQ('c', chunk->m_chunk[8]); + EXPECT_EQ('k', chunk->m_chunk[9]); + EXPECT_EQ(' ', chunk->m_chunk[10]); + EXPECT_EQ('d', chunk->m_chunk[11]); + EXPECT_EQ('a', chunk->m_chunk[12]); + EXPECT_EQ('t', chunk->m_chunk[13]); + EXPECT_EQ('a', chunk->m_chunk[14]); + EXPECT_EQ('\0', chunk->m_chunk[15]); - delete chunk; + delete chunk; } -TEST(ClipboardChunkTests, end_formatDataChunk) -{ - ClipboardID id = 1; - UInt32 sequence = 1; - ClipboardChunk* chunk = ClipboardChunk::end(id, sequence); +TEST(ClipboardChunkTests, end_formatDataChunk) { + ClipboardID id = 1; + UInt32 sequence = 1; + ClipboardChunk *chunk = ClipboardChunk::end(id, sequence); - EXPECT_EQ(id, chunk->m_chunk[0]); - EXPECT_EQ(sequence, (UInt32)chunk->m_chunk[1]); - EXPECT_EQ(kDataEnd, chunk->m_chunk[5]); - EXPECT_EQ('\0', chunk->m_chunk[6]); + EXPECT_EQ(id, chunk->m_chunk[0]); + EXPECT_EQ(sequence, (UInt32)chunk->m_chunk[1]); + EXPECT_EQ(kDataEnd, chunk->m_chunk[5]); + EXPECT_EQ('\0', chunk->m_chunk[6]); - delete chunk; + delete chunk; } diff --git a/src/test/unittests/synergy/ClipboardTests.cpp b/src/test/unittests/synergy/ClipboardTests.cpp index 2b1b84943..083b9c7d7 100644 --- a/src/test/unittests/synergy/ClipboardTests.cpp +++ b/src/test/unittests/synergy/ClipboardTests.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2011 Nick Bolton - * + * * 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 LICENSE 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 @@ -20,385 +20,360 @@ #include "test/global/gtest.h" -TEST(ClipboardTests, empty_openCalled_returnsTrue) -{ - Clipboard clipboard; - clipboard.open(0); +TEST(ClipboardTests, empty_openCalled_returnsTrue) { + Clipboard clipboard; + clipboard.open(0); - bool actual = clipboard.empty(); + bool actual = clipboard.empty(); - EXPECT_EQ(true, actual); + EXPECT_EQ(true, actual); } -TEST(ClipboardTests, empty_singleFormat_hasReturnsFalse) -{ - Clipboard clipboard; - clipboard.open(0); - clipboard.add(Clipboard::kText, "synergy rocks!"); +TEST(ClipboardTests, empty_singleFormat_hasReturnsFalse) { + Clipboard clipboard; + clipboard.open(0); + clipboard.add(Clipboard::kText, "synergy rocks!"); - clipboard.empty(); + clipboard.empty(); - bool actual = clipboard.has(Clipboard::kText); - EXPECT_FALSE(actual); + bool actual = clipboard.has(Clipboard::kText); + EXPECT_FALSE(actual); } -TEST(ClipboardTests, add_newValue_valueWasStored) -{ - Clipboard clipboard; - clipboard.open(0); +TEST(ClipboardTests, add_newValue_valueWasStored) { + Clipboard clipboard; + clipboard.open(0); - clipboard.add(IClipboard::kText, "synergy rocks!"); + clipboard.add(IClipboard::kText, "synergy rocks!"); - String actual = clipboard.get(IClipboard::kText); - EXPECT_EQ("synergy rocks!", actual); + String actual = clipboard.get(IClipboard::kText); + EXPECT_EQ("synergy rocks!", actual); } -TEST(ClipboardTests, add_replaceValue_valueWasReplaced) -{ - Clipboard clipboard; - clipboard.open(0); +TEST(ClipboardTests, add_replaceValue_valueWasReplaced) { + Clipboard clipboard; + clipboard.open(0); - clipboard.add(IClipboard::kText, "synergy rocks!"); - clipboard.add(IClipboard::kText, "maxivista sucks"); // haha, just kidding. + clipboard.add(IClipboard::kText, "synergy rocks!"); + clipboard.add(IClipboard::kText, "maxivista sucks"); // haha, just kidding. - String actual = clipboard.get(IClipboard::kText); - EXPECT_EQ("maxivista sucks", actual); + String actual = clipboard.get(IClipboard::kText); + EXPECT_EQ("maxivista sucks", actual); } -TEST(ClipboardTests, open_timeIsZero_returnsTrue) -{ - Clipboard clipboard; +TEST(ClipboardTests, open_timeIsZero_returnsTrue) { + Clipboard clipboard; - bool actual = clipboard.open(0); + bool actual = clipboard.open(0); - EXPECT_EQ(true, actual); + EXPECT_EQ(true, actual); } -TEST(ClipboardTests, open_timeIsOne_returnsTrue) -{ - Clipboard clipboard; +TEST(ClipboardTests, open_timeIsOne_returnsTrue) { + Clipboard clipboard; - bool actual = clipboard.open(1); + bool actual = clipboard.open(1); - EXPECT_EQ(true, actual); + EXPECT_EQ(true, actual); } -TEST(ClipboardTests, close_isOpen_noErrors) -{ - Clipboard clipboard; - clipboard.open(0); +TEST(ClipboardTests, close_isOpen_noErrors) { + Clipboard clipboard; + clipboard.open(0); - clipboard.close(); + clipboard.close(); - // can't assert anything + // can't assert anything } -TEST(ClipboardTests, getTime_openWithNoEmpty_returnsZero) -{ - Clipboard clipboard; - clipboard.open(1); +TEST(ClipboardTests, getTime_openWithNoEmpty_returnsZero) { + Clipboard clipboard; + clipboard.open(1); - Clipboard::Time actual = clipboard.getTime(); + Clipboard::Time actual = clipboard.getTime(); - EXPECT_EQ(0, actual); + EXPECT_EQ(0, actual); } -TEST(ClipboardTests, getTime_openAndEmpty_returnsOne) -{ - Clipboard clipboard; - clipboard.open(1); - clipboard.empty(); +TEST(ClipboardTests, getTime_openAndEmpty_returnsOne) { + Clipboard clipboard; + clipboard.open(1); + clipboard.empty(); - Clipboard::Time actual = clipboard.getTime(); + Clipboard::Time actual = clipboard.getTime(); - EXPECT_EQ(1, actual); + EXPECT_EQ(1, actual); } -TEST(ClipboardTests, has_withFormatAdded_returnsTrue) -{ - Clipboard clipboard; - clipboard.open(0); - clipboard.add(IClipboard::kText, "synergy rocks!"); +TEST(ClipboardTests, has_withFormatAdded_returnsTrue) { + Clipboard clipboard; + clipboard.open(0); + clipboard.add(IClipboard::kText, "synergy rocks!"); - bool actual = clipboard.has(IClipboard::kText); + bool actual = clipboard.has(IClipboard::kText); - EXPECT_EQ(true, actual); + EXPECT_EQ(true, actual); } -TEST(ClipboardTests, has_withNoFormats_returnsFalse) -{ - Clipboard clipboard; - clipboard.open(0); +TEST(ClipboardTests, has_withNoFormats_returnsFalse) { + Clipboard clipboard; + clipboard.open(0); - bool actual = clipboard.has(IClipboard::kText); + bool actual = clipboard.has(IClipboard::kText); - EXPECT_FALSE(actual); + EXPECT_FALSE(actual); } -TEST(ClipboardTests, get_withNoFormats_returnsEmpty) -{ - Clipboard clipboard; - clipboard.open(0); +TEST(ClipboardTests, get_withNoFormats_returnsEmpty) { + Clipboard clipboard; + clipboard.open(0); - String actual = clipboard.get(IClipboard::kText); + String actual = clipboard.get(IClipboard::kText); - EXPECT_EQ("", actual); + EXPECT_EQ("", actual); } -TEST(ClipboardTests, get_withFormatAdded_returnsExpected) -{ - Clipboard clipboard; - clipboard.open(0); - clipboard.add(IClipboard::kText, "synergy rocks!"); +TEST(ClipboardTests, get_withFormatAdded_returnsExpected) { + Clipboard clipboard; + clipboard.open(0); + clipboard.add(IClipboard::kText, "synergy rocks!"); - String actual = clipboard.get(IClipboard::kText); + String actual = clipboard.get(IClipboard::kText); - EXPECT_EQ("synergy rocks!", actual); + EXPECT_EQ("synergy rocks!", actual); } -TEST(ClipboardTests, marshall_addNotCalled_firstCharIsZero) -{ - Clipboard clipboard; +TEST(ClipboardTests, marshall_addNotCalled_firstCharIsZero) { + Clipboard clipboard; - String actual = clipboard.marshall(); + String actual = clipboard.marshall(); - // seems to return "\0\0\0\0" but EXPECT_EQ can't assert this, - // so instead, just assert that first char is '\0'. - EXPECT_EQ(0, (int)actual[0]); + // seems to return "\0\0\0\0" but EXPECT_EQ can't assert this, + // so instead, just assert that first char is '\0'. + EXPECT_EQ(0, (int)actual[0]); } -TEST(ClipboardTests, marshall_withTextAdded_typeCharIsText) -{ - Clipboard clipboard; - clipboard.open(0); - clipboard.add(IClipboard::kText, "synergy rocks!"); - clipboard.close(); +TEST(ClipboardTests, marshall_withTextAdded_typeCharIsText) { + Clipboard clipboard; + clipboard.open(0); + clipboard.add(IClipboard::kText, "synergy rocks!"); + clipboard.close(); - String actual = clipboard.marshall(); + String actual = clipboard.marshall(); - // string contains other data, but 8th char should be kText. - EXPECT_EQ(IClipboard::kText, (int)actual[7]); + // string contains other data, but 8th char should be kText. + EXPECT_EQ(IClipboard::kText, (int)actual[7]); } -TEST(ClipboardTests, marshall_withTextAdded_lastSizeCharIs14) -{ - Clipboard clipboard; - clipboard.open(0); - clipboard.add(IClipboard::kText, "synergy rocks!"); // 14 chars - clipboard.close(); +TEST(ClipboardTests, marshall_withTextAdded_lastSizeCharIs14) { + Clipboard clipboard; + clipboard.open(0); + clipboard.add(IClipboard::kText, "synergy rocks!"); // 14 chars + clipboard.close(); - String actual = clipboard.marshall(); + String actual = clipboard.marshall(); - EXPECT_EQ(14, (int)actual[11]); + EXPECT_EQ(14, (int)actual[11]); } -// TODO: there's some integer -> char encoding going on here. i find it +// TODO: there's some integer -> char encoding going on here. i find it // hard to believe that the clipboard is the only thing doing this. maybe // we should refactor this stuff out of the clipboard. -TEST(ClipboardTests, marshall_withTextSize285_sizeCharsValid) -{ - // 285 chars - String data; - data.append("Synergy is Free and Open Source Software that lets you "); - data.append("easily share your mouse and keyboard between multiple "); - data.append("computers, where each computer has it's own display. No "); - data.append("special hardware is required, all you need is a local area "); - data.append("network. Synergy is supported on Windows, Mac OS X and Linux."); +TEST(ClipboardTests, marshall_withTextSize285_sizeCharsValid) { + // 285 chars + String data; + data.append("Synergy is Free and Open Source Software that lets you "); + data.append("easily share your mouse and keyboard between multiple "); + data.append("computers, where each computer has it's own display. No "); + data.append("special hardware is required, all you need is a local area "); + data.append("network. Synergy is supported on Windows, Mac OS X and Linux."); - Clipboard clipboard; - clipboard.open(0); - clipboard.add(IClipboard::kText, data); - clipboard.close(); + Clipboard clipboard; + clipboard.open(0); + clipboard.add(IClipboard::kText, data); + clipboard.close(); - String actual = clipboard.marshall(); + String actual = clipboard.marshall(); - // 4 asserts here, but that's ok because we're really just asserting 1 - // thing. the 32-bit size value is split into 4 chars. if the size is 285 - // (29 more than the 8-bit max size), the last char "rolls over" to 29 - // (this is caused by a bit-wise & on 0xff and 8-bit truncation). each - // char before the last stores a bit-shifted version of the number, each - // 1 more power than the last, which is done by bit-shifting [0] by 24, - // [1] by 16, [2] by 8 ([3] is not bit-shifted). - EXPECT_EQ(0, actual[8]); // 285 >> 24 = 285 / (256^3) = 0 - EXPECT_EQ(0, actual[9]); // 285 >> 16 = 285 / (256^2) = 0 - EXPECT_EQ(1, actual[10]); // 285 >> 8 = 285 / (256^1) = 1(.11328125) - EXPECT_EQ(29, actual[11]); // 285 - 256 = 29 + // 4 asserts here, but that's ok because we're really just asserting 1 + // thing. the 32-bit size value is split into 4 chars. if the size is 285 + // (29 more than the 8-bit max size), the last char "rolls over" to 29 + // (this is caused by a bit-wise & on 0xff and 8-bit truncation). each + // char before the last stores a bit-shifted version of the number, each + // 1 more power than the last, which is done by bit-shifting [0] by 24, + // [1] by 16, [2] by 8 ([3] is not bit-shifted). + EXPECT_EQ(0, actual[8]); // 285 >> 24 = 285 / (256^3) = 0 + EXPECT_EQ(0, actual[9]); // 285 >> 16 = 285 / (256^2) = 0 + EXPECT_EQ(1, actual[10]); // 285 >> 8 = 285 / (256^1) = 1(.11328125) + EXPECT_EQ(29, actual[11]); // 285 - 256 = 29 } -TEST(ClipboardTests, marshall_withHtmlAdded_typeCharIsHtml) -{ - Clipboard clipboard; - clipboard.open(0); - clipboard.add(IClipboard::kHTML, "html sucks"); - clipboard.close(); +TEST(ClipboardTests, marshall_withHtmlAdded_typeCharIsHtml) { + Clipboard clipboard; + clipboard.open(0); + clipboard.add(IClipboard::kHTML, "html sucks"); + clipboard.close(); - String actual = clipboard.marshall(); + String actual = clipboard.marshall(); - // string contains other data, but 8th char should be kHTML. - EXPECT_EQ(IClipboard::kHTML, (int)actual[7]); + // string contains other data, but 8th char should be kHTML. + EXPECT_EQ(IClipboard::kHTML, (int)actual[7]); } -TEST(ClipboardTests, marshall_withHtmlAndText_has2Formats) -{ - Clipboard clipboard; - clipboard.open(0); - clipboard.add(IClipboard::kText, "synergy rocks"); - clipboard.add(IClipboard::kHTML, "html sucks"); - clipboard.close(); +TEST(ClipboardTests, marshall_withHtmlAndText_has2Formats) { + Clipboard clipboard; + clipboard.open(0); + clipboard.add(IClipboard::kText, "synergy rocks"); + clipboard.add(IClipboard::kHTML, "html sucks"); + clipboard.close(); - String actual = clipboard.marshall(); + String actual = clipboard.marshall(); - // the number of formats is stored inside the first 4 chars. - // the writeUInt32 function right-aligns numbers in 4 chars, - // so if you right align 2, it will be "\0\0\0\2" in a string. - // we assert that the char at the 4th index is 2 (the number of - // formats that we've added). - EXPECT_EQ(2, (int)actual[3]); + // the number of formats is stored inside the first 4 chars. + // the writeUInt32 function right-aligns numbers in 4 chars, + // so if you right align 2, it will be "\0\0\0\2" in a string. + // we assert that the char at the 4th index is 2 (the number of + // formats that we've added). + EXPECT_EQ(2, (int)actual[3]); } -TEST(ClipboardTests, marshall_withTextAdded_endsWithAdded) -{ - Clipboard clipboard; - clipboard.open(0); - clipboard.add(IClipboard::kText, "synergy rocks!"); - clipboard.close(); +TEST(ClipboardTests, marshall_withTextAdded_endsWithAdded) { + Clipboard clipboard; + clipboard.open(0); + clipboard.add(IClipboard::kText, "synergy rocks!"); + clipboard.close(); - String actual = clipboard.marshall(); + String actual = clipboard.marshall(); - // string contains other data, but should end in the string we added. - EXPECT_EQ("synergy rocks!", actual.substr(12)); + // string contains other data, but should end in the string we added. + EXPECT_EQ("synergy rocks!", actual.substr(12)); } -TEST(ClipboardTests, unmarshall_emptyData_hasTextIsFalse) -{ - Clipboard clipboard; +TEST(ClipboardTests, unmarshall_emptyData_hasTextIsFalse) { + Clipboard clipboard; - String data; - data += (char)0; - data += (char)0; - data += (char)0; - data += (char)0; // 0 formats added + String data; + data += (char)0; + data += (char)0; + data += (char)0; + data += (char)0; // 0 formats added - clipboard.unmarshall(data, 0); + clipboard.unmarshall(data, 0); - clipboard.open(0); - bool actual = clipboard.has(IClipboard::kText); - EXPECT_FALSE(actual); + clipboard.open(0); + bool actual = clipboard.has(IClipboard::kText); + EXPECT_FALSE(actual); } -TEST(ClipboardTests, unmarshall_withTextSize285_getTextIsValid) -{ - Clipboard clipboard; +TEST(ClipboardTests, unmarshall_withTextSize285_getTextIsValid) { + Clipboard clipboard; - // 285 chars - String text; - text.append("Synergy is Free and Open Source Software that lets you "); - text.append("easily share your mouse and keyboard between multiple "); - text.append("computers, where each computer has it's own display. No "); - text.append("special hardware is required, all you need is a local area "); - text.append("network. Synergy is supported on Windows, Mac OS X and Linux."); + // 285 chars + String text; + text.append("Synergy is Free and Open Source Software that lets you "); + text.append("easily share your mouse and keyboard between multiple "); + text.append("computers, where each computer has it's own display. No "); + text.append("special hardware is required, all you need is a local area "); + text.append("network. Synergy is supported on Windows, Mac OS X and Linux."); - String data; - data += (char)0; - data += (char)0; - data += (char)0; - data += (char)1; // 1 format added - data += (char)0; - data += (char)0; - data += (char)0; - data += (char)IClipboard::kText; - data += (char)0; // 285 >> 24 = 285 / (256^3) = 0 - data += (char)0; // 285 >> 16 = 285 / (256^2) = 0 - data += (char)1; // 285 >> 8 = 285 / (256^1) = 1(.11328125) - data += (char)29; // 285 - 256 = 29 - data += text; + String data; + data += (char)0; + data += (char)0; + data += (char)0; + data += (char)1; // 1 format added + data += (char)0; + data += (char)0; + data += (char)0; + data += (char)IClipboard::kText; + data += (char)0; // 285 >> 24 = 285 / (256^3) = 0 + data += (char)0; // 285 >> 16 = 285 / (256^2) = 0 + data += (char)1; // 285 >> 8 = 285 / (256^1) = 1(.11328125) + data += (char)29; // 285 - 256 = 29 + data += text; - clipboard.unmarshall(data, 0); + clipboard.unmarshall(data, 0); - clipboard.open(0); - String actual = clipboard.get(IClipboard::kText); - EXPECT_EQ(text, actual); + clipboard.open(0); + String actual = clipboard.get(IClipboard::kText); + EXPECT_EQ(text, actual); } -TEST(ClipboardTests, unmarshall_withTextAndHtml_getTextIsValid) -{ - Clipboard clipboard; - String data; - data += (char)0; - data += (char)0; - data += (char)0; - data += (char)2; // 2 formats added - data += (char)0; - data += (char)0; - data += (char)0; - data += (char)IClipboard::kText; - data += (char)0; - data += (char)0; - data += (char)0; - data += (char)14; - data += "synergy rocks!"; - data += (char)0; - data += (char)0; - data += (char)0; - data += (char)IClipboard::kHTML; - data += (char)0; - data += (char)0; - data += (char)0; - data += (char)10; - data += "html sucks"; +TEST(ClipboardTests, unmarshall_withTextAndHtml_getTextIsValid) { + Clipboard clipboard; + String data; + data += (char)0; + data += (char)0; + data += (char)0; + data += (char)2; // 2 formats added + data += (char)0; + data += (char)0; + data += (char)0; + data += (char)IClipboard::kText; + data += (char)0; + data += (char)0; + data += (char)0; + data += (char)14; + data += "synergy rocks!"; + data += (char)0; + data += (char)0; + data += (char)0; + data += (char)IClipboard::kHTML; + data += (char)0; + data += (char)0; + data += (char)0; + data += (char)10; + data += "html sucks"; - clipboard.unmarshall(data, 0); + clipboard.unmarshall(data, 0); - clipboard.open(0); - String actual = clipboard.get(IClipboard::kText); - EXPECT_EQ("synergy rocks!", actual); + clipboard.open(0); + String actual = clipboard.get(IClipboard::kText); + EXPECT_EQ("synergy rocks!", actual); } -TEST(ClipboardTests, unmarshall_withTextAndHtml_getHtmlIsValid) -{ - Clipboard clipboard; - String data; - data += (char)0; - data += (char)0; - data += (char)0; - data += (char)2; // 2 formats added - data += (char)0; - data += (char)0; - data += (char)0; - data += (char)IClipboard::kText; - data += (char)0; - data += (char)0; - data += (char)0; - data += (char)14; - data += "synergy rocks!"; - data += (char)0; - data += (char)0; - data += (char)0; - data += (char)IClipboard::kHTML; - data += (char)0; - data += (char)0; - data += (char)0; - data += (char)10; - data += "html sucks"; +TEST(ClipboardTests, unmarshall_withTextAndHtml_getHtmlIsValid) { + Clipboard clipboard; + String data; + data += (char)0; + data += (char)0; + data += (char)0; + data += (char)2; // 2 formats added + data += (char)0; + data += (char)0; + data += (char)0; + data += (char)IClipboard::kText; + data += (char)0; + data += (char)0; + data += (char)0; + data += (char)14; + data += "synergy rocks!"; + data += (char)0; + data += (char)0; + data += (char)0; + data += (char)IClipboard::kHTML; + data += (char)0; + data += (char)0; + data += (char)0; + data += (char)10; + data += "html sucks"; - clipboard.unmarshall(data, 0); + clipboard.unmarshall(data, 0); - clipboard.open(0); - String actual = clipboard.get(IClipboard::kHTML); - EXPECT_EQ("html sucks", actual); + clipboard.open(0); + String actual = clipboard.get(IClipboard::kHTML); + EXPECT_EQ("html sucks", actual); } -TEST(ClipboardTests, copy_withSingleText_clipboardsAreEqual) -{ - Clipboard clipboard1; - clipboard1.open(0); - clipboard1.add(Clipboard::kText, "synergy rocks!"); - clipboard1.close(); +TEST(ClipboardTests, copy_withSingleText_clipboardsAreEqual) { + Clipboard clipboard1; + clipboard1.open(0); + clipboard1.add(Clipboard::kText, "synergy rocks!"); + clipboard1.close(); - Clipboard clipboard2; - Clipboard::copy(&clipboard2, &clipboard1); + Clipboard clipboard2; + Clipboard::copy(&clipboard2, &clipboard1); - clipboard2.open(0); - String actual = clipboard2.get(Clipboard::kText); - EXPECT_EQ("synergy rocks!", actual); + clipboard2.open(0); + String actual = clipboard2.get(Clipboard::kText); + EXPECT_EQ("synergy rocks!", actual); } diff --git a/src/test/unittests/synergy/DeprecatedArgsParsingTests.cpp b/src/test/unittests/synergy/DeprecatedArgsParsingTests.cpp index 7996c99b5..18dd52dc1 100644 --- a/src/test/unittests/synergy/DeprecatedArgsParsingTests.cpp +++ b/src/test/unittests/synergy/DeprecatedArgsParsingTests.cpp @@ -21,30 +21,28 @@ using namespace synergy; -TEST(DeprecatedArgsParsingTests, parseDeprecatedArgs_cryptoPass_returnTrue) -{ - int i = 1; - const int argc = 3; - const char* kCryptoPassCmd[argc] = { "stub", "--crypto-pass", "mock_pass" }; +TEST(DeprecatedArgsParsingTests, parseDeprecatedArgs_cryptoPass_returnTrue) { + int i = 1; + const int argc = 3; + const char *kCryptoPassCmd[argc] = {"stub", "--crypto-pass", "mock_pass"}; - ArgParser argParser(NULL); + ArgParser argParser(NULL); - bool result = argParser.parseDeprecatedArgs(argc, kCryptoPassCmd, i); + bool result = argParser.parseDeprecatedArgs(argc, kCryptoPassCmd, i); - EXPECT_EQ(true, result); - EXPECT_EQ(2, i); + EXPECT_EQ(true, result); + EXPECT_EQ(2, i); } -TEST(DeprecatedArgsParsingTests, parseDeprecatedArgs_cryptoPass_returnFalse) -{ - int i = 1; - const int argc = 3; - const char* kCryptoPassCmd[argc] = { "stub", "--mock-arg", "mock_value" }; +TEST(DeprecatedArgsParsingTests, parseDeprecatedArgs_cryptoPass_returnFalse) { + int i = 1; + const int argc = 3; + const char *kCryptoPassCmd[argc] = {"stub", "--mock-arg", "mock_value"}; - ArgParser argParser(NULL); + ArgParser argParser(NULL); - bool result = argParser.parseDeprecatedArgs(argc, kCryptoPassCmd, i); + bool result = argParser.parseDeprecatedArgs(argc, kCryptoPassCmd, i); - EXPECT_FALSE(result); - EXPECT_EQ(1, i); + EXPECT_FALSE(result); + EXPECT_EQ(1, i); } diff --git a/src/test/unittests/synergy/GenericArgsParsingTests.cpp b/src/test/unittests/synergy/GenericArgsParsingTests.cpp index 0510d394a..5f4e3b525 100644 --- a/src/test/unittests/synergy/GenericArgsParsingTests.cpp +++ b/src/test/unittests/synergy/GenericArgsParsingTests.cpp @@ -1,11 +1,11 @@ /* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2014-2016 Symless Ltd. - * + * * 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 LICENSE 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 @@ -29,244 +29,217 @@ using ::testing::NiceMock; bool g_helpShowed = false; bool g_versionShowed = false; -void -showMockHelp() -{ - g_helpShowed = true; -} +void showMockHelp() { g_helpShowed = true; } -void -showMockVersion() -{ - g_versionShowed = true; -} +void showMockVersion() { g_versionShowed = true; } -class GenericArgsParsingTests : public ::testing::Test -{ +class GenericArgsParsingTests : public ::testing::Test { public: - void SetUp() - { - m_argParser = new ArgParser(nullptr); - m_argParser->setArgsBase(argsBase); - } + void SetUp() { + m_argParser = new ArgParser(nullptr); + m_argParser->setArgsBase(argsBase); + } - void TearDown() - { - delete m_argParser; - } + void TearDown() { delete m_argParser; } - static lib::synergy::ArgsBase argsBase; - ArgParser* m_argParser = nullptr; + static lib::synergy::ArgsBase argsBase; + ArgParser *m_argParser = nullptr; }; lib::synergy::ArgsBase GenericArgsParsingTests::argsBase; -TEST_F(GenericArgsParsingTests, parseGenericArgs_logLevelCmd_setLogLevel) -{ - int i = 1; - const int argc = 3; - const char* kLogLevelCmd[argc] = { "stub", "--debug", "DEBUG" }; +TEST_F(GenericArgsParsingTests, parseGenericArgs_logLevelCmd_setLogLevel) { + int i = 1; + const int argc = 3; + const char *kLogLevelCmd[argc] = {"stub", "--debug", "DEBUG"}; - m_argParser->parseGenericArgs(argc, kLogLevelCmd, i); - String logFilter(argsBase.m_logFilter); + m_argParser->parseGenericArgs(argc, kLogLevelCmd, i); + String logFilter(argsBase.m_logFilter); - EXPECT_EQ("DEBUG", logFilter); - EXPECT_EQ(2, i); + EXPECT_EQ("DEBUG", logFilter); + EXPECT_EQ(2, i); } -TEST_F(GenericArgsParsingTests, parseGenericArgs_logFileCmd_saveLogFilename) -{ - int i = 1; - const int argc = 3; - const char* kLogFileCmd[argc] = { "stub", "--log", "mock_filename" }; +TEST_F(GenericArgsParsingTests, parseGenericArgs_logFileCmd_saveLogFilename) { + int i = 1; + const int argc = 3; + const char *kLogFileCmd[argc] = {"stub", "--log", "mock_filename"}; - m_argParser->parseGenericArgs(argc, kLogFileCmd, i); - String logFile(argsBase.m_logFile); + m_argParser->parseGenericArgs(argc, kLogFileCmd, i); + String logFile(argsBase.m_logFile); - EXPECT_EQ("mock_filename", logFile); - EXPECT_EQ(2, i); + EXPECT_EQ("mock_filename", logFile); + EXPECT_EQ(2, i); } -TEST_F(GenericArgsParsingTests, parseGenericArgs_logFileCmdWithSpace_saveLogFilename) -{ - int i = 1; - const int argc = 3; - const char* kLogFileCmdWithSpace[argc] = { "stub", "--log", "mo ck_filename" }; +TEST_F(GenericArgsParsingTests, + parseGenericArgs_logFileCmdWithSpace_saveLogFilename) { + int i = 1; + const int argc = 3; + const char *kLogFileCmdWithSpace[argc] = {"stub", "--log", "mo ck_filename"}; - m_argParser->parseGenericArgs(argc, kLogFileCmdWithSpace, i); - String logFile(argsBase.m_logFile); + m_argParser->parseGenericArgs(argc, kLogFileCmdWithSpace, i); + String logFile(argsBase.m_logFile); - EXPECT_EQ("mo ck_filename", logFile); - EXPECT_EQ(2, i); + EXPECT_EQ("mo ck_filename", logFile); + EXPECT_EQ(2, i); } -TEST_F(GenericArgsParsingTests, parseGenericArgs_noDeamonCmd_daemonFalse) -{ - int i = 1; - const int argc = 2; - const char* kNoDeamonCmd[argc] = { "stub", "-f" }; +TEST_F(GenericArgsParsingTests, parseGenericArgs_noDeamonCmd_daemonFalse) { + int i = 1; + const int argc = 2; + const char *kNoDeamonCmd[argc] = {"stub", "-f"}; - m_argParser->parseGenericArgs(argc, kNoDeamonCmd, i); + m_argParser->parseGenericArgs(argc, kNoDeamonCmd, i); - EXPECT_FALSE(argsBase.m_daemon); - EXPECT_EQ(1, i); + EXPECT_FALSE(argsBase.m_daemon); + EXPECT_EQ(1, i); } -TEST_F(GenericArgsParsingTests, parseGenericArgs_deamonCmd_daemonTrue) -{ - int i = 1; - const int argc = 2; - const char* kDeamonCmd[argc] = { "stub", "--daemon" }; +TEST_F(GenericArgsParsingTests, parseGenericArgs_deamonCmd_daemonTrue) { + int i = 1; + const int argc = 2; + const char *kDeamonCmd[argc] = {"stub", "--daemon"}; - m_argParser->parseGenericArgs(argc, kDeamonCmd, i); + m_argParser->parseGenericArgs(argc, kDeamonCmd, i); - EXPECT_EQ(true, argsBase.m_daemon); - EXPECT_EQ(1, i); + EXPECT_EQ(true, argsBase.m_daemon); + EXPECT_EQ(1, i); } -TEST_F(GenericArgsParsingTests, parseGenericArgs_nameCmd_saveName) -{ - int i = 1; - const int argc = 3; - const char* kNameCmd[argc] = { "stub", "--name", "mock" }; +TEST_F(GenericArgsParsingTests, parseGenericArgs_nameCmd_saveName) { + int i = 1; + const int argc = 3; + const char *kNameCmd[argc] = {"stub", "--name", "mock"}; - m_argParser->parseGenericArgs(argc, kNameCmd, i); + m_argParser->parseGenericArgs(argc, kNameCmd, i); - EXPECT_EQ("mock", argsBase.m_name); - EXPECT_EQ(2, i); + EXPECT_EQ("mock", argsBase.m_name); + EXPECT_EQ(2, i); } -TEST_F(GenericArgsParsingTests, parseGenericArgs_noRestartCmd_restartFalse) -{ - int i = 1; - const int argc = 2; - const char* kNoRestartCmd[argc] = { "stub", "--no-restart" }; +TEST_F(GenericArgsParsingTests, parseGenericArgs_noRestartCmd_restartFalse) { + int i = 1; + const int argc = 2; + const char *kNoRestartCmd[argc] = {"stub", "--no-restart"}; - m_argParser->parseGenericArgs(argc, kNoRestartCmd, i); + m_argParser->parseGenericArgs(argc, kNoRestartCmd, i); - EXPECT_FALSE(argsBase.m_restartable); - EXPECT_EQ(1, i); + EXPECT_FALSE(argsBase.m_restartable); + EXPECT_EQ(1, i); } -TEST_F(GenericArgsParsingTests, parseGenericArgs_restartCmd_restartTrue) -{ - int i = 1; - const int argc = 2; - const char* kRestartCmd[argc] = { "stub", "--restart" }; +TEST_F(GenericArgsParsingTests, parseGenericArgs_restartCmd_restartTrue) { + int i = 1; + const int argc = 2; + const char *kRestartCmd[argc] = {"stub", "--restart"}; - m_argParser->parseGenericArgs(argc, kRestartCmd, i); + m_argParser->parseGenericArgs(argc, kRestartCmd, i); - EXPECT_EQ(true, argsBase.m_restartable); - EXPECT_EQ(1, i); + EXPECT_EQ(true, argsBase.m_restartable); + EXPECT_EQ(1, i); } -TEST_F(GenericArgsParsingTests, parseGenericArgs_backendCmd_rejected) -{ - int i = 1; - const int argc = 2; - const char* kBackendCmd[argc] = { "stub", "-z" }; +TEST_F(GenericArgsParsingTests, parseGenericArgs_backendCmd_rejected) { + int i = 1; + const int argc = 2; + const char *kBackendCmd[argc] = {"stub", "-z"}; - EXPECT_FALSE(m_argParser->parseGenericArgs(argc, kBackendCmd, i)); + EXPECT_FALSE(m_argParser->parseGenericArgs(argc, kBackendCmd, i)); } -TEST_F(GenericArgsParsingTests, parseGenericArgs_noHookCmd_noHookTrue) -{ - int i = 1; - const int argc = 2; - const char* kNoHookCmd[argc] = { "stub", "--no-hooks" }; +TEST_F(GenericArgsParsingTests, parseGenericArgs_noHookCmd_noHookTrue) { + int i = 1; + const int argc = 2; + const char *kNoHookCmd[argc] = {"stub", "--no-hooks"}; - m_argParser->parseGenericArgs(argc, kNoHookCmd, i); + m_argParser->parseGenericArgs(argc, kNoHookCmd, i); - EXPECT_EQ(true, argsBase.m_noHooks); - EXPECT_EQ(1, i); + EXPECT_EQ(true, argsBase.m_noHooks); + EXPECT_EQ(1, i); } -TEST_F(GenericArgsParsingTests, parseGenericArgs_helpCmd_showHelp) -{ - g_helpShowed = false; - int i = 1; - const int argc = 2; - const char* kHelpCmd[argc] = { "stub", "--help" }; +TEST_F(GenericArgsParsingTests, parseGenericArgs_helpCmd_showHelp) { + g_helpShowed = false; + int i = 1; + const int argc = 2; + const char *kHelpCmd[argc] = {"stub", "--help"}; - NiceMock app; - ArgParser argParser(&app); - argParser.setArgsBase(argsBase); - ON_CALL(app, help()).WillByDefault(Invoke(showMockHelp)); + NiceMock app; + ArgParser argParser(&app); + argParser.setArgsBase(argsBase); + ON_CALL(app, help()).WillByDefault(Invoke(showMockHelp)); - argParser.parseGenericArgs(argc, kHelpCmd, i); + argParser.parseGenericArgs(argc, kHelpCmd, i); - EXPECT_EQ(true, g_helpShowed); - EXPECT_EQ(1, i); + EXPECT_EQ(true, g_helpShowed); + EXPECT_EQ(1, i); } +TEST_F(GenericArgsParsingTests, parseGenericArgs_versionCmd_showVersion) { + g_versionShowed = false; + int i = 1; + const int argc = 2; + const char *kVersionCmd[argc] = {"stub", "--version"}; -TEST_F(GenericArgsParsingTests, parseGenericArgs_versionCmd_showVersion) -{ - g_versionShowed = false; - int i = 1; - const int argc = 2; - const char* kVersionCmd[argc] = { "stub", "--version" }; + NiceMock app; + ArgParser argParser(&app); + argParser.setArgsBase(argsBase); - NiceMock app; - ArgParser argParser(&app); - argParser.setArgsBase(argsBase); + ON_CALL(app, version()).WillByDefault(Invoke(showMockVersion)); - ON_CALL(app, version()).WillByDefault(Invoke(showMockVersion)); + argParser.parseGenericArgs(argc, kVersionCmd, i); - argParser.parseGenericArgs(argc, kVersionCmd, i); - - EXPECT_EQ(true, g_versionShowed); - EXPECT_EQ(1, i); + EXPECT_EQ(true, g_versionShowed); + EXPECT_EQ(1, i); } -TEST_F(GenericArgsParsingTests, parseGenericArgs_noTrayCmd_disableTrayTrue) -{ - int i = 1; - const int argc = 2; - const char* kNoTrayCmd[argc] = { "stub", "--no-tray" }; +TEST_F(GenericArgsParsingTests, parseGenericArgs_noTrayCmd_disableTrayTrue) { + int i = 1; + const int argc = 2; + const char *kNoTrayCmd[argc] = {"stub", "--no-tray"}; - m_argParser->parseGenericArgs(argc, kNoTrayCmd, i); + m_argParser->parseGenericArgs(argc, kNoTrayCmd, i); - EXPECT_EQ(true, argsBase.m_disableTray); - EXPECT_EQ(1, i); + EXPECT_EQ(true, argsBase.m_disableTray); + EXPECT_EQ(1, i); } -TEST_F(GenericArgsParsingTests, parseGenericArgs_ipcCmd_enableIpcTrue) -{ - int i = 1; - const int argc = 2; - const char* kIpcCmd[argc] = { "stub", "--ipc" }; +TEST_F(GenericArgsParsingTests, parseGenericArgs_ipcCmd_enableIpcTrue) { + int i = 1; + const int argc = 2; + const char *kIpcCmd[argc] = {"stub", "--ipc"}; - m_argParser->parseGenericArgs(argc, kIpcCmd, i); + m_argParser->parseGenericArgs(argc, kIpcCmd, i); - EXPECT_EQ(true, argsBase.m_enableIpc); - EXPECT_EQ(1, i); + EXPECT_EQ(true, argsBase.m_enableIpc); + EXPECT_EQ(1, i); } -#ifndef WINAPI_XWINDOWS -TEST_F(GenericArgsParsingTests, parseGenericArgs_dragDropCmdOnNonLinux_enableDragDropTrue) -{ - int i = 1; - const int argc = 2; - const char* kDragDropCmd[argc] = { "stub", "--enable-drag-drop" }; +#ifndef WINAPI_XWINDOWS +TEST_F(GenericArgsParsingTests, + parseGenericArgs_dragDropCmdOnNonLinux_enableDragDropTrue) { + int i = 1; + const int argc = 2; + const char *kDragDropCmd[argc] = {"stub", "--enable-drag-drop"}; - m_argParser->parseGenericArgs(argc, kDragDropCmd, i); + m_argParser->parseGenericArgs(argc, kDragDropCmd, i); - EXPECT_EQ(true, argsBase.m_enableDragDrop); - EXPECT_EQ(1, i); + EXPECT_EQ(true, argsBase.m_enableDragDrop); + EXPECT_EQ(1, i); } #endif -#ifdef WINAPI_XWINDOWS -TEST_F(GenericArgsParsingTests, parseGenericArgs_dragDropCmdOnLinux_enableDragDropFalse) -{ - int i = 1; - const int argc = 2; - const char* kDragDropCmd[argc] = { "stub", "--enable-drag-drop" }; +#ifdef WINAPI_XWINDOWS +TEST_F(GenericArgsParsingTests, + parseGenericArgs_dragDropCmdOnLinux_enableDragDropFalse) { + int i = 1; + const int argc = 2; + const char *kDragDropCmd[argc] = {"stub", "--enable-drag-drop"}; - m_argParser->parseGenericArgs(argc, kDragDropCmd, i); + m_argParser->parseGenericArgs(argc, kDragDropCmd, i); - EXPECT_FALSE(argsBase.m_enableDragDrop); - EXPECT_EQ(1, i); + EXPECT_FALSE(argsBase.m_enableDragDrop); + EXPECT_EQ(1, i); } #endif diff --git a/src/test/unittests/synergy/KeyMapTests.cpp b/src/test/unittests/synergy/KeyMapTests.cpp index f6518f99b..bb8b00074 100644 --- a/src/test/unittests/synergy/KeyMapTests.cpp +++ b/src/test/unittests/synergy/KeyMapTests.cpp @@ -1,11 +1,11 @@ /* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2016 Symless - * + * * 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 LICENSE 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 @@ -19,214 +19,204 @@ #include "synergy/KeyMap.h" -#include "test/global/gtest.h" #include "test/global/gmock.h" +#include "test/global/gtest.h" using ::testing::_; -using ::testing::NiceMock; using ::testing::Invoke; +using ::testing::NiceMock; using ::testing::Return; using ::testing::ReturnRef; using ::testing::SaveArg; namespace synergy { - -TEST(KeyMapTests, findBestKey_requiredDown_matchExactFirstItem) -{ - KeyMap keyMap; - KeyMap::KeyEntryList entryList; - KeyMap::KeyItemList itemList; - KeyMap::KeyItem item; - item.m_required = KeyModifierShift; - item.m_sensitive = KeyModifierShift; - KeyModifierMask desiredState = KeyModifierShift; - itemList.push_back(item); - entryList.push_back(itemList); - EXPECT_EQ(0, keyMap.findBestKey(entryList, desiredState)); -} - -TEST(KeyMapTests, findBestKey_requiredAndExtraSensitiveDown_matchExactFirstItem) -{ - KeyMap keyMap; - KeyMap::KeyEntryList entryList; - KeyMap::KeyItemList itemList; - KeyMap::KeyItem item; - item.m_required = KeyModifierShift; - item.m_sensitive = KeyModifierShift | KeyModifierAlt; - KeyModifierMask desiredState = KeyModifierShift; - itemList.push_back(item); - entryList.push_back(itemList); +TEST(KeyMapTests, findBestKey_requiredDown_matchExactFirstItem) { + KeyMap keyMap; + KeyMap::KeyEntryList entryList; + KeyMap::KeyItemList itemList; + KeyMap::KeyItem item; + item.m_required = KeyModifierShift; + item.m_sensitive = KeyModifierShift; + KeyModifierMask desiredState = KeyModifierShift; + itemList.push_back(item); + entryList.push_back(itemList); - EXPECT_EQ(0, keyMap.findBestKey(entryList, desiredState)); + EXPECT_EQ(0, keyMap.findBestKey(entryList, desiredState)); } -TEST(KeyMapTests, findBestKey_requiredAndExtraSensitiveDown_matchExactSecondItem) -{ - KeyMap keyMap; - KeyMap::KeyEntryList entryList; - KeyMap::KeyItemList itemList1; - KeyMap::KeyItem item1; - item1.m_required = KeyModifierAlt; - item1.m_sensitive = KeyModifierShift | KeyModifierAlt; - KeyMap::KeyItemList itemList2; - KeyMap::KeyItem item2; - item2.m_required = KeyModifierShift; - item2.m_sensitive = KeyModifierShift | KeyModifierAlt; - KeyModifierMask desiredState = KeyModifierShift; - itemList1.push_back(item1); - itemList2.push_back(item2); - entryList.push_back(itemList1); - entryList.push_back(itemList2); +TEST(KeyMapTests, + findBestKey_requiredAndExtraSensitiveDown_matchExactFirstItem) { + KeyMap keyMap; + KeyMap::KeyEntryList entryList; + KeyMap::KeyItemList itemList; + KeyMap::KeyItem item; + item.m_required = KeyModifierShift; + item.m_sensitive = KeyModifierShift | KeyModifierAlt; + KeyModifierMask desiredState = KeyModifierShift; + itemList.push_back(item); + entryList.push_back(itemList); - EXPECT_EQ(1, keyMap.findBestKey(entryList, desiredState)); -} - -TEST(KeyMapTests, findBestKey_extraSensitiveDown_matchExactSecondItem) -{ - KeyMap keyMap; - KeyMap::KeyEntryList entryList; - KeyMap::KeyItemList itemList1; - KeyMap::KeyItem item1; - item1.m_required = 0; - item1.m_sensitive = KeyModifierAlt; - KeyMap::KeyItemList itemList2; - KeyMap::KeyItem item2; - item2.m_required = 0; - item2.m_sensitive = KeyModifierShift; - KeyModifierMask desiredState = KeyModifierAlt; - itemList1.push_back(item1); - itemList2.push_back(item2); - entryList.push_back(itemList1); - entryList.push_back(itemList2); - - EXPECT_EQ(1, keyMap.findBestKey(entryList, desiredState)); + EXPECT_EQ(0, keyMap.findBestKey(entryList, desiredState)); } -TEST(KeyMapTests, findBestKey_noRequiredDown_matchOneRequiredChangeItem) -{ - KeyMap keyMap; - KeyMap::KeyEntryList entryList; - KeyMap::KeyItemList itemList1; - KeyMap::KeyItem item1; - item1.m_required = KeyModifierShift | KeyModifierAlt; - item1.m_sensitive = KeyModifierShift | KeyModifierAlt; - KeyMap::KeyItemList itemList2; - KeyMap::KeyItem item2; - item2.m_required = KeyModifierShift; - item2.m_sensitive = KeyModifierShift | KeyModifierAlt; - KeyModifierMask desiredState = 0; - itemList1.push_back(item1); - itemList2.push_back(item2); - entryList.push_back(itemList1); - entryList.push_back(itemList2); - - EXPECT_EQ(1, keyMap.findBestKey(entryList, desiredState)); +TEST(KeyMapTests, + findBestKey_requiredAndExtraSensitiveDown_matchExactSecondItem) { + KeyMap keyMap; + KeyMap::KeyEntryList entryList; + KeyMap::KeyItemList itemList1; + KeyMap::KeyItem item1; + item1.m_required = KeyModifierAlt; + item1.m_sensitive = KeyModifierShift | KeyModifierAlt; + KeyMap::KeyItemList itemList2; + KeyMap::KeyItem item2; + item2.m_required = KeyModifierShift; + item2.m_sensitive = KeyModifierShift | KeyModifierAlt; + KeyModifierMask desiredState = KeyModifierShift; + itemList1.push_back(item1); + itemList2.push_back(item2); + entryList.push_back(itemList1); + entryList.push_back(itemList2); + + EXPECT_EQ(1, keyMap.findBestKey(entryList, desiredState)); } -TEST(KeyMapTests, findBestKey_onlyOneRequiredDown_matchTwoRequiredChangesItem) -{ - KeyMap keyMap; - KeyMap::KeyEntryList entryList; - KeyMap::KeyItemList itemList1; - KeyMap::KeyItem item1; - item1.m_required = KeyModifierShift | KeyModifierAlt | KeyModifierControl; - item1.m_sensitive = KeyModifierShift | KeyModifierAlt | KeyModifierControl; - KeyMap::KeyItemList itemList2; - KeyMap::KeyItem item2; - item2.m_required = KeyModifierShift| KeyModifierAlt; - item2.m_sensitive = KeyModifierShift | KeyModifierAlt | KeyModifierControl; - KeyModifierMask desiredState = 0; - itemList1.push_back(item1); - itemList2.push_back(item2); - entryList.push_back(itemList1); - entryList.push_back(itemList2); +TEST(KeyMapTests, findBestKey_extraSensitiveDown_matchExactSecondItem) { + KeyMap keyMap; + KeyMap::KeyEntryList entryList; + KeyMap::KeyItemList itemList1; + KeyMap::KeyItem item1; + item1.m_required = 0; + item1.m_sensitive = KeyModifierAlt; + KeyMap::KeyItemList itemList2; + KeyMap::KeyItem item2; + item2.m_required = 0; + item2.m_sensitive = KeyModifierShift; + KeyModifierMask desiredState = KeyModifierAlt; + itemList1.push_back(item1); + itemList2.push_back(item2); + entryList.push_back(itemList1); + entryList.push_back(itemList2); - EXPECT_EQ(1, keyMap.findBestKey(entryList, desiredState)); -} - -TEST(KeyMapTests, findBestKey_noRequiredDown_cannotMatch) -{ - KeyMap keyMap; - KeyMap::KeyEntryList entryList; - KeyMap::KeyItemList itemList; - KeyMap::KeyItem item; - item.m_required = 0xffffffff; - item.m_sensitive = 0xffffffff; - KeyModifierMask desiredState = 0; - itemList.push_back(item); - entryList.push_back(itemList); - - EXPECT_EQ(-1, keyMap.findBestKey(entryList, desiredState)); -} - -TEST(KeyMapTests, isCommand_shiftMask_returnFalse) -{ - KeyMap keyMap; - KeyModifierMask mask= KeyModifierShift; - - EXPECT_FALSE(keyMap.isCommand(mask)); -} - -TEST(KeyMapTests, isCommand_controlMask_returnTrue) -{ - KeyMap keyMap; - KeyModifierMask mask= KeyModifierControl; - - EXPECT_EQ(true, keyMap.isCommand(mask)); -} - -TEST(KeyMapTests, isCommand_alternateMask_returnTrue) -{ - KeyMap keyMap; - KeyModifierMask mask= KeyModifierAlt; - - EXPECT_EQ(true, keyMap.isCommand(mask)); + EXPECT_EQ(1, keyMap.findBestKey(entryList, desiredState)); } -TEST(KeyMapTests, isCommand_alternateGraphicMask_returnTrue) -{ - KeyMap keyMap; - KeyModifierMask mask= KeyModifierAltGr; - - EXPECT_EQ(true, keyMap.isCommand(mask)); -} - -TEST(KeyMapTests, isCommand_metaMask_returnTrue) -{ - KeyMap keyMap; - KeyModifierMask mask= KeyModifierMeta; - - EXPECT_EQ(true, keyMap.isCommand(mask)); +TEST(KeyMapTests, findBestKey_noRequiredDown_matchOneRequiredChangeItem) { + KeyMap keyMap; + KeyMap::KeyEntryList entryList; + KeyMap::KeyItemList itemList1; + KeyMap::KeyItem item1; + item1.m_required = KeyModifierShift | KeyModifierAlt; + item1.m_sensitive = KeyModifierShift | KeyModifierAlt; + KeyMap::KeyItemList itemList2; + KeyMap::KeyItem item2; + item2.m_required = KeyModifierShift; + item2.m_sensitive = KeyModifierShift | KeyModifierAlt; + KeyModifierMask desiredState = 0; + itemList1.push_back(item1); + itemList2.push_back(item2); + entryList.push_back(itemList1); + entryList.push_back(itemList2); + + EXPECT_EQ(1, keyMap.findBestKey(entryList, desiredState)); } -TEST(KeyMapTests, isCommand_superMask_returnTrue) -{ - KeyMap keyMap; - KeyModifierMask mask= KeyModifierSuper; - - EXPECT_EQ(true, keyMap.isCommand(mask)); +TEST(KeyMapTests, findBestKey_onlyOneRequiredDown_matchTwoRequiredChangesItem) { + KeyMap keyMap; + KeyMap::KeyEntryList entryList; + KeyMap::KeyItemList itemList1; + KeyMap::KeyItem item1; + item1.m_required = KeyModifierShift | KeyModifierAlt | KeyModifierControl; + item1.m_sensitive = KeyModifierShift | KeyModifierAlt | KeyModifierControl; + KeyMap::KeyItemList itemList2; + KeyMap::KeyItem item2; + item2.m_required = KeyModifierShift | KeyModifierAlt; + item2.m_sensitive = KeyModifierShift | KeyModifierAlt | KeyModifierControl; + KeyModifierMask desiredState = 0; + itemList1.push_back(item1); + itemList2.push_back(item2); + entryList.push_back(itemList1); + entryList.push_back(itemList2); + + EXPECT_EQ(1, keyMap.findBestKey(entryList, desiredState)); } -TEST(KeyMapTests, mapkey_handles_setmodifier_with_no_mapped) -{ - KeyMap keyMap {}; - KeyMap::Keystroke stroke('A', true, false, 1); - KeyMap::KeyItem keyItem; - keyItem.m_button = 'A'; - keyItem.m_group = 1; - keyItem.m_id = 'A'; - keyMap.addKeyEntry(keyItem); - keyMap.finish(); - KeyMap::Keystrokes strokes {stroke}; - KeyMap::ModifierToKeys activeModifiers {}; - KeyModifierMask currentState {}; - KeyModifierMask desiredMask {}; - auto result = keyMap.mapKey(strokes, kKeySetModifiers, 1, activeModifiers, currentState, desiredMask, false, "en"); - EXPECT_FALSE(result == nullptr); - desiredMask = KeyModifierControl; - result = keyMap.mapKey(strokes, kKeySetModifiers, 1, activeModifiers, currentState, desiredMask, false, "en"); - EXPECT_TRUE(result == nullptr); +TEST(KeyMapTests, findBestKey_noRequiredDown_cannotMatch) { + KeyMap keyMap; + KeyMap::KeyEntryList entryList; + KeyMap::KeyItemList itemList; + KeyMap::KeyItem item; + item.m_required = 0xffffffff; + item.m_sensitive = 0xffffffff; + KeyModifierMask desiredState = 0; + itemList.push_back(item); + entryList.push_back(itemList); + + EXPECT_EQ(-1, keyMap.findBestKey(entryList, desiredState)); } +TEST(KeyMapTests, isCommand_shiftMask_returnFalse) { + KeyMap keyMap; + KeyModifierMask mask = KeyModifierShift; + + EXPECT_FALSE(keyMap.isCommand(mask)); } + +TEST(KeyMapTests, isCommand_controlMask_returnTrue) { + KeyMap keyMap; + KeyModifierMask mask = KeyModifierControl; + + EXPECT_EQ(true, keyMap.isCommand(mask)); +} + +TEST(KeyMapTests, isCommand_alternateMask_returnTrue) { + KeyMap keyMap; + KeyModifierMask mask = KeyModifierAlt; + + EXPECT_EQ(true, keyMap.isCommand(mask)); +} + +TEST(KeyMapTests, isCommand_alternateGraphicMask_returnTrue) { + KeyMap keyMap; + KeyModifierMask mask = KeyModifierAltGr; + + EXPECT_EQ(true, keyMap.isCommand(mask)); +} + +TEST(KeyMapTests, isCommand_metaMask_returnTrue) { + KeyMap keyMap; + KeyModifierMask mask = KeyModifierMeta; + + EXPECT_EQ(true, keyMap.isCommand(mask)); +} + +TEST(KeyMapTests, isCommand_superMask_returnTrue) { + KeyMap keyMap; + KeyModifierMask mask = KeyModifierSuper; + + EXPECT_EQ(true, keyMap.isCommand(mask)); +} + +TEST(KeyMapTests, mapkey_handles_setmodifier_with_no_mapped) { + KeyMap keyMap{}; + KeyMap::Keystroke stroke('A', true, false, 1); + KeyMap::KeyItem keyItem; + keyItem.m_button = 'A'; + keyItem.m_group = 1; + keyItem.m_id = 'A'; + keyMap.addKeyEntry(keyItem); + keyMap.finish(); + KeyMap::Keystrokes strokes{stroke}; + KeyMap::ModifierToKeys activeModifiers{}; + KeyModifierMask currentState{}; + KeyModifierMask desiredMask{}; + auto result = keyMap.mapKey(strokes, kKeySetModifiers, 1, activeModifiers, + currentState, desiredMask, false, "en"); + EXPECT_FALSE(result == nullptr); + desiredMask = KeyModifierControl; + result = keyMap.mapKey(strokes, kKeySetModifiers, 1, activeModifiers, + currentState, desiredMask, false, "en"); + EXPECT_TRUE(result == nullptr); +} + +} // namespace synergy diff --git a/src/test/unittests/synergy/KeyStateTests.cpp b/src/test/unittests/synergy/KeyStateTests.cpp index e5cf159bf..87522a9cf 100644 --- a/src/test/unittests/synergy/KeyStateTests.cpp +++ b/src/test/unittests/synergy/KeyStateTests.cpp @@ -2,11 +2,11 @@ * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2011 Nick Bolton - * + * * 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 LICENSE 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 @@ -16,487 +16,461 @@ * along with this program. If not, see . */ -#include "test/mock/synergy/MockKeyState.h" #include "test/mock/synergy/MockEventQueue.h" #include "test/mock/synergy/MockKeyMap.h" +#include "test/mock/synergy/MockKeyState.h" -#include "test/global/gtest.h" #include "test/global/gmock.h" +#include "test/global/gtest.h" using ::testing::_; -using ::testing::NiceMock; using ::testing::Invoke; +using ::testing::NiceMock; using ::testing::Return; using ::testing::ReturnRef; using ::testing::SaveArg; -void -stubPollPressedKeys(IKeyState::KeyButtonSet& pressedKeys); +void stubPollPressedKeys(IKeyState::KeyButtonSet &pressedKeys); -void -assertMaskIsOne(ForeachKeyCallback cb, void* userData); +void assertMaskIsOne(ForeachKeyCallback cb, void *userData); -const synergy::KeyMap::KeyItem* -stubMapKey( - synergy::KeyMap::Keystrokes& keys, KeyID id, SInt32 group, - synergy::KeyMap::ModifierToKeys& activeModifiers, - KeyModifierMask& currentState, - KeyModifierMask desiredMask, - bool isAutoRepeat, - const String& lang); +const synergy::KeyMap::KeyItem * +stubMapKey(synergy::KeyMap::Keystrokes &keys, KeyID id, SInt32 group, + synergy::KeyMap::ModifierToKeys &activeModifiers, + KeyModifierMask ¤tState, KeyModifierMask desiredMask, + bool isAutoRepeat, const String &lang); synergy::KeyMap::Keystroke s_stubKeystroke(1, false, false); synergy::KeyMap::KeyItem s_stubKeyItem; -TEST(CKeyStateTests, onKey_aKeyDown_keyStateOne) -{ - MockKeyMap keyMap; - MockEventQueue eventQueue; - KeyStateImpl keyState(eventQueue, keyMap); +TEST(CKeyStateTests, onKey_aKeyDown_keyStateOne) { + MockKeyMap keyMap; + MockEventQueue eventQueue; + KeyStateImpl keyState(eventQueue, keyMap); - keyState.onKey(1, true, KeyModifierAlt); + keyState.onKey(1, true, KeyModifierAlt); - EXPECT_EQ(1, keyState.getKeyState(1)); + EXPECT_EQ(1, keyState.getKeyState(1)); } -TEST(KeyStateTests, onKey_aKeyUp_keyStateZero) -{ - MockKeyMap keyMap; - MockEventQueue eventQueue; - KeyStateImpl keyState(eventQueue, keyMap); +TEST(KeyStateTests, onKey_aKeyUp_keyStateZero) { + MockKeyMap keyMap; + MockEventQueue eventQueue; + KeyStateImpl keyState(eventQueue, keyMap); - keyState.onKey(1, false, KeyModifierAlt); + keyState.onKey(1, false, KeyModifierAlt); - EXPECT_EQ(0, keyState.getKeyState(1)); + EXPECT_EQ(0, keyState.getKeyState(1)); } -TEST(KeyStateTests, onKey_invalidKey_keyStateZero) -{ - MockKeyMap keyMap; - MockEventQueue eventQueue; - KeyStateImpl keyState(eventQueue, keyMap); +TEST(KeyStateTests, onKey_invalidKey_keyStateZero) { + MockKeyMap keyMap; + MockEventQueue eventQueue; + KeyStateImpl keyState(eventQueue, keyMap); - keyState.onKey(0, true, KeyModifierAlt); + keyState.onKey(0, true, KeyModifierAlt); - EXPECT_EQ(0, keyState.getKeyState(0)); + EXPECT_EQ(0, keyState.getKeyState(0)); } -TEST(KeyStateTests, sendKeyEvent_halfDuplexAndRepeat_addEventNotCalled) -{ - NiceMock keyMap; - NiceMock eventQueue; - KeyStateImpl keyState(eventQueue, keyMap); +TEST(KeyStateTests, sendKeyEvent_halfDuplexAndRepeat_addEventNotCalled) { + NiceMock keyMap; + NiceMock eventQueue; + KeyStateImpl keyState(eventQueue, keyMap); - ON_CALL(keyMap, isHalfDuplex(_, _)).WillByDefault(Return(true)); + ON_CALL(keyMap, isHalfDuplex(_, _)).WillByDefault(Return(true)); - EXPECT_CALL(eventQueue, addEvent(_)).Times(0); + EXPECT_CALL(eventQueue, addEvent(_)).Times(0); - keyState.sendKeyEvent(NULL, false, true, kKeyCapsLock, 0, 0, 0); + keyState.sendKeyEvent(NULL, false, true, kKeyCapsLock, 0, 0, 0); } -TEST(KeyStateTests, sendKeyEvent_halfDuplex_addEventCalledTwice) -{ - NiceMock keyMap; - NiceMock eventQueue; - KeyStateImpl keyState(eventQueue, keyMap); - IKeyStateEvents keyStateEvents; - keyStateEvents.setEvents(&eventQueue); +TEST(KeyStateTests, sendKeyEvent_halfDuplex_addEventCalledTwice) { + NiceMock keyMap; + NiceMock eventQueue; + KeyStateImpl keyState(eventQueue, keyMap); + IKeyStateEvents keyStateEvents; + keyStateEvents.setEvents(&eventQueue); - ON_CALL(keyMap, isHalfDuplex(_, _)).WillByDefault(Return(true)); - ON_CALL(eventQueue, forIKeyState()).WillByDefault(ReturnRef(keyStateEvents)); + ON_CALL(keyMap, isHalfDuplex(_, _)).WillByDefault(Return(true)); + ON_CALL(eventQueue, forIKeyState()).WillByDefault(ReturnRef(keyStateEvents)); - EXPECT_CALL(eventQueue, addEvent(_)).Times(2); + EXPECT_CALL(eventQueue, addEvent(_)).Times(2); - keyState.sendKeyEvent(NULL, false, false, kKeyCapsLock, 0, 0, 0); + keyState.sendKeyEvent(NULL, false, false, kKeyCapsLock, 0, 0, 0); } -TEST(KeyStateTests, sendKeyEvent_keyRepeat_addEventCalledOnce) -{ - NiceMock keyMap; - NiceMock eventQueue; - KeyStateImpl keyState(eventQueue, keyMap); - IKeyStateEvents keyStateEvents; - keyStateEvents.setEvents(&eventQueue); +TEST(KeyStateTests, sendKeyEvent_keyRepeat_addEventCalledOnce) { + NiceMock keyMap; + NiceMock eventQueue; + KeyStateImpl keyState(eventQueue, keyMap); + IKeyStateEvents keyStateEvents; + keyStateEvents.setEvents(&eventQueue); - ON_CALL(eventQueue, forIKeyState()).WillByDefault(ReturnRef(keyStateEvents)); + ON_CALL(eventQueue, forIKeyState()).WillByDefault(ReturnRef(keyStateEvents)); - EXPECT_CALL(eventQueue, addEvent(_)).Times(1); + EXPECT_CALL(eventQueue, addEvent(_)).Times(1); - keyState.sendKeyEvent(NULL, false, true, 1, 0, 0, 0); + keyState.sendKeyEvent(NULL, false, true, 1, 0, 0, 0); } -TEST(KeyStateTests, sendKeyEvent_keyDown_addEventCalledOnce) -{ - NiceMock keyMap; - NiceMock eventQueue; - KeyStateImpl keyState(eventQueue, keyMap); - IKeyStateEvents keyStateEvents; - keyStateEvents.setEvents(&eventQueue); +TEST(KeyStateTests, sendKeyEvent_keyDown_addEventCalledOnce) { + NiceMock keyMap; + NiceMock eventQueue; + KeyStateImpl keyState(eventQueue, keyMap); + IKeyStateEvents keyStateEvents; + keyStateEvents.setEvents(&eventQueue); - ON_CALL(eventQueue, forIKeyState()).WillByDefault(ReturnRef(keyStateEvents)); + ON_CALL(eventQueue, forIKeyState()).WillByDefault(ReturnRef(keyStateEvents)); - EXPECT_CALL(eventQueue, addEvent(_)).Times(1); + EXPECT_CALL(eventQueue, addEvent(_)).Times(1); - keyState.sendKeyEvent(NULL, true, false, 1, 0, 0, 0); + keyState.sendKeyEvent(NULL, true, false, 1, 0, 0, 0); } -TEST(KeyStateTests, sendKeyEvent_keyUp_addEventCalledOnce) -{ - NiceMock keyMap; - NiceMock eventQueue; - KeyStateImpl keyState(eventQueue, keyMap); - IKeyStateEvents keyStateEvents; - keyStateEvents.setEvents(&eventQueue); +TEST(KeyStateTests, sendKeyEvent_keyUp_addEventCalledOnce) { + NiceMock keyMap; + NiceMock eventQueue; + KeyStateImpl keyState(eventQueue, keyMap); + IKeyStateEvents keyStateEvents; + keyStateEvents.setEvents(&eventQueue); - ON_CALL(eventQueue, forIKeyState()).WillByDefault(ReturnRef(keyStateEvents)); + ON_CALL(eventQueue, forIKeyState()).WillByDefault(ReturnRef(keyStateEvents)); - EXPECT_CALL(eventQueue, addEvent(_)).Times(1); + EXPECT_CALL(eventQueue, addEvent(_)).Times(1); - keyState.sendKeyEvent(NULL, false, false, 1, 0, 0, 0); + keyState.sendKeyEvent(NULL, false, false, 1, 0, 0, 0); } -TEST(KeyStateTests, updateKeyMap_mockKeyMap_keyMapGotMock) -{ - NiceMock keyMap; - MockEventQueue eventQueue; - KeyStateImpl keyState(eventQueue, keyMap); +TEST(KeyStateTests, updateKeyMap_mockKeyMap_keyMapGotMock) { + NiceMock keyMap; + MockEventQueue eventQueue; + KeyStateImpl keyState(eventQueue, keyMap); - // key map member gets a new key map via swap() - EXPECT_CALL(keyMap, swap(_)); + // key map member gets a new key map via swap() + EXPECT_CALL(keyMap, swap(_)); - keyState.updateKeyMap(); + keyState.updateKeyMap(); } -TEST(KeyStateTests, updateKeyState_pollInsertsSingleKey_keyIsDown) -{ - NiceMock keyMap; - MockEventQueue eventQueue; - KeyStateImpl keyState(eventQueue, keyMap); - ON_CALL(keyState, pollPressedKeys(_)).WillByDefault(Invoke(stubPollPressedKeys)); +TEST(KeyStateTests, updateKeyState_pollInsertsSingleKey_keyIsDown) { + NiceMock keyMap; + MockEventQueue eventQueue; + KeyStateImpl keyState(eventQueue, keyMap); + ON_CALL(keyState, pollPressedKeys(_)) + .WillByDefault(Invoke(stubPollPressedKeys)); - keyState.updateKeyState(); + keyState.updateKeyState(); - bool actual = keyState.isKeyDown(1); - ASSERT_TRUE(actual); + bool actual = keyState.isKeyDown(1); + ASSERT_TRUE(actual); } -TEST(KeyStateTests, updateKeyState_pollDoesNothing_keyNotSet) -{ - NiceMock keyMap; - MockEventQueue eventQueue; - KeyStateImpl keyState(eventQueue, keyMap); +TEST(KeyStateTests, updateKeyState_pollDoesNothing_keyNotSet) { + NiceMock keyMap; + MockEventQueue eventQueue; + KeyStateImpl keyState(eventQueue, keyMap); - keyState.updateKeyState(); + keyState.updateKeyState(); - bool actual = keyState.isKeyDown(1); - ASSERT_FALSE(actual); + bool actual = keyState.isKeyDown(1); + ASSERT_FALSE(actual); } -TEST(KeyStateTests, updateKeyState_activeModifiers_maskSet) -{ - NiceMock keyMap; - MockEventQueue eventQueue; - KeyStateImpl keyState(eventQueue, keyMap); - ON_CALL(keyState, pollActiveModifiers()).WillByDefault(Return(KeyModifierAlt)); +TEST(KeyStateTests, updateKeyState_activeModifiers_maskSet) { + NiceMock keyMap; + MockEventQueue eventQueue; + KeyStateImpl keyState(eventQueue, keyMap); + ON_CALL(keyState, pollActiveModifiers()) + .WillByDefault(Return(KeyModifierAlt)); - keyState.updateKeyState(); + keyState.updateKeyState(); - KeyModifierMask actual = keyState.getActiveModifiers(); - ASSERT_EQ(KeyModifierAlt, actual); + KeyModifierMask actual = keyState.getActiveModifiers(); + ASSERT_EQ(KeyModifierAlt, actual); } -TEST(KeyStateTests, updateKeyState_activeModifiers_maskNotSet) -{ - NiceMock keyMap; - MockEventQueue eventQueue; - KeyStateImpl keyState(eventQueue, keyMap); +TEST(KeyStateTests, updateKeyState_activeModifiers_maskNotSet) { + NiceMock keyMap; + MockEventQueue eventQueue; + KeyStateImpl keyState(eventQueue, keyMap); - keyState.updateKeyState(); + keyState.updateKeyState(); - KeyModifierMask actual = keyState.getActiveModifiers(); - ASSERT_EQ(0, actual); + KeyModifierMask actual = keyState.getActiveModifiers(); + ASSERT_EQ(0, actual); } -TEST(KeyStateTests, updateKeyState_activeModifiers_keyMapGotModifers) -{ - MockKeyMap keyMap; - MockEventQueue eventQueue; - KeyStateImpl keyState(eventQueue, keyMap); - ON_CALL(keyState, pollActiveModifiers()).WillByDefault(Return(1)); - ON_CALL(keyMap, foreachKey(_, _)).WillByDefault(Invoke(assertMaskIsOne)); +TEST(KeyStateTests, updateKeyState_activeModifiers_keyMapGotModifers) { + MockKeyMap keyMap; + MockEventQueue eventQueue; + KeyStateImpl keyState(eventQueue, keyMap); + ON_CALL(keyState, pollActiveModifiers()).WillByDefault(Return(1)); + ON_CALL(keyMap, foreachKey(_, _)).WillByDefault(Invoke(assertMaskIsOne)); - // key map gets new modifiers via foreachKey() - EXPECT_CALL(keyMap, foreachKey(_, _)); + // key map gets new modifiers via foreachKey() + EXPECT_CALL(keyMap, foreachKey(_, _)); - keyState.updateKeyState(); + keyState.updateKeyState(); } -TEST(KeyStateTests, setHalfDuplexMask_capsLock_halfDuplexCapsLockAdded) -{ - MockKeyMap keyMap; - MockEventQueue eventQueue; - KeyStateImpl keyState(eventQueue, keyMap); +TEST(KeyStateTests, setHalfDuplexMask_capsLock_halfDuplexCapsLockAdded) { + MockKeyMap keyMap; + MockEventQueue eventQueue; + KeyStateImpl keyState(eventQueue, keyMap); - EXPECT_CALL(keyMap, addHalfDuplexModifier(kKeyCapsLock)); + EXPECT_CALL(keyMap, addHalfDuplexModifier(kKeyCapsLock)); - keyState.setHalfDuplexMask(KeyModifierCapsLock); + keyState.setHalfDuplexMask(KeyModifierCapsLock); } -TEST(KeyStateTests, setHalfDuplexMask_numLock_halfDuplexNumLockAdded) -{ - MockKeyMap keyMap; - MockEventQueue eventQueue; - KeyStateImpl keyState(eventQueue, keyMap); +TEST(KeyStateTests, setHalfDuplexMask_numLock_halfDuplexNumLockAdded) { + MockKeyMap keyMap; + MockEventQueue eventQueue; + KeyStateImpl keyState(eventQueue, keyMap); - EXPECT_CALL(keyMap, addHalfDuplexModifier(kKeyNumLock)); + EXPECT_CALL(keyMap, addHalfDuplexModifier(kKeyNumLock)); - keyState.setHalfDuplexMask(KeyModifierNumLock); + keyState.setHalfDuplexMask(KeyModifierNumLock); } -TEST(KeyStateTests, setHalfDuplexMask_scrollLock_halfDuplexScollLockAdded) -{ - MockKeyMap keyMap; - MockEventQueue eventQueue; - KeyStateImpl keyState(eventQueue, keyMap); +TEST(KeyStateTests, setHalfDuplexMask_scrollLock_halfDuplexScollLockAdded) { + MockKeyMap keyMap; + MockEventQueue eventQueue; + KeyStateImpl keyState(eventQueue, keyMap); - EXPECT_CALL(keyMap, addHalfDuplexModifier(kKeyScrollLock)); + EXPECT_CALL(keyMap, addHalfDuplexModifier(kKeyScrollLock)); - keyState.setHalfDuplexMask(KeyModifierScrollLock); + keyState.setHalfDuplexMask(KeyModifierScrollLock); } -TEST(KeyStateTests, fakeKeyDown_serverKeyAlreadyDown_fakeKeyCalledTwice) -{ - NiceMock keyMap; - MockEventQueue eventQueue; - KeyStateImpl keyState(eventQueue, keyMap); - s_stubKeyItem.m_client = 0; - s_stubKeyItem.m_button = 1; - ON_CALL(keyMap, mapKey(_, _, _, _, _, _, _, _)).WillByDefault(Invoke(stubMapKey)); +TEST(KeyStateTests, fakeKeyDown_serverKeyAlreadyDown_fakeKeyCalledTwice) { + NiceMock keyMap; + MockEventQueue eventQueue; + KeyStateImpl keyState(eventQueue, keyMap); + s_stubKeyItem.m_client = 0; + s_stubKeyItem.m_button = 1; + ON_CALL(keyMap, mapKey(_, _, _, _, _, _, _, _)) + .WillByDefault(Invoke(stubMapKey)); - // 2 calls to fakeKeyDown should still call fakeKey, even though - // repeated keys are handled differently. - EXPECT_CALL(keyState, fakeKey(_)).Times(2); + // 2 calls to fakeKeyDown should still call fakeKey, even though + // repeated keys are handled differently. + EXPECT_CALL(keyState, fakeKey(_)).Times(2); - // call twice to simulate server key already down (a misreported autorepeat). - keyState.fakeKeyDown(1, 0, 0, "en"); - keyState.fakeKeyDown(1, 0, 0, "en"); + // call twice to simulate server key already down (a misreported autorepeat). + keyState.fakeKeyDown(1, 0, 0, "en"); + keyState.fakeKeyDown(1, 0, 0, "en"); } -TEST(KeyStateTests, fakeKeyDown_isIgnoredKey_fakeKeyNotCalled) -{ - MockKeyMap keyMap; - MockEventQueue eventQueue; - KeyStateImpl keyState(eventQueue, keyMap); +TEST(KeyStateTests, fakeKeyDown_isIgnoredKey_fakeKeyNotCalled) { + MockKeyMap keyMap; + MockEventQueue eventQueue; + KeyStateImpl keyState(eventQueue, keyMap); - EXPECT_CALL(keyState, fakeKey(_)).Times(0); + EXPECT_CALL(keyState, fakeKey(_)).Times(0); - keyState.fakeKeyDown(kKeyCapsLock, 0, 0, "en"); + keyState.fakeKeyDown(kKeyCapsLock, 0, 0, "en"); } -TEST(KeyStateTests, fakeKeyDown_mapReturnsKeystrokes_fakeKeyCalled) -{ - NiceMock keyMap; - MockEventQueue eventQueue; - KeyStateImpl keyState(eventQueue, keyMap); - s_stubKeyItem.m_button = 0; - s_stubKeyItem.m_client = 0; - ON_CALL(keyMap, mapKey(_, _, _, _, _, _, _, _)).WillByDefault(Invoke(stubMapKey)); +TEST(KeyStateTests, fakeKeyDown_mapReturnsKeystrokes_fakeKeyCalled) { + NiceMock keyMap; + MockEventQueue eventQueue; + KeyStateImpl keyState(eventQueue, keyMap); + s_stubKeyItem.m_button = 0; + s_stubKeyItem.m_client = 0; + ON_CALL(keyMap, mapKey(_, _, _, _, _, _, _, _)) + .WillByDefault(Invoke(stubMapKey)); - EXPECT_CALL(keyState, fakeKey(_)).Times(1); + EXPECT_CALL(keyState, fakeKey(_)).Times(1); - keyState.fakeKeyDown(1, 0, 0, "en"); + keyState.fakeKeyDown(1, 0, 0, "en"); } -TEST(KeyStateTests, fakeKeyRepeat_invalidKey_returnsFalse) -{ - MockKeyMap keyMap; - MockEventQueue eventQueue; - KeyStateImpl keyState(eventQueue, keyMap); +TEST(KeyStateTests, fakeKeyRepeat_invalidKey_returnsFalse) { + MockKeyMap keyMap; + MockEventQueue eventQueue; + KeyStateImpl keyState(eventQueue, keyMap); - bool actual = keyState.fakeKeyRepeat(0, 0, 0, 0, "en"); + bool actual = keyState.fakeKeyRepeat(0, 0, 0, 0, "en"); - ASSERT_FALSE(actual); + ASSERT_FALSE(actual); } -TEST(KeyStateTests, fakeKeyRepeat_nullKey_returnsFalse) -{ - NiceMock keyMap; - MockEventQueue eventQueue; - KeyStateImpl keyState(eventQueue, keyMap); +TEST(KeyStateTests, fakeKeyRepeat_nullKey_returnsFalse) { + NiceMock keyMap; + MockEventQueue eventQueue; + KeyStateImpl keyState(eventQueue, keyMap); - // set the key to down (we need to make mapKey return a valid key to do this). - synergy::KeyMap::KeyItem keyItem; - keyItem.m_client = 0; - keyItem.m_button = 1; - ON_CALL(keyMap, mapKey(_, _, _, _, _, _, _, _)).WillByDefault(Return(&keyItem)); - keyState.fakeKeyDown(1, 0, 0, "en"); + // set the key to down (we need to make mapKey return a valid key to do this). + synergy::KeyMap::KeyItem keyItem; + keyItem.m_client = 0; + keyItem.m_button = 1; + ON_CALL(keyMap, mapKey(_, _, _, _, _, _, _, _)) + .WillByDefault(Return(&keyItem)); + keyState.fakeKeyDown(1, 0, 0, "en"); - // change mapKey to return NULL so that fakeKeyRepeat exits early. - synergy::KeyMap::KeyItem* nullKeyItem = NULL; - ON_CALL(keyMap, mapKey(_, _, _, _, _, _, _, _)).WillByDefault(Return(nullKeyItem)); + // change mapKey to return NULL so that fakeKeyRepeat exits early. + synergy::KeyMap::KeyItem *nullKeyItem = NULL; + ON_CALL(keyMap, mapKey(_, _, _, _, _, _, _, _)) + .WillByDefault(Return(nullKeyItem)); - bool actual = keyState.fakeKeyRepeat(1, 0, 0, 0, "en"); + bool actual = keyState.fakeKeyRepeat(1, 0, 0, 0, "en"); - ASSERT_FALSE(actual); + ASSERT_FALSE(actual); } -TEST(KeyStateTests, fakeKeyRepeat_invalidButton_returnsFalse) -{ - NiceMock keyMap; - MockEventQueue eventQueue; - KeyStateImpl keyState(eventQueue, keyMap); +TEST(KeyStateTests, fakeKeyRepeat_invalidButton_returnsFalse) { + NiceMock keyMap; + MockEventQueue eventQueue; + KeyStateImpl keyState(eventQueue, keyMap); - // set the key to down (we need to make mapKey return a valid key to do this). - synergy::KeyMap::KeyItem keyItem; - keyItem.m_client = 0; - keyItem.m_button = 1; // set to 1 to make fakeKeyDown work. - ON_CALL(keyMap, mapKey(_, _, _, _, _, _, _, _)).WillByDefault(Return(&keyItem)); - keyState.fakeKeyDown(1, 0, 0, "en"); + // set the key to down (we need to make mapKey return a valid key to do this). + synergy::KeyMap::KeyItem keyItem; + keyItem.m_client = 0; + keyItem.m_button = 1; // set to 1 to make fakeKeyDown work. + ON_CALL(keyMap, mapKey(_, _, _, _, _, _, _, _)) + .WillByDefault(Return(&keyItem)); + keyState.fakeKeyDown(1, 0, 0, "en"); - // change button to 0 so that fakeKeyRepeat will return early. - keyItem.m_button = 0; - ON_CALL(keyMap, mapKey(_, _, _, _, _, _, _, _)).WillByDefault(Return(&keyItem)); + // change button to 0 so that fakeKeyRepeat will return early. + keyItem.m_button = 0; + ON_CALL(keyMap, mapKey(_, _, _, _, _, _, _, _)) + .WillByDefault(Return(&keyItem)); - bool actual = keyState.fakeKeyRepeat(1, 0, 0, 0, "en"); + bool actual = keyState.fakeKeyRepeat(1, 0, 0, 0, "en"); - ASSERT_FALSE(actual); + ASSERT_FALSE(actual); } -TEST(KeyStateTests, fakeKeyRepeat_validKey_returnsTrue) -{ - NiceMock keyMap; - MockEventQueue eventQueue; - KeyStateImpl keyState(eventQueue, keyMap); - s_stubKeyItem.m_client = 0; - s_stubKeystroke.m_type = synergy::KeyMap::Keystroke::kButton; - s_stubKeystroke.m_data.m_button.m_button = 2; +TEST(KeyStateTests, fakeKeyRepeat_validKey_returnsTrue) { + NiceMock keyMap; + MockEventQueue eventQueue; + KeyStateImpl keyState(eventQueue, keyMap); + s_stubKeyItem.m_client = 0; + s_stubKeystroke.m_type = synergy::KeyMap::Keystroke::kButton; + s_stubKeystroke.m_data.m_button.m_button = 2; - // set the button to 1 for fakeKeyDown call - s_stubKeyItem.m_button = 1; - ON_CALL(keyMap, mapKey(_, _, _, _, _, _, _, _)).WillByDefault(Invoke(stubMapKey)); - keyState.fakeKeyDown(1, 0, 0, "en"); + // set the button to 1 for fakeKeyDown call + s_stubKeyItem.m_button = 1; + ON_CALL(keyMap, mapKey(_, _, _, _, _, _, _, _)) + .WillByDefault(Invoke(stubMapKey)); + keyState.fakeKeyDown(1, 0, 0, "en"); - // change the button to 2 - s_stubKeyItem.m_button = 2; - ON_CALL(keyMap, mapKey(_, _, _, _, _, _, _, _)).WillByDefault(Invoke(stubMapKey)); + // change the button to 2 + s_stubKeyItem.m_button = 2; + ON_CALL(keyMap, mapKey(_, _, _, _, _, _, _, _)) + .WillByDefault(Invoke(stubMapKey)); - bool actual = keyState.fakeKeyRepeat(1, 0, 0, 0, "en"); + bool actual = keyState.fakeKeyRepeat(1, 0, 0, 0, "en"); - ASSERT_TRUE(actual); + ASSERT_TRUE(actual); } -TEST(KeyStateTests, fakeKeyUp_buttonNotDown_returnsFalse) -{ - MockKeyMap keyMap; - MockEventQueue eventQueue; - KeyStateImpl keyState(eventQueue, keyMap); +TEST(KeyStateTests, fakeKeyUp_buttonNotDown_returnsFalse) { + MockKeyMap keyMap; + MockEventQueue eventQueue; + KeyStateImpl keyState(eventQueue, keyMap); - bool actual = keyState.fakeKeyUp(0); + bool actual = keyState.fakeKeyUp(0); - ASSERT_FALSE(actual); + ASSERT_FALSE(actual); } -TEST(KeyStateTests, fakeKeyUp_buttonAlreadyDown_returnsTrue) -{ - NiceMock keyMap; - MockEventQueue eventQueue; - KeyStateImpl keyState(eventQueue, keyMap); +TEST(KeyStateTests, fakeKeyUp_buttonAlreadyDown_returnsTrue) { + NiceMock keyMap; + MockEventQueue eventQueue; + KeyStateImpl keyState(eventQueue, keyMap); - // press alt down so we get full coverage. - ON_CALL(keyState, pollActiveModifiers()).WillByDefault(Return(KeyModifierAlt)); - keyState.updateKeyState(); + // press alt down so we get full coverage. + ON_CALL(keyState, pollActiveModifiers()) + .WillByDefault(Return(KeyModifierAlt)); + keyState.updateKeyState(); - // press button 1 down. - s_stubKeyItem.m_button = 1; - ON_CALL(keyMap, mapKey(_, _, _, _, _, _, _, _)).WillByDefault(Invoke(stubMapKey)); - keyState.fakeKeyDown(1, 0, 1, "en"); + // press button 1 down. + s_stubKeyItem.m_button = 1; + ON_CALL(keyMap, mapKey(_, _, _, _, _, _, _, _)) + .WillByDefault(Invoke(stubMapKey)); + keyState.fakeKeyDown(1, 0, 1, "en"); - // this takes the button id, which is the 3rd arg of fakeKeyDown - bool actual = keyState.fakeKeyUp(1); + // this takes the button id, which is the 3rd arg of fakeKeyDown + bool actual = keyState.fakeKeyUp(1); - ASSERT_TRUE(actual); + ASSERT_TRUE(actual); } -TEST(KeyStateTests, fakeAllKeysUp_keysWereDown_keysAreUp) -{ - NiceMock keyMap; - MockEventQueue eventQueue; - KeyStateImpl keyState(eventQueue, keyMap); +TEST(KeyStateTests, fakeAllKeysUp_keysWereDown_keysAreUp) { + NiceMock keyMap; + MockEventQueue eventQueue; + KeyStateImpl keyState(eventQueue, keyMap); - // press button 1 down. - s_stubKeyItem.m_button = 1; - ON_CALL(keyMap, mapKey(_, _, _, _, _, _, _, _)).WillByDefault(Invoke(stubMapKey)); - keyState.fakeKeyDown(1, 0, 1, "en"); + // press button 1 down. + s_stubKeyItem.m_button = 1; + ON_CALL(keyMap, mapKey(_, _, _, _, _, _, _, _)) + .WillByDefault(Invoke(stubMapKey)); + keyState.fakeKeyDown(1, 0, 1, "en"); - // method under test - keyState.fakeAllKeysUp(); + // method under test + keyState.fakeAllKeysUp(); - bool actual = keyState.isKeyDown(1); - ASSERT_FALSE(actual); + bool actual = keyState.isKeyDown(1); + ASSERT_FALSE(actual); } -TEST(KeyStateTests, isKeyDown_keyDown_returnsTrue) -{ - NiceMock keyMap; - MockEventQueue eventQueue; - KeyStateImpl keyState(eventQueue, keyMap); +TEST(KeyStateTests, isKeyDown_keyDown_returnsTrue) { + NiceMock keyMap; + MockEventQueue eventQueue; + KeyStateImpl keyState(eventQueue, keyMap); - // press button 1 down. - s_stubKeyItem.m_button = 1; - ON_CALL(keyMap, mapKey(_, _, _, _, _, _, _, _)).WillByDefault(Invoke(stubMapKey)); - keyState.fakeKeyDown(1, 0, 1, "en"); + // press button 1 down. + s_stubKeyItem.m_button = 1; + ON_CALL(keyMap, mapKey(_, _, _, _, _, _, _, _)) + .WillByDefault(Invoke(stubMapKey)); + keyState.fakeKeyDown(1, 0, 1, "en"); - // method under test - bool actual = keyState.isKeyDown(1); + // method under test + bool actual = keyState.isKeyDown(1); - ASSERT_TRUE(actual); + ASSERT_TRUE(actual); } -TEST(KeyStateTests, isKeyDown_noKeysDown_returnsFalse) -{ - MockKeyMap keyMap; - MockEventQueue eventQueue; - KeyStateImpl keyState(eventQueue, keyMap); +TEST(KeyStateTests, isKeyDown_noKeysDown_returnsFalse) { + MockKeyMap keyMap; + MockEventQueue eventQueue; + KeyStateImpl keyState(eventQueue, keyMap); - // method under test - bool actual = keyState.isKeyDown(1); + // method under test + bool actual = keyState.isKeyDown(1); - ASSERT_FALSE(actual); + ASSERT_FALSE(actual); } -TEST(KeyStateTests, updateKeyMap_exercised) -{ - synergy::KeyMap keyMap; - synergy::KeyMap::KeyItem keyItem; - keyItem.m_button = 'A'; - keyItem.m_group = 1; - keyItem.m_id = 'A'; - keyMap.addKeyEntry(keyItem); - keyMap.finish(); - MockEventQueue eventQueue; - KeyStateImpl keyState(eventQueue, keyMap); +TEST(KeyStateTests, updateKeyMap_exercised) { + synergy::KeyMap keyMap; + synergy::KeyMap::KeyItem keyItem; + keyItem.m_button = 'A'; + keyItem.m_group = 1; + keyItem.m_id = 'A'; + keyMap.addKeyEntry(keyItem); + keyMap.finish(); + MockEventQueue eventQueue; + KeyStateImpl keyState(eventQueue, keyMap); - keyState.updateKeyMap(&keyMap); + keyState.updateKeyMap(&keyMap); } - -void -stubPollPressedKeys(IKeyState::KeyButtonSet& pressedKeys) -{ - pressedKeys.insert(1); +void stubPollPressedKeys(IKeyState::KeyButtonSet &pressedKeys) { + pressedKeys.insert(1); } -void -assertMaskIsOne(ForeachKeyCallback cb, void* userData) -{ - ASSERT_EQ(1, ((KeyState::AddActiveModifierContext*)userData)->m_mask); +void assertMaskIsOne(ForeachKeyCallback cb, void *userData) { + ASSERT_EQ(1, ((KeyState::AddActiveModifierContext *)userData)->m_mask); } -const synergy::KeyMap::KeyItem* -stubMapKey(synergy::KeyMap::Keystrokes& keys, KeyID, SInt32, - synergy::KeyMap::ModifierToKeys&, KeyModifierMask&, - KeyModifierMask, bool, const String&) -{ - keys.push_back(s_stubKeystroke); - return &s_stubKeyItem; +const synergy::KeyMap::KeyItem *stubMapKey(synergy::KeyMap::Keystrokes &keys, + KeyID, SInt32, + synergy::KeyMap::ModifierToKeys &, + KeyModifierMask &, KeyModifierMask, + bool, const String &) { + keys.push_back(s_stubKeystroke); + return &s_stubKeyItem; } diff --git a/src/test/unittests/synergy/ProtocolUtilTests.cpp b/src/test/unittests/synergy/ProtocolUtilTests.cpp index a1d34a3ec..cf60aab9a 100644 --- a/src/test/unittests/synergy/ProtocolUtilTests.cpp +++ b/src/test/unittests/synergy/ProtocolUtilTests.cpp @@ -15,605 +15,498 @@ * along with this program. If not, see . */ -#include +#include "synergy/ProtocolUtil.h" #include "test/global/gtest.h" #include "test/mock/io/MockStream.h" -#include "synergy/ProtocolUtil.h" +#include using ::testing::_; -using ::testing::Return; using ::testing::DoAll; -using ::testing::SetArgPointee; -using ::testing::Pointee; +using ::testing::ElementsAreArray; using ::testing::Eq; +using ::testing::Pointee; +using ::testing::Return; +using ::testing::SetArgPointee; using ::testing::StrEq; using ::testing::TypedEq; -using ::testing::ElementsAreArray; -ACTION_P2(SetValueToVoidPointerArg0, value, size) -{ - memcpy(arg0, value, size); +ACTION_P2(SetValueToVoidPointerArg0, value, size) { memcpy(arg0, value, size); } + +MATCHER_P(EqVoidPointeeInt8, expected, "") { + const UInt8 Actual8 = (*static_cast(arg)); + return (expected == Actual8); } -MATCHER_P(EqVoidPointeeInt8, expected, "") -{ - const UInt8 Actual8 = (*static_cast(arg)); - return (expected == Actual8); +MATCHER_P(EqVoidPointeeInt16, expected, "") { + const UInt16 Actual16 = (*static_cast(arg)); + return (expected == (Actual16 >> 8)); } -MATCHER_P(EqVoidPointeeInt16, expected, "") -{ - const UInt16 Actual16 = (*static_cast(arg)); - return (expected == (Actual16 >> 8)); +MATCHER_P(EqVoidPointeeInt32, expected, "") { + const UInt32 Actual32 = (*static_cast(arg)); + return (expected == (Actual32 >> 24)); } -MATCHER_P(EqVoidPointeeInt32, expected, "") -{ - const UInt32 Actual32 = (*static_cast(arg)); - return (expected == (Actual32 >> 24)); -} +MATCHER_P(EqVoidVectorInt1byte, expected, "") { + bool Result = true; + const UInt8 *Actual = (static_cast(arg)) + 4; + const size_t Size = *(Actual - 1); -MATCHER_P(EqVoidVectorInt1byte, expected, "") -{ - bool Result = true; - const UInt8* Actual = (static_cast(arg)) + 4; - const size_t Size = *(Actual - 1); - - if (Size == expected.size()){ - for(size_t i = 0; i < expected.size(); ++i){ - if (expected[i] != Actual[i]){ - Result = false; - break; - } - } - } - else{ + if (Size == expected.size()) { + for (size_t i = 0; i < expected.size(); ++i) { + if (expected[i] != Actual[i]) { Result = false; + break; + } } + } else { + Result = false; + } - return Result; + return Result; } -MATCHER_P(EqVoidVectorInt2bytes, expected, "") -{ - bool Result = true; - const UInt16* Actual = (static_cast(arg)) + 2; - const size_t Size = *(Actual - 1) >> 8; +MATCHER_P(EqVoidVectorInt2bytes, expected, "") { + bool Result = true; + const UInt16 *Actual = (static_cast(arg)) + 2; + const size_t Size = *(Actual - 1) >> 8; - if (Size == expected.size()){ - for(size_t i = 0; i < expected.size(); ++i){ - if (expected[i] != (Actual[i] >> 8) ){ - Result = false; - break; - } - } - } - else{ + if (Size == expected.size()) { + for (size_t i = 0; i < expected.size(); ++i) { + if (expected[i] != (Actual[i] >> 8)) { Result = false; + break; + } } + } else { + Result = false; + } - return Result; + return Result; } -MATCHER_P(EqVoidVectorInt4bytes, expected, "") -{ - bool Result = true; - const UInt32* Actual = (static_cast(arg)) + 1; - const size_t Size = *(Actual - 1) >> 24; +MATCHER_P(EqVoidVectorInt4bytes, expected, "") { + bool Result = true; + const UInt32 *Actual = (static_cast(arg)) + 1; + const size_t Size = *(Actual - 1) >> 24; - if (Size == expected.size()){ - for(size_t i = 0; i < expected.size(); ++i){ - if (expected[i] != (Actual[i] >> 24) ){ - Result = false; - break; - } - } - } - else{ + if (Size == expected.size()) { + for (size_t i = 0; i < expected.size(); ++i) { + if (expected[i] != (Actual[i] >> 24)) { Result = false; + break; + } } + } else { + Result = false; + } - return Result; + return Result; } -MATCHER_P(EqVectorSymbols, expected, "") -{ - bool Result = true; - const UInt8* Actual = (static_cast(arg)); +MATCHER_P(EqVectorSymbols, expected, "") { + bool Result = true; + const UInt8 *Actual = (static_cast(arg)); - for(size_t i = 0; i < expected.size(); ++i){ - if (expected[i] != (Actual[i]) ){ - Result = false; - break; - } + for (size_t i = 0; i < expected.size(); ++i) { + if (expected[i] != (Actual[i])) { + Result = false; + break; } + } - return Result; + return Result; } -ACTION(ThrowBadAlloc) -{ - throw std::bad_alloc(); -} +ACTION(ThrowBadAlloc) { throw std::bad_alloc(); } -class ProtocolUtilTests : public ::testing::Test -{ +class ProtocolUtilTests : public ::testing::Test { public: - MockStream stream; - UInt8 ActualInt8 = 0; - UInt16 ActualInt16 = 0; - UInt32 ActualInt32 = 0; - std::string ActualString; + MockStream stream; + UInt8 ActualInt8 = 0; + UInt16 ActualInt16 = 0; + UInt32 ActualInt32 = 0; + std::string ActualString; }; -TEST_F(ProtocolUtilTests, readf__XIOEndOfStream_exception) -{ - ON_CALL(stream, read(_, _)).WillByDefault(Return(0)); +TEST_F(ProtocolUtilTests, readf__XIOEndOfStream_exception) { + ON_CALL(stream, read(_, _)).WillByDefault(Return(0)); - EXPECT_FALSE(ProtocolUtil::readf(&stream, "%s", &ActualString)); - EXPECT_TRUE(ActualString.empty()); + EXPECT_FALSE(ProtocolUtil::readf(&stream, "%s", &ActualString)); + EXPECT_TRUE(ActualString.empty()); } -TEST_F(ProtocolUtilTests, readf_XIOReadMismatch_exception) -{ - EXPECT_CALL(stream, read(_, _)) - .WillOnce(DoAll(SetValueToVoidPointerArg0("b", 1), Return(1))); +TEST_F(ProtocolUtilTests, readf_XIOReadMismatch_exception) { + EXPECT_CALL(stream, read(_, _)) + .WillOnce(DoAll(SetValueToVoidPointerArg0("b", 1), Return(1))); - EXPECT_FALSE(ProtocolUtil::readf(&stream, "a%s", &ActualString)); - EXPECT_TRUE(ActualString.empty()); + EXPECT_FALSE(ProtocolUtil::readf(&stream, "a%s", &ActualString)); + EXPECT_TRUE(ActualString.empty()); } -TEST_F(ProtocolUtilTests, readf_bad_alloc_exception) -{ - ON_CALL(stream, read(_, _)).WillByDefault(ThrowBadAlloc()); +TEST_F(ProtocolUtilTests, readf_bad_alloc_exception) { + ON_CALL(stream, read(_, _)).WillByDefault(ThrowBadAlloc()); - EXPECT_FALSE(ProtocolUtil::readf(&stream, "a%s", &ActualString)); - EXPECT_TRUE(ActualString.empty()); + EXPECT_FALSE(ProtocolUtil::readf(&stream, "a%s", &ActualString)); + EXPECT_TRUE(ActualString.empty()); } -TEST_F(ProtocolUtilTests, readf_asserts) -{ - ASSERT_DEBUG_DEATH( - {ProtocolUtil::readf(&stream, "%x", &ActualString);}, - "invalid format specifier" - ); +TEST_F(ProtocolUtilTests, readf_asserts) { + ASSERT_DEBUG_DEATH( + { ProtocolUtil::readf(&stream, "%x", &ActualString); }, + "invalid format specifier"); - ASSERT_DEBUG_DEATH( - {ProtocolUtil::readf(&stream, "%5i", &ActualString);}, - "length to be read is wrong:" - ); + ASSERT_DEBUG_DEATH( + { ProtocolUtil::readf(&stream, "%5i", &ActualString); }, + "length to be read is wrong:"); - ASSERT_DEBUG_DEATH( - {ProtocolUtil::readf(&stream, "%5I", &ActualString);}, - "" - ); + ASSERT_DEBUG_DEATH( + { ProtocolUtil::readf(&stream, "%5I", &ActualString); }, ""); } -TEST_F(ProtocolUtilTests, readf_params_validation) -{ - EXPECT_FALSE(ProtocolUtil::readf(NULL, "%x", NULL)); - EXPECT_FALSE(ProtocolUtil::readf(&stream, NULL, NULL)); +TEST_F(ProtocolUtilTests, readf_params_validation) { + EXPECT_FALSE(ProtocolUtil::readf(NULL, "%x", NULL)); + EXPECT_FALSE(ProtocolUtil::readf(&stream, NULL, NULL)); } +TEST_F(ProtocolUtilTests, readf_string) { + const UInt8 Length = 200; + const std::string Expected(Length, 'x'); + std::array StringSize{{0, 0, 0, Length}}; -TEST_F(ProtocolUtilTests, readf_string) -{ - const UInt8 Length = 200; - const std::string Expected(Length, 'x'); - std::array StringSize{{0,0,0,Length}}; + EXPECT_CALL(stream, read(_, _)) + .WillOnce( + DoAll(SetValueToVoidPointerArg0(StringSize.data(), StringSize.size()), + Return(StringSize.size()))) + .WillOnce( + DoAll(SetValueToVoidPointerArg0(Expected.c_str(), Expected.length()), + Return(Expected.length()))); - EXPECT_CALL(stream, read(_, _)) - .WillOnce( - DoAll( - SetValueToVoidPointerArg0(StringSize.data(), StringSize.size()), - Return(StringSize.size()) - ) - ) - .WillOnce( - DoAll( - SetValueToVoidPointerArg0(Expected.c_str(), Expected.length()), - Return(Expected.length()) - ) - ); - - EXPECT_TRUE(ProtocolUtil::readf(&stream, "%s", &ActualString)); - EXPECT_EQ(Expected, ActualString); + EXPECT_TRUE(ProtocolUtil::readf(&stream, "%s", &ActualString)); + EXPECT_EQ(Expected, ActualString); } -class ReadfIntTestFixture : public ::testing::TestWithParam< std::tuple > -{ +class ReadfIntTestFixture + : public ::testing::TestWithParam> { public: - MockStream stream; - UInt8 StreamData1Byte = 10; - std::array StreamData2Bytes{{0, 10}}; - std::array StreamData4Bytes{{0, 0, 0, 10}}; + MockStream stream; + UInt8 StreamData1Byte = 10; + std::array StreamData2Bytes{{0, 10}}; + std::array StreamData4Bytes{{0, 0, 0, 10}}; - UInt8* getStreamData(int size) - { - UInt8* StreamData = nullptr; - switch(size){ - case 2: - StreamData = StreamData2Bytes.data(); - break; - case 4: - StreamData = StreamData4Bytes.data(); - break; - default: - StreamData = &StreamData1Byte; - break; - } - return StreamData; + UInt8 *getStreamData(int size) { + UInt8 *StreamData = nullptr; + switch (size) { + case 2: + StreamData = StreamData2Bytes.data(); + break; + case 4: + StreamData = StreamData4Bytes.data(); + break; + default: + StreamData = &StreamData1Byte; + break; } + return StreamData; + } }; -TEST_P(ReadfIntTestFixture, readf_int) -{ - int Actual = 0; - const int Expected = 10; - const char* Format = std::get<0>(GetParam()); - int StreamDataSize = std::get<1>(GetParam()); - UInt8* StreamData = getStreamData(StreamDataSize); +TEST_P(ReadfIntTestFixture, readf_int) { + int Actual = 0; + const int Expected = 10; + const char *Format = std::get<0>(GetParam()); + int StreamDataSize = std::get<1>(GetParam()); + UInt8 *StreamData = getStreamData(StreamDataSize); - ON_CALL(stream, read(_, _)) - .WillByDefault( - DoAll( - SetValueToVoidPointerArg0(StreamData, StreamDataSize), - Return(StreamDataSize) - ) - ); + ON_CALL(stream, read(_, _)) + .WillByDefault( + DoAll(SetValueToVoidPointerArg0(StreamData, StreamDataSize), + Return(StreamDataSize))); - EXPECT_TRUE(ProtocolUtil::readf(&stream, Format, &Actual)); - EXPECT_EQ(Expected, Actual); + EXPECT_TRUE(ProtocolUtil::readf(&stream, Format, &Actual)); + EXPECT_EQ(Expected, Actual); } -INSTANTIATE_TEST_SUITE_P( - ReadfIntTests, - ReadfIntTestFixture, - ::testing::Values( - std::make_tuple("%1i", 1), - std::make_tuple("%2i", 2), - std::make_tuple("%4i", 4))); +INSTANTIATE_TEST_SUITE_P(ReadfIntTests, ReadfIntTestFixture, + ::testing::Values(std::make_tuple("%1i", 1), + std::make_tuple("%2i", 2), + std::make_tuple("%4i", 4))); -class ReadfIntVectorTestFixture : public ReadfIntTestFixture -{ -}; +class ReadfIntVectorTestFixture : public ReadfIntTestFixture {}; -TEST_P(ReadfIntVectorTestFixture, readf_int_vector) -{ - std::vector Actual1Byte = {}; - std::vector Actual2Bytes = {}; - std::vector Actual4Bytes = {}; +TEST_P(ReadfIntVectorTestFixture, readf_int_vector) { + std::vector Actual1Byte = {}; + std::vector Actual2Bytes = {}; + std::vector Actual4Bytes = {}; - const std::vector Expected1Byte = {10,10}; - const std::vector Expected2Bytes = {10,10}; - const std::vector Expected4Bytes = {10,10}; - std::array StreamVectorSize{{0,0,0,2}}; + const std::vector Expected1Byte = {10, 10}; + const std::vector Expected2Bytes = {10, 10}; + const std::vector Expected4Bytes = {10, 10}; + std::array StreamVectorSize{{0, 0, 0, 2}}; - const char* Format = std::get<0>(GetParam()); - int StreamDataSize = std::get<1>(GetParam()); - UInt8* StreamData = getStreamData(StreamDataSize); + const char *Format = std::get<0>(GetParam()); + int StreamDataSize = std::get<1>(GetParam()); + UInt8 *StreamData = getStreamData(StreamDataSize); - MockStream stream; - EXPECT_CALL(stream, read(_, _)) - .WillOnce( - DoAll( - SetValueToVoidPointerArg0(StreamVectorSize.data(), StreamVectorSize.size()), - Return(StreamVectorSize.size()) - ) - ) - .WillRepeatedly( - DoAll( - SetValueToVoidPointerArg0(StreamData, StreamDataSize), - Return(StreamDataSize) - )); + MockStream stream; + EXPECT_CALL(stream, read(_, _)) + .WillOnce(DoAll(SetValueToVoidPointerArg0(StreamVectorSize.data(), + StreamVectorSize.size()), + Return(StreamVectorSize.size()))) + .WillRepeatedly( + DoAll(SetValueToVoidPointerArg0(StreamData, StreamDataSize), + Return(StreamDataSize))); - switch(StreamDataSize){ - case 2: - EXPECT_TRUE(ProtocolUtil::readf(&stream, Format, &Actual2Bytes)); - EXPECT_EQ(Expected2Bytes, Actual2Bytes); - break; - case 4: - EXPECT_TRUE(ProtocolUtil::readf(&stream, Format, &Actual4Bytes)); - EXPECT_EQ(Expected4Bytes, Actual4Bytes); - break; - default: - EXPECT_TRUE(ProtocolUtil::readf(&stream, Format, &Actual1Byte)); - EXPECT_EQ(Expected1Byte, Actual1Byte); - break; - } -} - -INSTANTIATE_TEST_SUITE_P( - ReadfIntVectorTests, - ReadfIntVectorTestFixture, - ::testing::Values( - std::make_tuple("%1I", 1), - std::make_tuple("%2I", 2), - std::make_tuple("%4I", 4))); - -class ReadfIntAndStringTest : public ReadfIntTestFixture -{ -public: - UInt8 ActualInt8 = 0; - UInt16 ActualInt16 = 0; - UInt32 ActualInt32 = 32; - std::string ActualString; -}; - -TEST_P(ReadfIntAndStringTest, readf_int_and_string) -{ - const int ExpectedInt = 10; - const UInt8 StringLength = 200; - const std::string ExpectedString(StringLength, 'x'); - std::array StringSize{{0,0,0,StringLength}}; - - const char* Format = std::get<0>(GetParam()); - int StreamDataSize = std::get<1>(GetParam()); - UInt8* StreamData = getStreamData(StreamDataSize); - - EXPECT_CALL(stream, read(_, _)) - .WillOnce( - DoAll( - SetValueToVoidPointerArg0(StreamData, StreamDataSize), - Return(StreamDataSize) - ) - ) - .WillOnce( - DoAll( - SetValueToVoidPointerArg0(StringSize.data(), StringSize.size()), - Return(StringSize.size()) - ) - ) - .WillOnce( - DoAll( - SetValueToVoidPointerArg0(ExpectedString.c_str(), ExpectedString.length()), - Return(ExpectedString.length()) - ) - ); - - switch(StreamDataSize){ - case 2: - EXPECT_TRUE(ProtocolUtil::readf(&stream, Format, &ActualInt16, &ActualString)); - EXPECT_EQ(ExpectedInt, ActualInt16); - break; - case 4: - EXPECT_TRUE(ProtocolUtil::readf(&stream, Format, &ActualInt32, &ActualString)); - EXPECT_EQ(ExpectedInt, ActualInt32); - break; - default: - EXPECT_TRUE(ProtocolUtil::readf(&stream, Format, &ActualInt8, &ActualString)); - EXPECT_EQ(ExpectedInt, ActualInt8); - break; - } - EXPECT_EQ(ExpectedString, ActualString); -} - -INSTANTIATE_TEST_SUITE_P( - IntAndStringTest, - ReadfIntAndStringTest, - ::testing::Values( - std::make_tuple("%1i%s", 1), - std::make_tuple("%2i%s", 2), - std::make_tuple("%4i%s", 4))); - - -TEST_F(ProtocolUtilTests, readf_string_and_int4bytes) -{ - const UInt8 ExpectedInt = 10; - std::array StreamIntData{{0,0,0,ExpectedInt}}; - - const std::string ExpectedStr(32768, 'x'); - std::array Size{{0,0,128,0}}; - - EXPECT_CALL(stream, read(_, _)) - .WillOnce( - DoAll( - SetValueToVoidPointerArg0(Size.data(), Size.size()), - Return(Size.size()) - ) - ) - .WillOnce( - DoAll( - SetValueToVoidPointerArg0(ExpectedStr.c_str(), ExpectedStr.length()), - Return(ExpectedStr.length()) - ) - ) - .WillOnce( - DoAll( - SetValueToVoidPointerArg0(StreamIntData.data(), StreamIntData.size()), - Return(StreamIntData.size()) - ) - ); - - EXPECT_TRUE(ProtocolUtil::readf(&stream, "%s%4i", &ActualString, &ActualInt32)); - EXPECT_EQ(ExpectedStr, ActualString); - EXPECT_EQ(ExpectedInt, ActualInt32); -} - -TEST_F(ProtocolUtilTests, readf_string_and_vector_int4bytes) -{ - std::vector Actual = {}; - const std::vector Expected4Bytes = {10,10}; - std::array StreamVectorSize{{0,0,0,2}}; - std::array StreamData4Bytes{{0, 0, 0, 10}}; - - const std::string ExpString(32768, 'x'); - std::array SizeString{{0,0,128,0}}; - - EXPECT_CALL(stream, read(_, _)) - .WillOnce( - DoAll( - SetValueToVoidPointerArg0(SizeString.data(), SizeString.size()), - Return(SizeString.size()) - ) - ) - .WillOnce( - DoAll( - SetValueToVoidPointerArg0(ExpString.c_str(), ExpString.length()), - Return(ExpString.length()) - ) - ) - .WillOnce( - DoAll( - SetValueToVoidPointerArg0(StreamVectorSize.data(), StreamVectorSize.size()), - Return(StreamVectorSize.size()) - ) - ) - .WillRepeatedly( - DoAll( - SetValueToVoidPointerArg0(StreamData4Bytes.data(), StreamData4Bytes.size()), - Return(StreamData4Bytes.size()) - ) - ); - - EXPECT_TRUE(ProtocolUtil::readf(&stream, "%s%4I", &ActualString, &Actual)); - EXPECT_EQ(ExpString, ActualString); - EXPECT_EQ(Expected4Bytes, Actual); -} - -TEST_F(ProtocolUtilTests, readf_vector_int4bytes_and_string) -{ - std::vector Actual4Bytes = {}; - const std::vector Expected4Bytes = {10,10}; - std::array StreamVectorSize{{0,0,0,2}}; - std::array StreamData4Bytes{{0, 0, 0, 10}}; - - const std::string ExpectedString(32768, 'x'); - std::array StringSize{{0,0,128,0}}; - - EXPECT_CALL(stream, read(_, _)) - .WillOnce( - DoAll( - SetValueToVoidPointerArg0(StreamVectorSize.data(), StreamVectorSize.size()), - Return(StreamVectorSize.size()) - ) - ) - .WillOnce( - DoAll( - SetValueToVoidPointerArg0(StreamData4Bytes.data(), StreamData4Bytes.size()), - Return(StreamData4Bytes.size()) - ) - ) - .WillOnce( - DoAll( - SetValueToVoidPointerArg0(StreamData4Bytes.data(), StreamData4Bytes.size()), - Return(StreamData4Bytes.size()) - ) - ) - .WillOnce( - DoAll( - SetValueToVoidPointerArg0(StringSize.data(), StringSize.size()), - Return(StringSize.size()) - ) - ) - .WillOnce( - DoAll( - SetValueToVoidPointerArg0(ExpectedString.c_str(), ExpectedString.length()), - Return(ExpectedString.length()) - ) - ); - - EXPECT_TRUE(ProtocolUtil::readf(&stream, "%4I%s", &Actual4Bytes, &ActualString)); - EXPECT_EQ(ExpectedString, ActualString); + switch (StreamDataSize) { + case 2: + EXPECT_TRUE(ProtocolUtil::readf(&stream, Format, &Actual2Bytes)); + EXPECT_EQ(Expected2Bytes, Actual2Bytes); + break; + case 4: + EXPECT_TRUE(ProtocolUtil::readf(&stream, Format, &Actual4Bytes)); EXPECT_EQ(Expected4Bytes, Actual4Bytes); + break; + default: + EXPECT_TRUE(ProtocolUtil::readf(&stream, Format, &Actual1Byte)); + EXPECT_EQ(Expected1Byte, Actual1Byte); + break; + } } -class WriteIntTest : public ::testing::TestWithParam< std::tuple > -{ +INSTANTIATE_TEST_SUITE_P(ReadfIntVectorTests, ReadfIntVectorTestFixture, + ::testing::Values(std::make_tuple("%1I", 1), + std::make_tuple("%2I", 2), + std::make_tuple("%4I", 4))); + +class ReadfIntAndStringTest : public ReadfIntTestFixture { public: - MockStream stream; - UInt8 Expected1Byte = 5; - UInt16 Expected2Bytes = 10; - UInt32 Expected4Bytes = 15; + UInt8 ActualInt8 = 0; + UInt16 ActualInt16 = 0; + UInt32 ActualInt32 = 32; + std::string ActualString; }; -TEST_P(WriteIntTest, write_int) -{ - const char* Format = std::get<0>(GetParam()); - const int DataSize = std::get<1>(GetParam()); - switch(DataSize) - { - case 2: - EXPECT_CALL(stream, write(EqVoidPointeeInt16(Expected2Bytes), Eq(DataSize))); - ProtocolUtil::writef(&stream, Format, Expected2Bytes); - break; - case 4: - EXPECT_CALL(stream, write(EqVoidPointeeInt32(Expected4Bytes), Eq(DataSize))); - ProtocolUtil::writef(&stream, Format, Expected4Bytes); - break; - default: - EXPECT_CALL(stream, write(EqVoidPointeeInt8(Expected1Byte), Eq(DataSize))); - ProtocolUtil::writef(&stream, Format, Expected1Byte); - break; - } +TEST_P(ReadfIntAndStringTest, readf_int_and_string) { + const int ExpectedInt = 10; + const UInt8 StringLength = 200; + const std::string ExpectedString(StringLength, 'x'); + std::array StringSize{{0, 0, 0, StringLength}}; + + const char *Format = std::get<0>(GetParam()); + int StreamDataSize = std::get<1>(GetParam()); + UInt8 *StreamData = getStreamData(StreamDataSize); + + EXPECT_CALL(stream, read(_, _)) + .WillOnce(DoAll(SetValueToVoidPointerArg0(StreamData, StreamDataSize), + Return(StreamDataSize))) + .WillOnce( + DoAll(SetValueToVoidPointerArg0(StringSize.data(), StringSize.size()), + Return(StringSize.size()))) + .WillOnce(DoAll(SetValueToVoidPointerArg0(ExpectedString.c_str(), + ExpectedString.length()), + Return(ExpectedString.length()))); + + switch (StreamDataSize) { + case 2: + EXPECT_TRUE( + ProtocolUtil::readf(&stream, Format, &ActualInt16, &ActualString)); + EXPECT_EQ(ExpectedInt, ActualInt16); + break; + case 4: + EXPECT_TRUE( + ProtocolUtil::readf(&stream, Format, &ActualInt32, &ActualString)); + EXPECT_EQ(ExpectedInt, ActualInt32); + break; + default: + EXPECT_TRUE( + ProtocolUtil::readf(&stream, Format, &ActualInt8, &ActualString)); + EXPECT_EQ(ExpectedInt, ActualInt8); + break; + } + EXPECT_EQ(ExpectedString, ActualString); } -INSTANTIATE_TEST_SUITE_P( - WriteIntTest, - WriteIntTest, - ::testing::Values( - std::make_tuple("%1i", 1), - std::make_tuple("%2i", 2), - std::make_tuple("%4i", 4))); +INSTANTIATE_TEST_SUITE_P(IntAndStringTest, ReadfIntAndStringTest, + ::testing::Values(std::make_tuple("%1i%s", 1), + std::make_tuple("%2i%s", 2), + std::make_tuple("%4i%s", 4))); -class WriteIntVectorTest : public ::testing::TestWithParam< std::tuple > -{ +TEST_F(ProtocolUtilTests, readf_string_and_int4bytes) { + const UInt8 ExpectedInt = 10; + std::array StreamIntData{{0, 0, 0, ExpectedInt}}; + + const std::string ExpectedStr(32768, 'x'); + std::array Size{{0, 0, 128, 0}}; + + EXPECT_CALL(stream, read(_, _)) + .WillOnce(DoAll(SetValueToVoidPointerArg0(Size.data(), Size.size()), + Return(Size.size()))) + .WillOnce(DoAll( + SetValueToVoidPointerArg0(ExpectedStr.c_str(), ExpectedStr.length()), + Return(ExpectedStr.length()))) + .WillOnce(DoAll( + SetValueToVoidPointerArg0(StreamIntData.data(), StreamIntData.size()), + Return(StreamIntData.size()))); + + EXPECT_TRUE( + ProtocolUtil::readf(&stream, "%s%4i", &ActualString, &ActualInt32)); + EXPECT_EQ(ExpectedStr, ActualString); + EXPECT_EQ(ExpectedInt, ActualInt32); +} + +TEST_F(ProtocolUtilTests, readf_string_and_vector_int4bytes) { + std::vector Actual = {}; + const std::vector Expected4Bytes = {10, 10}; + std::array StreamVectorSize{{0, 0, 0, 2}}; + std::array StreamData4Bytes{{0, 0, 0, 10}}; + + const std::string ExpString(32768, 'x'); + std::array SizeString{{0, 0, 128, 0}}; + + EXPECT_CALL(stream, read(_, _)) + .WillOnce( + DoAll(SetValueToVoidPointerArg0(SizeString.data(), SizeString.size()), + Return(SizeString.size()))) + .WillOnce(DoAll( + SetValueToVoidPointerArg0(ExpString.c_str(), ExpString.length()), + Return(ExpString.length()))) + .WillOnce(DoAll(SetValueToVoidPointerArg0(StreamVectorSize.data(), + StreamVectorSize.size()), + Return(StreamVectorSize.size()))) + .WillRepeatedly(DoAll(SetValueToVoidPointerArg0(StreamData4Bytes.data(), + StreamData4Bytes.size()), + Return(StreamData4Bytes.size()))); + + EXPECT_TRUE(ProtocolUtil::readf(&stream, "%s%4I", &ActualString, &Actual)); + EXPECT_EQ(ExpString, ActualString); + EXPECT_EQ(Expected4Bytes, Actual); +} + +TEST_F(ProtocolUtilTests, readf_vector_int4bytes_and_string) { + std::vector Actual4Bytes = {}; + const std::vector Expected4Bytes = {10, 10}; + std::array StreamVectorSize{{0, 0, 0, 2}}; + std::array StreamData4Bytes{{0, 0, 0, 10}}; + + const std::string ExpectedString(32768, 'x'); + std::array StringSize{{0, 0, 128, 0}}; + + EXPECT_CALL(stream, read(_, _)) + .WillOnce(DoAll(SetValueToVoidPointerArg0(StreamVectorSize.data(), + StreamVectorSize.size()), + Return(StreamVectorSize.size()))) + .WillOnce(DoAll(SetValueToVoidPointerArg0(StreamData4Bytes.data(), + StreamData4Bytes.size()), + Return(StreamData4Bytes.size()))) + .WillOnce(DoAll(SetValueToVoidPointerArg0(StreamData4Bytes.data(), + StreamData4Bytes.size()), + Return(StreamData4Bytes.size()))) + .WillOnce( + DoAll(SetValueToVoidPointerArg0(StringSize.data(), StringSize.size()), + Return(StringSize.size()))) + .WillOnce(DoAll(SetValueToVoidPointerArg0(ExpectedString.c_str(), + ExpectedString.length()), + Return(ExpectedString.length()))); + + EXPECT_TRUE( + ProtocolUtil::readf(&stream, "%4I%s", &Actual4Bytes, &ActualString)); + EXPECT_EQ(ExpectedString, ActualString); + EXPECT_EQ(Expected4Bytes, Actual4Bytes); +} + +class WriteIntTest + : public ::testing::TestWithParam> { public: - MockStream stream; - const std::vector Expected1Byte = {10, 20, 30}; - const std::vector Expected2Byte = {40, 50, 60}; - const std::vector Expected4Byte = {70, 80, 90}; + MockStream stream; + UInt8 Expected1Byte = 5; + UInt16 Expected2Bytes = 10; + UInt32 Expected4Bytes = 15; }; -TEST_P(WriteIntVectorTest, write_vector_int) -{ - const char* Format = std::get<0>(GetParam()); - const int Type = std::get<1>(GetParam()); - - switch(Type){ - case 2: - EXPECT_CALL(stream, write(EqVoidVectorInt2bytes(Expected2Byte), Eq(Type * Expected2Byte.size() + sizeof(UInt32)))); - ProtocolUtil::writef(&stream, Format, &Expected2Byte); - break; - case 4: - EXPECT_CALL(stream, write(EqVoidVectorInt4bytes(Expected4Byte), Eq(Type * Expected4Byte.size() + sizeof(UInt32)))); - ProtocolUtil::writef(&stream, Format, &Expected4Byte); - break; - default: - EXPECT_CALL(stream, write(EqVoidVectorInt1byte(Expected1Byte), Eq(Expected1Byte.size() + sizeof(UInt32)))); - ProtocolUtil::writef(&stream, Format, &Expected1Byte); - break; - } +TEST_P(WriteIntTest, write_int) { + const char *Format = std::get<0>(GetParam()); + const int DataSize = std::get<1>(GetParam()); + switch (DataSize) { + case 2: + EXPECT_CALL(stream, + write(EqVoidPointeeInt16(Expected2Bytes), Eq(DataSize))); + ProtocolUtil::writef(&stream, Format, Expected2Bytes); + break; + case 4: + EXPECT_CALL(stream, + write(EqVoidPointeeInt32(Expected4Bytes), Eq(DataSize))); + ProtocolUtil::writef(&stream, Format, Expected4Bytes); + break; + default: + EXPECT_CALL(stream, write(EqVoidPointeeInt8(Expected1Byte), Eq(DataSize))); + ProtocolUtil::writef(&stream, Format, Expected1Byte); + break; + } } -INSTANTIATE_TEST_SUITE_P( - WriteIntVectorTest, - WriteIntVectorTest, - ::testing::Values( - std::make_tuple("%1I", 1), - std::make_tuple("%2I", 2), - std::make_tuple("%4I", 4))); +INSTANTIATE_TEST_SUITE_P(WriteIntTest, WriteIntTest, + ::testing::Values(std::make_tuple("%1i", 1), + std::make_tuple("%2i", 2), + std::make_tuple("%4i", 4))); -TEST_F(ProtocolUtilTests, write_string_test) -{ - const String Expected = "Expected"; - const std::vector ExpectedVector = {'E', 'x', 'p', 'e', 'c', 't', 'e', 'd'}; - EXPECT_CALL(stream, write(EqVoidVectorInt1byte(ExpectedVector), Expected.size() + sizeof (UInt32))); - ProtocolUtil::writef(&stream, "%s", &Expected); +class WriteIntVectorTest + : public ::testing::TestWithParam> { +public: + MockStream stream; + const std::vector Expected1Byte = {10, 20, 30}; + const std::vector Expected2Byte = {40, 50, 60}; + const std::vector Expected4Byte = {70, 80, 90}; +}; + +TEST_P(WriteIntVectorTest, write_vector_int) { + const char *Format = std::get<0>(GetParam()); + const int Type = std::get<1>(GetParam()); + + switch (Type) { + case 2: + EXPECT_CALL(stream, + write(EqVoidVectorInt2bytes(Expected2Byte), + Eq(Type * Expected2Byte.size() + sizeof(UInt32)))); + ProtocolUtil::writef(&stream, Format, &Expected2Byte); + break; + case 4: + EXPECT_CALL(stream, + write(EqVoidVectorInt4bytes(Expected4Byte), + Eq(Type * Expected4Byte.size() + sizeof(UInt32)))); + ProtocolUtil::writef(&stream, Format, &Expected4Byte); + break; + default: + EXPECT_CALL(stream, write(EqVoidVectorInt1byte(Expected1Byte), + Eq(Expected1Byte.size() + sizeof(UInt32)))); + ProtocolUtil::writef(&stream, Format, &Expected1Byte); + break; + } } -TEST_F(ProtocolUtilTests, write_raw_bytes_test) -{ - const UInt32 Size = 5; - const std::array Expected{{10, 20, 30, 40, 50}}; - EXPECT_CALL(stream, write(EqVoidVectorInt1byte(Expected), Expected.size() + sizeof (UInt32))); - ProtocolUtil::writef(&stream, "%S", Size, &Expected); +INSTANTIATE_TEST_SUITE_P(WriteIntVectorTest, WriteIntVectorTest, + ::testing::Values(std::make_tuple("%1I", 1), + std::make_tuple("%2I", 2), + std::make_tuple("%4I", 4))); + +TEST_F(ProtocolUtilTests, write_string_test) { + const String Expected = "Expected"; + const std::vector ExpectedVector = {'E', 'x', 'p', 'e', + 'c', 't', 'e', 'd'}; + EXPECT_CALL(stream, write(EqVoidVectorInt1byte(ExpectedVector), + Expected.size() + sizeof(UInt32))); + ProtocolUtil::writef(&stream, "%s", &Expected); } -TEST_F(ProtocolUtilTests, write_symbols_from_format_test) -{ - const std::vector Expected = {'%', '1', '2', '3', '4', '5'}; - EXPECT_CALL(stream, write(EqVectorSymbols(Expected), Expected.size())); - ProtocolUtil::writef(&stream, "%%12345"); +TEST_F(ProtocolUtilTests, write_raw_bytes_test) { + const UInt32 Size = 5; + const std::array Expected{{10, 20, 30, 40, 50}}; + EXPECT_CALL(stream, write(EqVoidVectorInt1byte(Expected), + Expected.size() + sizeof(UInt32))); + ProtocolUtil::writef(&stream, "%S", Size, &Expected); } +TEST_F(ProtocolUtilTests, write_symbols_from_format_test) { + const std::vector Expected = {'%', '1', '2', '3', '4', '5'}; + EXPECT_CALL(stream, write(EqVectorSymbols(Expected), Expected.size())); + ProtocolUtil::writef(&stream, "%%12345"); +} diff --git a/src/test/unittests/synergy/ServerAppTests.cpp b/src/test/unittests/synergy/ServerAppTests.cpp index 2b4cb2a40..c1f32ff17 100644 --- a/src/test/unittests/synergy/ServerAppTests.cpp +++ b/src/test/unittests/synergy/ServerAppTests.cpp @@ -24,10 +24,9 @@ #include "test/global/gmock.h" -class MockServerApp : public ServerApp -{ +class MockServerApp : public ServerApp { public: - MockServerApp() : ServerApp(nullptr, nullptr) { } + MockServerApp() : ServerApp(nullptr, nullptr) {} }; #include "test/global/gtest.h" @@ -36,14 +35,14 @@ public: // using ::testing::Invoke; using ::testing::NiceMock; -TEST(ServerAppTests, runInner_will_handle_configuration_lifetime) -{ - NiceMock app; +TEST(ServerAppTests, runInner_will_handle_configuration_lifetime) { + NiceMock app; - EXPECT_FALSE(app.args().m_config); + EXPECT_FALSE(app.args().m_config); - const char *argv[] {"synergyc"}; - app.runInner(1, const_cast(argv), nullptr, [](int,char**){ return 0; }); + const char *argv[]{"synergyc"}; + app.runInner(1, const_cast(argv), nullptr, + [](int, char **) { return 0; }); - EXPECT_TRUE(app.args().m_config); + EXPECT_TRUE(app.args().m_config); } diff --git a/src/test/unittests/synergy/ServerArgsParsingTests.cpp b/src/test/unittests/synergy/ServerArgsParsingTests.cpp index 31ee63abd..a6121b3ca 100644 --- a/src/test/unittests/synergy/ServerArgsParsingTests.cpp +++ b/src/test/unittests/synergy/ServerArgsParsingTests.cpp @@ -27,76 +27,75 @@ using ::testing::_; using ::testing::Invoke; using ::testing::NiceMock; -bool -server_stubParseGenericArgs(int, const char* const*, int&) -{ - return false; +bool server_stubParseGenericArgs(int, const char *const *, int &) { + return false; } -bool -server_stubCheckUnexpectedArgs() -{ - return false; +bool server_stubCheckUnexpectedArgs() { return false; } + +TEST(ServerArgs, ServerArgs_will_construct_from_copy) { + lib::synergy::ServerArgs serverArgs; + serverArgs.m_display = "display0"; + lib::synergy::ServerArgs serverArgs2{serverArgs}; + EXPECT_EQ(serverArgs.m_display, serverArgs2.m_display); } -TEST(ServerArgs, ServerArgs_will_construct_from_copy) -{ - lib::synergy::ServerArgs serverArgs; - serverArgs.m_display = "display0"; - lib::synergy::ServerArgs serverArgs2 {serverArgs}; - EXPECT_EQ(serverArgs.m_display, serverArgs2.m_display); +TEST(ServerArgsParsingTests, parseServerArgs_addressArg_setSynergyAddress) { + NiceMock argParser; + ON_CALL(argParser, parseGenericArgs(_, _, _)) + .WillByDefault(Invoke(server_stubParseGenericArgs)); + ON_CALL(argParser, checkUnexpectedArgs()) + .WillByDefault(Invoke(server_stubCheckUnexpectedArgs)); + lib::synergy::ServerArgs serverArgs; + const int argc = 3; + const char *kAddressCmd[argc] = {"stub", "--address", "mock_address"}; + + argParser.parseServerArgs(serverArgs, argc, kAddressCmd); + + EXPECT_EQ("mock_address", serverArgs.m_synergyAddress); } -TEST(ServerArgsParsingTests, parseServerArgs_addressArg_setSynergyAddress) -{ - NiceMock argParser; - ON_CALL(argParser, parseGenericArgs(_, _, _)).WillByDefault(Invoke(server_stubParseGenericArgs)); - ON_CALL(argParser, checkUnexpectedArgs()).WillByDefault(Invoke(server_stubCheckUnexpectedArgs)); - lib::synergy::ServerArgs serverArgs; - const int argc = 3; - const char* kAddressCmd[argc] = { "stub", "--address", "mock_address" }; +TEST(ServerArgsParsingTests, parseServerArgs_configArg_setConfigFile) { + NiceMock argParser; + ON_CALL(argParser, parseGenericArgs(_, _, _)) + .WillByDefault(Invoke(server_stubParseGenericArgs)); + ON_CALL(argParser, checkUnexpectedArgs()) + .WillByDefault(Invoke(server_stubCheckUnexpectedArgs)); + lib::synergy::ServerArgs serverArgs; + const int argc = 3; + const char *kConfigCmd[argc] = {"stub", "--config", "mock_configFile"}; - argParser.parseServerArgs(serverArgs, argc, kAddressCmd); + argParser.parseServerArgs(serverArgs, argc, kConfigCmd); - EXPECT_EQ("mock_address", serverArgs.m_synergyAddress); + EXPECT_EQ("mock_configFile", serverArgs.m_configFile); } -TEST(ServerArgsParsingTests, parseServerArgs_configArg_setConfigFile) -{ - NiceMock argParser; - ON_CALL(argParser, parseGenericArgs(_, _, _)).WillByDefault(Invoke(server_stubParseGenericArgs)); - ON_CALL(argParser, checkUnexpectedArgs()).WillByDefault(Invoke(server_stubCheckUnexpectedArgs)); - lib::synergy::ServerArgs serverArgs; - const int argc = 3; - const char* kConfigCmd[argc] = { "stub", "--config", "mock_configFile" }; +TEST(ServerArgsParsingTests, parseServerArgs_checkSerialKeyParams) { + NiceMock argParser; + ON_CALL(argParser, parseGenericArgs(_, _, _)) + .WillByDefault(Invoke(server_stubParseGenericArgs)); + ON_CALL(argParser, checkUnexpectedArgs()) + .WillByDefault(Invoke(server_stubCheckUnexpectedArgs)); + lib::synergy::ServerArgs serverArgs; + const int argc = 3; + const char *serial = + "7B76323B737562736372697074696F6E3B62617369633B426F623B313B656D61696C3B63" + "6F6D70616E79206E616D653B303B38363430307D"; + std::array kSerialCmd = {"stub", "--serial-key", serial}; - argParser.parseServerArgs(serverArgs, argc, kConfigCmd); - - EXPECT_EQ("mock_configFile", serverArgs.m_configFile); + argParser.parseServerArgs(serverArgs, argc, kSerialCmd.data()); + EXPECT_EQ(serial, serverArgs.m_serial.toString()); } -TEST(ServerArgsParsingTests, parseServerArgs_checkSerialKeyParams) -{ - NiceMock argParser; - ON_CALL(argParser, parseGenericArgs(_, _, _)).WillByDefault(Invoke(server_stubParseGenericArgs)); - ON_CALL(argParser, checkUnexpectedArgs()).WillByDefault(Invoke(server_stubCheckUnexpectedArgs)); - lib::synergy::ServerArgs serverArgs; - const int argc = 3; - const char* serial = "7B76323B737562736372697074696F6E3B62617369633B426F623B313B656D61696C3B636F6D70616E79206E616D653B303B38363430307D"; - std::array kSerialCmd = { "stub", "--serial-key", serial }; +TEST(ServerArgsParsingTests, parseServerArgs_checkUnexpectedParams) { + NiceMock argParser; + ON_CALL(argParser, parseGenericArgs(_, _, _)) + .WillByDefault(Invoke(server_stubParseGenericArgs)); + ON_CALL(argParser, checkUnexpectedArgs()) + .WillByDefault(Invoke(server_stubCheckUnexpectedArgs)); + lib::synergy::ServerArgs serverArgs; + const int argc = 2; + std::array kUnknownCmd = {"stub", "--unknown"}; - argParser.parseServerArgs(serverArgs, argc, kSerialCmd.data()); - EXPECT_EQ(serial, serverArgs.m_serial.toString()); -} - -TEST(ServerArgsParsingTests, parseServerArgs_checkUnexpectedParams) -{ - NiceMock argParser; - ON_CALL(argParser, parseGenericArgs(_, _, _)).WillByDefault(Invoke(server_stubParseGenericArgs)); - ON_CALL(argParser, checkUnexpectedArgs()).WillByDefault(Invoke(server_stubCheckUnexpectedArgs)); - lib::synergy::ServerArgs serverArgs; - const int argc = 2; - std::array kUnknownCmd = { "stub", "--unknown" }; - - EXPECT_FALSE(argParser.parseServerArgs(serverArgs, argc, kUnknownCmd.data())); + EXPECT_FALSE(argParser.parseServerArgs(serverArgs, argc, kUnknownCmd.data())); } diff --git a/src/test/unittests/synergy/X11LayoutParserTests.cpp b/src/test/unittests/synergy/X11LayoutParserTests.cpp index 907c0b728..169d5f403 100644 --- a/src/test/unittests/synergy/X11LayoutParserTests.cpp +++ b/src/test/unittests/synergy/X11LayoutParserTests.cpp @@ -20,138 +20,148 @@ #include "test/global/gtest.h" #include -void createTestFiles() -{ - std::ofstream correctEvdevFile ("correctEvdev.xml"); - if(!correctEvdevFile.is_open()) { - FAIL(); - } +void createTestFiles() { + std::ofstream correctEvdevFile("correctEvdev.xml"); + if (!correctEvdevFile.is_open()) { + FAIL(); + } - correctEvdevFile << "" << std::endl; - correctEvdevFile << "" << std::endl; - correctEvdevFile << " " << std::endl; - correctEvdevFile << " " << std::endl; - correctEvdevFile << " " << std::endl; - correctEvdevFile << " us" << std::endl; - correctEvdevFile << " " << std::endl; - correctEvdevFile << " en" << std::endl; - correctEvdevFile << " English (US)" << std::endl; - correctEvdevFile << " " << std::endl; - correctEvdevFile << " eng" << std::endl; - correctEvdevFile << " " << std::endl; - correctEvdevFile << " " << std::endl; - correctEvdevFile << " " << std::endl; - correctEvdevFile << " " << std::endl; - correctEvdevFile << " " << std::endl; - correctEvdevFile << " eng" << std::endl; - correctEvdevFile << " eng" << std::endl; - correctEvdevFile << " Cherokee" << std::endl; - correctEvdevFile << " " << std::endl; - correctEvdevFile << " eng" << std::endl; - correctEvdevFile << " " << std::endl; - correctEvdevFile << " " << std::endl; - correctEvdevFile << " " << std::endl; - correctEvdevFile << " " << std::endl; - correctEvdevFile << " " << std::endl; - correctEvdevFile << " " << std::endl; - correctEvdevFile << " " << std::endl; - correctEvdevFile << " ru" << std::endl; - correctEvdevFile << " " << std::endl; - correctEvdevFile << " ru" << std::endl; - correctEvdevFile << " Russian" << std::endl; - correctEvdevFile << " " << std::endl; - correctEvdevFile << " rus" << std::endl; - correctEvdevFile << " " << std::endl; - correctEvdevFile << " " << std::endl; - correctEvdevFile << " " << std::endl; - correctEvdevFile << " " << std::endl; - correctEvdevFile << "" << std::endl; - correctEvdevFile.close(); + correctEvdevFile << "" << std::endl; + correctEvdevFile << "" << std::endl; + correctEvdevFile << " " << std::endl; + correctEvdevFile << " " << std::endl; + correctEvdevFile << " " << std::endl; + correctEvdevFile << " us" << std::endl; + correctEvdevFile << " " + << std::endl; + correctEvdevFile << " en" + << std::endl; + correctEvdevFile << " English (US)" + << std::endl; + correctEvdevFile << " " << std::endl; + correctEvdevFile << " eng" << std::endl; + correctEvdevFile << " " << std::endl; + correctEvdevFile << " " << std::endl; + correctEvdevFile << " " << std::endl; + correctEvdevFile << " " << std::endl; + correctEvdevFile << " " << std::endl; + correctEvdevFile << " eng" << std::endl; + correctEvdevFile << " eng" + << std::endl; + correctEvdevFile << " Cherokee" + << std::endl; + correctEvdevFile << " " << std::endl; + correctEvdevFile << " eng" << std::endl; + correctEvdevFile << " " << std::endl; + correctEvdevFile << " " << std::endl; + correctEvdevFile << " " << std::endl; + correctEvdevFile << " " << std::endl; + correctEvdevFile << " " << std::endl; + correctEvdevFile << " " << std::endl; + correctEvdevFile << " " << std::endl; + correctEvdevFile << " ru" << std::endl; + correctEvdevFile << " " + << std::endl; + correctEvdevFile << " ru" + << std::endl; + correctEvdevFile << " Russian" << std::endl; + correctEvdevFile << " " << std::endl; + correctEvdevFile << " rus" << std::endl; + correctEvdevFile << " " << std::endl; + correctEvdevFile << " " << std::endl; + correctEvdevFile << " " << std::endl; + correctEvdevFile << " " << std::endl; + correctEvdevFile << "" << std::endl; + correctEvdevFile.close(); - std::ofstream evdevFromFutureFile ("evdevFromFuture.xml"); - if(!evdevFromFutureFile.is_open()) { - FAIL(); - } + std::ofstream evdevFromFutureFile("evdevFromFuture.xml"); + if (!evdevFromFutureFile.is_open()) { + FAIL(); + } - evdevFromFutureFile << "" << std::endl; - evdevFromFutureFile << "" << std::endl; - evdevFromFutureFile << " " << std::endl; - evdevFromFutureFile << " " << std::endl; - evdevFromFutureFile << " " << std::endl; - evdevFromFutureFile << " futureLangName" << std::endl; - evdevFromFutureFile << " " << std::endl; - evdevFromFutureFile << " fln" << std::endl; - evdevFromFutureFile << " " << std::endl; - evdevFromFutureFile << " " << std::endl; - evdevFromFutureFile << " " << std::endl; - evdevFromFutureFile << " " << std::endl; - evdevFromFutureFile << "" << std::endl; - evdevFromFutureFile.close(); + evdevFromFutureFile << "" + << std::endl; + evdevFromFutureFile << "" << std::endl; + evdevFromFutureFile << " " << std::endl; + evdevFromFutureFile << " " << std::endl; + evdevFromFutureFile << " " << std::endl; + evdevFromFutureFile << " futureLangName" << std::endl; + evdevFromFutureFile << " " << std::endl; + evdevFromFutureFile << " fln" << std::endl; + evdevFromFutureFile << " " << std::endl; + evdevFromFutureFile << " " << std::endl; + evdevFromFutureFile << " " << std::endl; + evdevFromFutureFile << " " << std::endl; + evdevFromFutureFile << "" << std::endl; + evdevFromFutureFile.close(); - std::ofstream incorrectEvdevFile1 ("incorrectEvdev1.xml"); - if(!incorrectEvdevFile1.is_open()) { - FAIL(); - } + std::ofstream incorrectEvdevFile1("incorrectEvdev1.xml"); + if (!incorrectEvdevFile1.is_open()) { + FAIL(); + } - incorrectEvdevFile1 << "" << std::endl; - incorrectEvdevFile1.close(); + incorrectEvdevFile1 << "" << std::endl; + incorrectEvdevFile1.close(); - std::ofstream incorrectEvdevFile2 ("incorrectEvdev2.xml"); - if(!incorrectEvdevFile2.is_open()) { - FAIL(); - } + std::ofstream incorrectEvdevFile2("incorrectEvdev2.xml"); + if (!incorrectEvdevFile2.is_open()) { + FAIL(); + } - incorrectEvdevFile2 << "" << std::endl; - incorrectEvdevFile2 << "" << std::endl; - incorrectEvdevFile2 << "" << std::endl; - incorrectEvdevFile2.close(); + incorrectEvdevFile2 << "" + << std::endl; + incorrectEvdevFile2 << "" << std::endl; + incorrectEvdevFile2 << "" << std::endl; + incorrectEvdevFile2.close(); - std::ofstream incorrectEvdevFile3 ("incorrectEvdev3.xml"); - if(!incorrectEvdevFile3.is_open()) { - FAIL(); - } + std::ofstream incorrectEvdevFile3("incorrectEvdev3.xml"); + if (!incorrectEvdevFile3.is_open()) { + FAIL(); + } - incorrectEvdevFile3 << "" << std::endl; - incorrectEvdevFile3 << "" << std::endl; - incorrectEvdevFile3 << " " << std::endl; - incorrectEvdevFile3 << " " << std::endl; - incorrectEvdevFile3 << " " << std::endl; - incorrectEvdevFile3 << " " << std::endl; - incorrectEvdevFile3 << "" << std::endl; - incorrectEvdevFile3.close(); + incorrectEvdevFile3 << "" + << std::endl; + incorrectEvdevFile3 << "" << std::endl; + incorrectEvdevFile3 << " " << std::endl; + incorrectEvdevFile3 << " " << std::endl; + incorrectEvdevFile3 << " " << std::endl; + incorrectEvdevFile3 << " " << std::endl; + incorrectEvdevFile3 << "" << std::endl; + incorrectEvdevFile3.close(); } -TEST(X11LayoutsParsingTests, xmlCorrectParsingTest) -{ - createTestFiles(); - std::vector expectedResult = { "en", "ru" }; - auto parsedResult = X11LayoutsParser::getX11LanguageList("correctEvdev.xml"); +TEST(X11LayoutsParsingTests, xmlCorrectParsingTest) { + createTestFiles(); + std::vector expectedResult = {"en", "ru"}; + auto parsedResult = X11LayoutsParser::getX11LanguageList("correctEvdev.xml"); - EXPECT_EQ(parsedResult, parsedResult); + EXPECT_EQ(parsedResult, parsedResult); } -TEST(X11LayoutsParsingTests, xmlParsingMissedEvdevFileTest) -{ - auto parsedResult = X11LayoutsParser::getX11LanguageList("missedFile"); - EXPECT_TRUE(parsedResult.empty()); +TEST(X11LayoutsParsingTests, xmlParsingMissedEvdevFileTest) { + auto parsedResult = X11LayoutsParser::getX11LanguageList("missedFile"); + EXPECT_TRUE(parsedResult.empty()); } -TEST(X11LayoutsParsingTests, xmlParsingIncorrectEvdevFileTest) -{ - std::vector parsedResult; - parsedResult = X11LayoutsParser::getX11LanguageList("incorrectEvdev1.xml"); - EXPECT_TRUE(parsedResult.empty()); - parsedResult = X11LayoutsParser::getX11LanguageList("incorrectEvdev2.xml"); - EXPECT_TRUE(parsedResult.empty()); - parsedResult = X11LayoutsParser::getX11LanguageList("incorrectEvdev3.xml"); - EXPECT_TRUE(parsedResult.empty()); +TEST(X11LayoutsParsingTests, xmlParsingIncorrectEvdevFileTest) { + std::vector parsedResult; + parsedResult = X11LayoutsParser::getX11LanguageList("incorrectEvdev1.xml"); + EXPECT_TRUE(parsedResult.empty()); + parsedResult = X11LayoutsParser::getX11LanguageList("incorrectEvdev2.xml"); + EXPECT_TRUE(parsedResult.empty()); + parsedResult = X11LayoutsParser::getX11LanguageList("incorrectEvdev3.xml"); + EXPECT_TRUE(parsedResult.empty()); } -TEST(X11LayoutsParsingTests, layoutConvertTest) -{ - EXPECT_EQ(X11LayoutsParser::convertLayotToISO("correctEvdev.xml", "us", true), "en"); - EXPECT_EQ(X11LayoutsParser::convertLayotToISO("incorrectEvdev1.xml", "us", true), ""); - EXPECT_EQ(X11LayoutsParser::convertLayotToISO("evdevFromFuture.xml", "us", true), ""); +TEST(X11LayoutsParsingTests, layoutConvertTest) { + EXPECT_EQ(X11LayoutsParser::convertLayotToISO("correctEvdev.xml", "us", true), + "en"); + EXPECT_EQ( + X11LayoutsParser::convertLayotToISO("incorrectEvdev1.xml", "us", true), + ""); + EXPECT_EQ( + X11LayoutsParser::convertLayotToISO("evdevFromFuture.xml", "us", true), + ""); } #endif diff --git a/src/test/unittests/synergy/languages/LanguageManagerTests.cpp b/src/test/unittests/synergy/languages/LanguageManagerTests.cpp index 58bb3a86e..0243f6328 100644 --- a/src/test/unittests/synergy/languages/LanguageManagerTests.cpp +++ b/src/test/unittests/synergy/languages/LanguageManagerTests.cpp @@ -18,50 +18,46 @@ #include "synergy/languages/LanguageManager.h" #include "test/global/gtest.h" +TEST(LanguageManager, RemoteLanguagesTest) { + std::string remoteLanguages = "ruenuk"; + synergy::languages::LanguageManager manager({"ru", "en", "uk"}); -TEST(LanguageManager, RemoteLanguagesTest) -{ - std::string remoteLanguages = "ruenuk"; - synergy::languages::LanguageManager manager({"ru", "en", "uk"}); + manager.setRemoteLanguages(remoteLanguages); + EXPECT_EQ((std::vector{"ru", "en", "uk"}), + manager.getRemoteLanguages()); - manager.setRemoteLanguages(remoteLanguages); - EXPECT_EQ((std::vector {"ru", "en", "uk"}), manager.getRemoteLanguages()); - - manager.setRemoteLanguages(String()); - EXPECT_TRUE(manager.getRemoteLanguages().empty()); + manager.setRemoteLanguages(String()); + EXPECT_TRUE(manager.getRemoteLanguages().empty()); } -TEST(LanguageManager, LocalLanguagesTest) -{ - std::vector localLanguages = {"ru", "en", "uk"}; - synergy::languages::LanguageManager manager(localLanguages); +TEST(LanguageManager, LocalLanguagesTest) { + std::vector localLanguages = {"ru", "en", "uk"}; + synergy::languages::LanguageManager manager(localLanguages); - EXPECT_EQ((std::vector {"ru", "en", "uk"}), manager.getLocalLanguages()); + EXPECT_EQ((std::vector{"ru", "en", "uk"}), + manager.getLocalLanguages()); } -TEST(LanguageManager, MissedLanguagesTest) -{ - String remoteLanguages = "ruenuk"; - std::vector localLanguages = {"en"}; - synergy::languages::LanguageManager manager(localLanguages); +TEST(LanguageManager, MissedLanguagesTest) { + String remoteLanguages = "ruenuk"; + std::vector localLanguages = {"en"}; + synergy::languages::LanguageManager manager(localLanguages); - manager.setRemoteLanguages(remoteLanguages); - EXPECT_EQ("ru, uk", manager.getMissedLanguages()); + manager.setRemoteLanguages(remoteLanguages); + EXPECT_EQ("ru, uk", manager.getMissedLanguages()); } -TEST(LanguageManager, SerializeLocalLanguagesTest) -{ - std::vector localLanguages = {"ru", "en", "uk"}; - synergy::languages::LanguageManager manager(localLanguages); +TEST(LanguageManager, SerializeLocalLanguagesTest) { + std::vector localLanguages = {"ru", "en", "uk"}; + synergy::languages::LanguageManager manager(localLanguages); - EXPECT_EQ("ruenuk", manager.getSerializedLocalLanguages()); + EXPECT_EQ("ruenuk", manager.getSerializedLocalLanguages()); } -TEST(LanguageManager, LanguageInstalledTest) -{ - std::vector localLanguages = {"ru", "en", "uk"}; - synergy::languages::LanguageManager manager(localLanguages); +TEST(LanguageManager, LanguageInstalledTest) { + std::vector localLanguages = {"ru", "en", "uk"}; + synergy::languages::LanguageManager manager(localLanguages); - EXPECT_FALSE(manager.isLanguageInstalled("us")); - EXPECT_TRUE(manager.isLanguageInstalled("en")); + EXPECT_FALSE(manager.isLanguageInstalled("us")); + EXPECT_TRUE(manager.isLanguageInstalled("en")); }