Compare commits
229 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f781ac9855 | |||
| d6087cc5bd | |||
| 6e9694b5d8 | |||
| 201df59cb7 | |||
| bcfc77fde6 | |||
| 245a522188 | |||
| fdf1df1a30 | |||
| 84b433853a | |||
| e225a357fd | |||
| 54fac87ed2 | |||
| 56a665cd18 | |||
| cb8c6fe9d9 | |||
| 239a265e18 | |||
| ee53d28af7 | |||
| 91fd139a49 | |||
| 7f1a234d06 | |||
| db20c4b0c7 | |||
| 7bd3fc1eb5 | |||
| 8fde0d764e | |||
| e1eb4ebf98 | |||
| 4b06160f84 | |||
| 2160f7826f | |||
| 7f6a68bb2f | |||
| 95521c53d6 | |||
| 446847f4fb | |||
| 37bc70896b | |||
| f9c8d08ff7 | |||
| 55c611f754 | |||
| 541e30f406 | |||
| 4b24b5b38d | |||
| df8500178b | |||
| 378fdae140 | |||
| 31e95ad2dc | |||
| 8b5a61f07f | |||
| 516f803eb4 | |||
| c1a7b836ce | |||
| 9530b9c6ba | |||
| 9df2a2c28d | |||
| 133545d03f | |||
| 75e852d95f | |||
| 9c44653fff | |||
| 2adee7c460 | |||
| 6f6e9cddb7 | |||
| fdd9b1bb6d | |||
| b2ff6aa938 | |||
| 5e4188b2fe | |||
| a3875bf71c | |||
| f3930d9520 | |||
| f66a50dab7 | |||
| 68ebc88293 | |||
| 83c8d295d4 | |||
| 07219ed431 | |||
| da5f3c0be1 | |||
| a23e35c522 | |||
| eb74d8ca99 | |||
| 65b6fe7ca3 | |||
| 9b6615328b | |||
| 7fb87b32f5 | |||
| 8508805f5d | |||
| 385a610da2 | |||
| e00058a332 | |||
| 45b6ff19e7 | |||
| 1798d7e4e6 | |||
| 854787e6b3 | |||
| 498ffe85c3 | |||
| cd3f9b2e7d | |||
| 42b16efdb9 | |||
| 003f87db9e | |||
| 86dca27e4c | |||
| 26fa6860e4 | |||
| d9798a9b2b | |||
| 70a2554370 | |||
| 13c325eb3f | |||
| a3ad66dfb0 | |||
| c9d1a50bb0 | |||
| cb3e516206 | |||
| de2e3fb9ce | |||
| 3bad718bb7 | |||
| 40c10766f3 | |||
| bf09df835d | |||
| 4a16804d27 | |||
| 5e1aa9eb5d | |||
| 3c86d9dc83 | |||
| 099262d8ce | |||
| d9e6ec4b70 | |||
| d7b20fad5c | |||
| 6e6a88af87 | |||
| ce17167248 | |||
| 656ad6402b | |||
| 329742a411 | |||
| 4df982dd6f | |||
| b1010751ba | |||
| 4238441018 | |||
| a13bd3d0bd | |||
| 516e612282 | |||
| bfd4bbd8f4 | |||
| 1c4ec6ec41 | |||
| 2ef23b8206 | |||
| ecf70f09f3 | |||
| 397c652e1c | |||
| 1666a30b94 | |||
| 827d020d16 | |||
| 0138372871 | |||
| 9e78cb55aa | |||
| 38cc678ad2 | |||
| e624e6f174 | |||
| 96b50b7d1c | |||
| ffbe2cf885 | |||
| b1b8720781 | |||
| 8609cbc20a | |||
| 7fe862b715 | |||
| 377272e917 | |||
| b051c5ae60 | |||
| 38f00da704 | |||
| dcd2c62880 | |||
| b7f29d76c3 | |||
| 55601debe0 | |||
| 6c8eca6c41 | |||
| 6444e2c208 | |||
| b3ce7c41d3 | |||
| 6963c28219 | |||
| 99ed548495 | |||
| d37bda6edb | |||
| 73de5e964e | |||
| 27451d3425 | |||
| 613f3651ea | |||
| 0e3cee6287 | |||
| 6056e5850b | |||
| 1b01a010ed | |||
| 7faf76c7df | |||
| 55f513941b | |||
| 9e74100960 | |||
| 531b988dd1 | |||
| 5647121dd8 | |||
| c1af4c3b71 | |||
| dd895ed99f | |||
| 7771dcd04c | |||
| d537a23fda | |||
| f7b98465fa | |||
| ed1bf01306 | |||
| 80f814a2da | |||
| 5355c9080b | |||
| 16517ca541 | |||
| e8ea9f53ee | |||
| 7da8c54924 | |||
| 3683db0db9 | |||
| cd0aa6496a | |||
| c583252b03 | |||
| 2c433eddd7 | |||
| 5ee39c9b00 | |||
| c1642b8d9d | |||
| f2c16c4432 | |||
| 37b4e4b57f | |||
| b502a6b848 | |||
| fe0ddf85e4 | |||
| 6990477504 | |||
| e05b35dda4 | |||
| f50e4e850b | |||
| 3cd3d7b1ff | |||
| 5a7284fd6a | |||
| 362b2e1477 | |||
| 7bf716b232 | |||
| 554178b658 | |||
| af17b14224 | |||
| 1e9f92c93f | |||
| 8bb325a2d2 | |||
| 8606dc8618 | |||
| 6362948e15 | |||
| 085a70d5a5 | |||
| 93abf4217b | |||
| 88b0a7d2e1 | |||
| 5fa70d0d0a | |||
| d01c07cab8 | |||
| 6834862413 | |||
| 4273fe2318 | |||
| 266a4a5edf | |||
| 5e6381c88a | |||
| 9aa1d6b79d | |||
| d45d6baacb | |||
| a887ac066c | |||
| 787a48424e | |||
| b20d6361d6 | |||
| b833ca7a45 | |||
| 43eab1f04c | |||
| dc9e104f8c | |||
| f456aab196 | |||
| de3b9d8e2e | |||
| b7960eecb4 | |||
| 03f142977f | |||
| 5360fb3c89 | |||
| 4eb7ea3491 | |||
| 5642879a21 | |||
| 737328d7b0 | |||
| bee0f84556 | |||
| 2721de220a | |||
| 4c6195cc5d | |||
| 1e46bd2727 | |||
| 54ecdad101 | |||
| 51a749b109 | |||
| 788f6c3eb2 | |||
| e01c595071 | |||
| bcd90434a2 | |||
| 698fd3f83c | |||
| 2a53d4f187 | |||
| 53487e757b | |||
| ef315183f3 | |||
| 8b1e8dfd9f | |||
| b73aceee7d | |||
| 3b811a1bd0 | |||
| a099276e4e | |||
| 38f8159e9d | |||
| 87fb06781c | |||
| b9017de881 | |||
| 24d1d4e620 | |||
| 3bcc1e11ed | |||
| d26c75a784 | |||
| 5b091dee56 | |||
| 3344644d2e | |||
| 39e7f60c5a | |||
| 57d1e42eca | |||
| cd45164e40 | |||
| 0ed583a7fe | |||
| 751c869435 | |||
| 4cfeadf0be | |||
| 402baf3bde | |||
| d199130b43 | |||
| 758c1044b5 | |||
| 6e8952c8a0 | |||
| bb38ad0766 |
20
.github/actions/install-dependencies/action.yml
vendored
20
.github/actions/install-dependencies/action.yml
vendored
@ -37,30 +37,26 @@ runs:
|
||||
apt update -qqq > /dev/null
|
||||
apt install -qqq cmake build-essential ninja-build \
|
||||
xorg-dev libx11-dev libxtst-dev libssl-dev \
|
||||
libglib2.0-dev libgdk-pixbuf-2.0-dev libnotify-dev \
|
||||
libxkbfile-dev qt6-base-dev qt6-tools-dev \
|
||||
libgtk-3-dev libgtest-dev libgmock-dev libpugixml-dev \
|
||||
libglib2.0-dev libxkbfile-dev qt6-base-dev qt6-tools-dev \
|
||||
libgtk-3-dev libgtest-dev libgmock-dev \
|
||||
libei-dev libportal-dev libtomlplusplus-dev libcli11-dev -y >/dev/null
|
||||
elif [ ${{inputs.like}} == "fedora" ]; then
|
||||
dnf install -y cmake make ninja-build gcc-c++ \
|
||||
rpm-build openssl-devel glib2-devel \
|
||||
gdk-pixbuf2-devel libXtst-devel libnotify-devel \
|
||||
libxkbfile-devel qt6-qtbase-devel qt6-qttools-devel \
|
||||
gtk3-devel gtest-devel gmock-devel pugixml-devel \
|
||||
libXtst-devel libxkbfile-devel qt6-qtbase-devel qt6-qttools-devel \
|
||||
gtk3-devel gtest-devel gmock-devel \
|
||||
libei-devel libportal-devel tomlplusplus-devel \
|
||||
cli11-devel
|
||||
elif [ ${{inputs.like}} == "suse" ]; then
|
||||
zypper refresh
|
||||
zypper install -y --force-resolution \
|
||||
cmake make ninja gcc-c++ rpm-build libopenssl-devel \
|
||||
glib2-devel gdk-pixbuf-devel libXtst-devel libnotify-devel \
|
||||
libxkbfile-devel qt6-base-devel qt6-tools-devel gtk3-devel \
|
||||
googletest-devel googlemock-devel pugixml-devel libei-devel \
|
||||
glib2-devel libXtst-devel libxkbfile-devel qt6-base-devel qt6-tools-devel gtk3-devel \
|
||||
googletest-devel googlemock-devel libei-devel \
|
||||
libportal-devel tomlplusplus-devel cli11-devel
|
||||
elif [ ${{ inputs.like }} == "arch" ]; then
|
||||
pacman -Syu --noconfirm base-devel cmake ninja \
|
||||
gcc openssl glib2 gdk-pixbuf2 libxtst libnotify \
|
||||
libxkbfile gtest pugixml libei libportal \
|
||||
gcc openssl glib2 libxtst libxkbfile gtest libei libportal \
|
||||
qt6-base qt6-tools gtk3 tomlplusplus cli11
|
||||
else
|
||||
echo "Unknown like"
|
||||
@ -91,7 +87,7 @@ runs:
|
||||
id: vcpkg
|
||||
uses: johnwason/vcpkg-action@v6
|
||||
with:
|
||||
pkgs: wintoast gtest pkgconf openssl
|
||||
pkgs: gtest openssl
|
||||
extra-args: --classic
|
||||
triplet: x64-windows-release
|
||||
token: ${{ github.token }}
|
||||
|
||||
2
.github/actions/lint-check/action.yml
vendored
2
.github/actions/lint-check/action.yml
vendored
@ -5,7 +5,7 @@ runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: Install Dependencies
|
||||
run: pipx install --global clang_format
|
||||
run: pipx install --global clang-format==20.1.0
|
||||
shell: bash
|
||||
|
||||
- name: Run format command
|
||||
|
||||
@ -18,8 +18,8 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
# Fallback for when git can not be found
|
||||
set(DESKFLOW_VERSION_MAJOR 1)
|
||||
set(DESKFLOW_VERSION_MINOR 20)
|
||||
set(DESKFLOW_VERSION_PATCH 1)
|
||||
set(DESKFLOW_VERSION_MINOR 21)
|
||||
set(DESKFLOW_VERSION_PATCH 0)
|
||||
set(DESKFLOW_VERSION_TWEAK 0)
|
||||
|
||||
# Get the version from git if it's a git repository
|
||||
@ -95,6 +95,22 @@ set(REQUIRED_LIBEI_VERSION 1.3)
|
||||
set(REQUIRED_LIBPORTAL_VERSION 0.8)
|
||||
set(REQUIRED_QT_VERSION 6.7.0)
|
||||
|
||||
if (MSVC)
|
||||
# On Windows, require that the same MSVC runtime is used as on the host.
|
||||
# Mitigates things like access violations caused by accidental ABI-compatibility breakage.
|
||||
set(REQUIRED_MSVC_RUNTIME_MAJOR 14)
|
||||
cmake_host_system_information(
|
||||
RESULT REQUIRED_MSVC_RUNTIME_MINOR
|
||||
QUERY WINDOWS_REGISTRY
|
||||
"HKLM/SOFTWARE/Microsoft/VisualStudio/${REQUIRED_MSVC_RUNTIME_MAJOR}.0/VC/Runtimes/x64"
|
||||
VALUE "Minor")
|
||||
if (REQUIRED_MSVC_RUNTIME_MINOR)
|
||||
message(STATUS "MSVC runtime: ${REQUIRED_MSVC_RUNTIME_MAJOR}.${REQUIRED_MSVC_RUNTIME_MINOR}")
|
||||
else()
|
||||
message(FATAL_ERROR "MSVC runtime registry entry not found")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Control debug item visibility
|
||||
# When not set logging is forced to DEBUG and show code locations
|
||||
# Also exposes a test menu
|
||||
|
||||
@ -21,7 +21,7 @@ macro(configure_libs)
|
||||
|
||||
find_package(Qt6 ${REQUIRED_QT_VERSION} REQUIRED COMPONENTS Core Widgets Network)
|
||||
if(UNIX AND NOT APPLE)
|
||||
find_package(Qt6 ${REQUIRED_QT_VERSION} REQUIRED COMPONENTS DBus)
|
||||
find_package(Qt6 ${REQUIRED_QT_VERSION} REQUIRED COMPONENTS DBus Xml)
|
||||
endif()
|
||||
|
||||
# Define the location of Qt deployment tool
|
||||
@ -89,20 +89,11 @@ macro(configure_unix_libs)
|
||||
include(CheckSymbolExists)
|
||||
include(CheckCSourceCompiles)
|
||||
|
||||
check_include_file_cxx(istream HAVE_ISTREAM)
|
||||
check_include_file_cxx(ostream HAVE_OSTREAM)
|
||||
check_include_file_cxx(sstream HAVE_SSTREAM)
|
||||
|
||||
check_include_files(locale.h HAVE_LOCALE_H)
|
||||
check_include_files(sys/select.h HAVE_SYS_SELECT_H)
|
||||
check_include_files(sys/socket.h HAVE_SYS_SOCKET_H)
|
||||
check_include_files(sys/time.h HAVE_SYS_TIME_H)
|
||||
check_include_files(sys/utsname.h HAVE_SYS_UTSNAME_H)
|
||||
check_include_files(unistd.h HAVE_UNISTD_H)
|
||||
check_include_files(wchar.h HAVE_WCHAR_H)
|
||||
|
||||
check_function_exists(getpwuid_r HAVE_GETPWUID_R)
|
||||
check_function_exists(gmtime_r HAVE_GMTIME_R)
|
||||
check_function_exists(nanosleep HAVE_NANOSLEEP)
|
||||
check_function_exists(sigwait HAVE_POSIX_SIGWAIT)
|
||||
check_function_exists(inet_aton HAVE_INET_ATON)
|
||||
@ -158,34 +149,16 @@ macro(configure_unix_libs)
|
||||
configure_xorg_libs()
|
||||
|
||||
include(FindPkgConfig)
|
||||
|
||||
find_package(PkgConfig)
|
||||
if(PKG_CONFIG_FOUND)
|
||||
pkg_check_modules(LIBXKBCOMMON REQUIRED xkbcommon)
|
||||
pkg_check_modules(GLIB2 REQUIRED glib-2.0 gio-2.0)
|
||||
pkg_check_modules(GLIB2 REQUIRED glib-2.0)
|
||||
find_library(LIBM m)
|
||||
include_directories(${LIBXKBCOMMON_INCLUDE_DIRS} ${GLIB2_INCLUDE_DIRS}
|
||||
${LIBM_INCLUDE_DIRS})
|
||||
else()
|
||||
message(WARNING "pkg-config not found, skipping wayland libraries")
|
||||
endif()
|
||||
|
||||
|
||||
find_package(pugixml REQUIRED)
|
||||
|
||||
find_package(PkgConfig)
|
||||
if(PKG_CONFIG_FOUND)
|
||||
pkg_check_modules(lib_glib REQUIRED IMPORTED_TARGET glib-2.0)
|
||||
pkg_search_module(PC_GDKPIXBUF gdk-pixbuf-2.0)
|
||||
|
||||
include_directories(${PC_GDKPIXBUF_INCLUDE_DIRS})
|
||||
|
||||
pkg_check_modules(lib_gdkpixbuf REQUIRED IMPORTED_TARGET gdk-pixbuf-2.0)
|
||||
pkg_check_modules(lib_notify REQUIRED IMPORTED_TARGET libnotify)
|
||||
|
||||
add_definitions(-DHAVE_GDK_PIXBUF=1 -DHAVE_LIBNOTIFY=1)
|
||||
else()
|
||||
message(WARNING "pkg-config not found, skipping libnotify and gdk-pixbuf")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# For config.h, set some static values; it may be a good idea to make these
|
||||
@ -200,8 +173,8 @@ macro(configure_unix_libs)
|
||||
# Unix only: For config.h, save the results based on a template (config.h.in).
|
||||
# Note that this won't work on Windows because filenames are not case sensitive,
|
||||
# and we have header files named "Config.h" (upper case 'C').
|
||||
configure_file(${CMAKE_SOURCE_DIR}/src/lib/config.h.in
|
||||
${CMAKE_BINARY_DIR}/src/lib/config.h @ONLY)
|
||||
configure_file(${CMAKE_SOURCE_DIR}/src/lib/Config.h.in
|
||||
${CMAKE_BINARY_DIR}/src/lib/Config.h @ONLY)
|
||||
|
||||
add_definitions(-DSYSAPI_UNIX=1 -DHAVE_CONFIG_H)
|
||||
|
||||
|
||||
@ -26,6 +26,7 @@
|
||||
"Hadzhylov",
|
||||
"Hetu",
|
||||
"HINSTANCE",
|
||||
"HKLM",
|
||||
"hotspots",
|
||||
"Hutterer",
|
||||
"ifdef",
|
||||
@ -65,6 +66,7 @@
|
||||
"qobject",
|
||||
"qputenv",
|
||||
"readf",
|
||||
"Redist",
|
||||
"Regen",
|
||||
"Repology",
|
||||
"Rizzitello",
|
||||
|
||||
@ -22,9 +22,7 @@ depends=(
|
||||
'libxtst'
|
||||
'libxinerama'
|
||||
'libxkbcommon-x11'
|
||||
'libnotify'
|
||||
'hicolor-icon-theme'
|
||||
'pugixml'
|
||||
'qt6-base'
|
||||
'qt6-tools'
|
||||
'libei'
|
||||
|
||||
@ -23,17 +23,6 @@ cleanup:
|
||||
- /share/gir-1.0
|
||||
- /lib/girepository-1.0
|
||||
modules:
|
||||
- name: python3-attrs
|
||||
buildsystem: simple
|
||||
build-commands:
|
||||
- pip3 install --verbose --exists-action=i --no-index --find-links="file://${PWD}"
|
||||
--prefix=${FLATPAK_DEST} --no-build-isolation attrs
|
||||
sources:
|
||||
- type: file
|
||||
url: https://files.pythonhosted.org/packages/e0/44/827b2a91a5816512fcaf3cc4ebc465ccd5d598c45cefa6703fcf4a79018f/attrs-23.2.0-py3-none-any.whl
|
||||
sha256: 99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1
|
||||
cleanup:
|
||||
- '*'
|
||||
- name: python3-Jinja2
|
||||
buildsystem: simple
|
||||
build-commands:
|
||||
@ -57,8 +46,8 @@ modules:
|
||||
sources:
|
||||
- type: git
|
||||
url: https://gitlab.freedesktop.org/libinput/libei
|
||||
tag: 1.3.0
|
||||
commit: 997b7c0f37faea4f8bae59613c8f27370925d5b0
|
||||
tag: 1.4.0
|
||||
commit: 5d6d8e6590df210b75559a889baa9459c68d9366
|
||||
- name: libportal
|
||||
buildsystem: meson
|
||||
config-opts:
|
||||
@ -70,15 +59,8 @@ modules:
|
||||
sources:
|
||||
- type: git
|
||||
url: https://github.com/flatpak/libportal.git
|
||||
tag: 0.8.1
|
||||
commit: 26c15008cbe579f57f89468384f8efc033f25f6f
|
||||
- name: puixml
|
||||
buildsystem: cmake-ninja
|
||||
sources:
|
||||
- type: git
|
||||
url: https://github.com/zeux/pugixml
|
||||
tag: v1.14
|
||||
commit: db78afc2b7d8f043b4bc6b185635d949ea2ed2a8
|
||||
tag: 0.9.1
|
||||
commit: 8f5dc8d192f6e31dafe69e35219e3b707bde71ce
|
||||
- name: cli11
|
||||
buildsystem: cmake-ninja
|
||||
config-opts:
|
||||
|
||||
@ -42,6 +42,21 @@
|
||||
</branding>
|
||||
<content_rating type="oars-1.0" />
|
||||
<releases>
|
||||
<release version="1.21.0" date="2025-03-27" urgency="high">
|
||||
<description>
|
||||
<p>This stable release removes some dependencies, additionally fixes several bugs. For the full changelog see the release page.</p>
|
||||
<ul>
|
||||
<li>Cleanup unused classes</li>
|
||||
<li>New Settings class</li>
|
||||
<li>Remove need for pugixml</li>
|
||||
<li>Remove need for libNotify</li>
|
||||
<li>Remove need for gio</li>
|
||||
<li>Remove need for gitkpixbuf</li>
|
||||
<li>Fix issues with windows installer when msvc is missing</li>
|
||||
</ul>
|
||||
</description>
|
||||
<url>https://github.com/deskflow/deskflow/releases/tag/v1.21.0</url>
|
||||
</release>
|
||||
<release version="1.20.1" date="2025-03-07" urgency="low">
|
||||
<description>
|
||||
<p>This stable release introduces a Windows dependency requirement and fixes a macOS bug.</p>
|
||||
|
||||
@ -53,3 +53,18 @@ configure_file(
|
||||
|
||||
# This patch set ups filewall rules, the service and msm module
|
||||
set(CPACK_WIX_PATCH_FILE "${CMAKE_CURRENT_BINARY_DIR}/wix-patch.xml")
|
||||
|
||||
# Creates a DLL that can be used by our MSI for custom actions.
|
||||
configure_file(
|
||||
${MY_DIR}/wix-custom.h.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/wix-custom.h @ONLY
|
||||
)
|
||||
add_library(
|
||||
wix-custom SHARED
|
||||
${MY_DIR}/wix-custom.cpp
|
||||
)
|
||||
target_include_directories(wix-custom PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
|
||||
set_target_properties(wix-custom PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
|
||||
)
|
||||
target_link_libraries(wix-custom PRIVATE Msi)
|
||||
|
||||
72
deploy/windows/wix-custom.cpp
Normal file
72
deploy/windows/wix-custom.cpp
Normal file
@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Deskflow -- mouse and keyboard sharing utility
|
||||
* SPDX-FileCopyrightText: (C) 2025 Symless Ltd.
|
||||
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
|
||||
*/
|
||||
|
||||
#include "wix-custom.h"
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <Windows.h>
|
||||
|
||||
// Include after Windows.h
|
||||
#include <MsiQuery.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
|
||||
namespace {
|
||||
// Warning: DLL will crash with error code 1603 if we exceed this.
|
||||
const auto kLogLineMax = 1024;
|
||||
|
||||
// Prefixes log messages with the app name so they're easier to find/filter.
|
||||
const std::string kLogPrefix = std::string(kAppId) + " installer: ";
|
||||
|
||||
// Note: Resized to log line max when used.
|
||||
static std::string s_logMessageBuffer; // NOSONAR - Must be mutable.
|
||||
} // namespace
|
||||
|
||||
// This log output can be viewed by using the DebugView program.
|
||||
#define MS_LOG_DEBUG(message, ...) \
|
||||
s_logMessageBuffer.resize(kLogLineMax); \
|
||||
sprintf(s_logMessageBuffer.data(), message, __VA_ARGS__); \
|
||||
OutputDebugStringA((kLogPrefix + s_logMessageBuffer + "\n").c_str())
|
||||
|
||||
extern "C" __declspec(dllexport) UINT __stdcall CheckVCRedist(MSIHANDLE hInstall)
|
||||
{
|
||||
const auto kKeyName = TEXT("SOFTWARE\\Microsoft\\VisualStudio\\14.0\\VC\\Runtimes\\x64");
|
||||
const auto kValueName = TEXT("Minor");
|
||||
const auto kProperty = "VC_REDIST_VERSION_OK";
|
||||
|
||||
MS_LOG_DEBUG("checking for msvc redist v%d.%d", kWindowsRuntimeMajor, kWindowsRuntimeMinor);
|
||||
|
||||
HKEY hKey;
|
||||
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, kKeyName, 0, KEY_READ, &hKey) != ERROR_SUCCESS) {
|
||||
MS_LOG_DEBUG("msvc redist registry key not found");
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
}
|
||||
|
||||
MS_LOG_DEBUG("msvc redist registry key found, querying minor version");
|
||||
|
||||
DWORD minorVersion = 0;
|
||||
DWORD size = sizeof(DWORD);
|
||||
RegQueryValueEx(hKey, kValueName, nullptr, nullptr, (LPBYTE)&minorVersion, &size);
|
||||
RegCloseKey(hKey);
|
||||
|
||||
MS_LOG_DEBUG("msvc redist minor version: %lu", minorVersion);
|
||||
|
||||
if (minorVersion < kWindowsRuntimeMinor) {
|
||||
MS_LOG_DEBUG("msvc redist minor version %lu too low, expected >= %d", minorVersion, kWindowsRuntimeMinor);
|
||||
// Returning success allows the installer will show a friendly error message.
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
MS_LOG_DEBUG("msvc redist version ok, setting: %s", kProperty);
|
||||
if (MsiSetProperty(hInstall, kProperty, "ok") != ERROR_SUCCESS) {
|
||||
MS_LOG_DEBUG("failed to set property: %s", kProperty);
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
}
|
||||
|
||||
MS_LOG_DEBUG("msvc redist version check successful");
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
14
deploy/windows/wix-custom.h.in
Normal file
14
deploy/windows/wix-custom.h.in
Normal file
@ -0,0 +1,14 @@
|
||||
/*
|
||||
* Deskflow -- mouse and keyboard sharing utility
|
||||
* SPDX-FileCopyrightText: (C) 2025 Symless Ltd.
|
||||
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
const auto kAppId = "@CMAKE_PROJECT_NAME@";
|
||||
|
||||
// clang-format off
|
||||
const auto kWindowsRuntimeMajor = @REQUIRED_MSVC_RUNTIME_MAJOR@;
|
||||
const auto kWindowsRuntimeMinor = @REQUIRED_MSVC_RUNTIME_MINOR@;
|
||||
// clang-format on
|
||||
@ -32,20 +32,42 @@
|
||||
<RegistrySearch
|
||||
Id="FindVCRedist"
|
||||
Root="HKLM"
|
||||
Key="SOFTWARE\Microsoft\VisualStudio\14.0\VC\Runtimes\x64"
|
||||
Key="SOFTWARE\Microsoft\VisualStudio\@REQUIRED_MSVC_RUNTIME_MAJOR@.0\VC\Runtimes\x64"
|
||||
Name="Installed"
|
||||
Type="raw" />
|
||||
</Property>
|
||||
|
||||
<CustomAction Id="Run_Deskflow" ExeCommand="Deskflow" FileRef="CM_FP_deskflow.exe" Return="asyncNoWait"/>
|
||||
|
||||
<Binary Id="CustomDLL" SourceFile="@CMAKE_CURRENT_BINARY_DIR@/wix-custom.dll" />
|
||||
|
||||
<CustomAction
|
||||
Id="CheckVCRedist"
|
||||
BinaryRef="CustomDLL"
|
||||
DllEntry="CheckVCRedist"
|
||||
Execute="immediate" />
|
||||
|
||||
<CustomAction
|
||||
Id="ShowVCRedistError"
|
||||
Error="Latest Microsoft Visual C++ Redistributable is required. Please install it before proceeding."/>
|
||||
Error="Microsoft Visual C++ Redistributable v@REQUIRED_MSVC_RUNTIME_MAJOR@.@REQUIRED_MSVC_RUNTIME_MINOR@ or later is required. Please download and install the latest version and then restart the installation. See our documentation for instructions." />
|
||||
|
||||
<CustomAction
|
||||
Id="RunDeskflow"
|
||||
ExeCommand="Deskflow"
|
||||
FileRef="CM_FP_deskflow.exe"
|
||||
Return="asyncNoWait" />
|
||||
|
||||
<InstallExecuteSequence>
|
||||
<Custom Action="ShowVCRedistError" Before="InstallServices" Condition="NOT Installed AND NOT VC_REDIST_INSTALLED"/>
|
||||
<Custom Action="Run_Deskflow" OnExit="success" Condition="NOT Installed"/>
|
||||
<Custom
|
||||
Action="CheckVCRedist"
|
||||
Before="InstallInitialize"
|
||||
Condition="NOT Installed AND VC_REDIST_INSTALLED" />
|
||||
<Custom
|
||||
Action="ShowVCRedistError"
|
||||
Before="InstallInitialize"
|
||||
Condition="NOT Installed AND (NOT VC_REDIST_INSTALLED OR NOT VC_REDIST_VERSION_OK)" />
|
||||
<Custom
|
||||
Action="RunDeskflow"
|
||||
OnExit="success"
|
||||
Condition="NOT Installed" />
|
||||
</InstallExecuteSequence>
|
||||
</CPackWiXFragment>
|
||||
</CPackWiXPatch>
|
||||
|
||||
@ -8,7 +8,7 @@
|
||||
#include "arch/Arch.h"
|
||||
#include "base/EventQueue.h"
|
||||
#include "base/Log.h"
|
||||
#include "common/constants.h"
|
||||
#include "common/Settings.h"
|
||||
#include "deskflow/DaemonApp.h"
|
||||
#include "deskflow/ipc/DaemonIpcServer.h"
|
||||
|
||||
@ -21,12 +21,13 @@
|
||||
|
||||
#endif
|
||||
|
||||
#include <QCommandLineParser>
|
||||
#include <QCoreApplication>
|
||||
#include <QThread>
|
||||
|
||||
using namespace deskflow::core;
|
||||
|
||||
void handleError(const char *message);
|
||||
void handleError(const char *message = "Unrecognized error.");
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
@ -43,84 +44,86 @@ int main(int argc, char **argv)
|
||||
Log log;
|
||||
EventQueue events;
|
||||
|
||||
auto &daemon = DaemonApp::instance();
|
||||
DaemonApp::InitResult initResult;
|
||||
try {
|
||||
initResult = daemon.init(&events, argc, argv);
|
||||
} catch (std::exception &e) {
|
||||
handleError(e.what());
|
||||
return kExitFailed;
|
||||
} catch (...) {
|
||||
handleError("Unrecognized error.");
|
||||
return kExitFailed;
|
||||
// Daemon deliberately does not have a parent, as it will be moved to a new thread.
|
||||
DaemonApp daemon(events);
|
||||
|
||||
QCoreApplication app(argc, argv);
|
||||
QCoreApplication::setApplicationName(QStringLiteral("%1 Daemon").arg(kAppName));
|
||||
|
||||
QCommandLineParser parser;
|
||||
parser.addHelpOption();
|
||||
parser.addVersionOption();
|
||||
|
||||
const auto foregroundOption = QCommandLineOption({"f", "foreground"}, "Run in the foreground (show console)");
|
||||
parser.addOption(foregroundOption);
|
||||
|
||||
const auto installOption = QCommandLineOption({"i", "install"}, "Install as a Windows service");
|
||||
parser.addOption(installOption);
|
||||
|
||||
const auto uninstallOption = QCommandLineOption({"u", "uninstall"}, "Uninstall the Windows service");
|
||||
parser.addOption(uninstallOption);
|
||||
|
||||
parser.process(app);
|
||||
|
||||
if (parser.isSet(foregroundOption)) {
|
||||
daemon.setForeground();
|
||||
}
|
||||
|
||||
// Important: Log the app name and version number to the log file after the daemon app init
|
||||
// because the file log outputter is created there. Logging before would only log to stdout
|
||||
// which is not useful for troubleshooting Windows services.
|
||||
// Depends on whether foreground option was set.
|
||||
daemon.initLogging();
|
||||
|
||||
// Important: Log the app name and version number to the log file daemon app has initialized
|
||||
// logging as it creates the file logger. Logging before would only log to stdout which is not
|
||||
// useful for troubleshooting Windows services.
|
||||
// It's important to write the version number to the log file so we can be certain the old daemon
|
||||
// was uninstalled, since sometimes Windows services can get stuck and fail to be removed.
|
||||
LOG_PRINT("%s Daemon v%s", kAppName, kDisplayVersion);
|
||||
LOG_PRINT("%s v%s", QCoreApplication::applicationName().toStdString().c_str(), kDisplayVersion);
|
||||
|
||||
switch (initResult) {
|
||||
using enum DaemonApp::InitResult;
|
||||
// Default log level to system setting (found in Registry).
|
||||
auto logLevel = Settings::value(Settings::Daemon::LogLevel).toString().toStdString();
|
||||
if (logLevel != "") {
|
||||
CLOG->setFilter(logLevel.c_str());
|
||||
LOG_DEBUG("log level: %s", logLevel.c_str());
|
||||
}
|
||||
|
||||
case StartDaemon: {
|
||||
LOG_INFO("starting daemon");
|
||||
QCoreApplication app(argc, argv);
|
||||
try {
|
||||
|
||||
#if SYSAPI_WIN32
|
||||
// Show warning if not running as admin as daemon will behave differently.
|
||||
if (!ArchMiscWindows::isProcessElevated()) {
|
||||
LOG_WARN("not running as admin, some features may not work");
|
||||
}
|
||||
#endif
|
||||
|
||||
if (parser.isSet(installOption)) {
|
||||
daemon.install();
|
||||
return kExitSuccess;
|
||||
} else if (parser.isSet(uninstallOption)) {
|
||||
daemon.uninstall();
|
||||
return kExitSuccess;
|
||||
}
|
||||
|
||||
const auto ipcServer =
|
||||
new ipc::DaemonIpcServer(&app, DaemonApp::logFilename().toStdString().c_str()); // NOSONAR - Qt managed
|
||||
ipcServer->listen();
|
||||
daemon.connectIpcServer(ipcServer);
|
||||
|
||||
QThread daemonThread;
|
||||
daemon.moveToThread(&daemonThread);
|
||||
|
||||
QObject::connect(&daemonThread, &QThread::started, [&daemon, &daemonThread]() {
|
||||
LOG_DEBUG("daemon thread started");
|
||||
daemon.run();
|
||||
daemonThread.quit();
|
||||
LOG_DEBUG("daemon thread finished");
|
||||
});
|
||||
QObject::connect(&daemonThread, &QThread::finished, &app, &QCoreApplication::quit);
|
||||
daemon.run(daemonThread);
|
||||
|
||||
ipc::DaemonIpcServer ipcServer(&app, QString::fromStdString(daemon.logFilename()));
|
||||
|
||||
// Use direct connection as the daemon app is on it's own thread, and so is on a different event loop.
|
||||
QObject::connect(
|
||||
&ipcServer, &ipc::DaemonIpcServer::logLevelChanged, &daemon, &DaemonApp::saveLogLevel, //
|
||||
Qt::DirectConnection
|
||||
);
|
||||
QObject::connect(
|
||||
&ipcServer, &ipc::DaemonIpcServer::elevateModeChanged, &daemon, &DaemonApp::setElevate, //
|
||||
Qt::DirectConnection
|
||||
);
|
||||
QObject::connect(
|
||||
&ipcServer, &ipc::DaemonIpcServer::commandChanged, &daemon, &DaemonApp::setCommand, //
|
||||
Qt::DirectConnection
|
||||
);
|
||||
QObject::connect(
|
||||
&ipcServer, &ipc::DaemonIpcServer::startProcessRequested, &daemon, &DaemonApp::applyWatchdogCommand, //
|
||||
Qt::DirectConnection
|
||||
);
|
||||
QObject::connect(
|
||||
&ipcServer, &ipc::DaemonIpcServer::stopProcessRequested, &daemon, &DaemonApp::clearWatchdogCommand, //
|
||||
Qt::DirectConnection
|
||||
);
|
||||
QObject::connect(
|
||||
&ipcServer, &ipc::DaemonIpcServer::clearSettingsRequested, &daemon, &DaemonApp::clearSettings, //
|
||||
Qt::DirectConnection
|
||||
);
|
||||
|
||||
daemonThread.start();
|
||||
const auto exitCode = QCoreApplication::exec();
|
||||
daemonThread.wait();
|
||||
|
||||
LOG_DEBUG("daemon exited, code: %d", exitCode);
|
||||
return exitCode;
|
||||
}
|
||||
|
||||
case FatalError:
|
||||
} catch (std::exception &e) {
|
||||
handleError(e.what());
|
||||
return kExitFailed;
|
||||
} catch (...) {
|
||||
handleError();
|
||||
return kExitFailed;
|
||||
|
||||
default:
|
||||
return kExitSuccess;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -48,6 +48,8 @@ add_executable(${target} WIN32 MACOSX_BUNDLE
|
||||
Action.h
|
||||
DataDownloader.cpp
|
||||
DataDownloader.h
|
||||
Diagnostic.cpp
|
||||
Diagnostic.h
|
||||
Hotkey.cpp
|
||||
Hotkey.h
|
||||
KeySequence.cpp
|
||||
@ -56,13 +58,11 @@ add_executable(${target} WIN32 MACOSX_BUNDLE
|
||||
MainWindow.cpp
|
||||
MainWindow.h
|
||||
MainWindow.ui
|
||||
ProcessorArch.h
|
||||
QUtility.cpp
|
||||
QUtility.h
|
||||
ScreenSetupModel.cpp
|
||||
ScreenSetupModel.h
|
||||
ServerConfig.cpp
|
||||
ServerConfig.h
|
||||
StyleUtils.h
|
||||
VersionChecker.cpp
|
||||
VersionChecker.h
|
||||
dialogs/AboutDialog.cpp
|
||||
@ -88,6 +88,24 @@ add_executable(${target} WIN32 MACOSX_BUNDLE
|
||||
dialogs/SettingsDialog.cpp
|
||||
dialogs/SettingsDialog.h
|
||||
dialogs/SettingsDialog.ui
|
||||
validators/AliasValidator.cpp
|
||||
validators/AliasValidator.h
|
||||
validators/ComputerNameValidator.cpp
|
||||
validators/ComputerNameValidator.h
|
||||
validators/EmptyStringValidator.cpp
|
||||
validators/EmptyStringValidator.h
|
||||
validators/IStringValidator.cpp
|
||||
validators/IStringValidator.h
|
||||
validators/LineEditValidator.cpp
|
||||
validators/LineEditValidator.h
|
||||
validators/ScreenDuplicationsValidator.cpp
|
||||
validators/ScreenDuplicationsValidator.h
|
||||
validators/ScreenNameValidator.cpp
|
||||
validators/ScreenNameValidator.h
|
||||
validators/SpacesValidator.cpp
|
||||
validators/SpacesValidator.h
|
||||
validators/ValidationError.cpp
|
||||
validators/ValidationError.h
|
||||
widgets/FingerprintPreview.h
|
||||
widgets/FingerprintPreview.cpp
|
||||
widgets/KeySequenceWidget.cpp
|
||||
|
||||
@ -4,12 +4,11 @@
|
||||
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
|
||||
*/
|
||||
|
||||
#include "diagnostic.h"
|
||||
#include "Diagnostic.h"
|
||||
|
||||
#include "config/ConfigScopes.h"
|
||||
#include "paths.h"
|
||||
#include "common/Settings.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QCoreApplication>
|
||||
#include <QDir>
|
||||
#include <QProcess>
|
||||
|
||||
@ -27,23 +26,19 @@ void restart()
|
||||
QProcess::startDetached(program, arguments);
|
||||
|
||||
qDebug("exiting current process");
|
||||
QApplication::exit();
|
||||
QCoreApplication::exit();
|
||||
}
|
||||
|
||||
void clearSettings(ConfigScopes &scopes, bool enableRestart)
|
||||
void clearSettings(bool enableRestart)
|
||||
{
|
||||
qDebug("clearing settings");
|
||||
scopes.clear();
|
||||
Settings::proxy().clear();
|
||||
|
||||
// save but do not emit saving signal which will prevent the current state of
|
||||
// the app config and server configs from being applied.
|
||||
scopes.save(false);
|
||||
Settings::save(false);
|
||||
|
||||
auto configDir = paths::configDir();
|
||||
qDebug("removing config dir: %s", qPrintable(configDir.absolutePath()));
|
||||
configDir.removeRecursively();
|
||||
|
||||
auto profileDir = paths::coreProfileDir();
|
||||
auto profileDir = QDir(Settings::settingsPath());
|
||||
qDebug("removing profile dir: %s", qPrintable(profileDir.absolutePath()));
|
||||
profileDir.removeRecursively();
|
||||
|
||||
@ -6,10 +6,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "gui/config/ConfigScopes.h"
|
||||
|
||||
namespace deskflow::gui::diagnostic {
|
||||
|
||||
void clearSettings(ConfigScopes &scopes, bool enableRestart);
|
||||
void clearSettings(bool enableRestart);
|
||||
|
||||
}
|
||||
@ -9,28 +9,27 @@
|
||||
#include "MainWindow.h"
|
||||
#include "ui_MainWindow.h"
|
||||
|
||||
#include "Diagnostic.h"
|
||||
#include "StyleUtils.h"
|
||||
|
||||
#include "dialogs/AboutDialog.h"
|
||||
#include "dialogs/FingerprintDialog.h"
|
||||
#include "dialogs/ServerConfigDialog.h"
|
||||
#include "dialogs/SettingsDialog.h"
|
||||
|
||||
#include "base/String.h"
|
||||
#include "common/constants.h"
|
||||
#include "common/Settings.h"
|
||||
#include "common/UrlConstants.h"
|
||||
#include "gui/Logger.h"
|
||||
#include "gui/config/ConfigScopes.h"
|
||||
#include "gui/constants.h"
|
||||
#include "gui/Messages.h"
|
||||
#include "gui/Styles.h"
|
||||
#include "gui/core/CoreProcess.h"
|
||||
#include "gui/diagnostic.h"
|
||||
#include "gui/ipc/DaemonIpcClient.h"
|
||||
#include "gui/messages.h"
|
||||
#include "gui/string_utils.h"
|
||||
#include "gui/style_utils.h"
|
||||
#include "gui/styles.h"
|
||||
#include "net/FingerprintDatabase.h"
|
||||
#include "platform/wayland.h"
|
||||
#include "platform/Wayland.h"
|
||||
|
||||
#if defined(Q_OS_LINUX)
|
||||
#include "config.h"
|
||||
#include "Config.h"
|
||||
#endif
|
||||
|
||||
#include <QApplication>
|
||||
@ -56,19 +55,16 @@
|
||||
|
||||
using namespace deskflow::gui;
|
||||
|
||||
using CoreMode = CoreProcess::Mode;
|
||||
using CoreConnectionState = CoreProcess::ConnectionState;
|
||||
using CoreProcessState = CoreProcess::ProcessState;
|
||||
|
||||
MainWindow::MainWindow(ConfigScopes &configScopes, AppConfig &appConfig)
|
||||
MainWindow::MainWindow()
|
||||
: ui{std::make_unique<Ui::MainWindow>()},
|
||||
m_configScopes(configScopes),
|
||||
m_appConfig(appConfig),
|
||||
m_serverConfig(appConfig, *this),
|
||||
m_coreProcess(appConfig, m_serverConfig),
|
||||
m_serverConnection(this, appConfig, m_serverConfig, m_serverConfigDialogState),
|
||||
m_clientConnection(this, appConfig),
|
||||
m_tlsUtility(appConfig),
|
||||
m_serverConfig(*this),
|
||||
m_coreProcess(m_serverConfig),
|
||||
m_serverConnection(this, m_serverConfig),
|
||||
m_clientConnection(this),
|
||||
m_tlsUtility(this),
|
||||
m_trayIcon{new QSystemTrayIcon(this)},
|
||||
m_guiDupeChecker{new QLocalServer(this)},
|
||||
m_daemonIpcClient{new ipc::DaemonIpcClient(this)},
|
||||
@ -83,12 +79,9 @@ MainWindow::MainWindow(ConfigScopes &configScopes, AppConfig &appConfig)
|
||||
m_actionQuit{new QAction(tr("&Quit"), this)},
|
||||
m_actionTrayQuit{new QAction(tr("&Quit"), this)},
|
||||
m_actionRestore{new QAction(tr("&Open Deskflow"), this)},
|
||||
m_actionSave{new QAction(tr("Save configuration &as..."), this)},
|
||||
m_actionSettings{new QAction(tr("Preferences"), this)},
|
||||
m_actionStartCore{new QAction(tr("&Start"), this)},
|
||||
m_actionStopCore{new QAction(tr("S&top"), this)},
|
||||
m_actionTestCriticalError{new QAction(tr("Test Critical Error"), this)},
|
||||
m_actionTestFatalError{new QAction(tr("Test Fatal Error"), this)}
|
||||
m_actionStopCore{new QAction(tr("S&top"), this)}
|
||||
{
|
||||
const auto themeName = QStringLiteral("deskflow-%1").arg(iconMode());
|
||||
if (QIcon::themeName().isEmpty())
|
||||
@ -120,9 +113,6 @@ MainWindow::MainWindow(ConfigScopes &configScopes, AppConfig &appConfig)
|
||||
m_actionSettings->setMenuRole(QAction::PreferencesRole);
|
||||
m_actionSettings->setIcon(QIcon::fromTheme(QStringLiteral("configure")));
|
||||
|
||||
m_actionSave->setShortcut(QKeySequence(tr("Ctrl+Alt+S")));
|
||||
m_actionSave->setIcon(QIcon::fromTheme(QIcon::ThemeIcon::DocumentSaveAs));
|
||||
|
||||
m_actionStartCore->setShortcut(QKeySequence(tr("Ctrl+S")));
|
||||
m_actionStartCore->setIcon(QIcon::fromTheme(QStringLiteral("system-run")));
|
||||
|
||||
@ -146,25 +136,23 @@ MainWindow::MainWindow(ConfigScopes &configScopes, AppConfig &appConfig)
|
||||
|
||||
setupTrayIcon();
|
||||
|
||||
m_configScopes.signalReady();
|
||||
|
||||
updateScreenName();
|
||||
applyConfig();
|
||||
restoreWindow();
|
||||
|
||||
qDebug().noquote() << "active settings path:" << m_configScopes.activeFilePath();
|
||||
qDebug().noquote() << "active settings path:" << Settings::settingsPath();
|
||||
|
||||
updateSize();
|
||||
|
||||
// Force generation of SHA256 for the localhost
|
||||
if (m_appConfig.tlsEnabled()) {
|
||||
if (!QFile::exists(localFingerprintDb())) {
|
||||
if (Settings::value(Settings::Security::TlsEnabled).toBool()) {
|
||||
if (!QFile::exists(Settings::tlsLocalDb())) {
|
||||
regenerateLocalFingerprints();
|
||||
return;
|
||||
}
|
||||
|
||||
deskflow::FingerprintDatabase db;
|
||||
db.read(localFingerprintDb().toStdString());
|
||||
db.read(Settings::tlsLocalDb().toStdString());
|
||||
if (db.fingerprints().size() != kTlsDbSize) {
|
||||
regenerateLocalFingerprints();
|
||||
}
|
||||
@ -179,36 +167,33 @@ MainWindow::~MainWindow()
|
||||
|
||||
void MainWindow::restoreWindow()
|
||||
{
|
||||
const auto &windowSize = m_appConfig.mainWindowSize();
|
||||
if (windowSize.has_value()) {
|
||||
qDebug() << "restoring main window size";
|
||||
m_expandedSize = windowSize.value();
|
||||
}
|
||||
|
||||
const auto &windowPosition = m_appConfig.mainWindowPosition();
|
||||
if (windowPosition.has_value()) {
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
int w = 0;
|
||||
int h = 0;
|
||||
for (auto screen : QGuiApplication::screens()) {
|
||||
auto geo = screen->geometry();
|
||||
x = std::min(geo.x(), x);
|
||||
y = std::min(geo.y(), y);
|
||||
w = std::max(geo.x() + geo.width(), w);
|
||||
h = std::max(geo.y() + geo.height(), h);
|
||||
}
|
||||
const QSize totalScreenSize(w, h);
|
||||
const QPoint point = windowPosition.value();
|
||||
if (point.x() < totalScreenSize.width() && point.y() < totalScreenSize.height()) {
|
||||
qDebug() << "restoring main window position";
|
||||
move(point);
|
||||
}
|
||||
} else {
|
||||
const auto windowGeometry = Settings::value(Settings::Gui::WindowGeometry).toRect();
|
||||
if (!windowGeometry.isValid()) {
|
||||
// center main window in middle of screen
|
||||
const auto screen = QGuiApplication::primaryScreen();
|
||||
QRect screenGeometry = screen->geometry();
|
||||
move(screenGeometry.center() - rect().center());
|
||||
return;
|
||||
}
|
||||
|
||||
m_expandedSize = windowGeometry.size();
|
||||
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
int w = 0;
|
||||
int h = 0;
|
||||
const auto screens = QGuiApplication::screens();
|
||||
for (auto screen : screens) {
|
||||
auto geo = screen->geometry();
|
||||
x = std::min(geo.x(), x);
|
||||
y = std::min(geo.y(), y);
|
||||
w = std::max(geo.x() + geo.width(), w);
|
||||
h = std::max(geo.y() + geo.height(), h);
|
||||
}
|
||||
const QRect screensGeometry(x, y, w, h);
|
||||
if (screensGeometry.contains(windowGeometry)) {
|
||||
qDebug() << "restoring main window position";
|
||||
move(windowGeometry.topLeft());
|
||||
}
|
||||
}
|
||||
|
||||
@ -218,15 +203,16 @@ void MainWindow::setupControls()
|
||||
|
||||
secureSocket(false);
|
||||
|
||||
ui->btnConfigureServer->setIcon(QIcon::fromTheme(QStringLiteral("configure")));
|
||||
ui->lblIpAddresses->setText(tr("This computer's IP addresses: %1").arg(getIPAddresses()));
|
||||
|
||||
if (m_appConfig.lastVersion() != kVersion) {
|
||||
m_appConfig.setLastVersion(kVersion);
|
||||
if (Settings::value(Settings::Core::LastVersion).toString() != kVersion) {
|
||||
Settings::setValue(Settings::Core::LastVersion, kVersion);
|
||||
}
|
||||
|
||||
// Setup the log toggle, set its initial state to closed
|
||||
ui->btnToggleLog->setStyleSheet(kStyleFlatButton);
|
||||
if (m_appConfig.logExpanded()) {
|
||||
if (Settings::value(Settings::Gui::LogExpanded).toBool()) {
|
||||
ui->btnToggleLog->setArrowType(Qt::DownArrow);
|
||||
ui->textLog->setVisible(true);
|
||||
ui->btnToggleLog->click();
|
||||
@ -236,11 +222,13 @@ void MainWindow::setupControls()
|
||||
|
||||
ui->serverOptions->setVisible(false);
|
||||
ui->clientOptions->setVisible(false);
|
||||
ui->rbModeClient->setChecked(m_appConfig.clientGroupChecked());
|
||||
ui->rbModeServer->setChecked(m_appConfig.serverGroupChecked());
|
||||
|
||||
if (m_appConfig.clientGroupChecked() || m_appConfig.serverGroupChecked())
|
||||
updateModeControls(m_appConfig.serverGroupChecked());
|
||||
const auto coreMode = Settings::value(Settings::Core::CoreMode).value<Settings::CoreMode>();
|
||||
ui->rbModeClient->setChecked(coreMode == Settings::CoreMode::Client);
|
||||
ui->rbModeServer->setChecked(coreMode == Settings::CoreMode::Server);
|
||||
|
||||
if (coreMode != Settings::CoreMode::None)
|
||||
updateModeControls(coreMode == Settings::CoreMode::Server);
|
||||
|
||||
ui->lineEditName->setValidator(new QRegularExpressionValidator(m_nameRegEx, this));
|
||||
ui->lineEditName->setVisible(false);
|
||||
@ -292,11 +280,8 @@ void MainWindow::connectSlots()
|
||||
|
||||
connect(this, &MainWindow::shown, this, &MainWindow::firstShown, Qt::QueuedConnection);
|
||||
|
||||
connect(&m_configScopes, &ConfigScopes::saving, this, &MainWindow::configScopesSaving, Qt::DirectConnection);
|
||||
|
||||
connect(&m_appConfig, &AppConfig::tlsChanged, this, &MainWindow::appConfigTlsChanged);
|
||||
connect(&m_appConfig, &AppConfig::screenNameChanged, this, &MainWindow::updateScreenName);
|
||||
connect(&m_appConfig, &AppConfig::logLevelChanged, &m_coreProcess, &CoreProcess::applyLogLevel);
|
||||
connect(Settings::instance(), &Settings::serverSettingsChanged, this, &MainWindow::serverConfigSaving);
|
||||
connect(Settings::instance(), &Settings::settingsChanged, this, &MainWindow::settingsChanged);
|
||||
|
||||
connect(&m_coreProcess, &CoreProcess::starting, this, &MainWindow::coreProcessStarting, Qt::DirectConnection);
|
||||
connect(&m_coreProcess, &CoreProcess::error, this, &MainWindow::coreProcessError);
|
||||
@ -313,12 +298,9 @@ void MainWindow::connectSlots()
|
||||
connect(m_actionQuit, &QAction::triggered, this, &MainWindow::close);
|
||||
connect(m_actionTrayQuit, &QAction::triggered, this, &MainWindow::close);
|
||||
connect(m_actionRestore, &QAction::triggered, this, &MainWindow::showAndActivate);
|
||||
connect(m_actionSave, &QAction::triggered, this, &MainWindow::saveConfig);
|
||||
connect(m_actionSettings, &QAction::triggered, this, &MainWindow::openSettings);
|
||||
connect(m_actionStartCore, &QAction::triggered, this, &MainWindow::startCore);
|
||||
connect(m_actionStopCore, &QAction::triggered, this, &MainWindow::stopCore);
|
||||
connect(m_actionTestFatalError, &QAction::triggered, this, &MainWindow::testFatalError);
|
||||
connect(m_actionTestCriticalError, &QAction::triggered, this, &MainWindow::testCriticalError);
|
||||
|
||||
connect(&m_versionChecker, &VersionChecker::updateFound, this, &MainWindow::versionCheckerUpdateFound);
|
||||
|
||||
@ -339,6 +321,7 @@ void MainWindow::connectSlots()
|
||||
connect(ui->lineHostname, &QLineEdit::returnPressed, ui->btnConnect, &QPushButton::click);
|
||||
connect(ui->lineHostname, &QLineEdit::textChanged, &m_coreProcess, &deskflow::gui::CoreProcess::setAddress);
|
||||
|
||||
connect(ui->btnSaveServerConfig, &QPushButton::clicked, this, &MainWindow::saveServerConfig);
|
||||
connect(ui->btnConfigureServer, &QPushButton::clicked, this, [this] { showConfigureServer(""); });
|
||||
connect(ui->lblComputerName, &QLabel::linkActivated, this, &MainWindow::openSettings);
|
||||
connect(m_btnFingerprint, &QToolButton::clicked, this, &MainWindow::showMyFingerprint);
|
||||
@ -361,16 +344,14 @@ void MainWindow::toggleLogVisible(bool visible)
|
||||
{
|
||||
if (visible) {
|
||||
ui->btnToggleLog->setArrowType(Qt::DownArrow);
|
||||
ui->textLog->setVisible(true);
|
||||
m_appConfig.setLogExpanded(true);
|
||||
} else {
|
||||
ui->btnToggleLog->setArrowType(Qt::RightArrow);
|
||||
m_expandedSize = size();
|
||||
ui->textLog->setVisible(false);
|
||||
m_appConfig.setLogExpanded(false);
|
||||
}
|
||||
// 1 ms delay is to make sure we have left the function before calling updateSize
|
||||
QTimer::singleShot(1, this, &MainWindow::updateSize);
|
||||
ui->textLog->setVisible(visible);
|
||||
Settings::setValue(Settings::Gui::LogExpanded, visible);
|
||||
// 15 ms delay is to make sure we have left the function before calling updateSize
|
||||
QTimer::singleShot(15, this, &MainWindow::updateSize);
|
||||
}
|
||||
|
||||
void MainWindow::firstShown()
|
||||
@ -386,17 +367,30 @@ void MainWindow::firstShown()
|
||||
QTimer::singleShot(kCriticalDialogDelay, this, &messages::raiseCriticalDialog);
|
||||
}
|
||||
|
||||
void MainWindow::configScopesSaving()
|
||||
void MainWindow::settingsChanged(const QString &key)
|
||||
{
|
||||
m_serverConfig.commit();
|
||||
if (key == Settings::Log::Level) {
|
||||
m_coreProcess.applyLogLevel();
|
||||
return;
|
||||
}
|
||||
|
||||
if (key == Settings::Core::ScreenName)
|
||||
updateScreenName();
|
||||
|
||||
if ((key == Settings::Security::Certificate) || (key == Settings::Security::KeySize) ||
|
||||
(key == Settings::Security::TlsEnabled) || (key == Settings::Security::CheckPeers)) {
|
||||
const auto certificate = Settings::value(Settings::Security::Certificate).toString();
|
||||
if (m_tlsUtility.isEnabled() && !QFile::exists(certificate)) {
|
||||
m_tlsUtility.generateCertificate();
|
||||
}
|
||||
updateSecurityIcon(m_lblSecurityStatus->isVisible());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::appConfigTlsChanged()
|
||||
void MainWindow::serverConfigSaving()
|
||||
{
|
||||
if (m_tlsUtility.isEnabled() && !QFile::exists(m_appConfig.tlsCertPath())) {
|
||||
m_tlsUtility.generateCertificate();
|
||||
}
|
||||
updateSecurityIcon(m_lblSecurityStatus->isVisible());
|
||||
m_serverConfig.commit();
|
||||
}
|
||||
|
||||
void MainWindow::trayIconActivated(QSystemTrayIcon::ActivationReason reason)
|
||||
@ -409,7 +403,7 @@ void MainWindow::trayIconActivated(QSystemTrayIcon::ActivationReason reason)
|
||||
void MainWindow::versionCheckerUpdateFound(const QString &version)
|
||||
{
|
||||
m_btnUpdate->setVisible(true);
|
||||
m_btnUpdate->setToolTip(tr("A new version v%1 is avilable").arg(version));
|
||||
m_btnUpdate->setToolTip(tr("A new version v%1 is available").arg(version));
|
||||
}
|
||||
|
||||
void MainWindow::coreProcessError(CoreProcess::Error error)
|
||||
@ -441,16 +435,6 @@ void MainWindow::stopCore()
|
||||
m_coreProcess.stop();
|
||||
}
|
||||
|
||||
void MainWindow::testFatalError() const
|
||||
{
|
||||
qFatal() << "test fatal error";
|
||||
}
|
||||
|
||||
void MainWindow::testCriticalError() const
|
||||
{
|
||||
qCritical() << "test critical error";
|
||||
}
|
||||
|
||||
void MainWindow::clearSettings()
|
||||
{
|
||||
if (!messages::showClearSettings(this)) {
|
||||
@ -462,15 +446,15 @@ void MainWindow::clearSettings()
|
||||
m_coreProcess.clearSettings();
|
||||
|
||||
m_saveOnExit = false;
|
||||
diagnostic::clearSettings(m_configScopes, true);
|
||||
diagnostic::clearSettings(true);
|
||||
}
|
||||
|
||||
bool MainWindow::saveConfig()
|
||||
bool MainWindow::saveServerConfig()
|
||||
{
|
||||
QString fileName = QFileDialog::getSaveFileName(this, tr("Save configuration as..."));
|
||||
QString fileName = QFileDialog::getSaveFileName(this, tr("Save server configuration as..."));
|
||||
|
||||
if (!fileName.isEmpty() && !m_serverConfig.save(fileName)) {
|
||||
QMessageBox::warning(this, tr("Save failed"), tr("Could not save configuration to file."));
|
||||
QMessageBox::warning(this, tr("Save failed"), tr("Could not save server configuration to file."));
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -495,10 +479,10 @@ void MainWindow::openGetNewVersionUrl() const
|
||||
|
||||
void MainWindow::openSettings()
|
||||
{
|
||||
auto dialog = SettingsDialog(this, m_appConfig, m_serverConfig, m_coreProcess);
|
||||
auto dialog = SettingsDialog(this, m_serverConfig, m_coreProcess);
|
||||
|
||||
if (dialog.exec() == QDialog::Accepted) {
|
||||
m_configScopes.save();
|
||||
Settings::save();
|
||||
|
||||
applyConfig();
|
||||
|
||||
@ -516,28 +500,26 @@ void MainWindow::resetCore()
|
||||
|
||||
void MainWindow::updateSize()
|
||||
{
|
||||
if (m_appConfig.logExpanded()) {
|
||||
setMaximumHeight(16777215);
|
||||
setMaximumWidth(16777215);
|
||||
if (Settings::value(Settings::Gui::LogExpanded).toBool()) {
|
||||
setMaximumSize(16777215, 16777215);
|
||||
resize(m_expandedSize);
|
||||
} else {
|
||||
adjustSize();
|
||||
// Prevent Resize with log collapsed
|
||||
setMaximumHeight(height());
|
||||
setMaximumWidth(width());
|
||||
setMaximumSize(width(), height());
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::showMyFingerprint()
|
||||
{
|
||||
if (!QFile::exists(localFingerprintDb())) {
|
||||
if (!QFile::exists(Settings::tlsLocalDb())) {
|
||||
if (regenerateLocalFingerprints())
|
||||
showMyFingerprint();
|
||||
return;
|
||||
}
|
||||
|
||||
deskflow::FingerprintDatabase db;
|
||||
db.read(localFingerprintDb().toStdString());
|
||||
db.read(Settings::tlsLocalDb().toStdString());
|
||||
if (db.fingerprints().size() != kTlsDbSize) {
|
||||
if (regenerateLocalFingerprints())
|
||||
showMyFingerprint();
|
||||
@ -559,10 +541,10 @@ void MainWindow::coreModeToggled()
|
||||
const auto mode = serverMode ? QStringLiteral("server enabled") : QStringLiteral("client enabled");
|
||||
qDebug() << mode;
|
||||
|
||||
m_appConfig.setServerGroupChecked(serverMode);
|
||||
m_appConfig.setClientGroupChecked(!serverMode);
|
||||
m_configScopes.save();
|
||||
const auto coreMode = serverMode ? Settings::CoreMode::Server : Settings::CoreMode::Client;
|
||||
Settings::setValue(Settings::Core::CoreMode, coreMode);
|
||||
|
||||
Settings::save();
|
||||
updateModeControls(serverMode);
|
||||
}
|
||||
|
||||
@ -573,7 +555,7 @@ void MainWindow::updateModeControls(bool serverMode)
|
||||
ui->lblNoMode->setVisible(false);
|
||||
ui->btnToggleCore->setEnabled(true);
|
||||
m_actionStartCore->setEnabled(true);
|
||||
auto expectedCoreMode = serverMode ? CoreProcess::Mode::Server : CoreProcess::Mode::Client;
|
||||
auto expectedCoreMode = serverMode ? Settings::CoreMode::Server : Settings::CoreMode::Client;
|
||||
if (m_coreProcess.isStarted() && m_coreProcess.mode() != expectedCoreMode)
|
||||
m_coreProcess.stop();
|
||||
m_coreProcess.setMode(expectedCoreMode);
|
||||
@ -581,7 +563,8 @@ void MainWindow::updateModeControls(bool serverMode)
|
||||
// The server can run without any clients configured, and this is actually
|
||||
// what you'll want to do the first time since you'll be prompted when an
|
||||
// unrecognized client tries to connect.
|
||||
if (!m_appConfig.startedBefore() && !m_coreProcess.isStarted()) {
|
||||
const auto startedBefore = Settings::value(Settings::Core::StartedBefore).toBool();
|
||||
if (!startedBefore && !m_coreProcess.isStarted()) {
|
||||
qDebug() << "auto-starting core server for first time";
|
||||
m_coreProcess.start();
|
||||
messages::showFirstServerStartMessage(this);
|
||||
@ -595,7 +578,7 @@ void MainWindow::updateSecurityIcon(bool visible)
|
||||
if (!visible)
|
||||
return;
|
||||
|
||||
bool secureSocket = m_appConfig.tlsEnabled();
|
||||
bool secureSocket = Settings::value(Settings::Security::TlsEnabled).toBool();
|
||||
|
||||
const auto txt =
|
||||
secureSocket ? tr("%1 Encryption Enabled").arg(m_coreProcess.secureSocketVersion()) : tr("Encryption Disabled");
|
||||
@ -607,12 +590,12 @@ void MainWindow::updateSecurityIcon(bool visible)
|
||||
|
||||
void MainWindow::serverConnectionConfigureClient(const QString &clientName)
|
||||
{
|
||||
m_serverConfigDialogState.setVisible(true);
|
||||
ServerConfigDialog dialog(this, m_serverConfig, m_appConfig);
|
||||
Settings::setValue(Settings::Server::ConfigVisible, true);
|
||||
ServerConfigDialog dialog(this, m_serverConfig);
|
||||
if (dialog.addClient(clientName) && dialog.exec() == QDialog::Accepted) {
|
||||
m_coreProcess.restart();
|
||||
}
|
||||
m_serverConfigDialogState.setVisible(false);
|
||||
Settings::setValue(Settings::Server::ConfigVisible, false);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
@ -621,13 +604,13 @@ void MainWindow::serverConnectionConfigureClient(const QString &clientName)
|
||||
|
||||
void MainWindow::open()
|
||||
{
|
||||
if (!m_appConfig.enableUpdateCheck().has_value()) {
|
||||
|
||||
if (!Settings::value(Settings::Gui::AutoUpdateCheck).isValid()) {
|
||||
showAndActivate();
|
||||
m_appConfig.setEnableUpdateCheck(messages::showUpdateCheckOption(this));
|
||||
m_configScopes.save();
|
||||
Settings::setValue(Settings::Gui::AutoUpdateCheck, messages::showUpdateCheckOption(this));
|
||||
}
|
||||
|
||||
if (m_appConfig.enableUpdateCheck().value()) {
|
||||
if (Settings::value(Settings::Gui::AutoUpdateCheck).toBool()) {
|
||||
m_versionChecker.checkLatest();
|
||||
} else {
|
||||
qDebug() << "update check disabled";
|
||||
@ -635,21 +618,17 @@ void MainWindow::open()
|
||||
|
||||
m_coreProcess.applyLogLevel();
|
||||
|
||||
if (m_appConfig.startedBefore()) {
|
||||
if (Settings::value(Settings::Core::StartedBefore).toBool()) {
|
||||
m_coreProcess.start();
|
||||
}
|
||||
|
||||
if (m_appConfig.autoHide()) {
|
||||
hide();
|
||||
} else {
|
||||
showAndActivate();
|
||||
}
|
||||
Settings::value(Settings::Gui::Autohide).toBool() ? hide() : showAndActivate();
|
||||
}
|
||||
|
||||
void MainWindow::coreProcessStarting()
|
||||
{
|
||||
if (deskflow::platform::isWayland()) {
|
||||
m_waylandWarnings.showOnce(this, m_coreProcess.mode());
|
||||
m_waylandWarnings.showOnce(this);
|
||||
}
|
||||
saveSettings();
|
||||
}
|
||||
@ -661,18 +640,16 @@ void MainWindow::setStatus(const QString &status)
|
||||
|
||||
void MainWindow::createMenuBar()
|
||||
{
|
||||
auto menuFile = new QMenu(tr("File"));
|
||||
auto menuFile = new QMenu(tr("File"), this);
|
||||
menuFile->addAction(m_actionStartCore);
|
||||
menuFile->addAction(m_actionStopCore);
|
||||
menuFile->addSeparator();
|
||||
menuFile->addAction(m_actionSave);
|
||||
menuFile->addSeparator();
|
||||
menuFile->addAction(m_actionQuit);
|
||||
|
||||
auto menuEdit = new QMenu(tr("Edit"));
|
||||
auto menuEdit = new QMenu(tr("Edit"), this);
|
||||
menuEdit->addAction(m_actionSettings);
|
||||
|
||||
auto menuHelp = new QMenu(tr("Help"));
|
||||
auto menuHelp = new QMenu(tr("Help"), this);
|
||||
menuHelp->addAction(m_actionAbout);
|
||||
menuHelp->addAction(m_actionReportBug);
|
||||
menuHelp->addSeparator();
|
||||
@ -683,14 +660,6 @@ void MainWindow::createMenuBar()
|
||||
menuBar->addMenu(menuEdit);
|
||||
menuBar->addMenu(menuHelp);
|
||||
|
||||
const auto enableTestMenu = strToTrue(qEnvironmentVariable("DESKFLOW_TEST_MENU"));
|
||||
if (enableTestMenu || kDebugBuild) {
|
||||
auto testMenu = new QMenu(tr("Test"));
|
||||
menuBar->addMenu(testMenu);
|
||||
testMenu->addAction(m_actionTestFatalError);
|
||||
testMenu->addAction(m_actionTestCriticalError);
|
||||
}
|
||||
|
||||
setMenuBar(menuBar);
|
||||
}
|
||||
|
||||
@ -708,22 +677,26 @@ void MainWindow::setupTrayIcon()
|
||||
|
||||
void MainWindow::applyConfig()
|
||||
{
|
||||
ui->lineHostname->setText(m_appConfig.serverHostname());
|
||||
ui->lineHostname->setText(Settings::value(Settings::Client::RemoteHost).toString());
|
||||
updateLocalFingerprint();
|
||||
setIcon();
|
||||
|
||||
if (!m_appConfig.serverGroupChecked() && !m_appConfig.clientGroupChecked())
|
||||
const auto coreMode = Settings::value(Settings::Core::CoreMode).value<Settings::CoreMode>();
|
||||
|
||||
if (coreMode == Settings::CoreMode::None)
|
||||
return;
|
||||
updateModeControls(m_appConfig.serverGroupChecked());
|
||||
updateModeControls(coreMode == Settings::CoreMode::Server);
|
||||
}
|
||||
|
||||
void MainWindow::saveSettings()
|
||||
{
|
||||
m_appConfig.setServerGroupChecked(ui->rbModeServer->isChecked());
|
||||
m_appConfig.setClientGroupChecked(ui->rbModeClient->isChecked());
|
||||
m_appConfig.setServerHostname(ui->lineHostname->text());
|
||||
|
||||
m_configScopes.save();
|
||||
if (ui->rbModeClient->isChecked()) {
|
||||
Settings::setValue(Settings::Core::CoreMode, Settings::CoreMode::Client);
|
||||
} else if (ui->rbModeServer->isChecked()) {
|
||||
Settings::setValue(Settings::Core::CoreMode, Settings::CoreMode::Server);
|
||||
}
|
||||
Settings::setValue(Settings::Client::RemoteHost, ui->lineHostname->text());
|
||||
Settings::save();
|
||||
}
|
||||
|
||||
void MainWindow::setIcon()
|
||||
@ -731,19 +704,19 @@ void MainWindow::setIcon()
|
||||
// Using a theme icon that is packed in exe renders an invisible icon
|
||||
// Instead use the resource path of the packed icon
|
||||
// TODO Report to Qt ref the bug here
|
||||
const bool symbolicIcon = Settings::value(Settings::Gui::SymbolicTrayIcon).toBool();
|
||||
#ifndef Q_OS_MAC
|
||||
QString iconString = QStringLiteral(":/icons/deskflow-%1/apps/64/deskflow").arg(iconMode());
|
||||
if (!appConfig().colorfulTrayIcon()) {
|
||||
if (symbolicIcon)
|
||||
iconString.append(QStringLiteral("-symbolic"));
|
||||
}
|
||||
m_trayIcon->setIcon(QIcon(iconString));
|
||||
#else
|
||||
if (m_appConfig.colorfulTrayIcon()) {
|
||||
m_trayIcon->setIcon(QIcon::fromTheme(QStringLiteral("deskflow")));
|
||||
} else {
|
||||
if (symbolicIcon) {
|
||||
auto icon = QIcon::fromTheme(QStringLiteral("deskflow-symbolic"));
|
||||
icon.setIsMask(true);
|
||||
m_trayIcon->setIcon(icon);
|
||||
} else {
|
||||
m_trayIcon->setIcon(QIcon::fromTheme(QStringLiteral("deskflow")));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@ -759,7 +732,7 @@ void MainWindow::handleLogLine(const QString &line)
|
||||
|
||||
// only trim end instead of the whole line to prevent tab-indented debug
|
||||
// filenames from losing their indentation.
|
||||
ui->textLog->appendPlainText(trimEnd(line));
|
||||
ui->textLog->appendPlainText(line.trimmed());
|
||||
|
||||
if (scrollAtBottom) {
|
||||
verticalScroll->setValue(verticalScroll->maximum());
|
||||
@ -856,10 +829,10 @@ void MainWindow::showEvent(QShowEvent *event)
|
||||
|
||||
void MainWindow::closeEvent(QCloseEvent *event)
|
||||
{
|
||||
if (m_appConfig.closeToTray() && event->spontaneous()) {
|
||||
if (m_appConfig.showCloseReminder()) {
|
||||
if (Settings::value(Settings::Gui::CloseToTray).toBool() && event->spontaneous()) {
|
||||
if (Settings::value(Settings::Gui::CloseReminder).toBool()) {
|
||||
messages::showCloseReminder(this);
|
||||
m_appConfig.setShowCloseReminder(false);
|
||||
Settings::setValue(Settings::Gui::CloseReminder, false);
|
||||
}
|
||||
qDebug() << "hiding to tray";
|
||||
hide();
|
||||
@ -868,9 +841,7 @@ void MainWindow::closeEvent(QCloseEvent *event)
|
||||
}
|
||||
|
||||
if (m_saveOnExit) {
|
||||
m_appConfig.setMainWindowPosition(pos());
|
||||
m_appConfig.setMainWindowSize(size());
|
||||
m_configScopes.save();
|
||||
Settings::setValue(Settings::Gui::WindowGeometry, frameGeometry());
|
||||
}
|
||||
qDebug() << "quitting application";
|
||||
event->accept();
|
||||
@ -879,15 +850,16 @@ void MainWindow::closeEvent(QCloseEvent *event)
|
||||
|
||||
void MainWindow::showFirstConnectedMessage()
|
||||
{
|
||||
if (m_appConfig.startedBefore()) {
|
||||
if (Settings::value(Settings::Core::StartedBefore).toBool())
|
||||
return;
|
||||
}
|
||||
|
||||
m_appConfig.setStartedBefore(true);
|
||||
m_configScopes.save();
|
||||
Settings::setValue(Settings::Core::StartedBefore, true);
|
||||
|
||||
const auto isServer = m_coreProcess.mode() == CoreMode::Server;
|
||||
messages::showFirstConnectedMessage(this, m_appConfig.closeToTray(), m_appConfig.enableService(), isServer);
|
||||
const auto closeToTray = Settings::value(Settings::Gui::CloseToTray).toBool();
|
||||
|
||||
using ProcessMode = Settings::ProcessMode;
|
||||
const auto enableService = Settings::value(Settings::Core::ProcessMode).value<ProcessMode>() == ProcessMode::Service;
|
||||
messages::showFirstConnectedMessage(this, closeToTray, enableService, isServer);
|
||||
}
|
||||
|
||||
void MainWindow::updateStatus()
|
||||
@ -952,8 +924,7 @@ void MainWindow::coreProcessStateChanged(CoreProcessState state)
|
||||
|
||||
if (state == CoreProcessState::Started) {
|
||||
qDebug() << "recording that core has started";
|
||||
m_appConfig.setStartedBefore(true);
|
||||
m_configScopes.save();
|
||||
Settings::setValue(Settings::Core::StartedBefore, true);
|
||||
}
|
||||
|
||||
if (state == CoreProcessState::Started || state == CoreProcessState::Starting ||
|
||||
@ -1031,7 +1002,8 @@ QString MainWindow::getIPAddresses() const
|
||||
|
||||
void MainWindow::updateLocalFingerprint()
|
||||
{
|
||||
m_btnFingerprint->setVisible(m_appConfig.tlsEnabled() && QFile::exists(localFingerprintDb()));
|
||||
const bool tlsEnabled = Settings::value(Settings::Security::TlsEnabled).toBool();
|
||||
m_btnFingerprint->setVisible(tlsEnabled && QFile::exists(Settings::tlsLocalDb()));
|
||||
}
|
||||
|
||||
void MainWindow::autoAddScreen(const QString name)
|
||||
@ -1041,13 +1013,15 @@ void MainWindow::autoAddScreen(const QString name)
|
||||
if (r != kAutoAddScreenOk) {
|
||||
switch (r) {
|
||||
case kAutoAddScreenManualServer:
|
||||
showConfigureServer(tr("Please add the server (%1) to the grid.").arg(m_appConfig.screenName()));
|
||||
showConfigureServer(
|
||||
tr("Please add the server (%1) to the grid.").arg(Settings::value(Settings::Core::ScreenName).toString())
|
||||
);
|
||||
break;
|
||||
|
||||
case kAutoAddScreenManualClient:
|
||||
showConfigureServer(tr("Please drag the new client screen (%1) "
|
||||
"to the desired position on the grid.")
|
||||
.arg(name));
|
||||
showConfigureServer(
|
||||
tr("Please add the server (%1) to the grid.").arg(Settings::value(Settings::Core::ScreenName).toString())
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -1066,7 +1040,7 @@ void MainWindow::hide()
|
||||
|
||||
void MainWindow::showConfigureServer(const QString &message)
|
||||
{
|
||||
ServerConfigDialog dialog(this, serverConfig(), m_appConfig);
|
||||
ServerConfigDialog dialog(this, serverConfig());
|
||||
dialog.message(message);
|
||||
if ((dialog.exec() == QDialog::Accepted) && m_coreProcess.isStarted()) {
|
||||
m_coreProcess.restart();
|
||||
@ -1081,8 +1055,9 @@ void MainWindow::secureSocket(bool secureSocket)
|
||||
|
||||
void MainWindow::updateScreenName()
|
||||
{
|
||||
ui->lblComputerName->setText(m_appConfig.screenName());
|
||||
ui->lineEditName->setText(m_appConfig.screenName());
|
||||
const auto screenName = Settings::value(Settings::Core::ScreenName).toString();
|
||||
ui->lblComputerName->setText(screenName);
|
||||
ui->lineEditName->setText(screenName);
|
||||
m_serverConfig.updateServerName();
|
||||
}
|
||||
|
||||
@ -1113,11 +1088,12 @@ void MainWindow::setHostName()
|
||||
ui->btnEditName->show();
|
||||
|
||||
QString text = ui->lineEditName->text();
|
||||
bool existingScreen = serverConfig().screenExists(text) && text != m_appConfig.screenName();
|
||||
const auto screenName = Settings::value(Settings::Core::ScreenName).toString();
|
||||
bool existingScreen = serverConfig().screenExists(text) && (text != screenName);
|
||||
|
||||
if (!ui->lineEditName->hasAcceptableInput() || text.isEmpty() || existingScreen) {
|
||||
blockSignals(true);
|
||||
ui->lineEditName->setText(m_appConfig.screenName());
|
||||
ui->lineEditName->setText(screenName);
|
||||
blockSignals(false);
|
||||
|
||||
const auto title = tr("Invalid Screen Name");
|
||||
@ -1125,47 +1101,37 @@ void MainWindow::setHostName()
|
||||
if (existingScreen) {
|
||||
body = tr("Screen name already exists");
|
||||
} else {
|
||||
body = tr("The name you have chosen is invalid.\n\n"
|
||||
"Valid names:\n"
|
||||
"• Use letters and numbers\n"
|
||||
"• May also use _ or -\n"
|
||||
"• Are between 1 and 255 characters");
|
||||
body =
|
||||
tr("The name you have chosen is invalid.\n\n"
|
||||
"Valid names:\n"
|
||||
"• Use letters and numbers\n"
|
||||
"• May also use _ or -\n"
|
||||
"• Are between 1 and 255 characters");
|
||||
}
|
||||
QMessageBox::information(this, title, body);
|
||||
return;
|
||||
}
|
||||
|
||||
ui->lblComputerName->setText(ui->lineEditName->text());
|
||||
m_appConfig.setScreenName(ui->lineEditName->text());
|
||||
Settings::setValue(Settings::Core::ScreenName, ui->lineEditName->text());
|
||||
applyConfig();
|
||||
}
|
||||
|
||||
QString MainWindow::getTlsPath()
|
||||
{
|
||||
CoreTool coreTool;
|
||||
return QStringLiteral("%1/%2").arg(coreTool.getProfileDir(), kSslDir);
|
||||
}
|
||||
|
||||
QString MainWindow::localFingerprintDb()
|
||||
{
|
||||
return QStringLiteral("%1/%2").arg(getTlsPath(), kFingerprintLocalFilename);
|
||||
}
|
||||
|
||||
QString MainWindow::trustedFingerprintDb()
|
||||
{
|
||||
const bool isClient = m_coreProcess.mode() == CoreMode::Client;
|
||||
const auto trustFile = isClient ? kFingerprintTrustedServersFilename : kFingerprintTrustedClientsFilename;
|
||||
return QStringLiteral("%1/%2").arg(getTlsPath(), trustFile);
|
||||
return isClient ? Settings::tlsTrustedServersDb() : Settings::tlsTrustedClientsDb();
|
||||
}
|
||||
|
||||
bool MainWindow::regenerateLocalFingerprints()
|
||||
{
|
||||
if (!QFile::exists(m_appConfig.tlsCertPath()) && !m_tlsUtility.generateCertificate()) {
|
||||
const auto certificate = Settings::value(Settings::Security::Certificate).toString();
|
||||
if (!QFile::exists(certificate) && !m_tlsUtility.generateCertificate()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
TlsCertificate tls;
|
||||
if (!tls.generateFingerprint(m_appConfig.tlsCertPath())) {
|
||||
if (!tls.generateFingerprint(certificate)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@ -18,9 +18,6 @@
|
||||
|
||||
#include "ServerConfig.h"
|
||||
#include "VersionChecker.h"
|
||||
#include "gui/config/AppConfig.h"
|
||||
#include "gui/config/ConfigScopes.h"
|
||||
#include "gui/config/ServerConfigDialogState.h"
|
||||
#include "gui/core/ClientConnection.h"
|
||||
#include "gui/core/CoreProcess.h"
|
||||
#include "gui/core/ServerConnection.h"
|
||||
@ -59,7 +56,7 @@ class DaemonIpcClient;
|
||||
|
||||
class MainWindow : public QMainWindow
|
||||
{
|
||||
using CoreMode = deskflow::gui::CoreProcess::Mode;
|
||||
using CoreMode = Settings::CoreMode;
|
||||
using CoreProcess = deskflow::gui::CoreProcess;
|
||||
|
||||
Q_OBJECT
|
||||
@ -75,7 +72,7 @@ public:
|
||||
};
|
||||
|
||||
public:
|
||||
explicit MainWindow(deskflow::gui::ConfigScopes &configScopes, AppConfig &appConfig);
|
||||
explicit MainWindow();
|
||||
~MainWindow() override;
|
||||
|
||||
CoreMode coreMode() const
|
||||
@ -100,8 +97,8 @@ private:
|
||||
|
||||
void firstShown();
|
||||
|
||||
void configScopesSaving();
|
||||
void appConfigTlsChanged();
|
||||
void settingsChanged(const QString &key = QString());
|
||||
void serverConfigSaving();
|
||||
void coreProcessStarting();
|
||||
void coreProcessError(CoreProcess::Error error);
|
||||
void coreConnectionStateChanged(CoreProcess::ConnectionState state);
|
||||
@ -117,9 +114,7 @@ private:
|
||||
void openSettings();
|
||||
void startCore();
|
||||
void stopCore();
|
||||
bool saveConfig();
|
||||
void testFatalError() const;
|
||||
void testCriticalError() const;
|
||||
bool saveServerConfig();
|
||||
void resetCore();
|
||||
|
||||
void showMyFingerprint();
|
||||
@ -131,14 +126,6 @@ private:
|
||||
std::unique_ptr<Ui::MainWindow> ui;
|
||||
|
||||
void updateSize();
|
||||
AppConfig &appConfig()
|
||||
{
|
||||
return m_appConfig;
|
||||
}
|
||||
AppConfig const &appConfig() const
|
||||
{
|
||||
return m_appConfig;
|
||||
}
|
||||
void createMenuBar();
|
||||
void setupTrayIcon();
|
||||
void applyConfig();
|
||||
@ -172,14 +159,6 @@ private:
|
||||
void showHostNameEditor();
|
||||
void setHostName();
|
||||
|
||||
QString getTlsPath();
|
||||
|
||||
/**
|
||||
* @brief localFingerprintDb
|
||||
* @return The path to the local fingerprint file
|
||||
*/
|
||||
QString localFingerprintDb();
|
||||
|
||||
/**
|
||||
* @brief trustedFingerprintDb get the fingerprintDb for the trusted clients or trusted servers.
|
||||
* @return The path to the trusted fingerprint file
|
||||
@ -195,11 +174,8 @@ private:
|
||||
|
||||
VersionChecker m_versionChecker;
|
||||
bool m_secureSocket = false;
|
||||
deskflow::gui::config::ServerConfigDialogState m_serverConfigDialogState;
|
||||
bool m_saveOnExit = true;
|
||||
deskflow::gui::core::WaylandWarnings m_waylandWarnings;
|
||||
deskflow::gui::ConfigScopes &m_configScopes;
|
||||
AppConfig &m_appConfig;
|
||||
ServerConfig m_serverConfig;
|
||||
deskflow::gui::CoreProcess m_coreProcess;
|
||||
deskflow::gui::ServerConnection m_serverConnection;
|
||||
@ -225,10 +201,7 @@ private:
|
||||
QAction *m_actionQuit = nullptr;
|
||||
QAction *m_actionTrayQuit = nullptr;
|
||||
QAction *m_actionRestore = nullptr;
|
||||
QAction *m_actionSave = nullptr;
|
||||
QAction *m_actionSettings = nullptr;
|
||||
QAction *m_actionStartCore = nullptr;
|
||||
QAction *m_actionStopCore = nullptr;
|
||||
QAction *m_actionTestCriticalError = nullptr;
|
||||
QAction *m_actionTestFatalError = nullptr;
|
||||
};
|
||||
|
||||
@ -6,8 +6,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>730</width>
|
||||
<height>520</height>
|
||||
<width>735</width>
|
||||
<height>515</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
@ -233,6 +233,25 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="btnSaveServerConfig">
|
||||
<property name="toolTip">
|
||||
<string>Export server configuration</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="QIcon::ThemeIcon::DocumentSaveAs"/>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>22</width>
|
||||
<height>22</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
@ -325,33 +344,6 @@
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="widgetModes" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_8">
|
||||
<property name="spacing">
|
||||
<number>20</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QFrame" name="frameLog">
|
||||
<property name="sizePolicy">
|
||||
|
||||
@ -1,18 +0,0 @@
|
||||
/*
|
||||
* Deskflow -- mouse and keyboard sharing utility
|
||||
* SPDX-FileCopyrightText: (C) 2015 - 2016 Symless Ltd.
|
||||
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
enum qProcessorArch
|
||||
{
|
||||
kProcessorArchWin32,
|
||||
kProcessorArchWin64,
|
||||
kProcessorArchMac32,
|
||||
kProcessorArchMac64,
|
||||
kProcessorArchLinux32,
|
||||
kProcessorArchLinux64,
|
||||
kProcessorArchUnknown
|
||||
};
|
||||
@ -1,65 +0,0 @@
|
||||
/*
|
||||
* Deskflow -- mouse and keyboard sharing utility
|
||||
* SPDX-FileCopyrightText: (C) 2013 - 2016 Symless Ltd.
|
||||
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
|
||||
*/
|
||||
|
||||
#include "QUtility.h"
|
||||
|
||||
#include "ProcessorArch.h"
|
||||
|
||||
#if defined(Q_OS_LINUX)
|
||||
#include <QFile>
|
||||
#include <QProcess>
|
||||
#endif
|
||||
|
||||
#if defined(Q_OS_WIN)
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <Windows.h>
|
||||
#endif
|
||||
|
||||
void setIndexFromItemData(QComboBox *comboBox, const QVariant &itemData)
|
||||
{
|
||||
for (int i = 0; i < comboBox->count(); ++i) {
|
||||
if (comboBox->itemData(i) == itemData) {
|
||||
comboBox->setCurrentIndex(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QString hash(const QString &string)
|
||||
{
|
||||
QByteArray data = string.toUtf8();
|
||||
QByteArray hash = QCryptographicHash::hash(data, QCryptographicHash::Md5);
|
||||
return hash.toHex();
|
||||
}
|
||||
|
||||
qProcessorArch getProcessorArch()
|
||||
{
|
||||
#if defined(Q_OS_WIN)
|
||||
SYSTEM_INFO systemInfo;
|
||||
GetNativeSystemInfo(&systemInfo);
|
||||
|
||||
switch (systemInfo.wProcessorArchitecture) {
|
||||
case PROCESSOR_ARCHITECTURE_INTEL:
|
||||
return kProcessorArchWin32;
|
||||
case PROCESSOR_ARCHITECTURE_IA64:
|
||||
return kProcessorArchWin64;
|
||||
case PROCESSOR_ARCHITECTURE_AMD64:
|
||||
return kProcessorArchWin64;
|
||||
default:
|
||||
return kProcessorArchUnknown;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(Q_OS_LINUX)
|
||||
#ifdef __i386__
|
||||
return kProcessorArchLinux32;
|
||||
#else
|
||||
return kProcessorArchLinux64;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
return kProcessorArchUnknown;
|
||||
}
|
||||
@ -1,18 +0,0 @@
|
||||
/*
|
||||
* Deskflow -- mouse and keyboard sharing utility
|
||||
* SPDX-FileCopyrightText: (C) 2013 - 2016 Symless Ltd.
|
||||
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ProcessorArch.h"
|
||||
|
||||
#include <QComboBox>
|
||||
#include <QCryptographicHash>
|
||||
#include <QNetworkInterface>
|
||||
#include <QVariant>
|
||||
|
||||
void setIndexFromItemData(QComboBox *comboBox, const QVariant &itemData);
|
||||
QString hash(const QString &string);
|
||||
qProcessorArch getProcessorArch();
|
||||
@ -10,13 +10,13 @@
|
||||
|
||||
#include "Hotkey.h"
|
||||
#include "MainWindow.h"
|
||||
#include "common/Settings.h"
|
||||
#include "dialogs/AddClientDialog.h"
|
||||
|
||||
#include <QAbstractButton>
|
||||
#include <QMessageBox>
|
||||
#include <QPushButton>
|
||||
|
||||
using namespace deskflow::gui::proxy;
|
||||
using enum ScreenConfig::Modifier;
|
||||
using enum ScreenConfig::SwitchCorner;
|
||||
using enum ScreenConfig::Fix;
|
||||
@ -36,9 +36,8 @@ static const struct
|
||||
|
||||
const int serverDefaultIndex = 7;
|
||||
|
||||
ServerConfig::ServerConfig(AppConfig &appConfig, MainWindow &mainWindow, int columns, int rows)
|
||||
: m_pAppConfig(&appConfig),
|
||||
m_pMainWindow(&mainWindow),
|
||||
ServerConfig::ServerConfig(MainWindow &mainWindow, int columns, int rows)
|
||||
: m_pMainWindow(&mainWindow),
|
||||
m_Screens(columns),
|
||||
m_Columns(columns),
|
||||
m_Rows(rows),
|
||||
@ -76,7 +75,6 @@ bool ServerConfig::operator==(const ServerConfig &sc) const
|
||||
m_SwitchCornerSize == sc.m_SwitchCornerSize && //
|
||||
m_SwitchCorners == sc.m_SwitchCorners && //
|
||||
m_Hotkeys == sc.m_Hotkeys && //
|
||||
m_pAppConfig == sc.m_pAppConfig && //
|
||||
m_EnableDragAndDrop == sc.m_EnableDragAndDrop && //
|
||||
m_DisableLockToScreen == sc.m_DisableLockToScreen && //
|
||||
m_ClipboardSharing == sc.m_ClipboardSharing && //
|
||||
@ -138,8 +136,9 @@ void ServerConfig::commit()
|
||||
settings().setArrayIndex(i);
|
||||
auto &screen = screens()[i];
|
||||
screen.saveSettings(settings());
|
||||
if (screen.isServer() && m_pAppConfig->screenName() != screen.name()) {
|
||||
m_pAppConfig->setScreenName(screen.name());
|
||||
auto screenName = Settings::value(Settings::Core::ScreenName).toString();
|
||||
if (screen.isServer() && screenName != screen.name()) {
|
||||
Settings::setValue(Settings::Core::ScreenName, screen.name());
|
||||
}
|
||||
}
|
||||
settings().endArray();
|
||||
@ -331,8 +330,8 @@ int ServerConfig::autoAddScreen(const QString name)
|
||||
{
|
||||
int serverIndex = -1;
|
||||
int targetIndex = -1;
|
||||
if (!findScreenName(m_pAppConfig->screenName(), serverIndex) &&
|
||||
!fixNoServer(m_pAppConfig->screenName(), serverIndex)) {
|
||||
const auto screenName = Settings::value(Settings::Core::ScreenName).toString();
|
||||
if (!findScreenName(screenName, serverIndex) && !fixNoServer(screenName, serverIndex)) {
|
||||
return kAutoAddScreenManualServer;
|
||||
}
|
||||
|
||||
@ -388,29 +387,29 @@ int ServerConfig::autoAddScreen(const QString name)
|
||||
return kAutoAddScreenOk;
|
||||
}
|
||||
|
||||
const QString &ServerConfig::getServerName() const
|
||||
const QString ServerConfig::getServerName() const
|
||||
{
|
||||
return m_pAppConfig->screenName();
|
||||
return Settings::value(Settings::Core::ScreenName).toString();
|
||||
}
|
||||
|
||||
void ServerConfig::updateServerName()
|
||||
{
|
||||
for (auto &screen : screens()) {
|
||||
if (screen.isServer()) {
|
||||
screen.setName(m_pAppConfig->screenName());
|
||||
screen.setName(Settings::value(Settings::Core::ScreenName).toString());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const QString &ServerConfig::configFile() const
|
||||
const QString ServerConfig::configFile() const
|
||||
{
|
||||
return m_pAppConfig->configFile();
|
||||
return Settings::value(Settings::Server::ExternalConfigFile).toString();
|
||||
}
|
||||
|
||||
bool ServerConfig::useExternalConfig() const
|
||||
{
|
||||
return m_pAppConfig->useExternalConfig();
|
||||
return Settings::value(Settings::Server::ExternalConfig).toBool();
|
||||
}
|
||||
|
||||
bool ServerConfig::isFull() const
|
||||
@ -444,11 +443,12 @@ bool ServerConfig::screenExists(const QString &screenName) const
|
||||
void ServerConfig::addClient(const QString &clientName)
|
||||
{
|
||||
int serverIndex = -1;
|
||||
const auto screenName = Settings::value(Settings::Core::ScreenName).toString();
|
||||
|
||||
if (findScreenName(m_pAppConfig->screenName(), serverIndex)) {
|
||||
if (findScreenName(screenName, serverIndex)) {
|
||||
m_Screens[serverIndex].markAsServer();
|
||||
} else {
|
||||
fixNoServer(m_pAppConfig->screenName(), serverIndex);
|
||||
fixNoServer(screenName, serverIndex);
|
||||
}
|
||||
|
||||
m_Screens.addScreenByPriority(Screen(clientName));
|
||||
@ -456,12 +456,12 @@ void ServerConfig::addClient(const QString &clientName)
|
||||
|
||||
void ServerConfig::setConfigFile(const QString &configFile)
|
||||
{
|
||||
m_pAppConfig->setConfigFile(configFile);
|
||||
Settings::setValue(Settings::Server::ExternalConfigFile, configFile);
|
||||
}
|
||||
|
||||
void ServerConfig::setUseExternalConfig(bool useExternalConfig)
|
||||
{
|
||||
m_pAppConfig->setUseExternalConfig(useExternalConfig);
|
||||
Settings::setValue(Settings::Server::ExternalConfig, useExternalConfig);
|
||||
}
|
||||
|
||||
bool ServerConfig::findScreenName(const QString &name, int &index)
|
||||
@ -538,5 +538,5 @@ size_t ServerConfig::setClipboardSharingSize(size_t size)
|
||||
|
||||
QSettingsProxy &ServerConfig::settings()
|
||||
{
|
||||
return m_pAppConfig->scopes().activeSettings();
|
||||
return Settings::proxy();
|
||||
}
|
||||
|
||||
@ -23,7 +23,6 @@ class QString;
|
||||
class QFile;
|
||||
class ServerConfigDialog;
|
||||
class MainWindow;
|
||||
class AppConfig;
|
||||
|
||||
namespace synergy::gui {
|
||||
|
||||
@ -40,14 +39,13 @@ const auto kDefaultProtocol = ServerProtocol::kBarrier;
|
||||
|
||||
class ServerConfig : public ScreenConfig, public deskflow::gui::IServerConfig
|
||||
{
|
||||
using QSettingsProxy = deskflow::gui::proxy::QSettingsProxy;
|
||||
using ServerProtocol = synergy::gui::ServerProtocol;
|
||||
|
||||
friend class ServerConfigDialog;
|
||||
friend QTextStream &operator<<(QTextStream &outStream, const ServerConfig &config);
|
||||
|
||||
public:
|
||||
ServerConfig(AppConfig &appConfig, MainWindow &mainWindow, int columns = kDefaultColumns, int rows = kDefaultRows);
|
||||
ServerConfig(MainWindow &mainWindow, int columns = kDefaultColumns, int rows = kDefaultRows);
|
||||
~ServerConfig() override = default;
|
||||
|
||||
bool operator==(const ServerConfig &sc) const;
|
||||
@ -155,9 +153,9 @@ public:
|
||||
void commit();
|
||||
int numScreens() const;
|
||||
int autoAddScreen(const QString name);
|
||||
const QString &getServerName() const;
|
||||
const QString getServerName() const;
|
||||
void updateServerName();
|
||||
const QString &configFile() const;
|
||||
const QString configFile() const;
|
||||
bool useExternalConfig() const;
|
||||
void addClient(const QString &clientName);
|
||||
QString getClientAddress() const;
|
||||
@ -278,7 +276,6 @@ private:
|
||||
QList<bool> m_SwitchCorners;
|
||||
HotkeyList m_Hotkeys;
|
||||
|
||||
AppConfig *m_pAppConfig;
|
||||
MainWindow *m_pMainWindow;
|
||||
ScreenList m_Screens;
|
||||
int m_Columns;
|
||||
|
||||
@ -6,8 +6,7 @@
|
||||
|
||||
#include "VersionChecker.h"
|
||||
|
||||
#include "common/constants.h"
|
||||
#include "gui/env_vars.h"
|
||||
#include "common/Settings.h"
|
||||
|
||||
#include <QLocale>
|
||||
#include <QNetworkAccessManager>
|
||||
@ -17,18 +16,14 @@
|
||||
#include <QRegularExpression>
|
||||
#include <memory>
|
||||
|
||||
using namespace deskflow::gui;
|
||||
|
||||
VersionChecker::VersionChecker(std::shared_ptr<QNetworkAccessManagerProxy> network)
|
||||
: m_network(network ? network : std::make_shared<QNetworkAccessManagerProxy>())
|
||||
VersionChecker::VersionChecker(QObject *parent) : QObject(parent), m_network{new QNetworkAccessManager(this)}
|
||||
{
|
||||
m_network->init();
|
||||
connect(m_network.get(), &QNetworkAccessManagerProxy::finished, this, &VersionChecker::replyFinished);
|
||||
connect(m_network, &QNetworkAccessManager::finished, this, &VersionChecker::replyFinished, Qt::UniqueConnection);
|
||||
}
|
||||
|
||||
void VersionChecker::checkLatest() const
|
||||
{
|
||||
const QString url = env_vars::versionUrl();
|
||||
const QString url = Settings::value(Settings::Core::UpdateUrl).toString();
|
||||
qDebug("checking for updates at: %s", qPrintable(url));
|
||||
auto request = QNetworkRequest(url);
|
||||
auto userAgent = QString("%1 %2 on %3").arg(kAppName, kVersion, QSysInfo::prettyProductName());
|
||||
@ -50,13 +45,20 @@ void VersionChecker::replyFinished(QNetworkReply *reply)
|
||||
qDebug("version check server success, http status: %d", httpStatus);
|
||||
|
||||
const auto newestVersion = QString(reply->readAll());
|
||||
reply->deleteLater();
|
||||
qDebug("version check response: %s", qPrintable(newestVersion));
|
||||
|
||||
if (!newestVersion.isEmpty() && compareVersions(kVersion, newestVersion) > 0) {
|
||||
qDebug("update found");
|
||||
if (newestVersion.isEmpty()) {
|
||||
qWarning() << "version check is response is empty";
|
||||
return;
|
||||
}
|
||||
|
||||
if (compareVersions(kVersion, newestVersion) > 0) {
|
||||
qWarning().noquote() //
|
||||
<< QStringLiteral("current version %1 out of date, update available: %2").arg(kVersion, newestVersion);
|
||||
Q_EMIT updateFound(newestVersion);
|
||||
} else {
|
||||
qDebug("no updates found");
|
||||
qDebug().noquote() << QStringLiteral("current version %1 is upto date").arg(kVersion);
|
||||
}
|
||||
}
|
||||
|
||||
@ -97,8 +99,11 @@ int VersionChecker::compareVersions(const QString &left, const QString &right)
|
||||
QStringList leftParts = left.split("-");
|
||||
QStringList rightParts = right.split("-");
|
||||
|
||||
QStringList leftNumberParts = left.split(".");
|
||||
QStringList rightNumberParts = right.split(".");
|
||||
QString leftNumber = leftParts.at(0);
|
||||
QString rightNumber = rightParts.at(0);
|
||||
|
||||
QStringList leftNumberParts = leftNumber.split(".");
|
||||
QStringList rightNumberParts = rightNumber.split(".");
|
||||
|
||||
auto leftStagePart = leftParts.size() > 1 ? leftParts.at(1) : "";
|
||||
auto rightStagePart = rightParts.size() > 1 ? rightParts.at(1) : "";
|
||||
|
||||
@ -6,26 +6,18 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "gui/proxy/QNetworkAccessManagerProxy.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <memory>
|
||||
|
||||
class QNetworkAccessManager;
|
||||
class QNetworkReply;
|
||||
class VersionCheckerTests;
|
||||
|
||||
class VersionChecker : public QObject
|
||||
{
|
||||
using QNetworkAccessManagerProxy = deskflow::gui::proxy::QNetworkAccessManagerProxy;
|
||||
|
||||
Q_OBJECT
|
||||
|
||||
friend class VersionCheckerTests;
|
||||
|
||||
public:
|
||||
explicit VersionChecker(std::shared_ptr<QNetworkAccessManagerProxy> network = nullptr);
|
||||
explicit VersionChecker(QObject *parent = nullptr);
|
||||
void checkLatest() const;
|
||||
public slots:
|
||||
void replyFinished(QNetworkReply *reply);
|
||||
@ -42,6 +34,5 @@ private:
|
||||
* more recent the version
|
||||
*/
|
||||
static int getStageVersion(QString stage);
|
||||
|
||||
std::shared_ptr<QNetworkAccessManagerProxy> m_network;
|
||||
QNetworkAccessManager *m_network = nullptr;
|
||||
};
|
||||
|
||||
@ -9,7 +9,7 @@
|
||||
#include "AboutDialog.h"
|
||||
#include "ui_AboutDialog.h"
|
||||
|
||||
#include "common/constants.h"
|
||||
#include "common/Constants.h"
|
||||
|
||||
#include <QClipboard>
|
||||
#include <QDateTime>
|
||||
|
||||
@ -149,7 +149,7 @@
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Computers to recieve this event</string>
|
||||
<string>Computers to receive this event</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="_3">
|
||||
<item>
|
||||
|
||||
@ -45,8 +45,9 @@ FingerprintDialog::FingerprintDialog(
|
||||
connect(m_buttonBox->button(QDialogButtonBox::Ok), &QPushButton::clicked, this, &QDialog::accept);
|
||||
} else {
|
||||
setWindowTitle(tr("Security Question"));
|
||||
auto body = tr("Compare the fingerprints in this dialog to those on the %1.\n"
|
||||
"Only connect if they match!");
|
||||
auto body =
|
||||
tr("Compare the fingerprints in this dialog to those on the %1.\n"
|
||||
"Only connect if they match!");
|
||||
|
||||
if (mode == FingerprintDialogMode::Server) {
|
||||
m_lblHeader->setText(tr("A new client is connecting.\n%1").arg(body.arg(tr("client"))));
|
||||
|
||||
@ -8,11 +8,11 @@
|
||||
#include "ScreenSettingsDialog.h"
|
||||
#include "ui_ScreenSettingsDialog.h"
|
||||
|
||||
#include "gui/Styles.h"
|
||||
#include "gui/config/Screen.h"
|
||||
#include "gui/styles.h"
|
||||
#include "gui/validators/AliasValidator.h"
|
||||
#include "gui/validators/ScreenNameValidator.h"
|
||||
#include "gui/validators/ValidationError.h"
|
||||
#include "validators/AliasValidator.h"
|
||||
#include "validators/ScreenNameValidator.h"
|
||||
#include "validators/ValidationError.h"
|
||||
|
||||
#include <QMessageBox>
|
||||
|
||||
|
||||
@ -9,7 +9,7 @@
|
||||
#include "ServerConfigDialog.h"
|
||||
#include "ui_ServerConfigDialog.h"
|
||||
|
||||
#include "common/constants.h"
|
||||
#include "common/Constants.h"
|
||||
#include "dialogs/ActionDialog.h"
|
||||
#include "dialogs/HotkeyDialog.h"
|
||||
#include "dialogs/ScreenSettingsDialog.h"
|
||||
@ -22,7 +22,7 @@
|
||||
using enum ScreenConfig::SwitchCorner;
|
||||
using ServerProtocol = synergy::gui::ServerProtocol;
|
||||
|
||||
ServerConfigDialog::ServerConfigDialog(QWidget *parent, ServerConfig &config, AppConfig &appConfig)
|
||||
ServerConfigDialog::ServerConfigDialog(QWidget *parent, ServerConfig &config)
|
||||
: QDialog(parent, Qt::WindowTitleHint | Qt::WindowSystemMenuHint),
|
||||
ui{std::make_unique<Ui::ServerConfigDialog>()},
|
||||
m_OriginalServerConfig(config),
|
||||
@ -30,8 +30,7 @@ ServerConfigDialog::ServerConfigDialog(QWidget *parent, ServerConfig &config, Ap
|
||||
m_OriginalServerConfigUsesExternalFile(config.configFile()),
|
||||
m_ServerConfig(config),
|
||||
m_ScreenSetupModel(serverConfig().screens(), serverConfig().numColumns(), serverConfig().numRows()),
|
||||
m_Message(""),
|
||||
m_appConfig(appConfig)
|
||||
m_Message("")
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
|
||||
@ -10,7 +10,6 @@
|
||||
|
||||
#include "ScreenSetupModel.h"
|
||||
#include "ServerConfig.h"
|
||||
#include "gui/config/AppConfig.h"
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
@ -25,7 +24,7 @@ class ServerConfigDialog : public QDialog
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ServerConfigDialog(QWidget *parent, ServerConfig &config, AppConfig &appConfig);
|
||||
ServerConfigDialog(QWidget *parent, ServerConfig &config);
|
||||
~ServerConfigDialog();
|
||||
bool addClient(const QString &clientName);
|
||||
|
||||
@ -93,10 +92,6 @@ protected:
|
||||
{
|
||||
return m_ScreenSetupModel;
|
||||
}
|
||||
AppConfig &appConfig()
|
||||
{
|
||||
return m_appConfig;
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<Ui::ServerConfigDialog> ui;
|
||||
@ -106,7 +101,6 @@ private:
|
||||
QString m_OriginalServerConfigUsesExternalFile;
|
||||
ScreenSetupModel m_ScreenSetupModel;
|
||||
QString m_Message;
|
||||
AppConfig &m_appConfig;
|
||||
|
||||
private slots:
|
||||
void onChange();
|
||||
|
||||
@ -9,8 +9,9 @@
|
||||
#include "SettingsDialog.h"
|
||||
#include "ui_SettingsDialog.h"
|
||||
|
||||
#include "common/Settings.h"
|
||||
#include "gui/Messages.h"
|
||||
#include "gui/core/CoreProcess.h"
|
||||
#include "gui/messages.h"
|
||||
#include "gui/tls/TlsCertificate.h"
|
||||
#include "gui/tls/TlsUtility.h"
|
||||
|
||||
@ -20,15 +21,12 @@
|
||||
|
||||
using namespace deskflow::gui;
|
||||
|
||||
SettingsDialog::SettingsDialog(
|
||||
QWidget *parent, AppConfig &appConfig, const IServerConfig &serverConfig, const CoreProcess &coreProcess
|
||||
)
|
||||
SettingsDialog::SettingsDialog(QWidget *parent, const IServerConfig &serverConfig, const CoreProcess &coreProcess)
|
||||
: QDialog(parent),
|
||||
ui{std::make_unique<Ui::SettingsDialog>()},
|
||||
m_appConfig(appConfig),
|
||||
m_serverConfig(serverConfig),
|
||||
m_coreProcess(coreProcess),
|
||||
m_tlsUtility(appConfig)
|
||||
m_tlsUtility(this)
|
||||
{
|
||||
|
||||
ui->setupUi(this);
|
||||
@ -36,6 +34,7 @@ SettingsDialog::SettingsDialog(
|
||||
ui->comboTlsKeyLength->setItemIcon(0, QIcon::fromTheme(QIcon::ThemeIcon::SecurityLow));
|
||||
ui->comboTlsKeyLength->setItemIcon(1, QIcon::fromTheme(QStringLiteral("security-medium")));
|
||||
ui->comboTlsKeyLength->setItemIcon(2, QIcon::fromTheme(QIcon::ThemeIcon::SecurityHigh));
|
||||
ui->lblTlsCertInfo->setFixedSize(28, 28);
|
||||
|
||||
ui->rbIconMono->setIcon(QIcon::fromTheme(QStringLiteral("deskflow-symbolic")));
|
||||
ui->rbIconColorful->setIcon(QIcon::fromTheme(QStringLiteral("deskflow")));
|
||||
@ -45,7 +44,6 @@ SettingsDialog::SettingsDialog(
|
||||
ui->tabWidget->setCurrentIndex(0);
|
||||
|
||||
loadFromConfig();
|
||||
m_wasOriginallySystemScope = m_appConfig.isActiveScopeSystem();
|
||||
updateControls();
|
||||
|
||||
adjustSize();
|
||||
@ -59,25 +57,26 @@ SettingsDialog::SettingsDialog(
|
||||
void SettingsDialog::initConnections()
|
||||
{
|
||||
connect(this, &SettingsDialog::shown, this, &SettingsDialog::showReadOnlyMessage, Qt::QueuedConnection);
|
||||
connect(Settings::instance(), &Settings::writableChanged, this, &SettingsDialog::showReadOnlyMessage);
|
||||
|
||||
connect(ui->buttonBox, &QDialogButtonBox::accepted, this, &SettingsDialog::accept);
|
||||
connect(ui->buttonBox, &QDialogButtonBox::rejected, this, &SettingsDialog::reject);
|
||||
connect(ui->buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
|
||||
|
||||
connect(ui->groupSecurity, &QGroupBox::toggled, this, &SettingsDialog::updateTlsControlsEnabled);
|
||||
connect(ui->cbServiceEnabled, &QCheckBox::toggled, this, &SettingsDialog::updateControls);
|
||||
connect(ui->btnTlsRegenCert, &QPushButton::clicked, this, &SettingsDialog::regenCertificates);
|
||||
connect(ui->comboTlsKeyLength, &QComboBox::currentIndexChanged, this, &SettingsDialog::updateRequestedKeySize);
|
||||
connect(ui->btnTlsCertPath, &QPushButton::clicked, this, &SettingsDialog::browseCertificatePath);
|
||||
connect(ui->btnBrowseLog, &QPushButton::clicked, this, &SettingsDialog::browseLogPath);
|
||||
connect(ui->cbLogToFile, &QCheckBox::toggled, this, &SettingsDialog::setLogToFile);
|
||||
|
||||
// We only need to test the System scoped Radio as they are connected
|
||||
connect(ui->rbScopeSystem, &QRadioButton::toggled, this, &SettingsDialog::setSystemScope);
|
||||
}
|
||||
|
||||
void SettingsDialog::regenCertificates()
|
||||
{
|
||||
if (m_tlsUtility.generateCertificate()) {
|
||||
QMessageBox::information(this, tr("TLS Certificate Regenerated"), tr("TLS certificate regenerated successfully."));
|
||||
const auto certificate = Settings::value(Settings::Security::Certificate).toString();
|
||||
updateKeyLengthOnFile(certificate);
|
||||
}
|
||||
}
|
||||
|
||||
@ -114,17 +113,6 @@ void SettingsDialog::setLogToFile(bool logToFile)
|
||||
ui->widgetLogFilename->setEnabled(logToFile);
|
||||
}
|
||||
|
||||
void SettingsDialog::setSystemScope(bool systemScope)
|
||||
{
|
||||
m_appConfig.setLoadFromSystemScope(systemScope);
|
||||
loadFromConfig();
|
||||
updateControls();
|
||||
|
||||
if (isVisible() && !m_appConfig.isActiveScopeWritable()) {
|
||||
showReadOnlyMessage();
|
||||
}
|
||||
}
|
||||
|
||||
void SettingsDialog::showEvent(QShowEvent *event)
|
||||
{
|
||||
QDialog::showEvent(event);
|
||||
@ -133,79 +121,63 @@ void SettingsDialog::showEvent(QShowEvent *event)
|
||||
|
||||
void SettingsDialog::showReadOnlyMessage()
|
||||
{
|
||||
if (m_appConfig.isActiveScopeWritable())
|
||||
if (Settings::isWritable())
|
||||
return;
|
||||
const auto activeScopeFilename = m_appConfig.scopes().activeFilePath();
|
||||
messages::showReadOnlySettings(this, activeScopeFilename);
|
||||
messages::showReadOnlySettings(this, Settings::settingsFile());
|
||||
}
|
||||
|
||||
void SettingsDialog::accept()
|
||||
{
|
||||
m_appConfig.setLoadFromSystemScope(ui->rbScopeSystem->isChecked());
|
||||
m_appConfig.setPort(ui->sbPort->value());
|
||||
m_appConfig.setNetworkInterface(ui->lineInterface->text());
|
||||
m_appConfig.setLogLevel(ui->comboLogLevel->currentIndex());
|
||||
m_appConfig.setLogToFile(ui->cbLogToFile->isChecked());
|
||||
m_appConfig.setLogFilename(ui->lineLogFilename->text());
|
||||
m_appConfig.setElevateMode(static_cast<ElevateMode>(ui->comboElevate->currentIndex()));
|
||||
m_appConfig.setAutoHide(ui->cbAutoHide->isChecked());
|
||||
m_appConfig.setEnableUpdateCheck(ui->cbAutoUpdate->isChecked());
|
||||
m_appConfig.setPreventSleep(ui->cbPreventSleep->isChecked());
|
||||
m_appConfig.setTlsCertPath(ui->lineTlsCertPath->text());
|
||||
m_appConfig.setTlsKeyLength(ui->comboTlsKeyLength->currentText().toInt());
|
||||
m_appConfig.setTlsEnabled(ui->groupSecurity->isChecked());
|
||||
m_appConfig.setLanguageSync(ui->cbLanguageSync->isChecked());
|
||||
m_appConfig.setInvertScrollDirection(ui->cbScrollDirection->isChecked());
|
||||
m_appConfig.setEnableService(ui->cbServiceEnabled->isChecked());
|
||||
m_appConfig.setCloseToTray(ui->cbCloseToTray->isChecked());
|
||||
m_appConfig.setColorfulTrayIcon(ui->rbIconColorful->isChecked());
|
||||
m_appConfig.setRequireClientCerts(ui->cbRequireClientCert->isChecked());
|
||||
Settings::setValue(Settings::Core::Port, ui->sbPort->value());
|
||||
Settings::setValue(Settings::Core::Interface, ui->lineInterface->text());
|
||||
Settings::setValue(Settings::Log::Level, ui->comboLogLevel->currentIndex());
|
||||
Settings::setValue(Settings::Log::ToFile, ui->cbLogToFile->isChecked());
|
||||
Settings::setValue(Settings::Log::File, ui->lineLogFilename->text());
|
||||
Settings::setValue(Settings::Core::ElevateMode, ui->comboElevate->currentIndex());
|
||||
Settings::setValue(Settings::Gui::Autohide, ui->cbAutoHide->isChecked());
|
||||
Settings::setValue(Settings::Gui::AutoUpdateCheck, ui->cbAutoUpdate->isChecked());
|
||||
Settings::setValue(Settings::Core::PreventSleep, ui->cbPreventSleep->isChecked());
|
||||
Settings::setValue(Settings::Security::Certificate, ui->lineTlsCertPath->text());
|
||||
Settings::setValue(Settings::Security::KeySize, ui->comboTlsKeyLength->currentText().toInt());
|
||||
Settings::setValue(Settings::Security::TlsEnabled, ui->groupSecurity->isChecked());
|
||||
Settings::setValue(Settings::Client::LanguageSync, ui->cbLanguageSync->isChecked());
|
||||
Settings::setValue(Settings::Client::InvertScrollDirection, ui->cbScrollDirection->isChecked());
|
||||
Settings::setValue(Settings::Gui::CloseToTray, ui->cbCloseToTray->isChecked());
|
||||
Settings::setValue(Settings::Gui::SymbolicTrayIcon, ui->rbIconMono->isChecked());
|
||||
Settings::setValue(Settings::Security::CheckPeers, ui->cbRequireClientCert->isChecked());
|
||||
|
||||
Settings::ProcessMode mode;
|
||||
if (ui->cbServiceEnabled->isChecked())
|
||||
mode = Settings::ProcessMode::Service;
|
||||
else
|
||||
mode = Settings::ProcessMode::Desktop;
|
||||
Settings::setValue(Settings::Core::ProcessMode, mode);
|
||||
|
||||
QDialog::accept();
|
||||
}
|
||||
|
||||
void SettingsDialog::reject()
|
||||
{
|
||||
// restore original system scope value on reject.
|
||||
if (m_appConfig.isActiveScopeSystem() != m_wasOriginallySystemScope) {
|
||||
m_appConfig.setLoadFromSystemScope(m_wasOriginallySystemScope);
|
||||
}
|
||||
|
||||
QDialog::reject();
|
||||
}
|
||||
|
||||
void SettingsDialog::loadFromConfig()
|
||||
{
|
||||
ui->sbPort->setValue(Settings::value(Settings::Core::Port).toInt());
|
||||
ui->lineInterface->setText(Settings::value(Settings::Core::Interface).toString());
|
||||
ui->comboLogLevel->setCurrentIndex(Settings::value(Settings::Log::Level).toInt());
|
||||
ui->cbLogToFile->setChecked(Settings::value(Settings::Log::ToFile).toBool());
|
||||
ui->lineLogFilename->setText(Settings::value(Settings::Log::File).toString());
|
||||
ui->cbAutoHide->setChecked(Settings::value(Settings::Gui::Autohide).toBool());
|
||||
ui->cbPreventSleep->setChecked(Settings::value(Settings::Core::PreventSleep).toBool());
|
||||
ui->cbLanguageSync->setChecked(Settings::value(Settings::Client::LanguageSync).toBool());
|
||||
ui->cbScrollDirection->setChecked(Settings::value(Settings::Client::InvertScrollDirection).toBool());
|
||||
ui->cbCloseToTray->setChecked(Settings::value(Settings::Gui::CloseToTray).toBool());
|
||||
ui->comboElevate->setCurrentIndex(Settings::value(Settings::Core::ElevateMode).toInt());
|
||||
ui->cbAutoUpdate->setChecked(Settings::value(Settings::Gui::Autohide).toBool());
|
||||
|
||||
ui->sbPort->setValue(m_appConfig.port());
|
||||
ui->lineInterface->setText(m_appConfig.networkInterface());
|
||||
ui->comboLogLevel->setCurrentIndex(m_appConfig.logLevel());
|
||||
ui->cbLogToFile->setChecked(m_appConfig.logToFile());
|
||||
ui->lineLogFilename->setText(m_appConfig.logFilename());
|
||||
ui->cbAutoHide->setChecked(m_appConfig.autoHide());
|
||||
ui->cbPreventSleep->setChecked(m_appConfig.preventSleep());
|
||||
ui->cbLanguageSync->setChecked(m_appConfig.languageSync());
|
||||
ui->cbScrollDirection->setChecked(m_appConfig.invertScrollDirection());
|
||||
ui->cbServiceEnabled->setChecked(m_appConfig.enableService());
|
||||
ui->cbCloseToTray->setChecked(m_appConfig.closeToTray());
|
||||
ui->comboElevate->setCurrentIndex(static_cast<int>(m_appConfig.elevateMode()));
|
||||
const auto processMode = Settings::value(Settings::Core::ProcessMode).value<Settings::ProcessMode>();
|
||||
ui->cbServiceEnabled->setChecked(processMode == Settings::ProcessMode::Service);
|
||||
|
||||
if (m_appConfig.enableUpdateCheck().has_value()) {
|
||||
ui->cbAutoUpdate->setChecked(m_appConfig.enableUpdateCheck().value());
|
||||
} else {
|
||||
ui->cbAutoUpdate->setChecked(false);
|
||||
}
|
||||
|
||||
if (m_appConfig.isActiveScopeSystem()) {
|
||||
ui->rbScopeSystem->setChecked(true);
|
||||
} else {
|
||||
ui->rbScopeUser->setChecked(true);
|
||||
}
|
||||
|
||||
if (m_appConfig.colorfulTrayIcon())
|
||||
ui->rbIconColorful->setChecked(true);
|
||||
else
|
||||
if (Settings::value(Settings::Gui::SymbolicTrayIcon).toBool())
|
||||
ui->rbIconMono->setChecked(true);
|
||||
else
|
||||
ui->rbIconColorful->setChecked(true);
|
||||
|
||||
qDebug() << "load from config done";
|
||||
updateTlsControls();
|
||||
@ -213,20 +185,19 @@ void SettingsDialog::loadFromConfig()
|
||||
|
||||
void SettingsDialog::updateTlsControls()
|
||||
{
|
||||
|
||||
if (QFile(m_appConfig.tlsCertPath()).exists()) {
|
||||
updateKeyLengthOnFile(m_appConfig.tlsCertPath());
|
||||
} else {
|
||||
const auto keyLengthText = QString::number(m_appConfig.tlsKeyLength());
|
||||
ui->comboTlsKeyLength->setCurrentIndex(ui->comboTlsKeyLength->findText(keyLengthText));
|
||||
const auto certificate = Settings::value(Settings::Security::Certificate).toString();
|
||||
if (QFile(certificate).exists()) {
|
||||
updateKeyLengthOnFile(certificate);
|
||||
}
|
||||
|
||||
const auto tlsEnabled = m_tlsUtility.isEnabled();
|
||||
const auto writable = m_appConfig.isActiveScopeWritable();
|
||||
ui->comboTlsKeyLength->setCurrentText(Settings::value(Settings::Security::KeySize).toString());
|
||||
|
||||
const auto tlsEnabled = Settings::value(Settings::Security::TlsEnabled).toBool();
|
||||
const auto writable = Settings::isWritable();
|
||||
const auto enabled = writable && tlsEnabled;
|
||||
|
||||
ui->lineTlsCertPath->setText(m_appConfig.tlsCertPath());
|
||||
ui->cbRequireClientCert->setChecked(m_appConfig.requireClientCerts());
|
||||
ui->lineTlsCertPath->setText(certificate);
|
||||
ui->cbRequireClientCert->setChecked(Settings::value(Settings::Security::CheckPeers).toBool());
|
||||
ui->groupSecurity->setChecked(tlsEnabled);
|
||||
|
||||
ui->groupSecurity->setEnabled(writable);
|
||||
@ -239,8 +210,9 @@ void SettingsDialog::updateTlsControls()
|
||||
|
||||
void SettingsDialog::updateTlsControlsEnabled()
|
||||
{
|
||||
const auto writable = m_appConfig.isActiveScopeWritable();
|
||||
const auto clientMode = m_appConfig.clientGroupChecked();
|
||||
const auto writable = Settings::isWritable();
|
||||
const auto clientMode =
|
||||
Settings::value(Settings::Core::CoreMode).value<Settings::CoreMode>() == Settings::CoreMode::Client;
|
||||
const auto tlsChecked = ui->groupSecurity->isChecked();
|
||||
|
||||
auto enabled = writable && tlsChecked && !clientMode;
|
||||
@ -254,7 +226,7 @@ void SettingsDialog::updateTlsControlsEnabled()
|
||||
|
||||
bool SettingsDialog::isClientMode() const
|
||||
{
|
||||
return m_coreProcess.mode() == deskflow::gui::CoreProcess::Mode::Client;
|
||||
return m_coreProcess.mode() == Settings::CoreMode::Client;
|
||||
}
|
||||
|
||||
void SettingsDialog::updateKeyLengthOnFile(const QString &path)
|
||||
@ -265,9 +237,14 @@ void SettingsDialog::updateKeyLengthOnFile(const QString &path)
|
||||
}
|
||||
|
||||
auto length = ssl.getCertKeyLength(path);
|
||||
auto index = ui->comboTlsKeyLength->findText(QString::number(length));
|
||||
ui->comboTlsKeyLength->setCurrentIndex(index);
|
||||
m_appConfig.setTlsKeyLength(length);
|
||||
QPixmap labelIcon = QPixmap(QIcon::fromTheme(QIcon::ThemeIcon::SecurityLow).pixmap(24, 24));
|
||||
if (length == 2048)
|
||||
labelIcon = QPixmap(QIcon::fromTheme(QStringLiteral("security-medium")).pixmap(24, 24));
|
||||
if (length == 4096)
|
||||
labelIcon = QPixmap(QIcon::fromTheme(QIcon::ThemeIcon::SecurityHigh).pixmap(24, 24));
|
||||
|
||||
ui->lblTlsCertInfo->setPixmap(labelIcon);
|
||||
ui->lblTlsCertInfo->setToolTip(QStringLiteral("Key length: %1 bits").arg(QString::number(length)));
|
||||
}
|
||||
|
||||
void SettingsDialog::updateControls()
|
||||
@ -281,7 +258,7 @@ void SettingsDialog::updateControls()
|
||||
ui->groupService->setTitle("Service (Windows only)");
|
||||
#endif
|
||||
|
||||
const bool writable = m_appConfig.isActiveScopeWritable();
|
||||
const bool writable = Settings::isWritable();
|
||||
const bool serviceChecked = ui->cbServiceEnabled->isChecked();
|
||||
const bool logToFile = ui->cbLogToFile->isChecked();
|
||||
|
||||
@ -307,4 +284,11 @@ void SettingsDialog::updateControls()
|
||||
updateTlsControls();
|
||||
}
|
||||
|
||||
void SettingsDialog::updateRequestedKeySize()
|
||||
{
|
||||
if (ui->comboTlsKeyLength->currentText() == Settings::value(Settings::Security::KeySize).toString())
|
||||
return;
|
||||
Settings::setValue(Settings::Security::KeySize, ui->comboTlsKeyLength->currentText());
|
||||
}
|
||||
|
||||
SettingsDialog::~SettingsDialog() = default;
|
||||
|
||||
@ -9,11 +9,10 @@
|
||||
#pragma once
|
||||
#include <QDialog>
|
||||
|
||||
#include "gui/config/AppConfig.h"
|
||||
#include "gui/config/IServerConfig.h"
|
||||
#include "gui/core/CoreProcess.h"
|
||||
#include "gui/tls/TlsUtility.h"
|
||||
#include "gui/validators/ValidationError.h"
|
||||
#include "validators/ValidationError.h"
|
||||
|
||||
namespace Ui {
|
||||
class SettingsDialog;
|
||||
@ -28,9 +27,7 @@ class SettingsDialog : public QDialog
|
||||
|
||||
public:
|
||||
void extracted();
|
||||
SettingsDialog(
|
||||
QWidget *parent, AppConfig &appConfig, const IServerConfig &serverConfig, const CoreProcess &coreProcess
|
||||
);
|
||||
SettingsDialog(QWidget *parent, const IServerConfig &serverConfig, const CoreProcess &coreProcess);
|
||||
~SettingsDialog() override;
|
||||
|
||||
signals:
|
||||
@ -42,9 +39,7 @@ private:
|
||||
void browseCertificatePath();
|
||||
void browseLogPath();
|
||||
void setLogToFile(bool logToFile);
|
||||
void setSystemScope(bool systemScope);
|
||||
void accept() override;
|
||||
void reject() override;
|
||||
void showEvent(QShowEvent *event) override;
|
||||
bool isClientMode() const;
|
||||
void updateTlsControls();
|
||||
@ -54,22 +49,16 @@ private:
|
||||
/// @brief Load all settings.
|
||||
void loadFromConfig();
|
||||
|
||||
/// @brief Enables or disables the TLS regenerate button.
|
||||
void updateTlsRegenerateButton();
|
||||
|
||||
/// @brief Updates the key length value based on the loaded file.
|
||||
void updateKeyLengthOnFile(const QString &path);
|
||||
|
||||
/// @brief Enables controls when they should be.
|
||||
void updateControls();
|
||||
|
||||
/// @brief Stores settings scope at start of settings dialog
|
||||
/// This is necessary to restore state if user changes
|
||||
/// the scope and doesn't save changes
|
||||
bool m_wasOriginallySystemScope = false;
|
||||
/// @brief updates the setting vaule for key size.
|
||||
void updateRequestedKeySize();
|
||||
|
||||
std::unique_ptr<Ui::SettingsDialog> ui;
|
||||
AppConfig &m_appConfig;
|
||||
const IServerConfig &m_serverConfig;
|
||||
const CoreProcess &m_coreProcess;
|
||||
deskflow::gui::TlsUtility m_tlsUtility;
|
||||
|
||||
@ -163,6 +163,13 @@
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="lblTlsCertInfo">
|
||||
<property name="text">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="lblTlsCert">
|
||||
<property name="sizePolicy">
|
||||
@ -176,22 +183,6 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Policy::Minimum</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="lineTlsCertPath">
|
||||
<property name="minimumSize">
|
||||
@ -656,38 +647,6 @@
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupScope">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Use settings profile from</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="_5">
|
||||
<item>
|
||||
<widget class="QRadioButton" name="rbScopeUser">
|
||||
<property name="text">
|
||||
<string>Current user</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="rbScopeSystem">
|
||||
<property name="text">
|
||||
<string>All users</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
@ -728,8 +687,6 @@
|
||||
<tabstop>btnBrowseLog</tabstop>
|
||||
<tabstop>cbServiceEnabled</tabstop>
|
||||
<tabstop>comboElevate</tabstop>
|
||||
<tabstop>rbScopeUser</tabstop>
|
||||
<tabstop>rbScopeSystem</tabstop>
|
||||
</tabstops>
|
||||
<resources/>
|
||||
<connections/>
|
||||
|
||||
@ -6,17 +6,15 @@
|
||||
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
|
||||
*/
|
||||
|
||||
#include "Diagnostic.h"
|
||||
#include "MainWindow.h"
|
||||
#include "common/constants.h"
|
||||
#include "StyleUtils.h"
|
||||
|
||||
#include "common/Constants.h"
|
||||
#include "common/UrlConstants.h"
|
||||
#include "gui/DotEnv.h"
|
||||
#include "gui/Logger.h"
|
||||
#include "gui/config/AppConfig.h"
|
||||
#include "gui/config/ConfigScopes.h"
|
||||
#include "gui/constants.h"
|
||||
#include "gui/diagnostic.h"
|
||||
#include "gui/dotenv.h"
|
||||
#include "gui/messages.h"
|
||||
#include "gui/string_utils.h"
|
||||
#include "gui/style_utils.h"
|
||||
#include "gui/Messages.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QDebug>
|
||||
@ -120,8 +118,10 @@ int main(int argc, char *argv[])
|
||||
#if defined(Q_OS_MAC)
|
||||
|
||||
if (app.applicationDirPath().startsWith("/Volumes/")) {
|
||||
QString msgBody = QStringLiteral("Please drag %1 to the Applications folder, "
|
||||
"and open it from there.");
|
||||
QString msgBody = QStringLiteral(
|
||||
"Please drag %1 to the Applications folder, "
|
||||
"and open it from there."
|
||||
);
|
||||
QMessageBox::information(NULL, kAppName, msgBody.arg(kAppName));
|
||||
return 1;
|
||||
}
|
||||
@ -131,23 +131,15 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
#endif
|
||||
|
||||
ConfigScopes configScopes;
|
||||
|
||||
// --no-reset
|
||||
QStringList arguments = QCoreApplication::arguments();
|
||||
const auto noReset = hasArg("--no-reset", arguments);
|
||||
const auto resetEnvVar = strToTrue(qEnvironmentVariable("DESKFLOW_RESET_ALL"));
|
||||
const auto resetEnvVar = QVariant(qEnvironmentVariable("DESKFLOW_RESET_ALL")).toBool();
|
||||
if (resetEnvVar && !noReset) {
|
||||
diagnostic::clearSettings(configScopes, false);
|
||||
diagnostic::clearSettings(false);
|
||||
}
|
||||
|
||||
AppConfig appConfig(configScopes);
|
||||
|
||||
QObject::connect(
|
||||
&configScopes, &ConfigScopes::saving, &appConfig, [&appConfig]() { appConfig.commit(); }, Qt::DirectConnection
|
||||
);
|
||||
|
||||
MainWindow mainWindow(configScopes, appConfig);
|
||||
MainWindow mainWindow;
|
||||
mainWindow.open();
|
||||
|
||||
return QApplication::exec();
|
||||
@ -181,9 +173,11 @@ bool checkMacAssistiveDevices()
|
||||
// now deprecated in mavericks.
|
||||
bool result = AXAPIEnabled();
|
||||
if (!result) {
|
||||
QString msgBody = QString("Please enable access to assistive devices "
|
||||
"System Preferences -> Security & Privacy -> "
|
||||
"Privacy -> Accessibility, then re-open %1.");
|
||||
QString msgBody = QString(
|
||||
"Please enable access to assistive devices "
|
||||
"System Preferences -> Security & Privacy -> "
|
||||
"Privacy -> Accessibility, then re-open %1."
|
||||
);
|
||||
QMessageBox::information(NULL, kAppName, msgBody.arg(kAppName));
|
||||
}
|
||||
return result;
|
||||
|
||||
@ -4,11 +4,11 @@
|
||||
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
|
||||
*/
|
||||
|
||||
#include "gui/validators/ComputerNameValidator.h"
|
||||
#include "gui/validators/SpacesValidator.h"
|
||||
|
||||
#include "AliasValidator.h"
|
||||
|
||||
#include "ComputerNameValidator.h"
|
||||
#include "SpacesValidator.h"
|
||||
|
||||
#include <QRegularExpression>
|
||||
|
||||
namespace validators {
|
||||
@ -7,7 +7,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "LineEditValidator.h"
|
||||
#include "gui/validators/ValidationError.h"
|
||||
#include "ValidationError.h"
|
||||
|
||||
namespace validators {
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
|
||||
#include "LineEditValidator.h"
|
||||
|
||||
#include "gui/styles.h"
|
||||
#include "gui/Styles.h"
|
||||
|
||||
#include <QValidator>
|
||||
|
||||
@ -6,11 +6,11 @@
|
||||
|
||||
#include "ScreenNameValidator.h"
|
||||
|
||||
#include "gui/validators/ComputerNameValidator.h"
|
||||
#include "gui/validators/EmptyStringValidator.h"
|
||||
#include "gui/validators/ScreenDuplicationsValidator.h"
|
||||
#include "gui/validators/SpacesValidator.h"
|
||||
#include "gui/validators/ValidationError.h"
|
||||
#include "ComputerNameValidator.h"
|
||||
#include "EmptyStringValidator.h"
|
||||
#include "ScreenDuplicationsValidator.h"
|
||||
#include "SpacesValidator.h"
|
||||
#include "ValidationError.h"
|
||||
|
||||
#include <QRegularExpression>
|
||||
#include <memory>
|
||||
@ -23,9 +23,11 @@ ScreenNameValidator::ScreenNameValidator(QLineEdit *lineEdit, ValidationError *e
|
||||
addValidator(std::make_unique<EmptyStringValidator>("Computer name cannot be empty"));
|
||||
addValidator(std::make_unique<SpacesValidator>("Computer name cannot contain spaces"));
|
||||
addValidator(std::make_unique<ComputerNameValidator>("Contains invalid characters or is too long"));
|
||||
addValidator(std::make_unique<ScreenDuplicationsValidator>(
|
||||
"A computer with this name already exists", lineEdit ? lineEdit->text() : "", pScreens
|
||||
));
|
||||
addValidator(
|
||||
std::make_unique<ScreenDuplicationsValidator>(
|
||||
"A computer with this name already exists", lineEdit ? lineEdit->text() : "", pScreens
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
} // namespace validators
|
||||
@ -7,8 +7,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "LineEditValidator.h"
|
||||
#include "ValidationError.h"
|
||||
|
||||
#include "gui/config/ScreenList.h"
|
||||
#include "gui/validators/ValidationError.h"
|
||||
|
||||
namespace validators {
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
|
||||
#include "ValidationError.h"
|
||||
|
||||
#include "gui/styles.h"
|
||||
#include "gui/Styles.h"
|
||||
|
||||
using namespace deskflow::gui;
|
||||
|
||||
@ -10,27 +10,12 @@
|
||||
/* Define if the <X11/extensions/dpms.h> header file declares function prototypes. */
|
||||
#cmakedefine HAVE_DPMS_PROTOTYPES @HAVE_DPMS_PROTOTYPES@
|
||||
|
||||
/* Define if you have a working `getpwuid_r` function. */
|
||||
#cmakedefine HAVE_GETPWUID_R @HAVE_GETPWUID_R@
|
||||
|
||||
/* Define to 1 if you have the `gmtime_r` function. */
|
||||
#cmakedefine HAVE_GMTIME_R @HAVE_GMTIME_R@
|
||||
|
||||
/* Define if you have the `inet_aton` function. */
|
||||
#cmakedefine HAVE_INET_ATON @HAVE_INET_ATON@
|
||||
|
||||
/* Define to 1 if you have the <istream> header file. */
|
||||
#cmakedefine HAVE_ISTREAM @HAVE_ISTREAM@
|
||||
|
||||
/* Define to 1 if you have the <locale.h> header file. */
|
||||
#cmakedefine HAVE_LOCALE_H @HAVE_LOCALE_H@
|
||||
|
||||
/* Define if you have the `nanosleep` function. */
|
||||
#cmakedefine HAVE_NANOSLEEP @HAVE_NANOSLEEP@
|
||||
|
||||
/* Define to 1 if you have the <ostream> header file. */
|
||||
#cmakedefine HAVE_OSTREAM @HAVE_OSTREAM@
|
||||
|
||||
/* Define if you have a POSIX `sigwait` function. */
|
||||
#cmakedefine HAVE_POSIX_SIGWAIT @HAVE_POSIX_SIGWAIT@
|
||||
|
||||
@ -43,9 +28,6 @@
|
||||
/* Define if your compiler defines socklen_t. */
|
||||
#cmakedefine HAVE_SOCKLEN_T @HAVE_SOCKLEN_T@
|
||||
|
||||
/* Define to 1 if you have the <sstream> header file. */
|
||||
#cmakedefine HAVE_SSTREAM @HAVE_SSTREAM@
|
||||
|
||||
/* Define to 1 if you have the <sys/select.h> header file. */
|
||||
#cmakedefine HAVE_SYS_SELECT_H @HAVE_SYS_SELECT_H@
|
||||
|
||||
@ -58,15 +40,9 @@
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
#cmakedefine HAVE_SYS_TYPES_H @HAVE_SYS_TYPES_H@
|
||||
|
||||
/* Define to 1 if you have the <sys/utsname.h> header file. */
|
||||
#cmakedefine HAVE_SYS_UTSNAME_H @HAVE_SYS_UTSNAME_H@
|
||||
|
||||
/* Define to 1 if you have the <unistd.h> header file. */
|
||||
#cmakedefine HAVE_UNISTD_H @HAVE_UNISTD_H@
|
||||
|
||||
/* Define to 1 if you have the <wchar.h> header file. */
|
||||
#cmakedefine HAVE_WCHAR_H @HAVE_WCHAR_H@
|
||||
|
||||
/* Define to 1 if you have the <X11/extensions/Xrandr.h> header file. */
|
||||
#cmakedefine HAVE_X11_EXTENSIONS_XRANDR_H @HAVE_X11_EXTENSIONS_XRANDR_H@
|
||||
|
||||
@ -30,9 +30,6 @@ Arch::Arch(Arch *arch)
|
||||
|
||||
Arch::~Arch()
|
||||
{
|
||||
#if SYSAPI_WIN32
|
||||
ArchMiscWindows::cleanup();
|
||||
#endif
|
||||
}
|
||||
|
||||
void Arch::init()
|
||||
|
||||
@ -24,31 +24,27 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/common.h"
|
||||
#include "common/Common.h"
|
||||
|
||||
#if SYSAPI_WIN32
|
||||
|
||||
#include "arch/win32/ArchConsoleWindows.h"
|
||||
#include "arch/win32/ArchDaemonWindows.h"
|
||||
#include "arch/win32/ArchFileWindows.h"
|
||||
#include "arch/win32/ArchLogWindows.h"
|
||||
#include "arch/win32/ArchMultithreadWindows.h"
|
||||
#include "arch/win32/ArchNetworkWinsock.h"
|
||||
#include "arch/win32/ArchSleepWindows.h"
|
||||
#include "arch/win32/ArchStringWindows.h"
|
||||
#include "arch/win32/ArchSystemWindows.h"
|
||||
#include "arch/win32/ArchTimeWindows.h"
|
||||
|
||||
#elif SYSAPI_UNIX
|
||||
|
||||
#include "arch/unix/ArchConsoleUnix.h"
|
||||
#include "arch/unix/ArchDaemonUnix.h"
|
||||
#include "arch/unix/ArchFileUnix.h"
|
||||
#include "arch/unix/ArchLogUnix.h"
|
||||
#include "arch/unix/ArchNetworkBSD.h"
|
||||
#include "arch/unix/ArchSleepUnix.h"
|
||||
#include "arch/unix/ArchStringUnix.h"
|
||||
#include "arch/unix/ArchSystemUnix.h"
|
||||
#include "arch/unix/ArchTimeUnix.h"
|
||||
|
||||
#if HAVE_PTHREAD
|
||||
@ -75,13 +71,11 @@ typically at the beginning of \c main().
|
||||
*/
|
||||
class Arch : public ARCH_CONSOLE,
|
||||
public ARCH_DAEMON,
|
||||
public ARCH_FILE,
|
||||
public ARCH_LOG,
|
||||
public ARCH_MULTITHREAD,
|
||||
public ARCH_NETWORK,
|
||||
public ARCH_SLEEP,
|
||||
public ARCH_STRING,
|
||||
public ARCH_SYSTEM,
|
||||
public ARCH_TIME
|
||||
{
|
||||
public:
|
||||
|
||||
@ -10,8 +10,6 @@ if(WIN32)
|
||||
win32/ArchConsoleWindows.h
|
||||
win32/ArchDaemonWindows.cpp
|
||||
win32/ArchDaemonWindows.h
|
||||
win32/ArchFileWindows.cpp
|
||||
win32/ArchFileWindows.h
|
||||
win32/ArchLogWindows.cpp
|
||||
win32/ArchLogWindows.h
|
||||
win32/ArchMiscWindows.cpp
|
||||
@ -24,8 +22,6 @@ if(WIN32)
|
||||
win32/ArchSleepWindows.h
|
||||
win32/ArchStringWindows.cpp
|
||||
win32/ArchStringWindows.h
|
||||
win32/ArchSystemWindows.cpp
|
||||
win32/ArchSystemWindows.h
|
||||
win32/ArchTimeWindows.cpp
|
||||
win32/ArchTimeWindows.h
|
||||
win32/XArchWindows.cpp
|
||||
@ -38,8 +34,6 @@ elseif(UNIX)
|
||||
unix/ArchConsoleUnix.h
|
||||
unix/ArchDaemonUnix.cpp
|
||||
unix/ArchDaemonUnix.h
|
||||
unix/ArchFileUnix.cpp
|
||||
unix/ArchFileUnix.h
|
||||
unix/ArchLogUnix.cpp
|
||||
unix/ArchLogUnix.h
|
||||
unix/ArchMultithreadPosix.cpp
|
||||
@ -50,8 +44,6 @@ elseif(UNIX)
|
||||
unix/ArchSleepUnix.h
|
||||
unix/ArchStringUnix.cpp
|
||||
unix/ArchStringUnix.h
|
||||
unix/ArchSystemUnix.cpp
|
||||
unix/ArchSystemUnix.h
|
||||
unix/ArchTimeUnix.cpp
|
||||
unix/ArchTimeUnix.h
|
||||
unix/XArchUnix.cpp
|
||||
@ -68,22 +60,16 @@ add_library(arch STATIC ${PLATFORM_CODE}
|
||||
ArchDaemonNone.h
|
||||
IArchConsole.h
|
||||
IArchDaemon.h
|
||||
IArchFile.h
|
||||
IArchLog.h
|
||||
IArchMultithread.h
|
||||
IArchNetwork.h
|
||||
IArchSleep.h
|
||||
IArchString.cpp
|
||||
IArchString.h
|
||||
IArchSystem.h
|
||||
IArchTime.h
|
||||
multibyte.h
|
||||
XArch.h
|
||||
)
|
||||
|
||||
if(UNIX)
|
||||
target_link_libraries(arch ${libs})
|
||||
if(NOT APPLE)
|
||||
target_link_libraries(arch Qt6::DBus)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@ -8,6 +8,8 @@
|
||||
#pragma once
|
||||
|
||||
#include "common/IInterface.h"
|
||||
|
||||
#include <functional>
|
||||
#include <string>
|
||||
|
||||
//! Interface for architecture dependent daemonizing
|
||||
@ -19,7 +21,7 @@ implement this interface.
|
||||
class IArchDaemon : public IInterface
|
||||
{
|
||||
public:
|
||||
typedef int (*DaemonFunc)(int argc, const char **argv);
|
||||
using DaemonFunc = std::function<int(int, const char **)>;
|
||||
|
||||
//! @name manipulators
|
||||
//@{
|
||||
|
||||
@ -1,92 +0,0 @@
|
||||
/*
|
||||
* Deskflow -- mouse and keyboard sharing utility
|
||||
* SPDX-FileCopyrightText: (C) 2012 - 2016 Symless Ltd.
|
||||
* SPDX-FileCopyrightText: (C) 2002 Chris Schoeneman
|
||||
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/IInterface.h"
|
||||
#include <string>
|
||||
|
||||
//! Interface for architecture dependent file system operations
|
||||
/*!
|
||||
This interface defines the file system operations required by
|
||||
deskflow. Each architecture must implement this interface.
|
||||
*/
|
||||
class IArchFile : public IInterface
|
||||
{
|
||||
public:
|
||||
//! @name manipulators
|
||||
//@{
|
||||
|
||||
//! Extract base name
|
||||
/*!
|
||||
Find the base name in the given \c pathname.
|
||||
*/
|
||||
virtual const char *getBasename(const char *pathname) = 0;
|
||||
|
||||
//! Get user's home directory
|
||||
/*!
|
||||
Returns the user's home directory. Returns the empty string if
|
||||
this cannot be determined.
|
||||
*/
|
||||
virtual std::string getUserDirectory() = 0;
|
||||
|
||||
//! Get system directory
|
||||
/*!
|
||||
Returns the ussystem configuration file directory.
|
||||
*/
|
||||
virtual std::string getSystemDirectory() = 0;
|
||||
|
||||
//! Get installed directory
|
||||
/*!
|
||||
Returns the directory in which Deskflow is installed.
|
||||
*/
|
||||
virtual std::string getInstalledDirectory() = 0;
|
||||
|
||||
//! Get log directory
|
||||
/*!
|
||||
Returns the log file directory.
|
||||
*/
|
||||
virtual std::string getLogDirectory() = 0;
|
||||
|
||||
//! Get plugins directory
|
||||
/*!
|
||||
Returns the plugin files directory. If no plugin directory is set,
|
||||
this will return the plugin folder within the user's profile.
|
||||
*/
|
||||
virtual std::string getPluginDirectory() = 0;
|
||||
|
||||
//! Get user's profile directory
|
||||
/*!
|
||||
Returns the user's profile directory. If no profile directory is set,
|
||||
this will return the user's profile according to the operating system,
|
||||
which will depend on which user launched the program.
|
||||
*/
|
||||
virtual std::string getProfileDirectory() = 0;
|
||||
|
||||
//! Concatenate path components
|
||||
/*!
|
||||
Concatenate pathname components with a directory separator
|
||||
between them. This should not check if the resulting path
|
||||
is longer than allowed by the system; we'll rely on the
|
||||
system calls to tell us that.
|
||||
*/
|
||||
virtual std::string concatPath(const std::string &prefix, const std::string &suffix) = 0;
|
||||
|
||||
//@}
|
||||
//! Set the user's profile directory
|
||||
/*
|
||||
Returns the user's profile directory.
|
||||
*/
|
||||
virtual void setProfileDirectory(const std::string &s) = 0;
|
||||
|
||||
//@}
|
||||
//! Set the user's plugin directory
|
||||
/*
|
||||
Returns the user's plugin directory.
|
||||
*/
|
||||
virtual void setPluginDirectory(const std::string &s) = 0;
|
||||
};
|
||||
@ -7,7 +7,7 @@
|
||||
|
||||
#include "arch/IArchString.h"
|
||||
#include "arch/Arch.h"
|
||||
#include "common/common.h"
|
||||
#include "common/Common.h"
|
||||
|
||||
#include <climits>
|
||||
#include <cstdlib>
|
||||
|
||||
@ -8,8 +8,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/Common.h"
|
||||
#include "common/IInterface.h"
|
||||
#include "common/common.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
|
||||
@ -1,56 +0,0 @@
|
||||
/*
|
||||
* Deskflow -- mouse and keyboard sharing utility
|
||||
* SPDX-FileCopyrightText: (C) 2012 - 2016 Symless Ltd.
|
||||
* SPDX-FileCopyrightText: (C) 2004 Chris Schoeneman
|
||||
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/IInterface.h"
|
||||
#include <string>
|
||||
|
||||
//! Interface for architecture dependent system queries
|
||||
/*!
|
||||
This interface defines operations for querying system info.
|
||||
*/
|
||||
class IArchSystem : public IInterface
|
||||
{
|
||||
public:
|
||||
//! @name accessors
|
||||
//@{
|
||||
|
||||
//! Identify the OS
|
||||
/*!
|
||||
Returns a string identifying the operating system.
|
||||
*/
|
||||
virtual std::string getOSName() const = 0;
|
||||
|
||||
//! Identify the platform
|
||||
/*!
|
||||
Returns a string identifying the platform this OS is running on.
|
||||
*/
|
||||
virtual std::string getPlatformName() const = 0;
|
||||
//@}
|
||||
|
||||
//! Get a Deskflow setting
|
||||
/*!
|
||||
Reads a Deskflow setting from the system.
|
||||
*/
|
||||
virtual std::string setting(const std::string &valueName) const = 0;
|
||||
//@}
|
||||
|
||||
//! Set a Deskflow setting
|
||||
/*!
|
||||
Writes a Deskflow setting from the system.
|
||||
*/
|
||||
virtual void setting(const std::string &valueName, const std::string &valueString) const = 0;
|
||||
//@}
|
||||
|
||||
//! Delete settings
|
||||
/*!
|
||||
Deletes all Core settings from the system.
|
||||
*/
|
||||
virtual void clearSettings() const = 0;
|
||||
//@}
|
||||
};
|
||||
@ -7,8 +7,9 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/common.h"
|
||||
#include "common/stdexcept.h"
|
||||
#include "common/Common.h"
|
||||
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
//! Generic thread exception
|
||||
@ -57,7 +58,7 @@ public:
|
||||
XArchEval()
|
||||
{
|
||||
}
|
||||
virtual ~XArchEval() _NOEXCEPT
|
||||
virtual ~XArchEval() throw()
|
||||
{
|
||||
}
|
||||
|
||||
@ -75,7 +76,7 @@ public:
|
||||
XArch(const std::string &msg) : std::runtime_error(msg)
|
||||
{
|
||||
}
|
||||
virtual ~XArch() _NOEXCEPT
|
||||
virtual ~XArch() throw()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
@ -1,41 +0,0 @@
|
||||
/*
|
||||
* Deskflow -- mouse and keyboard sharing utility
|
||||
* SPDX-FileCopyrightText: (C) 2012 - 2016 Symless Ltd.
|
||||
* SPDX-FileCopyrightText: (C) 2002 Chris Schoeneman
|
||||
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "arch/Arch.h"
|
||||
#include "common/common.h"
|
||||
|
||||
#include <climits>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#if HAVE_LOCALE_H
|
||||
#include <locale.h>
|
||||
#endif
|
||||
#if HAVE_WCHAR_H || defined(_MSC_VER)
|
||||
#include <wchar.h>
|
||||
#elif __APPLE__
|
||||
// wtf? Darwin puts mbtowc() et al. in stdlib
|
||||
#include <cstdlib>
|
||||
#else
|
||||
// platform apparently has no wchar_t support. provide dummy
|
||||
// implementations. hopefully at least the C++ compiler has
|
||||
// a built-in wchar_t type.
|
||||
|
||||
static inline int mbtowc(wchar_t *dst, const char *src, int n)
|
||||
{
|
||||
*dst = static_cast<wchar_t>(*src);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline int wctomb(char *dst, wchar_t src)
|
||||
{
|
||||
*dst = static_cast<char>(src);
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -1,146 +0,0 @@
|
||||
/*
|
||||
* Deskflow -- mouse and keyboard sharing utility
|
||||
* SPDX-FileCopyrightText: (C) 2012 - 2016 Symless Ltd.
|
||||
* SPDX-FileCopyrightText: (C) 2002 Chris Schoeneman
|
||||
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
|
||||
*/
|
||||
|
||||
#include "arch/unix/ArchFileUnix.h"
|
||||
|
||||
#include "common/constants.h"
|
||||
#include <cstring>
|
||||
#include <filesystem>
|
||||
#include <pwd.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
//
|
||||
// ArchFileUnix
|
||||
//
|
||||
|
||||
ArchFileUnix::ArchFileUnix()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
ArchFileUnix::~ArchFileUnix()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
const char *ArchFileUnix::getBasename(const char *pathname)
|
||||
{
|
||||
if (pathname == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char *basename = strrchr(pathname, '/');
|
||||
if (basename != NULL) {
|
||||
return basename + 1;
|
||||
} else {
|
||||
return pathname;
|
||||
}
|
||||
}
|
||||
|
||||
std::string ArchFileUnix::getUserDirectory()
|
||||
{
|
||||
char *buffer = NULL;
|
||||
std::string dir;
|
||||
#if HAVE_GETPWUID_R
|
||||
struct passwd pwent;
|
||||
struct passwd *pwentp{};
|
||||
#if defined(_SC_GETPW_R_SIZE_MAX)
|
||||
long size = sysconf(_SC_GETPW_R_SIZE_MAX);
|
||||
if (size == -1) {
|
||||
size = BUFSIZ;
|
||||
}
|
||||
#else
|
||||
long size = BUFSIZ;
|
||||
#endif
|
||||
buffer = new char[size];
|
||||
getpwuid_r(getuid(), &pwent, buffer, size, &pwentp);
|
||||
#else
|
||||
struct passwd *pwentp = getpwuid(getuid());
|
||||
#endif
|
||||
if (pwentp != NULL && pwentp->pw_dir != NULL) {
|
||||
dir = pwentp->pw_dir;
|
||||
}
|
||||
delete[] buffer;
|
||||
return dir;
|
||||
}
|
||||
|
||||
std::string ArchFileUnix::getSystemDirectory()
|
||||
{
|
||||
return "/etc";
|
||||
}
|
||||
|
||||
std::string ArchFileUnix::getInstalledDirectory()
|
||||
{
|
||||
#if WINAPI_XWINDOWS
|
||||
return "/usr/bin";
|
||||
#else
|
||||
std::string rtn = "/Applications/";
|
||||
rtn.append(kAppName).append(".app/Contents/MacOS");
|
||||
return rtn;
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string ArchFileUnix::getLogDirectory()
|
||||
{
|
||||
return "/var/log";
|
||||
}
|
||||
|
||||
std::string ArchFileUnix::getPluginDirectory()
|
||||
{
|
||||
if (!m_pluginDirectory.empty()) {
|
||||
return m_pluginDirectory;
|
||||
}
|
||||
|
||||
#if WINAPI_XWINDOWS
|
||||
return getProfileDirectory().append("/plugins");
|
||||
#else
|
||||
return getProfileDirectory().append("/Plugins");
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string ArchFileUnix::getProfileDirectory()
|
||||
{
|
||||
if (!m_profileDirectory.empty()) {
|
||||
return m_profileDirectory;
|
||||
} else {
|
||||
const std::filesystem::path homeDir = getUserDirectory();
|
||||
#if WINAPI_XWINDOWS
|
||||
const auto xdgDir = std::getenv("XDG_CONFIG_HOME");
|
||||
if (xdgDir != nullptr) {
|
||||
return std::filesystem::path(xdgDir) / kAppName;
|
||||
} else {
|
||||
return homeDir / ".config" / kAppName;
|
||||
}
|
||||
#else
|
||||
return homeDir / "Library" / kAppName;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
std::string ArchFileUnix::concatPath(const std::string &prefix, const std::string &suffix)
|
||||
{
|
||||
std::string path;
|
||||
path.reserve(prefix.size() + 1 + suffix.size());
|
||||
path += prefix;
|
||||
if (path.size() == 0 || path[path.size() - 1] != '/') {
|
||||
path += '/';
|
||||
}
|
||||
path += suffix;
|
||||
return path;
|
||||
}
|
||||
|
||||
void ArchFileUnix::setProfileDirectory(const std::string &s)
|
||||
{
|
||||
m_profileDirectory = s;
|
||||
}
|
||||
|
||||
void ArchFileUnix::setPluginDirectory(const std::string &s)
|
||||
{
|
||||
m_pluginDirectory = s;
|
||||
}
|
||||
@ -1,36 +0,0 @@
|
||||
/*
|
||||
* Deskflow -- mouse and keyboard sharing utility
|
||||
* SPDX-FileCopyrightText: (C) 2012 - 2016 Symless Ltd.
|
||||
* SPDX-FileCopyrightText: (C) 2002 Chris Schoeneman
|
||||
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "arch/IArchFile.h"
|
||||
|
||||
#define ARCH_FILE ArchFileUnix
|
||||
|
||||
//! Unix implementation of IArchFile
|
||||
class ArchFileUnix : public IArchFile
|
||||
{
|
||||
public:
|
||||
ArchFileUnix();
|
||||
virtual ~ArchFileUnix();
|
||||
|
||||
// IArchFile overrides
|
||||
virtual const char *getBasename(const char *pathname);
|
||||
virtual std::string getUserDirectory();
|
||||
virtual std::string getSystemDirectory();
|
||||
virtual std::string getInstalledDirectory();
|
||||
virtual std::string getLogDirectory();
|
||||
virtual std::string getPluginDirectory();
|
||||
virtual std::string getProfileDirectory();
|
||||
virtual std::string concatPath(const std::string &prefix, const std::string &suffix);
|
||||
virtual void setProfileDirectory(const std::string &s);
|
||||
virtual void setPluginDirectory(const std::string &s);
|
||||
|
||||
private:
|
||||
std::string m_profileDirectory;
|
||||
std::string m_pluginDirectory;
|
||||
};
|
||||
@ -8,8 +8,8 @@
|
||||
#pragma once
|
||||
|
||||
#include "arch/IArchMultithread.h"
|
||||
#include "common/stdlist.h"
|
||||
|
||||
#include <list>
|
||||
#include <pthread.h>
|
||||
|
||||
#define ARCH_MULTITHREAD ArchMultithreadPosix
|
||||
|
||||
@ -13,8 +13,6 @@
|
||||
// ArchStringUnix
|
||||
//
|
||||
|
||||
#include "arch/multibyte.h"
|
||||
|
||||
ArchStringUnix::ArchStringUnix()
|
||||
{
|
||||
}
|
||||
|
||||
@ -1,131 +0,0 @@
|
||||
/*
|
||||
* Deskflow -- mouse and keyboard sharing utility
|
||||
* SPDX-FileCopyrightText: (C) 2012 - 2016 Symless Ltd.
|
||||
* SPDX-FileCopyrightText: (C) 2002 Chris Schoeneman
|
||||
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
|
||||
*/
|
||||
|
||||
#include "arch/unix/ArchSystemUnix.h"
|
||||
#include <array>
|
||||
|
||||
#include <common/constants.h>
|
||||
#include <sys/utsname.h>
|
||||
|
||||
#ifndef __APPLE__
|
||||
#include <QDBusConnection>
|
||||
#include <QDBusError>
|
||||
#include <QDBusInterface>
|
||||
#include <QDBusReply>
|
||||
#endif
|
||||
|
||||
//
|
||||
// ArchSystemUnix
|
||||
//
|
||||
|
||||
ArchSystemUnix::ArchSystemUnix()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
ArchSystemUnix::~ArchSystemUnix()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
std::string ArchSystemUnix::getOSName() const
|
||||
{
|
||||
#if defined(HAVE_SYS_UTSNAME_H)
|
||||
struct utsname info;
|
||||
if (uname(&info) == 0) {
|
||||
std::string msg;
|
||||
msg += info.sysname;
|
||||
msg += " ";
|
||||
msg += info.release;
|
||||
return msg;
|
||||
}
|
||||
#endif
|
||||
return "Unix";
|
||||
}
|
||||
|
||||
std::string ArchSystemUnix::getPlatformName() const
|
||||
{
|
||||
#if defined(HAVE_SYS_UTSNAME_H)
|
||||
struct utsname info;
|
||||
if (uname(&info) == 0) {
|
||||
return std::string(info.machine);
|
||||
}
|
||||
#endif
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
std::string ArchSystemUnix::setting(const std::string &) const
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
void ArchSystemUnix::setting(const std::string &, const std::string &) const
|
||||
{
|
||||
}
|
||||
|
||||
void ArchSystemUnix::clearSettings() const
|
||||
{
|
||||
// Not implemented
|
||||
}
|
||||
|
||||
std::string ArchSystemUnix::getLibsUsed(void) const
|
||||
{
|
||||
return "not implemented.\nuse lsof on shell";
|
||||
}
|
||||
|
||||
#ifndef __APPLE__
|
||||
bool ArchSystemUnix::DBusInhibitScreenCall(InhibitScreenServices serviceID, bool state, std::string &error)
|
||||
{
|
||||
error = "";
|
||||
static const std::array<QString, 2> services = {"org.freedesktop.ScreenSaver", "org.gnome.SessionManager"};
|
||||
static const std::array<QString, 2> paths = {"/org/freedesktop/ScreenSaver", "/org/gnome/SessionManager"};
|
||||
static std::array<uint, 2> cookies;
|
||||
|
||||
auto serviceNum = static_cast<uint8_t>(serviceID);
|
||||
|
||||
QDBusConnection bus = QDBusConnection::sessionBus();
|
||||
if (!bus.isConnected()) {
|
||||
error = "bus failed to connect";
|
||||
return false;
|
||||
}
|
||||
|
||||
QDBusInterface screenSaverInterface(services[serviceNum], paths[serviceNum], services[serviceNum], bus);
|
||||
|
||||
if (!screenSaverInterface.isValid()) {
|
||||
error = "screen saver interface failed to initialize";
|
||||
return false;
|
||||
}
|
||||
|
||||
QDBusReply<uint> reply;
|
||||
if (state) {
|
||||
if (cookies[serviceNum]) {
|
||||
error = "coockies are not empty";
|
||||
return false;
|
||||
}
|
||||
|
||||
QString msg = "Sleep is manually prevented by the %1 preferences";
|
||||
reply = screenSaverInterface.call("Inhibit", kAppName, msg.arg(kAppName));
|
||||
if (reply.isValid())
|
||||
cookies[serviceNum] = reply.value();
|
||||
} else {
|
||||
if (!cookies[serviceNum]) {
|
||||
error = "coockies are empty";
|
||||
return false;
|
||||
}
|
||||
reply = screenSaverInterface.call("UnInhibit", cookies[serviceNum]);
|
||||
cookies[serviceNum] = 0;
|
||||
}
|
||||
|
||||
if (!reply.isValid()) {
|
||||
QDBusError qerror = reply.error();
|
||||
error = qerror.name().toStdString() + " : " + qerror.message().toStdString();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
@ -1,37 +0,0 @@
|
||||
/*
|
||||
* Deskflow -- mouse and keyboard sharing utility
|
||||
* SPDX-FileCopyrightText: (C) 2012 - 2016 Symless Ltd.
|
||||
* SPDX-FileCopyrightText: (C) 2002 Chris Schoeneman
|
||||
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "arch/IArchSystem.h"
|
||||
|
||||
#define ARCH_SYSTEM ArchSystemUnix
|
||||
|
||||
//! Unix implementation of IArchString
|
||||
class ArchSystemUnix : public IArchSystem
|
||||
{
|
||||
public:
|
||||
ArchSystemUnix();
|
||||
virtual ~ArchSystemUnix();
|
||||
|
||||
// IArchSystem overrides
|
||||
virtual std::string getOSName() const;
|
||||
virtual std::string getPlatformName() const;
|
||||
virtual std::string setting(const std::string &) const;
|
||||
virtual void setting(const std::string &, const std::string &) const;
|
||||
virtual std::string getLibsUsed(void) const;
|
||||
virtual void clearSettings() const;
|
||||
|
||||
#ifndef __APPLE__
|
||||
enum class InhibitScreenServices
|
||||
{
|
||||
kScreenSaver,
|
||||
kSessionManager
|
||||
};
|
||||
static bool DBusInhibitScreenCall(InhibitScreenServices serviceID, bool state, std::string &error);
|
||||
#endif
|
||||
};
|
||||
@ -16,7 +16,7 @@ public:
|
||||
XArchEvalUnix(int error) : m_error(error)
|
||||
{
|
||||
}
|
||||
virtual ~XArchEvalUnix() _NOEXCEPT
|
||||
virtual ~XArchEvalUnix() throw()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@ -350,6 +350,8 @@ void ArchDaemonWindows::setStatus(DWORD state, DWORD step, DWORD waitHint)
|
||||
{
|
||||
assert(s_daemon != NULL);
|
||||
|
||||
LOG_DEBUG("setting service status: state=%d, step=%d, waitHint=%d", state, step, waitHint);
|
||||
|
||||
SERVICE_STATUS status;
|
||||
status.dwServiceType = SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS;
|
||||
status.dwCurrentState = state;
|
||||
|
||||
@ -9,20 +9,22 @@
|
||||
|
||||
#include "arch/IArchDaemon.h"
|
||||
#include "arch/IArchMultithread.h"
|
||||
#include "common/constants.h"
|
||||
#include <string>
|
||||
#include "common/Constants.h"
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <Windows.h>
|
||||
#include <tchar.h>
|
||||
|
||||
#include <functional>
|
||||
#include <string>
|
||||
|
||||
#define ARCH_DAEMON ArchDaemonWindows
|
||||
|
||||
//! Win32 implementation of IArchDaemon
|
||||
class ArchDaemonWindows : public IArchDaemon
|
||||
{
|
||||
public:
|
||||
typedef int (*RunFunc)(void);
|
||||
using RunFunc = std::function<int()>;
|
||||
|
||||
ArchDaemonWindows();
|
||||
virtual ~ArchDaemonWindows();
|
||||
|
||||
@ -1,173 +0,0 @@
|
||||
/*
|
||||
* Deskflow -- mouse and keyboard sharing utility
|
||||
* SPDX-FileCopyrightText: (C) 2012 - 2016 Symless Ltd.
|
||||
* SPDX-FileCopyrightText: (C) 2002 Chris Schoeneman
|
||||
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
|
||||
*/
|
||||
|
||||
#include "arch/win32/ArchFileWindows.h"
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <Windows.h>
|
||||
#include <shlobj.h>
|
||||
#include <string.h>
|
||||
#include <tchar.h>
|
||||
|
||||
//
|
||||
// ArchFileWindows
|
||||
//
|
||||
|
||||
ArchFileWindows::ArchFileWindows()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
ArchFileWindows::~ArchFileWindows()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
const char *ArchFileWindows::getBasename(const char *pathname)
|
||||
{
|
||||
if (pathname == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// check for last slash
|
||||
const char *basename = strrchr(pathname, '/');
|
||||
if (basename != NULL) {
|
||||
++basename;
|
||||
} else {
|
||||
basename = pathname;
|
||||
}
|
||||
|
||||
// check for last backslash
|
||||
const char *basename2 = strrchr(pathname, '\\');
|
||||
if (basename2 != NULL && basename2 > basename) {
|
||||
basename = basename2 + 1;
|
||||
}
|
||||
|
||||
return basename;
|
||||
}
|
||||
|
||||
std::string ArchFileWindows::getUserDirectory()
|
||||
{
|
||||
// try %HOMEPATH%
|
||||
TCHAR dir[MAX_PATH];
|
||||
DWORD size = sizeof(dir) / sizeof(TCHAR);
|
||||
DWORD result = GetEnvironmentVariable(_T("HOMEPATH"), dir, size);
|
||||
if (result != 0 && result <= size) {
|
||||
// sanity check -- if dir doesn't appear to start with a
|
||||
// drive letter and isn't a UNC name then don't use it
|
||||
// FIXME -- allow UNC names
|
||||
if (dir[0] != '\0' && (dir[1] == ':' || ((dir[0] == '\\' || dir[0] == '/') && (dir[1] == '\\' || dir[1] == '/')))) {
|
||||
return dir;
|
||||
}
|
||||
}
|
||||
|
||||
// get the location of the personal files. that's as close to
|
||||
// a home directory as we're likely to find.
|
||||
ITEMIDLIST *idl;
|
||||
if (SUCCEEDED(SHGetSpecialFolderLocation(NULL, CSIDL_PERSONAL, &idl))) {
|
||||
TCHAR *path = NULL;
|
||||
if (SHGetPathFromIDList(idl, dir)) {
|
||||
DWORD attr = GetFileAttributes(dir);
|
||||
if (attr != 0xffffffff && (attr & FILE_ATTRIBUTE_DIRECTORY) != 0)
|
||||
path = dir;
|
||||
}
|
||||
|
||||
IMalloc *shalloc;
|
||||
if (SUCCEEDED(SHGetMalloc(&shalloc))) {
|
||||
shalloc->Free(idl);
|
||||
shalloc->Release();
|
||||
}
|
||||
|
||||
if (path != NULL) {
|
||||
return path;
|
||||
}
|
||||
}
|
||||
|
||||
// use root of C drive as a default
|
||||
return "C:";
|
||||
}
|
||||
|
||||
std::string ArchFileWindows::getSystemDirectory()
|
||||
{
|
||||
// get windows directory
|
||||
char dir[MAX_PATH];
|
||||
if (GetWindowsDirectory(dir, sizeof(dir)) != 0) {
|
||||
return dir;
|
||||
} else {
|
||||
// can't get it. use C:\ as a default.
|
||||
return "C:";
|
||||
}
|
||||
}
|
||||
|
||||
std::string ArchFileWindows::getInstalledDirectory()
|
||||
{
|
||||
char fileNameBuffer[MAX_PATH];
|
||||
GetModuleFileName(NULL, fileNameBuffer, MAX_PATH);
|
||||
std::string fileName(fileNameBuffer);
|
||||
size_t lastSlash = fileName.find_last_of("\\");
|
||||
fileName = fileName.substr(0, lastSlash);
|
||||
|
||||
return fileName;
|
||||
}
|
||||
|
||||
std::string ArchFileWindows::getLogDirectory()
|
||||
{
|
||||
return getInstalledDirectory();
|
||||
}
|
||||
|
||||
std::string ArchFileWindows::getPluginDirectory()
|
||||
{
|
||||
if (!m_pluginDirectory.empty()) {
|
||||
return m_pluginDirectory;
|
||||
}
|
||||
|
||||
std::string dir = getProfileDirectory();
|
||||
dir.append("\\Plugins");
|
||||
return dir;
|
||||
}
|
||||
|
||||
std::string ArchFileWindows::getProfileDirectory()
|
||||
{
|
||||
std::string dir;
|
||||
if (!m_profileDirectory.empty()) {
|
||||
dir = m_profileDirectory;
|
||||
} else {
|
||||
TCHAR result[MAX_PATH];
|
||||
if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_LOCAL_APPDATA, NULL, 0, result))) {
|
||||
dir = result;
|
||||
} else {
|
||||
dir = getUserDirectory();
|
||||
}
|
||||
}
|
||||
|
||||
// HACK: append program name, this seems wrong.
|
||||
dir.append("\\Deskflow");
|
||||
|
||||
return dir;
|
||||
}
|
||||
|
||||
std::string ArchFileWindows::concatPath(const std::string &prefix, const std::string &suffix)
|
||||
{
|
||||
std::string path;
|
||||
path.reserve(prefix.size() + 1 + suffix.size());
|
||||
path += prefix;
|
||||
if (path.size() == 0 || (path[path.size() - 1] != '\\' && path[path.size() - 1] != '/')) {
|
||||
path += '\\';
|
||||
}
|
||||
path += suffix;
|
||||
return path;
|
||||
}
|
||||
|
||||
void ArchFileWindows::setProfileDirectory(const std::string &s)
|
||||
{
|
||||
m_profileDirectory = s;
|
||||
}
|
||||
|
||||
void ArchFileWindows::setPluginDirectory(const std::string &s)
|
||||
{
|
||||
m_pluginDirectory = s;
|
||||
}
|
||||
@ -1,36 +0,0 @@
|
||||
/*
|
||||
* Deskflow -- mouse and keyboard sharing utility
|
||||
* SPDX-FileCopyrightText: (C) 2012 - 2016 Symless Ltd.
|
||||
* SPDX-FileCopyrightText: (C) 2002 Chris Schoeneman
|
||||
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "arch/IArchFile.h"
|
||||
|
||||
#define ARCH_FILE ArchFileWindows
|
||||
|
||||
//! Win32 implementation of IArchFile
|
||||
class ArchFileWindows : public IArchFile
|
||||
{
|
||||
public:
|
||||
ArchFileWindows();
|
||||
virtual ~ArchFileWindows();
|
||||
|
||||
// IArchFile overrides
|
||||
virtual const char *getBasename(const char *pathname);
|
||||
virtual std::string getUserDirectory();
|
||||
virtual std::string getSystemDirectory();
|
||||
virtual std::string getInstalledDirectory();
|
||||
virtual std::string getLogDirectory();
|
||||
virtual std::string getPluginDirectory();
|
||||
virtual std::string getProfileDirectory();
|
||||
virtual std::string concatPath(const std::string &prefix, const std::string &suffix);
|
||||
virtual void setProfileDirectory(const std::string &s);
|
||||
virtual void setPluginDirectory(const std::string &s);
|
||||
|
||||
private:
|
||||
std::string m_profileDirectory;
|
||||
std::string m_pluginDirectory;
|
||||
};
|
||||
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Deskflow -- mouse and keyboard sharing utility
|
||||
* SPDX-FileCopyrightText: (C) 2012 - 2016 Symless Ltd.
|
||||
* SPDX-FileCopyrightText: (C) 2012 - 2016, 2024 - 2025 Symless Ltd.
|
||||
* SPDX-FileCopyrightText: (C) 2002 Chris Schoeneman
|
||||
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
|
||||
*/
|
||||
@ -12,95 +12,55 @@
|
||||
#include "base/Log.h"
|
||||
#include "base/String.h"
|
||||
|
||||
#include <Wtsapi32.h>
|
||||
#pragma warning(disable : 4099)
|
||||
#include <Userenv.h>
|
||||
#pragma warning(default : 4099)
|
||||
#include <Psapi.h>
|
||||
|
||||
#include <array>
|
||||
#include <filesystem>
|
||||
|
||||
// Welcome to DLL hell! :)
|
||||
//
|
||||
// Microsoft lets you run a program with an old runtime DLL, as long as the name matches.
|
||||
// Unfortunately if you compile on VS2022 and then use the VS2019 runtime, which both have the
|
||||
// same runtime DLL name, the app will randomly crash (e.g. access violation) or break in strange
|
||||
// and unpredictable ways due to ABI differences.
|
||||
//
|
||||
// In Windows, there is no concept of requiring a minimum version of the runtime DLL, so we have
|
||||
// to check the version ourselves.
|
||||
//
|
||||
// Our CI is set up to build with the latest compiler, so in this case we should insist on the
|
||||
// latest runtime DLL.
|
||||
//
|
||||
// As a developer convenience, we also allow builds on older compilers such as the minimum
|
||||
// requirements for the current Qt version we support.
|
||||
//
|
||||
// See table of the compiler versions and the matching runtime DLL versions:
|
||||
// https://dev.to/yumetodo/list-of-mscver-and-mscfullver-8nd
|
||||
#if _MSC_VER >= 1942 // Visual Studio 2022 Update 12 (v17.12.4)
|
||||
const auto kRequiredMajor = 14;
|
||||
const auto kRequiredMinor = 42;
|
||||
#elif _MSC_VER >= 1920 // Visual Studio 2019 Update 7 (v16.7)
|
||||
const auto kRequiredMajor = 14;
|
||||
const auto kRequiredMinor = 27;
|
||||
#else
|
||||
#pragma message("MSC version: " STRINGIFY(_MSC_VER))
|
||||
#error "Unsupported MSC version"
|
||||
#endif
|
||||
// Useful for debugging Windows specific bootstrapping code before the logging system is initialized.
|
||||
// This output can be viewed by attaching a Microsoft debugger or by using the DebugView program.
|
||||
#define MS_LOG_DEBUG(message, ...) \
|
||||
OutputDebugStringA((deskflow::string::sprintf((s_binaryName + ": " + message + "\n").c_str(), __VA_ARGS__)).c_str())
|
||||
|
||||
// parent process name for services in Vista
|
||||
#define SERVICE_LAUNCHER "services.exe"
|
||||
//
|
||||
// Free functions
|
||||
//
|
||||
|
||||
#ifndef ES_SYSTEM_REQUIRED
|
||||
#define ES_SYSTEM_REQUIRED ((DWORD)0x00000001)
|
||||
#endif
|
||||
#ifndef ES_DISPLAY_REQUIRED
|
||||
#define ES_DISPLAY_REQUIRED ((DWORD)0x00000002)
|
||||
#endif
|
||||
#ifndef ES_CONTINUOUS
|
||||
#define ES_CONTINUOUS ((DWORD)0x80000000)
|
||||
#endif
|
||||
using EXECUTION_STATE = DWORD;
|
||||
void errorMessageBox(const char *message, const char *title = "Fatal Error");
|
||||
|
||||
void errorMessageBox(const char *message, const char *title = "Fatal Error")
|
||||
std::string getBinaryName()
|
||||
{
|
||||
std::array<char, MAX_PATH> buffer;
|
||||
if (!GetModuleFileNameA(NULL, buffer.data(), MAX_PATH)) {
|
||||
errorMessageBox("Failed to get binary name.");
|
||||
abort();
|
||||
}
|
||||
|
||||
return std::filesystem::path(buffer.data()).filename().string();
|
||||
}
|
||||
|
||||
void errorMessageBox(const char *message, const char *title)
|
||||
{
|
||||
MessageBoxA(nullptr, message, title, MB_ICONERROR | MB_OK);
|
||||
}
|
||||
|
||||
// Used by bootstrap logging to differentiate between daemon and client/server messages.
|
||||
const std::string s_binaryName = getBinaryName();
|
||||
|
||||
//
|
||||
// ArchMiscWindows
|
||||
//
|
||||
|
||||
ArchMiscWindows::Dialogs *ArchMiscWindows::s_dialogs = NULL;
|
||||
DWORD ArchMiscWindows::s_busyState = 0;
|
||||
ArchMiscWindows::STES_t ArchMiscWindows::s_stes = NULL;
|
||||
HICON ArchMiscWindows::s_largeIcon = NULL;
|
||||
HICON ArchMiscWindows::s_smallIcon = NULL;
|
||||
HINSTANCE ArchMiscWindows::s_instanceWin32 = NULL;
|
||||
|
||||
void ArchMiscWindows::cleanup()
|
||||
{
|
||||
delete s_dialogs;
|
||||
}
|
||||
|
||||
void ArchMiscWindows::init()
|
||||
{
|
||||
// stop windows system error dialogs from showing.
|
||||
SetErrorMode(SEM_FAILCRITICALERRORS);
|
||||
|
||||
s_dialogs = new Dialogs;
|
||||
}
|
||||
|
||||
void ArchMiscWindows::setIcons(HICON largeIcon, HICON smallIcon)
|
||||
{
|
||||
s_largeIcon = largeIcon;
|
||||
s_smallIcon = smallIcon;
|
||||
}
|
||||
|
||||
void ArchMiscWindows::getIcons(HICON &largeIcon, HICON &smallIcon)
|
||||
{
|
||||
largeIcon = s_largeIcon;
|
||||
smallIcon = s_smallIcon;
|
||||
}
|
||||
|
||||
int ArchMiscWindows::runDaemon(RunFunc runFunc)
|
||||
@ -193,31 +153,6 @@ void ArchMiscWindows::deleteKey(HKEY key, const TCHAR *name)
|
||||
RegDeleteKey(key, name);
|
||||
}
|
||||
|
||||
void ArchMiscWindows::deleteValue(HKEY key, const TCHAR *name)
|
||||
{
|
||||
assert(key != NULL);
|
||||
assert(name != NULL);
|
||||
if (key == NULL || name == NULL)
|
||||
return;
|
||||
RegDeleteValue(key, name);
|
||||
}
|
||||
|
||||
void ArchMiscWindows::deleteKeyTree(HKEY key, const TCHAR *name)
|
||||
{
|
||||
assert(key != NULL);
|
||||
assert(name != NULL);
|
||||
if (key == NULL || name == NULL)
|
||||
return;
|
||||
RegDeleteTree(key, name);
|
||||
}
|
||||
|
||||
bool ArchMiscWindows::hasValue(HKEY key, const TCHAR *name)
|
||||
{
|
||||
DWORD type;
|
||||
LONG result = RegQueryValueEx(key, name, 0, &type, NULL, NULL);
|
||||
return (result == ERROR_SUCCESS && (type == REG_DWORD || type == REG_SZ));
|
||||
}
|
||||
|
||||
ArchMiscWindows::EValueType ArchMiscWindows::typeOfValue(HKEY key, const TCHAR *name)
|
||||
{
|
||||
DWORD type;
|
||||
@ -260,17 +195,6 @@ void ArchMiscWindows::setValue(HKEY key, const TCHAR *name, DWORD value)
|
||||
RegSetValueEx(key, name, 0, REG_DWORD, reinterpret_cast<CONST BYTE *>(&value), sizeof(DWORD));
|
||||
}
|
||||
|
||||
void ArchMiscWindows::setValueBinary(HKEY key, const TCHAR *name, const std::string &value)
|
||||
{
|
||||
assert(key != NULL);
|
||||
assert(name != NULL);
|
||||
if (key == NULL || name == NULL) {
|
||||
// TODO: throw exception
|
||||
return;
|
||||
}
|
||||
RegSetValueEx(key, name, 0, REG_BINARY, reinterpret_cast<const BYTE *>(value.data()), (DWORD)value.size());
|
||||
}
|
||||
|
||||
std::string ArchMiscWindows::readBinaryOrString(HKEY key, const TCHAR *name, DWORD type)
|
||||
{
|
||||
// get the size of the string
|
||||
@ -311,11 +235,6 @@ std::string ArchMiscWindows::readValueString(HKEY key, const TCHAR *name)
|
||||
return readBinaryOrString(key, name, REG_SZ);
|
||||
}
|
||||
|
||||
std::string ArchMiscWindows::readValueBinary(HKEY key, const TCHAR *name)
|
||||
{
|
||||
return readBinaryOrString(key, name, REG_BINARY);
|
||||
}
|
||||
|
||||
DWORD
|
||||
ArchMiscWindows::readValueInt(HKEY key, const TCHAR *name)
|
||||
{
|
||||
@ -329,26 +248,6 @@ ArchMiscWindows::readValueInt(HKEY key, const TCHAR *name)
|
||||
return value;
|
||||
}
|
||||
|
||||
void ArchMiscWindows::addDialog(HWND hwnd)
|
||||
{
|
||||
s_dialogs->insert(hwnd);
|
||||
}
|
||||
|
||||
void ArchMiscWindows::removeDialog(HWND hwnd)
|
||||
{
|
||||
s_dialogs->erase(hwnd);
|
||||
}
|
||||
|
||||
bool ArchMiscWindows::processDialog(MSG *msg)
|
||||
{
|
||||
for (Dialogs::const_iterator index = s_dialogs->begin(); index != s_dialogs->end(); ++index) {
|
||||
if (IsDialogMessage(*index, msg)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ArchMiscWindows::addBusyState(DWORD busyModes)
|
||||
{
|
||||
s_busyState |= busyModes;
|
||||
@ -375,7 +274,7 @@ void ArchMiscWindows::setThreadExecutionState(DWORD busyModes)
|
||||
}
|
||||
|
||||
// convert to STES form
|
||||
EXECUTION_STATE state = 0;
|
||||
DWORD state = 0;
|
||||
if ((busyModes & kSYSTEM) != 0) {
|
||||
state |= ES_SYSTEM_REQUIRED;
|
||||
}
|
||||
@ -426,7 +325,7 @@ bool ArchMiscWindows::wasLaunchedAsService()
|
||||
return false;
|
||||
}
|
||||
|
||||
return (name == SERVICE_LAUNCHER);
|
||||
return (name == "services.exe");
|
||||
}
|
||||
|
||||
bool ArchMiscWindows::getParentProcessName(std::string &name)
|
||||
@ -521,40 +420,89 @@ std::string ArchMiscWindows::getActiveDesktopName()
|
||||
return name;
|
||||
}
|
||||
|
||||
void ArchMiscWindows::guardRuntimeVersion() // NOSONAR - `noreturn` is not available
|
||||
HMODULE ArchMiscWindows::findLoadedModule(std::array<const char *, 2> moduleNames)
|
||||
{
|
||||
const auto kRuntimeDll = "vcruntime140.dll";
|
||||
std::array<HMODULE, 1024> hModules;
|
||||
DWORD cbNeeded;
|
||||
|
||||
HMODULE hModule = nullptr;
|
||||
if (!GetModuleHandleEx(0, kRuntimeDll, &hModule) && hModule) {
|
||||
errorMessageBox("Microsoft Visual C++ Runtime is not installed.");
|
||||
HANDLE hProcess = GetCurrentProcess();
|
||||
if (!EnumProcessModules(hProcess, hModules.data(), sizeof(hModules), &cbNeeded)) {
|
||||
errorMessageBox("Failed to enumerate process modules.");
|
||||
abort();
|
||||
}
|
||||
|
||||
std::string loadedModuleName;
|
||||
for (size_t i = 0; i < (cbNeeded / sizeof(HMODULE)); ++i) {
|
||||
if (!GetModuleBaseNameA(hProcess, hModules[i], loadedModuleName.data(), sizeof(loadedModuleName))) {
|
||||
LOG_WARN("could not get base name of loaded module %d", i);
|
||||
continue;
|
||||
}
|
||||
|
||||
for (const auto &moduleName : moduleNames) {
|
||||
if (_stricmp(loadedModuleName.data(), moduleName) == 0) {
|
||||
return hModules[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Enforcing minimum MSVC runtime version is quite strict, but we have a good reason.
|
||||
//
|
||||
// Microsoft lets you run a program with an older version of the runtime DLL than the one it was
|
||||
// compiled with. This is because the runtime DLLs are supposedly ABI-compatible when the major
|
||||
// version is the same, so hypothetically MSVC runtime 14.0 is compatible with 14.42.
|
||||
// However, we have found subtle edge cases such as mutex lock causes access violation.
|
||||
//
|
||||
// Example of how Microsoft breaks ABI compatibility between minor runtime versions:
|
||||
// https://stackoverflow.com/questions/69990339/why-is-stdmutex-so-much-worse-than-stdshared-mutex-in-visual-c
|
||||
//
|
||||
// Our CI is set up to build with the latest compiler, so in this case we should insist on at least
|
||||
// the runtime DLL that was released at the same time as the compiler.
|
||||
//
|
||||
// As a developer convenience, we also allow builds on older compilers such as the minimum
|
||||
// requirements for the current Qt version we support.
|
||||
void ArchMiscWindows::guardRuntimeVersion() // NOSONAR - `noreturn` is not available
|
||||
{
|
||||
auto hModule = findLoadedModule({"vcruntime140.dll", "vcruntime140d.dll"});
|
||||
if (hModule == nullptr) {
|
||||
errorMessageBox("Failed to find MSVC runtime DLL.");
|
||||
abort();
|
||||
}
|
||||
|
||||
MS_LOG_DEBUG("found msvc runtime dll, handle: %p", hModule);
|
||||
|
||||
std::array<char, MAX_PATH> pathBuffer;
|
||||
const auto path = pathBuffer.data();
|
||||
if (!GetModuleFileNameA(hModule, path, MAX_PATH)) {
|
||||
errorMessageBox("Failed to get the path of Microsoft Visual C++ Runtime.");
|
||||
errorMessageBox("Failed to get path of MSVC runtime.");
|
||||
abort();
|
||||
}
|
||||
|
||||
MS_LOG_DEBUG("msvc runtime dll path: %s", path);
|
||||
|
||||
DWORD handle;
|
||||
DWORD size = GetFileVersionInfoSizeA(path, &handle);
|
||||
if (size <= 0) {
|
||||
errorMessageBox("Failed to get the version info size for Microsoft Visual C++ Runtime.");
|
||||
errorMessageBox("Failed to get version info size for MSVC runtime.");
|
||||
abort();
|
||||
}
|
||||
|
||||
MS_LOG_DEBUG("msvc runtime dll version info size: %d", size);
|
||||
|
||||
std::vector<BYTE> versionInfo(size);
|
||||
if (!GetFileVersionInfoA(path, handle, size, versionInfo.data())) {
|
||||
errorMessageBox("Failed to get the file version info for Microsoft Visual C++ Runtime.");
|
||||
errorMessageBox("Failed to get file version info for MSVC runtime.");
|
||||
abort();
|
||||
}
|
||||
|
||||
MS_LOG_DEBUG("msvc runtime dll version info ok, querying values");
|
||||
|
||||
VS_FIXEDFILEINFO *fileInfo = nullptr;
|
||||
const auto lplpFileInfo = reinterpret_cast<void **>(&fileInfo); // NOSONAR - Idiomatic Win32
|
||||
if (UINT len = 0; !VerQueryValueA(versionInfo.data(), "\\", lplpFileInfo, &len)) {
|
||||
errorMessageBox("Failed to get the version information for Microsoft Visual C++ Runtime.");
|
||||
errorMessageBox("Failed to query file version info for MSVC runtime.");
|
||||
abort();
|
||||
}
|
||||
|
||||
@ -562,14 +510,42 @@ void ArchMiscWindows::guardRuntimeVersion() // NOSONAR - `noreturn` is not avail
|
||||
const auto currentMinor = LOWORD(fileInfo->dwFileVersionMS);
|
||||
const auto currentBuild = HIWORD(fileInfo->dwFileVersionLS);
|
||||
|
||||
if (currentMajor < kRequiredMajor || currentMinor < kRequiredMinor) {
|
||||
MS_LOG_DEBUG("msvc runtime dll version: %d.%d.%d", currentMajor, currentMinor, currentBuild);
|
||||
|
||||
if (currentMajor < kWindowsRuntimeMajor || currentMinor < kWindowsRuntimeMinor) {
|
||||
const auto message = deskflow::string::sprintf(
|
||||
"Installed Microsoft Visual C++ Runtime v%d.%d.%d is outdated.\n\n"
|
||||
"Minimum required version: v%d.%d\n\n"
|
||||
"Please update to the latest Microsoft Visual C++ Redistributable.",
|
||||
currentMajor, currentMinor, currentBuild, kRequiredMajor, kRequiredMinor
|
||||
currentMajor, currentMinor, currentBuild, kWindowsRuntimeMajor, kWindowsRuntimeMinor
|
||||
);
|
||||
MessageBoxA(nullptr, message.c_str(), "Dependency Error", MB_ICONERROR | MB_OK);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
bool ArchMiscWindows::isProcessElevated()
|
||||
{
|
||||
LOG_DEBUG("checking if process is elevated");
|
||||
|
||||
HANDLE hToken = nullptr;
|
||||
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)) {
|
||||
throw XArch(new XArchEvalWindows());
|
||||
}
|
||||
|
||||
TOKEN_ELEVATION elevation;
|
||||
|
||||
try {
|
||||
DWORD dwSize = sizeof(TOKEN_ELEVATION);
|
||||
if (!GetTokenInformation(hToken, TokenElevation, &elevation, sizeof(elevation), &dwSize)) {
|
||||
throw XArch(new XArchEvalWindows());
|
||||
}
|
||||
} catch (...) {
|
||||
CloseHandle(hToken);
|
||||
throw;
|
||||
}
|
||||
|
||||
const auto isElevated = elevation.TokenIsElevated;
|
||||
LOG_DEBUG("process is %s", isElevated ? "elevated" : "not elevated");
|
||||
return isElevated;
|
||||
}
|
||||
|
||||
@ -7,7 +7,6 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/stdset.h"
|
||||
#include <string>
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
@ -15,6 +14,8 @@
|
||||
|
||||
#include <Tlhelp32.h>
|
||||
|
||||
#include <functional>
|
||||
|
||||
//! Miscellaneous win32 functions.
|
||||
class ArchMiscWindows
|
||||
{
|
||||
@ -34,26 +35,11 @@ public:
|
||||
kDISPLAY = 0x0002
|
||||
};
|
||||
|
||||
typedef int (*RunFunc)(void);
|
||||
using RunFunc = std::function<int(void)>;
|
||||
|
||||
//! Initialize
|
||||
static void init();
|
||||
|
||||
//! Delete memory
|
||||
static void cleanup();
|
||||
|
||||
//! Set the application icons
|
||||
/*!
|
||||
Set the application icons.
|
||||
*/
|
||||
static void setIcons(HICON largeIcon, HICON smallIcon);
|
||||
|
||||
//! Get the application icons
|
||||
/*!
|
||||
Get the application icons.
|
||||
*/
|
||||
static void getIcons(HICON &largeIcon, HICON &smallIcon);
|
||||
|
||||
//! Run the daemon
|
||||
/*!
|
||||
Delegates to ArchDaemonWindows.
|
||||
@ -96,15 +82,6 @@ public:
|
||||
//! Delete a key (which should have no subkeys)
|
||||
static void deleteKey(HKEY parent, const TCHAR *name);
|
||||
|
||||
//! Delete a value
|
||||
static void deleteValue(HKEY parent, const TCHAR *name);
|
||||
|
||||
//! Delete a tree of keys from the registry
|
||||
static void deleteKeyTree(HKEY parent, const TCHAR *name);
|
||||
|
||||
//! Test if a value exists
|
||||
static bool hasValue(HKEY key, const TCHAR *name);
|
||||
|
||||
//! Get type of value
|
||||
static EValueType typeOfValue(HKEY key, const TCHAR *name);
|
||||
|
||||
@ -114,34 +91,12 @@ public:
|
||||
//! Set a DWORD value in the registry
|
||||
static void setValue(HKEY key, const TCHAR *name, DWORD value);
|
||||
|
||||
//! Set a BINARY value in the registry
|
||||
/*!
|
||||
Sets the \p name value of \p key to \p value.data().
|
||||
*/
|
||||
static void setValueBinary(HKEY key, const TCHAR *name, const std::string &value);
|
||||
|
||||
//! Read a string value from the registry
|
||||
static std::string readValueString(HKEY, const TCHAR *name);
|
||||
|
||||
//! Read a DWORD value from the registry
|
||||
static DWORD readValueInt(HKEY, const TCHAR *name);
|
||||
|
||||
//! Read a BINARY value from the registry
|
||||
static std::string readValueBinary(HKEY, const TCHAR *name);
|
||||
|
||||
//! Add a dialog
|
||||
static void addDialog(HWND);
|
||||
|
||||
//! Remove a dialog
|
||||
static void removeDialog(HWND);
|
||||
|
||||
//! Process dialog message
|
||||
/*!
|
||||
Checks if the message is destined for a dialog. If so the message
|
||||
is passed to the dialog and returns true, otherwise returns false.
|
||||
*/
|
||||
static bool processDialog(MSG *);
|
||||
|
||||
//! Disable power saving
|
||||
static void addBusyState(DWORD busyModes);
|
||||
|
||||
@ -160,13 +115,21 @@ public:
|
||||
//! Prevent hard to troubleshoot errors, e.g. access violations.
|
||||
static void guardRuntimeVersion();
|
||||
|
||||
//! Gets the window instance saved at program start.
|
||||
/*!
|
||||
e.g. Used by `GetModuleFileName` which is used when installing the daemon.
|
||||
*/
|
||||
static HINSTANCE instanceWin32();
|
||||
|
||||
//! Saves the window instance for later use.
|
||||
static void setInstanceWin32(HINSTANCE instance);
|
||||
static BOOL WINAPI getProcessEntry(PROCESSENTRY32 &entry, DWORD processID);
|
||||
static BOOL WINAPI getSelfProcessEntry(PROCESSENTRY32 &entry);
|
||||
static BOOL WINAPI getParentProcessEntry(PROCESSENTRY32 &entry);
|
||||
|
||||
//! Get the name of the active input desktop.
|
||||
static std::string getActiveDesktopName();
|
||||
|
||||
//! Returns true if the process is running with elevated privileges (i.e. as admin).
|
||||
static bool isProcessElevated();
|
||||
|
||||
private:
|
||||
//! Open and return a registry key, closing the parent key
|
||||
static HKEY openKey(HKEY parent, const TCHAR *child, bool create);
|
||||
@ -180,15 +143,29 @@ private:
|
||||
//! Set thread busy state
|
||||
static void setThreadExecutionState(DWORD);
|
||||
|
||||
//! Dummy function for thread execution state
|
||||
static DWORD WINAPI dummySetThreadExecutionState(DWORD);
|
||||
|
||||
//! Iterates over the process snapshot to find a process entry
|
||||
static BOOL WINAPI getProcessEntry(PROCESSENTRY32 &entry, DWORD processID);
|
||||
|
||||
//! Calls `getProcessEntry` with the current process ID
|
||||
static BOOL WINAPI getSelfProcessEntry(PROCESSENTRY32 &entry);
|
||||
|
||||
//! Calls `getProcessEntry` with the parent process ID
|
||||
static BOOL WINAPI getParentProcessEntry(PROCESSENTRY32 &entry);
|
||||
|
||||
//! Searches the loaded modules and returns the matching module handle
|
||||
/**
|
||||
* @param moduleNames Provide two module names to search for both release and debug versions.
|
||||
*/
|
||||
static HMODULE findLoadedModule(std::array<const char *, 2> moduleNames);
|
||||
|
||||
private:
|
||||
using Dialogs = std::set<HWND>;
|
||||
typedef DWORD(WINAPI *STES_t)(DWORD);
|
||||
|
||||
static Dialogs *s_dialogs;
|
||||
static DWORD s_busyState;
|
||||
static STES_t s_stes;
|
||||
static STES_t s_stes; // STES: Set thread execution state
|
||||
static HICON s_largeIcon;
|
||||
static HICON s_smallIcon;
|
||||
static HINSTANCE s_instanceWin32;
|
||||
|
||||
@ -8,7 +8,8 @@
|
||||
#pragma once
|
||||
|
||||
#include "arch/IArchMultithread.h"
|
||||
#include "common/stdlist.h"
|
||||
|
||||
#include <list>
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <Windows.h>
|
||||
|
||||
@ -1,111 +0,0 @@
|
||||
/*
|
||||
* Deskflow -- mouse and keyboard sharing utility
|
||||
* SPDX-FileCopyrightText: (C) 2012 - 2016 Symless Ltd.
|
||||
* SPDX-FileCopyrightText: (C) 2004 Chris Schoeneman
|
||||
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
|
||||
*/
|
||||
|
||||
#include "arch/win32/ArchSystemWindows.h"
|
||||
#include "arch/win32/ArchMiscWindows.h"
|
||||
|
||||
#include "arch/XArch.h"
|
||||
#include "base/Log.h"
|
||||
#include "common/constants.h"
|
||||
|
||||
#include "tchar.h"
|
||||
#include <string>
|
||||
|
||||
#include <psapi.h>
|
||||
#include <windows.h>
|
||||
|
||||
static const TCHAR *s_settingsKeyNames[] = {_T("SOFTWARE"), _T(kAppName), NULL};
|
||||
|
||||
//
|
||||
// ArchSystemWindows
|
||||
//
|
||||
|
||||
ArchSystemWindows::ArchSystemWindows()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
ArchSystemWindows::~ArchSystemWindows()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
std::string ArchSystemWindows::getOSName() const
|
||||
{
|
||||
std::string osName("Microsoft Windows <unknown>");
|
||||
static const TCHAR *const windowsVersionKeyNames[] = {
|
||||
_T("SOFTWARE"), _T("Microsoft"), _T("Windows NT"), _T("CurrentVersion"), NULL
|
||||
};
|
||||
|
||||
HKEY key = ArchMiscWindows::openKey(HKEY_LOCAL_MACHINE, windowsVersionKeyNames);
|
||||
if (key == NULL) {
|
||||
return osName;
|
||||
}
|
||||
|
||||
std::string productName = ArchMiscWindows::readValueString(key, "ProductName");
|
||||
if (osName.empty()) {
|
||||
return osName;
|
||||
}
|
||||
|
||||
return "Microsoft " + productName;
|
||||
}
|
||||
|
||||
std::string ArchSystemWindows::getPlatformName() const
|
||||
{
|
||||
#ifdef _X86_
|
||||
if (isWOW64())
|
||||
return "x86 (WOW64)";
|
||||
else
|
||||
return "x86";
|
||||
#else
|
||||
#ifdef _AMD64_
|
||||
return "x64";
|
||||
#else
|
||||
return "Unknown";
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string ArchSystemWindows::setting(const std::string &valueName) const
|
||||
{
|
||||
HKEY key = ArchMiscWindows::openKey(HKEY_LOCAL_MACHINE, s_settingsKeyNames);
|
||||
if (key == NULL)
|
||||
return "";
|
||||
|
||||
return ArchMiscWindows::readValueString(key, valueName.c_str());
|
||||
}
|
||||
|
||||
void ArchSystemWindows::setting(const std::string &valueName, const std::string &valueString) const
|
||||
{
|
||||
HKEY key = ArchMiscWindows::addKey(HKEY_LOCAL_MACHINE, s_settingsKeyNames);
|
||||
if (key == NULL)
|
||||
throw XArch(std::string("could not access registry key: ") + valueName);
|
||||
ArchMiscWindows::setValue(key, valueName.c_str(), valueString.c_str());
|
||||
}
|
||||
|
||||
void ArchSystemWindows::clearSettings() const
|
||||
{
|
||||
ArchMiscWindows::deleteKeyTree(HKEY_LOCAL_MACHINE, kWindowsRegistryKey);
|
||||
}
|
||||
|
||||
bool ArchSystemWindows::isWOW64() const
|
||||
{
|
||||
#if WINVER >= _WIN32_WINNT_WINXP
|
||||
typedef BOOL(WINAPI * LPFN_ISWOW64PROCESS)(HANDLE, PBOOL);
|
||||
HMODULE hModule = GetModuleHandle(TEXT("kernel32"));
|
||||
if (!hModule)
|
||||
return FALSE;
|
||||
|
||||
LPFN_ISWOW64PROCESS fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(hModule, "IsWow64Process");
|
||||
|
||||
BOOL bIsWow64 = FALSE;
|
||||
if (NULL != fnIsWow64Process && fnIsWow64Process(GetCurrentProcess(), &bIsWow64) && bIsWow64) {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
@ -1,29 +0,0 @@
|
||||
/*
|
||||
* Deskflow -- mouse and keyboard sharing utility
|
||||
* SPDX-FileCopyrightText: (C) 2012 - 2016 Symless Ltd.
|
||||
* SPDX-FileCopyrightText: (C) 2004 Chris Schoeneman
|
||||
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "arch/IArchSystem.h"
|
||||
|
||||
#define ARCH_SYSTEM ArchSystemWindows
|
||||
|
||||
//! Win32 implementation of IArchString
|
||||
class ArchSystemWindows : public IArchSystem
|
||||
{
|
||||
public:
|
||||
ArchSystemWindows();
|
||||
virtual ~ArchSystemWindows();
|
||||
|
||||
// IArchSystem overrides
|
||||
virtual std::string getOSName() const;
|
||||
virtual std::string getPlatformName() const;
|
||||
virtual std::string setting(const std::string &valueName) const;
|
||||
virtual void setting(const std::string &valueName, const std::string &valueString) const;
|
||||
virtual void clearSettings() const;
|
||||
|
||||
bool isWOW64() const;
|
||||
};
|
||||
@ -41,92 +41,166 @@ std::string XArchEvalWinsock::eval() const throw()
|
||||
{
|
||||
int m_code;
|
||||
const char *m_msg;
|
||||
} s_netErrorCodes[] = {
|
||||
/* 10004 */ {WSAEINTR, "The (blocking) call was canceled via WSACancelBlockingCall"},
|
||||
/* 10009 */ {WSAEBADF, "Bad file handle"},
|
||||
/* 10013 */
|
||||
{WSAEACCES, "The requested address is a broadcast address, but the "
|
||||
"appropriate flag was not set"},
|
||||
/* 10014 */ {WSAEFAULT, "WSAEFAULT"},
|
||||
/* 10022 */ {WSAEINVAL, "WSAEINVAL"},
|
||||
/* 10024 */ {WSAEMFILE, "No more file descriptors available"},
|
||||
/* 10035 */
|
||||
{WSAEWOULDBLOCK, "Socket is marked as non-blocking and no connections "
|
||||
"are present or the receive operation would block"},
|
||||
/* 10036 */
|
||||
}
|
||||
|
||||
s_netErrorCodes[] = {
|
||||
|
||||
// 10004
|
||||
{WSAEINTR, "The (blocking) call was canceled via WSACancelBlockingCall"},
|
||||
|
||||
// 10009
|
||||
{WSAEBADF, "Bad file handle"},
|
||||
|
||||
// 10013
|
||||
{WSAEACCES, "The requested address is a broadcast address, but the appropriate flag was not set"},
|
||||
|
||||
// 10014
|
||||
{WSAEFAULT, "WSAEFAULT"},
|
||||
|
||||
// 10022
|
||||
{WSAEINVAL, "WSAEINVAL"},
|
||||
|
||||
// 10024
|
||||
{WSAEMFILE, "No more file descriptors available"},
|
||||
|
||||
// 10035
|
||||
{WSAEWOULDBLOCK,
|
||||
"Socket is marked as non-blocking and no connections are present or the receive operation would block"},
|
||||
|
||||
// 10036
|
||||
{WSAEINPROGRESS, "A blocking Windows Sockets operation is in progress"},
|
||||
/* 10037 */
|
||||
|
||||
// 10037
|
||||
{WSAEALREADY, "The asynchronous routine being canceled has already completed"},
|
||||
/* 10038 */ {WSAENOTSOCK, "At least on descriptor is not a socket"},
|
||||
/* 10039 */ {WSAEDESTADDRREQ, "A destination address is required"},
|
||||
/* 10040 */
|
||||
{WSAEMSGSIZE, "The datagram was too large to fit into the specified "
|
||||
"buffer and was truncated"},
|
||||
/* 10041 */
|
||||
|
||||
// 10038
|
||||
{WSAENOTSOCK, "At least on descriptor is not a socket"},
|
||||
|
||||
// 10039
|
||||
{WSAEDESTADDRREQ, "A destination address is required"},
|
||||
|
||||
// 10040
|
||||
{WSAEMSGSIZE, "The datagram was too large to fit into the specified buffer and was truncated"},
|
||||
|
||||
// 10041
|
||||
{WSAEPROTOTYPE, "The specified protocol is the wrong type for this socket"},
|
||||
/* 10042 */ {WSAENOPROTOOPT, "The option is unknown or unsupported"},
|
||||
/* 10043 */
|
||||
|
||||
// 10042
|
||||
{WSAENOPROTOOPT, "The option is unknown or unsupported"},
|
||||
|
||||
// 10043
|
||||
{WSAEPROTONOSUPPORT, "The specified protocol is not supported"},
|
||||
/* 10044 */
|
||||
|
||||
// 10044
|
||||
{WSAESOCKTNOSUPPORT, "The specified socket type is not supported by this address family"},
|
||||
/* 10045 */
|
||||
|
||||
// 10045
|
||||
{WSAEOPNOTSUPP, "The referenced socket is not a type that supports that operation"},
|
||||
/* 10046 */ {WSAEPFNOSUPPORT, "BSD: Protocol family not supported"},
|
||||
/* 10047 */
|
||||
|
||||
// 10046
|
||||
{WSAEPFNOSUPPORT, "BSD: Protocol family not supported"},
|
||||
|
||||
// 10047
|
||||
{WSAEAFNOSUPPORT, "The specified address family is not supported"},
|
||||
/* 10048 */ {WSAEADDRINUSE, "The specified address is already in use"},
|
||||
/* 10049 */
|
||||
|
||||
// 10048
|
||||
{WSAEADDRINUSE, "The specified address is already in use"},
|
||||
|
||||
// 10049
|
||||
{WSAEADDRNOTAVAIL, "The specified address is not available from the local machine"},
|
||||
/* 10050 */
|
||||
{WSAENETDOWN, "The Windows Sockets implementation has detected that the "
|
||||
"network subsystem has failed"},
|
||||
/* 10051 */
|
||||
|
||||
// 10050
|
||||
{WSAENETDOWN, "The Windows Sockets implementation has detected that the network subsystem has failed"},
|
||||
|
||||
// 10051
|
||||
{WSAENETUNREACH, "The network can't be reached from this host at this time"},
|
||||
/* 10052 */
|
||||
{WSAENETRESET, "The connection must be reset because the Windows Sockets "
|
||||
"implementation dropped it"},
|
||||
/* 10053 */
|
||||
|
||||
// 10052
|
||||
{WSAENETRESET, "The connection must be reset because the Windows Sockets implementation dropped it"},
|
||||
|
||||
// 10053
|
||||
{WSAECONNABORTED, "The virtual circuit was aborted due to timeout or other failure"},
|
||||
/* 10054 */
|
||||
|
||||
// 10054
|
||||
{WSAECONNRESET, "The virtual circuit was reset by the remote side"},
|
||||
/* 10055 */
|
||||
{WSAENOBUFS, "No buffer space is available or a buffer deadlock has "
|
||||
"occured. The socket cannot be created"},
|
||||
/* 10056 */ {WSAEISCONN, "The socket is already connected"},
|
||||
/* 10057 */ {WSAENOTCONN, "The socket is not connected"},
|
||||
/* 10058 */ {WSAESHUTDOWN, "The socket has been shutdown"},
|
||||
/* 10059 */ {WSAETOOMANYREFS, "BSD: Too many references"},
|
||||
/* 10060 */
|
||||
|
||||
// 10055
|
||||
{WSAENOBUFS, "No buffer space is available or a buffer deadlock has occurred. The socket cannot be created"},
|
||||
|
||||
// 10056
|
||||
{WSAEISCONN, "The socket is already connected"},
|
||||
|
||||
// 10057
|
||||
{WSAENOTCONN, "The socket is not connected"},
|
||||
|
||||
// 10058
|
||||
{WSAESHUTDOWN, "The socket has been shutdown"},
|
||||
|
||||
// 10059
|
||||
{WSAETOOMANYREFS, "BSD: Too many references"},
|
||||
|
||||
// 10060
|
||||
{WSAETIMEDOUT, "Attempt to connect timed out without establishing a connection"},
|
||||
/* 10061 */ {WSAECONNREFUSED, "Connection was refused"},
|
||||
/* 10062 */ {WSAELOOP, "Undocumented WinSock error code used in BSD"},
|
||||
/* 10063 */
|
||||
|
||||
// 10061
|
||||
{WSAECONNREFUSED, "Connection was refused"},
|
||||
|
||||
// 10062
|
||||
{WSAELOOP, "Undocumented WinSock error code used in BSD"},
|
||||
|
||||
// 10063
|
||||
{WSAENAMETOOLONG, "Undocumented WinSock error code used in BSD"},
|
||||
/* 10064 */ {WSAEHOSTDOWN, "Undocumented WinSock error code used in BSD"},
|
||||
/* 10065 */ {WSAEHOSTUNREACH, "No route to host"},
|
||||
/* 10066 */ {WSAENOTEMPTY, "Undocumented WinSock error code"},
|
||||
/* 10067 */ {WSAEPROCLIM, "Undocumented WinSock error code"},
|
||||
/* 10068 */ {WSAEUSERS, "Undocumented WinSock error code"},
|
||||
/* 10069 */ {WSAEDQUOT, "Undocumented WinSock error code"},
|
||||
/* 10070 */ {WSAESTALE, "Undocumented WinSock error code"},
|
||||
/* 10071 */ {WSAEREMOTE, "Undocumented WinSock error code"},
|
||||
/* 10091 */
|
||||
|
||||
// 10064
|
||||
{WSAEHOSTDOWN, "Undocumented WinSock error code used in BSD"},
|
||||
|
||||
// 10065
|
||||
{WSAEHOSTUNREACH, "No route to host"},
|
||||
|
||||
// 10066
|
||||
{WSAENOTEMPTY, "Undocumented WinSock error code"},
|
||||
|
||||
// 10067
|
||||
{WSAEPROCLIM, "Undocumented WinSock error code"},
|
||||
|
||||
// 10068
|
||||
{WSAEUSERS, "Undocumented WinSock error code"},
|
||||
|
||||
// 10069
|
||||
{WSAEDQUOT, "Undocumented WinSock error code"},
|
||||
|
||||
// 10070
|
||||
{WSAESTALE, "Undocumented WinSock error code"},
|
||||
|
||||
// 10071
|
||||
{WSAEREMOTE, "Undocumented WinSock error code"},
|
||||
|
||||
// 10091
|
||||
{WSASYSNOTREADY, "Underlying network subsytem is not ready for network communication"},
|
||||
/* 10092 */
|
||||
{WSAVERNOTSUPPORTED, "The version of WinSock API support requested is "
|
||||
"not provided in this implementation"},
|
||||
/* 10093 */
|
||||
|
||||
// 10092
|
||||
{WSAVERNOTSUPPORTED, "The version of WinSock API support requested is not provided in this implementation"},
|
||||
|
||||
// 10093
|
||||
{WSANOTINITIALISED, "WinSock subsystem not properly initialized"},
|
||||
/* 10101 */
|
||||
|
||||
// 10101
|
||||
{WSAEDISCON, "Virtual circuit has gracefully terminated connection"},
|
||||
/* 11001 */ {WSAHOST_NOT_FOUND, "The specified host is unknown"},
|
||||
/* 11002 */
|
||||
|
||||
// 11001
|
||||
{WSAHOST_NOT_FOUND, "The specified host is unknown"},
|
||||
|
||||
// 11002
|
||||
{WSATRY_AGAIN, "A temporary error occurred on an authoritative name server"},
|
||||
/* 11003 */
|
||||
|
||||
// 11003
|
||||
{WSANO_RECOVERY, "A non-recoverable name server error occurred"},
|
||||
/* 11004 */
|
||||
|
||||
// 11004
|
||||
{WSANO_DATA, "The requested name is valid but does not have an IP address"},
|
||||
/* end */ {0, NULL}
|
||||
|
||||
// end
|
||||
{0, NULL}
|
||||
};
|
||||
|
||||
for (unsigned int i = 0; s_netErrorCodes[i].m_code != 0; ++i) {
|
||||
|
||||
@ -11,7 +11,7 @@ add_library(base STATIC
|
||||
EventQueue.h
|
||||
EventTypes.cpp
|
||||
EventTypes.h
|
||||
finally.h
|
||||
FinalAction.h
|
||||
FunctionEventJob.cpp
|
||||
FunctionEventJob.h
|
||||
FunctionJob.cpp
|
||||
@ -21,8 +21,8 @@ add_library(base STATIC
|
||||
IEventQueueBuffer.h
|
||||
IJob.h
|
||||
ILogOutputter.h
|
||||
log_outputters.cpp
|
||||
log_outputters.h
|
||||
LogOutputters.cpp
|
||||
LogOutputters.h
|
||||
Log.cpp
|
||||
Log.h
|
||||
Path.cpp
|
||||
|
||||
@ -7,8 +7,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/common.h"
|
||||
#include "common/stdmap.h"
|
||||
#include "common/Common.h"
|
||||
|
||||
class EventData
|
||||
{
|
||||
|
||||
@ -11,7 +11,6 @@
|
||||
#include "base/IEventJob.h"
|
||||
#include "base/Log.h"
|
||||
#include "base/SimpleEventQueueBuffer.h"
|
||||
#include "base/Stopwatch.h"
|
||||
#include "mt/Lock.h"
|
||||
#include "mt/Mutex.h"
|
||||
|
||||
|
||||
@ -7,17 +7,15 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "arch/IArchMultithread.h"
|
||||
#include "base/Event.h"
|
||||
#include "base/EventTypes.h"
|
||||
#include "base/IEventQueue.h"
|
||||
#include "base/PriorityQueue.h"
|
||||
#include "base/Stopwatch.h"
|
||||
#include "common/stdmap.h"
|
||||
#include "common/stdset.h"
|
||||
#include "mt/CondVar.h"
|
||||
|
||||
#include <map>
|
||||
#include <queue>
|
||||
#include <set>
|
||||
|
||||
class Mutex;
|
||||
|
||||
|
||||
@ -8,7 +8,6 @@
|
||||
#include "base/IEventQueue.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
|
||||
EventTypes::EventTypes() : m_events(NULL)
|
||||
{
|
||||
@ -160,7 +159,7 @@ REGISTER_EVENT(Clipboard, clipboardSending)
|
||||
//
|
||||
|
||||
REGISTER_EVENT(File, fileChunkSending)
|
||||
REGISTER_EVENT(File, fileRecieveCompleted)
|
||||
REGISTER_EVENT(File, fileReceiveCompleted)
|
||||
REGISTER_EVENT(File, keepAlive)
|
||||
|
||||
//
|
||||
|
||||
@ -673,7 +673,7 @@ class FileEvents : public EventTypes
|
||||
public:
|
||||
FileEvents()
|
||||
: m_fileChunkSending(Event::kUnknown),
|
||||
m_fileRecieveCompleted(Event::kUnknown),
|
||||
m_fileReceiveCompleted(Event::kUnknown),
|
||||
m_keepAlive(Event::kUnknown)
|
||||
{
|
||||
}
|
||||
@ -685,7 +685,7 @@ public:
|
||||
Event::Type fileChunkSending();
|
||||
|
||||
//! Completed receiving a file
|
||||
Event::Type fileRecieveCompleted();
|
||||
Event::Type fileReceiveCompleted();
|
||||
|
||||
//! Send a keep alive
|
||||
Event::Type keepAlive();
|
||||
@ -694,7 +694,7 @@ public:
|
||||
|
||||
private:
|
||||
Event::Type m_fileChunkSending;
|
||||
Event::Type m_fileRecieveCompleted;
|
||||
Event::Type m_fileReceiveCompleted;
|
||||
Event::Type m_keepAlive;
|
||||
};
|
||||
|
||||
|
||||
@ -7,8 +7,6 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <utility>
|
||||
|
||||
namespace deskflow {
|
||||
|
||||
/**
|
||||
@ -7,8 +7,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/Common.h"
|
||||
#include "common/IInterface.h"
|
||||
#include "common/common.h"
|
||||
|
||||
class Event;
|
||||
class EventQueueTimer;
|
||||
|
||||
@ -7,8 +7,8 @@
|
||||
|
||||
#include "base/Log.h"
|
||||
#include "arch/Arch.h"
|
||||
#include "base/log_outputters.h"
|
||||
#include "common/constants.h"
|
||||
#include "base/LogOutputters.h"
|
||||
#include "common/Constants.h"
|
||||
|
||||
#include <cstdarg>
|
||||
#include <cstdint>
|
||||
|
||||
@ -9,10 +9,7 @@
|
||||
|
||||
#include "arch/Arch.h"
|
||||
#include "arch/IArchMultithread.h"
|
||||
#include "common/common.h"
|
||||
#include "common/stdlist.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
#include "common/Common.h"
|
||||
|
||||
#define CLOG (Log::getInstance())
|
||||
#define BYE "\nTry `%s --help' for more information."
|
||||
|
||||
@ -6,11 +6,10 @@
|
||||
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
|
||||
*/
|
||||
|
||||
#include "base/log_outputters.h"
|
||||
#include "base/LogOutputters.h"
|
||||
#include "arch/Arch.h"
|
||||
#include "base/Path.h"
|
||||
#include "base/String.h"
|
||||
#include "base/TMethodJob.h"
|
||||
|
||||
#include <fstream>
|
||||
|
||||
@ -9,14 +9,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "base/ILogOutputter.h"
|
||||
#include "common/common.h"
|
||||
#include "common/stddeque.h"
|
||||
#include "common/Common.h"
|
||||
#include "mt/Thread.h"
|
||||
|
||||
#include <fstream>
|
||||
#include <list>
|
||||
#include <string>
|
||||
|
||||
//! Stop traversing log chain outputter
|
||||
/*!
|
||||
This outputter performs no output and returns false from \c write(),
|
||||
@ -6,7 +6,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <common/common.h>
|
||||
#include "common/Common.h"
|
||||
#include <string>
|
||||
|
||||
namespace deskflow {
|
||||
|
||||
@ -7,10 +7,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/stdvector.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
|
||||
//! A priority queue with an iterator
|
||||
/*!
|
||||
|
||||
@ -9,8 +9,8 @@
|
||||
|
||||
#include "arch/IArchMultithread.h"
|
||||
#include "base/IEventQueueBuffer.h"
|
||||
#include "common/stddeque.h"
|
||||
|
||||
#include <deque>
|
||||
//! In-memory event queue buffer
|
||||
/*!
|
||||
An event queue buffer provides a queue of events for an IEventQueue.
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/common.h"
|
||||
#include "common/Common.h"
|
||||
|
||||
//! A timer class
|
||||
/*!
|
||||
|
||||
@ -7,20 +7,11 @@
|
||||
*/
|
||||
|
||||
#include "base/String.h"
|
||||
#include "common/stdvector.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <cerrno>
|
||||
#include <cstdarg>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
|
||||
namespace deskflow {
|
||||
namespace string {
|
||||
@ -147,26 +138,6 @@ std::string sprintf(const char *fmt, ...)
|
||||
return result;
|
||||
}
|
||||
|
||||
void findReplaceAll(std::string &subject, const std::string &find, const std::string &replace)
|
||||
{
|
||||
size_t pos = 0;
|
||||
while ((pos = subject.find(find, pos)) != std::string::npos) {
|
||||
subject.replace(pos, find.length(), replace);
|
||||
pos += replace.length();
|
||||
}
|
||||
}
|
||||
|
||||
std::string removeFileExt(std::string filename)
|
||||
{
|
||||
size_t dot = filename.find_last_of('.');
|
||||
|
||||
if (dot == std::string::npos) {
|
||||
return filename;
|
||||
}
|
||||
|
||||
return filename.substr(0, dot);
|
||||
}
|
||||
|
||||
std::string toHex(const std::string &subject, int width, const char fill)
|
||||
{
|
||||
std::stringstream ss;
|
||||
@ -253,11 +224,6 @@ void uppercase(std::string &subject)
|
||||
std::transform(subject.begin(), subject.end(), subject.begin(), ::toupper);
|
||||
}
|
||||
|
||||
void removeChar(std::string &subject, const char c)
|
||||
{
|
||||
subject.erase(std::remove(subject.begin(), subject.end(), c), subject.end());
|
||||
}
|
||||
|
||||
std::string sizeTypeToString(size_t n)
|
||||
{
|
||||
std::stringstream ss;
|
||||
@ -273,27 +239,6 @@ size_t stringToSizeType(std::string string)
|
||||
return value;
|
||||
}
|
||||
|
||||
std::vector<std::string> splitString(std::string string, const char c)
|
||||
{
|
||||
std::vector<std::string> results;
|
||||
|
||||
size_t head = 0;
|
||||
size_t separator = string.find(c);
|
||||
while (separator != std::string::npos) {
|
||||
if (head != separator) {
|
||||
results.push_back(string.substr(head, separator - head));
|
||||
}
|
||||
head = separator + 1;
|
||||
separator = string.find(c, head);
|
||||
}
|
||||
|
||||
if (head < string.size()) {
|
||||
results.push_back(string.substr(head, string.size() - head));
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
//
|
||||
// CaselessCmp
|
||||
//
|
||||
@ -319,11 +264,5 @@ bool CaselessCmp::cmpLess(const std::string::value_type &a, const std::string::v
|
||||
return tolower(a) < tolower(b);
|
||||
}
|
||||
|
||||
bool CaselessCmp::cmpEqual(const std::string::value_type &a, const std::string::value_type &b)
|
||||
{
|
||||
// should use std::tolower but not in all versions of libstdc++ have it
|
||||
return tolower(a) == tolower(b);
|
||||
}
|
||||
|
||||
} // namespace string
|
||||
} // namespace deskflow
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user