/*
* Copyright (c) 1999 Albert Dorofeev <Albert@mail.dma.be>
* For the updates see http://bewoner.dma.be/Albert/
*
* This software is distributed under GPL. For details see LICENSE file.
*/
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <ctype.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include <string.h>
#include <X11/Xlib.h>
#include <X11/xpm.h>
#include <X11/Xatom.h>
#include "x_color.h"
#include "read_mem.h"
#include "background.xpm"
#include "alphabet.xpm"
#include "state.h"
struct asmem_state state;
/* nice idea from ascd */
typedef struct _XpmIcon {
Pixmap pixmap;
Pixmap mask;
XpmAttributes attributes;
} XpmIcon;
XpmIcon backgroundXpm;
XpmIcon alphabetXpm;
/* X windows related global variables */
Display * mainDisplay = 0; /* The display we are working on */
Window Root; /* The root window of X11 */
Window drawWindow; /* A hidden window for drawing */
Window mainWindow; /* Application window */
Window iconWindow; /* Icon window */
XGCValues mainGCV; /* graphics context values */
GC mainGC; /* Graphics context */
Atom wm_delete_window;
Atom wm_protocols;
Pixel back_pix, fore_pix;
/* background pixmap colors */
char bgpixmap_color[4][50];
char alphabet_color[4][50];
/* pixels we need */
Pixel pix[4][3];
/* last time we updated */
time_t last_time = 0;
/* requests for update */
int update_request = 0;
void draw_window(Window win)
{
int points[3];
unsigned int total;
unsigned int percentage;
unsigned long int free_mem;
unsigned int available;
int i;
unsigned int tmp[6];
int digits;
XCopyArea(
mainDisplay,
backgroundXpm.pixmap,
win,
mainGC,
0,
0,
backgroundXpm.attributes.width,
backgroundXpm.attributes.height,
0,
0
);
if ( (state.fresh.total > (999999 * 1024))
|| state.mb )
total = state.fresh.total / 1024 / 1024;
else
total = state.fresh.total / 1024;
digits = 0;
for (i=0 ; i<6; ++i) {
tmp[i] = total % 10;
total = total / 10;
++digits;
if (total == 0)
break;
}
for (i=0; i<digits; ++i) {
XCopyArea(
mainDisplay,
alphabetXpm.pixmap,
win,
mainGC,
tmp[i]*5,
0,
6,
9,
46-(i*5),
2
);
}
if ( state.standard_free )
free_mem = state.fresh.free;
else
free_mem = state.fresh.free
+state.fresh.buffers
+state.fresh.cached;
if ( state.show_used )
free_mem = state.fresh.total - free_mem;
if ( (state.fresh.total > (999999 * 1024))
|| state.mb )
available = free_mem / 1024 / 1024;
else
available = free_mem / 1024;
digits = 0;
for (i=0 ; i<6; ++i) {
tmp[i] = available % 10;
available = available / 10;
++digits;
if (available == 0)
break;
}
for (i=0; i<digits; ++i) {
XCopyArea(
mainDisplay,
alphabetXpm.pixmap,
win,
mainGC,
tmp[digits-1-i]*5,
0,
6,
9,
2+(i*5),
17
);
}
if ( state.fresh.total )
percentage = (int) ( ((float)free_mem) /
((float)state.fresh.total) * 100);
else
percentage = 0;
if (percentage >= 100)
tmp[0] = percentage / 100;
else
tmp[0] = 13;
if (percentage >= 10)
tmp[1] = percentage % 100 / 10;
else
tmp[1] = 10;
tmp[2] = percentage % 100 % 10;
tmp[3] = 11;
for (i=0; i<4; ++i) {
XCopyArea(
mainDisplay,
alphabetXpm.pixmap,
win,
mainGC,
tmp[i]*5,
0,
6,
9,
32+(i*5),
17
);
}
points[0] = ((float)(
state.fresh.used -
state.fresh.buffers -
state.fresh.cached
)) /
((float)state.fresh.total) *
46;
points[1] = ((float)state.fresh.buffers) /
((float)state.fresh.total) *
46;
points[2] = ((float)state.fresh.cached) /
((float)state.fresh.total) *
46;
for (i=0; i<3; ++i) {
mainGCV.foreground = pix[0][i];
XChangeGC(
mainDisplay,
mainGC,
GCForeground,
&mainGCV
);
XFillRectangle(
mainDisplay,
win,
mainGC,
3,
13+i,
points[0],
1
);
}
for (i=0; i<3; ++i) {
mainGCV.foreground = pix[1][i];
XChangeGC(
mainDisplay,
mainGC,
GCForeground,
&mainGCV
);
XFillRectangle(
mainDisplay,
win,
mainGC,
3+points[0],
13+i,
points[1],
1
);
}
for (i=0; i<3; ++i) {
mainGCV.foreground = pix[2][i];
XChangeGC(
mainDisplay,
mainGC,
GCForeground,
&mainGCV
);
XFillRectangle(
mainDisplay,
win,
mainGC,
3+points[0]+points[1],
13+i,
points[2],
1
);
}
if ( (state.fresh.swap_total > (999999*1024))
|| state.mb )
total = state.fresh.swap_total / 1024 / 1024;
else
total = state.fresh.swap_total / 1024;
digits = 0;
for (i=0 ; i<6; ++i) {
tmp[i] = total % 10;
total = total / 10;
++digits;
if (total == 0)
break;
}
for (i=0; i<digits; ++i) {
XCopyArea(
mainDisplay,
alphabetXpm.pixmap,
win,
mainGC,
tmp[i]*5,
0,
6,
9,
46-(i*5),
27
);
}
free_mem = state.fresh.swap_free;
if ( state.show_used )
free_mem = state.fresh.swap_total - free_mem;
if ( (free_mem > (999999*1024))
|| state.mb )
available = free_mem / 1024 / 1024;
else
available = free_mem / 1024;
digits = 0;
for (i=0 ; i<6; ++i) {
tmp[i] = available % 10;
available = available / 10;
++digits;
if (available == 0)
break;
}
for (i=0; i<digits; ++i) {
XCopyArea(
mainDisplay,
alphabetXpm.pixmap,
win,
mainGC,
tmp[digits-1-i]*5,
0,
6,
9,
2+(i*5),
42
);
}
if ( state.fresh.swap_total )
percentage = (int) (
((float)free_mem) /
((float)state.fresh.swap_total) * 100);
else
percentage = 0;
if (percentage >= 100)
tmp[0] = percentage / 100;
else
tmp[0] = 13;
if (percentage >= 10)
tmp[1] = percentage % 100 / 10;
else
tmp[1] = 10;
tmp[2] = percentage % 100 % 10;
tmp[3] = 11;
for (i=0; i<4; ++i) {
XCopyArea(
mainDisplay,
alphabetXpm.pixmap,
win,
mainGC,
tmp[i]*5,
0,
6,
9,
32+(i*5),
42
);
}
points[0] = ((float)state.fresh.swap_used) /
((float)state.fresh.swap_total) *
46;
for (i=0; i<3; ++i) {
mainGCV.foreground = pix[3][i];
XChangeGC(
mainDisplay,
mainGC,
GCForeground,
&mainGCV
);
XFillRectangle(
mainDisplay,
win,
mainGC,
3,
38+i,
points[0],
1
);
}
}
/*
* This function clears up all X related
* stuff and exits. It is called in case
* of emergencies .
*/
void asmem_cleanup()
{
if ( mainDisplay ) {
XCloseDisplay(mainDisplay);
}
close_meminfo();
exit(0);
}
/*
* This checks for X11 events. We distinguish the following:
* - request to repaint the window
* - request to quit (Close button)
*/
void CheckX11Events()
{
XEvent Event;
while (XPending(mainDisplay)) {
XNextEvent(mainDisplay, &Event);
switch(Event.type)
{
case Expose:
if(Event.xexpose.count == 0) {
++update_request;
}
break;
case ClientMessage:
if ((Event.xclient.message_type == wm_protocols)
&& (Event.xclient.data.l[0] == wm_delete_window))
{
#ifdef DEBUG
printf("caught wm_delete_window, closing\n");
#endif
asmem_cleanup();
}
break;
}
}
}
void asmem_redraw()
{
XCopyArea(
mainDisplay,
drawWindow,
mainWindow,
mainGC,
0,
0,
backgroundXpm.attributes.width,
backgroundXpm.attributes.height,
0,
0
);
XCopyArea(
mainDisplay,
drawWindow,
iconWindow,
mainGC,
0,
0,
backgroundXpm.attributes.width,
backgroundXpm.attributes.height,
0,
0
);
update_request = 0;
}
void asmem_update()
{
time_t cur_time;
cur_time = time(0);
if ( abs(cur_time - last_time) >= state.update_interval ) {
last_time = cur_time;
if (read_meminfo())
asmem_cleanup();
if (memcmp(&state.last, &state.fresh, sizeof(struct meminfo))) {
memcpy(&state.last, &state.fresh, sizeof(struct meminfo));
draw_window(drawWindow);
++update_request;
}
}
CheckX11Events();
if ( update_request ) {
asmem_redraw();
}
}
void asmem_initialize(
int argc, char** argv,
char * display_name,
char * mainGeometry,
int withdrawn,
int iconic,
int pushed_in)
{
int screen;
Status status;
XWindowAttributes winAttr;
XSizeHints SizeHints;
XTextProperty title;
char * app_name = "asmem";
XClassHint classHint;
int gravity;
XWMHints WmHints;
XEvent Event;
int color_depth;
int tmp;
int result;
int x_negative = 0;
int y_negative = 0;
mainDisplay = XOpenDisplay(display_name);
if ( ! mainDisplay ) {
printf("asmem : grrrr... can't open display %s. Sorry ...\n",
XDisplayName(display_name));
exit(1);
}
screen = DefaultScreen(mainDisplay);
Root = RootWindow(mainDisplay, screen);
back_pix = GetColor(state.bgcolor, mainDisplay, Root);
fore_pix = GetColor(state.fgcolor, mainDisplay, Root);
color_depth = DefaultDepth(mainDisplay, screen);
#ifdef DEBUG
printf("asmem : detected color depth %d bpp, using %d bpp\n",
color_depth, color_depth);
#endif
/* adjust the background pixmap */
sprintf(bgpixmap_color[3], "# c %s", state.fgcolor);
if (pushed_in) {
sprintf(bgpixmap_color[0],
". c %s",
DarkenCharColor(state.bgcolor, 1.6, mainDisplay, Root));
sprintf(bgpixmap_color[1],
"c c %s",
state.bgcolor);
sprintf(bgpixmap_color[2],
"q c %s",
LightenCharColor(state.bgcolor, 2.8, mainDisplay, Root));
} else {
sprintf(bgpixmap_color[2],
"q c %s",
DarkenCharColor(state.bgcolor, 1.2, mainDisplay, Root));
sprintf(bgpixmap_color[1],
"c c %s",
state.bgcolor);
sprintf(bgpixmap_color[0],
". c %s",
LightenCharColor(state.bgcolor, 2.5, mainDisplay, Root));
}
for (tmp = 0; tmp < 4; ++tmp)
background[tmp+1] = bgpixmap_color[tmp];
backgroundXpm.attributes.valuemask |=
(XpmReturnPixels | XpmReturnExtensions);
status = XpmCreatePixmapFromData(
mainDisplay, /* display */
Root, /* window */
background, /* xpm */
&backgroundXpm.pixmap, /* resulting pixmap */
&backgroundXpm.mask,
&backgroundXpm.attributes
);
if(status != XpmSuccess) {
printf("asmem : (%d) not enough free color cells for background.\n", status);
asmem_cleanup();
}
#ifdef DEBUG
printf("bg pixmap %d x %d\n",
backgroundXpm.attributes.width,
backgroundXpm.attributes.height);
#endif
sprintf(alphabet_color[0], ". c %s", state.bgcolor);
sprintf(alphabet_color[1], "# c %s", state.fgcolor);
sprintf(alphabet_color[2], "a c %s",
DarkenCharColor(state.bgcolor, 1.4, mainDisplay, Root));
sprintf(alphabet_color[3], "c c %s",
DarkenCharColor(state.fgcolor, 1.6, mainDisplay, Root));
for (tmp = 0; tmp < 4; ++tmp)
alphabet[tmp+1] = alphabet_color[tmp];
alphabetXpm.attributes.valuemask |=
(XpmReturnPixels | XpmReturnExtensions);
status = XpmCreatePixmapFromData(
mainDisplay,
Root,
alphabet,
&alphabetXpm.pixmap, /* resulting pixmap */
&alphabetXpm.mask,
&alphabetXpm.attributes
);
if(status != XpmSuccess) {
printf("asmem : (%d) not enough free color cells for alphabet.\n", status);
XCloseDisplay(mainDisplay);
exit(1);
}
if (strlen(mainGeometry)) {
/* Check the user-specified size */
result = XParseGeometry(
mainGeometry,
&SizeHints.x,
&SizeHints.y,
&SizeHints.width,
&SizeHints.height
);
if (result & XNegative)
x_negative = 1;
if (result & YNegative)
y_negative = 1;
}
SizeHints.flags= USSize|USPosition;
SizeHints.x = 0;
SizeHints.y = 0;
XWMGeometry(
mainDisplay,
screen,
mainGeometry,
NULL,
1,
& SizeHints,
&SizeHints.x,
&SizeHints.y,
&SizeHints.width,
&SizeHints.height,
&gravity
);
SizeHints.min_width =
SizeHints.max_width =
SizeHints.width = backgroundXpm.attributes.width;
SizeHints.min_height =
SizeHints.max_height =
SizeHints.height= backgroundXpm.attributes.height;
SizeHints.flags |= PMinSize|PMaxSize;
/* Correct the offsets if the X/Y are negative */
SizeHints.win_gravity = NorthWestGravity;
if (x_negative) {
SizeHints.x -= SizeHints.width;
SizeHints.win_gravity = NorthEastGravity;
}
if (y_negative) {
SizeHints.y -= SizeHints.height;
if (x_negative)
SizeHints.win_gravity = SouthEastGravity;
else
SizeHints.win_gravity = SouthWestGravity;
}
SizeHints.flags |= PWinGravity;
drawWindow = XCreatePixmap(
mainDisplay,
Root,
SizeHints.width,
SizeHints.height,
color_depth
);
mainWindow = XCreateSimpleWindow(
mainDisplay, /* display */
Root, /* parent */
SizeHints.x, /* x */
SizeHints.y, /* y */
SizeHints.width, /* width */
SizeHints.height, /* height */
0, /* border_width */
fore_pix, /* border */
back_pix /* background */
);
iconWindow = XCreateSimpleWindow(
mainDisplay, /* display */
Root, /* parent */
SizeHints.x, /* x */
SizeHints.y, /* y */
SizeHints.width, /* width */
SizeHints.height, /* height */
0, /* border_width */
fore_pix, /* border */
back_pix /* background */
);
XSetWMNormalHints(mainDisplay, mainWindow, &SizeHints);
status = XClearWindow(mainDisplay, mainWindow);
status = XGetWindowAttributes(
mainDisplay, /* display */
mainWindow, /* window */
& winAttr /* window_attributes_return */
);
status = XSetWindowBackgroundPixmap(
mainDisplay, /* display */
mainWindow, /* window */
backgroundXpm.pixmap /* background_pixmap */
);
status = XSetWindowBackgroundPixmap(
mainDisplay, /* display */
iconWindow, /* window */
backgroundXpm.pixmap /* background_pixmap */
);
status = XStringListToTextProperty(&app_name, 1, &title);
XSetWMName(mainDisplay, mainWindow, &title);
XSetWMName(mainDisplay, iconWindow, &title);
classHint.res_name = "asmem" ;
classHint.res_class = "ASMEM";
XSetClassHint(mainDisplay, mainWindow, &classHint);
XStoreName(mainDisplay, mainWindow, "asmem");
XSetIconName(mainDisplay, mainWindow, "asmem");
status = XSelectInput(
mainDisplay, /* display */
mainWindow, /* window */
ExposureMask /* event_mask */
);
status = XSelectInput(
mainDisplay, /* display */
iconWindow, /* window */
ExposureMask /* event_mask */
);
/* Creating Graphics context */
mainGCV.foreground = fore_pix;
mainGCV.background = back_pix;
mainGCV.graphics_exposures = False;
mainGCV.line_style = LineSolid;
mainGCV.fill_style = FillSolid;
mainGCV.line_width = 1;
mainGC = XCreateGC(
mainDisplay,
mainWindow,
GCForeground|GCBackground|GCLineWidth|
GCLineStyle|GCFillStyle,
&mainGCV
);
status = XSetCommand(mainDisplay, mainWindow, argv, argc);
/* Set up the event for quitting the window */
wm_delete_window = XInternAtom(
mainDisplay,
"WM_DELETE_WINDOW", /* atom_name */
False /* only_if_exists */
);
wm_protocols = XInternAtom(
mainDisplay,
"WM_PROTOCOLS", /* atom_name */
False /* only_if_exists */
);
status = XSetWMProtocols(
mainDisplay,
mainWindow,
&wm_delete_window,
1
);
status = XSetWMProtocols(
mainDisplay,
iconWindow,
&wm_delete_window,
1
);
WmHints.flags = StateHint | IconWindowHint;
WmHints.initial_state =
withdrawn ? WithdrawnState :
iconic ? IconicState : NormalState;
WmHints.icon_window = iconWindow;
if ( withdrawn ) {
WmHints.window_group = mainWindow;
WmHints.flags |= WindowGroupHint;
}
if ( iconic || withdrawn ) {
WmHints.icon_x = SizeHints.x;
WmHints.icon_y = SizeHints.y;
WmHints.flags |= IconPositionHint;
}
XSetWMHints(
mainDisplay,
mainWindow,
&WmHints);
/* Finally show the window */
status = XMapWindow(
mainDisplay,
mainWindow
);
/* Get colors while waiting for Expose */
pix[0][0] = LightenColor(state.memory_color, 1.4, mainDisplay, mainWindow);
pix[0][1] = GetColor(state.memory_color, mainDisplay, mainWindow);
pix[0][2] = DarkenColor(state.memory_color, 1.4, mainDisplay, mainWindow);
pix[1][0] = LightenColor(state.buffer_color, 1.4, mainDisplay, mainWindow);
pix[1][1] = GetColor(state.buffer_color, mainDisplay, mainWindow);
pix[1][2] = DarkenColor(state.buffer_color, 1.4, mainDisplay, mainWindow);
pix[2][0] = LightenColor(state.cache_color, 1.4, mainDisplay, mainWindow);
pix[2][1] = GetColor(state.cache_color, mainDisplay, mainWindow);
pix[2][2] = DarkenColor(state.cache_color, 1.4, mainDisplay, mainWindow);
pix[3][0] = LightenColor(state.swap_color, 1.4, mainDisplay, mainWindow);
pix[3][1] = GetColor(state.swap_color, mainDisplay, mainWindow);
pix[3][2] = DarkenColor(state.swap_color, 1.4, mainDisplay, mainWindow);
if ( open_meminfo() ) {
/* The /proc/meminfo file reading problems */
asmem_cleanup();
}
if ( read_meminfo() ) {
asmem_cleanup();
}
/* wait for the Expose event now */
XNextEvent(mainDisplay, &Event);
/* We 've got Expose -> draw the parts of the window. */
asmem_redraw();
XFlush(mainDisplay);
}
syntax highlighted by Code2HTML, v. 0.9.1