winwatch.c 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <draw.h>
  4. #include <event.h>
  5. #include <regexp.h>
  6. typedef struct Win Win;
  7. struct Win {
  8. int n;
  9. int dirty;
  10. char *label;
  11. Rectangle r;
  12. };
  13. Reprog *exclude = nil;
  14. Win *win;
  15. int nwin;
  16. int mwin;
  17. int onwin;
  18. int rows, cols;
  19. Font *font;
  20. Image *lightblue;
  21. enum {
  22. PAD = 3,
  23. MARGIN = 5
  24. };
  25. void*
  26. erealloc(void *v, ulong n)
  27. {
  28. v = realloc(v, n);
  29. if(v == nil)
  30. sysfatal("out of memory reallocating %lud", n);
  31. return v;
  32. }
  33. void*
  34. emalloc(ulong n)
  35. {
  36. void *v;
  37. v = malloc(n);
  38. if(v == nil)
  39. sysfatal("out of memory allocating %lud", n);
  40. memset(v, 0, n);
  41. return v;
  42. }
  43. char*
  44. estrdup(char *s)
  45. {
  46. int l;
  47. char *t;
  48. if (s == nil)
  49. return nil;
  50. l = strlen(s)+1;
  51. t = emalloc(l);
  52. memcpy(t, s, l);
  53. return t;
  54. }
  55. void
  56. refreshwin(void)
  57. {
  58. char label[128];
  59. int i, fd, lfd, n, nr, nw, m;
  60. Dir *pd;
  61. if((fd = open("/dev/wsys", OREAD)) < 0)
  62. return;
  63. nw = 0;
  64. /* i'd rather read one at a time but rio won't let me */
  65. while((nr=dirread(fd, &pd)) > 0){
  66. for(i=0; i<nr; i++){
  67. n = atoi(pd[i].name);
  68. sprint(label, "/dev/wsys/%d/label", n);
  69. if((lfd = open(label, OREAD)) < 0)
  70. continue;
  71. m = read(lfd, label, sizeof(label)-1);
  72. close(lfd);
  73. if(m < 0)
  74. continue;
  75. label[m] = '\0';
  76. if(exclude != nil && regexec(exclude,label,nil,0))
  77. continue;
  78. if(nw < nwin && win[nw].n == n && strcmp(win[nw].label, label)==0){
  79. nw++;
  80. continue;
  81. }
  82. if(nw < nwin){
  83. free(win[nw].label);
  84. win[nw].label = nil;
  85. }
  86. if(nw >= mwin){
  87. mwin += 8;
  88. win = erealloc(win, mwin*sizeof(win[0]));
  89. }
  90. win[nw].n = n;
  91. win[nw].label = estrdup(label);
  92. win[nw].dirty = 1;
  93. win[nw].r = Rect(0,0,0,0);
  94. nw++;
  95. }
  96. free(pd);
  97. }
  98. while(nwin > nw)
  99. free(win[--nwin].label);
  100. nwin = nw;
  101. close(fd);
  102. }
  103. void
  104. drawnowin(int i)
  105. {
  106. Rectangle r;
  107. r = Rect(0,0,(Dx(screen->r)-2*MARGIN+PAD)/cols-PAD, font->height);
  108. r = rectaddpt(rectaddpt(r, Pt(MARGIN+(PAD+Dx(r))*(i/rows),
  109. MARGIN+(PAD+Dy(r))*(i%rows))), screen->r.min);
  110. draw(screen, insetrect(r, -1), lightblue, nil, ZP);
  111. }
  112. void
  113. drawwin(int i)
  114. {
  115. draw(screen, win[i].r, lightblue, nil, ZP);
  116. _string(screen, addpt(win[i].r.min, Pt(2,0)), display->black, ZP,
  117. font, win[i].label, nil, strlen(win[i].label),
  118. win[i].r, nil, ZP, SoverD);
  119. border(screen, win[i].r, 1, display->black, ZP);
  120. win[i].dirty = 0;
  121. }
  122. int
  123. geometry(void)
  124. {
  125. int i, ncols, z;
  126. Rectangle r;
  127. z = 0;
  128. rows = (Dy(screen->r)-2*MARGIN+PAD)/(font->height+PAD);
  129. if(rows*cols < nwin || rows*cols >= nwin*2){
  130. ncols = nwin <= 0 ? 1 : (nwin+rows-1)/rows;
  131. if(ncols != cols){
  132. cols = ncols;
  133. z = 1;
  134. }
  135. }
  136. r = Rect(0,0,(Dx(screen->r)-2*MARGIN+PAD)/cols-PAD, font->height);
  137. for(i=0; i<nwin; i++)
  138. win[i].r = rectaddpt(rectaddpt(r, Pt(MARGIN+(PAD+Dx(r))*(i/rows),
  139. MARGIN+(PAD+Dy(r))*(i%rows))), screen->r.min);
  140. return z;
  141. }
  142. void
  143. redraw(Image *screen, int all)
  144. {
  145. int i;
  146. all |= geometry();
  147. if(all)
  148. draw(screen, screen->r, lightblue, nil, ZP);
  149. for(i=0; i<nwin; i++)
  150. if(all || win[i].dirty)
  151. drawwin(i);
  152. if(!all)
  153. for(; i<onwin; i++)
  154. drawnowin(i);
  155. onwin = nwin;
  156. }
  157. void
  158. eresized(int new)
  159. {
  160. if(new && getwindow(display, Refmesg) < 0)
  161. fprint(2,"can't reattach to window");
  162. geometry();
  163. redraw(screen, 1);
  164. }
  165. void
  166. click(Mouse m)
  167. {
  168. int fd, i, j;
  169. char buf[128];
  170. if(m.buttons == 0 || (m.buttons & ~4))
  171. return;
  172. for(i=0; i<nwin; i++)
  173. if(ptinrect(m.xy, win[i].r))
  174. break;
  175. if(i == nwin)
  176. return;
  177. do
  178. m = emouse();
  179. while(m.buttons == 4);
  180. if(m.buttons != 0){
  181. do
  182. m = emouse();
  183. while(m.buttons);
  184. return;
  185. }
  186. for(j=0; j<nwin; j++)
  187. if(ptinrect(m.xy, win[j].r))
  188. break;
  189. if(j != i)
  190. return;
  191. sprint(buf, "/dev/wsys/%d/wctl", win[i].n);
  192. if((fd = open(buf, OWRITE)) < 0)
  193. return;
  194. write(fd, "unhide\n", 7);
  195. write(fd, "top\n", 4);
  196. write(fd, "current\n", 8);
  197. close(fd);
  198. }
  199. void
  200. usage(void)
  201. {
  202. fprint(2, "usage: winwatch [-e exclude] [-f font]\n");
  203. exits("usage");
  204. }
  205. void
  206. main(int argc, char **argv)
  207. {
  208. char *fontname;
  209. int Etimer;
  210. Event e;
  211. fontname = "/lib/font/bit/lucidasans/unicode.8.font";
  212. ARGBEGIN{
  213. case 'f':
  214. fontname = EARGF(usage());
  215. break;
  216. case 'e':
  217. exclude = regcomp(EARGF(usage()));
  218. if(exclude == nil)
  219. sysfatal("Bad regexp");
  220. break;
  221. default:
  222. usage();
  223. }ARGEND
  224. if(argc)
  225. usage();
  226. initdraw(0, 0, "winwatch");
  227. lightblue = allocimagemix(display, DPalebluegreen, DWhite);
  228. if(lightblue == nil)
  229. sysfatal("allocimagemix: %r");
  230. if((font = openfont(display, fontname)) == nil)
  231. sysfatal("font '%s' not found", fontname);
  232. refreshwin();
  233. redraw(screen, 1);
  234. einit(Emouse|Ekeyboard);
  235. Etimer = etimer(0, 5000);
  236. for(;;){
  237. switch(eread(Emouse|Ekeyboard|Etimer, &e)){
  238. case Ekeyboard:
  239. if(e.kbdc==0x7F || e.kbdc=='q')
  240. exits(0);
  241. break;
  242. case Emouse:
  243. if(e.mouse.buttons)
  244. click(e.mouse);
  245. break;
  246. default: /* Etimer */
  247. refreshwin();
  248. redraw(screen, 0);
  249. break;
  250. }
  251. }
  252. }