mirror of
https://forgejo.xatacraft.ru/Sunshine/mkxp-sunshine.git
synced 2026-08-20 22:09:55 +00:00
Lots of stuff
This commit is contained in:
parent
cce13d8d01
commit
aa7818847c
14 changed files with 531 additions and 47 deletions
|
|
@ -5,50 +5,74 @@
|
|||
|
||||
#include <SDL.h>
|
||||
|
||||
#define OUT_BUFFER_SIZE 256
|
||||
#if defined __linux
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/inotify.h>
|
||||
#include <unistd.h>
|
||||
#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);
|
||||
|
|
|
|||
|
|
@ -4,26 +4,34 @@
|
|||
#include "eventthread.h"
|
||||
#include "debugwriter.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#if defined _WIN32
|
||||
#include <shlwapi.h>
|
||||
#endif
|
||||
|
||||
#include <SDL.h>
|
||||
namespace syswm {
|
||||
#include <SDL_syswm.h>
|
||||
}
|
||||
|
||||
#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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -1,6 +1,235 @@
|
|||
#include <xcb/xcb_ewmh.h>
|
||||
#include <xcb/xcb_icccm.h>
|
||||
#include <pthread.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/inotify.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
1
mkxp.pro
1
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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -106,7 +106,7 @@ bool EventThread::allocUserEvents()
|
|||
|
||||
EventThread::EventThread()
|
||||
: fullscreen(false),
|
||||
showCursor(false)
|
||||
showCursor(true)
|
||||
{}
|
||||
|
||||
void EventThread::process(RGSSThreadData &rtData)
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ void subRectImageEnd()
|
|||
}
|
||||
}
|
||||
|
||||
#define HAVE_NATIVE_VAO gl.GenVertexArrays
|
||||
#define HAVE_NATIVE_VAO false //gl.GenVertexArrays
|
||||
|
||||
static void vaoBindRes(VAO &vao)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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]))
|
||||
|
||||
|
|
|
|||
|
|
@ -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 <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/**
|
||||
* 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 <dir-type>\n", argv[0]);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
|
||||
printf ("%s\n", xdg_user_dir_lookup (argv[1]));
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in a new issue