mirror of
https://github.com/FEX-Emu/FEX.git
synced 2025-02-03 21:12:32 +00:00
Thunks/X11: Fixes variadic packing and callbacks.
Two bugs here that caused thunking X11 thunking in Wine/Proton to not work. The easier of the two. The various variadic functions that we thunk actually take key:value pairs where the first is a string pointer, and the value can be various things. We need to handle these as true key:value pairs rather than finding the first nullptr and dropping the remainder. Additionally, there are 12 keys that specify a callback that FEX needs to catch and convert to host callable. Wine is the first application that I have seen that actually uses this. If these callbacks aren't wired up then it it can miss events. The harder of the two problems is the `libX11_Variadic_u64` function was subtly incorrect. Nothing had previously truly exercised this and my test program didn't notice anything wrong while writing it. The first incorrect thing was that it was subtracting the nullptr ender variable before the stack size calculation, causing the value to overwrite the stack if the number of remaining elements was event. Secondly the assembly that was storing two elements per step was decrementing the counter by 8 instead of two. Didn't pick this up before since I believe the code was only hitting the non-pair path before. This gets Proton thunking working under FEX now.
This commit is contained in:
parent
597da88035
commit
e8fcb070b3
25
ThunkLibs/libX11/X11Common.h
Normal file
25
ThunkLibs/libX11/X11Common.h
Normal file
@ -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;
|
||||
|
@ -5,7 +5,9 @@ desc: Handles callbacks and varargs
|
||||
$end_info$
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
#include <cassert>
|
||||
#include <cstdlib>
|
||||
#include <stdio.h>
|
||||
|
||||
@ -31,6 +33,7 @@ extern "C" {
|
||||
#include <utility>
|
||||
|
||||
#include "thunkgen_host_libX11.inl"
|
||||
#include "X11Common.h"
|
||||
|
||||
#ifdef _M_ARM_64
|
||||
// This Variadic asm only works for one signature
|
||||
@ -46,15 +49,15 @@ extern "C" {
|
||||
//
|
||||
// Incoming:
|
||||
// x0 = XIM
|
||||
// x1 = count
|
||||
// x2 = array of 64-bit values
|
||||
// x1 = count (excluding final nullptr)
|
||||
// x2 = array of 64-bit values (excluding final nullptr)
|
||||
// x3 = Function to call
|
||||
//
|
||||
// Outgoing:
|
||||
// x0: Ptr
|
||||
|
||||
__attribute__((naked))
|
||||
void *libX11_Variadic_u64(uint64_t a_0, size_t count, unsigned long *list, void *Func) {
|
||||
void *libX11_Variadic_u64(uint64_t a_0, size_t count, void **list, void *Func) {
|
||||
asm volatile(R"(
|
||||
# Move our function to x8, which will be unused
|
||||
mov x8, x3
|
||||
@ -122,10 +125,11 @@ void *libX11_Variadic_u64(uint64_t a_0, size_t count, unsigned long *list, void
|
||||
# x1 = <count>
|
||||
# x9 = <list ptr>
|
||||
|
||||
# Stack objects
|
||||
# Count >= 7
|
||||
# The number of arguments on the stack will always be (Count - 7) + 1
|
||||
|
||||
# Subtract 6 count objects
|
||||
# Leaves us at least 1 (nullptr)
|
||||
# Gives us the total number of objects that need to be stored on to the stack.
|
||||
# If exactly 7 objects then only nullptr ends up on the stack.
|
||||
sub x1, x1, 6
|
||||
|
||||
# Round up to the nearest pair
|
||||
@ -141,29 +145,33 @@ void *libX11_Variadic_u64(uint64_t a_0, size_t count, unsigned long *list, void
|
||||
# Store how much data we added to the stack in our callee saved register we stole
|
||||
mov x28, x10
|
||||
|
||||
# Subtract one member due to nullptr ender
|
||||
sub x10, x1, 1
|
||||
|
||||
# x11 - stack offset
|
||||
# x11 - stack offset - for stack Arguments
|
||||
mov x11, sp
|
||||
|
||||
# x12 - load offset
|
||||
# x12 - load offset into input array (skipping the first 7 arguments)
|
||||
add x12, x9, (7 * 8)
|
||||
|
||||
cmp x10, 1
|
||||
# Compute the number of elements excluding the terminating nullptr
|
||||
subs x10, x1, 1
|
||||
|
||||
b.eq .single%=
|
||||
b.lt .no_single%=
|
||||
|
||||
.load_pair%=:
|
||||
# Copy data from x12 to x11
|
||||
ldp x1, x2, [x12], 16
|
||||
stp x1, x2, [x11], 16
|
||||
sub x10, x10, 8
|
||||
|
||||
# Stored two so subtract from the count.
|
||||
sub x10, x10, 2
|
||||
cmp x10, 1
|
||||
b.gt .load_pair%=
|
||||
b.lt .no_single%=
|
||||
|
||||
# One variable at most
|
||||
.single%=:
|
||||
# One variable at most
|
||||
# Load the argument from the source.
|
||||
# Then store that and the terminating nullptr.
|
||||
ldr x1, [x12]
|
||||
stp x1, xzr, [x11]
|
||||
b .top_reg_args%=
|
||||
@ -201,7 +209,32 @@ void *libX11_Variadic_u64(uint64_t a_0, size_t count, unsigned long *list, void
|
||||
|
||||
#endif
|
||||
|
||||
_XIC *fexfn_impl_libX11_XCreateIC_internal(XIM a_0, size_t count, unsigned long *list) {
|
||||
// Walks the array of key:value pairs provided from the guest code side.
|
||||
// Finalizing any callback functions that the guest side prepared for us.
|
||||
template<typename CallbackType>
|
||||
void FinalizeIncomingCallbacks(size_t Count, void **list) {
|
||||
assert(Count % 2 == 0 && "Incoming arguments needs to be in pairs");
|
||||
for (size_t i = 0; i < (Count / 2); ++i) {
|
||||
const char *Key = static_cast<const char*>(list[i * 2]);
|
||||
void** Data = &list[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;
|
||||
}
|
||||
|
||||
CallbackType *IncomingCallback = reinterpret_cast<CallbackType*>(*Data);
|
||||
FinalizeHostTrampolineForGuestFunction(IncomingCallback->callback);
|
||||
}
|
||||
}
|
||||
|
||||
_XIC *fexfn_impl_libX11_XCreateIC_internal(XIM a_0, size_t count, void **list) {
|
||||
FinalizeIncomingCallbacks<XICCallback>(count, list);
|
||||
|
||||
switch(count) {
|
||||
case 0: return fexldr_ptr_libX11_XCreateIC(a_0, nullptr); break;
|
||||
case 1: return fexldr_ptr_libX11_XCreateIC(a_0, list[0], nullptr); break;
|
||||
@ -222,7 +255,7 @@ _XIC *fexfn_impl_libX11_XCreateIC_internal(XIM a_0, size_t count, unsigned long
|
||||
}
|
||||
}
|
||||
|
||||
char* fexfn_impl_libX11_XGetICValues_internal(XIC a_0, size_t count, unsigned long *list) {
|
||||
char* fexfn_impl_libX11_XGetICValues_internal(XIC a_0, size_t count, void **list) {
|
||||
switch(count) {
|
||||
case 0: return fexldr_ptr_libX11_XGetICValues(a_0, nullptr); break;
|
||||
case 1: return fexldr_ptr_libX11_XGetICValues(a_0, list[0], nullptr); break;
|
||||
@ -243,7 +276,9 @@ char* fexfn_impl_libX11_XGetICValues_internal(XIC a_0, size_t count, unsigned lo
|
||||
}
|
||||
}
|
||||
|
||||
char* fexfn_impl_libX11_XSetICValues_internal(XIC a_0, size_t count, unsigned long *list) {
|
||||
char* fexfn_impl_libX11_XSetICValues_internal(XIC a_0, size_t count, void **list) {
|
||||
FinalizeIncomingCallbacks<XICCallback>(count, list);
|
||||
|
||||
switch(count) {
|
||||
case 0: return fexldr_ptr_libX11_XSetICValues(a_0, nullptr); break;
|
||||
case 1: return fexldr_ptr_libX11_XSetICValues(a_0, list[0], nullptr); break;
|
||||
@ -277,7 +312,7 @@ char* fexfn_impl_libX11_XGetIMValues_internal(XIM a_0, size_t count, void **list
|
||||
case 8: return fexldr_ptr_libX11_XGetIMValues(a_0, list[0], list[1], list[2], list[3], list[4], list[5], list[6], list[7], nullptr); break;
|
||||
default:
|
||||
#ifdef _M_ARM_64
|
||||
return reinterpret_cast<char*>(libX11_Variadic_u64(reinterpret_cast<uint64_t>(a_0), count, reinterpret_cast<unsigned long *>(list), reinterpret_cast<void*>(fexldr_ptr_libX11_XGetIMValues)));
|
||||
return reinterpret_cast<char*>(libX11_Variadic_u64(reinterpret_cast<uint64_t>(a_0), count, list, reinterpret_cast<void*>(fexldr_ptr_libX11_XGetIMValues)));
|
||||
#else
|
||||
fprintf(stderr, "XGetIMValues_internal FAILURE\n");
|
||||
abort();
|
||||
@ -286,6 +321,8 @@ char* fexfn_impl_libX11_XGetIMValues_internal(XIM a_0, size_t count, void **list
|
||||
}
|
||||
|
||||
char* fexfn_impl_libX11_XSetIMValues_internal(XIM a_0, size_t count, void **list) {
|
||||
FinalizeIncomingCallbacks<XIMCallback>(count, list);
|
||||
|
||||
switch(count) {
|
||||
case 0: return fexldr_ptr_libX11_XSetIMValues(a_0, nullptr); break;
|
||||
case 1: return fexldr_ptr_libX11_XSetIMValues(a_0, list[0], nullptr); break;
|
||||
@ -298,7 +335,7 @@ char* fexfn_impl_libX11_XSetIMValues_internal(XIM a_0, size_t count, void **list
|
||||
case 8: return fexldr_ptr_libX11_XSetIMValues(a_0, list[0], list[1], list[2], list[3], list[4], list[5], list[6], list[7], nullptr); break;
|
||||
default:
|
||||
#ifdef _M_ARM_64
|
||||
return reinterpret_cast<char*>(libX11_Variadic_u64(reinterpret_cast<uint64_t>(a_0), count, reinterpret_cast<unsigned long *>(list), reinterpret_cast<void*>(fexldr_ptr_libX11_XSetIMValues)));
|
||||
return reinterpret_cast<char*>(libX11_Variadic_u64(reinterpret_cast<uint64_t>(a_0), count, list, reinterpret_cast<void*>(fexldr_ptr_libX11_XSetIMValues)));
|
||||
#else
|
||||
fprintf(stderr, "XSetIMValues_internal FAILURE\n");
|
||||
abort();
|
||||
@ -306,7 +343,9 @@ char* fexfn_impl_libX11_XSetIMValues_internal(XIM a_0, size_t count, void **list
|
||||
}
|
||||
}
|
||||
|
||||
XVaNestedList fexfn_impl_libX11_XVaCreateNestedList_internal(int unused_arg, size_t count, void** list) {
|
||||
XVaNestedList fexfn_impl_libX11_XVaCreateNestedList_internal(int unused_arg, size_t count, void **list) {
|
||||
FinalizeIncomingCallbacks<XIMCallback>(count, list);
|
||||
|
||||
switch(count) {
|
||||
case 0: return fexldr_ptr_libX11_XVaCreateNestedList(unused_arg, nullptr); break;
|
||||
case 1: return fexldr_ptr_libX11_XVaCreateNestedList(unused_arg, list[0], nullptr); break;
|
||||
@ -319,7 +358,7 @@ XVaNestedList fexfn_impl_libX11_XVaCreateNestedList_internal(int unused_arg, siz
|
||||
case 8: return fexldr_ptr_libX11_XVaCreateNestedList(unused_arg, list[0], list[1], list[2], list[3], list[4], list[5], list[6], list[7], nullptr); break;
|
||||
default:
|
||||
#ifdef _M_ARM_64
|
||||
return reinterpret_cast<XVaNestedList>(libX11_Variadic_u64(unused_arg, count, reinterpret_cast<unsigned long *>(list), reinterpret_cast<void*>(fexldr_ptr_libX11_XVaCreateNestedList)));
|
||||
return reinterpret_cast<XVaNestedList>(libX11_Variadic_u64(unused_arg, count, list, reinterpret_cast<void*>(fexldr_ptr_libX11_XVaCreateNestedList)));
|
||||
#else
|
||||
fprintf(stderr, "XVaCreateNestedList_internal FAILURE\n");
|
||||
abort();
|
||||
|
@ -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> {};
|
||||
|
Loading…
x
Reference in New Issue
Block a user