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