From aa7818847cec129a754547b3e956d26e05fae075 Mon Sep 17 00:00:00 2001 From: Mathew Velasquez Date: Tue, 6 Dec 2016 23:49:17 -0500 Subject: [PATCH] Lots of stuff --- binding-mri/journal-binding.cpp | 94 ++++++++++--- binding-mri/niko-binding.cpp | 54 ++++++-- journal/journal.pro | 4 +- journal/linux/display.h | 2 + journal/linux/journal.c | 229 ++++++++++++++++++++++++++++++++ journal/linux/niko.c | 1 + journal/w32/journal.c | 15 ++- mkxp.pro | 1 + src/eventthread.cpp | 2 +- src/gl-meta.cpp | 2 +- src/glstate.h | 2 +- src/steam.cpp | 13 +- src/xdg-user-dir-lookup.c | 155 +++++++++++++++++++-- steamshim_parent/Makefile | 4 +- 14 files changed, 531 insertions(+), 47 deletions(-) diff --git a/binding-mri/journal-binding.cpp b/binding-mri/journal-binding.cpp index 3a2744b..6954dcc 100644 --- a/binding-mri/journal-binding.cpp +++ b/binding-mri/journal-binding.cpp @@ -5,50 +5,74 @@ #include -#define OUT_BUFFER_SIZE 256 +#if defined __linux +#include +#include +#include +#include +#include +#endif + +#define BUFFER_SIZE 256 static SDL_Thread *thread = NULL; static SDL_mutex *mutex = NULL; -static volatile char message_buffer[OUT_BUFFER_SIZE]; -static volatile int message_len = 0; +static volatile char message_buffer[BUFFER_SIZE]; static volatile bool active = false; +#if defined __linux +#define PIPE_PATH "/tmp/oneshot-pipe" +static volatile int message_len = 0; +static volatile int out_pipe = -1; +void cleanup_pipe() +{ + unlink(PIPE_PATH); +} +#endif + int server_thread(void *data) { (void)data; +#if defined _WIN32 HANDLE pipe = CreateNamedPipeW(L"\\\\.\\pipe\\oneshot-journal-to-game", PIPE_ACCESS_OUTBOUND, PIPE_TYPE_BYTE | PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, - OUT_BUFFER_SIZE, - OUT_BUFFER_SIZE, + BUFFER_SIZE, + BUFFER_SIZE, 0, NULL); for (;;) { ConnectNamedPipe(pipe, NULL); SDL_LockMutex(mutex); - WriteFile(pipe, (const void*)message_buffer, OUT_BUFFER_SIZE, NULL, NULL); + DWORD written; + WriteFile(pipe, (const void*)message_buffer, BUFFER_SIZE, &written, NULL); active = true; SDL_UnlockMutex(mutex); FlushFileBuffers(pipe); DisconnectNamedPipe(pipe); } - CloseHandle(pipe); - +#elif defined __linux + out_pipe = open(PIPE_PATH, O_WRONLY); + active = true; + SDL_LockMutex(mutex); + if (message_len > 0) + write(out_pipe, (char*)message_buffer, message_len); + SDL_UnlockMutex(mutex); return 0; +#endif } RB_METHOD(journalSet) { RB_UNUSED_PARAM; const char *name; - int len; - rb_get_args(argc, argv, "s", &name, &len RB_ARG_END); -#ifdef _WIN32 - if (thread == NULL) { - thread = SDL_CreateThread(server_thread, "journal", NULL); - } + rb_get_args(argc, argv, "z", &name RB_ARG_END); +#if defined _WIN32 + SDL_LockMutex(mutex); + strcpy((char*)message_buffer, name); + SDL_UnlockMutex(mutex); HANDLE pipe = CreateFileW(L"\\\\.\\pipe\\oneshot-game-to-journal", GENERIC_WRITE, 0, @@ -56,28 +80,60 @@ RB_METHOD(journalSet) OPEN_EXISTING, 0, NULL); - SDL_LockMutex(mutex); - strcpy((char*)message_buffer, name); - message_len = len; - SDL_UnlockMutex(mutex); if (pipe != INVALID_HANDLE_VALUE) { active = true; - WriteFile(pipe, (const void*)message_buffer, OUT_BUFFER_SIZE, NULL, NULL); + DWORD written; + WriteFile(pipe, (const void*)message_buffer, BUFFER_SIZE, &written, NULL); FlushFileBuffers(pipe); CloseHandle(pipe); } + if (thread == NULL) { + thread = SDL_CreateThread(server_thread, "journal", NULL); + } +#elif defined __linux + // Clean up connection thread + if (thread != NULL && out_pipe != -1) { + SDL_WaitThread(thread, NULL); + thread = NULL; + } + // Record message + SDL_LockMutex(mutex); + message_len = strlen(name); + memcpy((char*)message_buffer, name, message_len); + SDL_UnlockMutex(mutex); + + // Attempt to send it over the tubes + if (out_pipe != -1) { + // We have a connection, so send it over + if (write(out_pipe, (char*)message_buffer, message_len) <= 0) { + // In the case of an error, close + close(out_pipe); + out_pipe = -1; + } + } + if (out_pipe == -1) { + // We don't have a pipe open, so spawn the connection thread + thread = SDL_CreateThread(server_thread, "journal", NULL); + } +#else +#error "not yet implemented" #endif return Qnil; } RB_METHOD(journalActive) { + RB_UNUSED_PARAM; return active ? Qtrue : Qfalse; } void journalBindingInit() { mutex = SDL_CreateMutex(); +#if defined __linux + mkfifo(PIPE_PATH, 0666); + atexit(cleanup_pipe); +#endif VALUE module = rb_define_module("Journal"); _rb_define_module_function(module, "set", journalSet); diff --git a/binding-mri/niko-binding.cpp b/binding-mri/niko-binding.cpp index 4d88151..2d677b5 100644 --- a/binding-mri/niko-binding.cpp +++ b/binding-mri/niko-binding.cpp @@ -4,26 +4,34 @@ #include "eventthread.h" #include "debugwriter.h" -#ifdef _WIN32 +#if defined _WIN32 #include #endif #include +namespace syswm { #include +} + +#define NIKO_X (320 - 16) +#define NIKO_Y ((13 * 16) * 2) RB_METHOD(nikoStart) { RB_UNUSED_PARAM; - // Calculate where to stick the window - POINT pos; - pos.x = 320 - 16; - pos.y = (13 * 16) * 2; - SDL_SysWMinfo syswindow; + + // Prime native window info + syswm::SDL_SysWMinfo syswindow; SDL_VERSION(&syswindow.version); SDL_GetWindowWMInfo(shState->rtData().window, &syswindow); + +#if defined _WIN32 + // Calculate where to stick the window + POINT pos; + pos.x = NIKO_X; + pos.y = NIKO_Y; ClientToScreen(syswindow.info.win.window, &pos); // Start process -#ifdef _WIN32 WCHAR path[MAX_PATH]; WCHAR args[MAX_PATH]; GetModuleFileNameW(NULL, path, MAX_PATH); @@ -35,10 +43,36 @@ RB_METHOD(nikoStart) si.cb = sizeof(si); PROCESS_INFORMATION pi; CreateProcessW(path, args, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); +#elif defined __linux + // Calculate where to stick the window + int x, y; // Top-left area of client (hopefully) + SDL_GetWindowPosition(shState->rtData().window, &x, &y); + x += NIKO_X; + y += NIKO_Y; + char path[PATH_MAX]; + ssize_t len = readlink("/proc/self/exe", path, PATH_MAX); + if (len > 0) { + // Replace filename + for (size_t i = len; i > 0; --i) { + if (path[i-1] == '/') { + strcpy(path + i, "_______"); + break; + } + } + // X and Y string arguments + char x_str[16]; + char y_str[16]; + sprintf(x_str, "%d", x); + sprintf(y_str, "%d", y); + // Assume that was a success and run the binary + pid_t pid = fork(); + if (pid == 0) { + execl(path, "_______", x_str, y_str, NULL); + exit(1); + } + } #else -#ifdef linux -#else -#endif +#error "not yet implemented" #endif return Qnil; } diff --git a/journal/journal.pro b/journal/journal.pro index 140d5c3..44867c6 100644 --- a/journal/journal.pro +++ b/journal/journal.pro @@ -46,7 +46,9 @@ unix:!macx { linux/display.h \ linux/image.h - LIBS += -lxcb -lxcb-util -lxcb-image -lxcb-shape + QMAKE_CFLAGS += -pthread + + LIBS += -pthread -lxcb -lxcb-util -lxcb-image -lxcb-shape -lxcb-icccm -lxcb-ewmh } # OS X diff --git a/journal/linux/display.h b/journal/linux/display.h index 6825d6c..8592baf 100644 --- a/journal/linux/display.h +++ b/journal/linux/display.h @@ -11,5 +11,7 @@ struct Display { }; #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) +#define STRING(x) sizeof(x) - 1, (x) +#define ARRAY(x) sizeof(x), (x) #endif // DISPLAY_H diff --git a/journal/linux/journal.c b/journal/linux/journal.c index 3c80d0d..f8cc299 100644 --- a/journal/linux/journal.c +++ b/journal/linux/journal.c @@ -1,6 +1,235 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + #include "display.h" +#include "image.h" + +#define PIPE_DIR "/tmp" +#define PIPE_NAME "oneshot-pipe" +#define PIPE_PATH PIPE_DIR "/" PIPE_NAME +#define MESSAGE_BUF_SIZE 256 + +#define PAGES \ + PAGE(default) \ + PAGE(c1) \ + PAGE(c2) \ + PAGE(c3) \ + PAGE(c4) \ + PAGE(c5) \ + PAGE(c6) \ + PAGE(c7) \ + PAGE(s1) \ + PAGE(s2) \ + PAGE(s3) \ + PAGE(s4) \ + PAGE(t1) \ + PAGE(t2) \ + PAGE(t3) \ + PAGE(t4) \ + PAGE(t5) \ + PAGE(t6) \ + PAGE(t7) \ + PAGE(t8) \ + PAGE(t9) \ + PAGE(t10) \ + PAGE(t11) \ + PAGE(t12) \ + PAGE(t13) \ + PAGE(t14) \ + PAGE(t15) \ + PAGE(t16) \ + PAGE(final) \ + PAGE(save) + +struct ThreadData { + struct Display *dpy; + xcb_window_t window; + xcb_gcontext_t gc; + xcb_pixmap_t *masks; + xcb_pixmap_t *images; + volatile int page; +}; + +void set_page(struct ThreadData *threaddata, const char *name) +{ + int page = 0; +#define PAGE(x) if (strncmp(name, #x, MESSAGE_BUF_SIZE) == 0) { goto end; } else { ++page; } + PAGES +#undef PAGE + +end: + threaddata->page = page; + xcb_shape_mask(threaddata->dpy->c, ShapeSet, ShapeBounding, + threaddata->window, 0, 0, threaddata->masks[page]); + xcb_copy_area(threaddata->dpy->c, + threaddata->images[page], + threaddata->window, + threaddata->gc, + 0, 0, 0, 0, JOURNAL_WIDTH, JOURNAL_HEIGHT); + xcb_flush(threaddata->dpy->c); +} + +static void *ipc_thread(void *data) +{ + struct ThreadData *threaddata = (struct ThreadData*)data; + + for (;;) { + // Try to open pipe + int pipe = open(PIPE_PATH, O_RDONLY); + if (pipe == -1) { + // Use the default image for now + set_page(threaddata, "default"); + // Wait until the pipe appears to try again + int inotify = inotify_init(); + inotify_add_watch(inotify, PIPE_DIR, IN_CREATE); + char inotify_buf[sizeof(struct inotify_event) + NAME_MAX + 1]; + for (;;) { + ssize_t result = read(inotify, inotify_buf, sizeof(inotify_buf)); + if (result > 0) { + struct inotify_event *e = (struct inotify_event*)inotify_buf; + if (strcmp(e->name, PIPE_NAME) == 0) + break; + } else { + break; + } + } + close(inotify); + } else { + // Message loop + char message[MESSAGE_BUF_SIZE]; + for (;;) { + ssize_t len = read(pipe, message, sizeof(message)); + if (len > 0) { + set_page(threaddata, message); + } else if (len == 0) { + exit(0); // empty string + } else { + // End of the line + break; + } + } + close(pipe); + } + } + + return NULL; +} int do_journal(struct Display *dpy) { + // Connect EWMH + xcb_ewmh_connection_t ewmh; + xcb_ewmh_init_atoms_replies(&ewmh, xcb_ewmh_init_atoms(dpy->c, &ewmh), NULL); + + // Request some atoms + xcb_intern_atom_cookie_t WM_DELETE_WINDOW_cookie = xcb_intern_atom(dpy->c, false, STRING("WM_DELETE_WINDOW")); + xcb_intern_atom_cookie_t _NET_WM_PING_cookie = xcb_intern_atom(dpy->c, false, STRING("_NET_WM_PING")); + xcb_intern_atom_cookie_t WM_PROTOCOLS_cookie = xcb_intern_atom(dpy->c, false, STRING("WM_PROTOCOLS")); + xcb_atom_t WM_DELETE_WINDOW = xcb_intern_atom_reply(dpy->c, WM_DELETE_WINDOW_cookie, NULL)->atom; + xcb_atom_t _NET_WM_PING = xcb_intern_atom_reply(dpy->c, _NET_WM_PING_cookie, NULL)->atom; + xcb_atom_t WM_PROTOCOLS = xcb_intern_atom_reply(dpy->c, WM_PROTOCOLS_cookie, NULL)->atom; + + // Create window + uint32_t values[] = { + XCB_EVENT_MASK_EXPOSURE, // event mask + }; + xcb_window_t window = xcb_generate_id(dpy->c); + xcb_create_window(dpy->c, XCB_COPY_FROM_PARENT, window, dpy->screen->root, + 0, 0, JOURNAL_WIDTH, JOURNAL_HEIGHT, + 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, dpy->screen->root_visual, + XCB_CW_EVENT_MASK, &values); + + xcb_atom_t protocols[] = { + WM_DELETE_WINDOW, + _NET_WM_PING, + }; + xcb_icccm_set_wm_protocols(dpy->c, window, WM_PROTOCOLS, ARRAY(protocols)); + + xcb_icccm_set_wm_name(dpy->c, window, XCB_ATOM_STRING, 8, STRING("")); + xcb_icccm_set_wm_class(dpy->c, window, ARRAY("_______\0OneshotJournal")); + xcb_ewmh_set_wm_window_type(&ewmh, window, 1, &ewmh._NET_WM_WINDOW_TYPE_NORMAL); + + xcb_size_hints_t size_hints; + xcb_icccm_size_hints_set_min_size(&size_hints, JOURNAL_WIDTH, JOURNAL_HEIGHT); + xcb_icccm_size_hints_set_max_size(&size_hints, JOURNAL_WIDTH, JOURNAL_HEIGHT); + xcb_icccm_set_wm_size_hints(dpy->c, window, XCB_ATOM_WM_NORMAL_HINTS, &size_hints); + + // Create pixmaps + xcb_pixmap_t masks[] = { +#define PAGE(x) create_mask(dpy->c, window, x##_mask, JOURNAL_WIDTH, JOURNAL_HEIGHT), + PAGES +#undef PAGE + }; + xcb_pixmap_t images[] = { +#define PAGE(x) create_image(dpy->c, window, x##_rgb, JOURNAL_WIDTH, JOURNAL_HEIGHT), + PAGES +#undef PAGE + }; + + // Create graphics context + xcb_gcontext_t gc = xcb_generate_id(dpy->c); + xcb_create_gc(dpy->c, gc, window, 0, NULL); + + // Start IPC thread + struct ThreadData threaddata = { + dpy, + window, + gc, + masks, + images, + 0, + }; + pthread_t thread; + if (pthread_create(&thread, NULL, ipc_thread, &threaddata) != 0) + return 1; + + // Map! + xcb_map_window(dpy->c, window); + xcb_flush(dpy->c); + + // Handle events + xcb_generic_event_t *e; + while ((e = xcb_wait_for_event(dpy->c))) { + switch (e->response_type & ~0x80) { + case XCB_EXPOSE: { + xcb_expose_event_t *ee = (xcb_expose_event_t*)e; + xcb_copy_area(dpy->c, images[threaddata.page], + window, gc, + ee->x, ee->y, ee->x, ee->y, + ee->width, ee->height); + xcb_flush(dpy->c); + } break; + case XCB_CLIENT_MESSAGE: { + xcb_client_message_event_t *ce = (xcb_client_message_event_t*)e; + if (ce->type == WM_PROTOCOLS && ce->format == 32) { + xcb_atom_t atom = ce->data.data32[0]; + if (atom == WM_DELETE_WINDOW) { + goto end; + } else if (atom == _NET_WM_PING) { + ce->window = dpy->screen->root; + xcb_send_event(dpy->c, false, dpy->screen->root, + XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, + (const char*)e); + } + } + } break; + } + free(e); + } + +end: + xcb_free_gc(dpy->c, gc); + for (size_t i = 0; i < ARRAY_SIZE(masks); ++i) { + xcb_free_pixmap(dpy->c, masks[i]); + xcb_free_pixmap(dpy->c, images[i]); + } return 0; } diff --git a/journal/linux/niko.c b/journal/linux/niko.c index 1265d1f..eb99afb 100644 --- a/journal/linux/niko.c +++ b/journal/linux/niko.c @@ -86,6 +86,7 @@ int do_niko(struct Display *dpy, int x, int y) xcb_flush(dpy->c); } break; } + free(e); } else if (getticks() - ticks >= 1000 / 60) { break; } diff --git a/journal/w32/journal.c b/journal/w32/journal.c index af64c51..14871ea 100644 --- a/journal/w32/journal.c +++ b/journal/w32/journal.c @@ -6,6 +6,8 @@ #define DEFAULT_HEIGHT 600 #define IN_BUFFER_SIZE 256 +#define WINDOW_STYLE (WS_OVERLAPPEDWINDOW ^ (WS_THICKFRAME | WS_MAXIMIZEBOX)) + static const WCHAR journal_classname[] = L"journal"; static HBITMAP image_handle = NULL; @@ -132,7 +134,7 @@ int do_journal() wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = module; - wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); + wc.hIcon = LoadIcon(NULL, "MAINICON"); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = NULL; wc.lpszMenuName = NULL; @@ -142,12 +144,19 @@ int do_journal() if (!RegisterClassEx(&wc)) return 1; + RECT winrect; + winrect.left = 0; + winrect.top = 0; + winrect.right = DEFAULT_WIDTH; + winrect.bottom = DEFAULT_HEIGHT; + AdjustWindowRectEx(&winrect, WINDOW_STYLE, FALSE, 0); + if (!(window = CreateWindowExW(WS_EX_COMPOSITED | WS_EX_LAYERED, journal_classname, L"", - WS_OVERLAPPEDWINDOW ^ (WS_THICKFRAME | WS_MAXIMIZEBOX), + WINDOW_STYLE, CW_USEDEFAULT, CW_USEDEFAULT, - DEFAULT_WIDTH, DEFAULT_HEIGHT, + winrect.right - winrect.left, winrect.bottom - winrect.top, NULL, NULL, module, NULL))) { return 1; } diff --git a/mkxp.pro b/mkxp.pro index 49f54e0..cf06c11 100644 --- a/mkxp.pro +++ b/mkxp.pro @@ -56,6 +56,7 @@ unix { PKGCONFIG += openal zlib INCLUDEPATH += /usr/include/AL /usr/local/include/AL SOURCES += src/xdg-user-dir-lookup.c + LIBS += -lX11 } } diff --git a/src/eventthread.cpp b/src/eventthread.cpp index 4c0db83..7063ec9 100644 --- a/src/eventthread.cpp +++ b/src/eventthread.cpp @@ -106,7 +106,7 @@ bool EventThread::allocUserEvents() EventThread::EventThread() : fullscreen(false), - showCursor(false) + showCursor(true) {} void EventThread::process(RGSSThreadData &rtData) diff --git a/src/gl-meta.cpp b/src/gl-meta.cpp index 8733449..be32cb8 100644 --- a/src/gl-meta.cpp +++ b/src/gl-meta.cpp @@ -65,7 +65,7 @@ void subRectImageEnd() } } -#define HAVE_NATIVE_VAO gl.GenVertexArrays +#define HAVE_NATIVE_VAO false //gl.GenVertexArrays static void vaoBindRes(VAO &vao) { diff --git a/src/glstate.h b/src/glstate.h index 63b0bcb..b8be5c5 100644 --- a/src/glstate.h +++ b/src/glstate.h @@ -42,7 +42,7 @@ struct GLProperty } void push() { stack.push(current); } - void pop() { set(stack.top()); stack.pop(); } + void pop() { if (!stack.empty()) { set(stack.top()); stack.pop(); } } const T &get() { return current; } void set(const T &value) { diff --git a/src/steam.cpp b/src/steam.cpp index d1bdf6d..744af79 100644 --- a/src/steam.cpp +++ b/src/steam.cpp @@ -7,8 +7,17 @@ /* Achievements */ static const char *const achievementNames[] = { - "SaveWorld", - "SaveNiko", + "CHAOTIC_EVIL", + "SHOCK", + "EXTREME_BARTENDING", + "RAM_WHISPERER", + "PANCAKES", + "WE_RIDE_AT_DAWN", + "SECRET", + "BOOKWORM", + "REBIRTH", + "ONESHOT", + "RETURN", }; #define NUM_ACHIEVEMENTS (sizeof(achievementNames) / sizeof(achievementNames[0])) diff --git a/src/xdg-user-dir-lookup.c b/src/xdg-user-dir-lookup.c index 555a6c7..5c6c90d 100644 --- a/src/xdg-user-dir-lookup.c +++ b/src/xdg-user-dir-lookup.c @@ -10,10 +10,10 @@ including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, - subject to the following conditions: + subject to the following conditions: The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. + included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF @@ -29,7 +29,146 @@ #include #include +/** + * xdg_user_dir_lookup_with_fallback: + * @type: a string specifying the type of directory + * @fallback: value to use if the directory isn't specified by the user + * @returns: a newly allocated absolute pathname + * + * Looks up a XDG user directory of the specified type. + * Example of types are "DESKTOP" and "DOWNLOAD". + * + * In case the user hasn't specified any directory for the specified + * type the value returned is @fallback. + * + * The return value is newly allocated and must be freed with + * free(). The return value is never NULL if @fallback != NULL, unless + * out of memory. + **/ +static char * +xdg_user_dir_lookup_with_fallback (const char *type, const char *fallback) +{ + FILE *file; + char *home_dir, *config_home, *config_file; + char buffer[512]; + char *user_dir; + char *p, *d; + int len; + int relative; + home_dir = getenv ("HOME"); + + if (home_dir == NULL) + goto error; + + config_home = getenv ("XDG_CONFIG_HOME"); + if (config_home == NULL || config_home[0] == 0) + { + config_file = (char*) malloc (strlen (home_dir) + strlen ("/.config/user-dirs.dirs") + 1); + if (config_file == NULL) + goto error; + + strcpy (config_file, home_dir); + strcat (config_file, "/.config/user-dirs.dirs"); + } + else + { + config_file = (char*) malloc (strlen (config_home) + strlen ("/user-dirs.dirs") + 1); + if (config_file == NULL) + goto error; + + strcpy (config_file, config_home); + strcat (config_file, "/user-dirs.dirs"); + } + + file = fopen (config_file, "r"); + free (config_file); + if (file == NULL) + goto error; + + user_dir = NULL; + while (fgets (buffer, sizeof (buffer), file)) + { + /* Remove newline at end */ + len = strlen (buffer); + if (len > 0 && buffer[len-1] == '\n') + buffer[len-1] = 0; + + p = buffer; + while (*p == ' ' || *p == '\t') + p++; + + if (strncmp (p, "XDG_", 4) != 0) + continue; + p += 4; + if (strncmp (p, type, strlen (type)) != 0) + continue; + p += strlen (type); + if (strncmp (p, "_DIR", 4) != 0) + continue; + p += 4; + + while (*p == ' ' || *p == '\t') + p++; + + if (*p != '=') + continue; + p++; + + while (*p == ' ' || *p == '\t') + p++; + + if (*p != '"') + continue; + p++; + + relative = 0; + if (strncmp (p, "$HOME/", 6) == 0) + { + p += 6; + relative = 1; + } + else if (*p != '/') + continue; + + if (relative) + { + user_dir = (char*) malloc (strlen (home_dir) + 1 + strlen (p) + 1); + if (user_dir == NULL) + goto error2; + + strcpy (user_dir, home_dir); + strcat (user_dir, "/"); + } + else + { + user_dir = (char*) malloc (strlen (p) + 1); + if (user_dir == NULL) + goto error2; + + *user_dir = 0; + } + + d = user_dir + strlen (user_dir); + while (*p && *p != '"') + { + if ((*p == '\\') && (*(p+1) != 0)) + p++; + *d++ = *p++; + } + *d = 0; + } +error2: + fclose (file); + + if (user_dir) + return user_dir; + + error: + if (fallback) + return strdup (fallback); + return NULL; +} /** * xdg_user_dir_lookup: @@ -52,16 +191,16 @@ static char * xdg_user_dir_lookup (const char *type) { char *dir, *home_dir, *user_dir; - + dir = xdg_user_dir_lookup_with_fallback (type, NULL); if (dir != NULL) return dir; - + home_dir = getenv ("HOME"); - + if (home_dir == NULL) return strdup ("/tmp"); - + /* Special case desktop for historical compatibility */ if (strcmp (type, "DESKTOP") == 0) { @@ -73,7 +212,7 @@ xdg_user_dir_lookup (const char *type) strcat (user_dir, "/Desktop"); return user_dir; } - + return strdup (home_dir); } @@ -86,7 +225,7 @@ main (int argc, char *argv[]) fprintf (stderr, "Usage %s \n", argv[0]); exit (1); } - + printf ("%s\n", xdg_user_dir_lookup (argv[1])); return 0; } diff --git a/steamshim_parent/Makefile b/steamshim_parent/Makefile index fd4bad3..ed7a476 100644 --- a/steamshim_parent/Makefile +++ b/steamshim_parent/Makefile @@ -7,7 +7,7 @@ HOST ?= linux64 FLAGS := -I$(STEAMWORKS)/public -DGAME_LAUNCH_NAME=\"$(GAME_LAUNCH_NAME)\" -Wall ifeq ($(HOST),w32) - FLAGS += -L$(STEAMWORKS)/redistributable_bin -mwindows + FLAGS += -L$(STEAMWORKS)/redistributable_bin else ifeq ($(HOST),linux32) FLAGS += -L$(STEAMWORKS)/redistributable_bin/linux32 -m32 else ifeq ($(HOST),linux64) @@ -20,6 +20,8 @@ FLAGS += -lsteam_api ifeq ($(DEBUG),1) FLAGS += -DSTEAMSHIM_DEBUG +else + FLAGS += -mwindows endif SRC := steamshim_parent.cpp