added pool tags for better debugging
[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.61 2004/02/19 21:12:09 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/desktop.h"
40 #include "include/window.h"
41 #include "include/cursoricon.h"
42 #include "include/callback.h"
43 #include "include/palette.h"
44 #include "include/inteng.h"
45 #include "include/eng.h"
46 #include "include/tags.h"
47 #include <include/mouse.h>
48
49 #define NDEBUG
50 #include <debug.h>
51
52 #define GETSYSCURSOR(x) ((x) - OCR_NORMAL)
53
54 /* FUNCTIONS *****************************************************************/
55
56 BOOL FASTCALL
57 IntCheckClipCursor(LONG *x, LONG *y, PSYSTEM_CURSORINFO CurInfo)
58 {
59 if(CurInfo->CursorClipInfo.IsClipped)
60 {
61 if(*x > CurInfo->CursorClipInfo.Right)
62 *x = CurInfo->CursorClipInfo.Right;
63 if(*x < CurInfo->CursorClipInfo.Left)
64 *x = CurInfo->CursorClipInfo.Left;
65 if(*y > CurInfo->CursorClipInfo.Bottom)
66 *y = CurInfo->CursorClipInfo.Bottom;
67 if(*y < CurInfo->CursorClipInfo.Top)
68 *y = CurInfo->CursorClipInfo.Top;
69 return TRUE;
70 }
71 return TRUE;
72 }
73
74 BOOL FASTCALL
75 IntSwapMouseButton(PWINSTATION_OBJECT WinStaObject, BOOL Swap)
76 {
77 BOOL res = WinStaObject->SystemCursor.SwapButtons;
78 WinStaObject->SystemCursor.SwapButtons = Swap;
79 return res;
80 }
81
82 INT STDCALL
83 MouseSafetyOnDrawStart(PSURFOBJ SurfObj, PSURFGDI SurfGDI, LONG HazardX1,
84 LONG HazardY1, LONG HazardX2, LONG HazardY2)
85 /*
86 * FUNCTION: Notify the mouse driver that drawing is about to begin in
87 * a rectangle on a particular surface.
88 */
89 {
90 LONG tmp;
91 PSYSTEM_CURSORINFO CurInfo;
92 BOOL MouseEnabled = FALSE;
93 PCURICON_OBJECT Cursor;
94
95
96 /* Mouse is not allowed to move if GDI is busy drawing */
97
98 if(IntGetWindowStationObject(InputWindowStation))
99 {
100 CurInfo = &InputWindowStation->SystemCursor;
101
102 MouseEnabled = CurInfo->Enabled && CurInfo->ShowingCursor;
103 }
104 else
105 return FALSE;
106
107 if (SurfObj == NULL)
108 {
109 ObDereferenceObject(InputWindowStation);
110 return(FALSE);
111 }
112
113
114 if (SurfObj->iType != STYPE_DEVICE || MouseEnabled == FALSE)
115 {
116 ObDereferenceObject(InputWindowStation);
117 return(FALSE);
118 }
119
120 if (SPS_ACCEPT_NOEXCLUDE == SurfGDI->PointerStatus)
121 {
122 /* Hardware cursor, no need to remove it */
123 ObDereferenceObject(InputWindowStation);
124 return(FALSE);
125 }
126
127 if(!(Cursor = CurInfo->CurrentCursorObject))
128 {
129 ObDereferenceObject(InputWindowStation);
130 return(FALSE);
131 }
132
133 if (HazardX1 > HazardX2)
134 {
135 tmp = HazardX2; HazardX2 = HazardX1; HazardX1 = tmp;
136 }
137 if (HazardY1 > HazardY2)
138 {
139 tmp = HazardY2; HazardY2 = HazardY1; HazardY1 = tmp;
140 }
141
142 if (CurInfo->PointerRectRight >= HazardX1
143 && CurInfo->PointerRectLeft <= HazardX2
144 && CurInfo->PointerRectBottom >= HazardY1
145 && CurInfo->PointerRectTop <= HazardY2)
146 {
147 /* Mouse is not allowed to move if GDI is busy drawing */
148 ExAcquireFastMutex(&CurInfo->CursorMutex);
149 if (0 != CurInfo->SafetyRemoveCount++)
150 {
151 /* Was already removed */
152 ExReleaseFastMutex(&CurInfo->CursorMutex);
153 ObDereferenceObject(InputWindowStation);
154 return FALSE;
155 }
156 CurInfo->SafetySwitch = TRUE;
157 ExAcquireFastMutex(SurfGDI->DriverLock);
158 SurfGDI->MovePointer(SurfObj, -1, -1, NULL);
159 ExReleaseFastMutex(SurfGDI->DriverLock);
160 ExReleaseFastMutex(&CurInfo->CursorMutex);
161 }
162
163 ObDereferenceObject(InputWindowStation);
164 return(TRUE);
165 }
166
167 STATIC VOID FASTCALL
168 SetPointerRect(PSYSTEM_CURSORINFO CurInfo, PRECTL PointerRect)
169 {
170 CurInfo->PointerRectLeft = PointerRect->left;
171 CurInfo->PointerRectRight = PointerRect->right;
172 CurInfo->PointerRectTop = PointerRect->top;
173 CurInfo->PointerRectBottom = PointerRect->bottom;
174 }
175
176 INT FASTCALL
177 MouseSafetyOnDrawEnd(PSURFOBJ SurfObj, PSURFGDI SurfGDI)
178 /*
179 * FUNCTION: Notify the mouse driver that drawing has finished on a surface.
180 */
181 {
182 PSYSTEM_CURSORINFO CurInfo;
183 BOOL MouseEnabled = FALSE;
184 RECTL PointerRect;
185
186 if(IntGetWindowStationObject(InputWindowStation))
187 {
188 CurInfo = &InputWindowStation->SystemCursor;
189 }
190 else
191 return FALSE;
192
193 ExAcquireFastMutex(&CurInfo->CursorMutex);
194 if(SurfObj == NULL)
195 {
196 ExReleaseFastMutex(&CurInfo->CursorMutex);
197 ObDereferenceObject(InputWindowStation);
198 return FALSE;
199 }
200
201 MouseEnabled = CurInfo->Enabled && CurInfo->ShowingCursor;
202
203 if (SurfObj->iType != STYPE_DEVICE || MouseEnabled == FALSE)
204 {
205 ExReleaseFastMutex(&CurInfo->CursorMutex);
206 ObDereferenceObject(InputWindowStation);
207 return(FALSE);
208 }
209
210 if (SPS_ACCEPT_NOEXCLUDE == SurfGDI->PointerStatus)
211 {
212 /* Hardware cursor, it wasn't removed so need to restore it */
213 ExReleaseFastMutex(&CurInfo->CursorMutex);
214 ObDereferenceObject(InputWindowStation);
215 return(FALSE);
216 }
217
218 if (CurInfo->SafetySwitch)
219 {
220 if (1 < CurInfo->SafetyRemoveCount--)
221 {
222 /* Someone else removed it too, let them restore it */
223 ExReleaseFastMutex(&CurInfo->CursorMutex);
224 ObDereferenceObject(InputWindowStation);
225 return FALSE;
226 }
227 ExAcquireFastMutex(SurfGDI->DriverLock);
228 SurfGDI->MovePointer(SurfObj, CurInfo->x, CurInfo->y, &PointerRect);
229 ExReleaseFastMutex(SurfGDI->DriverLock);
230 SetPointerRect(CurInfo, &PointerRect);
231 CurInfo->SafetySwitch = FALSE;
232 }
233
234 ExReleaseFastMutex(&CurInfo->CursorMutex);
235 ObDereferenceObject(InputWindowStation);
236 return(TRUE);
237 }
238
239 BOOL FASTCALL
240 MouseMoveCursor(LONG X, LONG Y)
241 {
242 HDC hDC;
243 PDC dc;
244 BOOL res = FALSE;
245 PSURFOBJ SurfObj;
246 PSURFGDI SurfGDI;
247 PSYSTEM_CURSORINFO CurInfo;
248 MSG Msg;
249 LARGE_INTEGER LargeTickCount;
250 ULONG TickCount;
251 RECTL PointerRect;
252
253 if(!InputWindowStation)
254 return FALSE;
255
256 if(IntGetWindowStationObject(InputWindowStation))
257 {
258 CurInfo = &InputWindowStation->SystemCursor;
259 if(!CurInfo->Enabled)
260 {
261 ObDereferenceObject(InputWindowStation);
262 return FALSE;
263 }
264 hDC = IntGetScreenDC();
265 if(!hDC)
266 {
267 ObDereferenceObject(InputWindowStation);
268 return FALSE;
269 }
270 dc = DC_LockDc(hDC);
271 SurfObj = (PSURFOBJ)AccessUserObject((ULONG) dc->Surface);
272 SurfGDI = (PSURFGDI)AccessInternalObject((ULONG) dc->Surface);
273 DC_UnlockDc( hDC );
274 IntCheckClipCursor(&X, &Y, CurInfo);
275 if((X != CurInfo->x) || (Y != CurInfo->y))
276 {
277 /* move cursor */
278 CurInfo->x = X;
279 CurInfo->y = Y;
280 if(CurInfo->Enabled)
281 {
282 ExAcquireFastMutex(&CurInfo->CursorMutex);
283 ExAcquireFastMutex(SurfGDI->DriverLock);
284 SurfGDI->MovePointer(SurfObj, CurInfo->x, CurInfo->y, &PointerRect);
285 ExReleaseFastMutex(SurfGDI->DriverLock);
286 SetPointerRect(CurInfo, &PointerRect);
287 ExReleaseFastMutex(&CurInfo->CursorMutex);
288 }
289 /* send MOUSEMOVE message */
290 KeQueryTickCount(&LargeTickCount);
291 TickCount = LargeTickCount.u.LowPart;
292 Msg.wParam = CurInfo->ButtonsDown;
293 Msg.lParam = MAKELPARAM(X, Y);
294 Msg.message = WM_MOUSEMOVE;
295 Msg.time = TickCount;
296 Msg.pt.x = X;
297 Msg.pt.y = Y;
298 MsqInsertSystemMessage(&Msg, TRUE);
299 res = TRUE;
300 }
301
302 ObDereferenceObject(InputWindowStation);
303 return res;
304 }
305 else
306 return FALSE;
307 }
308
309 VOID /* STDCALL */
310 MouseGDICallBack(PMOUSE_INPUT_DATA Data, ULONG InputCount)
311 /*
312 * FUNCTION: Call by the mouse driver when input events occur.
313 */
314 {
315 ULONG i;
316 PSYSTEM_CURSORINFO CurInfo;
317 BOOL MouseEnabled = FALSE;
318 BOOL Moved = FALSE;
319 LONG mouse_ox, mouse_oy;
320 LONG mouse_cx = 0, mouse_cy = 0;
321 LONG dScroll = 0;
322 HDC hDC;
323 PDC dc;
324 PSURFOBJ SurfObj;
325 PSURFGDI SurfGDI;
326 MSG Msg;
327 RECTL PointerRect;
328
329 hDC = IntGetScreenDC();
330
331 if(!hDC || !InputWindowStation)
332 return;
333
334 if(IntGetWindowStationObject(InputWindowStation))
335 {
336 CurInfo = &InputWindowStation->SystemCursor;
337 MouseEnabled = CurInfo->Enabled;
338 if(!MouseEnabled)
339 {
340 ObDereferenceObject(InputWindowStation);
341 return;
342 }
343 mouse_ox = CurInfo->x;
344 mouse_oy = CurInfo->y;
345 }
346 else
347 return;
348
349 dc = DC_LockDc(hDC);
350 SurfObj = (PSURFOBJ)AccessUserObject((ULONG) dc->Surface);
351 SurfGDI = (PSURFGDI)AccessInternalObject((ULONG) dc->Surface);
352 DC_UnlockDc( hDC );
353
354 /* Compile the total mouse movement change and dispatch button events. */
355 for (i = 0; i < InputCount; i++)
356 {
357 mouse_cx += Data[i].LastX;
358 mouse_cy += Data[i].LastY;
359
360 CurInfo->x += Data[i].LastX;
361 CurInfo->y += Data[i].LastY;
362
363 CurInfo->x = max(CurInfo->x, 0);
364 CurInfo->y = max(CurInfo->y, 0);
365 CurInfo->x = min(CurInfo->x, SurfObj->sizlBitmap.cx - 1);
366 CurInfo->y = min(CurInfo->y, SurfObj->sizlBitmap.cy - 1);
367
368 IntCheckClipCursor(&CurInfo->x, &CurInfo->y, CurInfo);
369
370 Msg.wParam = CurInfo->ButtonsDown;
371 Msg.lParam = MAKELPARAM(CurInfo->x, CurInfo->y);
372 Msg.message = WM_MOUSEMOVE;
373 Msg.pt.x = CurInfo->x;
374 Msg.pt.y = CurInfo->y;
375
376 if (Data[i].ButtonFlags != 0)
377 {
378 if ((Data[i].ButtonFlags & MOUSE_LEFT_BUTTON_DOWN) > 0)
379 {
380 CurInfo->ButtonsDown |= (CurInfo->SwapButtons ? MK_RBUTTON : MK_LBUTTON);
381 Msg.message = (CurInfo->SwapButtons ? WM_RBUTTONDOWN : WM_LBUTTONDOWN);
382 }
383 if ((Data[i].ButtonFlags & MOUSE_MIDDLE_BUTTON_DOWN) > 0)
384 {
385 CurInfo->ButtonsDown |= MK_MBUTTON;
386 Msg.message = WM_MBUTTONDOWN;
387 }
388 if ((Data[i].ButtonFlags & MOUSE_RIGHT_BUTTON_DOWN) > 0)
389 {
390 CurInfo->ButtonsDown |= (CurInfo->SwapButtons ? MK_LBUTTON : MK_RBUTTON);
391 Msg.message = (CurInfo->SwapButtons ? WM_LBUTTONDOWN : WM_RBUTTONDOWN);
392 }
393
394 if ((Data[i].ButtonFlags & MOUSE_BUTTON_4_DOWN) > 0)
395 {
396 CurInfo->ButtonsDown |= MK_XBUTTON1;
397 Msg.message = WM_XBUTTONDOWN;
398 }
399 if ((Data[i].ButtonFlags & MOUSE_BUTTON_5_DOWN) > 0)
400 {
401 CurInfo->ButtonsDown |= MK_XBUTTON2;
402 Msg.message = WM_XBUTTONDOWN;
403 }
404
405 if ((Data[i].ButtonFlags & MOUSE_LEFT_BUTTON_UP) > 0)
406 {
407 CurInfo->ButtonsDown &= (CurInfo->SwapButtons ? ~MK_RBUTTON : ~MK_LBUTTON);
408 Msg.message = (CurInfo->SwapButtons ? WM_RBUTTONUP : WM_LBUTTONUP);
409 }
410 if ((Data[i].ButtonFlags & MOUSE_MIDDLE_BUTTON_UP) > 0)
411 {
412 CurInfo->ButtonsDown &= ~MK_MBUTTON;
413 Msg.message = WM_MBUTTONUP;
414 }
415 if ((Data[i].ButtonFlags & MOUSE_RIGHT_BUTTON_UP) > 0)
416 {
417 CurInfo->ButtonsDown &= (CurInfo->SwapButtons ? ~MK_LBUTTON : ~MK_RBUTTON);
418 Msg.message = (CurInfo->SwapButtons ? WM_LBUTTONUP : WM_RBUTTONUP);
419 }
420 if ((Data[i].ButtonFlags & MOUSE_BUTTON_4_UP) > 0)
421 {
422 CurInfo->ButtonsDown &= ~MK_XBUTTON1;
423 Msg.message = WM_XBUTTONUP;
424 }
425 if ((Data[i].ButtonFlags & MOUSE_BUTTON_5_UP) > 0)
426 {
427 CurInfo->ButtonsDown &= ~MK_XBUTTON2;
428 Msg.message = WM_XBUTTONUP;
429 }
430 if ((Data[i].ButtonFlags & MOUSE_WHEEL) > 0)
431 {
432 dScroll += (LONG)Data[i].ButtonData;
433 }
434
435 if (Data[i].ButtonFlags != MOUSE_WHEEL)
436 {
437 Moved = (0 != mouse_cx) || (0 != mouse_cy);
438 if(Moved && MouseEnabled)
439 {
440 if (!CurInfo->SafetySwitch && 0 == CurInfo->SafetyRemoveCount &&
441 ((mouse_ox != CurInfo->x) || (mouse_oy != CurInfo->y)))
442 {
443 ExAcquireFastMutex(&CurInfo->CursorMutex);
444 ExAcquireFastMutex(SurfGDI->DriverLock);
445 SurfGDI->MovePointer(SurfObj, CurInfo->x, CurInfo->y, &PointerRect);
446 ExReleaseFastMutex(SurfGDI->DriverLock);
447 SetPointerRect(CurInfo, &PointerRect);
448 ExReleaseFastMutex(&CurInfo->CursorMutex);
449 mouse_cx = 0;
450 mouse_cy = 0;
451 }
452 }
453
454 Msg.wParam = CurInfo->ButtonsDown;
455 MsqInsertSystemMessage(&Msg, FALSE);
456 }
457 }
458 }
459
460 /* If the mouse moved then move the pointer. */
461 if ((mouse_cx != 0 || mouse_cy != 0) && MouseEnabled)
462 {
463 Msg.wParam = CurInfo->ButtonsDown;
464 Msg.message = WM_MOUSEMOVE;
465 Msg.pt.x = CurInfo->x;
466 Msg.pt.y = CurInfo->y;
467 Msg.lParam = MAKELPARAM(CurInfo->x, CurInfo->y);
468 MsqInsertSystemMessage(&Msg, TRUE);
469
470 if (!CurInfo->SafetySwitch && 0 == CurInfo->SafetyRemoveCount &&
471 ((mouse_ox != CurInfo->x) || (mouse_oy != CurInfo->y)))
472 {
473 ExAcquireFastMutex(&CurInfo->CursorMutex);
474 ExAcquireFastMutex(SurfGDI->DriverLock);
475 SurfGDI->MovePointer(SurfObj, CurInfo->x, CurInfo->y, &PointerRect);
476 ExReleaseFastMutex(SurfGDI->DriverLock);
477 SetPointerRect(CurInfo, &PointerRect);
478 ExReleaseFastMutex(&CurInfo->CursorMutex);
479 }
480 }
481
482 /* send WM_MOUSEWHEEL message */
483 if(dScroll && MouseEnabled)
484 {
485 Msg.message = WM_MOUSEWHEEL;
486 Msg.wParam = MAKEWPARAM(CurInfo->ButtonsDown, dScroll);
487 Msg.lParam = MAKELPARAM(CurInfo->x, CurInfo->y);
488 Msg.pt.x = CurInfo->x;
489 Msg.pt.y = CurInfo->y;
490 MsqInsertSystemMessage(&Msg, FALSE);
491 }
492
493 ObDereferenceObject(InputWindowStation);
494 }
495
496 VOID FASTCALL
497 EnableMouse(HDC hDisplayDC)
498 {
499 PDC dc;
500 PSURFOBJ SurfObj;
501 PSURFGDI SurfGDI;
502
503 if( hDisplayDC && InputWindowStation)
504 {
505 if(!IntGetWindowStationObject(InputWindowStation))
506 {
507 InputWindowStation->SystemCursor.Enabled = FALSE;
508 return;
509 }
510
511 dc = DC_LockDc(hDisplayDC);
512 SurfObj = (PSURFOBJ)AccessUserObject((ULONG) dc->Surface);
513 SurfGDI = (PSURFGDI)AccessInternalObject((ULONG) dc->Surface);
514 DC_UnlockDc( hDisplayDC );
515
516 IntSetCursor(InputWindowStation, NULL, TRUE);
517
518 InputWindowStation->SystemCursor.Enabled = (SPS_ACCEPT_EXCLUDE == SurfGDI->PointerStatus ||
519 SPS_ACCEPT_NOEXCLUDE == SurfGDI->PointerStatus);
520
521 /* Move the cursor to the screen center */
522 DPRINT("Setting Cursor up at 0x%x, 0x%x\n", SurfObj->sizlBitmap.cx / 2, SurfObj->sizlBitmap.cy / 2);
523 MouseMoveCursor(SurfObj->sizlBitmap.cx / 2, SurfObj->sizlBitmap.cy / 2);
524
525 ObDereferenceObject(InputWindowStation);
526 }
527 else
528 {
529 if(IntGetWindowStationObject(InputWindowStation))
530 {
531 IntSetCursor(InputWindowStation, NULL, TRUE);
532 InputWindowStation->SystemCursor.Enabled = FALSE;
533 InputWindowStation->SystemCursor.CursorClipInfo.IsClipped = FALSE;
534 ObDereferenceObject(InputWindowStation);
535 return;
536 }
537 }
538 }
539
540 /* SOFTWARE MOUSE POINTER IMPLEMENTATION **************************************/
541
542 VOID FASTCALL
543 IntHideMousePointer(GDIDEVICE *ppdev, SURFOBJ *DestSurface)
544 {
545 if (ppdev->PointerAttributes.Enable == FALSE)
546 {
547 return;
548 }
549
550 ppdev->PointerAttributes.Enable = FALSE;
551
552 if (ppdev->PointerAttributes.Column + ppdev->PointerHotSpot.x == -1)
553 {
554 return;
555 }
556
557 if (ppdev->PointerSaveSurface != NULL)
558 {
559 RECTL DestRect;
560 POINTL SrcPoint;
561 SURFOBJ *SaveSurface;
562 SURFOBJ *MaskSurface;
563
564 DestRect.left = max(ppdev->PointerAttributes.Column, 0);
565 DestRect.top = max(ppdev->PointerAttributes.Row, 0);
566 DestRect.right = min(
567 ppdev->PointerAttributes.Column + ppdev->PointerAttributes.Width,
568 DestSurface->sizlBitmap.cx);
569 DestRect.bottom = min(
570 ppdev->PointerAttributes.Row + ppdev->PointerAttributes.Height,
571 DestSurface->sizlBitmap.cy);
572
573 SrcPoint.x = max(-ppdev->PointerAttributes.Column, 0);
574 SrcPoint.y = max(-ppdev->PointerAttributes.Row, 0);
575
576 SaveSurface = EngLockSurface(ppdev->PointerSaveSurface);
577 MaskSurface = EngLockSurface(ppdev->PointerMaskSurface);
578 EngBitBlt(DestSurface, SaveSurface, MaskSurface, NULL, NULL,
579 &DestRect, &SrcPoint, &SrcPoint, NULL, NULL, SRCCOPY);
580 EngUnlockSurface(MaskSurface);
581 EngUnlockSurface(SaveSurface);
582 }
583 }
584
585 VOID FASTCALL
586 IntShowMousePointer(GDIDEVICE *ppdev, SURFOBJ *DestSurface)
587 {
588 if (ppdev->PointerAttributes.Enable == TRUE)
589 {
590 return;
591 }
592
593 ppdev->PointerAttributes.Enable = TRUE;
594
595 /*
596 * Copy the pixels under the cursor to temporary surface.
597 */
598
599 if (ppdev->PointerSaveSurface != NULL)
600 {
601 RECTL DestRect;
602 POINTL SrcPoint;
603 SURFOBJ *SaveSurface;
604
605 SrcPoint.x = max(ppdev->PointerAttributes.Column, 0);
606 SrcPoint.y = max(ppdev->PointerAttributes.Row, 0);
607
608 DestRect.left = SrcPoint.x - ppdev->PointerAttributes.Column;
609 DestRect.top = SrcPoint.y - ppdev->PointerAttributes.Row;
610 DestRect.right = min(
611 ppdev->PointerAttributes.Width,
612 DestSurface->sizlBitmap.cx - ppdev->PointerAttributes.Column);
613 DestRect.bottom = min(
614 ppdev->PointerAttributes.Height,
615 DestSurface->sizlBitmap.cy - ppdev->PointerAttributes.Row);
616
617 SaveSurface = EngLockSurface(ppdev->PointerSaveSurface);
618 EngBitBlt(SaveSurface, DestSurface, NULL, NULL, NULL,
619 &DestRect, &SrcPoint, NULL, NULL, NULL, SRCCOPY);
620 EngUnlockSurface(SaveSurface);
621 }
622
623 /*
624 * Blit the cursor on the screen.
625 */
626
627 {
628 RECTL DestRect;
629 POINTL SrcPoint;
630 SURFOBJ *ColorSurf;
631 SURFOBJ *MaskSurf;
632
633 DestRect.left = max(ppdev->PointerAttributes.Column, 0);
634 DestRect.top = max(ppdev->PointerAttributes.Row, 0);
635 DestRect.right = min(
636 ppdev->PointerAttributes.Column + ppdev->PointerAttributes.Width,
637 DestSurface->sizlBitmap.cx);
638 DestRect.bottom = min(
639 ppdev->PointerAttributes.Row + ppdev->PointerAttributes.Height,
640 DestSurface->sizlBitmap.cy);
641
642 SrcPoint.x = max(-ppdev->PointerAttributes.Column, 0);
643 SrcPoint.y = max(-ppdev->PointerAttributes.Row, 0);
644
645 MaskSurf = EngLockSurface(ppdev->PointerMaskSurface);
646 if (ppdev->PointerColorSurface != NULL)
647 {
648 ColorSurf = EngLockSurface(ppdev->PointerColorSurface);
649 EngBitBlt(DestSurface, ColorSurf, MaskSurf, NULL, ppdev->PointerXlateObject,
650 &DestRect, &SrcPoint, &SrcPoint, NULL, NULL, 0xAACC);
651 EngUnlockSurface(ColorSurf);
652 }
653 else
654 {
655 EngBitBlt(DestSurface, MaskSurf, NULL, NULL, ppdev->PointerXlateObject,
656 &DestRect, &SrcPoint, NULL, NULL, NULL, SRCAND);
657 SrcPoint.y += ppdev->PointerAttributes.Height;
658 EngBitBlt(DestSurface, MaskSurf, NULL, NULL, ppdev->PointerXlateObject,
659 &DestRect, &SrcPoint, NULL, NULL, NULL, SRCINVERT);
660 }
661 EngUnlockSurface(MaskSurf);
662 }
663 }
664
665 /*
666 * @implemented
667 */
668
669 ULONG STDCALL
670 EngSetPointerShape(
671 IN SURFOBJ *pso,
672 IN SURFOBJ *psoMask,
673 IN SURFOBJ *psoColor,
674 IN XLATEOBJ *pxlo,
675 IN LONG xHot,
676 IN LONG yHot,
677 IN LONG x,
678 IN LONG y,
679 IN RECTL *prcl,
680 IN FLONG fl)
681 {
682 GDIDEVICE *ppdev = (GDIDEVICE *)pso->hdev;
683 SURFOBJ *TempSurfObj;
684
685 IntHideMousePointer(ppdev, pso);
686
687 if (ppdev->PointerColorSurface != NULL)
688 {
689 /* FIXME: Is this really needed? */
690 TempSurfObj = EngLockSurface(ppdev->PointerColorSurface);
691 EngFreeMem(TempSurfObj->pvBits);
692 TempSurfObj->pvBits = 0;
693 EngUnlockSurface(TempSurfObj);
694
695 EngDeleteSurface(ppdev->PointerColorSurface);
696 ppdev->PointerMaskSurface = NULL;
697 }
698
699 if (ppdev->PointerMaskSurface != NULL)
700 {
701 /* FIXME: Is this really needed? */
702 TempSurfObj = EngLockSurface(ppdev->PointerMaskSurface);
703 EngFreeMem(TempSurfObj->pvBits);
704 TempSurfObj->pvBits = 0;
705 EngUnlockSurface(TempSurfObj);
706
707 EngDeleteSurface(ppdev->PointerMaskSurface);
708 ppdev->PointerMaskSurface = NULL;
709 }
710
711 if (ppdev->PointerSaveSurface != NULL)
712 {
713 EngDeleteSurface(ppdev->PointerSaveSurface);
714 ppdev->PointerSaveSurface = NULL;
715 }
716
717 if (ppdev->PointerXlateObject != NULL)
718 {
719 EngDeleteXlate(ppdev->PointerXlateObject);
720 ppdev->PointerXlateObject = NULL;
721 }
722
723 /*
724 * See if we are being asked to hide the pointer.
725 */
726
727 if (psoMask == NULL)
728 {
729 return SPS_ACCEPT_NOEXCLUDE;
730 }
731
732 ppdev->PointerHotSpot.x = xHot;
733 ppdev->PointerHotSpot.y = yHot;
734
735 ppdev->PointerAttributes.Column = x - xHot;
736 ppdev->PointerAttributes.Row = y - yHot;
737 ppdev->PointerAttributes.Width = psoMask->lDelta << 3;
738 ppdev->PointerAttributes.Height = (psoMask->cjBits / psoMask->lDelta) >> 1;
739
740 if (prcl != NULL)
741 {
742 prcl->left = ppdev->PointerAttributes.Column;
743 prcl->top = ppdev->PointerAttributes.Row;
744 prcl->right = prcl->left + ppdev->PointerAttributes.Width;
745 prcl->bottom = prcl->top + ppdev->PointerAttributes.Height;
746 }
747
748 if (psoColor != NULL)
749 {
750 SIZEL Size;
751 PBYTE Bits;
752
753 Size.cx = ppdev->PointerAttributes.Width;
754 Size.cy = ppdev->PointerAttributes.Height;
755 Bits = EngAllocMem(0, psoColor->cjBits, TAG_MOUSE);
756 memcpy(Bits, psoColor->pvBits, psoColor->cjBits);
757
758 ppdev->PointerColorSurface = (HSURF)EngCreateBitmap(Size,
759 psoColor->lDelta, psoColor->iBitmapFormat, 0, Bits);
760 }
761 else
762 {
763 ppdev->PointerColorSurface = NULL;
764 }
765
766 {
767 SIZEL Size;
768 PBYTE Bits;
769
770 Size.cx = ppdev->PointerAttributes.Width;
771 Size.cy = ppdev->PointerAttributes.Height << 1;
772 Bits = EngAllocMem(0, psoMask->cjBits, TAG_MOUSE);
773 memcpy(Bits, psoMask->pvBits, psoMask->cjBits);
774
775 ppdev->PointerMaskSurface = (HSURF)EngCreateBitmap(Size,
776 psoMask->lDelta, psoMask->iBitmapFormat, 0, Bits);
777 }
778
779 /*
780 * Create and XLATEOBJ that will be used for drawing masks.
781 * FIXME: We should get this in pxlo parameter!
782 */
783
784 if (pxlo == NULL)
785 {
786 HPALETTE BWPalette, DestPalette;
787 ULONG BWColors[] = {0, 0xFFFFFF};
788 PDC Dc;
789 PPALGDI PalObj;
790 LONG DestMode;
791
792 BWPalette = EngCreatePalette(PAL_INDEXED, sizeof(BWColors) / sizeof(ULONG),
793 BWColors, 0, 0, 0);
794 Dc = DC_LockDc(IntGetScreenDC());
795 DestPalette = Dc->w.hPalette;
796 PalObj = PALETTE_LockPalette(DestPalette);
797 DestMode = PalObj->Mode;
798 PALETTE_UnlockPalette(DestPalette);
799 DC_UnlockDc(IntGetScreenDC());
800 ppdev->PointerXlateObject = IntEngCreateXlate(DestMode, PAL_INDEXED,
801 DestPalette, BWPalette);
802 EngDeletePalette(BWPalette);
803 }
804 else
805 {
806 ppdev->PointerXlateObject = pxlo;
807 }
808
809 /*
810 * Create surface for saving the pixels under the cursor.
811 */
812
813 {
814 SIZEL Size;
815 LONG lDelta;
816
817 Size.cx = ppdev->PointerAttributes.Width;
818 Size.cy = ppdev->PointerAttributes.Height;
819
820 switch (pso->iBitmapFormat)
821 {
822 case BMF_1BPP: lDelta = Size.cx >> 3; break;
823 case BMF_4BPP: lDelta = Size.cx >> 1; break;
824 case BMF_8BPP: lDelta = Size.cx; break;
825 case BMF_16BPP: lDelta = Size.cx << 1; break;
826 case BMF_24BPP: lDelta = Size.cx * 3; break;
827 case BMF_32BPP: lDelta = Size.cx << 2; break;
828 }
829
830 ppdev->PointerSaveSurface = (HSURF)EngCreateBitmap(
831 Size, lDelta, pso->iBitmapFormat, BMF_NOZEROINIT, NULL);
832 }
833
834 IntShowMousePointer(ppdev, pso);
835
836 return SPS_ACCEPT_EXCLUDE;
837 }
838
839 /*
840 * @implemented
841 */
842
843 VOID STDCALL
844 EngMovePointer(
845 IN SURFOBJ *pso,
846 IN LONG x,
847 IN LONG y,
848 IN RECTL *prcl)
849 {
850 GDIDEVICE *ppdev = (GDIDEVICE *)pso->hdev;
851 PSURFGDI SurfGDI = AccessInternalObjectFromUserObject(pso);
852
853 /*
854 * Prevent GDI from trying to remve the mouse cursor,
855 * because it would cause unexpected reentrancy effects.
856 */
857
858 SurfGDI->PointerStatus = SPS_ACCEPT_NOEXCLUDE;
859
860 IntHideMousePointer(ppdev, pso);
861 ppdev->PointerAttributes.Column = x - ppdev->PointerHotSpot.x;
862 ppdev->PointerAttributes.Row = y - ppdev->PointerHotSpot.y;
863 if (x != -1)
864 {
865 IntShowMousePointer(ppdev, pso);
866 }
867
868 if (prcl != NULL)
869 {
870 prcl->left = ppdev->PointerAttributes.Column;
871 prcl->top = ppdev->PointerAttributes.Row;
872 prcl->right = prcl->left + ppdev->PointerAttributes.Width;
873 prcl->bottom = prcl->top + ppdev->PointerAttributes.Height;
874 }
875
876 SurfGDI->PointerStatus = SPS_ACCEPT_EXCLUDE;
877 }
878
879 /* EOF */