bspwm.c 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. #include <err.h>
  2. #include <poll.h>
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include <stdint.h>
  6. #include <string.h>
  7. #include <unistd.h>
  8. #include <sys/un.h>
  9. #include <sys/stat.h>
  10. #include <sys/types.h>
  11. #include <sys/socket.h>
  12. #if USE_X
  13. # include <xcb/xcb.h>
  14. #endif
  15. #include "../lib/util.h"
  16. #include "../aslstatus.h"
  17. #include "../components_config.h"
  18. #ifndef BSPWM_FOCUSED_RESET
  19. # define BSPWM_FOCUSED_RESET "%{F-}%{B-}"
  20. #endif
  21. #ifndef BSPWM_FOCUSED_FG
  22. # define BSPWM_FOCUSED_FG "#0ff"
  23. #endif
  24. #ifndef BSPWM_FOCUSED_BG
  25. # define BSPWM_FOCUSED_BG "-"
  26. #endif
  27. #ifndef BSPWM_DELIM
  28. # define BSPWM_DELIM ' '
  29. #endif
  30. #define FAILURE_MESSAGE '\x07'
  31. #define SOCKET_ENV_VAR "BSPWM_SOCKET"
  32. #define SOCKET_PATH_TPL "/tmp/bspwm%s_%i_%i-socket"
  33. #define FOCUSED_PREFIX "%{F" BSPWM_FOCUSED_FG "}%{B" BSPWM_FOCUSED_BG "}"
  34. #define WITH_LEN(S) S, LEN(S)
  35. #define DESKTOP_END(D) \
  36. (D) = !0; \
  37. break
  38. /*
  39. * add delimiter if not first char
  40. * O out
  41. * S out size
  42. * I index
  43. */
  44. #define ADD_DELIM(O, S, I) \
  45. do { \
  46. if (((I) + 1) > S) ERRRET(O); \
  47. (O)[(I)] = BSPWM_DELIM; \
  48. ((I) += !!(I)); \
  49. } while (0)
  50. /* add FOCUSED_RESET if end of focused desktop
  51. * F `is_focused` identifier */
  52. #define END_FOCUS(F, O, S, I) \
  53. do { \
  54. if (!!(F)) { \
  55. (F) = !(F); \
  56. size_t _len; \
  57. if ((_len = sizeof(BSPWM_FOCUSED_RESET) - 1) > (S)) \
  58. ERRRET(O); \
  59. memcpy((O) + (I), BSPWM_FOCUSED_RESET, _len); \
  60. (I) += _len; \
  61. } \
  62. } while (0)
  63. #if USE_X
  64. static void parse_event(const char *, size_t, char *, size_t);
  65. void
  66. bspwm_ws(char *out,
  67. const char __unused *_a,
  68. uint32_t __unused _i,
  69. static_data_t *static_data)
  70. {
  71. char *sp, rsp[BUFSIZ];
  72. int nb, *fd = static_data->data;
  73. struct sockaddr_un sock_address;
  74. if (!static_data->cleanup) static_data->cleanup = fd_cleanup;
  75. if (!!*fd) goto run;
  76. sock_address.sun_family = AF_UNIX;
  77. if ((sp = getenv(SOCKET_ENV_VAR))) {
  78. snprintf(sock_address.sun_path,
  79. sizeof(sock_address.sun_path),
  80. "%s",
  81. sp);
  82. } else {
  83. int dn = 0, sn = 0;
  84. char *host = NULL;
  85. if (xcb_parse_display(NULL, &host, &dn, &sn))
  86. snprintf(sock_address.sun_path,
  87. sizeof(sock_address.sun_path),
  88. SOCKET_PATH_TPL,
  89. host,
  90. dn,
  91. sn);
  92. else
  93. ERRRET(out);
  94. free(host);
  95. }
  96. if ((*fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
  97. warn("Failed to create socket");
  98. ERRRET(out);
  99. }
  100. if (connect(*fd,
  101. (struct sockaddr *)&sock_address,
  102. sizeof(sock_address))
  103. == -1) {
  104. warn("Failed to connect to socket");
  105. ERRRET(out);
  106. }
  107. if (send(*fd, WITH_LEN("subscribe"), 0) == -1) {
  108. warn("Failed to subscribe to socket");
  109. ERRRET(out);
  110. }
  111. struct pollfd poll_fd = { *fd, POLLIN, 0 };
  112. run:
  113. if (poll(&poll_fd, 1, -1) > 0)
  114. if (poll_fd.revents & POLLIN) {
  115. if (SAFE_ASSIGN(nb, recv(*fd, rsp, sizeof(rsp) - 1, 0))
  116. > 0) {
  117. if (*rsp == FAILURE_MESSAGE)
  118. warn("%s", rsp + 1);
  119. else
  120. parse_event(rsp,
  121. (size_t)nb,
  122. out,
  123. BUFF_SZ);
  124. } else {
  125. ERRRET(out);
  126. }
  127. }
  128. }
  129. static void
  130. parse_event(const char *event, size_t size, char *out, size_t out_size)
  131. {
  132. size_t i, j;
  133. uint8_t is_desktop = 0, is_focused = 0;
  134. for (i = j = 0; i < size && j < out_size; i++) {
  135. if (event[i] == ':') {
  136. switch (event[i + 1]) {
  137. case 'o':
  138. # if defined(BSPWM_SHOW_VACANT_TAGS)
  139. case 'f':
  140. # endif /* BSPWM_SHOW_VACANT_TAGS */
  141. END_FOCUS(is_focused, out, out_size, j);
  142. ADD_DELIM(out, out_size, j);
  143. DESKTOP_END(is_desktop);
  144. case 'F':
  145. case 'O':
  146. is_focused = !0;
  147. ADD_DELIM(out, out_size, j);
  148. memcpy(out + j, WITH_LEN(FOCUSED_PREFIX));
  149. j += sizeof(FOCUSED_PREFIX) - 1;
  150. DESKTOP_END(is_desktop);
  151. default:
  152. is_desktop = 0;
  153. END_FOCUS(is_focused, out, out_size, j);
  154. }
  155. i++;
  156. continue;
  157. } else if (!is_desktop) {
  158. continue;
  159. }
  160. out[j++] = event[i];
  161. }
  162. out[j] = '\0';
  163. }
  164. #endif /* USE_X */