216002655582136f224d2216233d9a2974ae75d8
[reactos.git] / reactos / subsystems / win32 / win32k / ntuser / monitor.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * PURPOSE: Monitor support
5 * FILE: subsys/win32k/ntuser/monitor.c
6 * PROGRAMER: Anich Gregor (blight@blight.eu.org)
7 * REVISION HISTORY:
8 * 26-02-2004 Created
9 */
10
11 /* INCLUDES ******************************************************************/
12
13 #include <win32k.h>
14
15 /* FIXME: find include file for these */
16 #define MONITORINFOF_PRIMARY 1
17 #define MONITOR_DEFAULTTONULL 0
18 #define MONITOR_DEFAULTTOPRIMARY 1
19 #define MONITOR_DEFAULTTONEAREST 2
20
21 #define NDEBUG
22 #include <debug.h>
23
24 /* GLOBALS *******************************************************************/
25
26 /* list of monitors */
27 static PMONITOR gMonitorList = NULL;
28
29 /* INITALIZATION FUNCTIONS ****************************************************/
30
31 NTSTATUS
32 InitMonitorImpl()
33 {
34 DPRINT("Initializing monitor implementation...\n");
35
36 return STATUS_SUCCESS;
37 }
38
39 NTSTATUS
40 CleanupMonitorImpl()
41 {
42 DPRINT("Cleaning up monitor implementation...\n");
43 /* FIXME: Destroy monitor objects? */
44
45 return STATUS_SUCCESS;
46 }
47
48 /* PRIVATE FUNCTIONS **********************************************************/
49
50 #ifndef MIN
51 # define MIN(a, b) ((a) < (b) ? (a) : (b))
52 #endif
53 #ifndef MAX
54 # define MAX(a, b) ((a) > (b) ? (a) : (b))
55 #endif
56 #ifndef ABS
57 # define ABS(a) ((a) < (0) ? (-(a)) : (a))
58 #endif
59
60 /* IntCreateMonitorObject
61 *
62 * Creates a MONITOR
63 *
64 * Return value
65 * If the function succeeds a pointer to a MONITOR is returned. On failure
66 * NULL is returned.
67 */
68 static
69 PMONITOR
70 IntCreateMonitorObject()
71 {
72 HANDLE Handle;
73 PMONITOR Monitor;
74
75 Monitor = UserCreateObject(gHandleTable, NULL, &Handle, otMonitor, sizeof (MONITOR));
76 if (Monitor == NULL)
77 {
78 return NULL;
79 }
80
81 ExInitializeFastMutex(&Monitor->Lock);
82
83 return Monitor;
84 }
85
86 /* IntDestroyMonitorObject
87 *
88 * Destroys a MONITOR
89 * You have to be the owner of the monitors lock to safely destroy it.
90 *
91 * Arguments
92 *
93 * pMonitor
94 * Pointer to the MONITOR which shall be deleted
95 */
96 static
97 void
98 IntDestroyMonitorObject(IN PMONITOR pMonitor)
99 {
100 RtlFreeUnicodeString(&pMonitor->DeviceName);
101 UserDereferenceObject(pMonitor);
102 }
103
104
105 PMONITOR FASTCALL
106 UserGetMonitorObject(IN HMONITOR hMonitor)
107 {
108 PMONITOR Monitor;
109
110 if (!hMonitor)
111 {
112 SetLastWin32Error(ERROR_INVALID_MONITOR_HANDLE);
113 return NULL;
114 }
115
116 Monitor = (PMONITOR)UserGetObject(gHandleTable, hMonitor, otMonitor);
117 if (!Monitor)
118 {
119 SetLastWin32Error(ERROR_INVALID_MONITOR_HANDLE);
120 return NULL;
121 }
122
123 ASSERT(Monitor->head.cLockObj >= 0);
124
125 return Monitor;
126 }
127
128
129 /* IntAttachMonitor
130 *
131 * Creates a new MONITOR and appends it to the list of monitors.
132 *
133 * Arguments
134 *
135 * pGdiDevice Pointer to the PDEVOBJ onto which the monitor was attached
136 * DisplayNumber Display Number (starting with 0)
137 *
138 * Return value
139 * Returns a NTSTATUS
140 */
141 NTSTATUS
142 IntAttachMonitor(IN PDEVOBJ *pGdiDevice,
143 IN ULONG DisplayNumber)
144 {
145 PMONITOR Monitor;
146 WCHAR Buffer[CCHDEVICENAME];
147
148 DPRINT("Attaching monitor...\n");
149
150 /* create new monitor object */
151 Monitor = IntCreateMonitorObject();
152 if (Monitor == NULL)
153 {
154 DPRINT("Couldnt create monitor object\n");
155 return STATUS_INSUFFICIENT_RESOURCES;
156 }
157
158 _snwprintf(Buffer, CCHDEVICENAME, L"\\\\.\\DISPLAY%d", DisplayNumber + 1);
159 if (!RtlCreateUnicodeString(&Monitor->DeviceName, Buffer))
160 {
161 DPRINT("Couldn't duplicate monitor name!\n");
162 UserDereferenceObject(Monitor);
163 UserDeleteObject(UserHMGetHandle(Monitor), otMonitor);
164 return STATUS_INSUFFICIENT_RESOURCES;
165 }
166
167 Monitor->GdiDevice = pGdiDevice;
168 Monitor->rcMonitor.left = 0;
169 Monitor->rcMonitor.top = 0;
170 Monitor->rcMonitor.right = Monitor->rcMonitor.left + pGdiDevice->gdiinfo.ulHorzRes;
171 Monitor->rcMonitor.bottom = Monitor->rcMonitor.top + pGdiDevice->gdiinfo.ulVertRes;
172 Monitor->rcWork = Monitor->rcMonitor;
173 Monitor->cWndStack = 0;
174
175 Monitor->hrgnMonitor = IntSysCreateRectRgnIndirect( &Monitor->rcMonitor );
176
177 IntGdiSetRegionOwner(Monitor->hrgnMonitor, GDI_OBJ_HMGR_PUBLIC);
178
179 if (gMonitorList == NULL)
180 {
181 DPRINT("Primary monitor is beeing attached\n");
182 Monitor->IsPrimary = TRUE;
183 gMonitorList = Monitor;
184 }
185 else
186 {
187 PMONITOR p;
188 DPRINT("Additional monitor is beeing attached\n");
189 for (p = gMonitorList; p->Next != NULL; p = p->Next)
190 {
191 p->Next = Monitor;
192 }
193 Monitor->Prev = p;
194 }
195
196 return STATUS_SUCCESS;
197 }
198
199 /* IntDetachMonitor
200 *
201 * Deletes a MONITOR and removes it from the list of monitors.
202 *
203 * Arguments
204 *
205 * pGdiDevice Pointer to the PDEVOBJ from which the monitor was detached
206 *
207 * Return value
208 * Returns a NTSTATUS
209 */
210 NTSTATUS
211 IntDetachMonitor(IN PDEVOBJ *pGdiDevice)
212 {
213 PMONITOR Monitor;
214
215 for (Monitor = gMonitorList; Monitor != NULL; Monitor = Monitor->Next)
216 {
217 if (Monitor->GdiDevice == pGdiDevice)
218 break;
219 }
220
221 if (Monitor == NULL)
222 {
223 /* no monitor for given device found */
224 return STATUS_INVALID_PARAMETER;
225 }
226
227 if (Monitor->IsPrimary && (Monitor->Next != NULL || Monitor->Prev != NULL))
228 {
229 PMONITOR NewPrimaryMonitor = (Monitor->Prev != NULL) ? (Monitor->Prev) : (Monitor->Next);
230
231 ExEnterCriticalRegionAndAcquireFastMutexUnsafe(&NewPrimaryMonitor->Lock);
232 NewPrimaryMonitor->IsPrimary = TRUE;
233 ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(&NewPrimaryMonitor->Lock);
234 }
235
236 if (gMonitorList == Monitor)
237 {
238 gMonitorList = Monitor->Next;
239 if (Monitor->Next != NULL)
240 Monitor->Next->Prev = NULL;
241 }
242 else
243 {
244 Monitor->Prev->Next = Monitor->Next;
245 if (Monitor->Next != NULL)
246 Monitor->Next->Prev = Monitor->Prev;
247 }
248
249 if (Monitor->hrgnMonitor)
250 REGION_FreeRgnByHandle(Monitor->hrgnMonitor);
251
252 IntDestroyMonitorObject(Monitor);
253
254 return STATUS_SUCCESS;
255 }
256
257 /* IntGetPrimaryMonitor
258 *
259 * Returns a PMONITOR for the primary monitor
260 *
261 * Return value
262 * PMONITOR
263 */
264 PMONITOR
265 FASTCALL
266 IntGetPrimaryMonitor()
267 {
268 PMONITOR Monitor;
269
270 for (Monitor = gMonitorList; Monitor != NULL; Monitor = Monitor->Next)
271 {
272 /* FIXME: I guess locking the monitor is not neccessary to read 1 int */
273 if (Monitor->IsPrimary)
274 break;
275 }
276
277 return Monitor;
278 }
279
280 /* IntGetMonitorsFromRect
281 *
282 * Returns a list of monitor handles/rectangles. The rectangles in the list are
283 * the areas of intersection with the monitors.
284 *
285 * Arguments
286 *
287 * pRect
288 * Rectangle in desktop coordinates. If this is NULL all monitors are
289 * returned and the rect list is filled with the sizes of the monitors.
290 *
291 * hMonitorList
292 * Pointer to an array of HMONITOR which is filled with monitor handles.
293 * Can be NULL
294 *
295 * monitorRectList
296 * Pointer to an array of RECT which is filled with intersection rects in
297 * desktop coordinates.
298 * Can be NULL, will be ignored if no intersecting monitor is found and
299 * flags is MONITOR_DEFAULTTONEAREST
300 *
301 * listSize
302 * Size of the hMonitorList and monitorRectList arguments. If this is zero
303 * hMonitorList and monitorRectList are ignored.
304 *
305 * flags
306 * Either 0 or MONITOR_DEFAULTTONEAREST (ignored if rect is NULL)
307 *
308 * Returns
309 * The number of monitors which intersect the specified region.
310 */
311 static
312 UINT
313 IntGetMonitorsFromRect(OPTIONAL IN LPCRECTL pRect,
314 OPTIONAL OUT HMONITOR *hMonitorList,
315 OPTIONAL OUT PRECTL monitorRectList,
316 OPTIONAL IN DWORD listSize,
317 OPTIONAL IN DWORD flags)
318 {
319 PMONITOR Monitor, NearestMonitor = NULL, PrimaryMonitor = NULL;
320 UINT iCount = 0;
321 LONG iNearestDistanceX = 0x7fffffff, iNearestDistanceY = 0x7fffffff;
322
323 /* find monitors which intersect the rectangle */
324 for (Monitor = gMonitorList; Monitor != NULL; Monitor = Monitor->Next)
325 {
326 RECTL MonitorRect, IntersectionRect;
327
328 ExEnterCriticalRegionAndAcquireFastMutexUnsafe(&Monitor->Lock);
329 MonitorRect = Monitor->rcMonitor;
330 ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(&Monitor->Lock);
331
332 DPRINT("MonitorRect: left = %d, top = %d, right = %d, bottom = %d\n",
333 MonitorRect.left, MonitorRect.top, MonitorRect.right, MonitorRect.bottom);
334
335 if (flags == MONITOR_DEFAULTTOPRIMARY && Monitor->IsPrimary)
336 {
337 PrimaryMonitor = Monitor;
338 }
339
340 if (pRect != NULL)
341 {
342 BOOL intersects = TRUE;
343
344 /* check if the rect intersects the monitor */
345 if ((pRect->right < MonitorRect.left) || (pRect->left > MonitorRect.right) ||
346 (pRect->bottom < MonitorRect.top) || (pRect->top > MonitorRect.bottom))
347 {
348 intersects = FALSE;
349 }
350
351 if (flags == MONITOR_DEFAULTTONEAREST && !intersects)
352 {
353 INT distanceX, distanceY;
354
355 distanceX = MIN(ABS(MonitorRect.left - pRect->right),
356 ABS(pRect->left - MonitorRect.right));
357 distanceY = MIN(ABS(MonitorRect.top - pRect->bottom),
358 ABS(pRect->top - MonitorRect.bottom));
359
360 if (((distanceX < iNearestDistanceX) && (distanceY <= iNearestDistanceY)) ||
361 ((distanceX <= iNearestDistanceX) && (distanceY < iNearestDistanceY)))
362 {
363 iNearestDistanceX = distanceX;
364 iNearestDistanceY = distanceY;
365 NearestMonitor = Monitor;
366 }
367 }
368
369 if (!intersects)
370 continue;
371
372 /* calculate intersection */
373 IntersectionRect.left = MAX(MonitorRect.left, pRect->left);
374 IntersectionRect.top = MAX(MonitorRect.top, pRect->top);
375 IntersectionRect.right = MIN(MonitorRect.right, pRect->right);
376 IntersectionRect.bottom = MIN(MonitorRect.bottom, pRect->bottom);
377 }
378 else
379 {
380 IntersectionRect = MonitorRect;
381 }
382
383 if (iCount < listSize)
384 {
385 if (hMonitorList != NULL)
386 hMonitorList[iCount] = UserHMGetHandle(Monitor);
387 if (monitorRectList != NULL)
388 monitorRectList[iCount] = IntersectionRect;
389 }
390 iCount++;
391 }
392
393 if (iCount == 0 && flags == MONITOR_DEFAULTTONEAREST)
394 {
395 if (iCount < listSize)
396 {
397 if (hMonitorList != NULL)
398 hMonitorList[iCount] = UserHMGetHandle(NearestMonitor);
399 }
400 iCount++;
401 }
402 else if (iCount == 0 && flags == MONITOR_DEFAULTTOPRIMARY)
403 {
404 if (iCount < listSize)
405 {
406 if (hMonitorList != NULL)
407 hMonitorList[iCount] = UserHMGetHandle(PrimaryMonitor);
408 }
409 iCount++;
410 }
411 return iCount;
412 }
413
414 /* PUBLIC FUNCTIONS ***********************************************************/
415
416 /* NtUserEnumDisplayMonitors
417 *
418 * Enumerates display monitors which intersect the given HDC/cliprect
419 *
420 * Arguments
421 *
422 * hDC
423 * Handle to a DC for which to enum intersecting monitors. If this is NULL
424 * it returns all monitors which are part of the current virtual screen.
425 *
426 * pRect
427 * Clipping rectangle with coordinate system origin at the DCs origin if the
428 * given HDC is not NULL or in virtual screen coordinated if it is NULL.
429 * Can be NULL
430 *
431 * hMonitorList
432 * Pointer to an array of HMONITOR which is filled with monitor handles.
433 * Can be NULL
434 *
435 * monitorRectList
436 * Pointer to an array of RECT which is filled with intersection rectangles.
437 * Can be NULL
438 *
439 * listSize
440 * Size of the hMonitorList and monitorRectList arguments. If this is zero
441 * hMonitorList and monitorRectList are ignored.
442 *
443 * Returns
444 * The number of monitors which intersect the specified region or -1 on failure.
445 */
446 INT
447 APIENTRY
448 NtUserEnumDisplayMonitors(
449 OPTIONAL IN HDC hDC,
450 OPTIONAL IN LPCRECTL pRect,
451 OPTIONAL OUT HMONITOR *hMonitorList,
452 OPTIONAL OUT PRECTL monitorRectList,
453 OPTIONAL IN DWORD listSize)
454 {
455 INT numMonitors, i;
456 HMONITOR *safeHMonitorList = NULL;
457 PRECTL safeRectList = NULL;
458 RECTL rect, *myRect;
459 RECTL dcRect;
460 NTSTATUS status;
461
462 /* get rect */
463 if (pRect != NULL)
464 {
465 status = MmCopyFromCaller(&rect, pRect, sizeof (RECT));
466 if (!NT_SUCCESS(status))
467 {
468 DPRINT("MmCopyFromCaller() failed!\n");
469 SetLastNtError(status);
470 return -1;
471 }
472 }
473
474 if (hDC != NULL)
475 {
476 PDC dc;
477 INT regionType;
478
479 /* get visible region bounding rect */
480 dc = DC_LockDc(hDC);
481 if (dc == NULL)
482 {
483 DPRINT("DC_LockDc() failed!\n");
484 /* FIXME: setlasterror? */
485 return -1;
486 }
487 regionType = REGION_GetRgnBox(dc->prgnVis, &dcRect);
488 DC_UnlockDc(dc);
489
490 if (regionType == 0)
491 {
492 DPRINT("NtGdiGetRgnBox() failed!\n");
493 return -1;
494 }
495 if (regionType == NULLREGION)
496 return 0;
497 if (regionType == COMPLEXREGION)
498 {
499 /* TODO: warning */
500 }
501
502 /* if hDC and pRect are given the area of interest is pRect with
503 coordinate origin at the DC position */
504 if (pRect != NULL)
505 {
506 rect.left += dcRect.left;
507 rect.right += dcRect.left;
508 rect.top += dcRect.top;
509 rect.bottom += dcRect.top;
510 }
511 /* if hDC is given and pRect is not the area of interest is the
512 bounding rect of hDC */
513 else
514 {
515 rect = dcRect;
516 }
517 }
518
519 if (hDC == NULL && pRect == NULL)
520 myRect = NULL;
521 else
522 myRect = &rect;
523
524 /* find intersecting monitors */
525 numMonitors = IntGetMonitorsFromRect(myRect, NULL, NULL, 0, 0);
526 if (numMonitors == 0 || listSize == 0 ||
527 (hMonitorList == NULL && monitorRectList == NULL))
528 {
529 DPRINT("numMonitors = %d\n", numMonitors);
530 return numMonitors;
531 }
532
533 if (hMonitorList != NULL && listSize != 0)
534 {
535 safeHMonitorList = ExAllocatePoolWithTag(PagedPool, sizeof (HMONITOR) * listSize, USERTAG_MONITORRECTS);
536 if (safeHMonitorList == NULL)
537 {
538 /* FIXME: SetLastWin32Error? */
539 return -1;
540 }
541 }
542 if (monitorRectList != NULL && listSize != 0)
543 {
544 safeRectList = ExAllocatePoolWithTag(PagedPool, sizeof (RECT) * listSize, USERTAG_MONITORRECTS);
545 if (safeRectList == NULL)
546 {
547 ExFreePoolWithTag(safeHMonitorList, USERTAG_MONITORRECTS);
548 /* FIXME: SetLastWin32Error? */
549 return -1;
550 }
551 }
552
553 /* get intersecting monitors */
554 numMonitors = IntGetMonitorsFromRect(myRect, safeHMonitorList, safeRectList,
555 listSize, 0 );
556
557 if (hDC != NULL && pRect != NULL && safeRectList != NULL)
558 for (i = 0; i < numMonitors; i++)
559 {
560 safeRectList[i].left -= dcRect.left;
561 safeRectList[i].right -= dcRect.left;
562 safeRectList[i].top -= dcRect.top;
563 safeRectList[i].bottom -= dcRect.top;
564 }
565
566 /* output result */
567 if (hMonitorList != NULL && listSize != 0)
568 {
569 status = MmCopyToCaller(hMonitorList, safeHMonitorList, sizeof (HMONITOR) * listSize);
570 ExFreePool(safeHMonitorList);
571 if (!NT_SUCCESS(status))
572 {
573 ExFreePoolWithTag(safeRectList, USERTAG_MONITORRECTS);
574 SetLastNtError(status);
575 return -1;
576 }
577 }
578 if (monitorRectList != NULL && listSize != 0)
579 {
580 status = MmCopyToCaller(monitorRectList, safeRectList, sizeof (RECT) * listSize);
581 ExFreePoolWithTag(safeRectList, USERTAG_MONITORRECTS);
582 if (!NT_SUCCESS(status))
583 {
584 SetLastNtError(status);
585 return -1;
586 }
587 }
588
589 return numMonitors;
590 }
591
592 /* NtUserGetMonitorInfo
593 *
594 * Retrieves information about a given monitor
595 *
596 * Arguments
597 *
598 * hMonitor
599 * Handle to a monitor for which to get information
600 *
601 * pMonitorInfo
602 * Pointer to a MONITORINFO struct which is filled with the information.
603 * The cbSize member must be set to sizeof(MONITORINFO) or
604 * sizeof(MONITORINFOEX). Even if set to sizeof(MONITORINFOEX) only parts
605 * from MONITORINFO will be filled.
606 *
607 * pDevice
608 * Pointer to a UNICODE_STRING which will recieve the device's name. The
609 * length should be CCHDEVICENAME
610 * Can be NULL
611 *
612 * Return value
613 * TRUE on success; FALSE on failure (calls SetLastNtError())
614 *
615 */
616 BOOL
617 APIENTRY
618 NtUserGetMonitorInfo(
619 IN HMONITOR hMonitor,
620 OUT LPMONITORINFO pMonitorInfo)
621 {
622 PMONITOR Monitor;
623 MONITORINFOEXW MonitorInfo;
624 NTSTATUS Status;
625 DECLARE_RETURN(BOOL);
626
627 DPRINT("Enter NtUserGetMonitorInfo\n");
628 UserEnterShared();
629
630 /* get monitor object */
631 if (!(Monitor = UserGetMonitorObject(hMonitor)))
632 {
633 DPRINT("Couldnt find monitor 0x%lx\n", hMonitor);
634 RETURN(FALSE);
635 }
636
637 if(pMonitorInfo == NULL)
638 {
639 SetLastNtError(STATUS_INVALID_PARAMETER);
640 RETURN(FALSE);
641 }
642
643 /* get size of pMonitorInfo */
644 Status = MmCopyFromCaller(&MonitorInfo.cbSize, &pMonitorInfo->cbSize, sizeof (MonitorInfo.cbSize));
645 if (!NT_SUCCESS(Status))
646 {
647 SetLastNtError(Status);
648 RETURN(FALSE);
649 }
650 if ((MonitorInfo.cbSize != sizeof (MONITORINFO)) &&
651 (MonitorInfo.cbSize != sizeof (MONITORINFOEXW)))
652 {
653 SetLastNtError(STATUS_INVALID_PARAMETER);
654 RETURN(FALSE);
655 }
656
657 /* fill monitor info */
658 MonitorInfo.rcMonitor = Monitor->rcMonitor;
659 MonitorInfo.rcWork = Monitor->rcWork;
660 MonitorInfo.dwFlags = 0;
661
662 if (Monitor->IsPrimary)
663 MonitorInfo.dwFlags |= MONITORINFOF_PRIMARY;
664
665 /* fill device name */
666 if (MonitorInfo.cbSize == sizeof (MONITORINFOEXW))
667 {
668 WCHAR nul = L'\0';
669 INT len = Monitor->DeviceName.Length;
670 if (len >= CCHDEVICENAME * sizeof (WCHAR))
671 len = (CCHDEVICENAME - 1) * sizeof (WCHAR);
672
673 memcpy(MonitorInfo.szDevice, Monitor->DeviceName.Buffer, len);
674 memcpy(MonitorInfo.szDevice + (len / sizeof (WCHAR)), &nul, sizeof (WCHAR));
675 }
676
677 /* output data */
678 Status = MmCopyToCaller(pMonitorInfo, &MonitorInfo, MonitorInfo.cbSize);
679 if (!NT_SUCCESS(Status))
680 {
681 DPRINT("GetMonitorInfo: MmCopyToCaller failed\n");
682 SetLastNtError(Status);
683 RETURN(FALSE);
684 }
685
686 DPRINT("GetMonitorInfo: success\n");
687
688 RETURN(TRUE);
689
690 CLEANUP:
691 DPRINT("Leave NtUserGetMonitorInfo, ret=%i\n",_ret_);
692 UserLeave();
693 END_CLEANUP;
694 }
695
696 /* NtUserMonitorFromPoint
697 *
698 * Returns a handle to the monitor containing the given point.
699 *
700 * Arguments
701 *
702 * point
703 * Point for which to find monitor
704 *
705 * dwFlags
706 * Specifies the behaviour if the point isn't on any of the monitors.
707 *
708 * Return value
709 * If the point is found a handle to the monitor is returned; if not the
710 * return value depends on dwFlags
711 */
712 HMONITOR
713 APIENTRY
714 NtUserMonitorFromPoint(
715 IN POINT point,
716 IN DWORD dwFlags)
717 {
718 INT NumMonitors;
719 RECTL InRect;
720 HMONITOR hMonitor = NULL;
721
722 /* fill inRect */
723 InRect.left = InRect.right = point.x;
724 InRect.top = InRect.bottom = point.y;
725
726 /* find intersecting monitor */
727 NumMonitors = IntGetMonitorsFromRect(&InRect, &hMonitor, NULL, 1, 0);
728 if (NumMonitors < 0)
729 {
730 return (HMONITOR)NULL;
731 }
732
733 if (hMonitor == NULL)
734 {
735 if (dwFlags == MONITOR_DEFAULTTOPRIMARY)
736 {
737 PMONITOR MonitorObj = IntGetPrimaryMonitor();
738 if (MonitorObj)
739 hMonitor = UserHMGetHandle(MonitorObj);
740 }
741 else if (dwFlags == MONITOR_DEFAULTTONEAREST)
742 {
743 NumMonitors = IntGetMonitorsFromRect(&InRect, &hMonitor, NULL,
744 1, MONITOR_DEFAULTTONEAREST);
745 /*ASSERT( (numMonitors > 0) && (hMonitor != NULL) );*/
746 }
747 /* else flag is DEFAULTTONULL */
748 }
749
750 return hMonitor;
751 }
752
753 /* NtUserMonitorFromRect
754 *
755 * Returns a handle to the monitor having the largest intersection with a
756 * given rectangle
757 *
758 * Arguments
759 *
760 * pRect
761 * Pointer to a RECT for which to find monitor
762 *
763 * dwFlags
764 * Specifies the behaviour if no monitor intersects the given rect
765 *
766 * Return value
767 * If a monitor intersects the rect a handle to it is returned; if not the
768 * return value depends on dwFlags
769 */
770 HMONITOR
771 APIENTRY
772 NtUserMonitorFromRect(
773 IN LPCRECTL pRect,
774 IN DWORD dwFlags)
775 {
776 INT numMonitors, iLargestArea = -1, i;
777 PRECTL rectList;
778 HMONITOR *hMonitorList;
779 HMONITOR hMonitor = NULL;
780 RECTL rect;
781 NTSTATUS status;
782
783 /* get rect */
784 status = MmCopyFromCaller(&rect, pRect, sizeof (RECT));
785 if (!NT_SUCCESS(status))
786 {
787 SetLastNtError(status);
788 return (HMONITOR)NULL;
789 }
790
791 /* find intersecting monitors */
792 numMonitors = IntGetMonitorsFromRect(&rect, NULL, NULL, 0, 0);
793 if (numMonitors < 0)
794 {
795 return (HMONITOR)NULL;
796 }
797
798 if (numMonitors == 0)
799 {
800 if (dwFlags == MONITOR_DEFAULTTOPRIMARY)
801 {
802 PMONITOR monitorObj = IntGetPrimaryMonitor();
803 if (monitorObj)
804 return UserHMGetHandle(monitorObj);
805 }
806 else if (dwFlags == MONITOR_DEFAULTTONEAREST)
807 {
808 numMonitors = IntGetMonitorsFromRect(&rect, &hMonitor, NULL,
809 1, MONITOR_DEFAULTTONEAREST);
810 if (numMonitors <= 0)
811 {
812 /* error? */
813 return (HMONITOR)NULL;
814 }
815
816 if (numMonitors > 0)
817 return hMonitor;
818 }
819 /* else flag is DEFAULTTONULL */
820 return (HMONITOR)NULL;
821 }
822
823 hMonitorList = ExAllocatePoolWithTag(PagedPool, sizeof (HMONITOR) * numMonitors, USERTAG_MONITORRECTS);
824 if (hMonitorList == NULL)
825 {
826 /* FIXME: SetLastWin32Error? */
827 return (HMONITOR)NULL;
828 }
829 rectList = ExAllocatePoolWithTag(PagedPool, sizeof (RECT) * numMonitors, USERTAG_MONITORRECTS);
830 if (rectList == NULL)
831 {
832 ExFreePoolWithTag(hMonitorList, USERTAG_MONITORRECTS);
833 /* FIXME: SetLastWin32Error? */
834 return (HMONITOR)NULL;
835 }
836
837 /* get intersecting monitors */
838 numMonitors = IntGetMonitorsFromRect(&rect, hMonitorList, rectList,
839 numMonitors, 0);
840 if (numMonitors <= 0)
841 {
842 ExFreePoolWithTag(hMonitorList, USERTAG_MONITORRECTS);
843 ExFreePoolWithTag(rectList, USERTAG_MONITORRECTS);
844 return (HMONITOR)NULL;
845 }
846
847 /* find largest intersection */
848 for (i = 0; i < numMonitors; i++)
849 {
850 INT area = (rectList[i].right - rectList[i].left) *
851 (rectList[i].bottom - rectList[i].top);
852 if (area > iLargestArea)
853 {
854 hMonitor = hMonitorList[i];
855 }
856 }
857
858 ExFreePoolWithTag(hMonitorList, USERTAG_MONITORRECTS);
859 ExFreePoolWithTag(rectList, USERTAG_MONITORRECTS);
860
861 return hMonitor;
862 }
863
864
865 HMONITOR
866 APIENTRY
867 NtUserMonitorFromWindow(
868 IN HWND hWnd,
869 IN DWORD dwFlags)
870 {
871 PWND Window;
872 HMONITOR hMonitor = NULL;
873 RECTL Rect;
874 DECLARE_RETURN(HMONITOR);
875
876 DPRINT("Enter NtUserMonitorFromWindow\n");
877 UserEnterShared();
878
879 if (!(Window = UserGetWindowObject(hWnd)))
880 {
881 if (dwFlags == MONITOR_DEFAULTTONULL)
882 {
883 RETURN(hMonitor);
884 }
885 IntGetMonitorsFromRect(NULL, &hMonitor, NULL, 1, dwFlags);
886 RETURN(hMonitor);
887 }
888
889 Rect.left = Rect.right = Window->rcWindow.left;
890 Rect.top = Rect.bottom = Window->rcWindow.bottom;
891
892 IntGetMonitorsFromRect(&Rect, &hMonitor, NULL, 1, dwFlags);
893
894 RETURN(hMonitor);
895
896 CLEANUP:
897 DPRINT("Leave NtUserMonitorFromWindow, ret=%i\n",_ret_);
898 UserLeave();
899 END_CLEANUP;
900 }