1 /* Hot-babe
2 * Copyright (C) 2002 DindinX <David@dindinx.org>
3 * Copyright (C) 2002 Bruno Bellamy.
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the artistic License
7 *
8 * THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
9 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
10 * OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. See the
11 * Artistic License for more details.
12 *
13 * this code is using some ideas from wmbubble (timecop@japan.co.jp)
14 *
15 */
16
17 /* general includes */
18 #include <stdio.h>
19 #include <unistd.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #if defined(__FreeBSD__) || defined(__DragonFly__)
23 #include <sys/time.h>
24 #include <sys/resource.h>
25 #include <sys/types.h>
26 #include <sys/sysctl.h>
27 #ifndef CPUSTATES
28 #include <sys/dkstat.h>
29 #endif
30 #endif
31
32 /* x11 includes */
33 #include <gdk/gdk.h>
34 #include <gdk/gdkx.h>
35 #include <gdk-pixbuf/gdk-pixbuf.h>
36
37 #include "loader.h"
38
39 static int system_cpu(void);
40 static void hotbabe_setup_samples(void);
41 static void hotbabe_update(void);
42 static void create_hotbabe_window(void);
43 static void print_usage(void);
44
45 /* global variables */
46
47 typedef struct
48 {
49 /* X11 stuff */
50 GdkWindow *win; /* main window */
51 HotBabeAnim anim;
52 gint x,y;
53 guchar **pixels;
54 guchar *dest;
55
56 int samples;
57
58 /* CPU percentage stuff. soon to go away */
59 int loadIndex;
60 u_int64_t *load, *total;
61 guint threshold;
62
63 /* optional stuff */
64 gboolean incremental;
65 gboolean noNice;
66 guint delay;
67 } HotBabeData;
68
69 HotBabeData bm;
70
71 #if 0
72 /* FIXME New BSD and Solaris code.. to check.
73 * doesn't work with Linux (getloadavg return 1.000) */
74 static int system_cpu(void)
75 {
76 int rc;
77 double loadavg[15];
78 rc=getloadavg(loadavg, 1);
79 while( rc-- )
80 printf( "load = %f\n", loadavg[rc] );
81 rc=100*loadavg[0];
82 return rc;
83 }
84 #endif
85
86 /* returns current CPU load in percent, 0 to 256 */
system_cpu(void)87 static int system_cpu(void)
88 {
89 unsigned int cpuload;
90 int i;
91 #ifdef __linux__
92 u_int64_t load, total, oload, ototal;
93 u_int64_t ab, ac, ad, ae;
94 FILE *stat;
95 #endif
96 #if defined(__FreeBSD__) || defined(__DragonFly__)
97 long load, total, oload, ototal;
98 long ab, ac, ad, ae;
99 long cp_time[CPUSTATES];
100 size_t len = sizeof(cp_time);
101 #endif
102
103 #ifdef __linux__
104 stat = fopen("/proc/stat", "r");
105 fscanf(stat, "%*s %Ld %Ld %Ld %Ld", &ab, &ac, &ad, &ae);
106 fclose(stat);
107 #endif
108 #if defined(__FreeBSD__) || defined(__DragonFly__)
109 if (sysctlbyname("kern.cp_time", &cp_time, &len, NULL, 0) < 0)
110 (void)fprintf(stderr, "Cannot get kern.cp_time");
111
112 ab = cp_time[CP_USER];
113 ac = cp_time[CP_NICE];
114 ad = cp_time[CP_SYS];
115 ae = cp_time[CP_IDLE];
116 #endif
117
118
119 /* Find out the CPU load */
120 /* user + sys = load
121 * total = total */
122 load = ab + ad; /* cpu.user + cpu.sys; */
123 if(!bm.noNice) load += ac;
124 total = ab + ac + ad + ae; /* cpu.total; */
125
126 i = bm.loadIndex;
127 oload = bm.load[i];
128 ototal = bm.total[i];
129
130 bm.load[i] = load;
131 bm.total[i] = total;
132 bm.loadIndex = (i + 1) % bm.samples;
133
134 /*
135 * Because the load returned from libgtop is a value accumulated
136 * over time, and not the current load, the current load percentage
137 * is calculated as the extra amount of work that has been performed
138 * since the last sample. yah, right, what the fuck does that mean?
139 */
140 if (ototal == 0 || total==ototal) /* ototal == 0 means that this is the first time we get here */
141 cpuload = 0;
142 else
143 cpuload = (256 * (load - oload)) / (total - ototal);
144
145 return cpuload;
146 }
147
148 GdkPixmap *pixmap;
149 GdkGC *gc;
150
151 /* This is the function that actually creates the display widgets */
create_hotbabe_window(void)152 static void create_hotbabe_window(void)
153 {
154 #define MASK GDK_BUTTON_PRESS_MASK | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK
155 GdkWindowAttr attr;
156 GdkBitmap *mask;
157 GdkScreen *defscrn;
158
159 bm.anim.width = gdk_pixbuf_get_width(bm.anim.pixbuf[0]);
160 bm.anim.height = gdk_pixbuf_get_height(bm.anim.pixbuf[0]);
161 defscrn=gdk_screen_get_default();
162
163 attr.width = bm.anim.width;
164 attr.height = bm.anim.height;
165 if( bm.x < 0 ) bm.x += 1 + gdk_screen_get_width(defscrn) - attr.width;
166 if( bm.y < 0 ) bm.y += 1 + gdk_screen_get_height(defscrn) - attr.height;
167 attr.x = bm.x;
168 attr.y = bm.y;
169 attr.title = "hot-babe";
170 attr.event_mask = MASK;
171 attr.wclass = GDK_INPUT_OUTPUT;
172 attr.visual = gdk_visual_get_system();
173 attr.colormap = gdk_colormap_get_system();
174 attr.wmclass_name = "hot-babe";
175 attr.wmclass_class = "hot-babe";
176 attr.window_type = GDK_WINDOW_TOPLEVEL;
177
178 bm.win = gdk_window_new(NULL, &attr,
179 GDK_WA_TITLE | GDK_WA_WMCLASS |
180 GDK_WA_VISUAL | GDK_WA_COLORMAP |
181 GDK_WA_X | GDK_WA_Y);
182 if (!bm.win)
183 {
184 fprintf(stderr, "Cannot make toplevel window\n");
185 exit (-1);
186 }
187 gdk_window_set_decorations(bm.win, 0);
188 gdk_window_set_skip_taskbar_hint(bm.win, TRUE);
189 gdk_window_set_skip_pager_hint(bm.win, TRUE);
190 gdk_window_set_type_hint(bm.win, GDK_WINDOW_TYPE_HINT_DOCK);
191 // gdk_window_set_keep_below(bm.win, TRUE);
192
193 gdk_pixbuf_render_pixmap_and_mask( bm.anim.pixbuf[bm.anim.samples-1], &pixmap, &mask, 127 );
194
195 gdk_window_shape_combine_mask(bm.win, mask, 0, 0);
196 gdk_pixbuf_render_pixmap_and_mask( bm.anim.pixbuf[0], &pixmap, &mask, 127 );
197 gdk_window_set_back_pixmap(bm.win, pixmap, False);
198
199 gdk_window_show(bm.win);
200
201 gc = gdk_gc_new (pixmap);
202 #undef MASK
203 }
204
hotbabe_update(void)205 static void hotbabe_update(void)
206 {
207 guint loadPercentage;
208 static guint old_percentage = 0;
209 guint i;
210 guchar *pixels1, *pixels2, *src1, *src2, *dest;
211 static gint robinet = 0;
212
213 /* Find out the CPU load */
214 loadPercentage = system_cpu();
215
216 if (bm.threshold)
217 {
218 if (loadPercentage < bm.threshold || bm.threshold>255)
219 loadPercentage = 0;
220 else
221 loadPercentage = (loadPercentage-bm.threshold)*256/(256-bm.threshold);
222 }
223
224 robinet +=loadPercentage/50-3;
225
226 robinet = CLAMP(robinet, 0, 256);
227
228 if (bm.incremental)
229 loadPercentage = robinet;
230
231 if (loadPercentage != old_percentage)
232 {
233 gint range = 256 / (bm.anim.samples-1);
234 gint index = loadPercentage/range;
235
236 old_percentage = loadPercentage;
237 if (index>bm.anim.samples-1) index = bm.anim.samples-1;
238 pixels1 = bm.pixels[index];
239 if (index == bm.anim.samples-1) pixels2 = bm.pixels[index];
240 else pixels2 = bm.pixels[index+1];
241
242 loadPercentage = loadPercentage % range;
243 dest = bm.dest; src1 = pixels1; src2 = pixels2;
244 for (i=0 ; i<bm.anim.height*bm.anim.width ; i++)
245 {
246 guint val, j;
247
248 if (src1[3])
249 {
250 for (j=0;j<3;j++)
251 {
252 val = ((guint)*(src2++))*loadPercentage+((guint)*(src1++))*(range-loadPercentage);
253 *(dest++) = val/range;
254 //*(dest++) = (val >> 6); // bad hack!
255 }
256 src1++;
257 src2++;
258 } else
259 {
260 src1+=4;src2+=4;dest+=3;
261 }
262 }
263
264 gdk_draw_rgb_image(pixmap, gc, 0, 0, bm.anim.width, bm.anim.height, GDK_RGB_DITHER_NONE,
265 bm.dest, 3 * bm.anim.width);
266 gdk_window_set_back_pixmap(bm.win, pixmap, False);
267 gdk_window_clear(bm.win);
268 }
269 }
270
hotbabe_setup_samples(void)271 static void hotbabe_setup_samples(void)
272 {
273 int i;
274 u_int64_t load = 0, total = 0;
275
276 bm.loadIndex = 0;
277 bm.load = malloc(bm.samples * sizeof(u_int64_t));
278 bm.total = malloc(bm.samples * sizeof(u_int64_t));
279 for (i = 0; i < bm.samples;i++)
280 {
281 bm.load[i] = load;
282 bm.total[i] = total;
283 }
284 }
285
print_version(void)286 static void print_version(void)
287 {
288 g_print("hot-babe version " VERSION "\n\n");
289 }
290
print_usage(void)291 static void print_usage(void)
292 {
293 g_print("Usage: hot-babe [OPTIONS]\n\n");
294 g_print("OPTIONS are from the following:\n\n");
295 g_print(" -t, --threshold n use only the first picture before n%%.\n");
296 g_print(" -i, --incremental incremental (slow) mode.\n");
297 g_print(" -d, --delay n update every n millisecondes.\n");
298 g_print(" -h, --help show this message and exit.\n");
299 g_print(" -N, --noNice don't count nice time in usage.\n");
300 g_print(" -n, --nice n set self-nice to n.\n");
301 g_print(" --dir directory use images from directory.\n");
302 g_print(" --geometry {+|-}x{+|-}y position the hot-babe.\n");
303 g_print(" -v, --version show version and exit.\n");
304 }
305
parse_geometry(char * arg)306 void parse_geometry( char *arg )
307 {
308 char sign[2];
309 guint val[2];
310 int i = 0;
311
312 i = sscanf( arg, "%c%u%c%u", &sign[0], &val[0], &sign[1], &val[1] );
313 if( i != 4 )
314 return;
315
316 if( sign[0] == '+' ) bm.x = val[0];
317 if( sign[0] == '-' ) bm.x = -1-val[0];
318 if( sign[1] == '+' ) bm.y = val[1];
319 if( sign[1] == '-' ) bm.y = -1-val[1];
320 }
321
main(int argc,char ** argv)322 int main(int argc, char **argv)
323 {
324 GdkEvent *event;
325
326 gint i;
327 gchar *dir;
328 char conf[256];
329 FILE *f;
330
331 /* initialize GDK */
332 if (!gdk_init_check(&argc, &argv))
333 {
334 fprintf(stderr,
335 "GDK init failed, bye bye. Check \"DISPLAY\" variable.\n");
336 exit(-1);
337 }
338 gdk_rgb_init();
339
340 /* zero data structure */
341 memset(&bm, 0, sizeof(bm));
342
343 bm.samples = 16;
344 bm.incremental = FALSE;
345 bm.delay = 15000;
346 bm.noNice = FALSE;
347 bm.x = -1;
348 bm.y = -1;
349
350 dir = NULL;
351
352
353 snprintf( conf, 256, "%s/.hot-babe/config", g_get_home_dir() );
354 f = fopen( conf, "r" );
355 if( f )
356 {
357 char line[256], *l;
358 guint uval;
359 gint val;
360 char sval[260];
361
362 while( (l=fgets( line, 255, f )) )
363 {
364 while( *l )
365 {
366 if( *l == '\n' || *l == '#' ) *l = 0;
367 l++;
368 }
369 if( !*line ) continue;
370
371 if( sscanf( line, "threshold %u", &uval ) == 1 )
372 {
373 bm.threshold = uval*256/100;
374 bm.threshold = MIN (255, bm.threshold);
375 } else if ( !strcmp(line, "incremental") )
376 {
377 bm.incremental = TRUE;
378 } else if (!strcmp(line, "noNice") )
379 {
380 bm.noNice = TRUE;
381 } else if ( sscanf( line, "nice %d", &val) == 1 )
382 {
383 nice( val );
384 } else if ( sscanf( line, "delay %u", &uval) == 1 )
385 {
386 bm.delay = uval*1000;
387 } else if ( sscanf( line, "dir %s", sval) == 1)
388 {
389 dir = strdup( sval );
390 } else if ( sscanf( line, "geometry %s", sval) == 1)
391 {
392 parse_geometry( sval );
393 }
394 }
395 fclose(f);
396 }
397
398 for (i=1 ; i<argc ; i++)
399 {
400 if (!strcmp(argv[i], "--threshold") || !strcmp(argv[i], "-t"))
401 {
402 i++;
403 if (i<argc)
404 {
405 bm.threshold = atoi(argv[i])*256/100;
406 bm.threshold = MIN (255, bm.threshold);
407 }
408 } else if (!strcmp(argv[i], "--version") || !strcmp(argv[i], "-v"))
409 {
410 print_version();
411 exit(0);
412 } else if (!strcmp(argv[i], "--help") || !strcmp(argv[i], "-h"))
413 {
414 print_usage();
415 exit(0);
416 } else if (!strcmp(argv[i], "--incremental") || !strcmp(argv[i], "-i"))
417 {
418 bm.incremental = TRUE;
419 } else if (!strcmp(argv[i], "--noNice") || !strcmp(argv[i], "-N"))
420 {
421 bm.noNice = TRUE;
422 } else if (!strcmp(argv[i], "--nice") || !strcmp(argv[i], "-n"))
423 {
424 i++;
425 if (i<argc)
426 {
427 nice( atoi(argv[i]) );
428 }
429 } else if (!strcmp(argv[i], "--delay") || !strcmp(argv[i], "-d"))
430 {
431 i++;
432 if (i<argc)
433 {
434 bm.delay = atoi(argv[i])*1000;
435 }
436 } else if (!strcmp(argv[i], "--dir"))
437 {
438 i++;
439 if (i<argc)
440 {
441 dir = argv[i];
442 }
443 } else if (!strcmp(argv[i], "--geometry"))
444 {
445 i++;
446 if (i<argc)
447 {
448 parse_geometry( argv[i] );
449 }
450 }
451 }
452
453 if( dir != NULL ) {
454 char path[256], home[256];
455 snprintf( path, 256, PREFIX "/share/hot-babe/%s", dir );
456 snprintf( home, 256, "%s/.hot-babe/%s", g_get_home_dir(), dir );
457 if( load_anim( &bm.anim, path ) &&
458 load_anim( &bm.anim, home ) &&
459 load_anim( &bm.anim, dir ) ) {
460 fprintf( stderr, "Can't find pictures\n" );
461 return 1;
462 }
463 } else {
464 if( load_anim( &bm.anim, PREFIX "/share/hot-babe/hb01" ) &&
465 load_anim( &bm.anim, "hb01" ) ) {
466 fprintf( stderr, "Can't find pictures\n" );
467 return 1;
468 }
469 }
470 create_hotbabe_window();
471
472 bm.pixels = malloc( sizeof(guchar*) * bm.anim.samples );
473 for( i = 0 ; i < bm.anim.samples ; i++ )
474 bm.pixels[i] = gdk_pixbuf_get_pixels( bm.anim.pixbuf[i] );
475 bm.dest = malloc( bm.anim.width * bm.anim.height * 3 );
476
477 hotbabe_setup_samples();
478
479 while (1)
480 {
481 while (gdk_events_pending())
482 {
483 event = gdk_event_get();
484 if (event)
485 {
486 switch (event->type)
487 {
488 case GDK_DESTROY:
489 gdk_exit(0);
490 exit(0);
491 break;
492 case GDK_BUTTON_PRESS:
493 if (event->button.button == 3)
494 {
495 exit(0);
496 break;
497 }
498 break;
499 default:
500 break;
501 }
502 }
503 }
504 usleep(bm.delay);
505 hotbabe_update();
506 }
507 return 0;
508 }
509
510