source: trunk/ICeCoffEE/ICeCoffEE/ICeCoffEEServicePrefController.m @ 433

Last change on this file since 433 was 433, checked in by Nicholas Riley, 12 years ago

Undocumented method / hack fallback to determine whether we should draw the highlighted row as active.

File size: 19.9 KB
Line 
1//
2//  ICeCoffEEServicePrefController.m
3//  ICeCoffEE APE
4//
5//  Created by Nicholas Riley on Fri Jun 06 2003.
6//  Copyright (c) 2003 Nicholas Riley. All rights reserved.
7//
8
9#import "ICeCoffEEShared.h"
10#import "ICeCoffEEServices.h"
11#import "ICeCoffEEServicePrefController.h"
12#import "ICeCoffEEMenuOutlineView.h"
13#import "ICeCoffEENonHighlightingButtonCell.h"
14#import "ICeCoffEEInvertingTextFieldCell.h"
15#import "ICeCoffEELabeledIconCell.h"
16#import <objc/objc.h>
17#import <ApplicationEnhancer/ApplicationEnhancer.h>
18#import <QuartzCore/QuartzCore.h>
19
20const int ICCF_SERVICE_UNKNOWN = 0;
21const int ICCF_SERVICE_SHOWN = 1;
22const int ICCF_SERVICE_HIDDEN = 2;
23const int ICCF_SERVICE_MIXED = 3;
24
25static NSDictionary *ICCF_SERVICE_OPTION_HIDDEN;
26
27static float ICCF_TableViewCellHeight(NSTableView *tableView) {
28    return ([tableView rowHeight] + [tableView intercellSpacing].height);
29}
30
31static NSMutableDictionary *keyEquivalents;
32static NSDictionary *userKeyEquivalents;
33
34static void ICCF_RemoveSingleKeyEquivalents() {
35    NSMutableArray *singleKeys = [[NSMutableArray alloc] init];
36    NSEnumerator *e = [[keyEquivalents allKeys] objectEnumerator];
37    NSString *keyEquivalent;
38    ICLog(@"before ICCF_RemoveSingleKeyEquivalents: %@", keyEquivalents);
39    while ( (keyEquivalent = [e nextObject]) != nil) {
40        if ([[keyEquivalents objectForKey: keyEquivalent] count] == 1)
41            [singleKeys addObject: keyEquivalent];
42    }
43    [keyEquivalents removeObjectsForKeys: singleKeys];
44    [singleKeys release];
45    ICLog(@"after ICCF_RemoveSingleKeyEquivalents: %@", keyEquivalents);
46}
47
48static inline unsigned ICCF_CountForKeyEquivalent(NSString *keyEquivalent) {
49    if (keyEquivalent == nil) return 0;
50    NSMutableSet *setOrNil = (NSMutableSet *)[keyEquivalents objectForKey: keyEquivalent];
51    return (setOrNil == nil) ? 0 : [setOrNil count];
52}
53
54static inline void ICCF_AddKeyEquivalentForItem(NSMenuItem *item) {
55    NSString *keyEquivalent = [item toolTip];
56    if (keyEquivalent == nil) return;
57    NSMutableSet *setOrNil = (NSMutableSet *)[keyEquivalents objectForKey: keyEquivalent];
58    if (setOrNil == nil) return;
59    [setOrNil addObject: item];
60}
61
62static inline void ICCF_RemoveKeyEquivalentForItem(NSMenuItem *item) {
63    NSString *keyEquivalent = [item toolTip];
64    if (keyEquivalent == nil) return;
65    NSMutableSet *setOrNil = (NSMutableSet *)[keyEquivalents objectForKey: keyEquivalent];
66    if (setOrNil == nil) return;
67    [setOrNil removeObject: item];
68}
69
70static int ICCF_GetServiceState(NSMenuItem *item) {
71    return [item tag];
72}
73
74static void ICCF_SetServiceState(NSMenuItem *item, int state) {
75    [item setTag: state];
76}
77
78static inline void ICCF_UpdateKeyEquivalentForItem(NSMenuItem *item, int state) {
79    return; // XXX disabled until we can affect menubar Services menu(s)
80    int oldState = ICCF_GetServiceState(item);
81    if ((oldState == ICCF_SERVICE_UNKNOWN || oldState == ICCF_SERVICE_SHOWN) && state == ICCF_SERVICE_HIDDEN)
82        ICCF_RemoveKeyEquivalentForItem(item);
83    else if (oldState == ICCF_SERVICE_HIDDEN && (state == ICCF_SERVICE_SHOWN || state == ICCF_SERVICE_UNKNOWN))
84        ICCF_AddKeyEquivalentForItem(item);
85}
86
87
88static inline NSCellStateValue ICCF_ServiceItemState(NSMenuItem *item) {
89    int state = ICCF_GetServiceState(item);
90    if (state == ICCF_SERVICE_HIDDEN)
91        return NSOffState;
92    if (state == ICCF_SERVICE_MIXED)
93            return NSMixedState;
94    return NSOnState;
95}
96
97static void ICCF_PropagateServiceStateChange(NSMenu *menu, int state) {
98    NSEnumerator *e = [[menu itemArray] objectEnumerator];
99    NSMenuItem *item;
100    NSMenu *submenu;
101
102    while ( (item = [e nextObject]) != nil) {
103        submenu = [item submenu];
104        if (submenu != nil)
105            ICCF_PropagateServiceStateChange(submenu, state);
106        else
107            ICCF_UpdateKeyEquivalentForItem(item, state);
108       
109        ICCF_SetServiceState(item, state);
110    }
111}
112
113static NSCellStateValue ICCF_PropagateServiceState(NSMenuItem *item, NSMenuItem *changedItem) {
114    NSMenu *submenu = [item submenu];
115    if (submenu == nil) return ICCF_ServiceItemState(item);
116
117    if (item == changedItem) ICCF_PropagateServiceStateChange(submenu, [item tag]);
118
119    BOOL areOn = NO, areOff = NO;
120    NSEnumerator *e = [[submenu itemArray] objectEnumerator];
121    NSMenuItem *subItem;
122    while ( (subItem = [e nextObject]) != nil) {
123        switch (ICCF_PropagateServiceState(subItem, changedItem)) {
124            case NSOnState: if (!areOff) { areOn = YES; continue; }
125                break;
126            case NSOffState: if (!areOn) { areOff = YES; continue; }
127                break;
128            case NSMixedState:
129                break;
130        }
131        ICCF_SetServiceState(item, ICCF_SERVICE_MIXED);
132        return NSMixedState;
133    }
134    if (areOn) {
135        ICCF_SetServiceState(item, ICCF_SERVICE_SHOWN);
136        return NSOnState;
137    } else {
138        ICCF_SetServiceState(item, ICCF_SERVICE_HIDDEN);
139        return NSOffState;
140    }
141}
142
143static NSMutableDictionary *ICCF_RetainedServiceOptionsDictionary(NSMenu *menu) {
144    NSEnumerator *e = [[menu itemArray] objectEnumerator];
145    NSMenuItem *item;
146    NSMenu *submenu;
147    NSMutableDictionary *dict = nil, *subDict = nil, *submenuDict = nil;
148
149    while ( (item = [e nextObject]) != nil) {
150        submenu = [item submenu];
151        if (ICCF_ServiceItemState(item) == NSOffState) {
152            subDict = [ICCF_SERVICE_OPTION_HIDDEN retain];
153        } else if (submenu != nil) {
154            submenuDict = ICCF_RetainedServiceOptionsDictionary(submenu);
155            if (submenuDict == nil)
156                continue;
157            subDict = [[NSDictionary alloc] initWithObjectsAndKeys: submenuDict, kICServiceSubmenu, nil];
158            [submenuDict release];
159        } else continue;
160        if (dict == nil) {
161            dict = [[NSMutableDictionary alloc] init];
162        }
163        [dict setObject: subDict forKey: [item title]];
164        [subDict release];
165    }
166    return dict;
167}
168
169static void ICCF_RestoreServiceOptionsDictionary(NSMenu *menu, NSDictionary *dict) {
170    NSEnumerator *e = [dict keyEnumerator];
171    NSString *itemTitle;
172    NSDictionary *subDict, *submenuDict;
173    NSMenuItem *item;
174    NSMenu *submenu;
175
176    // XXX handle exceptions
177    while ( (itemTitle = [e nextObject]) != nil) {
178        item = (NSMenuItem *)[menu itemWithTitle: itemTitle];
179        if (item == nil) continue;
180        subDict = [dict objectForKey: itemTitle];
181        if ([[subDict objectForKey: (NSString *)kICServiceHidden] boolValue]) {
182            ICCF_SetServiceState(item, ICCF_SERVICE_HIDDEN);
183            ICCF_RemoveKeyEquivalentForItem(item);
184        }
185        if ( (submenu = [item submenu]) != nil) {
186            submenuDict = [subDict objectForKey: (NSString *)kICServiceSubmenu];
187            if ([submenuDict count] == 0)
188                ICCF_PropagateServiceStateChange(submenu, ICCF_SERVICE_HIDDEN);
189            else
190                ICCF_RestoreServiceOptionsDictionary(submenu, submenuDict);
191        }
192    }
193}
194
195static void ICCF_AddServiceKeyEquivalentsAndIcons(NSMenu *menu, NSDictionary *serviceInfo) {
196    if (serviceInfo == nil) return;
197    NSEnumerator *enumerator = [[menu itemArray] objectEnumerator];
198    NSMenuItem *menuItem;
199    NSMenu *submenu;
200    NSDictionary *itemInfo = nil;
201    while ( (menuItem = [enumerator nextObject]) != nil) {
202        itemInfo = [serviceInfo objectForKey: [menuItem title]];
203        if (itemInfo == nil) continue;
204       
205        if ( (submenu = [menuItem submenu]) != nil) {
206            ICCF_AddServiceKeyEquivalentsAndIcons(submenu, [itemInfo objectForKey: (NSString *)kICServiceSubmenu]);
207        } else {
208            NSString *keyEquivalent = (NSString *)[itemInfo objectForKey: (NSString *)kICServiceShortcut];
209            if (keyEquivalent == nil) {
210                keyEquivalent = [userKeyEquivalents objectForKey: [menuItem title]];
211            } else if ([keyEquivalent length] != 1) {
212                keyEquivalent = nil;
213            } else {
214                // XXX Inconsistency between Cocoa and Carbon: always command-shift in Carbon, not in Cocoa.  Since we only patch Cocoa for the moment, keep as is.
215                unichar key = [keyEquivalent characterAtIndex: 0];
216                if ([[NSCharacterSet uppercaseLetterCharacterSet] characterIsMember: key])
217                    keyEquivalent = [NSString stringWithFormat: @"$@%c", key];
218                else
219                    keyEquivalent = [NSString stringWithFormat: @"@%c", key];
220            }
221            if (keyEquivalent != nil) {
222                [menuItem setToolTip: keyEquivalent];
223                NSMutableSet *equivalentItems = (NSMutableSet *)[keyEquivalents objectForKey: keyEquivalent];
224                if (equivalentItems == nil) {
225                    equivalentItems = [[NSMutableSet alloc] initWithObjects: menuItem, nil];
226                    [keyEquivalents setObject: equivalentItems forKey: keyEquivalent];
227                    [equivalentItems release];
228                } else {
229                    [equivalentItems addObject: menuItem];
230                }
231            }
232        }
233
234        NSString *bundlePath = (NSString *)[itemInfo objectForKey: (NSString *)kICServiceBundlePath];
235        if (bundlePath == NULL) continue;
236        IconRef serviceIcon = ICCF_CopyIconRefForPath(bundlePath);
237        if (serviceIcon == NULL) continue;
238        [menuItem _setIconRef: serviceIcon];
239        ReleaseIconRef(serviceIcon);
240    }
241}
242
243@implementation ICeCoffEEServicePrefController
244
245#pragma mark class initialization
246
247+ (void)initialize;
248{
249    ICCF_SERVICE_OPTION_HIDDEN = [[NSDictionary alloc] initWithObjectsAndKeys: [NSNumber numberWithBool: YES], kICServiceHidden, nil];
250}
251
252#pragma mark initialize-release
253
254- (id)initWithParentWindow:(NSWindow *)parent;
255{
256    if ( (self = [self initWithWindowNibName: @"Select services"])) {
257        NSWindow *window = [self window]; // connect outlets
258        [serviceOutline setAutoresizesOutlineColumn: NO];
259       
260        NSButtonCell *checkBoxCell = [[ICeCoffEENonHighlightingButtonCell alloc] init];
261        [checkBoxCell setButtonType: NSSwitchButton];
262        [checkBoxCell setImagePosition: NSImageOnly];
263        [checkBoxCell setAllowsMixedState: YES];
264       
265        [[serviceOutline tableColumnWithIdentifier: @"show"] setDataCell: checkBoxCell];
266        [checkBoxCell release];
267
268        NSTextFieldCell *textFieldCell = [[serviceOutline tableColumnWithIdentifier: @"service"] dataCell];
269        [textFieldCell setWraps: YES];
270        [[serviceOutline tableColumnWithIdentifier: @"service"] setDataCell:
271            [ICeCoffEELabeledIconCell copyFromTextFieldCell: textFieldCell]];
272       
273        textFieldCell = [[serviceOutline tableColumnWithIdentifier: @"key"] dataCell];
274        ((struct objc_object *)textFieldCell)->isa = [ICeCoffEEInvertingTextFieldCell class];
275       
276        [serviceOutline noteNumberOfRowsChanged]; // or we get no active scroll bar or initial selection
277
278        [window setResizeIncrements: NSMakeSize(1, ICCF_TableViewCellHeight(serviceOutline))];
279        if (parent != nil) {
280            [NSApp beginSheet: window modalForWindow: parent modalDelegate: self didEndSelector: nil contextInfo: nil];
281        } else {
282            [window center];
283            [window makeKeyAndOrderFront: nil];
284        }
285    }
286    return self;
287}
288
289- (void)dealloc;
290{
291    [keyEquivalents release]; keyEquivalents = nil;
292    [userKeyEquivalents release]; userKeyEquivalents = nil;
293    [servicesMenu release]; servicesMenu = nil;
294    [closedTriangle release]; closedTriangle = nil;
295    [selectedClosedTriangle release]; selectedClosedTriangle = nil;
296    [openTriangle release]; openTriangle = nil;
297    [selectedOpenTriangle release]; selectedOpenTriangle = nil;
298    [super dealloc];
299}
300
301#pragma mark actions
302
303- (IBAction)showAll:(NSButton *)sender;
304{
305    ICCF_PropagateServiceStateChange(servicesMenu, 0);
306    [serviceOutline reloadData];
307}
308
309- (IBAction)hideAll:(NSButton *)sender;
310{
311    ICCF_PropagateServiceStateChange(servicesMenu, ICCF_SERVICE_HIDDEN);
312    [serviceOutline reloadData];
313}
314
315- (void)closeWithReturnCode:(int)returnCode;
316{
317    if ([[self window] isSheet]) {
318        [NSApp endSheet: [self window] returnCode: NSRunAbortedResponse];
319    }
320    [self close];
321}
322
323- (IBAction)cancel:(NSButton *)sender;
324{
325    [self closeWithReturnCode: NSRunAbortedResponse];
326}
327
328- (IBAction)saveChanges:(NSButton *)sender;
329{
330    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
331    NSMutableDictionary *icDefaults = [[defaults persistentDomainForName: (NSString *)kICBundleIdentifier] mutableCopy];
332    NSDictionary *serviceOptions = ICCF_RetainedServiceOptionsDictionary(servicesMenu);
333    if (serviceOptions != nil) {
334        [icDefaults setObject: serviceOptions forKey: (NSString *)kICServiceOptions];
335        [serviceOptions release];
336    } else {
337        [icDefaults removeObjectForKey: (NSString *)kICServiceOptions];
338    }
339    [defaults setPersistentDomain: icDefaults forName: (NSString *)kICBundleIdentifier];
340    [defaults synchronize];
341    APEMessageBroadcast(kICBundleIdentifier, kICPreferencesChanged, NULL);
342    [icDefaults release];
343    [self closeWithReturnCode: NSRunStoppedResponse];
344}
345
346@end
347
348@implementation ICeCoffEEServicePrefController (NSOutlineViewDataSource)
349
350- (int)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item;
351{
352    if (servicesMenu == nil) {
353        keyEquivalents = [[NSMutableDictionary alloc] init];
354        userKeyEquivalents = [[[NSUserDefaults standardUserDefaults] dictionaryForKey: @"NSUserKeyEquivalents"] retain];
355        servicesMenu = [[NSMenu alloc] initWithTitle: @""];
356        ICCF_SetServicesMenu(servicesMenu);
357        ICCF_AddServiceKeyEquivalentsAndIcons(servicesMenu, ICCF_GetServicesInfo());
358        ICCF_RemoveSingleKeyEquivalents();
359       
360        NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
361        NSDictionary *icDefaults = [defaults persistentDomainForName: (NSString *)kICBundleIdentifier];
362        NSDictionary *serviceOptions = [icDefaults objectForKey: (NSString *)kICServiceOptions];
363        ICCF_RestoreServiceOptionsDictionary(servicesMenu, serviceOptions);
364    }
365    return [(item == nil ? servicesMenu : [item submenu]) numberOfItems];
366}
367
368- (BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item;
369{
370    return (item == nil ? YES : [item submenu] != nil);
371}
372
373- (id)outlineView:(NSOutlineView *)outlineView child:(int)index ofItem:(id)item;
374{
375    return [(item == nil ? servicesMenu : [item submenu]) itemAtIndex: index];
376}
377
378NSAttributedString *ICCF_KeyEquivalentAttributedString(NSString *self, unsigned count);
379
380- (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item;
381{
382    if ([[tableColumn identifier] isEqualToString: @"service"]) {
383        static NSDictionary *attrDict = nil;
384        if (attrDict == nil) { // XXX we leak this, but so does the Apple sample code...
385            NSMutableParagraphStyle *style = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
386            [style setLineBreakMode: NSLineBreakByTruncatingMiddle];
387            attrDict = [[NSDictionary alloc] initWithObjectsAndKeys: style, NSParagraphStyleAttributeName, nil];
388            [style release];
389        }
390        return [[[NSAttributedString alloc] initWithString: [item title] attributes: attrDict] autorelease];
391    } else if ([[tableColumn identifier] isEqualToString: @"show"]) {
392        int state = ICCF_GetServiceState(item);
393        if ([item submenu] != nil && state == ICCF_SERVICE_UNKNOWN) {
394            return [NSNumber numberWithInt: ICCF_PropagateServiceState(item, nil)];
395        }
396        return [NSNumber numberWithInt: ICCF_ServiceItemState(item)];
397    } else if ([[tableColumn identifier] isEqualToString: @"key"]) {
398        NSString *equivalent = [item toolTip];
399        if (equivalent == nil)
400            return nil;
401        return ICCF_KeyEquivalentAttributedString(equivalent, ICCF_CountForKeyEquivalent(equivalent));
402    }
403    return nil;
404}
405
406- (void)outlineView:(NSOutlineView *)outlineView setObjectValue:(id)object forTableColumn:(NSTableColumn *)tableColumn byItem:(id)item;
407{
408    if ([[tableColumn identifier] isEqualToString: @"show"]) {
409        int newState = [object boolValue] ? ICCF_SERVICE_SHOWN : ICCF_SERVICE_HIDDEN;
410        ICCF_UpdateKeyEquivalentForItem(item, newState);
411        ICCF_SetServiceState(item, newState);
412       
413        NSMenu *submenu = [item menu];
414        if (submenu == servicesMenu) {
415            ICCF_PropagateServiceState(item, item);
416        } else {
417            NSMenu *supermenu;
418            while ( (supermenu = [submenu supermenu]) != servicesMenu) {
419                submenu = supermenu;
420            }
421            ICCF_PropagateServiceState((NSMenuItem *)[supermenu itemAtIndex: [supermenu indexOfItemWithSubmenu: submenu]], item);
422        }
423        [outlineView reloadData];
424    }
425}
426
427@end
428
429@implementation ICeCoffEEServicePrefController (NSOutlineViewDelegate)
430
431- (void)outlineView:(NSOutlineView *)outlineView willDisplayCell:(id)cell forTableColumn:(NSTableColumn *)tableColumn item:(id)item;
432{
433    if (![[tableColumn identifier] isEqualToString: @"service"])
434        return;
435    [(ICeCoffEELabeledIconCell *)cell setIconRef: [item _iconRef]];
436}
437
438static NSImage *ICCF_InvertedImage(NSImage *image) {
439    NSImage *invertedImage = [[NSImage alloc] initWithSize: [image size]];
440    NSBitmapImageRep *imageRep = [NSBitmapImageRep imageRepWithData: [image TIFFRepresentation]];
441    CIImage *source = [[CIImage alloc] initWithBitmapImageRep: imageRep];
442    CIColor *black = [[CIColor alloc] initWithColor: [NSColor blackColor]];
443                                                             
444    CIFilter *monochromeFilter = [CIFilter filterWithName: @"CIColorMonochrome"];
445    [monochromeFilter setValue: source forKey: @"inputImage"];
446    [monochromeFilter setValue: [NSNumber numberWithFloat: 1.0] forKey: @"inputIntensity"];
447    [monochromeFilter setValue: black forKey: @"inputColor"];
448   
449    CIFilter *invertFilter = [CIFilter filterWithName: @"CIColorInvert"];
450    [invertFilter setValue: [monochromeFilter valueForKey: @"outputImage"] forKey: @"inputImage"];
451   
452    CIFilter *maskToAlphaFilter = [CIFilter filterWithName: @"CIMaskToAlpha"];
453    [maskToAlphaFilter setValue: [invertFilter valueForKey: @"outputImage"] forKey: @"inputImage"];
454   
455    [invertedImage lockFocus];
456    CIContext *context = [CIContext contextWithCGContext: [[NSGraphicsContext currentContext] graphicsPort]
457                                                 options: nil];
458    CIImage *result = [maskToAlphaFilter valueForKey: @"outputImage"];
459    [context drawImage: result atPoint: CGPointZero fromRect: [result extent]];
460    [invertedImage unlockFocus];
461
462    [source release];
463    [black release];
464
465    return invertedImage;
466}
467
468- (void)outlineView:(NSOutlineView *)outlineView willDisplayOutlineCell:(id)cell forTableColumn:(NSTableColumn *)tableColumn item:(id)item;
469{
470    static BOOL isInverted = NO;
471
472    if (closedTriangle == nil) {
473        closedTriangle = [[cell image] retain];
474        openTriangle = [[cell alternateImage] retain];
475        selectedClosedTriangle = ICCF_InvertedImage(closedTriangle);
476        selectedOpenTriangle = ICCF_InvertedImage(openTriangle);
477    }
478   
479    if (![outlineView isRowSelected: [outlineView rowForItem: item]] ||
480        !ICCF_ViewHasKeyboardFocus(outlineView)) {
481        if (!isInverted)
482            return;
483       
484        [cell setImage: closedTriangle];
485        [cell setAlternateImage: openTriangle];
486        isInverted = NO;
487        return;
488    }
489   
490    // not checking for isInverted is intentional - images reset when triangle is flipped
491    [cell setImage: selectedClosedTriangle];
492    [cell setAlternateImage: selectedOpenTriangle];
493    isInverted = YES;
494}
495
496@end
497
498@implementation ICeCoffEEServicePrefController (NSWindowDelegate)
499
500- (NSRect)windowWillUseStandardFrame:(NSWindow *)sender defaultFrame:(NSRect)defaultFrame;
501{
502    NSWindow *window = [serviceOutline window];
503    NSRect frame = [window frame];
504    NSScrollView *scrollView = [serviceOutline enclosingScrollView];
505    float displayedHeight = [[scrollView contentView] bounds].size.height;
506    float heightChange = [[scrollView documentView] bounds].size.height - displayedHeight;
507    float heightExcess;
508
509    if (heightChange >= 0 && heightChange <= 1) {
510        // either the window is already optimal size, or it's too big
511        float rowHeight = ICCF_TableViewCellHeight(serviceOutline);
512        heightChange = (rowHeight * [serviceOutline numberOfRows]) - displayedHeight;
513    }
514
515    frame.size.height += heightChange;
516
517    if ( (heightExcess = [window minSize].height - frame.size.height) > 1 ||
518         (heightExcess = [window maxSize].height - frame.size.height) < 1) {
519        heightChange += heightExcess;
520        frame.size.height += heightExcess;
521    }
522
523    frame.origin.y -= heightChange;
524
525    return frame;
526}
527
528@end
529
530@implementation ICeCoffEEServicePrefController (NSWindowNotifications)
531
532- (void)windowWillClose:(NSNotification *)notification;
533{
534    [self autorelease];
535}
536
537@end
Note: See TracBrowser for help on using the repository browser.