mirror of
https://github.com/FEX-Emu/FEX.git
synced 2026-10-06 13:00:15 +02:00
Merge pull request #2763 from Sonicadvance1/fix_x11_variadic_thunks
Thunks/X11: Fixes variadic packing and callbacks.
This commit is contained in:
4 files changed
+2331
-344
No files matched your search
@@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <string>
|
||||
extern "C" {
|
||||
#include <X11/Xlib.h>
|
||||
}
|
||||
|
||||
namespace X11 {
|
||||
constexpr static std::array<std::string_view, 13> CallbackKeys = {{
|
||||
XNGeometryCallback,
|
||||
XNDestroyCallback,
|
||||
XNPreeditStartCallback,
|
||||
XNPreeditDoneCallback,
|
||||
XNPreeditDrawCallback,
|
||||
XNPreeditCaretCallback,
|
||||
XNPreeditStateNotifyCallback,
|
||||
XNStatusStartCallback,
|
||||
XNStatusDoneCallback,
|
||||
XNStatusDrawCallback,
|
||||
XNR6PreeditCallback,
|
||||
XNStringConversionCallback,
|
||||
}};
|
||||
|
||||
}
|
||||
@@ -20,134 +20,214 @@ extern "C" {
|
||||
#undef max
|
||||
}
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <stdio.h>
|
||||
#include <cstring>
|
||||
#include <map>
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "common/Guest.h"
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "thunkgen_guest_libX11.inl"
|
||||
#include "X11Common.h"
|
||||
|
||||
// Custom implementations //
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace {
|
||||
// The various X11 variadic functions take a flattened sequence of key:value pairs as arguments.
|
||||
// The key element is a pointer to a string.
|
||||
// The value element is a pointer to the data of that key type.
|
||||
//
|
||||
// Some keys describe function callbacks for various events that the server interface can call.
|
||||
// FEX needs to walk these keys and ensure any callback function has a trampoline so the native
|
||||
// X11 library can call it.
|
||||
template<typename CallbackType>
|
||||
static std::list<CallbackType> ConvertCallbackArguments(std::vector<void*> &IncomingArguments) {
|
||||
assert(IncomingArguments.size() % 2 == 0 && "Incoming arguments needs to be in pairs");
|
||||
|
||||
std::list<CallbackType> Callbacks;
|
||||
// Walk the arguments and convert any callbacks.
|
||||
const size_t ArgumentPairs = IncomingArguments.size() / 2;
|
||||
for (size_t i = 0; i < ArgumentPairs; ++i) {
|
||||
const char *Key = static_cast<const char*>(IncomingArguments[i * 2]);
|
||||
void** Data = &IncomingArguments[i * 2 + 1];
|
||||
if (!*Data) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if the key is a callback and needs to be modified.
|
||||
auto KeyIt = std::find(X11::CallbackKeys.begin(), X11::CallbackKeys.end(), Key);
|
||||
if (KeyIt == X11::CallbackKeys.end()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Key matches a callback, we need to wrap this.
|
||||
CallbackType *IncomingCallback = reinterpret_cast<CallbackType*>(*Data);
|
||||
CallbackType *ConvertedCallback = &Callbacks.emplace_back(CallbackType {
|
||||
// Client data stays the same.
|
||||
.client_data = IncomingCallback->client_data,
|
||||
|
||||
// Callback needs a trampoline.
|
||||
.callback = AllocateHostTrampolineForGuestFunction(IncomingCallback->callback),
|
||||
});
|
||||
|
||||
// Add this converted back in.
|
||||
*Data = ConvertedCallback;
|
||||
}
|
||||
|
||||
return Callbacks;
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
char* XGetICValues(XIC ic, ...) {
|
||||
fprintf(stderr, "XGetICValues\n");
|
||||
va_list ap;
|
||||
std::vector<unsigned long> args;
|
||||
va_start(ap, ic);
|
||||
for (;;) {
|
||||
auto arg = va_arg(ap, unsigned long);
|
||||
if (arg == 0)
|
||||
break;
|
||||
args.push_back(arg);
|
||||
fprintf(stderr, "%016lX\n", arg);
|
||||
}
|
||||
fprintf(stderr, "XGetICValues\n");
|
||||
va_list ap;
|
||||
std::vector<void*> args;
|
||||
va_start(ap, ic);
|
||||
for (;;) {
|
||||
auto arg = va_arg(ap, void*);
|
||||
if (arg == 0)
|
||||
break;
|
||||
args.push_back(arg);
|
||||
fprintf(stderr, "%p\n", arg);
|
||||
}
|
||||
|
||||
va_end(ap);
|
||||
auto rv = fexfn_pack_XGetICValues_internal(ic, args.size(), &args[0]);
|
||||
fprintf(stderr, "RV: %p\n", rv);
|
||||
return rv;
|
||||
va_end(ap);
|
||||
|
||||
auto rv = fexfn_pack_XGetICValues_internal(ic, args.size(), &args[0]);
|
||||
fprintf(stderr, "RV: %p\n", rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
char* XSetICValues(XIC ic, ...) {
|
||||
fprintf(stderr, "XSetICValues\n");
|
||||
va_list ap;
|
||||
std::vector<unsigned long> args;
|
||||
va_start(ap, ic);
|
||||
for (;;) {
|
||||
auto arg = va_arg(ap, unsigned long);
|
||||
if (arg == 0)
|
||||
break;
|
||||
args.push_back(arg);
|
||||
fprintf(stderr, "%016lX\n", arg);
|
||||
}
|
||||
fprintf(stderr, "XSetICValues\n");
|
||||
va_list ap;
|
||||
std::vector<void*> IncomingArguments;
|
||||
va_start(ap, ic);
|
||||
for (;;) {
|
||||
auto Key = va_arg(ap, void*);
|
||||
if (Key == 0)
|
||||
break;
|
||||
|
||||
va_end(ap);
|
||||
auto rv = fexfn_pack_XSetICValues_internal(ic, args.size(), &args[0]);
|
||||
fprintf(stderr, "RV: %p\n", rv);
|
||||
return rv;
|
||||
auto Value = va_arg(ap, void*);
|
||||
IncomingArguments.emplace_back(Key);
|
||||
IncomingArguments.emplace_back(Value);
|
||||
}
|
||||
|
||||
va_end(ap);
|
||||
|
||||
// Callback memory needs to live beyond internal function call.
|
||||
std::list<XICCallback> Callbacks = ConvertCallbackArguments<XICCallback>(IncomingArguments);
|
||||
|
||||
auto rv = fexfn_pack_XSetICValues_internal(ic, IncomingArguments.size(), &IncomingArguments[0]);
|
||||
fprintf(stderr, "RV: %p\n", rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
char* XGetIMValues(XIM ic, ...) {
|
||||
fprintf(stderr, "XGetIMValues\n");
|
||||
va_list ap;
|
||||
std::vector<void*> args;
|
||||
va_start(ap, ic);
|
||||
for (;;) {
|
||||
auto arg = va_arg(ap, void*);
|
||||
if (arg == 0)
|
||||
break;
|
||||
args.push_back(arg);
|
||||
fprintf(stderr, "%p\n", arg);
|
||||
}
|
||||
fprintf(stderr, "XGetIMValues\n");
|
||||
va_list ap;
|
||||
std::vector<void*> args;
|
||||
va_start(ap, ic);
|
||||
for (;;) {
|
||||
auto arg = va_arg(ap, void*);
|
||||
if (arg == 0)
|
||||
break;
|
||||
args.push_back(arg);
|
||||
fprintf(stderr, "%p\n", arg);
|
||||
}
|
||||
|
||||
va_end(ap);
|
||||
auto rv = fexfn_pack_XGetIMValues_internal(ic, args.size(), &args[0]);
|
||||
fprintf(stderr, "RV: %p\n", rv);
|
||||
return rv;
|
||||
va_end(ap);
|
||||
auto rv = fexfn_pack_XGetIMValues_internal(ic, args.size(), &args[0]);
|
||||
fprintf(stderr, "RV: %p\n", rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
char* XSetIMValues(XIM ic, ...) {
|
||||
fprintf(stderr, "XSetIMValues\n");
|
||||
va_list ap;
|
||||
std::vector<void*> args;
|
||||
va_start(ap, ic);
|
||||
for (;;) {
|
||||
auto arg = va_arg(ap, void*);
|
||||
if (arg == 0)
|
||||
break;
|
||||
args.push_back(arg);
|
||||
fprintf(stderr, "%p\n", arg);
|
||||
}
|
||||
fprintf(stderr, "XSetIMValues\n");
|
||||
va_list ap;
|
||||
std::vector<void*> IncomingArguments;
|
||||
va_start(ap, ic);
|
||||
for (;;) {
|
||||
auto Key = va_arg(ap, void*);
|
||||
if (Key == 0)
|
||||
break;
|
||||
|
||||
va_end(ap);
|
||||
auto rv = fexfn_pack_XSetIMValues_internal(ic, args.size(), &args[0]);
|
||||
fprintf(stderr, "RV: %p\n", rv);
|
||||
return rv;
|
||||
auto Value = va_arg(ap, void*);
|
||||
IncomingArguments.emplace_back(Key);
|
||||
IncomingArguments.emplace_back(Value);
|
||||
fprintf(stderr, "%s\n", (char*)Key);
|
||||
}
|
||||
|
||||
va_end(ap);
|
||||
|
||||
// Callback memory needs to live beyond internal function call.
|
||||
std::list<XIMCallback> Callbacks = ConvertCallbackArguments<XIMCallback>(IncomingArguments);
|
||||
|
||||
// Send a count (not including nullptr);
|
||||
auto rv = fexfn_pack_XSetIMValues_internal(ic, IncomingArguments.size(), &IncomingArguments[0]);
|
||||
fprintf(stderr, "RV: %p\n", rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
_XIC* XCreateIC(XIM im, ...) {
|
||||
fprintf(stderr, "XCreateIC\n");
|
||||
va_list ap;
|
||||
std::vector<unsigned long> args;
|
||||
va_start(ap, im);
|
||||
for (;;) {
|
||||
auto arg = va_arg(ap, unsigned long);
|
||||
if (arg == 0)
|
||||
break;
|
||||
args.push_back(arg);
|
||||
fprintf(stderr, "%016lX\n", arg);
|
||||
}
|
||||
fprintf(stderr, "XCreateIC\n");
|
||||
va_list ap;
|
||||
std::vector<void*> IncomingArguments;
|
||||
|
||||
va_end(ap);
|
||||
auto rv = fexfn_pack_XCreateIC_internal(im, args.size(), &args[0]);
|
||||
fprintf(stderr, "RV: %p\n", rv);
|
||||
return rv;
|
||||
va_start(ap, im);
|
||||
for (;;) {
|
||||
auto Key = va_arg(ap, void*);
|
||||
if (Key == 0)
|
||||
break;
|
||||
|
||||
auto Value = va_arg(ap, void*);
|
||||
IncomingArguments.emplace_back(Key);
|
||||
IncomingArguments.emplace_back(Value);
|
||||
}
|
||||
|
||||
va_end(ap);
|
||||
|
||||
// Callback memory needs to live beyond internal function call.
|
||||
std::list<XICCallback> Callbacks = ConvertCallbackArguments<XICCallback>(IncomingArguments);
|
||||
|
||||
auto rv = fexfn_pack_XCreateIC_internal(im, IncomingArguments.size(), &IncomingArguments[0]);
|
||||
return rv;
|
||||
}
|
||||
|
||||
XVaNestedList XVaCreateNestedList(int unused_arg, ...) {
|
||||
fprintf(stderr, "XVaCreateNestedList\n");
|
||||
va_list ap;
|
||||
std::vector<void*> args;
|
||||
va_start(ap, unused_arg);
|
||||
for (;;) {
|
||||
auto arg = va_arg(ap, void*);
|
||||
if (arg == 0)
|
||||
break;
|
||||
args.push_back(arg);
|
||||
fprintf(stderr, "%p\n", arg);
|
||||
}
|
||||
fprintf(stderr, "XVaCreateNestedList\n");
|
||||
va_list ap;
|
||||
std::vector<void*> IncomingArguments;
|
||||
|
||||
va_end(ap);
|
||||
auto rv = fexfn_pack_XVaCreateNestedList_internal(unused_arg, args.size(), &args[0]);
|
||||
fprintf(stderr, "RV: %p\n", rv);
|
||||
return rv;
|
||||
va_start(ap, unused_arg);
|
||||
for (;;) {
|
||||
auto Key = va_arg(ap, void*);
|
||||
if (Key == 0)
|
||||
break;
|
||||
|
||||
auto Value = va_arg(ap, void*);
|
||||
IncomingArguments.emplace_back(Key);
|
||||
IncomingArguments.emplace_back(Value);
|
||||
}
|
||||
|
||||
va_end(ap);
|
||||
|
||||
// Callback memory needs to live beyond internal function call.
|
||||
std::list<XICCallback> Callbacks = ConvertCallbackArguments<XICCallback>(IncomingArguments);
|
||||
|
||||
auto rv = fexfn_pack_XVaCreateNestedList_internal(unused_arg, IncomingArguments.size(), &IncomingArguments[0]);
|
||||
fprintf(stderr, "RV: %p\n", rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
static void LockMutexFunction(LockInfoPtr) {
|
||||
@@ -265,6 +345,27 @@ extern "C" {
|
||||
return ret;
|
||||
}
|
||||
|
||||
Bool XRegisterIMInstantiateCallback(Display* dpy,
|
||||
struct _XrmHashBucketRec* rdb,
|
||||
char* res_name,
|
||||
char* res_class,
|
||||
XIDProc callback,
|
||||
XPointer client_data
|
||||
) {
|
||||
return fexfn_pack_XRegisterIMInstantiateCallback(dpy, rdb, res_name, res_class, AllocateHostTrampolineForGuestFunction(callback), client_data);
|
||||
}
|
||||
|
||||
Bool XUnregisterIMInstantiateCallback(
|
||||
Display* dpy,
|
||||
struct _XrmHashBucketRec* rdb,
|
||||
char* res_name,
|
||||
char* res_class,
|
||||
XIDProc callback,
|
||||
XPointer client_data
|
||||
) {
|
||||
return fexfn_pack_XUnregisterIMInstantiateCallback(dpy, rdb, res_name, res_class, AllocateHostTrampolineForGuestFunction(callback), client_data);
|
||||
}
|
||||
|
||||
void (*_XLockMutex_fn)(LockInfoPtr) = LockMutexFunction;
|
||||
void (*_XUnlockMutex_fn)(LockInfoPtr) = UnlockMutexFunction;
|
||||
LockInfoPtr _Xglobal_lock = (LockInfoPtr)0x4142434445464748ULL;
|
||||
|
||||
+2103
-246
File diff suppressed because it is too large.
Load diff
@@ -45,6 +45,10 @@ template<> struct fex_gen_type<std::remove_pointer_t<XIOErrorExitHandler>> {}; /
|
||||
|
||||
template<> struct fex_gen_type<Bool(Display*, xReply*, char*, int, XPointer)> {}; // XDisplay::async_handlers->handler
|
||||
|
||||
template<> struct fex_gen_type<Bool(XIM, XPointer, XPointer)> {}; // XIMProc
|
||||
template<> struct fex_gen_type<Bool(XIC, XPointer, XPointer)> {}; // XICProc
|
||||
template<> struct fex_gen_type<void(Display*, XPointer, XPointer)> {}; // XIDProc
|
||||
|
||||
template<> struct fex_gen_type<int(XImage*)> {}; // XImage::f.destroy_image
|
||||
template<> struct fex_gen_type<unsigned long(XImage*, int, int)> {}; // XImage::f.get_pixel
|
||||
template<> struct fex_gen_type<int(XImage*, int, int, unsigned long)> {}; // XImage::f.put_pixel
|
||||
@@ -653,15 +657,15 @@ template<> struct fex_gen_config<Xutf8DrawImageString> {};
|
||||
template<> struct fex_gen_config<XOpenIM> {};
|
||||
template<> struct fex_gen_config<XCloseIM> {};
|
||||
template<> struct fex_gen_config<XGetIMValues> {
|
||||
using uniform_va_type = void*;
|
||||
using uniform_va_type = void*;
|
||||
};
|
||||
template<> struct fex_gen_config<XSetIMValues> {
|
||||
using uniform_va_type = void*;
|
||||
using uniform_va_type = void*;
|
||||
};
|
||||
template<> struct fex_gen_config<XDisplayOfIM> {};
|
||||
template<> struct fex_gen_config<XLocaleOfIM> {};
|
||||
template<> struct fex_gen_config<XCreateIC> {
|
||||
using uniform_va_type = unsigned long;
|
||||
using uniform_va_type = void*;
|
||||
};
|
||||
template<> struct fex_gen_config<XDestroyIC> {};
|
||||
template<> struct fex_gen_config<XSetICFocus> {};
|
||||
@@ -670,11 +674,11 @@ template<> struct fex_gen_config<XwcResetIC> {};
|
||||
template<> struct fex_gen_config<XmbResetIC> {};
|
||||
template<> struct fex_gen_config<Xutf8ResetIC> {};
|
||||
template<> struct fex_gen_config<XSetICValues> {
|
||||
using uniform_va_type = unsigned long;
|
||||
using uniform_va_type = void*;
|
||||
};
|
||||
|
||||
template<> struct fex_gen_config<XGetICValues> {
|
||||
using uniform_va_type = unsigned long;
|
||||
using uniform_va_type = void*;
|
||||
};
|
||||
|
||||
template<> struct fex_gen_config<XIMOfIC> {};
|
||||
@@ -683,11 +687,11 @@ template<> struct fex_gen_config<XmbLookupString> {};
|
||||
template<> struct fex_gen_config<XwcLookupString> {};
|
||||
template<> struct fex_gen_config<Xutf8LookupString> {};
|
||||
template<> struct fex_gen_config<XVaCreateNestedList> {
|
||||
using uniform_va_type = void*;
|
||||
using uniform_va_type = void*;
|
||||
};
|
||||
|
||||
template<> struct fex_gen_config<XRegisterIMInstantiateCallback> {};
|
||||
template<> struct fex_gen_config<XUnregisterIMInstantiateCallback> {};
|
||||
template<> struct fex_gen_config<XRegisterIMInstantiateCallback> : fexgen::custom_guest_entrypoint {};
|
||||
template<> struct fex_gen_config<XUnregisterIMInstantiateCallback> : fexgen::custom_guest_entrypoint {};
|
||||
template<> struct fex_gen_config<XInternalConnectionNumbers> {};
|
||||
template<> struct fex_gen_config<XProcessInternalConnection> {};
|
||||
template<> struct fex_gen_config<XAddConnectionWatch> {};
|
||||
|
||||
Reference in new issue
Block a user