mirror of
https://github.com/Toastconcern/FrameStudio.git
synced 2026-10-29 04:02:56 +01:00
Frame Studio now builds for Windows (x64, x86, ARM64), Linux (x64, x86, ARM64)
and macOS (Apple Silicon, Intel):
- studio/platform.h with Win32 and POSIX implementations (dialogs through
tinyfiledialogs on Linux/macOS), a GLFW window beside the Win32 one, and a
platform-neutral frame pacer
- MoltenVK support in the renderer (portability enumeration) and bundled in
the macOS app
- 32-bit builds: large-address-aware, LZMA packing within a 32-bit address space
- unaligned file reads in the loaders go through loadUnaligned (no UB)
- scripts/build-studio.sh, studio/build_windows.bat [x64|x86|arm64],
cmake/llvm-mingw.cmake, and a GitHub Actions workflow building every target
Frame Home installs without Studio: frame/install-frame-home.{sh,ps1} and
"Install Frame Home.bat" (packaged as FrameHome-installer.zip).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
64 lines
2.6 KiB
C++
64 lines
2.6 KiB
C++
#pragma once
|
|
// Running copies of a Frame program, for the installers. SteamVR's own bookkeeping (GetApplicationProcessId) loses
|
|
// track of an app once a utility process started from the same binary has connected, so look at /proc instead.
|
|
#include <signal.h>
|
|
#include <unistd.h>
|
|
|
|
#include <filesystem>
|
|
#include <fstream>
|
|
#include <iterator>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
// Processes named `name` running without arguments: the environment / the panel, not tools (--snapshot, --list).
|
|
inline std::vector<pid_t> runningCopies(const char* name) {
|
|
std::vector<pid_t> out;
|
|
std::error_code ec;
|
|
for (const auto& e : std::filesystem::directory_iterator("/proc", ec)) {
|
|
const std::string id = e.path().filename().string();
|
|
if (id.empty() || id.find_first_not_of("0123456789") != std::string::npos) continue;
|
|
const pid_t pid = static_cast<pid_t>(std::stol(id));
|
|
if (pid == getpid()) continue;
|
|
std::string comm;
|
|
std::getline(std::ifstream(e.path() / "comm"), comm);
|
|
if (comm != name) continue;
|
|
std::ifstream c(e.path() / "cmdline", std::ios::binary);
|
|
const std::string cmd((std::istreambuf_iterator<char>(c)), std::istreambuf_iterator<char>());
|
|
size_t args = 0;
|
|
for (char ch : cmd) args += ch == '\0';
|
|
if (args <= 1) out.push_back(pid);
|
|
}
|
|
return out;
|
|
}
|
|
|
|
// Asks them to quit, then insists after 5 s.
|
|
// Running copies of `name` (other than this process) started with `arg` among their arguments.
|
|
inline std::vector<pid_t> runningWith(const char* name, const std::string& arg) {
|
|
std::vector<pid_t> out;
|
|
std::error_code ec;
|
|
for (const auto& e : std::filesystem::directory_iterator("/proc", ec)) {
|
|
const std::string id = e.path().filename().string();
|
|
if (id.empty() || id.find_first_not_of("0123456789") != std::string::npos) continue;
|
|
const pid_t pid = static_cast<pid_t>(std::stol(id));
|
|
if (pid == getpid()) continue;
|
|
std::string comm;
|
|
std::getline(std::ifstream(e.path() / "comm"), comm);
|
|
if (comm != name) continue;
|
|
std::ifstream c(e.path() / "cmdline", std::ios::binary);
|
|
for (std::string a; std::getline(c, a, '\0');) if (a == arg) { out.push_back(pid); break; }
|
|
}
|
|
return out;
|
|
}
|
|
|
|
inline void stopCopies(const char* name) {
|
|
const std::vector<pid_t> pids = runningCopies(name);
|
|
for (pid_t p : pids) kill(p, SIGTERM);
|
|
for (int i = 0; i < 50; ++i) {
|
|
bool alive = false;
|
|
for (pid_t p : pids) alive |= kill(p, 0) == 0;
|
|
if (!alive) return;
|
|
usleep(100000);
|
|
}
|
|
for (pid_t p : pids) kill(p, SIGKILL);
|
|
}
|