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