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

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

Fragile hack 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        ![(ICeCoffEEMenuOutlineView *)outlineView shouldUseActiveHighlight]) {
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.