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