dockapps/wmload/wmload.c
2015-08-24 07:17:16 +01:00

595 lines
16 KiB
C

/* wmload - system load monitor designed for Window Maker
* Copyright (C) 1996 Beat Christen <bchriste@iiic.ethz.ch>
* Copyright (C) 1997 Ryan Land <rland@bc1.com>
* Copyright (C) 2015 Window Maker Developers Team
* <wmaker-dev@lists.windowmaker.org>
*
* 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 <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <ctype.h>
#include <errno.h>
#include <sys/wait.h>
#include <X11/Xlib.h>
#include <X11/xpm.h>
#include <X11/extensions/shape.h>
#include <time.h>
#include <math.h>
#include <fcntl.h>
#include <X11/Xatom.h>
#include "back.xpm"
#include "mask2.xbm"
#include "mask.xpm"
#define major_VER 0
#define minor_VER 9
#define patch_VER 7
#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 <secs> updatespeed",
" -exe <program> program to start on click",
" -led <color> 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;i++) {
char *arg= argv[i];
if (arg[0] == '-') {
switch(arg[1]) {
case 'u':
if(++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));
}