b8f83f2c0ac972d38acc95d88e0cbc7924206bd5
[dockapps.git] / wmload / wmload.c
blobb8f83f2c0ac972d38acc95d88e0cbc7924206bd5
1 /* wmload - system load monitor designed for Window Maker
2 * Copyright (C) 1996 Beat Christen <bchriste@iiic.ethz.ch>
3 * Copyright (C) 1997 Ryan Land <rland@bc1.com>
4 * Copyright (C) 2015 Window Maker Developers Team
5 * <wmaker-dev@lists.windowmaker.org>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
21 #define _POSIX_C_SOURCE 199309L
23 #include <stdio.h>
24 #include <string.h>
25 #include <unistd.h>
26 #include <stdlib.h>
27 #include <ctype.h>
28 #include <errno.h>
29 #include <sys/wait.h>
31 #include <X11/Xlib.h>
32 #include <X11/xpm.h>
33 #include <X11/extensions/shape.h>
34 #include <time.h>
35 #include <math.h>
36 #include <fcntl.h>
37 #include <X11/Xatom.h>
39 #include "back.xpm"
40 #include "mask2.xbm"
41 #include "mask.xpm"
43 #define major_VER 0
44 #define minor_VER 9
45 #define patch_VER 5
46 #define MW_EVENTS (ExposureMask | ButtonPressMask | StructureNotifyMask)
47 #define FALSE 0
48 #define Shape(num) (ONLYSHAPE ? num-5 : num)
49 #define NCPUSTATES 4
51 /* Global Data storage/structures ********************************************/
52 static long cp_time[NCPUSTATES];
53 static long last[NCPUSTATES];
54 int ONLYSHAPE=0; /* default value is noshape */
55 int updatespeed = 4;
56 static char *help_message[] = {
57 "where options include:",
58 " -u <secs> updatespeed",
59 " -exe <program> program to start on click",
60 " -led <color> color of the led",
61 " -position [+|-]x[+|-]y position of wmload",
62 " -shape without groundplate",
63 " -iconic start up as icon",
64 " -withdrawn start up withdrawn",
65 " -ver output version",
66 NULL
69 /* X11 Variables *************************************************************/
70 Display *dpy; /* welches DISPLAY */
71 Window Root; /* Hintergrund-Drawable */
72 int screen;
73 int x_fd;
74 int d_depth;
75 XSizeHints mysizehints;
76 XWMHints mywmhints;
77 Pixel back_pix, fore_pix;
78 GC NormalGC;
79 Window iconwin, win; /* My home is my window */
80 char *ProgName;
81 char *Geometry;
82 char *LedColor = "LightSeaGreen";
83 char Execute[] = "echo no program has been specified";
84 char *ERR_colorcells = "not enough free color cells\n";
85 char *ampers = " &";
87 /* XPM Structures & Variables ************************************************/
88 typedef struct _XpmIcon {
89 Pixmap pixmap;
90 Pixmap mask;
91 XpmAttributes attributes;
92 } XpmIcon;
94 XpmIcon wmload;
95 XpmIcon visible;
96 time_t actualtime;
97 long actualmin;
99 /* Function definitions ******************************************************/
100 void GetXPM(void);
101 Pixel GetColor(char *name);
102 void RedrawWindow( XpmIcon *v);
103 void InitLoad();
104 void InsertLoad();
106 /*****************************************************************************/
107 /* Source Code <--> Function Implementations */
108 /*****************************************************************************/
109 void usage()
111 char **cpp;
113 fprintf(stderr,"\nusage: %s [-options ...] \n", ProgName);
114 for (cpp = help_message; *cpp; cpp++) {
115 fprintf(stderr, "%s\n", *cpp);
117 fprintf(stderr,"\n");
118 exit(1);
122 * Copied from ascpu - albert@tigr.net - 09 Mar 2000
124 * This function executes an external command while
125 * checking whether we should drop the privileges.
127 * Since we might need privileges later we fork and
128 * then drop privileges in one of the instances which
129 * will then execute the command and die.
131 * This fixes the security hole for FreeBSD and AIX
132 * where this program needs privileges to access
133 * the system information.
135 void ExecuteExternal()
137 uid_t ruid, euid;
138 int pid;
139 #ifdef DEBUG
140 printf("asload: system(%s)\n",Execute);
141 #endif
142 if( Execute[0] == '\0' ) {
143 return;
145 ruid = getuid();
146 euid = geteuid();
147 if ( ruid == euid ) {
148 system( Execute );
149 return;
151 pid = fork();
152 if ( pid == -1 ) {
153 printf("asload : fork() failed (%s), command not executed",
154 strerror(errno));
155 return;
157 if ( pid != 0 ) {
158 /* parent process simply waits for the child and continues */
159 if ( waitpid(pid, 0, 0) == -1 ) {
160 printf("asload : waitpid() for child failed (%s)",
161 strerror(errno));
163 return;
166 * child process drops the privileges
167 * executes the command and dies
169 if ( setuid(ruid) ) {
170 printf("asload : setuid failed (%s), command not executed",
171 strerror(errno));
172 exit(127);
174 system( Execute );
175 exit(0);
177 int main(int argc,char *argv[])
179 int i;
180 unsigned int borderwidth ;
181 char *display_name = NULL;
182 char *wname = "wmload";
183 XGCValues gcv;
184 unsigned long gcm;
185 XEvent Event;
186 XTextProperty name;
187 XClassHint classHint;
188 Pixmap pixmask;
189 Atom _XA_WM_DELETE_WINDOW = None;
190 Geometry = "";
191 mywmhints.initial_state = NormalState;
193 /* Parse command line options */
194 ProgName = argv[0];
196 for(i=1;i<argc;i++) {
197 char *arg= argv[i];
199 if (arg[0] == '-') {
200 switch(arg[1]) {
201 case 'u':
202 if(++i >=argc) usage();
203 sscanf(argv[i], "%d", &updatespeed);
204 continue;
205 case 'e':
206 if(++i >=argc) usage();
207 strcpy(&Execute[0], argv[i]);
208 strcat(&Execute[0], " &");
209 continue;
210 case 's':
211 ONLYSHAPE=1;
212 continue;
213 case 'p':
214 if(++i >=argc) usage();
215 Geometry = argv[i];
216 continue;
217 case 'i':
218 mywmhints.initial_state = IconicState;
219 continue;
220 case 'w':
221 mywmhints.initial_state = WithdrawnState;
222 continue;
223 case 'l':
224 if(++i >=argc) usage();
225 LedColor = argv[i];
226 continue;
227 case 'v':
228 fprintf(stdout, "\nwmload version: %i.%i.%i\n", major_VER, minor_VER, patch_VER);
229 if(argc == 2) exit(0);
230 continue;
231 default:
232 usage();
235 else
237 fprintf(stderr, "\nInvalid argument: %s\n", arg);
238 usage();
242 /* Open the display */
243 if (!(dpy = XOpenDisplay(display_name)))
245 fprintf(stderr,"wmload: can't open display %s\n",
246 XDisplayName(display_name));
247 exit (1);
250 screen= DefaultScreen(dpy);
251 Root = RootWindow(dpy, screen);
252 d_depth = DefaultDepth(dpy, screen);
253 x_fd = XConnectionNumber(dpy);
254 _XA_WM_DELETE_WINDOW = XInternAtom (dpy, "WM_DELETE_WINDOW", False);
256 /* Convert XPM Data to XImage */
257 GetXPM();
259 /* Create a window to hold the banner */
260 mysizehints.flags= USSize|USPosition;
261 mysizehints.x = 0;
262 mysizehints.y = 0;
264 back_pix = GetColor("white");
265 fore_pix = GetColor("black");
267 XWMGeometry(dpy, screen, Geometry, NULL, (borderwidth =1), &mysizehints,
268 &mysizehints.x,&mysizehints.y,&mysizehints.width,&mysizehints.height, &i);
270 mysizehints.width = wmload.attributes.width;
271 mysizehints.height= wmload.attributes.height;
273 win = XCreateSimpleWindow(dpy,Root,mysizehints.x,mysizehints.y,
274 mysizehints.width,mysizehints.height,
275 borderwidth,fore_pix,back_pix);
276 iconwin = XCreateSimpleWindow(dpy,win,mysizehints.x,mysizehints.y,
277 mysizehints.width,mysizehints.height,
278 borderwidth,fore_pix,back_pix);
280 /* activate hints */
281 XSetWMNormalHints(dpy, win, &mysizehints);
282 classHint.res_name = "wmload";
283 classHint.res_class = "WMLoad";
284 XSetClassHint(dpy, win, &classHint);
286 XSelectInput(dpy,win,MW_EVENTS);
287 XSelectInput(dpy,iconwin,MW_EVENTS);
288 XSetCommand(dpy,win,argv,argc);
290 if (XStringListToTextProperty(&wname, 1, &name) ==0) {
291 fprintf(stderr, "wmload: can't allocate window name\n");
292 exit(-1);
294 XSetWMName(dpy, win, &name);
296 /* Create a GC for drawing */
297 gcm = GCForeground|GCBackground|GCGraphicsExposures;
298 gcv.foreground = fore_pix;
299 gcv.background = back_pix;
300 gcv.graphics_exposures = FALSE;
301 NormalGC = XCreateGC(dpy, Root, gcm, &gcv);
303 if (ONLYSHAPE) { /* try to make shaped window here */
304 pixmask = XCreateBitmapFromData(dpy, win, (char *)mask2_bits, mask2_width,
305 mask2_height);
306 XShapeCombineMask(dpy, win, ShapeBounding, 0, 0, pixmask, ShapeSet);
307 XShapeCombineMask(dpy, iconwin, ShapeBounding, 0, 0, pixmask, ShapeSet);
310 mywmhints.icon_window = iconwin;
311 mywmhints.icon_x = mysizehints.x;
312 mywmhints.icon_y = mysizehints.y;
313 mywmhints.window_group = win;
314 mywmhints.flags = StateHint | IconWindowHint | IconPositionHint
315 | WindowGroupHint;
316 XSetWMHints(dpy, win, &mywmhints);
317 XSetWMProtocols (dpy, win, &_XA_WM_DELETE_WINDOW, 1);
319 XMapWindow(dpy,win);
320 InitLoad();
321 InsertLoad();
322 RedrawWindow(&visible);
323 while(1)
325 if (actualtime != time(0))
327 actualtime = time(0);
329 if(actualtime % updatespeed == 0)
330 InsertLoad();
332 RedrawWindow(&visible);
335 /* read a packet */
336 while (XPending(dpy))
338 XNextEvent(dpy,&Event);
339 switch(Event.type)
341 case Expose:
342 if(Event.xexpose.count == 0 )
343 RedrawWindow(&visible);
344 break;
345 case ButtonPress:
346 ExecuteExternal();
347 break;
348 case ClientMessage:
349 if ((Event.xclient.format != 32) ||
350 ((Atom)Event.xclient.data.l[0] != _XA_WM_DELETE_WINDOW))
351 break;
352 case DestroyNotify:
353 XFreeGC(dpy, NormalGC);
354 XDestroyWindow(dpy, iconwin);
355 XDestroyWindow(dpy, win);
356 XCloseDisplay(dpy);
357 exit(0);
358 break ;
359 default:
360 break;
363 XFlush(dpy);
364 #ifdef SYSV
365 poll((struct poll *) 0, (size_t) 0, 50);
366 #else
368 struct timespec ts;
370 ts.tv_sec = 0;
371 ts.tv_nsec = 50000000L; /* 5/100 sec */
372 nanosleep(&ts, NULL);
374 #endif
376 return 0;
379 /*****************************************************************************/
380 void nocolor(char *a, char *b)
382 fprintf(stderr,"wmload: can't %s %s\n", a,b);
385 /*****************************************************************************/
386 /* convert the XPMIcons to XImage */
387 void GetXPM(void)
389 static char **alt_xpm;
390 XColor col;
391 XWindowAttributes attributes;
392 int ret;
393 char tempc1[12],tempc2[12],tempc3[12];
394 float colr,colg,colb;
396 alt_xpm =ONLYSHAPE ? mask_xpm : back_xpm;
398 /* for the colormap */
399 XGetWindowAttributes(dpy,Root,&attributes);
401 /* get user-defined color or validate the default */
402 if (!XParseColor (dpy, attributes.colormap, LedColor, &col))
404 nocolor("parse",LedColor);
406 else
408 /* scale down the Xcolor values */
409 colr = col.red / 257;
410 colg = col.green / 257;
411 colb = col.blue / 257;
412 /* the brightest color */
413 sprintf(tempc1, "S c #%.2x%.2x%.2x", (int)colr, (int)colg, (int)colb);
414 back_xpm[47] = tempc1;
416 /* make medium color */
417 colr = (colr /100) *89;
418 colg = (colg /100) *89;
419 colb = (colb /100) *89;
420 sprintf(tempc2, "R c #%.2x%.2x%.2x", (int)colr, (int)colg, (int)colb);
421 back_xpm[46] = tempc2;
423 /* make darkest color */
424 colr = (colr /100) *89;
425 colg = (colg /100) *89;
426 colb = (colb /100) *89;
427 sprintf(tempc3, "Q c #%.2x%.2x%.2x", (int)colr, (int)colg, (int)colb);
428 back_xpm[45] = tempc3;
431 wmload.attributes.valuemask |= (XpmReturnPixels | XpmReturnExtensions);
432 ret = XpmCreatePixmapFromData(dpy, Root, alt_xpm, &wmload.pixmap,
433 &wmload.mask, &wmload.attributes);
434 if(ret != XpmSuccess)
435 {fprintf(stderr, "%s\n", ERR_colorcells);exit(1);}
437 visible.attributes.valuemask |= (XpmReturnPixels | XpmReturnExtensions);
438 ret = XpmCreatePixmapFromData(dpy, Root, back_xpm, &visible.pixmap,
439 &visible.mask, &visible.attributes);
440 if(ret != XpmSuccess)
441 {fprintf(stderr, "%s\n", ERR_colorcells);exit(1);}
445 /*****************************************************************************/
446 /* Removes expose events for a specific window from the queue */
447 int flush_expose (Window w)
449 XEvent dummy;
450 int i=0;
452 while (XCheckTypedWindowEvent (dpy, w, Expose, &dummy))i++;
453 return i;
456 /*****************************************************************************/
457 /* Draws the icon window */
458 void RedrawWindow( XpmIcon *v)
460 flush_expose (iconwin);
461 XCopyArea(dpy,v->pixmap,iconwin,NormalGC,
462 0,0,v->attributes.width, v->attributes.height,0,0);
463 flush_expose (win);
464 XCopyArea(dpy,v->pixmap,win,NormalGC,
465 0,0,v->attributes.width, v->attributes.height,0,0);
469 /*****************************************************************************/
470 Pixel GetColor(char *name)
472 XColor color;
473 XWindowAttributes attributes;
475 XGetWindowAttributes(dpy,Root,&attributes);
476 color.pixel = 0;
477 if (!XParseColor (dpy, attributes.colormap, name, &color))
479 nocolor("parse",name);
481 else if(!XAllocColor (dpy, attributes.colormap, &color))
483 nocolor("alloc",name);
485 return color.pixel;
488 /*****************************************************************************/
489 void InitLoad()
491 /* Save the 4 base colors in wmload */
492 XCopyArea(dpy, visible.pixmap, wmload.pixmap, NormalGC,
493 6,6,3,52, Shape(6), Shape(6));
495 /* Copy the base panel to visible */
496 XCopyArea(dpy, wmload.pixmap, visible.pixmap, NormalGC,
497 0,0,mysizehints.width, mysizehints.height, 0 ,0);
499 /* Remove the 4 base colors from visible */
500 XCopyArea(dpy, visible.pixmap, visible.pixmap, NormalGC,
501 Shape(9),Shape(6),3,52, Shape(6), Shape(6));
504 static char *
505 skip_token(const char *p)
507 while (isspace(*p)) p++;
508 while (*p && !isspace(*p)) p++;
509 return (char *)p;
512 void GetLoad(int Maximum, int *usr, int *nice, int *sys, int *free)
514 char buffer[100];/*[4096+1];*/
515 int fd, len;
516 int total;
517 char *p;
519 fd = open("/proc/stat", O_RDONLY);
520 len = read(fd, buffer, sizeof(buffer)-1);
521 close(fd);
522 buffer[len] = '\0';
524 p = skip_token(buffer); /* "cpu" */
526 cp_time[0] = strtoul(p, &p, 0); /* user */
527 cp_time[1] = strtoul(p, &p, 0); /* nice */
528 cp_time[2] = strtoul(p, &p, 0); /* system */
529 cp_time[3] = strtoul(p, &p, 0); /* idle */
531 if( (*usr = cp_time[0] - last[0]) < 0 ) *usr = 0 ;
532 if( (*nice = cp_time[1] - last[1]) < 0 ) *nice = 0 ;
533 if( (*sys = cp_time[2] - last[2]) < 0 ) *sys = 0 ;
534 if( (*free = cp_time[3] - last[3]) < 0 ) *free = 0 ;
536 total = *usr + *nice + *sys + *free;
538 last[0] = cp_time[0];
539 last[1] = cp_time[1];
540 last[2] = cp_time[2];
541 last[3] = cp_time[3];
543 *usr = rint(Maximum * (float)(*usr) /total);
544 *nice =rint(Maximum * (float)(*nice) /total);
545 *sys = rint(Maximum * (float)(*sys) /total);
546 *free = rint(Maximum * (float)(*free) /total);
549 void InsertLoad()
551 int UserTime, NiceTime, SystemTime, FreeTime, act, constrain;
552 GetLoad( 52, &UserTime, &NiceTime, &SystemTime, &FreeTime);
554 constrain = (UserTime + NiceTime + SystemTime + FreeTime);
555 if(constrain == 53)
557 if(FreeTime > 0) FreeTime--;
558 else if(SystemTime > 0) SystemTime--;
559 else if(NiceTime > 0) NiceTime--;
560 else if(UserTime > 0) UserTime--;
562 else if(constrain == 51) FreeTime++;
564 /* Move the area */
565 XCopyArea(dpy, visible.pixmap, visible.pixmap, NormalGC,
566 Shape(7), Shape(6), 51, 52, Shape(6), Shape(6));
569 /* User Time */
570 act = 58 - UserTime;
571 if(UserTime > 0)
572 XCopyArea(dpy, wmload.pixmap, visible.pixmap, NormalGC,
573 Shape(6), Shape(6), 1, UserTime, Shape(57), Shape(act));
575 /* Nice Time */
576 act = act - NiceTime;
577 if(NiceTime > 0)
578 XCopyArea(dpy, wmload.pixmap, visible.pixmap, NormalGC,
579 Shape(7), Shape(6), 1, NiceTime, Shape(57), Shape(act));
581 /* System Time */
582 act = act - SystemTime;
583 if(SystemTime > 0)
584 XCopyArea(dpy, wmload.pixmap, visible.pixmap, NormalGC,
585 Shape(8), Shape(6), 1, SystemTime, Shape(57), Shape(act));
587 /* Free Time */
588 if(FreeTime > 0)
589 XCopyArea(dpy, wmload.pixmap, visible.pixmap, NormalGC,
590 Shape(9), Shape(6), 1, FreeTime, Shape(57), Shape(6));