Compare commits
569 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0096283779 | |||
| 0751639f93 | |||
| d719df1642 | |||
| 7abaca76af | |||
| 5ee3fc41bd | |||
| cab1eb9cee | |||
| 51db919d8f | |||
| 314899ac7d | |||
| 632c3462ec | |||
| d6f8cdf51d | |||
| 59173d6405 | |||
| d597d023b1 | |||
| 807e60ded2 | |||
| 0b4a2e0e5b | |||
| 9eabbb690c | |||
| 3eb3969a01 | |||
| d2ac36f3ed | |||
| e6a374369b | |||
| 9c56fa5dda | |||
| 6875969255 | |||
| aa1eaf601c | |||
| f77213af04 | |||
| a4f1a382d3 | |||
| 647201cd37 | |||
| e24b1c4b68 | |||
| 475b895755 | |||
| 593e53370a | |||
| be6a4f6b4d | |||
| 929131d10b | |||
| 767919b342 | |||
| 4224215991 | |||
| 45090d6b85 | |||
| 476f3ba243 | |||
| a33574e1bd | |||
| 456afaa13e | |||
| 17f12d8334 | |||
| 723671c2e5 | |||
| 5a90b51e97 | |||
| fe12972e83 | |||
| 9bdb4252e5 | |||
| c73729e72e | |||
| 04805d9a7e | |||
| 293c5e394c | |||
| 3cf0fb89ef | |||
| 52b0c1f061 | |||
| c224cd4661 | |||
| 635962618f | |||
| 0ff72441e6 | |||
| bdffda9a2f | |||
| cac63937ff | |||
| 12fbc2fd57 | |||
| 06324a941a | |||
| 8dd9e17e72 | |||
| a5e5bbc2e4 | |||
| 34f6186941 | |||
| 486b5a491f | |||
| 037fee0e59 | |||
| a9e0c62c24 | |||
| 43a51434ce | |||
| eaa4c71d6e | |||
| 393a006773 | |||
| 332e6c4a4d | |||
| 63e87c16d1 | |||
| 14cb921d4c | |||
| de583145d0 | |||
| 0309d35aef | |||
| c4704649ea | |||
| e4e332c13f | |||
| 33edb6ce01 | |||
| 49173b11b9 | |||
| 81392fe758 | |||
| 3ae2b3a571 | |||
| 2aee6d8812 | |||
| db3b18b36d | |||
| 89c199b630 | |||
| d023c8ef77 | |||
| af383decca | |||
| 8526facbe9 | |||
| 2b3ecd39c6 | |||
| 49589ae4aa | |||
| 8ce6a07d18 | |||
| a8eb772b68 | |||
| 0916009601 | |||
| f5cb636b31 | |||
| 7ced794317 | |||
| 7c279ec72d | |||
| 83a8d1c4ac | |||
| 84a9367124 | |||
| aaeef7905a | |||
| a0d0936433 | |||
| 8f53b88bb6 | |||
| d8b4fab9a3 | |||
| 9d867f6146 | |||
| 632be4b240 | |||
| b8c6d1b58f | |||
| 139dbf61f3 | |||
| e512125595 | |||
| ae37543a37 | |||
| 8a80c52208 | |||
| 38dc845c72 | |||
| b56a282a9c | |||
| d742901775 | |||
| 287d70a138 | |||
| 6c0843d088 | |||
| cbcaafe764 | |||
| 29a86cfbac | |||
| d7506697c8 | |||
| 6c2457d60b | |||
| 30d9034a0f | |||
| a2acfb0678 | |||
| 7fa326234e | |||
| baaa02cda2 | |||
| 231e5c0bc5 | |||
| 78cbe4b775 | |||
| a1a7c8f3ff | |||
| 501726d471 | |||
| b51dec01ad | |||
| 1c907991af | |||
| 0c3c913989 | |||
| 4479b90d37 | |||
| 8a139f0e3d | |||
| 810322623b | |||
| 245f9db5c8 | |||
| 807f32975a | |||
| 5365e34f08 | |||
| 55a7fa3266 | |||
| 118f867fd1 | |||
| 13dc055405 | |||
| 99dae58fd3 | |||
| e9ccd513f7 | |||
| 903401796e | |||
| 97863bda7c | |||
| 0c94adf03c | |||
| d643e4b189 | |||
| c8734755c5 | |||
| edea3b0df1 | |||
| f4264d71a1 | |||
| 6ffd0eb471 | |||
| 7619928d56 | |||
| d70c7fe720 | |||
| b26ca77ff1 | |||
| 68db2c3484 | |||
| 81c19c6ee8 | |||
| 1276a4a29c | |||
| d97f4d87ad | |||
| d5cbd002a9 | |||
| 31a6fd23e7 | |||
| f6c6d4e3a7 | |||
| 5801b92636 | |||
| b427ac91c2 | |||
| e87c596fbe | |||
| 35b4749627 | |||
| 6b2a28600a | |||
| 600378b72d | |||
| 8e24689f72 | |||
| 07f9c4ba47 | |||
| 9d476e143e | |||
| 6bcdd4ebe7 | |||
| 9085468d1c | |||
| 7bace4d36d | |||
| ca0d095283 | |||
| ace5b54912 | |||
| c99767c8b7 | |||
| 297b781578 | |||
| 8c4dc001bf | |||
| 9ca13a65d1 | |||
| 73566c061d | |||
| ed3118b81a | |||
| cc209b9b1f | |||
| ee22c31f32 | |||
| f376b049e4 | |||
| 57e3ff1fab | |||
| c39f69b64d | |||
| 218a506970 | |||
| 57cb7227a4 | |||
| 6aabb1e858 | |||
| 9aec1ad479 | |||
| c8d4a2186a | |||
| f68744a36d | |||
| 183d660186 | |||
| e20ef3ae55 | |||
| 0bfb95996a | |||
| 7d27031723 | |||
| ada495c681 | |||
| e91b9867e0 | |||
| d483dc38bd | |||
| 56dd5492b4 | |||
| 67c7ba6dae | |||
| 1138e3b1fb | |||
| 6523911e4d | |||
| a52552b821 | |||
| bd2188beb1 | |||
| edc0c0d7a0 | |||
| 95586c88fd | |||
| d7174a3a2f | |||
| 2289ed5845 | |||
| 2192636d2b | |||
| 6194868e89 | |||
| 00f53c1aac | |||
| 59df2db7b7 | |||
| 35f0e9e6e4 | |||
| 3b3d9e14fd | |||
| b3f179a08a | |||
| f3fca87e19 | |||
| a3093fa046 | |||
| c00ebbd6c1 | |||
| 09457793b4 | |||
| d436aa3001 | |||
| ec4851d326 | |||
| f338e5e7a8 | |||
| 55b48a5db7 | |||
| 352a871729 | |||
| b103f28202 | |||
| 39b49acb56 | |||
| 5d4fbc8ea6 | |||
| 3dfa3d5069 | |||
| 6d9c66b03f | |||
| 02b2b82c7f | |||
| aac086ad2a | |||
| 0d3f7248ed | |||
| da6e110b69 | |||
| a298cc84ad | |||
| d8348152ec | |||
| 572953d5ba | |||
| a23856ee09 | |||
| 637adc60b2 | |||
| 0ca847334e | |||
| d06d6a5003 | |||
| 6d856b674b | |||
| bcfc121c37 | |||
| b2ec2f1a34 | |||
| df9d5ded1c | |||
| f11dae97d4 | |||
| 3fdc5288eb | |||
| 955f9652fb | |||
| 9dedf25ecc | |||
| ee3dffc4f8 | |||
| 8123166e66 | |||
| 29626d6694 | |||
| 996af86b9b | |||
| 84fbe48d35 | |||
| 11423ef5a1 | |||
| 7cc108d87c | |||
| af70ff98b7 | |||
| b6f7497c44 | |||
| f6602baa36 | |||
| 72091c6ac4 | |||
| fb5f80857b | |||
| 6c7bdf3e07 | |||
| 1df01d3cf1 | |||
| 2bebdbaf4d | |||
| 63d65bb47b | |||
| 60dc4c0cd8 | |||
| 78d1c5222f | |||
| 6e3426855d | |||
| f49f5f790c | |||
| 4eaf6fda62 | |||
| ebc6186fe7 | |||
| 48f824ca31 | |||
| d6ace78a58 | |||
| 41fda741b3 | |||
| 793ea5f81c | |||
| 285abc7bb7 | |||
| d6c9897748 | |||
| ed4ecc2d81 | |||
| 794017402d | |||
| 4034302bfb | |||
| eab87e3869 | |||
| 294348b42b | |||
| 71b6f07220 | |||
| 9addada64c | |||
| b6196f147a | |||
| 2c4a68ebcf | |||
| d8f480b981 | |||
| 80afb92af1 | |||
| f5f3bc0475 | |||
| 17c7b0f8bf | |||
| fcaadc2cd4 | |||
| e3642f0955 | |||
| 07d837a39b | |||
| 1202145bb8 | |||
| abc963f886 | |||
| 4988196c47 | |||
| 8a2b6bd688 | |||
| 901dacf593 | |||
| c62b4ec068 | |||
| c8408c4823 | |||
| 8657532ca2 | |||
| 64b277a5df | |||
| cd7d53d2bd | |||
| d740574bd4 | |||
| 84ae597d69 | |||
| 16ef088c27 | |||
| 7e4b6b82f4 | |||
| daa095461d | |||
| fde880fb6f | |||
| a04568b25f | |||
| 6e6892b6e7 | |||
| 5ad2c9283d | |||
| 487030aade | |||
| 1ace03d4b5 | |||
| 5df333fae9 | |||
| 3b4306183c | |||
| 4203f42363 | |||
| 7e4ac48476 | |||
| 0b05b0e71d | |||
| ebb63d8113 | |||
| c1f1734943 | |||
| 12bcc1a4d6 | |||
| 84283a1b13 | |||
| 0a33e20723 | |||
| d4f916c365 | |||
| 6df96d4a56 | |||
| e617e4b537 | |||
| ca5cc8211b | |||
| f01b592dad | |||
| 46c6275c43 | |||
| b3fb8959a3 | |||
| 8354a81706 | |||
| d9807a2693 | |||
| 1b8067797e | |||
| cf4fe32aab | |||
| 6bbebe75f9 | |||
| 0b9ecbc2f4 | |||
| fc36cf6be8 | |||
| b7b295aeb6 | |||
| 00b5c32fc9 | |||
| 5355e84b63 | |||
| 8fbcf907b2 | |||
| d2bf5e63e4 | |||
| 3ed0915b57 | |||
| 01878b0522 | |||
| af6b42fe9e | |||
| a0051ea0bc | |||
| 40c915f6bd | |||
| 1cee520e2b | |||
| 1dd5654af6 | |||
| 2708fc96fe | |||
| 5cfaa4a4e0 | |||
| a6453a6819 | |||
| f781ac9855 | |||
| d6087cc5bd | |||
| 6e9694b5d8 | |||
| 201df59cb7 | |||
| bcfc77fde6 | |||
| 245a522188 | |||
| fdf1df1a30 | |||
| 84b433853a | |||
| e225a357fd | |||
| 54fac87ed2 | |||
| 56a665cd18 | |||
| cb8c6fe9d9 | |||
| 239a265e18 | |||
| ee53d28af7 | |||
| 91fd139a49 | |||
| 7f1a234d06 | |||
| db20c4b0c7 | |||
| 7bd3fc1eb5 | |||
| 8fde0d764e | |||
| e1eb4ebf98 | |||
| 4b06160f84 | |||
| 2160f7826f | |||
| 7f6a68bb2f | |||
| 95521c53d6 | |||
| 446847f4fb | |||
| 37bc70896b | |||
| f9c8d08ff7 | |||
| 55c611f754 | |||
| 541e30f406 | |||
| 4b24b5b38d | |||
| df8500178b | |||
| 378fdae140 | |||
| 31e95ad2dc | |||
| 8b5a61f07f | |||
| 516f803eb4 | |||
| c1a7b836ce | |||
| 9530b9c6ba | |||
| 9df2a2c28d | |||
| 133545d03f | |||
| 75e852d95f | |||
| 9c44653fff | |||
| 2adee7c460 | |||
| 6f6e9cddb7 | |||
| fdd9b1bb6d | |||
| b2ff6aa938 | |||
| 5e4188b2fe | |||
| a3875bf71c | |||
| f3930d9520 | |||
| f66a50dab7 | |||
| 68ebc88293 | |||
| 83c8d295d4 | |||
| 07219ed431 | |||
| da5f3c0be1 | |||
| a23e35c522 | |||
| eb74d8ca99 | |||
| 65b6fe7ca3 | |||
| 9b6615328b | |||
| 7fb87b32f5 | |||
| 8508805f5d | |||
| 385a610da2 | |||
| e00058a332 | |||
| 45b6ff19e7 | |||
| 1798d7e4e6 | |||
| 854787e6b3 | |||
| 498ffe85c3 | |||
| cd3f9b2e7d | |||
| 42b16efdb9 | |||
| 003f87db9e | |||
| 86dca27e4c | |||
| 26fa6860e4 | |||
| d9798a9b2b | |||
| 70a2554370 | |||
| 13c325eb3f | |||
| a3ad66dfb0 | |||
| c9d1a50bb0 | |||
| cb3e516206 | |||
| de2e3fb9ce | |||
| 3bad718bb7 | |||
| 40c10766f3 | |||
| bf09df835d | |||
| 4a16804d27 | |||
| 5e1aa9eb5d | |||
| 3c86d9dc83 | |||
| 099262d8ce | |||
| d9e6ec4b70 | |||
| d7b20fad5c | |||
| 6e6a88af87 | |||
| ce17167248 | |||
| 656ad6402b | |||
| 329742a411 | |||
| 4df982dd6f | |||
| b1010751ba | |||
| 4238441018 | |||
| a13bd3d0bd | |||
| 516e612282 | |||
| bfd4bbd8f4 | |||
| 1c4ec6ec41 | |||
| 2ef23b8206 | |||
| ecf70f09f3 | |||
| 397c652e1c | |||
| 1666a30b94 | |||
| 827d020d16 | |||
| 0138372871 | |||
| 9e78cb55aa | |||
| 38cc678ad2 | |||
| e624e6f174 | |||
| 96b50b7d1c | |||
| ffbe2cf885 | |||
| b1b8720781 | |||
| 8609cbc20a | |||
| 7fe862b715 | |||
| 377272e917 | |||
| b051c5ae60 | |||
| 38f00da704 | |||
| dcd2c62880 | |||
| b7f29d76c3 | |||
| 55601debe0 | |||
| 6c8eca6c41 | |||
| 6444e2c208 | |||
| b3ce7c41d3 | |||
| 6963c28219 | |||
| 99ed548495 | |||
| d37bda6edb | |||
| 73de5e964e | |||
| 27451d3425 | |||
| 613f3651ea | |||
| 0e3cee6287 | |||
| 6056e5850b | |||
| 1b01a010ed | |||
| 7faf76c7df | |||
| 55f513941b | |||
| 9e74100960 | |||
| 531b988dd1 | |||
| 5647121dd8 | |||
| c1af4c3b71 | |||
| dd895ed99f | |||
| 7771dcd04c | |||
| d537a23fda | |||
| f7b98465fa | |||
| ed1bf01306 | |||
| 80f814a2da | |||
| 5355c9080b | |||
| 16517ca541 | |||
| e8ea9f53ee | |||
| 7da8c54924 | |||
| 3683db0db9 | |||
| cd0aa6496a | |||
| c583252b03 | |||
| 2c433eddd7 | |||
| 5ee39c9b00 | |||
| c1642b8d9d | |||
| f2c16c4432 | |||
| 37b4e4b57f | |||
| b502a6b848 | |||
| fe0ddf85e4 | |||
| 6990477504 | |||
| e05b35dda4 | |||
| f50e4e850b | |||
| 3cd3d7b1ff | |||
| 5a7284fd6a | |||
| 362b2e1477 | |||
| 7bf716b232 | |||
| 554178b658 | |||
| af17b14224 | |||
| 1e9f92c93f | |||
| 8bb325a2d2 | |||
| 8606dc8618 | |||
| 6362948e15 | |||
| 085a70d5a5 | |||
| 93abf4217b | |||
| 88b0a7d2e1 | |||
| 5fa70d0d0a | |||
| d01c07cab8 | |||
| 6834862413 | |||
| 4273fe2318 | |||
| 266a4a5edf | |||
| 5e6381c88a | |||
| 9aa1d6b79d | |||
| d45d6baacb | |||
| a887ac066c | |||
| 787a48424e | |||
| b20d6361d6 | |||
| b833ca7a45 | |||
| 43eab1f04c | |||
| dc9e104f8c | |||
| f456aab196 | |||
| de3b9d8e2e | |||
| b7960eecb4 | |||
| 03f142977f | |||
| 5360fb3c89 | |||
| 4eb7ea3491 | |||
| 5642879a21 | |||
| 737328d7b0 | |||
| bee0f84556 | |||
| 2721de220a | |||
| 4c6195cc5d | |||
| 1e46bd2727 | |||
| 54ecdad101 | |||
| 51a749b109 | |||
| 788f6c3eb2 | |||
| e01c595071 | |||
| bcd90434a2 | |||
| 698fd3f83c | |||
| 2a53d4f187 | |||
| 53487e757b | |||
| ef315183f3 | |||
| 8b1e8dfd9f | |||
| b73aceee7d | |||
| 3b811a1bd0 | |||
| a099276e4e | |||
| 38f8159e9d | |||
| 87fb06781c | |||
| b9017de881 | |||
| 24d1d4e620 | |||
| 3bcc1e11ed | |||
| d26c75a784 | |||
| 5b091dee56 | |||
| 3344644d2e | |||
| 39e7f60c5a | |||
| 57d1e42eca | |||
| cd45164e40 | |||
| 0ed583a7fe | |||
| 751c869435 | |||
| 4cfeadf0be | |||
| 402baf3bde | |||
| d199130b43 | |||
| 758c1044b5 | |||
| 6e8952c8a0 | |||
| bb38ad0766 |
2
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
2
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@ -1,6 +1,6 @@
|
||||
name: Bug report
|
||||
description: If you find a bug in Deskflow, please let us know so we can fix it.
|
||||
labels: ["bug", "triage", "unanswered"]
|
||||
type: "Triage [bug]"
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
|
||||
2
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
2
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
@ -1,6 +1,6 @@
|
||||
name: Feature request
|
||||
description: Had an idea how to improve Deskflow? Share it with us.
|
||||
labels: ["enhancement", "triage", "unanswered"]
|
||||
type: "Triage [feature]"
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
|
||||
48
.github/actions/install-dependencies/action.yml
vendored
48
.github/actions/install-dependencies/action.yml
vendored
@ -27,41 +27,37 @@ runs:
|
||||
|
||||
steps:
|
||||
- name: Install Depends
|
||||
if: ${{ runner.os != 'Windows' }}
|
||||
run: |
|
||||
if [ "$RUNNER_OS" == "Windows" ]; then
|
||||
echo "Window not supported yet"
|
||||
elif [ "$RUNNER_OS" == "macOS" ]; then
|
||||
brew install cmake googletest ninja openssl --quiet
|
||||
if [ "$RUNNER_OS" == "macOS" ]; then
|
||||
brew install googletest openssl --quiet
|
||||
elif [ "$RUNNER_OS" == "Linux" ]; then
|
||||
if [ ${{inputs.like}} == "debian" ]; then
|
||||
apt update -qqq > /dev/null
|
||||
apt install -qqq cmake build-essential ninja-build \
|
||||
xorg-dev libx11-dev libxtst-dev libssl-dev \
|
||||
libglib2.0-dev libgdk-pixbuf-2.0-dev libnotify-dev \
|
||||
libxkbfile-dev qt6-base-dev qt6-tools-dev \
|
||||
libgtk-3-dev libgtest-dev libgmock-dev libpugixml-dev \
|
||||
libei-dev libportal-dev libtomlplusplus-dev libcli11-dev -y >/dev/null
|
||||
libglib2.0-dev libxkbfile-dev qt6-base-dev qt6-tools-dev \
|
||||
libgtk-3-dev libgtest-dev libgmock-dev \
|
||||
libei-dev libportal-dev libtomlplusplus-dev libcli11-dev \
|
||||
help2man -y >/dev/null
|
||||
elif [ ${{inputs.like}} == "fedora" ]; then
|
||||
dnf install -y cmake make ninja-build gcc-c++ \
|
||||
rpm-build openssl-devel glib2-devel \
|
||||
gdk-pixbuf2-devel libXtst-devel libnotify-devel \
|
||||
libxkbfile-devel qt6-qtbase-devel qt6-qttools-devel \
|
||||
gtk3-devel gtest-devel gmock-devel pugixml-devel \
|
||||
libXtst-devel libxkbfile-devel qt6-qtbase-devel qt6-qttools-devel \
|
||||
gtk3-devel gtest-devel gmock-devel \
|
||||
libei-devel libportal-devel tomlplusplus-devel \
|
||||
cli11-devel
|
||||
cli11-devel help2man
|
||||
elif [ ${{inputs.like}} == "suse" ]; then
|
||||
zypper refresh
|
||||
zypper install -y --force-resolution \
|
||||
cmake make ninja gcc-c++ rpm-build libopenssl-devel \
|
||||
glib2-devel gdk-pixbuf-devel libXtst-devel libnotify-devel \
|
||||
libxkbfile-devel qt6-base-devel qt6-tools-devel gtk3-devel \
|
||||
googletest-devel googlemock-devel pugixml-devel libei-devel \
|
||||
libportal-devel tomlplusplus-devel cli11-devel
|
||||
glib2-devel libXtst-devel libxkbfile-devel qt6-base-devel qt6-tools-devel gtk3-devel \
|
||||
googletest-devel googlemock-devel libei-devel \
|
||||
libportal-devel tomlplusplus-devel cli11-devel help2man
|
||||
elif [ ${{ inputs.like }} == "arch" ]; then
|
||||
pacman -Syu --noconfirm base-devel cmake ninja \
|
||||
gcc openssl glib2 gdk-pixbuf2 libxtst libnotify \
|
||||
libxkbfile gtest pugixml libei libportal \
|
||||
qt6-base qt6-tools gtk3 tomlplusplus cli11
|
||||
gcc openssl glib2 libxtst libxkbfile gtest libei libportal \
|
||||
qt6-base qt6-tools qt6-svg gtk3 tomlplusplus cli11 help2man
|
||||
else
|
||||
echo "Unknown like"
|
||||
fi
|
||||
@ -73,29 +69,23 @@ runs:
|
||||
- name: Install Qt
|
||||
if: ${{runner.os != 'Linux' }}
|
||||
uses: jurplel/install-qt-action@v4
|
||||
env:
|
||||
AQT_CONFIG: ${{ github.workspace }}/.github/actions/install-dependencies/aqt.ini
|
||||
with:
|
||||
dir: ${{inputs.qt-install-dir}}
|
||||
version: ${{inputs.qt-version}}
|
||||
cache: true
|
||||
cache-key-prefix: ${{matrix.target.os}}-${{inputs.qt-version}}
|
||||
|
||||
# Install Ninja with an action instead of using Chocolatey, as it's more
|
||||
# reliable and faster. The Ninja install action is pretty good as it
|
||||
# downloads directly from the `ninja-build` GitHub project releases.
|
||||
- name: Install Ninja
|
||||
if: ${{ runner.os == 'Windows' }}
|
||||
uses: seanmiddleditch/gha-setup-ninja@master
|
||||
|
||||
- name: Build and cache vcpkg
|
||||
if: ${{ runner.os == 'Windows' }}
|
||||
id: vcpkg
|
||||
uses: johnwason/vcpkg-action@v6
|
||||
uses: sithlord48/vcpkg-action@v7
|
||||
with:
|
||||
pkgs: wintoast gtest pkgconf openssl
|
||||
pkgs: gtest openssl
|
||||
extra-args: --classic
|
||||
triplet: x64-windows-release
|
||||
token: ${{ github.token }}
|
||||
github-binarycache: true
|
||||
|
||||
- name: Install Wix
|
||||
if: ${{ runner.os == 'Windows' }}
|
||||
|
||||
14
.github/actions/install-dependencies/aqt.ini
vendored
Normal file
14
.github/actions/install-dependencies/aqt.ini
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
[aqt]
|
||||
# Using this mirror instead of download.qt.io because of timeouts in CI
|
||||
baseurl: https://qt.mirror.constant.com
|
||||
|
||||
[requests]
|
||||
hash_algorithm: sha1
|
||||
|
||||
[mirrors]
|
||||
trusted_mirrors:
|
||||
https://qt.mirror.constant.com
|
||||
fallbacks:
|
||||
https://qt.mirror.constant.com
|
||||
https://mirrors.ocf.berkeley.edu
|
||||
https://download.qt.io
|
||||
2
.github/actions/lint-check/action.yml
vendored
2
.github/actions/lint-check/action.yml
vendored
@ -5,7 +5,7 @@ runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: Install Dependencies
|
||||
run: pipx install --global clang_format
|
||||
run: pipx install --global clang-format==20.1.0
|
||||
shell: bash
|
||||
|
||||
- name: Run format command
|
||||
|
||||
20
.github/actions/run-tests/action.yml
vendored
20
.github/actions/run-tests/action.yml
vendored
@ -15,12 +15,12 @@ runs:
|
||||
using: "composite"
|
||||
|
||||
steps:
|
||||
- name: Unit tests
|
||||
- name: Unit Tests
|
||||
id: unittests
|
||||
env:
|
||||
QT_QPA_PLATFORM: offscreen
|
||||
run: |
|
||||
./${{ inputs.bin-dir }}/unittests
|
||||
ctest --test-dir "build/src/unittests" --output-on-failure
|
||||
result=$?
|
||||
|
||||
if [ $result -ne 0 ]; then
|
||||
@ -29,16 +29,16 @@ runs:
|
||||
shell: bash
|
||||
continue-on-error: true
|
||||
|
||||
- name: Integration tests
|
||||
id: integtests
|
||||
- name: Legacy Tests
|
||||
id: legacytests
|
||||
env:
|
||||
QT_QPA_PLATFORM: offscreen
|
||||
run: |
|
||||
./${{ inputs.bin-dir }}/integtests
|
||||
./${{ inputs.bin-dir }}/legacytests
|
||||
result=$?
|
||||
|
||||
if [ $result -ne 0 ]; then
|
||||
echo "Integration tests failed with code: $result" >> $GITHUB_STEP_SUMMARY
|
||||
echo "Legacy tests failed with code: $result" >> $GITHUB_STEP_SUMMARY
|
||||
fi
|
||||
shell: bash
|
||||
continue-on-error: true
|
||||
@ -49,11 +49,11 @@ runs:
|
||||
pass="✅ Pass"
|
||||
fail="❌ Fail"
|
||||
unittests_outcome="${{ steps.unittests.outcome }}"
|
||||
integtests_outcome="${{ steps.integtests.outcome }}"
|
||||
legacytests_outcome="${{ steps.legacytests.outcome }}"
|
||||
unittests=$( [ "$unittests_outcome" = "success" ] && echo $pass || echo $fail )
|
||||
integtests=$( [ "$integtests_outcome" = "success" ] && echo $pass || echo $fail )
|
||||
legacytests=$( [ "$legacytests_outcome" = "success" ] && echo $pass || echo $fail )
|
||||
echo "unittests=$unittests" >> $GITHUB_OUTPUT
|
||||
echo "integtests=$integtests" >> $GITHUB_OUTPUT
|
||||
echo "legacytests=$legacytests" >> $GITHUB_OUTPUT
|
||||
shell: bash
|
||||
|
||||
- name: Summary row
|
||||
@ -64,7 +64,7 @@ runs:
|
||||
row=""
|
||||
row+="| ${{ inputs.job }} "
|
||||
row+="| ${{ steps.results.outputs.unittests }} "
|
||||
row+="| ${{ steps.results.outputs.integtests }} |"
|
||||
row+="| ${{ steps.results.outputs.legacytests }} "
|
||||
echo "$row" > $file
|
||||
|
||||
echo "file=$file" > $GITHUB_OUTPUT
|
||||
|
||||
34
.github/workflows/continuous-integration.yml
vendored
34
.github/workflows/continuous-integration.yml
vendored
@ -28,7 +28,7 @@ env:
|
||||
GIT_SHA: ${{ github.event.pull_request.head.sha || github.sha }}
|
||||
PACKAGE_PREFIX: "deskflow"
|
||||
PACKAGE_PATH: ./dist
|
||||
CMAKE_CONFIGURE: "cmake -Bbuild -DCMAKE_BUILD_TYPE=Release -DCMAKE_COMPILE_WARNING_AS_ERROR=ON"
|
||||
CMAKE_CONFIGURE: "cmake -Bbuild -DCMAKE_BUILD_TYPE=Release -DSKIP_BUILD_TESTS=ON -DCMAKE_COMPILE_WARNING_AS_ERROR=ON"
|
||||
|
||||
jobs:
|
||||
# Always run this job, even if not on PR, since other jobs need it.
|
||||
@ -138,14 +138,13 @@ jobs:
|
||||
- name: "macos-14-arm64"
|
||||
runs-on: "macos-14"
|
||||
timeout: 10
|
||||
arch: arm64
|
||||
config-args: "-DCMAKE_OSX_ARCHITECTURES=\"arm64\""
|
||||
config-args: "-DCMAKE_OSX_ARCHITECTURES=\"arm64\" -DCMAKE_OSX_SYSROOT=/Applications/Xcode_15.0.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk"
|
||||
qt-install-dir: "/Users/runner"
|
||||
|
||||
- name: "macos-13-x64"
|
||||
runs-on: macos-13
|
||||
timeout: 20
|
||||
config-args: "-DCMAKE_OSX_ARCHITECTURES=\"x86_64\""
|
||||
config-args: "-DCMAKE_OSX_ARCHITECTURES=\"x86_64\" -DCMAKE_OSX_SYSROOT=/Applications/Xcode_15.0.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk"
|
||||
qt-install-dir: "/Users/runner"
|
||||
|
||||
- name: "debian-13-x86_64"
|
||||
@ -162,6 +161,20 @@ jobs:
|
||||
timeout: 20
|
||||
config-args: "-G Ninja -DCMAKE_INSTALL_PREFIX=/usr"
|
||||
|
||||
- name: "fedora-42-x86_64"
|
||||
runs-on: ubuntu-latest
|
||||
container: fedora:42
|
||||
like: "fedora"
|
||||
timeout: 20
|
||||
config-args: "-G Ninja -DCMAKE_INSTALL_PREFIX=/usr"
|
||||
|
||||
- name: "fedora-42-arm64"
|
||||
runs-on: ubuntu-24.04-arm
|
||||
container: fedora:42
|
||||
like: "fedora"
|
||||
timeout: 20
|
||||
config-args: "-G Ninja -DCMAKE_INSTALL_PREFIX=/usr"
|
||||
|
||||
- name: "fedora-41-x86_64"
|
||||
runs-on: ubuntu-latest
|
||||
container: fedora:41
|
||||
@ -258,7 +271,7 @@ jobs:
|
||||
id: get-deps
|
||||
uses: ./.github/actions/install-dependencies
|
||||
with:
|
||||
qt-version: 6.8.2
|
||||
qt-version: 6.9.0
|
||||
qt-install-dir: ${{matrix.target.qt-install-dir}}
|
||||
like: ${{ matrix.target.like }}
|
||||
|
||||
@ -316,21 +329,20 @@ jobs:
|
||||
# it also makes sure we can use git --describe correctly
|
||||
- name: Fancy Checkout
|
||||
uses: sithlord48/fancy-checkout@v1
|
||||
|
||||
- name: Build on FreeBSD
|
||||
if: ${{ matrix.distro.name == 'freebsd' }}
|
||||
uses: vmactions/freebsd-vm@v1
|
||||
with:
|
||||
usesh: true
|
||||
run: |
|
||||
./scripts/install_deps.sh
|
||||
pkg install -y cmake ninja gmake gcc12 openssl glib \
|
||||
libX11 libXtst libxkbfile qt6-base qt6-tools gtk3 googletest \
|
||||
tomlplusplus cli11 pkgconf libei libportal
|
||||
${{env.CMAKE_CONFIGURE}} -G Ninja
|
||||
cmake --build build -j16
|
||||
|
||||
# Integration tests are flakey by nature, make them optional.
|
||||
export QT_QPA_PLATFORM=offscreen
|
||||
./build/bin/unittests
|
||||
./build/bin/integtests || true
|
||||
./build/bin/unittests || true
|
||||
flatpak:
|
||||
needs: lint-check
|
||||
name: flatpak-${{matrix.flatpak.arch}}
|
||||
@ -363,7 +375,7 @@ jobs:
|
||||
run: flatpak-builder-lint manifest deploy/linux/flatpak/org.deskflow.deskflow.yml
|
||||
|
||||
- name: Build
|
||||
uses: flathub-infra/flatpak-github-actions/flatpak-builder@53987ffa5f687586936d85fdce3f440848bea04d
|
||||
uses: flatpak/flatpak-github-actions/flatpak-builder@v6
|
||||
with:
|
||||
bundle: deskflow-${{env.DESKFLOW_PACKAGE_VERSION}}-linux-${{matrix.flatpak.arch}}.flatpak
|
||||
manifest-path: deploy/linux/flatpak/org.deskflow.deskflow.yml
|
||||
|
||||
19
.github/workflows/sonarcloud-analysis.yml
vendored
19
.github/workflows/sonarcloud-analysis.yml
vendored
@ -44,28 +44,27 @@ jobs:
|
||||
-G "Ninja" \
|
||||
-DCMAKE_BUILD_TYPE="Debug" \
|
||||
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON \
|
||||
-DSKIP_BUILD_TESTS=ON \
|
||||
-DENABLE_COVERAGE=ON
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
build-wrapper-linux-x86-64 --out-dir bw-output cmake --build build -j${CPU_CORE_COUNT}
|
||||
|
||||
- name: Unit tests coverage
|
||||
- name: Test coverage
|
||||
shell: bash
|
||||
env:
|
||||
QT_QPA_PLATFORM: offscreen
|
||||
run: cmake --build build --target coverage-unittests
|
||||
|
||||
- name: Integration tests coverage
|
||||
env:
|
||||
QT_QPA_PLATFORM: offscreen
|
||||
run: cmake --build build --target coverage-integtests
|
||||
run: |
|
||||
tests=(`cmake --build build --target help | grep -o "^coverage-[^:]*"`)
|
||||
for i in "${tests[@]}"; do
|
||||
cmake --build build --target "$i"
|
||||
done
|
||||
|
||||
- name: Get coverage report paths
|
||||
id: coverage-paths
|
||||
run: |
|
||||
unittests=$(find build -name coverage-unittests.xml)
|
||||
integtests=$(find build -name coverage-integtests.xml)
|
||||
paths="${unittests}${integtests:+,$integtests}"
|
||||
paths=$(ls -w 0 -m build/coverage-*.xml | sed 's/ //g')
|
||||
if [ -z "$paths" ]; then
|
||||
echo "Error: No coverage files found"
|
||||
exit 1
|
||||
|
||||
19
.github/workflows/valgrind-analysis.yml
vendored
19
.github/workflows/valgrind-analysis.yml
vendored
@ -31,16 +31,10 @@ jobs:
|
||||
run: cmake --build build -j8
|
||||
|
||||
- name: Valgrind unit tests
|
||||
id: unittests
|
||||
id: legacytests
|
||||
uses: ./.github/actions/run-valgrind
|
||||
with:
|
||||
executable: ./build/bin/unittests
|
||||
|
||||
- name: Valgrind integration tests
|
||||
id: integtests
|
||||
uses: ./.github/actions/run-valgrind
|
||||
with:
|
||||
executable: ./build/bin/integtests
|
||||
executable: ./build/bin/legacytests
|
||||
|
||||
- name: Set job summary
|
||||
run: |
|
||||
@ -48,14 +42,9 @@ jobs:
|
||||
message=$(cat <<EOF
|
||||
## Valgrind summary
|
||||
|
||||
### Unit tests
|
||||
### legacytests Unit tests
|
||||
$backticks
|
||||
${{ steps.unittests.outputs.summary }}
|
||||
$backticks
|
||||
|
||||
### Integration tests
|
||||
$backticks
|
||||
${{ steps.integtests.outputs.summary }}
|
||||
${{ steps.legacytests.outputs.summary }}
|
||||
$backticks
|
||||
EOF
|
||||
)
|
||||
|
||||
@ -18,8 +18,8 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
# Fallback for when git can not be found
|
||||
set(DESKFLOW_VERSION_MAJOR 1)
|
||||
set(DESKFLOW_VERSION_MINOR 20)
|
||||
set(DESKFLOW_VERSION_PATCH 1)
|
||||
set(DESKFLOW_VERSION_MINOR 22)
|
||||
set(DESKFLOW_VERSION_PATCH 0)
|
||||
set(DESKFLOW_VERSION_TWEAK 0)
|
||||
|
||||
# Get the version from git if it's a git repository
|
||||
@ -72,7 +72,7 @@ endif()
|
||||
project(
|
||||
deskflow
|
||||
VERSION "${DESKFLOW_VERSION_MAJOR}.${DESKFLOW_VERSION_MINOR}.${DESKFLOW_VERSION_PATCH}.${DESKFLOW_VERSION_TWEAK}"
|
||||
DESCRIPTION "Mouse and keyboard sharing utility"
|
||||
DESCRIPTION "Keyboard and mouse sharing utility"
|
||||
LANGUAGES C CXX)
|
||||
|
||||
# Define Additional "PROJECT" vars for packaging and metadata
|
||||
@ -95,6 +95,38 @@ set(REQUIRED_LIBEI_VERSION 1.3)
|
||||
set(REQUIRED_LIBPORTAL_VERSION 0.8)
|
||||
set(REQUIRED_QT_VERSION 6.7.0)
|
||||
|
||||
if (WIN32)
|
||||
# VSCMD_ARG_TGT_ARCH is set on CI
|
||||
if ("$ENV{VSCMD_ARG_TGT_ARCH}" STREQUAL "")
|
||||
# NOT on CI
|
||||
if (CMAKE_SYSTEM_PROCESSOR MATCHES "[Aa][Rr][Mm]64")
|
||||
set(BUILD_ARCHITECTURE arm64)
|
||||
else()
|
||||
set(BUILD_ARCHITECTURE x64)
|
||||
endif()
|
||||
else()
|
||||
set (BUILD_ARCHITECTURE $ENV{VSCMD_ARG_TGT_ARCH})
|
||||
endif()
|
||||
else()
|
||||
set (BUILD_ARCHITECTURE ${CMAKE_SYSTEM_PROCESSOR})
|
||||
endif()
|
||||
|
||||
if (MSVC)
|
||||
# On Windows, require that the same MSVC runtime is used as on the host.
|
||||
# Mitigates things like access violations caused by accidental ABI-compatibility breakage.
|
||||
set(REQUIRED_MSVC_RUNTIME_MAJOR 14)
|
||||
cmake_host_system_information(
|
||||
RESULT REQUIRED_MSVC_RUNTIME_MINOR
|
||||
QUERY WINDOWS_REGISTRY
|
||||
"HKLM/SOFTWARE/Microsoft/VisualStudio/${REQUIRED_MSVC_RUNTIME_MAJOR}.0/VC/Runtimes/${BUILD_ARCHITECTURE}"
|
||||
VALUE "Minor")
|
||||
if (REQUIRED_MSVC_RUNTIME_MINOR)
|
||||
message(STATUS "MSVC runtime: ${REQUIRED_MSVC_RUNTIME_MAJOR}.${REQUIRED_MSVC_RUNTIME_MINOR}")
|
||||
else()
|
||||
message(FATAL_ERROR "MSVC runtime registry entry not found")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Control debug item visibility
|
||||
# When not set logging is forced to DEBUG and show code locations
|
||||
# Also exposes a test menu
|
||||
|
||||
13
CONTRIBUTING.md
Normal file
13
CONTRIBUTING.md
Normal file
@ -0,0 +1,13 @@
|
||||
# Contributing to Deskflow
|
||||
|
||||
Thanks for your interest in contributing to Deskflow! We welcome all kinds of contributions — bug reports, feature suggestions, documentation improvements, and code.
|
||||
|
||||
## Read the Full Guidelines
|
||||
|
||||
To keep this repository clean and contribution-friendly, we've outlined our full contributing guidelines on the Deskflow Wiki:
|
||||
|
||||
👉 [How to Contribute to Deskflow](https://github.com/deskflow/deskflow/wiki/Contributing)
|
||||
|
||||
Please take a moment to read through the page before opening an issue or submitting a pull request.
|
||||
|
||||
Thanks again for helping make Deskflow better!
|
||||
89
README.md
89
README.md
@ -1,28 +1,22 @@
|
||||

|
||||
|
||||
> [!TIP]
|
||||
> [Synergy](https://symless.com/synergy) sponsors the Deskflow project by contributing code and providing financial support.
|
||||
>
|
||||
> - [**Bounties**](https://github.com/deskflow/deskflow/issues?q=is%3Aissue%20state%3Aopen%20label%3A%22%F0%9F%92%8E%20bounty%22) - Earn while contributing to open source
|
||||
> - [**Rewarded**](https://github.com/deskflow/deskflow/issues?q=label%3A%22%F0%9F%92%B0%20rewarded%22%20) - Issues with a rewarded bounty
|
||||
>
|
||||
> **Deskflow** is the official upstream project for Synergy.
|
||||
> Purchasing a Synergy license is one way to support Deskflow’s growth and sustainability.
|
||||
> Learn more: [Relationship with Synergy](https://github.com/deskflow/deskflow/wiki/Relationship-with-Synergy)
|
||||
|
||||
**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.
|
||||
It's like a software KVM (but without the video).
|
||||
TLS encryption is enabled by default. Wayland is supported. Clipboard sharing is supported.
|
||||
|
||||
[](https://github.com/deskflow/deskflow/releases/latest) [](https://github.com/deskflow/deskflow/releases/continuous) [](https://flathub.org/apps/org.deskflow.deskflow)
|
||||
## Download
|
||||
|
||||
To use Deskflow you can use one of our [packages](https://github.com/deskflow/deskflow/releases), install `deskflow` (if available in your package repository), or [build it](#build-quick-start) yourself from source.
|
||||
[](https://github.com/deskflow/deskflow/releases/latest) [](https://github.com/deskflow/deskflow/releases/continuous) [](https://flathub.org/apps/org.deskflow.deskflow)
|
||||
|
||||
> [!TIP]
|
||||
> For macOS users, the easiest way to install and stay up to date is to use [Homebrew](https://brew.sh) with our [homebrew-tap](https://github.com/deskflow/homebrew-tap).
|
||||
|
||||
To use Deskflow, download one of our [packages](https://github.com/deskflow/deskflow/releases), install `deskflow` (from your package repository), or [build it](https://github.com/deskflow/deskflow/wiki/Building) from source.
|
||||
|
||||
## Stats
|
||||
|
||||
[](https://github.com/deskflow/deskflow/commits/master/)
|
||||
[](https://github.com/deskflow/deskflow/commits/master/)
|
||||
[](LICENSE)
|
||||
@ -36,27 +30,16 @@ To use Deskflow you can use one of our [packages](https://github.com/deskflow/de
|
||||
[](https://github.com/deskflow/deskflow/actions/workflows/continuous-integration.yml)
|
||||
[](https://github.com/deskflow/deskflow/actions/workflows/codeql-analysis.yml)
|
||||
[](https://github.com/deskflow/deskflow/actions/workflows/sonarcloud-analysis.yml)
|
||||
## Project Values
|
||||
|
||||
- Motivated by the community interests (not business-driven)
|
||||
- Privacy by default (e.g. update check is off by default)
|
||||
- Leading edge releases (we don't focus on supporting older systems)
|
||||
- Decisions are discussed and documented publicly with majority rule
|
||||
- Have fun; we don't need to worry about impressing anyone
|
||||
## Contribute
|
||||
|
||||
## Ways to get involved
|
||||
[](https://github.com/deskflow/deskflow/labels/good%20first%20issue) [](https://github.com/deskflow/deskflow/issues?q=is%3Aissue%20state%3Aopen%20label%3A%22%F0%9F%92%8E%20bounty%22) [](https://github.com/deskflow/deskflow/issues?q=label%3A%22%F0%9F%92%B0%20rewarded%22%20sort%3Aupdated-desc)
|
||||
|
||||
> [!TIP]
|
||||
> Join us! Real-time discussion on Matrix: [`#deskflow:matrix.org`](https://matrix.to/#/#deskflow:matrix.org)
|
||||
>
|
||||
> Alternatively, we have [other ways](https://github.com/deskflow/deskflow/wiki/Chat-with-us) to communicate.
|
||||
>
|
||||
Here are a few ways to join in with the project and get involved:
|
||||
* Build the latest `master` version (see below) and [report a bug](https://github.com/deskflow/deskflow/issues)
|
||||
* [Submit a PR](https://github.com/deskflow/deskflow/wiki/Contributing) (pull request) with a bug fix or improvement
|
||||
* [Let us know](https://github.com/deskflow/deskflow/issues) if you have an idea for an improvement
|
||||
There are many ways to contribute to the Deskflow project.
|
||||
|
||||
## Build Quick Start
|
||||
We're a friendly, active, and welcoming community focused on building a great app.
|
||||
|
||||
Read our [Contributing](https://github.com/deskflow/deskflow/wiki/Contributing) page to get started.
|
||||
|
||||
For instructions on building Deskflow, use the wiki page: [Building](https://github.com/deskflow/deskflow/wiki/Building)
|
||||
|
||||
@ -65,11 +48,11 @@ For instructions on building Deskflow, use the wiki page: [Building](https://git
|
||||
We support all major operating systems, including Windows, macOS, Linux, and Unix-like BSD-derived.
|
||||
|
||||
> [!NOTE]
|
||||
> On Windows, you will need to install the
|
||||
> On Windows, you will need to install the
|
||||
> [Microsoft Visual C++ Redistributable](https://learn.microsoft.com/en-us/cpp/windows/latest-supported-vc-redist?view=msvc-170#latest-microsoft-visual-c-redistributable-version).
|
||||
> Download latest: [`vc_redist.x64.exe`](https://aka.ms/vs/17/release/vc_redist.x64.exe)
|
||||
|
||||
Windows 10 or higher is required.
|
||||
Windows 10 or higher is required.
|
||||
|
||||
macOS 12 or higher is required.
|
||||
|
||||
@ -102,46 +85,39 @@ macOS users who download directly from releases may need to run `xattr -c /Appli
|
||||
It is recommend to install Deskflow using [Homebrew](https://brew.sh) from our [homebrew-tap](https://github.com/deskflow/homebrew-tap)
|
||||
|
||||
To add our tap, run:
|
||||
|
||||
```
|
||||
brew tap deskflow/homebrew-tap
|
||||
```
|
||||
|
||||
Then install either:
|
||||
|
||||
- Stable: `brew install deskflow`
|
||||
- Continuous: `brew install deskflow-dev`
|
||||
|
||||
|
||||
|
||||
## Collaborative Projects
|
||||
## Similar Projects
|
||||
|
||||
In the open source developer community, similar projects collaborate for the improvement of all
|
||||
mouse and keyboard sharing tools. We aim for idea sharing and interoperability.
|
||||
|
||||
* [**Lan Mouse**](https://github.com/feschber/lan-mouse) -
|
||||
- [**Lan Mouse**](https://github.com/feschber/lan-mouse) -
|
||||
Rust implementation with the goal of having native front-ends and interoperability with
|
||||
Deskflow/Synergy.
|
||||
* [**Input Leap**](https://github.com/input-leap/input-leap) -
|
||||
- [**Input Leap**](https://github.com/input-leap/input-leap) -
|
||||
Deskflow/Synergy-derivative with the goal of continuing what Barrier started, after Barrier
|
||||
became a dead fork.
|
||||
* [**Synergy**](https://github.com/deskflow/deskflow/wiki/Relationship-with-Synergy) -
|
||||
Downstream commercial fork and Deskflow sponsor, geared toward adapting to customer
|
||||
needs, offering business and enterprise licensing.
|
||||
- [**Synergy**](https://symless.com/synergy) -
|
||||
Downstream commercial fork. Synergy sponsors Deskflow with financial support and contributes code ([learn more](https://github.com/deskflow/deskflow/wiki/Relationship-with-Synergy)).
|
||||
|
||||
## FAQ
|
||||
|
||||
### What is the relationship with Synergy?
|
||||
|
||||
[](https://github.com/deskflow/deskflow/wiki/Relationship-with-Synergy)
|
||||
|
||||
Synergy sponsors the Deskflow project by contributing code and providing financial support while maintaining its customer-oriented code downstream.
|
||||
|
||||
Learn more: [Relationship with Synergy](https://github.com/deskflow/deskflow/wiki/Relationship-with-Synergy)
|
||||
|
||||
### Is Deskflow compatible with Synergy, Input Leap, or Barrier?
|
||||
|
||||
Yes, Deskflow has network compatibility with all forks:
|
||||
|
||||
- Requires Deskflow >= v1.17.0.96
|
||||
- Deskflow will *just work* with Input Leap and Barrier (server or client).
|
||||
- Connecting a Deskflow client to a Synergy 1 server will also *just work*.
|
||||
- Deskflow will _just work_ with Input Leap and Barrier (server or client).
|
||||
- Connecting a Deskflow client to a Synergy 1 server will also _just work_.
|
||||
- To connect a Synergy 1 client, you need to select the Synergy protocol in the Deskflow server settings.
|
||||
|
||||
_Note:_ Only Synergy 1 is compatible with Deskflow (Synergy 3 is not yet compatible).
|
||||
@ -153,20 +129,20 @@ We would love to see compatibility with Lan Mouse. This may be quite an effort a
|
||||
### If I want to solve issues in Deskflow do I need to contribute to a fork?
|
||||
|
||||
We welcome PRs (pull requests) from the community. If you'd like to make a change, please feel
|
||||
free to [start a discussion](https://github.com/deskflow/deskflow/discussions) or
|
||||
free to [start a discussion](https://github.com/deskflow/deskflow/discussions) or
|
||||
[open a PR](https://github.com/deskflow/deskflow/wiki/Contributing).
|
||||
|
||||
### Is clipboard sharing supported?
|
||||
|
||||
Absolutely. The clipboard-sharing feature is a cornerstone feature of the product and we are
|
||||
Absolutely. The clipboard-sharing feature is a cornerstone feature of the product and we are
|
||||
committed to maintaining and improving that feature.
|
||||
|
||||
### Is Wayland for Linux supported?
|
||||
|
||||
Yes! Wayland (the Linux display server protocol aimed to become the successor of the X Window
|
||||
Yes! Wayland (the Linux display server protocol aimed to become the successor of the X Window
|
||||
System) is an important platform for us.
|
||||
The [`libei`](https://gitlab.freedesktop.org/libinput/libei) and
|
||||
[`libportal`](https://github.com/flatpak/libportal) libraries enable
|
||||
The [`libei`](https://gitlab.freedesktop.org/libinput/libei) and
|
||||
[`libportal`](https://github.com/flatpak/libportal) libraries enable
|
||||
Wayland support for Deskflow. We would like to give special thanks to Peter Hutterer,
|
||||
who is the author of `libei`, a major contributor to `libportal`, and the author of the Wayland
|
||||
implementation in Deskflow. Others such as Olivier Fourdan and Povilas Kanapickas helped with the
|
||||
@ -184,9 +160,12 @@ wiki.
|
||||
|
||||

|
||||
|
||||
|
||||
## Deskflow Contributors
|
||||
|
||||
[](https://symless.com/synergy)
|
||||
|
||||
[Synergy](https://symless.com/synergy) sponsors the Deskflow project by contributing code and providing financial support ([learn more](https://github.com/deskflow/deskflow/wiki/Relationship-with-Synergy)).
|
||||
|
||||
Deskflow is made by possible by these contributors.
|
||||
|
||||
<a href = "https://github.com/deskflow/deskflow/graphs/contributors">
|
||||
|
||||
18
REUSE.toml
18
REUSE.toml
@ -43,13 +43,7 @@ SPDX-FileCopyrightText = "Deskflow Developers"
|
||||
SPDX-License-Identifier = "MIT"
|
||||
|
||||
[[annotations]]
|
||||
path = "README.md"
|
||||
precedence = "override"
|
||||
SPDX-FileCopyrightText = "Deskflow Developers"
|
||||
SPDX-License-Identifier = "MIT"
|
||||
|
||||
[[annotations]]
|
||||
path = "SECURITY.md"
|
||||
path = "**/*.md"
|
||||
precedence = "override"
|
||||
SPDX-FileCopyrightText = "Deskflow Developers"
|
||||
SPDX-License-Identifier = "MIT"
|
||||
@ -145,6 +139,12 @@ precedence = "override"
|
||||
SPDX-FileCopyrightText = "Deskflow Developers"
|
||||
SPDX-License-Identifier = "MIT"
|
||||
|
||||
[[annotations]]
|
||||
path = "src/apps/res/manpage.txt"
|
||||
precedence = "override"
|
||||
SPDX-FileCopyrightText = "Deskflow Developers"
|
||||
SPDX-License-Identifier = "MIT"
|
||||
|
||||
[[annotations]]
|
||||
path = "src/apps/res/icons/deskflow-**/**/**/**.svg"
|
||||
precedence = "override"
|
||||
@ -194,13 +194,13 @@ SPDX-FileCopyrightText = "Chris Rizzitello <sithlord48@gmail.com>"
|
||||
SPDX-License-Identifier = "LGPL-2.1-only"
|
||||
|
||||
[[annotations]]
|
||||
path = "src/apps/deskflow-gui/MainWindow.ui"
|
||||
path = "src/lib/gui/MainWindow.ui"
|
||||
precedence = "override"
|
||||
SPDX-FileCopyrightText = "Deskflow Developers"
|
||||
SPDX-License-Identifier = "GPL-2.0-only WITH LicenseRef-OpenSSL-Exception"
|
||||
|
||||
[[annotations]]
|
||||
path = "src/apps/deskflow-gui/dialogs/*.ui"
|
||||
path = "src/lib/gui/dialogs/*.ui"
|
||||
precedence = "override"
|
||||
SPDX-FileCopyrightText = "Deskflow Developers"
|
||||
SPDX-License-Identifier = "GPL-2.0-only WITH LicenseRef-OpenSSL-Exception"
|
||||
|
||||
@ -21,7 +21,7 @@ macro(configure_libs)
|
||||
|
||||
find_package(Qt6 ${REQUIRED_QT_VERSION} REQUIRED COMPONENTS Core Widgets Network)
|
||||
if(UNIX AND NOT APPLE)
|
||||
find_package(Qt6 ${REQUIRED_QT_VERSION} REQUIRED COMPONENTS DBus)
|
||||
find_package(Qt6 ${REQUIRED_QT_VERSION} REQUIRED COMPONENTS DBus Xml)
|
||||
endif()
|
||||
|
||||
# Define the location of Qt deployment tool
|
||||
@ -46,7 +46,7 @@ macro(configure_libs)
|
||||
message(STATUS "Enabling code coverage")
|
||||
include(cmake/CodeCoverage.cmake)
|
||||
append_coverage_compiler_flags()
|
||||
set(test_exclude subprojects/* build/* src/test/*)
|
||||
set(test_exclude subprojects/* build/* src/unittests/*)
|
||||
set(test_src ${PROJECT_SOURCE_DIR}/src)
|
||||
|
||||
# Apparently solves the bug in gcov where it returns negative counts and confuses gcovr.
|
||||
@ -55,15 +55,8 @@ macro(configure_libs)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-update=atomic")
|
||||
|
||||
setup_target_for_coverage_gcovr_xml(
|
||||
NAME coverage-integtests
|
||||
EXECUTABLE integtests
|
||||
BASE_DIRECTORY ${test_src}
|
||||
EXCLUDE ${test_exclude}
|
||||
)
|
||||
|
||||
setup_target_for_coverage_gcovr_xml(
|
||||
NAME coverage-unittests
|
||||
EXECUTABLE unittests
|
||||
NAME coverage-legacytests
|
||||
EXECUTABLE legacytests
|
||||
BASE_DIRECTORY ${test_src}
|
||||
EXCLUDE ${test_exclude}
|
||||
)
|
||||
@ -89,20 +82,11 @@ macro(configure_unix_libs)
|
||||
include(CheckSymbolExists)
|
||||
include(CheckCSourceCompiles)
|
||||
|
||||
check_include_file_cxx(istream HAVE_ISTREAM)
|
||||
check_include_file_cxx(ostream HAVE_OSTREAM)
|
||||
check_include_file_cxx(sstream HAVE_SSTREAM)
|
||||
|
||||
check_include_files(locale.h HAVE_LOCALE_H)
|
||||
check_include_files(sys/select.h HAVE_SYS_SELECT_H)
|
||||
check_include_files(sys/socket.h HAVE_SYS_SOCKET_H)
|
||||
check_include_files(sys/time.h HAVE_SYS_TIME_H)
|
||||
check_include_files(sys/utsname.h HAVE_SYS_UTSNAME_H)
|
||||
check_include_files(unistd.h HAVE_UNISTD_H)
|
||||
check_include_files(wchar.h HAVE_WCHAR_H)
|
||||
|
||||
check_function_exists(getpwuid_r HAVE_GETPWUID_R)
|
||||
check_function_exists(gmtime_r HAVE_GMTIME_R)
|
||||
check_function_exists(nanosleep HAVE_NANOSLEEP)
|
||||
check_function_exists(sigwait HAVE_POSIX_SIGWAIT)
|
||||
check_function_exists(inet_aton HAVE_INET_ATON)
|
||||
@ -158,34 +142,16 @@ macro(configure_unix_libs)
|
||||
configure_xorg_libs()
|
||||
|
||||
include(FindPkgConfig)
|
||||
|
||||
find_package(PkgConfig)
|
||||
if(PKG_CONFIG_FOUND)
|
||||
pkg_check_modules(LIBXKBCOMMON REQUIRED xkbcommon)
|
||||
pkg_check_modules(GLIB2 REQUIRED glib-2.0 gio-2.0)
|
||||
pkg_check_modules(GLIB2 REQUIRED glib-2.0)
|
||||
find_library(LIBM m)
|
||||
include_directories(${LIBXKBCOMMON_INCLUDE_DIRS} ${GLIB2_INCLUDE_DIRS}
|
||||
${LIBM_INCLUDE_DIRS})
|
||||
else()
|
||||
message(WARNING "pkg-config not found, skipping wayland libraries")
|
||||
endif()
|
||||
|
||||
|
||||
find_package(pugixml REQUIRED)
|
||||
|
||||
find_package(PkgConfig)
|
||||
if(PKG_CONFIG_FOUND)
|
||||
pkg_check_modules(lib_glib REQUIRED IMPORTED_TARGET glib-2.0)
|
||||
pkg_search_module(PC_GDKPIXBUF gdk-pixbuf-2.0)
|
||||
|
||||
include_directories(${PC_GDKPIXBUF_INCLUDE_DIRS})
|
||||
|
||||
pkg_check_modules(lib_gdkpixbuf REQUIRED IMPORTED_TARGET gdk-pixbuf-2.0)
|
||||
pkg_check_modules(lib_notify REQUIRED IMPORTED_TARGET libnotify)
|
||||
|
||||
add_definitions(-DHAVE_GDK_PIXBUF=1 -DHAVE_LIBNOTIFY=1)
|
||||
else()
|
||||
message(WARNING "pkg-config not found, skipping libnotify and gdk-pixbuf")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# For config.h, set some static values; it may be a good idea to make these
|
||||
@ -200,8 +166,8 @@ macro(configure_unix_libs)
|
||||
# Unix only: For config.h, save the results based on a template (config.h.in).
|
||||
# Note that this won't work on Windows because filenames are not case sensitive,
|
||||
# and we have header files named "Config.h" (upper case 'C').
|
||||
configure_file(${CMAKE_SOURCE_DIR}/src/lib/config.h.in
|
||||
${CMAKE_BINARY_DIR}/src/lib/config.h @ONLY)
|
||||
configure_file(${CMAKE_SOURCE_DIR}/src/lib/Config.h.in
|
||||
${CMAKE_BINARY_DIR}/src/lib/Config.h @ONLY)
|
||||
|
||||
add_definitions(-DSYSAPI_UNIX=1 -DHAVE_CONFIG_H)
|
||||
|
||||
|
||||
@ -26,6 +26,7 @@
|
||||
"Hadzhylov",
|
||||
"Hetu",
|
||||
"HINSTANCE",
|
||||
"HKLM",
|
||||
"hotspots",
|
||||
"Hutterer",
|
||||
"ifdef",
|
||||
@ -65,6 +66,7 @@
|
||||
"qobject",
|
||||
"qputenv",
|
||||
"readf",
|
||||
"Redist",
|
||||
"Regen",
|
||||
"Repology",
|
||||
"Rizzitello",
|
||||
|
||||
@ -12,26 +12,30 @@ license=(LicenseRef-GPL-2.0-only-WITH-OpenSSL-Exception)
|
||||
conflicts=('synergy-git' 'synergy-1.6' 'synergy1-bin' 'synergy2-bin' 'synergy3-bin' 'synergy3-beta-bin' 'synergy3-stable-bin' 'barrier' 'barrier-git' 'barrier-headless' 'barrier-headless-git' 'input-leap' 'input-leap-git' 'input-leap-headless-git' 'input-leap-headless' 'waynergy' 'waynergy-git' 'qsynergy' 'slim-synergy' 'quicksynergy' 'deskflow')
|
||||
provides=("deskflow-git${pkgver}")
|
||||
depends=(
|
||||
'gcc-libs'
|
||||
'glibc'
|
||||
'openssl'
|
||||
'libx11'
|
||||
'libxi'
|
||||
'libxkbfile'
|
||||
'libxext'
|
||||
'libxtst'
|
||||
'libxinerama'
|
||||
'libxkbcommon-x11'
|
||||
'libnotify'
|
||||
'hicolor-icon-theme'
|
||||
'pugixml'
|
||||
'qt6-base'
|
||||
'qt6-tools'
|
||||
'libei'
|
||||
'libportal'
|
||||
'tomlplusplus'
|
||||
'cli11'
|
||||
gcc-libs
|
||||
glib2
|
||||
glibc
|
||||
hicolor-icon-theme
|
||||
libei
|
||||
libglvnd
|
||||
libice
|
||||
libportal
|
||||
libsm
|
||||
libx11
|
||||
libxext
|
||||
libxi
|
||||
libxinerama
|
||||
libxkbcommon
|
||||
libxkbcommon-x11
|
||||
libxkbfile
|
||||
libxrandr
|
||||
libxtst
|
||||
openssl
|
||||
qt6-base
|
||||
qt6-svg
|
||||
tomlplusplus
|
||||
)
|
||||
|
||||
options=('!debug')
|
||||
|
||||
package() {
|
||||
|
||||
@ -100,9 +100,9 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
||||
if("${DISTRO_NAME}" STREQUAL "")
|
||||
set(DISTRO_NAME "linux")
|
||||
endif()
|
||||
set(OS_STRING "${DISTRO_NAME}-${CN_STRING}${CMAKE_SYSTEM_PROCESSOR}")
|
||||
set(OS_STRING "${DISTRO_NAME}-${CN_STRING}${BUILD_ARCHITECTURE}")
|
||||
|
||||
elseif(${CMAKE_SYSTEM_NAME} MATCHES "|.*BSD")
|
||||
message(STATUS "BSD packaging not yet supported")
|
||||
set(OS_STRING ${CMAKE_SYSTEM_NAME}-${CMAKE_SYSTEM_PROCESSOR})
|
||||
set(OS_STRING ${CMAKE_SYSTEM_NAME}-${BUILD_ARCHITECTURE})
|
||||
endif()
|
||||
|
||||
41
deploy/linux/flatpak/libportal-qt69.patch
Normal file
41
deploy/linux/flatpak/libportal-qt69.patch
Normal file
@ -0,0 +1,41 @@
|
||||
From 796053d2eebe4532aad6bd3fd80cdf3b197806ec Mon Sep 17 00:00:00 2001
|
||||
From: Jan Grulich <jgrulich@redhat.com>
|
||||
Date: Thu, 27 Mar 2025 09:38:10 +0100
|
||||
Subject: [PATCH] qt6: fix build against Qt 6.9+
|
||||
|
||||
QGenericUnixServices was renamed to QDesktopUnixServices in Qt 6.9.
|
||||
|
||||
Upstream change: https://codereview.qt-project.org/c/qt/qtbase/+/609639
|
||||
---
|
||||
libportal/portal-qt6.cpp | 8 ++++++++
|
||||
1 file changed, 8 insertions(+)
|
||||
|
||||
diff --git a/libportal/portal-qt6.cpp b/libportal/portal-qt6.cpp
|
||||
index d38a4e30..34f0d72a 100644
|
||||
--- a/libportal/portal-qt6.cpp
|
||||
+++ b/libportal/portal-qt6.cpp
|
||||
@@ -31,8 +31,12 @@
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)
|
||||
#include <qpa/qplatformintegration.h>
|
||||
#include <private/qguiapplication_p.h>
|
||||
+#if QT_VERSION >= QT_VERSION_CHECK(6, 9, 0)
|
||||
+#include <private/qdesktopunixservices_p.h>
|
||||
+#else
|
||||
#include <private/qgenericunixservices_p.h>
|
||||
#endif
|
||||
+#endif
|
||||
|
||||
static gboolean
|
||||
_xdp_parent_export_qt (XdpParent *parent,
|
||||
@@ -45,7 +49,11 @@ _xdp_parent_export_qt (XdpParent *parent,
|
||||
}
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)
|
||||
+#if QT_VERSION >= QT_VERSION_CHECK(6, 9, 0)
|
||||
+ if (const auto services = dynamic_cast<QDesktopUnixServices*>(QGuiApplicationPrivate::platformIntegration()->services()))
|
||||
+#else
|
||||
if (const auto services = dynamic_cast<QGenericUnixServices*>(QGuiApplicationPrivate::platformIntegration()->services()))
|
||||
+#endif
|
||||
{
|
||||
g_autofree char *handle = g_strdup(services->portalWindowIdentifier(w).toUtf8().constData());
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
app-id: org.deskflow.deskflow
|
||||
runtime: org.kde.Platform
|
||||
runtime-version: "6.8"
|
||||
runtime-version: "6.9"
|
||||
sdk: org.kde.Sdk
|
||||
command: deskflow
|
||||
finish-args:
|
||||
@ -23,17 +23,6 @@ cleanup:
|
||||
- /share/gir-1.0
|
||||
- /lib/girepository-1.0
|
||||
modules:
|
||||
- name: python3-attrs
|
||||
buildsystem: simple
|
||||
build-commands:
|
||||
- pip3 install --verbose --exists-action=i --no-index --find-links="file://${PWD}"
|
||||
--prefix=${FLATPAK_DEST} --no-build-isolation attrs
|
||||
sources:
|
||||
- type: file
|
||||
url: https://files.pythonhosted.org/packages/e0/44/827b2a91a5816512fcaf3cc4ebc465ccd5d598c45cefa6703fcf4a79018f/attrs-23.2.0-py3-none-any.whl
|
||||
sha256: 99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1
|
||||
cleanup:
|
||||
- '*'
|
||||
- name: python3-Jinja2
|
||||
buildsystem: simple
|
||||
build-commands:
|
||||
@ -57,8 +46,8 @@ modules:
|
||||
sources:
|
||||
- type: git
|
||||
url: https://gitlab.freedesktop.org/libinput/libei
|
||||
tag: 1.3.0
|
||||
commit: 997b7c0f37faea4f8bae59613c8f27370925d5b0
|
||||
tag: 1.4.1
|
||||
commit: 9e0413cbc7d3ae6656266890425f152589ddf74d
|
||||
- name: libportal
|
||||
buildsystem: meson
|
||||
config-opts:
|
||||
@ -70,15 +59,10 @@ modules:
|
||||
sources:
|
||||
- type: git
|
||||
url: https://github.com/flatpak/libportal.git
|
||||
tag: 0.8.1
|
||||
commit: 26c15008cbe579f57f89468384f8efc033f25f6f
|
||||
- name: puixml
|
||||
buildsystem: cmake-ninja
|
||||
sources:
|
||||
- type: git
|
||||
url: https://github.com/zeux/pugixml
|
||||
tag: v1.14
|
||||
commit: db78afc2b7d8f043b4bc6b185635d949ea2ed2a8
|
||||
tag: 0.9.1
|
||||
commit: 8f5dc8d192f6e31dafe69e35219e3b707bde71ce
|
||||
- type: patch
|
||||
path: libportal-qt69.patch
|
||||
- name: cli11
|
||||
buildsystem: cmake-ninja
|
||||
config-opts:
|
||||
@ -86,8 +70,8 @@ modules:
|
||||
sources:
|
||||
- type: git
|
||||
url: https://github.com/CLIUtils/CLI11
|
||||
tag: v2.4.2
|
||||
commit: 6c7b07a878ad834957b98d0f9ce1dbe0cb204fc9
|
||||
tag: v2.5.0
|
||||
commit: 4160d259d961cd393fd8d67590a8c7d210207348
|
||||
- name: tomlplusplus
|
||||
buildsystem: cmake-ninja
|
||||
sources:
|
||||
|
||||
@ -42,6 +42,67 @@
|
||||
</branding>
|
||||
<content_rating type="oars-1.0" />
|
||||
<releases>
|
||||
<release version="1.22.0" date="2025-05-28" urgency="high">
|
||||
<description>
|
||||
<p>This stable release fixes a issues found in the previous version. For the full changelog see the release page.</p>
|
||||
<ul>
|
||||
<li>Remove: Broken drag and drop file transfer support</li>
|
||||
<li>Remove: DESKFLOW_RESET_ALL and --no-reset. reset settings is now done by passing the --reset option instead</li>
|
||||
<li>Continue migration to Qt by using more Qt classes in more places</li>
|
||||
<li>Retire SHA1 generation and use SHA256 always to compare</li>
|
||||
<li>Add missing accelerators for gui controls</li>
|
||||
<li>unittests binary is now legacytests</li>
|
||||
<li>integtests have been remove and replaced with Qt based tests run during build</li>
|
||||
<li>Fix: Potential XDG-Portal release issue</li>
|
||||
<li>Fix: Issue where the first start dialog could hang in the background</li>
|
||||
<li>Fix: Edge cases that could cause incorrect settings causing client / server process to crash</li>
|
||||
<li>Fix: Default server config file is Deskflow-server.conf</li>
|
||||
<li>Backport: Event Types from downstream</li>
|
||||
<li>Backport: Cleaner error handling from downstream</li>
|
||||
<li>Improve Windows Daemon</li>
|
||||
<li>Better detection of arm on windows, in build and installer</li>
|
||||
<li>Chore: Clean up sonar scan code smells</li>
|
||||
</ul>
|
||||
</description>
|
||||
<url>https://github.com/deskflow/deskflow/releases/tag/v1.22.0</url>
|
||||
</release>/
|
||||
<release version="1.21.2" date="2025-04-07" urgency="high">
|
||||
<description>
|
||||
<p>This stable release fixes a few critical bugs in 1.21.1. For the full changelog see the release page.</p>
|
||||
<ul>
|
||||
<li>Fix: Crash with Qt 6.9</li>
|
||||
<li>Fix: Windows settings in wrong locations</li>
|
||||
</ul>
|
||||
</description>
|
||||
<url>https://github.com/deskflow/deskflow/releases/tag/v1.21.2</url>
|
||||
</release>
|
||||
<release version="1.21.1" date="2025-03-31" urgency="high">
|
||||
<description>
|
||||
<p>This stable release fixes a few critical bugs in 1.21.0. For the full changelog see the release page.</p>
|
||||
<ul>
|
||||
<li>Fix: Flatpak can't save settings'</li>
|
||||
<li>Fix: Crash on localfingerprint dialog</li>
|
||||
<li>Fix: Check for updates settings reading from wrong value</li>
|
||||
<li>Fix: Windows settings saving blocked for non admin users </li>
|
||||
</ul>
|
||||
</description>
|
||||
<url>https://github.com/deskflow/deskflow/releases/tag/v1.21.1</url>
|
||||
</release>
|
||||
<release version="1.21.0" date="2025-03-27" urgency="high">
|
||||
<description>
|
||||
<p>This stable release removes some dependencies, additionally fixes several bugs. For the full changelog see the release page.</p>
|
||||
<ul>
|
||||
<li>Cleanup unused classes</li>
|
||||
<li>New Settings class</li>
|
||||
<li>Remove need for pugixml</li>
|
||||
<li>Remove need for libNotify</li>
|
||||
<li>Remove need for gio</li>
|
||||
<li>Remove need for gitkpixbuf</li>
|
||||
<li>Fix issues with windows installer when msvc is missing</li>
|
||||
</ul>
|
||||
</description>
|
||||
<url>https://github.com/deskflow/deskflow/releases/tag/v1.21.0</url>
|
||||
</release>
|
||||
<release version="1.20.1" date="2025-03-07" urgency="low">
|
||||
<description>
|
||||
<p>This stable release introduces a Windows dependency requirement and fixes a macOS bug.</p>
|
||||
|
||||
@ -11,7 +11,7 @@ install(CODE "execute_process(COMMAND
|
||||
-timestamp -codesign=-
|
||||
)")
|
||||
|
||||
set(OS_STRING "macos-${CMAKE_SYSTEM_PROCESSOR}")
|
||||
set(OS_STRING "macos-${BUILD_ARCHITECTURE}")
|
||||
set(CPACK_PACKAGE_ICON "${MY_DIR}/dmg-volume.icns")
|
||||
set(CPACK_DMG_BACKGROUND_IMAGE "${MY_DIR}/dmg-background.tiff")
|
||||
set(CPACK_DMG_DS_STORE_SETUP_SCRIPT "${MY_DIR}/generate_ds_store.applescript")
|
||||
|
||||
6
deploy/windows/cpack-options.cmake.in
Normal file
6
deploy/windows/cpack-options.cmake.in
Normal file
@ -0,0 +1,6 @@
|
||||
#SPDX-FileCopyrightText: 2025 Chris Rizzitello <sithlord48@gmail.com>
|
||||
#SPDX-License-Identifier: MIT
|
||||
|
||||
if(CPACK_GENERATOR MATCHES 7Z|ZIP)
|
||||
set(CPACK_PACKAGE_FILE_NAME ${CPACK_PACKAGE_FILE_NAME}-portable)
|
||||
endif()
|
||||
@ -5,18 +5,23 @@
|
||||
# calling CMAKE_CURRENT_LIST_DIR after include would return the wrong scope var
|
||||
set(MY_DIR ${CMAKE_CURRENT_LIST_DIR})
|
||||
|
||||
set(CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_SKIP TRUE)
|
||||
set(CMAKE_INSTALL_SYSTEM_RUNTIME_DESTINATION .)
|
||||
include(InstallRequiredSystemLibraries)
|
||||
|
||||
install(CODE "execute_process(
|
||||
COMMAND ${DEPLOYQT} --no-compiler-runtime --no-system-d3d-compiler --no-quick-import -network \"\${CMAKE_INSTALL_PREFIX}/deskflow.exe\"
|
||||
)")
|
||||
|
||||
# Setup OS_STRING
|
||||
if(CMAKE_SYSTEM_PROCESSOR MATCHES AMD64)
|
||||
set(OS_STRING "win-x64")
|
||||
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES ARM64)
|
||||
set(OS_STRING "win-arm64")
|
||||
else()
|
||||
set(OS_STRING "win-${CMAKE_SYSTEM_PROCESSOR}")
|
||||
endif()
|
||||
configure_file(${MY_DIR}/pre-cpack.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/pre-cpack.cmake @ONLY)
|
||||
set(CPACK_PRE_BUILD_SCRIPTS ${CMAKE_CURRENT_BINARY_DIR}/pre-cpack.cmake)
|
||||
|
||||
configure_file(${MY_DIR}/cpack-options.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/cpack-options.cmake @ONLY)
|
||||
set(CPACK_PROJECT_CONFIG_FILE ${CMAKE_CURRENT_BINARY_DIR}/cpack-options.cmake)
|
||||
|
||||
set(OS_STRING "win-${BUILD_ARCHITECTURE}")
|
||||
|
||||
list(APPEND CPACK_GENERATOR "7Z")
|
||||
|
||||
# If Wix4+ is installed make a package
|
||||
find_program(WIX_APP wix)
|
||||
@ -53,3 +58,18 @@ configure_file(
|
||||
|
||||
# This patch set ups filewall rules, the service and msm module
|
||||
set(CPACK_WIX_PATCH_FILE "${CMAKE_CURRENT_BINARY_DIR}/wix-patch.xml")
|
||||
|
||||
# Creates a DLL that can be used by our MSI for custom actions.
|
||||
configure_file(
|
||||
${MY_DIR}/wix-custom.h.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/wix-custom.h @ONLY
|
||||
)
|
||||
add_library(
|
||||
wix-custom SHARED
|
||||
${MY_DIR}/wix-custom.cpp
|
||||
)
|
||||
target_include_directories(wix-custom PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
|
||||
set_target_properties(wix-custom PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
|
||||
)
|
||||
target_link_libraries(wix-custom PRIVATE Msi)
|
||||
|
||||
19
deploy/windows/pre-cpack.cmake.in
Normal file
19
deploy/windows/pre-cpack.cmake.in
Normal file
@ -0,0 +1,19 @@
|
||||
# SPDX-FileCopyrightText: 2025 Chris Rizzitello <sithlord48@gmail.com>
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
if(CPACK_GENERATOR MATCHES 7Z|ZIP)
|
||||
string(REPLACE " " "*" _TEMP_LIST "@CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS@")
|
||||
set(${PORTABLE_LIBS} "")
|
||||
foreach(ITEM ${_TEMP_LIST})
|
||||
string(REPLACE "*" " " _ITEM ${ITEM})
|
||||
file(COPY ${_ITEM} DESTINATION ${CPACK_TEMPORARY_INSTALL_DIRECTORY})
|
||||
endforeach()
|
||||
file(WRITE ${CPACK_TEMPORARY_INSTALL_DIRECTORY}/settings/Deskflow.conf " ")
|
||||
file(REMOVE ${CPACK_TEMPORARY_INSTALL_DIRECTORY}/deskflow-daemon.exe)
|
||||
file(WRITE ${CPACK_TEMPORARY_INSTALL_DIRECTORY}/README.txt
|
||||
" Portable Deskflow: @CMAKE_PROJECT_VERSION@
|
||||
|
||||
The portable version must have the settings/Deskflow.conf file to save settings, or it will try to use the system settings location.
|
||||
The portable version does not include the daemon, so the client will not work at UAC prompts or the login screen.
|
||||
")
|
||||
endif()
|
||||
72
deploy/windows/wix-custom.cpp
Normal file
72
deploy/windows/wix-custom.cpp
Normal file
@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Deskflow -- mouse and keyboard sharing utility
|
||||
* SPDX-FileCopyrightText: (C) 2025 Symless Ltd.
|
||||
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
|
||||
*/
|
||||
|
||||
#include "wix-custom.h"
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <Windows.h>
|
||||
|
||||
// Include after Windows.h
|
||||
#include <MsiQuery.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
|
||||
namespace {
|
||||
// Warning: DLL will crash with error code 1603 if we exceed this.
|
||||
const auto kLogLineMax = 1024;
|
||||
|
||||
// Prefixes log messages with the app name so they're easier to find/filter.
|
||||
const std::string kLogPrefix = std::string(kAppId) + " installer: ";
|
||||
|
||||
// Note: Resized to log line max when used.
|
||||
static std::string s_logMessageBuffer; // NOSONAR - Must be mutable.
|
||||
} // namespace
|
||||
|
||||
// This log output can be viewed by using the DebugView program.
|
||||
#define MS_LOG_DEBUG(message, ...) \
|
||||
s_logMessageBuffer.resize(kLogLineMax); \
|
||||
sprintf(s_logMessageBuffer.data(), message, __VA_ARGS__); \
|
||||
OutputDebugStringA((kLogPrefix + s_logMessageBuffer + "\n").c_str())
|
||||
|
||||
extern "C" __declspec(dllexport) UINT __stdcall CheckVCRedist(MSIHANDLE hInstall)
|
||||
{
|
||||
const auto kKeyName = TEXT(kRegKey);
|
||||
const auto kValueName = TEXT("Minor");
|
||||
const auto kProperty = "VC_REDIST_VERSION_OK";
|
||||
|
||||
MS_LOG_DEBUG("checking for msvc redist v%d.%d", kWindowsRuntimeMajor, kWindowsRuntimeMinor);
|
||||
|
||||
HKEY hKey;
|
||||
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, kKeyName, 0, KEY_READ, &hKey) != ERROR_SUCCESS) {
|
||||
MS_LOG_DEBUG("msvc redist registry key not found");
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
}
|
||||
|
||||
MS_LOG_DEBUG("msvc redist registry key found, querying minor version");
|
||||
|
||||
DWORD minorVersion = 0;
|
||||
DWORD size = sizeof(DWORD);
|
||||
RegQueryValueEx(hKey, kValueName, nullptr, nullptr, (LPBYTE)&minorVersion, &size);
|
||||
RegCloseKey(hKey);
|
||||
|
||||
MS_LOG_DEBUG("msvc redist minor version: %lu", minorVersion);
|
||||
|
||||
if (minorVersion < kWindowsRuntimeMinor) {
|
||||
MS_LOG_DEBUG("msvc redist minor version %lu too low, expected >= %d", minorVersion, kWindowsRuntimeMinor);
|
||||
// Returning success allows the installer will show a friendly error message.
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
MS_LOG_DEBUG("msvc redist version ok, setting: %s", kProperty);
|
||||
if (MsiSetProperty(hInstall, kProperty, "ok") != ERROR_SUCCESS) {
|
||||
MS_LOG_DEBUG("failed to set property: %s", kProperty);
|
||||
return ERROR_FUNCTION_FAILED;
|
||||
}
|
||||
|
||||
MS_LOG_DEBUG("msvc redist version check successful");
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
15
deploy/windows/wix-custom.h.in
Normal file
15
deploy/windows/wix-custom.h.in
Normal file
@ -0,0 +1,15 @@
|
||||
/*
|
||||
* Deskflow -- mouse and keyboard sharing utility
|
||||
* SPDX-FileCopyrightText: (C) 2025 Symless Ltd.
|
||||
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
const auto kAppId = "@CMAKE_PROJECT_NAME@";
|
||||
const auto kRegKey = "SOFTWARE\\Microsoft\\VisualStudio\\14.0\\VC\\Runtimes\\@BUILD_ARCHITECTURE@";
|
||||
|
||||
// clang-format off
|
||||
const auto kWindowsRuntimeMajor = @REQUIRED_MSVC_RUNTIME_MAJOR@;
|
||||
const auto kWindowsRuntimeMinor = @REQUIRED_MSVC_RUNTIME_MINOR@;
|
||||
// clang-format on
|
||||
@ -32,20 +32,47 @@
|
||||
<RegistrySearch
|
||||
Id="FindVCRedist"
|
||||
Root="HKLM"
|
||||
Key="SOFTWARE\Microsoft\VisualStudio\14.0\VC\Runtimes\x64"
|
||||
Key="SOFTWARE\Microsoft\VisualStudio\@REQUIRED_MSVC_RUNTIME_MAJOR@.0\VC\Runtimes\@BUILD_ARCHITECTURE@"
|
||||
Name="Installed"
|
||||
Type="raw" />
|
||||
</Property>
|
||||
|
||||
<CustomAction Id="Run_Deskflow" ExeCommand="Deskflow" FileRef="CM_FP_deskflow.exe" Return="asyncNoWait"/>
|
||||
|
||||
<Binary Id="CustomDLL" SourceFile="@CMAKE_CURRENT_BINARY_DIR@/wix-custom.dll" />
|
||||
|
||||
<UI>
|
||||
<Publish Dialog="ExitDialog"
|
||||
Control="Finish"
|
||||
Event="DoAction"
|
||||
Value="RunDeskflow"
|
||||
Condition= "NOT Installed" />
|
||||
</UI>
|
||||
<CustomAction
|
||||
Id="CheckVCRedist"
|
||||
BinaryRef="CustomDLL"
|
||||
DllEntry="CheckVCRedist"
|
||||
Execute="immediate" />
|
||||
|
||||
<CustomAction
|
||||
Id="ShowVCRedistError"
|
||||
Error="Latest Microsoft Visual C++ Redistributable is required. Please install it before proceeding."/>
|
||||
Error="Microsoft Visual C++ Redistributable v@REQUIRED_MSVC_RUNTIME_MAJOR@.@REQUIRED_MSVC_RUNTIME_MINOR@ or later is required. Please download and install the latest version and then restart the installation. See our documentation for instructions." />
|
||||
|
||||
<CustomAction
|
||||
Id="RunDeskflow"
|
||||
ExeCommand="[INSTALL_ROOT]deskflow.exe"
|
||||
Directory="INSTALL_ROOT"
|
||||
Execute="immediate"
|
||||
Impersonate="yes"
|
||||
Return="asyncNoWait" />
|
||||
|
||||
<InstallExecuteSequence>
|
||||
<Custom Action="ShowVCRedistError" Before="InstallServices" Condition="NOT Installed AND NOT VC_REDIST_INSTALLED"/>
|
||||
<Custom Action="Run_Deskflow" OnExit="success" Condition="NOT Installed"/>
|
||||
<Custom
|
||||
Action="CheckVCRedist"
|
||||
Before="InstallInitialize"
|
||||
Condition="NOT Installed AND VC_REDIST_INSTALLED" />
|
||||
<Custom
|
||||
Action="ShowVCRedistError"
|
||||
Before="InstallInitialize"
|
||||
Condition="NOT Installed AND (NOT VC_REDIST_INSTALLED OR NOT VC_REDIST_VERSION_OK)" />
|
||||
</InstallExecuteSequence>
|
||||
</CPackWiXFragment>
|
||||
</CPackWiXPatch>
|
||||
|
||||
@ -1,3 +1,36 @@
|
||||
# GUI Config
|
||||
|
||||
Deskflow will automaticlly figure out where to save settings and other files.
|
||||
|
||||
|
||||
## Unix Systems
|
||||
The search order for a setting file is:
|
||||
1. `<XDG_CONFIG_HOME>/Deskflow/Deskflow.conf`
|
||||
1. A user settings file
|
||||
1. A system settings file
|
||||
|
||||
A new settings file will be created in the user path if no settings file is found.
|
||||
The path of the settings file will be used as the base for all other config files.
|
||||
|
||||
### Linux
|
||||
- System: `/etc/Deskflow/Deskflow.conf`
|
||||
- User: `~/.config/Deskflow/Deskflow.conf`
|
||||
|
||||
### macOS
|
||||
- System: `/Library/Deskflow/Deskflow.conf`
|
||||
- User: `~/Library/Deskflow/Deskflow.conf`
|
||||
|
||||
|
||||
## Windows
|
||||
|
||||
The search order for a setting file is:
|
||||
1. `<install-path>/settings/Deskflow.conf`
|
||||
1. Windows Registry `HKCU\Software\Deskflow\Deskflow`
|
||||
|
||||
Windows will save to the install dir if settings are loaded from there. If not, it saves any other config files in: `C:\ProgramData\Deskflow\`
|
||||
|
||||
When using settings from the install dir, the service mode will not be available.
|
||||
|
||||
# Server Config Examples
|
||||
|
||||
The `deskflow-server` command accepts the `-c` or `--config` option, which takes one argument,
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
sonar.organization=deskflow
|
||||
sonar.projectKey=deskflow_deskflow
|
||||
sonar.sources=src/apps,src/lib
|
||||
sonar.tests=src/test
|
||||
sonar.tests=src/unittests
|
||||
sonar.exclusions=subprojects/**,build/**
|
||||
sonar.coverage.exclusions=subprojects/**,src/test/**,src/apps/deskflow-gui/**,src/apps/res/**
|
||||
sonar.coverage.exclusions=subprojects/**,src/unittests/**,src/apps/deskflow-gui/**,src/apps/res/**
|
||||
sonar.cpd.exclusions=**/*Test*.cpp
|
||||
sonar.host.url=https://sonarcloud.io
|
||||
sonar.cfamily.compile-commands=build/compile_commands.json
|
||||
|
||||
@ -11,5 +11,6 @@ add_subdirectory(apps)
|
||||
|
||||
option(BUILD_TESTS "Build tests" ON)
|
||||
if(BUILD_TESTS)
|
||||
add_subdirectory(test)
|
||||
add_subdirectory(unittests)
|
||||
endif()
|
||||
|
||||
|
||||
@ -3,6 +3,30 @@
|
||||
# SPDX-FileCopyrightText: 2009 - 2012 Nick Bolton
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
if(UNIX AND NOT APPLE)
|
||||
find_program(HELP2MAN help2man)
|
||||
if(NOT HELP2MAN)
|
||||
message(STATUS "Man page tool (help2man) not found, man pages will not be generated")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
function(generate_app_man TARGET)
|
||||
if(HELP2MAN)
|
||||
add_custom_command(
|
||||
TARGET ${target} POST_BUILD
|
||||
COMMAND QT_QPA_PLATFORM=minimal PATH=$<TARGET_FILE_DIR:${target}>:${PATH} ${HELP2MAN}
|
||||
--include ${CMAKE_SOURCE_DIR}/src/apps/res/manpage.txt
|
||||
--no-info
|
||||
${target}
|
||||
-o $<TARGET_FILE_DIR:${target}>/${target}.1
|
||||
)
|
||||
install(
|
||||
FILES $<TARGET_FILE_DIR:${target}>/${target}.1
|
||||
DESTINATION ${CMAKE_INSTALL_MANDIR}/man1
|
||||
)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
option(BUILD_UNIFIED "Build unified binary" OFF)
|
||||
if(BUILD_UNIFIED)
|
||||
add_subdirectory(deskflow-core)
|
||||
|
||||
@ -45,6 +45,7 @@ if(APPLE)
|
||||
)
|
||||
elseif(UNIX)
|
||||
install(TARGETS ${target} DESTINATION bin)
|
||||
generate_app_man(${target})
|
||||
elseif(WIN32)
|
||||
install(
|
||||
TARGETS ${target}
|
||||
|
||||
@ -13,15 +13,20 @@
|
||||
|
||||
#if SYSAPI_WIN32
|
||||
#include "arch/win32/ArchMiscWindows.h"
|
||||
#include <QCoreApplication>
|
||||
#endif
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
#if SYSAPI_WIN32
|
||||
// HACK to make sure settings gets the correct qApp path
|
||||
QCoreApplication m(argc, argv);
|
||||
m.deleteLater();
|
||||
|
||||
ArchMiscWindows::guardRuntimeVersion();
|
||||
|
||||
// record window instance for tray icon, etc
|
||||
ArchMiscWindows::setInstanceWin32(GetModuleHandle(NULL));
|
||||
ArchMiscWindows::setInstanceWin32(GetModuleHandle(nullptr));
|
||||
#endif
|
||||
|
||||
Arch arch;
|
||||
|
||||
@ -40,6 +40,7 @@ if(APPLE)
|
||||
)
|
||||
elseif(UNIX)
|
||||
install(TARGETS ${target} DESTINATION bin)
|
||||
generate_app_man(${target})
|
||||
elseif(WIN32)
|
||||
install(
|
||||
TARGETS ${target}
|
||||
|
||||
@ -14,6 +14,7 @@
|
||||
|
||||
#if SYSAPI_WIN32
|
||||
#include "arch/win32/ArchMiscWindows.h"
|
||||
#include <QCoreApplication>
|
||||
#endif
|
||||
|
||||
#include <iostream>
|
||||
@ -39,7 +40,11 @@ bool isClient(int argc, char **argv)
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
#if SYSAPI_WIN32
|
||||
ArchMiscWindows::setInstanceWin32(GetModuleHandle(NULL));
|
||||
// HACK to make sure settings gets the correct qApp path
|
||||
QCoreApplication m(argc, argv);
|
||||
m.deleteLater();
|
||||
|
||||
ArchMiscWindows::setInstanceWin32(GetModuleHandle(nullptr));
|
||||
#endif
|
||||
|
||||
Arch arch;
|
||||
|
||||
@ -8,7 +8,7 @@
|
||||
#include "arch/Arch.h"
|
||||
#include "base/EventQueue.h"
|
||||
#include "base/Log.h"
|
||||
#include "common/constants.h"
|
||||
#include "common/Settings.h"
|
||||
#include "deskflow/DaemonApp.h"
|
||||
#include "deskflow/ipc/DaemonIpcServer.h"
|
||||
|
||||
@ -21,12 +21,13 @@
|
||||
|
||||
#endif
|
||||
|
||||
#include <QCommandLineParser>
|
||||
#include <QCoreApplication>
|
||||
#include <QThread>
|
||||
|
||||
using namespace deskflow::core;
|
||||
|
||||
void handleError(const char *message);
|
||||
void handleError(const char *message = "Unrecognized error.");
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
@ -43,84 +44,86 @@ int main(int argc, char **argv)
|
||||
Log log;
|
||||
EventQueue events;
|
||||
|
||||
auto &daemon = DaemonApp::instance();
|
||||
DaemonApp::InitResult initResult;
|
||||
try {
|
||||
initResult = daemon.init(&events, argc, argv);
|
||||
} catch (std::exception &e) {
|
||||
handleError(e.what());
|
||||
return kExitFailed;
|
||||
} catch (...) {
|
||||
handleError("Unrecognized error.");
|
||||
return kExitFailed;
|
||||
// Daemon deliberately does not have a parent, as it will be moved to a new thread.
|
||||
DaemonApp daemon(events);
|
||||
|
||||
QCoreApplication app(argc, argv);
|
||||
QCoreApplication::setApplicationName(QStringLiteral("%1 Daemon").arg(kAppName));
|
||||
|
||||
QCommandLineParser parser;
|
||||
parser.addHelpOption();
|
||||
parser.addVersionOption();
|
||||
|
||||
const auto foregroundOption = QCommandLineOption({"f", "foreground"}, "Run in the foreground (show console)");
|
||||
parser.addOption(foregroundOption);
|
||||
|
||||
const auto installOption = QCommandLineOption({"i", "install"}, "Install as a Windows service");
|
||||
parser.addOption(installOption);
|
||||
|
||||
const auto uninstallOption = QCommandLineOption({"u", "uninstall"}, "Uninstall the Windows service");
|
||||
parser.addOption(uninstallOption);
|
||||
|
||||
parser.process(app);
|
||||
|
||||
if (parser.isSet(foregroundOption)) {
|
||||
daemon.setForeground();
|
||||
}
|
||||
|
||||
// Important: Log the app name and version number to the log file after the daemon app init
|
||||
// because the file log outputter is created there. Logging before would only log to stdout
|
||||
// which is not useful for troubleshooting Windows services.
|
||||
// Depends on whether foreground option was set.
|
||||
daemon.initLogging();
|
||||
|
||||
// Important: Log the app name and version number to the log file daemon app has initialized
|
||||
// logging as it creates the file logger. Logging before would only log to stdout which is not
|
||||
// useful for troubleshooting Windows services.
|
||||
// It's important to write the version number to the log file so we can be certain the old daemon
|
||||
// was uninstalled, since sometimes Windows services can get stuck and fail to be removed.
|
||||
LOG_PRINT("%s Daemon v%s", kAppName, kDisplayVersion);
|
||||
LOG_PRINT("%s v%s", QCoreApplication::applicationName().toStdString().c_str(), kDisplayVersion);
|
||||
|
||||
switch (initResult) {
|
||||
using enum DaemonApp::InitResult;
|
||||
// Default log level to system setting (found in Registry).
|
||||
auto logLevel = Settings::value(Settings::Daemon::LogLevel).toString().toStdString();
|
||||
if (logLevel != "") {
|
||||
CLOG->setFilter(logLevel.c_str());
|
||||
LOG_DEBUG("log level: %s", logLevel.c_str());
|
||||
}
|
||||
|
||||
case StartDaemon: {
|
||||
LOG_INFO("starting daemon");
|
||||
QCoreApplication app(argc, argv);
|
||||
try {
|
||||
|
||||
#if SYSAPI_WIN32
|
||||
// Show warning if not running as admin as daemon will behave differently.
|
||||
if (!ArchMiscWindows::isProcessElevated()) {
|
||||
LOG_WARN("not running as admin, some features may not work");
|
||||
}
|
||||
#endif
|
||||
|
||||
if (parser.isSet(installOption)) {
|
||||
daemon.install();
|
||||
return kExitSuccess;
|
||||
} else if (parser.isSet(uninstallOption)) {
|
||||
daemon.uninstall();
|
||||
return kExitSuccess;
|
||||
}
|
||||
|
||||
const auto ipcServer =
|
||||
new ipc::DaemonIpcServer(&app, DaemonApp::logFilename().toStdString().c_str()); // NOSONAR - Qt managed
|
||||
ipcServer->listen();
|
||||
daemon.connectIpcServer(ipcServer);
|
||||
|
||||
QThread daemonThread;
|
||||
daemon.moveToThread(&daemonThread);
|
||||
|
||||
QObject::connect(&daemonThread, &QThread::started, [&daemon, &daemonThread]() {
|
||||
LOG_DEBUG("daemon thread started");
|
||||
daemon.run();
|
||||
daemonThread.quit();
|
||||
LOG_DEBUG("daemon thread finished");
|
||||
});
|
||||
QObject::connect(&daemonThread, &QThread::finished, &app, &QCoreApplication::quit);
|
||||
daemon.run(daemonThread);
|
||||
|
||||
ipc::DaemonIpcServer ipcServer(&app, QString::fromStdString(daemon.logFilename()));
|
||||
|
||||
// Use direct connection as the daemon app is on it's own thread, and so is on a different event loop.
|
||||
QObject::connect(
|
||||
&ipcServer, &ipc::DaemonIpcServer::logLevelChanged, &daemon, &DaemonApp::saveLogLevel, //
|
||||
Qt::DirectConnection
|
||||
);
|
||||
QObject::connect(
|
||||
&ipcServer, &ipc::DaemonIpcServer::elevateModeChanged, &daemon, &DaemonApp::setElevate, //
|
||||
Qt::DirectConnection
|
||||
);
|
||||
QObject::connect(
|
||||
&ipcServer, &ipc::DaemonIpcServer::commandChanged, &daemon, &DaemonApp::setCommand, //
|
||||
Qt::DirectConnection
|
||||
);
|
||||
QObject::connect(
|
||||
&ipcServer, &ipc::DaemonIpcServer::startProcessRequested, &daemon, &DaemonApp::applyWatchdogCommand, //
|
||||
Qt::DirectConnection
|
||||
);
|
||||
QObject::connect(
|
||||
&ipcServer, &ipc::DaemonIpcServer::stopProcessRequested, &daemon, &DaemonApp::clearWatchdogCommand, //
|
||||
Qt::DirectConnection
|
||||
);
|
||||
QObject::connect(
|
||||
&ipcServer, &ipc::DaemonIpcServer::clearSettingsRequested, &daemon, &DaemonApp::clearSettings, //
|
||||
Qt::DirectConnection
|
||||
);
|
||||
|
||||
daemonThread.start();
|
||||
const auto exitCode = QCoreApplication::exec();
|
||||
daemonThread.wait();
|
||||
|
||||
LOG_DEBUG("daemon exited, code: %d", exitCode);
|
||||
return exitCode;
|
||||
}
|
||||
|
||||
case FatalError:
|
||||
} catch (std::exception &e) {
|
||||
handleError(e.what());
|
||||
return kExitFailed;
|
||||
} catch (...) {
|
||||
handleError();
|
||||
return kExitFailed;
|
||||
|
||||
default:
|
||||
return kExitSuccess;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -44,60 +44,7 @@ endif()
|
||||
add_executable(${target} WIN32 MACOSX_BUNDLE
|
||||
${platform_extra}
|
||||
../res/deskflow.qrc
|
||||
Action.cpp
|
||||
Action.h
|
||||
DataDownloader.cpp
|
||||
DataDownloader.h
|
||||
Hotkey.cpp
|
||||
Hotkey.h
|
||||
KeySequence.cpp
|
||||
KeySequence.h
|
||||
main.cpp
|
||||
MainWindow.cpp
|
||||
MainWindow.h
|
||||
MainWindow.ui
|
||||
ProcessorArch.h
|
||||
QUtility.cpp
|
||||
QUtility.h
|
||||
ScreenSetupModel.cpp
|
||||
ScreenSetupModel.h
|
||||
ServerConfig.cpp
|
||||
ServerConfig.h
|
||||
VersionChecker.cpp
|
||||
VersionChecker.h
|
||||
dialogs/AboutDialog.cpp
|
||||
dialogs/AboutDialog.h
|
||||
dialogs/AboutDialog.ui
|
||||
dialogs/ActionDialog.cpp
|
||||
dialogs/ActionDialog.h
|
||||
dialogs/ActionDialog.ui
|
||||
dialogs/AddClientDialog.cpp
|
||||
dialogs/AddClientDialog.h
|
||||
dialogs/AddClientDialog.ui
|
||||
dialogs/FingerprintDialog.h
|
||||
dialogs/FingerprintDialog.cpp
|
||||
dialogs/HotkeyDialog.cpp
|
||||
dialogs/HotkeyDialog.h
|
||||
dialogs/HotkeyDialog.ui
|
||||
dialogs/ScreenSettingsDialog.cpp
|
||||
dialogs/ScreenSettingsDialog.h
|
||||
dialogs/ScreenSettingsDialog.ui
|
||||
dialogs/ServerConfigDialog.cpp
|
||||
dialogs/ServerConfigDialog.h
|
||||
dialogs/ServerConfigDialog.ui
|
||||
dialogs/SettingsDialog.cpp
|
||||
dialogs/SettingsDialog.h
|
||||
dialogs/SettingsDialog.ui
|
||||
widgets/FingerprintPreview.h
|
||||
widgets/FingerprintPreview.cpp
|
||||
widgets/KeySequenceWidget.cpp
|
||||
widgets/KeySequenceWidget.h
|
||||
widgets/NewScreenWidget.h
|
||||
widgets/NewScreenWidget.cpp
|
||||
widgets/ScreenSetupView.cpp
|
||||
widgets/ScreenSetupView.h
|
||||
widgets/TrashScreenWidget.cpp
|
||||
widgets/TrashScreenWidget.h
|
||||
deskflow-gui.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(
|
||||
@ -137,4 +84,5 @@ elseif(APPLE)
|
||||
install(TARGETS ${target} BUNDLE DESTINATION .)
|
||||
else()
|
||||
install(TARGETS ${target} DESTINATION bin)
|
||||
generate_app_man(${target})
|
||||
endif()
|
||||
|
||||
@ -1,18 +0,0 @@
|
||||
/*
|
||||
* Deskflow -- mouse and keyboard sharing utility
|
||||
* SPDX-FileCopyrightText: (C) 2015 - 2016 Symless Ltd.
|
||||
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
enum qProcessorArch
|
||||
{
|
||||
kProcessorArchWin32,
|
||||
kProcessorArchWin64,
|
||||
kProcessorArchMac32,
|
||||
kProcessorArchMac64,
|
||||
kProcessorArchLinux32,
|
||||
kProcessorArchLinux64,
|
||||
kProcessorArchUnknown
|
||||
};
|
||||
@ -1,65 +0,0 @@
|
||||
/*
|
||||
* Deskflow -- mouse and keyboard sharing utility
|
||||
* SPDX-FileCopyrightText: (C) 2013 - 2016 Symless Ltd.
|
||||
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
|
||||
*/
|
||||
|
||||
#include "QUtility.h"
|
||||
|
||||
#include "ProcessorArch.h"
|
||||
|
||||
#if defined(Q_OS_LINUX)
|
||||
#include <QFile>
|
||||
#include <QProcess>
|
||||
#endif
|
||||
|
||||
#if defined(Q_OS_WIN)
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <Windows.h>
|
||||
#endif
|
||||
|
||||
void setIndexFromItemData(QComboBox *comboBox, const QVariant &itemData)
|
||||
{
|
||||
for (int i = 0; i < comboBox->count(); ++i) {
|
||||
if (comboBox->itemData(i) == itemData) {
|
||||
comboBox->setCurrentIndex(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QString hash(const QString &string)
|
||||
{
|
||||
QByteArray data = string.toUtf8();
|
||||
QByteArray hash = QCryptographicHash::hash(data, QCryptographicHash::Md5);
|
||||
return hash.toHex();
|
||||
}
|
||||
|
||||
qProcessorArch getProcessorArch()
|
||||
{
|
||||
#if defined(Q_OS_WIN)
|
||||
SYSTEM_INFO systemInfo;
|
||||
GetNativeSystemInfo(&systemInfo);
|
||||
|
||||
switch (systemInfo.wProcessorArchitecture) {
|
||||
case PROCESSOR_ARCHITECTURE_INTEL:
|
||||
return kProcessorArchWin32;
|
||||
case PROCESSOR_ARCHITECTURE_IA64:
|
||||
return kProcessorArchWin64;
|
||||
case PROCESSOR_ARCHITECTURE_AMD64:
|
||||
return kProcessorArchWin64;
|
||||
default:
|
||||
return kProcessorArchUnknown;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(Q_OS_LINUX)
|
||||
#ifdef __i386__
|
||||
return kProcessorArchLinux32;
|
||||
#else
|
||||
return kProcessorArchLinux64;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
return kProcessorArchUnknown;
|
||||
}
|
||||
@ -1,18 +0,0 @@
|
||||
/*
|
||||
* Deskflow -- mouse and keyboard sharing utility
|
||||
* SPDX-FileCopyrightText: (C) 2013 - 2016 Symless Ltd.
|
||||
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ProcessorArch.h"
|
||||
|
||||
#include <QComboBox>
|
||||
#include <QCryptographicHash>
|
||||
#include <QNetworkInterface>
|
||||
#include <QVariant>
|
||||
|
||||
void setIndexFromItemData(QComboBox *comboBox, const QVariant &itemData);
|
||||
QString hash(const QString &string);
|
||||
qProcessorArch getProcessorArch();
|
||||
@ -6,26 +6,21 @@
|
||||
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
|
||||
*/
|
||||
|
||||
#include "MainWindow.h"
|
||||
#include "common/constants.h"
|
||||
#include "common/Constants.h"
|
||||
#include "common/UrlConstants.h"
|
||||
#include "gui/Diagnostic.h"
|
||||
#include "gui/DotEnv.h"
|
||||
#include "gui/Logger.h"
|
||||
#include "gui/config/AppConfig.h"
|
||||
#include "gui/config/ConfigScopes.h"
|
||||
#include "gui/constants.h"
|
||||
#include "gui/diagnostic.h"
|
||||
#include "gui/dotenv.h"
|
||||
#include "gui/messages.h"
|
||||
#include "gui/string_utils.h"
|
||||
#include "gui/style_utils.h"
|
||||
#include "gui/MainWindow.h"
|
||||
#include "gui/Messages.h"
|
||||
#include "gui/StyleUtils.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QDebug>
|
||||
#include <QCommandLineParser>
|
||||
#include <QGuiApplication>
|
||||
#include <QLocalSocket>
|
||||
#include <QMessageBox>
|
||||
#include <QObject>
|
||||
#include <QSharedMemory>
|
||||
#include <QtGlobal>
|
||||
|
||||
#if defined(Q_OS_MAC)
|
||||
#include <Carbon/Carbon.h>
|
||||
@ -38,24 +33,10 @@
|
||||
|
||||
using namespace deskflow::gui;
|
||||
|
||||
class QThreadImpl : public QThread
|
||||
{
|
||||
public:
|
||||
static void msleep(unsigned long msecs)
|
||||
{
|
||||
QThread::msleep(msecs);
|
||||
}
|
||||
};
|
||||
|
||||
#if defined(Q_OS_MAC)
|
||||
bool checkMacAssistiveDevices();
|
||||
#endif
|
||||
|
||||
bool hasArg(const QString &arg, const QStringList &args)
|
||||
{
|
||||
return std::ranges::any_of(args, [&arg](const QString &a) { return a == arg; });
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
#if defined(Q_OS_UNIX) && defined(QT_DEBUG)
|
||||
@ -63,21 +44,38 @@ int main(int argc, char *argv[])
|
||||
QLoggingCategory::setFilterRules(QStringLiteral("*.debug=true\nqt.*=false"));
|
||||
#endif
|
||||
|
||||
#if defined(Q_OS_MAC)
|
||||
/* Workaround for QTBUG-40332 - "High ping when QNetworkAccessManager is
|
||||
* instantiated" */
|
||||
::setenv("QT_BEARER_POLL_TIMEOUT", "-1", 1);
|
||||
#endif
|
||||
|
||||
QCoreApplication::setApplicationName(kAppName);
|
||||
QCoreApplication::setOrganizationName(kAppName);
|
||||
QCoreApplication::setApplicationVersion(kVersion);
|
||||
QCoreApplication::setOrganizationDomain(kOrgDomain); // used in prefix, can't be a url
|
||||
QGuiApplication::setDesktopFileName(QStringLiteral("org.deskflow.deskflow"));
|
||||
|
||||
// used as a prefix for settings paths, and must not be a url.
|
||||
QCoreApplication::setOrganizationDomain(kOrgDomain);
|
||||
|
||||
QApplication app(argc, argv);
|
||||
|
||||
// Add Command Line Options
|
||||
auto helpOption = QCommandLineOption("help", "Display Help on the command line");
|
||||
auto versionOption = QCommandLineOption("version", "Display version information");
|
||||
auto resetOption = QCommandLineOption("reset", "Reset all settings");
|
||||
|
||||
QCommandLineParser parser;
|
||||
parser.setSingleDashWordOptionMode(QCommandLineParser::ParseAsLongOptions);
|
||||
parser.addOption(helpOption);
|
||||
parser.addOption(versionOption);
|
||||
parser.addOption(resetOption);
|
||||
parser.parse(QCoreApplication::arguments());
|
||||
|
||||
const auto header = QStringLiteral("%1: %2\n").arg(kAppName, kDisplayVersion);
|
||||
if (parser.isSet(helpOption) || !parser.unknownOptionNames().isEmpty() || !parser.errorText().isEmpty()) {
|
||||
QTextStream(stdout) << header << QStringLiteral(" %1\n\n").arg(kAppDescription)
|
||||
<< parser.helpText().replace(QApplication::applicationFilePath(), kAppId);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (parser.isSet(versionOption)) {
|
||||
QTextStream(stdout) << header << kCopyright << Qt::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Create a shared memory segment with a unique key
|
||||
// This is to prevent a new instance from running if one is already running
|
||||
QSharedMemory sharedMemory("deskflow-gui");
|
||||
@ -120,9 +118,11 @@ int main(int argc, char *argv[])
|
||||
#if defined(Q_OS_MAC)
|
||||
|
||||
if (app.applicationDirPath().startsWith("/Volumes/")) {
|
||||
QString msgBody = QStringLiteral("Please drag %1 to the Applications folder, "
|
||||
"and open it from there.");
|
||||
QMessageBox::information(NULL, kAppName, msgBody.arg(kAppName));
|
||||
QString msgBody = QStringLiteral(
|
||||
"Please drag %1 to the Applications folder, "
|
||||
"and open it from there."
|
||||
);
|
||||
QMessageBox::information(nullptr, kAppName, msgBody.arg(kAppName));
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -131,23 +131,12 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
#endif
|
||||
|
||||
ConfigScopes configScopes;
|
||||
|
||||
// --no-reset
|
||||
QStringList arguments = QCoreApplication::arguments();
|
||||
const auto noReset = hasArg("--no-reset", arguments);
|
||||
const auto resetEnvVar = strToTrue(qEnvironmentVariable("DESKFLOW_RESET_ALL"));
|
||||
if (resetEnvVar && !noReset) {
|
||||
diagnostic::clearSettings(configScopes, false);
|
||||
if (parser.isSet(resetOption)) {
|
||||
diagnostic::clearSettings(false);
|
||||
}
|
||||
|
||||
AppConfig appConfig(configScopes);
|
||||
|
||||
QObject::connect(
|
||||
&configScopes, &ConfigScopes::saving, &appConfig, [&appConfig]() { appConfig.commit(); }, Qt::DirectConnection
|
||||
);
|
||||
|
||||
MainWindow mainWindow(configScopes, appConfig);
|
||||
MainWindow mainWindow;
|
||||
mainWindow.open();
|
||||
|
||||
return QApplication::exec();
|
||||
@ -156,8 +145,6 @@ int main(int argc, char *argv[])
|
||||
#if defined(Q_OS_MAC)
|
||||
bool checkMacAssistiveDevices()
|
||||
{
|
||||
#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090 // mavericks
|
||||
|
||||
// new in mavericks, applications are trusted individually
|
||||
// with use of the accessibility api. this call will show a
|
||||
// prompt which can show the security/privacy/accessibility
|
||||
@ -170,24 +157,10 @@ bool checkMacAssistiveDevices()
|
||||
|
||||
const void *keys[] = {kAXTrustedCheckOptionPrompt};
|
||||
const void *trueValue[] = {kCFBooleanTrue};
|
||||
CFDictionaryRef options = CFDictionaryCreate(NULL, keys, trueValue, 1, NULL, NULL);
|
||||
CFDictionaryRef options = CFDictionaryCreate(nullptr, keys, trueValue, 1, nullptr, nullptr);
|
||||
|
||||
bool result = AXIsProcessTrustedWithOptions(options);
|
||||
CFRelease(options);
|
||||
return result;
|
||||
|
||||
#else
|
||||
|
||||
// now deprecated in mavericks.
|
||||
bool result = AXAPIEnabled();
|
||||
if (!result) {
|
||||
QString msgBody = QString("Please enable access to assistive devices "
|
||||
"System Preferences -> Security & Privacy -> "
|
||||
"Privacy -> Accessibility, then re-open %1.");
|
||||
QMessageBox::information(NULL, kAppName, msgBody.arg(kAppName));
|
||||
}
|
||||
return result;
|
||||
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
@ -1,143 +0,0 @@
|
||||
/*
|
||||
* Deskflow -- mouse and keyboard sharing utility
|
||||
* SPDX-FileCopyrightText: (C) 2012 Symless Ltd.
|
||||
* SPDX-FileCopyrightText: (C) 2008 Volker Lanz <vl@fidra.de>
|
||||
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
|
||||
*/
|
||||
|
||||
#include "ScreenSettingsDialog.h"
|
||||
#include "ui_ScreenSettingsDialog.h"
|
||||
|
||||
#include "gui/config/Screen.h"
|
||||
#include "gui/styles.h"
|
||||
#include "gui/validators/AliasValidator.h"
|
||||
#include "gui/validators/ScreenNameValidator.h"
|
||||
#include "gui/validators/ValidationError.h"
|
||||
|
||||
#include <QMessageBox>
|
||||
|
||||
using namespace deskflow::gui;
|
||||
using enum ScreenConfig::Modifier;
|
||||
using enum ScreenConfig::SwitchCorner;
|
||||
using enum ScreenConfig::Fix;
|
||||
|
||||
ScreenSettingsDialog::~ScreenSettingsDialog() = default;
|
||||
|
||||
ScreenSettingsDialog::ScreenSettingsDialog(QWidget *parent, Screen *pScreen, const ScreenList *pScreens)
|
||||
: QDialog(parent, Qt::WindowTitleHint | Qt::WindowSystemMenuHint),
|
||||
ui_{std::make_unique<Ui::ScreenSettingsDialog>()},
|
||||
m_pScreen(pScreen)
|
||||
{
|
||||
|
||||
ui_->setupUi(this);
|
||||
|
||||
ui_->m_pLabelAliasError->setStyleSheet(kStyleErrorActiveLabel);
|
||||
ui_->m_pLabelNameError->setStyleSheet(kStyleErrorActiveLabel);
|
||||
|
||||
ui_->m_pLineEditName->setText(m_pScreen->name());
|
||||
ui_->m_pLineEditName->setValidator(new validators::ScreenNameValidator(
|
||||
ui_->m_pLineEditName, new validators::ValidationError(this, ui_->m_pLabelNameError), pScreens
|
||||
));
|
||||
ui_->m_pLineEditName->selectAll();
|
||||
|
||||
ui_->m_pLineEditAlias->setValidator(new validators::AliasValidator(
|
||||
ui_->m_pLineEditAlias, new validators::ValidationError(this, ui_->m_pLabelAliasError)
|
||||
));
|
||||
|
||||
for (int i = 0; i < m_pScreen->aliases().count(); i++)
|
||||
new QListWidgetItem(m_pScreen->aliases()[i], ui_->m_pListAliases);
|
||||
|
||||
ui_->m_pComboBoxShift->setCurrentIndex(m_pScreen->modifier(static_cast<int>(Shift)));
|
||||
ui_->m_pComboBoxCtrl->setCurrentIndex(m_pScreen->modifier(static_cast<int>(Ctrl)));
|
||||
ui_->m_pComboBoxAlt->setCurrentIndex(m_pScreen->modifier(static_cast<int>(Alt)));
|
||||
ui_->m_pComboBoxMeta->setCurrentIndex(m_pScreen->modifier(static_cast<int>(Meta)));
|
||||
ui_->m_pComboBoxSuper->setCurrentIndex(m_pScreen->modifier(static_cast<int>(Super)));
|
||||
|
||||
ui_->m_pCheckBoxCornerTopLeft->setChecked(m_pScreen->switchCorner(static_cast<int>(TopLeft)));
|
||||
ui_->m_pCheckBoxCornerTopRight->setChecked(m_pScreen->switchCorner(static_cast<int>(TopRight)));
|
||||
ui_->m_pCheckBoxCornerBottomLeft->setChecked(m_pScreen->switchCorner(static_cast<int>(BottomLeft)));
|
||||
ui_->m_pCheckBoxCornerBottomRight->setChecked(m_pScreen->switchCorner(static_cast<int>(BottomRight)));
|
||||
ui_->m_pSpinBoxSwitchCornerSize->setValue(m_pScreen->switchCornerSize());
|
||||
|
||||
ui_->m_pCheckBoxCapsLock->setChecked(m_pScreen->fix(CapsLock));
|
||||
ui_->m_pCheckBoxNumLock->setChecked(m_pScreen->fix(NumLock));
|
||||
ui_->m_pCheckBoxScrollLock->setChecked(m_pScreen->fix(ScrollLock));
|
||||
ui_->m_pCheckBoxXTest->setChecked(m_pScreen->fix(XTest));
|
||||
}
|
||||
|
||||
void ScreenSettingsDialog::accept()
|
||||
{
|
||||
if (ui_->m_pLineEditName->text().isEmpty()) {
|
||||
QMessageBox::warning(
|
||||
this, tr("Screen name is empty"),
|
||||
tr("The screen name cannot be empty. "
|
||||
"Please either fill in a name or cancel the dialog.")
|
||||
);
|
||||
return;
|
||||
} else if (!ui_->m_pLabelNameError->text().isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_pScreen->init();
|
||||
|
||||
m_pScreen->setName(ui_->m_pLineEditName->text());
|
||||
|
||||
for (int i = 0; i < ui_->m_pListAliases->count(); i++) {
|
||||
QString alias(ui_->m_pListAliases->item(i)->text());
|
||||
if (alias == ui_->m_pLineEditName->text()) {
|
||||
QMessageBox::warning(
|
||||
this, tr("Screen name matches alias"),
|
||||
tr("The screen name cannot be the same as an alias. "
|
||||
"Please either remove the alias or change the screen name.")
|
||||
);
|
||||
return;
|
||||
}
|
||||
m_pScreen->addAlias(alias);
|
||||
}
|
||||
|
||||
m_pScreen->setModifier(static_cast<int>(Shift), ui_->m_pComboBoxShift->currentIndex());
|
||||
m_pScreen->setModifier(static_cast<int>(Ctrl), ui_->m_pComboBoxCtrl->currentIndex());
|
||||
m_pScreen->setModifier(static_cast<int>(Alt), ui_->m_pComboBoxAlt->currentIndex());
|
||||
m_pScreen->setModifier(static_cast<int>(Meta), ui_->m_pComboBoxMeta->currentIndex());
|
||||
m_pScreen->setModifier(static_cast<int>(Super), ui_->m_pComboBoxSuper->currentIndex());
|
||||
|
||||
m_pScreen->setSwitchCorner(static_cast<int>(TopLeft), ui_->m_pCheckBoxCornerTopLeft->isChecked());
|
||||
m_pScreen->setSwitchCorner(static_cast<int>(TopRight), ui_->m_pCheckBoxCornerTopRight->isChecked());
|
||||
m_pScreen->setSwitchCorner(static_cast<int>(BottomLeft), ui_->m_pCheckBoxCornerBottomLeft->isChecked());
|
||||
m_pScreen->setSwitchCorner(static_cast<int>(BottomRight), ui_->m_pCheckBoxCornerBottomRight->isChecked());
|
||||
m_pScreen->setSwitchCornerSize(ui_->m_pSpinBoxSwitchCornerSize->value());
|
||||
|
||||
m_pScreen->setFix(static_cast<int>(CapsLock), ui_->m_pCheckBoxCapsLock->isChecked());
|
||||
m_pScreen->setFix(static_cast<int>(NumLock), ui_->m_pCheckBoxNumLock->isChecked());
|
||||
m_pScreen->setFix(static_cast<int>(ScrollLock), ui_->m_pCheckBoxScrollLock->isChecked());
|
||||
m_pScreen->setFix(static_cast<int>(XTest), ui_->m_pCheckBoxXTest->isChecked());
|
||||
|
||||
QDialog::accept();
|
||||
}
|
||||
|
||||
void ScreenSettingsDialog::on_m_pButtonAddAlias_clicked()
|
||||
{
|
||||
if (!ui_->m_pLineEditAlias->text().isEmpty() &&
|
||||
ui_->m_pListAliases->findItems(ui_->m_pLineEditAlias->text(), Qt::MatchFixedString).isEmpty()) {
|
||||
new QListWidgetItem(ui_->m_pLineEditAlias->text(), ui_->m_pListAliases);
|
||||
ui_->m_pLineEditAlias->clear();
|
||||
}
|
||||
}
|
||||
|
||||
void ScreenSettingsDialog::on_m_pLineEditAlias_textChanged(const QString &text)
|
||||
{
|
||||
ui_->m_pButtonAddAlias->setEnabled(!text.isEmpty() && ui_->m_pLabelAliasError->text().isEmpty());
|
||||
}
|
||||
|
||||
void ScreenSettingsDialog::on_m_pButtonRemoveAlias_clicked()
|
||||
{
|
||||
QList<QListWidgetItem *> items = ui_->m_pListAliases->selectedItems();
|
||||
|
||||
for (int i = 0; i < items.count(); i++)
|
||||
delete items[i];
|
||||
}
|
||||
|
||||
void ScreenSettingsDialog::on_m_pListAliases_itemSelectionChanged()
|
||||
{
|
||||
ui_->m_pButtonRemoveAlias->setEnabled(!ui_->m_pListAliases->selectedItems().isEmpty());
|
||||
}
|
||||
@ -45,6 +45,7 @@ if(APPLE)
|
||||
)
|
||||
elseif(UNIX)
|
||||
install(TARGETS ${target} DESTINATION bin)
|
||||
generate_app_man(${target})
|
||||
elseif(WIN32)
|
||||
install(
|
||||
TARGETS ${target}
|
||||
|
||||
@ -13,15 +13,20 @@
|
||||
|
||||
#if SYSAPI_WIN32
|
||||
#include "arch/win32/ArchMiscWindows.h"
|
||||
#include <QCoreApplication>
|
||||
#endif
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
#if SYSAPI_WIN32
|
||||
// HACK to make sure settings gets the correct qApp path
|
||||
QCoreApplication m(argc, argv);
|
||||
m.deleteLater();
|
||||
|
||||
ArchMiscWindows::guardRuntimeVersion();
|
||||
|
||||
// record window instance for tray icon, etc
|
||||
ArchMiscWindows::setInstanceWin32(GetModuleHandle(NULL));
|
||||
ArchMiscWindows::setInstanceWin32(GetModuleHandle(nullptr));
|
||||
#endif
|
||||
|
||||
Arch arch;
|
||||
@ -30,30 +35,6 @@ int main(int argc, char **argv)
|
||||
Log log;
|
||||
EventQueue events;
|
||||
|
||||
// HACK: the `--active-desktop` arg actually belongs in the `deskflow-core` binary,
|
||||
// but we are placing it here in the server binary temporarily until we are ready to
|
||||
// ship the `deskflow-core` binary. we are deliberately not integrating `--active-desktop`
|
||||
// into the existing `ServerApp` arg parsing code as that would be a waste of time.
|
||||
#if SYSAPI_WIN32
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
std::string arg(argv[i]);
|
||||
// This is called by the daemon (running in session 0) when it needs to know the name of the
|
||||
// interactive desktop.
|
||||
// It is necessary to run a utility process because the daemon runs in session 0, which does not
|
||||
// have access to the active desktop, and so cannot query it's name.
|
||||
if (arg == "--active-desktop") {
|
||||
const auto name = ArchMiscWindows::getActiveDesktopName();
|
||||
if (name.empty()) {
|
||||
LOG((CLOG_CRIT "failed to get active desktop name"));
|
||||
return kExitFailed;
|
||||
}
|
||||
|
||||
LOG((CLOG_PRINT "%s", name.c_str()));
|
||||
return kExitSuccess;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
ServerApp app(&events);
|
||||
return app.run(argc, argv);
|
||||
}
|
||||
|
||||
5
src/apps/res/manpage.txt
Normal file
5
src/apps/res/manpage.txt
Normal file
@ -0,0 +1,5 @@
|
||||
[SEE ALSO]
|
||||
deskflow(1), deskflow-client(1), deskflow-server(2)
|
||||
|
||||
All documentation is on the web, so please point your browser at
|
||||
<https://github.com/deskflow/deskflow/wiki> and surf away.
|
||||
@ -10,27 +10,12 @@
|
||||
/* Define if the <X11/extensions/dpms.h> header file declares function prototypes. */
|
||||
#cmakedefine HAVE_DPMS_PROTOTYPES @HAVE_DPMS_PROTOTYPES@
|
||||
|
||||
/* Define if you have a working `getpwuid_r` function. */
|
||||
#cmakedefine HAVE_GETPWUID_R @HAVE_GETPWUID_R@
|
||||
|
||||
/* Define to 1 if you have the `gmtime_r` function. */
|
||||
#cmakedefine HAVE_GMTIME_R @HAVE_GMTIME_R@
|
||||
|
||||
/* Define if you have the `inet_aton` function. */
|
||||
#cmakedefine HAVE_INET_ATON @HAVE_INET_ATON@
|
||||
|
||||
/* Define to 1 if you have the <istream> header file. */
|
||||
#cmakedefine HAVE_ISTREAM @HAVE_ISTREAM@
|
||||
|
||||
/* Define to 1 if you have the <locale.h> header file. */
|
||||
#cmakedefine HAVE_LOCALE_H @HAVE_LOCALE_H@
|
||||
|
||||
/* Define if you have the `nanosleep` function. */
|
||||
#cmakedefine HAVE_NANOSLEEP @HAVE_NANOSLEEP@
|
||||
|
||||
/* Define to 1 if you have the <ostream> header file. */
|
||||
#cmakedefine HAVE_OSTREAM @HAVE_OSTREAM@
|
||||
|
||||
/* Define if you have a POSIX `sigwait` function. */
|
||||
#cmakedefine HAVE_POSIX_SIGWAIT @HAVE_POSIX_SIGWAIT@
|
||||
|
||||
@ -43,9 +28,6 @@
|
||||
/* Define if your compiler defines socklen_t. */
|
||||
#cmakedefine HAVE_SOCKLEN_T @HAVE_SOCKLEN_T@
|
||||
|
||||
/* Define to 1 if you have the <sstream> header file. */
|
||||
#cmakedefine HAVE_SSTREAM @HAVE_SSTREAM@
|
||||
|
||||
/* Define to 1 if you have the <sys/select.h> header file. */
|
||||
#cmakedefine HAVE_SYS_SELECT_H @HAVE_SYS_SELECT_H@
|
||||
|
||||
@ -58,15 +40,9 @@
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
#cmakedefine HAVE_SYS_TYPES_H @HAVE_SYS_TYPES_H@
|
||||
|
||||
/* Define to 1 if you have the <sys/utsname.h> header file. */
|
||||
#cmakedefine HAVE_SYS_UTSNAME_H @HAVE_SYS_UTSNAME_H@
|
||||
|
||||
/* Define to 1 if you have the <unistd.h> header file. */
|
||||
#cmakedefine HAVE_UNISTD_H @HAVE_UNISTD_H@
|
||||
|
||||
/* Define to 1 if you have the <wchar.h> header file. */
|
||||
#cmakedefine HAVE_WCHAR_H @HAVE_WCHAR_H@
|
||||
|
||||
/* Define to 1 if you have the <X11/extensions/Xrandr.h> header file. */
|
||||
#cmakedefine HAVE_X11_EXTENSIONS_XRANDR_H @HAVE_X11_EXTENSIONS_XRANDR_H@
|
||||
|
||||
@ -15,11 +15,11 @@
|
||||
// Arch
|
||||
//
|
||||
|
||||
Arch *Arch::s_instance = NULL;
|
||||
Arch *Arch::s_instance = nullptr;
|
||||
|
||||
Arch::Arch()
|
||||
{
|
||||
assert(s_instance == NULL);
|
||||
assert(s_instance == nullptr);
|
||||
s_instance = this;
|
||||
}
|
||||
|
||||
@ -28,13 +28,6 @@ Arch::Arch(Arch *arch)
|
||||
s_instance = arch;
|
||||
}
|
||||
|
||||
Arch::~Arch()
|
||||
{
|
||||
#if SYSAPI_WIN32
|
||||
ArchMiscWindows::cleanup();
|
||||
#endif
|
||||
}
|
||||
|
||||
void Arch::init()
|
||||
{
|
||||
ARCH_NETWORK::init();
|
||||
@ -45,6 +38,6 @@ void Arch::init()
|
||||
|
||||
Arch *Arch::getInstance()
|
||||
{
|
||||
assert(s_instance != NULL);
|
||||
assert(s_instance != nullptr);
|
||||
return s_instance;
|
||||
}
|
||||
|
||||
@ -24,31 +24,24 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/common.h"
|
||||
#include "arch/ArchString.h"
|
||||
#include "common/Common.h"
|
||||
|
||||
#if SYSAPI_WIN32
|
||||
|
||||
#include "arch/win32/ArchConsoleWindows.h"
|
||||
#include "arch/win32/ArchDaemonWindows.h"
|
||||
#include "arch/win32/ArchFileWindows.h"
|
||||
#include "arch/win32/ArchLogWindows.h"
|
||||
#include "arch/win32/ArchMultithreadWindows.h"
|
||||
#include "arch/win32/ArchNetworkWinsock.h"
|
||||
#include "arch/win32/ArchSleepWindows.h"
|
||||
#include "arch/win32/ArchStringWindows.h"
|
||||
#include "arch/win32/ArchSystemWindows.h"
|
||||
#include "arch/win32/ArchTimeWindows.h"
|
||||
|
||||
#elif SYSAPI_UNIX
|
||||
|
||||
#include "arch/unix/ArchConsoleUnix.h"
|
||||
#include "arch/unix/ArchDaemonUnix.h"
|
||||
#include "arch/unix/ArchFileUnix.h"
|
||||
#include "arch/unix/ArchLogUnix.h"
|
||||
#include "arch/unix/ArchNetworkBSD.h"
|
||||
#include "arch/unix/ArchSleepUnix.h"
|
||||
#include "arch/unix/ArchStringUnix.h"
|
||||
#include "arch/unix/ArchSystemUnix.h"
|
||||
#include "arch/unix/ArchTimeUnix.h"
|
||||
|
||||
#if HAVE_PTHREAD
|
||||
@ -73,28 +66,25 @@ to each method to those implementations. Clients should use the
|
||||
exactly one of these objects before attempting to call any method,
|
||||
typically at the beginning of \c main().
|
||||
*/
|
||||
class Arch : public ARCH_CONSOLE,
|
||||
public ARCH_DAEMON,
|
||||
public ARCH_FILE,
|
||||
class Arch : public ARCH_DAEMON,
|
||||
public ARCH_LOG,
|
||||
public ARCH_MULTITHREAD,
|
||||
public ARCH_NETWORK,
|
||||
public ARCH_SLEEP,
|
||||
public ARCH_STRING,
|
||||
public ARCH_SYSTEM,
|
||||
public ArchString,
|
||||
public ARCH_TIME
|
||||
{
|
||||
public:
|
||||
Arch();
|
||||
Arch(Arch *arch);
|
||||
virtual ~Arch();
|
||||
explicit Arch(Arch *arch);
|
||||
~Arch() override = default;
|
||||
|
||||
//! Call init on other arch classes.
|
||||
/*!
|
||||
Some arch classes depend on others to exist first. When init is called
|
||||
these classes will have ARCH available for use.
|
||||
*/
|
||||
virtual void init();
|
||||
void init() override;
|
||||
|
||||
//
|
||||
// accessors
|
||||
@ -120,7 +110,7 @@ private:
|
||||
class ArchMutexLock
|
||||
{
|
||||
public:
|
||||
ArchMutexLock(ArchMutex mutex) : m_mutex(mutex)
|
||||
explicit ArchMutexLock(ArchMutex mutex) : m_mutex(mutex)
|
||||
{
|
||||
ARCH->lockMutex(m_mutex);
|
||||
}
|
||||
|
||||
@ -1,21 +0,0 @@
|
||||
/*
|
||||
* Deskflow -- mouse and keyboard sharing utility
|
||||
* SPDX-FileCopyrightText: (C) 2012 - 2016 Symless Ltd.
|
||||
* SPDX-FileCopyrightText: (C) 2002 Chris Schoeneman
|
||||
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
|
||||
*/
|
||||
|
||||
#include "arch/ArchConsoleStd.h"
|
||||
#include "base/Log.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
void ArchConsoleStd::writeConsole(ELevel level, const char *str)
|
||||
{
|
||||
if ((level >= kFATAL) && (level <= kWARNING))
|
||||
std::cerr << str << std::endl;
|
||||
else
|
||||
std::cout << str << std::endl;
|
||||
|
||||
std::cout.flush();
|
||||
}
|
||||
@ -1,34 +0,0 @@
|
||||
/*
|
||||
* Deskflow -- mouse and keyboard sharing utility
|
||||
* SPDX-FileCopyrightText: (C) 2012 - 2016 Symless Ltd.
|
||||
* SPDX-FileCopyrightText: (C) 2002 Chris Schoeneman
|
||||
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "arch/IArchConsole.h"
|
||||
|
||||
//! Cross platform implementation of IArchConsole
|
||||
class ArchConsoleStd : public IArchConsole
|
||||
{
|
||||
public:
|
||||
ArchConsoleStd()
|
||||
{
|
||||
}
|
||||
virtual ~ArchConsoleStd()
|
||||
{
|
||||
}
|
||||
|
||||
// IArchConsole overrides
|
||||
virtual void openConsole(const char *title)
|
||||
{
|
||||
}
|
||||
virtual void closeConsole()
|
||||
{
|
||||
}
|
||||
virtual void showConsole(bool)
|
||||
{
|
||||
}
|
||||
virtual void writeConsole(ELevel level, const char *);
|
||||
};
|
||||
@ -11,16 +11,6 @@
|
||||
// ArchDaemonNone
|
||||
//
|
||||
|
||||
ArchDaemonNone::ArchDaemonNone()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
ArchDaemonNone::~ArchDaemonNone()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
void ArchDaemonNone::installDaemon(const char *, const char *, const char *, const char *, const char *)
|
||||
{
|
||||
// do nothing
|
||||
@ -31,7 +21,7 @@ void ArchDaemonNone::uninstallDaemon(const char *)
|
||||
// do nothing
|
||||
}
|
||||
|
||||
int ArchDaemonNone::daemonize(const char *name, DaemonFunc func)
|
||||
int ArchDaemonNone::daemonize(const char *name, DaemonFunc const &func)
|
||||
{
|
||||
// simply forward the call to func. obviously, this doesn't
|
||||
// do any daemonizing.
|
||||
@ -50,10 +40,12 @@ bool ArchDaemonNone::isDaemonInstalled(const char *)
|
||||
|
||||
void ArchDaemonNone::installDaemon()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
void ArchDaemonNone::uninstallDaemon()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
std::string ArchDaemonNone::commandLine() const
|
||||
|
||||
@ -21,18 +21,18 @@ function and returns its result.
|
||||
class ArchDaemonNone : public IArchDaemon
|
||||
{
|
||||
public:
|
||||
ArchDaemonNone();
|
||||
virtual ~ArchDaemonNone();
|
||||
ArchDaemonNone() = default;
|
||||
~ArchDaemonNone() override = default;
|
||||
|
||||
// IArchDaemon overrides
|
||||
virtual void installDaemon(
|
||||
void installDaemon(
|
||||
const char *name, const char *description, const char *pathname, const char *commandLine, const char *dependencies
|
||||
);
|
||||
virtual void uninstallDaemon(const char *name);
|
||||
virtual int daemonize(const char *name, DaemonFunc func);
|
||||
virtual bool canInstallDaemon(const char *name);
|
||||
virtual bool isDaemonInstalled(const char *name);
|
||||
virtual void installDaemon();
|
||||
virtual void uninstallDaemon();
|
||||
virtual std::string commandLine() const;
|
||||
) override;
|
||||
void uninstallDaemon(const char *name) override;
|
||||
int daemonize(const char *name, DaemonFunc const &func) override;
|
||||
bool canInstallDaemon(const char *name) override;
|
||||
bool isDaemonInstalled(const char *name) override;
|
||||
void installDaemon() override;
|
||||
void uninstallDaemon() override;
|
||||
std::string commandLine() const override;
|
||||
};
|
||||
|
||||
@ -5,45 +5,44 @@
|
||||
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
|
||||
*/
|
||||
|
||||
#include "arch/IArchString.h"
|
||||
#include "arch/ArchString.h"
|
||||
#include "arch/Arch.h"
|
||||
#include "common/common.h"
|
||||
|
||||
#include <climits>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
static ArchMutex s_mutex = NULL;
|
||||
static ArchMutex s_mutex = nullptr;
|
||||
|
||||
//
|
||||
// use C library non-reentrant multibyte conversion with mutex
|
||||
//
|
||||
|
||||
IArchString::~IArchString()
|
||||
ArchString::~ArchString()
|
||||
{
|
||||
if (s_mutex != NULL) {
|
||||
if (s_mutex != nullptr) {
|
||||
ARCH->closeMutex(s_mutex);
|
||||
s_mutex = NULL;
|
||||
s_mutex = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
int IArchString::convStringWCToMB(char *dst, const wchar_t *src, uint32_t n, bool *errors)
|
||||
int ArchString::convStringWCToMB(char *dst, const wchar_t *src, uint32_t n, bool *errors) const
|
||||
{
|
||||
ptrdiff_t len = 0;
|
||||
|
||||
bool dummyErrors;
|
||||
if (errors == NULL) {
|
||||
if (errors == nullptr) {
|
||||
errors = &dummyErrors;
|
||||
}
|
||||
*errors = false;
|
||||
|
||||
if (s_mutex == NULL) {
|
||||
if (s_mutex == nullptr) {
|
||||
s_mutex = ARCH->newMutex();
|
||||
}
|
||||
|
||||
ARCH->lockMutex(s_mutex);
|
||||
|
||||
if (dst == NULL) {
|
||||
if (dst == nullptr) {
|
||||
char dummy[MB_LEN_MAX];
|
||||
const wchar_t *scan = src;
|
||||
for (; n > 0; --n) {
|
||||
@ -55,16 +54,14 @@ int IArchString::convStringWCToMB(char *dst, const wchar_t *src, uint32_t n, boo
|
||||
len += mblen;
|
||||
++scan;
|
||||
}
|
||||
ptrdiff_t mblen = wctomb(dummy, L'\0');
|
||||
if (mblen != -1) {
|
||||
if (ptrdiff_t mblen = wctomb(dummy, L'\0'); mblen != -1) {
|
||||
len += mblen - 1;
|
||||
}
|
||||
} else {
|
||||
char *dst0 = dst;
|
||||
const char *dst0 = dst;
|
||||
const wchar_t *scan = src;
|
||||
for (; n > 0; --n) {
|
||||
ptrdiff_t mblen = wctomb(dst, *scan);
|
||||
if (mblen == -1) {
|
||||
if (ptrdiff_t mblen = wctomb(dst, *scan); mblen == -1) {
|
||||
*errors = true;
|
||||
*dst++ = '?';
|
||||
} else {
|
||||
@ -72,8 +69,7 @@ int IArchString::convStringWCToMB(char *dst, const wchar_t *src, uint32_t n, boo
|
||||
}
|
||||
++scan;
|
||||
}
|
||||
ptrdiff_t mblen = wctomb(dst, L'\0');
|
||||
if (mblen != -1) {
|
||||
if (ptrdiff_t mblen = wctomb(dst, L'\0'); mblen != -1) {
|
||||
// don't include nul terminator
|
||||
dst += mblen - 1;
|
||||
}
|
||||
@ -84,28 +80,36 @@ int IArchString::convStringWCToMB(char *dst, const wchar_t *src, uint32_t n, boo
|
||||
return static_cast<int>(len);
|
||||
}
|
||||
|
||||
int IArchString::convStringMBToWC(wchar_t *dst, const char *src, uint32_t n, bool *errors)
|
||||
ArchString::EWideCharEncoding ArchString::getWideCharEncoding() const
|
||||
{
|
||||
#ifdef SYSAPI_WIN32
|
||||
return EWideCharEncoding::kUTF16;
|
||||
#else
|
||||
return EWideCharEncoding::kUCS4;
|
||||
#endif
|
||||
}
|
||||
|
||||
int ArchString::convStringMBToWC(wchar_t *dst, const char *src, uint32_t n, bool *errors) const
|
||||
{
|
||||
ptrdiff_t len = 0;
|
||||
wchar_t dummy;
|
||||
|
||||
bool dummyErrors;
|
||||
if (errors == NULL) {
|
||||
if (errors == nullptr) {
|
||||
errors = &dummyErrors;
|
||||
}
|
||||
*errors = false;
|
||||
|
||||
if (s_mutex == NULL) {
|
||||
if (s_mutex == nullptr) {
|
||||
s_mutex = ARCH->newMutex();
|
||||
}
|
||||
|
||||
ARCH->lockMutex(s_mutex);
|
||||
|
||||
if (dst == NULL) {
|
||||
if (dst == nullptr) {
|
||||
const char *scan = src;
|
||||
while (n > 0) {
|
||||
ptrdiff_t mblen = mbtowc(&dummy, scan, n);
|
||||
switch (mblen) {
|
||||
switch (ptrdiff_t mblen = mbtowc(&dummy, scan, n); mblen) {
|
||||
case -2:
|
||||
// incomplete last character. convert to unknown character.
|
||||
*errors = true;
|
||||
@ -137,11 +141,10 @@ int IArchString::convStringMBToWC(wchar_t *dst, const char *src, uint32_t n, boo
|
||||
}
|
||||
}
|
||||
} else {
|
||||
wchar_t *dst0 = dst;
|
||||
const wchar_t *dst0 = dst;
|
||||
const char *scan = src;
|
||||
while (n > 0) {
|
||||
ptrdiff_t mblen = mbtowc(dst, scan, n);
|
||||
switch (mblen) {
|
||||
switch (ptrdiff_t mblen = mbtowc(dst, scan, n); mblen) {
|
||||
case -2:
|
||||
// incomplete character. convert to unknown character.
|
||||
*errors = true;
|
||||
@ -8,8 +8,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/Common.h"
|
||||
#include "common/IInterface.h"
|
||||
#include "common/common.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
@ -18,22 +18,22 @@
|
||||
This interface defines the string operations required by
|
||||
deskflow. Each architecture must implement this interface.
|
||||
*/
|
||||
class IArchString : public IInterface
|
||||
class ArchString : public IInterface
|
||||
{
|
||||
public:
|
||||
IArchString() = default;
|
||||
IArchString(const IArchString &) = delete;
|
||||
IArchString(IArchString &&) = delete;
|
||||
virtual ~IArchString();
|
||||
ArchString() = default;
|
||||
ArchString(const ArchString &) = delete;
|
||||
ArchString(ArchString &&) = delete;
|
||||
~ArchString() override;
|
||||
|
||||
IArchString &operator=(const IArchString &) = delete;
|
||||
IArchString &operator=(IArchString &&) = delete;
|
||||
ArchString &operator=(const ArchString &) = delete;
|
||||
ArchString &operator=(ArchString &&) = delete;
|
||||
|
||||
//! Wide character encodings
|
||||
/*!
|
||||
The known wide character encodings
|
||||
*/
|
||||
enum EWideCharEncoding
|
||||
enum class EWideCharEncoding : uint8_t
|
||||
{
|
||||
kUCS2, //!< The UCS-2 encoding
|
||||
kUCS4, //!< The UCS-4 encoding
|
||||
@ -46,13 +46,13 @@ public:
|
||||
//@{
|
||||
|
||||
//! Convert multibyte string to wide character string
|
||||
virtual int convStringMBToWC(wchar_t *, const char *, uint32_t n, bool *errors);
|
||||
int convStringMBToWC(wchar_t *, const char *, uint32_t n, bool *errors) const;
|
||||
|
||||
//! Convert wide character string to multibyte string
|
||||
virtual int convStringWCToMB(char *, const wchar_t *, uint32_t n, bool *errors);
|
||||
int convStringWCToMB(char *, const wchar_t *, uint32_t n, bool *errors) const;
|
||||
|
||||
//! Return the architecture's native wide character encoding
|
||||
virtual EWideCharEncoding getWideCharEncoding() = 0;
|
||||
EWideCharEncoding getWideCharEncoding() const;
|
||||
|
||||
//@}
|
||||
};
|
||||
@ -6,12 +6,8 @@
|
||||
# Platform Specific Code
|
||||
if(WIN32)
|
||||
set(PLATFORM_CODE
|
||||
win32/ArchConsoleWindows.cpp
|
||||
win32/ArchConsoleWindows.h
|
||||
win32/ArchDaemonWindows.cpp
|
||||
win32/ArchDaemonWindows.h
|
||||
win32/ArchFileWindows.cpp
|
||||
win32/ArchFileWindows.h
|
||||
win32/ArchLogWindows.cpp
|
||||
win32/ArchLogWindows.h
|
||||
win32/ArchMiscWindows.cpp
|
||||
@ -22,10 +18,6 @@ if(WIN32)
|
||||
win32/ArchNetworkWinsock.h
|
||||
win32/ArchSleepWindows.cpp
|
||||
win32/ArchSleepWindows.h
|
||||
win32/ArchStringWindows.cpp
|
||||
win32/ArchStringWindows.h
|
||||
win32/ArchSystemWindows.cpp
|
||||
win32/ArchSystemWindows.h
|
||||
win32/ArchTimeWindows.cpp
|
||||
win32/ArchTimeWindows.h
|
||||
win32/XArchWindows.cpp
|
||||
@ -34,12 +26,8 @@ if(WIN32)
|
||||
|
||||
elseif(UNIX)
|
||||
set(PLATFORM_CODE
|
||||
unix/ArchConsoleUnix.cpp
|
||||
unix/ArchConsoleUnix.h
|
||||
unix/ArchDaemonUnix.cpp
|
||||
unix/ArchDaemonUnix.h
|
||||
unix/ArchFileUnix.cpp
|
||||
unix/ArchFileUnix.h
|
||||
unix/ArchLogUnix.cpp
|
||||
unix/ArchLogUnix.h
|
||||
unix/ArchMultithreadPosix.cpp
|
||||
@ -48,10 +36,6 @@ elseif(UNIX)
|
||||
unix/ArchNetworkBSD.h
|
||||
unix/ArchSleepUnix.cpp
|
||||
unix/ArchSleepUnix.h
|
||||
unix/ArchStringUnix.cpp
|
||||
unix/ArchStringUnix.h
|
||||
unix/ArchSystemUnix.cpp
|
||||
unix/ArchSystemUnix.h
|
||||
unix/ArchTimeUnix.cpp
|
||||
unix/ArchTimeUnix.h
|
||||
unix/XArchUnix.cpp
|
||||
@ -62,28 +46,19 @@ endif()
|
||||
add_library(arch STATIC ${PLATFORM_CODE}
|
||||
Arch.cpp
|
||||
Arch.h
|
||||
ArchConsoleStd.cpp
|
||||
ArchConsoleStd.h
|
||||
ArchDaemonNone.cpp
|
||||
ArchDaemonNone.h
|
||||
IArchConsole.h
|
||||
IArchDaemon.h
|
||||
IArchFile.h
|
||||
IArchLog.h
|
||||
IArchMultithread.h
|
||||
IArchNetwork.h
|
||||
IArchSleep.h
|
||||
IArchString.cpp
|
||||
IArchString.h
|
||||
IArchSystem.h
|
||||
ArchString.cpp
|
||||
ArchString.h
|
||||
IArchTime.h
|
||||
multibyte.h
|
||||
XArch.h
|
||||
)
|
||||
|
||||
if(UNIX)
|
||||
target_link_libraries(arch ${libs})
|
||||
if(NOT APPLE)
|
||||
target_link_libraries(arch Qt6::DBus)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@ -1,56 +0,0 @@
|
||||
/*
|
||||
* Deskflow -- mouse and keyboard sharing utility
|
||||
* SPDX-FileCopyrightText: (C) 2012 - 2016 Symless Ltd.
|
||||
* SPDX-FileCopyrightText: (C) 2002 Chris Schoeneman
|
||||
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "base/ELevel.h"
|
||||
#include "common/IInterface.h"
|
||||
|
||||
//! Interface for architecture dependent console output
|
||||
/*!
|
||||
This interface defines the console operations required by
|
||||
deskflow. Each architecture must implement this interface.
|
||||
*/
|
||||
class IArchConsole : public IInterface
|
||||
{
|
||||
public:
|
||||
//! @name manipulators
|
||||
//@{
|
||||
|
||||
//! Open the console
|
||||
/*!
|
||||
Opens the console for writing. The console is opened automatically
|
||||
on the first write so calling this method is optional. Uses \c title
|
||||
for the console's title if appropriate for the architecture. Calling
|
||||
this method on an already open console must have no effect.
|
||||
*/
|
||||
virtual void openConsole(const char *title) = 0;
|
||||
|
||||
//! Close the console
|
||||
/*!
|
||||
Close the console. Calling this method on an already closed console
|
||||
must have no effect.
|
||||
*/
|
||||
virtual void closeConsole() = 0;
|
||||
|
||||
//! Show the console
|
||||
/*!
|
||||
Causes the console to become visible. This generally only makes sense
|
||||
for a console in a graphical user interface. Other implementations
|
||||
will do nothing. Iff \p showIfEmpty is \c false then the implementation
|
||||
may optionally only show the console if it's not empty.
|
||||
*/
|
||||
virtual void showConsole(bool showIfEmpty) = 0;
|
||||
|
||||
//! Write to the console
|
||||
/*!
|
||||
Writes the given string to the console, opening it if necessary.
|
||||
*/
|
||||
virtual void writeConsole(ELevel, const char *) = 0;
|
||||
|
||||
//@}
|
||||
};
|
||||
@ -8,6 +8,8 @@
|
||||
#pragma once
|
||||
|
||||
#include "common/IInterface.h"
|
||||
|
||||
#include <functional>
|
||||
#include <string>
|
||||
|
||||
//! Interface for architecture dependent daemonizing
|
||||
@ -19,7 +21,7 @@ implement this interface.
|
||||
class IArchDaemon : public IInterface
|
||||
{
|
||||
public:
|
||||
typedef int (*DaemonFunc)(int argc, const char **argv);
|
||||
using DaemonFunc = std::function<int(int, const char **)>;
|
||||
|
||||
//! @name manipulators
|
||||
//@{
|
||||
@ -32,7 +34,7 @@ public:
|
||||
\c commandLine should \b not include the name of program as the
|
||||
first argument. If \c allUsers is true then the daemon will be
|
||||
installed to start at boot time, otherwise it will be installed to
|
||||
start when the current user logs in. If \p dependencies is not NULL
|
||||
start when the current user logs in. If \p dependencies is not nullptr
|
||||
then it's a concatenation of NUL terminated other daemon names
|
||||
followed by a NUL; the daemon will be configured to startup after
|
||||
the listed daemons. Throws an \c XArchDaemon exception on failure.
|
||||
@ -86,7 +88,7 @@ public:
|
||||
\c ArchMiscWindows::daemonFailed() to indicate startup failure.
|
||||
</ul>
|
||||
*/
|
||||
virtual int daemonize(const char *name, DaemonFunc func) = 0;
|
||||
virtual int daemonize(const char *name, DaemonFunc const &func) = 0;
|
||||
|
||||
//! Check if user has permission to install the daemon
|
||||
/*!
|
||||
|
||||
@ -1,92 +0,0 @@
|
||||
/*
|
||||
* Deskflow -- mouse and keyboard sharing utility
|
||||
* SPDX-FileCopyrightText: (C) 2012 - 2016 Symless Ltd.
|
||||
* SPDX-FileCopyrightText: (C) 2002 Chris Schoeneman
|
||||
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/IInterface.h"
|
||||
#include <string>
|
||||
|
||||
//! Interface for architecture dependent file system operations
|
||||
/*!
|
||||
This interface defines the file system operations required by
|
||||
deskflow. Each architecture must implement this interface.
|
||||
*/
|
||||
class IArchFile : public IInterface
|
||||
{
|
||||
public:
|
||||
//! @name manipulators
|
||||
//@{
|
||||
|
||||
//! Extract base name
|
||||
/*!
|
||||
Find the base name in the given \c pathname.
|
||||
*/
|
||||
virtual const char *getBasename(const char *pathname) = 0;
|
||||
|
||||
//! Get user's home directory
|
||||
/*!
|
||||
Returns the user's home directory. Returns the empty string if
|
||||
this cannot be determined.
|
||||
*/
|
||||
virtual std::string getUserDirectory() = 0;
|
||||
|
||||
//! Get system directory
|
||||
/*!
|
||||
Returns the ussystem configuration file directory.
|
||||
*/
|
||||
virtual std::string getSystemDirectory() = 0;
|
||||
|
||||
//! Get installed directory
|
||||
/*!
|
||||
Returns the directory in which Deskflow is installed.
|
||||
*/
|
||||
virtual std::string getInstalledDirectory() = 0;
|
||||
|
||||
//! Get log directory
|
||||
/*!
|
||||
Returns the log file directory.
|
||||
*/
|
||||
virtual std::string getLogDirectory() = 0;
|
||||
|
||||
//! Get plugins directory
|
||||
/*!
|
||||
Returns the plugin files directory. If no plugin directory is set,
|
||||
this will return the plugin folder within the user's profile.
|
||||
*/
|
||||
virtual std::string getPluginDirectory() = 0;
|
||||
|
||||
//! Get user's profile directory
|
||||
/*!
|
||||
Returns the user's profile directory. If no profile directory is set,
|
||||
this will return the user's profile according to the operating system,
|
||||
which will depend on which user launched the program.
|
||||
*/
|
||||
virtual std::string getProfileDirectory() = 0;
|
||||
|
||||
//! Concatenate path components
|
||||
/*!
|
||||
Concatenate pathname components with a directory separator
|
||||
between them. This should not check if the resulting path
|
||||
is longer than allowed by the system; we'll rely on the
|
||||
system calls to tell us that.
|
||||
*/
|
||||
virtual std::string concatPath(const std::string &prefix, const std::string &suffix) = 0;
|
||||
|
||||
//@}
|
||||
//! Set the user's profile directory
|
||||
/*
|
||||
Returns the user's profile directory.
|
||||
*/
|
||||
virtual void setProfileDirectory(const std::string &s) = 0;
|
||||
|
||||
//@}
|
||||
//! Set the user's plugin directory
|
||||
/*
|
||||
Returns the user's plugin directory.
|
||||
*/
|
||||
virtual void setPluginDirectory(const std::string &s) = 0;
|
||||
};
|
||||
@ -61,7 +61,7 @@ class IArchMultithread : public IInterface
|
||||
{
|
||||
public:
|
||||
//! Type of thread entry point
|
||||
typedef void *(*ThreadFunc)(void *);
|
||||
using ThreadFunc = void *(*)(void *);
|
||||
//! Type of thread identifier
|
||||
using ThreadID = unsigned int;
|
||||
//! Types of signals
|
||||
@ -78,7 +78,7 @@ public:
|
||||
kNUM_SIGNALS
|
||||
};
|
||||
//! Type of signal handler function
|
||||
typedef void (*SignalFunc)(ESignal, void *userData);
|
||||
using SignalFunc = void (*)(ESignal, void *userData);
|
||||
|
||||
//! @name manipulators
|
||||
//@{
|
||||
@ -247,7 +247,7 @@ public:
|
||||
//! Set the interrupt handler
|
||||
/*!
|
||||
Sets the function to call on receipt of an external interrupt.
|
||||
By default and when \p func is NULL, the main thread is cancelled.
|
||||
By default and when \p func is nullptr, the main thread is cancelled.
|
||||
*/
|
||||
virtual void setSignalHandler(ESignal, SignalFunc func, void *userData) = 0;
|
||||
|
||||
|
||||
@ -149,10 +149,10 @@ public:
|
||||
/*!
|
||||
Accepts a connection on socket \c s, returning a new socket for the
|
||||
connection and filling in \c addr with the address of the remote
|
||||
end. \c addr may be NULL if the remote address isn't required.
|
||||
end. \c addr may be nullptr if the remote address isn't required.
|
||||
The original socket \c s is unaffected and remains in the listening
|
||||
state. The new socket shares most of the properties of \c s except
|
||||
it's not in the listening state and it's connected. Returns NULL
|
||||
it's not in the listening state and it's connected. Returns nullptr
|
||||
if there are no pending connection requests.
|
||||
*/
|
||||
virtual ArchSocket acceptSocket(ArchSocket s, ArchNetAddress *addr) = 0;
|
||||
|
||||
@ -1,56 +0,0 @@
|
||||
/*
|
||||
* Deskflow -- mouse and keyboard sharing utility
|
||||
* SPDX-FileCopyrightText: (C) 2012 - 2016 Symless Ltd.
|
||||
* SPDX-FileCopyrightText: (C) 2004 Chris Schoeneman
|
||||
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/IInterface.h"
|
||||
#include <string>
|
||||
|
||||
//! Interface for architecture dependent system queries
|
||||
/*!
|
||||
This interface defines operations for querying system info.
|
||||
*/
|
||||
class IArchSystem : public IInterface
|
||||
{
|
||||
public:
|
||||
//! @name accessors
|
||||
//@{
|
||||
|
||||
//! Identify the OS
|
||||
/*!
|
||||
Returns a string identifying the operating system.
|
||||
*/
|
||||
virtual std::string getOSName() const = 0;
|
||||
|
||||
//! Identify the platform
|
||||
/*!
|
||||
Returns a string identifying the platform this OS is running on.
|
||||
*/
|
||||
virtual std::string getPlatformName() const = 0;
|
||||
//@}
|
||||
|
||||
//! Get a Deskflow setting
|
||||
/*!
|
||||
Reads a Deskflow setting from the system.
|
||||
*/
|
||||
virtual std::string setting(const std::string &valueName) const = 0;
|
||||
//@}
|
||||
|
||||
//! Set a Deskflow setting
|
||||
/*!
|
||||
Writes a Deskflow setting from the system.
|
||||
*/
|
||||
virtual void setting(const std::string &valueName, const std::string &valueString) const = 0;
|
||||
//@}
|
||||
|
||||
//! Delete settings
|
||||
/*!
|
||||
Deletes all Core settings from the system.
|
||||
*/
|
||||
virtual void clearSettings() const = 0;
|
||||
//@}
|
||||
};
|
||||
@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Deskflow -- mouse and keyboard sharing utility
|
||||
* SPDX-FileCopyrightText: (C) 2025 Deskflow Developers
|
||||
* SPDX-FileCopyrightText: (C) 2012 - 2016 Symless Ltd.
|
||||
* SPDX-FileCopyrightText: (C) 2002 Chris Schoeneman
|
||||
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
|
||||
@ -7,8 +8,9 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/common.h"
|
||||
#include "common/stdexcept.h"
|
||||
#include "common/Common.h"
|
||||
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
//! Generic thread exception
|
||||
@ -17,7 +19,7 @@ Exceptions derived from this class are used by the multithreading
|
||||
library to perform stack unwinding when a thread terminates. These
|
||||
exceptions must always be rethrown by clients when caught.
|
||||
*/
|
||||
class XThread
|
||||
class XThread : public std::exception
|
||||
{
|
||||
};
|
||||
|
||||
@ -44,134 +46,160 @@ cleanup but before leaving or returning from the handler.
|
||||
} catch (...) { \
|
||||
}
|
||||
|
||||
//! Lazy error message string evaluation
|
||||
/*!
|
||||
This class encapsulates platform dependent error string lookup.
|
||||
Platforms subclass this type, taking an appropriate error code
|
||||
type in the c'tor and overriding eval() to return the error
|
||||
string for that error code.
|
||||
*/
|
||||
class XArchEval
|
||||
{
|
||||
public:
|
||||
XArchEval()
|
||||
{
|
||||
}
|
||||
virtual ~XArchEval() _NOEXCEPT
|
||||
{
|
||||
}
|
||||
|
||||
virtual std::string eval() const = 0;
|
||||
};
|
||||
|
||||
//! Generic exception architecture dependent library
|
||||
class XArch : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
XArch(XArchEval *adopted) : std::runtime_error(adopted->eval())
|
||||
{
|
||||
delete adopted;
|
||||
}
|
||||
XArch(const std::string &msg) : std::runtime_error(msg)
|
||||
{
|
||||
}
|
||||
virtual ~XArch() _NOEXCEPT
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
// Macro to declare XArch derived types
|
||||
#define XARCH_SUBCLASS(name_, super_) \
|
||||
class name_ : public super_ \
|
||||
{ \
|
||||
public: \
|
||||
name_(XArchEval *adoptedEvaluator) : super_(adoptedEvaluator) \
|
||||
{ \
|
||||
} \
|
||||
name_(const std::string &msg) : super_(msg) \
|
||||
{ \
|
||||
} \
|
||||
}
|
||||
|
||||
//! Generic network exception
|
||||
/*!
|
||||
Exceptions derived from this class are used by the networking
|
||||
library to indicate various errors.
|
||||
*/
|
||||
XARCH_SUBCLASS(XArchNetwork, XArch);
|
||||
class XArchNetwork : public std::runtime_error
|
||||
{
|
||||
using std::runtime_error::runtime_error;
|
||||
};
|
||||
|
||||
//! Operation was interrupted
|
||||
XARCH_SUBCLASS(XArchNetworkInterrupted, XArchNetwork);
|
||||
class XArchNetworkInterrupted : public XArchNetwork
|
||||
{
|
||||
using XArchNetwork::XArchNetwork;
|
||||
};
|
||||
|
||||
//! Network insufficient permission
|
||||
XARCH_SUBCLASS(XArchNetworkAccess, XArchNetwork);
|
||||
class XArchNetworkAccess : public XArchNetwork
|
||||
{
|
||||
using XArchNetwork::XArchNetwork;
|
||||
};
|
||||
|
||||
//! Network insufficient resources
|
||||
XARCH_SUBCLASS(XArchNetworkResource, XArchNetwork);
|
||||
class XArchNetworkResource : public XArchNetwork
|
||||
{
|
||||
using XArchNetwork::XArchNetwork;
|
||||
};
|
||||
|
||||
//! No support for requested network resource/service
|
||||
XARCH_SUBCLASS(XArchNetworkSupport, XArchNetwork);
|
||||
class XArchNetworkSupport : public XArchNetwork
|
||||
{
|
||||
using XArchNetwork::XArchNetwork;
|
||||
};
|
||||
|
||||
//! Network I/O error
|
||||
XARCH_SUBCLASS(XArchNetworkIO, XArchNetwork);
|
||||
class XArchNetworkIO : public XArchNetwork
|
||||
{
|
||||
using XArchNetwork::XArchNetwork;
|
||||
};
|
||||
|
||||
//! Network address is unavailable or not local
|
||||
XARCH_SUBCLASS(XArchNetworkNoAddress, XArchNetwork);
|
||||
class XArchNetworkNoAddress : public XArchNetwork
|
||||
{
|
||||
using XArchNetwork::XArchNetwork;
|
||||
};
|
||||
|
||||
//! Network address in use
|
||||
XARCH_SUBCLASS(XArchNetworkAddressInUse, XArchNetwork);
|
||||
class XArchNetworkAddressInUse : public XArchNetwork
|
||||
{
|
||||
using XArchNetwork::XArchNetwork;
|
||||
};
|
||||
|
||||
//! No route to address
|
||||
XARCH_SUBCLASS(XArchNetworkNoRoute, XArchNetwork);
|
||||
class XArchNetworkNoRoute : public XArchNetwork
|
||||
{
|
||||
using XArchNetwork::XArchNetwork;
|
||||
};
|
||||
|
||||
//! Socket not connected
|
||||
XARCH_SUBCLASS(XArchNetworkNotConnected, XArchNetwork);
|
||||
class XArchNetworkNotConnected : public XArchNetwork
|
||||
{
|
||||
using XArchNetwork::XArchNetwork;
|
||||
};
|
||||
|
||||
//! Remote read end of socket has closed
|
||||
XARCH_SUBCLASS(XArchNetworkShutdown, XArchNetwork);
|
||||
class XArchNetworkShutdown : public XArchNetwork
|
||||
{
|
||||
using XArchNetwork::XArchNetwork;
|
||||
};
|
||||
|
||||
//! Remote end of socket has disconnected
|
||||
XARCH_SUBCLASS(XArchNetworkDisconnected, XArchNetwork);
|
||||
class XArchNetworkDisconnected : public XArchNetwork
|
||||
{
|
||||
using XArchNetwork::XArchNetwork;
|
||||
};
|
||||
|
||||
//! Remote end of socket refused connection
|
||||
XARCH_SUBCLASS(XArchNetworkConnectionRefused, XArchNetwork);
|
||||
class XArchNetworkConnectionRefused : public XArchNetwork
|
||||
{
|
||||
using XArchNetwork::XArchNetwork;
|
||||
};
|
||||
|
||||
//! Remote end of socket is not responding
|
||||
XARCH_SUBCLASS(XArchNetworkTimedOut, XArchNetwork);
|
||||
class XArchNetworkTimedOut : public XArchNetwork
|
||||
{
|
||||
using XArchNetwork::XArchNetwork;
|
||||
};
|
||||
|
||||
//! Generic network name lookup erros
|
||||
XARCH_SUBCLASS(XArchNetworkName, XArchNetwork);
|
||||
class XArchNetworkName : public XArchNetwork
|
||||
{
|
||||
using XArchNetwork::XArchNetwork;
|
||||
};
|
||||
|
||||
//! The named host is unknown
|
||||
XARCH_SUBCLASS(XArchNetworkNameUnknown, XArchNetworkName);
|
||||
class XArchNetworkNameUnknown : public XArchNetworkName
|
||||
{
|
||||
using XArchNetworkName::XArchNetworkName;
|
||||
};
|
||||
|
||||
//! The named host is known but has no address
|
||||
XARCH_SUBCLASS(XArchNetworkNameNoAddress, XArchNetworkName);
|
||||
class XArchNetworkNameNoAddress : public XArchNetworkName
|
||||
{
|
||||
using XArchNetworkName::XArchNetworkName;
|
||||
};
|
||||
|
||||
//! Non-recoverable name server error
|
||||
XARCH_SUBCLASS(XArchNetworkNameFailure, XArchNetworkName);
|
||||
class XArchNetworkNameFailure : public XArchNetworkName
|
||||
{
|
||||
using XArchNetworkName::XArchNetworkName;
|
||||
};
|
||||
|
||||
//! Temporary name server error
|
||||
XARCH_SUBCLASS(XArchNetworkNameUnavailable, XArchNetworkName);
|
||||
class XArchNetworkNameUnavailable : public XArchNetworkName
|
||||
{
|
||||
using XArchNetworkName::XArchNetworkName;
|
||||
};
|
||||
|
||||
//! The named host is known but no supported address
|
||||
XARCH_SUBCLASS(XArchNetworkNameUnsupported, XArchNetworkName);
|
||||
class XArchNetworkNameUnsupported : public XArchNetworkName
|
||||
{
|
||||
using XArchNetworkName::XArchNetworkName;
|
||||
};
|
||||
|
||||
//! Generic daemon exception
|
||||
/*!
|
||||
Exceptions derived from this class are used by the daemon
|
||||
library to indicate various errors.
|
||||
*/
|
||||
XARCH_SUBCLASS(XArchDaemon, XArch);
|
||||
class XArchDaemon : public std::runtime_error
|
||||
{
|
||||
using std::runtime_error::runtime_error;
|
||||
};
|
||||
|
||||
//! Could not daemonize
|
||||
XARCH_SUBCLASS(XArchDaemonFailed, XArchDaemon);
|
||||
class XArchDaemonFailed : public XArchDaemon
|
||||
{
|
||||
using XArchDaemon::XArchDaemon;
|
||||
};
|
||||
|
||||
//! Could not install daemon
|
||||
XARCH_SUBCLASS(XArchDaemonInstallFailed, XArchDaemon);
|
||||
class XArchDaemonInstallFailed : public XArchDaemon
|
||||
{
|
||||
using XArchDaemon::XArchDaemon;
|
||||
};
|
||||
|
||||
//! Could not uninstall daemon
|
||||
XARCH_SUBCLASS(XArchDaemonUninstallFailed, XArchDaemon);
|
||||
class XArchDaemonUninstallFailed : public XArchDaemon
|
||||
{
|
||||
using XArchDaemon::XArchDaemon;
|
||||
};
|
||||
|
||||
//! Attempted to uninstall a daemon that was not installed
|
||||
XARCH_SUBCLASS(XArchDaemonUninstallNotInstalled, XArchDaemonUninstallFailed);
|
||||
class XArchDaemonUninstallNotInstalled : public XArchDaemonFailed
|
||||
{
|
||||
using XArchDaemonFailed::XArchDaemonFailed;
|
||||
};
|
||||
|
||||
@ -1,41 +0,0 @@
|
||||
/*
|
||||
* Deskflow -- mouse and keyboard sharing utility
|
||||
* SPDX-FileCopyrightText: (C) 2012 - 2016 Symless Ltd.
|
||||
* SPDX-FileCopyrightText: (C) 2002 Chris Schoeneman
|
||||
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "arch/Arch.h"
|
||||
#include "common/common.h"
|
||||
|
||||
#include <climits>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#if HAVE_LOCALE_H
|
||||
#include <locale.h>
|
||||
#endif
|
||||
#if HAVE_WCHAR_H || defined(_MSC_VER)
|
||||
#include <wchar.h>
|
||||
#elif __APPLE__
|
||||
// wtf? Darwin puts mbtowc() et al. in stdlib
|
||||
#include <cstdlib>
|
||||
#else
|
||||
// platform apparently has no wchar_t support. provide dummy
|
||||
// implementations. hopefully at least the C++ compiler has
|
||||
// a built-in wchar_t type.
|
||||
|
||||
static inline int mbtowc(wchar_t *dst, const char *src, int n)
|
||||
{
|
||||
*dst = static_cast<wchar_t>(*src);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline int wctomb(char *dst, wchar_t src)
|
||||
{
|
||||
*dst = static_cast<char>(src);
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -1,16 +0,0 @@
|
||||
/*
|
||||
* Deskflow -- mouse and keyboard sharing utility
|
||||
* SPDX-FileCopyrightText: (C) 2012 - 2016 Symless Ltd.
|
||||
* SPDX-FileCopyrightText: (C) 2002 Chris Schoeneman
|
||||
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
|
||||
*/
|
||||
|
||||
#include "arch/unix/ArchConsoleUnix.h"
|
||||
|
||||
ArchConsoleUnix::ArchConsoleUnix()
|
||||
{
|
||||
}
|
||||
|
||||
ArchConsoleUnix::~ArchConsoleUnix()
|
||||
{
|
||||
}
|
||||
@ -1,19 +0,0 @@
|
||||
/*
|
||||
* Deskflow -- mouse and keyboard sharing utility
|
||||
* SPDX-FileCopyrightText: (C) 2012 - 2016 Symless Ltd.
|
||||
* SPDX-FileCopyrightText: (C) 2002 Chris Schoeneman
|
||||
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "arch/ArchConsoleStd.h"
|
||||
|
||||
#define ARCH_CONSOLE ArchConsoleUnix
|
||||
|
||||
class ArchConsoleUnix : public ArchConsoleStd
|
||||
{
|
||||
public:
|
||||
ArchConsoleUnix();
|
||||
virtual ~ArchConsoleUnix();
|
||||
};
|
||||
@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Deskflow -- mouse and keyboard sharing utility
|
||||
* SPDX-FileCopyrightText: (C) 2025 Deskflow Developers
|
||||
* SPDX-FileCopyrightText: (C) 2012 - 2016 Symless Ltd.
|
||||
* SPDX-FileCopyrightText: (C) 2002 Chris Schoeneman
|
||||
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
|
||||
@ -7,6 +8,7 @@
|
||||
|
||||
#include "arch/unix/ArchDaemonUnix.h"
|
||||
|
||||
#include "arch/XArch.h"
|
||||
#include "arch/unix/XArchUnix.h"
|
||||
#include "base/Log.h"
|
||||
|
||||
@ -21,16 +23,6 @@
|
||||
// ArchDaemonUnix
|
||||
//
|
||||
|
||||
ArchDaemonUnix::ArchDaemonUnix()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
ArchDaemonUnix::~ArchDaemonUnix()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
#ifdef __APPLE__
|
||||
|
||||
// In Mac OS X, fork()'d child processes can't use most APIs (the frameworks
|
||||
@ -49,12 +41,12 @@ int execSelfNonDaemonized()
|
||||
|
||||
bool alreadyDaemonized()
|
||||
{
|
||||
return getenv("_DESKFLOW_DAEMONIZED") != NULL;
|
||||
return getenv("_DESKFLOW_DAEMONIZED") != nullptr;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int ArchDaemonUnix::daemonize(const char *name, DaemonFunc func)
|
||||
int ArchDaemonUnix::daemonize(const char *name, DaemonFunc const &func)
|
||||
{
|
||||
#ifdef __APPLE__
|
||||
if (alreadyDaemonized())
|
||||
@ -66,7 +58,7 @@ int ArchDaemonUnix::daemonize(const char *name, DaemonFunc func)
|
||||
switch (fork()) {
|
||||
case -1:
|
||||
// failed
|
||||
throw XArchDaemonFailed(new XArchEvalUnix(errno));
|
||||
throw XArchDaemonFailed(errorToString(errno));
|
||||
|
||||
case 0:
|
||||
// child
|
||||
@ -84,8 +76,7 @@ int ArchDaemonUnix::daemonize(const char *name, DaemonFunc func)
|
||||
// NB: don't run chdir on apple; causes strange behaviour.
|
||||
// chdir to root so we don't keep mounted filesystems points busy
|
||||
// TODO: this is a bit of a hack - can we find a better solution?
|
||||
int chdirErr = chdir("/");
|
||||
if (chdirErr)
|
||||
if (int chdirErr = chdir("/"); chdirErr)
|
||||
// NB: file logging actually isn't working at this point!
|
||||
LOG((CLOG_ERR "chdir error: %i", chdirErr));
|
||||
#endif
|
||||
@ -103,9 +94,7 @@ int ArchDaemonUnix::daemonize(const char *name, DaemonFunc func)
|
||||
open("/dev/null", O_RDONLY);
|
||||
open("/dev/null", O_RDWR);
|
||||
|
||||
int dupErr = dup(1);
|
||||
|
||||
if (dupErr < 0) {
|
||||
if (int dupErr = dup(1); dupErr < 0) {
|
||||
// NB: file logging actually isn't working at this point!
|
||||
LOG((CLOG_ERR "dup error: %i", dupErr));
|
||||
}
|
||||
|
||||
@ -16,9 +16,9 @@
|
||||
class ArchDaemonUnix : public ArchDaemonNone
|
||||
{
|
||||
public:
|
||||
ArchDaemonUnix();
|
||||
virtual ~ArchDaemonUnix();
|
||||
ArchDaemonUnix() = default;
|
||||
~ArchDaemonUnix() override = default;
|
||||
|
||||
// IArchDaemon overrides
|
||||
virtual int daemonize(const char *name, DaemonFunc func);
|
||||
int daemonize(const char *name, DaemonFunc const &func) override;
|
||||
};
|
||||
|
||||
@ -1,146 +0,0 @@
|
||||
/*
|
||||
* Deskflow -- mouse and keyboard sharing utility
|
||||
* SPDX-FileCopyrightText: (C) 2012 - 2016 Symless Ltd.
|
||||
* SPDX-FileCopyrightText: (C) 2002 Chris Schoeneman
|
||||
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
|
||||
*/
|
||||
|
||||
#include "arch/unix/ArchFileUnix.h"
|
||||
|
||||
#include "common/constants.h"
|
||||
#include <cstring>
|
||||
#include <filesystem>
|
||||
#include <pwd.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
//
|
||||
// ArchFileUnix
|
||||
//
|
||||
|
||||
ArchFileUnix::ArchFileUnix()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
ArchFileUnix::~ArchFileUnix()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
const char *ArchFileUnix::getBasename(const char *pathname)
|
||||
{
|
||||
if (pathname == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char *basename = strrchr(pathname, '/');
|
||||
if (basename != NULL) {
|
||||
return basename + 1;
|
||||
} else {
|
||||
return pathname;
|
||||
}
|
||||
}
|
||||
|
||||
std::string ArchFileUnix::getUserDirectory()
|
||||
{
|
||||
char *buffer = NULL;
|
||||
std::string dir;
|
||||
#if HAVE_GETPWUID_R
|
||||
struct passwd pwent;
|
||||
struct passwd *pwentp{};
|
||||
#if defined(_SC_GETPW_R_SIZE_MAX)
|
||||
long size = sysconf(_SC_GETPW_R_SIZE_MAX);
|
||||
if (size == -1) {
|
||||
size = BUFSIZ;
|
||||
}
|
||||
#else
|
||||
long size = BUFSIZ;
|
||||
#endif
|
||||
buffer = new char[size];
|
||||
getpwuid_r(getuid(), &pwent, buffer, size, &pwentp);
|
||||
#else
|
||||
struct passwd *pwentp = getpwuid(getuid());
|
||||
#endif
|
||||
if (pwentp != NULL && pwentp->pw_dir != NULL) {
|
||||
dir = pwentp->pw_dir;
|
||||
}
|
||||
delete[] buffer;
|
||||
return dir;
|
||||
}
|
||||
|
||||
std::string ArchFileUnix::getSystemDirectory()
|
||||
{
|
||||
return "/etc";
|
||||
}
|
||||
|
||||
std::string ArchFileUnix::getInstalledDirectory()
|
||||
{
|
||||
#if WINAPI_XWINDOWS
|
||||
return "/usr/bin";
|
||||
#else
|
||||
std::string rtn = "/Applications/";
|
||||
rtn.append(kAppName).append(".app/Contents/MacOS");
|
||||
return rtn;
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string ArchFileUnix::getLogDirectory()
|
||||
{
|
||||
return "/var/log";
|
||||
}
|
||||
|
||||
std::string ArchFileUnix::getPluginDirectory()
|
||||
{
|
||||
if (!m_pluginDirectory.empty()) {
|
||||
return m_pluginDirectory;
|
||||
}
|
||||
|
||||
#if WINAPI_XWINDOWS
|
||||
return getProfileDirectory().append("/plugins");
|
||||
#else
|
||||
return getProfileDirectory().append("/Plugins");
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string ArchFileUnix::getProfileDirectory()
|
||||
{
|
||||
if (!m_profileDirectory.empty()) {
|
||||
return m_profileDirectory;
|
||||
} else {
|
||||
const std::filesystem::path homeDir = getUserDirectory();
|
||||
#if WINAPI_XWINDOWS
|
||||
const auto xdgDir = std::getenv("XDG_CONFIG_HOME");
|
||||
if (xdgDir != nullptr) {
|
||||
return std::filesystem::path(xdgDir) / kAppName;
|
||||
} else {
|
||||
return homeDir / ".config" / kAppName;
|
||||
}
|
||||
#else
|
||||
return homeDir / "Library" / kAppName;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
std::string ArchFileUnix::concatPath(const std::string &prefix, const std::string &suffix)
|
||||
{
|
||||
std::string path;
|
||||
path.reserve(prefix.size() + 1 + suffix.size());
|
||||
path += prefix;
|
||||
if (path.size() == 0 || path[path.size() - 1] != '/') {
|
||||
path += '/';
|
||||
}
|
||||
path += suffix;
|
||||
return path;
|
||||
}
|
||||
|
||||
void ArchFileUnix::setProfileDirectory(const std::string &s)
|
||||
{
|
||||
m_profileDirectory = s;
|
||||
}
|
||||
|
||||
void ArchFileUnix::setPluginDirectory(const std::string &s)
|
||||
{
|
||||
m_pluginDirectory = s;
|
||||
}
|
||||
@ -1,36 +0,0 @@
|
||||
/*
|
||||
* Deskflow -- mouse and keyboard sharing utility
|
||||
* SPDX-FileCopyrightText: (C) 2012 - 2016 Symless Ltd.
|
||||
* SPDX-FileCopyrightText: (C) 2002 Chris Schoeneman
|
||||
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "arch/IArchFile.h"
|
||||
|
||||
#define ARCH_FILE ArchFileUnix
|
||||
|
||||
//! Unix implementation of IArchFile
|
||||
class ArchFileUnix : public IArchFile
|
||||
{
|
||||
public:
|
||||
ArchFileUnix();
|
||||
virtual ~ArchFileUnix();
|
||||
|
||||
// IArchFile overrides
|
||||
virtual const char *getBasename(const char *pathname);
|
||||
virtual std::string getUserDirectory();
|
||||
virtual std::string getSystemDirectory();
|
||||
virtual std::string getInstalledDirectory();
|
||||
virtual std::string getLogDirectory();
|
||||
virtual std::string getPluginDirectory();
|
||||
virtual std::string getProfileDirectory();
|
||||
virtual std::string concatPath(const std::string &prefix, const std::string &suffix);
|
||||
virtual void setProfileDirectory(const std::string &s);
|
||||
virtual void setPluginDirectory(const std::string &s);
|
||||
|
||||
private:
|
||||
std::string m_profileDirectory;
|
||||
std::string m_pluginDirectory;
|
||||
};
|
||||
@ -13,16 +13,6 @@
|
||||
// ArchLogUnix
|
||||
//
|
||||
|
||||
ArchLogUnix::ArchLogUnix()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
ArchLogUnix::~ArchLogUnix()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
void ArchLogUnix::openLog(const char *name)
|
||||
{
|
||||
openlog(name, 0, LOG_DAEMON);
|
||||
|
||||
@ -15,12 +15,12 @@
|
||||
class ArchLogUnix : public IArchLog
|
||||
{
|
||||
public:
|
||||
ArchLogUnix();
|
||||
virtual ~ArchLogUnix();
|
||||
ArchLogUnix() = default;
|
||||
~ArchLogUnix() override = default;
|
||||
|
||||
// IArchLog overrides
|
||||
virtual void openLog(const char *name);
|
||||
virtual void closeLog();
|
||||
virtual void showLog(bool);
|
||||
virtual void writeLog(ELevel, const char *);
|
||||
void openLog(const char *name) override;
|
||||
void closeLog() override;
|
||||
void showLog(bool) override;
|
||||
void writeLog(ELevel, const char *) override;
|
||||
};
|
||||
|
||||
@ -52,51 +52,37 @@ static void setSignalSet(sigset_t *sigset)
|
||||
class ArchThreadImpl
|
||||
{
|
||||
public:
|
||||
ArchThreadImpl();
|
||||
ArchThreadImpl() = default;
|
||||
|
||||
public:
|
||||
int m_refCount;
|
||||
IArchMultithread::ThreadID m_id;
|
||||
int m_refCount = 1;
|
||||
IArchMultithread::ThreadID m_id = 0;
|
||||
pthread_t m_thread;
|
||||
IArchMultithread::ThreadFunc m_func;
|
||||
void *m_userData;
|
||||
bool m_cancel;
|
||||
bool m_cancelling;
|
||||
bool m_exited;
|
||||
void *m_result;
|
||||
void *m_networkData;
|
||||
IArchMultithread::ThreadFunc m_func = nullptr;
|
||||
void *m_userData = nullptr;
|
||||
bool m_cancel = false;
|
||||
bool m_cancelling = false;
|
||||
bool m_exited = false;
|
||||
void *m_result = nullptr;
|
||||
void *m_networkData = nullptr;
|
||||
};
|
||||
|
||||
ArchThreadImpl::ArchThreadImpl()
|
||||
: m_refCount(1),
|
||||
m_id(0),
|
||||
m_func(NULL),
|
||||
m_userData(NULL),
|
||||
m_cancel(false),
|
||||
m_cancelling(false),
|
||||
m_exited(false),
|
||||
m_result(NULL),
|
||||
m_networkData(NULL)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
//
|
||||
// ArchMultithreadPosix
|
||||
//
|
||||
|
||||
ArchMultithreadPosix *ArchMultithreadPosix::s_instance = NULL;
|
||||
ArchMultithreadPosix *ArchMultithreadPosix::s_instance = nullptr;
|
||||
|
||||
ArchMultithreadPosix::ArchMultithreadPosix() : m_newThreadCalled(false), m_nextID(0)
|
||||
ArchMultithreadPosix::ArchMultithreadPosix()
|
||||
{
|
||||
assert(s_instance == NULL);
|
||||
assert(s_instance == nullptr);
|
||||
|
||||
s_instance = this;
|
||||
|
||||
// no signal handlers
|
||||
for (size_t i = 0; i < kNUM_SIGNALS; ++i) {
|
||||
m_signalFunc[i] = NULL;
|
||||
m_signalUserData[i] = NULL;
|
||||
m_signalFunc[i] = nullptr;
|
||||
m_signalUserData[i] = nullptr;
|
||||
}
|
||||
|
||||
// create mutex for thread list
|
||||
@ -121,25 +107,25 @@ ArchMultithreadPosix::ArchMultithreadPosix() : m_newThreadCalled(false), m_nextI
|
||||
act.sa_flags = 0;
|
||||
#endif
|
||||
act.sa_handler = &threadCancel;
|
||||
sigaction(SIGWAKEUP, &act, NULL);
|
||||
sigaction(SIGWAKEUP, &act, nullptr);
|
||||
|
||||
// set desired signal dispositions. let SIGWAKEUP through but
|
||||
// ignore SIGPIPE (we'll handle EPIPE).
|
||||
sigset_t sigset;
|
||||
sigemptyset(&sigset);
|
||||
sigaddset(&sigset, SIGWAKEUP);
|
||||
pthread_sigmask(SIG_UNBLOCK, &sigset, NULL);
|
||||
pthread_sigmask(SIG_UNBLOCK, &sigset, nullptr);
|
||||
sigemptyset(&sigset);
|
||||
sigaddset(&sigset, SIGPIPE);
|
||||
pthread_sigmask(SIG_BLOCK, &sigset, NULL);
|
||||
pthread_sigmask(SIG_BLOCK, &sigset, nullptr);
|
||||
}
|
||||
|
||||
ArchMultithreadPosix::~ArchMultithreadPosix()
|
||||
{
|
||||
assert(s_instance != NULL);
|
||||
assert(s_instance != nullptr);
|
||||
|
||||
closeMutex(m_threadMutex);
|
||||
s_instance = NULL;
|
||||
s_instance = nullptr;
|
||||
}
|
||||
|
||||
void ArchMultithreadPosix::setNetworkDataForCurrentThread(void *data)
|
||||
@ -165,8 +151,8 @@ ArchMultithreadPosix *ArchMultithreadPosix::getInstance()
|
||||
|
||||
ArchCond ArchMultithreadPosix::newCondVar()
|
||||
{
|
||||
ArchCondImpl *cond = new ArchCondImpl;
|
||||
int status = pthread_cond_init(&cond->m_cond, NULL);
|
||||
auto *cond = new ArchCondImpl;
|
||||
int status = pthread_cond_init(&cond->m_cond, nullptr);
|
||||
(void)status;
|
||||
assert(status == 0);
|
||||
return cond;
|
||||
@ -204,8 +190,7 @@ bool ArchMultithreadPosix::waitCondVar(ArchCond cond, ArchMutex mutex, double ti
|
||||
// so we have to return to the caller. since the caller will
|
||||
// always check for spurious wakeups the only drawback here is
|
||||
// performance: we're waking up a lot more than desired.
|
||||
static const double maxCancellationLatency = 0.1;
|
||||
if (timeout < 0.0 || timeout > maxCancellationLatency) {
|
||||
if (static const double maxCancellationLatency = 0.1; timeout < 0.0 || timeout > maxCancellationLatency) {
|
||||
timeout = maxCancellationLatency;
|
||||
}
|
||||
|
||||
@ -214,12 +199,12 @@ bool ArchMultithreadPosix::waitCondVar(ArchCond cond, ArchMutex mutex, double ti
|
||||
|
||||
// get final time
|
||||
struct timeval now;
|
||||
gettimeofday(&now, NULL);
|
||||
gettimeofday(&now, nullptr);
|
||||
struct timespec finalTime;
|
||||
finalTime.tv_sec = now.tv_sec;
|
||||
finalTime.tv_nsec = now.tv_usec * 1000;
|
||||
long timeout_sec = (long)timeout;
|
||||
long timeout_nsec = (long)(1.0e+9 * (timeout - timeout_sec));
|
||||
auto timeout_sec = (long)timeout;
|
||||
auto timeout_nsec = (long)(1.0e+9 * (timeout - timeout_sec));
|
||||
finalTime.tv_sec += timeout_sec;
|
||||
finalTime.tv_nsec += timeout_nsec;
|
||||
if (finalTime.tv_nsec >= 1000000000) {
|
||||
@ -252,7 +237,7 @@ ArchMutex ArchMultithreadPosix::newMutex()
|
||||
pthread_mutexattr_t attr;
|
||||
int status = pthread_mutexattr_init(&attr);
|
||||
assert(status == 0);
|
||||
ArchMutexImpl *mutex = new ArchMutexImpl;
|
||||
auto *mutex = new ArchMutexImpl;
|
||||
status = pthread_mutex_init(&mutex->m_mutex, &attr);
|
||||
assert(status == 0);
|
||||
return mutex;
|
||||
@ -312,7 +297,7 @@ void ArchMultithreadPosix::unlockMutex(ArchMutex mutex)
|
||||
|
||||
ArchThread ArchMultithreadPosix::newThread(ThreadFunc func, void *data)
|
||||
{
|
||||
assert(func != NULL);
|
||||
assert(func != nullptr);
|
||||
|
||||
// initialize signal handler. we do this here instead of the
|
||||
// constructor so we can avoid daemonizing (using fork())
|
||||
@ -331,12 +316,12 @@ ArchThread ArchMultithreadPosix::newThread(ThreadFunc func, void *data)
|
||||
lockMutex(m_threadMutex);
|
||||
|
||||
// create thread impl for new thread
|
||||
ArchThreadImpl *thread = new ArchThreadImpl;
|
||||
auto *thread = new ArchThreadImpl;
|
||||
thread->m_func = func;
|
||||
thread->m_userData = data;
|
||||
|
||||
// create the thread. pthread_create() on RedHat 7.2 smp fails
|
||||
// if passed a NULL attr so use a default attr.
|
||||
// if passed a nullptr attr so use a default attr.
|
||||
pthread_attr_t attr;
|
||||
int status = pthread_attr_init(&attr);
|
||||
if (status == 0) {
|
||||
@ -348,7 +333,7 @@ ArchThread ArchMultithreadPosix::newThread(ThreadFunc func, void *data)
|
||||
if (status != 0) {
|
||||
// failed to start thread so clean up
|
||||
delete thread;
|
||||
thread = NULL;
|
||||
thread = nullptr;
|
||||
} else {
|
||||
// add thread to list
|
||||
insert(thread);
|
||||
@ -368,18 +353,18 @@ ArchThread ArchMultithreadPosix::newCurrentThread()
|
||||
lockMutex(m_threadMutex);
|
||||
ArchThreadImpl *thread = find(pthread_self());
|
||||
unlockMutex(m_threadMutex);
|
||||
assert(thread != NULL);
|
||||
assert(thread != nullptr);
|
||||
return thread;
|
||||
}
|
||||
|
||||
void ArchMultithreadPosix::closeThread(ArchThread thread)
|
||||
{
|
||||
assert(thread != NULL);
|
||||
assert(thread != nullptr);
|
||||
|
||||
// decrement ref count and clean up thread if no more references
|
||||
if (--thread->m_refCount == 0) {
|
||||
// detach from thread (unless it's the main thread)
|
||||
if (thread->m_func != NULL) {
|
||||
if (thread->m_func != nullptr) {
|
||||
pthread_detach(thread->m_thread);
|
||||
}
|
||||
|
||||
@ -402,7 +387,7 @@ ArchThread ArchMultithreadPosix::copyThread(ArchThread thread)
|
||||
|
||||
void ArchMultithreadPosix::cancelThread(ArchThread thread)
|
||||
{
|
||||
assert(thread != NULL);
|
||||
assert(thread != nullptr);
|
||||
|
||||
// set cancel and wakeup flags if thread can be cancelled
|
||||
bool wakeup = false;
|
||||
@ -421,7 +406,7 @@ void ArchMultithreadPosix::cancelThread(ArchThread thread)
|
||||
|
||||
void ArchMultithreadPosix::setPriorityOfThread(ArchThread thread, int /*n*/)
|
||||
{
|
||||
assert(thread != NULL);
|
||||
assert(thread != nullptr);
|
||||
|
||||
// FIXME
|
||||
}
|
||||
@ -439,7 +424,7 @@ void ArchMultithreadPosix::testCancelThread()
|
||||
|
||||
bool ArchMultithreadPosix::wait(ArchThread target, double timeout)
|
||||
{
|
||||
assert(target != NULL);
|
||||
assert(target != nullptr);
|
||||
|
||||
lockMutex(m_threadMutex);
|
||||
|
||||
@ -528,7 +513,7 @@ void ArchMultithreadPosix::setSignalHandler(ESignal signal, SignalFunc func, voi
|
||||
void ArchMultithreadPosix::raiseSignal(ESignal signal)
|
||||
{
|
||||
lockMutex(m_threadMutex);
|
||||
if (m_signalFunc[signal] != NULL) {
|
||||
if (m_signalFunc[signal] != nullptr) {
|
||||
m_signalFunc[signal](signal, m_signalUserData[signal]);
|
||||
pthread_kill(m_mainThread->m_thread, SIGWAKEUP);
|
||||
} else if (signal == kINTERRUPT || signal == kTERMINATE) {
|
||||
@ -541,7 +526,8 @@ void ArchMultithreadPosix::startSignalHandler()
|
||||
{
|
||||
// set signal mask. the main thread blocks these signals and
|
||||
// the signal handler thread will listen for them.
|
||||
sigset_t sigset, oldsigset;
|
||||
sigset_t sigset;
|
||||
sigset_t oldsigset;
|
||||
setSignalSet(&sigset);
|
||||
pthread_sigmask(SIG_BLOCK, &sigset, &oldsigset);
|
||||
|
||||
@ -552,20 +538,20 @@ void ArchMultithreadPosix::startSignalHandler()
|
||||
pthread_attr_t attr;
|
||||
int status = pthread_attr_init(&attr);
|
||||
if (status == 0) {
|
||||
status = pthread_create(&m_signalThread, &attr, &ArchMultithreadPosix::threadSignalHandler, NULL);
|
||||
status = pthread_create(&m_signalThread, &attr, &ArchMultithreadPosix::threadSignalHandler, nullptr);
|
||||
pthread_attr_destroy(&attr);
|
||||
}
|
||||
if (status != 0) {
|
||||
// can't create thread to wait for signal so don't block
|
||||
// the signals.
|
||||
pthread_sigmask(SIG_UNBLOCK, &oldsigset, NULL);
|
||||
pthread_sigmask(SIG_UNBLOCK, &oldsigset, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
ArchThreadImpl *ArchMultithreadPosix::find(pthread_t thread)
|
||||
{
|
||||
ArchThreadImpl *impl = findNoRef(thread);
|
||||
if (impl != NULL) {
|
||||
if (impl != nullptr) {
|
||||
refThread(impl);
|
||||
}
|
||||
return impl;
|
||||
@ -579,15 +565,15 @@ ArchThreadImpl *ArchMultithreadPosix::findNoRef(pthread_t thread)
|
||||
return *index;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void ArchMultithreadPosix::insert(ArchThreadImpl *thread)
|
||||
{
|
||||
assert(thread != NULL);
|
||||
assert(thread != nullptr);
|
||||
|
||||
// thread shouldn't already be on the list
|
||||
assert(findNoRef(thread->m_thread) == NULL);
|
||||
assert(findNoRef(thread->m_thread) == nullptr);
|
||||
|
||||
// set thread id. note that we don't worry about m_nextID
|
||||
// wrapping back to 0 and duplicating thread ID's since the
|
||||
@ -599,9 +585,9 @@ void ArchMultithreadPosix::insert(ArchThreadImpl *thread)
|
||||
m_threadList.push_back(thread);
|
||||
}
|
||||
|
||||
void ArchMultithreadPosix::erase(ArchThreadImpl *thread)
|
||||
void ArchMultithreadPosix::erase(const ArchThreadImpl *thread)
|
||||
{
|
||||
for (ThreadList::iterator index = m_threadList.begin(); index != m_threadList.end(); ++index) {
|
||||
for (auto index = m_threadList.begin(); index != m_threadList.end(); ++index) {
|
||||
if (*index == thread) {
|
||||
m_threadList.erase(index);
|
||||
break;
|
||||
@ -611,14 +597,14 @@ void ArchMultithreadPosix::erase(ArchThreadImpl *thread)
|
||||
|
||||
void ArchMultithreadPosix::refThread(ArchThreadImpl *thread)
|
||||
{
|
||||
assert(thread != NULL);
|
||||
assert(findNoRef(thread->m_thread) != NULL);
|
||||
assert(thread != nullptr);
|
||||
assert(findNoRef(thread->m_thread) != nullptr);
|
||||
++thread->m_refCount;
|
||||
}
|
||||
|
||||
void ArchMultithreadPosix::testCancelThreadImpl(ArchThreadImpl *thread)
|
||||
{
|
||||
assert(thread != NULL);
|
||||
assert(thread != nullptr);
|
||||
|
||||
// update cancel state
|
||||
lockMutex(m_threadMutex);
|
||||
@ -639,17 +625,17 @@ void ArchMultithreadPosix::testCancelThreadImpl(ArchThreadImpl *thread)
|
||||
void *ArchMultithreadPosix::threadFunc(void *vrep)
|
||||
{
|
||||
// get the thread
|
||||
ArchThreadImpl *thread = static_cast<ArchThreadImpl *>(vrep);
|
||||
auto *thread = static_cast<ArchThreadImpl *>(vrep);
|
||||
|
||||
// setup pthreads
|
||||
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
|
||||
pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
|
||||
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, nullptr);
|
||||
pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, nullptr);
|
||||
|
||||
// run thread
|
||||
s_instance->doThreadFunc(thread);
|
||||
|
||||
// terminate the thread
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void ArchMultithreadPosix::doThreadFunc(ArchThread thread)
|
||||
@ -748,5 +734,5 @@ void *ArchMultithreadPosix::threadSignalHandler(void *)
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -8,8 +8,8 @@
|
||||
#pragma once
|
||||
|
||||
#include "arch/IArchMultithread.h"
|
||||
#include "common/stdlist.h"
|
||||
|
||||
#include <list>
|
||||
#include <pthread.h>
|
||||
|
||||
#define ARCH_MULTITHREAD ArchMultithreadPosix
|
||||
@ -33,7 +33,7 @@ public:
|
||||
ArchMultithreadPosix();
|
||||
ArchMultithreadPosix(ArchMultithreadPosix const &) = delete;
|
||||
ArchMultithreadPosix(ArchMultithreadPosix &&) = delete;
|
||||
virtual ~ArchMultithreadPosix();
|
||||
~ArchMultithreadPosix() override;
|
||||
|
||||
ArchMultithreadPosix &operator=(ArchMultithreadPosix const &) = delete;
|
||||
ArchMultithreadPosix &operator=(ArchMultithreadPosix &&) = delete;
|
||||
@ -54,29 +54,29 @@ public:
|
||||
//@}
|
||||
|
||||
// IArchMultithread overrides
|
||||
virtual ArchCond newCondVar();
|
||||
virtual void closeCondVar(ArchCond);
|
||||
virtual void signalCondVar(ArchCond);
|
||||
virtual void broadcastCondVar(ArchCond);
|
||||
virtual bool waitCondVar(ArchCond, ArchMutex, double timeout);
|
||||
virtual ArchMutex newMutex();
|
||||
virtual void closeMutex(ArchMutex);
|
||||
virtual void lockMutex(ArchMutex);
|
||||
virtual void unlockMutex(ArchMutex);
|
||||
virtual ArchThread newThread(ThreadFunc, void *);
|
||||
virtual ArchThread newCurrentThread();
|
||||
virtual ArchThread copyThread(ArchThread);
|
||||
virtual void closeThread(ArchThread);
|
||||
virtual void cancelThread(ArchThread);
|
||||
virtual void setPriorityOfThread(ArchThread, int n);
|
||||
virtual void testCancelThread();
|
||||
virtual bool wait(ArchThread, double timeout);
|
||||
virtual bool isSameThread(ArchThread, ArchThread);
|
||||
virtual bool isExitedThread(ArchThread);
|
||||
virtual void *getResultOfThread(ArchThread);
|
||||
virtual ThreadID getIDOfThread(ArchThread);
|
||||
virtual void setSignalHandler(ESignal, SignalFunc, void *);
|
||||
virtual void raiseSignal(ESignal);
|
||||
ArchCond newCondVar() override;
|
||||
void closeCondVar(ArchCond) override;
|
||||
void signalCondVar(ArchCond) override;
|
||||
void broadcastCondVar(ArchCond) override;
|
||||
bool waitCondVar(ArchCond, ArchMutex, double timeout) override;
|
||||
ArchMutex newMutex() override;
|
||||
void closeMutex(ArchMutex) override;
|
||||
void lockMutex(ArchMutex) override;
|
||||
void unlockMutex(ArchMutex) override;
|
||||
ArchThread newThread(ThreadFunc, void *) final;
|
||||
ArchThread newCurrentThread() override;
|
||||
ArchThread copyThread(ArchThread) override;
|
||||
void closeThread(ArchThread) final;
|
||||
void cancelThread(ArchThread) override;
|
||||
void setPriorityOfThread(ArchThread, int n) override;
|
||||
void testCancelThread() override;
|
||||
bool wait(ArchThread, double timeout) override;
|
||||
bool isSameThread(ArchThread, ArchThread) override;
|
||||
bool isExitedThread(ArchThread) override;
|
||||
void *getResultOfThread(ArchThread) override;
|
||||
ThreadID getIDOfThread(ArchThread) override;
|
||||
void setSignalHandler(ESignal, SignalFunc, void *) override;
|
||||
void raiseSignal(ESignal) override;
|
||||
|
||||
private:
|
||||
void startSignalHandler();
|
||||
@ -84,7 +84,7 @@ private:
|
||||
ArchThreadImpl *find(pthread_t thread);
|
||||
ArchThreadImpl *findNoRef(pthread_t thread);
|
||||
void insert(ArchThreadImpl *thread);
|
||||
void erase(ArchThreadImpl *thread);
|
||||
void erase(const ArchThreadImpl *thread);
|
||||
|
||||
void refThread(ArchThreadImpl *rep);
|
||||
void testCancelThreadImpl(ArchThreadImpl *rep);
|
||||
@ -99,12 +99,12 @@ private:
|
||||
|
||||
static ArchMultithreadPosix *s_instance;
|
||||
|
||||
bool m_newThreadCalled;
|
||||
bool m_newThreadCalled = false;
|
||||
|
||||
ArchMutex m_threadMutex;
|
||||
ArchThread m_mainThread;
|
||||
ThreadList m_threadList;
|
||||
ThreadID m_nextID;
|
||||
ThreadID m_nextID = 0;
|
||||
|
||||
pthread_t m_signalThread;
|
||||
SignalFunc m_signalFunc[kNUM_SIGNALS];
|
||||
|
||||
@ -8,6 +8,7 @@
|
||||
#include "arch/unix/ArchNetworkBSD.h"
|
||||
|
||||
#include "arch/Arch.h"
|
||||
#include "arch/XArch.h"
|
||||
#include "arch/unix/ArchMultithreadPosix.h"
|
||||
#include "arch/unix/XArchUnix.h"
|
||||
|
||||
@ -65,7 +66,6 @@ static in_addr_t inet_aton(const char *cp, struct in_addr *inp)
|
||||
|
||||
void ArchNetworkBSD::Deps::sleep(double seconds)
|
||||
{
|
||||
//
|
||||
ARCH->sleep(seconds);
|
||||
}
|
||||
|
||||
@ -131,7 +131,7 @@ ArchSocket ArchNetworkBSD::newSocket(EAddressFamily family, ESocketType type)
|
||||
|
||||
ArchSocket ArchNetworkBSD::copySocket(ArchSocket s)
|
||||
{
|
||||
assert(s != NULL);
|
||||
assert(s != nullptr);
|
||||
|
||||
// ref the socket and return it
|
||||
ARCH->lockMutex(m_mutex);
|
||||
@ -142,7 +142,7 @@ ArchSocket ArchNetworkBSD::copySocket(ArchSocket s)
|
||||
|
||||
void ArchNetworkBSD::closeSocket(ArchSocket s)
|
||||
{
|
||||
assert(s != NULL);
|
||||
assert(s != nullptr);
|
||||
|
||||
// unref the socket and note if it should be released
|
||||
ARCH->lockMutex(m_mutex);
|
||||
@ -165,30 +165,26 @@ void ArchNetworkBSD::closeSocket(ArchSocket s)
|
||||
|
||||
void ArchNetworkBSD::closeSocketForRead(ArchSocket s)
|
||||
{
|
||||
assert(s != NULL);
|
||||
assert(s != nullptr);
|
||||
|
||||
if (shutdown(s->m_fd, 0) == -1) {
|
||||
if (errno != ENOTCONN) {
|
||||
throwError(errno);
|
||||
}
|
||||
if ((shutdown(s->m_fd, 0) == -1) && (errno != ENOTCONN)) {
|
||||
throwError(errno);
|
||||
}
|
||||
}
|
||||
|
||||
void ArchNetworkBSD::closeSocketForWrite(ArchSocket s)
|
||||
{
|
||||
assert(s != NULL);
|
||||
assert(s != nullptr);
|
||||
|
||||
if (shutdown(s->m_fd, 1) == -1) {
|
||||
if (errno != ENOTCONN) {
|
||||
throwError(errno);
|
||||
}
|
||||
if ((shutdown(s->m_fd, 1) == -1) && (errno != ENOTCONN)) {
|
||||
throwError(errno);
|
||||
}
|
||||
}
|
||||
|
||||
void ArchNetworkBSD::bindSocket(ArchSocket s, ArchNetAddress addr)
|
||||
{
|
||||
assert(s != NULL);
|
||||
assert(addr != NULL);
|
||||
assert(s != nullptr);
|
||||
assert(addr != nullptr);
|
||||
|
||||
if (bind(s->m_fd, TYPED_ADDR(struct sockaddr, addr), addr->m_len) == -1) {
|
||||
throwError(errno);
|
||||
@ -197,7 +193,7 @@ void ArchNetworkBSD::bindSocket(ArchSocket s, ArchNetAddress addr)
|
||||
|
||||
void ArchNetworkBSD::listenOnSocket(ArchSocket s)
|
||||
{
|
||||
assert(s != NULL);
|
||||
assert(s != nullptr);
|
||||
|
||||
// hardcoding backlog
|
||||
if (listen(s->m_fd, 3) == -1) {
|
||||
@ -207,9 +203,9 @@ void ArchNetworkBSD::listenOnSocket(ArchSocket s)
|
||||
|
||||
ArchSocket ArchNetworkBSD::acceptSocket(ArchSocket s, ArchNetAddress *addr)
|
||||
{
|
||||
assert(s != NULL);
|
||||
assert(s != nullptr);
|
||||
|
||||
// if user passed NULL in addr then use scratch space
|
||||
// if user passed nullptr in addr then use scratch space
|
||||
ArchNetAddress dummy;
|
||||
if (addr == nullptr) {
|
||||
addr = &dummy;
|
||||
@ -258,8 +254,8 @@ ArchSocket ArchNetworkBSD::acceptSocket(ArchSocket s, ArchNetAddress *addr)
|
||||
|
||||
bool ArchNetworkBSD::connectSocket(ArchSocket s, ArchNetAddress addr)
|
||||
{
|
||||
assert(s != NULL);
|
||||
assert(addr != NULL);
|
||||
assert(s != nullptr);
|
||||
assert(addr != nullptr);
|
||||
|
||||
if (connect(s->m_fd, TYPED_ADDR(struct sockaddr, addr), addr->m_len) == -1) {
|
||||
if (errno == EISCONN) {
|
||||
@ -372,7 +368,7 @@ void ArchNetworkBSD::unblockPollSocket(ArchThread thread)
|
||||
|
||||
size_t ArchNetworkBSD::readSocket(ArchSocket s, void *buf, size_t len)
|
||||
{
|
||||
assert(s != NULL);
|
||||
assert(s != nullptr);
|
||||
|
||||
ssize_t n = read(s->m_fd, buf, len);
|
||||
if (n == -1) {
|
||||
@ -386,7 +382,7 @@ size_t ArchNetworkBSD::readSocket(ArchSocket s, void *buf, size_t len)
|
||||
|
||||
size_t ArchNetworkBSD::writeSocket(ArchSocket s, const void *buf, size_t len)
|
||||
{
|
||||
assert(s != NULL);
|
||||
assert(s != nullptr);
|
||||
|
||||
ssize_t n = write(s->m_fd, buf, len);
|
||||
if (n == -1) {
|
||||
@ -400,12 +396,12 @@ size_t ArchNetworkBSD::writeSocket(ArchSocket s, const void *buf, size_t len)
|
||||
|
||||
void ArchNetworkBSD::throwErrorOnSocket(ArchSocket s)
|
||||
{
|
||||
assert(s != NULL);
|
||||
assert(s != nullptr);
|
||||
|
||||
// get the error from the socket layer
|
||||
int err = 0;
|
||||
auto size = static_cast<socklen_t>(sizeof(err));
|
||||
if (getsockopt(s->m_fd, SOL_SOCKET, SO_ERROR, reinterpret_cast<optval_t *>(&err), &size) == -1) {
|
||||
if (auto size = static_cast<socklen_t>(sizeof(err));
|
||||
getsockopt(s->m_fd, SOL_SOCKET, SO_ERROR, reinterpret_cast<optval_t *>(&err), &size) == -1) {
|
||||
err = errno;
|
||||
}
|
||||
|
||||
@ -415,7 +411,7 @@ void ArchNetworkBSD::throwErrorOnSocket(ArchSocket s)
|
||||
}
|
||||
}
|
||||
|
||||
void ArchNetworkBSD::setBlockingOnSocket(int fd, bool blocking)
|
||||
void ArchNetworkBSD::setBlockingOnSocket(int fd, bool blocking) const
|
||||
{
|
||||
assert(fd != -1);
|
||||
|
||||
@ -435,7 +431,7 @@ void ArchNetworkBSD::setBlockingOnSocket(int fd, bool blocking)
|
||||
|
||||
bool ArchNetworkBSD::setNoDelayOnSocket(ArchSocket s, bool noDelay)
|
||||
{
|
||||
assert(s != NULL);
|
||||
assert(s != nullptr);
|
||||
|
||||
// get old state
|
||||
int oflag;
|
||||
@ -455,7 +451,7 @@ bool ArchNetworkBSD::setNoDelayOnSocket(ArchSocket s, bool noDelay)
|
||||
|
||||
bool ArchNetworkBSD::setReuseAddrOnSocket(ArchSocket s, bool reuse)
|
||||
{
|
||||
assert(s != NULL);
|
||||
assert(s != nullptr);
|
||||
|
||||
// get old state
|
||||
int oflag;
|
||||
@ -501,7 +497,7 @@ ArchNetAddress ArchNetworkBSD::newAnyAddr(EAddressFamily family)
|
||||
}
|
||||
|
||||
case kINET6: {
|
||||
struct sockaddr_in6 *ipAddr = TYPED_ADDR(struct sockaddr_in6, addr);
|
||||
auto *ipAddr = TYPED_ADDR(struct sockaddr_in6, addr);
|
||||
ipAddr->sin6_family = AF_INET6;
|
||||
ipAddr->sin6_port = 0;
|
||||
memcpy(&ipAddr->sin6_addr, &in6addr_any, sizeof(in6addr_any));
|
||||
@ -518,7 +514,7 @@ ArchNetAddress ArchNetworkBSD::newAnyAddr(EAddressFamily family)
|
||||
|
||||
ArchNetAddress ArchNetworkBSD::copyAddr(ArchNetAddress addr)
|
||||
{
|
||||
assert(addr != NULL);
|
||||
assert(addr != nullptr);
|
||||
|
||||
// allocate and copy address
|
||||
return new ArchNetAddressImpl(*addr);
|
||||
@ -545,8 +541,8 @@ std::vector<ArchNetAddress> ArchNetworkBSD::nameToAddr(const std::string &name)
|
||||
// done with static buffer
|
||||
ARCH->lockMutex(m_mutex);
|
||||
struct addrinfo *pResult = nullptr;
|
||||
int ret = getaddrinfo(name.c_str(), nullptr, &hints, &pResult);
|
||||
if (ret != 0) {
|
||||
|
||||
if (int ret = getaddrinfo(name.c_str(), nullptr, &hints, &pResult); ret != 0) {
|
||||
ARCH->unlockMutex(m_mutex);
|
||||
throwNameError(ret);
|
||||
}
|
||||
@ -572,22 +568,23 @@ std::vector<ArchNetAddress> ArchNetworkBSD::nameToAddr(const std::string &name)
|
||||
|
||||
void ArchNetworkBSD::closeAddr(ArchNetAddress addr)
|
||||
{
|
||||
assert(addr != NULL);
|
||||
assert(addr != nullptr);
|
||||
|
||||
delete addr;
|
||||
}
|
||||
|
||||
std::string ArchNetworkBSD::addrToName(ArchNetAddress addr)
|
||||
{
|
||||
assert(addr != NULL);
|
||||
assert(addr != nullptr);
|
||||
|
||||
// mutexed name lookup (ugh)
|
||||
ARCH->lockMutex(m_mutex);
|
||||
char host[1024];
|
||||
char service[20];
|
||||
int ret =
|
||||
getnameinfo(TYPED_ADDR(struct sockaddr, addr), addr->m_len, host, sizeof(host), service, sizeof(service), 0);
|
||||
if (ret != 0) {
|
||||
|
||||
if (int ret =
|
||||
getnameinfo(TYPED_ADDR(struct sockaddr, addr), addr->m_len, host, sizeof(host), service, sizeof(service), 0);
|
||||
ret != 0) {
|
||||
ARCH->unlockMutex(m_mutex);
|
||||
throwNameError(ret);
|
||||
}
|
||||
@ -603,11 +600,11 @@ std::string ArchNetworkBSD::addrToName(ArchNetAddress addr)
|
||||
|
||||
std::string ArchNetworkBSD::addrToString(ArchNetAddress addr)
|
||||
{
|
||||
assert(addr != NULL);
|
||||
assert(addr != nullptr);
|
||||
|
||||
switch (getAddrFamily(addr)) {
|
||||
case kINET: {
|
||||
auto *ipAddr = TYPED_ADDR(struct sockaddr_in, addr);
|
||||
const auto *ipAddr = TYPED_ADDR(struct sockaddr_in, addr);
|
||||
ARCH->lockMutex(m_mutex);
|
||||
std::string s = inet_ntoa(ipAddr->sin_addr);
|
||||
ARCH->unlockMutex(m_mutex);
|
||||
@ -616,7 +613,7 @@ std::string ArchNetworkBSD::addrToString(ArchNetAddress addr)
|
||||
|
||||
case kINET6: {
|
||||
char strAddr[INET6_ADDRSTRLEN];
|
||||
struct sockaddr_in6 *ipAddr = TYPED_ADDR(struct sockaddr_in6, addr);
|
||||
const auto *ipAddr = TYPED_ADDR(struct sockaddr_in6, addr);
|
||||
ARCH->lockMutex(m_mutex);
|
||||
inet_ntop(AF_INET6, &ipAddr->sin6_addr, strAddr, INET6_ADDRSTRLEN);
|
||||
ARCH->unlockMutex(m_mutex);
|
||||
@ -631,7 +628,7 @@ std::string ArchNetworkBSD::addrToString(ArchNetAddress addr)
|
||||
|
||||
IArchNetwork::EAddressFamily ArchNetworkBSD::getAddrFamily(ArchNetAddress addr)
|
||||
{
|
||||
assert(addr != NULL);
|
||||
assert(addr != nullptr);
|
||||
|
||||
switch (addr->m_addr.ss_family) {
|
||||
case AF_INET:
|
||||
@ -646,7 +643,7 @@ IArchNetwork::EAddressFamily ArchNetworkBSD::getAddrFamily(ArchNetAddress addr)
|
||||
|
||||
void ArchNetworkBSD::setAddrPort(ArchNetAddress addr, int port)
|
||||
{
|
||||
assert(addr != NULL);
|
||||
assert(addr != nullptr);
|
||||
|
||||
switch (getAddrFamily(addr)) {
|
||||
case kINET: {
|
||||
@ -656,7 +653,7 @@ void ArchNetworkBSD::setAddrPort(ArchNetAddress addr, int port)
|
||||
}
|
||||
|
||||
case kINET6: {
|
||||
struct sockaddr_in6 *ipAddr = TYPED_ADDR(struct sockaddr_in6, addr);
|
||||
auto *ipAddr = TYPED_ADDR(struct sockaddr_in6, addr);
|
||||
ipAddr->sin6_port = htons(port);
|
||||
break;
|
||||
}
|
||||
@ -669,16 +666,16 @@ void ArchNetworkBSD::setAddrPort(ArchNetAddress addr, int port)
|
||||
|
||||
int ArchNetworkBSD::getAddrPort(ArchNetAddress addr)
|
||||
{
|
||||
assert(addr != NULL);
|
||||
assert(addr != nullptr);
|
||||
|
||||
switch (getAddrFamily(addr)) {
|
||||
case kINET: {
|
||||
auto *ipAddr = TYPED_ADDR(struct sockaddr_in, addr);
|
||||
const auto *ipAddr = TYPED_ADDR(struct sockaddr_in, addr);
|
||||
return ntohs(ipAddr->sin_port);
|
||||
}
|
||||
|
||||
case kINET6: {
|
||||
struct sockaddr_in6 *ipAddr = TYPED_ADDR(struct sockaddr_in6, addr);
|
||||
const auto *ipAddr = TYPED_ADDR(struct sockaddr_in6, addr);
|
||||
return ntohs(ipAddr->sin6_port);
|
||||
}
|
||||
|
||||
@ -690,16 +687,16 @@ int ArchNetworkBSD::getAddrPort(ArchNetAddress addr)
|
||||
|
||||
bool ArchNetworkBSD::isAnyAddr(ArchNetAddress addr)
|
||||
{
|
||||
assert(addr != NULL);
|
||||
assert(addr != nullptr);
|
||||
|
||||
switch (getAddrFamily(addr)) {
|
||||
case kINET: {
|
||||
auto *ipAddr = TYPED_ADDR(struct sockaddr_in, addr);
|
||||
const auto *ipAddr = TYPED_ADDR(struct sockaddr_in, addr);
|
||||
return (ipAddr->sin_addr.s_addr == INADDR_ANY && addr->m_len == static_cast<socklen_t>(sizeof(struct sockaddr_in)));
|
||||
}
|
||||
|
||||
case kINET6: {
|
||||
struct sockaddr_in6 *ipAddr = TYPED_ADDR(struct sockaddr_in6, addr);
|
||||
const auto *ipAddr = TYPED_ADDR(struct sockaddr_in6, addr);
|
||||
return (
|
||||
addr->m_len == (socklen_t)sizeof(struct sockaddr_in6) &&
|
||||
memcmp(
|
||||
@ -750,16 +747,16 @@ const int *ArchNetworkBSD::getUnblockPipeForThread(ArchThread thread)
|
||||
return unblockPipe;
|
||||
}
|
||||
|
||||
void ArchNetworkBSD::throwError(int err)
|
||||
void ArchNetworkBSD::throwError(int err) const
|
||||
{
|
||||
switch (err) {
|
||||
case EINTR:
|
||||
ARCH->testCancelThread();
|
||||
throw XArchNetworkInterrupted(new XArchEvalUnix(err));
|
||||
throw XArchNetworkInterrupted(errorToString(err));
|
||||
|
||||
case EACCES:
|
||||
case EPERM:
|
||||
throw XArchNetworkAccess(new XArchEvalUnix(err));
|
||||
throw XArchNetworkAccess(errorToString(err));
|
||||
|
||||
case ENFILE:
|
||||
case EMFILE:
|
||||
@ -770,7 +767,7 @@ void ArchNetworkBSD::throwError(int err)
|
||||
#if defined(ENOSR)
|
||||
case ENOSR:
|
||||
#endif
|
||||
throw XArchNetworkResource(new XArchEvalUnix(err));
|
||||
throw XArchNetworkResource(errorToString(err));
|
||||
|
||||
case EPROTOTYPE:
|
||||
case EPROTONOSUPPORT:
|
||||
@ -784,44 +781,44 @@ void ArchNetworkBSD::throwError(int err)
|
||||
#if defined(ENOPKG)
|
||||
case ENOPKG:
|
||||
#endif
|
||||
throw XArchNetworkSupport(new XArchEvalUnix(err));
|
||||
throw XArchNetworkSupport(errorToString(err));
|
||||
|
||||
case EIO:
|
||||
throw XArchNetworkIO(new XArchEvalUnix(err));
|
||||
throw XArchNetworkIO(errorToString(err));
|
||||
|
||||
case EADDRNOTAVAIL:
|
||||
throw XArchNetworkNoAddress(new XArchEvalUnix(err));
|
||||
throw XArchNetworkNoAddress(errorToString(err));
|
||||
|
||||
case EADDRINUSE:
|
||||
throw XArchNetworkAddressInUse(new XArchEvalUnix(err));
|
||||
throw XArchNetworkAddressInUse(errorToString(err));
|
||||
|
||||
case EHOSTUNREACH:
|
||||
case ENETUNREACH:
|
||||
throw XArchNetworkNoRoute(new XArchEvalUnix(err));
|
||||
throw XArchNetworkNoRoute(errorToString(err));
|
||||
|
||||
case ENOTCONN:
|
||||
throw XArchNetworkNotConnected(new XArchEvalUnix(err));
|
||||
throw XArchNetworkNotConnected(errorToString(err));
|
||||
|
||||
case EPIPE:
|
||||
throw XArchNetworkShutdown(new XArchEvalUnix(err));
|
||||
throw XArchNetworkShutdown(errorToString(err));
|
||||
|
||||
case ECONNABORTED:
|
||||
case ECONNRESET:
|
||||
throw XArchNetworkDisconnected(new XArchEvalUnix(err));
|
||||
throw XArchNetworkDisconnected(errorToString(err));
|
||||
|
||||
case ECONNREFUSED:
|
||||
throw XArchNetworkConnectionRefused(new XArchEvalUnix(err));
|
||||
throw XArchNetworkConnectionRefused(errorToString(err));
|
||||
|
||||
case EHOSTDOWN:
|
||||
case ETIMEDOUT:
|
||||
throw XArchNetworkTimedOut(new XArchEvalUnix(err));
|
||||
throw XArchNetworkTimedOut(errorToString(err));
|
||||
|
||||
default:
|
||||
throw XArchNetwork(new XArchEvalUnix(err));
|
||||
throw XArchNetwork(errorToString(err));
|
||||
}
|
||||
}
|
||||
|
||||
void ArchNetworkBSD::throwNameError(int err)
|
||||
void ArchNetworkBSD::throwNameError(int err) const
|
||||
{
|
||||
static const char *s_msg[] = {
|
||||
"The specified host is unknown", "The requested name is valid but does not have an IP address",
|
||||
|
||||
@ -55,6 +55,7 @@ class ArchNetAddressImpl
|
||||
public:
|
||||
ArchNetAddressImpl() : m_len(sizeof(m_addr))
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
public:
|
||||
@ -122,9 +123,9 @@ public:
|
||||
private:
|
||||
const int *getUnblockPipe();
|
||||
const int *getUnblockPipeForThread(ArchThread);
|
||||
void setBlockingOnSocket(int fd, bool blocking);
|
||||
void throwError(int);
|
||||
void throwNameError(int);
|
||||
void setBlockingOnSocket(int fd, bool blocking) const;
|
||||
void throwError(int) const;
|
||||
void throwNameError(int) const;
|
||||
|
||||
private:
|
||||
std::shared_ptr<Deps> m_pDeps;
|
||||
|
||||
@ -35,16 +35,6 @@
|
||||
// ArchSleepUnix
|
||||
//
|
||||
|
||||
ArchSleepUnix::ArchSleepUnix()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
ArchSleepUnix::~ArchSleepUnix()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
void ArchSleepUnix::sleep(double timeout)
|
||||
{
|
||||
ARCH->testCancelThread();
|
||||
@ -70,7 +60,7 @@ void ArchSleepUnix::sleep(double timeout)
|
||||
timeout2.tv_sec = static_cast<int>(timeLeft);
|
||||
timeout2.tv_usec = static_cast<int>(1.0e+6 * (timeLeft - timeout2.tv_sec));
|
||||
select(
|
||||
(SELECT_TYPE_ARG1)0, SELECT_TYPE_ARG234 NULL, SELECT_TYPE_ARG234 NULL, SELECT_TYPE_ARG234 NULL,
|
||||
(SELECT_TYPE_ARG1)0, SELECT_TYPE_ARG234 nullptr, SELECT_TYPE_ARG234 nullptr, SELECT_TYPE_ARG234 nullptr,
|
||||
SELECT_TYPE_ARG5 & timeout2
|
||||
);
|
||||
ARCH->testCancelThread();
|
||||
|
||||
@ -15,9 +15,9 @@
|
||||
class ArchSleepUnix : public IArchSleep
|
||||
{
|
||||
public:
|
||||
ArchSleepUnix();
|
||||
virtual ~ArchSleepUnix();
|
||||
ArchSleepUnix() = default;
|
||||
~ArchSleepUnix() override = default;
|
||||
|
||||
// IArchSleep overrides
|
||||
virtual void sleep(double timeout);
|
||||
void sleep(double timeout) override;
|
||||
};
|
||||
|
||||
@ -1,29 +0,0 @@
|
||||
/*
|
||||
* Deskflow -- mouse and keyboard sharing utility
|
||||
* SPDX-FileCopyrightText: (C) 2012 - 2016 Symless Ltd.
|
||||
* SPDX-FileCopyrightText: (C) 2002 Chris Schoeneman
|
||||
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
|
||||
*/
|
||||
|
||||
#include "arch/unix/ArchStringUnix.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
//
|
||||
// ArchStringUnix
|
||||
//
|
||||
|
||||
#include "arch/multibyte.h"
|
||||
|
||||
ArchStringUnix::ArchStringUnix()
|
||||
{
|
||||
}
|
||||
|
||||
ArchStringUnix::~ArchStringUnix()
|
||||
{
|
||||
}
|
||||
|
||||
IArchString::EWideCharEncoding ArchStringUnix::getWideCharEncoding()
|
||||
{
|
||||
return kUCS4;
|
||||
}
|
||||
@ -1,23 +0,0 @@
|
||||
/*
|
||||
* Deskflow -- mouse and keyboard sharing utility
|
||||
* SPDX-FileCopyrightText: (C) 2012 - 2016 Symless Ltd.
|
||||
* SPDX-FileCopyrightText: (C) 2002 Chris Schoeneman
|
||||
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "arch/IArchString.h"
|
||||
|
||||
#define ARCH_STRING ArchStringUnix
|
||||
|
||||
//! Unix implementation of IArchString
|
||||
class ArchStringUnix : public IArchString
|
||||
{
|
||||
public:
|
||||
ArchStringUnix();
|
||||
virtual ~ArchStringUnix();
|
||||
|
||||
// IArchString overrides
|
||||
virtual EWideCharEncoding getWideCharEncoding();
|
||||
};
|
||||
@ -1,131 +0,0 @@
|
||||
/*
|
||||
* Deskflow -- mouse and keyboard sharing utility
|
||||
* SPDX-FileCopyrightText: (C) 2012 - 2016 Symless Ltd.
|
||||
* SPDX-FileCopyrightText: (C) 2002 Chris Schoeneman
|
||||
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
|
||||
*/
|
||||
|
||||
#include "arch/unix/ArchSystemUnix.h"
|
||||
#include <array>
|
||||
|
||||
#include <common/constants.h>
|
||||
#include <sys/utsname.h>
|
||||
|
||||
#ifndef __APPLE__
|
||||
#include <QDBusConnection>
|
||||
#include <QDBusError>
|
||||
#include <QDBusInterface>
|
||||
#include <QDBusReply>
|
||||
#endif
|
||||
|
||||
//
|
||||
// ArchSystemUnix
|
||||
//
|
||||
|
||||
ArchSystemUnix::ArchSystemUnix()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
ArchSystemUnix::~ArchSystemUnix()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
std::string ArchSystemUnix::getOSName() const
|
||||
{
|
||||
#if defined(HAVE_SYS_UTSNAME_H)
|
||||
struct utsname info;
|
||||
if (uname(&info) == 0) {
|
||||
std::string msg;
|
||||
msg += info.sysname;
|
||||
msg += " ";
|
||||
msg += info.release;
|
||||
return msg;
|
||||
}
|
||||
#endif
|
||||
return "Unix";
|
||||
}
|
||||
|
||||
std::string ArchSystemUnix::getPlatformName() const
|
||||
{
|
||||
#if defined(HAVE_SYS_UTSNAME_H)
|
||||
struct utsname info;
|
||||
if (uname(&info) == 0) {
|
||||
return std::string(info.machine);
|
||||
}
|
||||
#endif
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
std::string ArchSystemUnix::setting(const std::string &) const
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
void ArchSystemUnix::setting(const std::string &, const std::string &) const
|
||||
{
|
||||
}
|
||||
|
||||
void ArchSystemUnix::clearSettings() const
|
||||
{
|
||||
// Not implemented
|
||||
}
|
||||
|
||||
std::string ArchSystemUnix::getLibsUsed(void) const
|
||||
{
|
||||
return "not implemented.\nuse lsof on shell";
|
||||
}
|
||||
|
||||
#ifndef __APPLE__
|
||||
bool ArchSystemUnix::DBusInhibitScreenCall(InhibitScreenServices serviceID, bool state, std::string &error)
|
||||
{
|
||||
error = "";
|
||||
static const std::array<QString, 2> services = {"org.freedesktop.ScreenSaver", "org.gnome.SessionManager"};
|
||||
static const std::array<QString, 2> paths = {"/org/freedesktop/ScreenSaver", "/org/gnome/SessionManager"};
|
||||
static std::array<uint, 2> cookies;
|
||||
|
||||
auto serviceNum = static_cast<uint8_t>(serviceID);
|
||||
|
||||
QDBusConnection bus = QDBusConnection::sessionBus();
|
||||
if (!bus.isConnected()) {
|
||||
error = "bus failed to connect";
|
||||
return false;
|
||||
}
|
||||
|
||||
QDBusInterface screenSaverInterface(services[serviceNum], paths[serviceNum], services[serviceNum], bus);
|
||||
|
||||
if (!screenSaverInterface.isValid()) {
|
||||
error = "screen saver interface failed to initialize";
|
||||
return false;
|
||||
}
|
||||
|
||||
QDBusReply<uint> reply;
|
||||
if (state) {
|
||||
if (cookies[serviceNum]) {
|
||||
error = "coockies are not empty";
|
||||
return false;
|
||||
}
|
||||
|
||||
QString msg = "Sleep is manually prevented by the %1 preferences";
|
||||
reply = screenSaverInterface.call("Inhibit", kAppName, msg.arg(kAppName));
|
||||
if (reply.isValid())
|
||||
cookies[serviceNum] = reply.value();
|
||||
} else {
|
||||
if (!cookies[serviceNum]) {
|
||||
error = "coockies are empty";
|
||||
return false;
|
||||
}
|
||||
reply = screenSaverInterface.call("UnInhibit", cookies[serviceNum]);
|
||||
cookies[serviceNum] = 0;
|
||||
}
|
||||
|
||||
if (!reply.isValid()) {
|
||||
QDBusError qerror = reply.error();
|
||||
error = qerror.name().toStdString() + " : " + qerror.message().toStdString();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
@ -1,37 +0,0 @@
|
||||
/*
|
||||
* Deskflow -- mouse and keyboard sharing utility
|
||||
* SPDX-FileCopyrightText: (C) 2012 - 2016 Symless Ltd.
|
||||
* SPDX-FileCopyrightText: (C) 2002 Chris Schoeneman
|
||||
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "arch/IArchSystem.h"
|
||||
|
||||
#define ARCH_SYSTEM ArchSystemUnix
|
||||
|
||||
//! Unix implementation of IArchString
|
||||
class ArchSystemUnix : public IArchSystem
|
||||
{
|
||||
public:
|
||||
ArchSystemUnix();
|
||||
virtual ~ArchSystemUnix();
|
||||
|
||||
// IArchSystem overrides
|
||||
virtual std::string getOSName() const;
|
||||
virtual std::string getPlatformName() const;
|
||||
virtual std::string setting(const std::string &) const;
|
||||
virtual void setting(const std::string &, const std::string &) const;
|
||||
virtual std::string getLibsUsed(void) const;
|
||||
virtual void clearSettings() const;
|
||||
|
||||
#ifndef __APPLE__
|
||||
enum class InhibitScreenServices
|
||||
{
|
||||
kScreenSaver,
|
||||
kSessionManager
|
||||
};
|
||||
static bool DBusInhibitScreenCall(InhibitScreenServices serviceID, bool state, std::string &error);
|
||||
#endif
|
||||
};
|
||||
@ -22,19 +22,9 @@
|
||||
// ArchTimeUnix
|
||||
//
|
||||
|
||||
ArchTimeUnix::ArchTimeUnix()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
ArchTimeUnix::~ArchTimeUnix()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
double ArchTimeUnix::time()
|
||||
{
|
||||
struct timeval t;
|
||||
gettimeofday(&t, NULL);
|
||||
gettimeofday(&t, nullptr);
|
||||
return (double)t.tv_sec + 1.0e-6 * (double)t.tv_usec;
|
||||
}
|
||||
|
||||
@ -15,9 +15,9 @@
|
||||
class ArchTimeUnix : public IArchTime
|
||||
{
|
||||
public:
|
||||
ArchTimeUnix();
|
||||
virtual ~ArchTimeUnix();
|
||||
ArchTimeUnix() = default;
|
||||
~ArchTimeUnix() override = default;
|
||||
|
||||
// IArchTime overrides
|
||||
virtual double time();
|
||||
double time() override;
|
||||
};
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Deskflow -- mouse and keyboard sharing utility
|
||||
* SPDX-FileCopyrightText: (C) 2025 Deskflow Developers
|
||||
* SPDX-FileCopyrightText: (C) 2012 - 2016 Symless Ltd.
|
||||
* SPDX-FileCopyrightText: (C) 2002 Chris Schoeneman
|
||||
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
|
||||
@ -9,12 +10,8 @@
|
||||
|
||||
#include <cstring>
|
||||
|
||||
//
|
||||
// XArchEvalUnix
|
||||
//
|
||||
|
||||
std::string XArchEvalUnix::eval() const
|
||||
std::string errorToString(int error)
|
||||
{
|
||||
// FIXME -- not thread safe
|
||||
return strerror(m_error);
|
||||
return std::strerror(error);
|
||||
}
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Deskflow -- mouse and keyboard sharing utility
|
||||
* SPDX-FileCopyrightText: (C) 2025 Deskflow Developers
|
||||
* SPDX-FileCopyrightText: (C) 2012 - 2016 Symless Ltd.
|
||||
* SPDX-FileCopyrightText: (C) 2002 Chris Schoeneman
|
||||
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
|
||||
@ -7,21 +8,6 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "arch/XArch.h"
|
||||
#include <string>
|
||||
|
||||
//! Lazy error message string evaluation for unix
|
||||
class XArchEvalUnix : public XArchEval
|
||||
{
|
||||
public:
|
||||
XArchEvalUnix(int error) : m_error(error)
|
||||
{
|
||||
}
|
||||
virtual ~XArchEvalUnix() _NOEXCEPT
|
||||
{
|
||||
}
|
||||
|
||||
virtual std::string eval() const;
|
||||
|
||||
private:
|
||||
int m_error;
|
||||
};
|
||||
std::string errorToString(int error);
|
||||
|
||||
@ -1,16 +0,0 @@
|
||||
/*
|
||||
* Deskflow -- mouse and keyboard sharing utility
|
||||
* SPDX-FileCopyrightText: (C) 2012 - 2016 Symless Ltd.
|
||||
* SPDX-FileCopyrightText: (C) 2002 Chris Schoeneman
|
||||
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
|
||||
*/
|
||||
|
||||
#include "arch/win32/ArchConsoleWindows.h"
|
||||
|
||||
ArchConsoleWindows::ArchConsoleWindows()
|
||||
{
|
||||
}
|
||||
|
||||
ArchConsoleWindows::~ArchConsoleWindows()
|
||||
{
|
||||
}
|
||||
@ -1,19 +0,0 @@
|
||||
/*
|
||||
* Deskflow -- mouse and keyboard sharing utility
|
||||
* SPDX-FileCopyrightText: (C) 2012 - 2016 Symless Ltd.
|
||||
* SPDX-FileCopyrightText: (C) 2002 Chris Schoeneman
|
||||
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "arch/ArchConsoleStd.h"
|
||||
|
||||
#define ARCH_CONSOLE ArchConsoleWindows
|
||||
|
||||
class ArchConsoleWindows : public ArchConsoleStd
|
||||
{
|
||||
public:
|
||||
ArchConsoleWindows();
|
||||
virtual ~ArchConsoleWindows();
|
||||
};
|
||||
@ -8,6 +8,7 @@
|
||||
#include "arch/win32/ArchDaemonWindows.h"
|
||||
|
||||
#include "arch/Arch.h"
|
||||
#include "arch/XArch.h"
|
||||
#include "arch/win32/ArchMiscWindows.h"
|
||||
#include "arch/win32/XArchWindows.h"
|
||||
#include "base/Log.h"
|
||||
@ -16,34 +17,29 @@
|
||||
// ArchDaemonWindows
|
||||
//
|
||||
|
||||
ArchDaemonWindows *ArchDaemonWindows::s_daemon = NULL;
|
||||
ArchDaemonWindows *ArchDaemonWindows::s_daemon = nullptr;
|
||||
|
||||
ArchDaemonWindows::ArchDaemonWindows() : m_daemonThreadID(0)
|
||||
{
|
||||
m_quitMessage = RegisterWindowMessage("DeskflowDaemonExit");
|
||||
}
|
||||
|
||||
ArchDaemonWindows::~ArchDaemonWindows()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
int ArchDaemonWindows::runDaemon(RunFunc runFunc)
|
||||
{
|
||||
assert(s_daemon != NULL);
|
||||
assert(s_daemon != nullptr);
|
||||
return s_daemon->doRunDaemon(runFunc);
|
||||
}
|
||||
|
||||
void ArchDaemonWindows::daemonRunning(bool running)
|
||||
{
|
||||
if (s_daemon != NULL) {
|
||||
if (s_daemon != nullptr) {
|
||||
s_daemon->doDaemonRunning(running);
|
||||
}
|
||||
}
|
||||
|
||||
UINT ArchDaemonWindows::getDaemonQuitMessage()
|
||||
{
|
||||
if (s_daemon != NULL) {
|
||||
if (s_daemon != nullptr) {
|
||||
return s_daemon->doGetDaemonQuitMessage();
|
||||
} else {
|
||||
return 0;
|
||||
@ -52,7 +48,7 @@ UINT ArchDaemonWindows::getDaemonQuitMessage()
|
||||
|
||||
void ArchDaemonWindows::daemonFailed(int result)
|
||||
{
|
||||
assert(s_daemon != NULL);
|
||||
assert(s_daemon != nullptr);
|
||||
throw XArchDaemonRunFailed(result);
|
||||
}
|
||||
|
||||
@ -63,24 +59,24 @@ void ArchDaemonWindows::installDaemon(
|
||||
LOG_DEBUG("installing windows service: %s", name);
|
||||
|
||||
// open service manager
|
||||
SC_HANDLE mgr = OpenSCManager(NULL, NULL, GENERIC_WRITE);
|
||||
if (mgr == NULL) {
|
||||
SC_HANDLE mgr = OpenSCManager(nullptr, nullptr, GENERIC_WRITE);
|
||||
if (mgr == nullptr) {
|
||||
// can't open service manager
|
||||
throw XArchDaemonInstallFailed(new XArchEvalWindows);
|
||||
throw XArchDaemonInstallFailed(windowsErrorToString(GetLastError()));
|
||||
}
|
||||
|
||||
// create the service
|
||||
SC_HANDLE service = CreateService(
|
||||
mgr, name, name, 0, SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS, SERVICE_AUTO_START,
|
||||
SERVICE_ERROR_NORMAL, pathname, NULL, NULL, dependencies, NULL, NULL
|
||||
SERVICE_ERROR_NORMAL, pathname, nullptr, nullptr, dependencies, nullptr, nullptr
|
||||
);
|
||||
|
||||
if (service == NULL) {
|
||||
if (service == nullptr) {
|
||||
// can't create service
|
||||
DWORD err = GetLastError();
|
||||
if (err != ERROR_SERVICE_EXISTS) {
|
||||
CloseServiceHandle(mgr);
|
||||
throw XArchDaemonInstallFailed(new XArchEvalWindows(err));
|
||||
throw XArchDaemonInstallFailed(windowsErrorToString(err));
|
||||
}
|
||||
} else {
|
||||
// done with service (but only try to close if not null)
|
||||
@ -93,7 +89,7 @@ void ArchDaemonWindows::installDaemon(
|
||||
// open the registry key for this service
|
||||
HKEY key = openNTServicesKey();
|
||||
key = ArchMiscWindows::addKey(key, name);
|
||||
if (key == NULL) {
|
||||
if (key == nullptr) {
|
||||
// can't open key
|
||||
DWORD err = GetLastError();
|
||||
try {
|
||||
@ -101,7 +97,7 @@ void ArchDaemonWindows::installDaemon(
|
||||
} catch (...) {
|
||||
// ignore
|
||||
}
|
||||
throw XArchDaemonInstallFailed(new XArchEvalWindows(err));
|
||||
throw XArchDaemonInstallFailed(windowsErrorToString(err));
|
||||
}
|
||||
|
||||
// set the description
|
||||
@ -109,7 +105,7 @@ void ArchDaemonWindows::installDaemon(
|
||||
|
||||
// set command line
|
||||
key = ArchMiscWindows::addKey(key, _T("Parameters"));
|
||||
if (key == NULL) {
|
||||
if (key == nullptr) {
|
||||
// can't open key
|
||||
DWORD err = GetLastError();
|
||||
ArchMiscWindows::closeKey(key);
|
||||
@ -118,7 +114,7 @@ void ArchDaemonWindows::installDaemon(
|
||||
} catch (...) {
|
||||
// ignore
|
||||
}
|
||||
throw XArchDaemonInstallFailed(new XArchEvalWindows(err));
|
||||
throw XArchDaemonInstallFailed(windowsErrorToString(err));
|
||||
}
|
||||
ArchMiscWindows::setValue(key, _T("CommandLine"), commandLine);
|
||||
|
||||
@ -133,27 +129,27 @@ void ArchDaemonWindows::uninstallDaemon(const char *name)
|
||||
// remove parameters for this service. ignore failures.
|
||||
HKEY key = openNTServicesKey();
|
||||
key = ArchMiscWindows::openKey(key, name);
|
||||
if (key != NULL) {
|
||||
if (key != nullptr) {
|
||||
ArchMiscWindows::deleteKey(key, _T("Parameters"));
|
||||
ArchMiscWindows::closeKey(key);
|
||||
}
|
||||
|
||||
// open service manager
|
||||
SC_HANDLE mgr = OpenSCManager(NULL, NULL, GENERIC_WRITE);
|
||||
if (mgr == NULL) {
|
||||
SC_HANDLE mgr = OpenSCManager(nullptr, nullptr, GENERIC_WRITE);
|
||||
if (mgr == nullptr) {
|
||||
// can't open service manager
|
||||
throw XArchDaemonUninstallFailed(new XArchEvalWindows);
|
||||
throw XArchDaemonUninstallFailed(windowsErrorToString(GetLastError()));
|
||||
}
|
||||
|
||||
// open the service. oddly, you must open a service to delete it.
|
||||
SC_HANDLE service = OpenService(mgr, name, DELETE | SERVICE_STOP);
|
||||
if (service == NULL) {
|
||||
if (service == nullptr) {
|
||||
DWORD err = GetLastError();
|
||||
CloseServiceHandle(mgr);
|
||||
if (err != ERROR_SERVICE_DOES_NOT_EXIST) {
|
||||
throw XArchDaemonUninstallFailed(new XArchEvalWindows(err));
|
||||
throw XArchDaemonUninstallFailed(windowsErrorToString(err));
|
||||
}
|
||||
throw XArchDaemonUninstallNotInstalled(new XArchEvalWindows(err));
|
||||
throw XArchDaemonUninstallNotInstalled(windowsErrorToString(err));
|
||||
}
|
||||
|
||||
// stop the service. we don't care if we fail.
|
||||
@ -186,16 +182,16 @@ void ArchDaemonWindows::uninstallDaemon(const char *name)
|
||||
return;
|
||||
}
|
||||
if (err != ERROR_SERVICE_MARKED_FOR_DELETE) {
|
||||
throw XArchDaemonUninstallFailed(new XArchEvalWindows(err));
|
||||
throw XArchDaemonUninstallFailed(windowsErrorToString(err));
|
||||
}
|
||||
throw XArchDaemonUninstallNotInstalled(new XArchEvalWindows(err));
|
||||
throw XArchDaemonUninstallNotInstalled(windowsErrorToString(err));
|
||||
}
|
||||
}
|
||||
|
||||
int ArchDaemonWindows::daemonize(const char *name, DaemonFunc func)
|
||||
int ArchDaemonWindows::daemonize(const char *name, DaemonFunc const &func)
|
||||
{
|
||||
assert(name != NULL);
|
||||
assert(func != NULL);
|
||||
assert(name != nullptr);
|
||||
assert(func != nullptr);
|
||||
|
||||
// save daemon function
|
||||
m_daemonFunc = func;
|
||||
@ -204,27 +200,27 @@ int ArchDaemonWindows::daemonize(const char *name, DaemonFunc func)
|
||||
SERVICE_TABLE_ENTRY entry[2];
|
||||
entry[0].lpServiceName = const_cast<char *>(name);
|
||||
entry[0].lpServiceProc = &ArchDaemonWindows::serviceMainEntry;
|
||||
entry[1].lpServiceName = NULL;
|
||||
entry[1].lpServiceProc = NULL;
|
||||
entry[1].lpServiceName = nullptr;
|
||||
entry[1].lpServiceProc = nullptr;
|
||||
|
||||
// hook us up to the service control manager. this won't return
|
||||
// (if successful) until the processes have terminated.
|
||||
s_daemon = this;
|
||||
if (StartServiceCtrlDispatcher(entry) == 0) {
|
||||
// StartServiceCtrlDispatcher failed
|
||||
s_daemon = NULL;
|
||||
throw XArchDaemonFailed(new XArchEvalWindows);
|
||||
s_daemon = nullptr;
|
||||
throw XArchDaemonFailed(windowsErrorToString(GetLastError()));
|
||||
}
|
||||
|
||||
s_daemon = NULL;
|
||||
s_daemon = nullptr;
|
||||
return m_daemonResult;
|
||||
}
|
||||
|
||||
bool ArchDaemonWindows::canInstallDaemon(const char * /*name*/)
|
||||
{
|
||||
// check if we can open service manager for write
|
||||
SC_HANDLE mgr = OpenSCManager(NULL, NULL, GENERIC_WRITE);
|
||||
if (mgr == NULL) {
|
||||
SC_HANDLE mgr = OpenSCManager(nullptr, nullptr, GENERIC_WRITE);
|
||||
if (mgr == nullptr) {
|
||||
return false;
|
||||
}
|
||||
CloseServiceHandle(mgr);
|
||||
@ -233,14 +229,14 @@ bool ArchDaemonWindows::canInstallDaemon(const char * /*name*/)
|
||||
HKEY key = openNTServicesKey();
|
||||
ArchMiscWindows::closeKey(key);
|
||||
|
||||
return (key != NULL);
|
||||
return (key != nullptr);
|
||||
}
|
||||
|
||||
bool ArchDaemonWindows::isDaemonInstalled(const char *name)
|
||||
{
|
||||
// open service manager
|
||||
SC_HANDLE mgr = OpenSCManager(NULL, NULL, GENERIC_READ);
|
||||
if (mgr == NULL) {
|
||||
SC_HANDLE mgr = OpenSCManager(nullptr, nullptr, GENERIC_READ);
|
||||
if (mgr == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -248,17 +244,17 @@ bool ArchDaemonWindows::isDaemonInstalled(const char *name)
|
||||
SC_HANDLE service = OpenService(mgr, name, GENERIC_READ);
|
||||
|
||||
// clean up
|
||||
if (service != NULL) {
|
||||
if (service != nullptr) {
|
||||
CloseServiceHandle(service);
|
||||
}
|
||||
CloseServiceHandle(mgr);
|
||||
|
||||
return (service != NULL);
|
||||
return (service != nullptr);
|
||||
}
|
||||
|
||||
HKEY ArchDaemonWindows::openNTServicesKey()
|
||||
{
|
||||
static const char *s_keyNames[] = {_T("SYSTEM"), _T("CurrentControlSet"), _T("Services"), NULL};
|
||||
static const char *s_keyNames[] = {_T("SYSTEM"), _T("CurrentControlSet"), _T("Services"), nullptr};
|
||||
|
||||
return ArchMiscWindows::addKey(HKEY_LOCAL_MACHINE, s_keyNames);
|
||||
}
|
||||
@ -279,12 +275,12 @@ bool ArchDaemonWindows::isRunState(DWORD state)
|
||||
int ArchDaemonWindows::doRunDaemon(RunFunc run)
|
||||
{
|
||||
// should only be called from DaemonFunc
|
||||
assert(m_serviceMutex != NULL);
|
||||
assert(run != NULL);
|
||||
assert(m_serviceMutex != nullptr);
|
||||
assert(run != nullptr);
|
||||
|
||||
// create message queue for this thread
|
||||
MSG dummy;
|
||||
PeekMessage(&dummy, NULL, 0, 0, PM_NOREMOVE);
|
||||
PeekMessage(&dummy, nullptr, 0, 0, PM_NOREMOVE);
|
||||
|
||||
int result = 0;
|
||||
ARCH->lockMutex(m_serviceMutex);
|
||||
@ -348,7 +344,9 @@ void ArchDaemonWindows::setStatus(DWORD state)
|
||||
|
||||
void ArchDaemonWindows::setStatus(DWORD state, DWORD step, DWORD waitHint)
|
||||
{
|
||||
assert(s_daemon != NULL);
|
||||
assert(s_daemon != nullptr);
|
||||
|
||||
LOG_DEBUG("setting service status: state=%d, step=%d, waitHint=%d", state, step, waitHint);
|
||||
|
||||
SERVICE_STATUS status;
|
||||
status.dwServiceType = SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS;
|
||||
@ -363,7 +361,7 @@ void ArchDaemonWindows::setStatus(DWORD state, DWORD step, DWORD waitHint)
|
||||
|
||||
void ArchDaemonWindows::setStatusError(DWORD error)
|
||||
{
|
||||
assert(s_daemon != NULL);
|
||||
assert(s_daemon != nullptr);
|
||||
|
||||
SERVICE_STATUS status;
|
||||
status.dwServiceType = SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS;
|
||||
@ -411,7 +409,7 @@ void ArchDaemonWindows::serviceMain(DWORD argc, LPTSTR *argvIn)
|
||||
HKEY key = openNTServicesKey();
|
||||
key = ArchMiscWindows::openKey(key, argvIn[0]);
|
||||
key = ArchMiscWindows::openKey(key, _T("Parameters"));
|
||||
if (key != NULL) {
|
||||
if (key != nullptr) {
|
||||
commandLine = ArchMiscWindows::readValueString(key, _T("CommandLine"));
|
||||
}
|
||||
|
||||
@ -496,14 +494,14 @@ void WINAPI ArchDaemonWindows::serviceMainEntry(DWORD argc, LPTSTR *argv)
|
||||
|
||||
void ArchDaemonWindows::serviceHandler(DWORD ctrl)
|
||||
{
|
||||
assert(m_serviceMutex != NULL);
|
||||
assert(m_serviceCondVar != NULL);
|
||||
assert(m_serviceMutex != nullptr);
|
||||
assert(m_serviceCondVar != nullptr);
|
||||
|
||||
ARCH->lockMutex(m_serviceMutex);
|
||||
|
||||
// ignore request if service is already stopped
|
||||
if (s_daemon == NULL || m_serviceState == SERVICE_STOPPED) {
|
||||
if (s_daemon != NULL) {
|
||||
if (s_daemon == nullptr || m_serviceState == SERVICE_STOPPED) {
|
||||
if (s_daemon != nullptr) {
|
||||
setStatus(m_serviceState);
|
||||
}
|
||||
ARCH->unlockMutex(m_serviceMutex);
|
||||
@ -558,39 +556,39 @@ void WINAPI ArchDaemonWindows::serviceHandlerEntry(DWORD ctrl)
|
||||
void ArchDaemonWindows::start(const char *name)
|
||||
{
|
||||
// open service manager
|
||||
SC_HANDLE mgr = OpenSCManager(NULL, NULL, GENERIC_READ);
|
||||
if (mgr == NULL) {
|
||||
throw XArchDaemonFailed(new XArchEvalWindows());
|
||||
SC_HANDLE mgr = OpenSCManager(nullptr, nullptr, GENERIC_READ);
|
||||
if (mgr == nullptr) {
|
||||
throw XArchDaemonFailed(windowsErrorToString(GetLastError()));
|
||||
}
|
||||
|
||||
// open the service
|
||||
SC_HANDLE service = OpenService(mgr, name, SERVICE_START);
|
||||
|
||||
if (service == NULL) {
|
||||
if (service == nullptr) {
|
||||
CloseServiceHandle(mgr);
|
||||
throw XArchDaemonFailed(new XArchEvalWindows());
|
||||
throw XArchDaemonFailed(windowsErrorToString(GetLastError()));
|
||||
}
|
||||
|
||||
// start the service
|
||||
if (!StartService(service, 0, NULL)) {
|
||||
throw XArchDaemonFailed(new XArchEvalWindows());
|
||||
if (!StartService(service, 0, nullptr)) {
|
||||
throw XArchDaemonFailed(windowsErrorToString(GetLastError()));
|
||||
}
|
||||
}
|
||||
|
||||
void ArchDaemonWindows::stop(const char *name)
|
||||
{
|
||||
// open service manager
|
||||
SC_HANDLE mgr = OpenSCManager(NULL, NULL, GENERIC_READ);
|
||||
if (mgr == NULL) {
|
||||
throw XArchDaemonFailed(new XArchEvalWindows());
|
||||
SC_HANDLE mgr = OpenSCManager(nullptr, nullptr, GENERIC_READ);
|
||||
if (mgr == nullptr) {
|
||||
throw XArchDaemonFailed(windowsErrorToString(GetLastError()));
|
||||
}
|
||||
|
||||
// open the service
|
||||
SC_HANDLE service = OpenService(mgr, name, SERVICE_STOP | SERVICE_QUERY_STATUS);
|
||||
|
||||
if (service == NULL) {
|
||||
if (service == nullptr) {
|
||||
CloseServiceHandle(mgr);
|
||||
throw XArchDaemonFailed(new XArchEvalWindows());
|
||||
throw XArchDaemonFailed(windowsErrorToString(GetLastError()));
|
||||
}
|
||||
|
||||
// ask the service to stop, asynchronously
|
||||
@ -598,7 +596,7 @@ void ArchDaemonWindows::stop(const char *name)
|
||||
if (!ControlService(service, SERVICE_CONTROL_STOP, &ss)) {
|
||||
DWORD dwErrCode = GetLastError();
|
||||
if (dwErrCode != ERROR_SERVICE_NOT_ACTIVE) {
|
||||
throw XArchDaemonFailed(new XArchEvalWindows());
|
||||
throw XArchDaemonFailed(windowsErrorToString(GetLastError()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -9,23 +9,25 @@
|
||||
|
||||
#include "arch/IArchDaemon.h"
|
||||
#include "arch/IArchMultithread.h"
|
||||
#include "common/constants.h"
|
||||
#include <string>
|
||||
#include "common/Constants.h"
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <Windows.h>
|
||||
#include <tchar.h>
|
||||
|
||||
#include <functional>
|
||||
#include <string>
|
||||
|
||||
#define ARCH_DAEMON ArchDaemonWindows
|
||||
|
||||
//! Win32 implementation of IArchDaemon
|
||||
class ArchDaemonWindows : public IArchDaemon
|
||||
{
|
||||
public:
|
||||
typedef int (*RunFunc)(void);
|
||||
using RunFunc = std::function<int()>;
|
||||
|
||||
ArchDaemonWindows();
|
||||
virtual ~ArchDaemonWindows();
|
||||
~ArchDaemonWindows() override = default;
|
||||
|
||||
//! Run the daemon
|
||||
/*!
|
||||
@ -66,15 +68,15 @@ public:
|
||||
static UINT getDaemonQuitMessage();
|
||||
|
||||
// IArchDaemon overrides
|
||||
virtual void installDaemon(
|
||||
void installDaemon(
|
||||
const char *name, const char *description, const char *pathname, const char *commandLine, const char *dependencies
|
||||
);
|
||||
virtual void uninstallDaemon(const char *name);
|
||||
virtual void installDaemon();
|
||||
virtual void uninstallDaemon();
|
||||
virtual int daemonize(const char *name, DaemonFunc func);
|
||||
virtual bool canInstallDaemon(const char *name);
|
||||
virtual bool isDaemonInstalled(const char *name);
|
||||
) override;
|
||||
void uninstallDaemon(const char *name) override;
|
||||
void installDaemon() override;
|
||||
void uninstallDaemon() override;
|
||||
int daemonize(const char *name, DaemonFunc const &func) override;
|
||||
bool canInstallDaemon(const char *name) override;
|
||||
bool isDaemonInstalled(const char *name) override;
|
||||
std::string commandLine() const
|
||||
{
|
||||
return m_commandLine;
|
||||
|
||||
@ -1,173 +0,0 @@
|
||||
/*
|
||||
* Deskflow -- mouse and keyboard sharing utility
|
||||
* SPDX-FileCopyrightText: (C) 2012 - 2016 Symless Ltd.
|
||||
* SPDX-FileCopyrightText: (C) 2002 Chris Schoeneman
|
||||
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
|
||||
*/
|
||||
|
||||
#include "arch/win32/ArchFileWindows.h"
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <Windows.h>
|
||||
#include <shlobj.h>
|
||||
#include <string.h>
|
||||
#include <tchar.h>
|
||||
|
||||
//
|
||||
// ArchFileWindows
|
||||
//
|
||||
|
||||
ArchFileWindows::ArchFileWindows()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
ArchFileWindows::~ArchFileWindows()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
const char *ArchFileWindows::getBasename(const char *pathname)
|
||||
{
|
||||
if (pathname == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// check for last slash
|
||||
const char *basename = strrchr(pathname, '/');
|
||||
if (basename != NULL) {
|
||||
++basename;
|
||||
} else {
|
||||
basename = pathname;
|
||||
}
|
||||
|
||||
// check for last backslash
|
||||
const char *basename2 = strrchr(pathname, '\\');
|
||||
if (basename2 != NULL && basename2 > basename) {
|
||||
basename = basename2 + 1;
|
||||
}
|
||||
|
||||
return basename;
|
||||
}
|
||||
|
||||
std::string ArchFileWindows::getUserDirectory()
|
||||
{
|
||||
// try %HOMEPATH%
|
||||
TCHAR dir[MAX_PATH];
|
||||
DWORD size = sizeof(dir) / sizeof(TCHAR);
|
||||
DWORD result = GetEnvironmentVariable(_T("HOMEPATH"), dir, size);
|
||||
if (result != 0 && result <= size) {
|
||||
// sanity check -- if dir doesn't appear to start with a
|
||||
// drive letter and isn't a UNC name then don't use it
|
||||
// FIXME -- allow UNC names
|
||||
if (dir[0] != '\0' && (dir[1] == ':' || ((dir[0] == '\\' || dir[0] == '/') && (dir[1] == '\\' || dir[1] == '/')))) {
|
||||
return dir;
|
||||
}
|
||||
}
|
||||
|
||||
// get the location of the personal files. that's as close to
|
||||
// a home directory as we're likely to find.
|
||||
ITEMIDLIST *idl;
|
||||
if (SUCCEEDED(SHGetSpecialFolderLocation(NULL, CSIDL_PERSONAL, &idl))) {
|
||||
TCHAR *path = NULL;
|
||||
if (SHGetPathFromIDList(idl, dir)) {
|
||||
DWORD attr = GetFileAttributes(dir);
|
||||
if (attr != 0xffffffff && (attr & FILE_ATTRIBUTE_DIRECTORY) != 0)
|
||||
path = dir;
|
||||
}
|
||||
|
||||
IMalloc *shalloc;
|
||||
if (SUCCEEDED(SHGetMalloc(&shalloc))) {
|
||||
shalloc->Free(idl);
|
||||
shalloc->Release();
|
||||
}
|
||||
|
||||
if (path != NULL) {
|
||||
return path;
|
||||
}
|
||||
}
|
||||
|
||||
// use root of C drive as a default
|
||||
return "C:";
|
||||
}
|
||||
|
||||
std::string ArchFileWindows::getSystemDirectory()
|
||||
{
|
||||
// get windows directory
|
||||
char dir[MAX_PATH];
|
||||
if (GetWindowsDirectory(dir, sizeof(dir)) != 0) {
|
||||
return dir;
|
||||
} else {
|
||||
// can't get it. use C:\ as a default.
|
||||
return "C:";
|
||||
}
|
||||
}
|
||||
|
||||
std::string ArchFileWindows::getInstalledDirectory()
|
||||
{
|
||||
char fileNameBuffer[MAX_PATH];
|
||||
GetModuleFileName(NULL, fileNameBuffer, MAX_PATH);
|
||||
std::string fileName(fileNameBuffer);
|
||||
size_t lastSlash = fileName.find_last_of("\\");
|
||||
fileName = fileName.substr(0, lastSlash);
|
||||
|
||||
return fileName;
|
||||
}
|
||||
|
||||
std::string ArchFileWindows::getLogDirectory()
|
||||
{
|
||||
return getInstalledDirectory();
|
||||
}
|
||||
|
||||
std::string ArchFileWindows::getPluginDirectory()
|
||||
{
|
||||
if (!m_pluginDirectory.empty()) {
|
||||
return m_pluginDirectory;
|
||||
}
|
||||
|
||||
std::string dir = getProfileDirectory();
|
||||
dir.append("\\Plugins");
|
||||
return dir;
|
||||
}
|
||||
|
||||
std::string ArchFileWindows::getProfileDirectory()
|
||||
{
|
||||
std::string dir;
|
||||
if (!m_profileDirectory.empty()) {
|
||||
dir = m_profileDirectory;
|
||||
} else {
|
||||
TCHAR result[MAX_PATH];
|
||||
if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_LOCAL_APPDATA, NULL, 0, result))) {
|
||||
dir = result;
|
||||
} else {
|
||||
dir = getUserDirectory();
|
||||
}
|
||||
}
|
||||
|
||||
// HACK: append program name, this seems wrong.
|
||||
dir.append("\\Deskflow");
|
||||
|
||||
return dir;
|
||||
}
|
||||
|
||||
std::string ArchFileWindows::concatPath(const std::string &prefix, const std::string &suffix)
|
||||
{
|
||||
std::string path;
|
||||
path.reserve(prefix.size() + 1 + suffix.size());
|
||||
path += prefix;
|
||||
if (path.size() == 0 || (path[path.size() - 1] != '\\' && path[path.size() - 1] != '/')) {
|
||||
path += '\\';
|
||||
}
|
||||
path += suffix;
|
||||
return path;
|
||||
}
|
||||
|
||||
void ArchFileWindows::setProfileDirectory(const std::string &s)
|
||||
{
|
||||
m_profileDirectory = s;
|
||||
}
|
||||
|
||||
void ArchFileWindows::setPluginDirectory(const std::string &s)
|
||||
{
|
||||
m_pluginDirectory = s;
|
||||
}
|
||||
@ -1,36 +0,0 @@
|
||||
/*
|
||||
* Deskflow -- mouse and keyboard sharing utility
|
||||
* SPDX-FileCopyrightText: (C) 2012 - 2016 Symless Ltd.
|
||||
* SPDX-FileCopyrightText: (C) 2002 Chris Schoeneman
|
||||
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "arch/IArchFile.h"
|
||||
|
||||
#define ARCH_FILE ArchFileWindows
|
||||
|
||||
//! Win32 implementation of IArchFile
|
||||
class ArchFileWindows : public IArchFile
|
||||
{
|
||||
public:
|
||||
ArchFileWindows();
|
||||
virtual ~ArchFileWindows();
|
||||
|
||||
// IArchFile overrides
|
||||
virtual const char *getBasename(const char *pathname);
|
||||
virtual std::string getUserDirectory();
|
||||
virtual std::string getSystemDirectory();
|
||||
virtual std::string getInstalledDirectory();
|
||||
virtual std::string getLogDirectory();
|
||||
virtual std::string getPluginDirectory();
|
||||
virtual std::string getProfileDirectory();
|
||||
virtual std::string concatPath(const std::string &prefix, const std::string &suffix);
|
||||
virtual void setProfileDirectory(const std::string &s);
|
||||
virtual void setPluginDirectory(const std::string &s);
|
||||
|
||||
private:
|
||||
std::string m_profileDirectory;
|
||||
std::string m_pluginDirectory;
|
||||
};
|
||||
@ -14,28 +14,23 @@
|
||||
// ArchLogWindows
|
||||
//
|
||||
|
||||
ArchLogWindows::ArchLogWindows() : m_eventLog(NULL)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
ArchLogWindows::~ArchLogWindows()
|
||||
ArchLogWindows::ArchLogWindows() : m_eventLog(nullptr)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
void ArchLogWindows::openLog(const char *name)
|
||||
{
|
||||
if (m_eventLog == NULL) {
|
||||
m_eventLog = RegisterEventSource(NULL, name);
|
||||
if (m_eventLog == nullptr) {
|
||||
m_eventLog = RegisterEventSource(nullptr, name);
|
||||
}
|
||||
}
|
||||
|
||||
void ArchLogWindows::closeLog()
|
||||
{
|
||||
if (m_eventLog != NULL) {
|
||||
if (m_eventLog != nullptr) {
|
||||
DeregisterEventSource(m_eventLog);
|
||||
m_eventLog = NULL;
|
||||
m_eventLog = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
@ -46,7 +41,7 @@ void ArchLogWindows::showLog(bool)
|
||||
|
||||
void ArchLogWindows::writeLog(ELevel level, const char *msg)
|
||||
{
|
||||
if (m_eventLog != NULL) {
|
||||
if (m_eventLog != nullptr) {
|
||||
// convert priority
|
||||
WORD type;
|
||||
switch (level) {
|
||||
@ -72,9 +67,9 @@ void ArchLogWindows::writeLog(ELevel level, const char *msg)
|
||||
ReportEvent(
|
||||
m_eventLog, type, static_cast<WORD>(level),
|
||||
0, // event ID
|
||||
NULL, 0,
|
||||
nullptr, 0,
|
||||
(DWORD)strlen(msg) + 1, // raw data size
|
||||
NULL,
|
||||
nullptr,
|
||||
const_cast<char *>(msg)
|
||||
); // raw data
|
||||
}
|
||||
|
||||
@ -19,13 +19,13 @@ class ArchLogWindows : public IArchLog
|
||||
{
|
||||
public:
|
||||
ArchLogWindows();
|
||||
virtual ~ArchLogWindows();
|
||||
~ArchLogWindows() override = default;
|
||||
|
||||
// IArchLog overrides
|
||||
virtual void openLog(const char *name);
|
||||
virtual void closeLog();
|
||||
virtual void showLog(bool showIfEmpty);
|
||||
virtual void writeLog(ELevel, const char *);
|
||||
void openLog(const char *name) override;
|
||||
void closeLog() override;
|
||||
void showLog(bool showIfEmpty) override;
|
||||
void writeLog(ELevel, const char *) override;
|
||||
|
||||
private:
|
||||
HANDLE m_eventLog;
|
||||
|
||||
@ -1,106 +1,67 @@
|
||||
/*
|
||||
* Deskflow -- mouse and keyboard sharing utility
|
||||
* SPDX-FileCopyrightText: (C) 2012 - 2016 Symless Ltd.
|
||||
* SPDX-FileCopyrightText: (C) 2012 - 2016, 2024 - 2025 Symless Ltd.
|
||||
* SPDX-FileCopyrightText: (C) 2002 Chris Schoeneman
|
||||
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
|
||||
*/
|
||||
|
||||
#include "arch/win32/ArchMiscWindows.h"
|
||||
|
||||
#include "arch/XArch.h"
|
||||
#include "arch/win32/ArchDaemonWindows.h"
|
||||
#include "arch/win32/XArchWindows.h"
|
||||
#include "base/Log.h"
|
||||
#include "base/String.h"
|
||||
|
||||
#include <Wtsapi32.h>
|
||||
#pragma warning(disable : 4099)
|
||||
#include <Userenv.h>
|
||||
#pragma warning(default : 4099)
|
||||
#include <Psapi.h>
|
||||
|
||||
#include <array>
|
||||
#include <filesystem>
|
||||
|
||||
// Welcome to DLL hell! :)
|
||||
//
|
||||
// Microsoft lets you run a program with an old runtime DLL, as long as the name matches.
|
||||
// Unfortunately if you compile on VS2022 and then use the VS2019 runtime, which both have the
|
||||
// same runtime DLL name, the app will randomly crash (e.g. access violation) or break in strange
|
||||
// and unpredictable ways due to ABI differences.
|
||||
//
|
||||
// In Windows, there is no concept of requiring a minimum version of the runtime DLL, so we have
|
||||
// to check the version ourselves.
|
||||
//
|
||||
// Our CI is set up to build with the latest compiler, so in this case we should insist on the
|
||||
// latest runtime DLL.
|
||||
//
|
||||
// As a developer convenience, we also allow builds on older compilers such as the minimum
|
||||
// requirements for the current Qt version we support.
|
||||
//
|
||||
// See table of the compiler versions and the matching runtime DLL versions:
|
||||
// https://dev.to/yumetodo/list-of-mscver-and-mscfullver-8nd
|
||||
#if _MSC_VER >= 1942 // Visual Studio 2022 Update 12 (v17.12.4)
|
||||
const auto kRequiredMajor = 14;
|
||||
const auto kRequiredMinor = 42;
|
||||
#elif _MSC_VER >= 1920 // Visual Studio 2019 Update 7 (v16.7)
|
||||
const auto kRequiredMajor = 14;
|
||||
const auto kRequiredMinor = 27;
|
||||
#else
|
||||
#pragma message("MSC version: " STRINGIFY(_MSC_VER))
|
||||
#error "Unsupported MSC version"
|
||||
#endif
|
||||
// Useful for debugging Windows specific bootstrapping code before the logging system is initialized.
|
||||
// This output can be viewed by attaching a Microsoft debugger or by using the DebugView program.
|
||||
#define MS_LOG_DEBUG(message, ...) \
|
||||
OutputDebugStringA((deskflow::string::sprintf((s_binaryName + ": " + message + "\n").c_str(), __VA_ARGS__)).c_str())
|
||||
|
||||
// parent process name for services in Vista
|
||||
#define SERVICE_LAUNCHER "services.exe"
|
||||
//
|
||||
// Free functions
|
||||
//
|
||||
|
||||
#ifndef ES_SYSTEM_REQUIRED
|
||||
#define ES_SYSTEM_REQUIRED ((DWORD)0x00000001)
|
||||
#endif
|
||||
#ifndef ES_DISPLAY_REQUIRED
|
||||
#define ES_DISPLAY_REQUIRED ((DWORD)0x00000002)
|
||||
#endif
|
||||
#ifndef ES_CONTINUOUS
|
||||
#define ES_CONTINUOUS ((DWORD)0x80000000)
|
||||
#endif
|
||||
using EXECUTION_STATE = DWORD;
|
||||
void errorMessageBox(const char *message, const char *title = "Fatal Error");
|
||||
|
||||
void errorMessageBox(const char *message, const char *title = "Fatal Error")
|
||||
std::string getBinaryName()
|
||||
{
|
||||
std::array<char, MAX_PATH> buffer;
|
||||
if (!GetModuleFileNameA(nullptr, buffer.data(), MAX_PATH)) {
|
||||
errorMessageBox("Failed to get binary name.");
|
||||
abort();
|
||||
}
|
||||
|
||||
return std::filesystem::path(buffer.data()).filename().string();
|
||||
}
|
||||
|
||||
void errorMessageBox(const char *message, const char *title)
|
||||
{
|
||||
MessageBoxA(nullptr, message, title, MB_ICONERROR | MB_OK);
|
||||
}
|
||||
|
||||
// Used by bootstrap logging to differentiate between daemon and client/server messages.
|
||||
const std::string s_binaryName = getBinaryName();
|
||||
|
||||
//
|
||||
// ArchMiscWindows
|
||||
//
|
||||
|
||||
ArchMiscWindows::Dialogs *ArchMiscWindows::s_dialogs = NULL;
|
||||
DWORD ArchMiscWindows::s_busyState = 0;
|
||||
ArchMiscWindows::STES_t ArchMiscWindows::s_stes = NULL;
|
||||
HICON ArchMiscWindows::s_largeIcon = NULL;
|
||||
HICON ArchMiscWindows::s_smallIcon = NULL;
|
||||
HINSTANCE ArchMiscWindows::s_instanceWin32 = NULL;
|
||||
|
||||
void ArchMiscWindows::cleanup()
|
||||
{
|
||||
delete s_dialogs;
|
||||
}
|
||||
ArchMiscWindows::STES_t ArchMiscWindows::s_stes = nullptr;
|
||||
HICON ArchMiscWindows::s_largeIcon = nullptr;
|
||||
HICON ArchMiscWindows::s_smallIcon = nullptr;
|
||||
HINSTANCE ArchMiscWindows::s_instanceWin32 = nullptr;
|
||||
|
||||
void ArchMiscWindows::init()
|
||||
{
|
||||
// stop windows system error dialogs from showing.
|
||||
SetErrorMode(SEM_FAILCRITICALERRORS);
|
||||
|
||||
s_dialogs = new Dialogs;
|
||||
}
|
||||
|
||||
void ArchMiscWindows::setIcons(HICON largeIcon, HICON smallIcon)
|
||||
{
|
||||
s_largeIcon = largeIcon;
|
||||
s_smallIcon = smallIcon;
|
||||
}
|
||||
|
||||
void ArchMiscWindows::getIcons(HICON &largeIcon, HICON &smallIcon)
|
||||
{
|
||||
largeIcon = s_largeIcon;
|
||||
smallIcon = s_smallIcon;
|
||||
}
|
||||
|
||||
int ArchMiscWindows::runDaemon(RunFunc runFunc)
|
||||
@ -145,9 +106,9 @@ HKEY ArchMiscWindows::addKey(HKEY key, const TCHAR *const *keyNames)
|
||||
|
||||
HKEY ArchMiscWindows::openKey(HKEY key, const TCHAR *keyName, bool create)
|
||||
{
|
||||
// ignore if parent is NULL
|
||||
if (key == NULL) {
|
||||
return NULL;
|
||||
// ignore if parent is nullptr
|
||||
if (key == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// open next key
|
||||
@ -155,11 +116,11 @@ HKEY ArchMiscWindows::openKey(HKEY key, const TCHAR *keyName, bool create)
|
||||
LSTATUS result = RegOpenKeyEx(key, keyName, 0, KEY_WRITE | KEY_QUERY_VALUE, &newKey);
|
||||
if (result != ERROR_SUCCESS && create) {
|
||||
DWORD disp;
|
||||
result = RegCreateKeyEx(key, keyName, 0, NULL, 0, KEY_WRITE | KEY_QUERY_VALUE, NULL, &newKey, &disp);
|
||||
result = RegCreateKeyEx(key, keyName, 0, nullptr, 0, KEY_WRITE | KEY_QUERY_VALUE, nullptr, &newKey, &disp);
|
||||
}
|
||||
if (result != ERROR_SUCCESS) {
|
||||
RegCloseKey(key);
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// switch to new key
|
||||
@ -169,7 +130,7 @@ HKEY ArchMiscWindows::openKey(HKEY key, const TCHAR *keyName, bool create)
|
||||
|
||||
HKEY ArchMiscWindows::openKey(HKEY key, const TCHAR *const *keyNames, bool create)
|
||||
{
|
||||
for (size_t i = 0; key != NULL && keyNames[i] != NULL; ++i) {
|
||||
for (size_t i = 0; key != nullptr && keyNames[i] != nullptr; ++i) {
|
||||
// open next key
|
||||
key = openKey(key, keyNames[i], create);
|
||||
}
|
||||
@ -178,50 +139,25 @@ HKEY ArchMiscWindows::openKey(HKEY key, const TCHAR *const *keyNames, bool creat
|
||||
|
||||
void ArchMiscWindows::closeKey(HKEY key)
|
||||
{
|
||||
assert(key != NULL);
|
||||
if (key == NULL)
|
||||
assert(key != nullptr);
|
||||
if (key == nullptr)
|
||||
return;
|
||||
RegCloseKey(key);
|
||||
}
|
||||
|
||||
void ArchMiscWindows::deleteKey(HKEY key, const TCHAR *name)
|
||||
{
|
||||
assert(key != NULL);
|
||||
assert(name != NULL);
|
||||
if (key == NULL || name == NULL)
|
||||
assert(key != nullptr);
|
||||
assert(name != nullptr);
|
||||
if (key == nullptr || name == nullptr)
|
||||
return;
|
||||
RegDeleteKey(key, name);
|
||||
}
|
||||
|
||||
void ArchMiscWindows::deleteValue(HKEY key, const TCHAR *name)
|
||||
{
|
||||
assert(key != NULL);
|
||||
assert(name != NULL);
|
||||
if (key == NULL || name == NULL)
|
||||
return;
|
||||
RegDeleteValue(key, name);
|
||||
}
|
||||
|
||||
void ArchMiscWindows::deleteKeyTree(HKEY key, const TCHAR *name)
|
||||
{
|
||||
assert(key != NULL);
|
||||
assert(name != NULL);
|
||||
if (key == NULL || name == NULL)
|
||||
return;
|
||||
RegDeleteTree(key, name);
|
||||
}
|
||||
|
||||
bool ArchMiscWindows::hasValue(HKEY key, const TCHAR *name)
|
||||
{
|
||||
DWORD type;
|
||||
LONG result = RegQueryValueEx(key, name, 0, &type, NULL, NULL);
|
||||
return (result == ERROR_SUCCESS && (type == REG_DWORD || type == REG_SZ));
|
||||
}
|
||||
|
||||
ArchMiscWindows::EValueType ArchMiscWindows::typeOfValue(HKEY key, const TCHAR *name)
|
||||
{
|
||||
DWORD type;
|
||||
LONG result = RegQueryValueEx(key, name, 0, &type, NULL, NULL);
|
||||
LONG result = RegQueryValueEx(key, name, 0, &type, nullptr, nullptr);
|
||||
if (result != ERROR_SUCCESS) {
|
||||
return kNO_VALUE;
|
||||
}
|
||||
@ -242,8 +178,8 @@ ArchMiscWindows::EValueType ArchMiscWindows::typeOfValue(HKEY key, const TCHAR *
|
||||
|
||||
void ArchMiscWindows::setValue(HKEY key, const TCHAR *name, const std::string &value)
|
||||
{
|
||||
assert(key != NULL);
|
||||
if (key == NULL) {
|
||||
assert(key != nullptr);
|
||||
if (key == nullptr) {
|
||||
// TODO: throw exception
|
||||
return;
|
||||
}
|
||||
@ -252,31 +188,20 @@ void ArchMiscWindows::setValue(HKEY key, const TCHAR *name, const std::string &v
|
||||
|
||||
void ArchMiscWindows::setValue(HKEY key, const TCHAR *name, DWORD value)
|
||||
{
|
||||
assert(key != NULL);
|
||||
if (key == NULL) {
|
||||
assert(key != nullptr);
|
||||
if (key == nullptr) {
|
||||
// TODO: throw exception
|
||||
return;
|
||||
}
|
||||
RegSetValueEx(key, name, 0, REG_DWORD, reinterpret_cast<CONST BYTE *>(&value), sizeof(DWORD));
|
||||
}
|
||||
|
||||
void ArchMiscWindows::setValueBinary(HKEY key, const TCHAR *name, const std::string &value)
|
||||
{
|
||||
assert(key != NULL);
|
||||
assert(name != NULL);
|
||||
if (key == NULL || name == NULL) {
|
||||
// TODO: throw exception
|
||||
return;
|
||||
}
|
||||
RegSetValueEx(key, name, 0, REG_BINARY, reinterpret_cast<const BYTE *>(value.data()), (DWORD)value.size());
|
||||
}
|
||||
|
||||
std::string ArchMiscWindows::readBinaryOrString(HKEY key, const TCHAR *name, DWORD type)
|
||||
{
|
||||
// get the size of the string
|
||||
DWORD actualType;
|
||||
DWORD size = 0;
|
||||
LONG result = RegQueryValueEx(key, name, 0, &actualType, NULL, &size);
|
||||
LONG result = RegQueryValueEx(key, name, 0, &actualType, nullptr, &size);
|
||||
if (result != ERROR_SUCCESS || actualType != type) {
|
||||
return std::string();
|
||||
}
|
||||
@ -311,11 +236,6 @@ std::string ArchMiscWindows::readValueString(HKEY key, const TCHAR *name)
|
||||
return readBinaryOrString(key, name, REG_SZ);
|
||||
}
|
||||
|
||||
std::string ArchMiscWindows::readValueBinary(HKEY key, const TCHAR *name)
|
||||
{
|
||||
return readBinaryOrString(key, name, REG_BINARY);
|
||||
}
|
||||
|
||||
DWORD
|
||||
ArchMiscWindows::readValueInt(HKEY key, const TCHAR *name)
|
||||
{
|
||||
@ -329,26 +249,6 @@ ArchMiscWindows::readValueInt(HKEY key, const TCHAR *name)
|
||||
return value;
|
||||
}
|
||||
|
||||
void ArchMiscWindows::addDialog(HWND hwnd)
|
||||
{
|
||||
s_dialogs->insert(hwnd);
|
||||
}
|
||||
|
||||
void ArchMiscWindows::removeDialog(HWND hwnd)
|
||||
{
|
||||
s_dialogs->erase(hwnd);
|
||||
}
|
||||
|
||||
bool ArchMiscWindows::processDialog(MSG *msg)
|
||||
{
|
||||
for (Dialogs::const_iterator index = s_dialogs->begin(); index != s_dialogs->end(); ++index) {
|
||||
if (IsDialogMessage(*index, msg)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ArchMiscWindows::addBusyState(DWORD busyModes)
|
||||
{
|
||||
s_busyState |= busyModes;
|
||||
@ -364,18 +264,18 @@ void ArchMiscWindows::removeBusyState(DWORD busyModes)
|
||||
void ArchMiscWindows::setThreadExecutionState(DWORD busyModes)
|
||||
{
|
||||
// look up function dynamically so we work on older systems
|
||||
if (s_stes == NULL) {
|
||||
if (s_stes == nullptr) {
|
||||
HINSTANCE kernel = LoadLibrary("kernel32.dll");
|
||||
if (kernel != NULL) {
|
||||
if (kernel != nullptr) {
|
||||
s_stes = reinterpret_cast<STES_t>(GetProcAddress(kernel, "SetThreadExecutionState"));
|
||||
}
|
||||
if (s_stes == NULL) {
|
||||
if (s_stes == nullptr) {
|
||||
s_stes = &ArchMiscWindows::dummySetThreadExecutionState;
|
||||
}
|
||||
}
|
||||
|
||||
// convert to STES form
|
||||
EXECUTION_STATE state = 0;
|
||||
DWORD state = 0;
|
||||
if ((busyModes & kSYSTEM) != 0) {
|
||||
state |= ES_SYSTEM_REQUIRED;
|
||||
}
|
||||
@ -402,12 +302,12 @@ void ArchMiscWindows::wakeupDisplay()
|
||||
// We can't use ::setThreadExecutionState here because it sets
|
||||
// ES_CONTINUOUS, which we don't want.
|
||||
|
||||
if (s_stes == NULL) {
|
||||
if (s_stes == nullptr) {
|
||||
HINSTANCE kernel = LoadLibrary("kernel32.dll");
|
||||
if (kernel != NULL) {
|
||||
if (kernel != nullptr) {
|
||||
s_stes = reinterpret_cast<STES_t>(GetProcAddress(kernel, "SetThreadExecutionState"));
|
||||
}
|
||||
if (s_stes == NULL) {
|
||||
if (s_stes == nullptr) {
|
||||
s_stes = &ArchMiscWindows::dummySetThreadExecutionState;
|
||||
}
|
||||
}
|
||||
@ -426,7 +326,7 @@ bool ArchMiscWindows::wasLaunchedAsService()
|
||||
return false;
|
||||
}
|
||||
|
||||
return (name == SERVICE_LAUNCHER);
|
||||
return (name == "services.exe");
|
||||
}
|
||||
|
||||
bool ArchMiscWindows::getParentProcessName(std::string &name)
|
||||
@ -495,13 +395,13 @@ BOOL WINAPI ArchMiscWindows::getProcessEntry(PROCESSENTRY32 &entry, DWORD proces
|
||||
HINSTANCE
|
||||
ArchMiscWindows::instanceWin32()
|
||||
{
|
||||
assert(s_instanceWin32 != NULL);
|
||||
assert(s_instanceWin32 != nullptr);
|
||||
return s_instanceWin32;
|
||||
}
|
||||
|
||||
void ArchMiscWindows::setInstanceWin32(HINSTANCE instance)
|
||||
{
|
||||
assert(instance != NULL);
|
||||
assert(instance != nullptr);
|
||||
s_instanceWin32 = instance;
|
||||
}
|
||||
|
||||
@ -510,7 +410,7 @@ std::string ArchMiscWindows::getActiveDesktopName()
|
||||
HDESK desk = OpenInputDesktop(0, TRUE, GENERIC_READ);
|
||||
if (desk == nullptr) {
|
||||
LOG((CLOG_ERR "could not open input desktop"));
|
||||
throw XArch(new XArchEvalWindows());
|
||||
throw std::runtime_error(windowsErrorToString(GetLastError()));
|
||||
}
|
||||
|
||||
DWORD size;
|
||||
@ -521,40 +421,89 @@ std::string ArchMiscWindows::getActiveDesktopName()
|
||||
return name;
|
||||
}
|
||||
|
||||
void ArchMiscWindows::guardRuntimeVersion() // NOSONAR - `noreturn` is not available
|
||||
HMODULE ArchMiscWindows::findLoadedModule(std::array<const char *, 2> moduleNames)
|
||||
{
|
||||
const auto kRuntimeDll = "vcruntime140.dll";
|
||||
std::array<HMODULE, 1024> hModules;
|
||||
DWORD cbNeeded;
|
||||
|
||||
HMODULE hModule = nullptr;
|
||||
if (!GetModuleHandleEx(0, kRuntimeDll, &hModule) && hModule) {
|
||||
errorMessageBox("Microsoft Visual C++ Runtime is not installed.");
|
||||
HANDLE hProcess = GetCurrentProcess();
|
||||
if (!EnumProcessModules(hProcess, hModules.data(), sizeof(hModules), &cbNeeded)) {
|
||||
errorMessageBox("Failed to enumerate process modules.");
|
||||
abort();
|
||||
}
|
||||
|
||||
std::string loadedModuleName;
|
||||
for (size_t i = 0; i < (cbNeeded / sizeof(HMODULE)); ++i) {
|
||||
if (!GetModuleBaseNameA(hProcess, hModules[i], loadedModuleName.data(), sizeof(loadedModuleName))) {
|
||||
LOG_WARN("could not get base name of loaded module %d", i);
|
||||
continue;
|
||||
}
|
||||
|
||||
for (const auto &moduleName : moduleNames) {
|
||||
if (_stricmp(loadedModuleName.data(), moduleName) == 0) {
|
||||
return hModules[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Enforcing minimum MSVC runtime version is quite strict, but we have a good reason.
|
||||
//
|
||||
// Microsoft lets you run a program with an older version of the runtime DLL than the one it was
|
||||
// compiled with. This is because the runtime DLLs are supposedly ABI-compatible when the major
|
||||
// version is the same, so hypothetically MSVC runtime 14.0 is compatible with 14.42.
|
||||
// However, we have found subtle edge cases such as mutex lock causes access violation.
|
||||
//
|
||||
// Example of how Microsoft breaks ABI compatibility between minor runtime versions:
|
||||
// https://stackoverflow.com/questions/69990339/why-is-stdmutex-so-much-worse-than-stdshared-mutex-in-visual-c
|
||||
//
|
||||
// Our CI is set up to build with the latest compiler, so in this case we should insist on at least
|
||||
// the runtime DLL that was released at the same time as the compiler.
|
||||
//
|
||||
// As a developer convenience, we also allow builds on older compilers such as the minimum
|
||||
// requirements for the current Qt version we support.
|
||||
void ArchMiscWindows::guardRuntimeVersion() // NOSONAR - `noreturn` is not available
|
||||
{
|
||||
auto hModule = findLoadedModule({"vcruntime140.dll", "vcruntime140d.dll"});
|
||||
if (hModule == nullptr) {
|
||||
errorMessageBox("Failed to find MSVC runtime DLL.");
|
||||
abort();
|
||||
}
|
||||
|
||||
MS_LOG_DEBUG("found msvc runtime dll, handle: %p", hModule);
|
||||
|
||||
std::array<char, MAX_PATH> pathBuffer;
|
||||
const auto path = pathBuffer.data();
|
||||
if (!GetModuleFileNameA(hModule, path, MAX_PATH)) {
|
||||
errorMessageBox("Failed to get the path of Microsoft Visual C++ Runtime.");
|
||||
errorMessageBox("Failed to get path of MSVC runtime.");
|
||||
abort();
|
||||
}
|
||||
|
||||
MS_LOG_DEBUG("msvc runtime dll path: %s", path);
|
||||
|
||||
DWORD handle;
|
||||
DWORD size = GetFileVersionInfoSizeA(path, &handle);
|
||||
if (size <= 0) {
|
||||
errorMessageBox("Failed to get the version info size for Microsoft Visual C++ Runtime.");
|
||||
errorMessageBox("Failed to get version info size for MSVC runtime.");
|
||||
abort();
|
||||
}
|
||||
|
||||
MS_LOG_DEBUG("msvc runtime dll version info size: %d", size);
|
||||
|
||||
std::vector<BYTE> versionInfo(size);
|
||||
if (!GetFileVersionInfoA(path, handle, size, versionInfo.data())) {
|
||||
errorMessageBox("Failed to get the file version info for Microsoft Visual C++ Runtime.");
|
||||
errorMessageBox("Failed to get file version info for MSVC runtime.");
|
||||
abort();
|
||||
}
|
||||
|
||||
MS_LOG_DEBUG("msvc runtime dll version info ok, querying values");
|
||||
|
||||
VS_FIXEDFILEINFO *fileInfo = nullptr;
|
||||
const auto lplpFileInfo = reinterpret_cast<void **>(&fileInfo); // NOSONAR - Idiomatic Win32
|
||||
if (UINT len = 0; !VerQueryValueA(versionInfo.data(), "\\", lplpFileInfo, &len)) {
|
||||
errorMessageBox("Failed to get the version information for Microsoft Visual C++ Runtime.");
|
||||
errorMessageBox("Failed to query file version info for MSVC runtime.");
|
||||
abort();
|
||||
}
|
||||
|
||||
@ -562,14 +511,42 @@ void ArchMiscWindows::guardRuntimeVersion() // NOSONAR - `noreturn` is not avail
|
||||
const auto currentMinor = LOWORD(fileInfo->dwFileVersionMS);
|
||||
const auto currentBuild = HIWORD(fileInfo->dwFileVersionLS);
|
||||
|
||||
if (currentMajor < kRequiredMajor || currentMinor < kRequiredMinor) {
|
||||
MS_LOG_DEBUG("msvc runtime dll version: %d.%d.%d", currentMajor, currentMinor, currentBuild);
|
||||
|
||||
if (currentMajor < kWindowsRuntimeMajor || currentMinor < kWindowsRuntimeMinor) {
|
||||
const auto message = deskflow::string::sprintf(
|
||||
"Installed Microsoft Visual C++ Runtime v%d.%d.%d is outdated.\n\n"
|
||||
"Minimum required version: v%d.%d\n\n"
|
||||
"Please update to the latest Microsoft Visual C++ Redistributable.",
|
||||
currentMajor, currentMinor, currentBuild, kRequiredMajor, kRequiredMinor
|
||||
currentMajor, currentMinor, currentBuild, kWindowsRuntimeMajor, kWindowsRuntimeMinor
|
||||
);
|
||||
MessageBoxA(nullptr, message.c_str(), "Dependency Error", MB_ICONERROR | MB_OK);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
bool ArchMiscWindows::isProcessElevated()
|
||||
{
|
||||
LOG_DEBUG("checking if process is elevated");
|
||||
|
||||
HANDLE hToken = nullptr;
|
||||
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)) {
|
||||
throw std::runtime_error(windowsErrorToString(GetLastError()));
|
||||
}
|
||||
|
||||
TOKEN_ELEVATION elevation;
|
||||
|
||||
try {
|
||||
DWORD dwSize = sizeof(TOKEN_ELEVATION);
|
||||
if (!GetTokenInformation(hToken, TokenElevation, &elevation, sizeof(elevation), &dwSize)) {
|
||||
throw std::runtime_error(windowsErrorToString(GetLastError()));
|
||||
}
|
||||
} catch (...) {
|
||||
CloseHandle(hToken);
|
||||
throw;
|
||||
}
|
||||
|
||||
const auto isElevated = elevation.TokenIsElevated;
|
||||
LOG_DEBUG("process is %s", isElevated ? "elevated" : "not elevated");
|
||||
return isElevated;
|
||||
}
|
||||
|
||||
@ -7,7 +7,6 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/stdset.h"
|
||||
#include <string>
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
@ -15,6 +14,8 @@
|
||||
|
||||
#include <Tlhelp32.h>
|
||||
|
||||
#include <functional>
|
||||
|
||||
//! Miscellaneous win32 functions.
|
||||
class ArchMiscWindows
|
||||
{
|
||||
@ -34,26 +35,11 @@ public:
|
||||
kDISPLAY = 0x0002
|
||||
};
|
||||
|
||||
typedef int (*RunFunc)(void);
|
||||
using RunFunc = std::function<int(void)>;
|
||||
|
||||
//! Initialize
|
||||
static void init();
|
||||
|
||||
//! Delete memory
|
||||
static void cleanup();
|
||||
|
||||
//! Set the application icons
|
||||
/*!
|
||||
Set the application icons.
|
||||
*/
|
||||
static void setIcons(HICON largeIcon, HICON smallIcon);
|
||||
|
||||
//! Get the application icons
|
||||
/*!
|
||||
Get the application icons.
|
||||
*/
|
||||
static void getIcons(HICON &largeIcon, HICON &smallIcon);
|
||||
|
||||
//! Run the daemon
|
||||
/*!
|
||||
Delegates to ArchDaemonWindows.
|
||||
@ -96,15 +82,6 @@ public:
|
||||
//! Delete a key (which should have no subkeys)
|
||||
static void deleteKey(HKEY parent, const TCHAR *name);
|
||||
|
||||
//! Delete a value
|
||||
static void deleteValue(HKEY parent, const TCHAR *name);
|
||||
|
||||
//! Delete a tree of keys from the registry
|
||||
static void deleteKeyTree(HKEY parent, const TCHAR *name);
|
||||
|
||||
//! Test if a value exists
|
||||
static bool hasValue(HKEY key, const TCHAR *name);
|
||||
|
||||
//! Get type of value
|
||||
static EValueType typeOfValue(HKEY key, const TCHAR *name);
|
||||
|
||||
@ -114,34 +91,12 @@ public:
|
||||
//! Set a DWORD value in the registry
|
||||
static void setValue(HKEY key, const TCHAR *name, DWORD value);
|
||||
|
||||
//! Set a BINARY value in the registry
|
||||
/*!
|
||||
Sets the \p name value of \p key to \p value.data().
|
||||
*/
|
||||
static void setValueBinary(HKEY key, const TCHAR *name, const std::string &value);
|
||||
|
||||
//! Read a string value from the registry
|
||||
static std::string readValueString(HKEY, const TCHAR *name);
|
||||
|
||||
//! Read a DWORD value from the registry
|
||||
static DWORD readValueInt(HKEY, const TCHAR *name);
|
||||
|
||||
//! Read a BINARY value from the registry
|
||||
static std::string readValueBinary(HKEY, const TCHAR *name);
|
||||
|
||||
//! Add a dialog
|
||||
static void addDialog(HWND);
|
||||
|
||||
//! Remove a dialog
|
||||
static void removeDialog(HWND);
|
||||
|
||||
//! Process dialog message
|
||||
/*!
|
||||
Checks if the message is destined for a dialog. If so the message
|
||||
is passed to the dialog and returns true, otherwise returns false.
|
||||
*/
|
||||
static bool processDialog(MSG *);
|
||||
|
||||
//! Disable power saving
|
||||
static void addBusyState(DWORD busyModes);
|
||||
|
||||
@ -160,13 +115,21 @@ public:
|
||||
//! Prevent hard to troubleshoot errors, e.g. access violations.
|
||||
static void guardRuntimeVersion();
|
||||
|
||||
//! Gets the window instance saved at program start.
|
||||
/*!
|
||||
e.g. Used by `GetModuleFileName` which is used when installing the daemon.
|
||||
*/
|
||||
static HINSTANCE instanceWin32();
|
||||
|
||||
//! Saves the window instance for later use.
|
||||
static void setInstanceWin32(HINSTANCE instance);
|
||||
static BOOL WINAPI getProcessEntry(PROCESSENTRY32 &entry, DWORD processID);
|
||||
static BOOL WINAPI getSelfProcessEntry(PROCESSENTRY32 &entry);
|
||||
static BOOL WINAPI getParentProcessEntry(PROCESSENTRY32 &entry);
|
||||
|
||||
//! Get the name of the active input desktop.
|
||||
static std::string getActiveDesktopName();
|
||||
|
||||
//! Returns true if the process is running with elevated privileges (i.e. as admin).
|
||||
static bool isProcessElevated();
|
||||
|
||||
private:
|
||||
//! Open and return a registry key, closing the parent key
|
||||
static HKEY openKey(HKEY parent, const TCHAR *child, bool create);
|
||||
@ -180,15 +143,29 @@ private:
|
||||
//! Set thread busy state
|
||||
static void setThreadExecutionState(DWORD);
|
||||
|
||||
//! Dummy function for thread execution state
|
||||
static DWORD WINAPI dummySetThreadExecutionState(DWORD);
|
||||
|
||||
//! Iterates over the process snapshot to find a process entry
|
||||
static BOOL WINAPI getProcessEntry(PROCESSENTRY32 &entry, DWORD processID);
|
||||
|
||||
//! Calls `getProcessEntry` with the current process ID
|
||||
static BOOL WINAPI getSelfProcessEntry(PROCESSENTRY32 &entry);
|
||||
|
||||
//! Calls `getProcessEntry` with the parent process ID
|
||||
static BOOL WINAPI getParentProcessEntry(PROCESSENTRY32 &entry);
|
||||
|
||||
//! Searches the loaded modules and returns the matching module handle
|
||||
/**
|
||||
* @param moduleNames Provide two module names to search for both release and debug versions.
|
||||
*/
|
||||
static HMODULE findLoadedModule(std::array<const char *, 2> moduleNames);
|
||||
|
||||
private:
|
||||
using Dialogs = std::set<HWND>;
|
||||
typedef DWORD(WINAPI *STES_t)(DWORD);
|
||||
|
||||
static Dialogs *s_dialogs;
|
||||
static DWORD s_busyState;
|
||||
static STES_t s_stes;
|
||||
static STES_t s_stes; // STES: Set thread execution state
|
||||
static HICON s_largeIcon;
|
||||
static HICON s_smallIcon;
|
||||
static HINSTANCE s_instanceWin32;
|
||||
|
||||
@ -50,16 +50,16 @@ public:
|
||||
|
||||
ArchThreadImpl::ArchThreadImpl()
|
||||
: m_refCount(1),
|
||||
m_thread(NULL),
|
||||
m_thread(nullptr),
|
||||
m_id(0),
|
||||
m_func(NULL),
|
||||
m_userData(NULL),
|
||||
m_func(nullptr),
|
||||
m_userData(nullptr),
|
||||
m_cancelling(false),
|
||||
m_result(NULL),
|
||||
m_networkData(NULL)
|
||||
m_result(nullptr),
|
||||
m_networkData(nullptr)
|
||||
{
|
||||
m_exit = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
m_cancel = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
m_exit = CreateEvent(nullptr, TRUE, FALSE, nullptr);
|
||||
m_cancel = CreateEvent(nullptr, TRUE, FALSE, nullptr);
|
||||
}
|
||||
|
||||
ArchThreadImpl::~ArchThreadImpl()
|
||||
@ -72,17 +72,17 @@ ArchThreadImpl::~ArchThreadImpl()
|
||||
// ArchMultithreadWindows
|
||||
//
|
||||
|
||||
ArchMultithreadWindows *ArchMultithreadWindows::s_instance = NULL;
|
||||
ArchMultithreadWindows *ArchMultithreadWindows::s_instance = nullptr;
|
||||
|
||||
ArchMultithreadWindows::ArchMultithreadWindows()
|
||||
{
|
||||
assert(s_instance == NULL);
|
||||
assert(s_instance == nullptr);
|
||||
s_instance = this;
|
||||
|
||||
// no signal handlers
|
||||
for (size_t i = 0; i < kNUM_SIGNALS; ++i) {
|
||||
m_signalFunc[i] = NULL;
|
||||
m_signalUserData[i] = NULL;
|
||||
m_signalFunc[i] = nullptr;
|
||||
m_signalUserData[i] = nullptr;
|
||||
}
|
||||
|
||||
// create mutex for thread list
|
||||
@ -91,14 +91,14 @@ ArchMultithreadWindows::ArchMultithreadWindows()
|
||||
// create thread for calling (main) thread and add it to our
|
||||
// list. no need to lock the mutex since we're the only thread.
|
||||
m_mainThread = new ArchThreadImpl;
|
||||
m_mainThread->m_thread = NULL;
|
||||
m_mainThread->m_thread = nullptr;
|
||||
m_mainThread->m_id = GetCurrentThreadId();
|
||||
insert(m_mainThread);
|
||||
}
|
||||
|
||||
ArchMultithreadWindows::~ArchMultithreadWindows()
|
||||
{
|
||||
s_instance = NULL;
|
||||
s_instance = nullptr;
|
||||
|
||||
// clean up thread list
|
||||
for (ThreadList::iterator index = m_threadList.begin(); index != m_threadList.end(); ++index) {
|
||||
@ -142,8 +142,8 @@ ArchMultithreadWindows *ArchMultithreadWindows::getInstance()
|
||||
ArchCond ArchMultithreadWindows::newCondVar()
|
||||
{
|
||||
ArchCondImpl *cond = new ArchCondImpl;
|
||||
cond->m_events[ArchCondImpl::kSignal] = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||
cond->m_events[ArchCondImpl::kBroadcast] = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
cond->m_events[ArchCondImpl::kSignal] = CreateEvent(nullptr, FALSE, FALSE, nullptr);
|
||||
cond->m_events[ArchCondImpl::kBroadcast] = CreateEvent(nullptr, TRUE, FALSE, nullptr);
|
||||
cond->m_waitCountMutex = newMutex();
|
||||
cond->m_waitCount = 0;
|
||||
return cond;
|
||||
@ -272,14 +272,14 @@ ArchThread ArchMultithreadWindows::newThread(ThreadFunc func, void *data)
|
||||
|
||||
// create thread
|
||||
unsigned int id = 0;
|
||||
thread->m_thread = reinterpret_cast<HANDLE>(_beginthreadex(NULL, 0, threadFunc, (void *)thread, 0, &id));
|
||||
thread->m_thread = reinterpret_cast<HANDLE>(_beginthreadex(nullptr, 0, threadFunc, (void *)thread, 0, &id));
|
||||
thread->m_id = static_cast<DWORD>(id);
|
||||
|
||||
// check if thread was started
|
||||
if (thread->m_thread == 0) {
|
||||
// failed to start thread so clean up
|
||||
delete thread;
|
||||
thread = NULL;
|
||||
thread = nullptr;
|
||||
} else {
|
||||
// add thread to list
|
||||
insert(thread);
|
||||
@ -299,18 +299,18 @@ ArchThread ArchMultithreadWindows::newCurrentThread()
|
||||
lockMutex(m_threadMutex);
|
||||
ArchThreadImpl *thread = find(GetCurrentThreadId());
|
||||
unlockMutex(m_threadMutex);
|
||||
assert(thread != NULL);
|
||||
assert(thread != nullptr);
|
||||
return thread;
|
||||
}
|
||||
|
||||
void ArchMultithreadWindows::closeThread(ArchThread thread)
|
||||
{
|
||||
assert(thread != NULL);
|
||||
assert(thread != nullptr);
|
||||
|
||||
// decrement ref count and clean up thread if no more references
|
||||
if (--thread->m_refCount == 0) {
|
||||
// close the handle (main thread has a NULL handle)
|
||||
if (thread->m_thread != NULL) {
|
||||
// close the handle (main thread has a nullptr handle)
|
||||
if (thread->m_thread != nullptr) {
|
||||
CloseHandle(thread->m_thread);
|
||||
}
|
||||
|
||||
@ -333,7 +333,7 @@ ArchThread ArchMultithreadWindows::copyThread(ArchThread thread)
|
||||
|
||||
void ArchMultithreadWindows::cancelThread(ArchThread thread)
|
||||
{
|
||||
assert(thread != NULL);
|
||||
assert(thread != nullptr);
|
||||
|
||||
// set cancel flag
|
||||
SetEvent(thread->m_cancel);
|
||||
@ -380,7 +380,7 @@ void ArchMultithreadWindows::setPriorityOfThread(ArchThread thread, int n)
|
||||
#endif
|
||||
static const size_t s_pBase = 8; // index of normal priority
|
||||
|
||||
assert(thread != NULL);
|
||||
assert(thread != nullptr);
|
||||
|
||||
size_t index;
|
||||
if (n > 0 && s_pBase < (size_t)n) {
|
||||
@ -410,7 +410,7 @@ void ArchMultithreadWindows::testCancelThread()
|
||||
|
||||
bool ArchMultithreadWindows::wait(ArchThread target, double timeout)
|
||||
{
|
||||
assert(target != NULL);
|
||||
assert(target != nullptr);
|
||||
|
||||
lockMutex(m_threadMutex);
|
||||
|
||||
@ -502,7 +502,7 @@ void ArchMultithreadWindows::setSignalHandler(ESignal signal, SignalFunc func, v
|
||||
void ArchMultithreadWindows::raiseSignal(ESignal signal)
|
||||
{
|
||||
lockMutex(m_threadMutex);
|
||||
if (m_signalFunc[signal] != NULL) {
|
||||
if (m_signalFunc[signal] != nullptr) {
|
||||
m_signalFunc[signal](signal, m_signalUserData[signal]);
|
||||
ARCH->unblockPollSocket(m_mainThread);
|
||||
} else if (signal == kINTERRUPT || signal == kTERMINATE) {
|
||||
@ -514,7 +514,7 @@ void ArchMultithreadWindows::raiseSignal(ESignal signal)
|
||||
ArchThreadImpl *ArchMultithreadWindows::find(DWORD id)
|
||||
{
|
||||
ArchThreadImpl *impl = findNoRef(id);
|
||||
if (impl != NULL) {
|
||||
if (impl != nullptr) {
|
||||
refThread(impl);
|
||||
}
|
||||
return impl;
|
||||
@ -523,13 +523,13 @@ ArchThreadImpl *ArchMultithreadWindows::find(DWORD id)
|
||||
ArchThreadImpl *ArchMultithreadWindows::findNoRef(DWORD id)
|
||||
{
|
||||
ArchThreadImpl *impl = findNoRefOrCreate(id);
|
||||
if (impl == NULL) {
|
||||
if (impl == nullptr) {
|
||||
// create thread for calling thread which isn't in our list and
|
||||
// add it to the list. this won't normally happen but it can if
|
||||
// the system calls us under a new thread, like it does when we
|
||||
// run as a service.
|
||||
impl = new ArchThreadImpl;
|
||||
impl->m_thread = NULL;
|
||||
impl->m_thread = nullptr;
|
||||
impl->m_id = GetCurrentThreadId();
|
||||
insert(impl);
|
||||
}
|
||||
@ -544,15 +544,15 @@ ArchThreadImpl *ArchMultithreadWindows::findNoRefOrCreate(DWORD id)
|
||||
return *index;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void ArchMultithreadWindows::insert(ArchThreadImpl *thread)
|
||||
{
|
||||
assert(thread != NULL);
|
||||
assert(thread != nullptr);
|
||||
|
||||
// thread shouldn't already be on the list
|
||||
assert(findNoRefOrCreate(thread->m_id) == NULL);
|
||||
assert(findNoRefOrCreate(thread->m_id) == nullptr);
|
||||
|
||||
// append to list
|
||||
m_threadList.push_back(thread);
|
||||
@ -570,14 +570,14 @@ void ArchMultithreadWindows::erase(ArchThreadImpl *thread)
|
||||
|
||||
void ArchMultithreadWindows::refThread(ArchThreadImpl *thread)
|
||||
{
|
||||
assert(thread != NULL);
|
||||
assert(findNoRefOrCreate(thread->m_id) != NULL);
|
||||
assert(thread != nullptr);
|
||||
assert(findNoRefOrCreate(thread->m_id) != nullptr);
|
||||
++thread->m_refCount;
|
||||
}
|
||||
|
||||
void ArchMultithreadWindows::testCancelThreadImpl(ArchThreadImpl *thread)
|
||||
{
|
||||
assert(thread != NULL);
|
||||
assert(thread != nullptr);
|
||||
|
||||
// poll cancel event. return if not set.
|
||||
const DWORD result = WaitForSingleObject(thread->m_cancel, 0);
|
||||
@ -616,7 +616,7 @@ void ArchMultithreadWindows::doThreadFunc(ArchThread thread)
|
||||
lockMutex(m_threadMutex);
|
||||
unlockMutex(m_threadMutex);
|
||||
|
||||
void *result = NULL;
|
||||
void *result = nullptr;
|
||||
try {
|
||||
// go
|
||||
result = (*thread->m_func)(thread->m_userData);
|
||||
|
||||
@ -8,7 +8,8 @@
|
||||
#pragma once
|
||||
|
||||
#include "arch/IArchMultithread.h"
|
||||
#include "common/stdlist.h"
|
||||
|
||||
#include <list>
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <Windows.h>
|
||||
@ -40,7 +41,7 @@ class ArchMultithreadWindows : public IArchMultithread
|
||||
{
|
||||
public:
|
||||
ArchMultithreadWindows();
|
||||
virtual ~ArchMultithreadWindows();
|
||||
~ArchMultithreadWindows() override;
|
||||
|
||||
//! @name manipulators
|
||||
//@{
|
||||
@ -60,29 +61,29 @@ public:
|
||||
//@}
|
||||
|
||||
// IArchMultithread overrides
|
||||
virtual ArchCond newCondVar();
|
||||
virtual void closeCondVar(ArchCond);
|
||||
virtual void signalCondVar(ArchCond);
|
||||
virtual void broadcastCondVar(ArchCond);
|
||||
virtual bool waitCondVar(ArchCond, ArchMutex, double timeout);
|
||||
virtual ArchMutex newMutex();
|
||||
virtual void closeMutex(ArchMutex);
|
||||
virtual void lockMutex(ArchMutex);
|
||||
virtual void unlockMutex(ArchMutex);
|
||||
virtual ArchThread newThread(ThreadFunc, void *);
|
||||
virtual ArchThread newCurrentThread();
|
||||
virtual ArchThread copyThread(ArchThread);
|
||||
virtual void closeThread(ArchThread);
|
||||
virtual void cancelThread(ArchThread);
|
||||
virtual void setPriorityOfThread(ArchThread, int n);
|
||||
virtual void testCancelThread();
|
||||
virtual bool wait(ArchThread, double timeout);
|
||||
virtual bool isSameThread(ArchThread, ArchThread);
|
||||
virtual bool isExitedThread(ArchThread);
|
||||
virtual void *getResultOfThread(ArchThread);
|
||||
virtual ThreadID getIDOfThread(ArchThread);
|
||||
virtual void setSignalHandler(ESignal, SignalFunc, void *);
|
||||
virtual void raiseSignal(ESignal);
|
||||
ArchCond newCondVar() override;
|
||||
void closeCondVar(ArchCond) override;
|
||||
void signalCondVar(ArchCond) override;
|
||||
void broadcastCondVar(ArchCond) override;
|
||||
bool waitCondVar(ArchCond, ArchMutex, double timeout) override;
|
||||
ArchMutex newMutex() override;
|
||||
void closeMutex(ArchMutex) override;
|
||||
void lockMutex(ArchMutex) override;
|
||||
void unlockMutex(ArchMutex) override;
|
||||
ArchThread newThread(ThreadFunc, void *) override;
|
||||
ArchThread newCurrentThread() override;
|
||||
ArchThread copyThread(ArchThread) override;
|
||||
void closeThread(ArchThread) override;
|
||||
void cancelThread(ArchThread) override;
|
||||
void setPriorityOfThread(ArchThread, int n) override;
|
||||
void testCancelThread() override;
|
||||
bool wait(ArchThread, double timeout) override;
|
||||
bool isSameThread(ArchThread, ArchThread) override;
|
||||
bool isExitedThread(ArchThread) override;
|
||||
void *getResultOfThread(ArchThread) override;
|
||||
ThreadID getIDOfThread(ArchThread) override;
|
||||
void setSignalHandler(ESignal, SignalFunc, void *) override;
|
||||
void raiseSignal(ESignal) override;
|
||||
|
||||
private:
|
||||
ArchThreadImpl *find(DWORD id);
|
||||
|
||||
@ -8,6 +8,7 @@
|
||||
#include "arch/win32/ArchNetworkWinsock.h"
|
||||
#include "arch/Arch.h"
|
||||
#include "arch/IArchMultithread.h"
|
||||
#include "arch/XArch.h"
|
||||
#include "arch/win32/ArchMultithreadWindows.h"
|
||||
#include "arch/win32/XArchWindows.h"
|
||||
|
||||
@ -58,7 +59,7 @@ static int(PASCAL FAR *WSAEnumNetworkEvents_winsock)(SOCKET, WSAEVENT, LPWSANETW
|
||||
|
||||
#define setfunc(var, name, type) var = (type)netGetProcAddress(module, #name)
|
||||
|
||||
static HMODULE s_networkModule = NULL;
|
||||
static HMODULE s_networkModule = nullptr;
|
||||
|
||||
static FARPROC netGetProcAddress(HMODULE module, LPCSTR name)
|
||||
{
|
||||
@ -81,20 +82,20 @@ ArchNetAddressImpl *ArchNetAddressImpl::alloc(size_t size)
|
||||
// ArchNetworkWinsock
|
||||
//
|
||||
|
||||
ArchNetworkWinsock::ArchNetworkWinsock() : m_mutex(NULL)
|
||||
ArchNetworkWinsock::ArchNetworkWinsock() : m_mutex(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
ArchNetworkWinsock::~ArchNetworkWinsock()
|
||||
{
|
||||
if (s_networkModule != NULL) {
|
||||
if (s_networkModule != nullptr) {
|
||||
WSACleanup_winsock();
|
||||
::FreeLibrary(s_networkModule);
|
||||
|
||||
WSACleanup_winsock = NULL;
|
||||
s_networkModule = NULL;
|
||||
WSACleanup_winsock = nullptr;
|
||||
s_networkModule = nullptr;
|
||||
}
|
||||
if (m_mutex != NULL) {
|
||||
if (m_mutex != nullptr) {
|
||||
ARCH->closeMutex(m_mutex);
|
||||
}
|
||||
|
||||
@ -108,8 +109,8 @@ void ArchNetworkWinsock::init()
|
||||
{
|
||||
static const char *s_library[] = {"ws2_32.dll"};
|
||||
|
||||
assert(WSACleanup_winsock == NULL);
|
||||
assert(s_networkModule == NULL);
|
||||
assert(WSACleanup_winsock == nullptr);
|
||||
assert(s_networkModule == nullptr);
|
||||
|
||||
// try each winsock library
|
||||
for (size_t i = 0; i < sizeof(s_library) / sizeof(s_library[0]); ++i) {
|
||||
@ -128,7 +129,7 @@ void ArchNetworkWinsock::init()
|
||||
|
||||
void ArchNetworkWinsock::initModule(HMODULE module)
|
||||
{
|
||||
if (module == NULL) {
|
||||
if (module == nullptr) {
|
||||
throw XArchNetworkSupport("");
|
||||
}
|
||||
|
||||
@ -141,7 +142,7 @@ void ArchNetworkWinsock::initModule(HMODULE module)
|
||||
WSADATA data;
|
||||
int err = startup(version, &data);
|
||||
if (data.wVersion != version) {
|
||||
throw XArchNetworkSupport(new XArchEvalWinsock(err));
|
||||
throw XArchNetworkSupport(winsockErrorToString(err));
|
||||
}
|
||||
if (err != 0) {
|
||||
// some other initialization error
|
||||
@ -229,7 +230,7 @@ ArchSocket ArchNetworkWinsock::newSocket(EAddressFamily family, ESocketType type
|
||||
|
||||
ArchSocket ArchNetworkWinsock::copySocket(ArchSocket s)
|
||||
{
|
||||
assert(s != NULL);
|
||||
assert(s != nullptr);
|
||||
|
||||
// ref the socket and return it
|
||||
ARCH->lockMutex(m_mutex);
|
||||
@ -240,7 +241,7 @@ ArchSocket ArchNetworkWinsock::copySocket(ArchSocket s)
|
||||
|
||||
void ArchNetworkWinsock::closeSocket(ArchSocket s)
|
||||
{
|
||||
assert(s != NULL);
|
||||
assert(s != nullptr);
|
||||
|
||||
// unref the socket and note if it should be released
|
||||
ARCH->lockMutex(m_mutex);
|
||||
@ -264,7 +265,7 @@ void ArchNetworkWinsock::closeSocket(ArchSocket s)
|
||||
|
||||
void ArchNetworkWinsock::closeSocketForRead(ArchSocket s)
|
||||
{
|
||||
assert(s != NULL);
|
||||
assert(s != nullptr);
|
||||
|
||||
if (shutdown_winsock(s->m_socket, SD_RECEIVE) == SOCKET_ERROR) {
|
||||
if (getsockerror_winsock() != WSAENOTCONN) {
|
||||
@ -275,7 +276,7 @@ void ArchNetworkWinsock::closeSocketForRead(ArchSocket s)
|
||||
|
||||
void ArchNetworkWinsock::closeSocketForWrite(ArchSocket s)
|
||||
{
|
||||
assert(s != NULL);
|
||||
assert(s != nullptr);
|
||||
|
||||
if (shutdown_winsock(s->m_socket, SD_SEND) == SOCKET_ERROR) {
|
||||
if (getsockerror_winsock() != WSAENOTCONN) {
|
||||
@ -286,8 +287,8 @@ void ArchNetworkWinsock::closeSocketForWrite(ArchSocket s)
|
||||
|
||||
void ArchNetworkWinsock::bindSocket(ArchSocket s, ArchNetAddress addr)
|
||||
{
|
||||
assert(s != NULL);
|
||||
assert(addr != NULL);
|
||||
assert(s != nullptr);
|
||||
assert(addr != nullptr);
|
||||
|
||||
if (bind_winsock(s->m_socket, TYPED_ADDR(struct sockaddr, addr), addr->m_len) == SOCKET_ERROR) {
|
||||
throwError(getsockerror_winsock());
|
||||
@ -296,7 +297,7 @@ void ArchNetworkWinsock::bindSocket(ArchSocket s, ArchNetAddress addr)
|
||||
|
||||
void ArchNetworkWinsock::listenOnSocket(ArchSocket s)
|
||||
{
|
||||
assert(s != NULL);
|
||||
assert(s != nullptr);
|
||||
|
||||
// hardcoding backlog
|
||||
if (listen_winsock(s->m_socket, 3) == SOCKET_ERROR) {
|
||||
@ -306,7 +307,7 @@ void ArchNetworkWinsock::listenOnSocket(ArchSocket s)
|
||||
|
||||
ArchSocket ArchNetworkWinsock::acceptSocket(ArchSocket s, ArchNetAddress *const addr)
|
||||
{
|
||||
assert(s != NULL);
|
||||
assert(s != nullptr);
|
||||
|
||||
// create new socket and temporary address
|
||||
ArchSocketImpl *socket = new ArchSocketImpl;
|
||||
@ -319,10 +320,10 @@ ArchSocket ArchNetworkWinsock::acceptSocket(ArchSocket s, ArchNetAddress *const
|
||||
delete socket;
|
||||
free(tmp);
|
||||
if (addr) {
|
||||
*addr = NULL;
|
||||
*addr = nullptr;
|
||||
}
|
||||
if (err == WSAEWOULDBLOCK) {
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
throwError(err);
|
||||
}
|
||||
@ -334,7 +335,7 @@ ArchSocket ArchNetworkWinsock::acceptSocket(ArchSocket s, ArchNetAddress *const
|
||||
delete socket;
|
||||
free(tmp);
|
||||
if (addr) {
|
||||
*addr = NULL;
|
||||
*addr = nullptr;
|
||||
}
|
||||
throw;
|
||||
}
|
||||
@ -346,7 +347,7 @@ ArchSocket ArchNetworkWinsock::acceptSocket(ArchSocket s, ArchNetAddress *const
|
||||
socket->m_pollWrite = true;
|
||||
|
||||
// copy address if requested
|
||||
if (addr != NULL) {
|
||||
if (addr != nullptr) {
|
||||
*addr = ARCH->copyAddr(tmp);
|
||||
}
|
||||
|
||||
@ -356,8 +357,8 @@ ArchSocket ArchNetworkWinsock::acceptSocket(ArchSocket s, ArchNetAddress *const
|
||||
|
||||
bool ArchNetworkWinsock::connectSocket(ArchSocket s, ArchNetAddress addr)
|
||||
{
|
||||
assert(s != NULL);
|
||||
assert(addr != NULL);
|
||||
assert(s != nullptr);
|
||||
assert(addr != nullptr);
|
||||
|
||||
if (connect_winsock(s->m_socket, TYPED_ADDR(struct sockaddr, addr), addr->m_len) == SOCKET_ERROR) {
|
||||
if (getsockerror_winsock() == WSAEISCONN) {
|
||||
@ -384,7 +385,7 @@ int ArchNetworkWinsock::pollSocket(PollEntry pe[], int num, double timeout)
|
||||
pe[i].m_revents = 0;
|
||||
|
||||
// set invalid flag if socket is bogus then go to next socket
|
||||
if (pe[i].m_socket == NULL) {
|
||||
if (pe[i].m_socket == nullptr) {
|
||||
pe[i].m_revents |= kPOLLNVAL;
|
||||
continue;
|
||||
}
|
||||
@ -428,7 +429,7 @@ int ArchNetworkWinsock::pollSocket(PollEntry pe[], int num, double timeout)
|
||||
ArchThread thread = mt->newCurrentThread();
|
||||
WSAEVENT *unblockEvent = (WSAEVENT *)mt->getNetworkDataForThread(thread);
|
||||
ARCH->closeThread(thread);
|
||||
if (unblockEvent == NULL) {
|
||||
if (unblockEvent == nullptr) {
|
||||
unblockEvent = new WSAEVENT;
|
||||
m_unblockEvents.push_back(unblockEvent);
|
||||
*unblockEvent = WSACreateEvent_winsock();
|
||||
@ -467,7 +468,7 @@ int ArchNetworkWinsock::pollSocket(PollEntry pe[], int num, double timeout)
|
||||
}
|
||||
for (i = 0, n = 0; i < num; ++i) {
|
||||
// skip events we didn't check
|
||||
if (pe[i].m_socket == NULL || (pe[i].m_events & (kPOLLIN | kPOLLOUT)) == 0) {
|
||||
if (pe[i].m_socket == nullptr || (pe[i].m_events & (kPOLLIN | kPOLLOUT)) == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -522,14 +523,14 @@ void ArchNetworkWinsock::unblockPollSocket(ArchThread thread)
|
||||
// set the unblock event
|
||||
ArchMultithreadWindows *mt = ArchMultithreadWindows::getInstance();
|
||||
WSAEVENT *unblockEvent = (WSAEVENT *)mt->getNetworkDataForThread(thread);
|
||||
if (unblockEvent != NULL) {
|
||||
if (unblockEvent != nullptr) {
|
||||
WSASetEvent_winsock(*unblockEvent);
|
||||
}
|
||||
}
|
||||
|
||||
size_t ArchNetworkWinsock::readSocket(ArchSocket s, void *buf, size_t len)
|
||||
{
|
||||
assert(s != NULL);
|
||||
assert(s != nullptr);
|
||||
|
||||
int n = recv_winsock(s->m_socket, buf, (int)len, 0);
|
||||
if (n == SOCKET_ERROR) {
|
||||
@ -544,7 +545,7 @@ size_t ArchNetworkWinsock::readSocket(ArchSocket s, void *buf, size_t len)
|
||||
|
||||
size_t ArchNetworkWinsock::writeSocket(ArchSocket s, const void *buf, size_t len)
|
||||
{
|
||||
assert(s != NULL);
|
||||
assert(s != nullptr);
|
||||
|
||||
int n = send_winsock(s->m_socket, buf, (int)len, 0);
|
||||
if (n == SOCKET_ERROR) {
|
||||
@ -563,7 +564,7 @@ size_t ArchNetworkWinsock::writeSocket(ArchSocket s, const void *buf, size_t len
|
||||
|
||||
void ArchNetworkWinsock::throwErrorOnSocket(ArchSocket s)
|
||||
{
|
||||
assert(s != NULL);
|
||||
assert(s != nullptr);
|
||||
|
||||
// get the error from the socket layer
|
||||
int err = 0;
|
||||
@ -590,7 +591,7 @@ void ArchNetworkWinsock::setBlockingOnSocket(SOCKET s, bool blocking)
|
||||
|
||||
bool ArchNetworkWinsock::setNoDelayOnSocket(ArchSocket s, bool noDelay)
|
||||
{
|
||||
assert(s != NULL);
|
||||
assert(s != nullptr);
|
||||
|
||||
// get old state
|
||||
BOOL oflag;
|
||||
@ -611,7 +612,7 @@ bool ArchNetworkWinsock::setNoDelayOnSocket(ArchSocket s, bool noDelay)
|
||||
|
||||
bool ArchNetworkWinsock::setReuseAddrOnSocket(ArchSocket s, bool reuse)
|
||||
{
|
||||
assert(s != NULL);
|
||||
assert(s != nullptr);
|
||||
|
||||
// get old state
|
||||
BOOL oflag;
|
||||
@ -643,7 +644,7 @@ std::string ArchNetworkWinsock::getHostName()
|
||||
|
||||
ArchNetAddress ArchNetworkWinsock::newAnyAddr(EAddressFamily family)
|
||||
{
|
||||
ArchNetAddressImpl *addr = NULL;
|
||||
ArchNetAddressImpl *addr = nullptr;
|
||||
switch (family) {
|
||||
case kINET: {
|
||||
addr = ArchNetAddressImpl::alloc(sizeof(struct sockaddr_in));
|
||||
@ -671,7 +672,7 @@ ArchNetAddress ArchNetworkWinsock::newAnyAddr(EAddressFamily family)
|
||||
|
||||
ArchNetAddress ArchNetworkWinsock::copyAddr(ArchNetAddress addr)
|
||||
{
|
||||
assert(addr != NULL);
|
||||
assert(addr != nullptr);
|
||||
|
||||
ArchNetAddressImpl *copy = ArchNetAddressImpl::alloc(addr->m_len);
|
||||
memcpy(TYPED_ADDR(void, copy), TYPED_ADDR(void, addr), addr->m_len);
|
||||
@ -690,7 +691,7 @@ std::vector<ArchNetAddress> ArchNetworkWinsock::nameToAddr(const std::string &na
|
||||
int ret = -1;
|
||||
|
||||
ARCH->lockMutex(m_mutex);
|
||||
if ((ret = getaddrinfo(name.c_str(), NULL, &hints, &pResult)) != 0) {
|
||||
if ((ret = getaddrinfo(name.c_str(), nullptr, &hints, &pResult)) != 0) {
|
||||
ARCH->unlockMutex(m_mutex);
|
||||
throwNameError(ret);
|
||||
}
|
||||
@ -713,21 +714,21 @@ std::vector<ArchNetAddress> ArchNetworkWinsock::nameToAddr(const std::string &na
|
||||
|
||||
void ArchNetworkWinsock::closeAddr(ArchNetAddress addr)
|
||||
{
|
||||
assert(addr != NULL);
|
||||
assert(addr != nullptr);
|
||||
|
||||
free(addr);
|
||||
}
|
||||
|
||||
std::string ArchNetworkWinsock::addrToName(ArchNetAddress addr)
|
||||
{
|
||||
assert(addr != NULL);
|
||||
assert(addr != nullptr);
|
||||
|
||||
char host[1024];
|
||||
char service[20];
|
||||
int ret =
|
||||
getnameinfo(TYPED_ADDR(struct sockaddr, addr), addr->m_len, host, sizeof(host), service, sizeof(service), 0);
|
||||
|
||||
if (ret != NULL) {
|
||||
if (ret != 0) {
|
||||
throwNameError(ret);
|
||||
}
|
||||
|
||||
@ -738,7 +739,7 @@ std::string ArchNetworkWinsock::addrToName(ArchNetAddress addr)
|
||||
|
||||
std::string ArchNetworkWinsock::addrToString(ArchNetAddress addr)
|
||||
{
|
||||
assert(addr != NULL);
|
||||
assert(addr != nullptr);
|
||||
|
||||
switch (getAddrFamily(addr)) {
|
||||
case kINET: {
|
||||
@ -761,7 +762,7 @@ std::string ArchNetworkWinsock::addrToString(ArchNetAddress addr)
|
||||
|
||||
IArchNetwork::EAddressFamily ArchNetworkWinsock::getAddrFamily(ArchNetAddress addr)
|
||||
{
|
||||
assert(addr != NULL);
|
||||
assert(addr != nullptr);
|
||||
|
||||
switch (addr->m_addr.ss_family) {
|
||||
case AF_INET:
|
||||
@ -777,7 +778,7 @@ IArchNetwork::EAddressFamily ArchNetworkWinsock::getAddrFamily(ArchNetAddress ad
|
||||
|
||||
void ArchNetworkWinsock::setAddrPort(ArchNetAddress addr, int port)
|
||||
{
|
||||
assert(addr != NULL);
|
||||
assert(addr != nullptr);
|
||||
|
||||
switch (getAddrFamily(addr)) {
|
||||
case kINET: {
|
||||
@ -800,7 +801,7 @@ void ArchNetworkWinsock::setAddrPort(ArchNetAddress addr, int port)
|
||||
|
||||
int ArchNetworkWinsock::getAddrPort(ArchNetAddress addr)
|
||||
{
|
||||
assert(addr != NULL);
|
||||
assert(addr != nullptr);
|
||||
|
||||
switch (getAddrFamily(addr)) {
|
||||
case kINET: {
|
||||
@ -821,7 +822,7 @@ int ArchNetworkWinsock::getAddrPort(ArchNetAddress addr)
|
||||
|
||||
bool ArchNetworkWinsock::isAnyAddr(ArchNetAddress addr)
|
||||
{
|
||||
assert(addr != NULL);
|
||||
assert(addr != nullptr);
|
||||
|
||||
switch (getAddrFamily(addr)) {
|
||||
case kINET: {
|
||||
@ -851,12 +852,12 @@ void ArchNetworkWinsock::throwError(int err)
|
||||
{
|
||||
switch (err) {
|
||||
case WSAEACCES:
|
||||
throw XArchNetworkAccess(new XArchEvalWinsock(err));
|
||||
throw XArchNetworkAccess(winsockErrorToString(err));
|
||||
|
||||
case WSAEMFILE:
|
||||
case WSAENOBUFS:
|
||||
case WSAENETDOWN:
|
||||
throw XArchNetworkResource(new XArchEvalWinsock(err));
|
||||
throw XArchNetworkResource(winsockErrorToString(err));
|
||||
|
||||
case WSAEPROTOTYPE:
|
||||
case WSAEPROTONOSUPPORT:
|
||||
@ -870,50 +871,50 @@ void ArchNetworkWinsock::throwError(int err)
|
||||
case WSANOTINITIALISED:
|
||||
case WSAVERNOTSUPPORTED:
|
||||
case WSASYSNOTREADY:
|
||||
throw XArchNetworkSupport(new XArchEvalWinsock(err));
|
||||
throw XArchNetworkSupport(winsockErrorToString(err));
|
||||
|
||||
case WSAEADDRNOTAVAIL:
|
||||
throw XArchNetworkNoAddress(new XArchEvalWinsock(err));
|
||||
throw XArchNetworkNoAddress(winsockErrorToString(err));
|
||||
|
||||
case WSAEADDRINUSE:
|
||||
throw XArchNetworkAddressInUse(new XArchEvalWinsock(err));
|
||||
throw XArchNetworkAddressInUse(winsockErrorToString(err));
|
||||
|
||||
case WSAEHOSTUNREACH:
|
||||
case WSAENETUNREACH:
|
||||
throw XArchNetworkNoRoute(new XArchEvalWinsock(err));
|
||||
throw XArchNetworkNoRoute(winsockErrorToString(err));
|
||||
|
||||
case WSAENOTCONN:
|
||||
throw XArchNetworkNotConnected(new XArchEvalWinsock(err));
|
||||
throw XArchNetworkNotConnected(winsockErrorToString(err));
|
||||
|
||||
case WSAEDISCON:
|
||||
throw XArchNetworkShutdown(new XArchEvalWinsock(err));
|
||||
throw XArchNetworkShutdown(winsockErrorToString(err));
|
||||
|
||||
case WSAENETRESET:
|
||||
case WSAECONNABORTED:
|
||||
case WSAECONNRESET:
|
||||
throw XArchNetworkDisconnected(new XArchEvalWinsock(err));
|
||||
throw XArchNetworkDisconnected(winsockErrorToString(err));
|
||||
|
||||
case WSAECONNREFUSED:
|
||||
throw XArchNetworkConnectionRefused(new XArchEvalWinsock(err));
|
||||
throw XArchNetworkConnectionRefused(winsockErrorToString(err));
|
||||
|
||||
case WSAEHOSTDOWN:
|
||||
case WSAETIMEDOUT:
|
||||
throw XArchNetworkTimedOut(new XArchEvalWinsock(err));
|
||||
throw XArchNetworkTimedOut(winsockErrorToString(err));
|
||||
|
||||
case WSAHOST_NOT_FOUND:
|
||||
throw XArchNetworkNameUnknown(new XArchEvalWinsock(err));
|
||||
throw XArchNetworkNameUnknown(winsockErrorToString(err));
|
||||
|
||||
case WSANO_DATA:
|
||||
throw XArchNetworkNameNoAddress(new XArchEvalWinsock(err));
|
||||
throw XArchNetworkNameNoAddress(winsockErrorToString(err));
|
||||
|
||||
case WSANO_RECOVERY:
|
||||
throw XArchNetworkNameFailure(new XArchEvalWinsock(err));
|
||||
throw XArchNetworkNameFailure(winsockErrorToString(err));
|
||||
|
||||
case WSATRY_AGAIN:
|
||||
throw XArchNetworkNameUnavailable(new XArchEvalWinsock(err));
|
||||
throw XArchNetworkNameUnavailable(winsockErrorToString(err));
|
||||
|
||||
default:
|
||||
throw XArchNetwork(new XArchEvalWinsock(err));
|
||||
throw XArchNetwork(winsockErrorToString(err));
|
||||
}
|
||||
}
|
||||
|
||||
@ -921,18 +922,18 @@ void ArchNetworkWinsock::throwNameError(int err)
|
||||
{
|
||||
switch (err) {
|
||||
case WSAHOST_NOT_FOUND:
|
||||
throw XArchNetworkNameUnknown(new XArchEvalWinsock(err));
|
||||
throw XArchNetworkNameUnknown(winsockErrorToString(err));
|
||||
|
||||
case WSANO_DATA:
|
||||
throw XArchNetworkNameNoAddress(new XArchEvalWinsock(err));
|
||||
throw XArchNetworkNameNoAddress(winsockErrorToString(err));
|
||||
|
||||
case WSANO_RECOVERY:
|
||||
throw XArchNetworkNameFailure(new XArchEvalWinsock(err));
|
||||
throw XArchNetworkNameFailure(winsockErrorToString(err));
|
||||
|
||||
case WSATRY_AGAIN:
|
||||
throw XArchNetworkNameUnavailable(new XArchEvalWinsock(err));
|
||||
throw XArchNetworkNameUnavailable(winsockErrorToString(err));
|
||||
|
||||
default:
|
||||
throw XArchNetworkName(new XArchEvalWinsock(err));
|
||||
throw XArchNetworkName(winsockErrorToString(err));
|
||||
}
|
||||
}
|
||||
|
||||
@ -52,39 +52,39 @@ class ArchNetworkWinsock : public IArchNetwork
|
||||
{
|
||||
public:
|
||||
ArchNetworkWinsock();
|
||||
virtual ~ArchNetworkWinsock();
|
||||
~ArchNetworkWinsock() override;
|
||||
|
||||
virtual void init();
|
||||
void init() override;
|
||||
|
||||
// IArchNetwork overrides
|
||||
virtual ArchSocket newSocket(EAddressFamily, ESocketType);
|
||||
virtual ArchSocket copySocket(ArchSocket s);
|
||||
virtual void closeSocket(ArchSocket s);
|
||||
virtual void closeSocketForRead(ArchSocket s);
|
||||
virtual void closeSocketForWrite(ArchSocket s);
|
||||
virtual void bindSocket(ArchSocket s, ArchNetAddress addr);
|
||||
virtual void listenOnSocket(ArchSocket s);
|
||||
virtual ArchSocket acceptSocket(ArchSocket s, ArchNetAddress *addr);
|
||||
virtual bool connectSocket(ArchSocket s, ArchNetAddress name);
|
||||
virtual int pollSocket(PollEntry[], int num, double timeout);
|
||||
virtual void unblockPollSocket(ArchThread thread);
|
||||
virtual size_t readSocket(ArchSocket s, void *buf, size_t len);
|
||||
virtual size_t writeSocket(ArchSocket s, const void *buf, size_t len);
|
||||
virtual void throwErrorOnSocket(ArchSocket);
|
||||
virtual bool setNoDelayOnSocket(ArchSocket, bool noDelay);
|
||||
virtual bool setReuseAddrOnSocket(ArchSocket, bool reuse);
|
||||
virtual std::string getHostName();
|
||||
virtual ArchNetAddress newAnyAddr(EAddressFamily);
|
||||
virtual ArchNetAddress copyAddr(ArchNetAddress);
|
||||
virtual std::vector<ArchNetAddress> nameToAddr(const std::string &);
|
||||
virtual void closeAddr(ArchNetAddress);
|
||||
virtual std::string addrToName(ArchNetAddress);
|
||||
virtual std::string addrToString(ArchNetAddress);
|
||||
virtual EAddressFamily getAddrFamily(ArchNetAddress);
|
||||
virtual void setAddrPort(ArchNetAddress, int port);
|
||||
virtual int getAddrPort(ArchNetAddress);
|
||||
virtual bool isAnyAddr(ArchNetAddress);
|
||||
virtual bool isEqualAddr(ArchNetAddress, ArchNetAddress);
|
||||
ArchSocket newSocket(EAddressFamily, ESocketType) override;
|
||||
ArchSocket copySocket(ArchSocket s) override;
|
||||
void closeSocket(ArchSocket s) override;
|
||||
void closeSocketForRead(ArchSocket s) override;
|
||||
void closeSocketForWrite(ArchSocket s) override;
|
||||
void bindSocket(ArchSocket s, ArchNetAddress addr) override;
|
||||
void listenOnSocket(ArchSocket s) override;
|
||||
ArchSocket acceptSocket(ArchSocket s, ArchNetAddress *addr) override;
|
||||
bool connectSocket(ArchSocket s, ArchNetAddress name) override;
|
||||
int pollSocket(PollEntry[], int num, double timeout) override;
|
||||
void unblockPollSocket(ArchThread thread) override;
|
||||
size_t readSocket(ArchSocket s, void *buf, size_t len) override;
|
||||
size_t writeSocket(ArchSocket s, const void *buf, size_t len) override;
|
||||
void throwErrorOnSocket(ArchSocket) override;
|
||||
bool setNoDelayOnSocket(ArchSocket, bool noDelay) override;
|
||||
bool setReuseAddrOnSocket(ArchSocket, bool reuse) override;
|
||||
std::string getHostName() override;
|
||||
ArchNetAddress newAnyAddr(EAddressFamily) override;
|
||||
ArchNetAddress copyAddr(ArchNetAddress) override;
|
||||
std::vector<ArchNetAddress> nameToAddr(const std::string &) override;
|
||||
void closeAddr(ArchNetAddress) override;
|
||||
std::string addrToName(ArchNetAddress) override;
|
||||
std::string addrToString(ArchNetAddress) override;
|
||||
EAddressFamily getAddrFamily(ArchNetAddress) override;
|
||||
void setAddrPort(ArchNetAddress, int port) override;
|
||||
int getAddrPort(ArchNetAddress) override;
|
||||
bool isAnyAddr(ArchNetAddress) override;
|
||||
bool isEqualAddr(ArchNetAddress, ArchNetAddress) override;
|
||||
|
||||
private:
|
||||
void initModule(HMODULE);
|
||||
|
||||
@ -13,16 +13,6 @@
|
||||
// ArchSleepWindows
|
||||
//
|
||||
|
||||
ArchSleepWindows::ArchSleepWindows()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
ArchSleepWindows::~ArchSleepWindows()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
void ArchSleepWindows::sleep(double timeout)
|
||||
{
|
||||
ARCH->testCancelThread();
|
||||
@ -35,7 +25,7 @@ void ArchSleepWindows::sleep(double timeout)
|
||||
// this is windows so that's pretty certain; we'll get a
|
||||
// link error if we're not, though.
|
||||
ArchMultithreadWindows *mt = ArchMultithreadWindows::getInstance();
|
||||
if (mt != NULL) {
|
||||
if (mt != nullptr) {
|
||||
HANDLE cancelEvent = mt->getCancelEventForCurrentThread();
|
||||
WaitForSingleObject(cancelEvent, (DWORD)(1000.0 * timeout));
|
||||
if (timeout == 0.0) {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user