Compare commits
88 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| abaf233a07 | |||
| b251c98a4e | |||
| 23c8496e24 | |||
| 18220a7847 | |||
| a26698c377 | |||
| ac8cc42b7a | |||
| 7126f31d3f | |||
| 44db410dad | |||
| bc7b1082e7 | |||
| ea0bf9d56d | |||
| 6657bdd9b1 | |||
| 11871d343d | |||
| 12cf55d4fc | |||
| e4cf1392c9 | |||
| f2a54f4af0 | |||
| fce1a37e97 | |||
| 90e79dad75 | |||
| 8f8874370e | |||
| 3d67865ffc | |||
| 22a303842e | |||
| c20671f1db | |||
| 844dac439a | |||
| 5e781e6095 | |||
| 2b379b31cd | |||
| 8bb23179c4 | |||
| a8588ab507 | |||
| c80cd56f27 | |||
| 7743d9008d | |||
| 2ecf91e50a | |||
| d8c7367900 | |||
| 8a53b4bc8e | |||
| fc1f3b0142 | |||
| 814d63af28 | |||
| a9bfcf3c81 | |||
| fb8104ff86 | |||
| a0a28e7a94 | |||
| 9188d4b1c1 | |||
| d392547fd8 | |||
| 220bf3178c | |||
| c0692b6fc7 | |||
| 47ed13868f | |||
| 09d4b1a27a | |||
| 4e641adae9 | |||
| 568f5c7fc5 | |||
| a0ac24a42c | |||
| f69bd5601c | |||
| 37728cc7a3 | |||
| b4dbce385c | |||
| 9aeb04b4a6 | |||
| 3db4c60155 | |||
| c37c7e2354 | |||
| 4314159a0b | |||
| 7f4b942817 | |||
| c2342d5124 | |||
| dd55247380 | |||
| fe9407ca33 | |||
| 9376c68739 | |||
| 439541fac1 | |||
| dfae2aaf20 | |||
| 5ea8874583 | |||
| 07de9efe7c | |||
| c791135160 | |||
| 79fdf3a1f6 | |||
| 76353eceb3 | |||
| fb60189078 | |||
| 3c140ed479 | |||
| 5b4dfefcf7 | |||
| 033e5530c3 | |||
| 727d6ff166 | |||
| aa54bd329f | |||
| 692f43d8af | |||
| 263a23fcaa | |||
| bde89d4026 | |||
| b3cecdde7f | |||
| 5534232a1d | |||
| 4c7f546c60 | |||
| 1ca8695659 | |||
| e7363aaf8e | |||
| 6ccef50b7c | |||
| d7fb9bc6d2 | |||
| 41197334f0 | |||
| 74c25fdff6 | |||
| f6348736e8 | |||
| 208556b5aa | |||
| 58963de10f | |||
| 457c31fbaf | |||
| 690d6a67ef | |||
| 094cbadf91 |
18
.github/CODE_OF_CONDUCT.md
vendored
Normal file
18
.github/CODE_OF_CONDUCT.md
vendored
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
# Deskflow Code of Conduct
|
||||||
|
|
||||||
|
## Our Pledge
|
||||||
|
|
||||||
|
We want the Deskflow community to be one where everyone can work together. We pledge to keep our community focused on the project and the code around the project.
|
||||||
|
|
||||||
|
## Community Standards
|
||||||
|
|
||||||
|
* Keep interactions respectful and focused on the project
|
||||||
|
* Contributions are expected to follow the [contribution guide](https://github.com/deskflow/deskflow/wiki/Contributing).
|
||||||
|
|
||||||
|
## Enforcement
|
||||||
|
|
||||||
|
Enforcement will be done at the descression of the Deskflow Moderators.
|
||||||
|
|
||||||
|
1. Warning
|
||||||
|
2. Temporary ban
|
||||||
|
3. Permanent banning
|
||||||
2
README.md → .github/README.md
vendored
2
README.md → .github/README.md
vendored
@ -184,4 +184,4 @@ Deskflow is made by possible by these contributors.
|
|||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
This project is licensed under [GPL-2.0](LICENSE) with an [OpenSSL exception](LICENSES/LicenseRef-OpenSSL-Exception.txt).
|
This project is licensed under [GPL-2.0](LICENSE) with an [OpenSSL exception](../LICENSES/LicenseRef-OpenSSL-Exception.txt).
|
||||||
34
.github/actions/add-kitware-repo/action.yml
vendored
34
.github/actions/add-kitware-repo/action.yml
vendored
@ -1,34 +0,0 @@
|
|||||||
# SPDX-FileCopyrightText: 2024 Chris Rizzitello <sithlord48@gmail.com>
|
|
||||||
# SPDX-License-Identifier: MIT
|
|
||||||
|
|
||||||
name: "Add Kitware repo"
|
|
||||||
description: "Add Kitware repo for Debian-like distros"
|
|
||||||
|
|
||||||
inputs:
|
|
||||||
distro:
|
|
||||||
description: "Ubuntu codename, Kitware uses: noble, jammy, focal"
|
|
||||||
required: true
|
|
||||||
|
|
||||||
runs:
|
|
||||||
using: "composite"
|
|
||||||
|
|
||||||
steps:
|
|
||||||
|
|
||||||
# This mirrors instructions at https://apt.kitware.com
|
|
||||||
- name: Add repo
|
|
||||||
run: |
|
|
||||||
apt update -y -qqq
|
|
||||||
apt install ca-certificates gpg wget -y -qqq
|
|
||||||
|
|
||||||
wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null \
|
|
||||||
| gpg --dearmor - \
|
|
||||||
> /usr/share/keyrings/kitware-archive-keyring.gpg
|
|
||||||
|
|
||||||
echo 'deb [signed-by=/usr/share/keyrings/kitware-archive-keyring.gpg] https://apt.kitware.com/ubuntu/ ${{ inputs.distro }} main' \
|
|
||||||
> /etc/apt/sources.list.d/kitware.list
|
|
||||||
|
|
||||||
apt update -y -qqq
|
|
||||||
env:
|
|
||||||
# Prevent apt prompting for input.
|
|
||||||
DEBIAN_FRONTEND: noninteractive
|
|
||||||
shell: bash
|
|
||||||
25
.github/actions/install-dependencies/action.yml
vendored
25
.github/actions/install-dependencies/action.yml
vendored
@ -30,7 +30,7 @@ runs:
|
|||||||
if: ${{ runner.os != 'Windows' }}
|
if: ${{ runner.os != 'Windows' }}
|
||||||
run: |
|
run: |
|
||||||
if [ "$RUNNER_OS" == "macOS" ]; then
|
if [ "$RUNNER_OS" == "macOS" ]; then
|
||||||
brew install googletest openssl --quiet
|
brew install googletest openssl doxygen --quiet
|
||||||
elif [ "$RUNNER_OS" == "Linux" ]; then
|
elif [ "$RUNNER_OS" == "Linux" ]; then
|
||||||
if [ ${{inputs.like}} == "debian" ]; then
|
if [ ${{inputs.like}} == "debian" ]; then
|
||||||
apt update -qqq > /dev/null
|
apt update -qqq > /dev/null
|
||||||
@ -38,17 +38,17 @@ runs:
|
|||||||
xorg-dev libx11-dev libxtst-dev libssl-dev \
|
xorg-dev libx11-dev libxtst-dev libssl-dev \
|
||||||
libglib2.0-dev libxkbfile-dev qt6-base-dev qt6-tools-dev \
|
libglib2.0-dev libxkbfile-dev qt6-base-dev qt6-tools-dev \
|
||||||
libgtk-3-dev libgtest-dev libgmock-dev \
|
libgtk-3-dev libgtest-dev libgmock-dev \
|
||||||
libei-dev libportal-dev help2man -y >/dev/null
|
libei-dev libportal-dev help2man doxygen -y >/dev/null
|
||||||
elif [ ${{inputs.like}} == "fedora" ]; then
|
elif [ ${{inputs.like}} == "fedora" ]; then
|
||||||
dnf install -y cmake make ninja-build gcc-c++ rpm-build openssl-devel \
|
dnf install -y cmake make ninja-build gcc-c++ rpm-build openssl-devel \
|
||||||
glib2-devel libXtst-devel libxkbfile-devel qt6-qtbase-devel qt6-qttools-devel \
|
glib2-devel libXtst-devel libxkbfile-devel qt6-qtbase-devel qt6-qttools-devel \
|
||||||
gtk3-devel gtest-devel gmock-devel libei-devel libportal-devel help2man
|
gtk3-devel gtest-devel gmock-devel libei-devel libportal-devel help2man doxygen
|
||||||
elif [ ${{inputs.like}} == "suse" ]; then
|
elif [ ${{inputs.like}} == "suse" ]; then
|
||||||
zypper refresh
|
zypper refresh
|
||||||
zypper install -y --force-resolution \
|
zypper install -y --force-resolution \
|
||||||
cmake make ninja gcc-c++ rpm-build libopenssl-devel \
|
cmake make ninja gcc-c++ rpm-build libopenssl-devel \
|
||||||
glib2-devel libXtst-devel libxkbfile-devel qt6-base-devel qt6-tools-devel \
|
glib2-devel libXtst-devel libxkbfile-devel qt6-base-devel qt6-tools-devel \
|
||||||
qt6-linguist-devel gtk3-devel \
|
qt6-linguist-devel gtk3-devel doxygen \
|
||||||
googletest-devel googlemock-devel libei-devel libportal-devel help2man
|
googletest-devel googlemock-devel libei-devel libportal-devel help2man
|
||||||
elif [ ${{ inputs.like }} == "arch" ]; then
|
elif [ ${{ inputs.like }} == "arch" ]; then
|
||||||
pacman -Syu --noconfirm base-devel cmake ninja \
|
pacman -Syu --noconfirm base-devel cmake ninja \
|
||||||
@ -83,6 +83,22 @@ runs:
|
|||||||
token: ${{ github.token }}
|
token: ${{ github.token }}
|
||||||
revision: master
|
revision: master
|
||||||
|
|
||||||
|
- name: Cache Chocolatey
|
||||||
|
id: cache-choco
|
||||||
|
if: (runner.os == 'Windows')
|
||||||
|
uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
C:/ProgramData/chocolatey/bin/
|
||||||
|
C:/ProgramData/chocolatey/lib/doxygen.install
|
||||||
|
C:/Program*/doxygen/
|
||||||
|
key: cache-chocolatey${{ matrix.config.arch }}-doxygen
|
||||||
|
|
||||||
|
- name: Install doxygen (windows)
|
||||||
|
if: ((runner.os == 'Windows') && (steps.cache-choco.outputs.cache-hit != 'true'))
|
||||||
|
shell: bash
|
||||||
|
run: choco install doxygen.install
|
||||||
|
|
||||||
- name: Install Wix
|
- name: Install Wix
|
||||||
if: ${{ runner.os == 'Windows' }}
|
if: ${{ runner.os == 'Windows' }}
|
||||||
run: |
|
run: |
|
||||||
@ -91,3 +107,4 @@ runs:
|
|||||||
wix extension add --global WixToolset.Util.wixext/5.0.2
|
wix extension add --global WixToolset.Util.wixext/5.0.2
|
||||||
wix extension add --global WixToolset.Firewall.wixext/5.0.2
|
wix extension add --global WixToolset.Firewall.wixext/5.0.2
|
||||||
shell: pwsh
|
shell: pwsh
|
||||||
|
|
||||||
|
|||||||
33
.github/actions/winget-publish/action.yaml
vendored
33
.github/actions/winget-publish/action.yaml
vendored
@ -1,33 +0,0 @@
|
|||||||
name: Winget Publish
|
|
||||||
description: A composite action to publish packages to the Windows Package Manager (Winget) repository
|
|
||||||
|
|
||||||
inputs:
|
|
||||||
release-version:
|
|
||||||
description: "Version to publish to Winget package manager (without 'v' prefix)"
|
|
||||||
required: true
|
|
||||||
token:
|
|
||||||
description: "GitHub token with public read permissions on the source repo"
|
|
||||||
required: true
|
|
||||||
|
|
||||||
runs:
|
|
||||||
using: "composite"
|
|
||||||
steps:
|
|
||||||
- name: Submit package to Windows Package Manager Community Repository
|
|
||||||
if: ${{ runner.os == 'Windows' }}
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ inputs.token }}
|
|
||||||
run: |
|
|
||||||
# Download latest wingetcreate
|
|
||||||
Invoke-WebRequest https://aka.ms/wingetcreate/latest -OutFile wingetcreate.exe
|
|
||||||
|
|
||||||
$packageId = "Deskflow.Deskflow"
|
|
||||||
$x64Url = "https://github.com/deskflow/deskflow/releases/download/v${{ inputs.release-version }}/deskflow-${{ inputs.release-version }}-win-x64.msi"
|
|
||||||
$arm64Url = "https://github.com/deskflow/deskflow/releases/download/v${{ inputs.release-version }}/deskflow-${{ inputs.release-version }}-win-arm64.msi"
|
|
||||||
|
|
||||||
# Submit package update
|
|
||||||
.\wingetcreate.exe update "$packageId" `
|
|
||||||
--version "${{ inputs.release-version }}" `
|
|
||||||
--urls "$x64Url|x64" "$arm64Url|arm64"`
|
|
||||||
--submit `
|
|
||||||
--token "${{ inputs.token }}"
|
|
||||||
shell: pwsh
|
|
||||||
46
.github/workflows/continuous-integration.yml
vendored
46
.github/workflows/continuous-integration.yml
vendored
@ -99,7 +99,7 @@ jobs:
|
|||||||
config-args: "-G Ninja"
|
config-args: "-G Ninja"
|
||||||
vcpkg-triplet: x64-windows-release
|
vcpkg-triplet: x64-windows-release
|
||||||
arch: "amd64"
|
arch: "amd64"
|
||||||
qt-version: 6.10.1
|
qt-version: 6.10.2
|
||||||
|
|
||||||
- name: "windows-2022-arm64"
|
- name: "windows-2022-arm64"
|
||||||
runs-on: "windows-11-arm"
|
runs-on: "windows-11-arm"
|
||||||
@ -107,12 +107,12 @@ jobs:
|
|||||||
config-args: "-G Ninja"
|
config-args: "-G Ninja"
|
||||||
vcpkg-triplet: arm64-windows
|
vcpkg-triplet: arm64-windows
|
||||||
arch: "arm64"
|
arch: "arm64"
|
||||||
qt-version: 6.10.1
|
qt-version: 6.10.2
|
||||||
|
|
||||||
- name: "macos-arm64"
|
- name: "macos-arm64"
|
||||||
runs-on: macos-15
|
runs-on: macos-15
|
||||||
timeout: 10
|
timeout: 10
|
||||||
qt-version: 6.10.1
|
qt-version: 6.10.2
|
||||||
config-args: '-DCMAKE_OSX_ARCHITECTURES="arm64" -DCMAKE_OSX_DEPLOYMENT_TARGET=14 -DCMAKE_OSX_SYSROOT=/Applications/Xcode_16.4.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk'
|
config-args: '-DCMAKE_OSX_ARCHITECTURES="arm64" -DCMAKE_OSX_DEPLOYMENT_TARGET=14 -DCMAKE_OSX_SYSROOT=/Applications/Xcode_16.4.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk'
|
||||||
|
|
||||||
- name: "macos-x64"
|
- name: "macos-x64"
|
||||||
@ -268,6 +268,11 @@ jobs:
|
|||||||
- name: Get version
|
- name: Get version
|
||||||
uses: ./.github/actions/get-version
|
uses: ./.github/actions/get-version
|
||||||
|
|
||||||
|
- name: Update Windows Paths
|
||||||
|
if: (runner.os == 'Windows')
|
||||||
|
shell: pwsh
|
||||||
|
run: echo "C:\Program Files\doxygen\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
|
||||||
|
|
||||||
- name: Configure
|
- name: Configure
|
||||||
run: ${{env.CMAKE_CONFIGURE}} ${{ matrix.target.config-args }} ${{ steps.get-deps.outputs.vcpkg-cmake-config }} -DPACKAGE_VERSION_LABEL="${{env.DESKFLOW_PACKAGE_VERSION}}"
|
run: ${{env.CMAKE_CONFIGURE}} ${{ matrix.target.config-args }} ${{ steps.get-deps.outputs.vcpkg-cmake-config }} -DPACKAGE_VERSION_LABEL="${{env.DESKFLOW_PACKAGE_VERSION}}"
|
||||||
|
|
||||||
@ -275,7 +280,21 @@ jobs:
|
|||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
if [[ "${{matrix.target.like}}" != "arch" ]]; then
|
if [[ "${{matrix.target.like}}" != "arch" ]]; then
|
||||||
|
if [ "$RUNNER_OS" != "macOS" ]; then
|
||||||
cmake --build build --config Release -j8 --target package
|
cmake --build build --config Release -j8 --target package
|
||||||
|
else
|
||||||
|
cmake --build build --config Release -j8
|
||||||
|
for i in $(seq 1 5); do
|
||||||
|
cmake --build build --config Release -j8 --target package 2>&1
|
||||||
|
if [ $? -eq 0 ]; then
|
||||||
|
echo "Package successful"
|
||||||
|
break
|
||||||
|
else
|
||||||
|
echo "Package attempt $i failed"
|
||||||
|
sleep 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
else
|
else
|
||||||
cmake --build build --config Release -j8
|
cmake --build build --config Release -j8
|
||||||
useradd -m build
|
useradd -m build
|
||||||
@ -312,7 +331,7 @@ jobs:
|
|||||||
uses: JamesIves/github-pages-deploy-action@v4.7.3
|
uses: JamesIves/github-pages-deploy-action@v4.7.3
|
||||||
with:
|
with:
|
||||||
branch: gh-pages
|
branch: gh-pages
|
||||||
folder: build/doc/dev/html
|
folder: build/docs/dev/html
|
||||||
|
|
||||||
- name: Upload
|
- name: Upload
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
@ -347,7 +366,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
pkg install -y cmake ninja gmake gcc12 openssl glib \
|
pkg install -y cmake ninja gmake gcc12 openssl glib \
|
||||||
libX11 libXtst libxkbfile qt6-base qt6-tools gtk3 \
|
libX11 libXtst libxkbfile qt6-base qt6-tools gtk3 \
|
||||||
googletest pkgconf libei libportal
|
googletest pkgconf libei libportal doxygen
|
||||||
${{env.CMAKE_CONFIGURE}} -G Ninja
|
${{env.CMAKE_CONFIGURE}} -G Ninja
|
||||||
cmake --build build -j16
|
cmake --build build -j16
|
||||||
# Integration tests are flakey by nature, make them optional.
|
# Integration tests are flakey by nature, make them optional.
|
||||||
@ -457,20 +476,3 @@ jobs:
|
|||||||
-H "X-GitHub-Api-Version: 2022-11-28" \
|
-H "X-GitHub-Api-Version: 2022-11-28" \
|
||||||
https://api.github.com/repos/deskflow/homebrew-tap/dispatches \
|
https://api.github.com/repos/deskflow/homebrew-tap/dispatches \
|
||||||
-d '{"event_type":"update_tap"}'
|
-d '{"event_type":"update_tap"}'
|
||||||
|
|
||||||
winget-publish:
|
|
||||||
needs: release
|
|
||||||
if: contains(github.ref, 'tags/v')
|
|
||||||
runs-on: windows-latest
|
|
||||||
steps:
|
|
||||||
- name: Fancy Checkout
|
|
||||||
uses: sithlord48/fancy-checkout@v2
|
|
||||||
|
|
||||||
- name: Get version
|
|
||||||
uses: ./.github/actions/get-version
|
|
||||||
|
|
||||||
- name: Submit
|
|
||||||
uses: ./.github/actions/winget-publish
|
|
||||||
with:
|
|
||||||
release-version: ${{env.DESKFLOW_PACKAGE_VERSION}}
|
|
||||||
token: ${{ secrets.WINGET_DEPLOY_TOKEN }}
|
|
||||||
|
|||||||
@ -99,11 +99,10 @@ message(STATUS "Building ${CMAKE_PROJECT_NAME}-${CMAKE_PROJECT_VERSION}")
|
|||||||
# Set lib versions
|
# Set lib versions
|
||||||
set(REQUIRED_OPENSSL_VERSION 3.0)
|
set(REQUIRED_OPENSSL_VERSION 3.0)
|
||||||
set(REQUIRED_LIBEI_VERSION 1.3)
|
set(REQUIRED_LIBEI_VERSION 1.3)
|
||||||
set(REQUIRED_LIBPORTAL_VERSION 0.8)
|
set(REQUIRED_LIBPORTAL_VERSION 0.9.1)
|
||||||
set(REQUIRED_QT_VERSION 6.7.0)
|
set(REQUIRED_QT_VERSION 6.7.0)
|
||||||
|
|
||||||
if (WIN32)
|
if (WIN32)
|
||||||
add_definitions(-DSYSAPI_WIN32 -DWINAPI_MSWINDOWS)
|
|
||||||
# VSCMD_ARG_TGT_ARCH is set on CI
|
# VSCMD_ARG_TGT_ARCH is set on CI
|
||||||
if ("$ENV{VSCMD_ARG_TGT_ARCH}" STREQUAL "")
|
if ("$ENV{VSCMD_ARG_TGT_ARCH}" STREQUAL "")
|
||||||
# NOT on CI
|
# NOT on CI
|
||||||
@ -162,11 +161,16 @@ endif()
|
|||||||
include(cmake/Libraries.cmake)
|
include(cmake/Libraries.cmake)
|
||||||
configure_libs()
|
configure_libs()
|
||||||
|
|
||||||
|
if(BUILD_OSX_BUNDLE AND APPLE_CODESIGN_DEV)
|
||||||
|
include(cmake/MacCodesign.cmake)
|
||||||
|
endif()
|
||||||
|
|
||||||
# setup install paths
|
# setup install paths
|
||||||
include(GNUInstallDirs)
|
include(GNUInstallDirs)
|
||||||
if (WIN32)
|
if (WIN32)
|
||||||
set(CMAKE_INSTALL_BINDIR .)
|
set(CMAKE_INSTALL_BINDIR .)
|
||||||
set(CMAKE_INSTALL_LIBDIR .)
|
set(CMAKE_INSTALL_LIBDIR .)
|
||||||
|
set(CMAKE_INSTALL_DOCDIR docs)
|
||||||
set(CMAKE_INSTALL_LICENSE_DIR .)
|
set(CMAKE_INSTALL_LICENSE_DIR .)
|
||||||
set(CMAKE_INSTALL_I18N_DIR translations)
|
set(CMAKE_INSTALL_I18N_DIR translations)
|
||||||
elseif(BUILD_OSX_BUNDLE)
|
elseif(BUILD_OSX_BUNDLE)
|
||||||
@ -177,7 +181,7 @@ else()
|
|||||||
set(CMAKE_INSTALL_I18N_DIR ${CMAKE_INSTALL_DATADIR}/${CMAKE_PROJECT_NAME}/translations)
|
set(CMAKE_INSTALL_I18N_DIR ${CMAKE_INSTALL_DATADIR}/${CMAKE_PROJECT_NAME}/translations)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_subdirectory(doc)
|
add_subdirectory(docs)
|
||||||
|
|
||||||
# build translations before source, I18N unit tests fail if they are missing
|
# build translations before source, I18N unit tests fail if they are missing
|
||||||
add_subdirectory(translations)
|
add_subdirectory(translations)
|
||||||
|
|||||||
@ -17,7 +17,7 @@ path = [
|
|||||||
, "sonar-project.properties"
|
, "sonar-project.properties"
|
||||||
, "cmake/vcpkg.json.in"
|
, "cmake/vcpkg.json.in"
|
||||||
, "**/*.md"
|
, "**/*.md"
|
||||||
, "doc/**"
|
, "docs/**"
|
||||||
, "deploy/linux/flatpak/**"
|
, "deploy/linux/flatpak/**"
|
||||||
, "deploy/linux/org.deskflow.deskflow.metainfo.xml"
|
, "deploy/linux/org.deskflow.deskflow.metainfo.xml"
|
||||||
, "deploy/windows/wix-patch.xml.in"
|
, "deploy/windows/wix-patch.xml.in"
|
||||||
|
|||||||
@ -141,8 +141,6 @@ macro(configure_unix_libs)
|
|||||||
${lib_ScreenSaver} ${lib_IOKit} ${lib_ApplicationServices}
|
${lib_ScreenSaver} ${lib_IOKit} ${lib_ApplicationServices}
|
||||||
${lib_Foundation} ${lib_Carbon} ${lib_UserNotifications}
|
${lib_Foundation} ${lib_Carbon} ${lib_UserNotifications}
|
||||||
)
|
)
|
||||||
|
|
||||||
add_definitions(-DWINAPI_CARBON=1)
|
|
||||||
else()
|
else()
|
||||||
|
|
||||||
if (BUILD_X11_SUPPORT)
|
if (BUILD_X11_SUPPORT)
|
||||||
@ -163,9 +161,6 @@ macro(configure_unix_libs)
|
|||||||
message(WARNING "pkg-config not found, skipping wayland libraries")
|
message(WARNING "pkg-config not found, skipping wayland libraries")
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_definitions(-DSYSAPI_UNIX=1)
|
|
||||||
|
|
||||||
endmacro()
|
endmacro()
|
||||||
|
|
||||||
#
|
#
|
||||||
|
|||||||
51
cmake/MacCodesign.cmake
Normal file
51
cmake/MacCodesign.cmake
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
# SPDX-FileCopyrightText: (C) 2025-2026 Deskflow Contributors
|
||||||
|
# SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
# Warning: Do not use for CI/production, as the `entitlements-dev.plist` file adds special
|
||||||
|
# entitlements that are only appropriate for local development.
|
||||||
|
#
|
||||||
|
# macOS made TCC stricter so that if you don't sign your local dev builds properly, macOS will
|
||||||
|
# nag you to remove and re-approve the app every time you make a change to the binary which is
|
||||||
|
# extremely annoying during development.
|
||||||
|
#
|
||||||
|
# If you were to use ad-hoc signing (i.e. not specify a certificate), TCC would still nag you
|
||||||
|
# because the binary identity is anchored not on the app ID, but on the CD hash (which changes
|
||||||
|
# based on the binary contents).
|
||||||
|
#
|
||||||
|
# To use, simply generate a personal certificate for free with Xcode and pass the ID to CMake.
|
||||||
|
# Full instructions are in the docs.
|
||||||
|
|
||||||
|
function(configure_mac_codesign target)
|
||||||
|
set_property(GLOBAL APPEND PROPERTY _MAC_CODESIGN_DEPENDS $<TARGET_FILE:${target}>)
|
||||||
|
|
||||||
|
get_property(deferred GLOBAL PROPERTY _MAC_CODESIGN_DEFERRED)
|
||||||
|
|
||||||
|
if(NOT deferred)
|
||||||
|
set_property(GLOBAL PROPERTY _MAC_CODESIGN_DEFERRED TRUE)
|
||||||
|
message(STATUS "Apple codesign ID for development only: ${APPLE_CODESIGN_DEV}")
|
||||||
|
cmake_language(DEFER DIRECTORY ${CMAKE_SOURCE_DIR} CALL _finalize_mac_codesign)
|
||||||
|
endif()
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
function(_finalize_mac_codesign)
|
||||||
|
get_property(depends GLOBAL PROPERTY _MAC_CODESIGN_DEPENDS)
|
||||||
|
|
||||||
|
set(stamp_file "${CMAKE_BINARY_DIR}/CMakeFiles/codesign-dev.stamp")
|
||||||
|
|
||||||
|
# Use a stamp file because codesign modifies the binaries it signs.
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT ${stamp_file}
|
||||||
|
COMMAND /usr/bin/codesign
|
||||||
|
--force
|
||||||
|
--options runtime
|
||||||
|
--entitlements "${CMAKE_SOURCE_DIR}/src/apps/res/entitlements-dev.plist"
|
||||||
|
--sign "${APPLE_CODESIGN_DEV}"
|
||||||
|
"$<TARGET_BUNDLE_DIR:${CMAKE_PROJECT_PROPER_NAME}>"
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E touch ${stamp_file}
|
||||||
|
DEPENDS ${depends}
|
||||||
|
COMMENT "Codesigning ${CMAKE_PROJECT_PROPER_NAME}"
|
||||||
|
VERBATIM
|
||||||
|
)
|
||||||
|
|
||||||
|
add_custom_target(codesign-dev ALL DEPENDS ${stamp_file})
|
||||||
|
endfunction()
|
||||||
@ -24,3 +24,12 @@ if (DOXYGEN_FOUND)
|
|||||||
else()
|
else()
|
||||||
message(STATUS "Doxygen not found, skipping docs build")
|
message(STATUS "Doxygen not found, skipping docs build")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# Show our documents in the IDE
|
||||||
|
add_custom_target(docs
|
||||||
|
SOURCES
|
||||||
|
Readme.md
|
||||||
|
Security.md
|
||||||
|
)
|
||||||
|
|
||||||
|
install(FILES Security.md Readme.md DESTINATION ${CMAKE_INSTALL_DOCDIR})
|
||||||
18
docs/Readme.md
Normal file
18
docs/Readme.md
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
# Deskflow
|
||||||
|
|
||||||
|
Deskflow is a free and open source keyboard and mouse sharing app. Use the keyboard, mouse, or trackpad of one computer to control nearby computers, and work seamlessly between them.
|
||||||
|
|
||||||
|
[Homepage](https://deskflow.org) [Code](https://github.com/deskflow/deskflo)
|
||||||
|
|
||||||
|
## Getting help online
|
||||||
|
|
||||||
|
- View the [wiki](https://github.com/deskflow/deskflow/wiki) Online resource
|
||||||
|
|
||||||
|
### Chat with us
|
||||||
|
- Main discussion on Matrix: [`#deskflow:matrix.org`](https://matrix.to/#/#deskflow:matrix.org) ([Matrix clients](https://matrix.org/ecosystem/clients/))
|
||||||
|
- Discussion also happens on IRC: `#deskflow` or `#deskflow-dev` on [Libera Chat](https://libera.chat/)
|
||||||
|
- Start a [new discussion](https://github.com/deskflow/deskflow/discussions) on our GitHub project.
|
||||||
|
|
||||||
|
## Reporting security issues
|
||||||
|
|
||||||
|
Check [Security](Security.md) to find out how to report security issues.
|
||||||
|
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 2.4 KiB |
@ -4,7 +4,7 @@ To build Deskflow you will a minimum of:
|
|||||||
- [cmake] 3.24+
|
- [cmake] 3.24+
|
||||||
- [Qt] 6.7.0+
|
- [Qt] 6.7.0+
|
||||||
- [openssl] 3.0+
|
- [openssl] 3.0+
|
||||||
- [libportal] 0.8+ (linux, bsd)
|
- [libportal] 0.9.1+ (linux, bsd)
|
||||||
- [libei] 1.3+ (linux, bsd)
|
- [libei] 1.3+ (linux, bsd)
|
||||||
- [google_test] ^
|
- [google_test] ^
|
||||||
|
|
||||||
@ -16,5 +16,4 @@ target_sources(user-docs PRIVATE
|
|||||||
install(
|
install(
|
||||||
DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/html"
|
DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/html"
|
||||||
DESTINATION ${CMAKE_INSTALL_DOCDIR}
|
DESTINATION ${CMAKE_INSTALL_DOCDIR}
|
||||||
COMPONENT deskflow_user_docs
|
|
||||||
)
|
)
|
||||||
@ -50,14 +50,14 @@ option=value
|
|||||||
This section contains options used when in client mode.
|
This section contains options used when in client mode.
|
||||||
It will begin with `[client]`
|
It will begin with `[client]`
|
||||||
|
|
||||||
|
|
||||||
| Option | Valid Values | Description |
|
| Option | Valid Values | Description |
|
||||||
|:----------------------|:------------------:|:-----------|
|
|:------------------|:------------------:|:-----------|
|
||||||
| binary | Filename | The filename of the binary to call for client mode. This binary exists in the same path as the GUI |
|
|
||||||
| invertScrollDirection | `true` or `false` | Invert scroll on this client [default: false] |
|
|
||||||
| languageSync | `true` or `false` | Sync to server language [default: true] |
|
| languageSync | `true` or `false` | Sync to server language [default: true] |
|
||||||
| remoteHost | `IP` or `hostname` | The remote host(s) to connect to. Use a comma seperated list when you want to try severial hosts |
|
| remoteHost | `IP` or `hostname` | The remote host(s) to connect to. Use a comma separated list when you want to try several hosts |
|
||||||
| yScrollScale | Double 0.1 - 10.0 | Mouse scrolling will be scaled by this amount on the client [default: 1.0] |
|
| yScrollScale | Double 0.1 - 10.0 | Vertical mouse scrolling will be scaled by this amount on the client [default: 1.0] |
|
||||||
|
| xScrollScale | Double 0.1 - 10.0 | Horizontal mouse scrolling will be scaled by this amount on the client [default: 1.0] |
|
||||||
|
| invertYScroll | `true` or `false` | Invert vertical scroll on this client [default: false] |
|
||||||
|
| invertXScroll | `true` or `false` | Invert horizontal scroll on this client [default: false] |
|
||||||
| xdpRestoreToken | UUID | Restore token provided by XDG portals |
|
| xdpRestoreToken | UUID | Restore token provided by XDG portals |
|
||||||
|
|
||||||
### Core
|
### Core
|
||||||
@ -77,6 +77,10 @@ This section contains general options it will begin with `[core]`
|
|||||||
| useHooks | `true` or `false` | If Windows uses hooks or not [default: true] |
|
| useHooks | `true` or `false` | If Windows uses hooks or not [default: true] |
|
||||||
| language | 639 language | The language to display the GUI in [default: en] |
|
| language | 639 language | The language to display the GUI in [default: en] |
|
||||||
| wlClipboard | `true` or `false` | When true the wl-clipboard backend will be enabled [default: false] |
|
| wlClipboard | `true` or `false` | When true the wl-clipboard backend will be enabled [default: false] |
|
||||||
|
| enableEnterCommand | `true` or `false` | Should the enter command be triggered when the screen is entered [defaut: false] |
|
||||||
|
| enterCommand | command | A command to run when the screen is entered. |
|
||||||
|
| enableExitCommand | `true` or `false` | Should the exit command be triggered when the screen is exited [defaut: false] |
|
||||||
|
| exitCommand | command | A command to run when the screen is exited. |
|
||||||
|
|
||||||
### Daemon
|
### Daemon
|
||||||
|
|
||||||
@ -50,6 +50,9 @@ if(BUILD_OSX_BUNDLE)
|
|||||||
INSTALL_RPATH "@loader_path/../Libraries;@loader_path/../Frameworks"
|
INSTALL_RPATH "@loader_path/../Libraries;@loader_path/../Frameworks"
|
||||||
RUNTIME_OUTPUT_DIRECTORY $<TARGET_BUNDLE_CONTENT_DIR:${CMAKE_PROJECT_PROPER_NAME}>/MacOS
|
RUNTIME_OUTPUT_DIRECTORY $<TARGET_BUNDLE_CONTENT_DIR:${CMAKE_PROJECT_PROPER_NAME}>/MacOS
|
||||||
)
|
)
|
||||||
|
if (APPLE_CODESIGN_DEV)
|
||||||
|
configure_mac_codesign(${target})
|
||||||
|
endif()
|
||||||
elseif (WIN32)
|
elseif (WIN32)
|
||||||
install(RUNTIME_DEPENDENCY_SET coreDeps
|
install(RUNTIME_DEPENDENCY_SET coreDeps
|
||||||
PRE_EXCLUDE_REGEXES ${WIN32_PRE_EXCLUDE_REGEXES}
|
PRE_EXCLUDE_REGEXES ${WIN32_PRE_EXCLUDE_REGEXES}
|
||||||
|
|||||||
@ -16,7 +16,7 @@
|
|||||||
#include "deskflow/ClientApp.h"
|
#include "deskflow/ClientApp.h"
|
||||||
#include "deskflow/ServerApp.h"
|
#include "deskflow/ServerApp.h"
|
||||||
|
|
||||||
#if SYSAPI_WIN32
|
#if defined(Q_OS_WIN)
|
||||||
#include "arch/win32/ArchMiscWindows.h"
|
#include "arch/win32/ArchMiscWindows.h"
|
||||||
#include <QCoreApplication>
|
#include <QCoreApplication>
|
||||||
#endif
|
#endif
|
||||||
@ -32,7 +32,7 @@ void showHelp(const CoreArgParser &parser)
|
|||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
#if SYSAPI_WIN32
|
#if defined(Q_OS_WIN)
|
||||||
// HACK to make sure settings gets the correct qApp path
|
// HACK to make sure settings gets the correct qApp path
|
||||||
QCoreApplication m(argc, argv);
|
QCoreApplication m(argc, argv);
|
||||||
m.deleteLater();
|
m.deleteLater();
|
||||||
|
|||||||
@ -15,8 +15,7 @@
|
|||||||
#include "common/Settings.h"
|
#include "common/Settings.h"
|
||||||
#include "deskflow/ipc/DaemonIpcServer.h"
|
#include "deskflow/ipc/DaemonIpcServer.h"
|
||||||
|
|
||||||
#if SYSAPI_WIN32
|
#if defined(Q_OS_WIN)
|
||||||
|
|
||||||
#include "arch/win32/ArchDaemonWindows.h"
|
#include "arch/win32/ArchDaemonWindows.h"
|
||||||
#include "deskflow/Screen.h"
|
#include "deskflow/Screen.h"
|
||||||
#include "platform/MSWindowsDebugOutputter.h"
|
#include "platform/MSWindowsDebugOutputter.h"
|
||||||
@ -64,7 +63,7 @@ void DaemonApp::applyWatchdogCommand() const
|
|||||||
{
|
{
|
||||||
LOG_DEBUG("applying watchdog command");
|
LOG_DEBUG("applying watchdog command");
|
||||||
|
|
||||||
#if SYSAPI_WIN32
|
#if defined(Q_OS_WIN)
|
||||||
m_pWatchdog->setProcessConfig(m_command, m_elevate);
|
m_pWatchdog->setProcessConfig(m_command, m_elevate);
|
||||||
#else
|
#else
|
||||||
LOG_ERR("applying watchdog command not implemented on this platform");
|
LOG_ERR("applying watchdog command not implemented on this platform");
|
||||||
@ -78,7 +77,7 @@ void DaemonApp::clearWatchdogCommand()
|
|||||||
// Clear the setting to prevent it from being next time the daemon starts.
|
// Clear the setting to prevent it from being next time the daemon starts.
|
||||||
setCommand("");
|
setCommand("");
|
||||||
|
|
||||||
#if SYSAPI_WIN32
|
#if defined(Q_OS_WIN)
|
||||||
m_pWatchdog->setProcessConfig("", false);
|
m_pWatchdog->setProcessConfig("", false);
|
||||||
#else
|
#else
|
||||||
LOG_ERR("clearing watchdog command not implemented on this platform");
|
LOG_ERR("clearing watchdog command not implemented on this platform");
|
||||||
@ -137,7 +136,7 @@ void DaemonApp::run(QThread &daemonThread)
|
|||||||
LOG_DEBUG("daemon thread finished");
|
LOG_DEBUG("daemon thread finished");
|
||||||
});
|
});
|
||||||
|
|
||||||
#if SYSAPI_WIN32
|
#if defined(Q_OS_WIN)
|
||||||
m_pWatchdog = std::make_unique<MSWindowsWatchdog>(m_foreground, *m_pFileLogOutputter);
|
m_pWatchdog = std::make_unique<MSWindowsWatchdog>(m_foreground, *m_pFileLogOutputter);
|
||||||
|
|
||||||
auto command = Settings::value(Settings::Daemon::Command).toString().toStdString();
|
auto command = Settings::value(Settings::Daemon::Command).toString().toStdString();
|
||||||
@ -154,17 +153,17 @@ void DaemonApp::run(QThread &daemonThread)
|
|||||||
|
|
||||||
int DaemonApp::daemonLoop()
|
int DaemonApp::daemonLoop()
|
||||||
{
|
{
|
||||||
#if SYSAPI_WIN32
|
#if defined(Q_OS_WIN)
|
||||||
// Runs the daemon through the Windows service controller, which controls the program lifecycle.
|
// Runs the daemon through the Windows service controller, which controls the program lifecycle.
|
||||||
return ArchDaemonWindows::runDaemon([this]() { return mainLoop(); });
|
return ArchDaemonWindows::runDaemon([this]() { return mainLoop(); });
|
||||||
#elif SYSAPI_UNIX
|
#else
|
||||||
return mainLoop();
|
return mainLoop();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
int DaemonApp::mainLoop()
|
int DaemonApp::mainLoop()
|
||||||
{
|
{
|
||||||
#if SYSAPI_WIN32
|
#if defined(Q_OS_WIN)
|
||||||
if (m_pWatchdog == nullptr) {
|
if (m_pWatchdog == nullptr) {
|
||||||
LOG_ERR("watchdog not initialized");
|
LOG_ERR("watchdog not initialized");
|
||||||
return s_exitFailed;
|
return s_exitFailed;
|
||||||
@ -173,7 +172,7 @@ int DaemonApp::mainLoop()
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
try {
|
try {
|
||||||
#if SYSAPI_WIN32
|
#if defined(Q_OS_WIN)
|
||||||
// Install the platform event queue to handle service stop events.
|
// Install the platform event queue to handle service stop events.
|
||||||
// This must be done on the same thread as the event loop, otherwise the service stop
|
// This must be done on the same thread as the event loop, otherwise the service stop
|
||||||
// request will not add the quit event to the event queue, and the service won't stop.
|
// request will not add the quit event to the event queue, and the service won't stop.
|
||||||
@ -193,7 +192,7 @@ int DaemonApp::mainLoop()
|
|||||||
|
|
||||||
LOG_INFO("daemon is stopping");
|
LOG_INFO("daemon is stopping");
|
||||||
|
|
||||||
#if SYSAPI_WIN32
|
#if defined(Q_OS_WIN)
|
||||||
try {
|
try {
|
||||||
LOG_DEBUG("stopping process watchdog");
|
LOG_DEBUG("stopping process watchdog");
|
||||||
m_pWatchdog->stop();
|
m_pWatchdog->stop();
|
||||||
@ -221,7 +220,7 @@ void DaemonApp::setForeground()
|
|||||||
|
|
||||||
void DaemonApp::initLogging()
|
void DaemonApp::initLogging()
|
||||||
{
|
{
|
||||||
#if SYSAPI_WIN32
|
#if defined(Q_OS_WIN)
|
||||||
if (!m_foreground) {
|
if (!m_foreground) {
|
||||||
// Only use MS debug outputter when the process is daemonized, since stdout won't be accessible
|
// Only use MS debug outputter when the process is daemonized, since stdout won't be accessible
|
||||||
// in that case, but is accessible when running in the foreground.
|
// in that case, but is accessible when running in the foreground.
|
||||||
@ -235,7 +234,7 @@ void DaemonApp::initLogging()
|
|||||||
|
|
||||||
void DaemonApp::showConsole()
|
void DaemonApp::showConsole()
|
||||||
{
|
{
|
||||||
#if SYSAPI_WIN32
|
#if defined(Q_OS_WIN)
|
||||||
// The daemon bin is compiled using the Win32 subsystem which works best for Windows services,
|
// The daemon bin is compiled using the Win32 subsystem which works best for Windows services,
|
||||||
// so when running as a foreground process we need to allocate a console (or we won't see output).
|
// so when running as a foreground process we need to allocate a console (or we won't see output).
|
||||||
// It is important to do this inside the arg check loop so that we can attach console ahead
|
// It is important to do this inside the arg check loop so that we can attach console ahead
|
||||||
|
|||||||
@ -21,7 +21,7 @@ namespace deskflow::core::ipc {
|
|||||||
class DaemonIpcServer;
|
class DaemonIpcServer;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if SYSAPI_WIN32
|
#if defined(Q_OS_WIN)
|
||||||
class MSWindowsWatchdog;
|
class MSWindowsWatchdog;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -56,7 +56,7 @@ private:
|
|||||||
|
|
||||||
static void showConsole();
|
static void showConsole();
|
||||||
|
|
||||||
#if SYSAPI_WIN32
|
#if defined(Q_OS_WIN)
|
||||||
std::unique_ptr<MSWindowsWatchdog> m_pWatchdog;
|
std::unique_ptr<MSWindowsWatchdog> m_pWatchdog;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@ -15,13 +15,11 @@
|
|||||||
#include "common/VersionInfo.h"
|
#include "common/VersionInfo.h"
|
||||||
#include "deskflow/ipc/DaemonIpcServer.h"
|
#include "deskflow/ipc/DaemonIpcServer.h"
|
||||||
|
|
||||||
#if SYSAPI_WIN32
|
#if defined(Q_OS_WIN)
|
||||||
|
|
||||||
#include "arch/win32/ArchMiscWindows.h"
|
#include "arch/win32/ArchMiscWindows.h"
|
||||||
|
|
||||||
#define WIN32_LEAN_AND_MEAN
|
#define WIN32_LEAN_AND_MEAN
|
||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <QCommandLineParser>
|
#include <QCommandLineParser>
|
||||||
@ -34,7 +32,7 @@ void handleError(const char *message = "Unrecognized error.");
|
|||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
#if SYSAPI_WIN32
|
#if defined(Q_OS_WIN)
|
||||||
ArchMiscWindows::guardRuntimeVersion();
|
ArchMiscWindows::guardRuntimeVersion();
|
||||||
|
|
||||||
// Save window instance for later use, e.g. `GetModuleFileName` which is used when installing the daemon.
|
// Save window instance for later use, e.g. `GetModuleFileName` which is used when installing the daemon.
|
||||||
@ -85,7 +83,7 @@ int main(int argc, char **argv)
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
#if SYSAPI_WIN32
|
#if defined(Q_OS_WIN)
|
||||||
// Show warning if not running as admin as daemon will behave differently.
|
// Show warning if not running as admin as daemon will behave differently.
|
||||||
if (!ArchMiscWindows::isProcessElevated()) {
|
if (!ArchMiscWindows::isProcessElevated()) {
|
||||||
LOG_WARN("not running as admin, some features may not work");
|
LOG_WARN("not running as admin, some features may not work");
|
||||||
@ -115,8 +113,7 @@ int main(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if SYSAPI_WIN32
|
#if defined(Q_OS_WIN)
|
||||||
|
|
||||||
// Win32 subsystem entry point (simply forwards to main).
|
// Win32 subsystem entry point (simply forwards to main).
|
||||||
// We need this because using regular main under the Win32 subsystem results in empty args.
|
// We need this because using regular main under the Win32 subsystem results in empty args.
|
||||||
int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
|
int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
|
||||||
@ -131,7 +128,7 @@ void handleError(const char *message)
|
|||||||
// Always print error to stdout in case run as CLI program.
|
// Always print error to stdout in case run as CLI program.
|
||||||
LOG_ERR("%s", message);
|
LOG_ERR("%s", message);
|
||||||
|
|
||||||
#if SYSAPI_WIN32
|
#if defined(Q_OS_WIN)
|
||||||
// Show a message box for when run from MSI in Win32 subsystem.
|
// Show a message box for when run from MSI in Win32 subsystem.
|
||||||
MessageBoxA(nullptr, message, "Deskflow daemon error", MB_OK | MB_ICONERROR);
|
MessageBoxA(nullptr, message, "Deskflow daemon error", MB_OK | MB_ICONERROR);
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -95,32 +95,8 @@ elseif(APPLE)
|
|||||||
INSTALL_RPATH "@loader_path/../Libraries;@loader_path/../Frameworks"
|
INSTALL_RPATH "@loader_path/../Libraries;@loader_path/../Frameworks"
|
||||||
MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_BINARY_DIR}/deskflow.plist"
|
MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_BINARY_DIR}/deskflow.plist"
|
||||||
)
|
)
|
||||||
|
if (APPLE_CODESIGN_DEV)
|
||||||
# Warning: Do not use for CI/production, as the `entitlements-dev.plist` file adds special
|
configure_mac_codesign(${target})
|
||||||
# entitlements that are only appropriate for local development.
|
|
||||||
#
|
|
||||||
# macOS made TCC stricter so that if you don't sign your local dev builds properly, macOS will
|
|
||||||
# nag you to remove and re-approve the app every time you make a change to the binary which is
|
|
||||||
# extremely annoying during development.
|
|
||||||
#
|
|
||||||
# If you were to use ad-hoc signing (i.e. not specify a certificate), TCC would still nag you
|
|
||||||
# because the binary identity is anchored not on the app ID, but on the CD hash (which changes
|
|
||||||
# based on the binary contents).
|
|
||||||
#
|
|
||||||
# To use, simply generate a personal certificate for free with Xcode and pass the ID to CMake.
|
|
||||||
# Full instructions are in the docs.
|
|
||||||
if (NOT "${APPLE_CODESIGN_DEV}" STREQUAL "")
|
|
||||||
message(STATUS "Apple codesign ID for development only: ${APPLE_CODESIGN_DEV}")
|
|
||||||
add_custom_command(
|
|
||||||
TARGET ${target} POST_BUILD
|
|
||||||
COMMAND /usr/bin/codesign
|
|
||||||
--force
|
|
||||||
--options runtime
|
|
||||||
--entitlements "$<SHELL_PATH:${CMAKE_SOURCE_DIR}/src/apps/res/entitlements-dev.plist>"
|
|
||||||
--sign "${APPLE_CODESIGN_DEV}"
|
|
||||||
"$<TARGET_BUNDLE_DIR:${target}>"
|
|
||||||
VERBATIM
|
|
||||||
)
|
|
||||||
endif()
|
endif()
|
||||||
else()
|
else()
|
||||||
set_target_properties(${target} PROPERTIES MACOSX_BUNDLE FALSE)
|
set_target_properties(${target} PROPERTIES MACOSX_BUNDLE FALSE)
|
||||||
|
|||||||
@ -32,7 +32,7 @@
|
|||||||
#include <QLoggingCategory>
|
#include <QLoggingCategory>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(WINAPI_XWINDOWS) or defined(WINAPI_LIBEI)
|
#if !defined(Q_OS_MAC) && !defined(Q_OS_WIN)
|
||||||
#include "platform/XDGPortalRegistry.h"
|
#include "platform/XDGPortalRegistry.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -51,7 +51,7 @@ int main(int argc, char *argv[])
|
|||||||
QLoggingCategory::setFilterRules(QStringLiteral("*.debug=true\nqt.*=false"));
|
QLoggingCategory::setFilterRules(QStringLiteral("*.debug=true\nqt.*=false"));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(WINAPI_XWINDOWS) or defined(WINAPI_LIBEI)
|
#if !defined(Q_OS_MAC) && !defined(Q_OS_WIN)
|
||||||
deskflow::platform::setAppId();
|
deskflow::platform::setAppId();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
#if SYSAPI_WIN32
|
#if defined(Q_OS_WIN)
|
||||||
#include "arch/win32/ArchMiscWindows.h"
|
#include "arch/win32/ArchMiscWindows.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -26,7 +26,7 @@ Arch::Arch()
|
|||||||
s_instance = this;
|
s_instance = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if SYSAPI_WIN32
|
#if defined(Q_OS_WIN)
|
||||||
void Arch::init()
|
void Arch::init()
|
||||||
{
|
{
|
||||||
ARCH_NETWORK::init();
|
ARCH_NETWORK::init();
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
* SPDX-FileCopyrightText: (C) 2002 Chris Schoeneman
|
* SPDX-FileCopyrightText: (C) 2002 Chris Schoeneman
|
||||||
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
|
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
|
||||||
*/
|
*/
|
||||||
|
#include <QtSystemDetection>
|
||||||
// Consider whether or not to use either encapsulation (as below)
|
// Consider whether or not to use either encapsulation (as below)
|
||||||
// or inheritance (as it is now) for the ARCH stuff.
|
// or inheritance (as it is now) for the ARCH stuff.
|
||||||
//
|
//
|
||||||
@ -25,20 +25,16 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#if SYSAPI_WIN32
|
#if defined(Q_OS_WIN)
|
||||||
|
|
||||||
#include "arch/win32/ArchDaemonWindows.h"
|
#include "arch/win32/ArchDaemonWindows.h"
|
||||||
#include "arch/win32/ArchLogWindows.h"
|
#include "arch/win32/ArchLogWindows.h"
|
||||||
#include "arch/win32/ArchMultithreadWindows.h"
|
#include "arch/win32/ArchMultithreadWindows.h"
|
||||||
#include "arch/win32/ArchNetworkWinsock.h"
|
#include "arch/win32/ArchNetworkWinsock.h"
|
||||||
|
#else
|
||||||
#elif SYSAPI_UNIX
|
|
||||||
|
|
||||||
#include "arch/ArchDaemonNone.h"
|
#include "arch/ArchDaemonNone.h"
|
||||||
#include "arch/unix/ArchLogUnix.h"
|
#include "arch/unix/ArchLogUnix.h"
|
||||||
#include "arch/unix/ArchMultithreadPosix.h"
|
#include "arch/unix/ArchMultithreadPosix.h"
|
||||||
#include "arch/unix/ArchNetworkBSD.h"
|
#include "arch/unix/ArchNetworkBSD.h"
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@ -63,7 +59,7 @@ public:
|
|||||||
Arch();
|
Arch();
|
||||||
~Arch() override = default;
|
~Arch() override = default;
|
||||||
|
|
||||||
#if SYSAPI_WIN32
|
#if defined(Q_OS_WIN)
|
||||||
//! Call init on other arch classes.
|
//! Call init on other arch classes.
|
||||||
/*!
|
/*!
|
||||||
Some arch classes depend on others to exist first. When init is called
|
Some arch classes depend on others to exist first. When init is called
|
||||||
|
|||||||
@ -91,6 +91,11 @@ enum class EventTypes : uint32_t
|
|||||||
/// This event is sent whenever a server accepts a client.
|
/// This event is sent whenever a server accepts a client.
|
||||||
ClientListenerAccepted,
|
ClientListenerAccepted,
|
||||||
|
|
||||||
|
/** This event is sent whenever a client disconnects/errors out before the connection
|
||||||
|
is fully accepted.
|
||||||
|
*/
|
||||||
|
ClientListenerDisconnectedOnAccept,
|
||||||
|
|
||||||
/** This event is sent when the client has completed the initial handshake. Until it is sent,
|
/** This event is sent when the client has completed the initial handshake. Until it is sent,
|
||||||
the client is not fully connected.
|
the client is not fully connected.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -21,3 +21,26 @@ enum class ErrorType : uint8_t
|
|||||||
};
|
};
|
||||||
Q_ENUM_NS(ErrorType)
|
Q_ENUM_NS(ErrorType)
|
||||||
} // namespace deskflow::client
|
} // namespace deskflow::client
|
||||||
|
|
||||||
|
namespace deskflow::core {
|
||||||
|
Q_NAMESPACE
|
||||||
|
|
||||||
|
enum class ProcessState
|
||||||
|
{
|
||||||
|
Starting,
|
||||||
|
Started,
|
||||||
|
Stopping,
|
||||||
|
Stopped,
|
||||||
|
RetryPending
|
||||||
|
};
|
||||||
|
Q_ENUM_NS(ProcessState)
|
||||||
|
|
||||||
|
enum class ConnectionState
|
||||||
|
{
|
||||||
|
Disconnected,
|
||||||
|
Connecting,
|
||||||
|
Connected,
|
||||||
|
Listening
|
||||||
|
};
|
||||||
|
Q_ENUM_NS(ConnectionState)
|
||||||
|
} // namespace deskflow::core
|
||||||
|
|||||||
@ -137,12 +137,11 @@ QString Settings::cleanComputerName(const QString &name)
|
|||||||
static const auto space = QStringLiteral(" ");
|
static const auto space = QStringLiteral(" ");
|
||||||
static const auto underscore = QStringLiteral("_");
|
static const auto underscore = QStringLiteral("_");
|
||||||
static const auto period = QStringLiteral(".");
|
static const auto period = QStringLiteral(".");
|
||||||
static const auto nothing = QStringLiteral("");
|
|
||||||
static const auto nameRegex = QRegularExpression(QStringLiteral("[^\\w\\-\\.]"));
|
static const auto nameRegex = QRegularExpression(QStringLiteral("[^\\w\\-\\.]"));
|
||||||
|
|
||||||
QString cleanName = name.simplified();
|
QString cleanName = name.simplified();
|
||||||
cleanName.replace(space, underscore);
|
cleanName.replace(space, underscore);
|
||||||
cleanName.replace(nameRegex, nothing);
|
cleanName.replace(nameRegex, {});
|
||||||
while (cleanName.startsWith(hyphen) || cleanName.startsWith(underscore) || cleanName.startsWith(period))
|
while (cleanName.startsWith(hyphen) || cleanName.startsWith(underscore) || cleanName.startsWith(period))
|
||||||
cleanName.removeFirst();
|
cleanName.removeFirst();
|
||||||
while (cleanName.endsWith(hyphen) || cleanName.endsWith(underscore) || cleanName.endsWith(period))
|
while (cleanName.endsWith(hyphen) || cleanName.endsWith(underscore) || cleanName.endsWith(period))
|
||||||
@ -233,6 +232,18 @@ QStringList Settings::validKeys()
|
|||||||
return Settings::m_validKeys;
|
return Settings::m_validKeys;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString Settings::serverConfigFile()
|
||||||
|
{
|
||||||
|
bool useExt = value(Server::ExternalConfig).toBool();
|
||||||
|
return useExt ? value(Server::ExternalConfigFile).toString() : defaultValue(Server::ExternalConfigFile).toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Settings::isServerConfigFileReadable()
|
||||||
|
{
|
||||||
|
auto file = QFile(serverConfigFile());
|
||||||
|
return file.open(QFile::ReadOnly);
|
||||||
|
}
|
||||||
|
|
||||||
bool Settings::isWritable()
|
bool Settings::isWritable()
|
||||||
{
|
{
|
||||||
return instance()->m_settings->isWritable();
|
return instance()->m_settings->isWritable();
|
||||||
|
|||||||
@ -55,6 +55,10 @@ public:
|
|||||||
inline static const auto UseHooks = QStringLiteral("core/useHooks");
|
inline static const auto UseHooks = QStringLiteral("core/useHooks");
|
||||||
inline static const auto Language = QStringLiteral("core/language");
|
inline static const auto Language = QStringLiteral("core/language");
|
||||||
inline static const auto UseWlClipboard = QStringLiteral("core/wlClipboard");
|
inline static const auto UseWlClipboard = QStringLiteral("core/wlClipboard");
|
||||||
|
inline static const auto EnableEnterCommand = QStringLiteral("core/enableEnterCommand");
|
||||||
|
inline static const auto ScreenEnterCommand = QStringLiteral("core/enterCommand");
|
||||||
|
inline static const auto EnableExitCommand = QStringLiteral("core/enableExitCommand");
|
||||||
|
inline static const auto ScreenExitCommand = QStringLiteral("core/exitCommand");
|
||||||
|
|
||||||
// TODO: REMOVE In 2.0
|
// TODO: REMOVE In 2.0
|
||||||
inline static const auto ScreenName = QStringLiteral("core/screenName"); // Replaced By ComputerName
|
inline static const auto ScreenName = QStringLiteral("core/screenName"); // Replaced By ComputerName
|
||||||
@ -77,7 +81,6 @@ public:
|
|||||||
inline static const auto LogExpanded = QStringLiteral("gui/logExpanded");
|
inline static const auto LogExpanded = QStringLiteral("gui/logExpanded");
|
||||||
inline static const auto SymbolicTrayIcon = QStringLiteral("gui/symbolicTrayIcon");
|
inline static const auto SymbolicTrayIcon = QStringLiteral("gui/symbolicTrayIcon");
|
||||||
inline static const auto WindowGeometry = QStringLiteral("gui/windowGeometry");
|
inline static const auto WindowGeometry = QStringLiteral("gui/windowGeometry");
|
||||||
inline static const auto ShowGenericClientFailureDialog = QStringLiteral("gui/showGenericClientFailureDialog");
|
|
||||||
inline static const auto ShownFirstConnectedMessage = QStringLiteral("gui/shownFirstConnectedMessage");
|
inline static const auto ShownFirstConnectedMessage = QStringLiteral("gui/shownFirstConnectedMessage");
|
||||||
inline static const auto ShownServerFirstStartMessage = QStringLiteral("gui/shownServerFirstStartMessage");
|
inline static const auto ShownServerFirstStartMessage = QStringLiteral("gui/shownServerFirstStartMessage");
|
||||||
inline static const auto ShowVersionInTitle = QStringLiteral("gui/showVersionInTitle");
|
inline static const auto ShowVersionInTitle = QStringLiteral("gui/showVersionInTitle");
|
||||||
@ -131,10 +134,12 @@ public:
|
|||||||
static QVariant value(const QString &key = QString());
|
static QVariant value(const QString &key = QString());
|
||||||
static void restoreDefaultSettings();
|
static void restoreDefaultSettings();
|
||||||
static QVariant defaultValue(const QString &key);
|
static QVariant defaultValue(const QString &key);
|
||||||
|
static bool isServerConfigFileReadable();
|
||||||
static bool isWritable();
|
static bool isWritable();
|
||||||
static bool isPortableMode();
|
static bool isPortableMode();
|
||||||
static QString settingsFile();
|
static QString settingsFile();
|
||||||
static QString settingsPath();
|
static QString settingsPath();
|
||||||
|
static QString serverConfigFile();
|
||||||
static QString tlsDir();
|
static QString tlsDir();
|
||||||
static QString tlsTrustedServersDb();
|
static QString tlsTrustedServersDb();
|
||||||
static QString tlsTrustedClientsDb();
|
static QString tlsTrustedClientsDb();
|
||||||
@ -206,6 +211,10 @@ private:
|
|||||||
, Settings::Core::Port
|
, Settings::Core::Port
|
||||||
, Settings::Core::PreventSleep
|
, Settings::Core::PreventSleep
|
||||||
, Settings::Core::ProcessMode
|
, Settings::Core::ProcessMode
|
||||||
|
, Settings::Core::EnableEnterCommand
|
||||||
|
, Settings::Core::EnableExitCommand
|
||||||
|
, Settings::Core::ScreenEnterCommand
|
||||||
|
, Settings::Core::ScreenExitCommand
|
||||||
, Settings::Core::ScreenName
|
, Settings::Core::ScreenName
|
||||||
, Settings::Core::ComputerName
|
, Settings::Core::ComputerName
|
||||||
, Settings::Core::Display
|
, Settings::Core::Display
|
||||||
@ -215,6 +224,7 @@ private:
|
|||||||
, Settings::Daemon::Command
|
, Settings::Daemon::Command
|
||||||
, Settings::Daemon::Elevate
|
, Settings::Daemon::Elevate
|
||||||
, Settings::Daemon::LogFile
|
, Settings::Daemon::LogFile
|
||||||
|
, Settings::Daemon::LogLevel
|
||||||
, Settings::Log::File
|
, Settings::Log::File
|
||||||
, Settings::Log::Level
|
, Settings::Log::Level
|
||||||
, Settings::Log::ToFile
|
, Settings::Log::ToFile
|
||||||
@ -228,7 +238,6 @@ private:
|
|||||||
, Settings::Gui::LogExpanded
|
, Settings::Gui::LogExpanded
|
||||||
, Settings::Gui::SymbolicTrayIcon
|
, Settings::Gui::SymbolicTrayIcon
|
||||||
, Settings::Gui::WindowGeometry
|
, Settings::Gui::WindowGeometry
|
||||||
, Settings::Gui::ShowGenericClientFailureDialog
|
|
||||||
, Settings::Gui::ShownFirstConnectedMessage
|
, Settings::Gui::ShownFirstConnectedMessage
|
||||||
, Settings::Gui::ShownServerFirstStartMessage
|
, Settings::Gui::ShownServerFirstStartMessage
|
||||||
, Settings::Gui::ShowVersionInTitle
|
, Settings::Gui::ShowVersionInTitle
|
||||||
@ -249,6 +258,8 @@ private:
|
|||||||
, Settings::Gui::ShowVersionInTitle
|
, Settings::Gui::ShowVersionInTitle
|
||||||
, Settings::Core::PreventSleep
|
, Settings::Core::PreventSleep
|
||||||
, Settings::Core::UseWlClipboard
|
, Settings::Core::UseWlClipboard
|
||||||
|
, Settings::Core::EnableEnterCommand
|
||||||
|
, Settings::Core::EnableExitCommand
|
||||||
, Settings::Server::ExternalConfig
|
, Settings::Server::ExternalConfig
|
||||||
, Settings::Client::InvertYScroll
|
, Settings::Client::InvertYScroll
|
||||||
, Settings::Client::InvertXScroll
|
, Settings::Client::InvertXScroll
|
||||||
@ -264,7 +275,6 @@ private:
|
|||||||
, Settings::Gui::CloseReminder
|
, Settings::Gui::CloseReminder
|
||||||
, Settings::Gui::LogExpanded
|
, Settings::Gui::LogExpanded
|
||||||
, Settings::Gui::SymbolicTrayIcon
|
, Settings::Gui::SymbolicTrayIcon
|
||||||
, Settings::Gui::ShowGenericClientFailureDialog
|
|
||||||
, Settings::Security::TlsEnabled
|
, Settings::Security::TlsEnabled
|
||||||
, Settings::Security::CheckPeers
|
, Settings::Security::CheckPeers
|
||||||
};
|
};
|
||||||
|
|||||||
@ -16,13 +16,13 @@
|
|||||||
#include "common/Settings.h"
|
#include "common/Settings.h"
|
||||||
#include "deskflow/DeskflowException.h"
|
#include "deskflow/DeskflowException.h"
|
||||||
|
|
||||||
#if SYSAPI_WIN32
|
#if defined(Q_OS_WIN)
|
||||||
#include "base/IEventQueue.h"
|
#include "base/IEventQueue.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
#if WINAPI_CARBON
|
#if defined(Q_OS_MAC)
|
||||||
#include "platform/OSXCocoaApp.h"
|
#include "platform/OSXCocoaApp.h"
|
||||||
#include <ApplicationServices/ApplicationServices.h>
|
#include <ApplicationServices/ApplicationServices.h>
|
||||||
#endif
|
#endif
|
||||||
@ -151,10 +151,7 @@ void App::handleScreenError() const
|
|||||||
void App::runEventsLoop(const void *)
|
void App::runEventsLoop(const void *)
|
||||||
{
|
{
|
||||||
m_events->loop();
|
m_events->loop();
|
||||||
|
#if defined(Q_OS_MAC)
|
||||||
#if WINAPI_CARBON
|
|
||||||
|
|
||||||
stopCocoaLoop();
|
stopCocoaLoop();
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,9 +13,9 @@
|
|||||||
#include "deskflow/IApp.h"
|
#include "deskflow/IApp.h"
|
||||||
#include "net/SocketMultiplexer.h"
|
#include "net/SocketMultiplexer.h"
|
||||||
|
|
||||||
#if SYSAPI_WIN32
|
#if defined(Q_OS_WIN)
|
||||||
#include "deskflow/win32/AppUtilWindows.h"
|
#include "deskflow/win32/AppUtilWindows.h"
|
||||||
#elif SYSAPI_UNIX
|
#else
|
||||||
#include "deskflow/unix/AppUtilUnix.h"
|
#include "deskflow/unix/AppUtilUnix.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@ -22,7 +22,7 @@
|
|||||||
#include "net/SocketMultiplexer.h"
|
#include "net/SocketMultiplexer.h"
|
||||||
#include "net/TCPSocketFactory.h"
|
#include "net/TCPSocketFactory.h"
|
||||||
|
|
||||||
#if WINAPI_MSWINDOWS
|
#if defined(Q_OS_WIN)
|
||||||
#include "platform/MSWindowsScreen.h"
|
#include "platform/MSWindowsScreen.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -36,7 +36,7 @@
|
|||||||
#include "platform/EiScreen.h"
|
#include "platform/EiScreen.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if WINAPI_CARBON
|
#if defined(Q_OS_MAC)
|
||||||
#include "base/TMethodJob.h"
|
#include "base/TMethodJob.h"
|
||||||
#include "mt/Thread.h"
|
#include "mt/Thread.h"
|
||||||
#include "platform/OSXCocoaApp.h"
|
#include "platform/OSXCocoaApp.h"
|
||||||
@ -104,7 +104,7 @@ const char *ClientApp::daemonName() const
|
|||||||
|
|
||||||
deskflow::Screen *ClientApp::createScreen()
|
deskflow::Screen *ClientApp::createScreen()
|
||||||
{
|
{
|
||||||
#if WINAPI_MSWINDOWS
|
#if defined(Q_OS_WIN)
|
||||||
return new deskflow::Screen(
|
return new deskflow::Screen(
|
||||||
new MSWindowsScreen(
|
new MSWindowsScreen(
|
||||||
false, Settings::value(Settings::Core::UseHooks).toBool(), getEvents(),
|
false, Settings::value(Settings::Core::UseHooks).toBool(), getEvents(),
|
||||||
@ -112,9 +112,11 @@ deskflow::Screen *ClientApp::createScreen()
|
|||||||
),
|
),
|
||||||
getEvents()
|
getEvents()
|
||||||
);
|
);
|
||||||
#endif
|
#elif defined(Q_OS_MAC)
|
||||||
|
return new deskflow::Screen(
|
||||||
#if defined(WINAPI_XWINDOWS) or defined(WINAPI_LIBEI)
|
new OSXScreen(getEvents(), false, Settings::value(Settings::Client::LanguageSync).toBool()), getEvents()
|
||||||
|
);
|
||||||
|
#else
|
||||||
if (deskflow::platform::isWayland()) {
|
if (deskflow::platform::isWayland()) {
|
||||||
#if WINAPI_LIBEI
|
#if WINAPI_LIBEI
|
||||||
LOG_INFO("using ei screen for wayland");
|
LOG_INFO("using ei screen for wayland");
|
||||||
@ -123,22 +125,14 @@ deskflow::Screen *ClientApp::createScreen()
|
|||||||
throw XNoEiSupport();
|
throw XNoEiSupport();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
#if WINAPI_XWINDOWS
|
#if WINAPI_XWINDOWS
|
||||||
LOG_INFO("using legacy x windows screen");
|
LOG_INFO("using legacy x windows screen");
|
||||||
return new deskflow::Screen(
|
return new deskflow::Screen(
|
||||||
new XWindowsScreen(qPrintable(Settings::value(Settings::Core::Display).toString()), false, getEvents()),
|
new XWindowsScreen(qPrintable(Settings::value(Settings::Core::Display).toString()), false, getEvents()),
|
||||||
getEvents()
|
getEvents()
|
||||||
);
|
);
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if WINAPI_CARBON
|
|
||||||
return new deskflow::Screen(
|
|
||||||
new OSXScreen(getEvents(), false, Settings::value(Settings::Client::LanguageSync).toBool()), getEvents()
|
|
||||||
);
|
|
||||||
#endif
|
#endif
|
||||||
|
#endif // end os check
|
||||||
}
|
}
|
||||||
|
|
||||||
deskflow::Screen *ClientApp::openClientScreen()
|
deskflow::Screen *ClientApp::openClientScreen()
|
||||||
@ -332,8 +326,7 @@ int ClientApp::mainLoop()
|
|||||||
// later. the timer installed by startClient() will take care of
|
// later. the timer installed by startClient() will take care of
|
||||||
// that.
|
// that.
|
||||||
|
|
||||||
#if WINAPI_CARBON
|
#if defined(Q_OS_MAC)
|
||||||
|
|
||||||
Thread thread(new TMethodJob<ClientApp>(this, &ClientApp::runEventsLoop, nullptr));
|
Thread thread(new TMethodJob<ClientApp>(this, &ClientApp::runEventsLoop, nullptr));
|
||||||
|
|
||||||
// wait until carbon loop is ready
|
// wait until carbon loop is ready
|
||||||
|
|||||||
@ -10,6 +10,8 @@
|
|||||||
#include "base/Log.h"
|
#include "base/Log.h"
|
||||||
#include "deskflow/IPlatformScreen.h"
|
#include "deskflow/IPlatformScreen.h"
|
||||||
|
|
||||||
|
#include <QProcess>
|
||||||
|
|
||||||
namespace deskflow {
|
namespace deskflow {
|
||||||
|
|
||||||
//
|
//
|
||||||
@ -119,6 +121,14 @@ void Screen::enter(KeyModifierMask toggleMask)
|
|||||||
} else {
|
} else {
|
||||||
enterSecondary(toggleMask);
|
enterSecondary(toggleMask);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Settings::value(Settings::Core::EnableEnterCommand).toBool()) {
|
||||||
|
auto args = QProcess::splitCommand(Settings::value(Settings::Core::ScreenEnterCommand).toString());
|
||||||
|
const auto command = args.takeFirst();
|
||||||
|
LOG_DEBUG("running screen enter command: %s %s", qPrintable(command), qPrintable(args.join(" ")));
|
||||||
|
if (!QProcess::startDetached(command, args))
|
||||||
|
LOG_ERR("failed to run screen enter command");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Screen::leave()
|
bool Screen::leave()
|
||||||
@ -140,6 +150,13 @@ bool Screen::leave()
|
|||||||
}
|
}
|
||||||
|
|
||||||
m_screen->leave();
|
m_screen->leave();
|
||||||
|
if (Settings::value(Settings::Core::EnableExitCommand).toBool()) {
|
||||||
|
auto args = QProcess::splitCommand(Settings::value(Settings::Core::ScreenExitCommand).toString());
|
||||||
|
const auto command = args.takeFirst();
|
||||||
|
LOG_DEBUG("running screen exit command: %s %s", qPrintable(command), qPrintable(args.join(" ")));
|
||||||
|
if (!QProcess::startDetached(command, args))
|
||||||
|
LOG_ERR("failed to run screen exit command");
|
||||||
|
}
|
||||||
|
|
||||||
// make sure our idea of clipboard ownership is correct
|
// make sure our idea of clipboard ownership is correct
|
||||||
m_screen->checkClipboards();
|
m_screen->checkClipboards();
|
||||||
|
|||||||
@ -30,7 +30,7 @@
|
|||||||
// must be before screen header includes
|
// must be before screen header includes
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
|
|
||||||
#if WINAPI_MSWINDOWS
|
#if defined(Q_OS_WIN)
|
||||||
#include "platform/MSWindowsScreen.h"
|
#include "platform/MSWindowsScreen.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -42,7 +42,7 @@
|
|||||||
#include "platform/EiScreen.h"
|
#include "platform/EiScreen.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if WINAPI_CARBON
|
#if defined(Q_OS_MAC)
|
||||||
#include "base/TMethodJob.h"
|
#include "base/TMethodJob.h"
|
||||||
#include "mt/Thread.h"
|
#include "mt/Thread.h"
|
||||||
#include "platform/OSXCocoaApp.h"
|
#include "platform/OSXCocoaApp.h"
|
||||||
@ -85,17 +85,10 @@ void ServerApp::reloadSignalHandler(Arch::ThreadSignal, void *)
|
|||||||
events->addEvent(Event(EventTypes::ServerAppReloadConfig, events->getSystemTarget()));
|
events->addEvent(Event(EventTypes::ServerAppReloadConfig, events->getSystemTarget()));
|
||||||
}
|
}
|
||||||
|
|
||||||
QString ServerApp::currentConfig() const
|
|
||||||
{
|
|
||||||
bool useExt = Settings::value(Settings::Server::ExternalConfig).toBool();
|
|
||||||
return useExt ? Settings::value(Settings::Server::ExternalConfigFile).toString()
|
|
||||||
: Settings::defaultValue(Settings::Server::ExternalConfigFile).toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ServerApp::reloadConfig()
|
void ServerApp::reloadConfig()
|
||||||
{
|
{
|
||||||
LOG_DEBUG("reload configuration");
|
LOG_DEBUG("reload configuration");
|
||||||
if (loadConfig(currentConfig())) {
|
if (loadConfig(Settings::serverConfigFile())) {
|
||||||
if (m_server != nullptr) {
|
if (m_server != nullptr) {
|
||||||
m_server->setConfig(*m_config);
|
m_server->setConfig(*m_config);
|
||||||
}
|
}
|
||||||
@ -105,7 +98,7 @@ void ServerApp::reloadConfig()
|
|||||||
|
|
||||||
void ServerApp::loadConfig()
|
void ServerApp::loadConfig()
|
||||||
{
|
{
|
||||||
const auto path = currentConfig();
|
const auto path = Settings::serverConfigFile();
|
||||||
if (path.isEmpty()) {
|
if (path.isEmpty()) {
|
||||||
LOG_CRIT("no configuration path provided");
|
LOG_CRIT("no configuration path provided");
|
||||||
bye(s_exitConfig);
|
bye(s_exitConfig);
|
||||||
@ -123,7 +116,7 @@ bool ServerApp::loadConfig(const QString &filename)
|
|||||||
try {
|
try {
|
||||||
// load configuration
|
// load configuration
|
||||||
LOG_DEBUG("opening configuration \"%s\"", path.c_str());
|
LOG_DEBUG("opening configuration \"%s\"", path.c_str());
|
||||||
#ifdef SYSAPI_WIN32
|
#if defined(Q_OS_WIN)
|
||||||
std::ifstream configStream(filename.toStdWString());
|
std::ifstream configStream(filename.toStdWString());
|
||||||
#else
|
#else
|
||||||
std::ifstream configStream(path);
|
std::ifstream configStream(path);
|
||||||
@ -399,13 +392,13 @@ bool ServerApp::startServer()
|
|||||||
|
|
||||||
deskflow::Screen *ServerApp::createScreen()
|
deskflow::Screen *ServerApp::createScreen()
|
||||||
{
|
{
|
||||||
#if WINAPI_MSWINDOWS
|
#if defined(Q_OS_WIN)
|
||||||
return new deskflow::Screen(
|
return new deskflow::Screen(
|
||||||
new MSWindowsScreen(true, Settings::value(Settings::Core::UseHooks).toBool(), getEvents()), getEvents()
|
new MSWindowsScreen(true, Settings::value(Settings::Core::UseHooks).toBool(), getEvents()), getEvents()
|
||||||
);
|
);
|
||||||
#endif
|
#elif defined(Q_OS_MAC)
|
||||||
|
return new deskflow::Screen(new OSXScreen(getEvents(), true), getEvents());
|
||||||
#if defined(WINAPI_XWINDOWS) or defined(WINAPI_LIBEI)
|
#else
|
||||||
if (deskflow::platform::isWayland()) {
|
if (deskflow::platform::isWayland()) {
|
||||||
#if WINAPI_LIBEI
|
#if WINAPI_LIBEI
|
||||||
LOG_INFO("using ei screen for wayland");
|
LOG_INFO("using ei screen for wayland");
|
||||||
@ -414,17 +407,14 @@ deskflow::Screen *ServerApp::createScreen()
|
|||||||
throw XNoEiSupport();
|
throw XNoEiSupport();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
#if WINAPI_XWINDOWS
|
#if WINAPI_XWINDOWS
|
||||||
LOG_INFO("using legacy x windows screen");
|
LOG_INFO("using legacy x windows screen");
|
||||||
return new deskflow::Screen(
|
return new deskflow::Screen(
|
||||||
new XWindowsScreen(qPrintable(Settings::value(Settings::Core::Display).toString()), true, getEvents()),
|
new XWindowsScreen(qPrintable(Settings::value(Settings::Core::Display).toString()), true, getEvents()),
|
||||||
getEvents()
|
getEvents()
|
||||||
);
|
);
|
||||||
#elif WINAPI_CARBON
|
|
||||||
return new deskflow::Screen(new OSXScreen(getEvents(), true), getEvents());
|
|
||||||
#endif
|
#endif
|
||||||
|
#endif // end os check
|
||||||
}
|
}
|
||||||
|
|
||||||
PrimaryClient *ServerApp::openPrimaryClient(const std::string &name, deskflow::Screen *screen)
|
PrimaryClient *ServerApp::openPrimaryClient(const std::string &name, deskflow::Screen *screen)
|
||||||
@ -553,7 +543,7 @@ int ServerApp::mainLoop()
|
|||||||
// later. the timer installed by startServer() will take care of
|
// later. the timer installed by startServer() will take care of
|
||||||
// that.
|
// that.
|
||||||
|
|
||||||
#if WINAPI_CARBON
|
#if defined(Q_OS_MAC)
|
||||||
|
|
||||||
Thread thread(new TMethodJob<ServerApp>(this, &ServerApp::runEventsLoop, nullptr));
|
Thread thread(new TMethodJob<ServerApp>(this, &ServerApp::runEventsLoop, nullptr));
|
||||||
|
|
||||||
|
|||||||
@ -106,7 +106,6 @@ private:
|
|||||||
std::unique_ptr<ISocketFactory> getSocketFactory() const;
|
std::unique_ptr<ISocketFactory> getSocketFactory() const;
|
||||||
NetworkAddress getAddress(const NetworkAddress &address) const;
|
NetworkAddress getAddress(const NetworkAddress &address) const;
|
||||||
|
|
||||||
QString currentConfig() const;
|
|
||||||
bool m_suspended = false;
|
bool m_suspended = false;
|
||||||
Server *m_server = nullptr;
|
Server *m_server = nullptr;
|
||||||
ServerState m_serverState = ServerState::Uninitialized;
|
ServerState m_serverState = ServerState::Uninitialized;
|
||||||
|
|||||||
@ -12,7 +12,7 @@
|
|||||||
#if WINAPI_XWINDOWS
|
#if WINAPI_XWINDOWS
|
||||||
#include "deskflow/unix/X11LayoutsParser.h"
|
#include "deskflow/unix/X11LayoutsParser.h"
|
||||||
#include <X11/XKBlib.h>
|
#include <X11/XKBlib.h>
|
||||||
#elif WINAPI_CARBON
|
#elif defined(Q_OS_MAC)
|
||||||
#include <Carbon/Carbon.h>
|
#include <Carbon/Carbon.h>
|
||||||
#include <platform/OSXAutoTypes.h>
|
#include <platform/OSXAutoTypes.h>
|
||||||
#endif
|
#endif
|
||||||
@ -50,7 +50,7 @@ std::vector<std::string> AppUtilUnix::getKeyboardLayoutList()
|
|||||||
m_evdev = "/usr/share/X11/xkb/rules/evdev.xml";
|
m_evdev = "/usr/share/X11/xkb/rules/evdev.xml";
|
||||||
layoutLangCodes = X11LayoutsParser::getX11LanguageList(m_evdev);
|
layoutLangCodes = X11LayoutsParser::getX11LanguageList(m_evdev);
|
||||||
|
|
||||||
#elif WINAPI_CARBON
|
#elif defined(Q_OS_MAC)
|
||||||
CFStringRef keys[] = {kTISPropertyInputSourceCategory};
|
CFStringRef keys[] = {kTISPropertyInputSourceCategory};
|
||||||
CFStringRef values[] = {kTISCategoryKeyboardInputSource};
|
CFStringRef values[] = {kTISCategoryKeyboardInputSource};
|
||||||
AutoCFDictionary dict(
|
AutoCFDictionary dict(
|
||||||
@ -134,7 +134,7 @@ std::string AppUtilUnix::getCurrentLanguageCode()
|
|||||||
|
|
||||||
result = X11LayoutsParser::convertLayoutToISO(m_evdev, result);
|
result = X11LayoutsParser::convertLayoutToISO(m_evdev, result);
|
||||||
|
|
||||||
#elif WINAPI_CARBON
|
#elif defined(Q_OS_MAC)
|
||||||
auto layoutLanguages =
|
auto layoutLanguages =
|
||||||
(CFArrayRef)TISGetInputSourceProperty(TISCopyCurrentKeyboardInputSource(), kTISPropertyInputSourceLanguages);
|
(CFArrayRef)TISGetInputSourceProperty(TISCopyCurrentKeyboardInputSource(), kTISPropertyInputSourceLanguages);
|
||||||
char temporaryCString[128] = {0};
|
char temporaryCString[128] = {0};
|
||||||
|
|||||||
@ -58,8 +58,6 @@ add_library(${target} STATIC
|
|||||||
core/ServerConnection.h
|
core/ServerConnection.h
|
||||||
core/ServerMessage.cpp
|
core/ServerMessage.cpp
|
||||||
core/ServerMessage.h
|
core/ServerMessage.h
|
||||||
core/WaylandWarnings.cpp
|
|
||||||
core/WaylandWarnings.h
|
|
||||||
dialogs/AboutDialog.cpp
|
dialogs/AboutDialog.cpp
|
||||||
dialogs/AboutDialog.h
|
dialogs/AboutDialog.h
|
||||||
dialogs/AboutDialog.ui
|
dialogs/AboutDialog.ui
|
||||||
@ -119,6 +117,8 @@ add_library(${target} STATIC
|
|||||||
widgets/ScreenSetupView.h
|
widgets/ScreenSetupView.h
|
||||||
widgets/SearchWidget.h
|
widgets/SearchWidget.h
|
||||||
widgets/SearchWidget.cpp
|
widgets/SearchWidget.cpp
|
||||||
|
widgets/StatusBar.cpp
|
||||||
|
widgets/StatusBar.h
|
||||||
widgets/TrashScreenWidget.cpp
|
widgets/TrashScreenWidget.cpp
|
||||||
widgets/TrashScreenWidget.h
|
widgets/TrashScreenWidget.h
|
||||||
)
|
)
|
||||||
|
|||||||
@ -29,6 +29,7 @@
|
|||||||
#include "gui/ipc/DaemonIpcClient.h"
|
#include "gui/ipc/DaemonIpcClient.h"
|
||||||
#include "gui/widgets/LogDock.h"
|
#include "gui/widgets/LogDock.h"
|
||||||
#include "net/FingerprintDatabase.h"
|
#include "net/FingerprintDatabase.h"
|
||||||
|
#include "widgets/StatusBar.h"
|
||||||
|
|
||||||
#include <QCloseEvent>
|
#include <QCloseEvent>
|
||||||
#include <QDesktopServices>
|
#include <QDesktopServices>
|
||||||
@ -54,9 +55,6 @@
|
|||||||
|
|
||||||
using namespace deskflow::gui;
|
using namespace deskflow::gui;
|
||||||
|
|
||||||
using CoreConnectionState = CoreProcess::ConnectionState;
|
|
||||||
using CoreProcessState = CoreProcess::ProcessState;
|
|
||||||
|
|
||||||
MainWindow::MainWindow()
|
MainWindow::MainWindow()
|
||||||
: ui{std::make_unique<Ui::MainWindow>()},
|
: ui{std::make_unique<Ui::MainWindow>()},
|
||||||
m_coreProcess(m_serverConfig),
|
m_coreProcess(m_serverConfig),
|
||||||
@ -66,10 +64,7 @@ MainWindow::MainWindow()
|
|||||||
m_guiDupeChecker{new QLocalServer(this)},
|
m_guiDupeChecker{new QLocalServer(this)},
|
||||||
m_daemonIpcClient{new ipc::DaemonIpcClient(this)},
|
m_daemonIpcClient{new ipc::DaemonIpcClient(this)},
|
||||||
m_logDock{new LogDock(this)},
|
m_logDock{new LogDock(this)},
|
||||||
m_lblSecurityStatus{new QLabel(this)},
|
m_statusBar{new StatusBar(this)},
|
||||||
m_lblStatus{new QLabel(this)},
|
|
||||||
m_btnFingerprint{new QPushButton(this)},
|
|
||||||
m_btnUpdate{new QPushButton(this)},
|
|
||||||
m_menuFile{new QMenu(this)},
|
m_menuFile{new QMenu(this)},
|
||||||
m_menuEdit{new QMenu(this)},
|
m_menuEdit{new QMenu(this)},
|
||||||
m_menuView{new QMenu(this)},
|
m_menuView{new QMenu(this)},
|
||||||
@ -141,8 +136,6 @@ MainWindow::MainWindow()
|
|||||||
connectSlots();
|
connectSlots();
|
||||||
setupTrayIcon();
|
setupTrayIcon();
|
||||||
updateScreenName();
|
updateScreenName();
|
||||||
applyConfig();
|
|
||||||
restoreWindow();
|
|
||||||
|
|
||||||
qDebug().noquote() << "active settings path:" << Settings::settingsPath();
|
qDebug().noquote() << "active settings path:" << Settings::settingsPath();
|
||||||
|
|
||||||
@ -161,6 +154,10 @@ MainWindow::MainWindow()
|
|||||||
m_fingerprint = {QCryptographicHash::Sha256, TlsUtility::certFingerprint()};
|
m_fingerprint = {QCryptographicHash::Sha256, TlsUtility::certFingerprint()};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
applyConfig();
|
||||||
|
m_statusBar->setSecurityIcon(TlsUtility::isEnabled());
|
||||||
|
restoreWindow();
|
||||||
}
|
}
|
||||||
MainWindow::~MainWindow()
|
MainWindow::~MainWindow()
|
||||||
{
|
{
|
||||||
@ -218,6 +215,7 @@ void MainWindow::setupControls()
|
|||||||
|
|
||||||
ui->lineEditName->setValidator(new QRegularExpressionValidator(m_nameRegEx, this));
|
ui->lineEditName->setValidator(new QRegularExpressionValidator(m_nameRegEx, this));
|
||||||
ui->lineEditName->setVisible(false);
|
ui->lineEditName->setVisible(false);
|
||||||
|
ui->lineEditName->installEventFilter(this);
|
||||||
|
|
||||||
if (deskflow::platform::isMac()) {
|
if (deskflow::platform::isMac()) {
|
||||||
ui->rbModeServer->setAttribute(Qt::WA_MacShowFocusRect, false);
|
ui->rbModeServer->setAttribute(Qt::WA_MacShowFocusRect, false);
|
||||||
@ -226,31 +224,7 @@ void MainWindow::setupControls()
|
|||||||
} else {
|
} else {
|
||||||
ui->btnSaveServerConfig->setIconSize(QSize(22, 22));
|
ui->btnSaveServerConfig->setIconSize(QSize(22, 22));
|
||||||
}
|
}
|
||||||
|
setStatusBar(m_statusBar);
|
||||||
static const auto btnHeight = ui->statusBar->height() - 2;
|
|
||||||
static const auto btnSize = QSize(btnHeight, btnHeight);
|
|
||||||
static const auto iconSize = QSize(fontMetrics().height() + 2, fontMetrics().height() + 2);
|
|
||||||
|
|
||||||
m_btnFingerprint->setFlat(true);
|
|
||||||
m_btnFingerprint->setIcon(QIcon::fromTheme(QStringLiteral("fingerprint")));
|
|
||||||
m_btnFingerprint->setFixedSize(btnSize);
|
|
||||||
m_btnFingerprint->setIconSize(iconSize);
|
|
||||||
ui->statusBar->insertPermanentWidget(0, m_btnFingerprint);
|
|
||||||
|
|
||||||
m_lblSecurityStatus->setVisible(false);
|
|
||||||
m_lblSecurityStatus->setFixedSize(iconSize);
|
|
||||||
m_lblSecurityStatus->setScaledContents(true);
|
|
||||||
ui->statusBar->insertPermanentWidget(1, m_lblSecurityStatus);
|
|
||||||
|
|
||||||
ui->statusBar->insertPermanentWidget(2, m_lblStatus, 1);
|
|
||||||
|
|
||||||
m_btnUpdate->setVisible(false);
|
|
||||||
m_btnUpdate->setFlat(true);
|
|
||||||
m_btnUpdate->setLayoutDirection(Qt::RightToLeft);
|
|
||||||
m_btnUpdate->setIcon(QIcon::fromTheme(QStringLiteral("software-updates-release")));
|
|
||||||
m_btnUpdate->setFixedHeight(btnHeight);
|
|
||||||
m_btnUpdate->setIconSize(iconSize);
|
|
||||||
ui->statusBar->insertPermanentWidget(3, m_btnUpdate);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
@ -276,6 +250,7 @@ void MainWindow::connectSlots()
|
|||||||
connect(
|
connect(
|
||||||
&m_coreProcess, &CoreProcess::daemonIpcClientConnectionFailed, this, &MainWindow::daemonIpcClientConnectionFailed
|
&m_coreProcess, &CoreProcess::daemonIpcClientConnectionFailed, this, &MainWindow::daemonIpcClientConnectionFailed
|
||||||
);
|
);
|
||||||
|
connect(&m_coreProcess, &CoreProcess::securityLevelChanged, m_statusBar, &StatusBar::setSecurityLevel);
|
||||||
|
|
||||||
connect(m_actionAbout, &QAction::triggered, this, &MainWindow::openAboutDialog);
|
connect(m_actionAbout, &QAction::triggered, this, &MainWindow::openAboutDialog);
|
||||||
connect(m_actionClearSettings, &QAction::triggered, this, &MainWindow::clearSettings);
|
connect(m_actionClearSettings, &QAction::triggered, this, &MainWindow::clearSettings);
|
||||||
@ -290,8 +265,6 @@ void MainWindow::connectSlots()
|
|||||||
connect(m_actionRestartCore, &QAction::triggered, this, &MainWindow::resetCore);
|
connect(m_actionRestartCore, &QAction::triggered, this, &MainWindow::resetCore);
|
||||||
connect(m_actionStopCore, &QAction::triggered, this, &MainWindow::stopCore);
|
connect(m_actionStopCore, &QAction::triggered, this, &MainWindow::stopCore);
|
||||||
|
|
||||||
connect(&m_versionChecker, &VersionChecker::updateFound, this, &MainWindow::versionCheckerUpdateFound);
|
|
||||||
|
|
||||||
// Mac os tray will only show a menu
|
// Mac os tray will only show a menu
|
||||||
if (!deskflow::platform::isMac())
|
if (!deskflow::platform::isMac())
|
||||||
connect(m_trayIcon, &QSystemTrayIcon::activated, this, &MainWindow::trayIconActivated);
|
connect(m_trayIcon, &QSystemTrayIcon::activated, this, &MainWindow::trayIconActivated);
|
||||||
@ -319,14 +292,15 @@ void MainWindow::connectSlots()
|
|||||||
connect(ui->btnConfigureServer, &QPushButton::clicked, this, [this] { showConfigureServer(""); });
|
connect(ui->btnConfigureServer, &QPushButton::clicked, this, [this] { showConfigureServer(""); });
|
||||||
connect(ui->btnConfigureClient, &QPushButton::clicked, this, [this] { showConfigureClient(); });
|
connect(ui->btnConfigureClient, &QPushButton::clicked, this, [this] { showConfigureClient(); });
|
||||||
connect(ui->lblComputerName, &QLabel::linkActivated, this, &MainWindow::openSettings);
|
connect(ui->lblComputerName, &QLabel::linkActivated, this, &MainWindow::openSettings);
|
||||||
connect(m_btnFingerprint, &QPushButton::clicked, this, &MainWindow::showMyFingerprint);
|
|
||||||
|
|
||||||
connect(ui->rbModeServer, &QRadioButton::toggled, this, &MainWindow::coreModeToggled);
|
connect(ui->rbModeServer, &QRadioButton::toggled, this, &MainWindow::coreModeToggled);
|
||||||
connect(ui->rbModeClient, &QRadioButton::toggled, this, &MainWindow::coreModeToggled);
|
connect(ui->rbModeClient, &QRadioButton::toggled, this, &MainWindow::coreModeToggled);
|
||||||
|
|
||||||
connect(m_logDock->toggleViewAction(), &QAction::toggled, this, &MainWindow::toggleLogVisible);
|
connect(m_logDock->toggleViewAction(), &QAction::toggled, this, &MainWindow::toggleLogVisible);
|
||||||
|
|
||||||
connect(m_btnUpdate, &QPushButton::clicked, this, &MainWindow::openGetNewVersionUrl);
|
connect(m_statusBar, &StatusBar::requestShowMyFingerprints, this, &MainWindow::showMyFingerprint);
|
||||||
|
connect(m_statusBar, &StatusBar::requestUpdateVersion, this, &MainWindow::openGetNewVersionUrl);
|
||||||
|
connect(&m_versionChecker, &VersionChecker::updateFound, m_statusBar, &StatusBar::updateFound);
|
||||||
|
|
||||||
connect(m_guiDupeChecker, &QLocalServer::newConnection, this, &MainWindow::showAndActivate);
|
connect(m_guiDupeChecker, &QLocalServer::newConnection, this, &MainWindow::showAndActivate);
|
||||||
|
|
||||||
@ -384,7 +358,7 @@ void MainWindow::settingsChanged(const QString &key)
|
|||||||
qWarning() << tr("invalid certificate, generating a new one");
|
qWarning() << tr("invalid certificate, generating a new one");
|
||||||
TlsUtility::generateCertificate();
|
TlsUtility::generateCertificate();
|
||||||
}
|
}
|
||||||
updateSecurityIcon(m_lblSecurityStatus->isVisible());
|
updateSecurityIcon(m_statusBar->securityIconVisible());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -401,12 +375,6 @@ void MainWindow::trayIconActivated(QSystemTrayIcon::ActivationReason reason)
|
|||||||
isVisible() ? hide() : showAndActivate();
|
isVisible() ? hide() : showAndActivate();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::versionCheckerUpdateFound(const QString &version)
|
|
||||||
{
|
|
||||||
m_btnUpdate->setVisible(true);
|
|
||||||
m_btnUpdate->setToolTip(tr("A new version v%1 is available").arg(version));
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainWindow::coreProcessError(CoreProcess::Error error)
|
void MainWindow::coreProcessError(CoreProcess::Error error)
|
||||||
{
|
{
|
||||||
if (error == CoreProcess::Error::AddressMissing) {
|
if (error == CoreProcess::Error::AddressMissing) {
|
||||||
@ -415,12 +383,17 @@ void MainWindow::coreProcessError(CoreProcess::Error error)
|
|||||||
);
|
);
|
||||||
} else if (error == CoreProcess::Error::StartFailed) {
|
} else if (error == CoreProcess::Error::StartFailed) {
|
||||||
show();
|
show();
|
||||||
QMessageBox::warning(
|
auto message = tr("The Core executable could not be started.\n"
|
||||||
this, tr("Core cannot be started"),
|
"Please check if you have sufficient permissions to run %1.")
|
||||||
tr("The Core executable could not be successfully started, "
|
.arg(kCoreBinName);
|
||||||
"although it does exist. "
|
|
||||||
"Please check if you have sufficient permissions to run this program.")
|
if (Settings::value(Settings::Core::CoreMode) == Settings::CoreMode::Server) {
|
||||||
);
|
const auto mode =
|
||||||
|
Settings::value(Settings::Server::ExternalConfigFile).toBool() ? tr("read") : tr("read and write");
|
||||||
|
message.append(tr("\nAdditionally, check you are able to %1 the server config file: %2")
|
||||||
|
.arg(mode, Settings::serverConfigFile()));
|
||||||
|
}
|
||||||
|
QMessageBox::warning(this, kAppName, message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -428,13 +401,13 @@ void MainWindow::startCore()
|
|||||||
{
|
{
|
||||||
// Save current IP state when server starts
|
// Save current IP state when server starts
|
||||||
if (m_coreProcess.mode() == CoreMode::Server && Settings::value(Settings::Core::Interface).toString().isEmpty()) {
|
if (m_coreProcess.mode() == CoreMode::Server && Settings::value(Settings::Core::Interface).toString().isEmpty()) {
|
||||||
m_serverStartIPs = m_networkMonitor->getAvailableIPv4Addresses();
|
m_serverStartIPs = NetworkMonitor::validAddresses();
|
||||||
m_serverStartSuggestedIP = m_serverStartIPs.isEmpty() ? "" : m_serverStartIPs.first();
|
m_serverStartSuggestedIP = m_serverStartIPs.isEmpty() ? "" : m_serverStartIPs.first();
|
||||||
}
|
}
|
||||||
|
|
||||||
m_coreProcess.start();
|
|
||||||
m_actionStartCore->setVisible(false);
|
m_actionStartCore->setVisible(false);
|
||||||
m_actionRestartCore->setVisible(true);
|
m_actionRestartCore->setVisible(true);
|
||||||
|
m_coreProcess.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::stopCore()
|
void MainWindow::stopCore()
|
||||||
@ -499,7 +472,7 @@ void MainWindow::openGetNewVersionUrl() const
|
|||||||
|
|
||||||
void MainWindow::openSettings()
|
void MainWindow::openSettings()
|
||||||
{
|
{
|
||||||
auto dialog = SettingsDialog(this, m_serverConfig, m_coreProcess);
|
auto dialog = SettingsDialog(this, m_serverConfig);
|
||||||
|
|
||||||
if (dialog.exec() == QDialog::Accepted) {
|
if (dialog.exec() == QDialog::Accepted) {
|
||||||
Settings::save();
|
Settings::save();
|
||||||
@ -559,7 +532,7 @@ void MainWindow::updateModeControls()
|
|||||||
ui->lblIpAddresses->setVisible(isServer);
|
ui->lblIpAddresses->setVisible(isServer);
|
||||||
ui->clientOptions->setVisible(isClient);
|
ui->clientOptions->setVisible(isClient);
|
||||||
ui->lblNoMode->setVisible(!isServer && !isClient);
|
ui->lblNoMode->setVisible(!isServer && !isClient);
|
||||||
toggleCanRunCore((isServer || isClient) && (isClient && !ui->lineHostname->text().isEmpty()) || isServer);
|
toggleCanRunCore(canRunCore());
|
||||||
|
|
||||||
if (isServer) {
|
if (isServer) {
|
||||||
updateNetworkInfo();
|
updateNetworkInfo();
|
||||||
@ -610,23 +583,15 @@ void MainWindow::updateModeControlLabels()
|
|||||||
|
|
||||||
void MainWindow::updateSecurityIcon(bool visible)
|
void MainWindow::updateSecurityIcon(bool visible)
|
||||||
{
|
{
|
||||||
m_lblSecurityStatus->setVisible(visible);
|
m_statusBar->setSecurityIconVisible(visible);
|
||||||
if (!visible)
|
if (!visible)
|
||||||
return;
|
return;
|
||||||
|
m_statusBar->setSecurityIcon(TlsUtility::isEnabled());
|
||||||
bool secureSocket = TlsUtility::isEnabled();
|
|
||||||
|
|
||||||
const auto txt =
|
|
||||||
secureSocket ? tr("%1 Encryption Enabled").arg(m_coreProcess.secureSocketVersion()) : tr("Encryption Disabled");
|
|
||||||
m_lblSecurityStatus->setToolTip(txt);
|
|
||||||
|
|
||||||
const auto icon = QIcon::fromTheme(secureSocket ? QIcon::ThemeIcon::SecurityHigh : QIcon::ThemeIcon::SecurityLow);
|
|
||||||
m_lblSecurityStatus->setPixmap(icon.pixmap(QSize(32, 32)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::updateNetworkInfo()
|
void MainWindow::updateNetworkInfo()
|
||||||
{
|
{
|
||||||
updateIpLabel(m_networkMonitor->getAvailableIPv4Addresses());
|
updateIpLabel(NetworkMonitor::validAddresses());
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::serverConnectionConfigureClient(const QString &clientName)
|
void MainWindow::serverConnectionConfigureClient(const QString &clientName)
|
||||||
@ -645,7 +610,13 @@ void MainWindow::serverConnectionConfigureClient(const QString &clientName)
|
|||||||
|
|
||||||
void MainWindow::open()
|
void MainWindow::open()
|
||||||
{
|
{
|
||||||
Settings::value(Settings::Gui::Autohide).toBool() ? hide() : showAndActivate();
|
if (!Settings::value(Settings::Gui::Autohide).toBool())
|
||||||
|
showAndActivate();
|
||||||
|
else if (deskflow::platform::isMac())
|
||||||
|
// macOS to call hide after this function ends
|
||||||
|
QTimer::singleShot(1, this, &MainWindow::hide);
|
||||||
|
else
|
||||||
|
hide();
|
||||||
|
|
||||||
// if a critical error was shown just before the main window (i.e. on app
|
// if a critical error was shown just before the main window (i.e. on app
|
||||||
// load), it will be hidden behind the main window. therefore we need to raise
|
// load), it will be hidden behind the main window. therefore we need to raise
|
||||||
@ -674,11 +645,6 @@ void MainWindow::open()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::setStatus(const QString &status)
|
|
||||||
{
|
|
||||||
m_lblStatus->setText(status);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainWindow::createMenuBar()
|
void MainWindow::createMenuBar()
|
||||||
{
|
{
|
||||||
m_menuFile->addAction(m_actionStartCore);
|
m_menuFile->addAction(m_actionStartCore);
|
||||||
@ -902,71 +868,22 @@ void MainWindow::showFirstConnectedMessage()
|
|||||||
|
|
||||||
void MainWindow::updateStatus()
|
void MainWindow::updateStatus()
|
||||||
{
|
{
|
||||||
|
using enum ProcessState;
|
||||||
const auto connection = m_coreProcess.connectionState();
|
const auto connection = m_coreProcess.connectionState();
|
||||||
const auto process = m_coreProcess.processState();
|
const auto process = m_coreProcess.processState();
|
||||||
const bool isServer = (m_coreProcess.mode() == CoreMode::Server);
|
const bool isServer = (m_coreProcess.mode() == CoreMode::Server);
|
||||||
|
if (process == Stopped || process == Started) {
|
||||||
updateSecurityIcon(false);
|
|
||||||
switch (process) {
|
|
||||||
using enum CoreProcessState;
|
|
||||||
|
|
||||||
case Starting:
|
|
||||||
setStatus(tr("%1 is starting...").arg(kAppName));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case RetryPending:
|
|
||||||
setStatus(tr("%1 will retry in a moment...").arg(kAppName));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Stopping:
|
|
||||||
setStatus(tr("%1 is stopping...").arg(kAppName));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Stopped:
|
|
||||||
updateNetworkInfo();
|
updateNetworkInfo();
|
||||||
setStatus(tr("%1 is not running").arg(kAppName));
|
ui->btnEditName->setVisible(process == Stopped);
|
||||||
break;
|
}
|
||||||
|
m_statusBar->setStatus(connection, process, isServer);
|
||||||
case Started: {
|
|
||||||
updateNetworkInfo();
|
|
||||||
switch (connection) {
|
|
||||||
using enum CoreConnectionState;
|
|
||||||
|
|
||||||
case Listening: {
|
|
||||||
if (isServer) {
|
|
||||||
updateSecurityIcon(true);
|
|
||||||
setStatus(tr("%1 is waiting for clients").arg(kAppName));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
void MainWindow::coreProcessStateChanged(ProcessState state)
|
||||||
}
|
|
||||||
|
|
||||||
case Connecting:
|
|
||||||
setStatus(tr("%1 is connecting...").arg(kAppName));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Connected: {
|
|
||||||
updateSecurityIcon(true);
|
|
||||||
if (!isServer) {
|
|
||||||
setStatus(tr("%1 is connected as client of %2")
|
|
||||||
.arg(kAppName, Settings::value(Settings::Client::RemoteHost).toString()));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case Disconnected:
|
|
||||||
setStatus(tr("%1 is disconnected").arg(kAppName));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainWindow::coreProcessStateChanged(CoreProcessState state)
|
|
||||||
{
|
{
|
||||||
|
using enum ProcessState;
|
||||||
updateStatus();
|
updateStatus();
|
||||||
|
if (state == Started) {
|
||||||
if (state == CoreProcessState::Started) {
|
|
||||||
qDebug() << "recording that core has started";
|
qDebug() << "recording that core has started";
|
||||||
Settings::setValue(Settings::Gui::AutoStartCore, true);
|
Settings::setValue(Settings::Gui::AutoStartCore, true);
|
||||||
if (m_coreProcess.mode() == CoreMode::Server &&
|
if (m_coreProcess.mode() == CoreMode::Server &&
|
||||||
@ -977,8 +894,7 @@ void MainWindow::coreProcessStateChanged(CoreProcessState state)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state == CoreProcessState::Started || state == CoreProcessState::Starting ||
|
if (state == Started || state == Starting || state == RetryPending) {
|
||||||
state == CoreProcessState::RetryPending) {
|
|
||||||
disconnect(ui->btnToggleCore, &QPushButton::clicked, m_actionStartCore, &QAction::trigger);
|
disconnect(ui->btnToggleCore, &QPushButton::clicked, m_actionStartCore, &QAction::trigger);
|
||||||
connect(ui->btnToggleCore, &QPushButton::clicked, m_actionStopCore, &QAction::trigger, Qt::UniqueConnection);
|
connect(ui->btnToggleCore, &QPushButton::clicked, m_actionStopCore, &QAction::trigger, Qt::UniqueConnection);
|
||||||
|
|
||||||
@ -987,10 +903,7 @@ void MainWindow::coreProcessStateChanged(CoreProcessState state)
|
|||||||
m_actionRestartCore->setVisible(true);
|
m_actionRestartCore->setVisible(true);
|
||||||
m_actionStopCore->setEnabled(true);
|
m_actionStopCore->setEnabled(true);
|
||||||
|
|
||||||
if (state == CoreProcessState::Starting) {
|
if (state == Starting) {
|
||||||
if (deskflow::platform::isWayland()) {
|
|
||||||
m_waylandWarnings.showOnce(this);
|
|
||||||
}
|
|
||||||
saveSettings();
|
saveSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1006,7 +919,7 @@ void MainWindow::coreProcessStateChanged(CoreProcessState state)
|
|||||||
updateModeControlLabels();
|
updateModeControlLabels();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::coreConnectionStateChanged(CoreConnectionState state)
|
void MainWindow::coreConnectionStateChanged(ConnectionState state)
|
||||||
{
|
{
|
||||||
qDebug() << "core connection state changed: " << static_cast<int>(state);
|
qDebug() << "core connection state changed: " << static_cast<int>(state);
|
||||||
|
|
||||||
@ -1015,7 +928,7 @@ void MainWindow::coreConnectionStateChanged(CoreConnectionState state)
|
|||||||
// always assume connection is not secure when connection changes
|
// always assume connection is not secure when connection changes
|
||||||
// to anything except connected. the only way the padlock shows is
|
// to anything except connected. the only way the padlock shows is
|
||||||
// when the correct TLS version string is detected.
|
// when the correct TLS version string is detected.
|
||||||
if (state != CoreConnectionState::Connected) {
|
if (state != ConnectionState::Connected) {
|
||||||
secureSocket(false);
|
secureSocket(false);
|
||||||
} else if (isVisible()) {
|
} else if (isVisible()) {
|
||||||
showFirstConnectedMessage();
|
showFirstConnectedMessage();
|
||||||
@ -1024,7 +937,7 @@ void MainWindow::coreConnectionStateChanged(CoreConnectionState state)
|
|||||||
|
|
||||||
void MainWindow::updateLocalFingerprint()
|
void MainWindow::updateLocalFingerprint()
|
||||||
{
|
{
|
||||||
m_btnFingerprint->setVisible(TlsUtility::isEnabled() && !m_fingerprint.data.isEmpty());
|
m_statusBar->setBtnFingerprintVisible(TlsUtility::isEnabled() && !m_fingerprint.data.isEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::hide()
|
void MainWindow::hide()
|
||||||
@ -1055,6 +968,20 @@ void MainWindow::changeEvent(QEvent *e)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool MainWindow::eventFilter(QObject *obj, QEvent *event)
|
||||||
|
{
|
||||||
|
if (obj != ui->lineEditName || event->type() != QEvent::KeyPress)
|
||||||
|
return false;
|
||||||
|
if (const auto keyEvent = static_cast<QKeyEvent *>(event); keyEvent->key() != Qt::Key_Escape)
|
||||||
|
return false;
|
||||||
|
ui->lineEditName->hide();
|
||||||
|
ui->lblComputerName->show();
|
||||||
|
ui->btnEditName->show();
|
||||||
|
ui->lineEditName->setText(Settings::value(Settings::Core::ComputerName).toString());
|
||||||
|
toggleCanRunCore(canRunCore());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void MainWindow::updateText()
|
void MainWindow::updateText()
|
||||||
{
|
{
|
||||||
m_menuFile->setTitle(tr("&File"));
|
m_menuFile->setTitle(tr("&File"));
|
||||||
@ -1088,10 +1015,6 @@ void MainWindow::updateText()
|
|||||||
m_actionQuit->setShortcut(QKeySequence(tr("Ctrl+Q")));
|
m_actionQuit->setShortcut(QKeySequence(tr("Ctrl+Q")));
|
||||||
m_actionTrayQuit->setShortcut(QKeySequence(tr("Ctrl+Q")));
|
m_actionTrayQuit->setShortcut(QKeySequence(tr("Ctrl+Q")));
|
||||||
}
|
}
|
||||||
|
|
||||||
// General controls
|
|
||||||
m_btnFingerprint->setToolTip(tr("View local fingerprint"));
|
|
||||||
m_btnUpdate->setText(tr("Update available"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::showConfigureServer(const QString &message)
|
void MainWindow::showConfigureServer(const QString &message)
|
||||||
@ -1114,7 +1037,7 @@ void MainWindow::showConfigureClient()
|
|||||||
void MainWindow::secureSocket(bool secureSocket)
|
void MainWindow::secureSocket(bool secureSocket)
|
||||||
{
|
{
|
||||||
m_secureSocket = secureSocket;
|
m_secureSocket = secureSocket;
|
||||||
updateSecurityIcon(m_lblSecurityStatus->isVisible());
|
updateSecurityIcon(m_statusBar->securityIconVisible());
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::updateScreenName()
|
void MainWindow::updateScreenName()
|
||||||
@ -1145,6 +1068,7 @@ void MainWindow::showHostNameEditor()
|
|||||||
ui->lineEditName->show();
|
ui->lineEditName->show();
|
||||||
ui->lblComputerName->hide();
|
ui->lblComputerName->hide();
|
||||||
ui->btnEditName->hide();
|
ui->btnEditName->hide();
|
||||||
|
toggleCanRunCore(false);
|
||||||
ui->lineEditName->setFocus();
|
ui->lineEditName->setFocus();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1153,6 +1077,7 @@ void MainWindow::setHostName()
|
|||||||
ui->lineEditName->hide();
|
ui->lineEditName->hide();
|
||||||
ui->lblComputerName->show();
|
ui->lblComputerName->show();
|
||||||
ui->btnEditName->show();
|
ui->btnEditName->show();
|
||||||
|
toggleCanRunCore(canRunCore());
|
||||||
|
|
||||||
QString text = ui->lineEditName->text();
|
QString text = ui->lineEditName->text();
|
||||||
const auto screenName = Settings::value(Settings::Core::ComputerName).toString();
|
const auto screenName = Settings::value(Settings::Core::ComputerName).toString();
|
||||||
@ -1216,21 +1141,7 @@ void MainWindow::serverClientsChanged(const QStringList &clients)
|
|||||||
{
|
{
|
||||||
if (m_coreProcess.mode() != CoreMode::Server || !m_coreProcess.isStarted())
|
if (m_coreProcess.mode() != CoreMode::Server || !m_coreProcess.isStarted())
|
||||||
return;
|
return;
|
||||||
|
m_statusBar->setServerClients(clients);
|
||||||
if (clients.isEmpty()) {
|
|
||||||
setStatus(tr("%1 is waiting for clients").arg(kAppName));
|
|
||||||
ui->statusBar->setToolTip("");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//: Shown when in server mode and at least 1 client is connected
|
|
||||||
//: %1 is replaced by the app name
|
|
||||||
//: %2 will be a list of at least one client
|
|
||||||
//: %n will be replaced by the number of clients (n is >=1), it is not requried to be in the translation
|
|
||||||
setStatus(tr("%1 is connected, with %n client(s): %2", "", clients.size()).arg(kAppName, clients.join(", ")));
|
|
||||||
|
|
||||||
const auto toolTipString = clients.count() == 1 ? "" : tr("Clients:\n %1").arg(clients.join("\n"));
|
|
||||||
ui->statusBar->setToolTip(toolTipString);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::daemonIpcClientConnectionFailed()
|
void MainWindow::daemonIpcClientConnectionFailed()
|
||||||
@ -1262,12 +1173,22 @@ void MainWindow::remoteHostChanged(const QString &newRemoteHost)
|
|||||||
|
|
||||||
void MainWindow::showClientError(deskflow::client::ErrorType error, const QString &address)
|
void MainWindow::showClientError(deskflow::client::ErrorType error, const QString &address)
|
||||||
{
|
{
|
||||||
if (!Settings::value(Settings::Gui::ShowGenericClientFailureDialog).toBool() || !isVisible() || m_clientErrorVisible)
|
if (!isVisible() || m_clientErrorVisible || error != deskflow::client::ErrorType::AlreadyConnected)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
m_clientErrorVisible = true;
|
m_clientErrorVisible = true;
|
||||||
|
|
||||||
showAndActivate();
|
showAndActivate();
|
||||||
deskflow::gui::messages::showClientConnectError(this, error, address);
|
|
||||||
|
QMessageBox::warning(
|
||||||
|
this, tr("%1 Connection Error").arg(kAppName),
|
||||||
|
tr("<p>Failed to connect to the server '%1'.</p>"
|
||||||
|
"<p>A Client with your name is already connected to the server.</p>"
|
||||||
|
"Please ensure that you're using a unique name and that only a "
|
||||||
|
"single instance of the client process is running.</p>")
|
||||||
|
.arg(address)
|
||||||
|
);
|
||||||
|
|
||||||
m_clientErrorVisible = false;
|
m_clientErrorVisible = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1324,3 +1245,11 @@ void MainWindow::updateIpLabel(const QStringList &addresses)
|
|||||||
ui->lblIpAddresses->setText(labelText);
|
ui->lblIpAddresses->setText(labelText);
|
||||||
ui->lblIpAddresses->setToolTip(toolTipText);
|
ui->lblIpAddresses->setToolTip(toolTipText);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool MainWindow::canRunCore() const
|
||||||
|
{
|
||||||
|
const auto mode = m_coreProcess.mode();
|
||||||
|
const bool isServer = mode == Settings::CoreMode::Server;
|
||||||
|
const bool isClient = mode == Settings::CoreMode::Client;
|
||||||
|
return ((isServer || isClient) && (isClient && !ui->lineHostname->text().isEmpty()) || isServer);
|
||||||
|
}
|
||||||
|
|||||||
@ -24,7 +24,6 @@
|
|||||||
#include "gui/core/CoreProcess.h"
|
#include "gui/core/CoreProcess.h"
|
||||||
#include "gui/core/NetworkMonitor.h"
|
#include "gui/core/NetworkMonitor.h"
|
||||||
#include "gui/core/ServerConnection.h"
|
#include "gui/core/ServerConnection.h"
|
||||||
#include "gui/core/WaylandWarnings.h"
|
|
||||||
#include "net/Fingerprint.h"
|
#include "net/Fingerprint.h"
|
||||||
|
|
||||||
#ifdef Q_OS_MACOS
|
#ifdef Q_OS_MACOS
|
||||||
@ -48,6 +47,7 @@ class QLocalServer;
|
|||||||
|
|
||||||
class DeskflowApplication;
|
class DeskflowApplication;
|
||||||
class LogDock;
|
class LogDock;
|
||||||
|
class StatusBar;
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
class MainWindow;
|
class MainWindow;
|
||||||
@ -59,9 +59,11 @@ class DaemonIpcClient;
|
|||||||
|
|
||||||
class MainWindow : public QMainWindow
|
class MainWindow : public QMainWindow
|
||||||
{
|
{
|
||||||
|
using ConnectionState = deskflow::core::ConnectionState;
|
||||||
using CoreMode = Settings::CoreMode;
|
using CoreMode = Settings::CoreMode;
|
||||||
using CoreProcess = deskflow::gui::CoreProcess;
|
using CoreProcess = deskflow::gui::CoreProcess;
|
||||||
using NetworkMonitor = deskflow::gui::NetworkMonitor;
|
using NetworkMonitor = deskflow::gui::NetworkMonitor;
|
||||||
|
using ProcessState = deskflow::core::ProcessState;
|
||||||
|
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
@ -93,6 +95,7 @@ public:
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
void changeEvent(QEvent *e) override;
|
void changeEvent(QEvent *e) override;
|
||||||
|
bool eventFilter(QObject *obj, QEvent *event) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
@ -104,9 +107,9 @@ private:
|
|||||||
void settingsChanged(const QString &key = QString());
|
void settingsChanged(const QString &key = QString());
|
||||||
void serverConfigSaving();
|
void serverConfigSaving();
|
||||||
void coreProcessError(CoreProcess::Error error);
|
void coreProcessError(CoreProcess::Error error);
|
||||||
void coreConnectionStateChanged(CoreProcess::ConnectionState state);
|
void coreConnectionStateChanged(ConnectionState state);
|
||||||
void coreProcessStateChanged(CoreProcess::ProcessState state);
|
void coreProcessStateChanged(ProcessState state);
|
||||||
void versionCheckerUpdateFound(const QString &version);
|
|
||||||
void trayIconActivated(QSystemTrayIcon::ActivationReason reason);
|
void trayIconActivated(QSystemTrayIcon::ActivationReason reason);
|
||||||
void serverConnectionConfigureClient(const QString &clientName);
|
void serverConnectionConfigureClient(const QString &clientName);
|
||||||
|
|
||||||
@ -133,7 +136,6 @@ private:
|
|||||||
void setupTrayIcon();
|
void setupTrayIcon();
|
||||||
void applyConfig();
|
void applyConfig();
|
||||||
void setTrayIcon();
|
void setTrayIcon();
|
||||||
void setStatus(const QString &status);
|
|
||||||
void updateFromLogLine(const QString &line);
|
void updateFromLogLine(const QString &line);
|
||||||
void checkConnected(const QString &line);
|
void checkConnected(const QString &line);
|
||||||
void checkFingerprint(const QString &line);
|
void checkFingerprint(const QString &line);
|
||||||
@ -159,6 +161,7 @@ private:
|
|||||||
void handleNewClientPromptRequest(const QString &clientName, bool usePeerAuth);
|
void handleNewClientPromptRequest(const QString &clientName, bool usePeerAuth);
|
||||||
void updateIpLabel(const QStringList &addresses);
|
void updateIpLabel(const QStringList &addresses);
|
||||||
|
|
||||||
|
bool canRunCore() const;
|
||||||
/**
|
/**
|
||||||
* @brief showClientError
|
* @brief showClientError
|
||||||
* @param error Error Type
|
* @param error Error Type
|
||||||
@ -189,7 +192,6 @@ private:
|
|||||||
bool m_secureSocket = false;
|
bool m_secureSocket = false;
|
||||||
bool m_saveOnExit = true;
|
bool m_saveOnExit = true;
|
||||||
bool m_clientErrorVisible = false;
|
bool m_clientErrorVisible = false;
|
||||||
deskflow::gui::core::WaylandWarnings m_waylandWarnings;
|
|
||||||
ServerConfig m_serverConfig;
|
ServerConfig m_serverConfig;
|
||||||
deskflow::gui::CoreProcess m_coreProcess;
|
deskflow::gui::CoreProcess m_coreProcess;
|
||||||
deskflow::gui::ServerConnection m_serverConnection;
|
deskflow::gui::ServerConnection m_serverConnection;
|
||||||
@ -202,10 +204,7 @@ private:
|
|||||||
deskflow::gui::ipc::DaemonIpcClient *m_daemonIpcClient = nullptr;
|
deskflow::gui::ipc::DaemonIpcClient *m_daemonIpcClient = nullptr;
|
||||||
|
|
||||||
LogDock *m_logDock;
|
LogDock *m_logDock;
|
||||||
QLabel *m_lblSecurityStatus = nullptr;
|
StatusBar *m_statusBar = nullptr;
|
||||||
QLabel *m_lblStatus = nullptr;
|
|
||||||
QPushButton *m_btnFingerprint = nullptr;
|
|
||||||
QPushButton *m_btnUpdate = nullptr;
|
|
||||||
|
|
||||||
// Window Menu
|
// Window Menu
|
||||||
QMenu *m_menuFile = nullptr;
|
QMenu *m_menuFile = nullptr;
|
||||||
|
|||||||
@ -497,7 +497,6 @@
|
|||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QStatusBar" name="statusBar"/>
|
|
||||||
</widget>
|
</widget>
|
||||||
<resources/>
|
<resources/>
|
||||||
<connections/>
|
<connections/>
|
||||||
|
|||||||
@ -8,7 +8,6 @@
|
|||||||
|
|
||||||
#include "Logger.h"
|
#include "Logger.h"
|
||||||
|
|
||||||
#include "common/Enums.h"
|
|
||||||
#include "common/Settings.h"
|
#include "common/Settings.h"
|
||||||
#include "common/UrlConstants.h"
|
#include "common/UrlConstants.h"
|
||||||
#include "common/VersionInfo.h"
|
#include "common/VersionInfo.h"
|
||||||
@ -183,61 +182,6 @@ void showFirstConnectedMessage(QWidget *parent, bool closeToTray, bool enableSer
|
|||||||
QMessageBox::information(parent, title, message);
|
QMessageBox::information(parent, title, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
void showClientConnectError(QWidget *parent, deskflow::client::ErrorType error, const QString &address)
|
|
||||||
{
|
|
||||||
using enum deskflow::client::ErrorType;
|
|
||||||
if (error == NoError)
|
|
||||||
return;
|
|
||||||
|
|
||||||
auto message = QObject::tr("<p>Failed to connect to the server '%1'.</p>").arg(address);
|
|
||||||
|
|
||||||
if (error == AlreadyConnected) {
|
|
||||||
message.append(
|
|
||||||
QObject::tr( //
|
|
||||||
"<p>A Client with your name is already connected to the server.</p>"
|
|
||||||
"Please ensure that you're using a unique name and that only a "
|
|
||||||
"single instance of the client process is running.</p>"
|
|
||||||
)
|
|
||||||
);
|
|
||||||
} else if (error == HostnameError) {
|
|
||||||
message.append(
|
|
||||||
QObject::tr( //
|
|
||||||
"<p>Please try to connect to the server using the server IP address "
|
|
||||||
"instead of the hostname. </p>"
|
|
||||||
"<p>If that doesn't work, please check your TLS and "
|
|
||||||
"firewall settings.</p>"
|
|
||||||
)
|
|
||||||
);
|
|
||||||
} else if (error == GenericError) {
|
|
||||||
message.append(QObject::tr("<p>Please check your TLS and firewall settings.</p>"));
|
|
||||||
} else {
|
|
||||||
qFatal("unknown client error");
|
|
||||||
}
|
|
||||||
|
|
||||||
auto title = QObject::tr("%1 Connection Error").arg(kAppName);
|
|
||||||
|
|
||||||
if (error != HostnameError) {
|
|
||||||
QMessageBox::warning(parent, title, message);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto dialog = QMessageBox(parent);
|
|
||||||
dialog.setWindowTitle(title);
|
|
||||||
dialog.setText(message);
|
|
||||||
dialog.setWindowModality(Qt::ApplicationModal);
|
|
||||||
dialog.setIcon(QMessageBox::Information);
|
|
||||||
|
|
||||||
auto cbNoShowAgain = new QCheckBox(QObject::tr("Do not show this message again"));
|
|
||||||
|
|
||||||
QObject::connect(cbNoShowAgain, &QCheckBox::toggled, [](bool enabled) {
|
|
||||||
Settings::setValue(Settings::Gui::ShowGenericClientFailureDialog, !enabled);
|
|
||||||
});
|
|
||||||
|
|
||||||
dialog.setCheckBox(cbNoShowAgain);
|
|
||||||
dialog.setDefaultButton(QMessageBox::Ok);
|
|
||||||
dialog.exec();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool showNewClientPrompt(QWidget *parent, const QString &clientName, bool serverRequiresPeerAuth)
|
bool showNewClientPrompt(QWidget *parent, const QString &clientName, bool serverRequiresPeerAuth)
|
||||||
{
|
{
|
||||||
if (serverRequiresPeerAuth) {
|
if (serverRequiresPeerAuth) {
|
||||||
@ -280,24 +224,6 @@ void showReadOnlySettings(QWidget *parent, const QString &systemSettingsPath)
|
|||||||
QMessageBox::information(parent, title, message);
|
QMessageBox::information(parent, title, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
void showWaylandLibraryError(QWidget *parent)
|
|
||||||
{
|
|
||||||
QMessageBox::critical(
|
|
||||||
parent, kAppName,
|
|
||||||
QObject::tr(
|
|
||||||
"<p>Sorry, while this version of %1 does support Wayland, "
|
|
||||||
"this build was not linked with one or more of the required "
|
|
||||||
"libraries.</p>"
|
|
||||||
"<p>Please either switch to X from your login screen or use a build "
|
|
||||||
"that uses the correct libraries.</p>"
|
|
||||||
"<p>If you think this is incorrect, please "
|
|
||||||
R"(<a href="%2">report a bug</a>.</p>)"
|
|
||||||
"<p>Please check the logs for more information.</p>"
|
|
||||||
)
|
|
||||||
.arg(kAppName, kUrlHelp)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool showUpdateCheckOption(QWidget *parent)
|
bool showUpdateCheckOption(QWidget *parent)
|
||||||
{
|
{
|
||||||
QMessageBox message(parent);
|
QMessageBox message(parent);
|
||||||
|
|||||||
@ -25,16 +25,12 @@ void showFirstConnectedMessage(QWidget *parent, bool closeToTray, bool enableSer
|
|||||||
|
|
||||||
void showCloseReminder(QWidget *parent);
|
void showCloseReminder(QWidget *parent);
|
||||||
|
|
||||||
void showClientConnectError(QWidget *parent, deskflow::client::ErrorType error, const QString &address);
|
|
||||||
|
|
||||||
bool showNewClientPrompt(QWidget *parent, const QString &clientName, bool serverRequiresPeerAuth = false);
|
bool showNewClientPrompt(QWidget *parent, const QString &clientName, bool serverRequiresPeerAuth = false);
|
||||||
|
|
||||||
bool showClearSettings(QWidget *parent);
|
bool showClearSettings(QWidget *parent);
|
||||||
|
|
||||||
void showReadOnlySettings(QWidget *parent, const QString &systemSettingsPath);
|
void showReadOnlySettings(QWidget *parent, const QString &systemSettingsPath);
|
||||||
|
|
||||||
void showWaylandLibraryError(QWidget *parent);
|
|
||||||
|
|
||||||
bool showUpdateCheckOption(QWidget *parent);
|
bool showUpdateCheckOption(QWidget *parent);
|
||||||
|
|
||||||
bool showDaemonOffline(QWidget *parent);
|
bool showDaemonOffline(QWidget *parent);
|
||||||
|
|||||||
@ -14,6 +14,11 @@
|
|||||||
#include "OSXHelpers.h"
|
#include "OSXHelpers.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef Q_OS_LINUX
|
||||||
|
#include <signal.h>
|
||||||
|
#include <sys/prctl.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <QCoreApplication>
|
#include <QCoreApplication>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
@ -203,6 +208,14 @@ void CoreProcess::startForegroundProcess(const QStringList &args)
|
|||||||
const auto quoted = makeQuotedArgs(m_appPath, args);
|
const auto quoted = makeQuotedArgs(m_appPath, args);
|
||||||
qInfo("running command: %s", qPrintable(quoted));
|
qInfo("running command: %s", qPrintable(quoted));
|
||||||
|
|
||||||
|
#ifdef Q_OS_LINUX
|
||||||
|
m_process->setChildProcessModifier([] {
|
||||||
|
// the core process becomes orphaned when the gui process exits abruptly (e.g. with kill -9),
|
||||||
|
// so ensure the os also kills the core when that happens to the gui.
|
||||||
|
prctl(PR_SET_PDEATHSIG, SIGTERM);
|
||||||
|
});
|
||||||
|
#endif
|
||||||
|
|
||||||
m_process->start(m_appPath, args);
|
m_process->start(m_appPath, args);
|
||||||
|
|
||||||
if (m_process->waitForStarted()) {
|
if (m_process->waitForStarted()) {
|
||||||
@ -330,11 +343,17 @@ void CoreProcess::start(std::optional<ProcessMode> processModeOption)
|
|||||||
QStringList args = {coreMode};
|
QStringList args = {coreMode};
|
||||||
|
|
||||||
if (m_mode == Settings::CoreMode::Server) {
|
if (m_mode == Settings::CoreMode::Server) {
|
||||||
const auto configFilename = persistServerConfig();
|
const auto [hasNeededPermissions, configFilename] = persistServerConfig();
|
||||||
if (configFilename.isEmpty()) {
|
if (configFilename.isEmpty()) {
|
||||||
qFatal("config file name empty for server args");
|
qFatal("config file name empty for server args");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (!hasNeededPermissions) {
|
||||||
|
setProcessState(ProcessState::Stopped);
|
||||||
|
setConnectionState(ConnectionState::Disconnected);
|
||||||
|
Q_EMIT error(Error::StartFailed);
|
||||||
|
return;
|
||||||
|
}
|
||||||
qInfo("core config file: %s", qPrintable(configFilename));
|
qInfo("core config file: %s", qPrintable(configFilename));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -417,21 +436,22 @@ void CoreProcess::cleanup()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QString CoreProcess::persistServerConfig() const
|
QPair<bool, QString> CoreProcess::persistServerConfig() const
|
||||||
{
|
{
|
||||||
if (Settings::value(Settings::Server::ExternalConfig).toBool()) {
|
if (Settings::value(Settings::Server::ExternalConfig).toBool()) {
|
||||||
return Settings::value(Settings::Server::ExternalConfigFile).toString();
|
return {Settings::isServerConfigFileReadable(), Settings::value(Settings::Server::ExternalConfigFile).toString()};
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto configFilePath = Settings::defaultValue(Settings::Server::ExternalConfigFile).toString();
|
const auto configFilePath = Settings::defaultValue(Settings::Server::ExternalConfigFile).toString();
|
||||||
QFile configFile(configFilePath);
|
QFile configFile(configFilePath);
|
||||||
if (!configFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
|
if (!configFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
|
||||||
qFatal("failed to open core config file for write: %s", qPrintable(configFile.fileName()));
|
qWarning() << "failed to open core config file for write:" << configFilePath;
|
||||||
|
return {false, configFile.fileName()};
|
||||||
}
|
}
|
||||||
|
|
||||||
m_serverConfig.save(configFile);
|
m_serverConfig.save(configFile);
|
||||||
configFile.close();
|
configFile.close();
|
||||||
return configFile.fileName();
|
return {Settings::isServerConfigFileReadable(), configFile.fileName()};
|
||||||
}
|
}
|
||||||
|
|
||||||
void CoreProcess::setConnectionState(ConnectionState state)
|
void CoreProcess::setConnectionState(ConnectionState state)
|
||||||
@ -498,7 +518,11 @@ bool CoreProcess::checkSecureSocket(const QString &line)
|
|||||||
}
|
}
|
||||||
|
|
||||||
Q_EMIT secureSocket(true);
|
Q_EMIT secureSocket(true);
|
||||||
m_secureSocketVersion = line.mid(index + tlsCheckString.size());
|
if (const auto ssv = line.mid(index + tlsCheckString.size()); ssv != m_secureSocketVersion) {
|
||||||
|
m_secureSocketVersion = ssv;
|
||||||
|
Q_EMIT securityLevelChanged(ssv);
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "common/Enums.h"
|
||||||
#include "common/Settings.h"
|
#include "common/Settings.h"
|
||||||
#include "gui/FileTail.h"
|
#include "gui/FileTail.h"
|
||||||
#include "gui/config/IServerConfig.h"
|
#include "gui/config/IServerConfig.h"
|
||||||
@ -24,7 +25,9 @@ class DaemonIpcClient;
|
|||||||
|
|
||||||
class CoreProcess : public QObject
|
class CoreProcess : public QObject
|
||||||
{
|
{
|
||||||
|
using ConnectionState = deskflow::core::ConnectionState;
|
||||||
using ProcessMode = Settings::ProcessMode;
|
using ProcessMode = Settings::ProcessMode;
|
||||||
|
using ProcessState = deskflow::core::ProcessState;
|
||||||
using IServerConfig = deskflow::gui::IServerConfig;
|
using IServerConfig = deskflow::gui::IServerConfig;
|
||||||
|
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
@ -35,23 +38,6 @@ public:
|
|||||||
AddressMissing,
|
AddressMissing,
|
||||||
StartFailed
|
StartFailed
|
||||||
};
|
};
|
||||||
enum class ProcessState
|
|
||||||
{
|
|
||||||
Starting,
|
|
||||||
Started,
|
|
||||||
Stopping,
|
|
||||||
Stopped,
|
|
||||||
RetryPending
|
|
||||||
};
|
|
||||||
Q_ENUM(ProcessState)
|
|
||||||
|
|
||||||
enum class ConnectionState
|
|
||||||
{
|
|
||||||
Disconnected,
|
|
||||||
Connecting,
|
|
||||||
Connected,
|
|
||||||
Listening
|
|
||||||
};
|
|
||||||
|
|
||||||
explicit CoreProcess(const IServerConfig &serverConfig);
|
explicit CoreProcess(const IServerConfig &serverConfig);
|
||||||
|
|
||||||
@ -98,10 +84,11 @@ public:
|
|||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
void error(deskflow::gui::CoreProcess::Error error);
|
void error(deskflow::gui::CoreProcess::Error error);
|
||||||
void logLine(const QString &line);
|
void logLine(const QString &line);
|
||||||
void connectionStateChanged(deskflow::gui::CoreProcess::ConnectionState state);
|
void connectionStateChanged(deskflow::core::ConnectionState state);
|
||||||
void processStateChanged(deskflow::gui::CoreProcess::ProcessState state);
|
void processStateChanged(deskflow::core::ProcessState state);
|
||||||
void secureSocket(bool enabled);
|
void secureSocket(bool enabled);
|
||||||
void daemonIpcClientConnectionFailed();
|
void daemonIpcClientConnectionFailed();
|
||||||
|
void securityLevelChanged(QString securityLevel);
|
||||||
|
|
||||||
private Q_SLOTS:
|
private Q_SLOTS:
|
||||||
void onProcessFinished(int exitCode, QProcess::ExitStatus);
|
void onProcessFinished(int exitCode, QProcess::ExitStatus);
|
||||||
@ -114,7 +101,7 @@ private:
|
|||||||
void startProcessFromDaemon(const QStringList &args);
|
void startProcessFromDaemon(const QStringList &args);
|
||||||
void stopForegroundProcess() const;
|
void stopForegroundProcess() const;
|
||||||
void stopProcessFromDaemon();
|
void stopProcessFromDaemon();
|
||||||
QString persistServerConfig() const;
|
QPair<bool, QString> persistServerConfig() const;
|
||||||
void setConnectionState(ConnectionState state);
|
void setConnectionState(ConnectionState state);
|
||||||
void setProcessState(ProcessState state);
|
void setProcessState(ProcessState state);
|
||||||
void checkLogLine(const QString &line);
|
void checkLogLine(const QString &line);
|
||||||
|
|||||||
@ -19,7 +19,7 @@ bool NetworkMonitor::isVirtualInterface(const QString &interfaceName)
|
|||||||
{
|
{
|
||||||
// Common virtual network interface patterns
|
// Common virtual network interface patterns
|
||||||
static const auto virtualRegEx = QRegularExpression(
|
static const auto virtualRegEx = QRegularExpression(
|
||||||
QStringLiteral("^vboxnet|vmnet|docker|virbr|veth|br\\-|tun|utun|awdl|p2p|llw|anpi|tap"),
|
QStringLiteral("^vboxnet|vmnet|docker|virbr|veth|br\\-|tun|utun|awdl|p2p|llw|anpi|tap|vEth"),
|
||||||
QRegularExpression::CaseInsensitiveOption
|
QRegularExpression::CaseInsensitiveOption
|
||||||
);
|
);
|
||||||
return virtualRegEx.match(interfaceName).hasMatch();
|
return virtualRegEx.match(interfaceName).hasMatch();
|
||||||
@ -52,10 +52,12 @@ void NetworkMonitor::stopMonitoring()
|
|||||||
m_isMonitoring = false;
|
m_isMonitoring = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList NetworkMonitor::getAvailableIPv4Addresses() const
|
QStringList NetworkMonitor::validAddresses()
|
||||||
{
|
{
|
||||||
QList<QHostAddress> physicalIPs;
|
QList<QHostAddress> physicalIP4;
|
||||||
QList<QHostAddress> virtualIPs;
|
QList<QHostAddress> physicalIP6;
|
||||||
|
QList<QHostAddress> virtualIP4;
|
||||||
|
QList<QHostAddress> virtualIP6;
|
||||||
QSet<QHostAddress> uniqueAddresses;
|
QSet<QHostAddress> uniqueAddresses;
|
||||||
|
|
||||||
const auto allInterfaces = QNetworkInterface::allInterfaces();
|
const auto allInterfaces = QNetworkInterface::allInterfaces();
|
||||||
@ -66,39 +68,57 @@ QStringList NetworkMonitor::getAvailableIPv4Addresses() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
const bool isP2P = (interface.flags() & QNetworkInterface::IsPointToPoint);
|
const bool isP2P = (interface.flags() & QNetworkInterface::IsPointToPoint);
|
||||||
const bool isVirtual = isVirtualInterface(interface.name()) || isP2P;
|
const bool isVirtualType = interface.type() == QNetworkInterface::Virtual;
|
||||||
|
const bool isVirtual = isVirtualInterface(interface.humanReadableName()) || isP2P || isVirtualType;
|
||||||
const auto addressEntries = interface.addressEntries();
|
const auto addressEntries = interface.addressEntries();
|
||||||
|
|
||||||
for (const auto &entry : addressEntries) {
|
for (const auto &entry : addressEntries) {
|
||||||
const QHostAddress address = entry.ip();
|
const QHostAddress address = entry.ip();
|
||||||
|
|
||||||
if (address.protocol() != QAbstractSocket::IPv4Protocol || address.isLinkLocal() || address.isLoopback() ||
|
if (address.isLinkLocal() || address.isLoopback() || uniqueAddresses.contains(address)) {
|
||||||
uniqueAddresses.contains(address)) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
uniqueAddresses.insert(address);
|
uniqueAddresses.insert(address);
|
||||||
|
|
||||||
if (isVirtual) {
|
if (address.protocol() == QHostAddress::IPv6Protocol) {
|
||||||
virtualIPs.append(address);
|
if (isVirtual)
|
||||||
|
virtualIP6.append(address);
|
||||||
|
else
|
||||||
|
physicalIP6.append(address);
|
||||||
} else {
|
} else {
|
||||||
physicalIPs.append(address);
|
if (isVirtual)
|
||||||
|
virtualIP4.append(address);
|
||||||
|
else
|
||||||
|
physicalIP4.append(address);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::ranges::sort(physicalIPs, [](const QHostAddress &a, const QHostAddress &b) {
|
std::ranges::sort(physicalIP4, [](const QHostAddress &a, const QHostAddress &b) {
|
||||||
if (a.isPrivateUse() != b.isPrivateUse())
|
if (a.isPrivateUse() != b.isPrivateUse())
|
||||||
return a.isPrivateUse();
|
return a.isPrivateUse();
|
||||||
return a.toIPv4Address() < b.toIPv4Address();
|
return a.toIPv4Address() < b.toIPv4Address();
|
||||||
});
|
});
|
||||||
|
|
||||||
std::ranges::sort(virtualIPs, [](const QHostAddress &a, const QHostAddress &b) {
|
std::ranges::sort(virtualIP4, [](const QHostAddress &a, const QHostAddress &b) {
|
||||||
return a.toIPv4Address() < b.toIPv4Address();
|
return a.toIPv4Address() < b.toIPv4Address();
|
||||||
});
|
});
|
||||||
|
|
||||||
auto result = physicalIPs;
|
std::ranges::sort(physicalIP6, [](const QHostAddress &a, const QHostAddress &b) {
|
||||||
result.append(virtualIPs);
|
if (a.isPrivateUse() != b.isPrivateUse())
|
||||||
|
return a.isPrivateUse();
|
||||||
|
return a.toString() < b.toString();
|
||||||
|
});
|
||||||
|
|
||||||
|
std::ranges::sort(virtualIP6, [](const QHostAddress &a, const QHostAddress &b) {
|
||||||
|
return a.toString() < b.toString();
|
||||||
|
});
|
||||||
|
|
||||||
|
auto result = physicalIP4;
|
||||||
|
result.append(virtualIP4);
|
||||||
|
result.append(physicalIP6);
|
||||||
|
result.append(virtualIP6);
|
||||||
|
|
||||||
QStringList ipList;
|
QStringList ipList;
|
||||||
for (const auto &host : result) {
|
for (const auto &host : result) {
|
||||||
@ -117,7 +137,7 @@ void NetworkMonitor::setIpAddresses(const QStringList &newAddresses)
|
|||||||
|
|
||||||
void NetworkMonitor::updateNetworkState()
|
void NetworkMonitor::updateNetworkState()
|
||||||
{
|
{
|
||||||
setIpAddresses(getAvailableIPv4Addresses());
|
setIpAddresses(validAddresses());
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace deskflow::gui
|
} // namespace deskflow::gui
|
||||||
|
|||||||
@ -47,10 +47,10 @@ public:
|
|||||||
void stopMonitoring();
|
void stopMonitoring();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get list of all available IPv4 addresses (excluding local and link-local addresses)
|
* @brief Get list of all available IP addresses (excluding local and link-local addresses)
|
||||||
* @return IPv4 address list
|
* @return IP address list
|
||||||
*/
|
*/
|
||||||
QStringList getAvailableIPv4Addresses() const;
|
static QStringList validAddresses();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Check if a network interface is virtual
|
* @brief Check if a network interface is virtual
|
||||||
|
|||||||
@ -1,31 +0,0 @@
|
|||||||
/*
|
|
||||||
* Deskflow -- mouse and keyboard sharing utility
|
|
||||||
* SPDX-FileCopyrightText: (C) 2025 Chris Rizzitello <sithlord48@gmail.com>
|
|
||||||
* SPDX-FileCopyrightText: (C) 2024 Symless Ltd.
|
|
||||||
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "WaylandWarnings.h"
|
|
||||||
|
|
||||||
#include "Messages.h"
|
|
||||||
#include "common/Settings.h"
|
|
||||||
|
|
||||||
namespace deskflow::gui::core {
|
|
||||||
|
|
||||||
void WaylandWarnings::showOnce(QWidget *parent)
|
|
||||||
{
|
|
||||||
const auto mode = Settings::value(Settings::Core::CoreMode).value<Settings::CoreMode>();
|
|
||||||
const bool portalIcProblem = !m_hasPortalInputCapture && mode == Settings::CoreMode::Server;
|
|
||||||
|
|
||||||
if (!m_hasEi || !m_hasPortal || portalIcProblem) {
|
|
||||||
if (!m_errorShown) {
|
|
||||||
m_errorShown = true;
|
|
||||||
messages::showWaylandLibraryError(parent);
|
|
||||||
} else {
|
|
||||||
qWarning("missing required wayland lib(s) or feature");
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace deskflow::gui::core
|
|
||||||
@ -1,43 +0,0 @@
|
|||||||
/*
|
|
||||||
* Deskflow -- mouse and keyboard sharing utility
|
|
||||||
* SPDX-FileCopyrightText: (C) 2025 Chris Rizzitello <sithlord48@gmail.com>
|
|
||||||
* SPDX-FileCopyrightText: (C) 2024 Symless Ltd.
|
|
||||||
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <QWidget>
|
|
||||||
|
|
||||||
namespace deskflow::gui::core {
|
|
||||||
|
|
||||||
class WaylandWarnings
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit WaylandWarnings() = default;
|
|
||||||
|
|
||||||
void showOnce(QWidget *parent);
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool m_errorShown{false};
|
|
||||||
|
|
||||||
#if WINAPI_LIBEI
|
|
||||||
const bool m_hasEi = true;
|
|
||||||
#else
|
|
||||||
const bool m_hasEi = false;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if WINAPI_LIBPORTAL
|
|
||||||
const bool m_hasPortal = true;
|
|
||||||
#else
|
|
||||||
const bool m_hasPortal = false;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if HAVE_LIBPORTAL_INPUTCAPTURE
|
|
||||||
const bool m_hasPortalInputCapture = true;
|
|
||||||
#else
|
|
||||||
const bool m_hasPortalInputCapture = false;
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace deskflow::gui::core
|
|
||||||
@ -23,15 +23,18 @@
|
|||||||
|
|
||||||
using namespace deskflow::gui;
|
using namespace deskflow::gui;
|
||||||
|
|
||||||
SettingsDialog::SettingsDialog(QWidget *parent, const IServerConfig &serverConfig, const CoreProcess &coreProcess)
|
SettingsDialog::SettingsDialog(QWidget *parent, const IServerConfig &serverConfig)
|
||||||
: QDialog(parent),
|
: QDialog(parent),
|
||||||
ui{std::make_unique<Ui::SettingsDialog>()},
|
ui{std::make_unique<Ui::SettingsDialog>()},
|
||||||
m_serverConfig(serverConfig),
|
m_serverConfig(serverConfig)
|
||||||
m_coreProcess(coreProcess)
|
|
||||||
{
|
{
|
||||||
|
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
|
|
||||||
|
// these are enabled by the control next to them
|
||||||
|
ui->lineCommandEnter->setEnabled(false);
|
||||||
|
ui->lineCommandExit->setEnabled(false);
|
||||||
|
|
||||||
// set up the language combo
|
// set up the language combo
|
||||||
I18N::reDetectLanguages();
|
I18N::reDetectLanguages();
|
||||||
ui->comboLanguage->addItems(I18N::detectedLanguages());
|
ui->comboLanguage->addItems(I18N::detectedLanguages());
|
||||||
@ -51,14 +54,19 @@ SettingsDialog::SettingsDialog(QWidget *parent, const IServerConfig &serverConfi
|
|||||||
ui->tabWidget->setCurrentIndex(0);
|
ui->tabWidget->setCurrentIndex(0);
|
||||||
|
|
||||||
// Populate the list of IP addresses
|
// Populate the list of IP addresses
|
||||||
NetworkMonitor networkMonitor(this);
|
const auto validAddresses = NetworkMonitor::validAddresses();
|
||||||
for (const auto &address : networkMonitor.getAvailableIPv4Addresses()) {
|
for (const auto &address : validAddresses) {
|
||||||
QString ipString = address;
|
QString ipString = address;
|
||||||
if (ui->comboInterface->findText(ipString) == -1) {
|
if (ui->comboInterface->findText(ipString) == -1) {
|
||||||
ui->comboInterface->addItem(ipString, ipString);
|
ui->comboInterface->addItem(ipString, ipString);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (const auto interface = Settings::value(Settings::Core::Interface).toString();
|
||||||
|
!interface.isEmpty() && (ui->comboInterface->findData(interface) == -1)) {
|
||||||
|
ui->comboInterface->addItem(interface, interface);
|
||||||
|
}
|
||||||
|
|
||||||
loadFromConfig();
|
loadFromConfig();
|
||||||
|
|
||||||
adjustSize();
|
adjustSize();
|
||||||
@ -66,6 +74,7 @@ SettingsDialog::SettingsDialog(QWidget *parent, const IServerConfig &serverConfi
|
|||||||
setFixedHeight(height());
|
setFixedHeight(height());
|
||||||
setWindowFlags((windowFlags() | Qt::CustomizeWindowHint) & ~Qt::WindowMinMaxButtonsHint);
|
setWindowFlags((windowFlags() | Qt::CustomizeWindowHint) & ~Qt::WindowMinMaxButtonsHint);
|
||||||
|
|
||||||
|
setButtonBoxEnabledButtons();
|
||||||
initConnections();
|
initConnections();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,6 +93,14 @@ void SettingsDialog::initConnections() const
|
|||||||
|
|
||||||
connect(ui->buttonBox, &QDialogButtonBox::accepted, this, &SettingsDialog::accept);
|
connect(ui->buttonBox, &QDialogButtonBox::accepted, this, &SettingsDialog::accept);
|
||||||
connect(ui->buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
|
connect(ui->buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
|
||||||
|
connect(ui->buttonBox->button(QDialogButtonBox::Reset), &QPushButton::clicked, this, &SettingsDialog::loadFromConfig);
|
||||||
|
connect(
|
||||||
|
ui->buttonBox->button(QDialogButtonBox::RestoreDefaults), &QPushButton::clicked, this,
|
||||||
|
&SettingsDialog::resetToDefault
|
||||||
|
);
|
||||||
|
|
||||||
|
connect(ui->cbRunEnterCommand, &QCheckBox::toggled, ui->lineCommandEnter, &QLineEdit::setEnabled);
|
||||||
|
connect(ui->cbRunExitCommand, &QCheckBox::toggled, ui->lineCommandExit, &QLineEdit::setEnabled);
|
||||||
|
|
||||||
connect(ui->groupSecurity, &QGroupBox::toggled, this, &SettingsDialog::updateTlsControlsEnabled);
|
connect(ui->groupSecurity, &QGroupBox::toggled, this, &SettingsDialog::updateTlsControlsEnabled);
|
||||||
connect(ui->groupService, &QGroupBox::toggled, this, &SettingsDialog::updateControls);
|
connect(ui->groupService, &QGroupBox::toggled, this, &SettingsDialog::updateControls);
|
||||||
@ -91,12 +108,38 @@ void SettingsDialog::initConnections() const
|
|||||||
connect(ui->comboTlsKeyLength, &QComboBox::currentIndexChanged, this, &SettingsDialog::updateRequestedKeySize);
|
connect(ui->comboTlsKeyLength, &QComboBox::currentIndexChanged, this, &SettingsDialog::updateRequestedKeySize);
|
||||||
connect(ui->btnTlsCertPath, &QPushButton::clicked, this, &SettingsDialog::browseCertificatePath);
|
connect(ui->btnTlsCertPath, &QPushButton::clicked, this, &SettingsDialog::browseCertificatePath);
|
||||||
connect(ui->btnBrowseLog, &QPushButton::clicked, this, &SettingsDialog::browseLogPath);
|
connect(ui->btnBrowseLog, &QPushButton::clicked, this, &SettingsDialog::browseLogPath);
|
||||||
connect(ui->cbLogToFile, &QCheckBox::toggled, this, &SettingsDialog::setLogToFile);
|
connect(ui->groupLogToFile, &QGroupBox::toggled, this, &SettingsDialog::setLogToFile);
|
||||||
connect(ui->comboLogLevel, &QComboBox::currentIndexChanged, this, &SettingsDialog::logLevelChanged);
|
connect(ui->comboLogLevel, &QComboBox::currentIndexChanged, this, &SettingsDialog::logLevelChanged);
|
||||||
connect(ui->comboLanguage, &QComboBox::currentTextChanged, this, [](const QString &lang) {
|
connect(ui->comboLanguage, &QComboBox::currentTextChanged, this, [](const QString &lang) {
|
||||||
const auto shortName = I18N::nativeTo639Name(lang);
|
const auto shortName = I18N::nativeTo639Name(lang);
|
||||||
I18N::setLanguage(shortName);
|
I18N::setLanguage(shortName);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Connect modifiable controls
|
||||||
|
connect(ui->rbIconMono, &QRadioButton::toggled, this, &SettingsDialog::setButtonBoxEnabledButtons);
|
||||||
|
connect(ui->sbPort, &QSpinBox::valueChanged, this, &SettingsDialog::setButtonBoxEnabledButtons);
|
||||||
|
connect(ui->comboLogLevel, &QComboBox::currentIndexChanged, this, &SettingsDialog::setButtonBoxEnabledButtons);
|
||||||
|
connect(ui->comboInterface, &QComboBox::currentIndexChanged, this, &SettingsDialog::setButtonBoxEnabledButtons);
|
||||||
|
connect(ui->comboTlsKeyLength, &QComboBox::currentIndexChanged, this, &SettingsDialog::setButtonBoxEnabledButtons);
|
||||||
|
connect(ui->comboLanguage, &QComboBox::currentIndexChanged, this, &SettingsDialog::setButtonBoxEnabledButtons);
|
||||||
|
connect(ui->rbAutoHide, &QRadioButton::toggled, this, &SettingsDialog::setButtonBoxEnabledButtons);
|
||||||
|
connect(ui->cbPreventSleep, &QCheckBox::toggled, this, &SettingsDialog::setButtonBoxEnabledButtons);
|
||||||
|
connect(ui->rbCloseToTray, &QRadioButton::toggled, this, &SettingsDialog::setButtonBoxEnabledButtons);
|
||||||
|
connect(ui->cbElevateDaemon, &QCheckBox::toggled, this, &SettingsDialog::setButtonBoxEnabledButtons);
|
||||||
|
connect(ui->cbAutoUpdate, &QCheckBox::toggled, this, &SettingsDialog::setButtonBoxEnabledButtons);
|
||||||
|
connect(ui->cbGuiDebug, &QCheckBox::toggled, this, &SettingsDialog::setButtonBoxEnabledButtons);
|
||||||
|
connect(ui->cbUseWlClipboard, &QCheckBox::toggled, this, &SettingsDialog::setButtonBoxEnabledButtons);
|
||||||
|
connect(ui->cbShowVersion, &QCheckBox::toggled, this, &SettingsDialog::setButtonBoxEnabledButtons);
|
||||||
|
connect(ui->cbRequireClientCert, &QCheckBox::toggled, this, &SettingsDialog::setButtonBoxEnabledButtons);
|
||||||
|
connect(ui->groupLogToFile, &QGroupBox::toggled, this, &SettingsDialog::setButtonBoxEnabledButtons);
|
||||||
|
connect(ui->groupService, &QGroupBox::toggled, this, &SettingsDialog::setButtonBoxEnabledButtons);
|
||||||
|
connect(ui->groupSecurity, &QGroupBox::toggled, this, &SettingsDialog::setButtonBoxEnabledButtons);
|
||||||
|
connect(ui->lineLogFilename, &QLineEdit::textChanged, this, &SettingsDialog::setButtonBoxEnabledButtons);
|
||||||
|
connect(ui->lineTlsCertPath, &QLineEdit::textChanged, this, &SettingsDialog::setButtonBoxEnabledButtons);
|
||||||
|
connect(ui->cbRunEnterCommand, &QCheckBox::toggled, this, &SettingsDialog::setButtonBoxEnabledButtons);
|
||||||
|
connect(ui->cbRunExitCommand, &QCheckBox::toggled, this, &SettingsDialog::setButtonBoxEnabledButtons);
|
||||||
|
connect(ui->lineCommandEnter, &QLineEdit::textChanged, this, &SettingsDialog::setButtonBoxEnabledButtons);
|
||||||
|
connect(ui->lineCommandExit, &QLineEdit::textChanged, this, &SettingsDialog::setButtonBoxEnabledButtons);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SettingsDialog::regenCertificates()
|
void SettingsDialog::regenCertificates()
|
||||||
@ -165,6 +208,10 @@ void SettingsDialog::updateText()
|
|||||||
ui->comboLogLevel->setItemData(5, tr("Debug entries"), Qt::ToolTipRole);
|
ui->comboLogLevel->setItemData(5, tr("Debug entries"), Qt::ToolTipRole);
|
||||||
ui->comboLogLevel->setItemData(6, tr("More debug output"), Qt::ToolTipRole);
|
ui->comboLogLevel->setItemData(6, tr("More debug output"), Qt::ToolTipRole);
|
||||||
ui->comboLogLevel->setItemData(7, tr("Verbose debug output"), Qt::ToolTipRole);
|
ui->comboLogLevel->setItemData(7, tr("Verbose debug output"), Qt::ToolTipRole);
|
||||||
|
ui->buttonBox->button(QDialogButtonBox::Save)->setToolTip(tr("Close and save changes"));
|
||||||
|
ui->buttonBox->button(QDialogButtonBox::Cancel)->setToolTip(tr("Close and forget changes"));
|
||||||
|
ui->buttonBox->button(QDialogButtonBox::Reset)->setToolTip(tr("Reset to stored values"));
|
||||||
|
ui->buttonBox->button(QDialogButtonBox::RestoreDefaults)->setToolTip(tr("Reset to default values"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void SettingsDialog::accept()
|
void SettingsDialog::accept()
|
||||||
@ -172,22 +219,26 @@ void SettingsDialog::accept()
|
|||||||
Settings::setValue(Settings::Core::Port, ui->sbPort->value());
|
Settings::setValue(Settings::Core::Port, ui->sbPort->value());
|
||||||
Settings::setValue(Settings::Core::Interface, ui->comboInterface->currentData());
|
Settings::setValue(Settings::Core::Interface, ui->comboInterface->currentData());
|
||||||
Settings::setValue(Settings::Log::Level, ui->comboLogLevel->currentIndex());
|
Settings::setValue(Settings::Log::Level, ui->comboLogLevel->currentIndex());
|
||||||
Settings::setValue(Settings::Log::ToFile, ui->cbLogToFile->isChecked());
|
Settings::setValue(Settings::Log::ToFile, ui->groupLogToFile->isChecked());
|
||||||
Settings::setValue(Settings::Log::File, ui->lineLogFilename->text());
|
Settings::setValue(Settings::Log::File, ui->lineLogFilename->text());
|
||||||
Settings::setValue(Settings::Daemon::Elevate, ui->cbElevateDaemon->isChecked());
|
Settings::setValue(Settings::Daemon::Elevate, ui->cbElevateDaemon->isChecked());
|
||||||
Settings::setValue(Settings::Gui::Autohide, ui->cbAutoHide->isChecked());
|
Settings::setValue(Settings::Gui::Autohide, ui->rbAutoHide->isChecked());
|
||||||
Settings::setValue(Settings::Gui::AutoUpdateCheck, ui->cbAutoUpdate->isChecked());
|
Settings::setValue(Settings::Gui::AutoUpdateCheck, ui->cbAutoUpdate->isChecked());
|
||||||
Settings::setValue(Settings::Core::PreventSleep, ui->cbPreventSleep->isChecked());
|
Settings::setValue(Settings::Core::PreventSleep, ui->cbPreventSleep->isChecked());
|
||||||
Settings::setValue(Settings::Security::Certificate, ui->lineTlsCertPath->text());
|
Settings::setValue(Settings::Security::Certificate, ui->lineTlsCertPath->text());
|
||||||
Settings::setValue(Settings::Security::KeySize, ui->comboTlsKeyLength->currentText().toInt());
|
Settings::setValue(Settings::Security::KeySize, ui->comboTlsKeyLength->currentText().toInt());
|
||||||
Settings::setValue(Settings::Security::TlsEnabled, ui->groupSecurity->isChecked());
|
Settings::setValue(Settings::Security::TlsEnabled, ui->groupSecurity->isChecked());
|
||||||
Settings::setValue(Settings::Gui::CloseToTray, ui->cbCloseToTray->isChecked());
|
Settings::setValue(Settings::Gui::CloseToTray, ui->rbCloseToTray->isChecked());
|
||||||
Settings::setValue(Settings::Gui::SymbolicTrayIcon, ui->rbIconMono->isChecked());
|
Settings::setValue(Settings::Gui::SymbolicTrayIcon, ui->rbIconMono->isChecked());
|
||||||
Settings::setValue(Settings::Security::CheckPeers, ui->cbRequireClientCert->isChecked());
|
Settings::setValue(Settings::Security::CheckPeers, ui->cbRequireClientCert->isChecked());
|
||||||
Settings::setValue(Settings::Core::Language, I18N::nativeTo639Name(ui->comboLanguage->currentText()));
|
Settings::setValue(Settings::Core::Language, I18N::nativeTo639Name(ui->comboLanguage->currentText()));
|
||||||
Settings::setValue(Settings::Log::GuiDebug, ui->cbGuiDebug->isChecked());
|
Settings::setValue(Settings::Log::GuiDebug, ui->cbGuiDebug->isChecked());
|
||||||
Settings::setValue(Settings::Core::UseWlClipboard, ui->cbUseWlClipboard->isChecked());
|
Settings::setValue(Settings::Core::UseWlClipboard, ui->cbUseWlClipboard->isChecked());
|
||||||
Settings::setValue(Settings::Gui::ShowVersionInTitle, ui->cbShowVersion->isChecked());
|
Settings::setValue(Settings::Gui::ShowVersionInTitle, ui->cbShowVersion->isChecked());
|
||||||
|
Settings::setValue(Settings::Core::EnableEnterCommand, ui->cbRunEnterCommand->isChecked());
|
||||||
|
Settings::setValue(Settings::Core::EnableExitCommand, ui->cbRunExitCommand->isChecked());
|
||||||
|
Settings::setValue(Settings::Core::ScreenEnterCommand, ui->lineCommandEnter->text());
|
||||||
|
Settings::setValue(Settings::Core::ScreenExitCommand, ui->lineCommandExit->text());
|
||||||
|
|
||||||
Settings::ProcessMode mode;
|
Settings::ProcessMode mode;
|
||||||
if (ui->groupService->isChecked())
|
if (ui->groupService->isChecked())
|
||||||
@ -203,16 +254,18 @@ void SettingsDialog::loadFromConfig()
|
|||||||
{
|
{
|
||||||
ui->sbPort->setValue(Settings::value(Settings::Core::Port).toInt());
|
ui->sbPort->setValue(Settings::value(Settings::Core::Port).toInt());
|
||||||
ui->comboLogLevel->setCurrentIndex(Settings::value(Settings::Log::Level).toInt());
|
ui->comboLogLevel->setCurrentIndex(Settings::value(Settings::Log::Level).toInt());
|
||||||
ui->cbLogToFile->setChecked(Settings::value(Settings::Log::ToFile).toBool());
|
ui->groupLogToFile->setChecked(Settings::value(Settings::Log::ToFile).toBool());
|
||||||
ui->lineLogFilename->setText(Settings::value(Settings::Log::File).toString());
|
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->cbPreventSleep->setChecked(Settings::value(Settings::Core::PreventSleep).toBool());
|
||||||
ui->cbCloseToTray->setChecked(Settings::value(Settings::Gui::CloseToTray).toBool());
|
|
||||||
ui->cbElevateDaemon->setChecked(Settings::value(Settings::Daemon::Elevate).toBool());
|
ui->cbElevateDaemon->setChecked(Settings::value(Settings::Daemon::Elevate).toBool());
|
||||||
ui->cbAutoUpdate->setChecked(Settings::value(Settings::Gui::AutoUpdateCheck).toBool());
|
ui->cbAutoUpdate->setChecked(Settings::value(Settings::Gui::AutoUpdateCheck).toBool());
|
||||||
ui->cbGuiDebug->setChecked(Settings::value(Settings::Log::GuiDebug).toBool());
|
ui->cbGuiDebug->setChecked(Settings::value(Settings::Log::GuiDebug).toBool());
|
||||||
ui->cbUseWlClipboard->setChecked(Settings::value(Settings::Core::UseWlClipboard).toBool());
|
ui->cbUseWlClipboard->setChecked(Settings::value(Settings::Core::UseWlClipboard).toBool());
|
||||||
ui->cbShowVersion->setChecked(Settings::value(Settings::Gui::ShowVersionInTitle).toBool());
|
ui->cbShowVersion->setChecked(Settings::value(Settings::Gui::ShowVersionInTitle).toBool());
|
||||||
|
ui->cbRunEnterCommand->setChecked(Settings::value(Settings::Core::EnableEnterCommand).toBool());
|
||||||
|
ui->cbRunExitCommand->setChecked(Settings::value(Settings::Core::EnableExitCommand).toBool());
|
||||||
|
ui->lineCommandEnter->setText(Settings::value(Settings::Core::ScreenEnterCommand).toString());
|
||||||
|
ui->lineCommandExit->setText(Settings::value(Settings::Core::ScreenExitCommand).toString());
|
||||||
|
|
||||||
const auto processMode = Settings::value(Settings::Core::ProcessMode).value<Settings::ProcessMode>();
|
const auto processMode = Settings::value(Settings::Core::ProcessMode).value<Settings::ProcessMode>();
|
||||||
ui->groupService->setChecked(processMode == Settings::ProcessMode::Service);
|
ui->groupService->setChecked(processMode == Settings::ProcessMode::Service);
|
||||||
@ -225,13 +278,26 @@ void SettingsDialog::loadFromConfig()
|
|||||||
else
|
else
|
||||||
ui->rbIconColorful->setChecked(true);
|
ui->rbIconColorful->setChecked(true);
|
||||||
|
|
||||||
|
const auto autoHide = Settings::value(Settings::Gui::Autohide).toBool();
|
||||||
|
ui->rbAutoHide->setChecked(autoHide);
|
||||||
|
ui->rbShowOnStart->setChecked(!autoHide);
|
||||||
|
|
||||||
|
const auto closeToTray = Settings::value(Settings::Gui::CloseToTray).toBool();
|
||||||
|
ui->rbCloseToTray->setChecked(closeToTray);
|
||||||
|
ui->rbExitOnClose->setChecked(!closeToTray);
|
||||||
|
|
||||||
ui->lblDebugWarning->setVisible(Settings::value(Settings::Log::Level).toInt() > 4);
|
ui->lblDebugWarning->setVisible(Settings::value(Settings::Log::Level).toInt() > 4);
|
||||||
|
|
||||||
ui->comboInterface->setCurrentText(Settings::value(Settings::Core::Interface).toString());
|
ui->comboInterface->setCurrentText(Settings::value(Settings::Core::Interface).toString());
|
||||||
if (ui->comboInterface->currentIndex() < 0)
|
if (ui->comboInterface->currentIndex() <= 0) {
|
||||||
ui->comboInterface->setCurrentIndex(0);
|
ui->comboInterface->setCurrentIndex(0);
|
||||||
|
m_interfaceSetOnLoad = false;
|
||||||
|
} else {
|
||||||
|
m_interfaceSetOnLoad = true;
|
||||||
|
}
|
||||||
|
|
||||||
qDebug() << "load from config done";
|
qDebug() << "load from config done";
|
||||||
|
|
||||||
updateControls();
|
updateControls();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -269,7 +335,7 @@ void SettingsDialog::updateTlsControlsEnabled()
|
|||||||
|
|
||||||
bool SettingsDialog::isClientMode() const
|
bool SettingsDialog::isClientMode() const
|
||||||
{
|
{
|
||||||
return m_coreProcess.mode() == Settings::CoreMode::Client;
|
return Settings::value(Settings::Core::CoreMode) == Settings::CoreMode::Client;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SettingsDialog::updateKeyLengthOnFile(const QString &path)
|
void SettingsDialog::updateKeyLengthOnFile(const QString &path)
|
||||||
@ -293,20 +359,26 @@ void SettingsDialog::updateControls()
|
|||||||
{
|
{
|
||||||
const bool writable = Settings::isWritable();
|
const bool writable = Settings::isWritable();
|
||||||
const bool serviceChecked = ui->groupService->isChecked();
|
const bool serviceChecked = ui->groupService->isChecked();
|
||||||
const bool logToFile = ui->cbLogToFile->isChecked();
|
const bool logToFile = ui->groupLogToFile->isChecked();
|
||||||
|
|
||||||
ui->buttonBox->button(QDialogButtonBox::Save)->setEnabled(writable);
|
ui->buttonBox->button(QDialogButtonBox::Save)->setEnabled(writable);
|
||||||
|
|
||||||
ui->sbPort->setEnabled(writable);
|
ui->sbPort->setEnabled(writable);
|
||||||
ui->comboInterface->setEnabled(writable);
|
ui->comboInterface->setEnabled(writable);
|
||||||
ui->comboLogLevel->setEnabled(writable);
|
ui->comboLogLevel->setEnabled(writable);
|
||||||
ui->cbLogToFile->setEnabled(writable);
|
ui->groupLogToFile->setEnabled(writable);
|
||||||
ui->cbAutoHide->setEnabled(writable);
|
ui->rbAutoHide->setEnabled(writable);
|
||||||
|
ui->rbShowOnStart->setEnabled(writable);
|
||||||
ui->cbAutoUpdate->setEnabled(writable);
|
ui->cbAutoUpdate->setEnabled(writable);
|
||||||
ui->cbPreventSleep->setEnabled(writable);
|
ui->cbPreventSleep->setEnabled(writable);
|
||||||
ui->lineTlsCertPath->setEnabled(writable);
|
ui->lineTlsCertPath->setEnabled(writable);
|
||||||
ui->comboTlsKeyLength->setEnabled(writable);
|
ui->comboTlsKeyLength->setEnabled(writable);
|
||||||
ui->cbCloseToTray->setEnabled(writable);
|
ui->rbCloseToTray->setEnabled(writable);
|
||||||
|
ui->rbExitOnClose->setEnabled(writable);
|
||||||
|
ui->cbRunEnterCommand->setEnabled(writable);
|
||||||
|
ui->cbRunExitCommand->setEnabled(writable);
|
||||||
|
ui->lineCommandEnter->setEnabled(writable && ui->cbRunEnterCommand->isChecked());
|
||||||
|
ui->lineCommandExit->setEnabled(writable && ui->cbRunExitCommand->isChecked());
|
||||||
|
|
||||||
// Portable mode only ever applies to Windows.
|
// Portable mode only ever applies to Windows.
|
||||||
// Daemon options should only be available on Windows when *not* in portable mode.
|
// Daemon options should only be available on Windows when *not* in portable mode.
|
||||||
@ -342,4 +414,124 @@ void SettingsDialog::logLevelChanged()
|
|||||||
ui->lblDebugWarning->setVisible(ui->comboLogLevel->currentIndex() > 4);
|
ui->lblDebugWarning->setVisible(ui->comboLogLevel->currentIndex() > 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SettingsDialog::isModified() const
|
||||||
|
{
|
||||||
|
const auto processMode = Settings::value(Settings::Core::ProcessMode).value<Settings::ProcessMode>();
|
||||||
|
const bool ignoreInterface = !m_interfaceSetOnLoad && (ui->comboInterface->currentIndex() == 0);
|
||||||
|
|
||||||
|
bool modified =
|
||||||
|
(ui->sbPort->value() != Settings::value(Settings::Core::Port).toInt()) ||
|
||||||
|
(ui->comboLogLevel->currentIndex() != Settings::value(Settings::Log::Level).toInt()) ||
|
||||||
|
(ui->groupLogToFile->isChecked() != Settings::value(Settings::Log::ToFile).toBool()) ||
|
||||||
|
(ui->lineLogFilename->text() != Settings::value(Settings::Log::File).toString()) ||
|
||||||
|
(ui->rbAutoHide->isChecked() != Settings::value(Settings::Gui::Autohide).toBool()) ||
|
||||||
|
(ui->cbPreventSleep->isChecked() != Settings::value(Settings::Core::PreventSleep).toBool()) ||
|
||||||
|
(ui->rbCloseToTray->isChecked() != Settings::value(Settings::Gui::CloseToTray).toBool()) ||
|
||||||
|
(ui->cbElevateDaemon->isChecked() != Settings::value(Settings::Daemon::Elevate).toBool()) ||
|
||||||
|
(ui->cbAutoUpdate->isChecked() != Settings::value(Settings::Gui::AutoUpdateCheck).toBool()) ||
|
||||||
|
(ui->cbGuiDebug->isChecked() != Settings::value(Settings::Log::GuiDebug).toBool()) ||
|
||||||
|
(ui->cbUseWlClipboard->isChecked() != Settings::value(Settings::Core::UseWlClipboard).toBool()) ||
|
||||||
|
(ui->cbShowVersion->isChecked() != Settings::value(Settings::Gui::ShowVersionInTitle).toBool()) ||
|
||||||
|
(ui->rbIconMono->isChecked() != Settings::value(Settings::Gui::SymbolicTrayIcon).toBool()) ||
|
||||||
|
(ui->groupService->isChecked() != (processMode == Settings::ProcessMode::Service)) ||
|
||||||
|
(ui->lineTlsCertPath->text() != Settings::value(Settings::Security::Certificate).toString()) ||
|
||||||
|
(ui->comboTlsKeyLength->currentText() != Settings::value(Settings::Security::KeySize).toString()) ||
|
||||||
|
(ui->groupSecurity->isChecked() != Settings::value(Settings::Security::TlsEnabled).toBool()) ||
|
||||||
|
(ui->cbRequireClientCert->isChecked() != Settings::value(Settings::Security::CheckPeers).toBool()) ||
|
||||||
|
(ui->cbRunEnterCommand->isChecked() != Settings::value(Settings::Core::EnableEnterCommand).toBool()) ||
|
||||||
|
(ui->cbRunExitCommand->isChecked() != Settings::value(Settings::Core::EnableExitCommand).toBool()) ||
|
||||||
|
(ui->lineCommandEnter->text() != Settings::value(Settings::Core::ScreenEnterCommand).toString()) ||
|
||||||
|
(ui->lineCommandExit->text() != Settings::value(Settings::Core::ScreenExitCommand).toString()) ||
|
||||||
|
(I18N::nativeTo639Name(ui->comboLanguage->currentText()) != Settings::value(Settings::Core::Language).toString());
|
||||||
|
|
||||||
|
if (!ignoreInterface)
|
||||||
|
modified = modified || ui->comboInterface->currentText() != Settings::value(Settings::Core::Interface).toString();
|
||||||
|
return modified;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SettingsDialog::isDefault() const
|
||||||
|
{
|
||||||
|
const auto processMode = Settings::defaultValue(Settings::Core::ProcessMode).value<Settings::ProcessMode>();
|
||||||
|
|
||||||
|
return (
|
||||||
|
(ui->sbPort->value() == Settings::defaultValue(Settings::Core::Port).toInt()) &&
|
||||||
|
(ui->comboLogLevel->currentIndex() == Settings::defaultValue(Settings::Log::Level).toInt()) &&
|
||||||
|
(ui->groupLogToFile->isChecked() == Settings::defaultValue(Settings::Log::ToFile).toBool()) &&
|
||||||
|
(ui->lineLogFilename->text() == Settings::defaultValue(Settings::Log::File).toString()) &&
|
||||||
|
(ui->rbAutoHide->isChecked() == Settings::defaultValue(Settings::Gui::Autohide).toBool()) &&
|
||||||
|
(ui->cbPreventSleep->isChecked() == Settings::defaultValue(Settings::Core::PreventSleep).toBool()) &&
|
||||||
|
(ui->rbCloseToTray->isChecked() == Settings::defaultValue(Settings::Gui::CloseToTray).toBool()) &&
|
||||||
|
(ui->cbElevateDaemon->isChecked() == Settings::defaultValue(Settings::Daemon::Elevate).toBool()) &&
|
||||||
|
(ui->cbAutoUpdate->isChecked() == Settings::defaultValue(Settings::Gui::AutoUpdateCheck).toBool()) &&
|
||||||
|
(ui->cbGuiDebug->isChecked() == Settings::defaultValue(Settings::Log::GuiDebug).toBool()) &&
|
||||||
|
(ui->cbUseWlClipboard->isChecked() == Settings::defaultValue(Settings::Core::UseWlClipboard).toBool()) &&
|
||||||
|
(ui->cbShowVersion->isChecked() == Settings::defaultValue(Settings::Gui::ShowVersionInTitle).toBool()) &&
|
||||||
|
(ui->rbIconMono->isChecked() == Settings::defaultValue(Settings::Gui::SymbolicTrayIcon).toBool()) &&
|
||||||
|
(ui->groupService->isChecked() == (processMode == Settings::ProcessMode::Service)) &&
|
||||||
|
(ui->comboInterface->currentIndex() == 0) &&
|
||||||
|
(ui->lineTlsCertPath->text() == Settings::defaultValue(Settings::Security::Certificate).toString()) &&
|
||||||
|
(ui->comboTlsKeyLength->currentText() == Settings::defaultValue(Settings::Security::KeySize).toString()) &&
|
||||||
|
(ui->groupSecurity->isChecked() == Settings::defaultValue(Settings::Security::TlsEnabled).toBool()) &&
|
||||||
|
(ui->cbRequireClientCert->isChecked() == Settings::defaultValue(Settings::Security::CheckPeers).toBool()) &&
|
||||||
|
(ui->lineCommandEnter->text() == Settings::defaultValue(Settings::Core::ScreenEnterCommand).toString()) &&
|
||||||
|
(ui->lineCommandExit->text() == Settings::defaultValue(Settings::Core::ScreenExitCommand).toString()) &&
|
||||||
|
(ui->cbRunEnterCommand->isChecked() == Settings::defaultValue(Settings::Core::EnableEnterCommand).toBool()) &&
|
||||||
|
(ui->cbRunExitCommand->isChecked() == Settings::defaultValue(Settings::Core::EnableExitCommand).toBool()) &&
|
||||||
|
(ui->comboLanguage->currentText() == "English")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SettingsDialog::resetToDefault()
|
||||||
|
{
|
||||||
|
ui->sbPort->setValue(Settings::defaultValue(Settings::Core::Port).toInt());
|
||||||
|
ui->comboLogLevel->setCurrentIndex(Settings::defaultValue(Settings::Log::Level).toInt());
|
||||||
|
ui->groupLogToFile->setChecked(Settings::defaultValue(Settings::Log::ToFile).toBool());
|
||||||
|
ui->lineLogFilename->setText(Settings::defaultValue(Settings::Log::File).toString());
|
||||||
|
ui->cbPreventSleep->setChecked(Settings::defaultValue(Settings::Core::PreventSleep).toBool());
|
||||||
|
ui->cbElevateDaemon->setChecked(Settings::defaultValue(Settings::Daemon::Elevate).toBool());
|
||||||
|
ui->cbAutoUpdate->setChecked(Settings::defaultValue(Settings::Gui::AutoUpdateCheck).toBool());
|
||||||
|
ui->cbGuiDebug->setChecked(Settings::defaultValue(Settings::Log::GuiDebug).toBool());
|
||||||
|
ui->cbUseWlClipboard->setChecked(Settings::defaultValue(Settings::Core::UseWlClipboard).toBool());
|
||||||
|
ui->cbShowVersion->setChecked(Settings::defaultValue(Settings::Gui::ShowVersionInTitle).toBool());
|
||||||
|
ui->cbRunEnterCommand->setChecked(Settings::defaultValue(Settings::Core::EnableEnterCommand).toBool());
|
||||||
|
ui->cbRunExitCommand->setChecked(Settings::defaultValue(Settings::Core::EnableExitCommand).toBool());
|
||||||
|
ui->lineCommandEnter->setText(Settings::defaultValue(Settings::Core::ScreenEnterCommand).toString());
|
||||||
|
ui->lineCommandExit->setText(Settings::defaultValue(Settings::Core::ScreenExitCommand).toString());
|
||||||
|
|
||||||
|
const auto autoHide = Settings::defaultValue(Settings::Gui::Autohide).toBool();
|
||||||
|
ui->rbCloseToTray->setChecked(autoHide);
|
||||||
|
ui->rbExitOnClose->setChecked(!autoHide);
|
||||||
|
|
||||||
|
const auto closeToTray = Settings::defaultValue(Settings::Gui::CloseToTray).toBool();
|
||||||
|
ui->rbCloseToTray->setChecked(closeToTray);
|
||||||
|
ui->rbExitOnClose->setChecked(!closeToTray);
|
||||||
|
|
||||||
|
const auto processMode = Settings::defaultValue(Settings::Core::ProcessMode).value<Settings::ProcessMode>();
|
||||||
|
ui->groupService->setChecked(processMode == Settings::ProcessMode::Service);
|
||||||
|
|
||||||
|
if (!deskflow::platform::isWindows())
|
||||||
|
ui->groupService->setVisible(false);
|
||||||
|
|
||||||
|
if (Settings::defaultValue(Settings::Gui::SymbolicTrayIcon).toBool())
|
||||||
|
ui->rbIconMono->setChecked(true);
|
||||||
|
else
|
||||||
|
ui->rbIconColorful->setChecked(true);
|
||||||
|
|
||||||
|
ui->lblDebugWarning->setVisible(false);
|
||||||
|
|
||||||
|
ui->comboInterface->setCurrentIndex(0);
|
||||||
|
|
||||||
|
qDebug() << "reset to default values";
|
||||||
|
updateControls();
|
||||||
|
setButtonBoxEnabledButtons();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SettingsDialog::setButtonBoxEnabledButtons() const
|
||||||
|
{
|
||||||
|
const bool modified = isModified();
|
||||||
|
ui->buttonBox->button(QDialogButtonBox::Save)->setEnabled(modified);
|
||||||
|
ui->buttonBox->button(QDialogButtonBox::Reset)->setEnabled(modified);
|
||||||
|
ui->buttonBox->button(QDialogButtonBox::RestoreDefaults)->setEnabled(!isDefault());
|
||||||
|
}
|
||||||
|
|
||||||
SettingsDialog::~SettingsDialog() = default;
|
SettingsDialog::~SettingsDialog() = default;
|
||||||
|
|||||||
@ -10,7 +10,6 @@
|
|||||||
#include <QDialog>
|
#include <QDialog>
|
||||||
|
|
||||||
#include "gui/config/IServerConfig.h"
|
#include "gui/config/IServerConfig.h"
|
||||||
#include "gui/core/CoreProcess.h"
|
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
class SettingsDialog;
|
class SettingsDialog;
|
||||||
@ -19,13 +18,12 @@ class SettingsDialog;
|
|||||||
class SettingsDialog : public QDialog
|
class SettingsDialog : public QDialog
|
||||||
{
|
{
|
||||||
using IServerConfig = deskflow::gui::IServerConfig;
|
using IServerConfig = deskflow::gui::IServerConfig;
|
||||||
using CoreProcess = deskflow::gui::CoreProcess;
|
|
||||||
|
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void extracted();
|
void extracted();
|
||||||
SettingsDialog(QWidget *parent, const IServerConfig &serverConfig, const CoreProcess &coreProcess);
|
SettingsDialog(QWidget *parent, const IServerConfig &serverConfig);
|
||||||
~SettingsDialog() override;
|
~SettingsDialog() override;
|
||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
@ -63,7 +61,30 @@ private:
|
|||||||
/// @brief update if the log level warning is shown
|
/// @brief update if the log level warning is shown
|
||||||
void logLevelChanged();
|
void logLevelChanged();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief isModified
|
||||||
|
* @return true when any client settings in the gui do not match the stored settings values.
|
||||||
|
*/
|
||||||
|
bool isModified() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief isDefault
|
||||||
|
* @return true if all client settings match the default values
|
||||||
|
*/
|
||||||
|
bool isDefault() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the gui values to the defalut values for all client settings
|
||||||
|
*/
|
||||||
|
void resetToDefault();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief setButtonBoxEnabledButtons
|
||||||
|
* Enable / Disable the button box buttons based on the state of the gui
|
||||||
|
*/
|
||||||
|
void setButtonBoxEnabledButtons() const;
|
||||||
|
|
||||||
|
bool m_interfaceSetOnLoad = false;
|
||||||
std::unique_ptr<Ui::SettingsDialog> ui;
|
std::unique_ptr<Ui::SettingsDialog> ui;
|
||||||
const IServerConfig &m_serverConfig;
|
const IServerConfig &m_serverConfig;
|
||||||
const CoreProcess &m_coreProcess;
|
|
||||||
};
|
};
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -9,7 +9,9 @@
|
|||||||
#include "ComputerNameValidator.h"
|
#include "ComputerNameValidator.h"
|
||||||
#include "IpAddressValidator.h"
|
#include "IpAddressValidator.h"
|
||||||
#include "SpacesValidator.h"
|
#include "SpacesValidator.h"
|
||||||
|
#include "ValidationError.h"
|
||||||
|
|
||||||
|
#include <QLineEdit>
|
||||||
#include <QRegularExpression>
|
#include <QRegularExpression>
|
||||||
|
|
||||||
namespace validators {
|
namespace validators {
|
||||||
|
|||||||
@ -7,9 +7,9 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "LineEditValidator.h"
|
#include "LineEditValidator.h"
|
||||||
#include "ValidationError.h"
|
|
||||||
|
|
||||||
namespace validators {
|
namespace validators {
|
||||||
|
class ValidationError;
|
||||||
|
|
||||||
class AliasValidator : public LineEditValidator
|
class AliasValidator : public LineEditValidator
|
||||||
{
|
{
|
||||||
|
|||||||
@ -17,7 +17,9 @@ ComputerNameValidator::ComputerNameValidator(const QString &message) : IStringVa
|
|||||||
|
|
||||||
bool ComputerNameValidator::validate(const QString &input) const
|
bool ComputerNameValidator::validate(const QString &input) const
|
||||||
{
|
{
|
||||||
auto match = m_nameValidator.match(input);
|
static const auto s_nameValidator =
|
||||||
|
QRegularExpression(QStringLiteral("^[\\w\\._-]{0,255}$"), QRegularExpression::CaseInsensitiveOption);
|
||||||
|
auto match = s_nameValidator.match(input);
|
||||||
return match.hasMatch();
|
return match.hasMatch();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -8,8 +8,6 @@
|
|||||||
|
|
||||||
#include "IStringValidator.h"
|
#include "IStringValidator.h"
|
||||||
|
|
||||||
#include <QRegularExpression>
|
|
||||||
|
|
||||||
namespace validators {
|
namespace validators {
|
||||||
|
|
||||||
class ComputerNameValidator : public IStringValidator
|
class ComputerNameValidator : public IStringValidator
|
||||||
@ -17,10 +15,6 @@ class ComputerNameValidator : public IStringValidator
|
|||||||
public:
|
public:
|
||||||
explicit ComputerNameValidator(const QString &message);
|
explicit ComputerNameValidator(const QString &message);
|
||||||
bool validate(const QString &input) const override;
|
bool validate(const QString &input) const override;
|
||||||
|
|
||||||
private:
|
|
||||||
inline static const QRegularExpression m_nameValidator =
|
|
||||||
QRegularExpression(QStringLiteral("^[\\w\\._-]{0,255}$"), QRegularExpression::CaseInsensitiveOption);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace validators
|
} // namespace validators
|
||||||
|
|||||||
@ -5,6 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "IpAddressValidator.h"
|
#include "IpAddressValidator.h"
|
||||||
|
#include <QRegularExpression>
|
||||||
|
|
||||||
namespace validators {
|
namespace validators {
|
||||||
|
|
||||||
|
|||||||
@ -7,7 +7,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "IStringValidator.h"
|
#include "IStringValidator.h"
|
||||||
#include <QRegularExpression>
|
|
||||||
|
|
||||||
namespace validators {
|
namespace validators {
|
||||||
|
|
||||||
|
|||||||
@ -6,8 +6,10 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "LineEditValidator.h"
|
#include "LineEditValidator.h"
|
||||||
|
#include "ValidationError.h"
|
||||||
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
|
#include <QLineEdit>
|
||||||
#include <QStyle>
|
#include <QStyle>
|
||||||
#include <QValidator>
|
#include <QValidator>
|
||||||
|
|
||||||
|
|||||||
@ -8,15 +8,14 @@
|
|||||||
|
|
||||||
#include "IStringValidator.h"
|
#include "IStringValidator.h"
|
||||||
|
|
||||||
#include <QLabel>
|
|
||||||
#include <QLineEdit>
|
|
||||||
#include <QValidator>
|
#include <QValidator>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "ValidationError.h"
|
class QLineEdit;
|
||||||
|
|
||||||
namespace validators {
|
namespace validators {
|
||||||
|
class ValidationError;
|
||||||
|
|
||||||
class LineEditValidator : public QValidator
|
class LineEditValidator : public QValidator
|
||||||
{
|
{
|
||||||
|
|||||||
@ -5,6 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "ScreenDuplicationsValidator.h"
|
#include "ScreenDuplicationsValidator.h"
|
||||||
|
#include "gui/config/ScreenList.h"
|
||||||
|
|
||||||
namespace validators {
|
namespace validators {
|
||||||
|
|
||||||
|
|||||||
@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
#include "IStringValidator.h"
|
#include "IStringValidator.h"
|
||||||
|
|
||||||
#include "gui/config/ScreenList.h"
|
class ScreenList;
|
||||||
|
|
||||||
namespace validators {
|
namespace validators {
|
||||||
|
|
||||||
|
|||||||
@ -12,6 +12,9 @@
|
|||||||
#include "SpacesValidator.h"
|
#include "SpacesValidator.h"
|
||||||
#include "ValidationError.h"
|
#include "ValidationError.h"
|
||||||
|
|
||||||
|
#include "gui/config/ScreenList.h"
|
||||||
|
|
||||||
|
#include <QLineEdit>
|
||||||
#include <QRegularExpression>
|
#include <QRegularExpression>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
|||||||
@ -7,11 +7,11 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "LineEditValidator.h"
|
#include "LineEditValidator.h"
|
||||||
#include "ValidationError.h"
|
|
||||||
|
|
||||||
#include "gui/config/ScreenList.h"
|
class ScreenList;
|
||||||
|
|
||||||
namespace validators {
|
namespace validators {
|
||||||
|
class ValidationError;
|
||||||
|
|
||||||
class ScreenNameValidator : public LineEditValidator
|
class ScreenNameValidator : public LineEditValidator
|
||||||
{
|
{
|
||||||
|
|||||||
@ -15,7 +15,7 @@ SpacesValidator::SpacesValidator(const QString &message) : IStringValidator(mess
|
|||||||
|
|
||||||
bool SpacesValidator::validate(const QString &input) const
|
bool SpacesValidator::validate(const QString &input) const
|
||||||
{
|
{
|
||||||
return !input.contains(' ');
|
return !input.contains(QChar::Space);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace validators
|
} // namespace validators
|
||||||
|
|||||||
@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
#include "ValidationError.h"
|
#include "ValidationError.h"
|
||||||
|
|
||||||
|
#include <QLabel>
|
||||||
#include <QPalette>
|
#include <QPalette>
|
||||||
|
|
||||||
namespace validators {
|
namespace validators {
|
||||||
|
|||||||
@ -7,10 +7,11 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QLabel>
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
|
||||||
|
class QLabel;
|
||||||
|
|
||||||
namespace validators {
|
namespace validators {
|
||||||
|
|
||||||
class ValidationError : public QObject
|
class ValidationError : public QObject
|
||||||
|
|||||||
@ -19,7 +19,7 @@ NewScreenWidget::NewScreenWidget(QWidget *parent) : QLabel(parent)
|
|||||||
// do nothing
|
// do nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
void NewScreenWidget::mousePressEvent(QMouseEvent *event)
|
void NewScreenWidget::mousePressEvent(QMouseEvent *)
|
||||||
{
|
{
|
||||||
//: Used as the hostname. Translation may not contain spaces
|
//: Used as the hostname. Translation may not contain spaces
|
||||||
Screen newScreen(tr("Unnamed"));
|
Screen newScreen(tr("Unnamed"));
|
||||||
|
|||||||
@ -20,5 +20,5 @@ public:
|
|||||||
explicit NewScreenWidget(QWidget *parent);
|
explicit NewScreenWidget(QWidget *parent);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void mousePressEvent(QMouseEvent *event) override;
|
void mousePressEvent(QMouseEvent *) override;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -10,8 +10,6 @@
|
|||||||
#include <QFlags>
|
#include <QFlags>
|
||||||
#include <QTableView>
|
#include <QTableView>
|
||||||
|
|
||||||
#include "gui/config/Screen.h"
|
|
||||||
|
|
||||||
class QWidget;
|
class QWidget;
|
||||||
class QMouseEvent;
|
class QMouseEvent;
|
||||||
class QResizeEvent;
|
class QResizeEvent;
|
||||||
|
|||||||
178
src/lib/gui/widgets/StatusBar.cpp
Normal file
178
src/lib/gui/widgets/StatusBar.cpp
Normal file
@ -0,0 +1,178 @@
|
|||||||
|
/*
|
||||||
|
* Deskflow -- mouse and keyboard sharing utility
|
||||||
|
* SPDX-FileCopyrightText: (C) 2025 - 2026 Deskflow Developers
|
||||||
|
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "StatusBar.h"
|
||||||
|
#include "common/Constants.h"
|
||||||
|
#include "common/Settings.h"
|
||||||
|
|
||||||
|
#include <QEvent>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QPushButton>
|
||||||
|
|
||||||
|
StatusBar::StatusBar(QWidget *parent)
|
||||||
|
: QStatusBar{parent},
|
||||||
|
m_btnFingerprint{new QPushButton(this)},
|
||||||
|
m_lblSecurityIcon{new QLabel(this)},
|
||||||
|
m_lblStatus{new QLabel(this)},
|
||||||
|
m_btnUpdate{new QPushButton(this)}
|
||||||
|
{
|
||||||
|
static const auto btnHeight = height() - 2;
|
||||||
|
static const auto btnSize = QSize(btnHeight, btnHeight);
|
||||||
|
static const auto iconSize = QSize(fontMetrics().height() + 2, fontMetrics().height() + 2);
|
||||||
|
|
||||||
|
m_btnFingerprint->setFlat(true);
|
||||||
|
m_btnFingerprint->setIcon(QIcon::fromTheme(QStringLiteral("fingerprint")));
|
||||||
|
m_btnFingerprint->setFixedSize(btnSize);
|
||||||
|
m_btnFingerprint->setIconSize(iconSize);
|
||||||
|
insertPermanentWidget(0, m_btnFingerprint);
|
||||||
|
connect(m_btnFingerprint, &QPushButton::clicked, this, &StatusBar::requestShowMyFingerprints);
|
||||||
|
|
||||||
|
m_lblSecurityIcon->setVisible(false);
|
||||||
|
m_lblSecurityIcon->setFixedSize(iconSize);
|
||||||
|
m_lblSecurityIcon->setScaledContents(true);
|
||||||
|
insertPermanentWidget(1, m_lblSecurityIcon);
|
||||||
|
|
||||||
|
m_lblStatus->setText(tr("%1 is not running").arg(kAppName));
|
||||||
|
insertPermanentWidget(2, m_lblStatus, 1);
|
||||||
|
|
||||||
|
m_btnUpdate->setVisible(false);
|
||||||
|
m_btnUpdate->setFlat(true);
|
||||||
|
m_btnUpdate->setLayoutDirection(Qt::RightToLeft);
|
||||||
|
m_btnUpdate->setIcon(QIcon::fromTheme(QStringLiteral("software-updates-release")));
|
||||||
|
m_btnUpdate->setFixedHeight(btnHeight);
|
||||||
|
m_btnUpdate->setIconSize(iconSize);
|
||||||
|
insertPermanentWidget(3, m_btnUpdate);
|
||||||
|
connect(m_btnUpdate, &QPushButton::clicked, this, &StatusBar::requestUpdateVersion);
|
||||||
|
|
||||||
|
updateText();
|
||||||
|
adjustSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
void StatusBar::setStatus(ConnectionState connectionState, ProcessState processState, bool isServer)
|
||||||
|
{
|
||||||
|
setSecurityIconVisible(false);
|
||||||
|
switch (processState) {
|
||||||
|
using enum ProcessState;
|
||||||
|
case Starting:
|
||||||
|
m_lblStatus->setText(tr("%1 is starting...").arg(kAppName));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RetryPending:
|
||||||
|
m_lblStatus->setText(tr("%1 will retry in a moment...").arg(kAppName));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Stopping:
|
||||||
|
m_lblStatus->setText(tr("%1 is stopping...").arg(kAppName));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Stopped:
|
||||||
|
m_lblStatus->setText(tr("%1 is not running").arg(kAppName));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Started: {
|
||||||
|
switch (connectionState) {
|
||||||
|
using enum ConnectionState;
|
||||||
|
|
||||||
|
case Listening: {
|
||||||
|
if (isServer) {
|
||||||
|
setSecurityIconVisible(true);
|
||||||
|
m_lblStatus->setText(tr("%1 is waiting for clients").arg(kAppName));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case Connecting:
|
||||||
|
m_lblStatus->setText(tr("%1 is connecting...").arg(kAppName));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Connected: {
|
||||||
|
setSecurityIconVisible(true);
|
||||||
|
if (!isServer) {
|
||||||
|
m_lblStatus->setText(tr("%1 is connected as client of %2")
|
||||||
|
.arg(kAppName, Settings::value(Settings::Client::RemoteHost).toString()));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case Disconnected:
|
||||||
|
m_lblStatus->setText(tr("%1 is disconnected").arg(kAppName));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// clang-format on
|
||||||
|
void StatusBar::setServerClients(const QStringList &clients)
|
||||||
|
{
|
||||||
|
if (clients.isEmpty()) {
|
||||||
|
m_lblStatus->setText(tr("%1 is waiting for clients").arg(kAppName));
|
||||||
|
m_lblStatus->setToolTip("");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto clientCount = static_cast<int>(clients.size());
|
||||||
|
static const auto comma = QStringLiteral(", ");
|
||||||
|
static const auto newLine = QStringLiteral("\n");
|
||||||
|
//: Shown when in server mode and at least 1 client is connected
|
||||||
|
//: %1 is replaced by the app name
|
||||||
|
//: %2 will be a list of at least one client
|
||||||
|
//: %n will be replaced by the number of clients (n is >=1), it is not requried to be in the translation
|
||||||
|
const auto text = tr("%1 is connected, with %n client(s): %2", "", clientCount).arg(kAppName, clients.join(comma));
|
||||||
|
m_lblStatus->setText(text);
|
||||||
|
|
||||||
|
const auto toolTipString = clientCount == 1 ? "" : tr("Clients:\n %1").arg(clients.join(newLine));
|
||||||
|
m_lblStatus->setToolTip(toolTipString);
|
||||||
|
}
|
||||||
|
|
||||||
|
void StatusBar::setSecurityIconVisible(bool visible)
|
||||||
|
{
|
||||||
|
m_lblSecurityIcon->setVisible(visible);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool StatusBar::securityIconVisible() const
|
||||||
|
{
|
||||||
|
return m_lblSecurityIcon->isVisible();
|
||||||
|
}
|
||||||
|
|
||||||
|
void StatusBar::setBtnFingerprintVisible(bool visible)
|
||||||
|
{
|
||||||
|
m_btnFingerprint->setVisible(visible);
|
||||||
|
}
|
||||||
|
|
||||||
|
void StatusBar::updateFound(const QString &version)
|
||||||
|
{
|
||||||
|
m_btnUpdate->setVisible(true);
|
||||||
|
m_btnUpdate->setToolTip(tr("A new version v%1 is available").arg(version));
|
||||||
|
}
|
||||||
|
|
||||||
|
void StatusBar::changeEvent(QEvent *e)
|
||||||
|
{
|
||||||
|
QStatusBar::changeEvent(e);
|
||||||
|
if (e->type() == QEvent::LanguageChange)
|
||||||
|
updateText();
|
||||||
|
}
|
||||||
|
|
||||||
|
void StatusBar::updateText()
|
||||||
|
{
|
||||||
|
m_btnFingerprint->setToolTip(tr("View local fingerprint"));
|
||||||
|
m_btnUpdate->setText(tr("Update available"));
|
||||||
|
setSecurityLevel(m_securityLevel);
|
||||||
|
}
|
||||||
|
|
||||||
|
void StatusBar::setSecurityIcon(bool encrypted)
|
||||||
|
{
|
||||||
|
const auto icon = QIcon::fromTheme(encrypted ? QIcon::ThemeIcon::SecurityHigh : QIcon::ThemeIcon::SecurityLow);
|
||||||
|
m_lblSecurityIcon->setPixmap(icon.pixmap(QSize(32, 32)));
|
||||||
|
m_encrypted = encrypted;
|
||||||
|
setSecurityLevel(m_securityLevel);
|
||||||
|
}
|
||||||
|
|
||||||
|
void StatusBar::setSecurityLevel(const QString &securityLevel)
|
||||||
|
{
|
||||||
|
m_securityLevel = securityLevel;
|
||||||
|
const auto txt = m_encrypted ? tr("%1 Encryption Enabled").arg(m_securityLevel) : tr("Encryption Disabled");
|
||||||
|
m_lblSecurityIcon->setToolTip(txt);
|
||||||
|
}
|
||||||
49
src/lib/gui/widgets/StatusBar.h
Normal file
49
src/lib/gui/widgets/StatusBar.h
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
* Deskflow -- mouse and keyboard sharing utility
|
||||||
|
* SPDX-FileCopyrightText: (C) 2025 - 2026 Deskflow Developers
|
||||||
|
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QStatusBar>
|
||||||
|
|
||||||
|
#include "common/Enums.h"
|
||||||
|
|
||||||
|
class QPushButton;
|
||||||
|
class QLabel;
|
||||||
|
|
||||||
|
using ProcessState = deskflow::core::ProcessState;
|
||||||
|
using ConnectionState = deskflow::core::ConnectionState;
|
||||||
|
|
||||||
|
class StatusBar : public QStatusBar
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit StatusBar(QWidget *parent = nullptr);
|
||||||
|
void setStatus(ConnectionState connectionState, ProcessState processState, bool isServer);
|
||||||
|
void setServerClients(const QStringList &clients);
|
||||||
|
void setSecurityIconVisible(bool visible);
|
||||||
|
bool securityIconVisible() const;
|
||||||
|
void updateSecurityInfo(bool encrypted);
|
||||||
|
void setSecurityIcon(bool encrypted);
|
||||||
|
void setSecurityLevel(const QString &securityLevel);
|
||||||
|
void setBtnFingerprintVisible(bool visible);
|
||||||
|
void updateFound(const QString &version);
|
||||||
|
|
||||||
|
Q_SIGNALS:
|
||||||
|
void requestShowMyFingerprints();
|
||||||
|
void requestUpdateVersion();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void changeEvent(QEvent *e) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void updateText();
|
||||||
|
QPushButton *m_btnFingerprint = nullptr;
|
||||||
|
QLabel *m_lblSecurityIcon = nullptr;
|
||||||
|
QLabel *m_lblStatus = nullptr;
|
||||||
|
QPushButton *m_btnUpdate = nullptr;
|
||||||
|
bool m_encrypted = false;
|
||||||
|
QString m_securityLevel;
|
||||||
|
};
|
||||||
@ -81,6 +81,11 @@ deskflow::IStream *StreamFilter::getStream() const
|
|||||||
return m_stream;
|
return m_stream;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool StreamFilter::adoptedStream() const
|
||||||
|
{
|
||||||
|
return m_adopted;
|
||||||
|
}
|
||||||
|
|
||||||
void StreamFilter::filterEvent(const Event &event)
|
void StreamFilter::filterEvent(const Event &event)
|
||||||
{
|
{
|
||||||
m_events->dispatchEvent(Event(event.getType(), getEventTarget(), event.getData()));
|
m_events->dispatchEvent(Event(event.getType(), getEventTarget(), event.getData()));
|
||||||
|
|||||||
@ -51,6 +51,8 @@ public:
|
|||||||
*/
|
*/
|
||||||
deskflow::IStream *getStream() const;
|
deskflow::IStream *getStream() const;
|
||||||
|
|
||||||
|
bool adoptedStream() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
//! Handle events from source stream
|
//! Handle events from source stream
|
||||||
/*!
|
/*!
|
||||||
|
|||||||
@ -658,9 +658,9 @@ ISocketMultiplexerJob *SecureSocket::serviceConnect(ISocketMultiplexerJob *const
|
|||||||
Lock lock(&getMutex());
|
Lock lock(&getMutex());
|
||||||
|
|
||||||
int status = 0;
|
int status = 0;
|
||||||
#ifdef SYSAPI_WIN32
|
#if defined(Q_OS_WIN)
|
||||||
status = secureConnect(static_cast<int>(getSocket()->m_socket));
|
status = secureConnect(static_cast<int>(getSocket()->m_socket));
|
||||||
#elif SYSAPI_UNIX
|
#else
|
||||||
status = secureConnect(getSocket()->m_fd);
|
status = secureConnect(getSocket()->m_fd);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -686,13 +686,14 @@ ISocketMultiplexerJob *SecureSocket::serviceAccept(ISocketMultiplexerJob *const,
|
|||||||
Lock lock(&getMutex());
|
Lock lock(&getMutex());
|
||||||
|
|
||||||
int status = 0;
|
int status = 0;
|
||||||
#ifdef SYSAPI_WIN32
|
#if defined(Q_OS_WIN)
|
||||||
status = secureAccept(static_cast<int>(getSocket()->m_socket));
|
status = secureAccept(static_cast<int>(getSocket()->m_socket));
|
||||||
#elif SYSAPI_UNIX
|
#else
|
||||||
status = secureAccept(getSocket()->m_fd);
|
status = secureAccept(getSocket()->m_fd);
|
||||||
#endif
|
#endif
|
||||||
// If status < 0, error happened
|
// If status < 0, error happened
|
||||||
if (status < 0) {
|
if (status < 0) {
|
||||||
|
sendEvent(EventTypes::ClientListenerDisconnectedOnAccept);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -92,7 +92,7 @@ void generatePemSelfSignedCert(const QString &path, int keyLength)
|
|||||||
X509_sign(cert, privateKey, EVP_sha256());
|
X509_sign(cert, privateKey, EVP_sha256());
|
||||||
|
|
||||||
const std::filesystem::path fsPath = path.toStdString();
|
const std::filesystem::path fsPath = path.toStdString();
|
||||||
#if SYSAPI_WIN32
|
#if defined(Q_OS_WIN)
|
||||||
auto fp = _wfopen(fsPath.native().c_str(), L"w");
|
auto fp = _wfopen(fsPath.native().c_str(), L"w");
|
||||||
#else
|
#else
|
||||||
auto fp = std::fopen(fsPath.native().c_str(), "w");
|
auto fp = std::fopen(fsPath.native().c_str(), "w");
|
||||||
|
|||||||
@ -54,7 +54,7 @@ void TCPListenSocket::bind(const NetworkAddress &addr)
|
|||||||
try {
|
try {
|
||||||
std::scoped_lock lock{m_mutex};
|
std::scoped_lock lock{m_mutex};
|
||||||
|
|
||||||
#if SYSAPI_UNIX
|
#if defined(Q_OS_UNIX)
|
||||||
// Only reuse socket addr on Unix so we can restart the server quickly (Unix holds the port
|
// Only reuse socket addr on Unix so we can restart the server quickly (Unix holds the port
|
||||||
// in TIME_WAIT for a few mins after close). This is not needed on Windows and can cause issues
|
// in TIME_WAIT for a few mins after close). This is not needed on Windows and can cause issues
|
||||||
// because binding to a re-use port makes it look like the server is listening when it is not.
|
// because binding to a re-use port makes it look like the server is listening when it is not.
|
||||||
|
|||||||
@ -177,7 +177,7 @@ if(UNIX)
|
|||||||
if(${LIBXKBCOMMON_VERSION} VERSION_GREATER_EQUAL "1.10")
|
if(${LIBXKBCOMMON_VERSION} VERSION_GREATER_EQUAL "1.10")
|
||||||
target_compile_definitions(platform PRIVATE HAVE_XKB_KEYMAP_MOD_GET_MASK=1)
|
target_compile_definitions(platform PRIVATE HAVE_XKB_KEYMAP_MOD_GET_MASK=1)
|
||||||
endif()
|
endif()
|
||||||
target_compile_definitions(platform PUBLIC WINAPI_LIBEI WINAPI_LIBPORTAL HAVE_LIBPORTAL_INPUTCAPTURE)
|
target_compile_definitions(platform PUBLIC WINAPI_LIBEI WINAPI_LIBPORTAL)
|
||||||
target_include_directories(platform PUBLIC ${LIBEI_INCLUDE_DIRS} ${LIBPORTAL_INCLUDE_DIRS})
|
target_include_directories(platform PUBLIC ${LIBEI_INCLUDE_DIRS} ${LIBPORTAL_INCLUDE_DIRS})
|
||||||
target_link_libraries(
|
target_link_libraries(
|
||||||
platform
|
platform
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Deskflow -- mouse and keyboard sharing utility
|
* Deskflow -- mouse and keyboard sharing utility
|
||||||
|
* SPDX-FileCopyrightText: (C) 2026 Deskflow Developers
|
||||||
* SPDX-FileCopyrightText: (C) 2012 - 2016 Symless Ltd.
|
* SPDX-FileCopyrightText: (C) 2012 - 2016 Symless Ltd.
|
||||||
* SPDX-FileCopyrightText: (C) 2002 Chris Schoeneman
|
* SPDX-FileCopyrightText: (C) 2002 Chris Schoeneman
|
||||||
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
|
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
|
||||||
@ -116,14 +117,26 @@ bool MSWindowsClipboard::open(Time time) const
|
|||||||
{
|
{
|
||||||
LOG_DEBUG("open clipboard");
|
LOG_DEBUG("open clipboard");
|
||||||
|
|
||||||
if (!OpenClipboard(m_window)) {
|
// The clipboard is a global mutex on Windows. We aren't always going to
|
||||||
LOG_WARN("failed to open clipboard: %d", GetLastError());
|
// get the lock on the first try, so try a few times before giving up.
|
||||||
return false;
|
// Based on Chromium's ScopedClipboard::Acquire() retry loop.
|
||||||
|
static const int kMaxRetries = 5;
|
||||||
|
static const int kRetryDelayMs = 5;
|
||||||
|
|
||||||
|
for (int i = 0; i < kMaxRetries; ++i) {
|
||||||
|
if (OpenClipboard(m_window)) {
|
||||||
|
m_time = time;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_time = time;
|
if (i < kMaxRetries - 1) {
|
||||||
|
LOG_DEBUG("failed to open clipboard (attempt %d/%d, error=%d), retrying", i + 1, kMaxRetries, GetLastError());
|
||||||
|
Sleep(kRetryDelayMs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
LOG_WARN("failed to open clipboard after %d attempts: %d", kMaxRetries, GetLastError());
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MSWindowsClipboard::close() const
|
void MSWindowsClipboard::close() const
|
||||||
|
|||||||
@ -5,7 +5,6 @@
|
|||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#if WINAPI_CARBON
|
|
||||||
#include <Carbon/Carbon.h>
|
#include <Carbon/Carbon.h>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
@ -13,5 +12,3 @@ using CFDeallocator = decltype(&CFRelease);
|
|||||||
using AutoCFArray = std::unique_ptr<const __CFArray, CFDeallocator>;
|
using AutoCFArray = std::unique_ptr<const __CFArray, CFDeallocator>;
|
||||||
using AutoCFDictionary = std::unique_ptr<const __CFDictionary, CFDeallocator>;
|
using AutoCFDictionary = std::unique_ptr<const __CFDictionary, CFDeallocator>;
|
||||||
using AutoTISInputSourceRef = std::unique_ptr<__TISInputSource, CFDeallocator>;
|
using AutoTISInputSourceRef = std::unique_ptr<__TISInputSource, CFDeallocator>;
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|||||||
@ -31,9 +31,10 @@ void OSXEventQueueBuffer::waitForEvent(double timeout)
|
|||||||
{
|
{
|
||||||
std::unique_lock lock(m_mutex);
|
std::unique_lock lock(m_mutex);
|
||||||
if (m_dataQueue.empty()) {
|
if (m_dataQueue.empty()) {
|
||||||
auto duration = std::chrono::duration<double>(timeout);
|
|
||||||
LOG_DEBUG2("waiting for event, timeout: %f seconds", timeout);
|
LOG_DEBUG2("waiting for event, timeout: %f seconds", timeout);
|
||||||
m_cond.wait_for(lock, duration, [this] { return !m_dataQueue.empty(); });
|
auto end = timeout < 0 ? std::chrono::steady_clock::time_point::max()
|
||||||
|
: std::chrono::steady_clock::now() + std::chrono::duration<double>(timeout);
|
||||||
|
m_cond.wait_until(lock, end, [this] { return !m_dataQueue.empty(); });
|
||||||
} else {
|
} else {
|
||||||
LOG_DEBUG2("found events in the queue");
|
LOG_DEBUG2("found events in the queue");
|
||||||
}
|
}
|
||||||
|
|||||||
@ -815,7 +815,7 @@ void XWindowsScreen::fakeMouseWheel(ScrollDelta delta) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
// send as many clicks as necessary
|
// send as many clicks as necessary
|
||||||
while (axisDelta >= 0) {
|
while (axisDelta > 0) {
|
||||||
XTestFakeButtonEvent(m_display, button, True, CurrentTime);
|
XTestFakeButtonEvent(m_display, button, True, CurrentTime);
|
||||||
XTestFakeButtonEvent(m_display, button, False, CurrentTime);
|
XTestFakeButtonEvent(m_display, button, False, CurrentTime);
|
||||||
axisDelta -= s_scrollDelta;
|
axisDelta -= s_scrollDelta;
|
||||||
|
|||||||
@ -138,6 +138,14 @@ void ClientListener::handleClientConnecting()
|
|||||||
[this, rawSocketPointer](const auto &) { handleClientAccepted(rawSocketPointer); }
|
[this, rawSocketPointer](const auto &) { handleClientAccepted(rawSocketPointer); }
|
||||||
);
|
);
|
||||||
|
|
||||||
|
m_events->addHandler(
|
||||||
|
EventTypes::ClientListenerDisconnectedOnAccept, rawSocketPointer->getEventTarget(),
|
||||||
|
[this, rawSocketPointer](const auto &) {
|
||||||
|
LOG_DEBUG("disconnected client before accept");
|
||||||
|
removeClientSocket(rawSocketPointer);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
// When using non SSL, server accepts clients immediately, while SSL
|
// When using non SSL, server accepts clients immediately, while SSL
|
||||||
// has to call secure accept which may require retry
|
// has to call secure accept which may require retry
|
||||||
if (m_securityLevel == SecurityLevel::PlainText) {
|
if (m_securityLevel == SecurityLevel::PlainText) {
|
||||||
@ -163,7 +171,15 @@ void ClientListener::handleClientAccepted(IDataSocket *socket)
|
|||||||
handleUnknownClient(client);
|
handleUnknownClient(client);
|
||||||
});
|
});
|
||||||
m_events->addHandler(EventTypes::ClientProxyUnknownFailure, client, [this, client](const auto &) {
|
m_events->addHandler(EventTypes::ClientProxyUnknownFailure, client, [this, client](const auto &) {
|
||||||
|
auto *filter = dynamic_cast<StreamFilter *>(client->getStream());
|
||||||
|
IDataSocket *socket = nullptr;
|
||||||
|
if (filter && !filter->adoptedStream()) {
|
||||||
|
socket = dynamic_cast<IDataSocket *>(filter->getStream());
|
||||||
|
}
|
||||||
removeUnknownClient(client);
|
removeUnknownClient(client);
|
||||||
|
if (socket) {
|
||||||
|
removeClientSocket(socket);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -205,14 +221,20 @@ void ClientListener::handleClientDisconnected(ClientProxy *client)
|
|||||||
// we know which socket we no longer need
|
// we know which socket we no longer need
|
||||||
auto *socket = static_cast<IDataSocket *>(client->getStream());
|
auto *socket = static_cast<IDataSocket *>(client->getStream());
|
||||||
delete client;
|
delete client;
|
||||||
m_clientSockets.erase(socket);
|
removeClientSocket(socket);
|
||||||
delete socket;
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ClientListener::removeClientSocket(IDataSocket *socket)
|
||||||
|
{
|
||||||
|
m_clientSockets.erase(socket);
|
||||||
|
m_events->removeHandlers(socket->getEventTarget());
|
||||||
|
delete socket;
|
||||||
|
}
|
||||||
|
|
||||||
void ClientListener::cleanupListenSocket()
|
void ClientListener::cleanupListenSocket()
|
||||||
{
|
{
|
||||||
delete m_listen;
|
delete m_listen;
|
||||||
|
|||||||
@ -71,6 +71,7 @@ private:
|
|||||||
void handleUnknownClient(ClientProxyUnknown *unknownClient);
|
void handleUnknownClient(ClientProxyUnknown *unknownClient);
|
||||||
void handleClientDisconnected(ClientProxy *client);
|
void handleClientDisconnected(ClientProxy *client);
|
||||||
|
|
||||||
|
void removeClientSocket(IDataSocket *socket);
|
||||||
void cleanupListenSocket();
|
void cleanupListenSocket();
|
||||||
void cleanupClientSockets();
|
void cleanupClientSockets();
|
||||||
void start();
|
void start();
|
||||||
|
|||||||
@ -199,7 +199,7 @@ public:
|
|||||||
|
|
||||||
//! Add screen
|
//! Add screen
|
||||||
/*!
|
/*!
|
||||||
Adds a screen, returning true iff successful. If a screen or
|
Adds a screen, returning true if successful. If a screen or
|
||||||
alias with the given name exists then it fails.
|
alias with the given name exists then it fails.
|
||||||
*/
|
*/
|
||||||
bool addScreen(const std::string &name);
|
bool addScreen(const std::string &name);
|
||||||
|
|||||||
@ -9,7 +9,7 @@
|
|||||||
#include "base/Log.h"
|
#include "base/Log.h"
|
||||||
#include "unittests/legacytests/shared/ExitTimeout.h"
|
#include "unittests/legacytests/shared/ExitTimeout.h"
|
||||||
|
|
||||||
#if SYSAPI_WIN32
|
#if defined(Q_OS_WIN)
|
||||||
#include "arch/win32/ArchMiscWindows.h"
|
#include "arch/win32/ArchMiscWindows.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -23,7 +23,7 @@ int main(int argc, char **argv)
|
|||||||
{
|
{
|
||||||
ExitTimeout exitTimeout(1, "Unit tests");
|
ExitTimeout exitTimeout(1, "Unit tests");
|
||||||
|
|
||||||
#if SYSAPI_WIN32
|
#if defined(Q_OS_WIN)
|
||||||
// HACK: shouldn't be needed, but logging fails without this.
|
// HACK: shouldn't be needed, but logging fails without this.
|
||||||
ArchMiscWindows::setInstanceWin32(GetModuleHandle(nullptr));
|
ArchMiscWindows::setInstanceWin32(GetModuleHandle(nullptr));
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
<!DOCTYPE TS>
|
<!DOCTYPE TS>
|
||||||
<TS version="2.1" language="en_US">
|
<TS version="2.1" language="en_US">
|
||||||
<context>
|
<context>
|
||||||
<name>MainWindow</name>
|
<name>StatusBar</name>
|
||||||
<message numerus="yes">
|
<message numerus="yes">
|
||||||
<source>%1 is connected, with %n client(s): %2</source>
|
<source>%1 is connected, with %n client(s): %2</source>
|
||||||
<extracomment>Shown when in server mode and at least 1 client is connected %1 is replaced by the app name %2 will be a list of at least one client %n will be replaced by the number of clients (n is >=1), it is not requried to be in the translation</extracomment>
|
<extracomment>Shown when in server mode and at least 1 client is connected %1 is replaced by the app name %2 will be a list of at least one client %n will be replaced by the number of clients (n is >=1), it is not requried to be in the translation</extracomment>
|
||||||
|
|||||||
@ -386,22 +386,14 @@ Do you want to connect to the server?
|
|||||||
<extracomment>stop core shortcut</extracomment>
|
<extracomment>stop core shortcut</extracomment>
|
||||||
<translation type="unfinished">Ctrl+T</translation>
|
<translation type="unfinished">Ctrl+T</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source><p>Failed to connect to the server '%1'.</p><p>A Client with your name is already connected to the server.</p>Please ensure that you're using a unique name and that only a single instance of the client process is running.</p></source>
|
||||||
|
<translation><p>Error al conectar con el servidor '%1'.</p><p>A Client with your name is already connected to the server.</p>Please ensure that you're using a unique name and that only a single instance of the client process is running.</p></translation>
|
||||||
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Your current TLS key is smaller than the minimum allowed size, A new key 2048-bit key will be generated.</source>
|
<source>Your current TLS key is smaller than the minimum allowed size, A new key 2048-bit key will be generated.</source>
|
||||||
<translation type="unfinished">Su clave TLS actual es más pequeña que el tamaño mínimo permitido. Se generará una nueva clave de 2048 bits.</translation>
|
<translation type="unfinished">Su clave TLS actual es más pequeña que el tamaño mínimo permitido. Se generará una nueva clave de 2048 bits.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>View local fingerprint</source>
|
|
||||||
<translation type="unfinished">Ver huella digital local</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>Update available</source>
|
|
||||||
<translation type="unfinished">Actualización disponible</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>A new version v%1 is available</source>
|
|
||||||
<translation type="unfinished">Ya está disponible una nueva versión v%1</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>Address missing</source>
|
<source>Address missing</source>
|
||||||
<translation type="unfinished">Dirección faltante</translation>
|
<translation type="unfinished">Dirección faltante</translation>
|
||||||
@ -410,10 +402,6 @@ Do you want to connect to the server?
|
|||||||
<source>Please enter the hostname or IP address of the other computer.</source>
|
<source>Please enter the hostname or IP address of the other computer.</source>
|
||||||
<translation type="unfinished">Introduzca el nombre de host o la dirección IP de la otra computadora.</translation>
|
<translation type="unfinished">Introduzca el nombre de host o la dirección IP de la otra computadora.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>Core cannot be started</source>
|
|
||||||
<translation type="unfinished">No se puede iniciar el núcleo</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>Save server configuration as...</source>
|
<source>Save server configuration as...</source>
|
||||||
<translation type="unfinished">Guardar la configuración del servidor como...</translation>
|
<translation type="unfinished">Guardar la configuración del servidor como...</translation>
|
||||||
@ -443,12 +431,8 @@ Do you want to connect to the server?
|
|||||||
<translation type="unfinished">Desconectar</translation>
|
<translation type="unfinished">Desconectar</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>%1 Encryption Enabled</source>
|
<source>%1 Connection Error</source>
|
||||||
<translation type="unfinished">%1 Cifrado habilitado</translation>
|
<translation>%1 Error de conexión</translation>
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>Encryption Disabled</source>
|
|
||||||
<translation type="unfinished">Cifrado deshabilitado</translation>
|
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>No IP Detected</source>
|
<source>No IP Detected</source>
|
||||||
@ -500,42 +484,10 @@ La dirección IP asignada ahora no es válida; es posible que deba reiniciar el
|
|||||||
<source>&Help</source>
|
<source>&Help</source>
|
||||||
<translation type="unfinished">&Ayuda</translation>
|
<translation type="unfinished">&Ayuda</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>%1 is starting...</source>
|
|
||||||
<translation type="unfinished">%1 está iniciando...</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>invalid certificate, generating a new one</source>
|
<source>invalid certificate, generating a new one</source>
|
||||||
<translation type="unfinished">certificado no válido, generando uno nuevo</translation>
|
<translation type="unfinished">certificado no válido, generando uno nuevo</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>%1 will retry in a moment...</source>
|
|
||||||
<translation type="unfinished">%1 lo intentará nuevamente en un momento...</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>%1 is stopping...</source>
|
|
||||||
<translation type="unfinished">%1 se está deteniendo...</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>%1 is not running</source>
|
|
||||||
<translation type="unfinished">%1 no se está ejecutando</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>%1 is waiting for clients</source>
|
|
||||||
<translation type="unfinished">%1 está esperando clientes</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>%1 is connecting...</source>
|
|
||||||
<translation type="unfinished">%1 se está conectando...</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>%1 is connected as client of %2</source>
|
|
||||||
<translation type="unfinished">%1 está conectado como cliente de %2</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>%1 is disconnected</source>
|
|
||||||
<translation type="unfinished">%1 está desconectado</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>Ctrl+Q</source>
|
<source>Ctrl+Q</source>
|
||||||
<extracomment>Quit shortcut</extracomment>
|
<extracomment>Quit shortcut</extracomment>
|
||||||
@ -562,29 +514,11 @@ Nombres válidos:
|
|||||||
• Use letras y números
|
• Use letras y números
|
||||||
• También puede usar _ o -
|
• También puede usar _ o -
|
||||||
• Tengan entre 1 y 255 caracteres</translation>
|
• Tengan entre 1 y 255 caracteres</translation>
|
||||||
</message>
|
|
||||||
<message numerus="yes">
|
|
||||||
<source>%1 is connected, with %n client(s): %2</source>
|
|
||||||
<extracomment>Shown when in server mode and at least 1 client is connected %1 is replaced by the app name %2 will be a list of at least one client %n will be replaced by the number of clients (n is >=1), it is not requried to be in the translation</extracomment>
|
|
||||||
<translation type="unfinished">
|
|
||||||
<numerusform>%1 está conectado, con un cliente: %2</numerusform>
|
|
||||||
<numerusform>%1 está conectado, con %n clientes: %2</numerusform>
|
|
||||||
</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>Clients:
|
|
||||||
%1</source>
|
|
||||||
<translation type="unfinished">Clientes:
|
|
||||||
%1</translation>
|
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>This computer's name:</source>
|
<source>This computer's name:</source>
|
||||||
<translation type="unfinished">Nombre de esta computadora:</translation>
|
<translation type="unfinished">Nombre de esta computadora:</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>The Core executable could not be successfully started, although it does exist. Please check if you have sufficient permissions to run this program.</source>
|
|
||||||
<translation type="unfinished">No se pudo iniciar el archivo ejecutable principal, aunque existe. Compruebe si tiene permisos suficientes para ejecutar este programa.</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>&Configure Client</source>
|
<source>&Configure Client</source>
|
||||||
<translation type="unfinished">&Configurar cliente</translation>
|
<translation type="unfinished">&Configurar cliente</translation>
|
||||||
@ -595,7 +529,27 @@ Nombres válidos:
|
|||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source><html>Hostname or IP address of the server computer.<br/>May contain a comma seperated list.</html></source>
|
<source><html>Hostname or IP address of the server computer.<br/>May contain a comma seperated list.</html></source>
|
||||||
<translation type="unfinished"><html>Nome host o indirizzo IP del computer server.<br/>Può contenere un elenco separato da virgole.</html></translation>
|
<translation type="unfinished"><html>Nombre de host o dirección IP del servidor.<br/>Puede contener una lista separada por comas.</html></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>read</source>
|
||||||
|
<translation type="unfinished">leer</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>read and write</source>
|
||||||
|
<translation type="unfinished">leer y escribir</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>The Core executable could not be started.
|
||||||
|
Please check if you have sufficient permissions to run %1.</source>
|
||||||
|
<translation type="unfinished">No se pudo iniciar el ejecutable Core.
|
||||||
|
Verifique si tiene permisos suficientes para ejecutar %1.</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>
|
||||||
|
Additionally, check you are able to %1 the server config file: %2</source>
|
||||||
|
<translation type="unfinished">
|
||||||
|
Además, verifique que puede %1 el archivo de configuración del servidor: %2</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
@ -676,30 +630,6 @@ Nombres válidos:
|
|||||||
<source>%1 Connected</source>
|
<source>%1 Connected</source>
|
||||||
<translation type="unfinished">%1 Conectado</translation>
|
<translation type="unfinished">%1 Conectado</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source><p>Failed to connect to the server '%1'.</p></source>
|
|
||||||
<translation type="unfinished"><p>Error al conectar con el servidor '%1'.</p></translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source><p>A Client with your name is already connected to the server.</p>Please ensure that you're using a unique name and that only a single instance of the client process is running.</p></source>
|
|
||||||
<translation type="unfinished"><p>Ya hay un cliente conectado al servidor con su nombre.</p>Asegúrese de utilizar un nombre único y de que solo se esté ejecutando una única instancia del proceso del cliente.</p></translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source><p>Please try to connect to the server using the server IP address instead of the hostname. </p><p>If that doesn't work, please check your TLS and firewall settings.</p></source>
|
|
||||||
<translation type="unfinished"><p>Intente conectarse al servidor usando la dirección IP del servidor en lugar del nombre de host.</p><p>Si eso no funciona, verifique la configuración de TLS y firewall.</p></translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source><p>Please check your TLS and firewall settings.</p></source>
|
|
||||||
<translation type="unfinished"><p>Por favor revise su configuración de TLS y firewall.</p></translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>%1 Connection Error</source>
|
|
||||||
<translation type="unfinished">%1 Error de conexión</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>Do not show this message again</source>
|
|
||||||
<translation type="unfinished">No volver a mostrar este mensaje</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>%1 - New Client</source>
|
<source>%1 - New Client</source>
|
||||||
<translation type="unfinished">%1 - Nuevo cliente</translation>
|
<translation type="unfinished">%1 - Nuevo cliente</translation>
|
||||||
@ -736,10 +666,6 @@ Nombres válidos:
|
|||||||
<source><p>Settings are read-only because you only have read access to the file:</p><p>%1</p></source>
|
<source><p>Settings are read-only because you only have read access to the file:</p><p>%1</p></source>
|
||||||
<translation type="unfinished"><p>Las configuraciones son de solo lectura porque solo tiene acceso de lectura al archivo:</p><p>%1</p></translation>
|
<translation type="unfinished"><p>Las configuraciones son de solo lectura porque solo tiene acceso de lectura al archivo:</p><p>%1</p></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source><p>Sorry, while this version of %1 does support Wayland, this build was not linked with one or more of the required libraries.</p><p>Please either switch to X from your login screen or use a build that uses the correct libraries.</p><p>If you think this is incorrect, please <a href="%2">report a bug</a>.</p><p>Please check the logs for more information.</p></source>
|
|
||||||
<translation><p>Lo sentimos, aunque esta versión de %1 es compatible con Wayland, esta compilación no se vinculó con una o más de las bibliotecas requeridas.</p><p>Cambie a X desde su pantalla de inicio de sesión o use una compilación que use las bibliotecas correctas.</p><p>Si cree que esto es incorrecto, <a href="%2">informe un error</a>.</p><p>Consulte los registros para obtener más información.</p></translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>No thanks</source>
|
<source>No thanks</source>
|
||||||
<translation type="unfinished">No, gracias</translation>
|
<translation type="unfinished">No, gracias</translation>
|
||||||
@ -1151,30 +1077,14 @@ Al habilitar esta opción, se deshabilitará la interfaz gráfica de usuario (GU
|
|||||||
<source>Preferences</source>
|
<source>Preferences</source>
|
||||||
<translation type="unfinished">Preferencias</translation>
|
<translation type="unfinished">Preferencias</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>&Regular</source>
|
|
||||||
<translation type="unfinished">&Regular</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>App</source>
|
|
||||||
<translation type="unfinished">Aplicación</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>Check for updates on startup</source>
|
<source>Check for updates on startup</source>
|
||||||
<translation type="unfinished">Buscar actualizaciones al iniciar</translation>
|
<translation type="unfinished">Buscar actualizaciones al iniciar</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>Hide the window when the app starts</source>
|
|
||||||
<translation type="unfinished">Ocultar la ventana cuando se inicia la aplicación</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>Prevent this computer from going to sleep</source>
|
<source>Prevent this computer from going to sleep</source>
|
||||||
<translation type="unfinished">Evitar que esta computadora entre en modo de suspensión</translation>
|
<translation type="unfinished">Evitar que esta computadora entre en modo de suspensión</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>Leave app running in notification area when the window is closed</source>
|
|
||||||
<translation type="unfinished">Dejar la aplicación ejecutándose en el área de notificación cuando la ventana esté cerrada</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>Tray icon style</source>
|
<source>Tray icon style</source>
|
||||||
<translation type="unfinished">Estilo de icono de bandeja</translation>
|
<translation type="unfinished">Estilo de icono de bandeja</translation>
|
||||||
@ -1211,10 +1121,6 @@ Al habilitar esta opción, se deshabilitará la interfaz gráfica de usuario (GU
|
|||||||
<source>&Advanced</source>
|
<source>&Advanced</source>
|
||||||
<translation type="unfinished">&Avanzado</translation>
|
<translation type="unfinished">&Avanzado</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>Networking</source>
|
|
||||||
<translation type="unfinished">Redes</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>Port</source>
|
<source>Port</source>
|
||||||
<translation type="unfinished">Puerto</translation>
|
<translation type="unfinished">Puerto</translation>
|
||||||
@ -1223,18 +1129,10 @@ Al habilitar esta opción, se deshabilitará la interfaz gráfica de usuario (GU
|
|||||||
<source>Network IP</source>
|
<source>Network IP</source>
|
||||||
<translation type="unfinished">IP de red</translation>
|
<translation type="unfinished">IP de red</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>Logs</source>
|
|
||||||
<translation type="unfinished">Registros</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>Log path</source>
|
<source>Log path</source>
|
||||||
<translation type="unfinished">Ruta de registro</translation>
|
<translation type="unfinished">Ruta de registro</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>Log to file</source>
|
|
||||||
<translation type="unfinished">Registrar en archivo</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>Fatal</source>
|
<source>Fatal</source>
|
||||||
<translation type="unfinished">Fatal</translation>
|
<translation type="unfinished">Fatal</translation>
|
||||||
@ -1315,6 +1213,22 @@ Al habilitar esta opción, se deshabilitará la interfaz gráfica de usuario (GU
|
|||||||
<source>Verbose debug output</source>
|
<source>Verbose debug output</source>
|
||||||
<translation type="unfinished">Salida de depuración detallada</translation>
|
<translation type="unfinished">Salida de depuración detallada</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Close and save changes</source>
|
||||||
|
<translation type="unfinished">Cerrar y guardar los cambios</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Close and forget changes</source>
|
||||||
|
<translation type="unfinished">Cerrar y olvidar los cambios</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Reset to stored values</source>
|
||||||
|
<translation type="unfinished">Restablecer los valores almacenados</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Reset to default values</source>
|
||||||
|
<translation type="unfinished">Restablecer valores predeterminados</translation>
|
||||||
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>TLS Certificate Regenerated</source>
|
<source>TLS Certificate Regenerated</source>
|
||||||
<translation type="unfinished">Certificado TLS regenerado</translation>
|
<translation type="unfinished">Certificado TLS regenerado</translation>
|
||||||
@ -1335,10 +1249,6 @@ Al habilitar esta opción, se deshabilitará la interfaz gráfica de usuario (GU
|
|||||||
<source>Language</source>
|
<source>Language</source>
|
||||||
<translation type="unfinished">Idioma</translation>
|
<translation type="unfinished">Idioma</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>Force a language to be used for the GUI.</source>
|
|
||||||
<translation type="unfinished">Fuerza el uso de un idioma para la interfaz gráfica de usuario.</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>Enable GUI debug messages</source>
|
<source>Enable GUI debug messages</source>
|
||||||
<translation type="unfinished">Habilitar mensajes de depuración de la interfaz gráfica de usuario</translation>
|
<translation type="unfinished">Habilitar mensajes de depuración de la interfaz gráfica de usuario</translation>
|
||||||
@ -1359,6 +1269,123 @@ Al habilitar esta opción, se deshabilitará la interfaz gráfica de usuario (GU
|
|||||||
<source>Include version in the window title</source>
|
<source>Include version in the window title</source>
|
||||||
<translation type="unfinished">Incluir la versión en el título de la ventana</translation>
|
<translation type="unfinished">Incluir la versión en el título de la ventana</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Log to file</source>
|
||||||
|
<translation>Registrar en archivo</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>&Logs</source>
|
||||||
|
<translation>&Registro</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>&General</source>
|
||||||
|
<translation type="unfinished">&General</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>&Network</source>
|
||||||
|
<translation>R&ed</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>&Window</source>
|
||||||
|
<translation type="unfinished">&Ventana</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>When the main window is closed</source>
|
||||||
|
<translation type="unfinished">Cuando la ventana principal está cerrada</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Exit</source>
|
||||||
|
<translation type="unfinished">Salir</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Send to background</source>
|
||||||
|
<translation type="unfinished">Enviar a segundo plano</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>When the application starts</source>
|
||||||
|
<translation type="unfinished">Cuando se inicia la aplicación</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Show the main window</source>
|
||||||
|
<translation type="unfinished">Mostrar la ventana principal</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Run command on enter</source>
|
||||||
|
<translation type="unfinished">Ejecutar comando al presionar Enter</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Run command on exit</source>
|
||||||
|
<translation type="unfinished">Ejecutar comando al salir</translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>StatusBar</name>
|
||||||
|
<message>
|
||||||
|
<source>%1 is not running</source>
|
||||||
|
<translation type="unfinished">%1 no se está ejecutando</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>%1 is starting...</source>
|
||||||
|
<translation type="unfinished">%1 está iniciando...</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>%1 will retry in a moment...</source>
|
||||||
|
<translation type="unfinished">%1 lo intentará nuevamente en un momento...</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>%1 is stopping...</source>
|
||||||
|
<translation type="unfinished">%1 se está deteniendo...</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>%1 is waiting for clients</source>
|
||||||
|
<translation type="unfinished">%1 está esperando clientes</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>%1 is connecting...</source>
|
||||||
|
<translation type="unfinished">%1 se está conectando...</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>%1 is connected as client of %2</source>
|
||||||
|
<translation type="unfinished">%1 está conectado como cliente de %2</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>%1 is disconnected</source>
|
||||||
|
<translation type="unfinished">%1 está desconectado</translation>
|
||||||
|
</message>
|
||||||
|
<message numerus="yes">
|
||||||
|
<source>%1 is connected, with %n client(s): %2</source>
|
||||||
|
<extracomment>Shown when in server mode and at least 1 client is connected %1 is replaced by the app name %2 will be a list of at least one client %n will be replaced by the number of clients (n is >=1), it is not requried to be in the translation</extracomment>
|
||||||
|
<translation>
|
||||||
|
<numerusform>%1 está conectado, con un cliente: %2</numerusform>
|
||||||
|
<numerusform>%1 está conectado, con %n clientes: %2</numerusform>
|
||||||
|
</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Clients:
|
||||||
|
%1</source>
|
||||||
|
<translation type="unfinished">Clientes:
|
||||||
|
%1</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>A new version v%1 is available</source>
|
||||||
|
<translation type="unfinished">Ya está disponible una nueva versión v%1</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>View local fingerprint</source>
|
||||||
|
<translation type="unfinished">Ver huella digital local</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Update available</source>
|
||||||
|
<translation type="unfinished">Actualización disponible</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>%1 Encryption Enabled</source>
|
||||||
|
<translation type="unfinished">%1 Cifrado habilitado</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Encryption Disabled</source>
|
||||||
|
<translation type="unfinished">Cifrado deshabilitado</translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>i18n</name>
|
<name>i18n</name>
|
||||||
|
|||||||
@ -374,22 +374,14 @@ Vuoi connetterti al server?
|
|||||||
<extracomment>stop core shortcut</extracomment>
|
<extracomment>stop core shortcut</extracomment>
|
||||||
<translation>Ctrl+F</translation>
|
<translation>Ctrl+F</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source><p>Failed to connect to the server '%1'.</p><p>A Client with your name is already connected to the server.</p>Please ensure that you're using a unique name and that only a single instance of the client process is running.</p></source>
|
||||||
|
<translation><p>Impossibile connettersi al server "%1".</p><p>Un client con il tuo nome è già connesso al server.</p>Assicurati di utilizzare un nome univoco e che sia in esecuzione una sola istanza del processo client.</p></translation>
|
||||||
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Your current TLS key is smaller than the minimum allowed size, A new key 2048-bit key will be generated.</source>
|
<source>Your current TLS key is smaller than the minimum allowed size, A new key 2048-bit key will be generated.</source>
|
||||||
<translation>La tua chiave TLS attuale è più piccola della dimensione minima consentita. Verrà generata una nuova chiave a 2048 bit.</translation>
|
<translation>La tua chiave TLS attuale è più piccola della dimensione minima consentita. Verrà generata una nuova chiave a 2048 bit.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>View local fingerprint</source>
|
|
||||||
<translation>Visualizza impronta digitale locale</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>Update available</source>
|
|
||||||
<translation>Aggiornamento disponibile</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>A new version v%1 is available</source>
|
|
||||||
<translation>È disponibile una nuova versione v%1</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>Address missing</source>
|
<source>Address missing</source>
|
||||||
<translation>Indirizzo mancante</translation>
|
<translation>Indirizzo mancante</translation>
|
||||||
@ -398,10 +390,6 @@ Vuoi connetterti al server?
|
|||||||
<source>Please enter the hostname or IP address of the other computer.</source>
|
<source>Please enter the hostname or IP address of the other computer.</source>
|
||||||
<translation>Inserisci l'hostname o l'indirizzo IP dell'altro computer.</translation>
|
<translation>Inserisci l'hostname o l'indirizzo IP dell'altro computer.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>Core cannot be started</source>
|
|
||||||
<translation>Impossibile avviare il core</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>Save server configuration as...</source>
|
<source>Save server configuration as...</source>
|
||||||
<translation>Salva configurazione server come...</translation>
|
<translation>Salva configurazione server come...</translation>
|
||||||
@ -431,12 +419,8 @@ Vuoi connetterti al server?
|
|||||||
<translation>Disconnetti</translation>
|
<translation>Disconnetti</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>%1 Encryption Enabled</source>
|
<source>%1 Connection Error</source>
|
||||||
<translation>%1 Crittografia abilitata</translation>
|
<translation>Errore di connessione %1</translation>
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>Encryption Disabled</source>
|
|
||||||
<translation>Crittografia disabilitata</translation>
|
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>No IP Detected</source>
|
<source>No IP Detected</source>
|
||||||
@ -502,48 +486,10 @@ Nomi validi:
|
|||||||
• Può anche usare _ o -
|
• Può anche usare _ o -
|
||||||
• Deve essere compreso tra 1 e 255 caratteri</translation>
|
• Deve essere compreso tra 1 e 255 caratteri</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>Clients:
|
|
||||||
%1</source>
|
|
||||||
<translation>Client:
|
|
||||||
%1</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>%1 is starting...</source>
|
|
||||||
<translation>%1 si sta avviando...</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>invalid certificate, generating a new one</source>
|
<source>invalid certificate, generating a new one</source>
|
||||||
<translation type="unfinished">certificato non valido, ne viene generato uno nuovo</translation>
|
<translation type="unfinished">certificato non valido, ne viene generato uno nuovo</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>%1 will retry in a moment...</source>
|
|
||||||
<translation>%1 riproverà tra un momento...</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>%1 is stopping...</source>
|
|
||||||
<translation>%1 si sta arrestando...</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>%1 is not running</source>
|
|
||||||
<translation>%1 non è in esecuzione</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>%1 is waiting for clients</source>
|
|
||||||
<translation>%1 è in attesa di client</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>%1 is connecting...</source>
|
|
||||||
<translation>%1 è in connessione...</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>%1 is connected as client of %2</source>
|
|
||||||
<translation>%1 è connesso come client di %2</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>%1 is disconnected</source>
|
|
||||||
<translation>%1 è disconnesso</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>Ctrl+Q</source>
|
<source>Ctrl+Q</source>
|
||||||
<extracomment>Quit shortcut</extracomment>
|
<extracomment>Quit shortcut</extracomment>
|
||||||
@ -557,14 +503,6 @@ Nomi validi:
|
|||||||
<source>Screen name already exists</source>
|
<source>Screen name already exists</source>
|
||||||
<translation>Il nome dello schermo esiste già</translation>
|
<translation>Il nome dello schermo esiste già</translation>
|
||||||
</message>
|
</message>
|
||||||
<message numerus="yes">
|
|
||||||
<source>%1 is connected, with %n client(s): %2</source>
|
|
||||||
<extracomment>Shown when in server mode and at least 1 client is connected %1 is replaced by the app name %2 will be a list of at least one client %n will be replaced by the number of clients (n is >=1), it is not requried to be in the translation</extracomment>
|
|
||||||
<translation>
|
|
||||||
<numerusform>%1 è connesso con un client %2</numerusform>
|
|
||||||
<numerusform>%1 è connesso con %n client: %2</numerusform>
|
|
||||||
</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>This computer's name:</source>
|
<source>This computer's name:</source>
|
||||||
<translation>Nome di questo computer:</translation>
|
<translation>Nome di questo computer:</translation>
|
||||||
@ -581,10 +519,6 @@ Nomi validi:
|
|||||||
<translation>Usa mouse e tastiera di un altro computer
|
<translation>Usa mouse e tastiera di un altro computer
|
||||||
(imposta questo computer come client)</translation>
|
(imposta questo computer come client)</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>The Core executable could not be successfully started, although it does exist. Please check if you have sufficient permissions to run this program.</source>
|
|
||||||
<translation type="unfinished">Non è stato possibile avviare correttamente l'eseguibile Core, sebbene esista. Verifica di disporre delle autorizzazioni necessarie per eseguire questo programma.</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>&Configure Client</source>
|
<source>&Configure Client</source>
|
||||||
<translation type="unfinished">&Configurare il client</translation>
|
<translation type="unfinished">&Configurare il client</translation>
|
||||||
@ -597,6 +531,26 @@ Nomi validi:
|
|||||||
<source><html>Hostname or IP address of the server computer.<br/>May contain a comma seperated list.</html></source>
|
<source><html>Hostname or IP address of the server computer.<br/>May contain a comma seperated list.</html></source>
|
||||||
<translation type="unfinished"><html>Nome host o indirizzo IP del computer server.<br/>Può contenere un elenco separato da virgole.</html></translation>
|
<translation type="unfinished"><html>Nome host o indirizzo IP del computer server.<br/>Può contenere un elenco separato da virgole.</html></translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>read</source>
|
||||||
|
<translation type="unfinished">leggere</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>read and write</source>
|
||||||
|
<translation type="unfinished">leggere e scrivere</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>The Core executable could not be started.
|
||||||
|
Please check if you have sufficient permissions to run %1.</source>
|
||||||
|
<translation type="unfinished">Impossibile avviare l'eseguibile Core.
|
||||||
|
Verifica di avere i permessi sufficienti per eseguire %1.</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>
|
||||||
|
Additionally, check you are able to %1 the server config file: %2</source>
|
||||||
|
<translation type="unfinished">
|
||||||
|
Inoltre, verifica di poter %1 il file di configurazione del server: %2</translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>NewScreenWidget</name>
|
<name>NewScreenWidget</name>
|
||||||
@ -676,30 +630,6 @@ Nomi validi:
|
|||||||
<source>%1 Connected</source>
|
<source>%1 Connected</source>
|
||||||
<translation>%1 Connesso</translation>
|
<translation>%1 Connesso</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source><p>Failed to connect to the server '%1'.</p></source>
|
|
||||||
<translation><p>Impossibile connettersi al server "%1".</p></translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source><p>A Client with your name is already connected to the server.</p>Please ensure that you're using a unique name and that only a single instance of the client process is running.</p></source>
|
|
||||||
<translation><p>Un client con il tuo nome è già connesso al server.</p>Assicurati di utilizzare un nome univoco e che sia in esecuzione una sola istanza del processo client.</p></translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source><p>Please try to connect to the server using the server IP address instead of the hostname. </p><p>If that doesn't work, please check your TLS and firewall settings.</p></source>
|
|
||||||
<translation><p>Prova a connetterti al server usando l'indirizzo IP del server invece del nome host.</p><p>Se non funziona, controlla le impostazioni TLS e del firewall.</p></translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source><p>Please check your TLS and firewall settings.</p></source>
|
|
||||||
<translation><p>Controlla le impostazioni TLS e del firewall.</p></translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>%1 Connection Error</source>
|
|
||||||
<translation>Errore di connessione %1</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>Do not show this message again</source>
|
|
||||||
<translation>Non mostrare più questo messaggio</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>%1 - New Client</source>
|
<source>%1 - New Client</source>
|
||||||
<translation>%1 - Nuovo Client</translation>
|
<translation>%1 - Nuovo Client</translation>
|
||||||
@ -736,10 +666,6 @@ Nomi validi:
|
|||||||
<source><p>Settings are read-only because you only have read access to the file:</p><p>%1</p></source>
|
<source><p>Settings are read-only because you only have read access to the file:</p><p>%1</p></source>
|
||||||
<translation><p>Le impostazioni sono di sola lettura perché hai solo accesso in lettura al file:</p><p>%1</p></translation>
|
<translation><p>Le impostazioni sono di sola lettura perché hai solo accesso in lettura al file:</p><p>%1</p></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source><p>Sorry, while this version of %1 does support Wayland, this build was not linked with one or more of the required libraries.</p><p>Please either switch to X from your login screen or use a build that uses the correct libraries.</p><p>If you think this is incorrect, please <a href="%2">report a bug</a>.</p><p>Please check the logs for more information.</p></source>
|
|
||||||
<translation><p>Siamo spiacenti, sebbene questa versione di %1 supporti Wayland, questa build non è stata collegata a una o più librerie richieste.</p><p>Passa a X dalla schermata di accesso o usa una build che utilizzi le librerie corrette.</p><p>Se ritieni che ciò sia errato, <a href="%2">segnala un bug</a>.</p><p>Controlla i log per maggiori informazioni.</p></translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>No thanks</source>
|
<source>No thanks</source>
|
||||||
<translation>No, grazie</translation>
|
<translation>No, grazie</translation>
|
||||||
@ -1151,30 +1077,14 @@ L'abilitazione di questa impostazione disabiliterà l'interfaccia graf
|
|||||||
<source>Preferences</source>
|
<source>Preferences</source>
|
||||||
<translation>Preferenze</translation>
|
<translation>Preferenze</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>&Regular</source>
|
|
||||||
<translation>&Regolare</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>App</source>
|
|
||||||
<translation>App</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>Check for updates on startup</source>
|
<source>Check for updates on startup</source>
|
||||||
<translation>Controlla aggiornamenti all'avvio</translation>
|
<translation>Controlla aggiornamenti all'avvio</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>Hide the window when the app starts</source>
|
|
||||||
<translation>Nascondi la finestra all'avvio dell'app</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>Prevent this computer from going to sleep</source>
|
<source>Prevent this computer from going to sleep</source>
|
||||||
<translation>Impedisci a questo computer di andare in sospensione</translation>
|
<translation>Impedisci a questo computer di andare in sospensione</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>Leave app running in notification area when the window is closed</source>
|
|
||||||
<translation>Lascia l'app in esecuzione nell'area di notifica quando la finestra viene chiusa</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>Tray icon style</source>
|
<source>Tray icon style</source>
|
||||||
<translation>Stile icona di notifica</translation>
|
<translation>Stile icona di notifica</translation>
|
||||||
@ -1211,10 +1121,6 @@ L'abilitazione di questa impostazione disabiliterà l'interfaccia graf
|
|||||||
<source>&Advanced</source>
|
<source>&Advanced</source>
|
||||||
<translation>&Avanzate</translation>
|
<translation>&Avanzate</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>Networking</source>
|
|
||||||
<translation>Rete</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>Port</source>
|
<source>Port</source>
|
||||||
<translation>Porta</translation>
|
<translation>Porta</translation>
|
||||||
@ -1223,18 +1129,10 @@ L'abilitazione di questa impostazione disabiliterà l'interfaccia graf
|
|||||||
<source>Network IP</source>
|
<source>Network IP</source>
|
||||||
<translation>IP di rete</translation>
|
<translation>IP di rete</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>Logs</source>
|
|
||||||
<translation>Log</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>Log path</source>
|
<source>Log path</source>
|
||||||
<translation>Percorso log</translation>
|
<translation>Percorso log</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>Log to file</source>
|
|
||||||
<translation>Salva log su file</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>Fatal</source>
|
<source>Fatal</source>
|
||||||
<translation>Fatale</translation>
|
<translation>Fatale</translation>
|
||||||
@ -1315,6 +1213,22 @@ L'abilitazione di questa impostazione disabiliterà l'interfaccia graf
|
|||||||
<source>Verbose debug output</source>
|
<source>Verbose debug output</source>
|
||||||
<translation>Output di debug dettagliato</translation>
|
<translation>Output di debug dettagliato</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Close and save changes</source>
|
||||||
|
<translation type="unfinished">Chiudi e salva le modifiche</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Close and forget changes</source>
|
||||||
|
<translation type="unfinished">Chiudi e dimentica le modifiche</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Reset to stored values</source>
|
||||||
|
<translation type="unfinished">Ripristina i valori memorizzati</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Reset to default values</source>
|
||||||
|
<translation type="unfinished">Ripristina i valori predefiniti</translation>
|
||||||
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>TLS Certificate Regenerated</source>
|
<source>TLS Certificate Regenerated</source>
|
||||||
<translation>Certificato TLS rigenerato</translation>
|
<translation>Certificato TLS rigenerato</translation>
|
||||||
@ -1335,10 +1249,6 @@ L'abilitazione di questa impostazione disabiliterà l'interfaccia graf
|
|||||||
<source>Language</source>
|
<source>Language</source>
|
||||||
<translation>Lingua</translation>
|
<translation>Lingua</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>Force a language to be used for the GUI.</source>
|
|
||||||
<translation>Forza l'utilizzo di una lingua per la GUI.</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>Enable GUI debug messages</source>
|
<source>Enable GUI debug messages</source>
|
||||||
<translation>Abilita i messaggi di debug della GUI</translation>
|
<translation>Abilita i messaggi di debug della GUI</translation>
|
||||||
@ -1359,6 +1269,123 @@ L'abilitazione di questa impostazione disabiliterà l'interfaccia graf
|
|||||||
<source>Include version in the window title</source>
|
<source>Include version in the window title</source>
|
||||||
<translation type="unfinished">Includi la versione nel titolo della finestra</translation>
|
<translation type="unfinished">Includi la versione nel titolo della finestra</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Log to file</source>
|
||||||
|
<translation>Salva log su file</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>&Logs</source>
|
||||||
|
<translation>&Logs</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>&General</source>
|
||||||
|
<translation type="unfinished">&Generale</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>&Network</source>
|
||||||
|
<translation>&Rete</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>&Window</source>
|
||||||
|
<translation type="unfinished">&Finestra</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>When the main window is closed</source>
|
||||||
|
<translation type="unfinished">Quando la finestra principale è chiusa</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Exit</source>
|
||||||
|
<translation type="unfinished">Esci</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Send to background</source>
|
||||||
|
<translation type="unfinished">Invia in background</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>When the application starts</source>
|
||||||
|
<translation type="unfinished">Quando l'applicazione si avvia</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Show the main window</source>
|
||||||
|
<translation type="unfinished">Mostra la finestra principale</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Run command on enter</source>
|
||||||
|
<translation type="unfinished">Esegui il comando alla pressione di Invio</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Run command on exit</source>
|
||||||
|
<translation type="unfinished">Esegui comando all'uscita</translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>StatusBar</name>
|
||||||
|
<message>
|
||||||
|
<source>%1 is not running</source>
|
||||||
|
<translation>%1 non è in esecuzione</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>%1 is starting...</source>
|
||||||
|
<translation>%1 si sta avviando...</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>%1 will retry in a moment...</source>
|
||||||
|
<translation>%1 riproverà tra un momento...</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>%1 is stopping...</source>
|
||||||
|
<translation>%1 si sta arrestando...</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>%1 is waiting for clients</source>
|
||||||
|
<translation>%1 è in attesa di client</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>%1 is connecting...</source>
|
||||||
|
<translation>%1 è in connessione...</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>%1 is connected as client of %2</source>
|
||||||
|
<translation>%1 è connesso come client di %2</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>%1 is disconnected</source>
|
||||||
|
<translation>%1 è disconnesso</translation>
|
||||||
|
</message>
|
||||||
|
<message numerus="yes">
|
||||||
|
<source>%1 is connected, with %n client(s): %2</source>
|
||||||
|
<extracomment>Shown when in server mode and at least 1 client is connected %1 is replaced by the app name %2 will be a list of at least one client %n will be replaced by the number of clients (n is >=1), it is not requried to be in the translation</extracomment>
|
||||||
|
<translation>
|
||||||
|
<numerusform>%1 è connesso con un client %2</numerusform>
|
||||||
|
<numerusform>%1 è connesso con %n client: %2</numerusform>
|
||||||
|
</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Clients:
|
||||||
|
%1</source>
|
||||||
|
<translation>Client:
|
||||||
|
%1</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>A new version v%1 is available</source>
|
||||||
|
<translation>È disponibile una nuova versione v%1</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>View local fingerprint</source>
|
||||||
|
<translation>Visualizza impronta digitale locale</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Update available</source>
|
||||||
|
<translation>Aggiornamento disponibile</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>%1 Encryption Enabled</source>
|
||||||
|
<translation>%1 Crittografia abilitata</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Encryption Disabled</source>
|
||||||
|
<translation>Crittografia disabilitata</translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>i18n</name>
|
<name>i18n</name>
|
||||||
|
|||||||
@ -143,47 +143,47 @@ p, li { white-space: pre-wrap; }
|
|||||||
<name>ClientConfigDialog</name>
|
<name>ClientConfigDialog</name>
|
||||||
<message>
|
<message>
|
||||||
<source>Client Configuration</source>
|
<source>Client Configuration</source>
|
||||||
<translation type="unfinished">クライアント構成</translation>
|
<translation>クライアント設定</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Use server's keyboard language on this computer</source>
|
<source>Use server's keyboard language on this computer</source>
|
||||||
<translation type="unfinished">サーバー側のキーボード言語をこのコンピューターで使用する</translation>
|
<translation>サーバー側のキーボード言語をこのコンピューターで使用する</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Scroll Modifiers</source>
|
<source>Scroll Modifiers</source>
|
||||||
<translation type="unfinished">スクロール修飾子</translation>
|
<translation>スクロール設定</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Invert</source>
|
<source>Invert</source>
|
||||||
<translation type="unfinished">反転</translation>
|
<translation>反転</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Horizontal Scroll</source>
|
<source>Horizontal Scroll</source>
|
||||||
<translation type="unfinished">水平スクロール</translation>
|
<translation>水平スクロール</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Vertical Scroll</source>
|
<source>Vertical Scroll</source>
|
||||||
<translation type="unfinished">垂直スクロール</translation>
|
<translation>垂直スクロール</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Scale</source>
|
<source>Scale</source>
|
||||||
<translation type="unfinished">規模</translation>
|
<translation>倍率</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Close and save changes</source>
|
<source>Close and save changes</source>
|
||||||
<translation type="unfinished">閉じて変更を保存する</translation>
|
<translation>変更を保存して閉じる</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Close and forget changes</source>
|
<source>Close and forget changes</source>
|
||||||
<translation type="unfinished">変更を閉じて忘れる</translation>
|
<translation>変更を破棄して閉じる</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Reset to stored values</source>
|
<source>Reset to stored values</source>
|
||||||
<translation type="unfinished">保存した値にリセット</translation>
|
<translation>変更前の値にリセットする</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Reset to default values</source>
|
<source>Reset to default values</source>
|
||||||
<translation type="unfinished">デフォルト値にリセット</translation>
|
<translation>デフォルト値にリセットする</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
@ -324,7 +324,7 @@ Do you want to connect to the server?
|
|||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>&Configure Server</source>
|
<source>&Configure Server</source>
|
||||||
<translation>サーバーを設定(&C)</translation>
|
<translation>サーバー設定(&C)</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Export server configuration</source>
|
<source>Export server configuration</source>
|
||||||
@ -348,11 +348,7 @@ Do you want to connect to the server?
|
|||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>invalid certificate, generating a new one</source>
|
<source>invalid certificate, generating a new one</source>
|
||||||
<translation type="unfinished">無効な証明書、新しい証明書を生成しています</translation>
|
<translation>無効な証明書、新しい証明書を生成しています</translation>
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>A new version v%1 is available</source>
|
|
||||||
<translation>新しいバージョン(v%1)が利用できます</translation>
|
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Address missing</source>
|
<source>Address missing</source>
|
||||||
@ -362,10 +358,6 @@ Do you want to connect to the server?
|
|||||||
<source>Please enter the hostname or IP address of the other computer.</source>
|
<source>Please enter the hostname or IP address of the other computer.</source>
|
||||||
<translation>他のコンピューターのIPアドレスかホスト名を入力してください。</translation>
|
<translation>他のコンピューターのIPアドレスかホスト名を入力してください。</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>Core cannot be started</source>
|
|
||||||
<translation>コアが起動できません</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>Save server configuration as...</source>
|
<source>Save server configuration as...</source>
|
||||||
<translation>サーバー設定を保存…</translation>
|
<translation>サーバー設定を保存…</translation>
|
||||||
@ -395,12 +387,8 @@ Do you want to connect to the server?
|
|||||||
<translation>切断</translation>
|
<translation>切断</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>%1 Encryption Enabled</source>
|
<source><p>Failed to connect to the server '%1'.</p><p>A Client with your name is already connected to the server.</p>Please ensure that you're using a unique name and that only a single instance of the client process is running.</p></source>
|
||||||
<translation>%1 暗号化有効</translation>
|
<translation><p>サーバー '%1' への接続に失敗しました。</p><p>同じ名前のクライアントがサーバーに接続済です。</p><p>名前の重複がないことと、クライアントプロセスが多重起動していない事を確認してください。</p></translation>
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>Encryption Disabled</source>
|
|
||||||
<translation>暗号化無効</translation>
|
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>No IP Detected</source>
|
<source>No IP Detected</source>
|
||||||
@ -412,7 +400,7 @@ Do you want to connect to the server?
|
|||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Using IP: </source>
|
<source>Using IP: </source>
|
||||||
<translation type="unfinished">IPアドレスを使用する: </translation>
|
<translation>使用IPアドレス: </translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source><p>If connecting via the hostname fails, try %1</p></source>
|
<source><p>If connecting via the hostname fails, try %1</p></source>
|
||||||
@ -420,7 +408,7 @@ Do you want to connect to the server?
|
|||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>the suggested IP.</source>
|
<source>the suggested IP.</source>
|
||||||
<translation>推奨IPアドレス</translation>
|
<translation>推奨するIPアドレス。</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>one of the following IPs:<br/>%1</source>
|
<source>one of the following IPs:<br/>%1</source>
|
||||||
@ -429,41 +417,9 @@ Do you want to connect to the server?
|
|||||||
<message>
|
<message>
|
||||||
<source>
|
<source>
|
||||||
A bound IP is now invalid, you may need to restart the server.</source>
|
A bound IP is now invalid, you may need to restart the server.</source>
|
||||||
<translation type="unfinished">
|
<translation>
|
||||||
割り当て済みのIPアドレスが無効になりました。サーバーを再起動する必要があるかもしれません。</translation>
|
割り当て済みのIPアドレスが無効になりました。サーバーを再起動する必要があるかもしれません。</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>%1 is starting...</source>
|
|
||||||
<translation>%1 は起動処理中です…</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>%1 will retry in a moment...</source>
|
|
||||||
<translation>%1 はまもなく再試行します…</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>%1 is stopping...</source>
|
|
||||||
<translation>%1 は停止処理中です…</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>%1 is not running</source>
|
|
||||||
<translation>%1 は起動していません</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>%1 is waiting for clients</source>
|
|
||||||
<translation>%1 はクライアント接続を待機中</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>%1 is connecting...</source>
|
|
||||||
<translation>%1 は接続処理中…</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>%1 is connected as client of %2</source>
|
|
||||||
<translation>%1 は %2 にクライアントとして接続中</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>%1 is disconnected</source>
|
|
||||||
<translation>%1 は切断しました</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>&File</source>
|
<source>&File</source>
|
||||||
<translation>ファイル(&F)</translation>
|
<translation>ファイル(&F)</translation>
|
||||||
@ -533,14 +489,6 @@ A bound IP is now invalid, you may need to restart the server.</source>
|
|||||||
<extracomment>Quit shortcut</extracomment>
|
<extracomment>Quit shortcut</extracomment>
|
||||||
<translation>Ctrl+Q</translation>
|
<translation>Ctrl+Q</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>View local fingerprint</source>
|
|
||||||
<translation>自分の指紋を表示</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>Update available</source>
|
|
||||||
<translation>ソフトウェア更新あり</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>Invalid Screen Name</source>
|
<source>Invalid Screen Name</source>
|
||||||
<translation>不正なコンピューター名</translation>
|
<translation>不正なコンピューター名</translation>
|
||||||
@ -563,38 +511,45 @@ Valid names:
|
|||||||
・_ と -
|
・_ と -
|
||||||
・1から255文字まで</translation>
|
・1から255文字まで</translation>
|
||||||
</message>
|
</message>
|
||||||
<message numerus="yes">
|
|
||||||
<source>%1 is connected, with %n client(s): %2</source>
|
|
||||||
<extracomment>Shown when in server mode and at least 1 client is connected %1 is replaced by the app name %2 will be a list of at least one client %n will be replaced by the number of clients (n is >=1), it is not requried to be in the translation</extracomment>
|
|
||||||
<translation>
|
|
||||||
<numerusform>%1 は%n台のクライアントと接続中: %2</numerusform>
|
|
||||||
</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>Clients:
|
<source>%1 Connection Error</source>
|
||||||
%1</source>
|
<translation>%1 接続エラー</translation>
|
||||||
<translation>クライアント:
|
|
||||||
%1</translation>
|
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Suggested IP: </source>
|
<source>Suggested IP: </source>
|
||||||
<translation type="unfinished">推奨IPアドレス: </translation>
|
<translation>推奨IPアドレス: </translation>
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>The Core executable could not be successfully started, although it does exist. Please check if you have sufficient permissions to run this program.</source>
|
|
||||||
<translation>コア実行ファイルは存在していますが、起動できませんでした。このプログラムを実行するのに十分な権限があることを確認してください。</translation>
|
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>&Configure Client</source>
|
<source>&Configure Client</source>
|
||||||
<translation type="unfinished">クライアントの設定 (&C)</translation>
|
<translation>クライアント設定 (&C)</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Connect to:</source>
|
<source>Connect to:</source>
|
||||||
<translation type="unfinished">接続先:</translation>
|
<translation>接続先:</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source><html>Hostname or IP address of the server computer.<br/>May contain a comma seperated list.</html></source>
|
<source><html>Hostname or IP address of the server computer.<br/>May contain a comma seperated list.</html></source>
|
||||||
<translation type="unfinished"><html>サーバー コンピューターのホスト名または IP アドレス。<br/>カンマ区切りのリストを含めることができます。</html></translation>
|
<translation><html>サーバーコンピューターのホスト名または IP アドレス。<br/>カンマ区切りのリストを含めることができます。</html></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>read</source>
|
||||||
|
<translation type="unfinished">読み取り</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>read and write</source>
|
||||||
|
<translation type="unfinished">読み書き</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>The Core executable could not be started.
|
||||||
|
Please check if you have sufficient permissions to run %1.</source>
|
||||||
|
<translation type="unfinished">Coreの実行ファイルを起動できませんでした。
|
||||||
|
%1を実行するための十分な権限があるか確認してください。</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>
|
||||||
|
Additionally, check you are able to %1 the server config file: %2</source>
|
||||||
|
<translation type="unfinished">
|
||||||
|
また、サーバー設定ファイルを%1できることを確認してください: %2</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
@ -677,30 +632,6 @@ Valid names:
|
|||||||
<source>%1 Connected</source>
|
<source>%1 Connected</source>
|
||||||
<translation>%1 接続完了</translation>
|
<translation>%1 接続完了</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source><p>Failed to connect to the server '%1'.</p></source>
|
|
||||||
<translation><p>サーバー '%1' への接続に失敗しました。</p></translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source><p>A Client with your name is already connected to the server.</p>Please ensure that you're using a unique name and that only a single instance of the client process is running.</p></source>
|
|
||||||
<translation><p>同じ名前のクライアントがサーバーに接続済です。</p><p>名前の重複がないことと、クライアントプロセスが多重起動していない事を確認してください。</p></translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source><p>Please try to connect to the server using the server IP address instead of the hostname. </p><p>If that doesn't work, please check your TLS and firewall settings.</p></source>
|
|
||||||
<translation><p>サーバーのホスト名ではなくIPアドレスで接続してみてください。</p><p>それでも接続できない場合は、TLSとファイアウォールの設定を確認してください。</p></translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source><p>Please check your TLS and firewall settings.</p></source>
|
|
||||||
<translation><p>TLSとファイアウォールの設定を確認してください。</p></translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>%1 Connection Error</source>
|
|
||||||
<translation>%1 接続エラー</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>Do not show this message again</source>
|
|
||||||
<translation>このメッセージを再表示しない</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>%1 - New Client</source>
|
<source>%1 - New Client</source>
|
||||||
<translation>%1 - 新しいクライアント</translation>
|
<translation>%1 - 新しいクライアント</translation>
|
||||||
@ -737,10 +668,6 @@ Valid names:
|
|||||||
<source><p>Settings are read-only because you only have read access to the file:</p><p>%1</p></source>
|
<source><p>Settings are read-only because you only have read access to the file:</p><p>%1</p></source>
|
||||||
<translation><p>以下のファイルへの書き込み権限がないため、設定は読み取り専用です:</p><p>%1</p></translation>
|
<translation><p>以下のファイルへの書き込み権限がないため、設定は読み取り専用です:</p><p>%1</p></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source><p>Sorry, while this version of %1 does support Wayland, this build was not linked with one or more of the required libraries.</p><p>Please either switch to X from your login screen or use a build that uses the correct libraries.</p><p>If you think this is incorrect, please <a href="%2">report a bug</a>.</p><p>Please check the logs for more information.</p></source>
|
|
||||||
<translation><p>申し訳ありません、このバージョンの %1 は Wayland に対応していますが、このビルドには必要なライブラリがリンクされていません。</p><p>ログイン画面から X に切り替えるか、正しいライブラリをリンクしたビルドを使用してください。</p><p>もしこの説明が正しくないと思われる場合は、<a href="%2">バグレポート</a>してください。</p><p>詳細はログを確認してください。</p></translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>No thanks</source>
|
<source>No thanks</source>
|
||||||
<translation>不要です</translation>
|
<translation>不要です</translation>
|
||||||
@ -772,21 +699,21 @@ Valid names:
|
|||||||
<message>
|
<message>
|
||||||
<source>failed to read key from certificate file: %1</source>
|
<source>failed to read key from certificate file: %1</source>
|
||||||
<extracomment>%1 will be replaced by the certificate path</extracomment>
|
<extracomment>%1 will be replaced by the certificate path</extracomment>
|
||||||
<translation type="unfinished">証明書ファイルからキーを読み取ることができませんでした: %1</translation>
|
<translation>証明書ファイルからキーを読み取ることができませんでした: %1</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>failed to parse certificate file: %1</source>
|
<source>failed to parse certificate file: %1</source>
|
||||||
<extracomment>%1 will be replaced by the certificate path</extracomment>
|
<extracomment>%1 will be replaced by the certificate path</extracomment>
|
||||||
<translation type="unfinished">証明書ファイルの解析に失敗しました: %1</translation>
|
<translation>証明書ファイルの解析に失敗しました: %1</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>key detected is the incorrect size</source>
|
<source>key detected is the incorrect size</source>
|
||||||
<translation type="unfinished">検出されたキーのサイズが正しくありません</translation>
|
<translation>検出されたキーのサイズが正しくありません</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>failed to read RSA key from certificate file: %1</source>
|
<source>failed to read RSA key from certificate file: %1</source>
|
||||||
<extracomment>%1 will be replaced by the certificate path</extracomment>
|
<extracomment>%1 will be replaced by the certificate path</extracomment>
|
||||||
<translation type="unfinished">証明書ファイルから RSA キーを読み取ることができませんでした: %1</translation>
|
<translation>証明書ファイルから RSA キーを読み取ることができませんでした: %1</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>%1 is already running</source>
|
<source>%1 is already running</source>
|
||||||
@ -939,19 +866,19 @@ Valid names:
|
|||||||
<name>SearchWidget</name>
|
<name>SearchWidget</name>
|
||||||
<message>
|
<message>
|
||||||
<source>Search</source>
|
<source>Search</source>
|
||||||
<translation type="unfinished">検索</translation>
|
<translation>検索</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Find next</source>
|
<source>Find next</source>
|
||||||
<translation type="unfinished">次を検索</translation>
|
<translation>次を検索</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Find previous</source>
|
<source>Find previous</source>
|
||||||
<translation type="unfinished">前を検索</translation>
|
<translation>前を検索</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Find...</source>
|
<source>Find...</source>
|
||||||
<translation type="unfinished">検索...</translation>
|
<translation>検索...</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
@ -1152,30 +1079,14 @@ Enabling this setting will disable the server config GUI.</source>
|
|||||||
<source>Preferences</source>
|
<source>Preferences</source>
|
||||||
<translation>設定</translation>
|
<translation>設定</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>&Regular</source>
|
|
||||||
<translation>基本(&R)</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>App</source>
|
|
||||||
<translation>アプリケーション</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>Check for updates on startup</source>
|
<source>Check for updates on startup</source>
|
||||||
<translation>起動時にソフトウェア更新を確認する</translation>
|
<translation>起動時にソフトウェア更新を確認する</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>Hide the window when the app starts</source>
|
|
||||||
<translation>アプリの起動時にウィンドウを隠す</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>Prevent this computer from going to sleep</source>
|
<source>Prevent this computer from going to sleep</source>
|
||||||
<translation>このコンピューターがスリープしないようにする</translation>
|
<translation>このコンピューターがスリープしないようにする</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>Leave app running in notification area when the window is closed</source>
|
|
||||||
<translation>ウィンドウを閉じてもアプリを通知領域で実行し続ける</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>Tray icon style</source>
|
<source>Tray icon style</source>
|
||||||
<translation>トレイアイコン</translation>
|
<translation>トレイアイコン</translation>
|
||||||
@ -1212,10 +1123,6 @@ Enabling this setting will disable the server config GUI.</source>
|
|||||||
<source>&Advanced</source>
|
<source>&Advanced</source>
|
||||||
<translation>詳細(&A)</translation>
|
<translation>詳細(&A)</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>Networking</source>
|
|
||||||
<translation>ネットワーク</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>Port</source>
|
<source>Port</source>
|
||||||
<translation>ポート</translation>
|
<translation>ポート</translation>
|
||||||
@ -1224,10 +1131,6 @@ Enabling this setting will disable the server config GUI.</source>
|
|||||||
<source>Network IP</source>
|
<source>Network IP</source>
|
||||||
<translation>IPアドレス</translation>
|
<translation>IPアドレス</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>Logs</source>
|
|
||||||
<translation>ログ</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>Level</source>
|
<source>Level</source>
|
||||||
<translation>レベル</translation>
|
<translation>レベル</translation>
|
||||||
@ -1268,10 +1171,6 @@ Enabling this setting will disable the server config GUI.</source>
|
|||||||
<source>Log path</source>
|
<source>Log path</source>
|
||||||
<translation>ログファイルのパス</translation>
|
<translation>ログファイルのパス</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>Log to file</source>
|
|
||||||
<translation>ファイルにログを保存する</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>Using a Debug log level may affect performance. Only use a Debug level if you are attempting to debug an issue or are gathering logs to submit with a bug report.</source>
|
<source>Using a Debug log level may affect performance. Only use a Debug level if you are attempting to debug an issue or are gathering logs to submit with a bug report.</source>
|
||||||
<translation>デバッグレベルのログ取得は性能に影響が出ることがあります。不具合の修正やバグレポートの送信に必要な場合にのみ使用してください。</translation>
|
<translation>デバッグレベルのログ取得は性能に影響が出ることがあります。不具合の修正やバグレポートの送信に必要な場合にのみ使用してください。</translation>
|
||||||
@ -1288,10 +1187,6 @@ Enabling this setting will disable the server config GUI.</source>
|
|||||||
<source>Always run as system (work at login screen and UAC)</source>
|
<source>Always run as system (work at login screen and UAC)</source>
|
||||||
<translation>常にsystem権限で実行する(ログイン画面とUACで必要)</translation>
|
<translation>常にsystem権限で実行する(ログイン画面とUACで必要)</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>Force a language to be used for the GUI.</source>
|
|
||||||
<translation>GUIの使用言語を設定します。</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>Language</source>
|
<source>Language</source>
|
||||||
<translation>言語</translation>
|
<translation>言語</translation>
|
||||||
@ -1344,6 +1239,22 @@ Enabling this setting will disable the server config GUI.</source>
|
|||||||
<source>Verbose debug output</source>
|
<source>Verbose debug output</source>
|
||||||
<translation>詳細なデバッグ出力</translation>
|
<translation>詳細なデバッグ出力</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Close and save changes</source>
|
||||||
|
<translation>変更を保存して閉じる</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Close and forget changes</source>
|
||||||
|
<translation>変更を破棄して閉じる</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Reset to stored values</source>
|
||||||
|
<translation>変更前の値にリセットする</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Reset to default values</source>
|
||||||
|
<translation>デフォルト値にリセットする</translation>
|
||||||
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Enable wl-clipboard support</source>
|
<source>Enable wl-clipboard support</source>
|
||||||
<translation>wl-clipboard によるクリップボード対応を有効にする</translation>
|
<translation>wl-clipboard によるクリップボード対応を有効にする</translation>
|
||||||
@ -1354,11 +1265,127 @@ Enabling this setting will disable the server config GUI.</source>
|
|||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Automatic</source>
|
<source>Automatic</source>
|
||||||
<translation type="unfinished">自動</translation>
|
<translation>自動</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Include version in the window title</source>
|
<source>Include version in the window title</source>
|
||||||
<translation type="unfinished">ウィンドウタイトルにバージョン情報を含める</translation>
|
<translation>ウィンドウタイトルにバージョン情報を含める</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Log to file</source>
|
||||||
|
<translation>ファイルにログを保存する</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>&Logs</source>
|
||||||
|
<translation>ログ(&L)</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>&General</source>
|
||||||
|
<translation>一般(&G)</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>&Network</source>
|
||||||
|
<translation>ネットワーク(&N)</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>&Window</source>
|
||||||
|
<translation type="unfinished">ウィンドウ(&W)</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>When the main window is closed</source>
|
||||||
|
<translation type="unfinished">メインウィンドウが閉じられているとき</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Exit</source>
|
||||||
|
<translation type="unfinished">終了</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Send to background</source>
|
||||||
|
<translation type="unfinished">バックグラウンドに送信</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>When the application starts</source>
|
||||||
|
<translation type="unfinished">アプリケーションが起動すると</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Show the main window</source>
|
||||||
|
<translation type="unfinished">メインウィンドウを表示する</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Run command on enter</source>
|
||||||
|
<translation type="unfinished">Enterキーでコマンドを実行</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Run command on exit</source>
|
||||||
|
<translation type="unfinished">終了時にコマンドを実行</translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>StatusBar</name>
|
||||||
|
<message>
|
||||||
|
<source>%1 is not running</source>
|
||||||
|
<translation>%1 は起動していません</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>%1 is starting...</source>
|
||||||
|
<translation>%1 は起動処理中です…</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>%1 will retry in a moment...</source>
|
||||||
|
<translation>%1 はまもなく再試行します…</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>%1 is stopping...</source>
|
||||||
|
<translation>%1 は停止処理中です…</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>%1 is waiting for clients</source>
|
||||||
|
<translation>%1 はクライアント接続を待機中</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>%1 is connecting...</source>
|
||||||
|
<translation>%1 は接続処理中…</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>%1 is connected as client of %2</source>
|
||||||
|
<translation>%1 は %2 にクライアントとして接続中</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>%1 is disconnected</source>
|
||||||
|
<translation>%1 は切断しました</translation>
|
||||||
|
</message>
|
||||||
|
<message numerus="yes">
|
||||||
|
<source>%1 is connected, with %n client(s): %2</source>
|
||||||
|
<extracomment>Shown when in server mode and at least 1 client is connected %1 is replaced by the app name %2 will be a list of at least one client %n will be replaced by the number of clients (n is >=1), it is not requried to be in the translation</extracomment>
|
||||||
|
<translation>
|
||||||
|
<numerusform>%1 は%n台のクライアントと接続中: %2</numerusform>
|
||||||
|
</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Clients:
|
||||||
|
%1</source>
|
||||||
|
<translation>クライアント:
|
||||||
|
%1</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>A new version v%1 is available</source>
|
||||||
|
<translation>新しいバージョン(v%1)が利用できます</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>View local fingerprint</source>
|
||||||
|
<translation>自分の指紋を表示</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Update available</source>
|
||||||
|
<translation>ソフトウェア更新あり</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>%1 Encryption Enabled</source>
|
||||||
|
<translation>%1 暗号化有効</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Encryption Disabled</source>
|
||||||
|
<translation>暗号化無効</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
|
|||||||
@ -151,11 +151,11 @@ p, li { white-space: pre-wrap; }
|
|||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Scroll Modifiers</source>
|
<source>Scroll Modifiers</source>
|
||||||
<translation type="unfinished">스크롤 수정자</translation>
|
<translation>스크롤 제어자</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Invert</source>
|
<source>Invert</source>
|
||||||
<translation type="unfinished">거꾸로 하다</translation>
|
<translation>반전</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Horizontal Scroll</source>
|
<source>Horizontal Scroll</source>
|
||||||
@ -171,11 +171,11 @@ p, li { white-space: pre-wrap; }
|
|||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Close and save changes</source>
|
<source>Close and save changes</source>
|
||||||
<translation type="unfinished">닫기 및 변경 사항 저장</translation>
|
<translation>변경 사항 저장 후 닫기</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Close and forget changes</source>
|
<source>Close and forget changes</source>
|
||||||
<translation type="unfinished">설정을 저장하고 나면 변경 사항은 더 이상 신경 쓸 필요가 없습니다</translation>
|
<translation>저장하지 않고 닫기</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Reset to stored values</source>
|
<source>Reset to stored values</source>
|
||||||
@ -190,16 +190,16 @@ p, li { white-space: pre-wrap; }
|
|||||||
<name>FingerprintDialog</name>
|
<name>FingerprintDialog</name>
|
||||||
<message>
|
<message>
|
||||||
<source>Local Fingerprints</source>
|
<source>Local Fingerprints</source>
|
||||||
<translation>로컬 지문값</translation>
|
<translation>로컬 핑거프린팅</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Local computer's fingerprint</source>
|
<source>Local computer's fingerprint</source>
|
||||||
<translation>이 컴퓨터의 지문값</translation>
|
<translation>이 컴퓨터의 핑거프린팅</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Compare the fingerprints in this dialog to those on the %1.
|
<source>Compare the fingerprints in this dialog to those on the %1.
|
||||||
Only connect if they match!</source>
|
Only connect if they match!</source>
|
||||||
<translation>이 대화상자에 표시된 지문값을 %1의 지문값과 비교하세요.
|
<translation>이 대화상자에 표시된 핑거프린팅을 %1의 핑거프린팅과 비교하세요.
|
||||||
일치할 때만 연결하세요!</translation>
|
일치할 때만 연결하세요!</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
@ -236,11 +236,11 @@ Do you want to connect to the server?
|
|||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Server Fingerprint</source>
|
<source>Server Fingerprint</source>
|
||||||
<translation>서버 지문값</translation>
|
<translation>서버 핑거프린팅</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Client Fingerprint</source>
|
<source>Client Fingerprint</source>
|
||||||
<translation>클라이언트 지문값</translation>
|
<translation>클라이언트 핑거프린팅</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Show image</source>
|
<source>Show image</source>
|
||||||
@ -252,11 +252,11 @@ Do you want to connect to the server?
|
|||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Display the fingerprint as an image</source>
|
<source>Display the fingerprint as an image</source>
|
||||||
<translation>지문값을 이미지로 표시</translation>
|
<translation>핑거프린팅을 이미지로 표시</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Display the fingerprint as a hash</source>
|
<source>Display the fingerprint as a hash</source>
|
||||||
<translation>지문값을 해시로 표시</translation>
|
<translation>핑거프린팅을 해시로 표시</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
@ -350,10 +350,6 @@ Do you want to connect to the server?
|
|||||||
<source>invalid certificate, generating a new one</source>
|
<source>invalid certificate, generating a new one</source>
|
||||||
<translation type="unfinished">유효하지 않은 인증서입니다. 새 인증서를 생성하는 중입니다</translation>
|
<translation type="unfinished">유효하지 않은 인증서입니다. 새 인증서를 생성하는 중입니다</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>A new version v%1 is available</source>
|
|
||||||
<translation>새 버전(v%1)을 사용할 수 있습니다</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>Address missing</source>
|
<source>Address missing</source>
|
||||||
<translation>주소가 없습니다</translation>
|
<translation>주소가 없습니다</translation>
|
||||||
@ -362,10 +358,6 @@ Do you want to connect to the server?
|
|||||||
<source>Please enter the hostname or IP address of the other computer.</source>
|
<source>Please enter the hostname or IP address of the other computer.</source>
|
||||||
<translation>다른 컴퓨터의 호스트 이름 또는 IP 주소를 입력하세요.</translation>
|
<translation>다른 컴퓨터의 호스트 이름 또는 IP 주소를 입력하세요.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>Core cannot be started</source>
|
|
||||||
<translation>코어를 시작할 수 없습니다</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>Save server configuration as...</source>
|
<source>Save server configuration as...</source>
|
||||||
<translation>서버 설정을 다른 이름으로 저장...</translation>
|
<translation>서버 설정을 다른 이름으로 저장...</translation>
|
||||||
@ -395,12 +387,8 @@ Do you want to connect to the server?
|
|||||||
<translation>연결 해제</translation>
|
<translation>연결 해제</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>%1 Encryption Enabled</source>
|
<source><p>Failed to connect to the server '%1'.</p><p>A Client with your name is already connected to the server.</p>Please ensure that you're using a unique name and that only a single instance of the client process is running.</p></source>
|
||||||
<translation>%1 암호화 사용</translation>
|
<translation><p>서버 '%1'에 연결하지 못했습니다.</p><p>같은 이름의 클라이언트가 이미 서버에 연결되어 있습니다.</p><p>고유한 이름을 사용하고, 클라이언트 프로세스가 하나만 실행 중인지 확인하세요.</p></translation>
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>Encryption Disabled</source>
|
|
||||||
<translation>암호화 사용 안 함</translation>
|
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>No IP Detected</source>
|
<source>No IP Detected</source>
|
||||||
@ -429,40 +417,8 @@ Do you want to connect to the server?
|
|||||||
<message>
|
<message>
|
||||||
<source>
|
<source>
|
||||||
A bound IP is now invalid, you may need to restart the server.</source>
|
A bound IP is now invalid, you may need to restart the server.</source>
|
||||||
<translation type="unfinished">
|
<translation>
|
||||||
바인딩된 IP가 이제 유효하지 않습니다. 서버를 재시작해야 할 수 있습니다.</translation>
|
연결된 IP가 이제 유효하지 않습니다. 서버를 재시작해야 합니다.</translation>
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>%1 is starting...</source>
|
|
||||||
<translation>%1 시작 중...</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>%1 will retry in a moment...</source>
|
|
||||||
<translation>%1 잠시 후 재시도합니다...</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>%1 is stopping...</source>
|
|
||||||
<translation>%1 중지 중...</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>%1 is not running</source>
|
|
||||||
<translation>%1 실행 중이 아닙니다</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>%1 is waiting for clients</source>
|
|
||||||
<translation>%1 클라이언트를 기다리는 중</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>%1 is connecting...</source>
|
|
||||||
<translation>%1 연결 중...</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>%1 is connected as client of %2</source>
|
|
||||||
<translation>%1이(가) %2의 클라이언트로 연결되었습니다</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>%1 is disconnected</source>
|
|
||||||
<translation>%1 연결이 해제되었습니다</translation>
|
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>&File</source>
|
<source>&File</source>
|
||||||
@ -533,14 +489,6 @@ A bound IP is now invalid, you may need to restart the server.</source>
|
|||||||
<extracomment>Quit shortcut</extracomment>
|
<extracomment>Quit shortcut</extracomment>
|
||||||
<translation>Ctrl+Q</translation>
|
<translation>Ctrl+Q</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>View local fingerprint</source>
|
|
||||||
<translation>로컬 지문값 보기</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>Update available</source>
|
|
||||||
<translation>업데이트 사용 가능</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>Invalid Screen Name</source>
|
<source>Invalid Screen Name</source>
|
||||||
<translation>잘못된 컴퓨터 이름</translation>
|
<translation>잘못된 컴퓨터 이름</translation>
|
||||||
@ -563,27 +511,14 @@ Valid names:
|
|||||||
• _ 또는 - 사용 가능
|
• _ 또는 - 사용 가능
|
||||||
• 1~255자</translation>
|
• 1~255자</translation>
|
||||||
</message>
|
</message>
|
||||||
<message numerus="yes">
|
|
||||||
<source>%1 is connected, with %n client(s): %2</source>
|
|
||||||
<extracomment>Shown when in server mode and at least 1 client is connected %1 is replaced by the app name %2 will be a list of at least one client %n will be replaced by the number of clients (n is >=1), it is not requried to be in the translation</extracomment>
|
|
||||||
<translation>
|
|
||||||
<numerusform>%1이(가) %n대의 클라이언트와 연결됨: %2</numerusform>
|
|
||||||
</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>Clients:
|
<source>%1 Connection Error</source>
|
||||||
%1</source>
|
<translation>%1 연결 오류</translation>
|
||||||
<translation>클라이언트:
|
|
||||||
%1</translation>
|
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Suggested IP: </source>
|
<source>Suggested IP: </source>
|
||||||
<translation type="unfinished">추천 IP: </translation>
|
<translation type="unfinished">추천 IP: </translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>The Core executable could not be successfully started, although it does exist. Please check if you have sufficient permissions to run this program.</source>
|
|
||||||
<translation>코어 실행 파일은 존재하지만 정상적으로 시작할 수 없습니다. 이 프로그램을 실행할 권한이 충분한지 확인하세요.</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>&Configure Client</source>
|
<source>&Configure Client</source>
|
||||||
<translation type="unfinished">클라이언트 구성 (&C)</translation>
|
<translation type="unfinished">클라이언트 구성 (&C)</translation>
|
||||||
@ -594,7 +529,27 @@ Valid names:
|
|||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source><html>Hostname or IP address of the server computer.<br/>May contain a comma seperated list.</html></source>
|
<source><html>Hostname or IP address of the server computer.<br/>May contain a comma seperated list.</html></source>
|
||||||
<translation type="unfinished"><html>서버 컴퓨터의 호스트 이름 또는 IP 주소입니다.<br/>쉼표로 구분된 목록을 포함할 수 있습니다.</html></translation>
|
<translation><html>서버 컴퓨터의 호스트 이름 또는 IP 주소입니다.<br/>목록 요소는 쉼표로 구분됩니다.</html></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>read</source>
|
||||||
|
<translation type="unfinished">읽기</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>read and write</source>
|
||||||
|
<translation type="unfinished">읽기 및 쓰기</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>The Core executable could not be started.
|
||||||
|
Please check if you have sufficient permissions to run %1.</source>
|
||||||
|
<translation type="unfinished">Core 실행 파일을 시작할 수 없습니다.
|
||||||
|
%1을 실행할 수 있는 충분한 권한이 있는지 확인하세요.</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>
|
||||||
|
Additionally, check you are able to %1 the server config file: %2</source>
|
||||||
|
<translation type="unfinished">
|
||||||
|
또한 서버 구성 파일을 %1할 수 있는지 확인하세요: %2</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
@ -602,7 +557,7 @@ Valid names:
|
|||||||
<message>
|
<message>
|
||||||
<source>Unnamed</source>
|
<source>Unnamed</source>
|
||||||
<extracomment>Used as the hostname. Translation may not contain spaces</extracomment>
|
<extracomment>Used as the hostname. Translation may not contain spaces</extracomment>
|
||||||
<translation>Unnamed</translation>
|
<translation>이름없음</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
@ -618,13 +573,13 @@ Valid names:
|
|||||||
<message>
|
<message>
|
||||||
<source><p>Sorry, a fatal error has occurred and the application must now exit.</p>
|
<source><p>Sorry, a fatal error has occurred and the application must now exit.</p>
|
||||||
</source>
|
</source>
|
||||||
<translation><p>죄송합니다. 치명적인 오류가 발생하여 애플리케이션을 종료해야 합니다.</p>
|
<translation><p>문제가 발생하여 애플리케이션을 종료합니다.</p>
|
||||||
</translation>
|
</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source><p>Sorry, a critical error has occurred.</p>
|
<source><p>Sorry, a critical error has occurred.</p>
|
||||||
</source>
|
</source>
|
||||||
<translation><p>죄송합니다. 심각한 오류가 발생했습니다.</p>
|
<translation><p>에러 발생</p>
|
||||||
</translation>
|
</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
@ -641,7 +596,7 @@ Valid names:
|
|||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source><p>On Linux systems using GNOME 3, the notification area might be disabled. You may need to <a href="%1">enable an extension</a> to see the %2 tray icon.</p></source>
|
<source><p>On Linux systems using GNOME 3, the notification area might be disabled. You may need to <a href="%1">enable an extension</a> to see the %2 tray icon.</p></source>
|
||||||
<translation><p>GNOME 3을 사용하는 Linux 시스템에서는 알림 영역이 비활성화되어 있을 수 있습니다. %2 트레이 아이콘을 보려면 <a href="%1">확장 기능을 활성화</a>해야 할 수 있습니다.</p></translation>
|
<translation><p>GNOME 3을 사용하는 Linux 시스템에서는 알림 영역이 비활성화되어 있을 수 있습니다. %2 트레이 아이콘을 보려면 <a href="%1">확장 기능을 활성화</a>해야 합니다.</p></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>%1 Server</source>
|
<source>%1 Server</source>
|
||||||
@ -653,11 +608,11 @@ Valid names:
|
|||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source><p>%1 is now connected!</p></source>
|
<source><p>%1 is now connected!</p></source>
|
||||||
<translation><p>%1이(가) 연결되었습니다!</p></translation>
|
<translation><p>%1이(가) 연결!</p></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source><p>Try moving your mouse to your other computer. Once there, go ahead and type something.</p><p>Don't forget, you can copy and paste between computers too.</p></source>
|
<source><p>Try moving your mouse to your other computer. Once there, go ahead and type something.</p><p>Don't forget, you can copy and paste between computers too.</p></source>
|
||||||
<translation><p>마우스를 다른 컴퓨터로 옮겨 보세요. 이동한 뒤 키보드로 아무 글자나 입력해 보세요.</p><p>컴퓨터 간 복사/붙여넣기도 할 수 있습니다.</p></translation>
|
<translation><p>마우스를 다른 컴퓨터로 이동시켜 보세요. 이동한 뒤 키보드로 아무 글자나 입력해 보세요.</p><p>컴퓨터 간 복사/붙여넣기도 가능합니다.</p></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source><p>Try controlling this computer remotely.</p></source>
|
<source><p>Try controlling this computer remotely.</p></source>
|
||||||
@ -675,37 +630,13 @@ Valid names:
|
|||||||
<source>%1 Connected</source>
|
<source>%1 Connected</source>
|
||||||
<translation>%1 연결됨</translation>
|
<translation>%1 연결됨</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source><p>Failed to connect to the server '%1'.</p></source>
|
|
||||||
<translation><p>서버 '%1'에 연결하지 못했습니다.</p></translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source><p>A Client with your name is already connected to the server.</p>Please ensure that you're using a unique name and that only a single instance of the client process is running.</p></source>
|
|
||||||
<translation><p>같은 이름의 클라이언트가 이미 서버에 연결되어 있습니다.</p><p>고유한 이름을 사용하고, 클라이언트 프로세스가 한 번만 실행 중인지 확인하세요.</p></translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source><p>Please try to connect to the server using the server IP address instead of the hostname. </p><p>If that doesn't work, please check your TLS and firewall settings.</p></source>
|
|
||||||
<translation><p>호스트 이름 대신 서버 IP 주소로 연결해 보세요.</p><p>문제가 계속되면 TLS 및 방화벽 설정을 확인하세요.</p></translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source><p>Please check your TLS and firewall settings.</p></source>
|
|
||||||
<translation><p>TLS 및 방화벽 설정을 확인하세요.</p></translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>%1 Connection Error</source>
|
|
||||||
<translation>%1 연결 오류</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>Do not show this message again</source>
|
|
||||||
<translation>다시 표시하지 않기</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>%1 - New Client</source>
|
<source>%1 - New Client</source>
|
||||||
<translation>%1 - 새 클라이언트</translation>
|
<translation>%1 - 새 클라이언트</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>A new client called '%1' has been accepted. You'll need to add it to your server's screen layout.</source>
|
<source>A new client called '%1' has been accepted. You'll need to add it to your server's screen layout.</source>
|
||||||
<translation>새 클라이언트 '%1'이(가) 허용되었습니다. 서버의 화면 배치에 추가해야 합니다.</translation>
|
<translation>새 클라이언트 '%1'이(가) 허용되었습니다. 서버의 화면 배치에 추가해 주세요.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Ignore</source>
|
<source>Ignore</source>
|
||||||
@ -725,7 +656,7 @@ Valid names:
|
|||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source><p>Are you sure you want to clear all settings and restart %1?</p><p>This action cannot be undone.</p></source>
|
<source><p>Are you sure you want to clear all settings and restart %1?</p><p>This action cannot be undone.</p></source>
|
||||||
<translation><p>모든 설정을 초기화하고 %1을(를) 재시작할까요?</p><p>이 작업은 되돌릴 수 없습니다.</p></translation>
|
<translation><p>모든 설정을 초기화하고 %1을(를) 재시작할까요?</p><p>이 작업은 번복될 수 없습니다.</p></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>%1 Read-only settings</source>
|
<source>%1 Read-only settings</source>
|
||||||
@ -735,10 +666,6 @@ Valid names:
|
|||||||
<source><p>Settings are read-only because you only have read access to the file:</p><p>%1</p></source>
|
<source><p>Settings are read-only because you only have read access to the file:</p><p>%1</p></source>
|
||||||
<translation><p>다음 파일에 대한 쓰기 권한이 없어 설정이 읽기 전용입니다:</p><p>%1</p></translation>
|
<translation><p>다음 파일에 대한 쓰기 권한이 없어 설정이 읽기 전용입니다:</p><p>%1</p></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source><p>Sorry, while this version of %1 does support Wayland, this build was not linked with one or more of the required libraries.</p><p>Please either switch to X from your login screen or use a build that uses the correct libraries.</p><p>If you think this is incorrect, please <a href="%2">report a bug</a>.</p><p>Please check the logs for more information.</p></source>
|
|
||||||
<translation><p>죄송합니다. 이 버전의 %1은(는) Wayland를 지원하지만, 이 빌드는 필요한 라이브러리 중 하나 이상이 링크되어 있지 않습니다.</p><p>로그인 화면에서 X로 전환하거나 올바른 라이브러리를 사용한 빌드를 이용하세요.</p><p>이 안내가 올바르지 않다고 생각되면 <a href="%2">버그를 신고</a>해 주세요.</p><p>자세한 내용은 로그를 확인하세요.</p></translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>No thanks</source>
|
<source>No thanks</source>
|
||||||
<translation>아니요</translation>
|
<translation>아니요</translation>
|
||||||
@ -765,7 +692,7 @@ Valid names:
|
|||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source><p>There was a problem finding the %1 background service (daemon).</p><p>The background service makes %1 work with UAC prompts and the login screen.</p><p>If don't want to use the background service and intentionally stopped it, you can prevent it's use by disabling this feature.</p><p>If you did not stop the background service intentionally, there may be a problem with it. Please retry or try restarting the %1 service from the Windows services program.</p></source>
|
<source><p>There was a problem finding the %1 background service (daemon).</p><p>The background service makes %1 work with UAC prompts and the login screen.</p><p>If don't want to use the background service and intentionally stopped it, you can prevent it's use by disabling this feature.</p><p>If you did not stop the background service intentionally, there may be a problem with it. Please retry or try restarting the %1 service from the Windows services program.</p></source>
|
||||||
<translation><p>%1 백그라운드 서비스(데몬)를 찾는 중 문제가 발생했습니다.</p><p>백그라운드 서비스는 %1이(가) UAC 프롬프트 및 로그인 화면에서 동작하도록 합니다.</p><p>백그라운드 서비스를 사용하지 않으려고 의도적으로 중지한 경우, 이 기능을 비활성화하여 사용을 막을 수 있습니다.</p><p>의도적으로 중지한 것이 아니라면 서비스에 문제가 있을 수 있습니다. 재시도하거나 Windows 서비스 관리 프로그램에서 %1 서비스를 재시작해 보세요.</p></translation>
|
<translation><p>%1 백그라운드 서비스(daemon)를 찾는 중 문제가 발생했습니다.</p><p>백그라운드 서비스는 %1이(가) UAC 프롬프트 및 로그인 화면에서 동작됩니다.</p><p>백그라운드 서비스를 사용하지 않으려고 의도적으로 중지한 경우, 이 기능을 비활성화하여 사용을 막을 수 있습니다.</p><p>의도적으로 중지한 것이 아니라면 서비스에 문제가 있을 수 있습니다. 재시도하거나 Windows 서비스 관리 프로그램에서 %1 서비스를 재시작해 보세요.</p></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>failed to read key from certificate file: %1</source>
|
<source>failed to read key from certificate file: %1</source>
|
||||||
@ -855,7 +782,7 @@ Valid names:
|
|||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Dead Corners</source>
|
<source>Dead Corners</source>
|
||||||
<translation>무효 모서리</translation>
|
<translation>화면 걸림 방지</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Top Left</source>
|
<source>Top Left</source>
|
||||||
@ -964,7 +891,7 @@ Valid names:
|
|||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Drag a computer from the grid to the trashcan to remove it.</source>
|
<source>Drag a computer from the grid to the trashcan to remove it.</source>
|
||||||
<translation>컴퓨터를 삭제하려면 격자에서 휴지통으로 드래그하세요.</translation>
|
<translation>컴퓨터를 삭제하려면 휴지통으로 드래그하세요.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Configure the layout of your computer displays by dragging to where you want.</source>
|
<source>Configure the layout of your computer displays by dragging to where you want.</source>
|
||||||
@ -1016,7 +943,7 @@ Valid names:
|
|||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>&Dead corners (for this computer)</source>
|
<source>&Dead corners (for this computer)</source>
|
||||||
<translation>무효 모서리(&D) (이 컴퓨터)</translation>
|
<translation>화면 걸림 방지(&D) (이 컴퓨터)</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>&Bottom-left</source>
|
<source>&Bottom-left</source>
|
||||||
@ -1118,7 +1045,7 @@ Valid names:
|
|||||||
<source>Use a server config file to create complex computer layouts that are not possible with the simple grid-based computer layout editor.
|
<source>Use a server config file to create complex computer layouts that are not possible with the simple grid-based computer layout editor.
|
||||||
|
|
||||||
Enabling this setting will disable the server config GUI.</source>
|
Enabling this setting will disable the server config GUI.</source>
|
||||||
<translation>단순한 격자 기반 레이아웃 편집기로는 만들 수 없는 복잡한 컴퓨터 배치를 구성하려면 서버 설정 파일을 사용하세요.
|
<translation>격자 기반 레이아웃 편집기로는 만들 수 없는 복잡한 컴퓨터 배치를 구성하려면 서버 설정 파일을 사용하세요.
|
||||||
|
|
||||||
이 설정을 활성화하면 서버 설정 GUI가 비활성화됩니다.</translation>
|
이 설정을 활성화하면 서버 설정 GUI가 비활성화됩니다.</translation>
|
||||||
</message>
|
</message>
|
||||||
@ -1150,30 +1077,14 @@ Enabling this setting will disable the server config GUI.</source>
|
|||||||
<source>Preferences</source>
|
<source>Preferences</source>
|
||||||
<translation>환경설정</translation>
|
<translation>환경설정</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>&Regular</source>
|
|
||||||
<translation>일반(&R)</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>App</source>
|
|
||||||
<translation>앱</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>Check for updates on startup</source>
|
<source>Check for updates on startup</source>
|
||||||
<translation>시작 시 업데이트 확인</translation>
|
<translation>시작 시 업데이트 확인</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>Hide the window when the app starts</source>
|
|
||||||
<translation>앱 시작 시 창 숨기기</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>Prevent this computer from going to sleep</source>
|
<source>Prevent this computer from going to sleep</source>
|
||||||
<translation>이 컴퓨터를 절전 모드로 전환하지 않음</translation>
|
<translation>이 컴퓨터를 절전 모드로 전환하지 않음</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>Leave app running in notification area when the window is closed</source>
|
|
||||||
<translation>창을 닫아도 알림 영역에서 앱을 계속 실행</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>Tray icon style</source>
|
<source>Tray icon style</source>
|
||||||
<translation>트레이 아이콘 스타일</translation>
|
<translation>트레이 아이콘 스타일</translation>
|
||||||
@ -1210,10 +1121,6 @@ Enabling this setting will disable the server config GUI.</source>
|
|||||||
<source>&Advanced</source>
|
<source>&Advanced</source>
|
||||||
<translation>고급(&A)</translation>
|
<translation>고급(&A)</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>Networking</source>
|
|
||||||
<translation>네트워크</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>Port</source>
|
<source>Port</source>
|
||||||
<translation>포트</translation>
|
<translation>포트</translation>
|
||||||
@ -1222,10 +1129,6 @@ Enabling this setting will disable the server config GUI.</source>
|
|||||||
<source>Network IP</source>
|
<source>Network IP</source>
|
||||||
<translation>네트워크 IP</translation>
|
<translation>네트워크 IP</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>Logs</source>
|
|
||||||
<translation>로그</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>Level</source>
|
<source>Level</source>
|
||||||
<translation>레벨</translation>
|
<translation>레벨</translation>
|
||||||
@ -1266,10 +1169,6 @@ Enabling this setting will disable the server config GUI.</source>
|
|||||||
<source>Log path</source>
|
<source>Log path</source>
|
||||||
<translation>로그 경로</translation>
|
<translation>로그 경로</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>Log to file</source>
|
|
||||||
<translation>파일로 로그 저장</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>Using a Debug log level may affect performance. Only use a Debug level if you are attempting to debug an issue or are gathering logs to submit with a bug report.</source>
|
<source>Using a Debug log level may affect performance. Only use a Debug level if you are attempting to debug an issue or are gathering logs to submit with a bug report.</source>
|
||||||
<translation>디버그 로그 레벨은 성능에 영향을 줄 수 있습니다. 문제를 디버깅하거나 버그 신고에 첨부할 로그를 수집할 때만 디버그 레벨을 사용하세요.</translation>
|
<translation>디버그 로그 레벨은 성능에 영향을 줄 수 있습니다. 문제를 디버깅하거나 버그 신고에 첨부할 로그를 수집할 때만 디버그 레벨을 사용하세요.</translation>
|
||||||
@ -1280,16 +1179,12 @@ Enabling this setting will disable the server config GUI.</source>
|
|||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Use background service (daemon)</source>
|
<source>Use background service (daemon)</source>
|
||||||
<translation>백그라운드 서비스(데몬) 사용</translation>
|
<translation>백그라운드 서비스(daemon) 사용</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Always run as system (work at login screen and UAC)</source>
|
<source>Always run as system (work at login screen and UAC)</source>
|
||||||
<translation>항상 시스템 권한으로 실행(로그인 화면 및 UAC에서 동작)</translation>
|
<translation>항상 시스템 권한으로 실행(로그인 화면 및 UAC에서 동작)</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>Force a language to be used for the GUI.</source>
|
|
||||||
<translation>GUI에서 사용할 언어를 강제로 지정합니다.</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>Language</source>
|
<source>Language</source>
|
||||||
<translation>언어</translation>
|
<translation>언어</translation>
|
||||||
@ -1342,13 +1237,29 @@ Enabling this setting will disable the server config GUI.</source>
|
|||||||
<source>Verbose debug output</source>
|
<source>Verbose debug output</source>
|
||||||
<translation>상세 디버그 출력</translation>
|
<translation>상세 디버그 출력</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Close and save changes</source>
|
||||||
|
<translation>변경 사항 저장 후 닫기</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Close and forget changes</source>
|
||||||
|
<translation>저장하지 않고 닫기</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Reset to stored values</source>
|
||||||
|
<translation type="unfinished">저장된 값으로 재설정</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Reset to default values</source>
|
||||||
|
<translation type="unfinished">기본값으로 재설정</translation>
|
||||||
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Enable wl-clipboard support</source>
|
<source>Enable wl-clipboard support</source>
|
||||||
<translation>wl-clipboard 지원 사용</translation>
|
<translation>wl-clipboard 지원 사용</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source><html><head/><body><p>Requires the wl-clipboard package</p><p>When using wl-clipboard v2.2.1, there is a focus stealing bug that may make Deskflow harder to use. This has been fixed when using the wl-clipboard master branch, unless your Compositor lacks wlroots-data-control protocol support.</p></body></html></source>
|
<source><html><head/><body><p>Requires the wl-clipboard package</p><p>When using wl-clipboard v2.2.1, there is a focus stealing bug that may make Deskflow harder to use. This has been fixed when using the wl-clipboard master branch, unless your Compositor lacks wlroots-data-control protocol support.</p></body></html></source>
|
||||||
<translation><html><head/><body><p>wl-clipboard 패키지가 필요합니다.</p><p>wl-clipboard v2.2.1 사용 시 포커스 탈취 버그로 인해 Deskflow 사용이 어려워질 수 있습니다. 이 문제는 wl-clipboard master 브랜치를 사용하면 해결되지만, 사용 중인 컴포지터가 wlroots-data-control 프로토콜을 지원하지 않으면 해결되지 않을 수 있습니다.</p></body></html></translation>
|
<translation><html><head/><body><p>wl-clipboard 패키지가 필요합니다.</p><p>wl-clipboard v2.2.1 사용 시 포커스 탈취 버그로 인해 Deskflow 사용이 어려워질 수 있습니다. 이 문제는 wl-clipboard master 브랜치를 사용하면 해결되지만, 사용 중인 컴포지터가 wlroots-data-control 프로토콜을 지원하지 않으면 해결이 안 될 수 있습니다.</p></body></html></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Automatic</source>
|
<source>Automatic</source>
|
||||||
@ -1358,6 +1269,122 @@ Enabling this setting will disable the server config GUI.</source>
|
|||||||
<source>Include version in the window title</source>
|
<source>Include version in the window title</source>
|
||||||
<translation type="unfinished">창 제목에 버전 정보 포함</translation>
|
<translation type="unfinished">창 제목에 버전 정보 포함</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Log to file</source>
|
||||||
|
<translation>파일로 로그 저장</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>&Logs</source>
|
||||||
|
<translation>로그 (&L)</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>&General</source>
|
||||||
|
<translation>일반(&G)</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>&Network</source>
|
||||||
|
<translation>네트워크(&N)</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>&Window</source>
|
||||||
|
<translation type="unfinished">창문(&W)</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>When the main window is closed</source>
|
||||||
|
<translation type="unfinished">메인 창이 닫혔을 때</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Exit</source>
|
||||||
|
<translation type="unfinished">출구</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Send to background</source>
|
||||||
|
<translation type="unfinished">백그라운드로 보내기</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>When the application starts</source>
|
||||||
|
<translation type="unfinished">애플리케이션이 시작될 때</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Show the main window</source>
|
||||||
|
<translation type="unfinished">메인 창을 표시합니다</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Run command on enter</source>
|
||||||
|
<translation type="unfinished">Enter 키를 누르면 명령 실행</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Run command on exit</source>
|
||||||
|
<translation type="unfinished">종료 시 명령 실행</translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>StatusBar</name>
|
||||||
|
<message>
|
||||||
|
<source>%1 is not running</source>
|
||||||
|
<translation>%1 실행 중이 아닙니다</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>%1 is starting...</source>
|
||||||
|
<translation>%1 시작 중...</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>%1 will retry in a moment...</source>
|
||||||
|
<translation>%1 잠시 후 재시도합니다...</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>%1 is stopping...</source>
|
||||||
|
<translation>%1 중지 중...</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>%1 is waiting for clients</source>
|
||||||
|
<translation>%1 클라이언트를 기다리는 중</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>%1 is connecting...</source>
|
||||||
|
<translation>%1 연결 중...</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>%1 is connected as client of %2</source>
|
||||||
|
<translation>%1이(가) %2의 클라이언트로 연결되었습니다</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>%1 is disconnected</source>
|
||||||
|
<translation>%1 연결이 해제되었습니다</translation>
|
||||||
|
</message>
|
||||||
|
<message numerus="yes">
|
||||||
|
<source>%1 is connected, with %n client(s): %2</source>
|
||||||
|
<extracomment>Shown when in server mode and at least 1 client is connected %1 is replaced by the app name %2 will be a list of at least one client %n will be replaced by the number of clients (n is >=1), it is not requried to be in the translation</extracomment>
|
||||||
|
<translation>
|
||||||
|
<numerusform>%1이(가) %n대의 클라이언트와 연결됨: %2</numerusform>
|
||||||
|
</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Clients:
|
||||||
|
%1</source>
|
||||||
|
<translation>클라이언트:
|
||||||
|
%1</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>A new version v%1 is available</source>
|
||||||
|
<translation>새 버전(v%1)을 사용할 수 있습니다</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>View local fingerprint</source>
|
||||||
|
<translation>로컬 핑거프린팅 보기</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Update available</source>
|
||||||
|
<translation>업데이트 사용 가능</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>%1 Encryption Enabled</source>
|
||||||
|
<translation>%1 암호화 사용</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Encryption Disabled</source>
|
||||||
|
<translation>암호화 사용 안 함</translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>i18n</name>
|
<name>i18n</name>
|
||||||
@ -1398,7 +1425,7 @@ Enabling this setting will disable the server config GUI.</source>
|
|||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>A computer with this name already exists</source>
|
<source>A computer with this name already exists</source>
|
||||||
<translation>이 이름의 컴퓨터가 이미 존재합니다</translation>
|
<translation>동명의 컴퓨터가 이미 존재합니다</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
</TS>
|
</TS>
|
||||||
|
|||||||
@ -350,10 +350,6 @@ Do you want to connect to the server?
|
|||||||
<source>invalid certificate, generating a new one</source>
|
<source>invalid certificate, generating a new one</source>
|
||||||
<translation>недействительный сертификат, создание нового</translation>
|
<translation>недействительный сертификат, создание нового</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>A new version v%1 is available</source>
|
|
||||||
<translation>Доступна новая версия v%1</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>Address missing</source>
|
<source>Address missing</source>
|
||||||
<translation>Адрес не указан</translation>
|
<translation>Адрес не указан</translation>
|
||||||
@ -362,10 +358,6 @@ Do you want to connect to the server?
|
|||||||
<source>Please enter the hostname or IP address of the other computer.</source>
|
<source>Please enter the hostname or IP address of the other computer.</source>
|
||||||
<translation>Пожалуйста, введите имя хоста или IP-адрес другого компьютера.</translation>
|
<translation>Пожалуйста, введите имя хоста или IP-адрес другого компьютера.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>Core cannot be started</source>
|
|
||||||
<translation>Не удалось запустить ядро</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>Save server configuration as...</source>
|
<source>Save server configuration as...</source>
|
||||||
<translation>Сохранить конфигурацию сервера как...</translation>
|
<translation>Сохранить конфигурацию сервера как...</translation>
|
||||||
@ -395,12 +387,8 @@ Do you want to connect to the server?
|
|||||||
<translation>Отключиться</translation>
|
<translation>Отключиться</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>%1 Encryption Enabled</source>
|
<source><p>Failed to connect to the server '%1'.</p><p>A Client with your name is already connected to the server.</p>Please ensure that you're using a unique name and that only a single instance of the client process is running.</p></source>
|
||||||
<translation>Шифрование %1 включено</translation>
|
<translation><p>Не удалось подключиться к серверу '%1'.</p><p>Клиент с таким именем уже подключен к серверу.</p>Убедитесь, что вы используете уникальное имя и запущен только один процесс клиента.</p></translation>
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>Encryption Disabled</source>
|
|
||||||
<translation>Шифрование отключено</translation>
|
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>No IP Detected</source>
|
<source>No IP Detected</source>
|
||||||
@ -432,38 +420,6 @@ A bound IP is now invalid, you may need to restart the server.</source>
|
|||||||
<translation>
|
<translation>
|
||||||
Привязанный IP-адрес стал недействительным. Возможно требуется перезапуск сервера.</translation>
|
Привязанный IP-адрес стал недействительным. Возможно требуется перезапуск сервера.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>%1 is starting...</source>
|
|
||||||
<translation>%1 запускается...</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>%1 will retry in a moment...</source>
|
|
||||||
<translation>%1 скоро повторит попытку...</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>%1 is stopping...</source>
|
|
||||||
<translation>%1 останавливается...</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>%1 is not running</source>
|
|
||||||
<translation>%1 не запущен</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>%1 is waiting for clients</source>
|
|
||||||
<translation>%1 ожидает подключения клиентов</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>%1 is connecting...</source>
|
|
||||||
<translation>%1 подключается...</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>%1 is connected as client of %2</source>
|
|
||||||
<translation>%1 подключен как клиент к %2</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>%1 is disconnected</source>
|
|
||||||
<translation>%1 отключен</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>&File</source>
|
<source>&File</source>
|
||||||
<translation>&Файл</translation>
|
<translation>&Файл</translation>
|
||||||
@ -533,14 +489,6 @@ A bound IP is now invalid, you may need to restart the server.</source>
|
|||||||
<extracomment>Quit shortcut</extracomment>
|
<extracomment>Quit shortcut</extracomment>
|
||||||
<translation>Ctrl+Q</translation>
|
<translation>Ctrl+Q</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>View local fingerprint</source>
|
|
||||||
<translation>Показать локальный отпечаток</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>Update available</source>
|
|
||||||
<translation>Доступно обновление</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>Invalid Screen Name</source>
|
<source>Invalid Screen Name</source>
|
||||||
<translation>Недопустимое имя экрана</translation>
|
<translation>Недопустимое имя экрана</translation>
|
||||||
@ -563,29 +511,14 @@ Valid names:
|
|||||||
• Можно использовать _ или -
|
• Можно использовать _ или -
|
||||||
• Длина от 1 до 255 символов</translation>
|
• Длина от 1 до 255 символов</translation>
|
||||||
</message>
|
</message>
|
||||||
<message numerus="yes">
|
|
||||||
<source>%1 is connected, with %n client(s): %2</source>
|
|
||||||
<extracomment>Shown when in server mode and at least 1 client is connected %1 is replaced by the app name %2 will be a list of at least one client %n will be replaced by the number of clients (n is >=1), it is not requried to be in the translation</extracomment>
|
|
||||||
<translation>
|
|
||||||
<numerusform>%1 подключен к %n клиенту: %2</numerusform>
|
|
||||||
<numerusform>%1 подключен к %n клиентам: %2</numerusform>
|
|
||||||
<numerusform>%1 подключен к %n клиентам: %2</numerusform>
|
|
||||||
</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>Clients:
|
<source>%1 Connection Error</source>
|
||||||
%1</source>
|
<translation>Ошибка соединения %1</translation>
|
||||||
<translation>Клиенты:
|
|
||||||
%1</translation>
|
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Suggested IP: </source>
|
<source>Suggested IP: </source>
|
||||||
<translation>Рекомендуемый IP-адрес: </translation>
|
<translation>Рекомендуемый IP-адрес: </translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>The Core executable could not be successfully started, although it does exist. Please check if you have sufficient permissions to run this program.</source>
|
|
||||||
<translation>Не удалось запустить исполняемый файл ядра, хотя он существует. Проверьте наличие прав на запуск программы.</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>&Configure Client</source>
|
<source>&Configure Client</source>
|
||||||
<translation type="unfinished">&Настройка клиента</translation>
|
<translation type="unfinished">&Настройка клиента</translation>
|
||||||
@ -598,6 +531,26 @@ Valid names:
|
|||||||
<source><html>Hostname or IP address of the server computer.<br/>May contain a comma seperated list.</html></source>
|
<source><html>Hostname or IP address of the server computer.<br/>May contain a comma seperated list.</html></source>
|
||||||
<translation type="unfinished"><html>Имя хоста или IP-адрес серверного компьютера.<br/>Может содержать список, разделенный запятыми.</html></translation>
|
<translation type="unfinished"><html>Имя хоста или IP-адрес серверного компьютера.<br/>Может содержать список, разделенный запятыми.</html></translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>read</source>
|
||||||
|
<translation type="unfinished">прочитать</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>read and write</source>
|
||||||
|
<translation type="unfinished">читать и записывать</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>The Core executable could not be started.
|
||||||
|
Please check if you have sufficient permissions to run %1.</source>
|
||||||
|
<translation type="unfinished">Не удалось запустить исполняемый файл Core.
|
||||||
|
Проверьте, достаточно ли у вас прав для запуска %1.</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>
|
||||||
|
Additionally, check you are able to %1 the server config file: %2</source>
|
||||||
|
<translation type="unfinished">
|
||||||
|
Также убедитесь, что вы можете %1 файл конфигурации сервера: %2</translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>NewScreenWidget</name>
|
<name>NewScreenWidget</name>
|
||||||
@ -677,30 +630,6 @@ Valid names:
|
|||||||
<source>%1 Connected</source>
|
<source>%1 Connected</source>
|
||||||
<translation>%1 подключено</translation>
|
<translation>%1 подключено</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source><p>Failed to connect to the server '%1'.</p></source>
|
|
||||||
<translation><p>Не удалось подключиться к серверу '%1'.</p></translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source><p>A Client with your name is already connected to the server.</p>Please ensure that you're using a unique name and that only a single instance of the client process is running.</p></source>
|
|
||||||
<translation><p>Клиент с таким именем уже подключен к серверу.</p>Убедитесь, что вы используете уникальное имя и запущен только один процесс клиента.</p></translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source><p>Please try to connect to the server using the server IP address instead of the hostname. </p><p>If that doesn't work, please check your TLS and firewall settings.</p></source>
|
|
||||||
<translation><p>Попробуйте подключиться к серверу по IP-адресу вместо имени хоста. </p><p>Если это не поможет, проверьте настройки TLS и брандмауэра.</p></translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source><p>Please check your TLS and firewall settings.</p></source>
|
|
||||||
<translation><p>Пожалуйста, проверьте настройки TLS и брандмауэра.</p></translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>%1 Connection Error</source>
|
|
||||||
<translation>Ошибка соединения %1</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>Do not show this message again</source>
|
|
||||||
<translation>Больше не показывать это сообщение</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>%1 - New Client</source>
|
<source>%1 - New Client</source>
|
||||||
<translation>%1 - Новый клиент</translation>
|
<translation>%1 - Новый клиент</translation>
|
||||||
@ -737,10 +666,6 @@ Valid names:
|
|||||||
<source><p>Settings are read-only because you only have read access to the file:</p><p>%1</p></source>
|
<source><p>Settings are read-only because you only have read access to the file:</p><p>%1</p></source>
|
||||||
<translation><p>Настройки доступны только для чтения, так как у вас есть доступ только на чтение к файлу:</p><p>%1</p></translation>
|
<translation><p>Настройки доступны только для чтения, так как у вас есть доступ только на чтение к файлу:</p><p>%1</p></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source><p>Sorry, while this version of %1 does support Wayland, this build was not linked with one or more of the required libraries.</p><p>Please either switch to X from your login screen or use a build that uses the correct libraries.</p><p>If you think this is incorrect, please <a href="%2">report a bug</a>.</p><p>Please check the logs for more information.</p></source>
|
|
||||||
<translation><p>Хотя эта версия %1 поддерживает Wayland, данная сборка не была слинкована с необходимыми библиотеками.</p><p>Пожалуйста, переключитесь на сессию X11 или используйте сборку с поддержкой нужных библиотек.</p><p>Если вы считаете это ошибкой, пожалуйста, <a href="%2">сообщите о ней</a>.</p></translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>No thanks</source>
|
<source>No thanks</source>
|
||||||
<translation>Нет, спасибо</translation>
|
<translation>Нет, спасибо</translation>
|
||||||
@ -1150,30 +1075,14 @@ Enabling this setting will disable the server config GUI.</source>
|
|||||||
<source>Preferences</source>
|
<source>Preferences</source>
|
||||||
<translation>Настройки</translation>
|
<translation>Настройки</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>&Regular</source>
|
|
||||||
<translation>&Основные</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>App</source>
|
|
||||||
<translation>Приложение</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>Check for updates on startup</source>
|
<source>Check for updates on startup</source>
|
||||||
<translation>Проверять обновления при запуске</translation>
|
<translation>Проверять обновления при запуске</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>Hide the window when the app starts</source>
|
|
||||||
<translation>Скрывать окно при запуске</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>Prevent this computer from going to sleep</source>
|
<source>Prevent this computer from going to sleep</source>
|
||||||
<translation>Запретить компьютеру переходить в спящий режим</translation>
|
<translation>Запретить компьютеру переходить в спящий режим</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>Leave app running in notification area when the window is closed</source>
|
|
||||||
<translation>Оставлять приложение в области уведомлений при закрытии окна</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>Tray icon style</source>
|
<source>Tray icon style</source>
|
||||||
<translation>Стиль иконки трея</translation>
|
<translation>Стиль иконки трея</translation>
|
||||||
@ -1210,10 +1119,6 @@ Enabling this setting will disable the server config GUI.</source>
|
|||||||
<source>&Advanced</source>
|
<source>&Advanced</source>
|
||||||
<translation>&Расширенные</translation>
|
<translation>&Расширенные</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>Networking</source>
|
|
||||||
<translation>Сеть</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>Port</source>
|
<source>Port</source>
|
||||||
<translation>Порт</translation>
|
<translation>Порт</translation>
|
||||||
@ -1222,10 +1127,6 @@ Enabling this setting will disable the server config GUI.</source>
|
|||||||
<source>Network IP</source>
|
<source>Network IP</source>
|
||||||
<translation>Сетевой IP-адрес</translation>
|
<translation>Сетевой IP-адрес</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>Logs</source>
|
|
||||||
<translation>Журналы</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>Level</source>
|
<source>Level</source>
|
||||||
<translation>Уровень</translation>
|
<translation>Уровень</translation>
|
||||||
@ -1266,10 +1167,6 @@ Enabling this setting will disable the server config GUI.</source>
|
|||||||
<source>Log path</source>
|
<source>Log path</source>
|
||||||
<translation>Путь к журналам</translation>
|
<translation>Путь к журналам</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>Log to file</source>
|
|
||||||
<translation>Записывать в файл</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>Using a Debug log level may affect performance. Only use a Debug level if you are attempting to debug an issue or are gathering logs to submit with a bug report.</source>
|
<source>Using a Debug log level may affect performance. Only use a Debug level if you are attempting to debug an issue or are gathering logs to submit with a bug report.</source>
|
||||||
<translation>Уровень отладки может повлиять на производительность. Используйте его только для поиска неисправностей.</translation>
|
<translation>Уровень отладки может повлиять на производительность. Используйте его только для поиска неисправностей.</translation>
|
||||||
@ -1286,10 +1183,6 @@ Enabling this setting will disable the server config GUI.</source>
|
|||||||
<source>Always run as system (work at login screen and UAC)</source>
|
<source>Always run as system (work at login screen and UAC)</source>
|
||||||
<translation>Всегда запускать от имени системы (работает на экране входа и UAC)</translation>
|
<translation>Всегда запускать от имени системы (работает на экране входа и UAC)</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>Force a language to be used for the GUI.</source>
|
|
||||||
<translation>Принудительно использовать язык для интерфейса.</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>Language</source>
|
<source>Language</source>
|
||||||
<translation>Язык</translation>
|
<translation>Язык</translation>
|
||||||
@ -1346,6 +1239,22 @@ Enabling this setting will disable the server config GUI.</source>
|
|||||||
<source>Verbose debug output</source>
|
<source>Verbose debug output</source>
|
||||||
<translation>Подробный вывод отладки</translation>
|
<translation>Подробный вывод отладки</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Close and save changes</source>
|
||||||
|
<translation type="unfinished">Закрыть и сохранить изменения</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Close and forget changes</source>
|
||||||
|
<translation type="unfinished">Закройте изменения и забудьте о них</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Reset to stored values</source>
|
||||||
|
<translation type="unfinished">Сбросить до сохраненных значений</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Reset to default values</source>
|
||||||
|
<translation type="unfinished">Сбросить до значений по умолчанию</translation>
|
||||||
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source><html><head/><body><p>Requires the wl-clipboard package</p><p>When using wl-clipboard v2.2.1, there is a focus stealing bug that may make Deskflow harder to use. This has been fixed when using the wl-clipboard master branch, unless your Compositor lacks wlroots-data-control protocol support.</p></body></html></source>
|
<source><html><head/><body><p>Requires the wl-clipboard package</p><p>When using wl-clipboard v2.2.1, there is a focus stealing bug that may make Deskflow harder to use. This has been fixed when using the wl-clipboard master branch, unless your Compositor lacks wlroots-data-control protocol support.</p></body></html></source>
|
||||||
<translation><html><head/><body><p>Требуется пакет wl-clipboard. В версии 2.2.1 есть ошибка перехвата фокуса.</p></body></html></translation>
|
<translation><html><head/><body><p>Требуется пакет wl-clipboard. В версии 2.2.1 есть ошибка перехвата фокуса.</p></body></html></translation>
|
||||||
@ -1358,6 +1267,124 @@ Enabling this setting will disable the server config GUI.</source>
|
|||||||
<source>Include version in the window title</source>
|
<source>Include version in the window title</source>
|
||||||
<translation type="unfinished">Включить номер версии в заголовок окна</translation>
|
<translation type="unfinished">Включить номер версии в заголовок окна</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Log to file</source>
|
||||||
|
<translation>Записывать в файл</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>&Logs</source>
|
||||||
|
<translation>&Журнал</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>&General</source>
|
||||||
|
<translation type="unfinished">&Общий</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>&Network</source>
|
||||||
|
<translation>&Сеть</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>&Window</source>
|
||||||
|
<translation type="unfinished">&Окно</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>When the main window is closed</source>
|
||||||
|
<translation type="unfinished">Когда главное окно закрыто</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Exit</source>
|
||||||
|
<translation type="unfinished">Выход</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Send to background</source>
|
||||||
|
<translation type="unfinished">Отправить в фоновый режим</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>When the application starts</source>
|
||||||
|
<translation type="unfinished">Когда приложение запускается</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Show the main window</source>
|
||||||
|
<translation type="unfinished">Показать главное окно</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Run command on enter</source>
|
||||||
|
<translation type="unfinished">Выполнять команду по нажатию Enter</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Run command on exit</source>
|
||||||
|
<translation type="unfinished">Выполнить команду при выходе</translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>StatusBar</name>
|
||||||
|
<message>
|
||||||
|
<source>%1 is not running</source>
|
||||||
|
<translation>%1 не запущен</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>%1 is starting...</source>
|
||||||
|
<translation>%1 запускается...</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>%1 will retry in a moment...</source>
|
||||||
|
<translation>%1 скоро повторит попытку...</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>%1 is stopping...</source>
|
||||||
|
<translation>%1 останавливается...</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>%1 is waiting for clients</source>
|
||||||
|
<translation>%1 ожидает подключения клиентов</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>%1 is connecting...</source>
|
||||||
|
<translation>%1 подключается...</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>%1 is connected as client of %2</source>
|
||||||
|
<translation>%1 подключен как клиент к %2</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>%1 is disconnected</source>
|
||||||
|
<translation>%1 отключен</translation>
|
||||||
|
</message>
|
||||||
|
<message numerus="yes">
|
||||||
|
<source>%1 is connected, with %n client(s): %2</source>
|
||||||
|
<extracomment>Shown when in server mode and at least 1 client is connected %1 is replaced by the app name %2 will be a list of at least one client %n will be replaced by the number of clients (n is >=1), it is not requried to be in the translation</extracomment>
|
||||||
|
<translation>
|
||||||
|
<numerusform>%1 подключен к %n клиенту: %2</numerusform>
|
||||||
|
<numerusform>%1 подключен к %n клиентам: %2</numerusform>
|
||||||
|
<numerusform>%1 подключен к %n клиентам: %2</numerusform>
|
||||||
|
</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Clients:
|
||||||
|
%1</source>
|
||||||
|
<translation>Клиенты:
|
||||||
|
%1</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>A new version v%1 is available</source>
|
||||||
|
<translation>Доступна новая версия v%1</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>View local fingerprint</source>
|
||||||
|
<translation>Показать локальный отпечаток</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Update available</source>
|
||||||
|
<translation>Доступно обновление</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>%1 Encryption Enabled</source>
|
||||||
|
<translation>Шифрование %1 включено</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Encryption Disabled</source>
|
||||||
|
<translation>Шифрование отключено</translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>i18n</name>
|
<name>i18n</name>
|
||||||
|
|||||||
@ -175,7 +175,7 @@ p, li { white-space: pre-wrap; }
|
|||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Close and forget changes</source>
|
<source>Close and forget changes</source>
|
||||||
<translation type="unfinished">关闭并忘记更改</translation>
|
<translation>关闭并放弃修改</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Reset to stored values</source>
|
<source>Reset to stored values</source>
|
||||||
@ -350,10 +350,6 @@ Do you want to connect to the server?
|
|||||||
<source>invalid certificate, generating a new one</source>
|
<source>invalid certificate, generating a new one</source>
|
||||||
<translation type="unfinished">证书无效,正在生成新证书</translation>
|
<translation type="unfinished">证书无效,正在生成新证书</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>A new version v%1 is available</source>
|
|
||||||
<translation>新版本 v%1 可用</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>Address missing</source>
|
<source>Address missing</source>
|
||||||
<translation>缺少地址</translation>
|
<translation>缺少地址</translation>
|
||||||
@ -362,10 +358,6 @@ Do you want to connect to the server?
|
|||||||
<source>Please enter the hostname or IP address of the other computer.</source>
|
<source>Please enter the hostname or IP address of the other computer.</source>
|
||||||
<translation>请输入另一台计算机的主机名或 IP 地址。</translation>
|
<translation>请输入另一台计算机的主机名或 IP 地址。</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>Core cannot be started</source>
|
|
||||||
<translation>核心服务无法启动</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>Save server configuration as...</source>
|
<source>Save server configuration as...</source>
|
||||||
<translation>另存服务器配置为...</translation>
|
<translation>另存服务器配置为...</translation>
|
||||||
@ -395,12 +387,8 @@ Do you want to connect to the server?
|
|||||||
<translation>断开</translation>
|
<translation>断开</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>%1 Encryption Enabled</source>
|
<source><p>Failed to connect to the server '%1'.</p><p>A Client with your name is already connected to the server.</p>Please ensure that you're using a unique name and that only a single instance of the client process is running.</p></source>
|
||||||
<translation>%1 加密已启用</translation>
|
<translation><p>连接到服务器“%1”失败。</p><p>一个同名的客户端已连接到服务器。</p>请确保您使用的名称唯一,且只有一个客户端进程实例在运行。</p></translation>
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>Encryption Disabled</source>
|
|
||||||
<translation>加密已禁用</translation>
|
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>No IP Detected</source>
|
<source>No IP Detected</source>
|
||||||
@ -432,38 +420,6 @@ A bound IP is now invalid, you may need to restart the server.</source>
|
|||||||
<translation type="unfinished">
|
<translation type="unfinished">
|
||||||
绑定的IP地址现在无效,您可能需要重启服务器。</translation>
|
绑定的IP地址现在无效,您可能需要重启服务器。</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>%1 is starting...</source>
|
|
||||||
<translation>%1 正在启动...</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>%1 will retry in a moment...</source>
|
|
||||||
<translation>%1 将稍后重试...</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>%1 is stopping...</source>
|
|
||||||
<translation>%1 正在停止...</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>%1 is not running</source>
|
|
||||||
<translation>%1 未在运行</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>%1 is waiting for clients</source>
|
|
||||||
<translation>%1 正在等待客户端连接</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>%1 is connecting...</source>
|
|
||||||
<translation>%1 正在连接...</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>%1 is connected as client of %2</source>
|
|
||||||
<translation>%1 已作为 %2 的客户端连接</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>%1 is disconnected</source>
|
|
||||||
<translation>%1 已断开连接</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>&File</source>
|
<source>&File</source>
|
||||||
<translation>文件(&F)</translation>
|
<translation>文件(&F)</translation>
|
||||||
@ -533,14 +489,6 @@ A bound IP is now invalid, you may need to restart the server.</source>
|
|||||||
<extracomment>Quit shortcut</extracomment>
|
<extracomment>Quit shortcut</extracomment>
|
||||||
<translation>Ctrl+Q</translation>
|
<translation>Ctrl+Q</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>View local fingerprint</source>
|
|
||||||
<translation>查看本地指纹</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>Update available</source>
|
|
||||||
<translation>有可用更新</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>Invalid Screen Name</source>
|
<source>Invalid Screen Name</source>
|
||||||
<translation>无效的屏幕名称</translation>
|
<translation>无效的屏幕名称</translation>
|
||||||
@ -563,27 +511,14 @@ Valid names:
|
|||||||
• 可以使用 _ 或 -
|
• 可以使用 _ 或 -
|
||||||
• 长度在 1 到 255 个字符之间</translation>
|
• 长度在 1 到 255 个字符之间</translation>
|
||||||
</message>
|
</message>
|
||||||
<message numerus="yes">
|
|
||||||
<source>%1 is connected, with %n client(s): %2</source>
|
|
||||||
<extracomment>Shown when in server mode and at least 1 client is connected %1 is replaced by the app name %2 will be a list of at least one client %n will be replaced by the number of clients (n is >=1), it is not requried to be in the translation</extracomment>
|
|
||||||
<translation>
|
|
||||||
<numerusform>%1 已连接,共有 %n 个客户端:%2</numerusform>
|
|
||||||
</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>Clients:
|
<source>%1 Connection Error</source>
|
||||||
%1</source>
|
<translation>%1 连接错误</translation>
|
||||||
<translation>客户端:
|
|
||||||
%1</translation>
|
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Suggested IP: </source>
|
<source>Suggested IP: </source>
|
||||||
<translation type="unfinished">建议 IP: </translation>
|
<translation type="unfinished">建议 IP: </translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>The Core executable could not be successfully started, although it does exist. Please check if you have sufficient permissions to run this program.</source>
|
|
||||||
<translation type="unfinished">Core 可执行文件虽然存在,但无法成功启动。请检查您是否拥有运行此程序的足够权限。</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>&Configure Client</source>
|
<source>&Configure Client</source>
|
||||||
<translation type="unfinished">配置客户端(&C)</translation>
|
<translation type="unfinished">配置客户端(&C)</translation>
|
||||||
@ -596,6 +531,26 @@ Valid names:
|
|||||||
<source><html>Hostname or IP address of the server computer.<br/>May contain a comma seperated list.</html></source>
|
<source><html>Hostname or IP address of the server computer.<br/>May contain a comma seperated list.</html></source>
|
||||||
<translation type="unfinished"><html>服务器计算机的主机名或 IP 地址。<br/>可以包含以逗号分隔的列表。</html></translation>
|
<translation type="unfinished"><html>服务器计算机的主机名或 IP 地址。<br/>可以包含以逗号分隔的列表。</html></translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>read</source>
|
||||||
|
<translation type="unfinished">读取</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>read and write</source>
|
||||||
|
<translation type="unfinished">读取和写入</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>The Core executable could not be started.
|
||||||
|
Please check if you have sufficient permissions to run %1.</source>
|
||||||
|
<translation type="unfinished">无法启动Core可执行文件。
|
||||||
|
请检查您是否有足够的权限来运行%1。</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>
|
||||||
|
Additionally, check you are able to %1 the server config file: %2</source>
|
||||||
|
<translation type="unfinished">
|
||||||
|
另外,请检查您是否能够%1服务器配置文件:%2</translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>NewScreenWidget</name>
|
<name>NewScreenWidget</name>
|
||||||
@ -677,30 +632,6 @@ Valid names:
|
|||||||
<source>%1 Connected</source>
|
<source>%1 Connected</source>
|
||||||
<translation>%1 已连接</translation>
|
<translation>%1 已连接</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source><p>Failed to connect to the server '%1'.</p></source>
|
|
||||||
<translation><p>连接到服务器“%1”失败。</p></translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source><p>A Client with your name is already connected to the server.</p>Please ensure that you're using a unique name and that only a single instance of the client process is running.</p></source>
|
|
||||||
<translation type="unfinished"><p>一个同名的客户端已连接到服务器。</p>请确保您使用的名称唯一,且只有一个客户端进程实例在运行。</p></translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source><p>Please try to connect to the server using the server IP address instead of the hostname. </p><p>If that doesn't work, please check your TLS and firewall settings.</p></source>
|
|
||||||
<translation><p>请尝试使用服务器 IP 地址而不是主机名来连接服务器。</p><p>如果不起作用,请检查您的 TLS 和防火墙设置。</p></translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source><p>Please check your TLS and firewall settings.</p></source>
|
|
||||||
<translation><p>请检查您的 TLS 和防火墙设置。</p></translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>%1 Connection Error</source>
|
|
||||||
<translation>%1 连接错误</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>Do not show this message again</source>
|
|
||||||
<translation>不再显示此消息</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>%1 - New Client</source>
|
<source>%1 - New Client</source>
|
||||||
<translation>%1 - 新客户端</translation>
|
<translation>%1 - 新客户端</translation>
|
||||||
@ -737,10 +668,6 @@ Valid names:
|
|||||||
<source><p>Settings are read-only because you only have read access to the file:</p><p>%1</p></source>
|
<source><p>Settings are read-only because you only have read access to the file:</p><p>%1</p></source>
|
||||||
<translation><p>设置是只读的,因为您对该文件只有读取权限:</p><p>%1</p></translation>
|
<translation><p>设置是只读的,因为您对该文件只有读取权限:</p><p>%1</p></translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source><p>Sorry, while this version of %1 does support Wayland, this build was not linked with one or more of the required libraries.</p><p>Please either switch to X from your login screen or use a build that uses the correct libraries.</p><p>If you think this is incorrect, please <a href="%2">report a bug</a>.</p><p>Please check the logs for more information.</p></source>
|
|
||||||
<translation><p>抱歉,虽然此版本的 %1 支持 Wayland,但此构建版本未链接一个或多个所需的库。</p><p>请从登录屏幕切换到 X,或者使用链接了正确库的构建版本。</p><p>如果您认为存在问题,请 <a href="%2">报告 Bug</a>。</p><p>请查看日志以获取更多信息。</p></translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>No thanks</source>
|
<source>No thanks</source>
|
||||||
<translation>不,谢谢</translation>
|
<translation>不,谢谢</translation>
|
||||||
@ -1152,30 +1079,14 @@ Enabling this setting will disable the server config GUI.</source>
|
|||||||
<source>Preferences</source>
|
<source>Preferences</source>
|
||||||
<translation>首选项</translation>
|
<translation>首选项</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>&Regular</source>
|
|
||||||
<translation>常规(&R)</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>App</source>
|
|
||||||
<translation>应用程序</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>Check for updates on startup</source>
|
<source>Check for updates on startup</source>
|
||||||
<translation>启动时检查更新</translation>
|
<translation>启动时检查更新</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>Hide the window when the app starts</source>
|
|
||||||
<translation>应用启动时隐藏窗口</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>Prevent this computer from going to sleep</source>
|
<source>Prevent this computer from going to sleep</source>
|
||||||
<translation>防止此计算机进入睡眠状态</translation>
|
<translation>防止此计算机进入睡眠状态</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>Leave app running in notification area when the window is closed</source>
|
|
||||||
<translation>窗口关闭时让应用在通知区域运行</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>Tray icon style</source>
|
<source>Tray icon style</source>
|
||||||
<translation>托盘图标样式</translation>
|
<translation>托盘图标样式</translation>
|
||||||
@ -1212,10 +1123,6 @@ Enabling this setting will disable the server config GUI.</source>
|
|||||||
<source>&Advanced</source>
|
<source>&Advanced</source>
|
||||||
<translation>高级(&A)</translation>
|
<translation>高级(&A)</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>Networking</source>
|
|
||||||
<translation>网络</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>Port</source>
|
<source>Port</source>
|
||||||
<translation>端口</translation>
|
<translation>端口</translation>
|
||||||
@ -1224,10 +1131,6 @@ Enabling this setting will disable the server config GUI.</source>
|
|||||||
<source>Network IP</source>
|
<source>Network IP</source>
|
||||||
<translation>网络 IP</translation>
|
<translation>网络 IP</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>Logs</source>
|
|
||||||
<translation>日志</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>Level</source>
|
<source>Level</source>
|
||||||
<translation>级别</translation>
|
<translation>级别</translation>
|
||||||
@ -1268,10 +1171,6 @@ Enabling this setting will disable the server config GUI.</source>
|
|||||||
<source>Log path</source>
|
<source>Log path</source>
|
||||||
<translation>日志路径</translation>
|
<translation>日志路径</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>Log to file</source>
|
|
||||||
<translation>记录日志到文件</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>Using a Debug log level may affect performance. Only use a Debug level if you are attempting to debug an issue or are gathering logs to submit with a bug report.</source>
|
<source>Using a Debug log level may affect performance. Only use a Debug level if you are attempting to debug an issue or are gathering logs to submit with a bug report.</source>
|
||||||
<translation>使用调试日志级别可能会影响性能。仅当您尝试调试问题或收集日志以提交 Bug 报告时,才使用调试级别。</translation>
|
<translation>使用调试日志级别可能会影响性能。仅当您尝试调试问题或收集日志以提交 Bug 报告时,才使用调试级别。</translation>
|
||||||
@ -1288,10 +1187,6 @@ Enabling this setting will disable the server config GUI.</source>
|
|||||||
<source>Always run as system (work at login screen and UAC)</source>
|
<source>Always run as system (work at login screen and UAC)</source>
|
||||||
<translation type="unfinished">始终以系统身份运行 (在登录屏幕和 UAC 下工作)</translation>
|
<translation type="unfinished">始终以系统身份运行 (在登录屏幕和 UAC 下工作)</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
|
||||||
<source>Force a language to be used for the GUI.</source>
|
|
||||||
<translation>强制 GUI 使用特定语言。</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
<message>
|
||||||
<source>Language</source>
|
<source>Language</source>
|
||||||
<translation>语言</translation>
|
<translation>语言</translation>
|
||||||
@ -1344,6 +1239,22 @@ Enabling this setting will disable the server config GUI.</source>
|
|||||||
<source>Verbose debug output</source>
|
<source>Verbose debug output</source>
|
||||||
<translation>详细调试输出</translation>
|
<translation>详细调试输出</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Close and save changes</source>
|
||||||
|
<translation type="unfinished">关闭并保存更改</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Close and forget changes</source>
|
||||||
|
<translation>关闭并放弃修改</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Reset to stored values</source>
|
||||||
|
<translation type="unfinished">重置为存储值</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Reset to default values</source>
|
||||||
|
<translation type="unfinished">重置为默认值</translation>
|
||||||
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Enable wl-clipboard support</source>
|
<source>Enable wl-clipboard support</source>
|
||||||
<translation>启用 wl-clipboard 支持</translation>
|
<translation>启用 wl-clipboard 支持</translation>
|
||||||
@ -1360,6 +1271,122 @@ Enabling this setting will disable the server config GUI.</source>
|
|||||||
<source>Include version in the window title</source>
|
<source>Include version in the window title</source>
|
||||||
<translation type="unfinished">在窗口标题中包含版本信息</translation>
|
<translation type="unfinished">在窗口标题中包含版本信息</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Log to file</source>
|
||||||
|
<translation>记录日志到文件</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>&Logs</source>
|
||||||
|
<translation type="unfinished">日志(&L)</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>&General</source>
|
||||||
|
<translation>常规(&G)</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>&Network</source>
|
||||||
|
<translation>网络(&N)</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>&Window</source>
|
||||||
|
<translation type="unfinished">窗户(&W)</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>When the main window is closed</source>
|
||||||
|
<translation type="unfinished">主窗口关闭时</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Exit</source>
|
||||||
|
<translation type="unfinished">出口</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Send to background</source>
|
||||||
|
<translation type="unfinished">发送到后台</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>When the application starts</source>
|
||||||
|
<translation type="unfinished">应用程序启动时</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Show the main window</source>
|
||||||
|
<translation type="unfinished">显示主窗口</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Run command on enter</source>
|
||||||
|
<translation type="unfinished">按下回车键执行命令</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Run command on exit</source>
|
||||||
|
<translation type="unfinished">退出时运行命令</translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>StatusBar</name>
|
||||||
|
<message>
|
||||||
|
<source>%1 is not running</source>
|
||||||
|
<translation>%1 未在运行</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>%1 is starting...</source>
|
||||||
|
<translation>%1 正在启动...</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>%1 will retry in a moment...</source>
|
||||||
|
<translation>%1 将稍后重试...</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>%1 is stopping...</source>
|
||||||
|
<translation>%1 正在停止...</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>%1 is waiting for clients</source>
|
||||||
|
<translation>%1 正在等待客户端连接</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>%1 is connecting...</source>
|
||||||
|
<translation>%1 正在连接...</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>%1 is connected as client of %2</source>
|
||||||
|
<translation>%1 已作为 %2 的客户端连接</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>%1 is disconnected</source>
|
||||||
|
<translation>%1 已断开连接</translation>
|
||||||
|
</message>
|
||||||
|
<message numerus="yes">
|
||||||
|
<source>%1 is connected, with %n client(s): %2</source>
|
||||||
|
<extracomment>Shown when in server mode and at least 1 client is connected %1 is replaced by the app name %2 will be a list of at least one client %n will be replaced by the number of clients (n is >=1), it is not requried to be in the translation</extracomment>
|
||||||
|
<translation>
|
||||||
|
<numerusform>%1 已连接,共有 %n 个客户端:%2</numerusform>
|
||||||
|
</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Clients:
|
||||||
|
%1</source>
|
||||||
|
<translation>客户端:
|
||||||
|
%1</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>A new version v%1 is available</source>
|
||||||
|
<translation>新版本 v%1 可用</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>View local fingerprint</source>
|
||||||
|
<translation>查看本地指纹</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Update available</source>
|
||||||
|
<translation>有可用更新</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>%1 Encryption Enabled</source>
|
||||||
|
<translation>%1 加密已启用</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Encryption Disabled</source>
|
||||||
|
<translation>加密已禁用</translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>i18n</name>
|
<name>i18n</name>
|
||||||
|
|||||||
Reference in New Issue
Block a user