winwatch.c 5.2 KB

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