/*
    Written by Jef De Geeter: wmzazof is a WindowMaker dock app
	that monitors some system information like uptime, mem free
	and mem used.
	
    Copyright (C) 2001 Jef De Geeter

    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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

*/

#include <dockapp.h>
#include <unistd.h>
#include <string.h>
#include <time.h>
#include <sys/time.h>
#include <sys/sysctl.h>
#include <sys/vmmeter.h>
#include <vm/vm_param.h>
#include "pix/master.xpm"
#include "pix/numbers.xpm"
#include "pix/char.xpm"

#define DESCRIPTION "\nA utility to monitor uptime, mem free and mem used.\n"
#define VERSION "wmzazof 0.3"

#define WIN_SZ 56
#define NUM_SX 7
#define NUM_SY 9

#define CHAR_SX 6
#define CHAR_SY 7

#define BUTTON_LEFT  1
#define BUTTON_RIGHT 3

#define UPTIME_MINUTES 0
#define UPTIME_HOURS   1
#define UPTIME_DAYS    2

#define MEM_FREE	0 // FREE = free
#define MEM_FREE_CACHED 1 // FREE = free + cached 

#define MEM_USED	0 // USED = used
#define MEM_USED_CACHED 1 // USED = used - cached

// mem_free and mem_used in kB
// uptime in hours
unsigned int mem_cached, mem_free, mem_used, uptime;

int state_uptime; 
int state_mem_free;
int state_mem_used;

char *displayName = "";

struct timeval boottime;
int page_size;

unsigned int *cmdline;

FILE *file;

GC gc;
Pixmap pixmap, mask;
Pixmap pixnum, masknum;
Pixmap pixchar, maskchar;

void writeFile(void);

static DAProgramOption options[] = {
	{"-display", NULL, "Display to use", DOString, False, {&displayName}}
};

/*
 * draws a figure num on the specified postion (row, column) 
 */
void drawNum (int num, int column, int row)
{
	if(row == 1)
		row = 2*NUM_SY - 3;
	else if(row == 2)
		row = 3*NUM_SY + 2;
	else if(row == 3)
		row = 4*NUM_SY + 7;		
	else
		return;
		
	XCopyArea (DADisplay, pixnum, pixmap, gc, num*NUM_SX, 0, NUM_SX, NUM_SY, column*NUM_SX + 3, row);
}

/*
 * draws a character on the specified position (row)
 */ 
void drawChar(int Char, int row)
{
	if (row == 1){
		row = 2*NUM_SY - 2;
	}
	if (row == 2){
		row = 3*NUM_SY + 3;
	}
	if (row == 3){
		row = 4*NUM_SY + 8;		
	}
	XCopyArea(DADisplay, pixchar, pixmap, gc, Char*CHAR_SX, 0, CHAR_SX, CHAR_SY, 3, row);
}

void drawNumber(int number, int line)
{
	char numbers[8];
	int i;
	
	for(i=1; i<7; i++)
	{
		drawNum(16, i, line);
	}
	
	sprintf(numbers, "%7d", number); 
	
	for(i=0; i<7; i++)
	{
		if(numbers[i] != ' ' && numbers[i] <= '9') drawNum((int)numbers[i] - (int)'0', i, line);
	}
}

void check_values()
{
	time_t now = time(NULL);
	int mib[2] = { CTL_VM, VM_METER }, mcs = sizeof(mem_cached);
	struct vmtotal meter;
	size_t size = sizeof(meter);
	
	// uptime in seconds
	uptime = now - boottime.tv_sec;

	// in Kb
	if (sysctl(mib, 2, &meter, &size, NULL, 0) != -1 &&
	sysctlbyname("vm.stats.vm.v_cache_count", &mem_cached, &mcs, NULL, 0) != -1)
	{
		mem_used = meter.t_rm * page_size / 1024;
		mem_free = meter.t_free * page_size / 1024;
		mem_cached = mem_cached * page_size / 1024;
	}
}

void transform_values()
{
	// uptime
	if (state_uptime == UPTIME_MINUTES){
		uptime = uptime / 60;
	}
	else if (state_uptime == UPTIME_HOURS){
		uptime = uptime / 3600;
	}
	else if (state_uptime == UPTIME_DAYS){
		uptime = uptime / 86400;
	}
	// mem free
	if (state_mem_free == MEM_FREE_CACHED){
		mem_free = mem_free + mem_cached;
	}
	// mem used
	if (state_mem_used == MEM_USED_CACHED){
		mem_used = mem_used - mem_cached;
	}
}

void buttonPressCallback (int button, int state, int x, int y)
{

	if (button == BUTTON_LEFT){
		if (y > 15 && y < 25){
			// uptime
			// there're 3 possible states
			state_uptime = ++state_uptime % 3;
		}
		else if (y > 30 && y < 40){
		       	// mem free
			// there're 2 possible states
			state_mem_free = ++state_mem_free % 2;
		}
		else if (y > 45 && y < 55){
			// mem used
			// there're 2 possible states
			state_mem_used = ++state_mem_used % 2;
		}	
	}
	else if (button == BUTTON_RIGHT){
		// nothing
	}
}

int main (int argc, char **argv)
{
	unsigned int height, width;

	int mib[2] = { CTL_KERN, KERN_BOOTTIME };
	size_t size_bt = sizeof(boottime), size_ps = sizeof(page_size);
	
	DACallbacks callbacks = { NULL, buttonPressCallback, NULL, NULL, NULL, NULL, NULL }; 

	DAParseArguments (argc, argv, options, sizeof (options) / sizeof (DAProgramOption), DESCRIPTION, VERSION);
	DAInitialize (displayName, "wmzazof", WIN_SZ, WIN_SZ, argc, argv);

	DAMakePixmapFromData (master_xpm, &pixmap, &mask, &height, &width);
	DASetPixmap (pixmap);
	DAMakePixmapFromData (numbers_xpm, &pixnum, &masknum, &height, &width);
	DAMakePixmapFromData (char_xpm, &pixchar, &maskchar, &height, &width);
	gc = DefaultGC (DADisplay, DefaultScreen (DADisplay));

	DASetCallbacks (&callbacks);
	DAShow ();

	state_uptime = UPTIME_HOURS;
	state_mem_free = MEM_FREE_CACHED;
	state_mem_used = MEM_USED_CACHED;

	if (sysctl(mib, 2, &boottime, &size_bt, NULL, 0) == -1 ||
   sysctlbyname("vm.stats.vm.v_page_size", &page_size, &size_ps, NULL, 0) == -1)
	{
		perror(NULL);
		exit(EXIT_FAILURE);
	}
	
	while (1)
	{
		XEvent ev;
		DASetPixmap (pixmap);
		
		/* handle all pending X events */
		while (XPending (DADisplay))
		{
			XNextEvent (DADisplay, &ev);
			DAProcessEvent (&ev);
		}
		check_values();
		transform_values();
		drawNumber(uptime, 1);
		drawChar(19, 1);
		drawNumber(mem_free, 2);
		drawChar(5, 2);
		drawNumber(mem_used, 3);
		drawChar(20, 3);
		usleep (500000L);
	}
	return 0;
}


syntax highlighted by Code2HTML, v. 0.9.1