/* * gmemusage.c * main file for gmemusage * * Copyright (C) 1997, 1998 by Raju Mathur (raju@sgi.com) * Some portions based on O'Reilly and Associates' Xlib Programming tutorial * examples. * * See file COPYING (included in this distribution) for copyright information. * * Xemacs configuration for this indentation: * (add-hook 'c-mode-common-hook * '(lambda () * (c-set-style "ellemtel") * (c-set-offset 'topmost-intro-cont '+) * (c-set-offset 'topmost-intro '-) * (c-set-offset 'case-label '*) * (c-set-offset 'statement-case-intro '*))) * * Version 0.2, 980114 */ #include #include #include #include #include #include "memusage.xbm" #include #include #include #include #include #include "common.h" #include "defaults.h" #define BITMAPDEPTH 1 #define TOO_SMALL 0 #define BIG_ENOUGH 1 /* * I hate these file-wide variables, but since draw_window is going to be * called from a signal, we can't pass it any args. */ static Display *display ; static int screen_num ; char progname [128] , /* other functions need to access this one */ *version = "0.1" ; /* and this one */ static Window win ; #ifndef SAVE_XSERVER_MEMORY static Pixmap pxm; #endif static int window_width , window_height ; static int nColors ; static int Threshhold = -1 ; static XColor Foreground , Background ; static XFontStruct *font_info ; static int Exposed = 0 ; /* * Is this the right way to have (e.g.) 16 colors? 16 different GC's with * a different foreground? */ static GC gc [MaxColors] ; static GC blackGC; /* * Protos. */ void getGCs ( Window win , Colormap cmap ) ; #if 0 void place_text ( Window win , GC gc , XFontStruct *font_info , unsigned int win_width , unsigned int win_height ) ; void place_graphics ( Window win , GC gc , unsigned int window_width , unsigned int window_height ) ; #endif void draw_window ( void ) ; void TooSmall ( Window win , GC gc , XFontStruct *font_into ) ; void main ( int argc , char **argv ) { int default_height , default_width , default_x , default_y ; int x = 0 , y = 0 , width , height ; unsigned int border_width = 4 , display_width , display_height ; char *window_name = "gmemusage" , *icon_name = "gmemusage" ; Pixmap icon_pixmap ; XSizeHints *size_hints ; XEvent report ; int screen_num ; Screen *screen_ptr ; XWMHints *wm_hints ; XClassHint *class_hints ; XTextProperty windowName , iconName ; Colormap cmap ; /* * Remove leading dir.../ from argv[0] and store in progname */ if ( strrchr ( argv [0] , '/' ) ) { strcpy ( progname , strrchr ( argv [0] , '/' ) + 1 ) ; } else { strcpy ( progname , argv [0] ) ; } /* * Allocate necessaru X structures for later use. Apparently this needs to * be done before any other X stuff. */ if ( !( size_hints = XAllocSizeHints () ) ) { fprintf ( stderr , "%s: failure allocating SizeHints\n" , progname ) ; exit ( 1 ) ; } if ( !( wm_hints = XAllocWMHints () ) ) { fprintf ( stderr , "%s: failure allocating WMHints\n" , progname ) ; exit ( 1 ) ; } if ( !( class_hints = XAllocClassHint () ) ) { fprintf ( stderr , "%s: failure allocating ClassHints\n" , progname ) ; exit ( 1 ) ; } /* * Figure out resources from the command-line and screen resources. */ GetInitialResources ( &argc , argv ) ; if ( ( display = XOpenDisplay ( dDisplay ) ) == NULL ) { (void) fprintf ( stderr , "%s: cannot connect to X server %s\n" , progname , XDisplayName ( dDisplay ) ) ; exit ( 1 ) ; } GetResources ( display , argc , argv ) ; XParseGeometry ( dGeometry , &default_x , &default_y , &default_width , &default_height ) ; screen_num = DefaultScreen ( display ) ; screen_ptr = DefaultScreenOfDisplay ( display ) ; display_width = DisplayWidth ( display , screen_num ) ; display_height = DisplayHeight ( display , screen_num ) ; /* * Get foreground and background colors for the window */ cmap = DefaultColormap ( display , DefaultScreen ( display ) ) ; if (!XParseColor ( display , cmap , dForeground , &Foreground ) ) { fprintf ( stderr , "%s: Cannot parse color %s\n" , progname , dForeground ) ; Foreground . pixel = BlackPixel ( display , screen_num ) ; } else { XAllocColor ( display , cmap , &Foreground ) ; } if (!XParseColor ( display , cmap , dBackground , &Background ) ) { fprintf ( stderr , "%s: Cannot parse color %s\n" , progname , dBackground ) ; Background . pixel = WhitePixel ( display , screen_num ) ; } else { XAllocColor ( display , cmap , &Background ) ; } width = default_width ; height = default_height ; win = XCreateSimpleWindow ( display , RootWindow ( display , screen_num ) , x , y , width , height , border_width , Foreground . pixel , Background . pixel ) ; #ifndef SAVE_XSERVER_MEMORY pxm = XCreatePixmap ( display , win , width , height , DefaultDepth ( display , screen_num ) ); #endif icon_pixmap = XCreateBitmapFromData ( display , win , memusage_bits , memusage_width , memusage_height ) ; size_hints -> flags = PPosition | PSize | PMinSize ; size_hints -> min_width = default_width ; size_hints -> min_height = default_height ; if ( XStringListToTextProperty (&window_name , 1 , &windowName ) == 0 ) { fprintf ( stderr , "%s: struct allocation for windowName failed\n" , progname ) ; exit ( 1 ) ; } if ( XStringListToTextProperty ( &icon_name , 1 , &iconName ) == 0 ) { fprintf ( stderr , "%s: struct allocation for iconName failed\n" , progname ) ; exit ( 1 ) ; } wm_hints -> initial_state = NormalState ; wm_hints -> input = True ; wm_hints -> icon_pixmap = icon_pixmap ; wm_hints -> flags = StateHint | IconPixmapHint | InputHint ; class_hints -> res_name = progname ; class_hints -> res_class = "BasicWin" ; XSetWMProperties ( display , win , &windowName , &iconName , argv , argc , size_hints , wm_hints , class_hints ) ; XSelectInput ( display , win , ExposureMask | KeyPressMask | ButtonPressMask | StructureNotifyMask ) ; getGCs ( win , cmap ) ; XMapWindow ( display , win ) ; while ( 1 ) { XNextEvent ( display , &report ) ; switch ( report . type ) { char keybuf [10] ; KeySym keysym ; int count ; XComposeStatus composestatus ; case Expose: if ( report . xexpose . count != 0 ) { break ; } #if 0 printf("Expose %d %d %d %d\n",report.xexpose.x,report.xexpose.y,report.xexpose.width,report.xexpose.height); #endif #if 0 if ( window_size == TOO_SMALL ) { TooSmall ( win , gc , font_info ) ; } else #endif { Exposed = 1 ; draw_window () ; } break ; case ConfigureNotify: window_width = report . xconfigure . width ; window_height = report . xconfigure . height ; #ifndef SAVE_XSERVER_MEMORY XFreePixmap ( display , pxm ); pxm = XCreatePixmap ( display , win , window_width , window_height , DefaultDepth ( display , screen_num ) ); #endif #if 0 if ( window_width < size_hints -> min_width || window_height < size_hints -> min_height ) { window_size = TOO_SMALL ; } else { window_size = BIG_ENOUGH ; } #endif break ; case ButtonPress: /* ignore buttons for now */ XBell ( display , 10 ) ; break ; case KeyPress: count = XLookupString ( &report . xkey , keybuf , sizeof ( keybuf ) , &keysym , &composestatus ) ; if ( ( keysym >= XK_KP_Space && keysym <= XK_KP_9 ) || ( keysym >= XK_space && keysym <= XK_asciitilde ) ) { register int i ; for ( i = 0 ; keybuf [i] ; i++ ) { switch ( keybuf [i] ) { register int j ; case 'q': case 'Q': XUnloadFont ( display , font_info -> fid ) ; for ( j = 0 ; j < nColors ; j++ ) { XFreeGC ( display , gc [j] ) ; } XCloseDisplay ( display ) ; exit ( 0 ) ; default: XBell ( display , 10 ) ; break ; } } } else { switch ( keysym ) { case XK_Up: Threshhold += ThreshholdDelta ; break ; case XK_Down: Threshhold -= ThreshholdDelta ; if ( Threshhold < ThreshholdDelta ) { XBell ( display , 0 ) ; Threshhold = ThreshholdDelta ; } break ; default: #ifdef BELL_ON_UNKNOWN_KEYPRESS XBell ( display , 10 ) ; #endif break ; } } break ; default: #if 0 fprintf ( stderr , "%s: Unknown event: %d\n" , progname , report . type ) ; #endif break ; } } exit ( 0 ) ; } /* * Do all the drawing. */ void draw_window ( void ) { int pcWidth , pcHeight , pixelWidth , pixelHeight ; #ifdef SAVE_XSERVER_MEMORY Pixmap pxm; #endif struct XProcInfo { struct ProcInfo *pi ; int pixelHeight , base , midpoint ; } ; register int i ; static int nprocs ; static int oldThreshhold ; int oldnprocs ; register struct XProcInfo *this ; static struct ProcInfo *pi ; static struct XProcInfo *xpi , *oldxpi ; int alarmsecs ; static int done = 0 ; int basex , basey ; #if 0 int temp1 ; #endif GC *thisGC ; int thxpi = -1 ; struct ProcInfo thProc ; int labelNumber = 0 , nLabels = 0 ; int longestLabel = 0 ; /* * No alarms while we're here. */ (void) signal ( SIGALRM , SIG_IGN ) ; /* * See if we're being called due to an alarm, and schedule the next alarm. * If the alarm is pending, we can reuse the old data rather than calling * AllProcs again. */ if ( alarmsecs = alarm ( dUpdate ) && done ) { /* * if the alarm didn't go off, we don't need to recalc everything. */ #if 0 printf("called from expose\n"); #endif alarm ( alarmsecs ) ; } else { /* * Get the process info */ #if 0 printf("called from alarm\n"); #endif oldxpi = xpi ; oldnprocs = nprocs ; makeProcs () ; pi = AllProcs ( &nprocs ) ; done = 1 ; } /* * Calculate width of memory bars as percentage and in pixels. */ pcWidth = 40 ; pixelWidth = window_width * pcWidth / 100.0 ; pcHeight = 90 ; pixelHeight = window_height * pcHeight / 100.0 ; basex = DefaultBorder ; basey = window_height - ( window_height - pixelHeight ) / 2 - 1 ; if ( Threshhold < 0 ) { Threshhold = dThreshhold ; } #if 0 printf("pcw %d, pw %d, pch %d, ph %d, base %d\n",pcWidth,pixelWidth,pcHeight,pixelHeight,basey); #endif /* * Go through the array: allocate the ProcInfo pointer, calculate height, * base, midpoint for each rectangle. */ if ( ( xpi = calloc ( nprocs , sizeof ( struct XProcInfo ) ) ) == NULL ) { fprintf ( stderr , "%s: calloc struct XProcInfo failed" , progname ) ; perror ( "" ) ; exit ( 1 ) ; } this = xpi ; /* * First get the sum of processes less than the threshhold size */ for ( i = 0 ; i < nprocs ; i++ ) { if ( pi [i] . totRSS < Threshhold && strcmp ( pi [i] . procname , kernelname ) && strcmp ( pi [i] . procname , freename ) ) { if ( thxpi < 0 ) { thxpi = i ; sprintf ( thProc . procname , "< %d" , Threshhold ) ; thProc . totRSS = pi [i] . totRSS ; thProc . totMem = 0 ; thProc . nProcs = pi [i] . nProcs ; this [i] . pi = &thProc ; } else { this [thxpi] . pi -> nProcs += pi [i] . nProcs ; this [thxpi] . pi -> totRSS += pi [i] . totRSS ; } } } #if 0 temp1=0; printf("%d %s %d\n",thxpi,this[thxpi].pi->procname,this[thxpi].pi->totRSS); #endif /* * Now calculate percentages and sizes for the remaining (large-enough) * processes. */ for ( i = 0 ; i < nprocs ; i++ ) { if ( i != thxpi ) { if ( pi [i] . totRSS < Threshhold ) { this [i] . pi = NULL ; continue ; } else { this [i] . pi = &pi [i] ; } } nLabels++ ; #if 0 temp1+=pi[i].totRSS; printf("%s %d %d %d\n",this[i].pi->procname,this[i].pi->totMem,this[i].pi->totRSS,temp1); #endif this [i] . pixelHeight = this [i] . pi -> totRSS * pixelHeight / sysmem ; basey -= this [i] . pixelHeight ; this [i] . base = basey ; this [i] . midpoint = basey + this [i] . pixelHeight / 2 ; if ( strlen ( this [i] . pi -> procname ) > longestLabel ) { longestLabel = strlen ( this [i] . pi -> procname ) ; } } #if 0 /* Needs much more work */ /* * Check if the new values have changed at all from the previous values. * If not, just deallocate and return without redrawing. */ if ( oldThreshhold == Threshhold && oldnprocs == nprocs && !memcmp ( xpi , oldxpi , sizeof ( struct XProcInfo ) * nprocs ) && !Exposed ) { free ( oldxpi ) ; return ; } #endif /* * Make the boxes. */ #if 0 XClearArea ( display , win , 0 , 0 , 0 , 0 , False ) ; #else #ifdef SAVE_XSERVER_MEMORY pxm = XCreatePixmap ( display , win , window_width , window_height , DefaultDepth ( display , screen_num ) ); #endif XFillRectangle ( display , pxm , blackGC , 0 , 0 , window_width , window_height ) ; #endif #if 0 printf("%d %d\n",window_height,window_width); #endif labelNumber = 0 ; for ( i = 0 ; i < nprocs ; i++ ) { if ( !this [i] . pi ) { continue ; } thisGC = &gc [labelNumber % nColors] ; #if 0 printf("%d %d %d %d\n",basex,this[i].base,pixelWidth,this[i].pixelHeight); #endif XFillRectangle ( display , pxm , *thisGC , basex , this [i] . base , pixelWidth , this [i] . pixelHeight ) ; labelNumber++ ; } /* * Make the lines and the text. */ { int lineSpace = window_height / nLabels , longestLabelWidth , textXoffset , fontHeight ; char buf [128] , nprocbuf [10] ; /* procname (nnn) : nnnnnK */ memset ( buf , 'W' , longestLabel + 6 + 2 + 7 ) ; longestLabelWidth = XTextWidth ( font_info , buf , longestLabel + 6 + 2 + 7 ) ; textXoffset = window_width - DefaultBorder - longestLabelWidth ; fontHeight = font_info -> ascent + font_info -> descent ; labelNumber = 0 ; for ( i = 0 ; i < nprocs ; i++ ) { if ( !this [i] . pi ) { continue ; } thisGC = &gc [labelNumber % nColors] ; XDrawLine ( display , pxm , *thisGC , DefaultBorder + pixelWidth , this [i] . midpoint , textXoffset - 2 , window_height - (labelNumber * lineSpace ) - lineSpace / 2 ) ; if ( this [i] . pi -> nProcs > 1 ) { sprintf ( nprocbuf , "(%d)" , this [i] . pi -> nProcs ) ; } else { nprocbuf [0] = '\0' ; } sprintf ( buf , "%-*s %6s : %5dK" , longestLabel , this [i] . pi -> procname , nprocbuf , this [i] . pi -> totRSS ) ; #if 0 if ( strcmp ( this [i] . pi -> procname , kernelname ) && strcmp ( this [i] . pi -> procname , freename ) ) { sprintf ( buf , "%s (%d)" , this [i] . pi -> procname , this [i] . pi -> nProcs ) ; } else { strcpy ( buf , this [i] . pi -> procname ) ; } #endif XDrawString ( display , pxm , *thisGC , textXoffset , window_height - ( labelNumber * lineSpace ) - ( lineSpace - fontHeight ) / 2 - 2 , buf , strlen ( buf ) ) ; labelNumber++ ; } } XCopyArea ( display , pxm , win , blackGC, 0 , 0 , window_width, window_height, 0 , 0 ); #ifdef SAVE_XSERVER_MEMORY XFreePixmap ( display , pxm ); #endif XFlush ( display ) ; /* * Save and clear some of the values. */ oldThreshhold = Threshhold ; Exposed = 0 ; if ( oldxpi ) { free ( oldxpi ) ; oldxpi = NULL ; } /* * We can accept alarms again */ (void) signal ( SIGALRM , draw_window ) ; return ; } void getGCs ( Window win , Colormap cmap ) { unsigned long valuemask = 0 ; XGCValues values ; unsigned int line_width = 0 ; /* fastest server-dependent line */ int line_style = LineSolid , cap_style = CapRound , join_style = JoinRound ; XColor rgb ; register int i ; if ( ( font_info = XLoadQueryFont ( display , dFont ) ) == NULL ) { fprintf ( stderr , "%s: cannot load font %s\n" , progname , dFont ) ; exit ( 1 ) ; } nColors = dnColors ; for ( i = 0 ; i < nColors ; i++ ) { if ( dColor [i] [0] && !XParseColor ( display , cmap , dColor [i] , &rgb ) ) { fprintf ( stderr , "%s: Cannot parse color %s\n" , progname , dColor [i] ) ; rgb . pixel = BlackPixel ( display , screen_num ) ; } else { XAllocColor ( display , cmap , &rgb ) ; } gc [i] = XCreateGC ( display , win , valuemask , &values ) ; XSetForeground ( display , gc [i] , rgb . pixel ) ; XSetFont ( display , gc [i] , font_info -> fid ) ; XSetLineAttributes ( display , gc [i] , line_width , line_style , cap_style , join_style ) ; } valuemask |= GCPlaneMask; values.plane_mask = AllPlanes; blackGC = XCreateGC ( display , win , valuemask , &values ) ; XSetForeground ( display , blackGC , BlackPixel ( display , screen_num ) ) ; return ; } #if 0 void place_text ( Window win , GC gc , XFontStruct *font_info , unsigned int win_width , unsigned int win_height ) { char *string1 = "Hi! I'm a window, who are you?" , *string2 = "To terminate program: press any key" , *string3 = "or button while in this window." , *string4 = "Screen Dimensions" ; int len1 , len2 , len3 , len4 , width1 , width2 , width3 ; char cd_height[50] , cd_width [50] , cd_depth [50] ; int font_height , initial_y_offset , x_offset ; len1 = strlen ( string1 ) ; len2 = strlen ( string2 ) ; len3 = strlen ( string3 ) ; width1 = XTextWidth ( font_info , string1 , len1 ) ; width2 = XTextWidth ( font_info , string2 , len2 ) ; width3 = XTextWidth ( font_info , string3 , len3 ) ; font_height = font_info -> ascent + font_info -> descent ; XDrawString ( display , win , gc , ( win_width - width1 ) / 2 , font_height , string1 , len1 ) ; XDrawString ( display , win , gc , ( win_width - width2 ) / 2 , win_height - 2 * font_height , string2 , len2 ) ; XDrawString ( display , win , gc , ( win_width - width3 ) / 2 , win_height - 3 * font_height , string3 , len3 ) ; sprintf ( cd_height , " Height - %d pixels" , DisplayHeight ( display , screen_num ) ) ; sprintf ( cd_width , " Width - %d pixels" , DisplayWidth ( display , screen_num ) ) ; sprintf ( cd_depth , " Depth - %d planes" , DefaultDepth ( display , screen_num ) ) ; len4 = strlen ( string4 ) ; len1 = strlen ( cd_height ) ; len2 = strlen ( cd_width ) ; len3 = strlen ( cd_depth ) ; initial_y_offset = win_height / 2 - font_height - font_info -> descent ; x_offset = win_width / 4 ; XDrawString ( display , win , gc , x_offset , initial_y_offset , string4 , len4 ) ; XDrawString ( display , win , gc , x_offset , initial_y_offset + font_height , cd_height , len1 ) ; XDrawString ( display , win , gc , x_offset , initial_y_offset + 2 * font_height , cd_width , len2 ) ; XDrawString ( display , win , gc , x_offset , initial_y_offset + 3 * font_height , cd_depth , len3 ) ; } void place_graphics ( Window win , GC gc , unsigned int window_width , unsigned int window_height ) { int x , y , width , height ; height = window_height / 2 ; width = 3 * window_width / 4 ; x = window_width / 2 - width / 2 ; y = window_height / 2 - height / 2 ; XDrawRectangle ( display , win , gc , x , y , width , height ) ; } void TooSmall ( Window win , GC gc , XFontStruct *font_info ) { char *string1 = "Too Small" ; int x_offset , y_offset ; y_offset = font_info -> ascent + 2 ; x_offset = 2 ; XDrawString ( display , win , gc , x_offset , y_offset , string1 , strlen ( string1 ) ) ; } #endif