From 78c4674d97eb96452bc1b1ead0f94b7bc68e5269 Mon Sep 17 00:00:00 2001 From: Romain Vimont Date: Sun, 29 Jun 2025 18:22:46 +0200 Subject: [PATCH 1/8] Handle mouse integer scrolling locally Do not rely on SDL to expose integer scroll values, as they are not available in all versions. It was reimplemented in SDL 3.2.12 by this commit: Refs #6156 --- app/src/hid/hid_mouse.c | 35 ++++++++++++++++++++++++++++------- app/src/hid/hid_mouse.h | 10 +++++++++- app/src/input_events.h | 2 -- app/src/input_manager.c | 2 -- app/src/uhid/mouse_uhid.c | 5 ++++- app/src/uhid/mouse_uhid.h | 2 ++ app/src/usb/mouse_aoa.c | 5 ++++- app/src/usb/mouse_aoa.h | 2 ++ app/src/usb/screen_otg.c | 2 -- 9 files changed, 49 insertions(+), 16 deletions(-) diff --git a/app/src/hid/hid_mouse.c b/app/src/hid/hid_mouse.c index 33f0807e..54105a17 100644 --- a/app/src/hid/hid_mouse.c +++ b/app/src/hid/hid_mouse.c @@ -166,6 +166,12 @@ sc_hid_buttons_from_buttons_state(uint8_t buttons_state) { return c; } +void +sc_hid_mouse_init(struct sc_hid_mouse *hid) { + hid->residual_hscroll = 0; + hid->residual_vscroll = 0; +} + void sc_hid_mouse_generate_input_from_motion(struct sc_hid_input *hid_input, const struct sc_mouse_motion_event *event) { @@ -192,22 +198,37 @@ sc_hid_mouse_generate_input_from_click(struct sc_hid_input *hid_input, data[4] = 0; // no horizontal scrolling } +static int8_t +consume_scroll_integer(float *scroll) { + float value = CLAMP(*scroll, -127, 127); + int8_t consume = value; // truncate towards 0 + float residual = value - consume; + *scroll = residual; + return consume; +} + bool -sc_hid_mouse_generate_input_from_scroll(struct sc_hid_input *hid_input, +sc_hid_mouse_generate_input_from_scroll(struct sc_hid_mouse *hid, + struct sc_hid_input *hid_input, const struct sc_mouse_scroll_event *event) { - if (!event->vscroll_int && !event->hscroll_int) { - // Need a full integral value for HID + sc_hid_mouse_input_init(hid_input); + + hid->residual_hscroll += event->hscroll; + hid->residual_vscroll += event->vscroll; + int8_t hscroll = consume_scroll_integer(&hid->residual_hscroll); + int8_t vscroll = consume_scroll_integer(&hid->residual_vscroll); + + if (!hscroll && !vscroll) { + // Not enough scrolling to inject a scroll event return false; } - sc_hid_mouse_input_init(hid_input); - uint8_t *data = hid_input->data; data[0] = 0; // buttons state irrelevant (and unknown) data[1] = 0; // no x motion data[2] = 0; // no y motion - data[3] = CLAMP(event->vscroll_int, -127, 127); - data[4] = CLAMP(event->hscroll_int, -127, 127); + data[3] = vscroll; + data[4] = hscroll; return true; } diff --git a/app/src/hid/hid_mouse.h b/app/src/hid/hid_mouse.h index 4ae4bfd4..6d590267 100644 --- a/app/src/hid/hid_mouse.h +++ b/app/src/hid/hid_mouse.h @@ -8,6 +8,13 @@ #define SC_HID_ID_MOUSE 2 +struct sc_hid_mouse { + float residual_hscroll; + float residual_vscroll; +}; + +void sc_hid_mouse_init(struct sc_hid_mouse *hid); + void sc_hid_mouse_generate_open(struct sc_hid_open *hid_open); @@ -23,7 +30,8 @@ sc_hid_mouse_generate_input_from_click(struct sc_hid_input *hid_input, const struct sc_mouse_click_event *event); bool -sc_hid_mouse_generate_input_from_scroll(struct sc_hid_input *hid_input, +sc_hid_mouse_generate_input_from_scroll(struct sc_hid_mouse *hid, + struct sc_hid_input *hid_input, const struct sc_mouse_scroll_event *event); #endif diff --git a/app/src/input_events.h b/app/src/input_events.h index 1e34b50e..0c022acc 100644 --- a/app/src/input_events.h +++ b/app/src/input_events.h @@ -393,8 +393,6 @@ struct sc_mouse_scroll_event { struct sc_position position; float hscroll; float vscroll; - int32_t hscroll_int; - int32_t vscroll_int; uint8_t buttons_state; // bitwise-OR of sc_mouse_button values }; diff --git a/app/src/input_manager.c b/app/src/input_manager.c index 3e4dd0f3..f7a787d1 100644 --- a/app/src/input_manager.c +++ b/app/src/input_manager.c @@ -903,8 +903,6 @@ sc_input_manager_process_mouse_wheel(struct sc_input_manager *im, .hscroll = event->x, .vscroll = event->y, #endif - .hscroll_int = event->x, - .vscroll_int = event->y, .buttons_state = im->mouse_buttons_state, }; diff --git a/app/src/uhid/mouse_uhid.c b/app/src/uhid/mouse_uhid.c index 869e48a4..1277ed84 100644 --- a/app/src/uhid/mouse_uhid.c +++ b/app/src/uhid/mouse_uhid.c @@ -55,7 +55,8 @@ sc_mouse_processor_process_mouse_scroll(struct sc_mouse_processor *mp, struct sc_mouse_uhid *mouse = DOWNCAST(mp); struct sc_hid_input hid_input; - if (!sc_hid_mouse_generate_input_from_scroll(&hid_input, event)) { + if (!sc_hid_mouse_generate_input_from_scroll(&mouse->hid, &hid_input, + event)) { return; } @@ -65,6 +66,8 @@ sc_mouse_processor_process_mouse_scroll(struct sc_mouse_processor *mp, bool sc_mouse_uhid_init(struct sc_mouse_uhid *mouse, struct sc_controller *controller) { + sc_hid_mouse_init(&mouse->hid); + mouse->controller = controller; static const struct sc_mouse_processor_ops ops = { diff --git a/app/src/uhid/mouse_uhid.h b/app/src/uhid/mouse_uhid.h index f117ba97..998bf21a 100644 --- a/app/src/uhid/mouse_uhid.h +++ b/app/src/uhid/mouse_uhid.h @@ -4,11 +4,13 @@ #include #include "controller.h" +#include "hid/hid_mouse.h" #include "trait/mouse_processor.h" struct sc_mouse_uhid { struct sc_mouse_processor mouse_processor; // mouse processor trait + struct sc_hid_mouse hid; struct sc_controller *controller; }; diff --git a/app/src/usb/mouse_aoa.c b/app/src/usb/mouse_aoa.c index fd5fa5e0..4bc76c54 100644 --- a/app/src/usb/mouse_aoa.c +++ b/app/src/usb/mouse_aoa.c @@ -42,7 +42,8 @@ sc_mouse_processor_process_mouse_scroll(struct sc_mouse_processor *mp, struct sc_mouse_aoa *mouse = DOWNCAST(mp); struct sc_hid_input hid_input; - if (!sc_hid_mouse_generate_input_from_scroll(&hid_input, event)) { + if (!sc_hid_mouse_generate_input_from_scroll(&mouse->hid, &hid_input, + event)) { return; } @@ -64,6 +65,8 @@ sc_mouse_aoa_init(struct sc_mouse_aoa *mouse, struct sc_aoa *aoa) { return false; } + sc_hid_mouse_init(&mouse->hid); + static const struct sc_mouse_processor_ops ops = { .process_mouse_motion = sc_mouse_processor_process_mouse_motion, .process_mouse_click = sc_mouse_processor_process_mouse_click, diff --git a/app/src/usb/mouse_aoa.h b/app/src/usb/mouse_aoa.h index 506286ba..1a25d986 100644 --- a/app/src/usb/mouse_aoa.h +++ b/app/src/usb/mouse_aoa.h @@ -6,11 +6,13 @@ #include #include "usb/aoa_hid.h" +#include "hid/hid_mouse.h" #include "trait/mouse_processor.h" struct sc_mouse_aoa { struct sc_mouse_processor mouse_processor; // mouse processor trait + struct sc_hid_mouse hid; struct sc_aoa *aoa; }; diff --git a/app/src/usb/screen_otg.c b/app/src/usb/screen_otg.c index 5c580df9..bed48eb6 100644 --- a/app/src/usb/screen_otg.c +++ b/app/src/usb/screen_otg.c @@ -171,8 +171,6 @@ sc_screen_otg_process_mouse_wheel(struct sc_screen_otg *screen, .hscroll = event->x, .vscroll = event->y, #endif - .hscroll_int = event->x, - .vscroll_int = event->y, .buttons_state = sc_mouse_buttons_state_from_sdl(sdl_buttons_state), }; From 6a0529ca13b9ddc7d0c872efb15311fec26a989f Mon Sep 17 00:00:00 2001 From: Romain Vimont Date: Thu, 3 Jul 2025 18:36:17 +0200 Subject: [PATCH 2/8] Remove prepare_for_frame() Inline the function body in its only caller. This will simplify further refactors. --- app/src/screen.c | 53 +++++++++++++++++++++--------------------------- 1 file changed, 23 insertions(+), 30 deletions(-) diff --git a/app/src/screen.c b/app/src/screen.c index da17df0e..67177efa 100644 --- a/app/src/screen.c +++ b/app/src/screen.c @@ -619,28 +619,6 @@ sc_screen_init_size(struct sc_screen *screen) { return res != SC_DISPLAY_RESULT_ERROR; } -// 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; - } - - // frame dimension changed - screen->frame_size = new_frame_size; - - struct sc_size new_content_size = - get_oriented_size(new_frame_size, screen->orientation); - set_content_size(screen, new_content_size); - - sc_screen_update_content_rect(screen); - - return sc_display_set_texture_size(&screen->display, screen->frame_size); -} - static bool sc_screen_apply_frame(struct sc_screen *screen) { assert(screen->video); @@ -649,16 +627,31 @@ sc_screen_apply_frame(struct sc_screen *screen) { AVFrame *frame = screen->frame; struct sc_size new_frame_size = {frame->width, frame->height}; - enum sc_display_result res = prepare_for_frame(screen, new_frame_size); - if (res == SC_DISPLAY_RESULT_ERROR) { - return false; - } - if (res == SC_DISPLAY_RESULT_PENDING) { - // Not an error, but do not continue - return true; + + if (screen->frame_size.width != new_frame_size.width + || screen->frame_size.height != new_frame_size.height) { + // frame dimension changed + screen->frame_size = new_frame_size; + + struct sc_size new_content_size = + get_oriented_size(new_frame_size, screen->orientation); + set_content_size(screen, new_content_size); + + sc_screen_update_content_rect(screen); + + enum sc_display_result res = + sc_display_set_texture_size(&screen->display, screen->frame_size); + if (res == SC_DISPLAY_RESULT_ERROR) { + return false; + } + if (res == SC_DISPLAY_RESULT_PENDING) { + // Not an error, but do not continue + return true; + } } - res = sc_display_update_texture(&screen->display, frame); + enum sc_display_result res = + sc_display_update_texture(&screen->display, frame); if (res == SC_DISPLAY_RESULT_ERROR) { return false; } From 023fad8badd9b0d76355bfb02df3ae88d71bd220 Mon Sep 17 00:00:00 2001 From: Romain Vimont Date: Thu, 3 Jul 2025 18:49:35 +0200 Subject: [PATCH 3/8] 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. --- app/src/events.h | 1 - app/src/screen.c | 66 ++++++++++++++---------------------------------- app/src/screen.h | 1 + 3 files changed, 20 insertions(+), 48 deletions(-) diff --git a/app/src/events.h b/app/src/events.h index 2fe4d3a7..2e7318e5 100644 --- a/app/src/events.h +++ b/app/src/events.h @@ -16,7 +16,6 @@ enum { SC_EVENT_USB_DEVICE_DISCONNECTED, SC_EVENT_DEMUXER_ERROR, SC_EVENT_RECORDER_ERROR, - SC_EVENT_SCREEN_INIT_SIZE, SC_EVENT_TIME_LIMIT_REACHED, SC_EVENT_CONTROLLER_ERROR, SC_EVENT_AOA_OPEN_ERROR, diff --git a/app/src/screen.c b/app/src/screen.c index 67177efa..a2c22b25 100644 --- a/app/src/screen.c +++ b/app/src/screen.c @@ -208,6 +208,7 @@ sc_screen_update_content_rect(struct sc_screen *screen) { static void sc_screen_render(struct sc_screen *screen, bool update_content_rect) { assert(screen->video); + assert(screen->has_video_window); if (update_content_rect) { sc_screen_update_content_rect(screen); @@ -264,19 +265,6 @@ sc_screen_frame_sink_open(struct sc_frame_sink *sink, return false; } - assert(ctx->width > 0 && ctx->width <= 0xFFFF); - assert(ctx->height > 0 && ctx->height <= 0xFFFF); - // screen->frame_size is never used before the event is pushed, and the - // event acts as a memory barrier so it is safe without mutex - screen->frame_size.width = ctx->width; - screen->frame_size.height = ctx->height; - - // Post the event on the UI thread (the texture must be created from there) - bool ok = sc_push_event(SC_EVENT_SCREEN_INIT_SIZE); - if (!ok) { - return false; - } - #ifndef NDEBUG screen->open = true; #endif @@ -327,6 +315,7 @@ sc_screen_init(struct sc_screen *screen, const struct sc_screen_params *params) { screen->resize_pending = false; screen->has_frame = false; + screen->has_video_window = false; screen->fullscreen = false; screen->maximized = false; screen->minimized = false; @@ -603,22 +592,6 @@ sc_screen_set_orientation(struct sc_screen *screen, sc_screen_render(screen, true); } -static bool -sc_screen_init_size(struct sc_screen *screen) { - // Before first frame - assert(!screen->has_frame); - - // The requested size is passed via screen->frame_size - - struct sc_size content_size = - get_oriented_size(screen->frame_size, screen->orientation); - screen->content_size = content_size; - - enum sc_display_result res = - sc_display_set_texture_size(&screen->display, screen->frame_size); - return res != SC_DISPLAY_RESULT_ERROR; -} - static bool sc_screen_apply_frame(struct sc_screen *screen) { assert(screen->video); @@ -628,16 +601,22 @@ sc_screen_apply_frame(struct sc_screen *screen) { AVFrame *frame = screen->frame; struct sc_size new_frame_size = {frame->width, frame->height}; - if (screen->frame_size.width != new_frame_size.width + if (!screen->has_frame + || screen->frame_size.width != new_frame_size.width || screen->frame_size.height != new_frame_size.height) { // frame dimension changed screen->frame_size = new_frame_size; struct sc_size new_content_size = get_oriented_size(new_frame_size, screen->orientation); - set_content_size(screen, new_content_size); - - sc_screen_update_content_rect(screen); + if (screen->has_frame) { + set_content_size(screen, new_content_size); + sc_screen_update_content_rect(screen); + } else { + // This is the first frame + screen->has_frame = true; + screen->content_size = new_content_size; + } enum sc_display_result res = sc_display_set_texture_size(&screen->display, screen->frame_size); @@ -660,8 +639,9 @@ sc_screen_apply_frame(struct sc_screen *screen) { return true; } - if (!screen->has_frame) { - screen->has_frame = true; + assert(screen->has_frame); + if (!screen->has_video_window) { + screen->has_video_window = true; // this is the very first frame, show the window sc_screen_show_initial_window(screen); @@ -794,15 +774,6 @@ sc_screen_resize_to_pixel_perfect(struct sc_screen *screen) { bool sc_screen_handle_event(struct sc_screen *screen, const SDL_Event *event) { switch (event->type) { - case SC_EVENT_SCREEN_INIT_SIZE: { - // The initial size is passed via screen->frame_size - bool ok = sc_screen_init_size(screen); - if (!ok) { - LOGE("Could not initialize screen size"); - return false; - } - return true; - } case SC_EVENT_NEW_FRAME: { bool ok = sc_screen_update_frame(screen); if (!ok) { @@ -815,11 +786,12 @@ sc_screen_handle_event(struct sc_screen *screen, const SDL_Event *event) { if (!screen->video && event->window.event == SDL_WINDOWEVENT_EXPOSED) { sc_screen_render_novideo(screen); + return true; } - // !video implies !has_frame - assert(screen->video || !screen->has_frame); - if (!screen->has_frame) { + // !video implies !has_video_window + assert(screen->video || !screen->has_video_window); + if (!screen->has_video_window) { // Do nothing return true; } diff --git a/app/src/screen.h b/app/src/screen.h index 6621b2d2..89a25cda 100644 --- a/app/src/screen.h +++ b/app/src/screen.h @@ -61,6 +61,7 @@ struct sc_screen { // rectangle of the content (excluding black borders) struct SDL_Rect rect; bool has_frame; + bool has_video_window; bool fullscreen; bool maximized; bool minimized; From 0b840dcef14a5d38e3c8a18fbb5a25b2d0ac2376 Mon Sep 17 00:00:00 2001 From: Romain Vimont Date: Thu, 3 Jul 2025 19:04:09 +0200 Subject: [PATCH 4/8] 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. --- app/src/display.c | 61 ++++++++++++++++++++++++----------------------- app/src/display.h | 12 ++++++---- app/src/screen.c | 3 ++- 3 files changed, 40 insertions(+), 36 deletions(-) diff --git a/app/src/display.c b/app/src/display.c index aee8ef80..b701f8bf 100644 --- a/app/src/display.c +++ b/app/src/display.c @@ -94,7 +94,6 @@ sc_display_init(struct sc_display *display, SDL_Window *window, display->texture = NULL; display->pending.flags = 0; display->pending.frame = NULL; - display->has_frame = false; if (icon_novideo) { // Without video, set a static scrcpy icon as window content @@ -125,9 +124,15 @@ sc_display_destroy(struct sc_display *display) { SDL_DestroyRenderer(display->renderer); } +static SDL_YUV_CONVERSION_MODE +sc_display_to_sdl_color_range(enum AVColorRange color_range) { + return color_range == AVCOL_RANGE_JPEG ? SDL_YUV_CONVERSION_JPEG + : SDL_YUV_CONVERSION_AUTOMATIC; +} + static SDL_Texture * sc_display_create_texture(struct sc_display *display, - struct sc_size size) { + struct sc_size size, enum AVColorRange color_range) { SDL_Renderer *renderer = display->renderer; SDL_Texture *texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_YV12, SDL_TEXTUREACCESS_STREAMING, @@ -150,14 +155,22 @@ sc_display_create_texture(struct sc_display *display, SDL_GL_UnbindTexture(texture); } + // Configure YUV color range conversion + SDL_YUV_CONVERSION_MODE sdl_color_range = + sc_display_to_sdl_color_range(color_range); + SDL_SetYUVConversionMode(sdl_color_range); + return texture; } static inline void -sc_display_set_pending_size(struct sc_display *display, struct sc_size size) { +sc_display_set_pending_texture(struct sc_display *display, + struct sc_size size, + enum AVColorRange color_range) { assert(!display->texture); - display->pending.size = size; - display->pending.flags |= SC_DISPLAY_PENDING_FLAG_SIZE; + display->pending.texture.size = size; + display->pending.texture.color_range = color_range; + display->pending.flags |= SC_DISPLAY_PENDING_FLAG_TEXTURE; } static bool @@ -183,15 +196,17 @@ sc_display_set_pending_frame(struct sc_display *display, const AVFrame *frame) { static bool sc_display_apply_pending(struct sc_display *display) { - if (display->pending.flags & SC_DISPLAY_PENDING_FLAG_SIZE) { + if (display->pending.flags & SC_DISPLAY_PENDING_FLAG_TEXTURE) { assert(!display->texture); display->texture = - sc_display_create_texture(display, display->pending.size); + sc_display_create_texture(display, + display->pending.texture.size, + display->pending.texture.color_range); if (!display->texture) { return false; } - display->pending.flags &= ~SC_DISPLAY_PENDING_FLAG_SIZE; + display->pending.flags &= ~SC_DISPLAY_PENDING_FLAG_TEXTURE; } if (display->pending.flags & SC_DISPLAY_PENDING_FLAG_FRAME) { @@ -209,15 +224,16 @@ sc_display_apply_pending(struct sc_display *display) { } static bool -sc_display_set_texture_size_internal(struct sc_display *display, - struct sc_size size) { +sc_display_prepare_texture_internal(struct sc_display *display, + struct sc_size size, + enum AVColorRange color_range) { assert(size.width && size.height); if (display->texture) { SDL_DestroyTexture(display->texture); } - display->texture = sc_display_create_texture(display, size); + display->texture = sc_display_create_texture(display, size, color_range); if (!display->texture) { return false; } @@ -227,10 +243,11 @@ sc_display_set_texture_size_internal(struct sc_display *display, } enum sc_display_result -sc_display_set_texture_size(struct sc_display *display, struct sc_size size) { - bool ok = sc_display_set_texture_size_internal(display, size); +sc_display_prepare_texture(struct sc_display *display, struct sc_size size, + enum AVColorRange color_range) { + bool ok = sc_display_prepare_texture_internal(display, size, color_range); if (!ok) { - sc_display_set_pending_size(display, size); + sc_display_set_pending_texture(display, size, color_range); return SC_DISPLAY_RESULT_PENDING; } @@ -238,25 +255,9 @@ sc_display_set_texture_size(struct sc_display *display, struct sc_size size) { return SC_DISPLAY_RESULT_OK; } -static SDL_YUV_CONVERSION_MODE -sc_display_to_sdl_color_range(enum AVColorRange color_range) { - return color_range == AVCOL_RANGE_JPEG ? SDL_YUV_CONVERSION_JPEG - : SDL_YUV_CONVERSION_AUTOMATIC; -} - static bool sc_display_update_texture_internal(struct sc_display *display, const AVFrame *frame) { - if (!display->has_frame) { - // First frame - display->has_frame = true; - - // Configure YUV color range conversion - SDL_YUV_CONVERSION_MODE sdl_color_range = - sc_display_to_sdl_color_range(frame->color_range); - SDL_SetYUVConversionMode(sdl_color_range); - } - int ret = SDL_UpdateYUVTexture(display->texture, NULL, frame->data[0], frame->linesize[0], frame->data[1], frame->linesize[1], diff --git a/app/src/display.h b/app/src/display.h index 4de9b0a9..0abfe862 100644 --- a/app/src/display.h +++ b/app/src/display.h @@ -28,14 +28,15 @@ struct sc_display { bool mipmaps; struct { -#define SC_DISPLAY_PENDING_FLAG_SIZE 1 +#define SC_DISPLAY_PENDING_FLAG_TEXTURE 1 #define SC_DISPLAY_PENDING_FLAG_FRAME 2 int8_t flags; - struct sc_size size; + struct { + struct sc_size size; + enum AVColorRange color_range; + } texture; AVFrame *frame; } pending; - - bool has_frame; }; enum sc_display_result { @@ -52,7 +53,8 @@ void sc_display_destroy(struct sc_display *display); enum sc_display_result -sc_display_set_texture_size(struct sc_display *display, struct sc_size size); +sc_display_prepare_texture(struct sc_display *display, struct sc_size size, + enum AVColorRange color_range); enum sc_display_result sc_display_update_texture(struct sc_display *display, const AVFrame *frame); diff --git a/app/src/screen.c b/app/src/screen.c index a2c22b25..0d74cac7 100644 --- a/app/src/screen.c +++ b/app/src/screen.c @@ -619,7 +619,8 @@ sc_screen_apply_frame(struct sc_screen *screen) { } enum sc_display_result res = - sc_display_set_texture_size(&screen->display, screen->frame_size); + sc_display_prepare_texture(&screen->display, screen->frame_size, + frame->color_range); if (res == SC_DISPLAY_RESULT_ERROR) { return false; } From d7e0d36fe6a95e49ba3dceba1f550d746fbfc30b Mon Sep 17 00:00:00 2001 From: Romain Vimont Date: Thu, 10 Jul 2025 23:07:45 +0200 Subject: [PATCH 5/8] Improve color space conversion Use both the color space and color range from FFmpeg to determine the appropriate SDL YUV conversion mode. --- app/src/display.c | 35 ++++++++++++++++++++++++++--------- app/src/display.h | 2 ++ app/src/screen.c | 2 +- 3 files changed, 29 insertions(+), 10 deletions(-) diff --git a/app/src/display.c b/app/src/display.c index b701f8bf..a1369ae8 100644 --- a/app/src/display.c +++ b/app/src/display.c @@ -125,14 +125,26 @@ sc_display_destroy(struct sc_display *display) { } static SDL_YUV_CONVERSION_MODE -sc_display_to_sdl_color_range(enum AVColorRange color_range) { - return color_range == AVCOL_RANGE_JPEG ? SDL_YUV_CONVERSION_JPEG - : SDL_YUV_CONVERSION_AUTOMATIC; +sc_display_to_sdl_color_mode(enum AVColorSpace color_space, + enum AVColorRange color_range) { + switch (color_space) { + case AVCOL_SPC_BT709: + return SDL_YUV_CONVERSION_BT709; + case AVCOL_SPC_BT470BG: + case AVCOL_SPC_SMPTE170M: + return SDL_YUV_CONVERSION_BT601; + default: + if (color_range == AVCOL_RANGE_JPEG) { + return SDL_YUV_CONVERSION_JPEG; + } + return SDL_YUV_CONVERSION_AUTOMATIC; + } } static SDL_Texture * sc_display_create_texture(struct sc_display *display, - struct sc_size size, enum AVColorRange color_range) { + struct sc_size size, enum AVColorSpace color_space, + enum AVColorRange color_range) { SDL_Renderer *renderer = display->renderer; SDL_Texture *texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_YV12, SDL_TEXTUREACCESS_STREAMING, @@ -156,9 +168,9 @@ sc_display_create_texture(struct sc_display *display, } // Configure YUV color range conversion - SDL_YUV_CONVERSION_MODE sdl_color_range = - sc_display_to_sdl_color_range(color_range); - SDL_SetYUVConversionMode(sdl_color_range); + SDL_YUV_CONVERSION_MODE sdl_color_mode = + sc_display_to_sdl_color_mode(color_space, color_range); + SDL_SetYUVConversionMode(sdl_color_mode); return texture; } @@ -201,6 +213,7 @@ sc_display_apply_pending(struct sc_display *display) { display->texture = sc_display_create_texture(display, display->pending.texture.size, + display->pending.texture.color_space, display->pending.texture.color_range); if (!display->texture) { return false; @@ -226,6 +239,7 @@ sc_display_apply_pending(struct sc_display *display) { static bool sc_display_prepare_texture_internal(struct sc_display *display, struct sc_size size, + enum AVColorSpace color_space, enum AVColorRange color_range) { assert(size.width && size.height); @@ -233,7 +247,8 @@ sc_display_prepare_texture_internal(struct sc_display *display, SDL_DestroyTexture(display->texture); } - display->texture = sc_display_create_texture(display, size, color_range); + display->texture = + sc_display_create_texture(display, size, color_space, color_range); if (!display->texture) { return false; } @@ -244,8 +259,10 @@ sc_display_prepare_texture_internal(struct sc_display *display, enum sc_display_result sc_display_prepare_texture(struct sc_display *display, struct sc_size size, + enum AVColorSpace color_space, enum AVColorRange color_range) { - bool ok = sc_display_prepare_texture_internal(display, size, color_range); + bool ok = sc_display_prepare_texture_internal(display, size, color_space, + color_range); if (!ok) { sc_display_set_pending_texture(display, size, color_range); return SC_DISPLAY_RESULT_PENDING; diff --git a/app/src/display.h b/app/src/display.h index 0abfe862..cc9107f5 100644 --- a/app/src/display.h +++ b/app/src/display.h @@ -33,6 +33,7 @@ struct sc_display { int8_t flags; struct { struct sc_size size; + enum AVColorSpace color_space; enum AVColorRange color_range; } texture; AVFrame *frame; @@ -54,6 +55,7 @@ sc_display_destroy(struct sc_display *display); enum sc_display_result sc_display_prepare_texture(struct sc_display *display, struct sc_size size, + enum AVColorSpace color_space, enum AVColorRange color_range); enum sc_display_result diff --git a/app/src/screen.c b/app/src/screen.c index 0d74cac7..fc4a22ff 100644 --- a/app/src/screen.c +++ b/app/src/screen.c @@ -620,7 +620,7 @@ sc_screen_apply_frame(struct sc_screen *screen) { enum sc_display_result res = sc_display_prepare_texture(&screen->display, screen->frame_size, - frame->color_range); + frame->colorspace, frame->color_range); if (res == SC_DISPLAY_RESULT_ERROR) { return false; } From 77cd5d9aef6774e3509789a1069aec1db5c6b5d4 Mon Sep 17 00:00:00 2001 From: Romain Vimont Date: Fri, 11 Jul 2025 09:42:03 +0200 Subject: [PATCH 6/8] Migrate from SDL2 to SDL3 Refs --- app/meson.build | 3 +- app/src/audio_player.c | 87 ++++++++++++++----- app/src/audio_player.h | 8 +- app/src/compat.h | 24 +----- app/src/display.c | 140 +++++++++++++++++++++---------- app/src/display.h | 3 +- app/src/events.c | 28 ++----- app/src/events.h | 4 +- app/src/icon.c | 66 ++++++++------- app/src/icon.h | 2 +- app/src/input_events.h | 158 +++++++++++++++++------------------ app/src/input_manager.c | 134 ++++++++++++++--------------- app/src/input_manager.h | 4 +- app/src/main.c | 5 +- app/src/mouse_capture.c | 39 ++++----- app/src/mouse_capture.h | 2 +- app/src/opengl.c | 18 ++-- app/src/opengl.h | 5 +- app/src/receiver.c | 3 +- app/src/scrcpy.c | 48 +++++------ app/src/screen.c | 107 +++++++++++++----------- app/src/screen.h | 2 +- app/src/shortcut_mod.h | 28 +++---- app/src/uhid/gamepad_uhid.c | 8 +- app/src/uhid/keyboard_uhid.c | 4 +- app/src/usb/scrcpy_otg.c | 12 +-- app/src/usb/screen_otg.c | 85 +++++++++---------- app/src/usb/screen_otg.h | 2 +- app/src/util/log.c | 12 +-- app/src/util/log.h | 2 +- app/src/util/thread.c | 80 ++++-------------- app/src/util/thread.h | 8 +- app/src/util/window.c | 33 ++++++++ app/src/util/window.h | 13 +++ app/src/version.c | 13 +-- 35 files changed, 632 insertions(+), 558 deletions(-) create mode 100644 app/src/util/window.c create mode 100644 app/src/util/window.h diff --git a/app/meson.build b/app/meson.build index f7df69eb..d7eb5384 100644 --- a/app/meson.build +++ b/app/meson.build @@ -63,6 +63,7 @@ src = [ 'src/util/thread.c', 'src/util/tick.c', 'src/util/timeout.c', + 'src/util/window.c', ] conf = configuration_data() @@ -117,7 +118,7 @@ dependencies = [ dependency('libavcodec', version: '>= 57.37', static: static), dependency('libavutil', static: static), dependency('libswresample', static: static), - dependency('sdl2', version: '>= 2.0.5', static: static), + dependency('sdl3', version: '>= 3.2.0', static: static), ] if v4l2_support diff --git a/app/src/audio_player.c b/app/src/audio_player.c index 9413c2ea..e1a4134e 100644 --- a/app/src/audio_player.c +++ b/app/src/audio_player.c @@ -1,23 +1,40 @@ #include "audio_player.h" #include "util/log.h" +#include "SDL3/SDL_hints.h" /** Downcast frame_sink to sc_audio_player */ #define DOWNCAST(SINK) container_of(SINK, struct sc_audio_player, frame_sink) -#define SC_SDL_SAMPLE_FMT AUDIO_F32 +#define SC_SDL_SAMPLE_FMT SDL_AUDIO_F32LE static void SDLCALL -sc_audio_player_sdl_callback(void *userdata, uint8_t *stream, int len_int) { +sc_audio_player_stream_callback(void *userdata, SDL_AudioStream *stream, + int additional_amount, int total_amount) { + (void) total_amount; + struct sc_audio_player *ap = userdata; - assert(len_int > 0); - size_t len = len_int; + if (additional_amount > 0) { + size_t len = additional_amount; - assert(len % ap->audioreg.sample_size == 0); - uint32_t out_samples = len / ap->audioreg.sample_size; + assert(len <= ap->aout_buffer_size); + if (len > ap->aout_buffer_size) { + // Just in case for release builds + LOGE("Unexpected SDL audio behavior: too much data requested"); + len = ap->aout_buffer_size; + } - sc_audio_regulator_pull(&ap->audioreg, stream, out_samples); + assert(len % ap->audioreg.sample_size == 0); + uint32_t out_samples = len / ap->audioreg.sample_size; + + sc_audio_regulator_pull(&ap->audioreg, ap->aout_buffer, out_samples); + bool ok = SDL_PutAudioStreamData(stream, ap->aout_buffer, len); + SDL_stack_free(data); + if (!ok) { + LOGW("Audio stream error: %s", SDL_GetError()); + } + } } static bool @@ -61,23 +78,42 @@ sc_audio_player_frame_sink_open(struct sc_frame_sink *sink, / SC_TICK_FREQ; assert(aout_samples <= 0xFFFF); - SDL_AudioSpec desired = { - .freq = ctx->sample_rate, - .format = SC_SDL_SAMPLE_FMT, - .channels = nb_channels, - .samples = aout_samples, - .callback = sc_audio_player_sdl_callback, - .userdata = ap, - }; - SDL_AudioSpec obtained; - - ap->device = SDL_OpenAudioDevice(NULL, 0, &desired, &obtained, 0); - if (!ap->device) { - LOGE("Could not open audio device: %s", SDL_GetError()); + char str[5 + 1]; // max 65535 + int r = snprintf(str, sizeof(str), "%" PRIu16, (uint16_t) aout_samples); + assert(r >= 0 && (size_t) r < sizeof(str)); + (void) r; + if (!SDL_SetHint(SDL_HINT_AUDIO_DEVICE_SAMPLE_FRAMES, str)) { + LOGE("Could not set audio output buffer"); sc_audio_regulator_destroy(&ap->audioreg); return false; } + ap->aout_buffer_size = aout_samples * sample_size; + ap->aout_buffer = malloc(ap->aout_buffer_size); + if (!ap->aout_buffer) { + sc_audio_regulator_destroy(&ap->audioreg); + return false; + } + + SDL_AudioSpec spec = { + .freq = ctx->sample_rate, + .format = SC_SDL_SAMPLE_FMT, + .channels = nb_channels, + }; + + ap->stream = SDL_OpenAudioDeviceStream(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, + &spec, + sc_audio_player_stream_callback, ap); + if (!ap->stream) { + LOGE("Could not open audio device: %s", SDL_GetError()); + free(ap->aout_buffer); + sc_audio_regulator_destroy(&ap->audioreg); + return false; + } + + ap->device = SDL_GetAudioStreamDevice(ap->stream); + assert(ap->device); + // The thread calling open() is the thread calling push(), which fills the // audio buffer consumed by the SDL audio thread. ok = sc_thread_set_priority(SC_THREAD_PRIORITY_TIME_CRITICAL); @@ -86,7 +122,7 @@ sc_audio_player_frame_sink_open(struct sc_frame_sink *sink, (void) ok; // We don't care if it worked, at least we tried } - SDL_PauseAudioDevice(ap->device, 0); + SDL_ResumeAudioDevice(ap->device); return true; } @@ -95,11 +131,16 @@ static void sc_audio_player_frame_sink_close(struct sc_frame_sink *sink) { struct sc_audio_player *ap = DOWNCAST(sink); + assert(ap->stream); assert(ap->device); - SDL_PauseAudioDevice(ap->device, 1); - SDL_CloseAudioDevice(ap->device); + SDL_PauseAudioDevice(ap->device); + + // ap->device is owned by ap->stream + SDL_DestroyAudioStream(ap->stream); sc_audio_regulator_destroy(&ap->audioreg); + + free(ap->aout_buffer); } void diff --git a/app/src/audio_player.h b/app/src/audio_player.h index 5a66d43b..786200bb 100644 --- a/app/src/audio_player.h +++ b/app/src/audio_player.h @@ -3,7 +3,7 @@ #include "common.h" -#include +#include #include "audio_regulator.h" #include "trait/frame_sink.h" @@ -22,7 +22,11 @@ struct sc_audio_player { // SDL audio output buffer size sc_tick output_buffer_duration; - SDL_AudioDeviceID device; + uint8_t *aout_buffer; + size_t aout_buffer_size; + + SDL_AudioStream *stream; + SDL_AudioDeviceID device; // owned by the audio stream struct sc_audio_regulator audioreg; }; diff --git a/app/src/compat.h b/app/src/compat.h index 296d1a9f..a7ba289b 100644 --- a/app/src/compat.h +++ b/app/src/compat.h @@ -6,7 +6,7 @@ #include #include #include -#include +#include #ifndef _WIN32 # define PRIu64_ PRIu64 @@ -61,28 +61,6 @@ # define SCRCPY_LAVC_HAS_CODECPAR_CODEC_SIDEDATA #endif -#if SDL_VERSION_ATLEAST(2, 0, 6) -// -# define SCRCPY_SDL_HAS_HINT_TOUCH_MOUSE_EVENTS -#endif - -#if SDL_VERSION_ATLEAST(2, 0, 8) -// -# define SCRCPY_SDL_HAS_HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR -#endif - -#if SDL_VERSION_ATLEAST(2, 0, 16) -# define SCRCPY_SDL_HAS_THREAD_PRIORITY_TIME_CRITICAL -#endif - -#if SDL_VERSION_ATLEAST(2, 0, 18) -# define SCRCPY_SDL_HAS_HINT_APP_NAME -#endif - -#if SDL_VERSION_ATLEAST(2, 0, 14) -# define SCRCPY_SDL_HAS_HINT_AUDIO_DEVICE_APP_NAME -#endif - #ifndef HAVE_STRDUP char *strdup(const char *s); #endif diff --git a/app/src/display.c b/app/src/display.c index a1369ae8..fce540f4 100644 --- a/app/src/display.c +++ b/app/src/display.c @@ -12,8 +12,11 @@ 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)) { + bool ok = SDL_SetRenderLogicalPresentation(display->renderer, + icon_novideo->w, + icon_novideo->h, + SDL_LOGICAL_PRESENTATION_LETTERBOX); + if (!ok) { LOGW("Could not set renderer logical size: %s", SDL_GetError()); // don't fail } @@ -31,16 +34,13 @@ sc_display_init_novideo_icon(struct sc_display *display, bool 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); + display->renderer = SDL_CreateRenderer(window, NULL); if (!display->renderer) { LOGE("Could not create renderer: %s", SDL_GetError()); return false; } - SDL_RendererInfo renderer_info; - int r = SDL_GetRendererInfo(display->renderer, &renderer_info); - const char *renderer_name = r ? NULL : renderer_info.name; + const char *renderer_name = SDL_GetRendererName(display->renderer); LOGI("Renderer: %s", renderer_name ? renderer_name : "(unknown)"); display->mipmaps = false; @@ -100,7 +100,7 @@ sc_display_init(struct sc_display *display, SDL_Window *window, 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); + SDL_GL_DestroyContext(display->gl_context); #endif SDL_DestroyRenderer(display->renderer); return false; @@ -116,7 +116,7 @@ sc_display_destroy(struct sc_display *display) { av_frame_free(&display->pending.frame); } #ifdef SC_DISPLAY_FORCE_OPENGL_CORE_PROFILE - SDL_GL_DeleteContext(display->gl_context); + SDL_GL_DestroyContext(display->gl_context); #endif if (display->texture) { SDL_DestroyTexture(display->texture); @@ -124,20 +124,25 @@ sc_display_destroy(struct sc_display *display) { SDL_DestroyRenderer(display->renderer); } -static SDL_YUV_CONVERSION_MODE -sc_display_to_sdl_color_mode(enum AVColorSpace color_space, - enum AVColorRange color_range) { +static enum SDL_Colorspace +sc_display_to_sdl_color_space(enum AVColorSpace color_space, + enum AVColorRange color_range) { + bool full_range = color_range == AVCOL_RANGE_JPEG; + switch (color_space) { case AVCOL_SPC_BT709: - return SDL_YUV_CONVERSION_BT709; + return full_range ? SDL_COLORSPACE_BT709_FULL + : SDL_COLORSPACE_BT709_LIMITED; case AVCOL_SPC_BT470BG: case AVCOL_SPC_SMPTE170M: - return SDL_YUV_CONVERSION_BT601; + return full_range ? SDL_COLORSPACE_BT601_FULL + : SDL_COLORSPACE_BT601_LIMITED; + case AVCOL_SPC_BT2020_NCL: + case AVCOL_SPC_BT2020_CL: + return full_range ? SDL_COLORSPACE_BT2020_FULL + : SDL_COLORSPACE_BT2020_LIMITED; default: - if (color_range == AVCOL_RANGE_JPEG) { - return SDL_YUV_CONVERSION_JPEG; - } - return SDL_YUV_CONVERSION_AUTOMATIC; + return SDL_COLORSPACE_JPEG; } } @@ -145,10 +150,36 @@ static SDL_Texture * sc_display_create_texture(struct sc_display *display, struct sc_size size, enum AVColorSpace color_space, enum AVColorRange color_range) { + SDL_PropertiesID props = SDL_CreateProperties(); + if (!props) { + return NULL; + } + + enum SDL_Colorspace sdl_color_space = + sc_display_to_sdl_color_space(color_space, color_range); + + bool ok = + SDL_SetNumberProperty(props, SDL_PROP_TEXTURE_CREATE_FORMAT_NUMBER, + SDL_PIXELFORMAT_YV12); + ok &= SDL_SetNumberProperty(props, SDL_PROP_TEXTURE_CREATE_ACCESS_NUMBER, + SDL_TEXTUREACCESS_STREAMING); + ok &= SDL_SetNumberProperty(props, SDL_PROP_TEXTURE_CREATE_WIDTH_NUMBER, + size.width); + ok &= SDL_SetNumberProperty(props, SDL_PROP_TEXTURE_CREATE_HEIGHT_NUMBER, + size.height); + ok &= SDL_SetNumberProperty(props, + SDL_PROP_TEXTURE_CREATE_COLORSPACE_NUMBER, + sdl_color_space); + + if (!ok) { + LOGE("Could not set texture properties"); + SDL_DestroyProperties(props); + return NULL; + } + SDL_Renderer *renderer = display->renderer; - SDL_Texture *texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_YV12, - SDL_TEXTUREACCESS_STREAMING, - size.width, size.height); + SDL_Texture *texture = SDL_CreateTextureWithProperties(renderer, props); + SDL_DestroyProperties(props); if (!texture) { LOGD("Could not create texture: %s", SDL_GetError()); return NULL; @@ -157,21 +188,35 @@ sc_display_create_texture(struct sc_display *display, if (display->mipmaps) { struct sc_opengl *gl = &display->gl; - SDL_GL_BindTexture(texture, NULL, NULL); + SDL_PropertiesID props = SDL_GetTextureProperties(texture); + if (!props) { + LOGE("Could not get texture properties: %s", SDL_GetError()); + SDL_DestroyTexture(texture); + return NULL; + } + + int64_t texture_id = + SDL_GetNumberProperty(props, + SDL_PROP_TEXTURE_OPENGL_TEXTURE_NUMBER, 0); + SDL_DestroyProperties(props); + if (!texture_id) { + LOGE("Could not get texture id: %s", SDL_GetError()); + SDL_DestroyTexture(texture); + return NULL; + } + + assert(!(texture_id & ~0xFFFFFFFF)); // fits in uint32_t + display->texture_id = texture_id; + gl->BindTexture(GL_TEXTURE_2D, display->texture_id); // Enable trilinear filtering for downscaling gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); gl->TexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, -1.f); - SDL_GL_UnbindTexture(texture); + gl->BindTexture(GL_TEXTURE_2D, 0); } - // Configure YUV color range conversion - SDL_YUV_CONVERSION_MODE sdl_color_mode = - sc_display_to_sdl_color_mode(color_space, color_range); - SDL_SetYUVConversionMode(sdl_color_mode); - return texture; } @@ -275,19 +320,22 @@ sc_display_prepare_texture(struct sc_display *display, struct sc_size size, static bool sc_display_update_texture_internal(struct sc_display *display, const AVFrame *frame) { - int ret = SDL_UpdateYUVTexture(display->texture, NULL, + bool ok = SDL_UpdateYUVTexture(display->texture, NULL, frame->data[0], frame->linesize[0], frame->data[1], frame->linesize[1], frame->data[2], frame->linesize[2]); - if (ret) { + if (!ok) { LOGD("Could not update texture: %s", SDL_GetError()); return false; } if (display->mipmaps) { - SDL_GL_BindTexture(display->texture, NULL, NULL); + assert(display->texture_id); + struct sc_opengl *gl = &display->gl; + + gl->BindTexture(GL_TEXTURE_2D, display->texture_id); display->gl.GenerateMipmap(GL_TEXTURE_2D); - SDL_GL_UnbindTexture(display->texture); + gl->BindTexture(GL_TEXTURE_2D, 0); } return true; @@ -325,8 +373,10 @@ sc_display_render(struct sc_display *display, const SDL_Rect *geometry, SDL_Texture *texture = display->texture; if (orientation == SC_ORIENTATION_0) { - int ret = SDL_RenderCopy(renderer, texture, NULL, geometry); - if (ret) { + SDL_FRect frect; + SDL_RectToFRect(geometry, &frect); + bool ok = SDL_RenderTexture(renderer, texture, NULL, &frect); + if (!ok) { LOGE("Could not render texture: %s", SDL_GetError()); return SC_DISPLAY_RESULT_ERROR; } @@ -334,24 +384,22 @@ sc_display_render(struct sc_display *display, const SDL_Rect *geometry, unsigned cw_rotation = sc_orientation_get_rotation(orientation); double angle = 90 * cw_rotation; - const SDL_Rect *dstrect = NULL; - SDL_Rect rect; + SDL_FRect frect; if (sc_orientation_is_swap(orientation)) { - rect.x = geometry->x + (geometry->w - geometry->h) / 2; - rect.y = geometry->y + (geometry->h - geometry->w) / 2; - rect.w = geometry->h; - rect.h = geometry->w; - dstrect = ▭ + frect.x = geometry->x + (geometry->w - geometry->h) / 2.f; + frect.y = geometry->y + (geometry->h - geometry->w) / 2.f; + frect.w = geometry->h; + frect.h = geometry->w; } else { - dstrect = geometry; + SDL_RectToFRect(geometry, &frect); } - SDL_RendererFlip flip = sc_orientation_is_mirror(orientation) + SDL_FlipMode flip = sc_orientation_is_mirror(orientation) ? SDL_FLIP_HORIZONTAL : 0; - int ret = SDL_RenderCopyEx(renderer, texture, NULL, dstrect, angle, - NULL, flip); - if (ret) { + bool ok = SDL_RenderTextureRotated(renderer, texture, NULL, &frect, + angle, NULL, flip); + if (!ok) { LOGE("Could not render texture: %s", SDL_GetError()); return SC_DISPLAY_RESULT_ERROR; } diff --git a/app/src/display.h b/app/src/display.h index cc9107f5..8d2a1bd3 100644 --- a/app/src/display.h +++ b/app/src/display.h @@ -6,7 +6,7 @@ #include #include #include -#include +#include #include "coords.h" #include "opengl.h" @@ -26,6 +26,7 @@ struct sc_display { #endif bool mipmaps; + uint32_t texture_id; // only set if mipmaps is enabled struct { #define SC_DISPLAY_PENDING_FLAG_TEXTURE 1 diff --git a/app/src/events.c b/app/src/events.c index b4322d1b..ca7e4008 100644 --- a/app/src/events.c +++ b/app/src/events.c @@ -9,11 +9,8 @@ bool sc_push_event_impl(uint32_t type, const char *name) { SDL_Event event; event.type = type; - int ret = SDL_PushEvent(&event); - // ret < 0: error (queue full) - // ret == 0: event was filtered - // ret == 1: success - if (ret != 1) { + bool ok = SDL_PushEvent(&event); + if (!ok) { LOGE("Could not post %s event: %s", name, SDL_GetError()); return false; } @@ -30,34 +27,25 @@ sc_post_to_main_thread(sc_runnable_fn run, void *userdata) { .data2 = userdata, }, }; - int ret = SDL_PushEvent(&event); - // ret < 0: error (queue full) - // ret == 0: event was filtered - // ret == 1: success - if (ret != 1) { - if (ret == 0) { - // if ret == 0, this is expected on exit, log in debug mode - LOGD("Could not post runnable to main thread (filtered)"); - } else { - assert(ret < 0); - LOGW("Could not post runnable to main thread: %s", SDL_GetError()); - } + bool ok = SDL_PushEvent(&event); + if (!ok) { + LOGW("Could not post runnable to main thread: %s", SDL_GetError()); return false; } return true; } -static int SDLCALL +static bool SDLCALL task_event_filter(void *userdata, SDL_Event *event) { (void) userdata; if (event->type == SC_EVENT_RUN_ON_MAIN_THREAD) { // Reject this event type from now on - return 0; + return false; } - return 1; + return true; } void diff --git a/app/src/events.h b/app/src/events.h index 2e7318e5..8667bc57 100644 --- a/app/src/events.h +++ b/app/src/events.h @@ -5,10 +5,10 @@ #include #include -#include +#include enum { - SC_EVENT_NEW_FRAME = SDL_USEREVENT, + SC_EVENT_NEW_FRAME = SDL_EVENT_USER, SC_EVENT_RUN_ON_MAIN_THREAD, SC_EVENT_DEVICE_DISCONNECTED, SC_EVENT_SERVER_CONNECTION_FAILED, diff --git a/app/src/icon.c b/app/src/icon.c index 797afc75..ac80ecb3 100644 --- a/app/src/icon.c +++ b/app/src/icon.c @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include "config.h" #include "util/env.h" @@ -156,13 +156,7 @@ free_ctx: return result; } -#if !SDL_VERSION_ATLEAST(2, 0, 10) -// SDL_PixelFormatEnum has been introduced in SDL 2.0.10. Use int for older SDL -// versions. -typedef int SDL_PixelFormatEnum; -#endif - -static SDL_PixelFormatEnum +static SDL_PixelFormat to_sdl_pixel_format(enum AVPixelFormat fmt) { switch (fmt) { case AV_PIX_FMT_RGB24: return SDL_PIXELFORMAT_RGB24; @@ -172,13 +166,11 @@ to_sdl_pixel_format(enum AVPixelFormat fmt) { case AV_PIX_FMT_ABGR: return SDL_PIXELFORMAT_ABGR32; case AV_PIX_FMT_BGRA: return SDL_PIXELFORMAT_BGRA32; case AV_PIX_FMT_RGB565BE: return SDL_PIXELFORMAT_RGB565; - case AV_PIX_FMT_RGB555BE: return SDL_PIXELFORMAT_RGB555; + case AV_PIX_FMT_RGB555BE: return SDL_PIXELFORMAT_XRGB1555; case AV_PIX_FMT_BGR565BE: return SDL_PIXELFORMAT_BGR565; - case AV_PIX_FMT_BGR555BE: return SDL_PIXELFORMAT_BGR555; - case AV_PIX_FMT_RGB444BE: return SDL_PIXELFORMAT_RGB444; -#if SDL_VERSION_ATLEAST(2, 0, 12) - case AV_PIX_FMT_BGR444BE: return SDL_PIXELFORMAT_BGR444; -#endif + case AV_PIX_FMT_BGR555BE: return SDL_PIXELFORMAT_XBGR1555; + case AV_PIX_FMT_RGB444BE: return SDL_PIXELFORMAT_XRGB4444; + case AV_PIX_FMT_BGR444BE: return SDL_PIXELFORMAT_XBGR4444; case AV_PIX_FMT_PAL8: return SDL_PIXELFORMAT_INDEX8; default: return SDL_PIXELFORMAT_UNKNOWN; } @@ -203,20 +195,16 @@ load_from_path(const char *path) { goto error; } - SDL_PixelFormatEnum format = to_sdl_pixel_format(frame->format); + SDL_PixelFormat format = to_sdl_pixel_format(frame->format); if (format == SDL_PIXELFORMAT_UNKNOWN) { LOGE("Unsupported icon pixel format: %s (%d)", desc->name, frame->format); goto error; } - int bits_per_pixel = av_get_bits_per_pixel(desc); SDL_Surface *surface = - SDL_CreateRGBSurfaceWithFormatFrom(frame->data[0], - frame->width, frame->height, - bits_per_pixel, - frame->linesize[0], - format); + SDL_CreateSurfaceFrom(frame->width, frame->height, format, + frame->data[0], frame->linesize[0]); if (!surface) { LOGE("Could not create icon surface"); @@ -248,17 +236,35 @@ load_from_path(const char *path) { #endif } - SDL_Palette *palette = surface->format->palette; - assert(palette); - int ret = SDL_SetPaletteColors(palette, colors, 0, 256); - if (ret) { + SDL_Palette *palette = SDL_CreateSurfacePalette(surface); + if (!palette) { + LOGE("Could not create palette"); + SDL_DestroySurface(surface); + goto error; + } + + bool ok = SDL_SetPaletteColors(palette, colors, 0, 256); + if (!ok) { LOGE("Could not set palette colors"); - SDL_FreeSurface(surface); + SDL_DestroySurface(surface); goto error; } } - surface->userdata = frame; // frame owns the data + SDL_PropertiesID props = SDL_GetSurfaceProperties(surface); + if (!props) { + LOGE("Could not get surface properties: %s", SDL_GetError()); + SDL_DestroySurface(surface); + goto error; + } + + // frame owns the data + bool ok = SDL_SetPointerProperty(props, "sc_frame", frame); + if (!ok) { + LOGE("Could not get surface properties: %s", SDL_GetError()); + SDL_DestroySurface(surface); + goto error; + } return surface; @@ -281,8 +287,10 @@ scrcpy_icon_load(void) { void scrcpy_icon_destroy(SDL_Surface *icon) { - AVFrame *frame = icon->userdata; + SDL_PropertiesID props = SDL_GetSurfaceProperties(icon); + assert(props); + AVFrame *frame = SDL_GetPointerProperty(props, "sc_frame", NULL); assert(frame); av_frame_free(&frame); - SDL_FreeSurface(icon); + SDL_DestroySurface(icon); } diff --git a/app/src/icon.h b/app/src/icon.h index 6bcf46d2..21fbc548 100644 --- a/app/src/icon.h +++ b/app/src/icon.h @@ -3,7 +3,7 @@ #include "common.h" -#include +#include SDL_Surface * scrcpy_icon_load(void); diff --git a/app/src/input_events.h b/app/src/input_events.h index 0c022acc..87ea6634 100644 --- a/app/src/input_events.h +++ b/app/src/input_events.h @@ -6,7 +6,7 @@ #include #include #include -#include +#include #include "coords.h" @@ -43,17 +43,17 @@ */ enum sc_mod { - SC_MOD_LSHIFT = KMOD_LSHIFT, - SC_MOD_RSHIFT = KMOD_RSHIFT, - SC_MOD_LCTRL = KMOD_LCTRL, - SC_MOD_RCTRL = KMOD_RCTRL, - SC_MOD_LALT = KMOD_LALT, - SC_MOD_RALT = KMOD_RALT, - SC_MOD_LGUI = KMOD_LGUI, - SC_MOD_RGUI = KMOD_RGUI, + SC_MOD_LSHIFT = SDL_KMOD_LSHIFT, + SC_MOD_RSHIFT = SDL_KMOD_RSHIFT, + SC_MOD_LCTRL = SDL_KMOD_LCTRL, + SC_MOD_RCTRL = SDL_KMOD_RCTRL, + SC_MOD_LALT = SDL_KMOD_LALT, + SC_MOD_RALT = SDL_KMOD_RALT, + SC_MOD_LGUI = SDL_KMOD_LGUI, + SC_MOD_RGUI = SDL_KMOD_RGUI, - SC_MOD_NUM = KMOD_NUM, - SC_MOD_CAPS = KMOD_CAPS, + SC_MOD_NUM = SDL_KMOD_NUM, + SC_MOD_CAPS = SDL_KMOD_CAPS, }; enum sc_action { @@ -70,12 +70,12 @@ enum sc_keycode { SC_KEYCODE_TAB = SDLK_TAB, SC_KEYCODE_SPACE = SDLK_SPACE, SC_KEYCODE_EXCLAIM = SDLK_EXCLAIM, - SC_KEYCODE_QUOTEDBL = SDLK_QUOTEDBL, + SC_KEYCODE_QUOTEDBL = SDLK_DBLAPOSTROPHE, SC_KEYCODE_HASH = SDLK_HASH, SC_KEYCODE_PERCENT = SDLK_PERCENT, SC_KEYCODE_DOLLAR = SDLK_DOLLAR, SC_KEYCODE_AMPERSAND = SDLK_AMPERSAND, - SC_KEYCODE_QUOTE = SDLK_QUOTE, + SC_KEYCODE_QUOTE = SDLK_APOSTROPHE, SC_KEYCODE_LEFTPAREN = SDLK_LEFTPAREN, SC_KEYCODE_RIGHTPAREN = SDLK_RIGHTPAREN, SC_KEYCODE_ASTERISK = SDLK_ASTERISK, @@ -107,33 +107,33 @@ enum sc_keycode { SC_KEYCODE_RIGHTBRACKET = SDLK_RIGHTBRACKET, SC_KEYCODE_CARET = SDLK_CARET, SC_KEYCODE_UNDERSCORE = SDLK_UNDERSCORE, - SC_KEYCODE_BACKQUOTE = SDLK_BACKQUOTE, - SC_KEYCODE_a = SDLK_a, - SC_KEYCODE_b = SDLK_b, - SC_KEYCODE_c = SDLK_c, - SC_KEYCODE_d = SDLK_d, - SC_KEYCODE_e = SDLK_e, - SC_KEYCODE_f = SDLK_f, - SC_KEYCODE_g = SDLK_g, - SC_KEYCODE_h = SDLK_h, - SC_KEYCODE_i = SDLK_i, - SC_KEYCODE_j = SDLK_j, - SC_KEYCODE_k = SDLK_k, - SC_KEYCODE_l = SDLK_l, - SC_KEYCODE_m = SDLK_m, - SC_KEYCODE_n = SDLK_n, - SC_KEYCODE_o = SDLK_o, - SC_KEYCODE_p = SDLK_p, - SC_KEYCODE_q = SDLK_q, - SC_KEYCODE_r = SDLK_r, - SC_KEYCODE_s = SDLK_s, - SC_KEYCODE_t = SDLK_t, - SC_KEYCODE_u = SDLK_u, - SC_KEYCODE_v = SDLK_v, - SC_KEYCODE_w = SDLK_w, - SC_KEYCODE_x = SDLK_x, - SC_KEYCODE_y = SDLK_y, - SC_KEYCODE_z = SDLK_z, + SC_KEYCODE_BACKQUOTE = SDLK_GRAVE, + SC_KEYCODE_a = SDLK_A, + SC_KEYCODE_b = SDLK_B, + SC_KEYCODE_c = SDLK_C, + SC_KEYCODE_d = SDLK_D, + SC_KEYCODE_e = SDLK_E, + SC_KEYCODE_f = SDLK_F, + SC_KEYCODE_g = SDLK_G, + SC_KEYCODE_h = SDLK_H, + SC_KEYCODE_i = SDLK_I, + SC_KEYCODE_j = SDLK_J, + SC_KEYCODE_k = SDLK_K, + SC_KEYCODE_l = SDLK_L, + SC_KEYCODE_m = SDLK_M, + SC_KEYCODE_n = SDLK_N, + SC_KEYCODE_o = SDLK_O, + SC_KEYCODE_p = SDLK_P, + SC_KEYCODE_q = SDLK_Q, + SC_KEYCODE_r = SDLK_R, + SC_KEYCODE_s = SDLK_S, + SC_KEYCODE_t = SDLK_T, + SC_KEYCODE_u = SDLK_U, + SC_KEYCODE_v = SDLK_V, + SC_KEYCODE_w = SDLK_W, + SC_KEYCODE_x = SDLK_X, + SC_KEYCODE_y = SDLK_Y, + SC_KEYCODE_z = SDLK_Z, SC_KEYCODE_CAPSLOCK = SDLK_CAPSLOCK, @@ -315,11 +315,11 @@ enum sc_scancode { // to avoid unnecessary conversions (and confusion). enum sc_mouse_button { SC_MOUSE_BUTTON_UNKNOWN = 0, - SC_MOUSE_BUTTON_LEFT = SDL_BUTTON(SDL_BUTTON_LEFT), - SC_MOUSE_BUTTON_RIGHT = SDL_BUTTON(SDL_BUTTON_RIGHT), - SC_MOUSE_BUTTON_MIDDLE = SDL_BUTTON(SDL_BUTTON_MIDDLE), - SC_MOUSE_BUTTON_X1 = SDL_BUTTON(SDL_BUTTON_X1), - SC_MOUSE_BUTTON_X2 = SDL_BUTTON(SDL_BUTTON_X2), + SC_MOUSE_BUTTON_LEFT = SDL_BUTTON_MASK(SDL_BUTTON_LEFT), + SC_MOUSE_BUTTON_RIGHT = SDL_BUTTON_MASK(SDL_BUTTON_RIGHT), + SC_MOUSE_BUTTON_MIDDLE = SDL_BUTTON_MASK(SDL_BUTTON_MIDDLE), + SC_MOUSE_BUTTON_X1 = SDL_BUTTON_MASK(SDL_BUTTON_X1), + SC_MOUSE_BUTTON_X2 = SDL_BUTTON_MASK(SDL_BUTTON_X2), }; // Use the naming from SDL3 for gamepad axis and buttons: @@ -327,31 +327,31 @@ enum sc_mouse_button { enum sc_gamepad_axis { SC_GAMEPAD_AXIS_UNKNOWN = -1, - SC_GAMEPAD_AXIS_LEFTX = SDL_CONTROLLER_AXIS_LEFTX, - SC_GAMEPAD_AXIS_LEFTY = SDL_CONTROLLER_AXIS_LEFTY, - SC_GAMEPAD_AXIS_RIGHTX = SDL_CONTROLLER_AXIS_RIGHTX, - SC_GAMEPAD_AXIS_RIGHTY = SDL_CONTROLLER_AXIS_RIGHTY, - SC_GAMEPAD_AXIS_LEFT_TRIGGER = SDL_CONTROLLER_AXIS_TRIGGERLEFT, - SC_GAMEPAD_AXIS_RIGHT_TRIGGER = SDL_CONTROLLER_AXIS_TRIGGERRIGHT, + SC_GAMEPAD_AXIS_LEFTX = SDL_GAMEPAD_AXIS_LEFTX, + SC_GAMEPAD_AXIS_LEFTY = SDL_GAMEPAD_AXIS_LEFTY, + SC_GAMEPAD_AXIS_RIGHTX = SDL_GAMEPAD_AXIS_RIGHTX, + SC_GAMEPAD_AXIS_RIGHTY = SDL_GAMEPAD_AXIS_RIGHTY, + SC_GAMEPAD_AXIS_LEFT_TRIGGER = SDL_GAMEPAD_AXIS_LEFT_TRIGGER, + SC_GAMEPAD_AXIS_RIGHT_TRIGGER = SDL_GAMEPAD_AXIS_RIGHT_TRIGGER, }; enum sc_gamepad_button { SC_GAMEPAD_BUTTON_UNKNOWN = -1, - SC_GAMEPAD_BUTTON_SOUTH = SDL_CONTROLLER_BUTTON_A, - SC_GAMEPAD_BUTTON_EAST = SDL_CONTROLLER_BUTTON_B, - SC_GAMEPAD_BUTTON_WEST = SDL_CONTROLLER_BUTTON_X, - SC_GAMEPAD_BUTTON_NORTH = SDL_CONTROLLER_BUTTON_Y, - SC_GAMEPAD_BUTTON_BACK = SDL_CONTROLLER_BUTTON_BACK, - SC_GAMEPAD_BUTTON_GUIDE = SDL_CONTROLLER_BUTTON_GUIDE, - SC_GAMEPAD_BUTTON_START = SDL_CONTROLLER_BUTTON_START, - SC_GAMEPAD_BUTTON_LEFT_STICK = SDL_CONTROLLER_BUTTON_LEFTSTICK, - SC_GAMEPAD_BUTTON_RIGHT_STICK = SDL_CONTROLLER_BUTTON_RIGHTSTICK, - SC_GAMEPAD_BUTTON_LEFT_SHOULDER = SDL_CONTROLLER_BUTTON_LEFTSHOULDER, - SC_GAMEPAD_BUTTON_RIGHT_SHOULDER = SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, - SC_GAMEPAD_BUTTON_DPAD_UP = SDL_CONTROLLER_BUTTON_DPAD_UP, - SC_GAMEPAD_BUTTON_DPAD_DOWN = SDL_CONTROLLER_BUTTON_DPAD_DOWN, - SC_GAMEPAD_BUTTON_DPAD_LEFT = SDL_CONTROLLER_BUTTON_DPAD_LEFT, - SC_GAMEPAD_BUTTON_DPAD_RIGHT = SDL_CONTROLLER_BUTTON_DPAD_RIGHT, + SC_GAMEPAD_BUTTON_SOUTH = SDL_GAMEPAD_BUTTON_SOUTH, + SC_GAMEPAD_BUTTON_EAST = SDL_GAMEPAD_BUTTON_EAST, + SC_GAMEPAD_BUTTON_WEST = SDL_GAMEPAD_BUTTON_WEST, + SC_GAMEPAD_BUTTON_NORTH = SDL_GAMEPAD_BUTTON_NORTH, + SC_GAMEPAD_BUTTON_BACK = SDL_GAMEPAD_BUTTON_BACK, + SC_GAMEPAD_BUTTON_GUIDE = SDL_GAMEPAD_BUTTON_GUIDE, + SC_GAMEPAD_BUTTON_START = SDL_GAMEPAD_BUTTON_START, + SC_GAMEPAD_BUTTON_LEFT_STICK = SDL_GAMEPAD_BUTTON_LEFT_STICK, + SC_GAMEPAD_BUTTON_RIGHT_STICK = SDL_GAMEPAD_BUTTON_RIGHT_STICK, + SC_GAMEPAD_BUTTON_LEFT_SHOULDER = SDL_GAMEPAD_BUTTON_LEFT_SHOULDER, + SC_GAMEPAD_BUTTON_RIGHT_SHOULDER = SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER, + SC_GAMEPAD_BUTTON_DPAD_UP = SDL_GAMEPAD_BUTTON_DPAD_UP, + SC_GAMEPAD_BUTTON_DPAD_DOWN = SDL_GAMEPAD_BUTTON_DPAD_DOWN, + SC_GAMEPAD_BUTTON_DPAD_LEFT = SDL_GAMEPAD_BUTTON_DPAD_LEFT, + SC_GAMEPAD_BUTTON_DPAD_RIGHT = SDL_GAMEPAD_BUTTON_DPAD_RIGHT, }; static_assert(sizeof(enum sc_mod) >= sizeof(SDL_Keymod), @@ -449,8 +449,8 @@ sc_scancode_from_sdl(SDL_Scancode scancode) { static inline enum sc_action sc_action_from_sdl_keyboard_type(uint32_t type) { - assert(type == SDL_KEYDOWN || type == SDL_KEYUP); - if (type == SDL_KEYDOWN) { + assert(type == SDL_EVENT_KEY_DOWN || type == SDL_EVENT_KEY_UP); + if (type == SDL_EVENT_KEY_DOWN) { return SC_ACTION_DOWN; } return SC_ACTION_UP; @@ -458,8 +458,8 @@ sc_action_from_sdl_keyboard_type(uint32_t type) { static inline enum sc_action sc_action_from_sdl_mousebutton_type(uint32_t type) { - assert(type == SDL_MOUSEBUTTONDOWN || type == SDL_MOUSEBUTTONUP); - if (type == SDL_MOUSEBUTTONDOWN) { + assert(type == SDL_EVENT_MOUSE_BUTTON_DOWN || type == SDL_EVENT_MOUSE_BUTTON_UP); + if (type == SDL_EVENT_MOUSE_BUTTON_DOWN) { return SC_ACTION_DOWN; } return SC_ACTION_UP; @@ -467,12 +467,12 @@ sc_action_from_sdl_mousebutton_type(uint32_t type) { static inline enum sc_touch_action sc_touch_action_from_sdl(uint32_t type) { - assert(type == SDL_FINGERMOTION || type == SDL_FINGERDOWN || - type == SDL_FINGERUP); - if (type == SDL_FINGERMOTION) { + assert(type == SDL_EVENT_FINGER_MOTION || type == SDL_EVENT_FINGER_DOWN || + type == SDL_EVENT_FINGER_UP); + if (type == SDL_EVENT_FINGER_MOTION) { return SC_TOUCH_ACTION_MOVE; } - if (type == SDL_FINGERDOWN) { + if (type == SDL_EVENT_FINGER_DOWN) { return SC_TOUCH_ACTION_DOWN; } return SC_TOUCH_ACTION_UP; @@ -482,7 +482,7 @@ static inline enum sc_mouse_button sc_mouse_button_from_sdl(uint8_t button) { if (button >= SDL_BUTTON_LEFT && button <= SDL_BUTTON_X2) { // SC_MOUSE_BUTTON_* constants are initialized from SDL_BUTTON(index) - return SDL_BUTTON(button); + return SDL_BUTTON_MASK(button); } return SC_MOUSE_BUTTON_UNKNOWN; @@ -498,7 +498,7 @@ sc_mouse_buttons_state_from_sdl(uint32_t buttons_state) { static inline enum sc_gamepad_axis sc_gamepad_axis_from_sdl(uint8_t axis) { - if (axis <= SDL_CONTROLLER_AXIS_TRIGGERRIGHT) { + if (axis <= SDL_GAMEPAD_AXIS_RIGHT_TRIGGER) { // SC_GAMEPAD_AXIS_* constants are initialized from // SDL_CONTROLLER_AXIS_* return axis; @@ -508,7 +508,7 @@ sc_gamepad_axis_from_sdl(uint8_t axis) { static inline enum sc_gamepad_button sc_gamepad_button_from_sdl(uint8_t button) { - if (button <= SDL_CONTROLLER_BUTTON_DPAD_RIGHT) { + if (button <= SDL_GAMEPAD_BUTTON_DPAD_RIGHT) { // SC_GAMEPAD_BUTTON_* constants are initialized from // SDL_CONTROLLER_BUTTON_* return button; @@ -518,8 +518,8 @@ sc_gamepad_button_from_sdl(uint8_t button) { static inline enum sc_action sc_action_from_sdl_controllerbutton_type(uint32_t type) { - assert(type == SDL_CONTROLLERBUTTONDOWN || type == SDL_CONTROLLERBUTTONUP); - if (type == SDL_CONTROLLERBUTTONDOWN) { + assert(type == SDL_EVENT_GAMEPAD_BUTTON_DOWN || type == SDL_EVENT_GAMEPAD_BUTTON_UP); + if (type == SDL_EVENT_GAMEPAD_BUTTON_DOWN) { return SC_ACTION_DOWN; } return SC_ACTION_UP; diff --git a/app/src/input_manager.c b/app/src/input_manager.c index f7a787d1..caba5fab 100644 --- a/app/src/input_manager.c +++ b/app/src/input_manager.c @@ -3,7 +3,7 @@ #include #include #include -#include +#include #include "android/input.h" #include "android/keycodes.h" @@ -374,11 +374,11 @@ sc_input_manager_process_key(struct sc_input_manager *im, bool paused = im->screen->paused; bool video = im->screen->video; - SDL_Keycode sdl_keycode = event->keysym.sym; - uint16_t mod = event->keysym.mod; - bool down = event->type == SDL_KEYDOWN; - bool ctrl = event->keysym.mod & KMOD_CTRL; - bool shift = event->keysym.mod & KMOD_SHIFT; + SDL_Keycode sdl_keycode = event->key; + uint16_t mod = event->mod; + bool down = event->type == SDL_EVENT_KEY_DOWN; + bool ctrl = event->mod & SDL_KMOD_CTRL; + bool shift = event->mod & SDL_KMOD_SHIFT; bool repeat = event->repeat; // Either the modifier includes a shortcut modifier, or the key @@ -402,39 +402,39 @@ sc_input_manager_process_key(struct sc_input_manager *im, if (is_shortcut) { enum sc_action action = down ? SC_ACTION_DOWN : SC_ACTION_UP; switch (sdl_keycode) { - case SDLK_h: + case SDLK_H: if (im->kp && !shift && !repeat && !paused) { action_home(im, action); } return; - case SDLK_b: // fall-through + case SDLK_B: // fall-through case SDLK_BACKSPACE: if (im->kp && !shift && !repeat && !paused) { action_back(im, action); } return; - case SDLK_s: + case SDLK_S: if (im->kp && !shift && !repeat && !paused) { action_app_switch(im, action); } return; - case SDLK_m: + case SDLK_M: if (im->kp && !shift && !repeat && !paused) { action_menu(im, action); } return; - case SDLK_p: + case SDLK_P: if (im->kp && !shift && !repeat && !paused) { action_power(im, action); } return; - case SDLK_o: + case SDLK_O: if (control && !repeat && down && !paused) { bool on = shift; set_display_power(im, on); } return; - case SDLK_z: + case SDLK_Z: if (video && down && !repeat) { sc_screen_set_paused(im->screen, !shift); } @@ -483,17 +483,17 @@ sc_input_manager_process_key(struct sc_input_manager *im, } } return; - case SDLK_c: + case SDLK_C: if (im->kp && !shift && !repeat && down && !paused) { get_device_clipboard(im, SC_COPY_KEY_COPY); } return; - case SDLK_x: + case SDLK_X: if (im->kp && !shift && !repeat && down && !paused) { get_device_clipboard(im, SC_COPY_KEY_CUT); } return; - case SDLK_v: + case SDLK_V: if (im->kp && !repeat && down && !paused) { if (shift || im->legacy_paste) { // inject the text as input events @@ -505,27 +505,27 @@ sc_input_manager_process_key(struct sc_input_manager *im, } } return; - case SDLK_f: + case SDLK_F: if (video && !shift && !repeat && down) { sc_screen_toggle_fullscreen(im->screen); } return; - case SDLK_w: + case SDLK_W: if (video && !shift && !repeat && down) { sc_screen_resize_to_fit(im->screen); } return; - case SDLK_g: + case SDLK_G: if (video && !shift && !repeat && down) { sc_screen_resize_to_pixel_perfect(im->screen); } return; - case SDLK_i: + case SDLK_I: if (video && !shift && !repeat && down) { switch_fps_counter_state(im); } return; - case SDLK_n: + case SDLK_N: if (control && !repeat && down && !paused) { if (shift) { collapse_panels(im); @@ -536,7 +536,7 @@ sc_input_manager_process_key(struct sc_input_manager *im, } } return; - case SDLK_r: + case SDLK_R: if (control && !repeat && down && !paused) { if (shift) { reset_video(im); @@ -545,7 +545,7 @@ sc_input_manager_process_key(struct sc_input_manager *im, } } return; - case SDLK_k: + case SDLK_K: if (control && !shift && !repeat && down && !paused && im->kp && im->kp->hid) { // Only if the current keyboard is hid @@ -562,7 +562,7 @@ sc_input_manager_process_key(struct sc_input_manager *im, } uint64_t ack_to_wait = SC_SEQUENCE_INVALID; - bool is_ctrl_v = ctrl && !shift && sdl_keycode == SDLK_v && down && !repeat; + bool is_ctrl_v = ctrl && !shift && sdl_keycode == SDLK_V && down && !repeat; if (im->clipboard_autosync && is_ctrl_v) { if (im->legacy_paste) { // inject the text as input events @@ -595,7 +595,7 @@ sc_input_manager_process_key(struct sc_input_manager *im, return; } - enum sc_scancode scancode = sc_scancode_from_sdl(event->keysym.scancode); + enum sc_scancode scancode = sc_scancode_from_sdl(event->scancode); if (scancode == SC_SCANCODE_UNKNOWN) { return; } @@ -605,7 +605,7 @@ sc_input_manager_process_key(struct sc_input_manager *im, .keycode = keycode, .scancode = scancode, .repeat = event->repeat, - .mods_state = sc_mods_state_from_sdl(event->keysym.mod), + .mods_state = sc_mods_state_from_sdl(event->mod), }; assert(im->kp->ops->process_key); @@ -674,7 +674,7 @@ sc_input_manager_process_touch(struct sc_input_manager *im, int dw; int dh; - SDL_GL_GetDrawableSize(im->screen->window, &dw, &dh); + SDL_GetWindowSizeInPixels(im->screen->window, &dw, &dh); // SDL touch event coordinates are normalized in the range [0; 1] int32_t x = event->x * dw; @@ -687,7 +687,7 @@ sc_input_manager_process_touch(struct sc_input_manager *im, sc_screen_convert_drawable_to_frame_coords(im->screen, x, y), }, .action = sc_touch_action_from_sdl(event->type), - .pointer_id = event->fingerId, + .pointer_id = event->fingerID, .pressure = event->pressure, }; @@ -723,7 +723,7 @@ sc_input_manager_process_mouse_button(struct sc_input_manager *im, bool control = im->controller; bool paused = im->screen->paused; - bool down = event->type == SDL_MOUSEBUTTONDOWN; + bool down = event->type == SDL_EVENT_MOUSE_BUTTON_DOWN; enum sc_mouse_button button = sc_mouse_button_from_sdl(event->button); if (button == SC_MOUSE_BUTTON_UNKNOWN) { @@ -736,8 +736,8 @@ sc_input_manager_process_mouse_button(struct sc_input_manager *im, } SDL_Keymod keymod = SDL_GetModState(); - bool ctrl_pressed = keymod & KMOD_CTRL; - bool shift_pressed = keymod & KMOD_SHIFT; + bool ctrl_pressed = keymod & SDL_KMOD_CTRL; + bool shift_pressed = keymod & SDL_KMOD_SHIFT; if (control && !paused) { enum sc_action action = down ? SC_ACTION_DOWN : SC_ACTION_UP; @@ -889,16 +889,16 @@ sc_input_manager_process_mouse_wheel(struct sc_input_manager *im, } // mouse_x and mouse_y are expressed in pixels relative to the window - int mouse_x; - int mouse_y; + float mouse_x; + float mouse_y; uint32_t buttons = SDL_GetMouseState(&mouse_x, &mouse_y); (void) buttons; // Actual buttons are tracked manually to ignore shortcuts struct sc_mouse_scroll_event evt = { .position = sc_input_manager_get_position(im, mouse_x, mouse_y), #if SDL_VERSION_ATLEAST(2, 0, 18) - .hscroll = event->preciseX, - .vscroll = event->preciseY, + .hscroll = event->x, + .vscroll = event->y, #else .hscroll = event->x, .vscroll = event->y, @@ -911,31 +911,31 @@ sc_input_manager_process_mouse_wheel(struct sc_input_manager *im, static void sc_input_manager_process_gamepad_device(struct sc_input_manager *im, - const SDL_ControllerDeviceEvent *event) { - if (event->type == SDL_CONTROLLERDEVICEADDED) { - SDL_GameController *gc = SDL_GameControllerOpen(event->which); + const SDL_GamepadDeviceEvent *event) { + if (event->type == SDL_EVENT_GAMEPAD_ADDED) { + SDL_Gamepad *gc = SDL_OpenGamepad(event->which); if (!gc) { LOGW("Could not open game controller"); return; } - SDL_Joystick *joystick = SDL_GameControllerGetJoystick(gc); + SDL_Joystick *joystick = SDL_GetGamepadJoystick(gc); if (!joystick) { LOGW("Could not get controller joystick"); - SDL_GameControllerClose(gc); + SDL_CloseGamepad(gc); return; } struct sc_gamepad_device_event evt = { - .gamepad_id = SDL_JoystickInstanceID(joystick), + .gamepad_id = SDL_GetJoystickID(joystick), }; im->gp->ops->process_gamepad_added(im->gp, &evt); - } else if (event->type == SDL_CONTROLLERDEVICEREMOVED) { + } else if (event->type == SDL_EVENT_GAMEPAD_REMOVED) { SDL_JoystickID id = event->which; - SDL_GameController *gc = SDL_GameControllerFromInstanceID(id); + SDL_Gamepad *gc = SDL_GetGamepadFromID(id); if (gc) { - SDL_GameControllerClose(gc); + SDL_CloseGamepad(gc); } else { LOGW("Unknown gamepad device removed"); } @@ -952,7 +952,7 @@ sc_input_manager_process_gamepad_device(struct sc_input_manager *im, static void sc_input_manager_process_gamepad_axis(struct sc_input_manager *im, - const SDL_ControllerAxisEvent *event) { + const SDL_GamepadAxisEvent *event) { enum sc_gamepad_axis axis = sc_gamepad_axis_from_sdl(event->axis); if (axis == SC_GAMEPAD_AXIS_UNKNOWN) { return; @@ -968,7 +968,7 @@ sc_input_manager_process_gamepad_axis(struct sc_input_manager *im, static void sc_input_manager_process_gamepad_button(struct sc_input_manager *im, - const SDL_ControllerButtonEvent *event) { + const SDL_GamepadButtonEvent *event) { enum sc_gamepad_button button = sc_gamepad_button_from_sdl(event->button); if (button == SC_GAMEPAD_BUTTON_UNKNOWN) { return; @@ -991,8 +991,8 @@ is_apk(const char *file) { static void sc_input_manager_process_file(struct sc_input_manager *im, const SDL_DropEvent *event) { - char *file = strdup(event->file); - SDL_free(event->file); + assert(event->type == SDL_EVENT_DROP_FILE); + char *file = strdup(event->data); if (!file) { LOG_OOM(); return; @@ -1016,66 +1016,66 @@ sc_input_manager_handle_event(struct sc_input_manager *im, bool control = im->controller; bool paused = im->screen->paused; switch (event->type) { - case SDL_TEXTINPUT: + case SDL_EVENT_TEXT_INPUT: if (!im->kp || paused) { break; } sc_input_manager_process_text_input(im, &event->text); break; - case SDL_KEYDOWN: - case SDL_KEYUP: + case SDL_EVENT_KEY_DOWN: + case SDL_EVENT_KEY_UP: // some key events do not interact with the device, so process the // event even if control is disabled sc_input_manager_process_key(im, &event->key); break; - case SDL_MOUSEMOTION: + case SDL_EVENT_MOUSE_MOTION: if (!im->mp || paused) { break; } sc_input_manager_process_mouse_motion(im, &event->motion); break; - case SDL_MOUSEWHEEL: + case SDL_EVENT_MOUSE_WHEEL: if (!im->mp || paused) { break; } sc_input_manager_process_mouse_wheel(im, &event->wheel); break; - case SDL_MOUSEBUTTONDOWN: - case SDL_MOUSEBUTTONUP: + case SDL_EVENT_MOUSE_BUTTON_DOWN: + case SDL_EVENT_MOUSE_BUTTON_UP: // some mouse events do not interact with the device, so process // the event even if control is disabled sc_input_manager_process_mouse_button(im, &event->button); break; - case SDL_FINGERMOTION: - case SDL_FINGERDOWN: - case SDL_FINGERUP: + case SDL_EVENT_FINGER_MOTION: + case SDL_EVENT_FINGER_DOWN: + case SDL_EVENT_FINGER_UP: if (!im->mp || paused) { break; } sc_input_manager_process_touch(im, &event->tfinger); break; - case SDL_CONTROLLERDEVICEADDED: - case SDL_CONTROLLERDEVICEREMOVED: + case SDL_EVENT_GAMEPAD_ADDED: + case SDL_EVENT_GAMEPAD_REMOVED: // Handle device added or removed even if paused if (!im->gp) { break; } - sc_input_manager_process_gamepad_device(im, &event->cdevice); + sc_input_manager_process_gamepad_device(im, &event->gdevice); break; - case SDL_CONTROLLERAXISMOTION: + case SDL_EVENT_GAMEPAD_AXIS_MOTION: if (!im->gp || paused) { break; } - sc_input_manager_process_gamepad_axis(im, &event->caxis); + sc_input_manager_process_gamepad_axis(im, &event->gaxis); break; - case SDL_CONTROLLERBUTTONDOWN: - case SDL_CONTROLLERBUTTONUP: + case SDL_EVENT_GAMEPAD_BUTTON_DOWN: + case SDL_EVENT_GAMEPAD_BUTTON_UP: if (!im->gp || paused) { break; } - sc_input_manager_process_gamepad_button(im, &event->cbutton); + sc_input_manager_process_gamepad_button(im, &event->gbutton); break; - case SDL_DROPFILE: { + case SDL_EVENT_DROP_FILE: { if (!control) { break; } diff --git a/app/src/input_manager.h b/app/src/input_manager.h index af4cbc69..6f4af8f7 100644 --- a/app/src/input_manager.h +++ b/app/src/input_manager.h @@ -5,8 +5,8 @@ #include #include -#include -#include +#include +#include #include "controller.h" #include "file_pusher.h" diff --git a/app/src/main.c b/app/src/main.c index 968b1934..a3d323d2 100644 --- a/app/src/main.c +++ b/app/src/main.c @@ -5,8 +5,9 @@ #ifdef HAVE_V4L2 # include #endif -#define SDL_MAIN_HANDLED // avoid link error on Linux Windows Subsystem -#include +#define SDL_FUNCTION_POINTER_IS_VOID_POINTER +#include +#include #include "cli.h" #include "options.h" diff --git a/app/src/mouse_capture.c b/app/src/mouse_capture.c index 25345faa..5ea7a3ca 100644 --- a/app/src/mouse_capture.c +++ b/app/src/mouse_capture.c @@ -20,14 +20,11 @@ bool sc_mouse_capture_handle_event(struct sc_mouse_capture *mc, const SDL_Event *event) { switch (event->type) { - case SDL_WINDOWEVENT: - if (event->window.event == SDL_WINDOWEVENT_FOCUS_LOST) { - sc_mouse_capture_set_active(mc, false); - return true; - } - break; - case SDL_KEYDOWN: { - SDL_Keycode key = event->key.keysym.sym; + case SDL_EVENT_WINDOW_FOCUS_LOST: + sc_mouse_capture_set_active(mc, false); + return true; + case SDL_EVENT_KEY_DOWN: { + SDL_Keycode key = event->key.key; if (sc_mouse_capture_is_capture_key(mc, key)) { if (!mc->mouse_capture_key_pressed) { mc->mouse_capture_key_pressed = key; @@ -41,8 +38,8 @@ sc_mouse_capture_handle_event(struct sc_mouse_capture *mc, } break; } - case SDL_KEYUP: { - SDL_Keycode key = event->key.keysym.sym; + case SDL_EVENT_KEY_UP: { + SDL_Keycode key = event->key.key; SDL_Keycode cap = mc->mouse_capture_key_pressed; mc->mouse_capture_key_pressed = 0; if (sc_mouse_capture_is_capture_key(mc, key)) { @@ -56,24 +53,24 @@ sc_mouse_capture_handle_event(struct sc_mouse_capture *mc, } break; } - case SDL_MOUSEWHEEL: - case SDL_MOUSEMOTION: - case SDL_MOUSEBUTTONDOWN: + case SDL_EVENT_MOUSE_WHEEL: + case SDL_EVENT_MOUSE_MOTION: + case SDL_EVENT_MOUSE_BUTTON_DOWN: if (!sc_mouse_capture_is_active(mc)) { // The mouse will be captured on SDL_MOUSEBUTTONUP, so consume // the event return true; } break; - case SDL_MOUSEBUTTONUP: + case SDL_EVENT_MOUSE_BUTTON_UP: if (!sc_mouse_capture_is_active(mc)) { sc_mouse_capture_set_active(mc, true); return true; } break; - case SDL_FINGERMOTION: - case SDL_FINGERDOWN: - case SDL_FINGERUP: + case SDL_EVENT_FINGER_MOTION: + case SDL_EVENT_FINGER_DOWN: + case SDL_EVENT_FINGER_UP: // Touch events are not compatible with relative mode // (coordinates are not relative), so consume the event return true; @@ -101,10 +98,9 @@ sc_mouse_capture_set_active(struct sc_mouse_capture *mc, bool capture) { SDL_WarpMouseInWindow(mc->window, w / 2, h / 2); } } -#else - (void) mc; #endif - if (SDL_SetRelativeMouseMode(capture)) { + bool ok = SDL_SetWindowRelativeMouseMode(mc->window, capture); + if (!ok) { LOGE("Could not set relative mouse mode to %s: %s", capture ? "true" : "false", SDL_GetError()); } @@ -112,8 +108,7 @@ sc_mouse_capture_set_active(struct sc_mouse_capture *mc, bool capture) { bool sc_mouse_capture_is_active(struct sc_mouse_capture *mc) { - (void) mc; - return SDL_GetRelativeMouseMode(); + return SDL_GetWindowRelativeMouseMode(mc->window); } void diff --git a/app/src/mouse_capture.h b/app/src/mouse_capture.h index f352cc13..65770f8a 100644 --- a/app/src/mouse_capture.h +++ b/app/src/mouse_capture.h @@ -5,7 +5,7 @@ #include -#include +#include struct sc_mouse_capture { SDL_Window *window; diff --git a/app/src/opengl.c b/app/src/opengl.c index 0cb83ed7..91e8d01d 100644 --- a/app/src/opengl.c +++ b/app/src/opengl.c @@ -3,21 +3,29 @@ #include #include #include -#include +#include void sc_opengl_init(struct sc_opengl *gl) { - gl->GetString = SDL_GL_GetProcAddress("glGetString"); + gl->GetString = (const GLubyte *(*)(GLenum)) + SDL_GL_GetProcAddress("glGetString"); assert(gl->GetString); - gl->TexParameterf = SDL_GL_GetProcAddress("glTexParameterf"); + gl->BindTexture = (void (*)(GLenum, GLuint)) + SDL_GL_GetProcAddress("glBindTexture"); + assert(gl->BindTexture); + + gl->TexParameterf = (void (*)(GLenum, GLenum, GLfloat)) + SDL_GL_GetProcAddress("glTexParameterf"); assert(gl->TexParameterf); - gl->TexParameteri = SDL_GL_GetProcAddress("glTexParameteri"); + gl->TexParameteri = (void (*)(GLenum, GLenum, GLint)) + SDL_GL_GetProcAddress("glTexParameteri"); assert(gl->TexParameteri); // optional - gl->GenerateMipmap = SDL_GL_GetProcAddress("glGenerateMipmap"); + gl->GenerateMipmap = (void (*)(GLenum)) + SDL_GL_GetProcAddress("glGenerateMipmap"); const char *version = (const char *) gl->GetString(GL_VERSION); assert(version); diff --git a/app/src/opengl.h b/app/src/opengl.h index 81163704..8db4e5d4 100644 --- a/app/src/opengl.h +++ b/app/src/opengl.h @@ -4,7 +4,7 @@ #include "common.h" #include -#include +#include struct sc_opengl { const char *version; @@ -15,6 +15,9 @@ struct sc_opengl { const GLubyte * (*GetString)(GLenum name); + void + (*BindTexture)(GLenum target, GLuint texture); + void (*TexParameterf)(GLenum target, GLenum pname, GLfloat param); diff --git a/app/src/receiver.c b/app/src/receiver.c index 2ccb8a8b..ef9e9f00 100644 --- a/app/src/receiver.c +++ b/app/src/receiver.c @@ -2,7 +2,8 @@ #include #include -#include +#include +#include #include "device_msg.h" #include "events.h" diff --git a/app/src/scrcpy.c b/app/src/scrcpy.c index a4c8c340..0d293605 100644 --- a/app/src/scrcpy.c +++ b/app/src/scrcpy.c @@ -6,7 +6,7 @@ #include #include #include -#include +#include #ifdef _WIN32 // not needed here, but winsock2.h must never be included AFTER windows.h @@ -94,7 +94,7 @@ struct scrcpy { #ifdef _WIN32 static BOOL WINAPI windows_ctrl_handler(DWORD ctrl_type) { if (ctrl_type == CTRL_C_EVENT) { - sc_push_event(SDL_QUIT); + sc_push_event(SDL_EVENT_QUIT); return TRUE; } return FALSE; @@ -108,41 +108,26 @@ sdl_set_hints(const char *render_driver) { } // App name used in various contexts (such as PulseAudio) -#if defined(SCRCPY_SDL_HAS_HINT_APP_NAME) if (!SDL_SetHint(SDL_HINT_APP_NAME, "scrcpy")) { LOGW("Could not set app name"); } -#elif defined(SCRCPY_SDL_HAS_HINT_AUDIO_DEVICE_APP_NAME) - if (!SDL_SetHint(SDL_HINT_AUDIO_DEVICE_APP_NAME, "scrcpy")) { - LOGW("Could not set audio device app name"); - } -#endif - - // Linear filtering - if (!SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "1")) { - LOGW("Could not enable linear filtering"); - } // Handle a click to gain focus as any other click if (!SDL_SetHint(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, "1")) { LOGW("Could not enable mouse focus clickthrough"); } -#ifdef SCRCPY_SDL_HAS_HINT_TOUCH_MOUSE_EVENTS // Disable synthetic mouse events from touch events // Touch events with id SDL_TOUCH_MOUSEID are ignored anyway, but it is // better not to generate them in the first place. if (!SDL_SetHint(SDL_HINT_TOUCH_MOUSE_EVENTS, "0")) { LOGW("Could not disable synthetic mouse events"); } -#endif -#ifdef SCRCPY_SDL_HAS_HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR // Disable compositor bypassing on X11 if (!SDL_SetHint(SDL_HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR, "0")) { LOGW("Could not disable X11 compositor bypass"); } -#endif // Do not minimize on focus loss if (!SDL_SetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, "0")) { @@ -198,7 +183,7 @@ event_loop(struct scrcpy *s, bool has_screen) { case SC_EVENT_TIME_LIMIT_REACHED: LOGI("Time limit reached"); return SCRCPY_EXIT_SUCCESS; - case SDL_QUIT: + case SDL_EVENT_QUIT: LOGD("User requested to quit"); return SCRCPY_EXIT_SUCCESS; case SC_EVENT_RUN_ON_MAIN_THREAD: { @@ -238,7 +223,7 @@ await_for_server(bool *connected) { SDL_Event event; while (SDL_WaitEvent(&event)) { switch (event.type) { - case SDL_QUIT: + case SDL_EVENT_QUIT: if (connected) { *connected = false; } @@ -366,12 +351,19 @@ static void init_sdl_gamepads(void) { // Trigger a SDL_CONTROLLERDEVICEADDED event for all gamepads already // connected - int num_joysticks = SDL_NumJoysticks(); - for (int i = 0; i < num_joysticks; ++i) { - if (SDL_IsGameController(i)) { + int count; + SDL_JoystickID *joysticks = SDL_GetJoysticks(&count); + if (!joysticks) { + LOGE("Could not list joysticks: %s", SDL_GetError()); + return; + } + + for (int i = 0; i < count; ++i) { + SDL_JoystickID joystick = joysticks[i]; + if (SDL_IsGamepad(joystick)) { SDL_Event event; - event.cdevice.type = SDL_CONTROLLERDEVICEADDED; - event.cdevice.which = i; + event.gdevice.type = SDL_EVENT_GAMEPAD_ADDED; + event.gdevice.which = i; SDL_PushEvent(&event); } } @@ -387,7 +379,7 @@ scrcpy(struct scrcpy_options *options) { struct scrcpy *s = &scrcpy; // Minimal SDL initialization - if (SDL_Init(SDL_INIT_EVENTS)) { + if (!SDL_Init(SDL_INIT_EVENTS)) { LOGE("Could not initialize SDL: %s", SDL_GetError()); return SCRCPY_EXIT_FAILURE; } @@ -513,7 +505,7 @@ scrcpy(struct scrcpy_options *options) { // --no-video-playback is passed so that clipboard synchronization // still works. // - if (SDL_Init(SDL_INIT_VIDEO)) { + if (!SDL_Init(SDL_INIT_VIDEO)) { // If it fails, it is an error only if video playback is enabled if (options->video_playback) { LOGE("Could not initialize SDL video: %s", SDL_GetError()); @@ -525,14 +517,14 @@ scrcpy(struct scrcpy_options *options) { } if (options->audio_playback) { - if (SDL_Init(SDL_INIT_AUDIO)) { + if (!SDL_Init(SDL_INIT_AUDIO)) { LOGE("Could not initialize SDL audio: %s", SDL_GetError()); goto end; } } if (options->gamepad_input_mode != SC_GAMEPAD_INPUT_MODE_DISABLED) { - if (SDL_Init(SDL_INIT_GAMECONTROLLER)) { + if (!SDL_Init(SDL_INIT_GAMEPAD)) { LOGE("Could not initialize SDL gamepad: %s", SDL_GetError()); goto end; } diff --git a/app/src/screen.c b/app/src/screen.c index fc4a22ff..a4f14b50 100644 --- a/app/src/screen.c +++ b/app/src/screen.c @@ -2,12 +2,13 @@ #include #include -#include +#include #include "events.h" #include "icon.h" #include "options.h" #include "util/log.h" +#include "util/window.h" #define DISPLAY_MARGINS 96 @@ -64,7 +65,9 @@ set_window_size(struct sc_screen *screen, struct sc_size new_size) { static bool get_preferred_display_bounds(struct sc_size *bounds) { SDL_Rect rect; - if (SDL_GetDisplayUsableBounds(0, &rect)) { + SDL_DisplayID display = SDL_GetPrimaryDisplay(); + bool ok = SDL_GetDisplayUsableBounds(display, &rect); + if (!ok) { LOGW("Could not get display usable bounds: %s", SDL_GetError()); return false; } @@ -168,7 +171,7 @@ sc_screen_update_content_rect(struct sc_screen *screen) { int dw; int dh; - SDL_GL_GetDrawableSize(screen->window, &dw, &dh); + SDL_GetWindowSizeInPixels(screen->window, &dw, &dh); struct sc_size content_size = screen->content_size; // The drawable size is the window size * the HiDPI scale @@ -236,18 +239,18 @@ sc_screen_render_novideo(struct sc_screen *screen) { // // // -static int +static bool 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) { + if (event->type == SDL_EVENT_WINDOW_EXPOSED) { // In practice, it seems to always be called from the same thread in // that specific case. Anyway, it's just a workaround. sc_screen_render(screen, true); } - return 0; + + return true; } #endif @@ -258,6 +261,7 @@ sc_screen_frame_sink_open(struct sc_frame_sink *sink, (void) ctx; struct sc_screen *screen = DOWNCAST(sink); + (void) screen; if (ctx->width <= 0 || ctx->width > 0xFFFF || ctx->height <= 0 || ctx->height > 0xFFFF) { @@ -349,7 +353,7 @@ sc_screen_init(struct sc_screen *screen, } } - uint32_t window_flags = SDL_WINDOW_ALLOW_HIGHDPI; + uint32_t window_flags = SDL_WINDOW_HIGH_PIXEL_DENSITY; if (params->always_on_top) { window_flags |= SDL_WINDOW_ALWAYS_ON_TOP; } @@ -383,15 +387,24 @@ sc_screen_init(struct sc_screen *screen, } // The window will be positioned and sized on first video frame - screen->window = SDL_CreateWindow(title, x, y, width, height, window_flags); + screen->window = + sc_create_sdl_window(title, x, y, width, height, window_flags); if (!screen->window) { LOGE("Could not create window: %s", SDL_GetError()); goto error_destroy_fps_counter; } + ok = SDL_StartTextInput(screen->window); + if (!ok) { + LOGE("Could not enable text input: %s", SDL_GetError()); + goto error_destroy_window; + } + SDL_Surface *icon = scrcpy_icon_load(); if (icon) { - SDL_SetWindowIcon(screen->window, icon); + if (!SDL_SetWindowIcon(screen->window, icon)) { + LOGW("Could not set window icon: %s", SDL_GetError()); + } } else if (params->video) { // just a warning LOGW("Could not load icon"); @@ -712,8 +725,8 @@ void sc_screen_toggle_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)) { + bool ok = SDL_SetWindowFullscreen(screen->window, !screen->fullscreen); + if (!ok) { LOGW("Could not switch fullscreen mode: %s", SDL_GetError()); return; } @@ -774,6 +787,8 @@ sc_screen_resize_to_pixel_perfect(struct sc_screen *screen) { bool sc_screen_handle_event(struct sc_screen *screen, const SDL_Event *event) { + // !video implies !has_video_window + assert(screen->video || !screen->has_video_window); switch (event->type) { case SC_EVENT_NEW_FRAME: { bool ok = sc_screen_update_frame(screen); @@ -783,46 +798,38 @@ 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) { + case SDL_EVENT_WINDOW_EXPOSED: + if (!screen->video) { sc_screen_render_novideo(screen); + } else if (screen->has_video_window) { + sc_screen_render(screen, true); + } + return true; + case SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED: + if (screen->has_video_window) { + sc_screen_render(screen, true); + } + return true; + case SDL_EVENT_WINDOW_MAXIMIZED: + screen->maximized = true; + return true; + case SDL_EVENT_WINDOW_MINIMIZED: + screen->minimized = true; + return true; + case SDL_EVENT_WINDOW_RESTORED: + if (screen->fullscreen) { + // On Windows, in maximized+fullscreen, disabling + // fullscreen mode unexpectedly triggers the "restored" + // then "maximized" events, leaving the window in a + // weird state (maximized according to the events, but + // not maximized visually). return true; } - - // !video implies !has_video_window - assert(screen->video || !screen->has_video_window); - if (!screen->has_video_window) { - // Do nothing - return true; - } - switch (event->window.event) { - case SDL_WINDOWEVENT_EXPOSED: - sc_screen_render(screen, true); - break; - case SDL_WINDOWEVENT_SIZE_CHANGED: - sc_screen_render(screen, true); - break; - case SDL_WINDOWEVENT_MAXIMIZED: - screen->maximized = true; - break; - case SDL_WINDOWEVENT_MINIMIZED: - screen->minimized = true; - break; - case SDL_WINDOWEVENT_RESTORED: - if (screen->fullscreen) { - // On Windows, in maximized+fullscreen, disabling - // fullscreen mode unexpectedly triggers the "restored" - // then "maximized" events, leaving the window in a - // weird state (maximized according to the events, but - // not maximized visually). - break; - } - screen->maximized = false; - screen->minimized = false; - apply_pending_resize(screen); - sc_screen_render(screen, true); - break; + screen->maximized = false; + screen->minimized = false; + if (screen->has_video_window) { + apply_pending_resize(screen); + sc_screen_render(screen, true); } return true; } @@ -905,7 +912,7 @@ sc_screen_hidpi_scale_coords(struct sc_screen *screen, int32_t *x, int32_t *y) { // take the HiDPI scaling (dw/ww and dh/wh) into account int ww, wh, dw, dh; SDL_GetWindowSize(screen->window, &ww, &wh); - SDL_GL_GetDrawableSize(screen->window, &dw, &dh); + SDL_GetWindowSizeInPixels(screen->window, &dw, &dh); // scale for HiDPI (64 bits for intermediate multiplications) *x = (int64_t) *x * dw / ww; diff --git a/app/src/screen.h b/app/src/screen.h index 89a25cda..0b992292 100644 --- a/app/src/screen.h +++ b/app/src/screen.h @@ -5,7 +5,7 @@ #include #include -#include +#include #include #include #include diff --git a/app/src/shortcut_mod.h b/app/src/shortcut_mod.h index f6c13f03..c53b0ff9 100644 --- a/app/src/shortcut_mod.h +++ b/app/src/shortcut_mod.h @@ -6,11 +6,11 @@ #include #include #include -#include +#include #include "options.h" -#define SC_SDL_SHORTCUT_MODS_MASK (KMOD_CTRL | KMOD_ALT | KMOD_GUI) +#define SC_SDL_SHORTCUT_MODS_MASK (SDL_KMOD_CTRL | SDL_KMOD_ALT | SDL_KMOD_GUI) // input: OR of enum sc_shortcut_mod // output: OR of SDL_Keymod @@ -18,22 +18,22 @@ static inline uint16_t sc_shortcut_mods_to_sdl(uint8_t shortcut_mods) { uint16_t sdl_mod = 0; if (shortcut_mods & SC_SHORTCUT_MOD_LCTRL) { - sdl_mod |= KMOD_LCTRL; + sdl_mod |= SDL_KMOD_LCTRL; } if (shortcut_mods & SC_SHORTCUT_MOD_RCTRL) { - sdl_mod |= KMOD_RCTRL; + sdl_mod |= SDL_KMOD_RCTRL; } if (shortcut_mods & SC_SHORTCUT_MOD_LALT) { - sdl_mod |= KMOD_LALT; + sdl_mod |= SDL_KMOD_LALT; } if (shortcut_mods & SC_SHORTCUT_MOD_RALT) { - sdl_mod |= KMOD_RALT; + sdl_mod |= SDL_KMOD_RALT; } if (shortcut_mods & SC_SHORTCUT_MOD_LSUPER) { - sdl_mod |= KMOD_LGUI; + sdl_mod |= SDL_KMOD_LGUI; } if (shortcut_mods & SC_SHORTCUT_MOD_RSUPER) { - sdl_mod |= KMOD_RGUI; + sdl_mod |= SDL_KMOD_RGUI; } return sdl_mod; } @@ -50,12 +50,12 @@ sc_shortcut_mods_is_shortcut_mod(uint16_t sdl_shortcut_mods, uint16_t sdl_mod) { static inline bool sc_shortcut_mods_is_shortcut_key(uint16_t sdl_shortcut_mods, SDL_Keycode keycode) { - return (sdl_shortcut_mods & KMOD_LCTRL && keycode == SDLK_LCTRL) - || (sdl_shortcut_mods & KMOD_RCTRL && keycode == SDLK_RCTRL) - || (sdl_shortcut_mods & KMOD_LALT && keycode == SDLK_LALT) - || (sdl_shortcut_mods & KMOD_RALT && keycode == SDLK_RALT) - || (sdl_shortcut_mods & KMOD_LGUI && keycode == SDLK_LGUI) - || (sdl_shortcut_mods & KMOD_RGUI && keycode == SDLK_RGUI); + return (sdl_shortcut_mods & SDL_KMOD_LCTRL && keycode == SDLK_LCTRL) + || (sdl_shortcut_mods & SDL_KMOD_RCTRL && keycode == SDLK_RCTRL) + || (sdl_shortcut_mods & SDL_KMOD_LALT && keycode == SDLK_LALT) + || (sdl_shortcut_mods & SDL_KMOD_RALT && keycode == SDLK_RALT) + || (sdl_shortcut_mods & SDL_KMOD_LGUI && keycode == SDLK_LGUI) + || (sdl_shortcut_mods & SDL_KMOD_RGUI && keycode == SDLK_RGUI); } #endif diff --git a/app/src/uhid/gamepad_uhid.c b/app/src/uhid/gamepad_uhid.c index c64feb18..b4fef59e 100644 --- a/app/src/uhid/gamepad_uhid.c +++ b/app/src/uhid/gamepad_uhid.c @@ -3,7 +3,7 @@ #include #include #include -#include +#include #include "hid/hid_gamepad.h" #include "input_events.h" @@ -74,10 +74,10 @@ sc_gamepad_processor_process_gamepad_added(struct sc_gamepad_processor *gp, return; } - SDL_GameController* game_controller = - SDL_GameControllerFromInstanceID(event->gamepad_id); + SDL_Gamepad * game_controller = + SDL_GetGamepadFromID(event->gamepad_id); assert(game_controller); - const char *name = SDL_GameControllerName(game_controller); + const char *name = SDL_GetGamepadName(game_controller); LOGI("Gamepad added: [%" PRIu32 "] %s", event->gamepad_id, name); sc_gamepad_uhid_send_open(gamepad, &hid_open); diff --git a/app/src/uhid/keyboard_uhid.c b/app/src/uhid/keyboard_uhid.c index 70082990..d8337df0 100644 --- a/app/src/uhid/keyboard_uhid.c +++ b/app/src/uhid/keyboard_uhid.c @@ -2,8 +2,8 @@ #include #include -#include -#include +#include +#include #include "util/log.h" #include "util/thread.h" diff --git a/app/src/usb/scrcpy_otg.c b/app/src/usb/scrcpy_otg.c index 1a9cc46e..ef0c1c5c 100644 --- a/app/src/usb/scrcpy_otg.c +++ b/app/src/usb/scrcpy_otg.c @@ -3,7 +3,7 @@ #include #include #include -#include +#include #ifdef _WIN32 # include "adb/adb.h" @@ -45,7 +45,7 @@ event_loop(struct scrcpy_otg *s) { case SC_EVENT_AOA_OPEN_ERROR: LOGE("AOA open error"); return SCRCPY_EXIT_FAILURE; - case SDL_QUIT: + case SDL_EVENT_QUIT: LOGD("User requested to quit"); return SCRCPY_EXIT_SUCCESS; default: @@ -63,22 +63,18 @@ scrcpy_otg(struct scrcpy_options *options) { const char *serial = options->serial; - if (!SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "1")) { - LOGW("Could not enable linear filtering"); - } - if (!SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1")) { LOGW("Could not allow joystick background events"); } // Minimal SDL initialization - if (SDL_Init(SDL_INIT_EVENTS)) { + if (!SDL_Init(SDL_INIT_EVENTS)) { LOGE("Could not initialize SDL: %s", SDL_GetError()); return SCRCPY_EXIT_FAILURE; } if (options->gamepad_input_mode != SC_GAMEPAD_INPUT_MODE_DISABLED) { - if (SDL_Init(SDL_INIT_GAMECONTROLLER)) { + if (!SDL_Init(SDL_INIT_GAMEPAD)) { LOGE("Could not initialize SDL controller: %s", SDL_GetError()); // Not fatal, keyboard/mouse should still work } diff --git a/app/src/usb/screen_otg.c b/app/src/usb/screen_otg.c index bed48eb6..3f77e2c1 100644 --- a/app/src/usb/screen_otg.c +++ b/app/src/usb/screen_otg.c @@ -7,12 +7,13 @@ #include "options.h" #include "util/acksync.h" #include "util/log.h" +#include "util/window.h" static void sc_screen_otg_render(struct sc_screen_otg *screen) { SDL_RenderClear(screen->renderer); if (screen->texture) { - SDL_RenderCopy(screen->renderer, screen->texture, NULL, NULL); + SDL_RenderTexture(screen->renderer, screen->texture, NULL, NULL); } SDL_RenderPresent(screen->renderer); } @@ -34,7 +35,7 @@ sc_screen_otg_init(struct sc_screen_otg *screen, int width = params->window_width ? params->window_width : 256; int height = params->window_height ? params->window_height : 256; - uint32_t window_flags = SDL_WINDOW_ALLOW_HIGHDPI; + uint32_t window_flags = SDL_WINDOW_HIGH_PIXEL_DENSITY; if (params->always_on_top) { window_flags |= SDL_WINDOW_ALWAYS_ON_TOP; } @@ -42,13 +43,14 @@ sc_screen_otg_init(struct sc_screen_otg *screen, window_flags |= SDL_WINDOW_BORDERLESS; } - screen->window = SDL_CreateWindow(title, x, y, width, height, window_flags); + screen->window = + sc_create_sdl_window(title, x, y, width, height, window_flags); if (!screen->window) { LOGE("Could not create window: %s", SDL_GetError()); return false; } - screen->renderer = SDL_CreateRenderer(screen->window, -1, 0); + screen->renderer = SDL_CreateRenderer(screen->window, NULL); if (!screen->renderer) { LOGE("Could not create renderer: %s", SDL_GetError()); goto error_destroy_window; @@ -59,7 +61,10 @@ sc_screen_otg_init(struct sc_screen_otg *screen, if (icon) { SDL_SetWindowIcon(screen->window, icon); - if (SDL_RenderSetLogicalSize(screen->renderer, icon->w, icon->h)) { + bool ok = + SDL_SetRenderLogicalPresentation(screen->renderer, icon->w, icon->h, + SDL_LOGICAL_PRESENTATION_LETTERBOX); + if (!ok) { LOGW("Could not set renderer logical size: %s", SDL_GetError()); // don't fail } @@ -108,10 +113,10 @@ sc_screen_otg_process_key(struct sc_screen_otg *screen, struct sc_key_event evt = { .action = sc_action_from_sdl_keyboard_type(event->type), - .keycode = sc_keycode_from_sdl(event->keysym.sym), - .scancode = sc_scancode_from_sdl(event->keysym.scancode), + .keycode = sc_keycode_from_sdl(event->key), + .scancode = sc_scancode_from_sdl(event->scancode), .repeat = event->repeat, - .mods_state = sc_mods_state_from_sdl(event->keysym.mod), + .mods_state = sc_mods_state_from_sdl(event->mod), }; assert(kp->ops->process_key); @@ -165,8 +170,8 @@ sc_screen_otg_process_mouse_wheel(struct sc_screen_otg *screen, struct sc_mouse_scroll_event evt = { // .position not used for HID events #if SDL_VERSION_ATLEAST(2, 0, 18) - .hscroll = event->preciseX, - .vscroll = event->preciseY, + .hscroll = event->x, + .vscroll = event->y, #else .hscroll = event->x, .vscroll = event->y, @@ -180,34 +185,34 @@ sc_screen_otg_process_mouse_wheel(struct sc_screen_otg *screen, static void sc_screen_otg_process_gamepad_device(struct sc_screen_otg *screen, - const SDL_ControllerDeviceEvent *event) { + const SDL_GamepadDeviceEvent *event) { assert(screen->gamepad); struct sc_gamepad_processor *gp = &screen->gamepad->gamepad_processor; - if (event->type == SDL_CONTROLLERDEVICEADDED) { - SDL_GameController *gc = SDL_GameControllerOpen(event->which); + if (event->type == SDL_EVENT_GAMEPAD_ADDED) { + SDL_Gamepad *gc = SDL_OpenGamepad(event->which); if (!gc) { LOGW("Could not open game controller"); return; } - SDL_Joystick *joystick = SDL_GameControllerGetJoystick(gc); + SDL_Joystick *joystick = SDL_GetGamepadJoystick(gc); if (!joystick) { LOGW("Could not get controller joystick"); - SDL_GameControllerClose(gc); + SDL_CloseGamepad(gc); return; } struct sc_gamepad_device_event evt = { - .gamepad_id = SDL_JoystickInstanceID(joystick), + .gamepad_id = SDL_GetJoystickID(joystick), }; gp->ops->process_gamepad_added(gp, &evt); - } else if (event->type == SDL_CONTROLLERDEVICEREMOVED) { + } else if (event->type == SDL_EVENT_GAMEPAD_REMOVED) { SDL_JoystickID id = event->which; - SDL_GameController *gc = SDL_GameControllerFromInstanceID(id); + SDL_Gamepad *gc = SDL_GetGamepadFromID(id); if (gc) { - SDL_GameControllerClose(gc); + SDL_CloseGamepad(gc); } else { LOGW("Unknown gamepad device removed"); } @@ -221,7 +226,7 @@ sc_screen_otg_process_gamepad_device(struct sc_screen_otg *screen, static void sc_screen_otg_process_gamepad_axis(struct sc_screen_otg *screen, - const SDL_ControllerAxisEvent *event) { + const SDL_GamepadAxisEvent *event) { assert(screen->gamepad); struct sc_gamepad_processor *gp = &screen->gamepad->gamepad_processor; @@ -240,7 +245,7 @@ sc_screen_otg_process_gamepad_axis(struct sc_screen_otg *screen, static void sc_screen_otg_process_gamepad_button(struct sc_screen_otg *screen, - const SDL_ControllerButtonEvent *event) { + const SDL_GamepadButtonEvent *event) { assert(screen->gamepad); struct sc_gamepad_processor *gp = &screen->gamepad->gamepad_processor; @@ -265,59 +270,55 @@ sc_screen_otg_handle_event(struct sc_screen_otg *screen, SDL_Event *event) { } switch (event->type) { - case SDL_WINDOWEVENT: - switch (event->window.event) { - case SDL_WINDOWEVENT_EXPOSED: - sc_screen_otg_render(screen); - break; - } - return; - case SDL_KEYDOWN: + case SDL_EVENT_WINDOW_EXPOSED: + sc_screen_otg_render(screen); + break; + case SDL_EVENT_KEY_DOWN: if (screen->keyboard) { sc_screen_otg_process_key(screen, &event->key); } break; - case SDL_KEYUP: + case SDL_EVENT_KEY_UP: if (screen->keyboard) { sc_screen_otg_process_key(screen, &event->key); } break; - case SDL_MOUSEMOTION: + case SDL_EVENT_MOUSE_MOTION: if (screen->mouse) { sc_screen_otg_process_mouse_motion(screen, &event->motion); } break; - case SDL_MOUSEBUTTONDOWN: + case SDL_EVENT_MOUSE_BUTTON_DOWN: if (screen->mouse) { sc_screen_otg_process_mouse_button(screen, &event->button); } break; - case SDL_MOUSEBUTTONUP: + case SDL_EVENT_MOUSE_BUTTON_UP: if (screen->mouse) { sc_screen_otg_process_mouse_button(screen, &event->button); } break; - case SDL_MOUSEWHEEL: + case SDL_EVENT_MOUSE_WHEEL: if (screen->mouse) { sc_screen_otg_process_mouse_wheel(screen, &event->wheel); } break; - case SDL_CONTROLLERDEVICEADDED: - case SDL_CONTROLLERDEVICEREMOVED: + case SDL_EVENT_GAMEPAD_ADDED: + case SDL_EVENT_GAMEPAD_REMOVED: // Handle device added or removed even if paused if (screen->gamepad) { - sc_screen_otg_process_gamepad_device(screen, &event->cdevice); + sc_screen_otg_process_gamepad_device(screen, &event->gdevice); } break; - case SDL_CONTROLLERAXISMOTION: + case SDL_EVENT_GAMEPAD_AXIS_MOTION: if (screen->gamepad) { - sc_screen_otg_process_gamepad_axis(screen, &event->caxis); + sc_screen_otg_process_gamepad_axis(screen, &event->gaxis); } break; - case SDL_CONTROLLERBUTTONDOWN: - case SDL_CONTROLLERBUTTONUP: + case SDL_EVENT_GAMEPAD_BUTTON_DOWN: + case SDL_EVENT_GAMEPAD_BUTTON_UP: if (screen->gamepad) { - sc_screen_otg_process_gamepad_button(screen, &event->cbutton); + sc_screen_otg_process_gamepad_button(screen, &event->gbutton); } break; } diff --git a/app/src/usb/screen_otg.h b/app/src/usb/screen_otg.h index 08b76ae7..32d9da96 100644 --- a/app/src/usb/screen_otg.h +++ b/app/src/usb/screen_otg.h @@ -5,7 +5,7 @@ #include #include -#include +#include #include "mouse_capture.h" #include "usb/gamepad_aoa.h" diff --git a/app/src/util/log.c b/app/src/util/log.c index 9114a258..c583b8fb 100644 --- a/app/src/util/log.c +++ b/app/src/util/log.c @@ -50,13 +50,13 @@ log_level_sdl_to_sc(SDL_LogPriority priority) { void sc_set_log_level(enum sc_log_level level) { SDL_LogPriority sdl_log = log_level_sc_to_sdl(level); - SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, sdl_log); - SDL_LogSetPriority(SDL_LOG_CATEGORY_CUSTOM, sdl_log); + SDL_SetLogPriority(SDL_LOG_CATEGORY_APPLICATION, sdl_log); + SDL_SetLogPriority(SDL_LOG_CATEGORY_CUSTOM, sdl_log); } enum sc_log_level sc_get_log_level(void) { - SDL_LogPriority sdl_log = SDL_LogGetPriority(SDL_LOG_CATEGORY_APPLICATION); + SDL_LogPriority sdl_log = SDL_GetLogPriority(SDL_LOG_CATEGORY_APPLICATION); return log_level_sdl_to_sc(sdl_log); } @@ -128,7 +128,7 @@ sc_av_log_callback(void *avcl, int level, const char *fmt, va_list vl) { free(local_fmt); } -static const char *const sc_sdl_log_priority_names[SDL_NUM_LOG_PRIORITIES] = { +static const char *const sc_sdl_log_priority_names[SDL_LOG_PRIORITY_COUNT] = { [SDL_LOG_PRIORITY_VERBOSE] = "VERBOSE", [SDL_LOG_PRIORITY_DEBUG] = "DEBUG", [SDL_LOG_PRIORITY_INFO] = "INFO", @@ -144,14 +144,14 @@ sc_sdl_log_print(void *userdata, int category, SDL_LogPriority priority, (void) category; FILE *out = priority < SDL_LOG_PRIORITY_WARN ? stdout : stderr; - assert(priority < SDL_NUM_LOG_PRIORITIES); + assert(priority < SDL_LOG_PRIORITY_COUNT); const char *prio_name = sc_sdl_log_priority_names[priority]; fprintf(out, "%s: %s\n", prio_name, message); } void sc_log_configure(void) { - SDL_LogSetOutputFunction(sc_sdl_log_print, NULL); + SDL_SetLogOutputFunction(sc_sdl_log_print, NULL); // Redirect FFmpeg logs to SDL logs av_log_set_callback(sc_av_log_callback); } diff --git a/app/src/util/log.h b/app/src/util/log.h index 0d79c9a4..02606cb4 100644 --- a/app/src/util/log.h +++ b/app/src/util/log.h @@ -3,7 +3,7 @@ #include "common.h" -#include +#include #include "options.h" diff --git a/app/src/util/thread.c b/app/src/util/thread.c index 2a5253f7..dce189bd 100644 --- a/app/src/util/thread.c +++ b/app/src/util/thread.c @@ -4,7 +4,7 @@ #include #include #include -#include +#include #include "util/log.h" @@ -31,11 +31,7 @@ static SDL_ThreadPriority to_sdl_thread_priority(enum sc_thread_priority priority) { switch (priority) { case SC_THREAD_PRIORITY_TIME_CRITICAL: -#ifdef SCRCPY_SDL_HAS_THREAD_PRIORITY_TIME_CRITICAL return SDL_THREAD_PRIORITY_TIME_CRITICAL; -#else - // fall through -#endif case SC_THREAD_PRIORITY_HIGH: return SDL_THREAD_PRIORITY_HIGH; case SC_THREAD_PRIORITY_NORMAL: @@ -51,8 +47,8 @@ to_sdl_thread_priority(enum sc_thread_priority priority) { bool sc_thread_set_priority(enum sc_thread_priority priority) { SDL_ThreadPriority sdl_priority = to_sdl_thread_priority(priority); - int r = SDL_SetThreadPriority(sdl_priority); - if (r) { + bool ok = SDL_SetCurrentThreadPriority(sdl_priority); + if (!ok) { LOGD("Could not set thread priority: %s", SDL_GetError()); return false; } @@ -67,7 +63,7 @@ sc_thread_join(sc_thread *thread, int *status) { bool sc_mutex_init(sc_mutex *mutex) { - SDL_mutex *sdl_mutex = SDL_CreateMutex(); + SDL_Mutex *sdl_mutex = SDL_CreateMutex(); if (!sdl_mutex) { LOG_OOM(); return false; @@ -89,40 +85,25 @@ void sc_mutex_lock(sc_mutex *mutex) { // SDL mutexes are recursive, but we don't want to use recursive mutexes assert(!sc_mutex_held(mutex)); - int r = SDL_LockMutex(mutex->mutex); + SDL_LockMutex(mutex->mutex); #ifndef NDEBUG - if (r) { - LOGE("Could not lock mutex: %s", SDL_GetError()); - abort(); - } - atomic_store_explicit(&mutex->locker, sc_thread_get_id(), memory_order_relaxed); -#else - (void) r; #endif } void sc_mutex_unlock(sc_mutex *mutex) { -#ifndef NDEBUG assert(sc_mutex_held(mutex)); +#ifndef NDEBUG atomic_store_explicit(&mutex->locker, 0, memory_order_relaxed); #endif - int r = SDL_UnlockMutex(mutex->mutex); -#ifndef NDEBUG - if (r) { - LOGE("Could not lock mutex: %s", SDL_GetError()); - abort(); - } -#else - (void) r; -#endif + SDL_UnlockMutex(mutex->mutex); } sc_thread_id sc_thread_get_id(void) { - return SDL_ThreadID(); + return SDL_GetCurrentThreadID(); } #ifndef NDEBUG @@ -136,7 +117,7 @@ sc_mutex_held(struct sc_mutex *mutex) { bool sc_cond_init(sc_cond *cond) { - SDL_cond *sdl_cond = SDL_CreateCond(); + SDL_Condition *sdl_cond = SDL_CreateCondition(); if (!sdl_cond) { LOG_OOM(); return false; @@ -148,22 +129,15 @@ sc_cond_init(sc_cond *cond) { void sc_cond_destroy(sc_cond *cond) { - SDL_DestroyCond(cond->cond); + SDL_DestroyCondition(cond->cond); } void sc_cond_wait(sc_cond *cond, sc_mutex *mutex) { - int r = SDL_CondWait(cond->cond, mutex->mutex); + SDL_WaitCondition(cond->cond, mutex->mutex); #ifndef NDEBUG - if (r) { - LOGE("Could not wait on condition: %s", SDL_GetError()); - abort(); - } - atomic_store_explicit(&mutex->locker, sc_thread_get_id(), memory_order_relaxed); -#else - (void) r; #endif } @@ -177,44 +151,22 @@ sc_cond_timedwait(sc_cond *cond, sc_mutex *mutex, sc_tick deadline) { // Round up to the next millisecond to guarantee that the deadline is // reached when returning due to timeout uint32_t ms = SC_TICK_TO_MS(deadline - now + SC_TICK_FROM_MS(1) - 1); - int r = SDL_CondWaitTimeout(cond->cond, mutex->mutex, ms); + bool signaled = SDL_WaitConditionTimeout(cond->cond, mutex->mutex, ms); #ifndef NDEBUG - if (r < 0) { - LOGE("Could not wait on condition with timeout: %s", SDL_GetError()); - abort(); - } - atomic_store_explicit(&mutex->locker, sc_thread_get_id(), memory_order_relaxed); #endif - assert(r == 0 || r == SDL_MUTEX_TIMEDOUT); // The deadline is reached on timeout - assert(r != SDL_MUTEX_TIMEDOUT || sc_tick_now() >= deadline); - return r == 0; + assert(signaled || sc_tick_now() >= deadline); + return signaled; } void sc_cond_signal(sc_cond *cond) { - int r = SDL_CondSignal(cond->cond); -#ifndef NDEBUG - if (r) { - LOGE("Could not signal a condition: %s", SDL_GetError()); - abort(); - } -#else - (void) r; -#endif + SDL_SignalCondition(cond->cond); } void sc_cond_broadcast(sc_cond *cond) { - int r = SDL_CondBroadcast(cond->cond); -#ifndef NDEBUG - if (r) { - LOGE("Could not broadcast a condition: %s", SDL_GetError()); - abort(); - } -#else - (void) r; -#endif + SDL_BroadcastCondition(cond->cond); } diff --git a/app/src/util/thread.h b/app/src/util/thread.h index 3d544046..13734bdc 100644 --- a/app/src/util/thread.h +++ b/app/src/util/thread.h @@ -10,8 +10,8 @@ /* Forward declarations */ typedef struct SDL_Thread SDL_Thread; -typedef struct SDL_mutex SDL_mutex; -typedef struct SDL_cond SDL_cond; +typedef struct SDL_Mutex SDL_Mutex; +typedef struct SDL_Condition SDL_Condition; typedef int sc_thread_fn(void *); typedef unsigned sc_thread_id; @@ -29,14 +29,14 @@ enum sc_thread_priority { }; typedef struct sc_mutex { - SDL_mutex *mutex; + SDL_Mutex *mutex; #ifndef NDEBUG sc_atomic_thread_id locker; #endif } sc_mutex; typedef struct sc_cond { - SDL_cond *cond; + SDL_Condition *cond; } sc_cond; extern sc_thread_id SC_MAIN_THREAD_ID; diff --git a/app/src/util/window.c b/app/src/util/window.c new file mode 100644 index 00000000..ae1c0ac1 --- /dev/null +++ b/app/src/util/window.c @@ -0,0 +1,33 @@ +#include "window.h" + +SDL_Window * +sc_create_sdl_window(const char *title, int64_t x, int64_t y, int64_t width, + int64_t height, int64_t flags) { + SDL_Window *window = NULL; + + SDL_PropertiesID props = SDL_CreateProperties(); + if (!props) { + return NULL; + } + + bool ok = + SDL_SetStringProperty(props, SDL_PROP_WINDOW_CREATE_TITLE_STRING, + title); + ok &= SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_X_NUMBER, x); + ok &= SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_Y_NUMBER, y); + ok &= SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_WIDTH_NUMBER, + width); + ok &= SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_HEIGHT_NUMBER, + height); + ok &= SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_FLAGS_NUMBER, + flags); + + if (!ok) { + SDL_DestroyProperties(props); + return NULL; + } + + window = SDL_CreateWindowWithProperties(props); + SDL_DestroyProperties(props); + return window; +} diff --git a/app/src/util/window.h b/app/src/util/window.h new file mode 100644 index 00000000..c6f349e5 --- /dev/null +++ b/app/src/util/window.h @@ -0,0 +1,13 @@ +#ifndef SC_WINDOW_H +#define SC_WINDOW_H + +#include "common.h" + +#include +#include + +SDL_Window * +sc_create_sdl_window(const char *title, int64_t x, int64_t y, int64_t width, + int64_t height, int64_t flags); + +#endif diff --git a/app/src/version.c b/app/src/version.c index f8610714..9a22a7e9 100644 --- a/app/src/version.c +++ b/app/src/version.c @@ -10,17 +10,20 @@ #ifdef HAVE_USB # include #endif -#include +#include void scrcpy_print_version(void) { printf("\nDependencies (compiled / linked):\n"); - SDL_version sdl; - SDL_GetVersion(&sdl); + int sdl = SDL_GetVersion(); printf(" - SDL: %u.%u.%u / %u.%u.%u\n", - SDL_MAJOR_VERSION, SDL_MINOR_VERSION, SDL_PATCHLEVEL, - (unsigned) sdl.major, (unsigned) sdl.minor, (unsigned) sdl.patch); + SDL_MAJOR_VERSION, + SDL_MINOR_VERSION, + SDL_MICRO_VERSION, + SDL_VERSIONNUM_MAJOR(sdl), + SDL_VERSIONNUM_MINOR(sdl), + SDL_VERSIONNUM_MICRO(sdl)); unsigned avcodec = avcodec_version(); printf(" - libavcodec: %u.%u.%u / %u.%u.%u\n", From 9cf66950c568732a555b42b1dfbcd2f3e8af1f18 Mon Sep 17 00:00:00 2001 From: Romain Vimont Date: Fri, 11 Jul 2025 09:42:20 +0200 Subject: [PATCH 7/8] Upgrade SDL build script for SDL3 --- app/deps/sdl.sh | 41 ++++++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/app/deps/sdl.sh b/app/deps/sdl.sh index e04deb0d..48f5c4ae 100755 --- a/app/deps/sdl.sh +++ b/app/deps/sdl.sh @@ -5,10 +5,10 @@ cd "$DEPS_DIR" . common process_args "$@" -VERSION=2.32.8 +VERSION=3.2.18 FILENAME=SDL-$VERSION.tar.gz PROJECT_DIR=SDL-release-$VERSION -SHA256SUM=dd35e05644ae527848d02433bec24dd0ea65db59faecf1a0e5d1880c533dac2c +SHA256SUM=51539fa13e546bc50c632beed3f34257de2baa38a4c642048de56377903b4265 cd "$SOURCES_DIR" @@ -35,45 +35,48 @@ else cd "$DIRNAME" conf=( - --prefix="$INSTALL_DIR/$DIRNAME" + -DCMAKE_INSTALL_PREFIX="$INSTALL_DIR/$DIRNAME" ) if [[ "$HOST" == linux ]] then conf+=( - --enable-video-wayland - --enable-video-x11 + -DSDL_WAYLAND=ON + -DSDL_X11=ON ) fi if [[ "$LINK_TYPE" == static ]] then conf+=( - --enable-static - --disable-shared + -DBUILD_SHARED_LIBS=OFF ) else conf+=( - --disable-static - --enable-shared + -DBUILD_SHARED_LIBS=ON ) fi if [[ "$BUILD_TYPE" == cross ]] then + if [[ "$HOST" = win32 ]] + then + TOOLCHAIN_FILENAME="cmake-toolchain-mingw64-i686.cmake" + elif [[ "$HOST" = win64 ]] + then + TOOLCHAIN_FILENAME="cmake-toolchain-mingw64-x86_64.cmake" + else + echo "Unsupported cross-build to host: $HOST" >&2 + exit 1 + fi + conf+=( - --host="$HOST_TRIPLET" + -DCMAKE_TOOLCHAIN_FILE="$SOURCES_DIR/$PROJECT_DIR/build-scripts/$TOOLCHAIN_FILENAME" ) fi - "$SOURCES_DIR/$PROJECT_DIR"/configure "${conf[@]}" + cmake "$SOURCES_DIR/$PROJECT_DIR" "${conf[@]}" fi -make -j -# There is no "make install-strip" -make install -# Strip manually -if [[ "$LINK_TYPE" == shared && "$HOST" == win* ]] -then - ${HOST_TRIPLET}-strip "$INSTALL_DIR/$DIRNAME/bin/SDL2.dll" -fi +cmake --build . +cmake --install . From 8bde81415519992209fc1d0e07b7475a57e4c738 Mon Sep 17 00:00:00 2001 From: Romain Vimont Date: Fri, 11 Jul 2025 19:33:26 +0200 Subject: [PATCH 8/8] Build SDL3 for test step on Github Actions The latest Ubuntu does not provide the SDL3 package yet. --- .github/workflows/release.yml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 27e3abf2..65950d23 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -80,8 +80,16 @@ jobs: libavutil-dev libswresample-dev libusb-1.0-0 libusb-1.0-0-dev \ libv4l-dev + # SDL3 is not available in Ubuntu yet + - name: Install SDL3 + run: | + app/deps/sdl.sh linux native shared + - name: Test - run: release/test_client.sh + run: | + export PKG_CONFIG_PATH="$PWD"/app/deps/work/install/linux-native-shared/lib/pkgconfig + export LD_LIBRARY_PATH="$PWD"/app/deps/work/install/linux-native-shared/lib + release/test_client.sh build-linux-x86_64: runs-on: ubuntu-22.04