/* wmload - system load monitor designed for Window Maker * Copyright (C) 1996 Beat Christen * Copyright (C) 1997 Ryan Land * Copyright (C) 2015 Window Maker Developers Team * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * 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. */ #define _POSIX_C_SOURCE 200112L #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "back.xpm" #include "mask2.xbm" #include "mask.xpm" #define major_VER 0 #define minor_VER 9 #define patch_VER 6 #define MW_EVENTS (ExposureMask | ButtonPressMask | StructureNotifyMask) #define FALSE 0 #define Shape(num) (ONLYSHAPE ? num-5 : num) #define NCPUSTATES 4 /* Global Data storage/structures ********************************************/ static long cp_time[NCPUSTATES]; static long last[NCPUSTATES]; int ONLYSHAPE=0; /* default value is noshape */ int updatespeed = 4; static char *help_message[] = { "where options include:", " -u updatespeed", " -exe program to start on click", " -led color of the led", " -position [+|-]x[+|-]y position of wmload", " -shape without groundplate", " -iconic start up as icon", " -withdrawn start up withdrawn", " -ver output version", NULL }; /* X11 Variables *************************************************************/ Display *dpy; /* welches DISPLAY */ Window Root; /* Hintergrund-Drawable */ int screen; int x_fd; int d_depth; XSizeHints mysizehints; XWMHints mywmhints; Pixel back_pix, fore_pix; GC NormalGC; Window iconwin, win; /* My home is my window */ char *ProgName; char *Geometry; char *LedColor = "LightSeaGreen"; char Execute[] = "echo no program has been specified"; char *ERR_colorcells = "not enough free color cells\n"; char *ampers = " &"; /* XPM Structures & Variables ************************************************/ typedef struct _XpmIcon { Pixmap pixmap; Pixmap mask; XpmAttributes attributes; } XpmIcon; XpmIcon wmload; XpmIcon visible; time_t actualtime; long actualmin; /* Function definitions ******************************************************/ void GetXPM(void); Pixel GetColor(char *name); void RedrawWindow( XpmIcon *v); void InitLoad(); void InsertLoad(); /*****************************************************************************/ /* Source Code <--> Function Implementations */ /*****************************************************************************/ void usage() { char **cpp; fprintf(stderr,"\nusage: %s [-options ...] \n", ProgName); for (cpp = help_message; *cpp; cpp++) { fprintf(stderr, "%s\n", *cpp); } fprintf(stderr,"\n"); exit(1); } /* * Copied from ascpu - albert@tigr.net - 09 Mar 2000 * * This function executes an external command while * checking whether we should drop the privileges. * * Since we might need privileges later we fork and * then drop privileges in one of the instances which * will then execute the command and die. * * This fixes the security hole for FreeBSD and AIX * where this program needs privileges to access * the system information. */ void ExecuteExternal() { uid_t ruid, euid; int pid; #ifdef DEBUG printf("asload: system(%s)\n",Execute); #endif if( Execute[0] == '\0' ) { return; } ruid = getuid(); euid = geteuid(); if ( ruid == euid ) { if (system( Execute ) == -1) fprintf(stderr, "system(%s) returned an error", Execute); return; } pid = fork(); if ( pid == -1 ) { printf("asload : fork() failed (%s), command not executed", strerror(errno)); return; } if ( pid != 0 ) { /* parent process simply waits for the child and continues */ if ( waitpid(pid, 0, 0) == -1 ) { printf("asload : waitpid() for child failed (%s)", strerror(errno)); } return; } /* * child process drops the privileges * executes the command and dies */ if ( setuid(ruid) ) { printf("asload : setuid failed (%s), command not executed", strerror(errno)); exit(127); } if (system( Execute ) == -1) fprintf(stderr, "system(%s) returned an error", Execute); exit(0); } int main(int argc,char *argv[]) { int i; unsigned int borderwidth ; char *display_name = NULL; char *wname = "wmload"; XGCValues gcv; unsigned long gcm; XEvent Event; XTextProperty name; XClassHint classHint; Pixmap pixmask; Atom _XA_WM_DELETE_WINDOW = None; Geometry = ""; mywmhints.initial_state = NormalState; /* Parse command line options */ ProgName = argv[0]; for(i=1;i=argc) usage(); sscanf(argv[i], "%d", &updatespeed); continue; case 'e': if(++i >=argc) usage(); strcpy(&Execute[0], argv[i]); strcat(&Execute[0], " &"); continue; case 's': ONLYSHAPE=1; continue; case 'p': if(++i >=argc) usage(); Geometry = argv[i]; continue; case 'i': mywmhints.initial_state = IconicState; continue; case 'w': mywmhints.initial_state = WithdrawnState; continue; case 'l': if(++i >=argc) usage(); LedColor = argv[i]; continue; case 'v': fprintf(stdout, "\nwmload version: %i.%i.%i\n", major_VER, minor_VER, patch_VER); if(argc == 2) exit(0); continue; default: usage(); } } else { fprintf(stderr, "\nInvalid argument: %s\n", arg); usage(); } } /* Open the display */ if (!(dpy = XOpenDisplay(display_name))) { fprintf(stderr,"wmload: can't open display %s\n", XDisplayName(display_name)); exit (1); } screen= DefaultScreen(dpy); Root = RootWindow(dpy, screen); d_depth = DefaultDepth(dpy, screen); x_fd = XConnectionNumber(dpy); _XA_WM_DELETE_WINDOW = XInternAtom (dpy, "WM_DELETE_WINDOW", False); /* Convert XPM Data to XImage */ GetXPM(); /* Create a window to hold the banner */ mysizehints.flags= USSize|USPosition; mysizehints.x = 0; mysizehints.y = 0; back_pix = GetColor("white"); fore_pix = GetColor("black"); XWMGeometry(dpy, screen, Geometry, NULL, (borderwidth =1), &mysizehints, &mysizehints.x,&mysizehints.y,&mysizehints.width,&mysizehints.height, &i); mysizehints.width = wmload.attributes.width; mysizehints.height= wmload.attributes.height; win = XCreateSimpleWindow(dpy,Root,mysizehints.x,mysizehints.y, mysizehints.width,mysizehints.height, borderwidth,fore_pix,back_pix); iconwin = XCreateSimpleWindow(dpy,win,mysizehints.x,mysizehints.y, mysizehints.width,mysizehints.height, borderwidth,fore_pix,back_pix); /* activate hints */ XSetWMNormalHints(dpy, win, &mysizehints); classHint.res_name = "wmload"; classHint.res_class = "WMLoad"; XSetClassHint(dpy, win, &classHint); XSelectInput(dpy,win,MW_EVENTS); XSelectInput(dpy,iconwin,MW_EVENTS); XSetCommand(dpy,win,argv,argc); if (XStringListToTextProperty(&wname, 1, &name) ==0) { fprintf(stderr, "wmload: can't allocate window name\n"); exit(-1); } XSetWMName(dpy, win, &name); /* Create a GC for drawing */ gcm = GCForeground|GCBackground|GCGraphicsExposures; gcv.foreground = fore_pix; gcv.background = back_pix; gcv.graphics_exposures = FALSE; NormalGC = XCreateGC(dpy, Root, gcm, &gcv); if (ONLYSHAPE) { /* try to make shaped window here */ pixmask = XCreateBitmapFromData(dpy, win, (char *)mask2_bits, mask2_width, mask2_height); XShapeCombineMask(dpy, win, ShapeBounding, 0, 0, pixmask, ShapeSet); XShapeCombineMask(dpy, iconwin, ShapeBounding, 0, 0, pixmask, ShapeSet); } mywmhints.icon_window = iconwin; mywmhints.icon_x = mysizehints.x; mywmhints.icon_y = mysizehints.y; mywmhints.window_group = win; mywmhints.flags = StateHint | IconWindowHint | IconPositionHint | WindowGroupHint; XSetWMHints(dpy, win, &mywmhints); XSetWMProtocols (dpy, win, &_XA_WM_DELETE_WINDOW, 1); XMapWindow(dpy,win); InitLoad(); InsertLoad(); RedrawWindow(&visible); while(1) { if (actualtime != time(0)) { actualtime = time(0); if(actualtime % updatespeed == 0) InsertLoad(); RedrawWindow(&visible); } /* read a packet */ while (XPending(dpy)) { XNextEvent(dpy,&Event); switch(Event.type) { case Expose: if(Event.xexpose.count == 0 ) RedrawWindow(&visible); break; case ButtonPress: ExecuteExternal(); break; case ClientMessage: if ((Event.xclient.format != 32) || ((Atom)Event.xclient.data.l[0] != _XA_WM_DELETE_WINDOW)) break; case DestroyNotify: XFreeGC(dpy, NormalGC); XDestroyWindow(dpy, iconwin); XDestroyWindow(dpy, win); XCloseDisplay(dpy); exit(0); break ; default: break; } } XFlush(dpy); #ifdef SYSV poll((struct poll *) 0, (size_t) 0, 50); #else { struct timespec ts; ts.tv_sec = 0; ts.tv_nsec = 50000000L; /* 5/100 sec */ nanosleep(&ts, NULL); } #endif } return 0; } /*****************************************************************************/ void nocolor(char *a, char *b) { fprintf(stderr,"wmload: can't %s %s\n", a,b); } /*****************************************************************************/ /* convert the XPMIcons to XImage */ void GetXPM(void) { static char **alt_xpm; XColor col; XWindowAttributes attributes; int ret; char tempc1[12],tempc2[12],tempc3[12]; float colr,colg,colb; alt_xpm =ONLYSHAPE ? mask_xpm : back_xpm; /* for the colormap */ XGetWindowAttributes(dpy,Root,&attributes); /* get user-defined color or validate the default */ if (!XParseColor (dpy, attributes.colormap, LedColor, &col)) { nocolor("parse",LedColor); } else { /* scale down the Xcolor values */ colr = col.red / 257; colg = col.green / 257; colb = col.blue / 257; /* the brightest color */ sprintf(tempc1, "S c #%.2x%.2x%.2x", (int)colr, (int)colg, (int)colb); back_xpm[47] = tempc1; /* make medium color */ colr = (colr /100) *89; colg = (colg /100) *89; colb = (colb /100) *89; sprintf(tempc2, "R c #%.2x%.2x%.2x", (int)colr, (int)colg, (int)colb); back_xpm[46] = tempc2; /* make darkest color */ colr = (colr /100) *89; colg = (colg /100) *89; colb = (colb /100) *89; sprintf(tempc3, "Q c #%.2x%.2x%.2x", (int)colr, (int)colg, (int)colb); back_xpm[45] = tempc3; } wmload.attributes.valuemask |= (XpmReturnPixels | XpmReturnExtensions); ret = XpmCreatePixmapFromData(dpy, Root, alt_xpm, &wmload.pixmap, &wmload.mask, &wmload.attributes); if(ret != XpmSuccess) {fprintf(stderr, "%s\n", ERR_colorcells);exit(1);} visible.attributes.valuemask |= (XpmReturnPixels | XpmReturnExtensions); ret = XpmCreatePixmapFromData(dpy, Root, back_xpm, &visible.pixmap, &visible.mask, &visible.attributes); if(ret != XpmSuccess) {fprintf(stderr, "%s\n", ERR_colorcells);exit(1);} } /*****************************************************************************/ /* Removes expose events for a specific window from the queue */ int flush_expose (Window w) { XEvent dummy; int i=0; while (XCheckTypedWindowEvent (dpy, w, Expose, &dummy))i++; return i; } /*****************************************************************************/ /* Draws the icon window */ void RedrawWindow( XpmIcon *v) { flush_expose (iconwin); XCopyArea(dpy,v->pixmap,iconwin,NormalGC, 0,0,v->attributes.width, v->attributes.height,0,0); flush_expose (win); XCopyArea(dpy,v->pixmap,win,NormalGC, 0,0,v->attributes.width, v->attributes.height,0,0); } /*****************************************************************************/ Pixel GetColor(char *name) { XColor color; XWindowAttributes attributes; XGetWindowAttributes(dpy,Root,&attributes); color.pixel = 0; if (!XParseColor (dpy, attributes.colormap, name, &color)) { nocolor("parse",name); } else if(!XAllocColor (dpy, attributes.colormap, &color)) { nocolor("alloc",name); } return color.pixel; } /*****************************************************************************/ void InitLoad() { /* Save the 4 base colors in wmload */ XCopyArea(dpy, visible.pixmap, wmload.pixmap, NormalGC, 6,6,3,52, Shape(6), Shape(6)); /* Copy the base panel to visible */ XCopyArea(dpy, wmload.pixmap, visible.pixmap, NormalGC, 0,0,mysizehints.width, mysizehints.height, 0 ,0); /* Remove the 4 base colors from visible */ XCopyArea(dpy, visible.pixmap, visible.pixmap, NormalGC, Shape(9),Shape(6),3,52, Shape(6), Shape(6)); } static char * skip_token(const char *p) { while (isspace(*p)) p++; while (*p && !isspace(*p)) p++; return (char *)p; } void GetLoad(int Maximum, int *usr, int *nice, int *sys, int *free) { char buffer[100];/*[4096+1];*/ int fd, len; int total; char *p; fd = open("/proc/stat", O_RDONLY); len = read(fd, buffer, sizeof(buffer)-1); close(fd); buffer[len] = '\0'; p = skip_token(buffer); /* "cpu" */ cp_time[0] = strtoul(p, &p, 0); /* user */ cp_time[1] = strtoul(p, &p, 0); /* nice */ cp_time[2] = strtoul(p, &p, 0); /* system */ cp_time[3] = strtoul(p, &p, 0); /* idle */ if( (*usr = cp_time[0] - last[0]) < 0 ) *usr = 0 ; if( (*nice = cp_time[1] - last[1]) < 0 ) *nice = 0 ; if( (*sys = cp_time[2] - last[2]) < 0 ) *sys = 0 ; if( (*free = cp_time[3] - last[3]) < 0 ) *free = 0 ; total = *usr + *nice + *sys + *free; last[0] = cp_time[0]; last[1] = cp_time[1]; last[2] = cp_time[2]; last[3] = cp_time[3]; *usr = rint(Maximum * (float)(*usr) /total); *nice =rint(Maximum * (float)(*nice) /total); *sys = rint(Maximum * (float)(*sys) /total); *free = rint(Maximum * (float)(*free) /total); } void InsertLoad() { int UserTime, NiceTime, SystemTime, FreeTime, act, constrain; GetLoad( 52, &UserTime, &NiceTime, &SystemTime, &FreeTime); constrain = (UserTime + NiceTime + SystemTime + FreeTime); if(constrain == 53) { if(FreeTime > 0) FreeTime--; else if(SystemTime > 0) SystemTime--; else if(NiceTime > 0) NiceTime--; else if(UserTime > 0) UserTime--; } else if(constrain == 51) FreeTime++; /* Move the area */ XCopyArea(dpy, visible.pixmap, visible.pixmap, NormalGC, Shape(7), Shape(6), 51, 52, Shape(6), Shape(6)); /* User Time */ act = 58 - UserTime; if(UserTime > 0) XCopyArea(dpy, wmload.pixmap, visible.pixmap, NormalGC, Shape(6), Shape(6), 1, UserTime, Shape(57), Shape(act)); /* Nice Time */ act = act - NiceTime; if(NiceTime > 0) XCopyArea(dpy, wmload.pixmap, visible.pixmap, NormalGC, Shape(7), Shape(6), 1, NiceTime, Shape(57), Shape(act)); /* System Time */ act = act - SystemTime; if(SystemTime > 0) XCopyArea(dpy, wmload.pixmap, visible.pixmap, NormalGC, Shape(8), Shape(6), 1, SystemTime, Shape(57), Shape(act)); /* Free Time */ if(FreeTime > 0) XCopyArea(dpy, wmload.pixmap, visible.pixmap, NormalGC, Shape(9), Shape(6), 1, FreeTime, Shape(57), Shape(6)); }