|
|
@@ -161,6 +161,11 @@ static void loc_touchinput_update (lglw_int_t *lglw); |
|
|
|
|
|
|
|
static void loc_enable_dropfiles (lglw_int_t *lglw, lglw_bool_t _bEnable); |
|
|
|
|
|
|
|
static void loc_eventProc (void *_xevent); |
|
|
|
static void loc_setProperty (Display *_display, Window _window, const char *_name, void *_value); |
|
|
|
static void *loc_getProperty (Display *_display, Window _window, const char *_name); |
|
|
|
static void loc_setEventProc (Display *display, Window window); |
|
|
|
|
|
|
|
|
|
|
|
// ---------------------------------------------------------------------------- module vars |
|
|
|
static lglw_int_t *khook_lglw = NULL; // currently key-hooked lglw instance (one at a time) |
|
|
@@ -173,6 +178,7 @@ static FILE *logfile; |
|
|
|
void lglw_log(const char *logData, ...) { |
|
|
|
fprintf(logfile, logData); |
|
|
|
fflush(logfile); |
|
|
|
printf(logData); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@@ -190,6 +196,8 @@ static int xerror_handler(Display *display, XErrorEvent *error) { |
|
|
|
lglw_t lglw_init(int32_t _w, int32_t _h) { |
|
|
|
lglw_int_t *lglw = malloc(sizeof(lglw_int_t)); |
|
|
|
|
|
|
|
printf("xxx lglw_init: sizeof(uint32_t)=%u sizeof(long)=%u sizeof(void*)=%u\n", sizeof(uint32_t), sizeof(long), sizeof(void*)); |
|
|
|
|
|
|
|
// TODO: remove/improve |
|
|
|
logfile = fopen("/tmp/lglw_log.txt", "w"); |
|
|
|
XSetErrorHandler(xerror_handler); |
|
|
@@ -351,9 +359,153 @@ static void loc_destroy_hidden_window(lglw_int_t *lglw) { |
|
|
|
// https://github.com/COx2/DistortionFilter/blob/c6a34fb56b503a6e95bf0975e00f438bbf4ff52a/juce/modules/juce_audio_processors/format_types/juce_VSTPluginFormat.cpp |
|
|
|
|
|
|
|
// Very simple function to test _XEventProc is properly called |
|
|
|
void loc_eventProc(void *xevent) { |
|
|
|
static void loc_eventProc(void *_xevent) { |
|
|
|
XEvent *xev = (XEvent*)_xevent; |
|
|
|
|
|
|
|
lglw_log("XEventProc\n"); |
|
|
|
printf("vstgltest<lglw_linux>: XEventProc\n"); |
|
|
|
printf("vstgltest<lglw_linux>: XEventProc, xev=%p\n", xev); |
|
|
|
|
|
|
|
if(NULL != xev) |
|
|
|
{ |
|
|
|
LGLW(loc_getProperty(xev->xany.display, xev->xany.window, "_lglw")); // get instance pointer |
|
|
|
|
|
|
|
printf("vstgltest<lglw_linux>: XEventProc, type=%d serial=%lu send_event=%d lglw=%p\n", xev->xany.type, xev->xany.serial, xev->xany.send_event, lglw); |
|
|
|
|
|
|
|
if(NULL != lglw) |
|
|
|
{ |
|
|
|
switch(xev->type) |
|
|
|
{ |
|
|
|
default: |
|
|
|
printf("vstgltest<lglw_linux>: unhandled X11 event type=%d\n", xev->type); |
|
|
|
break; |
|
|
|
|
|
|
|
case Expose: |
|
|
|
printf("vstgltest<lglw_linux>: xev Expose\n"); |
|
|
|
if(NULL != lglw->redraw.cbk) |
|
|
|
{ |
|
|
|
lglw->redraw.cbk(lglw); |
|
|
|
} |
|
|
|
break; |
|
|
|
|
|
|
|
case MotionNotify: |
|
|
|
printf("vstgltest<lglw_linux>: xev MotionNotify\n"); |
|
|
|
break; |
|
|
|
|
|
|
|
case KeyPress: |
|
|
|
printf("vstgltest<lglw_linux>: xev KeyPress\n"); |
|
|
|
lglw_redraw(lglw); |
|
|
|
break; |
|
|
|
|
|
|
|
case KeyRelease: |
|
|
|
printf("vstgltest<lglw_linux>: xev KeyRelease\n"); |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
static void loc_setProperty(Display *_display, Window _window, const char *_name, void *_value) { |
|
|
|
size_t data = (size_t)_value; |
|
|
|
long temp[2]; |
|
|
|
|
|
|
|
// Split the 64 bit pointer into a little-endian long array |
|
|
|
temp[0] = (long)(data & 0xffffffffUL); |
|
|
|
temp[1] = (long)(data >> 32L); |
|
|
|
|
|
|
|
printf("xxx lglw_linux:loc_setProperty: name=\"%s\" value=%p temp[0]=%08x temp[1]=%08x\n", _name, _value, temp[0], temp[1]); |
|
|
|
|
|
|
|
Atom atom = XInternAtom(_display, _name, False/*only_if_exists*/); |
|
|
|
|
|
|
|
// (note) what's quite weird here is that we're writing an array of 32bit values, yet the element format must be 64bit (long) |
|
|
|
XChangeProperty(_display, _window, |
|
|
|
atom/*property*/, |
|
|
|
atom/*type*/, |
|
|
|
32/*format*/, |
|
|
|
PropModeReplace/*mode*/, |
|
|
|
(unsigned char*)temp/*data*/, |
|
|
|
2/*nelements*/ |
|
|
|
); |
|
|
|
} |
|
|
|
|
|
|
|
static void *loc_getProperty(Display *_display, Window _window, const char *_name) { |
|
|
|
int userSize; |
|
|
|
unsigned long bytes; |
|
|
|
unsigned long userCount; |
|
|
|
unsigned char *data; |
|
|
|
Atom userType; |
|
|
|
Atom atom = XInternAtom(_display, _name, False); |
|
|
|
|
|
|
|
// (note) 64bit properties need to be read with two XGetWindowProperty() calls. |
|
|
|
// When using just one call and setting the 'length' to 2, the upper 32bit (second array element) will be 0xFFFFffff. |
|
|
|
XGetWindowProperty(_display, |
|
|
|
_window, |
|
|
|
atom, |
|
|
|
0/*offset*/, |
|
|
|
1/*length*/, |
|
|
|
False/*delete*/, |
|
|
|
AnyPropertyType, |
|
|
|
&userType/*actual_type_return*/, |
|
|
|
&userSize/*actual_format_return*/, |
|
|
|
&userCount/*nitems_return*/, |
|
|
|
&bytes/*bytes_after_return / partial reads*/, |
|
|
|
&data); |
|
|
|
|
|
|
|
union { |
|
|
|
uint32_t ui[2]; |
|
|
|
void *any; |
|
|
|
} uptr; |
|
|
|
uptr.any = 0; |
|
|
|
|
|
|
|
printf("xxx lglw_linux: loc_getProperty: LOWER userSize=%d userCount=%lu bytes=%lu data=%p\n", userSize, userCount, bytes, data); |
|
|
|
|
|
|
|
if(NULL != data) |
|
|
|
{ |
|
|
|
if(userCount >= 1) |
|
|
|
{ |
|
|
|
if(userCount >= 2) |
|
|
|
{ |
|
|
|
printf("xxx loc_getProperty: lo=0x%08x hi=0x%08x\n", ((uint32_t*)data)[0], ((uint32_t*)data)[1]); |
|
|
|
} |
|
|
|
|
|
|
|
// lower 32-bit |
|
|
|
uptr.ui[0] = *(long*)data; |
|
|
|
uptr.ui[1] = 0; |
|
|
|
|
|
|
|
printf("xxx lower=0x%08x\n", uptr.ui[0]); |
|
|
|
// // printf("xxx upper=0x%08x\n", uptr.ui[1]); |
|
|
|
|
|
|
|
XFree(data); |
|
|
|
|
|
|
|
// // if(userCount >= 2) |
|
|
|
{ |
|
|
|
XGetWindowProperty(_display, |
|
|
|
_window, |
|
|
|
atom, |
|
|
|
1/*offset*/, |
|
|
|
1/*length*/, |
|
|
|
False/*delete*/, |
|
|
|
AnyPropertyType, |
|
|
|
&userType/*actual_type_return*/, |
|
|
|
&userSize/*actual_format_return*/, |
|
|
|
&userCount/*nitems_return*/, |
|
|
|
&bytes/*bytes_after_return / partial reads*/, |
|
|
|
&data); |
|
|
|
|
|
|
|
printf("xxx lglw_linux: loc_getProperty: UPPER userSize=%d userCount=%lu bytes=%lu data=%p\n", userSize, userCount, bytes, data); |
|
|
|
if(NULL != data) |
|
|
|
{ |
|
|
|
// upper 32-bit |
|
|
|
uptr.ui[1] = *(long*)data; |
|
|
|
printf("xxx upper=0x%08x\n", uptr.ui[1]); |
|
|
|
XFree(data); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
printf("xxx lglw_linux: loc_getProperty: return value=%p\n", uptr.any); |
|
|
|
|
|
|
|
return uptr.any; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@@ -362,24 +514,30 @@ void loc_eventProc(void *xevent) { |
|
|
|
// Pulled from the Renoise 64-bit callback example |
|
|
|
// Unsure what data was supposed to be, but swapping it to a function name did not work |
|
|
|
// This does nothing, no event proc found |
|
|
|
void loc_setEventProc (Display *display, Window window) { |
|
|
|
static void loc_setEventProc (Display *display, Window window) { |
|
|
|
size_t data = (size_t)loc_eventProc; |
|
|
|
long temp[2]; |
|
|
|
|
|
|
|
printf("vstgltest<lglw_linux>: setEventProc (2*32bit). window=%lu loc_eventProc=%p\n", window, &loc_eventProc); |
|
|
|
|
|
|
|
// Split the 64 bit pointer into a little-endian long array |
|
|
|
temp[0] = (long)(data & 0xffffffffUL); |
|
|
|
temp[1] = (long)(data >> 32L); |
|
|
|
// Split the 64 bit pointer into a little-endian unsigned int array |
|
|
|
temp[0] = (uint32_t)(data & 0xffffffffUL); |
|
|
|
temp[1] = (uint32_t)(data >> 32L); |
|
|
|
|
|
|
|
Atom atom = XInternAtom(display, "_XEventProc", False); |
|
|
|
XChangeProperty(display, window, atom, atom, 32, |
|
|
|
PropModeReplace, (unsigned char*)temp, 2); |
|
|
|
XChangeProperty(display, window, |
|
|
|
atom/*property*/, |
|
|
|
atom/*type*/, |
|
|
|
32/*format*/, |
|
|
|
PropModeReplace/*mode*/, |
|
|
|
(unsigned char*)temp/*data*/, |
|
|
|
2/*nelements*/ |
|
|
|
); |
|
|
|
} |
|
|
|
#else |
|
|
|
// GPL code pulled from the amsynth example <https://github.com/amsynth/amsynth/blob/4a87798e650c6d71d70274a961c9b8d98fc6da7e/src/amsynth_vst.cpp> |
|
|
|
// Simply swapped out the function names, crashes Ardour in the same was as the others |
|
|
|
void loc_setEventProc (Display *display, Window window) { |
|
|
|
static void loc_setEventProc (Display *display, Window window) { |
|
|
|
// |
|
|
|
// JUCE calls XGetWindowProperty with long_length = 1 which means it only fetches the lower 32 bits of the address. |
|
|
|
// Therefore we need to ensure we return an address in the lower 32-bits of address space. |
|
|
@@ -412,20 +570,33 @@ void loc_setEventProc (Display *display, Window window) { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
long temp[2] = {(long)ptr, 0}; |
|
|
|
long temp[2] = {(uint32_t)(((size_t)ptr)&0xFFFFfffful), 0}; |
|
|
|
Atom atom = XInternAtom(display, "_XEventProc", False); |
|
|
|
XChangeProperty(display, window, atom, atom, 32, PropModeReplace, (unsigned char *)temp, 2); |
|
|
|
XChangeProperty(display, window, |
|
|
|
atom/*property*/, |
|
|
|
atom/*type*/, |
|
|
|
32/*format*/, |
|
|
|
PropModeReplace/*mode*/, |
|
|
|
(unsigned char *)temp/*data*/, |
|
|
|
2/*nelements*/ |
|
|
|
); |
|
|
|
} |
|
|
|
#endif |
|
|
|
#else |
|
|
|
// Pulled from the eXT2 example |
|
|
|
// TODO: 32-bit support |
|
|
|
void loc_setEventProc (Display *display, Window window) { |
|
|
|
static void loc_setEventProc (Display *display, Window window) { |
|
|
|
void* data = (void*)&loc_eventProc; // swapped the function name here |
|
|
|
|
|
|
|
// (note) 32-bit only |
|
|
|
Atom atom = XInternAtom(display, "_XEventProc", False); |
|
|
|
XChangeProperty(display, window, atom, atom, 32, |
|
|
|
PropModeReplace, (unsigned char*)&data, 1); // 1 instead of 2 will crash Ardour, 2 will not do anything |
|
|
|
XChangeProperty(display, window, |
|
|
|
atom/*property*/, |
|
|
|
atom/*type*/, |
|
|
|
32/*format*/, |
|
|
|
PropModeReplace/*mode*/, |
|
|
|
(unsigned char*)&data/*data*/, |
|
|
|
1/*nelements*/ |
|
|
|
); |
|
|
|
} |
|
|
|
#endif // ARCH_X64 |
|
|
|
|
|
|
@@ -437,10 +608,10 @@ lglw_bool_t lglw_window_open (lglw_t _lglw, void *_parentHWNDOrNull, int32_t _x, |
|
|
|
|
|
|
|
if(NULL != lglw) |
|
|
|
{ |
|
|
|
lglw_log("lglw:lglw_window_open: 1, %p, %i\n", (Window)_parentHWNDOrNull, (Window)_parentHWNDOrNull); |
|
|
|
lglw_log("lglw:lglw_window_open: 1, %p, %i \n", (Window)_parentHWNDOrNull, (Window)_parentHWNDOrNull); |
|
|
|
lglw->parent_xwnd = (0 == _parentHWNDOrNull) ? DefaultRootWindow(lglw->xdsp) : (Window)_parentHWNDOrNull; |
|
|
|
|
|
|
|
lglw_log("lglw:lglw_window_open: 2\n"); |
|
|
|
lglw_log("lglw:lglw_window_open: 2 lglw=%p\n", lglw); |
|
|
|
if(_w <= 16) |
|
|
|
_w = lglw->hidden.size.x; |
|
|
|
|
|
|
@@ -452,7 +623,7 @@ lglw_bool_t lglw_window_open (lglw_t _lglw, void *_parentHWNDOrNull, int32_t _x, |
|
|
|
|
|
|
|
lglw_log("lglw:lglw_window_open: 4\n"); |
|
|
|
XSetWindowAttributes swa; |
|
|
|
XEvent event; |
|
|
|
// // XEvent event; |
|
|
|
XSync(lglw->xdsp, False); |
|
|
|
|
|
|
|
#if 1 |
|
|
@@ -508,7 +679,13 @@ lglw_bool_t lglw_window_open (lglw_t _lglw, void *_parentHWNDOrNull, int32_t _x, |
|
|
|
// It was simpler to do this than check in the debug host for the reparent event |
|
|
|
lglw_log("lglw:lglw_window_open: 8\n"); |
|
|
|
loc_setEventProc(lglw->xdsp, lglw->win.xwnd); |
|
|
|
loc_setEventProc(lglw->xdsp, lglw->parent_xwnd); |
|
|
|
|
|
|
|
if(NULL != _parentHWNDOrNull) |
|
|
|
{ |
|
|
|
loc_setEventProc(lglw->xdsp, lglw->parent_xwnd); |
|
|
|
loc_setProperty(lglw->xdsp, lglw->parent_xwnd, "_lglw", (void*)lglw); // set instance pointer |
|
|
|
} |
|
|
|
loc_setProperty(lglw->xdsp, lglw->win.xwnd, "_lglw", (void*)lglw); // set instance pointer |
|
|
|
|
|
|
|
lglw_log("lglw:lglw_window_open: 9\n"); |
|
|
|
if(lglw->win.b_owner) |
|
|
@@ -548,6 +725,8 @@ lglw_bool_t lglw_window_open (lglw_t _lglw, void *_parentHWNDOrNull, int32_t _x, |
|
|
|
loc_enable_dropfiles(lglw, (NULL != lglw->dropfiles.cbk)); |
|
|
|
|
|
|
|
lglw_log("lglw:lglw_window_open: EXIT\n"); |
|
|
|
|
|
|
|
r = LGLW_TRUE; |
|
|
|
} |
|
|
|
return r; |
|
|
|
} |
|
|
@@ -725,7 +904,23 @@ void lglw_redraw(lglw_t _lglw) { |
|
|
|
{ |
|
|
|
// TODO Event Loop |
|
|
|
lglw_log("lglw:lglw_redraw: 1\n"); |
|
|
|
XClearArea(lglw->xdsp, lglw->win.xwnd, 0, 0, 1, 1, True); // clear tiny area for exposing |
|
|
|
// XClearArea(lglw->xdsp, lglw->win.xwnd, 0, 0, 1, 1, True); // clear tiny area for exposing |
|
|
|
XEvent xev; |
|
|
|
xev.xany.type = Expose; |
|
|
|
xev.xany.serial = 0; |
|
|
|
xev.xany.send_event = True; |
|
|
|
xev.xany.display = lglw->xdsp; |
|
|
|
xev.xany.window = lglw->win.xwnd; |
|
|
|
xev.xexpose.x = 0; |
|
|
|
xev.xexpose.y = 0; |
|
|
|
xev.xexpose.width = lglw->win.size.x; |
|
|
|
xev.xexpose.height = lglw->win.size.y; |
|
|
|
xev.xexpose.count = 0; |
|
|
|
XSendEvent(lglw->xdsp, lglw->win.xwnd, |
|
|
|
True/*propagate*/, |
|
|
|
ExposureMask/*event_mask*/, |
|
|
|
&xev |
|
|
|
); |
|
|
|
XFlush(lglw->xdsp); |
|
|
|
} |
|
|
|
} |
|
|
@@ -802,7 +997,7 @@ void lglw_swap_interval_set(lglw_t _lglw, int32_t _ival) { |
|
|
|
{ |
|
|
|
lglw_log("lglw:lglw_swap_interval_set: 1\n"); |
|
|
|
PFNWGLEXTSWAPINTERVALPROC glXSwapIntervalEXT; |
|
|
|
glXSwapIntervalEXT = (PFNWGLEXTSWAPINTERVALPROC) glXGetProcAddress("glXSwapIntervalEXT"); |
|
|
|
glXSwapIntervalEXT = (PFNWGLEXTSWAPINTERVALPROC) glXGetProcAddress((const GLubyte*)"glXSwapIntervalEXT"); |
|
|
|
if(NULL != glXSwapIntervalEXT) |
|
|
|
{ |
|
|
|
lglw_log("lglw:lglw_swap_interval_set: 2\n"); |
|
|
@@ -1199,6 +1394,7 @@ void lglw_clipboard_text_set(lglw_t _lglw, const uint32_t _numChars, const char |
|
|
|
|
|
|
|
if(NULL != _text) |
|
|
|
{ |
|
|
|
(void)lglw; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
@@ -1218,6 +1414,7 @@ void lglw_clipboard_text_get(lglw_t _lglw, uint32_t _maxChars, uint32_t *_retNum |
|
|
|
if(NULL != _lglw) |
|
|
|
{ |
|
|
|
// (todo) implement me |
|
|
|
(void)lglw; |
|
|
|
} |
|
|
|
} |
|
|
|
} |