fixed a bug that caused the mouse cursor drawing incorrectly
[reactos.git] / reactos / subsys / win32k / eng / mouse.c
1 /*
2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program 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
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 /* $Id: mouse.c,v 1.33 2003/08/25 00:28:22 weiden Exp $
20 *
21 * PROJECT: ReactOS kernel
22 * PURPOSE: Mouse
23 * FILE: subsys/win32k/eng/mouse.c
24 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
25 * REVISION HISTORY:
26 * 06-06-2001 CSH Created
27 */
28 /* INCLUDES ******************************************************************/
29
30 #include <windows.h>
31 #include <ddk/ntddk.h>
32 #include <ddk/ntddmou.h>
33 #include <win32k/win32k.h>
34 #include <win32k/dc.h>
35 #include "objects.h"
36 #include "include/msgqueue.h"
37 #include "include/object.h"
38 #include "include/winsta.h"
39 #include <include/mouse.h>
40
41 #define NDEBUG
42 #include <debug.h>
43
44
45 #define GETSYSCURSOR(x) ((x) - OCR_NORMAL)
46
47 /* GLOBALS *******************************************************************/
48
49 static ULONG PointerStatus;
50
51 static UCHAR DefaultCursor[256] = {
52 0x3F, 0xFF, 0xFF, 0xFF,
53 0x1F, 0xFF, 0xFF, 0xFF,
54 0x0F, 0xFF, 0xFF, 0xFF,
55 0x07, 0xFF, 0xFF, 0xFF,
56 0x03, 0xFF, 0xFF, 0xFF,
57 0x01, 0xFF, 0xFF, 0xFF,
58 0x00, 0xFF, 0xFF, 0xFF,
59 0x00, 0x7F, 0xFF, 0xFF,
60 0x00, 0x3F, 0xFF, 0xFF,
61 0x00, 0x1F, 0xFF, 0xFF,
62 0x00, 0x0F, 0xFF, 0xFF,
63 0x00, 0xFF, 0xFF, 0xFF,
64 0x00, 0xFF, 0xFF, 0xFF,
65 0x18, 0x7F, 0xFF, 0xFF,
66 0x38, 0x7F, 0xFF, 0xFF,
67 0x7C, 0x3F, 0xFF, 0xFF,
68 0xFC, 0x3F, 0xFF, 0xFF,
69 0xFE, 0x1F, 0xFF, 0xFF,
70 0xFE, 0x1F, 0xFF, 0xFF,
71 0xFF, 0x3F, 0xFF, 0xFF,
72 0xFF, 0xFF, 0xFF, 0xFF,
73 0xFF, 0xFF, 0xFF, 0xFF,
74 0xFF, 0xFF, 0xFF, 0xFF,
75 0xFF, 0xFF, 0xFF, 0xFF,
76 0xFF, 0xFF, 0xFF, 0xFF,
77 0xFF, 0xFF, 0xFF, 0xFF,
78 0xFF, 0xFF, 0xFF, 0xFF,
79 0xFF, 0xFF, 0xFF, 0xFF,
80 0xFF, 0xFF, 0xFF, 0xFF,
81 0xFF, 0xFF, 0xFF, 0xFF,
82 0xFF, 0xFF, 0xFF, 0xFF,
83 0xFF, 0xFF, 0xFF, 0xFF,
84
85 0x00, 0x00, 0x00, 0x00,
86 0x40, 0x00, 0x00, 0x00,
87 0x60, 0x00, 0x00, 0x00,
88 0x70, 0x00, 0x00, 0x00,
89 0x78, 0x00, 0x00, 0x00,
90 0x7C, 0x00, 0x00, 0x00,
91 0x7E, 0x00, 0x00, 0x00,
92 0x7F, 0x00, 0x00, 0x00,
93 0x7F, 0x80, 0x00, 0x00,
94 0x7F, 0xC0, 0x00, 0x00,
95 0x7E, 0x00, 0x00, 0x00,
96 0x76, 0x00, 0x00, 0x00,
97 0x76, 0x00, 0x00, 0x00,
98 0x43, 0x00, 0x00, 0x00,
99 0x03, 0x00, 0x00, 0x00,
100 0x01, 0x80, 0x00, 0x00,
101 0x01, 0x80, 0x00, 0x00,
102 0x00, 0xC0, 0x00, 0x00,
103 0x00, 0xC0, 0x00, 0x00,
104 0x00, 0x00, 0x00, 0x00,
105 0x00, 0x00, 0x00, 0x00,
106 0x00, 0x00, 0x00, 0x00,
107 0x00, 0x00, 0x00, 0x00,
108 0x00, 0x00, 0x00, 0x00,
109 0x00, 0x00, 0x00, 0x00,
110 0x00, 0x00, 0x00, 0x00,
111 0x00, 0x00, 0x00, 0x00,
112 0x00, 0x00, 0x00, 0x00,
113 0x00, 0x00, 0x00, 0x00,
114 0x00, 0x00, 0x00, 0x00,
115 0x00, 0x00, 0x00, 0x00,
116 0x00, 0x00, 0x00, 0x00};
117
118 /* FUNCTIONS *****************************************************************/
119
120 BOOL FASTCALL
121 CheckClipCursor(LONG *x, LONG *y, PSYSTEM_CURSORINFO CurInfo)
122 {
123 if(CurInfo->CursorClipInfo.IsClipped)
124 {
125 if(*x > CurInfo->CursorClipInfo.Right)
126 *x = CurInfo->CursorClipInfo.Right;
127 if(*x < CurInfo->CursorClipInfo.Left)
128 *x = CurInfo->CursorClipInfo.Left;
129 if(*y > CurInfo->CursorClipInfo.Bottom)
130 *y = CurInfo->CursorClipInfo.Bottom;
131 if(*y < CurInfo->CursorClipInfo.Top)
132 *y = CurInfo->CursorClipInfo.Top;
133 return TRUE;
134 }
135 return TRUE;
136 }
137
138 INT STDCALL
139 MouseSafetyOnDrawStart(PSURFOBJ SurfObj, PSURFGDI SurfGDI, LONG HazardX1,
140 LONG HazardY1, LONG HazardX2, LONG HazardY2)
141 /*
142 * FUNCTION: Notify the mouse driver that drawing is about to begin in
143 * a rectangle on a particular surface.
144 */
145 {
146 RECTL MouseRect;
147 LONG tmp;
148 PSYSTEM_CURSORINFO CurInfo;
149 PSYSCURSOR SysCursor;
150 BOOL MouseEnabled = FALSE;
151
152
153 /* Mouse is not allowed to move if GDI is busy drawing */
154
155 if(IntGetWindowStationObject(InputWindowStation))
156 {
157 CurInfo = &InputWindowStation->SystemCursor;
158
159 SysCursor = &CurInfo->SystemCursors[CurInfo->CurrentCursor];
160 MouseEnabled = CurInfo->Enabled && SysCursor->hCursor;
161 }
162 else
163 return FALSE;
164
165 CurInfo->SafetySwitch2 = TRUE;
166
167 if (SurfObj == NULL)
168 {
169 ObDereferenceObject(InputWindowStation);
170 return(FALSE);
171 }
172
173
174 if (SurfObj->iType != STYPE_DEVICE || MouseEnabled == FALSE)
175 {
176 ObDereferenceObject(InputWindowStation);
177 return(FALSE);
178 }
179
180 if (SPS_ACCEPT_NOEXCLUDE == PointerStatus)
181 {
182 /* Hardware cursor, no need to remove it */
183 ObDereferenceObject(InputWindowStation);
184 return(FALSE);
185 }
186
187 if (HazardX1 > HazardX2)
188 {
189 tmp = HazardX2; HazardX2 = HazardX1; HazardX1 = tmp;
190 }
191 if (HazardY1 > HazardY2)
192 {
193 tmp = HazardY2; HazardY2 = HazardY1; HazardY1 = tmp;
194 }
195
196 if (((CurInfo->x + SysCursor->cx) >= HazardX1) && (CurInfo->x <= HazardX2) &&
197 ((CurInfo->y + SysCursor->cy) >= HazardY1) && (CurInfo->y <= HazardY2))
198 {
199 /* Mouse is not allowed to move if GDI is busy drawing */
200 ExAcquireFastMutexUnsafe(&CurInfo->CursorMutex);
201 CurInfo->SafetySwitch = TRUE;
202 SurfGDI->MovePointer(SurfObj, -1, -1, &MouseRect);
203 ExReleaseFastMutexUnsafe(&CurInfo->CursorMutex);
204 }
205
206 ObDereferenceObject(InputWindowStation);
207 return(TRUE);
208 }
209
210 INT FASTCALL
211 MouseSafetyOnDrawEnd(PSURFOBJ SurfObj, PSURFGDI SurfGDI)
212 /*
213 * FUNCTION: Notify the mouse driver that drawing has finished on a surface.
214 */
215 {
216 RECTL MouseRect;
217 PSYSTEM_CURSORINFO CurInfo;
218 PSYSCURSOR SysCursor;
219 BOOL MouseEnabled = FALSE;
220
221 if(IntGetWindowStationObject(InputWindowStation))
222 {
223 CurInfo = &InputWindowStation->SystemCursor;
224 }
225 else
226 return FALSE;
227
228 if(SurfObj == NULL)
229 {
230 CurInfo->SafetySwitch2 = FALSE;
231 ObDereferenceObject(InputWindowStation);
232 return FALSE;
233 }
234
235 SysCursor = &CurInfo->SystemCursors[CurInfo->CurrentCursor];
236 MouseEnabled = CurInfo->Enabled && SysCursor->hCursor;
237
238 if (SurfObj->iType != STYPE_DEVICE || MouseEnabled == FALSE)
239 {
240 CurInfo->SafetySwitch2 = FALSE;
241 ObDereferenceObject(InputWindowStation);
242 return(FALSE);
243 }
244
245 if (SPS_ACCEPT_NOEXCLUDE == PointerStatus)
246 {
247 /* Hardware cursor, it wasn't removed so need to restore it */
248 CurInfo->SafetySwitch2 = FALSE;
249 ObDereferenceObject(InputWindowStation);
250 return(FALSE);
251 }
252
253 if (CurInfo->SafetySwitch)
254 {
255 ExAcquireFastMutexUnsafe(&CurInfo->CursorMutex);
256 SurfGDI->MovePointer(SurfObj, CurInfo->x, CurInfo->y, &MouseRect);
257 CurInfo->SafetySwitch = FALSE;
258 ExReleaseFastMutexUnsafe(&CurInfo->CursorMutex);
259 }
260
261 CurInfo->SafetySwitch2 = FALSE;
262 ObDereferenceObject(InputWindowStation);
263 return(TRUE);
264 }
265
266 BOOL FASTCALL
267 MouseMoveCursor(LONG X, LONG Y)
268 {
269 HDC hDC;
270 PDC dc;
271 RECTL MouseRect;
272 BOOL res = FALSE;
273 PSURFOBJ SurfObj;
274 PSURFGDI SurfGDI;
275 PSYSTEM_CURSORINFO CurInfo;
276 MSG Msg;
277 LARGE_INTEGER LargeTickCount;
278 ULONG TickCount;
279 static ULONG ButtonsDown = 0;
280
281 hDC = IntGetScreenDC();
282
283 if(!hDC || !InputWindowStation)
284 return FALSE;
285
286 if(IntGetWindowStationObject(InputWindowStation))
287 {
288 dc = DC_LockDc(hDC);
289 SurfObj = (PSURFOBJ)AccessUserObject((ULONG) dc->Surface);
290 SurfGDI = (PSURFGDI)AccessInternalObject((ULONG) dc->Surface);
291 DC_UnlockDc( hDC );
292 CurInfo = &InputWindowStation->SystemCursor;
293 CheckClipCursor(&X, &Y, CurInfo);
294 if((X != CurInfo->x) || (Y != CurInfo->y))
295 {
296 /* send MOUSEMOVE message */
297 KeQueryTickCount(&LargeTickCount);
298 TickCount = LargeTickCount.u.LowPart;
299 Msg.wParam = ButtonsDown;
300 Msg.lParam = MAKELPARAM(X, Y);
301 Msg.message = WM_MOUSEMOVE;
302 Msg.time = TickCount;
303 Msg.pt.x = X;
304 Msg.pt.y = Y;
305 MsqInsertSystemMessage(&Msg);
306 /* move cursor */
307 CurInfo->x = X;
308 CurInfo->y = Y;
309 if(!CurInfo->SafetySwitch && !CurInfo->SafetySwitch2 && CurInfo->Enabled)
310 {
311 ExAcquireFastMutexUnsafe(&CurInfo->CursorMutex);
312 SurfGDI->MovePointer(SurfObj, CurInfo->x, CurInfo->y, &MouseRect);
313 ExReleaseFastMutexUnsafe(&CurInfo->CursorMutex);
314 }
315 res = TRUE;
316 }
317
318 ObDereferenceObject(InputWindowStation);
319 return res;
320 }
321 else
322 return FALSE;
323 }
324
325 VOID /* STDCALL */
326 MouseGDICallBack(PMOUSE_INPUT_DATA Data, ULONG InputCount)
327 /*
328 * FUNCTION: Call by the mouse driver when input events occur.
329 */
330 {
331 ULONG i;
332 PSYSTEM_CURSORINFO CurInfo;
333 PSYSCURSOR SysCursor;
334 BOOL MouseEnabled = FALSE;
335 LONG mouse_ox, mouse_oy;
336 LONG mouse_cx = 0, mouse_cy = 0;
337 HDC hDC;
338 PDC dc;
339 PSURFOBJ SurfObj;
340 PSURFGDI SurfGDI;
341 RECTL MouseRect;
342 MSG Msg;
343 LARGE_INTEGER LargeTickCount;
344 ULONG TickCount;
345 static ULONG ButtonsDown = 0;
346
347 hDC = IntGetScreenDC();
348
349 if(!hDC || !InputWindowStation)
350 return;
351
352 if(IntGetWindowStationObject(InputWindowStation))
353 {
354 CurInfo = &InputWindowStation->SystemCursor;
355 SysCursor = &CurInfo->SystemCursors[CurInfo->CurrentCursor];
356 MouseEnabled = CurInfo->Enabled;
357 mouse_ox = CurInfo->x;
358 mouse_oy = CurInfo->y;
359 }
360 else
361 return;
362
363 KeQueryTickCount(&LargeTickCount);
364 TickCount = LargeTickCount.u.LowPart;
365
366 dc = DC_LockDc(hDC);
367 SurfObj = (PSURFOBJ)AccessUserObject((ULONG) dc->Surface);
368 SurfGDI = (PSURFGDI)AccessInternalObject((ULONG) dc->Surface);
369 DC_UnlockDc( hDC );
370
371 /* Compile the total mouse movement change and dispatch button events. */
372 for (i = 0; i < InputCount; i++)
373 {
374 mouse_cx += Data[i].LastX;
375 mouse_cy += Data[i].LastY;
376
377 Msg.wParam = ButtonsDown;
378 Msg.lParam = MAKELPARAM(CurInfo->x + mouse_cx, CurInfo->y + mouse_cy);
379 Msg.message = WM_MOUSEMOVE;
380 Msg.time = TickCount;
381 Msg.pt.x = CurInfo->x + mouse_cx;
382 Msg.pt.y = CurInfo->y + mouse_cy;
383
384 CheckClipCursor(&Msg.pt.x, &Msg.pt.y, CurInfo);
385
386 if ((0 != Data[i].LastX) || (0 != Data[i].LastY))
387 {
388 MsqInsertSystemMessage(&Msg);
389 }
390
391 if (Data[i].ButtonFlags != 0)
392 {
393 if ((Data[i].ButtonFlags & MOUSE_LEFT_BUTTON_DOWN) > 0)
394 {
395 Msg.wParam = MK_LBUTTON;
396 Msg.message = WM_LBUTTONDOWN;
397 }
398 if ((Data[i].ButtonFlags & MOUSE_MIDDLE_BUTTON_DOWN) > 0)
399 {
400 Msg.wParam = MK_MBUTTON;
401 Msg.message = WM_MBUTTONDOWN;
402 }
403 if ((Data[i].ButtonFlags & MOUSE_RIGHT_BUTTON_DOWN) > 0)
404 {
405 Msg.wParam = MK_RBUTTON;
406 Msg.message = WM_RBUTTONDOWN;
407 }
408
409 if ((Data[i].ButtonFlags & MOUSE_LEFT_BUTTON_UP) > 0)
410 {
411 Msg.wParam = MK_LBUTTON;
412 Msg.message = WM_LBUTTONUP;
413 }
414 if ((Data[i].ButtonFlags & MOUSE_MIDDLE_BUTTON_UP) > 0)
415 {
416 Msg.wParam = MK_MBUTTON;
417 Msg.message = WM_MBUTTONUP;
418 }
419 if ((Data[i].ButtonFlags & MOUSE_RIGHT_BUTTON_UP) > 0)
420 {
421 Msg.wParam = MK_RBUTTON;
422 Msg.message = WM_RBUTTONUP;
423 }
424
425 MsqInsertSystemMessage(&Msg);
426 }
427 }
428
429 /* If the mouse moved then move the pointer. */
430 if ((mouse_cx != 0 || mouse_cy != 0) && MouseEnabled)
431 {
432 CurInfo->x += mouse_cx;
433 CurInfo->y += mouse_cy;
434
435 CurInfo->x = max(CurInfo->x, 0);
436 CurInfo->y = max(CurInfo->y, 0);
437 CurInfo->x = min(CurInfo->x, SurfObj->sizlBitmap.cx - 20);
438 CurInfo->y = min(CurInfo->y, SurfObj->sizlBitmap.cy - 20);
439
440 CheckClipCursor(&CurInfo->x, &CurInfo->y, CurInfo);
441
442 if (!CurInfo->SafetySwitch && !CurInfo->SafetySwitch2 &&
443 ((mouse_ox != CurInfo->x) || (mouse_oy != CurInfo->y)))
444 {
445 ExAcquireFastMutexUnsafe(&CurInfo->CursorMutex);
446 SurfGDI->MovePointer(SurfObj, CurInfo->x, CurInfo->y, &MouseRect);
447 ExReleaseFastMutexUnsafe(&CurInfo->CursorMutex);
448 }
449 }
450
451 ObDereferenceObject(InputWindowStation);
452 }
453
454 VOID FASTCALL
455 EnableMouse(HDC hDisplayDC)
456 {
457 PDC dc;
458 PSURFOBJ SurfObj;
459 PSURFGDI SurfGDI;
460 HBITMAP hMouseSurf;
461 PSURFOBJ MouseSurf;
462 SIZEL MouseSize;
463 RECTL MouseRect;
464 PSYSTEM_CURSORINFO CurInfo;
465 PSYSCURSOR SysCursor;
466
467 if( hDisplayDC && InputWindowStation)
468 {
469 if(!IntGetWindowStationObject(InputWindowStation))
470 {
471 InputWindowStation->SystemCursor.Enabled = FALSE;
472 return;
473 }
474
475 CurInfo = &InputWindowStation->SystemCursor;
476 SysCursor = &CurInfo->SystemCursors[CurInfo->CurrentCursor];
477
478 dc = DC_LockDc(hDisplayDC);
479 SurfObj = (PSURFOBJ)AccessUserObject((ULONG) dc->Surface);
480 SurfGDI = (PSURFGDI)AccessInternalObject((ULONG) dc->Surface);
481 DC_UnlockDc( hDisplayDC );
482
483 /* Tell the display driver to set the pointer shape. */
484 #if 1
485 CurInfo->x = SurfObj->sizlBitmap.cx / 2;
486 CurInfo->y = SurfObj->sizlBitmap.cy / 2;
487 #else
488 CurInfo->x = 320;
489 CurInfo->y = 240;
490 #endif
491
492 /* Create the default mouse cursor. */
493 MouseSize.cx = SysCursor->cx;
494 MouseSize.cy = SysCursor->cy * 2;
495 hMouseSurf = EngCreateBitmap(MouseSize, 4, BMF_1BPP, BMF_TOPDOWN, DefaultCursor);
496 MouseSurf = (PSURFOBJ)AccessUserObject((ULONG) hMouseSurf);
497
498 DbgPrint("Setting Cursor up at 0x%x, 0x%x\n", CurInfo->x, CurInfo->y);
499 CheckClipCursor(&CurInfo->x,
500 &CurInfo->y,
501 CurInfo);
502
503 PointerStatus = SurfGDI->SetPointerShape(SurfObj, MouseSurf, NULL, NULL,
504 0, 0,
505 CurInfo->x,
506 CurInfo->y,
507 &MouseRect,
508 SPS_CHANGE);
509
510 InputWindowStation->SystemCursor.Enabled = (SPS_ACCEPT_EXCLUDE == PointerStatus ||
511 SPS_ACCEPT_NOEXCLUDE == PointerStatus);
512
513 EngDeleteSurface(hMouseSurf);
514 ObDereferenceObject(InputWindowStation);
515
516 }
517 else
518 {
519 if(IntGetWindowStationObject(InputWindowStation))
520 {
521 InputWindowStation->SystemCursor.Enabled = FALSE;
522 InputWindowStation->SystemCursor.CursorClipInfo.IsClipped = FALSE;
523 ObDereferenceObject(InputWindowStation);
524 return;
525 }
526 }
527 }
528 /* EOF */