Compare commits
598 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 | |||
| bc96ddebdd | |||
| 80606ef040 | |||
| 836d9b9a2b | |||
| f2063f9e05 | |||
| a74d792b5b | |||
| 256ba2411b | |||
| 0a23e62093 | |||
| e38a8e6b15 | |||
| 6f022ff700 | |||
| 265c2c2a2c | |||
| 1594b8e760 | |||
| 029cb8fc0b | |||
| 8e236e7e5c | |||
| 38b2798bb7 | |||
| d580dfba57 | |||
| da4237f349 | |||
| a78d1acc71 | |||
| 24d5b26da2 | |||
| 9c81f1c045 | |||
| 899a49d09a | |||
| 3a4bf35e22 | |||
| 495331108b | |||
| a7ce936d68 | |||
| f6ccd2a25b | |||
| 5d310be807 | |||
| bd674f546b | |||
| cc821f750d | |||
| 2485e993a4 | |||
| b5d12b8aa5 |
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,7 +18,7 @@ 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_MINOR 22)
|
||||
set(DESKFLOW_VERSION_PATCH 0)
|
||||
set(DESKFLOW_VERSION_TWEAK 0)
|
||||
|
||||
@ -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!
|
||||
@ -1,61 +0,0 @@
|
||||
MICROSOFT SOFTWARE LICENSE TERMS
|
||||
|
||||
MICROSOFT VISUAL C++ 2015 - 2022 RUNTIME
|
||||
|
||||
These license terms are an agreement between Microsoft Corporation (or based on where you live, one of its affiliates) and you. They apply to the software named above. The terms also apply to any Microsoft services or updates for the software, except to the extent those have different terms.
|
||||
|
||||
IF YOU COMPLY WITH THESE LICENSE TERMS, YOU HAVE THE RIGHTS BELOW.
|
||||
|
||||
1. INSTALLATION AND USE RIGHTS.
|
||||
|
||||
You may install and use any number of copies of the software.
|
||||
|
||||
2. TERMS FOR SPECIFIC COMPONENTS.
|
||||
|
||||
a. Microsoft Platforms. The software may include components from Microsoft Windows; Microsoft Windows Server; Microsoft SQL Server; Microsoft Exchange; Microsoft Office; and Microsoft SharePoint. These components are governed by separate agreements and their own product support policies, as described in the Microsoft “Licenses” folder accompanying the software, except that, if license terms for those components are also included in the associated installation directory, those license terms control.
|
||||
|
||||
b. Third Party Components. The software may include third party components with separate legal notices or governed by other agreements, as may be described in the notices file(s) accompanying the software.
|
||||
|
||||
3. SCOPE OF LICENSE. The software is licensed, not sold. This agreement only gives you some rights to use the software. Microsoft reserves all other rights. Unless applicable law gives you more rights despite this limitation, you may use the software only as expressly permitted in this agreement. In doing so, you must comply with any technical limitations in the software that only allow you to use it in certain ways. You may not
|
||||
|
||||
· work around any technical limitations in the software;
|
||||
|
||||
· reverse engineer, decompile or disassemble the software, or otherwise attempt to derive the source code for the software except, and only to the extent required by third party licensing terms governing the use of certain open source components that may be included in the software;
|
||||
|
||||
· remove, minimize, block or modify any notices of Microsoft or its suppliers in the software;
|
||||
|
||||
· use the software in any way that is against the law;
|
||||
|
||||
· share, publish, rent or lease the software; or
|
||||
|
||||
· provide the software as a stand-alone offering or combined with any of your applications for others to use, or transfer the software or this agreement to any third party.
|
||||
|
||||
4. EXPORT RESTRICTIONS. You must comply with all domestic and international export laws and regulations that apply to the software, which include restrictions on destinations, end users, and end use. For further information on export restrictions, visit www.microsoft.com/exporting.
|
||||
|
||||
5. SUPPORT SERVICES. Because this software is “as is,” we may not provide support services for it.
|
||||
|
||||
6. ENTIRE AGREEMENT. This agreement, and the terms for supplements, updates, Internet-based services and support services that you use, are the entire agreement for the software and support services.
|
||||
|
||||
7. APPLICABLE LAW. If you acquired the software in the United States, Washington law applies to interpretation of and claims for breach of this agreement, and the laws of the state where you live apply to all other claims. If you acquired the software in any other country, its laws apply.
|
||||
|
||||
8. CONSUMER RIGHTS; REGIONAL VARIATIONS. This agreement describes certain legal rights. You may have other rights, including consumer rights, under the laws of your state or country. Separate and apart from your relationship with Microsoft, you may also have rights with respect to the party from which you acquired the software. This agreement does not change those other rights if the laws of your state or country do not permit it to do so. For example, if you acquired the software in one of the below regions, or mandatory country law applies, then the following provisions apply to you:
|
||||
|
||||
a. Australia. You have statutory guarantees under the Australian Consumer Law and nothing in this agreement is intended to affect those rights.
|
||||
|
||||
b. Canada. If you acquired this software in Canada, you may stop receiving updates by turning off the automatic update feature, disconnecting your device from the Internet (if and when you re-connect to the Internet, however, the software will resume checking for and installing updates), or uninstalling the software. The product documentation, if any, may also specify how to turn off updates for your specific device or software.
|
||||
|
||||
c. Germany and Austria.
|
||||
|
||||
(i) Warranty. The properly licensed software will perform substantially as described in any Microsoft materials that accompany the software. However, Microsoft gives no contractual guarantee in relation to the licensed software.
|
||||
|
||||
(ii) Limitation of Liability. In case of intentional conduct, gross negligence, claims based on the Product Liability Act, as well as, in case of death or personal or physical injury, Microsoft is liable according to the statutory law.
|
||||
|
||||
Subject to the foregoing clause (ii), Microsoft will only be liable for slight negligence if Microsoft is in breach of such material contractual obligations, the fulfillment of which facilitate the due performance of this agreement, the breach of which would endanger the purpose of this agreement and the compliance with which a party may constantly trust in (so-called "cardinal obligations"). In other cases of slight negligence, Microsoft will not be liable for slight negligence.
|
||||
|
||||
9. DISCLAIMER OF WARRANTY. THE SOFTWARE IS LICENSED “AS-IS.” YOU BEAR THE RISK OF USING IT. MICROSOFT GIVES NO EXPRESS WARRANTIES, GUARANTEES OR CONDITIONS. TO THE EXTENT PERMITTED UNDER YOUR LOCAL LAWS, MICROSOFT EXCLUDES THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
|
||||
|
||||
10. LIMITATION ON AND EXCLUSION OF DAMAGES. YOU CAN RECOVER FROM MICROSOFT AND ITS SUPPLIERS ONLY DIRECT DAMAGES UP TO U.S. $5.00. YOU CANNOT RECOVER ANY OTHER DAMAGES, INCLUDING CONSEQUENTIAL, LOST PROFITS, SPECIAL, INDIRECT OR INCIDENTAL DAMAGES.
|
||||
|
||||
This limitation applies to (a) anything related to the software, services, content (including code) on third party Internet sites, or third party applications; and (b) claims for breach of contract, breach of warranty, guarantee or condition, strict liability, negligence, or other tort to the extent permitted by applicable law.
|
||||
|
||||
It also applies even if Microsoft knew or should have known about the possibility of the damages. The above limitation or exclusion may not apply to you because your country may not allow the exclusion or limitation of incidental, consequential or other damages.
|
||||
90
README.md
90
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)
|
||||
|
||||
@ -64,6 +47,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
|
||||
> [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.
|
||||
|
||||
macOS 12 or higher is required.
|
||||
@ -97,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).
|
||||
@ -148,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
|
||||
@ -179,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">
|
||||
|
||||
24
REUSE.toml
24
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"
|
||||
@ -127,12 +121,6 @@ precedence = "override"
|
||||
SPDX-FileCopyrightText = "Deskflow Developers"
|
||||
SPDX-License-Identifier = "MIT"
|
||||
|
||||
[[annotations]]
|
||||
path = "deploy/windows/Microsoft_VC142_CRT_x64.msm"
|
||||
precedence = "override"
|
||||
SPDX-FileCopyrightText = "Microsoft"
|
||||
SPDX-License-Identifier = "LicenseRef-Microsoft-vc-redist"
|
||||
|
||||
[[annotations]]
|
||||
path = "src/apps/deskflow-client/deskflow-client.exe.manifest"
|
||||
precedence = "override"
|
||||
@ -151,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"
|
||||
@ -200,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"
|
||||
|
||||
@ -8,10 +8,9 @@ macro(configure_libs)
|
||||
if(UNIX)
|
||||
configure_unix_libs()
|
||||
elseif(WIN32)
|
||||
find_package(Python REQUIRED QUIET)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP /D _BIND_TO_CURRENT_VCLIBS_VERSION=1")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MD /O2 /Ob2")
|
||||
list(APPEND libs Wtsapi32 Userenv Wininet comsuppw Shlwapi)
|
||||
list(APPEND libs Wtsapi32 Userenv Wininet comsuppw Shlwapi version)
|
||||
add_definitions(
|
||||
/DWIN32
|
||||
/D_WINDOWS
|
||||
@ -21,6 +20,9 @@ macro(configure_libs)
|
||||
endif()
|
||||
|
||||
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 Xml)
|
||||
endif()
|
||||
|
||||
# Define the location of Qt deployment tool
|
||||
if(WIN32)
|
||||
@ -33,25 +35,18 @@ macro(configure_libs)
|
||||
find_program(DEPLOYQT macdeployqt)
|
||||
endif()
|
||||
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
set(CMAKE_AUTOUIC ON)
|
||||
set(CMAKE_AUTORCC ON)
|
||||
|
||||
message(STATUS "Qt version: ${Qt6_VERSION}")
|
||||
|
||||
# TODO SSL check can happen in lib/net when don't have to deploy it any longer on windows
|
||||
|
||||
# Apple has to use static libraries because "Use of the Apple-provided OpenSSL
|
||||
# libraries by apps is strongly discouraged."
|
||||
# https://developer.apple.com/library/archive/documentation/Security/Conceptual/cryptoservices/SecureNetworkCommunicationAPIs/SecureNetworkCommunicationAPIs.html
|
||||
if(APPLE)
|
||||
set(OPENSSL_USE_STATIC_LIBS TRUE)
|
||||
endif()
|
||||
|
||||
find_package(OpenSSL ${REQUIRED_OPENSSL_VERSION} REQUIRED COMPONENTS SSL Crypto)
|
||||
|
||||
option(ENABLE_COVERAGE "Enable test coverage" OFF)
|
||||
if(ENABLE_COVERAGE)
|
||||
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.
|
||||
@ -60,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}
|
||||
)
|
||||
@ -94,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)
|
||||
@ -163,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
|
||||
@ -205,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,7 +42,79 @@
|
||||
</branding>
|
||||
<content_rating type="oars-1.0" />
|
||||
<releases>
|
||||
<release version="1.20.0" date="2025-3-03" urgency="high">
|
||||
<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>
|
||||
<ul>
|
||||
<li>Fix: macOS menu bar icon invisible when menu bar is light</li>
|
||||
<li>Feature: Add Windows installer check for Visual C++ Redistributable</li>
|
||||
<li>Feature: Prevent Windows binaries running if MSVC runtime too old</li>
|
||||
</ul>
|
||||
</description>
|
||||
<url>https://github.com/deskflow/deskflow/releases/tag/v1.20.1</url>
|
||||
</release>
|
||||
<release version="1.20.0" date="2025-03-03" urgency="high">
|
||||
<description>
|
||||
<p>This stable release fixes a few security issues, additionally fixes several bugs and adds a few new features. For the full changelog see the release page.</p>
|
||||
<ul>
|
||||
@ -56,9 +128,9 @@
|
||||
<li>Win32: Fix clear settings</li>
|
||||
</ul>
|
||||
</description>
|
||||
<url>https://github.com/deskflow/deskflow/releases/tag/v1.20.0</url>
|
||||
<url>https://github.com/deskflow/deskflow/releases/tag/v1.20.0</url>
|
||||
</release>
|
||||
<release version="1.19.0" date="2025-1-31" urgency="high">
|
||||
<release version="1.19.0" date="2025-01-31" urgency="high">
|
||||
<description>
|
||||
<p>This stable release fixes several bugs and adds a few new features. For the full changelog see the release page.</p>
|
||||
<ul>
|
||||
@ -76,7 +148,7 @@
|
||||
<li>Lots of Internal Cleanup</li>
|
||||
</ul>
|
||||
</description>
|
||||
<url>https://github.com/deskflow/deskflow/releases/tag/v1.19.0</url>
|
||||
<url>https://github.com/deskflow/deskflow/releases/tag/v1.19.0</url>
|
||||
</release>
|
||||
<release version="1.18.0" date="2024-12-26" urgency="high">
|
||||
<description>
|
||||
@ -95,7 +167,7 @@
|
||||
<li>Update the windows clipboard format listener to monitor the clipboard</li>
|
||||
</ul>
|
||||
</description>
|
||||
<url>https://github.com/deskflow/deskflow/releases/tag/v1.18.0</url>
|
||||
<url>https://github.com/deskflow/deskflow/releases/tag/v1.18.0</url>
|
||||
</release>
|
||||
<release version="1.17.2" date="2024-11-20" urgency="medium">
|
||||
<description>
|
||||
@ -149,9 +221,9 @@
|
||||
<li>ci: build flatpaks</li>
|
||||
</ul>
|
||||
</description>
|
||||
<url>https://github.com/deskflow/deskflow/releases/tag/v1.17.2</url>
|
||||
<url>https://github.com/deskflow/deskflow/releases/tag/v1.17.2</url>
|
||||
</release>
|
||||
<release version="1.17.1" date="2024-11-7" urgency="high">
|
||||
<release version="1.17.1" date="2024-11-07" urgency="high">
|
||||
<description>
|
||||
<p>This stable release has a very long changelog some notable ones are.</p>
|
||||
<ul>
|
||||
@ -266,7 +338,7 @@
|
||||
<li>ci: adjust pacakge script to use the names we would like when in cpack</li>
|
||||
</ul>
|
||||
</description>
|
||||
<url>https://github.com/deskflow/deskflow/releases/tag/v1.17.1</url>
|
||||
<url>https://github.com/deskflow/deskflow/releases/tag/v1.17.1</url>
|
||||
</release>
|
||||
<release version="1.17.0" date="2024-10-02" urgency="low">
|
||||
<description>
|
||||
@ -316,7 +388,7 @@
|
||||
<li>Use sonarsource/sonarcloud-github-c-cpp</li>
|
||||
</ul>
|
||||
</description>
|
||||
<url>https://github.com/deskflow/deskflow/releases/tag/v1.17.0</url>
|
||||
<url>https://github.com/deskflow/deskflow/releases/tag/v1.17.0</url>
|
||||
</release>
|
||||
</releases>
|
||||
</component>
|
||||
|
||||
@ -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")
|
||||
|
||||
Binary file not shown.
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)
|
||||
@ -46,7 +51,6 @@ list(APPEND CPACK_WIX_EXTENSIONS "WixToolset.Util.wixext" "WixToolset.Firewall.w
|
||||
list(APPEND CPACK_WIX_CUSTOM_XMLNS "util=http://wixtoolset.org/schemas/v4/wxs/util" "firewall=http://wixtoolset.org/schemas/v4/wxs/firewall")
|
||||
|
||||
# The patch has to know the full path of our msm file
|
||||
set(CPACK_WIX_MSM_FILE "${MY_DIR}/Microsoft_VC142_CRT_x64.msm")
|
||||
configure_file(
|
||||
${MY_DIR}/wix-patch.xml.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/wix-patch.xml @ONLY
|
||||
@ -54,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
|
||||
@ -1,26 +1,78 @@
|
||||
<CPackWiXPatch>
|
||||
<CPackWiXFragment Id="CM_CP_deskflow_daemon.exe">
|
||||
<ServiceInstall Description="Controls the Deskflow foreground processes." DisplayName="Deskflow" ErrorControl="normal" Id="ServiceInstall" Name="Deskflow" Start="auto" Type="ownProcess">
|
||||
<util:ServiceConfig FirstFailureActionType="restart" ResetPeriodInDays="1" RestartServiceDelayInSeconds="1" SecondFailureActionType="restart" ThirdFailureActionType="restart"/>
|
||||
<ServiceInstall
|
||||
Id="ServiceInstall"
|
||||
Name="Deskflow"
|
||||
DisplayName="Deskflow"
|
||||
Description="Runs the Core process on secure desktops (UAC prompts, login screen, etc)."
|
||||
ErrorControl="normal"
|
||||
Start="auto"
|
||||
Type="ownProcess">
|
||||
<util:ServiceConfig
|
||||
ResetPeriodInDays="1"
|
||||
RestartServiceDelayInSeconds="1"
|
||||
FirstFailureActionType="restart"
|
||||
SecondFailureActionType="restart"
|
||||
ThirdFailureActionType="none"
|
||||
/>
|
||||
</ServiceInstall>
|
||||
<ServiceControl Id="ServiceControl" Name="Deskflow" Remove="uninstall" Start="install" Stop="both"/>
|
||||
</CPackWiXFragment>
|
||||
|
||||
<CPackWiXFragment Id="CM_CP_deskflow_server.exe">
|
||||
<firewall:FirewallException Id="ServerFirewallException" Name="Deskflow Server" Program="[INSTALL_ROOT]deskflow-server.exe" Scope="any"/>
|
||||
</CPackWiXFragment>
|
||||
|
||||
<CPackWiXFragment Id="CM_CP_deskflow_client.exe">
|
||||
<firewall:FirewallException Id="ClientFirewallException" Name="Deskflow Client" Program="[INSTALL_ROOT]deskflow-client.exe" Scope="any"/>
|
||||
</CPackWiXFragment>
|
||||
|
||||
<CPackWiXFragment Id="#PRODUCT">
|
||||
<StandardDirectory Id="TARGETDIR">
|
||||
<Merge Id="VCRedist" SourceFile="@CPACK_WIX_MSM_FILE@" DiskId="1" Language="0"/>
|
||||
</StandardDirectory >
|
||||
<Feature Id="VCRedist" Title="Visual C++ Runtime" AllowAbsent="no" AllowAdvertise="yes" Display="hidden" InstallDefault="local" TypicalDefault="install">
|
||||
<MergeRef Id="VCRedist" Primary="yes"/>
|
||||
</Feature>
|
||||
<CustomAction Id="Run_Deskflow" ExeCommand="Deskflow" FileRef="CM_FP_deskflow.exe" Return="asyncNoWait"/>
|
||||
<Property Id="VC_REDIST_INSTALLED">
|
||||
<RegistrySearch
|
||||
Id="FindVCRedist"
|
||||
Root="HKLM"
|
||||
Key="SOFTWARE\Microsoft\VisualStudio\@REQUIRED_MSVC_RUNTIME_MAJOR@.0\VC\Runtimes\@BUILD_ARCHITECTURE@"
|
||||
Name="Installed"
|
||||
Type="raw" />
|
||||
</Property>
|
||||
|
||||
<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="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="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,13 +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,14 +8,12 @@ if(WIN32)
|
||||
set(target ${CMAKE_PROJECT_NAME}-daemon)
|
||||
|
||||
# Generate rc file
|
||||
set(EXE_DESCRIPTION "Windows service to run ${CMAKE_PROJECT_NAME} in secure desktops (UAC prompts, login screen, etc)")
|
||||
set(EXE_DESCRIPTION "${CMAKE_PROJECT_PROPER_NAME} Daemon for handling secure desktops (UAC prompts, login screen, etc)")
|
||||
set(EXE_ICON "IDI_DESKFLOW ICON DISCARDABLE \"${CMAKE_SOURCE_DIR}/src/apps/res/deskflow.ico\"")
|
||||
configure_file(${CMAKE_SOURCE_DIR}/src/apps/res/windows.rc.in ${target}.rc)
|
||||
|
||||
add_executable(${target} WIN32 ${target}.cpp ${CMAKE_CURRENT_BINARY_DIR}/${target}.rc)
|
||||
|
||||
find_package(Qt6 COMPONENTS Core Network)
|
||||
|
||||
target_link_libraries(
|
||||
${target}
|
||||
arch
|
||||
@ -25,6 +23,7 @@ if(WIN32)
|
||||
net
|
||||
platform
|
||||
app
|
||||
common
|
||||
${libs}
|
||||
Qt6::Core)
|
||||
|
||||
|
||||
@ -5,15 +5,12 @@
|
||||
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
|
||||
*/
|
||||
|
||||
#include "arch/Arch.h"
|
||||
#include "base/Log.h"
|
||||
#include "common/constants.h"
|
||||
#include "deskflow/DaemonApp.h"
|
||||
#include "deskflow/ipc/DaemonIpcServer.h"
|
||||
|
||||
#include "arch/Arch.h"
|
||||
#include "base/EventQueue.h"
|
||||
#include "base/Log.h"
|
||||
#include "common/Settings.h"
|
||||
#include "deskflow/DaemonApp.h"
|
||||
#include "deskflow/ipc/DaemonIpcServer.h"
|
||||
|
||||
#if SYSAPI_WIN32
|
||||
|
||||
@ -24,16 +21,19 @@
|
||||
|
||||
#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)
|
||||
{
|
||||
#if SYSAPI_WIN32
|
||||
ArchMiscWindows::guardRuntimeVersion();
|
||||
|
||||
// Save window instance for later use, e.g. `GetModuleFileName` which is used when installing the daemon.
|
||||
ArchMiscWindows::setInstanceWin32(GetModuleHandle(nullptr));
|
||||
#endif
|
||||
@ -44,79 +44,86 @@ int main(int argc, char **argv)
|
||||
Log log;
|
||||
EventQueue events;
|
||||
|
||||
LOG((CLOG_PRINT "%s daemon (v%s)", kAppName, kVersion));
|
||||
// Daemon deliberately does not have a parent, as it will be moved to a new thread.
|
||||
DaemonApp daemon(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;
|
||||
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();
|
||||
}
|
||||
|
||||
switch (initResult) {
|
||||
using enum DaemonApp::InitResult;
|
||||
// Depends on whether foreground option was set.
|
||||
daemon.initLogging();
|
||||
|
||||
case StartDaemon: {
|
||||
LOG_INFO("starting daemon");
|
||||
QCoreApplication app(argc, argv);
|
||||
// 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 v%s", QCoreApplication::applicationName().toStdString().c_str(), kDisplayVersion);
|
||||
|
||||
// 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());
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -8,10 +8,6 @@ else()
|
||||
set(target deskflow)
|
||||
endif()
|
||||
|
||||
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
set(CMAKE_AUTORCC ON)
|
||||
set(CMAKE_AUTOUIC ON)
|
||||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||
|
||||
if(WIN32)
|
||||
@ -48,65 +44,13 @@ 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(
|
||||
${target}
|
||||
gui
|
||||
common
|
||||
Qt6::Core
|
||||
Qt6::Widgets
|
||||
Qt6::Network)
|
||||
@ -140,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,13 +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;
|
||||
@ -28,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,29 +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 ${CMAKE_DL_LIBS} ${libs})
|
||||
if(NOT APPLE)
|
||||
find_package(Qt6 ${REQUIRED_QT_VERSION} REQUIRED COMPONENTS DBus)
|
||||
target_link_libraries(arch Qt6::DBus)
|
||||
endif()
|
||||
target_link_libraries(arch ${libs})
|
||||
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;
|
||||
@ -135,7 +137,7 @@ private:
|
||||
};
|
||||
|
||||
#define DEFAULT_DAEMON_NAME _T(kAppName)
|
||||
#define DEFAULT_DAEMON_INFO _T("Manages the Deskflow foreground processes.")
|
||||
#define DEFAULT_DAEMON_INFO _T("Runs the Core process on secure desktops (UAC prompts, login screen, etc).")
|
||||
|
||||
#define LEGACY_SERVER_DAEMON_NAME _T("Deskflow Server")
|
||||
#define LEGACY_CLIENT_DAEMON_NAME _T("Deskflow Client")
|
||||
|
||||
@ -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,69 +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 "common/constants.h"
|
||||
#include "base/String.h"
|
||||
|
||||
#include <Wtsapi32.h>
|
||||
#pragma warning(disable : 4099)
|
||||
#include <Userenv.h>
|
||||
#pragma warning(default : 4099)
|
||||
#include <Psapi.h>
|
||||
|
||||
// parent process name for services in Vista
|
||||
#define SERVICE_LAUNCHER "services.exe"
|
||||
#include <array>
|
||||
#include <filesystem>
|
||||
|
||||
#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;
|
||||
// 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())
|
||||
|
||||
//
|
||||
// Free functions
|
||||
//
|
||||
|
||||
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)
|
||||
@ -108,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
|
||||
@ -118,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
|
||||
@ -132,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);
|
||||
}
|
||||
@ -141,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;
|
||||
}
|
||||
@ -205,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;
|
||||
}
|
||||
@ -215,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();
|
||||
}
|
||||
@ -274,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)
|
||||
{
|
||||
@ -292,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;
|
||||
@ -327,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;
|
||||
}
|
||||
@ -365,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;
|
||||
}
|
||||
}
|
||||
@ -389,7 +326,7 @@ bool ArchMiscWindows::wasLaunchedAsService()
|
||||
return false;
|
||||
}
|
||||
|
||||
return (name == SERVICE_LAUNCHER);
|
||||
return (name == "services.exe");
|
||||
}
|
||||
|
||||
bool ArchMiscWindows::getParentProcessName(std::string &name)
|
||||
@ -458,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;
|
||||
}
|
||||
|
||||
@ -473,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;
|
||||
@ -483,3 +420,133 @@ std::string ArchMiscWindows::getActiveDesktopName()
|
||||
CloseDesktop(desk);
|
||||
return name;
|
||||
}
|
||||
|
||||
HMODULE ArchMiscWindows::findLoadedModule(std::array<const char *, 2> moduleNames)
|
||||
{
|
||||
std::array<HMODULE, 1024> hModules;
|
||||
DWORD cbNeeded;
|
||||
|
||||
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 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 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 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 query file version info for MSVC runtime.");
|
||||
abort();
|
||||
}
|
||||
|
||||
const auto currentMajor = HIWORD(fileInfo->dwFileVersionMS);
|
||||
const auto currentMinor = LOWORD(fileInfo->dwFileVersionMS);
|
||||
const auto currentBuild = HIWORD(fileInfo->dwFileVersionLS);
|
||||
|
||||
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, 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);
|
||||
|
||||
@ -157,13 +112,24 @@ public:
|
||||
//! Returns true if we got the parent process name.
|
||||
static bool getParentProcessName(std::string &name);
|
||||
|
||||
//! 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);
|
||||
@ -177,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);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user