wmclockmon: handle fgets NULL returns and zero-length lines
[dockapps.git] / wmload / wmload.c
blob3a33696f23cff5e896ae8cbeefa02491c28212da
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@googlegroups.com>
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 200112L
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 7
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 if (system( Execute ) == -1)
149 fprintf(stderr, "system(%s) returned an error",
150 Execute);
151 return;
153 pid = fork();
154 if ( pid == -1 ) {
155 printf("asload : fork() failed (%s), command not executed",
156 strerror(errno));
157 return;
159 if ( pid != 0 ) {
160 /* parent process simply waits for the child and continues */
161 if ( waitpid(pid, 0, 0) == -1 ) {
162 printf("asload : waitpid() for child failed (%s)",
163 strerror(errno));
165 return;
168 * child process drops the privileges
169 * executes the command and dies
171 if ( setuid(ruid) ) {
172 printf("asload : setuid failed (%s), command not executed",
173 strerror(errno));
174 exit(127);
176 if (system( Execute ) == -1)
177 fprintf(stderr, "system(%s) returned an error", Execute);
178 exit(0);
180 int main(int argc,char *argv[])
182 int i;
183 unsigned int borderwidth ;
184 char *display_name = NULL;
185 char *wname = "wmload";
186 XGCValues gcv;
187 unsigned long gcm;
188 XEvent Event;
189 XTextProperty name;
190 XClassHint classHint;
191 Pixmap pixmask;
192 Atom _XA_WM_DELETE_WINDOW = None;
193 Geometry = "";
194 mywmhints.initial_state = NormalState;
196 /* Parse command line options */
197 ProgName = argv[0];
199 for(i=1;i<argc;i++) {
200 char *arg= argv[i];
202 if (arg[0] == '-') {
203 switch(arg[1]) {
204 case 'u':
205 if(++i >=argc) usage();
206 sscanf(argv[i], "%d", &updatespeed);
207 continue;
208 case 'e':
209 if(++i >=argc) usage();
210 strcpy(&Execute[0], argv[i]);
211 strcat(&Execute[0], " &");
212 continue;
213 case 's':
214 ONLYSHAPE=1;
215 continue;
216 case 'p':
217 if(++i >=argc) usage();
218 Geometry = argv[i];
219 continue;
220 case 'i':
221 mywmhints.initial_state = IconicState;
222 continue;
223 case 'w':
224 mywmhints.initial_state = WithdrawnState;
225 continue;
226 case 'l':
227 if(++i >=argc) usage();
228 LedColor = argv[i];
229 continue;
230 case 'v':
231 fprintf(stdout, "\nwmload version: %i.%i.%i\n", major_VER, minor_VER, patch_VER);
232 if(argc == 2) exit(0);
233 continue;
234 default:
235 usage();
238 else
240 fprintf(stderr, "\nInvalid argument: %s\n", arg);
241 usage();
245 /* Open the display */
246 if (!(dpy = XOpenDisplay(display_name)))
248 fprintf(stderr,"wmload: can't open display %s\n",
249 XDisplayName(display_name));
250 exit (1);
253 screen= DefaultScreen(dpy);
254 Root = RootWindow(dpy, screen);
255 d_depth = DefaultDepth(dpy, screen);
256 x_fd = XConnectionNumber(dpy);
257 _XA_WM_DELETE_WINDOW = XInternAtom (dpy, "WM_DELETE_WINDOW", False);
259 /* Convert XPM Data to XImage */
260 GetXPM();
262 /* Create a window to hold the banner */
263 mysizehints.flags= USSize|USPosition;
264 mysizehints.x = 0;
265 mysizehints.y = 0;
267 back_pix = GetColor("white");
268 fore_pix = GetColor("black");
270 XWMGeometry(dpy, screen, Geometry, NULL, (borderwidth =1), &mysizehints,
271 &mysizehints.x,&mysizehints.y,&mysizehints.width,&mysizehints.height, &i);
273 mysizehints.width = wmload.attributes.width;
274 mysizehints.height= wmload.attributes.height;
276 win = XCreateSimpleWindow(dpy,Root,mysizehints.x,mysizehints.y,
277 mysizehints.width,mysizehints.height,
278 borderwidth,fore_pix,back_pix);
279 iconwin = XCreateSimpleWindow(dpy,win,mysizehints.x,mysizehints.y,
280 mysizehints.width,mysizehints.height,
281 borderwidth,fore_pix,back_pix);
283 /* activate hints */
284 XSetWMNormalHints(dpy, win, &mysizehints);
285 classHint.res_name = "wmload";
286 classHint.res_class = "WMLoad";
287 XSetClassHint(dpy, win, &classHint);
289 XSelectInput(dpy,win,MW_EVENTS);
290 XSelectInput(dpy,iconwin,MW_EVENTS);
291 XSetCommand(dpy,win,argv,argc);
293 if (XStringListToTextProperty(&wname, 1, &name) ==0) {
294 fprintf(stderr, "wmload: can't allocate window name\n");
295 exit(-1);
297 XSetWMName(dpy, win, &name);
299 /* Create a GC for drawing */
300 gcm = GCForeground|GCBackground|GCGraphicsExposures;
301 gcv.foreground = fore_pix;
302 gcv.background = back_pix;
303 gcv.graphics_exposures = FALSE;
304 NormalGC = XCreateGC(dpy, Root, gcm, &gcv);
306 if (ONLYSHAPE) { /* try to make shaped window here */
307 pixmask = XCreateBitmapFromData(dpy, win, (char *)mask2_bits, mask2_width,
308 mask2_height);
309 XShapeCombineMask(dpy, win, ShapeBounding, 0, 0, pixmask, ShapeSet);
310 XShapeCombineMask(dpy, iconwin, ShapeBounding, 0, 0, pixmask, ShapeSet);
313 mywmhints.icon_window = iconwin;
314 mywmhints.icon_x = mysizehints.x;
315 mywmhints.icon_y = mysizehints.y;
316 mywmhints.window_group = win;
317 mywmhints.flags = StateHint | IconWindowHint | IconPositionHint
318 | WindowGroupHint;
319 XSetWMHints(dpy, win, &mywmhints);
320 XSetWMProtocols (dpy, win, &_XA_WM_DELETE_WINDOW, 1);
322 XMapWindow(dpy,win);
323 InitLoad();
324 InsertLoad();
325 RedrawWindow(&visible);
326 while(1)
328 if (actualtime != time(0))
330 actualtime = time(0);
332 if(actualtime % updatespeed == 0)
333 InsertLoad();
335 RedrawWindow(&visible);
338 /* read a packet */
339 while (XPending(dpy))
341 XNextEvent(dpy,&Event);
342 switch(Event.type)
344 case Expose:
345 if(Event.xexpose.count == 0 )
346 RedrawWindow(&visible);
347 break;
348 case ButtonPress:
349 ExecuteExternal();
350 break;
351 case ClientMessage:
352 if ((Event.xclient.format != 32) ||
353 ((Atom)Event.xclient.data.l[0] != _XA_WM_DELETE_WINDOW))
354 break;
355 case DestroyNotify:
356 XFreeGC(dpy, NormalGC);
357 XDestroyWindow(dpy, iconwin);
358 XDestroyWindow(dpy, win);
359 XCloseDisplay(dpy);
360 exit(0);
361 break ;
362 default:
363 break;
366 XFlush(dpy);
367 #ifdef SYSV
368 poll((struct poll *) 0, (size_t) 0, 50);
369 #else
371 struct timespec ts;
373 ts.tv_sec = 0;
374 ts.tv_nsec = 50000000L; /* 5/100 sec */
375 nanosleep(&ts, NULL);
377 #endif
379 return 0;
382 /*****************************************************************************/
383 void nocolor(char *a, char *b)
385 fprintf(stderr,"wmload: can't %s %s\n", a,b);
388 /*****************************************************************************/
389 /* convert the XPMIcons to XImage */
390 void GetXPM(void)
392 static char **alt_xpm;
393 XColor col;
394 XWindowAttributes attributes;
395 int ret;
396 char tempc1[12],tempc2[12],tempc3[12];
397 float colr,colg,colb;
399 alt_xpm =ONLYSHAPE ? mask_xpm : back_xpm;
401 /* for the colormap */
402 XGetWindowAttributes(dpy,Root,&attributes);
404 /* get user-defined color or validate the default */
405 if (!XParseColor (dpy, attributes.colormap, LedColor, &col))
407 nocolor("parse",LedColor);
409 else
411 /* scale down the Xcolor values */
412 colr = col.red / 257;
413 colg = col.green / 257;
414 colb = col.blue / 257;
415 /* the brightest color */
416 sprintf(tempc1, "S c #%.2x%.2x%.2x", (int)colr, (int)colg, (int)colb);
417 back_xpm[47] = tempc1;
419 /* make medium color */
420 colr = (colr /100) *89;
421 colg = (colg /100) *89;
422 colb = (colb /100) *89;
423 sprintf(tempc2, "R c #%.2x%.2x%.2x", (int)colr, (int)colg, (int)colb);
424 back_xpm[46] = tempc2;
426 /* make darkest color */
427 colr = (colr /100) *89;
428 colg = (colg /100) *89;
429 colb = (colb /100) *89;
430 sprintf(tempc3, "Q c #%.2x%.2x%.2x", (int)colr, (int)colg, (int)colb);
431 back_xpm[45] = tempc3;
434 wmload.attributes.valuemask |= (XpmReturnPixels | XpmReturnExtensions);
435 ret = XpmCreatePixmapFromData(dpy, Root, alt_xpm, &wmload.pixmap,
436 &wmload.mask, &wmload.attributes);
437 if(ret != XpmSuccess)
438 {fprintf(stderr, "%s\n", ERR_colorcells);exit(1);}
440 visible.attributes.valuemask |= (XpmReturnPixels | XpmReturnExtensions);
441 ret = XpmCreatePixmapFromData(dpy, Root, back_xpm, &visible.pixmap,
442 &visible.mask, &visible.attributes);
443 if(ret != XpmSuccess)
444 {fprintf(stderr, "%s\n", ERR_colorcells);exit(1);}
448 /*****************************************************************************/
449 /* Removes expose events for a specific window from the queue */
450 int flush_expose (Window w)
452 XEvent dummy;
453 int i=0;
455 while (XCheckTypedWindowEvent (dpy, w, Expose, &dummy))i++;
456 return i;
459 /*****************************************************************************/
460 /* Draws the icon window */
461 void RedrawWindow( XpmIcon *v)
463 flush_expose (iconwin);
464 XCopyArea(dpy,v->pixmap,iconwin,NormalGC,
465 0,0,v->attributes.width, v->attributes.height,0,0);
466 flush_expose (win);
467 XCopyArea(dpy,v->pixmap,win,NormalGC,
468 0,0,v->attributes.width, v->attributes.height,0,0);
472 /*****************************************************************************/
473 Pixel GetColor(char *name)
475 XColor color;
476 XWindowAttributes attributes;
478 XGetWindowAttributes(dpy,Root,&attributes);
479 color.pixel = 0;
480 if (!XParseColor (dpy, attributes.colormap, name, &color))
482 nocolor("parse",name);
484 else if(!XAllocColor (dpy, attributes.colormap, &color))
486 nocolor("alloc",name);
488 return color.pixel;
491 /*****************************************************************************/
492 void InitLoad()
494 /* Save the 4 base colors in wmload */
495 XCopyArea(dpy, visible.pixmap, wmload.pixmap, NormalGC,
496 6,6,3,52, Shape(6), Shape(6));
498 /* Copy the base panel to visible */
499 XCopyArea(dpy, wmload.pixmap, visible.pixmap, NormalGC,
500 0,0,mysizehints.width, mysizehints.height, 0 ,0);
502 /* Remove the 4 base colors from visible */
503 XCopyArea(dpy, visible.pixmap, visible.pixmap, NormalGC,
504 Shape(9),Shape(6),3,52, Shape(6), Shape(6));
507 static char *
508 skip_token(const char *p)
510 while (isspace(*p)) p++;
511 while (*p && !isspace(*p)) p++;
512 return (char *)p;
515 void GetLoad(int Maximum, int *usr, int *nice, int *sys, int *free)
517 char buffer[100];/*[4096+1];*/
518 int fd, len;
519 int total;
520 char *p;
522 fd = open("/proc/stat", O_RDONLY);
523 len = read(fd, buffer, sizeof(buffer)-1);
524 close(fd);
525 buffer[len] = '\0';
527 p = skip_token(buffer); /* "cpu" */
529 cp_time[0] = strtoul(p, &p, 0); /* user */
530 cp_time[1] = strtoul(p, &p, 0); /* nice */
531 cp_time[2] = strtoul(p, &p, 0); /* system */
532 cp_time[3] = strtoul(p, &p, 0); /* idle */
534 if( (*usr = cp_time[0] - last[0]) < 0 ) *usr = 0 ;
535 if( (*nice = cp_time[1] - last[1]) < 0 ) *nice = 0 ;
536 if( (*sys = cp_time[2] - last[2]) < 0 ) *sys = 0 ;
537 if( (*free = cp_time[3] - last[3]) < 0 ) *free = 0 ;
539 total = *usr + *nice + *sys + *free;
541 last[0] = cp_time[0];
542 last[1] = cp_time[1];
543 last[2] = cp_time[2];
544 last[3] = cp_time[3];
546 *usr = rint(Maximum * (float)(*usr) /total);
547 *nice =rint(Maximum * (float)(*nice) /total);
548 *sys = rint(Maximum * (float)(*sys) /total);
549 *free = rint(Maximum * (float)(*free) /total);
552 void InsertLoad()
554 int UserTime, NiceTime, SystemTime, FreeTime, act, constrain;
555 GetLoad( 52, &UserTime, &NiceTime, &SystemTime, &FreeTime);
557 constrain = (UserTime + NiceTime + SystemTime + FreeTime);
558 if(constrain == 53)
560 if(FreeTime > 0) FreeTime--;
561 else if(SystemTime > 0) SystemTime--;
562 else if(NiceTime > 0) NiceTime--;
563 else if(UserTime > 0) UserTime--;
565 else if(constrain == 51) FreeTime++;
567 /* Move the area */
568 XCopyArea(dpy, visible.pixmap, visible.pixmap, NormalGC,
569 Shape(7), Shape(6), 51, 52, Shape(6), Shape(6));
572 /* User Time */
573 act = 58 - UserTime;
574 if(UserTime > 0)
575 XCopyArea(dpy, wmload.pixmap, visible.pixmap, NormalGC,
576 Shape(6), Shape(6), 1, UserTime, Shape(57), Shape(act));
578 /* Nice Time */
579 act = act - NiceTime;
580 if(NiceTime > 0)
581 XCopyArea(dpy, wmload.pixmap, visible.pixmap, NormalGC,
582 Shape(7), Shape(6), 1, NiceTime, Shape(57), Shape(act));
584 /* System Time */
585 act = act - SystemTime;
586 if(SystemTime > 0)
587 XCopyArea(dpy, wmload.pixmap, visible.pixmap, NormalGC,
588 Shape(8), Shape(6), 1, SystemTime, Shape(57), Shape(act));
590 /* Free Time */
591 if(FreeTime > 0)
592 XCopyArea(dpy, wmload.pixmap, visible.pixmap, NormalGC,
593 Shape(9), Shape(6), 1, FreeTime, Shape(57), Shape(6));