Implement safer memory use, improve dev env, fixed GUI bugs (#7407)

* Improve dev script for daemon

* Ignore `.user` files created by Qt

* Add `FORCE_DESKTOP_PROCESS` option

* Catch errors related to getting profile dir

* Disable IPC entirely if forced desktop

* Use in-class init for AppConfig members

* Refactor config to use safer memory management

* Improve launch config to make OS-specific debugger usage clearer

* Re-enable MainWindowTests on Windows, further refactor for memory safety, fixed some include orders

* Remove dead singleton code

* Swap order of tests

* Use HTTPs for URLs

* Fixed compile errors for `SYNERGY_ENABLE_LICENSING` compile path

* Restore exec function call

* Remove extra link in cancel dialog

* Fixed broken link on activation cancel UI

* Close dialog if activated

* Fixed macOS enum ref to kCurrentProcess

* Improve wording on cancel activation dialog

* WIP - Test timeout (compile error)

* Finished timeout logic (with smart pointer)

* Include string_view

* Switch to thread from jthread (maybe not supported by macOS compiler?)

* Improve comment

* Disable test on Windows

* Add TODO related to jthread on macOS

* Refactor settings and paths on Windows

* Launch in desktop mode on Windows

* Remove arg quote wraps which break desktop mode

* Fixed qFatal on Linux

* Remove test value

* Follow original `AppConfig` accessor convention

* Disable service checkbox if not Windows

* Simplify TLS control enable logic

* Update command and Git ignore

* Fixed code style

* Fixed include consistency

* Fixed includes in validator

* Fixed lint errors

* Update ChangeLog

* Use smart pointer for core process

* Remove unneccesary default operators

* Don't halt on stderr
This commit is contained in:
Nick Bolton
2024-07-22 17:48:02 +01:00
committed by GitHub
parent f81901f633
commit 85b8b83a53
58 changed files with 2244 additions and 2221 deletions

2
.gitignore vendored
View File

@ -14,3 +14,5 @@ Brewfile.lock.json
*.code-workspace
.env*
/scripts/*.egg-info
/*.user
*.ui.autosave

71
.vscode/launch.json vendored
View File

@ -2,55 +2,68 @@
"version": "0.2.0",
"configurations": [
{
"name": "gui lldb",
"name": "gui unix",
"type": "lldb",
"request": "launch",
"program": "${workspaceFolder}/build/bin/synergy",
"preLaunchTask": "build-kill"
"preLaunchTask": "kill-build"
},
{
"name": "unittests lldb",
"name": "gui windows",
"type": "cppvsdbg",
"cwd": "${workspaceRoot}/build/bin",
"request": "launch",
"program": "${workspaceFolder}/build/bin/synergy",
"internalConsoleOptions": "openOnSessionStart",
"preLaunchTask": "kill-build"
},
{
"name": "unittests unix",
"type": "lldb",
"request": "launch",
"program": "${workspaceFolder}/build/bin/unittests",
"preLaunchTask": "build"
},
{
"name": "integtests lldb",
"name": "unittests windows",
"type": "cppvsdbg",
"cwd": "${workspaceRoot}/build/bin",
"request": "launch",
"program": "${workspaceFolder}/build/bin/unittests",
"internalConsoleOptions": "openOnSessionStart",
"preLaunchTask": "build"
},
{
"name": "integtests unix",
"type": "lldb",
"request": "launch",
"program": "${workspaceFolder}/build/bin/integtests",
"preLaunchTask": "build"
},
{
"name": "win daemon attach",
"name": "integtests windows",
"type": "cppvsdbg",
"cwd": "${workspaceRoot}/build/bin",
"request": "launch",
"program": "${workspaceFolder}/build/bin/integtests",
"internalConsoleOptions": "openOnSessionStart",
"preLaunchTask": "build"
},
{
"name": "daemon windows",
"type": "cppvsdbg",
"cwd": "${workspaceRoot}/build/bin",
"request": "launch",
"program": "${workspaceFolder}/build/bin/synergyd",
"args": ["-f"],
"internalConsoleOptions": "openOnSessionStart",
"preLaunchTask": "build"
},
{
"name": "daemon windows attach",
"type": "cppvsdbg",
"request": "attach",
"processId": "${command:pickProcess}"
},
{
"name": "win daemon attach - lldb",
"type": "lldb",
"request": "attach",
"program": "${workspaceFolder}/build/bin/synergyd"
},
{
"name": "win daemon launch",
"type": "cppvsdbg",
"cwd": "${workspaceRoot}/build/bin",
"request": "launch",
"program": "${workspaceFolder}/build/bin/synergyd",
"args": ["-f"],
"internalConsoleOptions": "openOnSessionStart"
},
{
"name": "win daemon launch - rebuild",
"type": "cppvsdbg",
"cwd": "${workspaceRoot}/build/bin",
"request": "launch",
"program": "${workspaceFolder}/build/bin/synergyd",
"args": ["-f"],
"preLaunchTask": "build"
}
]
}

31
.vscode/tasks.json vendored
View File

@ -22,7 +22,7 @@
},
{
"label": "tests",
"dependsOn": ["unittests", "integtests"],
"dependsOn": ["integtests", "unittests"],
"problemMatcher": []
},
{
@ -31,24 +31,43 @@
"command": "killall synergy; killall synergyc; killall synergys || true",
"windows": {
"command": "taskkill /F /IM synergy.exe /IM synergyc.exe /IM synergys.exe; $true"
},
"presentation": {
"reveal": "silent"
}
},
{
"label": "build-kill",
"dependsOn": ["build", "kill"]
"label": "kill-build",
"dependsOn": ["kill", "build"],
"problemMatcher": []
},
{
"label": "gui",
"type": "process",
"command": "${workspaceFolder}/build/bin/synergy",
"dependsOn": ["build", "kill"]
"dependsOn": ["build", "kill"],
"problemMatcher": [],
"windows": {
"command": "${workspaceFolder}/build/bin/synergy.exe"
}
},
{
"label": "windows daemon",
"label": "restart daemon",
"type": "shell",
"command": "python scripts/windows_daemon.py",
"command": "python scripts/daemon.py --restart",
"dependsOn": ["build"]
},
{
"label": "reinstall daemon",
"type": "shell",
"command": "python scripts/daemon.py --reinstall",
"dependsOn": ["build"]
},
{
"label": "stop daemon",
"type": "shell",
"command": "python scripts/daemon.py --stop"
},
{
"label": "clean-gcda",
"type": "shell",

View File

@ -57,6 +57,7 @@ Enhancements:
- #7403 Solve low hanging reliability and maintainability issues
- #7404 Restore integtests and add to CI as warning comment on failure
- #7406 Migrate scripts from `requirements.txt` to `pyproject.toml`
- #7407 Implement safer memory use, improve dev env, fixed GUI bugs
# 1.14.6

View File

@ -1,19 +1,3 @@
# Synergy -- mouse and keyboard sharing utility
# Copyright (C) 2012-2024 Symless Ltd.
# Copyright (C) 2009-2012 Nick Bolton
#
# This package is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# found in the file LICENSE that should have accompanied this file.
#
# This package is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# 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(configure_libs)
set(libs)
@ -295,6 +279,9 @@ macro(configure_windows_libs)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/res/win/version.rc.in
${CMAKE_BINARY_DIR}/src/version.rc @ONLY)
find_openssl_dir_win32(OPENSSL_PATH)
add_definitions(-DOPENSSL_PATH="${OPENSSL_PATH}")
endmacro()
macro(configure_openssl)
@ -383,3 +370,36 @@ macro(configure_python)
set(PYTHON_BIN "${CMAKE_BINARY_DIR}/python/bin/python")
endif()
endmacro()
#
# Find the OpenSSL directory on Windows based on the location of the first
# `openssl` binary found.
#
function(find_openssl_dir_win32 result)
execute_process(
COMMAND where openssl
OUTPUT_VARIABLE OPENSSL_PATH
OUTPUT_STRIP_TRAILING_WHITESPACE)
# It's possible that there are multiple OpenSSL installations on the system,
# which is the case on GitHub runners. For now we'll pick the first one, but
# that's probably not very robust. Maybe our choco config could install to a
# specific location?
string(REGEX REPLACE "\r?\n" ";" OPENSSL_PATH_LIST ${OPENSSL_PATH})
message(STATUS "Found OpenSSL binaries at: ${OPENSSL_PATH_LIST}")
list(GET OPENSSL_PATH_LIST 0 OPENSSL_FIRST_PATH)
message(STATUS "First OpenSSL binary: ${OPENSSL_FIRST_PATH}")
get_filename_component(OPENSSL_BIN_DIR ${OPENSSL_FIRST_PATH} DIRECTORY)
message(STATUS "OpenSSL bin dir: ${OPENSSL_BIN_DIR}")
get_filename_component(OPENSSL_DIR ${OPENSSL_BIN_DIR} DIRECTORY)
message(STATUS "OpenSSL install root dir: ${OPENSSL_DIR}")
set(${result}
${OPENSSL_DIR}
PARENT_SCOPE)
endfunction()

View File

@ -51,8 +51,6 @@ macro(configure_windows_packaging)
set(CPACK_PACKAGE_VERSION ${SYNERGY_VERSION_MS})
set(QT_PATH $ENV{CMAKE_PREFIX_PATH})
find_openssl_dir_win32(OPENSSL_PATH)
configure_files(${CMAKE_CURRENT_SOURCE_DIR}/res/dist/wix
${CMAKE_BINARY_DIR}/installer)
@ -157,36 +155,3 @@ macro(configure_files srcDir destDir)
endforeach(templateFile)
endmacro(configure_files)
#
# Find the OpenSSL directory on Windows based on the location of the first
# `openssl` binary found.
#
function(find_openssl_dir_win32 result)
execute_process(
COMMAND where openssl
OUTPUT_VARIABLE OPENSSL_PATH
OUTPUT_STRIP_TRAILING_WHITESPACE)
# It's possible that there are multiple OpenSSL installations on the system,
# which is the case on GitHub runners. For now we'll pick the first one, but
# that's probably not very robust. Maybe our choco config could install to a
# specific location?
string(REGEX REPLACE "\r?\n" ";" OPENSSL_PATH_LIST ${OPENSSL_PATH})
message(STATUS "Found OpenSSL binaries at: ${OPENSSL_PATH_LIST}")
list(GET OPENSSL_PATH_LIST 0 OPENSSL_FIRST_PATH)
message(STATUS "First OpenSSL binary: ${OPENSSL_FIRST_PATH}")
get_filename_component(OPENSSL_BIN_DIR ${OPENSSL_FIRST_PATH} DIRECTORY)
message(STATUS "OpenSSL bin dir: ${OPENSSL_BIN_DIR}")
get_filename_component(OPENSSL_DIR ${OPENSSL_BIN_DIR} DIRECTORY)
message(STATUS "OpenSSL install root dir: ${OPENSSL_DIR}")
set(${result}
${OPENSSL_DIR}
PARENT_SCOPE)
endfunction()

192
scripts/daemon.py Normal file
View File

@ -0,0 +1,192 @@
import os, sys, time, subprocess, argparse
import lib.windows as windows
import lib.file_utils as file_utils
import lib.env as env
import lib.colors as colors
import psutil
DEFAULT_BIN_NAME = "synergyd"
DEFAULT_SOURCE_DIR = os.path.join("build", "temp", "bin")
DEFAULT_TARGET_DIR = os.path.join("build", "bin")
SERVICE_NOT_RUNNING_ERROR = 2
ERROR_ACCESS_VIOLATION = 0xC0000005
IGNORE_PROCESSES = ["synergy.exe"]
class Context:
def __init__(self, verbose):
self.verbose = verbose
def main():
"""Entry point for the script."""
parser = argparse.ArgumentParser()
parser.add_argument("--reinstall", action="store_true")
parser.add_argument("--stop", action="store_true")
parser.add_argument("--restart", action="store_true")
parser.add_argument("--pause-on-exit", action="store_true")
parser.add_argument("--source-dir", default=DEFAULT_SOURCE_DIR)
parser.add_argument("--target-dir", default=DEFAULT_TARGET_DIR)
parser.add_argument("--bin-name", default=DEFAULT_BIN_NAME)
parser.add_argument("--verbose", action="store_true")
args = parser.parse_args()
if not env.is_windows():
print(
f"{colors.ERROR_TEXT} This script is only supported on Windows",
file=sys.stderr,
)
sys.exit(1)
context = Context(args.verbose)
try:
if args.reinstall:
reinstall(context, args.source_dir, args.target_dir, args.bin_name)
elif args.stop:
stop(context, args.target_dir)
elif args.restart:
restart(context, args.source_dir, args.target_dir)
else:
print("No action specified", file=sys.stderr)
exit(1)
except Exception as e:
print(f"{colors.ERROR_TEXT} {e}", file=sys.stderr)
if args.pause_on_exit:
input("Press enter to continue...")
def print_verbose(context, message):
if context.verbose:
print(message)
def ensure_admin():
if not windows.is_admin():
windows.relaunch_as_admin(__file__)
sys.exit()
def restart(context, source_dir, target_dir):
"""Stops the daemon service, copies files, and restarts the daemon service."""
ensure_admin()
stop(context, target_dir)
copy_files(source_dir, target_dir)
start()
def reinstall(context, source_dir, target_dir, bin_name):
"""Stops and uninstalls daemon service, copies files, and reinstalls the daemon service."""
ensure_admin()
stop(context, target_dir)
source_bin_path = f"{os.path.join(source_dir, bin_name)}.exe"
copy_files(source_dir, target_dir)
print("Removing old daemon service")
try:
subprocess.run([source_bin_path, "/uninstall"], shell=True, check=True)
except subprocess.CalledProcessError as e:
check_access_violation(e.returncode, source_bin_path)
if e.returncode != 0:
print(
f"{colors.WARNING_TEXT} Uninstall failed, return code: {e.returncode}",
file=sys.stderr,
)
target_bin_path = os.path.join(target_dir, bin_name + ".exe")
try:
print("Installing daemon service")
subprocess.run([target_bin_path, "/install"], shell=True, check=True)
except subprocess.CalledProcessError as e:
check_access_violation(e.returncode, target_bin_path)
if e.returncode != 0:
print(f"{colors.WARNING_TEXT} Install failed, return code: {e.returncode}")
def copy_files(source_dir, target_dir):
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)
def stop(context, target_dir):
ensure_admin()
print("Stopping daemon service")
try:
subprocess.run(["net", "stop", "synergy"], shell=True, check=True)
except subprocess.CalledProcessError as e:
if e.returncode == SERVICE_NOT_RUNNING_ERROR:
print_verbose(context, "Daemon service not running")
else:
raise e
# Wait for Windows to release the file handles after process termination.
wait_for_stop(context, target_dir)
def start():
ensure_admin()
print("Starting daemon service")
subprocess.run(["net", "start", "synergy"], shell=True, check=True)
def wait_for_stop(context, target_dir):
if is_any_process_running(context, target_dir):
print("Waiting for file handles to release...", end="", flush=True)
while is_any_process_running(context, target_dir):
if not context.verbose:
print(".", end="", flush=True)
time.sleep(1)
if not context.verbose:
print()
def check_access_violation(return_code, bin_path):
if return_code == ERROR_ACCESS_VIOLATION:
print(
f"{colors.WARNING_TEXT} Process crashed with memory access violation: {bin_path}",
file=sys.stderr,
)
def is_ignored_process(exe):
for ignore_process in IGNORE_PROCESSES:
if exe.endswith(ignore_process):
return True
return False
def is_any_process_running(context, dir):
"""Check if there is any running process that contains the given directory."""
print_verbose(context, 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:
print_verbose(context, f"Skipping process with no exe: {proc}")
continue
if is_ignored_process(exe):
print_verbose(context, f"Ignoring process: {exe}")
continue
try:
if dir.lower() in exe.lower():
print_verbose(context, f"Process found: {exe}")
return True
except (psutil.NoSuchProcess, psutil.AccessDenied):
pass
return False
main()

View File

@ -3,6 +3,7 @@
import argparse
import lib.env as env
import lib.file_utils as file_utils
import lib.colors as colors
def main():
@ -34,7 +35,7 @@ def main():
if not args.ignore_errors:
raise e
else:
print(f"Error: {e}")
print(f"{colors.ERROR_TEXT} {e}")
if __name__ == "__main__":

8
scripts/lib/colors.py Normal file
View File

@ -0,0 +1,8 @@
import colorama # type: ignore
from colorama import Fore # type: ignore
colorama.init()
ERROR_TEXT = f"{Fore.RED}Error:{Fore.RESET}"
WARNING_TEXT = f"{Fore.YELLOW}Warning:{Fore.RESET}"
HINT_TEXT = f"{Fore.LIGHTBLUE_EX}Hint:{Fore.RESET}"

View File

@ -1,9 +1,6 @@
import glob, os, shutil, sys
import colorama # type: ignore
from colorama import Fore # type: ignore
colorama.init()
import lib.env as env
import lib.colors as colors
class CopyOptions:
@ -24,24 +21,24 @@ def copy(source, target, options):
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")
try:
for match in glob.glob(source):
if context.errors and options.ignore_errors:
print(
f"{Fore.YELLOW}WARNING:{Fore.RESET} Ignored {context.errors} copy error(s)"
)
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")
finally:
if context.errors and options.ignore_errors:
print(f"{colors.WARNING_TEXT} 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"
)
if context.permission_error and env.is_windows():
print(
f"{colors.HINT_TEXT} A Windows file permission error may mean that the file is in use"
)
def copy_dir(match, target, options, context):
@ -50,12 +47,8 @@ def copy_dir(match, target, options, context):
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)
handle_all_copy_errors(e, options, context)
def copy_file(match, target, options, context):
@ -64,17 +57,33 @@ def copy_file(match, target, options, context):
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)
handle_all_copy_errors(e, options, context)
def handle_copy_error(e, options, context):
context.errors += 1
def handle_all_copy_errors(error, options, context):
if isinstance(error, shutil.Error):
for _, _, file_error in error.args[0]:
handle_copy_error(file_error, options, context)
else:
handle_copy_error(error, options, context)
if not options.ignore_errors:
raise e
else:
print(f"{Fore.YELLOW}WARNING:{Fore.RESET} Copy failed: {e}", file=sys.stderr)
raise error
def handle_copy_error(error, options, context):
if isinstance(error, PermissionError):
context.permission_error = True
if isinstance(error, str):
context.permission_error = error.startswith("[Errno 13] Permission denied")
context.errors += 1
if options.ignore_errors:
print(
f"{colors.WARNING_TEXT} Copy failed: {error}",
file=sys.stderr,
)

View File

@ -1,112 +0,0 @@
import os, sys, time, subprocess, argparse, glob
import lib.windows as windows
import lib.file_utils as file_utils
import psutil
DEFAULT_BIN_NAME = "synergyd"
DEFAULT_SOURCE_DIR = os.path.join("build", "temp", "bin")
DEFAULT_TARGET_DIR = os.path.join("build", "bin")
SERVICE_NOT_RUNNING_ERROR = 2
ERROR_ACCESS_VIOLATION = 0xC0000005
def main():
"""Entry point for the script."""
parser = argparse.ArgumentParser()
parser.add_argument("--pause-on-exit", action="store_true")
parser.add_argument("--source-dir", default=DEFAULT_SOURCE_DIR)
parser.add_argument("--target-dir", default=DEFAULT_TARGET_DIR)
parser.add_argument("--bin-name", default=DEFAULT_BIN_NAME)
args = parser.parse_args()
if not windows.is_admin():
windows.relaunch_as_admin(__file__)
sys.exit()
try:
reinstall(
args.source_dir,
args.target_dir,
args.bin_name,
)
except Exception as e:
print(f"Error: {e}", file=sys.stderr)
if args.pause_on_exit:
input("Press enter to continue...")
def reinstall(source_dir, target_dir, bin_name):
"""Stops the running daemon service, copies files, and reinstalls."""
print("Stopping daemon service")
try:
subprocess.run(["net", "stop", "synergy"], shell=True, check=True)
except subprocess.CalledProcessError as e:
if e.returncode == SERVICE_NOT_RUNNING_ERROR:
print("Daemon service not running")
else:
raise e
source_bin_path = f"{os.path.join(source_dir, 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")
try:
subprocess.run([source_bin_path, "/uninstall"], shell=True, check=True)
except subprocess.CalledProcessError as e:
check_access_violation(e.returncode, source_bin_path)
if e.returncode != 0:
print(
f"Warning: Uninstall failed, return code: {e.returncode}",
file=sys.stderr,
)
target_bin_path = os.path.join(target_dir, bin_name + ".exe")
try:
print("Installing daemon service")
subprocess.run([target_bin_path, "/install"], shell=True, check=True)
except subprocess.CalledProcessError as 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()

View File

@ -24,7 +24,7 @@ AboutDialog::AboutDialog(MainWindow *parent, const AppConfig &config)
Ui::AboutDialogBase() {
setupUi(this);
m_versionChecker.setApp(parent->appPath(config.synergycName()));
m_versionChecker.setApp(parent->appPath(config.coreClientName()));
QString version = SYNERGY_VERSION;
#ifdef GIT_SHA_SHORT

View File

@ -1,17 +1,31 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2016 Synergy 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/>.
*/
#include "ActivationDialog.h"
#include "ActivationNotifier.h"
#include "AppConfig.h"
#include "CancelActivationDialog.h"
#include "FailedLoginDialog.h"
#include "LicenseManager.h"
#include "MainWindow.h"
#include "QUtility.h"
#include "shared/EditionType.h"
#include "ui_ActivationDialog.h"
#include <shared/EditionType.h>
#include <QApplication>
#include <QMessageBox>
#include <QThread>
#include <iostream>
ActivationDialog::ActivationDialog(
QWidget *parent, AppConfig &appConfig, LicenseManager &licenseManager)
@ -38,15 +52,18 @@ void ActivationDialog::refreshSerialKey() {
ActivationDialog::~ActivationDialog() { delete ui; }
void ActivationDialog::reject() {
if (m_LicenseManager->activeEdition() == kUnregistered) {
CancelActivationDialog cancelActivationDialog(this);
if (QDialog::Accepted == cancelActivationDialog.exec()) {
m_LicenseManager->skipActivation();
} else {
return;
}
// don't show the cancel confirmation dialog if they've already registered,
// since it's not revent to customers who are changing their serial key.
if (m_LicenseManager->activeEdition() != kUnregistered) {
QDialog::reject();
return;
}
// the user is told that the 'No' button will exit the app.
CancelActivationDialog cancelActivationDialog(this);
if (cancelActivationDialog.exec() == QDialog::Rejected) {
QApplication::exit();
}
QDialog::reject();
}
void ActivationDialog::accept() {
@ -82,7 +99,7 @@ void ActivationDialog::accept() {
.arg((daysLeft == 1) ? "" : "s")
.arg((daysLeft == 1) ? "s" : "");
if (m_appConfig->isCryptoAvailable()) {
if (m_appConfig->cryptoAvailable()) {
m_appConfig->generateCertificate();
thanksMessage =
thanksMessage.arg("If you're using SSL, "

View File

@ -1,5 +1,21 @@
#ifndef ACTIVATIONDIALOG_H
#define ACTIVATIONDIALOG_H
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2016 Synergy 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/>.
*/
#pragma once
#include <LicenseManager.h>
#include <QDialog>
@ -30,5 +46,3 @@ private:
AppConfig *m_appConfig;
LicenseManager *m_LicenseManager;
};
#endif // ACTIVATIONDIALOG_H

View File

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>410</width>
<height>211</height>
<width>477</width>
<height>241</height>
</rect>
</property>
<property name="windowTitle">
@ -18,7 +18,6 @@
<widget class="QLabel" name="label">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
@ -30,7 +29,7 @@
<item>
<widget class="QLabel" name="label_5">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;This can be found on your &lt;a href=&quot;https://symless.com/synergy/account?source=gui&quot;&gt;&lt;span style=&quot; text-decoration: none; color: #4285F4;&quot;&gt;account&lt;/span&gt;&lt;/a&gt; page.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Your serial key is on your &lt;a href=&quot;https://symless.com/synergy/account?source=gui&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#4285f4;&quot;&gt;account&lt;/span&gt;&lt;/a&gt; page. Don't have a license? &lt;a href=&quot;https://symless.com/synergy/purchase?source=gui&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#007af4;&quot;&gt;Purchase Synergy&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="openExternalLinks">
<bool>true</bool>
@ -47,9 +46,12 @@
</property>
<property name="html">
<string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;meta charset=&quot;utf-8&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'.AppleSystemUIFont'; font-size:13pt; font-weight:400; font-style:normal;&quot;&gt;
hr { height: 1px; border-width: 0; }
li.unchecked::marker { content: &quot;\2610&quot;; }
li.checked::marker { content: &quot;\2612&quot;; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Segoe UI'; font-size:9pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans'; font-size:10pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="acceptRichText">

View File

@ -1,6 +1,6 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2012 Symless Ltd.
* Copyright (C) 2008 Volker Lanz (vl@fidra.de)
*
* This package is free software; you can redistribute it and/or
@ -18,32 +18,35 @@
#include "AppConfig.h"
#include "ConfigWriter.h"
#include "Config.h"
#include "SslCertificate.h"
#include <QApplication>
#include <QPushButton>
#include <QtCore>
#include <QtNetwork>
#include <QtWidgets/QMessageBox>
#include <qapplication.h>
using synergy::gui::Config;
// this should be incremented each time the wizard is changed,
// which will force it to re-run for existing installations.
const int kWizardVersion = 8;
using GUI::Config::ConfigWriter;
#if defined(Q_OS_WIN)
const char AppConfig::m_SynergysName[] = "synergys.exe";
const char AppConfig::m_SynergycName[] = "synergyc.exe";
const char AppConfig::m_SynergyLogDir[] = "log/";
const char AppConfig::m_SynergyConfigName[] = "synergy.sgc";
const ProcessMode kDefaultProcessMode = ProcessMode::kService;
const char AppConfig::m_CoreServerName[] = "synergys.exe";
const char AppConfig::m_CoreClientName[] = "synergyc.exe";
const char AppConfig::m_LogDir[] = "log/";
const char AppConfig::m_ConfigFilename[] = "synergy.sgc";
#else
const char AppConfig::m_SynergysName[] = "synergys";
const char AppConfig::m_SynergycName[] = "synergyc";
const char AppConfig::m_SynergyLogDir[] = "/var/log/";
const char AppConfig::m_SynergyConfigName[] = "synergy.conf";
const ProcessMode kDefaultProcessMode = ProcessMode::kDesktop;
const char AppConfig::m_CoreServerName[] = "synergys";
const char AppConfig::m_CoreClientName[] = "synergyc";
const char AppConfig::m_LogDir[] = "/var/log/";
const char AppConfig::m_ConfigFilename[] = "synergy.conf";
#endif
const ElevateMode kDefaultElevateMode = ElevateAsNeeded;
const char *AppConfig::m_SynergySettingsName[] = {
const char *const AppConfig::m_SettingsName[] = {
"screenName",
"port",
"interface",
@ -80,55 +83,38 @@ const char *AppConfig::m_SynergySettingsName[] = {
"licenseNextCheck",
"initiateConnectionFromServer",
"clientHostMode",
"serverClientMode"};
"serverClientMode",
"serviceEnabled",
"minimizeOnClose"};
static const char *logLevelNames[] = {"INFO", "DEBUG", "DEBUG1", "DEBUG2"};
AppConfig::AppConfig(bool globalLoad)
: m_ScreenName(),
m_Port(24800),
m_Interface(),
m_LogLevel(0),
m_LogToFile(),
m_WizardLastRun(0),
m_ProcessMode(kDefaultProcessMode),
m_StartedBefore(),
m_ElevateMode(kDefaultElevateMode),
m_Edition(kUnregistered),
m_CryptoEnabled(false),
m_AutoHide(false),
m_LastExpiringWarningTime(0),
m_ActivationHasRun(),
m_MinimizeToTray(false),
m_ServerGroupChecked(),
m_UseExternalConfig(),
m_UseInternalConfig(),
m_ClientGroupChecked(),
m_LoadFromSystemScope() {
AppConfig::AppConfig() {
m_Config.registerReceiever(this);
load();
}
auto writer = ConfigWriter::make();
// Register this class to receive global load and saves
writer->registerClass(this);
// HACK: enable global load by default but allow it to be disabled for tests.
// when run in a test environment, this function causes a segfault.
if (globalLoad) {
writer->globalLoad();
}
void AppConfig::load() {
m_Config.loadAll();
// User settings exist and the load from system scope variable is true
if (writer->hasSetting(
settingName(Setting::kLoadSystemSettings), ConfigWriter::kUser)) {
if (m_Config.hasSetting(
settingName(Setting::kLoadSystemSettings), Config::Scope::User)) {
setLoadFromSystemScope(m_LoadFromSystemScope);
}
// If user setting don't exist but system ones do, load the system settings
else if (writer->hasSetting(
settingName(Setting::kScreenName), ConfigWriter::kSystem)) {
else if (m_Config.hasSetting(
settingName(Setting::kScreenName), Config::Scope::System)) {
setLoadFromSystemScope(true);
}
}
void AppConfig::applyAppSettings() const {
QApplication::setQuitOnLastWindowClosed(!m_MinimizeOnClose);
}
Config &AppConfig::config() { return m_Config; }
const QString &AppConfig::screenName() const { return m_ScreenName; }
int AppConfig::port() const { return m_Port; }
@ -141,18 +127,13 @@ bool AppConfig::logToFile() const { return m_LogToFile; }
const QString &AppConfig::logFilename() const { return m_LogFilename; }
QString AppConfig::synergyLogDir() const {
QString AppConfig::logDir() const {
// by default log to home dir
return QDir::home().absolutePath() + "/";
}
QString AppConfig::synergyProgramDir() const {
// synergy binaries should be in the same dir.
return QCoreApplication::applicationDirPath() + "/";
}
void AppConfig::persistLogDir() {
QDir dir = synergyLogDir();
void AppConfig::persistLogDir() const {
QDir dir = logDir();
// persist the log directory
if (!dir.exists()) {
@ -160,18 +141,11 @@ void AppConfig::persistLogDir() {
}
}
const QString AppConfig::logFilenameCmd() const {
QString filename = m_LogFilename;
#if defined(Q_OS_WIN)
// wrap in quotes in case username contains spaces.
filename = QString("\"%1\"").arg(filename);
#endif
return filename;
}
QString AppConfig::logLevelText() const { return logLevelNames[logLevel()]; }
ProcessMode AppConfig::processMode() const { return m_ProcessMode; }
ProcessMode AppConfig::processMode() const {
return m_ServiceEnabled ? ProcessMode::kService : ProcessMode::kDesktop;
}
bool AppConfig::wizardShouldRun() const {
return m_WizardLastRun < kWizardVersion;
@ -180,141 +154,137 @@ bool AppConfig::wizardShouldRun() const {
bool AppConfig::startedBefore() const { return m_StartedBefore; }
void AppConfig::loadSettings() {
using enum AppConfig::Setting;
m_ScreenName =
loadSetting(Setting::kScreenName, QHostInfo::localHostName()).toString();
loadSetting(kScreenName, QHostInfo::localHostName()).toString();
if (m_ScreenName.isEmpty()) {
m_ScreenName = QHostInfo::localHostName();
}
m_Port = loadSetting(Setting::kPort, 24800).toInt();
m_Interface = loadSetting(Setting::kInterfaceSetting).toString();
m_LogLevel = loadSetting(Setting::kLogLevel, 0).toInt();
m_LogToFile = loadSetting(Setting::kLogToFile, false).toBool();
m_Port = loadSetting(kPort, 24800).toInt();
m_Interface = loadSetting(kInterfaceSetting).toString();
m_LogLevel = loadSetting(kLogLevel, 0).toInt();
m_LogToFile = loadSetting(kLogToFile, false).toBool();
m_LogFilename =
loadSetting(Setting::kLogFilename, synergyLogDir() + "synergy.log")
.toString();
m_WizardLastRun = loadCommonSetting(Setting::kWizardLastRun, 0).toInt();
m_StartedBefore = loadSetting(Setting::kStartedBefore, false).toBool();
loadSetting(kLogFilename, logDir() + "synergy.log").toString();
m_WizardLastRun = loadCommonSetting(kWizardLastRun, 0).toInt();
m_StartedBefore = loadSetting(kStartedBefore, false).toBool();
{ // Scope related code together
// TODO Investigate why kElevateModeEnum isn't loaded fully
QVariant elevateMode = loadSetting(Setting::kElevateModeEnum);
if (!elevateMode.isValid()) {
elevateMode = loadSetting(
Setting::kElevateModeSetting,
QVariant(static_cast<int>(kDefaultElevateMode)));
}
m_ElevateMode = static_cast<ElevateMode>(elevateMode.toInt());
QVariant elevateMode = loadSetting(kElevateModeEnum);
if (!elevateMode.isValid()) {
elevateMode = loadSetting(
kElevateModeSetting, QVariant(static_cast<int>(kDefaultElevateMode)));
}
m_ElevateMode = static_cast<ElevateMode>(elevateMode.toInt());
m_ActivateEmail = loadSetting(Setting::kActivateEmail, "").toString();
m_CryptoEnabled = loadSetting(Setting::kCryptoEnabled, true).toBool();
m_AutoHide = loadSetting(Setting::kAutoHide, false).toBool();
m_lastVersion = loadSetting(Setting::kLastVersion, "Unknown").toString();
m_LastExpiringWarningTime =
loadSetting(Setting::kLastExpireWarningTime, 0).toInt();
m_ActivationHasRun = loadSetting(Setting::kActivationHasRun, false).toBool();
m_MinimizeToTray = loadSetting(Setting::kMinimizeToTray, false).toBool();
m_ActivateEmail = loadSetting(kActivateEmail, "").toString();
m_CryptoEnabled = loadSetting(kCryptoEnabled, true).toBool();
m_AutoHide = loadSetting(kAutoHide, false).toBool();
m_LastVersion = loadSetting(kLastVersion, "Unknown").toString();
m_LastExpiringWarningTime = loadSetting(kLastExpireWarningTime, 0).toInt();
m_ActivationHasRun = loadSetting(kActivationHasRun, false).toBool();
m_MinimizeToTray = loadSetting(kMinimizeToTray, false).toBool();
m_LoadFromSystemScope =
loadCommonSetting(Setting::kLoadSystemSettings, false).toBool();
m_ServerGroupChecked =
loadSetting(Setting::kGroupServerCheck, false).toBool();
m_UseExternalConfig =
loadSetting(Setting::kUseExternalConfig, false).toBool();
loadCommonSetting(kLoadSystemSettings, false).toBool();
m_ServerGroupChecked = loadSetting(kGroupServerCheck, false).toBool();
m_UseExternalConfig = loadSetting(kUseExternalConfig, false).toBool();
m_ConfigFile =
loadSetting(
Setting::kConfigFile, QDir::homePath() + "/" + m_SynergyConfigName)
loadSetting(kConfigFile, QDir::homePath() + "/" + m_ConfigFilename)
.toString();
m_UseInternalConfig =
loadSetting(Setting::kUseInternalConfig, false).toBool();
m_ClientGroupChecked =
loadSetting(Setting::kGroupClientCheck, false).toBool();
m_ServerHostname = loadSetting(Setting::kServerHostname).toString();
m_PreventSleep = loadSetting(Setting::kPreventSleep, false).toBool();
m_LanguageSync = loadSetting(Setting::kLanguageSync, false).toBool();
m_InvertScrollDirection =
loadSetting(Setting::kInvertScrollDirection, false).toBool();
m_guid = loadCommonSetting(Setting::kGuid, QUuid::createUuid()).toString();
m_licenseRegistryUrl = loadCommonSetting(
Setting::kLicenseRegistryUrl,
"https://api2.prod.symless.com/license/register")
.toString();
m_licenseNextCheck =
loadCommonSetting(Setting::kLicenseNextCheck, 0).toULongLong();
m_ClientHostMode = loadSetting(Setting::kClientHostMode, true).toBool();
m_ServerClientMode = loadSetting(Setting::kServerClientMode, true).toBool();
m_UseInternalConfig = loadSetting(kUseInternalConfig, false).toBool();
m_ClientGroupChecked = loadSetting(kGroupClientCheck, false).toBool();
m_ServerHostname = loadSetting(kServerHostname).toString();
m_PreventSleep = loadSetting(kPreventSleep, false).toBool();
m_LanguageSync = loadSetting(kLanguageSync, false).toBool();
m_InvertScrollDirection = loadSetting(kInvertScrollDirection, false).toBool();
m_Guid = loadCommonSetting(kGuid, QUuid::createUuid()).toString();
m_licenseNextCheck = loadCommonSetting(kLicenseNextCheck, 0).toULongLong();
m_ClientHostMode = loadSetting(kClientHostMode, true).toBool();
m_ServerClientMode = loadSetting(kServerClientMode, true).toBool();
m_InitiateConnectionFromServer =
loadSetting(Setting::kInitiateConnectionFromServer, false).toBool();
loadSetting(kInitiateConnectionFromServer, false).toBool();
// only change the serial key if the settings being loaded contains a key
bool updateSerial = ConfigWriter::make()->hasSetting(
settingName(Setting::kLoadSystemSettings), ConfigWriter::kCurrent);
bool updateSerial = m_Config.hasSetting(
settingName(kLoadSystemSettings), Config::Scope::Current);
// if the setting exists and is not empty
updateSerial =
updateSerial &&
!loadSetting(Setting::kSerialKey, "").toString().trimmed().isEmpty();
updateSerial = updateSerial &&
!loadSetting(kSerialKey, "").toString().trimmed().isEmpty();
if (updateSerial) {
m_Serialkey = loadSetting(Setting::kSerialKey, "").toString().trimmed();
m_Serialkey = loadSetting(kSerialKey, "").toString().trimmed();
m_Edition = static_cast<Edition>(
loadSetting(Setting::kEditionSetting, kUnregistered).toInt());
loadSetting(kEditionSetting, kUnregistered).toInt());
}
// Set the default path of the TLS certificate file in the users DIR
QString certificateFilename =
QString("%1/%2/%3")
.arg(m_CoreInterface.getProfileDir(), "SSL", "Synergy.pem");
m_ServiceEnabled = loadSetting(kServiceEnabled, m_ServiceEnabled).toBool();
m_TLSCertificatePath =
loadSetting(Setting::kTLSCertPath, certificateFilename).toString();
m_TLSKeyLength = loadSetting(Setting::kTLSKeyLength, "2048").toString();
try {
// Set the default path of the TLS certificate file in the users DIR
QString certificateFilename =
QString("%1/%2/%3")
.arg(m_CoreInterface.getProfileDir(), "SSL", "Synergy.pem");
if (getCryptoEnabled()) {
m_TlsCertPath = loadSetting(kTlsCertPath, certificateFilename).toString();
m_TlsKeyLength = loadSetting(kTlsKeyLength, "2048").toString();
} catch (const std::exception &e) {
qDebug() << e.what();
qFatal("Failed to get profile dir, unable to configure TLS");
}
if (cryptoEnabled()) {
generateCertificate();
}
applyAppSettings();
}
void AppConfig::saveSettings() {
setCommonSetting(Setting::kWizardLastRun, m_WizardLastRun);
setCommonSetting(Setting::kLoadSystemSettings, m_LoadFromSystemScope);
setCommonSetting(Setting::kGroupClientCheck, m_ClientGroupChecked);
setCommonSetting(Setting::kGroupServerCheck, m_ServerGroupChecked);
setCommonSetting(Setting::kGuid, m_guid);
setCommonSetting(Setting::kLicenseRegistryUrl, m_licenseRegistryUrl);
setCommonSetting(Setting::kLicenseNextCheck, m_licenseNextCheck);
using enum Setting;
setCommonSetting(kWizardLastRun, m_WizardLastRun);
setCommonSetting(kLoadSystemSettings, m_LoadFromSystemScope);
setCommonSetting(kGroupClientCheck, m_ClientGroupChecked);
setCommonSetting(kGroupServerCheck, m_ServerGroupChecked);
setCommonSetting(kGuid, m_Guid);
setCommonSetting(kLicenseNextCheck, m_licenseNextCheck);
if (isWritable()) {
setSetting(Setting::kScreenName, m_ScreenName);
setSetting(Setting::kPort, m_Port);
setSetting(Setting::kInterfaceSetting, m_Interface);
setSetting(Setting::kLogLevel, m_LogLevel);
setSetting(Setting::kLogToFile, m_LogToFile);
setSetting(Setting::kLogFilename, m_LogFilename);
setSetting(Setting::kStartedBefore, m_StartedBefore);
// Refer to enum ElevateMode declaration for insight in to why this
// flag is mapped this way
setSetting(Setting::kElevateModeSetting, m_ElevateMode == ElevateAlways);
setSetting(Setting::kElevateModeEnum, static_cast<int>(m_ElevateMode));
setSetting(Setting::kEditionSetting, m_Edition);
setSetting(Setting::kCryptoEnabled, m_CryptoEnabled);
setSetting(Setting::kAutoHide, m_AutoHide);
setSetting(Setting::kSerialKey, m_Serialkey);
setSetting(Setting::kLastVersion, m_lastVersion);
setSetting(Setting::kLastExpireWarningTime, m_LastExpiringWarningTime);
setSetting(Setting::kActivationHasRun, m_ActivationHasRun);
setSetting(Setting::kMinimizeToTray, m_MinimizeToTray);
setSetting(Setting::kUseExternalConfig, m_UseExternalConfig);
setSetting(Setting::kConfigFile, m_ConfigFile);
setSetting(Setting::kUseInternalConfig, m_UseInternalConfig);
setSetting(Setting::kServerHostname, m_ServerHostname);
setSetting(Setting::kPreventSleep, m_PreventSleep);
setSetting(Setting::kLanguageSync, m_LanguageSync);
setSetting(Setting::kInvertScrollDirection, m_InvertScrollDirection);
setSetting(Setting::kClientHostMode, m_ClientHostMode);
setSetting(Setting::kServerClientMode, m_ServerClientMode);
setSetting(kScreenName, m_ScreenName);
setSetting(kPort, m_Port);
setSetting(kInterfaceSetting, m_Interface);
setSetting(kLogLevel, m_LogLevel);
setSetting(kLogToFile, m_LogToFile);
setSetting(kLogFilename, m_LogFilename);
setSetting(kStartedBefore, m_StartedBefore);
setSetting(kElevateModeEnum, static_cast<int>(m_ElevateMode));
setSetting(kEditionSetting, m_Edition);
setSetting(kCryptoEnabled, m_CryptoEnabled);
setSetting(kAutoHide, m_AutoHide);
setSetting(kSerialKey, m_Serialkey);
setSetting(kLastVersion, m_LastVersion);
setSetting(kLastExpireWarningTime, m_LastExpiringWarningTime);
setSetting(kActivationHasRun, m_ActivationHasRun);
setSetting(kMinimizeToTray, m_MinimizeToTray);
setSetting(kUseExternalConfig, m_UseExternalConfig);
setSetting(kConfigFile, m_ConfigFile);
setSetting(kUseInternalConfig, m_UseInternalConfig);
setSetting(kServerHostname, m_ServerHostname);
setSetting(kPreventSleep, m_PreventSleep);
setSetting(kLanguageSync, m_LanguageSync);
setSetting(kInvertScrollDirection, m_InvertScrollDirection);
setSetting(kClientHostMode, m_ClientHostMode);
setSetting(kServerClientMode, m_ServerClientMode);
setSetting(kServiceEnabled, m_ServiceEnabled);
setSetting(kMinimizeOnClose, m_MinimizeOnClose);
// See enum ElevateMode declaration to understand why this setting is bool
setSetting(kElevateModeSetting, m_ElevateMode == ElevateAlways);
}
m_unsavedChanges = false;
setModified(false);
applyAppSettings();
}
#ifdef SYNERGY_ENABLE_LICENSING
@ -326,10 +296,10 @@ AppConfig &AppConfig::activationHasRun(bool value) {
}
#endif
QString AppConfig::lastVersion() const { return m_lastVersion; }
QString AppConfig::lastVersion() const { return m_LastVersion; }
void AppConfig::setLastVersion(const QString &version) {
setSettingModified(m_lastVersion, version);
setSettingModified(m_LastVersion, version);
}
void AppConfig::setScreenName(const QString &s) {
@ -389,9 +359,9 @@ void AppConfig::setLastExpiringWarningTime(int newValue) {
}
#endif
QString AppConfig::synergysName() const { return m_SynergysName; }
QString AppConfig::coreServerName() const { return m_CoreServerName; }
QString AppConfig::synergycName() const { return m_SynergycName; }
QString AppConfig::coreClientName() const { return m_CoreClientName; }
ElevateMode AppConfig::elevateMode() { return m_ElevateMode; }
@ -404,7 +374,7 @@ void AppConfig::setCryptoEnabled(bool newValue) {
setSettingModified(m_CryptoEnabled, newValue);
}
bool AppConfig::isCryptoAvailable() const {
bool AppConfig::cryptoAvailable() const {
bool result{true};
#ifdef SYNERGY_ENABLE_LICENSING
@ -416,19 +386,19 @@ bool AppConfig::isCryptoAvailable() const {
return result;
}
bool AppConfig::getCryptoEnabled() const {
return isCryptoAvailable() && m_CryptoEnabled;
bool AppConfig::cryptoEnabled() const {
return cryptoAvailable() && m_CryptoEnabled;
}
void AppConfig::setAutoHide(bool b) { setSettingModified(m_AutoHide, b); }
bool AppConfig::getAutoHide() { return m_AutoHide; }
bool AppConfig::autoHide() { return m_AutoHide; }
void AppConfig::setMinimizeToTray(bool newValue) {
setSettingModified(m_MinimizeToTray, newValue);
}
bool AppConfig::getInvertScrollDirection() const {
bool AppConfig::invertScrollDirection() const {
return m_InvertScrollDirection;
}
@ -436,17 +406,13 @@ void AppConfig::setLicenseNextCheck(unsigned long long time) {
setSettingModified(m_licenseNextCheck, time);
}
const QString &AppConfig::getLicenseRegistryUrl() const {
return m_licenseRegistryUrl;
}
unsigned long long AppConfig::getLicenseNextCheck() const {
unsigned long long AppConfig::licenseNextCheck() const {
return m_licenseNextCheck;
}
const QString &AppConfig::getGuid() const { return m_guid; }
const QString &AppConfig::guid() const { return m_Guid; }
bool AppConfig::getLanguageSync() const { return m_LanguageSync; }
bool AppConfig::languageSync() const { return m_LanguageSync; }
void AppConfig::setInvertScrollDirection(bool newValue) {
setSettingModified(m_InvertScrollDirection, newValue);
@ -456,17 +422,17 @@ void AppConfig::setLanguageSync(bool newValue) {
setSettingModified(m_LanguageSync, newValue);
}
bool AppConfig::getPreventSleep() const { return m_PreventSleep; }
bool AppConfig::preventSleep() const { return m_PreventSleep; }
bool AppConfig::getClientHostMode() const {
return (m_ClientHostMode && getInitiateConnectionFromServer());
bool AppConfig::clientHostMode() const {
return (m_ClientHostMode && initiateConnectionFromServer());
}
bool AppConfig::getServerClientMode() const {
return (m_ServerClientMode && getInitiateConnectionFromServer());
bool AppConfig::serverClientMode() const {
return (m_ServerClientMode && initiateConnectionFromServer());
}
bool AppConfig::getInitiateConnectionFromServer() const {
bool AppConfig::initiateConnectionFromServer() const {
return m_InitiateConnectionFromServer;
}
@ -474,57 +440,53 @@ void AppConfig::setPreventSleep(bool newValue) {
setSettingModified(m_PreventSleep, newValue);
}
bool AppConfig::getMinimizeToTray() { return m_MinimizeToTray; }
bool AppConfig::minimizeToTray() { return m_MinimizeToTray; }
QString AppConfig::settingName(Setting name) {
auto index = static_cast<int>(name);
return m_SynergySettingsName[index];
return m_SettingsName[index];
}
template <typename T> void AppConfig::setSetting(Setting name, T value) {
ConfigWriter::make()->setSetting(settingName(name), value);
m_Config.setSetting(settingName(name), value);
}
template <typename T> void AppConfig::setCommonSetting(Setting name, T value) {
ConfigWriter::make()->setSetting(
settingName(name), value, ConfigWriter::kUser);
ConfigWriter::make()->setSetting(
settingName(name), value, ConfigWriter::kSystem);
m_Config.setSetting(settingName(name), value, Config::Scope::User);
m_Config.setSetting(settingName(name), value, Config::Scope::System);
}
QVariant AppConfig::loadSetting(Setting name, const QVariant &defaultValue) {
return ConfigWriter::make()->loadSetting(settingName(name), defaultValue);
return m_Config.loadSetting(settingName(name), defaultValue);
}
QVariant
AppConfig::loadCommonSetting(Setting name, const QVariant &defaultValue) const {
QVariant result(defaultValue);
QString setting(settingName(name));
auto &writer = *ConfigWriter::make();
if (writer.hasSetting(setting)) {
result = writer.loadSetting(setting, defaultValue);
} else if (writer.getScope() == ConfigWriter::kSystem) {
if (writer.hasSetting(setting, ConfigWriter::kUser)) {
result = writer.loadSetting(setting, defaultValue, ConfigWriter::kUser);
if (m_Config.hasSetting(setting)) {
result = m_Config.loadSetting(setting, defaultValue);
} else if (m_Config.getScope() == Config::Scope::System) {
if (m_Config.hasSetting(setting, Config::Scope::User)) {
result = m_Config.loadSetting(setting, defaultValue, Config::Scope::User);
}
} else if (writer.hasSetting(setting, ConfigWriter::kSystem)) {
result = writer.loadSetting(setting, defaultValue, ConfigWriter::kSystem);
} else if (m_Config.hasSetting(setting, Config::Scope::System)) {
result = m_Config.loadSetting(setting, defaultValue, Config::Scope::System);
}
return result;
}
void AppConfig::loadScope(ConfigWriter::Scope scope) {
auto writer = ConfigWriter::make();
void AppConfig::loadScope(Config::Scope scope) {
if (writer->getScope() != scope) {
if (m_Config.getScope() != scope) {
setDefaultValues();
writer->setScope(scope);
if (writer->hasSetting(
settingName(Setting::kScreenName), writer->getScope())) {
m_Config.setScope(scope);
if (m_Config.hasSetting(
settingName(Setting::kScreenName), m_Config.getScope())) {
// If the user already has settings, then load them up now.
writer->globalLoad();
m_Config.loadAll();
}
}
}
@ -534,9 +496,9 @@ void AppConfig::setDefaultValues() { m_InitiateConnectionFromServer = false; }
void AppConfig::setLoadFromSystemScope(bool value) {
if (value) {
loadScope(ConfigWriter::kSystem);
loadScope(Config::Scope::System);
} else {
loadScope(ConfigWriter::kUser);
loadScope(Config::Scope::User);
}
/*
@ -546,25 +508,23 @@ void AppConfig::setLoadFromSystemScope(bool value) {
m_LoadFromSystemScope = value;
}
bool AppConfig::isWritable() const {
return ConfigWriter::make()->isWritable();
}
bool AppConfig::isWritable() const { return m_Config.isWritable(); }
bool AppConfig::isSystemScoped() const {
return ConfigWriter::make()->getScope() == ConfigWriter::kSystem;
return m_Config.getScope() == Config::Scope::System;
}
bool AppConfig::getServerGroupChecked() const { return m_ServerGroupChecked; }
bool AppConfig::serverGroupChecked() const { return m_ServerGroupChecked; }
bool AppConfig::getUseExternalConfig() const { return m_UseExternalConfig; }
bool AppConfig::useExternalConfig() const { return m_UseExternalConfig; }
const QString &AppConfig::getConfigFile() const { return m_ConfigFile; }
const QString &AppConfig::configFile() const { return m_ConfigFile; }
bool AppConfig::getUseInternalConfig() const { return m_UseInternalConfig; }
bool AppConfig::useInternalConfig() const { return m_UseInternalConfig; }
bool AppConfig::getClientGroupChecked() const { return m_ClientGroupChecked; }
bool AppConfig::clientGroupChecked() const { return m_ClientGroupChecked; }
QString AppConfig::getServerHostname() const { return m_ServerHostname; }
QString AppConfig::serverHostname() const { return m_ServerHostname; }
void AppConfig::setServerGroupChecked(bool newValue) {
setSettingModified(m_ServerGroupChecked, newValue);
@ -602,28 +562,43 @@ template <typename T>
void AppConfig::setSettingModified(T &variable, const T &newValue) {
if (variable != newValue) {
variable = newValue;
m_unsavedChanges = true;
setModified(true);
}
}
void AppConfig::setTLSCertPath(const QString &path) {
m_TLSCertificatePath = path;
}
void AppConfig::setTlsCertPath(const QString &path) { m_TlsCertPath = path; }
QString AppConfig::getTLSCertPath() const { return m_TLSCertificatePath; }
QString AppConfig::tlsCertPath() const { return m_TlsCertPath; }
QString AppConfig::getTLSKeyLength() const { return m_TLSKeyLength; }
QString AppConfig::tlsKeyLength() const { return m_TlsKeyLength; }
void AppConfig::setTLSKeyLength(const QString &length) {
if (m_TLSKeyLength != length) {
m_TLSKeyLength = length;
void AppConfig::setTlsKeyLength(const QString &length) {
if (m_TlsKeyLength != length) {
m_TlsKeyLength = length;
generateCertificate(true);
}
}
void AppConfig::generateCertificate(bool forceGeneration) const {
SslCertificate sslCertificate;
sslCertificate.generateCertificate(
getTLSCertPath(), getTLSKeyLength(), forceGeneration);
emit sslToggled();
try {
SslCertificate sslCertificate;
sslCertificate.generateCertificate(
tlsCertPath(), tlsKeyLength(), forceGeneration);
emit sslToggled();
} catch (const std::exception &e) {
qDebug() << e.what();
qFatal("Failed to configure TLS");
}
}
void AppConfig::setServiceEnabled(bool enabled) {
setSettingModified(m_ServiceEnabled, enabled);
}
bool AppConfig::serviceEnabled() const { return m_ServiceEnabled; }
void AppConfig::setMinimizeOnClose(bool minimize) {
setSettingModified(m_MinimizeOnClose, minimize);
}
bool AppConfig::minimizeOnClose() const { return m_MinimizeOnClose; }

View File

@ -1,6 +1,6 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2012 Symless Ltd.
* Copyright (C) 2008 Volker Lanz (vl@fidra.de)
*
* This package is free software; you can redistribute it and/or
@ -16,165 +16,122 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#if !defined(APPCONFIG_H)
#pragma once
#define APPCONFIG_H
#include "ConfigBase.h"
#include "ConfigWriter.h"
#include "CommonConfig.h"
#include "Config.h"
#include "CoreInterface.h"
#include "ElevateMode.h"
#include "LicenseManager.h"
#include "shared/EditionType.h"
#include <QObject>
#include <QString>
#include <QVariant>
#include <mutex>
#include <shared/EditionType.h>
// this should be incremented each time a new page is added. this is
// saved to settings when the user finishes running the wizard. if
// the saved wizard version is lower than this number, the wizard
// will be displayed. each version incrememnt should be described
// here...
//
// 1: first version
// 2: added language page
// 3: added premium page and removed
// 4: ssl plugin 'ns' v1.0
// 5: ssl plugin 'ns' v1.1
// 6: ssl plugin 'ns' v1.2
// 7: serial key activation
// 8: Visual Studio 2015 support
//
const int kWizardVersion = 8;
class QSettings;
class SettingsDialog;
class ServerConfig;
class LicenseRegister;
class ServerConfig;
class LicenseManager;
class ActivationDialog;
class LicenseRegistry;
enum class ProcessMode { kService, kDesktop };
class AppConfig : public QObject, public GUI::Config::ConfigBase {
const ElevateMode kDefaultElevateMode = ElevateAsNeeded;
#if defined(Q_OS_WIN)
const ProcessMode kDefaultProcessMode = ProcessMode::kService;
#else
const ProcessMode kDefaultProcessMode = ProcessMode::kDesktop;
#endif
/// @brief Reads and writes application specific settings
class AppConfig : public QObject, public synergy::gui::CommonConfig {
Q_OBJECT
friend class SettingsDialog;
friend class MainWindow;
friend class SetupWizard;
friend class ServerConfig;
friend class LicenseManager;
friend class ActivationDialog;
friend class LicenseRegistry;
public:
explicit AppConfig(bool globalLoad = true);
explicit AppConfig();
/// @brief Underlying configuration reader/writer
synergy::gui::Config &config();
void saveSettings() override;
void applyAppSettings() const;
/// @brief Generates TLS certificate
/// @param [in] bool forceGeneration Generate certificate even if it's exists.
void generateCertificate(bool forceGeneration = false) const;
/**
* Getters
*/
bool isWritable() const;
bool isSystemScoped() const;
const QString &screenName() const;
int port() const;
const QString &networkInterface() const;
int logLevel() const;
bool logToFile() const;
const QString &logFilename() const;
const QString logFilenameCmd() const;
QString logLevelText() const;
ProcessMode processMode() const;
bool wizardShouldRun() const;
bool startedBefore() const;
#ifdef SYNERGY_ENABLE_LICENSING
void setEdition(Edition);
Edition edition() const;
void setSerialKey(const QString &serial);
void clearSerialKey();
QString serialKey() const;
int lastExpiringWarningTime() const;
void setLastExpiringWarningTime(int t);
#endif
QString synergysName() const;
QString synergycName() const;
QString synergyProgramDir() const;
QString synergyLogDir() const;
void persistLogDir();
QString coreServerName() const;
QString coreClientName() const;
QString logDir() const;
void persistLogDir() const;
ElevateMode elevateMode();
bool isCryptoAvailable() const;
void setCryptoEnabled(bool e);
bool getCryptoEnabled() const;
void setAutoHide(bool b);
bool getAutoHide();
void setInvertScrollDirection(bool b);
bool getInvertScrollDirection() const;
void setLicenseNextCheck(unsigned long long);
const QString &getLicenseRegistryUrl() const;
unsigned long long getLicenseNextCheck() const;
const QString &getGuid() const;
void setLanguageSync(bool b);
bool getLanguageSync() const;
void setPreventSleep(bool b);
bool getPreventSleep() const;
bool getClientHostMode() const;
bool getServerClientMode() const;
bool getInitiateConnectionFromServer() const;
#ifdef SYNERGY_ENABLE_LICENSING
bool activationHasRun() const;
AppConfig &activationHasRun(bool value);
#endif
/// @brief Sets the user preference to load from SystemScope.
/// @param [in] value
/// True - This will set the variable and load the global scope
/// settings. False - This will set the variable and load the user
/// scope settings.
void setLoadFromSystemScope(bool value);
bool getServerGroupChecked() const;
bool getUseExternalConfig() const;
const QString &getConfigFile() const;
bool getUseInternalConfig() const;
bool getClientGroupChecked() const;
QString getServerHostname() const;
bool cryptoAvailable() const;
bool cryptoEnabled() const;
bool autoHide();
bool invertScrollDirection() const;
unsigned long long licenseNextCheck() const;
const QString &guid() const;
bool languageSync() const;
bool preventSleep() const;
bool clientHostMode() const;
bool serverClientMode() const;
bool initiateConnectionFromServer() const;
bool serverGroupChecked() const;
bool useExternalConfig() const;
const QString &configFile() const;
bool useInternalConfig() const;
bool clientGroupChecked() const;
QString serverHostname() const;
QString lastVersion() const;
bool serviceEnabled() const;
bool minimizeToTray();
bool minimizeOnClose() const;
/// @brief Gets the current TLS certificate path
/// @return QString The path to the cert
QString getTLSCertPath() const;
QString tlsCertPath() const;
/// @brief Get the key length to be used for the private key of a TLS cert
/// @return QString The key length in bits
QString getTLSKeyLength() const;
QString tlsKeyLength() const;
void setServerGroupChecked(bool);
void setUseExternalConfig(bool);
void setConfigFile(const QString &);
void setUseInternalConfig(bool);
void setClientGroupChecked(bool);
void setServerHostname(const QString &);
void setClientHostMode(bool newValue);
void setServerClientMode(bool newValue);
/// @brief Set the path to the TLS/SSL certificate file that will be used
/// @param [in] path The path to the Certificate
void setTLSCertPath(const QString &path);
/// @brief Sets the key length of the private key to use in a TLS connection
/// @param [in] QString length The key length eg: 1024, 2048, 4096
void setTLSKeyLength(const QString &length);
QString lastVersion() const;
void setMinimizeToTray(bool b);
bool getMinimizeToTray();
void saveSettings() override;
void setLastVersion(const QString &version);
/// @brief Generates TLS certificate
/// @param [in] bool forceGeneration Generate certificate even if it's exists.
void generateCertificate(bool forceGeneration = false) const;
#ifdef SYNERGY_ENABLE_LICENSING
Edition edition() const;
QString serialKey() const;
int lastExpiringWarningTime() const;
bool activationHasRun() const;
#endif
protected:
/// @brief The enumeration to easily access the names of the setting inside
/// m_SynergySettingsName
enum class Setting {
kScreenName,
kPort,
@ -202,8 +159,8 @@ protected:
kUseInternalConfig,
kGroupClientCheck,
kServerHostname,
kTLSCertPath,
kTLSKeyLength,
kTlsCertPath,
kTlsKeyLength,
kPreventSleep,
kLanguageSync,
kInvertScrollDirection,
@ -212,9 +169,20 @@ protected:
kLicenseNextCheck,
kInitiateConnectionFromServer,
kClientHostMode,
kServerClientMode
kServerClientMode,
kServiceEnabled,
kMinimizeOnClose
};
static QString settingName(AppConfig::Setting name);
/// @brief Loads the setting from the current scope
void loadSettings() override;
/**
* Setters
*/
void setScreenName(const QString &s);
void setPort(int i);
void setNetworkInterface(const QString &s);
@ -224,70 +192,48 @@ protected:
void setWizardHasRun();
void setStartedBefore(bool b);
void setElevateMode(ElevateMode em);
void setCryptoEnabled(bool e);
void setEdition(Edition);
void setSerialKey(const QString &serial);
void clearSerialKey();
void setLastExpiringWarningTime(int t);
void setAutoHide(bool b);
void setInvertScrollDirection(bool b);
void setLicenseNextCheck(unsigned long long);
void setLanguageSync(bool b);
void setPreventSleep(bool b);
void setServerGroupChecked(bool);
void setUseExternalConfig(bool);
void setConfigFile(const QString &);
void setUseInternalConfig(bool);
void setClientGroupChecked(bool);
void setServerHostname(const QString &);
void setClientHostMode(bool newValue);
void setServerClientMode(bool newValue);
AppConfig &activationHasRun(bool value);
void setMinimizeToTray(bool b);
void setLastVersion(const QString &version);
void setServiceEnabled(bool enabled);
void setMinimizeOnClose(bool minimize);
/// @brief loads the setting from the current scope
/// @param ignoreSystem should the load feature ignore the globalScope setting
/// that was saved
void loadSettings() override;
static QString settingName(AppConfig::Setting name);
/// @brief Sets the user preference to load from SystemScope.
/// @param [in] value
/// True - This will set the variable and load the global scope
/// settings. False - This will set the variable and load the user
/// scope settings.
void setLoadFromSystemScope(bool value);
/// @brief Set the path to the TLS/SSL certificate file that will be used
/// @param [in] path The path to the Certificate
void setTlsCertPath(const QString &path);
/// @brief Sets the key length of the private key to use in a TLS connection
/// @param [in] QString length The key length eg: 1024, 2048, 4096
void setTlsKeyLength(const QString &length);
private:
QString m_ScreenName;
int m_Port;
QString m_Interface;
int m_LogLevel;
bool m_LogToFile;
QString m_LogFilename;
int m_WizardLastRun;
ProcessMode m_ProcessMode;
bool m_StartedBefore;
ElevateMode m_ElevateMode;
Edition m_Edition;
QString m_ActivateEmail;
bool m_CryptoEnabled;
bool m_AutoHide;
QString m_Serialkey;
QString m_lastVersion;
QString m_guid;
QString m_licenseRegistryUrl;
unsigned long long m_licenseNextCheck;
int m_LastExpiringWarningTime;
bool m_ActivationHasRun;
bool m_MinimizeToTray;
bool m_InvertScrollDirection = false;
bool m_LanguageSync = true;
bool m_PreventSleep = false;
bool m_InitiateConnectionFromServer = false;
bool m_ClientHostMode = true;
bool m_ServerClientMode = true;
bool m_ServerGroupChecked;
bool m_UseExternalConfig;
QString m_ConfigFile;
bool m_UseInternalConfig;
bool m_ClientGroupChecked;
QString m_ServerHostname;
QString m_TLSCertificatePath; /// @brief The path to the TLS certificate file
QString m_TLSKeyLength; /// @brief The key length of the TLS cert to make
bool m_LoadFromSystemScope; /// @brief should the setting be loaded from
/// SystemScope
/// If the user has settings but this is
/// true then system settings will be
/// loaded instead of the users
CoreInterface m_CoreInterface;
static const char m_SynergysName[];
static const char m_SynergycName[];
static const char m_SynergyLogDir[];
/// @brief Contains the string values of the settings names that will be saved
static const char *m_SynergySettingsName[];
/// @brief Contains the name of the default configuration filename
static const char m_SynergyConfigName[];
/// @brief Loads config from the underlying reader/writer
void load();
/// @brief Sets the value of a setting
/// @param [in] name The Setting to be saved
@ -312,12 +258,6 @@ private:
QVariant loadCommonSetting(
AppConfig::Setting name, const QVariant &defaultValue = QVariant()) const;
/// @brief As the settings will be accessible by multiple objects this lock
/// will ensure that
/// it cant be modified by more that one object at a time if the
/// setting is being switched from system to user.
std::mutex m_settings_lock;
/// @brief Sets the setting in the config checking if it has changed and
/// flagging that settings
/// needs to be saved if the setting was different
@ -327,15 +267,79 @@ private:
/// @brief This method loads config from specified scope
/// @param [in] scope which should be loaded.
void loadScope(GUI::Config::ConfigWriter::Scope scope);
void loadScope(synergy::gui::Config::Scope scope);
/// @brief This function sets default values
/// for settings that shouldn't be copied from between scopes.
void setDefaultValues();
synergy::gui::Config m_Config;
CoreInterface m_CoreInterface;
QString m_ScreenName = "";
int m_Port = 24800;
QString m_Interface = "";
int m_LogLevel = 0;
bool m_LogToFile = false;
QString m_LogFilename = "";
int m_WizardLastRun = 0;
bool m_StartedBefore = false;
ElevateMode m_ElevateMode = kDefaultElevateMode;
Edition m_Edition = Edition::kUnregistered;
QString m_ActivateEmail = "";
bool m_CryptoEnabled = false;
bool m_AutoHide = false;
QString m_Serialkey = "";
QString m_LastVersion = "";
QString m_Guid = "";
unsigned long long m_licenseNextCheck = 0;
int m_LastExpiringWarningTime = 0;
bool m_ActivationHasRun = false;
bool m_MinimizeToTray = true;
bool m_InvertScrollDirection = false;
bool m_LanguageSync = true;
bool m_PreventSleep = false;
bool m_InitiateConnectionFromServer = false;
bool m_ClientHostMode = true;
bool m_ServerClientMode = true;
bool m_ServerGroupChecked = false;
bool m_UseExternalConfig = false;
QString m_ConfigFile = "";
bool m_UseInternalConfig = false;
bool m_ClientGroupChecked = false;
QString m_ServerHostname = "";
bool m_ServiceEnabled = kDefaultProcessMode == ProcessMode::kService;
bool m_MinimizeOnClose = true;
/// @brief The path to the TLS certificate file
QString m_TlsCertPath = "";
/// @brief The key length of the TLS cert to make
QString m_TlsKeyLength = "";
/// @brief should the setting be loaded from
/// SystemScope
/// If the user has settings but this is
/// true then system settings will be
/// loaded instead of the users
bool m_LoadFromSystemScope = false;
/// @brief As the settings will be accessible by multiple objects this lock
/// will ensure that
/// it cant be modified by more that one object at a time if the
/// setting is being switched from system to user.
std::mutex m_settings_lock;
static const char m_CoreServerName[];
static const char m_CoreClientName[];
static const char m_LogDir[];
/// @brief Contains the string values of the settings names that will be saved
static const char *const m_SettingsName[];
/// @brief Contains the name of the default configuration filename
static const char m_ConfigFilename[];
signals:
void sslToggled() const;
void screenNameChanged() const;
};
#endif

View File

@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>400</width>
<height>165</height>
<height>246</height>
</rect>
</property>
<property name="windowTitle">
@ -17,9 +17,7 @@
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Are you sure?
If you don't activate Synergy you'll be missing out on some great features.</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;You'll need to purchase a license to use this build of Synergy.&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://symless.com/synergy/purchase?source=gui&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#007af4;&quot;&gt;Purchase Synergy&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;If you'd prefer to use the community edition instead, visit us on GitHub.&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/symless/synergy-core&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#007af4;&quot;&gt;GitHub project&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;Would you like to go back and enter a serial key?&lt;/p&gt;&lt;p&gt;Choosing 'No' will quit Synergy.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="wordWrap">
<bool>true</bool>
@ -30,14 +28,17 @@ If you don't activate Synergy you'll be missing out on some great features.</str
</widget>
</item>
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;https://symless.com/pricing?source=gui&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;Buy now&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="openExternalLinks">
<bool>true</bool>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</widget>
</spacer>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">

View File

@ -59,13 +59,13 @@ QString ClientConnection::getMessage(const QString &line) const {
message =
QObject::tr("Connection failed.\nYou cant name 2 computers the same.");
} else {
QHostAddress address(m_parent.appConfig().getServerHostname());
QHostAddress address(m_parent.appConfig().serverHostname());
if (address.isNull()) {
message =
QObject::tr(
"We cant connect to the server \"%1\" try to connect using the "
"server IP address and check your firewall settings.")
.arg(m_parent.appConfig().getServerHostname());
.arg(m_parent.appConfig().serverHostname());
}
}

View File

@ -18,7 +18,6 @@
#include "CommandProcess.h"
#include <QProcess>
#include <stdexcept>
CommandProcess::CommandProcess(
QString cmd, QStringList arguments, QString input)
@ -32,7 +31,8 @@ QString CommandProcess::run() {
process.start(m_Command, m_Arguments);
bool success = process.waitForStarted();
QString output, error;
QString output;
QString error;
if (success) {
if (!m_Input.isEmpty()) {
process.write(m_Input.toStdString().c_str());
@ -45,12 +45,11 @@ QString CommandProcess::run() {
}
}
int code = process.exitCode();
if (!error.isEmpty() || !success || code != 0) {
throw std::runtime_error(QString("Code: %1\nError: %2")
.arg(process.exitCode())
.arg(error.isEmpty() ? "Unknown" : error)
.toStdString());
if (int code = process.exitCode(); !success || code != 0) {
qFatal(
"Command failed: %s %s\nCode: %d\nError: %s", qUtf8Printable(m_Command),
qUtf8Printable(m_Arguments.join(" ")), code,
error.isEmpty() ? "None" : qUtf8Printable(error));
}
emit finished();

View File

@ -0,0 +1,36 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2020 Symless Ltd.
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* 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/>.
*/
#pragma once
namespace synergy::gui {
/// @brief Common configuration interface
class CommonConfig {
public:
CommonConfig() = default;
virtual ~CommonConfig() = default;
virtual void loadSettings() = 0;
virtual void saveSettings() = 0;
bool modified() const { return m_modified; }
void setModified(bool modified) { m_modified = modified; }
private:
bool m_modified = false;
};
} // namespace synergy::gui

View File

@ -1,6 +1,6 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2020-2020 Symless Ltd.
* Copyright (C) 2020 Symless Ltd.
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -15,21 +15,21 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <cassert>
#include "Config.h"
#include "CommonConfig.h"
#include <QCoreApplication>
#include <QFile>
#include <cassert>
#include <memory>
#include "ConfigBase.h"
#include "ConfigWriter.h"
namespace {
namespace synergy::gui {
QString getSystemSettingPath() {
const QString settingFilename("SystemConfig.ini");
QString path;
#if defined(Q_OS_WIN)
// Program file
path = QCoreApplication::applicationDirPath() + "\\";
#elif defined(Q_OS_DARWIN)
// Global preferances dir
@ -46,7 +46,7 @@ QString getSystemSettingPath() {
}
#if defined(Q_OS_WIN)
void loadOldSystemSettings(QSettings &settings) {
void loadWindowsLegacy(QSettings &settings) {
if (!QFile(settings.fileName()).exists()) {
QSettings::setPath(
QSettings::IniFormat, QSettings::SystemScope, "SystemConfig.ini");
@ -68,147 +68,114 @@ void loadOldSystemSettings(QSettings &settings) {
}
#endif
} // namespace
namespace GUI {
namespace Config {
// Assignment of static variable
ConfigWriter *ConfigWriter::s_pConfiguration = nullptr;
ConfigWriter *ConfigWriter::make() {
// Only one ConfigWriter can exist at any one time (Singleton)
if (!s_pConfiguration) {
s_pConfiguration = new ConfigWriter();
}
return s_pConfiguration;
}
ConfigWriter::ConfigWriter() {
Config::Config() {
QSettings::setPath(
QSettings::Format::IniFormat, QSettings::Scope::SystemScope,
getSystemSettingPath());
// Config will default to User settings if they exist,
// otherwise it will load System setting and save them to User settings
m_pSettingsSystem = new QSettings(
m_pSystemSettings = std::make_unique<QSettings>(
QSettings::Format::IniFormat, QSettings::Scope::SystemScope,
QCoreApplication::organizationName(),
QCoreApplication::applicationName());
// default to user scope.
// if we set the scope specifically then we also have to set the application
// name and the organisation name which breaks backwards compatibility.
m_pUserSettings = std::make_unique<QSettings>();
load();
}
Config::~Config() {
while (!m_pReceievers.empty()) {
m_pReceievers.pop_back();
}
}
void Config::load() {
#if defined(Q_OS_WIN)
// This call is needed for backwardcapability with old settings.
loadOldSystemSettings(*m_pSettingsSystem);
loadWindowsLegacy(*m_pSystemSettings);
#endif
// defaults to user scope, if we set the scope specifically then we also have
// to set
// the application name and the organisation name which breaks backwards
// compatibility See #6730
m_pSettingsUser = new QSettings();
// Set scope to user for initially
m_pSettingsCurrent = m_pSettingsUser;
}
void ConfigWriter::destroy() { destroy(s_pConfiguration); }
ConfigWriter::~ConfigWriter() {
while (!m_pCallerList.empty()) {
m_pCallerList.pop_back();
}
m_pSettingsCurrent = nullptr; // this only references other pointers
destroy(m_pSettingsSystem);
destroy(m_pSettingsUser);
}
bool ConfigWriter::hasSetting(const QString &name, Scope scope) const {
bool Config::hasSetting(const QString &name, Scope scope) const {
switch (scope) {
case kUser:
return m_pSettingsUser->contains(name);
case kSystem:
return m_pSettingsSystem->contains(name);
case Scope::User:
return m_pUserSettings->contains(name);
case Scope::System:
return m_pSystemSettings->contains(name);
default:
return m_pSettingsCurrent->contains(name);
return currentSettings()->contains(name);
}
}
bool ConfigWriter::isWritable() const {
return m_pSettingsCurrent->isWritable();
}
bool Config::isWritable() const { return currentSettings()->isWritable(); }
QVariant ConfigWriter::loadSetting(
const QString &name, const QVariant &defaultValue, Scope scope) {
QVariant Config::loadSetting(
const QString &name, const QVariant &defaultValue, Scope scope) const {
switch (scope) {
case kUser:
return m_pSettingsUser->value(name, defaultValue);
case kSystem:
return m_pSettingsSystem->value(name, defaultValue);
case Scope::User:
return m_pUserSettings->value(name, defaultValue);
case Scope::System:
return m_pSystemSettings->value(name, defaultValue);
default:
return m_pSettingsCurrent->value(name, defaultValue);
return currentSettings()->value(name, defaultValue);
}
}
void ConfigWriter::setScope(ConfigWriter::Scope scope) {
if (m_CurrentScope != scope) {
m_CurrentScope = scope;
switch (scope) {
case kUser:
m_pSettingsCurrent = m_pSettingsUser;
break;
case kSystem:
m_pSettingsCurrent = m_pSettingsSystem;
break;
default:
// setScope should never be kCurrent
assert(scope);
}
}
}
void Config::setScope(Config::Scope scope) { m_CurrentScope = scope; }
ConfigWriter::Scope ConfigWriter::getScope() const { return m_CurrentScope; }
Config::Scope Config::getScope() const { return m_CurrentScope; }
void ConfigWriter::globalLoad() {
for (auto &i : m_pCallerList) {
void Config::loadAll() {
for (auto &i : m_pReceievers) {
i->loadSettings();
}
}
void ConfigWriter::globalSave() {
void Config::saveAll() {
// Save if there are any unsaved changes otherwise skip
if (unsavedChanges()) {
for (auto &i : m_pCallerList) {
for (auto &i : m_pReceievers) {
i->saveSettings();
}
m_pSettingsUser->sync();
m_pSettingsSystem->sync();
m_pUserSettings->sync();
m_pSystemSettings->sync();
m_unsavedChanges = false;
}
}
QSettings &ConfigWriter::settings() { return *m_pSettingsCurrent; }
void ConfigWriter::registerClass(ConfigBase *receiver) {
m_pCallerList.push_back(receiver);
QSettings *Config::currentSettings() const {
if (m_CurrentScope == Scope::User) {
return m_pUserSettings.get();
} else {
return m_pSystemSettings.get();
}
}
bool ConfigWriter::unsavedChanges() const {
void Config::registerReceiever(CommonConfig *receiver) {
m_pReceievers.push_back(receiver);
}
bool Config::unsavedChanges() const {
if (m_unsavedChanges) {
return true;
}
for (const auto &i : m_pCallerList) {
for (const auto &i : m_pReceievers) {
if (i->modified()) {
// If any class returns true there is no point checking more
return true;
}
}
// If this line is reached no class has unsaved changes
return false;
}
void ConfigWriter::markUnsaved() { m_unsavedChanges = true; }
} // namespace Config
} // namespace GUI
void Config::markUnsaved() { m_unsavedChanges = true; }
} // namespace synergy::gui

115
src/gui/src/Config.h Normal file
View File

@ -0,0 +1,115 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2020 Symless Ltd.
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* 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/>.
*/
#pragma once
#include <QSettings>
#include <QVariant>
#include <memory>
namespace synergy::gui {
class CommonConfig;
/// @brief A general config reader and writer for user and gloabl settings
class Config : private QObject {
public:
enum class Scope { Current, System, User };
explicit Config();
~Config() override;
/// @brief Checks if the setting exists
/// @param [in] name The name of the setting to check
/// @param [in] scope The scope to search in
/// @return bool True if the current scope has the named setting
bool hasSetting(const QString &name, Scope scope = Scope::Current) const;
/// @brief Checks if the current scope settings writable
/// @return bool True if the current scope writable
bool isWritable() const;
/// @brief Sets the value of a setting
/// @param [in] name The Setting to be saved
/// @param [in] value The Value to be saved (Templated)
/// @param [in] scope The scope to get the value from, default is current
/// scope
template <typename T>
void setSetting(const QString &name, T value, Scope scope = Scope::Current);
/// @brief Loads a setting
/// @param [in] name The setting to be loaded
/// @param [in] defaultValue The default value of the setting
/// @param [in] scope The scope to get the value from, default is current
/// scope
QVariant loadSetting(
const QString &name, const QVariant &defaultValue = QVariant(),
Scope scope = Scope::Current) const;
/// @brief Changes the setting save and load location between System and User
/// scope
/// @param [in] scope The scope to set
void setScope(Scope scope = Scope::User);
/// @brief Get the current scope the settings are loading and save from.
/// @return Scope An enum defining the current scope
Scope getScope() const;
/// @brief trigger a config load across all registered classes
void loadAll();
/// @brief trigger a config save across all registered classes
void saveAll();
/// @brief Returns the current scopes settings object
/// If more specialize control into the settings is needed this can
/// provide direct access to the settings file handler
/// @return QSettings The Settings object as a reference
QSettings *currentSettings() const;
/// @brief This marks the settings as unsaved if the settings() was used to
/// directly affect the config file
void markUnsaved();
/// @brief Register a class to receives requests to save and load settings
void registerReceiever(CommonConfig *receiver);
/// @brief Checks if any registered class has any unsaved changes
/// @return bool True if any registered class has unsaved changes
bool unsavedChanges() const;
private:
void load();
Scope m_CurrentScope = Scope::User;
std::unique_ptr<QSettings> m_pUserSettings;
std::unique_ptr<QSettings> m_pSystemSettings;
/// @brief Receivers of load/save callbacks
std::list<CommonConfig *> m_pReceievers;
/// @brief Is set to true when settings are changed
bool m_unsavedChanges = false;
};
template <typename T>
void Config::setSetting(const QString &name, T value, Scope scope) {
currentSettings()->setValue(name, value);
m_unsavedChanges = true;
}
} // namespace synergy::gui

View File

@ -1,51 +0,0 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2020 - 2020 Symless Ltd.
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* 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/>.
*/
#ifndef SYNERGY_CORE_CONFIGBASE_H
#define SYNERGY_CORE_CONFIGBASE_H
namespace GUI {
namespace Config {
///@brief This abstract class will be used by all classes that use the
/// ConfigWriter
/// to allow global saving and loading
class ConfigBase {
public:
ConfigBase() = default;
virtual ~ConfigBase() = default;
/// @brief The function that is called when the settings need to be loaded
/// from file
virtual void loadSettings() = 0;
/// @brief The function that is called when the settings need to be saved to
/// file
virtual void saveSettings() = 0;
/// @brief Returns true if the class has marked itself with having unsaved
/// changes
bool modified() const { return m_unsavedChanges; }
protected:
/// @brief Does the class have unsaved changes in it.
bool m_unsavedChanges = false;
};
} // namespace Config
} // namespace GUI
#endif // SYNERGY_CORE_CONFIGBASE_H

View File

@ -1,157 +0,0 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2020 - 2020 Symless Ltd.
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* 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/>.
*/
#ifndef SYNERGY_CORE_CONFIGWRITER_H
#define SYNERGY_CORE_CONFIGWRITER_H
#include <QSettings>
#include <QVariant>
/// @brief Contains GUI code
namespace GUI {
/// @brief Contains Configuration code
namespace Config {
// Forward declare the class referenced by pointer
class ConfigBase;
class ConfigWriter : private QObject {
public:
/// @brief the public way to construct the configuration calls
/// The pointer returned is owned by this class and should not be
/// stored by other classes.
static ConfigWriter *make();
/// @brief the public way to destroy the configuration class
static void destroy();
~ConfigWriter() override;
///@brief An Enumeration of all the scopes available
enum Scope { kCurrent, kSystem, kUser };
/// @brief Checks if the setting exists
/// @param [in] name The name of the setting to check
/// @param [in] scope The scope to search in
/// @return bool True if the current scope has the named setting
bool hasSetting(const QString &name, Scope scope = kCurrent) const;
/// @brief Checks if the current scope settings writable
/// @return bool True if the current scope writable
bool isWritable() const;
/// @brief Sets the value of a setting
/// @param [in] name The Setting to be saved
/// @param [in] value The Value to be saved (Templated)
/// @param [in] scope The scope to get the value from, default is current
/// scope
template <typename T>
void setSetting(const QString &name, T value, Scope scope = kCurrent);
/// @brief Loads a setting
/// @param [in] name The setting to be loaded
/// @param [in] defaultValue The default value of the setting
/// @param [in] scope The scope to get the value from, default is current
/// scope
QVariant loadSetting(
const QString &name, const QVariant &defaultValue = QVariant(),
Scope scope = kCurrent);
/// @brief Changes the setting save and load location between System and User
/// scope
/// @param [in] scope The scope to set
void setScope(Scope scope = kUser);
/// @brief Get the current scope the settings are loading and save from.
/// @return Scope An enum defining the current scope
Scope getScope() const;
/// @brief trigger a config load across all registered classes
void globalLoad();
/// @brief trigger a config save across all registered classes
void globalSave();
/// @brief Returns the current scopes settings object
/// If more specialize control into the settings is needed this can
/// provide direct access to the settings file handler
/// @return QSettings The Settings object as a reference
QSettings &settings();
/// @brief This marks the settings as unsaved if the settings() was used to
/// directly affect the config file
void markUnsaved();
/// @brief Register a class to receives globalLoad and globalSave events
/// @param [in] ConfigBase The class that will receive the events
void registerClass(ConfigBase *receiver);
/// @brief Checks if any registered class has any unsaved changes
/// @return bool True if any registered class has unsaved changes
bool unsavedChanges() const;
protected:
Scope m_CurrentScope = kUser; /// @brief The current scope of the settings
QSettings *m_pSettingsCurrent =
nullptr; /// @brief The currently active settings
QSettings *m_pSettingsUser = nullptr; /// @brief The user specific settings
QSettings *m_pSettingsSystem = nullptr; /// @brief The system wide settings
private:
/// @brief Contains a list all all classes that hook into the writer.
/// This allows all classes that save settings to be called an updated
/// on a save and reload by any other class
std::list<ConfigBase *> m_pCallerList;
/// @brief if this class modified settings then set the flag
bool m_unsavedChanges = false;
/// @brief The constructor, as this is a singolton we want to control who can
/// call the constructor
ConfigWriter();
/// @brief the pointer of the ConfigWriter for singolton use
static ConfigWriter *s_pConfiguration;
/// @brief deletes pointers and sets the value to null
template <class T> static inline void destroy(T *&p) {
delete p;
p = 0;
}
};
// Implementation of a template function needs to be visible to all calls thus
// is must be in the header Moved so its not bulking out the class definition
template <typename T>
void ConfigWriter::setSetting(const QString &name, T value, Scope scope) {
switch (scope) {
case kUser:
m_pSettingsUser->setValue(name, value);
break;
case kSystem:
m_pSettingsSystem->setValue(name, value);
break;
default:
m_pSettingsCurrent->setValue(name, value);
break;
}
m_unsavedChanges = true;
}
} // namespace Config
} // namespace GUI
#endif // SYNERGY_CORE_CONFIGWRITER_H

View File

@ -18,13 +18,11 @@
#include "CoreInterface.h"
#include "CommandProcess.h"
#include "QUtility.h"
#include <QCoreApplication>
#include <QDir>
#include <QProcess>
#include <QtGlobal>
#include <stdexcept>
static const char kCoreBinary[] = "syntool";
@ -34,16 +32,14 @@ static const char kSerialKeyFilename[] = "Synergy.subkey";
static const char kSerialKeyFilename[] = ".synergy.subkey";
#endif
CoreInterface::CoreInterface() {}
QString CoreInterface::getProfileDir() {
QStringList args("--get-profile-dir");
return run(args);
return QDir::cleanPath(run(args));
}
QString CoreInterface::getInstalledDir() {
QStringList args("--get-installed-dir");
return run(args);
return QDir::cleanPath(run(args));
}
QString CoreInterface::getArch() {
@ -52,11 +48,12 @@ QString CoreInterface::getArch() {
}
QString CoreInterface::getSerialKeyFilePath() {
QString filename = getProfileDir() + QDir::separator() + kSerialKeyFilename;
return filename;
auto filename = getProfileDir() + QDir::separator() + kSerialKeyFilename;
return QDir::cleanPath(filename);
}
QString CoreInterface::run(const QStringList &args, const QString &input) {
QString
CoreInterface::run(const QStringList &args, const QString &input) const {
QString program(QCoreApplication::applicationDirPath() + "/" + kCoreBinary);
CommandProcess commandProcess(program, args, input);

View File

@ -21,11 +21,9 @@
class CoreInterface {
public:
CoreInterface();
QString getProfileDir();
QString getInstalledDir();
QString getArch();
QString getSerialKeyFilePath();
QString run(const QStringList &args, const QString &input = "");
QString run(const QStringList &args, const QString &input = "") const;
};

View File

@ -33,5 +33,3 @@
// ElevateNever | false | false
//
enum ElevateMode { ElevateAsNeeded = 0, ElevateAlways = 1, ElevateNever = 2 };
extern const ElevateMode kDefaultElevateMode;

View File

@ -16,7 +16,10 @@
*/
#include "LicenseManager.h"
#include "ActivationNotifier.h"
#include "AppConfig.h"
#include <QDateTime>
#include <QLocale>
#include <QThread>
@ -66,7 +69,7 @@ void checkSerialKey(const SerialKey &serialKey, bool acceptExpired) {
} // namespace
LicenseManager::LicenseManager(AppConfig *appConfig)
: m_AppConfig(appConfig),
: m_pAppConfig(appConfig),
m_serialKey(appConfig->edition()),
m_registry(*appConfig) {}
@ -76,14 +79,14 @@ void LicenseManager::setSerialKey(SerialKey serialKey, bool acceptExpired) {
if (serialKey != m_serialKey) {
using std::swap;
swap(serialKey, m_serialKey);
m_AppConfig->setSerialKey(QString::fromStdString(m_serialKey.toString()));
m_pAppConfig->setSerialKey(QString::fromStdString(m_serialKey.toString()));
emit showLicenseNotice(getLicenseNotice());
validateSerialKey();
m_registry.scheduleRegistration();
if (m_serialKey.edition() != serialKey.edition()) {
m_AppConfig->setEdition(m_serialKey.edition());
m_pAppConfig->setEdition(m_serialKey.edition());
emit editionChanged(m_serialKey.edition());
}
}
@ -119,13 +122,14 @@ QString LicenseManager::activeEditionName() const {
const SerialKey &LicenseManager::serialKey() const { return m_serialKey; }
void LicenseManager::refresh() {
if (!m_AppConfig->serialKey().isEmpty()) {
if (!m_pAppConfig->serialKey().isEmpty()) {
try {
SerialKey serialKey(m_AppConfig->serialKey().toStdString());
SerialKey serialKey(m_pAppConfig->serialKey().toStdString());
setSerialKey(serialKey, true);
} catch (...) {
} catch (const std::exception &e) {
qDebug() << e.what();
m_serialKey = SerialKey();
m_AppConfig->clearSerialKey();
m_pAppConfig->clearSerialKey();
}
}
if (!m_serialKey.isValid()) {
@ -133,10 +137,6 @@ void LicenseManager::refresh() {
}
}
void LicenseManager::skipActivation() const {
notifyActivation("skip:unknown");
}
QString LicenseManager::getEditionName(Edition const edition, bool trial) {
SerialKeyEdition KeyEdition(edition);
std::string name = KeyEdition.getProductName();

View File

@ -17,13 +17,11 @@
#pragma once
#include <ActivationNotifier.h>
#include <QObject>
#include <shared/EditionType.h>
#include <shared/SerialKey.h>
#include <utility>
#include "LicenseRegistry.h"
#include "shared/EditionType.h"
#include "shared/SerialKey.h"
#include <QObject>
class AppConfig;
@ -37,14 +35,13 @@ public:
Edition activeEdition() const;
QString activeEditionName() const;
const SerialKey &serialKey() const;
void skipActivation() const;
void notifyUpdate(QString fromVersion, QString toVersion) const;
static QString getEditionName(Edition edition, bool trial = false);
void notifyActivation(QString identity) const;
QString getLicenseNotice() const;
private:
AppConfig *m_AppConfig;
AppConfig *m_pAppConfig;
SerialKey m_serialKey;
LicenseRegistry m_registry;

View File

@ -23,6 +23,9 @@
#include "LicenseRegistry.h"
#include <QSysInfo>
const char *const kLicenseRegistryUrl =
"https://api2.prod.symless.com/license/register";
LicenseRegistry::LicenseRegistry(AppConfig &config) : m_config(config) {
connect(&m_timer, SIGNAL(timeout()), this, SLOT(registerLicense()));
}
@ -30,8 +33,7 @@ LicenseRegistry::LicenseRegistry(AppConfig &config) : m_config(config) {
void LicenseRegistry::registerLicense() {
m_timer.stop();
if (m_config.edition() == Edition::kBusiness) {
const auto REGISTER_LICENSE_URL = m_config.getLicenseRegistryUrl();
const auto url = QUrl(REGISTER_LICENSE_URL);
const auto url = QUrl(kLicenseRegistryUrl);
auto request = QNetworkRequest(url);
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
@ -73,18 +75,18 @@ QByteArray LicenseRegistry::getRequestData() const {
data["guid"] = guid;
data["guid_type"] = "system";
} else {
data["guid"] = m_config.getGuid();
data["guid"] = m_config.guid();
data["guid_type"] = "synergy";
}
data["key"] = m_config.serialKey();
data["is_server"] = m_config.getServerGroupChecked();
data["is_server"] = m_config.serverGroupChecked();
return QJsonDocument(data).toJson();
}
void LicenseRegistry::scheduleRegistration() {
const auto nextCheck = m_config.getLicenseNextCheck();
const auto nextCheck = m_config.licenseNextCheck();
const auto currentTimestamp = static_cast<unsigned long long>(time(nullptr));
if (currentTimestamp >= nextCheck) {

View File

@ -16,11 +16,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define DOWNLOAD_URL "http://symless.com/?source=gui"
#define HELP_URL "http://symless.com/help?source=gui"
#include <array>
#include "MainWindow.h"
#include "AboutDialog.h"
@ -29,8 +24,8 @@
#include "LicenseManager.h"
#include "ServerConfigDialog.h"
#include "SettingsDialog.h"
#include <QPushButton>
#include <shared/EditionType.h>
#include "shared/EditionType.h"
#include <memory>
#if defined(Q_OS_MAC)
#include "OSXHelpers.h"
@ -42,39 +37,46 @@
#include <QMenuBar>
#include <QMessageBox>
#include <QNetworkAccessManager>
#include <QPushButton>
#include <QRegularExpression>
#include <QtCore>
#include <QtGui>
#include <QtNetwork>
#include <array>
#if defined(Q_OS_MAC)
#include <ApplicationServices/ApplicationServices.h>
#endif
static const int debugLogLevel = 1;
static const char *const kDownloadUrl = "https://symless.com/?source=gui";
static const char *const kHelpUrl = "https://symless.com/help?source=gui";
static const int kRetryDelay = 1000;
static const int kDebugLogLevel = 1;
static const char *synergyLightIconFiles[] = {
#if defined(Q_OS_MAC)
static const char *const kLightIconFiles[] = {
":/res/icons/64x64/synergy-light-disconnected.png",
":/res/icons/64x64/synergy-light-disconnected.png",
":/res/icons/64x64/synergy-light-connected.png",
":/res/icons/64x64/synergy-light-transfering.png",
":/res/icons/64x64/synergy-light-disconnected.png"};
static const char *synergyDarkIconFiles[] = {
static const char *const kDarkIconFiles[] = {
":/res/icons/64x64/synergy-dark-disconnected.png",
":/res/icons/64x64/synergy-dark-disconnected.png",
":/res/icons/64x64/synergy-dark-connected.png",
":/res/icons/64x64/synergy-dark-transfering.png",
":/res/icons/64x64/synergy-dark-disconnected.png" // synergyPendingRetry
};
":/res/icons/64x64/synergy-dark-disconnected.png"};
static const char *synergyDefaultIconFiles[] = {
":/res/icons/16x16/synergy-disconnected.png", // synergyDisconnected
":/res/icons/16x16/synergy-disconnected.png", // synergyConnecting
":/res/icons/16x16/synergy-connected.png", // synergyConnected
":/res/icons/16x16/synergy-transfering.png", // synergyListening
":/res/icons/16x16/synergy-disconnected.png" // synergyPendingRetry
};
#endif
static const char *const kDefaultIconFiles[] = {
":/res/icons/16x16/synergy-disconnected.png",
":/res/icons/16x16/synergy-disconnected.png",
":/res/icons/16x16/synergy-connected.png",
":/res/icons/16x16/synergy-transfering.png",
":/res/icons/16x16/synergy-disconnected.png"};
#ifdef SYNERGY_ENABLE_LICENSING
MainWindow::MainWindow(AppConfig &appConfig, LicenseManager &licenseManager)
@ -84,21 +86,9 @@ MainWindow::MainWindow(AppConfig &appConfig)
:
#ifdef SYNERGY_ENABLE_LICENSING
m_LicenseManager(&licenseManager),
m_ActivationDialogRunning(false),
#endif
m_AppConfig(&appConfig),
m_pSynergy(NULL),
m_SynergyState(synergyDisconnected),
m_ServerConfig(5, 3, m_AppConfig, this),
m_AlreadyHidden(false),
m_pMenuBar(NULL),
m_pMenuFile(NULL),
m_pMenuEdit(NULL),
m_pMenuWindow(NULL),
m_pMenuHelp(NULL),
m_pCancelButton(NULL),
m_ExpectedRunningState(kStopped),
m_SecureSocket(false),
m_AppConfig(appConfig),
m_ServerConfig(5, 3, &m_AppConfig, this),
m_serverConnection(*this),
m_clientConnection(*this) {
@ -109,16 +99,19 @@ MainWindow::MainWindow(AppConfig &appConfig)
m_pRadioGroupClient->setAttribute(Qt::WA_MacShowFocusRect, 0);
#endif
m_ServerConfig.loadSettings();
createMenuBar();
loadSettings();
initConnections();
m_pWidgetUpdate->hide();
m_VersionChecker.setApp(appPath(appConfig.synergycName()));
m_VersionChecker.setApp(appPath(appConfig.coreClientName()));
updateScreenName();
connect(
m_AppConfig, SIGNAL(screenNameChanged()), this, SLOT(updateScreenName()));
appConfigPtr(), SIGNAL(screenNameChanged()), this,
SLOT(updateScreenName()));
m_pLabelIpAddresses->setText(
tr("This computer's IP addresses: %1").arg(getIPAddresses()));
@ -172,14 +165,14 @@ MainWindow::MainWindow(AppConfig &appConfig)
#endif
connect(
m_AppConfig, SIGNAL(sslToggled()), this, SLOT(updateLocalFingerprint()),
Qt::QueuedConnection);
appConfigPtr(), SIGNAL(sslToggled()), this,
SLOT(updateLocalFingerprint()), Qt::QueuedConnection);
updateWindowTitle();
QString lastVersion = m_AppConfig->lastVersion();
QString lastVersion = m_AppConfig.lastVersion();
if (lastVersion != SYNERGY_VERSION) {
m_AppConfig->setLastVersion(SYNERGY_VERSION);
m_AppConfig.setLastVersion(SYNERGY_VERSION);
#ifdef SYNERGY_ENABLE_LICENSING
m_LicenseManager->notifyUpdate(lastVersion, SYNERGY_VERSION);
@ -193,13 +186,12 @@ MainWindow::MainWindow(AppConfig &appConfig)
MainWindow::~MainWindow() {
if (appConfig().processMode() == ProcessMode::kDesktop) {
m_ExpectedRunningState = kStopped;
m_ExpectedRunningState = RuningState::Stopped;
try {
stopDesktop();
} catch (...) {
// do not throw, since throwing from a dtor can result in unreliable
// behaviour.
qCritical() << "error stopping desktop in main window destructor";
} catch (const std::exception &e) {
qDebug() << e.what();
qFatal("Failed to stop synergy desktop process");
}
}
}
@ -207,16 +199,15 @@ MainWindow::~MainWindow() {
void MainWindow::open() {
std::array<QAction *, 7> trayMenu = {
m_pActionStartSynergy, m_pActionStopSynergy, nullptr,
m_pActionMinimize, m_pActionRestore, nullptr,
m_pActionQuit};
m_pActionStartCore, m_pActionStopCore, nullptr, m_pActionMinimize,
m_pActionRestore, nullptr, m_pActionQuit};
m_trayIcon.create(trayMenu, [this](QObject const *o, const char *s) {
connect(o, s, this, SLOT(trayActivated(QSystemTrayIcon::ActivationReason)));
setIcon(synergyDisconnected);
setIcon(CoreState::Disconnected);
});
if (appConfig().getAutoHide()) {
if (appConfig().autoHide()) {
hide();
} else {
showNormal();
@ -229,7 +220,7 @@ void MainWindow::open() {
// confuses first time users, who think synergy has crashed).
if (appConfig().startedBefore() &&
appConfig().processMode() == ProcessMode::kDesktop) {
startSynergy();
startCore();
}
}
@ -251,8 +242,8 @@ void MainWindow::createMenuBar() {
#endif
m_pMenuBar->addAction(m_pMenuHelp->menuAction());
m_pMenuFile->addAction(m_pActionStartSynergy);
m_pMenuFile->addAction(m_pActionStopSynergy);
m_pMenuFile->addAction(m_pActionStartCore);
m_pMenuFile->addAction(m_pActionStopCore);
m_pMenuFile->addSeparator();
m_pMenuFile->addAction(m_pActivate);
m_pMenuFile->addSeparator();
@ -269,19 +260,18 @@ void MainWindow::createMenuBar() {
}
void MainWindow::loadSettings() {
enableServer(appConfig().getServerGroupChecked());
enableClient(appConfig().getClientGroupChecked());
enableServer(appConfig().serverGroupChecked());
enableClient(appConfig().clientGroupChecked());
m_pLineEditHostname->setText(appConfig().getServerHostname());
m_pLineEditHostname->setText(appConfig().serverHostname());
m_pLineEditClienIp->setText(serverConfig().getClientAddress());
}
void MainWindow::initConnections() {
connect(m_pActionMinimize, SIGNAL(triggered()), this, SLOT(hide()));
connect(m_pActionRestore, SIGNAL(triggered()), this, SLOT(showNormal()));
connect(
m_pActionStartSynergy, SIGNAL(triggered()), this, SLOT(actionStart()));
connect(m_pActionStopSynergy, SIGNAL(triggered()), this, SLOT(stopSynergy()));
connect(m_pActionStartCore, SIGNAL(triggered()), this, SLOT(actionStart()));
connect(m_pActionStopCore, SIGNAL(triggered()), this, SLOT(stopCore()));
connect(m_pActionQuit, SIGNAL(triggered()), qApp, SLOT(quit()));
connect(
&m_VersionChecker, SIGNAL(updateFound(const QString &)), this,
@ -289,35 +279,34 @@ void MainWindow::initConnections() {
}
void MainWindow::saveSettings() {
// program settings
appConfig().setServerGroupChecked(m_pRadioGroupServer->isChecked());
appConfig().setClientGroupChecked(m_pRadioGroupClient->isChecked());
appConfig().setServerHostname(m_pLineEditHostname->text());
serverConfig().setClientAddress(m_pLineEditClienIp->text());
/* Save everything */
GUI::Config::ConfigWriter::make()->globalSave();
appConfig().config().saveAll();
}
void MainWindow::setIcon(qSynergyState state) const {
void MainWindow::setIcon(CoreState state) const {
QIcon icon;
auto index = static_cast<int>(state);
#ifdef Q_OS_MAC
switch (getOSXIconsTheme()) {
case IconsTheme::ICONS_DARK:
icon.addFile(synergyDarkIconFiles[state]);
icon.addFile(kDarkIconFiles[index]);
break;
case IconsTheme::ICONS_LIGHT:
icon.addFile(synergyLightIconFiles[state]);
icon.addFile(kLightIconFiles[index]);
break;
case IconsTheme::ICONS_TEMPLATE:
default:
icon.addFile(synergyDarkIconFiles[state]);
icon.addFile(kDarkIconFiles[index]);
icon.setIsMask(true);
break;
}
#else
icon.addFile(synergyDefaultIconFiles[state]);
icon.addFile(kDefaultIconFiles[index]);
#endif
m_trayIcon.set(icon);
@ -335,8 +324,8 @@ void MainWindow::trayActivated(QSystemTrayIcon::ActivationReason reason) {
}
void MainWindow::logOutput() {
if (m_pSynergy) {
QString text(m_pSynergy->readAllStandardOutput());
if (m_pCoreProcess) {
QString text(m_pCoreProcess->readAllStandardOutput());
for (QString line : text.split(QRegularExpression("\r|\n|\r\n"))) {
if (!line.isEmpty()) {
appendLogRaw(line);
@ -346,8 +335,8 @@ void MainWindow::logOutput() {
}
void MainWindow::logError() {
if (m_pSynergy) {
appendLogRaw(m_pSynergy->readAllStandardError());
if (m_pCoreProcess) {
appendLogRaw(m_pCoreProcess->readAllStandardError());
}
}
@ -357,7 +346,7 @@ void MainWindow::updateFound(const QString &version) {
"Version <b>%1</b> is now available to "
"<a href=\"%2\">download</a>.</p>")
.arg(version)
.arg(DOWNLOAD_URL));
.arg(kDownloadUrl));
}
void MainWindow::appendLogInfo(const QString &text) {
@ -365,7 +354,7 @@ void MainWindow::appendLogInfo(const QString &text) {
}
void MainWindow::appendLogDebug(const QString &text) {
if (appConfig().logLevel() >= debugLogLevel) {
if (appConfig().logLevel() >= kDebugLogLevel) {
appendLogRaw(getTimeStamp() + " DEBUG: " + text);
}
}
@ -395,7 +384,7 @@ void MainWindow::handleIdleService(const QString &text) {
// only start if there is no active service running
if (!line.isEmpty() && line.contains("service status: idle") &&
appConfig().startedBefore()) {
startSynergy();
startCore();
}
}
}
@ -428,7 +417,7 @@ void MainWindow::checkConnected(const QString &line) {
}
if (line.contains("connected to server") || line.contains("has connected")) {
setSynergyState(synergyConnected);
setCoreState(CoreState::Connected);
if (!appConfig().startedBefore() && isVisible()) {
QMessageBox::information(
@ -440,13 +429,13 @@ void MainWindow::checkConnected(const QString &line) {
appConfig().setStartedBefore(true);
}
} else if (line.contains("started server")) {
setSynergyState(synergyListening);
setCoreState(CoreState::Listening);
} else if (
line.contains("disconnected from server") ||
line.contains("process exited")) {
setSynergyState(synergyDisconnected);
setCoreState(CoreState::Disconnected);
} else if (line.contains("connecting to")) {
setSynergyState(synergyConnecting);
setCoreState(CoreState::Connecting);
}
}
@ -474,7 +463,7 @@ void MainWindow::checkFingerprint(const QString &line) {
static bool messageBoxAlreadyShown = false;
if (!messageBoxAlreadyShown) {
stopSynergy();
stopCore();
messageBoxAlreadyShown = true;
QMessageBox::StandardButton fingerprintReply = QMessageBox::information(
@ -493,7 +482,7 @@ void MainWindow::checkFingerprint(const QString &line) {
if (fingerprintReply == QMessageBox::Yes) {
// restart core process after trusting fingerprint.
Fingerprint::trustedServers().trust(fingerprint);
startSynergy();
startCore();
}
messageBoxAlreadyShown = false;
@ -536,9 +525,9 @@ QString MainWindow::getTimeStamp() {
return '[' + current.toString(Qt::ISODate) + ']';
}
void MainWindow::restartSynergy() {
stopSynergy();
startSynergy();
void MainWindow::restartCore() {
stopCore();
startCore();
}
void MainWindow::showEvent(QShowEvent *event) {
@ -548,7 +537,7 @@ void MainWindow::showEvent(QShowEvent *event) {
void MainWindow::clearLog() { m_pLogOutput->clear(); }
void MainWindow::startSynergy() {
void MainWindow::startCore() {
saveSettings();
#ifdef Q_OS_MAC
@ -564,12 +553,10 @@ void MainWindow::startSynergy() {
}
m_LicenseManager->registerLicense();
#endif
bool desktopMode = appConfig().processMode() == ProcessMode::kDesktop;
bool serviceMode = appConfig().processMode() == ProcessMode::kService;
appendLogDebug("starting process");
m_ExpectedRunningState = kStarted;
setSynergyState(synergyConnecting);
m_ExpectedRunningState = RuningState::Started;
setCoreState(CoreState::Connecting);
QString app;
QStringList args;
@ -580,8 +567,10 @@ void MainWindow::startSynergy() {
args << "--name" << appConfig().screenName();
if (desktopMode) {
setSynergyProcess(new QProcess(this));
ProcessMode mode = appConfig().processMode();
if (mode == ProcessMode::kDesktop) {
m_pCoreProcess = std::make_unique<QProcess>(this);
} else {
// tell client/server to talk to daemon through ipc.
args << "--ipc";
@ -611,25 +600,30 @@ void MainWindow::startSynergy() {
#endif
#if defined(Q_OS_WIN)
if (m_AppConfig->getCryptoEnabled()) {
if (m_AppConfig.cryptoEnabled()) {
args << "--enable-crypto";
args << "--tls-cert"
<< QString("\"%1\"").arg(m_AppConfig->getTLSCertPath());
args << "--tls-cert" << m_AppConfig.tlsCertPath();
}
try {
// on windows, the profile directory changes depending on the user that
// launched the process (e.g. when launched with elevation). setting the
// profile dir on launch ensures it uses the same profile dir is used
// no matter how its relaunched.
args << "--profile-dir" << getProfileRootForArg();
} catch (const std::exception &e) {
qDebug() << e.what();
qFatal("Failed to get profile dir, skipping arg");
}
// on windows, the profile directory changes depending on the user that
// launched the process (e.g. when launched with elevation). setting the
// profile dir on launch ensures it uses the same profile dir is used
// no matter how its relaunched.
args << "--profile-dir" << getProfileRootForArg();
#else
if (m_AppConfig->getCryptoEnabled()) {
if (m_AppConfig.cryptoEnabled()) {
args << "--enable-crypto";
args << "--tls-cert" << m_AppConfig->getTLSCertPath();
args << "--tls-cert" << m_AppConfig.tlsCertPath();
}
#endif
if (m_AppConfig->getPreventSleep()) {
if (m_AppConfig.preventSleep()) {
args << "--prevent-sleep";
}
@ -639,28 +633,26 @@ void MainWindow::startSynergy() {
appendLogInfo(
"starting " +
QString(synergyType() == synergyServer ? "server" : "client"));
QString(coreMode() == CoreMode::Server ? "server" : "client"));
if ((synergyType() == synergyClient && !clientArgs(args, app)) ||
(synergyType() == synergyServer && !serverArgs(args, app))) {
stopSynergy();
if ((coreMode() == CoreMode::Client && !clientArgs(args, app)) ||
(coreMode() == CoreMode::Server && !serverArgs(args, app))) {
stopCore();
return;
}
if (desktopMode) {
if (mode == ProcessMode::kDesktop) {
connect(
synergyProcess(), SIGNAL(finished(int, QProcess::ExitStatus)), this,
SLOT(synergyFinished(int, QProcess::ExitStatus)));
m_pCoreProcess.get(), SIGNAL(finished(int, QProcess::ExitStatus)), this,
SLOT(coreProcessExit(int, QProcess::ExitStatus)));
connect(
synergyProcess(), SIGNAL(readyReadStandardOutput()), this,
m_pCoreProcess.get(), SIGNAL(readyReadStandardOutput()), this,
SLOT(logOutput()));
connect(
synergyProcess(), SIGNAL(readyReadStandardError()), this,
m_pCoreProcess.get(), SIGNAL(readyReadStandardError()), this,
SLOT(logError()));
}
qDebug() << args;
// show command if debug log level...
if (appConfig().logLevel() >= 4) {
appendLogInfo(QString("command: %1 %2").arg(app, args.join(" ")));
@ -671,9 +663,9 @@ void MainWindow::startSynergy() {
if (appConfig().logToFile())
appendLogInfo("log file: " + appConfig().logFilename());
if (desktopMode) {
synergyProcess()->start(app, args);
if (!synergyProcess()->waitForStarted()) {
if (mode == ProcessMode::kDesktop) {
m_pCoreProcess->start(app, args);
if (!m_pCoreProcess->waitForStarted()) {
show();
QMessageBox::warning(
this, tr("Program can not be started"),
@ -684,9 +676,7 @@ void MainWindow::startSynergy() {
.arg(app)));
return;
}
}
if (serviceMode) {
} else if (mode == ProcessMode::kService) {
QString command(app + " " + args.join(" "));
m_IpcClient.sendCommand(command, appConfig().elevateMode());
}
@ -694,19 +684,19 @@ void MainWindow::startSynergy() {
void MainWindow::actionStart() {
m_clientConnection.setCheckConnection(true);
startSynergy();
startCore();
}
void MainWindow::retryStart() {
// This function is only called after a failed start
// Only start synergy if the current state is pending retry
if (m_SynergyState == synergyPendingRetry) {
startSynergy();
if (m_CoreState == CoreState::PendingRetry) {
startCore();
}
}
bool MainWindow::clientArgs(QStringList &args, QString &app) {
app = appPath(appConfig().synergycName());
app = appPath(appConfig().coreClientName());
if (!QFile::exists(app)) {
show();
@ -716,38 +706,31 @@ bool MainWindow::clientArgs(QStringList &args, QString &app) {
return false;
}
#if defined(Q_OS_WIN)
// wrap in quotes so a malicious user can't start \Program.exe as admin.
app = QString("\"%1\"").arg(app);
#endif
if (appConfig().logToFile()) {
appConfig().persistLogDir();
args << "--log" << appConfig().logFilenameCmd();
args << "--log" << appConfig().logFilename();
}
if (appConfig().getLanguageSync()) {
if (appConfig().languageSync()) {
args << "--sync-language";
}
if (appConfig().getInvertScrollDirection()) {
if (appConfig().invertScrollDirection()) {
args << "--invert-scroll";
}
if (m_pLineEditHostname->text().isEmpty() &&
!appConfig().getClientHostMode()) {
show();
QMessageBox::warning(
this, tr("Hostname is empty"),
tr("Please fill in a hostname for the synergy "
"client to connect to."));
return false;
}
if (appConfig().getClientHostMode()) {
if (appConfig().clientHostMode()) {
args << "--host";
args << ":" + QString::number(appConfig().port());
} else {
if (m_pLineEditHostname->text().isEmpty()) {
show();
QMessageBox::warning(
this, tr("IP/hostname is empty"),
tr("Please enter a server hostname or IP address."));
return false;
}
QString hostName = m_pLineEditHostname->text();
// if interface is IPv6 - ensure that ip is in square brackets
if (hostName.count(':') > 1) {
@ -766,8 +749,8 @@ bool MainWindow::clientArgs(QStringList &args, QString &app) {
QString MainWindow::configFilename() {
QString configFullPath;
if (appConfig().getUseExternalConfig()) {
configFullPath = appConfig().getConfigFile();
if (appConfig().useExternalConfig()) {
configFullPath = appConfig().configFile();
} else {
QStringList errors;
for (auto path :
@ -818,11 +801,12 @@ QString MainWindow::address() const {
}
QString MainWindow::appPath(const QString &name) {
return appConfig().synergyProgramDir() + name;
QDir dir(QCoreApplication::applicationDirPath());
return dir.filePath(name);
}
bool MainWindow::serverArgs(QStringList &args, QString &app) {
app = appPath(appConfig().synergysName());
app = appPath(appConfig().coreServerName());
if (!QFile::exists(app)) {
QMessageBox::warning(
@ -831,33 +815,24 @@ bool MainWindow::serverArgs(QStringList &args, QString &app) {
return false;
}
if (appConfig().getServerClientMode() &&
m_pLineEditClienIp->text().isEmpty()) {
if (appConfig().serverClientMode() && m_pLineEditClienIp->text().isEmpty()) {
QMessageBox::warning(
this, tr("Client IP address or name is empty"),
tr("Please fill in a client IP address or name."));
return false;
}
#if defined(Q_OS_WIN)
// wrap in quotes so a malicious user can't start \Program.exe as admin.
app = QString("\"%1\"").arg(app);
#endif
if (appConfig().logToFile()) {
appConfig().persistLogDir();
args << "--log" << appConfig().logFilenameCmd();
args << "--log" << appConfig().logFilename();
}
QString configFilename = this->configFilename();
if (configFilename.isEmpty()) {
return false;
}
#if defined(Q_OS_WIN)
// wrap in quotes in case username contains spaces.
configFilename = QString("\"%1\"").arg(configFilename);
#endif
args << "-c" << configFilename << "--address" << address();
appendLogInfo("config file: " + configFilename);
@ -870,10 +845,10 @@ bool MainWindow::serverArgs(QStringList &args, QString &app) {
return true;
}
void MainWindow::stopSynergy() {
void MainWindow::stopCore() {
appendLogDebug("stopping process");
m_ExpectedRunningState = kStopped;
m_ExpectedRunningState = RuningState::Stopped;
if (appConfig().processMode() == ProcessMode::kService) {
stopService();
@ -881,7 +856,7 @@ void MainWindow::stopSynergy() {
stopDesktop();
}
setSynergyState(synergyDisconnected);
setCoreState(CoreState::Disconnected);
// reset so that new connects cause auto-hide.
m_AlreadyHidden = false;
@ -894,87 +869,92 @@ void MainWindow::stopService() {
void MainWindow::stopDesktop() {
QMutexLocker locker(&m_StopDesktopMutex);
if (!synergyProcess()) {
if (!m_pCoreProcess) {
return;
}
appendLogInfo("stopping synergy desktop process");
if (synergyProcess()->isOpen()) {
synergyProcess()->close();
if (m_pCoreProcess->isOpen()) {
m_pCoreProcess->close();
}
delete synergyProcess();
setSynergyProcess(NULL);
m_pCoreProcess->reset();
}
void MainWindow::synergyFinished(int exitCode, QProcess::ExitStatus) {
void MainWindow::coreProcessExit(int exitCode, QProcess::ExitStatus) {
if (exitCode == 0) {
appendLogInfo(QString("process exited normally"));
appendLogInfo("process exited normally");
} else {
appendLogError(QString("process exited with error code: %1").arg(exitCode));
}
if (m_ExpectedRunningState == kStarted) {
if (m_ExpectedRunningState == RuningState::Started) {
setSynergyState(synergyPendingRetry);
QTimer::singleShot(1000, this, SLOT(retryStart()));
appendLogInfo(QString("detected process not running, auto restarting"));
if (coreState() != CoreState::PendingRetry) {
QTimer::singleShot(kRetryDelay, this, SLOT(retryStart()));
appendLogInfo("detected process not running, auto restarting");
} else {
appendLogInfo("detected process not running, already auto restarting");
}
setCoreState(CoreState::PendingRetry);
} else {
setSynergyState(synergyDisconnected);
setCoreState(CoreState::Disconnected);
}
}
void MainWindow::setSynergyState(qSynergyState state) {
void MainWindow::setCoreState(CoreState state) {
// always assume connection is not secure when connection changes
// to anything except connected. the only way the padlock shows is
// when the correct TLS version string is detected.
if (state != synergyConnected) {
if (state != CoreState::Connected) {
secureSocket(false);
}
if (synergyState() == state)
if (coreState() == state)
return;
if ((state == synergyConnected) || (state == synergyConnecting) ||
(state == synergyListening) || (state == synergyPendingRetry)) {
if ((state == CoreState::Connected) || (state == CoreState::Connecting) ||
(state == CoreState::Listening) || (state == CoreState::PendingRetry)) {
disconnect(
m_pButtonToggleStart, SIGNAL(clicked()), m_pActionStartSynergy,
m_pButtonToggleStart, SIGNAL(clicked()), m_pActionStartCore,
SLOT(trigger()));
connect(
m_pButtonToggleStart, SIGNAL(clicked()), m_pActionStopSynergy,
m_pButtonToggleStart, SIGNAL(clicked()), m_pActionStopCore,
SLOT(trigger()));
m_pButtonToggleStart->setText(tr("&Stop"));
m_pButtonApply->setEnabled(true);
} else if (state == synergyDisconnected) {
m_pActionStartCore->setEnabled(false);
m_pActionStopCore->setEnabled(true);
} else if (state == CoreState::Disconnected) {
disconnect(
m_pButtonToggleStart, SIGNAL(clicked()), m_pActionStopSynergy,
m_pButtonToggleStart, SIGNAL(clicked()), m_pActionStopCore,
SLOT(trigger()));
connect(
m_pButtonToggleStart, SIGNAL(clicked()), m_pActionStartSynergy,
m_pButtonToggleStart, SIGNAL(clicked()), m_pActionStartCore,
SLOT(trigger()));
m_pButtonToggleStart->setText(tr("&Start"));
m_pButtonApply->setEnabled(false);
}
bool running = false;
if (state == synergyConnected || state == synergyListening) {
running = true;
m_pActionStartCore->setEnabled(true);
m_pActionStopCore->setEnabled(false);
}
m_pActionStartSynergy->setEnabled(!running);
m_pActionStopSynergy->setEnabled(running);
switch (state) {
case synergyListening: {
if (synergyType() == synergyServer) {
case CoreState::Listening: {
if (coreMode() == CoreMode::Server) {
setStatus(
tr("Synergy is waiting for clients").arg(m_SecureSocketVersion));
}
break;
}
case synergyConnected: {
case CoreState::Connected: {
if (m_SecureSocket) {
setStatus(
tr("Synergy is connected (with %1)").arg(m_SecureSocketVersion));
@ -984,20 +964,20 @@ void MainWindow::setSynergyState(qSynergyState state) {
}
break;
}
case synergyConnecting:
case CoreState::Connecting:
setStatus(tr("Synergy is starting..."));
break;
case synergyPendingRetry:
case CoreState::PendingRetry:
setStatus(tr("There was an error, retrying..."));
break;
case synergyDisconnected:
case CoreState::Disconnected:
setStatus(tr("Synergy is not running"));
break;
}
setIcon(state);
m_SynergyState = state;
m_CoreState = state;
}
void MainWindow::setVisible(bool visible) {
@ -1057,8 +1037,8 @@ void MainWindow::setEdition(Edition edition) {
#ifdef SYNERGY_ENABLE_LICENSING
void MainWindow::InvalidLicense() {
stopSynergy();
m_AppConfig->activationHasRun(false);
stopCore();
m_AppConfig.activationHasRun(false);
}
void MainWindow::showLicenseNotice(const QString &notice) {
@ -1074,7 +1054,15 @@ void MainWindow::showLicenseNotice(const QString &notice) {
#endif
void MainWindow::updateLocalFingerprint() {
if (m_AppConfig->getCryptoEnabled() && Fingerprint::local().fileExists() &&
bool fingerprintExists = false;
try {
fingerprintExists = Fingerprint::local().fileExists();
} catch (const std::exception &e) {
qDebug() << e.what();
qFatal("Failed to check if fingerprint exists");
}
if (m_AppConfig.cryptoEnabled() && fingerprintExists &&
m_pRadioGroupServer->isChecked()) {
m_pLabelFingerprint->setVisible(true);
} else {
@ -1105,7 +1093,7 @@ void MainWindow::on_m_pActionAbout_triggered() {
}
void MainWindow::on_m_pActionHelp_triggered() {
QDesktopServices::openUrl(QUrl(HELP_URL));
QDesktopServices::openUrl(QUrl(kHelpUrl));
}
void MainWindow::updateWindowTitle() {
@ -1123,12 +1111,12 @@ void MainWindow::updateWindowTitle() {
void MainWindow::on_m_pActionSettings_triggered() {
auto result = SettingsDialog(this, appConfig()).exec();
if (result == QDialog::Accepted) {
enableServer(appConfig().getServerGroupChecked());
enableClient(appConfig().getClientGroupChecked());
auto state = synergyState();
if ((state == synergyConnected) || (state == synergyConnecting) ||
(state == synergyListening)) {
restartSynergy();
enableServer(appConfig().serverGroupChecked());
enableClient(appConfig().clientGroupChecked());
auto state = coreState();
if ((state == CoreState::Connected) || (state == CoreState::Connecting) ||
(state == CoreState::Listening)) {
restartCore();
}
}
}
@ -1168,10 +1156,10 @@ void MainWindow::showConfigureServer(const QString &message) {
auto result = dlg.exec();
if (result == QDialog::Accepted) {
auto state = synergyState();
if ((state == synergyConnected) || (state == synergyConnecting) ||
(state == synergyListening)) {
restartSynergy();
auto state = coreState();
if ((state == CoreState::Connected) || (state == CoreState::Connecting) ||
(state == CoreState::Listening)) {
restartCore();
}
}
}
@ -1188,7 +1176,7 @@ void MainWindow::on_m_pActivate_triggered() {
void MainWindow::on_m_pButtonApply_clicked() {
m_clientConnection.setCheckConnection(true);
restartSynergy();
restartCore();
}
#ifdef SYNERGY_ENABLE_LICENSING
@ -1214,7 +1202,7 @@ int MainWindow::raiseActivationDialog() {
void MainWindow::on_windowShown() {
#ifdef SYNERGY_ENABLE_LICENSING
auto serialKey = m_LicenseManager->serialKey();
if (!m_AppConfig->activationHasRun() && !serialKey.isValid()) {
if (!m_AppConfig.activationHasRun() && !serialKey.isValid()) {
setEdition(Edition::kUnregistered);
raiseActivationDialog();
}
@ -1232,7 +1220,7 @@ QString MainWindow::getProfileRootForArg() {
dir.replace("/.synergy", "");
#endif
return QString("\"%1\"").arg(dir);
return dir;
}
void MainWindow::secureSocket(bool secureSocket) {
@ -1254,7 +1242,7 @@ void MainWindow::on_m_pLabelFingerprint_linkActivated(const QString &) {
}
void MainWindow::windowStateChanged() {
if (windowState() == Qt::WindowMinimized && appConfig().getMinimizeToTray())
if (windowState() == Qt::WindowMinimized && appConfig().minimizeToTray())
hide();
}
@ -1267,11 +1255,11 @@ void MainWindow::updateScreenName() {
}
void MainWindow::enableServer(bool enable) {
m_AppConfig->setServerGroupChecked(enable);
m_AppConfig.setServerGroupChecked(enable);
m_pRadioGroupServer->setChecked(enable);
if (enable) {
if (m_AppConfig->getServerClientMode()) {
if (m_AppConfig.serverClientMode()) {
m_pLabelClientIp->show();
m_pLineEditClienIp->show();
m_pButtonConnectToClient->show();
@ -1296,11 +1284,11 @@ void MainWindow::enableServer(bool enable) {
}
void MainWindow::enableClient(bool enable) {
m_AppConfig->setClientGroupChecked(enable);
m_AppConfig.setClientGroupChecked(enable);
m_pRadioGroupClient->setChecked(enable);
if (enable) {
if (m_AppConfig->getClientHostMode()) {
if (m_AppConfig.clientHostMode()) {
m_pLabelServerName->hide();
m_pLineEditHostname->hide();
m_pButtonConnect->hide();
@ -1318,23 +1306,16 @@ void MainWindow::enableClient(bool enable) {
}
}
void MainWindow::closeEvent(QCloseEvent *event) {
#if defined(Q_OS_LINUX)
QCoreApplication::quit();
#endif
QWidget::closeEvent(event);
}
void MainWindow::on_m_pRadioGroupServer_clicked(bool) {
enableServer(true);
enableClient(false);
m_AppConfig->saveSettings();
m_AppConfig.saveSettings();
}
void MainWindow::on_m_pRadioGroupClient_clicked(bool) {
enableClient(true);
enableServer(false);
m_AppConfig->saveSettings();
m_AppConfig.saveSettings();
}
void MainWindow::on_m_pButtonConnect_clicked() { on_m_pButtonApply_clicked(); }

View File

@ -24,13 +24,14 @@
#include <QSettings>
#include <QSystemTrayIcon>
#include <QThread>
#include <memory>
#include "ui_MainWindowBase.h"
#include "ActivationDialog.h"
#include "AppConfig.h"
#include "ClientConnection.h"
#include "ConfigWriter.h"
#include "Config.h"
#include "QIpcClient.h"
#include "ServerConfig.h"
#include "ServerConnection.h"
@ -70,34 +71,35 @@ class MainWindow : public QMainWindow, public Ui::MainWindowBase {
friend class ClientConnection;
public:
enum qSynergyState {
synergyDisconnected,
synergyConnecting,
synergyConnected,
synergyListening,
synergyPendingRetry
enum class CoreState {
Disconnected,
Connecting,
Connected,
Listening,
PendingRetry
};
enum qSynergyType { synergyClient, synergyServer };
enum class CoreMode { Client, Server };
enum qLevel { Error, Info };
enum class LogLevel { Error, Info };
enum qRuningState { kStarted, kStopped };
enum class RuningState { Started, Stopped };
public:
#ifdef SYNERGY_ENABLE_LICENSING
MainWindow(AppConfig &appConfig, LicenseManager &licenseManager);
#else
MainWindow(AppConfig &appConfig);
explicit MainWindow(AppConfig &appConfig);
#endif
~MainWindow();
~MainWindow() override;
public:
void setVisible(bool visible);
int synergyType() const {
return m_pRadioGroupClient->isChecked() ? synergyClient : synergyServer;
CoreMode coreMode() const {
auto isClient = m_pRadioGroupClient->isChecked();
return isClient ? CoreMode::Client : CoreMode::Server;
}
int synergyState() const { return m_SynergyState; }
CoreState coreState() const { return m_CoreState; }
QString hostname() const { return m_pLineEditHostname->text(); }
QString configFilename();
QString address() const;
@ -124,8 +126,8 @@ public slots:
void appendLogInfo(const QString &text);
void appendLogDebug(const QString &text);
void appendLogError(const QString &text);
void startSynergy();
void retryStart(); // If the connection failed this will retry a startSynergy
void startCore();
void retryStart();
void actionStart();
void handleIdleService(const QString &text);
@ -140,30 +142,26 @@ protected slots:
void on_m_pActionHelp_triggered();
void on_m_pActionSettings_triggered();
void on_m_pActivate_triggered();
void synergyFinished(int exitCode, QProcess::ExitStatus);
void coreProcessExit(int exitCode, QProcess::ExitStatus);
void trayActivated(QSystemTrayIcon::ActivationReason reason);
void stopSynergy();
void stopCore();
void logOutput();
void logError();
void updateFound(const QString &version);
void saveSettings();
protected:
// TODO This should be properly using the ConfigWriter system.
QSettings &settings() {
return GUI::Config::ConfigWriter::make()->settings();
}
AppConfig &appConfig() { return *m_AppConfig; }
AppConfig const &appConfig() const { return *m_AppConfig; }
QProcess *synergyProcess() { return m_pSynergy; }
void setSynergyProcess(QProcess *p) { m_pSynergy = p; }
QSettings &settings() { return *appConfig().config().currentSettings(); }
AppConfig &appConfig() { return m_AppConfig; }
AppConfig const &appConfig() const { return m_AppConfig; }
AppConfig *appConfigPtr() { return &m_AppConfig; }
void initConnections();
void createMenuBar();
void createStatusBar();
void createTrayIcon();
void loadSettings();
void setIcon(qSynergyState state) const;
void setSynergyState(qSynergyState state);
void setIcon(CoreState state) const;
void setCoreState(CoreState state);
bool checkForApp(int which, QString &app);
bool clientArgs(QStringList &args, QString &app);
bool serverArgs(QStringList &args, QString &app);
@ -175,13 +173,6 @@ protected:
void stopDesktop();
void enableServer(bool enable);
void enableClient(bool enable);
void closeEvent(QCloseEvent *event) override;
#if defined(Q_OS_WIN)
bool isServiceRunning(QString name);
#else
bool isServiceRunning();
#endif
QString getProfileRootForArg();
void checkConnected(const QString &line);
@ -194,43 +185,50 @@ protected:
void checkLicense(const QString &line);
#endif
QString getTimeStamp();
void restartSynergy();
void restartCore();
void showEvent(QShowEvent *);
void showEvent(QShowEvent *) override;
void secureSocket(bool secureSocket);
void windowStateChanged();
private:
void updateWindowTitle();
#ifdef SYNERGY_ENABLE_LICENSING
LicenseManager *m_LicenseManager;
bool m_ActivationDialogRunning;
QStringList m_PendingClientNames;
LicenseManager *m_LicenseManager = nullptr;
#endif
AppConfig *m_AppConfig;
QProcess *m_pSynergy;
int m_SynergyState;
AppConfig &m_AppConfig;
ServerConfig m_ServerConfig;
bool m_AlreadyHidden;
VersionChecker m_VersionChecker;
QIpcClient m_IpcClient;
QMenuBar *m_pMenuBar;
QMenu *m_pMenuFile;
QMenu *m_pMenuEdit;
QMenu *m_pMenuWindow;
QMenu *m_pMenuHelp;
QAbstractButton *m_pCancelButton;
TrayIcon m_trayIcon;
qRuningState m_ExpectedRunningState;
QMutex m_StopDesktopMutex;
bool m_SecureSocket; // brief Is the program running a secure socket protocol
// (SSL/TLS)
QString m_SecureSocketVersion; // brief Contains the version of the Secure
// Socket currently active
ServerConnection m_serverConnection;
ClientConnection m_clientConnection;
VersionChecker m_VersionChecker;
QIpcClient m_IpcClient;
TrayIcon m_trayIcon;
QMutex m_StopDesktopMutex;
void updateWindowTitle();
#ifdef SYNERGY_ENABLE_LICENSING
bool m_ActivationDialogRunning = false;
QStringList m_PendingClientNames;
#endif
RuningState m_ExpectedRunningState = RuningState::Stopped;
std::unique_ptr<QProcess> m_pCoreProcess;
QMenuBar *m_pMenuBar = nullptr;
QMenu *m_pMenuFile = nullptr;
QMenu *m_pMenuEdit = nullptr;
QMenu *m_pMenuWindow = nullptr;
QMenu *m_pMenuHelp = nullptr;
QAbstractButton *m_pCancelButton = nullptr;
CoreState m_CoreState = CoreState::Disconnected;
bool m_AlreadyHidden = false;
/// @brief Is the program running a secure socket protocol (SSL/TLS)
bool m_SecureSocket = false;
/// @brief Contains the version of the Secure Socket currently active
QString m_SecureSocketVersion = "";
private slots:
void on_m_pButtonApply_clicked();

View File

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>720</width>
<height>552</height>
<width>750</width>
<height>650</height>
</rect>
</property>
<property name="sizePolicy">
@ -18,8 +18,8 @@
</property>
<property name="minimumSize">
<size>
<width>720</width>
<height>552</height>
<width>750</width>
<height>550</height>
</size>
</property>
<property name="windowTitle">
@ -357,7 +357,7 @@ background-color: rgba(192,192,192, 0.1);
</size>
</property>
<property name="text">
<string>&amp;Configure server</string>
<string>&amp;Configure</string>
</property>
</widget>
</item>
@ -692,7 +692,6 @@ background-color: rgba(192,192,192, 0.1);
<font>
<family>Arial</family>
<pointsize>-1</pointsize>
<weight>88</weight>
<bold>true</bold>
</font>
</property>
@ -789,7 +788,7 @@ top: 3px;</string>
<string notr="true">Ctrl+Q</string>
</property>
</action>
<action name="m_pActionStartSynergy">
<action name="m_pActionStartCore">
<property name="text">
<string>&amp;Start</string>
</property>
@ -797,10 +796,10 @@ top: 3px;</string>
<string>Run</string>
</property>
<property name="shortcut">
<string notr="true">Ctrl+S</string>
<string>Ctrl+S</string>
</property>
</action>
<action name="m_pActionStopSynergy">
<action name="m_pActionStopCore">
<property name="enabled">
<bool>false</bool>
</property>
@ -811,7 +810,7 @@ top: 3px;</string>
<string>Stop</string>
</property>
<property name="shortcut">
<string notr="true">Ctrl+T</string>
<string>Ctrl+T</string>
</property>
</action>
<action name="actionShowStatus">
@ -894,7 +893,7 @@ top: 3px;</string>
<connection>
<sender>m_pButtonToggleStart</sender>
<signal>clicked()</signal>
<receiver>m_pActionStartSynergy</receiver>
<receiver>m_pActionStartCore</receiver>
<slot>trigger()</slot>
<hints>
<hint type="sourcelabel">

View File

@ -1,6 +1,6 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2012 Symless Ltd.
* Copyright (C) 2008 Volker Lanz (vl@fidra.de)
*
* This package is free software; you can redistribute it and/or
@ -17,32 +17,31 @@
*/
#include "QSynergyApplication.h"
#include "MainWindow.h"
#include <QtCore>
#include <QtGui>
QSynergyApplication *QSynergyApplication::s_Instance = NULL;
QSynergyApplication::QSynergyApplication(int &argc, char **argv)
: QApplication(argc, argv) {
s_Instance = this;
QFontDatabase::addApplicationFont(":/res/fonts/Arial.ttf");
QFont Arial("Arial");
Arial.setPixelSize(13);
Arial.setStyleHint(QFont::SansSerif);
setFont(Arial);
// Setting the style to 'Fusion' seems to fix issues such as text being
// rendered as black on black. This may not be the style we want long-term
// but it does fix the style issues for now.
setStyle("Fusion");
}
QSynergyApplication::~QSynergyApplication() {}
void QSynergyApplication::commitData(QSessionManager &) {
void QSynergyApplication::commitData(const QSessionManager &) const {
foreach (QWidget *widget, topLevelWidgets()) {
MainWindow *mainWindow = qobject_cast<MainWindow *>(widget);
if (mainWindow)
mainWindow->saveSettings();
}
}
QSynergyApplication *QSynergyApplication::getInstance() { return s_Instance; }

View File

@ -1,6 +1,6 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2012 Symless Ltd.
* Copyright (C) 2008 Volker Lanz (vl@fidra.de)
*
* This package is free software; you can redistribute it and/or
@ -16,9 +16,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#if !defined(QSYNERGYAPPLICATION__H)
#define QSYNERGYAPPLICATION__H
#pragma once
#include <QApplication>
@ -27,15 +25,7 @@ class QSessionManager;
class QSynergyApplication : public QApplication {
public:
QSynergyApplication(int &argc, char **argv);
~QSynergyApplication();
~QSynergyApplication() override = default;
public:
void commitData(QSessionManager &manager);
static QSynergyApplication *getInstance();
private:
static QSynergyApplication *s_Instance;
void commitData(const QSessionManager &manager) const;
};
#endif

View File

@ -16,23 +16,20 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#if !defined(SCREEN__H)
#pragma once
#define SCREEN__H
#include "ScreenConfig.h"
#include <QList>
#include <QPixmap>
#include <QString>
#include <QStringList>
#include "BaseConfig.h"
class QSettings;
class QTextStream;
class ScreenSettingsDialog;
class Screen : public BaseConfig {
class Screen : public ScreenConfig {
friend QDataStream &operator<<(QDataStream &outStream, const Screen &screen);
friend QDataStream &operator>>(QDataStream &inStream, Screen &screen);
friend class ScreenSettingsDialog;
@ -102,5 +99,3 @@ private:
QDataStream &operator<<(QDataStream &outStream, const Screen &screen);
QDataStream &operator>>(QDataStream &inStream, Screen &screen);
#endif

View File

@ -16,14 +16,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "BaseConfig.h"
#include "ScreenConfig.h"
const char *BaseConfig::m_ModifierNames[] = {"shift", "ctrl", "alt",
"meta", "super", "none"};
const char *ScreenConfig::m_ModifierNames[] = {"shift", "ctrl", "alt",
"meta", "super", "none"};
const char *BaseConfig::m_FixNames[] = {
const char *ScreenConfig::m_FixNames[] = {
"halfDuplexCapsLock", "halfDuplexNumLock", "halfDuplexScrollLock",
"xtestIsXineramaUnaware"};
const char *BaseConfig::m_SwitchCornerNames[] = {
const char *ScreenConfig::m_SwitchCornerNames[] = {
"top-left", "top-right", "bottom-left", "bottom-right"};

View File

@ -1,6 +1,6 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2012 Symless Ltd.
* Copyright (C) 2008 Volker Lanz (vl@fidra.de)
*
* This package is free software; you can redistribute it and/or
@ -16,15 +16,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#if !defined(BASECONFIG_H)
#define BASECONFIG_H
#pragma once
#include <QSettings>
#include <QString>
#include <QVariant>
class BaseConfig {
/// @brief Screen configuration base class
class ScreenConfig {
public:
enum Modifier {
DefaultMod = -1,
@ -46,8 +45,8 @@ public:
enum Fix { CapsLock, NumLock, ScrollLock, XTest, NumFixes };
protected:
BaseConfig() {}
virtual ~BaseConfig() {}
explicit ScreenConfig() = default;
~ScreenConfig() = default;
protected:
template <typename T1, typename T2>
@ -101,5 +100,3 @@ private:
static const char *m_FixNames[];
static const char *m_SwitchCornerNames[];
};
#endif

View File

@ -1,6 +1,6 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2012 Symless Ltd.
* Copyright (C) 2008 Volker Lanz (vl@fidra.de)
*
* This package is free software; you can redistribute it and/or
@ -17,7 +17,9 @@
*/
#include "ServerConfig.h"
#include "AddClientDialog.h"
#include "Config.h"
#include "Hotkey.h"
#include "MainWindow.h"
@ -26,6 +28,8 @@
#include <QPushButton>
#include <QtCore>
using synergy::gui::Config;
static const struct {
int x;
int y;
@ -42,25 +46,20 @@ const int serverDefaultIndex = 7;
ServerConfig::ServerConfig(
int numColumns, int numRows, AppConfig *appConfig, MainWindow *mainWindow)
:
: m_pAppConfig(appConfig),
m_pMainWindow(mainWindow),
m_Screens(numColumns),
m_NumColumns(numColumns),
m_NumRows(numRows),
m_pAppConfig(appConfig),
m_EnableDragAndDrop(false),
m_DisableLockToScreen(false),
m_ClipboardSharing(true),
m_ClipboardSharingSize(defaultClipboardSharingSize()),
m_pMainWindow(mainWindow) {
GUI::Config::ConfigWriter::make()->registerClass(this);
ServerConfig::loadSettings();
m_ClipboardSharingSize(defaultClipboardSharingSize()) {
appConfig->config().registerReceiever(this);
}
ServerConfig::~ServerConfig() {
try {
ServerConfig::saveSettings();
} catch (const std::exception &e) {
qDebug() << e.what();
m_pMainWindow->appendLogError(e.what());
}
}
@ -165,8 +164,7 @@ void ServerConfig::saveSettings() {
settings().endGroup();
m_pAppConfig->saveSettings();
// Tell the config writer there are changes
GUI::Config::ConfigWriter::make()->markUnsaved();
m_pAppConfig->config().markUnsaved();
}
void ServerConfig::loadSettings() {
@ -422,12 +420,12 @@ void ServerConfig::updateServerName() {
}
}
const QString &ServerConfig::getConfigFile() const {
return m_pAppConfig->getConfigFile();
const QString &ServerConfig::configFile() const {
return m_pAppConfig->configFile();
}
bool ServerConfig::getUseExternalConfig() const {
return m_pAppConfig->getUseExternalConfig();
bool ServerConfig::useExternalConfig() const {
return m_pAppConfig->useExternalConfig();
}
bool ServerConfig::isFull() const {
@ -543,25 +541,23 @@ size_t ServerConfig::setClipboardSharingSize(size_t size) {
}
void ServerConfig::setClientAddress(const QString &address) {
if (m_pAppConfig->getServerClientMode()) {
m_clientAddress = address;
if (m_pAppConfig->serverClientMode()) {
m_ClientAddress = address;
}
}
QString ServerConfig::getClientAddress() const {
QString clientAddress;
if (m_pAppConfig->getServerClientMode()) {
clientAddress = m_clientAddress.trimmed();
if (m_pAppConfig->serverClientMode()) {
clientAddress = m_ClientAddress.trimmed();
}
return clientAddress;
}
QSettings &ServerConfig::settings() {
using GUI::Config::ConfigWriter;
return ConfigWriter::make()->settings();
return *m_pAppConfig->config().currentSettings();
}
bool ServerConfig::isHotkeysAvailable() const {

View File

@ -16,15 +16,13 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#if !defined(SERVERCONFIG__H)
#define SERVERCONFIG__H
#pragma once
#include <QList>
#include "BaseConfig.h"
#include "ConfigBase.h"
#include "CommonConfig.h"
#include "Hotkey.h"
#include "ScreenConfig.h"
#include "ScreenList.h"
class QTextStream;
@ -35,7 +33,7 @@ class ServerConfigDialog;
class MainWindow;
class AppConfig;
class ServerConfig : public BaseConfig, public GUI::Config::ConfigBase {
class ServerConfig : public ScreenConfig, public synergy::gui::CommonConfig {
friend class ServerConfigDialog;
friend class ServerConnection;
friend QTextStream &
@ -45,16 +43,10 @@ public:
ServerConfig(
int numColumns, int numRows, AppConfig *appConfig,
MainWindow *mainWindow);
ServerConfig(const ServerConfig &src) = default;
ServerConfig(ServerConfig &&) = default;
~ServerConfig();
ServerConfig &operator=(const ServerConfig &src) = default;
ServerConfig &operator=(ServerConfig &&) = delete;
~ServerConfig() override;
bool operator==(const ServerConfig &sc) const;
public:
const ScreenList &screens() const { return m_Screens; }
int numColumns() const { return m_NumColumns; }
int numRows() const { return m_NumRows; }
@ -84,8 +76,8 @@ public:
int autoAddScreen(const QString name);
const QString &getServerName() const;
void updateServerName();
const QString &getConfigFile() const;
bool getUseExternalConfig() const;
const QString &configFile() const;
bool useExternalConfig() const;
bool isFull() const;
bool isScreenExists(const QString &screenName) const;
void addClient(const QString &clientName);
@ -129,27 +121,28 @@ private:
void addToFirstEmptyGrid(const QString &clientName);
private:
bool m_HasHeartbeat = false;
int m_Heartbeat = 0;
bool m_RelativeMouseMoves = false;
bool m_Win32KeepForeground = false;
bool m_HasSwitchDelay = false;
int m_SwitchDelay = 0;
bool m_HasSwitchDoubleTap = false;
int m_SwitchDoubleTap = 0;
int m_SwitchCornerSize = 0;
bool m_EnableDragAndDrop = false;
bool m_DisableLockToScreen = false;
bool m_ClipboardSharing = true;
QString m_ClientAddress = "";
QList<bool> m_SwitchCorners;
HotkeyList m_Hotkeys;
AppConfig *m_pAppConfig;
MainWindow *m_pMainWindow;
ScreenList m_Screens;
int m_NumColumns;
int m_NumRows;
bool m_HasHeartbeat;
int m_Heartbeat;
bool m_RelativeMouseMoves;
bool m_Win32KeepForeground;
bool m_HasSwitchDelay;
int m_SwitchDelay;
bool m_HasSwitchDoubleTap;
int m_SwitchDoubleTap;
int m_SwitchCornerSize;
QList<bool> m_SwitchCorners;
HotkeyList m_Hotkeys;
AppConfig *m_pAppConfig;
bool m_EnableDragAndDrop;
bool m_DisableLockToScreen;
bool m_ClipboardSharing;
size_t m_ClipboardSharingSize;
QString m_clientAddress;
MainWindow *m_pMainWindow;
};
QTextStream &operator<<(QTextStream &outStream, const ServerConfig &config);
@ -160,5 +153,3 @@ enum {
kAutoAddScreenManualClient,
kAutoAddScreenIgnore
};
#endif

View File

@ -33,9 +33,9 @@ ServerConfigDialog::ServerConfigDialog(
QWidget *parent, ServerConfig &config, AppConfig &appConfig)
: QDialog(parent, Qt::WindowTitleHint | Qt::WindowSystemMenuHint),
Ui::ServerConfigDialogBase(),
m_OrigServerConfig(config),
m_OrigServerAppConfigUseExternalConfig(config.getUseExternalConfig()),
m_OrigServerAppConfigExternalConfigFile(config.getConfigFile()),
m_OriginalServerConfig(config),
m_OriginalServerConfigIsExternal(config.useExternalConfig()),
m_OriginalServerConfigUsesExternalFile(config.configFile()),
m_ServerConfig(config),
m_ScreenSetupModel(
serverConfig().screens(), serverConfig().numColumns(),
@ -44,9 +44,8 @@ ServerConfigDialog::ServerConfigDialog(
m_appConfig(appConfig) {
setupUi(this);
m_pEditConfigFile->setText(serverConfig().getConfigFile());
m_pCheckBoxUseExternalConfig->setChecked(
serverConfig().getUseExternalConfig());
m_pEditConfigFile->setText(serverConfig().configFile());
m_pCheckBoxUseExternalConfig->setChecked(serverConfig().useExternalConfig());
m_pCheckBoxHeartbeat->setChecked(serverConfig().hasHeartbeat());
m_pSpinBoxHeartbeat->setValue(serverConfig().heartbeat());
@ -62,13 +61,13 @@ ServerConfigDialog::ServerConfigDialog(
m_pSpinBoxSwitchDoubleTap->setValue(serverConfig().switchDoubleTap());
m_pCheckBoxCornerTopLeft->setChecked(
serverConfig().switchCorner(BaseConfig::TopLeft));
serverConfig().switchCorner(ScreenConfig::TopLeft));
m_pCheckBoxCornerTopRight->setChecked(
serverConfig().switchCorner(BaseConfig::TopRight));
serverConfig().switchCorner(ScreenConfig::TopRight));
m_pCheckBoxCornerBottomLeft->setChecked(
serverConfig().switchCorner(BaseConfig::BottomLeft));
serverConfig().switchCorner(ScreenConfig::BottomLeft));
m_pCheckBoxCornerBottomRight->setChecked(
serverConfig().switchCorner(BaseConfig::BottomRight));
serverConfig().switchCorner(ScreenConfig::BottomRight));
m_pSpinBoxSwitchCornerSize->setValue(serverConfig().switchCornerSize());
m_pCheckBoxDisableLockToScreen->setChecked(
serverConfig().disableLockToScreen());
@ -186,25 +185,25 @@ ServerConfigDialog::ServerConfigDialog(
connect(
m_pCheckBoxCornerTopLeft, &QCheckBox::stateChanged, this,
[this](const int &v) {
serverConfig().setSwitchCorner(BaseConfig::TopLeft, v);
serverConfig().setSwitchCorner(ScreenConfig::TopLeft, v);
onChange();
});
connect(
m_pCheckBoxCornerTopRight, &QCheckBox::stateChanged, this,
[this](const int &v) {
serverConfig().setSwitchCorner(BaseConfig::TopRight, v);
serverConfig().setSwitchCorner(ScreenConfig::TopRight, v);
onChange();
});
connect(
m_pCheckBoxCornerBottomLeft, &QCheckBox::stateChanged, this,
[this](const int &v) {
serverConfig().setSwitchCorner(BaseConfig::BottomLeft, v);
serverConfig().setSwitchCorner(ScreenConfig::BottomLeft, v);
onChange();
});
connect(
m_pCheckBoxCornerBottomRight, &QCheckBox::stateChanged, this,
[this](const int &v) {
serverConfig().setSwitchCorner(BaseConfig::BottomRight, v);
serverConfig().setSwitchCorner(ScreenConfig::BottomRight, v);
onChange();
});
connect(
@ -261,14 +260,14 @@ void ServerConfigDialog::accept() {
// now that the dialog has been accepted, copy the new server config to the
// original one, which is a reference to the one in MainWindow.
setOrigServerConfig(serverConfig());
setOriginalServerConfig(serverConfig());
QDialog::accept();
}
void ServerConfigDialog::reject() {
serverConfig().setUseExternalConfig(m_OrigServerAppConfigUseExternalConfig);
serverConfig().setConfigFile(m_OrigServerAppConfigExternalConfigFile);
serverConfig().setUseExternalConfig(m_OriginalServerConfigIsExternal);
serverConfig().setConfigFile(m_OriginalServerConfigUsesExternalFile);
QDialog::reject();
}
@ -460,10 +459,9 @@ bool ServerConfigDialog::addComputer(const QString &clientName, bool doSilent) {
void ServerConfigDialog::onChange() {
bool isAppConfigDataEqual =
m_OrigServerAppConfigUseExternalConfig ==
serverConfig().getUseExternalConfig() &&
m_OrigServerAppConfigExternalConfigFile == serverConfig().getConfigFile();
m_OriginalServerConfigIsExternal == serverConfig().useExternalConfig() &&
m_OriginalServerConfigUsesExternalFile == serverConfig().configFile();
m_pButtonBox->button(QDialogButtonBox::Ok)
->setEnabled(
!isAppConfigDataEqual || !(m_OrigServerConfig == m_ServerConfig));
!isAppConfigDataEqual || !(m_OriginalServerConfig == m_ServerConfig));
}

View File

@ -61,15 +61,17 @@ protected slots:
protected:
bool addComputer(const QString &clientName, bool doSilent);
ServerConfig &serverConfig() { return m_ServerConfig; }
void setOrigServerConfig(const ServerConfig &s) { m_OrigServerConfig = s; }
void setOriginalServerConfig(const ServerConfig &s) {
m_OriginalServerConfig = s;
}
ScreenSetupModel &model() { return m_ScreenSetupModel; }
AppConfig &appConfig() { return m_appConfig; }
private:
ServerConfig &m_OrigServerConfig;
bool m_OrigServerAppConfigUseExternalConfig;
QString m_OrigServerAppConfigExternalConfigFile;
ServerConfig &m_OriginalServerConfig;
ServerConfig m_ServerConfig;
bool m_OriginalServerConfigIsExternal;
QString m_OriginalServerConfigUsesExternalFile;
ScreenSetupModel m_ScreenSetupModel;
QString m_Message;
AppConfig &m_appConfig;

View File

@ -30,7 +30,7 @@ ServerConnection::ServerConnection(MainWindow &parent) : m_parent(parent) {}
void ServerConnection::update(const QString &line) {
ServerMessage message(line);
if (!m_parent.appConfig().getUseExternalConfig() &&
if (!m_parent.appConfig().useExternalConfig() &&
message.isNewClientMessage() &&
!m_ignoredClients.contains(message.getClientName())) {
addClient(message.getClientName());
@ -73,6 +73,6 @@ void ServerConnection::configureClient(const QString &clientName) {
&m_parent, m_parent.serverConfig(), m_parent.appConfig());
if (dlg.addClient(clientName) && dlg.exec() == QDialog::Accepted) {
m_parent.restartSynergy();
m_parent.restartCore();
}
}

View File

@ -1,6 +1,6 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2012 Symless Ltd.
* Copyright (C) 2008 Volker Lanz (vl@fidra.de)
*
* This package is free software; you can redistribute it and/or
@ -15,14 +15,11 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "SettingsDialog.h"
#include "validators/ScreenNameValidator.h"
#include "AppConfig.h"
#include "CoreInterface.h"
#include "MainWindow.h"
#include "QSynergyApplication.h"
#include "QUtility.h"
#include "SslCertificate.h"
#include "UpgradeDialog.h"
@ -31,6 +28,7 @@
#include <QMessageBox>
#include <QtCore>
#include <QtGui>
#include <memory>
SettingsDialog::SettingsDialog(QWidget *parent, AppConfig &config)
: QDialog(parent, Qt::WindowTitleHint | Qt::WindowSystemMenuHint),
@ -43,15 +41,15 @@ SettingsDialog::SettingsDialog(QWidget *parent, AppConfig &config)
loadFromConfig();
m_isSystemAtStart = appConfig().isSystemScoped();
buttonBox->button(QDialogButtonBox::Save)->setEnabled(false);
enableControls(appConfig().isWritable());
m_pCheckBoxLanguageSync->setEnabled(isClientMode());
m_pCheckBoxScrollDirection->setEnabled(isClientMode());
updateControlsEnabled();
const auto &serveConfig = m_pMainWindow->serverConfig();
m_pLineEditScreenName->setValidator(new validators::ScreenNameValidator(
m_pLineEditScreenName, m_pLabelNameError, (&serveConfig.screens())));
m_screenNameValidator = std::make_unique<validators::ScreenNameValidator>(
m_pLineEditScreenName, nullptr, (&serveConfig.screens()));
connect(
m_screenNameValidator.get(), SIGNAL(finished(QString)), this,
SLOT(on_m_pScreenNameValidator_finished(QString)));
m_pLineEditScreenName->setValidator(m_screenNameValidator.get());
connect(
m_pLineEditLogFilename, SIGNAL(textChanged(QString)), this,
@ -86,6 +84,11 @@ SettingsDialog::SettingsDialog(QWidget *parent, AppConfig &config)
}
void SettingsDialog::accept() {
if (!m_nameError.isEmpty()) {
QMessageBox::warning(this, tr("Invalid screen name"), m_nameError);
return;
}
appConfig().setLoadFromSystemScope(m_pRadioSystemScope->isChecked());
appConfig().setScreenName(m_pLineEditScreenName->text());
appConfig().setPort(m_pSpinBoxPort->value());
@ -98,13 +101,15 @@ void SettingsDialog::accept() {
appConfig().setAutoHide(m_pCheckBoxAutoHide->isChecked());
appConfig().setPreventSleep(m_pCheckBoxPreventSleep->isChecked());
appConfig().setMinimizeToTray(m_pCheckBoxMinimizeToTray->isChecked());
appConfig().setTLSCertPath(m_pLineEditCertificatePath->text());
appConfig().setTLSKeyLength(m_pComboBoxKeyLength->currentText());
appConfig().setTlsCertPath(m_pLineEditCertificatePath->text());
appConfig().setTlsKeyLength(m_pComboBoxKeyLength->currentText());
appConfig().setCryptoEnabled(m_pCheckBoxEnableCrypto->isChecked());
appConfig().setLanguageSync(m_pCheckBoxLanguageSync->isChecked());
appConfig().setInvertScrollDirection(m_pCheckBoxScrollDirection->isChecked());
appConfig().setClientHostMode(m_pCheckBoxClientHostMode->isChecked());
appConfig().setServerClientMode(m_pCheckBoxServerClientMode->isChecked());
appConfig().setServiceEnabled(m_pCheckBoxServiceEnabled->isChecked());
appConfig().setMinimizeOnClose(m_pCheckBoxMinimizeOnClose->isChecked());
appConfig().saveSettings();
QDialog::accept();
@ -127,18 +132,17 @@ void SettingsDialog::loadFromConfig() {
m_pComboLogLevel->setCurrentIndex(appConfig().logLevel());
m_pCheckBoxLogToFile->setChecked(appConfig().logToFile());
m_pLineEditLogFilename->setText(appConfig().logFilename());
m_pCheckBoxAutoHide->setChecked(appConfig().getAutoHide());
m_pCheckBoxPreventSleep->setChecked(appConfig().getPreventSleep());
m_pCheckBoxMinimizeToTray->setChecked(appConfig().getMinimizeToTray());
m_pLineEditCertificatePath->setText(appConfig().getTLSCertPath());
m_pCheckBoxEnableCrypto->setChecked(m_appConfig.getCryptoEnabled());
m_pCheckBoxLanguageSync->setChecked(m_appConfig.getLanguageSync());
m_pCheckBoxScrollDirection->setChecked(
m_appConfig.getInvertScrollDirection());
m_pCheckBoxClientHostMode->setChecked(m_appConfig.getClientHostMode());
m_pCheckBoxServerClientMode->setChecked(m_appConfig.getServerClientMode());
setupSeurity();
m_pCheckBoxAutoHide->setChecked(appConfig().autoHide());
m_pCheckBoxPreventSleep->setChecked(appConfig().preventSleep());
m_pCheckBoxMinimizeToTray->setChecked(appConfig().minimizeToTray());
m_pLineEditCertificatePath->setText(appConfig().tlsCertPath());
m_pCheckBoxEnableCrypto->setChecked(m_appConfig.cryptoEnabled());
m_pCheckBoxLanguageSync->setChecked(m_appConfig.languageSync());
m_pCheckBoxScrollDirection->setChecked(m_appConfig.invertScrollDirection());
m_pCheckBoxClientHostMode->setChecked(m_appConfig.clientHostMode());
m_pCheckBoxServerClientMode->setChecked(m_appConfig.serverClientMode());
m_pCheckBoxServiceEnabled->setChecked(m_appConfig.serviceEnabled());
m_pCheckBoxMinimizeOnClose->setChecked(m_appConfig.minimizeOnClose());
if (m_appConfig.isSystemScoped()) {
m_pRadioSystemScope->setChecked(true);
@ -146,44 +150,42 @@ void SettingsDialog::loadFromConfig() {
m_pRadioUserScope->setChecked(true);
}
#if defined(Q_OS_WIN)
m_pComboElevate->setCurrentIndex(static_cast<int>(appConfig().elevateMode()));
#else
// elevate checkbox is only useful on ms windows.
m_pLabelElevate->hide();
m_pComboElevate->hide();
#endif
m_pCheckBoxClientHostMode->setVisible(
isClientMode() && appConfig().getInitiateConnectionFromServer());
m_pCheckBoxServerClientMode->setVisible(
!isClientMode() && appConfig().getInitiateConnectionFromServer());
updateTlsControls();
}
void SettingsDialog::setupSeurity() {
// If the tls file exists test its key length
if (QFile(appConfig().getTLSCertPath()).exists()) {
updateKeyLengthOnFile(appConfig().getTLSCertPath());
void SettingsDialog::updateTlsControls() {
if (QFile(appConfig().tlsCertPath()).exists()) {
updateKeyLengthOnFile(appConfig().tlsCertPath());
} else {
m_pComboBoxKeyLength->setCurrentIndex(
m_pComboBoxKeyLength->findText(appConfig().getTLSKeyLength()));
m_pComboBoxKeyLength->findText(appConfig().tlsKeyLength()));
}
m_pCheckBoxEnableCrypto->setChecked(m_appConfig.getCryptoEnabled());
m_pCheckBoxEnableCrypto->setChecked(m_appConfig.cryptoEnabled());
if (appConfig().getClientGroupChecked()) {
m_pLabelKeyLength->hide();
m_pComboBoxKeyLength->hide();
m_pLabelCertificate->hide();
m_pLineEditCertificatePath->hide();
m_pPushButtonBrowseCert->hide();
m_pPushButtonRegenCert->hide();
}
updateTlsControlsEnabled();
}
void SettingsDialog::updateTlsControlsEnabled() {
auto clientMode = appConfig().clientGroupChecked();
auto cryptoAvailable = appConfig().cryptoAvailable();
auto tlsChecked = m_pCheckBoxEnableCrypto->isChecked();
auto enabled = !clientMode && cryptoAvailable && tlsChecked;
qDebug(
"TLS controls enabled=%d, client=%d, crypto=%d, checked=%d", enabled,
clientMode, cryptoAvailable, tlsChecked);
m_pLabelKeyLength->setEnabled(enabled);
m_pComboBoxKeyLength->setEnabled(enabled);
m_pLabelCertificate->setEnabled(enabled);
m_pLineEditCertificatePath->setEnabled(enabled);
m_pPushButtonBrowseCert->setEnabled(enabled);
m_pPushButtonRegenCert->setEnabled(enabled);
}
bool SettingsDialog::isClientMode() const {
return (m_pMainWindow->synergyType() == MainWindow::synergyClient);
return (m_pMainWindow->coreMode() == MainWindow::CoreMode::Client);
}
void SettingsDialog::on_m_pCheckBoxLogToFile_stateChanged(int i) {
@ -192,7 +194,6 @@ void SettingsDialog::on_m_pCheckBoxLogToFile_stateChanged(int i) {
m_pLabelLogPath->setEnabled(checked);
m_pLineEditLogFilename->setEnabled(checked);
m_pButtonBrowseLog->setEnabled(checked);
buttonBox->button(QDialogButtonBox::Save)->setEnabled(isModified());
}
void SettingsDialog::on_m_pButtonBrowseLog_clicked() {
@ -206,17 +207,9 @@ void SettingsDialog::on_m_pButtonBrowseLog_clicked() {
}
void SettingsDialog::on_m_pCheckBoxEnableCrypto_clicked(bool checked) {
if (appConfig().isCryptoAvailable()) {
m_pLabelKeyLength->setEnabled(checked);
m_pComboBoxKeyLength->setEnabled(checked);
m_pLabelCertificate->setEnabled(checked);
m_pLineEditCertificatePath->setEnabled(checked);
m_pPushButtonBrowseCert->setEnabled(checked);
m_pPushButtonRegenCert->setEnabled(checked);
updateTlsControlsEnabled();
buttonBox->button(QDialogButtonBox::Save)->setEnabled(isModified());
} else {
m_pCheckBoxEnableCrypto->setChecked(false);
if (!appConfig().cryptoAvailable()) {
#ifdef SYNERGY_ENABLE_LICENSING
auto edition = appConfig().edition();
@ -238,9 +231,7 @@ void SettingsDialog::on_m_pRadioSystemScope_toggled(bool checked) {
// We only need to test the System scoped Radio as they are connected
appConfig().setLoadFromSystemScope(checked);
loadFromConfig();
buttonBox->button(QDialogButtonBox::Save)
->setEnabled(m_isSystemAtStart != checked);
enableControls(appConfig().isWritable());
updateControlsEnabled();
}
void SettingsDialog::on_m_pPushButtonBrowseCert_clicked() {
@ -252,24 +243,23 @@ void SettingsDialog::on_m_pPushButtonBrowseCert_clicked() {
if (!fileName.isEmpty()) {
m_pLineEditCertificatePath->setText(fileName);
// If the tls file exists test its key length and update
if (QFile(appConfig().getTLSCertPath()).exists()) {
if (QFile(appConfig().tlsCertPath()).exists()) {
updateKeyLengthOnFile(fileName);
}
}
updateRegenButton();
updateTlsRegenerateButton();
}
void SettingsDialog::on_m_pComboBoxKeyLength_currentIndexChanged(int index) {
buttonBox->button(QDialogButtonBox::Save)->setEnabled(isModified());
updateRegenButton();
updateTlsRegenerateButton();
}
void SettingsDialog::updateRegenButton() {
void SettingsDialog::updateTlsRegenerateButton() {
// Disable the Regenerate cert button if the key length is different to saved
auto keyChanged =
appConfig().getTLSKeyLength() != m_pComboBoxKeyLength->currentText();
appConfig().tlsKeyLength() != m_pComboBoxKeyLength->currentText();
auto pathChanged =
appConfig().getTLSCertPath() != m_pLineEditCertificatePath->text();
appConfig().tlsCertPath() != m_pLineEditCertificatePath->text();
// NOR the above bools, if any have changed regen should be disabled as it
// will be done on save
auto nor = !(keyChanged || pathChanged);
@ -287,82 +277,65 @@ void SettingsDialog::updateKeyLengthOnFile(const QString &path) {
auto index = m_pComboBoxKeyLength->findText(length);
m_pComboBoxKeyLength->setCurrentIndex(index);
// Also update what is in the appconfig to match the file itself
appConfig().setTLSKeyLength(length);
appConfig().setTlsKeyLength(length);
}
bool SettingsDialog::isModified() {
return (
!m_pLineEditScreenName->text().isEmpty() &&
m_pLabelNameError->text().isEmpty() &&
(appConfig().screenName() != m_pLineEditScreenName->text() ||
appConfig().port() != m_pSpinBoxPort->value() ||
appConfig().networkInterface() != m_pLineEditInterface->text() ||
appConfig().logLevel() != m_pComboLogLevel->currentIndex() ||
appConfig().logToFile() != m_pCheckBoxLogToFile->isChecked() ||
appConfig().logFilename() != m_pLineEditLogFilename->text() ||
appConfig().elevateMode() !=
static_cast<ElevateMode>(m_pComboElevate->currentIndex()) ||
appConfig().getAutoHide() != m_pCheckBoxAutoHide->isChecked() ||
appConfig().getPreventSleep() != m_pCheckBoxPreventSleep->isChecked() ||
appConfig().getMinimizeToTray() !=
m_pCheckBoxMinimizeToTray->isChecked() ||
appConfig().getTLSCertPath() != m_pLineEditCertificatePath->text() ||
appConfig().getTLSKeyLength() != m_pComboBoxKeyLength->currentText() ||
appConfig().getCryptoEnabled() != m_pCheckBoxEnableCrypto->isChecked() ||
appConfig().isSystemScoped() != m_isSystemAtStart ||
appConfig().getLanguageSync() != m_pCheckBoxLanguageSync->isChecked() ||
appConfig().getClientHostMode() !=
m_pCheckBoxClientHostMode->isChecked() ||
appConfig().getServerClientMode() !=
m_pCheckBoxServerClientMode->isChecked() ||
appConfig().getInvertScrollDirection() !=
m_pCheckBoxScrollDirection->isChecked()));
}
void SettingsDialog::updateControlsEnabled() {
bool writable = appConfig().isWritable();
void SettingsDialog::enableControls(bool enable) {
m_pLineEditScreenName->setEnabled(enable);
m_pSpinBoxPort->setEnabled(enable);
m_pLineEditInterface->setEnabled(enable);
m_pComboLogLevel->setEnabled(enable);
m_pCheckBoxLogToFile->setEnabled(enable);
m_pComboElevate->setEnabled(enable);
m_pCheckBoxAutoHide->setEnabled(enable);
m_pCheckBoxPreventSleep->setEnabled(enable);
m_pCheckBoxMinimizeToTray->setEnabled(enable);
m_pLineEditCertificatePath->setEnabled(enable);
m_pComboBoxKeyLength->setEnabled(enable);
m_pPushButtonBrowseCert->setEnabled(enable);
m_pCheckBoxEnableCrypto->setEnabled(enable);
m_labelAdminRightsMessage->setVisible(!enable);
m_pCheckBoxLanguageSync->setEnabled(enable);
m_pCheckBoxScrollDirection->setEnabled(enable);
m_pCheckBoxClientHostMode->setEnabled(enable);
m_pCheckBoxServerClientMode->setEnabled(enable);
m_pLineEditScreenName->setEnabled(writable);
m_pSpinBoxPort->setEnabled(writable);
m_pLineEditInterface->setEnabled(writable);
m_pComboLogLevel->setEnabled(writable);
m_pCheckBoxLogToFile->setEnabled(writable);
m_pComboElevate->setEnabled(writable);
m_pCheckBoxAutoHide->setEnabled(writable);
m_pCheckBoxPreventSleep->setEnabled(writable);
m_pCheckBoxMinimizeToTray->setEnabled(writable);
m_pLineEditCertificatePath->setEnabled(writable);
m_pComboBoxKeyLength->setEnabled(writable);
m_pPushButtonBrowseCert->setEnabled(writable);
m_pCheckBoxEnableCrypto->setEnabled(writable);
m_pCheckBoxClientHostMode->setEnabled(writable);
m_pCheckBoxServerClientMode->setEnabled(writable);
m_pCheckBoxServiceEnabled->setEnabled(writable);
m_pCheckBoxMinimizeOnClose->setEnabled(writable);
if (enable) {
m_pLabelLogPath->setEnabled(m_pCheckBoxLogToFile->isChecked());
m_pLineEditLogFilename->setEnabled(m_pCheckBoxLogToFile->isChecked());
m_pButtonBrowseLog->setEnabled(m_pCheckBoxLogToFile->isChecked());
m_pLabelKeyLength->setEnabled(m_pCheckBoxEnableCrypto->isChecked());
m_pComboBoxKeyLength->setEnabled(m_pCheckBoxEnableCrypto->isChecked());
m_pLabelCertificate->setEnabled(m_pCheckBoxEnableCrypto->isChecked());
m_pLineEditCertificatePath->setEnabled(
m_pCheckBoxEnableCrypto->isChecked());
m_pPushButtonBrowseCert->setEnabled(m_pCheckBoxEnableCrypto->isChecked());
updateRegenButton();
} else {
m_pLabelLogPath->setEnabled(enable);
m_pLineEditLogFilename->setEnabled(enable);
m_pButtonBrowseLog->setEnabled(enable);
m_pLabelKeyLength->setEnabled(enable);
m_pComboBoxKeyLength->setEnabled(enable);
m_pLabelCertificate->setEnabled(enable);
m_pLineEditCertificatePath->setEnabled(enable);
m_pPushButtonBrowseCert->setEnabled(enable);
m_pPushButtonRegenCert->setEnabled(enable);
m_pCheckBoxLanguageSync->setEnabled(writable && isClientMode());
m_pCheckBoxScrollDirection->setEnabled(writable && isClientMode());
#if !defined(Q_OS_WIN)
m_pCheckBoxServiceEnabled->setEnabled(false);
#endif
m_pCheckBoxClientHostMode->setEnabled(
writable && isClientMode() && appConfig().initiateConnectionFromServer());
m_pCheckBoxServerClientMode->setEnabled(
writable && !isClientMode() &&
appConfig().initiateConnectionFromServer());
m_pLabelLogPath->setEnabled(writable && m_pCheckBoxLogToFile->isChecked());
m_pLineEditLogFilename->setEnabled(
writable && m_pCheckBoxLogToFile->isChecked());
m_pButtonBrowseLog->setEnabled(writable && m_pCheckBoxLogToFile->isChecked());
updateTlsControlsEnabled();
if (writable) {
updateTlsRegenerateButton();
}
#if defined(Q_OS_WIN)
m_pComboElevate->setCurrentIndex(static_cast<int>(appConfig().elevateMode()));
#else
// elevate checkbox is only usable on ms windows.
m_pLabelElevate->setEnabled(false);
m_pComboElevate->setEnabled(false);
#endif
updateTlsControls();
}
void SettingsDialog::onChange() {
buttonBox->button(QDialogButtonBox::Save)->setEnabled(isModified());
void SettingsDialog::on_m_pScreenNameValidator_finished(const QString &error) {
m_nameError = error;
}

View File

@ -1,6 +1,6 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2012 Symless Ltd.
* Copyright (C) 2008 Volker Lanz (vl@fidra.de)
*
* This package is free software; you can redistribute it and/or
@ -16,15 +16,15 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#if !defined(SETTINGSDIALOG_H)
#define SETTINGSDIALOG_H
#pragma once
#include "ui_SettingsDialogBase.h"
#include <QDialog>
#include <memory>
#include "CoreInterface.h"
#include "validators/ScreenNameValidator.h"
#include <QDialog>
#include <memory>
class MainWindow;
class AppConfig;
@ -35,49 +35,46 @@ class SettingsDialog : public QDialog, public Ui::SettingsDialogBase {
public:
SettingsDialog(QWidget *parent, AppConfig &config);
static QString browseForSynergyc(
QWidget *parent, const QString &programDir, const QString &synergycName);
QWidget *parent, const QString &programDir,
const QString &coreClientName);
static QString browseForSynergys(
QWidget *parent, const QString &programDir, const QString &synergysName);
QWidget *parent, const QString &programDir,
const QString &coreServerName);
protected:
void accept() override;
void reject() override;
AppConfig &appConfig() { return m_appConfig; }
/// @brief Causes the dialog to load all the settings from m_appConfig
/// @brief Load all settings.
void loadFromConfig();
/// @brief Check if the regenerate button should be enabled or disabled and
/// sets it
void updateRegenButton();
/// @brief Enables or disables the TLS regenerate button.
void updateTlsRegenerateButton();
/// @brief Updates the key length value based on the loaded file
/// @param [in] QString path The path to the file to test
/// @brief Updates the key length value based on the loaded file.
void updateKeyLengthOnFile(const QString &path);
/// @brief Check if there are modifications.
/// @return true if there are modifications.
bool isModified();
/// @brief Enables controls when they should be.
void updateControlsEnabled();
/// @brief Enables\disables all controls.
void enableControls(bool enabled);
/// @brief This method setups security section in setting
void setupSeurity();
/// @brief Returns true if current mode is a client mode
bool isClientMode() const;
void updateTlsControls();
void updateTlsControlsEnabled();
private:
MainWindow *m_pMainWindow;
AppConfig &m_appConfig;
CoreInterface m_CoreInterface;
std::unique_ptr<validators::ScreenNameValidator> m_screenNameValidator;
/// @brief Stores settings scope at start of settings dialog
/// This is neccessary to restore state if user changes
/// the scope and doesn't save changes
bool m_isSystemAtStart = false;
QString m_nameError = "";
private slots:
void on_m_pCheckBoxEnableCrypto_clicked(bool checked);
void on_m_pCheckBoxLogToFile_stateChanged(int);
@ -100,8 +97,5 @@ private slots:
/// haven't changed
void on_m_pPushButtonRegenCert_clicked();
/// @brief This slot handles common functionality for all fields.
void onChange();
void on_m_pScreenNameValidator_finished(const QString &error);
};
#endif

View File

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>404</width>
<height>819</height>
<width>417</width>
<height>786</height>
</rect>
</property>
<property name="sizePolicy">
@ -38,64 +38,6 @@
<property name="verticalSpacing">
<number>5</number>
</property>
<item row="2" column="0">
<widget class="QLabel" name="m_pLabelGroupNetwork">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Security</string>
</property>
</widget>
</item>
<item row="8" column="0">
<spacer name="verticalSpacer_5">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>3</height>
</size>
</property>
</spacer>
</item>
<item row="12" column="0">
<widget class="QLabel" name="m_pLabelGroupAdvanced">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Advanced</string>
</property>
</widget>
</item>
<item row="4" column="0">
<spacer name="verticalSpacer_4">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>3</height>
</size>
</property>
</spacer>
</item>
<item row="6" column="0">
<widget class="QFrame" name="m_pGroupLog1">
<property name="styleSheet">
@ -181,7 +123,7 @@ background-color: rgba(192,192,192, 0.1);
</size>
</property>
<property name="text">
<string>&amp;Level</string>
<string>Level</string>
</property>
<property name="buddy">
<cstring>m_pComboLogLevel</cstring>
@ -285,8 +227,213 @@ background-color: rgba(192,192,192, 0.1);
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="m_pLabelGroupLog">
<item row="0" column="0">
<widget class="QFrame" name="m_pGroupBoxCommon">
<property name="styleSheet">
<string notr="true">.QFrame{
border: 1px solid rgba(192,192,192, 0.2);
border-radius: 4px;
background-color: rgba(192,192,192, 0.1);
}
</string>
</property>
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<property name="topMargin">
<number>17</number>
</property>
<property name="bottomMargin">
<number>17</number>
</property>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="m_pLabelComputerName">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>75</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Computer &amp;name</string>
</property>
<property name="buddy">
<cstring>m_pLineEditScreenName</cstring>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Maximum</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLineEdit" name="m_pLineEditScreenName">
<property name="enabled">
<bool>true</bool>
</property>
<property name="maxLength">
<number>255</number>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="topMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="m_pLabel_20">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>P&amp;ort</string>
</property>
<property name="buddy">
<cstring>m_pSpinBoxPort</cstring>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="m_pSpinBoxPort">
<property name="enabled">
<bool>true</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximum">
<number>65535</number>
</property>
<property name="value">
<number>24800</number>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="m_pLabel_21">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Network IP</string>
</property>
<property name="buddy">
<cstring>m_pLineEditInterface</cstring>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="m_pLineEditInterface">
<property name="enabled">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<property name="topMargin">
<number>0</number>
</property>
<item>
<widget class="QCheckBox" name="m_pCheckBoxMinimizeOnClose">
<property name="text">
<string>Minimize to tray on close</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_6">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QCheckBox" name="m_pCheckBoxMinimizeToTray">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<property name="layoutDirection">
<enum>Qt::LeftToRight</enum>
</property>
<property name="text">
<string>Minimize to system &amp;tray</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QCheckBox" name="m_pCheckBoxAutoHide">
<property name="text">
<string>Hide window on start</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="m_pLabelGroupNetwork">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
@ -294,12 +441,12 @@ background-color: rgba(192,192,192, 0.1);
</sizepolicy>
</property>
<property name="text">
<string>Logs</string>
<string>Security</string>
</property>
</widget>
</item>
<item row="11" column="0">
<spacer name="verticalSpacer_3">
<item row="8" column="0">
<spacer name="verticalSpacer_5">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
@ -337,104 +484,125 @@ background-color: rgba(192,192,192, 0.1);
<enum>QFrame::Raised</enum>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<item row="1" column="0" colspan="3">
<item row="7" column="0" colspan="3">
<widget class="QCheckBox" name="m_pCheckBoxScrollDirection">
<property name="text">
<string>Invert scroll direction on this computer</string>
<string>Invert scroll direction on this computer (client mode)</string>
</property>
</widget>
</item>
<item row="7" column="0">
<spacer name="verticalSpacer_6">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="4" column="0">
<widget class="QCheckBox" name="m_pCheckBoxClientHostMode">
<property name="text">
<string>Host mode</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QComboBox" name="m_pComboElevate">
<property name="toolTip">
<string>Specify when the Synergy service should run at an elevated privilege level</string>
</property>
<property name="currentIndex">
<number>0</number>
</property>
<item>
<property name="text">
<string>As Needed</string>
</property>
</item>
<item>
<property name="text">
<string>Always</string>
</property>
</item>
<item>
<property name="text">
<string>Never</string>
</property>
</item>
</widget>
</item>
<item row="2" column="0" colspan="3">
<item row="8" column="0" colspan="3">
<widget class="QCheckBox" name="m_pCheckBoxLanguageSync">
<property name="text">
<string>&amp;Use server's keyboard language on this machine</string>
<string>Use server's keyboard language on this computer (client mode)</string>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QCheckBox" name="m_pCheckBoxServerClientMode">
<item row="2" column="0">
<widget class="QCheckBox" name="m_pCheckBoxServiceEnabled">
<property name="text">
<string>Client mode</string>
<string>Use background service (daemon)</string>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="m_pLabelElevate">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<item row="3" column="0" rowspan="3" colspan="2">
<layout class="QHBoxLayout" name="horizontalLayout_9">
<item>
<widget class="QLabel" name="m_pLabelElevate">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Elevate privileges (service required)</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="m_pComboElevate">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>Specify when the Synergy service should run at an elevated privilege level</string>
</property>
<property name="currentIndex">
<number>0</number>
</property>
<item>
<property name="text">
<string>As Needed</string>
</property>
</item>
<item>
<property name="text">
<string>Always</string>
</property>
</item>
<item>
<property name="text">
<string>Never</string>
</property>
</item>
</widget>
</item>
</layout>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="m_pCheckBoxPreventSleep">
<property name="text">
<string>Elevate privileges</string>
<string>Stop this computer from sleeping</string>
</property>
</widget>
</item>
<item row="9" column="0" colspan="3">
<layout class="QHBoxLayout" name="horizontalLayout_8">
<property name="sizeConstraint">
<enum>QLayout::SetNoConstraint</enum>
</property>
<item>
<widget class="QCheckBox" name="m_pCheckBoxServerClientMode">
<property name="text">
<string>Use server as a client</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_8">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QCheckBox" name="m_pCheckBoxClientHostMode">
<property name="text">
<string>Use client in host mode</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item row="1" column="0">
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>3</height>
</size>
</property>
</spacer>
</item>
<item row="3" column="0">
<widget class="QFrame" name="m_pGroupSecurity">
<property name="styleSheet">
@ -472,7 +640,7 @@ background-color: rgba(192,192,192, 0.1);
<bool>true</bool>
</property>
<property name="text">
<string>Enable &amp;TLS encryption</string>
<string>Enable TLS encryption</string>
</property>
</widget>
</item>
@ -628,6 +796,61 @@ background-color: rgba(192,192,192, 0.1);
</layout>
</widget>
</item>
<item row="12" column="0">
<widget class="QLabel" name="m_pLabelGroupAdvanced">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Advanced</string>
</property>
</widget>
</item>
<item row="14" column="0">
<spacer name="verticalSpacer_6">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="5" column="0">
<widget class="QLabel" name="m_pLabelGroupLog">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Logs</string>
</property>
</widget>
</item>
<item row="4" column="0">
<spacer name="verticalSpacer_4">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>3</height>
</size>
</property>
</spacer>
</item>
<item row="10" column="0">
<widget class="QFrame" name="m_pGroupScope">
<property name="styleSheet">
@ -654,13 +877,6 @@ background-color: rgba(192,192,192, 0.1);
<property name="verticalSpacing">
<number>6</number>
</property>
<item row="0" column="0">
<widget class="QRadioButton" name="m_pRadioUserScope">
<property name="text">
<string>Current user</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QRadioButton" name="m_pRadioSystemScope">
<property name="text">
@ -671,33 +887,18 @@ background-color: rgba(192,192,192, 0.1);
</property>
</widget>
</item>
<item row="1" column="0" colspan="2">
<widget class="QLabel" name="m_labelAdminRightsMessage">
<property name="enabled">
<bool>false</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<weight>50</weight>
<bold>false</bold>
</font>
</property>
<item row="0" column="0">
<widget class="QRadioButton" name="m_pRadioUserScope">
<property name="text">
<string>Note: Only Admins can edit settings for all users.</string>
<string>Current user</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="20" column="0">
<widget class="QDialogButtonBox" name="buttonBox">
<item row="18" column="0">
<widget class="QDialogButtonBox" name="m_pButtonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
@ -706,56 +907,8 @@ background-color: rgba(192,192,192, 0.1);
</property>
</widget>
</item>
<item row="18" column="0">
<layout class="QGridLayout" name="m_pGridLayoutNetwork">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>1</number>
</property>
<property name="horizontalSpacing">
<number>0</number>
</property>
<property name="verticalSpacing">
<number>6</number>
</property>
<item row="0" column="0">
<widget class="QCheckBox" name="m_pCheckBoxAutoConfig">
<property name="enabled">
<bool>false</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Ignored" vsizetype="Ignored">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Enable Auto Config</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="m_pLabelInstallBonjour">
<property name="sizePolicy">
<sizepolicy hsizetype="Ignored" vsizetype="Ignored">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;a href=&quot;#&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#007af4;&quot;&gt;Install Bonjour&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="textFormat">
<enum>Qt::RichText</enum>
</property>
</widget>
</item>
</layout>
</item>
<item row="19" column="0">
<spacer name="verticalSpacer">
<item row="11" column="0">
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
@ -770,244 +923,56 @@ background-color: rgba(192,192,192, 0.1);
</property>
</spacer>
</item>
<item row="0" column="0">
<widget class="QFrame" name="m_pGroupBoxCommon">
<property name="styleSheet">
<string notr="true">.QFrame{
border: 1px solid rgba(192,192,192, 0.2);
border-radius: 4px;
background-color: rgba(192,192,192, 0.1);
}
</string>
<item row="1" column="0">
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>3</height>
</size>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<property name="topMargin">
<number>17</number>
</property>
<property name="bottomMargin">
<number>17</number>
</property>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="m_pLabelComputerName">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>75</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Computer name</string>
</property>
<property name="buddy">
<cstring>m_pLineEditScreenName</cstring>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Maximum</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLineEdit" name="m_pLineEditScreenName">
<property name="enabled">
<bool>true</bool>
</property>
<property name="maxLength">
<number>255</number>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QLabel" name="m_pLabelNameError">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="styleSheet">
<string notr="true">color: #EC4C47;
font-size: 13px;
font-family: Arial;
font-weight: bold;</string>
</property>
<property name="text">
<string/>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="topMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="m_pLabel_20">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>P&amp;ort</string>
</property>
<property name="buddy">
<cstring>m_pSpinBoxPort</cstring>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="m_pSpinBoxPort">
<property name="enabled">
<bool>true</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximum">
<number>65535</number>
</property>
<property name="value">
<number>24800</number>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="m_pLabel_21">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Network IP</string>
</property>
<property name="buddy">
<cstring>m_pLineEditInterface</cstring>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="m_pLineEditInterface">
<property name="enabled">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<property name="topMargin">
<number>0</number>
</property>
<item>
<widget class="QCheckBox" name="m_pCheckBoxAutoHide">
<property name="text">
<string>&amp;Hide on startup</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_6">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QCheckBox" name="m_pCheckBoxMinimizeToTray">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<property name="layoutDirection">
<enum>Qt::LeftToRight</enum>
</property>
<property name="text">
<string>Minimize to system &amp;tray</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QCheckBox" name="m_pCheckBoxPreventSleep">
<property name="text">
<string>Stop this computer from sleeping</string>
</property>
</widget>
</item>
</layout>
</widget>
</spacer>
</item>
</layout>
</widget>
<tabstops>
<tabstop>m_pCheckBoxAutoConfig</tabstop>
<tabstop>m_pLineEditScreenName</tabstop>
<tabstop>m_pSpinBoxPort</tabstop>
<tabstop>m_pLineEditInterface</tabstop>
<tabstop>m_pCheckBoxMinimizeOnClose</tabstop>
<tabstop>m_pCheckBoxMinimizeToTray</tabstop>
<tabstop>m_pCheckBoxAutoHide</tabstop>
<tabstop>m_pCheckBoxEnableCrypto</tabstop>
<tabstop>m_pComboBoxKeyLength</tabstop>
<tabstop>m_pLineEditCertificatePath</tabstop>
<tabstop>m_pPushButtonBrowseCert</tabstop>
<tabstop>m_pPushButtonRegenCert</tabstop>
<tabstop>m_pCheckBoxLogToFile</tabstop>
<tabstop>m_pComboLogLevel</tabstop>
<tabstop>m_pLineEditLogFilename</tabstop>
<tabstop>m_pButtonBrowseLog</tabstop>
<tabstop>m_pRadioUserScope</tabstop>
<tabstop>m_pRadioSystemScope</tabstop>
<tabstop>m_pCheckBoxPreventSleep</tabstop>
<tabstop>m_pCheckBoxServiceEnabled</tabstop>
<tabstop>m_pComboElevate</tabstop>
<tabstop>m_pCheckBoxScrollDirection</tabstop>
<tabstop>m_pCheckBoxLanguageSync</tabstop>
<tabstop>m_pCheckBoxServerClientMode</tabstop>
<tabstop>m_pCheckBoxClientHostMode</tabstop>
</tabstops>
<resources>
<include location="../res/Synergy.qrc"/>
</resources>
<connections>
<connection>
<sender>buttonBox</sender>
<sender>m_pButtonBox</sender>
<signal>accepted()</signal>
<receiver>SettingsDialogBase</receiver>
<slot>accept()</slot>
@ -1023,7 +988,7 @@ font-weight: bold;</string>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<sender>m_pButtonBox</sender>
<signal>rejected()</signal>
<receiver>SettingsDialogBase</receiver>
<slot>reject()</slot>

View File

@ -23,21 +23,72 @@
#include <QDir>
#include <QProcess>
static const char kCertificateKeyLength[] =
"rsa:"; // RSA Bit length (e.g. 1024/2048/4096)
static const char kCertificateHashAlgorithm[] =
"-sha256"; // fingerprint hashing algorithm
static const char kCertificateLifetime[] = "365";
static const char kCertificateSubjectInfo[] = "/CN=Synergy";
static const char kCertificateFilename[] = "Synergy.pem";
static const char kSslDir[] = "SSL";
static const char kUnixOpenSslCommand[] = "openssl";
// RSA Bit length (e.g. 1024/2048/4096)
static const char *const kCertificateKeyLength = "rsa:";
// fingerprint hashing algorithm
static const char *const kCertificateHashAlgorithm = "-sha256";
static const char *const kCertificateLifetime = "365";
static const char *const kCertificateSubjectInfo = "/CN=Synergy";
static const char *const kCertificateFilename = "Synergy.pem";
static const char *const kSslDir = "SSL";
#if defined(Q_OS_WIN)
static const char kWinOpenSslBinary[] = "OpenSSL\\openssl.exe";
static const char kConfigFile[] = "OpenSSL\\synergy.conf";
static const char *const kWinOpenSslDir = "OpenSSL";
static const char *const kWinOpenSslBinary = "openssl.exe";
static const char *const kConfigFile = "synergy.conf";
#elif defined(Q_OS_UNIX)
static const char *const kUnixOpenSslCommand = "openssl";
#endif
namespace synergy::gui {
#if defined(Q_OS_WIN)
QString openSslWindowsDir() {
auto appDir = QDir(QCoreApplication::applicationDirPath());
auto openSslDir = QDir(appDir.filePath(kWinOpenSslDir));
// in production, openssl is deployed with the app.
// in development, we can use the openssl path available at compile-time.
if (!openSslDir.exists()) {
openSslDir = QDir(OPENSSL_PATH);
}
// if the path still isn't found, something is seriously wrong.
if (!openSslDir.exists()) {
qFatal() << "OpenSSL dir not found: " << openSslDir;
}
return QDir::cleanPath(openSslDir.absolutePath());
}
QString openSslWindowsBinary() {
auto dir = QDir(openSslWindowsDir());
auto path = dir.filePath(kWinOpenSslBinary);
// when installed, there is no openssl bin dir; it's installed at the base.
// in development, we use the standard dir structure for openssl (bin dir).
if (!QFile::exists(path)) {
auto binDir = QDir(dir.filePath("bin"));
path = binDir.filePath(kWinOpenSslBinary);
}
// if the path still isn't found, something is seriously wrong.
if (!QFile::exists(path)) {
qFatal() << "OpenSSL binary not found: " << path;
}
return path;
}
#endif
} // namespace synergy::gui
using namespace synergy::gui;
SslCertificate::SslCertificate(QObject *parent) : QObject(parent) {
m_ProfileDir = m_CoreInterface.getProfileDir();
if (m_ProfileDir.isEmpty()) {
@ -48,17 +99,16 @@ SslCertificate::SslCertificate(QObject *parent) : QObject(parent) {
bool SslCertificate::runTool(const QStringList &args) {
QString program;
#if defined(Q_OS_WIN)
program = QCoreApplication::applicationDirPath();
program.append("\\").append(kWinOpenSslBinary);
program = openSslWindowsBinary();
#else
program = kUnixOpenSslCommand;
#endif
QStringList environment;
#if defined(Q_OS_WIN)
environment << QString("OPENSSL_CONF=%1\\%2")
.arg(QCoreApplication::applicationDirPath())
.arg(kConfigFile);
auto openSslDir = QDir(openSslWindowsDir());
auto config = QDir::cleanPath(openSslDir.filePath(kConfigFile));
environment << QString("OPENSSL_CONF=%1").arg(config);
#endif
QProcess process;
@ -73,8 +123,7 @@ bool SslCertificate::runTool(const QStringList &args) {
standardError = process.readAllStandardError().trimmed();
}
int code = process.exitCode();
if (!success || code != 0) {
if (int code = process.exitCode(); !success || code != 0) {
emit error(QString("SSL tool failed: %1\n\nCode: %2\nError: %3")
.arg(program)
.arg(process.exitCode())
@ -99,9 +148,7 @@ void SslCertificate::generateCertificate(
const QString pathToUse = path.isEmpty() ? filename : path;
// If path is empty use filename
QFile file(pathToUse);
if (!file.exists() || forceGen) {
if (QFile file(pathToUse); !file.exists() || forceGen) {
QStringList arguments;
// self signed certificate
@ -123,8 +170,7 @@ void SslCertificate::generateCertificate(
arguments.append("-newkey");
arguments.append(keySize);
QDir sslDir(sslDirPath);
if (!sslDir.exists()) {
if (QDir sslDir(sslDirPath); !sslDir.exists()) {
sslDir.mkpath(".");
}
@ -161,7 +207,7 @@ void SslCertificate::generateFingerprint(const QString &certificateFilename) {
}
// find the fingerprint from the tool output
int i = m_ToolOutput.indexOf("=");
auto i = m_ToolOutput.indexOf("=");
if (i != -1) {
i++;
QString fingerprint = m_ToolOutput.mid(i, m_ToolOutput.size() - i);

View File

@ -1,6 +1,6 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2012 Symless Ltd.
* Copyright (C) 2008 Volker Lanz (vl@fidra.de)
*
* This package is free software; you can redistribute it and/or
@ -35,6 +35,8 @@
#include <cstdlib>
#endif
using namespace synergy::gui;
class QThreadImpl : public QThread {
public:
static void msleep(unsigned long msecs) { QThread::msleep(msecs); }
@ -53,10 +55,6 @@ int main(int argc, char *argv[]) {
::setenv("QT_BEARER_POLL_TIMEOUT", "-1", 1);
#endif
#if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#endif
QCoreApplication::setOrganizationName("Synergy");
QCoreApplication::setOrganizationDomain("http://symless.com/");
QCoreApplication::setApplicationName("Synergy");
@ -78,17 +76,11 @@ int main(int argc, char *argv[]) {
}
#endif
#ifndef Q_OS_WIN
QApplication::setQuitOnLastWindowClosed(false);
#endif
AppConfig appConfig;
qRegisterMetaType<Edition>("Edition");
#ifdef SYNERGY_ENABLE_LICENSING
LicenseManager licenseManager(&appConfig);
#endif
#ifdef SYNERGY_ENABLE_LICENSING
LicenseManager licenseManager(&appConfig);
MainWindow mainWindow(appConfig, licenseManager);
#else
MainWindow mainWindow(appConfig);
@ -114,7 +106,7 @@ int main(int argc, char *argv[]) {
mainWindow.open();
}
return app.exec();
return QSynergyApplication::exec();
}
#if defined(Q_OS_MAC)

View File

@ -33,19 +33,27 @@ void LineEditValidator::addValidator(
}
QValidator::State LineEditValidator::validate(QString &input, int &pos) const {
if (m_pControl) {
showError("");
m_pControl->setStyleSheet("");
if (!m_pControl) {
qFatal("Validator control not set");
return Invalid;
}
for (const auto &validator : m_Validators) {
if (!validator->validate(input)) {
m_pControl->setStyleSheet("border: 1px solid #EC4C47");
showError(validator->getMessage());
break;
}
QString error;
for (const auto &validator : m_Validators) {
if (!validator->validate(input)) {
error = validator->getMessage();
break;
}
}
if (error.isEmpty()) {
m_pControl->setStyleSheet("");
} else {
showError(error);
m_pControl->setStyleSheet("border: 1px solid #EC4C47");
}
finished(error);
return Acceptable;
}

View File

@ -1,6 +1,6 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2012-2021 Symless Ltd.
* Copyright (C) 2012 Symless Ltd.
* Copyright (C) 2008 Volker Lanz (vl@fidra.de)
*
* This package is free software; you can redistribute it and/or
@ -15,27 +15,31 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LINEEDITVALIDATOR_H
#define LINEEDITVALIDATOR_H
#include <memory>
#include <vector>
#include <QtWidgets/QLabel>
#include <QtWidgets/QLineEdit>
#include <qvalidator.h>
#pragma once
#include "IStringValidator.h"
#include <QValidator>
#include <QtWidgets/QLabel>
#include <QtWidgets/QLineEdit>
#include <memory>
#include <vector>
namespace validators {
class LineEditValidator : public QValidator {
Q_OBJECT
public:
explicit LineEditValidator(
QLineEdit *parent = nullptr, QLabel *errors = nullptr);
QValidator::State validate(QString &input, int &pos) const override;
void addValidator(std::unique_ptr<IStringValidator> validator);
signals:
void finished(const QString &message) const;
private:
QLabel *m_pErrors = nullptr;
QLineEdit *m_pControl = nullptr;
@ -45,5 +49,3 @@ private:
};
} // namespace validators
#endif // LINEEDITVALIDATOR_H

View File

@ -558,9 +558,9 @@ String Config::formatInterval(const Interval &x) {
(int)(x.second * 100.0f + 0.5f));
}
String Config::getClientAddress() const { return m_clientAddress; }
String Config::getClientAddress() const { return m_ClientAddress; }
bool Config::isClientMode() const { return (!m_clientAddress.empty()); }
bool Config::isClientMode() const { return (!m_ClientAddress.empty()); }
void Config::readSection(ConfigReadContext &s) {
static const char s_section[] = "section:";
@ -659,7 +659,7 @@ void Config::readSectionOptions(ConfigReadContext &s) {
} else if (name == "clipboardSharingSize") {
addOption("", kOptionClipboardSharingSize, s.parseInt(value));
} else if (name == "clientAddress") {
m_clientAddress = value;
m_ClientAddress = value;
} else {
handled = false;
}

View File

@ -479,7 +479,7 @@ private:
InputFilter m_inputFilter;
bool m_hasLockToScreenAction;
IEventQueue *m_events;
String m_clientAddress;
String m_ClientAddress;
};
//! Configuration read context

View File

@ -15,7 +15,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
// TODO: fix randomly freezing on windows
// TODO: fix test freezing only on windows
#ifndef WIN32
#include "MainWindow.h"
@ -51,18 +51,16 @@ public:
};
TestMainWindow() {
m_appConfig = std::make_shared<AppConfig>(false);
#ifdef SYNERGY_ENABLE_LICENSING
m_licenseManager = std::make_shared<LicenseManager>(m_appConfig.get());
m_licenseManager = std::make_shared<LicenseManager>(&m_appConfig);
m_mainWindow =
std::make_shared<MainWindowProxy>(*m_appConfig, *m_licenseManager);
std::make_shared<MainWindowProxy>(m_appConfig, *m_licenseManager);
#else
m_mainWindow = std::make_shared<MainWindowProxy>(*m_appConfig);
m_mainWindow = std::make_shared<MainWindowProxy>(m_appConfig);
#endif
}
std::shared_ptr<AppConfig> m_appConfig;
AppConfig m_appConfig;
std::shared_ptr<LicenseManager> m_licenseManager;
std::shared_ptr<MainWindowProxy> m_mainWindow;
};

View File

@ -1,6 +1,6 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2012 Symless Ltd.
* Copyright (C) 2011 Nick Bolton
*
* This package is free software; you can redistribute it and/or
@ -18,21 +18,19 @@
#include "arch/Arch.h"
#include "base/Log.h"
#include "shared/ExitTimeout.h"
#if SYSAPI_WIN32
#include "arch/win32/ArchMiscWindows.h"
#endif
#include <fstream>
#include <gtest/gtest.h>
#include <iostream>
#define LOCK_TIMEOUT 30
void lock(const std::string &lockFile);
void unlock(const std::string &lockFile);
using synergy::test::ExitTimeout;
int main(int argc, char **argv) {
ExitTimeout exitTimeout(1, "Integration tests");
#if SYSAPI_WIN32
// record window instance for tray icon, etc
ArchMiscWindows::setInstanceWin32(GetModuleHandle(NULL));
@ -44,53 +42,10 @@ int main(int argc, char **argv) {
Log log;
log.setFilter(kDEBUG2);
std::string lockFile;
for (int i = 0; i < argc; i++) {
const std::string option(argv[i]);
if (option.find("--lock-file") != std::string::npos) {
lockFile = argv[i + 1];
}
}
if (!lockFile.empty()) {
lock(lockFile);
}
::testing::GTEST_FLAG(throw_on_failure) = true;
testing::InitGoogleTest(&argc, argv);
int result = RUN_ALL_TESTS();
if (!lockFile.empty()) {
unlock(lockFile);
}
// return code 1 means the test failed.
// any other non-zero code is probably a memory error.
return result;
return RUN_ALL_TESTS();
}
void lock(const std::string &lockFile) {
double start = ARCH->time();
// keep checking until timeout is reached.
while ((ARCH->time() - start) < LOCK_TIMEOUT) {
std::ifstream is(lockFile.c_str());
bool noLock = !is;
is.close();
if (noLock) {
break;
}
// check every second if file has gone.
ARCH->sleep(1);
}
// write empty lock file.
std::ofstream os(lockFile.c_str());
os.close();
}
void unlock(const std::string &lockFile) { remove(lockFile.c_str()); }

View 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/>.
*/
#include "ExitTimeout.h"
#include <chrono>
#include <iostream>
#include <memory>
#include <string_view>
#include <thread>
namespace synergy::test {
const auto checkMilliseconds = std::chrono::milliseconds(100);
using std::chrono::duration_cast;
using std::chrono::steady_clock;
bool timeoutReached(const steady_clock::time_point &start, const int minutes) {
auto now = steady_clock::now();
auto duration = duration_cast<std::chrono::minutes>(now - start);
return duration.count() >= minutes;
}
ExitTimeout::ExitTimeout(const int minutes, const std::string_view &name)
: m_minutes(minutes),
m_name(name),
m_thread(std::make_unique<std::thread>([this]() { run(); })) {}
ExitTimeout::~ExitTimeout() {
m_running = false;
m_thread->join();
}
void ExitTimeout::run() const {
auto start = steady_clock::now();
while (m_running) {
std::this_thread::sleep_for(checkMilliseconds);
if (timeoutReached(start, m_minutes)) {
std::cerr << m_name << " timed out after " << m_minutes << " minute(s)"
<< std::endl;
std::exit(EXIT_FAILURE);
}
}
}
} // namespace synergy::test

View File

@ -0,0 +1,47 @@
/*
* 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/>.
*/
#pragma once
#include <string_view>
#include <thread>
namespace synergy::test {
/**
* @brief Exits the program after a specified timeout, unless destroyed.
*
* The `std::thread` class is used instead of `std::jthread` as Apple Clang has
* no `std::jthread` support: https://en.cppreference.com/w/cpp/compiler_support
*
* TODO: Switch to regular Clang instead of Apple Clang:
* https://symless.atlassian.net/browse/S1-1754
*/
class ExitTimeout {
public:
ExitTimeout(const int minutes, const std::string_view &name);
~ExitTimeout();
void run() const;
private:
bool m_running = true;
int m_minutes = 0;
std::string_view m_name;
std::unique_ptr<std::thread> m_thread;
};
} // namespace synergy::test

View File

@ -1,6 +1,6 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2012 Symless Ltd.
* Copyright (C) 2011 Nick Bolton
*
* This package is free software; you can redistribute it and/or
@ -18,15 +18,19 @@
#include "arch/Arch.h"
#include "base/Log.h"
#include "shared/ExitTimeout.h"
#if SYSAPI_WIN32
#include "arch/win32/ArchMiscWindows.h"
#endif
#include <QApplication>
#include <gtest/gtest.h>
using synergy::test::ExitTimeout;
int main(int argc, char **argv) {
ExitTimeout exitTimeout(1, "Integration tests");
#if SYSAPI_WIN32
// HACK: shouldn't be needed, but logging fails without this.
ArchMiscWindows::setInstanceWin32(GetModuleHandle(NULL));