1/*
2 * Copyright 2001-2009, Haiku.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		DarkWyrm <bpmagic@columbus.rr.com>
7 *		Stephan A��mus <superstippi@gmx.de>
8 *		Axel D��rfler, axeld@pinc-software.de
9 */
10
11
12/*!	Although descended from ServerBitmaps, ServerCursors are not handled by
13	the BitmapManager, but the CursorManager instead. Until they have been
14	attached to a CursorManager, you can delete cursors like any other object.
15
16	Unlike BeOS, cursors can be any size or color space, and this class
17	accomodates and expands the BeOS API.
18*/
19
20
21#include "CursorManager.h"
22#include "ServerCursor.h"
23
24#include <ByteOrder.h>
25
26#include <new>
27#include <stdio.h>
28
29
30using std::nothrow;
31
32
33/*!	\brief Constructor
34
35	\param r Size of the cursor
36	\param cspace Color space of the cursor
37	\param flags ServerBitmap flags. See Bitmap.h.
38	\param hotspot Hotspot of the cursor
39	\param bytesperline Bytes per row for the cursor. See
40		ServerBitmap::ServerBitmap()
41
42*/
43ServerCursor::ServerCursor(BRect r, color_space format, int32 flags,
44		BPoint hotspot, int32 bytesPerRow, screen_id screen)
45	:
46	ServerBitmap(r, format, flags, bytesPerRow, screen),
47	fHotSpot(hotspot),
48	fOwningTeam(-1),
49	fCursorData(NULL),
50	fManager(NULL)
51{
52	fHotSpot.ConstrainTo(Bounds());
53	AllocateBuffer();
54}
55
56
57/*!	\brief Constructor
58	\param data Pointer to 68-byte cursor data array. See BeBook entry for
59		BCursor for details
60*/
61ServerCursor::ServerCursor(const uint8* data)
62	:
63	ServerBitmap(BRect(0, 0, 15, 15), B_RGBA32, 0),
64	fHotSpot(0, 0),
65	fOwningTeam(-1),
66	fCursorData(NULL),
67	fManager(NULL)
68{
69	// 68-byte array used in BeOS for holding cursors.
70	// This API has serious problems and should be deprecated (but supported)
71	// in R2
72
73	// Now that we have all the setup, we're going to map (for now) the cursor
74	// to RGBA32 (little endian). Eventually, there will be support for 16 and
75	// 8-bit depths
76	// NOTE: review this once we have working PPC graphics cards (big endian).
77	if (data) {
78		AllocateBuffer();
79		uint8* buffer = Bits();
80		if (!buffer)
81			return;
82
83		uint16* cursorBits = (uint16*)(data + 4);
84		uint16* transparencyBits = (uint16*)(data + 36);
85		fHotSpot.Set(data[3], data[2]);
86
87		// for each row in the cursor data
88		for (int32 j = 0; j < 16; j++) {
89			uint32* bits = (uint32*)(buffer + (j * BytesPerRow()));
90
91			// On intel, our bytes end up swapped, so we must swap them back
92			uint16 cursorLine = __swap_int16(cursorBits[j]);
93			uint16 transparencyLine = __swap_int16(transparencyBits[j]);
94
95			uint16 mask = 1 << 15;
96
97			// for each column in each row of cursor data
98			for (int32 i = 0; i < 16; i++, mask >>= 1) {
99				// Get the values and dump them to the bitmap
100				if (cursorLine & mask)
101					bits[i] = 0xff000000; // black
102				else if (transparencyLine & mask)
103					bits[i] = 0xffffffff; // white
104				else
105					bits[i] = 0x00000000; // transparent
106			}
107		}
108
109		// remember cursor data for later
110		fCursorData = new (nothrow) uint8[68];
111		if (fCursorData)
112			memcpy(fCursorData, data, 68);
113
114	} else {
115		fWidth = 0;
116		fHeight = 0;
117		fBytesPerRow = 0;
118		fSpace = B_NO_COLOR_SPACE;
119	}
120}
121
122
123/*!	\brief Constructor
124	\param data Pointer to bitmap data in memory,
125	the padding bytes should be contained when format less than 32 bpp.
126*/
127ServerCursor::ServerCursor(const uint8* alreadyPaddedData, uint32 width,
128		uint32 height, color_space format)
129	:
130	ServerBitmap(BRect(0, 0, width - 1, height - 1), format, 0),
131	fHotSpot(0, 0),
132	fOwningTeam(-1),
133	fCursorData(NULL),
134	fManager(NULL)
135{
136	AllocateBuffer();
137	if (Bits())
138		memcpy(Bits(), alreadyPaddedData, BitsLength());
139}
140
141
142/*!	\brief Copy constructor
143	\param cursor cursor to copy
144*/
145ServerCursor::ServerCursor(const ServerCursor* cursor)
146	:
147	ServerBitmap(cursor),
148	fHotSpot(0, 0),
149	fOwningTeam(-1),
150	fCursorData(NULL),
151	fManager(NULL)
152{
153	// TODO: Hm. I don't move this into the if clause,
154	// because it might break code elsewhere.
155	AllocateBuffer();
156
157	if (cursor) {
158		if (Bits() && cursor->Bits())
159			memcpy(Bits(), cursor->Bits(), BitsLength());
160		fHotSpot = cursor->fHotSpot;
161		if (cursor->fCursorData) {
162			fCursorData = new (nothrow) uint8[68];
163			if (fCursorData)
164				memcpy(fCursorData, cursor->fCursorData, 68);
165		}
166	}
167}
168
169
170//!	Frees the heap space allocated for the cursor's image data
171ServerCursor::~ServerCursor()
172{
173	delete[] fCursorData;
174}
175
176
177/*!	\brief Sets the cursor's hotspot
178	\param pt New location of hotspot, constrained to the cursor's boundaries.
179*/
180void
181ServerCursor::SetHotSpot(BPoint hotSpot)
182{
183	fHotSpot = hotSpot;
184	fHotSpot.ConstrainTo(Bounds());
185}
186
187
188void
189ServerCursor::AttachedToManager(CursorManager* manager)
190{
191	fManager = manager;
192}
193
194
195void
196ServerCursor::LastReferenceReleased()
197{
198	if (fManager == NULL || fManager->RemoveCursor(this))
199		delete this;
200}
201
202