Updates to support services

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/gui/trunk@3317 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
richard 1998-11-24 15:25:22 +00:00
parent 9ab3c75337
commit d438ecfaed
4 changed files with 1353 additions and 620 deletions

View file

@ -70,6 +70,7 @@ extern NSString *NSEventTrackingRunLoopMode;
id key_window; id key_window;
id main_window; id main_window;
id delegate; id delegate;
id listener;
int window_count; int window_count;
NSMenu *main_menu; NSMenu *main_menu;
NSMenuItem *windows_menu; NSMenuItem *windows_menu;
@ -210,7 +211,9 @@ extern NSString *NSEventTrackingRunLoopMode;
- (void)registerServicesMenuSendTypes:(NSArray *)sendTypes - (void)registerServicesMenuSendTypes:(NSArray *)sendTypes
returnTypes:(NSArray *)returnTypes; returnTypes:(NSArray *)returnTypes;
- (NSMenu *)servicesMenu; - (NSMenu *)servicesMenu;
- (id)servicesProvider;
- (void)setServicesMenu:(NSMenu *)aMenu; - (void)setServicesMenu:(NSMenu *)aMenu;
- (void)setServicesProvider:(id)anObject;
- validRequestorForSendType:(NSString *)sendType - validRequestorForSendType:(NSString *)sendType
returnType:(NSString *)returnType; returnType:(NSString *)returnType;
@ -331,6 +334,11 @@ BOOL NSPerformService(NSString *item, NSPasteboard *pboard);
// //
void NSUpdateDynamicServices(void); void NSUpdateDynamicServices(void);
//
// Register object to handle services requests.
//
void
NSRegisterServicesProvider(id provider, NSString *name);
int NSApplicationMain(int argc, const char **argv); int NSApplicationMain(int argc, const char **argv);

View file

@ -32,6 +32,7 @@
#include <stdio.h> #include <stdio.h>
#include <Foundation/NSArray.h> #include <Foundation/NSArray.h>
#include <Foundation/NSSet.h>
#include <Foundation/NSDictionary.h> #include <Foundation/NSDictionary.h>
#include <Foundation/NSNotification.h> #include <Foundation/NSNotification.h>
#include <Foundation/NSRunLoop.h> #include <Foundation/NSRunLoop.h>
@ -39,14 +40,13 @@
#include <Foundation/NSTimer.h> #include <Foundation/NSTimer.h>
#include <Foundation/NSProcessInfo.h> #include <Foundation/NSProcessInfo.h>
#include <Foundation/NSFileManager.h> #include <Foundation/NSFileManager.h>
#ifndef LIB_FOUNDATION_LIBRARY
#include <Foundation/NSConnection.h> #include <Foundation/NSConnection.h>
#endif #include <Foundation/NSUserDefaults.h>
#include <AppKit/GPSDrawContext.h> #include <AppKit/GPSDrawContext.h>
#include <AppKit/NSApplication.h> #include <AppKit/NSApplication.h>
#include <AppKit/NSPopUpButton.h> #include <AppKit/NSPopUpButton.h>
#include <AppKit/NSPasteboard.h>
#include <AppKit/NSPanel.h> #include <AppKit/NSPanel.h>
#include <AppKit/NSEvent.h> #include <AppKit/NSEvent.h>
#include <AppKit/NSImage.h> #include <AppKit/NSImage.h>
@ -56,9 +56,584 @@
#include <AppKit/IMLoading.h> #include <AppKit/IMLoading.h>
#define CONVEY(a, b) [b retain]; \ extern NSDictionary *GSAllServicesDictionary();
[a release]; \
a = b; /*
* Local class for handling incoming service requests etc.
*/
@interface ApplicationListener : NSObject
{
id servicesProvider;
NSApplication *application;
NSMenu *servicesMenu;
NSMutableArray *languages;
NSMutableSet *returnInfo;
NSMutableDictionary *combinations;
NSMutableDictionary *title2info;
NSArray *menuTitles;
BOOL isRegistered;
}
+ (ApplicationListener*) newWithApplication: (NSApplication*)app;
- (void) doService: (NSCell*)item;
- (BOOL) hasRegisteredTypes: (NSDictionary*)service;
- (NSString*) item2title: (NSCell*)item;
- (void) rebuildServices;
- (void) rebuildServicesMenu;
- (void) registerAsServiceProvider;
- (void) registerSendTypes: (NSArray *)sendTypes
returnTypes: (NSArray *)returnTypes;
- (NSMenu *) servicesMenu;
- (id) servicesProvider;
- (void) setServicesMenu: (NSMenu *)anObject;
- (void) setServicesProvider: (id)anObject;
- (BOOL) validateMenuItem: (NSCell*)item;
- (void) updateServicesMenu;
@end
@implementation ApplicationListener
/*
* Create a new listener for this application.
* Uses NSRegisterServicesProvider() to register itsself as a service
* provider with the applications name so we can handle incoming
* service requests.
*/
+ (ApplicationListener*) newWithApplication: (NSApplication*)app
{
ApplicationListener *listener = [ApplicationListener alloc];
/*
* Don't retain application object - that would reate a cycle.
*/
listener->application = app;
listener->returnInfo = [[NSMutableSet alloc] initWithCapacity: 16];
listener->combinations = [[NSMutableDictionary alloc] initWithCapacity: 16];
return listener;
}
- (void) doService: (NSCell*)item
{
NSString *title = [self item2title: item];
NSDictionary *info = [title2info objectForKey: title];
NSArray *sendTypes = [info objectForKey: @"NSSendTypes"];
NSArray *returnTypes = [info objectForKey: @"NSReturnTypes"];
unsigned i, j;
unsigned es = [sendTypes count];
unsigned er = [returnTypes count];
NSWindow *resp = [[application keyWindow] firstResponder];
id obj = nil;
for (i = 0; i <= es; i++)
{
NSString *sendType;
sendType = (i < es) ? [sendTypes objectAtIndex: i] : nil;
for (j = 0; j <= er; j++)
{
NSString *returnType;
returnType = (j < er) ? [returnTypes objectAtIndex: j] : nil;
obj = [resp validRequestorForSendType: sendType
returnType: returnType];
if (obj != nil)
{
NSPasteboard *pb;
pb = [NSPasteboard pasteboardWithUniqueName];
if ([obj writeSelectionToPasteboard: pb
types: sendTypes] == NO)
{
NSLog(@"object failed to write to pasteboard\n");
}
else if (NSPerformService(title, pb) == NO)
{
NSLog(@"Failed to perform %@\n", title);
}
else if ([obj readSelectionFromPasteboard: pb] == NO)
{
NSLog(@"object failed to read from pasteboard\n");
}
return;
}
}
}
}
- (BOOL) hasRegisteredTypes: (NSDictionary*)service
{
NSArray *sendTypes = [service objectForKey: @"NSSendTypes"];
NSArray *returnTypes = [service objectForKey: @"NSReturnTypes"];
NSString *type;
unsigned i;
/*
* We know that both sendTypes and returnTypes can't be nil since
* make_services has validated the service entry for us.
*/
if (sendTypes == nil || [sendTypes count] == 0)
{
for (i = 0; i < [returnTypes count]; i++)
{
type = [returnTypes objectAtIndex: i];
if ([returnInfo member: type] != nil)
{
return YES;
}
}
}
else if (returnTypes == nil || [returnTypes count] == 0)
{
for (i = 0; i < [sendTypes count]; i++)
{
type = [sendTypes objectAtIndex: i];
if ([combinations objectForKey: type] != nil)
{
return YES;
}
}
}
else
{
for (i = 0; i < [sendTypes count]; i++)
{
NSSet *rset;
type = [sendTypes objectAtIndex: i];
rset = [combinations objectForKey: type];
if (rset != nil)
{
unsigned j;
for (j = 0; j < [returnTypes count]; j++)
{
type = [returnTypes objectAtIndex: j];
if ([rset member: type] != nil)
{
return YES;
}
}
}
}
}
return NO;
}
/*
* Use tag in menu cell to identify slot in menu titles array that
* contains the full title of the service.
* Return nil if this is not one of our service menu cells.
*/
- (NSString*) item2title: (NSCell*)item
{
unsigned pos;
if ([item target] != self)
return nil;
pos = [item tag];
if (pos > [menuTitles count])
return nil;
return [menuTitles objectAtIndex: pos];
}
- (void) dealloc
{
NSRegisterServicesProvider(nil, nil);
[languages release];
[servicesProvider release];
[returnInfo release];
[combinations release];
[title2info release];
[menuTitles release];
[servicesMenu release];
[super dealloc];
}
- forward: (SEL)aSel :(arglist_t)frame
{
NSString *selName = NSStringFromSelector(aSel);
/*
* If the selector matches the correct form for a services request,
* send the message to the services provider - otherwise raise an
* exception to say the method is not implemented.
*/
if ([selName hasSuffix: @":userData:error:"])
return [servicesProvider performv: aSel :frame];
else
return [self notImplemented: aSel];
}
- (void) rebuildServices
{
NSDictionary *services;
NSUserDefaults *defs;
NSMutableArray *newLang;
NSSet *disabled;
NSMutableSet *alreadyFound;
NSMutableDictionary *newServices;
unsigned pos;
/*
* If the application has not yet started up fully and registered us,
* we defer the rebuild intil we are registered. This avoids loads
* of successive rebuilds as responder classes register the types they
* can handle on startup.
*/
if (isRegistered == NO)
return;
defs = [NSUserDefaults standardUserDefaults];
newLang = [[[defs arrayForKey: @"Languages"] mutableCopy] autorelease];
if (newLang == nil)
{
newLang = [NSMutableArray arrayWithCapacity: 1];
}
if ([newLang containsObject: @"default"] == NO)
{
[newLang addObject: @"default"];
}
ASSIGN(languages, newLang);
disabled = [NSSet setWithArray: [defs arrayForKey: @"DisabledServices"]];
services = [GSAllServicesDictionary() objectForKey: @"ByService"];
newServices = [NSMutableDictionary dictionaryWithCapacity: 16];
alreadyFound = [NSMutableSet setWithCapacity: 16];
/*
* Build dictionary of services we can use.
* 1. make sure we make dictionary keyed on preferred menu item language
* 2. don't include entries for services already examined.
* 3. don't include entries for menu items specifically disabled.
* 4. don't include entries for which we have no registered types.
*/
for (pos = 0; pos < [languages count]; pos++)
{
NSDictionary *byLanguage;
byLanguage = [services objectForKey: [languages objectAtIndex: pos]];
if (byLanguage != nil)
{
NSEnumerator *enumerator = [byLanguage keyEnumerator];
NSString *menuItem;
while ((menuItem = [enumerator nextObject]) != nil)
{
NSDictionary *service = [byLanguage objectForKey: menuItem];
if ([alreadyFound member: service] != nil)
continue;
[alreadyFound addObject: service];
if ([disabled member: menuItem] != nil)
continue;
if ([self hasRegisteredTypes: service])
[newServices setObject: service forKey: menuItem];
}
}
}
if ([newServices isEqual: title2info] == NO)
{
NSArray *titles;
ASSIGN(title2info, newServices);
titles = [title2info allKeys];
titles = [titles sortedArrayUsingSelector: @selector(compare:)];
ASSIGN(menuTitles, titles);
[self rebuildServicesMenu];
}
}
- (void) rebuildServicesMenu
{
if (isRegistered && servicesMenu)
{
NSArray *itemArray;
NSMutableSet *keyEquivalents;
unsigned pos;
unsigned loc0;
unsigned loc1;
SEL sel = @selector(doService:);
NSMenu *submenu = nil;
itemArray = [[servicesMenu itemArray] retain];
pos = [itemArray count];
while (pos > 0)
{
[servicesMenu removeItem: [itemArray objectAtIndex: --pos]];
}
[itemArray release];
keyEquivalents = [NSMutableSet setWithCapacity: 4];
for (loc0 = pos = 0; pos < [menuTitles count]; pos++)
{
NSString *title = [menuTitles objectAtIndex: pos];
NSString *equiv = @"";
NSDictionary *info = [title2info objectForKey: title];
NSDictionary *titles;
NSDictionary *equivs;
NSRange r;
unsigned lang;
id<NSMenuItem> item;
/*
* Find the key equivalent corresponding to this menu title
* in the service definition.
*/
titles = [info objectForKey: @"NSMenuItem"];
equivs = [info objectForKey: @"NSKeyEquivalent"];
for (lang = 0; lang < [languages count]; lang++)
{
NSString *language = [languages objectAtIndex: lang];
NSString *t = [titles objectForKey: language];
if ([t isEqual: title])
{
equiv = [equivs objectForKey: language];
}
}
/*
* Make a note that we are using the key equivalent, or
* set to nil if we have already used it in this menu.
*/
if (equiv)
{
if ([keyEquivalents member: equiv] == nil)
{
[keyEquivalents addObject: equiv];
}
else
{
equiv = @"";
}
}
r = [title rangeOfString: @"/"];
if (r.length > 0)
{
NSString *subtitle = [title substringFromIndex: r.location+1];
NSString *parentTitle = [title substringToIndex: r.location];
NSMenu *menu;
item = [servicesMenu itemWithTitle: parentTitle];
if (item == nil)
{
loc1 = 0;
item = [servicesMenu insertItemWithTitle: parentTitle
action: 0
keyEquivalent: @""
atIndex: loc0++];
menu = [[NSMenu alloc] initWithTitle: parentTitle];
[servicesMenu setSubmenu: submenu
forItem: item];
}
else
{
menu = (NSMenu*)[item target];
}
if (menu != submenu)
{
[submenu sizeToFit];
submenu = menu;
}
item = [submenu insertItemWithTitle: subtitle
action: sel
keyEquivalent: equiv
atIndex: loc1++];
[item setTarget: self];
[item setTag: pos];
}
else
{
item = [servicesMenu insertItemWithTitle: title
action: sel
keyEquivalent: equiv
atIndex: loc0++];
[item setTarget: self];
[item setTag: pos];
}
}
[submenu sizeToFit];
[servicesMenu sizeToFit];
[servicesMenu update];
}
}
/*
* Set up connection to listen for incoming service requests.
*/
- (void) registerAsServiceProvider
{
if (isRegistered == NO)
{
NSString *appName;
isRegistered = YES;
[self rebuildServices];
appName = [[[NSProcessInfo processInfo] processName] lastPathComponent];
NSRegisterServicesProvider(self, appName);
}
}
/*
* Register send and return types that an object can handle - we keep
* a note of all the possible combinations -
* 'returnInfo' is a set of all the return types that can be handled
* without a send.
* 'combinations' is a dictionary of all send types, with the assciated
* values being sets of possible return types.
*/
- (void) registerSendTypes: (NSArray *)sendTypes
returnTypes: (NSArray *)returnTypes
{
BOOL didChange = NO;
unsigned i;
for (i = 0; i < [sendTypes count]; i++)
{
NSString *sendType = [sendTypes objectAtIndex: i];
NSMutableSet *returnSet = [combinations objectForKey: sendType];
if (returnSet == nil)
{
returnSet = [NSMutableSet setWithCapacity: [returnTypes count]];
[combinations setObject: returnSet forKey: sendType];
[returnSet addObjectsFromArray: returnTypes];
didChange = YES;
}
else
{
unsigned count = [returnSet count];
[returnSet addObjectsFromArray: returnTypes];
if ([returnSet count] != count)
{
didChange = YES;
}
}
}
i = [returnInfo count];
[returnInfo addObjectsFromArray: returnTypes];
if ([returnInfo count] != i)
{
didChange = YES;
}
if (didChange)
{
[self rebuildServices];
}
}
- (NSMenu*) servicesMenu
{
return servicesMenu;
}
- (id) servicesProvider
{
return servicesProvider;
}
- (void) setServicesMenu: (NSMenu*)aMenu
{
ASSIGN(servicesMenu, aMenu);
[self rebuildServicesMenu];
}
- (void) setServicesProvider: (id)anObject
{
ASSIGN(servicesProvider, anObject);
}
- (BOOL) validateMenuItem: (NSCell*)item
{
NSString *title = [self item2title: item];
NSDictionary *info = [title2info objectForKey: title];
NSArray *sendTypes = [info objectForKey: @"NSSendTypes"];
NSArray *returnTypes = [info objectForKey: @"NSReturnTypes"];
unsigned i, j;
unsigned es = [sendTypes count];
unsigned er = [returnTypes count];
NSWindow *resp = [[application keyWindow] firstResponder];
/*
* If the menu item is not in our map, it must be the cell containing
* a sub-menu - so we see if any cell in the submenu is valid.
*/
if (title == nil)
{
NSMenu *sub = [item target];
if (sub && [sub isKindOfClass: [NSMenu class]])
{
NSArray *a = [sub itemArray];
for (i = 0; i < [a count]; i++)
{
if ([self validateMenuItem: [a objectAtIndex: i]] == YES)
{
return YES;
}
}
}
return NO;
}
/*
* The cell corresponds to one of our services - so we check to see if
* there is anything that can deal with it.
*/
for (i = 0; i <= es; i++)
{
NSString *sendType;
sendType = (i < es) ? [sendTypes objectAtIndex: i] : nil;
for (j = 0; j <= er; j++)
{
NSString *returnType;
returnType = (j < er) ? [returnTypes objectAtIndex: j] : nil;
if ([resp validRequestorForSendType: sendType
returnType: returnType] != nil)
{
return YES;
}
}
}
return NO;
}
- (void) updateServicesMenu
{
if (servicesMenu)
{
NSArray *a = [servicesMenu itemArray];
unsigned i;
for (i = 0; i < [a count]; i++)
{
NSCell *cell = [a objectAtIndex: i];
if ([self validateMenuItem: cell] == YES)
{
[cell setEnabled: YES];
}
}
}
}
@end
// //
// Class variables // Class variables
// //
@ -107,6 +682,7 @@ static id NSApp;
NSDebugLog(@"Begin of NSApplication -init\n"); NSDebugLog(@"Begin of NSApplication -init\n");
listener = [ApplicationListener newWithApplication: self];
window_list = [NSMutableArray new]; // allocate window list window_list = [NSMutableArray new]; // allocate window list
window_count = 1; window_count = 1;
@ -135,25 +711,28 @@ static id NSApp;
{ {
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
NSBundle* mainBundle = [NSBundle mainBundle]; NSBundle* mainBundle = [NSBundle mainBundle];
NSString* resourcePath = [mainBundle resourcePath];
NSString* infoFilePath = [resourcePath
stringByAppendingPathComponent:@"Info-gnustep.plist"];
NSDictionary* infoDict; NSDictionary* infoDict;
NSString* mainModelFile; NSString* mainModelFile;
infoDict = [[NSString stringWithContentsOfFile:infoFilePath] propertyList]; infoDict = [mainBundle infoDictionary];
mainModelFile = [infoDict objectForKey:@"NSMainNibFile"]; mainModelFile = [infoDict objectForKey:@"NSMainNibFile"];
if (mainModelFile && ![mainModelFile isEqual:@""]) if (mainModelFile && ![mainModelFile isEqual:@""])
{ {
if (![GMModel loadIMFile:mainModelFile if (![GMModel loadIMFile:mainModelFile
owner:[NSApplication sharedApplication]]) owner:[NSApplication sharedApplication]])
NSLog (@"Cannot load the main model file '%@", mainModelFile); NSLog(@"Cannot load the main model file '%@'", mainModelFile);
} }
// post notification that // post notification that
// launch will finish // launch will finish
[nc postNotificationName: NSApplicationWillFinishLaunchingNotification [nc postNotificationName: NSApplicationWillFinishLaunchingNotification
object: self]; object: self];
/*
* Register our listener to handle incoming services requests etc.
*/
[listener registerAsServiceProvider];
// finish the launching // finish the launching
// post notification that // post notification that
// launching has finished // launching has finished
@ -167,6 +746,7 @@ NSString* mainModelFile;
// Let ourselves know we // Let ourselves know we
gnustep_gui_app_is_in_dealloc = YES; // are within dealloc gnustep_gui_app_is_in_dealloc = YES; // are within dealloc
[listener release];
[window_list release]; [window_list release];
[event_queue release]; [event_queue release];
[current_event release]; [current_event release];
@ -224,7 +804,8 @@ NSAutoreleasePool* pool;
app_should_quit = NO; app_should_quit = NO;
app_is_running = YES; app_is_running = YES;
do { do
{
pool = [NSAutoreleasePool new]; pool = [NSAutoreleasePool new];
e = [self nextEventMatchingMask: NSAnyEventMask e = [self nextEventMatchingMask: NSAnyEventMask
@ -234,8 +815,10 @@ NSAutoreleasePool* pool;
if (e) if (e)
[self sendEvent: e]; [self sendEvent: e];
if(windows_need_update) // send an update message // send an update message
[self updateWindows]; // to all visible windows // to all visible windows
if (windows_need_update)
[self updateWindows];
[pool release]; [pool release];
} }
@ -267,8 +850,10 @@ NSAutoreleasePool* pool;
switch ([theEvent type]) // determine the event type switch ([theEvent type]) // determine the event type
{ {
case NSPeriodic: // NSApplication traps the case NSPeriodic:
break; // periodic events // NSApplication traps the
// periodic events
break;
case NSKeyDown: case NSKeyDown:
{ {
@ -300,8 +885,10 @@ NSAutoreleasePool* pool;
} }
break; break;
default: // pass all other events to default:
{ // the event's window // pass all other events to
// the event's window
{
NSWindow* window = [theEvent window]; NSWindow* window = [theEvent window];
if (!theEvent) if (!theEvent)
@ -440,29 +1027,44 @@ BOOL match = NO;
}; // in the queue }; // in the queue
} }
- (NSEvent*)_eventMatchingMask:(unsigned int)mask dequeue:(BOOL)flag - (NSEvent*) _eventMatchingMask: (unsigned int)mask
dequeue: (BOOL)flag
{ {
NSEvent* event; // return the next NSEvent* event;
int i, count; // event in the queue int i, count;
BOOL match = NO; // which matches mask BOOL match = NO;
// return the next
// event in the queue
// which matches mask
[self _nextEvent]; [self _nextEvent];
[listener updateServicesMenu];
if ((count = [event_queue count])) // if queue contains // if queue contains
{ // events check them // events check them
if ((count = [event_queue count]))
{
for (i = 0; i < count; i++) for (i = 0; i < count; i++)
{ // Get next event from {
event = [event_queue objectAtIndex:i]; // the events queue // Get next event from
// the events queue
event = [event_queue objectAtIndex:i];
if (mask == NSAnyEventMask) // the any event mask // the any event mask
match = YES; // matches all events // matches all events
if (mask == NSAnyEventMask)
match = YES;
else else
{ {
if (event == null_event) // do not send the null // do not send the null
{ // event // event
if (event == null_event)
{
match = NO; match = NO;
if(flag) // dequeue null event // dequeue null event
{ // if flag is set // if flag is set
if (flag)
{
[event retain]; [event retain];
[event_queue removeObjectAtIndex:i]; [event_queue removeObjectAtIndex:i];
} }
@ -544,23 +1146,31 @@ BOOL match = NO; // which matches mask
default: default:
match = NO; match = NO;
break; break;
} } } }
}
}
if (match) if (match)
{ {
if(flag) // dequeue the event if // dequeue the event if
{ // flag is set // flag is set
if (flag)
{
[event retain]; [event retain];
[event_queue removeObjectAtIndex:i]; [event_queue removeObjectAtIndex:i];
} }
CONVEY(current_event, event); ASSIGN(current_event, event);
return event; // return an event from // return an event from
} // the queue which // the queue which
} // matches the mask // matches the mask
return event;
}
}
} }
// no event in the // no event in the
return nil; // queue matches mask // queue matches mask
return nil;
} }
- (NSEvent*) nextEventMatchingMask: (unsigned int)mask - (NSEvent*) nextEventMatchingMask: (unsigned int)mask
@ -582,8 +1192,10 @@ BOOL done = NO;
if (!expiration) if (!expiration)
expiration = [NSDate distantFuture]; expiration = [NSDate distantFuture];
while (!done) // Not in queue so wait // Not in queue so wait
{ // for next event // for next event
while (!done)
{
NSDate *limitDate, *originalLimitDate; NSDate *limitDate, *originalLimitDate;
NSRunLoop* currentLoop = [NSRunLoop currentRunLoop]; NSRunLoop* currentLoop = [NSRunLoop currentRunLoop];
// Retain the limitDate so that it doesn't get released // Retain the limitDate so that it doesn't get released
@ -610,11 +1222,16 @@ BOOL done = NO;
break; break;
} }
// no need to unhide cursor // no need to unhide cursor
if (!inTrackingLoop) // while in a tracking loop // while in a tracking loop
if (!inTrackingLoop)
{ {
if ([NSCursor isHiddenUntilMouseMoves]) // do so only if we should // do so only if we should
{ // unhide when mouse moves // unhide when mouse moves
NSEventType type = [event type]; // and event is mouse event // and event is mouse event
if ([NSCursor isHiddenUntilMouseMoves])
{
NSEventType type = [event type];
if ((type == NSLeftMouseDown) || (type == NSLeftMouseUp) if ((type == NSLeftMouseDown) || (type == NSLeftMouseUp)
|| (type == NSRightMouseDown) || (type == NSRightMouseUp) || (type == NSRightMouseDown) || (type == NSRightMouseUp)
|| (type == NSMouseMoved)) || (type == NSMouseMoved))
@ -712,7 +1329,8 @@ int i, count;
app_is_hidden = NO; app_is_hidden = NO;
// Bring the key window to // Bring the key window to
[[self keyWindow] makeKeyAndOrderFront:self]; // the front // the front
[[self keyWindow] makeKeyAndOrderFront:self];
} }
- (void)unhideWithoutActivation - (void)unhideWithoutActivation
@ -862,10 +1480,14 @@ NSArray *mi;
[main_menu release]; [main_menu release];
main_menu = aMenu; main_menu = aMenu;
mi = [main_menu itemArray]; // find a menucell with // find a menucell with
j = [mi count]; // the title Windows // the title Windows
windows_menu = nil; // this is the default // this is the default
for (i = 0;i < j; ++i) // windows menu // windows menu
mi = [main_menu itemArray];
j = [mi count];
windows_menu = nil;
for (i = 0;i < j; ++i)
{ {
mc = [mi objectAtIndex:i]; mc = [mi objectAtIndex:i];
if ([[mc stringValue] compare:@"Windows"] == NSOrderedSame) if ([[mc stringValue] compare:@"Windows"] == NSOrderedSame)
@ -932,7 +1554,7 @@ int i;
- (void)setWindowsMenu:aMenu - (void)setWindowsMenu:aMenu
{ {
if (windows_menu) if (windows_menu)
[windows_menu setSubmenu:aMenu]; [windows_menu setTarget:aMenu];
} }
- (void)updateWindowsItem:aWindow - (void)updateWindowsItem:aWindow
@ -942,7 +1564,7 @@ int i;
- (NSMenu *)windowsMenu - (NSMenu *)windowsMenu
{ {
if (windows_menu) if (windows_menu)
return [windows_menu submenu]; return [windows_menu target];
else else
return nil; return nil;
} }
@ -953,18 +1575,31 @@ int i;
- (void) registerServicesMenuSendTypes: (NSArray *)sendTypes - (void) registerServicesMenuSendTypes: (NSArray *)sendTypes
returnTypes: (NSArray *)returnTypes returnTypes: (NSArray *)returnTypes
{ {
[listener registerSendTypes: sendTypes
returnTypes: returnTypes];
} }
- (NSMenu *) servicesMenu - (NSMenu *) servicesMenu
{ {
return nil; return [listener servicesMenu];
}
- (id) servicesProvider
{
return [listener servicesProvider];
} }
- (void) setServicesMenu: (NSMenu *)aMenu - (void) setServicesMenu: (NSMenu *)aMenu
{ {
[listener setServicesMenu: aMenu];
} }
- validRequestorForSendType:(NSString *)sendType - (void) setServicesProvider: (id)anObject
{
[listener setServicesProvider: anObject];
}
- (id) validRequestorForSendType: (NSString *)sendType
returnType: (NSString *)returnType returnType: (NSString *)returnType
{ {
return nil; return nil;
@ -977,6 +1612,10 @@ int i;
// Reporting an exception // Reporting an exception
- (void) reportException: (NSException *)anException - (void) reportException: (NSException *)anException
{ {
if (anException)
{
NSLog(@"reported exception - %@", anException);
}
} }
// //
@ -1177,7 +1816,7 @@ BOOL result = YES;
+ (void)setNullEvent:(NSEvent *)e + (void)setNullEvent:(NSEvent *)e
{ {
CONVEY(null_event, e); ASSIGN(null_event, e);
} }
+ (NSEvent *)getNullEvent; + (NSEvent *)getNullEvent;

View file

@ -59,8 +59,15 @@
#include <Foundation/NSData.h> #include <Foundation/NSData.h>
static NSRange MakeRangeFromAbs(int a1,int a2) // not the same as NSMakeRange! static NSRange MakeRangeFromAbs(int a1,int a2) // not the same as NSMakeRange!
{ if(a1< a2) return NSMakeRange(a1,a2-a1); {
else return NSMakeRange(a2,a1-a2); if (a1 < 0)
a1 = 0;
if (a2 < 0)
a2 = 0;
if (a1 < a2)
return NSMakeRange(a1,a2-a1);
else
return NSMakeRange(a2,a1-a2);
} }
extern BOOL NSEqualRanges(NSRange range1, NSRange range2); // should define in base FIX ME FAR extern BOOL NSEqualRanges(NSRange range1, NSRange range2); // should define in base FIX ME FAR
@ -335,7 +342,17 @@ typedef enum
+ (void)initialize + (void)initialize
{ {
if (self == [NSText class]) if (self == [NSText class])
{ [self setVersion:1]; // Initial version {
NSArray *r;
NSArray *s;
[self setVersion:1]; // Initial version
r = [NSArray arrayWithObjects: NSStringPboardType, nil];
s = [NSArray arrayWithObjects: NSStringPboardType, nil];
[[NSApplication sharedApplication] registerServicesMenuSendTypes: s
returnTypes: r];
} }
} }
@ -407,6 +424,65 @@ typedef enum
nil]; nil];
} }
/*
* Handle enabling/disabling of services menu items.
*/
- (id) validRequestorForSendType: (NSString*)sendType
returnType: (NSString*)returnType
{
if ((!sendType || [sendType isEqual: NSStringPboardType]) &&
(!returnType || [returnType isEqual: NSStringPboardType]))
{
if (([self selectedRange].length || !sendType) &&
([self isEditable] || !returnType))
{
return self;
}
}
return [super validRequestorForSendType: sendType
returnType: returnType];
}
- (BOOL) readSelectionFromPasteboard: (NSPasteboard*)pb
{
NSArray *types;
NSString *string;
NSRange range;
types = [pb types];
if ([types containsObject: NSStringPboardType] == NO)
{
return NO;
}
string = [pb stringForType: NSStringPboardType];
range = [self selectedRange];
[self deleteRange: range backspace: NO];
[self insertText: string];
range.length = [string length];
[self setSelectedRange: range];
return YES;
}
- (BOOL) writeSelectionToPasteboard: (NSPasteboard*)pb
types: (NSArray*)sendTypes
{
NSArray *types;
NSRange range;
NSString *string;
if ([sendTypes containsObject: NSStringPboardType] == NO)
{
return NO;
}
types = [NSArray arrayWithObjects: NSStringPboardType, nil];
[pb declareTypes: types owner: nil];
range = [self selectedRange];
string = [self string];
string = [string substringWithRange: range];
return [pb setString: string forType: NSStringPboardType];
}
// <!> // <!>
// handle font pasteboard as well! // handle font pasteboard as well!

View file

@ -1022,7 +1022,17 @@ NSView *v;
- validRequestorForSendType:(NSString *)sendType - validRequestorForSendType:(NSString *)sendType
returnType:(NSString *)returnType returnType:(NSString *)returnType
{ {
return nil; id result = nil;
if (delegate && [delegate respondsToSelector: _cmd])
result = [delegate validRequestorForSendType: sendType
returnType: returnType];
if (result == nil)
result = [[NSApplication sharedApplication]
validRequestorForSendType: sendType
returnType: returnType];
return result;
} }
// //