status.c 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380
  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. 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. struct status_ctx
  31. status_new_ctx(struct barwin *b, struct theme *t)
  32. {
  33. struct status_ctx ctx = { .barwin = b, .theme = t };
  34. SLIST_INIT(&ctx.statushead);
  35. return ctx;
  36. }
  37. void
  38. status_free_ctx(struct status_ctx *ctx)
  39. {
  40. free(ctx->status);
  41. if(ctx->barwin)
  42. SLIST_INIT(&ctx->barwin->statusmousebinds);
  43. status_flush_list(ctx);
  44. }
  45. /* Parse mousebind sequence next normal sequence: \<seq>[](button;func;cmd) */
  46. static char*
  47. status_parse_mouse(struct status_seq *sq, char *str)
  48. {
  49. struct mousebind *m;
  50. char *end, *arg[3] = { NULL };
  51. int i;
  52. if(*str != '(' || !(end = strchr(str, ')')))
  53. return str;
  54. i = parse_args(++str, ';', ')', 3, arg);
  55. m = xcalloc(1, sizeof(struct mousebind));
  56. m->use_area = true;
  57. m->button = ATOI(arg[0]);
  58. m->func = uicb_name_func(arg[1]);
  59. m->cmd = (i > 1 ? xstrdup(arg[2]) : NULL);
  60. SLIST_INSERT_HEAD(&sq->mousebinds, m, snext);
  61. return end + 1;
  62. }
  63. #define STATUS_CHECK_ARGS(i, n1, n2, str, end) \
  64. if(i != n1 && i != n2) \
  65. { \
  66. str = end + 2; \
  67. continue; \
  68. }
  69. void
  70. status_parse(struct status_ctx *ctx)
  71. {
  72. struct status_seq *sq, *prev = NULL;
  73. int i, shift = 0;
  74. char *dstr = xstrdup(ctx->status), *sauv = dstr;
  75. char type, *p, *pp, *end, *arg[6] = { NULL };
  76. for(; *dstr; ++dstr)
  77. {
  78. /* Check if this is a sequence */
  79. if(*dstr != '^' && *dstr != '\\')
  80. continue;
  81. p = ++dstr;
  82. /* Search for correct end of sequence (] without \ behind) */
  83. if((end = strchr(p, ']')))
  84. while(*(end - 1) == '\\')
  85. end = strchr(end + 1, ']');
  86. if(!(strchr("sRi", *p)) || !end)
  87. continue;
  88. /* Then parse & list it */
  89. switch((type = *p))
  90. {
  91. /*
  92. * Text sequence: \s[left/right;#color;text] OR \s[x;y;#color;text]
  93. */
  94. case 's':
  95. i = parse_args(p + 2, ';', ']', 4, arg);
  96. STATUS_CHECK_ARGS(i, 2, 3, dstr, end);
  97. sq = status_new_seq(type, i, 2, arg, &shift);
  98. sq->color = color_atoh(arg[1 + shift]);
  99. sq->str = xstrdup(arg[2 + shift]);
  100. /* Remove \ from string */
  101. for(pp = sq->str; (pp = strchr(sq->str, '\\'));)
  102. memmove(pp, pp + 1, strlen(pp));
  103. break;
  104. /*
  105. * Rectangle sequence: \R[left/right;w;h;#color] OR \R[x;y;w;h;#color]
  106. */
  107. case 'R':
  108. i = parse_args(p + 2, ';', ']', 5, arg);
  109. STATUS_CHECK_ARGS(i, 3, 4, dstr, end);
  110. sq = status_new_seq(type, i, 3, arg, &shift);
  111. sq->geo.w = ATOI(arg[1 + shift]);
  112. sq->geo.h = ATOI(arg[2 + shift]);
  113. sq->color = color_atoh(arg[3 + shift]);
  114. break;
  115. /*
  116. * Image sequence: \i[left/right;w;h;/path/img] OR \i[x;y;w;h;/path/img]
  117. */
  118. #ifdef HAVE_IMLIB2
  119. case 'i':
  120. i = parse_args(p + 2, ';', ']', 5, arg);
  121. STATUS_CHECK_ARGS(i, 3, 4, dstr, end);
  122. sq = status_new_seq(type, i, 3, arg, &shift);
  123. sq->geo.w = ATOI(arg[1 + shift]);
  124. sq->geo.h = ATOI(arg[2 + shift]);
  125. sq->str = xstrdup(arg[3 + shift]);
  126. break;
  127. #endif /* HAVE_IMLIB2 */
  128. }
  129. if (sq->align == Right)
  130. SLIST_INSERT_HEAD(&ctx->statushead, sq, next);
  131. else
  132. SLIST_INSERT_TAIL(&ctx->statushead, sq, next, prev);
  133. /*
  134. * Optional mousebind sequence(s) \<seq>[](button;func;cmd)
  135. * Parse it while there is a mousebind sequence.
  136. */
  137. dstr = end + 1;
  138. do
  139. dstr = status_parse_mouse(sq, dstr);
  140. while(*dstr == '(');
  141. --dstr;
  142. prev = sq;
  143. }
  144. free(sauv);
  145. }
  146. #define STATUS_ALIGN(align) \
  147. if(align == Left) \
  148. { \
  149. sq->geo.x = left; \
  150. left += sq->geo.w; \
  151. } \
  152. else if(align == Right) \
  153. { \
  154. sq->geo.x = ctx->barwin->geo.w - right - sq->geo.w; \
  155. right += sq->geo.w; \
  156. }
  157. static void
  158. status_apply_list(struct status_ctx *ctx)
  159. {
  160. struct status_seq *sq;
  161. struct mousebind *m;
  162. int left = 0, right = 0, w, h;
  163. SLIST_FOREACH(sq, &ctx->statushead, next)
  164. {
  165. switch(sq->type)
  166. {
  167. /* Text */
  168. case 's':
  169. sq->geo.w = draw_textw(ctx->theme, sq->str);
  170. sq->geo.h = ctx->theme->font.height;
  171. if(sq->align != NoAlign)
  172. sq->geo.y = TEXTY(ctx->theme, ctx->barwin->geo.h);
  173. STATUS_ALIGN(sq->align);
  174. draw_text(ctx->barwin->dr, ctx->theme, sq->geo.x, sq->geo.y, sq->color, sq->str);
  175. if(!SLIST_EMPTY(&sq->mousebinds))
  176. SLIST_FOREACH(m, &sq->mousebinds, snext)
  177. {
  178. m->area = sq->geo;
  179. m->area.y -= sq->geo.h;
  180. }
  181. break;
  182. /* Rectangle */
  183. case 'R':
  184. if(sq->align != NoAlign)
  185. sq->geo.y = (ctx->barwin->geo.h >> 1) - (sq->geo.h >> 1);
  186. STATUS_ALIGN(sq->align);
  187. draw_rect(ctx->barwin->dr, &sq->geo, sq->color);
  188. if(!SLIST_EMPTY(&sq->mousebinds))
  189. SLIST_FOREACH(m, &sq->mousebinds, snext)
  190. m->area = sq->geo;
  191. break;
  192. /* Image */
  193. #ifdef HAVE_IMLIB2
  194. case 'i':
  195. draw_image_load(sq->str, &w, &h);
  196. if(sq->geo.w <= 0)
  197. sq->geo.w = w;
  198. if(sq->geo.h <= 0)
  199. sq->geo.h = h;
  200. if(sq->align != NoAlign)
  201. sq->geo.y = (ctx->barwin->geo.h >> 1) - (sq->geo.h >> 1);
  202. STATUS_ALIGN(sq->align);
  203. draw_image(ctx->barwin->dr, &sq->geo);
  204. if(!SLIST_EMPTY(&sq->mousebinds))
  205. SLIST_FOREACH(m, &sq->mousebinds, snext)
  206. m->area = sq->geo;
  207. break;
  208. #endif /* HAVE_IMLIB2 */
  209. }
  210. }
  211. }
  212. /* Render current statustext of an element */
  213. void
  214. status_render(struct status_ctx *ctx)
  215. {
  216. if(!ctx->status)
  217. return;
  218. barwin_refresh_color(ctx->barwin);
  219. /* Use simple text instead sequence if no sequence found */
  220. if(SLIST_EMPTY(&ctx->statushead))
  221. {
  222. int l = draw_textw(ctx->theme, ctx->status);
  223. draw_text(ctx->barwin->dr, ctx->theme, ctx->barwin->geo.w - l,
  224. TEXTY(ctx->theme, ctx->barwin->geo.h), ctx->barwin->fg, ctx->status);
  225. }
  226. else
  227. status_apply_list(ctx);
  228. barwin_refresh(ctx->barwin);
  229. }
  230. void
  231. status_flush_list(struct status_ctx *ctx)
  232. {
  233. struct status_seq *sq;
  234. struct mousebind *m;
  235. /* Flush previous linked list of status sequences */
  236. while(!SLIST_EMPTY(&ctx->statushead))
  237. {
  238. sq = SLIST_FIRST(&ctx->statushead);
  239. SLIST_REMOVE_HEAD(&ctx->statushead, next);
  240. while(!SLIST_EMPTY(&sq->mousebinds))
  241. {
  242. m = SLIST_FIRST(&sq->mousebinds);
  243. SLIST_REMOVE_HEAD(&sq->mousebinds, snext);
  244. free((void*)m->cmd);
  245. free(m);
  246. }
  247. free(sq->str);
  248. free(sq);
  249. }
  250. }
  251. void
  252. status_copy_mousebind(struct status_ctx *ctx)
  253. {
  254. struct mousebind *m;
  255. struct status_seq *sq;
  256. if(!ctx->barwin)
  257. return;
  258. /* Flush barwin head of status mousebinds */
  259. SLIST_INIT(&ctx->barwin->statusmousebinds);
  260. SLIST_FOREACH(sq, &ctx->statushead, next)
  261. {
  262. SLIST_FOREACH(m, &sq->mousebinds, snext)
  263. SLIST_INSERT_HEAD(&ctx->barwin->statusmousebinds, m, next);
  264. }
  265. }
  266. /* Parse and render statustext */
  267. void
  268. status_manage(struct status_ctx *ctx)
  269. {
  270. if(!ctx->status)
  271. return;
  272. ctx->update = false;
  273. status_flush_list(ctx);
  274. status_parse(ctx);
  275. status_render(ctx);
  276. status_copy_mousebind(ctx);
  277. }
  278. /* Syntax: "<infobar name> <status string>" */
  279. void
  280. uicb_status(Uicb cmd)
  281. {
  282. struct infobar *ib;
  283. struct screen *s;
  284. char *p;
  285. if(!cmd || !(p = strchr(cmd, ' ')))
  286. return;
  287. /* Get infobar name & status */
  288. *p = '\0';
  289. ++p;
  290. SLIST_FOREACH(s, &W->h.screen, next)
  291. {
  292. SLIST_FOREACH(ib, &s->infobars, next)
  293. if(!strcmp(cmd, ib->name))
  294. {
  295. free(ib->statusctx.status);
  296. ib->statusctx.status = xstrdup(p);
  297. ib->statusctx.update = true;
  298. infobar_elem_screen_update(s, ElemStatus);
  299. }
  300. }
  301. }