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