Preparing for the win32k emulated mouse cursor support.
[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.56 2004/01/17 15:20:25 navaraf 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/desktop.h"
40 #include "include/window.h"
41 #include "include/cursoricon.h"
42 #include "include/callback.h"
43 #include <include/mouse.h>
44
45 #define NDEBUG
46 #include <debug.h>
47
48 #define GETSYSCURSOR(x) ((x) - OCR_NORMAL)
49
50 /* FUNCTIONS *****************************************************************/
51
52 BOOL FASTCALL
53 IntCheckClipCursor(LONG *x, LONG *y, PSYSTEM_CURSORINFO CurInfo)
54 {
55 if(CurInfo->CursorClipInfo.IsClipped)
56 {
57 if(*x > CurInfo->CursorClipInfo.Right)
58 *x = CurInfo->CursorClipInfo.Right;
59 if(*x < CurInfo->CursorClipInfo.Left)
60 *x = CurInfo->CursorClipInfo.Left;
61 if(*y > CurInfo->CursorClipInfo.Bottom)
62 *y = CurInfo->CursorClipInfo.Bottom;
63 if(*y < CurInfo->CursorClipInfo.Top)
64 *y = CurInfo->CursorClipInfo.Top;
65 return TRUE;
66 }
67 return TRUE;
68 }
69
70 BOOL FASTCALL
71 IntSwapMouseButton(PWINSTATION_OBJECT WinStaObject, BOOL Swap)
72 {
73 BOOL res = WinStaObject->SystemCursor.SwapButtons;
74 WinStaObject->SystemCursor.SwapButtons = Swap;
75 return res;
76 }
77
78 INT STDCALL
79 MouseSafetyOnDrawStart(PSURFOBJ SurfObj, PSURFGDI SurfGDI, LONG HazardX1,
80 LONG HazardY1, LONG HazardX2, LONG HazardY2)
81 /*
82 * FUNCTION: Notify the mouse driver that drawing is about to begin in
83 * a rectangle on a particular surface.
84 */
85 {
86 LONG tmp;
87 PSYSTEM_CURSORINFO CurInfo;
88 BOOL MouseEnabled = FALSE;
89 PCURICON_OBJECT Cursor;
90
91
92 /* Mouse is not allowed to move if GDI is busy drawing */
93
94 if(IntGetWindowStationObject(InputWindowStation))
95 {
96 CurInfo = &InputWindowStation->SystemCursor;
97
98 MouseEnabled = CurInfo->Enabled && CurInfo->ShowingCursor;
99 }
100 else
101 return FALSE;
102
103 if (SurfObj == NULL)
104 {
105 ObDereferenceObject(InputWindowStation);
106 return(FALSE);
107 }
108
109
110 if (SurfObj->iType != STYPE_DEVICE || MouseEnabled == FALSE)
111 {
112 ObDereferenceObject(InputWindowStation);
113 return(FALSE);
114 }
115
116 if (SPS_ACCEPT_NOEXCLUDE == SurfGDI->PointerStatus)
117 {
118 /* Hardware cursor, no need to remove it */
119 ObDereferenceObject(InputWindowStation);
120 return(FALSE);
121 }
122
123 if(!(Cursor = CurInfo->CurrentCursorObject))
124 {
125 ObDereferenceObject(InputWindowStation);
126 return(FALSE);
127 }
128
129 if (HazardX1 > HazardX2)
130 {
131 tmp = HazardX2; HazardX2 = HazardX1; HazardX1 = tmp;
132 }
133 if (HazardY1 > HazardY2)
134 {
135 tmp = HazardY2; HazardY2 = HazardY1; HazardY1 = tmp;
136 }
137
138 if (CurInfo->PointerRectRight >= HazardX1
139 && CurInfo->PointerRectLeft <= HazardX2
140 && CurInfo->PointerRectBottom >= HazardY1
141 && CurInfo->PointerRectTop <= HazardY2)
142 {
143 /* Mouse is not allowed to move if GDI is busy drawing */
144 ExAcquireFastMutex(&CurInfo->CursorMutex);
145 if (0 != CurInfo->SafetyRemoveCount++)
146 {
147 /* Was already removed */
148 ExReleaseFastMutex(&CurInfo->CursorMutex);
149 ObDereferenceObject(InputWindowStation);
150 return FALSE;
151 }
152 CurInfo->SafetySwitch = TRUE;
153 ExAcquireFastMutex(SurfGDI->DriverLock);
154 SurfGDI->MovePointer(SurfObj, -1, -1, NULL);
155 ExReleaseFastMutex(SurfGDI->DriverLock);
156 ExReleaseFastMutex(&CurInfo->CursorMutex);
157 }
158
159 ObDereferenceObject(InputWindowStation);
160 return(TRUE);
161 }
162
163 STATIC VOID FASTCALL
164 SetPointerRect(PSYSTEM_CURSORINFO CurInfo, PRECTL PointerRect)
165 {
166 CurInfo->PointerRectLeft = PointerRect->left;
167 CurInfo->PointerRectRight = PointerRect->right;
168 CurInfo->PointerRectTop = PointerRect->top;
169 CurInfo->PointerRectBottom = PointerRect->bottom;
170 }
171
172 INT FASTCALL
173 MouseSafetyOnDrawEnd(PSURFOBJ SurfObj, PSURFGDI SurfGDI)
174 /*
175 * FUNCTION: Notify the mouse driver that drawing has finished on a surface.
176 */
177 {
178 PSYSTEM_CURSORINFO CurInfo;
179 BOOL MouseEnabled = FALSE;
180 RECTL PointerRect;
181
182 if(IntGetWindowStationObject(InputWindowStation))
183 {
184 CurInfo = &InputWindowStation->SystemCursor;
185 }
186 else
187 return FALSE;
188
189 ExAcquireFastMutex(&CurInfo->CursorMutex);
190 if(SurfObj == NULL)
191 {
192 ExReleaseFastMutex(&CurInfo->CursorMutex);
193 ObDereferenceObject(InputWindowStation);
194 return FALSE;
195 }
196
197 MouseEnabled = CurInfo->Enabled && CurInfo->ShowingCursor;
198
199 if (SurfObj->iType != STYPE_DEVICE || MouseEnabled == FALSE)
200 {
201 ExReleaseFastMutex(&CurInfo->CursorMutex);
202 ObDereferenceObject(InputWindowStation);
203 return(FALSE);
204 }
205
206 if (SPS_ACCEPT_NOEXCLUDE == SurfGDI->PointerStatus)
207 {
208 /* Hardware cursor, it wasn't removed so need to restore it */
209 ExReleaseFastMutex(&CurInfo->CursorMutex);
210 ObDereferenceObject(InputWindowStation);
211 return(FALSE);
212 }
213
214 if (CurInfo->SafetySwitch)
215 {
216 if (1 < CurInfo->SafetyRemoveCount--)
217 {
218 /* Someone else removed it too, let them restore it */
219 ExReleaseFastMutex(&CurInfo->CursorMutex);
220 ObDereferenceObject(InputWindowStation);
221 return FALSE;
222 }
223 ExAcquireFastMutex(SurfGDI->DriverLock);
224 SurfGDI->MovePointer(SurfObj, CurInfo->x, CurInfo->y, &PointerRect);
225 ExReleaseFastMutex(SurfGDI->DriverLock);
226 SetPointerRect(CurInfo, &PointerRect);
227 CurInfo->SafetySwitch = FALSE;
228 }
229
230 ExReleaseFastMutex(&CurInfo->CursorMutex);
231 ObDereferenceObject(InputWindowStation);
232 return(TRUE);
233 }
234
235 BOOL FASTCALL
236 MouseMoveCursor(LONG X, LONG Y)
237 {
238 HDC hDC;
239 PDC dc;
240 BOOL res = FALSE;
241 PSURFOBJ SurfObj;
242 PSURFGDI SurfGDI;
243 PSYSTEM_CURSORINFO CurInfo;
244 MSG Msg;
245 LARGE_INTEGER LargeTickCount;
246 ULONG TickCount;
247 RECTL PointerRect;
248
249 if(!InputWindowStation)
250 return FALSE;
251
252 if(IntGetWindowStationObject(InputWindowStation))
253 {
254 CurInfo = &InputWindowStation->SystemCursor;
255 if(!CurInfo->Enabled)
256 {
257 ObDereferenceObject(InputWindowStation);
258 return FALSE;
259 }
260 hDC = IntGetScreenDC();
261 if(!hDC)
262 {
263 ObDereferenceObject(InputWindowStation);
264 return FALSE;
265 }
266 dc = DC_LockDc(hDC);
267 SurfObj = (PSURFOBJ)AccessUserObject((ULONG) dc->Surface);
268 SurfGDI = (PSURFGDI)AccessInternalObject((ULONG) dc->Surface);
269 DC_UnlockDc( hDC );
270 IntCheckClipCursor(&X, &Y, CurInfo);
271 if((X != CurInfo->x) || (Y != CurInfo->y))
272 {
273 /* move cursor */
274 CurInfo->x = X;
275 CurInfo->y = Y;
276 if(CurInfo->Enabled)
277 {
278 ExAcquireFastMutex(&CurInfo->CursorMutex);
279 ExAcquireFastMutex(SurfGDI->DriverLock);
280 SurfGDI->MovePointer(SurfObj, CurInfo->x, CurInfo->y, &PointerRect);
281 ExReleaseFastMutex(SurfGDI->DriverLock);
282 SetPointerRect(CurInfo, &PointerRect);
283 ExReleaseFastMutex(&CurInfo->CursorMutex);
284 }
285 /* send MOUSEMOVE message */
286 KeQueryTickCount(&LargeTickCount);
287 TickCount = LargeTickCount.u.LowPart;
288 Msg.wParam = CurInfo->ButtonsDown;
289 Msg.lParam = MAKELPARAM(X, Y);
290 Msg.message = WM_MOUSEMOVE;
291 Msg.time = TickCount;
292 Msg.pt.x = X;
293 Msg.pt.y = Y;
294 MsqInsertSystemMessage(&Msg, TRUE);
295 res = TRUE;
296 }
297
298 ObDereferenceObject(InputWindowStation);
299 return res;
300 }
301 else
302 return FALSE;
303 }
304
305 VOID /* STDCALL */
306 MouseGDICallBack(PMOUSE_INPUT_DATA Data, ULONG InputCount)
307 /*
308 * FUNCTION: Call by the mouse driver when input events occur.
309 */
310 {
311 ULONG i;
312 PSYSTEM_CURSORINFO CurInfo;
313 BOOL MouseEnabled = FALSE;
314 BOOL Moved = FALSE;
315 LONG mouse_ox, mouse_oy;
316 LONG mouse_cx = 0, mouse_cy = 0;
317 LONG dScroll = 0;
318 HDC hDC;
319 PDC dc;
320 PSURFOBJ SurfObj;
321 PSURFGDI SurfGDI;
322 MSG Msg;
323 RECTL PointerRect;
324
325 hDC = IntGetScreenDC();
326
327 if(!hDC || !InputWindowStation)
328 return;
329
330 if(IntGetWindowStationObject(InputWindowStation))
331 {
332 CurInfo = &InputWindowStation->SystemCursor;
333 MouseEnabled = CurInfo->Enabled;
334 if(!MouseEnabled)
335 {
336 ObDereferenceObject(InputWindowStation);
337 return;
338 }
339 mouse_ox = CurInfo->x;
340 mouse_oy = CurInfo->y;
341 }
342 else
343 return;
344
345 dc = DC_LockDc(hDC);
346 SurfObj = (PSURFOBJ)AccessUserObject((ULONG) dc->Surface);
347 SurfGDI = (PSURFGDI)AccessInternalObject((ULONG) dc->Surface);
348 DC_UnlockDc( hDC );
349
350 /* Compile the total mouse movement change and dispatch button events. */
351 for (i = 0; i < InputCount; i++)
352 {
353 mouse_cx += Data[i].LastX;
354 mouse_cy += Data[i].LastY;
355
356 CurInfo->x += Data[i].LastX;
357 CurInfo->y += Data[i].LastY;
358
359 CurInfo->x = max(CurInfo->x, 0);
360 CurInfo->y = max(CurInfo->y, 0);
361 CurInfo->x = min(CurInfo->x, SurfObj->sizlBitmap.cx - 1);
362 CurInfo->y = min(CurInfo->y, SurfObj->sizlBitmap.cy - 1);
363
364 IntCheckClipCursor(&CurInfo->x, &CurInfo->y, CurInfo);
365
366 Msg.wParam = CurInfo->ButtonsDown;
367 Msg.lParam = MAKELPARAM(CurInfo->x, CurInfo->y);
368 Msg.message = WM_MOUSEMOVE;
369 Msg.pt.x = CurInfo->x;
370 Msg.pt.y = CurInfo->y;
371
372 if (Data[i].ButtonFlags != 0)
373 {
374 if ((Data[i].ButtonFlags & MOUSE_LEFT_BUTTON_DOWN) > 0)
375 {
376 CurInfo->ButtonsDown |= (CurInfo->SwapButtons ? MK_RBUTTON : MK_LBUTTON);
377 Msg.message = (CurInfo->SwapButtons ? WM_RBUTTONDOWN : WM_LBUTTONDOWN);
378 }
379 if ((Data[i].ButtonFlags & MOUSE_MIDDLE_BUTTON_DOWN) > 0)
380 {
381 CurInfo->ButtonsDown |= MK_MBUTTON;
382 Msg.message = WM_MBUTTONDOWN;
383 }
384 if ((Data[i].ButtonFlags & MOUSE_RIGHT_BUTTON_DOWN) > 0)
385 {
386 CurInfo->ButtonsDown |= (CurInfo->SwapButtons ? MK_LBUTTON : MK_RBUTTON);
387 Msg.message = (CurInfo->SwapButtons ? WM_LBUTTONDOWN : WM_RBUTTONDOWN);
388 }
389
390 if ((Data[i].ButtonFlags & MOUSE_BUTTON_4_DOWN) > 0)
391 {
392 CurInfo->ButtonsDown |= MK_XBUTTON1;
393 Msg.message = WM_XBUTTONDOWN;
394 }
395 if ((Data[i].ButtonFlags & MOUSE_BUTTON_5_DOWN) > 0)
396 {
397 CurInfo->ButtonsDown |= MK_XBUTTON2;
398 Msg.message = WM_XBUTTONDOWN;
399 }
400
401 if ((Data[i].ButtonFlags & MOUSE_LEFT_BUTTON_UP) > 0)
402 {
403 CurInfo->ButtonsDown &= (CurInfo->SwapButtons ? ~MK_RBUTTON : ~MK_LBUTTON);
404 Msg.message = (CurInfo->SwapButtons ? WM_RBUTTONUP : WM_LBUTTONUP);
405 }
406 if ((Data[i].ButtonFlags & MOUSE_MIDDLE_BUTTON_UP) > 0)
407 {
408 CurInfo->ButtonsDown &= ~MK_MBUTTON;
409 Msg.message = WM_MBUTTONUP;
410 }
411 if ((Data[i].ButtonFlags & MOUSE_RIGHT_BUTTON_UP) > 0)
412 {
413 CurInfo->ButtonsDown &= (CurInfo->SwapButtons ? ~MK_LBUTTON : ~MK_RBUTTON);
414 Msg.message = (CurInfo->SwapButtons ? WM_LBUTTONUP : WM_RBUTTONUP);
415 }
416 if ((Data[i].ButtonFlags & MOUSE_BUTTON_4_UP) > 0)
417 {
418 CurInfo->ButtonsDown &= ~MK_XBUTTON1;
419 Msg.message = WM_XBUTTONUP;
420 }
421 if ((Data[i].ButtonFlags & MOUSE_BUTTON_5_UP) > 0)
422 {
423 CurInfo->ButtonsDown &= ~MK_XBUTTON2;
424 Msg.message = WM_XBUTTONUP;
425 }
426 if ((Data[i].ButtonFlags & MOUSE_WHEEL) > 0)
427 {
428 dScroll += (LONG)Data[i].ButtonData;
429 }
430
431 if (Data[i].ButtonFlags != MOUSE_WHEEL)
432 {
433 Moved = (0 != mouse_cx) || (0 != mouse_cy);
434 if(Moved && MouseEnabled)
435 {
436 if (!CurInfo->SafetySwitch && 0 == CurInfo->SafetyRemoveCount &&
437 ((mouse_ox != CurInfo->x) || (mouse_oy != CurInfo->y)))
438 {
439 ExAcquireFastMutex(&CurInfo->CursorMutex);
440 ExAcquireFastMutex(SurfGDI->DriverLock);
441 SurfGDI->MovePointer(SurfObj, CurInfo->x, CurInfo->y, &PointerRect);
442 ExReleaseFastMutex(SurfGDI->DriverLock);
443 SetPointerRect(CurInfo, &PointerRect);
444 ExReleaseFastMutex(&CurInfo->CursorMutex);
445 mouse_cx = 0;
446 mouse_cy = 0;
447 }
448 }
449
450 Msg.wParam = CurInfo->ButtonsDown;
451 MsqInsertSystemMessage(&Msg, FALSE);
452 }
453 }
454 }
455
456 /* If the mouse moved then move the pointer. */
457 if ((mouse_cx != 0 || mouse_cy != 0) && MouseEnabled)
458 {
459 Msg.wParam = CurInfo->ButtonsDown;
460 Msg.message = WM_MOUSEMOVE;
461 Msg.pt.x = CurInfo->x;
462 Msg.pt.y = CurInfo->y;
463 Msg.lParam = MAKELPARAM(CurInfo->x, CurInfo->y);
464 MsqInsertSystemMessage(&Msg, TRUE);
465
466 if (!CurInfo->SafetySwitch && 0 == CurInfo->SafetyRemoveCount &&
467 ((mouse_ox != CurInfo->x) || (mouse_oy != CurInfo->y)))
468 {
469 ExAcquireFastMutex(&CurInfo->CursorMutex);
470 ExAcquireFastMutex(SurfGDI->DriverLock);
471 SurfGDI->MovePointer(SurfObj, CurInfo->x, CurInfo->y, &PointerRect);
472 ExReleaseFastMutex(SurfGDI->DriverLock);
473 SetPointerRect(CurInfo, &PointerRect);
474 ExReleaseFastMutex(&CurInfo->CursorMutex);
475 }
476 }
477
478 /* send WM_MOUSEWHEEL message */
479 if(dScroll && MouseEnabled)
480 {
481 Msg.message = WM_MOUSEWHEEL;
482 Msg.wParam = MAKEWPARAM(CurInfo->ButtonsDown, dScroll);
483 Msg.lParam = MAKELPARAM(CurInfo->x, CurInfo->y);
484 Msg.pt.x = CurInfo->x;
485 Msg.pt.y = CurInfo->y;
486 MsqInsertSystemMessage(&Msg, FALSE);
487 }
488
489 ObDereferenceObject(InputWindowStation);
490 }
491
492 VOID FASTCALL
493 EnableMouse(HDC hDisplayDC)
494 {
495 PDC dc;
496 PSURFOBJ SurfObj;
497 PSURFGDI SurfGDI;
498
499 if( hDisplayDC && InputWindowStation)
500 {
501 if(!IntGetWindowStationObject(InputWindowStation))
502 {
503 InputWindowStation->SystemCursor.Enabled = FALSE;
504 return;
505 }
506
507 dc = DC_LockDc(hDisplayDC);
508 SurfObj = (PSURFOBJ)AccessUserObject((ULONG) dc->Surface);
509 SurfGDI = (PSURFGDI)AccessInternalObject((ULONG) dc->Surface);
510 DC_UnlockDc( hDisplayDC );
511
512 IntSetCursor(InputWindowStation, NULL, TRUE);
513
514 InputWindowStation->SystemCursor.Enabled = (SPS_ACCEPT_EXCLUDE == SurfGDI->PointerStatus ||
515 SPS_ACCEPT_NOEXCLUDE == SurfGDI->PointerStatus);
516
517 /* Move the cursor to the screen center */
518 DPRINT("Setting Cursor up at 0x%x, 0x%x\n", SurfObj->sizlBitmap.cx / 2, SurfObj->sizlBitmap.cy / 2);
519 MouseMoveCursor(SurfObj->sizlBitmap.cx / 2, SurfObj->sizlBitmap.cy / 2);
520
521 ObDereferenceObject(InputWindowStation);
522 }
523 else
524 {
525 if(IntGetWindowStationObject(InputWindowStation))
526 {
527 IntSetCursor(InputWindowStation, NULL, TRUE);
528 InputWindowStation->SystemCursor.Enabled = FALSE;
529 InputWindowStation->SystemCursor.CursorClipInfo.IsClipped = FALSE;
530 ObDereferenceObject(InputWindowStation);
531 return;
532 }
533 }
534 }
535
536 ULONG
537 STDCALL
538 EngSetPointerShape(
539 IN SURFOBJ *pso,
540 IN SURFOBJ *psoMask,
541 IN SURFOBJ *psoColor,
542 IN XLATEOBJ *pxlo,
543 IN LONG xHot,
544 IN LONG yHot,
545 IN LONG x,
546 IN LONG y,
547 IN RECTL *prcl,
548 IN FLONG fl
549 )
550 {
551 // www.osr.com/ddk/graphics/gdifncs_1y5j.htm
552 UNIMPLEMENTED;
553 return 0;
554 }
555
556 /*
557 * @unimplemented
558 */
559 VOID
560 STDCALL
561 EngMovePointer(
562 IN SURFOBJ *pso,
563 IN LONG x,
564 IN LONG y,
565 IN RECTL *prcl
566 )
567 {
568 // www.osr.com/ddk/graphics/gdifncs_8wfb.htm
569 UNIMPLEMENTED;
570 }
571
572 /* EOF */