Compare commits
2 Commits
tmp
...
macos_clos
Author | SHA1 | Date | |
---|---|---|---|
1ddf289d82 | |||
bf7c7d8038 |
201
.github/workflows/release.yml
vendored
201
.github/workflows/release.yml
vendored
@ -42,10 +42,10 @@ jobs:
|
||||
distribution: 'zulu'
|
||||
java-version: '17'
|
||||
|
||||
- name: Build
|
||||
- name: Build scrcpy-server
|
||||
run: release/build_server.sh
|
||||
|
||||
- name: Upload artifact
|
||||
- name: Upload scrcpy-server artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: scrcpy-server
|
||||
@ -63,7 +63,7 @@ jobs:
|
||||
distribution: 'zulu'
|
||||
java-version: '17'
|
||||
|
||||
- name: Build without gradle
|
||||
- name: Build scrcpy-server without gradle
|
||||
run: server/build_without_gradle.sh
|
||||
|
||||
test-client:
|
||||
@ -74,6 +74,7 @@ jobs:
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt install -y meson ninja-build nasm ffmpeg libsdl2-2.0-0 \
|
||||
libsdl2-dev libavcodec-dev libavdevice-dev libavformat-dev \
|
||||
libavutil-dev libswresample-dev libusb-1.0-0 libusb-1.0-0-dev \
|
||||
@ -82,44 +83,36 @@ jobs:
|
||||
- name: Test
|
||||
run: release/test_client.sh
|
||||
|
||||
build-linux-x86_64:
|
||||
build-linux:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check architecture
|
||||
run: |
|
||||
arch=$(uname -m)
|
||||
if [[ "$arch" != x86_64 ]]
|
||||
then
|
||||
echo "Unexpected architecture: $arch" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt install -y meson ninja-build nasm ffmpeg libsdl2-2.0-0 \
|
||||
libsdl2-dev libavcodec-dev libavdevice-dev libavformat-dev \
|
||||
libavutil-dev libswresample-dev libusb-1.0-0 libusb-1.0-0-dev \
|
||||
libv4l-dev
|
||||
|
||||
- name: Build
|
||||
run: release/build_linux.sh x86_64
|
||||
- name: Build linux
|
||||
run: release/build_linux.sh
|
||||
|
||||
# upload-artifact does not preserve permissions
|
||||
- name: Tar
|
||||
run: |
|
||||
cd release/work/build-linux-x86_64
|
||||
cd release/work/build-linux
|
||||
mkdir dist-tar
|
||||
cd dist-tar
|
||||
tar -C .. -cvf dist.tar.gz dist/
|
||||
|
||||
- name: Upload artifact
|
||||
- name: Upload build-linux artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: build-linux-x86_64-intermediate
|
||||
path: release/work/build-linux-x86_64/dist-tar/
|
||||
name: build-linux-intermediate
|
||||
path: release/work/build-linux/dist-tar/
|
||||
|
||||
build-win32:
|
||||
runs-on: ubuntu-latest
|
||||
@ -129,6 +122,7 @@ jobs:
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt install -y meson ninja-build nasm ffmpeg libsdl2-2.0-0 \
|
||||
libsdl2-dev libavcodec-dev libavdevice-dev libavformat-dev \
|
||||
libavutil-dev libswresample-dev libusb-1.0-0 libusb-1.0-0-dev \
|
||||
@ -137,7 +131,7 @@ jobs:
|
||||
- name: Workaround for old meson version run by Github Actions
|
||||
run: sed -i 's/^pkg-config/pkgconfig/' cross_win32.txt
|
||||
|
||||
- name: Build
|
||||
- name: Build win32
|
||||
run: release/build_windows.sh 32
|
||||
|
||||
# upload-artifact does not preserve permissions
|
||||
@ -148,7 +142,7 @@ jobs:
|
||||
cd dist-tar
|
||||
tar -C .. -cvf dist.tar.gz dist/
|
||||
|
||||
- name: Upload artifact
|
||||
- name: Upload build-win32 artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: build-win32-intermediate
|
||||
@ -162,6 +156,7 @@ jobs:
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt install -y meson ninja-build nasm ffmpeg libsdl2-2.0-0 \
|
||||
libsdl2-dev libavcodec-dev libavdevice-dev libavformat-dev \
|
||||
libavutil-dev libswresample-dev libusb-1.0-0 libusb-1.0-0-dev \
|
||||
@ -170,7 +165,7 @@ jobs:
|
||||
- name: Workaround for old meson version run by Github Actions
|
||||
run: sed -i 's/^pkg-config/pkgconfig/' cross_win64.txt
|
||||
|
||||
- name: Build
|
||||
- name: Build win64
|
||||
run: release/build_windows.sh 64
|
||||
|
||||
# upload-artifact does not preserve permissions
|
||||
@ -181,24 +176,15 @@ jobs:
|
||||
cd dist-tar
|
||||
tar -C .. -cvf dist.tar.gz dist/
|
||||
|
||||
- name: Upload artifact
|
||||
- name: Upload build-win64 artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: build-win64-intermediate
|
||||
path: release/work/build-win64/dist-tar/
|
||||
|
||||
build-macos-aarch64:
|
||||
build-macos:
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- name: Check architecture
|
||||
run: |
|
||||
arch=$(uname -m)
|
||||
if [[ "$arch" != arm64 ]]
|
||||
then
|
||||
echo "Unexpected architecture: $arch" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
@ -207,63 +193,27 @@ jobs:
|
||||
brew install meson ninja nasm libiconv zlib automake autoconf \
|
||||
libtool
|
||||
|
||||
- name: Build
|
||||
run: release/build_macos.sh aarch64
|
||||
- name: Build macOS
|
||||
run: release/build_macos.sh
|
||||
|
||||
# upload-artifact does not preserve permissions
|
||||
- name: Tar
|
||||
run: |
|
||||
cd release/work/build-macos-aarch64
|
||||
cd release/work/build-macos
|
||||
mkdir dist-tar
|
||||
cd dist-tar
|
||||
tar -C .. -cvf dist.tar.gz dist/
|
||||
|
||||
- name: Upload artifact
|
||||
- name: Upload build-macos artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: build-macos-aarch64-intermediate
|
||||
path: release/work/build-macos-aarch64/dist-tar/
|
||||
name: build-macos-intermediate
|
||||
path: release/work/build-macos/dist-tar/
|
||||
|
||||
build-macos-x86_64:
|
||||
runs-on: macos-13
|
||||
steps:
|
||||
- name: Check architecture
|
||||
run: |
|
||||
arch=$(uname -m)
|
||||
if [[ "$arch" != x86_64 ]]
|
||||
then
|
||||
echo "Unexpected architecture: $arch" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install dependencies
|
||||
run: brew install meson ninja nasm libiconv zlib automake
|
||||
# autoconf and libtool are already installed on macos-13
|
||||
|
||||
- name: Build
|
||||
run: release/build_macos.sh x86_64
|
||||
|
||||
# upload-artifact does not preserve permissions
|
||||
- name: Tar
|
||||
run: |
|
||||
cd release/work/build-macos-x86_64
|
||||
mkdir dist-tar
|
||||
cd dist-tar
|
||||
tar -C .. -cvf dist.tar.gz dist/
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: build-macos-x86_64-intermediate
|
||||
path: release/work/build-macos-x86_64/dist-tar/
|
||||
|
||||
package-linux-x86_64:
|
||||
package-linux:
|
||||
needs:
|
||||
- build-scrcpy-server
|
||||
- build-linux-x86_64
|
||||
- build-linux
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
@ -275,25 +225,25 @@ jobs:
|
||||
name: scrcpy-server
|
||||
path: release/work/build-server/server/
|
||||
|
||||
- name: Download build-linux-x86_64
|
||||
- name: Download build-linux
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: build-linux-x86_64-intermediate
|
||||
path: release/work/build-linux-x86_64/dist-tar/
|
||||
name: build-linux-intermediate
|
||||
path: release/work/build-linux/dist-tar/
|
||||
|
||||
# upload-artifact does not preserve permissions
|
||||
- name: Detar
|
||||
run: |
|
||||
cd release/work/build-linux-x86_64
|
||||
cd release/work/build-linux
|
||||
tar xf dist-tar/dist.tar.gz
|
||||
|
||||
- name: Package
|
||||
run: release/package_client.sh linux-x86_64 tar.gz
|
||||
- name: Package linux
|
||||
run: release/package_client.sh linux tar.gz
|
||||
|
||||
- name: Upload release
|
||||
- name: Upload linux release
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: release-linux-x86_64
|
||||
name: release-linux
|
||||
path: release/output/
|
||||
|
||||
package-win32:
|
||||
@ -323,10 +273,10 @@ jobs:
|
||||
cd release/work/build-win32
|
||||
tar xf dist-tar/dist.tar.gz
|
||||
|
||||
- name: Package
|
||||
- name: Package win32
|
||||
run: release/package_client.sh win32 zip
|
||||
|
||||
- name: Upload release
|
||||
- name: Upload win32 release
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: release-win32
|
||||
@ -359,55 +309,19 @@ jobs:
|
||||
cd release/work/build-win64
|
||||
tar xf dist-tar/dist.tar.gz
|
||||
|
||||
- name: Package
|
||||
- name: Package win64
|
||||
run: release/package_client.sh win64 zip
|
||||
|
||||
- name: Upload release
|
||||
- name: Upload win64 release
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: release-win64
|
||||
path: release/output
|
||||
|
||||
package-macos-aarch64:
|
||||
package-macos:
|
||||
needs:
|
||||
- build-scrcpy-server
|
||||
- build-macos-aarch64
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Download scrcpy-server
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: scrcpy-server
|
||||
path: release/work/build-server/server/
|
||||
|
||||
- name: Download build-macos-aarch64
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: build-macos-aarch64-intermediate
|
||||
path: release/work/build-macos-aarch64/dist-tar/
|
||||
|
||||
# upload-artifact does not preserve permissions
|
||||
- name: Detar
|
||||
run: |
|
||||
cd release/work/build-macos-aarch64
|
||||
tar xf dist-tar/dist.tar.gz
|
||||
|
||||
- name: Package
|
||||
run: release/package_client.sh macos-aarch64 tar.gz
|
||||
|
||||
- name: Upload release
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: release-macos-aarch64
|
||||
path: release/output/
|
||||
|
||||
package-macos-x86_64:
|
||||
needs:
|
||||
- build-scrcpy-server
|
||||
- build-macos-x86_64
|
||||
- build-macos
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
@ -422,32 +336,31 @@ jobs:
|
||||
- name: Download build-macos
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: build-macos-x86_64-intermediate
|
||||
path: release/work/build-macos-x86_64/dist-tar/
|
||||
name: build-macos-intermediate
|
||||
path: release/work/build-macos/dist-tar/
|
||||
|
||||
# upload-artifact does not preserve permissions
|
||||
- name: Detar
|
||||
run: |
|
||||
cd release/work/build-macos-x86_64
|
||||
cd release/work/build-macos
|
||||
tar xf dist-tar/dist.tar.gz
|
||||
|
||||
- name: Package
|
||||
run: release/package_client.sh macos-x86_64 tar.gz
|
||||
- name: Package macos
|
||||
run: release/package_client.sh macos tar.gz
|
||||
|
||||
- name: Upload release
|
||||
- name: Upload macos release
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: release-macos-x86_64
|
||||
name: release-macos
|
||||
path: release/output/
|
||||
|
||||
release:
|
||||
needs:
|
||||
- build-scrcpy-server
|
||||
- package-linux-x86_64
|
||||
- package-linux
|
||||
- package-win32
|
||||
- package-win64
|
||||
- package-macos-aarch64
|
||||
- package-macos-x86_64
|
||||
- package-macos
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
@ -459,10 +372,10 @@ jobs:
|
||||
name: scrcpy-server
|
||||
path: release/work/build-server/server/
|
||||
|
||||
- name: Download release-linux-x86_64
|
||||
- name: Download release-linux
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: release-linux-x86_64
|
||||
name: release-linux
|
||||
path: release/output/
|
||||
|
||||
- name: Download release-win32
|
||||
@ -477,16 +390,10 @@ jobs:
|
||||
name: release-win64
|
||||
path: release/output/
|
||||
|
||||
- name: Download release-macos-aarch64
|
||||
- name: Download release-macos
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: release-macos-aarch64
|
||||
path: release/output/
|
||||
|
||||
- name: Download release-macos-x86_64
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: release-macos-x86_64
|
||||
name: release-macos
|
||||
path: release/output/
|
||||
|
||||
- name: Package server
|
||||
|
6
app/data/scrcpy_static_wrapper.sh
Executable file
6
app/data/scrcpy_static_wrapper.sh
Executable file
@ -0,0 +1,6 @@
|
||||
#!/bin/bash
|
||||
cd "$(dirname ${BASH_SOURCE[0]})"
|
||||
export ADB="${ADB:-./adb}"
|
||||
export SCRCPY_SERVER_PATH="${SCRCPY_SERVER_PATH:-./scrcpy-server}"
|
||||
export SCRCPY_ICON_PATH="${SCRCPY_ICON_PATH:-./icon.png}"
|
||||
./scrcpy_bin "$@"
|
@ -46,7 +46,6 @@ src = [
|
||||
'src/util/acksync.c',
|
||||
'src/util/audiobuf.c',
|
||||
'src/util/average.c',
|
||||
'src/util/env.c',
|
||||
'src/util/file.c',
|
||||
'src/util/intmap.c',
|
||||
'src/util/intr.c',
|
||||
|
@ -7,7 +7,6 @@
|
||||
|
||||
#include "adb_device.h"
|
||||
#include "adb_parser.h"
|
||||
#include "util/env.h"
|
||||
#include "util/file.h"
|
||||
#include "util/log.h"
|
||||
#include "util/process_intr.h"
|
||||
@ -25,45 +24,15 @@
|
||||
*/
|
||||
#define SC_ADB_COMMAND(...) { sc_adb_get_executable(), __VA_ARGS__, NULL }
|
||||
|
||||
static char *adb_executable;
|
||||
|
||||
bool
|
||||
sc_adb_init(void) {
|
||||
adb_executable = sc_get_env("ADB");
|
||||
if (adb_executable) {
|
||||
LOGD("Using adb: %s", adb_executable);
|
||||
return true;
|
||||
}
|
||||
|
||||
#if !defined(PORTABLE) || defined(_WIN32)
|
||||
adb_executable = strdup("adb");
|
||||
if (!adb_executable) {
|
||||
LOG_OOM();
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
// For portable builds, use the absolute path to the adb executable
|
||||
// in the same directory as scrcpy (except on Windows, where "adb"
|
||||
// is sufficient)
|
||||
adb_executable = sc_file_get_local_path("adb");
|
||||
if (!adb_executable) {
|
||||
// Error already logged
|
||||
return false;
|
||||
}
|
||||
|
||||
LOGD("Using adb (portable): %s", adb_executable);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
sc_adb_destroy(void) {
|
||||
free(adb_executable);
|
||||
}
|
||||
static const char *adb_executable;
|
||||
|
||||
const char *
|
||||
sc_adb_get_executable(void) {
|
||||
if (!adb_executable) {
|
||||
adb_executable = getenv("ADB");
|
||||
if (!adb_executable)
|
||||
adb_executable = "adb";
|
||||
}
|
||||
return adb_executable;
|
||||
}
|
||||
|
||||
|
@ -15,12 +15,6 @@
|
||||
|
||||
#define SC_ADB_SILENT (SC_ADB_NO_STDOUT | SC_ADB_NO_STDERR | SC_ADB_NO_LOGERR)
|
||||
|
||||
bool
|
||||
sc_adb_init(void);
|
||||
|
||||
void
|
||||
sc_adb_destroy(void);
|
||||
|
||||
const char *
|
||||
sc_adb_get_executable(void);
|
||||
|
||||
|
@ -9,7 +9,6 @@
|
||||
|
||||
#include "config.h"
|
||||
#include "compat.h"
|
||||
#include "util/env.h"
|
||||
#include "util/file.h"
|
||||
#include "util/log.h"
|
||||
#include "util/str.h"
|
||||
@ -20,22 +19,35 @@
|
||||
|
||||
static char *
|
||||
get_icon_path(void) {
|
||||
char *icon_path = sc_get_env("SCRCPY_ICON_PATH");
|
||||
if (icon_path) {
|
||||
#ifdef __WINDOWS__
|
||||
const wchar_t *icon_path_env = _wgetenv(L"SCRCPY_ICON_PATH");
|
||||
#else
|
||||
const char *icon_path_env = getenv("SCRCPY_ICON_PATH");
|
||||
#endif
|
||||
if (icon_path_env) {
|
||||
// if the envvar is set, use it
|
||||
#ifdef __WINDOWS__
|
||||
char *icon_path = sc_str_from_wchars(icon_path_env);
|
||||
#else
|
||||
char *icon_path = strdup(icon_path_env);
|
||||
#endif
|
||||
if (!icon_path) {
|
||||
LOG_OOM();
|
||||
return NULL;
|
||||
}
|
||||
LOGD("Using SCRCPY_ICON_PATH: %s", icon_path);
|
||||
return icon_path;
|
||||
}
|
||||
|
||||
#ifndef PORTABLE
|
||||
LOGD("Using icon: " SCRCPY_DEFAULT_ICON_PATH);
|
||||
icon_path = strdup(SCRCPY_DEFAULT_ICON_PATH);
|
||||
char *icon_path = strdup(SCRCPY_DEFAULT_ICON_PATH);
|
||||
if (!icon_path) {
|
||||
LOG_OOM();
|
||||
return NULL;
|
||||
}
|
||||
#else
|
||||
icon_path = sc_file_get_local_path(SCRCPY_PORTABLE_ICON_FILENAME);
|
||||
char *icon_path = sc_file_get_local_path(SCRCPY_PORTABLE_ICON_FILENAME);
|
||||
if (!icon_path) {
|
||||
LOGE("Could not get icon path");
|
||||
return NULL;
|
||||
|
@ -9,7 +9,6 @@
|
||||
|
||||
#include "adb/adb.h"
|
||||
#include "util/binary.h"
|
||||
#include "util/env.h"
|
||||
#include "util/file.h"
|
||||
#include "util/log.h"
|
||||
#include "util/net_intr.h"
|
||||
@ -26,22 +25,35 @@
|
||||
|
||||
static char *
|
||||
get_server_path(void) {
|
||||
char *server_path = sc_get_env("SCRCPY_SERVER_PATH");
|
||||
if (server_path) {
|
||||
#ifdef __WINDOWS__
|
||||
const wchar_t *server_path_env = _wgetenv(L"SCRCPY_SERVER_PATH");
|
||||
#else
|
||||
const char *server_path_env = getenv("SCRCPY_SERVER_PATH");
|
||||
#endif
|
||||
if (server_path_env) {
|
||||
// if the envvar is set, use it
|
||||
#ifdef __WINDOWS__
|
||||
char *server_path = sc_str_from_wchars(server_path_env);
|
||||
#else
|
||||
char *server_path = strdup(server_path_env);
|
||||
#endif
|
||||
if (!server_path) {
|
||||
LOG_OOM();
|
||||
return NULL;
|
||||
}
|
||||
LOGD("Using SCRCPY_SERVER_PATH: %s", server_path);
|
||||
return server_path;
|
||||
}
|
||||
|
||||
#ifndef PORTABLE
|
||||
LOGD("Using server: " SC_SERVER_PATH_DEFAULT);
|
||||
server_path = strdup(SC_SERVER_PATH_DEFAULT);
|
||||
char *server_path = strdup(SC_SERVER_PATH_DEFAULT);
|
||||
if (!server_path) {
|
||||
LOG_OOM();
|
||||
return NULL;
|
||||
}
|
||||
#else
|
||||
server_path = sc_file_get_local_path(SC_SERVER_FILENAME);
|
||||
char *server_path = sc_file_get_local_path(SC_SERVER_FILENAME);
|
||||
if (!server_path) {
|
||||
LOGE("Could not get local file path, "
|
||||
"using " SC_SERVER_FILENAME " from current directory");
|
||||
@ -485,21 +497,14 @@ sc_server_init(struct sc_server *server, const struct sc_server_params *params,
|
||||
// end of the program
|
||||
server->params = *params;
|
||||
|
||||
bool ok = sc_adb_init();
|
||||
bool ok = sc_mutex_init(&server->mutex);
|
||||
if (!ok) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ok = sc_mutex_init(&server->mutex);
|
||||
if (!ok) {
|
||||
sc_adb_destroy();
|
||||
return false;
|
||||
}
|
||||
|
||||
ok = sc_cond_init(&server->cond_stopped);
|
||||
if (!ok) {
|
||||
sc_mutex_destroy(&server->mutex);
|
||||
sc_adb_destroy();
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -507,7 +512,6 @@ sc_server_init(struct sc_server *server, const struct sc_server_params *params,
|
||||
if (!ok) {
|
||||
sc_cond_destroy(&server->cond_stopped);
|
||||
sc_mutex_destroy(&server->mutex);
|
||||
sc_adb_destroy();
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1149,6 +1153,4 @@ sc_server_destroy(struct sc_server *server) {
|
||||
sc_intr_destroy(&server->intr);
|
||||
sc_cond_destroy(&server->cond_stopped);
|
||||
sc_mutex_destroy(&server->mutex);
|
||||
|
||||
sc_adb_destroy();
|
||||
}
|
||||
|
@ -6,9 +6,6 @@
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#ifdef __APPLE__
|
||||
# include <mach-o/dyld.h> // for _NSGetExecutablePath()
|
||||
#endif
|
||||
|
||||
#include "util/log.h"
|
||||
|
||||
@ -63,22 +60,11 @@ sc_file_get_executable_path(void) {
|
||||
}
|
||||
buf[len] = '\0';
|
||||
return strdup(buf);
|
||||
#elif defined(__APPLE__)
|
||||
char buf[PATH_MAX];
|
||||
uint32_t bufsize = PATH_MAX;
|
||||
if (_NSGetExecutablePath(buf, &bufsize) != 0) {
|
||||
LOGE("Executable path buffer too small; need %u bytes", bufsize);
|
||||
return NULL;
|
||||
}
|
||||
return realpath(buf, NULL);
|
||||
#else
|
||||
// "_" is often used to store the full path of the command being executed
|
||||
char *path = getenv("_");
|
||||
if (!path) {
|
||||
LOGE("Could not determine executable path");
|
||||
return NULL;
|
||||
}
|
||||
return strdup(path);
|
||||
// in practice, we only need this feature for portable builds, only used on
|
||||
// Windows, so we don't care implementing it for every platform
|
||||
// (it's useful to have a working version on Linux for debugging though)
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -95,14 +95,9 @@ scrcpy_otg(struct scrcpy_options *options) {
|
||||
// On Windows, only one process could open a USB device
|
||||
// <https://github.com/Genymobile/scrcpy/issues/2773>
|
||||
LOGI("Killing adb server (if any)...");
|
||||
if (sc_adb_init()) {
|
||||
unsigned flags = SC_ADB_NO_STDOUT | SC_ADB_NO_STDERR | SC_ADB_NO_LOGERR;
|
||||
// uninterruptible (intr == NULL), but in practice it's very quick
|
||||
sc_adb_kill_server(NULL, flags);
|
||||
sc_adb_destroy();
|
||||
} else {
|
||||
LOGW("Could not call adb executable, adb server not killed");
|
||||
}
|
||||
unsigned flags = SC_ADB_NO_STDOUT | SC_ADB_NO_STDERR | SC_ADB_NO_LOGERR;
|
||||
// uninterruptible (intr == NULL), but in practice it's very quick
|
||||
sc_adb_kill_server(NULL, flags);
|
||||
#endif
|
||||
|
||||
static const struct sc_usb_callbacks cbs = {
|
||||
|
@ -1,29 +0,0 @@
|
||||
#include "env.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "util/str.h"
|
||||
|
||||
char *
|
||||
sc_get_env(const char *varname) {
|
||||
#ifdef _WIN32
|
||||
wchar_t *w_varname = sc_str_to_wchars(varname);
|
||||
if (!w_varname) {
|
||||
return NULL;
|
||||
}
|
||||
const wchar_t *value = _wgetenv(w_varname);
|
||||
free(w_varname);
|
||||
if (!value) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return sc_str_from_wchars(value);
|
||||
#else
|
||||
const char *value = getenv(varname);
|
||||
if (!value) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return strdup(value);
|
||||
#endif
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
#ifndef SC_ENV_H
|
||||
#define SC_ENV_H
|
||||
|
||||
#include "common.h"
|
||||
|
||||
// Return the value of the environment variable (may be NULL).
|
||||
//
|
||||
// The returned value must be freed by the caller.
|
||||
char *
|
||||
sc_get_env(const char *varname);
|
||||
|
||||
#endif
|
@ -12,6 +12,7 @@
|
||||
# define SC_RAW_SOCKET_NONE INVALID_SOCKET
|
||||
#else // not _WIN32
|
||||
# include <sys/socket.h>
|
||||
# define SC_SOCKET_NONE -1
|
||||
typedef int sc_raw_socket;
|
||||
# define SC_RAW_SOCKET_NONE -1
|
||||
#endif
|
||||
|
@ -15,10 +15,8 @@ scrcpy --new-display=/240 # use the main display size and 240 dpi
|
||||
|
||||
On some devices, a launcher is available in the virtual display.
|
||||
|
||||
When no launcher is available (or if is explicitly disabled by
|
||||
[`--no-vd-system-decorations`](#system-decorations)), the virtual display is
|
||||
empty. In that case, you must [start an Android
|
||||
app](device.md#start-android-app).
|
||||
When no launcher is available, the virtual display is empty. In that case, you
|
||||
must [start an Android app](device.md#start-android-app).
|
||||
|
||||
For example:
|
||||
|
||||
@ -26,27 +24,12 @@ For example:
|
||||
scrcpy --new-display=1920x1080 --start-app=org.videolan.vlc
|
||||
```
|
||||
|
||||
The app may itself be a launcher. For example, to run the open source [Fossify
|
||||
Launcher]:
|
||||
|
||||
```bash
|
||||
scrcpy --new-display=1920x1080 --no-vd-system-decorations --start-app=org.fossify.home
|
||||
```
|
||||
|
||||
[Fossify Launcher]: https://f-droid.org/en/packages/org.fossify.home/
|
||||
|
||||
|
||||
## System decorations
|
||||
|
||||
By default, virtual display system decorations are enabled. To disable them, use
|
||||
`--no-vd-system-decorations`:
|
||||
By default, virtual display system decorations are enabled. But some devices
|
||||
might display a broken UI;
|
||||
|
||||
```
|
||||
scrcpy --new-display --no-vd-system-decorations
|
||||
```
|
||||
|
||||
This is useful for some devices which might display a broken UI, or to disable
|
||||
any default launcher UI available in virtual displays.
|
||||
Use `--no-vd-system-decorations` to disable it.
|
||||
|
||||
Note that if no app is started, no content will be rendered, so no video frame
|
||||
will be produced at all.
|
||||
|
@ -4,14 +4,7 @@ cd "$(dirname ${BASH_SOURCE[0]})"
|
||||
. build_common
|
||||
cd .. # root project dir
|
||||
|
||||
if [[ $# != 1 ]]
|
||||
then
|
||||
echo "Syntax: $0 <arch>" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
ARCH="$1"
|
||||
LINUX_BUILD_DIR="$WORK_DIR/build-linux-$ARCH"
|
||||
LINUX_BUILD_DIR="$WORK_DIR/build-linux"
|
||||
|
||||
app/deps/adb_linux.sh
|
||||
app/deps/sdl.sh linux native static
|
||||
@ -36,7 +29,8 @@ ninja -C "$LINUX_BUILD_DIR"
|
||||
|
||||
# Group intermediate outputs into a 'dist' directory
|
||||
mkdir -p "$LINUX_BUILD_DIR/dist"
|
||||
cp "$LINUX_BUILD_DIR"/app/scrcpy "$LINUX_BUILD_DIR/dist/"
|
||||
cp "$LINUX_BUILD_DIR"/app/scrcpy "$LINUX_BUILD_DIR/dist/scrcpy_bin"
|
||||
cp app/data/icon.png "$LINUX_BUILD_DIR/dist/"
|
||||
cp app/data/scrcpy_static_wrapper.sh "$LINUX_BUILD_DIR/dist/scrcpy"
|
||||
cp app/scrcpy.1 "$LINUX_BUILD_DIR/dist/"
|
||||
cp -r "$ADB_INSTALL_DIR"/. "$LINUX_BUILD_DIR/dist/"
|
||||
|
@ -4,14 +4,7 @@ cd "$(dirname ${BASH_SOURCE[0]})"
|
||||
. build_common
|
||||
cd .. # root project dir
|
||||
|
||||
if [[ $# != 1 ]]
|
||||
then
|
||||
echo "Syntax: $0 <arch>" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
ARCH="$1"
|
||||
MACOS_BUILD_DIR="$WORK_DIR/build-macos-$ARCH"
|
||||
MACOS_BUILD_DIR="$WORK_DIR/build-macos"
|
||||
|
||||
app/deps/adb_macos.sh
|
||||
app/deps/sdl.sh macos native static
|
||||
@ -36,7 +29,8 @@ ninja -C "$MACOS_BUILD_DIR"
|
||||
|
||||
# Group intermediate outputs into a 'dist' directory
|
||||
mkdir -p "$MACOS_BUILD_DIR/dist"
|
||||
cp "$MACOS_BUILD_DIR"/app/scrcpy "$MACOS_BUILD_DIR/dist/"
|
||||
cp "$MACOS_BUILD_DIR"/app/scrcpy "$MACOS_BUILD_DIR/dist/scrcpy_bin"
|
||||
cp app/data/icon.png "$MACOS_BUILD_DIR/dist/"
|
||||
cp app/data/scrcpy_static_wrapper.sh "$MACOS_BUILD_DIR/dist/scrcpy"
|
||||
cp app/scrcpy.1 "$MACOS_BUILD_DIR/dist/"
|
||||
cp -r "$ADB_INSTALL_DIR"/. "$MACOS_BUILD_DIR/dist/"
|
||||
|
@ -5,10 +5,9 @@ cd "$(dirname ${BASH_SOURCE[0]})"
|
||||
|
||||
cd "$OUTPUT_DIR"
|
||||
sha256sum "scrcpy-server-$VERSION" \
|
||||
"scrcpy-linux-x86_64-$VERSION.tar.gz" \
|
||||
"scrcpy-linux-$VERSION.tar.gz" \
|
||||
"scrcpy-win32-$VERSION.zip" \
|
||||
"scrcpy-win64-$VERSION.zip" \
|
||||
"scrcpy-macos-aarch64-$VERSION.tar.gz" \
|
||||
"scrcpy-macos-x86_64-$VERSION.tar.gz" \
|
||||
"scrcpy-macos-$VERSION.tar.gz" \
|
||||
| tee SHA256SUMS.txt
|
||||
echo "Release checksums generated in $PWD/SHA256SUMS.txt"
|
||||
|
@ -14,39 +14,39 @@ fi
|
||||
|
||||
FORMAT=$2
|
||||
|
||||
if [[ "$FORMAT" != zip && "$FORMAT" != tar.gz ]]
|
||||
if [[ "$2" != zip && "$2" != tar.gz ]]
|
||||
then
|
||||
echo "Invalid format (expected zip or tar.gz): $FORMAT" >&2
|
||||
echo "Invalid format (expected zip or tar.gz): $2" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
BUILD_DIR="$WORK_DIR/build-$1"
|
||||
ARCHIVE_DIR="$BUILD_DIR/release-archive"
|
||||
TARGET_DIRNAME="scrcpy-$1-$VERSION"
|
||||
TARGET="scrcpy-$1-$VERSION"
|
||||
|
||||
rm -rf "$ARCHIVE_DIR/$TARGET_DIRNAME"
|
||||
mkdir -p "$ARCHIVE_DIR/$TARGET_DIRNAME"
|
||||
rm -rf "$ARCHIVE_DIR/$TARGET"
|
||||
mkdir -p "$ARCHIVE_DIR/$TARGET"
|
||||
|
||||
cp -r "$BUILD_DIR/dist/." "$ARCHIVE_DIR/$TARGET_DIRNAME/"
|
||||
cp "$WORK_DIR/build-server/server/scrcpy-server" "$ARCHIVE_DIR/$TARGET_DIRNAME/"
|
||||
cp -r "$BUILD_DIR/dist/." "$ARCHIVE_DIR/$TARGET/"
|
||||
cp "$WORK_DIR/build-server/server/scrcpy-server" "$ARCHIVE_DIR/$TARGET/"
|
||||
|
||||
mkdir -p "$OUTPUT_DIR"
|
||||
|
||||
cd "$ARCHIVE_DIR"
|
||||
rm -f "$OUTPUT_DIR/$TARGET_DIRNAME.$FORMAT"
|
||||
rm -f "$OUTPUT_DIR/$TARGET.$FORMAT"
|
||||
|
||||
case "$FORMAT" in
|
||||
zip)
|
||||
zip -r "$OUTPUT_DIR/$TARGET_DIRNAME.zip" "$TARGET_DIRNAME"
|
||||
zip -r "$OUTPUT_DIR/$TARGET.zip" "$TARGET"
|
||||
;;
|
||||
tar.gz)
|
||||
tar cvzf "$OUTPUT_DIR/$TARGET_DIRNAME.tar.gz" "$TARGET_DIRNAME"
|
||||
tar cvf "$OUTPUT_DIR/$TARGET.tar.gz" "$TARGET"
|
||||
;;
|
||||
*)
|
||||
echo "Invalid format (expected zip or tar.gz): $FORMAT" >&2
|
||||
exit 1
|
||||
esac
|
||||
|
||||
rm -rf "$TARGET_DIRNAME"
|
||||
rm -rf "$TARGET"
|
||||
cd -
|
||||
echo "Generated '$OUTPUT_DIR/$TARGET_DIRNAME.$FORMAT'"
|
||||
echo "Generated '$OUTPUT_DIR/$TARGET.$FORMAT'"
|
||||
|
@ -12,12 +12,12 @@ rm -rf output
|
||||
./build_server.sh
|
||||
./build_windows.sh 32
|
||||
./build_windows.sh 64
|
||||
./build_linux.sh x86_64
|
||||
./build_linux.sh
|
||||
|
||||
./package_server.sh
|
||||
./package_client.sh win32 zip
|
||||
./package_client.sh win64 zip
|
||||
./package_client.sh linux-x86_64 tar.gz
|
||||
./package_client.sh linux tar.gz
|
||||
|
||||
./generate_checksums.sh
|
||||
|
||||
|
@ -21,7 +21,6 @@ import android.content.IOnPrimaryClipChangedListener;
|
||||
import android.content.Intent;
|
||||
import android.os.Build;
|
||||
import android.os.SystemClock;
|
||||
import android.util.Pair;
|
||||
import android.view.InputDevice;
|
||||
import android.view.KeyCharacterMap;
|
||||
import android.view.KeyEvent;
|
||||
@ -351,47 +350,24 @@ public class Controller implements AsyncProcessor, VirtualDisplayListener {
|
||||
return successCount;
|
||||
}
|
||||
|
||||
private Pair<Point, Integer> getEventPointAndDisplayId(Position position) {
|
||||
// it hides the field on purpose, to read it with atomic access
|
||||
@SuppressWarnings("checkstyle:HiddenField")
|
||||
DisplayData displayData = this.displayData.get();
|
||||
// In scrcpy, displayData should never be null (a touch event can only be generated from the client when a video frame is present).
|
||||
// However, it is possible to send events without video playback when using scrcpy-server alone (except for virtual displays).
|
||||
assert displayData != null || displayId != Device.DISPLAY_ID_NONE : "Cannot receive a positional event without a display";
|
||||
|
||||
Point point;
|
||||
int targetDisplayId;
|
||||
if (displayData != null) {
|
||||
point = displayData.positionMapper.map(position);
|
||||
if (point == null) {
|
||||
if (Ln.isEnabled(Ln.Level.VERBOSE)) {
|
||||
Size eventSize = position.getScreenSize();
|
||||
Size currentSize = displayData.positionMapper.getVideoSize();
|
||||
Ln.v("Ignore positional event generated for size " + eventSize + " (current size is " + currentSize + ")");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
targetDisplayId = displayData.virtualDisplayId;
|
||||
} else {
|
||||
// No display, use the raw coordinates
|
||||
point = position.getPoint();
|
||||
targetDisplayId = displayId;
|
||||
}
|
||||
|
||||
return Pair.create(point, targetDisplayId);
|
||||
}
|
||||
|
||||
private boolean injectTouch(int action, long pointerId, Position position, float pressure, int actionButton, int buttons) {
|
||||
long now = SystemClock.uptimeMillis();
|
||||
|
||||
Pair<Point, Integer> pair = getEventPointAndDisplayId(position);
|
||||
if (pair == null) {
|
||||
// it hides the field on purpose, to read it with atomic access
|
||||
@SuppressWarnings("checkstyle:HiddenField")
|
||||
DisplayData displayData = this.displayData.get();
|
||||
assert displayData != null : "Cannot receive a touch event without a display";
|
||||
|
||||
Point point = displayData.positionMapper.map(position);
|
||||
if (point == null) {
|
||||
if (Ln.isEnabled(Ln.Level.VERBOSE)) {
|
||||
Size eventSize = position.getScreenSize();
|
||||
Size currentSize = displayData.positionMapper.getVideoSize();
|
||||
Ln.v("Ignore touch event generated for size " + eventSize + " (current size is " + currentSize + ")");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Point point = pair.first;
|
||||
int targetDisplayId = pair.second;
|
||||
|
||||
int pointerIndex = pointersState.getPointerIndex(pointerId);
|
||||
if (pointerIndex == -1) {
|
||||
Ln.w("Too many pointers for touch event");
|
||||
@ -445,7 +421,7 @@ public class Controller implements AsyncProcessor, VirtualDisplayListener {
|
||||
// First button pressed: ACTION_DOWN
|
||||
MotionEvent downEvent = MotionEvent.obtain(lastTouchDown, now, MotionEvent.ACTION_DOWN, pointerCount, pointerProperties,
|
||||
pointerCoords, 0, buttons, 1f, 1f, DEFAULT_DEVICE_ID, 0, source, 0);
|
||||
if (!Device.injectEvent(downEvent, targetDisplayId, Device.INJECT_MODE_ASYNC)) {
|
||||
if (!Device.injectEvent(downEvent, displayData.virtualDisplayId, Device.INJECT_MODE_ASYNC)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -456,7 +432,7 @@ public class Controller implements AsyncProcessor, VirtualDisplayListener {
|
||||
if (!InputManager.setActionButton(pressEvent, actionButton)) {
|
||||
return false;
|
||||
}
|
||||
if (!Device.injectEvent(pressEvent, targetDisplayId, Device.INJECT_MODE_ASYNC)) {
|
||||
if (!Device.injectEvent(pressEvent, displayData.virtualDisplayId, Device.INJECT_MODE_ASYNC)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -470,7 +446,7 @@ public class Controller implements AsyncProcessor, VirtualDisplayListener {
|
||||
if (!InputManager.setActionButton(releaseEvent, actionButton)) {
|
||||
return false;
|
||||
}
|
||||
if (!Device.injectEvent(releaseEvent, targetDisplayId, Device.INJECT_MODE_ASYNC)) {
|
||||
if (!Device.injectEvent(releaseEvent, displayData.virtualDisplayId, Device.INJECT_MODE_ASYNC)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -478,7 +454,7 @@ public class Controller implements AsyncProcessor, VirtualDisplayListener {
|
||||
// Last button released: ACTION_UP
|
||||
MotionEvent upEvent = MotionEvent.obtain(lastTouchDown, now, MotionEvent.ACTION_UP, pointerCount, pointerProperties,
|
||||
pointerCoords, 0, buttons, 1f, 1f, DEFAULT_DEVICE_ID, 0, source, 0);
|
||||
if (!Device.injectEvent(upEvent, targetDisplayId, Device.INJECT_MODE_ASYNC)) {
|
||||
if (!Device.injectEvent(upEvent, displayData.virtualDisplayId, Device.INJECT_MODE_ASYNC)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -489,20 +465,27 @@ public class Controller implements AsyncProcessor, VirtualDisplayListener {
|
||||
|
||||
MotionEvent event = MotionEvent.obtain(lastTouchDown, now, action, pointerCount, pointerProperties, pointerCoords, 0, buttons, 1f, 1f,
|
||||
DEFAULT_DEVICE_ID, 0, source, 0);
|
||||
return Device.injectEvent(event, targetDisplayId, Device.INJECT_MODE_ASYNC);
|
||||
return Device.injectEvent(event, displayData.virtualDisplayId, Device.INJECT_MODE_ASYNC);
|
||||
}
|
||||
|
||||
private boolean injectScroll(Position position, float hScroll, float vScroll, int buttons) {
|
||||
long now = SystemClock.uptimeMillis();
|
||||
|
||||
Pair<Point, Integer> pair = getEventPointAndDisplayId(position);
|
||||
if (pair == null) {
|
||||
// it hides the field on purpose, to read it with atomic access
|
||||
@SuppressWarnings("checkstyle:HiddenField")
|
||||
DisplayData displayData = this.displayData.get();
|
||||
assert displayData != null : "Cannot receive a scroll event without a display";
|
||||
|
||||
Point point = displayData.positionMapper.map(position);
|
||||
if (point == null) {
|
||||
if (Ln.isEnabled(Ln.Level.VERBOSE)) {
|
||||
Size eventSize = position.getScreenSize();
|
||||
Size currentSize = displayData.positionMapper.getVideoSize();
|
||||
Ln.v("Ignore scroll event generated for size " + eventSize + " (current size is " + currentSize + ")");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Point point = pair.first;
|
||||
int targetDisplayId = pair.second;
|
||||
|
||||
MotionEvent.PointerProperties props = pointerProperties[0];
|
||||
props.id = 0;
|
||||
|
||||
@ -514,7 +497,7 @@ public class Controller implements AsyncProcessor, VirtualDisplayListener {
|
||||
|
||||
MotionEvent event = MotionEvent.obtain(lastTouchDown, now, MotionEvent.ACTION_SCROLL, 1, pointerProperties, pointerCoords, 0, buttons, 1f, 1f,
|
||||
DEFAULT_DEVICE_ID, 0, InputDevice.SOURCE_MOUSE, 0);
|
||||
return Device.injectEvent(event, targetDisplayId, Device.INJECT_MODE_ASYNC);
|
||||
return Device.injectEvent(event, displayData.virtualDisplayId, Device.INJECT_MODE_ASYNC);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -112,8 +112,8 @@ public class SurfaceEncoder implements AsyncProcessor {
|
||||
// The capture might have been closed internally (for example if the camera is disconnected)
|
||||
alive = !stopped.get() && !capture.isClosed();
|
||||
}
|
||||
} catch (IllegalStateException | IllegalArgumentException | IOException e) {
|
||||
Ln.e("Capture/encoding error: " + e.getClass().getName() + ": " + e.getMessage());
|
||||
} catch (IllegalStateException | IllegalArgumentException e) {
|
||||
Ln.e("Encoding error: " + e.getClass().getName() + ": " + e.getMessage());
|
||||
if (!prepareRetry(size)) {
|
||||
throw e;
|
||||
}
|
||||
|
Reference in New Issue
Block a user