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