Solve low hanging reliability and maintainability issues (#7403)
* Add missing atom ctor init * Init members with `None` * Use in-class init and delcare getter inside if init * Temp revert of changes ahead of unit test repair * Move IPC header to shared, restore X clipboard test, simplify test cmake, new X clipboard unit test * Suppress sonar for undefs * Remove base dir include * Revert "Temp revert of changes ahead of unit test repair" This reverts commit 8f84b6ea5d5828f1be1362de3809279bcacb8cc8. * Use new accessor * Use default dtor * Beef up to 32 core * Use enum class * Make IPC protocol headers const at all levels * Use enum class and const char for better type safety * Use unique_ptr for m_clipboard * Use `-j` instead of `-j8` to utilize full parallelism * Increase thread count for sonar-scanner * Use 32 threads * Use in-class init for IpcClientProxy members * Use const instead of #define * Remove ctor member inits * Use unique_ptr on win * Implement temp bin dir for windows with more robust post-build copy * Fixed missing iostream * Add warning about copy errors * Only run clean-gcda on Linux * Use in-class init for IPC mutex * Do no-op on Windows * Hide clean-gcda task * Move flakey test to integtests * Delete dead code * Test * Temp disable post_config_all * Disable post config step * Revert "Disable post config step" This reverts commit 2f956a7714ba9bedacd4b39d4ae00940c3d565d6. * Revert "Temp disable post_config_all" This reverts commit b44ed72e44f838bfe1309f6e9672d2f1c6f21b75. * Restore -j8 * Simplify error handling * Use const for test port * Remove python check * Update changelog * Fixed order * Fixed bad issue number * Fixed bin copy source path * Remove redundant except
This commit is contained in:
parent
47849db4d9
commit
6399feb324
62 changed files with 814 additions and 698 deletions
5
.github/workflows/sonarcloud-analysis.yml
vendored
5
.github/workflows/sonarcloud-analysis.yml
vendored
|
|
@ -19,7 +19,7 @@ jobs:
|
||||||
sonarcloud-analysis:
|
sonarcloud-analysis:
|
||||||
if: ${{ vars.SONAR_SCANNER_ENABLED }}
|
if: ${{ vars.SONAR_SCANNER_ENABLED }}
|
||||||
|
|
||||||
runs-on: ubuntu-24.04-16-core-x64
|
runs-on: ubuntu-24.04-32-core-x64
|
||||||
container: symless/synergy-core:ubuntu-22.04-amd64
|
container: symless/synergy-core:ubuntu-22.04-amd64
|
||||||
timeout-minutes: 20
|
timeout-minutes: 20
|
||||||
|
|
||||||
|
|
@ -27,6 +27,7 @@ jobs:
|
||||||
SONAR_SCANNER_VERSION: 6.1.0.4477
|
SONAR_SCANNER_VERSION: 6.1.0.4477
|
||||||
SONAR_SCANNER_OPTS: -server
|
SONAR_SCANNER_OPTS: -server
|
||||||
SONAR_SCANNER_URL_BASE: https://binaries.sonarsource.com/Distribution/sonar-scanner-cli
|
SONAR_SCANNER_URL_BASE: https://binaries.sonarsource.com/Distribution/sonar-scanner-cli
|
||||||
|
SONAR_SCANNER_THREADS: 32
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
|
|
@ -83,7 +84,7 @@ jobs:
|
||||||
-Dsonar.cfamily.build-wrapper-output=bw-output \
|
-Dsonar.cfamily.build-wrapper-output=bw-output \
|
||||||
-Dsonar.host.url=https://sonarcloud.io \
|
-Dsonar.host.url=https://sonarcloud.io \
|
||||||
-Dsonar.coverageReportPaths=build/coverage.xml \
|
-Dsonar.coverageReportPaths=build/coverage.xml \
|
||||||
-Dsonar.cfamily.threads=2
|
-Dsonar.cfamily.threads=${{ env.SONAR_SCANNER_THREADS }}
|
||||||
env:
|
env:
|
||||||
SONAR_TOKEN: ${{secrets.SONAR_TOKEN}}
|
SONAR_TOKEN: ${{secrets.SONAR_TOKEN}}
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
|
||||||
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -1,6 +1,5 @@
|
||||||
# temp dirs created during build
|
# temp dirs created during build
|
||||||
/build
|
/build
|
||||||
/bin
|
|
||||||
/dist
|
/dist
|
||||||
/deps
|
/deps
|
||||||
/tmp
|
/tmp
|
||||||
|
|
|
||||||
27
.vscode/tasks.json
vendored
27
.vscode/tasks.json
vendored
|
|
@ -14,9 +14,9 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "cmake",
|
"type": "cmake",
|
||||||
"label": "coverage",
|
"label": "clean",
|
||||||
"command": "build",
|
"command": "build",
|
||||||
"targets": ["coverage"],
|
"targets": ["clean"],
|
||||||
"preset": "${command:cmake.activeBuildPresetName}",
|
"preset": "${command:cmake.activeBuildPresetName}",
|
||||||
"group": "build"
|
"group": "build"
|
||||||
},
|
},
|
||||||
|
|
@ -32,6 +32,17 @@
|
||||||
"command": "${workspaceFolder}/build/bin/synergy",
|
"command": "${workspaceFolder}/build/bin/synergy",
|
||||||
"dependsOn": ["build"]
|
"dependsOn": ["build"]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"label": "clean-gcda",
|
||||||
|
"type": "shell",
|
||||||
|
"command": "find . -name '*.gcda' -delete",
|
||||||
|
"windows": {
|
||||||
|
"command": "$null" // no-op
|
||||||
|
},
|
||||||
|
"presentation": {
|
||||||
|
"reveal": "silent"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"label": "unittests (current)",
|
"label": "unittests (current)",
|
||||||
"type": "shell",
|
"type": "shell",
|
||||||
|
|
@ -42,7 +53,7 @@
|
||||||
"--ignore-return-code",
|
"--ignore-return-code",
|
||||||
"--filter-file=${file}"
|
"--filter-file=${file}"
|
||||||
],
|
],
|
||||||
"dependsOn": ["build"]
|
"dependsOn": ["build", "clean-gcda"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"label": "integtests (current)",
|
"label": "integtests (current)",
|
||||||
|
|
@ -54,21 +65,21 @@
|
||||||
"--ignore-return-code",
|
"--ignore-return-code",
|
||||||
"--filter-file=${file}"
|
"--filter-file=${file}"
|
||||||
],
|
],
|
||||||
"dependsOn": ["build"]
|
"dependsOn": ["build", "clean-gcda"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"label": "unittests (all)",
|
"label": "unittests (all)",
|
||||||
"type": "shell",
|
"type": "shell",
|
||||||
"command": "python",
|
"command": "python",
|
||||||
"args": ["./scripts/tests.py", "--unit-tests", "--ignore-return-code"],
|
"args": ["./scripts/tests.py", "--unit-tests", "--ignore-return-code"],
|
||||||
"dependsOn": ["build"]
|
"dependsOn": ["build", "clean-gcda"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"label": "integtests (all)",
|
"label": "integtests (all)",
|
||||||
"type": "shell",
|
"type": "shell",
|
||||||
"command": "python",
|
"command": "python",
|
||||||
"args": ["./scripts/tests.py", "--integ-tests", "--ignore-return-code"],
|
"args": ["./scripts/tests.py", "--integ-tests", "--ignore-return-code"],
|
||||||
"dependsOn": ["build"]
|
"dependsOn": ["build", "clean-gcda"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"label": "unittests (current, valgrind)",
|
"label": "unittests (current, valgrind)",
|
||||||
|
|
@ -81,7 +92,7 @@
|
||||||
"--filter-file=${file}",
|
"--filter-file=${file}",
|
||||||
"--valgrind"
|
"--valgrind"
|
||||||
],
|
],
|
||||||
"dependsOn": ["build"]
|
"dependsOn": ["build", "clean-gcda"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"label": "integtests (current, valgrind)",
|
"label": "integtests (current, valgrind)",
|
||||||
|
|
@ -94,7 +105,7 @@
|
||||||
"--filter-file=${file}",
|
"--filter-file=${file}",
|
||||||
"--valgrind"
|
"--valgrind"
|
||||||
],
|
],
|
||||||
"dependsOn": ["build"]
|
"dependsOn": ["build", "clean-gcda"]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ project(synergy-core C CXX)
|
||||||
|
|
||||||
include(cmake/Version.cmake)
|
include(cmake/Version.cmake)
|
||||||
include(cmake/Definitions.cmake)
|
include(cmake/Definitions.cmake)
|
||||||
|
include(cmake/Build.cmake)
|
||||||
include(cmake/Libraries.cmake)
|
include(cmake/Libraries.cmake)
|
||||||
include(cmake/Packaging.cmake)
|
include(cmake/Packaging.cmake)
|
||||||
|
|
||||||
|
|
@ -28,3 +29,5 @@ configure_libs()
|
||||||
configure_packaging()
|
configure_packaging()
|
||||||
|
|
||||||
add_subdirectory(src)
|
add_subdirectory(src)
|
||||||
|
|
||||||
|
post_config_all()
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ Enhancements:
|
||||||
- #7326 Restore lpDesktop assignment in Windows daemon
|
- #7326 Restore lpDesktop assignment in Windows daemon
|
||||||
- #7327 Only use Ninja to build on Windows
|
- #7327 Only use Ninja to build on Windows
|
||||||
- #7328 Reset error state before calling Process32Next
|
- #7328 Reset error state before calling Process32Next
|
||||||
- #1177 Split CMake presets into debug and release
|
- #7330 Split CMake presets into debug and release
|
||||||
- #7331 Script to install deps (Windows only for now)
|
- #7331 Script to install deps (Windows only for now)
|
||||||
- #7332 Static link OpenSSL libs in CMake preset for Windows
|
- #7332 Static link OpenSSL libs in CMake preset for Windows
|
||||||
- #7333 Update VS Code config for Windows daemon debugging
|
- #7333 Update VS Code config for Windows daemon debugging
|
||||||
|
|
@ -50,10 +50,11 @@ Enhancements:
|
||||||
- #7380 Add `qt6-qpa-plugins` Qt dependency for Debian
|
- #7380 Add `qt6-qpa-plugins` Qt dependency for Debian
|
||||||
- #7381 Set macOS min version to macOS 12.0
|
- #7381 Set macOS min version to macOS 12.0
|
||||||
- #7382 Re-run `macdeployqt6` to copy missing Qt 6 dependencies
|
- #7382 Re-run `macdeployqt6` to copy missing Qt 6 dependencies
|
||||||
|
- #7383 Solve SonarCloud security hotspots and bugs
|
||||||
- #7384 Run `install_deps.py` script when building containers weekly
|
- #7384 Run `install_deps.py` script when building containers weekly
|
||||||
- #7389 Correct Qt macOS target and drop `Core5Compat` lib
|
- #7389 Correct Qt macOS target and drop `Core5Compat` lib
|
||||||
- #7383 Solve SonarCloud security hotspots and bugs
|
|
||||||
- #7401 Run Valgrind on unit tests in CI to detect memory leaks
|
- #7401 Run Valgrind on unit tests in CI to detect memory leaks
|
||||||
|
- #7403 Solve low hanging reliability and maintainability issues
|
||||||
|
|
||||||
# 1.14.6
|
# 1.14.6
|
||||||
|
|
||||||
|
|
|
||||||
61
cmake/Build.cmake
Normal file
61
cmake/Build.cmake
Normal file
|
|
@ -0,0 +1,61 @@
|
||||||
|
# Synergy -- mouse and keyboard sharing utility
|
||||||
|
# Copyright (C) 2024 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
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
macro(post_config)
|
||||||
|
|
||||||
|
# Build to a temp bin dir on Windows and then copy to the final bin dir
|
||||||
|
# (ignore copy fail). It is neccesary to do this. Since the binary may already
|
||||||
|
# be running and you can't write to a running binary (on Windows). It's common
|
||||||
|
# to use Synergy to develop Synergy (i.e. eating your own dog food immediately
|
||||||
|
# making it).
|
||||||
|
if(WIN32)
|
||||||
|
|
||||||
|
if(NOT target)
|
||||||
|
message(FATAL_ERROR "target not set")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set_target_properties(${target} PROPERTIES RUNTIME_OUTPUT_DIRECTORY
|
||||||
|
${BIN_TEMP_DIR})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
macro(post_config_all)
|
||||||
|
|
||||||
|
# Always try to copy the files to the bin directory after every build, even if
|
||||||
|
# there was nothing to do. This is because the copy may have failed last time
|
||||||
|
# due to the file being in use, and we'll usually want to try again.
|
||||||
|
if(WIN32)
|
||||||
|
|
||||||
|
if(NOT EXISTS ${PYTHON_BIN})
|
||||||
|
message(FATAL_ERROR "Python not found at: ${PYTHON_BIN}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
add_custom_target(
|
||||||
|
run_post_build ALL
|
||||||
|
COMMAND ${PYTHON_BIN} ${CMAKE_SOURCE_DIR}/scripts/fancy_copy.py
|
||||||
|
${BIN_TEMP_DIR} ${CMAKE_BINARY_DIR}/bin --ignore-errors
|
||||||
|
VERBATIM
|
||||||
|
COMMENT "Copying files to bin dir")
|
||||||
|
|
||||||
|
add_dependencies(
|
||||||
|
run_post_build
|
||||||
|
synergy
|
||||||
|
synergyc
|
||||||
|
synergys
|
||||||
|
synergyd)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
endmacro()
|
||||||
|
|
@ -28,6 +28,7 @@ macro(configure_definitions)
|
||||||
|
|
||||||
configure_ninja()
|
configure_ninja()
|
||||||
configure_options()
|
configure_options()
|
||||||
|
configure_python()
|
||||||
|
|
||||||
if("${VERSION_URL}" STREQUAL "")
|
if("${VERSION_URL}" STREQUAL "")
|
||||||
set(VERSION_URL "https://api.symless.com/version?version=v1")
|
set(VERSION_URL "https://api.symless.com/version?version=v1")
|
||||||
|
|
@ -58,17 +59,20 @@ macro(configure_definitions)
|
||||||
add_definitions(-DNDEBUG)
|
add_definitions(-DNDEBUG)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# TODO: find out why we need these, and remove them if we don't
|
# TODO: find out why we need these, and remove them if we don't.
|
||||||
if(COMMAND cmake_policy)
|
if(COMMAND cmake_policy)
|
||||||
cmake_policy(SET CMP0003 NEW)
|
cmake_policy(SET CMP0003 NEW)
|
||||||
cmake_policy(SET CMP0005 NEW)
|
cmake_policy(SET CMP0005 NEW)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# TODO: explain why we're adding headers to sources.
|
||||||
if(${CMAKE_GENERATOR} STREQUAL "Unix Makefiles")
|
if(${CMAKE_GENERATOR} STREQUAL "Unix Makefiles")
|
||||||
set(SYNERGY_ADD_HEADERS FALSE)
|
set(ADD_HEADERS_TO_SOURCES FALSE)
|
||||||
else()
|
else()
|
||||||
set(SYNERGY_ADD_HEADERS TRUE)
|
set(ADD_HEADERS_TO_SOURCES TRUE)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
set(BIN_TEMP_DIR ${CMAKE_BINARY_DIR}/temp/bin)
|
||||||
endmacro()
|
endmacro()
|
||||||
|
|
||||||
macro(configure_ninja)
|
macro(configure_ninja)
|
||||||
|
|
|
||||||
|
|
@ -361,3 +361,11 @@ macro(update_submodules)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
endmacro()
|
endmacro()
|
||||||
|
|
||||||
|
macro(configure_python)
|
||||||
|
if(WIN32)
|
||||||
|
set(PYTHON_BIN "${CMAKE_BINARY_DIR}/python/Scripts/python.exe")
|
||||||
|
else()
|
||||||
|
set(PYTHON_BIN "${CMAKE_BINARY_DIR}/python/bin/python")
|
||||||
|
endif()
|
||||||
|
endmacro()
|
||||||
|
|
|
||||||
41
scripts/fancy_copy.py
Normal file
41
scripts/fancy_copy.py
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import lib.env as env
|
||||||
|
import lib.file_utils as file_utils
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""
|
||||||
|
Cross platform script to copy files and directories.
|
||||||
|
This script was mostly created beause the default `copy` command on Windows is too noisy.
|
||||||
|
If this becomes complex it must be replaced with a library.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# important: load venv before loading modules that install deps.
|
||||||
|
env.ensure_in_venv(__file__)
|
||||||
|
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument("source", help="Source pattern to copy from")
|
||||||
|
parser.add_argument("target", help="Destination pattern to copy to")
|
||||||
|
parser.add_argument(
|
||||||
|
"--ignore-errors", action="store_true", help="Ignore errors when copying"
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--verbose", action="store_true", help="Print more information to the console"
|
||||||
|
)
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
options = file_utils.CopyOptions(args.ignore_errors, args.verbose)
|
||||||
|
|
||||||
|
try:
|
||||||
|
file_utils.copy(args.source, args.target, options)
|
||||||
|
except Exception as e:
|
||||||
|
if not args.ignore_errors:
|
||||||
|
raise e
|
||||||
|
else:
|
||||||
|
print(f"Error: {e}")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
80
scripts/lib/file_utils.py
Normal file
80
scripts/lib/file_utils.py
Normal file
|
|
@ -0,0 +1,80 @@
|
||||||
|
import glob, os, shutil, sys
|
||||||
|
|
||||||
|
import colorama # type: ignore
|
||||||
|
from colorama import Fore # type: ignore
|
||||||
|
|
||||||
|
colorama.init()
|
||||||
|
|
||||||
|
|
||||||
|
class CopyOptions:
|
||||||
|
def __init__(self, ignore_errors, verbose):
|
||||||
|
self.ignore_errors = ignore_errors
|
||||||
|
self.verbose = verbose
|
||||||
|
|
||||||
|
|
||||||
|
class CopyContext:
|
||||||
|
def __init__(self):
|
||||||
|
self.errors = 0
|
||||||
|
self.permission_error = False
|
||||||
|
|
||||||
|
|
||||||
|
def copy(source, target, options):
|
||||||
|
"""Copy files and directories from source to target."""
|
||||||
|
|
||||||
|
context = CopyContext()
|
||||||
|
if options.verbose:
|
||||||
|
print(f"Copying files from {source} to {target}")
|
||||||
|
for match in glob.glob(source):
|
||||||
|
|
||||||
|
if os.path.isfile(match):
|
||||||
|
copy_file(match, target, options, context)
|
||||||
|
elif os.path.isdir(match):
|
||||||
|
copy_dir(match, target, options, context)
|
||||||
|
else:
|
||||||
|
raise RuntimeError(f"Path {match} is not a file or directory")
|
||||||
|
|
||||||
|
if context.errors and options.ignore_errors:
|
||||||
|
print(
|
||||||
|
f"{Fore.YELLOW}WARNING:{Fore.RESET} Ignored {context.errors} copy error(s)"
|
||||||
|
)
|
||||||
|
|
||||||
|
if context.permission_error:
|
||||||
|
print(
|
||||||
|
f"{Fore.BLUE}HINT:{Fore.RESET} A permission error may mean that the file is in use"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def copy_dir(match, target, options, context):
|
||||||
|
if options.verbose:
|
||||||
|
print(f"Copying directory {match} to {target}")
|
||||||
|
|
||||||
|
try:
|
||||||
|
shutil.copytree(match, target, dirs_exist_ok=True)
|
||||||
|
|
||||||
|
except PermissionError as e:
|
||||||
|
context.permission_error = True
|
||||||
|
handle_copy_error(e, options, context)
|
||||||
|
except Exception as e:
|
||||||
|
handle_copy_error(e, options, context)
|
||||||
|
|
||||||
|
|
||||||
|
def copy_file(match, target, options, context):
|
||||||
|
if options.verbose:
|
||||||
|
print(f"Copying file {match} to {target}")
|
||||||
|
|
||||||
|
try:
|
||||||
|
shutil.copy(match, target)
|
||||||
|
except PermissionError as e:
|
||||||
|
context.permission_error = True
|
||||||
|
handle_copy_error(e, options, context)
|
||||||
|
except Exception as e:
|
||||||
|
handle_copy_error(e, options, context)
|
||||||
|
|
||||||
|
|
||||||
|
def handle_copy_error(e, options, context):
|
||||||
|
context.errors += 1
|
||||||
|
|
||||||
|
if not options.ignore_errors:
|
||||||
|
raise e
|
||||||
|
else:
|
||||||
|
print(f"{Fore.YELLOW}WARNING:{Fore.RESET} Copy failed: {e}", file=sys.stderr)
|
||||||
|
|
@ -1,14 +1,13 @@
|
||||||
import os
|
import os, sys, time, subprocess, argparse, glob
|
||||||
import subprocess
|
|
||||||
import sys
|
|
||||||
import argparse
|
|
||||||
import glob
|
|
||||||
import lib.windows as windows
|
import lib.windows as windows
|
||||||
|
import lib.file_utils as file_utils
|
||||||
|
import psutil
|
||||||
|
|
||||||
BIN_NAME = "synergyd"
|
DEFAULT_BIN_NAME = "synergyd"
|
||||||
SOURCE_BIN_DIR = os.path.join("build", "bin")
|
DEFAULT_SOURCE_DIR = os.path.join("build", "temp", "bin")
|
||||||
TARGET_BIN_DIR = "bin"
|
DEFAULT_TARGET_DIR = os.path.join("build", "bin")
|
||||||
SERVICE_NOT_RUNNING_ERROR = 2
|
SERVICE_NOT_RUNNING_ERROR = 2
|
||||||
|
ERROR_ACCESS_VIOLATION = 0xC0000005
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
|
@ -16,10 +15,9 @@ def main():
|
||||||
|
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
parser.add_argument("--pause-on-exit", action="store_true")
|
parser.add_argument("--pause-on-exit", action="store_true")
|
||||||
parser.add_argument("--source-bin-dir", default=SOURCE_BIN_DIR)
|
parser.add_argument("--source-dir", default=DEFAULT_SOURCE_DIR)
|
||||||
parser.add_argument("--target-bin-dir", default=TARGET_BIN_DIR)
|
parser.add_argument("--target-dir", default=DEFAULT_TARGET_DIR)
|
||||||
parser.add_argument("--source-bin-name", default=BIN_NAME)
|
parser.add_argument("--bin-name", default=DEFAULT_BIN_NAME)
|
||||||
parser.add_argument("--target-bin-name", default=BIN_NAME)
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
if not windows.is_admin():
|
if not windows.is_admin():
|
||||||
|
|
@ -28,19 +26,18 @@ def main():
|
||||||
|
|
||||||
try:
|
try:
|
||||||
reinstall(
|
reinstall(
|
||||||
args.source_bin_dir,
|
args.source_dir,
|
||||||
args.target_bin_dir,
|
args.target_dir,
|
||||||
args.source_bin_name,
|
args.bin_name,
|
||||||
args.target_bin_name,
|
|
||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Error: {e}")
|
print(f"Error: {e}", file=sys.stderr)
|
||||||
|
|
||||||
if args.pause_on_exit:
|
if args.pause_on_exit:
|
||||||
input("Press enter to continue...")
|
input("Press enter to continue...")
|
||||||
|
|
||||||
|
|
||||||
def reinstall(source_bin_dir, target_bin_dir, source_bin_name, target_bin_name):
|
def reinstall(source_dir, target_dir, bin_name):
|
||||||
"""Stops the running daemon service, copies files, and reinstalls."""
|
"""Stops the running daemon service, copies files, and reinstalls."""
|
||||||
|
|
||||||
print("Stopping daemon service")
|
print("Stopping daemon service")
|
||||||
|
|
@ -52,43 +49,64 @@ def reinstall(source_bin_dir, target_bin_dir, source_bin_name, target_bin_name):
|
||||||
else:
|
else:
|
||||||
raise e
|
raise e
|
||||||
|
|
||||||
copy_bin_files(source_bin_dir, target_bin_dir, source_bin_name, target_bin_name)
|
source_bin_path = f"{os.path.join(source_dir, bin_name)}.exe"
|
||||||
|
|
||||||
target_bin_file = f"{os.path.join(target_bin_dir, target_bin_name)}.exe"
|
# Wait for Windows to release the file handles after process termination.
|
||||||
|
while is_any_process_running(target_dir):
|
||||||
|
print("Waiting for file handles to release")
|
||||||
|
time.sleep(1)
|
||||||
|
|
||||||
|
options = file_utils.CopyOptions(ignore_errors=True, verbose=False)
|
||||||
|
print(f"Copying files from {source_dir} to {target_dir}")
|
||||||
|
file_utils.copy(f"{source_dir}/*", target_dir, options)
|
||||||
|
|
||||||
print("Removing old daemon service")
|
print("Removing old daemon service")
|
||||||
subprocess.run([target_bin_file, "/uninstall"], shell=True, check=True)
|
try:
|
||||||
|
subprocess.run([source_bin_path, "/uninstall"], shell=True, check=True)
|
||||||
print("Installing daemon service")
|
except subprocess.CalledProcessError as e:
|
||||||
subprocess.run([target_bin_file, "/install"], shell=True, check=True)
|
check_access_violation(e.returncode, source_bin_path)
|
||||||
|
if e.returncode != 0:
|
||||||
|
print(
|
||||||
def copy_bin_files(source_bin_dir, target_bin_dir, source_bin_name, target_bin_name):
|
f"Warning: Uninstall failed, return code: {e.returncode}",
|
||||||
|
file=sys.stderr,
|
||||||
if not os.path.isdir(source_bin_dir):
|
|
||||||
raise RuntimeError(f"Invalid source bin dir: {source_bin_dir}")
|
|
||||||
|
|
||||||
print(f"Persisting dir: {target_bin_dir}")
|
|
||||||
os.makedirs(target_bin_dir, exist_ok=True)
|
|
||||||
|
|
||||||
source_bin_glob = f"{source_bin_name}*"
|
|
||||||
source_files = glob.glob(os.path.join(source_bin_dir, source_bin_glob))
|
|
||||||
|
|
||||||
if not source_files:
|
|
||||||
raise RuntimeError(
|
|
||||||
f"No files found in {source_bin_dir} matching {source_bin_glob}"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
for source_file in source_files:
|
target_bin_path = os.path.join(target_dir, bin_name + ".exe")
|
||||||
base_name = os.path.basename(source_file)
|
|
||||||
base_name = base_name.replace(source_bin_name, target_bin_name)
|
|
||||||
target_file = os.path.join(target_bin_dir, base_name)
|
|
||||||
print(f"Copying {source_file} to {target_file}")
|
|
||||||
# use the copy command; shutil.copy gives us a permission denied error.
|
|
||||||
try:
|
try:
|
||||||
subprocess.run(["copy", source_file, target_file], shell=True, check=True)
|
print("Installing daemon service")
|
||||||
|
subprocess.run([target_bin_path, "/install"], shell=True, check=True)
|
||||||
except subprocess.CalledProcessError as e:
|
except subprocess.CalledProcessError as e:
|
||||||
print(f"Copy failed: {e}")
|
check_access_violation(e.returncode, target_bin_path)
|
||||||
|
if e.returncode != 0:
|
||||||
|
print(f"Warning: Install failed, return code: {e.returncode}")
|
||||||
|
|
||||||
|
|
||||||
|
def check_access_violation(return_code, bin_path):
|
||||||
|
if return_code == ERROR_ACCESS_VIOLATION:
|
||||||
|
print(
|
||||||
|
f"Warning: Process crashed with memory access violation: {bin_path}",
|
||||||
|
file=sys.stderr,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def is_any_process_running(dir):
|
||||||
|
"""Check if there is any running process that contains the given directory."""
|
||||||
|
|
||||||
|
print(f"Checking if any process is running in: {dir}")
|
||||||
|
for proc in psutil.process_iter(attrs=["name", "exe"]):
|
||||||
|
exe = proc.info["exe"]
|
||||||
|
|
||||||
|
if not exe:
|
||||||
|
continue
|
||||||
|
|
||||||
|
try:
|
||||||
|
if dir.lower() in exe.lower():
|
||||||
|
print(f"Process found: {exe}")
|
||||||
|
return True
|
||||||
|
except (psutil.NoSuchProcess, psutil.AccessDenied):
|
||||||
|
pass
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
main()
|
main()
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ endif()
|
||||||
list(APPEND sources ${arch_sources})
|
list(APPEND sources ${arch_sources})
|
||||||
list(APPEND headers ${arch_headers})
|
list(APPEND headers ${arch_headers})
|
||||||
|
|
||||||
if(SYNERGY_ADD_HEADERS)
|
if(ADD_HEADERS_TO_SOURCES)
|
||||||
list(APPEND sources ${headers})
|
list(APPEND sources ${headers})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
@ -69,3 +69,5 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||||
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
||||||
install(TARGETS ${target} DESTINATION bin)
|
install(TARGETS ${target} DESTINATION bin)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
post_config()
|
||||||
|
|
|
||||||
|
|
@ -38,3 +38,5 @@ target_link_libraries(
|
||||||
synlib
|
synlib
|
||||||
shared
|
shared
|
||||||
${libs})
|
${libs})
|
||||||
|
|
||||||
|
post_config()
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ endif()
|
||||||
list(APPEND sources ${arch_sources})
|
list(APPEND sources ${arch_sources})
|
||||||
list(APPEND headers ${arch_headers})
|
list(APPEND headers ${arch_headers})
|
||||||
|
|
||||||
if(SYNERGY_ADD_HEADERS)
|
if(ADD_HEADERS_TO_SOURCES)
|
||||||
list(APPEND sources ${headers})
|
list(APPEND sources ${headers})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
@ -69,3 +69,5 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||||
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
||||||
install(TARGETS ${target} DESTINATION bin)
|
install(TARGETS ${target} DESTINATION bin)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
post_config()
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,20 @@
|
||||||
|
# Synergy -- mouse and keyboard sharing utility
|
||||||
|
# Copyright (C) 2024 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
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
set(target synergy)
|
||||||
|
|
||||||
find_package(
|
find_package(
|
||||||
Qt6
|
Qt6
|
||||||
COMPONENTS Core Widgets Network
|
COMPONENTS Core Widgets Network
|
||||||
|
|
@ -33,7 +50,7 @@ if(WIN32)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_executable(
|
add_executable(
|
||||||
synergy WIN32
|
${target} WIN32
|
||||||
${GUI_SOURCE_FILES}
|
${GUI_SOURCE_FILES}
|
||||||
${GUI_UI_FILES}
|
${GUI_UI_FILES}
|
||||||
${GUI_RC_FILES}
|
${GUI_RC_FILES}
|
||||||
|
|
@ -41,16 +58,16 @@ add_executable(
|
||||||
${QM_FILES})
|
${QM_FILES})
|
||||||
|
|
||||||
include_directories(./src)
|
include_directories(./src)
|
||||||
target_link_libraries(synergy shared)
|
target_link_libraries(${target} shared)
|
||||||
|
|
||||||
target_link_libraries(synergy Qt6::Core Qt6::Widgets Qt6::Network)
|
target_link_libraries(${target} Qt6::Core Qt6::Widgets Qt6::Network)
|
||||||
target_compile_definitions(
|
target_compile_definitions(
|
||||||
synergy PRIVATE -DSYNERGY_VERSION_STAGE="${SYNERGY_VERSION_STAGE}")
|
${target} PRIVATE -DSYNERGY_VERSION_STAGE="${SYNERGY_VERSION_STAGE}")
|
||||||
target_compile_definitions(synergy
|
target_compile_definitions(${target}
|
||||||
PRIVATE -DSYNERGY_REVISION="${SYNERGY_REVISION}")
|
PRIVATE -DSYNERGY_REVISION="${SYNERGY_REVISION}")
|
||||||
|
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
set_target_properties(synergy PROPERTIES LINK_FLAGS "/NODEFAULTLIB:LIBCMT")
|
set_target_properties(${target} PROPERTIES LINK_FLAGS "/NODEFAULTLIB:LIBCMT")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||||
|
|
@ -61,13 +78,13 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||||
set(MACDEPLOYQT_CMD
|
set(MACDEPLOYQT_CMD
|
||||||
"${MACDEPLOYQT_BIN} ${SYNERGY_BUNDLE_APP_DIR} -always-overwrite")
|
"${MACDEPLOYQT_BIN} ${SYNERGY_BUNDLE_APP_DIR} -always-overwrite")
|
||||||
|
|
||||||
install(TARGETS synergy DESTINATION ${SYNERGY_BUNDLE_BINARY_DIR})
|
install(TARGETS ${target} DESTINATION ${SYNERGY_BUNDLE_BINARY_DIR})
|
||||||
install(CODE "MESSAGE (\"Running: ${MACDEPLOYQT_CMD}\")")
|
install(CODE "MESSAGE (\"Running: ${MACDEPLOYQT_CMD}\")")
|
||||||
install(CODE "execute_process(COMMAND ${MACDEPLOYQT_CMD})")
|
install(CODE "execute_process(COMMAND ${MACDEPLOYQT_CMD})")
|
||||||
|
|
||||||
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
||||||
|
|
||||||
install(TARGETS synergy DESTINATION bin)
|
install(TARGETS ${target} DESTINATION bin)
|
||||||
|
|
||||||
elseif(WIN32)
|
elseif(WIN32)
|
||||||
|
|
||||||
|
|
@ -96,7 +113,7 @@ elseif(WIN32)
|
||||||
if(TARGET Qt6::windeployqt)
|
if(TARGET Qt6::windeployqt)
|
||||||
# execute windeployqt in a tmp directory after build
|
# execute windeployqt in a tmp directory after build
|
||||||
add_custom_command(
|
add_custom_command(
|
||||||
TARGET synergy
|
TARGET ${target}
|
||||||
POST_BUILD
|
POST_BUILD
|
||||||
COMMAND set PATH=%PATH%$<SEMICOLON>${qt6_install_prefix}/bin
|
COMMAND set PATH=%PATH%$<SEMICOLON>${qt6_install_prefix}/bin
|
||||||
COMMAND Qt6::windeployqt
|
COMMAND Qt6::windeployqt
|
||||||
|
|
@ -104,3 +121,5 @@ elseif(WIN32)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
post_config()
|
||||||
|
|
|
||||||
|
|
@ -22,8 +22,8 @@
|
||||||
// command line argument to synergy core, determines if the server restarts
|
// command line argument to synergy core, determines if the server restarts
|
||||||
// when switching Windows desktops (e.g. when Windows UAC dialog pops up).
|
// when switching Windows desktops (e.g. when Windows UAC dialog pops up).
|
||||||
// The second, passed as a boolean flag to Synergyd over the IPC inside
|
// The second, passed as a boolean flag to Synergyd over the IPC inside
|
||||||
// kIpcCommandMessage, determines whether Synergy should be started with
|
// IpcMessageType::CommandMessage, determines whether Synergy should be started
|
||||||
// elevated privileges.
|
// with elevated privileges.
|
||||||
//
|
//
|
||||||
// The matrix for these two behaviours is as follows:
|
// The matrix for these two behaviours is as follows:
|
||||||
// SodS Elevate
|
// SodS Elevate
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "IpcReader.h"
|
#include "IpcReader.h"
|
||||||
#include "Ipc.h"
|
#include "shared/Ipc.h"
|
||||||
#include <QByteArray>
|
#include <QByteArray>
|
||||||
#include <QMutex>
|
#include <QMutex>
|
||||||
#include <QTcpSocket>
|
#include <QTcpSocket>
|
||||||
|
|
|
||||||
|
|
@ -31,13 +31,12 @@
|
||||||
#include "AppConfig.h"
|
#include "AppConfig.h"
|
||||||
#include "ClientConnection.h"
|
#include "ClientConnection.h"
|
||||||
#include "ConfigWriter.h"
|
#include "ConfigWriter.h"
|
||||||
#include "Ipc.h"
|
|
||||||
#include "QIpcClient.h"
|
#include "QIpcClient.h"
|
||||||
#include "ServerConfig.h"
|
#include "ServerConfig.h"
|
||||||
#include "ServerConnection.h"
|
#include "ServerConnection.h"
|
||||||
#include "VersionChecker.h"
|
|
||||||
|
|
||||||
#include "TrayIcon.h"
|
#include "TrayIcon.h"
|
||||||
|
#include "VersionChecker.h"
|
||||||
|
#include "shared/Ipc.h"
|
||||||
|
|
||||||
class QAction;
|
class QAction;
|
||||||
class QMenu;
|
class QMenu;
|
||||||
|
|
@ -169,8 +168,7 @@ protected:
|
||||||
bool clientArgs(QStringList &args, QString &app);
|
bool clientArgs(QStringList &args, QString &app);
|
||||||
bool serverArgs(QStringList &args, QString &app);
|
bool serverArgs(QStringList &args, QString &app);
|
||||||
void setStatus(const QString &status);
|
void setStatus(const QString &status);
|
||||||
void
|
void sendIpcMessage(IpcMessageType type, const char *buffer, bool showErrors);
|
||||||
sendIpcMessage(qIpcMessageType type, const char *buffer, bool showErrors);
|
|
||||||
void updateFromLogLine(const QString &line);
|
void updateFromLogLine(const QString &line);
|
||||||
QString getIPAddresses();
|
QString getIPAddresses();
|
||||||
void stopService();
|
void stopService();
|
||||||
|
|
|
||||||
|
|
@ -16,12 +16,13 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "QIpcClient.h"
|
#include "QIpcClient.h"
|
||||||
#include "Ipc.h"
|
|
||||||
#include "IpcReader.h"
|
#include "IpcReader.h"
|
||||||
|
#include "shared/Ipc.h"
|
||||||
|
|
||||||
#include <QDataStream>
|
#include <QDataStream>
|
||||||
#include <QHostAddress>
|
#include <QHostAddress>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
#include <qglobal.h>
|
||||||
|
|
||||||
QIpcClient::QIpcClient(const StreamProvider &streamProvider)
|
QIpcClient::QIpcClient(const StreamProvider &streamProvider)
|
||||||
: m_ReaderStarted(false),
|
: m_ReaderStarted(false),
|
||||||
|
|
@ -61,7 +62,8 @@ void QIpcClient::connectToHost() {
|
||||||
m_Enabled = true;
|
m_Enabled = true;
|
||||||
|
|
||||||
infoMessage("connecting to service...");
|
infoMessage("connecting to service...");
|
||||||
m_Socket->connectToHost(QHostAddress(QHostAddress::LocalHost), IPC_PORT);
|
const auto port = static_cast<quint16>(kIpcPort);
|
||||||
|
m_Socket->connectToHost(QHostAddress(QHostAddress::LocalHost), port);
|
||||||
|
|
||||||
if (!m_ReaderStarted) {
|
if (!m_ReaderStarted) {
|
||||||
m_Reader->start();
|
m_Reader->start();
|
||||||
|
|
@ -105,7 +107,7 @@ void QIpcClient::sendHello() {
|
||||||
stream->writeRawData(kIpcMsgHello, 4);
|
stream->writeRawData(kIpcMsgHello, 4);
|
||||||
|
|
||||||
char typeBuf[1];
|
char typeBuf[1];
|
||||||
typeBuf[0] = kIpcClientGui;
|
typeBuf[0] = static_cast<char>(IpcClientType::GUI);
|
||||||
stream->writeRawData(typeBuf, 1);
|
stream->writeRawData(typeBuf, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
file(GLOB headers "*.h")
|
file(GLOB headers "*.h")
|
||||||
file(GLOB sources "*.cpp")
|
file(GLOB sources "*.cpp")
|
||||||
|
|
||||||
if(SYNERGY_ADD_HEADERS)
|
if(ADD_HEADERS_TO_SOURCES)
|
||||||
list(APPEND sources ${headers})
|
list(APPEND sources ${headers})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
@ -33,7 +33,7 @@ endif()
|
||||||
list(APPEND sources ${arch_sources})
|
list(APPEND sources ${arch_sources})
|
||||||
list(APPEND headers ${arch_headers})
|
list(APPEND headers ${arch_headers})
|
||||||
|
|
||||||
if(SYNERGY_ADD_HEADERS)
|
if(ADD_HEADERS_TO_SOURCES)
|
||||||
list(APPEND sources ${headers})
|
list(APPEND sources ${headers})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
file(GLOB headers "*.h")
|
file(GLOB headers "*.h")
|
||||||
file(GLOB sources "*.cpp")
|
file(GLOB sources "*.cpp")
|
||||||
|
|
||||||
if(SYNERGY_ADD_HEADERS)
|
if(ADD_HEADERS_TO_SOURCES)
|
||||||
list(APPEND sources ${headers})
|
list(APPEND sources ${headers})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -212,40 +212,3 @@ 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
|
|
||||||
}
|
|
||||||
|
|
||||||
void MesssageBoxLogOutputter::open(const char *title) {
|
|
||||||
// do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
void MesssageBoxLogOutputter::close() {
|
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if SYSAPI_WIN32
|
|
||||||
MessageBox(NULL, msg, CLOG->getFilterName(level), MB_OK);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -160,19 +160,3 @@ private:
|
||||||
UInt32 m_maxBufferSize;
|
UInt32 m_maxBufferSize;
|
||||||
Buffer m_buffer;
|
Buffer m_buffer;
|
||||||
};
|
};
|
||||||
|
|
||||||
//! Write log to message box
|
|
||||||
/*!
|
|
||||||
The level for each message is ignored.
|
|
||||||
*/
|
|
||||||
class MesssageBoxLogOutputter : public ILogOutputter {
|
|
||||||
public:
|
|
||||||
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);
|
|
||||||
};
|
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
file(GLOB headers "*.h")
|
file(GLOB headers "*.h")
|
||||||
file(GLOB sources "*.cpp")
|
file(GLOB sources "*.cpp")
|
||||||
|
|
||||||
if(SYNERGY_ADD_HEADERS)
|
if(ADD_HEADERS_TO_SOURCES)
|
||||||
list(APPEND sources ${headers})
|
list(APPEND sources ${headers})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
file(GLOB headers "*.h")
|
file(GLOB headers "*.h")
|
||||||
file(GLOB sources "*.cpp")
|
file(GLOB sources "*.cpp")
|
||||||
|
|
||||||
if(SYNERGY_ADD_HEADERS)
|
if(ADD_HEADERS_TO_SOURCES)
|
||||||
list(APPEND sources ${headers})
|
list(APPEND sources ${headers})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
file(GLOB headers "*.h")
|
file(GLOB headers "*.h")
|
||||||
file(GLOB sources "*.cpp")
|
file(GLOB sources "*.cpp")
|
||||||
|
|
||||||
if(SYNERGY_ADD_HEADERS)
|
if(ADD_HEADERS_TO_SOURCES)
|
||||||
list(APPEND sources ${headers})
|
list(APPEND sources ${headers})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
file(GLOB headers "*.h")
|
file(GLOB headers "*.h")
|
||||||
file(GLOB sources "*.cpp")
|
file(GLOB sources "*.cpp")
|
||||||
|
|
||||||
if(SYNERGY_ADD_HEADERS)
|
if(ADD_HEADERS_TO_SOURCES)
|
||||||
list(APPEND sources ${headers})
|
list(APPEND sources ${headers})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* synergy -- mouse and keyboard sharing utility
|
* synergy -- mouse and keyboard sharing utility
|
||||||
* Copyright (C) 2012-2016 Symless Ltd.
|
* Copyright (C) 2012 Symless Ltd.
|
||||||
* Copyright (C) 2012 Nick Bolton
|
|
||||||
*
|
*
|
||||||
* This package is free software; you can redistribute it and/or
|
* This package is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU General Public License
|
||||||
|
|
@ -18,16 +17,16 @@
|
||||||
|
|
||||||
#include "ipc/IpcClient.h"
|
#include "ipc/IpcClient.h"
|
||||||
#include "base/TMethodEventJob.h"
|
#include "base/TMethodEventJob.h"
|
||||||
#include "ipc/Ipc.h"
|
|
||||||
#include "ipc/IpcMessage.h"
|
#include "ipc/IpcMessage.h"
|
||||||
#include "ipc/IpcServerProxy.h"
|
#include "ipc/IpcServerProxy.h"
|
||||||
|
#include "shared/Ipc.h"
|
||||||
|
|
||||||
//
|
//
|
||||||
// IpcClient
|
// IpcClient
|
||||||
//
|
//
|
||||||
|
|
||||||
IpcClient::IpcClient(IEventQueue *events, SocketMultiplexer *socketMultiplexer)
|
IpcClient::IpcClient(IEventQueue *events, SocketMultiplexer *socketMultiplexer)
|
||||||
: m_serverAddress(NetworkAddress(IPC_HOST, IPC_PORT)),
|
: m_serverAddress(NetworkAddress(kIpcHost, kIpcPort)),
|
||||||
m_socket(events, socketMultiplexer),
|
m_socket(events, socketMultiplexer),
|
||||||
m_server(nullptr),
|
m_server(nullptr),
|
||||||
m_events(events) {
|
m_events(events) {
|
||||||
|
|
@ -36,7 +35,7 @@ IpcClient::IpcClient(IEventQueue *events, SocketMultiplexer *socketMultiplexer)
|
||||||
|
|
||||||
IpcClient::IpcClient(
|
IpcClient::IpcClient(
|
||||||
IEventQueue *events, SocketMultiplexer *socketMultiplexer, int port)
|
IEventQueue *events, SocketMultiplexer *socketMultiplexer, int port)
|
||||||
: m_serverAddress(NetworkAddress(IPC_HOST, port)),
|
: m_serverAddress(NetworkAddress(kIpcHost, port)),
|
||||||
m_socket(events, socketMultiplexer),
|
m_socket(events, socketMultiplexer),
|
||||||
m_server(nullptr),
|
m_server(nullptr),
|
||||||
m_events(events) {
|
m_events(events) {
|
||||||
|
|
@ -81,7 +80,7 @@ void IpcClient::handleConnected(const Event &, void *) {
|
||||||
m_events->forIpcClient().connected(), this, m_server,
|
m_events->forIpcClient().connected(), this, m_server,
|
||||||
Event::kDontFreeData));
|
Event::kDontFreeData));
|
||||||
|
|
||||||
IpcHelloMessage message(kIpcClientNode);
|
IpcHelloMessage message(IpcClientType::Node);
|
||||||
send(message);
|
send(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* synergy -- mouse and keyboard sharing utility
|
* synergy -- mouse and keyboard sharing utility
|
||||||
* Copyright (C) 2012-2016 Symless Ltd.
|
* Copyright (C) 2012 Symless Ltd.
|
||||||
* Copyright (C) 2012 Nick Bolton
|
|
||||||
*
|
*
|
||||||
* This package is free software; you can redistribute it and/or
|
* This package is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU General Public License
|
||||||
|
|
@ -18,13 +17,12 @@
|
||||||
|
|
||||||
#include "ipc/IpcClientProxy.h"
|
#include "ipc/IpcClientProxy.h"
|
||||||
|
|
||||||
#include "arch/Arch.h"
|
|
||||||
#include "base/Log.h"
|
#include "base/Log.h"
|
||||||
#include "base/TMethodEventJob.h"
|
#include "base/TMethodEventJob.h"
|
||||||
#include "io/IStream.h"
|
#include "io/IStream.h"
|
||||||
#include "ipc/Ipc.h"
|
|
||||||
#include "ipc/IpcMessage.h"
|
#include "ipc/IpcMessage.h"
|
||||||
#include "ipc/IpcSettingMessage.h"
|
#include "ipc/IpcSettingMessage.h"
|
||||||
|
#include "shared/Ipc.h"
|
||||||
#include "synergy/ProtocolUtil.h"
|
#include "synergy/ProtocolUtil.h"
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
@ -33,10 +31,6 @@
|
||||||
|
|
||||||
IpcClientProxy::IpcClientProxy(synergy::IStream &stream, IEventQueue *events)
|
IpcClientProxy::IpcClientProxy(synergy::IStream &stream, IEventQueue *events)
|
||||||
: m_stream(stream),
|
: m_stream(stream),
|
||||||
m_clientType(kIpcClientUnknown),
|
|
||||||
m_disconnecting(false),
|
|
||||||
m_readMutex(ARCH->newMutex()),
|
|
||||||
m_writeMutex(ARCH->newMutex()),
|
|
||||||
m_events(events) {
|
m_events(events) {
|
||||||
m_events->adoptHandler(
|
m_events->adoptHandler(
|
||||||
m_events->forIStream().inputReady(), stream.getEventTarget(),
|
m_events->forIStream().inputReady(), stream.getEventTarget(),
|
||||||
|
|
@ -135,7 +129,7 @@ void IpcClientProxy::send(const IpcMessage &message) {
|
||||||
LOG((CLOG_DEBUG4 "ipc write: %d", message.type()));
|
LOG((CLOG_DEBUG4 "ipc write: %d", message.type()));
|
||||||
|
|
||||||
switch (message.type()) {
|
switch (message.type()) {
|
||||||
case kIpcLogLine: {
|
case IpcMessageType::LogLine: {
|
||||||
const IpcLogLineMessage &llm =
|
const IpcLogLineMessage &llm =
|
||||||
static_cast<const IpcLogLineMessage &>(message);
|
static_cast<const IpcLogLineMessage &>(message);
|
||||||
const String logLine = llm.logLine();
|
const String logLine = llm.logLine();
|
||||||
|
|
@ -143,11 +137,11 @@ void IpcClientProxy::send(const IpcMessage &message) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case kIpcShutdown:
|
case IpcMessageType::Shutdown:
|
||||||
ProtocolUtil::writef(&m_stream, kIpcMsgShutdown);
|
ProtocolUtil::writef(&m_stream, kIpcMsgShutdown);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case kIpcHelloBack:
|
case IpcMessageType::HelloBack:
|
||||||
ProtocolUtil::writef(&m_stream, kIpcMsgHelloBack);
|
ProtocolUtil::writef(&m_stream, kIpcMsgHelloBack);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
@ -161,7 +155,7 @@ IpcHelloMessage *IpcClientProxy::parseHello() {
|
||||||
UInt8 type;
|
UInt8 type;
|
||||||
ProtocolUtil::readf(&m_stream, kIpcMsgHello + 4, &type);
|
ProtocolUtil::readf(&m_stream, kIpcMsgHello + 4, &type);
|
||||||
|
|
||||||
m_clientType = static_cast<EIpcClientType>(type);
|
m_clientType = static_cast<IpcClientType>(type);
|
||||||
|
|
||||||
// must be deleted by event handler.
|
// must be deleted by event handler.
|
||||||
return new IpcHelloMessage(m_clientType);
|
return new IpcHelloMessage(m_clientType);
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* synergy -- mouse and keyboard sharing utility
|
* synergy -- mouse and keyboard sharing utility
|
||||||
* Copyright (C) 2012-2016 Symless Ltd.
|
* Copyright (C) 2012 Symless Ltd.
|
||||||
* Copyright (C) 2012 Nick Bolton
|
|
||||||
*
|
*
|
||||||
* This package is free software; you can redistribute it and/or
|
* This package is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU General Public License
|
||||||
|
|
@ -18,10 +17,11 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "arch/Arch.h"
|
||||||
#include "arch/IArchMultithread.h"
|
#include "arch/IArchMultithread.h"
|
||||||
#include "base/Event.h"
|
#include "base/Event.h"
|
||||||
#include "base/EventTypes.h"
|
#include "base/EventTypes.h"
|
||||||
#include "ipc/Ipc.h"
|
#include "shared/Ipc.h"
|
||||||
|
|
||||||
namespace synergy {
|
namespace synergy {
|
||||||
class IStream;
|
class IStream;
|
||||||
|
|
@ -56,9 +56,9 @@ private:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
synergy::IStream &m_stream;
|
synergy::IStream &m_stream;
|
||||||
EIpcClientType m_clientType;
|
|
||||||
bool m_disconnecting;
|
|
||||||
ArchMutex m_readMutex;
|
|
||||||
ArchMutex m_writeMutex;
|
|
||||||
IEventQueue *m_events;
|
IEventQueue *m_events;
|
||||||
|
IpcClientType m_clientType = IpcClientType::Unknown;
|
||||||
|
bool m_disconnecting = false;
|
||||||
|
ArchMutex m_readMutex = ARCH->newMutex();
|
||||||
|
ArchMutex m_writeMutex = ARCH->newMutex();
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -24,11 +24,11 @@
|
||||||
#include "base/EventQueue.h"
|
#include "base/EventQueue.h"
|
||||||
#include "base/TMethodEventJob.h"
|
#include "base/TMethodEventJob.h"
|
||||||
#include "base/TMethodJob.h"
|
#include "base/TMethodJob.h"
|
||||||
#include "ipc/Ipc.h"
|
|
||||||
#include "ipc/IpcClientProxy.h"
|
#include "ipc/IpcClientProxy.h"
|
||||||
#include "ipc/IpcMessage.h"
|
#include "ipc/IpcMessage.h"
|
||||||
#include "ipc/IpcServer.h"
|
#include "ipc/IpcServer.h"
|
||||||
#include "mt/Thread.h"
|
#include "mt/Thread.h"
|
||||||
|
#include "shared/Ipc.h"
|
||||||
|
|
||||||
enum EIpcLogOutputter {
|
enum EIpcLogOutputter {
|
||||||
kBufferMaxSize = 1000,
|
kBufferMaxSize = 1000,
|
||||||
|
|
@ -38,7 +38,7 @@ enum EIpcLogOutputter {
|
||||||
};
|
};
|
||||||
|
|
||||||
IpcLogOutputter::IpcLogOutputter(
|
IpcLogOutputter::IpcLogOutputter(
|
||||||
IpcServer &ipcServer, EIpcClientType clientType, bool useThread)
|
IpcServer &ipcServer, IpcClientType clientType, bool useThread)
|
||||||
: m_ipcServer(ipcServer),
|
: m_ipcServer(ipcServer),
|
||||||
m_bufferMutex(ARCH->newMutex()),
|
m_bufferMutex(ARCH->newMutex()),
|
||||||
m_sending(false),
|
m_sending(false),
|
||||||
|
|
@ -179,7 +179,7 @@ void IpcLogOutputter::sendBuffer() {
|
||||||
|
|
||||||
IpcLogLineMessage message(getChunk(kMaxSendLines));
|
IpcLogLineMessage message(getChunk(kMaxSendLines));
|
||||||
m_sending = true;
|
m_sending = true;
|
||||||
m_ipcServer.send(message, kIpcClientGui);
|
m_ipcServer.send(message, IpcClientType::GUI);
|
||||||
m_sending = false;
|
m_sending = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@
|
||||||
#include "arch/Arch.h"
|
#include "arch/Arch.h"
|
||||||
#include "arch/IArchMultithread.h"
|
#include "arch/IArchMultithread.h"
|
||||||
#include "base/ILogOutputter.h"
|
#include "base/ILogOutputter.h"
|
||||||
#include "ipc/Ipc.h"
|
#include "shared/Ipc.h"
|
||||||
|
|
||||||
#include <deque>
|
#include <deque>
|
||||||
|
|
||||||
|
|
@ -41,7 +41,7 @@ public:
|
||||||
using the \c sendBuffer() function.
|
using the \c sendBuffer() function.
|
||||||
*/
|
*/
|
||||||
IpcLogOutputter(
|
IpcLogOutputter(
|
||||||
IpcServer &ipcServer, EIpcClientType clientType, bool useThread);
|
IpcServer &ipcServer, IpcClientType clientType, bool useThread);
|
||||||
IpcLogOutputter(IpcLogOutputter const &) = delete;
|
IpcLogOutputter(IpcLogOutputter const &) = delete;
|
||||||
virtual ~IpcLogOutputter();
|
virtual ~IpcLogOutputter();
|
||||||
|
|
||||||
|
|
@ -115,6 +115,6 @@ private:
|
||||||
double m_bufferRateTimeLimit;
|
double m_bufferRateTimeLimit;
|
||||||
UInt16 m_bufferWriteCount;
|
UInt16 m_bufferWriteCount;
|
||||||
double m_bufferRateStart;
|
double m_bufferRateStart;
|
||||||
EIpcClientType m_clientType;
|
IpcClientType m_clientType;
|
||||||
ArchMutex m_runningMutex;
|
ArchMutex m_runningMutex;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -17,35 +17,25 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "ipc/IpcMessage.h"
|
#include "ipc/IpcMessage.h"
|
||||||
#include "ipc/Ipc.h"
|
#include "shared/Ipc.h"
|
||||||
|
|
||||||
IpcMessage::IpcMessage(UInt8 type) : m_type(type) {}
|
IpcMessage::IpcMessage(IpcMessageType type) : m_type(type) {}
|
||||||
|
|
||||||
IpcMessage::~IpcMessage() {}
|
IpcHelloMessage::IpcHelloMessage(IpcClientType clientType)
|
||||||
|
: IpcMessage(IpcMessageType::Hello),
|
||||||
IpcHelloMessage::IpcHelloMessage(EIpcClientType clientType)
|
|
||||||
: IpcMessage(kIpcHello),
|
|
||||||
m_clientType(clientType) {}
|
m_clientType(clientType) {}
|
||||||
|
|
||||||
IpcHelloMessage::~IpcHelloMessage() {}
|
IpcHelloBackMessage::IpcHelloBackMessage()
|
||||||
|
: IpcMessage(IpcMessageType::HelloBack) {}
|
||||||
|
|
||||||
IpcHelloBackMessage::IpcHelloBackMessage() : IpcMessage(kIpcHelloBack) {}
|
IpcShutdownMessage::IpcShutdownMessage()
|
||||||
|
: IpcMessage(IpcMessageType::Shutdown) {}
|
||||||
IpcHelloBackMessage::~IpcHelloBackMessage() {}
|
|
||||||
|
|
||||||
IpcShutdownMessage::IpcShutdownMessage() : IpcMessage(kIpcShutdown) {}
|
|
||||||
|
|
||||||
IpcShutdownMessage::~IpcShutdownMessage() {}
|
|
||||||
|
|
||||||
IpcLogLineMessage::IpcLogLineMessage(const String &logLine)
|
IpcLogLineMessage::IpcLogLineMessage(const String &logLine)
|
||||||
: IpcMessage(kIpcLogLine),
|
: IpcMessage(IpcMessageType::LogLine),
|
||||||
m_logLine(logLine) {}
|
m_logLine(logLine) {}
|
||||||
|
|
||||||
IpcLogLineMessage::~IpcLogLineMessage() {}
|
|
||||||
|
|
||||||
IpcCommandMessage::IpcCommandMessage(const String &command, bool elevate)
|
IpcCommandMessage::IpcCommandMessage(const String &command, bool elevate)
|
||||||
: IpcMessage(kIpcCommand),
|
: IpcMessage(IpcMessageType::Command),
|
||||||
m_command(command),
|
m_command(command),
|
||||||
m_elevate(elevate) {}
|
m_elevate(elevate) {}
|
||||||
|
|
||||||
IpcCommandMessage::~IpcCommandMessage() {}
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* synergy -- mouse and keyboard sharing utility
|
* synergy -- mouse and keyboard sharing utility
|
||||||
* Copyright (C) 2012-2016 Symless Ltd.
|
* Copyright (C) 2012 Symless Ltd.
|
||||||
* Copyright (C) 2012 Nick Bolton
|
|
||||||
*
|
*
|
||||||
* This package is free software; you can redistribute it and/or
|
* This package is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU General Public License
|
||||||
|
|
@ -19,52 +18,51 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "base/Event.h"
|
#include "base/Event.h"
|
||||||
#include "base/EventTypes.h"
|
|
||||||
#include "base/String.h"
|
#include "base/String.h"
|
||||||
#include "ipc/Ipc.h"
|
#include "shared/Ipc.h"
|
||||||
|
|
||||||
class IpcMessage : public EventData {
|
class IpcMessage : public EventData {
|
||||||
public:
|
public:
|
||||||
virtual ~IpcMessage();
|
~IpcMessage() override = default;
|
||||||
|
|
||||||
//! Gets the message type ID.
|
//! Gets the message type ID.
|
||||||
UInt8 type() const { return m_type; }
|
IpcMessageType type() const { return m_type; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
IpcMessage(UInt8 type);
|
explicit IpcMessage(IpcMessageType type);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
UInt8 m_type;
|
IpcMessageType m_type;
|
||||||
};
|
};
|
||||||
|
|
||||||
class IpcHelloMessage : public IpcMessage {
|
class IpcHelloMessage : public IpcMessage {
|
||||||
public:
|
public:
|
||||||
IpcHelloMessage(EIpcClientType clientType);
|
explicit IpcHelloMessage(IpcClientType clientType);
|
||||||
virtual ~IpcHelloMessage();
|
~IpcHelloMessage() override = default;
|
||||||
|
|
||||||
//! Gets the message type ID.
|
//! Gets the message type ID.
|
||||||
EIpcClientType clientType() const { return m_clientType; }
|
IpcClientType clientType() const { return m_clientType; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
EIpcClientType m_clientType;
|
IpcClientType m_clientType;
|
||||||
};
|
};
|
||||||
|
|
||||||
class IpcHelloBackMessage : public IpcMessage {
|
class IpcHelloBackMessage : public IpcMessage {
|
||||||
public:
|
public:
|
||||||
IpcHelloBackMessage();
|
explicit IpcHelloBackMessage();
|
||||||
virtual ~IpcHelloBackMessage();
|
~IpcHelloBackMessage() override = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
class IpcShutdownMessage : public IpcMessage {
|
class IpcShutdownMessage : public IpcMessage {
|
||||||
public:
|
public:
|
||||||
IpcShutdownMessage();
|
explicit IpcShutdownMessage();
|
||||||
virtual ~IpcShutdownMessage();
|
~IpcShutdownMessage() override = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
class IpcLogLineMessage : public IpcMessage {
|
class IpcLogLineMessage : public IpcMessage {
|
||||||
public:
|
public:
|
||||||
IpcLogLineMessage(const String &logLine);
|
explicit IpcLogLineMessage(const String &logLine);
|
||||||
virtual ~IpcLogLineMessage();
|
~IpcLogLineMessage() override = default;
|
||||||
|
|
||||||
//! Gets the log line.
|
//! Gets the log line.
|
||||||
String logLine() const { return m_logLine; }
|
String logLine() const { return m_logLine; }
|
||||||
|
|
@ -75,8 +73,8 @@ private:
|
||||||
|
|
||||||
class IpcCommandMessage : public IpcMessage {
|
class IpcCommandMessage : public IpcMessage {
|
||||||
public:
|
public:
|
||||||
IpcCommandMessage(const String &command, bool elevate);
|
explicit IpcCommandMessage(const String &command, bool elevate);
|
||||||
virtual ~IpcCommandMessage();
|
~IpcCommandMessage() override = default;
|
||||||
|
|
||||||
//! Gets the command.
|
//! Gets the command.
|
||||||
String command() const { return m_command; }
|
String command() const { return m_command; }
|
||||||
|
|
|
||||||
|
|
@ -23,10 +23,10 @@
|
||||||
#include "base/Log.h"
|
#include "base/Log.h"
|
||||||
#include "base/TMethodEventJob.h"
|
#include "base/TMethodEventJob.h"
|
||||||
#include "io/IStream.h"
|
#include "io/IStream.h"
|
||||||
#include "ipc/Ipc.h"
|
|
||||||
#include "ipc/IpcClientProxy.h"
|
#include "ipc/IpcClientProxy.h"
|
||||||
#include "ipc/IpcMessage.h"
|
#include "ipc/IpcMessage.h"
|
||||||
#include "net/IDataSocket.h"
|
#include "net/IDataSocket.h"
|
||||||
|
#include "shared/Ipc.h"
|
||||||
|
|
||||||
//
|
//
|
||||||
// IpcServer
|
// IpcServer
|
||||||
|
|
@ -37,7 +37,7 @@ IpcServer::IpcServer(IEventQueue *events, SocketMultiplexer *socketMultiplexer)
|
||||||
m_events(events),
|
m_events(events),
|
||||||
m_socketMultiplexer(socketMultiplexer),
|
m_socketMultiplexer(socketMultiplexer),
|
||||||
m_socket(nullptr),
|
m_socket(nullptr),
|
||||||
m_address(NetworkAddress(IPC_HOST, IPC_PORT)) {
|
m_address(NetworkAddress(kIpcHost, kIpcPort)) {
|
||||||
init();
|
init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -46,7 +46,7 @@ IpcServer::IpcServer(
|
||||||
: m_mock(false),
|
: m_mock(false),
|
||||||
m_events(events),
|
m_events(events),
|
||||||
m_socketMultiplexer(socketMultiplexer),
|
m_socketMultiplexer(socketMultiplexer),
|
||||||
m_address(NetworkAddress(IPC_HOST, port)) {
|
m_address(NetworkAddress(kIpcHost, port)) {
|
||||||
init();
|
init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -135,7 +135,7 @@ void IpcServer::deleteClient(IpcClientProxy *proxy) {
|
||||||
delete proxy;
|
delete proxy;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IpcServer::hasClients(EIpcClientType clientType) const {
|
bool IpcServer::hasClients(IpcClientType clientType) const {
|
||||||
ArchMutexLock lock(m_clientsMutex);
|
ArchMutexLock lock(m_clientsMutex);
|
||||||
|
|
||||||
if (m_clients.empty()) {
|
if (m_clients.empty()) {
|
||||||
|
|
@ -155,7 +155,7 @@ bool IpcServer::hasClients(EIpcClientType clientType) const {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void IpcServer::send(const IpcMessage &message, EIpcClientType filterType) {
|
void IpcServer::send(const IpcMessage &message, IpcClientType filterType) {
|
||||||
ArchMutexLock lock(m_clientsMutex);
|
ArchMutexLock lock(m_clientsMutex);
|
||||||
|
|
||||||
ClientList::iterator it;
|
ClientList::iterator it;
|
||||||
|
|
|
||||||
|
|
@ -20,9 +20,9 @@
|
||||||
|
|
||||||
#include "arch/Arch.h"
|
#include "arch/Arch.h"
|
||||||
#include "base/EventTypes.h"
|
#include "base/EventTypes.h"
|
||||||
#include "ipc/Ipc.h"
|
|
||||||
#include "net/NetworkAddress.h"
|
#include "net/NetworkAddress.h"
|
||||||
#include "net/TCPListenSocket.h"
|
#include "net/TCPListenSocket.h"
|
||||||
|
#include "shared/Ipc.h"
|
||||||
|
|
||||||
#include <list>
|
#include <list>
|
||||||
|
|
||||||
|
|
@ -58,14 +58,14 @@ public:
|
||||||
virtual void listen();
|
virtual void listen();
|
||||||
|
|
||||||
//! Send a message to all clients matching the filter type.
|
//! Send a message to all clients matching the filter type.
|
||||||
virtual void send(const IpcMessage &message, EIpcClientType filterType);
|
virtual void send(const IpcMessage &message, IpcClientType filterType);
|
||||||
|
|
||||||
//@}
|
//@}
|
||||||
//! @name accessors
|
//! @name accessors
|
||||||
//@{
|
//@{
|
||||||
|
|
||||||
//! Returns true when there are clients of the specified type connected.
|
//! Returns true when there are clients of the specified type connected.
|
||||||
virtual bool hasClients(EIpcClientType clientType) const;
|
virtual bool hasClients(IpcClientType clientType) const;
|
||||||
|
|
||||||
//@}
|
//@}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,8 +21,8 @@
|
||||||
#include "base/Log.h"
|
#include "base/Log.h"
|
||||||
#include "base/TMethodEventJob.h"
|
#include "base/TMethodEventJob.h"
|
||||||
#include "io/IStream.h"
|
#include "io/IStream.h"
|
||||||
#include "ipc/Ipc.h"
|
|
||||||
#include "ipc/IpcMessage.h"
|
#include "ipc/IpcMessage.h"
|
||||||
|
#include "shared/Ipc.h"
|
||||||
#include "synergy/ProtocolUtil.h"
|
#include "synergy/ProtocolUtil.h"
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
@ -78,13 +78,13 @@ void IpcServerProxy::send(const IpcMessage &message) {
|
||||||
LOG((CLOG_DEBUG4 "ipc write: %d", message.type()));
|
LOG((CLOG_DEBUG4 "ipc write: %d", message.type()));
|
||||||
|
|
||||||
switch (message.type()) {
|
switch (message.type()) {
|
||||||
case kIpcHello: {
|
case IpcMessageType::Hello: {
|
||||||
const IpcHelloMessage &hm = static_cast<const IpcHelloMessage &>(message);
|
const IpcHelloMessage &hm = static_cast<const IpcHelloMessage &>(message);
|
||||||
ProtocolUtil::writef(&m_stream, kIpcMsgHello, hm.clientType());
|
ProtocolUtil::writef(&m_stream, kIpcMsgHello, hm.clientType());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case kIpcCommand: {
|
case IpcMessageType::Command: {
|
||||||
const IpcCommandMessage &cm =
|
const IpcCommandMessage &cm =
|
||||||
static_cast<const IpcCommandMessage &>(message);
|
static_cast<const IpcCommandMessage &>(message);
|
||||||
const String command = cm.command();
|
const String command = cm.command();
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@
|
||||||
|
|
||||||
IpcSettingMessage::IpcSettingMessage(
|
IpcSettingMessage::IpcSettingMessage(
|
||||||
const std::string &name, const std::string &value)
|
const std::string &name, const std::string &value)
|
||||||
: IpcMessage(kIpcSetting),
|
: IpcMessage(IpcMessageType::Setting),
|
||||||
m_name(name),
|
m_name(name),
|
||||||
m_value(value) {}
|
m_value(value) {}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
file(GLOB headers "*.h")
|
file(GLOB headers "*.h")
|
||||||
file(GLOB sources "*.cpp")
|
file(GLOB sources "*.cpp")
|
||||||
|
|
||||||
if(SYNERGY_ADD_HEADERS)
|
if(ADD_HEADERS_TO_SOURCES)
|
||||||
list(APPEND sources ${headers})
|
list(APPEND sources ${headers})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
file(GLOB headers "*.h" "InverseSockets/*.h")
|
file(GLOB headers "*.h" "InverseSockets/*.h")
|
||||||
file(GLOB sources "*.cpp" "InverseSockets/*.cpp")
|
file(GLOB sources "*.cpp" "InverseSockets/*.cpp")
|
||||||
|
|
||||||
if(SYNERGY_ADD_HEADERS)
|
if(ADD_HEADERS_TO_SOURCES)
|
||||||
list(APPEND sources ${headers})
|
list(APPEND sources ${headers})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ elseif(UNIX)
|
||||||
file(GLOB sources "XWindows*.cpp")
|
file(GLOB sources "XWindows*.cpp")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(SYNERGY_ADD_HEADERS)
|
if(ADD_HEADERS_TO_SOURCES)
|
||||||
list(APPEND sources ${headers})
|
list(APPEND sources ${headers})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,11 +23,11 @@
|
||||||
#include "base/Log.h"
|
#include "base/Log.h"
|
||||||
#include "base/TMethodJob.h"
|
#include "base/TMethodJob.h"
|
||||||
#include "base/log_outputters.h"
|
#include "base/log_outputters.h"
|
||||||
#include "ipc/Ipc.h"
|
|
||||||
#include "ipc/IpcLogOutputter.h"
|
#include "ipc/IpcLogOutputter.h"
|
||||||
#include "ipc/IpcMessage.h"
|
#include "ipc/IpcMessage.h"
|
||||||
#include "ipc/IpcServer.h"
|
#include "ipc/IpcServer.h"
|
||||||
#include "mt/Thread.h"
|
#include "mt/Thread.h"
|
||||||
|
#include "shared/Ipc.h"
|
||||||
#include "synergy/App.h"
|
#include "synergy/App.h"
|
||||||
#include "synergy/ArgsBase.h"
|
#include "synergy/ArgsBase.h"
|
||||||
|
|
||||||
|
|
@ -510,7 +510,7 @@ void MSWindowsWatchdog::shutdownProcess(HANDLE handle, DWORD pid, int timeout) {
|
||||||
}
|
}
|
||||||
|
|
||||||
IpcShutdownMessage shutdown;
|
IpcShutdownMessage shutdown;
|
||||||
m_ipcServer.send(shutdown, kIpcClientNode);
|
m_ipcServer.send(shutdown, IpcClientType::Node);
|
||||||
|
|
||||||
// wait for process to exit gracefully.
|
// wait for process to exit gracefully.
|
||||||
double start = ARCH->time();
|
double start = ARCH->time();
|
||||||
|
|
|
||||||
|
|
@ -21,8 +21,8 @@
|
||||||
#include "arch/Arch.h"
|
#include "arch/Arch.h"
|
||||||
#include "base/Log.h"
|
#include "base/Log.h"
|
||||||
#include "base/Stopwatch.h"
|
#include "base/Stopwatch.h"
|
||||||
|
#include "common/basic_types.h"
|
||||||
#include "common/stdvector.h"
|
#include "common/stdvector.h"
|
||||||
#include "mt/Thread.h"
|
|
||||||
#include "platform/XWindowsClipboardBMPConverter.h"
|
#include "platform/XWindowsClipboardBMPConverter.h"
|
||||||
#include "platform/XWindowsClipboardHTMLConverter.h"
|
#include "platform/XWindowsClipboardHTMLConverter.h"
|
||||||
#include "platform/XWindowsClipboardTextConverter.h"
|
#include "platform/XWindowsClipboardTextConverter.h"
|
||||||
|
|
@ -534,13 +534,13 @@ bool XWindowsClipboard::icccmGetSelection(
|
||||||
assert(data != nullptr);
|
assert(data != nullptr);
|
||||||
|
|
||||||
// request data conversion
|
// request data conversion
|
||||||
CICCCMGetClipboard getter(m_window, m_time, m_atomData);
|
if (CICCCMGetClipboard getter(m_window, m_time, m_atomData);
|
||||||
if (!getter.readClipboard(
|
!getter.readClipboard(
|
||||||
m_display, m_selection, target, actualTarget, data)) {
|
m_display, m_selection, target, actualTarget, data)) {
|
||||||
LOG(
|
LOG(
|
||||||
(CLOG_DEBUG1 "can't get data for selection target %s",
|
(CLOG_DEBUG1 "can't get data for selection target %s",
|
||||||
XWindowsUtil::atomToString(m_display, target).c_str()));
|
XWindowsUtil::atomToString(m_display, target).c_str()));
|
||||||
LOGC(getter.m_error, (CLOG_WARN "icccm violation by clipboard owner"));
|
LOGC(getter.error(), (CLOG_WARN "icccm violation by clipboard owner"));
|
||||||
return false;
|
return false;
|
||||||
} else if (*actualTarget == None) {
|
} else if (*actualTarget == None) {
|
||||||
LOG(
|
LOG(
|
||||||
|
|
@ -630,7 +630,7 @@ bool XWindowsClipboard::motifOwnsClipboard() const {
|
||||||
if (data.size() >= sizeof(MotifClipHeader)) {
|
if (data.size() >= sizeof(MotifClipHeader)) {
|
||||||
MotifClipHeader header;
|
MotifClipHeader header;
|
||||||
std::memcpy(&header, data.data(), sizeof(header));
|
std::memcpy(&header, data.data(), sizeof(header));
|
||||||
if ((header.m_id == kMotifClipHeader) &&
|
if ((header.m_id == MotifClip::Header) &&
|
||||||
(static_cast<Window>(header.m_selectionOwner) == owner)) {
|
(static_cast<Window>(header.m_selectionOwner) == owner)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -658,7 +658,7 @@ void XWindowsClipboard::motifFillCache() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
std::memcpy(&header, data.data(), sizeof(header));
|
std::memcpy(&header, data.data(), sizeof(header));
|
||||||
if (header.m_id != kMotifClipHeader || header.m_numItems < 1) {
|
if (header.m_id != MotifClip::Header || header.m_numItems < 1) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -678,7 +678,7 @@ void XWindowsClipboard::motifFillCache() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
std::memcpy(&item, data.data(), sizeof(item));
|
std::memcpy(&item, data.data(), sizeof(item));
|
||||||
if (item.m_id != kMotifClipItem ||
|
if (item.m_id != MotifClip::Item ||
|
||||||
item.m_numFormats - item.m_numDeletedFormats < 1) {
|
item.m_numFormats - item.m_numDeletedFormats < 1) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -707,7 +707,7 @@ void XWindowsClipboard::motifFillCache() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
std::memcpy(&motifFormat, data.data(), sizeof(motifFormat));
|
std::memcpy(&motifFormat, data.data(), sizeof(motifFormat));
|
||||||
if (motifFormat.m_id != kMotifClipFormat || motifFormat.m_length < 0 ||
|
if (motifFormat.m_id != MotifClip::Format || motifFormat.m_length < 0 ||
|
||||||
motifFormat.m_type == None || motifFormat.m_deleted != 0) {
|
motifFormat.m_type == None || motifFormat.m_deleted != 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
@ -1197,18 +1197,7 @@ XWindowsClipboard::CICCCMGetClipboard::CICCCMGetClipboard(
|
||||||
Window requestor, Time time, Atom property)
|
Window requestor, Time time, Atom property)
|
||||||
: m_requestor(requestor),
|
: m_requestor(requestor),
|
||||||
m_time(time),
|
m_time(time),
|
||||||
m_property(property),
|
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
|
|
||||||
}
|
|
||||||
|
|
||||||
bool XWindowsClipboard::CICCCMGetClipboard::readClipboard(
|
bool XWindowsClipboard::CICCCMGetClipboard::readClipboard(
|
||||||
Display *display, Atom selection, Atom target, Atom *actualTarget,
|
Display *display, Atom selection, Atom target, Atom *actualTarget,
|
||||||
|
|
|
||||||
|
|
@ -132,6 +132,7 @@ private:
|
||||||
void fillCache() const;
|
void fillCache() const;
|
||||||
void doFillCache();
|
void doFillCache();
|
||||||
|
|
||||||
|
protected:
|
||||||
//
|
//
|
||||||
// helper classes
|
// helper classes
|
||||||
//
|
//
|
||||||
|
|
@ -140,7 +141,7 @@ private:
|
||||||
class CICCCMGetClipboard {
|
class CICCCMGetClipboard {
|
||||||
public:
|
public:
|
||||||
CICCCMGetClipboard(Window requestor, Time time, Atom property);
|
CICCCMGetClipboard(Window requestor, Time time, Atom property);
|
||||||
~CICCCMGetClipboard();
|
~CICCCMGetClipboard() = default;
|
||||||
|
|
||||||
// convert the given selection to the given type. returns
|
// convert the given selection to the given type. returns
|
||||||
// true iff the conversion was successful or the conversion
|
// true iff the conversion was successful or the conversion
|
||||||
|
|
@ -156,16 +157,16 @@ private:
|
||||||
Window m_requestor;
|
Window m_requestor;
|
||||||
Time m_time;
|
Time m_time;
|
||||||
Atom m_property;
|
Atom m_property;
|
||||||
bool m_incr;
|
bool m_incr = false;
|
||||||
bool m_failed;
|
bool m_failed = false;
|
||||||
bool m_done;
|
bool m_done = false;
|
||||||
|
|
||||||
// atoms needed for the protocol
|
// atoms needed for the protocol
|
||||||
Atom m_atomNone; // NONE, not None
|
Atom m_atomNone = None;
|
||||||
Atom m_atomIncr;
|
Atom m_atomIncr = None;
|
||||||
|
|
||||||
// true iff we've received the selection notify
|
// true iff we've received the selection notify
|
||||||
bool m_reading;
|
bool m_reading = false;
|
||||||
|
|
||||||
// the converted selection data
|
// the converted selection data
|
||||||
String *m_data = nullptr;
|
String *m_data = nullptr;
|
||||||
|
|
@ -174,18 +175,20 @@ private:
|
||||||
// selection owner cannot convert to the requested type.
|
// selection owner cannot convert to the requested type.
|
||||||
Atom *m_actualTarget = nullptr;
|
Atom *m_actualTarget = nullptr;
|
||||||
|
|
||||||
public:
|
|
||||||
// true iff the selection owner didn't follow ICCCM conventions
|
// true iff the selection owner didn't follow ICCCM conventions
|
||||||
bool m_error;
|
bool m_error = false;
|
||||||
|
|
||||||
|
public:
|
||||||
|
bool error() const { return m_error; }
|
||||||
};
|
};
|
||||||
|
|
||||||
// Motif structure IDs
|
// Motif structure IDs
|
||||||
enum { kMotifClipFormat = 1, kMotifClipItem, kMotifClipHeader };
|
enum class MotifClip : SInt32 { Format = 1, Item = 2, Header = 3 };
|
||||||
|
|
||||||
// _MOTIF_CLIP_HEADER structure
|
// _MOTIF_CLIP_HEADER structure
|
||||||
class MotifClipHeader {
|
class MotifClipHeader {
|
||||||
public:
|
public:
|
||||||
SInt32 m_id; // kMotifClipHeader
|
MotifClip m_id;
|
||||||
SInt32 m_pad1[3];
|
SInt32 m_pad1[3];
|
||||||
SInt32 m_item;
|
SInt32 m_item;
|
||||||
SInt32 m_pad2[4];
|
SInt32 m_pad2[4];
|
||||||
|
|
@ -198,7 +201,7 @@ private:
|
||||||
// Motif clip item structure
|
// Motif clip item structure
|
||||||
class MotifClipItem {
|
class MotifClipItem {
|
||||||
public:
|
public:
|
||||||
SInt32 m_id; // kMotifClipItem
|
MotifClip m_id;
|
||||||
SInt32 m_pad1[5];
|
SInt32 m_pad1[5];
|
||||||
SInt32 m_size;
|
SInt32 m_size;
|
||||||
SInt32 m_numFormats;
|
SInt32 m_numFormats;
|
||||||
|
|
@ -209,7 +212,7 @@ private:
|
||||||
// Motif clip format structure
|
// Motif clip format structure
|
||||||
class MotifClipFormat {
|
class MotifClipFormat {
|
||||||
public:
|
public:
|
||||||
SInt32 m_id; // kMotifClipFormat
|
MotifClip m_id;
|
||||||
SInt32 m_pad1[6];
|
SInt32 m_pad1[6];
|
||||||
SInt32 m_length;
|
SInt32 m_length;
|
||||||
SInt32 m_data;
|
SInt32 m_data;
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
file(GLOB headers "*.h")
|
file(GLOB headers "*.h")
|
||||||
file(GLOB sources "*.cpp")
|
file(GLOB sources "*.cpp")
|
||||||
|
|
||||||
if(SYNERGY_ADD_HEADERS)
|
if(ADD_HEADERS_TO_SOURCES)
|
||||||
list(APPEND sources ${headers})
|
list(APPEND sources ${headers})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
file(GLOB headers "*.h")
|
file(GLOB headers "*.h")
|
||||||
file(GLOB sources "*.cpp")
|
file(GLOB sources "*.cpp")
|
||||||
|
|
||||||
if(SYNERGY_ADD_HEADERS)
|
if(ADD_HEADERS_TO_SOURCES)
|
||||||
list(APPEND sources ${headers})
|
list(APPEND sources ${headers})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* synergy -- mouse and keyboard sharing utility
|
* synergy -- mouse and keyboard sharing utility
|
||||||
* Copyright (C) 2012-2016 Symless Ltd.
|
* Copyright (C) 2012 Symless Ltd.
|
||||||
* Copyright (C) 2012 Nick Bolton
|
|
||||||
*
|
*
|
||||||
* This package is free software; you can redistribute it and/or
|
* This package is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU General Public License
|
||||||
|
|
@ -16,11 +15,14 @@
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "ipc/Ipc.h"
|
#include "Ipc.h"
|
||||||
|
|
||||||
const char *kIpcMsgHello = "IHEL%1i";
|
const char *const kIpcHost = "127.0.0.1";
|
||||||
const char *kIpcMsgHelloBack = "IHEL";
|
const int kIpcPort = 24801;
|
||||||
const char *kIpcMsgLogLine = "ILOG%s";
|
|
||||||
const char *kIpcMsgCommand = "ICMD%s%1i";
|
const char *const kIpcMsgHello = "IHEL%1i";
|
||||||
const char *kIpcMsgShutdown = "ISDN";
|
const char *const kIpcMsgHelloBack = "IHEL";
|
||||||
const char *kIpcMsgSetting = "SSET%s%s";
|
const char *const kIpcMsgLogLine = "ILOG%s";
|
||||||
|
const char *const kIpcMsgCommand = "ICMD%s%1i";
|
||||||
|
const char *const kIpcMsgShutdown = "ISDN";
|
||||||
|
const char *const kIpcMsgSetting = "SSET%s%s";
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* synergy -- mouse and keyboard sharing utility
|
* synergy -- mouse and keyboard sharing utility
|
||||||
* Copyright (C) 2012-2016 Symless Ltd.
|
* Copyright (C) 2012 Symless Ltd.
|
||||||
* Copyright (C) 2012 Nick Bolton
|
|
||||||
*
|
*
|
||||||
* This package is free software; you can redistribute it and/or
|
* This package is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU General Public License
|
||||||
|
|
@ -18,42 +17,44 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#define IPC_HOST "127.0.0.1"
|
#include "common/basic_types.h"
|
||||||
#define IPC_PORT 24801
|
|
||||||
|
|
||||||
enum EIpcMessage {
|
enum class IpcMessageType : UInt8 {
|
||||||
kIpcHello,
|
Hello,
|
||||||
kIpcHelloBack,
|
HelloBack,
|
||||||
kIpcLogLine,
|
LogLine,
|
||||||
kIpcCommand,
|
Command,
|
||||||
kIpcShutdown,
|
Shutdown,
|
||||||
kIpcSetting
|
Setting
|
||||||
};
|
};
|
||||||
|
|
||||||
enum EIpcClientType { kIpcClientUnknown, kIpcClientGui, kIpcClientNode };
|
enum class IpcClientType { Unknown, GUI, Node };
|
||||||
|
|
||||||
|
extern const char *const kIpcHost;
|
||||||
|
extern const int kIpcPort;
|
||||||
|
|
||||||
// handshake: node/gui -> daemon
|
// handshake: node/gui -> daemon
|
||||||
// $1 = type, the client identifies it's self as gui or node (synergyc/s).
|
// $1 = type, the client identifies it's self as gui or node (synergyc/s).
|
||||||
extern const char *kIpcMsgHello;
|
extern const char *const kIpcMsgHello;
|
||||||
|
|
||||||
// handshake: daemon -> node/gui
|
// handshake: daemon -> node/gui
|
||||||
// the daemon responds to the handshake.
|
// the daemon responds to the handshake.
|
||||||
extern const char *kIpcMsgHelloBack;
|
extern const char *const kIpcMsgHelloBack;
|
||||||
|
|
||||||
// log line: daemon -> gui
|
// log line: daemon -> gui
|
||||||
// $1 = aggregate log lines collected from synergys/c or the daemon itself.
|
// $1 = aggregate log lines collected from synergys/c or the daemon itself.
|
||||||
extern const char *kIpcMsgLogLine;
|
extern const char *const kIpcMsgLogLine;
|
||||||
|
|
||||||
// command: gui -> daemon
|
// command: gui -> daemon
|
||||||
// $1 = command; the command for the daemon to launch, typically the full
|
// $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.
|
// path to synergys/c. $2 = true when process must be elevated on ms windows.
|
||||||
extern const char *kIpcMsgCommand;
|
extern const char *const kIpcMsgCommand;
|
||||||
|
|
||||||
// shutdown: daemon -> node
|
// shutdown: daemon -> node
|
||||||
// the daemon tells synergys/c to shut down gracefully.
|
// the daemon tells synergys/c to shut down gracefully.
|
||||||
extern const char *kIpcMsgShutdown;
|
extern const char *const kIpcMsgShutdown;
|
||||||
|
|
||||||
// set setting: gui -> daemon
|
// set setting: gui -> daemon
|
||||||
// $1 = setting name
|
// $1 = setting name
|
||||||
// $2 = setting value
|
// $2 = setting value
|
||||||
extern const char *kIpcMsgSetting;
|
extern const char *const kIpcMsgSetting;
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* synergy -- mouse and keyboard sharing utility
|
* synergy -- mouse and keyboard sharing utility
|
||||||
* Copyright (C) 2012-2016 Symless Ltd.
|
* Copyright (C) 2012 Symless Ltd.
|
||||||
* Copyright (C) 2002 Chris Schoeneman
|
* Copyright (C) 2002 Chris Schoeneman
|
||||||
*
|
*
|
||||||
* This package is free software; you can redistribute it and/or
|
* This package is free software; you can redistribute it and/or
|
||||||
|
|
@ -27,9 +27,9 @@
|
||||||
#include "base/XBase.h"
|
#include "base/XBase.h"
|
||||||
#include "base/log_outputters.h"
|
#include "base/log_outputters.h"
|
||||||
#include "common/Version.h"
|
#include "common/Version.h"
|
||||||
#include "ipc/Ipc.h"
|
|
||||||
#include "ipc/IpcMessage.h"
|
#include "ipc/IpcMessage.h"
|
||||||
#include "ipc/IpcServerProxy.h"
|
#include "ipc/IpcServerProxy.h"
|
||||||
|
#include "shared/Ipc.h"
|
||||||
#include "synergy/ArgsBase.h"
|
#include "synergy/ArgsBase.h"
|
||||||
#include "synergy/XSynergy.h"
|
#include "synergy/XSynergy.h"
|
||||||
#include "synergy/protocol_types.h"
|
#include "synergy/protocol_types.h"
|
||||||
|
|
@ -230,7 +230,7 @@ void App::cleanupIpcClient() {
|
||||||
|
|
||||||
void App::handleIpcMessage(const Event &e, void *) {
|
void App::handleIpcMessage(const Event &e, void *) {
|
||||||
IpcMessage *m = static_cast<IpcMessage *>(e.getDataObject());
|
IpcMessage *m = static_cast<IpcMessage *>(e.getDataObject());
|
||||||
if (m->type() == kIpcShutdown) {
|
if (m->type() == IpcMessageType::Shutdown) {
|
||||||
LOG((CLOG_INFO "got ipc shutdown message"));
|
LOG((CLOG_INFO "got ipc shutdown message"));
|
||||||
m_events->addEvent(Event(Event::kQuit));
|
m_events->addEvent(Event(Event::kQuit));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ endif()
|
||||||
list(APPEND sources ${arch_sources})
|
list(APPEND sources ${arch_sources})
|
||||||
list(APPEND headers ${arch_headers})
|
list(APPEND headers ${arch_headers})
|
||||||
|
|
||||||
if(SYNERGY_ADD_HEADERS)
|
if(ADD_HEADERS_TO_SOURCES)
|
||||||
list(APPEND sources ${headers})
|
list(APPEND sources ${headers})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* synergy -- mouse and keyboard sharing utility
|
* synergy -- mouse and keyboard sharing utility
|
||||||
* Copyright (C) 2012-2016 Symless Ltd.
|
* Copyright (C) 2012 Symless Ltd.
|
||||||
* Copyright (C) 2012 Nick Bolton
|
|
||||||
*
|
*
|
||||||
* This package is free software; you can redistribute it and/or
|
* This package is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU General Public License
|
||||||
|
|
@ -25,41 +24,43 @@
|
||||||
#include "base/EventQueue.h"
|
#include "base/EventQueue.h"
|
||||||
#include "base/Log.h"
|
#include "base/Log.h"
|
||||||
#include "base/TMethodEventJob.h"
|
#include "base/TMethodEventJob.h"
|
||||||
#include "base/TMethodJob.h"
|
|
||||||
#include "base/log_outputters.h"
|
#include "base/log_outputters.h"
|
||||||
#include "ipc/Ipc.h"
|
|
||||||
#include "ipc/IpcClientProxy.h"
|
#include "ipc/IpcClientProxy.h"
|
||||||
#include "ipc/IpcLogOutputter.h"
|
#include "ipc/IpcLogOutputter.h"
|
||||||
#include "ipc/IpcMessage.h"
|
#include "ipc/IpcMessage.h"
|
||||||
#include "ipc/IpcSettingMessage.h"
|
#include "ipc/IpcSettingMessage.h"
|
||||||
#include "net/SocketMultiplexer.h"
|
#include "net/SocketMultiplexer.h"
|
||||||
|
#include "shared/Ipc.h"
|
||||||
#include "synergy/App.h"
|
#include "synergy/App.h"
|
||||||
#include "synergy/ArgParser.h"
|
#include "synergy/ArgParser.h"
|
||||||
#include "synergy/ClientArgs.h"
|
#include "synergy/ClientArgs.h"
|
||||||
#include "synergy/ServerArgs.h"
|
#include "synergy/ServerArgs.h"
|
||||||
#include "synergy/protocol_types.h"
|
|
||||||
|
|
||||||
#if SYSAPI_WIN32
|
#if SYSAPI_WIN32
|
||||||
|
|
||||||
#include "arch/win32/ArchMiscWindows.h"
|
#include "arch/win32/ArchMiscWindows.h"
|
||||||
#include "arch/win32/XArchWindows.h"
|
|
||||||
#include "platform/MSWindowsDebugOutputter.h"
|
#include "platform/MSWindowsDebugOutputter.h"
|
||||||
#include "platform/MSWindowsEventQueueBuffer.h"
|
#include "platform/MSWindowsEventQueueBuffer.h"
|
||||||
#include "platform/MSWindowsScreen.h"
|
|
||||||
#include "platform/MSWindowsWatchdog.h"
|
#include "platform/MSWindowsWatchdog.h"
|
||||||
#include "synergy/Screen.h"
|
#include "synergy/Screen.h"
|
||||||
|
|
||||||
#define WIN32_LEAN_AND_MEAN
|
#define WIN32_LEAN_AND_MEAN
|
||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
|
|
||||||
#endif
|
#elif SYSAPI_UNIX
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
|
const char *const kLogFilename = "synergyd.log";
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
void updateSetting(const IpcMessage &message) {
|
void updateSetting(const IpcMessage &message) {
|
||||||
try {
|
try {
|
||||||
|
|
@ -84,7 +85,7 @@ bool isServerCommandLine(const std::vector<String> &cmd) {
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
DaemonApp *DaemonApp::s_instance = NULL;
|
DaemonApp *DaemonApp::s_instance = nullptr;
|
||||||
|
|
||||||
int mainLoopStatic() {
|
int mainLoopStatic() {
|
||||||
DaemonApp::s_instance->mainLoop(true);
|
DaemonApp::s_instance->mainLoop(true);
|
||||||
|
|
@ -99,18 +100,9 @@ int winMainLoopStatic(int, const char **) {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
DaemonApp::DaemonApp()
|
DaemonApp::DaemonApp() { s_instance = this; }
|
||||||
: 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() { s_instance = nullptr; }
|
||||||
|
|
||||||
int DaemonApp::run(int argc, char **argv) {
|
int DaemonApp::run(int argc, char **argv) {
|
||||||
#if SYSAPI_WIN32
|
#if SYSAPI_WIN32
|
||||||
|
|
@ -122,8 +114,7 @@ int DaemonApp::run(int argc, char **argv) {
|
||||||
arch.init();
|
arch.init();
|
||||||
|
|
||||||
Log log;
|
Log log;
|
||||||
EventQueue events;
|
m_events = std::make_unique<EventQueue>();
|
||||||
m_events = &events;
|
|
||||||
|
|
||||||
bool uninstall = false;
|
bool uninstall = false;
|
||||||
try {
|
try {
|
||||||
|
|
@ -134,8 +125,7 @@ int DaemonApp::run(int argc, char **argv) {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// default log level to system setting.
|
// default log level to system setting.
|
||||||
string logLevel = arch.setting("LogLevel");
|
if (string logLevel = arch.setting("LogLevel"); logLevel != "")
|
||||||
if (logLevel != "")
|
|
||||||
log.setFilter(logLevel.c_str());
|
log.setFilter(logLevel.c_str());
|
||||||
|
|
||||||
bool foreground = false;
|
bool foreground = false;
|
||||||
|
|
@ -210,8 +200,9 @@ void DaemonApp::mainLoop(bool logToFile, bool foreground) {
|
||||||
DAEMON_RUNNING(true);
|
DAEMON_RUNNING(true);
|
||||||
|
|
||||||
if (logToFile) {
|
if (logToFile) {
|
||||||
m_fileLogOutputter = new FileLogOutputter(logFilename().c_str());
|
m_fileLogOutputter =
|
||||||
CLOG->insert(m_fileLogOutputter);
|
std::make_unique<FileLogOutputter>(logFilename().c_str());
|
||||||
|
CLOG->insert(m_fileLogOutputter.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
// create socket multiplexer. this must happen after daemonization
|
// create socket multiplexer. this must happen after daemonization
|
||||||
|
|
@ -219,20 +210,21 @@ void DaemonApp::mainLoop(bool logToFile, bool foreground) {
|
||||||
SocketMultiplexer multiplexer;
|
SocketMultiplexer multiplexer;
|
||||||
|
|
||||||
// uses event queue, must be created here.
|
// uses event queue, must be created here.
|
||||||
m_ipcServer = new IpcServer(m_events, &multiplexer);
|
m_ipcServer = std::make_unique<IpcServer>(m_events.get(), &multiplexer);
|
||||||
|
|
||||||
// send logging to gui via ipc, log system adopts outputter.
|
// send logging to gui via ipc, log system adopts outputter.
|
||||||
m_ipcLogOutputter = new IpcLogOutputter(*m_ipcServer, kIpcClientGui, true);
|
m_ipcLogOutputter = std::make_unique<IpcLogOutputter>(
|
||||||
CLOG->insert(m_ipcLogOutputter);
|
*m_ipcServer, IpcClientType::GUI, true);
|
||||||
|
CLOG->insert(m_ipcLogOutputter.get());
|
||||||
|
|
||||||
#if SYSAPI_WIN32
|
#if SYSAPI_WIN32
|
||||||
m_watchdog = new MSWindowsWatchdog(
|
m_watchdog = std::make_unique<MSWindowsWatchdog>(
|
||||||
false, *m_ipcServer, *m_ipcLogOutputter, foreground);
|
false, *m_ipcServer, *m_ipcLogOutputter, foreground);
|
||||||
m_watchdog->setFileLogOutputter(m_fileLogOutputter);
|
m_watchdog->setFileLogOutputter(m_fileLogOutputter.get());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
m_events->adoptHandler(
|
m_events->adoptHandler(
|
||||||
m_events->forIpcServer().messageReceived(), m_ipcServer,
|
m_events->forIpcServer().messageReceived(), m_ipcServer.get(),
|
||||||
new TMethodEventJob<DaemonApp>(this, &DaemonApp::handleIpcMessage));
|
new TMethodEventJob<DaemonApp>(this, &DaemonApp::handleIpcMessage));
|
||||||
|
|
||||||
m_ipcServer->listen();
|
m_ipcServer->listen();
|
||||||
|
|
@ -240,7 +232,7 @@ void DaemonApp::mainLoop(bool logToFile, bool foreground) {
|
||||||
#if SYSAPI_WIN32
|
#if SYSAPI_WIN32
|
||||||
|
|
||||||
// install the platform event queue to handle service stop events.
|
// install the platform event queue to handle service stop events.
|
||||||
m_events->adoptBuffer(new MSWindowsEventQueueBuffer(m_events));
|
m_events->adoptBuffer(new MSWindowsEventQueueBuffer(m_events.get()));
|
||||||
|
|
||||||
String command = ARCH->setting("Command");
|
String command = ARCH->setting("Command");
|
||||||
bool elevate = ARCH->setting("Elevate") == "1";
|
bool elevate = ARCH->setting("Elevate") == "1";
|
||||||
|
|
@ -255,15 +247,12 @@ void DaemonApp::mainLoop(bool logToFile, bool foreground) {
|
||||||
|
|
||||||
#if SYSAPI_WIN32
|
#if SYSAPI_WIN32
|
||||||
m_watchdog->stop();
|
m_watchdog->stop();
|
||||||
delete m_watchdog;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
m_events->removeHandler(
|
m_events->removeHandler(
|
||||||
m_events->forIpcServer().messageReceived(), m_ipcServer);
|
m_events->forIpcServer().messageReceived(), m_ipcServer.get());
|
||||||
|
|
||||||
CLOG->remove(m_ipcLogOutputter);
|
CLOG->remove(m_ipcLogOutputter.get());
|
||||||
delete m_ipcLogOutputter;
|
|
||||||
delete m_ipcServer;
|
|
||||||
|
|
||||||
DAEMON_RUNNING(false);
|
DAEMON_RUNNING(false);
|
||||||
} catch (std::exception &e) {
|
} catch (std::exception &e) {
|
||||||
|
|
@ -287,7 +276,7 @@ std::string DaemonApp::logFilename() {
|
||||||
if (logFilename.empty()) {
|
if (logFilename.empty()) {
|
||||||
logFilename = ARCH->getLogDirectory();
|
logFilename = ARCH->getLogDirectory();
|
||||||
logFilename.append("/");
|
logFilename.append("/");
|
||||||
logFilename.append(LOG_FILENAME);
|
logFilename.append(kLogFilename);
|
||||||
}
|
}
|
||||||
|
|
||||||
return logFilename;
|
return logFilename;
|
||||||
|
|
@ -296,7 +285,7 @@ std::string DaemonApp::logFilename() {
|
||||||
void DaemonApp::handleIpcMessage(const Event &e, void *) {
|
void DaemonApp::handleIpcMessage(const Event &e, void *) {
|
||||||
IpcMessage *m = static_cast<IpcMessage *>(e.getDataObject());
|
IpcMessage *m = static_cast<IpcMessage *>(e.getDataObject());
|
||||||
switch (m->type()) {
|
switch (m->type()) {
|
||||||
case kIpcCommand: {
|
case IpcMessageType::Command: {
|
||||||
IpcCommandMessage *cm = static_cast<IpcCommandMessage *>(m);
|
IpcCommandMessage *cm = static_cast<IpcCommandMessage *>(m);
|
||||||
String command = cm->command();
|
String command = cm->command();
|
||||||
|
|
||||||
|
|
@ -361,14 +350,14 @@ void DaemonApp::handleIpcMessage(const Event &e, void *) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case kIpcHello: {
|
case IpcMessageType::Hello: {
|
||||||
IpcHelloMessage *hm = static_cast<IpcHelloMessage *>(m);
|
IpcHelloMessage *hm = static_cast<IpcHelloMessage *>(m);
|
||||||
String type;
|
String type;
|
||||||
switch (hm->clientType()) {
|
switch (hm->clientType()) {
|
||||||
case kIpcClientGui:
|
case IpcClientType::GUI:
|
||||||
type = "gui";
|
type = "gui";
|
||||||
break;
|
break;
|
||||||
case kIpcClientNode:
|
case IpcClientType::Node:
|
||||||
type = "node";
|
type = "node";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|
@ -379,7 +368,7 @@ void DaemonApp::handleIpcMessage(const Event &e, void *) {
|
||||||
LOG((CLOG_DEBUG "ipc hello, type=%s", type.c_str()));
|
LOG((CLOG_DEBUG "ipc hello, type=%s", type.c_str()));
|
||||||
|
|
||||||
// TODO: implement hello back handling in s1 gui and node (server/client).
|
// TODO: implement hello back handling in s1 gui and node (server/client).
|
||||||
if (hm->clientType() == kIpcClientGui) {
|
if (hm->clientType() == IpcClientType::GUI) {
|
||||||
LOG((CLOG_DEBUG "sending ipc hello back"));
|
LOG((CLOG_DEBUG "sending ipc hello back"));
|
||||||
IpcHelloBackMessage hbm;
|
IpcHelloBackMessage hbm;
|
||||||
m_ipcServer->send(hbm, hm->clientType());
|
m_ipcServer->send(hbm, hm->clientType());
|
||||||
|
|
@ -394,7 +383,7 @@ void DaemonApp::handleIpcMessage(const Event &e, void *) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case kIpcSetting:
|
case IpcMessageType::Setting:
|
||||||
updateSetting(*m);
|
updateSetting(*m);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* synergy -- mouse and keyboard sharing utility
|
* synergy -- mouse and keyboard sharing utility
|
||||||
* Copyright (C) 2012-2016 Symless Ltd.
|
* Copyright (C) 2012 Symless Ltd.
|
||||||
* Copyright (C) 2012 Nick Bolton
|
|
||||||
*
|
*
|
||||||
* This package is free software; you can redistribute it and/or
|
* This package is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU General Public License
|
||||||
|
|
@ -18,9 +17,9 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "arch/Arch.h"
|
|
||||||
#include "ipc/IpcServer.h"
|
#include "ipc/IpcServer.h"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
class Event;
|
class Event;
|
||||||
|
|
@ -31,11 +30,13 @@ class FileLogOutputter;
|
||||||
class MSWindowsWatchdog;
|
class MSWindowsWatchdog;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
extern const char *const kLogFilename;
|
||||||
|
|
||||||
class DaemonApp {
|
class DaemonApp {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DaemonApp();
|
DaemonApp();
|
||||||
virtual ~DaemonApp();
|
~DaemonApp();
|
||||||
int run(int argc, char **argv);
|
int run(int argc, char **argv);
|
||||||
void mainLoop(bool logToFile, bool foreground = false);
|
void mainLoop(bool logToFile, bool foreground = false);
|
||||||
|
|
||||||
|
|
@ -49,14 +50,12 @@ public:
|
||||||
static DaemonApp *s_instance;
|
static DaemonApp *s_instance;
|
||||||
|
|
||||||
#if SYSAPI_WIN32
|
#if SYSAPI_WIN32
|
||||||
MSWindowsWatchdog *m_watchdog;
|
std::unique_ptr<MSWindowsWatchdog> m_watchdog;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
private:
|
private:
|
||||||
IpcServer *m_ipcServer;
|
std::unique_ptr<IpcServer> m_ipcServer;
|
||||||
IpcLogOutputter *m_ipcLogOutputter;
|
std::unique_ptr<IpcLogOutputter> m_ipcLogOutputter;
|
||||||
IEventQueue *m_events;
|
std::unique_ptr<IEventQueue> m_events;
|
||||||
FileLogOutputter *m_fileLogOutputter;
|
std::unique_ptr<FileLogOutputter> m_fileLogOutputter;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define LOG_FILENAME "synergyd.log"
|
|
||||||
|
|
|
||||||
|
|
@ -14,18 +14,158 @@
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
include_directories(
|
macro(config_all_tests)
|
||||||
../../ext/googletest/googletest ../../ext/googletest/googletest/include
|
|
||||||
../../ext/googletest/googlemock ../../ext/googletest/googlemock/include)
|
|
||||||
|
|
||||||
add_library(gtest STATIC ../../ext/googletest/googletest/src/gtest-all.cc)
|
set(base_dir ${CMAKE_SOURCE_DIR})
|
||||||
add_library(gmock STATIC ../../ext/googletest/googlemock/src/gmock-all.cc)
|
set(src_dir ${base_dir}/src)
|
||||||
|
set(test_base_dir ${src_dir}/test)
|
||||||
|
set(ext_dir ${base_dir}/ext)
|
||||||
|
set(gtest_base_dir ${ext_dir}/googletest)
|
||||||
|
set(gui_dir ${src_dir}/gui/src)
|
||||||
|
|
||||||
if(UNIX)
|
config_test_deps()
|
||||||
|
|
||||||
|
add_subdirectory(integtests)
|
||||||
|
add_subdirectory(unittests)
|
||||||
|
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
macro(config_test)
|
||||||
|
|
||||||
|
include_directories(
|
||||||
|
${test_base_dir}
|
||||||
|
${src_dir}
|
||||||
|
${src_dir}/lib
|
||||||
|
${gui_dir}
|
||||||
|
${ext_dir})
|
||||||
|
|
||||||
|
set_sources()
|
||||||
|
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
macro(set_sources)
|
||||||
|
|
||||||
|
file(GLOB_RECURSE headers ${CMAKE_CURRENT_SOURCE_DIR}/*.h)
|
||||||
|
file(GLOB_RECURSE sources ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)
|
||||||
|
|
||||||
|
file(GLOB_RECURSE shared_headers ${test_base_dir}/shared/*.h)
|
||||||
|
file(GLOB_RECURSE shared_sources ${test_base_dir}/shared/*.cpp)
|
||||||
|
|
||||||
|
list(APPEND headers ${shared_headers})
|
||||||
|
list(APPEND sources ${shared_sources})
|
||||||
|
|
||||||
|
file(GLOB_RECURSE mock_headers ${test_base_dir}/mock/*.h)
|
||||||
|
file(GLOB_RECURSE mock_sources ${test_base_dir}/mock/*.cpp)
|
||||||
|
|
||||||
|
list(APPEND headers ${mock_headers})
|
||||||
|
list(APPEND sources ${mock_sources})
|
||||||
|
|
||||||
|
file(GLOB_RECURSE gui_sources ${gui_dir}/*.cpp)
|
||||||
|
|
||||||
|
file(GLOB activation_sources ${gui_dir}/*Activation* ${gui_dir}/*License*)
|
||||||
|
if(NOT ENABLE_LICENSING)
|
||||||
|
list(REMOVE_ITEM gui_sources ${activation_sources})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# remove main gui as the test already has its own main.
|
||||||
|
file(GLOB gui_main ${gui_dir}/main.cpp)
|
||||||
|
list(REMOVE_ITEM gui_sources ${gui_main})
|
||||||
|
|
||||||
|
if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||||
|
file(GLOB mac_gui_sources ${gui_dir}/*.mm)
|
||||||
|
list(APPEND gui_sources ${mac_gui_sources})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
list(APPEND sources ${gui_sources})
|
||||||
|
|
||||||
|
if(ADD_HEADERS_TO_SOURCES)
|
||||||
|
list(APPEND sources ${headers})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(WIN32)
|
||||||
|
list(APPEND sources ${CMAKE_BINARY_DIR}/src/version.rc)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
add_platform_sources()
|
||||||
|
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
macro(add_platform_sources)
|
||||||
|
|
||||||
|
set(platform_dir ${CMAKE_CURRENT_SOURCE_DIR}/platform)
|
||||||
|
|
||||||
|
# Remove platform files so that specific platform files can be added later.
|
||||||
|
# This is a bit weird, but it's simpler to include everything, remove all
|
||||||
|
# platform files, then only include the platforms we need.
|
||||||
|
file(GLOB_RECURSE all_platform_files ${platform_dir}/*)
|
||||||
|
list(REMOVE_ITEM headers ${all_platform_files})
|
||||||
|
list(REMOVE_ITEM sources ${all_platform_files})
|
||||||
|
|
||||||
|
if(WIN32)
|
||||||
|
file(GLOB platform_sources ${platform_dir}/MSWindows*.cpp)
|
||||||
|
file(GLOB platform_headers ${platform_dir}/MSWindows*.h)
|
||||||
|
elseif(APPLE)
|
||||||
|
file(GLOB platform_sources ${platform_dir}/OSX*.cpp)
|
||||||
|
file(GLOB platform_headers ${platform_dir}/OSX*.h)
|
||||||
|
elseif(UNIX)
|
||||||
|
file(GLOB platform_sources ${platform_dir}/XWindows*.cpp)
|
||||||
|
file(GLOB platform_headers ${platform_dir}/XWindows*.h)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
list(APPEND sources ${platform_sources})
|
||||||
|
list(APPEND headers ${platform_headers})
|
||||||
|
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
macro(config_test_deps)
|
||||||
|
|
||||||
|
set(CMAKE_AUTOMOC ON)
|
||||||
|
set(CMAKE_AUTORCC ON)
|
||||||
|
set(CMAKE_AUTOUIC ON)
|
||||||
|
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||||
|
|
||||||
|
find_package(
|
||||||
|
Qt6
|
||||||
|
COMPONENTS Core Widgets Network Test
|
||||||
|
REQUIRED)
|
||||||
|
|
||||||
|
set(gtest_dir ${gtest_base_dir}/googletest)
|
||||||
|
set(gmock_dir ${gtest_base_dir}/googlemock)
|
||||||
|
|
||||||
|
include_directories(${gtest_dir} ${gmock_dir} ${gtest_dir}/include
|
||||||
|
${gmock_dir}/include)
|
||||||
|
|
||||||
|
add_library(gtest STATIC ${gtest_dir}/src/gtest-all.cc)
|
||||||
|
add_library(gmock STATIC ${gmock_dir}/src/gmock-all.cc)
|
||||||
|
|
||||||
|
if(UNIX)
|
||||||
# ignore warnings in gtest and gmock
|
# ignore warnings in gtest and gmock
|
||||||
set_target_properties(gtest PROPERTIES COMPILE_FLAGS "-w")
|
set_target_properties(gtest PROPERTIES COMPILE_FLAGS "-w")
|
||||||
set_target_properties(gmock PROPERTIES COMPILE_FLAGS "-w")
|
set_target_properties(gmock PROPERTIES COMPILE_FLAGS "-w")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_subdirectory(integtests)
|
set(test_libs
|
||||||
add_subdirectory(unittests)
|
arch
|
||||||
|
base
|
||||||
|
client
|
||||||
|
server
|
||||||
|
common
|
||||||
|
io
|
||||||
|
net
|
||||||
|
platform
|
||||||
|
server
|
||||||
|
synlib
|
||||||
|
mt
|
||||||
|
ipc
|
||||||
|
gtest
|
||||||
|
gmock
|
||||||
|
shared
|
||||||
|
Qt6::Core
|
||||||
|
Qt6::Widgets
|
||||||
|
Qt6::Network
|
||||||
|
Qt6::Test
|
||||||
|
${libs})
|
||||||
|
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
config_all_tests()
|
||||||
|
|
|
||||||
|
|
@ -14,67 +14,7 @@
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
file(GLOB_RECURSE headers "*.h")
|
config_test()
|
||||||
file(GLOB_RECURSE sources "*.cpp")
|
set(target integtests)
|
||||||
|
add_executable(${target} ${sources})
|
||||||
# remove platform files (specific platform added later).
|
target_link_libraries(${target} ${test_libs})
|
||||||
file(GLOB_RECURSE remove_platform "platform/*")
|
|
||||||
list(REMOVE_ITEM headers ${remove_platform})
|
|
||||||
list(REMOVE_ITEM sources ${remove_platform})
|
|
||||||
|
|
||||||
# platform
|
|
||||||
if(WIN32)
|
|
||||||
file(GLOB platform_sources "platform/MSWindows*.cpp")
|
|
||||||
file(GLOB platform_headers "platform/MSWindows*.h")
|
|
||||||
elseif(APPLE)
|
|
||||||
file(GLOB platform_sources "platform/OSX*.cpp")
|
|
||||||
file(GLOB platform_headers "platform/OSX*.h")
|
|
||||||
elseif(UNIX)
|
|
||||||
file(GLOB platform_sources "platform/XWindows*.cpp")
|
|
||||||
file(GLOB platform_headers "platform/XWindows*.h")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
list(APPEND sources ${platform_sources})
|
|
||||||
list(APPEND headers ${platform_headers})
|
|
||||||
|
|
||||||
file(GLOB_RECURSE shared_headers "../../test/shared/*.h")
|
|
||||||
file(GLOB_RECURSE shared_sources "../../test/shared/*.cpp")
|
|
||||||
|
|
||||||
list(APPEND headers ${shared_headers})
|
|
||||||
list(APPEND sources ${shared_sources})
|
|
||||||
|
|
||||||
file(GLOB_RECURSE mock_headers "../../test/mock/*.h")
|
|
||||||
file(GLOB_RECURSE mock_sources "../../test/mock/*.cpp")
|
|
||||||
|
|
||||||
list(APPEND headers ${mock_headers})
|
|
||||||
list(APPEND sources ${mock_sources})
|
|
||||||
|
|
||||||
if(SYNERGY_ADD_HEADERS)
|
|
||||||
list(APPEND sources ${headers})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(WIN32)
|
|
||||||
list(APPEND sources ${CMAKE_BINARY_DIR}/src/version.rc)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
include_directories(
|
|
||||||
../../ ../../lib/ ../../../ext/googletest/googletest/include
|
|
||||||
../../../ext/googletest/googlemock/include)
|
|
||||||
|
|
||||||
add_executable(integtests ${sources})
|
|
||||||
target_link_libraries(
|
|
||||||
integtests
|
|
||||||
arch
|
|
||||||
base
|
|
||||||
client
|
|
||||||
common
|
|
||||||
io
|
|
||||||
ipc
|
|
||||||
mt
|
|
||||||
net
|
|
||||||
platform
|
|
||||||
server
|
|
||||||
synlib
|
|
||||||
gtest
|
|
||||||
gmock
|
|
||||||
${libs})
|
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,6 @@
|
||||||
#include "base/String.h"
|
#include "base/String.h"
|
||||||
#include "base/TMethodEventJob.h"
|
#include "base/TMethodEventJob.h"
|
||||||
#include "base/TMethodJob.h"
|
#include "base/TMethodJob.h"
|
||||||
#include "ipc/Ipc.h"
|
|
||||||
#include "ipc/IpcClient.h"
|
#include "ipc/IpcClient.h"
|
||||||
#include "ipc/IpcClientProxy.h"
|
#include "ipc/IpcClientProxy.h"
|
||||||
#include "ipc/IpcMessage.h"
|
#include "ipc/IpcMessage.h"
|
||||||
|
|
@ -35,11 +34,12 @@
|
||||||
#include "ipc/IpcServerProxy.h"
|
#include "ipc/IpcServerProxy.h"
|
||||||
#include "mt/Thread.h"
|
#include "mt/Thread.h"
|
||||||
#include "net/SocketMultiplexer.h"
|
#include "net/SocketMultiplexer.h"
|
||||||
|
#include "shared/Ipc.h"
|
||||||
#include "test/shared/TestEventQueue.h"
|
#include "test/shared/TestEventQueue.h"
|
||||||
|
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
#define TEST_IPC_PORT 24802
|
const int kTestPort = 24802;
|
||||||
|
|
||||||
class IpcTests : public ::testing::Test {
|
class IpcTests : public ::testing::Test {
|
||||||
public:
|
public:
|
||||||
|
|
@ -65,7 +65,7 @@ public:
|
||||||
|
|
||||||
TEST_F(IpcTests, connectToServer) {
|
TEST_F(IpcTests, connectToServer) {
|
||||||
SocketMultiplexer socketMultiplexer;
|
SocketMultiplexer socketMultiplexer;
|
||||||
IpcServer server(&m_events, &socketMultiplexer, TEST_IPC_PORT);
|
IpcServer server(&m_events, &socketMultiplexer, kTestPort);
|
||||||
server.listen();
|
server.listen();
|
||||||
m_connectToServer_server = &server;
|
m_connectToServer_server = &server;
|
||||||
|
|
||||||
|
|
@ -74,7 +74,7 @@ TEST_F(IpcTests, connectToServer) {
|
||||||
new TMethodEventJob<IpcTests>(
|
new TMethodEventJob<IpcTests>(
|
||||||
this, &IpcTests::connectToServer_handleMessageReceived));
|
this, &IpcTests::connectToServer_handleMessageReceived));
|
||||||
|
|
||||||
IpcClient client(&m_events, &socketMultiplexer, TEST_IPC_PORT);
|
IpcClient client(&m_events, &socketMultiplexer, kTestPort);
|
||||||
client.connect();
|
client.connect();
|
||||||
|
|
||||||
m_events.initQuitTimeout(5);
|
m_events.initQuitTimeout(5);
|
||||||
|
|
@ -88,7 +88,7 @@ TEST_F(IpcTests, connectToServer) {
|
||||||
|
|
||||||
TEST_F(IpcTests, sendMessageToServer) {
|
TEST_F(IpcTests, sendMessageToServer) {
|
||||||
SocketMultiplexer socketMultiplexer;
|
SocketMultiplexer socketMultiplexer;
|
||||||
IpcServer server(&m_events, &socketMultiplexer, TEST_IPC_PORT);
|
IpcServer server(&m_events, &socketMultiplexer, kTestPort);
|
||||||
server.listen();
|
server.listen();
|
||||||
|
|
||||||
// event handler sends "test" command to server.
|
// event handler sends "test" command to server.
|
||||||
|
|
@ -97,7 +97,7 @@ TEST_F(IpcTests, sendMessageToServer) {
|
||||||
new TMethodEventJob<IpcTests>(
|
new TMethodEventJob<IpcTests>(
|
||||||
this, &IpcTests::sendMessageToServer_serverHandleMessageReceived));
|
this, &IpcTests::sendMessageToServer_serverHandleMessageReceived));
|
||||||
|
|
||||||
IpcClient client(&m_events, &socketMultiplexer, TEST_IPC_PORT);
|
IpcClient client(&m_events, &socketMultiplexer, kTestPort);
|
||||||
client.connect();
|
client.connect();
|
||||||
m_sendMessageToServer_client = &client;
|
m_sendMessageToServer_client = &client;
|
||||||
|
|
||||||
|
|
@ -111,7 +111,7 @@ TEST_F(IpcTests, sendMessageToServer) {
|
||||||
|
|
||||||
TEST_F(IpcTests, sendMessageToClient) {
|
TEST_F(IpcTests, sendMessageToClient) {
|
||||||
SocketMultiplexer socketMultiplexer;
|
SocketMultiplexer socketMultiplexer;
|
||||||
IpcServer server(&m_events, &socketMultiplexer, TEST_IPC_PORT);
|
IpcServer server(&m_events, &socketMultiplexer, kTestPort);
|
||||||
server.listen();
|
server.listen();
|
||||||
m_sendMessageToClient_server = &server;
|
m_sendMessageToClient_server = &server;
|
||||||
|
|
||||||
|
|
@ -121,7 +121,7 @@ TEST_F(IpcTests, sendMessageToClient) {
|
||||||
new TMethodEventJob<IpcTests>(
|
new TMethodEventJob<IpcTests>(
|
||||||
this, &IpcTests::sendMessageToClient_serverHandleClientConnected));
|
this, &IpcTests::sendMessageToClient_serverHandleClientConnected));
|
||||||
|
|
||||||
IpcClient client(&m_events, &socketMultiplexer, TEST_IPC_PORT);
|
IpcClient client(&m_events, &socketMultiplexer, kTestPort);
|
||||||
client.connect();
|
client.connect();
|
||||||
|
|
||||||
m_events.adoptHandler(
|
m_events.adoptHandler(
|
||||||
|
|
@ -149,9 +149,9 @@ IpcTests::~IpcTests() {}
|
||||||
|
|
||||||
void IpcTests::connectToServer_handleMessageReceived(const Event &e, void *) {
|
void IpcTests::connectToServer_handleMessageReceived(const Event &e, void *) {
|
||||||
IpcMessage *m = static_cast<IpcMessage *>(e.getDataObject());
|
IpcMessage *m = static_cast<IpcMessage *>(e.getDataObject());
|
||||||
if (m->type() == kIpcHello) {
|
if (m->type() == IpcMessageType::Hello) {
|
||||||
m_connectToServer_hasClientNode =
|
m_connectToServer_hasClientNode =
|
||||||
m_connectToServer_server->hasClients(kIpcClientNode);
|
m_connectToServer_server->hasClients(IpcClientType::Node);
|
||||||
m_connectToServer_helloMessageReceived = true;
|
m_connectToServer_helloMessageReceived = true;
|
||||||
m_events.raiseQuitEvent();
|
m_events.raiseQuitEvent();
|
||||||
}
|
}
|
||||||
|
|
@ -160,11 +160,11 @@ void IpcTests::connectToServer_handleMessageReceived(const Event &e, void *) {
|
||||||
void IpcTests::sendMessageToServer_serverHandleMessageReceived(
|
void IpcTests::sendMessageToServer_serverHandleMessageReceived(
|
||||||
const Event &e, void *) {
|
const Event &e, void *) {
|
||||||
IpcMessage *m = static_cast<IpcMessage *>(e.getDataObject());
|
IpcMessage *m = static_cast<IpcMessage *>(e.getDataObject());
|
||||||
if (m->type() == kIpcHello) {
|
if (m->type() == IpcMessageType::Hello) {
|
||||||
LOG((CLOG_DEBUG "client said hello, sending test to server"));
|
LOG((CLOG_DEBUG "client said hello, sending test to server"));
|
||||||
IpcCommandMessage m("test", true);
|
IpcCommandMessage m("test", true);
|
||||||
m_sendMessageToServer_client->send(m);
|
m_sendMessageToServer_client->send(m);
|
||||||
} else if (m->type() == kIpcCommand) {
|
} else if (m->type() == IpcMessageType::Command) {
|
||||||
IpcCommandMessage *cm = static_cast<IpcCommandMessage *>(m);
|
IpcCommandMessage *cm = static_cast<IpcCommandMessage *>(m);
|
||||||
LOG((CLOG_DEBUG "got ipc command message, %d", cm->command().c_str()));
|
LOG((CLOG_DEBUG "got ipc command message, %d", cm->command().c_str()));
|
||||||
m_sendMessageToServer_receivedString = cm->command();
|
m_sendMessageToServer_receivedString = cm->command();
|
||||||
|
|
@ -175,17 +175,17 @@ void IpcTests::sendMessageToServer_serverHandleMessageReceived(
|
||||||
void IpcTests::sendMessageToClient_serverHandleClientConnected(
|
void IpcTests::sendMessageToClient_serverHandleClientConnected(
|
||||||
const Event &e, void *) {
|
const Event &e, void *) {
|
||||||
IpcMessage *m = static_cast<IpcMessage *>(e.getDataObject());
|
IpcMessage *m = static_cast<IpcMessage *>(e.getDataObject());
|
||||||
if (m->type() == kIpcHello) {
|
if (m->type() == IpcMessageType::Hello) {
|
||||||
LOG((CLOG_DEBUG "client said hello, sending test to client"));
|
LOG((CLOG_DEBUG "client said hello, sending test to client"));
|
||||||
IpcLogLineMessage m("test");
|
IpcLogLineMessage m("test");
|
||||||
m_sendMessageToClient_server->send(m, kIpcClientNode);
|
m_sendMessageToClient_server->send(m, IpcClientType::Node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void IpcTests::sendMessageToClient_clientHandleMessageReceived(
|
void IpcTests::sendMessageToClient_clientHandleMessageReceived(
|
||||||
const Event &e, void *) {
|
const Event &e, void *) {
|
||||||
IpcMessage *m = static_cast<IpcMessage *>(e.getDataObject());
|
IpcMessage *m = static_cast<IpcMessage *>(e.getDataObject());
|
||||||
if (m->type() == kIpcLogLine) {
|
if (m->type() == IpcMessageType::LogLine) {
|
||||||
IpcLogLineMessage *llm = static_cast<IpcLogLineMessage *>(m);
|
IpcLogLineMessage *llm = static_cast<IpcLogLineMessage *>(m);
|
||||||
LOG((CLOG_DEBUG "got ipc log message, %d", llm->logLine().c_str()));
|
LOG((CLOG_DEBUG "got ipc log message, %d", llm->logLine().c_str()));
|
||||||
m_sendMessageToClient_receivedString = llm->logLine();
|
m_sendMessageToClient_receivedString = llm->logLine();
|
||||||
|
|
|
||||||
|
|
@ -16,21 +16,17 @@
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// TODO: fix tests - compile error on linux
|
|
||||||
#if 0
|
|
||||||
|
|
||||||
#include "platform/XWindowsClipboard.h"
|
#include "platform/XWindowsClipboard.h"
|
||||||
|
|
||||||
#include <gtest/gtest.h>
|
#include "test/shared/undef_x11_macros.h"
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
class CXWindowsClipboardTests : public ::testing::Test
|
#include <gtest/gtest.h>
|
||||||
{
|
#include <memory>
|
||||||
|
|
||||||
|
class XWindowsClipboardTests : public ::testing::Test {
|
||||||
protected:
|
protected:
|
||||||
virtual void
|
void SetUp() override {
|
||||||
SetUp()
|
m_display = XOpenDisplay(nullptr);
|
||||||
{
|
|
||||||
m_display = XOpenDisplay(NULL);
|
|
||||||
int screen = DefaultScreen(m_display);
|
int screen = DefaultScreen(m_display);
|
||||||
Window root = XRootWindow(m_display, screen);
|
Window root = XRootWindow(m_display, screen);
|
||||||
|
|
||||||
|
|
@ -40,54 +36,46 @@ protected:
|
||||||
attr.cursor = Cursor();
|
attr.cursor = Cursor();
|
||||||
|
|
||||||
m_window = XCreateWindow(
|
m_window = XCreateWindow(
|
||||||
m_display, root, 0, 0, 1, 1, 0, 0,
|
m_display, root, 0, 0, 1, 1, 0, 0, InputOnly, nullptr, 0, &attr);
|
||||||
InputOnly, CopyFromParent, 0, &attr);
|
|
||||||
|
m_clipboard = std::make_unique<XWindowsClipboard>(m_display, m_window, 0);
|
||||||
|
m_clipboard->open(0);
|
||||||
|
m_clipboard->empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void
|
void TearDown() override {
|
||||||
TearDown()
|
|
||||||
{
|
|
||||||
XDestroyWindow(m_display, m_window);
|
XDestroyWindow(m_display, m_window);
|
||||||
XCloseDisplay(m_display);
|
XCloseDisplay(m_display);
|
||||||
}
|
}
|
||||||
|
|
||||||
CXWindowsClipboard&
|
XWindowsClipboard &getClipboard() { return *m_clipboard; }
|
||||||
createClipboard()
|
|
||||||
{
|
|
||||||
CXWindowsClipboard* clipboard;
|
|
||||||
clipboard = new CXWindowsClipboard(m_display, m_window, 0);
|
|
||||||
clipboard->open(0); // needed to empty the clipboard
|
|
||||||
clipboard->empty(); // needed to own the clipboard
|
|
||||||
return *clipboard;
|
|
||||||
}
|
|
||||||
|
|
||||||
Display* m_display;
|
private:
|
||||||
|
Display *m_display;
|
||||||
Window m_window;
|
Window m_window;
|
||||||
|
std::unique_ptr<XWindowsClipboard> m_clipboard;
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST_F(CXWindowsClipboardTests, empty_openCalled_returnsTrue)
|
TEST_F(XWindowsClipboardTests, empty_openCalled_returnsTrue) {
|
||||||
{
|
XWindowsClipboard &clipboard = getClipboard();
|
||||||
CXWindowsClipboard clipboard = createClipboard();
|
|
||||||
|
|
||||||
bool actual = clipboard.empty();
|
bool actual = clipboard.empty();
|
||||||
|
|
||||||
EXPECT_EQ(true, actual);
|
EXPECT_EQ(true, actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(CXWindowsClipboardTests, empty_singleFormat_hasReturnsFalse)
|
TEST_F(XWindowsClipboardTests, empty_singleFormat_hasReturnsFalse) {
|
||||||
{
|
XWindowsClipboard &clipboard = getClipboard();
|
||||||
CXWindowsClipboard clipboard = createClipboard();
|
clipboard.add(XWindowsClipboard::kText, "synergy rocks!");
|
||||||
clipboard.add(CXWindowsClipboard::kText, "synergy rocks!");
|
|
||||||
|
|
||||||
clipboard.empty();
|
clipboard.empty();
|
||||||
|
|
||||||
bool actual = clipboard.has(CXWindowsClipboard::kText);
|
bool actual = clipboard.has(XWindowsClipboard::kText);
|
||||||
EXPECT_FALSE(actual);
|
EXPECT_FALSE(actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(CXWindowsClipboardTests, add_newValue_valueWasStored)
|
TEST_F(XWindowsClipboardTests, add_newValue_valueWasStored) {
|
||||||
{
|
XWindowsClipboard &clipboard = getClipboard();
|
||||||
CXWindowsClipboard clipboard = createClipboard();
|
|
||||||
|
|
||||||
clipboard.add(IClipboard::kText, "synergy rocks!");
|
clipboard.add(IClipboard::kText, "synergy rocks!");
|
||||||
|
|
||||||
|
|
@ -95,9 +83,8 @@ TEST_F(CXWindowsClipboardTests, add_newValue_valueWasStored)
|
||||||
EXPECT_EQ("synergy rocks!", actual);
|
EXPECT_EQ("synergy rocks!", actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(CXWindowsClipboardTests, add_replaceValue_valueWasReplaced)
|
TEST_F(XWindowsClipboardTests, add_replaceValue_valueWasReplaced) {
|
||||||
{
|
XWindowsClipboard &clipboard = getClipboard();
|
||||||
CXWindowsClipboard clipboard = createClipboard();
|
|
||||||
|
|
||||||
clipboard.add(IClipboard::kText, "synergy rocks!");
|
clipboard.add(IClipboard::kText, "synergy rocks!");
|
||||||
clipboard.add(IClipboard::kText, "maxivista sucks"); // haha, just kidding.
|
clipboard.add(IClipboard::kText, "maxivista sucks"); // haha, just kidding.
|
||||||
|
|
@ -106,9 +93,8 @@ TEST_F(CXWindowsClipboardTests, add_replaceValue_valueWasReplaced)
|
||||||
EXPECT_EQ("maxivista sucks", actual);
|
EXPECT_EQ("maxivista sucks", actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(CXWindowsClipboardTests, close_isOpen_noErrors)
|
TEST_F(XWindowsClipboardTests, close_isOpen_noErrors) {
|
||||||
{
|
XWindowsClipboard &clipboard = getClipboard();
|
||||||
CXWindowsClipboard clipboard = createClipboard();
|
|
||||||
|
|
||||||
// clipboard opened in createClipboard()
|
// clipboard opened in createClipboard()
|
||||||
clipboard.close();
|
clipboard.close();
|
||||||
|
|
@ -116,9 +102,8 @@ TEST_F(CXWindowsClipboardTests, close_isOpen_noErrors)
|
||||||
// can't assert anything
|
// can't assert anything
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(CXWindowsClipboardTests, has_withFormatAdded_returnsTrue)
|
TEST_F(XWindowsClipboardTests, has_withFormatAdded_returnsTrue) {
|
||||||
{
|
XWindowsClipboard &clipboard = getClipboard();
|
||||||
CXWindowsClipboard clipboard = createClipboard();
|
|
||||||
clipboard.add(IClipboard::kText, "synergy rocks!");
|
clipboard.add(IClipboard::kText, "synergy rocks!");
|
||||||
|
|
||||||
bool actual = clipboard.has(IClipboard::kText);
|
bool actual = clipboard.has(IClipboard::kText);
|
||||||
|
|
@ -126,32 +111,27 @@ TEST_F(CXWindowsClipboardTests, has_withFormatAdded_returnsTrue)
|
||||||
EXPECT_EQ(true, actual);
|
EXPECT_EQ(true, actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(CXWindowsClipboardTests, has_withNoFormats_returnsFalse)
|
TEST_F(XWindowsClipboardTests, has_withNoFormats_returnsFalse) {
|
||||||
{
|
XWindowsClipboard &clipboard = getClipboard();
|
||||||
CXWindowsClipboard clipboard = createClipboard();
|
|
||||||
|
|
||||||
bool actual = clipboard.has(IClipboard::kText);
|
bool actual = clipboard.has(IClipboard::kText);
|
||||||
|
|
||||||
EXPECT_FALSE(actual);
|
EXPECT_FALSE(actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(CXWindowsClipboardTests, get_withNoFormats_returnsEmpty)
|
TEST_F(XWindowsClipboardTests, get_withNoFormats_returnsEmpty) {
|
||||||
{
|
XWindowsClipboard &clipboard = getClipboard();
|
||||||
CXWindowsClipboard clipboard = createClipboard();
|
|
||||||
|
|
||||||
String actual = clipboard.get(IClipboard::kText);
|
String actual = clipboard.get(IClipboard::kText);
|
||||||
|
|
||||||
EXPECT_EQ("", actual);
|
EXPECT_EQ("", actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(CXWindowsClipboardTests, get_withFormatAdded_returnsExpected)
|
TEST_F(XWindowsClipboardTests, get_withFormatAdded_returnsExpected) {
|
||||||
{
|
XWindowsClipboard &clipboard = getClipboard();
|
||||||
CXWindowsClipboard clipboard = createClipboard();
|
|
||||||
clipboard.add(IClipboard::kText, "synergy rocks!");
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
|
||||||
|
|
@ -45,8 +45,8 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
MOCK_METHOD(void, listen, (), (override));
|
MOCK_METHOD(void, listen, (), (override));
|
||||||
MOCK_METHOD(void, send, (const IpcMessage &, EIpcClientType), (override));
|
MOCK_METHOD(void, send, (const IpcMessage &, IpcClientType), (override));
|
||||||
MOCK_METHOD(bool, hasClients, (EIpcClientType), (const, override));
|
MOCK_METHOD(bool, hasClients, (IpcClientType), (const, override));
|
||||||
|
|
||||||
void delegateToFake() {
|
void delegateToFake() {
|
||||||
ON_CALL(*this, send(_, _))
|
ON_CALL(*this, send(_, _))
|
||||||
|
|
@ -56,7 +56,7 @@ public:
|
||||||
void waitForSend() { ARCH->waitCondVar(m_sendCond, m_sendMutex, 5); }
|
void waitForSend() { ARCH->waitCondVar(m_sendCond, m_sendMutex, 5); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void mockSend(const IpcMessage &, EIpcClientType) {
|
void mockSend(const IpcMessage &, IpcClientType) {
|
||||||
ArchMutexLock lock(m_sendMutex);
|
ArchMutexLock lock(m_sendMutex);
|
||||||
ARCH->broadcastCondVar(m_sendCond);
|
ARCH->broadcastCondVar(m_sendCond);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* synergy -- mouse and keyboard sharing utility
|
* synergy -- mouse and keyboard sharing utility
|
||||||
* Copyright (C) 2012-2016 Symless Ltd.
|
* Copyright (C) 2024 Symless Ltd.
|
||||||
* Copyright (C) 2012 Nick Bolton
|
|
||||||
*
|
*
|
||||||
* This package is free software; you can redistribute it and/or
|
* This package is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU General Public License
|
||||||
|
|
@ -16,11 +15,12 @@
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// this class is a duplicate of /src/lib/ipc/Ipc.cpp
|
/**
|
||||||
|
* This header fixes conflicts between X11 and Google Test.
|
||||||
|
*
|
||||||
|
* It should be included after headers of code under test (that use X11)
|
||||||
|
* and before including Google Test headers.
|
||||||
|
*/
|
||||||
|
|
||||||
#include "Ipc.h"
|
#undef None // NOSONAR
|
||||||
|
#undef Bool // NOSONAR
|
||||||
const char *kIpcMsgHello = "IHEL%1i";
|
|
||||||
const char *kIpcMsgLogLine = "ILOG%s";
|
|
||||||
const char *kIpcMsgCommand = "ICMD%s%1i";
|
|
||||||
const char *kIpcMsgShutdown = "ISDN";
|
|
||||||
|
|
@ -14,110 +14,7 @@
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
config_test()
|
||||||
set(target unittests)
|
set(target unittests)
|
||||||
|
|
||||||
file(GLOB_RECURSE headers "*.h" "languages/*.h")
|
|
||||||
file(GLOB_RECURSE sources "*.cpp" "languages/*.cpp")
|
|
||||||
|
|
||||||
file(GLOB_RECURSE remove_platform "platform/*")
|
|
||||||
list(REMOVE_ITEM headers ${remove_platform})
|
|
||||||
list(REMOVE_ITEM sources ${remove_platform})
|
|
||||||
|
|
||||||
file(GLOB_RECURSE shared_headers "../../test/shared/*.h")
|
|
||||||
file(GLOB_RECURSE shared_sources "../../test/shared/*.cpp")
|
|
||||||
|
|
||||||
list(APPEND headers ${shared_headers})
|
|
||||||
list(APPEND sources ${shared_sources})
|
|
||||||
|
|
||||||
file(GLOB_RECURSE mock_headers "../../test/mock/*.h")
|
|
||||||
file(GLOB_RECURSE mock_sources "../../test/mock/*.cpp")
|
|
||||||
|
|
||||||
list(APPEND headers ${mock_headers})
|
|
||||||
list(APPEND sources ${mock_sources})
|
|
||||||
|
|
||||||
set(gui_dir "../../gui/src")
|
|
||||||
file(GLOB_RECURSE gui_sources "${gui_dir}/*.cpp")
|
|
||||||
|
|
||||||
file(GLOB activation_sources "${gui_dir}/*Activation*" "${gui_dir}/*License*")
|
|
||||||
if(NOT ENABLE_LICENSING)
|
|
||||||
list(REMOVE_ITEM gui_sources ${activation_sources})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# remove main gui as the test already has its own main.
|
|
||||||
file(GLOB gui_main "${gui_dir}/main.cpp")
|
|
||||||
list(REMOVE_ITEM gui_sources ${gui_main})
|
|
||||||
|
|
||||||
if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
|
||||||
file(GLOB mac_gui_sources "${gui_dir}/*.mm")
|
|
||||||
list(APPEND gui_sources ${mac_gui_sources})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
list(APPEND sources ${gui_sources})
|
|
||||||
|
|
||||||
# platform
|
|
||||||
if(WIN32)
|
|
||||||
file(GLOB platform_sources "platform/MSWindows*.cpp")
|
|
||||||
file(GLOB platform_headers "platform/MSWindows*.h")
|
|
||||||
elseif(APPLE)
|
|
||||||
file(GLOB platform_sources "platform/OSX*.cpp")
|
|
||||||
file(GLOB platform_headers "platform/OSX*.h")
|
|
||||||
elseif(UNIX)
|
|
||||||
file(GLOB platform_sources "platform/XWindows*.cpp")
|
|
||||||
file(GLOB platform_headers "platform/XWindows*.h")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
list(APPEND sources ${platform_sources})
|
|
||||||
list(APPEND headers ${platform_headers})
|
|
||||||
|
|
||||||
set(ext_dir "../../../ext")
|
|
||||||
|
|
||||||
include_directories(
|
|
||||||
"../.."
|
|
||||||
"../../lib"
|
|
||||||
${ext_dir}
|
|
||||||
${gui_dir}
|
|
||||||
"${ext_dir}/gtest/include"
|
|
||||||
"${ext_dir}/gmock/include")
|
|
||||||
|
|
||||||
if(SYNERGY_ADD_HEADERS)
|
|
||||||
list(APPEND sources ${headers})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(WIN32)
|
|
||||||
list(APPEND sources ${CMAKE_BINARY_DIR}/src/version.rc)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set(CMAKE_AUTOMOC ON)
|
|
||||||
set(CMAKE_AUTORCC ON)
|
|
||||||
set(CMAKE_AUTOUIC ON)
|
|
||||||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
|
||||||
|
|
||||||
find_package(
|
|
||||||
Qt6
|
|
||||||
COMPONENTS Core Widgets Network Test
|
|
||||||
REQUIRED)
|
|
||||||
|
|
||||||
add_executable(${target} ${sources})
|
add_executable(${target} ${sources})
|
||||||
|
target_link_libraries(${target} ${test_libs})
|
||||||
target_link_libraries(
|
|
||||||
${target}
|
|
||||||
arch
|
|
||||||
base
|
|
||||||
client
|
|
||||||
server
|
|
||||||
common
|
|
||||||
io
|
|
||||||
net
|
|
||||||
platform
|
|
||||||
server
|
|
||||||
synlib
|
|
||||||
mt
|
|
||||||
ipc
|
|
||||||
gtest
|
|
||||||
gmock
|
|
||||||
shared
|
|
||||||
Qt6::Core
|
|
||||||
Qt6::Widgets
|
|
||||||
Qt6::Network
|
|
||||||
Qt6::Test
|
|
||||||
${libs})
|
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,7 @@ using namespace synergy;
|
||||||
// _)).Times(1); EXPECT_CALL(mockServer, send(IpcLogLineMessageEq("mock
|
// _)).Times(1); EXPECT_CALL(mockServer, send(IpcLogLineMessageEq("mock
|
||||||
// 2\n"), _)).Times(1);
|
// 2\n"), _)).Times(1);
|
||||||
//
|
//
|
||||||
// IpcLogOutputter outputter(mockServer, kIpcClientUnknown, true);
|
// IpcLogOutputter outputter(mockServer, IpcClientType::Unknown, true);
|
||||||
// outputter.write(kNOTE, "mock 1");
|
// outputter.write(kNOTE, "mock 1");
|
||||||
// mockServer.waitForSend();
|
// mockServer.waitForSend();
|
||||||
// outputter.write(kNOTE, "mock 2");
|
// outputter.write(kNOTE, "mock 2");
|
||||||
|
|
@ -78,7 +78,7 @@ using namespace synergy;
|
||||||
// EXPECT_CALL(mockServer, send(IpcLogLineMessageEq("mock 2\nmock 3\n"),
|
// EXPECT_CALL(mockServer, send(IpcLogLineMessageEq("mock 2\nmock 3\n"),
|
||||||
// _)).Times(1);
|
// _)).Times(1);
|
||||||
//
|
//
|
||||||
// IpcLogOutputter outputter(mockServer, kIpcClientUnknown, false);
|
// IpcLogOutputter outputter(mockServer, IpcClientType::Unknown, false);
|
||||||
// outputter.bufferMaxSize(2);
|
// outputter.bufferMaxSize(2);
|
||||||
//
|
//
|
||||||
// // log more lines than the buffer can contain
|
// // log more lines than the buffer can contain
|
||||||
|
|
@ -98,7 +98,7 @@ using namespace synergy;
|
||||||
// EXPECT_CALL(mockServer, send(IpcLogLineMessageEq("mock 1\nmock 2\n"),
|
// EXPECT_CALL(mockServer, send(IpcLogLineMessageEq("mock 1\nmock 2\n"),
|
||||||
// _)).Times(1);
|
// _)).Times(1);
|
||||||
//
|
//
|
||||||
// IpcLogOutputter outputter(mockServer, kIpcClientUnknown, false);
|
// IpcLogOutputter outputter(mockServer, IpcClientType::Unknown, false);
|
||||||
// outputter.bufferMaxSize(2);
|
// outputter.bufferMaxSize(2);
|
||||||
//
|
//
|
||||||
// // log more lines than the buffer can contain
|
// // log more lines than the buffer can contain
|
||||||
|
|
@ -156,7 +156,7 @@ using namespace synergy;
|
||||||
// _)).Times(1); EXPECT_CALL(mockServer, send(IpcLogLineMessageEq("mock
|
// _)).Times(1); EXPECT_CALL(mockServer, send(IpcLogLineMessageEq("mock
|
||||||
// 3\nmock 4\n"), _)).Times(1);
|
// 3\nmock 4\n"), _)).Times(1);
|
||||||
//
|
//
|
||||||
// IpcLogOutputter outputter(mockServer, kIpcClientUnknown, false);
|
// IpcLogOutputter outputter(mockServer, IpcClientType::Unknown, false);
|
||||||
// outputter.bufferRateLimit(4, 1); // 1s (should be plenty of time)
|
// outputter.bufferRateLimit(4, 1); // 1s (should be plenty of time)
|
||||||
//
|
//
|
||||||
// // log 1 more line than the buffer can accept in time limit.
|
// // log 1 more line than the buffer can accept in time limit.
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* synergy -- mouse and keyboard sharing utility
|
* synergy -- mouse and keyboard sharing utility
|
||||||
* Copyright (C) 2012-2016 Symless Ltd.
|
* Copyright (C) 2024 Symless Ltd.
|
||||||
* Copyright (C) 2012 Nick Bolton
|
|
||||||
*
|
*
|
||||||
* This package is free software; you can redistribute it and/or
|
* This package is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU General Public License
|
||||||
|
|
@ -16,27 +15,24 @@
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// this class is a duplicate of /src/lib/ipc/Ipc.h
|
#include "platform/XWindowsClipboard.h"
|
||||||
|
|
||||||
#pragma once
|
#include "test/shared/undef_x11_macros.h"
|
||||||
|
|
||||||
#define IPC_HOST "127.0.0.1"
|
#include <gtest/gtest.h>
|
||||||
#define IPC_PORT 24801
|
|
||||||
|
|
||||||
enum qIpcMessageType {
|
const auto None = 0L;
|
||||||
kIpcHello,
|
|
||||||
kIpcLogLine,
|
class TestXWindowsClipboard : public XWindowsClipboard {
|
||||||
kIpcCommand,
|
public:
|
||||||
kIpcShutdown,
|
class TestCICCCMGetClipboard : public CICCCMGetClipboard {
|
||||||
|
public:
|
||||||
|
TestCICCCMGetClipboard() : CICCCMGetClipboard(None, None, None) {}
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
enum qIpcClientType {
|
TEST(XWindowsClipboardTests_CICCCMGetClipboard, ctor_default_errorNone) {
|
||||||
kIpcClientUnknown,
|
TestXWindowsClipboard::TestCICCCMGetClipboard clipboard;
|
||||||
kIpcClientGui,
|
|
||||||
kIpcClientNode,
|
|
||||||
};
|
|
||||||
|
|
||||||
extern const char *kIpcMsgHello;
|
EXPECT_EQ(None, clipboard.error());
|
||||||
extern const char *kIpcMsgLogLine;
|
}
|
||||||
extern const char *kIpcMsgCommand;
|
|
||||||
extern const char *kIpcMsgShutdown;
|
|
||||||
Loading…
Reference in a new issue