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.

2014 lines
67KB

  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. uint32_t numChars;
  114. char *data;
  115. } clipboard;
  116. struct {
  117. lglw_dropfiles_fxn_t cbk;
  118. } dropfiles;
  119. struct {
  120. lglw_redraw_fxn_t cbk;
  121. } redraw;
  122. } lglw_int_t;
  123. // ---------------------------------------------------------------------------- module fxn fwd decls
  124. static lglw_bool_t loc_create_hidden_window (lglw_int_t *lglw, int32_t _w, int32_t _h);
  125. static void loc_destroy_hidden_window(lglw_int_t *lglw);
  126. static lglw_bool_t loc_handle_key (lglw_int_t *lglw, lglw_bool_t _bPressed, uint32_t _vkey);
  127. // static lglw_bool_t loc_touchkeyboard_get_rect (RECT *rect);
  128. // static lglw_bool_t loc_touchkeyboard_is_visible (void);
  129. extern lglw_bool_t lglw_int_touchkeyboard_toggle (void);
  130. static void loc_handle_mouseleave (lglw_int_t *lglw);
  131. static void loc_handle_mouseenter (lglw_int_t *lglw);
  132. static void loc_handle_mousebutton (lglw_int_t *lglw, lglw_bool_t _bPressed, uint32_t _button);
  133. static void loc_handle_mousemotion (lglw_int_t *lglw);
  134. static void loc_handle_queued_mouse_warp (lglw_int_t *lglw);
  135. static void loc_touchinput_update (lglw_int_t *lglw);
  136. static void loc_enable_dropfiles (lglw_int_t *lglw, lglw_bool_t _bEnable);
  137. static void loc_eventProc (void *_xevent);
  138. static void loc_setProperty (Display *_display, Window _window, const char *_name, void *_value);
  139. static void *loc_getProperty (Display *_display, Window _window, const char *_name);
  140. static void loc_setEventProc (Display *display, Window window);
  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. lglw_bool_t eventHandled = LGLW_FALSE;
  295. switch(xev->type)
  296. {
  297. default:
  298. printf("vstgltest<lglw_linux>: unhandled X11 event type=%d\n", xev->type);
  299. eventHandled = LGLW_FALSE;
  300. break;
  301. case Expose:
  302. printf("vstgltest<lglw_linux>: xev Expose\n");
  303. loc_handle_queued_mouse_warp(lglw);
  304. eventHandled = LGLW_FALSE;
  305. if(NULL != lglw->redraw.cbk)
  306. {
  307. lglw->redraw.cbk(lglw);
  308. eventHandled = LGLW_TRUE;
  309. }
  310. break;
  311. // TODO: Should FocusIn/Out be treated like WM_CAPTURECHANGED and reset the grab state?
  312. case FocusIn:
  313. printf("vstgltest<lglw_linux>: xev FocusIn\n");
  314. eventHandled = LGLW_FALSE;
  315. break;
  316. case FocusOut:
  317. printf("vstgltest<lglw_linux>: xev FocusOut\n");
  318. eventHandled = LGLW_FALSE;
  319. break;
  320. case EnterNotify:
  321. // printf("vstgltest<lglw_linux>: xev XEnterWindowEvent\n");
  322. ; // empty statement
  323. XEnterWindowEvent *wenter = (XEnterWindowEvent*)xev;
  324. printf("vstgltest<lglw_linux>: xev EnterNotify: mode:%i, detail:%i, state:%d\n", wenter->mode, wenter->detail, wenter->state);
  325. lglw->mouse.p.x = wenter->x;
  326. lglw->mouse.p.y = wenter->y;
  327. loc_handle_mousemotion(lglw);
  328. // EnterNotify messages can be pseudo-motion events (NotifyGrab, NotifyUngrab)
  329. // when buttons are pressed, which would trigger false focus changes
  330. // so, the callback is only sent when a normal entry happens
  331. if (wenter->mode == NotifyNormal)
  332. {
  333. loc_handle_mouseenter(lglw);
  334. }
  335. eventHandled = LGLW_TRUE;
  336. break;
  337. case LeaveNotify:
  338. // printf("vstgltest<lglw_linux>: xev XLeaveWindowEvent\n");
  339. ; // empty statement
  340. XLeaveWindowEvent *wexit = (XLeaveWindowEvent*)xev;
  341. printf("vstgltest<lglw_linux>: xev LeaveNotify: mode:%i, detail:%i, state:%d\n", wexit->mode, wexit->detail, wexit->state);
  342. // LeaveNotify messages can be pseudo-motion events (NotifyGrab, NotifyUngrab)
  343. // when buttons are pressed, which would trigger false focus changes
  344. // so, the callback is only sent when a normal entry happens
  345. if (wexit->mode == NotifyNormal)
  346. {
  347. loc_handle_mouseleave(lglw);
  348. }
  349. eventHandled = LGLW_TRUE;
  350. break;
  351. case MotionNotify:
  352. // printf("vstgltest<lglw_linux>: xev MotionNotify\n");
  353. ; // empty statement
  354. XMotionEvent *motion = (XMotionEvent*)xev;
  355. if(LGLW_MOUSE_GRAB_WARP == lglw->mouse.grab.mode)
  356. {
  357. lglw->mouse.grab.b_queue_warp = LGLW_TRUE;
  358. lglw->mouse.p.x += (motion->x - lglw->mouse.grab.last_p.x);
  359. lglw->mouse.p.y += (motion->y - lglw->mouse.grab.last_p.y);
  360. lglw->mouse.grab.last_p.x = motion->x;
  361. lglw->mouse.grab.last_p.y = motion->y;
  362. }
  363. else
  364. {
  365. lglw->mouse.p.x = motion->x;
  366. lglw->mouse.p.y = motion->y;
  367. }
  368. loc_handle_mousemotion(lglw);
  369. eventHandled = LGLW_TRUE;
  370. break;
  371. case KeyPress:
  372. printf("vstgltest<lglw_linux>: xev KeyPress\n");
  373. XKeyPressedEvent *keyPress = (XKeyPressedEvent*)xev;
  374. eventHandled = LGLW_FALSE;
  375. KeySym xkp = XLookupKeysym(keyPress, 0);
  376. switch(xkp)
  377. {
  378. default:
  379. printf("vstgltest<lglw_linux>: xev KeyPress: %x or %lu\n", keyPress->keycode, xkp);
  380. if(0u != (lglw->keyboard.kmod_state & LGLW_KMOD_SHIFT))
  381. {
  382. KeySym xkpl;
  383. KeySym xkpu;
  384. XConvertCase(xkp, &xkpl, &xkpu);
  385. eventHandled = loc_handle_key(lglw, LGLW_TRUE/*bPressed*/, xkpu);
  386. }
  387. else
  388. {
  389. eventHandled = loc_handle_key(lglw, LGLW_TRUE/*bPressed*/, xkp);
  390. }
  391. break;
  392. case NoSymbol:
  393. printf("vstgltest<lglw_linux>: xev UNKNOWN KeyPress: %x\n", keyPress->keycode);
  394. break;
  395. case XK_F1:
  396. eventHandled = loc_handle_key(lglw, LGLW_TRUE/*bPressed*/, LGLW_VKEY_F1);
  397. break;
  398. case XK_F2:
  399. eventHandled = loc_handle_key(lglw, LGLW_TRUE/*bPressed*/, LGLW_VKEY_F2);
  400. break;
  401. case XK_F3:
  402. eventHandled = loc_handle_key(lglw, LGLW_TRUE/*bPressed*/, LGLW_VKEY_F3);
  403. break;
  404. case XK_F4:
  405. eventHandled = loc_handle_key(lglw, LGLW_TRUE/*bPressed*/, LGLW_VKEY_F4);
  406. break;
  407. case XK_F5:
  408. eventHandled = loc_handle_key(lglw, LGLW_TRUE/*bPressed*/, LGLW_VKEY_F5);
  409. break;
  410. case XK_F6:
  411. eventHandled = loc_handle_key(lglw, LGLW_TRUE/*bPressed*/, LGLW_VKEY_F6);
  412. break;
  413. case XK_F7:
  414. eventHandled = loc_handle_key(lglw, LGLW_TRUE/*bPressed*/, LGLW_VKEY_F7);
  415. break;
  416. case XK_F8:
  417. eventHandled = loc_handle_key(lglw, LGLW_TRUE/*bPressed*/, LGLW_VKEY_F8);
  418. break;
  419. case XK_F9:
  420. eventHandled = loc_handle_key(lglw, LGLW_TRUE/*bPressed*/, LGLW_VKEY_F9);
  421. break;
  422. case XK_F10:
  423. eventHandled = loc_handle_key(lglw, LGLW_TRUE/*bPressed*/, LGLW_VKEY_F10);
  424. break;
  425. case XK_F11:
  426. eventHandled = loc_handle_key(lglw, LGLW_TRUE/*bPressed*/, LGLW_VKEY_F11);
  427. break;
  428. case XK_F12:
  429. eventHandled = loc_handle_key(lglw, LGLW_TRUE/*bPressed*/, LGLW_VKEY_F12);
  430. break;
  431. case XK_BackSpace:
  432. eventHandled = loc_handle_key(lglw, LGLW_TRUE/*bPressed*/, LGLW_VKEY_BACKSPACE);
  433. break;
  434. case XK_Tab:
  435. eventHandled = loc_handle_key(lglw, LGLW_TRUE/*bPressed*/, LGLW_VKEY_TAB);
  436. break;
  437. case XK_Return:
  438. eventHandled = loc_handle_key(lglw, LGLW_TRUE/*bPressed*/, LGLW_VKEY_RETURN);
  439. break;
  440. case XK_Escape:
  441. eventHandled = loc_handle_key(lglw, LGLW_TRUE/*bPressed*/, LGLW_VKEY_ESCAPE);
  442. break;
  443. case XK_Shift_L:
  444. lglw->keyboard.kmod_state |= LGLW_KMOD_LSHIFT;
  445. eventHandled = loc_handle_key(lglw, LGLW_TRUE/*bPressed*/, LGLW_VKEY_LSHIFT);
  446. eventHandled = LGLW_FALSE;
  447. break;
  448. case XK_Shift_R:
  449. lglw->keyboard.kmod_state |= LGLW_KMOD_RSHIFT;
  450. eventHandled = loc_handle_key(lglw, LGLW_TRUE/*bPressed*/, LGLW_VKEY_RSHIFT);
  451. eventHandled = LGLW_FALSE;
  452. break;
  453. case XK_Control_L:
  454. lglw->keyboard.kmod_state |= LGLW_KMOD_LCTRL;
  455. eventHandled = loc_handle_key(lglw, LGLW_TRUE/*bPressed*/, LGLW_KMOD_LCTRL);
  456. eventHandled = LGLW_FALSE;
  457. break;
  458. case XK_Control_R:
  459. lglw->keyboard.kmod_state |= LGLW_KMOD_RCTRL;
  460. eventHandled = loc_handle_key(lglw, LGLW_TRUE/*bPressed*/, LGLW_KMOD_RCTRL);
  461. eventHandled = LGLW_FALSE;
  462. break;
  463. }
  464. break;
  465. case KeyRelease:
  466. printf("vstgltest<lglw_linux>: xev KeyRelease\n");
  467. XKeyReleasedEvent *keyRelease = (XKeyReleasedEvent*)xev;
  468. eventHandled = LGLW_FALSE;
  469. KeySym xkr = XLookupKeysym(keyRelease, 0);
  470. switch(xkr)
  471. {
  472. default:
  473. printf("vstgltest<lglw_linux>: xev KeyRelease: %x or %lu\n", keyRelease->keycode, xkr);
  474. if(0u != (lglw->keyboard.kmod_state & LGLW_KMOD_SHIFT))
  475. {
  476. KeySym xkrl;
  477. KeySym xkru;
  478. XConvertCase(xkr, &xkrl, &xkru);
  479. eventHandled = loc_handle_key(lglw, LGLW_FALSE/*bPressed*/, xkru);
  480. }
  481. else
  482. {
  483. eventHandled = loc_handle_key(lglw, LGLW_FALSE/*bPressed*/, xkr);
  484. }
  485. break;
  486. case NoSymbol:
  487. printf("vstgltest<lglw_linux>: xev UNKNOWN KeyRelease: %x\n", keyRelease->keycode);
  488. break;
  489. case XK_F1:
  490. eventHandled = loc_handle_key(lglw, LGLW_FALSE/*bPressed*/, LGLW_VKEY_F1);
  491. break;
  492. case XK_F2:
  493. eventHandled = loc_handle_key(lglw, LGLW_FALSE/*bPressed*/, LGLW_VKEY_F2);
  494. break;
  495. case XK_F3:
  496. eventHandled = loc_handle_key(lglw, LGLW_FALSE/*bPressed*/, LGLW_VKEY_F3);
  497. break;
  498. case XK_F4:
  499. eventHandled = loc_handle_key(lglw, LGLW_FALSE/*bPressed*/, LGLW_VKEY_F4);
  500. break;
  501. case XK_F5:
  502. eventHandled = loc_handle_key(lglw, LGLW_FALSE/*bPressed*/, LGLW_VKEY_F5);
  503. break;
  504. case XK_F6:
  505. eventHandled = loc_handle_key(lglw, LGLW_FALSE/*bPressed*/, LGLW_VKEY_F6);
  506. break;
  507. case XK_F7:
  508. eventHandled = loc_handle_key(lglw, LGLW_FALSE/*bPressed*/, LGLW_VKEY_F7);
  509. break;
  510. case XK_F8:
  511. eventHandled = loc_handle_key(lglw, LGLW_FALSE/*bPressed*/, LGLW_VKEY_F8);
  512. break;
  513. case XK_F9:
  514. eventHandled = loc_handle_key(lglw, LGLW_FALSE/*bPressed*/, LGLW_VKEY_F9);
  515. break;
  516. case XK_F10:
  517. eventHandled = loc_handle_key(lglw, LGLW_FALSE/*bPressed*/, LGLW_VKEY_F10);
  518. break;
  519. case XK_F11:
  520. eventHandled = loc_handle_key(lglw, LGLW_FALSE/*bPressed*/, LGLW_VKEY_F11);
  521. break;
  522. case XK_F12:
  523. eventHandled = loc_handle_key(lglw, LGLW_FALSE/*bPressed*/, LGLW_VKEY_F12);
  524. break;
  525. case XK_BackSpace:
  526. eventHandled = loc_handle_key(lglw, LGLW_FALSE/*bPressed*/, LGLW_VKEY_BACKSPACE);
  527. break;
  528. case XK_Tab:
  529. eventHandled = loc_handle_key(lglw, LGLW_FALSE/*bPressed*/, LGLW_VKEY_TAB);
  530. break;
  531. case XK_Return:
  532. eventHandled = loc_handle_key(lglw, LGLW_FALSE/*bPressed*/, LGLW_VKEY_RETURN);
  533. break;
  534. case XK_Escape:
  535. eventHandled = loc_handle_key(lglw, LGLW_FALSE/*bPressed*/, LGLW_VKEY_ESCAPE);
  536. break;
  537. case XK_Shift_L:
  538. lglw->keyboard.kmod_state &= ~LGLW_KMOD_LSHIFT;
  539. eventHandled = loc_handle_key(lglw, LGLW_FALSE/*bPressed*/, LGLW_VKEY_LSHIFT);
  540. eventHandled = LGLW_FALSE;
  541. break;
  542. case XK_Shift_R:
  543. lglw->keyboard.kmod_state &= ~LGLW_KMOD_RSHIFT;
  544. eventHandled = loc_handle_key(lglw, LGLW_FALSE/*bPressed*/, LGLW_VKEY_RSHIFT);
  545. eventHandled = LGLW_FALSE;
  546. break;
  547. case XK_Control_L:
  548. lglw->keyboard.kmod_state &= ~LGLW_KMOD_LCTRL;
  549. eventHandled = loc_handle_key(lglw, LGLW_FALSE/*bPressed*/, LGLW_VKEY_LCTRL);
  550. eventHandled = LGLW_FALSE;
  551. break;
  552. case XK_Control_R:
  553. lglw->keyboard.kmod_state &= ~LGLW_KMOD_RCTRL;
  554. eventHandled = loc_handle_key(lglw, LGLW_FALSE/*bPressed*/, LGLW_VKEY_RCTRL);
  555. eventHandled = LGLW_FALSE;
  556. break;
  557. }
  558. break;
  559. case ButtonPress:
  560. printf("vstgltest<lglw_linux>: xev ButtonPress\n");
  561. XButtonPressedEvent *btnPress = (XButtonPressedEvent*)xev;
  562. lglw->mouse.p.x = btnPress->x;
  563. lglw->mouse.p.y = btnPress->y;
  564. if(0u == (lglw->focus.state & LGLW_FOCUS_MOUSE))
  565. {
  566. loc_handle_mouseenter(lglw);
  567. }
  568. switch(btnPress->button)
  569. {
  570. default:
  571. printf("vstgltest<lglw_linux>: xev ButtonPress unhandled button: %i\n", btnPress->button);
  572. eventHandled = LGLW_FALSE;
  573. break;
  574. case Button1:
  575. loc_handle_mousebutton(lglw, LGLW_TRUE/*bPressed*/, LGLW_MOUSE_LBUTTON);
  576. eventHandled = LGLW_TRUE;
  577. break;
  578. case Button2:
  579. loc_handle_mousebutton(lglw, LGLW_TRUE/*bPressed*/, LGLW_MOUSE_RBUTTON);
  580. eventHandled = LGLW_TRUE;
  581. break;
  582. case Button3:
  583. loc_handle_mousebutton(lglw, LGLW_TRUE/*bPressed*/, LGLW_MOUSE_MBUTTON);
  584. eventHandled = LGLW_TRUE;
  585. break;
  586. case Button4:
  587. loc_handle_mousebutton(lglw, LGLW_TRUE/*bPressed*/, LGLW_MOUSE_WHEELUP);
  588. eventHandled = LGLW_TRUE;
  589. break;
  590. case Button5:
  591. loc_handle_mousebutton(lglw, LGLW_TRUE/*bPressed*/, LGLW_MOUSE_WHEELDOWN);
  592. eventHandled = LGLW_TRUE;
  593. break;
  594. }
  595. break;
  596. case ButtonRelease:
  597. printf("vstgltest<lglw_linux>: xev ButtonRelease\n");
  598. XButtonReleasedEvent *btnRelease = (XButtonReleasedEvent*)xev;
  599. lglw->mouse.p.x = btnRelease->x;
  600. lglw->mouse.p.y = btnRelease->y;
  601. switch(btnRelease->button)
  602. {
  603. default:
  604. printf("vstgltest<lglw_linux>: xev ButtonRelease unhandled button: %i\n", btnRelease->button);
  605. eventHandled = LGLW_FALSE;
  606. break;
  607. case Button1:
  608. loc_handle_mousebutton(lglw, LGLW_FALSE/*bPressed*/, LGLW_MOUSE_LBUTTON);
  609. eventHandled = LGLW_TRUE;
  610. break;
  611. case Button2:
  612. loc_handle_mousebutton(lglw, LGLW_FALSE/*bPressed*/, LGLW_MOUSE_RBUTTON);
  613. eventHandled = LGLW_TRUE;
  614. break;
  615. case Button3:
  616. loc_handle_mousebutton(lglw, LGLW_FALSE/*bPressed*/, LGLW_MOUSE_MBUTTON);
  617. eventHandled = LGLW_TRUE;
  618. break;
  619. case Button4:
  620. loc_handle_mousebutton(lglw, LGLW_FALSE/*bPressed*/, LGLW_MOUSE_WHEELUP);
  621. eventHandled = LGLW_TRUE;
  622. break;
  623. case Button5:
  624. loc_handle_mousebutton(lglw, LGLW_FALSE/*bPressed*/, LGLW_MOUSE_WHEELDOWN);
  625. eventHandled = LGLW_TRUE;
  626. break;
  627. }
  628. break;
  629. case SelectionClear:
  630. printf("vstgltest<lglw_linux>: xev SelectionClear\n");
  631. lglw->clipboard.numChars = 0;
  632. free(lglw->clipboard.data);
  633. eventHandled = LGLW_TRUE;
  634. break;
  635. case SelectionRequest:
  636. printf("vstgltest<lglw_linux>: xev SelectionRequest\n");
  637. XSelectionRequestEvent *cbReq = (XSelectionRequestEvent*)xev;
  638. XSelectionEvent cbRes;
  639. Atom utf8 = XInternAtom(lglw->xdsp, "UTF8_STRING", False);
  640. cbRes.type = SelectionNotify;
  641. cbRes.requestor = cbReq->requestor;
  642. cbRes.selection = cbReq->selection;
  643. cbRes.target = cbReq->target;
  644. cbRes.time = cbReq->time;
  645. if(cbReq->target == utf8)
  646. {
  647. XChangeProperty(lglw->xdsp, cbReq->requestor, cbReq->property, utf8, 8/*format*/, PropModeReplace,
  648. (unsigned char *)lglw->clipboard.data, lglw->clipboard.numChars);
  649. cbRes.property = cbReq->property;
  650. }
  651. else
  652. {
  653. cbRes.property = None;
  654. }
  655. XSendEvent(lglw->xdsp, cbReq->requestor, True, NoEventMask, (XEvent *)&cbRes);
  656. eventHandled = LGLW_TRUE;
  657. break;
  658. }
  659. if(LGLW_FALSE == eventHandled)
  660. {
  661. if(0 == lglw->parent_xwnd)
  662. {
  663. printf("lglw_linux:loc_eventProc: no parent window to send events to");
  664. XSendEvent(lglw->xdsp, InputFocus, True/*propgate*/, NoEventMask, xev);
  665. }
  666. else
  667. {
  668. XSendEvent(lglw->xdsp, lglw->parent_xwnd, True/*propgate*/, NoEventMask, xev);
  669. }
  670. }
  671. }
  672. }
  673. }
  674. static void loc_setProperty(Display *_display, Window _window, const char *_name, void *_value) {
  675. size_t data = (size_t)_value;
  676. long temp[2];
  677. // Split the 64 bit pointer into a little-endian long array
  678. temp[0] = (long)(data & 0xffffffffUL);
  679. temp[1] = (long)(data >> 32L);
  680. printf("xxx lglw_linux:loc_setProperty: name=\"%s\" value=%p temp[0]=%08x temp[1]=%08x\n", _name, _value, temp[0], temp[1]);
  681. Atom atom = XInternAtom(_display, _name, False/*only_if_exists*/);
  682. // (note) what's quite weird here is that we're writing an array of 32bit values, yet the element format must be 64bit (long)
  683. XChangeProperty(_display, _window,
  684. atom/*property*/,
  685. atom/*type*/,
  686. 32/*format*/,
  687. PropModeReplace/*mode*/,
  688. (unsigned char*)temp/*data*/,
  689. 2/*nelements*/
  690. );
  691. }
  692. static void *loc_getProperty(Display *_display, Window _window, const char *_name) {
  693. int userSize;
  694. unsigned long bytes;
  695. unsigned long userCount;
  696. unsigned char *data;
  697. Atom userType;
  698. Atom atom = XInternAtom(_display, _name, False);
  699. // (note) 64bit properties need to be read with two XGetWindowProperty() calls.
  700. // When using just one call and setting the 'length' to 2, the upper 32bit (second array element) will be 0xFFFFffff.
  701. XGetWindowProperty(_display,
  702. _window,
  703. atom,
  704. 0/*offset*/,
  705. 1/*length*/,
  706. False/*delete*/,
  707. AnyPropertyType,
  708. &userType/*actual_type_return*/,
  709. &userSize/*actual_format_return*/,
  710. &userCount/*nitems_return*/,
  711. &bytes/*bytes_after_return / partial reads*/,
  712. &data);
  713. union {
  714. uint32_t ui[2];
  715. void *any;
  716. } uptr;
  717. uptr.any = 0;
  718. printf("xxx lglw_linux: loc_getProperty: LOWER userSize=%d userCount=%lu bytes=%lu data=%p\n", userSize, userCount, bytes, data);
  719. if(NULL != data)
  720. {
  721. if(userCount >= 1)
  722. {
  723. if(userCount >= 2)
  724. {
  725. printf("xxx loc_getProperty: lo=0x%08x hi=0x%08x\n", ((uint32_t*)data)[0], ((uint32_t*)data)[1]);
  726. }
  727. // lower 32-bit
  728. uptr.ui[0] = *(long*)data;
  729. uptr.ui[1] = 0;
  730. printf("xxx lower=0x%08x\n", uptr.ui[0]);
  731. // // printf("xxx upper=0x%08x\n", uptr.ui[1]);
  732. XFree(data);
  733. // // if(userCount >= 2)
  734. {
  735. XGetWindowProperty(_display,
  736. _window,
  737. atom,
  738. 1/*offset*/,
  739. 1/*length*/,
  740. False/*delete*/,
  741. AnyPropertyType,
  742. &userType/*actual_type_return*/,
  743. &userSize/*actual_format_return*/,
  744. &userCount/*nitems_return*/,
  745. &bytes/*bytes_after_return / partial reads*/,
  746. &data);
  747. printf("xxx lglw_linux: loc_getProperty: UPPER userSize=%d userCount=%lu bytes=%lu data=%p\n", userSize, userCount, bytes, data);
  748. if(NULL != data)
  749. {
  750. // upper 32-bit
  751. uptr.ui[1] = *(long*)data;
  752. printf("xxx upper=0x%08x\n", uptr.ui[1]);
  753. XFree(data);
  754. }
  755. }
  756. }
  757. }
  758. printf("xxx lglw_linux: loc_getProperty: return value=%p\n", uptr.any);
  759. return uptr.any;
  760. }
  761. #ifdef ARCH_X64
  762. #if 0
  763. // Pulled from the Renoise 64-bit callback example
  764. // Unsure what data was supposed to be, but swapping it to a function name did not work
  765. // This does nothing, no event proc found
  766. static void loc_setEventProc (Display *display, Window window) {
  767. size_t data = (size_t)loc_eventProc;
  768. long temp[2];
  769. printf("vstgltest<lglw_linux>: setEventProc (2*32bit). window=%lu loc_eventProc=%p\n", window, &loc_eventProc);
  770. // Split the 64 bit pointer into a little-endian unsigned int array
  771. temp[0] = (uint32_t)(data & 0xffffffffUL);
  772. temp[1] = (uint32_t)(data >> 32L);
  773. Atom atom = XInternAtom(display, "_XEventProc", False);
  774. XChangeProperty(display, window,
  775. atom/*property*/,
  776. atom/*type*/,
  777. 32/*format*/,
  778. PropModeReplace/*mode*/,
  779. (unsigned char*)temp/*data*/,
  780. 2/*nelements*/
  781. );
  782. }
  783. #else
  784. // GPL code pulled from the amsynth example <https://github.com/amsynth/amsynth/blob/4a87798e650c6d71d70274a961c9b8d98fc6da7e/src/amsynth_vst.cpp>
  785. // Simply swapped out the function names, crashes Ardour in the same was as the others
  786. static void loc_setEventProc (Display *display, Window window) {
  787. //
  788. // JUCE calls XGetWindowProperty with long_length = 1 which means it only fetches the lower 32 bits of the address.
  789. // Therefore we need to ensure we return an address in the lower 32-bits of address space.
  790. //
  791. // based on mach_override
  792. static const unsigned char kJumpInstructions[] = {
  793. 0xFF, 0x25, 0x00, 0x00, 0x00, 0x00,
  794. 0x00, 0x00, 0x00, 0x00,
  795. 0x00, 0x00, 0x00, 0x00
  796. };
  797. static const int kJumpAddress = 6;
  798. static char *ptr = 0;
  799. if (!ptr) {
  800. ptr = (char *)mmap(0,
  801. getpagesize()/*PAGE_SIZE*/,
  802. PROT_READ | PROT_WRITE | PROT_EXEC,
  803. MAP_ANONYMOUS | MAP_PRIVATE | MAP_32BIT,
  804. 0, 0);
  805. if (ptr == MAP_FAILED) {
  806. perror("mmap");
  807. ptr = 0;
  808. return;
  809. } else {
  810. memcpy(ptr, kJumpInstructions, sizeof(kJumpInstructions));
  811. *((uint64_t *)(ptr + kJumpAddress)) = (uint64_t)(&loc_eventProc);
  812. msync(ptr, sizeof(kJumpInstructions), MS_INVALIDATE);
  813. printf("vstgltest<lglw_linux>: 64bit trampoline installed\n");
  814. }
  815. }
  816. long temp[2] = {(uint32_t)(((size_t)ptr)&0xFFFFfffful), 0};
  817. Atom atom = XInternAtom(display, "_XEventProc", False);
  818. XChangeProperty(display, window,
  819. atom/*property*/,
  820. atom/*type*/,
  821. 32/*format*/,
  822. PropModeReplace/*mode*/,
  823. (unsigned char *)temp/*data*/,
  824. 2/*nelements*/
  825. );
  826. }
  827. #endif
  828. #else
  829. // Pulled from the eXT2 example
  830. static void loc_setEventProc (Display *display, Window window) {
  831. void* data = (void*)&loc_eventProc; // swapped the function name here
  832. // (note) 32-bit only
  833. Atom atom = XInternAtom(display, "_XEventProc", False);
  834. XChangeProperty(display, window,
  835. atom/*property*/,
  836. atom/*type*/,
  837. 32/*format*/,
  838. PropModeReplace/*mode*/,
  839. (unsigned char*)&data/*data*/,
  840. 1/*nelements*/
  841. );
  842. }
  843. #endif // ARCH_X64
  844. // ---------------------------------------------------------------------------- lglw_window_open
  845. lglw_bool_t lglw_window_open (lglw_t _lglw, void *_parentHWNDOrNull, int32_t _x, int32_t _y, int32_t _w, int32_t _h) {
  846. lglw_bool_t r = LGLW_FALSE;
  847. LGLW(_lglw);
  848. if(NULL != lglw)
  849. {
  850. lglw_log("lglw:lglw_window_open: 1, %p, %i \n", (Window)_parentHWNDOrNull, (Window)_parentHWNDOrNull);
  851. lglw->parent_xwnd = (0 == _parentHWNDOrNull) ? DefaultRootWindow(lglw->xdsp) : (Window)_parentHWNDOrNull;
  852. lglw_log("lglw:lglw_window_open: 2 lglw=%p\n", lglw);
  853. if(_w <= 16)
  854. _w = lglw->hidden.size.x;
  855. lglw_log("lglw:lglw_window_open: 3\n");
  856. if(_h <= 16)
  857. _h = lglw->hidden.size.y;
  858. // TODO: compare to 'WindowClass' from Windows implementation
  859. lglw_log("lglw:lglw_window_open: 4\n");
  860. XSetWindowAttributes swa;
  861. // // XEvent event;
  862. XSync(lglw->xdsp, False);
  863. #if 1
  864. lglw_log("lglw:lglw_window_open: 5\n");
  865. swa.border_pixel = 0;
  866. swa.colormap = lglw->cmap;
  867. // (note) [bsp] setting this to NoEventMask causes all events to be propagated to the parent (host) window.
  868. // The host then reports the event to the plugin by calling its eventProc function (set via "_XEventProc").
  869. swa.event_mask = NoEventMask;/////ExposureMask | KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | EnterWindowMask | LeaveWindowMask | PointerMotionMask | ButtonMotionMask | FocusChangeMask;
  870. lglw->win.xwnd = XCreateWindow(lglw->xdsp/*display*/,
  871. DefaultRootWindow(lglw->xdsp)/*parent. see Cameron's comment below.*/,
  872. 0/*x*/,
  873. 0/*y*/,
  874. _w/*width*/,
  875. _h/*height*/,
  876. 0/*border_width*/,
  877. CopyFromParent/*depth*/,
  878. InputOutput/*class*/,
  879. lglw->vi->visual,
  880. CWBorderPixel | CWColormap | CWEventMask/*value_mask*/,
  881. &swa/*attributes*/
  882. );
  883. lglw_log("lglw:lglw_window_open: 6\n");
  884. XSetStandardProperties(lglw->xdsp/*display*/,
  885. lglw->win.xwnd/*window*/,
  886. "LGLW"/*window_name*/,
  887. "LGLW"/*icon_name*/,
  888. None/*icon_pixmap*/,
  889. NULL/*argv*/,
  890. 0/*argc*/,
  891. NULL/*XSizeHints*/
  892. );
  893. // Setup the event proc now, on the parent window as well just for the debug host
  894. // It was simpler to do this than check in the debug host for the reparent event
  895. lglw_log("lglw:lglw_window_open: 7\n");
  896. loc_setEventProc(lglw->xdsp, lglw->win.xwnd);
  897. loc_setProperty(lglw->xdsp, lglw->win.xwnd, "_lglw", (void*)lglw); // set instance pointer
  898. if(0 != _parentHWNDOrNull)
  899. {
  900. loc_setEventProc(lglw->xdsp, lglw->parent_xwnd);
  901. loc_setProperty(lglw->xdsp, lglw->parent_xwnd, "_lglw", (void*)lglw); // set instance pointer
  902. }
  903. // Some hosts only check and store the callback when the Window is reparented
  904. // Since creating the Window with a Parent may or may not do that, but the callback is not set,
  905. // ... it's created as a root window, the callback is set, and then it's reparented
  906. #if 1
  907. // (note) [cameronleger] In Ardour's code-base, the only time it looks for the _XEventProc is during a ReparentNotify event
  908. if (0 != _parentHWNDOrNull)
  909. {
  910. lglw_log("lglw:lglw_window_open: 8\n");
  911. XReparentWindow(lglw->xdsp, lglw->win.xwnd, lglw->parent_xwnd, 0, 0);
  912. }
  913. #endif
  914. lglw->win.b_owner = LGLW_TRUE;
  915. #else
  916. lglw->win.xwnd = (Window)_parentHWNDOrNull;
  917. lglw->win.b_owner = LGLW_FALSE;
  918. #endif
  919. lglw_log("lglw:lglw_window_open: 9\n");
  920. if(lglw->win.b_owner)
  921. {
  922. // // XMapRaised(lglw->xdsp, lglw->win.xwnd);
  923. XMapWindow(lglw->xdsp, lglw->win.xwnd);
  924. }
  925. #if 0
  926. XSelectInput(lglw->xdsp, lglw->win.xwnd,
  927. ExposureMask | KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | EnterWindowMask | LeaveWindowMask | PointerMotionMask | ButtonMotionMask | FocusChangeMask
  928. );
  929. XGrabKeyboard(lglw->xdsp, lglw->win.xwnd,
  930. False/*owner_events*/,
  931. GrabModeAsync/*pointer_mode*/,
  932. GrabModeAsync/*keyboard_mode*/,
  933. CurrentTime/*time*/
  934. );
  935. #endif
  936. #if 0
  937. XSetInputFocus(lglw->xdsp/*display*/,
  938. PointerRoot/*focus*/,
  939. RevertToPointerRoot/*revert_to*/,
  940. CurrentTime
  941. );
  942. #endif
  943. XSync(lglw->xdsp, False);
  944. lglw->win.mapped = LGLW_TRUE;
  945. lglw_log("lglw:lglw_window_open: 10\n");
  946. lglw->win.size.x = _w;
  947. lglw->win.size.y = _h;
  948. lglw_log("lglw:lglw_window_open: 11\n");
  949. loc_enable_dropfiles(lglw, (NULL != lglw->dropfiles.cbk));
  950. lglw_log("lglw:lglw_window_open: EXIT\n");
  951. r = LGLW_TRUE;
  952. }
  953. return r;
  954. }
  955. // ---------------------------------------------------------------------------- lglw_window_resize
  956. lglw_bool_t lglw_window_resize (lglw_t _lglw, int32_t _w, int32_t _h) {
  957. lglw_bool_t r = LGLW_FALSE;
  958. LGLW(_lglw);
  959. if(NULL != lglw)
  960. {
  961. if(0 != lglw->win.xwnd)
  962. {
  963. lglw_log("lglw:lglw_window_resize: 1\n");
  964. r = LGLW_TRUE;
  965. lglw_log("lglw:lglw_window_resize: 2\n");
  966. XResizeWindow(lglw->xdsp, lglw->win.xwnd, _w, _h);
  967. XRaiseWindow(lglw->xdsp, lglw->win.xwnd);
  968. lglw_log("lglw:lglw_window_resize: 3\n");
  969. int deltaW = _w - lglw->win.size.x;
  970. int deltaH = _h - lglw->win.size.y;
  971. lglw_log("lglw:lglw_window_resize: 4\n");
  972. lglw->win.size.x = _w;
  973. lglw->win.size.y = _h;
  974. lglw_log("lglw:lglw_window_resize: 5\n");
  975. Window root, parent, *children = NULL;
  976. unsigned int num_children;
  977. lglw_log("lglw:lglw_window_resize: 6\n");
  978. if(!XQueryTree(lglw->xdsp, lglw->win.xwnd, &root, &parent, &children, &num_children))
  979. return r;
  980. lglw_log("lglw:lglw_window_resize: 7\n");
  981. if(children)
  982. XFree((char *)children);
  983. lglw_log("lglw:lglw_window_resize: 8\n");
  984. // Resize parent window (if any)
  985. if(0 != parent)
  986. {
  987. lglw_log("lglw:lglw_window_resize: 8.1\n");
  988. int x, y;
  989. unsigned int width, height;
  990. unsigned int border_width;
  991. unsigned int depth;
  992. lglw_log("lglw:lglw_window_resize: 8.2\n");
  993. if(!XGetGeometry(lglw->xdsp, lglw->win.xwnd, &root, &x, &y, &width, &height, &border_width, &depth))
  994. return r;
  995. lglw_log("lglw:lglw_window_resize: 8.3\n");
  996. XResizeWindow(lglw->xdsp, parent, width + deltaW, height + deltaH);
  997. }
  998. lglw_log("lglw:lglw_window_resize: EXIT\n");
  999. }
  1000. }
  1001. return r;
  1002. }
  1003. // ---------------------------------------------------------------------------- lglw_window_close
  1004. void lglw_window_close (lglw_t _lglw) {
  1005. LGLW(_lglw);
  1006. if(NULL != lglw)
  1007. {
  1008. if(0 != lglw->win.xwnd)
  1009. {
  1010. lglw_log("lglw:lglw_window_close: 1\n");
  1011. lglw_timer_stop(_lglw);
  1012. lglw_log("lglw:lglw_window_close: 2\n");
  1013. glXMakeCurrent(lglw->xdsp, None, NULL);
  1014. lglw_log("lglw:lglw_window_close: 3\n");
  1015. if(lglw->win.b_owner)
  1016. {
  1017. XDestroyWindow(lglw->xdsp, lglw->win.xwnd);
  1018. lglw->win.b_owner = LGLW_FALSE;
  1019. }
  1020. XSync(lglw->xdsp, False);
  1021. lglw->win.xwnd = 0;
  1022. lglw->win.mapped = LGLW_FALSE;
  1023. }
  1024. }
  1025. lglw_log("lglw:lglw_window_close: EXIT\n");
  1026. }
  1027. // ---------------------------------------------------------------------------- lglw_window_show
  1028. void lglw_window_show(lglw_t _lglw) {
  1029. LGLW(_lglw);
  1030. if(NULL != lglw)
  1031. {
  1032. lglw_log("lglw:lglw_window_show: 1\n");
  1033. XMapRaised(lglw->xdsp, lglw->win.xwnd);
  1034. lglw->win.mapped = LGLW_TRUE;
  1035. }
  1036. lglw_log("lglw:lglw_window_show: EXIT\n");
  1037. }
  1038. // ---------------------------------------------------------------------------- lglw_window_hide
  1039. void lglw_window_hide(lglw_t _lglw) {
  1040. LGLW(_lglw);
  1041. if(NULL != lglw)
  1042. {
  1043. lglw_log("lglw:lglw_window_hide: 1\n");
  1044. XUnmapWindow(lglw->xdsp, lglw->win.xwnd);
  1045. lglw->win.mapped = LGLW_FALSE;
  1046. }
  1047. lglw_log("lglw:lglw_window_hide: EXIT\n");
  1048. }
  1049. // ---------------------------------------------------------------------------- lglw_window_is_visible
  1050. lglw_bool_t lglw_window_is_visible(lglw_t _lglw) {
  1051. lglw_bool_t r = LGLW_FALSE;
  1052. LGLW(_lglw);
  1053. // lglw_log("lglw:lglw_window_is_visible: 1\n");
  1054. if(NULL != lglw && 0 != lglw->win.xwnd)
  1055. {
  1056. // lglw_log("lglw:lglw_window_is_visible: 2\n");
  1057. r = lglw->win.mapped;
  1058. }
  1059. // lglw_log("lglw:lglw_window_is_visible: EXIT\n");
  1060. return r;
  1061. }
  1062. // ---------------------------------------------------------------------------- lglw_window_size_get
  1063. void lglw_window_size_get(lglw_t _lglw, int32_t *_retX, int32_t *_retY) {
  1064. LGLW(_lglw);
  1065. lglw_log("lglw:lglw_window_size_get: 1\n");
  1066. if(NULL != lglw)
  1067. {
  1068. if(0 != lglw->win.xwnd)
  1069. {
  1070. if(NULL != _retX)
  1071. *_retX = lglw->win.size.x;
  1072. if(NULL != _retY)
  1073. *_retY = lglw->win.size.y;
  1074. }
  1075. }
  1076. lglw_log("lglw:lglw_window_size_get: EXIT\n");
  1077. }
  1078. // ---------------------------------------------------------------------------- lglw_redraw
  1079. void lglw_redraw(lglw_t _lglw) {
  1080. LGLW(_lglw);
  1081. // (todo) implement me
  1082. if(NULL != lglw)
  1083. {
  1084. if(0 != lglw->win.xwnd)
  1085. {
  1086. // TODO Event Loop
  1087. lglw_log("lglw:lglw_redraw: 1\n");
  1088. XEvent xev;
  1089. xev.xany.type = Expose;
  1090. xev.xany.serial = 0;
  1091. xev.xany.send_event = True;
  1092. xev.xany.display = lglw->xdsp;
  1093. xev.xany.window = lglw->win.xwnd;
  1094. xev.xexpose.x = 0;
  1095. xev.xexpose.y = 0;
  1096. xev.xexpose.width = lglw->win.size.x;
  1097. xev.xexpose.height = lglw->win.size.y;
  1098. xev.xexpose.count = 0;
  1099. XSendEvent(lglw->xdsp, lglw->win.xwnd,
  1100. True/*propagate*/,
  1101. ExposureMask/*event_mask*/,
  1102. &xev
  1103. );
  1104. XFlush(lglw->xdsp);
  1105. }
  1106. }
  1107. }
  1108. // ---------------------------------------------------------------------------- lglw_redraw_callback_set
  1109. void lglw_redraw_callback_set(lglw_t _lglw, lglw_redraw_fxn_t _cbk) {
  1110. LGLW(_lglw);
  1111. if(NULL != lglw)
  1112. {
  1113. lglw->redraw.cbk = _cbk;
  1114. }
  1115. }
  1116. // ---------------------------------------------------------------------------- lglw_glcontext_push
  1117. void lglw_glcontext_push(lglw_t _lglw) {
  1118. LGLW(_lglw);
  1119. if(NULL != lglw)
  1120. {
  1121. lglw->prev.drw = glXGetCurrentDrawable();
  1122. lglw->prev.ctx = glXGetCurrentContext();
  1123. // lglw_log("lglw:lglw_glcontext_push: win.xwnd=%p hidden.xwnd=%p ctx=%p\n",
  1124. // lglw->win.xwnd, lglw->hidden.xwnd, lglw->ctx);
  1125. if(!glXMakeCurrent(lglw->xdsp, (0 == lglw->win.xwnd) ? lglw->hidden.xwnd : lglw->win.xwnd, lglw->ctx))
  1126. {
  1127. 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());
  1128. }
  1129. }
  1130. }
  1131. // ---------------------------------------------------------------------------- lglw_glcontext_pop
  1132. void lglw_glcontext_pop(lglw_t _lglw) {
  1133. LGLW(_lglw);
  1134. if(NULL != lglw)
  1135. {
  1136. // lglw_log("lglw:lglw_glcontext_pop: prev.drw=%p prev.ctx=%p\n",
  1137. // lglw->prev.drw, lglw->prev.ctx);
  1138. if(!glXMakeCurrent(lglw->xdsp, lglw->prev.drw, lglw->prev.ctx))
  1139. {
  1140. lglw_log("[---] lglw_glcontext_pop: glXMakeCurrent() failed. prev.drw=%p ctx=%p glGetError()=%d\n", lglw->prev.drw, lglw->prev.ctx, glGetError());
  1141. }
  1142. }
  1143. }
  1144. // ---------------------------------------------------------------------------- lglw_swap_buffers
  1145. void lglw_swap_buffers(lglw_t _lglw) {
  1146. LGLW(_lglw);
  1147. if(NULL != lglw)
  1148. {
  1149. if(0 != lglw->win.xwnd)
  1150. {
  1151. // lglw_log("lglw:lglw_swap_buffers: 1\n");
  1152. glXSwapBuffers(lglw->xdsp, lglw->win.xwnd);
  1153. }
  1154. }
  1155. }
  1156. // ---------------------------------------------------------------------------- lglw_swap_interval_set
  1157. typedef void (APIENTRY *PFNWGLEXTSWAPINTERVALPROC) (int);
  1158. void lglw_swap_interval_set(lglw_t _lglw, int32_t _ival) {
  1159. LGLW(_lglw);
  1160. if(NULL != lglw)
  1161. {
  1162. lglw_log("lglw:lglw_swap_interval_set: 1\n");
  1163. PFNWGLEXTSWAPINTERVALPROC glXSwapIntervalEXT;
  1164. glXSwapIntervalEXT = (PFNWGLEXTSWAPINTERVALPROC) glXGetProcAddress((const GLubyte*)"glXSwapIntervalEXT");
  1165. if(NULL != glXSwapIntervalEXT)
  1166. {
  1167. lglw_log("lglw:lglw_swap_interval_set: 2\n");
  1168. glXSwapIntervalEXT(_ival);
  1169. lglw->win.swap_interval = _ival;
  1170. }
  1171. }
  1172. }
  1173. // ---------------------------------------------------------------------------- lglw_swap_interval_get
  1174. int32_t lglw_swap_interval_get(lglw_t _lglw) {
  1175. LGLW(_lglw);
  1176. int32_t r = 0;
  1177. if(NULL != lglw)
  1178. {
  1179. r = lglw->win.swap_interval;
  1180. }
  1181. return r;
  1182. }
  1183. // ---------------------------------------------------------------------------- loc_handle_mouseleave
  1184. static void loc_handle_mouseleave(lglw_int_t *lglw) {
  1185. lglw->focus.state &= ~LGLW_FOCUS_MOUSE;
  1186. if(NULL != lglw->focus.cbk)
  1187. {
  1188. lglw->focus.cbk(lglw, lglw->focus.state, LGLW_FOCUS_MOUSE);
  1189. }
  1190. lglw_log("xxx lglw:loc_handle_mouseleave: LEAVE\n");
  1191. }
  1192. // ---------------------------------------------------------------------------- loc_handle_mouseenter
  1193. static void loc_handle_mouseenter(lglw_int_t *lglw) {
  1194. lglw->focus.state |= LGLW_FOCUS_MOUSE;
  1195. if(NULL != lglw->focus.cbk)
  1196. {
  1197. lglw->focus.cbk(lglw, lglw->focus.state, LGLW_FOCUS_MOUSE);
  1198. }
  1199. lglw_log("xxx lglw:loc_handle_mouseenter: LEAVE\n");
  1200. }
  1201. // ---------------------------------------------------------------------------- loc_handle_mousebutton
  1202. static void loc_handle_mousebutton(lglw_int_t *lglw, lglw_bool_t _bPressed, uint32_t _button) {
  1203. if(_bPressed)
  1204. lglw->mouse.button_state |= _button;
  1205. else
  1206. lglw->mouse.button_state &= ~_button;
  1207. if(NULL != lglw->mouse.cbk)
  1208. {
  1209. lglw->mouse.cbk(lglw, lglw->mouse.p.x, lglw->mouse.p.y, lglw->mouse.button_state, _button);
  1210. }
  1211. }
  1212. // ---------------------------------------------------------------------------- loc_handle_mousemotion
  1213. static void loc_handle_mousemotion(lglw_int_t *lglw) {
  1214. if(NULL != lglw->mouse.cbk)
  1215. {
  1216. lglw->mouse.cbk(lglw, lglw->mouse.p.x, lglw->mouse.p.y, lglw->mouse.button_state, 0u/*changedbuttonstate*/);
  1217. }
  1218. }
  1219. // ---------------------------------------------------------------------------- lglw_mouse_callback_set
  1220. void lglw_mouse_callback_set(lglw_t _lglw, lglw_mouse_fxn_t _cbk) {
  1221. LGLW(_lglw);
  1222. if(NULL != lglw)
  1223. {
  1224. lglw->mouse.cbk = _cbk;
  1225. }
  1226. }
  1227. // ---------------------------------------------------------------------------- lglw_mouse_callback_set
  1228. void lglw_focus_callback_set(lglw_t _lglw, lglw_focus_fxn_t _cbk) {
  1229. LGLW(_lglw);
  1230. if(NULL != lglw)
  1231. {
  1232. lglw->focus.cbk = _cbk;
  1233. }
  1234. }
  1235. // ---------------------------------------------------------------------------- loc_handle_key
  1236. static lglw_bool_t loc_handle_key(lglw_int_t *lglw, lglw_bool_t _bPressed, uint32_t _vkey) {
  1237. lglw_bool_t r = LGLW_FALSE;
  1238. if(NULL != lglw->keyboard.cbk)
  1239. {
  1240. r = lglw->keyboard.cbk(lglw, _vkey, lglw->keyboard.kmod_state, _bPressed);
  1241. }
  1242. return r;
  1243. }
  1244. // ---------------------------------------------------------------------------- lglw_keyboard_callback_set
  1245. void lglw_keyboard_callback_set(lglw_t _lglw, lglw_keyboard_fxn_t _cbk) {
  1246. LGLW(_lglw);
  1247. if(NULL != lglw)
  1248. {
  1249. lglw->keyboard.cbk = _cbk;
  1250. }
  1251. }
  1252. // ---------------------------------------------------------------------------- lglw_keyboard_get_modifiers
  1253. uint32_t lglw_keyboard_get_modifiers(lglw_t _lglw) {
  1254. uint32_t r = 0u;
  1255. LGLW(_lglw);
  1256. if(NULL != lglw)
  1257. {
  1258. r = lglw->keyboard.kmod_state;
  1259. }
  1260. return r;
  1261. }
  1262. // ---------------------------------------------------------------------------- lglw_touchkeyboard_show
  1263. void lglw_touchkeyboard_show(lglw_t _lglw, lglw_bool_t _bEnable) {
  1264. LGLW(_lglw);
  1265. // (todo) implement me
  1266. if(NULL != lglw)
  1267. {
  1268. }
  1269. }
  1270. // ---------------------------------------------------------------------------- lglw_mouse_get_buttons
  1271. uint32_t lglw_mouse_get_buttons(lglw_t _lglw) {
  1272. uint32_t r = 0u;
  1273. LGLW(_lglw);
  1274. if(NULL != lglw)
  1275. {
  1276. r = lglw->mouse.button_state;
  1277. }
  1278. return r;
  1279. }
  1280. // ---------------------------------------------------------------------------- lglw_mouse_grab
  1281. void lglw_mouse_grab(lglw_t _lglw, uint32_t _grabMode) {
  1282. LGLW(_lglw);
  1283. if(NULL != lglw)
  1284. {
  1285. if(0 != lglw->win.xwnd)
  1286. {
  1287. if(!lglw->mouse.touch.b_enable)
  1288. {
  1289. if(lglw->mouse.grab.mode != _grabMode)
  1290. {
  1291. lglw_mouse_ungrab(_lglw);
  1292. }
  1293. int result;
  1294. switch(_grabMode)
  1295. {
  1296. default:
  1297. case LGLW_MOUSE_GRAB_NONE:
  1298. break;
  1299. case LGLW_MOUSE_GRAB_CAPTURE:
  1300. result = XGrabPointer(lglw->xdsp, lglw->win.xwnd,
  1301. True/*owner_events*/,
  1302. ButtonPressMask | ButtonReleaseMask | EnterWindowMask | LeaveWindowMask | PointerMotionMask | PointerMotionHintMask | ButtonMotionMask | KeymapStateMask/*event_mask*/,
  1303. GrabModeAsync/*pointer_mode*/,
  1304. GrabModeAsync/*keyboard_mode*/,
  1305. lglw->win.xwnd/*confine_to*/,
  1306. None/*cursor*/,
  1307. CurrentTime/*time*/);
  1308. if(GrabSuccess != result)
  1309. {
  1310. printf("vstgltest<lglw_linux>: Grab Result: %i\n", result);
  1311. }
  1312. else
  1313. {
  1314. lglw->mouse.grab.mode = _grabMode;
  1315. }
  1316. break;
  1317. case LGLW_MOUSE_GRAB_WARP:
  1318. result = XGrabPointer(lglw->xdsp, lglw->win.xwnd,
  1319. True/*owner_events*/,
  1320. ButtonPressMask | ButtonReleaseMask | EnterWindowMask | LeaveWindowMask | PointerMotionMask | PointerMotionHintMask | ButtonMotionMask | KeymapStateMask/*event_mask*/,
  1321. GrabModeAsync/*pointer_mode*/,
  1322. GrabModeAsync/*keyboard_mode*/,
  1323. lglw->win.xwnd/*confine_to*/,
  1324. None/*cursor*/,
  1325. CurrentTime/*time*/);
  1326. if(GrabSuccess != result)
  1327. {
  1328. printf("vstgltest<lglw_linux>: Grab Result: %i\n", result);
  1329. }
  1330. else
  1331. {
  1332. lglw_mouse_cursor_show(_lglw, LGLW_FALSE);
  1333. lglw->mouse.grab.p = lglw->mouse.p;
  1334. lglw->mouse.grab.last_p = lglw->mouse.p;
  1335. lglw->mouse.grab.mode = _grabMode;
  1336. }
  1337. break;
  1338. }
  1339. }
  1340. }
  1341. }
  1342. }
  1343. // ---------------------------------------------------------------------------- lglw_mouse_ungrab
  1344. void lglw_mouse_ungrab(lglw_t _lglw) {
  1345. LGLW(_lglw);
  1346. if(NULL != lglw)
  1347. {
  1348. if(0 != lglw->win.xwnd)
  1349. {
  1350. if(!lglw->mouse.touch.b_enable)
  1351. {
  1352. switch(lglw->mouse.grab.mode)
  1353. {
  1354. default:
  1355. case LGLW_MOUSE_GRAB_NONE:
  1356. break;
  1357. case LGLW_MOUSE_GRAB_CAPTURE:
  1358. XUngrabPointer(lglw->xdsp, CurrentTime);
  1359. lglw->mouse.grab.mode = LGLW_MOUSE_GRAB_NONE;
  1360. break;
  1361. case LGLW_MOUSE_GRAB_WARP:
  1362. XUngrabPointer(lglw->xdsp, CurrentTime);
  1363. lglw->mouse.grab.mode = LGLW_MOUSE_GRAB_NONE;
  1364. lglw->mouse.grab.b_queue_warp = LGLW_TRUE;
  1365. lglw_mouse_cursor_show(_lglw, LGLW_TRUE);
  1366. break;
  1367. }
  1368. }
  1369. }
  1370. }
  1371. }
  1372. // ---------------------------------------------------------------------------- lglw_mouse_warp
  1373. void lglw_mouse_warp(lglw_t _lglw, int32_t _x, int32_t _y) {
  1374. LGLW(_lglw);
  1375. if(NULL != lglw)
  1376. {
  1377. if(0 != lglw->win.xwnd)
  1378. {
  1379. XWarpPointer(lglw->xdsp,
  1380. None/*src_w*/,
  1381. lglw->win.xwnd/*dest_w*/,
  1382. 0/*src_x*/,
  1383. 0/*src_y*/,
  1384. 0/*src_width*/,
  1385. 0/*src_height*/,
  1386. _x/*dest_x*/,
  1387. _y/*dest_y*/);
  1388. }
  1389. }
  1390. }
  1391. // ---------------------------------------------------------------------------- loc_handle_queued_mouse_warp
  1392. static void loc_handle_queued_mouse_warp(lglw_int_t *lglw) {
  1393. if(lglw->mouse.grab.b_queue_warp)
  1394. {
  1395. lglw->mouse.grab.b_queue_warp = LGLW_FALSE;
  1396. lglw_mouse_warp(lglw, lglw->mouse.grab.p.x, lglw->mouse.grab.p.y);
  1397. lglw->mouse.grab.last_p = lglw->mouse.grab.p;
  1398. }
  1399. }
  1400. // ---------------------------------------------------------------------------- lglw_mouse_cursor_show
  1401. void lglw_mouse_cursor_show (lglw_t _lglw, lglw_bool_t _bShow) {
  1402. LGLW(_lglw);
  1403. if(NULL != lglw)
  1404. {
  1405. if(LGLW_FALSE == _bShow)
  1406. {
  1407. Pixmap noPxm;
  1408. Cursor noCursor;
  1409. XColor black, dummy;
  1410. static char pxmNoData[] = {0, 0, 0, 0, 0, 0, 0, 0};
  1411. XAllocNamedColor(lglw->xdsp, lglw->cmap, "black", &black, &dummy);
  1412. noPxm = XCreateBitmapFromData(lglw->xdsp, lglw->win.xwnd, pxmNoData, 8, 8);
  1413. noCursor = XCreatePixmapCursor(lglw->xdsp, noPxm, noPxm, &black, &black, 0, 0);
  1414. XDefineCursor(lglw->xdsp, lglw->win.xwnd, noCursor);
  1415. XFreeCursor(lglw->xdsp, noCursor);
  1416. if(noPxm != None)
  1417. {
  1418. XFreePixmap(lglw->xdsp, noPxm);
  1419. }
  1420. }
  1421. else
  1422. {
  1423. XUndefineCursor(lglw->xdsp, lglw->win.xwnd);
  1424. }
  1425. }
  1426. }
  1427. // ---------------------------------------------------------------------------- lglw_timer_start
  1428. void lglw_timer_start(lglw_t _lglw, uint32_t _millisec) {
  1429. LGLW(_lglw);
  1430. // (todo) implement me
  1431. if(NULL != lglw)
  1432. {
  1433. }
  1434. }
  1435. // ---------------------------------------------------------------------------- lglw_timer_stop
  1436. void lglw_timer_stop(lglw_t _lglw) {
  1437. LGLW(_lglw);
  1438. // (todo) implement me
  1439. if(NULL != lglw)
  1440. {
  1441. }
  1442. }
  1443. // ---------------------------------------------------------------------------- lglw_timer_callback_set
  1444. void lglw_timer_callback_set(lglw_t _lglw, lglw_timer_fxn_t _cbk) {
  1445. LGLW(_lglw);
  1446. if(NULL != lglw)
  1447. {
  1448. lglw->timer.cbk = _cbk;
  1449. }
  1450. }
  1451. // ---------------------------------------------------------------------------- loc_enable_dropfiles
  1452. static void loc_enable_dropfiles(lglw_int_t *lglw, lglw_bool_t _bEnable) {
  1453. // (todo) implement me
  1454. }
  1455. // ---------------------------------------------------------------------------- lglw_dropfiles_callback_set
  1456. void lglw_dropfiles_callback_set(lglw_t _lglw, lglw_dropfiles_fxn_t _cbk) {
  1457. LGLW(_lglw);
  1458. if(NULL != _lglw)
  1459. {
  1460. lglw->dropfiles.cbk = _cbk;
  1461. loc_enable_dropfiles(lglw, (NULL != _cbk));
  1462. }
  1463. }
  1464. // ---------------------------------------------------------------------------- loc_touchinput_update
  1465. static void loc_touchinput_update(lglw_int_t *lglw) {
  1466. // (todo) implement me
  1467. }
  1468. // ---------------------------------------------------------------------------- lglw_touchinput_set
  1469. void lglw_touchinput_set(lglw_t _lglw, lglw_bool_t _bEnable) {
  1470. LGLW(_lglw);
  1471. if(NULL != _lglw)
  1472. {
  1473. lglw->mouse.touch.b_enable = _bEnable;
  1474. lglw->mouse.touch.b_update_queued = LGLW_TRUE;
  1475. }
  1476. }
  1477. // ---------------------------------------------------------------------------- lglw_touchinput_get
  1478. lglw_bool_t lglw_touchinput_get(lglw_t _lglw) {
  1479. lglw_bool_t r = LGLW_FALSE;
  1480. LGLW(_lglw);
  1481. if(NULL != _lglw)
  1482. {
  1483. r = lglw->mouse.touch.b_enable;
  1484. }
  1485. return r;
  1486. }
  1487. // ---------------------------------------------------------------------------- lglw_clipboard_text_set
  1488. void lglw_clipboard_text_set(lglw_t _lglw, const uint32_t _numChars, const char *_text) {
  1489. LGLW(_lglw);
  1490. (void)_numChars;
  1491. if(NULL != _text)
  1492. {
  1493. if(NULL != _lglw)
  1494. {
  1495. if(0 != lglw->win.xwnd)
  1496. {
  1497. uint32_t numChars = (0u == _numChars) ? ((uint32_t)strlen(_text)+1u) : _numChars;
  1498. if(numChars > 0u)
  1499. {
  1500. lglw->clipboard.numChars = numChars;
  1501. lglw->clipboard.data = malloc(numChars+1);
  1502. uint32_t i;
  1503. for(i = 0u; i < numChars; i++)
  1504. {
  1505. lglw->clipboard.data[i] = _text[i];
  1506. }
  1507. lglw->clipboard.data[numChars - 1] = 0;
  1508. printf("xxx lglw_clipboard_text_set(%i): %s\n", lglw->clipboard.numChars, lglw->clipboard.data);
  1509. Atom clipboard = XInternAtom(lglw->xdsp, "CLIPBOARD", False);
  1510. XSetSelectionOwner(lglw->xdsp, clipboard, lglw->win.xwnd, CurrentTime);
  1511. XSync(lglw->xdsp, False);
  1512. }
  1513. }
  1514. }
  1515. }
  1516. }
  1517. // ---------------------------------------------------------------------------- loc_is_clipboard_event
  1518. static Bool loc_is_clipboard_event(Display *_display, XEvent *_xevent, XPointer _xarg) {
  1519. return _xevent->type == SelectionNotify;
  1520. }
  1521. // ---------------------------------------------------------------------------- lglw_clipboard_text_get
  1522. void lglw_clipboard_text_get(lglw_t _lglw, uint32_t _maxChars, uint32_t *_retNumChars, char *_retText) {
  1523. LGLW(_lglw);
  1524. if(NULL != _retNumChars)
  1525. *_retNumChars = 0u;
  1526. if(NULL != _retText)
  1527. *_retText = 0;
  1528. if(_maxChars > 0u)
  1529. {
  1530. if(NULL != _lglw)
  1531. {
  1532. if(0 != lglw->win.xwnd)
  1533. {
  1534. Window owner;
  1535. XEvent xev;
  1536. XSelectionEvent *cbReq;
  1537. Atom clipboard = XInternAtom(lglw->xdsp, "CLIPBOARD", False);
  1538. Atom utf8 = XInternAtom(lglw->xdsp, "UTF8_STRING", False);
  1539. Atom target = XInternAtom(lglw->xdsp, "_clipboard_result", False);
  1540. owner = XGetSelectionOwner(lglw->xdsp, clipboard);
  1541. if(owner == None)
  1542. {
  1543. printf("xxx lglw_clipboard_text_get: No Window can provide a clipboard result\n");
  1544. return;
  1545. }
  1546. if(owner == lglw->win.xwnd)
  1547. {
  1548. printf("xxx lglw_clipboard_text_get: We are the owner of the clipboard, skip X interactions\n");
  1549. uint32_t i = 0u;
  1550. for(; i < _maxChars; i++)
  1551. {
  1552. _retText[i] = lglw->clipboard.data[i];
  1553. if(0 == _retText[i])
  1554. break;
  1555. }
  1556. _retText[_maxChars - 1u] = 0;
  1557. if(NULL != _retNumChars)
  1558. *_retNumChars = i;
  1559. printf("xxx lglw_clipboard_text_get: (result on next line)\n%s\n", _retText);
  1560. return;
  1561. }
  1562. XConvertSelection(lglw->xdsp, clipboard, utf8, target, lglw->win.xwnd, CurrentTime);
  1563. XIfEvent(lglw->xdsp, &xev, &loc_is_clipboard_event, None);
  1564. cbReq = (XSelectionEvent*)&xev;
  1565. if(None == cbReq->property)
  1566. {
  1567. printf("xxx lglw_clipboard_text_get: Clipboard was not converted to UTF-8 string\n");
  1568. return;
  1569. }
  1570. Atom returnType;
  1571. int returnFormat;
  1572. unsigned long size, returnSize, bytesLeft;
  1573. unsigned char *propertyValue = NULL;
  1574. XGetWindowProperty(lglw->xdsp, lglw->win.xwnd, target,
  1575. 0/*offset*/,
  1576. 0/*length*/,
  1577. False/*delete*/,
  1578. AnyPropertyType/*req_type*/,
  1579. &returnType/*actual_type_return*/,
  1580. &returnFormat/*actual_format_return*/,
  1581. &returnSize/*nitems_return*/,
  1582. &size/*bytes_after_return*/,
  1583. &propertyValue/*prop_return*/);
  1584. XFree(propertyValue);
  1585. if(utf8 != returnType)
  1586. {
  1587. printf("xxx lglw_clipboard_text_get: Clipboard result is not a UTF-8 string\n");
  1588. return;
  1589. }
  1590. if(8u != returnFormat)
  1591. {
  1592. printf("xxx lglw_clipboard_text_get: Clipboard format is not a char array\n");
  1593. return;
  1594. }
  1595. if(_maxChars < size)
  1596. size = _maxChars;
  1597. size = 1 + ((size - 1) / 4);
  1598. // TODO: Even with the largest current use-case, multiple calls aren't necessary. do it anyway just in case
  1599. XGetWindowProperty(lglw->xdsp, lglw->win.xwnd, target,
  1600. 0/*offset*/,
  1601. size/*length*/,
  1602. True/*delete*/,
  1603. AnyPropertyType/*req_type*/,
  1604. &returnType/*actual_type_return*/,
  1605. &returnFormat/*actual_format_return*/,
  1606. &returnSize/*nitems_return*/,
  1607. &bytesLeft/*bytes_after_return*/,
  1608. &propertyValue/*prop_return*/);
  1609. if(returnSize == 0)
  1610. {
  1611. printf("xxx lglw_clipboard_text_get: No Clipboard result after final request\n");
  1612. return;
  1613. }
  1614. uint32_t i = 0u;
  1615. for(; i < _maxChars; i++)
  1616. {
  1617. _retText[i] = propertyValue[i];
  1618. if(0 == _retText[i])
  1619. break;
  1620. }
  1621. _retText[_maxChars - 1u] = 0;
  1622. if(NULL != _retNumChars)
  1623. *_retNumChars = i;
  1624. printf("xxx lglw_clipboard_text_get: (result on next line)\n%s\n", _retText);
  1625. XFree(propertyValue);
  1626. }
  1627. }
  1628. }
  1629. }