status.c 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  1. /*
  2. * wmfs2 by Martin Duquesnoy <xorg62@gmail.com> { for(i = 2011; i < 2111; ++i) ©(i); }
  3. * For license, see COPYING.
  4. */
  5. #include "status.h"
  6. #include "barwin.h"
  7. #include "config.h"
  8. #include "infobar.h"
  9. #include "util.h"
  10. #include "draw.h"
  11. #include <string.h>
  12. static struct status_seq*
  13. status_new_seq(char type, int narg, int minarg, char *args[], int *shift)
  14. {
  15. struct status_seq *sq = xcalloc(1, sizeof(struct status_seq));
  16. SLIST_INIT(&sq->mousebinds);
  17. sq->type = type;
  18. *shift = 0;
  19. if(narg == minarg || !strcmp(args[0], "right") || !strcmp(args[0], "left"))
  20. sq->align = str_to_position(args[0]);
  21. else
  22. {
  23. sq->align = NoAlign;
  24. sq->geo.x = ATOI(args[0]);
  25. sq->geo.y = ATOI(args[1]);
  26. *shift = 1;
  27. }
  28. return sq;
  29. }
  30. /* Parse mousebind sequence next normal sequence: \<seq>[](button;func;cmd) */
  31. static char*
  32. status_parse_mouse(struct status_seq *sq, struct element *e, char *str)
  33. {
  34. struct mousebind *m;
  35. struct barwin *b = SLIST_FIRST(&e->bars);
  36. char *end, *arg[3] = { NULL };
  37. int i;
  38. if(*str != '(' || !(end = strchr(str, ')')))
  39. return str + 1;
  40. i = parse_args(++str, ';', ')', 3, arg);
  41. m = xcalloc(1, sizeof(struct mousebind));
  42. m->use_area = true;
  43. m->button = ATOI(arg[0]);
  44. m->func = uicb_name_func(arg[1]);
  45. m->cmd = (i > 1 ? xstrdup(arg[2]) : NULL);
  46. SLIST_INSERT_HEAD(&b->mousebinds, m, next);
  47. SLIST_INSERT_HEAD(&sq->mousebinds, m, snext);
  48. return end + 1;
  49. }
  50. #define STATUS_CHECK_ARGS(i, n1, n2, str, end) \
  51. if(i != n1 && i != n2) \
  52. { \
  53. str = end + 2; \
  54. continue; \
  55. }
  56. static void
  57. status_parse(struct element *e)
  58. {
  59. struct status_seq *sq, *prev = NULL;
  60. int i, shift = 0;
  61. char *dstr = xstrdup(e->infobar->status), *sauv = dstr;
  62. char type, *p, *end, *arg[6] = { NULL };
  63. for(; *dstr; ++dstr)
  64. {
  65. /* Check if this is a sequence */
  66. if(*dstr != '\\')
  67. continue;
  68. p = ++dstr;
  69. if(!(strchr("sRi", *p)) || !(end = strchr(p, ']')))
  70. continue;
  71. /* Then parse & list it */
  72. switch((type = *p))
  73. {
  74. /*
  75. * Text sequence: \s[left/right;#color;text] OR \s[x;y;#color;text]
  76. */
  77. case 's':
  78. i = parse_args(p + 2, ';', ']', 4, arg);
  79. STATUS_CHECK_ARGS(i, 2, 3, dstr, end);
  80. sq = status_new_seq(type, i, 2, arg, &shift);
  81. sq->color = color_atoh(arg[1 + shift]);
  82. sq->str = xstrdup(arg[2 + shift]);
  83. break;
  84. /*
  85. * Rectangle sequence: \R[left/right;w;h;#color] OR \R[x;y;w;h;#color]
  86. */
  87. case 'R':
  88. i = parse_args(p + 2, ';', ']', 5, arg);
  89. STATUS_CHECK_ARGS(i, 3, 4, dstr, end);
  90. sq = status_new_seq(type, i, 3, arg, &shift);
  91. sq->geo.w = ATOI(arg[1 + shift]);
  92. sq->geo.h = ATOI(arg[2 + shift]);
  93. sq->color = color_atoh(arg[3 + shift]);
  94. break;
  95. /*
  96. * Image sequence: \i[left/right;w;h;/path/img] OR \i[x;y;w;h;/path/img]
  97. */
  98. #ifdef HAVE_IMLIB2
  99. case 'i':
  100. i = parse_args(p + 2, ';', ']', 5, arg);
  101. STATUS_CHECK_ARGS(i, 3, 4, dstr, end);
  102. sq = status_new_seq(type, i, 3, arg, &shift);
  103. sq->geo.w = ATOI(arg[1 + shift]);
  104. sq->geo.h = ATOI(arg[2 + shift]);
  105. sq->str = xstrdup(arg[3 + shift]);
  106. break;
  107. #endif /* HAVE_IMLIB2 */
  108. }
  109. SLIST_INSERT_TAIL(&e->infobar->statushead, sq, next, prev);
  110. /*
  111. * Optional mousebind sequence(s) \<seq>[](button;func;cmd)
  112. * Parse it while there is a mousebind sequence.
  113. */
  114. dstr = ++end;
  115. while((*(dstr = status_parse_mouse(sq, e, dstr)) == '('));
  116. prev = sq;
  117. }
  118. free(sauv);
  119. }
  120. #define STATUS_ALIGN(align) \
  121. if(align == Left) \
  122. { \
  123. sq->geo.x = left; \
  124. left += sq->geo.w; \
  125. } \
  126. else if(align == Right) \
  127. { \
  128. sq->geo.x = e->geo.w - right - sq->geo.w; \
  129. right += sq->geo.w; \
  130. }
  131. static void
  132. status_apply_list(struct element *e)
  133. {
  134. struct status_seq *sq;
  135. struct barwin *b = SLIST_FIRST(&e->bars);
  136. struct mousebind *m;
  137. int left = 0, right = 0, w, h;
  138. SLIST_FOREACH(sq, &e->infobar->statushead, next)
  139. {
  140. switch(sq->type)
  141. {
  142. /* Text */
  143. case 's':
  144. sq->geo.w = draw_textw(e->infobar->theme, sq->str);
  145. sq->geo.h = e->infobar->theme->font.height;
  146. if(sq->align != NoAlign)
  147. sq->geo.y = TEXTY(e->infobar->theme, e->geo.h);
  148. STATUS_ALIGN(sq->align);
  149. draw_text(b->dr, e->infobar->theme, sq->geo.x, sq->geo.y, sq->color, sq->str);
  150. if(!SLIST_EMPTY(&sq->mousebinds))
  151. SLIST_FOREACH(m, &sq->mousebinds, snext)
  152. {
  153. m->area = sq->geo;
  154. m->area.y -= sq->geo.h;
  155. }
  156. break;
  157. /* Rectangle */
  158. case 'R':
  159. if(sq->align != NoAlign)
  160. sq->geo.y = (e->geo.h >> 1) - (sq->geo.h >> 1);
  161. STATUS_ALIGN(sq->align);
  162. draw_rect(b->dr, &sq->geo, sq->color);
  163. if(!SLIST_EMPTY(&sq->mousebinds))
  164. SLIST_FOREACH(m, &sq->mousebinds, snext)
  165. m->area = sq->geo;
  166. break;
  167. /* Image */
  168. #ifdef HAVE_IMLIB2
  169. case 'i':
  170. draw_image_get_size(sq->str, &w, &h);
  171. if(sq->geo.w <= 0)
  172. sq->geo.w = w;
  173. if(sq->geo.h <= 0)
  174. sq->geo.h = h;
  175. if(sq->align != NoAlign)
  176. sq->geo.y = (e->geo.h >> 1) - (sq->geo.h >> 1);
  177. STATUS_ALIGN(sq->align);
  178. draw_image(b->dr, &sq->geo, sq->str);
  179. if(!SLIST_EMPTY(&sq->mousebinds))
  180. SLIST_FOREACH(m, &sq->mousebinds, snext)
  181. m->area = sq->geo;
  182. break;
  183. #endif /* HAVE_IMLIB2 */
  184. }
  185. }
  186. }
  187. /* Render current statustext of an element */
  188. void
  189. status_render(struct element *e)
  190. {
  191. struct barwin *b = SLIST_FIRST(&e->bars);
  192. if(!e->infobar->status)
  193. return;
  194. barwin_refresh_color(b);
  195. /* Use simple text instead sequence if no sequence found */
  196. if(SLIST_EMPTY(&e->infobar->statushead))
  197. {
  198. int l = draw_textw(e->infobar->theme, e->infobar->status);
  199. draw_text(b->dr, e->infobar->theme, e->geo.w - l,
  200. TEXTY(e->infobar->theme, e->geo.h), b->fg, e->infobar->status);
  201. }
  202. else
  203. status_apply_list(e);
  204. barwin_refresh(b);
  205. }
  206. /* Parse and render statustext */
  207. void
  208. status_manage(struct element *e)
  209. {
  210. struct status_seq *sq;
  211. struct mousebind *m;
  212. struct barwin *b = SLIST_FIRST(&e->bars);
  213. /*
  214. * Flush previous linked list of status sequences
  215. * and mousebind of status barwin
  216. */
  217. while(!SLIST_EMPTY(&e->infobar->statushead))
  218. {
  219. sq = SLIST_FIRST(&e->infobar->statushead);
  220. SLIST_REMOVE_HEAD(&e->infobar->statushead, next);
  221. free(sq->str);
  222. free(sq);
  223. }
  224. while(!SLIST_EMPTY(&b->mousebinds))
  225. {
  226. m = SLIST_FIRST(&b->mousebinds);
  227. SLIST_REMOVE_HEAD(&b->mousebinds, next);
  228. free((void*)m->cmd);
  229. free(m);
  230. }
  231. status_parse(e);
  232. status_render(e);
  233. }
  234. /* Syntax: "<infobar name> <status string>" */
  235. void
  236. uicb_status(Uicb cmd)
  237. {
  238. struct infobar *ib;
  239. struct screen *s;
  240. char *p;
  241. if(!cmd || !(p = strchr(cmd, ' ')))
  242. return;
  243. /* Get infobar name & status */
  244. *p = '\0';
  245. ++p;
  246. SLIST_FOREACH(s, &W->h.screen, next)
  247. {
  248. SLIST_FOREACH(ib, &s->infobars, next)
  249. if(!strcmp(cmd, ib->name))
  250. {
  251. free(ib->status);
  252. ib->status = xstrdup(p);
  253. infobar_elem_screen_update(s, ElemStatus);
  254. }
  255. }
  256. }