SDL 1.2.13
[crawl:crawl-sdl.git] / src / video / wincommon / SDL_sysmouse.c
1 /*
2     SDL - Simple DirectMedia Layer
3     Copyright (C) 1997-2006 Sam Lantinga
4
5     This library is free software; you can redistribute it and/or
6     modify it under the terms of the GNU Lesser General Public
7     License as published by the Free Software Foundation; either
8     version 2.1 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     Lesser General Public License for more details.
14
15     You should have received a copy of the GNU Lesser General Public
16     License along with this library; if not, write to the Free Software
17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18
19     Sam Lantinga
20     slouken@libsdl.org
21 */
22 #include "SDL_config.h"
23
24 #define WIN32_LEAN_AND_MEAN
25 #include <windows.h>
26
27 #include "SDL_mouse.h"
28 #include "../../events/SDL_events_c.h"
29 #include "../SDL_cursor_c.h"
30 #include "SDL_sysmouse_c.h"
31 #include "SDL_lowvideo.h"
32
33 #ifdef _WIN32_WCE
34 #define USE_STATIC_CURSOR
35 #endif
36
37 HCURSOR SDL_hcursor = NULL;             /* Exported for SDL_eventloop.c */
38
39 /* The implementation dependent data for the window manager cursor */
40 /* For some reason when creating a windows cursor, the ands and xors memory
41    is not copied, so we need to keep track of it and free it when we are done
42    with the cursor.  If we free the memory prematurely, the app crashes. :-}
43 */
44 struct WMcursor {
45         HCURSOR curs;
46 #ifndef USE_STATIC_CURSOR
47         Uint8 *ands;
48         Uint8 *xors;
49 #endif
50 };
51
52 /* Convert bits to padded bytes */
53 #define PAD_BITS(bits)  ((bits+7)/8)
54
55 #ifdef CURSOR_DEBUG
56 static void PrintBITMAP(FILE *out, char *bits, int w, int h)
57 {
58         int i;
59         unsigned char ch;
60
61         while ( h-- > 0 ) {
62                 for ( i=0; i<w; ++i ) {
63                         if ( (i%8) == 0 )
64                                 ch = *bits++;
65                         if ( ch&0x80 )
66                                 fprintf(out, "X");
67                         else
68                                 fprintf(out, " ");
69                         ch <<= 1;
70                 }
71                 fprintf(out, "\n");
72         }
73 }
74 #endif
75
76 #ifndef USE_STATIC_CURSOR
77 /* Local functions to convert the SDL cursor mask into Windows format */
78 static void memnot(Uint8 *dst, Uint8 *src, int len)
79 {
80         while ( len-- > 0 )
81                 *dst++ = ~*src++;
82 }
83 static void memxor(Uint8 *dst, Uint8 *src1, Uint8 *src2, int len)
84 {
85         while ( len-- > 0 )
86                 *dst++ = (*src1++)^(*src2++);
87 }
88 #endif /* !USE_STATIC_CURSOR */
89
90 void WIN_FreeWMCursor(_THIS, WMcursor *cursor)
91 {
92 #ifndef USE_STATIC_CURSOR
93         if ( cursor->curs == GetCursor() )
94                 SetCursor(NULL);
95         if ( cursor->curs != NULL )
96                 DestroyCursor(cursor->curs);
97         if ( cursor->ands != NULL )
98                 SDL_free(cursor->ands);
99         if ( cursor->xors != NULL )
100                 SDL_free(cursor->xors);
101 #endif /* !USE_STATIC_CURSOR */
102         SDL_free(cursor);
103 }
104
105 WMcursor *WIN_CreateWMCursor(_THIS,
106                 Uint8 *data, Uint8 *mask, int w, int h, int hot_x, int hot_y)
107 {
108 #ifdef USE_STATIC_CURSOR
109         WMcursor *cursor;
110
111         /* Allocate the cursor */
112         cursor = (WMcursor *)SDL_malloc(sizeof(*cursor));
113         if ( cursor ) {
114                 cursor->curs = LoadCursor(NULL, IDC_ARROW);
115         }
116         return(cursor);
117 #else
118         WMcursor *cursor;
119         int allowed_x;
120         int allowed_y;
121         int run, pad, i;
122         Uint8 *aptr, *xptr;
123
124         /* Check to make sure the cursor size is okay */
125         allowed_x = GetSystemMetrics(SM_CXCURSOR);
126         allowed_y = GetSystemMetrics(SM_CYCURSOR);
127         if ( (w > allowed_x) || (h > allowed_y) ) {
128                 SDL_SetError("Only cursors of dimension (%dx%d) are allowed",
129                                                         allowed_x, allowed_y);
130                 return(NULL);
131         }
132
133         /* Allocate the cursor */
134         cursor = (WMcursor *)SDL_malloc(sizeof(*cursor));
135         if ( cursor == NULL ) {
136                 SDL_SetError("Out of memory");
137                 return(NULL);
138         }
139         cursor->curs = NULL;
140         cursor->ands = NULL;
141         cursor->xors = NULL;
142
143         /* Pad out to the normal cursor size */
144         run = PAD_BITS(w);
145         pad = PAD_BITS(allowed_x)-run;
146         aptr = cursor->ands = (Uint8 *)SDL_malloc((run+pad)*allowed_y);
147         xptr = cursor->xors = (Uint8 *)SDL_malloc((run+pad)*allowed_y);
148         if ( (aptr == NULL) || (xptr == NULL) ) {
149                 WIN_FreeWMCursor(NULL, cursor);
150                 SDL_OutOfMemory();
151                 return(NULL);
152         }
153         for ( i=0; i<h; ++i ) {
154                 memxor(xptr, data, mask, run);
155                 xptr += run;
156                 data += run;
157                 memnot(aptr, mask, run);
158                 mask += run;
159                 aptr += run;
160                 SDL_memset(xptr,  0, pad);
161                 xptr += pad;
162                 SDL_memset(aptr, ~0, pad);
163                 aptr += pad;
164         }
165         pad += run;
166         for ( ; i<allowed_y; ++i ) {
167                 SDL_memset(xptr,  0, pad);
168                 xptr += pad;
169                 SDL_memset(aptr, ~0, pad);
170                 aptr += pad;
171         }
172
173         /* Create the cursor */
174         cursor->curs = CreateCursor(
175                         (HINSTANCE)GetWindowLongPtr(SDL_Window, GWLP_HINSTANCE),
176                                         hot_x, hot_y, allowed_x, allowed_y, 
177                                                 cursor->ands, cursor->xors);
178         if ( cursor->curs == NULL ) {
179                 WIN_FreeWMCursor(NULL, cursor);
180                 SDL_SetError("Windows couldn't create the requested cursor");
181                 return(NULL);
182         }
183         return(cursor);
184 #endif /* USE_STATIC_CURSOR */
185 }
186
187 int WIN_ShowWMCursor(_THIS, WMcursor *cursor)
188 {
189         POINT mouse_pos;
190
191         /* The fullscreen cursor must be done in software with DirectInput */
192         if ( !this->screen || DDRAW_FULLSCREEN() ) {
193                 return(0);
194         }
195
196         /* Set the window cursor to our cursor, if applicable */
197         if ( cursor != NULL ) {
198                 SDL_hcursor = cursor->curs;
199         } else {
200                 SDL_hcursor = NULL;
201         }
202         GetCursorPos(&mouse_pos);
203         if ( PtInRect(&SDL_bounds, mouse_pos) ) {
204                 SetCursor(SDL_hcursor);
205         }
206         return(1);
207 }
208
209 void WIN_WarpWMCursor(_THIS, Uint16 x, Uint16 y)
210 {
211         if ( DDRAW_FULLSCREEN() ) {
212                 SDL_PrivateMouseMotion(0, 0, x, y);
213         } else if ( mouse_relative) {
214                 /*      RJR: March 28, 2000
215                         leave physical cursor at center of screen if
216                         mouse hidden and grabbed */
217                 SDL_PrivateMouseMotion(0, 0, x, y);
218         } else {
219                 POINT pt;
220                 pt.x = x;
221                 pt.y = y;
222                 ClientToScreen(SDL_Window, &pt);
223                 SetCursorPos(pt.x, pt.y);
224         }
225 }
226
227 /* Update the current mouse state and position */
228 void WIN_UpdateMouse(_THIS)
229 {
230         RECT rect;
231         POINT pt;
232
233         if ( ! DDRAW_FULLSCREEN() ) {
234                 GetClientRect(SDL_Window, &rect);
235                 GetCursorPos(&pt);
236                 MapWindowPoints(NULL, SDL_Window, &pt, 1);
237                 if (PtInRect(&rect, pt) && (WindowFromPoint(pt) == SDL_Window)){
238                         SDL_PrivateAppActive(1, SDL_APPMOUSEFOCUS);
239                         SDL_PrivateMouseMotion(0,0, (Sint16)pt.x, (Sint16)pt.y);
240                 } else {
241                         SDL_PrivateAppActive(0, SDL_APPMOUSEFOCUS);
242                 }
243         }
244 }
245
246 /* Check to see if we need to enter or leave mouse relative mode */
247 void WIN_CheckMouseMode(_THIS)
248 {
249 #ifndef _WIN32_WCE 
250         /* If the mouse is hidden and input is grabbed, we use relative mode */
251         if ( !(SDL_cursorstate & CURSOR_VISIBLE) &&
252              (this->input_grab != SDL_GRAB_OFF) ) {
253                 mouse_relative = 1;
254         } else {
255                 mouse_relative = 0;
256         }
257 #else
258                 mouse_relative =  0; 
259 #endif
260 }