If we can't make a CPUInfo object, things should die. TODO.
[cpuHistory.git] / MainController.m
bloba7323e118b2676ff508d405ac15e652c6fcbaf4e
1 /*
2  *      CPU History
3  *      Christopher Bowns, 2008
4  *      
5  *      Formerly: Memory Monitor, by Bernhard Baehr
6  *
7  *      Copyright © 2001-2003 Bernhard Baehr
8  *
9  *      MainController.m - Main Application Controller Class
10  *
11  *      This program is free software; you can redistribute it and/or modify
12  *      it under the terms of the GNU General Public License as published by
13  *      the Free Software Foundation; either version 2 of the License, or
14  *      (at your option) any later version.
15  *
16  *      This program is distributed in the hope that it will be useful,
17  *      but WITHOUT ANY WARRANTY; without even the implied warranty of
18  *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  *      GNU General Public License for more details.
20  *
21  *      You should have received a copy of the GNU General Public License
22  *      along with this program; if not, write to the Free Software
23  *      Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
24  */
27 #import "MainController.h"
30 #define GRAPH_SIZE      128
33 @implementation MainController
36 - (void)drawImageOnWindow
38         [displayImage drawInRect:NSMakeRect(0, 0, NSWidth([window frame]), NSHeight([window frame]))
39                 fromRect:NSMakeRect(0, 0, GRAPH_SIZE, GRAPH_SIZE) operation:NSCompositeCopy
40                 fraction:1.0];
44 - (void)showHideWindow
46         float   size;
47         
48         if ([[preferences objectForKey:SHOW_GRAPH_WINDOW_KEY] boolValue]) {
49                 size = [[preferences objectForKey:GRAPH_WINDOW_SIZE_KEY] floatValue];
50                 [window setContentSize:NSMakeSize(size, size)];
51                 [window orderWindow:NSWindowBelow relativeTo:[preferences windowNumber]];
52                 [window setLevel:([[preferences objectForKey:GRAPH_WINDOW_ON_TOP_KEY] boolValue] ?
53                         NSFloatingWindowLevel : NSNormalWindowLevel)];
54         } else
55                 [window orderOut:self];
59 - (void)drawComplete
60 // completely redraw graphImage, put graph into displayImage
61 {       
62         CPUData                 cpudata;
63         
64         
65         int                             x;
66         float                   y, yy;
67         
68         double interval = 0.1 * [[preferences objectForKey:UPDATE_FREQUENCY_KEY] floatValue];
69         
70         [graphImage lockFocus];
72         // draw the cpu usage graph
73         [cpuInfo startIterate];
74         // for (x = 0; [memInfo getNext:&vmdata]; x++) {
75         for (x = 0; [cpuInfo getNext:&cpudata]; x++) {
76                 
77                 // y = vmdata.wired * GRAPH_SIZE;
78                 y = cpudata.user * GRAPH_SIZE;
79                 [[preferences objectForKey:WIRED_COLOR_KEY] set];
80                 NSRectFill (NSMakeRect(x - 1, 0.0, x, y));
81                 yy = y;
82                 // y += vmdata.active * GRAPH_SIZE;
83                 y += cpudata.sys * GRAPH_SIZE;
84                 [[preferences objectForKey:ACTIVE_COLOR_KEY] set];
85                 NSRectFill (NSMakeRect(x - 1, yy, x, y));
86                 yy = y;
87                 // y += vmdata.inactive * GRAPH_SIZE;
88                 y += cpudata.nice * GRAPH_SIZE;
89                 [[preferences objectForKey:INACTIVE_COLOR_KEY] set];
90                 NSRectFill (NSMakeRect(x - 1, yy, x, y));
91                 
92                 // free data here
93                 [[preferences objectForKey:FREE_COLOR_KEY] set];
94                 NSRectFill (NSMakeRect(x - 1, y, x, GRAPH_SIZE));
95         }
96         
97         // transfer graph image to icon image
98         [graphImage unlockFocus];
99         [displayImage lockFocus];       
100         [graphImage compositeToPoint:NSMakePoint(0.0, 0.0) operation:NSCompositeCopy];
101                 
102         [displayImage unlockFocus];
106 - (void)drawDelta
107 // update graphImage (based on previous graphImage), put graph into displayImage
108 {       
109         // VMData                       vmdata, vmdata0;
110         CPUData                 cpudata, cpudata0;
111         float                   y, yy;
112         
113         double interval = 0.1 * [[preferences objectForKey:UPDATE_FREQUENCY_KEY] floatValue];
114         
115         [graphImage lockFocus];
117         // offset the old graph image
118         [graphImage compositeToPoint:NSMakePoint(-1, 0) operation:NSCompositeCopy];
119                 
120         // [memInfo getLast:&vmdata0];
121         [cpuInfo getLast:&cpudata0];
122         // [memInfo getCurrent:&vmdata];
123         [cpuInfo getCurrent:&cpudata];
124         
125         // draw chronological graph into graph image
126         // y = vmdata.wired * GRAPH_SIZE;
127         y = cpudata.user * GRAPH_SIZE;
128         [[preferences objectForKey:WIRED_COLOR_KEY] set];
129         NSRectFill (NSMakeRect(GRAPH_SIZE - 1, 0.0, GRAPH_SIZE - 1, y));
130         yy = y;
131         
132         // y += vmdata.active * GRAPH_SIZE;
133         y += cpudata.sys * GRAPH_SIZE;
134         [[preferences objectForKey:ACTIVE_COLOR_KEY] set];
135         NSRectFill (NSMakeRect(GRAPH_SIZE - 1, yy, GRAPH_SIZE - 1, y));
136         yy = y;
137         
138         // y += vmdata.inactive * GRAPH_SIZE;
139         y += cpudata.nice * GRAPH_SIZE;
140         [[preferences objectForKey:INACTIVE_COLOR_KEY] set];
141         NSRectFill (NSMakeRect(GRAPH_SIZE - 1, yy, GRAPH_SIZE - 1, y));
142         
143         // free data here
144         [[preferences objectForKey:FREE_COLOR_KEY] set];
145         NSRectFill (NSMakeRect(GRAPH_SIZE - 1, y, GRAPH_SIZE - 1, GRAPH_SIZE));
148         // transfer graph image to icon image
149         [graphImage unlockFocus];
150         [displayImage lockFocus];
151         [graphImage compositeToPoint:NSMakePoint(0.0, 0.0) operation:NSCompositeCopy];
153         [displayImage unlockFocus];
157 - (void)setApplicationIcon
158 // set the (scaled) application icon
160         float inc = GRAPH_SIZE * (1.0 - [[preferences objectForKey:DOCK_ICON_SIZE_KEY] floatValue]);
161         [iconImage lockFocus];
162         [displayImage drawInRect:NSMakeRect(inc, inc, GRAPH_SIZE - 2 * inc, GRAPH_SIZE - 2 * inc) fromRect:NSMakeRect(0, 0, GRAPH_SIZE, GRAPH_SIZE) operation:NSCompositeCopy fraction:1.0];
163         [iconImage unlockFocus];
164         [NSApp setApplicationIconImage:iconImage];
168 - (void)refreshGraph
169 // get a new sample and refresh the graph
171         // [memInfo refresh];
172         [cpuInfo refresh];
173         [self drawDelta];
174         [self setApplicationIcon];
175         
176         if ([[preferences objectForKey:SHOW_GRAPH_WINDOW_KEY] boolValue]) {
177                 [window disableFlushWindow];
178                 [view display];
179                 [window enableFlushWindow];
180                 [window flushWindow];
181         }
185 - (void)updateGraph
186 // completely redraw the graph (to show new preferences settings)
188         [self drawComplete];
189         [iconImage lockFocus];
190         [[NSColor clearColor] set];
191         NSRectFill (NSMakeRect(0, 0, GRAPH_SIZE, GRAPH_SIZE));
192         [iconImage unlockFocus];
193         [self setApplicationIcon];
194         
195         if ([[preferences objectForKey:SHOW_GRAPH_WINDOW_KEY] boolValue]) {
196                 [window disableFlushWindow];
197                 [view display];
198                 [window enableFlushWindow];
199                 [window flushWindow];
200         }
204 - (void)setTimer
206         double newInterval = 0.1 * [[preferences objectForKey:UPDATE_FREQUENCY_KEY] floatValue];
208         if (timer) {
209                 if (fabs([timer timeInterval] - newInterval) < 0.001)
210                         return;         /* frequency not changed */
211                 [timer invalidate];
212                 [timer release];
213         }
214         timer = [NSTimer scheduledTimerWithTimeInterval:newInterval
215                 target:self selector:@selector(refreshGraph) userInfo:nil repeats:YES];
216         [timer retain];
220 - (void)showPreferences:(id)sender
222         [NSApp activateIgnoringOtherApps:YES];  /* activate application when called from Dock menu */
223         [preferences showPreferences:self];
227 - (void)showAboutBox:(id)sender
229         [NSApp activateIgnoringOtherApps:YES];  /* activate application when called from Dock menu */
230         [NSApp orderFrontStandardAboutPanel:sender];
234 - (BOOL)isLoginItem
236         id      obj;
237         
238         NSString *memoryMonitorPath = [[NSBundle mainBundle] bundlePath];
239         NSDictionary *loginItemDict = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:@"%@/Library/Preferences/loginwindow.plist", NSHomeDirectory()]];
240         NSEnumerator *loginItemEnumerator = [[loginItemDict objectForKey:@"AutoLaunchedApplicationDictionary"] objectEnumerator];
242         while ((obj = [loginItemEnumerator nextObject])) {
243                 if ([[obj objectForKey:@"Path"] isEqualTo:memoryMonitorPath])
244                         return (YES);
245         }
246         return (NO);
250 - (unsigned)systemVersion
251 // returns the system version normally retrieved with Gestalt(gestaltSystemVersion, &systemVersion)
253         const char      *p;
254         
255         unsigned version = 0;
256         
257         for (p = [[[NSDictionary dictionaryWithContentsOfFile:@"/System/Library/CoreServices/SystemVersion.plist"]
258                 objectForKey:@"ProductVersion"] cString]; *p; p++) {
259                 if (*p != '.')
260                         version = (version << 4) | (*p - '0');
261         }
262         if (version < 0x1000)   // for 10.0, 10.1
263                 version <<= 4;
264         return (version);
268 - (BOOL)updateFrameName
269 // calculate the frameName used to save the window position; return TRUE iff the name changed,
270 // i. e. the display configuration changed since last call of this method
272         NSRect          rect;
273         NSScreen        *screen;
274         BOOL            nameDidChange;
275         
276         NSString *string = @"MMWL";     // MemoryMonitorWindowLocation
277         NSEnumerator *enumerator = [[NSScreen screens] objectEnumerator];
279         while ((screen = [enumerator nextObject])) {
280                 rect = [screen frame];
281                 string = [string
282                         stringByAppendingString:[NSString stringWithFormat:@"%.0f%.0f%.0f%.0f",
283                         rect.origin.x, rect.origin.y, rect.size.width, rect.size.height]];
284         }
285         nameDidChange = ! [string isEqualToString:frameName];
286         [frameName release];
287         frameName = string;
288         [frameName retain];
289         return (nameDidChange);
293 - (void)applicationDidFinishLaunching:(NSNotification *)notification
295         preferences = [[Preferences alloc] init];
296         // memInfo = [[MemInfo alloc] initWithCapacity:GRAPH_SIZE];
297         cpuInfo = [[CPUInfo alloc] initWithCapacity:GRAPH_SIZE];
298         if (nil == cpuInfo) //then we need to bomb out. We can't go anywhere from here.
299         {
300                 NSLog(@"%s failed to create CPUInfo object! App will crash in a minute. This is unavoidable until we learn how to gracefully exit.", _cmd);
301                 /*
302                         TODO appDidFinishLaunching: error on creating cpuInfo obj: shut down the app gracefully. Display error message?
303                 */
304         }
305         
306         displayImage = [[NSImage allocWithZone:[self zone]] initWithSize:NSMakeSize(GRAPH_SIZE, GRAPH_SIZE)];
307         graphImage = [[NSImage allocWithZone:[self zone]] initWithSize:NSMakeSize(GRAPH_SIZE, GRAPH_SIZE)];
308         iconImage = [[NSImage allocWithZone:[self zone]] initWithSize:NSMakeSize(GRAPH_SIZE, GRAPH_SIZE)];
309         [self drawComplete];
311         window = [[TranslucentWindow allocWithZone:[self zone]]
312                 initWithContentRect:NSMakeRect(0.0, 0.0, GRAPH_SIZE, GRAPH_SIZE)
313                 styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:NO];
314         [window setReleasedWhenClosed:NO];
315         [window setBackgroundColor:[NSColor clearColor]];
316         [self updateFrameName];
317         if (! [window setFrameUsingName:frameName]) {
318                 // for compatibility with version 1.1 preferences file
319                 [window setFrameUsingName:@"MemoryMonitorWindowLocation"];
320                 [NSWindow removeFrameUsingName:@"MemoryMonitorWindowLocation"];
321                 [window saveFrameUsingName:frameName];
322         }
323         [window setDelegate:self];
325         view = [[TranslucentView allocWithZone:[self zone]] initWithFrame:NSMakeRect(0.0, 0.0, GRAPH_SIZE, GRAPH_SIZE)];
326         [window setContentView:view];
327         [view setContentDrawer:self method:@selector(drawImageOnWindow)];
328         [view setAutoresizingMask:(NSViewHeightSizable | NSViewWidthSizable)];
329         [view setToolTip:@"Memory Monitor"];
330         
331         
332         [self showHideWindow];
334         [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(showHideWindow) name:PREFERENCES_CHANGED object:nil];
335         [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(updateGraph) name:PREFERENCES_CHANGED object:nil];
336         [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(setTimer) name:PREFERENCES_CHANGED object:nil];
338         if ([self systemVersion] < 0x1010 && [self isLoginItem])
339                 [NSTimer scheduledTimerWithTimeInterval:30 target:self selector:@selector(setTimer) userInfo:nil repeats:NO];
340         else
341                 [self setTimer];
345 - (void)applicationWillTerminate:(NSNotification *)aNotification 
347         if (timer) {
348                 [timer invalidate];
349                 [timer release];
350                 timer = nil;
351         }
352         [preferences savePreferences];
353         [NSApp setApplicationIconImage:[NSImage imageNamed:@"MemoryMonitor.icns"]];     
357 - (void)applicationDidChangeScreenParameters:(NSNotification *)aNotification
359         [self updateFrameName];
360         [window setFrameUsingName:frameName];
364 - (void)windowDidMove:(NSNotification *)aNotification
366         if (! [self updateFrameName])
367                 [window saveFrameUsingName:frameName];
371 @end