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