Skip to content

feat: add portrait mode, dynamic monitor positioning, and stream flow control - #1

Merged
neonjava merged 1 commit into
mainfrom
feat/portrait-dynamic-positioning-stream-control
Oct 31, 2026
Merged

neonjava merged 1 commit into
mainfrom
feat/portrait-dynamic-positioning-stream-control

Conversation

@neonjava

Copy link
Copy Markdown
Owner

Summary of Changes

This PR introduces portrait orientation support, dynamic monitor positioning, stream flow control to eliminate latency, and replaces hardcoded paths and coordinates with dynamic detection.

1. Dynamic Monitor Positioning & Portrait Support

  • Dynamic Headless Placement: Added --position [auto|left|right] and --transform [0|1|2|3] flags, plus a --portrait convenience shortcut.
  • Layer-Shell Compatibility: When positioning the virtual display on the left (--position left), the primary display is dynamically shifted to positive coordinates (e.g. 1080x0). This preserves strictly non-negative coordinate space across all outputs, preventing Wayland layer-shell daemons (such as swww for wallpaper and waybar) from clipping or failing to render.
  • Graceful Restoration: Automatically caches and restores the primary display's original coordinates upon display teardown.

2. Stream Flow Control & Latency Elimination

  • Capture Pacing: Paces staggered multi-worker capture intervals (frame_interval * num_workers) so workers evenly deliver the target FPS without overloading grim or Hyprland.
  • WebSocket Send Throttling: Regulates transmission intervals to match target FPS with a timeout, preventing TCP socket bufferbloat and latency backlog over ADB reverse connections.

3. Edge-to-Edge Fit & Orientation Controls

  • Android App: Updated AndroidManifest.xml to android:screenOrientation="fullSensor" and defaulted to FillBounds scaling to support any physical orientation.
  • Web Client: Enhanced HTML5 canvas styling with fixed 100vw/100vh fullscreen positioning and added an interactive Stretch Fit / Contain Aspect toggle.

4. Portability & Cleanup

  • Replaced all hardcoded paths and usernames in scripts/linuxextend.sh and scripts/install_apk.sh with portable BASH_SOURCE and standard environment variable fallbacks.
  • Updated scripts/switch_monitor.sh to dynamically detect monitor geometry, orientation, and focus center via hyprctl.
  • Made mDNS service advertising asynchronous (zeroconf) to prevent blocking server startup.

5. Testing & Validation

  • Ran full test suite: 13 passed (pytest tests/).
  • Audited diff for security: zero leaks of personal paths, private IPs, credentials, or machine identifiers.

… control

- Dynamic monitor positioning (--position auto|left|right) and rotation/transform support (--transform, --portrait)
- Non-negative coordinate shifting when placing displays on the left, keeping layer-shell daemons (waybar, swww) fully intact
- Multi-worker frame pacing and dynamic WebSocket transmission interval matching target FPS to eliminate TCP socket bufferbloat and lag
- Made scripts fully portable and dynamic without hardcoded user paths or monitor coordinates
- Added fullSensor orientation and FillBounds stretch toggle support to Android app and HTML5 web client
- Asynchronous mDNS registration thread to prevent startup blocking
@coderabbitai

coderabbitai Bot commented Oct 30, 2026

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 34984717-e001-4936-8de8-3ca34b766808
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@neonjava

Copy link
Copy Markdown
Owner Author

@codex review

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 30, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-30T16:13:04.379290Z a1f4d6b Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a1f4d6b15c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread scripts/linuxextend.sh
Comment on lines +99 to +100
if command -v systemd-run >/dev/null 2>&1; then
systemd-run --user --unit=linuxextend-server --working-directory="$INSTALL_DIR/server" python3 -u -m linuxextend "$@" >/dev/null 2>&1

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Fall back to nohup when the user service manager is unavailable

When systemd-run is installed but no user service manager is reachable, start now exits without launching the server. The installed command's help describes --user as “Run as user unit”; executable availability alone does not establish that this works. In the inspected environment, systemd-run --user ... /bin/true fails with Failed to connect to bus: No medium found. Because this invocation runs under set -e and suppresses its diagnostics, the existing nohup branch is never reached. Test whether service creation succeeds and fall back on failure.

Useful? React with 👍 / 👎.

Comment on lines +202 to 203
self._run_hyprctl("keyword", "monitor", f"{p_name},{p_w}x{p_h}@{p_r},0x0,{p_scale}")
return f"{p_w}x0"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Calculate right-side placement using the preserved monitor scale

For a primary monitor with scale other than 1, preserving p_scale while still positioning the headless output at the physical pixel width creates a gap between the displays. For example, a 3840-wide primary at scale 2 occupies 1920 logical units, but this places the tablet at x=3840. The Hyprland monitor documentation explicitly states that “The position is calculated with the scaled (and transformed) resolution.” Previously this branch forced scale 1, so its width calculation was consistent. Calculate the primary's logical width before returning the tablet position.

Useful? React with 👍 / 👎.

Comment thread scripts/linuxextend.sh
echo "$s_pid" > "$PID_FILE"
# Start server in background (using systemd-run if available, else nohup)
if command -v systemd-run >/dev/null 2>&1; then
systemd-run --user --unit=linuxextend-server --working-directory="$INSTALL_DIR/server" python3 -u -m linuxextend "$@" >/dev/null 2>&1

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve log access for the new systemd launch path

When the systemd branch is used, the server no longer writes to $LOG_FILE, but both cmd_logs() and the startup-failure diagnostic still read only that file. Consequently, linuxextend logs reports no log file on a fresh installation or follows stale output from an earlier nohup launch, and startup errors lose their Python diagnostics. Route the service output to the existing log file or update both readers to retrieve the unit's journal.

Useful? React with 👍 / 👎.

@neonjava
neonjava merged commit 177a237 into main Oct 31, 2026
1 check 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.

1 participant