2f587bfd49268de6a1eb62c4529837b78047dba1
[reactos.git] / reactos / 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 INT regionType;
496
497 /* get visible region bounding rect */
498 dc = DC_LockDc(hDC);
499 if (dc == NULL)
500 {
501 DPRINT("DC_LockDc() failed!\n");
502 /* FIXME: setlasterror? */
503 return -1;
504 }
505 regionType = REGION_GetRgnBox(dc->prgnVis, &dcRect);
506 DC_UnlockDc(dc);
507
508 if (regionType == 0)
509 {
510 DPRINT("NtGdiGetRgnBox() failed!\n");
511 return -1;
512 }
513 if (regionType == NULLREGION)
514 return 0;
515 if (regionType == COMPLEXREGION)
516 { /* TODO: warning */
517 }
518
519 /* if hDC and pRect are given the area of interest is pRect with
520 coordinate origin at the DC position */
521 if (pRect != NULL)
522 {
523 rect.left += dcRect.left;
524 rect.right += dcRect.left;
525 rect.top += dcRect.top;
526 rect.bottom += dcRect.top;
527 }
528 /* if hDC is given and pRect is not the area of interest is the
529 bounding rect of hDC */
530 else
531 {
532 rect = dcRect;
533 }
534 }
535
536 if (hDC == NULL && pRect == NULL)
537 myRect = NULL;
538 else
539 myRect = &rect;
540
541 /* find intersecting monitors */
542 numMonitors = IntGetMonitorsFromRect(myRect, NULL, NULL, 0, 0);
543 if (numMonitors == 0 || listSize == 0 ||
544 (hMonitorList == NULL && monitorRectList == NULL))
545 {
546 DPRINT("numMonitors = %d\n", numMonitors);
547 return numMonitors;
548 }
549
550 if (hMonitorList != NULL && listSize != 0)
551 {
552 safeHMonitorList = ExAllocatePoolWithTag(PagedPool, sizeof (HMONITOR) * listSize, USERTAG_MONITORRECTS);
553 if (safeHMonitorList == NULL)
554 {
555 /* FIXME: SetLastWin32Error? */
556 return -1;
557 }
558 }
559 if (monitorRectList != NULL && listSize != 0)
560 {
561 safeRectList = ExAllocatePoolWithTag(PagedPool, sizeof (RECT) * listSize, USERTAG_MONITORRECTS);
562 if (safeRectList == NULL)
563 {
564 ExFreePoolWithTag(safeHMonitorList, USERTAG_MONITORRECTS);
565 /* FIXME: SetLastWin32Error? */
566 return -1;
567 }
568 }
569
570 /* get intersecting monitors */
571 numMonitors = IntGetMonitorsFromRect(myRect, safeHMonitorList, safeRectList,
572 listSize, 0 );
573
574 if (hDC != NULL && pRect != NULL && safeRectList != NULL)
575 for (i = 0; i < numMonitors; i++)
576 {
577 safeRectList[i].left -= dcRect.left;
578 safeRectList[i].right -= dcRect.left;
579 safeRectList[i].top -= dcRect.top;
580 safeRectList[i].bottom -= dcRect.top;
581 }
582
583 /* output result */
584 if (hMonitorList != NULL && listSize != 0)
585 {
586 status = MmCopyToCaller(hMonitorList, safeHMonitorList, sizeof (HMONITOR) * listSize);
587 ExFreePool(safeHMonitorList);
588 if (!NT_SUCCESS(status))
589 {
590 ExFreePoolWithTag(safeRectList, USERTAG_MONITORRECTS);
591 SetLastNtError(status);
592 return -1;
593 }
594 }
595 if (monitorRectList != NULL && listSize != 0)
596 {
597 status = MmCopyToCaller(monitorRectList, safeRectList, sizeof (RECT) * listSize);
598 ExFreePoolWithTag(safeRectList, USERTAG_MONITORRECTS);
599 if (!NT_SUCCESS(status))
600 {
601 SetLastNtError(status);
602 return -1;
603 }
604 }
605
606 return numMonitors;
607 }
608
609 /* NtUserGetMonitorInfo
610 *
611 * Retrieves information about a given monitor
612 *
613 * Arguments
614 *
615 * hMonitor
616 * Handle to a monitor for which to get information
617 *
618 * pMonitorInfo
619 * Pointer to a MONITORINFO struct which is filled with the information.
620 * The cbSize member must be set to sizeof(MONITORINFO) or
621 * sizeof(MONITORINFOEX). Even if set to sizeof(MONITORINFOEX) only parts
622 * from MONITORINFO will be filled.
623 *
624 * pDevice
625 * Pointer to a UNICODE_STRING which will recieve the device's name. The
626 * length should be CCHDEVICENAME
627 * Can be NULL
628 *
629 * Return value
630 * TRUE on success; FALSE on failure (calls SetLastNtError())
631 *
632 */
633 BOOL
634 APIENTRY
635 NtUserGetMonitorInfo(
636 IN HMONITOR hMonitor,
637 OUT LPMONITORINFO pMonitorInfo)
638 {
639 PMONITOR Monitor;
640 MONITORINFOEXW MonitorInfo;
641 NTSTATUS Status;
642 DECLARE_RETURN(BOOL);
643
644 DPRINT("Enter NtUserGetMonitorInfo\n");
645 UserEnterShared();
646
647 /* get monitor object */
648 if (!(Monitor = UserGetMonitorObject(hMonitor)))
649 {
650 DPRINT("Couldnt find monitor 0x%lx\n", hMonitor);
651 RETURN(FALSE);
652 }
653
654 if(pMonitorInfo == NULL)
655 {
656 SetLastNtError(STATUS_INVALID_PARAMETER);
657 RETURN(FALSE);
658 }
659
660 /* get size of pMonitorInfo */
661 Status = MmCopyFromCaller(&MonitorInfo.cbSize, &pMonitorInfo->cbSize, sizeof (MonitorInfo.cbSize));
662 if (!NT_SUCCESS(Status))
663 {
664 SetLastNtError(Status);
665 RETURN(FALSE);
666 }
667 if ((MonitorInfo.cbSize != sizeof (MONITORINFO)) &&
668 (MonitorInfo.cbSize != sizeof (MONITORINFOEXW)))
669 {
670 SetLastNtError(STATUS_INVALID_PARAMETER);
671 RETURN(FALSE);
672 }
673
674 /* fill monitor info */
675 MonitorInfo.rcMonitor = Monitor->rcMonitor;
676 MonitorInfo.rcWork = Monitor->rcWork;
677 MonitorInfo.dwFlags = 0;
678
679 if (Monitor->IsPrimary)
680 MonitorInfo.dwFlags |= MONITORINFOF_PRIMARY;
681
682 /* fill device name */
683 if (MonitorInfo.cbSize == sizeof (MONITORINFOEXW))
684 {
685 WCHAR nul = L'\0';
686 INT len = Monitor->DeviceName.Length;
687 if (len >= CCHDEVICENAME * sizeof (WCHAR))
688 len = (CCHDEVICENAME - 1) * sizeof (WCHAR);
689
690 memcpy(MonitorInfo.szDevice, Monitor->DeviceName.Buffer, len);
691 memcpy(MonitorInfo.szDevice + (len / sizeof (WCHAR)), &nul, sizeof (WCHAR));
692 }
693
694 /* output data */
695 Status = MmCopyToCaller(pMonitorInfo, &MonitorInfo, MonitorInfo.cbSize);
696 if (!NT_SUCCESS(Status))
697 {
698 DPRINT("GetMonitorInfo: MmCopyToCaller failed\n");
699 SetLastNtError(Status);
700 RETURN(FALSE);
701 }
702
703 DPRINT("GetMonitorInfo: success\n");
704
705 RETURN(TRUE);
706
707 CLEANUP:
708 DPRINT("Leave NtUserGetMonitorInfo, ret=%i\n",_ret_);
709 UserLeave();
710 END_CLEANUP;
711 }
712
713 /* NtUserMonitorFromPoint
714 *
715 * Returns a handle to the monitor containing the given point.
716 *
717 * Arguments
718 *
719 * point
720 * Point for which to find monitor
721 *
722 * dwFlags
723 * Specifies the behaviour if the point isn't on any of the monitors.
724 *
725 * Return value
726 * If the point is found a handle to the monitor is returned; if not the
727 * return value depends on dwFlags
728 */
729 HMONITOR
730 APIENTRY
731 NtUserMonitorFromPoint(
732 IN POINT point,
733 IN DWORD dwFlags)
734 {
735 INT NumMonitors;
736 RECTL InRect;
737 HMONITOR hMonitor = NULL;
738
739 /* fill inRect */
740 InRect.left = InRect.right = point.x;
741 InRect.top = InRect.bottom = point.y;
742
743 /* find intersecting monitor */
744 NumMonitors = IntGetMonitorsFromRect(&InRect, &hMonitor, NULL, 1, 0);
745 if (NumMonitors < 0)
746 {
747 return (HMONITOR)NULL;
748 }
749
750 if (hMonitor == NULL)
751 {
752 if (dwFlags == MONITOR_DEFAULTTOPRIMARY)
753 {
754 PMONITOR MonitorObj = IntGetPrimaryMonitor();
755 if (MonitorObj)
756 hMonitor = UserHMGetHandle(MonitorObj);
757 }
758 else if (dwFlags == MONITOR_DEFAULTTONEAREST)
759 {
760 NumMonitors = IntGetMonitorsFromRect(&InRect, &hMonitor, NULL,
761 1, MONITOR_DEFAULTTONEAREST);
762 /*ASSERT( (numMonitors > 0) && (hMonitor != NULL) );*/
763 }
764 /* else flag is DEFAULTTONULL */
765 }
766
767 return hMonitor;
768 }
769
770 /* NtUserMonitorFromRect
771 *
772 * Returns a handle to the monitor having the largest intersection with a
773 * given rectangle
774 *
775 * Arguments
776 *
777 * pRect
778 * Pointer to a RECT for which to find monitor
779 *
780 * dwFlags
781 * Specifies the behaviour if no monitor intersects the given rect
782 *
783 * Return value
784 * If a monitor intersects the rect a handle to it is returned; if not the
785 * return value depends on dwFlags
786 */
787 HMONITOR
788 APIENTRY
789 NtUserMonitorFromRect(
790 IN LPCRECTL pRect,
791 IN DWORD dwFlags)
792 {
793 INT numMonitors, iLargestArea = -1, i;
794 PRECTL rectList;
795 HMONITOR *hMonitorList;
796 HMONITOR hMonitor = NULL;
797 RECTL rect;
798 NTSTATUS status;
799
800 /* get rect */
801 status = MmCopyFromCaller(&rect, pRect, sizeof (RECT));
802 if (!NT_SUCCESS(status))
803 {
804 SetLastNtError(status);
805 return (HMONITOR)NULL;
806 }
807
808 /* find intersecting monitors */
809 numMonitors = IntGetMonitorsFromRect(&rect, NULL, NULL, 0, 0);
810 if (numMonitors < 0)
811 {
812 return (HMONITOR)NULL;
813 }
814
815 if (numMonitors == 0)
816 {
817 if (dwFlags == MONITOR_DEFAULTTOPRIMARY)
818 {
819 PMONITOR monitorObj = IntGetPrimaryMonitor();
820 if (monitorObj)
821 return UserHMGetHandle(monitorObj);
822 }
823 else if (dwFlags == MONITOR_DEFAULTTONEAREST)
824 {
825 numMonitors = IntGetMonitorsFromRect(&rect, &hMonitor, NULL,
826 1, MONITOR_DEFAULTTONEAREST);
827 if (numMonitors <= 0)
828 {
829 /* error? */
830 return (HMONITOR)NULL;
831 }
832
833 if (numMonitors > 0)
834 return hMonitor;
835 }
836 /* else flag is DEFAULTTONULL */
837 return (HMONITOR)NULL;
838 }
839
840 hMonitorList = ExAllocatePoolWithTag(PagedPool, sizeof (HMONITOR) * numMonitors, USERTAG_MONITORRECTS);
841 if (hMonitorList == NULL)
842 {
843 /* FIXME: SetLastWin32Error? */
844 return (HMONITOR)NULL;
845 }
846 rectList = ExAllocatePoolWithTag(PagedPool, sizeof (RECT) * numMonitors, USERTAG_MONITORRECTS);
847 if (rectList == NULL)
848 {
849 ExFreePoolWithTag(hMonitorList, USERTAG_MONITORRECTS);
850 /* FIXME: SetLastWin32Error? */
851 return (HMONITOR)NULL;
852 }
853
854 /* get intersecting monitors */
855 numMonitors = IntGetMonitorsFromRect(&rect, hMonitorList, rectList,
856 numMonitors, 0);
857 if (numMonitors <= 0)
858 {
859 ExFreePoolWithTag(hMonitorList, USERTAG_MONITORRECTS);
860 ExFreePoolWithTag(rectList, USERTAG_MONITORRECTS);
861 return (HMONITOR)NULL;
862 }
863
864 /* find largest intersection */
865 for (i = 0; i < numMonitors; i++)
866 {
867 INT area = (rectList[i].right - rectList[i].left) *
868 (rectList[i].bottom - rectList[i].top);
869 if (area > iLargestArea)
870 {
871 hMonitor = hMonitorList[i];
872 }
873 }
874
875 ExFreePoolWithTag(hMonitorList, USERTAG_MONITORRECTS);
876 ExFreePoolWithTag(rectList, USERTAG_MONITORRECTS);
877
878 return hMonitor;
879 }
880
881
882 HMONITOR
883 APIENTRY
884 NtUserMonitorFromWindow(
885 IN HWND hWnd,
886 IN DWORD dwFlags)
887 {
888 PWND Window;
889 HMONITOR hMonitor = NULL;
890 RECTL Rect;
891 DECLARE_RETURN(HMONITOR);
892
893 DPRINT("Enter NtUserMonitorFromWindow\n");
894 UserEnterShared();
895
896 if (!(Window = UserGetWindowObject(hWnd)))
897 {
898 if (dwFlags == MONITOR_DEFAULTTONULL)
899 {
900 RETURN(hMonitor);
901 }
902 IntGetMonitorsFromRect(NULL, &hMonitor, NULL, 1, dwFlags);
903 RETURN(hMonitor);
904 }
905
906 Rect.left = Rect.right = Window->rcWindow.left;
907 Rect.top = Rect.bottom = Window->rcWindow.bottom;
908
909 IntGetMonitorsFromRect(&Rect, &hMonitor, NULL, 1, dwFlags);
910
911 RETURN(hMonitor);
912
913 CLEANUP:
914 DPRINT("Leave NtUserMonitorFromWindow, ret=%i\n",_ret_);
915 UserLeave();
916 END_CLEANUP;
917 }