Le 30 oct. 04, à 15:35, Alex Perez a écrit :
This patch builds upon a previous non-behavior-changing patch which I
wrote and Alexander Malmberg comitted this morning on my behalf. For
some background:
NSWorkspace had a private convenience class called _getImageWithName:
which, with the permission of Alexander Malmberg, we moved to NSImage
and renamed to -standardImageWithName: and modified slightly so the
alternate: argument was not necessary (it now intelligently looks for
"ImageName" and then for "common_ImageName" (and anything else for
that matter, like "camaelon_ImageName", if you override the method.)
In any event, What this patch does is enable icon themability. You can
have sets of icons which you can use by simply having a very small
bundle override the -getImageWithName: method.
This patch builds upon the previous one, by making nearly every single
image which was previously loaded directly via NSImage -imageNamed:
"common_ImageName" load with the new convenience NSImage method.
Unless you want your own icon set, you will notice zero behavioral
change.
Everyone, please comment on this...If I don't hear anything negative
from anyone by tuesday or so of next week, I will commit it as-is. It
works on my machine.
Alexander Malmberg, anything you feel you need to add?
Hi Alex,
it's nice to want to improve GNUstep theme support, but I must said I
strongly disagree with your patch.
- in my opinion, the themes support for icons or interface should not be
supported at the GNUstep level but by a separate framework which can
eventually be included in /gnustep/core and built when wanted.
- trying to implement icons themes support without taking in account
interface themes is a waste time because icons themes and interface
themes have a lot in common, and they should be implemented with some
coordination (although two frameworks can be used)
- a correct icons themes support can be tricky to do especially if you
consider the fallback issues or the file types relation (see the icons
vs MIME discussion in the October 2004 FreeDesktop xdg list).
- your patch reimplements something which already exists but in a way
which is worst I think, because to create a theme now you need to write
some code (I never saw a theme engine which involves such requirement) :
nsmappings solution is way more easy (just a file to edit) and can
eventually modified to support exactly what you doing in your code (with
something like GSImagePatternName = "common_*" included at the beginning
of the nsmapping file). Anyway I see with your solution that you want to
allow with extra code what I would call a hack : the possibility to have
theme icons anywhere on your computer, then why not install libraries in
the same way… ;-) it is true that nsmapping doesn't permit that, but
that doesn't mean that your solution is right…
- it gives no facility to support FreeDesktop icons themes.
Well, because you will probably ask what is my solution, here it is:
Icons themes implemented the right way should meet the following
requirements :
- a special folder should exist in ~/GNUstep/Library,
/GNUstep/System/Library, /GNUstep/Local/Library, GNUstep/Network/Library
where you can install themes in the same way you add fonts or whatever
resources.
***
The modified NSImage code :
+ (id) imageNamed: (NSString *)aName
{
NSString *realName = [nsmapping objectForKey: aName];
NSImage *image;
if (realName)
aName = realName;
image = (NSImage*)[nameDict objectForKey: aName];
if (image == nil)
{
NSString *ext;
NSString *path = nil;
NSBundle *main_bundle;
NSArray *array;
NSString *the_name = aName;
// FIXME: This should use [NSBundle pathForImageResource], but
this will
// only allow imageUnfilteredFileTypes.
/* If there is no image with that name, search in the main bundle */
main_bundle = [NSBundle mainBundle];
ext = [aName pathExtension];
if (ext != nil && [ext length] == 0)
{
ext = nil;
}
/* Check if extension is one of the image types */
array = [self imageFileTypes];
if ([array indexOfObject: ext] != NSNotFound)
{
/* Extension is one of the image types so remove from the name */
the_name = [aName stringByDeletingPathExtension];
}
else
{
/* Otherwise extension is not an image type so leave it alone */
the_name = aName;
ext = nil;
}
// Now look for the images in the current application
path = [self _pathForApplicationImageNamed: the_name];
// Now in the system
if (!path)
{
path = [self _pathForSystemImageNamed: the_name];
}
if ([path length] != 0)
{
image = [[self allocWithZone: NSDefaultMallocZone()]
initByReferencingFile: path];
if (image != nil)
{
[image setName: aName];
RELEASE(image); // Retained in dictionary.
image->_flags.archiveByName = YES;
}
return image;
}
}
return image;
}
- (NSString *) _pathForApplicationImageNamed: (NSString *)name
{
NSString *ext = [name pathExtension];
NSString *path;
NSBundle *main_bundle = [NSBundle mainBundle];
if (ext)
{
path = [main_bundle pathForResource: name ofType: ext];
}
else
{
id o, e;
e = [[self fileTypes] objectEnumerator];
while ((o = [e nextObject]))
{
path = [main_bundle pathForResource: name
ofType: o];
if (path != nil && [path length] != 0)
break;
}
}
return path;
}
- (NSString *) _pathForSystemImageNamed: (NSString *)name
{
NSString *ext = [name pathExtension];
NSString *path;
/* If not found then search in system */
if (name)
{
if (ext)
{
path = [NSBundle pathForLibraryResource: the_name
ofType: ext
inDirectory: @"Images"];
}
else
{
id o, e;
e = [array objectEnumerator];
while ((o = [e nextObject]))
{
path = [NSBundle pathForLibraryResource: the_name
ofType: o
inDirectory: @"Images"];
if (path != nil && [path length] != 0)
break;
}
}
return path;
}
***
Now the method rewritten in the theme engine bundle :
NSString *ThemeIconResource = @"ThemeIconResource";
NSString *ThemeInterfaceResource = @"ThemeInterfaceResource";
NSString *ThemeNotDefinedResource = @"ThemeNotDefinedResource";
- (NSString *) _imageNameThemeResource: (NSString *)name
{
// iconResourceNames and interfaceResourceNames are set by loading a
plist like file from
// the system which describe if an image name (system defined) is
associated to an icon
// or an interface image.
if ([iconResourceNames containsObject: name])
{
return ThemeIconResource;
}
else if ([interfaceResourceNames containsObject: name])
{
return ThemeInterfaceResource;
}
return ThemeNotDefinedResource;
}
- (NSString *) _pathForApplicationImageNamed: (NSString *)name
{
NSBundle *main_bundle = [NSBundle mainBundle];
NSString *path;
// We try with the bundle identifier first
path = [self _pathForThemeImageNamed: name application: [main_bundle
bundleIdentifier]];
// If no result, we try with the application name
if (path == nil)
{
path = [self _pathThemeImageNamed: name application: [NSApp
applicationName]];
}
return path;
}
- (NSString *) _pathForSystemImageNamed: (NSString *)name
{
return [self _pathForThemeImageNamed: name application: nil];
}
- (NSString *) _pathForThemeImageNamed: (NSString *)name application:
(BOOL)app
{
NSUserDefaults = [NSUserDefaults standardUserDefaults];
NSString *ext = [name pathExtension];
NSString *path;
NSString *themeResource;
NSString *themeResourceDir;
NSString *themeName;
NSString *baseDir = @"Themes";
if (app == nil)
{
themeResource = [self _imageNameThemeResource: name];
if ([themeResource isEqualToString: ThemeNotDefinedResource])
{
return nil; // May be we should look in the System Images
directory
}
if ([themeResource isEqualToString: ThemeIconResource])
{
themeResourceDir = @"Icons";
}
else if ([themeResource isEqualToString: ThemeInterfaceResource])
{
themeResourceDir = @"Interface";
}
}
else
{
themeResourceDir = @"Icons";
}
themeName = [userDefaults objectForKey: themeResource];
if (app != nil)
{
NSString *applicationThemeName =
[userDefaults objectForKey: [app stringByAppendingString:
@"ThemeIconResource"]];
if (applicationThemeName != nil)
themeName = applicationThemeName;
}
path = [[baseDir stringByAppendingPathComponent: themeName]
stringByAppendingPathComponent: themeResourceDir];
if (app != nil)
{
// App is equal to the bundle identifier or the application name
path = [path stringByAppendingPathComponent: app];
}
if (ext)
{
path = [NSBundle pathForLibraryResource: name
ofType: ext
inDirectory: path];
if (path == nil)
{
path = [NSBundle pathForLibraryResource: name
ofType: ext
inDirectory: @"Images"];
}
}
else
{
id o, e;
NSArray *fileTypes = [self fileTypes];
e = [filesTypes objectEnumerator];
while ((o = [e nextObject]))
{
path = [NSBundle pathForLibraryResource: name
ofType: o
inDirectory: path];
if (path != nil && [path length] != 0)
break;
}
e = [filesTypes objectEnumerator];
while ((o = [e nextObject]))
{
path = [NSBundle pathForLibraryResource: name
ofType: o
inDirectory: @"Images"];
if (path != nil && [path length] != 0)
break;
}
}
return path;
}
--
Quentin Mathé
address@hidden