µGFX library fork

gdisp_lld_X.c 15KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529
  1. /*
  2. * This file is subject to the terms of the GFX License. If a copy of
  3. * the license was not distributed with this file, you can obtain one at:
  4. *
  5. * http://ugfx.org/license.html
  6. */
  7. // We need to include stdio.h below. Turn off GFILE_NEED_STDIO just for this file to prevent conflicts
  8. #define GFILE_NEED_STDIO_MUST_BE_OFF
  9. #include "gfx.h"
  10. #if GFX_USE_GDISP
  11. #include <X11/Xlib.h>
  12. #include <X11/Xutil.h>
  13. #include <X11/Xresource.h>
  14. #include <stdio.h>
  15. #include <stdlib.h>
  16. #define GDISP_DRIVER_VMT GDISPVMT_X11
  17. #include "gdisp_lld_config.h"
  18. #include "../../../src/gdisp/gdisp_driver.h"
  19. // Configuration parameters for this driver
  20. #ifndef GDISP_FORCE_24BIT
  21. #define GDISP_FORCE_24BIT FALSE
  22. #endif
  23. #ifndef GDISP_SCREEN_WIDTH
  24. #define GDISP_SCREEN_WIDTH 640
  25. #endif
  26. #ifndef GDISP_SCREEN_HEIGHT
  27. #define GDISP_SCREEN_HEIGHT 480
  28. #endif
  29. #ifndef GKEYBOARD_X_NO_LAYOUT
  30. /**
  31. * Setting this to TRUE turns off the layout engine.
  32. * In this situation "cooked" characters are returned but
  33. * shift states etc are lost.
  34. * As only a limited number of keyboard layouts are currently
  35. * defined for X in uGFX (currently none), setting this
  36. * to TRUE enables the X keyboard mapping to be pass non-English
  37. * characters to uGFX or to handle non-standard keyboard layouts at
  38. * the expense of losing special function keys etc.
  39. */
  40. // We set this to TRUE by default as currently the X layout code is not complete!
  41. #define GKEYBOARD_X_NO_LAYOUT TRUE
  42. #endif
  43. #ifndef GKEYBOARD_X_DEFAULT_LAYOUT
  44. #define GKEYBOARD_X_DEFAULT_LAYOUT KeyboardLayout_X_US
  45. #endif
  46. // Driver status flags
  47. #define GDISP_FLG_READY (GDISP_FLG_DRIVER<<0)
  48. #if GINPUT_NEED_MOUSE
  49. // Include mouse support code
  50. #define GMOUSE_DRIVER_VMT GMOUSEVMT_X11
  51. #include "../../../src/ginput/ginput_driver_mouse.h"
  52. // Forward definitions
  53. static bool_t XMouseInit(GMouse *m, unsigned driverinstance);
  54. static bool_t XMouseRead(GMouse *m, GMouseReading *prd);
  55. const GMouseVMT const GMOUSE_DRIVER_VMT[1] = {{
  56. {
  57. GDRIVER_TYPE_MOUSE,
  58. GMOUSE_VFLG_NOPOLL|GMOUSE_VFLG_DYNAMICONLY,
  59. // Extra flags for testing only
  60. //GMOUSE_VFLG_TOUCH|GMOUSE_VFLG_SELFROTATION|GMOUSE_VFLG_DEFAULTFINGER
  61. //GMOUSE_VFLG_CALIBRATE|GMOUSE_VFLG_CAL_EXTREMES|GMOUSE_VFLG_CAL_TEST|GMOUSE_VFLG_CAL_LOADFREE
  62. //GMOUSE_VFLG_ONLY_DOWN|GMOUSE_VFLG_POORUPDOWN
  63. sizeof(GMouse),
  64. _gmouseInitDriver, _gmousePostInitDriver, _gmouseDeInitDriver
  65. },
  66. 1, // z_max
  67. 0, // z_min
  68. 1, // z_touchon
  69. 0, // z_touchoff
  70. { // pen_jitter
  71. 0, // calibrate
  72. 0, // click
  73. 0 // move
  74. },
  75. { // finger_jitter
  76. 0, // calibrate
  77. 2, // click
  78. 2 // move
  79. },
  80. XMouseInit, // init
  81. 0, // deinit
  82. XMouseRead, // get
  83. 0, // calsave
  84. 0 // calload
  85. }};
  86. #endif
  87. #if GINPUT_NEED_KEYBOARD
  88. // Include mouse support code
  89. #define GKEYBOARD_DRIVER_VMT GKEYBOARDVMT_X
  90. #include "../../../src/ginput/ginput_driver_keyboard.h"
  91. #if !GKEYBOARD_X_NO_LAYOUT
  92. #if GKEYBOARD_LAYOUT_OFF
  93. #error "The X keyboard driver is using the layout engine. Please set GKEYBOARD_LAYOUT_OFF=FALSE or GKEYBOARD_X_NO_LAYOUT=TRUE."
  94. #endif
  95. // Forward definitions
  96. extern uint8_t GKEYBOARD_X_DEFAULT_LAYOUT[];
  97. #include "../../../src/ginput/ginput_keyboard_microcode.h"
  98. #include <X11/keysym.h>
  99. // This is the layout code for the English US keyboard.
  100. // We make it public so that a user can switch to a different layout if required.
  101. uint8_t KeyboardLayout_X_US[] = {
  102. KMC_HEADERSTART, KMC_HEADER_ID1, KMC_HEADER_ID2, KMC_HEADER_VER_1,
  103. // TODO
  104. #error "The code to do keyboard layouts in X is not complete."
  105. // Transient Shifters: SHIFT, CTRL, ALT, WINKEY
  106. // Locking Shifters: CAPSLOCK, NUMLOCK and SCROLLLOCK
  107. // Keyup, Repeat
  108. // 0 - 9
  109. // A - Z
  110. // Number pad
  111. // Symbols
  112. // Special Keys
  113. // Anything else
  114. // EOF
  115. KMC_RECORDSTART, 0
  116. };
  117. #elif !GKEYBOARD_LAYOUT_OFF
  118. #if GFX_COMPILER_WARNING_TYPE == GFX_COMPILER_WARNING_DIRECT
  119. #warning "The X keyboard driver is not using the layout engine. If no other keyboard is using it consider defining GKEYBOARD_LAYOUT_OFF=TRUE to save code size."
  120. #elif GFX_COMPILER_WARNING_TYPE == GFX_COMPILER_WARNING_MACRO
  121. COMPILER_WARNING("The X keyboard driver is not using the layout engine. If no other keyboard is using it consider defining GKEYBOARD_LAYOUT_OFF=TRUE to save code size.")
  122. #endif
  123. #endif
  124. // Forward definitions
  125. static bool_t XKeyboardInit(GKeyboard *k, unsigned driverinstance);
  126. static int XKeyboardGetData(GKeyboard *k, uint8_t *pch, int sz);
  127. const GKeyboardVMT const GKEYBOARD_DRIVER_VMT[1] = {{
  128. {
  129. GDRIVER_TYPE_KEYBOARD,
  130. GKEYBOARD_VFLG_NOPOLL, // GKEYBOARD_VFLG_DYNAMICONLY
  131. sizeof(GKeyboard),
  132. _gkeyboardInitDriver, _gkeyboardPostInitDriver, _gkeyboardDeInitDriver
  133. },
  134. // The default keyboard layout
  135. #if GKEYBOARD_X_NO_LAYOUT
  136. 0,
  137. #else
  138. GKEYBOARD_X_DEFAULT_LAYOUT,
  139. #endif
  140. XKeyboardInit, // init
  141. 0, // deinit
  142. XKeyboardGetData, // getdata
  143. 0 // putdata void (*putdata)(GKeyboard *k, char ch); Optional
  144. }};
  145. static int keypos;
  146. static uint8_t keybuffer[8];
  147. static GKeyboard *keyboard;
  148. #endif
  149. static bool_t initdone;
  150. static Display *dis;
  151. static int scr;
  152. static XEvent evt;
  153. static Colormap cmap;
  154. static XVisualInfo vis;
  155. static XContext cxt;
  156. static Atom wmDelete;
  157. typedef struct xPriv {
  158. Pixmap pix;
  159. GC gc;
  160. Window win;
  161. #if GINPUT_NEED_MOUSE
  162. coord_t mousex, mousey;
  163. uint16_t buttons;
  164. GMouse * mouse;
  165. #endif
  166. } xPriv;
  167. static void ProcessEvent(GDisplay *g, xPriv *priv) {
  168. switch(evt.type) {
  169. case MapNotify:
  170. XSelectInput(dis, evt.xmap.window,
  171. StructureNotifyMask|ExposureMask|ButtonPressMask|ButtonReleaseMask|PointerMotionMask|KeyPressMask|KeyReleaseMask|KeymapStateMask);
  172. g->flags |= GDISP_FLG_READY;
  173. break;
  174. case UnmapNotify:
  175. XCloseDisplay(dis);
  176. exit(0);
  177. break;
  178. case ClientMessage:
  179. if ((Atom)evt.xclient.data.l[0] == wmDelete) {
  180. XCloseDisplay(dis);
  181. exit(0);
  182. }
  183. break;
  184. case Expose:
  185. XCopyArea(dis, priv->pix, evt.xexpose.window, priv->gc,
  186. evt.xexpose.x, evt.xexpose.y,
  187. evt.xexpose.width, evt.xexpose.height,
  188. evt.xexpose.x, evt.xexpose.y);
  189. break;
  190. #if GINPUT_NEED_MOUSE
  191. case ButtonPress:
  192. priv->mousex = evt.xbutton.x;
  193. priv->mousey = evt.xbutton.y;
  194. switch(evt.xbutton.button){
  195. case 1: priv->buttons |= GINPUT_MOUSE_BTN_LEFT; break;
  196. case 2: priv->buttons |= GINPUT_MOUSE_BTN_MIDDLE; break;
  197. case 3: priv->buttons |= GINPUT_MOUSE_BTN_RIGHT; break;
  198. case 4: priv->buttons |= GINPUT_MOUSE_BTN_4; break;
  199. }
  200. _gmouseWakeup(priv->mouse);
  201. break;
  202. case ButtonRelease:
  203. priv->mousex = evt.xbutton.x;
  204. priv->mousey = evt.xbutton.y;
  205. switch(evt.xbutton.button){
  206. case 1: priv->buttons &= ~GINPUT_MOUSE_BTN_LEFT; break;
  207. case 2: priv->buttons &= ~GINPUT_MOUSE_BTN_MIDDLE; break;
  208. case 3: priv->buttons &= ~GINPUT_MOUSE_BTN_RIGHT; break;
  209. case 4: priv->buttons &= ~GINPUT_MOUSE_BTN_4; break;
  210. }
  211. _gmouseWakeup(priv->mouse);
  212. break;
  213. case MotionNotify:
  214. priv->mousex = evt.xmotion.x;
  215. priv->mousey = evt.xmotion.y;
  216. _gmouseWakeup(priv->mouse);
  217. break;
  218. #endif
  219. #if GINPUT_NEED_KEYBOARD
  220. case KeymapNotify:
  221. XRefreshKeyboardMapping(&evt.xmapping);
  222. break;
  223. case KeyPress:
  224. #if !GKEYBOARD_X_NO_LAYOUT
  225. // TODO
  226. #error "The code to do keyboard layouts in X is not complete."
  227. #endif
  228. /* ignore these when there is no layout engine */
  229. break;
  230. case KeyRelease:
  231. #if !GKEYBOARD_X_NO_LAYOUT
  232. // TODO
  233. #error "The code to do keyboard layouts in X is not complete."
  234. #endif
  235. if (keyboard && !keyboard->pLayout && keypos < (int)sizeof(keybuffer)) {
  236. int len;
  237. len = XLookupString(&evt.xkey, (char *)(keybuffer+keypos), sizeof(keybuffer)-keypos, /*&keysym*/0, NULL);
  238. if (len > 0) {
  239. keypos += len;
  240. _gkeyboardWakeup(keyboard);
  241. }
  242. }
  243. break;
  244. #endif
  245. }
  246. }
  247. /* this is the X11 thread which keeps track of all events */
  248. static DECLARE_THREAD_STACK(waXThread, 1024);
  249. static DECLARE_THREAD_FUNCTION(ThreadX, arg) {
  250. GDisplay *g;
  251. (void)arg;
  252. while(1) {
  253. gfxSleepMilliseconds(100);
  254. while(XPending(dis)) {
  255. XNextEvent(dis, &evt);
  256. XFindContext(evt.xany.display, evt.xany.window, cxt, (XPointer*)&g);
  257. ProcessEvent(g, (xPriv *)g->priv);
  258. }
  259. }
  260. return 0;
  261. }
  262. static int FatalXIOError(Display *d) {
  263. (void) d;
  264. /* The window has closed */
  265. fprintf(stderr, "GFX Window closed!\n");
  266. exit(0);
  267. }
  268. LLDSPEC bool_t gdisp_lld_init(GDisplay *g) {
  269. XSizeHints *pSH;
  270. XSetWindowAttributes xa;
  271. XTextProperty WindowTitle;
  272. char * WindowTitleText;
  273. xPriv *priv;
  274. if (!initdone) {
  275. gfxThreadHandle hth;
  276. initdone = TRUE;
  277. #if GFX_USE_OS_LINUX || GFX_USE_OS_OSX
  278. XInitThreads();
  279. #endif
  280. dis = XOpenDisplay(0);
  281. scr = DefaultScreen(dis);
  282. cxt = XUniqueContext();
  283. wmDelete = XInternAtom(dis, "WM_DELETE_WINDOW", False);
  284. XSetIOErrorHandler(FatalXIOError);
  285. #if GDISP_FORCE_24BIT
  286. if (!XMatchVisualInfo(dis, scr, 24, TrueColor, &vis)) {
  287. fprintf(stderr, "Your display has no TrueColor mode\n");
  288. XCloseDisplay(dis);
  289. return FALSE;
  290. }
  291. cmap = XCreateColormap(dis, RootWindow(dis, scr),
  292. vis.visual, AllocNone);
  293. #else
  294. vis.visual = CopyFromParent;
  295. vis.depth = DefaultDepth(dis, scr);
  296. cmap = DefaultColormap(dis, scr);
  297. #endif
  298. fprintf(stderr, "Running GFX Window in %d bit color\n", vis.depth);
  299. if (!(hth = gfxThreadCreate(waXThread, sizeof(waXThread), HIGH_PRIORITY, ThreadX, 0))) {
  300. fprintf(stderr, "Cannot start X Thread\n");
  301. XCloseDisplay(dis);
  302. exit(0);
  303. }
  304. #if GFX_USE_OS_LINUX || GFX_USE_OS_OSX
  305. pthread_detach(hth);
  306. #endif
  307. gfxThreadClose(hth);
  308. }
  309. g->priv = gfxAlloc(sizeof(xPriv));
  310. priv = (xPriv *)g->priv;
  311. g->board = 0; // No board interface for this driver
  312. xa.colormap = cmap;
  313. xa.border_pixel = 0xFFFFFF;
  314. xa.background_pixel = 0x000000;
  315. priv->win = XCreateWindow(dis, RootWindow(dis, scr), 16, 16,
  316. GDISP_SCREEN_WIDTH, GDISP_SCREEN_HEIGHT,
  317. 0, vis.depth, InputOutput, vis.visual,
  318. CWBackPixel|CWColormap|CWBorderPixel, &xa);
  319. XSync(dis, TRUE);
  320. XSaveContext(dis, priv->win, cxt, (XPointer)g);
  321. XSetWMProtocols(dis, priv->win, &wmDelete, 1);
  322. {
  323. char buf[132];
  324. sprintf(buf, "uGFX - %u", g->systemdisplay+1);
  325. WindowTitleText = buf;
  326. XStringListToTextProperty(&WindowTitleText, 1, &WindowTitle);
  327. XSetWMName(dis, priv->win, &WindowTitle);
  328. XSetWMIconName(dis, priv->win, &WindowTitle);
  329. XSync(dis, TRUE);
  330. }
  331. pSH = XAllocSizeHints();
  332. pSH->flags = PSize | PMinSize | PMaxSize;
  333. pSH->min_width = pSH->max_width = pSH->base_width = GDISP_SCREEN_WIDTH;
  334. pSH->min_height = pSH->max_height = pSH->base_height = GDISP_SCREEN_HEIGHT;
  335. XSetWMNormalHints(dis, priv->win, pSH);
  336. XFree(pSH);
  337. XSync(dis, TRUE);
  338. priv->pix = XCreatePixmap(dis, priv->win,
  339. GDISP_SCREEN_WIDTH, GDISP_SCREEN_HEIGHT, vis.depth);
  340. XSync(dis, TRUE);
  341. priv->gc = XCreateGC(dis, priv->win, 0, 0);
  342. XSetBackground(dis, priv->gc, BlackPixel(dis, scr));
  343. XSync(dis, TRUE);
  344. // Create the associated mouse before the map
  345. #if GINPUT_NEED_MOUSE
  346. priv->mouse = (GMouse *)gdriverRegister((const GDriverVMT const *)GMOUSE_DRIVER_VMT, g);
  347. #endif
  348. XSelectInput(dis, priv->win, StructureNotifyMask);
  349. XMapWindow(dis, priv->win);
  350. // Wait for the window creation to complete (for safety)
  351. while(!(((volatile GDisplay *)g)->flags & GDISP_FLG_READY))
  352. gfxSleepMilliseconds(100);
  353. /* Initialise the GDISP structure to match */
  354. g->g.Orientation = GDISP_ROTATE_0;
  355. g->g.Powermode = powerOn;
  356. g->g.Backlight = 100;
  357. g->g.Contrast = 50;
  358. g->g.Width = GDISP_SCREEN_WIDTH;
  359. g->g.Height = GDISP_SCREEN_HEIGHT;
  360. return TRUE;
  361. }
  362. LLDSPEC void gdisp_lld_draw_pixel(GDisplay *g)
  363. {
  364. xPriv * priv = (xPriv *)g->priv;
  365. XColor col;
  366. col.red = RED_OF(g->p.color) << 8;
  367. col.green = GREEN_OF(g->p.color) << 8;
  368. col.blue = BLUE_OF(g->p.color) << 8;
  369. XAllocColor(dis, cmap, &col);
  370. XSetForeground(dis, priv->gc, col.pixel);
  371. XDrawPoint(dis, priv->pix, priv->gc, (int)g->p.x, (int)g->p.y );
  372. XDrawPoint(dis, priv->win, priv->gc, (int)g->p.x, (int)g->p.y );
  373. XFlush(dis);
  374. }
  375. #if GDISP_HARDWARE_FILLS
  376. LLDSPEC void gdisp_lld_fill_area(GDisplay *g) {
  377. xPriv * priv = (xPriv *)g->priv;
  378. XColor col;
  379. col.red = RED_OF(g->p.color) << 8;
  380. col.green = GREEN_OF(g->p.color) << 8;
  381. col.blue = BLUE_OF(g->p.color) << 8;
  382. XAllocColor(dis, cmap, &col);
  383. XSetForeground(dis, priv->gc, col.pixel);
  384. XFillRectangle(dis, priv->pix, priv->gc, g->p.x, g->p.y, g->p.cx, g->p.cy);
  385. XFillRectangle(dis, priv->win, priv->gc, g->p.x, g->p.y, g->p.cx, g->p.cy);
  386. XFlush(dis);
  387. }
  388. #endif
  389. #if 0 && GDISP_HARDWARE_BITFILLS
  390. LLDSPEC void gdisp_lld_blit_area(GDisplay *g) {
  391. // Start of Bitblit code
  392. //XImage bitmap;
  393. //pixel_t *bits;
  394. // bits = malloc(vis.depth * GDISP_SCREEN_WIDTH * GDISP_SCREEN_HEIGHT);
  395. // bitmap = XCreateImage(dis, vis, vis.depth, ZPixmap,
  396. // 0, bits, GDISP_SCREEN_WIDTH, GDISP_SCREEN_HEIGHT,
  397. // 0, 0);
  398. }
  399. #endif
  400. #if GDISP_HARDWARE_PIXELREAD
  401. LLDSPEC color_t gdisp_lld_get_pixel_color(GDisplay *g) {
  402. xPriv * priv = (xPriv *)g->priv;
  403. XColor color;
  404. XImage *img;
  405. img = XGetImage (dis, priv->pix, g->p.x, g->p.y, 1, 1, AllPlanes, XYPixmap);
  406. color.pixel = XGetPixel (img, 0, 0);
  407. XFree(img);
  408. XQueryColor(dis, cmap, &color);
  409. return RGB2COLOR(color.red>>8, color.green>>8, color.blue>>8);
  410. }
  411. #endif
  412. #if GDISP_NEED_SCROLL && GDISP_HARDWARE_SCROLL
  413. LLDSPEC void gdisp_lld_vertical_scroll(GDisplay *g) {
  414. xPriv * priv = (xPriv *)g->priv;
  415. if (g->p.y1 > 0) {
  416. XCopyArea(dis, priv->pix, priv->pix, priv->gc, g->p.x, g->p.y+g->p.y1, g->p.cx, g->p.cy-g->p.y1, g->p.x, g->p.y);
  417. XCopyArea(dis, priv->pix, priv->win, priv->gc, g->p.x, g->p.y, g->p.cx, g->p.cy-g->p.y1, g->p.x, g->p.y);
  418. } else {
  419. XCopyArea(dis, priv->pix, priv->pix, priv->gc, g->p.x, g->p.y, g->p.cx, g->p.cy+g->p.y1, g->p.x, g->p.y-g->p.y1);
  420. XCopyArea(dis, priv->pix, priv->win, priv->gc, g->p.x, g->p.y-g->p.y1, g->p.cx, g->p.cy+g->p.y1, g->p.x, g->p.y-g->p.y1);
  421. }
  422. }
  423. #endif
  424. #if GINPUT_NEED_MOUSE
  425. static bool_t XMouseInit(GMouse *m, unsigned driverinstance) {
  426. (void) m;
  427. (void) driverinstance;
  428. return TRUE;
  429. }
  430. static bool_t XMouseRead(GMouse *m, GMouseReading *pt) {
  431. xPriv * priv;
  432. priv = m->display->priv;
  433. pt->x = priv->mousex;
  434. pt->y = priv->mousey;
  435. pt->z = (priv->buttons & GINPUT_MOUSE_BTN_LEFT) ? 1 : 0;
  436. pt->buttons = priv->buttons;
  437. return TRUE;
  438. }
  439. #endif /* GINPUT_NEED_MOUSE */
  440. #if GINPUT_NEED_KEYBOARD
  441. static bool_t XKeyboardInit(GKeyboard *k, unsigned driverinstance) {
  442. (void) driverinstance;
  443. // Only one please
  444. if (keyboard)
  445. return FALSE;
  446. keyboard = k;
  447. return TRUE;
  448. }
  449. static int XKeyboardGetData(GKeyboard *k, uint8_t *pch, int sz) {
  450. int i, j;
  451. (void) k;
  452. if (!keypos)
  453. return 0;
  454. for(i = 0; i < keypos && i < sz; i++)
  455. pch[i] = keybuffer[i];
  456. keypos -= i;
  457. for(j=0; j < keypos; j++)
  458. keybuffer[j] = keybuffer[i+j];
  459. return i;
  460. }
  461. #endif /* GINPUT_NEED_KEYBOARD */
  462. #endif /* GFX_USE_GDISP */