mirror of
https://github.com/gnustep/libs-gui.git
synced 2025-05-31 19:50:48 +00:00
Major revision of services - all menu services stuff in place now.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/gui/trunk@3363 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
4d64c2187a
commit
15cfd849ba
11 changed files with 1434 additions and 861 deletions
14
ChangeLog
14
ChangeLog
|
@ -1,3 +1,17 @@
|
||||||
|
Tue Dec 1 21:00:00 1998 Richard Frith-Macdonald <richard@brainstorm.co.uk>
|
||||||
|
|
||||||
|
* NSApplication.m: Moved services code out to GNUServiceManager.m
|
||||||
|
* NSPasteboard.m: Moved services code out to GNUServiceManager.m
|
||||||
|
* NSWorkspace.m: Moved services code out to GNUServiceManager.m
|
||||||
|
* GNUServicesManager.m: All services stuff in here - now full
|
||||||
|
implementation of services functions.
|
||||||
|
* GNUServicesManager.h: Header for services manager class.
|
||||||
|
* GNUmakefile: Added services manager stuff
|
||||||
|
* Tools/set_show_service.m: New tool to enable/disable services.
|
||||||
|
* Tools/GNUmakefile: Added set_show_service.m
|
||||||
|
* Tools/dummy.m: More dummy backend functions.
|
||||||
|
* Tools/make_services.m: Update for new directory structure.
|
||||||
|
|
||||||
Tue Dec 1 1998 Felipe A. Rodriguez <far@ix.netcom.com>
|
Tue Dec 1 1998 Felipe A. Rodriguez <far@ix.netcom.com>
|
||||||
|
|
||||||
* NSWindow.m rename windowWithNumber to _windowWithTag per backend
|
* NSWindow.m rename windowWithNumber to _windowWithTag per backend
|
||||||
|
|
80
Headers/gnustep/gui/GNUServicesManager.h
Normal file
80
Headers/gnustep/gui/GNUServicesManager.h
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
/*
|
||||||
|
GNUServicesManager.h
|
||||||
|
|
||||||
|
Copyright (C) 1998 Free Software Foundation, Inc.
|
||||||
|
|
||||||
|
Author: Richard Frith-Macdonald <richard@brainstorm.co.uk>
|
||||||
|
Date: Novemeber 1998
|
||||||
|
|
||||||
|
This file is part of the GNUstep GUI Library.
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Library General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Library General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Library General Public
|
||||||
|
License along with this library; see the file COPYING.LIB.
|
||||||
|
If not, write to the Free Software Foundation,
|
||||||
|
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _GNUstep_H_GNUServicesManager
|
||||||
|
#define _GNUstep_H_GNUServicesManager
|
||||||
|
|
||||||
|
@class NSApplication;
|
||||||
|
@class NSArray;
|
||||||
|
@class NSCell;
|
||||||
|
@class NSMenu;
|
||||||
|
@class NSMutableArray;
|
||||||
|
@class NSMutableDictionary;
|
||||||
|
@class NSMutableSet;
|
||||||
|
@class NSString;
|
||||||
|
@class NSTimer;
|
||||||
|
|
||||||
|
@interface GNUServicesManager : NSObject
|
||||||
|
{
|
||||||
|
NSApplication *application;
|
||||||
|
NSMenu *servicesMenu;
|
||||||
|
NSMutableArray *languages;
|
||||||
|
NSMutableSet *returnInfo;
|
||||||
|
NSMutableDictionary *combinations;
|
||||||
|
NSMutableDictionary *title2info;
|
||||||
|
NSArray *menuTitles;
|
||||||
|
NSString *disabledPath;
|
||||||
|
NSString *servicesPath;
|
||||||
|
NSDate *disabledStamp;
|
||||||
|
NSDate *servicesStamp;
|
||||||
|
NSMutableSet *allDisabled;
|
||||||
|
NSMutableDictionary *allServices;
|
||||||
|
NSTimer *timer;
|
||||||
|
}
|
||||||
|
+ (GNUServicesManager*) newWithApplication: (NSApplication*)app;
|
||||||
|
+ (GNUServicesManager*) manager;
|
||||||
|
- (void) checkServices;
|
||||||
|
- (void) doService: (NSCell*)item;
|
||||||
|
- (BOOL) hasRegisteredTypes: (NSDictionary*)service;
|
||||||
|
- (NSString*) item2title: (NSCell*)item;
|
||||||
|
- (void) loadServices;
|
||||||
|
- (NSDictionary*) menuServices;
|
||||||
|
- (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;
|
||||||
|
- (int) setShowsServicesMenuItem: (NSString*)item to: (BOOL)enable;
|
||||||
|
- (BOOL) validateMenuItem: (NSCell*)item;
|
||||||
|
- (void) updateServicesMenu;
|
||||||
|
@end
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
1073
Source/GNUServicesManager.m
Normal file
1073
Source/GNUServicesManager.m
Normal file
File diff suppressed because it is too large
Load diff
|
@ -106,6 +106,7 @@ NSView.m \
|
||||||
NSWindow.m \
|
NSWindow.m \
|
||||||
NSWorkspace.m \
|
NSWorkspace.m \
|
||||||
TrackingRectangle.m \
|
TrackingRectangle.m \
|
||||||
|
GNUServicesManager.m \
|
||||||
PSMatrix.m \
|
PSMatrix.m \
|
||||||
tiff.m \
|
tiff.m \
|
||||||
externs.m
|
externs.m
|
||||||
|
@ -199,6 +200,7 @@ AppKit/NSWindow.h \
|
||||||
AppKit/NSWorkspace.h \
|
AppKit/NSWorkspace.h \
|
||||||
AppKit/TrackingRectangle.h \
|
AppKit/TrackingRectangle.h \
|
||||||
AppKit/PSMatrix.h \
|
AppKit/PSMatrix.h \
|
||||||
|
AppKit/GNUServiceManager.h \
|
||||||
AppKit/nsimage-tiff.h \
|
AppKit/nsimage-tiff.h \
|
||||||
|
|
||||||
-include GNUmakefile.preamble
|
-include GNUmakefile.preamble
|
||||||
|
|
|
@ -64,641 +64,7 @@
|
||||||
[a release]; \
|
[a release]; \
|
||||||
a = b;
|
a = b;
|
||||||
|
|
||||||
|
#include "GNUServicesManager.h"
|
||||||
//*****************************************************************************
|
|
||||||
//
|
|
||||||
// ApplicationListener
|
|
||||||
//
|
|
||||||
//*****************************************************************************
|
|
||||||
|
|
||||||
extern NSDictionary *GSAllServicesDictionary();
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
if (es == 0)
|
|
||||||
{
|
|
||||||
if (er == 0)
|
|
||||||
{
|
|
||||||
if ([resp validRequestorForSendType: nil
|
|
||||||
returnType: nil] != nil)
|
|
||||||
return YES;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for (j = 0; j < er; j++)
|
|
||||||
{
|
|
||||||
NSString *returnType;
|
|
||||||
|
|
||||||
returnType = [returnTypes objectAtIndex: j];
|
|
||||||
if ([resp validRequestorForSendType: nil
|
|
||||||
returnType: returnType] != nil)
|
|
||||||
return YES;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for (i = 0; i < es; i++)
|
|
||||||
{
|
|
||||||
NSString *sendType;
|
|
||||||
|
|
||||||
sendType = [sendTypes objectAtIndex: i];
|
|
||||||
|
|
||||||
if (er == 0)
|
|
||||||
{
|
|
||||||
if ([resp validRequestorForSendType: sendType
|
|
||||||
returnType: nil] != nil)
|
|
||||||
return YES;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for (j = 0; j < er; j++)
|
|
||||||
{
|
|
||||||
NSString *returnType;
|
|
||||||
|
|
||||||
returnType = [returnTypes objectAtIndex: j];
|
|
||||||
if ([resp validRequestorForSendType: sendType
|
|
||||||
returnType: returnType] != nil)
|
|
||||||
return YES;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void) updateServicesMenu
|
|
||||||
{
|
|
||||||
if (servicesMenu && [[application mainMenu] autoenablesItems])
|
|
||||||
{
|
|
||||||
NSMenuMatrix *menuCells;
|
|
||||||
NSArray *a;
|
|
||||||
unsigned i;
|
|
||||||
NSMenu *mainMenu = [application mainMenu];
|
|
||||||
BOOL found = NO;
|
|
||||||
|
|
||||||
a = [mainMenu itemArray];
|
|
||||||
for (i = 0; i < [a count]; i++)
|
|
||||||
if ([[a objectAtIndex: i] target] == servicesMenu)
|
|
||||||
found = YES;
|
|
||||||
if (found == NO)
|
|
||||||
{
|
|
||||||
NSLog(@"Services menu not in main menu!\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
menuCells = [servicesMenu menuCells];
|
|
||||||
a = [menuCells itemArray];
|
|
||||||
|
|
||||||
for (i = 0; i < [a count]; i++)
|
|
||||||
{
|
|
||||||
NSCell *cell = [a objectAtIndex: i];
|
|
||||||
BOOL wasEnabled = [cell isEnabled];
|
|
||||||
BOOL shouldBeEnabled = [self validateMenuItem: cell];
|
|
||||||
|
|
||||||
if (wasEnabled != shouldBeEnabled)
|
|
||||||
{
|
|
||||||
[cell setEnabled: shouldBeEnabled];
|
|
||||||
[menuCells setNeedsDisplayInRect: [menuCells cellFrameAtRow: i]];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* FIXME - only doing this here 'cos auto-display doesn't work */
|
|
||||||
if ([menuCells needsDisplay])
|
|
||||||
[menuCells display];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@end /* ApplicationListener */
|
|
||||||
|
|
||||||
//*****************************************************************************
|
//*****************************************************************************
|
||||||
//
|
//
|
||||||
|
@ -754,7 +120,7 @@ static id NSApp;
|
||||||
|
|
||||||
NSDebugLog(@"Begin of NSApplication -init\n");
|
NSDebugLog(@"Begin of NSApplication -init\n");
|
||||||
|
|
||||||
listener = [ApplicationListener newWithApplication: self];
|
listener = [GNUServicesManager newWithApplication: self];
|
||||||
window_list = [NSMutableArray new]; // allocate window list
|
window_list = [NSMutableArray new]; // allocate window list
|
||||||
window_count = 1;
|
window_count = 1;
|
||||||
|
|
||||||
|
@ -1609,7 +975,7 @@ int i;
|
||||||
returnTypes: (NSArray *)returnTypes
|
returnTypes: (NSArray *)returnTypes
|
||||||
{
|
{
|
||||||
[listener registerSendTypes: sendTypes
|
[listener registerSendTypes: sendTypes
|
||||||
returnTypes: returnTypes];
|
returnTypes: returnTypes];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSMenu *) servicesMenu
|
- (NSMenu *) servicesMenu
|
||||||
|
|
|
@ -738,177 +738,3 @@ NSGetFileTypes(NSArray *pboardTypes)
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
extern NSDictionary* GSAllServicesDictionary();
|
|
||||||
extern NSDictionary* GSApplicationsDictionary();
|
|
||||||
|
|
||||||
static NSConnection *listener = nil;
|
|
||||||
|
|
||||||
void
|
|
||||||
NSRegisterServicesProvider(id provider, NSString *name)
|
|
||||||
{
|
|
||||||
if (listener)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Ensure there is no previous listener and nothing else using
|
|
||||||
* the given port name.
|
|
||||||
*/
|
|
||||||
[[NSPortNameServer defaultPortNameServer] removePortForName: name];
|
|
||||||
[listener release];
|
|
||||||
}
|
|
||||||
listener = [NSConnection newRegisteringAtName: name
|
|
||||||
withRootObject: provider];
|
|
||||||
[listener retain];
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOL
|
|
||||||
NSPerformService(NSString *serviceItem, NSPasteboard *pboard)
|
|
||||||
{
|
|
||||||
NSUserDefaults *defs;
|
|
||||||
NSArray *languages;
|
|
||||||
NSDictionary *services;
|
|
||||||
NSDictionary *byLanguage;
|
|
||||||
NSDictionary *service;
|
|
||||||
NSString *port;
|
|
||||||
unsigned end;
|
|
||||||
unsigned pos;
|
|
||||||
NSString *timeout;
|
|
||||||
double seconds;
|
|
||||||
NSDate *finishBy;
|
|
||||||
NSString *appPath;
|
|
||||||
id provider;
|
|
||||||
NSConnection *connection;
|
|
||||||
NSString *message;
|
|
||||||
NSString *selName;
|
|
||||||
SEL msgSel;
|
|
||||||
NSString *userData;
|
|
||||||
IMP msgImp;
|
|
||||||
NSString *error = nil;
|
|
||||||
NSDictionary *allServices;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Get language preference array.
|
|
||||||
*/
|
|
||||||
defs = [NSUserDefaults standardUserDefaults];
|
|
||||||
languages = [defs arrayForKey: @"Languages"];
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Get dictionary of menu services from workspace manager.
|
|
||||||
*/
|
|
||||||
allServices = GSAllServicesDictionary();
|
|
||||||
|
|
||||||
services = [allServices objectForKey: @"ByService"];
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Find service information for a service matching the given menu item
|
|
||||||
* Search in language preference order.
|
|
||||||
*/
|
|
||||||
if (languages)
|
|
||||||
end = [languages count];
|
|
||||||
else
|
|
||||||
end = 0;
|
|
||||||
byLanguage = nil;
|
|
||||||
for (pos = 0; pos < end; pos++)
|
|
||||||
{
|
|
||||||
NSString *language = [languages objectAtIndex: pos];
|
|
||||||
|
|
||||||
byLanguage = [services objectForKey: language];
|
|
||||||
if (byLanguage != nil)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (byLanguage == nil)
|
|
||||||
byLanguage = [services objectForKey: @"default"];
|
|
||||||
service = [byLanguage objectForKey: serviceItem];
|
|
||||||
|
|
||||||
if (service == nil)
|
|
||||||
return NO; /* No matching service. */
|
|
||||||
|
|
||||||
port = [service objectForKey: @"NSPortName"];
|
|
||||||
timeout = [service objectForKey: @"NSTimeout"];
|
|
||||||
if (timeout && [timeout floatValue] > 100)
|
|
||||||
{
|
|
||||||
seconds = [timeout floatValue] / 1000.0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
seconds = 30.0;
|
|
||||||
}
|
|
||||||
finishBy = [NSDate dateWithTimeIntervalSinceNow: seconds];
|
|
||||||
appPath = [service objectForKey: @"ServicePath"];
|
|
||||||
userData = [service objectForKey: @"NSUserData"];
|
|
||||||
message = [service objectForKey: @"NSMessage"];
|
|
||||||
selName = [message stringByAppendingString: @":userData:error:"];
|
|
||||||
msgSel = NSSelectorFromString(selName);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If there is no selector - we need to generate one with the
|
|
||||||
* appropriate types.
|
|
||||||
*/
|
|
||||||
if (msgSel == 0)
|
|
||||||
{
|
|
||||||
NSMethodSignature *sig;
|
|
||||||
const char *name;
|
|
||||||
const char *type;
|
|
||||||
|
|
||||||
sig = [NSMethodSignature signatureWithObjCTypes: "v@:@@^@"];
|
|
||||||
type = [sig methodType];
|
|
||||||
name = [selName cString];
|
|
||||||
msgSel = sel_register_typed_name(name, type);
|
|
||||||
}
|
|
||||||
|
|
||||||
provider = [NSConnection rootProxyForConnectionWithRegisteredName: port
|
|
||||||
host: @""];
|
|
||||||
if (provider == nil)
|
|
||||||
{
|
|
||||||
if ([[NSWorkspace sharedWorkspace] launchApplication: appPath] == NO)
|
|
||||||
{
|
|
||||||
return NO; /* Unable to launch. */
|
|
||||||
}
|
|
||||||
|
|
||||||
provider = [NSConnection rootProxyForConnectionWithRegisteredName: port
|
|
||||||
host: @""];
|
|
||||||
while (provider == nil && [finishBy timeIntervalSinceNow] > 1.0)
|
|
||||||
{
|
|
||||||
NSRunLoop *loop = [NSRunLoop currentRunLoop];
|
|
||||||
NSDate *next;
|
|
||||||
|
|
||||||
[NSTimer scheduledTimerWithTimeInterval: 1.0
|
|
||||||
invocation: nil
|
|
||||||
repeats: NO];
|
|
||||||
next = [NSDate dateWithTimeIntervalSinceNow: 5.0];
|
|
||||||
[loop runUntilDate: next];
|
|
||||||
provider = [NSConnection
|
|
||||||
rootProxyForConnectionWithRegisteredName: port
|
|
||||||
host: @""];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (provider == nil)
|
|
||||||
{
|
|
||||||
return NO; /* Unable to contact. */
|
|
||||||
}
|
|
||||||
connection = [(NSDistantObject*)provider connectionForProxy];
|
|
||||||
seconds = [finishBy timeIntervalSinceNow];
|
|
||||||
[connection setRequestTimeout: seconds];
|
|
||||||
[connection setReplyTimeout: seconds];
|
|
||||||
|
|
||||||
msgImp = get_imp(fastClass(provider), msgSel);
|
|
||||||
NS_DURING
|
|
||||||
{
|
|
||||||
(*msgImp)(provider, msgSel, pboard, userData, &error);
|
|
||||||
}
|
|
||||||
NS_HANDLER
|
|
||||||
{
|
|
||||||
[NSException raise: NSPasteboardCommunicationException
|
|
||||||
format: @"%s", [[localException reason] cString]];
|
|
||||||
}
|
|
||||||
NS_ENDHANDLER
|
|
||||||
|
|
||||||
if (error != nil)
|
|
||||||
{
|
|
||||||
NSLog(error);
|
|
||||||
return NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
return YES;
|
|
||||||
}
|
|
||||||
|
|
|
@ -39,18 +39,10 @@
|
||||||
|
|
||||||
#define stringify_it(X) #X
|
#define stringify_it(X) #X
|
||||||
#define prog_path(X,Y) \
|
#define prog_path(X,Y) \
|
||||||
stringify_it(X) "/Tools/" GNUSTEP_TARGET_DIR "/" LIBRARY_COMBO Y
|
stringify_it(X) "/Tools/" GNUSTEP_TARGET_DIR "/" LIBRARY_COMBO
|
||||||
|
|
||||||
static NSDictionary *allServices = nil;
|
|
||||||
static NSDictionary *applications = nil;
|
static NSDictionary *applications = nil;
|
||||||
|
|
||||||
NSDictionary*
|
|
||||||
GSAllServicesDictionary()
|
|
||||||
{
|
|
||||||
if (allServices == nil)
|
|
||||||
[[NSWorkspace sharedWorkspace] findApplications];
|
|
||||||
return allServices;
|
|
||||||
}
|
|
||||||
|
|
||||||
NSDictionary*
|
NSDictionary*
|
||||||
GSApplicationsDictionary()
|
GSApplicationsDictionary()
|
||||||
|
@ -60,20 +52,14 @@ GSApplicationsDictionary()
|
||||||
return applications;
|
return applications;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
NSUpdateDynamicServices()
|
|
||||||
{
|
|
||||||
[[NSWorkspace sharedWorkspace] findApplications];
|
|
||||||
}
|
|
||||||
|
|
||||||
@implementation NSWorkspace
|
@implementation NSWorkspace
|
||||||
|
|
||||||
static NSWorkspace *sharedWorkspace = nil;
|
static NSWorkspace *sharedWorkspace = nil;
|
||||||
static NSNotificationCenter *workspaceCenter = nil;
|
static NSNotificationCenter *workspaceCenter = nil;
|
||||||
static BOOL userDefaultsChanged = NO;
|
static BOOL userDefaultsChanged = NO;
|
||||||
|
|
||||||
static NSString *cacheName = @".GNUstepServices";
|
static NSString *appListName = @".GNUstepAppList";
|
||||||
static NSString *servicesPath = nil;
|
static NSString *appListPath = nil;
|
||||||
|
|
||||||
static NSString* gnustep_target_dir =
|
static NSString* gnustep_target_dir =
|
||||||
#ifdef GNUSTEP_TARGET_DIR
|
#ifdef GNUSTEP_TARGET_DIR
|
||||||
|
@ -130,9 +116,10 @@ static NSString* library_combo =
|
||||||
|
|
||||||
str = [env objectForKey: @"GNUSTEP_USER_ROOT"];
|
str = [env objectForKey: @"GNUSTEP_USER_ROOT"];
|
||||||
if (str == nil)
|
if (str == nil)
|
||||||
str = [NSString stringWithFormat: @"%@/GNUstep", NSHomeDirectory()];
|
str = [NSString stringWithFormat: @"%@/GNUstep/Services",
|
||||||
str = [str stringByAppendingPathComponent: cacheName];
|
NSHomeDirectory()];
|
||||||
servicesPath = [str retain];
|
str = [str stringByAppendingPathComponent: appListName];
|
||||||
|
appListPath = [str retain];
|
||||||
|
|
||||||
if ((str = [env objectForKey: @"GNUSTEP_TARGET_DIR"]) != nil)
|
if ((str = [env objectForKey: @"GNUSTEP_TARGET_DIR"]) != nil)
|
||||||
gnustep_target_dir = [str retain];
|
gnustep_target_dir = [str retain];
|
||||||
|
@ -258,7 +245,7 @@ inFileViewerRootedAtPath:(NSString *)rootFullpath
|
||||||
NSString *last = [appName lastPathComponent];
|
NSString *last = [appName lastPathComponent];
|
||||||
|
|
||||||
if (applications == nil)
|
if (applications == nil)
|
||||||
NSUpdateDynamicServices();
|
[self findApplications];
|
||||||
|
|
||||||
if ([appName isEqual: last])
|
if ([appName isEqual: last])
|
||||||
{
|
{
|
||||||
|
@ -322,21 +309,18 @@ inFileViewerRootedAtPath:(NSString *)rootFullpath
|
||||||
- (void)findApplications
|
- (void)findApplications
|
||||||
{
|
{
|
||||||
NSData *data;
|
NSData *data;
|
||||||
NSDictionary *newServices;
|
NSDictionary *newApps;
|
||||||
NSDictionary *dict;
|
|
||||||
|
|
||||||
system(prog_path(GNUSTEP_INSTALL_PREFIX, "/make_services"));
|
system(prog_path(GNUSTEP_INSTALL_PREFIX, "/make_services"));
|
||||||
|
|
||||||
data = [NSData dataWithContentsOfFile: servicesPath];
|
data = [NSData dataWithContentsOfFile: appListPath];
|
||||||
if (data)
|
if (data)
|
||||||
newServices = [NSDeserializer deserializePropertyListFromData: data
|
newApps = [NSDeserializer deserializePropertyListFromData: data
|
||||||
mutableContainers: NO];
|
mutableContainers: NO];
|
||||||
else
|
else
|
||||||
newServices = [NSDictionary dictionary];
|
newApps = [NSDictionary dictionary];
|
||||||
|
|
||||||
ASSIGN(allServices, newServices);
|
ASSIGN(applications, newApps);
|
||||||
dict = [newServices objectForKey: @"Applications"];
|
|
||||||
ASSIGN(applications, dict);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
|
@ -32,12 +32,13 @@ GNUSTEP_MAKEFILES = $(GNUSTEP_SYSTEM_ROOT)/Makefiles
|
||||||
include $(GNUSTEP_MAKEFILES)/common.make
|
include $(GNUSTEP_MAKEFILES)/common.make
|
||||||
|
|
||||||
# The applications to be compiled
|
# The applications to be compiled
|
||||||
TOOL_NAME = gpbs make_services
|
TOOL_NAME = gpbs make_services set_show_service
|
||||||
SERVICE_NAME = example
|
SERVICE_NAME = example
|
||||||
|
|
||||||
# The source files to be compiled
|
# The source files to be compiled
|
||||||
gpbs_OBJC_FILES = gpbs.m dummy.m
|
gpbs_OBJC_FILES = gpbs.m dummy.m
|
||||||
make_services_OBJC_FILES = make_services.m dummy.m
|
make_services_OBJC_FILES = make_services.m dummy.m
|
||||||
|
set_show_service_OBJC_FILES = set_show_service.m dummy.m
|
||||||
|
|
||||||
example_OBJC_FILES = example.m dummy.m
|
example_OBJC_FILES = example.m dummy.m
|
||||||
|
|
||||||
|
|
|
@ -54,6 +54,22 @@ NSBeep(void)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GSfill() {}
|
||||||
|
void GSsetgray() {}
|
||||||
|
void GSnewpath() {}
|
||||||
|
void GSgrestore() {}
|
||||||
|
void GSrectfill() {}
|
||||||
|
void GSsetlinewidth() {}
|
||||||
|
void GSclosepath() {}
|
||||||
|
void GSshow() {}
|
||||||
|
void GStranslate() {}
|
||||||
|
void GSmoveto() {}
|
||||||
|
void GSgsave() {}
|
||||||
|
void GSlineto() {}
|
||||||
|
void GSstroke() {}
|
||||||
|
void GSrlineto() {}
|
||||||
|
void GSrectclip() {}
|
||||||
|
|
||||||
void NSFrameRect(NSRect aRect)
|
void NSFrameRect(NSRect aRect)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -79,3 +95,15 @@ void NSDrawGroove(NSRect aRect, NSRect clipRect)
|
||||||
@implementation GMUnarchiver
|
@implementation GMUnarchiver
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
@interface NSWindowView : NSObject
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation NSWindowView
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface GPSDrawContext : NSObject
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation GPSDrawContext
|
||||||
|
@end
|
||||||
|
|
||||||
|
|
|
@ -31,13 +31,16 @@
|
||||||
#include <Foundation/NSProcessInfo.h>
|
#include <Foundation/NSProcessInfo.h>
|
||||||
#include <Foundation/NSData.h>
|
#include <Foundation/NSData.h>
|
||||||
#include <Foundation/NSDebug.h>
|
#include <Foundation/NSDebug.h>
|
||||||
|
#include <Foundation/NSDistributedLock.h>
|
||||||
#include <Foundation/NSAutoreleasePool.h>
|
#include <Foundation/NSAutoreleasePool.h>
|
||||||
#include <Foundation/NSSerialization.h>
|
#include <Foundation/NSSerialization.h>
|
||||||
|
|
||||||
static void scanDirectory(NSMutableDictionary *services, NSString *path);
|
static void scanDirectory(NSMutableDictionary *services, NSString *path);
|
||||||
|
static void scanDynamic(NSMutableDictionary *services, NSString *path);
|
||||||
static NSMutableArray *validateEntry(id svcs, NSString* path);
|
static NSMutableArray *validateEntry(id svcs, NSString* path);
|
||||||
static NSMutableDictionary *validateService(NSDictionary *service, NSString* path, unsigned i);
|
static NSMutableDictionary *validateService(NSDictionary *service, NSString* path, unsigned i);
|
||||||
|
|
||||||
|
static NSString *appsName = @".GNUstepAppList";
|
||||||
static NSString *cacheName = @".GNUstepServices";
|
static NSString *cacheName = @".GNUstepServices";
|
||||||
static NSString *infoLoc = @"Resources/Info-gnustep.plist";
|
static NSString *infoLoc = @"Resources/Info-gnustep.plist";
|
||||||
|
|
||||||
|
@ -65,6 +68,7 @@ main(int argc, char** argv)
|
||||||
unsigned index;
|
unsigned index;
|
||||||
BOOL isDir;
|
BOOL isDir;
|
||||||
NSMutableDictionary *fullMap;
|
NSMutableDictionary *fullMap;
|
||||||
|
NSDictionary *oldMap;
|
||||||
|
|
||||||
pool = [NSAutoreleasePool new];
|
pool = [NSAutoreleasePool new];
|
||||||
|
|
||||||
|
@ -132,18 +136,43 @@ main(int argc, char** argv)
|
||||||
}
|
}
|
||||||
|
|
||||||
roots = [NSMutableArray arrayWithCapacity: 3];
|
roots = [NSMutableArray arrayWithCapacity: 3];
|
||||||
|
services = [NSMutableDictionary dictionaryWithCapacity: 200];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Build a list of 'root' directories to search for applications.
|
* Build a list of 'root' directories to search for applications.
|
||||||
* Order is important - later duplicates of services are ignored.
|
* Order is important - later duplicates of services are ignored.
|
||||||
|
*
|
||||||
|
* Make sure that the users 'GNUstep/Services' directory exists.
|
||||||
*/
|
*/
|
||||||
str = [env objectForKey: @"GNUSTEP_USER_ROOT"];
|
str = [env objectForKey: @"GNUSTEP_USER_ROOT"];
|
||||||
if (str != nil)
|
if (str != nil)
|
||||||
usrRoot = str;
|
usrRoot = str;
|
||||||
else
|
else
|
||||||
usrRoot = [NSString stringWithFormat: @"%@/GNUstep", NSHomeDirectory()];
|
usrRoot = [NSString stringWithFormat: @"%@/GNUstep", NSHomeDirectory()];
|
||||||
|
|
||||||
|
mgr = [NSFileManager defaultManager];
|
||||||
|
if (([mgr fileExistsAtPath: usrRoot isDirectory: &isDir] && isDir) == 0)
|
||||||
|
{
|
||||||
|
if ([mgr createDirectoryAtPath: usrRoot attributes: nil] == NO)
|
||||||
|
{
|
||||||
|
NSLog(@"couldn't create %@\n", usrRoot);
|
||||||
|
[pool release];
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
[roots addObject: usrRoot];
|
[roots addObject: usrRoot];
|
||||||
|
|
||||||
|
usrRoot = [usrRoot stringByAppendingPathComponent: @"Services"];
|
||||||
|
if (([mgr fileExistsAtPath: usrRoot isDirectory: &isDir] && isDir) == 0)
|
||||||
|
{
|
||||||
|
if ([mgr createDirectoryAtPath: usrRoot attributes: nil] == NO)
|
||||||
|
{
|
||||||
|
NSLog(@"couldn't create %@\n", usrRoot);
|
||||||
|
[pool release];
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
str = [env objectForKey: @"GNUSTEP_LOCAL_ROOT"];
|
str = [env objectForKey: @"GNUSTEP_LOCAL_ROOT"];
|
||||||
if (str != nil)
|
if (str != nil)
|
||||||
[roots addObject: str];
|
[roots addObject: str];
|
||||||
|
@ -156,14 +185,19 @@ main(int argc, char** argv)
|
||||||
else
|
else
|
||||||
[roots addObject: @"/usr/GNUstep"];
|
[roots addObject: @"/usr/GNUstep"];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Before doing the main scan, we examine the 'Services' directory to
|
||||||
|
* see if any application has registered dynamic services - these take
|
||||||
|
* precedence over any listed in an applications Info_gnustep.plist.
|
||||||
|
*/
|
||||||
|
scanDynamic(services, usrRoot);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* List of directory names to search within each root directory
|
* List of directory names to search within each root directory
|
||||||
* when looking for applications providing services.
|
* when looking for applications providing services.
|
||||||
*/
|
*/
|
||||||
locations = [NSArray arrayWithObjects: @"Apps", @"Library/Services", nil];
|
locations = [NSArray arrayWithObjects: @"Apps", @"Library/Services", nil];
|
||||||
|
|
||||||
services = [NSMutableDictionary dictionaryWithCapacity: 200];
|
|
||||||
|
|
||||||
for (index = 0; index < [roots count]; index++)
|
for (index = 0; index < [roots count]; index++)
|
||||||
{
|
{
|
||||||
NSString *root = [roots objectAtIndex: index];
|
NSString *root = [roots objectAtIndex: index];
|
||||||
|
@ -178,33 +212,57 @@ main(int argc, char** argv)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mgr = [NSFileManager defaultManager];
|
|
||||||
if (([mgr fileExistsAtPath: usrRoot isDirectory: &isDir] && isDir) == 0)
|
|
||||||
{
|
|
||||||
if ([mgr createDirectoryAtPath: usrRoot attributes: nil] == NO)
|
|
||||||
{
|
|
||||||
NSLog(@"couldn't create %@\n", usrRoot);
|
|
||||||
[pool release];
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fullMap = [NSMutableDictionary dictionaryWithCapacity: 5];
|
fullMap = [NSMutableDictionary dictionaryWithCapacity: 5];
|
||||||
[fullMap setObject: services forKey: @"ByPath"];
|
[fullMap setObject: services forKey: @"ByPath"];
|
||||||
[fullMap setObject: serviceMap forKey: @"ByService"];
|
[fullMap setObject: serviceMap forKey: @"ByService"];
|
||||||
[fullMap setObject: filterMap forKey: @"ByFilter"];
|
[fullMap setObject: filterMap forKey: @"ByFilter"];
|
||||||
[fullMap setObject: printMap forKey: @"ByPrint"];
|
[fullMap setObject: printMap forKey: @"ByPrint"];
|
||||||
[fullMap setObject: spellMap forKey: @"BySpell"];
|
[fullMap setObject: spellMap forKey: @"BySpell"];
|
||||||
[fullMap setObject: applicationMap forKey: @"Applications"];
|
|
||||||
|
|
||||||
str = [usrRoot stringByAppendingPathComponent: cacheName];
|
str = [usrRoot stringByAppendingPathComponent: cacheName];
|
||||||
data = [NSSerializer serializePropertyList: fullMap];
|
if ([mgr fileExistsAtPath: str])
|
||||||
if ([data writeToFile: str atomically: YES] == NO)
|
|
||||||
{
|
{
|
||||||
NSLog(@"couldn't write %@\n", str);
|
data = [NSData dataWithContentsOfFile: str];
|
||||||
[pool release];
|
oldMap = [NSDeserializer deserializePropertyListFromData: data
|
||||||
exit(1);
|
mutableContainers: NO];
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
oldMap = nil;
|
||||||
|
}
|
||||||
|
if ([fullMap isEqual: oldMap] == NO)
|
||||||
|
{
|
||||||
|
data = [NSSerializer serializePropertyList: fullMap];
|
||||||
|
if ([data writeToFile: str atomically: YES] == NO)
|
||||||
|
{
|
||||||
|
NSLog(@"couldn't write %@\n", str);
|
||||||
|
[pool release];
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
str = [usrRoot stringByAppendingPathComponent: appsName];
|
||||||
|
if ([mgr fileExistsAtPath: str])
|
||||||
|
{
|
||||||
|
data = [NSData dataWithContentsOfFile: str];
|
||||||
|
oldMap = [NSDeserializer deserializePropertyListFromData: data
|
||||||
|
mutableContainers: NO];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
oldMap = nil;
|
||||||
|
}
|
||||||
|
if ([applicationMap isEqual: oldMap] == NO)
|
||||||
|
{
|
||||||
|
data = [NSSerializer serializePropertyList: applicationMap];
|
||||||
|
if ([data writeToFile: str atomically: YES] == NO)
|
||||||
|
{
|
||||||
|
NSLog(@"couldn't write %@\n", str);
|
||||||
|
[pool release];
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[pool release];
|
[pool release];
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
@ -331,6 +389,54 @@ scanDirectory(NSMutableDictionary *services, NSString *path)
|
||||||
[arp release];
|
[arp release];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
scanDynamic(NSMutableDictionary *services, NSString *path)
|
||||||
|
{
|
||||||
|
NSFileManager *mgr = [NSFileManager defaultManager];
|
||||||
|
NSAutoreleasePool *arp = [NSAutoreleasePool new];
|
||||||
|
NSArray *contents = [mgr directoryContentsAtPath: path];
|
||||||
|
unsigned index;
|
||||||
|
|
||||||
|
for (index = 0; index < [contents count]; index++)
|
||||||
|
{
|
||||||
|
NSString *name = [contents objectAtIndex: index];
|
||||||
|
NSString *infPath;
|
||||||
|
NSDictionary *info;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Ignore anything with a leading dot.
|
||||||
|
*/
|
||||||
|
if ([name hasPrefix: @"."])
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
infPath = [path stringByAppendingPathComponent: name];
|
||||||
|
|
||||||
|
info = [NSDictionary dictionaryWithContentsOfFile: infPath];
|
||||||
|
if (info)
|
||||||
|
{
|
||||||
|
id svcs = [info objectForKey: @"NSServices"];
|
||||||
|
|
||||||
|
if (svcs)
|
||||||
|
{
|
||||||
|
NSMutableArray *entry;
|
||||||
|
|
||||||
|
entry = validateEntry(svcs, infPath);
|
||||||
|
if (entry)
|
||||||
|
{
|
||||||
|
[services setObject: entry forKey: infPath];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
NSLog(@"bad app info - %@\n", infPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[arp release];
|
||||||
|
}
|
||||||
|
|
||||||
static NSMutableArray*
|
static NSMutableArray*
|
||||||
validateEntry(id svcs, NSString *path)
|
validateEntry(id svcs, NSString *path)
|
||||||
{
|
{
|
||||||
|
|
93
Tools/set_show_service.m
Normal file
93
Tools/set_show_service.m
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
/*
|
||||||
|
set_show_servicaes.m
|
||||||
|
|
||||||
|
GNUstep utility to enable or disable a service for the current user.
|
||||||
|
|
||||||
|
Copyright (C) 1998 Free Software Foundation, Inc.
|
||||||
|
|
||||||
|
Author: Richard Frith-Macdonald <richard@brainstorm.co.uk>
|
||||||
|
Date: November 1998
|
||||||
|
|
||||||
|
This file is part of the GNUstep GUI Library.
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Library General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Library General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Library General Public
|
||||||
|
License along with this library; see the file COPYING.LIB.
|
||||||
|
If not, write to the Free Software Foundation,
|
||||||
|
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <Foundation/NSAutoreleasePool.h>
|
||||||
|
#include <Foundation/NSArray.h>
|
||||||
|
#include <Foundation/NSProcessInfo.h>
|
||||||
|
#include <Foundation/NSString.h>
|
||||||
|
#include <AppKit/NSApplication.h>
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char** argv)
|
||||||
|
{
|
||||||
|
NSAutoreleasePool *pool;
|
||||||
|
NSProcessInfo *proc;
|
||||||
|
NSArray *args;
|
||||||
|
unsigned index;
|
||||||
|
|
||||||
|
// [NSObject enableDoubleReleaseCheck: YES];
|
||||||
|
|
||||||
|
pool = [NSAutoreleasePool new];
|
||||||
|
|
||||||
|
proc = [NSProcessInfo processInfo];
|
||||||
|
if (proc == nil)
|
||||||
|
{
|
||||||
|
NSLog(@"unable to get process information!\n");
|
||||||
|
[pool release];
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
args = [proc arguments];
|
||||||
|
|
||||||
|
for (index = 0; index < [args count]; index++)
|
||||||
|
{
|
||||||
|
if ([[args objectAtIndex: index] isEqual: @"--help"])
|
||||||
|
{
|
||||||
|
printf(
|
||||||
|
"set_show_service enables or disables the display of a specified service\n"
|
||||||
|
"item. It's should be in the form 'set_show_services --enable name' or \n"
|
||||||
|
"'set_show_service --disable name' where 'name' is a service name.\n");
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
if ([[args objectAtIndex: index] isEqual: @"--enable"])
|
||||||
|
{
|
||||||
|
if (index >= [args count] - 1)
|
||||||
|
{
|
||||||
|
NSLog(@"No name specified for enable.\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
NSSetShowsServicesMenuItem([args objectAtIndex: ++index], YES);
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
if ([[args objectAtIndex: index] isEqual: @"--disable"])
|
||||||
|
{
|
||||||
|
if (index >= [args count] - 1)
|
||||||
|
{
|
||||||
|
NSLog(@"No name specified for disable.\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
NSSetShowsServicesMenuItem([args objectAtIndex: ++index], NO);
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NSLog(@"Nothing to do.\n");
|
||||||
|
return(1);
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue