wmclockmon: update change-log
[dockapps.git] / wmhdplop / wmhdplop.c
blobbbbe971e12d535ee7540e68b31362bdc88d54d31
1 /*
2 This program is free software; you can redistribute it and/or modify
3 it under the terms of the GNU General Public License as published by
4 the Free Software Foundation; either version 2 of the License, or
5 (at your option) any later version.
7 This program is distributed in the hope that it will be useful,
8 but WITHOUT ANY WARRANTY; without even the implied warranty of
9 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 GNU General Public License for more details.
12 You should have received a copy of the GNU General Public License
13 along with this program; if not, write to the Free Software
14 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
15 USA.
18 #include "config.h"
19 #include <string.h>
20 #include <sys/types.h>
21 #include <sys/stat.h>
22 #include <dirent.h>
23 #include <fcntl.h>
24 #include <limits.h>
25 #include <unistd.h>
26 #include <time.h>
27 #include <math.h>
28 #include <ctype.h>
29 #include <errno.h>
30 #include <getopt.h>
31 #ifdef ENABLE_HDDTEMP_QUERY
32 #include <sys/socket.h>
33 #include <sys/wait.h>
34 #include <netinet/in.h>
35 #include <netdb.h>
36 #endif
37 #define GLOBALS_HERE
38 #include "global.h"
39 #include "wmhdplop.h"
41 uid_t euid, uid;
45 void update_swap_matrix(App *app) {
46 SwapMatrix *sm = &app->sm;
47 unsigned i;
48 int col,row;
49 unsigned sw_in = ceil(get_swapin_throughput()*4), sw_out = ceil(get_swapout_throughput()*4);
50 for (i=0; i < sw_in+sw_out; i++) {
51 col = rand() % sm->ncol;
52 row = rand() % sm->nrow;
53 if (sm->intensity[row][col] == 0) {
54 sm->pre_cnt[row][col] = rand() % 10; //(app->update_stats_mult);
56 sm->intensity[row][col] = app->swap_matrix_lighting * ((i < sw_in) ? -1 : +1);
60 void update_io_matrix_rw(App *app, float mbs, int op) {
61 IOMatrix *io = &app->iom;
62 IO_op_lst *l;
63 if (mbs > 10000) mbs = 10000; /* very quick and ugly fix for the strange bug which only occurs in gkhdplop */
64 int bsz = MAX(SQR(16*64./(app->dock->w + app->dock->h)),2); /* 1024 for a 64x64 applet */
65 while (mbs>1e-5) {
66 float v = MIN(mbs, bsz); /* a throughput > 1MB/s will create more than one spot */
67 mbs -= v;
68 l = calloc(1,sizeof(*l)); assert(l);
69 l->next = io->ops;
70 l->n = (int)(log2f(1+v*1024)/10.);
71 l->op = op;
72 l->i = rand() % io->h;
73 l->j = rand() % io->w;
74 io->ops = l;
78 void update_io_matrix(App *app) {
79 update_io_matrix_rw(app, get_read_throughput(), OP_READ);
80 update_io_matrix_rw(app, get_write_throughput(), OP_WRITE);
83 #define IOSCAL 32768
85 void evolve_io_matrix(App *app, DATA32 * __restrict buff) {
86 IOMatrix *io = &app->iom;
87 int i,j;
88 int * __restrict pl, * __restrict tmp;
89 IO_op_lst *o = io->ops, *po = NULL, *no;
90 while (o) {
91 io->v[o->i+1][o->j+1] = ((o->op == OP_READ) ? +50000000 : -50000000);
92 no = o->next;
93 if (--o->n <= 0) {
94 if (po) { po->next = no; }
95 else { io->ops = no; }
96 free(o);
97 } else po = po->next;
98 o = no;
101 /* brain-dead diffusion */
102 pl = io->v[io->h+2];
103 int * __restrict l = io->v[io->h+3];
104 for (j=1; j < io->w+1; ++j) pl[j] = 0;
105 for (i=1; i < io->h+1; ++i) {
107 for (j=1; j < io->w+1; ++j) {
108 l[j] = io->v[i][j]*0.99 + (io->v[i][j-1] + io->v[i][j+1] + pl[j] + io->v[i+1][j] - 4*io->v[i][j])/5.;
112 float *__restrict nl = io->v[i+1]+1;
113 float *__restrict cl = io->v[i];
114 for (j=1; j < io->w+1; ++j, ++cl) {
115 l[j] = (cl[1])*0.99 + (cl[0] + cl[2] + pl[j] + *nl++ - 4*cl[1])/5.;
118 int *__restrict dest;
119 int *__restrict pn = io->v[i+1]+1;
120 int *__restrict pc = io->v[i]+1;
121 int *__restrict pp = pl+1;
122 int pj,cj=0,nj=*pc++;
123 for (j=0, dest=l+1, pj = 0.; j < io->w; ++j) {
124 pj = cj; cj = nj; nj = *pc++;
125 *dest = (cj * 37)/200 + (pj + nj + *pp++ + *pn++)/5;
126 /* *dest = 99*(cj + (pj + nj + *pp++ + *pn++)/(4))/200; */
127 //} for (j=0, dest=l+1; j < io->w; ++j) {
128 int v = (int)(*dest++ >> 10);
129 if (v == 0) { *buff++ = io->cm.p[CMAPSZ/2]; continue; }
130 if (v > CMAPSZ/4) { /* cheaper than a log(vv) ... */
131 v = MIN(CMAPSZ/4 + (v-CMAPSZ/4)/16,CMAPSZ/2-1);
132 } else if (v < -CMAPSZ/4) {
133 v = MAX(-CMAPSZ/4 + (v+CMAPSZ/4)/16,-CMAPSZ/2);
135 *buff++ = io->cm.p[v+CMAPSZ/2];
138 tmp = pl; pl = io->v[i]; io->v[i] = l; l = tmp;
139 io->v[io->h+2] = pl; io->v[io->h+3] = l;
144 #if 0
145 static void draw_io_matrix(App *app, DATA32 * __restrict buff) {
146 IOMatrix *io = &app->iom;
147 int i,j;
148 for (i=0; i < io->h; ++i) {
149 for (j=0; j < io->w; ++j) {
150 float vv = io->v[i+1][j+1];
151 int v = (int)(vv * 32768); //((int)ldexpf(vv,15)); /* (int)v*(2^15) */
152 //if (v == 0) continue;
153 //if (v < 0) v*=3; /* write op are rare, so they are brighter .. */
154 if (v > CMAPSZ/4) { /* cheaper than a log(vv) ... */
155 v = MIN(CMAPSZ/4 + (v-CMAPSZ/4)/16,CMAPSZ/2-1);
156 } else if (v < -CMAPSZ/4) {
157 v = MAX(-CMAPSZ/4 + (v+CMAPSZ/4)/16,-CMAPSZ/2);
159 //assert(v+CMAPSZ/2>=0);
160 //assert(v+CMAPSZ/2 < sizeof io->cm.p);
161 *buff++ /*[j+i*io->w]*/ = io->cm.p[v+CMAPSZ/2];
165 #endif
167 void draw_swap_matrix(App *app) {
168 SwapMatrix *sm = &app->sm;
169 int rcnt[sm->nrow+1], ccnt[sm->ncol+1];
170 int row, col;
171 int isswapping = 0;
172 static int darkcnt = 0;
173 memset(rcnt, 0, sizeof rcnt); memset(ccnt, 0, sizeof ccnt);
174 for (row = 0; row < sm->nrow; row++) {
175 for (col = 0; col < sm->ncol; col++) {
176 if (sm->pre_cnt[row][col]>0) { isswapping = 1; sm->pre_cnt[row][col]--; }
179 if (isswapping) darkcnt = MIN(darkcnt+1,7);
180 else darkcnt = MAX(darkcnt-1, 0);
182 /* darken everything */
183 if (darkcnt) {
184 imlib_context_set_color(0, 0, 0, (darkcnt+1)*16);
185 imlib_image_fill_rectangle(0, 0, app->dock->w, app->dock->h);
187 /* draw squares */
188 for (row = 0; row < sm->nrow; row++) {
189 for (col = 0; col < sm->ncol; col++) {
190 if (sm->intensity[row][col] && sm->pre_cnt[row][col]==0) {
191 int v = sm->intensity[row][col];
192 v = (v * app->swap_matrix_luminosity)/(int)app->swap_matrix_lighting;
193 rcnt[row ] = MAX(rcnt[row ],abs(v)); ccnt[col ] = MAX(ccnt[col ],abs(v));
194 rcnt[row+1] = MAX(rcnt[row+1],abs(v)); ccnt[col+1] = MAX(ccnt[col+1],abs(v));
195 //v = (v*155)/255;
196 /*if (v > 0) imlib_context_set_color(100+v, 155-v, 155-v, 250);
197 else imlib_context_set_color(0, 100-v, 0, 250);*/
198 if (v > 0) imlib_context_set_color(255, 50, 50, MIN(v+80,255));
199 else imlib_context_set_color(50, 255, 50, MIN(v+80,255));
200 imlib_image_fill_rectangle(row*sm->w+1,col*sm->w+1,sm->w-1,sm->w-1);
202 if (sm->intensity[row][col] > 0) {
203 sm->intensity[row][col]--;
204 } else if (sm->intensity[row][col] < 0) {
205 sm->intensity[row][col]++;
211 /* draw lines */
212 for (row = 0; row < sm->nrow+1; row++) {
213 if (rcnt[row]) {
214 imlib_context_set_color(255, 255, 255, MIN(rcnt[row]*2/3, 255));
215 imlib_image_draw_line(row*sm->w,0,row*sm->w,app->dock->w,0);
218 for (col = 0; col < sm->ncol+1; col++) {
219 if (ccnt[col]) {
220 imlib_context_set_color(255, 255, 255, MIN(ccnt[col]*2/3, 255));
221 imlib_image_draw_line(0,col*sm->w,app->dock->h,col*sm->w,0);
226 float f2celsius(float Tf) {
227 return (5./9.)*(Tf-32.);
230 float celsius2f(float Tc) {
231 return (9./5.)*Tc+32.;
234 static void query_hddtemp(App *app) {
235 int fd;
236 struct hostent *h;
237 struct sockaddr_in addr;
238 char buff[1024];
239 SET_VEC(app->disk_temperature, -1, 0, app->nb_hd);
240 if ((h = gethostbyname("127.0.0.1")) == NULL) {
241 fprintf(stderr, "gethostbyname(localhost) failed : %s\n", strerror(errno)); return;
243 if ((fd = socket(h->h_addrtype, SOCK_STREAM,0)) == -1) {
244 fprintf(stderr, "can't create socket : %s\n", strerror(errno)); return;
246 memset(&addr,0,sizeof(struct sockaddr_in));
247 addr.sin_family = AF_INET;
248 addr.sin_port = htons(Prefs.hddtemp_port);
249 addr.sin_addr.s_addr = ((struct in_addr*)(h->h_addr))->s_addr;
250 if (connect(fd, (struct sockaddr *)&addr, sizeof addr) < 0) {
251 close(fd);
252 fprintf(stderr,"can't connect to 127.0.0.1:%d : %s\n", Prefs.hddtemp_port, strerror(errno));
253 #ifdef GKRELLM
254 Prefs.enable_hddtemp = 0;
255 #endif
256 return;
258 int n = 0;
259 do {
260 int nn=read(fd,buff+n,MAX((int)(sizeof buff) - n,0));
261 if (nn <= 0) { if (nn < 0) n=nn; break; }
262 n+=nn;
263 } while (n != sizeof buff);
265 BLAHBLAH(2,printf("n=%d, err=%s\n",n, strerror(errno)));
266 if (n != -1) {
267 char *s;
268 DiskList *dl;
269 int cnt;
270 buff[MIN(n,(int)sizeof buff - 1)] = 0;
271 for (dl = first_hd_in_list(), cnt = 0; dl; dl = next_hd_in_list(dl), cnt++) {
272 if (dl->enable_hddtemp) {
273 int found = 0;
274 if ((s=strstr(buff, dl->dev_path))) { found = 1; s+= strlen(dl->name); }
275 if (found) {
276 s=strchr(s,'|');
277 if (s && ((s=strchr(s+1,'|')))) {
278 int unit = 'C';
279 char *p = strchr(++s,'|'), oldv=0;
280 if (p) {
281 oldv = *p;
282 if (*p && toupper(p[1]) == 'F') unit = 'F';
283 *p = 0;
285 BLAHBLAH(1,printf("temperature of '%s' : %s %c\n", dl->name, s, unit));
286 if (strcmp(s,"SLP") == 0) app->disk_temperature[cnt] = -2;
287 else {
288 int temp = atoi(s);
289 if (unit == 'C' && Prefs.temperatures_unit == 'F') {
290 temp = (int)(floor(celsius2f(temp)+.5));
291 } else if (unit == 'F' && Prefs.temperatures_unit == 'C') {
292 temp = (int)(floor(f2celsius(temp)+.5));
294 app->disk_temperature[cnt] = temp;
296 if (p) *p = oldv; /* or bug... */
298 } else {
299 ONLY_NTIMES(4,fprintf(stderr, "could not find device '%s' in the output of hddtemp: '%s'\n", dl->name, buff));
303 } else { fprintf(stderr, "error with hddtemp: %s\n", strerror(errno)); }
304 close(fd);
307 const char *power_mode_str(int m) {
308 switch (m) {
309 case HD_ACTIVE: return "active/idle";
310 case HD_STANDBY: return "standby";
311 case HD_SLEEP: return "sleep";
312 case HD_UNKNOWN:
313 default:
314 return "unknown/error";
318 void sethw(App *app, int lw, int lh, int pos, int *px, int *py, int *pw, int *ph) {
319 *px = *py = 0; *pw = lw; *ph = lh;
320 if (!(pos & (AL_RIGHT | AL_LEFT | AL_HCENTER))) *pw = app->dock->w;
321 if (pos & AL_RIGHT) *px = app->dock->w - lw;
322 else if (pos & AL_HCENTER) *px = (app->dock->w - lw)/2;
323 else if (pos & AL_LEFT) *px = 0;
324 else { *px = 0; *pw = app->dock->w; }
325 if (pos & AL_BOTTOM) *py = app->dock->h - lh;
326 else if (pos & AL_VCENTER) *py = (app->dock->h - lh)/2;
327 else if (pos & AL_TOP) *py = 0;
328 else { *py = 0; *ph = app->dock->h; }
331 static void my_imlib_text_draw(int x, int y, const char *s) {
332 char s2[100]; snprintf(s2,100,"%s ",s); /* my imlib2 often forgets half of the last character... */
333 imlib_text_draw(x,y,s2);
336 int is_displayed(int hd_id, int part_id) {
337 return (((hd_id == app->filter_hd) || (app->filter_hd == -1)) &&
338 ((part_id == app->filter_part) || (app->filter_part == -1)));
341 void change_displayed_hd(int dir) {
342 DiskList *dl = find_id(app->filter_hd, app->filter_part);
343 if (dl == NULL) {
344 app->filter_hd = -1; app->filter_part = -1;
345 dl = find_id(app->filter_hd, app->filter_part); assert(dl);
347 else if (dir > 0) {
348 if (app->filter_hd == -1 && app->filter_part == -1) {
349 app->filter_hd = -1; app->filter_part = 0;
350 } else if (app->filter_hd == -1 && app->filter_part == 0) {
351 app->filter_hd = first_dev_in_list()->hd_id;
352 app->filter_part = -1;
353 } else if (app->filter_hd != -1 && app->filter_part != -1) {
354 DiskList *dl2 = dl->next;
355 if (dl2) {
356 if (dl2->hd_id == app->filter_hd)
357 app->filter_part = dl2->part_id;
358 else {
359 app->filter_hd = dl2->hd_id;
360 app->filter_part = -1;
362 } else {
363 app->filter_hd = -1;
364 app->filter_part = -1;
366 } else if (app->filter_hd != -1) {
367 app->filter_part = dl->part_id;
368 } else {
369 app->filter_hd = dl->hd_id;
371 } else if (dir < 0) { /* very very bourin */
372 int ph, pph, pp, ppp;
373 ph = app->filter_hd; pp = app->filter_part;
374 do {
375 pph = app->filter_hd; ppp = app->filter_part;
376 change_displayed_hd(+1);
377 } while (!(app->filter_hd == ph && app->filter_part == pp));
378 app->filter_hd = pph; app->filter_part = ppp;
380 app->displayed_hd_changed = 1;
383 void next_displayed_hd() {
384 BLAHBLAH(1,printf("next_displayed_hd() : filter_hd=%d, filter_part=%d\n", app->filter_hd, app->filter_part));
385 change_displayed_hd(-1);
386 init_stats(app->update_display_delay_ms*1e-3*app->update_stats_mult);
389 void prev_displayed_hd() {
390 BLAHBLAH(1,printf("prev_displayed_hd() : filter_hd=%d, filter_part=%d\n", app->filter_hd, app->filter_part));
391 change_displayed_hd(+1);
392 init_stats(app->update_display_delay_ms*1e-3*app->update_stats_mult);
395 const char *shorten_name(DiskList *dl) {
396 static char s[8];
397 if (dl->name && strlen(dl->name)) {
398 const char *p = dl->name;
399 if (strchr(p,'/')) p = strrchr(p,'/')+1;
400 if (strlen(p) == 0) p = dl->name;
401 snprintf(s, sizeof s, "%s%s", dl->part_id ? " " : "", p);
402 } else strncpy(s, dl->name, sizeof s);
403 return s;
406 static void draw_hdlist(App *app) {
407 if (Prefs.hdlist_pos == AL_NONE) return;
408 DiskList *dl;
410 int dev_cnt, hd_cnt, w;
411 static int lw = -1, lh = -1, lx = -1, ly = -1, h = -1,
412 reshape_cnt = 0;
414 if (!app->smallfont) return;
415 if (app->displayed_hd_changed) { lx = -1; app->displayed_hd_changed = 0; }
416 imlib_context_set_font(app->smallfont);
417 /* get dimensions */
418 if (lx == -1 || reshape_cnt != app->reshape_cnt) {
419 int wtemp = 1;
420 lw = 0; lh = 0;
421 //printf("update : first displayed(%d) = %p\n", cnt, dl);
423 for (dl = first_dev_in_list(), dev_cnt=hd_cnt=-1; dl; dl = dl->next) {
424 if (dl->part_id == 0) ++hd_cnt;
425 if (!is_displayed(dl->hd_id, dl->part_id)) continue;
426 ++dev_cnt;
427 imlib_get_text_size(shorten_name(dl),&w,&h);
428 lw = MAX(w,lw);
429 lh += h;
431 if (!Prefs.disable_hd_leds) { lw += 5; }
432 if (Prefs.enable_hddtemp) imlib_get_text_size(" 000",&wtemp,&h);
433 if (lw + wtemp > (int)(app->dock->w*2/3)) { lw = app->dock->w; }
434 else lw += wtemp;
435 sethw(app,lw,lh,Prefs.hdlist_pos,&lx,&ly,&lw,&lh);
436 reshape_cnt = app->reshape_cnt;
439 imlib_context_set_color(100, 100, 100, 150);
440 imlib_image_fill_rectangle(lx,ly,lw,lh);
441 imlib_context_set_color(100, 100, 100, 200);
442 imlib_image_draw_rectangle(lx-1,ly-1,lw+2,lh+2);
444 for (dl = first_dev_in_list(), dev_cnt=hd_cnt=-1; dl; dl = dl->next) {
445 if (dl->part_id==0) ++hd_cnt;
446 if (!is_displayed(dl->hd_id, dl->part_id)) continue;
447 ++dev_cnt;
448 int x = lx, y = ly + lh - dev_cnt * h;
449 if (!Prefs.disable_hd_leds) {
450 if (dl->touched_r) {
451 imlib_context_set_color(50, 255, 50, 25*dl->touched_r--);
452 imlib_image_fill_rectangle(lx+1,y-5,3,3);
454 if (dl->touched_w) {
455 imlib_context_set_color(255,100-10*dl->touched_w,100-10*dl->touched_w, 25*dl->touched_w - 1);
456 dl->touched_w--;
457 imlib_image_fill_rectangle(lx+1,y-9,3,3);
459 x += 5;
461 imlib_context_set_color(200, 255, 255, 200);
462 my_imlib_text_draw(x,y-h,shorten_name(dl));
463 if (dl->part_id==0 && app->disk_temperature[hd_cnt] != -1) {
464 char s[200];
465 if (app->disk_temperature[hd_cnt] != -2) {
466 snprintf(s,200,"%d",app->disk_temperature[hd_cnt]);
467 } else {
468 strcpy(s,"SLP");
470 imlib_get_text_size(s,&w,&h);
471 x = lx + lw - w + ((app->disk_temperature[hd_cnt] != -2) ? -7 : -3);
472 imlib_context_set_color(255, 250, 100, 255);
473 my_imlib_text_draw(x, y-h, s);
474 imlib_context_set_color(255, 255, 255, 200);
476 /* below is a quick fix for the degree sign which is not drawn
477 properly by recent release of imlib -- many thanks to
478 Krzysztof Kotlenga for the patch */
480 //if (app->disk_temperature[hd_cnt] != -2) imlib_image_draw_ellipse(x+w+3, y - h + 2, 1, 1);
482 //if (app->disk_temperature[hd_cnt] != -2) imlib_image_draw_ellipse(x+w+3, y - h + 2, 1, 1);
483 /* imlib2 >= 1.1.1 workaround - imlib_image_draw_ellipse() can't properly draw circle with radius = 1 */
484 if (app->disk_temperature[hd_cnt] != -2) {
485 /*ImlibPolygon poly;
486 poly = imlib_polygon_new();
487 imlib_polygon_add_point(poly, x+w+3, y-h+3);
488 imlib_polygon_add_point(poly, x+w+2, y-h+2);
489 imlib_polygon_add_point(poly, x+w+3, y-h+1);
490 imlib_polygon_add_point(poly, x+w+4, y-h+2);
491 imlib_image_draw_polygon(poly, 1);*/
492 /*imlib_image_draw_pixel(x+w+3, y-h+3, 0);
493 imlib_image_draw_pixel(x+w+2, y-h+2, 0);
494 imlib_image_draw_pixel(x+w+3, y-h+1, 0);
495 imlib_image_draw_pixel(x+w+4, y-h+2, 0);*/
497 int i=x+w+2, j=y-h;
498 imlib_image_draw_pixel(i+1,j,0);
499 imlib_image_draw_pixel(i+2,j,0);
500 imlib_image_draw_pixel(i+3,j+1,0);
501 imlib_image_draw_pixel(i+3,j+2,0);
502 imlib_image_draw_pixel(i+1,j+3,0);
503 imlib_image_draw_pixel(i+2,j+3,0);
504 imlib_image_draw_pixel(i,j+1,0);
505 imlib_image_draw_pixel(i,j+2,0);
511 static void draw_throughput(App *app) {
512 static int tpstep = 0, tpw, tph;
513 static char tpmsg[20];
514 static int lw = -1, lh = -1, lx = -1, ly = -1;
515 static int reshape_cnt = 0;
516 if (Prefs.popup_throughput_pos == AL_NONE) return;
518 if (!app->bigfont) return;
519 imlib_context_set_font(app->bigfont);
520 /* get dimensions (only once) */
521 if (lx == -1 || app->reshape_cnt != reshape_cnt) {
522 imlib_get_text_size("00.0M/s",&lw,&lh);
523 if (lw > (int)(app->dock->w*3/4)) { lw = app->dock->w; }
524 sethw(app,lw,lh,Prefs.popup_throughput_pos,&lx,&ly,&lw,&lh);
525 reshape_cnt = app->reshape_cnt;
528 if (get_read_mean_throughput() + get_write_mean_throughput() > Prefs.popup_throughput_threshold) {
529 tpstep = MIN(tpstep+1,4);
530 snprintf(tpmsg,sizeof tpmsg, "%.1fM/s",get_read_mean_throughput() + get_write_mean_throughput());
531 imlib_get_text_size(tpmsg,&tpw,&tph);
532 if (tpw > lw) {
533 snprintf(tpmsg,sizeof tpmsg, "%.1fM",get_read_mean_throughput() + get_write_mean_throughput());
534 imlib_get_text_size(tpmsg,&tpw,&tph);
536 } else if (tpstep) tpstep--;
537 if (tpstep) {
538 imlib_context_set_color(128, 128, 128, tpstep*30);
539 imlib_image_draw_rectangle(lx-1,ly-1,lw+2,lh+2);
540 imlib_context_set_color(128, 128, 128, 10+tpstep*25);
541 imlib_image_fill_rectangle(lx,ly,lw,lh);
542 imlib_context_set_color(255, 255, 255, 50+tpstep*50);
543 my_imlib_text_draw(lx + (lw - tpw)/2, ly, tpmsg);
547 static void draw(App *app) {
548 DATA32 *buff = imlib_image_get_data();
550 if (!Prefs.disable_io_matrix) {
551 evolve_io_matrix(app,buff);
552 //draw_io_matrix(app,buff);
553 } else memset(buff, 0, sizeof(DATA32)*app->dock->w*app->dock->h);
554 imlib_image_put_back_data(buff);
555 draw_hdlist(app);
556 if (!Prefs.disable_swap_matrix) draw_swap_matrix(app);
557 draw_throughput(app);
560 void reshape(int w, int h) {
561 DockImlib2 *dock = app->dock;
562 static int isinit = 0;
563 dock->w = w; dock->h = h;
564 dock->win_width = dock->w + dock->x0;
565 dock->win_height = dock->h + dock->y0;
566 app->reshape_cnt++;
567 app->sm.w = 6;
568 app->sm.nrow = (dock->w-1) / app->sm.w;
569 app->sm.ncol = (dock->h-1) / app->sm.w;
570 if (isinit) FREE_ARR(app->sm.pre_cnt);
571 ALLOC_ARR(app->sm.pre_cnt, app->sm.nrow, app->sm.ncol);
572 if (isinit) FREE_ARR(app->sm.intensity)
573 ALLOC_ARR(app->sm.intensity, app->sm.nrow, app->sm.ncol);
574 app->iom.w = dock->w; app->iom.h = dock->h;
575 if (isinit) FREE_ARR((void*)app->iom.v);
576 ALLOC_ARR(app->iom.v,app->iom.h+4, app->iom.w+2);
577 if (isinit) { dockimlib2_reset_imlib(dock); }
579 isinit = 1;
582 #ifndef GKRELLM
583 static void event_loop(App *app) {
584 int tic_cnt = 0;
585 while (1) {
586 XEvent ev;
587 tic_cnt++;
588 if (tic_cnt % 5 == 0) {
589 XWindowAttributes attr;
590 if (app->dock->normalwin) {
591 XGetWindowAttributes(app->dock->display, app->dock->normalwin, &attr);
592 app->dock->normalwin_mapped = (attr.map_state == IsViewable);
594 if (app->dock->iconwin) {
595 XGetWindowAttributes(app->dock->display, app->dock->iconwin, &attr);
596 app->dock->iconwin_mapped = (attr.map_state == IsViewable);
600 while (XPending(app->dock->display)) {
601 XNextEvent(app->dock->display, &ev);
602 switch (ev.type) {
603 case ClientMessage:
604 if (ev.xclient.message_type == app->dock->atom_WM_PROTOCOLS
605 && ev.xclient.format == 32
606 && (Atom)ev.xclient.data.l[0] == app->dock->atom_WM_DELETE_WINDOW) {
607 exit(0);
609 break;
610 case ButtonRelease:
611 //exit(0);
612 if (ev.xbutton.button == Button4) prev_displayed_hd(-1);
613 else if (ev.xbutton.button == Button5 || ev.xbutton.button == Button1) next_displayed_hd(+1);
614 break;
615 case ConfigureNotify: {
616 if (app->dock->iconwin == None &&
617 (ev.xconfigure.width != (int)app->dock->win_width ||
618 ev.xconfigure.height != (int)app->dock->win_height)) {
619 app->dock->w = app->dock->win_width = ev.xconfigure.width;
620 app->dock->h = app->dock->win_height = ev.xconfigure.height;
621 reshape(ev.xconfigure.width, ev.xconfigure.height); //app->dock->w, app->dock->h, None);
622 /*printf("ConfigureNotify : %dx%d %dx%d\n",
623 ev.xconfigure.width, ev.xconfigure.height,
624 app->sm.nrow, app->sm.ncol);*/
626 } break;
629 if (tic_cnt % app->update_stats_mult == 0) {
630 update_stats();
631 if (!Prefs.disable_io_matrix) update_io_matrix(app);
632 if (!Prefs.disable_swap_matrix) update_swap_matrix(app);
634 if (tic_cnt % 100 == 5) {
635 # ifdef ENABLE_HDDTEMP_QUERY
636 if (Prefs.enable_hddtemp) {
637 query_hddtemp(app);
639 # endif
640 # ifdef ENABLE_POWER_QUERY
641 if (Prefs.enable_power_status) {
642 DiskList *dl; int cnt;
643 for (cnt = 0, dl = first_hd_in_list(); dl; dl = next_hd_in_list(dl), ++cnt) {
644 if (dl->enable_power_status && !dl->is_scsi) {
645 char devname[512]; snprintf(devname, 512, "/dev/%s", dl->name);
646 app->disk_power_mode[cnt] = query_power_mode(devname);
650 # endif
652 //if (tic_cnt > 500) exit(1);
653 usleep(app->update_display_delay_ms * 1000);
654 draw(app);
655 dockimlib2_render(app->dock);
658 #endif /* ndef GKRELLM */
660 void setup_cmap(cmap *m) {
661 struct {
662 float x0;
663 DATA32 c;
664 } colors0[] = {{-128, 0xff8080},
665 {- 70, 0xF00000},
666 { -60, 0xDf0080},
667 { -20, 0x800000},
668 { 0, 0x000000},
669 { 10, 0x008000},
670 { 60, 0xf09000},
671 { 90, 0xffa000},
672 { 116, 0xffd000},
673 { 127, 0xffff00}},
674 colors1[] = {{-128, 0xff0000},
675 {- 64, 0x808080},
676 { 0, 0x404040},
677 //{ , 0x000000},
678 //{ 0 , 0x000000},
679 { 1, 0x208020},
680 { 64, 0x509050},
681 {+ 90, 0x60C060},
682 {+127, 0x008000}},
683 colors2[] = {{-128, 0x400000},
684 { -60, 0xA00000},
685 { -34, 0xff0000},
686 { -16, 0x400000},
687 { 0, 0x000000},
688 { 16, 0x000040},
689 { 34, 0x0000ff},
690 { 60, 0x0000A0},
691 {+128, 0x000040}},
692 colors3[] = {{-128, 0x500060},
693 { -60, 0x500050},
694 { -34, 0x000000},
695 { 0, 0x000000},
696 { 34, 0x000000},
697 { 60, 0x206020},
698 {+128, 0x205020}},
699 colors4[] = {{-128, 0x5000F0},
700 { -70, 0x0000C0},
701 { -50, 0x0000A0},
702 { -40, 0x707090},
703 { -30, 0x000080},
704 { -20, 0x505070},
705 { -10, 0x000060},
706 { 0, 0x000000},
707 { 10, 0x006000},
708 { 20, 0x707070},
709 { 30, 0x008000},
710 { 40, 0x909090},
711 { 50, 0x00A000},
712 { 70, 0x00C000},
713 {+128, 0x20D020}},
715 *cdef = NULL;
717 #define SELMAP(n) \
718 if (Prefs.iomatrix_colormap == n) { sz = sizeof(colors##n)/sizeof(*colors0); cdef = colors##n; }
720 unsigned i, sz=0;
721 SELMAP(0); SELMAP(1); SELMAP(2); SELMAP(3); SELMAP(4);
722 float x0 = cdef[0].x0, x1 = cdef[sz-1].x0;
723 for (i = 0; i < sz - 1; ++i) {
724 int i0 = (int)((cdef[i].x0-x0)*CMAPSZ/(x1-x0));
725 int i1 = (int)((cdef[i+1].x0-x0)*CMAPSZ/(x1-x0));
726 int r1 = cdef[i].c>>16 & 0xff, r2 = cdef[i+1].c>>16 & 0xff;
727 int g1 = cdef[i].c>> 8 & 0xff, g2 = cdef[i+1].c>> 8 & 0xff;
728 int b1 = cdef[i].c & 0xff, b2 = cdef[i+1].c & 0xff;
729 int j;
730 for (j=i0; j <= MIN(i1,CMAPSZ-1); ++j) {
731 float alpha = (j-i0+.5)/(float)(i1-i0);
732 m->p[j] =
733 (MIN((int)(r1*(1-alpha) + alpha*r2),255)<<16) +
734 (MIN((int)(g1*(1-alpha) + alpha*g2),255)<<8) +
735 (MIN((int)(b1*(1-alpha) + alpha*b2),255));
736 //printf("cmap[%d] = 0x%06x\n", j, m->p[j]);
741 unsigned getpos(const char *pp) {
742 char p[2];
743 unsigned v = AL_NONE, i;
744 if (!pp || !pp[0]) return AL_NONE;
745 if (strlen(pp) > 2) { fprintf(stderr, "invalid position specification: '%s'\n", pp); exit(1); }
746 strncpy(p,pp,2);
747 if (p[0] == 'c') { char tmp = p[0]; p[0] = p[1]; p[1] = tmp; }
748 for (i=0; i < 2 && p[i]; ++i) {
749 if (p[i] == 'r') { v |= AL_RIGHT; }
750 else if (p[i] == 'l') { v |= AL_LEFT; }
751 else if (p[i] == 't') { v |= AL_TOP; }
752 else if (p[i] == 'b') { v |= AL_BOTTOM; }
753 else if (p[i] == 'c') {
754 if (v & (AL_LEFT | AL_RIGHT | AL_HCENTER)) v |= AL_VCENTER; else v |= AL_HCENTER;
755 } else {
756 fprintf(stderr, "unknown position specifier: '%c'\n", p[i]); exit(1);
759 return v;
762 void init_prefs(int argc, char **argv) {
763 #ifndef GKRELLM
764 /* Prefs already read from the gkrellm config file: */
765 Prefs.disable_swap_matrix = 0;
766 Prefs.disable_io_matrix = 0;
767 Prefs.disable_hd_leds = 0;
768 Prefs.iomatrix_colormap = 0;
769 Prefs.popup_throughput_threshold = 0.5; /* MB/s */
770 Prefs.hdlist_pos = AL_BOTTOM + AL_LEFT;
771 Prefs.enable_hddtemp = 0;
772 Prefs.bigfontname = Prefs.smallfontname = NULL;
773 #endif
774 Prefs.xprefs.dockapp_size = 64;
775 Prefs.verbosity = 0;
776 Prefs.hddtemp_port = 7634;
777 Prefs.enable_power_status = 0;
778 Prefs.debug_swapio = 0; Prefs.debug_disk_wr = Prefs.debug_disk_rd = 0;
779 Prefs.popup_throughput_pos = AL_TOP;
780 Prefs.xprefs.argc = argc; Prefs.xprefs.argv = argv;
781 Prefs.xprefs.flags = 0;
782 Prefs.temperatures_unit = 'C';
785 #ifndef GKRELLM
786 void parse_options(int argc, char **argv) {
787 int d_opt_used = 0;
788 enum { OPT_DISPLAY=1, OPT_SMALLFONT, OPT_BIGFONT, OPT_FONTPATH,
789 OPT_NOSWAP, OPT_NOIO, OPT_NOLEDS, OPT_HDLIST, OPT_THROUGHPUT, OPT_32, OPT_56, OPT_48 };
790 static struct option long_options[] = {
791 {"help",0,0,'h'},
792 {"verbose",0,0,'v'},
793 {"version",0,0,'V'},
794 {"hddtemp",0,0,'t'},
795 {"farenheit",0,0,'F'},
796 {"display",1,0,OPT_DISPLAY},
797 {"geometry",2,0,'g'},
798 {"smallfont",1,0,OPT_SMALLFONT},
799 {"bigfont",1,0,OPT_BIGFONT},
800 {"fontpath",1,0,OPT_FONTPATH},
801 {"colormap",1,0,'c'},
802 {"noswap",0,0,OPT_NOSWAP},
803 {"noio",0,0,OPT_NOIO},
804 {"noleds",0,0,OPT_NOLEDS},
805 {"hdlist",2,0,OPT_HDLIST},
806 {"throughput",2,0,OPT_THROUGHPUT},
807 {"32",0,0,OPT_32},
808 {"48",0,0,OPT_48},
809 {"56",0,0,OPT_56},
810 {NULL,0,0,0}
812 int long_options_index;
813 const char *help =
814 "wmhdplop " VERSION " - monitor hard-drive (or partition) activity\n"
815 "A recent kernel is required (>2.4.20)\n"
816 "Usage: wmhdplop [options]\n"
817 "Option list:\n"
818 " -h, --help print this.\n"
819 " -v, --verbose increase verbosity\n"
820 " -V, --version print version\n"
821 " -t[=port], --hddtemp[=port]\n"
822 " display hd temperatures, in Celsius degrees (requires hddtemp daemon running)\n"
823 " -F, --farenheit display hd temperatures in Farenheit degrees\n"
824 /* " -p : monitor harddrive power status (idle, standby or sleeping, as reported by hdparm -C)\n"
825 " note that this options requires that wmhd is suid..\n"*/ /* hddtemp already reports when a drive is asleep ... */
826 " --noswap disable the animation reflecting swap activity\n"
827 " --noio disable background animation reflecting disk activity\n"
828 " --noleds hide the small led indicating disk activity\n"
829 " --fontpath path add a new directory to the font search directory list\n"
830 " default: --fontpath=/usr/share/fonts/truetype (and subdirectories)\n"
831 " --fontpath=/usr/share/fonts/ttf (and subdirectories)\n"
832 " --fontpath=$HOME/.fonts (and subdirectories)\n"
833 " --smallfont fontname/size\n"
834 " --bigfont fontname/size\n"
835 " Set the 'small font' and the 'big font' name/size in pixel\n"
836 " (default: --smallfont=Vera/7 --bigfont=Arial_Black/10)\n"
837 " The font name are case-sensitive, and must correspound to the name\n"
838 " of a .ttf file which can be found in one of the fontpaths\n"
839 " By default, wmhdplop tries to load the following fonts:\n"
840 " * Arial_Black/10, FreeSansBold/11, VeraMoBd/9\n"
841 " * Vera/7, FreeSans/7, Trebuchet_MS/7\n"
842 " -c n, --colormap=n\n"
843 " select colormap number n\n"
844 " --hdlist[=pos] hide completely the list of drives with leds and temperatures (if no position given)\n"
845 " or change its location (default: 'B'). Possible positions are: 't','b','l','bl','bc','br',...\n"
846 " (t=top, b=bottom, l=left, r=right, c=centered, etc)\n"
847 " --throughput=mbs[,pos]\n"
848 " minimum io throughput (MB/s) that will be displayed in the popup display (default 0.5)\n"
849 " and position of the popup (same format than hdlist)\n"
850 " -g[=WxH+x+y], --geometry[=WxH+x+y]\n"
851 " start in window (i.e. undocked) mode with specified geometry (i.e -g 96x32 or -g 64x64+0+0)\n"
852 " --32, --48, --56\n"
853 " start in a reduced dockapp, for people whose dock is too small too contain 64x64 dockapps\n"
854 " -d device[:name] monitor activity on the specified hard-drive. This option can be\n"
855 " used many times. If you do not use it, all hard-drives will be monitored.\n"
856 " If an optional 'name' is given, it will be displayed instead of the /dev/hdx name\n"
857 " The device may also be a single partition.\n";
858 init_prefs(argc, argv);
859 while (1) {
860 int c;
861 c = getopt_long(argc, argv, "g::hvVt::Fc:LP:d:@:",long_options,&long_options_index); /* -g option is handled in dockapp_imlib2 */
862 if (c == -1)
863 break;
864 switch (c) {
865 case ':':
866 case '?':
867 exit(1);
868 case OPT_DISPLAY:
869 Prefs.xprefs.flags |= DOCKPREF_DISPLAY; Prefs.xprefs.display = strdup(optarg);
870 break;
871 case 'g':
872 Prefs.xprefs.flags |= DOCKPREF_GEOMETRY; if (optarg) Prefs.xprefs.geometry = strdup(optarg);
873 break;
874 case 'h':
875 puts(help); exit(0);
876 case 'v':
877 Prefs.verbosity++;
878 break;
879 case 'V':
880 printf("wmhdplop %s\n",VERSION); exit(0);
881 break;
882 case 't':
883 Prefs.enable_hddtemp = 1;
884 if (optarg) Prefs.hddtemp_port = atoi(optarg);
885 break;
886 /*case 'p':
887 Prefs.enable_power_status = 1;
888 break;*/
889 case 'F':
890 Prefs.enable_hddtemp = 1;
891 Prefs.temperatures_unit = 'F';
892 break;
893 case OPT_NOIO:
894 Prefs.disable_io_matrix = 1;
895 break;
896 case OPT_NOSWAP:
897 Prefs.disable_swap_matrix = 1;
898 break;
899 case OPT_NOLEDS:
900 Prefs.disable_hd_leds = 1;
901 break;
902 case OPT_FONTPATH:
903 printf("add font path: %s\n", optarg);
904 imlib_add_path_to_font_path(optarg);
905 break;
906 case OPT_SMALLFONT:
907 Prefs.smallfontname = strdup(optarg);
908 break;
909 case OPT_BIGFONT:
910 Prefs.bigfontname = strdup(optarg);
911 break;
912 case OPT_HDLIST:
913 Prefs.hdlist_pos = getpos(optarg);
914 break;
915 case 'c':
916 Prefs.iomatrix_colormap = atoi(optarg);
917 if (Prefs.iomatrix_colormap > 4) { fprintf(stderr,"invalid colormap number\n"); exit(1); }
918 break;
919 case OPT_THROUGHPUT:
920 if (optarg) {
921 Prefs.popup_throughput_threshold = atof(optarg);
922 if (strchr(optarg,',')) Prefs.popup_throughput_pos = getpos(strchr(optarg,',')+1);
923 } break;
924 case OPT_56:
925 Prefs.xprefs.dockapp_size = 56;
926 break;
927 case OPT_48:
928 Prefs.xprefs.dockapp_size = 48;
929 break;
930 case OPT_32:
931 Prefs.xprefs.dockapp_size = 32;
932 break;
933 case 'd':
934 if (optarg) {
935 char *p = strchr(optarg, ':');
936 assert(optarg);
937 if (p) *p++ = 0;
938 BLAHBLAH(1,printf("adding device %s to monitored disc list\n",optarg));
939 if (add_device_by_name(optarg, p) != 0)
940 fprintf(stderr, "Warning: device %s not found or not recognized -- try option -v to get additional information\n", optarg);
941 d_opt_used = 1;
942 } break;
943 case '@':
944 sscanf(optarg,"%d,%d,%d",&Prefs.debug_swapio,&Prefs.debug_disk_rd,&Prefs.debug_disk_wr);
945 break;
946 default:
947 assert(0);
950 if (optind != argc) {
951 fprintf(stderr, "unknown option: %s\n", argv[optind]); exit(1);
953 if (!d_opt_used) scan_all_hd(1);
955 #endif
957 char *xstrdup(const char *s) {
958 if (s) return strdup(s);
959 else return NULL;
962 void init_fonts(App *app) {
963 char *bigfontlist[] = {"Arial_Black/10", "luxisb/11", "VeraMoBd/9", "arialbd/12", "Vera/9", "Verdana_Bold/10", "VerdanaBd/10", "Verdana/10", "FreeSansBold/11", NULL};
964 char *smallfontlist[] = {"Vera/7","Trebuchet_MS/7", "luxisr/7", "Verdana/7","Arial/7","FreeSans/7", NULL};
965 if (app->bigfont) {
966 imlib_context_set_font(app->bigfont); imlib_free_font(); app->bigfont = NULL;
968 if (app->smallfont) {
969 imlib_context_set_font(app->smallfont); imlib_free_font(); app->smallfont = NULL;
971 app->bigfont = load_font(Prefs.bigfontname, bigfontlist);
972 if (app->bigfont)
973 app->current_bigfont_name = strdup(dockimlib2_last_loaded_font());
974 app->smallfont = load_font(Prefs.smallfontname, smallfontlist);
975 if (app->smallfont)
976 app->current_smallfont_name = strdup(dockimlib2_last_loaded_font());
979 #ifndef GKRELLM
980 int main(int argc, char**argv)
981 #else
982 int hdplop_main(int width, int height, GdkDrawable *gkdrawable)
983 #endif
985 int s;
987 euid = geteuid(); uid = getuid();
988 s = seteuid(uid);
989 if (s == -1)
990 fprintf(stderr, "seteuid(uid) failed : %s\n", strerror(errno));
991 ALLOC_OBJ(app);
992 srand(time(NULL));
993 /* Initialize options */
994 #ifndef GKRELLM
995 parse_options(argc,argv);
996 #else
997 init_prefs(0, NULL);
998 scan_all_hd(1);
999 #endif
1000 /* Initialize imlib2 */
1001 #ifndef GKRELLM
1002 app->dock = dockimlib2_setup(2, 2, Prefs.xprefs.dockapp_size-5, Prefs.xprefs.dockapp_size-5, &Prefs.xprefs);
1003 #else
1004 app->dock = dockimlib2_gkrellm_setup(0, 0, width, height, &Prefs.xprefs, gkdrawable);
1005 #endif
1006 app->bigfont = app->smallfont = NULL;
1007 app->current_bigfont_name = app->current_smallfont_name = NULL;
1008 app->reshape_cnt = 0;
1009 if (find_id(-1,0) == 0) {
1010 app->filter_hd = -1; app->filter_part = -1; /* only partitions */
1011 } else {
1012 app->filter_hd = -1; app->filter_part = 0;
1014 app->displayed_hd_changed = 1;
1015 if (nb_dev_in_list() == 0) {
1016 #ifndef GKRELLM
1017 fprintf(stderr, "No common hard-drives found in /etc/mtab and /proc/partitions..\n"
1018 "Please use option -d to add devices (i.e. %s -d /dev/hda -d /dev/hdb ...)\n", argv[0]);
1019 exit(1);
1020 #else
1021 fprintf(stderr, "No hard drive found...\n");
1022 /* Euh, on fait quoi maintenant ? exit ? */
1023 #endif
1025 init_fonts(app);
1026 app->update_display_delay_ms = 50;
1027 app->update_stats_mult = 2;
1029 app->swap_matrix_lighting = (int)(300/app->update_display_delay_ms);
1030 app->swap_matrix_luminosity = 255;
1032 app->nb_hd = nb_hd_in_list();
1033 app->nb_dev = nb_dev_in_list();
1034 ALLOC_VEC(app->disk_power_mode, app->nb_hd); SET_VEC(app->disk_power_mode, HD_ACTIVE,0,app->nb_hd);
1035 ALLOC_VEC(app->disk_temperature, app->nb_hd); SET_VEC(app->disk_temperature, -1, 0, app->nb_hd);
1037 init_stats(app->update_display_delay_ms*1e-3*app->update_stats_mult);
1038 BLAHBLAH(1, {
1039 DiskList *dl = first_dev_in_list();
1040 for ( ; dl; dl=dl->next) {
1041 printf("Monitored: %s (%s) major=%d, minor=%d is_partition=%d\n",
1042 dl->dev_path, dl->name, dl->major, dl->minor, is_partition(dl->major,dl->minor));
1046 reshape(app->dock->w,app->dock->h);
1047 app->iom.ops = NULL;
1048 setup_cmap(&app->iom.cm);
1049 #ifndef GKRELLM
1050 event_loop(app);
1051 #endif
1052 return 0;
1055 #ifdef GKRELLM
1056 void gkrellm_hdplop_update(int update_options) {
1057 static int tic_cnt = 0;
1058 if (update_options) {
1059 setup_cmap(&app->iom.cm);
1060 if (!Prefs.enable_hddtemp)
1061 SET_VEC(app->disk_temperature, -1, 0, app->nb_hd);
1063 // update the data:
1065 if (tic_cnt % app->update_stats_mult == 0) {
1066 update_stats();
1067 if (!Prefs.disable_io_matrix)
1068 update_io_matrix(app);
1069 if (!Prefs.disable_swap_matrix)
1070 update_swap_matrix(app);
1072 if (tic_cnt % 100 == 5 && Prefs.enable_hddtemp) {
1073 query_hddtemp(app);
1076 // draw the Imlib2 pixmap:
1077 draw(app);
1078 dockimlib2_render(app->dock);
1079 ++tic_cnt;
1081 #endif