Split Headless And Server Mode Code
This commit is contained in:
parent
4aeb2fd95b
commit
a762654e35
@ -3,6 +3,7 @@ cmake_minimum_required(VERSION 3.13.0)
|
||||
# Specify Options
|
||||
option(MCPI_USE_MEDIA_LAYER_PROXY "Whether To Enable The Media Layer Proxy" FALSE)
|
||||
option(MCPI_SERVER_MODE "Server Mode" FALSE)
|
||||
option(MCPI_HEADLESS_MODE "Headless Mode" ${MCPI_SERVER_MODE})
|
||||
set(MCPI_BUILD_MODE "both" CACHE STRING "\"arm\" = Build Only Code That Must Be ARM; \"native\" = Build Architecture-Independent Code; \"both\" = Build All Code As ARM")
|
||||
set_property(CACHE MCPI_BUILD_MODE PROPERTY STRINGS "both" "arm" "native")
|
||||
|
||||
@ -95,6 +96,9 @@ set(CMAKE_CXX_STANDARD 11)
|
||||
if(MCPI_SERVER_MODE)
|
||||
add_definitions(-DMCPI_SERVER_MODE)
|
||||
endif()
|
||||
if(MCPI_HEADLESS_MODE)
|
||||
add_definitions(-DMCPI_HEADLESS_MODE)
|
||||
endif()
|
||||
|
||||
# Version
|
||||
file(STRINGS VERSION VERSION)
|
||||
|
@ -8,6 +8,9 @@
|
||||
* ``MCPI_SERVER_MODE``
|
||||
* ``ON``: Enable Server Mode
|
||||
* ``OFF`` (Default): Disable Server Mode
|
||||
* ``MCPI_HEADLESS_MODE``
|
||||
* ``ON`` (Default In Server Mode): Enable Headless Mode
|
||||
* ``OFF`` (Default In Client Mode): Disable Headless Mode
|
||||
* ``MCPI_USE_MEDIA_LAYER_PROXY``
|
||||
* ``ON``: Enable The Media Layer Proxy
|
||||
* ``OFF`` (Default): Disable The Media Layer Proxy
|
||||
|
@ -7,3 +7,4 @@
|
||||
#define INFO(format, ...) { fprintf(stderr, "[INFO]: " format "\n", __VA_ARGS__); }
|
||||
#define WARN(format, ...) { fprintf(stderr, "[WARN]: " format "\n", __VA_ARGS__); }
|
||||
#define ERR(format, ...) { fprintf(stderr, "[ERR]: " format "\n", __VA_ARGS__); exit(EXIT_FAILURE); }
|
||||
#define IMPOSSIBLE() ERR("(%s:%i) This Should Never Be Called", __FILE__, __LINE__)
|
||||
|
@ -2,8 +2,8 @@ project(media-layer)
|
||||
|
||||
# Check Options
|
||||
if(MCPI_USE_MEDIA_LAYER_PROXY)
|
||||
if(MCPI_SERVER_MODE)
|
||||
message(FATAL_ERROR "Server Mode With Media Layer Proxy Configuration Is Redundant")
|
||||
if(MCPI_HEADLESS_MODE)
|
||||
message(FATAL_ERROR "Headless Mode With Media Layer Proxy Configuration Is Redundant")
|
||||
endif()
|
||||
if(MCPI_BUILD_MODE STREQUAL "both")
|
||||
message(FATAL_ERROR "Media Layer Proxy Is Redundant When Building ARM And Native Components In The Same Build")
|
||||
|
@ -18,7 +18,7 @@ endif()
|
||||
if(TARGET media-layer-core)
|
||||
# Link
|
||||
target_link_libraries(media-layer-core media-layer-headers reborn-headers pthread dl)
|
||||
if(NOT MCPI_SERVER_MODE)
|
||||
if(NOT MCPI_HEADLESS_MODE)
|
||||
# Find GLFW
|
||||
find_package(glfw3 3.3 REQUIRED)
|
||||
# Find FreeImage
|
||||
|
@ -3,17 +3,17 @@
|
||||
#include <SDL/SDL.h>
|
||||
#include <GLES/gl.h>
|
||||
|
||||
#ifndef MCPI_SERVER_MODE
|
||||
#ifndef MCPI_HEADLESS_MODE
|
||||
#define GLFW_INCLUDE_NONE
|
||||
#include <GLFW/glfw3.h>
|
||||
#endif // #ifndef MCPI_SERVER_MODE
|
||||
#endif // #ifndef MCPI_HEADLESS_MODE
|
||||
|
||||
#include <libreborn/libreborn.h>
|
||||
#include <libreborn/media-layer/core.h>
|
||||
#include <libreborn/media-layer/internal.h>
|
||||
|
||||
// GLFW Code Not Needed In Server Mode
|
||||
#ifndef MCPI_SERVER_MODE
|
||||
#ifndef MCPI_HEADLESS_MODE
|
||||
|
||||
static GLFWwindow *glfw_window;
|
||||
|
||||
@ -194,12 +194,12 @@ static void glfw_scroll(__attribute__((unused)) GLFWwindow *window, __attribute_
|
||||
}
|
||||
}
|
||||
|
||||
#endif // #ifndef MCPI_SERVER_MODE
|
||||
#endif // #ifndef MCPI_HEADLESS_MODE
|
||||
|
||||
// Init GLFW
|
||||
void SDL_WM_SetCaption(const char *title, __attribute__((unused)) const char *icon) {
|
||||
// Don't Enable GLFW In Server Mode
|
||||
#ifndef MCPI_SERVER_MODE
|
||||
#ifndef MCPI_HEADLESS_MODE
|
||||
glfwSetErrorCallback(glfw_error);
|
||||
|
||||
if (!glfwInit()) {
|
||||
@ -229,20 +229,20 @@ void SDL_WM_SetCaption(const char *title, __attribute__((unused)) const char *ic
|
||||
glfwSetScrollCallback(glfw_window, glfw_scroll);
|
||||
|
||||
glfwMakeContextCurrent(glfw_window);
|
||||
#else // #ifndef MCPI_SERVER_MODE
|
||||
#else // #ifndef MCPI_HEADLESS_MODE
|
||||
(void) title; // Mark As Used
|
||||
#endif // #ifndef MCPI_SERVER_MODE
|
||||
#endif // #ifndef MCPI_HEADLESS_MODE
|
||||
}
|
||||
|
||||
void media_swap_buffers() {
|
||||
#ifndef MCPI_SERVER_MODE
|
||||
#ifndef MCPI_HEADLESS_MODE
|
||||
// Don't Swap Buffers In A Context-Less Window
|
||||
glfwSwapBuffers(glfw_window);
|
||||
#endif // #ifndef MCPI_SERVER_MODE
|
||||
#endif // #ifndef MCPI_HEADLESS_MODE
|
||||
}
|
||||
|
||||
// Fullscreen Not Needed In Server Mode
|
||||
#ifndef MCPI_SERVER_MODE
|
||||
#ifndef MCPI_HEADLESS_MODE
|
||||
static int is_fullscreen = 0;
|
||||
|
||||
// Old Size And Position To Use When Exiting Fullscreen
|
||||
@ -271,15 +271,15 @@ void media_toggle_fullscreen() {
|
||||
}
|
||||
is_fullscreen = !is_fullscreen;
|
||||
}
|
||||
#else // #ifndef MCPI_SERVER_MODE
|
||||
#else // #ifndef MCPI_HEADLESS_MODE
|
||||
void media_toggle_fullscreen() {
|
||||
}
|
||||
#endif // #ifndef MCPI_SERVER_MODE
|
||||
#endif // #ifndef MCPI_HEADLESS_MODE
|
||||
|
||||
// Intercept SDL Events
|
||||
void _media_handle_SDL_PollEvent() {
|
||||
// GLFW Is Disabled In Server Mode
|
||||
#ifndef MCPI_SERVER_MODE
|
||||
#ifndef MCPI_HEADLESS_MODE
|
||||
// Process GLFW Events
|
||||
glfwPollEvents();
|
||||
|
||||
@ -290,16 +290,16 @@ void _media_handle_SDL_PollEvent() {
|
||||
SDL_PushEvent(&event);
|
||||
glfwSetWindowShouldClose(glfw_window, GLFW_FALSE);
|
||||
}
|
||||
#endif // #ifndef MCPI_SERVER_MODE
|
||||
#endif // #ifndef MCPI_HEADLESS_MODE
|
||||
}
|
||||
|
||||
// Terminate GLFW
|
||||
void media_cleanup() {
|
||||
// GLFW Is Disabled In Server Mode
|
||||
#ifndef MCPI_SERVER_MODE
|
||||
#ifndef MCPI_HEADLESS_MODE
|
||||
glfwDestroyWindow(glfw_window);
|
||||
glfwTerminate();
|
||||
#endif // #ifndef MCPI_SERVER_MODE
|
||||
#endif // #ifndef MCPI_HEADLESS_MODE
|
||||
}
|
||||
|
||||
// Store Cursor State
|
||||
@ -307,7 +307,7 @@ static int cursor_grabbed = 0;
|
||||
static int cursor_visible = 1;
|
||||
|
||||
// Update GLFW Cursor State (Client Only)
|
||||
#ifndef MCPI_SERVER_MODE
|
||||
#ifndef MCPI_HEADLESS_MODE
|
||||
static void update_glfw_cursor() {
|
||||
// Store Old Mode
|
||||
int old_mode = glfwGetInputMode(glfw_window, GLFW_CURSOR);
|
||||
@ -352,7 +352,7 @@ SDL_GrabMode SDL_WM_GrabInput(SDL_GrabMode mode) {
|
||||
cursor_grabbed = 0;
|
||||
}
|
||||
// Update Cursor GLFW State (Client Only)
|
||||
#ifndef MCPI_SERVER_MODE
|
||||
#ifndef MCPI_HEADLESS_MODE
|
||||
update_glfw_cursor();
|
||||
#endif
|
||||
// Return
|
||||
@ -372,7 +372,7 @@ int SDL_ShowCursor(int toggle) {
|
||||
cursor_visible = 0;
|
||||
}
|
||||
// Update Cursor GLFW State (Client Only)
|
||||
#ifndef MCPI_SERVER_MODE
|
||||
#ifndef MCPI_HEADLESS_MODE
|
||||
update_glfw_cursor();
|
||||
#endif
|
||||
// Return
|
||||
@ -381,12 +381,12 @@ int SDL_ShowCursor(int toggle) {
|
||||
|
||||
// Get Framebuffer Size
|
||||
void media_get_framebuffer_size(int *width, int *height) {
|
||||
#ifndef MCPI_SERVER_MODE
|
||||
#ifndef MCPI_HEADLESS_MODE
|
||||
if (glfw_window != NULL) {
|
||||
glfwGetFramebufferSize(glfw_window, width, height);
|
||||
return;
|
||||
}
|
||||
#endif // #ifndef MCPI_SERVER_MODE
|
||||
#endif // #ifndef MCPI_HEADLESS_MODE
|
||||
*width = DEFAULT_WIDTH;
|
||||
*height = DEFAULT_HEIGHT;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Screenshot Code Is Useless In Server Mode
|
||||
#ifndef MCPI_SERVER_MODE
|
||||
#ifndef MCPI_HEADLESS_MODE
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
@ -16,22 +16,41 @@
|
||||
#include <libreborn/libreborn.h>
|
||||
#include <libreborn/media-layer/core.h>
|
||||
|
||||
// Ensure Screenshots Folder Exists
|
||||
static void ensure_screenshots_folder(char *screenshots) {
|
||||
// Check Screenshots Folder
|
||||
struct stat obj;
|
||||
if (stat(screenshots, &obj) != 0 || !S_ISDIR(obj.st_mode)) {
|
||||
// Create Screenshots Folder
|
||||
int ret = mkdir(screenshots, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
|
||||
if (ret != 0) {
|
||||
// Unable To Create Folder
|
||||
ERR("Error Creating Directory: %s: %s", screenshots, strerror(errno));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 4 (Year) + 1 (Hyphen) + 2 (Month) + 1 (Hyphen) + 2 (Day) + 1 (Underscore) + 2 (Hour) + 1 (Period) + 2 (Minute) + 1 (Period) + 2 (Second) + 1 (Null Terminator)
|
||||
#define TIME_SIZE 20
|
||||
|
||||
// Take Screenshot
|
||||
void media_take_screenshot() {
|
||||
void media_take_screenshot(char *home) {
|
||||
// Get Directory
|
||||
char *screenshots = NULL;
|
||||
safe_asprintf(&screenshots, "%s/screenshots", home);
|
||||
|
||||
// Get Timestamp
|
||||
time_t rawtime;
|
||||
struct tm *timeinfo;
|
||||
|
||||
time(&rawtime);
|
||||
timeinfo = localtime(&rawtime);
|
||||
char time[TIME_SIZE];
|
||||
strftime(time, TIME_SIZE, "%Y-%m-%d_%H.%M.%S", timeinfo);
|
||||
|
||||
char *screenshots = NULL;
|
||||
safe_asprintf(&screenshots, "%s/.minecraft-pi/screenshots", getenv("HOME"));
|
||||
// Ensure Screenshots Folder Exists
|
||||
ensure_screenshots_folder(screenshots);
|
||||
|
||||
// Prevent Overwriting Screenshots
|
||||
int num = 1;
|
||||
char *file = NULL;
|
||||
safe_asprintf(&file, "%s/%s.png", screenshots, time);
|
||||
@ -42,6 +61,7 @@ void media_take_screenshot() {
|
||||
num++;
|
||||
}
|
||||
|
||||
// Get Image Size
|
||||
GLint viewport[4];
|
||||
glGetIntegerv(GL_VIEWPORT, viewport);
|
||||
int x = viewport[0];
|
||||
@ -49,12 +69,15 @@ void media_take_screenshot() {
|
||||
int width = viewport[2];
|
||||
int height = viewport[3];
|
||||
|
||||
// Get Line Size
|
||||
int line_size = width * 3;
|
||||
int size = height * line_size;
|
||||
|
||||
// Read Pixels
|
||||
unsigned char pixels[size];
|
||||
glReadPixels(x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, pixels);
|
||||
|
||||
// Handle Little Endian Systems
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
// Swap Red And Blue
|
||||
for (int i = 0; i < (size / 3); i++) {
|
||||
@ -66,6 +89,7 @@ void media_take_screenshot() {
|
||||
}
|
||||
#endif
|
||||
|
||||
// Save Image
|
||||
FIBITMAP *image = FreeImage_ConvertFromRawBits(pixels, width, height, line_size, 24, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK, 0);
|
||||
if (!FreeImage_Save(FIF_PNG, image, file, 0)) {
|
||||
INFO("Screenshot Failed: %s", file);
|
||||
@ -74,6 +98,7 @@ void media_take_screenshot() {
|
||||
}
|
||||
FreeImage_Unload(image);
|
||||
|
||||
// Free
|
||||
free(file);
|
||||
free(screenshots);
|
||||
}
|
||||
@ -82,27 +107,10 @@ void media_take_screenshot() {
|
||||
__attribute__((constructor)) static void init() {
|
||||
// Init FreeImage
|
||||
FreeImage_Initialise(0);
|
||||
|
||||
// Screenshots Folder
|
||||
char *screenshots_folder = NULL;
|
||||
safe_asprintf(&screenshots_folder, "%s/.minecraft-pi/screenshots", getenv("HOME"));
|
||||
{
|
||||
// Check Screenshots Folder
|
||||
struct stat obj;
|
||||
if (stat(screenshots_folder, &obj) != 0 || !S_ISDIR(obj.st_mode)) {
|
||||
// Create Screenshots Folder
|
||||
int ret = mkdir(screenshots_folder, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
|
||||
if (ret != 0) {
|
||||
// Unable To Create Folder
|
||||
ERR("Error Creating Directory: %s: %s", screenshots_folder, strerror(errno));
|
||||
}
|
||||
}
|
||||
}
|
||||
free(screenshots_folder);
|
||||
}
|
||||
|
||||
#else // #ifndef MCPI_SERVER_MODE
|
||||
#else // #ifndef MCPI_HEADLESS_MODE
|
||||
void media_take_screenshot() {
|
||||
// NOP
|
||||
}
|
||||
#endif // #ifndef MCPI_SERVER_MODE
|
||||
#endif // #ifndef MCPI_HEADLESS_MODE
|
||||
|
@ -8,7 +8,7 @@ extern "C" {
|
||||
#define DEFAULT_WIDTH 840
|
||||
#define DEFAULT_HEIGHT 480
|
||||
|
||||
void media_take_screenshot();
|
||||
void media_take_screenshot(char *home);
|
||||
void media_toggle_fullscreen();
|
||||
void media_swap_buffers();
|
||||
void media_cleanup();
|
||||
|
@ -1,9 +1,3 @@
|
||||
# Component Details:
|
||||
# Media Layer Proxy
|
||||
#
|
||||
# This components proxies multi-media calls from the ARM
|
||||
# MCPI to the native architecture by using a UNIX socket.
|
||||
|
||||
project(media-layer-proxy)
|
||||
|
||||
# Configuration
|
||||
|
@ -284,15 +284,22 @@ CALL(6, SDL_ShowCursor, int, (int32_t toggle)) {
|
||||
#endif
|
||||
}
|
||||
|
||||
CALL(7, media_take_screenshot, void, ()) {
|
||||
CALL(7, media_take_screenshot, void, (char *home)) {
|
||||
#if defined(MEDIA_LAYER_PROXY_SERVER)
|
||||
// Lock Proxy
|
||||
start_proxy_call();
|
||||
|
||||
// Arguments
|
||||
write_string(home);
|
||||
|
||||
// Release Proxy
|
||||
end_proxy_call();
|
||||
#else
|
||||
char *home = read_string();
|
||||
// Run
|
||||
media_take_screenshot();
|
||||
media_take_screenshot(home);
|
||||
// Free
|
||||
free(home);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -21,21 +21,21 @@ if(BUILD_ARM_COMPONENTS)
|
||||
target_link_libraries(X11 reborn-headers media-layer-headers)
|
||||
set_target_properties(X11 PROPERTIES SOVERSION "6")
|
||||
# Install
|
||||
if(MCPI_SERVER_MODE OR MCPI_USE_MEDIA_LAYER_PROXY)
|
||||
if(MCPI_HEADLESS_MODE OR MCPI_USE_MEDIA_LAYER_PROXY)
|
||||
install(TARGETS EGL X11 DESTINATION "${MCPI_LIB_DIR}")
|
||||
else()
|
||||
install(TARGETS EGL X11 DESTINATION "${MCPI_FALLBACK_LIB_DIR}") # Place At The End Of LD_LIBRARY_PATH
|
||||
endif()
|
||||
|
||||
# Install GLESv1_CM Stubs In Server Mode
|
||||
if(MCPI_SERVER_MODE)
|
||||
if(MCPI_HEADLESS_MODE)
|
||||
install(TARGETS GLESv1_CM DESTINATION "${MCPI_LIB_DIR}")
|
||||
endif()
|
||||
|
||||
# MCPI Depends On GLESv2, But Uses GLESv1_CM
|
||||
install_symlink("libGLESv1_CM.so.1" "${MCPI_LIB_DIR}/libGLESv2.so")
|
||||
# Prevent MCPI From Linking To The Legacy GL Driver When Directly Linking To GL
|
||||
if(NOT MCPI_SERVER_MODE AND NOT MCPI_USE_MEDIA_LAYER_PROXY)
|
||||
if(NOT MCPI_HEADLESS_MODE AND NOT MCPI_USE_MEDIA_LAYER_PROXY)
|
||||
# Symlinks
|
||||
install_symlink("/usr/lib/arm-linux-gnueabihf/libEGL.so.1" "${MCPI_LIB_DIR}/libEGL.so")
|
||||
install_symlink("/usr/lib/arm-linux-gnueabihf/libGLESv1_CM.so.1" "${MCPI_LIB_DIR}/libGLESv1_CM.so.1")
|
||||
|
@ -2,8 +2,6 @@
|
||||
|
||||
#include <libreborn/libreborn.h>
|
||||
|
||||
#define IMPOSSIBLE() ERR("(%s:%i) This Should Never Be Called", __FILE__, __LINE__)
|
||||
|
||||
// EGL Is Replaced With GLFW
|
||||
|
||||
EGLDisplay eglGetDisplay(__attribute__((unused)) NativeDisplayType native_display) {
|
||||
|
@ -2,8 +2,6 @@
|
||||
|
||||
#include <libreborn/libreborn.h>
|
||||
|
||||
#define IMPOSSIBLE() ERR("(%s:%i) This Should Never Be Called", __FILE__, __LINE__)
|
||||
|
||||
// Raw X11 Is Replaced With GLFW
|
||||
|
||||
int XTranslateCoordinates(__attribute__((unused)) void *display, __attribute__((unused)) XID src_w, __attribute__((unused)) XID dest_w, __attribute__((unused)) int src_x, __attribute__((unused)) int src_y, __attribute__((unused)) int *dest_x_return, __attribute__((unused)) int *dest_y_return, __attribute__((unused)) XID *child_return) {
|
||||
|
@ -8,7 +8,7 @@ add_definitions(-D_GLIBCXX_USE_CXX11_ABI=0)
|
||||
## Mods
|
||||
|
||||
add_library(compat SHARED src/compat/compat.c src/compat/egl.c src/compat/x11.c)
|
||||
target_link_libraries(compat feature input chat sign media-layer-core dl)
|
||||
target_link_libraries(compat feature input chat sign media-layer-core home dl)
|
||||
|
||||
add_library(readdir SHARED src/readdir/readdir.c)
|
||||
|
||||
@ -27,7 +27,7 @@ else()
|
||||
endif()
|
||||
|
||||
add_library(camera SHARED src/camera/camera.cpp)
|
||||
target_link_libraries(camera reborn media-layer-core feature)
|
||||
target_link_libraries(camera reborn media-layer-core feature home)
|
||||
|
||||
add_library(game-mode SHARED src/game-mode/game-mode.c src/game-mode/game-mode.cpp)
|
||||
target_link_libraries(game-mode reborn feature)
|
||||
|
@ -2,12 +2,13 @@
|
||||
#include <libreborn/media-layer/core.h>
|
||||
#include <libreborn/minecraft.h>
|
||||
|
||||
#include "../init/init.h"
|
||||
#include "../feature/feature.h"
|
||||
#include "../home/home.h"
|
||||
#include "../init/init.h"
|
||||
|
||||
// Take Screenshot Using TripodCamera
|
||||
static void AppPlatform_linux_saveScreenshot_injection(__attribute__((unused)) unsigned char *app_platform, __attribute__((unused)) std::string const& path, __attribute__((unused)) int32_t width, __attribute__((unused)) int32_t height) {
|
||||
media_take_screenshot();
|
||||
media_take_screenshot(home_get());
|
||||
}
|
||||
|
||||
// Enable TripodCameraRenderer
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "../input/input.h"
|
||||
#include "../sign/sign.h"
|
||||
#include "../chat/chat.h"
|
||||
#include "../home/home.h"
|
||||
#include "../init/init.h"
|
||||
#include "compat.h"
|
||||
|
||||
@ -53,7 +54,7 @@ HOOK(SDL_PollEvent, int, (SDL_Event *event)) {
|
||||
media_toggle_fullscreen();
|
||||
handled = 1;
|
||||
} else if (event->key.keysym.sym == SDLK_F2) {
|
||||
media_take_screenshot();
|
||||
media_take_screenshot(home_get());
|
||||
handled = 1;
|
||||
} else if (event->key.keysym.sym == SDLK_F1) {
|
||||
input_hide_gui();
|
||||
|
@ -13,15 +13,24 @@
|
||||
#define NEW_PATH ""
|
||||
|
||||
// Store Launch Directory
|
||||
static char *get_launch_directory() {
|
||||
static char *launch_directory = NULL;
|
||||
__attribute__((constructor)) static void init_launch_directory() {
|
||||
if (launch_directory == NULL) {
|
||||
launch_directory = getcwd(NULL, 0);
|
||||
}
|
||||
return launch_directory;
|
||||
}
|
||||
__attribute__((constructor)) static void init_launch_directory() {
|
||||
get_launch_directory();
|
||||
}
|
||||
__attribute__((destructor)) static void free_launch_directory() {
|
||||
free(get_launch_directory());
|
||||
}
|
||||
|
||||
// Pretend $HOME Is Launch Directory
|
||||
HOOK(getenv, char *, (const char *name)) {
|
||||
if (strcmp(name, "HOME") == 0) {
|
||||
return launch_directory;
|
||||
return get_launch_directory();
|
||||
} else {
|
||||
ensure_getenv();
|
||||
return (*real_getenv)(name);
|
||||
@ -34,7 +43,7 @@ char *home_get() {
|
||||
static char *dir = NULL;
|
||||
// Load
|
||||
if (dir == NULL) {
|
||||
safe_asprintf(&dir, "%s/" NEW_PATH, getenv("HOME"));
|
||||
safe_asprintf(&dir, "%s" NEW_PATH, getenv("HOME"));
|
||||
}
|
||||
// Return
|
||||
return dir;
|
||||
|
Loading…
Reference in New Issue
Block a user