Commit graph

201 commits

Author SHA1 Message Date
Romain Vimont
f7c5f71ea0 Add --render-fit feature
Add an option to configure how the rendering fits the window.

The default, `--render-fit=letterbox`, preserves the aspect ratio
and fits the window as best as possible, adding black bars at
the top/bottom or left/right if needed. This has been the only behavior
scrcpy supported so far.

Another mode, `--render-fit=disabled`, renders the display at the
top-left corner without scaling. This mode will be useful for virtual
display resizing.
2026-04-19 12:20:38 +02:00
Romain Vimont
3b068b669e Signal client resize in session packets
So far, scrcpy always resized the window whenever a frame with a new
size was received. However, with the upcoming "flex display" feature,
the size of the virtual display can change either on its own (e.g.,
due to app rotation) or as a result of a client window resize.

Track the cause of each resize and signal it in the session metadata.

Resize the window only if the change was not triggered by a client
request to prevent resize loops and stuttering.
2026-04-19 12:20:38 +02:00
Romain Vimont
160a378719 Remove frame buffer internal mutex
Let the caller handle locking as needed, allowing them to perform other
actions under the same lock.
2026-04-19 12:20:38 +02:00
Romain Vimont
f4a872bef4 Fix aspect ratio accuracy
The window aspect ratio was previously enforced by calling
`SDL_SetWindowAspectRatio()` before explicitly setting the window size,
using the width/height ratio of the new size.

However, this size may already be a scaled version of the actual content
size, subject to integer rounding. Using this derived size instead of
the actual content size could result in an inaccurate ratio, causing a
mismatch between the content and window aspect ratios, which may result
in a thin row or column of black pixels.

To avoid this issue, always set the aspect ratio based on the content
size.

Refs 1b4fd67286
Refs #6761 <https://github.com/Genymobile/scrcpy/pull/6761>
PR #6774 <https://github.com/Genymobile/scrcpy/pull/6774>
2026-04-17 18:30:25 +02:00
Tech-Tac
65153a09c3 Add option to disable window aspect ratio lock
By default, the window aspect ratio is preserved when resizing.

Add `--no-window-aspect-ratio-lock` to disable this behavior.

PR #6761 <https://github.com/Genymobile/scrcpy/pull/6761>

Signed-off-by: Romain Vimont <rom@rom1v.com>
2026-04-10 19:35:43 +02:00
Tech-Tac
1b4fd67286 Enforce window aspect ratio
Preserve the aspect ratio when resizing the window, so that the window
always matches the device content.

Fixes #2317 <https://github.com/Genymobile/scrcpy/issues/2317>
Fixes #2387 <https://github.com/Genymobile/scrcpy/issues/2387>
Fixes #3460 <https://github.com/Genymobile/scrcpy/issues/3460>
PR #6761 <https://github.com/Genymobile/scrcpy/pull/6761>

Signed-off-by: Romain Vimont <rom@rom1v.com>
2026-04-10 19:34:02 +02:00
Romain Vimont
523c820bfa Avoid double-rendering on resize
On Windows and macOS, resizing the window with the mouse blocks the
event loop until the click is released. To keep rendering during
resizing, an event watcher is registered to handle resize events.

Avoid handling resize events twice by ensuring
`SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED` is processed only once.

PR #6758 <https://github.com/Genymobile/scrcpy/pull/6758>
2026-04-10 19:27:13 +02:00
Romain Vimont
8983023457 Factorize resize event handling
Reuse the same code to handle resize events from the event loop or the
event watcher.

PR #6758 <https://github.com/Genymobile/scrcpy/pull/6758>
2026-04-10 19:27:13 +02:00
Romain Vimont
a4000a1487 Display disconnected icon before closing
Previously, when the connection to the device was lost while mirroring,
the window closed immediately, suggesting scrcpy had crashed.

To make it clear that a disconnection occurred, display a disconnected
icon for 2 seconds before closing the window.

PR #6662 <https://github.com/Genymobile/scrcpy/pull/6662>
2026-03-17 18:40:35 +01:00
Romain Vimont
6ca1b79228 Add filename parameter to icon loading
Replace scrcpy_icon_load(), which loaded the unique scrcpy app icon,
with sc_icon_load(filename), which can load any icon from the icons
directory.

PR #6662 <https://github.com/Genymobile/scrcpy/pull/6662>
2026-03-17 18:40:34 +01:00
Romain Vimont
e17a885f32 Draw a dark square when no texture is rendered
Draw a dark 10x10 square in the top-right corner to distinguish a black
frame from the absence of a frame (useful for debugging).

PR #6694 <https://github.com/Genymobile/scrcpy/pull/6694>
2026-03-10 20:11:04 +01:00
Romain Vimont
691a63761c Open the scrcpy window earlier
Previously, the window was opened only once the first frame was
available. Instead, open it as soon as the frame dimensions are known.

This is especially useful when the encoder does not produce an initial
frame while the phone is turned off (e.g., with --no-power-on).

Fixes #6546 <https://github.com/Genymobile/scrcpy/issues/6546>
PR #6694 <https://github.com/Genymobile/scrcpy/pull/6694>
2026-03-10 20:11:04 +01:00
Romain Vimont
57af6b9209 Track window shown state
Use a flag to indicate whether the window is currently shown.

This replaces the old has_video_window flag, which was true only when
the window was shown and video was enabled.

This will simplify performing actions only when the window is currently
shown.

PR #6694 <https://github.com/Genymobile/scrcpy/pull/6694>
2026-03-10 20:11:04 +01:00
Romain Vimont
0597c5eb8d Remove unnecessary void cast
The ctx variable is used.

PR #6694 <https://github.com/Genymobile/scrcpy/pull/6694>
2026-03-10 20:11:04 +01:00
Romain Vimont
2301f64158 Make icon loading failure non-fatal
Do not close scrcpy if the content icon cannot be loaded, even when
video playback is disabled.
2026-02-09 18:36:54 +01:00
Romain Vimont
d7f0e22067 Make screen event handler return void
The function always returned true.
2026-02-09 18:36:54 +01:00
Romain Vimont
77998f543f Rename sc_display to sc_texture
The sc_display component now only handles a texture. Rendering has been
moved to sc_screen.

PR #6651 <https://github.com/Genymobile/scrcpy/pull/6651>
2026-02-09 18:33:57 +01:00
Romain Vimont
c43cc2ddc3 Set display texture from a frame
Add a function to set a texture from an AVFrame on a sc_display.

PR #6651 <https://github.com/Genymobile/scrcpy/pull/6651>
2026-02-09 18:33:52 +01:00
Romain Vimont
1617979549 Set display texture from a surface
Add a function to set a texture from a surface on a sc_display.

PR #6651 <https://github.com/Genymobile/scrcpy/pull/6651>
2026-02-09 18:33:48 +01:00
Romain Vimont
58818dc860 Use floating-point for content location
In SDL3, texture rendering uses SDL_FRect, unlike SDL2 which used
SDL_Rect.

Compute content location using floating-point coordinates from the
start.

PR #6651 <https://github.com/Genymobile/scrcpy/pull/6651>
2026-02-09 18:33:44 +01:00
Romain Vimont
3ef51e691e Factorize icon rendering
Replace SDL "logical rendering" with explicit computation of icon
location, and unify rendering of video frames and icons using the same
common code.

PR #6651 <https://github.com/Genymobile/scrcpy/pull/6651>
2026-02-09 18:33:41 +01:00
Romain Vimont
fb77f8556a Extract function to compute content location
PR #6651 <https://github.com/Genymobile/scrcpy/pull/6651>
2026-02-09 18:33:38 +01:00
Romain Vimont
e3f0c21f2a Use render output size to compute content location
The coordinates of the content to render depend on the render output
size, not the window size in pixels. In theory, the two could differ.

PR #6651 <https://github.com/Genymobile/scrcpy/pull/6651>
2026-02-09 18:33:35 +01:00
Romain Vimont
930169af4e Move rendering from sc_display to sc_screen
Three components are involved in displaying device content on screen:
 - a window
 - a renderer
 - a texture

Originally, all three were handled by sc_screen.

Commit 051b74c883 later extracted the
renderer and texture into a separate component, sc_display.

However, the split was a bit awkward because the window size and
rendering location were managed by separate components.

Move rendering back to sc_screen, keeping only texture management
separated.

PR #6651 <https://github.com/Genymobile/scrcpy/pull/6651>
2026-02-09 18:33:31 +01:00
Romain Vimont
3ce5feb5cb Move renderer from sc_display to sc_screen
Make sc_screen the owner of both the SDL window and the SDL renderer.
This is the first step toward limiting the role of sc_display to texture
management.

PR #6651 <https://github.com/Genymobile/scrcpy/pull/6651>
2026-02-09 18:33:29 +01:00
Romain Vimont
42e2264d67 Simplify texture failure handling
When the scrcpy window is minimized on Windows with D3D9, texture
creation and updates fail.

As a workaround, a mechanism was implemented to reattempt applying the
requested changes.

Since SDL3 defaults to the D3D11 backend, remove this workaround,
which adds a lot of complexity for a backend that should almost never
be used.

However, do not close scrcpy when texture creation or updates fail; only
that specific rendering should fail.

Refs SDL/#7651 <https://github.com/libsdl-org/SDL/issues/7651>
Refs #3947 <https://github.com/Genymobile/scrcpy/issues/3947>
Refs 6298ef095f
PR #6651 <https://github.com/Genymobile/scrcpy/pull/6651>
2026-02-09 18:33:18 +01:00
Romain Vimont
078565d40b Enable controls for camera video source
This will allow the implementation of camera-specific shortcuts.

PR #6243 <https://github.com/Genymobile/scrcpy/pull/6243>

Co-authored-by: Tommie <teh420@gmail.com>
2026-01-13 20:27:33 +01:00
Romain Vimont
78cba1b7c2 Add session metadata for the video stream
Introduce a new packet type, a "session" packet, containing metadata
about the encoding session. It is used only for the video stream and
currently includes the video resolution.

For illustration, here is a sequence of packets on the video stream:

                                        device rotation
                                        v
    CODEC | SESSION | MEDIA | MEDIA | … | SESSION | MEDIA | MEDIA | …
           1920x1080 <-----------------> 1080x1920 <------------------
                      encoding session 1            encoding session 2

This metadata is not strictly necessary, since the video resolution can
be determined after decoding. However, it allows detection of cases
where the encoder does not respect the requested size (and logs a
warning), even without decoding (e.g., when there is no video playback).

Additional metadata could be added later if necessary, for example the
actual device rotation.

Refs #5918 <https://github.com/Genymobile/scrcpy/pull/5918>
Refs #5894 <https://github.com/Genymobile/scrcpy/pull/5894>
PR #6159 <https://github.com/Genymobile/scrcpy/pull/6159>

Co-authored-by: gz0119 <liyong2@4399.com>
2026-01-10 11:53:22 +01:00
Romain Vimont
f4cc07da24 Keep the window hidden during initialization
This prevents blinking during display initialization.
2026-01-09 19:08:04 +01:00
Romain Vimont
4879950a06 Fix asynchronous SDL window state handling
The SDL3 migration guide [1] says:

> The following window operations are now considered to be asynchronous
requests and should not be assumed to succeed unless a corresponding
event has been received […]

Remove the boolean fields used to track the window state, as they were
fundamentally inconsistent with SDL's internal state. Use
SDL_GetWindowFlags() explicitly instead.

[1]: <https://wiki.libsdl.org/SDL3/README-migration>

Refs #6216 comment <https://github.com/Genymobile/scrcpy/pull/6216#discussion_r2651810005>
PR #6216 <https://github.com/Genymobile/scrcpy/pull/6216>
2026-01-08 20:40:51 +01:00
Romain Vimont
170b7a02e7 Disable "resize to pixel-perfect" when maximized
This improves consistency and will simplify further refactors.

PR #6216 <https://github.com/Genymobile/scrcpy/pull/6216>
2026-01-08 20:40:51 +01:00
Romain Vimont
02989249f6 Migrate from SDL2 to SDL3
Refs <https://wiki.libsdl.org/SDL3/README-migration>
PR #6216 <https://github.com/Genymobile/scrcpy/pull/6216>
2026-01-06 16:22:48 +01:00
Romain Vimont
f8e0b9be4b Improve color space conversion
Use both the color space and color range from FFmpeg to determine the
appropriate SDL YUV conversion mode.

PR #6216 <https://github.com/Genymobile/scrcpy/pull/6216>
2026-01-04 14:14:33 +01:00
Romain Vimont
ed62ca124c Set color range during texture creation
This prepares for the migration to SDL3, where the color range can only
be specified at the time of texture creation.

PR #6216 <https://github.com/Genymobile/scrcpy/pull/6216>
2026-01-04 14:14:18 +01:00
Romain Vimont
3571fe62ed Create texture on first frame
The texture was created as soon as the initial video size was known,
even before the first frame arrived.

However, texture creation will require other data, such as the color
range, which is only available once the first frame is received.

Therefore, delay texture creation until the first frame.

PR #6216 <https://github.com/Genymobile/scrcpy/pull/6216>
2026-01-04 14:13:33 +01:00
Romain Vimont
bca98133d1 Remove prepare_for_frame()
Inline the function body into its only caller to simplify further
refactors.

PR #6216 <https://github.com/Genymobile/scrcpy/pull/6216>
2026-01-04 14:12:12 +01:00
Romain Vimont
eb576c44f8 Replace __WINDOWS__ by _WIN32
Replace the SDL2-specific preprocessor macro __WINDOWS__ by the
"standard" _WIN32 macro.
2025-07-17 18:23:25 +02:00
Romain Vimont
04542a9f58 Fix window leak on icon error 2025-07-17 13:19:15 +02:00
Romain Vimont
ff9fb5994d Use shortcut mods as mouse capture keys
Instead of using separate hardcoded keys for mouse capture/uncapture,
use the shortcut mods.

By changing the shortcut mods (for example --shortcut-mod=rctrl), it
allows to forward Alt and Super to the device.

Fixes #5318 <https://github.com/Genymobile/scrcpy/issues/5318>
PR #5322 <https://github.com/Genymobile/scrcpy/pull/5322>
2024-10-06 18:01:02 +02:00
Romain Vimont
281fcc7052 Extract mouse capture
Factorize mouse capture for relative mouse mode to reduce code
duplication between normal and OTG modes.

PR #5322 <https://github.com/Genymobile/scrcpy/pull/5322>
2024-10-06 18:00:56 +02:00
Romain Vimont
d92b7a6024 Rename switch_fullscreen() to toggle_fullscreen()
Toggle means to switch between two states.
2024-09-25 19:59:49 +02:00
Romain Vimont
4565f36ee6 Handle SDL gamepad events
Introduce a gamepad processor trait, similar to the keyboard processor
and mouse processor traits.

Handle gamepad events received from SDL, convert them to scrcpy-specific
gamepad events, and forward them to the gamepad processor.

Further commits will provide AOA and UHID implementations of the gamepad
processor trait.

PR #5270 <https://github.com/Genymobile/scrcpy/pull/5270>

Co-authored-by: Luiz Henrique Laurini <luizhenriquelaurini@gmail.com>
2024-09-15 11:21:56 +02:00
Romain Vimont
e9b32d8a52 Extract sc_push_event()
Expose a convenience function to push an event without args to the main
thread.

PR #5270 <https://github.com/Genymobile/scrcpy/pull/5270>
2024-09-14 21:24:15 +02:00
Romain Vimont
dea1fe3386 Validate crop and video size
A video width or height of 0 triggered an assert.

Fail explicitly instead: the server may actually send this size in
practice (for example on cropping with small dimensions, even if the
requested crop size is not 0).
2024-09-13 19:48:55 +02:00
Romain Vimont
035d60cf5d Add option to configure mouse bindings
Add a new option --mouse-bind=xxxx.

The argument must be exactly 4 characters, one for each secondary click:

    --mouse-bind=xxxx
                 ^^^^
                 ||||
                 ||| `- 5th click
                 || `-- 4th click
                 | `--- middle click
                  `---- right click

Each character must be one of the following:
 - `+`: forward the click to the device
 - `-`: ignore the click
 - `b`: trigger shortcut BACK (or turn screen on if off)
 - `h`: trigger shortcut HOME
 - `s`: trigger shortcut APP_SWITCH
 - `n`: trigger shortcut "expand notification panel"

This deprecates --forward-all-clicks (use --mouse-bind=++++ instead).

Refs <https://github.com/Genymobile/scrcpy/pull/2258#issuecomment-2182394460>
PR #5022 <https://github.com/Genymobile/scrcpy/pull/5022>
2024-06-24 23:17:23 +02:00
Romain Vimont
45fe6b602b Add scrcpy window without video playback
Add the possibility to solely control the device without screen
mirroring:

    scrcpy --no-video --no-audio

This is different from OTG mode, which does not require USB debugging at
all. Here, the standard mode is used but with the possibility to disable
video playback.

By default, always open a window (even without video playback), and add
an option --no-window.

Fixes #4727 <https://github.com/Genymobile/scrcpy/issues/4727>
Fixes #4793 <https://github.com/Genymobile/scrcpy/issues/4793>
PR #4868 <https://github.com/Genymobile/scrcpy/pull/4868>
2024-05-11 17:06:16 +02:00
Romain Vimont
1c3801a0b1 Add a shortcut to pause/unpause display
Pause/unpause display on MOD+z and MOD+Shift+z.

It only impacts rendering, the device is still captured, the video
stream continues to be transmitted to the device and recorded (if
recording is enabled).

Fixes #1632 <https://github.com/Genymobile/scrcpy/issues/1632>
PR #4748 <https://github.com/Genymobile/scrcpy/pull/4748>
2024-03-30 14:20:51 +01:00
Romain Vimont
bb88b60227 Add --display-orientation
Deprecate the option --rotation and introduce a new option
--display-orientation with the 8 possible orientations (0, 90, 180, 270,
flip0, flip90, flip180 and flip270).

New shortcuts MOD+Shift+(arrow) dynamically change the display
(horizontal or vertical) flip.

Fixes #1380 <https://github.com/Genymobile/scrcpy/issues/1380>
Fixes #3819 <https://github.com/Genymobile/scrcpy/issues/3819>
PR #4441 <https://github.com/Genymobile/scrcpy/pull/4441>
2023-11-23 23:27:28 +01:00
Romain Vimont
85b55b3c4e Fix possible division by zero
On sway (a window manager), SDL_WINDOWEVENT_EXPOSED and
SDL_WINDOWEVENT_SIZE_CHANGED might not be called before a mouse event is
triggered. As a consequence, the "content rectangle" might not be
initialized when the mouse event is processed, causing a division by
zero.

To avoid the problem, initialize the content rect immediately when the
window is shown.

Fixes #4115 <https://github.com/Genymobile/scrcpy/issues/4115>
2023-06-29 19:18:32 +02:00
Romain Vimont
e926bf1fe8 Delay window resize when minimized
On some window managers (e.g. on Windows), performing a resize while the
window is minimized does nothing (the restored window keeps its old
size).

Therefore, like for maximized and fullscreen states, wait for the window
to be restored to apply a resize.

Refs #3947 <https://github.com/Genymobile/scrcpy/issues/3947>
2023-05-22 18:22:45 +02:00