[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [RFC] [PATCH]: Icon themability patch for -GUI images/icons
From: |
Quentin Mathé |
Subject: |
Re: [RFC] [PATCH]: Icon themability patch for -GUI images/icons |
Date: |
Sun, 31 Oct 2004 00:44:08 +0200 |
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.
- a theme should be loaded only for to the user who chooses to use it
- the icons themes and interface themes should use the same packaging
- the icons themes and interface themes should have the possibility to
override specifics application
An interface theme will be a collection of images used to draw the
widgets (a pixmap theme if you want) and eventually icons, an icon
theme would be an interface theme which contains just icons.
I propose to have the special folder called "Themes".
The theme you want to install should go directly in this folder.
Each theme is subdivided in a folder called "Icons" and a folder called
"Interface" (for the images used by the widgets), the two folders
"Icons" and "Interface" can also contain folders named by applications
bundle identifiers or applications names to have the possibility to
customize applications specific icons or even to have them use a
special interface look.
With defaults, you specify the themes you want to use with the
following keys :
* User domain *
- IconThemeName
- InterfaceThemeName
* Application domain *
- IconThemeName
- InterfaceThemeName
In case of a theme "plop" containing interface and icons where you want
both, you just set IconThemeName="plop" and
InterfaceThemeName="plop".With this solution, you can mix the icons
theme and the interface theme from two different theme packages, you
can even override the icons theme and the interface theme for each
application.
Now here is a basic implementation of it with a modified NSImage class
in a way to make -imageNamed: more modular and easy to override, and a
category to NSImage which would be included in the theme engine (like
Camaelon or whatever).
Well in the code below there is no support for nsmapping files direclty
inside theme packages but it is something which can be added.
***
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
Re: [RFC] [PATCH]: Icon themability patch for -GUI images/icons,
Quentin Mathé <=
Re: [RFC] [PATCH]: Icon themability patch for -GUI images/icons, Alexander Malmberg, 2004/10/31