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