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