1 /* Copyright (C) 2006 Sergei Golubchik, Nicolas Chauvat
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License version 2
5 as published by the Free Software Foundation
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 USA */
18 WMgMon - Window Maker Generic Monitor
19 by Nicolas Chauvat <nico@caesium.fr>
21 WMMon by Antoine Nulle and Martijn
24 #define Wmsupermon_VERSION "1.2.2"
25 #define Wmsupermon_VERSION_DATE "2007/06/23"
34 #include "wmsupermon-master.xpm"
39 /* define layout constants */
41 #define LABEL_WIDTH 25
43 /******************************************************************************/
44 /* master xpm coordinates */
45 /******************************************************************************/
55 #define H_LABEL (ROW_HEIGHT-1)
59 #define W_NOLABEL W_LABEL
60 #define H_NOLABEL H_LABEL
64 #define W_DIAG W_LABEL
65 #define H_SDIAG (ROW_HEIGHT*1)
66 #define H_MDIAG (ROW_HEIGHT*2)
67 #define H_DIAG (ROW_HEIGHT*3)
68 #define H_BDIAG (ROW_HEIGHT*4)
70 #define X_BLANK_SBAR (118-2)
71 #define Y_BLANK_SBAR (127-50)
72 #define X_SBAR (118-2)
73 #define Y_SBAR (138-50)
76 #define X_BLANK_LBAR (62-2)
77 #define Y_BLANK_LBAR (127-50)
79 #define Y_LBAR (138-50)
89 /******************************************************************************/
90 /* global variables */
91 /******************************************************************************/
93 Pixmap work_pixmap
, master_pixmap
;
96 char *displayName
="", *config
=0;
98 static DAProgramOption options
[]={
99 {"-d", "--display", "display to use", DOString
, False
, {&displayName
} },
100 {"-c", "--config", "path to config file", DOString
, False
, {&config
} }
104 wind_desc winds
[WIND_MAX
];
107 #define PANE_MAX (8*WIND_MAX)
108 pane_desc pane
[PANE_MAX
];
110 int rotate_interval
=4;
115 #define STAT_DEV_MAX 20
116 stat_dev stat_device
[STAT_DEV_MAX
];
119 #define APP_HEIGHT 56
121 /******************************************************************************/
123 /******************************************************************************/
125 void draw_label(const char *, int, int);
126 void draw_bar(pane_part
*, int, int);
127 void draw_graph(pane_part
*, int, int, int, int);
128 void draw_current_frame(pane_part
*);
129 void draw_current_pane(pane_part
*);
131 static void click(Window w
, int button
, int state
, int x
, int y
);
133 char mask_bits
[APP_HEIGHT
*APP_WIDTH
];
135 /******************************************************************************/
137 /******************************************************************************/
139 int main (int argc
, char *argv
[])
142 int i
, device_num
=0, pane_num
=0;
143 DACallbacks callbacks
={ NULL
, &click
, NULL
, NULL
, NULL
, NULL
, NULL
};
145 DAParseArguments(argc
, argv
, options
,
146 sizeof(options
)/sizeof(DAProgramOption
),
147 "wmsupermon", Wmsupermon_VERSION
);
149 /* init structures */
150 for (i
=0; i
<STAT_DEV_MAX
; i
++)
151 stat_dev_init(&stat_device
[i
]);
153 /* read config file and populate structures */
154 i
=read_config_file(pane
, &pane_num
, PANE_MAX
,
155 stat_device
, &device_num
, STAT_DEV_MAX
,
156 winds
, &wind_num
, WIND_MAX
);
157 if (i
< 0) /* error in config file */
159 if (i
> 0) /* no config file */
160 exit(2); /* TODO: setup default panes */
162 /* init timing stuff */
163 next_rotate
=time(0) + rotate_interval
;
165 for (i
=0; i
<device_num
; i
++)
166 stat_dev_initstat(&stat_device
[i
]);
169 for (i
=0; i
< wind_num
; i
++) {
170 DAInitialize(displayName
, winds
[i
].name
, APP_WIDTH
, APP_HEIGHT
, argc
, argv
, winds
[i
].w
);
171 DASetCallbacks(winds
[i
].w
, &callbacks
);
173 winds
[i
].pixmap
=work_pixmap
=DAMakePixmap(winds
[i
].w
);
174 DAMakePixmapFromData(winds
[i
].w
, wmsupermon_master_xpm
, &master_pixmap
, 0, &w
, &h
);
180 gc
=DefaultGC(DADisplay
, DefaultScreen(DADisplay
));
182 XSetForeground(DADisplay
, gc
, BlackPixel(DADisplay
, DefaultScreen(DADisplay
)));
184 for (i
=0; i
< wind_num
; i
++) {
185 XFillRectangle(DADisplay
, work_pixmap
=winds
[i
].pixmap
, gc
, 0, 0, APP_WIDTH
, APP_HEIGHT
);
186 draw_current_frame(winds
[i
].panes
[winds
[i
].cur_pane
]);
187 winds
[i
].mask
=XCreateBitmapFromData(DADisplay
, winds
[i
].w
[0], mask_bits
, APP_WIDTH
, APP_HEIGHT
);
188 DASetShape(winds
[i
].w
, winds
[i
].mask
);
195 current_time
=time(0);
198 if (current_time
> next_rotate
) {
199 next_rotate
=current_time
+rotate_interval
;
200 for (i
=0; i
< wind_num
; i
++) {
201 if (winds
[i
].num_panes
> 1) {
203 if (winds
[i
].cur_pane
>= winds
[i
].num_panes
)
206 work_pixmap
=winds
[i
].pixmap
;
207 draw_current_frame(winds
[i
].panes
[winds
[i
].cur_pane
]);
208 XFreePixmap(DADisplay
, winds
[i
].mask
);
209 winds
[i
].mask
=XCreateBitmapFromData(DADisplay
, winds
[i
].w
[0], mask_bits
, APP_WIDTH
, APP_HEIGHT
);
210 DASetShape(winds
[i
].w
, winds
[i
].mask
);
215 for (i
=0; i
< device_num
; i
++) {
216 stat_dev
*st
=&stat_device
[i
];
217 /* if time has come, update stats */
218 if (current_time
>= st
->next_update
) {
220 history
**h
=st
->hist
;
223 double v
=st
->smooth
[0];
224 for (j
=0; j
< SMOOTH_SIZE
-2; j
++)
225 v
+=(st
->smooth
[j
]=st
->smooth
[j
+1]);
226 v
+=(st
->smooth
[j
]=st
->value
[0]);
227 st
->value
[1]=v
/SMOOTH_SIZE
;
229 for (j
=0; j
<= P_HIST
; j
++, h
++) {
231 (*h
)->data
[HIST_LAST
]+= st
->value
[j
& P_SMOOTH
];
234 st
->next_update
=current_time
+st
->update_interval
;
236 /* if time has come, update history */
237 if (current_time
> st
->hist_next_update
) {
238 stat_dev_update_history(st
);
239 if (st
->hist_next_update
< current_time
)
240 st
->hist_next_update
=current_time
;
241 st
->hist_next_update
+=st
->hist_update_interval
;
246 for (i
=0; i
< wind_num
; i
++) {
247 work_pixmap
=winds
[i
].pixmap
;
248 draw_current_pane(winds
[i
].panes
[winds
[i
].cur_pane
]);
249 XCopyArea(DADisplay
, work_pixmap
, winds
[i
].w
[0], gc
, 0, 0,
250 APP_WIDTH
, APP_HEIGHT
, 0, 0);
253 /* handle all pending X events */
254 while (XPending(DADisplay
)) {
255 XNextEvent(DADisplay
, &ev
);
256 for (i
=0; i
< wind_num
; i
++)
257 DAProcessEvent(winds
[i
].w
, &ev
);
268 /******************************************************************************/
269 /* mouse events / callbacks */
270 /******************************************************************************/
272 static void click(Window w
, int button
, int state
, int x
, int y
)
276 for (i
=0; i
< wind_num
; i
++) {
277 if (winds
[i
].w
[0] != w
) continue;
278 pane
=winds
[i
].panes
[winds
[i
].cur_pane
];
280 for (p
=0; pane
[p
].stat
&& p
< PANE_PARTS
; p
++)
281 if ((y
-= ROW_HEIGHT
*pane
[p
].height
) < 0) break;
282 if (y
< 0 && pane
[p
].stat
->action
)
284 system(pane
[p
].stat
->action
);
291 /******************************************************************************/
293 /******************************************************************************/
295 void copy_area(int src_x
, int src_y
, int width
, int height
, int d_x
, int d_y
)
297 XCopyArea(DADisplay
, master_pixmap
, work_pixmap
, gc
,
298 src_x
, src_y
, width
, height
, d_x
, d_y
);
301 void draw_current_frame(pane_part
*pane
)
306 XSetForeground(DADisplay
, gc
, BlackPixel(DADisplay
, DefaultScreen(DADisplay
)));
307 XFillRectangle(DADisplay
, work_pixmap
, gc
, 0, 0, APP_WIDTH
, APP_HEIGHT
);
309 for (j
=0; j
< sizeof(mask_bits
); j
++) mask_bits
[j
]=0xff;
310 for (i
=0; (row
<PANE_PARTS
) && (i
<PANE_MAX
) && pane
[i
].stat
; i
++) {
311 switch(pane
[i
].height
) {
313 if (pane
[i
].flags
& P_LABEL
) {
314 copy_area (X_LABEL
, Y_LABEL
, W_LABEL
, H_LABEL
, 0, row
*ROW_HEIGHT
);
315 draw_label(pane
[i
].stat
->name
, 1, 2+row
*ROW_HEIGHT
);
316 for (j
=0; j
< ROW_HEIGHT
; j
++)
317 mask_bits
[(row
*ROW_HEIGHT
+j
)*W_LABEL
/8+(LABEL_WIDTH
-3)/8] &=
318 ~(1 << (LABEL_WIDTH
-3) % 8);
320 copy_area (X_NOLABEL
, Y_NOLABEL
, W_NOLABEL
, H_NOLABEL
, 0, row
*ROW_HEIGHT
);
323 copy_area (X_DIAG
, Y_DIAG
, W_DIAG
, H_MDIAG
-5, 0, row
*ROW_HEIGHT
);
324 copy_area (X_DIAG
, Y_DIAG
+H_DIAG
-H_MDIAG
+5, W_DIAG
, H_MDIAG
-5, 0, row
*ROW_HEIGHT
+5);
327 copy_area (X_DIAG
, Y_DIAG
, W_DIAG
, H_DIAG
, 0, row
*ROW_HEIGHT
);
330 copy_area (X_DIAG
, Y_DIAG
, W_DIAG
, H_DIAG
-5, 0, row
*ROW_HEIGHT
);
331 copy_area (X_DIAG
, Y_DIAG
+5, W_DIAG
, H_DIAG
-5, 0, row
*ROW_HEIGHT
+H_BDIAG
-H_DIAG
+5);
337 for (j
=0; j
< W_LABEL
/8; j
++) mask_bits
[(row
*ROW_HEIGHT
-1)*W_LABEL
/8+j
]=0;
341 static struct { int w
,h
; } graph_box
[]=
344 {W_DIAG
-2, H_SDIAG
-2},
345 {W_DIAG
-2, H_MDIAG
-2},
346 {W_DIAG
-2, H_DIAG
-2},
347 {W_DIAG
-2, H_BDIAG
-2}
350 void draw_current_pane(pane_part
*pane
)
353 int row
=0, label_width
;
356 for (i
=0; (row
<PANE_PARTS
) && pane
->stat
; pane
++, i
++) {
357 label_width
=pane
->flags
& P_LABEL
&& pane
->height
== 1 ?
361 draw_bar(pane
, label_width
+1, 1+row
*ROW_HEIGHT
);
364 sprintf(str
, " %*.*f%%", label_width
? 2 : 5, label_width
? 0 : 2,
365 100*pane
->stat
->value
[pane
->flags
& P_SMOOTH
]);
366 draw_label(str
, label_width
+4, 2+row
*ROW_HEIGHT
);
370 pane
->flags
& P_FLOAT
? "%2$*1$.*1$g" : "%2$*1$.0f",
371 label_width
? 4 : 6, pane
->stat
->value
[pane
->flags
& P_SMOOTH
]);
372 draw_label(str
, label_width
+4, 2+row
*ROW_HEIGHT
);
375 draw_graph(pane
, label_width
+1, 1+row
*ROW_HEIGHT
,
376 graph_box
[pane
->height
].w
-label_width
,
377 graph_box
[pane
->height
].h
);
378 if (pane
->flags
& P_LABEL
&& pane
->height
> 1)
379 draw_label(pane
->stat
->name
, 1, 1+row
*ROW_HEIGHT
);
389 void draw_label(const char *str
, int x
, int y
)
393 for (i
=0; str
[i
] != '\0'; i
++) {
394 if (isalnum(str
[i
])) {
396 if (c
>= 'A' && c
<= 'Z') {
398 copy_area(X_ALPHA
+c
*6, Y_ALPHA
, 6, 8, x
+i
*6, y
);
402 copy_area(X_NUM
+c
*6, Y_NUM
, 6, 8, x
+i
*6, y
);
408 copy_area(72-2, 61-50, 6, 8, x
+i
*6, y
);
411 copy_area(84-2, 61-50, 6, 8, x
+i
*6, y
);
414 copy_area(66-2, 61-50, 6, 8, x
+i
*6, y
);
417 copy_area(89-2, 61-50, 6, 8, x
+i
*6, y
);
420 copy_area(78-2, 61-50, 6, 8, x
+i
*6, y
);
426 static const struct {
427 int x_blank
, y_blank
, x
, y
, h
, w
;
429 {X_BLANK_SBAR
, Y_BLANK_SBAR
, X_SBAR
, Y_SBAR
, H_SBAR
, W_SBAR
},
430 {X_BLANK_LBAR
, Y_BLANK_LBAR
, X_LBAR
, Y_LBAR
, H_LBAR
, W_LBAR
}
433 void draw_bar (pane_part
*widget
, int x
, int y
)
435 stat_dev
*st
=widget
->stat
;
440 copy_area(bar_coords
[label
].x_blank
, bar_coords
[label
].y_blank
,
441 bar_coords
[label
].w
, bar_coords
[label
].h
, x
, y
);
445 value
=(st
->value
[widget
->flags
& P_SMOOTH
]-st
->min
)/st
->max
*
448 value
=st
->value
[widget
->flags
& P_SMOOTH
] * bar_coords
[label
].w
;
449 if (value
> bar_coords
[label
].w
)
450 value
=bar_coords
[label
].w
;
454 /* copy part of color bar */
455 copy_area(bar_coords
[label
].x
, bar_coords
[label
].y
,
456 value
, bar_coords
[label
].h
, x
, y
);
459 /* Below: (0) - to disable, (st->max) to enable */
460 #define USER_RANGE (st->max)
461 void draw_graph (pane_part
*widget
, int x
, int y
, int width
, int height
)
463 stat_dev
*st
=widget
->stat
;
464 int row
, column
, top
, x0
, y0
;
465 history
*hist
=st
->hist
[widget
->flags
& P_HIST
];
467 x0
=width
- HIST_LAST
+ x
;
472 if (widget
->flags
& P_SCALEDOWN
) {
474 for (column
=HIST_LAST
-width
; column
< HIST_LAST
; column
++) {
475 if (hist
->data
[column
] > hist_max
)
476 hist_max
=hist
->data
[column
];
481 else if (hist
->data
[HIST_LAST
-1] > hist
->max
)
482 hist
->max
=hist
->data
[HIST_LAST
-1];
484 /* draw bars (top is lighter) */
485 for (column
=HIST_LAST
-width
; column
< HIST_LAST
; column
++) {
487 top
=(hist
->data
[column
] - st
->min
) * height
/ st
->max
;
489 top
=hist
->data
[column
] * height
/ hist
->max
;
491 for (row
=0; row
< height
; row
++) {
493 copy_area (X_DOT
, COLOR_DOT
, 1, 1, x0
+column
, y0
-row
);
495 copy_area (X_DOT
, BRIGHT_DOT
, 1, 1, x0
+column
, y0
-row
);
497 copy_area (X_DOT
, BACK_DOT
, 1, 1, x0
+column
, y0
-row
);