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