1/** <title>NSColor</title>
2
3   <abstract>The colorful color class</abstract>
4
5   Copyright (C) 1996, 1998, 2001, 2002 Free Software Foundation, Inc.
6
7   Author: Scott Christley <scottc@net-community.com>
8   Date: 1996
9   Author: Fred Kiefer <fredkiefer@gmx.de>
10   Date: 2001, 2002
11
12   This file is part of the GNUstep GUI Library.
13
14   This library is free software; you can redistribute it and/or
15   modify it under the terms of the GNU Lesser General Public
16   License as published by the Free Software Foundation; either
17   version 2 of the License, or (at your option) any later version.
18
19   This library is distributed in the hope that it will be useful,
20   but WITHOUT ANY WARRANTY; without even the implied warranty of
21   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
22   Lesser General Public License for more details.
23
24   You should have received a copy of the GNU Lesser General Public
25   License along with this library; see the file COPYING.LIB.
26   If not, see <http://www.gnu.org/licenses/> or write to the
27   Free Software Foundation, 51 Franklin Street, Fifth Floor,
28   Boston, MA 02110-1301, USA.
29*/
30
31#import "config.h"
32#import <Foundation/NSString.h>
33#import <Foundation/NSArchiver.h>
34#import <Foundation/NSDictionary.h>
35#import <Foundation/NSException.h>
36#import <Foundation/NSLock.h>
37#import <Foundation/NSNotification.h>
38#import <Foundation/NSUserDefaults.h>
39#import <Foundation/NSBundle.h>
40#import <Foundation/NSDebug.h>
41#import <Foundation/NSScanner.h>
42
43#import "AppKit/NSBezierPath.h"
44#import "AppKit/NSColor.h"
45#import "AppKit/NSColorList.h"
46#import "AppKit/NSColorSpace.h"
47#import "AppKit/NSPasteboard.h"
48#import "AppKit/NSView.h"
49#import "AppKit/NSImage.h"
50#import "AppKit/NSGraphics.h"
51#import "AppKit/PSOperators.h"
52#import "GNUstepGUI/GSTheme.h"
53#import "GSGuiPrivate.h"
54
55static Class	NSColorClass;
56
57/* This interface must be provided in NSColorList to let us manage
58 * system colors.
59 */
60@interface NSColorList (GNUstepPrivate)
61+ (void) _setDefaultSystemColorList: (NSColorList*)aList;
62+ (void) _setThemeSystemColorList: (NSColorList*)aList;
63@end
64
65
66@interface GSNamedColor : NSColor
67{
68  NSString *_catalog_name;
69  NSString *_color_name;
70  NSString *_cached_name_space;
71  NSColor *_cached_color;
72}
73
74- (NSColor*) initWithCatalogName: (NSString *)listName
75		       colorName: (NSString *)colorName;
76- (void) recache;
77
78@end
79
80@interface GSWhiteColor : NSColor
81{
82  CGFloat _white_component;
83  CGFloat _alpha_component;
84}
85
86@end
87
88@interface GSDeviceWhiteColor : GSWhiteColor
89
90- (NSColor*) initWithDeviceWhite: (CGFloat)white
91			   alpha: (CGFloat)alpha;
92
93@end
94
95@interface GSCalibratedWhiteColor : GSWhiteColor
96
97- (NSColor*) initWithCalibratedWhite: (CGFloat)white
98			       alpha: (CGFloat)alpha;
99
100@end
101
102@interface GSDeviceCMYKColor : NSColor
103{
104  CGFloat _cyan_component;
105  CGFloat _magenta_component;
106  CGFloat _yellow_component;
107  CGFloat _black_component;
108  CGFloat _alpha_component;
109}
110
111- (NSColor*) initWithDeviceCyan: (CGFloat)cyan
112			magenta: (CGFloat)magenta
113			 yellow: (CGFloat)yellow
114			  black: (CGFloat)black
115			  alpha: (CGFloat)alpha;
116
117@end
118
119@interface GSRGBColor : NSColor
120{
121  CGFloat _red_component;
122  CGFloat _green_component;
123  CGFloat _blue_component;
124  CGFloat _hue_component;
125  CGFloat _saturation_component;
126  CGFloat _brightness_component;
127  CGFloat _alpha_component;
128}
129
130@end
131
132@interface GSDeviceRGBColor : GSRGBColor
133
134- (NSColor*) initWithDeviceRed: (CGFloat)red
135			 green: (CGFloat)green
136			  blue: (CGFloat)blue
137			 alpha: (CGFloat)alpha;
138- (NSColor*) initWithDeviceHue: (CGFloat)hue
139		    saturation: (CGFloat)saturation
140		    brightness: (CGFloat)brightness
141			 alpha: (CGFloat)alpha;
142
143@end
144
145@interface GSCalibratedRGBColor : GSRGBColor
146
147- (NSColor*) initWithCalibratedRed: (CGFloat)red
148			     green: (CGFloat)green
149			      blue: (CGFloat)blue
150			     alpha: (CGFloat)alpha;
151- (NSColor*) initWithCalibratedHue: (CGFloat)hue
152			saturation: (CGFloat)saturation
153			brightness: (CGFloat)brightness
154			     alpha: (CGFloat)alpha;
155@end
156
157// FIXME: This is not described in the specification
158@interface GSPatternColor : NSColor
159{
160  NSImage *_pattern;
161}
162
163- (NSColor*) initWithPatternImage: (NSImage*) pattern;
164
165@end
166
167@interface NSColor (GNUstepPrivate)
168
169+ (NSColor*) colorFromString: (NSString*)string;
170+ (void) defaultsDidChange: (NSNotification*)notification;
171+ (void) themeDidActivate: (NSNotification*)notification;
172
173@end
174
175// Class variables
176static BOOL gnustep_gui_ignores_alpha = YES;
177static NSColorList		*systemColors = nil;
178static NSColorList		*defaultSystemColors = nil;
179static NSMutableDictionary	*colorStrings = nil;
180static NSMutableDictionary	*systemDict = nil;
181
182static
183void initSystemColors(void)
184{
185  NSString *white;
186  NSString *lightGray;
187  NSString *gray;
188  NSString *darkGray;
189  NSString *black;
190  NSString *lightYellow;
191
192  // Set up a dictionary containing the names of all the system colors
193  // as keys and with colors in string format as values.
194  white = [NSString stringWithFormat: @"%g %g %g",
195		    (double)NSWhite, (double)NSWhite, (double)NSWhite];
196  lightGray = [NSString stringWithFormat: @"%g %g %g",
197			(double)NSLightGray, (double)NSLightGray, (double)NSLightGray];
198  gray = [NSString stringWithFormat: @"%g %g %g",
199		   (double)NSGray, (double)NSGray, (double)NSGray];
200  darkGray = [NSString stringWithFormat: @"%g %g %g",
201		       (double)NSDarkGray, (double)NSDarkGray, (double)NSDarkGray];
202  black = [NSString stringWithFormat: @"%g %g %g",
203		    (double)NSBlack, (double)NSBlack, (double)NSBlack];
204  lightYellow = @"1.0 1.0 0.9";
205
206  colorStrings = [[NSMutableDictionary alloc]
207		     initWithObjectsAndKeys:
208		     black, @"alternateSelectedControlColor",
209		     white, @"alternateSelectedControlTextColor",
210		     lightGray, @"controlBackgroundColor",
211		     lightGray, @"controlColor",
212		     black, @"controlDarkShadowColor",
213		     lightGray, @"controlHighlightColor",
214		     white, @"controlLightHighlightColor",
215		     darkGray, @"controlShadowColor",
216		     black, @"controlTextColor",
217		     darkGray, @"disabledControlTextColor",
218		     gray, @"gridColor",
219		     lightGray, @"headerColor",
220		     black, @"headerTextColor",
221		     white, @"highlightColor",
222		     black, @"keyboardFocusIndicatorColor",
223		     lightGray, @"knobColor",
224		     black, @"labelColor",
225		     black, @"quaternaryLabelColor",
226		     gray, @"scrollBarColor",
227		     black, @"secondaryLabelColor",
228		     lightGray, @"secondarySelectedControlColor",
229		     white, @"selectedControlColor",
230		     black, @"selectedControlTextColor",
231		     lightGray, @"selectedKnobColor",
232		     white, @"selectedMenuItemColor",
233		     black, @"selectedMenuItemTextColor",
234		     lightGray, @"selectedTextBackgroundColor",
235		     black, @"selectedTextColor",
236		     black, @"shadowColor",
237		     black, @"tertiaryLabelColor",
238		     white, @"textBackgroundColor",
239		     black, @"textColor",
240		     lightGray, @"windowBackgroundColor",
241		     black, @"windowFrameColor",
242		     white, @"windowFrameTextColor",
243
244		     white, @"rowBackgroundColor",
245		     lightGray, @"alternateRowBackgroundColor",
246
247		     lightYellow, @"toolTipColor",
248		     black, @"toolTipTextColor",
249
250		     nil];
251
252  systemColors = RETAIN([NSColorList colorListNamed: @"System"]);
253  defaultSystemColors = [[NSColorList alloc] initWithName: @"System"];
254  [NSColorList _setDefaultSystemColorList: defaultSystemColors];
255  if (systemColors == nil)
256    {
257      ASSIGN(systemColors, defaultSystemColors);
258    }
259
260    {
261      NSEnumerator *enumerator;
262      NSString *key;
263
264      // Set up default system colors
265
266      enumerator = [colorStrings keyEnumerator];
267
268      while ((key = (NSString *)[enumerator nextObject]))
269	{
270	  NSColor *color;
271
272	  if ((color = [systemColors colorWithKey: key]) == nil)
273	    {
274	      NSString	*aColorString;
275
276	      aColorString = [colorStrings objectForKey: key];
277	      color = [NSColorClass colorFromString: aColorString];
278
279	      NSCAssert1(color, @"couldn't get default system color %@", key);
280	      [systemColors setColor: color forKey: key];
281	    }
282	  if (defaultSystemColors != systemColors)
283	    {
284	      [defaultSystemColors setColor: color forKey: key];
285	    }
286	}
287    }
288
289  systemDict = [NSMutableDictionary new];
290}
291
292static NSColor*
293systemColorWithName(NSString *name)
294{
295  NSColor	*col = [systemDict objectForKey: name];
296
297  if (col == nil)
298    {
299      col = [NSColor colorWithCatalogName: @"System" colorName: name];
300      [systemDict setObject: col forKey: name];
301    }
302
303  return col;
304}
305
306/**
307 *<p>TODO NSColor description</p>
308 *
309 */
310@implementation NSColor
311
312//
313// Class methods
314//
315+ (void) initialize
316{
317  if (self == [NSColor class])
318    {
319      NSColorClass = self;
320
321      // Set the version number
322      [self setVersion: 3];
323
324      // ignore alpha by default
325      gnustep_gui_ignores_alpha = YES;
326
327      // Load or define the system colour list
328      initSystemColors();
329
330      // ensure user defaults are loaded, then use them and watch for changes.
331      [self defaultsDidChange: nil];
332      [[NSNotificationCenter defaultCenter]
333	addObserver: self
334	selector: @selector(defaultsDidChange:)
335	name: NSUserDefaultsDidChangeNotification
336	object: nil];
337      // watch for themes which may provide new system color lists
338      [[NSNotificationCenter defaultCenter]
339	addObserver: self
340	selector: @selector(themeDidActivate:)
341	name: GSThemeDidActivateNotification
342	object: nil];
343    }
344}
345
346/**<p>Creates and returns a new NSColor in a NSCalibratedRGBColorSpace space
347   name, with hue, saturation, brightness and alpha as specified. Valid values
348   are the range 0.0 to 1.0. Out of range values will be clipped.</p>
349*/
350+ (NSColor*) colorWithCalibratedHue: (CGFloat)hue
351			 saturation: (CGFloat)saturation
352			 brightness: (CGFloat)brightness
353			      alpha: (CGFloat)alpha
354{
355  id color;
356
357  color = [GSCalibratedRGBColor allocWithZone: NSDefaultMallocZone()];
358  color = [color initWithCalibratedHue: hue
359		 saturation: saturation
360		 brightness: brightness
361		 alpha: alpha];
362
363  return AUTORELEASE(color);
364}
365
366
367/**<p>Creates and returns a new NSColor in a NSCalibratedRGBColorSpace space
368   name, with red, green, blue and alpha as specified. Valid values
369   are the range 0.0 to 1.0. Out of range values will be clipped.</p>
370*/
371+ (NSColor*) colorWithCalibratedRed: (CGFloat)red
372			      green: (CGFloat)green
373			       blue: (CGFloat)blue
374			      alpha: (CGFloat)alpha
375{
376  id color;
377
378  color = [GSCalibratedRGBColor allocWithZone: NSDefaultMallocZone()];
379  color = [color initWithCalibratedRed: red
380		 green: green
381		 blue: blue
382		 alpha: alpha];
383  return AUTORELEASE(color);
384}
385
386
387/**<p>Creates and returns a new NSColor in a NSCalibratedWhiteColorSpace space
388   name, with red, green, blue and alpha as specified. Valid values
389   are the range 0.0 to 1.0. Out of range values will be clipped.</p>
390*/
391+ (NSColor*) colorWithCalibratedWhite: (CGFloat)white
392				alpha: (CGFloat)alpha
393{
394  id color;
395
396  color = [GSCalibratedWhiteColor allocWithZone: NSDefaultMallocZone()] ;
397  color = [color initWithCalibratedWhite: white
398		 alpha: alpha];
399
400  return AUTORELEASE(color);
401}
402
403/**
404 * <p> TODO </p>
405 */
406+ (NSColor*) colorWithCatalogName: (NSString *)listName
407			colorName: (NSString *)colorName
408{
409  id color;
410
411  color = [GSNamedColor allocWithZone: NSDefaultMallocZone()] ;
412  color = [color initWithCatalogName: listName
413		 colorName: colorName];
414
415  return AUTORELEASE(color);
416}
417
418/**<p>Creates and returns a new NSColor in a NSDeviceCMYKColorSpace space
419   name, with cyan, magenta, yellow, black and alpha as specified. Valid values
420   are the range 0.0 to 1.0. Out of range values will be clipped.</p>
421*/
422+ (NSColor*) colorWithDeviceCyan: (CGFloat)cyan
423			 magenta: (CGFloat)magenta
424			  yellow: (CGFloat)yellow
425			   black: (CGFloat)black
426			   alpha: (CGFloat)alpha
427{
428  id color;
429
430  color = [GSDeviceCMYKColor allocWithZone: NSDefaultMallocZone()];
431  color = [color initWithDeviceCyan: cyan
432		 magenta: magenta
433		 yellow: yellow
434		 black: black
435		 alpha: alpha];
436
437  return AUTORELEASE(color);
438}
439
440
441/**<p>Creates and returns a new NSColor in a NSDeviceCMYKColorSpace space
442   name, with hue, saturation, brightness and alpha as specified. Valid values
443   are the range 0.0 to 1.0. Out of range values will be clipped.</p>
444*/
445+ (NSColor*) colorWithDeviceHue: (CGFloat)hue
446		     saturation: (CGFloat)saturation
447		     brightness: (CGFloat)brightness
448			  alpha: (CGFloat)alpha
449{
450  id color;
451
452  color = [GSDeviceRGBColor allocWithZone: NSDefaultMallocZone()];
453  color = [color initWithDeviceHue: hue
454		 saturation: saturation
455		 brightness: brightness
456		 alpha: alpha];
457
458  return AUTORELEASE(color);
459}
460
461/**<p>Creates and returns a new NSColor in a NSDeviceCMYKColorSpace space
462   name, with red, green, blue and alpha as specified. Valid values
463   are the range 0.0 to 1.0. Out of range values will be clipped.</p>
464*/
465+ (NSColor*) colorWithDeviceRed: (CGFloat)red
466			  green: (CGFloat)green
467			   blue: (CGFloat)blue
468			  alpha: (CGFloat)alpha
469{
470  id color;
471
472  color = [GSDeviceRGBColor allocWithZone: NSDefaultMallocZone()];
473  color = [color initWithDeviceRed: red
474		 green: green
475		 blue: blue
476		 alpha: alpha];
477
478  return AUTORELEASE(color);
479}
480
481/**<p>Creates and returns a new NSColor in a  NSDeviceWhiteColorSpace space
482   name, with red, green, blue and alpha as specified. Valid values
483   are the range 0.0 to 1.0. Out of range values will be clipped.</p>
484*/
485+ (NSColor*) colorWithDeviceWhite: (CGFloat)white
486			    alpha: (CGFloat)alpha
487{
488  id color;
489
490  color = [GSDeviceWhiteColor allocWithZone: NSDefaultMallocZone()];
491  color = [color initWithDeviceWhite: white
492		 alpha: alpha];
493
494  return AUTORELEASE(color);
495}
496
497+ (NSColor*) colorForControlTint: (NSControlTint)controlTint
498{
499  switch (controlTint)
500    {
501      default:
502      case NSDefaultControlTint:
503        return [self colorForControlTint: [self currentControlTint]];
504      case NSGraphiteControlTint:
505        // FIXME
506      case NSClearControlTint:
507        // FIXME
508      case NSBlueControlTint:
509        return [NSColor blueColor];
510    }
511}
512
513+ (NSControlTint) currentControlTint
514{
515  // FIXME: should be made a system setting
516  return NSBlueControlTint;
517}
518
519+ (NSColor*) colorWithPatternImage: (NSImage*)image
520{
521  id color;
522
523  color = [GSPatternColor allocWithZone: NSDefaultMallocZone()];
524  color = [color initWithPatternImage: image];
525
526  return AUTORELEASE(color);
527}
528
529
530/**<p>Returns a NSColor in a NSCalibratedWhiteColorSpace space name.
531  with white and alpha values set as NSBlack and 1.0 respectively.</p>
532  <p>See Also : +colorWithCalibratedWhite:alpha:</p>
533*/
534+ (NSColor*) blackColor
535{
536  return [self colorWithCalibratedWhite: NSBlack alpha: 1.0];
537}
538
539
540/**<p>Returns an NSColor in a  NSCalibratedRGBColorSpace space name.
541  with red, green, blue and alpha values set as 0.0, 0.0, 1.0 and 1.0
542  respectively.</p><p>See Also : +colorWithCalibratedRed:green:blue:alpha:</p>
543*/
544+ (NSColor*) blueColor
545{
546  return [self colorWithCalibratedRed: 0.0
547			        green: 0.0
548				 blue: 1.0
549			        alpha: 1.0];
550}
551
552/**<p>Returns a NSColor in a NSCalibratedRGBColorSpace space name.
553  with red, green, blue and alpha values set as 0.6, 0.4, 0.2 and 1.0
554  respectively.</p><p>See Also: +colorWithCalibratedRed:green:blue:alpha:</p>
555*/
556+ (NSColor*) brownColor
557{
558  return [self colorWithCalibratedRed: 0.6
559			        green: 0.4
560				 blue: 0.2
561			        alpha: 1.0];
562}
563
564/**<p>Returns a NSColor in a NSCalibratedWhiteColorSpace space name.
565  with white and alpha values set as 0.0 and 1.0 respectively.</p>
566  <p>See Also : +colorWithCalibratedWhite:alpha:</p>
567*/
568+ (NSColor*) clearColor
569{
570  return [self colorWithCalibratedWhite: 0.0 alpha: 0.0];
571}
572
573
574/**<p>Returns a NSColor in a NSCalibratedRGBColorSpace space name.
575  with red, green, blue and alpha values set as 0.0, 1.0, 1.0 and 1.0
576  respectively.</p><p>See Also : +colorWithCalibratedRed:green:blue:alpha:</p>
577*/
578+ (NSColor*) cyanColor
579{
580  return [self colorWithCalibratedRed: 0.0
581			        green: 1.0
582				 blue: 1.0
583			        alpha: 1.0];
584}
585
586/**<p>Returns a NSColor in a NSCalibratedWhiteColorSpace space name.
587  with white and alpha values set as NSDarkGray and 1.0 respectively. </p>
588  <p>See Also : +colorWithCalibratedWhite:alpha:</p>
589*/
590+ (NSColor*) darkGrayColor
591{
592  return [self colorWithCalibratedWhite: NSDarkGray alpha: 1.0];
593}
594
595/**<p>Returns a NSColor in a NSCalibratedWhiteColorSpace space name.
596  with white and alpha values set as NSGray and 1.0 respectively. </p>
597  <p>See Also: +colorWithCalibratedWhite:alpha:</p>
598*/
599+ (NSColor*) grayColor
600{
601  return [self colorWithCalibratedWhite: NSGray alpha: 1.0];
602}
603
604/**<p>Returns a NSColor in a  NSCalibratedRGBColorSpace space name.
605  with red, green, blue and alpha values set as 0.0, 1.0, 0.0 and 1.0
606  respectively </p><p>See Also: +colorWithCalibratedRed:green:blue:alpha:</p>
607*/
608+ (NSColor*) greenColor
609{
610  return [self colorWithCalibratedRed: 0.0
611			        green: 1.0
612				 blue: 0.0
613			        alpha: 1.0];
614}
615
616/**<p>Returns a NSColor in a NSCalibratedWhiteColorSpace space name.
617  with white and alpha values set as NSLightGray and 1.0 respectively </p>
618  <p>See Also : +colorWithCalibratedRed:green:blue:alpha:</p>
619*/
620+ (NSColor*) lightGrayColor
621{
622  return [self colorWithCalibratedWhite: NSLightGray alpha: 1];
623}
624
625/**<p>Returns a NSColor in a NSCalibratedRGBColorSpace space name.
626  with red, green, blue and alpha values set as 1.0, 0.0, 1.0 and 1.0
627  respectively.</p><p>See Also : +colorWithCalibratedRed:green:blue:alpha:</p>
628*/
629+ (NSColor*) magentaColor
630{
631  return [self colorWithCalibratedRed: 1.0
632			        green: 0.0
633				 blue: 1.0
634			        alpha: 1.0];
635}
636
637
638/**<p>Returns a NSColor in a NSCalibratedRGBColorSpace space name.
639  with red, green, blue and alpha values set as 1.0, 0.5, 0.0 and 1.0
640  respectively.</p><p>See Also: +colorWithCalibratedRed:green:blue:alpha:</p>
641*/
642+ (NSColor*) orangeColor
643{
644  return [self colorWithCalibratedRed: 1.0
645			        green: 0.5
646				 blue: 0.0
647			        alpha: 1.0];
648}
649
650
651/**<p>Returns a NSColor in a NSCalibratedRGBColorSpace space name.
652  with red, green, blue and alpha values set as 0.5, 0.0, 0.5 and 1.0
653  respectively.</p><p>See Also : +colorWithCalibratedRed:green:blue:alpha:</p>
654*/
655+ (NSColor*) purpleColor
656{
657  return [self colorWithCalibratedRed: 0.5
658			        green: 0.0
659				 blue: 0.5
660			        alpha: 1.0];
661}
662
663
664/**<p>Returns a NSColor in a NSCalibratedRGBColorSpace space name.
665  with red, green, blue and alpha values set as 1.0, 0.0, 0.0 and 1.0
666  respectively </p><p>See Also: +colorWithCalibratedRed:green:blue:alpha:</p>
667*/
668+ (NSColor*) redColor
669{
670  return [self colorWithCalibratedRed: 1.0
671			        green: 0.0
672				 blue: 0.0
673			        alpha: 1.0];
674}
675
676/**<p>Returns a NSColor in a NSCalibratedWhiteColorSpace space name.
677  with white and alpha values set as NSWhite and 1.0 respectively. </p>
678  <p>See Also : +colorWithCalibratedWhite:alpha:</p>
679*/
680+ (NSColor*) whiteColor
681{
682  return [self colorWithCalibratedWhite: NSWhite alpha: 1.0];
683}
684
685
686/**<p>Returns a NSColor in a NSCalibratedRGBColorSpace space name.
687  with red, green, blue and alpha values set as 1.0, 0.0, 0.0 and 1.0
688  respectively.</p><p>See Also : +colorWithCalibratedRed:green:blue:alpha:</p>
689*/
690+ (NSColor*) yellowColor
691{
692  return [self colorWithCalibratedRed: 1.0
693			        green: 1.0
694				 blue: 0.0
695			        alpha: 1.0];
696}
697
698
699/** Returns whether TODO
700 *<p>See Also: +setIgnoresAlpha:</p>
701 */
702+ (BOOL) ignoresAlpha
703{
704  return gnustep_gui_ignores_alpha;
705}
706
707/** TODO
708 *<p>See Also: +ignoresAlpha</p>
709 */
710+ (void) setIgnoresAlpha: (BOOL)flag
711{
712  gnustep_gui_ignores_alpha = flag;
713}
714
715/**<p>Returns the NSColor on the NSPasteboard pasteBoard
716   or nil if it does not exists.</p><p>See Also: -writeToPasteboard:</p>
717 */
718+ (NSColor*) colorFromPasteboard: (NSPasteboard *)pasteBoard
719{
720  NSData *colorData = [pasteBoard dataForType: NSColorPboardType];
721
722  // FIXME: This should better use the description format
723  if (colorData != nil)
724    return [NSUnarchiver unarchiveObjectWithData: colorData];
725
726  return nil;
727}
728
729//
730// System colors stuff.
731//
732+ (NSColor*) alternateSelectedControlColor
733{
734  return systemColorWithName(@"alternateSelectedControlColor");
735}
736
737+ (NSColor*) alternateSelectedControlTextColor
738{
739  return systemColorWithName(@"alternateSelectedControlTextColor");
740}
741
742+ (NSColor*) controlBackgroundColor
743{
744  return systemColorWithName(@"controlBackgroundColor");
745}
746
747+ (NSColor*) controlColor
748{
749  return systemColorWithName(@"controlColor");
750}
751
752+ (NSColor*) controlDarkShadowColor
753{
754  return systemColorWithName(@"controlDarkShadowColor");
755}
756
757+ (NSColor*) controlHighlightColor
758{
759  return systemColorWithName(@"controlHighlightColor");
760}
761
762+ (NSColor*) controlLightHighlightColor
763{
764  return systemColorWithName(@"controlLightHighlightColor");
765}
766
767+ (NSColor*) controlShadowColor
768{
769  return systemColorWithName(@"controlShadowColor");
770}
771
772+ (NSColor*) controlTextColor
773{
774  return systemColorWithName(@"controlTextColor");
775}
776
777+ (NSColor*) disabledControlTextColor
778{
779  return systemColorWithName(@"disabledControlTextColor");
780}
781
782+ (NSColor*) gridColor
783{
784  return systemColorWithName(@"gridColor");
785}
786
787+ (NSColor*) headerColor
788{
789  return systemColorWithName(@"headerColor");
790}
791
792+ (NSColor*) headerTextColor
793{
794  return systemColorWithName(@"headerTextColor");
795}
796
797+ (NSColor*) highlightColor
798{
799  return systemColorWithName(@"highlightColor");
800}
801
802+ (NSColor*) keyboardFocusIndicatorColor
803{
804  return systemColorWithName(@"keyboardFocusIndicatorColor");
805}
806
807+ (NSColor*) knobColor
808{
809  return systemColorWithName(@"knobColor");
810}
811
812+ (NSColor*) labelColor
813{
814  return systemColorWithName(@"labelColor");
815}
816
817+ (NSColor*) quaternaryLabelColor
818{
819  return systemColorWithName(@"quaternaryLabelColor");
820}
821
822+ (NSColor*) scrollBarColor
823{
824  return systemColorWithName(@"scrollBarColor");
825}
826
827+ (NSColor*) secondaryLabelColor
828{
829  return systemColorWithName(@"secondaryLabelColor");
830}
831
832+ (NSColor*) secondarySelectedControlColor
833{
834  return systemColorWithName(@"secondarySelectedControlColor");
835}
836
837+ (NSColor*) selectedControlColor
838{
839  return systemColorWithName(@"selectedControlColor");
840}
841
842+ (NSColor*) selectedControlTextColor
843{
844  return systemColorWithName(@"selectedControlTextColor");
845}
846
847+ (NSColor*) selectedKnobColor
848{
849  return systemColorWithName(@"selectedKnobColor");
850}
851
852+ (NSColor*) selectedMenuItemColor
853{
854  return systemColorWithName(@"selectedMenuItemColor");
855}
856
857+ (NSColor*) selectedMenuItemTextColor
858{
859  return systemColorWithName(@"selectedMenuItemTextColor");
860}
861
862+ (NSColor*) selectedTextBackgroundColor
863{
864  return systemColorWithName(@"selectedTextBackgroundColor");
865}
866
867+ (NSColor*) selectedTextColor
868{
869  return systemColorWithName(@"selectedTextColor");
870}
871
872+ (NSColor*) shadowColor
873{
874  return systemColorWithName(@"shadowColor");
875}
876
877+ (NSColor*) tertiaryLabelColor
878{
879  return systemColorWithName(@"tertiaryLabelColor");
880}
881
882+ (NSColor*) textBackgroundColor
883{
884  return systemColorWithName(@"textBackgroundColor");
885}
886
887+ (NSColor*) textColor
888{
889  return systemColorWithName(@"textColor");
890}
891
892+ (NSColor*) toolTipColor
893{
894  return systemColorWithName(@"toolTipColor");
895}
896
897+ (NSColor*) toolTipTextColor
898{
899  return systemColorWithName(@"toolTipTextColor");
900}
901
902+ (NSColor *)windowBackgroundColor
903{
904  return systemColorWithName(@"windowBackgroundColor");
905}
906
907+ (NSColor*) windowFrameColor
908{
909  return systemColorWithName(@"windowFrameColor");
910}
911
912+ (NSColor*) windowFrameTextColor
913{
914  return systemColorWithName(@"windowFrameTextColor");
915}
916
917+ (NSArray*) controlAlternatingRowBackgroundColors
918{
919  return [NSArray arrayWithObjects: systemColorWithName(@"rowBackgroundColor"),
920		  systemColorWithName(@"alternateRowBackgroundColor"), nil];
921}
922
923////////////////////////////////////////////////////////////
924//
925// Instance methods
926//
927
928- (id) copyWithZone: (NSZone*)aZone
929{
930  if (NSShouldRetainWithZone(self, aZone))
931    {
932      return RETAIN(self);
933    }
934  else
935    {
936      return NSCopyObject(self, 0, aZone);
937    }
938}
939
940- (NSString*) description
941{
942  [self subclassResponsibility: _cmd];
943  return nil;
944}
945
946/**<p>Gets the cyan, magenta, yellow,black and alpha values from the NSColor.
947 Raises a NSInternalInconsistencyException if the NSColor is not a CYMK color
948 </p>
949 */
950- (void) getCyan: (CGFloat*)cyan
951	 magenta: (CGFloat*)magenta
952	  yellow: (CGFloat*)yellow
953	   black: (CGFloat*)black
954	   alpha: (CGFloat*)alpha
955{
956  [NSException raise: NSInternalInconsistencyException
957    format: @"Called getCyan:magenta:yellow:black:alpha: on non-CMYK colour"];
958}
959
960/**<p>Gets the hue, saturation, brightness and alpha values from the NSColor.
961 Raises a NSInternalInconsistencyException if the NSColor is not a RGB color
962 </p>
963 */
964- (void) getHue: (CGFloat*)hue
965     saturation: (CGFloat*)saturation
966     brightness: (CGFloat*)brightness
967	  alpha: (CGFloat*)alpha
968{
969  [NSException raise: NSInternalInconsistencyException
970    format: @"Called getHue:saturation:brightness:alpha: on non-RGB colour"];
971}
972
973/**<p>Gets the red, green, blue and alpha values from the NSColor.
974 Raises a NSInternalInconsistencyException if the NSColor is not a RGB color
975 </p>
976 */
977-(void) getRed: (CGFloat*)red
978	  green: (CGFloat*)green
979	   blue: (CGFloat*)blue
980	  alpha: (CGFloat*)alpha
981{
982  [NSException raise: NSInternalInconsistencyException
983	      format: @"Called getRed:green:blue:alpha: on non-RGB colour"];
984}
985
986/**<p>Gets the white alpha values from the NSColor.
987 Raises a NSInternalInconsistencyException if the NSColor is not a
988 greyscale color</p>
989 */
990- (void) getWhite: (CGFloat*)white
991	    alpha: (CGFloat*)alpha
992{
993  [NSException raise: NSInternalInconsistencyException
994	      format: @"Called getWhite:alpha: on non-grayscale colour"];
995}
996
997- (BOOL) isEqual: (id)other
998{
999  if (other == self)
1000    return YES;
1001  if ([other isKindOfClass: NSColorClass] == NO)
1002    return NO;
1003  else
1004    {
1005      [self subclassResponsibility: _cmd];
1006      return NO;
1007    }
1008}
1009
1010/** <p>Returns the alpha component. </p>
1011 */
1012- (CGFloat) alphaComponent
1013{
1014  return 1.0;
1015}
1016
1017/** <p>Returns the black component. Raises a NSInternalInconsistencyException
1018    if NSColor is not a CMYK color.</p>
1019 */
1020- (CGFloat) blackComponent
1021{
1022  [NSException raise: NSInternalInconsistencyException
1023	      format: @"Called blackComponent on non-CMYK colour"];
1024  return 0.0;
1025}
1026
1027/** <p>Returns the blue component. Raises a NSInternalInconsistencyException
1028    if NSColor is not a RGB color.</p>
1029 */
1030- (CGFloat) blueComponent
1031{
1032  [NSException raise: NSInternalInconsistencyException
1033	      format: @"Called blueComponent on non-RGB colour"];
1034  return 0.0;
1035}
1036
1037/** <p>Returns the brightness component. Raises a
1038    NSInternalInconsistencyException if NSColor space is not a RGB color</p>
1039*/
1040- (CGFloat) brightnessComponent
1041{
1042  [NSException raise: NSInternalInconsistencyException
1043	      format: @"Called brightnessComponent on non-RGB colour"];
1044  return 0.0;
1045}
1046
1047- (NSString *) catalogNameComponent
1048{
1049  [NSException raise: NSInternalInconsistencyException
1050	      format: @"Called catalogNameComponent on colour with name"];
1051  return nil;
1052}
1053
1054- (NSString *) colorNameComponent
1055{
1056  [NSException raise: NSInternalInconsistencyException
1057	      format: @"Called colorNameComponent on colour with name"];
1058  return nil;
1059}
1060
1061/** <p>Returns the cyan component. Raises a  NSInternalInconsistencyException
1062    if NSColor is not a CYMK color</p>
1063*/
1064- (CGFloat) cyanComponent
1065{
1066  [NSException raise: NSInternalInconsistencyException
1067	      format: @"Called cyanComponent on non-CMYK colour"];
1068  return 0.0;
1069}
1070
1071/** <p>Returns the green component. Raises a  NSInternalInconsistencyException
1072    if NSColor is not a RGB color</p>
1073*/
1074- (CGFloat) greenComponent
1075{
1076  [NSException raise: NSInternalInconsistencyException
1077	      format: @"Called greenComponent on non-RGB colour"];
1078  return 0.0;
1079}
1080
1081/** <p>Returns the hue component. Raises a  NSInternalInconsistencyException
1082    if NSColor is not a RGB color</p>
1083*/
1084- (CGFloat) hueComponent
1085{
1086  [NSException raise: NSInternalInconsistencyException
1087	      format: @"Called hueComponent on non-RGB colour"];
1088  return 0.0;
1089}
1090
1091- (NSString *) localizedCatalogNameComponent
1092{
1093  [NSException raise: NSInternalInconsistencyException
1094    format: @"Called localizedCatalogNameComponent on colour with name"];
1095  return nil;
1096}
1097
1098- (NSString *) localizedColorNameComponent
1099{
1100  [NSException raise: NSInternalInconsistencyException
1101    format: @"Called localizedColorNameComponent on colour with name"];
1102  return nil;
1103}
1104
1105/** <p>Returns the magenta component. Raises a
1106    NSInternalInconsistencyException  if NSColor is not a CMYK color</p>
1107*/
1108- (CGFloat) magentaComponent
1109{
1110  [NSException raise: NSInternalInconsistencyException
1111	      format: @"Called magentaComponent on non-CMYK colour"];
1112  return 0.0;
1113}
1114
1115/** <p>Returns the red component. Raises a NSInternalInconsistencyException
1116    if NSColor is not a RGB color</p>
1117*/
1118- (CGFloat) redComponent
1119{
1120  [NSException raise: NSInternalInconsistencyException
1121	      format: @"Called redComponent on non-RGB colour"];
1122  return 0.0;
1123}
1124
1125/** <p>Returns the saturation component. Raises a
1126    NSInternalInconsistencyException if NSColor is not a RGB color</p>
1127*/
1128- (CGFloat) saturationComponent
1129{
1130  [NSException raise: NSInternalInconsistencyException
1131	      format: @"Called saturationComponent on non-RGB colour"];
1132  return 0.0;
1133}
1134
1135/** <p>Returns the white component. Raises a NSInternalInconsistencyException
1136    if NSColor is not a grayscale color</p>
1137*/
1138- (CGFloat) whiteComponent
1139{
1140  [NSException raise: NSInternalInconsistencyException
1141	      format: @"Called whiteComponent on non-grayscale colour"];
1142  return 0.0;
1143}
1144
1145- (NSImage*) patternImage
1146{
1147  [NSException raise: NSInternalInconsistencyException
1148	      format: @"Called patternImage on non-pattern colour"];
1149  return nil;
1150}
1151
1152/** <p>Returns the yellow component. Raises a NSInternalInconsistencyException
1153    if NSColor is not a RGB color</p>
1154*/
1155- (CGFloat) yellowComponent
1156{
1157  [NSException raise: NSInternalInconsistencyException
1158	      format: @"Called yellowComponent on non-CMYK colour"];
1159  return 0.0;
1160}
1161
1162//
1163// Converting to Another Color Space
1164//
1165- (NSString *) colorSpaceName
1166{
1167  [self subclassResponsibility: _cmd];
1168  return nil;
1169}
1170
1171- (NSColor*) colorUsingColorSpaceName: (NSString *)colorSpace
1172{
1173  return [self colorUsingColorSpaceName: colorSpace
1174				 device: nil];
1175}
1176
1177- (NSColor*) colorUsingColorSpaceName: (NSString *)colorSpace
1178			       device: (NSDictionary *)deviceDescription
1179{
1180  if (colorSpace == nil)
1181    {
1182      if (deviceDescription != nil)
1183	colorSpace = [deviceDescription objectForKey: NSDeviceColorSpaceName];
1184      if (colorSpace == nil)
1185        colorSpace = NSDeviceRGBColorSpace;
1186    }
1187  if ([colorSpace isEqualToString: [self colorSpaceName]])
1188    {
1189      return self;
1190    }
1191
1192  if ([colorSpace isEqualToString: NSNamedColorSpace])
1193    {
1194      // FIXME: We cannot convert to named color space.
1195      return nil;
1196    }
1197
1198  [self subclassResponsibility: _cmd];
1199
1200  return nil;
1201}
1202
1203+ (NSColor *) colorWithColorSpace: (NSColorSpace *)space
1204                       components: (const CGFloat *)comp
1205                            count: (NSInteger)number
1206{
1207  // FIXME
1208  if (space == [NSColorSpace genericRGBColorSpace] && (number == 4))
1209    {
1210      return [self colorWithCalibratedRed: comp[0]
1211                   green: comp[1]
1212                   blue: comp[2]
1213                   alpha: comp[3]];
1214    }
1215  if (space == [NSColorSpace deviceRGBColorSpace] && (number == 4))
1216    {
1217      return [self colorWithDeviceRed: comp[0]
1218                   green: comp[1]
1219                   blue: comp[2]
1220                   alpha: comp[3]];
1221    }
1222  if (space == [NSColorSpace genericGrayColorSpace] && (number == 2))
1223    {
1224      return [NSColor colorWithCalibratedWhite: comp[0] alpha: comp[1]];
1225    }
1226  if (space == [NSColorSpace deviceGrayColorSpace] && (number == 2))
1227    {
1228      return [NSColor colorWithDeviceWhite: comp[0] alpha: comp[1]];
1229    }
1230  if (space == [NSColorSpace genericCMYKColorSpace] && (number == 5))
1231    {
1232      return [NSColor colorWithDeviceCyan: comp[0]
1233                      magenta: comp[1]
1234                      yellow: comp[2]
1235                      black: comp[3]
1236                      alpha: comp[4]];
1237    }
1238  if (space == [NSColorSpace deviceCMYKColorSpace] && (number == 5))
1239    {
1240      return [NSColor colorWithDeviceCyan: comp[0]
1241                      magenta: comp[1]
1242                      yellow: comp[2]
1243                      black: comp[3]
1244                      alpha: comp[4]];
1245    }
1246
1247  return nil;
1248}
1249
1250/*
1251  FIXME: This method does it the wrong way around. We should store the
1252  actual colour space and get the colour space name from there.
1253*/
1254- (NSColorSpace *) colorSpace
1255{
1256  NSString *name = [self colorSpaceName];
1257
1258  if ([name isEqualToString: NSCalibratedRGBColorSpace])
1259    return [NSColorSpace genericRGBColorSpace];
1260  if ([name isEqualToString: NSDeviceRGBColorSpace])
1261    return [NSColorSpace deviceRGBColorSpace];
1262  if ([name isEqualToString: NSCalibratedBlackColorSpace]
1263    || [name isEqualToString: NSCalibratedWhiteColorSpace])
1264    return [NSColorSpace genericGrayColorSpace];
1265  if ([name isEqualToString: NSDeviceBlackColorSpace]
1266    || [name isEqualToString: NSDeviceWhiteColorSpace])
1267    return [NSColorSpace deviceGrayColorSpace];
1268  if ([name isEqualToString: NSDeviceCMYKColorSpace])
1269    return [NSColorSpace deviceCMYKColorSpace];
1270
1271  return nil;
1272}
1273
1274- (NSColor *) colorUsingColorSpace: (NSColorSpace *)space
1275{
1276  // FIXME
1277  NSString *colorSpaceName;
1278
1279  if (space == [self colorSpace])
1280    {
1281      return self;
1282    }
1283
1284  switch ([space colorSpaceModel])
1285    {
1286      default:
1287      case NSUnknownColorSpaceModel:
1288        return nil;
1289      case NSGrayColorSpaceModel:
1290        colorSpaceName = NSDeviceWhiteColorSpace;
1291        break;
1292      case NSRGBColorSpaceModel:
1293        colorSpaceName = NSDeviceRGBColorSpace;
1294        break;
1295      case NSCMYKColorSpaceModel:
1296        colorSpaceName = NSDeviceCMYKColorSpace;
1297        break;
1298      case NSLABColorSpaceModel:
1299        return nil;
1300      case NSDeviceNColorSpaceModel:
1301        return nil;
1302    }
1303  return [self colorUsingColorSpaceName: colorSpaceName
1304				 device: nil];
1305}
1306
1307- (NSUInteger) hash
1308{
1309  int nums = [self numberOfComponents];
1310  CGFloat floats[nums];
1311  NSUInteger	h = 0;
1312  unsigned	i;
1313
1314  [self getComponents: &floats[0]];
1315  for (i = 0; i < sizeof(floats); i++)
1316    {
1317      h = (h << 5) + h + *(uint8_t*)(((uintptr_t)&floats[0])+(i*sizeof(uint8_t)));
1318    }
1319  return h;
1320}
1321
1322- (NSInteger) numberOfComponents
1323{
1324  [NSException raise: NSInternalInconsistencyException
1325    format: @"Called numberOfComponents on non-standard colour"];
1326  return 0;
1327}
1328
1329- (void) getComponents: (CGFloat *)components
1330{
1331  [NSException raise: NSInternalInconsistencyException
1332    format: @"Called getComponents: on non-standard colour"];
1333}
1334
1335//
1336// Changing the Color
1337//
1338- (NSColor*) blendedColorWithFraction: (CGFloat)fraction
1339			      ofColor: (NSColor*)aColor
1340{
1341  NSColor *myColor = [self colorUsingColorSpaceName: NSCalibratedRGBColorSpace];
1342  NSColor *other = [aColor colorUsingColorSpaceName: NSCalibratedRGBColorSpace];
1343  CGFloat mr, mg, mb, ma, or, og, ob, oa, red, green, blue, alpha;
1344
1345  if (fraction <= 0.0)
1346    {
1347      return self;
1348    }
1349
1350  if (fraction >= 1.0)
1351    {
1352      return aColor;
1353    }
1354
1355  if (myColor == nil || other == nil)
1356    {
1357      return nil;
1358    }
1359
1360  [myColor getRed: &mr green: &mg blue: &mb alpha: &ma];
1361  [other getRed: &or green: &og blue: &ob alpha: &oa];
1362  red = fraction * or + (1 - fraction) * mr;
1363  green = fraction * og + (1 - fraction) * mg;
1364  blue = fraction * ob + (1 - fraction) * mb;
1365  alpha = fraction * oa + (1 - fraction) * ma;
1366  return [NSColorClass colorWithCalibratedRed: red
1367					green: green
1368					 blue: blue
1369					alpha: alpha];
1370}
1371
1372- (NSColor*) colorWithAlphaComponent: (CGFloat)alpha
1373{
1374  return self;
1375}
1376
1377- (NSColor*) highlightWithLevel: (CGFloat)level
1378{
1379  return [self blendedColorWithFraction: level
1380			        ofColor: [NSColorClass highlightColor]];
1381}
1382
1383- (NSColor*) shadowWithLevel: (CGFloat)level
1384{
1385  return [self blendedColorWithFraction: level
1386			        ofColor: [NSColorClass shadowColor]];
1387}
1388
1389/**<p>Writes the NSColor into the NSPasteboard specified by pasteBoard</p>
1390 * <p>See Also: +colorFromPasteboard: </p>
1391 */
1392- (void) writeToPasteboard: (NSPasteboard *)pasteBoard
1393{
1394  // FIXME: We should better use the description
1395  NSData *colorData = [NSArchiver archivedDataWithRootObject: self];
1396
1397  if (colorData != nil)
1398    [pasteBoard setData: colorData
1399		forType: NSColorPboardType];
1400}
1401
1402//
1403// Drawing
1404//
1405- (void) drawSwatchInRect: (NSRect)rect
1406{
1407  if ([self alphaComponent] < 1.0)
1408    {
1409      NSBezierPath *triangle = [NSBezierPath bezierPath];
1410
1411      [[NSColor whiteColor] set];
1412      NSRectFill(rect);
1413
1414      [triangle moveToPoint: NSMakePoint(rect.origin.x,
1415		rect.origin.y + rect.size.height)];
1416      [triangle lineToPoint: NSMakePoint(rect.origin.x + rect.size.width,
1417		rect.origin.y + rect.size.height)];
1418      [triangle lineToPoint: rect.origin];
1419      [triangle closePath];
1420      [[NSColor blackColor] set];
1421      [triangle fill];
1422    }
1423
1424  [self set];
1425  NSRectFill(rect);
1426}
1427
1428- (void) set
1429{
1430  // This is here to keep old code working
1431  [[self colorUsingColorSpaceName: NSDeviceRGBColorSpace] set];
1432}
1433
1434- (void) setFill
1435{
1436  [[self colorUsingColorSpaceName: NSDeviceRGBColorSpace] setFill];
1437}
1438
1439- (void) setStroke
1440{
1441  [[self colorUsingColorSpaceName: NSDeviceRGBColorSpace] setStroke];
1442}
1443
1444//
1445// NSCoding protocol
1446//
1447- (Class) classForCoder
1448{
1449  return NSColorClass;
1450}
1451
1452- (void) encodeWithCoder: (NSCoder*)aCoder
1453{
1454  [self subclassResponsibility: _cmd];
1455}
1456
1457- (id) initWithCoder: (NSCoder*)aDecoder
1458{
1459  if ([aDecoder allowsKeyedCoding])
1460    {
1461      int colorSpace = [aDecoder decodeIntForKey: @"NSColorSpace"];
1462
1463      DESTROY(self);
1464
1465      if ((colorSpace == 1) || (colorSpace == 2))
1466        {
1467	  NSUInteger length;
1468	  const uint8_t *data;
1469	  double red = 0.0;
1470	  double green = 0.0;
1471	  double blue = 0.0;
1472	  double alpha = 1.0;
1473	  NSString *str;
1474	  NSScanner *scanner;
1475
1476	  if ([aDecoder containsValueForKey: @"NSRGB"])
1477	    {
1478	      data = [aDecoder decodeBytesForKey: @"NSRGB"
1479			       returnedLength: &length];
1480	      str = [[NSString alloc] initWithCString: (const char*)data
1481				      length: length];
1482	      scanner = [[NSScanner alloc] initWithString: str];
1483	      [scanner scanDouble: &red];
1484	      [scanner scanDouble: &green];
1485	      [scanner scanDouble: &blue];
1486	      [scanner scanDouble: &alpha];
1487	      RELEASE(scanner);
1488	      RELEASE(str);
1489	    }
1490
1491	  if (colorSpace == 1)
1492	    {
1493	      self = RETAIN([NSColor colorWithCalibratedRed: red
1494				     green: green
1495				     blue: blue
1496				     alpha: alpha]);
1497	    }
1498	  else
1499	    {
1500	      self = RETAIN([NSColor colorWithDeviceRed: red
1501				     green: green
1502				     blue: blue
1503				     alpha: alpha]);
1504	    }
1505	}
1506      else if ((colorSpace == 3) || (colorSpace == 4))
1507        {
1508	  NSUInteger length;
1509	  const uint8_t *data;
1510	  double white = 0.0;
1511	  double alpha = 1.0;
1512	  NSString *str;
1513	  NSScanner *scanner;
1514
1515	  if ([aDecoder containsValueForKey: @"NSWhite"])
1516	    {
1517	      data = [aDecoder decodeBytesForKey: @"NSWhite"
1518			       returnedLength: &length];
1519	      str = [[NSString alloc] initWithCString: (const char*)data
1520				      length: length];
1521	      scanner = [[NSScanner alloc] initWithString: str];
1522	      [scanner scanDouble: &white];
1523	      [scanner scanDouble: &alpha];
1524	      RELEASE(scanner);
1525	      RELEASE(str);
1526	    }
1527
1528	  if (colorSpace == 3)
1529	    {
1530	      self = RETAIN([NSColor colorWithCalibratedWhite: white
1531				     alpha: alpha]);
1532	    }
1533	  else
1534	    {
1535	      self = RETAIN([NSColor colorWithDeviceWhite: white
1536				     alpha: alpha]);
1537	    }
1538	}
1539      else if (colorSpace == 5)
1540        {
1541	  NSUInteger length;
1542	  const uint8_t *data;
1543	  double cyan = 0.0;
1544	  double yellow = 0.0;
1545	  double magenta = 0.0;
1546	  double black = 0.0;
1547	  double alpha = 1.0;
1548	  NSString *str;
1549	  NSScanner *scanner;
1550
1551	  if ([aDecoder containsValueForKey: @"NSCYMK"])
1552	    {
1553	      data = [aDecoder decodeBytesForKey: @"NSCYMK"
1554			       returnedLength: &length];
1555	      str = [[NSString alloc] initWithCString: (const char*)data
1556				      length: length];
1557	      scanner = [[NSScanner alloc] initWithString: str];
1558	      [scanner scanDouble: &cyan];
1559	      [scanner scanDouble: &yellow];
1560	      [scanner scanDouble: &magenta];
1561	      [scanner scanDouble: &black];
1562	      [scanner scanDouble: &alpha];
1563	      RELEASE(scanner);
1564	      RELEASE(str);
1565	    }
1566
1567	  self = RETAIN([NSColor colorWithDeviceCyan: cyan
1568				 magenta: magenta
1569				 yellow: yellow
1570				 black: black
1571				 alpha: alpha]);
1572	}
1573      else if (colorSpace == 6)
1574        {
1575	  NSString *catalog = [aDecoder decodeObjectForKey: @"NSCatalogName"];
1576	  NSString *name = [aDecoder decodeObjectForKey: @"NSColorName"];
1577	  //NSColor *color = [aDecoder decodeObjectForKey: @"NSColor"];
1578
1579	  self = RETAIN([NSColor colorWithCatalogName: catalog
1580				 colorName: name]);
1581	}
1582      else if (colorSpace == 10)
1583        {
1584	  NSImage *image = [aDecoder decodeObjectForKey: @"NSImage"];
1585
1586	  self = RETAIN([NSColor colorWithPatternImage: image]);
1587	}
1588
1589      return self;
1590    }
1591  else if ([aDecoder versionForClassName: @"NSColor"] < 3)
1592    {
1593      float red;
1594      float green;
1595      float blue;
1596      float cyan;
1597      float magenta;
1598      float yellow;
1599      float black;
1600      float hue;
1601      float saturation;
1602      float brightness;
1603      float alpha;
1604      float white;
1605
1606      int active_component;
1607      int valid_components;
1608      NSString *colorspace_name;
1609      NSString *catalog_name;
1610      NSString *color_name;
1611      BOOL is_clear;
1612
1613      DESTROY(self);
1614
1615      // Version 1
1616      [aDecoder decodeValueOfObjCType: @encode(float) at: &red];
1617      [aDecoder decodeValueOfObjCType: @encode(float) at: &green];
1618      [aDecoder decodeValueOfObjCType: @encode(float) at: &blue];
1619      [aDecoder decodeValueOfObjCType: @encode(float) at: &alpha];
1620      [aDecoder decodeValueOfObjCType: @encode(BOOL) at: &is_clear];
1621
1622      // Version 2
1623      [aDecoder decodeValueOfObjCType: @encode(id) at: &colorspace_name];
1624      [aDecoder decodeValueOfObjCType: @encode(id) at: &catalog_name];
1625      [aDecoder decodeValueOfObjCType: @encode(id) at: &color_name];
1626      [aDecoder decodeValueOfObjCType: @encode(float) at: &cyan];
1627      [aDecoder decodeValueOfObjCType: @encode(float) at: &magenta];
1628      [aDecoder decodeValueOfObjCType: @encode(float) at: &yellow];
1629      [aDecoder decodeValueOfObjCType: @encode(float) at: &black];
1630      [aDecoder decodeValueOfObjCType: @encode(float) at: &hue];
1631      [aDecoder decodeValueOfObjCType: @encode(float) at: &saturation];
1632      [aDecoder decodeValueOfObjCType: @encode(float) at: &brightness];
1633      [aDecoder decodeValueOfObjCType: @encode(float) at: &white];
1634      [aDecoder decodeValueOfObjCType: @encode(int) at: &active_component];
1635      [aDecoder decodeValueOfObjCType: @encode(int) at: &valid_components];
1636
1637      if ([colorspace_name isEqualToString: @"NSDeviceCMYKColorSpace"])
1638	{
1639	  self = [NSColorClass colorWithDeviceCyan: cyan
1640					   magenta: magenta
1641					    yellow: yellow
1642					     black: black
1643					     alpha: alpha];
1644	}
1645      else if ([colorspace_name isEqualToString: @"NSDeviceWhiteColorSpace"])
1646	{
1647	  self = [NSColorClass colorWithDeviceWhite: white alpha: alpha];
1648	}
1649      else if ([colorspace_name isEqualToString:
1650	@"NSCalibratedWhiteColorSpace"])
1651	{
1652	  self = [NSColorClass colorWithCalibratedWhite:white alpha: alpha];
1653	}
1654      else if ([colorspace_name isEqualToString: @"NSDeviceRGBColorSpace"])
1655	{
1656	  self = [NSColorClass colorWithDeviceRed: red
1657					    green: green
1658					     blue: blue
1659					    alpha: alpha];
1660	}
1661      else if ([colorspace_name isEqualToString: @"NSCalibratedRGBColorSpace"])
1662	{
1663	  self = [NSColorClass colorWithCalibratedRed: red
1664						green: green
1665						 blue: blue
1666						alpha: alpha];
1667	}
1668      else if ([colorspace_name isEqualToString: @"NSNamedColorSpace"])
1669	{
1670	  self = [NSColorClass colorWithCatalogName: catalog_name
1671					  colorName: color_name];
1672	}
1673
1674      return RETAIN(self);
1675    }
1676  else
1677    {
1678      NSString	*csName = [aDecoder decodeObject];
1679
1680      RELEASE(self);
1681      if ([csName isEqualToString: @"NSDeviceCMYKColorSpace"])
1682	{
1683	  self = [GSDeviceCMYKColor alloc];
1684	}
1685      else if ([csName isEqualToString: @"NSDeviceRGBColorSpace"])
1686	{
1687	  self = [GSDeviceRGBColor alloc];
1688	}
1689      else if ([csName isEqualToString: @"NSDeviceWhiteColorSpace"])
1690	{
1691	  self = [GSDeviceWhiteColor alloc];
1692	}
1693      else if ([csName isEqualToString: @"NSCalibratedWhiteColorSpace"])
1694	{
1695	  self = [GSCalibratedWhiteColor alloc];
1696	}
1697      else if ([csName isEqualToString: @"NSCalibratedRGBColorSpace"])
1698	{
1699	  self = [GSCalibratedRGBColor alloc];
1700	}
1701      else if ([csName isEqualToString: @"NSNamedColorSpace"])
1702	{
1703	  self = [GSNamedColor alloc];
1704	}
1705      else
1706	{
1707	  NSLog(@"Unknown colorspace name in decoded color");
1708	  return nil;
1709	}
1710      return [self initWithCoder: aDecoder];
1711    }
1712}
1713
1714@end
1715
1716//
1717// Private methods
1718//
1719@implementation NSColor (GNUstepPrivate)
1720
1721+ (NSColor*) colorFromString: (NSString*)str
1722{
1723  if ([str hasPrefix: @"{"])
1724    {
1725      NSDictionary	*dict;
1726      NSString		*space;
1727      CGFloat		alpha;
1728
1729      dict = [str propertyList];
1730      if (dict == nil)
1731	return nil;
1732      if ((space = [dict objectForKey: @"ColorSpace"]) == nil)
1733	return nil;
1734
1735      str = [dict objectForKey: @"Alpha"];
1736      if (str == nil || [str isEqualToString: @""])
1737	{
1738	  alpha = 1.0;
1739	}
1740      else
1741	{
1742	  alpha = [str doubleValue];
1743	}
1744
1745      if ([space isEqual: NSCalibratedWhiteColorSpace])
1746	{
1747	  CGFloat white = [[dict objectForKey: @"W"] doubleValue];
1748
1749	  return [self colorWithCalibratedWhite: white alpha: alpha];
1750	}
1751      if ([space isEqual: NSCalibratedBlackColorSpace])
1752	{
1753	  CGFloat white = [[dict objectForKey: @"W"] doubleValue];
1754
1755	  return [self colorWithCalibratedWhite: white
1756					  alpha: alpha];
1757	}
1758      if ([space isEqual: NSCalibratedRGBColorSpace])
1759	{
1760	  if ([dict objectForKey: @"H"] != nil)
1761	    {
1762	      CGFloat	hue = [[dict objectForKey: @"H"] doubleValue];
1763	      CGFloat	saturation = [[dict objectForKey: @"S"] doubleValue];
1764	      CGFloat	brightness = [[dict objectForKey: @"B"] doubleValue];
1765
1766	      return [self colorWithCalibratedHue: hue
1767				       saturation: saturation
1768				       brightness: brightness
1769					    alpha: alpha];
1770	    }
1771	  else
1772	    {
1773	      CGFloat	red = [[dict objectForKey: @"R"] doubleValue];
1774	      CGFloat	green = [[dict objectForKey: @"G"] doubleValue];
1775	      CGFloat	blue = [[dict objectForKey: @"B"] doubleValue];
1776
1777	      return [self colorWithCalibratedRed: red
1778					    green: green
1779					     blue: blue
1780					    alpha: alpha];
1781	    }
1782	}
1783      if ([space isEqual: NSDeviceCMYKColorSpace])
1784	{
1785	  CGFloat	cyan = [[dict objectForKey: @"C"] doubleValue];
1786	  CGFloat	magenta = [[dict objectForKey: @"M"] doubleValue];
1787	  CGFloat	yellow = [[dict objectForKey: @"Y"] doubleValue];
1788	  CGFloat	black = [[dict objectForKey: @"B"] doubleValue];
1789
1790	  return [self colorWithDeviceCyan: cyan
1791				   magenta: magenta
1792				    yellow: yellow
1793				     black: black
1794				     alpha: alpha];
1795	}
1796      if ([space isEqual: NSNamedColorSpace])
1797	{
1798	  NSString	*cat = [dict objectForKey: @"Catalog"];
1799	  NSString	*col = [dict objectForKey: @"Color"];
1800
1801	  return [self colorWithCatalogName: cat
1802				  colorName: col];
1803	}
1804    }
1805  else if (str != nil)
1806    {
1807      double		r, g, b;
1808      NSScanner *scanner = [[NSScanner alloc] initWithString: str];
1809
1810      if ([scanner scanDouble: &r] &&
1811	  [scanner scanDouble: &g] &&
1812	  [scanner scanDouble: &b] &&
1813	  [scanner isAtEnd])
1814	{
1815	  RELEASE(scanner);
1816	  return [self colorWithCalibratedRed: r
1817					green: g
1818					 blue: b
1819					alpha: 1.0];
1820	}
1821
1822      RELEASE(scanner);
1823    }
1824
1825  return nil;
1826}
1827
1828/*
1829 *	Go through all the names of system colors - for each color where
1830 *	there is a value in the defaults database, see if the current
1831 *	value of the color differs from the old one.
1832 *	Where there is a difference, update the color strings dictionary
1833 *	and update the system colors list to contain the new color.
1834 *	Finally, issue a notification if appropriate.
1835 */
1836+ (void) defaultsDidChange: (NSNotification*)notification
1837{
1838  NSUserDefaults	*defs;
1839  NSEnumerator		*enumerator;
1840  NSString		*key;
1841  BOOL			didChange = NO;
1842
1843  defs = [NSUserDefaults standardUserDefaults];
1844
1845  enumerator = [colorStrings keyEnumerator];
1846  while ((key = [enumerator nextObject]) != nil)
1847    {
1848      NSString	*def = [[defs objectForKey: key] description];
1849
1850      if (def != nil)
1851	{
1852	  NSColor *old = [systemColors colorWithKey: key];
1853	  NSColor *color = [NSColor colorFromString: def];
1854
1855	  if (color == nil)
1856	    {
1857	      NSLog(@"System color '%@' has bad string rep - '%@'\n",
1858		    key, def);
1859	    }
1860	  else if ([color isEqual: old] == NO)
1861	    {
1862	      didChange = YES;
1863	      [colorStrings setObject: def forKey: key];
1864	      [systemColors setColor: color forKey: key];
1865	      // Refresh the cache for this named colour
1866	      [[systemDict objectForKey: key] recache];
1867	    }
1868	}
1869    }
1870
1871  if (didChange)
1872    {
1873      [[NSNotificationCenter defaultCenter]
1874	postNotificationName: NSSystemColorsDidChangeNotification object: nil];
1875    }
1876}
1877
1878/*
1879 * Handle activation of a new theme ... look for a 'System' color list
1880 * in the theme bundle and use it instead of the default system color
1881 * list if it is present.
1882 */
1883+ (void) themeDidActivate: (NSNotification*)notification
1884{
1885  GSTheme	*theme = [notification object];
1886  NSColorList	*list = [theme colors];
1887  NSEnumerator	*enumerator;
1888  NSString	*name;
1889
1890  if (list == nil)
1891    {
1892      list = defaultSystemColors;
1893    }
1894  NSAssert([[list name] isEqual: @"System"], NSInvalidArgumentException);
1895  [NSColorList _setThemeSystemColorList: list];
1896
1897  /* We always update the system dictionary and send a notification, since
1898   * the theme may have given us a pre-existing color list, but have changed
1899   * one or more of the colors in it.
1900   */
1901  list = [NSColorList colorListNamed: @"System"];
1902  ASSIGN(systemColors, list);
1903  enumerator = [systemDict keyEnumerator];
1904  while ((name = [enumerator nextObject]) != nil)
1905    {
1906      [[systemDict objectForKey: name] recache];
1907    }
1908  [[NSNotificationCenter defaultCenter]
1909    postNotificationName: NSSystemColorsDidChangeNotification object: nil];
1910}
1911
1912@end
1913
1914
1915// Named colours
1916@implementation GSNamedColor
1917
1918static	NSMutableDictionary	*namedColors = nil;
1919static	NSRecursiveLock		*namedColorLock = nil;
1920
1921+ (void) initialize
1922{
1923  namedColorLock = [NSRecursiveLock new];
1924  namedColors = [NSMutableDictionary new];
1925}
1926
1927- (NSColor*) initWithCatalogName: (NSString *)listName
1928		       colorName: (NSString *)colorName
1929{
1930  NSMutableDictionary	*d;
1931  NSColor		*c;
1932
1933  _catalog_name = [listName copy];
1934  _color_name = [colorName copy];
1935  [namedColorLock lock];
1936  d = [namedColors objectForKey: _catalog_name];
1937  if (d == nil)
1938    {
1939      d = [NSMutableDictionary new];
1940      [namedColors setObject: d forKey: _catalog_name];
1941      [d release];
1942    }
1943  c = [d objectForKey: _color_name];
1944  if (c == nil)
1945    {
1946      [d setObject: self forKey: _color_name];
1947    }
1948  else
1949    {
1950      [self release];
1951      self = (GSNamedColor*)[c retain];
1952    }
1953  [namedColorLock unlock];
1954  return self;
1955}
1956
1957- (void) dealloc
1958{
1959  RELEASE(_catalog_name);
1960  RELEASE(_color_name);
1961  RELEASE(_cached_name_space);
1962  RELEASE(_cached_color);
1963  [super dealloc];
1964}
1965
1966- (NSString *) colorSpaceName
1967{
1968  return NSNamedColorSpace;
1969}
1970
1971- (id) copyWithZone: (NSZone*)aZone
1972{
1973  return RETAIN(self);
1974}
1975
1976- (NSString*) description
1977{
1978  NSMutableString *desc;
1979
1980  /*
1981   *	We encode information in a dictionary
1982   *	format with meaningful keys.
1983   */
1984  desc = [NSMutableString stringWithCapacity: 128];
1985  [desc appendFormat: @"{ ColorSpace = \"%@\";", [self colorSpaceName]];
1986  [desc appendFormat: @" Catalog = \"%@\";", _catalog_name];
1987  [desc appendFormat: @" Color = \"%@\"; }", _color_name];
1988
1989  return desc;
1990}
1991
1992- (NSString *) catalogNameComponent
1993{
1994  return _catalog_name;
1995}
1996
1997- (NSString *) colorNameComponent
1998{
1999  return _color_name;
2000}
2001
2002- (NSString *) localizedCatalogNameComponent
2003{
2004  // FIXME: How do we localize?
2005  return NSLocalizedString(_catalog_name, @"colour list name");
2006}
2007
2008- (NSString *) localizedColorNameComponent
2009{
2010  // FIXME: How do we localize?
2011  return NSLocalizedString(_color_name, @"colour name");
2012}
2013
2014- (NSUInteger) hash
2015{
2016  return [_catalog_name hash] + [_color_name hash];
2017}
2018
2019- (BOOL) isEqual: (id)other
2020{
2021  if (other == self)
2022    return YES;
2023  if ([other isKindOfClass: [self class]] == NO
2024    || [[other catalogNameComponent] isEqualToString: _catalog_name] == NO
2025    || [[other colorNameComponent] isEqualToString: _color_name] == NO)
2026    {
2027      return NO;
2028    }
2029  return YES;
2030}
2031
2032- (NSColor*) colorUsingColorSpaceName: (NSString *)colorSpace
2033			       device: (NSDictionary *)deviceDescription
2034{
2035  NSColorList	*list;
2036  NSColor	*real;
2037
2038  if (colorSpace == nil)
2039    {
2040      if (deviceDescription != nil)
2041	colorSpace = [deviceDescription objectForKey: NSDeviceColorSpaceName];
2042      // FIXME: If the deviceDescription is nil, we should get it from the
2043      // current view or printer
2044      if (colorSpace == nil)
2045        colorSpace = NSCalibratedRGBColorSpace;
2046    }
2047  if ([colorSpace isEqualToString: [self colorSpaceName]])
2048    {
2049      return self;
2050    }
2051
2052  // Is there a cache hit?
2053  // FIXME How would we detect that the cache has become invalid by a
2054  // change to the colour list?
2055  [namedColorLock lock];
2056  if (NO == [colorSpace isEqualToString: _cached_name_space])
2057    {
2058      list = [NSColorList colorListNamed: _catalog_name];
2059      real = [list colorWithKey: _color_name];
2060      ASSIGN(_cached_color, [real colorUsingColorSpaceName: colorSpace
2061	device: deviceDescription]);
2062      ASSIGN(_cached_name_space, colorSpace);
2063    }
2064  real = [[_cached_color retain] autorelease];
2065  [namedColorLock unlock];
2066
2067  return real;
2068}
2069
2070- (void) recache
2071{
2072  [namedColorLock lock];
2073  DESTROY(_cached_name_space);
2074  DESTROY(_cached_color);
2075  [namedColorLock unlock];
2076}
2077
2078//
2079// NSCoding protocol
2080//
2081- (void) encodeWithCoder: (NSCoder*)aCoder
2082{
2083  if ([aCoder allowsKeyedCoding])
2084    {
2085      [aCoder encodeInt: 6 forKey: @"NSColorSpace"];
2086      [aCoder encodeObject: _catalog_name forKey: @"NSCatalogName"];
2087      [aCoder encodeObject: _color_name forKey: @"NSColorName"];
2088    }
2089  else
2090    {
2091      [aCoder encodeObject: [self colorSpaceName]];
2092      [aCoder encodeObject: _catalog_name];
2093      [aCoder encodeObject: _color_name];
2094    }
2095}
2096
2097- (id) initWithCoder: (NSCoder*)aDecoder
2098{
2099  NSString	*listName;
2100  NSString	*colorName;
2101
2102  listName = [aDecoder decodeObject];
2103  colorName = [aDecoder decodeObject];
2104  return [self initWithCatalogName: listName
2105		         colorName: colorName];
2106}
2107
2108@end
2109
2110// Grayscale colours
2111@implementation GSWhiteColor
2112
2113- (CGFloat) alphaComponent
2114{
2115  return _alpha_component;
2116}
2117
2118- (CGFloat) whiteComponent
2119{
2120  return _white_component;
2121}
2122
2123- (void) getComponents: (CGFloat *)components;
2124{
2125  components[0] = _white_component;
2126  components[1] = _alpha_component;
2127}
2128
2129- (NSInteger) numberOfComponents
2130{
2131  return 2;
2132}
2133
2134- (NSString*) description
2135{
2136  NSMutableString *desc;
2137
2138  /*
2139   *	We encode information in a dictionary
2140   *	format with meaningful keys.
2141   */
2142  desc = [NSMutableString stringWithCapacity: 128];
2143  [desc appendFormat: @"{ ColorSpace = \"%@\";", [self colorSpaceName]];
2144  [desc appendFormat: @" W = \"%g\";", (double)_white_component];
2145  [desc appendFormat: @" Alpha = \"%g\"; }", (double)_alpha_component];
2146
2147  return desc;
2148}
2149
2150- (void) getWhite: (CGFloat*)white
2151	    alpha: (CGFloat*)alpha
2152{
2153  // Only set what is wanted
2154  if (white)
2155    *white = _white_component;
2156  if (alpha)
2157    *alpha = _alpha_component;
2158}
2159
2160- (BOOL) isEqual: (id)other
2161{
2162  if (other == self)
2163    return YES;
2164  if ([other isKindOfClass: [self class]] == NO
2165    || [other whiteComponent] != _white_component
2166    || [other alphaComponent] != _alpha_component)
2167    {
2168      return NO;
2169    }
2170  return YES;
2171}
2172
2173- (NSColor*) colorWithAlphaComponent: (CGFloat)alpha
2174{
2175  GSWhiteColor *aCopy;
2176
2177  if (alpha < 0.0) alpha = 0.0;
2178  else if (alpha > 1.0) alpha = 1.0;
2179
2180  if (alpha == _alpha_component)
2181    return self;
2182
2183  aCopy = (GSWhiteColor*)NSCopyObject(self, 0, NSDefaultMallocZone());
2184
2185  if (aCopy)
2186    {
2187      aCopy->_alpha_component = alpha;
2188    }
2189
2190  return AUTORELEASE(aCopy);
2191}
2192
2193- (NSColor*) colorUsingColorSpaceName: (NSString *)colorSpace
2194			       device: (NSDictionary *)deviceDescription
2195{
2196  if (colorSpace == nil)
2197    {
2198      if (deviceDescription != nil)
2199	colorSpace = [deviceDescription objectForKey: NSDeviceColorSpaceName];
2200      if (colorSpace == nil)
2201        colorSpace = NSCalibratedRGBColorSpace;
2202    }
2203  if ([colorSpace isEqualToString: [self colorSpaceName]])
2204    {
2205      return self;
2206    }
2207
2208  if ([colorSpace isEqualToString: NSNamedColorSpace])
2209    {
2210      // FIXME: We cannot convert to named color space.
2211      return nil;
2212    }
2213
2214  if ([colorSpace isEqualToString: NSDeviceWhiteColorSpace]
2215    || [colorSpace isEqualToString: NSDeviceBlackColorSpace])
2216    {
2217      return [NSColor colorWithDeviceWhite: _white_component
2218				     alpha: _alpha_component];
2219    }
2220
2221  if ([colorSpace isEqualToString: NSCalibratedWhiteColorSpace]
2222    || [colorSpace isEqualToString: NSCalibratedBlackColorSpace])
2223    {
2224      return [NSColor colorWithCalibratedWhite: _white_component
2225					 alpha: _alpha_component];
2226    }
2227
2228  if ([colorSpace isEqualToString: NSCalibratedRGBColorSpace])
2229    {
2230      return [NSColor colorWithCalibratedRed: _white_component
2231				       green: _white_component
2232					blue: _white_component
2233				       alpha: _alpha_component];
2234    }
2235
2236  if ([colorSpace isEqualToString: NSDeviceRGBColorSpace])
2237    {
2238      return [NSColor colorWithDeviceRed: _white_component
2239				   green: _white_component
2240				    blue: _white_component
2241				   alpha: _alpha_component];
2242    }
2243
2244  if ([colorSpace isEqualToString: NSDeviceCMYKColorSpace])
2245    {
2246      return [NSColor colorWithDeviceCyan: 0.0
2247				  magenta: 0.0
2248				   yellow: 0.0
2249				    black: 1.0 - _white_component
2250				    alpha: _alpha_component];
2251    }
2252
2253  return nil;
2254}
2255
2256- (void) set
2257{
2258  // This should be in GSDeviceWhiteColor, but is here to keep old code working
2259  NSDebugLLog(@"NSColor", @"Gray %g\n", (double)_white_component);
2260  PSsetgray(_white_component);
2261  // Should we check the ignore flag here?
2262  PSsetalpha(_alpha_component);
2263}
2264
2265//
2266// NSCoding protocol
2267//
2268- (void) encodeWithCoder: (NSCoder*)aCoder
2269{
2270  if ([aCoder allowsKeyedCoding])
2271    {
2272      NSString *str;
2273
2274      if ([[self colorSpaceName] isEqualToString: NSCalibratedWhiteColorSpace])
2275        {
2276	  [aCoder encodeInt: 3 forKey: @"NSColorSpace"];
2277	}
2278      else
2279        {
2280	  [aCoder encodeInt: 4 forKey: @"NSColorSpace"];
2281	}
2282
2283      if (_alpha_component == 1.0)
2284        {
2285          str = [[NSString alloc] initWithFormat: @"%g", (double)_white_component];
2286        }
2287      else
2288        {
2289          str = [[NSString alloc] initWithFormat: @"%g %g", (double)_white_component, (double)_alpha_component];
2290        }
2291      [aCoder encodeBytes: (const uint8_t*)[str cString]
2292	      length: [str cStringLength]
2293	      forKey: @"NSWhite"];
2294      RELEASE(str);
2295    }
2296  else
2297    {
2298      float white = _white_component;
2299      float alpha = _alpha_component;
2300      [aCoder encodeObject: [self colorSpaceName]];
2301      [aCoder encodeValueOfObjCType: @encode(float) at: &white];
2302      [aCoder encodeValueOfObjCType: @encode(float) at: &alpha];
2303    }
2304}
2305
2306- (id) initWithCoder: (NSCoder*)aDecoder
2307{
2308  float white, alpha;
2309  [aDecoder decodeValueOfObjCType: @encode(float) at: &white];
2310  [aDecoder decodeValueOfObjCType: @encode(float) at: &alpha];
2311  _white_component = white;
2312  _alpha_component = alpha;
2313  return self;
2314}
2315
2316@end
2317
2318@implementation GSDeviceWhiteColor
2319
2320- (NSString *) colorSpaceName
2321{
2322  return NSDeviceWhiteColorSpace;
2323}
2324
2325- (NSColor*) initWithDeviceWhite: (CGFloat)white
2326			   alpha: (CGFloat)alpha
2327{
2328  if (white < 0.0) white = 0.0;
2329  else if (white > 1.0) white = 1.0;
2330  _white_component = white;
2331
2332  if (alpha < 0.0) alpha = 0.0;
2333  else if (alpha > 1.0) alpha = 1.0;
2334  _alpha_component = alpha;
2335
2336  return self;
2337}
2338
2339@end
2340
2341@implementation GSCalibratedWhiteColor
2342
2343- (NSString *) colorSpaceName
2344{
2345  return NSCalibratedWhiteColorSpace;
2346}
2347
2348- (NSColor*) initWithCalibratedWhite: (CGFloat)white
2349			       alpha: (CGFloat)alpha
2350{
2351  if (white < 0.0) white = 0.0;
2352  else if (white > 1.0) white = 1.0;
2353  _white_component = white;
2354
2355  if (alpha < 0.0) alpha = 0.0;
2356  else if (alpha > 1.0) alpha = 1.0;
2357  _alpha_component = alpha;
2358
2359  return self;
2360}
2361
2362@end
2363
2364@implementation GSDeviceCMYKColor
2365
2366- (NSColor*) initWithDeviceCyan: (CGFloat)cyan
2367			magenta: (CGFloat)magenta
2368			 yellow: (CGFloat)yellow
2369			  black: (CGFloat)black
2370			  alpha: (CGFloat)alpha
2371{
2372  if (cyan < 0.0) cyan = 0.0;
2373  else if (cyan > 1.0) cyan = 1.0;
2374  _cyan_component = cyan;
2375
2376  if (magenta < 0.0) magenta = 0.0;
2377  else if (magenta > 1.0) magenta = 1.0;
2378  _magenta_component = magenta;
2379
2380  if (yellow < 0.0) yellow = 0.0;
2381  else if (yellow > 1.0) yellow = 1.0;
2382  _yellow_component = yellow;
2383
2384  if (black < 0.0) black = 0.0;
2385  else if (black > 1.0) black = 1.0;
2386  _black_component = black;
2387
2388  if (alpha < 0.0) alpha = 0.0;
2389  else if (alpha > 1.0) alpha = 1.0;
2390  _alpha_component = alpha;
2391
2392  return self;
2393}
2394
2395- (NSString *) colorSpaceName
2396{
2397  return NSDeviceCMYKColorSpace;
2398}
2399
2400- (CGFloat) alphaComponent
2401{
2402  return _alpha_component;
2403}
2404
2405- (CGFloat) blackComponent
2406{
2407  return _black_component;
2408}
2409
2410- (CGFloat) cyanComponent
2411{
2412  return _cyan_component;
2413}
2414
2415- (CGFloat) magentaComponent
2416{
2417  return _magenta_component;
2418}
2419
2420- (CGFloat) yellowComponent
2421{
2422  return _yellow_component;
2423}
2424
2425- (void) getComponents: (CGFloat *)components;
2426{
2427  components[0] = _cyan_component;
2428  components[1] = _magenta_component;
2429  components[2] = _yellow_component;
2430  components[3] = _black_component;
2431  components[4] = _alpha_component;
2432}
2433
2434- (NSInteger) numberOfComponents
2435{
2436  return 5;
2437}
2438
2439- (NSString*) description
2440{
2441  NSMutableString *desc;
2442
2443  /*
2444   *	We encode information in a dictionary
2445   *	format with meaningful keys.
2446   */
2447  desc = [NSMutableString stringWithCapacity: 128];
2448  [desc appendFormat: @"{ ColorSpace = \"%@\";", [self colorSpaceName]];
2449  [desc appendFormat: @" C = \"%g\";", (double)_cyan_component];
2450  [desc appendFormat: @" M = \"%g\";", (double)_magenta_component];
2451  [desc appendFormat: @" Y = \"%g\";", (double)_yellow_component];
2452  [desc appendFormat: @" K = \"%g\";", (double)_black_component];
2453  [desc appendFormat: @" Alpha = \"%g\"; }", (double)_alpha_component];
2454
2455  return desc;
2456}
2457
2458- (void) getCyan: (CGFloat*)cyan
2459	 magenta: (CGFloat*)magenta
2460	  yellow: (CGFloat*)yellow
2461	   black: (CGFloat*)black
2462	   alpha: (CGFloat*)alpha
2463{
2464  // Only set what is wanted
2465  if (cyan)
2466    *cyan = _cyan_component;
2467  if (magenta)
2468    *magenta = _magenta_component;
2469  if (yellow)
2470    *yellow = _yellow_component;
2471  if (black)
2472    *black = _black_component;
2473  if (alpha)
2474    *alpha = _alpha_component;
2475}
2476
2477- (BOOL) isEqual: (id)other
2478{
2479  if (other == self)
2480    return YES;
2481  if ([other isKindOfClass: [self class]] == NO
2482    || [other cyanComponent] != _cyan_component
2483    || [other magentaComponent] != _magenta_component
2484    || [other yellowComponent] != _yellow_component
2485    || [other blackComponent] != _black_component
2486    || [other alphaComponent] != _alpha_component)
2487    {
2488      return NO;
2489    }
2490  return YES;
2491}
2492
2493- (NSColor*) colorWithAlphaComponent: (CGFloat)alpha
2494{
2495  GSDeviceCMYKColor *aCopy;
2496
2497  if (alpha < 0.0) alpha = 0.0;
2498  else if (alpha > 1.0) alpha = 1.0;
2499
2500  if (alpha == _alpha_component)
2501    return self;
2502
2503  aCopy = (GSDeviceCMYKColor*)NSCopyObject(self, 0, NSDefaultMallocZone());
2504
2505  if (aCopy)
2506    {
2507      aCopy->_alpha_component = alpha;
2508    }
2509
2510  return AUTORELEASE(aCopy);
2511}
2512
2513- (NSColor*) colorUsingColorSpaceName: (NSString *)colorSpace
2514			       device: (NSDictionary *)deviceDescription
2515{
2516  if (colorSpace == nil)
2517    {
2518      if (deviceDescription != nil)
2519	colorSpace = [deviceDescription objectForKey: NSDeviceColorSpaceName];
2520      if (colorSpace == nil)
2521        colorSpace = NSCalibratedRGBColorSpace;
2522    }
2523  if ([colorSpace isEqualToString: [self colorSpaceName]])
2524    {
2525      return self;
2526    }
2527
2528  if ([colorSpace isEqualToString: NSNamedColorSpace])
2529    {
2530      // FIXME: We cannot convert to named color space.
2531      return nil;
2532    }
2533
2534  if ([colorSpace isEqualToString: NSCalibratedRGBColorSpace])
2535    {
2536      double c = _cyan_component;
2537      double m = _magenta_component;
2538      double y = _yellow_component;
2539      double white = 1 - _black_component;
2540
2541      return [NSColor colorWithCalibratedRed: (c > white ? 0 : white - c)
2542		      green: (m > white ? 0 : white - m)
2543		      blue: (y > white ? 0 : white - y)
2544		      alpha: _alpha_component];
2545    }
2546
2547  if ([colorSpace isEqualToString: NSDeviceRGBColorSpace])
2548    {
2549      double c = _cyan_component;
2550      double m = _magenta_component;
2551      double y = _yellow_component;
2552      double white = 1 - _black_component;
2553
2554      return [NSColor colorWithDeviceRed: (c > white ? 0 : white - c)
2555		      green: (m > white ? 0 : white - m)
2556		      blue: (y > white ? 0 : white - y)
2557		      alpha: _alpha_component];
2558    }
2559
2560  if ([colorSpace isEqualToString: NSCalibratedWhiteColorSpace]
2561    || [colorSpace isEqualToString: NSCalibratedBlackColorSpace])
2562    {
2563      return [NSColor colorWithCalibratedWhite: 1 - _black_component -
2564	(_cyan_component + _magenta_component + _yellow_component)/3
2565	alpha: _alpha_component];
2566    }
2567
2568  if ([colorSpace isEqualToString: NSDeviceWhiteColorSpace]
2569    || [colorSpace isEqualToString: NSDeviceBlackColorSpace])
2570    {
2571      return [NSColor colorWithDeviceWhite: 1 - _black_component -
2572	(_cyan_component + _magenta_component + _yellow_component)/3
2573	alpha: _alpha_component];
2574    }
2575
2576  return nil;
2577}
2578
2579- (void) set
2580{
2581  NSDebugLLog(@"NSColor", @"CMYK %g %g %g %g\n",
2582	      (double)_cyan_component, (double)_magenta_component,
2583	      (double)_yellow_component, (double)_black_component);
2584  PSsetcmykcolor(_cyan_component, _magenta_component,
2585		 _yellow_component, _black_component);
2586
2587  // Should we check the ignore flag here?
2588  PSsetalpha(_alpha_component);
2589}
2590
2591//
2592// NSCoding protocol
2593//
2594- (void) encodeWithCoder: (NSCoder*)aCoder
2595{
2596  if ([aCoder allowsKeyedCoding])
2597    {
2598      NSString *str;
2599
2600      [aCoder encodeInt: 5 forKey: @"NSColorSpace"];
2601      if (_alpha_component == 1.0)
2602        {
2603          str = [[NSString alloc] initWithFormat: @"%g %g %g %g", (double)_cyan_component,
2604                                  (double)_magenta_component, (double)_yellow_component,
2605                                  (double)_black_component];
2606        }
2607      else
2608        {
2609          str = [[NSString alloc] initWithFormat: @"%g %g %g %g %g", (double)_cyan_component,
2610                                  (double)_magenta_component, (double)_yellow_component,
2611                                  (double)_black_component, (double)_alpha_component];
2612        }
2613      [aCoder encodeBytes: (const uint8_t*)[str cString]
2614		   length: [str cStringLength]
2615		   forKey: @"NSCYMK"];
2616      RELEASE(str);
2617    }
2618  else
2619    {
2620      float c = _cyan_component;
2621      float m = _magenta_component;
2622      float y = _yellow_component;
2623      float k = _black_component;
2624      float a = _alpha_component;
2625      [aCoder encodeObject: [self colorSpaceName]];
2626      [aCoder encodeValueOfObjCType: @encode(float) at: &c];
2627      [aCoder encodeValueOfObjCType: @encode(float) at: &m];
2628      [aCoder encodeValueOfObjCType: @encode(float) at: &y];
2629      [aCoder encodeValueOfObjCType: @encode(float) at: &k];
2630      [aCoder encodeValueOfObjCType: @encode(float) at: &a];
2631    }
2632}
2633
2634- (id) initWithCoder: (NSCoder*)aDecoder
2635{
2636  // FIXME: Implement keyed decoding!
2637
2638  float c, m, y, k, a;
2639  [aDecoder decodeValueOfObjCType: @encode(float) at: &c];
2640  [aDecoder decodeValueOfObjCType: @encode(float) at: &m];
2641  [aDecoder decodeValueOfObjCType: @encode(float) at: &y];
2642  [aDecoder decodeValueOfObjCType: @encode(float) at: &k];
2643  [aDecoder decodeValueOfObjCType: @encode(float) at: &a];
2644  _cyan_component = c;
2645  _magenta_component = m;
2646  _yellow_component = y;
2647  _black_component = k;
2648  _alpha_component = a;
2649
2650  return self;
2651}
2652
2653@end
2654
2655// RGB/HSB colours
2656@implementation GSRGBColor
2657
2658- (CGFloat) alphaComponent
2659{
2660  return _alpha_component;
2661}
2662
2663- (CGFloat) redComponent
2664{
2665  return _red_component;
2666}
2667
2668- (CGFloat) greenComponent
2669{
2670  return _green_component;
2671}
2672
2673- (CGFloat) blueComponent
2674{
2675  return _blue_component;
2676}
2677
2678- (CGFloat) hueComponent
2679{
2680  return _hue_component;
2681}
2682
2683- (CGFloat) saturationComponent
2684{
2685  return _saturation_component;
2686}
2687
2688- (CGFloat) brightnessComponent
2689{
2690  return _brightness_component;
2691}
2692
2693- (void) getComponents: (CGFloat *)components;
2694{
2695  components[0] = _red_component;
2696  components[1] = _green_component;
2697  components[2] = _blue_component;
2698  components[3] = _alpha_component;
2699}
2700
2701- (NSInteger) numberOfComponents
2702{
2703  return 4;
2704}
2705
2706- (void) getHue: (CGFloat*)hue
2707     saturation: (CGFloat*)saturation
2708     brightness: (CGFloat*)brightness
2709	  alpha: (CGFloat*)alpha
2710{
2711  // Only set what is wanted
2712  if (hue)
2713    *hue = _hue_component;
2714  if (saturation)
2715    *saturation = _saturation_component;
2716  if (brightness)
2717    *brightness = _brightness_component;
2718  if (alpha)
2719    *alpha = _alpha_component;
2720}
2721
2722- (void) getRed: (CGFloat*)red
2723	  green: (CGFloat*)green
2724	   blue: (CGFloat*)blue
2725	  alpha: (CGFloat*)alpha
2726{
2727  // Only set what is wanted
2728  if (red)
2729    *red = _red_component;
2730  if (green)
2731    *green = _green_component;
2732  if (blue)
2733    *blue = _blue_component;
2734  if (alpha)
2735    *alpha = _alpha_component;
2736}
2737
2738- (BOOL) isEqual: (id)other
2739{
2740  if (other == self)
2741    return YES;
2742  if ([other isKindOfClass: [self class]] == NO
2743    || [other redComponent] != _red_component
2744    || [other greenComponent] != _green_component
2745    || [other blueComponent] != _blue_component
2746    || [other alphaComponent] != _alpha_component)
2747    {
2748      return NO;
2749    }
2750  return YES;
2751}
2752
2753- (NSColor*) colorWithAlphaComponent: (CGFloat)alpha
2754{
2755  GSRGBColor *aCopy;
2756
2757  if (alpha < 0.0) alpha = 0.0;
2758  else if (alpha > 1.0) alpha = 1.0;
2759
2760  if (alpha == _alpha_component)
2761    return self;
2762
2763  aCopy = (GSRGBColor*)NSCopyObject(self, 0, NSDefaultMallocZone());
2764
2765  if (aCopy)
2766    {
2767      aCopy->_alpha_component = alpha;
2768    }
2769
2770  return AUTORELEASE(aCopy);
2771}
2772
2773- (NSColor*) colorUsingColorSpaceName: (NSString *)colorSpace
2774			       device: (NSDictionary *)deviceDescription
2775{
2776  if (colorSpace == nil)
2777    {
2778      if (deviceDescription != nil)
2779	colorSpace = [deviceDescription objectForKey: NSDeviceColorSpaceName];
2780      if (colorSpace == nil)
2781        colorSpace = NSCalibratedRGBColorSpace;
2782    }
2783  if ([colorSpace isEqualToString: [self colorSpaceName]])
2784    {
2785      return self;
2786    }
2787
2788  if ([colorSpace isEqualToString: NSNamedColorSpace])
2789    {
2790      // FIXME: We cannot convert to named color space.
2791      return nil;
2792    }
2793
2794  if ([colorSpace isEqualToString: NSCalibratedRGBColorSpace])
2795    {
2796      return [NSColor colorWithCalibratedRed: _red_component
2797		      green: _green_component
2798		      blue: _blue_component
2799		      alpha: _alpha_component];
2800    }
2801
2802  if ([colorSpace isEqualToString: NSDeviceRGBColorSpace])
2803    {
2804      return [NSColor colorWithDeviceRed: _red_component
2805		      green: _green_component
2806		      blue: _blue_component
2807		      alpha: _alpha_component];
2808    }
2809
2810  if ([colorSpace isEqualToString: NSCalibratedWhiteColorSpace]
2811    || [colorSpace isEqualToString: NSCalibratedBlackColorSpace])
2812    {
2813      return [NSColor colorWithCalibratedWhite:
2814	(_red_component + _green_component + _blue_component)/3
2815	alpha: _alpha_component];
2816    }
2817
2818  if ([colorSpace isEqualToString: NSDeviceWhiteColorSpace]
2819    || [colorSpace isEqualToString: NSDeviceBlackColorSpace])
2820    {
2821      return [NSColor colorWithDeviceWhite:
2822	(_red_component + _green_component + _blue_component)/3
2823	alpha: _alpha_component];
2824    }
2825
2826  if ([colorSpace isEqualToString: NSDeviceCMYKColorSpace])
2827    {
2828      return [NSColor colorWithDeviceCyan: 1 - _red_component
2829				  magenta: 1 - _green_component
2830				   yellow: 1 - _blue_component
2831				    black: 0.0
2832				    alpha: _alpha_component];
2833    }
2834
2835  return nil;
2836}
2837
2838- (NSString*) description
2839{
2840  NSMutableString *desc;
2841
2842  /*
2843   *	For a simple RGB color without alpha, we use a shorthand description
2844   *	consisting of the three component values in a quoted string.
2845   */
2846  if (_alpha_component == 1.0)
2847    return [NSString stringWithFormat: @"%g %g %g",
2848		     (double)_red_component, (double)_green_component, (double)_blue_component];
2849
2850  /*
2851   *	For more complex color values - we encode information in a dictionary
2852   *	format with meaningful keys.
2853   */
2854  desc = [NSMutableString stringWithCapacity: 128];
2855  [desc appendFormat: @"{ ColorSpace = \"%@\";", [self colorSpaceName]];
2856  [desc appendFormat: @" R = \"%g\";", (double)_red_component];
2857  [desc appendFormat: @" G = \"%g\";", (double)_green_component];
2858  [desc appendFormat: @" B = \"%g\";", (double)_blue_component];
2859  [desc appendFormat: @" Alpha = \"%g\"; }", (double)_alpha_component];
2860  return desc;
2861}
2862
2863- (void) set
2864{
2865  /* This should only be in GSDeviceRGBColor,
2866   * but is here to keep old code working.
2867   */
2868  NSDebugLLog(@"NSColor", @"RGB %g %g %g\n", (double)_red_component,
2869	      (double)_green_component, (double)_blue_component);
2870  PSsetrgbcolor(_red_component, _green_component,
2871		_blue_component);
2872  // Should we check the ignore flag here?
2873  PSsetalpha(_alpha_component);
2874}
2875
2876- (void) setFill
2877{
2878  int num = [self numberOfComponents];
2879  CGFloat values[num];
2880  NSGraphicsContext *ctxt = GSCurrentContext();
2881
2882  [ctxt GSSetFillColorspace: [self colorSpace]];
2883  [self getComponents: values];
2884  [ctxt GSSetFillColor: values];
2885}
2886
2887- (void) setStroke
2888{
2889  int num = [self numberOfComponents];
2890  CGFloat values[num];
2891  NSGraphicsContext *ctxt = GSCurrentContext();
2892
2893  [ctxt GSSetStrokeColorspace: [self colorSpace]];
2894  [self getComponents: values];
2895  [ctxt GSSetStrokeColor: values];
2896}
2897
2898//
2899// NSCoding protocol
2900//
2901- (void) encodeWithCoder: (NSCoder*)aCoder
2902{
2903  if ([aCoder allowsKeyedCoding])
2904    {
2905      NSString *str;
2906
2907      if ([[self colorSpaceName] isEqualToString: NSCalibratedRGBColorSpace])
2908        {
2909	  [aCoder encodeInt: 1 forKey: @"NSColorSpace"];
2910	}
2911      else
2912        {
2913	  [aCoder encodeInt: 2 forKey: @"NSColorSpace"];
2914	}
2915
2916      if (_alpha_component == 1.0)
2917        {
2918          str = [[NSString alloc] initWithFormat: @"%g %g %g", (double)_red_component,
2919                                  (double)_green_component, (double)_blue_component];
2920        }
2921      else
2922        {
2923          str = [[NSString alloc] initWithFormat: @"%g %g %g %g", (double)_red_component,
2924                                  (double)_green_component, (double)_blue_component,
2925				  (double)_alpha_component];
2926        }
2927      [aCoder encodeBytes: (const uint8_t*)[str cString]
2928	      length: [str cStringLength]
2929	      forKey: @"NSRGB"];
2930      RELEASE(str);
2931    }
2932  else
2933    {
2934      float red = _red_component;
2935      float green = _green_component;
2936      float blue = _blue_component;
2937      float hue = _hue_component;
2938      float saturation = _saturation_component;
2939      float brightness = _brightness_component;
2940      float alpha = _alpha_component;
2941      [aCoder encodeObject: [self colorSpaceName]];
2942      [aCoder encodeValueOfObjCType: @encode(float) at: &red];
2943      [aCoder encodeValueOfObjCType: @encode(float) at: &green];
2944      [aCoder encodeValueOfObjCType: @encode(float) at: &blue];
2945      [aCoder encodeValueOfObjCType: @encode(float) at: &hue];
2946      [aCoder encodeValueOfObjCType: @encode(float) at: &saturation];
2947      [aCoder encodeValueOfObjCType: @encode(float) at: &brightness];
2948      [aCoder encodeValueOfObjCType: @encode(float) at: &alpha];
2949    }
2950}
2951
2952- (id) initWithCoder: (NSCoder*)aDecoder
2953{
2954  float red, green, blue, hue, saturation, brightness, alpha;
2955  [aDecoder decodeValueOfObjCType: @encode(float) at: &red];
2956  [aDecoder decodeValueOfObjCType: @encode(float) at: &green];
2957  [aDecoder decodeValueOfObjCType: @encode(float) at: &blue];
2958  [aDecoder decodeValueOfObjCType: @encode(float) at: &hue];
2959  [aDecoder decodeValueOfObjCType: @encode(float) at: &saturation];
2960  [aDecoder decodeValueOfObjCType: @encode(float) at: &brightness];
2961  [aDecoder decodeValueOfObjCType: @encode(float) at: &alpha];
2962  _red_component = red;
2963  _green_component = green;
2964  _blue_component = blue;
2965  _hue_component = hue;
2966  _saturation_component = saturation;
2967  _brightness_component = brightness;
2968  _alpha_component = alpha;
2969  return self;
2970}
2971
2972@end
2973
2974@implementation GSDeviceRGBColor
2975
2976- (NSString *) colorSpaceName
2977{
2978  return NSDeviceRGBColorSpace;
2979}
2980
2981- (NSColor*) initWithDeviceRed: (CGFloat)red
2982			 green: (CGFloat)green
2983			  blue: (CGFloat)blue
2984			 alpha: (CGFloat)alpha
2985{
2986  if (red < 0.0) red = 0.0;
2987  else if (red > 1.0) red = 1.0;
2988  _red_component = red;
2989
2990  if (green < 0.0) green = 0.0;
2991  else if (green > 1.0) green = 1.0;
2992  _green_component = green;
2993
2994  if (blue < 0.0) blue = 0.0;
2995  else if (blue > 1.0) blue = 1.0;
2996  _blue_component = blue;
2997
2998  {
2999    CGFloat r = _red_component;
3000    CGFloat g = _green_component;
3001    CGFloat b = _blue_component;
3002
3003    if (r == g && r == b)
3004      {
3005	_hue_component = 0;
3006	_saturation_component = 0;
3007	_brightness_component = r;
3008      }
3009    else
3010      {
3011	double H;
3012	double V;
3013	double Temp;
3014	double diff;
3015
3016	V = (r > g ? r : g);
3017	V = (b > V ? b : V);
3018	Temp = (r < g ? r : g);
3019	Temp = (b < Temp ? b : Temp);
3020	diff = V - Temp;
3021	if (V == r)
3022	  {
3023	    H = (g - b)/diff;
3024	  }
3025	else if (V == g)
3026	  {
3027	    H = (b - r)/diff + 2;
3028	  }
3029	else
3030	  {
3031	    H = (r - g)/diff + 4;
3032	  }
3033	if (H < 0)
3034	  {
3035	    H += 6;
3036	  }
3037	_hue_component = H/6;
3038	_saturation_component = diff/V;
3039	_brightness_component = V;
3040      }
3041  }
3042
3043  if (alpha < 0.0) alpha = 0.0;
3044  else if (alpha > 1.0) alpha = 1.0;
3045  _alpha_component = alpha;
3046
3047  return self;
3048}
3049
3050- (NSColor*) initWithDeviceHue: (CGFloat)hue
3051		    saturation: (CGFloat)saturation
3052		    brightness: (CGFloat)brightness
3053			 alpha: (CGFloat)alpha;
3054{
3055  if (hue < 0.0) hue = 0.0;
3056  else if (hue > 1.0) hue = 1.0;
3057  _hue_component = hue;
3058
3059  if (saturation < 0.0) saturation = 0.0;
3060  else if (saturation > 1.0) saturation = 1.0;
3061  _saturation_component = saturation;
3062
3063  if (brightness < 0.0) brightness = 0.0;
3064  else if (brightness > 1.0) brightness = 1.0;
3065  _brightness_component = brightness;
3066
3067  {
3068    int	I = (int)(hue * 6);
3069    double V = brightness;
3070    double S = saturation;
3071    double F = (hue * 6) - I;
3072    double M = V * (1 - S);
3073    double N = V * (1 - S * F);
3074    double K = M - N + V;
3075    double R, G, B;
3076
3077    switch (I)
3078      {
3079	default: R = V; G = K; B = M; break;
3080	  case 1: R = N; G = V; B = M; break;
3081	  case 2: R = M; G = V; B = K; break;
3082	  case 3: R = M; G = N; B = V; break;
3083	  case 4: R = K; G = M; B = V; break;
3084	  case 5: R = V; G = M; B = N; break;
3085      }
3086    _red_component = (CGFloat)R;
3087    _green_component = (CGFloat)G;
3088    _blue_component = (CGFloat)B;
3089  }
3090
3091  if (alpha < 0.0) alpha = 0.0;
3092  else if (alpha > 1.0) alpha = 1.0;
3093  _alpha_component = alpha;
3094
3095  return self;
3096}
3097
3098@end
3099
3100@implementation GSCalibratedRGBColor
3101
3102- (NSString *) colorSpaceName
3103{
3104  return NSCalibratedRGBColorSpace;
3105}
3106
3107- (NSColor*) initWithCalibratedRed: (CGFloat)red
3108			     green: (CGFloat)green
3109			      blue: (CGFloat)blue
3110			     alpha: (CGFloat)alpha
3111{
3112  if (red < 0.0) red = 0.0;
3113  else if (red > 1.0) red = 1.0;
3114  _red_component = red;
3115
3116  if (green < 0.0) green = 0.0;
3117  else if (green > 1.0) green = 1.0;
3118  _green_component = green;
3119
3120  if (blue < 0.0) blue = 0.0;
3121  else if (blue > 1.0) blue = 1.0;
3122  _blue_component = blue;
3123
3124  {
3125    CGFloat r = _red_component;
3126    CGFloat g = _green_component;
3127    CGFloat b = _blue_component;
3128
3129    if (r == g && r == b)
3130      {
3131	_hue_component = 0;
3132	_saturation_component = 0;
3133	_brightness_component = r;
3134      }
3135    else
3136      {
3137	double H;
3138	double V;
3139	double Temp;
3140	double diff;
3141
3142	V = (r > g ? r : g);
3143	V = (b > V ? b : V);
3144	Temp = (r < g ? r : g);
3145	Temp = (b < Temp ? b : Temp);
3146	diff = V - Temp;
3147	if (V == r)
3148	  {
3149	    H = (g - b)/diff;
3150	  }
3151	else if (V == g)
3152	  {
3153	    H = (b - r)/diff + 2;
3154	  }
3155	else
3156	  {
3157	    H = (r - g)/diff + 4;
3158	  }
3159	if (H < 0)
3160	  {
3161	    H += 6;
3162	  }
3163	_hue_component = H/6;
3164	_saturation_component = diff/V;
3165	_brightness_component = V;
3166      }
3167  }
3168
3169  if (alpha < 0.0) alpha = 0.0;
3170  else if (alpha > 1.0) alpha = 1.0;
3171  _alpha_component = alpha;
3172
3173  return self;
3174}
3175
3176- (NSColor*) initWithCalibratedHue: (CGFloat)hue
3177			saturation: (CGFloat)saturation
3178			brightness: (CGFloat)brightness
3179			     alpha: (CGFloat)alpha;
3180{
3181  if (hue < 0.0) hue = 0.0;
3182  else if (hue > 1.0) hue = 1.0;
3183  _hue_component = hue;
3184
3185  if (saturation < 0.0) saturation = 0.0;
3186  else if (saturation > 1.0) saturation = 1.0;
3187  _saturation_component = saturation;
3188
3189  if (brightness < 0.0) brightness = 0.0;
3190  else if (brightness > 1.0) brightness = 1.0;
3191  _brightness_component = brightness;
3192
3193  {
3194    int	I = (int)(hue * 6);
3195    double V = brightness;
3196    double S = saturation;
3197    double F = (hue * 6) - I;
3198    double M = V * (1 - S);
3199    double N = V * (1 - S * F);
3200    double K = M - N + V;
3201    double R, G, B;
3202
3203    switch (I)
3204      {
3205	default: R = V; G = K; B = M; break;
3206	  case 1: R = N; G = V; B = M; break;
3207	  case 2: R = M; G = V; B = K; break;
3208	  case 3: R = M; G = N; B = V; break;
3209	  case 4: R = K; G = M; B = V; break;
3210	  case 5: R = V; G = M; B = N; break;
3211      }
3212    _red_component = (CGFloat)R;
3213    _green_component = (CGFloat)G;
3214    _blue_component = (CGFloat)B;
3215  }
3216
3217  if (alpha < 0.0) alpha = 0.0;
3218  else if (alpha > 1.0) alpha = 1.0;
3219  _alpha_component = alpha;
3220
3221  return self;
3222}
3223
3224@end
3225
3226@implementation GSPatternColor
3227
3228- (NSColor*) initWithPatternImage: (NSImage*) pattern;
3229{
3230  ASSIGN(_pattern, pattern);
3231
3232  return self;
3233}
3234
3235- (void) dealloc
3236{
3237  RELEASE(_pattern);
3238  [super dealloc];
3239}
3240
3241- (NSString *) colorSpaceName
3242{
3243  return NSPatternColorSpace;
3244}
3245
3246- (NSImage*) patternImage
3247{
3248  return _pattern;
3249}
3250
3251- (NSString*) description
3252{
3253  NSMutableString *desc;
3254
3255  /*
3256   *	We encode information in a dictionary
3257   *	format with meaningful keys.
3258   */
3259  desc = [NSMutableString stringWithCapacity: 128];
3260  [desc appendFormat: @"{ ColorSpace = \"%@\";", [self colorSpaceName]];
3261  [desc appendFormat: @" Pattern = \"%@\"; }", [_pattern description]];
3262
3263  return desc;
3264}
3265
3266- (NSUInteger) hash
3267{
3268  return [_pattern hash];
3269}
3270
3271- (BOOL) isEqual: (id)other
3272{
3273  if (other == self)
3274    return YES;
3275  if ([other isKindOfClass: [self class]] == NO
3276    || [[other patternImage] isEqual: _pattern] == NO)
3277    {
3278      return NO;
3279    }
3280  return YES;
3281}
3282
3283- (id) copyWithZone: (NSZone*)aZone
3284{
3285  if (NSShouldRetainWithZone(self, aZone))
3286    {
3287      return RETAIN(self);
3288    }
3289  else
3290    {
3291      GSPatternColor *aCopy = (GSPatternColor*)NSCopyObject(self, 0, aZone);
3292
3293      aCopy->_pattern = [_pattern copyWithZone: aZone];
3294      return aCopy;
3295    }
3296}
3297
3298- (void) set
3299{
3300  [GSCurrentContext() GSSetPatterColor: _pattern];
3301}
3302
3303//
3304// NSCoding protocol
3305//
3306- (void) encodeWithCoder: (NSCoder*)aCoder
3307{
3308  if ([aCoder allowsKeyedCoding])
3309    {
3310      [aCoder encodeInt: 10 forKey: @"NSColorSpace"];
3311      [aCoder encodeObject: _pattern forKey: @"NSImage"];
3312    }
3313  else
3314    {
3315      [aCoder encodeObject: [self colorSpaceName]];
3316      [aCoder encodeObject: _pattern];
3317    }
3318}
3319
3320- (id) initWithCoder: (NSCoder*)aDecoder
3321{
3322  [aDecoder decodeValueOfObjCType: @encode(id) at: &_pattern];
3323
3324  return self;
3325}
3326
3327@end
3328
3329//
3330// Implementation of the NSCoder additions
3331//
3332@implementation NSCoder (NSCoderAdditions)
3333
3334//
3335// Converting an archived NXColor to an NSColor
3336//
3337- (NSColor*) decodeNXColor
3338{
3339  // FIXME
3340  return nil;
3341}
3342
3343@end
3344