You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1600 lines
51KB

  1. /* ----
  2. * ---- file : lglw_linux.c (**stub**)
  3. * ---- author : bsp
  4. * ---- legal : Distributed under terms of the MIT LICENSE (MIT).
  5. * ----
  6. * ---- Permission is hereby granted, free of charge, to any person obtaining a copy
  7. * ---- of this software and associated documentation files (the "Software"), to deal
  8. * ---- in the Software without restriction, including without limitation the rights
  9. * ---- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10. * ---- copies of the Software, and to permit persons to whom the Software is
  11. * ---- furnished to do so, subject to the following conditions:
  12. * ----
  13. * ---- The above copyright notice and this permission notice shall be included in
  14. * ---- all copies or substantial portions of the Software.
  15. * ----
  16. * ---- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17. * ---- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18. * ---- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  19. * ---- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20. * ---- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21. * ---- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22. * ---- THE SOFTWARE.
  23. * ----
  24. * ---- info : This is part of the "lglw" package.
  25. * ----
  26. * ---- created: 04Aug2018
  27. * ---- changed: 05Aug2018, 06Aug2018, 07Aug2018, 08Aug2018, 09Aug2018, 18Aug2018, 10Oct2018, 16Oct2018
  28. * ----
  29. * ----
  30. */
  31. #include "lglw.h"
  32. #include <stdlib.h>
  33. #include <stdio.h>
  34. #include <string.h>
  35. #include <X11/Xlib.h>
  36. #include <X11/Xutil.h>
  37. #include <X11/Xos.h>
  38. #include <GL/gl.h>
  39. #include <GL/glx.h>
  40. #ifdef ARCH_X64
  41. #include <sys/mman.h>
  42. #include <unistd.h>
  43. #endif // ARCH_X64
  44. #define Dprintf if(0);else printf
  45. // #define Dprintf if(1);else printf
  46. // ---------------------------------------------------------------------------- macros and defines
  47. #define LGLW(a) lglw_int_t *lglw = ((lglw_int_t*)(a))
  48. #define LGLW_DEFAULT_HIDDEN_W (800)
  49. #define LGLW_DEFAULT_HIDDEN_H (600)
  50. #define LGLW_MOUSE_TOUCH_LMB_TIMEOUT (250u)
  51. #define LGLW_MOUSE_TOUCH_RMB_TIMEOUT (500u)
  52. #define LGLW_MOUSE_TOUCH_RMB_STATE_IDLE (0u)
  53. #define LGLW_MOUSE_TOUCH_RMB_STATE_LMB (1u)
  54. #define LGLW_MOUSE_TOUCH_RMB_STATE_WAIT (2u)
  55. #define LGLW_MOUSE_TOUCH_RMB_STATE_RMB (3u)
  56. #define LGLW_MOUSE_TOUCH_RMB_MOVE_THRESHOLD (7u)
  57. #define sABS(x) (((x)>0)?(x):-(x))
  58. // ---------------------------------------------------------------------------- structs and typedefs
  59. typedef struct lglw_int_s {
  60. void *user_data; // arbitrary user data
  61. Display *xdsp;
  62. XVisualInfo *vi;
  63. Colormap cmap;
  64. Window parent_xwnd; // created by host
  65. struct {
  66. lglw_vec2i_t size;
  67. Window xwnd;
  68. } hidden;
  69. struct {
  70. lglw_vec2i_t size;
  71. Window xwnd;
  72. lglw_bool_t mapped;
  73. int32_t swap_interval;
  74. lglw_bool_t b_owner;
  75. } win;
  76. GLXContext ctx;
  77. struct {
  78. GLXContext ctx;
  79. GLXDrawable drw;
  80. } prev;
  81. struct {
  82. uint32_t kmod_state; // See LGLW_KMOD_xxx
  83. lglw_keyboard_fxn_t cbk;
  84. } keyboard;
  85. struct {
  86. lglw_vec2i_t p; // last seen mouse position
  87. uint32_t button_state;
  88. lglw_mouse_fxn_t cbk;
  89. struct {
  90. uint32_t mode;
  91. lglw_vec2i_t p; // grab-start mouse position
  92. lglw_bool_t b_queue_warp;
  93. lglw_vec2i_t last_p;
  94. } grab;
  95. struct {
  96. lglw_bool_t b_enable;
  97. lglw_bool_t b_update_queued;
  98. lglw_bool_t b_syn_rmb;
  99. uint32_t syn_rmb_hold_state; // see LGLW_MOUSE_TOUCH_RMB_STATE_xxx
  100. uint32_t hold_start_ms;
  101. lglw_vec2i_t hold_start_p;
  102. } touch;
  103. } mouse;
  104. struct {
  105. uint32_t state;
  106. lglw_focus_fxn_t cbk;
  107. } focus;
  108. struct {
  109. lglw_bool_t b_running;
  110. lglw_timer_fxn_t cbk;
  111. } timer;
  112. struct {
  113. lglw_dropfiles_fxn_t cbk;
  114. } dropfiles;
  115. struct {
  116. lglw_redraw_fxn_t cbk;
  117. } redraw;
  118. } lglw_int_t;
  119. // ---------------------------------------------------------------------------- module fxn fwd decls
  120. static lglw_bool_t loc_create_hidden_window (lglw_int_t *lglw, int32_t _w, int32_t _h);
  121. static void loc_destroy_hidden_window(lglw_int_t *lglw);
  122. static void loc_key_hook(lglw_int_t *lglw);
  123. static void loc_key_unhook(lglw_int_t *lglw);
  124. static lglw_bool_t loc_handle_key (lglw_int_t *lglw, lglw_bool_t _bPressed, uint32_t _vkey);
  125. // static lglw_bool_t loc_touchkeyboard_get_rect (RECT *rect);
  126. // static lglw_bool_t loc_touchkeyboard_is_visible (void);
  127. extern lglw_bool_t lglw_int_touchkeyboard_toggle (void);
  128. static void loc_handle_mouseleave (lglw_int_t *lglw);
  129. static void loc_handle_mouseenter (lglw_int_t *lglw);
  130. static void loc_handle_mousebutton (lglw_int_t *lglw, lglw_bool_t _bPressed, uint32_t _button);
  131. static void loc_handle_mousemotion (lglw_int_t *lglw);
  132. static void loc_handle_queued_mouse_warp (lglw_int_t *lglw);
  133. static void loc_touchinput_update (lglw_int_t *lglw);
  134. static void loc_enable_dropfiles (lglw_int_t *lglw, lglw_bool_t _bEnable);
  135. static void loc_eventProc (void *_xevent);
  136. static void loc_setProperty (Display *_display, Window _window, const char *_name, void *_value);
  137. static void *loc_getProperty (Display *_display, Window _window, const char *_name);
  138. static void loc_setEventProc (Display *display, Window window);
  139. // ---------------------------------------------------------------------------- module vars
  140. static lglw_int_t *khook_lglw = NULL; // currently key-hooked lglw instance (one at a time)
  141. // TODO: remove and/or improve debug logging for a debug build
  142. // ---------------------------------------------------------------------------- lglw_log
  143. static FILE *logfile;
  144. void lglw_log(const char *logData, ...) {
  145. fprintf(logfile, logData);
  146. fflush(logfile);
  147. printf(logData);
  148. }
  149. // TODO: remove, or maybe not in some specific use cases
  150. // ---------------------------------------------------------------------------- xerror_log
  151. static int xerror_handler(Display *display, XErrorEvent *error) {
  152. char error_text[1024];
  153. XGetErrorText(display, error->error_code, error_text, 1024);
  154. lglw_log("XERROR (%d): %s, %d, %d\n", error->error_code, error_text, error->request_code, error->minor_code);
  155. return 0;
  156. }
  157. // ---------------------------------------------------------------------------- lglw_init
  158. lglw_t lglw_init(int32_t _w, int32_t _h) {
  159. lglw_int_t *lglw = malloc(sizeof(lglw_int_t));
  160. printf("xxx lglw_init: sizeof(uint32_t)=%u sizeof(long)=%u sizeof(void*)=%u\n", sizeof(uint32_t), sizeof(long), sizeof(void*));
  161. // TODO: remove/improve
  162. logfile = fopen("/tmp/lglw_log.txt", "w");
  163. XSetErrorHandler(xerror_handler);
  164. XInitThreads(); // fix GL crash, see <https://forum.juce.com/t/linux-vst-opengl-crash-because-xinitthreads-not-called/22821>
  165. if(NULL != lglw)
  166. {
  167. memset(lglw, 0, sizeof(lglw_int_t));
  168. lglw_log("lglw:lglw_init: 1\n");
  169. if(_w <= 16)
  170. _w = LGLW_DEFAULT_HIDDEN_W;
  171. if(_h <= 16)
  172. _h = LGLW_DEFAULT_HIDDEN_H;
  173. lglw_log("lglw:lglw_init: 2\n");
  174. if(!loc_create_hidden_window(lglw, _w, _h))
  175. {
  176. free(lglw);
  177. lglw = NULL;
  178. }
  179. lglw_log("lglw:lglw_init: 3\n");
  180. }
  181. lglw_log("lglw:lglw_init: EXIT\n");
  182. return lglw;
  183. }
  184. // ---------------------------------------------------------------------------- lglw_exit
  185. void lglw_exit(lglw_t _lglw) {
  186. LGLW(_lglw);
  187. if(NULL != lglw)
  188. {
  189. lglw_log("lglw:lglw_exit: 1\n");
  190. loc_destroy_hidden_window(lglw);
  191. lglw_log("lglw:lglw_exit: 2\n");
  192. fclose(logfile);
  193. free(lglw);
  194. }
  195. }
  196. // ---------------------------------------------------------------------------- lglw_userdata_set
  197. void lglw_userdata_set(lglw_t _lglw, void *_userData) {
  198. LGLW(_lglw);
  199. if(NULL != lglw)
  200. {
  201. lglw_log("lglw:lglw_userdata_set: 1\n");
  202. lglw->user_data = _userData;
  203. }
  204. }
  205. // ---------------------------------------------------------------------------- lglw_userdata_get
  206. void *lglw_userdata_get(lglw_t _lglw) {
  207. LGLW(_lglw);
  208. if(NULL != lglw)
  209. {
  210. lglw_log("lglw:lglw_userdata_get: 1\n");
  211. return lglw->user_data;
  212. }
  213. return NULL;
  214. }
  215. // ---------------------------------------------------------------------------- loc_create_hidden_window
  216. static lglw_bool_t loc_create_hidden_window(lglw_int_t *lglw, int32_t _w, int32_t _h) {
  217. // TODO: compare to 'WindowClass' from Windows implementation
  218. lglw_log("lglw:loc_create_hidden_window: 1\n");
  219. XSetWindowAttributes swa;
  220. int attrib[] = { GLX_RGBA, GLX_DOUBLEBUFFER, GLX_DEPTH_SIZE, 24, None };
  221. int screen;
  222. lglw_log("lglw:loc_create_hidden_window: 2\n");
  223. lglw->xdsp = XOpenDisplay(NULL);
  224. screen = DefaultScreen(lglw->xdsp);
  225. lglw_log("lglw:loc_create_hidden_window: 3\n");
  226. lglw->vi = glXChooseVisual(lglw->xdsp, screen, attrib);
  227. lglw_log("lglw:loc_create_hidden_window: 4\n");
  228. if(NULL == lglw->vi)
  229. {
  230. lglw_log("[---] lglw: failed to find GLX Visual for hidden window\n");
  231. return LGLW_FALSE;
  232. }
  233. lglw_log("lglw:loc_create_hidden_window: 5\n");
  234. lglw->ctx = glXCreateContext(lglw->xdsp, lglw->vi, None, True);
  235. lglw_log("lglw:loc_create_hidden_window: 6\n");
  236. if(NULL == lglw->ctx)
  237. {
  238. lglw_log("[---] lglw: failed to create GLX Context for hidden window\n");
  239. return LGLW_FALSE;
  240. }
  241. lglw_log("lglw:loc_create_hidden_window: 7\n");
  242. lglw->cmap = XCreateColormap(lglw->xdsp, RootWindow(lglw->xdsp, lglw->vi->screen),
  243. lglw->vi->visual, AllocNone);
  244. lglw_log("lglw:loc_create_hidden_window: 8\n");
  245. swa.border_pixel = 0;
  246. swa.colormap = lglw->cmap;
  247. lglw->hidden.xwnd = XCreateWindow(lglw->xdsp, DefaultRootWindow(lglw->xdsp),
  248. 0, 0, LGLW_DEFAULT_HIDDEN_W, LGLW_DEFAULT_HIDDEN_H, 0, CopyFromParent, InputOutput,
  249. lglw->vi->visual, CWBorderPixel | CWColormap, &swa);
  250. lglw_log("lglw:loc_create_hidden_window: 9\n");
  251. XSetStandardProperties(lglw->xdsp, lglw->hidden.xwnd, "LGLW_hidden", "LGLW_hidden", None, NULL, 0, NULL);
  252. XSync(lglw->xdsp, False);
  253. lglw_log("lglw:loc_create_hidden_window: EXIT\n");
  254. lglw->hidden.size.x = _w;
  255. lglw->hidden.size.y = _h;
  256. return LGLW_TRUE;
  257. }
  258. // ---------------------------------------------------------------------------- loc_destroy_hidden_window
  259. static void loc_destroy_hidden_window(lglw_int_t *lglw) {
  260. lglw_log("lglw:loc_destroy_hidden_window: 1\n");
  261. if(NULL != lglw->xdsp && NULL != lglw->ctx)
  262. {
  263. glXMakeCurrent(lglw->xdsp, None, NULL);
  264. glXDestroyContext(lglw->xdsp, lglw->ctx);
  265. }
  266. lglw_log("lglw:loc_destroy_hidden_window: 2\n");
  267. if(NULL != lglw->xdsp && 0 != lglw->hidden.xwnd) XDestroyWindow(lglw->xdsp, lglw->hidden.xwnd);
  268. lglw_log("lglw:loc_destroy_hidden_window: 3\n");
  269. if(NULL != lglw->xdsp && 0 != lglw->cmap) XFreeColormap(lglw->xdsp, lglw->cmap);
  270. lglw_log("lglw:loc_destroy_hidden_window: 4\n");
  271. if(NULL != lglw->vi) XFree(lglw->vi);
  272. lglw_log("lglw:loc_destroy_hidden_window: 5\n");
  273. XSync(lglw->xdsp, False);
  274. if(NULL != lglw->xdsp) XCloseDisplay(lglw->xdsp);
  275. }
  276. // ---------------------------------------------------------------------------- loc_setEventProc
  277. // https://www.kvraudio.com/forum/viewtopic.php?t=387924
  278. // https://github.com/Ardour/ardour/blob/master/gtk2_ardour/linux_vst_gui_support.cc
  279. // https://discourse.ardour.org/t/overtonedsp-plugins/90115/22
  280. // https://github.com/amsynth/amsynth/blob/4a87798e650c6d71d70274a961c9b8d98fc6da7e/src/amsynth_vst.cpp
  281. // https://github.com/rsenn/eXT2/blob/7f00a09561ded8175ffed2f4912dad74e466a1c7/vstplugins/vstgui/vstgui.cpp
  282. // https://github.com/COx2/DistortionFilter/blob/c6a34fb56b503a6e95bf0975e00f438bbf4ff52a/juce/modules/juce_audio_processors/format_types/juce_VSTPluginFormat.cpp
  283. // Very simple function to test _XEventProc is properly called
  284. static void loc_eventProc(void *_xevent) {
  285. XEvent *xev = (XEvent*)_xevent;
  286. lglw_log("XEventProc\n");
  287. printf("vstgltest<lglw_linux>: XEventProc, xev=%p\n", xev);
  288. if(NULL != xev)
  289. {
  290. LGLW(loc_getProperty(xev->xany.display, xev->xany.window, "_lglw")); // get instance pointer
  291. 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);
  292. if(NULL != lglw)
  293. {
  294. switch(xev->type)
  295. {
  296. default:
  297. printf("vstgltest<lglw_linux>: unhandled X11 event type=%d\n", xev->type);
  298. break;
  299. case Expose:
  300. printf("vstgltest<lglw_linux>: xev Expose\n");
  301. if(NULL != lglw->redraw.cbk)
  302. {
  303. lglw->redraw.cbk(lglw);
  304. }
  305. break;
  306. case FocusIn:
  307. printf("vstgltest<lglw_linux>: xev FocusIn\n");
  308. break;
  309. case FocusOut:
  310. printf("vstgltest<lglw_linux>: xev FocusOut\n");
  311. break;
  312. case EnterNotify:
  313. // printf("vstgltest<lglw_linux>: xev XEnterWindowEvent\n");
  314. ; // empty statement
  315. XEnterWindowEvent *wenter = (XEnterWindowEvent*)xev;
  316. printf("vstgltest<lglw_linux>: xev EnterNotify: mode:%i, detail:%i, state:%d\n", wenter->mode, wenter->detail, wenter->state);
  317. lglw->mouse.p.x = wenter->x;
  318. lglw->mouse.p.y = wenter->y;
  319. loc_handle_mousemotion(lglw);
  320. // EnterNotify messages can be pseudo-motion events (NotifyGrab, NotifyUngrab)
  321. // when buttons are pressed, which would trigger false focus changes
  322. // so, the callback is only sent when a normal entry happens
  323. if (wenter->mode == NotifyNormal)
  324. {
  325. loc_handle_mouseenter(lglw);
  326. }
  327. break;
  328. case LeaveNotify:
  329. // printf("vstgltest<lglw_linux>: xev XLeaveWindowEvent\n");
  330. ; // empty statement
  331. XLeaveWindowEvent *wexit = (XLeaveWindowEvent*)xev;
  332. printf("vstgltest<lglw_linux>: xev LeaveNotify: mode:%i, detail:%i, state:%d\n", wexit->mode, wexit->detail, wexit->state);
  333. // LeaveNotify messages can be pseudo-motion events (NotifyGrab, NotifyUngrab)
  334. // when buttons are pressed, which would trigger false focus changes
  335. // so, the callback is only sent when a normal entry happens
  336. if (wexit->mode == NotifyNormal)
  337. {
  338. loc_handle_mouseleave(lglw);
  339. }
  340. break;
  341. case MotionNotify:
  342. // printf("vstgltest<lglw_linux>: xev MotionNotify\n");
  343. ; // empty statement
  344. XMotionEvent *motion = (XMotionEvent*)xev;
  345. if(LGLW_MOUSE_GRAB_WARP == lglw->mouse.grab.mode)
  346. {
  347. lglw->mouse.grab.b_queue_warp = LGLW_TRUE;
  348. lglw->mouse.p.x += (motion->x - lglw->mouse.grab.last_p.x);
  349. lglw->mouse.p.y += (motion->y - lglw->mouse.grab.last_p.y);
  350. lglw->mouse.grab.last_p.x = motion->x;
  351. lglw->mouse.grab.last_p.y = motion->y;
  352. }
  353. else
  354. {
  355. lglw->mouse.p.x = motion->x;
  356. lglw->mouse.p.y = motion->y;
  357. }
  358. loc_handle_mousemotion(lglw);
  359. break;
  360. case KeyPress:
  361. printf("vstgltest<lglw_linux>: xev KeyPress\n");
  362. lglw_redraw(lglw);
  363. break;
  364. case KeyRelease:
  365. printf("vstgltest<lglw_linux>: xev KeyRelease\n");
  366. break;
  367. case ButtonPress:
  368. printf("vstgltest<lglw_linux>: xev ButtonPress\n");
  369. XButtonPressedEvent *btnPress = (XButtonPressedEvent*)xev;
  370. lglw->mouse.p.x = btnPress->x;
  371. lglw->mouse.p.y = btnPress->y;
  372. if(0u == (lglw->focus.state & LGLW_FOCUS_MOUSE))
  373. {
  374. loc_handle_mouseenter(lglw);
  375. }
  376. switch(btnPress->button)
  377. {
  378. default:
  379. printf("vstgltest<lglw_linux>: xev ButtonPress unhandled button: %i\n", btnPress->button);
  380. break;
  381. case Button1:
  382. loc_handle_mousebutton(lglw, LGLW_TRUE/*bPressed*/, LGLW_MOUSE_LBUTTON);
  383. break;
  384. case Button2:
  385. loc_handle_mousebutton(lglw, LGLW_TRUE/*bPressed*/, LGLW_MOUSE_RBUTTON);
  386. break;
  387. case Button3:
  388. loc_handle_mousebutton(lglw, LGLW_TRUE/*bPressed*/, LGLW_MOUSE_MBUTTON);
  389. break;
  390. case Button4:
  391. loc_handle_mousebutton(lglw, LGLW_TRUE/*bPressed*/, LGLW_MOUSE_WHEELUP);
  392. break;
  393. case Button5:
  394. loc_handle_mousebutton(lglw, LGLW_TRUE/*bPressed*/, LGLW_MOUSE_WHEELDOWN);
  395. break;
  396. }
  397. break;
  398. case ButtonRelease:
  399. printf("vstgltest<lglw_linux>: xev ButtonRelease\n");
  400. XButtonReleasedEvent *btnRelease = (XButtonReleasedEvent*)xev;
  401. lglw->mouse.p.x = btnRelease->x;
  402. lglw->mouse.p.y = btnRelease->y;
  403. switch(btnRelease->button)
  404. {
  405. default:
  406. printf("vstgltest<lglw_linux>: xev ButtonRelease unhandled button: %i\n", btnRelease->button);
  407. break;
  408. case Button1:
  409. loc_handle_mousebutton(lglw, LGLW_FALSE/*bPressed*/, LGLW_MOUSE_LBUTTON);
  410. break;
  411. case Button2:
  412. loc_handle_mousebutton(lglw, LGLW_FALSE/*bPressed*/, LGLW_MOUSE_RBUTTON);
  413. break;
  414. case Button3:
  415. loc_handle_mousebutton(lglw, LGLW_FALSE/*bPressed*/, LGLW_MOUSE_MBUTTON);
  416. break;
  417. case Button4:
  418. loc_handle_mousebutton(lglw, LGLW_FALSE/*bPressed*/, LGLW_MOUSE_WHEELUP);
  419. break;
  420. case Button5:
  421. loc_handle_mousebutton(lglw, LGLW_FALSE/*bPressed*/, LGLW_MOUSE_WHEELDOWN);
  422. break;
  423. }
  424. break;
  425. }
  426. }
  427. }
  428. }
  429. static void loc_setProperty(Display *_display, Window _window, const char *_name, void *_value) {
  430. size_t data = (size_t)_value;
  431. long temp[2];
  432. // Split the 64 bit pointer into a little-endian long array
  433. temp[0] = (long)(data & 0xffffffffUL);
  434. temp[1] = (long)(data >> 32L);
  435. printf("xxx lglw_linux:loc_setProperty: name=\"%s\" value=%p temp[0]=%08x temp[1]=%08x\n", _name, _value, temp[0], temp[1]);
  436. Atom atom = XInternAtom(_display, _name, False/*only_if_exists*/);
  437. // (note) what's quite weird here is that we're writing an array of 32bit values, yet the element format must be 64bit (long)
  438. XChangeProperty(_display, _window,
  439. atom/*property*/,
  440. atom/*type*/,
  441. 32/*format*/,
  442. PropModeReplace/*mode*/,
  443. (unsigned char*)temp/*data*/,
  444. 2/*nelements*/
  445. );
  446. }
  447. static void *loc_getProperty(Display *_display, Window _window, const char *_name) {
  448. int userSize;
  449. unsigned long bytes;
  450. unsigned long userCount;
  451. unsigned char *data;
  452. Atom userType;
  453. Atom atom = XInternAtom(_display, _name, False);
  454. // (note) 64bit properties need to be read with two XGetWindowProperty() calls.
  455. // When using just one call and setting the 'length' to 2, the upper 32bit (second array element) will be 0xFFFFffff.
  456. XGetWindowProperty(_display,
  457. _window,
  458. atom,
  459. 0/*offset*/,
  460. 1/*length*/,
  461. False/*delete*/,
  462. AnyPropertyType,
  463. &userType/*actual_type_return*/,
  464. &userSize/*actual_format_return*/,
  465. &userCount/*nitems_return*/,
  466. &bytes/*bytes_after_return / partial reads*/,
  467. &data);
  468. union {
  469. uint32_t ui[2];
  470. void *any;
  471. } uptr;
  472. uptr.any = 0;
  473. printf("xxx lglw_linux: loc_getProperty: LOWER userSize=%d userCount=%lu bytes=%lu data=%p\n", userSize, userCount, bytes, data);
  474. if(NULL != data)
  475. {
  476. if(userCount >= 1)
  477. {
  478. if(userCount >= 2)
  479. {
  480. printf("xxx loc_getProperty: lo=0x%08x hi=0x%08x\n", ((uint32_t*)data)[0], ((uint32_t*)data)[1]);
  481. }
  482. // lower 32-bit
  483. uptr.ui[0] = *(long*)data;
  484. uptr.ui[1] = 0;
  485. printf("xxx lower=0x%08x\n", uptr.ui[0]);
  486. // // printf("xxx upper=0x%08x\n", uptr.ui[1]);
  487. XFree(data);
  488. // // if(userCount >= 2)
  489. {
  490. XGetWindowProperty(_display,
  491. _window,
  492. atom,
  493. 1/*offset*/,
  494. 1/*length*/,
  495. False/*delete*/,
  496. AnyPropertyType,
  497. &userType/*actual_type_return*/,
  498. &userSize/*actual_format_return*/,
  499. &userCount/*nitems_return*/,
  500. &bytes/*bytes_after_return / partial reads*/,
  501. &data);
  502. printf("xxx lglw_linux: loc_getProperty: UPPER userSize=%d userCount=%lu bytes=%lu data=%p\n", userSize, userCount, bytes, data);
  503. if(NULL != data)
  504. {
  505. // upper 32-bit
  506. uptr.ui[1] = *(long*)data;
  507. printf("xxx upper=0x%08x\n", uptr.ui[1]);
  508. XFree(data);
  509. }
  510. }
  511. }
  512. }
  513. printf("xxx lglw_linux: loc_getProperty: return value=%p\n", uptr.any);
  514. return uptr.any;
  515. }
  516. #ifdef ARCH_X64
  517. #if 0
  518. // Pulled from the Renoise 64-bit callback example
  519. // Unsure what data was supposed to be, but swapping it to a function name did not work
  520. // This does nothing, no event proc found
  521. static void loc_setEventProc (Display *display, Window window) {
  522. size_t data = (size_t)loc_eventProc;
  523. long temp[2];
  524. printf("vstgltest<lglw_linux>: setEventProc (2*32bit). window=%lu loc_eventProc=%p\n", window, &loc_eventProc);
  525. // Split the 64 bit pointer into a little-endian unsigned int array
  526. temp[0] = (uint32_t)(data & 0xffffffffUL);
  527. temp[1] = (uint32_t)(data >> 32L);
  528. Atom atom = XInternAtom(display, "_XEventProc", False);
  529. XChangeProperty(display, window,
  530. atom/*property*/,
  531. atom/*type*/,
  532. 32/*format*/,
  533. PropModeReplace/*mode*/,
  534. (unsigned char*)temp/*data*/,
  535. 2/*nelements*/
  536. );
  537. }
  538. #else
  539. // GPL code pulled from the amsynth example <https://github.com/amsynth/amsynth/blob/4a87798e650c6d71d70274a961c9b8d98fc6da7e/src/amsynth_vst.cpp>
  540. // Simply swapped out the function names, crashes Ardour in the same was as the others
  541. static void loc_setEventProc (Display *display, Window window) {
  542. //
  543. // JUCE calls XGetWindowProperty with long_length = 1 which means it only fetches the lower 32 bits of the address.
  544. // Therefore we need to ensure we return an address in the lower 32-bits of address space.
  545. //
  546. // based on mach_override
  547. static const unsigned char kJumpInstructions[] = {
  548. 0xFF, 0x25, 0x00, 0x00, 0x00, 0x00,
  549. 0x00, 0x00, 0x00, 0x00,
  550. 0x00, 0x00, 0x00, 0x00
  551. };
  552. static const int kJumpAddress = 6;
  553. static char *ptr = 0;
  554. if (!ptr) {
  555. ptr = (char *)mmap(0,
  556. getpagesize()/*PAGE_SIZE*/,
  557. PROT_READ | PROT_WRITE | PROT_EXEC,
  558. MAP_ANONYMOUS | MAP_PRIVATE | MAP_32BIT,
  559. 0, 0);
  560. if (ptr == MAP_FAILED) {
  561. perror("mmap");
  562. ptr = 0;
  563. return;
  564. } else {
  565. memcpy(ptr, kJumpInstructions, sizeof(kJumpInstructions));
  566. *((uint64_t *)(ptr + kJumpAddress)) = (uint64_t)(&loc_eventProc);
  567. msync(ptr, sizeof(kJumpInstructions), MS_INVALIDATE);
  568. printf("vstgltest<lglw_linux>: 64bit trampoline installed\n");
  569. }
  570. }
  571. long temp[2] = {(uint32_t)(((size_t)ptr)&0xFFFFfffful), 0};
  572. Atom atom = XInternAtom(display, "_XEventProc", False);
  573. XChangeProperty(display, window,
  574. atom/*property*/,
  575. atom/*type*/,
  576. 32/*format*/,
  577. PropModeReplace/*mode*/,
  578. (unsigned char *)temp/*data*/,
  579. 2/*nelements*/
  580. );
  581. }
  582. #endif
  583. #else
  584. // Pulled from the eXT2 example
  585. static void loc_setEventProc (Display *display, Window window) {
  586. void* data = (void*)&loc_eventProc; // swapped the function name here
  587. // (note) 32-bit only
  588. Atom atom = XInternAtom(display, "_XEventProc", False);
  589. XChangeProperty(display, window,
  590. atom/*property*/,
  591. atom/*type*/,
  592. 32/*format*/,
  593. PropModeReplace/*mode*/,
  594. (unsigned char*)&data/*data*/,
  595. 1/*nelements*/
  596. );
  597. }
  598. #endif // ARCH_X64
  599. // ---------------------------------------------------------------------------- lglw_window_open
  600. lglw_bool_t lglw_window_open (lglw_t _lglw, void *_parentHWNDOrNull, int32_t _x, int32_t _y, int32_t _w, int32_t _h) {
  601. lglw_bool_t r = LGLW_FALSE;
  602. LGLW(_lglw);
  603. if(NULL != lglw)
  604. {
  605. lglw_log("lglw:lglw_window_open: 1, %p, %i \n", (Window)_parentHWNDOrNull, (Window)_parentHWNDOrNull);
  606. lglw->parent_xwnd = (0 == _parentHWNDOrNull) ? DefaultRootWindow(lglw->xdsp) : (Window)_parentHWNDOrNull;
  607. lglw_log("lglw:lglw_window_open: 2 lglw=%p\n", lglw);
  608. if(_w <= 16)
  609. _w = lglw->hidden.size.x;
  610. lglw_log("lglw:lglw_window_open: 3\n");
  611. if(_h <= 16)
  612. _h = lglw->hidden.size.y;
  613. // TODO: compare to 'WindowClass' from Windows implementation
  614. lglw_log("lglw:lglw_window_open: 4\n");
  615. XSetWindowAttributes swa;
  616. // // XEvent event;
  617. XSync(lglw->xdsp, False);
  618. #if 1
  619. lglw_log("lglw:lglw_window_open: 5\n");
  620. swa.border_pixel = 0;
  621. swa.colormap = lglw->cmap;
  622. // (note) [bsp] setting this to NoEventMask causes all events to be propagated to the parent (host) window.
  623. // The host then reports the event to the plugin by calling its eventProc function (set via "_XEventProc").
  624. swa.event_mask = NoEventMask;/////ExposureMask | KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | EnterWindowMask | LeaveWindowMask | PointerMotionMask | ButtonMotionMask | FocusChangeMask;
  625. lglw->win.xwnd = XCreateWindow(lglw->xdsp/*display*/,
  626. DefaultRootWindow(lglw->xdsp)/*parent. see Cameron's comment below.*/,
  627. 0/*x*/,
  628. 0/*y*/,
  629. _w/*width*/,
  630. _h/*height*/,
  631. 0/*border_width*/,
  632. CopyFromParent/*depth*/,
  633. InputOutput/*class*/,
  634. lglw->vi->visual,
  635. CWBorderPixel | CWColormap | CWEventMask/*value_mask*/,
  636. &swa/*attributes*/
  637. );
  638. lglw_log("lglw:lglw_window_open: 6\n");
  639. XSetStandardProperties(lglw->xdsp/*display*/,
  640. lglw->win.xwnd/*window*/,
  641. "LGLW"/*window_name*/,
  642. "LGLW"/*icon_name*/,
  643. None/*icon_pixmap*/,
  644. NULL/*argv*/,
  645. 0/*argc*/,
  646. NULL/*XSizeHints*/
  647. );
  648. // Setup the event proc now, on the parent window as well just for the debug host
  649. // It was simpler to do this than check in the debug host for the reparent event
  650. lglw_log("lglw:lglw_window_open: 7\n");
  651. loc_setEventProc(lglw->xdsp, lglw->win.xwnd);
  652. loc_setProperty(lglw->xdsp, lglw->win.xwnd, "_lglw", (void*)lglw); // set instance pointer
  653. if(0 != _parentHWNDOrNull)
  654. {
  655. loc_setEventProc(lglw->xdsp, lglw->parent_xwnd);
  656. loc_setProperty(lglw->xdsp, lglw->parent_xwnd, "_lglw", (void*)lglw); // set instance pointer
  657. }
  658. // Some hosts only check and store the callback when the Window is reparented
  659. // Since creating the Window with a Parent may or may not do that, but the callback is not set,
  660. // ... it's created as a root window, the callback is set, and then it's reparented
  661. #if 1
  662. // (note) [cameronleger] In Ardour's code-base, the only time it looks for the _XEventProc is during a ReparentNotify event
  663. if (0 != _parentHWNDOrNull)
  664. {
  665. lglw_log("lglw:lglw_window_open: 8\n");
  666. XReparentWindow(lglw->xdsp, lglw->win.xwnd, lglw->parent_xwnd, 0, 0);
  667. }
  668. #endif
  669. lglw->win.b_owner = LGLW_TRUE;
  670. #else
  671. lglw->win.xwnd = (Window)_parentHWNDOrNull;
  672. lglw->win.b_owner = LGLW_FALSE;
  673. #endif
  674. lglw_log("lglw:lglw_window_open: 9\n");
  675. if(lglw->win.b_owner)
  676. {
  677. // // XMapRaised(lglw->xdsp, lglw->win.xwnd);
  678. XMapWindow(lglw->xdsp, lglw->win.xwnd);
  679. }
  680. #if 0
  681. XSelectInput(lglw->xdsp, lglw->win.xwnd,
  682. ExposureMask | KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | EnterWindowMask | LeaveWindowMask | PointerMotionMask | ButtonMotionMask | FocusChangeMask
  683. );
  684. XGrabKeyboard(lglw->xdsp, lglw->win.xwnd,
  685. False/*owner_events*/,
  686. GrabModeAsync/*pointer_mode*/,
  687. GrabModeAsync/*keyboard_mode*/,
  688. CurrentTime/*time*/
  689. );
  690. #endif
  691. #if 0
  692. XSetInputFocus(lglw->xdsp/*display*/,
  693. PointerRoot/*focus*/,
  694. RevertToPointerRoot/*revert_to*/,
  695. CurrentTime
  696. );
  697. #endif
  698. XSync(lglw->xdsp, False);
  699. lglw->win.mapped = LGLW_TRUE;
  700. lglw_log("lglw:lglw_window_open: 10\n");
  701. lglw->win.size.x = _w;
  702. lglw->win.size.y = _h;
  703. lglw_log("lglw:lglw_window_open: 11\n");
  704. loc_enable_dropfiles(lglw, (NULL != lglw->dropfiles.cbk));
  705. lglw_log("lglw:lglw_window_open: EXIT\n");
  706. r = LGLW_TRUE;
  707. }
  708. return r;
  709. }
  710. // ---------------------------------------------------------------------------- lglw_window_resize
  711. lglw_bool_t lglw_window_resize (lglw_t _lglw, int32_t _w, int32_t _h) {
  712. lglw_bool_t r = LGLW_FALSE;
  713. LGLW(_lglw);
  714. if(NULL != lglw)
  715. {
  716. if(0 != lglw->win.xwnd)
  717. {
  718. lglw_log("lglw:lglw_window_resize: 1\n");
  719. r = LGLW_TRUE;
  720. lglw_log("lglw:lglw_window_resize: 2\n");
  721. XResizeWindow(lglw->xdsp, lglw->win.xwnd, _w, _h);
  722. XRaiseWindow(lglw->xdsp, lglw->win.xwnd);
  723. lglw_log("lglw:lglw_window_resize: 3\n");
  724. int deltaW = _w - lglw->win.size.x;
  725. int deltaH = _h - lglw->win.size.y;
  726. lglw_log("lglw:lglw_window_resize: 4\n");
  727. lglw->win.size.x = _w;
  728. lglw->win.size.y = _h;
  729. lglw_log("lglw:lglw_window_resize: 5\n");
  730. Window root, parent, *children = NULL;
  731. unsigned int num_children;
  732. lglw_log("lglw:lglw_window_resize: 6\n");
  733. if(!XQueryTree(lglw->xdsp, lglw->win.xwnd, &root, &parent, &children, &num_children))
  734. return r;
  735. lglw_log("lglw:lglw_window_resize: 7\n");
  736. if(children)
  737. XFree((char *)children);
  738. lglw_log("lglw:lglw_window_resize: 8\n");
  739. // Resize parent window (if any)
  740. if(0 != parent)
  741. {
  742. lglw_log("lglw:lglw_window_resize: 8.1\n");
  743. int x, y;
  744. unsigned int width, height;
  745. unsigned int border_width;
  746. unsigned int depth;
  747. lglw_log("lglw:lglw_window_resize: 8.2\n");
  748. if(!XGetGeometry(lglw->xdsp, lglw->win.xwnd, &root, &x, &y, &width, &height, &border_width, &depth))
  749. return r;
  750. lglw_log("lglw:lglw_window_resize: 8.3\n");
  751. XResizeWindow(lglw->xdsp, parent, width + deltaW, height + deltaH);
  752. }
  753. lglw_log("lglw:lglw_window_resize: EXIT\n");
  754. }
  755. }
  756. return r;
  757. }
  758. // ---------------------------------------------------------------------------- lglw_window_close
  759. void lglw_window_close (lglw_t _lglw) {
  760. LGLW(_lglw);
  761. if(NULL != lglw)
  762. {
  763. if(0 != lglw->win.xwnd)
  764. {
  765. lglw_log("lglw:lglw_window_close: 1\n");
  766. lglw_timer_stop(_lglw);
  767. lglw_log("lglw:lglw_window_close: 2\n");
  768. loc_key_unhook(lglw);
  769. lglw_log("lglw:lglw_window_close: 3\n");
  770. glXMakeCurrent(lglw->xdsp, None, NULL);
  771. lglw_log("lglw:lglw_window_close: 4\n");
  772. if(lglw->win.b_owner)
  773. {
  774. XDestroyWindow(lglw->xdsp, lglw->win.xwnd);
  775. lglw->win.b_owner = LGLW_FALSE;
  776. }
  777. XSync(lglw->xdsp, False);
  778. lglw->win.xwnd = 0;
  779. lglw->win.mapped = LGLW_FALSE;
  780. }
  781. }
  782. lglw_log("lglw:lglw_window_close: EXIT\n");
  783. }
  784. // ---------------------------------------------------------------------------- lglw_window_show
  785. void lglw_window_show(lglw_t _lglw) {
  786. LGLW(_lglw);
  787. if(NULL != lglw)
  788. {
  789. lglw_log("lglw:lglw_window_show: 1\n");
  790. XMapRaised(lglw->xdsp, lglw->win.xwnd);
  791. lglw->win.mapped = LGLW_TRUE;
  792. }
  793. lglw_log("lglw:lglw_window_show: EXIT\n");
  794. }
  795. // ---------------------------------------------------------------------------- lglw_window_hide
  796. void lglw_window_hide(lglw_t _lglw) {
  797. LGLW(_lglw);
  798. if(NULL != lglw)
  799. {
  800. lglw_log("lglw:lglw_window_hide: 1\n");
  801. XUnmapWindow(lglw->xdsp, lglw->win.xwnd);
  802. lglw->win.mapped = LGLW_FALSE;
  803. }
  804. lglw_log("lglw:lglw_window_hide: EXIT\n");
  805. }
  806. // ---------------------------------------------------------------------------- lglw_window_is_visible
  807. lglw_bool_t lglw_window_is_visible(lglw_t _lglw) {
  808. lglw_bool_t r = LGLW_FALSE;
  809. LGLW(_lglw);
  810. // lglw_log("lglw:lglw_window_is_visible: 1\n");
  811. if(NULL != lglw && 0 != lglw->win.xwnd)
  812. {
  813. // lglw_log("lglw:lglw_window_is_visible: 2\n");
  814. r = lglw->win.mapped;
  815. }
  816. // lglw_log("lglw:lglw_window_is_visible: EXIT\n");
  817. return r;
  818. }
  819. // ---------------------------------------------------------------------------- lglw_window_size_get
  820. void lglw_window_size_get(lglw_t _lglw, int32_t *_retX, int32_t *_retY) {
  821. LGLW(_lglw);
  822. lglw_log("lglw:lglw_window_size_get: 1\n");
  823. if(NULL != lglw)
  824. {
  825. if(0 != lglw->win.xwnd)
  826. {
  827. if(NULL != _retX)
  828. *_retX = lglw->win.size.x;
  829. if(NULL != _retY)
  830. *_retY = lglw->win.size.y;
  831. }
  832. }
  833. lglw_log("lglw:lglw_window_size_get: EXIT\n");
  834. }
  835. // ---------------------------------------------------------------------------- lglw_redraw
  836. void lglw_redraw(lglw_t _lglw) {
  837. LGLW(_lglw);
  838. // (todo) implement me
  839. if(NULL != lglw)
  840. {
  841. if(0 != lglw->win.xwnd)
  842. {
  843. // TODO Event Loop
  844. lglw_log("lglw:lglw_redraw: 1\n");
  845. XEvent xev;
  846. xev.xany.type = Expose;
  847. xev.xany.serial = 0;
  848. xev.xany.send_event = True;
  849. xev.xany.display = lglw->xdsp;
  850. xev.xany.window = lglw->win.xwnd;
  851. xev.xexpose.x = 0;
  852. xev.xexpose.y = 0;
  853. xev.xexpose.width = lglw->win.size.x;
  854. xev.xexpose.height = lglw->win.size.y;
  855. xev.xexpose.count = 0;
  856. XSendEvent(lglw->xdsp, lglw->win.xwnd,
  857. True/*propagate*/,
  858. ExposureMask/*event_mask*/,
  859. &xev
  860. );
  861. XFlush(lglw->xdsp);
  862. }
  863. }
  864. }
  865. // ---------------------------------------------------------------------------- lglw_redraw_callback_set
  866. void lglw_redraw_callback_set(lglw_t _lglw, lglw_redraw_fxn_t _cbk) {
  867. LGLW(_lglw);
  868. if(NULL != lglw)
  869. {
  870. lglw->redraw.cbk = _cbk;
  871. }
  872. }
  873. // ---------------------------------------------------------------------------- lglw_glcontext_push
  874. void lglw_glcontext_push(lglw_t _lglw) {
  875. LGLW(_lglw);
  876. if(NULL != lglw)
  877. {
  878. lglw->prev.drw = glXGetCurrentDrawable();
  879. lglw->prev.ctx = glXGetCurrentContext();
  880. // lglw_log("lglw:lglw_glcontext_push: win.xwnd=%p hidden.xwnd=%p ctx=%p\n",
  881. // lglw->win.xwnd, lglw->hidden.xwnd, lglw->ctx);
  882. if(!glXMakeCurrent(lglw->xdsp, (0 == lglw->win.xwnd) ? lglw->hidden.xwnd : lglw->win.xwnd, lglw->ctx))
  883. {
  884. lglw_log("[---] lglw_glcontext_push: glXMakeCurrent() failed. win.xwnd=%p hidden.xwnd=%p ctx=%p glGetError()=%d\n", lglw->win.xwnd, lglw->hidden.xwnd, lglw->ctx, glGetError());
  885. }
  886. }
  887. }
  888. // ---------------------------------------------------------------------------- lglw_glcontext_pop
  889. void lglw_glcontext_pop(lglw_t _lglw) {
  890. LGLW(_lglw);
  891. if(NULL != lglw)
  892. {
  893. // lglw_log("lglw:lglw_glcontext_pop: prev.drw=%p prev.ctx=%p\n",
  894. // lglw->prev.drw, lglw->prev.ctx);
  895. if(!glXMakeCurrent(lglw->xdsp, lglw->prev.drw, lglw->prev.ctx))
  896. {
  897. lglw_log("[---] lglw_glcontext_pop: glXMakeCurrent() failed. prev.drw=%p ctx=%p glGetError()=%d\n", lglw->prev.drw, lglw->prev.ctx, glGetError());
  898. }
  899. }
  900. }
  901. // ---------------------------------------------------------------------------- lglw_swap_buffers
  902. void lglw_swap_buffers(lglw_t _lglw) {
  903. LGLW(_lglw);
  904. if(NULL != lglw)
  905. {
  906. if(0 != lglw->win.xwnd)
  907. {
  908. // lglw_log("lglw:lglw_swap_buffers: 1\n");
  909. glXSwapBuffers(lglw->xdsp, lglw->win.xwnd);
  910. }
  911. }
  912. }
  913. // ---------------------------------------------------------------------------- lglw_swap_interval_set
  914. typedef void (APIENTRY *PFNWGLEXTSWAPINTERVALPROC) (int);
  915. void lglw_swap_interval_set(lglw_t _lglw, int32_t _ival) {
  916. LGLW(_lglw);
  917. if(NULL != lglw)
  918. {
  919. lglw_log("lglw:lglw_swap_interval_set: 1\n");
  920. PFNWGLEXTSWAPINTERVALPROC glXSwapIntervalEXT;
  921. glXSwapIntervalEXT = (PFNWGLEXTSWAPINTERVALPROC) glXGetProcAddress((const GLubyte*)"glXSwapIntervalEXT");
  922. if(NULL != glXSwapIntervalEXT)
  923. {
  924. lglw_log("lglw:lglw_swap_interval_set: 2\n");
  925. glXSwapIntervalEXT(_ival);
  926. lglw->win.swap_interval = _ival;
  927. }
  928. }
  929. }
  930. // ---------------------------------------------------------------------------- lglw_swap_interval_get
  931. int32_t lglw_swap_interval_get(lglw_t _lglw) {
  932. LGLW(_lglw);
  933. int32_t r = 0;
  934. if(NULL != lglw)
  935. {
  936. r = lglw->win.swap_interval;
  937. }
  938. return r;
  939. }
  940. // ---------------------------------------------------------------------------- loc_key_hook
  941. static void loc_key_hook(lglw_int_t *lglw) {
  942. loc_key_unhook(lglw);
  943. // (todo) implement me
  944. khook_lglw = lglw;
  945. }
  946. // ---------------------------------------------------------------------------- loc_key_unhook
  947. static void loc_key_unhook(lglw_int_t *lglw) {
  948. // (todo) implement me
  949. if(khook_lglw == lglw)
  950. khook_lglw = NULL;
  951. }
  952. // ---------------------------------------------------------------------------- loc_handle_mouseleave
  953. static void loc_handle_mouseleave(lglw_int_t *lglw) {
  954. loc_key_unhook(lglw);
  955. lglw->focus.state &= ~LGLW_FOCUS_MOUSE;
  956. if(NULL != lglw->focus.cbk)
  957. {
  958. lglw->focus.cbk(lglw, lglw->focus.state, LGLW_FOCUS_MOUSE);
  959. }
  960. lglw_log("xxx lglw:loc_handle_mouseleave: LEAVE\n");
  961. }
  962. // ---------------------------------------------------------------------------- loc_handle_mouseenter
  963. static void loc_handle_mouseenter(lglw_int_t *lglw) {
  964. loc_key_hook(lglw);
  965. lglw->focus.state |= LGLW_FOCUS_MOUSE;
  966. if(NULL != lglw->focus.cbk)
  967. {
  968. lglw->focus.cbk(lglw, lglw->focus.state, LGLW_FOCUS_MOUSE);
  969. }
  970. lglw_log("xxx lglw:loc_handle_mouseenter: LEAVE\n");
  971. }
  972. // ---------------------------------------------------------------------------- loc_handle_mousebutton
  973. static void loc_handle_mousebutton(lglw_int_t *lglw, lglw_bool_t _bPressed, uint32_t _button) {
  974. if(_bPressed)
  975. lglw->mouse.button_state |= _button;
  976. else
  977. lglw->mouse.button_state &= ~_button;
  978. if(NULL != lglw->mouse.cbk)
  979. {
  980. lglw->mouse.cbk(lglw, lglw->mouse.p.x, lglw->mouse.p.y, lglw->mouse.button_state, _button);
  981. }
  982. }
  983. // ---------------------------------------------------------------------------- loc_handle_mousemotion
  984. static void loc_handle_mousemotion(lglw_int_t *lglw) {
  985. if(NULL != lglw->mouse.cbk)
  986. {
  987. lglw->mouse.cbk(lglw, lglw->mouse.p.x, lglw->mouse.p.y, lglw->mouse.button_state, 0u/*changedbuttonstate*/);
  988. }
  989. }
  990. // ---------------------------------------------------------------------------- lglw_mouse_callback_set
  991. void lglw_mouse_callback_set(lglw_t _lglw, lglw_mouse_fxn_t _cbk) {
  992. LGLW(_lglw);
  993. if(NULL != lglw)
  994. {
  995. lglw->mouse.cbk = _cbk;
  996. }
  997. }
  998. // ---------------------------------------------------------------------------- lglw_mouse_callback_set
  999. void lglw_focus_callback_set(lglw_t _lglw, lglw_focus_fxn_t _cbk) {
  1000. LGLW(_lglw);
  1001. if(NULL != lglw)
  1002. {
  1003. lglw->focus.cbk = _cbk;
  1004. }
  1005. }
  1006. // ---------------------------------------------------------------------------- loc_handle_key
  1007. static lglw_bool_t loc_handle_key(lglw_int_t *lglw, lglw_bool_t _bPressed, uint32_t _vkey) {
  1008. lglw_bool_t r = LGLW_FALSE;
  1009. if(NULL != lglw->keyboard.cbk)
  1010. {
  1011. r = lglw->keyboard.cbk(lglw, _vkey, lglw->keyboard.kmod_state, _bPressed);
  1012. }
  1013. return r;
  1014. }
  1015. // ---------------------------------------------------------------------------- lglw_keyboard_callback_set
  1016. void lglw_keyboard_callback_set(lglw_t _lglw, lglw_keyboard_fxn_t _cbk) {
  1017. LGLW(_lglw);
  1018. if(NULL != lglw)
  1019. {
  1020. lglw->keyboard.cbk = _cbk;
  1021. }
  1022. }
  1023. // ---------------------------------------------------------------------------- lglw_keyboard_get_modifiers
  1024. uint32_t lglw_keyboard_get_modifiers(lglw_t _lglw) {
  1025. uint32_t r = 0u;
  1026. LGLW(_lglw);
  1027. if(NULL != lglw)
  1028. {
  1029. r = lglw->keyboard.kmod_state;
  1030. }
  1031. return r;
  1032. }
  1033. // ---------------------------------------------------------------------------- lglw_touchkeyboard_show
  1034. void lglw_touchkeyboard_show(lglw_t _lglw, lglw_bool_t _bEnable) {
  1035. LGLW(_lglw);
  1036. // (todo) implement me
  1037. if(NULL != lglw)
  1038. {
  1039. }
  1040. }
  1041. // ---------------------------------------------------------------------------- lglw_mouse_get_buttons
  1042. uint32_t lglw_mouse_get_buttons(lglw_t _lglw) {
  1043. uint32_t r = 0u;
  1044. LGLW(_lglw);
  1045. if(NULL != lglw)
  1046. {
  1047. r = lglw->mouse.button_state;
  1048. }
  1049. return r;
  1050. }
  1051. // ---------------------------------------------------------------------------- lglw_mouse_grab
  1052. void lglw_mouse_grab(lglw_t _lglw, uint32_t _grabMode) {
  1053. LGLW(_lglw);
  1054. if(NULL != lglw)
  1055. {
  1056. if(0 != lglw->win.xwnd)
  1057. {
  1058. if(!lglw->mouse.touch.b_enable)
  1059. {
  1060. if(lglw->mouse.grab.mode != _grabMode)
  1061. {
  1062. lglw_mouse_ungrab(_lglw);
  1063. }
  1064. int result;
  1065. switch(_grabMode)
  1066. {
  1067. default:
  1068. case LGLW_MOUSE_GRAB_NONE:
  1069. break;
  1070. case LGLW_MOUSE_GRAB_CAPTURE:
  1071. result = XGrabPointer(lglw->xdsp, lglw->win.xwnd,
  1072. True/*owner_events*/,
  1073. ButtonPressMask | ButtonReleaseMask | EnterWindowMask | LeaveWindowMask | PointerMotionMask | PointerMotionHintMask | ButtonMotionMask | KeymapStateMask/*event_mask*/,
  1074. GrabModeAsync/*pointer_mode*/,
  1075. GrabModeAsync/*keyboard_mode*/,
  1076. lglw->win.xwnd/*confine_to*/,
  1077. None/*cursor*/,
  1078. CurrentTime/*time*/);
  1079. if(GrabSuccess != result)
  1080. {
  1081. printf("vstgltest<lglw_linux>: Grab Result: %i\n", result);
  1082. }
  1083. else
  1084. {
  1085. lglw->mouse.grab.mode = _grabMode;
  1086. }
  1087. break;
  1088. case LGLW_MOUSE_GRAB_WARP:
  1089. result = XGrabPointer(lglw->xdsp, lglw->win.xwnd,
  1090. True/*owner_events*/,
  1091. ButtonPressMask | ButtonReleaseMask | EnterWindowMask | LeaveWindowMask | PointerMotionMask | PointerMotionHintMask | ButtonMotionMask | KeymapStateMask/*event_mask*/,
  1092. GrabModeAsync/*pointer_mode*/,
  1093. GrabModeAsync/*keyboard_mode*/,
  1094. lglw->win.xwnd/*confine_to*/,
  1095. None/*cursor*/,
  1096. CurrentTime/*time*/);
  1097. if(GrabSuccess != result)
  1098. {
  1099. printf("vstgltest<lglw_linux>: Grab Result: %i\n", result);
  1100. }
  1101. else
  1102. {
  1103. lglw_mouse_cursor_show(_lglw, LGLW_FALSE);
  1104. lglw->mouse.grab.p = lglw->mouse.p;
  1105. lglw->mouse.grab.last_p = lglw->mouse.p;
  1106. lglw->mouse.grab.mode = _grabMode;
  1107. }
  1108. break;
  1109. }
  1110. }
  1111. }
  1112. }
  1113. }
  1114. // ---------------------------------------------------------------------------- lglw_mouse_ungrab
  1115. void lglw_mouse_ungrab(lglw_t _lglw) {
  1116. LGLW(_lglw);
  1117. if(NULL != lglw)
  1118. {
  1119. if(0 != lglw->win.xwnd)
  1120. {
  1121. if(!lglw->mouse.touch.b_enable)
  1122. {
  1123. switch(lglw->mouse.grab.mode)
  1124. {
  1125. default:
  1126. case LGLW_MOUSE_GRAB_NONE:
  1127. break;
  1128. case LGLW_MOUSE_GRAB_CAPTURE:
  1129. XUngrabPointer(lglw->xdsp, CurrentTime);
  1130. lglw->mouse.grab.mode = LGLW_MOUSE_GRAB_NONE;
  1131. break;
  1132. case LGLW_MOUSE_GRAB_WARP:
  1133. XUngrabPointer(lglw->xdsp, CurrentTime);
  1134. lglw->mouse.grab.mode = LGLW_MOUSE_GRAB_NONE;
  1135. lglw->mouse.grab.b_queue_warp = LGLW_TRUE;
  1136. lglw_mouse_cursor_show(_lglw, LGLW_TRUE);
  1137. break;
  1138. }
  1139. }
  1140. }
  1141. }
  1142. }
  1143. // ---------------------------------------------------------------------------- lglw_mouse_warp
  1144. void lglw_mouse_warp(lglw_t _lglw, int32_t _x, int32_t _y) {
  1145. LGLW(_lglw);
  1146. if(NULL != lglw)
  1147. {
  1148. if(0 != lglw->win.xwnd)
  1149. {
  1150. XWarpPointer(lglw->xdsp,
  1151. None/*src_w*/,
  1152. lglw->win.xwnd/*dest_w*/,
  1153. 0/*src_x*/,
  1154. 0/*src_y*/,
  1155. 0/*src_width*/,
  1156. 0/*src_height*/,
  1157. _x/*dest_x*/,
  1158. _y/*dest_y*/);
  1159. }
  1160. }
  1161. }
  1162. // ---------------------------------------------------------------------------- loc_handle_queued_mouse_warp
  1163. static void loc_handle_queued_mouse_warp(lglw_int_t *lglw) {
  1164. if(lglw->mouse.grab.b_queue_warp)
  1165. {
  1166. lglw->mouse.grab.b_queue_warp = LGLW_FALSE;
  1167. lglw_mouse_warp(lglw, lglw->mouse.grab.p.x, lglw->mouse.grab.p.y);
  1168. lglw->mouse.grab.last_p = lglw->mouse.grab.p;
  1169. }
  1170. }
  1171. // ---------------------------------------------------------------------------- lglw_mouse_cursor_show
  1172. void lglw_mouse_cursor_show (lglw_t _lglw, lglw_bool_t _bShow) {
  1173. LGLW(_lglw);
  1174. if(NULL != lglw)
  1175. {
  1176. if(LGLW_FALSE == _bShow)
  1177. {
  1178. Pixmap noPxm;
  1179. Cursor noCursor;
  1180. XColor black, dummy;
  1181. static char pxmNoData[] = {0, 0, 0, 0, 0, 0, 0, 0};
  1182. XAllocNamedColor(lglw->xdsp, lglw->cmap, "black", &black, &dummy);
  1183. noPxm = XCreateBitmapFromData(lglw->xdsp, lglw->win.xwnd, pxmNoData, 8, 8);
  1184. noCursor = XCreatePixmapCursor(lglw->xdsp, noPxm, noPxm, &black, &black, 0, 0);
  1185. XDefineCursor(lglw->xdsp, lglw->win.xwnd, noCursor);
  1186. XFreeCursor(lglw->xdsp, noCursor);
  1187. if(noPxm != None)
  1188. {
  1189. XFreePixmap(lglw->xdsp, noPxm);
  1190. }
  1191. }
  1192. else
  1193. {
  1194. XUndefineCursor(lglw->xdsp, lglw->win.xwnd);
  1195. }
  1196. }
  1197. }
  1198. // ---------------------------------------------------------------------------- lglw_timer_start
  1199. void lglw_timer_start(lglw_t _lglw, uint32_t _millisec) {
  1200. LGLW(_lglw);
  1201. // (todo) implement me
  1202. if(NULL != lglw)
  1203. {
  1204. }
  1205. }
  1206. // ---------------------------------------------------------------------------- lglw_timer_stop
  1207. void lglw_timer_stop(lglw_t _lglw) {
  1208. LGLW(_lglw);
  1209. // (todo) implement me
  1210. if(NULL != lglw)
  1211. {
  1212. }
  1213. }
  1214. // ---------------------------------------------------------------------------- lglw_timer_callback_set
  1215. void lglw_timer_callback_set(lglw_t _lglw, lglw_timer_fxn_t _cbk) {
  1216. LGLW(_lglw);
  1217. if(NULL != lglw)
  1218. {
  1219. lglw->timer.cbk = _cbk;
  1220. }
  1221. }
  1222. // ---------------------------------------------------------------------------- loc_enable_dropfiles
  1223. static void loc_enable_dropfiles(lglw_int_t *lglw, lglw_bool_t _bEnable) {
  1224. // (todo) implement me
  1225. }
  1226. // ---------------------------------------------------------------------------- lglw_dropfiles_callback_set
  1227. void lglw_dropfiles_callback_set(lglw_t _lglw, lglw_dropfiles_fxn_t _cbk) {
  1228. LGLW(_lglw);
  1229. if(NULL != _lglw)
  1230. {
  1231. lglw->dropfiles.cbk = _cbk;
  1232. loc_enable_dropfiles(lglw, (NULL != _cbk));
  1233. }
  1234. }
  1235. // ---------------------------------------------------------------------------- loc_touchinput_update
  1236. static void loc_touchinput_update(lglw_int_t *lglw) {
  1237. // (todo) implement me
  1238. }
  1239. // ---------------------------------------------------------------------------- lglw_touchinput_set
  1240. void lglw_touchinput_set(lglw_t _lglw, lglw_bool_t _bEnable) {
  1241. LGLW(_lglw);
  1242. if(NULL != _lglw)
  1243. {
  1244. lglw->mouse.touch.b_enable = _bEnable;
  1245. lglw->mouse.touch.b_update_queued = LGLW_TRUE;
  1246. }
  1247. }
  1248. // ---------------------------------------------------------------------------- lglw_touchinput_get
  1249. lglw_bool_t lglw_touchinput_get(lglw_t _lglw) {
  1250. lglw_bool_t r = LGLW_FALSE;
  1251. LGLW(_lglw);
  1252. if(NULL != _lglw)
  1253. {
  1254. r = lglw->mouse.touch.b_enable;
  1255. }
  1256. return r;
  1257. }
  1258. // ---------------------------------------------------------------------------- lglw_clipboard_text_set
  1259. void lglw_clipboard_text_set(lglw_t _lglw, const uint32_t _numChars, const char *_text) {
  1260. LGLW(_lglw);
  1261. (void)_numChars;
  1262. // (todo) implement me
  1263. if(NULL != _text)
  1264. {
  1265. (void)lglw;
  1266. }
  1267. }
  1268. // ---------------------------------------------------------------------------- lglw_clipboard_text_get
  1269. void lglw_clipboard_text_get(lglw_t _lglw, uint32_t _maxChars, uint32_t *_retNumChars, char *_retText) {
  1270. LGLW(_lglw);
  1271. if(NULL != _retNumChars)
  1272. *_retNumChars = 0u;
  1273. if(NULL != _retText)
  1274. *_retText = 0;
  1275. if(_maxChars > 0u)
  1276. {
  1277. if(NULL != _lglw)
  1278. {
  1279. // (todo) implement me
  1280. (void)lglw;
  1281. }
  1282. }
  1283. }