diff --git a/app/src/common.h b/app/src/common.h index 8963f058..9eba00ac 100644 --- a/app/src/common.h +++ b/app/src/common.h @@ -17,6 +17,11 @@ struct point { int32_t y; }; +struct window_position { + int16_t x; + int16_t y; +}; + struct position { // The video screen size may be different from the real device screen size, // so store to which size the absolute position apply, to scale it diff --git a/app/src/main.c b/app/src/main.c index dfeca7cb..bd4348d7 100644 --- a/app/src/main.c +++ b/app/src/main.c @@ -28,8 +28,11 @@ struct args { bool show_touches; uint16_t port; uint16_t max_size; + int16_t x; + int16_t y; uint32_t bit_rate; bool always_on_top; + bool borderless; bool turn_screen_off; bool render_expired_frames; }; @@ -49,6 +52,8 @@ static void usage(const char *arg0) { " Encode the video at the given bit-rate, expressed in bits/s.\n" " Unit suffixes are supported: 'K' (x1000) and 'M' (x1000000).\n" " Default is %d.\n" + " -B, --borderless\n" + " Make scrcpy window borderless.\n" "\n" " -c, --crop width:height:x:y\n" " Crop the device screen on the server.\n" @@ -115,6 +120,13 @@ static void usage(const char *arg0) { " -v, --version\n" " Print the version of scrcpy.\n" "\n" + " -x, --pos-x value\n" + " Set the window horizontal position.\n" + " Default is automatic\n" + " -y, --pos-y value\n" + " Set the window vertical position.\n" + " Default is automatic.\n" + "\n" " --window-title text\n" " Set a custom window title.\n" "\n" @@ -258,6 +270,28 @@ parse_max_size(char *optarg, uint16_t *max_size) { return true; } +static bool +parse_position(char *optarg, int16_t *position) { + char *endptr; + if (*optarg == '\0') { + LOGE("Position (x,y) parameter is empty"); + return false; + } + long value = strtol(optarg, &endptr, 0); + if (*endptr != '\0') { + LOGE("Invalid position (x,y): %s", optarg); + return false; + } + if (value & ~0x7fff) { + LOGE("Position (x,y) must be between -32767 and 32767: %ld", value); + return false; + } + + *position = (int16_t) value; + return true; +} + + static bool parse_port(char *optarg, uint16_t *port) { char *endptr; @@ -317,6 +351,7 @@ static bool parse_args(struct args *args, int argc, char *argv[]) { static const struct option long_options[] = { {"always-on-top", no_argument, NULL, 'T'}, + {"borderless", no_argument, NULL, 'B'}, {"bit-rate", required_argument, NULL, 'b'}, {"crop", required_argument, NULL, 'c'}, {"fullscreen", no_argument, NULL, 'f'}, @@ -335,12 +370,16 @@ parse_args(struct args *args, int argc, char *argv[]) { {"show-touches", no_argument, NULL, 't'}, {"turn-screen-off", no_argument, NULL, 'S'}, {"version", no_argument, NULL, 'v'}, + + {"pos-x", required_argument, NULL, 'x'}, + {"pos-y", required_argument, NULL, 'y'}, + {"window-title", required_argument, NULL, OPT_WINDOW_TITLE}, {NULL, 0, NULL, 0 }, }; int c; - while ((c = getopt_long(argc, argv, "b:c:fF:hm:nNp:r:s:StTv", long_options, + while ((c = getopt_long(argc, argv, "b:c:fF:hm:nNp:r:s:StTBvx:y:", long_options, NULL)) != -1) { switch (c) { case 'b': @@ -348,6 +387,9 @@ parse_args(struct args *args, int argc, char *argv[]) { return false; } break; + case 'B': + args->borderless = true; + break; case 'c': args->crop = optarg; break; @@ -396,6 +438,16 @@ parse_args(struct args *args, int argc, char *argv[]) { case 'v': args->version = true; break; + case 'x': + if (!parse_position(optarg, &args->x)) { + return false; + } + break; + case 'y': + if (!parse_position(optarg, &args->y)) { + return false; + } + break; case OPT_RENDER_EXPIRED_FRAMES: args->render_expired_frames = true; break; @@ -469,8 +521,11 @@ main(int argc, char *argv[]) { .show_touches = false, .port = DEFAULT_LOCAL_PORT, .max_size = DEFAULT_MAX_SIZE, + .x = -1, + .y = -1, .bit_rate = DEFAULT_BIT_RATE, .always_on_top = false, + .borderless = false, .no_control = false, .no_display = false, .turn_screen_off = false, @@ -513,10 +568,13 @@ main(int argc, char *argv[]) { .push_target = args.push_target, .record_format = args.record_format, .max_size = args.max_size, + .x = args.x, + .y = args.y, .bit_rate = args.bit_rate, .show_touches = args.show_touches, .fullscreen = args.fullscreen, .always_on_top = args.always_on_top, + .borderless = args.borderless, .control = !args.no_control, .display = !args.no_display, .turn_screen_off = args.turn_screen_off, diff --git a/app/src/scrcpy.c b/app/src/scrcpy.c index ed988778..47e05062 100644 --- a/app/src/scrcpy.c +++ b/app/src/scrcpy.c @@ -383,8 +383,14 @@ scrcpy(const struct scrcpy_options *options) { const char *window_title = options->window_title ? options->window_title : device_name; - if (!screen_init_rendering(&screen, window_title, frame_size, - options->always_on_top)) { + + struct window_position window_position; + + window_position.x = options->x; + window_position.y = options->y; + + if (!screen_init_rendering(&screen, window_title, frame_size, window_position, + options->always_on_top, options->borderless)) { goto end; } diff --git a/app/src/scrcpy.h b/app/src/scrcpy.h index faeb246f..5bd61664 100644 --- a/app/src/scrcpy.h +++ b/app/src/scrcpy.h @@ -14,10 +14,13 @@ struct scrcpy_options { enum recorder_format record_format; uint16_t port; uint16_t max_size; + int16_t x; + int16_t y; uint32_t bit_rate; bool show_touches; bool fullscreen; bool always_on_top; + bool borderless; bool control; bool display; bool turn_screen_off; diff --git a/app/src/screen.c b/app/src/screen.c index 18d24dda..1d5e2b3c 100644 --- a/app/src/screen.c +++ b/app/src/screen.c @@ -135,8 +135,9 @@ create_texture(SDL_Renderer *renderer, struct size frame_size) { bool screen_init_rendering(struct screen *screen, const char *window_title, - struct size frame_size, bool always_on_top) { + struct size frame_size, struct window_position window_position ,bool always_on_top, bool borderless) { screen->frame_size = frame_size; + screen->window_position = window_position; struct size window_size = get_initial_optimal_size(frame_size); uint32_t window_flags = SDL_WINDOW_HIDDEN | SDL_WINDOW_RESIZABLE; @@ -152,8 +153,13 @@ screen_init_rendering(struct screen *screen, const char *window_title, #endif } - screen->window = SDL_CreateWindow(window_title, SDL_WINDOWPOS_UNDEFINED, - SDL_WINDOWPOS_UNDEFINED, + if (borderless) { + window_flags |= SDL_WINDOW_BORDERLESS; + } + + screen->window = SDL_CreateWindow(window_title, + screen->window_position.x == -1? SDL_WINDOWPOS_UNDEFINED:screen->window_position.x, + screen->window_position.y == -1? SDL_WINDOWPOS_UNDEFINED:screen->window_position.y, window_size.width, window_size.height, window_flags); if (!screen->window) { diff --git a/app/src/screen.h b/app/src/screen.h index 63da6aa5..c550b9ed 100644 --- a/app/src/screen.h +++ b/app/src/screen.h @@ -13,6 +13,7 @@ struct screen { SDL_Window *window; SDL_Renderer *renderer; SDL_Texture *texture; + struct window_position window_position; struct size frame_size; //used only in fullscreen mode to know the windowed window size struct size windowed_window_size; @@ -25,6 +26,10 @@ struct screen { .window = NULL, \ .renderer = NULL, \ .texture = NULL, \ + .window_position = { \ + .x = -1, \ + .y = -1, \ + }, \ .frame_size = { \ .width = 0, \ .height = 0, \ @@ -45,7 +50,7 @@ screen_init(struct screen *screen); // initialize screen, create window, renderer and texture (window is hidden) bool screen_init_rendering(struct screen *screen, const char *window_title, - struct size frame_size, bool always_on_top); + struct size frame_size, struct window_position window_position, bool always_on_top, bool borderless); // show the window void