mirror of
https://github.com/Genymobile/scrcpy.git
synced 2026-04-21 01:33:36 +00:00
Add resizable virtual display feature
Introduce `--flex-display` to continuously resize the virtual display to match the window.
This commit is contained in:
parent
00c941ab03
commit
3ca88616d2
18 changed files with 219 additions and 19 deletions
|
|
@ -791,7 +791,8 @@ static const struct sc_option options[] = {
|
|||
"and bottom or at the sides if needed).\n"
|
||||
"\"disabled\": render the display at the top-left corner, "
|
||||
"without scaling.\n"
|
||||
"Default is \"letterbox\".",
|
||||
"Default is \"letterbox\", unless --flex-display is set, in "
|
||||
"which case it is \"disabled\".",
|
||||
},
|
||||
{
|
||||
.longopt_id = OPT_REQUIRE_AUDIO,
|
||||
|
|
@ -1016,6 +1017,11 @@ static const struct sc_option options[] = {
|
|||
.text = "Set the initial window height.\n"
|
||||
"Default is 0 (automatic).",
|
||||
},
|
||||
{
|
||||
.shortopt = 'x',
|
||||
.longopt = "flex-display",
|
||||
.text = "Continuously resize the virtual display to match the window.",
|
||||
},
|
||||
};
|
||||
|
||||
static const struct sc_shortcut shortcuts[] = {
|
||||
|
|
@ -2792,6 +2798,9 @@ parse_args_with_getopt(struct scrcpy_cli_args *args, int argc, char *argv[],
|
|||
return false;
|
||||
}
|
||||
break;
|
||||
case 'x':
|
||||
opts->flex_display = true;
|
||||
break;
|
||||
default:
|
||||
// getopt prints the error message on stderr
|
||||
return false;
|
||||
|
|
@ -2971,6 +2980,11 @@ parse_args_with_getopt(struct scrcpy_cli_args *args, int argc, char *argv[],
|
|||
}
|
||||
}
|
||||
|
||||
if (opts->render_fit == SC_RENDER_FIT_AUTO) {
|
||||
opts->render_fit = opts->flex_display ? SC_RENDER_FIT_DISABLED
|
||||
: SC_RENDER_FIT_LETTERBOX;
|
||||
}
|
||||
|
||||
if (otg) {
|
||||
if (!opts->control) {
|
||||
LOGE("--no-control is not allowed in OTG mode");
|
||||
|
|
@ -3090,6 +3104,28 @@ parse_args_with_getopt(struct scrcpy_cli_args *args, int argc, char *argv[],
|
|||
return false;
|
||||
}
|
||||
|
||||
if (opts->flex_display) {
|
||||
if (opts->video_source != SC_VIDEO_SOURCE_DISPLAY
|
||||
|| !opts->new_display) {
|
||||
LOGE("-x/--flex-display can only be applied to displays created "
|
||||
"with --new-display");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (opts->max_size) {
|
||||
LOGE("--max-size is not compatible with -x/--flex-display");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (opts->crop) {
|
||||
LOGE("--crop is not compatible with -x/--flex-display");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Force free resizing
|
||||
opts->window_aspect_ratio_lock = false;
|
||||
}
|
||||
|
||||
if (opts->display_ime_policy != SC_DISPLAY_IME_POLICY_UNDEFINED
|
||||
&& opts->display_id == 0 && !opts->new_display) {
|
||||
LOGE("--display-ime-policy is only supported on a secondary display");
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ const struct scrcpy_options scrcpy_options_default = {
|
|||
.display_orientation = SC_ORIENTATION_0,
|
||||
.record_orientation = SC_ORIENTATION_0,
|
||||
.display_ime_policy = SC_DISPLAY_IME_POLICY_UNDEFINED,
|
||||
.render_fit = SC_RENDER_FIT_LETTERBOX,
|
||||
.render_fit = SC_RENDER_FIT_AUTO,
|
||||
.window_x = SC_WINDOW_POSITION_UNDEFINED,
|
||||
.window_y = SC_WINDOW_POSITION_UNDEFINED,
|
||||
.window_width = 0,
|
||||
|
|
@ -117,6 +117,7 @@ const struct scrcpy_options scrcpy_options_default = {
|
|||
.vd_destroy_content = true,
|
||||
.vd_system_decorations = true,
|
||||
.camera_torch = false,
|
||||
.flex_display = false,
|
||||
};
|
||||
|
||||
enum sc_orientation
|
||||
|
|
|
|||
|
|
@ -221,6 +221,7 @@ enum sc_shortcut_mod {
|
|||
};
|
||||
|
||||
enum sc_render_fit {
|
||||
SC_RENDER_FIT_AUTO,
|
||||
SC_RENDER_FIT_LETTERBOX,
|
||||
SC_RENDER_FIT_DISABLED,
|
||||
};
|
||||
|
|
@ -336,6 +337,7 @@ struct scrcpy_options {
|
|||
bool vd_destroy_content;
|
||||
bool vd_system_decorations;
|
||||
bool camera_torch;
|
||||
bool flex_display;
|
||||
};
|
||||
|
||||
extern const struct scrcpy_options scrcpy_options_default;
|
||||
|
|
|
|||
|
|
@ -465,6 +465,7 @@ scrcpy(struct scrcpy_options *options) {
|
|||
.camera_zoom = options->camera_zoom,
|
||||
.vd_destroy_content = options->vd_destroy_content,
|
||||
.vd_system_decorations = options->vd_system_decorations,
|
||||
.flex_display = options->flex_display,
|
||||
.list = options->list,
|
||||
};
|
||||
|
||||
|
|
@ -797,6 +798,7 @@ aoa_complete:
|
|||
struct sc_screen_params screen_params = {
|
||||
.video = options->video_playback,
|
||||
.camera = options->video_source == SC_VIDEO_SOURCE_CAMERA,
|
||||
.flex_display = options->flex_display,
|
||||
.controller = controller,
|
||||
.fp = fp,
|
||||
.kp = kp,
|
||||
|
|
|
|||
|
|
@ -286,10 +286,27 @@ end:
|
|||
}
|
||||
|
||||
static void
|
||||
sc_screen_on_resize(struct sc_screen *screen) {
|
||||
sc_screen_on_resize(struct sc_screen *screen, const SDL_WindowEvent *event) {
|
||||
// This event can be triggered before the window is shown
|
||||
if (screen->window_shown) {
|
||||
sc_screen_render(screen, true);
|
||||
|
||||
if (screen->flex_display) {
|
||||
assert(!screen->camera);
|
||||
assert(!(event->data1 & !0xFFFF));
|
||||
assert(!(event->data2 & !0xFFFF));
|
||||
uint16_t width = event->data1;
|
||||
uint16_t height = event->data2;
|
||||
if (sc_orientation_is_swap(screen->orientation)) {
|
||||
uint16_t tmp = width;
|
||||
width = height;
|
||||
height = tmp;
|
||||
}
|
||||
|
||||
LOGV("resize_display(%" PRIu16 ", %" PRIu16 ")", width, height);
|
||||
sc_controller_resize_display(screen->controller, width,
|
||||
height);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -311,7 +328,7 @@ event_watcher(void *data, SDL_Event *event) {
|
|||
if (event->type == SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED) {
|
||||
// In practice, it seems to always be called from the same thread in
|
||||
// that specific case. Anyway, it's just a workaround.
|
||||
sc_screen_on_resize(screen);
|
||||
sc_screen_on_resize(screen, &event->window);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
@ -406,6 +423,8 @@ sc_screen_frame_sink_push_session(struct sc_frame_sink *sink,
|
|||
bool
|
||||
sc_screen_init(struct sc_screen *screen,
|
||||
const struct sc_screen_params *params) {
|
||||
screen->controller = params->controller;
|
||||
|
||||
screen->resize_pending = false;
|
||||
screen->window_shown = false;
|
||||
screen->paused = false;
|
||||
|
|
@ -418,6 +437,7 @@ sc_screen_init(struct sc_screen *screen,
|
|||
screen->camera = params->camera;
|
||||
screen->window_aspect_ratio_lock = params->window_aspect_ratio_lock;
|
||||
screen->render_fit = params->render_fit;
|
||||
screen->flex_display = params->flex_display;
|
||||
|
||||
screen->req.x = params->window_x;
|
||||
screen->req.y = params->window_y;
|
||||
|
|
@ -739,11 +759,13 @@ resize_for_content(struct sc_screen *screen, struct sc_size old_content_size,
|
|||
assert(screen->video);
|
||||
|
||||
struct sc_size window_size = sc_sdl_get_window_size(screen->window);
|
||||
struct sc_size target_size = {
|
||||
.width = (uint32_t) window_size.width * new_content_size.width
|
||||
/ old_content_size.width,
|
||||
.height = (uint32_t) window_size.height * new_content_size.height
|
||||
/ old_content_size.height,
|
||||
struct sc_size target_size = new_content_size;
|
||||
if (!screen->flex_display) {
|
||||
// Scale proportionally
|
||||
target_size.width = (uint32_t) window_size.width * target_size.width
|
||||
/ old_content_size.width;
|
||||
target_size.height = (uint32_t) window_size.height * target_size.height
|
||||
/ old_content_size.height;
|
||||
};
|
||||
target_size = get_optimal_size(target_size, new_content_size, true);
|
||||
assert(is_windowed(screen));
|
||||
|
|
@ -999,7 +1021,7 @@ sc_screen_handle_event(struct sc_screen *screen, const SDL_Event *event) {
|
|||
// If defined, then the actions are already performed by the event watcher
|
||||
#ifndef CONTINUOUS_RESIZING_WORKAROUND
|
||||
case SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED:
|
||||
sc_screen_on_resize(screen);
|
||||
sc_screen_on_resize(screen, &event->window);
|
||||
return;
|
||||
#endif
|
||||
case SDL_EVENT_WINDOW_RESTORED:
|
||||
|
|
|
|||
|
|
@ -37,6 +37,9 @@ struct sc_screen {
|
|||
bool video;
|
||||
bool camera;
|
||||
bool window_aspect_ratio_lock;
|
||||
bool flex_display;
|
||||
|
||||
struct sc_controller *controller;
|
||||
|
||||
struct sc_texture tex;
|
||||
struct sc_input_manager im;
|
||||
|
|
@ -96,6 +99,7 @@ struct sc_screen {
|
|||
struct sc_screen_params {
|
||||
bool video;
|
||||
bool camera;
|
||||
bool flex_display;
|
||||
|
||||
struct sc_controller *controller;
|
||||
struct sc_file_pusher *fp;
|
||||
|
|
|
|||
|
|
@ -413,6 +413,9 @@ execute_server(struct sc_server *server,
|
|||
VALIDATE_STRING(params->new_display);
|
||||
ADD_PARAM("new_display=%s", params->new_display);
|
||||
}
|
||||
if (params->flex_display) {
|
||||
ADD_PARAM("flex_display=true");
|
||||
}
|
||||
if (params->display_ime_policy != SC_DISPLAY_IME_POLICY_UNDEFINED) {
|
||||
ADD_PARAM("display_ime_policy=%s",
|
||||
sc_server_get_display_ime_policy_name(params->display_ime_policy));
|
||||
|
|
|
|||
|
|
@ -72,6 +72,7 @@ struct sc_server_params {
|
|||
bool camera_torch;
|
||||
bool vd_destroy_content;
|
||||
bool vd_system_decorations;
|
||||
bool flex_display;
|
||||
uint8_t list;
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue