printer.c 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353
  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. void loadFont(struct printerEnv *env, XFontStruct **font, char* fontname)
  24. {
  25. *font = XLoadQueryFont(env->d, fontname);
  26. if(!*font)
  27. {
  28. fprintf (stderr, "unable to load font %s - using normal font\n", fontname);
  29. *font = env->fontinfo;
  30. }
  31. else
  32. {
  33. if((*font)->ascent > env->maxascent)
  34. env->maxascent = (*font)->ascent;
  35. if((*font)->descent > env->maxdescent)
  36. env->maxdescent = (*font)->descent;
  37. }
  38. }
  39. struct printerEnv printerOpenWindow(char *font, char *font_i, char *font_b,
  40. char *font_bi)
  41. {
  42. struct printerEnv env;
  43. // open connection
  44. env.d = XOpenDisplay(NULL);
  45. if (env.d == NULL) {
  46. fprintf(stderr, "Unable to open display\n");
  47. exit(1);
  48. }
  49. env.d_fd = ConnectionNumber(env.d);
  50. env.s = DefaultScreen(env.d);
  51. XVisualInfo vinfo;
  52. XMatchVisualInfo(env.d, env.s, 32, TrueColor, &vinfo);
  53. // size of the screen
  54. XWindowAttributes RootAttr;
  55. XGetWindowAttributes(env.d, RootWindow(env.d, env.s), &RootAttr);
  56. env.root_width = RootAttr.width;
  57. env.root_height = RootAttr.height;
  58. // set window attributes
  59. XSetWindowAttributes attr;
  60. attr.colormap = XCreateColormap(env.d, RootWindow(env.d, env.s),
  61. vinfo.visual, AllocNone);
  62. attr.border_pixel = 0;
  63. attr.background_pixel = 0;
  64. attr.override_redirect = 1; // no window manager border
  65. // set colors
  66. env.color_text = XWhitePixel(env.d, env.s);
  67. XColor tmp;
  68. XParseColor(env.d, attr.colormap, "#222222", &tmp);
  69. XAllocColor(env.d, attr.colormap, &tmp);
  70. env.color_background = tmp.pixel;
  71. //unsigned short r = 34, g = 34, b = 34, a = 192; // TODO where is the doc ?
  72. //env.color_background = a*256*256*256 + r*256*256 + g*256 + b;
  73. // create the window
  74. env.w = XCreateWindow(env.d, RootWindow(env.d, env.s), 0, 0, 1, 1, 0, vinfo.depth, InputOutput, vinfo.visual,
  75. CWColormap | CWBorderPixel | CWBackPixel | CWOverrideRedirect, &attr);
  76. // setting fonts
  77. char *fontname = (font == NULL) ?
  78. "-bitstream-bitstream charter-medium-r-normal--*-280-100-100-p-*-iso8859-1"
  79. : font;
  80. env.fontinfo = XLoadQueryFont(env.d, fontname);
  81. if(!env.fontinfo)
  82. {
  83. fprintf (stderr, "unable to load font %s: using fixed\n", fontname);
  84. env.fontinfo = XLoadQueryFont(env.d, "fixed");
  85. }
  86. env.maxascent = env.fontinfo->ascent;
  87. env.maxdescent = env.fontinfo->descent;
  88. loadFont(&env, &env.fontinfo_i, (font_i == NULL) ?
  89. "-bitstream-bitstream charter-medium-i-normal--*-280-100-100-p-*-iso8859-1"
  90. : font_i);
  91. loadFont(&env, &env.fontinfo_b, (font_b == NULL) ?
  92. "-bitstream-bitstream charter-bold-r-normal--*-280-100-100-p-*-iso8859-1"
  93. : font_b);
  94. loadFont(&env, &env.fontinfo_bi, (font_bi == NULL) ?
  95. "-bitstream-bitstream charter-bold-i-normal--*-280-100-100-p-*-iso8859-1"
  96. : font_bi);
  97. // create GC
  98. XGCValues gr_values;
  99. gr_values.font = env.fontinfo->fid;
  100. gr_values.foreground = XWhitePixel(env.d, env.s);
  101. gr_values.background = XBlackPixel(env.d, env.s);
  102. env.gc = XCreateGC(env.d, env.w, GCFont | GCForeground, &gr_values);
  103. // focused window (for keyboard)
  104. int revert;
  105. XGetInputFocus(env.d, &env.w_focused, &revert);
  106. // event to be listened
  107. XSelectInput(env.d, env.w_focused, KeyPressMask | FocusChangeMask | ExposureMask);
  108. // empty message set
  109. env.maxsize = 0;
  110. env.size = 0;
  111. env.texts = NULL;
  112. return env;
  113. }
  114. void printerCloseWindow(struct printerEnv env)
  115. {
  116. XCloseDisplay(env.d); // window is automatically destroyed
  117. }
  118. XFontStruct* getFont(struct printerEnv env, enum t_type flags)
  119. {
  120. if(flags & T_ITALIC && flags & T_BOLD)
  121. return env.fontinfo_bi;
  122. if(flags & T_ITALIC)
  123. return env.fontinfo_i;
  124. if(flags & T_BOLD)
  125. return env.fontinfo_b;
  126. return env.fontinfo;
  127. }
  128. int drawTextRaw(struct printerEnv env, char *text, int size, enum t_type font,
  129. int *x, int *y, int draw)
  130. {
  131. int font_direction, font_ascent, font_descent;
  132. XCharStruct text_structure;
  133. XTextExtents(getFont(env, font), text, size,
  134. &font_direction, &font_ascent, &font_descent,
  135. &text_structure);
  136. if(draw)
  137. {
  138. XSetFont(env.d, env.gc, getFont(env, font)->fid);
  139. XDrawString(env.d, env.w, env.gc, *x, *y, text, size);
  140. }
  141. *x += text_structure.width;
  142. }
  143. int drawTextLines(struct printerEnv env, char *text, int size, enum t_type font,
  144. int initx, int *x, int *y, int *maxw, int draw)
  145. {
  146. char *nl = memchr(text, '\n', size);
  147. if(nl == NULL)
  148. {
  149. drawTextRaw(env, text, size, font, x, y, draw);
  150. if(*x > *maxw)
  151. *maxw = *x;
  152. }
  153. else
  154. {
  155. drawTextRaw(env, text, nl-text, font, x, y, draw);
  156. if(*x > *maxw)
  157. *maxw = *x;
  158. *x = initx; // TODO center
  159. *y += env.maxascent + env.maxdescent + env.gap;
  160. drawTextLines(env, nl+1, text-nl-1+size, font, initx, x, y, maxw, draw);
  161. }
  162. }
  163. // update x and y
  164. int drawText(struct printerEnv env, struct richText *rt,
  165. int initx, int *x, int *y, int *maxw, int draw)
  166. {
  167. if(rt->left != NULL && rt->right != NULL)
  168. {
  169. drawText(env, rt->left, initx, x, y, maxw, draw);
  170. drawText(env, rt->right, initx, x, y, maxw, draw);
  171. }
  172. else
  173. drawTextLines(env, rt->pos, rt->size, rt->type, initx, x, y, maxw, draw);
  174. }
  175. void printerRender(struct printerEnv *env)
  176. {
  177. if(env->size == 0)
  178. {
  179. XClearWindow(env->d, env->w);
  180. XUnmapWindow(env->d, env->w);
  181. }
  182. else
  183. {
  184. int i;
  185. int w = 0, h = 0;
  186. // remap the window
  187. XMapWindow(env->d, env->w);
  188. XClearWindow(env->d, env->w);
  189. // resize the window
  190. for(i = 0; i < env->size; i++)
  191. {
  192. if(env->texts[i].width > w)
  193. w = env->texts[i].width;
  194. if(-env->texts[i].posy > h)
  195. h = -env->texts[i].posy;
  196. }
  197. w += 2*env->padding;
  198. h += 2*env->padding;
  199. XMoveResizeWindow(env->d, env->w, (env->root_width - w)/2,
  200. env->root_height - env->margin_bottom - h, w, h);
  201. // draw texts
  202. for(i = 0; i < env->size; i++)
  203. {
  204. int x = (w-env->texts[i].width)/2;
  205. int y = h+env->texts[i].posy - env->padding;
  206. // frame
  207. XSetForeground(env->d, env->gc, env->color_background);
  208. XFillRectangle(env->d, env->w, env->gc, x - env->padding, y - env->padding,
  209. env->texts[i].width + 2*env->padding,
  210. env->texts[i].height + 2*env->padding);
  211. XSetForeground(env->d, env->gc, env->color_text);
  212. // text
  213. y += env->maxascent;
  214. drawText(*env, env->texts[i].t, x, &x, &y, &x, 1);
  215. }
  216. }
  217. XFlush(env->d);
  218. }
  219. void printerHide(struct printerEnv *env, int id)
  220. {
  221. int i;
  222. for(i = 0; i < env->size; i++)
  223. if(env->texts[i].id == id)
  224. break;
  225. if(i < env->size)
  226. {
  227. // delete it
  228. memmove(env->texts + i, env->texts + (i + 1),
  229. sizeof(struct message[env->size-i-1]));
  230. env->size--;
  231. }
  232. }
  233. int getPos(struct printerEnv *env, int h)
  234. {
  235. int pos = -h, i;
  236. // change pos until it works
  237. while(1)
  238. {
  239. // is it ok betwen pos and pos+h ?
  240. int i, gap = env->gap2 + 2 * env->padding;
  241. for(i = 0; i < env->size; i++)
  242. {
  243. int pos2 = env->texts[i].posy;
  244. int h2 = env->texts[i].height;
  245. if(h2 + pos2 <= pos - gap)
  246. continue;
  247. if(pos2 >= pos + h + gap)
  248. continue;
  249. pos = pos2 - h - gap;
  250. break;
  251. }
  252. if(i == env->size)
  253. return pos;
  254. }
  255. }
  256. void printerShow(struct printerEnv *env, struct richText *rt, int id)
  257. {
  258. int w = 0, h = 0, x = 0;
  259. // hide previous message with this id
  260. printerHide(env, id);
  261. if(env->maxsize == 0) // first call
  262. {
  263. env->maxsize = 2;
  264. env->texts = malloc(sizeof(struct message[env->maxsize]));
  265. }
  266. else if(env->size == env->maxsize) // too small
  267. {
  268. env->maxsize *= 2;
  269. env->texts = realloc(env->texts, sizeof(struct message[env->maxsize]));
  270. }
  271. if(env->texts == NULL)
  272. {
  273. perror("[re|m]alloc()");
  274. exit(1);
  275. }
  276. env->texts[env->size].t = rt;
  277. env->texts[env->size].id = id;
  278. // compute w and h
  279. drawText(*env, rt, 0, &x, &h, &w, 0);
  280. // 0 is the bottom
  281. env->texts[env->size].posy = getPos(env, h);
  282. env->texts[env->size].height = h;
  283. env->texts[env->size].width = w;
  284. env->size++;
  285. printerRender(env);
  286. }
  287. t_event manageEvent(struct printerEnv *env)
  288. {
  289. XEvent event;
  290. int r;
  291. XComposeStatus comp;
  292. t_event e;
  293. XNextEvent(env->d, &event);
  294. switch(event.type)
  295. {
  296. case Expose:
  297. if(event.xexpose.count == 0) // last expose event
  298. printerRender(env);
  299. break;
  300. case FocusOut:
  301. XGetInputFocus(env->d, &env->w_focused, &r);
  302. if(env->w_focused == PointerRoot)
  303. env->w_focused = RootWindow(env->d, env->s); // TODO why ?
  304. XSelectInput(env->d, env->w_focused, KeyPressMask|FocusChangeMask);
  305. event.type = T_NONE;
  306. break;
  307. case KeyPress:
  308. e.type = T_KEYPRESSED;
  309. e.keyPressed.key = (int)XkbKeycodeToKeysym(env->d, event.xkey.keycode, 0,
  310. event.xkey.state & ShiftMask ? 1 : 0);
  311. // e.keyPress.time = TODO (event.xkey.time is the number of milliseconds (from uptime ?)
  312. break;
  313. default:
  314. e.type = T_NONE;
  315. break;
  316. }
  317. return e;
  318. }