/**
NSCursor
Holds an image to use as a cursor
Copyright (C) 1996,1999,2001 Free Software Foundation, Inc.
Author: Scott Christley
Date: 1996
Author: Adam Fedor
Date: Dec 2001
This file is part of the GNUstep GUI Library.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; see the file COPYING.LIB.
If not, write to the Free Software Foundation,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include
#include
#include
#include "AppKit/NSColor.h"
#include "AppKit/NSCursor.h"
#include "AppKit/NSGraphics.h"
#include "AppKit/NSImage.h"
#include "AppKit/NSBitmapImageRep.h"
#include "GNUstepGUI/GSDisplayServer.h"
// Class variables
static NSMutableArray *gnustep_gui_cursor_stack;
static NSCursor *gnustep_gui_current_cursor;
static BOOL gnustep_gui_hidden_until_move;
static Class NSCursor_class;
static NSMutableDictionary *cursorDict = nil;
@implementation NSCursor
/*
* Class methods
*/
+ (void) initialize
{
if (self == [NSCursor class])
{
// Initial version
[self setVersion:1];
// Initialize class variables
NSCursor_class = self;
gnustep_gui_cursor_stack = [[NSMutableArray alloc] initWithCapacity: 2];
gnustep_gui_hidden_until_move = YES;
cursorDict = [NSMutableDictionary new];
[[self arrowCursor] push];
}
}
- (void *) _cid
{
return _cid;
}
- (void) _setCid: (void *)val
{
_cid = val;
}
- (void) _computeCid
{
void *c;
NSBitmapImageRep *rep;
if (_cursor_image == nil)
{
_cid = NULL;
return;
}
rep = (NSBitmapImageRep *)[_cursor_image bestRepresentationForDevice: nil];
/* FIXME: Handle cached image reps also */
if (!rep || ![rep respondsToSelector: @selector(samplesPerPixel)])
{
NSLog(@"NSCursor can only handle NSBitmapImageReps for now");
return;
}
if (_hot_spot.x >= [rep pixelsWide])
_hot_spot.x = [rep pixelsWide]-1;
if (_hot_spot.y >= [rep pixelsHigh])
_hot_spot.y = [rep pixelsHigh]-1;
[GSCurrentServer() imagecursor: _hot_spot
: [rep pixelsWide] : [rep pixelsHigh]
: [rep samplesPerPixel] : [rep bitmapData] : &c];
_cid = c;
}
/*
* Setting the Cursor
*/
+ (void) hide
{
[GSCurrentServer() hidecursor];
}
+ (void) pop
{
/*
* The object we pop is the current cursor
*/
if ([gnustep_gui_cursor_stack count] > 1)
{
[gnustep_gui_cursor_stack removeLastObject];
gnustep_gui_current_cursor = [gnustep_gui_cursor_stack lastObject];
NSDebugLLog(@"NSCursor", @"Cursor pop");
[gnustep_gui_current_cursor set];
}
}
+ (void) setHiddenUntilMouseMoves: (BOOL)flag
{
gnustep_gui_hidden_until_move = flag;
}
+ (BOOL) isHiddenUntilMouseMoves
{
return gnustep_gui_hidden_until_move;
}
+ (void) unhide
{
[GSCurrentServer() showcursor];
}
/*
* Getting the Cursor
*/
+ (NSCursor*) arrowCursor
{
NSString *name = @"GSArrowCursor";
NSCursor *cursor = [cursorDict objectForKey: name];
if (cursor == nil)
{
void *c;
cursor = [[NSCursor_class alloc] initWithImage: nil];
[GSCurrentServer() standardcursor: GSArrowCursor : &c];
[cursor _setCid: c];
[cursorDict setObject: cursor forKey: name];
RELEASE(cursor);
}
return cursor;
}
+ (NSCursor*) currentCursor
{
return gnustep_gui_current_cursor;
}
+ (NSCursor*) IBeamCursor
{
NSString *name = @"GSIBeamCursor";
NSCursor *cursor = [cursorDict objectForKey: name];
if (cursor == nil)
{
void *c;
cursor = [[NSCursor_class alloc] initWithImage: nil];
[GSCurrentServer() standardcursor: GSIBeamCursor : &c];
[cursor _setCid: c];
[cursorDict setObject: cursor forKey: name];
RELEASE(cursor);
}
return cursor;
}
+ (NSCursor*) greenArrowCursor
{
NSString *name = @"GSGreenArrowCursor";
NSCursor *cursor = [cursorDict objectForKey: name];
if (cursor == nil)
{
void *c;
cursor = [[NSCursor_class alloc] initWithImage: nil];
[GSCurrentServer() standardcursor: GSArrowCursor : &c];
[GSCurrentServer() setcursorcolor: [NSColor greenColor]
: [NSColor blackColor] : c];
[cursor _setCid: c];
[cursorDict setObject: cursor forKey: name];
RELEASE(cursor);
}
return cursor;
}
/*
* Initializing a New NSCursor Object
*/
- (id) init
{
return [self initWithImage: nil hotSpot: NSMakePoint(0,15)];
}
- (id) initWithImage: (NSImage *)newImage
{
return [self initWithImage: newImage
hotSpot: NSMakePoint(0,15)];
}
- (id) initWithImage: (NSImage *)newImage hotSpot: (NSPoint)hotSpot
{
//_is_set_on_mouse_entered = NO;
//_is_set_on_mouse_exited = NO;
_hot_spot = hotSpot;
[self setImage: newImage];
return self;
}
- (id)initWithImage:(NSImage *)newImage
foregroundColorHint:(NSColor *)fg
backgroundColorHint:(NSColor *)bg
hotSpot:(NSPoint)hotSpot
{
NSCursor *cursor = [self initWithImage: newImage hotSpot: hotSpot];
if (fg || bg)
{
if (bg == nil)
bg = [NSColor whiteColor];
if (fg == nil)
fg = [NSColor blackColor];
bg = [bg colorUsingColorSpaceName: NSDeviceRGBColorSpace];
fg = [fg colorUsingColorSpaceName: NSDeviceRGBColorSpace];
[GSCurrentServer() setcursorcolor: fg : bg : _cid];
}
return cursor;
}
- (void)dealloc
{
RELEASE (_cursor_image);
[super dealloc];
}
/*
* Defining the Cursor
*/
- (NSPoint) hotSpot
{
// FIXME: This wont work for the two standard cursor
return _hot_spot;
}
- (NSImage*) image
{
// FIXME: This wont work for the two standard cursor
return _cursor_image;
}
- (void) setHotSpot: (NSPoint)spot
{
_hot_spot = spot;
[self _computeCid];
}
- (void) setImage: (NSImage *)newImage
{
ASSIGN(_cursor_image, newImage);
[self _computeCid];
}
/*
* Setting the Cursor
*/
- (BOOL) isSetOnMouseEntered
{
return _is_set_on_mouse_entered;
}
- (BOOL) isSetOnMouseExited
{
return _is_set_on_mouse_exited;
}
- (void) mouseEntered: (NSEvent*)theEvent
{
if (_is_set_on_mouse_entered == YES)
{
[self set];
}
else if (_is_set_on_mouse_exited == NO)
{
/*
* Undocumented behavior - if a cursor is not set on exit or entry,
* we assume a push-pop situation instead.
*/
[self push];
}
}
- (void) mouseExited: (NSEvent*)theEvent
{
NSDebugLLog(@"NSCursor", @"Cursor mouseExited:");
if (_is_set_on_mouse_exited == YES)
{
[self set];
}
else if (_is_set_on_mouse_entered == NO)
{
/*
* Undocumented behavior - if a cursor is not set on exit or entry,
* we assume a push-pop situation instead.
*/
[self pop];
}
}
- (void) pop
{
[NSCursor_class pop];
}
- (void) push
{
[gnustep_gui_cursor_stack addObject: self];
[self set];
NSDebugLLog(@"NSCursor", @"Cursor push %p", _cid);
}
- (void) set
{
gnustep_gui_current_cursor = self;
if (_cid)
{
[GSCurrentServer() setcursorcolor: nil : nil : _cid];
}
}
- (void) setOnMouseEntered: (BOOL)flag
{
_is_set_on_mouse_entered = flag;
}
- (void) setOnMouseExited: (BOOL)flag
{
_is_set_on_mouse_exited = flag;
}
/*
* NSCoding protocol
*/
- (void) encodeWithCoder: (NSCoder*)aCoder
{
// FIXME: This wont work for the two standard cursor
[aCoder encodeValueOfObjCType: @encode(BOOL) at: &_is_set_on_mouse_entered];
[aCoder encodeValueOfObjCType: @encode(BOOL) at: &_is_set_on_mouse_exited];
[aCoder encodeObject: _cursor_image];
[aCoder encodePoint: _hot_spot];
}
- (id) initWithCoder: (NSCoder*)aDecoder
{
if ([aDecoder allowsKeyedCoding])
{
int type = 0;
NSPoint hotSpot;
if ([aDecoder containsValueForKey: @"NSCursorType"])
{
type = [aDecoder decodeIntForKey: @"NSCursorType"];
}
DESTROY(self);
// FIXME
if (type == 0)
{
self = [NSCursor arrowCursor];
}
else if (type == 1)
{
self = [NSCursor IBeamCursor];
}
else
{
// FIXME
self = [NSCursor arrowCursor];
}
if ([aDecoder containsValueForKey: @"NSHotSpot"])
{
hotSpot = [aDecoder decodePointForKey: @"NSHotSpot"];
}
}
else
{
[aDecoder decodeValueOfObjCType: @encode(BOOL) at: &_is_set_on_mouse_entered];
[aDecoder decodeValueOfObjCType: @encode(BOOL) at: &_is_set_on_mouse_exited];
_cursor_image = [aDecoder decodeObject];
_hot_spot = [aDecoder decodePoint];
[self _computeCid];
}
return self;
}
@end