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