200 Commits

Author SHA1 Message Date
a80cea3ca7 Release 1.17.1
Some checks are pending
CI / pr-comment-flags (push) Blocked by required conditions
CI / ci-passed (push) Blocked by required conditions
CI / test-results (push) Blocked by required conditions
CI / lint-clang (push) Waiting to run
CI / analyse-valgrind (push) Blocked by required conditions
CI / analyse-sonarcloud (push) Blocked by required conditions
CI / macos-14-arm64 (push) Blocked by required conditions
CI / macos-13-x64 (push) Blocked by required conditions
CI / archlinux-amd64 (push) Blocked by required conditions
CI / debian-13-amd64 (push) Blocked by required conditions
CI / fedora-40-amd64 (push) Blocked by required conditions
CI / fedora-41-amd64 (push) Blocked by required conditions
CI / opensuse-amd64 (push) Blocked by required conditions
CI / windows-2022-x64 (push) Blocked by required conditions
CI / unix-freebsd (push) Blocked by required conditions
CI / release (push) Blocked by required conditions
CI / winget-publish (push) Blocked by required conditions
2024-11-08 07:05:58 -05:00
9929b09088 refactor: mv src/gui/src/ScreenSetupView => src/gui/src/widgets/ScreenSetupView 2024-11-08 07:05:58 -05:00
226c835ee9 refactor: mv src/gui/src/KeySequenceWidget => src/gui/src/widgets/KeySwquenceWidget 2024-11-08 07:05:58 -05:00
fbda5b4053 refactor: mv src/gui/src/TrashScreenWidget => src/gui/src/widgets/TrashScreenWidget 2024-11-08 07:05:57 -05:00
f31cb26e0b refactor: mv src/lib/gui/widgets => src/gui/src/widgets 2024-11-08 07:05:57 -05:00
1bbc581037 refactor: mv src/gui/src/ServerConfigDialog => src/gui/src/dialogs/ServerConfigDialog 2024-11-08 07:05:57 -05:00
ce45d74806 refactor: mv src/gui/src/ScreenSettingsDialog => src/gui/src/dialogs/ScreenSettingsDialog 2024-11-08 07:05:57 -05:00
916f1e6144 refactor: mv src/gui/src/HotkeyDialog => src/gui/src/dialogs/HotkeyDialog 2024-11-08 07:05:57 -05:00
4f4261a237 refactor: mv src/gui/src/AddClientDialog => src/gui/src/dialog/AddClientDialog 2024-11-08 07:05:57 -05:00
e06741e62e refactor: mv src/gui/src/ActionDialog => src/gui/src/dialogs/ActionDialog 2024-11-08 07:05:57 -05:00
585a895b4a refactor: Settings Dialog rm ui as base class 2024-11-08 07:05:56 -05:00
dc5c2b9422 refactor: mv src/lib/gui/dialogs/SettingsDialog => src/gui/src/dialogs/SettingsDialpg 2024-11-08 07:05:54 -05:00
3822336db2 ci: release on master or tags/v 2024-11-08 10:02:21 +00:00
5ca9afc3f7 ci: get-version strip refs/tags/v from DESKFLOW_PACKAGE_VERSION" 2024-11-08 10:02:21 +00:00
8273c0e70b chore: Replace screen leave/enter asserts with warnings 2024-11-06 20:55:59 -05:00
fa9b2d91d5 ci: release a file with packages sums 'sums.txt' with releases 2024-11-06 15:41:37 -05:00
170b4251f3 build: align window mac names with community norms 2024-11-06 12:45:28 -05:00
ddf6450486 build: use PACKAGE_VERSION_LABEL to set generated package's name
If unset use CPACK_PACKAGE_VERSION when set only replaces the version in the package's filename
2024-11-06 11:49:31 -05:00
4a769e6a7f ci: get-version action new DESKFLOW_PACKAGE_VERSION returns "continuous" when not a v* tag otherwise the tag
DESKFLOW_VERSION is the version described by git
2024-11-06 11:32:50 -05:00
07fb3a9a7a chore: add homebrew tap info to readme 2024-11-06 14:51:46 +00:00
155e4d6b32 refactor: ui less aboutDialog 2024-11-06 14:50:39 +00:00
f87b4bc0c2 refactor: mv AboutDialog to gui/src/dialogs/ 2024-11-06 14:50:39 +00:00
f66a0219f6 fix: isDarkMode Check
while newer Qt does provide a method to check if dark mode
  Its not always correct the old method is
  Anytime the text is lighter then the window its dark mode.
2024-11-06 14:50:39 +00:00
3a53149a48 docs: contributors on readme 2024-11-06 14:11:15 +00:00
45f328cd80 fix: crash on --help arg 2024-11-05 13:26:00 -05:00
1e3d332002 chore: add project version for windows rc 2024-11-05 13:17:08 -05:00
3359a2a9d9 build: add deskflow devs to binary copyright 2024-11-05 13:17:08 -05:00
e369af9d74 chore: remove scripts/lib/github.py file 2024-11-05 14:33:23 +00:00
afab39e7f8 chore: remove unused scripts/tests.py 2024-11-05 14:33:23 +00:00
e33405bef8 chore: remove unused package parts, do not allow package via python on linux 2024-11-05 14:33:23 +00:00
9875bc6613 chore: Remove unused install deps scripts and related parts 2024-11-05 14:33:23 +00:00
16a1ba8f45 ci: adjust pacakge script to use the names we would like when in cpack 2024-11-01 12:02:00 +00:00
37889e5659 ci: git-version-action: Always report described version 2024-11-01 11:52:45 +00:00
1835a2cab6 ci: use pre-release for continuous to stop it from grabbing latest tag also 2024-11-01 10:16:24 +00:00
8c314ad82c ci: Use GITHUB_TOKEN in place of PAT 2024-10-31 12:39:39 +00:00
da64ca577c docs: Improve error messages around Doxygen 2024-10-31 12:38:44 +00:00
232e8fafee doc: correct target for documents 2024-10-31 11:57:16 +00:00
fb686ede21 refactor: remove desktop legacy 2024-10-30 20:04:55 +00:00
ce784ab383 refactor: CoreTool use arch classes directly 2024-10-30 20:04:55 +00:00
946a2b778e refactor: rm unused coreTool include in tlscert.h 2024-10-30 20:04:55 +00:00
45bde73810 chore: settingsDialog rm unused CoreTool include 2024-10-30 17:41:17 +00:00
8b62f5b083 docs: cmake to generate doxygen 2024-10-30 16:50:12 +00:00
f74cce32a4 doc: New document mainpage 2024-10-30 16:50:12 +00:00
170d6f4889 docs: Add new doc/configuration.md 2024-10-30 16:50:12 +00:00
48a8111fc5 docs: Remove BUILD.md 2024-10-30 16:50:12 +00:00
656601f2ba docs: rm CONTRIBUTING.md 2024-10-30 16:50:12 +00:00
1880a157b6 ci: added updated winget package submission 2024-10-30 13:28:38 +00:00
3cb1980af3 docs: Fixed sponsor link 2024-10-29 14:27:39 +00:00
c24444c77e docs: Update README.md to restore sponsor link 2024-10-29 12:56:45 +00:00
675e10d7b1 docs: readme add mac os xattr note
add a tip for mac users to run xattr -c on the app post download
2024-10-28 12:22:41 +00:00
915760b899 chore: add link to wayland discussion
added an additional link to the linux wayland question pointing to the discussion
2024-10-28 11:56:08 +00:00
077412f7ec build: update package names for linux to be more unified
We are not making offical packages
    we should not set a rpm or debian revision
    we should do not have to use 'correct' names for deb / rpm
2024-10-25 20:29:05 +01:00
968037b85b build(cmd/deskflow-core):Explicit Sources 2024-10-24 15:11:03 -04:00
08d3347740 build(cmd/deskflow-legacy): Explicit Sources 2024-10-24 15:11:03 -04:00
ad6551262c build(cmd/deskflows): Explicit Sources 2024-10-24 15:11:03 -04:00
337d236f54 build(cmd/deskflowd): Explicit Sources 2024-10-24 15:11:03 -04:00
04d6895990 build(cmd/deskflowc): Explicit Sources 2024-10-24 15:11:03 -04:00
1b13c843aa build(lib/server): Explict Sources 2024-10-24 15:11:03 -04:00
9e2880f714 build(lib/platform): Explicit Sources 2024-10-24 15:11:03 -04:00
e8010eea60 build(lib/net): Explicit sources 2024-10-24 15:11:03 -04:00
75c0b53113 build(lib/mt): Explicit Sources 2024-10-24 15:11:03 -04:00
bf96a641bf build(lib/ipc): Explicit Sources 2024-10-24 15:11:03 -04:00
7db781b9bf build(lib/io): Explicit Sources 2024-10-24 15:11:03 -04:00
8bfe0c18bc build(lib/app): Explicit Sources 2024-10-24 15:11:03 -04:00
10f7b05a73 build(lib/client): Explicit Sources 2024-10-24 15:11:03 -04:00
ba97d63403 build(lib/base): Explicit Sources 2024-10-24 15:11:03 -04:00
da4b85b3fb build(lib/arch): Explicit Sources 2024-10-24 15:11:03 -04:00
5657152c58 chore(gui): Add _what's this_ for Windows service setting 2024-10-24 14:29:13 +01:00
9b4635b6d2 docs: Remote build containers badge
The build containers badge now points at a nonexistent workflow.
2024-10-23 15:24:01 -04:00
1aa6e8c6bb ci: add fedora-41 2024-10-23 14:13:37 +01:00
6846a97eec ci: Drop Docker container builds (not enough time saved)
Add user 'build' for arch to make a package
2024-10-23 14:13:37 +01:00
f26581f20a build: remove python dependency for non windows 2024-10-23 14:13:37 +01:00
01565ba9a9 ci: make sure git is installed before calling fancy-checkout
When we want to use the base runners they do not have git
   Install devscripts for debian images that will make packages
2024-10-23 14:13:37 +01:00
32b84f0a4b docs: Remove confusing reference in readme 2024-10-23 08:30:36 -04:00
d5a8dd7927 ci: remove unused libportal check from Librarires.cmake 2024-10-23 13:15:03 +01:00
dfbd612e2f doc: clean up readme 2024-10-22 20:13:17 +01:00
a406b51f96 ci: one matrix to run them all 2024-10-22 12:29:17 -04:00
b2532c81b9 ci: Add install-dependencies action 2024-10-22 12:29:17 -04:00
a362174e73 ci: only do release job when run on master 2024-10-22 09:42:32 -04:00
7b7ff81a9f build: Require libei and libportal from the system on linux
Removing remaining meson parts
2024-10-22 09:42:32 -04:00
2136af68b5 build(win32): resolve #7763 working windows installer
use correct QT_PATH
  Force install of depends
2024-10-22 10:53:51 +01:00
df91d845f7 build(win32): Link wintoast correctly 2024-10-22 10:53:51 +01:00
f967b9ed46 ci: use fancy checkout action 2024-10-21 15:24:06 -04:00
5d183c98e9 ci: Bump containers for analyze workflows 2024-10-21 14:15:05 -04:00
f3657edc80 refactor: use Q_EMIT 2024-10-21 14:30:02 +01:00
2a8a43a689 refactor: remove unused strings 2024-10-21 14:30:02 +01:00
498e3aa015 refactor: use static regularexpressions and matches 2024-10-21 14:30:02 +01:00
58323f515f refactor: use multi arg were possible 2024-10-21 14:30:02 +01:00
560345cf4f refactor: add context object for lambdas 2024-10-21 14:30:02 +01:00
90d27a174d refactor: do not include full modules in qt files 2024-10-21 14:30:02 +01:00
8b54b84880 refactor: use const for ranged loops 2024-10-21 14:30:02 +01:00
45050d3d36 refactor: use modern range for loops in place of old foreach macro 2024-10-21 14:30:02 +01:00
f0a946a0f1 refactor(SettingsWizard): Ui Less 2024-10-20 21:55:44 +01:00
db6b6b9386 refactor(SetupWizard): Foward declare appconfig 2024-10-20 21:55:44 +01:00
b10eb3baa8 refactor(SetupWizard): Do not use auto connect name for slot 2024-10-20 21:55:44 +01:00
9ea143c1df ci: unify cmake config command into a base env.CMAKE_CONFIGURE 2024-10-20 21:46:36 +01:00
a6b5879df3 ci: new mac os ci 2024-10-20 21:46:36 +01:00
1b904e7c02 ci: Normalize CI step names, descriptions, etc
Also:
- Surfaced the comment about the Kitware repo so it's more visible
- Remove the hard-coded CMake version in comment which is likely to get out of sync and confuse someone
2024-10-20 02:01:58 +01:00
f7ca548ee2 build: remove stale meson parts for wintoast 2024-10-19 20:53:10 -04:00
7c74b90620 fix scan alert #559 2024-10-19 19:49:21 -04:00
46915bff94 fix:#7760 use a proper fedora package name 2024-10-19 19:34:37 -04:00
949e1c0d71 build: Use Fetch Content for Gtest
Use Fetch Content to get gtest and gmock
2024-10-19 19:17:19 -04:00
b1fa9eadd9 build: arch package requires tomlplusplus and cli11 2024-10-19 19:00:21 -04:00
a786cdf972 chore: Set default server protocol to "Barrier" (determined by community vote)
Vote: https://github.com/deskflow/deskflow/discussions/7742
2024-10-19 23:46:42 +01:00
a5cd0fab9e feat: Option to change server protocol in GUI 2024-10-19 23:46:42 +01:00
512faeea28 test: Modularize hello back logic and add tests 2024-10-19 23:46:42 +01:00
47366f1272 feat: Dynamic client Barrier/Synergy hello back response to server 2024-10-19 23:46:42 +01:00
199f682e27 refactor: setupwizard ui is not longer the base of the class 2024-10-19 23:18:26 +01:00
afff2eb6ac refactor: serverconfigdialog ui is no longer base for the class 2024-10-19 23:18:26 +01:00
9167bf04f6 refactor: hotkeydialog ui no longer base of the class 2024-10-19 23:18:26 +01:00
0298a132c1 refactor: addclientdialog ui no longer base for the class 2024-10-19 23:18:26 +01:00
7b3d8c3dc3 refactor: actiondialog to not have ui as base of the class 2024-10-19 23:18:26 +01:00
06aa41e8f5 refactor: mainwindow ui not the base of the class 2024-10-19 23:18:26 +01:00
bf4a762124 build: use vcpkg for all depends, vcpkg action on ci to cache 2024-10-19 03:07:13 -04:00
7199e5f170 docs: Checkbox for continuous build on bug template 2024-10-18 19:09:07 -04:00
3d2883ad02 fix: remove server config dialog custom show event
Fixes Crash with Qt 6.8
2024-10-18 18:19:16 -04:00
6395630964 ci: Make integtests optional on FreeBSD and reduce CMake arg dupe
- Integration tests are flakey by nature, make them optional.
- This also includes a mini refactor of `ci.yml` to reduce some duplication.
2024-10-18 21:11:56 +01:00
a32463586c ci: Catch std::exception on toml::parse_file 2024-10-18 21:01:39 +01:00
9c9feba565 build: use File to dl toml++ if not on system 2024-10-18 15:02:34 -04:00
37fcec2554 build: arch package won't install /bin 2024-10-18 14:50:28 -04:00
246f5d59ab ci: remove unused cache step 2024-10-18 13:57:11 -04:00
710c1dd353 build: get CLI11 via file download if not on system 2024-10-18 13:34:10 -04:00
add8d5370a ci: Remove CMake presets 2024-10-18 18:23:26 +01:00
33b14ccc5c ci: cache vcpkg
Fixes:7712
2024-10-18 17:29:54 +01:00
ba5eaa4c90 build: Require cmake 3.24
Fixes:#7739
2024-10-18 15:22:35 +01:00
4ce81b59fb ci: Use cmake instead of make directly for Arch package 2024-10-18 12:19:37 +01:00
71e74735c0 build: update required ssl to 3.0+ 2024-10-18 06:49:02 +01:00
99251ad867 chore: Update feature request template
For a feature request we only want to know about the proposed feature
2024-10-17 21:39:48 +01:00
9b9ecb0d05 chore: Adjust Clang-format linter rules
120 Column Lines
 Block Indent for Bracket Align
 Custom Line Break Rules
 No Single Line Functions
2024-10-17 21:38:29 +01:00
3f2bb2531a fix: Let users select version number and build in About Dialog
Fixes: #7722
2024-10-17 19:51:00 +01:00
01d67e4614 chore: resolve cmake cap nits
Fixes: #7727
2024-10-17 13:37:50 +01:00
219958898e chore: Replace assert with warning for screen boundary issue 2024-10-17 11:17:05 +01:00
ae3bcfc809 build: Fixed deskflow-server binary name for VS Code users 2024-10-17 11:16:40 +01:00
dc9a5c0f12 build: Add gtest-args for VS Code users 2024-10-17 11:16:40 +01:00
1dc449fe0a fix: Use OPENSSL_EXE_DIR instead of OPENSSL_ROOT_DIR on Windows 2024-10-16 20:17:53 -04:00
52f616a15d ci: vcpkg cache working 2024-10-16 20:58:42 +01:00
da6b3942ae build: Linux packages with proper names 2024-10-16 16:51:24 +01:00
9a5c1a3212 chore: Remove Wayland experimental pop 2024-10-16 14:00:10 +01:00
8424ffa438 ci: Ignore .editorconfig in workflows 2024-10-15 23:08:28 +01:00
e2a0a97705 docs: Add .editorconfig file 2024-10-15 23:08:28 +01:00
78d086369b ci: Always run PR comments job 2024-10-15 22:49:35 +01:00
5f78d175c9 ci: Ignore paths for CodeQL Analysis 2024-10-15 22:19:02 +01:00
2b930a7b03 ci: Remove cmake-format linter 2024-10-15 22:03:15 +01:00
28c8aae9af ci: More consistent code style in ci.yml 2024-10-15 19:14:06 +01:00
3cc43bf1ce docs: Add other build type to bug report template 2024-10-15 18:44:34 +01:00
c78dccca71 Force LF in gitattributes 2024-10-15 18:02:20 +01:00
0a6f79fb31 build: Arch package needs pubixml 2024-10-15 17:16:29 +01:00
5925d42dbd build: allow PKGBUILD to build for more then just x86 2024-10-15 17:16:29 +01:00
6af331bd93 ci: clearer and cleaner steps 2024-10-15 14:17:33 +01:00
87b4e3b7fe fix: Check for errors before reading version string 2024-10-15 07:57:53 -04:00
23c4cadf17 build: set project description 2024-10-15 09:27:00 +01:00
6dcfcd50a2 ci: Add src/gui to coverage exclusions 2024-10-15 07:23:38 +01:00
f70528d082 build: Clean up warning for new QCheckBox signals With 6.7+ 2024-10-15 07:23:38 +01:00
f2f75ae7b9 ci: Fixed error count logic for test summary 2024-10-14 18:06:36 +01:00
572cc80577 ci: Restore pull_request trigger for codeql-analysis.yml 2024-10-14 18:00:17 +01:00
636e3eab96 feat: Respect XDG_CONFIG_HOME in server/client 2024-10-14 17:43:30 +01:00
9c4f6e6d0b chore: Change TLS dir to same as Qt config 2024-10-14 17:43:30 +01:00
3525b8a686 docs: Fixed minor typos in the bug report template 2024-10-14 17:06:24 +01:00
9b7cd1e250 docs: Add leading edge philosophy to README.md
I think it's important to help people understand the difference between Deskflow and Input Leap. e.g. We don't support Qt5, but IL seem to want to support Qt5.
2024-10-14 16:52:21 +01:00
26926a4a6a ci: run on tags v* and not on cron or dispatch 2024-10-14 09:22:28 -04:00
3991fc0d25 ci: use git version for packages 2024-10-14 09:22:28 -04:00
5cff026d7e build: get verson from git 2024-10-14 09:22:28 -04:00
e4b348c183 ci: make sure checkouts fetch tags 2024-10-14 09:22:28 -04:00
24db09b023 fix: align --display explanation in help message
Broken "." position was fixed like this.

Before:

        --display <display>  when in X mode, connect to the X server
                               at <display>
  .      --no-xinitthreads    do not call XInitThreads()

After:

        --display <display>  when in X mode, connect to the X server
                               at <display>.
        --no-xinitthreads    do not call XInitThreads()

Signed-off-by: Kentaro Hayashi <kenhys@xdump.org>
2024-10-14 13:11:30 +01:00
181c34e662 ci: attempt releases 2024-10-13 17:51:18 -04:00
ccfff7015a ci: working vcpkg cache 2024-10-13 16:15:33 -04:00
6b641a432a ci: Remove dead test-dist-upload.yml file 2024-10-13 15:42:23 -04:00
10873eddcd ci: lint-clang as composite action 2024-10-13 20:13:04 +01:00
5b76982093 ci: lint-cmake as composite action 2024-10-13 20:13:04 +01:00
c498e148b8 ci: do not auto create version tags on push to master 2024-10-13 20:13:04 +01:00
abe8146631 ci: Run CI when landing to master branch
No longer run sonar or codeQL on push to master
    They are auto run by the CI job

s
2024-10-13 20:13:04 +01:00
c630ad0952 test: Coverage for AboutDialog.cpp 2024-10-13 19:52:09 +01:00
ce35234f18 chore: Add issue not about mac os signing 2024-10-13 14:02:34 -04:00
c5247a15c7 chore: add note about known wayland issues in bug_template 2024-10-13 14:01:05 -04:00
c03e3f56a7 chore: update mono tray icons 2024-10-13 13:54:15 -04:00
821a9599ba chore: keep only a single copy of the windows icon 2024-10-13 13:54:15 -04:00
0361f850eb chore: remove unused warning icon 2024-10-13 13:54:15 -04:00
c66d7a6942 chore: Update tray icon 2024-10-13 13:54:15 -04:00
8340f106e7 chore: Update Padlock icon 2024-10-13 13:54:15 -04:00
b3775eb6fd chore: add basic .gitattributes
Don't add the items below to "Source" exports
     .github*
     .gitattributes
     .gitignore
2024-10-13 13:39:59 -04:00
e940b8526b chore: add more user files to gitignore
Add Spdx License info
  Add Cmake user files to gitignore
2024-10-13 13:37:06 -04:00
9604a9e747 ci: test results skipped if dependant skipped 2024-10-13 11:49:56 -04:00
fe67b92cdc build: Drop warnings_as_errors
This should not be used

It results in build failures when using different environments/toolchains that produce new warnings

This can especially happen on compiler or dependency updates
2024-10-12 22:13:50 -04:00
4500e7a1aa build: use @only to configure config.h 2024-10-12 21:06:55 -04:00
78a8bba7a4 refactor: move res/config.h.in -> src/lib/config.h.in 2024-10-12 21:06:55 -04:00
14dfcb672d ci: Allow ci to skip running if only specific files are changed 2024-10-12 20:37:17 -04:00
6c3b2b3e6b ci: Linting must pass before other jobs are run 2024-10-12 20:37:17 -04:00
f6b9a5f204 build: Don't force CMAKE_INSTALL_PREFIX
This should only ever be set from the outside, not the project itself

Distribution build systems will set it to the right value

This breaks installing it to a custom if desired
2024-10-12 12:59:04 -04:00
38631193b5 feat: Use native style on KDE Plasma
On Plasma it is preferred to use the default Breeze style instead of Fusion

Breeze also has dark mode support out of the box, so no need to work around that
2024-10-12 12:31:37 -04:00
c959e641cb fix: Set correct QGuiApplication::desktopFileName
The implicity default doesn't match the actual name of the desktop file.

This fixes e.g. the application icon on Wayland
2024-10-12 12:08:16 -04:00
02c5418b9e build(cmake): Require SSL 1.1.1 or higher
Link using OpenSSL provided alises
  Remove Windows specifc check ssl macro for simpler check
2024-10-12 14:23:56 +01:00
eedb3ad1c3 chore: rm unused string_utils file 2024-10-11 17:10:50 +01:00
159f49c5ee chore: use modern connections 2024-10-11 16:56:46 +01:00
80503cd2c6 docs: Add discussion value to project values in README.md 2024-10-11 08:50:24 -04:00
132e1975d3 ci: Remove cache of Python .venv as it added complexity 2024-10-11 13:24:08 +01:00
932ca44d75 build: use pragma once not ifndef def pattern for headers 2024-10-08 06:52:41 -04:00
e3ed711b98 docs: Make README.md more relevant to current repo state 2024-10-03 13:38:45 +01:00
32d36ab0be build: Bump version to 1.18.0 2024-10-02 16:13:19 +01:00
0c28a38d90 docs: Update README.md with Matrix link 2024-10-02 09:37:30 -04:00
049e34f7a5 chore: Remove word 'beta' from Wayland message 2024-10-02 09:17:57 -04:00
786 changed files with 19289 additions and 20810 deletions

View File

@ -13,16 +13,40 @@ BasedOnStyle: LLVM
# Turn off LLVM default alignment of params with the opening bracket,
# which can be less readable in some cases in our code base.
#
# Using `AlwaysBreak` will result in:
# Using `BlockIndent` will result in:
# void fooBarBazQuxHelloWorld(
# int a,
# int b);
# int b
# );
#
# Instead of:
# void fooBarBazQuxHelloWorld(int a,
# int b);
AlignAfterOpenBracket: AlwaysBreak
AlignAfterOpenBracket: BlockIndent
# Turn off LLVM default packing of ctor initializers.
# This makes it easier to see which members were initialized and in what order.
PackConstructorInitializers: CurrentLine
# up our limit to 120
ColumnLimit: 120
# Custom Breaking rules
BreakBeforeBraces: Custom
BraceWrapping:
AfterCaseLabel: false
AfterClass: true
AfterControlStatement: Never
AfterEnum: true
AfterFunction: true
AfterNamespace: false
AfterStruct: true
AfterUnion: true
AfterExternBlock: true
BeforeCatch: false
BeforeElse: false
BeforeLambdaBody: false
BeforeWhile: false
# no single line functions
AllowShortFunctionsOnASingleLine: None

9
.editorconfig Normal file
View File

@ -0,0 +1,9 @@
root = true
[*]
end_of_line = lf
insert_final_newline = true
[{*.yml,*.yaml,*.json,CMakeLists.txt,*.cmake}]
indent_style = space
indent_size = 2

View File

@ -1,65 +0,0 @@
#
# Usage: Copy this .env.example file to .env
#
#
# App
#
# Shows the test menu in the GUI (on by default in debug mode)
# DESKFLOW_TEST_MENU=true
# Version checker URL to use (useful for testing)
# DESKFLOW_VERSION_URL="https://api.deskflow.org/version?fake=1.100.0"
# Enable debug logging in the GUI (on by default in debug mode)
# DESKFLOW_GUI_DEBUG=true
# Enable verbose logging in the GUI (always off by default)
# DESKFLOW_GUI_VERBOSE=true
# Reset all settings and delete all data on startup
# DESKFLOW_RESET_ALL=true
#
# Build
#
# [Windows] The version of Qt to build against (overrides the value in the config.yml file)
# QT_VERSION=1.2.3
#
# Packaging (optional)
#
# [Linux] Build extra packages (self-extracting tar.gz and tar.gz)
# LINUX_EXTRA_PACKAGES=true
# [Linux] Run the package command as a different user (requires sudo)
# LINUX_PACKAGE_USER=build
# [Windows] Base64 encoded PFX code signing certificate
# WINDOWS_PFX_CERTIFICATE="very-long-base64-encoded-string"
# [Windows] Password for the PFX code signing certificate
# WINDOWS_PFX_PASSWORD="super-secret-password"
# [macOS] Certificate ID for the Developer ID Application code signing certificate
# APPLE_CODESIGN_ID="Developer ID Application: Acme Inc (ABC123XYZ9)"
# [macOS] Base64 encoded P12 code signing certificate
# APPLE_P12_CERTIFICATE="very-long-base64-encoded-string"
# [macOS] Password for the P12 code signing certificate
# APPLE_P12_PASSWORD="super-secret-password"
# [macOS] Apple Team ID
# https://developer.apple.com/account/#/membership
# APPLE_TEAM_ID="ABC123XYZ9"
# [macOS] Apple ID used to notarize the app
# APPLE_NOTARY_USER="example@example.com"
# [macOS] App-specific password for the Apple ID
# https://support.apple.com/en-gb/102654
# APPLE_NOTARY_PASSWORD="super-secret-password"

9
.gitattributes vendored Normal file
View File

@ -0,0 +1,9 @@
# SPDX-FileCopyrightText: Chris Rizzitello <sithlord48@gmail.com>
# SPDX-License-Identifier: MIT
#auto handle line feed
* text=auto eol=lf
.gitattributes export-ignore
.gitignore export-ignore
.github* export-ignore

View File

@ -27,7 +27,7 @@ body:
attributes:
label: Deskflow version number
description: You can find the Deskflow version number on the about screen.
placeholder: 1.2.3
placeholder: 1.2.3.4
validations:
required: true
@ -39,9 +39,10 @@ body:
options:
# Empty option to force selection
-
- Local developer build (built it yourself)
- Deskflow package (downloaded from Deskflow)
- Community package (apt, dnf, brew, etc.)
- Deskflow package (downloaded from us)
- Local developer build (built it myself)
- Other (please specify)
default: 0
validations:
required: true
@ -54,12 +55,40 @@ body:
options:
- label: Windows
- label: macOS
- label: Linux
- label: Linux (X11)
- label: Linux (Wayland)
- label: BSD-derived
- label: Other
- label: Other (please specify)
validations:
required: true
- type: checkboxes
id: linux-wayland
attributes:
label: Wayland on Linux
description: If using Wayland on Linux, please review the [known issues](https://github.com/deskflow/deskflow/discussions/7499) before reporting.
options:
- label: I have reviewed the Wayland [known issues](https://github.com/deskflow/deskflow/discussions/7499) and my issue is new
- label: I am not using Wayland on Linux
- type: checkboxes
id: mac-signing
attributes:
label: Signing on macOS
description: If using macOS and the app crashes, try [Apple's solution](https://support.apple.com/guide/mac-help/open-a-mac-app-from-an-unknown-developer-mh40616/mac) before reporting.
options:
- label: I have authorized the app to run on my Mac
- label: I am not using macOS
- type: checkboxes
id: continuous-build
attributes:
label: Continuous build
description: Please try the latest [continuous build](https://github.com/deskflow/deskflow/releases) of Deskflow. It may have a fix for your issue.
options:
- label: I have tried the latest continuous build and the issue persists
- label: I am unable to try the latest continuous build
- type: textarea
id: os-version
attributes:
@ -87,8 +116,6 @@ body:
- Windows 11 server, macOS 15 client
- Each computer has a single monitor
- Windows is on the left, macOS is on the right
validations:
required: true
- type: textarea
id: repro-steps
@ -102,8 +129,6 @@ body:
1. Start Deskflow
2. Click 'Configure Server'
3. Click 'Apply'
validations:
required: true
- type: textarea
id: logs

View File

@ -6,85 +6,11 @@ body:
attributes:
value: Thanks for taking the time to help us improve Deskflow.
- type: dropdown
id: project
attributes:
label: Project
description: Are you using Deskflow or a fork/derivative?
options:
# Empty option to force selection
-
- Deskflow
- Barrier
- Input Leap
- Synergy
default: 0
validations:
required: true
- type: checkboxes
id: os
attributes:
label: Operating systems (OS)
description: Which operating systems (OS) are you using?
options:
- label: Windows
- label: macOS
- label: Linux
- label: BSD-derived
- label: Other
validations:
required: true
- type: textarea
id: os-version
id: request
attributes:
label: OS versions/distros
label: Feature Request
description: |
Please provide the version number of your operating system (OS).
If you're using Linux, please provide the name of the distribution.
placeholder: |
- Windows 11
- macOS 15
- Ubuntu 24.04
- FreeBSD 14.0
validations:
required: true
- type: textarea
id: config
attributes:
label: Deskflow configuration
description: |
Please provide a very brief description of your configuration.
Let us know the OS of the server/host/primary and the OS of the client/guest/secondary.
This will help us understand how you're using Deskflow.
placeholder: |
- Windows 11 server, macOS 15 client
- Each computer has a single monitor
- Windows is on the left, macOS is on the right
validations:
required: true
- type: textarea
id: problem
attributes:
label: What problem are you trying to solve?
description: |
The most important part of problem solving is understanding the problem.
The more detail you provide, the better we can understand your idea.
“If I had only one hour to save the world,
I would spend fifty-five minutes defining the problem,
and only five minutes finding the solution.”
— Albert Einstein
validations:
required: true
- type: textarea
id: solution
attributes:
label: What solution do you propose?
description: |
Please describe the solution you have in mind.
Please describe the feature you have in mind.
validations:
required: true

View File

@ -0,0 +1,34 @@
# SPDX-FileCopyrightText: 2024 Chris Rizzitello <sithlord48@gmail.com>
# SPDX-License-Identifier: MIT
name: "Add Kitware repo"
description: "Add Kitware repo for Debian-like distros"
inputs:
distro:
description: "Ubuntu codename, Kitware uses: noble, jammy, focal"
required: true
runs:
using: "composite"
steps:
# This mirrors instructions at https://apt.kitware.com
- name: Add repo
run: |
apt update -y -qqq
apt install ca-certificates gpg wget -y -qqq
wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null \
| gpg --dearmor - \
> /usr/share/keyrings/kitware-archive-keyring.gpg
echo 'deb [signed-by=/usr/share/keyrings/kitware-archive-keyring.gpg] https://apt.kitware.com/ubuntu/ ${{ inputs.distro }} main' \
> /etc/apt/sources.list.d/kitware.list
apt update -y -qqq
env:
# Prevent apt prompting for input.
DEBIAN_FRONTEND: noninteractive
shell: bash

View File

@ -6,10 +6,10 @@ runs:
steps:
- run: |
if [[ "${{ github.ref }}" == refs/tags/* ]]; then
echo "DESKFLOW_VERSION=${{ github.ref_name }}" >> $GITHUB_ENV
fi
if [[ "${{ github.event.inputs.version }}" != "" ]]; then
echo "DESKFLOW_VERSION=${{ github.event.inputs.version }}" >> $GITHUB_ENV
echo "DESKFLOW_VERSION=$(git describe --long | sed 's/-/./g;s/v//g' | grep -o '^[0-9]*.[0-9]*.[0-9]*.[0-9]*')">> $GITHUB_ENV
if [[ "$GITHUB_REF" == *"tags/v"* ]]; then
echo "DESKFLOW_PACKAGE_VERSION=$(echo $GITHUB_REF | sed 's,refs/tags/v,,g')">> $GITHUB_ENV
else
echo "DESKFLOW_PACKAGE_VERSION=continuous">> $GITHUB_ENV
fi
shell: bash

View File

@ -1,50 +1,23 @@
# Important: Do not be tempted to cache the .venv dir (Python virtual environment).
# When the runner environment changes (e.g. Python is upgraded), the venv will need to be
# re-created. Trying to upgrade a venv can be complex and it's usually more practical re-create it.
# We don't save much time anyway by caching the venv so it's not worth the added complexity.
name: "Setup Python venv"
description: "Creates and caches a Python virtual environment"
inputs:
cache:
description: "Cache Python venv"
default: true
setup:
description: "Setup Python venv"
default: true
python-bin:
description: "Python binary to use"
default: "python3"
cache-key:
description: "Cache key (note: hash is appended)"
required: true
description: "Creates a Python virtual environment (venv)"
runs:
using: "composite"
steps:
- name: Check cache key
if: ${{ inputs.cache }}
run: |
if [ -z "${{ inputs.cache-key }}" ]; then
echo "Cache key is required"
exit 1
fi
shell: bash
- name: Cache Python venv
if: ${{ inputs.cache }}
uses: actions/cache@v4
with:
path: .venv
key: python-venv-${{ inputs.cache-key }}-${{ hashFiles('scripts/pyproject.toml') }}
# Use bash if to make output clearer in case of skipping.
- name: Setup Python venv
run: |
if [ "${{ inputs.setup }}" = "true" ]; then
echo "Setting up Python venv"
${{ inputs.python-bin }} -m venv .venv
if [ "${{ runner.os }}" == "Windows" ]; then
python=python
else
echo "Skipping Python venv setup"
python=python3
fi
echo "Setting up Python venv, bin=$python"
$python -m venv .venv
shell: bash

View File

@ -0,0 +1,100 @@
# SPDX-FileCopyrightText: 2024 Chris Rizzitello <sithlord48@gmail.com>
# SPDX-License-Identifier: MIT
name: "Install dependencies for deskflow"
description: "Install the dependencies needed to build deskflow"
inputs:
like:
description: "Used only on linux distro type: debian, fedora, suse, arch"
required: false
mac-qt-version:
description: "The verison of Qt to install on mac os"
required: false
outputs:
vcpkg-cmake-config:
description: "windows vcpkg output for cmaket"
value: ${{ steps.vcpkg.outputs.vcpkg-cmake-config }}
runs:
using: "composite"
steps:
- name: Install Depends
run: |
if [ "$RUNNER_OS" == "Windows" ]; then
echo "Window not supported yet"
elif [ "$RUNNER_OS" == "macOS" ]; then
brew install cmake googletest ninja 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
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 \
libei-devel libportal-devel tomlplusplus-devel \
cli11-devel
elif [ ${{inputs.like}} == "suse" ]; then
zypper refresh
zypper install -y --force-resolution \
cmake make ninja gcc-c++ rpm-build libopenssl-devel \
glib2-devel gdk-pixbuf-devel libXtst-devel libnotify-devel \
libxkbfile-devel qt6-base-devel qt6-tools-devel gtk3-devel \
googletest-devel googlemock-devel pugixml-devel libei-devel \
libportal-devel tomlplusplus-devel cli11-devel
elif [ ${{ inputs.like }} == "arch" ]; then
pacman -Syu --noconfirm base-devel cmake ninja \
gcc openssl glib2 gdk-pixbuf2 libxtst libnotify \
libxkbfile gtest pugixml libei libportal \
qt6-base qt6-tools gtk3 tomlplusplus cli11
else
echo "Unknown like"
fi
else
echo "Unknown OS: $RUNNER_OS"
fi
shell: bash
- name: Install Qt
if: ${{runner.os == 'macOS' }}
uses: jurplel/install-qt-action@v4
with:
dir: "/Users/runner"
version: ${{inputs.mac-qt-version}}
cache: true
cache-key-prefix: ${{matrix.target.os}}-${{env.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
with:
manifest-dir: ${{ github.workspace }}
triplet: x64-windows-release
token: ${{ github.token }}
github-binarycache: true
- name: Install Wix
if: ${{ runner.os == 'Windows' }}
run: |
dotnet tool install --global wix --version 4.0.4
wix extension add --global WixToolset.UI.wixext/4.0.4
shell: pwsh

21
.github/actions/lint-clang/action.yml vendored Normal file
View File

@ -0,0 +1,21 @@
name: "Lint clang"
description: "Lint with Clang formatter"
runs:
using: "composite"
steps:
- name: Setup Python venv
uses: ./.github/actions/init-python
- name: Install dependencies
shell: bash
run: |
source .venv/bin/activate
pip install pyyaml clang_format
- name: Linting with Clang formatter
uses: ./.github/actions/lint-error
with:
format-command: ./scripts/lint_clang.py -f
format-tool: "clang-format"

View File

@ -1,13 +1,24 @@
name: "Test Summary"
description: "Creates a markdown table from test results and uploads a summary file"
inputs:
download-pattern:
description: "The pattern to download test result rows"
required: false
default: test-result-*
upload-name:
description: "The artifact upload name for the summary"
required: false
default: summary-tests
runs:
using: "composite"
steps:
- name: Download test result rows
uses: actions/download-artifact@v4
with:
pattern: test-result-*
pattern: ${{ inputs.download-pattern }}
merge-multiple: true
path: rows
@ -44,24 +55,30 @@ runs:
table="${{ steps.markdown-table.outputs.markdown }}"
if [ -z "$table" ]; then
echo "No test results found" > $GITHUB_STEP_SUMMARY
echo "No test results found" | tee $GITHUB_STEP_SUMMARY >&2
exit 1
else
echo "$table" > $GITHUB_STEP_SUMMARY
fi
count=$(echo -n "$table" | grep -o "❌" | wc -l || echo 0)
count=$(echo "$table" | awk -v RS='' '{gsub(/[^❌]/, ""); print length}')
file="ci-summary.md"
if [ $count -gt 0 ]; then
file="ci-summary.md"
echo "❌🔬 Tests failed: $count" > $file
echo "❌🔬 Tests failed: $count" | tee $file
echo "file=$file" >> $GITHUB_OUTPUT
else
# For debugging; don't send success to CI summary (reduce noise).
echo > $file
echo "✅🔬 All tests passed"
fi
shell: bash
- name: Upload CI summary
if: steps.summary.outputs.file
uses: actions/upload-artifact@v4
with:
name: summary-tests
name: ${{ inputs.upload-name }}
path: ${{ steps.summary.outputs.file }}
if-no-files-found: error

View File

@ -0,0 +1,32 @@
name: Winget Publish
description: A composite action to publish packages to the Windows Package Manager (Winget) repository
inputs:
release-version:
description: "Version to publish to Winget package manager (without 'v' prefix)"
required: true
token:
description: "GitHub token with public read permissions on the source repo"
required: true
runs:
using: "composite"
steps:
- name: Submit package to Windows Package Manager Community Repository
if: ${{ runner.os == 'Windows' }}
env:
GITHUB_TOKEN: ${{ inputs.token }}
run: |
# Download latest wingetcreate
Invoke-WebRequest https://aka.ms/wingetcreate/latest -OutFile wingetcreate.exe
$packageId = "Deskflow.Deskflow"
$installerUrl = "https://github.com/deskflow/deskflow/releases/download/v${{ inputs.release-version }}/deskflow-${{ inputs.release-version }}.0_win64.msi"
# Submit package update
.\wingetcreate.exe update "$packageId" `
--version "${{ inputs.release-version }}" `
--urls "$installerUrl" `
--submit `
--token "${{ inputs.token }}"
shell: pwsh

View File

@ -1,17 +0,0 @@
# syntax=docker/dockerfile:1
ARG BASE_IMAGE
FROM $BASE_IMAGE AS base
FROM base AS deps
RUN pacman -Syu --noconfirm git python sudo && \
pacman -Scc --noconfirm
RUN useradd -m build
WORKDIR /app
RUN --mount=type=bind,target=/app,rw \
./scripts/install_deps.py && \
pacman -Scc --noconfirm

View File

@ -1,17 +0,0 @@
# syntax=docker/dockerfile:1
ARG BASE_IMAGE
FROM $BASE_IMAGE AS base
FROM base AS deps
RUN apt update && \
apt dist-upgrade -y && \
apt install -y git python3 && \
apt clean
WORKDIR /app
RUN --mount=type=bind,target=/app,rw \
./scripts/install_deps.py && \
apt clean

View File

@ -1,16 +0,0 @@
# syntax=docker/dockerfile:1
ARG BASE_IMAGE
FROM $BASE_IMAGE AS base
FROM base AS deps
RUN dnf upgrade -y && \
dnf install -y git python3 && \
dnf clean all
WORKDIR /app
RUN --mount=type=bind,target=/app,rw \
./scripts/install_deps.py && \
dnf clean all

View File

@ -1,17 +0,0 @@
# syntax=docker/dockerfile:1
ARG BASE_IMAGE
FROM $BASE_IMAGE AS base
FROM base AS deps
RUN zypper refresh && \
zypper update -y && \
zypper install -y git python3 && \
zypper clean --all
WORKDIR /app
RUN --mount=type=bind,target=/app,rw \
./scripts/install_deps.py && \
zypper clean --all

View File

@ -1,128 +0,0 @@
# Weekly build of the Linux Docker containers.
#
# The objective is to reduce the problem where package updates often break the build process
# due to transient network errors.
#
# We use Docker Buildx instead of Docker Automated Builds so that we can create an image that is
# always at most a week out of date (instead of the last time a Dockerfile change was pushed).
name: Build containers
on:
workflow_dispatch:
schedule:
- cron: "0 5 * * 0"
jobs:
build-containers:
name: ${{ matrix.os.name }}
runs-on: ${{ matrix.os.runs-on }}
if: ${{ vars.BUILD_CONTAINERS }}
timeout-minutes: 10
strategy:
# Build all images even if some fail.
fail-fast: false
matrix:
os:
- name: debian-13-amd64
runs-on: ubuntu-latest
config-dir: debian
base-image: debian:trixie-slim
platform: amd64
- name: debian-12-amd64
runs-on: ubuntu-latest
config-dir: debian
base-image: debian:12-slim
platform: amd64
- name: debian-12-arm64
runs-on: ubuntu-24.04-2-core-arm64
config-dir: debian
base-image: arm64v8/debian:12-slim
platform: arm64
- name: ubuntu-24.04-amd64
runs-on: ubuntu-latest
config-dir: debian
base-image: ubuntu:24.04
platform: amd64
- name: ubuntu-22.04-amd64
runs-on: ubuntu-latest
config-dir: debian
base-image: ubuntu:22.04
platform: amd64
- name: fedora-40-amd64
runs-on: ubuntu-latest
config-dir: fedora
base-image: fedora:40
platform: amd64
- name: fedora-40-arm64
runs-on: ubuntu-24.04-2-core-arm64
config-dir: fedora
base-image: arm64v8/fedora:40
platform: arm64
- name: fedora-39-amd64
runs-on: ubuntu-latest
config-dir: fedora
base-image: fedora:39
platform: amd64
- name: rockylinux-9-amd64
runs-on: ubuntu-latest
config-dir: fedora
base-image: rockylinux:9
platform: amd64
- name: almalinux-9-amd64
runs-on: ubuntu-latest
config-dir: fedora
base-image: almalinux:9
platform: amd64
- name: opensuse-amd64
runs-on: ubuntu-latest
config-dir: opensuse
base-image: opensuse/tumbleweed:latest
platform: amd64
- name: archlinux-amd64
runs-on: ubuntu-latest
config-dir: archlinux
base-image: archlinux:latest
platform: amd64
- name: manjaro-amd64
config-dir: archlinux
runs-on: ubuntu-latest
base-image: manjarolinux/base:latest
platform: amd64
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v6
with:
push: true
context: .
file: ./.github/docker/${{ matrix.os.config-dir }}/Dockerfile
tags: deskflow/deskflow:${{ matrix.os.name }}
build-args: BASE_IMAGE=${{ matrix.os.base-image }}
platforms: linux/${{ matrix.os.platform }}

View File

@ -1,76 +0,0 @@
{
"distro": [
{
"name": "debian-13-amd64",
"container": "deskflow/deskflow:debian-13-amd64",
"runs-on": "ubuntu-latest",
"extra-packages": true
},
{
"name": "debian-12-arm64",
"container": "deskflow/deskflow:debian-12-arm64",
"runs-on": "ubuntu-24.04-4-core-arm64",
"extra-packages": true
},
{
"name": "debian-12-amd64",
"container": "deskflow/deskflow:debian-12-amd64",
"runs-on": "ubuntu-latest",
"extra-packages": true
},
{
"name": "ubuntu-24.04-amd64",
"container": "deskflow/deskflow:ubuntu-24.04-amd64",
"runs-on": "ubuntu-latest",
"extra-dep-args": "--meson-no-system libportal --meson-static libportal --subprojects",
"extra-cmake-args": "-DSYSTEM_LIBPORTAL=OFF -DSTATIC_LIBPORTAL=ON"
},
{
"name": "ubuntu-22.04-amd64",
"container": "deskflow/deskflow:ubuntu-22.04-amd64",
"runs-on": "ubuntu-latest"
},
{
"name": "fedora-40-arm64",
"container": "deskflow/deskflow:fedora-40-arm64",
"runs-on": "ubuntu-24.04-4-core-arm64"
},
{
"name": "fedora-40-amd64",
"container": "deskflow/deskflow:fedora-40-amd64",
"runs-on": "ubuntu-latest"
},
{
"name": "fedora-39-amd64",
"container": "deskflow/deskflow:fedora-39-amd64",
"runs-on": "ubuntu-latest"
},
{
"name": "opensuse-amd64",
"container": "deskflow/deskflow:opensuse-amd64",
"runs-on": "ubuntu-latest"
},
{
"name": "rockylinux-9-amd64",
"container": "deskflow/deskflow:rockylinux-9-amd64",
"runs-on": "ubuntu-latest"
},
{
"name": "almalinux-9-amd64",
"container": "deskflow/deskflow:almalinux-9-amd64",
"runs-on": "ubuntu-latest"
},
{
"name": "archlinux-amd64",
"container": "deskflow/deskflow:archlinux-amd64",
"runs-on": "ubuntu-latest",
"package-user": "build"
},
{
"name": "manjaro-amd64",
"container": "deskflow/deskflow:manjaro-amd64",
"runs-on": "ubuntu-latest",
"package-user": "build"
}
]
}

View File

@ -5,28 +5,36 @@
name: CI
on:
workflow_dispatch:
inputs:
version:
description: Deskflow version number
push:
branches: [master]
tags:
- 'v*'
pull_request:
types:
- opened
- reopened
- synchronize
- ready_for_review
schedule:
- cron: "0 5 * * *" # 5am UTC
paths-ignore:
- '**/*.md'
- '.github/ISSUE_TEMPLATE/**'
- '.editorconfig'
- '.env-example'
- '.gitignore'
- '.gitattributes'
- 'cspell.json'
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"
jobs:
# Always run this job, even if not on PR, since other jobs need it.
pr-comment-flags:
runs-on: ubuntu-latest
if: ${{ github.event_name == 'pull_request' }}
needs: lint-clang
outputs:
no-sonar: ${{ steps.check.outputs.no-sonar }}
@ -36,6 +44,7 @@ jobs:
uses: actions/checkout@v4
- name: Check PR comment for flags
if: ${{ github.event_name == 'pull_request' }}
id: check
env:
PR_BODY: ${{ github.event.pull_request.body }}
@ -52,7 +61,7 @@ jobs:
# Quality gate to allow PR merge, used in the branch protection rules.
ci-passed:
runs-on: ubuntu-latest
needs: [lint-cmake, lint-clang, windows, macos, linux, unix]
needs: [test-results, unix]
steps:
- run: echo "✅ CI passed" > $GITHUB_STEP_SUMMARY
@ -60,8 +69,8 @@ jobs:
# Summary of test results, combined from test result artifacts.
# Runs even if the tests fail to provide a summary of the failures.
test-results:
needs: [windows, macos, linux]
if: always()
needs: main-build
if: always() && needs.main-build.result != 'skipped'
runs-on: ubuntu-latest
timeout-minutes: 5
@ -73,35 +82,35 @@ jobs:
- name: Test summary
uses: ./.github/actions/test-summary
lint-cmake:
if: ${{ github.event_name == 'pull_request' }}
uses: ./.github/workflows/lint-cmake.yml
lint-clang:
if: ${{ github.event_name == 'pull_request' }}
uses: ./.github/workflows/lint-clang.yml
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Linting Clang
uses: ./.github/actions/lint-clang
analyse-valgrind:
needs: lint-clang
if: ${{ github.event_name == 'pull_request' }}
uses: ./.github/workflows/valgrind-analysis.yml
analyse-codeql:
if: ${{ github.event_name == 'pull_request' }}
uses: ./.github/workflows/codeql-analysis.yml
analyse-sonarcloud:
needs: pr-comment-flags
if: ${{ github.event_name == 'pull_request' && needs.pr-comment-flags.outputs.no-sonar != 'true' }}
if: ${{ needs.pr-comment-flags.outputs.no-sonar != 'true' }}
uses: ./.github/workflows/sonarcloud-analysis.yml
secrets:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
windows:
main-build:
needs: lint-clang
name: ${{ matrix.target.name }}
runs-on: ${{ matrix.target.runs-on }}
container: ${{ matrix.target.container }}
timeout-minutes: 20
timeout-minutes: ${{ matrix.target.timeout }}
strategy:
# Normally, we want to fail fast, but in this case we shouldn't since one target may
# fail due to transient issues unrelated to the build.
@ -109,136 +118,122 @@ jobs:
matrix:
target:
- name: windows-2022-x64
runs-on: ${{ vars.CI_WINDOWS_RUNNER || 'windows-2022' }}
- name: "windows-2022-x64"
runs-on: "windows-2022"
timeout: 120 #Windows can take while if it has to build vcpkg cache
config-args: "-G Ninja"
- name: "macos-14-arm64"
runs-on: "macos-14"
timeout: 10
arch: arm64
config-args: "-DCMAKE_OSX_ARCHITECTURES=\"arm64\" -DMACOSX_DEPLOYMENT_TARGET=12"
- name: "macos-13-x64"
runs-on: macos-13
timeout: 20
config-args: "-DCMAKE_OSX_ARCHITECTURES=\"x86_64\" -DMACOSX_DEPLOYMENT_TARGET=12"
- name: "debian-13-amd64"
runs-on: ubuntu-latest
container: debian:trixie-slim
like: "debian"
timeout: 20
config-args: "-G Ninja -DCMAKE_INSTALL_PREFIX=/usr"
- name: "fedora-41-amd64"
runs-on: ubuntu-latest
container: fedora:41
like: "fedora"
timeout: 20
config-args: "-G Ninja -DCMAKE_INSTALL_PREFIX=/usr"
- name: "fedora-40-amd64"
runs-on: ubuntu-latest
container: fedora:40
like: "fedora"
timeout: 20
config-args: "-G Ninja -DCMAKE_INSTALL_PREFIX=/usr"
- name: "opensuse-amd64"
runs-on: ubuntu-latest
container: opensuse/tumbleweed:latest
like: "suse"
timeout: 20
config-args: "-G Ninja -DCMAKE_INSTALL_PREFIX=/usr"
- name: "archlinux-amd64"
runs-on: ubuntu-latest
container: archlinux:latest
like: "arch"
timeout: 20
config-args: "-G Ninja -DCMAKE_INSTALL_PREFIX=/usr"
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Get version
uses: ./.github/actions/get-version
- name: Cache vcpkg dir
uses: actions/cache@v4
with:
# We also need to cache the `LOCALAPPDATA` dir; without doing so, openssl
# rebuilds (after it is detected in cache) every time, which takes around 10 mins.
path: |
vcpkg
vcpkg_installed
${{ env.LOCALAPPDATA }}/vcpkg
key: vcpkg-${{ runner.os }}-${{ hashFiles('vcpkg.json', 'vcpkg-configuration.json') }}
# Should only restore the .venv directory from cache.
- name: Init Python venv
uses: ./.github/actions/init-python
with:
cache-key: ci-${{ matrix.target.name }}
setup: false
- name: Cache deps dir
uses: actions/cache@v4
with:
path: ./deps
key: ${{ runner.os }}-deps-${{ hashFiles('config.yaml') }}
# Make sure the container has git before we do anything else
- name: Install Git on Container
if: ${{ matrix.target.container }}
shell: bash
run : |
if [ "${{matrix.target.like}}" == "debian" ]; then
apt update -qqq > /dev/null && apt install -qqq git devscripts > /dev/null
elif [ "${{matrix.target.like}}" == "fedora" ]; then
dnf install -y git
elif [ "${{matrix.target.like}}" == "suse" ]; then
zypper refresh
zypper install -y --force-resolution git
elif [ "${{matrix.target.like}}" == "arch" ]; then
pacman -Syu --noconfirm git
else
echo "Unknown: ${{matrix.target.like}}"
fi
# Fancy checkout gets all the tags
# it also makes sure we can use git --describe correctly
- name: Fancy Checkout
uses: sithlord48/fancy-checkout@v1.0.0
# This effectively runs `vcvarsall.bat`, etc. It's not actually installing
# VC++ as that's already pre-installed on the Windows runner.
- name: Setup VC++ environment
if: ${{ runner.os == 'Windows' }}
uses: ilammy/msvc-dev-cmd@v1
# 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
uses: seanmiddleditch/gha-setup-ninja@master
- name: Install dependencies
env:
VCPKG_ROOT: "" # Unset deliberately to suppress 'already installed' warning.
run: python ./scripts/install_deps.py
- name: Configure
run: cmake -B build --preset=windows-release
- name: Build
run: cmake --build build -j8
- name: Tests
uses: ./.github/actions/run-tests
timeout-minutes: 2
id: get-deps
uses: ./.github/actions/install-dependencies
with:
job: ${{ matrix.target.name }}
mac-qt-version: 6.7.2
like: ${{ matrix.target.like }}
- name: Package
run: python ./scripts/package.py
env:
WINDOWS_PFX_CERTIFICATE: ${{ secrets.WINDOWS_PFX }}
WINDOWS_PFX_PASSWORD: ${{ secrets.WINDOWS_PFX_PASS }}
- name: Upload
uses: actions/upload-artifact@v4
with:
name: ${{ env.PACKAGE_PREFIX }}-${{ matrix.target.name }}
path: ${{ env.PACKAGE_PATH }}
macos:
name: ${{ matrix.target.name }}
runs-on: ${{ matrix.target.os }}
timeout-minutes: ${{ matrix.target.timeout }}
defaults:
run:
shell: ${{ matrix.target.shell }}
strategy:
# Normally, we want to fail fast, but in this case we shouldn't since one target may
# fail due to transient issues unrelated to the build.
fail-fast: false
matrix:
target:
- name: "macos-14-arm64"
timeout: 10
os: "macos-14"
arch: arm64
shell: "/usr/bin/arch -arch arm64e /bin/bash --noprofile --norc -eo pipefail {0}"
- name: ${{ vars.CI_MAC_INTEL_NAME || 'macos-13-x64' }}
timeout: 20
os: ${{ vars.CI_MAC_INTEL_RUNNER || 'macos-13' }}
arch: x64
shell: "bash"
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Python
if: ${{runner.os != 'Linux' }}
run: python ./scripts/setup_venv.py
- name: Get version
uses: ./.github/actions/get-version
# Should only restore the .venv directory from cache.
- name: Setup Python venv
uses: ./.github/actions/init-python
with:
cache-key: ci-${{ matrix.target.name }}
setup: false
- name: Cache deps dir
uses: actions/cache@v4
with:
path: ./deps
key: ${{ runner.os }}-deps-${{ hashFiles('config.yaml') }}
- name: Install dependencies
run: ./scripts/install_deps.py
- name: Configure
run: cmake -B build --preset=macos-release
run: ${{env.CMAKE_CONFIGURE}} ${{ matrix.target.config-args }} ${{ steps.get-deps.outputs.vcpkg-cmake-config }} -DPACKAGE_VERSION_LABEL=${{env.DESKFLOW_PACKAGE_VERSION}}
- name: Build
run: cmake --build build -j8
shell: bash
run: |
if [[ "$RUNNER_OS" == "Linux" && "${{matrix.target.like}}" != "arch" ]]; then
cmake --build build -j8 --target package
else
cmake --build build -j8
fi
if [ ${{ matrix.target.like }} == "arch" ];then
useradd -m build
sudo chown -R build build
cd build
sudo -u build makepkg -s
export OSNAME=$(cat /etc/os-release | grep ^ID= | sed 's/ID=//g')
export ARCH=$(uname -m)
mv *.pkg.tar.zst deskflow-${{env.DESKFLOW_PACKAGE_VERSION}}-${OSNAME}-${ARCH}.pkg.tar.zst
cd ..
fi
- name: Tests
uses: ./.github/actions/run-tests
@ -246,9 +241,16 @@ jobs:
with:
job: ${{ matrix.target.name }}
- name: Package
run: ./scripts/package.py
if: ${{ runner.os != 'Linux' }}
shell: bash
run: |
python ./scripts/package.py --package-version ${{env.DESKFLOW_PACKAGE_VERSION}}
mv dist/deskflow* build/
env:
WINDOWS_PFX_CERTIFICATE: ${{ secrets.WINDOWS_PFX }}
WINDOWS_PFX_PASSWORD: ${{ secrets.WINDOWS_PFX_PASS }}
APPLE_CODESIGN_ID: ${{ secrets.APPLE_CODESIGN_ID }}
APPLE_P12_CERTIFICATE: ${{ secrets.APPLE_P12_CERTIFICATE }}
APPLE_P12_PASSWORD: ${{ secrets.APPLE_P12_PASSWORD }}
@ -259,102 +261,16 @@ jobs:
- name: Upload
uses: actions/upload-artifact@v4
with:
name: ${{ env.PACKAGE_PREFIX }}-${{ matrix.target.name }}
path: ${{ env.PACKAGE_PATH }}
linux-matrix:
runs-on: ubuntu-latest
outputs:
json-matrix: ${{ steps.filter.outputs.json }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Filter JSON
uses: ./.github/actions/filter-json
id: filter
with:
json-file: .github/workflows/ci-linux.json
condition: '"${{ vars.CI_USE_LINUX_ARM_RUNNER }}" != "true"'
jq-filter: .distro |= map(select(.["runs-on"] | contains("arm64") | not))
linux:
needs: linux-matrix
name: linux-${{ matrix.distro.name }}
runs-on: ${{ matrix.distro.runs-on }}
container: ${{ matrix.distro.container }}
timeout-minutes: 20
strategy:
# Normally, we want to fail fast, but in this case we shouldn't since one distro may
# fail due to transient issues unrelated to the build.
fail-fast: false
matrix: ${{fromJson(needs.linux-matrix.outputs.json-matrix)}}
steps:
- name: Checkout
uses: actions/checkout@v4
# Should only restore the .venv directory from cache.
- name: Setup Python venv
uses: ./.github/actions/init-python
with:
cache-key: ci-${{ matrix.distro.name }}
setup: false
- name: Get version
uses: ./.github/actions/get-version
- name: Config Git safe dir
run: git config --global --add safe.directory $GITHUB_WORKSPACE
- name: Install dependencies
run: ./scripts/install_deps.py ${{ matrix.distro.extra-dep-args }}
env:
# Prevent apt prompting for input.
DEBIAN_FRONTEND: noninteractive
- name: Configure
run: cmake -B build --preset=linux-release ${{ matrix.distro.extra-cmake-args }}
- name: Build
run: cmake --build build -j8
- name: Tests
uses: ./.github/actions/run-tests
timeout-minutes: 2
with:
job: linux-${{ matrix.distro.name }}
- name: Package
env:
LINUX_EXTRA_PACKAGES: ${{ matrix.distro.extra-packages }}
LINUX_PACKAGE_USER: ${{ matrix.distro.package-user }}
run: ./scripts/package.py
- name: Upload
uses: actions/upload-artifact@v4
with:
name: ${{ env.PACKAGE_PREFIX }}-${{ matrix.distro.name }}
path: ${{ env.PACKAGE_PATH }}
name: package-${{ env.PACKAGE_PREFIX }}-${{ matrix.target.name }}
path: ${{github.workspace}}/build/deskflow[-_]*.*
# Technically, "unix" is a misnomer, but we use it here to mean "Unix-like BSD-derived".
unix:
needs: lint-clang
name: unix-${{ matrix.distro.name }}
runs-on: ${{ vars.CI_UNIX_RUNNER || 'ubuntu-24.04' }}
timeout-minutes: 20
env:
DESKFLOW_BUILD_CMD: |
./scripts/install_deps.sh;
cmake -B build;
cmake --build build -j16;
export QT_QPA_PLATFORM=offscreen;
./build/bin/unittests
./build/bin/integtests
strategy:
fail-fast: false
@ -363,12 +279,85 @@ jobs:
- name: freebsd
steps:
- name: Checkout
uses: actions/checkout@v4
# Fancy checkout gets all the tags
# it also makes sure we can use git --describe correctly
- name: Fancy Checkout
uses: sithlord48/fancy-checkout@v1.0.0
- name: Build on FreeBSD
if: ${{ matrix.distro.name == 'freebsd' }}
uses: vmactions/freebsd-vm@v1
with:
usesh: true
run: ${{ env.DESKFLOW_BUILD_CMD }}
run: |
./scripts/install_deps.sh
${{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
release:
needs: ci-passed
if: (github.ref == 'refs/heads/master') || (contains(github.ref, '/tags/v'))
runs-on: ubuntu-latest
steps:
- name: Fancy Checkout
uses: sithlord48/fancy-checkout@v1.0.0
- name: Get version
uses: ./.github/actions/get-version
- name: Download artifacts
uses: actions/download-artifact@v4
- name: Generate package checksums
id: generate_notes
shell: bash
run: |
mv $GITHUB_WORKSPACE/package-*/deskflow-* .
rm -rf $GITHUB_WORKSPACE/package-*
echo "Build: ${{env.DESKFLOW_VERSION }}" > sums.txt
sha256sum deskflow-* >> sums.txt
- name: Deploy continuous
if: (github.ref == 'refs/heads/master') && !(contains(github.ref, '/tags/v'))
uses: crowbarmaster/GH-Automatic-Releases@latest
with:
repo_token: "${{ secrets.GITHUB_TOKEN }}"
automatic_release_tag: "continuous"
prerelease: true
title: 'Continuous Build'
files: |
deskflow-*
sums.txt
- name: Deploy release
if: contains(github.ref, '/tags/v')
uses: crowbarmaster/GH-Automatic-Releases@latest
with:
repo_token: "${{ secrets.GITHUB_TOKEN }}"
prerelease: false
files: |
deskflow-*
sums.txt
winget-publish:
needs: release
if: contains(github.ref, 'tags/v')
runs-on: windows-latest
steps:
- name: Fancy Checkout
uses: sithlord48/fancy-checkout@v1.0.0
- name: Get version
uses: ./.github/actions/get-version
- name: Submit
uses: ./.github/actions/winget-publish
with:
release-version: ${{env.DESKFLOW_PACKAGE_VERSION}}
token: ${{ secrets.WINGET_DEPLOY_TOKEN }}

View File

@ -1,8 +1,25 @@
name: "CodeQL Analysis"
# According to the docs, the CodeQL workflow should be triggered directly by push to master
# and by pull requests (we only run this on open PRs as it's very slow). We also use the
# `workflow_dispatch` event is also enabled to allow manual triggering of the workflow for testing.
#
# We should not trigger this workflow with `workflow_call` as this causes the error:
# "1 configuration present on `master` was not found"
#
# Sadly, this means we can't roll it into our monolithic CI workflow.
on:
workflow_dispatch:
workflow_call:
pull_request:
types: [opened, synchronize, reopened, ready_for_review]
paths-ignore:
- '**/*.md'
- '.github/ISSUE_TEMPLATE/**'
- '.editorconfig'
- '.env-example'
- '.gitignore'
- '.gitattributes'
- 'cspell.json'
push:
branches: [master]
@ -11,8 +28,8 @@ jobs:
if: ${{ !github.event.pull_request.draft }}
name: Analyze
runs-on: ${{ vars.CODEQL_RUNNER || 'ubuntu-24.04' }}
container: deskflow/deskflow:ubuntu-24.04-amd64
runs-on: ubuntu-latest
container: debian:trixie-slim
timeout-minutes: 20
strategy:
@ -21,24 +38,18 @@ jobs:
language: ["cpp"]
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install container dependencies
run: |
apt update -qqq > /dev/null
apt install -qqq git > /dev/null
- name: Config Git safe dir
run: git config --global --add safe.directory $GITHUB_WORKSPACE
# Should only restore the .venv directory from cache.
- name: Init Python venv
uses: ./.github/actions/init-python
with:
cache-key: "codeql"
setup: false
- name: Fancy Checkout
uses: sithlord48/fancy-checkout@v1.0.0
- name: Install dependencies
run: ./scripts/install_deps.py
env:
# Prevent apt prompting for input.
DEBIAN_FRONTEND: noninteractive
uses: ./.github/actions/install-dependencies
with:
like: "debian"
- name: Initialize CodeQL
uses: github/codeql-action/init@v3

View File

@ -1,53 +0,0 @@
name: Create tag
on:
workflow_dispatch:
push:
branches:
- master
- release/**
jobs:
create-tag:
if: ${{ vars.CREATE_TAGS }}
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Checkout
uses: actions/checkout@v4
with:
# Fetch all tags
fetch-depth: 0
- name: Read version file
run: echo "CURRENT_VERSION=$(cat VERSION)" >> $GITHUB_ENV
- name: Override stage
if: ${{ !startsWith(github.ref, 'refs/heads/release') }}
run: echo "OVERRIDE_STAGE=snapshot" >> $GITHUB_ENV
- name: Get next version
id: next-version
uses: symless/actions/next-version@master
with:
current-version: ${{ env.CURRENT_VERSION }}
override-stage: ${{ env.OVERRIDE_STAGE }}
- name: Create and push Git tag
run: |
git tag ${{ steps.next-version.outputs.next-version }}
git push origin ${{ steps.next-version.outputs.next-version }}
shell: bash
- name: Trigger CI workflow
uses: actions/github-script@v7
with:
script: |
await github.rest.actions.createWorkflowDispatch({
owner: context.repo.owner,
repo: context.repo.repo,
workflow_id: 'ci.yml',
ref: '${{ steps.next-version.outputs.next-version }}'
});

View File

@ -1,31 +0,0 @@
name: "Lint Clang"
on:
workflow_dispatch:
workflow_call:
jobs:
lint-clang:
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Python venv
uses: ./.github/actions/init-python
with:
cache-key: "lint-clang"
- name: Install dependencies
run: |
source .venv/bin/activate
pip install pyyaml clang_format
- name: Linting with Clang format
id: lint-clang
uses: ./.github/actions/lint-error
with:
format-command: ./scripts/lint_clang.py -f
format-tool: "clang-format"

View File

@ -1,31 +0,0 @@
name: "Lint CMake"
on:
workflow_dispatch:
workflow_call:
jobs:
lint-cmake:
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Python venv
uses: ./.github/actions/init-python
with:
cache-key: "lint-cmake"
- name: Install dependencies
run: |
source .venv/bin/activate
pip install pyyaml cmake_format
- name: Linting with CMake formatter
id: lint-cmake
uses: ./.github/actions/lint-error
with:
format-command: ./scripts/lint_cmake.py -f
format-tool: "cmake-format"

View File

@ -6,15 +6,13 @@ on:
secrets:
SONAR_TOKEN:
required: true
push:
branches: [master]
jobs:
sonarcloud-analysis:
if: ${{ vars.SONAR_SCANNER_ENABLED }}
runs-on: ${{ vars.SONAR_SCANNER_RUNNER || 'ubuntu-24.04' }}
container: deskflow/deskflow:ubuntu-22.04-amd64
runs-on: ubuntu-latest
container: debian:trixie-slim
timeout-minutes: 20
env:
@ -24,36 +22,29 @@ jobs:
CPU_CORE_COUNT: ${{ vars.SONAR_SCANNER_CPU_COUNT || 4 }}
steps:
- name: Checkout
uses: actions/checkout@v4
with:
# Fetch all history for SonarScanner blame data
fetch-depth: 0
- name: Config Git safe dir
run: git config --global --add safe.directory $GITHUB_WORKSPACE
# Should only restore the .venv directory from cache.
- name: Init Python venv
uses: ./.github/actions/init-python
with:
cache-key: "sonarcloud"
setup: false
- name: Install dependencies
- name: Install container dependencies
run: |
./scripts/install_deps.py &&
apt install curl unzip -y &&
pip install gcovr
env:
# Prevent apt prompting for input.
DEBIAN_FRONTEND: noninteractive
apt update -qqq > /dev/null
apt install -qqq git curl unzip gcovr > /dev/null
- name: Fancy Checkout
uses: sithlord48/fancy-checkout@v1.0.0
- name: Install project dependencies
uses: ./.github/actions/install-dependencies
with:
like: "debian"
- name: Install sonar-scanner and build-wrapper
uses: sonarsource/sonarcloud-github-c-cpp@v3
- name: Configure
run: cmake -B build --preset=linux-debug -DENABLE_COVERAGE=ON
run: |
cmake -B build \
-G "Ninja" \
-DCMAKE_BUILD_TYPE="Debug" \
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON \
-DENABLE_COVERAGE=ON
- name: Build
run: |

41
.github/workflows/test-actions.yml vendored Normal file
View File

@ -0,0 +1,41 @@
name: Test actions
# Intended to only be run manually for testing actions in isolation.
on:
workflow_dispatch:
jobs:
test-summary:
runs-on: ubuntu-latest
name: Test summary (${{ matrix.message.name }})
strategy:
matrix:
message:
- name: success
text: "|Success|✅|✅|"
expect: ""
- name: failure
text: "|Failure|❌|❌|"
expect: "❌🔬 Tests failed: 2"
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Generate
shell: bash
run: |
echo "${{ matrix.message.text }}" > test-result.md
- name: Upload
uses: actions/upload-artifact@v4
with:
path: test-result.md
name: test-result-${{ matrix.message.name }}
- name: Test
uses: ./.github/actions/test-summary
with:
download-pattern: test-result-${{ matrix.message.name }}
upload-name: summary-${{ matrix.message.name }}

View File

@ -1,38 +0,0 @@
# Used only for testing the `dist-upload` action.
# Triggered using 'Run workflow' in the Actions tab.
name: Test dist upload
on:
workflow_dispatch:
jobs:
test:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Make test dist
run: |
mkdir dist
echo "test" > dist/test
- name: Upload to GitHub
if:
uses: ./.github/actions/dist-upload
with:
use-github: true
github-target-filename: "test"
- name: Upload to Google Drive
if:
uses: ./.github/actions/dist-upload
with:
use_gdrive: true
gdrive-target-base-dir: "test"
gdrive-secret-key: ${{ secrets.GOOGLE_DRIVE_KEY }}
gdrive-parent-folder-id: ${{ secrets.GOOGLE_DRIVE_TECH_DRIVE }}
package-version: 1.0.0-test

View File

@ -7,33 +7,25 @@ on:
jobs:
valgrind-analysis:
runs-on: ubuntu-latest
container: deskflow/deskflow:ubuntu-22.04-amd64
container: debian:trixie-slim
timeout-minutes: 10
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install container dependencies
run: |
apt update -qqq > /dev/null
apt install -qqq git valgrind > /dev/null
- name: Config Git safe dir
run: git config --global --add safe.directory $GITHUB_WORKSPACE
# Should only restore the .venv directory from cache.
- name: Init Python venv
uses: ./.github/actions/init-python
with:
cache-key: "valgrind"
setup: false
- name: Fancy Checkout
uses: sithlord48/fancy-checkout@v1.0.0
- name: Install dependencies
run: |
./scripts/install_deps.py &&
apt install valgrind -y
env:
# Prevent apt prompting for input.
DEBIAN_FRONTEND: noninteractive
uses: ./.github/actions/install-dependencies
with:
like: "debian"
- name: Configure
run: cmake -B build --preset=linux-release
run: cmake -B build -G "Ninja"
- name: Build
run: cmake --build build -j8

14
.gitignore vendored
View File

@ -1,3 +1,8 @@
# SPDX-FileCopyrightText: Copyright (C) 2024 Chris Rizzitello <sithlord48@gmail.com>
# SPDX-FileCopyrightText: Copyright (C) 2011 Symless Ltd.
# SPDX-FileCopyrightText: Copyright (C) 2010 Jason Axelson <BostonVaulter@gmail.com>
# SPDX-License-Identifier: MIT
# temp dirs created during build
/build
/dist
@ -20,3 +25,12 @@ deskflow-config.toml
/scripts/*.egg-info
/*.user
*.ui.autosave
#Generic linux files
**/*.directory
#CMake ignores
CMakeLists.txt.user
CMakeCache.txt
CMakeUserPresets.json
CMakeFiles/*

16
.vscode/launch.json vendored
View File

@ -15,6 +15,7 @@
"cwd": "${workspaceRoot}",
"request": "launch",
"program": "${workspaceFolder}/build/bin/unittests",
"args": [ "${input:gtest-args}" ],
"preLaunchTask": "build"
},
{
@ -23,14 +24,15 @@
"cwd": "${workspaceRoot}",
"request": "launch",
"program": "${workspaceFolder}/build/bin/integtests",
"preLaunchTask": "build"
"args": [ "${input:gtest-args}" ],
"preLaunchTask": "build",
},
{
"name": "unix - server",
"type": "lldb",
"cwd": "${workspaceRoot}",
"request": "launch",
"program": "${workspaceFolder}/build/bin/deskflows",
"program": "${workspaceFolder}/build/bin/deskflow-server",
"args": ["--config-toml", "deskflow-config.toml"],
"preLaunchTask": "kill-build"
},
@ -64,6 +66,7 @@
"cwd": "${workspaceRoot}",
"request": "launch",
"program": "${workspaceFolder}/build/bin/unittests",
"args": [ "${input:gtest-args}" ],
"internalConsoleOptions": "openOnSessionStart",
"preLaunchTask": "build"
},
@ -73,6 +76,7 @@
"cwd": "${workspaceRoot}",
"request": "launch",
"program": "${workspaceFolder}/build/bin/integtests",
"args": [ "${input:gtest-args}" ],
"internalConsoleOptions": "openOnSessionStart",
"preLaunchTask": "build"
},
@ -119,5 +123,13 @@
"program": "scripts/install_deps.py",
"console": "integratedTerminal"
}
],
"inputs": [
{
"id": "gtest-args",
"type": "promptString",
"description": "Test arguments",
"default": "--gtest_filter=*"
}
]
}

3
.vscode/tasks.json vendored
View File

@ -14,9 +14,6 @@
"problemMatcher": {
"base": "$gcc",
"fileLocation": ["absolute"]
},
"presentation": {
"revealProblems": "onProblem"
}
},
{

View File

@ -1,50 +0,0 @@
# Build Deskflow
## Developer Quick Start
Deskflow is free and open source software, and anyone is welcome to build it,
run it, tinker with it, redistribute it as part of their own app, etc.
These instructions will build Deskflow, which doesn't require a license
or serial key. Check the [Build Guide](https://github.com/deskflow/deskflow/wiki/Build-Guide)
wiki page if you have problems.
**1. Dependencies:**
*Linux, macOS, or BSD-derived:*
```
./scripts/install_deps.sh
```
*Windows:*
```
python scripts/install_deps.py
```
**2. Configure:**
*Linux, macOS, or BSD-derived:*
```
cmake -B build
```
*Windows:*
```
cmake -B build --preset=windows-release
```
**3. Build:**
```
cmake --build build -j8
```
**4. Test:**
```
./build/bin/unittests
./build/bin/integtests
```
**5. Run**
```
./build/bin/deskflow
```

View File

@ -1,7 +0,0 @@
brew 'make'
brew 'cmake'
brew 'openssl'
brew 'ninja'
brew 'googletest'
brew 'tomlplusplus'
brew 'cli11'

View File

@ -19,22 +19,75 @@
# > New in version 3.8: If the SOURCE_DATE_EPOCH environment variable is set,
# > its value will be used instead of the current time.
# > See https://reproducible-builds.org/specs/source-date-epoch/ for details.
cmake_minimum_required(VERSION 3.8)
cmake_minimum_required(VERSION 3.24)
project(deskflow C CXX)
# Fallback for when git can not be found
set(DESKFLOW_VERSION_MAJOR 1)
set(DESKFLOW_VERSION_MINOR 17)
set(DESKFLOW_VERSION_PATCH 1)
set(DESKFLOW_VERSION_TWEAK 0)
# Get the version from git if it's a git repository
# cmake-format: off
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/.git)
find_package(Git)
if(GIT_FOUND)
execute_process(
COMMAND ${GIT_EXECUTABLE} describe --long --match v* --always
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
OUTPUT_VARIABLE GITREV
ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
string(FIND ${GITREV} "v" isRev)
if(NOT ifRev EQUAL -1)
string(REGEX MATCH [0-9]+ MAJOR ${GITREV})
string(REGEX MATCH \\.[0-9]+ MINOR ${GITREV})
string(REPLACE "." "" MINOR "${MINOR}")
string(REGEX MATCH [0-9]+\- PATCH ${GITREV})
string(REPLACE "-" "" PATCH "${PATCH}")
string(REGEX MATCH \-[0-9]+\- TWEAK ${GITREV})
string(REPLACE "-" "" TWEAK "${TWEAK}")
set(DESKFLOW_VERSION_MAJOR ${MAJOR})
set(DESKFLOW_VERSION_MINOR ${MINOR})
set(DESKFLOW_VERSION_PATCH ${PATCH})
set(DESKFLOW_VERSION_TWEAK ${TWEAK})
elseif(NOT ${GITREV} STREQUAL "")
set(DESKFLOW_VERSION_TWEAK ${GITREV})
endif()
endif()
endif()
# cmake-format: on
set(DESKFLOW_VERSION
"${DESKFLOW_VERSION_MAJOR}.${DESKFLOW_VERSION_MINOR}.${DESKFLOW_VERSION_PATCH}.${DESKFLOW_VERSION_TWEAK}"
)
set(DESKFLOW_VERSION_MS_CSV
"${DESKFLOW_VERSION_MAJOR},${DESKFLOW_VERSION_MINOR},${DESKFLOW_VERSION_PATCH},${DESKFLOW_VERSION_TWEAK}"
)
add_definitions(-DDESKFLOW_VERSION="${DESKFLOW_VERSION}")
#Define our project
project(
deskflow
VERSION ${DESKFLOW_VERSION}
DESCRIPTION "Mouse and keyboard sharing utility"
LANGUAGES C CXX)
message(STATUS "Building ${CMAKE_PROJECT_NAME}-${CMAKE_PROJECT_VERSION}")
include(cmake/Version.cmake)
include(cmake/Definitions.cmake)
include(cmake/Build.cmake)
include(cmake/Libraries.cmake)
include(cmake/Packaging.cmake)
set_version()
include(GNUInstallDirs)
configure_definitions()
configure_build()
configure_libs()
configure_packaging()
add_subdirectory(doc)
add_subdirectory(src)
post_config_all()

View File

@ -1,134 +0,0 @@
{
"version": 2,
"configurePresets": [
{
"name": "base",
"hidden": true,
"binaryDir": "${sourceDir}/build",
"cacheVariables": {
"CMAKE_EXPORT_COMPILE_COMMANDS": "ON"
}
},
{
"name": "minimal",
"hidden": true,
"environment": {
"DESKFLOW_BUILD_MINIMAL": "ON"
}
},
{
"name": "windows",
"inherits": "base",
"hidden": true,
"generator": "Ninja",
"cacheVariables": {
"CMAKE_C_COMPILER": "cl.exe",
"CMAKE_CXX_COMPILER": "cl.exe"
},
"architecture": {
"value": "x64",
"strategy": "external"
},
"toolset": {
"value": "host=x64",
"strategy": "external"
}
},
{
"name": "linux",
"hidden": true,
"inherits": "base",
"generator": "Unix Makefiles"
},
{
"name": "macos",
"hidden": true,
"inherits": "base",
"generator": "Unix Makefiles"
},
{
"name": "windows-debug",
"inherits": "windows",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug"
}
},
{
"name": "windows-release",
"inherits": "windows",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release"
}
},
{
"name": "linux-debug",
"inherits": "linux",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug"
}
},
{
"name": "linux-release",
"inherits": "linux",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release"
}
},
{
"name": "macos-debug",
"inherits": "macos",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug"
}
},
{
"name": "macos-release",
"inherits": "macos",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release"
}
},
{
"name": "windows-debug-min",
"inherits": ["windows", "minimal"],
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug"
}
},
{
"name": "windows-release-min",
"inherits": ["windows", "minimal"],
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release"
}
},
{
"name": "linux-debug-min",
"inherits": ["linux", "minimal"],
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug"
}
},
{
"name": "linux-release-min",
"inherits": ["linux", "minimal"],
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release"
}
},
{
"name": "macos-debug-min",
"inherits": ["macos", "minimal"],
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug"
}
},
{
"name": "macos-release-min",
"inherits": ["macos", "minimal"],
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release"
}
}
]
}

View File

@ -1,12 +0,0 @@
# Contributing to Deskflow
Hello future community member!
Deskflow is free and open source software, and anyone is welcome to build it,
run it, tinker with it, redistribute it as part of their own app, etc.
See our wiki page on [contributing](https://github.com/deskflow/deskflow/wiki/Contributing) for more
information. We look forward to reviewing your PR!
Thanks,
The Deskflow community

View File

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- install with: choco install Chocolatey.config -y -->
<packages>
<package id="wixtoolset" />
<package id="visualstudio2022buildtools"
packageParameters="--includeRecommended --add Microsoft.VisualStudio.Workload.MSBuildTools --add Microsoft.VisualStudio.Workload.VCTools " />
</packages>

2494
Doxyfile

File diff suppressed because it is too large Load Diff

225
README.md
View File

@ -1,59 +1,55 @@
![Deskflow](https://github.com/user-attachments/assets/f005b958-24df-4f4a-9bfd-4f834dae59d6)
> [!TIP]
> We're on Libera Chat IRC network (`#deskflow` or `#deskflow-dev`).
>
> Or if you want to stay on GitHub, you can [start a new discussion](https://github.com/deskflow/deskflow/discussions).
> [!IMPORTANT]
> 🚀 Deskflow is now the upstream project for Synergy.
> [!NOTE]
> **Deskflow** is the official upstream project for [Synergy](https://symless.com/synergy).
> Purchasing a Synergy license is one way to support Deskflows growth and sustainability.
>
> The project has been renamed to draw a line between the community-run project (now Deskflow),
> and the commercially licensed product, Synergy.
> The Deskflow project was established to cultivate community-driven development where everyone can collaborate.
> Synergy sponsors the Deskflow project by contributing code and providing financial support.
>
> We are currently in the process of renaming the project to Deskflow and moving all licensing code
> downstream.
>
> Hold on to your butts, this is going to be a hell of a ride.
>
> [Join the discussion](https://github.com/deskflow/deskflow/discussions/7517)
[![Sponsored by: Synergy](https://raw.githubusercontent.com/deskflow/deskflow-artwork/b2c72a3e60a42dee793bd47efc275b5ee0bdaa5f/misc/synergy-sponsor.svg)](https://github.com/deskflow/deskflow/wiki/Relationship-with-Synergy)
[![GitHub Release](https://img.shields.io/github/v/release/deskflow/deskflow?display_name=release&label=latest%20version)](https://github.com/deskflow/deskflow/releases)
[![GitHub commit activity](https://img.shields.io/github/commit-activity/m/deskflow/deskflow)](https://github.com/deskflow/deskflow/commits/master/)
![GitHub top language](https://img.shields.io/github/languages/top/deskflow/deskflow)
[![GitHub License](https://img.shields.io/github/license/deskflow/deskflow)](LICENSE)
[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=deskflow_deskflow&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=deskflow_deskflow)
[![CI](https://github.com/deskflow/deskflow/actions/workflows/ci.yml/badge.svg)](https://github.com/deskflow/deskflow/actions/workflows/ci.yml)
[![CodeQL Analysis](https://github.com/deskflow/deskflow/actions/workflows/codeql-analysis.yml/badge.svg)](https://github.com/deskflow/deskflow/actions/workflows/codeql-analysis.yml)
[![SonarCloud Analysis](https://github.com/deskflow/deskflow/actions/workflows/sonarcloud-analysis.yml/badge.svg)](https://github.com/deskflow/deskflow/actions/workflows/sonarcloud-analysis.yml)
[![Build containers](https://github.com/deskflow/deskflow/actions/workflows/build-containers.yml/badge.svg)](https://github.com/deskflow/deskflow/actions/workflows/build-containers.yml)
> More info: [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.
**Wayland support:** Experimental support in
[Deskflow v1.16](https://github.com/deskflow/deskflow/releases/tag/1.16.0-beta%2Br2)
(required >= GNOME 46 or KDE Plasma 6.1).
[![Downloads: Stable Release](https://img.shields.io/github/downloads/deskflow/deskflow/v1.17.0/total?style=for-the-badge&logo=github&label=Download%20Stable)](https://github.com/deskflow/deskflow/releases/tag/v1.17.0)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[![Downloads: Continuous Build](https://img.shields.io/github/downloads/deskflow/deskflow/continuous/total?style=for-the-badge&logo=github&label=Download%20Continuous)](https://github.com/deskflow/deskflow/releases)
![Deskflow GUI](https://github.com/user-attachments/assets/883660dc-f3f5-4b69-8821-a079a58d3882)
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.
To use Deskflow you can follow the [Build Quick Start](#build-quick-start),
use one of our packages, or if it's available by your favorite package repository,
install `deskflow` (see: [installing packages](#how-to-install-packages)).
> [!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).
## Project values
[![GitHub commit activity](https://img.shields.io/github/commit-activity/m/deskflow/deskflow?logo=github)](https://github.com/deskflow/deskflow/commits/master/)
[![GitHub top language](https://img.shields.io/github/languages/top/deskflow/deskflow?logo=github)](https://github.com/deskflow/deskflow/commits/master/)
[![GitHub License](https://img.shields.io/github/license/deskflow/deskflow?logo=github)](LICENSE)
[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=deskflow_deskflow&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=deskflow_deskflow)
[![Coverage](https://sonarcloud.io/api/project_badges/measure?project=deskflow_deskflow&metric=coverage)](https://sonarcloud.io/summary/new_code?id=deskflow_deskflow)
[![Code Smells](https://sonarcloud.io/api/project_badges/measure?project=deskflow_deskflow&metric=code_smells)](https://sonarcloud.io/summary/new_code?id=deskflow_deskflow)
[![Vulnerabilities](https://sonarcloud.io/api/project_badges/measure?project=deskflow_deskflow&metric=vulnerabilities)](https://sonarcloud.io/summary/new_code?id=deskflow_deskflow)
[![CI](https://github.com/deskflow/deskflow/actions/workflows/ci.yml/badge.svg)](https://github.com/deskflow/deskflow/actions/workflows/ci.yml)
[![CodeQL Analysis](https://github.com/deskflow/deskflow/actions/workflows/codeql-analysis.yml/badge.svg)](https://github.com/deskflow/deskflow/actions/workflows/codeql-analysis.yml)
[![SonarCloud Analysis](https://github.com/deskflow/deskflow/actions/workflows/sonarcloud-analysis.yml/badge.svg)](https://github.com/deskflow/deskflow/actions/workflows/sonarcloud-analysis.yml)
## Project Values
- Motivated by the community interests (not business-driven)
- Privacy by default (no update check or phone home on by default)
- Nothing customer-related (this is all moved downstream to Synergy)
- 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
## Ways to get involved
> [!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
@ -61,85 +57,7 @@ Here are a few ways to join in with the project and get involved:
## Build Quick Start
> [!TIP]
> Check the [Build Guide](https://github.com/deskflow/deskflow/wiki/Build-Guide)
> wiki page if you have problems.
**1. Dependencies:**
You can either copy/paste the commands for your OS from [`config.yaml`](config.yaml) or use the deps script.
*Linux, macOS, or BSD-derived:*
```
./scripts/install_deps.sh
```
*Windows:*
```
python scripts/install_deps.py
```
**2. Configure:**
*Linux, macOS, or BSD-derived:*
```
cmake -B build
```
*Windows:*
```
cmake -B build --preset=windows-release
```
**3. Build:**
```
cmake --build build -j8
```
**4. Test:**
```
./build/bin/unittests
./build/bin/integtests
```
**5. Run**
```
./build/bin/deskflow
```
## How to install (packages)
*macOS:*
*(coming soon)*
```
brew install deskflow
```
*Fedora, Red Hat, etc:*
*(coming soon)*
```
sudo dnf install deskflow
```
*Debian, Ubuntu, etc:*
*(coming soon)*
```
sudo apt install deskflow
```
*Arch, Manjaro, etc:*
*(coming soon)*
```
sudo pacman -S deskflow
```
*Windows:*
*(coming soon)*
```
choco install deskflow
```
**Note:** We are working with package maintainers to have our new package name adopted.
For instructions on building Deskflow, use the wiki page: [Building](https://github.com/deskflow/deskflow/wiki/Building)
## Operating Systems
@ -150,9 +68,42 @@ Debian, Ubuntu, Linux Mint, Fedora, RHEL, AlmaLinux, Rocky Linux, Arch Linux, op
We officially support FreeBSD, and would also like to support: OpenBSD, NetBSD, DragonFly, Solaris.
## Repology
Repology monitors a huge number of package repositories and other sources comparing package
versions across them and gathering other information.
[![Repology](https://repology.org/badge/vertical-allrepos/deskflow.svg?exclude_unsupported=1)](https://repology.org/project/deskflow/versions)
**Note:** We are working with package maintainers to have our new package name adopted.
## Installing on macOS
When you install Deskflow on macOS, you need to allow accessibility access (Privacy & Security) to both the `Deskflow` app and the `deskflow` process.
If using Sequoia, you may also need to allow `Deskflow` under Local Network settings (Privacy & Security).
When prompted by the OS, go to the settings and enable the access.
If you are upgrading and you already have `Deskflow` or `deskflow`
on the allowed list you will need to manually remove them before accessibility access can be granted to the new version.
macOS users who download directly from releases may need to run `xattr -c /Applications/Deskflow.app` after copying the app to the `Applications` dir.
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 instal deskflow`
- Continuous: `brew install deskflow-dev`
## Collaborative Projects
In the open source developer community, similar projects collaborate for the betterment of all
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) -
@ -162,16 +113,30 @@ mouse and keyboard sharing tools. We aim for idea sharing and interoperability.
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 upstream to customer
Downstream commercial fork and Deskflow sponsor, geared toward adapting to customer
needs, offering business and enterprise licensing.
## FAQ
### Is Deskflow compatible with Lan Mouse or Input Leap?
### What is the relationship with Synergy?
We would love to see compatibility between our fellow open source projects, Lan Mouse and
Input Leap. This idea is discussed from time in the communities for all of our projects,
so it may happen in the not-too-distant future.
[![Sponsored by: Synergy](https://raw.githubusercontent.com/deskflow/deskflow-artwork/b2c72a3e60a42dee793bd47efc275b5ee0bdaa5f/misc/synergy-sponsor.svg)](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 server will also *just work*.
- To connect a Synergy client, you need to select the Synergy protocol in the Deskflow server settings.
### Is Deskflow compatible with Lan Mouse?
We would love to see compatibility with Lan Mouse. This maybe quite an effort as currently they way they handle the generated input is very different.
### If I want to solve issues in Deskflow do I need to contribute to a fork?
@ -201,12 +166,18 @@ Deskflow was first created as Synergy in 2001 by Chris Schoeneman.
Read about the [history of the project](https://github.com/deskflow/deskflow/wiki/History) on our
wiki.
## Repology
## Meow'Dib (our mascot)
Repology monitors a huge number of package repositories and other sources comparing package
versions across them and gathering other information.
![Meow'Dib](https://github.com/user-attachments/assets/726f695c-3dfb-4abd-875d-ed658f6c610f)
[![Repology](https://repology.org/badge/vertical-allrepos/deskflow.svg?exclude_unsupported=1)](https://repology.org/project/deskflow/versions)
## Deskflow Contributors
Deskflow is made by possible by these contributors.
<a href = "https://github.com/deskflow/deskflow/graphs/contributors">
<img src = "https://contrib.rocks/image?repo=deskflow/deskflow"/>
</a>
## License

View File

@ -1 +0,0 @@
1.17.0

View File

@ -1,10 +0,0 @@
format:
# Solves line ending issues on Windows.
line_ending: "auto"
# Any more than 4 args, and function calls become hard to read.
max_pargs_hwrap: 4
markup:
# Disable formatting of comments entirely, as this is annoying.
enable_markup: false

View File

@ -26,22 +26,11 @@ macro(configure_build)
set(CMAKE_OSX_DEPLOYMENT_TARGET "12.0")
endif()
warnings_as_errors()
set_build_date()
configure_file_shared()
endmacro()
macro(warnings_as_errors)
if(WIN32)
message(STATUS "Enabling warnings as errors (MSVC)")
add_compile_options(/WX)
elseif(UNIX)
message(STATUS "Enabling warnings as errors (GNU/Clang)")
add_compile_options(-Werror)
endif()
endmacro()
macro(set_build_date)
# Since CMake 3.8.0, `string(TIMESTAMP ...)` respects `SOURCE_DATE_EPOCH` env var if set,
# which allows package maintainers to create reproducible builds.

View File

@ -154,23 +154,19 @@ macro(configure_bin_names)
"deskflow-daemon"
CACHE STRING "Filename of the daemon binary")
set(LEGACY_BINARY_NAME
"deskflow-legacy"
CACHE STRING "Filename of the legacy binary")
message(VERBOSE "GUI binary: ${GUI_BINARY_NAME}")
message(VERBOSE "Server binary: ${SERVER_BINARY_NAME}")
message(VERBOSE "Client binary: ${CLIENT_BINARY_NAME}")
message(VERBOSE "Core binary: ${CORE_BINARY_NAME}")
message(VERBOSE "Daemon binary: ${DAEMON_BINARY_NAME}")
message(VERBOSE "Legacy binary: ${LEGACY_BINARY_NAME}")
add_definitions(-DGUI_BINARY_NAME="${GUI_BINARY_NAME}")
add_definitions(-DSERVER_BINARY_NAME="${SERVER_BINARY_NAME}")
add_definitions(-DCLIENT_BINARY_NAME="${CLIENT_BINARY_NAME}")
add_definitions(-DCORE_BINARY_NAME="${CORE_BINARY_NAME}")
add_definitions(-DDAEMON_BINARY_NAME="${DAEMON_BINARY_NAME}")
add_definitions(-DLEGACY_BINARY_NAME="${LEGACY_BINARY_NAME}")
endmacro()

View File

@ -23,18 +23,12 @@ macro(configure_libs)
configure_unix_libs()
elseif(WIN32)
configure_windows_libs()
find_package(Python REQUIRED QUIET)
endif()
configure_python()
configure_qt()
configure_openssl()
configure_coverage()
configure_tomlplusplus()
configure_cli11()
if(BUILD_TESTS)
configure_gtest()
endif()
endmacro()
@ -163,7 +157,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(res/config.h.in ${CMAKE_CURRENT_BINARY_DIR}/src/lib/config.h)
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)
@ -205,9 +200,6 @@ macro(configure_wayland_libs)
include(FindPkgConfig)
if(PKG_CONFIG_FOUND)
configure_libei()
configure_libportal()
pkg_check_modules(LIBXKBCOMMON REQUIRED xkbcommon)
pkg_check_modules(GLIB2 REQUIRED glib-2.0 gio-2.0)
find_library(LIBM m)
@ -219,140 +211,6 @@ macro(configure_wayland_libs)
endmacro()
macro(configure_libei)
option(SYSTEM_LIBEI "Use system libei" ON)
if(SYSTEM_LIBEI)
pkg_check_modules(LIBEI QUIET "libei-1.0 >= ${LIBEI_MIN_VERSION}")
if(LIBEI_FOUND)
message(STATUS "libei version: ${LIBEI_VERSION}")
add_definitions(-DWINAPI_LIBEI=1)
include_directories(${LIBEI_INCLUDE_DIRS})
else()
message(WARNING "libei >= ${LIBEI_MIN_VERSION} not found")
endif()
else()
set(libei_bin_dir ${PROJECT_BINARY_DIR}/meson/subprojects/libei/src)
set(libei_src_dir ${PROJECT_SOURCE_DIR}/subprojects/libei)
find_library(
LIBEI_LINK_LIBRARIES
NAMES ei
PATHS ${libei_bin_dir}
NO_DEFAULT_PATH)
if(LIBEI_LINK_LIBRARIES)
message(STATUS "Using local subproject libei")
set(LIBEI_FOUND true)
add_definitions(-DWINAPI_LIBEI=1)
set(LIBEI_INCLUDE_DIRS ${libei_src_dir}/src)
include_directories(${LIBEI_INCLUDE_DIRS})
else()
message(WARNING "Local libei not found")
endif()
endif()
endmacro()
macro(configure_libportal)
option(SYSTEM_LIBPORTAL "Use system libportal" ON)
if(SYSTEM_LIBPORTAL)
pkg_check_modules(LIBPORTAL QUIET "libportal >= ${LIBPORTAL_MIN_VERSION}")
if(LIBPORTAL_FOUND)
message(STATUS "libportal version: ${LIBPORTAL_VERSION}")
check_libportal()
else()
message(WARNING "libportal >= ${LIBPORTAL_MIN_VERSION} not found")
endif()
else()
set(libportal_bin_dir
${PROJECT_BINARY_DIR}/meson/subprojects/libportal/libportal)
set(libportal_src_dir ${PROJECT_SOURCE_DIR}/subprojects/libportal)
option(LIBPORTAL_STATIC "Use the static libportal binary" OFF)
if(LIBPORTAL_STATIC)
set(CMAKE_FIND_LIBRARY_SUFFIXES .a ${CMAKE_FIND_LIBRARY_SUFFIXES})
endif()
find_library(
LIBPORTAL_LINK_LIBRARIES
NAMES portal
PATHS ${libportal_bin_dir}
NO_DEFAULT_PATH)
if(LIBPORTAL_LINK_LIBRARIES)
message(STATUS "Using local subproject libportal")
set(LIBPORTAL_FOUND true)
set(LIBPORTAL_INCLUDE_DIRS ${libportal_src_dir})
message(STATUS "libportal library file: ${LIBPORTAL_LINK_LIBRARIES}")
# HACK: Somehow `check_symbol_exists` doesn't pick up on the symbols even though
# they are actually there. Since we use master branch of libportal, for now we'll
# assume that the symbols are there.
set(HAVE_LIBPORTAL_SESSION_CONNECT_TO_EIS true)
set(HAVE_LIBPORTAL_CREATE_REMOTE_DESKTOP_SESSION_FULL true)
set(HAVE_LIBPORTAL_INPUTCAPTURE true)
set(HAVE_LIBPORTAL_OUTPUT_NONE true)
else()
message(WARNING "Local libportal not found")
endif()
endif()
if(LIBPORTAL_FOUND)
add_definitions(-DWINAPI_LIBPORTAL=1)
include_directories(${LIBPORTAL_INCLUDE_DIRS})
endif()
endmacro()
# libportal 0.7 has xdp_session_connect_to_eis but it doesn't have remote desktop session restore or
# the inputcapture code, so let's check for explicit functions that bits depending on what we have
macro(check_libportal)
include(CMakePushCheckState)
include(CheckCXXSourceCompiles)
cmake_push_check_state(RESET)
set(CMAKE_REQUIRED_INCLUDES
"${CMAKE_REQUIRED_INCLUDES};${LIBPORTAL_INCLUDE_DIRS};${GLIB2_INCLUDE_DIRS}"
)
set(CMAKE_REQUIRED_LIBRARIES
"${CMAKE_REQUIRED_LIBRARIES};${LIBPORTAL_LINK_LIBRARIES};${GLIB2_LINK_LIBRARIES}"
)
check_symbol_exists(xdp_session_connect_to_eis "libportal/portal.h"
HAVE_LIBPORTAL_SESSION_CONNECT_TO_EIS)
check_symbol_exists(
xdp_portal_create_remote_desktop_session_full "libportal/portal.h"
HAVE_LIBPORTAL_CREATE_REMOTE_DESKTOP_SESSION_FULL)
check_symbol_exists(xdp_input_capture_session_connect_to_eis
"libportal/inputcapture.h" HAVE_LIBPORTAL_INPUTCAPTURE)
# check_symbol_exists cant check for enum values
check_cxx_source_compiles(
"#include <libportal/portal.h>
int main() { XdpOutputType out = XDP_OUTPUT_NONE; }
" HAVE_LIBPORTAL_OUTPUT_NONE)
cmake_pop_check_state()
if(NOT HAVE_LIBPORTAL_SESSION_CONNECT_TO_EIS)
message(WARNING "xdp_session_connect_to_eis not found")
endif()
if(NOT HAVE_LIBPORTAL_CREATE_REMOTE_DESKTOP_SESSION_FULL)
message(WARNING "xdp_portal_create_remote_desktop_session_full not found")
endif()
if(NOT HAVE_LIBPORTAL_INPUTCAPTURE)
message(WARNING "xdp_input_capture_session_connect_to_eis not found")
endif()
if(NOT HAVE_LIBPORTAL_OUTPUT_NONE)
message(WARNING "XDP_OUTPUT_NONE not found")
endif()
endmacro()
#
# X.org/X11 for Linux, BSD, etc
#
@ -460,8 +318,6 @@ endmacro()
#
macro(configure_windows_libs)
configure_wintoast()
set(CMAKE_CXX_FLAGS
"${CMAKE_CXX_FLAGS} /MP /D _BIND_TO_CURRENT_VCLIBS_VERSION=1")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MD /O2 /Ob2")
@ -485,36 +341,10 @@ macro(configure_windows_libs)
configure_file(${PROJECT_SOURCE_DIR}/res/win/version.rc.in
${PROJECT_BINARY_DIR}/src/version.rc @ONLY)
configure_windows_openssl()
configure_openssl()
endmacro()
macro(configure_windows_openssl)
set(OPENSSL_ROOT_DIR ${PROJECT_SOURCE_DIR}/vcpkg_installed/x64-windows)
set(OPENSSL_EXE_DIR ${OPENSSL_ROOT_DIR}/tools/openssl)
if(EXISTS ${OPENSSL_EXE_DIR})
message(VERBOSE "OpenSSL exe dir: ${OPENSSL_EXE_DIR}")
add_definitions(-DOPENSSL_EXE_DIR="${OPENSSL_EXE_DIR}")
else()
message(FATAL_ERROR "OpenSSL exe dir not found: ${OPENSSL_EXE_DIR}")
endif()
if(EXISTS ${OPENSSL_ROOT_DIR})
message(VERBOSE "OpenSSL root dir: ${OPENSSL_ROOT_DIR}")
else()
message(FATAL_ERROR "OpenSSL root dir not found: ${OPENSSL_ROOT_DIR}")
endif()
endmacro()
macro(configure_python)
if(WIN32)
find_package(Python REQUIRED QUIET)
else()
find_package(Python3 REQUIRED QUIET)
endif()
endmacro()
macro(configure_qt)
find_package(
@ -538,65 +368,12 @@ macro(configure_openssl)
set(OPENSSL_USE_STATIC_LIBS TRUE)
endif()
find_package(OpenSSL REQUIRED)
include_directories(${OPENSSL_INCLUDE_DIR})
endmacro()
macro(configure_gtest)
file(GLOB gtest_base_dir ${PROJECT_SOURCE_DIR}/subprojects/googletest-*)
if(gtest_base_dir)
set(DEFAULT_SYSTEM_GTEST OFF)
else()
set(DEFAULT_SYSTEM_GTEST ON)
endif()
# Arch Linux package maintainers:
# We do care about not bundling libs and didn't mean to cause upset. We made some mistakes
# and we're trying to put that right.
# The comment "They BUNDLE a fucking zip for cryptopp" in deskflow.git/PKGBUILD is only
# relevant to a very version of old the code, so the comment should probably be removed.
# If there are any problems like this in future, please do feel free send us a patch! :)
option(SYSTEM_GTEST "Use system GoogleTest" ${DEFAULT_SYSTEM_GTEST})
if(SYSTEM_GTEST)
message(VERBOSE "Using system GoogleTest")
find_package(GTest)
if(GTEST_FOUND)
# Ordinarily, we'd use GTEST_LIBRARIES, but it seems that these do not always export
# the required libraries (e.g. gmock) on some OS (e.g macOS with brew).
set(GTEST_LIB GTest::gtest)
set(GMOCK_LIB GTest::gmock)
else()
message(
FATAL_ERROR
"Google Test not found, re-configure with -DBUILD_TESTS=OFF or -DSYSTEM_GTEST=OFF"
)
endif()
else()
if(NOT EXISTS ${gtest_base_dir})
message(
FATAL_ERROR
"Google Test subproject not found, reconfigure with -DBUILD_TESTS=OFF"
)
endif()
message(VERBOSE "Using local GoogleTest")
set(gtest_dir ${gtest_base_dir}/googletest)
set(gmock_dir ${gtest_base_dir}/googlemock)
include_directories(${gtest_dir} ${gmock_dir} ${gtest_dir}/include
${gmock_dir}/include)
add_library(gtest STATIC ${gtest_dir}/src/gtest-all.cc)
add_library(gmock STATIC ${gmock_dir}/src/gmock-all.cc)
if(UNIX)
# Ignore noisy GoogleTest warnings
set_target_properties(gtest PROPERTIES COMPILE_FLAGS "-w")
set_target_properties(gmock PROPERTIES COMPILE_FLAGS "-w")
endif()
set(GTEST_LIB gtest)
set(GMOCK_LIB gmock)
find_package(OpenSSL 3.0 REQUIRED COMPONENTS SSL Crypto)
if(WIN32) #Used for dev in TLS and WIX
cmake_path(SET OPENSSL_ROOT_DIR NORMALIZE "${OPENSSL_INCLUDE_DIR}/..")
message(VERBOSE "Set OPENSSL_ROOT_DIR: ${OPENSSL_ROOT_DIR}")
set(OPENSSL_EXE_DIR "${OPENSSL_ROOT_DIR}/tools/openssl")
add_definitions(-DOPENSSL_EXE_DIR="${OPENSSL_EXE_DIR}")
endif()
endmacro()
@ -639,80 +416,3 @@ macro(configure_coverage)
message(STATUS "Code coverage is disabled")
endif()
endmacro()
macro(configure_wintoast)
# WinToast is a pretty niche library, and there doesn't seem to be an installable package,
# so we rely on building from source.
file(GLOB WINTOAST_DIR ${PROJECT_SOURCE_DIR}/subprojects/WinToast-*)
if(WINTOAST_DIR)
set(HAVE_WINTOAST true)
add_definitions(-DHAVE_WINTOAST=1)
include_directories(${WINTOAST_DIR}/include)
else()
message(WARNING "Subproject 'WinToast' not found")
endif()
endmacro()
macro(configure_tomlplusplus)
file(GLOB tomlplusplus_dir ${PROJECT_SOURCE_DIR}/subprojects/tomlplusplus-*)
if(tomlplusplus_dir)
set(DEFAULT_SYSTEM_TOMLPLUSPLUS OFF)
else()
set(DEFAULT_SYSTEM_TOMLPLUSPLUS ON)
endif()
option(SYSTEM_TOMLPLUSPLUS "Use system tomlplusplus"
${DEFAULT_SYSTEM_TOMLPLUSPLUS})
if(SYSTEM_TOMLPLUSPLUS)
message(VERBOSE "Using system tomlplusplus")
find_package(tomlplusplus)
if(tomlplusplus_FOUND)
message(STATUS "tomlplusplus version: ${tomlplusplus_VERSION}")
else()
message(WARNING "System tomlplusplus not found")
endif()
else()
if(EXISTS ${tomlplusplus_dir})
message(VERBOSE "Using local tomlplusplus")
set(HAVE_TOMLPLUSPLUS true)
add_definitions(-DHAVE_TOMLPLUSPLUS=1)
include_directories(${tomlplusplus_dir}/include)
else()
message(WARNING "Local tomlplusplus subproject not found")
endif()
endif()
endmacro()
macro(configure_cli11)
file(GLOB cli11_dir ${PROJECT_SOURCE_DIR}/subprojects/CLI11-*)
if(cli11_dir)
set(DEFAULT_SYSTEM_CLI11 OFF)
else()
set(DEFAULT_SYSTEM_CLI11 ON)
endif()
option(SYSTEM_CLI11 "Use system CLI11" ${DEFAULT_SYSTEM_CLI11})
if(SYSTEM_CLI11)
message(VERBOSE "Using system CLI11")
find_package(CLI11)
if(CLI11_FOUND)
message(STATUS "CLI11 version: ${CLI11_VERSION}")
else()
message(WARNING "System CLI11 not found")
endif()
else()
if(EXISTS ${cli11_dir})
message(VERBOSE "Using local CLI11")
set(HAVE_CLI11 true)
add_definitions(-DHAVE_CLI11=1)
include_directories(${cli11_dir}/include)
else()
message(WARNING "Local CLI11 subproject not found at: ${cli11_dir}")
endif()
endif()
endmacro()

View File

@ -1,33 +1,31 @@
# Deskflow -- mouse and keyboard sharing utility
# Copyright (C) 2012-2024 Symless Ltd.
# Copyright (C) 2009-2012 Nick Bolton
#
# This package is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# found in the file LICENSE that should have accompanied this file.
#
# This package is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# SPDX-FileCopyrightText: (C) 2024 Chris Rizzitello <sithlord48@gmail.com>
# SPDX-FileCopyrightText: (C) 2012 - 2024 Symless Ltd.
# SPDX-FileCopyrightText: (C) 2009 - 2012 Nick Bolton
# SPDX-License-Identifier: MIT
#
# If enabled, configure packaging based on OS.
#
macro(configure_packaging)
message(VERBOSE "Configuring Packaging")
set(DESKFLOW_PROJECT_RES_DIR ${PROJECT_SOURCE_DIR}/res)
if(${BUILD_INSTALLER})
set(CPACK_PACKAGE_NAME ${DESKFLOW_APP_ID})
set(CPACK_PACKAGE_CONTACT ${DESKFLOW_MAINTAINER})
set(CPACK_PACKAGE_DESCRIPTION "Mouse and keyboard sharing utility")
set(CPACK_PACKAGE_DESCRIPTION ${CMAKE_PROJECT_DESCRIPTION})
set(CPACK_PACKAGE_VENDOR ${DESKFLOW_AUTHOR_NAME})
set(CPACK_RESOURCE_FILE_LICENSE ${PROJECT_SOURCE_DIR}/LICENSE)
set(CPACK_PACKAGE_VERSION ${CMAKE_PROJECT_VERSION})
#Prevent this override from being written in the package
if(NOT PACKAGE_VERSION_LABEL)
set (PACKAGE_VERSION_LABEL "${CPACK_PACKAGE_VERSION}")
endif()
if(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
configure_windows_packaging()
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
@ -36,8 +34,12 @@ macro(configure_packaging)
configure_linux_packaging()
elseif(${CMAKE_SYSTEM_NAME} MATCHES "|.*BSD")
message(STATUS "BSD packaging not yet supported")
set(OS_STRING ${CMAKE_SYSTEM_NAME}-${CMAKE_SYSTEM_PROCESSOR})
endif()
set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${PACKAGE_VERSION_LABEL}-${OS_STRING}")
message(STATUS "Package Basename: ${CPACK_PACKAGE_FILE_NAME}")
include(CPack)
else()
message(STATUS "Not configuring installer")
@ -50,10 +52,7 @@ endmacro()
#
macro(configure_windows_packaging)
message(VERBOSE "Configuring Windows installer")
set(CPACK_PACKAGE_VERSION ${DESKFLOW_VERSION_MS})
set(QT_PATH $ENV{CMAKE_PREFIX_PATH})
cmake_path(SET QT_PATH NORMALIZE "${Qt6_DIR}../../")
set(DESKFLOW_MSI_64_GUID
"027D1C8A-E7A5-4754-BB93-B2D45BFDBDC8"
@ -66,6 +65,14 @@ macro(configure_windows_packaging)
configure_files(${PROJECT_SOURCE_DIR}/res/dist/wix
${PROJECT_BINARY_DIR}/installer)
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()
endmacro()
#
@ -73,10 +80,6 @@ endmacro()
#
macro(configure_mac_packaging)
message(VERBOSE "Configuring macOS app bundle")
set(CPACK_PACKAGE_VERSION ${DESKFLOW_VERSION})
set(CMAKE_INSTALL_RPATH
"@loader_path/../Libraries;@loader_path/../Frameworks")
set(DESKFLOW_BUNDLE_SOURCE_DIR
@ -87,6 +90,8 @@ macro(configure_mac_packaging)
configure_files(${DESKFLOW_BUNDLE_SOURCE_DIR} ${DESKFLOW_BUNDLE_DIR})
set(OS_STRING "macos-${CMAKE_SYSTEM_PROCESSOR}")
file(RENAME ${DESKFLOW_BUNDLE_DIR}/Contents/Resources/App.icns
${DESKFLOW_BUNDLE_DIR}/Contents/Resources/${DESKFLOW_APP_NAME}.icns)
@ -95,12 +100,81 @@ endmacro()
#
# Linux packages
#
macro(configure_linux_package_name)
# Get Distro name information
execute_process(
COMMAND bash "-c" "cat /etc/os-release | grep ^ID= | sed 's/ID=//g'"
OUTPUT_VARIABLE _DISTRO_NAME
OUTPUT_STRIP_TRAILING_WHITESPACE)
string(REPLACE "\"" "" DISTRO_NAME "${_DISTRO_NAME}")
message(STATUS "Distro Name: ${DISTRO_NAME}")
execute_process(
COMMAND bash "-c"
"cat /etc/os-release | grep ^ID_LIKE= | sed 's/ID_LIKE=//g'"
OUTPUT_VARIABLE _DISTRO_LIKE
OUTPUT_STRIP_TRAILING_WHITESPACE)
string(REPLACE "\"" "" DISTRO_LIKE "${_DISTRO_LIKE}")
message(STATUS "Distro Like: ${DISTRO_LIKE}")
execute_process(
COMMAND
bash "-c"
"cat /etc/os-release | grep ^VERSION_CODENAME= | sed 's/VERSION_CODENAME=//g'"
OUTPUT_VARIABLE _DISTRO_CODENAME
OUTPUT_STRIP_TRAILING_WHITESPACE)
string(REPLACE "\"" "" DISTRO_CODENAME "${_DISTRO_CODENAME}")
message(STATUS "Distro Codename: ${DISTRO_CODENAME}")
execute_process(
COMMAND bash "-c"
"cat /etc/os-release | grep ^VERSION_ID= | sed 's/VERSION_ID=//g'"
OUTPUT_VARIABLE _DISTRO_VERSION_ID
OUTPUT_STRIP_TRAILING_WHITESPACE)
string(REPLACE "\"" "" DISTRO_VERSION_ID "${_DISTRO_VERSION_ID}")
message(STATUS "Distro ID: ${DISTRO_VERSION_ID}")
# Check if Debian-link
string(REGEX MATCH debian|buntu DEBTYPE "${DISTRO_LIKE}")
if((NOT ("${DEBTYPE}" STREQUAL "")) OR ("${DISTRO_NAME}" STREQUAL "debian"))
set(CPACK_GENERATOR "DEB")
endif()
# Check if Rpm-like
string(REGEX MATCH suse|fedora|rhel RPMTYPE "${DISTRO_LIKE}")
string(REGEX MATCH fedora|suse|rhel RPMNAME "${DISTRO_NAME}")
if((NOT ("${RPMTYPE}" STREQUAL "")) OR (NOT ("${RPMNAME}" STREQUAL "")))
set(CPACK_GENERATOR "RPM")
endif()
# Disto specific name adjustments
if("${DISTRO_NAME}" STREQUAL "opensuse-tumbleweed")
set(DISTRO_NAME "opensuse")
set(DISTRO_CODENAME "tumbleweed")
elseif("${DISTRO_NAME}" STREQUAL "arch")
# Arch linux is rolling the version id reported is the date of last iso.
set(DISTRO_VERSION_ID "")
endif()
# Determain the code name to be used if any
if(NOT "${DISTRO_VERSION_ID}" STREQUAL "")
set(CN_STRING "${DISTRO_VERSION_ID}-")
endif()
if(NOT "${DISTRO_CODENAME}" STREQUAL "")
set(CN_STRING "${DISTRO_CODENAME}-")
endif()
set(OS_STRING "${DISTRO_NAME}-${CN_STRING}${CMAKE_SYSTEM_PROCESSOR}")
endmacro()
macro(configure_linux_packaging)
message(VERBOSE "Configuring Linux packaging")
set(CPACK_PACKAGE_VERSION ${DESKFLOW_VERSION_LINUX})
set(CPACK_GENERATOR "DEB;RPM;TGZ")
# Gather distro info
# This is used in package names
configure_linux_package_name()
set(CPACK_DEBIAN_PACKAGE_MAINTAINER ${DESKFLOW_MAINTAINER})
set(CPACK_DEBIAN_PACKAGE_SECTION "utils")
@ -114,13 +188,6 @@ macro(configure_linux_packaging)
# 12), so we must add it manually.
set(CPACK_DEBIAN_PACKAGE_DEPENDS "qt6-qpa-plugins")
# The default for CMake seems to be /usr/local, which seems uncommon. While
# the default /usr/local prefix causes the app to appear on Debian and Fedora,
# it doesn't seem to appear on Arch Linux. Setting the prefix to /usr seems to
# work on a wider variety of distros, and that also seems to be where most
# apps install to.
set(CMAKE_INSTALL_PREFIX /usr)
set(source_desktop_file ${DESKFLOW_PROJECT_RES_DIR}/dist/linux/app.desktop.in)
set(configured_desktop_file ${PROJECT_BINARY_DIR}/app.desktop)
set(install_desktop_file ${DESKFLOW_APP_ID}.desktop)
@ -184,3 +251,9 @@ macro(configure_files srcDir destDir)
endforeach(templateFile)
endmacro(configure_files)
macro(check_is_rpm)
# Check if RPM-like.
endmacro()

View File

@ -1,94 +0,0 @@
# Deskflow -- mouse and keyboard sharing utility
# Copyright (C) 2012-2024 Symless Ltd.
# Copyright (C) 2009-2012 Nick Bolton
#
# This package is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# found in the file LICENSE that should have accompanied this file.
#
# This package is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# Either get the version number from the environment or from the VERSION file.
# On Windows, we also set a special 4-digit MSI version number.
macro(set_version)
set(DESKFLOW_VERSION $ENV{DESKFLOW_VERSION})
string(STRIP "${DESKFLOW_VERSION}" DESKFLOW_VERSION)
if(NOT DESKFLOW_VERSION)
file(READ "${PROJECT_SOURCE_DIR}/VERSION" DESKFLOW_VERSION)
string(STRIP "${DESKFLOW_VERSION}" DESKFLOW_VERSION)
endif()
message(STATUS "Version number (semver): " ${DESKFLOW_VERSION})
add_definitions(-DDESKFLOW_VERSION="${DESKFLOW_VERSION}")
# Useful for copyright (e.g. in macOS bundle .plist.in and Windows version .rc
# file)
string(TIMESTAMP DESKFLOW_BUILD_YEAR "%Y")
if(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
set_windows_version()
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
set_linux_version()
endif()
endmacro()
macro(set_four_part_version)
string(REGEX MATCH "^([0-9]+)\\.([0-9]+)\\.([0-9]+)" _ "${DESKFLOW_VERSION}")
set(VERSION_MAJOR "${CMAKE_MATCH_1}")
set(VERSION_MINOR "${CMAKE_MATCH_2}")
set(VERSION_PATCH "${CMAKE_MATCH_3}")
# Find the revision number, which is the number after the 'r'.
string(REGEX MATCH "r([0-9]+)$" _ "${DESKFLOW_VERSION}")
set(VERSION_REVISION "${CMAKE_MATCH_1}")
if(NOT VERSION_REVISION)
set(VERSION_REVISION "0")
endif()
set(DESKFLOW_VERSION_FOUR_PART
"${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}.${VERSION_REVISION}")
endmacro()
# MSI requires a 4-digit number and doesn't accept semver.
macro(set_windows_version)
set_four_part_version()
# Dot-separated version number for MSI and Windows version .rc file.
set(DESKFLOW_VERSION_MS ${DESKFLOW_VERSION_FOUR_PART})
message(VERBOSE "Version number for (Microsoft 4-part): "
${DESKFLOW_VERSION_MS})
# CSV version number for Windows version .rc file.
set(DESKFLOW_VERSION_MS_CSV
"${VERSION_MAJOR},${VERSION_MINOR},${VERSION_PATCH},${VERSION_REVISION}")
message(VERBOSE "Version number for (Microsoft CSV): "
${DESKFLOW_VERSION_MS_CSV})
endmacro()
macro(set_linux_version)
# Replace the first occurrence of '-' with '~' for Linux versioning; the '-'
# char is reserved for use at at the end of the version string to indicate a
# package revision. Debian has always used this convention, but support for
# this was also introduced in RPM 4.10.0.
string(REGEX REPLACE "-" "~" DESKFLOW_VERSION_LINUX "${DESKFLOW_VERSION}")
message(STATUS "Version number (DEB/RPM): ${DESKFLOW_VERSION_LINUX}")
# Arch does not support SemVer or DEB/RPM version format, so use the four-part
# version format which funnily enough is what Microsoft requires for MSI.
set_four_part_version()
message(STATUS "Version number (4-part): ${DESKFLOW_VERSION_FOUR_PART}")
endmacro()

View File

@ -1,205 +0,0 @@
config:
windows:
dependencies:
# We only run `choco` when not in CI env because it's pretty unreliable and slow.
# The Chocolatey mirror cannot be 100% reliable (according to docs) so it will often fail
# with an error `503 (Service Unavailable: Back-end server is at capacity)` which causes
# the nightly CI to fail intermittently.
command-elevated: if not defined CI (choco install Chocolatey.config -y)
# We only run `winget` when not in CI env; it's not available on the GitHub Windows runner.
# It's simpler to solve dependencies like Ninja with a GitHub workflow action, and cmake is
# already installed on the Windows runner.
command: if not defined CI (winget install ninja-build.ninja cmake)
qt:
version: 6.7.2
mirror: https://qt.mirror.constant.com/
base-dir: ./deps/qt
mac:
dependencies:
command: brew bundle --file=Brewfile
qt:
version: 6.7.2
mirror: https://qt.mirror.constant.com/
base-dir: ./deps/qt
linux:
debian: &debian
dependencies:
command-pre: sudo apt-get update
command: |
sudo apt-get install -y \
cmake \
make \
ninja-build \
g++ \
file \
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
optional: [libei-dev, libportal-dev, libtomlplusplus-dev]
linuxmint:
<<: *debian
ubuntu:
<<: *debian
fedora: &fedora
dependencies: &fedora_deps
command-pre: sudo dnf check-update
command: |
sudo 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 \
libei-devel \
libportal-devel \
tomlplusplus-devel \
cli11-devel
optional: [libei-devel, libportal-devel]
# RHEL is not actually supported yet, since it doesn't have Qt6 libs.
# We simply use it as a base for Alma Linux and Rocky Linux.
rhel: &rhel
<<: *fedora
dependencies: &rhel_deps
<<: *fedora_deps
command-pre: |
sudo dnf check-update;
sudo dnf install -y epel-release;
dnf config-manager --set-enabled crb
rocky:
<<: *rhel
dependencies:
<<: *rhel_deps
almalinux:
<<: *rhel
dependencies:
<<: *rhel_deps
opensuse-tumbleweed: &opensuse-tumbleweed
dependencies:
command-pre: sudo zypper refresh
command: sudo 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
arch: &arch
dependencies:
command: sudo 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
manjaro:
<<: *arch
subprojects:
libei:
dependencies:
debian: &debian_libei |
sudo apt-get install -y \
python3-attr \
python3-jinja2 \
libsystemd-dev &&
pip install attrs jinja2
ubuntu: *debian_libei
linuxmint: *debian_libei
fedora: &fedora_libei |
sudo dnf install -y \
python3-attrs \
python3-jinja2 \
systemd-devel &&
pip install attrs jinja2
rhel: *fedora_libei
rocky: *fedora_libei
almalinux: *fedora_libei
libportal:
dependencies:
debian: &debian_libportal |
sudo apt-get install -y \
python3-dbusmock \
python3-pytest \
valac \
protobuf-c-compiler \
protobuf-compiler \
libglib2.0 \
libgtk-3-dev \
libprotobuf-c-dev \
libsystemd-dev \
libgirepository1.0-dev
ubuntu: *debian_libportal
linuxmint: *debian_libportal

View File

@ -7,13 +7,14 @@
"aqtinstall",
"Axelson",
"Breen",
"cmakelang",
"codesign",
"codesigning",
"Compat",
"contribs",
"Daun",
"Devs",
"Deskflow",
"distro",
"distros",
"dmgbuild",
"dotenv",
@ -31,6 +32,7 @@
"Kanapickas",
"keychain",
"Keychains",
"Kitware",
"Kutytska",
"Lanz",
"libei",
@ -49,18 +51,22 @@
"pacman",
"Petroules",
"Pixmap",
"Pointee",
"Poschta",
"Povilas",
"Priddy",
"psutil",
"pyproject",
"qputenv",
"readf",
"Regen",
"Repology",
"Rizzitello",
"runas",
"Sbârnea",
"Schoeneman",
"Serhii",
"shemp",
"Sorin",
"subproject",
"subprojects",
@ -68,12 +74,14 @@
"Trixie",
"unittests",
"Valgrind",
"vbuffer",
"vcpkg",
"venv",
"vmactions",
"Volker",
"whot",
"winget",
"writef",
"XWINDOWS"
],
"ignoreWords": [],

31
doc/CMakeLists.txt Normal file
View File

@ -0,0 +1,31 @@
# SPDX-FileCopyrightText: 2019 - 2024 Chris Rizzitello <sithlord48@gmail.com>
# SPDX-License-Identifier: MIT
find_package(Doxygen QUIET)
option(BUILD_DOCS "Build and install documents" ${DOXYGEN_FOUND})
if (BUILD_DOCS AND DOXYGEN_FOUND)
set(DOXYGEN_EXTRACT_ALL YES)
set(DOXYGEN_STRIP_FROM_PATH ${CMAKE_SOURCE_DIR})
set(DOXYGEN_USE_MDFILE_AS_MAINPAGE mainpage.md)
set(DOXYGEN_QUIET YES)
# Files used to make our documents
# User facing documents will not include doxy comments in source code
doxygen_add_docs(user-docs ${CMAKE_SOURCE_DIR}/doc COMMENT "Generating user documentation" ALL)
# HACK Only these will show in your IDE
target_sources(user-docs PRIVATE
mainpage.md
configuration.md
)
install(
DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/html"
DESTINATION ${CMAKE_INSTALL_DOCDIR}
COMPONENT deskflow_docs)
else()
message(STATUS "Doxygen not found, skipping docs build")
endif()

168
doc/configuration.md Normal file
View File

@ -0,0 +1,168 @@
# Server Config Examples
The `deskflow-server` command accepts the `-c` or `--config` option, which takes one argument,
the path to a server configuration file. The format is non-standard but similar to YAML.
Comments begin with the `#` character and continue to the end of line.
Comments may appear anywhere the syntax permits.
Each `section` element must have a matching `end` element.
## Stacked Example
Stack one computer's screen on top of another's.
```
# +-------+
# | curly |
# | |
# +-------+
# +-------+ +-------+
# | moe | | larry |
# | | | |
# +-------+ +-------+
section: screens
# three hosts named: moe, larry, and curly
moe:
larry:
curly:
end
section: links
# larry is to the right of moe and curly is above moe.
moe:
right = larry
up = curly
# moe is to the left of larry and curly is above larry.
larry:
left = moe
up = curly
# larry is below curly.
curly:
down = larry
end
section: aliases
# curly is also known as shemp
curly:
shemp
end
```
## Horizontal Example
Align all screens horizontally.
```
# +-------+ +-------+ +-------+
# | moe | | larry | | curly |
# | | | | | |
# +-------+ +-------+ +-------+
section: screens
# three hosts named: moe, larry, and curly
moe:
larry:
curly:
end
section: links
# curly is to the right of larry and moe is to the left of larry.
larry:
right = curly
left = moe
# larry is to the right of moe.
moe:
right = larry
# larry is to the left of curly.
curly:
left = larry
end
```
## Span Example
Span two screens on one computer across the screens of two computers.
```
# +-------+ +-------+
# | curly | | curly |
# | | | |
# +-------+ +-------+
# +-------+ +-------+
# | moe | | larry |
# | | | |
# +-------+ +-------+
section: screens
# three hosts named: moe, larry, and curly
moe:
larry:
curly:
end
section: links
# larry is to the right of moe and curly is above moe.
moe:
right = larry
up = curly
# moe is to the left of larry and curly is above larry.
larry:
left = moe
up = curly
# larry is below curly.
curly:
down = larry
end
```
# Example file for `--config-toml` arg
```
[server.args]
no-daemon = true
no-tray = true
debug = "DEBUG"
name = "moe"
address = ":24800"
[client.args]
no-daemon = true
no-tray = true
debug = "DEBUG2"
name = "larry"
_last = "moe:24800"
```
# Example `.env` file
```
#
# App
#
# Shows the test menu in the GUI (on by default in debug mode)
# DESKFLOW_TEST_MENU=true
# Version checker URL to use (useful for testing)
# DESKFLOW_VERSION_URL="https://api.deskflow.org/version?fake=1.100.0"
# Enable debug logging in the GUI (on by default in debug mode)
# DESKFLOW_GUI_DEBUG=true
# Enable verbose logging in the GUI (always off by default)
# DESKFLOW_GUI_VERBOSE=true
# Reset all settings and delete all data on startup
# DESKFLOW_RESET_ALL=true
```

View File

@ -1,37 +0,0 @@
# sample deskflow configuration file
#
# comments begin with the # character and continue to the end of
# line. comments may appear anywhere the syntax permits.
section: screens
# three hosts named: moe, larry, and curly
moe:
larry:
curly:
end
section: links
# larry is to the right of moe and curly is above moe
moe:
right = larry
up = curly
# moe is to the left of larry and curly is above larry.
# note that curly is above both moe and larry and moe
# and larry have a symmetric connection (they're in
# opposite directions of each other).
larry:
left = moe
up = curly
# larry is below curly. if you move up from moe and then
# down, you'll end up on larry.
curly:
down = larry
end
section: aliases
# curly is also known as shemp
curly:
shemp
end

View File

@ -1,55 +0,0 @@
# sample deskflow configuration file
#
# comments begin with the # character and continue to the end of
# line. comments may appear anywhere the syntax permits.
# This example uses 3 computers. A laptop and two desktops (one a mac)
# They are arranged in the following configuration with Desktop1 acting as the server
# Desktop 2 has 3 screens arranged around desktop1
#
# +--------+ +---------+
# |Desktop2| |Desktop2 |
# | | | |
# +--------+ +---------+
# +-------+ +--------+ +---------+
# |Laptop | |Desktop1| |Desktop2 |
# | | | | | |
# +-------+ +--------+ +---------+
#
# The laptop comes and goes but that doesn't really affect this configuration
# The screens section is for the logical or short name of the computers
section: screens
# three computers that are logically named: desktop1, desktop2, and laptop
desktop1:
desktop2:
laptop:
end
section: links
# larry is to the right of moe and curly is above moe
moe:
right = larry
up = curly
# moe is to the left of larry and curly is above larry.
# note that curly is above both moe and larry and moe
# and larry have a symmetric connection (they're in
# opposite directions of each other).
larry:
left = moe
up = curly
# larry is below curly. if you move up from moe and then
# down, you'll end up on larry.
curly:
down = larry
end
# The aliases section is to map the full names of the computers to their logical names used in the screens section
# One way to find the actual name of a comptuer is to run hostname from a command window
section: aliases
# Laptop is actually known as John-Smiths-MacBook-3.local
desktop2:
John-Smiths-MacBook-3.local
end

View File

@ -1,39 +0,0 @@
# sample deskflow configuration file
#
# comments begin with the # character and continue to the end of
# line. comments may appear anywhere the syntax permits.
# +-------+ +--------+ +---------+
# |Laptop | |Desktop1| |iMac |
# | | | | | |
# +-------+ +--------+ +---------+
section: screens
# three hosts named: Laptop, Desktop1, and iMac
# These are the nice names of the hosts to make it easy to write the config file
# The aliases section below contain the "actual" names of the hosts (their hostnames)
Laptop:
Desktop1:
iMac:
end
section: links
# iMac is to the right of Desktop1
# Laptop is to the left of Desktop1
Desktop1:
right = iMac
left = Laptop
# Desktop1 is to the right of Laptop
Laptop:
right = Desktop1
# Desktop1 is to the left of iMac
iMac:
left = Desktop1
end
section: aliases
# The "real" name of iMac is John-Smiths-iMac-3.local. If we wanted we could remove this alias and instead use John-Smiths-iMac-3.local everywhere iMac is above. Hopefully it should be easy to see why using an alias is nicer
iMac:
John-Smiths-iMac-3.local
end

16
doc/mainpage.md Normal file
View File

@ -0,0 +1,16 @@
![Deskflow](https://github.com/user-attachments/assets/f005b958-24df-4f4a-9bfd-4f834dae59d6)
**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.
## Configuration
Our [Configuration] page has example configurations
## More info
For more info, see our [Wiki](https://github.com/deskflow/deskflow/wiki).
[Configuration]:configuration.md

View File

@ -1,56 +0,0 @@
# For now, we're only using Meson to resolve dependencies. CMake is called separately.
# In future, we may completely replace CMake with Meson.
# Where available, we use system packages, otherwise we use subprojects.
# Subprojects are also used to get the latest version during development.
project('deskflow', 'cpp')
if host_machine.system() == 'windows'
subproject('wintoast')
endif
system_tomlplusplus = get_option('system-tomlplusplus')
if system_tomlplusplus
dependency('tomlplusplus', required: false)
else
subproject('tomlplusplus')
endif
system_cli11 = get_option('system-cli11')
if system_cli11
dependency('cli11', required: false)
else
subproject('cli11')
endif
system_gtest = get_option('system-gtest')
if system_gtest
dependency('gtest', required: false)
else
subproject('gtest')
endif
if host_machine.system() == 'linux'
system_libei = get_option('system-libei')
if system_libei
dependency('libei-1.0', required: false)
else
# Using the subproject is only useful for development; it's not intended for normal use.
# GNOME46 or above is required as this has the required bits for libei.
# Building on anything older is pointless as you won't be able to actually connect to anything.
subproject('libei', default_options: ['tests=disabled', 'liboeffis=disabled'])
endif
system_libportal = get_option('system-libportal')
if system_libportal
dependency('libportal', required: false)
else
# Using the subproject is only useful for development; it's not intended for normal use.
subproject('libportal', default_options: [
'docs=false',
'backend-gtk3=enabled',
'backend-qt6=disabled'
])
endif
endif

View File

@ -1,5 +0,0 @@
option('system-gtest', type: 'boolean', value: true, description: 'Use system gtest')
option('system-libportal', type: 'boolean', value: true, description: 'Use system libportal')
option('system-libei', type: 'boolean', value: true, description: 'Use system libei')
option('system-tomlplusplus', type: 'boolean', value: true, description: 'Use system tomlplusplus')
option('system-cli11', type: 'boolean', value: true, description: 'Use system cli11')

View File

@ -1,11 +1,11 @@
# Maintainer: @DESKFLOW_MAINTAINER@
pkgname=@DESKFLOW_APP_ID@
pkgver=@DESKFLOW_VERSION_FOUR_PART@
pkgver=@DESKFLOW_VERSION@
pkgrel=1
pkgdesc="Mouse and keyboard sharing utility"
url='@DESKFLOW_WEBSITE_URL@'
arch=('x86_64')
arch=('i686' 'x86_64' 'armv6h' 'armv7h' 'aarch64')
license=('GPL-2.0-only')
depends=(
'gcc-libs'
@ -20,10 +20,13 @@ depends=(
'libxkbcommon-x11'
'libnotify'
'hicolor-icon-theme'
'pugixml'
'qt6-base'
'qt6-tools'
'libei'
'libportal'
'tomlplusplus'
'cli11'
)
conflicts=('synergy-git' 'synergy1-bin' 'synergy2-bin' 'synergy3-bin')
options=('!debug')
@ -31,7 +34,7 @@ options=('!debug')
package() {
# By default, `makepkg` will run from the `src` directory, which would
# only install the binaries, and not the .desktop file, etc. To install
# everything, we need to run `make install` with the root Makefile.
# everything, we need to set DESTDIR.
cd $startdir
make install DESTDIR=$pkgdir
DESTDIR=$pkgdir cmake --install .
}

View File

@ -24,7 +24,7 @@
<key>CFBundleVersion</key>
<string>@DESKFLOW_VERSION@</string>
<key>NSHumanReadableCopyright</key>
<string>© 2012-@DESKFLOW_BUILD_YEAR@ Symless Ltd</string>
<string>© 2024 Deskflow Developers</string>
<key>LSMinimumSystemVersion</key>
<string>10.9.0</string>
</dict>

View File

@ -1,30 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<Include>
<?define AppId="@DESKFLOW_APP_ID@"?>
<?define Name="@DESKFLOW_APP_NAME@"?>
<?define Version="@DESKFLOW_VERSION_MS@"?>
<?define Author="@DESKFLOW_AUTHOR_NAME@"?>
<?define BinDir="@CMAKE_RUNTIME_OUTPUT_DIRECTORY@"?>
<?define ProjectResDir="@DESKFLOW_PROJECT_RES_DIR@"?>
<?define ResDir="@DESKFLOW_RES_DIR@"?>
<?define QtDir="@QT_PATH@"?>
<?define QtBinDir="$(var.QtDir)\bin"?>
<?if $(var.Platform) = "x64"?>
<?define ProgramFilesFolder="ProgramFiles64Folder"?>
<?define PlatformSimpleName="64-bit"?>
<?define UpgradeGuid="@DESKFLOW_MSI_64_GUID@"?>
<?else?>
<?define ProgramFilesFolder="ProgramFilesFolder"?>
<?define PlatformSimpleName="32-bit"?>
<?define UpgradeGuid="@DESKFLOW_MSI_32_GUID@"?>
<?endif?>
<?define QtPluginsPath="$(var.QtDir)\plugins"?>
<?define OpenSslExeDir="@OPENSSL_EXE_DIR@"?>
<?define OpenSslDllDir="@OPENSSL_ROOT_DIR@/bin"?>
<?define GuiBin="@GUI_BINARY_NAME@.exe"?>
<?define ServerBin="@SERVER_BINARY_NAME@.exe"?>
<?define ClientBin="@CLIENT_BINARY_NAME@.exe"?>
<?define CoreBin="@CORE_BINARY_NAME@.exe"?>
<?define DaemonBin="@DAEMON_BINARY_NAME@.exe"?>
<?define LegacyBin="@LEGACY_BINARY_NAME@.exe"?>
</Include>
<?xml version="1.0" encoding="utf-8"?>
<Include>
<?define AppId="@DESKFLOW_APP_ID@"?>
<?define Name="@DESKFLOW_APP_NAME@"?>
<?define Version="@DESKFLOW_VERSION@"?>
<?define Author="@DESKFLOW_AUTHOR_NAME@"?>
<?define BinDir="@CMAKE_RUNTIME_OUTPUT_DIRECTORY@"?>
<?define ProjectResDir="@DESKFLOW_PROJECT_RES_DIR@"?>
<?define ResDir="@DESKFLOW_RES_DIR@"?>
<?define QtDir="@QT_PATH@"?>
<?define QtBinDir="$(var.QtDir)\bin"?>
<?if $(var.Platform) = "x64"?>
<?define ProgramFilesFolder="ProgramFiles64Folder"?>
<?define PlatformSimpleName="64-bit"?>
<?define UpgradeGuid="@DESKFLOW_MSI_64_GUID@"?>
<?else?>
<?define ProgramFilesFolder="ProgramFilesFolder"?>
<?define PlatformSimpleName="32-bit"?>
<?define UpgradeGuid="@DESKFLOW_MSI_32_GUID@"?>
<?endif?>
<?define QtPluginsPath="$(var.QtDir)\plugins"?>
<?define OpenSslExeDir="@OPENSSL_EXE_DIR@"?>
<?define OpenSslDllDir="@OPENSSL_ROOT_DIR@/bin"?>
<?define GuiBin="@GUI_BINARY_NAME@.exe"?>
<?define ServerBin="@SERVER_BINARY_NAME@.exe"?>
<?define ClientBin="@CLIENT_BINARY_NAME@.exe"?>
<?define CoreBin="@CORE_BINARY_NAME@.exe"?>
<?define DaemonBin="@DAEMON_BINARY_NAME@.exe"?>
</Include>

View File

@ -1,154 +1,166 @@
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" xmlns:fire="http://schemas.microsoft.com/wix/FirewallExtension" xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
<?include Include.wxi?>
<Product Id="*" Language="1033" Manufacturer="$(var.Author)" Name="$(var.Name) ($(var.PlatformSimpleName))" UpgradeCode="$(var.UpgradeGuid)" Version="$(var.Version)">
<Package Compressed="yes" InstallScope="perMachine" InstallerVersion="301"/>
<MajorUpgrade DowngradeErrorMessage="A newer version of $(var.Name) is already installed."/>
<MediaTemplate EmbedCab="yes"/>
<!-- causes ICE61 warning, but stops user from installing many instances from nightly builds. -->
<Upgrade Id="$(var.UpgradeGuid)">
<UpgradeVersion Minimum="0.0.0.0" Property="UPGRADE"/>
</Upgrade>
<Feature Id="ProductFeature" Title="$(var.Name)">
<ComponentGroupRef Id="ProductComponents"/>
<ComponentGroupRef Id="OpenSSLComponents"/>
<ComponentGroupRef Id="ProductQtStylesComponents"/>
<ComponentGroupRef Id="ProductQtPluginComponents"/>
<ComponentRef Id="RegistryEntries"/>
<MergeRef Id="VC_Redist"/>
</Feature>
<DirectoryRef Id="TARGETDIR">
<Component Guid="7CF3564D-1F8E-4D3D-9781-E1EE22D5BD67" Id="RegistryEntries">
<RegistryKey Id="$(var.AppId)_server" ForceCreateOnInstall="yes" ForceDeleteOnUninstall="yes" Key="Software\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers" Root="HKLM">
<RegistryValue Name="[INSTALLFOLDER]$(var.ServerBin)" Type="string" Value="~ HIGHDPIAWARE WIN7RTM"/>
</RegistryKey>
<RegistryKey Id="$(var.AppId)_client" Root="HKLM"
Key="Software\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers"
ForceCreateOnInstall="yes" ForceDeleteOnUninstall="yes">
<RegistryValue Type="string" Name="[INSTALLFOLDER]$(var.ClientBin)" Value="~ HIGHDPIAWARE WIN7RTM"/>
</RegistryKey>
<RegistryKey Id="$(var.AppId)" Root="HKLM"
Key="Software\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers"
ForceCreateOnInstall="yes" ForceDeleteOnUninstall="yes">
<RegistryValue Type="string" Name="[INSTALLFOLDER]$(var.GuiBin)" Value="~ HIGHDPIAWARE WIN7RTM"/>
</RegistryKey>
<!-- Windows 8 and later only -->
<Condition><![CDATA[Installed OR (VersionNT >= 602)]]></Condition>
</Component>
<?if $(var.Platform) = x64 ?>
<Merge Id="VC_Redist" SourceFile="$(var.ProjectResDir)\dist\wix\msm\Microsoft_VC142_CRT_x64.msm" DiskId="1" Language="0"/>
<?else ?>
<Merge Id="VC_Redist" SourceFile="$(var.ProjectResDir)\dist\wix\msm\Microsoft_VC142_CRT_x86.msm" DiskId="1" Language="0"/>
<?endif ?>
</DirectoryRef>
<Property Id="CommonBackground">CommonBackground</Property>
<Binary Id="CommonBackground" SourceFile="$(var.ResDir)\dist\wix\images\common_background.png"/>
<Icon Id="AppIcon" SourceFile="$(var.ResDir)/app.ico"/>
<WixVariable Id="WixUIBannerBmp" Value="$(var.ResDir)\dist\wix\images\banner.png"/>
<WixVariable Id="WixUIDialogBmp" Value="$(var.ResDir)\dist\wix\images\dialog.png"/>
<Property Id="ARPPRODUCTICON" Value="AppIcon"/>
<Property Id="WIXUI_INSTALLDIR" Value="INSTALLFOLDER"/>
<Property Id="LEGACY_UNINSTALL_EXISTS">
<RegistrySearch Id="LegacyRegistrySearch" Key="SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\$(var.Name)" Name="UninstallString" Root="HKLM" Type="file" Win64="no">
<FileSearch Id="LegacyFileSearch" Name="uninstall.exe"/>
</RegistrySearch>
</Property>
<Condition Message="An existing installation of $(var.Name) was detected, please uninstall it before continuing.">NOT LEGACY_UNINSTALL_EXISTS
</Condition>
<CustomAction ExeCommand="" FileKey="GuiProgram" Id="StartGui" Return="asyncNoWait"/>
<UI>
<UIRef Id="AppDlgSequence" />
</UI>
</Product>
<Fragment>
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="$(var.ProgramFilesFolder)">
<Directory Id="INSTALLFOLDER" Name="$(var.Name)">
<Directory Id="OpenSSLDir" Name="OpenSSL"/>
<Directory Id="PlatformsDir" Name="Platforms"/>
<Directory Id="QTStylesDir" Name="styles"/>
</Directory>
</Directory>
<Directory Id="ProgramMenuFolder"/>
</Directory>
</Fragment>
<Fragment>
<ComponentGroup Directory="INSTALLFOLDER" Id="ProductComponents">
<Component Guid="EC9AD3B0-277C-4157-B5C8-5FD5B6A5F4AD" Id="Core">
<File KeyPath="yes" Source="$(var.BinDir)/$(var.DaemonBin)"/>
<ServiceInstall Description="Controls the $(var.Name) foreground processes." DisplayName="$(var.Name)" ErrorControl="normal" Id="ServiceInstall" Name="$(var.Name)" Start="auto" Type="ownProcess">
<util:ServiceConfig FirstFailureActionType="restart" ResetPeriodInDays="1" RestartServiceDelayInSeconds="1" SecondFailureActionType="restart" ThirdFailureActionType="restart"/>
</ServiceInstall>
<ServiceControl Id="ServiceControl" Name="$(var.Name)" Remove="uninstall" Start="install" Stop="both"/>
<File Source="$(var.BinDir)/$(var.ServerBin)">
<fire:FirewallException Id="ServerFirewallException" IgnoreFailure="yes" Name="$(var.Name) Server" Scope="any"/>
</File>
<File Source="$(var.BinDir)/$(var.ClientBin)">
<fire:FirewallException Id="ClientFirewallException" IgnoreFailure="yes" Name="$(var.Name) Client" Scope="any"/>
</File>
<File Source="$(var.BinDir)/$(var.LegacyBin)" />
<?if $(var.Platform) = x64 ?>
<File Source="$(var.OpenSslDllDir)/libssl-3-x64.dll"/>
<File Source="$(var.OpenSslDllDir)/libcrypto-3-x64.dll"/>
<?else ?>
<File Source="$(var.OpenSslDllDir)/libssl-3.dll"/>
<File Source="$(var.OpenSslDllDir)/libcrypto-3.dll"/>
<?endif ?>
</Component>
<Component Guid="BAC8149B-6287-45BF-9C27-43D71ED40214" Id="Gui">
<File Id="GuiProgram" KeyPath="yes" Source="$(var.BinDir)/$(var.GuiBin)">
<Shortcut Advertise="yes" Directory="ProgramMenuFolder" Icon="$(var.GuiBin)" Id="GuiShortcut" Name="$(var.Name)">
<Icon Id="$(var.GuiBin)" SourceFile="$(var.ResDir)/app.ico"/>
</Shortcut>
<fire:FirewallException Id="GuiFirewallException" IgnoreFailure="yes" Name="$(var.Name)" Scope="any"/>
</File>
<?if $(var.Configuration) = "Debug" ?>
<File Source="$(var.BinDir)\Qt6Cored.dll"/>
<File Source="$(var.BinDir)\Qt6Guid.dll"/>
<File Source="$(var.BinDir)\Qt6Networkd.dll"/>
<File Source="$(var.BinDir)\Qt6Svgd.dll"/>
<File Source="$(var.BinDir)\Qt6Widgetsd.dll"/>
<File Source="$(var.BinDir)\styles\qmodernwindowsstyle.dll"/>
<!-- HACK: Normally the C++ redistributable solves this dependency, including it can cause problems -->
<File Source="C:\Program Files (x86)\Windows Kits\10\bin\$(var.Platform)\ucrt\ucrtbased.dll"/>
<?else ?>
<File Source="$(var.BinDir)\Qt6Core.dll"/>
<File Source="$(var.BinDir)\Qt6Gui.dll"/>
<File Source="$(var.BinDir)\Qt6Network.dll"/>
<File Source="$(var.BinDir)\Qt6Svg.dll"/>
<File Source="$(var.BinDir)\Qt6Widgets.dll"/>
<File Source="$(var.BinDir)\styles\qmodernwindowsstyle.dll"/>
<?endif ?>
</Component>
</ComponentGroup>
<ComponentGroup Directory="QTStylesDir" Id="ProductQtStylesComponents">
<Component Guid="96E0F8D8-64FD-4CE8-94D1-F6EDCBBB4995" Id="Styles">
<File Id="qmodernwindowsstyle" Source="$(var.BinDir)\styles\qmodernwindowsstyle.dll"/>
</Component>
</ComponentGroup>
<ComponentGroup Directory="PlatformsDir" Id="ProductQtPluginComponents">
<Component Guid="684EFA14-856B-440E-A5E6-E90E04E36B41" Id="QtPlatformPlugin">
<?if $(var.Configuration) = "Debug" ?>
<File Source="$(var.BinDir)\platforms\qwindowsd.dll"/>
<?else ?>
<File Source="$(var.BinDir)\platforms\qwindows.dll"/>
<?endif ?>
</Component>
</ComponentGroup>
<ComponentGroup Directory="OpenSSLDir" Id="OpenSSLComponents">
<Component Guid="92648F77-65A6-4B16-AC59-A1F37BD341B1" Id="OpenSSL">
<?if $(var.Platform) = x64 ?>
<File Id="OpenSSLDll1" Source="$(var.OpenSslDllDir)/libcrypto-3-x64.dll"/>
<File Id="OpenSSLDll2" Source="$(var.OpenSslDllDir)/libssl-3-x64.dll"/>
<?else ?>
<File Id="OpenSSLDll1" Source="$(var.OpenSslDllDir)/libcrypto-3.dll"/>
<File Id="OpenSSLDll2" Source="$(var.OpenSslDllDir)/libssl-3.dll"/>
<?endif ?>
<File Source="$(var.OpenSslExeDir)/openssl.exe"/>
<File Source="$(var.OpenSslExeDir)/openssl.cnf"/>
</Component>
</ComponentGroup>
</Fragment>
</Wix>
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" xmlns:fire="http://schemas.microsoft.com/wix/FirewallExtension" xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
<?include Include.wxi?>
<Product Id="*" Language="1033" Manufacturer="$(var.Author)" Name="$(var.Name) ($(var.PlatformSimpleName))" UpgradeCode="$(var.UpgradeGuid)" Version="$(var.Version)">
<Package Compressed="yes" InstallScope="perMachine" InstallerVersion="301"/>
<MajorUpgrade DowngradeErrorMessage="A newer version of $(var.Name) is already installed."/>
<MediaTemplate EmbedCab="yes"/>
<!-- causes ICE61 warning, but stops user from installing many instances from nightly builds. -->
<Upgrade Id="$(var.UpgradeGuid)">
<UpgradeVersion Minimum="0.0.0.0" Property="UPGRADE"/>
</Upgrade>
<Feature Id="ProductFeature" Title="$(var.Name)">
<ComponentGroupRef Id="ProductComponents"/>
<ComponentGroupRef Id="OpenSSLComponents"/>
<ComponentGroupRef Id="ProductQtStylesComponents"/>
<ComponentGroupRef Id="ProductQtPluginComponents"/>
<ComponentRef Id="RegistryEntries"/>
<MergeRef Id="VC_Redist"/>
</Feature>
<DirectoryRef Id="TARGETDIR">
<Component Guid="7CF3564D-1F8E-4D3D-9781-E1EE22D5BD67" Id="RegistryEntries">
<RegistryKey Id="$(var.AppId)_server" ForceCreateOnInstall="yes" ForceDeleteOnUninstall="yes" Key="Software\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers" Root="HKLM">
<RegistryValue Name="[INSTALLFOLDER]$(var.ServerBin)" Type="string" Value="~ HIGHDPIAWARE WIN7RTM"/>
</RegistryKey>
<RegistryKey Id="$(var.AppId)_client" Root="HKLM"
Key="Software\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers"
ForceCreateOnInstall="yes" ForceDeleteOnUninstall="yes">
<RegistryValue Type="string" Name="[INSTALLFOLDER]$(var.ClientBin)" Value="~ HIGHDPIAWARE WIN7RTM"/>
</RegistryKey>
<RegistryKey Id="$(var.AppId)" Root="HKLM"
Key="Software\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers"
ForceCreateOnInstall="yes" ForceDeleteOnUninstall="yes">
<RegistryValue Type="string" Name="[INSTALLFOLDER]$(var.GuiBin)" Value="~ HIGHDPIAWARE WIN7RTM"/>
</RegistryKey>
<!-- Windows 8 and later only -->
<Condition><![CDATA[Installed OR (VersionNT >= 602)]]></Condition>
</Component>
<?if $(var.Platform) = x64 ?>
<Merge Id="VC_Redist" SourceFile="$(var.ProjectResDir)\dist\wix\msm\Microsoft_VC142_CRT_x64.msm" DiskId="1" Language="0"/>
<?else ?>
<Merge Id="VC_Redist" SourceFile="$(var.ProjectResDir)\dist\wix\msm\Microsoft_VC142_CRT_x86.msm" DiskId="1" Language="0"/>
<?endif ?>
</DirectoryRef>
<Property Id="CommonBackground">CommonBackground</Property>
<Binary Id="CommonBackground" SourceFile="$(var.ResDir)\dist\wix\images\common_background.png"/>
<Icon Id="AppIcon" SourceFile="$(var.ResDir)/app.ico"/>
<WixVariable Id="WixUIBannerBmp" Value="$(var.ResDir)\dist\wix\images\banner.png"/>
<WixVariable Id="WixUIDialogBmp" Value="$(var.ResDir)\dist\wix\images\dialog.png"/>
<Property Id="ARPPRODUCTICON" Value="AppIcon"/>
<Property Id="WIXUI_INSTALLDIR" Value="INSTALLFOLDER"/>
<Property Id="LEGACY_UNINSTALL_EXISTS">
<RegistrySearch Id="LegacyRegistrySearch" Key="SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\$(var.Name)" Name="UninstallString" Root="HKLM" Type="file" Win64="no">
<FileSearch Id="LegacyFileSearch" Name="uninstall.exe"/>
</RegistrySearch>
</Property>
<Condition Message="An existing installation of $(var.Name) was detected, please uninstall it before continuing.">NOT LEGACY_UNINSTALL_EXISTS
</Condition>
<CustomAction ExeCommand="" FileKey="GuiProgram" Id="StartGui" Return="asyncNoWait"/>
<UI>
<UIRef Id="AppDlgSequence" />
</UI>
</Product>
<Fragment>
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="$(var.ProgramFilesFolder)">
<Directory Id="INSTALLFOLDER" Name="$(var.Name)">
<Directory Id="OpenSSLDir" Name="OpenSSL"/>
<Directory Id="PlatformsDir" Name="Platforms"/>
<Directory Id="QTStylesDir" Name="styles"/>
</Directory>
</Directory>
<Directory Id="ProgramMenuFolder"/>
</Directory>
</Fragment>
<Fragment>
<ComponentGroup Directory="INSTALLFOLDER" Id="ProductComponents">
<Component Guid="EC9AD3B0-277C-4157-B5C8-5FD5B6A5F4AD" Id="Core">
<File KeyPath="yes" Source="$(var.BinDir)/$(var.DaemonBin)"/>
<ServiceInstall Description="Controls the $(var.Name) foreground processes." DisplayName="$(var.Name)" ErrorControl="normal" Id="ServiceInstall" Name="$(var.Name)" Start="auto" Type="ownProcess">
<util:ServiceConfig FirstFailureActionType="restart" ResetPeriodInDays="1" RestartServiceDelayInSeconds="1" SecondFailureActionType="restart" ThirdFailureActionType="restart"/>
</ServiceInstall>
<ServiceControl Id="ServiceControl" Name="$(var.Name)" Remove="uninstall" Start="install" Stop="both"/>
<File Source="$(var.BinDir)/$(var.ServerBin)">
<fire:FirewallException Id="ServerFirewallException" IgnoreFailure="yes" Name="$(var.Name) Server" Scope="any"/>
</File>
<File Source="$(var.BinDir)/$(var.ClientBin)">
<fire:FirewallException Id="ClientFirewallException" IgnoreFailure="yes" Name="$(var.Name) Client" Scope="any"/>
</File>
<?if $(var.Platform) = x64 ?>
<File Source="$(var.OpenSslDllDir)/libssl-3-x64.dll"/>
<File Source="$(var.OpenSslDllDir)/libcrypto-3-x64.dll"/>
<?else ?>
<File Source="$(var.OpenSslDllDir)/libssl-3.dll"/>
<File Source="$(var.OpenSslDllDir)/libcrypto-3.dll"/>
<?endif ?>
</Component>
<Component Guid="BAC8149B-6287-45BF-9C27-43D71ED40214" Id="Gui">
<File Id="GuiProgram" KeyPath="yes" Source="$(var.BinDir)/$(var.GuiBin)">
<Shortcut Advertise="yes" Directory="ProgramMenuFolder" Icon="$(var.GuiBin)" Id="GuiShortcut" Name="$(var.Name)">
<Icon Id="$(var.GuiBin)" SourceFile="$(var.ResDir)/app.ico"/>
</Shortcut>
<fire:FirewallException Id="GuiFirewallException" IgnoreFailure="yes" Name="$(var.Name)" Scope="any"/>
</File>
<?if $(var.Configuration) = "Debug" ?>
<File Source="$(var.BinDir)\Qt6Cored.dll"/>
<File Source="$(var.BinDir)\Qt6Guid.dll"/>
<File Source="$(var.BinDir)\Qt6Networkd.dll"/>
<File Source="$(var.BinDir)\Qt6Svgd.dll"/>
<File Source="$(var.BinDir)\Qt6Widgetsd.dll"/>
<File Source="$(var.BinDir)\styles\qmodernwindowsstyle.dll"/>
<!-- HACK: Normally the C++ redistributable solves this dependency, including it can cause problems -->
<File Source="C:\Program Files (x86)\Windows Kits\10\bin\$(var.Platform)\ucrt\ucrtbased.dll"/>
<?else ?>
<File Source="$(var.BinDir)\brotlicommon.dll"/>
<File Source="$(var.BinDir)\brotlidec.dll"/>
<File Source="$(var.BinDir)\bz2.dll"/>
<File Source="$(var.BinDir)\double-conversion.dll"/>
<File Source="$(var.BinDir)\freetype.dll"/>
<File Source="$(var.BinDir)\harfbuzz.dll"/>
<File Source="$(var.BinDir)\icudt74.dll"/>
<File Source="$(var.BinDir)\icuin74.dll"/>
<File Source="$(var.BinDir)\icuuc74.dll"/>
<File Source="$(var.BinDir)\libpng16.dll"/>
<File Source="$(var.BinDir)\pcre2-16.dll"/>
<File Source="$(var.BinDir)\Qt6Core.dll"/>
<File Source="$(var.BinDir)\Qt6Gui.dll"/>
<File Source="$(var.BinDir)\Qt6Network.dll"/>
<File Source="$(var.BinDir)\Qt6Svg.dll"/>
<File Source="$(var.BinDir)\Qt6Widgets.dll"/>
<File Source="$(var.BinDir)\zlib1.dll"/>
<File Source="$(var.BinDir)\zstd.dll"/>
<File Source="$(var.BinDir)\styles\qmodernwindowsstyle.dll"/>
<?endif ?>
</Component>
</ComponentGroup>
<ComponentGroup Directory="QTStylesDir" Id="ProductQtStylesComponents">
<Component Guid="96E0F8D8-64FD-4CE8-94D1-F6EDCBBB4995" Id="Styles">
<File Id="qmodernwindowsstyle" Source="$(var.BinDir)\styles\qmodernwindowsstyle.dll"/>
</Component>
</ComponentGroup>
<ComponentGroup Directory="PlatformsDir" Id="ProductQtPluginComponents">
<Component Guid="684EFA14-856B-440E-A5E6-E90E04E36B41" Id="QtPlatformPlugin">
<?if $(var.Configuration) = "Debug" ?>
<File Source="$(var.BinDir)\platforms\qwindowsd.dll"/>
<?else ?>
<File Source="$(var.BinDir)\platforms\qwindows.dll"/>
<?endif ?>
</Component>
</ComponentGroup>
<ComponentGroup Directory="OpenSSLDir" Id="OpenSSLComponents">
<Component Guid="92648F77-65A6-4B16-AC59-A1F37BD341B1" Id="OpenSSL">
<?if $(var.Platform) = x64 ?>
<File Id="OpenSSLDll1" Source="$(var.OpenSslDllDir)/libcrypto-3-x64.dll"/>
<File Id="OpenSSLDll2" Source="$(var.OpenSslDllDir)/libssl-3-x64.dll"/>
<?else ?>
<File Id="OpenSSLDll1" Source="$(var.OpenSslDllDir)/libcrypto-3.dll"/>
<File Id="OpenSSLDll2" Source="$(var.OpenSslDllDir)/libssl-3.dll"/>
<?endif ?>
<File Source="$(var.OpenSslExeDir)/openssl.exe"/>
<File Source="$(var.OpenSslExeDir)/openssl.cnf"/>
</Component>
</ComponentGroup>
</Fragment>
</Wix>

View File

@ -1,17 +1,17 @@
<RCC>
<qresource>
<file>icons/16x16/tray.png</file>
<file>icons/64x64/video-display.png</file>
<file>icons/64x64/user-trash.png</file>
<file>icons/16x16/warning.png</file>
<file>icons/256x256/app.ico</file>
<file>image/logo-light.png</file>
<file>image/logo-dark.png</file>
<file>icons/16x16/padlock.png</file>
<file>icons/64x64/tray-dark.png</file>
<file>icons/64x64/tray-light.png</file>
<file>icons/64x64/padlock.png</file>
<file>icons/128x128/tray-dark.png</file>
<file>icons/128x128/tray-light.png</file>
<file>icons/128x128/tray.png</file>
<file>image/welcome.png</file>
<file>icons/64x64/folder.png</file>
<file>icons/64x64/copy-light.png</file>
<file>icons/64x64/copy-dark.png</file>
<file>image/placeholder.png</file>
</qresource>
</RCC>

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 450 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 926 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 693 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

View File

@ -1 +1 @@
IDI_ICON1 ICON DISCARDABLE "../icons/256x256/app.ico"
IDI_ICON1 ICON DISCARDABLE "../../app.ico"

View File

@ -10,12 +10,12 @@ https://learn.microsoft.com/en-us/windows/win32/menurc/versioninfo-resource?redi
#define VER_FILEVERSION_STR "@DESKFLOW_VERSION_MS@\0"
#define VER_PRODUCTVERSION @DESKFLOW_VERSION_MS_CSV@
#define VER_PRODUCTVERSION_STR "@DESKFLOW_VERSION_MS@\0"
#define VER_PRODUCTVERSION_STR "@DESKFLOW_VERSION@\0"
#define VER_COMPANYNAME_STR "@DESKFLOW_AUTHOR_NAME@\0"
#define VER_FILEDESCRIPTION_STR "@DESKFLOW_APP_NAME@\0"
#define VER_INTERNALNAME_STR "@DESKFLOW_APP_NAME@\0"
#define VER_LEGALCOPYRIGHT_STR "Copyright (C) Symless Ltd. @DESKFLOW_BUILD_YEAR@\0"
#define VER_LEGALCOPYRIGHT_STR "© 2024 Deskflow Developers\0"
#define VER_LEGALTRADEMARKS1_STR "All Rights Reserved\0"
#define VER_LEGALTRADEMARKS2_STR "\0"
#define VER_ORIGINALFILENAME_STR "\0"

View File

@ -1,355 +0,0 @@
#!/usr/bin/env python3
# Deskflow -- mouse and keyboard sharing utility
# Copyright (C) 2024 Symless Ltd.
#
# This package is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# found in the file LICENSE that should have accompanied this file.
#
# This package is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os, sys, argparse, traceback
import lib.env as env
import lib.cmd_utils as cmd_utils
import lib.qt_utils as qt_utils
import lib.github as github
import lib.meson as meson
path_env_var = "PATH"
cmake_prefix_env_var = "CMAKE_PREFIX_PATH"
def main():
is_ci = os.getenv("CI") is not None
if is_ci:
print("CI environment detected")
args = parse_args(is_ci)
if args.lock_file:
env.persist_lock_file(args.lock_file)
try:
run(args)
except Exception:
traceback.print_exc()
sys.exit(1)
finally:
if env.is_windows() and args.pause_on_exit:
# Allow the rest of the install to continue while sitting at the pause.
if args.lock_file:
env.remove_lock_file(args.lock_file)
# Useful on Windows, when elevated, Python is opened in a new window and closes
# immediately after the script finishes. This keeps the script window open so that
# the user can see the output.
print()
input("Press enter to continue...")
def parse_args(is_ci):
parser = argparse.ArgumentParser()
parser.add_argument(
"--ci-env",
action="store_true",
help="Useful for faking CI env (defaults to true in CI env)",
default=is_ci,
)
parser.add_argument(
"--lock-file",
type=str,
help="Create a file to indicate script is running",
)
parser.add_argument(
"--only-python", action="store_true", help="Only install Python dependencies"
)
parser.add_argument(
"--skip-python",
action="store_true",
help="Do not install Python dependencies",
)
parser.add_argument(
"--skip-system",
action="store_true",
help="Do not install system dependencies (apt, dnf, etc)",
)
parser.add_argument(
"--skip-meson", action="store_true", help="Do not setup and compile with Meson"
)
parser.add_argument(
"--subprojects",
action="store_true",
help="Install dependencies for Meson subprojects (use with --meson-no-system)",
)
parser.add_argument(
"--meson-install",
action="store_true",
help="Install built Meson subprojects to system",
)
parser.add_argument(
"--meson-no-system",
nargs="+",
help="Specify which Meson subprojects to use instead of system dependencies",
)
parser.add_argument(
"--meson-static",
nargs="+",
help="Specify which Meson subprojects to build as static libraries",
)
if env.is_windows():
parser.add_argument(
"--skip-vcpkg",
action="store_true",
help="Windows only: Do not install vcpkg dependencies",
)
parser.add_argument(
"--skip-elevated",
action="store_true",
help="Windows only: Do not run elevated command",
)
parser.add_argument(
"--only-elevated",
action="store_true",
help="Windows only: Only run elevated command",
)
parser.add_argument(
"--pause-on-exit",
action="store_true",
help="Windows only: Useful to prevent elevated window from closing",
)
return parser.parse_args()
def run(args):
env.ensure_dependencies()
env.ensure_in_venv(__file__, create_venv=True)
if not args.skip_python:
env.install_requirements()
colors = env.import_colors()
if args.only_python:
print()
print(colors.SUCCESS_TEXT + " Only Python dependencies installed")
return
try:
install(args)
print()
print(f"\n{colors.SUCCESS_TEXT} Dependencies installed")
# On Windows and macOS, we set env vars for cmake, but for them to be picked up,
# either the shell needs to be restarted or the env vars need to be re-sourced.
# Restarting the shell is easier for most people.
if not env.is_linux():
print(
f"{colors.WARNING_TEXT} You may need to restart your terminal "
"or IDE to use new env vars"
)
except Exception:
traceback.print_exc()
print()
print(f"\n{colors.ERROR_TEXT} Failed to install dependencies")
sys.exit(1)
def install(args):
if not args.skip_system:
deps = Dependencies(args)
deps.install()
# Only install vcpkg dependencies on Windows, since on other OS it's not needed (yet).
# We probably won't ever need this on macOS and Linux since brew and apt/dnf/etc do a
# good job of providing dependencies. Where they don't, we can use Meson.
if env.is_windows() and not args.skip_vcpkg:
import lib.vcpkg as vcpkg
vcpkg.install(args.ci_env)
if not args.skip_meson:
if args.subprojects:
for subproject in args.meson_no_system or []:
deps = SubprojectDependencies(subproject)
deps.install()
run_meson(args.meson_install, args.meson_no_system, args.meson_static)
# It's a bit weird to use Meson just for installing deps, but it's a stopgap until
# we fully switch from CMake to Meson. For the meantime, Meson will install the deps
# so that CMake can find them easily. Once we switch to Meson, it might be possible for
# Meson handle the deps resolution, so that we won't need to install them on the system.
def run_meson(install, no_system_list, static_list):
meson.setup(no_system_list, static_list)
# Only compile and install on Linux for now, since we're only using Meson to fetch
# the deps on Windows and macOS.
if env.is_linux():
meson.compile()
if install:
meson.install()
class Dependencies:
def __init__(self, args):
from lib.config import Config
self.config = Config()
self.args = args
self.ci_env = args.ci_env
def install(self):
"""Installs dependencies for the current platform."""
if env.is_windows():
self.windows()
elif env.is_mac():
self.mac()
elif env.is_linux():
self.linux()
else:
raise RuntimeError(f"Unsupported platform: {os}")
def windows(self):
"""Installs dependencies on Windows."""
import lib.windows as windows
if not self.args.skip_elevated:
if windows.is_admin():
# The choco command should run from the elevated command.
choco = windows.WindowsChoco()
choco.ensure_choco_installed()
command_elevated = self.config.get_os_deps_command("command-elevated")
cmd_utils.run(command_elevated, shell=True, print_cmd=True)
if self.args.only_elevated:
sys.exit(0)
else:
windows.run_elevated(
__file__, "--only-elevated --skip-python", wait_for_exit=True
)
qt = qt_utils.WindowsQt(*self.config.get_qt_config())
qt.install()
if self.ci_env:
github.set_env_var(cmake_prefix_env_var, qt.get_install_dir())
else:
windows.set_env_var(cmake_prefix_env_var, qt.get_install_dir())
command = self.config.get_os_deps_command()
cmd_utils.run(command, shell=True, print_cmd=True)
def mac(self):
"""Installs dependencies on macOS."""
import lib.mac as mac
# On macOS, brew does have a Qt package available, but it is always built against the
# current macOS version and the brew version also does some really weird stuff with the
# library symbols, which confuses the heck out of `macqtdeploy`. So, using the official
# Qt library binaries seems to be the most reliable option for distribution.
qt = qt_utils.MacQt(*self.config.get_qt_config())
qt.install()
qt_dir = qt.get_install_dir()
qt_bin_dir = os.path.join(qt_dir, "bin")
env_vars_set = 0
if self.ci_env:
github.set_env_var(cmake_prefix_env_var, qt_dir)
github.add_to_path(qt_bin_dir)
else:
env_vars_set += mac.set_env_var(cmake_prefix_env_var, qt_dir)
env_vars_set += mac.set_env_var(path_env_var, qt_bin_dir)
command = self.config.get_os_deps_command()
cmd_utils.run(command, shell=True, print_cmd=True)
if env_vars_set:
print(f"To load env vars, run: source {mac.SHELL_RC}")
def linux(self):
"""Installs dependencies on Linux."""
import lib.linux as linux
distro, distro_like, _distro_version = env.get_linux_distro()
if not distro:
raise RuntimeError("Unable to detect Linux distro")
command_pre = self.config.get_os_deps_command_pre(
linux_distro=distro, required=False
)
if command_pre:
print("Running dependencies prerequisites command")
check = True
if distro == "fedora" or (distro_like and "fedora" in distro_like):
print(
"Fedora-like detected, "
"ignoring return code on dependencies prerequisites command"
)
# On Fedora-like, dnf update returns code 100 when updates are available.
check = False
linux.run_command(command_pre, check)
command = self.config.get_os_deps_command(linux_distro=distro)
optional = self.config.get_os_deps_value(
"optional", linux_distro=distro, required=False
)
for optional_package in optional or []:
if not linux.is_package_available(optional_package):
print(f"Optional package not found, stripping: {optional_package}")
command = command.replace(optional_package, "")
linux.run_command(command, check=True)
subprojects = self.config.get_os_subprojects()
if subprojects:
for subproject in subprojects:
deps = SubprojectDependencies(subproject)
deps.install()
class SubprojectDependencies:
def __init__(self, subproject):
from lib.config import Config
self.subproject = subproject
self.config = Config()
def install(self):
"""Installs dependencies for the current platform."""
print(f"Installing dependencies for sub-project: {self.subproject}")
if env.is_linux():
self.linux()
else:
raise RuntimeError(f"Unsupported platform: {os}")
def linux(self):
"""Installs dependencies on Linux."""
import lib.linux as linux
command = self.config.get_subproject_deps_command(self.subproject)
linux.run_command(command, check=True)
if __name__ == "__main__":
main()

View File

@ -1,78 +0,0 @@
#!/usr/bin/env sh
SUDO=$(which sudo > /dev/null 2>&1 && echo "sudo" || echo "")
install_deps() {
uname_out="$(uname -s)"
case "${uname_out}" in
FreeBSD*) install_freebsd ;;
OpenBSD*) install_openbsd ;;
NetBSD*) install_netbsd ;;
DragonFly*) install_dragonfly ;;
SunOS*) install_solaris ;;
*) install_other $@ ;;
esac
}
install_freebsd() {
run_cmd pkg install -y \
cmake \
ninja \
gmake \
gcc10 \
openssl \
glib \
gdk-pixbuf2 \
libX11 \
libXtst \
libnotify \
libxkbfile \
qt6-base \
qt6-tools \
gtk3 \
googletest \
pugixml \
tomlplusplus \
cli11
}
install_openbsd() {
# Patches welcome!
# pkg_add error:
# Can't find libX11
# Can't find libXtst
echo "Sorry, OpenBSD is not supported yet."
}
install_netbsd() {
# Patches welcome!
# pkg_add error:
# pkg_add: no pkg found for 'libX11', sorry.
# pkg_add: no pkg found for 'libXtst', sorry.
echo "Sorry, NetBSD is not supported yet."
}
install_dragonfly() {
# Patches welcome!
# The C++ version on DragonFly BSD seems to be too old.
echo "Sorry, DragonFly BSD is not supported yet."
}
install_solaris() {
# Patches welcome!
echo "Sorry, Solaris is not supported yet."
}
install_other() {
# TODO: Port the .py script to shell script to make the deps installation lighter on
# Linux and macOS. The .py script is probably only really needed to deal with Windows.
./scripts/install_deps.py $@
}
run_cmd() {
cmd="${SUDO:+$SUDO }$@"
echo "Running: $cmd"
$cmd
}
install_deps $@

View File

@ -1,129 +0,0 @@
# Deskflow -- mouse and keyboard sharing utility
# Copyright (C) 2024 Symless Ltd.
#
# This package is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# found in the file LICENSE that should have accompanied this file.
#
# This package is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import yaml
import lib.env as env
import lib.cmd_utils as cmd_utils
config_file = "config.yaml"
root_key = "config"
deps_key = "dependencies"
command_key = "command"
command_pre_key = "command-pre"
subprojects_key = "subprojects"
arrow = ""
class ConfigKeyError(RuntimeError):
def __init__(self, config_file, key):
self.config_file = config_file
self.key = key
def __str__(self):
return f"Not found in {self.config_file}: {self.key}"
def _get(dict, key, key_parent=None, required=True):
value = dict.get(key)
if required and not value:
key_path = f"{root_key}{arrow}{key_parent}{arrow}{key}" if key_parent else key
raise ConfigKeyError(config_file, key_path)
return value
class Config:
"""Reads the project configuration YAML file."""
def __init__(self):
with open(config_file, "r") as f:
data = yaml.safe_load(f)
self.os_name = env.get_os()
print("Config for OS:", self.os_name)
self.root = _get(data, root_key)
self.os = _get(self.root, self.os_name)
def get_os_value(self, key, required=True, linux_distro=None):
if linux_distro:
# recurse with the linux distro as the key parameter to get the base distro key.
distro = self.get_os_value(key=linux_distro)
return _get(distro, key, f"{self.os_name}{arrow}{linux_distro}", required)
else:
return _get(self.os, key, self.os_name, required)
def get_qt_config(self):
qt_key = "qt"
qt = self.get_os_deps_value(qt_key)
parent_key = f"{self.os_name}{arrow}{deps_key}"
mirror_url = _get(qt, "mirror", parent_key)
version = _get(qt, "version", parent_key)
base_dir = _get(qt, "base-dir", parent_key)
modules = _get(qt, "modules", parent_key, required=False)
return mirror_url, version, base_dir, modules
def get_os_deps_value(self, key, required=True, linux_distro=None):
deps = self.get_os_value(deps_key, required, linux_distro)
if linux_distro:
key_parent = f"{self.os_name}{arrow}{linux_distro}{arrow}{deps_key}"
else:
key_parent = f"{self.os_name}{arrow}{deps_key}"
return _get(deps, key, key_parent, required)
def get_os_deps_command(self, key=command_key, required=True, linux_distro=None):
command = self.get_os_deps_value(key, required, linux_distro)
if command:
return cmd_utils.strip_continuation_sequences(command)
else:
return None
def get_os_subprojects(self):
distro, _distro_like, _distro_version = env.get_linux_distro()
return self.get_os_value(subprojects_key, linux_distro=distro, required=False)
def get_subproject_deps_command(self, subproject_name):
subprojects = _get(self.root, subprojects_key)
subproject = _get(subprojects, subproject_name, subprojects_key)
deps_parent = f"{subprojects_key}{arrow}{subproject_name}"
deps = _get(subproject, deps_key, deps_parent)
if env.is_linux():
distro, _distro_like, _distro_version = env.get_linux_distro()
if not distro:
raise RuntimeError("Unable to detect Linux distro")
command = _get(deps, distro, f"{deps_parent}{arrow}{deps_key}")
else:
command = _get(deps, self.os_name, f"{deps_parent}{arrow}{deps_key}")
return cmd_utils.strip_continuation_sequences(command)
def get_os_deps_command_pre(self, required=True, linux_distro=None):
return self.get_os_deps_command(command_pre_key, required, linux_distro)
def get_windows_ci_config(self):
choco_ci_key = "ci"
choco_ci = self.get_os_deps_value(choco_ci_key)
choco_ci_path = f"{self.os_name}{arrow}{deps_key}{arrow}{choco_ci_key}"
edit_config = _get(choco_ci, "edit-config", choco_ci_path)
skip_packages = _get(choco_ci, "skip-packages", choco_ci_path)
return edit_config, skip_packages

View File

@ -1,68 +0,0 @@
# Deskflow -- mouse and keyboard sharing utility
# Copyright (C) 2024 Symless Ltd.
#
# This package is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# found in the file LICENSE that should have accompanied this file.
#
# This package is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os
github_env_key = "GITHUB_ENV"
github_path_key = "GITHUB_PATH"
github_output_key = "GITHUB_OUTPUT"
def set_env_var(key, value):
"""
Appends the key=value pair to the GitHub environment file.
"""
env_file = os.getenv(github_env_key)
if not env_file:
raise RuntimeError(f"Env var {github_env_key} not set")
if not os.path.exists(env_file):
raise RuntimeError(f"Env file not found: {env_file}")
print(f"Setting GitHub env var: {key}={value}")
with open(env_file, "a") as env_file:
env_file.write(f"{key}={value}\n")
def add_to_path(value):
"""
Appends the value to the GitHub path.
"""
path_file = os.getenv(github_path_key)
if not path_file:
raise RuntimeError(f"Env var {github_path_key} not set")
if not os.path.exists(path_file):
raise RuntimeError(f"Path file not found: {path_file}")
print(f"Adding to GitHub path: {value}")
with open(path_file, "a") as path_file:
path_file.write(f"{value}\n")
def set_output(name, value):
"""
Sets the output parameter for the GitHub action.
"""
output_file = os.getenv(github_output_key)
if not output_file:
raise RuntimeError(f"Env var {github_output_key} not set")
if not os.path.exists(output_file):
raise RuntimeError(f"Output file not found: {output_file}")
print(f"Setting GitHub output: {name}={value}")
with open(output_file, "a") as output_file:
output_file.write(f"{name}={value}\n")

View File

@ -1,218 +0,0 @@
# Deskflow -- mouse and keyboard sharing utility
# Copyright (C) 2024 Symless Ltd.
#
# This package is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# found in the file LICENSE that should have accompanied this file.
#
# This package is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os, shutil, glob, sys
import lib.cmd_utils as cmd_utils
import lib.env as env
from enum import Enum, auto
BUILD_ROOT_DIR = "build"
class PackageType(Enum):
DISTRO = auto()
TGZ = auto()
def run_command(command, check=True):
has_sudo = cmd_utils.has_command("sudo")
if "sudo" in command and not has_sudo:
# assume we're running as root if sudo is not found (common on older distros).
# a space char is intentionally added after "sudo" for intentionality.
# possible limitation with stripping "sudo" is that if any packages with "sudo" in the
# name are added to the list (probably very unlikely), this will have undefined behavior.
print("The 'sudo' command was not found, stripping sudo from command")
command = command.replace("sudo ", "").strip()
cmd_utils.run(command, check, shell=True, print_cmd=True)
def package(
filename_base,
dist_dir,
test_cmd,
package_name,
package_type: PackageType,
leave_test_installed=False,
):
working_dir = BUILD_ROOT_DIR
extension, cmd = get_package_build_info(
package_type,
)
run_package_cmd(cmd, working_dir)
package_filename = get_package_filename(extension, working_dir)
target_file = f"{filename_base}.{extension}"
target_path = copy_to_dist_dir(package_filename, dist_dir, target_file)
if package_type == PackageType.DISTRO:
test_install(
target_path, package_name, test_cmd, remove_test=not leave_test_installed
)
def get_package_build_info(package_type: PackageType):
command = None
cpack_generator = None
file_extension = None
if package_type == PackageType.TGZ:
cpack_generator = "TGZ"
file_extension = "tar.gz"
elif package_type == PackageType.DISTRO:
distro, distro_like, _distro_version = env.get_linux_distro()
if not distro_like:
distro_like = distro
if "debian" in distro_like:
cpack_generator = "DEB"
file_extension = "deb"
elif "fedora" in distro_like or "opensuse" in distro_like:
cpack_generator = "RPM"
file_extension = "rpm"
elif "arch" in distro_like:
command = ["makepkg", "-s"]
file_extension = "pkg.tar.zst"
else:
raise RuntimeError(f"Linux distro not yet supported: {distro}")
if not cpack_generator and not command:
raise RuntimeError("No package generator or command found")
if cpack_generator:
command = ["cpack", "-G", cpack_generator]
return file_extension, command
def run_package_cmd(command, working_dir):
package_user = env.get_env("LINUX_PACKAGE_USER", required=False)
if package_user:
cmd_utils.run(
["sudo", "chown", "-R", package_user, working_dir],
check=True,
print_cmd=True,
)
command = ["sudo", "-u", package_user] + command
cwd = os.getcwd()
try:
os.chdir(working_dir)
cmd_utils.run(command, check=True, print_cmd=True)
finally:
os.chdir(cwd)
def get_package_filename(extension, working_dir):
files = glob.glob(f"{working_dir}/*.{extension}")
if not files:
raise ValueError(
f"No .{extension} file found in build directory: {working_dir}"
)
return files[0]
def copy_to_dist_dir(source_file, dist_dir, target_file):
os.makedirs(dist_dir, exist_ok=True)
target_path = f"{dist_dir}/{target_file}"
print(f"Copying to: {target_path}")
shutil.copy(source_file, target_path)
return target_path
def test_install(package_file, package_name, test_cmd, remove_test=True):
distro, distro_like, _distro_version = env.get_linux_distro()
if not distro_like:
distro_like = distro
install_base = None
list_cmd = None
remove_base = None
if "debian" in distro_like:
install_base = ["apt", "install", "-f", "-y"]
remove_base = ["apt", "remove", "-y"]
list_cmd = ["dpkg", "-L", package_name]
elif "fedora" in distro_like:
install_base = ["dnf", "install", "-y"]
remove_base = ["dnf", "remove", "-y"]
list_cmd = ["rpm", "-ql", package_name]
elif "opensuse" in distro_like:
install_base = ["zypper", "--no-gpg-checks", "install", "-y"]
remove_base = ["zypper", "remove", "-y"]
list_cmd = ["rpm", "-ql", package_name]
elif "arch" in distro_like:
install_base = ["pacman", "-U", "--noconfirm"]
remove_base = ["pacman", "-R", "--noconfirm"]
list_cmd = ["pacman", "-Ql", package_name]
else:
raise RuntimeError(f"Linux distro not yet supported: {distro}")
has_sudo = cmd_utils.has_command("sudo")
sudo = ["sudo"] if has_sudo else []
print("Testing installation...")
cmd_utils.run(
sudo + install_base + [f"./{package_file}"],
check=True,
print_cmd=True,
)
print("Listing installed files...")
cmd_utils.run(sudo + list_cmd, check=True, print_cmd=True)
try:
cmd_utils.run(test_cmd, shell=True, check=True, print_cmd=True)
except Exception:
raise RuntimeError("Unable to verify version")
finally:
if remove_test:
cmd_utils.run(
sudo + remove_base + [package_name], check=True, print_cmd=True
)
else:
print("Leaving test package installed")
print("Installation test passed")
def is_package_available(package):
distro, distro_like, _distro_version = env.get_linux_distro()
if not distro_like:
distro_like = distro
if "debian" in distro_like:
command = ["apt-cache", "show", package]
elif "fedora" in distro_like:
command = ["dnf", "info", package]
elif "opensuse" in distro_like:
command = ["zypper", "info", package]
elif "arch" in distro_like:
command = ["pacman", "-Si", package]
else:
raise RuntimeError(f"Linux distro not yet supported: {distro}")
result = cmd_utils.run(command, check=False, print_cmd=True, get_output=True)
if result.stderr:
print(result.stderr, file=sys.stderr)
return result.returncode == 0

View File

@ -1,91 +0,0 @@
# Deskflow -- mouse and keyboard sharing utility
# Copyright (C) 2024 Symless Ltd.
#
# This package is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# found in the file LICENSE that should have accompanied this file.
#
# This package is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os, sys
import lib.cmd_utils as cmd_utils
import lib.env as env
build_dir = "build/meson"
def meson_venv_bin():
if not env.in_venv():
raise RuntimeError("Not in a virtual environment")
return os.path.join(os.path.dirname(sys.executable), "meson")
def setup(no_system_list, static_list):
cmd = [meson_venv_bin(), "setup", build_dir]
# TODO: These special Windows exceptions should probably be in Meson
# or somewhere other than this script, as it's a bit hacky.
if env.is_windows():
cmd.append("-Dsystem-gtest=false")
cmd.append("-Dsystem-tomlplusplus=false")
cmd.append("-Dsystem-cli11=false")
for subproject in no_system_list or []:
cmd.append(f"-Dsystem-{subproject}=false")
# This might be a bit rude, but Meson seems to cache a lot (like CMake),
# so wiping every time is the easiest way to ensure that the build is clean.
# Plus, the way we're using Meson (at the moment) is just for satisfying
# dependencies, so this script is run infrequently enough to not matter.
if os.path.exists(build_dir):
cmd.append("--wipe")
cmd_utils.run(cmd, print_cmd=True)
for subproject in static_list or []:
static_subproject(subproject)
def static_subproject(subproject):
if subproject == "libportal":
# HACK: This is a bit horrible. Ideally, Meson would take care of applying this patch,
# but it only seems to copy the .diff over and not apply the patch.
#
# Important: Static linking is not intended for package maintainers, only for beta testers.
# Static linking is also pretty horrible, but many distros will be slow to pick up 0.8.x
# which has input capture support. The sooner we can remove this patching code the better.
cmd_utils.run(
[
"patch",
"-d",
"subprojects/libportal",
"-p1",
"-i",
"static-lib.diff",
],
print_cmd=True,
check=False,
)
else:
raise RuntimeError(f"Unknown subproject: {subproject}")
def compile():
cmd_utils.run([meson_venv_bin(), "compile", "-C", build_dir], print_cmd=True)
def install():
cmd = [meson_venv_bin(), "install", "-C", build_dir]
has_sudo = cmd_utils.has_command("sudo")
if has_sudo:
cmd.insert(0, "sudo")
cmd_utils.run(cmd, print_cmd=True)

View File

@ -1,88 +0,0 @@
# Deskflow -- mouse and keyboard sharing utility
# Copyright (C) 2024 Symless Ltd.
#
# This package is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# found in the file LICENSE that should have accompanied this file.
#
# This package is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os, sys
import lib.cmd_utils as cmd_utils
import glob
class Qt:
def __init__(
self, mirror_url, version, base_dir, modules, os_name, compiler, tool_dir
):
self.mirror_url = mirror_url
self.version = version
self.base_dir = base_dir
self.modules = modules
self.os_name = os_name
self.compiler = compiler
self.tool_dir = tool_dir
self.dir_pattern = f"{self.base_dir}{os.sep}{self.version}*/{self.tool_dir}"
def get_install_dir(self):
match = glob.glob(self.dir_pattern)
return os.path.abspath(match[0]) if match else None
def install(self):
"""Install Qt."""
if self.get_install_dir():
print(f"Skipping Qt, already installed at: {self.dir_pattern}")
return
args = [sys.executable, "-m", "aqt", "install-qt"]
args.extend(["--outputdir", self.base_dir])
args.extend(["--base", self.mirror_url])
args.extend([self.os_name, "desktop", str(self.version), self.compiler])
if self.modules:
args.extend(["-m"] + self.modules)
print(args)
cmd_utils.run(
args,
print_cmd=True,
)
if not self.get_install_dir():
raise RuntimeError(
f"Qt was not installed, path not found: {self.dir_pattern}"
)
class WindowsQt(Qt):
def __init__(self, mirror_url, version, base_dir, modules):
super().__init__(
mirror_url,
version,
base_dir,
modules,
"windows",
"win64_msvc2019_64",
"msvc2019_64",
)
class MacQt(Qt):
def __init__(self, mirror_url, version, base_dir, modules):
super().__init__(
mirror_url,
version,
base_dir,
modules,
"mac",
"clang_64",
"macos",
)

View File

@ -1,65 +0,0 @@
# Deskflow -- mouse and keyboard sharing utility
# Copyright (C) 2024 Symless Ltd.
#
# This package is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# found in the file LICENSE that should have accompanied this file.
#
# This package is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os
import git # type: ignore
import lib.env as env
import lib.cmd_utils as cmd_utils
GIT_REPO = "https://github.com/microsoft/vcpkg.git"
def install(ci_env):
vcpkg_bin = ensure_vcpkg(ci_env)
cmd_utils.run([vcpkg_bin, "install"], print_cmd=True)
def ensure_vcpkg(ci_env):
# Don't use the local vcpkg if we're in CI, since this makes caching complicated.
if not ci_env and cmd_utils.has_command("vcpkg"):
print("Using system vcpkg")
return "vcpkg"
if not os.path.exists("vcpkg"):
get_vcpkg()
else:
print("Updating vcpkg...")
repo = git.Repo("vcpkg")
repo.remotes.origin.pull()
if env.is_windows():
vcpkg_bin = "vcpkg/vcpkg.exe"
else:
vcpkg_bin = "vcpkg/vcpkg"
if not os.path.exists(vcpkg_bin):
raise RuntimeError(f"Path not found: {vcpkg_bin}")
return vcpkg_bin
def get_vcpkg():
print("Downloading vcpkg...")
git.Repo.clone_from(GIT_REPO, "vcpkg")
os.chdir("vcpkg")
try:
if env.is_windows():
cmd_utils.run("bootstrap-vcpkg.bat", shell=True, print_cmd=True)
else:
cmd_utils.run("./bootstrap-vcpkg.sh", shell=True, print_cmd=True)
finally:
os.chdir("..")

View File

@ -196,36 +196,6 @@ class WindowsPackager:
run_codesign(path, cert_base64, cert_password)
class WindowsChoco:
"""Chocolatey for Windows."""
def ensure_choco_installed(self):
if cmd_utils.has_command("choco"):
return
if not cmd_utils.has_command("winget"):
print(
"The winget command was not found, please install Chocolatey manually",
file=sys.stderr,
)
sys.exit(1)
print("The choco command was not found, installing Chocolatey...")
cmd_utils.run(
"winget install chocolatey",
check=False,
shell=True,
print_cmd=True,
)
if not cmd_utils.has_command("choco"):
print(
"The choco command was still not found, please re-run this script...",
file=sys.stderr,
)
sys.exit(1)
class WindowsService:
def __init__(self, script, args):
self.script = script

View File

@ -1,78 +0,0 @@
#!/usr/bin/env python3
# Deskflow -- mouse and keyboard sharing utility
# Copyright (C) 2024 Symless Ltd.
#
# This package is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# found in the file LICENSE that should have accompanied this file.
#
# This package is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import lib.env as env
env.ensure_in_venv(__file__)
import sys, argparse
import lib.fs as fs
from cmakelang.format.__main__ import main as cmake_format_main # type: ignore
INCLUDE_FILES = [
"*.cmake",
"CMakeLists.txt",
]
EXCLUDE_DIRS = [
"build",
".venv",
"deps",
"subprojects",
]
def main():
"""
Cross-platform equivalent of using find and xargs with cmake-format.
Lints by performing a dry run (--check) which fails when formatting is needed.
"""
parser = argparse.ArgumentParser()
parser.add_argument(
"-f",
"--format",
action="store_true",
help="In-place format all files",
)
args = parser.parse_args()
cmd_args = ["--in-place"] if args.format else ["--check"]
files_recursive = fs.find_files(".", INCLUDE_FILES, EXCLUDE_DIRS)
if args.format:
print("Formatting files with CMake formatter:")
else:
print("Checking files with CMake formatter:")
for file in files_recursive:
print(file)
if files_recursive:
sys.argv = [""] + cmd_args + files_recursive
result = cmake_format_main()
if result == 0:
print("CMake lint passed")
sys.exit(result)
else:
print("No CMake files found to process.", file=sys.stderr)
sys.exit(0)
if __name__ == "__main__":
main()

View File

@ -21,7 +21,6 @@ env.ensure_in_venv(__file__)
import argparse
import platform
from lib.linux import PackageType
from dotenv import load_dotenv # type: ignore
ENV_FILE = ".env"
@ -29,13 +28,15 @@ DEFAULT_PRODUCT_NAME = "Deskflow"
DEFAULT_FILENAME_BASE = "deskflow"
DEFAULT_PROJECT_BUILD_DIR = "build"
DEFAULT_DIST_DIR = "dist"
DEFAULT_TEST_CMD = "deskflow-server --version"
DEFAULT_PACKAGE_NAME = "deskflow"
VERSION_FILE = "VERSION"
def main():
parser = argparse.ArgumentParser()
parser.add_argument(
"--package-version",
help="Set the Package Version",
required=True)
parser.add_argument(
"--leave-test-installed",
action="store_true",
@ -47,38 +48,19 @@ def main():
package(
DEFAULT_FILENAME_BASE,
get_app_version(VERSION_FILE),
DEFAULT_PROJECT_BUILD_DIR,
DEFAULT_DIST_DIR,
DEFAULT_TEST_CMD,
DEFAULT_PRODUCT_NAME,
DEFAULT_PACKAGE_NAME,
leave_test_installed=args.leave_test_installed,
version=args.package_version,
)
def get_app_version(filename):
"""
Returns the version either from the env var, or from the version file.
"""
version = env.get_env("DESKFLOW_VERSION", required=False)
if version:
return version
with open(filename, "r") as f:
return f.read().strip()
def package(
filename_prefix,
version,
project_build_dir,
dist_dir,
test_cmd,
product_name,
package_name,
version,
source_dir=None,
leave_test_installed=False,
):
filename_base = get_filename_base(version, filename_prefix)
print(f"Package filename base: {filename_base}")
@ -89,50 +71,27 @@ def package(
mac_package(
filename_base, source_dir, project_build_dir, dist_dir, product_name
)
elif env.is_linux():
linux_package(
filename_base,
filename_prefix,
dist_dir,
test_cmd,
package_name,
version,
leave_test_installed,
)
else:
raise RuntimeError(f"Unsupported platform: {env.get_os()}")
def get_filename_base(version, prefix, use_linux_distro=True):
def get_filename_base(version, prefix):
os = env.get_os()
machine = platform.machine().lower()
os_part = os
if os == "linux" and use_linux_distro:
distro_name, _distro_like, distro_version = env.get_linux_distro()
if not distro_name:
raise RuntimeError("Failed to detect Linux distro")
if distro_version:
version_for_filename = distro_version.replace(".", "-")
os_part = f"{distro_name}-{version_for_filename}"
else:
os_part = distro_name
# For consistency with existing filenames, we'll use 'amd64' instead of 'x86_64'.
# Also, that's what Linux distros tend to call that architecture anyway.
if machine == "x86_64":
machine = "amd64"
else:
if os == "windows":
# Some Windows users get confused by 'amd64' and think it's 'arm64',
# so we'll use Intel's 'x64' branding (even though it's wrong).
# Also replace 'x86_64' with 'x64' for consistency.
os_part= "win"
if machine == "amd64" or machine == "x86_64":
machine = "x64"
elif os == "mac":
os_part = "macos"
# Add '-' between our name parts we do not want spaces in the filename
return f"{prefix}-{version}-{os_part}-{machine}"
# Underscore is used to delimit different parts of the filename (e.g. version, OS, etc).
# Dashes are used to delimit spaces, e.g. "debian-trixie" for "Debian Trixie".
return f"{prefix}_{version}_{os_part}_{machine}"
def windows_package(filename_base, project_build_dir, dist_dir):
@ -146,41 +105,5 @@ def mac_package(filename_base, source_dir, project_build_dir, dist_dir, product_
mac.package(filename_base, source_dir, project_build_dir, dist_dir, product_name)
def linux_package(
filename_base,
filename_prefix,
dist_dir,
test_cmd,
package_name,
version,
leave_test_installed,
):
import lib.linux as linux
extra_packages = env.get_env_bool("LINUX_EXTRA_PACKAGES", False)
linux.package(
filename_base,
dist_dir,
test_cmd,
package_name,
PackageType.DISTRO,
leave_test_installed,
)
if extra_packages:
filename_base = get_filename_base(
version, filename_base, use_linux_distro=False
)
linux.package(
filename_prefix,
dist_dir,
test_cmd,
package_name,
PackageType.TGZ,
)
if __name__ == "__main__":
main()

View File

@ -4,13 +4,11 @@ version = "0.0.1"
description = "Scripts to assist with development of Deskflow"
requires-python = ">=3.9"
dependencies = [
"cmake_format",
"clang-format",
"python-dotenv",
"pyyaml",
"dmgbuild; sys_platform == 'darwin'",
"aqtinstall; sys_platform == 'win32' or sys_platform == 'darwin'",
"colorama",
"meson",
"gitpython",
"psutil",
]

View File

@ -1,82 +0,0 @@
#!/usr/bin/env python3
# Deskflow -- mouse and keyboard sharing utility
# Copyright (C) 2024 Symless Ltd.
#
# This package is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# found in the file LICENSE that should have accompanied this file.
#
# This package is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import lib.env as env
env.ensure_in_venv(__file__)
import argparse, os, sys
import lib.cmd_utils as cmd_utils
import lib.colors as colors
valgrind_bin = "valgrind"
def main():
parser = argparse.ArgumentParser()
parser.add_argument("--unit-tests", action="store_true")
parser.add_argument("--integ-tests", action="store_true")
parser.add_argument(
"--filter-file",
type=str,
help="Takes the base filename without extension and uses it as a filter",
)
parser.add_argument(
"--ignore-return-code",
action="store_true",
help="Ignore the return code of the test command",
)
parser.add_argument(
"--valgrind",
action="store_true",
help="Run the test command with valgrind",
)
args = parser.parse_args()
binary = get_binary_path(args)
if args.filter_file:
file_base = os.path.basename(args.filter_file)
without_ext = os.path.splitext(file_base)[0]
command = [binary, f"--gtest_filter={without_ext}*"]
else:
command = [binary]
if args.valgrind:
if not cmd_utils.has_command(valgrind_bin):
print(f"{colors.ERROR_TEXT} {valgrind_bin} not found")
sys.exit(1)
command = [valgrind_bin] + command
result = cmd_utils.run(command, print_cmd=True, check=False)
if not args.ignore_return_code:
sys.exit(result.returncode)
def get_binary_path(args):
base_dir = "./build/bin"
if args.unit_tests:
return f"{base_dir}/unittests"
elif args.integ_tests:
return f"{base_dir}/integtests"
else:
raise RuntimeError("No test type specified")
if __name__ == "__main__":
main()

View File

@ -3,7 +3,7 @@ sonar.projectKey=deskflow_deskflow
sonar.sources=scripts,src/cmd,src/gui,src/lib
sonar.tests=src/test
sonar.exclusions=subprojects/**,build/**
sonar.coverage.exclusions=subprojects/**,scripts/**,src/test/**
sonar.coverage.exclusions=subprojects/**,scripts/**,src/test/**,src/gui/**
sonar.cpd.exclusions=**/*Test*.cpp
sonar.host.url=https://sonarcloud.io
sonar.coverageReportPaths=${{ steps.coverage-paths.outputs.csv }}

View File

@ -14,7 +14,6 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
add_subdirectory(deskflowd)
if(BUILD_UNIFIED)
add_subdirectory(deskflow-core)
@ -23,4 +22,5 @@ else()
add_subdirectory(deskflows)
endif(BUILD_UNIFIED)
add_subdirectory(deskflow-legacy)
## Only used on windows
add_subdirectory(deskflowd)

View File

@ -1,4 +1,5 @@
# Deskflow -- mouse and keyboard sharing utility
# Copyright (C) 2024 Chris Rizzitello <sithlord48@gmail.com>
# Copyright (C) 2012-2024 Symless Ltd.
# Copyright (C) 2009-2012 Nick Bolton
#
@ -15,14 +16,15 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
set(target ${CORE_BINARY_NAME})
set(sources ${target}.cpp)
add_executable(${target} "${target}.cpp")
if(WIN32)
list(APPEND sources ${target}.exe.manifest
${PROJECT_BINARY_DIR}/src/version.rc)
target_sources(${target} PRIVATE
"${target}.exe.manifest"
"${PROJECT_BINARY_DIR}/src/version.rc"
)
endif()
add_executable(${target} ${sources})
target_link_libraries(
${target}
arch

View File

@ -26,27 +26,26 @@
#include "arch/win32/ArchMiscWindows.h"
#endif
void showHelp() {
std::cout << "Usage: " CORE_BINARY_NAME " <server | client> [...options]"
<< std::endl;
std::cout << "server - start as a server (" << SERVER_BINARY_NAME << ")"
<< std::endl;
std::cout << "client - start as a client (" << CLIENT_BINARY_NAME << ")"
<< std::endl;
std::cout << "use " CORE_BINARY_NAME
" <server|client> --help for more information."
<< std::endl;
void showHelp()
{
std::cout << "Usage: " CORE_BINARY_NAME " <server | client> [...options]" << std::endl;
std::cout << "server - start as a server (" << SERVER_BINARY_NAME << ")" << std::endl;
std::cout << "client - start as a client (" << CLIENT_BINARY_NAME << ")" << std::endl;
std::cout << "use " CORE_BINARY_NAME " <server|client> --help for more information." << std::endl;
}
bool isServer(int argc, char **argv) {
bool isServer(int argc, char **argv)
{
return (argc > 1 && argv[1] == std::string("server"));
}
bool isClient(int argc, char **argv) {
bool isClient(int argc, char **argv)
{
return (argc > 1 && argv[1] == std::string("client"));
}
int main(int argc, char **argv) {
int main(int argc, char **argv)
{
#if SYSAPI_WIN32
ArchMiscWindows::setInstanceWin32(GetModuleHandle(NULL));
#endif

View File

@ -1,45 +0,0 @@
# Deskflow -- mouse and keyboard sharing utility
# Copyright (C) 2012-2024 Symless Ltd.
# Copyright (C) 2009-2012 Nick Bolton
#
# This package is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# found in the file LICENSE that should have accompanied this file.
#
# This package is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
set(target ${LEGACY_BINARY_NAME})
file(GLOB headers "*.h")
file(GLOB sources "*.cpp")
if(WIN32)
list(APPEND sources ${PROJECT_BINARY_DIR}/src/version.rc)
endif()
add_executable(${target} ${sources})
target_link_libraries(
${target}
app
arch
base
client
io
ipc
mt
net
platform
server
${libs})
if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
install(TARGETS ${target} DESTINATION ${DESKFLOW_BUNDLE_BINARY_DIR})
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
install(TARGETS ${target} DESTINATION bin)
endif()

View File

@ -1,33 +0,0 @@
/*
* Deskflow -- mouse and keyboard sharing utility
* Copyright (C) 2014-2016 Symless Ltd.
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "arch/Arch.h"
#include "deskflow/ToolApp.h"
#if SYSAPI_WIN32
#include "arch/win32/ArchMiscWindows.h"
#endif
int main(int argc, char **argv) {
#if SYSAPI_WIN32
// record window instance for tray icon, etc
ArchMiscWindows::setInstanceWin32(GetModuleHandle(NULL));
#endif
ToolApp app;
return app.run(argc, argv);
}

View File

@ -1,4 +1,5 @@
# Deskflow -- mouse and keyboard sharing utility
# Copyright (C) 2024 Chris Rizzitello <sithlord48@gmail.com>
# Copyright (C) 2012-2024 Symless Ltd.
# Copyright (C) 2009-2012 Nick Bolton
#
@ -16,39 +17,35 @@
set(client_source_name "deskflowc")
set(target ${CLIENT_BINARY_NAME})
set(sources ${client_source_name}.cpp)
if(WIN32)
file(GLOB arch_headers "MSWindows*.h")
file(GLOB arch_sources "MSWindows*.cpp")
list(
APPEND
sources
resource.h
set(PLATFORM_SOURCES
${client_source_name}.exe.manifest
${client_source_name}.ico
${client_source_name}.rc
MSWindowsClientTaskBarReceiver.cpp
MSWindowsClientTaskBarReceiver.h
resource.h
tb_error.ico
tb_idle.ico
tb_run.ico
tb_wait.ico
${client_source_name}.exe.manifest
${PROJECT_BINARY_DIR}/src/version.rc)
${PROJECT_BINARY_DIR}/src/version.rc
)
elseif(APPLE)
file(GLOB arch_headers "OSX*.h")
file(GLOB arch_sources "OSX*.cpp")
set(PLATFORM_SOURCES
OSXClientTaskBarReceiver.cpp
OSXClientTaskBarReceiver.h
)
elseif(UNIX)
file(GLOB arch_headers "XWindows*.h")
file(GLOB arch_sources "XWindows*.cpp")
set(PLATFORM_SOURCES
XWindowsClientTaskBarReceiver.cpp
XWindowsClientTaskBarReceiver.h
)
endif()
list(APPEND sources ${arch_sources})
list(APPEND headers ${arch_headers})
add_executable(${target} ${PLATFORM_SOURCES} "${client_source_name}.cpp")
if(ADD_HEADERS_TO_SOURCES)
list(APPEND sources ${headers})
endif()
add_executable(${target} ${sources})
target_link_libraries(
${target}
arch

View File

@ -34,16 +34,18 @@
//
const UINT MSWindowsClientTaskBarReceiver::s_stateToIconID[kMaxState] = {
IDI_TASKBAR_NOT_RUNNING, IDI_TASKBAR_NOT_WORKING, IDI_TASKBAR_NOT_CONNECTED,
IDI_TASKBAR_NOT_CONNECTED, IDI_TASKBAR_CONNECTED};
IDI_TASKBAR_NOT_RUNNING, IDI_TASKBAR_NOT_WORKING, IDI_TASKBAR_NOT_CONNECTED, IDI_TASKBAR_NOT_CONNECTED,
IDI_TASKBAR_CONNECTED
};
MSWindowsClientTaskBarReceiver::MSWindowsClientTaskBarReceiver(
HINSTANCE appInstance, const BufferedLogOutputter *logBuffer,
IEventQueue *events)
HINSTANCE appInstance, const BufferedLogOutputter *logBuffer, IEventQueue *events
)
: ClientTaskBarReceiver(events),
m_appInstance(appInstance),
m_window(NULL),
m_logBuffer(logBuffer) {
m_logBuffer(logBuffer)
{
for (UInt32 i = 0; i < kMaxState; ++i) {
m_icon[i] = loadIcon(s_stateToIconID[i]);
}
@ -58,9 +60,13 @@ MSWindowsClientTaskBarReceiver::MSWindowsClientTaskBarReceiver(
ARCH->addReceiver(this);
}
MSWindowsClientTaskBarReceiver::~MSWindowsClientTaskBarReceiver() { cleanup(); }
MSWindowsClientTaskBarReceiver::~MSWindowsClientTaskBarReceiver()
{
cleanup();
}
void MSWindowsClientTaskBarReceiver::cleanup() {
void MSWindowsClientTaskBarReceiver::cleanup()
{
ARCH->removeReceiver(this);
for (UInt32 i = 0; i < kMaxState; ++i) {
deleteIcon(m_icon[i]);
@ -69,7 +75,8 @@ void MSWindowsClientTaskBarReceiver::cleanup() {
destroyWindow();
}
void MSWindowsClientTaskBarReceiver::showStatus() {
void MSWindowsClientTaskBarReceiver::showStatus()
{
// create the window
createWindow();
@ -126,7 +133,8 @@ void MSWindowsClientTaskBarReceiver::showStatus() {
}
}
void MSWindowsClientTaskBarReceiver::runMenu(int x, int y) {
void MSWindowsClientTaskBarReceiver::runMenu(int x, int y)
{
// do popup menu. we need a window to pass to TrackPopupMenu().
// the SetForegroundWindow() and SendMessage() calls around
// TrackPopupMenu() are to get the menu to be dismissed when
@ -137,11 +145,9 @@ void MSWindowsClientTaskBarReceiver::runMenu(int x, int y) {
HMENU menu = GetSubMenu(m_menu, 0);
SetMenuDefaultItem(menu, IDC_TASKBAR_STATUS, FALSE);
HMENU logLevelMenu = GetSubMenu(menu, 3);
CheckMenuRadioItem(
logLevelMenu, 0, 6, CLOG->getFilter() - kERROR, MF_BYPOSITION);
int n = TrackPopupMenu(
menu, TPM_NONOTIFY | TPM_RETURNCMD | TPM_LEFTBUTTON | TPM_RIGHTBUTTON, x,
y, 0, m_window, NULL);
CheckMenuRadioItem(logLevelMenu, 0, 6, CLOG->getFilter() - kERROR, MF_BYPOSITION);
int n =
TrackPopupMenu(menu, TPM_NONOTIFY | TPM_RETURNCMD | TPM_LEFTBUTTON | TPM_RIGHTBUTTON, x, y, 0, m_window, NULL);
SendMessage(m_window, WM_NULL, 0, 0);
// perform the requested operation
@ -192,19 +198,22 @@ void MSWindowsClientTaskBarReceiver::runMenu(int x, int y) {
}
}
void MSWindowsClientTaskBarReceiver::primaryAction() { showStatus(); }
void MSWindowsClientTaskBarReceiver::primaryAction()
{
showStatus();
}
const IArchTaskBarReceiver::Icon
MSWindowsClientTaskBarReceiver::getIcon() const {
const IArchTaskBarReceiver::Icon MSWindowsClientTaskBarReceiver::getIcon() const
{
return static_cast<Icon>(m_icon[getStatus()]);
}
void MSWindowsClientTaskBarReceiver::copyLog() const {
void MSWindowsClientTaskBarReceiver::copyLog() const
{
if (m_logBuffer != NULL) {
// collect log buffer
String data;
for (BufferedLogOutputter::const_iterator index = m_logBuffer->begin();
index != m_logBuffer->end(); ++index) {
for (BufferedLogOutputter::const_iterator index = m_logBuffer->begin(); index != m_logBuffer->end(); ++index) {
data += *index;
data += "\n";
}
@ -220,26 +229,29 @@ void MSWindowsClientTaskBarReceiver::copyLog() const {
}
}
void MSWindowsClientTaskBarReceiver::onStatusChanged() {
void MSWindowsClientTaskBarReceiver::onStatusChanged()
{
if (IsWindowVisible(m_window)) {
showStatus();
}
}
HICON
MSWindowsClientTaskBarReceiver::loadIcon(UINT id) {
HANDLE icon = LoadImage(
m_appInstance, MAKEINTRESOURCE(id), IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR);
MSWindowsClientTaskBarReceiver::loadIcon(UINT id)
{
HANDLE icon = LoadImage(m_appInstance, MAKEINTRESOURCE(id), IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR);
return static_cast<HICON>(icon);
}
void MSWindowsClientTaskBarReceiver::deleteIcon(HICON icon) {
void MSWindowsClientTaskBarReceiver::deleteIcon(HICON icon)
{
if (icon != NULL) {
DestroyIcon(icon);
}
}
void MSWindowsClientTaskBarReceiver::createWindow() {
void MSWindowsClientTaskBarReceiver::createWindow()
{
// ignore if already created
if (m_window != NULL) {
return;
@ -247,9 +259,9 @@ void MSWindowsClientTaskBarReceiver::createWindow() {
// get the status dialog
m_window = CreateDialogParam(
m_appInstance, MAKEINTRESOURCE(IDD_TASKBAR_STATUS), NULL,
(DLGPROC)&MSWindowsClientTaskBarReceiver::staticDlgProc,
reinterpret_cast<LPARAM>(static_cast<void *>(this)));
m_appInstance, MAKEINTRESOURCE(IDD_TASKBAR_STATUS), NULL, (DLGPROC)&MSWindowsClientTaskBarReceiver::staticDlgProc,
reinterpret_cast<LPARAM>(static_cast<void *>(this))
);
// window should appear on top of everything, including (especially)
// the task bar.
@ -261,7 +273,8 @@ void MSWindowsClientTaskBarReceiver::createWindow() {
ArchTaskBarWindows::addDialog(m_window);
}
void MSWindowsClientTaskBarReceiver::destroyWindow() {
void MSWindowsClientTaskBarReceiver::destroyWindow()
{
if (m_window != NULL) {
ArchTaskBarWindows::removeDialog(m_window);
DestroyWindow(m_window);
@ -269,8 +282,8 @@ void MSWindowsClientTaskBarReceiver::destroyWindow() {
}
}
BOOL MSWindowsClientTaskBarReceiver::dlgProc(
HWND hwnd, UINT msg, WPARAM wParam, LPARAM) {
BOOL MSWindowsClientTaskBarReceiver::dlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM)
{
switch (msg) {
case WM_INITDIALOG:
// use default focus
@ -286,14 +299,13 @@ BOOL MSWindowsClientTaskBarReceiver::dlgProc(
return FALSE;
}
BOOL CALLBACK MSWindowsClientTaskBarReceiver::staticDlgProc(
HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
BOOL CALLBACK MSWindowsClientTaskBarReceiver::staticDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
// if msg is WM_INITDIALOG, extract the MSWindowsClientTaskBarReceiver*
// and put it in the extra window data then forward the call.
MSWindowsClientTaskBarReceiver *self = NULL;
if (msg == WM_INITDIALOG) {
self = static_cast<MSWindowsClientTaskBarReceiver *>(
reinterpret_cast<void *>(lParam));
self = static_cast<MSWindowsClientTaskBarReceiver *>(reinterpret_cast<void *>(lParam));
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)lParam);
} else {
// get the extra window data and forward the call
@ -311,16 +323,12 @@ BOOL CALLBACK MSWindowsClientTaskBarReceiver::staticDlgProc(
}
}
IArchTaskBarReceiver *createTaskBarReceiver(
const BufferedLogOutputter *logBuffer, IEventQueue *events) {
IArchTaskBarReceiver *createTaskBarReceiver(const BufferedLogOutputter *logBuffer, IEventQueue *events)
{
ArchMiscWindows::setIcons(
(HICON)LoadImage(
ArchMiscWindows::instanceWin32(), MAKEINTRESOURCE(IDI_DESKFLOW),
IMAGE_ICON, 32, 32, LR_SHARED),
(HICON)LoadImage(
ArchMiscWindows::instanceWin32(), MAKEINTRESOURCE(IDI_DESKFLOW),
IMAGE_ICON, 16, 16, LR_SHARED));
(HICON)LoadImage(ArchMiscWindows::instanceWin32(), MAKEINTRESOURCE(IDI_DESKFLOW), IMAGE_ICON, 32, 32, LR_SHARED),
(HICON)LoadImage(ArchMiscWindows::instanceWin32(), MAKEINTRESOURCE(IDI_DESKFLOW), IMAGE_ICON, 16, 16, LR_SHARED)
);
return new MSWindowsClientTaskBarReceiver(
MSWindowsScreen::getWindowInstance(), logBuffer, events);
return new MSWindowsClientTaskBarReceiver(MSWindowsScreen::getWindowInstance(), logBuffer, events);
}

View File

@ -27,10 +27,10 @@ class BufferedLogOutputter;
class IEventQueue;
//! Implementation of ClientTaskBarReceiver for Microsoft Windows
class MSWindowsClientTaskBarReceiver : public ClientTaskBarReceiver {
class MSWindowsClientTaskBarReceiver : public ClientTaskBarReceiver
{
public:
MSWindowsClientTaskBarReceiver(
HINSTANCE, const BufferedLogOutputter *, IEventQueue *events);
MSWindowsClientTaskBarReceiver(HINSTANCE, const BufferedLogOutputter *, IEventQueue *events);
virtual ~MSWindowsClientTaskBarReceiver();
// IArchTaskBarReceiver overrides
@ -53,8 +53,7 @@ private:
void destroyWindow();
BOOL dlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
static BOOL CALLBACK
staticDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
static BOOL CALLBACK staticDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
private:
HINSTANCE m_appInstance;

View File

@ -23,34 +23,39 @@
// OSXClientTaskBarReceiver
//
OSXClientTaskBarReceiver::OSXClientTaskBarReceiver(
const BufferedLogOutputter *, IEventQueue *events)
: ClientTaskBarReceiver(events) {
OSXClientTaskBarReceiver::OSXClientTaskBarReceiver(const BufferedLogOutputter *, IEventQueue *events)
: ClientTaskBarReceiver(events)
{
// add ourself to the task bar
ARCH->addReceiver(this);
}
OSXClientTaskBarReceiver::~OSXClientTaskBarReceiver() {
OSXClientTaskBarReceiver::~OSXClientTaskBarReceiver()
{
ARCH->removeReceiver(this);
}
void OSXClientTaskBarReceiver::showStatus() {
void OSXClientTaskBarReceiver::showStatus()
{
// do nothing
}
void OSXClientTaskBarReceiver::runMenu(int, int) {
void OSXClientTaskBarReceiver::runMenu(int, int)
{
// do nothing
}
void OSXClientTaskBarReceiver::primaryAction() {
void OSXClientTaskBarReceiver::primaryAction()
{
// do nothing
}
const IArchTaskBarReceiver::Icon OSXClientTaskBarReceiver::getIcon() const {
const IArchTaskBarReceiver::Icon OSXClientTaskBarReceiver::getIcon() const
{
return NULL;
}
IArchTaskBarReceiver *createTaskBarReceiver(
const BufferedLogOutputter *logBuffer, IEventQueue *events) {
IArchTaskBarReceiver *createTaskBarReceiver(const BufferedLogOutputter *logBuffer, IEventQueue *events)
{
return new OSXClientTaskBarReceiver(logBuffer, events);
}

View File

@ -24,7 +24,8 @@ class BufferedLogOutputter;
class IEventQueue;
//! Implementation of ClientTaskBarReceiver for OS X
class OSXClientTaskBarReceiver : public ClientTaskBarReceiver {
class OSXClientTaskBarReceiver : public ClientTaskBarReceiver
{
public:
OSXClientTaskBarReceiver(const BufferedLogOutputter *, IEventQueue *events);
virtual ~OSXClientTaskBarReceiver();

View File

@ -23,35 +23,39 @@
// CXWindowsClientTaskBarReceiver
//
CXWindowsClientTaskBarReceiver::CXWindowsClientTaskBarReceiver(
const BufferedLogOutputter *, IEventQueue *events)
: ClientTaskBarReceiver(events) {
CXWindowsClientTaskBarReceiver::CXWindowsClientTaskBarReceiver(const BufferedLogOutputter *, IEventQueue *events)
: ClientTaskBarReceiver(events)
{
// add ourself to the task bar
ARCH->addReceiver(this);
}
CXWindowsClientTaskBarReceiver::~CXWindowsClientTaskBarReceiver() {
CXWindowsClientTaskBarReceiver::~CXWindowsClientTaskBarReceiver()
{
ARCH->removeReceiver(this);
}
void CXWindowsClientTaskBarReceiver::showStatus() {
void CXWindowsClientTaskBarReceiver::showStatus()
{
// do nothing
}
void CXWindowsClientTaskBarReceiver::runMenu(int, int) {
void CXWindowsClientTaskBarReceiver::runMenu(int, int)
{
// do nothing
}
void CXWindowsClientTaskBarReceiver::primaryAction() {
void CXWindowsClientTaskBarReceiver::primaryAction()
{
// do nothing
}
const IArchTaskBarReceiver::Icon
CXWindowsClientTaskBarReceiver::getIcon() const {
const IArchTaskBarReceiver::Icon CXWindowsClientTaskBarReceiver::getIcon() const
{
return NULL;
}
IArchTaskBarReceiver *createTaskBarReceiver(
const BufferedLogOutputter *logBuffer, IEventQueue *events) {
IArchTaskBarReceiver *createTaskBarReceiver(const BufferedLogOutputter *logBuffer, IEventQueue *events)
{
return new CXWindowsClientTaskBarReceiver(logBuffer, events);
}

Some files were not shown because too many files have changed in this diff Show More