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