ui_x11.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  1. /*
  2. * sfnedit/ui_x11.c
  3. *
  4. * Copyright (C) 2019 bzt (bztsrc@gitlab)
  5. *
  6. * Permission is hereby granted, free of charge, to any person
  7. * obtaining a copy of this software and associated documentation
  8. * files (the "Software"), to deal in the Software without
  9. * restriction, including without limitation the rights to use, copy,
  10. * modify, merge, publish, distribute, sublicense, and/or sell copies
  11. * of the Software, and to permit persons to whom the Software is
  12. * furnished to do so, subject to the following conditions:
  13. *
  14. * The above copyright notice and this permission notice shall be
  15. * included in all copies or substantial portions of the Software.
  16. *
  17. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  18. * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  19. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  20. * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  21. * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  22. * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  23. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  24. * DEALINGS IN THE SOFTWARE.
  25. *
  26. * @brief User interface fallback driver for X11
  27. *
  28. */
  29. #include <stdint.h>
  30. #include <stdlib.h>
  31. #include <stdio.h>
  32. #include <string.h>
  33. #include <Xlib.h>
  34. #include <Xutil.h>
  35. #include <Xos.h>
  36. #include <Xatom.h>
  37. #ifdef HAS_XMU
  38. #include <Xmu/Atoms.h>
  39. #endif
  40. #include <keysymdef.h>
  41. #include <cursorfont.h>
  42. #include "lang.h"
  43. #include "util.h"
  44. #include "ui.h"
  45. Display *display;
  46. Visual *visual;
  47. Atom wmDel, wmTargets;
  48. Cursor cursors[5];
  49. extern uint8_t *tools, *icon32, *icon64;
  50. #define ICON_LENGTH (2 + 16 * 16 + 2 + 32 * 32 + 2 + 64 * 64)
  51. long icons[ICON_LENGTH];
  52. int screen_num = 0, red_shift,green_shift,blue_shift, btnflags = 0, keyflags = 0, keypressed = 0;
  53. #ifdef HAS_XMU
  54. unsigned char selection[8] = { 0 };
  55. #endif
  56. /**
  57. * Copy text to clipboard
  58. */
  59. void ui_copy(char *s)
  60. {
  61. #ifdef HAS_XMU
  62. memcpy(selection, s, sizeof(selection));
  63. XSetSelectionOwner(display, XA_CLIPBOARD(display), (Window)wins[0].winid, CurrentTime);
  64. #else
  65. /* in lack of Xmu and XA_CLIPBOARD, we just print it to console */
  66. printf("UTF8: %s\n", s);
  67. #endif
  68. }
  69. /**
  70. * Create a window
  71. */
  72. void *ui_createwin(int w, int h)
  73. {
  74. Window window;
  75. Atom net_wm_icon, cardinal;
  76. if(!(window = XCreateSimpleWindow(display, RootWindow(display, screen_num), 0, 0, w, h, 0, theme[THEME_FG], theme[THEME_BG])))
  77. return 0;
  78. XSelectInput(display, window, KeyPressMask|KeyReleaseMask|ButtonPressMask|ButtonReleaseMask|
  79. ButtonMotionMask|PointerMotionMask|ExposureMask|StructureNotifyMask);
  80. net_wm_icon = XInternAtom(display, "_NET_WM_ICON", False);
  81. cardinal = XInternAtom(display, "CARDINAL", False);
  82. XChangeProperty(display, window, net_wm_icon, cardinal, 32, PropModeReplace, (unsigned char *)icons, ICON_LENGTH);
  83. XSetWMProtocols(display, window, &wmDel, 1);
  84. return (void*)window;
  85. }
  86. /**
  87. * Set window title
  88. */
  89. void ui_titlewin(ui_win_t *win, char *title)
  90. {
  91. XTextProperty title_property;
  92. int i;
  93. i = XStringListToTextProperty(&title, 1, &title_property);
  94. if(i) {
  95. XSetWMName(display, (Window)win->winid, &title_property);
  96. XSetWMIconName(display, (Window)win->winid, &title_property);
  97. }
  98. }
  99. /**
  100. * Resize a window
  101. */
  102. void ui_resizewin(ui_win_t *win, int w, int h)
  103. {
  104. int i;
  105. XImage *xi;
  106. if(win->data) free(win->data);
  107. if(win->surface) {
  108. ((XImage*)win->surface)->data = NULL;
  109. XDestroyImage((XImage*)win->surface);
  110. }
  111. xi = XCreateImage(display, visual, DefaultDepth(display, screen_num), ZPixmap, 0, NULL, w, h, 8, w * 4);
  112. win->data = (uint32_t*)malloc(w * h * sizeof(uint32_t));
  113. if(!xi || !win->data) ui_error("x11", ERR_MEM);
  114. xi->data = (char*)win->data;
  115. xi->byte_order= LSBFirst;
  116. xi->bits_per_pixel = 32;
  117. win->surface = (void*)xi;
  118. win->p = w;
  119. win->w = w;
  120. win->h = h;
  121. for(i = 0; i < w * h; i++) win->data[i] = theme[THEME_BG];
  122. }
  123. /**
  124. * Display modified window
  125. */
  126. void ui_flushwin(ui_win_t *win, int x, int y, int w, int h)
  127. {
  128. GC gc = XCreateGC(display, (Window)win->winid, 0, 0);
  129. XPutImage(display, (Window)win->winid, gc, (XImage*)win->surface, x, y, x, y, w, h);
  130. XFlush(display);
  131. XFreeGC(display, gc);
  132. }
  133. /**
  134. * Destroy a window
  135. */
  136. void ui_destroywin(ui_win_t *win)
  137. {
  138. free(win->data);
  139. win->data = NULL;
  140. ((XImage*)win->surface)->data = NULL;
  141. XDestroyImage((XImage*)win->surface);
  142. XUnmapWindow(display, (Window)win->winid);
  143. XDestroyWindow(display, (Window)win->winid);
  144. XFlush(display);
  145. }
  146. /**
  147. * Focus a window
  148. */
  149. void ui_focuswin(ui_win_t *win)
  150. {
  151. XMapWindow(display, (Window)win->winid);
  152. XRaiseWindow(display, (Window)win->winid);
  153. XFlush(display);
  154. }
  155. /**
  156. * Change cursor of window
  157. */
  158. void ui_cursorwin(ui_win_t *win, int cursor)
  159. {
  160. XDefineCursor(display, (Window)win->winid, cursors[cursor]);
  161. }
  162. /**
  163. * Initialize X11 driver
  164. */
  165. void ui_init()
  166. {
  167. int i;
  168. long *ptr = icons;
  169. display = XOpenDisplay(getenv("DISPLAY"));
  170. if (!display) ui_error("x11", ERR_DISPLAY);
  171. screen_num = DefaultScreen(display);
  172. visual = DefaultVisual(display, screen_num);
  173. red_shift = green_shift = blue_shift = 24;
  174. if(!DisplayWidth(display, screen_num)) ui_error("x11", ERR_DISPLAY);
  175. for (i = visual->red_mask; !(i&0x80000000); i <<= 1) red_shift--;
  176. for (i = visual->green_mask; !(i&0x80000000); i <<= 1) green_shift--;
  177. for (i = visual->blue_mask; !(i&0x80000000); i <<= 1) blue_shift--;
  178. *ptr++ = 16;
  179. *ptr++ = 16;
  180. for(i=0; i < 16 * 16 * 4; i += 4)
  181. *ptr++ = tools[i+2] | (tools[i+1] << 8) | (tools[i] << 16) | (tools[i+3] << 24);
  182. *ptr++ = 32;
  183. *ptr++ = 32;
  184. for(i=0; i < 32 * 32 * 4; i += 4)
  185. *ptr++ = icon32[i+2] | (icon32[i+1] << 8) | (icon32[i] << 16) | (icon32[i+3] << 24);
  186. *ptr++ = 64;
  187. *ptr++ = 64;
  188. for(i=0; i < 64 * 64 * 4; i += 4)
  189. *ptr++ = icon64[i+2] | (icon64[i+1] << 8) | (icon64[i] << 16) | (icon64[i+3] << 24);
  190. cursors[CURSOR_LOADING] = XCreateFontCursor(display, XC_watch);
  191. cursors[CURSOR_PTR] = XCreateFontCursor(display, XC_left_ptr);
  192. cursors[CURSOR_CROSS] = XCreateFontCursor(display, XC_crosshair);
  193. cursors[CURSOR_MOVE] = XCreateFontCursor(display, XC_fleur);
  194. cursors[CURSOR_GRAB] = XCreateFontCursor(display, XC_hand2);
  195. wmDel = XInternAtom(display, "WM_DELETE_WINDOW", False);
  196. wmTargets = XInternAtom(display, "TARGETS", False);
  197. }
  198. /**
  199. * Finish X11 driver
  200. */
  201. void ui_fini()
  202. {
  203. int i;
  204. for(i=0;i<5;i++) XFreeCursor(display, cursors[i]);
  205. XCloseDisplay(display);
  206. }
  207. /**
  208. * Convert an X11 event
  209. */
  210. void ui_getevent()
  211. {
  212. XEvent e;
  213. #ifdef HAS_XMU
  214. XEvent r;
  215. #endif
  216. KeySym k;
  217. e.type = None;
  218. event.type = E_NONE;
  219. XNextEvent(display, &e);
  220. event.win = ui_getwin((void*)e.xany.window);
  221. switch(e.type) {
  222. case Expose:
  223. event.type = E_REFRESH;
  224. event.x = e.xexpose.x;
  225. event.y = e.xexpose.y;
  226. event.w = e.xexpose.width;
  227. event.h = e.xexpose.height;
  228. break;
  229. case ConfigureNotify:
  230. event.type = E_RESIZE;
  231. event.x = event.y = 0;
  232. event.w = e.xconfigure.width;
  233. event.h = e.xconfigure.height;
  234. break;
  235. case ClientMessage:
  236. if((Atom)e.xclient.data.l[0] == wmDel) event.type = E_CLOSE;
  237. break;
  238. case KeyRelease:
  239. if(!keypressed) break; else keypressed--;
  240. k = XLookupKeysym(&e.xkey, 0);
  241. event.x = XLookupKeysym(&e.xkey, keyflags & 1);
  242. switch(k) {
  243. case XK_F1: event.x = K_F1; break;
  244. case XK_Escape: event.x = K_ESC; break;
  245. case XK_Delete: event.x = K_DEL; break;
  246. case XK_BackSpace: event.x = K_BACKSPC; break;
  247. case XK_Tab: event.x = K_TAB; break;
  248. case XK_Up: event.x = K_UP; break;
  249. case XK_Down: event.x = K_DOWN; break;
  250. case XK_Left: event.x = K_LEFT; break;
  251. case XK_Right: event.x = K_RIGHT; break;
  252. case XK_Home: event.x = K_HOME; break;
  253. case XK_End: event.x = K_END; break;
  254. case XK_Page_Up: event.x = K_PGUP; break;
  255. case XK_Page_Down: event.x = K_PGDN; break;
  256. case XK_Return: event.x = K_ENTER; break;
  257. case XK_Shift_L:
  258. case XK_Shift_R: event.x = 0; keyflags &= ~1; break;
  259. case XK_Control_L:
  260. case XK_Control_R: event.x = 0; keyflags &= ~2; break;
  261. case XK_Super_L:
  262. case XK_Super_R:
  263. case XK_Alt_L:
  264. case XK_Alt_R: event.x = 0; keyflags &= ~4;break;
  265. }
  266. event.h = keyflags;
  267. if(event.x) event.type = E_KEY;
  268. break;
  269. case KeyPress:
  270. k = XLookupKeysym(&e.xkey, 0);
  271. keypressed++;
  272. switch(k) {
  273. case XK_Shift_L:
  274. case XK_Shift_R: keyflags |= 1; break;
  275. case XK_Control_L:
  276. case XK_Control_R: keyflags |= 2; break;
  277. case XK_Super_L:
  278. case XK_Super_R:
  279. case XK_Alt_L:
  280. case XK_Alt_R: keyflags |= 4; break;
  281. }
  282. break;
  283. case MotionNotify:
  284. event.type = E_MOUSEMOVE;
  285. event.x = e.xmotion.x;
  286. event.y = e.xmotion.y;
  287. event.w = btnflags;
  288. event.h = keyflags;
  289. break;
  290. case ButtonPress:
  291. event.type = E_BTNPRESS;
  292. event.x = e.xbutton.x;
  293. event.y = e.xbutton.y;
  294. btnflags |= (1<<(e.xbutton.button-1));
  295. event.w = btnflags;
  296. event.h = keyflags;
  297. break;
  298. case ButtonRelease:
  299. event.type = E_BTNRELEASE;
  300. event.x = e.xbutton.x;
  301. event.y = e.xbutton.y;
  302. btnflags &= ~(1<<(e.xbutton.button-1));
  303. event.w = btnflags;
  304. event.h = keyflags;
  305. break;
  306. #ifdef HAS_XMU
  307. case SelectionRequest:
  308. if(selection[0]) {
  309. XChangeProperty(display, e.xselectionrequest.requestor, e.xselectionrequest.property,
  310. XA_UTF8_STRING(display), 8, PropModeReplace, selection, strlen((char*)selection));
  311. r.xselection.type = SelectionNotify;
  312. r.xselection.requestor = e.xselectionrequest.requestor;
  313. r.xselection.property = e.xselectionrequest.property;
  314. r.xselection.display = display;
  315. r.xselection.selection = e.xselectionrequest.selection;
  316. r.xselection.target = e.xselectionrequest.target;
  317. r.xselection.time = e.xselectionrequest.time;
  318. XSendEvent(display, e.xselectionrequest.requestor, 0, 0, &r);
  319. XFlush(display);
  320. }
  321. break;
  322. #endif
  323. }
  324. }