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.

2108 lines
69KB

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