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