Repository navigation
feat: add portrait mode, dynamic monitor positioning, and stream flow control #1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,11 +5,11 @@ | |
|
|
||
| set -eo pipefail | ||
|
|
||
| INSTALL_DIR="/home/neonjava/LinuxExtend" | ||
| LOG_DIR="$HOME/.local/state/linuxextend" | ||
| INSTALL_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" | ||
| LOG_DIR="${XDG_STATE_HOME:-$HOME/.local/state}/linuxextend" | ||
| LOG_FILE="$LOG_DIR/server.log" | ||
| PID_FILE="$LOG_DIR/server.pid" | ||
| ADB_BIN="/home/neonjava/Android/Sdk/platform-tools/adb" | ||
| ADB_BIN="${ANDROID_HOME:-$HOME/Android/Sdk}/platform-tools/adb" | ||
| [ -x "$ADB_BIN" ] || ADB_BIN="$(command -v adb 2>/dev/null || true)" | ||
|
|
||
| mkdir -p "$LOG_DIR" | ||
|
|
@@ -44,7 +44,7 @@ get_pid() { | |
| return | ||
| fi | ||
| fi | ||
| pgrep -f "python3 -m linuxextend" | head -1 | ||
| pgrep -f "python3 -m linuxextend" 2>/dev/null | head -1 || true | ||
| } | ||
|
|
||
| cleanup_displays() { | ||
|
|
@@ -68,10 +68,13 @@ setup_usb() { | |
| "$ADB_BIN" reverse tcp:8080 tcp:8080 >/dev/null 2>&1 || true | ||
| echo -e " ${C_GREEN}✓ USB ADB reverse active${C_RESET}" | ||
|
|
||
| # Check if app is installed and launch it | ||
| # Launch on tablet: native app if installed, otherwise browser | ||
| if "$ADB_BIN" shell pm list packages 2>/dev/null | grep -q "com.linuxextend"; then | ||
| echo -e " ${C_CYAN}Launching LinuxExtend on tablet...${C_RESET}" | ||
| "$ADB_BIN" shell am start -n com.linuxextend/.MainActivity >/dev/null 2>&1 || true | ||
| elif "$ADB_BIN" shell pm list packages 2>/dev/null | grep -q "com.android.chrome"; then | ||
| echo -e " ${C_CYAN}Launching stream in Chrome on tablet...${C_RESET}" | ||
| "$ADB_BIN" shell am start -n com.android.chrome/com.google.android.apps.chrome.Main -d "http://127.0.0.1:8080" >/dev/null 2>&1 || true | ||
| fi | ||
| fi | ||
| fi | ||
|
|
@@ -92,10 +95,17 @@ cmd_start() { | |
| echo -e "${C_BOLD}${C_BLUE}Starting LinuxExtend server...${C_RESET}" | ||
| cd "$INSTALL_DIR/server" | ||
|
|
||
| # Start server in background | ||
| nohup python3 -m linuxextend "$@" > "$LOG_FILE" 2>&1 & | ||
| local s_pid=$! | ||
| 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 | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
When the systemd branch is used, the server no longer writes to Useful? React with 👍 / 👎. |
||
| local s_pid | ||
| s_pid=$(pgrep -f "python3 -u -m linuxextend" 2>/dev/null | head -1 || true) | ||
| [ -n "$s_pid" ] && echo "$s_pid" > "$PID_FILE" | ||
| else | ||
| nohup python3 -u -m linuxextend "$@" < /dev/null > "$LOG_FILE" 2>&1 & | ||
| local s_pid=$! | ||
| echo "$s_pid" > "$PID_FILE" | ||
| fi | ||
|
|
||
| # Wait for virtual display initialization | ||
| local timeout=10 | ||
|
|
@@ -143,6 +153,11 @@ cmd_stop() { | |
| echo -e "${C_BOLD}${C_BLUE}Stopping LinuxExtend...${C_RESET}" | ||
| local stopped=0 | ||
|
|
||
| # Stop systemd unit if running | ||
| if command -v systemctl >/dev/null 2>&1; then | ||
| systemctl --user stop linuxextend-server 2>/dev/null || true | ||
| fi | ||
|
|
||
| local pid | ||
| pid=$(get_pid) | ||
| if [ -n "$pid" ]; then | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,19 +1,46 @@ | ||
| #!/usr/bin/env bash | ||
| # Switch mouse cursor and monitor focus between laptop (eDP-1) and tablet (HEADLESS-*) | ||
|
|
||
| CURSOR_POS=$(hyprctl cursorpos | tr -d ' ') | ||
| CURSOR_X=$(echo "$CURSOR_POS" | cut -d',' -f1) | ||
|
|
||
| # Laptop width is 1920 | ||
| if [ "${CURSOR_X:-0}" -lt 1920 ]; then | ||
| # Currently on Laptop -> Jump to Tablet (centered at 2880, 540) | ||
| hyprctl dispatch movecursor 2880 540 | ||
| HEADLESS_NAME=$(hyprctl monitors -j | jq -r '.[] | select(.name | startswith("HEADLESS")) | .name' | head -1) | ||
| if [ -n "$HEADLESS_NAME" ]; then | ||
| hyprctl dispatch focusmonitor "$HEADLESS_NAME" | ||
| fi | ||
| # Switch mouse cursor and monitor focus between primary monitor and virtual headless monitor | ||
|
|
||
| if ! command -v hyprctl >/dev/null 2>&1; then | ||
| exit 0 | ||
| fi | ||
|
|
||
| FOCUSED_MON=$(hyprctl monitors -j 2>/dev/null | jq -r '.[] | select(.focused) | .name') | ||
| HEADLESS_MON=$(hyprctl monitors -j 2>/dev/null | jq -r '.[] | select(.name | startswith("HEADLESS")) | .name' | head -1) | ||
| PRIMARY_MON=$(hyprctl monitors -j 2>/dev/null | jq -r '.[] | select((.name | startswith("HEADLESS") | not)) | .name' | head -1) | ||
|
|
||
| if [ -z "$HEADLESS_MON" ]; then | ||
| # No virtual monitor active | ||
| exit 0 | ||
| fi | ||
|
|
||
| if [ "$FOCUSED_MON" = "$HEADLESS_MON" ]; then | ||
| TARGET_MON="$PRIMARY_MON" | ||
| else | ||
| # Currently on Tablet -> Jump to Laptop (centered at 960, 540) | ||
| hyprctl dispatch movecursor 960 540 | ||
| hyprctl dispatch focusmonitor eDP-1 | ||
| TARGET_MON="$HEADLESS_MON" | ||
| fi | ||
|
|
||
| [ -z "$TARGET_MON" ] && exit 0 | ||
|
|
||
| # Calculate center coordinates of target monitor | ||
| TARGET_INFO=$(hyprctl monitors -j 2>/dev/null | jq -r ".[] | select(.name == \"$TARGET_MON\")") | ||
| TARGET_X=$(echo "$TARGET_INFO" | jq -r '.x // 0') | ||
| TARGET_Y=$(echo "$TARGET_INFO" | jq -r '.y // 0') | ||
| TARGET_W=$(echo "$TARGET_INFO" | jq -r '.width // 1920') | ||
| TARGET_H=$(echo "$TARGET_INFO" | jq -r '.height // 1080') | ||
| TARGET_TRANSFORM=$(echo "$TARGET_INFO" | jq -r '.transform // 0') | ||
|
|
||
| # Account for rotated orientation | ||
| if [ "$TARGET_TRANSFORM" -eq 1 ] || [ "$TARGET_TRANSFORM" -eq 3 ]; then | ||
| EFF_W=$TARGET_H | ||
| EFF_H=$TARGET_W | ||
| else | ||
| EFF_W=$TARGET_W | ||
| EFF_H=$TARGET_H | ||
| fi | ||
|
|
||
| CENTER_X=$(( TARGET_X + EFF_W / 2 )) | ||
| CENTER_Y=$(( TARGET_Y + EFF_H / 2 )) | ||
|
|
||
| hyprctl dispatch focusmonitor "$TARGET_MON" >/dev/null 2>&1 || true | ||
| hyprctl dispatch movecursor "$CENTER_X" "$CENTER_Y" >/dev/null 2>&1 || true |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When
systemd-runis installed but no user service manager is reachable,startnow exits without launching the server. The installed command's help describes--useras “Run as user unit”; executable availability alone does not establish that this works. In the inspected environment,systemd-run --user ... /bin/truefails withFailed to connect to bus: No medium found. Because this invocation runs underset -eand suppresses its diagnostics, the existing nohup branch is never reached. Test whether service creation succeeds and fall back on failure.Useful? React with 👍 / 👎.