mirror of
https://github.com/Genymobile/scrcpy
synced 2024-11-11 01:10:32 +00:00
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>
This commit is contained in:
parent
cca2c9ffb7
commit
45fe6b602b
@ -316,6 +316,10 @@ Disable video forwarding.
|
||||
.B \-\-no\-video\-playback
|
||||
Disable video playback on the computer.
|
||||
|
||||
.TP
|
||||
.B \-\-no\-window
|
||||
Disable scrcpy window. Implies --no-video-playback and --no-control.
|
||||
|
||||
.TP
|
||||
.BI "\-\-orientation " value
|
||||
Same as --display-orientation=value --record-orientation=value.
|
||||
|
@ -97,6 +97,7 @@ enum {
|
||||
OPT_MOUSE,
|
||||
OPT_HID_KEYBOARD_DEPRECATED,
|
||||
OPT_HID_MOUSE_DEPRECATED,
|
||||
OPT_NO_WINDOW,
|
||||
};
|
||||
|
||||
struct sc_option {
|
||||
@ -566,6 +567,12 @@ static const struct sc_option options[] = {
|
||||
.longopt = "no-video-playback",
|
||||
.text = "Disable video playback on the computer.",
|
||||
},
|
||||
{
|
||||
.longopt_id = OPT_NO_WINDOW,
|
||||
.longopt = "no-window",
|
||||
.text = "Disable scrcpy window. Implies --no-video-playback and "
|
||||
"--no-control.",
|
||||
},
|
||||
{
|
||||
.longopt_id = OPT_ORIENTATION,
|
||||
.longopt = "orientation",
|
||||
@ -2486,6 +2493,9 @@ parse_args_with_getopt(struct scrcpy_cli_args *args, int argc, char *argv[],
|
||||
case OPT_CAMERA_HIGH_SPEED:
|
||||
opts->camera_high_speed = true;
|
||||
break;
|
||||
case OPT_NO_WINDOW:
|
||||
opts->window = false;
|
||||
break;
|
||||
default:
|
||||
// getopt prints the error message on stderr
|
||||
return false;
|
||||
@ -2523,6 +2533,12 @@ parse_args_with_getopt(struct scrcpy_cli_args *args, int argc, char *argv[],
|
||||
v4l2 = !!opts->v4l2_device;
|
||||
#endif
|
||||
|
||||
if (!opts->window) {
|
||||
// Without window, there cannot be any video playback or control
|
||||
opts->video_playback = false;
|
||||
opts->control = false;
|
||||
}
|
||||
|
||||
if (!opts->video) {
|
||||
opts->video_playback = false;
|
||||
// Do not power on the device on start if video capture is disabled
|
||||
@ -2544,8 +2560,8 @@ parse_args_with_getopt(struct scrcpy_cli_args *args, int argc, char *argv[],
|
||||
opts->audio = false;
|
||||
}
|
||||
|
||||
if (!opts->video && !opts->audio && !otg) {
|
||||
LOGE("No video, no audio, no OTG: nothing to do");
|
||||
if (!opts->video && !opts->audio && !opts->control && !otg) {
|
||||
LOGE("No video, no audio, no control, no OTG: nothing to do");
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -2569,6 +2585,11 @@ parse_args_with_getopt(struct scrcpy_cli_args *args, int argc, char *argv[],
|
||||
|
||||
#ifdef HAVE_V4L2
|
||||
if (v4l2) {
|
||||
if (!opts->video) {
|
||||
LOGE("V4L2 sink requires video capture, but --no-video was set.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (opts->lock_video_orientation ==
|
||||
SC_LOCK_VIDEO_ORIENTATION_UNLOCKED) {
|
||||
LOGI("Video orientation is locked for v4l2 sink. "
|
||||
@ -2588,13 +2609,25 @@ parse_args_with_getopt(struct scrcpy_cli_args *args, int argc, char *argv[],
|
||||
}
|
||||
#endif
|
||||
|
||||
if (opts->control) {
|
||||
if (opts->keyboard_input_mode == SC_KEYBOARD_INPUT_MODE_AUTO) {
|
||||
opts->keyboard_input_mode = otg ? SC_KEYBOARD_INPUT_MODE_AOA
|
||||
: SC_KEYBOARD_INPUT_MODE_SDK;
|
||||
}
|
||||
if (opts->mouse_input_mode == SC_MOUSE_INPUT_MODE_AUTO) {
|
||||
opts->mouse_input_mode = otg ? SC_MOUSE_INPUT_MODE_AOA
|
||||
: SC_MOUSE_INPUT_MODE_SDK;
|
||||
if (otg) {
|
||||
opts->mouse_input_mode = SC_MOUSE_INPUT_MODE_AOA;
|
||||
} else if (!opts->video_playback) {
|
||||
LOGI("No video mirroring, mouse mode switched to UHID");
|
||||
opts->mouse_input_mode = SC_MOUSE_INPUT_MODE_UHID;
|
||||
} else {
|
||||
opts->mouse_input_mode = SC_MOUSE_INPUT_MODE_SDK;
|
||||
}
|
||||
} else if (opts->mouse_input_mode == SC_MOUSE_INPUT_MODE_SDK
|
||||
&& !opts->video_playback) {
|
||||
LOGE("SDK mouse mode requires video playback. Try --mouse=uhid.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (otg) {
|
||||
|
@ -5,8 +5,30 @@
|
||||
|
||||
#include "util/log.h"
|
||||
|
||||
static bool
|
||||
sc_display_init_novideo_icon(struct sc_display *display,
|
||||
SDL_Surface *icon_novideo) {
|
||||
assert(icon_novideo);
|
||||
|
||||
if (SDL_RenderSetLogicalSize(display->renderer,
|
||||
icon_novideo->w, icon_novideo->h)) {
|
||||
LOGW("Could not set renderer logical size: %s", SDL_GetError());
|
||||
// don't fail
|
||||
}
|
||||
|
||||
display->texture = SDL_CreateTextureFromSurface(display->renderer,
|
||||
icon_novideo);
|
||||
if (!display->texture) {
|
||||
LOGE("Could not create texture: %s", SDL_GetError());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
sc_display_init(struct sc_display *display, SDL_Window *window, bool mipmaps) {
|
||||
sc_display_init(struct sc_display *display, SDL_Window *window,
|
||||
SDL_Surface *icon_novideo, bool mipmaps) {
|
||||
display->renderer =
|
||||
SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
|
||||
if (!display->renderer) {
|
||||
@ -68,6 +90,18 @@ sc_display_init(struct sc_display *display, SDL_Window *window, bool mipmaps) {
|
||||
display->pending.frame = NULL;
|
||||
display->has_frame = false;
|
||||
|
||||
if (icon_novideo) {
|
||||
// Without video, set a static scrcpy icon as window content
|
||||
bool ok = sc_display_init_novideo_icon(display, icon_novideo);
|
||||
if (!ok) {
|
||||
#ifdef SC_DISPLAY_FORCE_OPENGL_CORE_PROFILE
|
||||
SDL_GL_DeleteContext(display->gl_context);
|
||||
#endif
|
||||
SDL_DestroyRenderer(display->renderer);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -44,7 +44,8 @@ enum sc_display_result {
|
||||
};
|
||||
|
||||
bool
|
||||
sc_display_init(struct sc_display *display, SDL_Window *window, bool mipmaps);
|
||||
sc_display_init(struct sc_display *display, SDL_Window *window,
|
||||
SDL_Surface *icon_novideo, bool mipmaps);
|
||||
|
||||
void
|
||||
sc_display_destroy(struct sc_display *display);
|
||||
|
@ -403,6 +403,7 @@ sc_input_manager_process_key(struct sc_input_manager *im,
|
||||
// controller is NULL if --no-control is requested
|
||||
bool control = im->controller;
|
||||
bool paused = im->screen->paused;
|
||||
bool video = im->screen->video;
|
||||
|
||||
SDL_Keycode keycode = event->keysym.sym;
|
||||
uint16_t mod = event->keysym.mod;
|
||||
@ -462,13 +463,13 @@ sc_input_manager_process_key(struct sc_input_manager *im,
|
||||
}
|
||||
return;
|
||||
case SDLK_z:
|
||||
if (down && !repeat) {
|
||||
if (video && down && !repeat) {
|
||||
sc_screen_set_paused(im->screen, !shift);
|
||||
}
|
||||
return;
|
||||
case SDLK_DOWN:
|
||||
if (shift) {
|
||||
if (!repeat && down) {
|
||||
if (video && !repeat && down) {
|
||||
apply_orientation_transform(im,
|
||||
SC_ORIENTATION_FLIP_180);
|
||||
}
|
||||
@ -479,7 +480,7 @@ sc_input_manager_process_key(struct sc_input_manager *im,
|
||||
return;
|
||||
case SDLK_UP:
|
||||
if (shift) {
|
||||
if (!repeat && down) {
|
||||
if (video && !repeat && down) {
|
||||
apply_orientation_transform(im,
|
||||
SC_ORIENTATION_FLIP_180);
|
||||
}
|
||||
@ -489,7 +490,7 @@ sc_input_manager_process_key(struct sc_input_manager *im,
|
||||
}
|
||||
return;
|
||||
case SDLK_LEFT:
|
||||
if (!repeat && down) {
|
||||
if (video && !repeat && down) {
|
||||
if (shift) {
|
||||
apply_orientation_transform(im,
|
||||
SC_ORIENTATION_FLIP_0);
|
||||
@ -500,7 +501,7 @@ sc_input_manager_process_key(struct sc_input_manager *im,
|
||||
}
|
||||
return;
|
||||
case SDLK_RIGHT:
|
||||
if (!repeat && down) {
|
||||
if (video && !repeat && down) {
|
||||
if (shift) {
|
||||
apply_orientation_transform(im,
|
||||
SC_ORIENTATION_FLIP_0);
|
||||
@ -533,22 +534,22 @@ sc_input_manager_process_key(struct sc_input_manager *im,
|
||||
}
|
||||
return;
|
||||
case SDLK_f:
|
||||
if (!shift && !repeat && down) {
|
||||
if (video && !shift && !repeat && down) {
|
||||
sc_screen_switch_fullscreen(im->screen);
|
||||
}
|
||||
return;
|
||||
case SDLK_w:
|
||||
if (!shift && !repeat && down) {
|
||||
if (video && !shift && !repeat && down) {
|
||||
sc_screen_resize_to_fit(im->screen);
|
||||
}
|
||||
return;
|
||||
case SDLK_g:
|
||||
if (!shift && !repeat && down) {
|
||||
if (video && !shift && !repeat && down) {
|
||||
sc_screen_resize_to_pixel_perfect(im->screen);
|
||||
}
|
||||
return;
|
||||
case SDLK_i:
|
||||
if (!shift && !repeat && down) {
|
||||
if (video && !shift && !repeat && down) {
|
||||
switch_fps_counter_state(im);
|
||||
}
|
||||
return;
|
||||
@ -625,6 +626,23 @@ sc_input_manager_process_key(struct sc_input_manager *im,
|
||||
im->kp->ops->process_key(im->kp, &evt, ack_to_wait);
|
||||
}
|
||||
|
||||
static struct sc_position
|
||||
sc_input_manager_get_position(struct sc_input_manager *im, int32_t x,
|
||||
int32_t y) {
|
||||
if (im->mp->relative_mode) {
|
||||
// No absolute position
|
||||
return (struct sc_position) {
|
||||
.screen_size = {0, 0},
|
||||
.point = {0, 0},
|
||||
};
|
||||
}
|
||||
|
||||
return (struct sc_position) {
|
||||
.screen_size = im->screen->frame_size,
|
||||
.point = sc_screen_convert_window_to_frame_coords(im->screen, x, y),
|
||||
};
|
||||
}
|
||||
|
||||
static void
|
||||
sc_input_manager_process_mouse_motion(struct sc_input_manager *im,
|
||||
const SDL_MouseMotionEvent *event) {
|
||||
@ -634,12 +652,7 @@ sc_input_manager_process_mouse_motion(struct sc_input_manager *im,
|
||||
}
|
||||
|
||||
struct sc_mouse_motion_event evt = {
|
||||
.position = {
|
||||
.screen_size = im->screen->frame_size,
|
||||
.point = sc_screen_convert_window_to_frame_coords(im->screen,
|
||||
event->x,
|
||||
event->y),
|
||||
},
|
||||
.position = sc_input_manager_get_position(im, event->x, event->y),
|
||||
.pointer_id = im->forward_all_clicks ? POINTER_ID_MOUSE
|
||||
: POINTER_ID_GENERIC_FINGER,
|
||||
.xrel = event->xrel,
|
||||
@ -735,7 +748,8 @@ sc_input_manager_process_mouse_button(struct sc_input_manager *im,
|
||||
}
|
||||
|
||||
// double-click on black borders resize to fit the device screen
|
||||
if (event->button == SDL_BUTTON_LEFT && event->clicks == 2) {
|
||||
bool video = im->screen->video;
|
||||
if (video && event->button == SDL_BUTTON_LEFT && event->clicks == 2) {
|
||||
int32_t x = event->x;
|
||||
int32_t y = event->y;
|
||||
sc_screen_hidpi_scale_coords(im->screen, &x, &y);
|
||||
@ -759,12 +773,7 @@ sc_input_manager_process_mouse_button(struct sc_input_manager *im,
|
||||
uint32_t sdl_buttons_state = SDL_GetMouseState(NULL, NULL);
|
||||
|
||||
struct sc_mouse_click_event evt = {
|
||||
.position = {
|
||||
.screen_size = im->screen->frame_size,
|
||||
.point = sc_screen_convert_window_to_frame_coords(im->screen,
|
||||
event->x,
|
||||
event->y),
|
||||
},
|
||||
.position = sc_input_manager_get_position(im, event->x, event->y),
|
||||
.action = sc_action_from_sdl_mousebutton_type(event->type),
|
||||
.button = sc_mouse_button_from_sdl(event->button),
|
||||
.pointer_id = im->forward_all_clicks ? POINTER_ID_MOUSE
|
||||
@ -839,11 +848,7 @@ sc_input_manager_process_mouse_wheel(struct sc_input_manager *im,
|
||||
uint32_t buttons = SDL_GetMouseState(&mouse_x, &mouse_y);
|
||||
|
||||
struct sc_mouse_scroll_event evt = {
|
||||
.position = {
|
||||
.screen_size = im->screen->frame_size,
|
||||
.point = sc_screen_convert_window_to_frame_coords(im->screen,
|
||||
mouse_x, mouse_y),
|
||||
},
|
||||
.position = sc_input_manager_get_position(im, mouse_x, mouse_y),
|
||||
#if SDL_VERSION_ATLEAST(2, 0, 18)
|
||||
.hscroll = CLAMP(event->preciseX, -1.0f, 1.0f),
|
||||
.vscroll = CLAMP(event->preciseY, -1.0f, 1.0f),
|
||||
|
@ -89,6 +89,7 @@ const struct scrcpy_options scrcpy_options_default = {
|
||||
.kill_adb_on_close = false,
|
||||
.camera_high_speed = false,
|
||||
.list = 0,
|
||||
.window = true,
|
||||
};
|
||||
|
||||
enum sc_orientation
|
||||
|
@ -279,6 +279,7 @@ struct scrcpy_options {
|
||||
#define SC_OPTION_LIST_CAMERAS 0x4
|
||||
#define SC_OPTION_LIST_CAMERA_SIZES 0x8
|
||||
uint8_t list;
|
||||
bool window;
|
||||
};
|
||||
|
||||
extern const struct scrcpy_options scrcpy_options_default;
|
||||
|
@ -408,7 +408,7 @@ scrcpy(struct scrcpy_options *options) {
|
||||
return SCRCPY_EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (options->video_playback) {
|
||||
if (options->window) {
|
||||
// Set hints before starting the server thread to avoid race conditions
|
||||
// in SDL
|
||||
sdl_set_hints(options->render_driver);
|
||||
@ -430,7 +430,7 @@ scrcpy(struct scrcpy_options *options) {
|
||||
assert(!options->video_playback || options->video);
|
||||
assert(!options->audio_playback || options->audio);
|
||||
|
||||
if (options->video_playback ||
|
||||
if (options->window ||
|
||||
(options->control && options->clipboard_autosync)) {
|
||||
// Initialize the video subsystem even if --no-video or
|
||||
// --no-video-playback is passed so that clipboard synchronization
|
||||
@ -684,11 +684,12 @@ scrcpy(struct scrcpy_options *options) {
|
||||
// There is a controller if and only if control is enabled
|
||||
assert(options->control == !!controller);
|
||||
|
||||
if (options->video_playback) {
|
||||
if (options->window) {
|
||||
const char *window_title =
|
||||
options->window_title ? options->window_title : info->device_name;
|
||||
|
||||
struct sc_screen_params screen_params = {
|
||||
.video = options->video_playback,
|
||||
.controller = controller,
|
||||
.fp = fp,
|
||||
.kp = kp,
|
||||
@ -710,21 +711,26 @@ scrcpy(struct scrcpy_options *options) {
|
||||
.start_fps_counter = options->start_fps_counter,
|
||||
};
|
||||
|
||||
struct sc_frame_source *src = &s->video_decoder.frame_source;
|
||||
struct sc_frame_source *src;
|
||||
if (options->video_playback) {
|
||||
src = &s->video_decoder.frame_source;
|
||||
if (options->display_buffer) {
|
||||
sc_delay_buffer_init(&s->display_buffer, options->display_buffer,
|
||||
true);
|
||||
sc_delay_buffer_init(&s->display_buffer,
|
||||
options->display_buffer, true);
|
||||
sc_frame_source_add_sink(src, &s->display_buffer.frame_sink);
|
||||
src = &s->display_buffer.frame_source;
|
||||
}
|
||||
}
|
||||
|
||||
if (!sc_screen_init(&s->screen, &screen_params)) {
|
||||
goto end;
|
||||
}
|
||||
screen_initialized = true;
|
||||
|
||||
if (options->video_playback) {
|
||||
sc_frame_source_add_sink(src, &s->screen.frame_sink);
|
||||
}
|
||||
}
|
||||
|
||||
if (options->audio_playback) {
|
||||
sc_audio_player_init(&s->audio_player, options->audio_buffer,
|
||||
|
113
app/src/screen.c
113
app/src/screen.c
@ -205,6 +205,8 @@ sc_screen_toggle_mouse_capture(struct sc_screen *screen) {
|
||||
|
||||
static void
|
||||
sc_screen_update_content_rect(struct sc_screen *screen) {
|
||||
assert(screen->video);
|
||||
|
||||
int dw;
|
||||
int dh;
|
||||
SDL_GL_GetDrawableSize(screen->window, &dw, &dh);
|
||||
@ -246,6 +248,8 @@ sc_screen_update_content_rect(struct sc_screen *screen) {
|
||||
// changed, so that the content rectangle is recomputed
|
||||
static void
|
||||
sc_screen_render(struct sc_screen *screen, bool update_content_rect) {
|
||||
assert(screen->video);
|
||||
|
||||
if (update_content_rect) {
|
||||
sc_screen_update_content_rect(screen);
|
||||
}
|
||||
@ -255,6 +259,13 @@ sc_screen_render(struct sc_screen *screen, bool update_content_rect) {
|
||||
(void) res; // any error already logged
|
||||
}
|
||||
|
||||
static void
|
||||
sc_screen_render_novideo(struct sc_screen *screen) {
|
||||
enum sc_display_result res =
|
||||
sc_display_render(&screen->display, NULL, SC_ORIENTATION_0);
|
||||
(void) res; // any error already logged
|
||||
}
|
||||
|
||||
#if defined(__APPLE__) || defined(__WINDOWS__)
|
||||
# define CONTINUOUS_RESIZING_WORKAROUND
|
||||
#endif
|
||||
@ -268,6 +279,8 @@ sc_screen_render(struct sc_screen *screen, bool update_content_rect) {
|
||||
static int
|
||||
event_watcher(void *data, SDL_Event *event) {
|
||||
struct sc_screen *screen = data;
|
||||
assert(screen->video);
|
||||
|
||||
if (event->type == SDL_WINDOWEVENT
|
||||
&& event->window.event == SDL_WINDOWEVENT_RESIZED) {
|
||||
// In practice, it seems to always be called from the same thread in
|
||||
@ -326,6 +339,7 @@ sc_screen_frame_sink_close(struct sc_frame_sink *sink) {
|
||||
static bool
|
||||
sc_screen_frame_sink_push(struct sc_frame_sink *sink, const AVFrame *frame) {
|
||||
struct sc_screen *screen = DOWNCAST(sink);
|
||||
assert(screen->video);
|
||||
|
||||
bool previous_skipped;
|
||||
bool ok = sc_frame_buffer_push(&screen->fb, frame, &previous_skipped);
|
||||
@ -364,6 +378,9 @@ sc_screen_init(struct sc_screen *screen,
|
||||
screen->mouse_capture_key_pressed = 0;
|
||||
screen->paused = false;
|
||||
screen->resume_frame = NULL;
|
||||
screen->orientation = SC_ORIENTATION_0;
|
||||
|
||||
screen->video = params->video;
|
||||
|
||||
screen->req.x = params->window_x;
|
||||
screen->req.y = params->window_y;
|
||||
@ -381,41 +398,75 @@ sc_screen_init(struct sc_screen *screen,
|
||||
goto error_destroy_frame_buffer;
|
||||
}
|
||||
|
||||
if (screen->video) {
|
||||
screen->orientation = params->orientation;
|
||||
if (screen->orientation != SC_ORIENTATION_0) {
|
||||
LOGI("Initial display orientation set to %s",
|
||||
sc_orientation_get_name(screen->orientation));
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t window_flags = SDL_WINDOW_HIDDEN
|
||||
| SDL_WINDOW_RESIZABLE
|
||||
| SDL_WINDOW_ALLOW_HIGHDPI;
|
||||
uint32_t window_flags = SDL_WINDOW_ALLOW_HIGHDPI;
|
||||
if (params->always_on_top) {
|
||||
window_flags |= SDL_WINDOW_ALWAYS_ON_TOP;
|
||||
}
|
||||
if (params->window_borderless) {
|
||||
window_flags |= SDL_WINDOW_BORDERLESS;
|
||||
}
|
||||
if (params->video) {
|
||||
// The window will be shown on first frame
|
||||
window_flags |= SDL_WINDOW_HIDDEN
|
||||
| SDL_WINDOW_RESIZABLE;
|
||||
}
|
||||
|
||||
const char *title = params->window_title;
|
||||
assert(title);
|
||||
|
||||
int x = SDL_WINDOWPOS_UNDEFINED;
|
||||
int y = SDL_WINDOWPOS_UNDEFINED;
|
||||
int width = 256;
|
||||
int height = 256;
|
||||
if (params->window_x != SC_WINDOW_POSITION_UNDEFINED) {
|
||||
x = params->window_x;
|
||||
}
|
||||
if (params->window_y != SC_WINDOW_POSITION_UNDEFINED) {
|
||||
y = params->window_y;
|
||||
}
|
||||
if (params->window_width) {
|
||||
width = params->window_width;
|
||||
}
|
||||
if (params->window_height) {
|
||||
height = params->window_height;
|
||||
}
|
||||
|
||||
// The window will be positioned and sized on first video frame
|
||||
screen->window =
|
||||
SDL_CreateWindow(params->window_title, 0, 0, 0, 0, window_flags);
|
||||
screen->window = SDL_CreateWindow(title, x, y, width, height, window_flags);
|
||||
if (!screen->window) {
|
||||
LOGE("Could not create window: %s", SDL_GetError());
|
||||
goto error_destroy_fps_counter;
|
||||
}
|
||||
|
||||
ok = sc_display_init(&screen->display, screen->window, params->mipmaps);
|
||||
if (!ok) {
|
||||
goto error_destroy_window;
|
||||
}
|
||||
|
||||
SDL_Surface *icon = scrcpy_icon_load();
|
||||
if (icon) {
|
||||
SDL_SetWindowIcon(screen->window, icon);
|
||||
scrcpy_icon_destroy(icon);
|
||||
} else {
|
||||
} else if (params->video) {
|
||||
// just a warning
|
||||
LOGW("Could not load icon");
|
||||
} else {
|
||||
// without video, the icon is used as window content, it must be present
|
||||
LOGE("Could not load icon");
|
||||
goto error_destroy_fps_counter;
|
||||
}
|
||||
|
||||
SDL_Surface *icon_novideo = params->video ? NULL : icon;
|
||||
bool mipmaps = params->video && params->mipmaps;
|
||||
ok = sc_display_init(&screen->display, screen->window, icon_novideo,
|
||||
mipmaps);
|
||||
if (icon) {
|
||||
scrcpy_icon_destroy(icon);
|
||||
}
|
||||
if (!ok) {
|
||||
goto error_destroy_window;
|
||||
}
|
||||
|
||||
screen->frame = av_frame_alloc();
|
||||
@ -439,7 +490,9 @@ sc_screen_init(struct sc_screen *screen,
|
||||
sc_input_manager_init(&screen->im, &im_params);
|
||||
|
||||
#ifdef CONTINUOUS_RESIZING_WORKAROUND
|
||||
if (screen->video) {
|
||||
SDL_AddEventWatch(event_watcher, screen);
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct sc_frame_sink_ops ops = {
|
||||
@ -454,6 +507,11 @@ sc_screen_init(struct sc_screen *screen,
|
||||
screen->open = false;
|
||||
#endif
|
||||
|
||||
if (!screen->video && sc_screen_is_relative_mode(screen)) {
|
||||
// Capture mouse immediately if video mirroring is disabled
|
||||
sc_screen_set_mouse_capture(screen, true);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
error_destroy_display:
|
||||
@ -524,6 +582,8 @@ sc_screen_destroy(struct sc_screen *screen) {
|
||||
static void
|
||||
resize_for_content(struct sc_screen *screen, struct sc_size old_content_size,
|
||||
struct sc_size new_content_size) {
|
||||
assert(screen->video);
|
||||
|
||||
struct sc_size window_size = get_window_size(screen);
|
||||
struct sc_size target_size = {
|
||||
.width = (uint32_t) window_size.width * new_content_size.width
|
||||
@ -537,6 +597,8 @@ resize_for_content(struct sc_screen *screen, struct sc_size old_content_size,
|
||||
|
||||
static void
|
||||
set_content_size(struct sc_screen *screen, struct sc_size new_content_size) {
|
||||
assert(screen->video);
|
||||
|
||||
if (!screen->fullscreen && !screen->maximized && !screen->minimized) {
|
||||
resize_for_content(screen, screen->content_size, new_content_size);
|
||||
} else if (!screen->resize_pending) {
|
||||
@ -551,6 +613,8 @@ set_content_size(struct sc_screen *screen, struct sc_size new_content_size) {
|
||||
|
||||
static void
|
||||
apply_pending_resize(struct sc_screen *screen) {
|
||||
assert(screen->video);
|
||||
|
||||
assert(!screen->fullscreen);
|
||||
assert(!screen->maximized);
|
||||
assert(!screen->minimized);
|
||||
@ -564,6 +628,8 @@ apply_pending_resize(struct sc_screen *screen) {
|
||||
void
|
||||
sc_screen_set_orientation(struct sc_screen *screen,
|
||||
enum sc_orientation orientation) {
|
||||
assert(screen->video);
|
||||
|
||||
if (orientation == screen->orientation) {
|
||||
return;
|
||||
}
|
||||
@ -598,6 +664,8 @@ sc_screen_init_size(struct sc_screen *screen) {
|
||||
// recreate the texture and resize the window if the frame size has changed
|
||||
static enum sc_display_result
|
||||
prepare_for_frame(struct sc_screen *screen, struct sc_size new_frame_size) {
|
||||
assert(screen->video);
|
||||
|
||||
if (screen->frame_size.width == new_frame_size.width
|
||||
&& screen->frame_size.height == new_frame_size.height) {
|
||||
return SC_DISPLAY_RESULT_OK;
|
||||
@ -617,6 +685,8 @@ prepare_for_frame(struct sc_screen *screen, struct sc_size new_frame_size) {
|
||||
|
||||
static bool
|
||||
sc_screen_apply_frame(struct sc_screen *screen) {
|
||||
assert(screen->video);
|
||||
|
||||
sc_fps_counter_add_rendered_frame(&screen->fps_counter);
|
||||
|
||||
AVFrame *frame = screen->frame;
|
||||
@ -656,6 +726,8 @@ sc_screen_apply_frame(struct sc_screen *screen) {
|
||||
|
||||
static bool
|
||||
sc_screen_update_frame(struct sc_screen *screen) {
|
||||
assert(screen->video);
|
||||
|
||||
if (screen->paused) {
|
||||
if (!screen->resume_frame) {
|
||||
screen->resume_frame = av_frame_alloc();
|
||||
@ -677,6 +749,8 @@ sc_screen_update_frame(struct sc_screen *screen) {
|
||||
|
||||
void
|
||||
sc_screen_set_paused(struct sc_screen *screen, bool paused) {
|
||||
assert(screen->video);
|
||||
|
||||
if (!paused && !screen->paused) {
|
||||
// nothing to do
|
||||
return;
|
||||
@ -704,6 +778,8 @@ sc_screen_set_paused(struct sc_screen *screen, bool paused) {
|
||||
|
||||
void
|
||||
sc_screen_switch_fullscreen(struct sc_screen *screen) {
|
||||
assert(screen->video);
|
||||
|
||||
uint32_t new_mode = screen->fullscreen ? 0 : SDL_WINDOW_FULLSCREEN_DESKTOP;
|
||||
if (SDL_SetWindowFullscreen(screen->window, new_mode)) {
|
||||
LOGW("Could not switch fullscreen mode: %s", SDL_GetError());
|
||||
@ -721,6 +797,8 @@ sc_screen_switch_fullscreen(struct sc_screen *screen) {
|
||||
|
||||
void
|
||||
sc_screen_resize_to_fit(struct sc_screen *screen) {
|
||||
assert(screen->video);
|
||||
|
||||
if (screen->fullscreen || screen->maximized || screen->minimized) {
|
||||
return;
|
||||
}
|
||||
@ -745,6 +823,8 @@ sc_screen_resize_to_fit(struct sc_screen *screen) {
|
||||
|
||||
void
|
||||
sc_screen_resize_to_pixel_perfect(struct sc_screen *screen) {
|
||||
assert(screen->video);
|
||||
|
||||
if (screen->fullscreen || screen->minimized) {
|
||||
return;
|
||||
}
|
||||
@ -788,6 +868,13 @@ sc_screen_handle_event(struct sc_screen *screen, const SDL_Event *event) {
|
||||
return true;
|
||||
}
|
||||
case SDL_WINDOWEVENT:
|
||||
if (!screen->video
|
||||
&& event->window.event == SDL_WINDOWEVENT_EXPOSED) {
|
||||
sc_screen_render_novideo(screen);
|
||||
}
|
||||
|
||||
// !video implies !has_frame
|
||||
assert(screen->video || !screen->has_frame);
|
||||
if (!screen->has_frame) {
|
||||
// Do nothing
|
||||
return true;
|
||||
@ -891,6 +978,8 @@ sc_screen_handle_event(struct sc_screen *screen, const SDL_Event *event) {
|
||||
struct sc_point
|
||||
sc_screen_convert_drawable_to_frame_coords(struct sc_screen *screen,
|
||||
int32_t x, int32_t y) {
|
||||
assert(screen->video);
|
||||
|
||||
enum sc_orientation orientation = screen->orientation;
|
||||
|
||||
int32_t w = screen->content_size.width;
|
||||
|
@ -26,6 +26,8 @@ struct sc_screen {
|
||||
bool open; // track the open/close state to assert correct behavior
|
||||
#endif
|
||||
|
||||
bool video;
|
||||
|
||||
struct sc_display display;
|
||||
struct sc_input_manager im;
|
||||
struct sc_frame_buffer fb;
|
||||
@ -70,6 +72,8 @@ struct sc_screen {
|
||||
};
|
||||
|
||||
struct sc_screen_params {
|
||||
bool video;
|
||||
|
||||
struct sc_controller *controller;
|
||||
struct sc_file_pusher *fp;
|
||||
struct sc_key_processor *kp;
|
||||
|
Loading…
Reference in New Issue
Block a user