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