Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added app/data/disconnected.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
File renamed without changes
File renamed without changes
6 changes: 3 additions & 3 deletions app/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ src = [
'src/delay_buffer.c',
'src/demuxer.c',
'src/device_msg.c',
'src/disconnect.c',
'src/events.c',
'src/icon.c',
'src/file_pusher.c',
Expand Down Expand Up @@ -190,8 +191,7 @@ executable('scrcpy', src,
datadir = get_option('datadir') # by default 'share'

install_man('scrcpy.1')
install_data('data/icon.png',
rename: 'scrcpy.png',
install_data('data/scrcpy.png',
install_dir: datadir / 'icons/hicolor/256x256/apps')
install_data('data/zsh-completion/_scrcpy',
install_dir: datadir / 'zsh/site-functions')
Expand Down Expand Up @@ -282,6 +282,6 @@ endif

if meson.version().version_compare('>= 0.58.0')
devenv = environment()
devenv.set('SCRCPY_ICON_PATH', meson.current_source_dir() / 'data/icon.png')
devenv.set('SCRCPY_ICON_DIR', meson.current_source_dir() / 'data')
meson.add_devenv(devenv)
endif
4 changes: 2 additions & 2 deletions app/scrcpy.1
Original file line number Diff line number Diff line change
Expand Up @@ -851,8 +851,8 @@ Path to adb.
Device serial to use if no selector (\fB-s\fR, \fB-d\fR, \fB-e\fR or \fB\-\-tcpip=\fIaddr\fR) is specified.

.TP
.B SCRCPY_ICON_PATH
Path to the program icon.
.B SCRCPY_ICON_DIR
Path to the icon directory.

.TP
.B SCRCPY_SERVER_PATH
Expand Down
4 changes: 2 additions & 2 deletions app/src/cli.c
Original file line number Diff line number Diff line change
Expand Up @@ -1249,8 +1249,8 @@ static const struct sc_envvar envvars[] = {
"--tcpip=<addr>) is specified",
},
{
.name = "SCRCPY_ICON_PATH",
.text = "Path to the program icon",
.name = "SCRCPY_ICON_DIR",
.text = "Path to the icon directory",
},
{
.name = "SCRCPY_SERVER_PATH",
Expand Down
89 changes: 89 additions & 0 deletions app/src/disconnect.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
#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");
}

if (d->deadline != SC_TICK_NONE) {
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);
}
sc_mutex_unlock(&d->mutex);

if (!d->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;
}

ok = sc_thread_create(&d->thread, run, "scrcpy-dis", d);
if (!ok) {
goto error_destroy_cond;
}

d->deadline = deadline;
d->interrupted = false;

assert(cbs && cbs->on_icon_loaded && cbs->on_timeout);
d->cbs = cbs;
d->cbs_userdata = cbs_userdata;

return true;

error_destroy_mutex:
sc_mutex_destroy(&d->mutex);
error_destroy_cond:
sc_cond_destroy(&d->cond);

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 changes: 47 additions & 0 deletions app/src/disconnect.h
Original file line number Diff line number Diff line change
@@ -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
10 changes: 7 additions & 3 deletions app/src/events.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,13 @@
#include "util/thread.h"

bool
sc_push_event_impl(uint32_t type, const char *name) {
SDL_Event event;
event.type = type;
sc_push_event_impl(uint32_t type, void* ptr, const char *name) {
SDL_Event event = {
.user = {
.type = type,
.data1 = ptr,
}
};
bool ok = SDL_PushEvent(&event);
if (!ok) {
LOGE("Could not post %s event: %s", name, SDL_GetError());
Expand Down
8 changes: 5 additions & 3 deletions app/src/events.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,20 @@ enum {
SC_EVENT_DEVICE_DISCONNECTED,
SC_EVENT_SERVER_CONNECTION_FAILED,
SC_EVENT_SERVER_CONNECTED,
SC_EVENT_USB_DEVICE_DISCONNECTED,
SC_EVENT_DEMUXER_ERROR,
SC_EVENT_RECORDER_ERROR,
SC_EVENT_TIME_LIMIT_REACHED,
SC_EVENT_CONTROLLER_ERROR,
SC_EVENT_AOA_OPEN_ERROR,
SC_EVENT_DISCONNECTED_ICON_LOADED,
SC_EVENT_DISCONNECTED_TIMEOUT,
};

bool
sc_push_event_impl(uint32_t type, const char *name);
sc_push_event_impl(uint32_t type, void* ptr, const char *name);

#define sc_push_event(TYPE) sc_push_event_impl(TYPE, # TYPE)
#define sc_push_event(TYPE) sc_push_event_impl(TYPE, NULL, # TYPE)
#define sc_push_event_with_data(TYPE, PTR) sc_push_event_impl(TYPE, PTR, # TYPE)

typedef void (*sc_runnable_fn)(void *userdata);

Expand Down
40 changes: 22 additions & 18 deletions app/src/icon.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,33 +14,37 @@

#include "config.h"
#include "util/env.h"
#ifdef PORTABLE
# include "util/file.h"
#endif
#include "util/file.h"
#include "util/log.h"

#define SCRCPY_PORTABLE_ICON_FILENAME "icon.png"
#define SCRCPY_DEFAULT_ICON_PATH \
PREFIX "/share/icons/hicolor/256x256/apps/scrcpy.png"
#define SCRCPY_DEFAULT_ICON_DIR PREFIX "/share/icons/hicolor/256x256/apps"

static char *
get_icon_path(void) {
char *icon_path = sc_get_env("SCRCPY_ICON_PATH");
if (icon_path) {
get_icon_path(const char *filename) {
char *icon_path;

char *icon_dir = sc_get_env("SCRCPY_ICON_DIR");
if (icon_dir) {
// if the envvar is set, use it
LOGD("Using SCRCPY_ICON_PATH: %s", icon_path);
icon_path = sc_file_build_path(icon_dir, filename);
free(icon_dir);
if (!icon_path) {
LOG_OOM();
return NULL;
}
LOGD("Using icon from SCRCPY_ICON_DIR: %s", icon_path);
return icon_path;
}

#ifndef PORTABLE
LOGD("Using icon: " SCRCPY_DEFAULT_ICON_PATH);
icon_path = strdup(SCRCPY_DEFAULT_ICON_PATH);
icon_path = sc_file_build_path(SCRCPY_DEFAULT_ICON_DIR, filename);
if (!icon_path) {
LOG_OOM();
return NULL;
}
LOGD("Using icon: %s", icon_path);
#else
icon_path = sc_file_get_local_path(SCRCPY_PORTABLE_ICON_FILENAME);
icon_path = sc_file_get_local_path(filename);
if (!icon_path) {
LOGE("Could not get icon path");
return NULL;
Expand Down Expand Up @@ -177,7 +181,7 @@ to_sdl_pixel_format(enum AVPixelFormat fmt) {
}

static SDL_Surface *
load_from_path(const char *path) {
sc_icon_load_from_full_path(const char *path) {
AVFrame *frame = decode_image(path);
if (!frame) {
return NULL;
Expand Down Expand Up @@ -274,19 +278,19 @@ load_from_path(const char *path) {
}

SDL_Surface *
scrcpy_icon_load(void) {
char *icon_path = get_icon_path();
sc_icon_load(const char *filename) {
char *icon_path = get_icon_path(filename);
if (!icon_path) {
return NULL;
}

SDL_Surface *icon = load_from_path(icon_path);
SDL_Surface *icon = sc_icon_load_from_full_path(icon_path);
free(icon_path);
return icon;
}

void
scrcpy_icon_destroy(SDL_Surface *icon) {
sc_icon_destroy(SDL_Surface *icon) {
SDL_PropertiesID props = SDL_GetSurfaceProperties(icon);
assert(props);
AVFrame *frame = SDL_GetPointerProperty(props, "sc_frame", NULL);
Expand Down
7 changes: 5 additions & 2 deletions app/src/icon.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,13 @@

#include <SDL3/SDL_surface.h>

#define SC_ICON_FILENAME_SCRCPY "scrcpy.png"
#define SC_ICON_FILENAME_DISCONNECTED "disconnected.png"

SDL_Surface *
scrcpy_icon_load(void);
sc_icon_load(const char *filename);

void
scrcpy_icon_destroy(SDL_Surface *icon);
sc_icon_destroy(SDL_Surface *icon);

#endif
24 changes: 16 additions & 8 deletions app/src/scrcpy.c
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,9 @@ event_loop(struct scrcpy *s, bool has_screen) {
switch (event.type) {
case SC_EVENT_DEVICE_DISCONNECTED:
LOGW("Device disconnected");
if (has_screen) {
sc_screen_handle_event(&s->screen, &event);
}
return SCRCPY_EXIT_DISCONNECTED;
case SC_EVENT_DEMUXER_ERROR:
LOGE("Demuxer error");
Expand Down Expand Up @@ -414,6 +417,7 @@ scrcpy(struct scrcpy_options *options) {
bool screen_initialized = false;
bool timeout_initialized = false;
bool timeout_started = false;
bool disconnected = false;

struct sc_acksync *acksync = NULL;

Expand Down Expand Up @@ -947,14 +951,7 @@ scrcpy(struct scrcpy_options *options) {

ret = event_loop(s, options->window);
terminate_event_loop();
LOGD("quit...");

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);
}
disconnected = ret == SCRCPY_EXIT_DISCONNECTED;

end:
if (timeout_started) {
Expand Down Expand Up @@ -999,6 +996,17 @@ scrcpy(struct scrcpy_options *options) {
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) {
sc_timeout_join(&s->timeout);
}
Expand Down
Loading