printer.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381
  1. /*
  2. Copyright (C) 2014 Olivier Marty <olivier.marty.m at gmail.com>
  3. This program is free software; you can redistribute it and/or
  4. modify it under the terms of the GNU General Public License
  5. as published by the Free Software Foundation; either version 2
  6. of the License, or (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program; if not, write to the Free Software
  13. Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  14. */
  15. #include "printer.h"
  16. #include <stdio.h>
  17. #include <stdlib.h>
  18. #include <X11/Xlib.h>
  19. #include <X11/Xutil.h>
  20. #include <X11/keysym.h>
  21. #include <X11/XKBlib.h>
  22. #include <string.h>
  23. char *strnstr(const char *s, const char *find, size_t slen)
  24. {
  25. char c, sc;
  26. size_t len;
  27. if ((c = *find++) != '\0') {
  28. len = strlen(find);
  29. do {
  30. do {
  31. if ((sc = *s++) == '\0' || slen-- < 1)
  32. return (NULL);
  33. } while (sc != c);
  34. if (len > slen)
  35. return (NULL);
  36. } while (strncmp(s, find, len) != 0);
  37. s--;
  38. }
  39. return ((char *)s);
  40. }
  41. void loadFont(struct printerEnv *env, XFontStruct **font, char* fontname)
  42. {
  43. *font = XLoadQueryFont(env->d, fontname);
  44. if(!*font)
  45. {
  46. fprintf (stderr, "unable to load font %s - using normal font\n", fontname);
  47. *font = env->fontinfo;
  48. }
  49. else
  50. {
  51. if((*font)->ascent > env->maxascent)
  52. env->maxascent = (*font)->ascent;
  53. if((*font)->descent > env->maxdescent)
  54. env->maxdescent = (*font)->descent;
  55. }
  56. }
  57. struct printerEnv printerOpenWindow(char *font, char *font_i, char *font_b,
  58. char *font_bi)
  59. {
  60. struct printerEnv env;
  61. // open connection
  62. env.d = XOpenDisplay(NULL);
  63. if (env.d == NULL) {
  64. fprintf(stderr, "Unable to open display\n");
  65. exit(1);
  66. }
  67. env.s = DefaultScreen(env.d);
  68. XVisualInfo vinfo;
  69. XMatchVisualInfo(env.d, env.s, 32, TrueColor, &vinfo);
  70. // size of the screen
  71. XWindowAttributes RootAttr;
  72. XGetWindowAttributes(env.d, RootWindow(env.d, env.s), &RootAttr);
  73. env.root_width = RootAttr.width;
  74. env.root_height = RootAttr.height;
  75. // set window attributes
  76. XSetWindowAttributes attr;
  77. attr.colormap = XCreateColormap(env.d, RootWindow(env.d, env.s),
  78. vinfo.visual, AllocNone);
  79. attr.border_pixel = 0;
  80. attr.background_pixel = 0;
  81. attr.override_redirect = 1; // no window manager border
  82. // set colors
  83. env.color_text = XWhitePixel(env.d, env.s);
  84. XColor tmp;
  85. XParseColor(env.d, attr.colormap, "#222222", &tmp);
  86. XAllocColor(env.d, attr.colormap, &tmp);
  87. env.color_background = tmp.pixel;
  88. //unsigned short r = 34, g = 34, b = 34, a = 192; // TODO where is the doc ?
  89. //env.color_background = a*256*256*256 + r*256*256 + g*256 + b;
  90. // create the window
  91. env.width = 1;
  92. env.height = 1;
  93. env.w = XCreateWindow(env.d, RootWindow(env.d, env.s), 0, 0, env.width,
  94. env.height, 0, vinfo.depth, InputOutput, vinfo.visual,
  95. CWColormap | CWBorderPixel | CWBackPixel | CWOverrideRedirect, &attr);
  96. // setting fonts
  97. char *fontname = (font == NULL) ?
  98. "-bitstream-bitstream charter-medium-r-normal--*-280-100-100-p-*-iso8859-1"
  99. : font;
  100. env.fontinfo = XLoadQueryFont(env.d, fontname);
  101. if(!env.fontinfo)
  102. {
  103. fprintf (stderr, "unable to load font %s: using fixed\n", fontname);
  104. env.fontinfo = XLoadQueryFont(env.d, "fixed");
  105. }
  106. env.maxascent = env.fontinfo->ascent;
  107. env.maxdescent = env.fontinfo->descent;
  108. loadFont(&env, &env.fontinfo_i, (font_i == NULL) ?
  109. "-bitstream-bitstream charter-medium-i-normal--*-280-100-100-p-*-iso8859-1"
  110. : font_i);
  111. loadFont(&env, &env.fontinfo_b, (font_b == NULL) ?
  112. "-bitstream-bitstream charter-bold-r-normal--*-280-100-100-p-*-iso8859-1"
  113. : font_b);
  114. loadFont(&env, &env.fontinfo_bi, (font_bi == NULL) ?
  115. "-bitstream-bitstream charter-bold-i-normal--*-280-100-100-p-*-iso8859-1"
  116. : font_bi);
  117. // create GC
  118. XGCValues gr_values;
  119. gr_values.font = env.fontinfo->fid;
  120. gr_values.foreground = XWhitePixel(env.d, env.s);
  121. gr_values.background = XBlackPixel(env.d, env.s);
  122. env.gc = XCreateGC(env.d, env.w, GCFont | GCForeground, &gr_values);
  123. // focused window (for keyboard)
  124. int revert;
  125. XGetInputFocus(env.d, &env.w_focused, &revert);
  126. // event to be listened
  127. XSelectInput(env.d, env.w_focused, KeyPressMask|FocusChangeMask);
  128. return env;
  129. }
  130. void printerCloseWindow(struct printerEnv env)
  131. {
  132. XCloseDisplay(env.d); // window is automatically destroyed
  133. }
  134. XFontStruct* getFont(struct printerEnv env, enum t_type flags)
  135. {
  136. if(flags & T_ITALIC && flags & T_BOLD)
  137. return env.fontinfo_bi;
  138. if(flags & T_ITALIC)
  139. return env.fontinfo_i;
  140. if(flags & T_BOLD)
  141. return env.fontinfo_b;
  142. return env.fontinfo;
  143. }
  144. // return the width of the text drawn
  145. // look for i and b html tags
  146. // bug when there is several i (or several v) nested
  147. // set in rflags the flags at the end of the text
  148. int drawText(struct printerEnv env, char *text, int size,
  149. int x, int y, enum t_type flags, enum t_type *rflags, int draw)
  150. {
  151. char *i = strnstr(text, "<i>", size),
  152. *b = strnstr(text, "<b>", size),
  153. *begin = NULL, *end = NULL;
  154. int wopentag = 0, wclosetag = 0,
  155. width;
  156. enum t_type nflags = flags;
  157. *rflags = flags;
  158. if(i != NULL && (b == NULL || i < b)) // i is the first
  159. {
  160. wopentag = 3;
  161. begin = i;
  162. end = strnstr(i, "</i>", size - (i - text));
  163. nflags |= T_ITALIC;
  164. if(end != NULL)
  165. wclosetag = 4;
  166. else
  167. *rflags |= T_ITALIC;
  168. }
  169. else if(b != NULL) // b is the first
  170. {
  171. wopentag = 3;
  172. begin = b;
  173. end = strnstr(b, "</b>", size - (b - text));
  174. nflags |= T_BOLD;
  175. if(end != NULL)
  176. wclosetag = 4;
  177. else
  178. *rflags |= T_BOLD;
  179. }
  180. else // no opening tag
  181. {
  182. if(flags & T_ITALIC) // we look for it
  183. i = strnstr(text, "</i>", size);
  184. if(flags & T_BOLD)
  185. b = strnstr(text, "</b>", size);
  186. if(i != NULL && (b == NULL || i < b))
  187. {
  188. wclosetag = 4;
  189. begin = text;
  190. end = i;
  191. nflags |= T_ITALIC;
  192. *rflags &= ~T_ITALIC;
  193. }
  194. else if(b != NULL)
  195. {
  196. wclosetag = 4;
  197. begin = text;
  198. end = b;
  199. nflags |= T_BOLD;
  200. *rflags &= ~T_BOLD;
  201. }
  202. }
  203. enum t_type dummy;
  204. if(begin != NULL && end != NULL)
  205. {
  206. // before
  207. width = drawText(env, text, begin - text, x, y, flags, &dummy, draw);
  208. // middle
  209. width += drawText(env, begin + wopentag, end - begin - wopentag,
  210. x + width, y, nflags, &dummy, draw);
  211. // after
  212. width += drawText(env, end + wclosetag, size - (end + wclosetag - begin),
  213. x + width, y, flags, rflags, draw);
  214. }
  215. else if(begin != NULL)
  216. {
  217. // before
  218. width = drawText(env, text, begin - text, x, y, flags, &dummy, draw);
  219. // middle
  220. width += drawText(env, begin + wopentag, size - (begin + wopentag - text),
  221. x + width, y, nflags, &dummy, draw);
  222. *rflags |= dummy;
  223. }
  224. else
  225. {
  226. int font_direction, font_ascent, font_descent;
  227. XCharStruct text_structure;
  228. XTextExtents(getFont(env, flags), text, size,
  229. &font_direction, &font_ascent, &font_descent,
  230. &text_structure);
  231. width = text_structure.width;
  232. if(draw)
  233. {
  234. XSetFont(env.d, env.gc, getFont(env, flags)->fid);
  235. XDrawString(env.d, env.w, env.gc, x, y, text, size);
  236. }
  237. }
  238. return width;
  239. }
  240. // return a the max width
  241. int printLines(struct printerEnv env, char *text, int y, enum t_type flags,
  242. int draw)
  243. {
  244. char *next;
  245. int size;
  246. int width = 0;
  247. next = strchr(text, '\n');
  248. if(next == NULL)
  249. {
  250. size = strlen(text);
  251. next = text + size;
  252. }
  253. else
  254. {
  255. size = next-text;
  256. if(*(next-1) == '\r')
  257. size--; // hide this character
  258. next++; // forget \n
  259. }
  260. // compute the size of the text
  261. enum t_type dummy;
  262. int tmp = drawText(env, text, size, 0, 0, flags, &dummy, 0);
  263. // print line
  264. if(draw)
  265. drawText(env, text, size, (env.width - tmp)/2, y, flags, &flags, 1);
  266. else
  267. flags = dummy;
  268. // print next lines
  269. if(*next != '\0')
  270. width = printLines(env, next, y + env.maxascent + env.maxdescent
  271. + env.gap, flags, draw);
  272. if(tmp > width)
  273. return tmp;
  274. return width;
  275. }
  276. void printerShow(struct printerEnv *env, char* text, enum t_type font)
  277. {
  278. int nlines = 1;
  279. char *p = text;
  280. // remap the window
  281. XMapWindow(env->d, env->w);
  282. while((p = strchr(p, '\n')) != NULL)
  283. {
  284. p++;
  285. if(*p == '\0')
  286. break;
  287. nlines++;
  288. }
  289. // width and height
  290. env->width = printLines(*env, text, 0, font, 0) + 2 * env->padding;
  291. env->height = nlines * (env->maxascent + env->maxdescent + env->gap)
  292. - env->gap + 2 * env->padding;
  293. XClearWindow(env->d, env->w);
  294. XMoveResizeWindow(env->d, env->w, (env->root_width - env->width)/2,
  295. env->root_height - env->margin_bottom - env->height, env->width,
  296. env->height);
  297. // frame
  298. XSetForeground(env->d, env->gc, env->color_background);
  299. XFillRectangle(env->d, env->w, env->gc, 0, 0, env->width, env->height);
  300. XSetForeground(env->d, env->gc, env->color_text);
  301. // text
  302. printLines(*env, text, env->padding + env->maxascent, font, 1);
  303. XFlush(env->d);
  304. }
  305. void printerClean(struct printerEnv env)
  306. {
  307. XClearWindow(env.d, env.w);
  308. XUnmapWindow(env.d, env.w);
  309. XFlush(env.d);
  310. }
  311. void manageEvent(struct printerEnv *env, void callback(struct printerEnv*,int,void*), void* callback_arg)
  312. {
  313. XEvent event;
  314. int r;
  315. XComposeStatus comp;
  316. while(XPending(env->d))
  317. {
  318. XNextEvent(env->d, &event);
  319. switch(event.type)
  320. {
  321. case FocusOut:
  322. XGetInputFocus(env->d, &env->w_focused, &r);
  323. if(env->w_focused == PointerRoot)
  324. env->w_focused = RootWindow(env->d, env->s); // TODO why ?
  325. XSelectInput(env->d, env->w_focused, KeyPressMask|FocusChangeMask);
  326. break;
  327. case KeyPress:
  328. callback(env, (int)XkbKeycodeToKeysym(env->d, event.xkey.keycode, 0, event.xkey.state & ShiftMask ? 1 : 0), callback_arg);
  329. break;
  330. default:
  331. break;
  332. }
  333. }
  334. }
  335. void waitEvent(struct printerEnv *env)
  336. {
  337. XEvent event;
  338. XPeekEvent(env->d, &event);
  339. }