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