/* Copyright (C) 2006 Sergei Golubchik, Nicolas Chauvat This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* originally based on WMgMon - Window Maker Generic Monitor by Nicolas Chauvat which was based on WMMon by Antoine Nulle and Martijn */ #define Wmsupermon_VERSION "1.2.2" #define Wmsupermon_VERSION_DATE "2007/06/23" #include #include #include #include #include #include "dockapp.h" #include "wmsupermon-master.xpm" #include "expr.h" #include "stat_dev.h" #include "panes.h" /* define layout constants */ #define ROW_HEIGHT 14 #define LABEL_WIDTH 25 /******************************************************************************/ /* master xpm coordinates */ /******************************************************************************/ #define X_ALPHA 1 #define Y_ALPHA 1 #define X_NUM 1 #define Y_NUM 11 #define X_LABEL 1 #define Y_LABEL 21 #define W_LABEL 56 #define H_LABEL (ROW_HEIGHT-1) #define X_NOLABEL 1 #define Y_NOLABEL 77 #define W_NOLABEL W_LABEL #define H_NOLABEL H_LABEL #define X_DIAG 1 #define Y_DIAG 34 #define W_DIAG W_LABEL #define H_SDIAG (ROW_HEIGHT*1) #define H_MDIAG (ROW_HEIGHT*2) #define H_DIAG (ROW_HEIGHT*3) #define H_BDIAG (ROW_HEIGHT*4) #define X_BLANK_SBAR (118-2) #define Y_BLANK_SBAR (127-50) #define X_SBAR (118-2) #define Y_SBAR (138-50) #define W_SBAR 30 #define H_SBAR 10 #define X_BLANK_LBAR (62-2) #define Y_BLANK_LBAR (127-50) #define X_LBAR (62-2) #define Y_LBAR (138-50) #define W_LBAR 54 #define H_LBAR H_SBAR #define X_DOT 150 #define COLOR_DOT 27 #define BRIGHT_DOT 28 #define BACK_DOT 29 #define LINE_DOT 30 /******************************************************************************/ /* global variables */ /******************************************************************************/ Pixmap work_pixmap, master_pixmap; GC gc; char *displayName="", *config=0; static DAProgramOption options[]={ {"-d", "--display", "display to use", DOString, False, {&displayName} }, {"-c", "--config", "path to config file", DOString, False, {&config} } }; #define WIND_MAX 4 wind_desc winds[WIND_MAX]; /* define panes */ #define PANE_MAX (8*WIND_MAX) pane_desc pane[PANE_MAX]; int rotate_interval=4; int next_rotate=0; int current_time=0; int wind_num=0; #define STAT_DEV_MAX 20 stat_dev stat_device[STAT_DEV_MAX]; #define APP_WIDTH 56 #define APP_HEIGHT 56 /******************************************************************************/ /* prototypes */ /******************************************************************************/ void draw_label(const char *, int, int); void draw_bar(pane_part *, int, int); void draw_graph(pane_part *, int, int, int, int); void draw_current_frame(pane_part *); void draw_current_pane(pane_part *); static void click(Window w, int button, int state, int x, int y); char mask_bits[APP_HEIGHT*APP_WIDTH]; /******************************************************************************/ /* main */ /******************************************************************************/ int main (int argc, char *argv[]) { unsigned w, h; int i, device_num=0, pane_num=0; DACallbacks callbacks={ NULL, &click, NULL, NULL, NULL, NULL, NULL }; DAParseArguments(argc, argv, options, sizeof(options)/sizeof(DAProgramOption), "wmsupermon", Wmsupermon_VERSION); /* init structures */ for (i=0; i 0) /* no config file */ exit(2); /* TODO: setup default panes */ /* init timing stuff */ next_rotate=time(0) + rotate_interval; for (i=0; i next_rotate) { next_rotate=current_time+rotate_interval; for (i=0; i < wind_num; i++) { if (winds[i].num_panes > 1) { winds[i].cur_pane++; if (winds[i].cur_pane >= winds[i].num_panes) winds[i].cur_pane=0; /* redraw frame */ work_pixmap=winds[i].pixmap; draw_current_frame(winds[i].panes[winds[i].cur_pane]); XFreePixmap(DADisplay, winds[i].mask); winds[i].mask=XCreateBitmapFromData(DADisplay, winds[i].w[0], mask_bits, APP_WIDTH, APP_HEIGHT); DASetShape(winds[i].w, winds[i].mask); } } } for (i=0; i < device_num; i++) { stat_dev *st=&stat_device[i]; /* if time has come, update stats */ if (current_time >= st->next_update) { int j; history **h=st->hist; update_stat(st); if (st->smooth) { double v=st->smooth[0]; for (j=0; j < SMOOTH_SIZE-2; j++) v+=(st->smooth[j]=st->smooth[j+1]); v+=(st->smooth[j]=st->value[0]); st->value[1]=v/SMOOTH_SIZE; } for (j=0; j <= P_HIST; j++, h++) { if (!*h) continue; (*h)->data[HIST_LAST]+= st->value[j & P_SMOOTH]; (*h)->count++; } st->next_update=current_time+st->update_interval; } /* if time has come, update history */ if (current_time > st->hist_next_update) { stat_dev_update_history(st); if (st->hist_next_update < current_time) st->hist_next_update=current_time; st->hist_next_update+=st->hist_update_interval; } } /* update view */ for (i=0; i < wind_num; i++) { work_pixmap=winds[i].pixmap; draw_current_pane(winds[i].panes[winds[i].cur_pane]); XCopyArea(DADisplay, work_pixmap, winds[i].w[0], gc, 0, 0, APP_WIDTH, APP_HEIGHT, 0, 0); } /* handle all pending X events */ while (XPending(DADisplay)) { XNextEvent(DADisplay, &ev); for (i=0; i < wind_num; i++) DAProcessEvent(winds[i].w, &ev); } /* short sleep */ usleep(250000L); } return 0; } /******************************************************************************/ /* mouse events / callbacks */ /******************************************************************************/ static void click(Window w, int button, int state, int x, int y) { pane_part *pane; int p=y, i; for (i=0; i < wind_num; i++) { if (winds[i].w[0] != w) continue; pane=winds[i].panes[winds[i].cur_pane]; for (p=0; pane[p].stat && p < PANE_PARTS; p++) if ((y-= ROW_HEIGHT*pane[p].height) < 0) break; if (y < 0 && pane[p].stat->action) if (!fork()) { system(pane[p].stat->action); exit(0); } break; } } /******************************************************************************/ /* draw functions */ /******************************************************************************/ void copy_area(int src_x, int src_y, int width, int height, int d_x, int d_y) { XCopyArea(DADisplay, master_pixmap, work_pixmap, gc, src_x, src_y, width, height, d_x, d_y); } void draw_current_frame(pane_part *pane) { int i, j; int row=0; XSetForeground(DADisplay, gc, BlackPixel(DADisplay, DefaultScreen(DADisplay))); XFillRectangle(DADisplay, work_pixmap, gc, 0, 0, APP_WIDTH, APP_HEIGHT); for (j=0; j < sizeof(mask_bits); j++) mask_bits[j]=0xff; for (i=0; (rowname, 1, 2+row*ROW_HEIGHT); for (j=0; j < ROW_HEIGHT; j++) mask_bits[(row*ROW_HEIGHT+j)*W_LABEL/8+(LABEL_WIDTH-3)/8] &= ~(1 << (LABEL_WIDTH-3) % 8); } else copy_area (X_NOLABEL, Y_NOLABEL, W_NOLABEL, H_NOLABEL, 0, row*ROW_HEIGHT); break; case 2: copy_area (X_DIAG, Y_DIAG, W_DIAG, H_MDIAG-5, 0, row*ROW_HEIGHT); copy_area (X_DIAG, Y_DIAG+H_DIAG-H_MDIAG+5, W_DIAG, H_MDIAG-5, 0, row*ROW_HEIGHT+5); break; case 3: copy_area (X_DIAG, Y_DIAG, W_DIAG, H_DIAG, 0, row*ROW_HEIGHT); break; case 4: copy_area (X_DIAG, Y_DIAG, W_DIAG, H_DIAG-5, 0, row*ROW_HEIGHT); copy_area (X_DIAG, Y_DIAG+5, W_DIAG, H_DIAG-5, 0, row*ROW_HEIGHT+H_BDIAG-H_DIAG+5); break; default: assert(0); } row+=pane[i].height; for (j=0; j < W_LABEL/8; j++) mask_bits[(row*ROW_HEIGHT-1)*W_LABEL/8+j]=0; } } static struct { int w,h; } graph_box[]= { {0,0}, {W_DIAG-2, H_SDIAG-2}, {W_DIAG-2, H_MDIAG-2}, {W_DIAG-2, H_DIAG-2}, {W_DIAG-2, H_BDIAG-2} }; void draw_current_pane(pane_part *pane) { int i; int row=0, label_width; char str[6]={0}; for (i=0; (rowstat; pane++, i++) { label_width=pane->flags & P_LABEL && pane->height == 1 ? LABEL_WIDTH-1 : 0; switch(pane->type) { case PTBar: draw_bar(pane, label_width+1, 1+row*ROW_HEIGHT); break; case PTPercent: sprintf(str, " %*.*f%%", label_width ? 2 : 5, label_width ? 0 : 2, 100*pane->stat->value[pane->flags & P_SMOOTH]); draw_label(str, label_width+4, 2+row*ROW_HEIGHT); break; case PTNumber: sprintf(str, pane->flags & P_FLOAT ? "%2$*1$.*1$g" : "%2$*1$.0f", label_width ? 4 : 6, pane->stat->value[pane->flags & P_SMOOTH]); draw_label(str, label_width+4, 2+row*ROW_HEIGHT); break; case PTGraph: draw_graph(pane, label_width+1, 1+row*ROW_HEIGHT, graph_box[pane->height].w-label_width, graph_box[pane->height].h); if (pane->flags & P_LABEL && pane->height > 1) draw_label(pane->stat->name, 1, 1+row*ROW_HEIGHT); break; default: assert(0); break; } row+=pane->height; } } void draw_label(const char *str, int x, int y) { int i, c; for (i=0; str[i] != '\0'; i++) { if (isalnum(str[i])) { c=toupper(str[i]); if (c >= 'A' && c <= 'Z') { c -= 'A'; copy_area(X_ALPHA+c*6, Y_ALPHA, 6, 8, x+i*6, y); } else { c -= '0'; copy_area(X_NUM+c*6, Y_NUM, 6, 8, x+i*6, y); } } else { switch(str[i]) { case '/' : copy_area(72-2, 61-50, 6, 8, x+i*6, y); break; case '.' : copy_area(84-2, 61-50, 6, 8, x+i*6, y); break; case '%' : copy_area(66-2, 61-50, 6, 8, x+i*6, y); break; case '-' : copy_area(89-2, 61-50, 6, 8, x+i*6, y); break; default: copy_area(78-2, 61-50, 6, 8, x+i*6, y); } } } } static const struct { int x_blank, y_blank, x, y, h, w; } bar_coords[]={ {X_BLANK_SBAR, Y_BLANK_SBAR, X_SBAR, Y_SBAR, H_SBAR, W_SBAR}, {X_BLANK_LBAR, Y_BLANK_LBAR, X_LBAR, Y_LBAR, H_LBAR, W_LBAR} }; void draw_bar (pane_part *widget, int x, int y) { stat_dev *st=widget->stat; int value; int label= x==1; /* copy blank bar */ copy_area(bar_coords[label].x_blank, bar_coords[label].y_blank, bar_coords[label].w, bar_coords[label].h, x, y); /* compute value */ if (st->max) value=(st->value[widget->flags & P_SMOOTH]-st->min)/st->max * bar_coords[label].w; else value=st->value[widget->flags & P_SMOOTH] * bar_coords[label].w; if (value > bar_coords[label].w) value=bar_coords[label].w; if (value < 0) value=0; /* copy part of color bar */ copy_area(bar_coords[label].x, bar_coords[label].y, value, bar_coords[label].h, x, y); } /* Below: (0) - to disable, (st->max) to enable */ #define USER_RANGE (st->max) void draw_graph (pane_part *widget, int x, int y, int width, int height) { stat_dev *st=widget->stat; int row, column, top, x0, y0; history *hist=st->hist[widget->flags & P_HIST]; x0=width - HIST_LAST + x; y0=y + height - 1; if (!USER_RANGE) { /* compute scale */ if (widget->flags & P_SCALEDOWN) { double hist_max=0; for (column=HIST_LAST-width; column < HIST_LAST; column++) { if (hist->data[column] > hist_max) hist_max=hist->data[column]; } if (hist_max > 0) hist->max=hist_max; } else if (hist->data[HIST_LAST-1] > hist->max) hist->max=hist->data[HIST_LAST-1]; } /* draw bars (top is lighter) */ for (column=HIST_LAST-width; column < HIST_LAST; column++) { if (USER_RANGE) top=(hist->data[column] - st->min) * height / st->max; else top=hist->data[column] * height / hist->max; for (row=0; row < height; row++) { if (row < top - 3) copy_area (X_DOT, COLOR_DOT, 1, 1, x0+column, y0-row); else if (row < top) copy_area (X_DOT, BRIGHT_DOT, 1, 1, x0+column, y0-row); else copy_area (X_DOT, BACK_DOT, 1, 1, x0+column, y0-row); } } } #undef USER_RANGE