From dff8b887edf10407f22aaab9d147948cd5491f0a Mon Sep 17 00:00:00 2001 From: Unit 193 Date: Sat, 5 Oct 2019 21:10:01 -0400 Subject: New upstream version 2.3.2+dfsg --- .gitignore | 1 + Build.properties | 2 +- CMakeLists.txt | 8 +- README.md | 14 ++- azure-pipelines/build_env_tmpl.bat | 2 +- azure-pipelines/download_install_qt.ps1 | 2 +- clean_build.bat | 2 + cmake/Version.cmake | 8 +- pre-build.bat | 2 +- snap/snapcraft.yaml | 7 +- src/lib/arch/IArchString.cpp | 26 ++---- src/lib/arch/unix/ArchMultithreadPosix.cpp | 118 ++++++++++++------------ src/lib/arch/unix/ArchMultithreadPosix.h | 3 +- src/lib/barrier/App.cpp | 2 +- src/lib/barrier/App.h | 8 +- src/lib/barrier/ClientApp.cpp | 3 +- src/lib/barrier/ServerApp.cpp | 5 +- src/lib/barrier/mouse_types.h | 5 +- src/lib/base/EventQueue.cpp | 24 +++-- src/lib/base/EventQueue.h | 5 +- src/lib/base/Log.cpp | 16 ++-- src/lib/base/Log.h | 3 +- src/lib/ipc/IpcClientProxy.cpp | 19 ++-- src/lib/ipc/IpcClientProxy.h | 6 +- src/lib/ipc/IpcLogOutputter.cpp | 14 ++- src/lib/ipc/IpcLogOutputter.h | 5 +- src/lib/ipc/IpcServer.cpp | 33 +++---- src/lib/ipc/IpcServer.h | 3 +- src/lib/net/ISocketMultiplexerJob.h | 31 +++++-- src/lib/net/SecureSocket.cpp | 69 ++++++++------- src/lib/net/SecureSocket.h | 14 ++- src/lib/net/SocketMultiplexer.cpp | 72 +++++++-------- src/lib/net/SocketMultiplexer.h | 7 +- src/lib/net/TCPListenSocket.cpp | 27 +++--- src/lib/net/TCPListenSocket.h | 6 +- src/lib/net/TCPSocket.cpp | 61 +++++++------ src/lib/net/TCPSocket.h | 17 ++-- src/lib/net/TSocketMultiplexerMethodJob.h | 18 ++-- src/lib/platform/MSWindowsDesks.cpp | 13 ++- src/lib/platform/MSWindowsHook.cpp | 11 +++ src/lib/platform/MSWindowsScreen.cpp | 11 ++- src/lib/platform/MSWindowsScreen.h | 2 +- src/lib/platform/OSXScreen.h | 2 +- src/lib/platform/OSXScreen.mm | 29 ++++-- src/lib/platform/XWindowsScreen.cpp | 138 +++++++++++++++-------------- src/lib/platform/XWindowsScreen.h | 10 ++- 46 files changed, 464 insertions(+), 420 deletions(-) diff --git a/.gitignore b/.gitignore index feeb09e..10c604b 100644 --- a/.gitignore +++ b/.gitignore @@ -31,3 +31,4 @@ CMakeCache.txt .vscode/ # Transient in-project-directory dependencies /deps/ +/out/build/x64-Debug diff --git a/Build.properties b/Build.properties index 7f71f09..437beb7 100644 --- a/Build.properties +++ b/Build.properties @@ -3,5 +3,5 @@ # BARRIER_VERSION_MAJOR = 2 BARRIER_VERSION_MINOR = 3 -BARRIER_VERSION_PATCH = 1 +BARRIER_VERSION_PATCH = 2 BARRIER_VERSION_STAGE = snapshot diff --git a/CMakeLists.txt b/CMakeLists.txt index 1c28635..e456e2f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -53,7 +53,7 @@ include_directories (BEFORE SYSTEM ./ext/gtest/include) if (UNIX) if (NOT APPLE) - set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC") + set (CMAKE_POSITION_INDEPENDENT_CODE TRUE) endif() # For config.h, detect the libraries, functions, etc. @@ -349,6 +349,12 @@ else() set (OPENSSL_LIBS ${lib_ssl} ${lib_crypto}) endif() + +# Check we have the *required* Qt5 libs. +find_package(Qt5Core REQUIRED) +find_package(Qt5Network REQUIRED) +find_package(Qt5Widgets REQUIRED) + # # Configure_file... but for directories, recursively. # diff --git a/README.md b/README.md index 3dd5dc0..39d2c61 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,9 @@ # Barrier Eliminate the barrier between your machines. -Find [releases here](https://github.com/debauchee/barrier/releases). +Find [releases for windows and macOS here](https://github.com/debauchee/barrier/releases). +Your distro probably already has barrier packaged for it, see [distro specific packages](#distro-specific-packages) +below for a list. Alternatively, we also provide a [flatpak](https://github.com/flathub/com.github.debauchee.barrier). ### Contact info: @@ -14,8 +16,9 @@ Master branch overall build status: [![Build Status](https://dev.azure.com/debau * Mac Build Status: [![Build Status](https://dev.azure.com/debauchee/Barrier/_apis/build/status/debauchee.barrier?branchName=master&jobName=Mac%20Build)](https://dev.azure.com/debauchee/Barrier/_build/latest?definitionId=1&branchName=master) * Windows Debug Build Status: [![Build Status](https://dev.azure.com/debauchee/Barrier/_apis/build/status/debauchee.barrier?branchName=master&jobName=Windows%20Build&configuration=Windows%20Build%20Debug)](https://dev.azure.com/debauchee/Barrier/_build/latest?definitionId=1&branchName=master) * Windows Release Build Status: [![Build Status](https://dev.azure.com/debauchee/Barrier/_apis/build/status/debauchee.barrier?branchName=master&jobName=Windows%20Build&configuration=Windows%20Build%20Release%20with%20Release%20Installer)](https://dev.azure.com/debauchee/Barrier/_build/latest?definitionId=1&branchName=master) +* Snap: [![Snap Status](https://build.snapcraft.io/badge/debauchee/barrier.svg)](https://build.snapcraft.io/user/debauchee/barrier) -Our CI Builds are provided by Microsoft Azure Pipelines. +Our CI Builds are provided by Microsoft Azure Pipelines, Flathub, and Canonical. ### What is it? @@ -43,6 +46,13 @@ For short and simple questions or to just say hello find us on the Freenode IRC At this time we are looking for developers to help fix the issues found in the issue tracker. Submit pull requests once you've polished up your patch and we'll review and possibly merge it. +## Distro specific packages + +While not a comprehensive list, repology provides a decent list of distro +specific packages. + +[![Packaging status](https://repology.org/badge/vertical-allrepos/barrier.svg)](https://repology.org/project/barrier/versions) + ### FAQ Q: Does drag and drop work on linux? diff --git a/azure-pipelines/build_env_tmpl.bat b/azure-pipelines/build_env_tmpl.bat index eefa014..c2a5c1d 100644 --- a/azure-pipelines/build_env_tmpl.bat +++ b/azure-pipelines/build_env_tmpl.bat @@ -1,6 +1,6 @@ set B_BUILD_TYPE=%CI_ENV_BUILD_TYPE% set B_QT_ROOT=%cd%\deps\Qt -set B_QT_VER=Qt5.12.3\5.12.3 +set B_QT_VER=Qt5.13.0\5.13.0 set B_QT_MSVC=msvc2017_64 set B_BONJOUR=%cd%\deps\BonjourSDKLike diff --git a/azure-pipelines/download_install_qt.ps1 b/azure-pipelines/download_install_qt.ps1 index 7edefbf..c2c2322 100644 --- a/azure-pipelines/download_install_qt.ps1 +++ b/azure-pipelines/download_install_qt.ps1 @@ -1,7 +1,7 @@ $ErrorActionPreference = "Stop" $qli_install_version = '2019.05.26.1' -$qt_version = '5.12.3' +$qt_version = '5.13.0' New-Item -Force -ItemType Directory -Path ".\deps\" diff --git a/clean_build.bat b/clean_build.bat index e45f334..edce29c 100644 --- a/clean_build.bat +++ b/clean_build.bat @@ -50,6 +50,8 @@ if exist bin\Debug ( copy %B_QT_FULLPATH%\bin\Qt5Cored.dll bin\Debug\ > NUL copy ..\ext\openssl\windows\x64\bin\* bin\Debug\ > NUL copy ..\res\openssl\barrier.conf bin\Debug\ > NUL + mkdir bin\Debug\platforms + copy %B_QT_FULLPATH%\plugins\platforms\qwindowsd.dll bin\Debug\platforms\ > NUL ) else if exist bin\Release ( copy %B_QT_FULLPATH%\bin\Qt5Core.dll bin\Release\ > NUL copy %B_QT_FULLPATH%\bin\Qt5Gui.dll bin\Release\ > NUL diff --git a/cmake/Version.cmake b/cmake/Version.cmake index d90f48b..a27ffb4 100644 --- a/cmake/Version.cmake +++ b/cmake/Version.cmake @@ -2,7 +2,7 @@ cmake_minimum_required (VERSION 3.4) set (BARRIER_VERSION_MAJOR 2) set (BARRIER_VERSION_MINOR 3) -set (BARRIER_VERSION_PATCH 1) +set (BARRIER_VERSION_PATCH 2) # # Barrier Version @@ -11,7 +11,7 @@ if (NOT DEFINED BARRIER_VERSION_MAJOR) if (DEFINED ENV{BARRIER_VERSION_MAJOR}) set (BARRIER_VERSION_MAJOR $ENV{BARRIER_VERSION_MAJOR}) else() - set (BARRIER_VERSION_MAJOR 1) + set (BARRIER_VERSION_MAJOR 2) endif() endif() @@ -19,7 +19,7 @@ if (NOT DEFINED BARRIER_VERSION_MINOR) if (DEFINED ENV{BARRIER_VERSION_MINOR}) set (BARRIER_VERSION_MINOR $ENV{BARRIER_VERSION_MINOR}) else() - set (BARRIER_VERSION_MINOR 9) + set (BARRIER_VERSION_MINOR 3) endif() endif() @@ -27,7 +27,7 @@ if (NOT DEFINED BARRIER_VERSION_PATCH) if (DEFINED ENV{BARRIER_VERSION_PATCH}) set (BARRIER_VERSION_PATCH $ENV{BARRIER_VERSION_PATCH}) else() - set (BARRIER_VERSION_PATCH 0) + set (BARRIER_VERSION_PATCH 2) message (WARNING "Barrier version wasn't set. Set to ${BARRIER_VERSION_MAJOR}.${BARRIER_VERSION_MINOR}.${BARRIER_VERSION_PATCH}") endif() endif() diff --git a/pre-build.bat b/pre-build.bat index 0c78903..44b74d6 100644 --- a/pre-build.bat +++ b/pre-build.bat @@ -1 +1 @@ -%comspec% /k "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\Common7\Tools\VsDevCmd.bat" +%comspec% /k "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\Common7\Tools\VsDevCmd.bat" diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index 3aa2a33..804c0fc 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -1,5 +1,5 @@ -name: barrier-kvm # the Barrier Snappy for Linux / not tested on MAC yet -base: core18 +name: barrier +base: core18 version: master version-script: git describe --tags --long | sed "s/^v//" adopt-info: appstream-flathub @@ -43,8 +43,9 @@ parts: plugin: cmake configflags: - "-DCMAKE_INSTALL_PREFIX=/usr" + - "-DCMAKE_BUILD_TYPE=Release" build-packages: - - xorg-dev + - xorg-dev - libcurl4-openssl-dev - libavahi-compat-libdnssd-dev - libssl-dev diff --git a/src/lib/arch/IArchString.cpp b/src/lib/arch/IArchString.cpp index f618c12..0f7f300 100644 --- a/src/lib/arch/IArchString.cpp +++ b/src/lib/arch/IArchString.cpp @@ -24,7 +24,9 @@ #include #include -static ArchMutex s_mutex = NULL; +#include + +std::mutex s_mutex; // // use C library non-reentrant multibyte conversion with mutex @@ -32,16 +34,14 @@ static ArchMutex 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) { + std::lock_guard lock(s_mutex); + ptrdiff_t len = 0; bool dummyErrors; @@ -49,12 +49,6 @@ IArchString::convStringWCToMB(char* dst, errors = &dummyErrors; } - if (s_mutex == NULL) { - s_mutex = ARCH->newMutex(); - } - - ARCH->lockMutex(s_mutex); - if (dst == NULL) { char dummy[MB_LEN_MAX]; for (const wchar_t* scan = src; n > 0; ++scan, --n) { @@ -89,7 +83,6 @@ IArchString::convStringWCToMB(char* dst, } len = dst - dst0; } - ARCH->unlockMutex(s_mutex); return (int)len; } @@ -98,6 +91,8 @@ int IArchString::convStringMBToWC(wchar_t* dst, const char* src, UInt32 n_param, bool* errors) { + std::lock_guard lock(s_mutex); + ptrdiff_t n = (ptrdiff_t)n_param; // fix compiler warning ptrdiff_t len = 0; wchar_t dummy; @@ -107,12 +102,6 @@ IArchString::convStringMBToWC(wchar_t* dst, errors = &dummyErrors; } - if (s_mutex == NULL) { - s_mutex = ARCH->newMutex(); - } - - ARCH->lockMutex(s_mutex); - if (dst == NULL) { for (const char* scan = src; n > 0; ) { ptrdiff_t mblen = mbtowc(&dummy, scan, n); @@ -184,7 +173,6 @@ IArchString::convStringMBToWC(wchar_t* dst, } len = dst - dst0; } - ARCH->unlockMutex(s_mutex); return (int)len; } diff --git a/src/lib/arch/unix/ArchMultithreadPosix.cpp b/src/lib/arch/unix/ArchMultithreadPosix.cpp index ade6c51..c9ddc6c 100644 --- a/src/lib/arch/unix/ArchMultithreadPosix.cpp +++ b/src/lib/arch/unix/ArchMultithreadPosix.cpp @@ -114,9 +114,6 @@ ArchMultithreadPosix::ArchMultithreadPosix() : m_signalUserData[i] = NULL; } - // 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; @@ -153,26 +150,22 @@ ArchMultithreadPosix::~ArchMultithreadPosix() { assert(s_instance != NULL); - closeMutex(m_threadMutex); s_instance = NULL; } void ArchMultithreadPosix::setNetworkDataForCurrentThread(void* data) { - lockMutex(m_threadMutex); + std::lock_guard lock(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; + std::lock_guard lock(m_threadMutex); + return thread->m_networkData; } ArchMultithreadPosix* @@ -356,7 +349,8 @@ ArchMultithreadPosix::newThread(ThreadFunc func, void* data) #endif } - lockMutex(m_threadMutex); + // note that the child thread will wait until we release this mutex + std::lock_guard lock(m_threadMutex); // create thread impl for new thread ArchThreadImpl* thread = new ArchThreadImpl; @@ -387,18 +381,15 @@ ArchMultithreadPosix::newThread(ThreadFunc func, void* data) 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); + std::lock_guard lock(m_threadMutex); + ArchThreadImpl* thread = find(pthread_self()); - unlockMutex(m_threadMutex); assert(thread != NULL); return thread; } @@ -416,10 +407,11 @@ ArchMultithreadPosix::closeThread(ArchThread thread) } // remove thread from list - lockMutex(m_threadMutex); - assert(findNoRef(thread->m_thread) == thread); - erase(thread); - unlockMutex(m_threadMutex); + { + std::lock_guard lock(m_threadMutex); + assert(findNoRef(thread->m_thread) == thread); + erase(thread); + } // done with thread delete thread; @@ -440,12 +432,14 @@ ArchMultithreadPosix::cancelThread(ArchThread thread) // 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; + + { + std::lock_guard lock(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) { @@ -465,9 +459,11 @@ void ArchMultithreadPosix::testCancelThread() { // find current thread - lockMutex(m_threadMutex); - ArchThreadImpl* thread = findNoRef(pthread_self()); - unlockMutex(m_threadMutex); + ArchThreadImpl* thread = nullptr; + { + std::lock_guard lock(m_threadMutex); + thread = findNoRef(pthread_self()); + } // test cancel on thread testCancelThreadImpl(thread); @@ -478,21 +474,22 @@ ArchMultithreadPosix::wait(ArchThread target, double timeout) { assert(target != NULL); - lockMutex(m_threadMutex); + ArchThreadImpl* self = nullptr; - // find current thread - ArchThreadImpl* self = findNoRef(pthread_self()); + { + std::lock_guard lock(m_threadMutex); - // ignore wait if trying to wait on ourself - if (target == self) { - unlockMutex(m_threadMutex); - return false; - } + // find current thread + self = findNoRef(pthread_self()); - // ref the target so it can't go away while we're watching it - refThread(target); + // ignore wait if trying to wait on ourself + if (target == self) { + return false; + } - unlockMutex(m_threadMutex); + // ref the target so it can't go away while we're watching it + refThread(target); + } try { // do first test regardless of timeout @@ -538,19 +535,15 @@ ArchMultithreadPosix::isSameThread(ArchThread thread1, ArchThread thread2) bool ArchMultithreadPosix::isExitedThread(ArchThread thread) { - lockMutex(m_threadMutex); - bool exited = thread->m_exited; - unlockMutex(m_threadMutex); - return exited; + std::lock_guard lock(m_threadMutex); + return thread->m_exited; } void* ArchMultithreadPosix::getResultOfThread(ArchThread thread) { - lockMutex(m_threadMutex); - void* result = thread->m_result; - unlockMutex(m_threadMutex); - return result; + std::lock_guard lock(m_threadMutex); + return thread->m_result; } IArchMultithread::ThreadID @@ -563,16 +556,15 @@ void ArchMultithreadPosix::setSignalHandler( ESignal signal, SignalFunc func, void* userData) { - lockMutex(m_threadMutex); + std::lock_guard lock(m_threadMutex); m_signalFunc[signal] = func; m_signalUserData[signal] = userData; - unlockMutex(m_threadMutex); } void ArchMultithreadPosix::raiseSignal(ESignal signal) { - lockMutex(m_threadMutex); + std::lock_guard lock(m_threadMutex); if (m_signalFunc[signal] != NULL) { m_signalFunc[signal](signal, m_signalUserData[signal]); pthread_kill(m_mainThread->m_thread, SIGWAKEUP); @@ -580,7 +572,6 @@ ArchMultithreadPosix::raiseSignal(ESignal signal) else if (signal == kINTERRUPT || signal == kTERMINATE) { ARCH->cancelThread(m_mainThread); } - unlockMutex(m_threadMutex); } void @@ -677,15 +668,15 @@ ArchMultithreadPosix::testCancelThreadImpl(ArchThreadImpl* thread) { assert(thread != NULL); + std::lock_guard lock(m_threadMutex); + // 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) { @@ -717,8 +708,9 @@ ArchMultithreadPosix::doThreadFunc(ArchThread thread) setPriorityOfThread(thread, 1); // wait for parent to initialize this object - lockMutex(m_threadMutex); - unlockMutex(m_threadMutex); + { + std::lock_guard lock(m_threadMutex); + } void* result = NULL; try { @@ -731,18 +723,20 @@ ArchMultithreadPosix::doThreadFunc(ArchThread thread) } catch (...) { // note -- don't catch (...) to avoid masking bugs - lockMutex(m_threadMutex); - thread->m_exited = true; - unlockMutex(m_threadMutex); + { + std::lock_guard lock(m_threadMutex); + thread->m_exited = true; + } closeThread(thread); throw; } // thread has exited - lockMutex(m_threadMutex); - thread->m_result = result; - thread->m_exited = true; - unlockMutex(m_threadMutex); + { + std::lock_guard lock(m_threadMutex); + thread->m_result = result; + thread->m_exited = true; + } // done with thread closeThread(thread); diff --git a/src/lib/arch/unix/ArchMultithreadPosix.h b/src/lib/arch/unix/ArchMultithreadPosix.h index 98b5eda..4bd879f 100644 --- a/src/lib/arch/unix/ArchMultithreadPosix.h +++ b/src/lib/arch/unix/ArchMultithreadPosix.h @@ -22,6 +22,7 @@ #include "common/stdlist.h" #include +#include #define ARCH_MULTITHREAD ArchMultithreadPosix @@ -104,7 +105,7 @@ private: bool m_newThreadCalled; - ArchMutex m_threadMutex; + std::mutex m_threadMutex; ArchThread m_mainThread; ThreadList m_threadList; ThreadID m_nextID; diff --git a/src/lib/barrier/App.cpp b/src/lib/barrier/App.cpp index f4293b6..8a79aa2 100644 --- a/src/lib/barrier/App.cpp +++ b/src/lib/barrier/App.cpp @@ -200,7 +200,7 @@ App::initApp(int argc, const char** argv) void App::initIpcClient() { - m_ipcClient = new IpcClient(m_events, m_socketMultiplexer); + m_ipcClient = new IpcClient(m_events, m_socketMultiplexer.get()); m_ipcClient->connect(); m_events->adoptHandler( diff --git a/src/lib/barrier/App.h b/src/lib/barrier/App.h index b7c77a0..8040da8 100644 --- a/src/lib/barrier/App.h +++ b/src/lib/barrier/App.h @@ -23,7 +23,9 @@ #include "base/String.h" #include "base/Log.h" #include "base/EventQueue.h" +#include "net/SocketMultiplexer.h" #include "common/common.h" +#include #if SYSAPI_WIN32 #include "barrier/win32/AppUtilWindows.h" @@ -95,8 +97,8 @@ public: virtual IEventQueue* getEvents() const { return m_events; } - void setSocketMultiplexer(SocketMultiplexer* sm) { m_socketMultiplexer = sm; } - SocketMultiplexer* getSocketMultiplexer() const { return m_socketMultiplexer; } + void setSocketMultiplexer(std::unique_ptr&& sm) { m_socketMultiplexer = std::move(sm); } + SocketMultiplexer* getSocketMultiplexer() const { return m_socketMultiplexer.get(); } void setEvents(EventQueue& events) { m_events = &events; } @@ -119,7 +121,7 @@ private: CreateTaskBarReceiverFunc m_createTaskBarReceiver; ARCH_APP_UTIL m_appUtil; IpcClient* m_ipcClient; - SocketMultiplexer* m_socketMultiplexer; + std::unique_ptr m_socketMultiplexer; }; class MinimalApp : public App { diff --git a/src/lib/barrier/ClientApp.cpp b/src/lib/barrier/ClientApp.cpp index 15416f6..a91312d 100644 --- a/src/lib/barrier/ClientApp.cpp +++ b/src/lib/barrier/ClientApp.cpp @@ -443,8 +443,7 @@ ClientApp::mainLoop() { // create socket multiplexer. this must happen after daemonization // on unix because threads evaporate across a fork(). - SocketMultiplexer multiplexer; - setSocketMultiplexer(&multiplexer); + setSocketMultiplexer(std::make_unique()); // start client, etc appUtil().startNode(); diff --git a/src/lib/barrier/ServerApp.cpp b/src/lib/barrier/ServerApp.cpp index fbb5092..318673c 100644 --- a/src/lib/barrier/ServerApp.cpp +++ b/src/lib/barrier/ServerApp.cpp @@ -302,8 +302,8 @@ void ServerApp::stopRetryTimer() { if (m_timer != NULL) { + m_events->removeHandler(Event::kTimer, m_timer); m_events->deleteTimer(m_timer); - m_events->removeHandler(Event::kTimer, NULL); m_timer = NULL; } } @@ -713,8 +713,7 @@ ServerApp::mainLoop() { // create socket multiplexer. this must happen after daemonization // on unix because threads evaporate across a fork(). - SocketMultiplexer multiplexer; - setSocketMultiplexer(&multiplexer); + setSocketMultiplexer(std::make_unique()); // if configuration has no screens then add this system // as the default diff --git a/src/lib/barrier/mouse_types.h b/src/lib/barrier/mouse_types.h index cf860c0..62a2396 100644 --- a/src/lib/barrier/mouse_types.h +++ b/src/lib/barrier/mouse_types.h @@ -32,10 +32,13 @@ static const ButtonID kButtonNone = 0; static const ButtonID kButtonLeft = 1; static const ButtonID kButtonMiddle = 2; static const ButtonID kButtonRight = 3; +// mouse button 4 static const ButtonID kButtonExtra0 = 4; +// mouse button 5 +static const ButtonID kButtonExtra1 = 5; static const ButtonID kMacButtonRight = 2; static const ButtonID kMacButtonMiddle = 3; //@} -static const UInt8 NumButtonIDs = 5; +static const UInt8 NumButtonIDs = 6; diff --git a/src/lib/base/EventQueue.cpp b/src/lib/base/EventQueue.cpp index b17e35b..fe8cff5 100644 --- a/src/lib/base/EventQueue.cpp +++ b/src/lib/base/EventQueue.cpp @@ -90,7 +90,6 @@ EventQueue::EventQueue() : 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; @@ -104,7 +103,6 @@ EventQueue::~EventQueue() ARCH->setSignalHandler(Arch::kINTERRUPT, NULL, NULL); ARCH->setSignalHandler(Arch::kTERMINATE, NULL, NULL); - ARCH->closeMutex(m_mutex); } void @@ -136,7 +134,7 @@ EventQueue::loop() Event::Type EventQueue::registerTypeOnce(Event::Type& type, const char* name) { - ArchMutexLock lock(m_mutex); + std::lock_guard 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)); @@ -176,7 +174,7 @@ EventQueue::getTypeName(Event::Type type) void EventQueue::adoptBuffer(IEventQueueBuffer* buffer) { - ArchMutexLock lock(m_mutex); + std::lock_guard lock(m_mutex); LOG((CLOG_DEBUG "adopting new buffer")); @@ -261,7 +259,7 @@ retry: case IEventQueueBuffer::kUser: { - ArchMutexLock lock(m_mutex); + std::lock_guard lock(m_mutex); event = removeEvent(dataID); return true; } @@ -316,7 +314,7 @@ EventQueue::addEvent(const Event& event) void EventQueue::addEventToBuffer(const Event& event) { - ArchMutexLock lock(m_mutex); + std::lock_guard lock(m_mutex); // store the event's data locally UInt32 eventID = saveEvent(event); @@ -338,7 +336,7 @@ EventQueue::newTimer(double duration, void* target) if (target == NULL) { target = timer; } - ArchMutexLock lock(m_mutex); + std::lock_guard 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 @@ -357,7 +355,7 @@ EventQueue::newOneShotTimer(double duration, void* target) if (target == NULL) { target = timer; } - ArchMutexLock lock(m_mutex); + std::lock_guard 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 @@ -370,7 +368,7 @@ EventQueue::newOneShotTimer(double duration, void* target) void EventQueue::deleteTimer(EventQueueTimer* timer) { - ArchMutexLock lock(m_mutex); + std::lock_guard lock(m_mutex); for (TimerQueue::iterator index = m_timerQueue.begin(); index != m_timerQueue.end(); ++index) { if (index->getTimer() == timer) { @@ -388,7 +386,7 @@ EventQueue::deleteTimer(EventQueueTimer* timer) void EventQueue::adoptHandler(Event::Type type, void* target, IEventJob* handler) { - ArchMutexLock lock(m_mutex); + std::lock_guard lock(m_mutex); IEventJob*& job = m_handlers[target][type]; delete job; job = handler; @@ -399,7 +397,7 @@ EventQueue::removeHandler(Event::Type type, void* target) { IEventJob* handler = NULL; { - ArchMutexLock lock(m_mutex); + std::lock_guard lock(m_mutex); HandlerTable::iterator index = m_handlers.find(target); if (index != m_handlers.end()) { TypeHandlerTable& typeHandlers = index->second; @@ -418,7 +416,7 @@ EventQueue::removeHandlers(void* target) { std::vector handlers; { - ArchMutexLock lock(m_mutex); + std::lock_guard lock(m_mutex); HandlerTable::iterator index = m_handlers.find(target); if (index != m_handlers.end()) { // copy to handlers array and clear table for target @@ -447,7 +445,7 @@ EventQueue::isEmpty() const IEventJob* EventQueue::getHandler(Event::Type type, void* target) const { - ArchMutexLock lock(m_mutex); + std::lock_guard lock(m_mutex); HandlerTable::const_iterator index = m_handlers.find(target); if (index != m_handlers.end()) { const TypeHandlerTable& typeHandlers = index->second; diff --git a/src/lib/base/EventQueue.h b/src/lib/base/EventQueue.h index 97e7fba..0a2179b 100644 --- a/src/lib/base/EventQueue.h +++ b/src/lib/base/EventQueue.h @@ -28,10 +28,9 @@ #include "common/stdset.h" #include "base/NonBlockingStream.h" +#include #include -class Mutex; - //! Event queue /*! An event queue that implements the platform independent parts and @@ -114,7 +113,7 @@ private: typedef std::map HandlerTable; int m_systemTarget; - ArchMutex m_mutex; + mutable std::mutex m_mutex; // registered events Event::Type m_nextType; diff --git a/src/lib/base/Log.cpp b/src/lib/base/Log.cpp index 823bf6d..1252ed9 100644 --- a/src/lib/base/Log.cpp +++ b/src/lib/base/Log.cpp @@ -63,9 +63,6 @@ Log::Log() { assert(s_log == NULL); - // create mutex for multithread safe operation - m_mutex = ARCH->newMutex(); - // other initalization m_maxPriority = g_defaultMaxPriority; m_maxNewlineLength = 0; @@ -90,7 +87,6 @@ Log::~Log() index != m_alwaysOutputters.end(); ++index) { delete *index; } - ARCH->closeMutex(m_mutex); } Log* @@ -214,7 +210,7 @@ Log::insert(ILogOutputter* outputter, bool alwaysAtHead) { assert(outputter != NULL); - ArchMutexLock lock(m_mutex); + std::lock_guard lock(m_mutex); if (alwaysAtHead) { m_alwaysOutputters.push_front(outputter); } @@ -237,7 +233,7 @@ Log::insert(ILogOutputter* outputter, bool alwaysAtHead) void Log::remove(ILogOutputter* outputter) { - ArchMutexLock lock(m_mutex); + std::lock_guard lock(m_mutex); m_outputters.remove(outputter); m_alwaysOutputters.remove(outputter); } @@ -245,7 +241,7 @@ Log::remove(ILogOutputter* outputter) void Log::pop_front(bool alwaysAtHead) { - ArchMutexLock lock(m_mutex); + std::lock_guard lock(m_mutex); OutputterList* list = alwaysAtHead ? &m_alwaysOutputters : &m_outputters; if (!list->empty()) { delete list->front(); @@ -271,14 +267,14 @@ Log::setFilter(const char* maxPriority) void Log::setFilter(int maxPriority) { - ArchMutexLock lock(m_mutex); + std::lock_guard lock(m_mutex); m_maxPriority = maxPriority; } int Log::getFilter() const { - ArchMutexLock lock(m_mutex); + std::lock_guard lock(m_mutex); return m_maxPriority; } @@ -289,7 +285,7 @@ Log::output(ELevel priority, char* msg) assert(msg != NULL); if (!msg) return; - ArchMutexLock lock(m_mutex); + std::lock_guard lock(m_mutex); OutputterList::const_iterator i; diff --git a/src/lib/base/Log.h b/src/lib/base/Log.h index 1d09be2..0ed458f 100644 --- a/src/lib/base/Log.h +++ b/src/lib/base/Log.h @@ -24,6 +24,7 @@ #include "common/stdlist.h" #include +#include #define CLOG (Log::getInstance()) #define BYE "\nTry `%s --help' for more information." @@ -132,7 +133,7 @@ private: static Log* s_log; - ArchMutex m_mutex; + mutable std::mutex m_mutex; OutputterList m_outputters; OutputterList m_alwaysOutputters; int m_maxNewlineLength; diff --git a/src/lib/ipc/IpcClientProxy.cpp b/src/lib/ipc/IpcClientProxy.cpp index af85eca..5104277 100644 --- a/src/lib/ipc/IpcClientProxy.cpp +++ b/src/lib/ipc/IpcClientProxy.cpp @@ -34,8 +34,6 @@ IpcClientProxy::IpcClientProxy(barrier::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( @@ -71,14 +69,11 @@ IpcClientProxy::~IpcClientProxy() 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); - - ARCH->closeMutex(m_readMutex); - ARCH->closeMutex(m_writeMutex); + { + std::lock_guard lock_read(m_readMutex); + std::lock_guard lock_write(m_writeMutex); + delete &m_stream; + } } void @@ -99,7 +94,7 @@ void IpcClientProxy::handleData(const Event&, void*) { // don't allow the dtor to destroy the stream while we're using it. - ArchMutexLock lock(m_readMutex); + std::lock_guard lock(m_readMutex); LOG((CLOG_DEBUG "start ipc handle data")); @@ -139,7 +134,7 @@ 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); + std::lock_guard lock(m_writeMutex); LOG((CLOG_DEBUG4 "ipc write: %d", message.type())); diff --git a/src/lib/ipc/IpcClientProxy.h b/src/lib/ipc/IpcClientProxy.h index eaa12c7..eb9f1e9 100644 --- a/src/lib/ipc/IpcClientProxy.h +++ b/src/lib/ipc/IpcClientProxy.h @@ -23,6 +23,8 @@ #include "base/EventTypes.h" #include "base/Event.h" +#include + namespace barrier { class IStream; } class IpcMessage; class IpcCommandMessage; @@ -49,7 +51,7 @@ private: barrier::IStream& m_stream; EIpcClientType m_clientType; bool m_disconnecting; - ArchMutex m_readMutex; - ArchMutex m_writeMutex; + std::mutex m_readMutex; + std::mutex m_writeMutex; IEventQueue* m_events; }; diff --git a/src/lib/ipc/IpcLogOutputter.cpp b/src/lib/ipc/IpcLogOutputter.cpp index 984793e..b62c76a 100644 --- a/src/lib/ipc/IpcLogOutputter.cpp +++ b/src/lib/ipc/IpcLogOutputter.cpp @@ -39,7 +39,6 @@ enum EIpcLogOutputter { IpcLogOutputter::IpcLogOutputter(IpcServer& ipcServer, EIpcClientType clientType, bool useThread) : m_ipcServer(ipcServer), - m_bufferMutex(ARCH->newMutex()), m_sending(false), m_bufferThread(nullptr), m_running(false), @@ -52,8 +51,7 @@ IpcLogOutputter::IpcLogOutputter(IpcServer& ipcServer, EIpcClientType clientType m_bufferRateTimeLimit(kBufferRateTimeLimit), m_bufferWriteCount(0), m_bufferRateStart(ARCH->time()), - m_clientType(clientType), - m_runningMutex(ARCH->newMutex()) + m_clientType(clientType) { if (useThread) { m_bufferThread = new Thread(new TMethodJob( @@ -65,8 +63,6 @@ IpcLogOutputter::~IpcLogOutputter() { close(); - ARCH->closeMutex(m_bufferMutex); - if (m_bufferThread != nullptr) { m_bufferThread->cancel(); m_bufferThread->wait(); @@ -86,7 +82,7 @@ void IpcLogOutputter::close() { if (m_bufferThread != nullptr) { - ArchMutexLock lock(m_runningMutex); + std::lock_guard lock(m_runningMutex); m_running = false; notifyBuffer(); m_bufferThread->wait(5); @@ -116,7 +112,7 @@ IpcLogOutputter::write(ELevel, const char* text) void IpcLogOutputter::appendBuffer(const String& text) { - ArchMutexLock lock(m_bufferMutex); + std::lock_guard lock(m_bufferMutex); double elapsed = ARCH->time() - m_bufferRateStart; if (elapsed < m_bufferRateTimeLimit) { @@ -143,7 +139,7 @@ IpcLogOutputter::appendBuffer(const String& text) bool IpcLogOutputter::isRunning() { - ArchMutexLock lock(m_runningMutex); + std::lock_guard lock(m_runningMutex); return m_running; } @@ -180,7 +176,7 @@ IpcLogOutputter::notifyBuffer() String IpcLogOutputter::getChunk(size_t count) { - ArchMutexLock lock(m_bufferMutex); + std::lock_guard lock(m_bufferMutex); if (m_buffer.size() < count) { count = m_buffer.size(); diff --git a/src/lib/ipc/IpcLogOutputter.h b/src/lib/ipc/IpcLogOutputter.h index 461f022..2f1b98c 100644 --- a/src/lib/ipc/IpcLogOutputter.h +++ b/src/lib/ipc/IpcLogOutputter.h @@ -24,6 +24,7 @@ #include "ipc/Ipc.h" #include +#include class IpcServer; class Event; @@ -100,7 +101,7 @@ private: IpcServer& m_ipcServer; Buffer m_buffer; - ArchMutex m_bufferMutex; + std::mutex m_bufferMutex; bool m_sending; Thread* m_bufferThread; bool m_running; @@ -115,5 +116,5 @@ private: UInt16 m_bufferWriteCount; double m_bufferRateStart; EIpcClientType m_clientType; - ArchMutex m_runningMutex; + std::mutex m_runningMutex; }; diff --git a/src/lib/ipc/IpcServer.cpp b/src/lib/ipc/IpcServer.cpp index e05a913..8df98d1 100644 --- a/src/lib/ipc/IpcServer.cpp +++ b/src/lib/ipc/IpcServer.cpp @@ -56,7 +56,6 @@ IpcServer::init() { m_socket = new TCPListenSocket(m_events, m_socketMultiplexer, IArchNetwork::kINET); - m_clientsMutex = ARCH->newMutex(); m_address.resolve(); m_events->adoptHandler( @@ -75,15 +74,15 @@ IpcServer::~IpcServer() delete m_socket; } - ARCH->lockMutex(m_clientsMutex); - ClientList::iterator it; - for (it = m_clients.begin(); it != m_clients.end(); it++) { - deleteClient(*it); + { + std::lock_guard lock(m_clientsMutex); + ClientList::iterator it; + for (it = m_clients.begin(); it != m_clients.end(); it++) { + deleteClient(*it); + } + m_clients.clear(); } - m_clients.clear(); - ARCH->unlockMutex(m_clientsMutex); - ARCH->closeMutex(m_clientsMutex); - + m_events->removeHandler(m_events->forIListenSocket().connecting(), m_socket); } @@ -103,10 +102,12 @@ IpcServer::handleClientConnecting(const Event&, void*) 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); + IpcClientProxy* proxy = nullptr; + { + std::lock_guard lock(m_clientsMutex); + proxy = new IpcClientProxy(*stream, m_events); + m_clients.push_back(proxy); + } m_events->adoptHandler( m_events->forIpcClientProxy().disconnected(), proxy, @@ -127,7 +128,7 @@ IpcServer::handleClientDisconnected(const Event& e, void*) { IpcClientProxy* proxy = static_cast(e.getTarget()); - ArchMutexLock lock(m_clientsMutex); + std::lock_guard lock(m_clientsMutex); m_clients.remove(proxy); deleteClient(proxy); @@ -153,7 +154,7 @@ IpcServer::deleteClient(IpcClientProxy* proxy) bool IpcServer::hasClients(EIpcClientType clientType) const { - ArchMutexLock lock(m_clientsMutex); + std::lock_guard lock(m_clientsMutex); if (m_clients.empty()) { return false; @@ -175,7 +176,7 @@ IpcServer::hasClients(EIpcClientType clientType) const void IpcServer::send(const IpcMessage& message, EIpcClientType filterType) { - ArchMutexLock lock(m_clientsMutex); + std::lock_guard lock(m_clientsMutex); ClientList::iterator it; for (it = m_clients.begin(); it != m_clients.end(); it++) { diff --git a/src/lib/ipc/IpcServer.h b/src/lib/ipc/IpcServer.h index d9bbe3e..179bad8 100644 --- a/src/lib/ipc/IpcServer.h +++ b/src/lib/ipc/IpcServer.h @@ -25,6 +25,7 @@ #include "base/EventTypes.h" #include +#include class Event; class IpcClientProxy; @@ -79,7 +80,7 @@ private: TCPListenSocket* m_socket; NetworkAddress m_address; ClientList m_clients; - ArchMutex m_clientsMutex; + mutable std::mutex m_clientsMutex; #ifdef TEST_ENV public: diff --git a/src/lib/net/ISocketMultiplexerJob.h b/src/lib/net/ISocketMultiplexerJob.h index ddd3ba5..c27fce2 100644 --- a/src/lib/net/ISocketMultiplexerJob.h +++ b/src/lib/net/ISocketMultiplexerJob.h @@ -20,6 +20,19 @@ #include "arch/IArchNetwork.h" #include "common/IInterface.h" +#include + +class ISocketMultiplexerJob; + +struct MultiplexerJobStatus +{ + MultiplexerJobStatus(bool cont, std::unique_ptr&& nj) : + continue_servicing(cont), new_job(std::move(nj)) + {} + + bool continue_servicing = false; + std::unique_ptr new_job; +}; //! Socket multiplexer job /*! @@ -32,21 +45,20 @@ public: //! 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. + Called by a socket multiplexer when the socket becomes readable, writable, or has an error. + The socket is readable if \p readable is true, writable if \p writable is true, and in error + if \p error is true. + + The method returns false as the continue_servicing member of the returned struct if the socket + should no longer be served and true otherwise. Additionally, if the new_job member of the + returned pair is not empty, the socket should be serviced differently with the specified job. 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; + virtual MultiplexerJobStatus run(bool readable, bool writable, bool error) = 0; //@} //! @name accessors @@ -72,5 +84,6 @@ public: */ virtual bool isWritable() const = 0; + virtual bool isCursor() const { return false; } //@} }; diff --git a/src/lib/net/SecureSocket.cpp b/src/lib/net/SecureSocket.cpp index 360db31..99f626e 100644 --- a/src/lib/net/SecureSocket.cpp +++ b/src/lib/net/SecureSocket.cpp @@ -83,17 +83,9 @@ SecureSocket::~SecureSocket() // 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->m_ssl != NULL) { - SSL_shutdown(m_ssl->m_ssl); + removeJob(); + freeSSLResources(); - 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; - } // removing sleep() because I have no idea why you would want to do it // ... smells of trying to cover up a bug you don't understand //ARCH->sleep(1); @@ -104,10 +96,22 @@ void SecureSocket::close() { isFatal(true); + freeSSLResources(); + TCPSocket::close(); +} - SSL_shutdown(m_ssl->m_ssl); +void SecureSocket::freeSSLResources() +{ + if (m_ssl->m_ssl != NULL) { + SSL_shutdown(m_ssl->m_ssl); + SSL_free(m_ssl->m_ssl); + m_ssl->m_ssl = NULL; + } - TCPSocket::close(); + if (m_ssl->m_context != NULL) { + SSL_CTX_free(m_ssl->m_context); + m_ssl->m_context = NULL; + } } void @@ -121,13 +125,12 @@ SecureSocket::connect(const NetworkAddress& addr) TCPSocket::connect(addr); } -ISocketMultiplexerJob* -SecureSocket::newJob() +std::unique_ptr SecureSocket::newJob() { // after TCP connection is established, SecureSocket will pick up // connected event and do secureConnect if (m_connected && !m_secureReady) { - return NULL; + return {}; } return TCPSocket::newJob(); @@ -136,7 +139,7 @@ SecureSocket::newJob() void SecureSocket::secureConnect() { - setJob(new TSocketMultiplexerMethodJob( + setJob(std::make_unique>( this, &SecureSocket::serviceConnect, getSocket(), isReadable(), isWritable())); } @@ -144,7 +147,7 @@ SecureSocket::secureConnect() void SecureSocket::secureAccept() { - setJob(new TSocketMultiplexerMethodJob( + setJob(std::make_unique>( this, &SecureSocket::serviceAccept, getSocket(), isReadable(), isWritable())); } @@ -736,10 +739,11 @@ SecureSocket::verifyCertFingerprint() return isValid; } -ISocketMultiplexerJob* -SecureSocket::serviceConnect(ISocketMultiplexerJob* job, - bool, bool write, bool error) +MultiplexerJobStatus SecureSocket::serviceConnect(ISocketMultiplexerJob* job, + bool read, bool write, bool error) { + (void) read; + Lock lock(&getMutex()); int status = 0; @@ -751,25 +755,28 @@ SecureSocket::serviceConnect(ISocketMultiplexerJob* job, // If status < 0, error happened if (status < 0) { - return NULL; + return {false, {}}; } // If status > 0, success if (status > 0) { sendEvent(m_events->forIDataSocket().secureConnected()); - return newJob(); + return {true, newJob()}; } // Retry case - return new TSocketMultiplexerMethodJob( + return { + true, + std::make_unique>( this, &SecureSocket::serviceConnect, - getSocket(), isReadable(), isWritable()); + getSocket(), isReadable(), isWritable()) + }; } -ISocketMultiplexerJob* -SecureSocket::serviceAccept(ISocketMultiplexerJob* job, - bool, bool write, bool error) +MultiplexerJobStatus SecureSocket::serviceAccept(ISocketMultiplexerJob* job, + bool read, bool write, bool error) { + (void) read; Lock lock(&getMutex()); int status = 0; @@ -780,19 +787,19 @@ SecureSocket::serviceAccept(ISocketMultiplexerJob* job, #endif // If status < 0, error happened if (status < 0) { - return NULL; + return {false, {}}; } // If status > 0, success if (status > 0) { sendEvent(m_events->forClientListener().accepted()); - return newJob(); + return {true, newJob()}; } // Retry case - return new TSocketMultiplexerMethodJob( + return {true, std::make_unique>( this, &SecureSocket::serviceAccept, - getSocket(), isReadable(), isWritable()); + getSocket(), isReadable(), isWritable())}; } void diff --git a/src/lib/net/SecureSocket.h b/src/lib/net/SecureSocket.h index 01d3c3f..773b508 100644 --- a/src/lib/net/SecureSocket.h +++ b/src/lib/net/SecureSocket.h @@ -44,8 +44,7 @@ public: // IDataSocket overrides virtual void connect(const NetworkAddress&); - ISocketMultiplexerJob* - newJob(); + std::unique_ptr newJob() override; bool isFatal() const { return m_fatal; } void isFatal(bool b) { m_fatal = b; } bool isSecureReady(); @@ -74,13 +73,8 @@ private: bool separator = true); bool verifyCertFingerprint(); - ISocketMultiplexerJob* - serviceConnect(ISocketMultiplexerJob*, - bool, bool, bool); - - ISocketMultiplexerJob* - serviceAccept(ISocketMultiplexerJob*, - bool, bool, bool); + MultiplexerJobStatus serviceConnect(ISocketMultiplexerJob*, bool, bool, bool); + MultiplexerJobStatus serviceAccept(ISocketMultiplexerJob*, bool, bool, bool); void showSecureConnectInfo(); void showSecureLibInfo(); @@ -88,6 +82,8 @@ private: void handleTCPConnected(const Event& event, void*); + void freeSSLResources(); + private: Ssl* m_ssl; bool m_secureReady; diff --git a/src/lib/net/SocketMultiplexer.cpp b/src/lib/net/SocketMultiplexer.cpp index c4bc64a..cdb9039 100644 --- a/src/lib/net/SocketMultiplexer.cpp +++ b/src/lib/net/SocketMultiplexer.cpp @@ -33,6 +33,20 @@ // SocketMultiplexer // +class CursorMultiplexerJob : public ISocketMultiplexerJob { +public: + MultiplexerJobStatus run(bool readable, bool writable, bool error) override + { + return {false, {}}; + } + + ArchSocket getSocket() const override { return {}; } + bool isReadable() const override { return false; } + bool isWritable() const override { return false; } + bool isCursor() const override { return true; } +}; + + SocketMultiplexer::SocketMultiplexer() : m_mutex(new Mutex), m_thread(NULL), @@ -43,12 +57,6 @@ SocketMultiplexer::SocketMultiplexer() : 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)); @@ -66,16 +74,9 @@ SocketMultiplexer::~SocketMultiplexer() 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); - } } -void -SocketMultiplexer::addSocket(ISocket* socket, ISocketMultiplexerJob* job) +void SocketMultiplexer::addSocket(ISocket* socket, std::unique_ptr&& job) { assert(socket != NULL); assert(job != NULL); @@ -95,16 +96,12 @@ SocketMultiplexer::addSocket(ISocket* socket, ISocketMultiplexerJob* job) // 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); + JobCursor j = m_socketJobs.insert(m_socketJobs.end(), std::move(job)); m_update = true; m_socketJobMap.insert(std::make_pair(socket, j)); } else { - JobCursor j = i->second; - if (*j != job) { - delete *j; - *j = job; - } + *(i->second) = std::move(job); m_update = true; } @@ -131,10 +128,9 @@ SocketMultiplexer::removeSocket(ISocket* socket) // 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; + if (*(i->second)) { + i->second->reset(); + m_update = true; } } @@ -173,14 +169,13 @@ SocketMultiplexer::serviceThread(void*) JobCursor cursor = newCursor(); JobCursor jobCursor = nextCursor(cursor); while (jobCursor != m_socketJobs.end()) { - ISocketMultiplexerJob* job = *jobCursor; - if (job != NULL) { - pfd.m_socket = job->getSocket(); + if (*jobCursor) { + pfd.m_socket = (*jobCursor)->getSocket(); pfd.m_events = 0; - if (job->isReadable()) { + if ((*jobCursor)->isReadable()) { pfd.m_events |= IArchNetwork::kPOLLIN; } - if (job->isWritable()) { + if ((*jobCursor)->isWritable()) { pfd.m_events |= IArchNetwork::kPOLLOUT; } pfds.push_back(pfd); @@ -221,15 +216,16 @@ SocketMultiplexer::serviceThread(void*) IArchNetwork::kPOLLNVAL)) != 0); // run job - ISocketMultiplexerJob* job = *jobCursor; - ISocketMultiplexerJob* newJob = job->run(read, write, error); + MultiplexerJobStatus status = (*jobCursor)->run(read, write, error); - // save job, if different - if (newJob != job) { + if (!status.continue_servicing) { + Lock lock(m_mutex); + jobCursor->reset(); + m_update = true; + } else if (status.new_job) { Lock lock(m_mutex); - delete job; - *jobCursor = newJob; - m_update = true; + *jobCursor = std::move(status.new_job); + m_update = true; } ++i; } @@ -262,7 +258,7 @@ SocketMultiplexer::JobCursor SocketMultiplexer::newCursor() { Lock lock(m_mutex); - return m_socketJobs.insert(m_socketJobs.begin(), m_cursorMark); + return m_socketJobs.insert(m_socketJobs.begin(), std::make_unique()); } SocketMultiplexer::JobCursor @@ -272,7 +268,7 @@ SocketMultiplexer::nextCursor(JobCursor cursor) JobCursor j = m_socketJobs.end(); JobCursor i = cursor; while (++i != m_socketJobs.end()) { - if (*i != m_cursorMark) { + if (*i && !(*i)->isCursor()) { // found a real job (as opposed to a cursor) j = i; diff --git a/src/lib/net/SocketMultiplexer.h b/src/lib/net/SocketMultiplexer.h index 4aa39fc..9891558 100644 --- a/src/lib/net/SocketMultiplexer.h +++ b/src/lib/net/SocketMultiplexer.h @@ -21,6 +21,7 @@ #include "arch/IArchNetwork.h" #include "common/stdlist.h" #include "common/stdmap.h" +#include template class CondVar; @@ -41,7 +42,7 @@ public: //! @name manipulators //@{ - void addSocket(ISocket*, ISocketMultiplexerJob*); + void addSocket(ISocket*, std::unique_ptr&& job); void removeSocket(ISocket*); @@ -58,7 +59,7 @@ public: private: // list of jobs. we use a list so we can safely iterate over it // while other threads modify it. - typedef std::list SocketJobs; + using SocketJobs = std::list>; typedef SocketJobs::iterator JobCursor; typedef std::map SocketJobMap; @@ -106,6 +107,4 @@ private: SocketJobs m_socketJobs; SocketJobMap m_socketJobMap; - ISocketMultiplexerJob* - m_cursorMark; }; diff --git a/src/lib/net/TCPListenSocket.cpp b/src/lib/net/TCPListenSocket.cpp index 8e1540e..26f03b0 100644 --- a/src/lib/net/TCPListenSocket.cpp +++ b/src/lib/net/TCPListenSocket.cpp @@ -69,10 +69,11 @@ TCPListenSocket::bind(const NetworkAddress& addr) 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)); + + auto new_job = std::make_unique>( + this, &TCPListenSocket::serviceListening, m_socket, true, false); + + m_socketMultiplexer->addSocket(this, std::move(new_job)); } catch (XArchNetworkAddressInUse& e) { throw XSocketAddressInUse(e.what()); @@ -135,24 +136,22 @@ TCPListenSocket::accept() void TCPListenSocket::setListeningJob() { - m_socketMultiplexer->addSocket(this, - new TSocketMultiplexerMethodJob( - this, &TCPListenSocket::serviceListening, - m_socket, true, false)); + auto new_job = std::make_unique>( + this, &TCPListenSocket::serviceListening, m_socket, true, false); + m_socketMultiplexer->addSocket(this, std::move(new_job)); } -ISocketMultiplexerJob* -TCPListenSocket::serviceListening(ISocketMultiplexerJob* job, - bool read, bool, bool error) +MultiplexerJobStatus TCPListenSocket::serviceListening(ISocketMultiplexerJob* job, + bool read, bool, bool error) { if (error) { close(); - return NULL; + return {false, {}}; } if (read) { m_events->addEvent(Event(m_events->forIListenSocket().connecting(), this, NULL)); // stop polling on this socket until the client accepts - return NULL; + return {false, {}}; } - return job; + return {true, {}}; } diff --git a/src/lib/net/TCPListenSocket.h b/src/lib/net/TCPListenSocket.h index 1060356..f3ababc 100644 --- a/src/lib/net/TCPListenSocket.h +++ b/src/lib/net/TCPListenSocket.h @@ -19,10 +19,10 @@ #pragma once #include "net/IListenSocket.h" +#include "net/ISocketMultiplexerJob.h" #include "arch/IArchNetwork.h" class Mutex; -class ISocketMultiplexerJob; class IEventQueue; class SocketMultiplexer; @@ -48,9 +48,7 @@ protected: void setListeningJob(); public: - ISocketMultiplexerJob* - serviceListening(ISocketMultiplexerJob*, - bool, bool, bool); + MultiplexerJobStatus serviceListening(ISocketMultiplexerJob*, bool, bool, bool); protected: ArchSocket m_socket; diff --git a/src/lib/net/TCPSocket.cpp b/src/lib/net/TCPSocket.cpp index d454aa1..4f4251a 100644 --- a/src/lib/net/TCPSocket.cpp +++ b/src/lib/net/TCPSocket.cpp @@ -388,40 +388,42 @@ TCPSocket::doWrite() return kRetry; } -void -TCPSocket::setJob(ISocketMultiplexerJob* job) +void TCPSocket::removeJob() { // multiplexer will delete the old job - if (job == NULL) { - m_socketMultiplexer->removeSocket(this); - } - else { - m_socketMultiplexer->addSocket(this, job); + m_socketMultiplexer->removeSocket(this); +} + +void TCPSocket::setJob(std::unique_ptr&& job) +{ + if (job.get() == nullptr) { + removeJob(); + } else { + m_socketMultiplexer->addSocket(this, std::move(job)); } } -ISocketMultiplexerJob* -TCPSocket::newJob() +std::unique_ptr TCPSocket::newJob() { // note -- must have m_mutex locked on entry if (m_socket == NULL) { - return NULL; + return {}; } else if (!m_connected) { assert(!m_readable); if (!(m_readable || m_writable)) { - return NULL; + return {}; } - return new TSocketMultiplexerMethodJob( + return std::make_unique>( this, &TCPSocket::serviceConnecting, m_socket, m_readable, m_writable); } else { if (!(m_readable || (m_writable && (m_outputBuffer.getSize() > 0)))) { - return NULL; + return {}; } - return new TSocketMultiplexerMethodJob( + return std::make_unique>( this, &TCPSocket::serviceConnected, m_socket, m_readable, m_writable && (m_outputBuffer.getSize() > 0)); @@ -488,9 +490,7 @@ TCPSocket::onDisconnected() m_connected = false; } -ISocketMultiplexerJob* -TCPSocket::serviceConnecting(ISocketMultiplexerJob* job, - bool, bool write, bool error) +MultiplexerJobStatus TCPSocket::serviceConnecting(ISocketMultiplexerJob* job, bool, bool write, bool error) { Lock lock(&m_mutex); @@ -519,29 +519,36 @@ TCPSocket::serviceConnecting(ISocketMultiplexerJob* job, catch (XArchNetwork& e) { sendConnectionFailedEvent(e.what()); onDisconnected(); - return newJob(); + auto new_job = newJob(); + if (new_job) + return {true, std::move(new_job)}; + else + return {false, {}}; } } if (write) { sendEvent(m_events->forIDataSocket().connected()); onConnected(); - return newJob(); + auto new_job = newJob(); + if (new_job) + return {true, std::move(new_job)}; + else + return {false, {}}; } - return job; + return {true, {}}; } -ISocketMultiplexerJob* -TCPSocket::serviceConnected(ISocketMultiplexerJob* job, - bool read, bool write, bool error) +MultiplexerJobStatus TCPSocket::serviceConnected(ISocketMultiplexerJob* job, + bool read, bool write, bool error) { Lock lock(&m_mutex); if (error) { sendEvent(m_events->forISocket().disconnected()); onDisconnected(); - return newJob(); + return {true, newJob()}; } EJobResult writeResult = kRetry; @@ -594,10 +601,10 @@ TCPSocket::serviceConnected(ISocketMultiplexerJob* job, } if (writeResult == kBreak || readResult == kBreak) { - return NULL; + return {false, {}}; } else if (writeResult == kNew || readResult == kNew) { - return newJob(); + return {true, newJob()}; } else { - return job; + return {true, {}}; } } diff --git a/src/lib/net/TCPSocket.h b/src/lib/net/TCPSocket.h index 1006f88..2889135 100644 --- a/src/lib/net/TCPSocket.h +++ b/src/lib/net/TCPSocket.h @@ -19,14 +19,15 @@ #pragma once #include "net/IDataSocket.h" +#include "net/ISocketMultiplexerJob.h" #include "io/StreamBuffer.h" #include "mt/CondVar.h" #include "mt/Mutex.h" #include "arch/IArchNetwork.h" +#include class Mutex; class Thread; -class ISocketMultiplexerJob; class IEventQueue; class SocketMultiplexer; @@ -59,8 +60,7 @@ public: virtual void connect(const NetworkAddress&); - virtual ISocketMultiplexerJob* - newJob(); + virtual std::unique_ptr newJob(); protected: enum EJobResult { @@ -74,7 +74,8 @@ protected: virtual EJobResult doRead(); virtual EJobResult doWrite(); - void setJob(ISocketMultiplexerJob*); + void removeJob(); + void setJob(std::unique_ptr&& job); bool isReadable() { return m_readable; } bool isWritable() { return m_writable; } @@ -93,12 +94,8 @@ private: void onOutputShutdown(); void onDisconnected(); - ISocketMultiplexerJob* - serviceConnecting(ISocketMultiplexerJob*, - bool, bool, bool); - ISocketMultiplexerJob* - serviceConnected(ISocketMultiplexerJob*, - bool, bool, bool); + MultiplexerJobStatus serviceConnecting(ISocketMultiplexerJob*, bool, bool, bool); + MultiplexerJobStatus serviceConnected(ISocketMultiplexerJob*, bool, bool, bool); protected: bool m_readable; diff --git a/src/lib/net/TSocketMultiplexerMethodJob.h b/src/lib/net/TSocketMultiplexerMethodJob.h index 90efbe7..9e74cdd 100644 --- a/src/lib/net/TSocketMultiplexerMethodJob.h +++ b/src/lib/net/TSocketMultiplexerMethodJob.h @@ -28,8 +28,7 @@ A socket multiplexer job class that invokes a member function. template class TSocketMultiplexerMethodJob : public ISocketMultiplexerJob { public: - typedef ISocketMultiplexerJob* - (T::*Method)(ISocketMultiplexerJob*, bool, bool, bool); + using Method = MultiplexerJobStatus (T::*)(ISocketMultiplexerJob*, bool, bool, bool); //! run() invokes \c object->method(arg) TSocketMultiplexerMethodJob(T* object, Method method, @@ -37,11 +36,10 @@ public: virtual ~TSocketMultiplexerMethodJob(); // IJob overrides - virtual ISocketMultiplexerJob* - run(bool readable, bool writable, bool error); - virtual ArchSocket getSocket() const; - virtual bool isReadable() const; - virtual bool isWritable() const; + virtual MultiplexerJobStatus run(bool readable, bool writable, bool error) override; + virtual ArchSocket getSocket() const override; + virtual bool isReadable() const override; + virtual bool isWritable() const override; private: T* m_object; @@ -74,14 +72,12 @@ TSocketMultiplexerMethodJob::~TSocketMultiplexerMethodJob() } template -inline -ISocketMultiplexerJob* -TSocketMultiplexerMethodJob::run(bool read, bool write, bool error) +inline MultiplexerJobStatus TSocketMultiplexerMethodJob::run(bool read, bool write, bool error) { if (m_object != NULL) { return (m_object->*m_method)(this, read, write, error); } - return NULL; + return {false, {}}; } template diff --git a/src/lib/platform/MSWindowsDesks.cpp b/src/lib/platform/MSWindowsDesks.cpp index b43a218..e47aeaa 100644 --- a/src/lib/platform/MSWindowsDesks.cpp +++ b/src/lib/platform/MSWindowsDesks.cpp @@ -33,6 +33,7 @@ #include "base/IEventQueue.h" #include +#include // these are only defined when WINVER >= 0x0500 #if !defined(SPI_GETMOUSESPEED) @@ -45,6 +46,10 @@ #define SPI_GETSCREENSAVERRUNNING 114 #endif +#if !defined(MOUSEEVENTF_HWHEEL) +#define MOUSEEVENTF_HWHEEL 0x1000 +#endif + // X button stuff #if !defined(WM_XBUTTONDOWN) #define WM_XBUTTONDOWN 0x020B @@ -296,12 +301,12 @@ MSWindowsDesks::fakeMouseButton(ButtonID button, bool press) flags = press ? MOUSEEVENTF_RIGHTDOWN : MOUSEEVENTF_RIGHTUP; break; - case kButtonExtra0 + 0: + case kButtonExtra0: data = XBUTTON1; flags = press ? MOUSEEVENTF_XDOWN : MOUSEEVENTF_XUP; break; - case kButtonExtra0 + 1: + case kButtonExtra1: data = XBUTTON2; flags = press ? MOUSEEVENTF_XDOWN : MOUSEEVENTF_XUP; break; @@ -686,10 +691,12 @@ MSWindowsDesks::deskThread(void* vdesk) break; case BARRIER_MSG_FAKE_WHEEL: - // XXX -- add support for x-axis scrolling if (msg.lParam != 0) { mouse_event(MOUSEEVENTF_WHEEL, 0, 0, (DWORD)msg.lParam, 0); } + else if (IsWindowsVistaOrGreater() && msg.wParam != 0) { + mouse_event(MOUSEEVENTF_HWHEEL, 0, 0, (DWORD)msg.wParam, 0); + } break; case BARRIER_MSG_CURSOR_POS: { diff --git a/src/lib/platform/MSWindowsHook.cpp b/src/lib/platform/MSWindowsHook.cpp index 2d7845a..b9b9740 100644 --- a/src/lib/platform/MSWindowsHook.cpp +++ b/src/lib/platform/MSWindowsHook.cpp @@ -25,6 +25,10 @@ #include "common/DataDirectories.h" #include "base/Log.h" +#ifndef WM_MOUSEHWHEEL +#define WM_MOUSEHWHEEL 0x020E +#endif + // // debugging compile flag. when not zero the server doesn't grab // the keyboard when the mouse leaves the server screen. this @@ -473,6 +477,13 @@ mouseHookHandler(WPARAM wParam, SInt32 x, SInt32 y, SInt32 data) } return (g_mode == kHOOK_RELAY_EVENTS); + case WM_MOUSEHWHEEL: + if (g_mode == kHOOK_RELAY_EVENTS) { + // relay event + PostThreadMessage(g_threadID, BARRIER_MSG_MOUSE_WHEEL, 0, data); + } + return (g_mode == kHOOK_RELAY_EVENTS); + case WM_NCMOUSEMOVE: case WM_MOUSEMOVE: if (g_mode == kHOOK_RELAY_EVENTS) { diff --git a/src/lib/platform/MSWindowsScreen.cpp b/src/lib/platform/MSWindowsScreen.cpp index 5246f96..2717034 100644 --- a/src/lib/platform/MSWindowsScreen.cpp +++ b/src/lib/platform/MSWindowsScreen.cpp @@ -952,9 +952,9 @@ MSWindowsScreen::updateButtons() 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) && + m_buttons[kButtonExtra0] = (numButtons >= 4) && (GetKeyState(VK_XBUTTON1) < 0); - m_buttons[kButtonExtra0 + 1] = (numButtons >= 5) && + m_buttons[kButtonExtra1] = (numButtons >= 5) && (GetKeyState(VK_XBUTTON2) < 0); } @@ -1007,8 +1007,7 @@ MSWindowsScreen::onPreDispatchPrimary(HWND, static_cast(lParam)); case BARRIER_MSG_MOUSE_WHEEL: - // XXX -- support x-axis scrolling - return onMouseWheel(0, static_cast(wParam)); + return onMouseWheel(static_cast(lParam), static_cast(wParam)); case BARRIER_MSG_PRE_WARP: { @@ -1670,13 +1669,13 @@ MSWindowsScreen::mapButtonFromEvent(WPARAM msg, LPARAM button) const switch (button) { case XBUTTON1: if (GetSystemMetrics(SM_CMOUSEBUTTONS) >= 4) { - return kButtonExtra0 + 0; + return kButtonExtra0; } break; case XBUTTON2: if (GetSystemMetrics(SM_CMOUSEBUTTONS) >= 5) { - return kButtonExtra0 + 1; + return kButtonExtra1; } break; } diff --git a/src/lib/platform/MSWindowsScreen.h b/src/lib/platform/MSWindowsScreen.h index 4245d6c..14cd505 100644 --- a/src/lib/platform/MSWindowsScreen.h +++ b/src/lib/platform/MSWindowsScreen.h @@ -307,7 +307,7 @@ private: HotKeyToIDMap m_hotKeyToIDMap; // map of button state - bool m_buttons[1 + kButtonExtra0 + 1]; + bool m_buttons[NumButtonIDs]; // the system shows the mouse cursor when an internal display count // is >= 0. this count is maintained per application but there's diff --git a/src/lib/platform/OSXScreen.h b/src/lib/platform/OSXScreen.h index 6178529..bbddfb9 100644 --- a/src/lib/platform/OSXScreen.h +++ b/src/lib/platform/OSXScreen.h @@ -118,7 +118,7 @@ private: void sendClipboardEvent(Event::Type type, ClipboardID id) const; // message handlers - bool onMouseMove(SInt32 mx, SInt32 my); + 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. diff --git a/src/lib/platform/OSXScreen.mm b/src/lib/platform/OSXScreen.mm index 8c7e24c..2b4594f 100644 --- a/src/lib/platform/OSXScreen.mm +++ b/src/lib/platform/OSXScreen.mm @@ -422,6 +422,7 @@ OSXScreen::constructMouseButtonEventMap() {kCGEventRightMouseUp, kCGEventRightMouseDragged, kCGEventRightMouseDown}, {kCGEventOtherMouseUp, kCGEventOtherMouseDragged, kCGEventOtherMouseDown}, {kCGEventOtherMouseUp, kCGEventOtherMouseDragged, kCGEventOtherMouseDown}, + {kCGEventOtherMouseUp, kCGEventOtherMouseDragged, kCGEventOtherMouseDown}, {kCGEventOtherMouseUp, kCGEventOtherMouseDragged, kCGEventOtherMouseDown} }; @@ -1076,20 +1077,20 @@ OSXScreen::handleSystemEvent(const Event& event, void*) } bool -OSXScreen::onMouseMove(SInt32 mx, SInt32 my) +OSXScreen::onMouseMove(CGFloat mx, CGFloat my) { - LOG((CLOG_DEBUG2 "mouse move %+d,%+d", mx, my)); + LOG((CLOG_DEBUG2 "mouse move %+f,%+f", mx, my)); - SInt32 x = mx - m_xCursor; - SInt32 y = my - m_yCursor; + CGFloat x = mx - m_xCursor; + CGFloat y = my - m_yCursor; if ((x == 0 && y == 0) || (mx == m_xCenter && mx == m_yCenter)) { return true; } // save position to compute delta of next motion - m_xCursor = mx; - m_yCursor = my; + m_xCursor = (SInt32)mx; + m_yCursor = (SInt32)my; if (m_isOnScreen) { // motion on primary screen @@ -1118,7 +1119,21 @@ OSXScreen::onMouseMove(SInt32 mx, SInt32 my) } else { // send motion - sendEvent(m_events->forIPrimaryScreen().motionOnSecondary(), MotionInfo::alloc(x, y)); + // Accumulate together the move into the running total + static CGFloat m_xFractionalMove = 0; + static CGFloat m_yFractionalMove = 0; + + m_xFractionalMove += x; + m_yFractionalMove += y; + + // Return the integer part + SInt32 intX = (SInt32)m_xFractionalMove; + SInt32 intY = (SInt32)m_yFractionalMove; + + // And keep only the fractional part + m_xFractionalMove -= intX; + m_yFractionalMove -= intY; + sendEvent(m_events->forIPrimaryScreen().motionOnSecondary(), MotionInfo::alloc(intX, intY)); } } diff --git a/src/lib/platform/XWindowsScreen.cpp b/src/lib/platform/XWindowsScreen.cpp index 5f6c623..e5db1a3 100644 --- a/src/lib/platform/XWindowsScreen.cpp +++ b/src/lib/platform/XWindowsScreen.cpp @@ -66,7 +66,8 @@ XWindowsScreen::XWindowsScreen( IEventQueue* events) : m_isPrimary(isPrimary), m_mouseScrollDelta(mouseScrollDelta), - m_accumulatedScroll(0), + m_x_accumulatedScroll(0), + m_y_accumulatedScroll(0), m_display(NULL), m_root(None), m_window(None), @@ -829,35 +830,37 @@ XWindowsScreen::fakeMouseRelativeMove(SInt32 dx, SInt32 dy) const } void -XWindowsScreen::fakeMouseWheel(SInt32, SInt32 yDelta) const +XWindowsScreen::fakeMouseWheel(SInt32 xDelta, SInt32 yDelta) const { - // XXX -- support x-axis scrolling - if (yDelta == 0) { - return; - } + int numEvents; - int numEvents = accumulateMouseScroll(yDelta); + if ((!xDelta && !yDelta) || (xDelta && yDelta)) { + // Invalid scrolling inputs + return; + } - // choose button depending on rotation direction - const unsigned int xButton = mapButtonToX(static_cast( - (numEvents >= 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 = m_impl->XKeysymToKeycode(m_display, XK_Page_Up); - } - else { - keycode = m_impl->XKeysymToKeycode(m_display, XK_Page_Down); - } - if (keycode != 0) { - m_impl->XTestFakeKeyEvent(m_display, keycode, True, CurrentTime); - m_impl->XTestFakeKeyEvent(m_display, keycode, False, CurrentTime); - } - return; - } + // 4, 5, 6, 7 + // up, down, left, right + unsigned int xButton; + + if (yDelta) { // vertical scroll + numEvents = y_accumulateMouseScroll(yDelta); + if (numEvents >= 0) { + xButton = 4; // up + } + else { + xButton = 5; // down + } + } + else { // horizontal scroll + numEvents = x_accumulateMouseScroll(xDelta); + if (numEvents >= 0) { + xButton = 7; // right + } + else { + xButton = 6; // left + } + } numEvents = std::abs(numEvents); @@ -1540,7 +1543,14 @@ XWindowsScreen::onMouseRelease(const XButtonEvent& xbutton) // wheel backward (toward user) sendEvent(m_events->forIPrimaryScreen().wheel(), WheelInfo::alloc(0, -120)); } - // XXX -- support x-axis scrolling + else if (xbutton.button == 6) { + // wheel left + sendEvent(m_events->forIPrimaryScreen().wheel(), WheelInfo::alloc(-120, 0)); + } + else if (xbutton.button == 7) { + // wheel right + sendEvent(m_events->forIPrimaryScreen().wheel(), WheelInfo::alloc(120, 0)); + } } void @@ -1613,11 +1623,20 @@ XWindowsScreen::onMouseMove(const XMotionEvent& xmotion) } int -XWindowsScreen::accumulateMouseScroll(SInt32 yDelta) const +XWindowsScreen::x_accumulateMouseScroll(SInt32 xDelta) const +{ + m_x_accumulatedScroll += xDelta; + int numEvents = m_x_accumulatedScroll / m_mouseScrollDelta; + m_x_accumulatedScroll -= numEvents * m_mouseScrollDelta; + return numEvents; +} + +int +XWindowsScreen::y_accumulateMouseScroll(SInt32 yDelta) const { - m_accumulatedScroll += yDelta; - int numEvents = m_accumulatedScroll / m_mouseScrollDelta; - m_accumulatedScroll -= numEvents * m_mouseScrollDelta; + m_y_accumulatedScroll += yDelta; + int numEvents = m_y_accumulatedScroll / m_mouseScrollDelta; + m_y_accumulatedScroll -= numEvents * m_mouseScrollDelta; return numEvents; } @@ -1840,19 +1859,19 @@ 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) { + // http://xahlee.info/linux/linux_x11_mouse_button_number.html + // and the program `xev` + switch (button) + { + case 1: case 2: case 3: // kButtonLeft, Middle, Right 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); - } - - // unknown button - else { + case 4: case 5: case 6: case 7: // scroll up, down, left, right -- ignored here + return kButtonNone; + case 8: // mouse button 4 + return kButtonExtra0; + case 9: // mouse button 5 + return kButtonExtra1; + default: // unknown button return kButtonNone; } } @@ -1860,30 +1879,17 @@ XWindowsScreen::mapButtonFromX(const XButtonEvent* event) const 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 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 + switch (id) + { + case kButtonLeft: case kButtonMiddle: case kButtonRight: + return id; + case kButtonExtra0: + return 8; + case kButtonExtra1: + return 9; + default: return 0; } - - // map button - return static_cast(id); } void diff --git a/src/lib/platform/XWindowsScreen.h b/src/lib/platform/XWindowsScreen.h index 7134017..5573839 100644 --- a/src/lib/platform/XWindowsScreen.h +++ b/src/lib/platform/XWindowsScreen.h @@ -139,7 +139,8 @@ private: // Returns the number of scroll events needed after the current delta has // been taken into account - int accumulateMouseScroll(SInt32 yDelta) const; + int x_accumulateMouseScroll(SInt32 xDelta) const; + int y_accumulateMouseScroll(SInt32 yDelta) const; bool detectXI2(); #ifdef HAVE_XI2 @@ -183,10 +184,11 @@ private: // The size of a smallest supported scroll event, in points int m_mouseScrollDelta; - // Accumulates scrolls of less than m_mouseScrollDelta across multiple + // Accumulates scrolls of less than m_?_mouseScrollDelta across multiple // scroll events. We dispatch a scroll event whenever the accumulated scroll - // becomes larger than m_mouseScrollDelta - mutable int m_accumulatedScroll; + // becomes larger than m_?_mouseScrollDelta + mutable int m_x_accumulatedScroll; + mutable int m_y_accumulatedScroll; Display* m_display; Window m_root; -- cgit v1.2.3