mirror of
https://github.com/gnustep/libs-gui.git
synced 2025-06-02 05:20:59 +00:00
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:
parent
9ab3c75337
commit
d438ecfaed
4 changed files with 1353 additions and 620 deletions
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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!
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue