1/*
2    SDL - Simple DirectMedia Layer
3    Copyright (C) 1997-2012 Sam Lantinga
4
5    This library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Library General Public
7    License as published by the Free Software Foundation; either
8    version 2 of the License, or (at your option) any later version.
9
10    This library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Library General Public License for more details.
14
15    You should have received a copy of the GNU Library General Public
16    License along with this library; if not, write to the Free
17    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18
19    Sam Lantinga
20    slouken@libsdl.org
21*/
22#include "SDL_config.h"
23
24/*
25     File added by Alan Buckley (alan_baa@hotmail.com) for RISC OS compatability
26	 27 March 2003
27
28     Implements mouse cursor shape definitions and positioning
29*/
30
31#include "SDL_mouse.h"
32#include "../../events/SDL_events_c.h"
33
34#include "SDL_riscosmouse_c.h"
35
36#include "kernel.h"
37#include "swis.h"
38
39static WMcursor *current_cursor = NULL;
40static WMcursor *defined_cursor = NULL;
41
42extern int mouseInWindow;
43
44/* Area to save cursor palette colours changed by SDL.
45   Actual values will be read before we change to the SDL cursor */
46static Uint8 wimp_cursor_palette[2][5] = {
47  {1, 25, 255, 255, 255},
48  {3, 25, 255, 255, 255}
49};
50
51static int cursor_palette_saved = 0;
52
53void WIMP_SaveCursorPalette();
54void WIMP_RestoreWimpCursor();
55void WIMP_SetSDLCursorPalette();
56
57
58void RISCOS_FreeWMCursor(_THIS, WMcursor *cursor)
59{
60    SDL_free(cursor->data);
61	SDL_free(cursor);
62}
63
64WMcursor *RISCOS_CreateWMCursor(_THIS,
65		Uint8 *data, Uint8 *mask, int w, int h, int hot_x, int hot_y)
66{
67	WMcursor *cursor;
68	Uint8 *cursor_data;
69	Uint8 *ptr;
70	int i,j,k;
71	int data_byte, mask_byte;
72
73	/* Check to make sure the cursor size is okay */
74	if ( (w > 32) || (h > 32) ) {
75		SDL_SetError("Only with width and height <= 32 pixels are allowed");
76		return(NULL);
77	}
78
79	/* Allocate the cursor */
80	cursor = (WMcursor *)SDL_malloc(sizeof(*cursor));
81	if ( cursor == NULL ) {
82		SDL_SetError("Out of memory");
83		return(NULL);
84	}
85
86	/* Note: SDL says width must be a multiple of 8 */
87	cursor_data = SDL_malloc(w/4 * h);
88	if (cursor_data == NULL)
89	{
90		SDL_free(cursor);
91		SDL_SetError("Out of memory");
92		return(NULL);
93	}
94
95	cursor->w = w;
96	cursor->h = h;
97	cursor->hot_x = hot_x;
98	cursor->hot_y = hot_y;
99	cursor->data = cursor_data;
100
101
102/* Data / Mask Resulting pixel on screen
103   0 / 1 White
104   1 / 1 Black
105   0 / 0 Transparent
106   1 / 0 Inverted color if possible, black if not.
107*/
108	ptr = cursor_data;
109
110	for ( i=0; i<h; ++i )
111	{
112		for (j = 0; j < w/8; ++j)
113		{
114			data_byte = *data;
115			mask_byte = *mask;
116			*ptr++ = 0; /* Sets whole byte transparent */
117			*ptr = 0;
118			for (k = 0; k < 8; k++)
119			{
120				(*ptr) <<= 2;
121				if (data_byte & 1) *ptr |= 3; /* Black or inverted */
122				else if(mask_byte & 1) *ptr |= 1; /* White */
123				if ((k&3) == 3) ptr--;
124				data_byte >>= 1;
125				mask_byte >>= 1;
126			}
127
128            ptr+=3;
129		    data++;
130		    mask++;
131		}
132	}
133
134	return(cursor);
135}
136
137int RISCOS_ShowWMCursor(_THIS, WMcursor *cursor)
138{
139	current_cursor = cursor;
140
141	if (cursor == NULL)
142	{
143		_kernel_osbyte(106,0,0);
144		defined_cursor = NULL;
145	} else
146	{
147        WMcursor *old_cursor = defined_cursor;
148
149		if (cursor != defined_cursor)
150		{
151			Uint8 cursor_def[10];
152
153			cursor_def[0] = 0;
154			cursor_def[1] = 2; /* Use shape number 2 */
155			cursor_def[2] = cursor->w/4; /* Width in bytes */
156			cursor_def[3] = cursor->h; /* Height (h) in pixels */
157			cursor_def[4] = cursor->hot_x; /* ActiveX in pixels from left */
158			cursor_def[5] = cursor->hot_y; /* ActiveY in pixels from top */
159			cursor_def[6] = ((int)(cursor->data) & 0xFF);       /* Least significant byte of pointer to data */
160			cursor_def[7] = ((int)(cursor->data) >> 8) & 0xFF;  /* ... */
161			cursor_def[8] = ((int)(cursor->data) >> 16) & 0xFF; /* ... */
162			cursor_def[9] = ((int)(cursor->data) >> 24) & 0xFF; /* Most significant byte of pointer to data */
163
164			if (_kernel_osword(21, (int *)cursor_def) != 0)
165			{
166				SDL_SetError("RISCOS couldn't create the cursor to show");
167				return(0);
168			}
169			defined_cursor = cursor;
170		}
171
172        if (old_cursor == NULL)
173        {
174            /* First time or reshow in window, so save/setup palette */
175            if (!cursor_palette_saved)
176            {
177                WIMP_SaveCursorPalette();
178            }
179            WIMP_SetSDLCursorPalette();
180        }
181
182        _kernel_osbyte(106, 2, 0);
183	}
184
185	return(1);
186}
187
188void FULLSCREEN_WarpWMCursor(_THIS, Uint16 x, Uint16 y)
189{
190	Uint8 move_block[5];
191	int eig_block[3];
192	_kernel_swi_regs regs;
193	int os_x, os_y;
194
195	eig_block[0] = 4;  /* X eig factor */
196	eig_block[1] = 5;  /* Y eig factor */
197	eig_block[2] = -1;  /* End of list of variables to request */
198
199    regs.r[0] = (int)eig_block;
200    regs.r[1] = (int)eig_block;
201    _kernel_swi(OS_ReadVduVariables, &regs, &regs);
202
203	os_x = x << eig_block[0];
204	os_y = y << eig_block[1];
205
206	move_block[0] = 3; /* Move cursor */
207	move_block[1] = os_x & 0xFF;
208	move_block[2] = (os_x >> 8) & 0xFF;
209	move_block[3] = os_y & 0xFF;
210	move_block[4] = (os_y >> 8) & 0xFF;
211
212	_kernel_osword(21, (int *)move_block);
213	SDL_PrivateMouseMotion(0, 0, x, y);
214}
215
216
217/* Reshow cursor when mouse re-enters the window */
218void WIMP_ReshowCursor(_THIS)
219{
220	defined_cursor = NULL;
221    cursor_palette_saved = 0;
222	RISCOS_ShowWMCursor(this, current_cursor);
223}
224
225void WIMP_WarpWMCursor(_THIS, Uint16 x, Uint16 y)
226{
227	_kernel_swi_regs regs;
228	int window_state[9];
229	char block[5];
230	int osX, osY;
231
232	window_state[0] = this->hidden->window_handle;
233	regs.r[1] = (unsigned int)window_state;
234	_kernel_swi(Wimp_GetWindowState, &regs, &regs);
235
236	 osX = (x << this->hidden->xeig) + window_state[1];
237	 osY = window_state[4] - (y << this->hidden->yeig);
238
239	block[0] = 3;
240	block[1] = osX & 0xFF;
241	block[2] = (osX >> 8) & 0xFF;
242	block[3] = osY & 0xFF;
243	block[4] = (osY >> 8) & 0xFF;
244
245	regs.r[0] = 21;
246	regs.r[1] = (int)block;
247	_kernel_swi(OS_Word, &regs, &regs);
248	SDL_PrivateMouseMotion(0, 0, x, y);
249}
250
251int WIMP_ShowWMCursor(_THIS, WMcursor *cursor)
252{
253	if (mouseInWindow) return RISCOS_ShowWMCursor(this, cursor);
254	else current_cursor = cursor;
255
256	return 1;
257}
258
259SDL_GrabMode RISCOS_GrabInput(_THIS, SDL_GrabMode mode)
260{
261   /* In fullscreen mode we don't need to do anything */
262   if (mode < SDL_GRAB_FULLSCREEN)
263   {
264      _kernel_swi_regs regs;
265      unsigned char block[9];
266      block[0] = 1; /* Define mouse cursor bounding block */
267
268      if ( mode == SDL_GRAB_OFF )
269      {
270         /* Clip to whole screen */
271
272         int r = (this->hidden->screen_width << this->hidden->xeig) - 1;
273         int t = (this->hidden->screen_height << this->hidden->yeig) - 1;
274
275	 block[1] = 0; block[2] = 0; /* Left*/
276         block[3] = 0; block[4] = 0; /* Bottom */
277         block[5] = r & 0xFF; block[6] = (r >> 8) & 0xFF; /* Right */
278         block[7] = t & 0xFF; block[8] = (t >> 8) & 0xFF; /* Top */
279      } else
280      {
281        /* Clip to window */
282       	unsigned char window_state[36];
283
284	*((int *)window_state) = this->hidden->window_handle;
285	regs.r[1] = (unsigned int)window_state;
286	_kernel_swi(Wimp_GetWindowState, &regs, &regs);
287
288        block[1] = window_state[4];
289        block[2] = window_state[5];
290        block[3] = window_state[8];
291        block[4] = window_state[9];
292        block[5] = window_state[12];
293        block[6] = window_state[13];
294        block[7] = window_state[16];
295        block[8] = window_state[17];
296
297      }
298
299      regs.r[0] = 21; /* OS word code */
300      regs.r[1] = (int)block;
301      _kernel_swi(OS_Word, &regs, &regs);
302   }
303
304   return mode;
305}
306
307/* Save mouse cursor palette to be restore when we are no longer
308   defining a cursor */
309
310void WIMP_SaveCursorPalette()
311{
312    _kernel_swi_regs regs;
313    int colour;
314
315    for (colour = 0; colour < 2; colour++)
316    {
317      regs.r[0] = (int)wimp_cursor_palette[colour][0];
318      regs.r[1] = 25;
319      /* Read settings with OS_ReadPalette */
320      if (_kernel_swi(0x2f, &regs, &regs) == NULL)
321      {
322        wimp_cursor_palette[colour][2] = (unsigned char)((regs.r[2] >> 8) & 0xFF);
323        wimp_cursor_palette[colour][3] = (unsigned char)((regs.r[2] >> 16) & 0xFF);
324        wimp_cursor_palette[colour][4] = (unsigned char)((regs.r[2] >> 24) & 0xFF);
325      }
326    }
327
328    cursor_palette_saved = 1;
329}
330
331/* Restore the WIMP's cursor when we leave the SDL window */
332void WIMP_RestoreWimpCursor()
333{
334    int colour;
335
336    /* Reset to pointer shape 1 */
337    _kernel_osbyte(106, 1, 0);
338
339    /* Reset pointer colours */
340    if (cursor_palette_saved)
341    {
342      for (colour = 0; colour < 2; colour++)
343      {
344        _kernel_osword(12, (int *)wimp_cursor_palette[colour]);
345      }
346    }
347    cursor_palette_saved = 0;
348}
349
350/* Set palette used for SDL mouse cursors */
351void WIMP_SetSDLCursorPalette()
352{
353  /* First time set up the mouse colours */
354  Uint8 block[5];
355
356  /* Set up colour 1 as white */
357  block[0] = 1;   /* Colour to change 1 - 3 */
358  block[1] = 25;  /* Set pointer colour */
359  block[2] = 255; /* red component*/
360  block[3] = 255; /* green component */
361  block[4] = 255; /* blue component*/
362 _kernel_osword(12, (int *)block);
363
364 /* Set colour 3 to back */
365 block[0] = 3;   /* Colour to change 1 - 3 */
366 block[1] = 25;  /* Set pointer colour*/
367 block[2] = 0; /* red component*/
368 block[3] = 0; /* green component */
369 block[4] = 0; /* blue component*/
370 _kernel_osword(12, (int *)block);
371}
372