Merge from amd64 branch:
[reactos.git] / reactos / subsystems / win32 / win32k / ntuser / monitor.c
1 /*
2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * COPYRIGHT: See COPYING in the top level directory
20 * PROJECT: ReactOS kernel
21 * PURPOSE: Monitor support
22 * FILE: subsys/win32k/ntuser/monitor.c
23 * PROGRAMER: Anich Gregor (blight@blight.eu.org)
24 * REVISION HISTORY:
25 * 26-02-2004 Created
26 */
27
28 /* INCLUDES ******************************************************************/
29
30 #include <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 = UserCreateObject(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 UserDereferenceObject(pMonitor);
120 }
121
122
123 PMONITOR_OBJECT FASTCALL
124 UserGetMonitorObject(IN HMONITOR hMonitor)
125 {
126 PMONITOR_OBJECT Monitor;
127
128 if (!hMonitor)
129 {
130 SetLastWin32Error(ERROR_INVALID_MONITOR_HANDLE);
131 return NULL;
132 }
133
134
135 Monitor = (PMONITOR_OBJECT)UserGetObject(gHandleTable, hMonitor, otMonitor);
136 if (!Monitor)
137 {
138 SetLastWin32Error(ERROR_INVALID_MONITOR_HANDLE);
139 return NULL;
140 }
141
142 ASSERT(USER_BODY_TO_HEADER(Monitor)->RefCount >= 0);
143
144 return Monitor;
145 }
146
147
148 /* IntAttachMonitor
149 *
150 * Creates a new MONITOR_OBJECT and appends it to the list of monitors.
151 *
152 * Arguments
153 *
154 * pGdiDevice Pointer to the PDEVOBJ onto which the monitor was attached
155 * DisplayNumber Display Number (starting with 0)
156 *
157 * Return value
158 * Returns a NTSTATUS
159 */
160 NTSTATUS
161 IntAttachMonitor(IN PDEVOBJ *pGdiDevice,
162 IN ULONG DisplayNumber)
163 {
164 PMONITOR_OBJECT Monitor;
165 WCHAR Buffer[CCHDEVICENAME];
166
167 DPRINT("Attaching monitor...\n");
168
169 /* create new monitor object */
170 Monitor = IntCreateMonitorObject();
171 if (Monitor == NULL)
172 {
173 DPRINT("Couldnt create monitor object\n");
174 return STATUS_INSUFFICIENT_RESOURCES;
175 }
176
177 _snwprintf(Buffer, CCHDEVICENAME, L"\\\\.\\DISPLAY%d", DisplayNumber + 1);
178 if (!RtlCreateUnicodeString(&Monitor->DeviceName, Buffer))
179 {
180 DPRINT("Couldn't duplicate monitor name!\n");
181 UserDereferenceObject(Monitor);
182 UserDeleteObject(Monitor->Handle, otMonitor);
183 return STATUS_INSUFFICIENT_RESOURCES;
184 }
185
186 Monitor->GdiDevice = pGdiDevice;
187 if (gMonitorList == NULL)
188 {
189 DPRINT("Primary monitor is beeing attached\n");
190 Monitor->IsPrimary = TRUE;
191 gMonitorList = Monitor;
192 }
193 else
194 {
195 PMONITOR_OBJECT p;
196 DPRINT("Additional monitor is beeing attached\n");
197 for (p = gMonitorList; p->Next != NULL; p = p->Next)
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 PDEVOBJ from which the monitor was detached
214 *
215 * Return value
216 * Returns a NTSTATUS
217 */
218 NTSTATUS
219 IntDetachMonitor(IN PDEVOBJ *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 LPCRECTL pRect,
319 OPTIONAL OUT HMONITOR *hMonitorList,
320 OPTIONAL OUT PRECTL monitorRectList,
321 OPTIONAL IN DWORD listSize,
322 OPTIONAL IN DWORD flags)
323 {
324 PMONITOR_OBJECT Monitor, NearestMonitor = NULL, PrimaryMonitor = 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 RECTL 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 (flags == MONITOR_DEFAULTTOPRIMARY && Monitor->IsPrimary)
344 {
345 PrimaryMonitor = Monitor;
346 }
347
348 if (pRect != NULL)
349 {
350 BOOL intersects = TRUE;
351
352 /* check if the rect intersects the monitor */
353 if ((pRect->right < MonitorRect.left) || (pRect->left > MonitorRect.right) ||
354 (pRect->bottom < MonitorRect.top) || (pRect->top > MonitorRect.bottom))
355 {
356 intersects = FALSE;
357 }
358
359 if (flags == MONITOR_DEFAULTTONEAREST && !intersects)
360 {
361 INT distanceX, distanceY;
362
363 distanceX = MIN(ABS(MonitorRect.left - pRect->right),
364 ABS(pRect->left - MonitorRect.right));
365 distanceY = MIN(ABS(MonitorRect.top - pRect->bottom),
366 ABS(pRect->top - MonitorRect.bottom));
367
368 if (((distanceX < iNearestDistanceX) && (distanceY <= iNearestDistanceY)) ||
369 ((distanceX <= iNearestDistanceX) && (distanceY < iNearestDistanceY)))
370 {
371 iNearestDistanceX = distanceX;
372 iNearestDistanceY = distanceY;
373 NearestMonitor = Monitor;
374 }
375 }
376
377 if (!intersects)
378 continue;
379
380 /* calculate intersection */
381 IntersectionRect.left = MAX(MonitorRect.left, pRect->left);
382 IntersectionRect.top = MAX(MonitorRect.top, pRect->top);
383 IntersectionRect.right = MIN(MonitorRect.right, pRect->right);
384 IntersectionRect.bottom = MIN(MonitorRect.bottom, pRect->bottom);
385 }
386 else
387 {
388 IntersectionRect = MonitorRect;
389 }
390
391 if (iCount < listSize)
392 {
393 if (hMonitorList != NULL)
394 hMonitorList[iCount] = Monitor->Handle;
395 if (monitorRectList != NULL)
396 monitorRectList[iCount] = IntersectionRect;
397 }
398 iCount++;
399 }
400
401 if (iCount == 0 && flags == MONITOR_DEFAULTTONEAREST)
402 {
403 if (iCount < listSize)
404 {
405 if (hMonitorList != NULL)
406 hMonitorList[iCount] = NearestMonitor->Handle;
407 }
408 iCount++;
409 }
410 else if (iCount == 0 && flags == MONITOR_DEFAULTTOPRIMARY)
411 {
412 if (iCount < listSize)
413 {
414 if (hMonitorList != NULL)
415 hMonitorList[iCount] = PrimaryMonitor->Handle;
416 }
417 iCount++;
418 }
419 return iCount;
420 }
421
422 /* PUBLIC FUNCTIONS ***********************************************************/
423
424 /* NtUserEnumDisplayMonitors
425 *
426 * Enumerates display monitors which intersect the given HDC/cliprect
427 *
428 * Arguments
429 *
430 * hDC
431 * Handle to a DC for which to enum intersecting monitors. If this is NULL
432 * it returns all monitors which are part of the current virtual screen.
433 *
434 * pRect
435 * Clipping rectangle with coordinate system origin at the DCs origin if the
436 * given HDC is not NULL or in virtual screen coordinated if it is NULL.
437 * Can be NULL
438 *
439 * hMonitorList
440 * Pointer to an array of HMONITOR which is filled with monitor handles.
441 * Can be NULL
442 *
443 * monitorRectList
444 * Pointer to an array of RECT which is filled with intersection rectangles.
445 * Can be NULL
446 *
447 * listSize
448 * Size of the hMonitorList and monitorRectList arguments. If this is zero
449 * hMonitorList and monitorRectList are ignored.
450 *
451 * Returns
452 * The number of monitors which intersect the specified region or -1 on failure.
453 */
454 INT
455 APIENTRY
456 NtUserEnumDisplayMonitors(
457 OPTIONAL IN HDC hDC,
458 OPTIONAL IN LPCRECTL pRect,
459 OPTIONAL OUT HMONITOR *hMonitorList,
460 OPTIONAL OUT PRECTL monitorRectList,
461 OPTIONAL IN DWORD listSize)
462 {
463 INT numMonitors, i;
464 HMONITOR *safeHMonitorList = NULL;
465 PRECTL safeRectList = NULL;
466 RECTL rect, *myRect;
467 RECTL dcRect;
468 NTSTATUS status;
469
470 /* get rect */
471 if (pRect != NULL)
472 {
473 status = MmCopyFromCaller(&rect, pRect, sizeof (RECT));
474 if (!NT_SUCCESS(status))
475 {
476 DPRINT("MmCopyFromCaller() failed!\n");
477 SetLastNtError(status);
478 return -1;
479 }
480 }
481
482 if (hDC != NULL)
483 {
484 PDC dc;
485 HRGN dcVisRgn;
486 INT regionType;
487
488 /* get visible region bounding rect */
489 dc = DC_LockDc(hDC);
490 if (dc == NULL)
491 {
492 DPRINT("DC_LockDc() failed!\n");
493 /* FIXME: setlasterror? */
494 return -1;
495 }
496 dcVisRgn = dc->rosdc.hVisRgn;
497 DC_UnlockDc(dc);
498
499 regionType = NtGdiGetRgnBox(dcVisRgn, &dcRect);
500 if (regionType == 0)
501 {
502 DPRINT("NtGdiGetRgnBox() failed!\n");
503 return -1;
504 }
505 if (regionType == NULLREGION)
506 return 0;
507 if (regionType == COMPLEXREGION)
508 { /* TODO: warning */
509 }
510
511 /* if hDC and pRect are given the area of interest is pRect with
512 coordinate origin at the DC position */
513 if (pRect != NULL)
514 {
515 rect.left += dcRect.left;
516 rect.right += dcRect.left;
517 rect.top += dcRect.top;
518 rect.bottom += dcRect.top;
519 }
520 /* if hDC is given and pRect is not the area of interest is the
521 bounding rect of hDC */
522 else
523 {
524 rect = dcRect;
525 }
526 }
527
528 if (hDC == NULL && pRect == NULL)
529 myRect = NULL;
530 else
531 myRect = &rect;
532
533 /* find intersecting monitors */
534 numMonitors = IntGetMonitorsFromRect(myRect, NULL, NULL, 0, 0);
535 if (numMonitors == 0 || listSize == 0 ||
536 (hMonitorList == NULL && monitorRectList == NULL))
537 {
538 DPRINT("numMonitors = %d\n", numMonitors);
539 return numMonitors;
540 }
541
542 if (hMonitorList != NULL && listSize != 0)
543 {
544 safeHMonitorList = ExAllocatePool(PagedPool, sizeof (HMONITOR) * listSize);
545 if (safeHMonitorList == NULL)
546 {
547 /* FIXME: SetLastWin32Error? */
548 return -1;
549 }
550 }
551 if (monitorRectList != NULL && listSize != 0)
552 {
553 safeRectList = ExAllocatePool(PagedPool, sizeof (RECT) * listSize);
554 if (safeRectList == NULL)
555 {
556 ExFreePool(safeHMonitorList);
557 /* FIXME: SetLastWin32Error? */
558 return -1;
559 }
560 }
561
562 /* get intersecting monitors */
563 numMonitors = IntGetMonitorsFromRect(myRect, safeHMonitorList, safeRectList,
564 listSize, 0 );
565
566 if (hDC != NULL && pRect != NULL && safeRectList != NULL)
567 for (i = 0; i < numMonitors; i++)
568 {
569 safeRectList[i].left -= dcRect.left;
570 safeRectList[i].right -= dcRect.left;
571 safeRectList[i].top -= dcRect.top;
572 safeRectList[i].bottom -= dcRect.top;
573 }
574
575 /* output result */
576 if (hMonitorList != NULL && listSize != 0)
577 {
578 status = MmCopyToCaller(hMonitorList, safeHMonitorList, sizeof (HMONITOR) * listSize);
579 ExFreePool(safeHMonitorList);
580 if (!NT_SUCCESS(status))
581 {
582 ExFreePool(safeRectList);
583 SetLastNtError(status);
584 return -1;
585 }
586 }
587 if (monitorRectList != NULL && listSize != 0)
588 {
589 status = MmCopyToCaller(monitorRectList, safeRectList, sizeof (RECT) * listSize);
590 ExFreePool(safeRectList);
591 if (!NT_SUCCESS(status))
592 {
593 SetLastNtError(status);
594 return -1;
595 }
596 }
597
598 return numMonitors;
599 }
600
601 /* NtUserGetMonitorInfo
602 *
603 * Retrieves information about a given monitor
604 *
605 * Arguments
606 *
607 * hMonitor
608 * Handle to a monitor for which to get information
609 *
610 * pMonitorInfo
611 * Pointer to a MONITORINFO struct which is filled with the information.
612 * The cbSize member must be set to sizeof(MONITORINFO) or
613 * sizeof(MONITORINFOEX). Even if set to sizeof(MONITORINFOEX) only parts
614 * from MONITORINFO will be filled.
615 *
616 * pDevice
617 * Pointer to a UNICODE_STRING which will recieve the device's name. The
618 * length should be CCHDEVICENAME
619 * Can be NULL
620 *
621 * Return value
622 * TRUE on success; FALSE on failure (calls SetLastNtError())
623 *
624 */
625 BOOL
626 APIENTRY
627 NtUserGetMonitorInfo(
628 IN HMONITOR hMonitor,
629 OUT LPMONITORINFO pMonitorInfo)
630 {
631 PMONITOR_OBJECT Monitor;
632 MONITORINFOEXW MonitorInfo;
633 NTSTATUS Status;
634 DECLARE_RETURN(BOOL);
635
636 DPRINT("Enter NtUserGetMonitorInfo\n");
637 UserEnterShared();
638
639 /* get monitor object */
640 if (!(Monitor = UserGetMonitorObject(hMonitor)))
641 {
642 DPRINT("Couldnt find monitor 0x%lx\n", hMonitor);
643 RETURN(FALSE);
644 }
645
646 if(pMonitorInfo == NULL)
647 {
648 SetLastNtError(STATUS_INVALID_PARAMETER);
649 RETURN(FALSE);
650 }
651
652 /* get size of pMonitorInfo */
653 Status = MmCopyFromCaller(&MonitorInfo.cbSize, &pMonitorInfo->cbSize, sizeof (MonitorInfo.cbSize));
654 if (!NT_SUCCESS(Status))
655 {
656 SetLastNtError(Status);
657 RETURN(FALSE);
658 }
659 if ((MonitorInfo.cbSize != sizeof (MONITORINFO)) &&
660 (MonitorInfo.cbSize != sizeof (MONITORINFOEXW)))
661 {
662 SetLastNtError(STATUS_INVALID_PARAMETER);
663 RETURN(FALSE);
664 }
665
666 /* fill monitor info */
667 MonitorInfo.rcMonitor.left = 0; /* FIXME: get origin */
668 MonitorInfo.rcMonitor.top = 0; /* FIXME: get origin */
669 MonitorInfo.rcMonitor.right = MonitorInfo.rcMonitor.left + Monitor->GdiDevice->gdiinfo.ulHorzRes;
670 MonitorInfo.rcMonitor.bottom = MonitorInfo.rcMonitor.top + Monitor->GdiDevice->gdiinfo.ulVertRes;
671 MonitorInfo.rcWork = MonitorInfo.rcMonitor; /* FIXME: use DEVMODE panning to calculate work area? */
672 MonitorInfo.dwFlags = 0;
673
674 if (Monitor->IsPrimary)
675 MonitorInfo.dwFlags |= MONITORINFOF_PRIMARY;
676
677 /* fill device name */
678 if (MonitorInfo.cbSize == sizeof (MONITORINFOEXW))
679 {
680 WCHAR nul = L'\0';
681 INT len = Monitor->DeviceName.Length;
682 if (len >= CCHDEVICENAME * sizeof (WCHAR))
683 len = (CCHDEVICENAME - 1) * sizeof (WCHAR);
684
685 memcpy(MonitorInfo.szDevice, Monitor->DeviceName.Buffer, len);
686 memcpy(MonitorInfo.szDevice + (len / sizeof (WCHAR)), &nul, sizeof (WCHAR));
687 }
688
689 /* output data */
690 Status = MmCopyToCaller(pMonitorInfo, &MonitorInfo, MonitorInfo.cbSize);
691 if (!NT_SUCCESS(Status))
692 {
693 DPRINT("GetMonitorInfo: MmCopyToCaller failed\n");
694 SetLastNtError(Status);
695 RETURN(FALSE);
696 }
697
698 DPRINT("GetMonitorInfo: success\n");
699
700 RETURN(TRUE);
701
702 CLEANUP:
703 DPRINT("Leave NtUserGetMonitorInfo, ret=%i\n",_ret_);
704 UserLeave();
705 END_CLEANUP;
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 APIENTRY
726 NtUserMonitorFromPoint(
727 IN POINT point,
728 IN DWORD dwFlags)
729 {
730 INT NumMonitors;
731 RECTL 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 APIENTRY
784 NtUserMonitorFromRect(
785 IN LPCRECTL pRect,
786 IN DWORD dwFlags)
787 {
788 INT numMonitors, iLargestArea = -1, i;
789 PRECTL rectList;
790 HMONITOR *hMonitorList;
791 HMONITOR hMonitor = NULL;
792 RECTL 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 ExFreePool(hMonitorList);
855 ExFreePool(rectList);
856 return (HMONITOR)NULL;
857 }
858
859 /* find largest intersection */
860 for (i = 0; i < numMonitors; i++)
861 {
862 INT area = (rectList[i].right - rectList[i].left) *
863 (rectList[i].bottom - rectList[i].top);
864 if (area > iLargestArea)
865 {
866 hMonitor = hMonitorList[i];
867 }
868 }
869
870 ExFreePool(hMonitorList);
871 ExFreePool(rectList);
872
873 return hMonitor;
874 }
875
876
877 HMONITOR
878 APIENTRY
879 NtUserMonitorFromWindow(
880 IN HWND hWnd,
881 IN DWORD dwFlags)
882 {
883 PWINDOW_OBJECT Window;
884 HMONITOR hMonitor = NULL;
885 RECTL Rect;
886 DECLARE_RETURN(HMONITOR);
887
888 DPRINT("Enter NtUserMonitorFromWindow\n");
889 UserEnterShared();
890
891 if (!(Window = UserGetWindowObject(hWnd)))
892 {
893 if (dwFlags == MONITOR_DEFAULTTONULL)
894 {
895 RETURN(hMonitor);
896 }
897 IntGetMonitorsFromRect(NULL, &hMonitor, NULL, 1, dwFlags);
898 RETURN(hMonitor);
899 }
900
901 if (!Window->Wnd)
902 RETURN(hMonitor);
903
904 Rect.left = Rect.right = Window->Wnd->rcWindow.left;
905 Rect.top = Rect.bottom = Window->Wnd->rcWindow.bottom;
906
907 IntGetMonitorsFromRect(&Rect, &hMonitor, NULL, 1, dwFlags);
908
909 RETURN(hMonitor);
910
911 CLEANUP:
912 DPRINT("Leave NtUserMonitorFromWindow, ret=%i\n",_ret_);
913 UserLeave();
914 END_CLEANUP;
915 }