PageRenderTime 52ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 1ms

/wmtop-0.84/wmtop.c

#
C | 996 lines | 645 code | 155 blank | 196 comment | 108 complexity | 97249af72f2d788f2e56767635f0a06d MD5 | raw file
Possible License(s): GPL-2.0
  1. /******************************************/
  2. /* WMTOP - Mini top in a dock app */
  3. /******************************************/
  4. /*
  5. * wmtop.c -- WindowMaker process view dock app
  6. * Derived by Dan Piponi dan@tanelorn.demon.co.uk
  7. * http://www.tanelorn.demon.co.uk
  8. * http://wmtop.sourceforge.net
  9. * from code originally contained in wmsysmon by Dave Clark (clarkd@skynet.ca)
  10. * This software is licensed through the GNU General Public License.
  11. */
  12. /*
  13. * Ensure there's an operating system defined. There is *no* default
  14. * because every OS has it's own way of revealing CPU/memory usage.
  15. */
  16. #if defined(FREEBSD)
  17. #define OS_DEFINED
  18. #endif /* defined(FREEBSD) */
  19. #if defined(LINUX)
  20. #define OS_DEFINED
  21. #endif /* defined(LINUX) */
  22. #if !defined(OS_DEFINED)
  23. #error No operating system selected
  24. #endif /* !defined(OS_DEFINED) */
  25. /******************************************/
  26. /* Includes */
  27. /******************************************/
  28. #include <stdlib.h>
  29. #include <stdio.h>
  30. #include <time.h>
  31. #include <dirent.h>
  32. #include <string.h>
  33. #include <fcntl.h>
  34. #include <unistd.h>
  35. #include <ctype.h>
  36. #include <math.h>
  37. #include <limits.h>
  38. #include <errno.h>
  39. #include <signal.h>
  40. #if defined(PARANOID)
  41. #include <assert.h>
  42. #endif /* defined(PARANOID) */
  43. #include <sys/wait.h>
  44. #include <sys/stat.h>
  45. #include <sys/param.h>
  46. #include <sys/types.h>
  47. #include <sys/ioctl.h>
  48. #include <sys/time.h>
  49. #include <X11/Xlib.h>
  50. #include <X11/xpm.h>
  51. #include <X11/extensions/shape.h>
  52. #include <X11/keysym.h>
  53. #include <regex.h>
  54. #include "wmgeneral/wmgeneral.h"
  55. #include "wmgeneral/misc.h"
  56. #include "xpm/wmtop-default.xpm"
  57. #include "xpm/wmtop-lcd.xpm"
  58. #include "xpm/wmtop-neon1.xpm"
  59. #include "xpm/wmtop-neon2.xpm"
  60. #include "xpm/wmtop-rainbow.xpm"
  61. /******************************************/
  62. /* Defines */
  63. /******************************************/
  64. #define WMTOP_VERSION "0.9"
  65. /*
  66. * XXX: I shouldn't really use this WMTOP_BUFLENGTH variable but scanf is so
  67. * lame and it'll take me a while to write a replacement.
  68. */
  69. #define WMTOP_BUFLENGTH 1024
  70. #if defined(LINUX)
  71. #define PROCFS_TEMPLATE "/proc/%d/stat"
  72. #define PROCFS_CMDLINE_TEMPLATE "/proc/%d/cmdline"
  73. #endif /* defined(LINUX) */
  74. #if defined(FREEBSD)
  75. #define PROCFS_TEMPLATE "/proc/%d/status"
  76. #endif /* defined(FREEBSD) */
  77. /******************************************/
  78. /* Globals */
  79. /******************************************/
  80. regex_t *exclusion_expression = 0;
  81. int user = -1;
  82. char *process_command = 0;
  83. /*
  84. * Default mode: zero=cpu one=memory
  85. */
  86. int mode = 0;
  87. /*
  88. * Number and default artistic styles.
  89. */
  90. int nstyles = 5;
  91. int style = 0;
  92. char wmtop_mask_bits[64*64];
  93. int wmtop_mask_width = 64;
  94. int wmtop_mask_height = 64;
  95. int update_rate = 1000000;
  96. int refresh_rate = 100000;
  97. extern char **environ;
  98. char *ProgName;
  99. /******************************************/
  100. /* Debug */
  101. /******************************************/
  102. #if defined(DEBUG)
  103. /*
  104. * Memory handler
  105. */
  106. int g_malloced = 0;
  107. void *wmtop_malloc(int n) {
  108. int *p = (int *)malloc(sizeof(int)+n);
  109. p[0] = n;
  110. g_malloced += n;
  111. return (void *)(p+1);
  112. }
  113. void wmtop_free(void *n) {
  114. int *p = (int *)n;
  115. g_malloced -= p[-1];
  116. free(p-1);
  117. }
  118. void show_memory() {
  119. fprintf(stderr,"%d bytes allocated\n",g_malloced);
  120. }
  121. #else /* defined(DEBUG) */
  122. #define wmtop_malloc malloc
  123. #define wmtop_free free
  124. #endif /* defined(DEBUG) */
  125. char *wmtop_strdup(const char *s) {
  126. return strcpy((char *)wmtop_malloc(strlen(s)+1),s);
  127. }
  128. /******************************************/
  129. /* Structures */
  130. /******************************************/
  131. struct {
  132. char **pixmap;
  133. char *description;
  134. } styles[] = {
  135. { wmtop_default_xpm, "Light emitting diode (default)" },
  136. { wmtop_lcd_xpm, "Liquid crystal display" },
  137. { wmtop_rainbow_xpm, "Rainbow display" },
  138. { wmtop_neon1_xpm, "Neon lights" },
  139. { wmtop_neon2_xpm, "More neon lights" },
  140. };
  141. struct process {
  142. #if defined(PARANOID)
  143. long id;
  144. #endif /* defined(PARANOID) */
  145. /*
  146. * Store processes in a doubly linked list
  147. */
  148. struct process *next;
  149. struct process *previous;
  150. pid_t pid;
  151. char *name;
  152. float amount;
  153. int user_time;
  154. int kernel_time;
  155. int previous_user_time;
  156. int previous_kernel_time;
  157. int vsize;
  158. int rss;
  159. int time_stamp;
  160. int counted;
  161. };
  162. /******************************************/
  163. /* Process class */
  164. /******************************************/
  165. /*
  166. * Global pointer to head of process list
  167. */
  168. struct process *first_process = 0;
  169. int g_time = 0;
  170. struct process *find_process(pid_t pid) {
  171. struct process *p = first_process;
  172. while (p) {
  173. if (p->pid==pid)
  174. return p;
  175. p = p->next;
  176. }
  177. return 0;
  178. }
  179. /*
  180. * Create a new process object and insert it into the process list
  181. */
  182. struct process *new_process(int p) {
  183. struct process *process;
  184. process = wmtop_malloc(sizeof(struct process));
  185. #if defined(PARANOID)
  186. process->id = 0x0badfeed;
  187. #endif /* defined(PARANOID) */
  188. /*
  189. * Do stitching necessary for doubly linked list
  190. */
  191. process->name = 0;
  192. process->previous = 0;
  193. process->next = first_process;
  194. if (process->next)
  195. process->next->previous = process;
  196. first_process = process;
  197. process->pid = p;
  198. process->time_stamp = 0;
  199. process->previous_user_time = INT_MAX;
  200. process->previous_kernel_time = INT_MAX;
  201. process->counted = 1;
  202. /* process_find_name(process);*/
  203. return process;
  204. }
  205. /******************************************/
  206. /* Functions */
  207. /******************************************/
  208. void wmtop_routine(int, char **);
  209. int process_parse_procfs(struct process *);
  210. int update_process_table(void);
  211. int calculate_cpu(struct process *);
  212. void process_cleanup(void);
  213. void delete_process(struct process *);
  214. inline void draw_processes(void);
  215. int calc_cpu_total(void);
  216. void calc_cpu_each(int);
  217. #if defined(LINUX)
  218. int calc_mem_total(void);
  219. void calc_mem_each(int);
  220. #endif
  221. int process_find_top_three(struct process **);
  222. void draw_bar(int, int, int, int, float, int, int);
  223. inline void blit_string(char *, int, int);
  224. void usage(void);
  225. inline void printversion(void);
  226. /******************************************/
  227. /* Main */
  228. /******************************************/
  229. int main(int argc, char *argv[]) {
  230. int i;
  231. struct stat sbuf;
  232. /*
  233. * Make sure we have a /proc filesystem. No point in continuing if we
  234. * haven't!
  235. */
  236. if (stat("/proc",&sbuf)<0) {
  237. fprintf(stderr,
  238. "No /proc filesystem present. Unable to obtain processor info.\n");
  239. exit(1);
  240. }
  241. /*
  242. * Parse Command Line
  243. */
  244. ProgName = argv[0];
  245. if (strlen(ProgName) >= 5)
  246. ProgName += strlen(ProgName) - 5;
  247. for (i = 1; i<argc; i++) {
  248. char *arg = argv[i];
  249. if (*arg=='-') {
  250. switch (arg[1]) {
  251. case 'x' :
  252. if (argc>i+1) {
  253. static regex_t reg;
  254. exclusion_expression = &reg;
  255. regcomp(exclusion_expression,argv[i+1],REG_EXTENDED);
  256. i++;
  257. } else {
  258. usage();
  259. exit(1);
  260. }
  261. break;
  262. case 'c' :
  263. if (argc>i+1) {
  264. process_command = argv[i+1];
  265. i++;
  266. break;
  267. } else {
  268. usage();
  269. exit(1);
  270. }
  271. #if defined(LINUX)
  272. case 'm':
  273. /*
  274. * Display memory
  275. */
  276. mode = 1;
  277. break;
  278. #endif /* defined(LINUX) */
  279. case 'd' :
  280. if (strcmp(arg+1, "display")) {
  281. usage();
  282. exit(1);
  283. }
  284. break;
  285. case 'g' :
  286. if (strcmp(arg+1, "geometry")) {
  287. usage();
  288. exit(1);
  289. }
  290. break;
  291. case 'v' :
  292. printversion();
  293. exit(0);
  294. break;
  295. case 'U' :
  296. user = getuid();
  297. break;
  298. case 's':
  299. if (argc > (i+1)) {
  300. update_rate = (atoi(argv[i+1]) * 1000);
  301. i++;
  302. }
  303. break;
  304. case 'r':
  305. if (argc > (i+1)) {
  306. refresh_rate = (atoi(argv[i+1]) * 1000);
  307. i++;
  308. }
  309. break;
  310. case 'a':
  311. if (argc > (i+1)) {
  312. if (atoi(argv[i+1]) < 1 || atoi(argv[i+1]) > nstyles) {
  313. usage();
  314. exit(1);
  315. }
  316. style = atoi(argv[i+1]) - 1;
  317. i++;
  318. }
  319. break;
  320. default:
  321. usage();
  322. exit(0);
  323. break;
  324. }
  325. }
  326. }
  327. wmtop_routine(argc, argv);
  328. return 0;
  329. }
  330. /******************************************/
  331. /* Main routine */
  332. /******************************************/
  333. void wmtop_routine(int argc, char **argv) {
  334. XEvent Event;
  335. struct timeval tv={0,0};
  336. struct timeval last={0,0};
  337. int count = update_rate;
  338. createXBMfromXPM(wmtop_mask_bits, styles[style].pixmap, wmtop_mask_width, wmtop_mask_height);
  339. openXwindow(argc, argv, styles[style].pixmap, wmtop_mask_bits, wmtop_mask_width, wmtop_mask_height);
  340. while (1) {
  341. waitpid(0, NULL, WNOHANG);
  342. if (count>=update_rate) {
  343. memcpy(&last,&tv,sizeof(tv));
  344. /*
  345. * Update display
  346. */
  347. draw_processes();
  348. RedrawWindow();
  349. count = 0;
  350. }
  351. /*
  352. * X Events
  353. */
  354. while (XPending(display)) {
  355. XNextEvent(display, &Event);
  356. switch (Event.type) {
  357. case Expose:
  358. RedrawWindow();
  359. break;
  360. case DestroyNotify:
  361. XCloseDisplay(display);
  362. exit(0);
  363. case ButtonPress:
  364. #if defined(LINUX)
  365. if (Event.xbutton.button==1)
  366. mode = !mode;
  367. #endif
  368. if (Event.xbutton.button==2) {
  369. if (user==-1)
  370. user=getuid();
  371. else
  372. user=-1;
  373. }
  374. if (Event.xbutton.button==3 && process_command)
  375. execCommand(process_command);
  376. break;
  377. }
  378. }
  379. usleep(refresh_rate);
  380. count = count + refresh_rate;
  381. }
  382. }
  383. /******************************************/
  384. /* Extract information from /proc */
  385. /******************************************/
  386. /*
  387. * These are the guts that extract information out of /proc.
  388. * Anyone hoping to port wmtop should look here first.
  389. */
  390. int process_parse_procfs(struct process *process) {
  391. char line[WMTOP_BUFLENGTH],filename[WMTOP_BUFLENGTH],procname[WMTOP_BUFLENGTH];
  392. int ps;
  393. struct stat sbuf;
  394. int user_time,kernel_time;
  395. int rc;
  396. #if defined(LINUX)
  397. char *r,*q;
  398. char deparenthesised_name[WMTOP_BUFLENGTH];
  399. int endl;
  400. #endif /* defined(LINUX) */
  401. #if defined(FREEBSD)
  402. int us,um,ks,km;
  403. #endif /* defined(FREEBSD) */
  404. #if defined(PARANOID)
  405. assert(process->id==0x0badfeed);
  406. #endif /* defined(PARANOID) */
  407. sprintf(filename,PROCFS_TEMPLATE,process->pid);
  408. /*
  409. * Permissions of /proc filesystem are permissions of process too
  410. */
  411. if (user>=0) {
  412. stat(filename,&sbuf);
  413. if (sbuf.st_uid!=user)
  414. return 1;
  415. }
  416. ps = open(filename,O_RDONLY);
  417. if (ps<0)
  418. /*
  419. * The process must have finished in the last few jiffies!
  420. */
  421. return 1;
  422. /*
  423. * Mark process as up-to-date.
  424. */
  425. process->time_stamp = g_time;
  426. rc = read(ps,line,sizeof(line));
  427. close(ps);
  428. if (rc<0)
  429. return 1;
  430. #if defined(LINUX)
  431. /*
  432. * Extract cpu times from data in /proc filesystem
  433. */
  434. rc = sscanf(line,"%*s %s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %d %d %*s %*s %*s %*s %*s %*s %*s %d %d",
  435. procname,
  436. &process->user_time,&process->kernel_time,
  437. &process->vsize,&process->rss);
  438. if (rc<5)
  439. return 1;
  440. /*
  441. * Remove parentheses from the process name stored in /proc/ under Linux...
  442. */
  443. r = procname+1;
  444. /* remove any "kdeinit: " */
  445. if (r == strstr(r, "kdeinit"))
  446. {
  447. sprintf(filename,PROCFS_CMDLINE_TEMPLATE,process->pid);
  448. /*
  449. * Permissions of /proc filesystem are permissions of process too
  450. */
  451. if (user>=0) {
  452. stat(filename,&sbuf);
  453. if (sbuf.st_uid!=user)
  454. return 1;
  455. }
  456. ps = open(filename,O_RDONLY);
  457. if (ps<0)
  458. /*
  459. * The process must have finished in the last few jiffies!
  460. */
  461. return 1;
  462. endl = read(ps,line,sizeof(line));
  463. close(ps);
  464. /* null terminate the input */
  465. line[endl]=0;
  466. /* account for "kdeinit: " */
  467. if ((char*)line == strstr(line, "kdeinit: "))
  468. r = ((char*)line)+9;
  469. else
  470. r = (char*)line;
  471. q = deparenthesised_name;
  472. /* stop at space */
  473. while (*r && *r!=' ')
  474. *q++ = *r++;
  475. *q = 0;
  476. }
  477. else
  478. {
  479. q = deparenthesised_name;
  480. while (*r && *r!=')')
  481. *q++ = *r++;
  482. *q = 0;
  483. }
  484. if (process->name)
  485. wmtop_free(process->name);
  486. process->name = wmtop_strdup(deparenthesised_name);
  487. #endif /* defined(LINUX) */
  488. #if defined(FREEBSD)
  489. /*
  490. * Extract cpu times from data in /proc/<pid>/stat
  491. * XXX: Process name extractor for FreeBSD is untested right now.
  492. */
  493. rc = sscanf(line,"%s %*s %*s %*s %*s %*s %*s %*s %d,%d %d,%d",
  494. procname,
  495. &us,&um,&ks,&km);
  496. if (rc<5)
  497. return 1;
  498. if (process->name)
  499. wmtop_free(process->name);
  500. process->name = wmtop_strdup(procname);
  501. process->user_time = us*1000+um/1000;
  502. process->kernel_time = ks*1000+km/1000;
  503. #endif /* defined(FREEBSD) */
  504. process->rss *= getpagesize();
  505. if (process->previous_user_time==INT_MAX)
  506. process->previous_user_time = process->user_time;
  507. if (process->previous_kernel_time==INT_MAX)
  508. process->previous_kernel_time = process->kernel_time;
  509. user_time = process->user_time-process->previous_user_time;
  510. kernel_time = process->kernel_time-process->previous_kernel_time;
  511. process->previous_user_time = process->user_time;
  512. process->previous_kernel_time = process->kernel_time;
  513. process->user_time = user_time;
  514. process->kernel_time = kernel_time;
  515. return 0;
  516. }
  517. /******************************************/
  518. /* Update process table */
  519. /******************************************/
  520. int update_process_table() {
  521. DIR *dir;
  522. struct dirent *entry;
  523. if (!(dir = opendir("/proc")))
  524. return 1;
  525. /*
  526. * Get list of processes from /proc directory
  527. */
  528. while ((entry = readdir(dir))) {
  529. pid_t pid;
  530. if (!entry) {
  531. /*
  532. * Problem reading list of processes
  533. */
  534. closedir(dir);
  535. return 1;
  536. }
  537. if (sscanf(entry->d_name,"%d",&pid)>0) {
  538. struct process *p;
  539. p = find_process(pid);
  540. if (!p)
  541. p = new_process(pid);
  542. calculate_cpu(p);
  543. }
  544. }
  545. closedir(dir);
  546. return 0;
  547. }
  548. /******************************************/
  549. /* Get process structure for process pid */
  550. /******************************************/
  551. /*
  552. * This function seems to hog all of the CPU time. I can't figure out why - it
  553. * doesn't do much.
  554. */
  555. int calculate_cpu(struct process *process) {
  556. int rc;
  557. #if defined(PARANOID)
  558. assert(process->id==0x0badfeed);
  559. #endif /* defined(PARANOID) */
  560. rc = process_parse_procfs(process);
  561. if (rc)
  562. return 1;
  563. /*
  564. * Check name against the exclusion list
  565. */
  566. if (process->counted && exclusion_expression && !regexec(exclusion_expression,process->name,0,0,0))
  567. process->counted = 0;
  568. return 0;
  569. }
  570. /******************************************/
  571. /* Strip dead process entries */
  572. /******************************************/
  573. void process_cleanup() {
  574. struct process *p = first_process;
  575. while (p) {
  576. struct process *current = p;
  577. #if defined(PARANOID)
  578. assert(p->id==0x0badfeed);
  579. #endif /* defined(PARANOID) */
  580. p = p->next;
  581. /*
  582. * Delete processes that have died
  583. */
  584. if (current->time_stamp!=g_time)
  585. delete_process(current);
  586. }
  587. }
  588. /******************************************/
  589. /* Destroy and remove a process */
  590. /******************************************/
  591. void delete_process(struct process *p) {
  592. #if defined(PARANOID)
  593. assert(p->id==0x0badfeed);
  594. /*
  595. * Ensure that deleted processes aren't reused.
  596. */
  597. p->id = 0x007babe;
  598. #endif /* defined(PARANOID) */
  599. /*
  600. * Maintain doubly linked list.
  601. */
  602. if (p->next)
  603. p->next->previous = p->previous;
  604. if (p->previous)
  605. p->previous->next = p->next;
  606. else
  607. first_process = p->next;
  608. if (p->name)
  609. wmtop_free(p->name);
  610. wmtop_free(p);
  611. }
  612. /******************************************/
  613. /* Generate display */
  614. /******************************************/
  615. void draw_processes() {
  616. int i,n;
  617. struct process *best[3] = { 0, 0, 0 };
  618. int total;
  619. /*
  620. * Invalidate time stamps
  621. */
  622. ++g_time;
  623. update_process_table();
  624. switch (mode) {
  625. case 0:
  626. total = calc_cpu_total();
  627. calc_cpu_each(total);
  628. break;
  629. #if defined(LINUX)
  630. case 1:
  631. total = calc_mem_total();
  632. calc_mem_each(total);
  633. break;
  634. #endif
  635. }
  636. process_cleanup();
  637. /*
  638. * Find the top three!
  639. */
  640. n = process_find_top_three(best);
  641. for (i = 0; i<3; ++i) {
  642. int j;
  643. char s[10];
  644. strcpy(s," ");
  645. if (i<n) {
  646. for (j = 0; j<9; ++j) {
  647. char c;
  648. c = best[i]->name[j];
  649. if (c)
  650. s[j] = c;
  651. else
  652. break;
  653. }
  654. draw_bar(0, 97, 55, 6, best[i]->amount, 4, 13+i*20);
  655. } else
  656. draw_bar(0, 97, 55, 6, 0, 4, 13+i*20);
  657. blit_string(s,4,4+i*20);
  658. }
  659. #if defined(DEBUG)
  660. show_memory();
  661. #endif
  662. }
  663. /******************************************/
  664. /* Calculate cpu total */
  665. /******************************************/
  666. int calc_cpu_total() {
  667. int total,t;
  668. static int previous_total = INT_MAX;
  669. #if defined(LINUX)
  670. int rc;
  671. int ps;
  672. char line[WMTOP_BUFLENGTH];
  673. int cpu,nice,system,idle;
  674. ps = open("/proc/stat",O_RDONLY);
  675. rc = read(ps,line,sizeof(line));
  676. close(ps);
  677. if (rc<0)
  678. return 0;
  679. sscanf(line,"%*s %d %d %d %d",&cpu,&nice,&system,&idle);
  680. total = cpu+nice+system+idle;
  681. #endif /* defined(LINUX) */
  682. #if defined(FREEBSD)
  683. struct timeval tv;
  684. gettimeofday(&tv,0);
  685. total = tv.tv_sec*1000+tv.tv_usec/1000;
  686. #endif /* defined(FREEBSD) */
  687. t = total-previous_total;
  688. previous_total = total;
  689. if (t<0)
  690. t = 0;
  691. return t;
  692. }
  693. /******************************************/
  694. /* Calculate each processes cpu */
  695. /******************************************/
  696. void calc_cpu_each(int total) {
  697. struct process *p = first_process;
  698. while (p) {
  699. #if defined(PARANOID)
  700. assert(p->id==0x0badfeed);
  701. #endif /* defined(PARANOID) */
  702. p->amount = total ? 100*(float)(p->user_time+p->kernel_time)/total : 0;
  703. p = p->next;
  704. }
  705. }
  706. /******************************************/
  707. /* Calculate total memory */
  708. /******************************************/
  709. #if defined(LINUX)
  710. int calc_mem_total() {
  711. int ps;
  712. char line[512];
  713. char *ptr;
  714. int rc;
  715. ps = open("/proc/meminfo",O_RDONLY);
  716. rc = read(ps,line,sizeof(line));
  717. close(ps);
  718. if (rc<0)
  719. return 0;
  720. if ((ptr = strstr(line, "Mem:")) == NULL) {
  721. return 0;
  722. } else {
  723. ptr += 4;
  724. return atoi(ptr);
  725. }
  726. }
  727. #endif /* defined(LINUX) */
  728. /******************************************/
  729. /* Calculate each processes memory */
  730. /******************************************/
  731. #if defined(LINUX)
  732. void calc_mem_each(int total) {
  733. struct process *p = first_process;
  734. while (p) {
  735. p->amount = 100*(float)p->rss/total;
  736. p = p->next;
  737. }
  738. }
  739. #endif /* defined(LINUX) */
  740. /******************************************/
  741. /* Find the top three processes */
  742. /******************************************/
  743. /*
  744. * Result is stored in decreasing order in best[0-2].
  745. */
  746. int process_find_top_three(struct process **best) {
  747. struct process *p = first_process;
  748. int n = 0;
  749. /*
  750. * Insertion sort approach to skim top 3
  751. */
  752. while (p) {
  753. if (p->counted && p->amount>0 && (!best[0] || p->amount>best[0]->amount)) {
  754. best[2] = best[1];
  755. best[1] = best[0];
  756. best[0] = p;
  757. ++n;
  758. } else if (p->counted && p->amount>0 && (!best[1] || p->amount>best[1]->amount)) {
  759. best[2] = best[1];
  760. best[1] = p;
  761. ++n;
  762. } else if (p->counted && p->amount>0 && (!best[2] || p->amount>best[2]->amount)) {
  763. ++n;
  764. best[2] = p;
  765. }
  766. p = p->next;
  767. }
  768. return n>3 ? 3 : n;
  769. }
  770. /******************************************/
  771. /* Blit bar at co-ordinates */
  772. /******************************************/
  773. void draw_bar(int sx, int sy, int w, int h, float percent, int dx, int dy) {
  774. int tx;
  775. if (percent<=100)
  776. tx = w * (float)percent / 100;
  777. else
  778. tx = w;
  779. if (tx>0)
  780. copyXPMArea(sx, sy, tx, h, dx, dy);
  781. if (tx<w)
  782. copyXPMArea(sx+tx, sy+h, w-tx, h, dx+tx, dy);
  783. }
  784. /******************************************/
  785. /* Blit string at co-ordinates */
  786. /******************************************/
  787. void blit_string(char *name, int x, int y) {
  788. int i;
  789. int c;
  790. int k;
  791. k = x;
  792. for ( i = 0; name[i]; i++) {
  793. c = toupper(name[i]);
  794. if (c >= 'A' && c <= 'J') {
  795. c -= 'A';
  796. copyXPMArea(c*6,73,6,7,k,y);
  797. } else if (c>='K' && c<='T') {
  798. c -= 'K';
  799. copyXPMArea(c*6,81,6,7,k,y);
  800. } else if (c>='U' && c<='Z') {
  801. c -= 'U';
  802. copyXPMArea(c*6,89,6,7,k,y);
  803. } else if (c>='0' && c<='9') {
  804. c -= '0';
  805. copyXPMArea(c*6,65,6,7,k,y);
  806. } else {
  807. copyXPMArea(36,89,6,7,k,y);
  808. }
  809. k += 6;
  810. }
  811. }
  812. /******************************************/
  813. /* Usage */
  814. /******************************************/
  815. void usage(void) {
  816. int i;
  817. fprintf(stderr,"\nWMtop - Dan Piponi <dan@tanelorn.demon.co.uk> http://www.tanelorn.demon.co.uk\n\n");
  818. fprintf(stderr,"usage:\n");
  819. fprintf(stderr," -display <display name>\n");
  820. fprintf(stderr," -geometry +XPOS+YPOS initial window position\n");
  821. fprintf(stderr," -s <...> sample rate in milliseconds (default:%d)\n", update_rate/1000);
  822. fprintf(stderr," -r <...> refresh rate in milliseconds (default:%d)\n", refresh_rate/1000);
  823. fprintf(stderr," -U display user processes only\n");
  824. fprintf(stderr," -x <...> exclude matching processes\n");
  825. fprintf(stderr," -c <...> command\n");
  826. #if defined(LINUX)
  827. fprintf(stderr," -m display memory usage\n");
  828. #endif /* defined(LINUX) */
  829. fprintf(stderr," -v print version number\n");
  830. fprintf(stderr," -a <1..%d> select artistic style\n", nstyles);
  831. fprintf(stderr,"\n");
  832. fprintf(stderr,"The artistic style is one of:\n");
  833. for (i = 0; i<nstyles; ++i)
  834. fprintf(stderr," %d - %s\n",i+1,styles[i].description);
  835. }
  836. /******************************************/
  837. /* Print version */
  838. /******************************************/
  839. void printversion(void) {
  840. fprintf(stderr, "wmtop v%s\n",WMTOP_VERSION);
  841. }