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.

2175 lines
71KB

  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. #define Dprintf_verbose if(1);else printf
  47. // #define Dprintf_verbose if(0);else printf
  48. #define Dlog_verbose if(1);else lglw_log
  49. // #define Dlog_verbose if(0);else lglw_log
  50. // ---------------------------------------------------------------------------- macros and defines
  51. #define LGLW(a) lglw_int_t *lglw = ((lglw_int_t*)(a))
  52. #define LGLW_DEFAULT_HIDDEN_W (800)
  53. #define LGLW_DEFAULT_HIDDEN_H (600)
  54. #define LGLW_MOUSE_TOUCH_LMB_TIMEOUT (250u)
  55. #define LGLW_MOUSE_TOUCH_RMB_TIMEOUT (500u)
  56. #define LGLW_MOUSE_TOUCH_RMB_STATE_IDLE (0u)
  57. #define LGLW_MOUSE_TOUCH_RMB_STATE_LMB (1u)
  58. #define LGLW_MOUSE_TOUCH_RMB_STATE_WAIT (2u)
  59. #define LGLW_MOUSE_TOUCH_RMB_STATE_RMB (3u)
  60. #define LGLW_MOUSE_TOUCH_RMB_MOVE_THRESHOLD (7u)
  61. #define sABS(x) (((x)>0)?(x):-(x))
  62. // ---------------------------------------------------------------------------- structs and typedefs
  63. typedef struct lglw_int_s {
  64. void *user_data; // arbitrary user data
  65. Display *xdsp;
  66. XVisualInfo *vi;
  67. Colormap cmap;
  68. Window parent_xwnd; // created by host
  69. struct {
  70. lglw_vec2i_t size;
  71. Window xwnd;
  72. } hidden;
  73. struct {
  74. lglw_vec2i_t size;
  75. Window xwnd;
  76. lglw_bool_t mapped;
  77. int32_t swap_interval;
  78. lglw_bool_t b_owner;
  79. } win;
  80. GLXContext ctx;
  81. struct {
  82. GLXContext ctx;
  83. GLXDrawable drw;
  84. } prev;
  85. struct {
  86. uint32_t kmod_state; // See LGLW_KMOD_xxx
  87. lglw_keyboard_fxn_t cbk;
  88. } keyboard;
  89. struct {
  90. lglw_vec2i_t p; // last seen mouse position
  91. uint32_t button_state;
  92. lglw_mouse_fxn_t cbk;
  93. struct {
  94. uint32_t mode;
  95. lglw_vec2i_t p; // grab-start mouse position
  96. lglw_bool_t b_queue_warp;
  97. lglw_vec2i_t last_p;
  98. } grab;
  99. struct {
  100. lglw_bool_t b_enable;
  101. lglw_bool_t b_update_queued;
  102. lglw_bool_t b_syn_rmb;
  103. uint32_t syn_rmb_hold_state; // see LGLW_MOUSE_TOUCH_RMB_STATE_xxx
  104. uint32_t hold_start_ms;
  105. lglw_vec2i_t hold_start_p;
  106. } touch;
  107. } mouse;
  108. struct {
  109. uint32_t state;
  110. lglw_focus_fxn_t cbk;
  111. } focus;
  112. struct {
  113. lglw_bool_t b_running;
  114. lglw_timer_fxn_t cbk;
  115. struct timeval tv_start;
  116. uint32_t interval_ms;
  117. uint32_t last_ms;
  118. } timer;
  119. struct {
  120. uint32_t numChars;
  121. char *data;
  122. } clipboard;
  123. struct {
  124. lglw_dropfiles_fxn_t cbk;
  125. } dropfiles;
  126. struct {
  127. lglw_redraw_fxn_t cbk;
  128. } redraw;
  129. } lglw_int_t;
  130. // ---------------------------------------------------------------------------- module fxn fwd decls
  131. static lglw_bool_t loc_create_hidden_window (lglw_int_t *lglw, int32_t _w, int32_t _h);
  132. static void loc_destroy_hidden_window(lglw_int_t *lglw);
  133. static lglw_bool_t loc_handle_key (lglw_int_t *lglw, lglw_bool_t _bPressed, uint32_t _vkey);
  134. // static lglw_bool_t loc_touchkeyboard_get_rect (RECT *rect);
  135. // static lglw_bool_t loc_touchkeyboard_is_visible (void);
  136. extern lglw_bool_t lglw_int_touchkeyboard_toggle (void);
  137. static void loc_handle_mouseleave (lglw_int_t *lglw);
  138. static void loc_handle_mouseenter (lglw_int_t *lglw);
  139. static void loc_handle_mousebutton (lglw_int_t *lglw, lglw_bool_t _bPressed, uint32_t _button);
  140. static void loc_handle_mousemotion (lglw_int_t *lglw);
  141. static void loc_handle_queued_mouse_warp (lglw_int_t *lglw);
  142. static void loc_enable_dropfiles (lglw_int_t *lglw, lglw_bool_t _bEnable);
  143. static void loc_eventProc (XEvent *xev, lglw_int_t *lglw);
  144. static void loc_XEventProc (void *_xevent);
  145. static void loc_setProperty (Display *_display, Window _window, const char *_name, void *_value);
  146. static void *loc_getProperty (Display *_display, Window _window, const char *_name);
  147. static void loc_setEventProc (Display *display, Window window);
  148. static void loc_millisec_init (lglw_int_t *lglw);
  149. static uint32_t loc_millisec_delta (lglw_int_t *lglw); // return millisec since init()
  150. static void loc_process_timer (lglw_int_t *lglw);
  151. // ---------------------------------------------------------------------------- lglw_millisec_init
  152. static void loc_millisec_init (lglw_int_t *lglw) {
  153. gettimeofday(&lglw->timer.tv_start, 0);
  154. }
  155. // ---------------------------------------------------------------------------- lglw_millisec_delta
  156. static uint32_t loc_millisec_delta (lglw_int_t *lglw) {
  157. struct timeval c; gettimeofday(&c, 0);
  158. const struct timeval*s = &lglw->timer.tv_start;
  159. return (uint32_t) ( (c.tv_sec-s->tv_sec)*1000 + (c.tv_usec-s->tv_usec)/1000 );
  160. }
  161. // TODO: remove and/or improve debug logging for a debug build
  162. // ---------------------------------------------------------------------------- lglw_log
  163. static FILE *logfile;
  164. void lglw_log(const char *logData, ...) {
  165. fprintf(logfile, logData);
  166. fflush(logfile);
  167. printf(logData);
  168. }
  169. // TODO: remove, or maybe not in some specific use cases
  170. // ---------------------------------------------------------------------------- xerror_log
  171. static int xerror_handler(Display *display, XErrorEvent *error) {
  172. char error_text[1024];
  173. XGetErrorText(display, error->error_code, error_text, 1024);
  174. lglw_log("XERROR (%d): %s, %d, %d\n", error->error_code, error_text, error->request_code, error->minor_code);
  175. return 0;
  176. }
  177. // ---------------------------------------------------------------------------- lglw_init
  178. lglw_t lglw_init(int32_t _w, int32_t _h) {
  179. lglw_int_t *lglw = malloc(sizeof(lglw_int_t));
  180. printf("xxx lglw_init: sizeof(uint32_t)=%lu sizeof(long)=%lu sizeof(void*)=%lu\n", sizeof(uint32_t), sizeof(long), sizeof(void*));
  181. // TODO: remove/improve
  182. logfile = fopen("/tmp/lglw_log.txt", "w");
  183. XSetErrorHandler(xerror_handler);
  184. XInitThreads(); // fix GL crash, see <https://forum.juce.com/t/linux-vst-opengl-crash-because-xinitthreads-not-called/22821>
  185. loc_millisec_init(lglw);
  186. if(NULL != lglw)
  187. {
  188. memset(lglw, 0, sizeof(lglw_int_t));
  189. lglw_log("lglw:lglw_init: 1\n");
  190. if(_w <= 16)
  191. _w = LGLW_DEFAULT_HIDDEN_W;
  192. if(_h <= 16)
  193. _h = LGLW_DEFAULT_HIDDEN_H;
  194. lglw_log("lglw:lglw_init: 2\n");
  195. if(!loc_create_hidden_window(lglw, _w, _h))
  196. {
  197. free(lglw);
  198. lglw = NULL;
  199. }
  200. lglw_log("lglw:lglw_init: 3\n");
  201. }
  202. lglw_log("lglw:lglw_init: EXIT\n");
  203. return lglw;
  204. }
  205. // ---------------------------------------------------------------------------- lglw_exit
  206. void lglw_exit(lglw_t _lglw) {
  207. LGLW(_lglw);
  208. if(NULL != lglw)
  209. {
  210. lglw_log("lglw:lglw_exit: 1\n");
  211. loc_destroy_hidden_window(lglw);
  212. lglw_log("lglw:lglw_exit: 2\n");
  213. fclose(logfile);
  214. free(lglw);
  215. }
  216. }
  217. // ---------------------------------------------------------------------------- lglw_userdata_set
  218. void lglw_userdata_set(lglw_t _lglw, void *_userData) {
  219. LGLW(_lglw);
  220. if(NULL != lglw)
  221. {
  222. // lglw_log("lglw:lglw_userdata_set: 1\n");
  223. lglw->user_data = _userData;
  224. }
  225. }
  226. // ---------------------------------------------------------------------------- lglw_userdata_get
  227. void *lglw_userdata_get(lglw_t _lglw) {
  228. LGLW(_lglw);
  229. if(NULL != lglw)
  230. {
  231. // lglw_log("lglw:lglw_userdata_get: 1\n");
  232. return lglw->user_data;
  233. }
  234. return NULL;
  235. }
  236. // ---------------------------------------------------------------------------- loc_create_hidden_window
  237. static lglw_bool_t loc_create_hidden_window(lglw_int_t *lglw, int32_t _w, int32_t _h) {
  238. // TODO: compare to 'WindowClass' from Windows implementation
  239. lglw_log("lglw:loc_create_hidden_window: 1\n");
  240. XSetWindowAttributes swa;
  241. int attrib[] = { GLX_RGBA, GLX_DOUBLEBUFFER, GLX_DEPTH_SIZE, 24, None };
  242. int screen;
  243. lglw_log("lglw:loc_create_hidden_window: 2\n");
  244. lglw->xdsp = XOpenDisplay(NULL);
  245. screen = DefaultScreen(lglw->xdsp);
  246. lglw_log("lglw:loc_create_hidden_window: 3\n");
  247. lglw->vi = glXChooseVisual(lglw->xdsp, screen, attrib);
  248. lglw_log("lglw:loc_create_hidden_window: 4\n");
  249. if(NULL == lglw->vi)
  250. {
  251. lglw_log("[---] lglw: failed to find GLX Visual for hidden window\n");
  252. return LGLW_FALSE;
  253. }
  254. lglw_log("lglw:loc_create_hidden_window: 5\n");
  255. lglw->ctx = glXCreateContext(lglw->xdsp, lglw->vi, None, True);
  256. lglw_log("lglw:loc_create_hidden_window: 6\n");
  257. if(NULL == lglw->ctx)
  258. {
  259. lglw_log("[---] lglw: failed to create GLX Context for hidden window\n");
  260. return LGLW_FALSE;
  261. }
  262. lglw_log("lglw:loc_create_hidden_window: 7\n");
  263. lglw->cmap = XCreateColormap(lglw->xdsp, RootWindow(lglw->xdsp, lglw->vi->screen),
  264. lglw->vi->visual, AllocNone);
  265. lglw_log("lglw:loc_create_hidden_window: 8\n");
  266. swa.border_pixel = 0;
  267. swa.colormap = lglw->cmap;
  268. lglw->hidden.xwnd = XCreateWindow(lglw->xdsp, DefaultRootWindow(lglw->xdsp),
  269. 0, 0, LGLW_DEFAULT_HIDDEN_W, LGLW_DEFAULT_HIDDEN_H, 0, CopyFromParent, InputOutput,
  270. lglw->vi->visual, CWBorderPixel | CWColormap, &swa);
  271. lglw_log("lglw:loc_create_hidden_window: 9\n");
  272. XSetStandardProperties(lglw->xdsp, lglw->hidden.xwnd, "LGLW_hidden", "LGLW_hidden", None, NULL, 0, NULL);
  273. XSync(lglw->xdsp, False);
  274. lglw_log("lglw:loc_create_hidden_window: EXIT\n");
  275. lglw->hidden.size.x = _w;
  276. lglw->hidden.size.y = _h;
  277. return LGLW_TRUE;
  278. }
  279. // ---------------------------------------------------------------------------- loc_destroy_hidden_window
  280. static void loc_destroy_hidden_window(lglw_int_t *lglw) {
  281. lglw_log("lglw:loc_destroy_hidden_window: 1\n");
  282. if(NULL != lglw->xdsp && NULL != lglw->ctx)
  283. {
  284. glXMakeCurrent(lglw->xdsp, None, NULL);
  285. glXDestroyContext(lglw->xdsp, lglw->ctx);
  286. }
  287. lglw_log("lglw:loc_destroy_hidden_window: 2\n");
  288. if(NULL != lglw->xdsp && 0 != lglw->hidden.xwnd) XDestroyWindow(lglw->xdsp, lglw->hidden.xwnd);
  289. lglw_log("lglw:loc_destroy_hidden_window: 3\n");
  290. if(NULL != lglw->xdsp && 0 != lglw->cmap) XFreeColormap(lglw->xdsp, lglw->cmap);
  291. lglw_log("lglw:loc_destroy_hidden_window: 4\n");
  292. if(NULL != lglw->vi) XFree(lglw->vi);
  293. lglw_log("lglw:loc_destroy_hidden_window: 5\n");
  294. XSync(lglw->xdsp, False);
  295. if(NULL != lglw->xdsp) XCloseDisplay(lglw->xdsp);
  296. }
  297. // ---------------------------------------------------------------------------- loc_setEventProc
  298. // https://www.kvraudio.com/forum/viewtopic.php?t=387924
  299. // https://github.com/Ardour/ardour/blob/master/gtk2_ardour/linux_vst_gui_support.cc
  300. // https://discourse.ardour.org/t/overtonedsp-plugins/90115/22
  301. // https://github.com/amsynth/amsynth/blob/4a87798e650c6d71d70274a961c9b8d98fc6da7e/src/amsynth_vst.cpp
  302. // https://github.com/rsenn/eXT2/blob/7f00a09561ded8175ffed2f4912dad74e466a1c7/vstplugins/vstgui/vstgui.cpp
  303. // https://github.com/COx2/DistortionFilter/blob/c6a34fb56b503a6e95bf0975e00f438bbf4ff52a/juce/modules/juce_audio_processors/format_types/juce_VSTPluginFormat.cpp
  304. // Very simple function to test _XEventProc is properly called
  305. static void loc_eventProc(XEvent *xev, lglw_int_t *lglw) {
  306. Dlog_verbose("vstgltest<lglw_linux>: eventProc: type=%d serial=%lu send_event=%d lglw=%p\n", xev->xany.type, xev->xany.serial, xev->xany.send_event, lglw);
  307. loc_process_timer(lglw);
  308. if(NULL != lglw)
  309. {
  310. lglw_bool_t eventHandled = LGLW_FALSE;
  311. switch(xev->type)
  312. {
  313. default:
  314. printf("vstgltest<lglw_linux>: unhandled X11 event type=%d\n", xev->type);
  315. eventHandled = LGLW_FALSE;
  316. break;
  317. case Expose:
  318. Dlog_verbose("vstgltest<lglw_linux>: xev Expose\n");
  319. loc_handle_queued_mouse_warp(lglw);
  320. eventHandled = LGLW_FALSE;
  321. if(NULL != lglw->redraw.cbk)
  322. {
  323. lglw->redraw.cbk(lglw);
  324. eventHandled = LGLW_TRUE;
  325. }
  326. break;
  327. // TODO: Should FocusIn/Out be treated like WM_CAPTURECHANGED and reset the grab state?
  328. case FocusIn:
  329. Dlog_verbose("vstgltest<lglw_linux>: xev FocusIn\n");
  330. eventHandled = LGLW_FALSE;
  331. break;
  332. case FocusOut:
  333. Dlog_verbose("vstgltest<lglw_linux>: xev FocusOut\n");
  334. eventHandled = LGLW_FALSE;
  335. break;
  336. case EnterNotify:
  337. // printf("vstgltest<lglw_linux>: xev XEnterWindowEvent\n");
  338. ; // empty statement
  339. XEnterWindowEvent *wenter = (XEnterWindowEvent*)xev;
  340. printf("vstgltest<lglw_linux>: xev EnterNotify: mode:%i, detail:%i, state:%d\n", wenter->mode, wenter->detail, wenter->state);
  341. lglw->mouse.p.x = wenter->x;
  342. lglw->mouse.p.y = wenter->y;
  343. loc_handle_mousemotion(lglw);
  344. // EnterNotify messages can be pseudo-motion events (NotifyGrab, NotifyUngrab)
  345. // when buttons are pressed, which would trigger false focus changes
  346. // so, the callback is only sent when a normal entry happens
  347. if (wenter->mode == NotifyNormal)
  348. {
  349. loc_handle_mouseenter(lglw);
  350. }
  351. eventHandled = LGLW_TRUE;
  352. break;
  353. case LeaveNotify:
  354. // printf("vstgltest<lglw_linux>: xev XLeaveWindowEvent\n");
  355. ; // empty statement
  356. XLeaveWindowEvent *wexit = (XLeaveWindowEvent*)xev;
  357. printf("vstgltest<lglw_linux>: xev LeaveNotify: mode:%i, detail:%i, state:%d\n", wexit->mode, wexit->detail, wexit->state);
  358. // LeaveNotify messages can be pseudo-motion events (NotifyGrab, NotifyUngrab)
  359. // when buttons are pressed, which would trigger false focus changes
  360. // so, the callback is only sent when a normal entry happens
  361. if (wexit->mode == NotifyNormal)
  362. {
  363. loc_handle_mouseleave(lglw);
  364. }
  365. eventHandled = LGLW_TRUE;
  366. break;
  367. case MotionNotify:
  368. // printf("vstgltest<lglw_linux>: xev MotionNotify\n");
  369. ; // empty statement
  370. XMotionEvent *motion = (XMotionEvent*)xev;
  371. if(LGLW_MOUSE_GRAB_WARP == lglw->mouse.grab.mode)
  372. {
  373. lglw->mouse.grab.b_queue_warp = LGLW_TRUE;
  374. lglw->mouse.p.x += (motion->x - lglw->mouse.grab.last_p.x);
  375. lglw->mouse.p.y += (motion->y - lglw->mouse.grab.last_p.y);
  376. lglw->mouse.grab.last_p.x = motion->x;
  377. lglw->mouse.grab.last_p.y = motion->y;
  378. }
  379. else
  380. {
  381. lglw->mouse.p.x = motion->x;
  382. lglw->mouse.p.y = motion->y;
  383. }
  384. loc_handle_mousemotion(lglw);
  385. eventHandled = LGLW_TRUE;
  386. break;
  387. case KeyPress:
  388. printf("vstgltest<lglw_linux>: xev KeyPress\n");
  389. XKeyPressedEvent *keyPress = (XKeyPressedEvent*)xev;
  390. eventHandled = LGLW_FALSE;
  391. KeySym xkp = XLookupKeysym(keyPress, 0);
  392. switch(xkp)
  393. {
  394. default:
  395. printf("vstgltest<lglw_linux>: xev KeyPress: %x or %lu\n", keyPress->keycode, xkp);
  396. if(0u != (lglw->keyboard.kmod_state & LGLW_KMOD_SHIFT))
  397. {
  398. KeySym xkpl;
  399. KeySym xkpu;
  400. XConvertCase(xkp, &xkpl, &xkpu);
  401. eventHandled = loc_handle_key(lglw, LGLW_TRUE/*bPressed*/, xkpu);
  402. }
  403. else
  404. {
  405. eventHandled = loc_handle_key(lglw, LGLW_TRUE/*bPressed*/, xkp);
  406. }
  407. break;
  408. case NoSymbol:
  409. printf("vstgltest<lglw_linux>: xev UNKNOWN KeyPress: %x\n", keyPress->keycode);
  410. break;
  411. case XK_Left:
  412. eventHandled = loc_handle_key(lglw, LGLW_TRUE/*bPressed*/, LGLW_VKEY_LEFT);
  413. break;
  414. case XK_Right:
  415. eventHandled = loc_handle_key(lglw, LGLW_TRUE/*bPressed*/, LGLW_VKEY_RIGHT);
  416. break;
  417. case XK_Up:
  418. eventHandled = loc_handle_key(lglw, LGLW_TRUE/*bPressed*/, LGLW_VKEY_UP);
  419. break;
  420. case XK_Down:
  421. eventHandled = loc_handle_key(lglw, LGLW_TRUE/*bPressed*/, LGLW_VKEY_DOWN);
  422. break;
  423. case XK_Insert:
  424. eventHandled = loc_handle_key(lglw, LGLW_TRUE/*bPressed*/, LGLW_VKEY_INSERT);
  425. break;
  426. case XK_Delete:
  427. eventHandled = loc_handle_key(lglw, LGLW_TRUE/*bPressed*/, LGLW_VKEY_DELETE);
  428. break;
  429. case XK_Home:
  430. eventHandled = loc_handle_key(lglw, LGLW_TRUE/*bPressed*/, LGLW_VKEY_HOME);
  431. break;
  432. case XK_End:
  433. eventHandled = loc_handle_key(lglw, LGLW_TRUE/*bPressed*/, LGLW_VKEY_END);
  434. break;
  435. case XK_F1:
  436. eventHandled = loc_handle_key(lglw, LGLW_TRUE/*bPressed*/, LGLW_VKEY_F1);
  437. break;
  438. case XK_F2:
  439. eventHandled = loc_handle_key(lglw, LGLW_TRUE/*bPressed*/, LGLW_VKEY_F2);
  440. break;
  441. case XK_F3:
  442. eventHandled = loc_handle_key(lglw, LGLW_TRUE/*bPressed*/, LGLW_VKEY_F3);
  443. break;
  444. case XK_F4:
  445. eventHandled = loc_handle_key(lglw, LGLW_TRUE/*bPressed*/, LGLW_VKEY_F4);
  446. break;
  447. case XK_F5:
  448. eventHandled = loc_handle_key(lglw, LGLW_TRUE/*bPressed*/, LGLW_VKEY_F5);
  449. break;
  450. case XK_F6:
  451. eventHandled = loc_handle_key(lglw, LGLW_TRUE/*bPressed*/, LGLW_VKEY_F6);
  452. break;
  453. case XK_F7:
  454. eventHandled = loc_handle_key(lglw, LGLW_TRUE/*bPressed*/, LGLW_VKEY_F7);
  455. break;
  456. case XK_F8:
  457. eventHandled = loc_handle_key(lglw, LGLW_TRUE/*bPressed*/, LGLW_VKEY_F8);
  458. break;
  459. case XK_F9:
  460. eventHandled = loc_handle_key(lglw, LGLW_TRUE/*bPressed*/, LGLW_VKEY_F9);
  461. break;
  462. case XK_F10:
  463. eventHandled = loc_handle_key(lglw, LGLW_TRUE/*bPressed*/, LGLW_VKEY_F10);
  464. break;
  465. case XK_F11:
  466. eventHandled = loc_handle_key(lglw, LGLW_TRUE/*bPressed*/, LGLW_VKEY_F11);
  467. break;
  468. case XK_F12:
  469. eventHandled = loc_handle_key(lglw, LGLW_TRUE/*bPressed*/, LGLW_VKEY_F12);
  470. break;
  471. case XK_BackSpace:
  472. eventHandled = loc_handle_key(lglw, LGLW_TRUE/*bPressed*/, LGLW_VKEY_BACKSPACE);
  473. break;
  474. case XK_Tab:
  475. eventHandled = loc_handle_key(lglw, LGLW_TRUE/*bPressed*/, LGLW_VKEY_TAB);
  476. break;
  477. case XK_Return:
  478. eventHandled = loc_handle_key(lglw, LGLW_TRUE/*bPressed*/, LGLW_VKEY_RETURN);
  479. break;
  480. case XK_Escape:
  481. eventHandled = loc_handle_key(lglw, LGLW_TRUE/*bPressed*/, LGLW_VKEY_ESCAPE);
  482. break;
  483. case XK_Shift_L:
  484. lglw->keyboard.kmod_state |= LGLW_KMOD_LSHIFT;
  485. eventHandled = loc_handle_key(lglw, LGLW_TRUE/*bPressed*/, LGLW_VKEY_LSHIFT);
  486. eventHandled = LGLW_FALSE;
  487. break;
  488. case XK_Shift_R:
  489. lglw->keyboard.kmod_state |= LGLW_KMOD_RSHIFT;
  490. eventHandled = loc_handle_key(lglw, LGLW_TRUE/*bPressed*/, LGLW_VKEY_RSHIFT);
  491. eventHandled = LGLW_FALSE;
  492. break;
  493. case XK_Control_L:
  494. lglw->keyboard.kmod_state |= LGLW_KMOD_LCTRL;
  495. eventHandled = loc_handle_key(lglw, LGLW_TRUE/*bPressed*/, LGLW_KMOD_LCTRL);
  496. eventHandled = LGLW_FALSE;
  497. break;
  498. case XK_Control_R:
  499. lglw->keyboard.kmod_state |= LGLW_KMOD_RCTRL;
  500. eventHandled = loc_handle_key(lglw, LGLW_TRUE/*bPressed*/, LGLW_KMOD_RCTRL);
  501. eventHandled = LGLW_FALSE;
  502. break;
  503. }
  504. break;
  505. case KeyRelease:
  506. printf("vstgltest<lglw_linux>: xev KeyRelease\n");
  507. XKeyReleasedEvent *keyRelease = (XKeyReleasedEvent*)xev;
  508. eventHandled = LGLW_FALSE;
  509. KeySym xkr = XLookupKeysym(keyRelease, 0);
  510. switch(xkr)
  511. {
  512. default:
  513. printf("vstgltest<lglw_linux>: xev KeyRelease: %x or %lu\n", keyRelease->keycode, xkr);
  514. if(0u != (lglw->keyboard.kmod_state & LGLW_KMOD_SHIFT))
  515. {
  516. KeySym xkrl;
  517. KeySym xkru;
  518. XConvertCase(xkr, &xkrl, &xkru);
  519. eventHandled = loc_handle_key(lglw, LGLW_FALSE/*bPressed*/, xkru);
  520. }
  521. else
  522. {
  523. eventHandled = loc_handle_key(lglw, LGLW_FALSE/*bPressed*/, xkr);
  524. }
  525. break;
  526. case NoSymbol:
  527. printf("vstgltest<lglw_linux>: xev UNKNOWN KeyRelease: %x\n", keyRelease->keycode);
  528. break;
  529. case XK_Left:
  530. eventHandled = loc_handle_key(lglw, LGLW_FALSE/*bPressed*/, LGLW_VKEY_LEFT);
  531. break;
  532. case XK_Right:
  533. eventHandled = loc_handle_key(lglw, LGLW_FALSE/*bPressed*/, LGLW_VKEY_RIGHT);
  534. break;
  535. case XK_Up:
  536. eventHandled = loc_handle_key(lglw, LGLW_FALSE/*bPressed*/, LGLW_VKEY_UP);
  537. break;
  538. case XK_Down:
  539. eventHandled = loc_handle_key(lglw, LGLW_FALSE/*bPressed*/, LGLW_VKEY_DOWN);
  540. break;
  541. case XK_Insert:
  542. eventHandled = loc_handle_key(lglw, LGLW_FALSE/*bPressed*/, LGLW_VKEY_INSERT);
  543. break;
  544. case XK_Delete:
  545. eventHandled = loc_handle_key(lglw, LGLW_FALSE/*bPressed*/, LGLW_VKEY_DELETE);
  546. break;
  547. case XK_Home:
  548. eventHandled = loc_handle_key(lglw, LGLW_FALSE/*bPressed*/, LGLW_VKEY_HOME);
  549. break;
  550. case XK_End:
  551. eventHandled = loc_handle_key(lglw, LGLW_FALSE/*bPressed*/, LGLW_VKEY_END);
  552. break;
  553. case XK_F1:
  554. eventHandled = loc_handle_key(lglw, LGLW_FALSE/*bPressed*/, LGLW_VKEY_F1);
  555. break;
  556. case XK_F2:
  557. eventHandled = loc_handle_key(lglw, LGLW_FALSE/*bPressed*/, LGLW_VKEY_F2);
  558. break;
  559. case XK_F3:
  560. eventHandled = loc_handle_key(lglw, LGLW_FALSE/*bPressed*/, LGLW_VKEY_F3);
  561. break;
  562. case XK_F4:
  563. eventHandled = loc_handle_key(lglw, LGLW_FALSE/*bPressed*/, LGLW_VKEY_F4);
  564. break;
  565. case XK_F5:
  566. eventHandled = loc_handle_key(lglw, LGLW_FALSE/*bPressed*/, LGLW_VKEY_F5);
  567. break;
  568. case XK_F6:
  569. eventHandled = loc_handle_key(lglw, LGLW_FALSE/*bPressed*/, LGLW_VKEY_F6);
  570. break;
  571. case XK_F7:
  572. eventHandled = loc_handle_key(lglw, LGLW_FALSE/*bPressed*/, LGLW_VKEY_F7);
  573. break;
  574. case XK_F8:
  575. eventHandled = loc_handle_key(lglw, LGLW_FALSE/*bPressed*/, LGLW_VKEY_F8);
  576. break;
  577. case XK_F9:
  578. eventHandled = loc_handle_key(lglw, LGLW_FALSE/*bPressed*/, LGLW_VKEY_F9);
  579. break;
  580. case XK_F10:
  581. eventHandled = loc_handle_key(lglw, LGLW_FALSE/*bPressed*/, LGLW_VKEY_F10);
  582. break;
  583. case XK_F11:
  584. eventHandled = loc_handle_key(lglw, LGLW_FALSE/*bPressed*/, LGLW_VKEY_F11);
  585. break;
  586. case XK_F12:
  587. eventHandled = loc_handle_key(lglw, LGLW_FALSE/*bPressed*/, LGLW_VKEY_F12);
  588. break;
  589. case XK_BackSpace:
  590. eventHandled = loc_handle_key(lglw, LGLW_FALSE/*bPressed*/, LGLW_VKEY_BACKSPACE);
  591. break;
  592. case XK_Tab:
  593. eventHandled = loc_handle_key(lglw, LGLW_FALSE/*bPressed*/, LGLW_VKEY_TAB);
  594. break;
  595. case XK_Return:
  596. eventHandled = loc_handle_key(lglw, LGLW_FALSE/*bPressed*/, LGLW_VKEY_RETURN);
  597. break;
  598. case XK_Escape:
  599. eventHandled = loc_handle_key(lglw, LGLW_FALSE/*bPressed*/, LGLW_VKEY_ESCAPE);
  600. break;
  601. case XK_Shift_L:
  602. lglw->keyboard.kmod_state &= ~LGLW_KMOD_LSHIFT;
  603. eventHandled = loc_handle_key(lglw, LGLW_FALSE/*bPressed*/, LGLW_VKEY_LSHIFT);
  604. eventHandled = LGLW_FALSE;
  605. break;
  606. case XK_Shift_R:
  607. lglw->keyboard.kmod_state &= ~LGLW_KMOD_RSHIFT;
  608. eventHandled = loc_handle_key(lglw, LGLW_FALSE/*bPressed*/, LGLW_VKEY_RSHIFT);
  609. eventHandled = LGLW_FALSE;
  610. break;
  611. case XK_Control_L:
  612. lglw->keyboard.kmod_state &= ~LGLW_KMOD_LCTRL;
  613. eventHandled = loc_handle_key(lglw, LGLW_FALSE/*bPressed*/, LGLW_VKEY_LCTRL);
  614. eventHandled = LGLW_FALSE;
  615. break;
  616. case XK_Control_R:
  617. lglw->keyboard.kmod_state &= ~LGLW_KMOD_RCTRL;
  618. eventHandled = loc_handle_key(lglw, LGLW_FALSE/*bPressed*/, LGLW_VKEY_RCTRL);
  619. eventHandled = LGLW_FALSE;
  620. break;
  621. }
  622. break;
  623. case ButtonPress:
  624. printf("vstgltest<lglw_linux>: xev ButtonPress\n");
  625. XButtonPressedEvent *btnPress = (XButtonPressedEvent*)xev;
  626. lglw->mouse.p.x = btnPress->x;
  627. lglw->mouse.p.y = btnPress->y;
  628. if(0u == (lglw->focus.state & LGLW_FOCUS_MOUSE))
  629. {
  630. loc_handle_mouseenter(lglw);
  631. }
  632. switch(btnPress->button)
  633. {
  634. default:
  635. printf("vstgltest<lglw_linux>: xev ButtonPress unhandled button: %i\n", btnPress->button);
  636. eventHandled = LGLW_FALSE;
  637. break;
  638. case Button1:
  639. loc_handle_mousebutton(lglw, LGLW_TRUE/*bPressed*/, LGLW_MOUSE_LBUTTON);
  640. eventHandled = LGLW_TRUE;
  641. break;
  642. case Button2:
  643. loc_handle_mousebutton(lglw, LGLW_TRUE/*bPressed*/, LGLW_MOUSE_MBUTTON);
  644. eventHandled = LGLW_TRUE;
  645. break;
  646. case Button3:
  647. loc_handle_mousebutton(lglw, LGLW_TRUE/*bPressed*/, LGLW_MOUSE_RBUTTON);
  648. eventHandled = LGLW_TRUE;
  649. break;
  650. case Button4:
  651. loc_handle_mousebutton(lglw, LGLW_TRUE/*bPressed*/, LGLW_MOUSE_WHEELUP);
  652. eventHandled = LGLW_TRUE;
  653. break;
  654. case Button5:
  655. loc_handle_mousebutton(lglw, LGLW_TRUE/*bPressed*/, LGLW_MOUSE_WHEELDOWN);
  656. eventHandled = LGLW_TRUE;
  657. break;
  658. }
  659. break;
  660. case ButtonRelease:
  661. printf("vstgltest<lglw_linux>: xev ButtonRelease\n");
  662. XButtonReleasedEvent *btnRelease = (XButtonReleasedEvent*)xev;
  663. lglw->mouse.p.x = btnRelease->x;
  664. lglw->mouse.p.y = btnRelease->y;
  665. switch(btnRelease->button)
  666. {
  667. default:
  668. printf("vstgltest<lglw_linux>: xev ButtonRelease unhandled button: %i\n", btnRelease->button);
  669. eventHandled = LGLW_FALSE;
  670. break;
  671. case Button1:
  672. loc_handle_mousebutton(lglw, LGLW_FALSE/*bPressed*/, LGLW_MOUSE_LBUTTON);
  673. eventHandled = LGLW_TRUE;
  674. break;
  675. case Button2:
  676. loc_handle_mousebutton(lglw, LGLW_FALSE/*bPressed*/, LGLW_MOUSE_MBUTTON);
  677. eventHandled = LGLW_TRUE;
  678. break;
  679. case Button3:
  680. loc_handle_mousebutton(lglw, LGLW_FALSE/*bPressed*/, LGLW_MOUSE_RBUTTON);
  681. eventHandled = LGLW_TRUE;
  682. break;
  683. case Button4:
  684. loc_handle_mousebutton(lglw, LGLW_FALSE/*bPressed*/, LGLW_MOUSE_WHEELUP);
  685. eventHandled = LGLW_TRUE;
  686. break;
  687. case Button5:
  688. loc_handle_mousebutton(lglw, LGLW_FALSE/*bPressed*/, LGLW_MOUSE_WHEELDOWN);
  689. eventHandled = LGLW_TRUE;
  690. break;
  691. }
  692. break;
  693. case SelectionClear:
  694. printf("vstgltest<lglw_linux>: xev SelectionClear\n");
  695. lglw->clipboard.numChars = 0;
  696. free(lglw->clipboard.data);
  697. eventHandled = LGLW_TRUE;
  698. break;
  699. case SelectionRequest:
  700. printf("vstgltest<lglw_linux>: xev SelectionRequest\n");
  701. XSelectionRequestEvent *cbReq = (XSelectionRequestEvent*)xev;
  702. XSelectionEvent cbRes;
  703. Atom utf8 = XInternAtom(lglw->xdsp, "UTF8_STRING", False);
  704. cbRes.type = SelectionNotify;
  705. cbRes.requestor = cbReq->requestor;
  706. cbRes.selection = cbReq->selection;
  707. cbRes.target = cbReq->target;
  708. cbRes.time = cbReq->time;
  709. if(cbReq->target == utf8)
  710. {
  711. XChangeProperty(lglw->xdsp, cbReq->requestor, cbReq->property, utf8, 8/*format*/, PropModeReplace,
  712. (unsigned char *)lglw->clipboard.data, lglw->clipboard.numChars);
  713. cbRes.property = cbReq->property;
  714. }
  715. else
  716. {
  717. cbRes.property = None;
  718. }
  719. XSendEvent(lglw->xdsp, cbReq->requestor, True, NoEventMask, (XEvent *)&cbRes);
  720. eventHandled = LGLW_TRUE;
  721. break;
  722. }
  723. #if 0
  724. // (note) this causes a feedback loop in the VST2 debug host
  725. if(LGLW_FALSE == eventHandled)
  726. {
  727. if(0 == lglw->parent_xwnd)
  728. {
  729. printf("lglw_linux:loc_eventProc: no parent window to send events to");
  730. XSendEvent(lglw->xdsp, InputFocus, True/*propgate*/, NoEventMask, xev);
  731. }
  732. else
  733. {
  734. XSendEvent(lglw->xdsp, lglw->parent_xwnd, True/*propgate*/, NoEventMask, xev);
  735. }
  736. }
  737. #else
  738. (void)eventHandled;
  739. #endif
  740. }
  741. }
  742. static void loc_XEventProc(void *_xevent) {
  743. XEvent *xev = (XEvent*)_xevent;
  744. Dlog_verbose("XEventProc\n");
  745. // printf("vstgltest<lglw_linux>: XEventProc, xev=%p\n", xev);
  746. if(NULL != xev)
  747. {
  748. LGLW(loc_getProperty(xev->xany.display, xev->xany.window, "_lglw")); // get instance pointer
  749. Dlog_verbose("lglw_linux:loc_XEventProc: xev=%p lglw=%p\n", xev, lglw);
  750. loc_eventProc(xev, lglw);
  751. }
  752. }
  753. static void loc_setProperty(Display *_display, Window _window, const char *_name, void *_value) {
  754. size_t data = (size_t)_value;
  755. long temp[2];
  756. // Split the 64 bit pointer into a little-endian long array
  757. temp[0] = (long)(data & 0xffffffffUL);
  758. temp[1] = (long)(data >> 32L);
  759. printf("xxx lglw_linux:loc_setProperty: name=\"%s\" value=%p temp[0]=%08x temp[1]=%08x\n", _name, _value, (uint32_t)temp[0], (uint32_t)temp[1]);
  760. Atom atom = XInternAtom(_display, _name, False/*only_if_exists*/);
  761. // (note) what's quite weird here is that we're writing an array of 32bit values, yet the element format must be 64bit (long)
  762. XChangeProperty(_display, _window,
  763. atom/*property*/,
  764. atom/*type*/,
  765. 32/*format*/,
  766. PropModeReplace/*mode*/,
  767. (unsigned char*)temp/*data*/,
  768. 2/*nelements*/
  769. );
  770. }
  771. static void *loc_getProperty(Display *_display, Window _window, const char *_name) {
  772. int userSize;
  773. unsigned long bytes;
  774. unsigned long userCount;
  775. unsigned char *data;
  776. Atom userType;
  777. Atom atom = XInternAtom(_display, _name, False);
  778. // (note) 64bit properties need to be read with two XGetWindowProperty() calls.
  779. // When using just one call and setting the 'length' to 2, the upper 32bit (second array element) will be 0xFFFFffff.
  780. XGetWindowProperty(_display,
  781. _window,
  782. atom,
  783. 0/*offset*/,
  784. 1/*length*/,
  785. False/*delete*/,
  786. AnyPropertyType,
  787. &userType/*actual_type_return*/,
  788. &userSize/*actual_format_return*/,
  789. &userCount/*nitems_return*/,
  790. &bytes/*bytes_after_return / partial reads*/,
  791. &data);
  792. union {
  793. uint32_t ui[2];
  794. void *any;
  795. } uptr;
  796. uptr.any = 0;
  797. // printf("xxx lglw_linux: loc_getProperty: LOWER userSize=%d userCount=%lu bytes=%lu data=%p\n", userSize, userCount, bytes, data);
  798. if(NULL != data)
  799. {
  800. if(userCount >= 1)
  801. {
  802. // if(userCount >= 2)
  803. // {
  804. // printf("xxx loc_getProperty: lo=0x%08x hi=0x%08x\n", ((uint32_t*)data)[0], ((uint32_t*)data)[1]);
  805. // }
  806. // lower 32-bit
  807. uptr.ui[0] = *(long*)data;
  808. uptr.ui[1] = 0;
  809. // printf("xxx lower=0x%08x\n", uptr.ui[0]);
  810. // // printf("xxx upper=0x%08x\n", uptr.ui[1]);
  811. XFree(data);
  812. // // if(userCount >= 2)
  813. {
  814. XGetWindowProperty(_display,
  815. _window,
  816. atom,
  817. 1/*offset*/,
  818. 1/*length*/,
  819. False/*delete*/,
  820. AnyPropertyType,
  821. &userType/*actual_type_return*/,
  822. &userSize/*actual_format_return*/,
  823. &userCount/*nitems_return*/,
  824. &bytes/*bytes_after_return / partial reads*/,
  825. &data);
  826. // printf("xxx lglw_linux: loc_getProperty: UPPER userSize=%d userCount=%lu bytes=%lu data=%p\n", userSize, userCount, bytes, data);
  827. if(NULL != data)
  828. {
  829. // upper 32-bit
  830. uptr.ui[1] = *(long*)data;
  831. // printf("xxx upper=0x%08x\n", uptr.ui[1]);
  832. XFree(data);
  833. }
  834. }
  835. }
  836. }
  837. // printf("xxx lglw_linux: loc_getProperty: return value=%p\n", uptr.any);
  838. return uptr.any;
  839. }
  840. #ifdef ARCH_X64
  841. #if 0
  842. // Pulled from the Renoise 64-bit callback example
  843. // Unsure what data was supposed to be, but swapping it to a function name did not work
  844. // This does nothing, no event proc found
  845. static void loc_setEventProc (Display *display, Window window) {
  846. size_t data = (size_t)loc_eventProc;
  847. long temp[2];
  848. printf("vstgltest<lglw_linux>: setEventProc (2*32bit). window=%lu loc_eventProc=%p\n", window, &loc_eventProc);
  849. // Split the 64 bit pointer into a little-endian unsigned int array
  850. temp[0] = (uint32_t)(data & 0xffffffffUL);
  851. temp[1] = (uint32_t)(data >> 32L);
  852. Atom atom = XInternAtom(display, "_XEventProc", False);
  853. XChangeProperty(display, window,
  854. atom/*property*/,
  855. atom/*type*/,
  856. 32/*format*/,
  857. PropModeReplace/*mode*/,
  858. (unsigned char*)temp/*data*/,
  859. 2/*nelements*/
  860. );
  861. }
  862. #else
  863. // GPL code pulled from the amsynth example <https://github.com/amsynth/amsynth/blob/4a87798e650c6d71d70274a961c9b8d98fc6da7e/src/amsynth_vst.cpp>
  864. // Simply swapped out the function names, crashes Ardour in the same was as the others
  865. static void loc_setEventProc (Display *display, Window window) {
  866. //
  867. // JUCE calls XGetWindowProperty with long_length = 1 which means it only fetches the lower 32 bits of the address.
  868. // Therefore we need to ensure we return an address in the lower 32-bits of address space.
  869. //
  870. // based on mach_override
  871. static const unsigned char kJumpInstructions[] = {
  872. 0xFF, 0x25, 0x00, 0x00, 0x00, 0x00,
  873. 0x00, 0x00, 0x00, 0x00,
  874. 0x00, 0x00, 0x00, 0x00
  875. };
  876. static const int kJumpAddress = 6;
  877. static char *ptr = 0;
  878. if (!ptr) {
  879. ptr = (char *)mmap(0,
  880. getpagesize()/*PAGE_SIZE*/,
  881. PROT_READ | PROT_WRITE | PROT_EXEC,
  882. MAP_ANONYMOUS | MAP_PRIVATE | MAP_32BIT,
  883. 0, 0);
  884. if (ptr == MAP_FAILED) {
  885. perror("mmap");
  886. ptr = 0;
  887. return;
  888. } else {
  889. memcpy(ptr, kJumpInstructions, sizeof(kJumpInstructions));
  890. *((uint64_t *)(ptr + kJumpAddress)) = (uint64_t)(&loc_XEventProc);
  891. msync(ptr, sizeof(kJumpInstructions), MS_INVALIDATE);
  892. printf("vstgltest<lglw_linux>: 64bit trampoline installed\n");
  893. }
  894. }
  895. long temp[2] = {(uint32_t)(((size_t)ptr)&0xFFFFfffful), 0};
  896. Atom atom = XInternAtom(display, "_XEventProc", False);
  897. XChangeProperty(display, window,
  898. atom/*property*/,
  899. atom/*type*/,
  900. 32/*format*/,
  901. PropModeReplace/*mode*/,
  902. (unsigned char *)temp/*data*/,
  903. 2/*nelements*/
  904. );
  905. }
  906. #endif
  907. #else
  908. // Pulled from the eXT2 example
  909. static void loc_setEventProc (Display *display, Window window) {
  910. void* data = (void*)&loc_XEventProc; // swapped the function name here
  911. // (note) 32-bit only
  912. Atom atom = XInternAtom(display, "_XEventProc", False);
  913. XChangeProperty(display, window,
  914. atom/*property*/,
  915. atom/*type*/,
  916. 32/*format*/,
  917. PropModeReplace/*mode*/,
  918. (unsigned char*)&data/*data*/,
  919. 1/*nelements*/
  920. );
  921. }
  922. #endif // ARCH_X64
  923. // ---------------------------------------------------------------------------- lglw_window_open
  924. lglw_bool_t lglw_window_open (lglw_t _lglw, void *_parentHWNDOrNull, int32_t _x, int32_t _y, int32_t _w, int32_t _h) {
  925. lglw_bool_t r = LGLW_FALSE;
  926. LGLW(_lglw);
  927. if(NULL != lglw)
  928. {
  929. lglw_log("lglw:lglw_window_open: 1, %p, %i \n", (Window)_parentHWNDOrNull, (Window)_parentHWNDOrNull);
  930. lglw->parent_xwnd = (0 == _parentHWNDOrNull) ? DefaultRootWindow(lglw->xdsp) : (Window)_parentHWNDOrNull;
  931. lglw_log("lglw:lglw_window_open: 2 lglw=%p\n", lglw);
  932. if(_w <= 16)
  933. _w = lglw->hidden.size.x;
  934. lglw_log("lglw:lglw_window_open: 3\n");
  935. if(_h <= 16)
  936. _h = lglw->hidden.size.y;
  937. // TODO: compare to 'WindowClass' from Windows implementation
  938. lglw_log("lglw:lglw_window_open: 4\n");
  939. XSetWindowAttributes swa;
  940. // // XEvent event;
  941. XSync(lglw->xdsp, False);
  942. #if 1
  943. lglw_log("lglw:lglw_window_open: 5\n");
  944. swa.border_pixel = 0;
  945. swa.colormap = lglw->cmap;
  946. // (note) [bsp] setting this to NoEventMask causes all events to be propagated to the parent (host) window.
  947. // The host then reports the event to the plugin by calling its eventProc function (set via "_XEventProc").
  948. swa.event_mask = NoEventMask;/////ExposureMask | KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | EnterWindowMask | LeaveWindowMask | PointerMotionMask | ButtonMotionMask | FocusChangeMask;
  949. lglw->win.xwnd = XCreateWindow(lglw->xdsp/*display*/,
  950. DefaultRootWindow(lglw->xdsp)/*parent. see Cameron's comment below.*/,
  951. 0/*x*/,
  952. 0/*y*/,
  953. _w/*width*/,
  954. _h/*height*/,
  955. 0/*border_width*/,
  956. CopyFromParent/*depth*/,
  957. InputOutput/*class*/,
  958. lglw->vi->visual,
  959. CWBorderPixel | CWColormap | CWEventMask/*value_mask*/,
  960. &swa/*attributes*/
  961. );
  962. lglw_log("lglw:lglw_window_open: 6\n");
  963. XSetStandardProperties(lglw->xdsp/*display*/,
  964. lglw->win.xwnd/*window*/,
  965. "LGLW"/*window_name*/,
  966. "LGLW"/*icon_name*/,
  967. None/*icon_pixmap*/,
  968. NULL/*argv*/,
  969. 0/*argc*/,
  970. NULL/*XSizeHints*/
  971. );
  972. // Setup the event proc now, on the parent window as well just for the debug host
  973. // It was simpler to do this than check in the debug host for the reparent event
  974. lglw_log("lglw:lglw_window_open: 7\n");
  975. loc_setEventProc(lglw->xdsp, lglw->win.xwnd);
  976. loc_setProperty(lglw->xdsp, lglw->win.xwnd, "_lglw", (void*)lglw); // set instance pointer
  977. if(0 != _parentHWNDOrNull)
  978. {
  979. loc_setEventProc(lglw->xdsp, lglw->parent_xwnd);
  980. loc_setProperty(lglw->xdsp, lglw->parent_xwnd, "_lglw", (void*)lglw); // set instance pointer
  981. }
  982. // Some hosts only check and store the callback when the Window is reparented
  983. // Since creating the Window with a Parent may or may not do that, but the callback is not set,
  984. // ... it's created as a root window, the callback is set, and then it's reparented
  985. #if 1
  986. // (note) [cameronleger] In Ardour's code-base, the only time it looks for the _XEventProc is during a ReparentNotify event
  987. if (0 != _parentHWNDOrNull)
  988. {
  989. lglw_log("lglw:lglw_window_open: 8\n");
  990. XReparentWindow(lglw->xdsp, lglw->win.xwnd, lglw->parent_xwnd, 0, 0);
  991. }
  992. #endif
  993. lglw->win.b_owner = LGLW_TRUE;
  994. #else
  995. lglw->win.xwnd = (Window)_parentHWNDOrNull;
  996. lglw->win.b_owner = LGLW_FALSE;
  997. #endif
  998. lglw_log("lglw:lglw_window_open: 9\n");
  999. if(lglw->win.b_owner)
  1000. {
  1001. // // XMapRaised(lglw->xdsp, lglw->win.xwnd);
  1002. XMapWindow(lglw->xdsp, lglw->win.xwnd);
  1003. }
  1004. #if 0
  1005. XSelectInput(lglw->xdsp, lglw->win.xwnd,
  1006. ExposureMask | KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | EnterWindowMask | LeaveWindowMask | PointerMotionMask | ButtonMotionMask | FocusChangeMask
  1007. );
  1008. XGrabKeyboard(lglw->xdsp, lglw->win.xwnd,
  1009. False/*owner_events*/,
  1010. GrabModeAsync/*pointer_mode*/,
  1011. GrabModeAsync/*keyboard_mode*/,
  1012. CurrentTime/*time*/
  1013. );
  1014. #endif
  1015. #if 0
  1016. XSetInputFocus(lglw->xdsp/*display*/,
  1017. PointerRoot/*focus*/,
  1018. RevertToPointerRoot/*revert_to*/,
  1019. CurrentTime
  1020. );
  1021. #endif
  1022. XSync(lglw->xdsp, False);
  1023. lglw->win.mapped = LGLW_TRUE;
  1024. lglw_log("lglw:lglw_window_open: 10\n");
  1025. lglw->win.size.x = _w;
  1026. lglw->win.size.y = _h;
  1027. lglw_log("lglw:lglw_window_open: 11\n");
  1028. loc_enable_dropfiles(lglw, (NULL != lglw->dropfiles.cbk));
  1029. lglw_log("lglw:lglw_window_open: EXIT\n");
  1030. r = LGLW_TRUE;
  1031. }
  1032. return r;
  1033. }
  1034. // ---------------------------------------------------------------------------- lglw_window_resize
  1035. lglw_bool_t lglw_window_resize (lglw_t _lglw, int32_t _w, int32_t _h) {
  1036. lglw_bool_t r = LGLW_FALSE;
  1037. LGLW(_lglw);
  1038. if(NULL != lglw)
  1039. {
  1040. if(0 != lglw->win.xwnd)
  1041. {
  1042. lglw_log("lglw:lglw_window_resize: 1\n");
  1043. r = LGLW_TRUE;
  1044. lglw_log("lglw:lglw_window_resize: 2\n");
  1045. XResizeWindow(lglw->xdsp, lglw->win.xwnd, _w, _h);
  1046. XRaiseWindow(lglw->xdsp, lglw->win.xwnd);
  1047. lglw_log("lglw:lglw_window_resize: 3\n");
  1048. int deltaW = _w - lglw->win.size.x;
  1049. int deltaH = _h - lglw->win.size.y;
  1050. lglw_log("lglw:lglw_window_resize: 4\n");
  1051. lglw->win.size.x = _w;
  1052. lglw->win.size.y = _h;
  1053. lglw_log("lglw:lglw_window_resize: 5\n");
  1054. Window root, parent, *children = NULL;
  1055. unsigned int num_children;
  1056. lglw_log("lglw:lglw_window_resize: 6\n");
  1057. if(!XQueryTree(lglw->xdsp, lglw->win.xwnd, &root, &parent, &children, &num_children))
  1058. return r;
  1059. lglw_log("lglw:lglw_window_resize: 7\n");
  1060. if(children)
  1061. XFree((char *)children);
  1062. lglw_log("lglw:lglw_window_resize: 8\n");
  1063. // Resize parent window (if any)
  1064. if(0 != parent)
  1065. {
  1066. lglw_log("lglw:lglw_window_resize: 8.1\n");
  1067. int x, y;
  1068. unsigned int width, height;
  1069. unsigned int border_width;
  1070. unsigned int depth;
  1071. lglw_log("lglw:lglw_window_resize: 8.2\n");
  1072. if(!XGetGeometry(lglw->xdsp, lglw->win.xwnd, &root, &x, &y, &width, &height, &border_width, &depth))
  1073. return r;
  1074. lglw_log("lglw:lglw_window_resize: 8.3\n");
  1075. XResizeWindow(lglw->xdsp, parent, width + deltaW, height + deltaH);
  1076. }
  1077. lglw_log("lglw:lglw_window_resize: EXIT\n");
  1078. }
  1079. }
  1080. return r;
  1081. }
  1082. // ---------------------------------------------------------------------------- lglw_window_close
  1083. void lglw_window_close (lglw_t _lglw) {
  1084. LGLW(_lglw);
  1085. if(NULL != lglw)
  1086. {
  1087. if(0 != lglw->win.xwnd)
  1088. {
  1089. lglw_log("lglw:lglw_window_close: 1\n");
  1090. lglw_timer_stop(_lglw);
  1091. lglw_log("lglw:lglw_window_close: 2\n");
  1092. glXMakeCurrent(lglw->xdsp, None, NULL);
  1093. lglw_log("lglw:lglw_window_close: 3\n");
  1094. if(lglw->win.b_owner)
  1095. {
  1096. XDestroyWindow(lglw->xdsp, lglw->win.xwnd);
  1097. lglw->win.b_owner = LGLW_FALSE;
  1098. }
  1099. XSync(lglw->xdsp, False);
  1100. lglw->win.xwnd = 0;
  1101. lglw->win.mapped = LGLW_FALSE;
  1102. }
  1103. }
  1104. lglw_log("lglw:lglw_window_close: EXIT\n");
  1105. }
  1106. // ---------------------------------------------------------------------------- lglw_window_show
  1107. void lglw_window_show(lglw_t _lglw) {
  1108. LGLW(_lglw);
  1109. if(NULL != lglw)
  1110. {
  1111. lglw_log("lglw:lglw_window_show: 1\n");
  1112. XMapRaised(lglw->xdsp, lglw->win.xwnd);
  1113. lglw->win.mapped = LGLW_TRUE;
  1114. }
  1115. lglw_log("lglw:lglw_window_show: EXIT\n");
  1116. }
  1117. // ---------------------------------------------------------------------------- lglw_window_hide
  1118. void lglw_window_hide(lglw_t _lglw) {
  1119. LGLW(_lglw);
  1120. if(NULL != lglw)
  1121. {
  1122. lglw_log("lglw:lglw_window_hide: 1\n");
  1123. XUnmapWindow(lglw->xdsp, lglw->win.xwnd);
  1124. lglw->win.mapped = LGLW_FALSE;
  1125. }
  1126. lglw_log("lglw:lglw_window_hide: EXIT\n");
  1127. }
  1128. // ---------------------------------------------------------------------------- lglw_window_is_visible
  1129. lglw_bool_t lglw_window_is_visible(lglw_t _lglw) {
  1130. lglw_bool_t r = LGLW_FALSE;
  1131. LGLW(_lglw);
  1132. // lglw_log("lglw:lglw_window_is_visible: 1\n");
  1133. if(NULL != lglw && 0 != lglw->win.xwnd)
  1134. {
  1135. // lglw_log("lglw:lglw_window_is_visible: 2\n");
  1136. r = lglw->win.mapped;
  1137. }
  1138. // lglw_log("lglw:lglw_window_is_visible: EXIT\n");
  1139. return r;
  1140. }
  1141. // ---------------------------------------------------------------------------- lglw_window_size_get
  1142. void lglw_window_size_get(lglw_t _lglw, int32_t *_retX, int32_t *_retY) {
  1143. LGLW(_lglw);
  1144. Dlog_verbose("lglw:lglw_window_size_get: 1\n");
  1145. if(NULL != lglw)
  1146. {
  1147. if(0 != lglw->win.xwnd)
  1148. {
  1149. if(NULL != _retX)
  1150. *_retX = lglw->win.size.x;
  1151. if(NULL != _retY)
  1152. *_retY = lglw->win.size.y;
  1153. }
  1154. }
  1155. Dlog_verbose("lglw:lglw_window_size_get: EXIT\n");
  1156. }
  1157. // ---------------------------------------------------------------------------- lglw_redraw
  1158. void lglw_redraw(lglw_t _lglw) {
  1159. LGLW(_lglw);
  1160. // (todo) implement me
  1161. if(NULL != lglw)
  1162. {
  1163. if(0 != lglw->win.xwnd)
  1164. {
  1165. // TODO Event Loop
  1166. Dlog_verbose("lglw:lglw_redraw: 1\n");
  1167. XEvent xev;
  1168. xev.xany.type = Expose;
  1169. xev.xany.serial = 0;
  1170. xev.xany.send_event = True;
  1171. xev.xany.display = lglw->xdsp;
  1172. xev.xany.window = lglw->win.xwnd;
  1173. xev.xexpose.x = 0;
  1174. xev.xexpose.y = 0;
  1175. xev.xexpose.width = lglw->win.size.x;
  1176. xev.xexpose.height = lglw->win.size.y;
  1177. xev.xexpose.count = 0;
  1178. XSendEvent(lglw->xdsp, lglw->win.xwnd,
  1179. True/*propagate*/,
  1180. ExposureMask/*event_mask*/,
  1181. &xev
  1182. );
  1183. XFlush(lglw->xdsp);
  1184. }
  1185. }
  1186. }
  1187. // ---------------------------------------------------------------------------- lglw_redraw_callback_set
  1188. void lglw_redraw_callback_set(lglw_t _lglw, lglw_redraw_fxn_t _cbk) {
  1189. LGLW(_lglw);
  1190. if(NULL != lglw)
  1191. {
  1192. lglw->redraw.cbk = _cbk;
  1193. }
  1194. }
  1195. // ---------------------------------------------------------------------------- lglw_glcontext_push
  1196. void lglw_glcontext_push(lglw_t _lglw) {
  1197. LGLW(_lglw);
  1198. if(NULL != lglw)
  1199. {
  1200. lglw->prev.drw = glXGetCurrentDrawable();
  1201. lglw->prev.ctx = glXGetCurrentContext();
  1202. // lglw_log("lglw:lglw_glcontext_push: win.xwnd=%p hidden.xwnd=%p ctx=%p\n",
  1203. // lglw->win.xwnd, lglw->hidden.xwnd, lglw->ctx);
  1204. if(!glXMakeCurrent(lglw->xdsp, (0 == lglw->win.xwnd) ? lglw->hidden.xwnd : lglw->win.xwnd, lglw->ctx))
  1205. {
  1206. 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());
  1207. }
  1208. }
  1209. }
  1210. // ---------------------------------------------------------------------------- lglw_glcontext_pop
  1211. void lglw_glcontext_pop(lglw_t _lglw) {
  1212. LGLW(_lglw);
  1213. if(NULL != lglw)
  1214. {
  1215. // lglw_log("lglw:lglw_glcontext_pop: prev.drw=%p prev.ctx=%p\n",
  1216. // lglw->prev.drw, lglw->prev.ctx);
  1217. if(!glXMakeCurrent(lglw->xdsp, lglw->prev.drw, lglw->prev.ctx))
  1218. {
  1219. lglw_log("[---] lglw_glcontext_pop: glXMakeCurrent() failed. prev.drw=%p ctx=%p glGetError()=%d\n", lglw->prev.drw, lglw->prev.ctx, glGetError());
  1220. }
  1221. }
  1222. }
  1223. // ---------------------------------------------------------------------------- lglw_swap_buffers
  1224. void lglw_swap_buffers(lglw_t _lglw) {
  1225. LGLW(_lglw);
  1226. if(NULL != lglw)
  1227. {
  1228. if(0 != lglw->win.xwnd)
  1229. {
  1230. // lglw_log("lglw:lglw_swap_buffers: 1\n");
  1231. glXSwapBuffers(lglw->xdsp, lglw->win.xwnd);
  1232. }
  1233. }
  1234. }
  1235. // ---------------------------------------------------------------------------- lglw_swap_interval_set
  1236. typedef void (APIENTRY *PFNWGLEXTSWAPINTERVALPROC) (Display *, GLXDrawable, int);
  1237. void lglw_swap_interval_set(lglw_t _lglw, int32_t _ival) {
  1238. LGLW(_lglw);
  1239. if(NULL != lglw)
  1240. {
  1241. if(0 != lglw->win.xwnd)
  1242. {
  1243. lglw_log("lglw:lglw_swap_interval_set: 1\n");
  1244. PFNWGLEXTSWAPINTERVALPROC glXSwapIntervalEXT;
  1245. glXSwapIntervalEXT = (PFNWGLEXTSWAPINTERVALPROC) glXGetProcAddress((const GLubyte*)"glXSwapIntervalEXT");
  1246. if(NULL != glXSwapIntervalEXT)
  1247. {
  1248. lglw_log("lglw:lglw_swap_interval_set: 2\n");
  1249. glXSwapIntervalEXT(lglw->xdsp, lglw->win.xwnd, _ival);
  1250. lglw->win.swap_interval = _ival;
  1251. }
  1252. }
  1253. }
  1254. }
  1255. // ---------------------------------------------------------------------------- lglw_swap_interval_get
  1256. int32_t lglw_swap_interval_get(lglw_t _lglw) {
  1257. LGLW(_lglw);
  1258. int32_t r = 0;
  1259. if(NULL != lglw)
  1260. {
  1261. r = lglw->win.swap_interval;
  1262. }
  1263. return r;
  1264. }
  1265. // ---------------------------------------------------------------------------- loc_handle_mouseleave
  1266. static void loc_handle_mouseleave(lglw_int_t *lglw) {
  1267. lglw->focus.state &= ~LGLW_FOCUS_MOUSE;
  1268. if(NULL != lglw->focus.cbk)
  1269. {
  1270. lglw->focus.cbk(lglw, lglw->focus.state, LGLW_FOCUS_MOUSE);
  1271. }
  1272. lglw_log("xxx lglw:loc_handle_mouseleave: LEAVE\n");
  1273. }
  1274. // ---------------------------------------------------------------------------- loc_handle_mouseenter
  1275. static void loc_handle_mouseenter(lglw_int_t *lglw) {
  1276. lglw->focus.state |= LGLW_FOCUS_MOUSE;
  1277. if(NULL != lglw->focus.cbk)
  1278. {
  1279. lglw->focus.cbk(lglw, lglw->focus.state, LGLW_FOCUS_MOUSE);
  1280. }
  1281. lglw_log("xxx lglw:loc_handle_mouseenter: LEAVE\n");
  1282. }
  1283. // ---------------------------------------------------------------------------- loc_handle_mousebutton
  1284. static void loc_handle_mousebutton(lglw_int_t *lglw, lglw_bool_t _bPressed, uint32_t _button) {
  1285. if(_bPressed)
  1286. lglw->mouse.button_state |= _button;
  1287. else
  1288. lglw->mouse.button_state &= ~_button;
  1289. if(NULL != lglw->mouse.cbk)
  1290. {
  1291. lglw->mouse.cbk(lglw, lglw->mouse.p.x, lglw->mouse.p.y, lglw->mouse.button_state, _button);
  1292. }
  1293. }
  1294. // ---------------------------------------------------------------------------- loc_handle_mousemotion
  1295. static void loc_handle_mousemotion(lglw_int_t *lglw) {
  1296. if(NULL != lglw->mouse.cbk)
  1297. {
  1298. lglw->mouse.cbk(lglw, lglw->mouse.p.x, lglw->mouse.p.y, lglw->mouse.button_state, 0u/*changedbuttonstate*/);
  1299. }
  1300. }
  1301. // ---------------------------------------------------------------------------- lglw_mouse_callback_set
  1302. void lglw_mouse_callback_set(lglw_t _lglw, lglw_mouse_fxn_t _cbk) {
  1303. LGLW(_lglw);
  1304. if(NULL != lglw)
  1305. {
  1306. lglw->mouse.cbk = _cbk;
  1307. }
  1308. }
  1309. // ---------------------------------------------------------------------------- lglw_mouse_callback_set
  1310. void lglw_focus_callback_set(lglw_t _lglw, lglw_focus_fxn_t _cbk) {
  1311. LGLW(_lglw);
  1312. if(NULL != lglw)
  1313. {
  1314. lglw->focus.cbk = _cbk;
  1315. }
  1316. }
  1317. // ---------------------------------------------------------------------------- loc_handle_key
  1318. static lglw_bool_t loc_handle_key(lglw_int_t *lglw, lglw_bool_t _bPressed, uint32_t _vkey) {
  1319. lglw_bool_t r = LGLW_FALSE;
  1320. if(NULL != lglw->keyboard.cbk)
  1321. {
  1322. r = lglw->keyboard.cbk(lglw, _vkey, lglw->keyboard.kmod_state, _bPressed);
  1323. }
  1324. return r;
  1325. }
  1326. // ---------------------------------------------------------------------------- lglw_keyboard_callback_set
  1327. void lglw_keyboard_callback_set(lglw_t _lglw, lglw_keyboard_fxn_t _cbk) {
  1328. LGLW(_lglw);
  1329. if(NULL != lglw)
  1330. {
  1331. lglw->keyboard.cbk = _cbk;
  1332. }
  1333. }
  1334. // ---------------------------------------------------------------------------- lglw_keyboard_get_modifiers
  1335. uint32_t lglw_keyboard_get_modifiers(lglw_t _lglw) {
  1336. uint32_t r = 0u;
  1337. LGLW(_lglw);
  1338. if(NULL != lglw)
  1339. {
  1340. r = lglw->keyboard.kmod_state;
  1341. }
  1342. return r;
  1343. }
  1344. // ---------------------------------------------------------------------------- lglw_touchkeyboard_show
  1345. void lglw_touchkeyboard_show(lglw_t _lglw, lglw_bool_t _bEnable) {
  1346. LGLW(_lglw);
  1347. // (todo) implement me
  1348. if(NULL != lglw)
  1349. {
  1350. }
  1351. }
  1352. // ---------------------------------------------------------------------------- lglw_mouse_get_buttons
  1353. uint32_t lglw_mouse_get_buttons(lglw_t _lglw) {
  1354. uint32_t r = 0u;
  1355. LGLW(_lglw);
  1356. if(NULL != lglw)
  1357. {
  1358. r = lglw->mouse.button_state;
  1359. }
  1360. return r;
  1361. }
  1362. // ---------------------------------------------------------------------------- lglw_mouse_grab
  1363. void lglw_mouse_grab(lglw_t _lglw, uint32_t _grabMode) {
  1364. LGLW(_lglw);
  1365. if(NULL != lglw)
  1366. {
  1367. if(0 != lglw->win.xwnd)
  1368. {
  1369. if(!lglw->mouse.touch.b_enable)
  1370. {
  1371. if(lglw->mouse.grab.mode != _grabMode)
  1372. {
  1373. lglw_mouse_ungrab(_lglw);
  1374. }
  1375. int result;
  1376. switch(_grabMode)
  1377. {
  1378. default:
  1379. case LGLW_MOUSE_GRAB_NONE:
  1380. break;
  1381. case LGLW_MOUSE_GRAB_CAPTURE:
  1382. result = XGrabPointer(lglw->xdsp, lglw->win.xwnd,
  1383. True/*owner_events*/,
  1384. ButtonPressMask | ButtonReleaseMask | EnterWindowMask | LeaveWindowMask | PointerMotionMask | PointerMotionHintMask | ButtonMotionMask | KeymapStateMask/*event_mask*/,
  1385. GrabModeAsync/*pointer_mode*/,
  1386. GrabModeAsync/*keyboard_mode*/,
  1387. lglw->win.xwnd/*confine_to*/,
  1388. None/*cursor*/,
  1389. CurrentTime/*time*/);
  1390. if(GrabSuccess != result)
  1391. {
  1392. printf("vstgltest<lglw_linux>: Grab Result: %i\n", result);
  1393. }
  1394. else
  1395. {
  1396. lglw->mouse.grab.mode = _grabMode;
  1397. }
  1398. break;
  1399. case LGLW_MOUSE_GRAB_WARP:
  1400. result = XGrabPointer(lglw->xdsp, lglw->win.xwnd,
  1401. True/*owner_events*/,
  1402. ButtonPressMask | ButtonReleaseMask | EnterWindowMask | LeaveWindowMask | PointerMotionMask | PointerMotionHintMask | ButtonMotionMask | KeymapStateMask/*event_mask*/,
  1403. GrabModeAsync/*pointer_mode*/,
  1404. GrabModeAsync/*keyboard_mode*/,
  1405. lglw->win.xwnd/*confine_to*/,
  1406. None/*cursor*/,
  1407. CurrentTime/*time*/);
  1408. if(GrabSuccess != result)
  1409. {
  1410. printf("vstgltest<lglw_linux>: Grab Result: %i\n", result);
  1411. }
  1412. else
  1413. {
  1414. lglw_mouse_cursor_show(_lglw, LGLW_FALSE);
  1415. lglw->mouse.grab.p = lglw->mouse.p;
  1416. lglw->mouse.grab.last_p = lglw->mouse.p;
  1417. lglw->mouse.grab.mode = _grabMode;
  1418. }
  1419. break;
  1420. }
  1421. }
  1422. }
  1423. }
  1424. }
  1425. // ---------------------------------------------------------------------------- lglw_mouse_ungrab
  1426. void lglw_mouse_ungrab(lglw_t _lglw) {
  1427. LGLW(_lglw);
  1428. if(NULL != lglw)
  1429. {
  1430. if(0 != lglw->win.xwnd)
  1431. {
  1432. if(!lglw->mouse.touch.b_enable)
  1433. {
  1434. switch(lglw->mouse.grab.mode)
  1435. {
  1436. default:
  1437. case LGLW_MOUSE_GRAB_NONE:
  1438. break;
  1439. case LGLW_MOUSE_GRAB_CAPTURE:
  1440. XUngrabPointer(lglw->xdsp, CurrentTime);
  1441. lglw->mouse.grab.mode = LGLW_MOUSE_GRAB_NONE;
  1442. break;
  1443. case LGLW_MOUSE_GRAB_WARP:
  1444. XUngrabPointer(lglw->xdsp, CurrentTime);
  1445. lglw->mouse.grab.mode = LGLW_MOUSE_GRAB_NONE;
  1446. lglw->mouse.grab.b_queue_warp = LGLW_TRUE;
  1447. lglw_mouse_cursor_show(_lglw, LGLW_TRUE);
  1448. break;
  1449. }
  1450. }
  1451. }
  1452. }
  1453. }
  1454. // ---------------------------------------------------------------------------- lglw_mouse_warp
  1455. void lglw_mouse_warp(lglw_t _lglw, int32_t _x, int32_t _y) {
  1456. LGLW(_lglw);
  1457. if(NULL != lglw)
  1458. {
  1459. if(0 != lglw->win.xwnd)
  1460. {
  1461. XWarpPointer(lglw->xdsp,
  1462. None/*src_w*/,
  1463. lglw->win.xwnd/*dest_w*/,
  1464. 0/*src_x*/,
  1465. 0/*src_y*/,
  1466. 0/*src_width*/,
  1467. 0/*src_height*/,
  1468. _x/*dest_x*/,
  1469. _y/*dest_y*/);
  1470. }
  1471. }
  1472. }
  1473. // ---------------------------------------------------------------------------- loc_handle_queued_mouse_warp
  1474. static void loc_handle_queued_mouse_warp(lglw_int_t *lglw) {
  1475. if(lglw->mouse.grab.b_queue_warp)
  1476. {
  1477. lglw->mouse.grab.b_queue_warp = LGLW_FALSE;
  1478. lglw_mouse_warp(lglw, lglw->mouse.grab.p.x, lglw->mouse.grab.p.y);
  1479. lglw->mouse.grab.last_p = lglw->mouse.grab.p;
  1480. }
  1481. }
  1482. // ---------------------------------------------------------------------------- lglw_mouse_cursor_show
  1483. void lglw_mouse_cursor_show (lglw_t _lglw, lglw_bool_t _bShow) {
  1484. LGLW(_lglw);
  1485. if(NULL != lglw)
  1486. {
  1487. if(LGLW_FALSE == _bShow)
  1488. {
  1489. Pixmap noPxm;
  1490. Cursor noCursor;
  1491. XColor black, dummy;
  1492. static char pxmNoData[] = {0, 0, 0, 0, 0, 0, 0, 0};
  1493. XAllocNamedColor(lglw->xdsp, lglw->cmap, "black", &black, &dummy);
  1494. noPxm = XCreateBitmapFromData(lglw->xdsp, lglw->win.xwnd, pxmNoData, 8, 8);
  1495. noCursor = XCreatePixmapCursor(lglw->xdsp, noPxm, noPxm, &black, &black, 0, 0);
  1496. XDefineCursor(lglw->xdsp, lglw->win.xwnd, noCursor);
  1497. XFreeCursor(lglw->xdsp, noCursor);
  1498. if(noPxm != None)
  1499. {
  1500. XFreePixmap(lglw->xdsp, noPxm);
  1501. }
  1502. }
  1503. else
  1504. {
  1505. XUndefineCursor(lglw->xdsp, lglw->win.xwnd);
  1506. }
  1507. }
  1508. }
  1509. // ---------------------------------------------------------------------------- lglw_timer_start
  1510. void lglw_timer_start(lglw_t _lglw, uint32_t _millisec) {
  1511. LGLW(_lglw);
  1512. if(NULL != lglw)
  1513. {
  1514. lglw_log("xxx lglw_linux:lglw_timer_start: interval=%u\n", _millisec);
  1515. lglw->timer.interval_ms = _millisec;
  1516. lglw->timer.b_running = LGLW_TRUE;
  1517. }
  1518. }
  1519. // ---------------------------------------------------------------------------- lglw_timer_stop
  1520. void lglw_timer_stop(lglw_t _lglw) {
  1521. LGLW(_lglw);
  1522. if(NULL != lglw)
  1523. {
  1524. lglw_log("xxx lglw_linux:lglw_timer_stop\n");
  1525. lglw->timer.b_running = LGLW_FALSE;
  1526. }
  1527. }
  1528. // ---------------------------------------------------------------------------- lglw_timer_callback_set
  1529. void lglw_timer_callback_set(lglw_t _lglw, lglw_timer_fxn_t _cbk) {
  1530. LGLW(_lglw);
  1531. if(NULL != lglw)
  1532. {
  1533. lglw->timer.cbk = _cbk;
  1534. }
  1535. }
  1536. // ---------------------------------------------------------------------------- loc_process_timer()
  1537. static void loc_process_timer(lglw_int_t *lglw) {
  1538. if(lglw->timer.b_running)
  1539. {
  1540. uint32_t ms = loc_millisec_delta(lglw);
  1541. if( (ms - lglw->timer.last_ms) >= lglw->timer.interval_ms )
  1542. {
  1543. lglw->timer.last_ms = ms;
  1544. if(NULL != lglw->timer.cbk)
  1545. {
  1546. lglw->timer.cbk(lglw);
  1547. }
  1548. }
  1549. }
  1550. }
  1551. // ---------------------------------------------------------------------------- loc_enable_dropfiles
  1552. static void loc_enable_dropfiles(lglw_int_t *lglw, lglw_bool_t _bEnable) {
  1553. // (todo) implement me
  1554. }
  1555. // ---------------------------------------------------------------------------- lglw_dropfiles_callback_set
  1556. void lglw_dropfiles_callback_set(lglw_t _lglw, lglw_dropfiles_fxn_t _cbk) {
  1557. LGLW(_lglw);
  1558. if(NULL != _lglw)
  1559. {
  1560. lglw->dropfiles.cbk = _cbk;
  1561. loc_enable_dropfiles(lglw, (NULL != _cbk));
  1562. }
  1563. }
  1564. // ---------------------------------------------------------------------------- lglw_touchinput_set
  1565. void lglw_touchinput_set(lglw_t _lglw, lglw_bool_t _bEnable) {
  1566. LGLW(_lglw);
  1567. if(NULL != _lglw)
  1568. {
  1569. lglw->mouse.touch.b_enable = _bEnable;
  1570. lglw->mouse.touch.b_update_queued = LGLW_TRUE;
  1571. }
  1572. }
  1573. // ---------------------------------------------------------------------------- lglw_touchinput_get
  1574. lglw_bool_t lglw_touchinput_get(lglw_t _lglw) {
  1575. lglw_bool_t r = LGLW_FALSE;
  1576. LGLW(_lglw);
  1577. if(NULL != _lglw)
  1578. {
  1579. r = lglw->mouse.touch.b_enable;
  1580. }
  1581. return r;
  1582. }
  1583. // ---------------------------------------------------------------------------- lglw_clipboard_text_set
  1584. void lglw_clipboard_text_set(lglw_t _lglw, const uint32_t _numChars, const char *_text) {
  1585. LGLW(_lglw);
  1586. (void)_numChars;
  1587. if(NULL != _text)
  1588. {
  1589. if(NULL != _lglw)
  1590. {
  1591. if(0 != lglw->win.xwnd)
  1592. {
  1593. uint32_t numChars = (0u == _numChars) ? ((uint32_t)strlen(_text)+1u) : _numChars;
  1594. if(numChars > 0u)
  1595. {
  1596. lglw->clipboard.numChars = numChars;
  1597. lglw->clipboard.data = malloc(numChars+1);
  1598. uint32_t i;
  1599. for(i = 0u; i < numChars; i++)
  1600. {
  1601. lglw->clipboard.data[i] = _text[i];
  1602. }
  1603. lglw->clipboard.data[numChars - 1] = 0;
  1604. printf("xxx lglw_clipboard_text_set(%i): %s\n", lglw->clipboard.numChars, lglw->clipboard.data);
  1605. Atom clipboard = XInternAtom(lglw->xdsp, "CLIPBOARD", False);
  1606. XSetSelectionOwner(lglw->xdsp, clipboard, lglw->win.xwnd, CurrentTime);
  1607. XSync(lglw->xdsp, False);
  1608. }
  1609. }
  1610. }
  1611. }
  1612. }
  1613. // ---------------------------------------------------------------------------- loc_is_clipboard_event
  1614. static Bool loc_is_clipboard_event(Display *_display, XEvent *_xevent, XPointer _xarg) {
  1615. return _xevent->type == SelectionNotify;
  1616. }
  1617. // ---------------------------------------------------------------------------- lglw_clipboard_text_get
  1618. void lglw_clipboard_text_get(lglw_t _lglw, uint32_t _maxChars, uint32_t *_retNumChars, char *_retText) {
  1619. LGLW(_lglw);
  1620. if(NULL != _retNumChars)
  1621. *_retNumChars = 0u;
  1622. if(NULL != _retText)
  1623. *_retText = 0;
  1624. if(_maxChars > 0u)
  1625. {
  1626. if(NULL != _lglw)
  1627. {
  1628. if(0 != lglw->win.xwnd)
  1629. {
  1630. Window owner;
  1631. XEvent xev;
  1632. XSelectionEvent *cbReq;
  1633. Atom clipboard = XInternAtom(lglw->xdsp, "CLIPBOARD", False);
  1634. Atom utf8 = XInternAtom(lglw->xdsp, "UTF8_STRING", False);
  1635. Atom target = XInternAtom(lglw->xdsp, "_clipboard_result", False);
  1636. owner = XGetSelectionOwner(lglw->xdsp, clipboard);
  1637. if(owner == None)
  1638. {
  1639. printf("xxx lglw_clipboard_text_get: No Window can provide a clipboard result\n");
  1640. return;
  1641. }
  1642. if(owner == lglw->win.xwnd)
  1643. {
  1644. printf("xxx lglw_clipboard_text_get: We are the owner of the clipboard, skip X interactions\n");
  1645. uint32_t i = 0u;
  1646. for(; i < _maxChars; i++)
  1647. {
  1648. _retText[i] = lglw->clipboard.data[i];
  1649. if(0 == _retText[i])
  1650. break;
  1651. }
  1652. _retText[_maxChars - 1u] = 0;
  1653. if(NULL != _retNumChars)
  1654. *_retNumChars = i;
  1655. printf("xxx lglw_clipboard_text_get: (result on next line)\n%s\n", _retText);
  1656. return;
  1657. }
  1658. XConvertSelection(lglw->xdsp, clipboard, utf8, target, lglw->win.xwnd, CurrentTime);
  1659. XIfEvent(lglw->xdsp, &xev, &loc_is_clipboard_event, None);
  1660. cbReq = (XSelectionEvent*)&xev;
  1661. if(None == cbReq->property)
  1662. {
  1663. printf("xxx lglw_clipboard_text_get: Clipboard was not converted to UTF-8 string\n");
  1664. return;
  1665. }
  1666. Atom returnType;
  1667. int returnFormat;
  1668. unsigned long size, returnSize, bytesLeft;
  1669. unsigned char *propertyValue = NULL;
  1670. XGetWindowProperty(lglw->xdsp, lglw->win.xwnd, target,
  1671. 0/*offset*/,
  1672. 0/*length*/,
  1673. False/*delete*/,
  1674. AnyPropertyType/*req_type*/,
  1675. &returnType/*actual_type_return*/,
  1676. &returnFormat/*actual_format_return*/,
  1677. &returnSize/*nitems_return*/,
  1678. &size/*bytes_after_return*/,
  1679. &propertyValue/*prop_return*/);
  1680. XFree(propertyValue);
  1681. if(utf8 != returnType)
  1682. {
  1683. printf("xxx lglw_clipboard_text_get: Clipboard result is not a UTF-8 string\n");
  1684. return;
  1685. }
  1686. if(8u != returnFormat)
  1687. {
  1688. printf("xxx lglw_clipboard_text_get: Clipboard format is not a char array\n");
  1689. return;
  1690. }
  1691. if(_maxChars < size)
  1692. size = _maxChars;
  1693. size = 1 + ((size - 1) / 4);
  1694. // TODO: Even with the largest current use-case, multiple calls aren't necessary. do it anyway just in case
  1695. XGetWindowProperty(lglw->xdsp, lglw->win.xwnd, target,
  1696. 0/*offset*/,
  1697. size/*length*/,
  1698. True/*delete*/,
  1699. AnyPropertyType/*req_type*/,
  1700. &returnType/*actual_type_return*/,
  1701. &returnFormat/*actual_format_return*/,
  1702. &returnSize/*nitems_return*/,
  1703. &bytesLeft/*bytes_after_return*/,
  1704. &propertyValue/*prop_return*/);
  1705. if(returnSize == 0)
  1706. {
  1707. printf("xxx lglw_clipboard_text_get: No Clipboard result after final request\n");
  1708. return;
  1709. }
  1710. uint32_t i = 0u;
  1711. for(; i < _maxChars; i++)
  1712. {
  1713. _retText[i] = propertyValue[i];
  1714. if(0 == _retText[i])
  1715. break;
  1716. }
  1717. _retText[_maxChars - 1u] = 0;
  1718. if(NULL != _retNumChars)
  1719. *_retNumChars = i;
  1720. printf("xxx lglw_clipboard_text_get: (result on next line)\n%s\n", _retText);
  1721. XFree(propertyValue);
  1722. }
  1723. }
  1724. }
  1725. }
  1726. // ---------------------------------------------------------------------------- lglw_events
  1727. void lglw_events(lglw_t _lglw) {
  1728. LGLW(_lglw);
  1729. if(NULL != lglw)
  1730. {
  1731. if(0 != lglw->win.xwnd)
  1732. {
  1733. #if 0
  1734. //int numEv = XEventsQueued(lglw->xdsp, QueuedAlready);
  1735. int numEv = XEventsQueued(lglw->xdsp, QueuedAfterReading);
  1736. // => numEv is always 0
  1737. int evIdx = 0;
  1738. printf("xxx lglw_events: numEv=%d\n", numEv);
  1739. //for(; evIdx < numEv; evIdx++)
  1740. for(;;)
  1741. {
  1742. XEvent xev;
  1743. XNextEvent(lglw->xdsp, &xev);
  1744. printf("xxx lglw_events: XNextEvent[%d]\n", evIdx++);
  1745. loc_eventProc(&xev, lglw);
  1746. }
  1747. #else
  1748. // // int evIdx = 0;
  1749. // // for(;;)
  1750. // // {
  1751. // // XEvent xev;
  1752. // // // => blocks forever
  1753. // // XNextEvent(lglw->xdsp, &xev);
  1754. // // printf("xxx XNextEvent[%d]\n", evIdx++);
  1755. // // }
  1756. loc_process_timer(lglw);
  1757. #endif
  1758. }
  1759. }
  1760. }