bspwm.c 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  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 ((nb = recv(*fd, rsp, sizeof(rsp) - 1, 0)) > 0) {
  116. if (*rsp == FAILURE_MESSAGE)
  117. warn("%s", rsp + 1);
  118. else
  119. parse_event(rsp, nb, out, BUFF_SZ);
  120. } else {
  121. ERRRET(out);
  122. }
  123. }
  124. }
  125. static void
  126. parse_event(const char *event, size_t size, char *out, size_t out_size)
  127. {
  128. size_t i, j;
  129. uint8_t is_desktop = 0, is_focused = 0;
  130. for (i = j = 0; i < size && j < out_size; i -= -1) {
  131. if (event[i] == ':') {
  132. switch (event[i + 1]) {
  133. case 'o':
  134. # if defined(BSPWM_SHOW_VACANT_TAGS)
  135. case 'f':
  136. # endif /* BSPWM_SHOW_VACANT_TAGS */
  137. END_FOCUS(is_focused, out, out_size, j);
  138. ADD_DELIM(out, out_size, j);
  139. DESKTOP_END(is_desktop);
  140. case 'F':
  141. case 'O':
  142. is_focused = !0;
  143. ADD_DELIM(out, out_size, j);
  144. memcpy(out + j, WITH_LEN(FOCUSED_PREFIX));
  145. j += sizeof(FOCUSED_PREFIX) - 1;
  146. DESKTOP_END(is_desktop);
  147. default:
  148. is_desktop = 0;
  149. END_FOCUS(is_focused, out, out_size, j);
  150. }
  151. i++;
  152. continue;
  153. } else if (!is_desktop) {
  154. continue;
  155. }
  156. out[j++] = event[i];
  157. }
  158. out[j] = '\0';
  159. }
  160. #endif /* USE_X */