xref: /haiku/src/add-ons/accelerants/intel_extreme/cursor.cpp (revision 1214ef1b2100f2b3299fc9d8d6142e46f70a4c3f)
1 /*
2  * Copyright 2006, Haiku, Inc. All Rights Reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Axel Dörfler, axeld@pinc-software.de
7  */
8 
9 
10 #include "accelerant_protos.h"
11 #include "accelerant.h"
12 
13 #include <string.h>
14 
15 
16 status_t
17 intel_set_cursor_shape(uint16 width, uint16 height, uint16 hotX, uint16 hotY,
18 	uint8 *andMask, uint8 *xorMask)
19 {
20 	if (width > 64 || height > 64)
21 		return B_BAD_VALUE;
22 
23 	write32(INTEL_CURSOR_CONTROL, 0);
24 		// disable cursor
25 
26 	// In two-color mode, the data is ordered as follows (always 64 bit per line):
27 	//	plane 1: line 0 (AND mask)
28 	//	plane 0: line 0 (XOR mask)
29 	//	plane 1: line 1 (AND mask)
30 	//	...
31 	//
32 	// If the planes add to the value 0x2, the corresponding pixel is
33 	// transparent, for 0x3 it inverts the background, so only the first
34 	// two palette entries will be used (since we're using the 2 color mode).
35 
36 	uint8 *data = gInfo->cursor_memory;
37 	uint8 byteWidth = (width + 7) / 8;
38 
39 	for (int32 y = 0; y < height; y++) {
40 		for (int32 x = 0; x < byteWidth; x++) {
41 			data[16 * y + x] = andMask[byteWidth * y + x];
42 			data[16 * y + x + 8] = xorMask[byteWidth * y + x];
43 		}
44 	}
45 
46 	// We can only change the width of the pixel, but apparently
47 	// not the height (or at least I couldn't figure out how),
48 	// so we need to make the rest transparent
49 	for (uint32 y = height; y < 64; y++) {
50 		for (int32 x = 0; x < byteWidth; x++) {
51 			data[16 * y + x] = 0xff;
52 			data[16 * y + x + 8] = 0;
53 		}
54 	}
55 
56 	// set palette entries to white/black
57 	write32(INTEL_CURSOR_PALETTE + 0, 0x00ffffff);
58 	write32(INTEL_CURSOR_PALETTE + 4, 0);
59 
60 	gInfo->shared_info->cursor_format = CURSOR_FORMAT_2_COLORS;
61 
62 	write32(INTEL_CURSOR_CONTROL, CURSOR_ENABLED | gInfo->shared_info->cursor_format);
63 	write32(INTEL_CURSOR_SIZE, width);
64 		// TODO: I've no idea how to specify the height of the cursor - it seems to
65 		//	be always 64 pixels
66 
67 	write32(INTEL_CURSOR_BASE, (uint32)gInfo->shared_info->physical_graphics_memory
68 		+ gInfo->shared_info->cursor_buffer_offset);
69 
70 	// changing the hot point changes the cursor position, too
71 
72 	if (hotX != gInfo->shared_info->cursor_hot_x
73 		|| hotY != gInfo->shared_info->cursor_hot_y) {
74 		int32 x = read32(INTEL_CURSOR_POSITION);
75 		int32 y = x >> 16;
76 		x &= 0xffff;
77 
78 		if (x & CURSOR_POSITION_NEGATIVE)
79 			x = -(x & CURSOR_POSITION_MASK);
80 		if (y & CURSOR_POSITION_NEGATIVE)
81 			y = -(y & CURSOR_POSITION_MASK);
82 
83 		x += gInfo->shared_info->cursor_hot_x;
84 		y += gInfo->shared_info->cursor_hot_y;
85 
86 		gInfo->shared_info->cursor_hot_x = hotX;
87 		gInfo->shared_info->cursor_hot_y = hotY;
88 
89 		intel_move_cursor(x, y);
90 	}
91 
92 	return B_OK;
93 }
94 
95 
96 void
97 intel_move_cursor(uint16 _x, uint16 _y)
98 {
99 	int32 x = (int32)_x - gInfo->shared_info->cursor_hot_x;
100 	int32 y = (int32)_y - gInfo->shared_info->cursor_hot_x;
101 
102 	if (x < 0)
103 		x = -x | CURSOR_POSITION_NEGATIVE;
104 	if (y < 0)
105 		y = -y | CURSOR_POSITION_NEGATIVE;
106 
107 	write32(INTEL_CURSOR_POSITION, (y << 16) | x);
108 }
109 
110 
111 void
112 intel_show_cursor(bool isVisible)
113 {
114 	if (gInfo->shared_info->cursor_visible == isVisible)
115 		return;
116 
117 	write32(INTEL_CURSOR_CONTROL, (isVisible ? CURSOR_ENABLED : 0)
118 		| gInfo->shared_info->cursor_format);
119 	write32(INTEL_CURSOR_BASE, (uint32)gInfo->shared_info->physical_graphics_memory
120 		+ gInfo->shared_info->cursor_buffer_offset);
121 
122 	gInfo->shared_info->cursor_visible = isVisible;
123 }
124 
125