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.

1056 lines
29KB

  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. #define Dprintf if(0);else printf
  41. // #define Dprintf if(1);else printf
  42. // ---------------------------------------------------------------------------- macros and defines
  43. #define LGLW(a) lglw_int_t *lglw = ((lglw_int_t*)(a))
  44. #define LGLW_DEFAULT_HIDDEN_W (800)
  45. #define LGLW_DEFAULT_HIDDEN_H (600)
  46. #define LGLW_MOUSE_TOUCH_LMB_TIMEOUT (250u)
  47. #define LGLW_MOUSE_TOUCH_RMB_TIMEOUT (500u)
  48. #define LGLW_MOUSE_TOUCH_RMB_STATE_IDLE (0u)
  49. #define LGLW_MOUSE_TOUCH_RMB_STATE_LMB (1u)
  50. #define LGLW_MOUSE_TOUCH_RMB_STATE_WAIT (2u)
  51. #define LGLW_MOUSE_TOUCH_RMB_STATE_RMB (3u)
  52. #define LGLW_MOUSE_TOUCH_RMB_MOVE_THRESHOLD (7u)
  53. #define sABS(x) (((x)>0)?(x):-(x))
  54. // ---------------------------------------------------------------------------- structs and typedefs
  55. typedef struct lglw_int_s {
  56. void *user_data; // arbitrary user data
  57. Display *xdsp;
  58. XVisualInfo *vi;
  59. Colormap cmap;
  60. Window parent_xwnd; // created by host
  61. struct {
  62. lglw_vec2i_t size;
  63. Window xwnd;
  64. } hidden;
  65. struct {
  66. lglw_vec2i_t size;
  67. Window xwnd;
  68. lglw_bool_t mapped;
  69. int32_t swap_interval;
  70. } win;
  71. GLXContext ctx;
  72. struct {
  73. GLXContext ctx;
  74. GLXDrawable drw;
  75. } prev;
  76. struct {
  77. uint32_t kmod_state; // See LGLW_KMOD_xxx
  78. lglw_keyboard_fxn_t cbk;
  79. } keyboard;
  80. struct {
  81. lglw_vec2i_t p; // last seen mouse position
  82. uint32_t button_state;
  83. lglw_mouse_fxn_t cbk;
  84. struct {
  85. uint32_t mode;
  86. lglw_vec2i_t p; // grab-start mouse position
  87. lglw_bool_t b_queue_warp;
  88. lglw_vec2i_t last_p;
  89. } grab;
  90. struct {
  91. lglw_bool_t b_enable;
  92. lglw_bool_t b_update_queued;
  93. lglw_bool_t b_syn_rmb;
  94. uint32_t syn_rmb_hold_state; // see LGLW_MOUSE_TOUCH_RMB_STATE_xxx
  95. uint32_t hold_start_ms;
  96. lglw_vec2i_t hold_start_p;
  97. } touch;
  98. } mouse;
  99. struct {
  100. uint32_t state;
  101. lglw_focus_fxn_t cbk;
  102. } focus;
  103. struct {
  104. lglw_bool_t b_running;
  105. lglw_timer_fxn_t cbk;
  106. } timer;
  107. struct {
  108. lglw_dropfiles_fxn_t cbk;
  109. } dropfiles;
  110. struct {
  111. lglw_redraw_fxn_t cbk;
  112. } redraw;
  113. } lglw_int_t;
  114. // ---------------------------------------------------------------------------- module fxn fwd decls
  115. static lglw_bool_t loc_create_hidden_window (lglw_int_t *lglw, int32_t _w, int32_t _h);
  116. static void loc_destroy_hidden_window(lglw_int_t *lglw);
  117. static void loc_key_hook(lglw_int_t *lglw);
  118. static void loc_key_unhook(lglw_int_t *lglw);
  119. static lglw_bool_t loc_handle_key (lglw_int_t *lglw, lglw_bool_t _bPressed, uint32_t _vkey);
  120. // static lglw_bool_t loc_touchkeyboard_get_rect (RECT *rect);
  121. // static lglw_bool_t loc_touchkeyboard_is_visible (void);
  122. extern lglw_bool_t lglw_int_touchkeyboard_toggle (void);
  123. static void loc_handle_mouseleave (lglw_int_t *lglw);
  124. static void loc_handle_mouseenter (lglw_int_t *lglw);
  125. static void loc_handle_mousebutton (lglw_int_t *lglw, lglw_bool_t _bPressed, uint32_t _button);
  126. static void loc_handle_mousemotion (lglw_int_t *lglw);
  127. static void loc_handle_queued_mouse_warp (lglw_int_t *lglw);
  128. static void loc_touchinput_update (lglw_int_t *lglw);
  129. static void loc_enable_dropfiles (lglw_int_t *lglw, lglw_bool_t _bEnable);
  130. // ---------------------------------------------------------------------------- module vars
  131. static lglw_int_t *khook_lglw = NULL; // currently key-hooked lglw instance (one at a time)
  132. // TODO: remove and/or improve debug logging for a debug build
  133. // ---------------------------------------------------------------------------- lglw_log
  134. static FILE *logfile;
  135. void lglw_log(const char *logData, ...) {
  136. fprintf(logfile, logData);
  137. fflush(logfile);
  138. }
  139. // TODO: remove, or maybe not in some specific use cases
  140. // ---------------------------------------------------------------------------- xerror_log
  141. static int xerror_handler(Display *display, XErrorEvent *error) {
  142. char error_text[1024];
  143. XGetErrorText(display, error->error_code, error_text, 1024);
  144. lglw_log("XERROR (%d): %s, %d, %d\n", error->error_code, error_text, error->request_code, error->minor_code);
  145. return 0;
  146. }
  147. // ---------------------------------------------------------------------------- lglw_init
  148. lglw_t lglw_init(int32_t _w, int32_t _h) {
  149. lglw_int_t *lglw = malloc(sizeof(lglw_int_t));
  150. // TODO: remove/improve
  151. logfile = fopen("/home/cameron/src/VeeSeeVSTRack/other/log.txt", "w");
  152. XSetErrorHandler(xerror_handler);
  153. if(NULL != lglw)
  154. {
  155. memset(lglw, 0, sizeof(lglw_int_t));
  156. lglw_log("lglw:lglw_init: 1\n");
  157. if(_w <= 16)
  158. _w = LGLW_DEFAULT_HIDDEN_W;
  159. if(_h <= 16)
  160. _h = LGLW_DEFAULT_HIDDEN_H;
  161. lglw_log("lglw:lglw_init: 2\n");
  162. if(!loc_create_hidden_window(lglw, _w, _h))
  163. {
  164. free(lglw);
  165. lglw = NULL;
  166. }
  167. lglw_log("lglw:lglw_init: 3\n");
  168. }
  169. lglw_log("lglw:lglw_init: EXIT\n");
  170. return lglw;
  171. }
  172. // ---------------------------------------------------------------------------- lglw_exit
  173. void lglw_exit(lglw_t _lglw) {
  174. LGLW(_lglw);
  175. if(NULL != lglw)
  176. {
  177. lglw_log("lglw:lglw_exit: 1\n");
  178. loc_destroy_hidden_window(lglw);
  179. lglw_log("lglw:lglw_exit: 2\n");
  180. fclose(logfile);
  181. free(lglw);
  182. }
  183. }
  184. // ---------------------------------------------------------------------------- lglw_userdata_set
  185. void lglw_userdata_set(lglw_t _lglw, void *_userData) {
  186. LGLW(_lglw);
  187. if(NULL != lglw)
  188. {
  189. lglw_log("lglw:lglw_userdata_set: 1\n");
  190. lglw->user_data = _userData;
  191. }
  192. }
  193. // ---------------------------------------------------------------------------- lglw_userdata_get
  194. void *lglw_userdata_get(lglw_t _lglw) {
  195. LGLW(_lglw);
  196. if(NULL != lglw)
  197. {
  198. lglw_log("lglw:lglw_userdata_get: 1\n");
  199. return lglw->user_data;
  200. }
  201. return NULL;
  202. }
  203. // ---------------------------------------------------------------------------- loc_create_hidden_window
  204. static lglw_bool_t loc_create_hidden_window(lglw_int_t *lglw, int32_t _w, int32_t _h) {
  205. // TODO: compare to 'WindowClass' from Windows implementation
  206. lglw_log("lglw:loc_create_hidden_window: 1\n");
  207. XSetWindowAttributes swa;
  208. int attrib[] = { GLX_RGBA, GLX_DOUBLEBUFFER, GLX_DEPTH_SIZE, 24, None };
  209. int screen;
  210. lglw_log("lglw:loc_create_hidden_window: 2\n");
  211. lglw->xdsp = XOpenDisplay(NULL);
  212. screen = DefaultScreen(lglw->xdsp);
  213. lglw_log("lglw:loc_create_hidden_window: 3\n");
  214. lglw->vi = glXChooseVisual(lglw->xdsp, screen, attrib);
  215. lglw_log("lglw:loc_create_hidden_window: 4\n");
  216. if(NULL == lglw->vi)
  217. {
  218. lglw_log("[---] lglw: failed to find GLX Visual for hidden window\n");
  219. return LGLW_FALSE;
  220. }
  221. lglw_log("lglw:loc_create_hidden_window: 5\n");
  222. lglw->ctx = glXCreateContext(lglw->xdsp, lglw->vi, None, True);
  223. lglw_log("lglw:loc_create_hidden_window: 6\n");
  224. if(NULL == lglw->ctx)
  225. {
  226. lglw_log("[---] lglw: failed to create GLX Context for hidden window\n");
  227. return LGLW_FALSE;
  228. }
  229. lglw_log("lglw:loc_create_hidden_window: 7\n");
  230. lglw->cmap = XCreateColormap(lglw->xdsp, RootWindow(lglw->xdsp, lglw->vi->screen),
  231. lglw->vi->visual, AllocNone);
  232. lglw_log("lglw:loc_create_hidden_window: 8\n");
  233. swa.border_pixel = 0;
  234. swa.colormap = lglw->cmap;
  235. lglw->hidden.xwnd = XCreateWindow(lglw->xdsp, DefaultRootWindow(lglw->xdsp),
  236. 0, 0, LGLW_DEFAULT_HIDDEN_W, LGLW_DEFAULT_HIDDEN_H, 0, CopyFromParent, InputOutput,
  237. lglw->vi->visual, CWBorderPixel | CWColormap, &swa);
  238. lglw_log("lglw:loc_create_hidden_window: 9\n");
  239. XSetStandardProperties(lglw->xdsp, lglw->hidden.xwnd, "LGLW_hidden", "LGLW_hidden", None, NULL, 0, NULL);
  240. XSync(lglw->xdsp, False);
  241. lglw_log("lglw:loc_create_hidden_window: EXIT\n");
  242. lglw->hidden.size.x = _w;
  243. lglw->hidden.size.y = _h;
  244. return LGLW_TRUE;
  245. }
  246. // ---------------------------------------------------------------------------- loc_destroy_hidden_window
  247. static void loc_destroy_hidden_window(lglw_int_t *lglw) {
  248. lglw_log("lglw:loc_destroy_hidden_window: 1\n");
  249. if(NULL != lglw->xdsp && NULL != lglw->ctx)
  250. {
  251. glXMakeCurrent(lglw->xdsp, None, NULL);
  252. glXDestroyContext(lglw->xdsp, lglw->ctx);
  253. }
  254. lglw_log("lglw:loc_destroy_hidden_window: 2\n");
  255. if(NULL != lglw->xdsp && 0 != lglw->hidden.xwnd) XDestroyWindow(lglw->xdsp, lglw->hidden.xwnd);
  256. lglw_log("lglw:loc_destroy_hidden_window: 3\n");
  257. if(NULL != lglw->xdsp && 0 != lglw->cmap) XFreeColormap(lglw->xdsp, lglw->cmap);
  258. lglw_log("lglw:loc_destroy_hidden_window: 4\n");
  259. if(NULL != lglw->vi) XFree(lglw->vi);
  260. lglw_log("lglw:loc_destroy_hidden_window: 5\n");
  261. XSync(lglw->xdsp, False);
  262. if(NULL != lglw->xdsp) XCloseDisplay(lglw->xdsp);
  263. }
  264. // ---------------------------------------------------------------------------- lglw_window_open
  265. lglw_bool_t lglw_window_open (lglw_t _lglw, void *_parentHWNDOrNull, int32_t _x, int32_t _y, int32_t _w, int32_t _h) {
  266. lglw_bool_t r = LGLW_FALSE;
  267. LGLW(_lglw);
  268. if(NULL != lglw)
  269. {
  270. lglw_log("lglw:lglw_window_open: 1, %p, %i\n", (Window)_parentHWNDOrNull, (Window)_parentHWNDOrNull);
  271. lglw->parent_xwnd = (0 == _parentHWNDOrNull) ? DefaultRootWindow(lglw->xdsp) : (Window)_parentHWNDOrNull;
  272. lglw_log("lglw:lglw_window_open: 2\n");
  273. if(_w <= 16)
  274. _w = lglw->hidden.size.x;
  275. lglw_log("lglw:lglw_window_open: 3\n");
  276. if(_h <= 16)
  277. _h = lglw->hidden.size.y;
  278. // TODO: compare to 'WindowClass' from Windows implementation
  279. lglw_log("lglw:lglw_window_open: 4\n");
  280. XSetWindowAttributes swa;
  281. XEvent event;
  282. XSync(lglw->xdsp, False);
  283. lglw_log("lglw:lglw_window_open: 5\n");
  284. swa.border_pixel = 0;
  285. swa.colormap = lglw->cmap;
  286. swa.event_mask = EnterWindowMask | LeaveWindowMask;
  287. lglw->win.xwnd = XCreateWindow(lglw->xdsp, lglw->parent_xwnd,
  288. 0, 0, _w, _h, 0, CopyFromParent, InputOutput,
  289. lglw->vi->visual, CWBorderPixel | CWColormap | CWEventMask, &swa);
  290. lglw_log("lglw:lglw_window_open: 6\n");
  291. XSetStandardProperties(lglw->xdsp, lglw->win.xwnd, "LGLW", "LGLW", None, NULL, 0, NULL);
  292. lglw_log("lglw:lglw_window_open: 9\n");
  293. XMapRaised(lglw->xdsp, lglw->win.xwnd);
  294. XSync(lglw->xdsp, False);
  295. lglw->win.mapped = LGLW_TRUE;
  296. lglw_log("lglw:lglw_window_open: 10\n");
  297. lglw->win.size.x = _w;
  298. lglw->win.size.y = _h;
  299. lglw_log("lglw:lglw_window_open: 11\n");
  300. loc_enable_dropfiles(lglw, (NULL != lglw->dropfiles.cbk));
  301. lglw_log("lglw:lglw_window_open: EXIT\n");
  302. }
  303. return r;
  304. }
  305. // ---------------------------------------------------------------------------- lglw_window_resize
  306. lglw_bool_t lglw_window_resize (lglw_t _lglw, int32_t _w, int32_t _h) {
  307. lglw_bool_t r = LGLW_FALSE;
  308. LGLW(_lglw);
  309. if(NULL != lglw)
  310. {
  311. if(0 != lglw->win.xwnd)
  312. {
  313. lglw_log("lglw:lglw_window_resize: 1\n");
  314. r = LGLW_TRUE;
  315. lglw_log("lglw:lglw_window_resize: 2\n");
  316. XResizeWindow(lglw->xdsp, lglw->win.xwnd, _w, _h);
  317. XRaiseWindow(lglw->xdsp, lglw->win.xwnd);
  318. lglw_log("lglw:lglw_window_resize: 3\n");
  319. int deltaW = _w - lglw->win.size.x;
  320. int deltaH = _h - lglw->win.size.y;
  321. lglw_log("lglw:lglw_window_resize: 4\n");
  322. lglw->win.size.x = _w;
  323. lglw->win.size.y = _h;
  324. lglw_log("lglw:lglw_window_resize: 5\n");
  325. Window root, parent, *children = NULL;
  326. unsigned int num_children;
  327. lglw_log("lglw:lglw_window_resize: 6\n");
  328. if(!XQueryTree(lglw->xdsp, lglw->win.xwnd, &root, &parent, &children, &num_children))
  329. return r;
  330. lglw_log("lglw:lglw_window_resize: 7\n");
  331. if(children)
  332. XFree((char *)children);
  333. lglw_log("lglw:lglw_window_resize: 8\n");
  334. // Resize parent window (if any)
  335. if(0 != parent)
  336. {
  337. lglw_log("lglw:lglw_window_resize: 8.1\n");
  338. int x, y;
  339. unsigned int width, height;
  340. unsigned int border_width;
  341. unsigned int depth;
  342. lglw_log("lglw:lglw_window_resize: 8.2\n");
  343. if(!XGetGeometry(lglw->xdsp, lglw->win.xwnd, &root, &x, &y, &width, &height, &border_width, &depth))
  344. return r;
  345. lglw_log("lglw:lglw_window_resize: 8.3\n");
  346. XResizeWindow(lglw->xdsp, parent, width + deltaW, height + deltaH);
  347. }
  348. lglw_log("lglw:lglw_window_resize: EXIT\n");
  349. }
  350. }
  351. return r;
  352. }
  353. // ---------------------------------------------------------------------------- lglw_window_close
  354. void lglw_window_close (lglw_t _lglw) {
  355. LGLW(_lglw);
  356. if(NULL != lglw)
  357. {
  358. if(0 != lglw->win.xwnd)
  359. {
  360. lglw_log("lglw:lglw_window_close: 1\n");
  361. lglw_timer_stop(_lglw);
  362. lglw_log("lglw:lglw_window_close: 2\n");
  363. loc_key_unhook(lglw);
  364. lglw_log("lglw:lglw_window_close: 3\n");
  365. glXMakeCurrent(lglw->xdsp, None, NULL);
  366. lglw_log("lglw:lglw_window_close: 4\n");
  367. XDestroyWindow(lglw->xdsp, lglw->win.xwnd);
  368. XSync(lglw->xdsp, False);
  369. lglw->win.xwnd = 0;
  370. lglw->win.mapped = LGLW_FALSE;
  371. }
  372. }
  373. lglw_log("lglw:lglw_window_close: EXIT\n");
  374. }
  375. // ---------------------------------------------------------------------------- lglw_window_show
  376. void lglw_window_show(lglw_t _lglw) {
  377. LGLW(_lglw);
  378. if(NULL != lglw)
  379. {
  380. lglw_log("lglw:lglw_window_show: 1\n");
  381. XMapRaised(lglw->xdsp, lglw->win.xwnd);
  382. lglw->win.mapped = LGLW_TRUE;
  383. }
  384. lglw_log("lglw:lglw_window_show: EXIT\n");
  385. }
  386. // ---------------------------------------------------------------------------- lglw_window_hide
  387. void lglw_window_hide(lglw_t _lglw) {
  388. LGLW(_lglw);
  389. if(NULL != lglw)
  390. {
  391. lglw_log("lglw:lglw_window_hide: 1\n");
  392. XUnmapWindow(lglw->xdsp, lglw->win.xwnd);
  393. lglw->win.mapped = LGLW_FALSE;
  394. }
  395. lglw_log("lglw:lglw_window_hide: EXIT\n");
  396. }
  397. // ---------------------------------------------------------------------------- lglw_window_is_visible
  398. lglw_bool_t lglw_window_is_visible(lglw_t _lglw) {
  399. lglw_bool_t r = LGLW_FALSE;
  400. LGLW(_lglw);
  401. // lglw_log("lglw:lglw_window_is_visible: 1\n");
  402. if(NULL != lglw && 0 != lglw->win.xwnd)
  403. {
  404. // lglw_log("lglw:lglw_window_is_visible: 2\n");
  405. r = lglw->win.mapped;
  406. }
  407. // lglw_log("lglw:lglw_window_is_visible: EXIT\n");
  408. return r;
  409. }
  410. // ---------------------------------------------------------------------------- lglw_window_size_get
  411. void lglw_window_size_get(lglw_t _lglw, int32_t *_retX, int32_t *_retY) {
  412. LGLW(_lglw);
  413. lglw_log("lglw:lglw_window_size_get: 1\n");
  414. if(NULL != lglw)
  415. {
  416. if(0 != lglw->win.xwnd)
  417. {
  418. if(NULL != _retX)
  419. *_retX = lglw->win.size.x;
  420. if(NULL != _retY)
  421. *_retY = lglw->win.size.y;
  422. }
  423. }
  424. lglw_log("lglw:lglw_window_size_get: EXIT\n");
  425. }
  426. // ---------------------------------------------------------------------------- lglw_redraw
  427. void lglw_redraw(lglw_t _lglw) {
  428. LGLW(_lglw);
  429. // (todo) implement me
  430. if(NULL != lglw)
  431. {
  432. if(0 != lglw->win.xwnd)
  433. {
  434. // TODO Event Loop
  435. lglw_log("lglw:lglw_redraw: 1\n");
  436. XClearArea(lglw->xdsp, lglw->win.xwnd, 0, 0, 1, 1, True); // clear tiny area for exposing
  437. XFlush(lglw->xdsp);
  438. }
  439. }
  440. }
  441. // ---------------------------------------------------------------------------- lglw_redraw_callback_set
  442. void lglw_redraw_callback_set(lglw_t _lglw, lglw_redraw_fxn_t _cbk) {
  443. LGLW(_lglw);
  444. if(NULL != lglw)
  445. {
  446. lglw->redraw.cbk = _cbk;
  447. }
  448. }
  449. // ---------------------------------------------------------------------------- lglw_glcontext_push
  450. void lglw_glcontext_push(lglw_t _lglw) {
  451. LGLW(_lglw);
  452. if(NULL != lglw)
  453. {
  454. lglw->prev.drw = glXGetCurrentDrawable();
  455. lglw->prev.ctx = glXGetCurrentContext();
  456. // lglw_log("lglw:lglw_glcontext_push: win.xwnd=%p hidden.xwnd=%p ctx=%p\n",
  457. // lglw->win.xwnd, lglw->hidden.xwnd, lglw->ctx);
  458. if(!glXMakeCurrent(lglw->xdsp, (0 == lglw->win.xwnd) ? lglw->hidden.xwnd : lglw->win.xwnd, lglw->ctx))
  459. {
  460. 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());
  461. }
  462. }
  463. }
  464. // ---------------------------------------------------------------------------- lglw_glcontext_pop
  465. void lglw_glcontext_pop(lglw_t _lglw) {
  466. LGLW(_lglw);
  467. if(NULL != lglw)
  468. {
  469. // lglw_log("lglw:lglw_glcontext_pop: prev.drw=%p prev.ctx=%p\n",
  470. // lglw->prev.drw, lglw->prev.ctx);
  471. if(!glXMakeCurrent(lglw->xdsp, lglw->prev.drw, lglw->prev.ctx))
  472. {
  473. lglw_log("[---] lglw_glcontext_pop: glXMakeCurrent() failed. prev.drw=%p ctx=%p glGetError()=%d\n", lglw->prev.drw, lglw->prev.ctx, glGetError());
  474. }
  475. }
  476. }
  477. // ---------------------------------------------------------------------------- lglw_swap_buffers
  478. void lglw_swap_buffers(lglw_t _lglw) {
  479. LGLW(_lglw);
  480. if(NULL != lglw)
  481. {
  482. if(0 != lglw->win.xwnd)
  483. {
  484. // lglw_log("lglw:lglw_swap_buffers: 1\n");
  485. glXSwapBuffers(lglw->xdsp, lglw->win.xwnd);
  486. }
  487. }
  488. }
  489. // ---------------------------------------------------------------------------- lglw_swap_interval_set
  490. typedef void (APIENTRY *PFNWGLEXTSWAPINTERVALPROC) (int);
  491. void lglw_swap_interval_set(lglw_t _lglw, int32_t _ival) {
  492. LGLW(_lglw);
  493. if(NULL != lglw)
  494. {
  495. lglw_log("lglw:lglw_swap_interval_set: 1\n");
  496. PFNWGLEXTSWAPINTERVALPROC glXSwapIntervalEXT;
  497. glXSwapIntervalEXT = (PFNWGLEXTSWAPINTERVALPROC) glXGetProcAddress("glXSwapIntervalEXT");
  498. if(NULL != glXSwapIntervalEXT)
  499. {
  500. lglw_log("lglw:lglw_swap_interval_set: 2\n");
  501. glXSwapIntervalEXT(_ival);
  502. lglw->win.swap_interval = _ival;
  503. }
  504. }
  505. }
  506. // ---------------------------------------------------------------------------- lglw_swap_interval_get
  507. int32_t lglw_swap_interval_get(lglw_t _lglw) {
  508. LGLW(_lglw);
  509. int32_t r = 0;
  510. if(NULL != lglw)
  511. {
  512. r = lglw->win.swap_interval;
  513. }
  514. return r;
  515. }
  516. // ---------------------------------------------------------------------------- loc_key_hook
  517. static void loc_key_hook(lglw_int_t *lglw) {
  518. loc_key_unhook(lglw);
  519. // (todo) implement me
  520. khook_lglw = lglw;
  521. }
  522. // ---------------------------------------------------------------------------- loc_key_unhook
  523. static void loc_key_unhook(lglw_int_t *lglw) {
  524. // (todo) implement me
  525. if(khook_lglw == lglw)
  526. khook_lglw = NULL;
  527. }
  528. // ---------------------------------------------------------------------------- loc_handle_mouseleave
  529. static void loc_handle_mouseleave(lglw_int_t *lglw) {
  530. loc_key_unhook(lglw);
  531. lglw->focus.state &= ~LGLW_FOCUS_MOUSE;
  532. if(NULL != lglw->focus.cbk)
  533. {
  534. lglw->focus.cbk(lglw, lglw->focus.state, LGLW_FOCUS_MOUSE);
  535. }
  536. lglw_log("xxx lglw:loc_handle_mouseleave: LEAVE\n");
  537. }
  538. // ---------------------------------------------------------------------------- loc_handle_mouseenter
  539. static void loc_handle_mouseenter(lglw_int_t *lglw) {
  540. loc_key_hook(lglw);
  541. lglw->focus.state |= LGLW_FOCUS_MOUSE;
  542. if(NULL != lglw->focus.cbk)
  543. {
  544. lglw->focus.cbk(lglw, lglw->focus.state, LGLW_FOCUS_MOUSE);
  545. }
  546. lglw_log("xxx lglw:loc_handle_mouseenter: LEAVE\n");
  547. }
  548. // ---------------------------------------------------------------------------- loc_handle_mousebutton
  549. static void loc_handle_mousebutton(lglw_int_t *lglw, lglw_bool_t _bPressed, uint32_t _button) {
  550. if(_bPressed)
  551. lglw->mouse.button_state |= _button;
  552. else
  553. lglw->mouse.button_state &= ~_button;
  554. if(NULL != lglw->mouse.cbk)
  555. {
  556. lglw->mouse.cbk(lglw, lglw->mouse.p.x, lglw->mouse.p.y, lglw->mouse.button_state, _button);
  557. }
  558. }
  559. // ---------------------------------------------------------------------------- loc_handle_mousemotion
  560. static void loc_handle_mousemotion(lglw_int_t *lglw) {
  561. if(NULL != lglw->mouse.cbk)
  562. {
  563. lglw->mouse.cbk(lglw, lglw->mouse.p.x, lglw->mouse.p.y, lglw->mouse.button_state, 0u/*changedbuttonstate*/);
  564. }
  565. }
  566. // ---------------------------------------------------------------------------- lglw_mouse_callback_set
  567. void lglw_mouse_callback_set(lglw_t _lglw, lglw_mouse_fxn_t _cbk) {
  568. LGLW(_lglw);
  569. if(NULL != lglw)
  570. {
  571. lglw->mouse.cbk = _cbk;
  572. }
  573. }
  574. // ---------------------------------------------------------------------------- lglw_mouse_callback_set
  575. void lglw_focus_callback_set(lglw_t _lglw, lglw_focus_fxn_t _cbk) {
  576. LGLW(_lglw);
  577. if(NULL != lglw)
  578. {
  579. lglw->focus.cbk = _cbk;
  580. }
  581. }
  582. // ---------------------------------------------------------------------------- loc_handle_key
  583. static lglw_bool_t loc_handle_key(lglw_int_t *lglw, lglw_bool_t _bPressed, uint32_t _vkey) {
  584. lglw_bool_t r = LGLW_FALSE;
  585. if(NULL != lglw->keyboard.cbk)
  586. {
  587. r = lglw->keyboard.cbk(lglw, _vkey, lglw->keyboard.kmod_state, _bPressed);
  588. }
  589. return r;
  590. }
  591. // ---------------------------------------------------------------------------- lglw_keyboard_callback_set
  592. void lglw_keyboard_callback_set(lglw_t _lglw, lglw_keyboard_fxn_t _cbk) {
  593. LGLW(_lglw);
  594. if(NULL != lglw)
  595. {
  596. lglw->keyboard.cbk = _cbk;
  597. }
  598. }
  599. // ---------------------------------------------------------------------------- lglw_keyboard_get_modifiers
  600. uint32_t lglw_keyboard_get_modifiers(lglw_t _lglw) {
  601. uint32_t r = 0u;
  602. LGLW(_lglw);
  603. if(NULL != lglw)
  604. {
  605. r = lglw->keyboard.kmod_state;
  606. }
  607. return r;
  608. }
  609. // ---------------------------------------------------------------------------- lglw_touchkeyboard_show
  610. void lglw_touchkeyboard_show(lglw_t _lglw, lglw_bool_t _bEnable) {
  611. LGLW(_lglw);
  612. // (todo) implement me
  613. if(NULL != lglw)
  614. {
  615. }
  616. }
  617. // ---------------------------------------------------------------------------- lglw_mouse_get_buttons
  618. uint32_t lglw_mouse_get_buttons(lglw_t _lglw) {
  619. uint32_t r = 0u;
  620. LGLW(_lglw);
  621. if(NULL != lglw)
  622. {
  623. r = lglw->mouse.button_state;
  624. }
  625. return r;
  626. }
  627. // ---------------------------------------------------------------------------- lglw_mouse_grab
  628. void lglw_mouse_grab(lglw_t _lglw, uint32_t _grabMode) {
  629. LGLW(_lglw);
  630. if(NULL != lglw)
  631. {
  632. // (todo) implement me
  633. // if(NULL != lglw->win.hwnd)
  634. {
  635. if(!lglw->mouse.touch.b_enable)
  636. {
  637. if(lglw->mouse.grab.mode != _grabMode)
  638. {
  639. lglw_mouse_ungrab(_lglw);
  640. }
  641. switch(_grabMode)
  642. {
  643. default:
  644. case LGLW_MOUSE_GRAB_NONE:
  645. break;
  646. case LGLW_MOUSE_GRAB_CAPTURE:
  647. // (todo) implement me
  648. // (void)SetCapture(lglw->win.hwnd);
  649. lglw->mouse.grab.mode = _grabMode;
  650. break;
  651. case LGLW_MOUSE_GRAB_WARP:
  652. // (todo) implement me
  653. // (void)SetCapture(lglw->win.hwnd);
  654. lglw_mouse_cursor_show(_lglw, LGLW_FALSE);
  655. lglw->mouse.grab.p = lglw->mouse.p;
  656. lglw->mouse.grab.last_p = lglw->mouse.p;
  657. lglw->mouse.grab.mode = _grabMode;
  658. break;
  659. }
  660. }
  661. }
  662. }
  663. }
  664. // ---------------------------------------------------------------------------- lglw_mouse_ungrab
  665. void lglw_mouse_ungrab(lglw_t _lglw) {
  666. LGLW(_lglw);
  667. if(NULL != lglw)
  668. {
  669. // (todo) implement me
  670. // if(NULL != lglw->win.hwnd)
  671. {
  672. if(!lglw->mouse.touch.b_enable)
  673. {
  674. switch(lglw->mouse.grab.mode)
  675. {
  676. default:
  677. case LGLW_MOUSE_GRAB_NONE:
  678. break;
  679. case LGLW_MOUSE_GRAB_CAPTURE:
  680. // (todo) implement me
  681. // (void)ReleaseCapture();
  682. lglw->mouse.grab.mode = LGLW_MOUSE_GRAB_NONE;
  683. break;
  684. case LGLW_MOUSE_GRAB_WARP:
  685. // (todo) implement me
  686. // (void)ReleaseCapture();
  687. lglw->mouse.grab.mode = LGLW_MOUSE_GRAB_NONE;
  688. lglw->mouse.grab.b_queue_warp = LGLW_TRUE;
  689. lglw_mouse_cursor_show(_lglw, LGLW_TRUE);
  690. break;
  691. }
  692. }
  693. }
  694. }
  695. }
  696. // ---------------------------------------------------------------------------- lglw_mouse_warp
  697. void lglw_mouse_warp(lglw_t _lglw, int32_t _x, int32_t _y) {
  698. LGLW(_lglw);
  699. // (todo) implement me
  700. if(NULL != lglw)
  701. {
  702. }
  703. }
  704. // ---------------------------------------------------------------------------- loc_handle_queued_mouse_warp
  705. static void loc_handle_queued_mouse_warp(lglw_int_t *lglw) {
  706. if(lglw->mouse.grab.b_queue_warp)
  707. {
  708. lglw->mouse.grab.b_queue_warp = LGLW_FALSE;
  709. lglw_mouse_warp(lglw, lglw->mouse.grab.p.x, lglw->mouse.grab.p.y);
  710. lglw->mouse.grab.last_p = lglw->mouse.grab.p;
  711. }
  712. }
  713. // ---------------------------------------------------------------------------- lglw_mouse_cursor_show
  714. void lglw_mouse_cursor_show (lglw_t _lglw, lglw_bool_t _bShow) {
  715. LGLW(_lglw);
  716. // (todo) implement me
  717. if(NULL != lglw)
  718. {
  719. }
  720. }
  721. // ---------------------------------------------------------------------------- lglw_timer_start
  722. void lglw_timer_start(lglw_t _lglw, uint32_t _millisec) {
  723. LGLW(_lglw);
  724. // (todo) implement me
  725. if(NULL != lglw)
  726. {
  727. }
  728. }
  729. // ---------------------------------------------------------------------------- lglw_timer_stop
  730. void lglw_timer_stop(lglw_t _lglw) {
  731. LGLW(_lglw);
  732. // (todo) implement me
  733. if(NULL != lglw)
  734. {
  735. }
  736. }
  737. // ---------------------------------------------------------------------------- lglw_timer_callback_set
  738. void lglw_timer_callback_set(lglw_t _lglw, lglw_timer_fxn_t _cbk) {
  739. LGLW(_lglw);
  740. if(NULL != lglw)
  741. {
  742. lglw->timer.cbk = _cbk;
  743. }
  744. }
  745. // ---------------------------------------------------------------------------- loc_enable_dropfiles
  746. static void loc_enable_dropfiles(lglw_int_t *lglw, lglw_bool_t _bEnable) {
  747. // (todo) implement me
  748. }
  749. // ---------------------------------------------------------------------------- lglw_dropfiles_callback_set
  750. void lglw_dropfiles_callback_set(lglw_t _lglw, lglw_dropfiles_fxn_t _cbk) {
  751. LGLW(_lglw);
  752. if(NULL != _lglw)
  753. {
  754. lglw->dropfiles.cbk = _cbk;
  755. loc_enable_dropfiles(lglw, (NULL != _cbk));
  756. }
  757. }
  758. // ---------------------------------------------------------------------------- loc_touchinput_update
  759. static void loc_touchinput_update(lglw_int_t *lglw) {
  760. // (todo) implement me
  761. }
  762. // ---------------------------------------------------------------------------- lglw_touchinput_set
  763. void lglw_touchinput_set(lglw_t _lglw, lglw_bool_t _bEnable) {
  764. LGLW(_lglw);
  765. if(NULL != _lglw)
  766. {
  767. lglw->mouse.touch.b_enable = _bEnable;
  768. lglw->mouse.touch.b_update_queued = LGLW_TRUE;
  769. }
  770. }
  771. // ---------------------------------------------------------------------------- lglw_touchinput_get
  772. lglw_bool_t lglw_touchinput_get(lglw_t _lglw) {
  773. lglw_bool_t r = LGLW_FALSE;
  774. LGLW(_lglw);
  775. if(NULL != _lglw)
  776. {
  777. r = lglw->mouse.touch.b_enable;
  778. }
  779. return r;
  780. }
  781. // ---------------------------------------------------------------------------- lglw_clipboard_text_set
  782. void lglw_clipboard_text_set(lglw_t _lglw, const uint32_t _numChars, const char *_text) {
  783. LGLW(_lglw);
  784. (void)_numChars;
  785. // (todo) implement me
  786. if(NULL != _text)
  787. {
  788. }
  789. }
  790. // ---------------------------------------------------------------------------- lglw_clipboard_text_get
  791. void lglw_clipboard_text_get(lglw_t _lglw, uint32_t _maxChars, uint32_t *_retNumChars, char *_retText) {
  792. LGLW(_lglw);
  793. if(NULL != _retNumChars)
  794. *_retNumChars = 0u;
  795. if(NULL != _retText)
  796. *_retText = 0;
  797. if(_maxChars > 0u)
  798. {
  799. if(NULL != _lglw)
  800. {
  801. // (todo) implement me
  802. }
  803. }
  804. }