Skip to content

feat(linux): Linux platform foundation, Qt6 windowing, and packaging (Part 1/6) - #34

Merged
thtbee merged 2 commits into
thtbee:mainfrom
jochenkirstaetter:linux-1-build
Oct 20, 2026
Merged

thtbee merged 2 commits into
thtbee:mainfrom
jochenkirstaetter:linux-1-build

Conversation

@jochenkirstaetter

Copy link
Copy Markdown
Contributor

Summary

First slice of splitting the Linux desktop port (#12) into 6 focused, independently reviewable PRs as requested in #12 (review).

Every change outside desktop/app/src/linux/ and desktop/packaging/linux/ is strictly gated behind #[cfg(windows)] / #[cfg(target_os = "linux")] (#ifdef _WIN32 in C++) so existing Windows and shared code paths remain untouched.

What's in Part 1 (linux-1-build)

  • Build & CI:
    • Target-gate windows crate dependency in desktop/app/Cargo.toml and desktop/vcam/Cargo.toml; add Linux dependencies (libc, fuser).
    • Gate Win32 link libraries in desktop/app/build.rs and spikes/s1-qt-rust/build.rs (CARGO_CFG_TARGET_OS == "windows").
    • Update .github/workflows/ci.yml to build and test the full workspace (--workspace) on Linux with Qt 6.12 installed via jurplel/install-qt-action@v4.
  • Qt6 / C++ Windowing & Helpers:
    • Guard Win32/D3D11/DWM calls in desktop/app/cpp/native_window.cpp, desktop/app/cpp/app_helpers.cpp, and spikes/s1-qt-rust/cpp/* with #ifdef _WIN32 and provide Linux equivalents (QGuiApplication::screens() primary refresh rate, QClipboard image fallback, /proc/self/statm RSS reading).
  • Linux Platform Layer (desktop/app/src/linux/):
    • linux/mod.rs system probes (machine_guid, os_version, os_build_number, is_laptop, power_saver, system_dark, reduce_motion, work_area, secure_random), linux/elevated.rs (geteuid / pkexec), linux/icon.rs (embedded PNG writer), linux/net.rs (AF_NETLINK route address watcher), and compile-ready module stubs for the remaining submodules filled in Parts 2–6.
    • POSIX shm_open / mmap shared-memory frame backing in desktop/vcam/src/shm.rs.
  • CLI Linux Support (core/nectarlink-cli):
    • linux_watch process watcher (pidfd_open + /proc/<pid>/stat) for nectarlink-cli notify-when and DesktopDir IPC transport on Linux (flock lock detection + instance.sock wakeup).
  • Linux Packaging (desktop/packaging/linux/):
    • .deb, AppImage, and portable .tar.gz packaging scripts, .desktop launcher, and AppStream metadata (org.nectarlink.desktop.metainfo.xml).

Series Roadmap

  1. Part 1 (linux-1-build) — Build, CI, Qt6 windowing, linux/mod.rs foundation, CLI linux_watch, and packaging (this PR)
  2. Part 2 (linux-2-basics) — Clipboard, Freedesktop notifications (toast.rs, pc_notifications.rs), tray & hotkeys, autostart, shell, shortcuts, single-instance, widget, WoL, BLE beacon, and doctor checks
  3. Part 3 (linux-3-input) — Input injection (uinput / Wayland / X11), deck actions, frameless Wayland/X11 window move/resize filter, and window capture
  4. Part 4 (linux-4-media) — Audio (wpctl/pactl), low-latency PCM output, PC loopback audio stream, MPRIS (media_sessions.rs, smtc.rs), OpenH264/FFmpeg H.264 & MP4, phone/PC screen mirroring, v4l2loopback virtual camera, PipeWire/PulseAudio virtual microphone, Bluetooth HFP, and voice recording conversion
  5. Part 5 (linux-5-storage) — FUSE3 virtual filesystem (fuser) and file-manager sidebar bookmarks (gtk-3.0/bookmarks, user-places.xbel)
  6. Part 6 (linux-6-updater) — Linux HTTP client (curl), self-updater (.deb / .AppImage / .tar.gz), and setup uninstaller

@jochenkirstaetter

Copy link
Copy Markdown
Contributor Author

Hi @thtbee

This is the largest, one-off chunk to establish a clean cross-platform baseline.
Which would then most likely suit the macOS port by @saivinay1805 too.

Please give it a review and hit me with your feedback...

Cheers

@thtbee thtbee left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for splitting it up, this is much easier to go through. I compared the shared Rust files with main token by token, and the Windows code is unchanged apart from the cfg attributes.

Before it can go in:

  1. On Linux, desktop/vcam/src/shm.rs opens /dev/shm/nectarlink_shm_<name> with the OpenOptions defaults, so the file is 0644 after the usual umask and readable by every user on the PC, and the name is the same for everyone. Another user could read the live camera frames, or create that name first (as a file or a symlink) and have our process write into it or set_len it. Please create it 0600 with O_NOFOLLOW (OpenOptionsExt::mode and custom_flags), check after opening that it's ours, and put the user in the name or use $XDG_RUNTIME_DIR.
  2. compile_translations() in desktop/app/build.rs runs on every platform, so Windows builds now compile the .ts files and copy .qm files into target/<profile>, outside OUT_DIR. On Windows scripts/package.ps1 already does this and only ships finished languages, so please limit it to Linux.
  3. spikes/s1-qt-rust/build.rs adds -fuse-ld=bfd and a link path into .qt6-sysroot, and .gitignore gets /.qt6-sysroot/. That looks like a local setup and shouldn't be in the repo.
  4. This and #24 (macOS) conflict in 16 files. I'd like to merge #24 first, since it has had two rounds and is close, and then have this rebase onto it. #24 wraps the Windows-only parts in #[cfg(windows)] mod imp with one #[cfg(not(windows))] stub module, so macOS and Linux share the stubs until Linux replaces them in parts 2 to 6, and the Windows code stays in one block instead of an attribute on every item. Could you move to that layout when you rebase?

Smaller: stubs that return Err("stub") would reach the UI like that; "not supported on Linux yet" reads better. setup::remove returns Outcome::Done without removing anything and current_recording_stem always returns 2026-01-01 00:00, which is fine as placeholders if parts 4 and 6 replace them. linux/elevated.rs declares geteuid by hand while libc is already a dependency. The CI job installs ffmpeg and openh264 dev packages that part 1 doesn't seem to use yet.

@jochenkirstaetter

Copy link
Copy Markdown
Contributor Author

Hello @thtbee

Thanks for taking the time to look into that.
Going to address the feedback. However I'm concerned about 4. because this is a roundtrip, as #24 code changes are built on my original, larger code base of #12 which has now been broken up into 6 stacked PRs as per your request/suggestion. Meaning #24 is built on outdated code which is not supposed to be in the main branch yet.

Your suggestion inverts this situation, and probably the code of the next 5 PRs gets it straight for #24.

Same or very similar for the CI. It is currently based on the complete set of these 6 stacked PRs and will be much likely the same after all steps have been taken into consideration.

I'm going to run a deeper analysis against the other, follow-up branches and get back to you on this.

Again thanks, and no worries, we're going to untangle this. ✌️

Cheers

…(Part 1)

Signed-off-by: Jochen Kirstätter <7329802+jochenkirstaetter@users.noreply.github.com>
@jochenkirstaetter

jochenkirstaetter commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor Author

Hi @thtbee

First three remarks have been addressed, and I hope resolved as intended.

As for "the PR race" 😸 , this one has been aligned with #24 to keep it as simple and pain-free as possible to merge the code bases. Shared cross-platform files match PR #24 's exact structure, and parts 2-6 progressively layer Linux capabilities onto that structure.

Cheers

Both ports' CI jobs, link libraries and platform modules side by side; vcam keeps this branch's shm, which serves macOS too, instead of thtbee#24's stubs.

@thtbee thtbee left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Checked the new version: the shared memory is per user, 0600 and opened with O_NOFOLLOW with the owner checked, translations build on Linux only, the sysroot setup is gone, and the shared files use the same layout as #24. I merged main (with #24) into the branch: both ports' CI jobs, link libraries and module lines side by side, and vcam keeps your shm, which macOS now uses too instead of #24's stubs. CI is green on all three platforms. Thanks for reworking it.

Two small things for later parts: on Linux, a watched process always reports exit code 0 (notify-when), though the CLI can't know it there, so none would be more honest; and the /proc fallback in linux/net.rs includes /proc/net/arp, which changes all the time and would report network changes every few seconds. Also, when part 3 makes Linux windows frameless, CaptionButtons.qml needs Linux back in its visible check, since #24 shows the buttons on Windows only.

@thtbee
thtbee merged commit 0e561fb into thtbee:main Oct 20, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants