mirror of
https://github.com/Genymobile/scrcpy.git
synced 2026-04-11 14:21:49 +08:00
Display disconnected icon before closing
When the connection to the device is lost while mirroring, the window closed immediately, suggesting scrcpy had crashed. To make it clear that a disconnection occurred, display a disconnected icon for 2 seconds before closing the window.
This commit is contained in:
parent
d36322c841
commit
5a54e3bbb3
BIN
app/data/disconnected.png
Normal file
BIN
app/data/disconnected.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.6 KiB |
@ -15,6 +15,7 @@ src = [
|
|||||||
'src/delay_buffer.c',
|
'src/delay_buffer.c',
|
||||||
'src/demuxer.c',
|
'src/demuxer.c',
|
||||||
'src/device_msg.c',
|
'src/device_msg.c',
|
||||||
|
'src/disconnect.c',
|
||||||
'src/events.c',
|
'src/events.c',
|
||||||
'src/icon.c',
|
'src/icon.c',
|
||||||
'src/file_pusher.c',
|
'src/file_pusher.c',
|
||||||
|
|||||||
88
app/src/disconnect.c
Normal file
88
app/src/disconnect.c
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
#include "disconnect.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "icon.h"
|
||||||
|
#include "util/log.h"
|
||||||
|
|
||||||
|
static int
|
||||||
|
run(void *userdata) {
|
||||||
|
struct sc_disconnect *d = userdata;
|
||||||
|
|
||||||
|
SDL_Surface *icon = sc_icon_load(SC_ICON_FILENAME_DISCONNECTED);
|
||||||
|
if (icon) {
|
||||||
|
d->cbs->on_icon_loaded(d, icon, d->cbs_userdata);
|
||||||
|
} else {
|
||||||
|
LOGE("Could not load disconnected icon");
|
||||||
|
}
|
||||||
|
|
||||||
|
sc_mutex_lock(&d->mutex);
|
||||||
|
bool timed_out = false;
|
||||||
|
while (!d->interrupted && !timed_out) {
|
||||||
|
timed_out = !sc_cond_timedwait(&d->cond, &d->mutex, d->deadline);
|
||||||
|
}
|
||||||
|
bool interrupted = d->interrupted;
|
||||||
|
sc_mutex_unlock(&d->mutex);
|
||||||
|
|
||||||
|
if (!interrupted) {
|
||||||
|
d->cbs->on_timeout(d, d->cbs_userdata);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
sc_disconnect_start(struct sc_disconnect *d, sc_tick deadline,
|
||||||
|
const struct sc_disconnect_callbacks *cbs,
|
||||||
|
void *cbs_userdata) {
|
||||||
|
bool ok = sc_mutex_init(&d->mutex);
|
||||||
|
if (!ok) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ok = sc_cond_init(&d->cond);
|
||||||
|
if (!ok) {
|
||||||
|
goto error_destroy_mutex;
|
||||||
|
}
|
||||||
|
|
||||||
|
d->deadline = deadline;
|
||||||
|
d->interrupted = false;
|
||||||
|
|
||||||
|
assert(cbs && cbs->on_icon_loaded && cbs->on_timeout);
|
||||||
|
d->cbs = cbs;
|
||||||
|
d->cbs_userdata = cbs_userdata;
|
||||||
|
|
||||||
|
ok = sc_thread_create(&d->thread, run, "scrcpy-dis", d);
|
||||||
|
if (!ok) {
|
||||||
|
goto error_destroy_cond;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
error_destroy_cond:
|
||||||
|
sc_cond_destroy(&d->cond);
|
||||||
|
error_destroy_mutex:
|
||||||
|
sc_mutex_destroy(&d->mutex);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
sc_disconnect_interrupt(struct sc_disconnect *d) {
|
||||||
|
sc_mutex_lock(&d->mutex);
|
||||||
|
d->interrupted = true;
|
||||||
|
sc_mutex_unlock(&d->mutex);
|
||||||
|
// wake up blocking wait
|
||||||
|
sc_cond_signal(&d->cond);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
sc_disconnect_join(struct sc_disconnect *d) {
|
||||||
|
sc_thread_join(&d->thread, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
sc_disconnect_destroy(struct sc_disconnect *d) {
|
||||||
|
sc_cond_destroy(&d->cond);
|
||||||
|
sc_mutex_destroy(&d->mutex);
|
||||||
|
}
|
||||||
47
app/src/disconnect.h
Normal file
47
app/src/disconnect.h
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
#ifndef SC_DISCONNECT
|
||||||
|
#define SC_DISCONNECT
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
#include "SDL3/SDL_surface.h"
|
||||||
|
#include "util/tick.h"
|
||||||
|
#include "util/thread.h"
|
||||||
|
|
||||||
|
// Tool to handle loading the icon and signal timeout when the device is
|
||||||
|
// unexpectedly disconnected
|
||||||
|
struct sc_disconnect {
|
||||||
|
sc_tick deadline;
|
||||||
|
|
||||||
|
struct sc_thread thread;
|
||||||
|
struct sc_mutex mutex;
|
||||||
|
struct sc_cond cond;
|
||||||
|
bool interrupted;
|
||||||
|
|
||||||
|
const struct sc_disconnect_callbacks *cbs;
|
||||||
|
void *cbs_userdata;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct sc_disconnect_callbacks {
|
||||||
|
// Called when the disconnected icon is loaded
|
||||||
|
void (*on_icon_loaded)(struct sc_disconnect *d, SDL_Surface *icon,
|
||||||
|
void *userdata);
|
||||||
|
|
||||||
|
// Called when the timeout expired (the scrcpy window must be closed)
|
||||||
|
void (*on_timeout)(struct sc_disconnect *d, void *userdata);
|
||||||
|
};
|
||||||
|
|
||||||
|
bool
|
||||||
|
sc_disconnect_start(struct sc_disconnect *d, sc_tick deadline,
|
||||||
|
const struct sc_disconnect_callbacks *cbs,
|
||||||
|
void *cbs_userdata);
|
||||||
|
|
||||||
|
void
|
||||||
|
sc_disconnect_interrupt(struct sc_disconnect *d);
|
||||||
|
|
||||||
|
void
|
||||||
|
sc_disconnect_join(struct sc_disconnect *d);
|
||||||
|
|
||||||
|
void
|
||||||
|
sc_disconnect_destroy(struct sc_disconnect *d);
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -13,12 +13,13 @@ enum {
|
|||||||
SC_EVENT_DEVICE_DISCONNECTED,
|
SC_EVENT_DEVICE_DISCONNECTED,
|
||||||
SC_EVENT_SERVER_CONNECTION_FAILED,
|
SC_EVENT_SERVER_CONNECTION_FAILED,
|
||||||
SC_EVENT_SERVER_CONNECTED,
|
SC_EVENT_SERVER_CONNECTED,
|
||||||
SC_EVENT_USB_DEVICE_DISCONNECTED,
|
|
||||||
SC_EVENT_DEMUXER_ERROR,
|
SC_EVENT_DEMUXER_ERROR,
|
||||||
SC_EVENT_RECORDER_ERROR,
|
SC_EVENT_RECORDER_ERROR,
|
||||||
SC_EVENT_TIME_LIMIT_REACHED,
|
SC_EVENT_TIME_LIMIT_REACHED,
|
||||||
SC_EVENT_CONTROLLER_ERROR,
|
SC_EVENT_CONTROLLER_ERROR,
|
||||||
SC_EVENT_AOA_OPEN_ERROR,
|
SC_EVENT_AOA_OPEN_ERROR,
|
||||||
|
SC_EVENT_DISCONNECTED_ICON_LOADED,
|
||||||
|
SC_EVENT_DISCONNECTED_TIMEOUT,
|
||||||
};
|
};
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
|||||||
@ -6,6 +6,7 @@
|
|||||||
#include <SDL3/SDL_surface.h>
|
#include <SDL3/SDL_surface.h>
|
||||||
|
|
||||||
#define SC_ICON_FILENAME_SCRCPY "scrcpy.png"
|
#define SC_ICON_FILENAME_SCRCPY "scrcpy.png"
|
||||||
|
#define SC_ICON_FILENAME_DISCONNECTED "disconnected.png"
|
||||||
|
|
||||||
SDL_Surface *
|
SDL_Surface *
|
||||||
sc_icon_load(const char *filename);
|
sc_icon_load(const char *filename);
|
||||||
|
|||||||
@ -173,6 +173,9 @@ event_loop(struct scrcpy *s, bool has_screen) {
|
|||||||
switch (event.type) {
|
switch (event.type) {
|
||||||
case SC_EVENT_DEVICE_DISCONNECTED:
|
case SC_EVENT_DEVICE_DISCONNECTED:
|
||||||
LOGW("Device disconnected");
|
LOGW("Device disconnected");
|
||||||
|
if (has_screen) {
|
||||||
|
sc_screen_handle_event(&s->screen, &event);
|
||||||
|
}
|
||||||
return SCRCPY_EXIT_DISCONNECTED;
|
return SCRCPY_EXIT_DISCONNECTED;
|
||||||
case SC_EVENT_DEMUXER_ERROR:
|
case SC_EVENT_DEMUXER_ERROR:
|
||||||
LOGE("Demuxer error");
|
LOGE("Demuxer error");
|
||||||
@ -415,6 +418,7 @@ scrcpy(struct scrcpy_options *options) {
|
|||||||
bool screen_initialized = false;
|
bool screen_initialized = false;
|
||||||
bool timeout_initialized = false;
|
bool timeout_initialized = false;
|
||||||
bool timeout_started = false;
|
bool timeout_started = false;
|
||||||
|
bool disconnected = false;
|
||||||
|
|
||||||
struct sc_acksync *acksync = NULL;
|
struct sc_acksync *acksync = NULL;
|
||||||
|
|
||||||
@ -948,14 +952,7 @@ aoa_complete:
|
|||||||
|
|
||||||
ret = event_loop(s, options->window);
|
ret = event_loop(s, options->window);
|
||||||
terminate_runnables_on_event_loop();
|
terminate_runnables_on_event_loop();
|
||||||
LOGD("quit...");
|
disconnected = ret == SCRCPY_EXIT_DISCONNECTED;
|
||||||
|
|
||||||
if (options->window) {
|
|
||||||
// Close the window immediately on closing, because screen_destroy()
|
|
||||||
// may only be called once the video demuxer thread is joined (it may
|
|
||||||
// take time)
|
|
||||||
sc_screen_hide_window(&s->screen);
|
|
||||||
}
|
|
||||||
|
|
||||||
end:
|
end:
|
||||||
if (timeout_started) {
|
if (timeout_started) {
|
||||||
@ -1000,6 +997,17 @@ end:
|
|||||||
sc_server_stop(&s->server);
|
sc_server_stop(&s->server);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (screen_initialized) {
|
||||||
|
if (disconnected) {
|
||||||
|
sc_screen_handle_disconnection(&s->screen);
|
||||||
|
}
|
||||||
|
LOGD("Quit...");
|
||||||
|
|
||||||
|
// Close the window immediately, because sc_screen_destroy() may only be
|
||||||
|
// called once the video demuxer thread is joined (it may take time)
|
||||||
|
sc_screen_hide_window(&s->screen);
|
||||||
|
}
|
||||||
|
|
||||||
if (timeout_started) {
|
if (timeout_started) {
|
||||||
sc_timeout_join(&s->timeout);
|
sc_timeout_join(&s->timeout);
|
||||||
}
|
}
|
||||||
|
|||||||
121
app/src/screen.c
121
app/src/screen.c
@ -184,7 +184,7 @@ compute_content_rect(struct sc_size render_size, struct sc_size content_size,
|
|||||||
static void
|
static void
|
||||||
sc_screen_update_content_rect(struct sc_screen *screen) {
|
sc_screen_update_content_rect(struct sc_screen *screen) {
|
||||||
// Only upscale video frames, not icon
|
// Only upscale video frames, not icon
|
||||||
bool can_upscale = screen->video;
|
bool can_upscale = screen->video && !screen->disconnected;
|
||||||
|
|
||||||
struct sc_size render_size =
|
struct sc_size render_size =
|
||||||
sc_sdl_get_render_output_size(screen->renderer);
|
sc_sdl_get_render_output_size(screen->renderer);
|
||||||
@ -210,7 +210,9 @@ sc_screen_render(struct sc_screen *screen, bool update_content_rect) {
|
|||||||
bool ok = false;
|
bool ok = false;
|
||||||
SDL_Texture *texture = screen->tex.texture;
|
SDL_Texture *texture = screen->tex.texture;
|
||||||
if (!texture) {
|
if (!texture) {
|
||||||
LOGW("No texture to render");
|
if (!screen->disconnected) {
|
||||||
|
LOGW("No texture to render");
|
||||||
|
}
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -346,6 +348,8 @@ sc_screen_init(struct sc_screen *screen,
|
|||||||
screen->paused = false;
|
screen->paused = false;
|
||||||
screen->resume_frame = NULL;
|
screen->resume_frame = NULL;
|
||||||
screen->orientation = SC_ORIENTATION_0;
|
screen->orientation = SC_ORIENTATION_0;
|
||||||
|
screen->disconnected = false;
|
||||||
|
screen->disconnect_started = false;
|
||||||
|
|
||||||
screen->video = params->video;
|
screen->video = params->video;
|
||||||
screen->camera = params->camera;
|
screen->camera = params->camera;
|
||||||
@ -606,9 +610,19 @@ sc_screen_interrupt(struct sc_screen *screen) {
|
|||||||
sc_fps_counter_interrupt(&screen->fps_counter);
|
sc_fps_counter_interrupt(&screen->fps_counter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
sc_screen_interrupt_disconnect(struct sc_screen *screen) {
|
||||||
|
if (screen->disconnect_started) {
|
||||||
|
sc_disconnect_interrupt(&screen->disconnect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
sc_screen_join(struct sc_screen *screen) {
|
sc_screen_join(struct sc_screen *screen) {
|
||||||
sc_fps_counter_join(&screen->fps_counter);
|
sc_fps_counter_join(&screen->fps_counter);
|
||||||
|
if (screen->disconnect_started) {
|
||||||
|
sc_disconnect_join(&screen->disconnect);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -616,6 +630,9 @@ sc_screen_destroy(struct sc_screen *screen) {
|
|||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
assert(!screen->open);
|
assert(!screen->open);
|
||||||
#endif
|
#endif
|
||||||
|
if (screen->disconnect_started) {
|
||||||
|
sc_disconnect_destroy(&screen->disconnect);
|
||||||
|
}
|
||||||
sc_texture_destroy(&screen->tex);
|
sc_texture_destroy(&screen->tex);
|
||||||
av_frame_free(&screen->frame);
|
av_frame_free(&screen->frame);
|
||||||
#ifdef SC_DISPLAY_FORCE_OPENGL_CORE_PROFILE
|
#ifdef SC_DISPLAY_FORCE_OPENGL_CORE_PROFILE
|
||||||
@ -625,6 +642,17 @@ sc_screen_destroy(struct sc_screen *screen) {
|
|||||||
SDL_DestroyWindow(screen->window);
|
SDL_DestroyWindow(screen->window);
|
||||||
sc_fps_counter_destroy(&screen->fps_counter);
|
sc_fps_counter_destroy(&screen->fps_counter);
|
||||||
sc_frame_buffer_destroy(&screen->fb);
|
sc_frame_buffer_destroy(&screen->fb);
|
||||||
|
|
||||||
|
SDL_Event event;
|
||||||
|
int nevents = SDL_PeepEvents(&event, 1, SDL_GETEVENT,
|
||||||
|
SC_EVENT_DISCONNECTED_ICON_LOADED,
|
||||||
|
SC_EVENT_DISCONNECTED_ICON_LOADED);
|
||||||
|
if (nevents == 1) {
|
||||||
|
assert(event.type == SC_EVENT_DISCONNECTED_ICON_LOADED);
|
||||||
|
// The event was posted, but not handled, the icon must be freed
|
||||||
|
SDL_Surface *dangling_icon = event.user.data1;
|
||||||
|
sc_icon_destroy(dangling_icon);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -854,6 +882,27 @@ sc_screen_resize_to_pixel_perfect(struct sc_screen *screen) {
|
|||||||
content_size.height);
|
content_size.height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
sc_disconnect_on_icon_loaded(struct sc_disconnect *d, SDL_Surface *icon,
|
||||||
|
void *userdata) {
|
||||||
|
(void) d;
|
||||||
|
(void) userdata;
|
||||||
|
|
||||||
|
bool ok = sc_push_event_with_data(SC_EVENT_DISCONNECTED_ICON_LOADED, icon);
|
||||||
|
if (!ok) {
|
||||||
|
sc_icon_destroy(icon);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
sc_disconnect_on_timeout(struct sc_disconnect *d, void *userdata) {
|
||||||
|
(void) d;
|
||||||
|
(void) userdata;
|
||||||
|
|
||||||
|
bool ok = sc_push_event(SC_EVENT_DISCONNECTED_TIMEOUT);
|
||||||
|
(void) ok; // ignore failure
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
sc_screen_handle_event(struct sc_screen *screen, const SDL_Event *event) {
|
sc_screen_handle_event(struct sc_screen *screen, const SDL_Event *event) {
|
||||||
switch (event->type) {
|
switch (event->type) {
|
||||||
@ -890,6 +939,29 @@ sc_screen_handle_event(struct sc_screen *screen, const SDL_Event *event) {
|
|||||||
apply_pending_resize(screen);
|
apply_pending_resize(screen);
|
||||||
sc_screen_render(screen, true);
|
sc_screen_render(screen, true);
|
||||||
}
|
}
|
||||||
|
return;
|
||||||
|
case SC_EVENT_DEVICE_DISCONNECTED:
|
||||||
|
assert(!screen->disconnected);
|
||||||
|
screen->disconnected = true;
|
||||||
|
if (!screen->window_shown) {
|
||||||
|
// No window open
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sc_texture_reset(&screen->tex);
|
||||||
|
sc_screen_render(screen, true);
|
||||||
|
|
||||||
|
sc_tick deadline = sc_tick_now() + SC_TICK_FROM_SEC(2);
|
||||||
|
static const struct sc_disconnect_callbacks cbs = {
|
||||||
|
.on_icon_loaded = sc_disconnect_on_icon_loaded,
|
||||||
|
.on_timeout = sc_disconnect_on_timeout,
|
||||||
|
};
|
||||||
|
bool ok =
|
||||||
|
sc_disconnect_start(&screen->disconnect, deadline, &cbs, NULL);
|
||||||
|
if (ok) {
|
||||||
|
screen->disconnect_started = true;
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -902,6 +974,51 @@ sc_screen_handle_event(struct sc_screen *screen, const SDL_Event *event) {
|
|||||||
sc_input_manager_handle_event(&screen->im, event);
|
sc_input_manager_handle_event(&screen->im, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
sc_screen_handle_disconnection(struct sc_screen *screen) {
|
||||||
|
if (!screen->window_shown) {
|
||||||
|
// No window open, quit immediately
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!screen->disconnect_started) {
|
||||||
|
// If sc_disconnect_start() failed, quit immediately
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_Event event;
|
||||||
|
while (SDL_WaitEvent(&event)) {
|
||||||
|
switch (event.type) {
|
||||||
|
case SC_EVENT_DISCONNECTED_ICON_LOADED: {
|
||||||
|
SDL_Surface *icon_disconnected = event.user.data1;
|
||||||
|
assert(icon_disconnected);
|
||||||
|
|
||||||
|
bool ok = sc_texture_set_from_surface(&screen->tex, icon_disconnected);
|
||||||
|
if (ok) {
|
||||||
|
screen->content_size.width = icon_disconnected->w;
|
||||||
|
screen->content_size.height = icon_disconnected->h;
|
||||||
|
sc_screen_render(screen, true);
|
||||||
|
} else {
|
||||||
|
// not fatal
|
||||||
|
LOGE("Could not set disconnected icon");
|
||||||
|
}
|
||||||
|
|
||||||
|
sc_icon_destroy(icon_disconnected);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SC_EVENT_DISCONNECTED_TIMEOUT:
|
||||||
|
LOGD("Closing after device disconnection");
|
||||||
|
goto end;
|
||||||
|
case SDL_EVENT_QUIT:
|
||||||
|
LOGD("User requested to quit");
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
end:
|
||||||
|
sc_screen_interrupt_disconnect(screen);
|
||||||
|
}
|
||||||
|
|
||||||
struct sc_point
|
struct sc_point
|
||||||
sc_screen_convert_drawable_to_frame_coords(struct sc_screen *screen,
|
sc_screen_convert_drawable_to_frame_coords(struct sc_screen *screen,
|
||||||
int32_t x, int32_t y) {
|
int32_t x, int32_t y) {
|
||||||
|
|||||||
@ -12,6 +12,7 @@
|
|||||||
|
|
||||||
#include "controller.h"
|
#include "controller.h"
|
||||||
#include "coords.h"
|
#include "coords.h"
|
||||||
|
#include "disconnect.h"
|
||||||
#include "fps_counter.h"
|
#include "fps_counter.h"
|
||||||
#include "frame_buffer.h"
|
#include "frame_buffer.h"
|
||||||
#include "input_manager.h"
|
#include "input_manager.h"
|
||||||
@ -77,6 +78,10 @@ struct sc_screen {
|
|||||||
|
|
||||||
bool paused;
|
bool paused;
|
||||||
AVFrame *resume_frame;
|
AVFrame *resume_frame;
|
||||||
|
|
||||||
|
bool disconnected;
|
||||||
|
bool disconnect_started;
|
||||||
|
struct sc_disconnect disconnect;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct sc_screen_params {
|
struct sc_screen_params {
|
||||||
@ -116,7 +121,7 @@ bool
|
|||||||
sc_screen_init(struct sc_screen *screen, const struct sc_screen_params *params);
|
sc_screen_init(struct sc_screen *screen, const struct sc_screen_params *params);
|
||||||
|
|
||||||
// request to interrupt any inner thread
|
// request to interrupt any inner thread
|
||||||
// must be called before screen_join()
|
// must be called before sc_screen_join()
|
||||||
void
|
void
|
||||||
sc_screen_interrupt(struct sc_screen *screen);
|
sc_screen_interrupt(struct sc_screen *screen);
|
||||||
|
|
||||||
@ -160,6 +165,10 @@ sc_screen_set_paused(struct sc_screen *screen, bool paused);
|
|||||||
void
|
void
|
||||||
sc_screen_handle_event(struct sc_screen *screen, const SDL_Event *event);
|
sc_screen_handle_event(struct sc_screen *screen, const SDL_Event *event);
|
||||||
|
|
||||||
|
// run the event loop once the device is disconnected
|
||||||
|
void
|
||||||
|
sc_screen_handle_disconnection(struct sc_screen *screen);
|
||||||
|
|
||||||
// convert point from window coordinates to frame coordinates
|
// convert point from window coordinates to frame coordinates
|
||||||
// x and y are expressed in pixels
|
// x and y are expressed in pixels
|
||||||
struct sc_point
|
struct sc_point
|
||||||
|
|||||||
@ -31,7 +31,7 @@ sc_usb_on_disconnected(struct sc_usb *usb, void *userdata) {
|
|||||||
(void) usb;
|
(void) usb;
|
||||||
(void) userdata;
|
(void) userdata;
|
||||||
|
|
||||||
sc_push_event(SC_EVENT_USB_DEVICE_DISCONNECTED);
|
sc_push_event(SC_EVENT_DEVICE_DISCONNECTED);
|
||||||
}
|
}
|
||||||
|
|
||||||
static enum scrcpy_exit_code
|
static enum scrcpy_exit_code
|
||||||
@ -39,8 +39,9 @@ event_loop(struct scrcpy_otg *s) {
|
|||||||
SDL_Event event;
|
SDL_Event event;
|
||||||
while (SDL_WaitEvent(&event)) {
|
while (SDL_WaitEvent(&event)) {
|
||||||
switch (event.type) {
|
switch (event.type) {
|
||||||
case SC_EVENT_USB_DEVICE_DISCONNECTED:
|
case SC_EVENT_DEVICE_DISCONNECTED:
|
||||||
LOGW("Device disconnected");
|
LOGW("Device disconnected");
|
||||||
|
sc_screen_handle_event(&s->screen, &event);
|
||||||
return SCRCPY_EXIT_DISCONNECTED;
|
return SCRCPY_EXIT_DISCONNECTED;
|
||||||
case SC_EVENT_AOA_OPEN_ERROR:
|
case SC_EVENT_AOA_OPEN_ERROR:
|
||||||
LOGE("AOA open error");
|
LOGE("AOA open error");
|
||||||
@ -96,6 +97,7 @@ scrcpy_otg(struct scrcpy_options *options) {
|
|||||||
bool aoa_started = false;
|
bool aoa_started = false;
|
||||||
bool aoa_initialized = false;
|
bool aoa_initialized = false;
|
||||||
bool screen_initialized = false;
|
bool screen_initialized = false;
|
||||||
|
bool disconnected = false;
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
// On Windows, only one process could open a USB device
|
// On Windows, only one process could open a USB device
|
||||||
@ -221,7 +223,7 @@ scrcpy_otg(struct scrcpy_options *options) {
|
|||||||
usb_device_initialized = false;
|
usb_device_initialized = false;
|
||||||
|
|
||||||
ret = event_loop(s);
|
ret = event_loop(s);
|
||||||
LOGD("quit...");
|
disconnected = ret == SCRCPY_EXIT_DISCONNECTED;
|
||||||
|
|
||||||
end:
|
end:
|
||||||
if (aoa_started) {
|
if (aoa_started) {
|
||||||
@ -231,6 +233,14 @@ end:
|
|||||||
|
|
||||||
if (screen_initialized) {
|
if (screen_initialized) {
|
||||||
sc_screen_interrupt(&s->screen);
|
sc_screen_interrupt(&s->screen);
|
||||||
|
|
||||||
|
if (disconnected) {
|
||||||
|
sc_screen_handle_disconnection(&s->screen);
|
||||||
|
}
|
||||||
|
LOGD("Quit...");
|
||||||
|
|
||||||
|
// Close the window immediately
|
||||||
|
sc_screen_hide_window(&s->screen);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mp) {
|
if (mp) {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user