printer.c 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  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 <string.h>
  21. char *strnstr(const char *s, const char *find, size_t slen)
  22. {
  23. char c, sc;
  24. size_t len;
  25. if ((c = *find++) != '\0') {
  26. len = strlen(find);
  27. do {
  28. do {
  29. if ((sc = *s++) == '\0' || slen-- < 1)
  30. return (NULL);
  31. } while (sc != c);
  32. if (len > slen)
  33. return (NULL);
  34. } while (strncmp(s, find, len) != 0);
  35. s--;
  36. }
  37. return ((char *)s);
  38. }
  39. struct printerEnv printerOpenWindow(int width, int height, int padding_bottom)
  40. {
  41. struct printerEnv env;
  42. // open connection
  43. env.d = XOpenDisplay(NULL);
  44. if (env.d == NULL) {
  45. fprintf(stderr, "Unable to open display\n");
  46. exit(1);
  47. }
  48. env.s = DefaultScreen(env.d);
  49. XVisualInfo vinfo;
  50. XMatchVisualInfo(env.d, env.s, 32, TrueColor, &vinfo);
  51. // size of the screen
  52. XWindowAttributes RootAttr;
  53. XGetWindowAttributes(env.d, RootWindow(env.d, env.s), &RootAttr);
  54. // set window attributes
  55. XSetWindowAttributes attr;
  56. attr.colormap = XCreateColormap(env.d, RootWindow(env.d, env.s),
  57. vinfo.visual, AllocNone);
  58. attr.border_pixel = 0;
  59. attr.background_pixel = 0;
  60. attr.override_redirect = 1; // no window manager border
  61. // set colors
  62. env.color_text = XWhitePixel(env.d, env.s);
  63. XColor tmp;
  64. XParseColor(env.d, attr.colormap, "#222222", &tmp);
  65. XAllocColor(env.d, attr.colormap, &tmp);
  66. env.color_background = tmp.pixel;
  67. //env.color_text = -1;
  68. //env.color_background = (100 * 256 + 100) * 256 + 100;
  69. // create the window
  70. env.width = (width < 0) ? RootAttr.width : width;
  71. env.height = height;
  72. env.w = XCreateWindow(env.d, RootWindow(env.d, env.s),
  73. (RootAttr.width - env.width)/2,
  74. RootAttr.height - env.height - padding_bottom, env.width, env.height, 0,
  75. vinfo.depth, InputOutput, vinfo.visual,
  76. CWColormap | CWBorderPixel | CWBackPixel | CWOverrideRedirect, &attr);
  77. // setting fonts
  78. char fontname[] = "*x24*",//"*charter-medium-r-normal*",
  79. fontname_i[] = "*charter-medium-i-normal*",
  80. fontname_b[] = "*charter-bold-r-normal*",
  81. fontname_bi[] = "*charter-bold-i-normal*";
  82. env.fontinfo = XLoadQueryFont(env.d, fontname);
  83. env.fontinfo_i = XLoadQueryFont(env.d, fontname_i);
  84. env.fontinfo_b = XLoadQueryFont(env.d, fontname_b);
  85. env.fontinfo_bi = XLoadQueryFont(env.d, fontname_bi);
  86. if(!env.fontinfo)
  87. {
  88. fprintf (stderr, "unable to load font %s: using fixed\n", fontname);
  89. env.fontinfo = XLoadQueryFont(env.d, "fixed");
  90. }
  91. env.maxascent = env.fontinfo->ascent;
  92. env.maxdescent = env.fontinfo->descent;
  93. if(!env.fontinfo_i)
  94. {
  95. fprintf (stderr, "unable to load font %s\n", fontname_i);
  96. env.fontinfo_i = env.fontinfo;
  97. }
  98. else
  99. {
  100. if(env.fontinfo_i->ascent > env.maxascent)
  101. env.maxascent = env.fontinfo_i->ascent;
  102. if(env.fontinfo_i->descent > env.maxdescent)
  103. env.maxdescent = env.fontinfo_i->descent;
  104. }
  105. if(!env.fontinfo_b)
  106. {
  107. fprintf (stderr, "unable to load font %s\n", fontname_b);
  108. env.fontinfo_b = env.fontinfo;
  109. }
  110. else
  111. {
  112. if(env.fontinfo_b->ascent > env.maxascent)
  113. env.maxascent = env.fontinfo_b->ascent;
  114. if(env.fontinfo_b->descent > env.maxdescent)
  115. env.maxdescent = env.fontinfo_b->descent;
  116. }
  117. if(!env.fontinfo_bi)
  118. {
  119. fprintf (stderr, "unable to load font %s\n", fontname_bi);
  120. env.fontinfo_bi = env.fontinfo;
  121. }
  122. else
  123. {
  124. if(env.fontinfo_bi->ascent > env.maxascent)
  125. env.maxascent = env.fontinfo_bi->ascent;
  126. if(env.fontinfo_bi->descent > env.maxdescent)
  127. env.maxdescent = env.fontinfo_bi->descent;
  128. }
  129. XGCValues gr_values;
  130. gr_values.font = env.fontinfo->fid;
  131. gr_values.foreground = XWhitePixel(env.d, env.s);
  132. gr_values.background = XBlackPixel(env.d, env.s);
  133. env.gc = XCreateGC(env.d, env.w, GCFont | GCForeground, &gr_values);
  134. // event to be listened
  135. //XSelectInput(env.d, env.w, ExposureMask | KeyPressMask);
  136. // display the window
  137. XMapWindow(env.d, env.w);
  138. XFlush(env.d);
  139. return env;
  140. }
  141. void printerCloseWindow(struct printerEnv env)
  142. {
  143. XCloseDisplay(env.d); // window is destroyed
  144. }
  145. XFontStruct* getFont(struct printerEnv env, enum t_type flags)
  146. {
  147. if(flags & T_ITALIC && flags & T_BOLD)
  148. return env.fontinfo_bi;
  149. if(flags & T_ITALIC)
  150. return env.fontinfo_i;
  151. if(flags & T_BOLD)
  152. return env.fontinfo_b;
  153. return env.fontinfo;
  154. }
  155. // return the width of the text drawn
  156. // look for i and b html tags
  157. // bug when there is several i (or several v) nested
  158. // set in rflags the flags at the end of the text
  159. int drawText(struct printerEnv env, char *text, int size,
  160. int x, int y, enum t_type flags, enum t_type *rflags, int draw)
  161. {
  162. char *i = strnstr(text, "<i>", size),
  163. *b = strnstr(text, "<b>", size),
  164. *begin = NULL, *end = NULL;
  165. int wopentag = 0, wclosetag = 0,
  166. width;
  167. enum t_type nflags = flags;
  168. *rflags = flags;
  169. if(i != NULL && (b == NULL || i < b)) // i is the first
  170. {
  171. wopentag = 3;
  172. begin = i;
  173. end = strnstr(i, "</i>", size - (i - text));
  174. nflags |= T_ITALIC;
  175. if(end != NULL)
  176. wclosetag = 4;
  177. else
  178. *rflags |= T_ITALIC;
  179. }
  180. else if(b != NULL) // b is the first
  181. {
  182. wopentag = 3;
  183. begin = b;
  184. end = strnstr(b, "</b>", size - (b - text));
  185. nflags |= T_BOLD;
  186. if(end != NULL)
  187. wclosetag = 4;
  188. else
  189. *rflags |= T_BOLD;
  190. }
  191. else // no opening tag
  192. {
  193. if(flags & T_ITALIC) // we look for it
  194. i = strnstr(text, "</i>", size);
  195. if(flags & T_BOLD)
  196. b = strnstr(text, "</b>", size);
  197. if(i != NULL && (b == NULL || i < b))
  198. {
  199. wclosetag = 4;
  200. begin = text;
  201. end = i;
  202. nflags |= T_ITALIC;
  203. *rflags &= ~T_ITALIC;
  204. }
  205. else if(b != NULL)
  206. {
  207. wclosetag = 4;
  208. begin = text;
  209. end = b;
  210. nflags |= T_BOLD;
  211. *rflags &= ~T_BOLD;
  212. }
  213. }
  214. enum t_type dummy;
  215. if(begin != NULL && end != NULL)
  216. {
  217. // before
  218. width = drawText(env, text, begin - text, x, y, flags, &dummy, draw);
  219. // middle
  220. width += drawText(env, begin + wopentag, end - begin - wopentag,
  221. x + width, y, nflags, &dummy, draw);
  222. // after
  223. width += drawText(env, end + wclosetag, size - (end + wclosetag - begin),
  224. x + width, y, flags, rflags, draw);
  225. }
  226. else if(begin != NULL)
  227. {
  228. // before
  229. width = drawText(env, text, begin - text, x, y, flags, &dummy, draw);
  230. // middle
  231. width += drawText(env, begin + wopentag, size - (begin + wopentag - text),
  232. x + width, y, nflags, &dummy, draw);
  233. *rflags |= dummy;
  234. }
  235. else
  236. {
  237. int font_direction, font_ascent, font_descent;
  238. XCharStruct text_structure;
  239. XTextExtents(getFont(env, flags), text, size,
  240. &font_direction, &font_ascent, &font_descent,
  241. &text_structure);
  242. width = text_structure.width;
  243. if(draw)
  244. {
  245. XSetFont(env.d, env.gc, getFont(env, flags)->fid);
  246. XDrawString(env.d, env.w, env.gc, x, y, text, size);
  247. }
  248. }
  249. return width;
  250. }
  251. // return a the max width
  252. int printLines(struct printerEnv env, char *text, int gap, int y,
  253. enum t_type flags, int draw)
  254. {
  255. char *next;
  256. int size;
  257. int width;
  258. next = strchr(text, '\n');
  259. if(next == NULL)
  260. {
  261. size = strlen(text);
  262. next = text + size;
  263. }
  264. else
  265. {
  266. size = next-text;
  267. if(*(next-1) == '\r')
  268. size--; // hide this character
  269. next++; // forget \n
  270. }
  271. // compute the size of the text
  272. enum t_type dummy;
  273. int tmp = drawText(env, text, size, 0, 0, flags, &dummy, 0);
  274. // print line
  275. if(draw)
  276. drawText(env, text, size, (env.width - tmp)/2, y, flags, &flags, 1);
  277. else
  278. flags = dummy;
  279. // print next lines
  280. if(*next != '\0')
  281. width = printLines(env, next, gap, y + env.maxascent + env.maxdescent + gap,
  282. flags, draw);
  283. if(tmp > width)
  284. return tmp;
  285. return width;
  286. }
  287. void printerShow(struct printerEnv env, char* text, enum t_type font)
  288. {
  289. int gap = 5, padding = 5;
  290. int nlines = 1,
  291. width, height;
  292. char *p = text;
  293. while((p = strchr(p, '\n')) != NULL)
  294. {
  295. p++;
  296. if(*p == '\0')
  297. break;
  298. nlines++;
  299. }
  300. XClearWindow(env.d, env.w);
  301. // max width
  302. width = printLines(env, text, gap, 0, font, 0);
  303. height = nlines * (env.maxascent + env.maxdescent + gap) - gap;
  304. // frame
  305. XSetForeground(env.d, env.gc, env.color_background);
  306. XFillRectangle(env.d, env.w, env.gc, (env.width - width)/2 - padding,
  307. env.height - 2*padding - height, width + 2*padding, height + 2*padding);
  308. XSetForeground(env.d, env.gc, env.color_text);
  309. // text
  310. printLines(env, text, gap,
  311. env.height - padding - height + env.maxascent, font, 1);
  312. XFlush(env.d);
  313. }
  314. void printerClean(struct printerEnv env)
  315. {
  316. XClearWindow(env.d, env.w);
  317. XFlush(env.d);
  318. }