[SHELLBTRFS] Add a PCH.
[reactos.git] / win32ss / user / ntuser / monitor.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * PURPOSE: pMonitor support
5 * FILE: subsys/win32k/ntuser/monitor.c
6 * PROGRAMERS: Anich Gregor (blight@blight.eu.org)
7 * Rafal Harabien (rafalh@reactos.org)
8 */
9
10 #include <win32k.h>
11 DBG_DEFAULT_CHANNEL(UserMonitor);
12
13 #define NDEBUG
14 #include <debug.h>
15
16 /* GLOBALS *******************************************************************/
17
18 /* List of monitors */
19 static PMONITOR gMonitorList = NULL;
20
21 /* PRIVATE FUNCTIONS **********************************************************/
22
23 /* IntCreateMonitorObject
24 *
25 * Creates a MONITOR
26 *
27 * Return value
28 * If the function succeeds a pointer to a MONITOR is returned. On failure
29 * NULL is returned.
30 */
31 static
32 PMONITOR
33 IntCreateMonitorObject(VOID)
34 {
35 return UserCreateObject(gHandleTable, NULL, NULL, NULL, TYPE_MONITOR, sizeof(MONITOR));
36 }
37
38 /* IntDestroyMonitorObject
39 *
40 * Destroys a MONITOR
41 * You have to be the owner of the monitors lock to safely destroy it.
42 *
43 * Arguments
44 *
45 * pMonitor
46 * Pointer to the MONITOR which shall be deleted
47 */
48 static
49 void
50 IntDestroyMonitorObject(IN PMONITOR pMonitor)
51 {
52 /* Remove monitor region */
53 if (pMonitor->hrgnMonitor)
54 {
55 GreSetObjectOwner(pMonitor->hrgnMonitor, GDI_OBJ_HMGR_POWNED);
56 GreDeleteObject(pMonitor->hrgnMonitor);
57 }
58
59 /* Destroy monitor object */
60 UserDereferenceObject(pMonitor);
61 UserDeleteObject(UserHMGetHandle(pMonitor), TYPE_MONITOR);
62 }
63
64 /* UserGetMonitorObject
65 *
66 * Returns monitor object from handle or sets last error if handle is invalid
67 *
68 * Arguments
69 *
70 * hMonitor
71 * Handle of MONITOR object
72 */
73 PMONITOR NTAPI
74 UserGetMonitorObject(IN HMONITOR hMonitor)
75 {
76 PMONITOR pMonitor;
77
78 if (!hMonitor)
79 {
80 EngSetLastError(ERROR_INVALID_MONITOR_HANDLE);
81 return NULL;
82 }
83
84 pMonitor = (PMONITOR)UserGetObject(gHandleTable, hMonitor, TYPE_MONITOR);
85 if (!pMonitor)
86 {
87 EngSetLastError(ERROR_INVALID_MONITOR_HANDLE);
88 return NULL;
89 }
90
91 return pMonitor;
92 }
93
94 /* UserGetPrimaryMonitor
95 *
96 * Returns a PMONITOR for the primary monitor
97 *
98 * Return value
99 * PMONITOR
100 */
101 PMONITOR NTAPI
102 UserGetPrimaryMonitor(VOID)
103 {
104 PMONITOR pMonitor;
105
106 /* Find primary monitor */
107 for (pMonitor = gMonitorList; pMonitor != NULL; pMonitor = pMonitor->pMonitorNext)
108 {
109 if (pMonitor->IsPrimary)
110 break;
111 }
112
113 return pMonitor;
114 }
115
116 /* UserAttachMonitor
117 *
118 * Creates a new MONITOR and appends it to the list of monitors.
119 *
120 * Arguments
121 *
122 * pGdiDevice Pointer to the PDEVOBJ onto which the monitor was attached
123 * DisplayNumber Display Number (starting with 0)
124 *
125 * Return value
126 * Returns a NTSTATUS
127 */
128 NTSTATUS NTAPI
129 UserAttachMonitor(IN HDEV hDev)
130 {
131 PMONITOR pMonitor;
132
133 TRACE("Attaching monitor...\n");
134
135 /* Create new monitor object */
136 pMonitor = IntCreateMonitorObject();
137 if (pMonitor == NULL)
138 {
139 TRACE("Couldnt create monitor object\n");
140 return STATUS_INSUFFICIENT_RESOURCES;
141 }
142
143 pMonitor->hDev = hDev;
144 pMonitor->cWndStack = 0;
145
146 if (gMonitorList == NULL)
147 {
148 TRACE("Primary monitor is beeing attached\n");
149 pMonitor->IsPrimary = TRUE;
150 gMonitorList = pMonitor;
151 }
152 else
153 {
154 PMONITOR pmonLast = gMonitorList;
155 TRACE("Additional monitor is beeing attached\n");
156 while (pmonLast->pMonitorNext != NULL)
157 pmonLast = pmonLast->pMonitorNext;
158
159 pmonLast->pMonitorNext = pMonitor;
160 }
161
162 UserUpdateMonitorSize(hDev);
163
164 return STATUS_SUCCESS;
165 }
166
167 /* UserDetachMonitor
168 *
169 * Deletes a MONITOR and removes it from the list of monitors.
170 *
171 * Arguments
172 *
173 * pGdiDevice Pointer to the PDEVOBJ from which the monitor was detached
174 *
175 * Return value
176 * Returns a NTSTATUS
177 */
178 NTSTATUS NTAPI
179 UserDetachMonitor(IN HDEV hDev)
180 {
181 PMONITOR pMonitor = gMonitorList, *pLink = &gMonitorList;
182
183 /* Find monitor attached to given device */
184 while (pMonitor != NULL)
185 {
186 if (pMonitor->hDev == hDev)
187 break;
188
189 pLink = &pMonitor->pMonitorNext;
190 pMonitor = pMonitor->pMonitorNext;
191 }
192
193 if (pMonitor == NULL)
194 {
195 /* No monitor has been found */
196 return STATUS_INVALID_PARAMETER;
197 }
198
199 /* We destroy primary monitor - set next as primary */
200 if (pMonitor->IsPrimary && pMonitor->pMonitorNext != NULL)
201 pMonitor->pMonitorNext->IsPrimary = TRUE;
202
203 /* Update Next ptr in previous monitor */
204 *pLink = pMonitor->pMonitorNext;
205
206 /* Finally destroy monitor */
207 IntDestroyMonitorObject(pMonitor);
208
209 return STATUS_SUCCESS;
210 }
211
212 /* UserUpdateMonitorSize
213 *
214 * Reset size of the monitor using atached device
215 *
216 * Arguments
217 *
218 * PMONITOR
219 * pGdiDevice Pointer to the PDEVOBJ, which size has changed
220 *
221 * Return value
222 * Returns a NTSTATUS
223 */
224 NTSTATUS NTAPI
225 UserUpdateMonitorSize(IN HDEV hDev)
226 {
227 PMONITOR pMonitor;
228 SIZEL DeviceSize;
229
230 /* Find monitor attached to given device */
231 for (pMonitor = gMonitorList; pMonitor != NULL; pMonitor = pMonitor->pMonitorNext)
232 {
233 if (pMonitor->hDev == hDev)
234 break;
235 }
236
237 if (pMonitor == NULL)
238 {
239 /* No monitor has been found */
240 return STATUS_INVALID_PARAMETER;
241 }
242
243 /* Get the size of the hdev */
244 PDEVOBJ_sizl((PPDEVOBJ)hDev, &DeviceSize);
245
246 /* Update monitor size */
247 pMonitor->rcMonitor.left = 0;
248 pMonitor->rcMonitor.top = 0;
249 pMonitor->rcMonitor.right = pMonitor->rcMonitor.left + DeviceSize.cx;
250 pMonitor->rcMonitor.bottom = pMonitor->rcMonitor.top + DeviceSize.cy;
251 pMonitor->rcWork = pMonitor->rcMonitor;
252
253 /* Destroy monitor region... */
254 if (pMonitor->hrgnMonitor)
255 {
256 GreSetObjectOwner(pMonitor->hrgnMonitor, GDI_OBJ_HMGR_POWNED);
257 GreDeleteObject(pMonitor->hrgnMonitor);
258 }
259
260 /* ...and create new one */
261 pMonitor->hrgnMonitor = NtGdiCreateRectRgn(
262 pMonitor->rcMonitor.left,
263 pMonitor->rcMonitor.top,
264 pMonitor->rcMonitor.right,
265 pMonitor->rcMonitor.bottom);
266 if (pMonitor->hrgnMonitor)
267 IntGdiSetRegionOwner(pMonitor->hrgnMonitor, GDI_OBJ_HMGR_PUBLIC);
268
269 //
270 // Should be Virtual accumulation of all the available monitors.
271 //
272 gpsi->rcScreenReal = pMonitor->rcMonitor;
273
274 return STATUS_SUCCESS;
275 }
276
277 /* IntGetMonitorsFromRect
278 *
279 * Returns a list of monitor handles/rectangles. The rectangles in the list are
280 * the areas of intersection with the monitors.
281 *
282 * Arguments
283 *
284 * pRect
285 * Rectangle in desktop coordinates. If this is NULL all monitors are
286 * returned and the rect list is filled with the sizes of the monitors.
287 *
288 * phMonitorList
289 * Pointer to an array of HMONITOR which is filled with monitor handles.
290 * Can be NULL
291 *
292 * prcMonitorList
293 * Pointer to an array of RECT which is filled with intersection rects in
294 * desktop coordinates.
295 * Can be NULL, will be ignored if no intersecting monitor is found and
296 * flags is MONITOR_DEFAULTTONEAREST
297 *
298 * dwListSize
299 * Size of the phMonitorList and prcMonitorList arguments. If this is zero
300 * phMonitorList and prcMonitorList are ignored.
301 *
302 * dwFlags
303 * Either 0 or MONITOR_DEFAULTTONEAREST (ignored if rect is NULL)
304 *
305 * Returns
306 * The number of monitors which intersect the specified region.
307 */
308 static
309 UINT
310 IntGetMonitorsFromRect(OPTIONAL IN LPCRECTL pRect,
311 OPTIONAL OUT HMONITOR *phMonitorList,
312 OPTIONAL OUT PRECTL prcMonitorList,
313 OPTIONAL IN DWORD dwListSize,
314 OPTIONAL IN DWORD dwFlags)
315 {
316 PMONITOR pMonitor, pNearestMonitor = NULL, pPrimaryMonitor = NULL;
317 UINT cMonitors = 0;
318 ULONG iNearestDistance = 0xffffffff;
319
320 /* Find monitors which intersects the rectangle */
321 for (pMonitor = gMonitorList; pMonitor != NULL; pMonitor = pMonitor->pMonitorNext)
322 {
323 RECTL MonitorRect, IntersectionRect;
324
325 MonitorRect = pMonitor->rcMonitor;
326
327 TRACE("MonitorRect: left = %d, top = %d, right = %d, bottom = %d\n",
328 MonitorRect.left, MonitorRect.top, MonitorRect.right, MonitorRect.bottom);
329
330 /* Save primary monitor for later usage */
331 if (dwFlags == MONITOR_DEFAULTTOPRIMARY && pMonitor->IsPrimary)
332 pPrimaryMonitor = pMonitor;
333
334 /* Check if a rect is given */
335 if (pRect == NULL)
336 {
337 /* No rect given, so use the full monitor rect */
338 IntersectionRect = MonitorRect;
339 }
340 /* We have a rect, calculate intersection */
341 else if (!RECTL_bIntersectRect(&IntersectionRect, &MonitorRect, pRect))
342 {
343 /* Rects did not intersect */
344 if (dwFlags == MONITOR_DEFAULTTONEAREST)
345 {
346 ULONG cx, cy, iDistance;
347
348 /* Get x and y distance */
349 cx = min(abs(MonitorRect.left - pRect->right),
350 abs(pRect->left - MonitorRect.right));
351 cy = min(abs(MonitorRect.top - pRect->bottom),
352 abs(pRect->top - MonitorRect.bottom));
353
354 /* Calculate distance square */
355 iDistance = cx * cx + cy * cy;
356
357 /* Check if this is the new nearest monitor */
358 if (iDistance < iNearestDistance)
359 {
360 iNearestDistance = iDistance;
361 pNearestMonitor = pMonitor;
362 }
363 }
364
365 continue;
366 }
367
368 /* Check if there's space in the buffer */
369 if (cMonitors < dwListSize)
370 {
371 /* Save monitor data */
372 if (phMonitorList != NULL)
373 phMonitorList[cMonitors] = UserHMGetHandle(pMonitor);
374 if (prcMonitorList != NULL)
375 prcMonitorList[cMonitors] = IntersectionRect;
376 }
377
378 /* Increase count of found monitors */
379 cMonitors++;
380 }
381
382 /* Nothing has been found? */
383 if (cMonitors == 0)
384 {
385 /* Check if we shall default to the nearest monitor */
386 if (dwFlags == MONITOR_DEFAULTTONEAREST && pNearestMonitor)
387 {
388 if (phMonitorList && dwListSize > 0)
389 phMonitorList[cMonitors] = UserHMGetHandle(pNearestMonitor);
390 cMonitors++;
391 }
392 /* Check if we shall default to the primary monitor */
393 else if (dwFlags == MONITOR_DEFAULTTOPRIMARY && pPrimaryMonitor)
394 {
395 if (phMonitorList != NULL && dwListSize > 0)
396 phMonitorList[cMonitors] = UserHMGetHandle(pPrimaryMonitor);
397 cMonitors++;
398 }
399 }
400
401 return cMonitors;
402 }
403
404 PMONITOR NTAPI
405 UserMonitorFromRect(
406 PRECTL pRect,
407 DWORD dwFlags)
408 {
409 ULONG cMonitors, LargestArea = 0, i;
410 PRECTL prcMonitorList = NULL;
411 HMONITOR *phMonitorList = NULL;
412 HMONITOR hMonitor = NULL;
413
414 /* Check if flags are valid */
415 if (dwFlags != MONITOR_DEFAULTTONULL &&
416 dwFlags != MONITOR_DEFAULTTOPRIMARY &&
417 dwFlags != MONITOR_DEFAULTTONEAREST)
418 {
419 EngSetLastError(ERROR_INVALID_FLAGS);
420 return NULL;
421 }
422
423 /* Find intersecting monitors */
424 cMonitors = IntGetMonitorsFromRect(pRect, &hMonitor, NULL, 1, dwFlags);
425 if (cMonitors <= 1)
426 {
427 /* No or one monitor found. Just return handle. */
428 goto cleanup;
429 }
430
431 /* There is more than one monitor. Find monitor with largest intersection.
432 Temporary reset hMonitor */
433 hMonitor = NULL;
434
435 /* Allocate helper buffers */
436 phMonitorList = ExAllocatePoolWithTag(PagedPool,
437 sizeof(HMONITOR) * cMonitors,
438 USERTAG_MONITORRECTS);
439 if (phMonitorList == NULL)
440 {
441 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
442 goto cleanup;
443 }
444
445 prcMonitorList = ExAllocatePoolWithTag(PagedPool,
446 sizeof(RECT) * cMonitors,
447 USERTAG_MONITORRECTS);
448 if (prcMonitorList == NULL)
449 {
450 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
451 goto cleanup;
452 }
453
454 /* Get intersecting monitors again but now with rectangle list */
455 cMonitors = IntGetMonitorsFromRect(pRect, phMonitorList, prcMonitorList,
456 cMonitors, 0);
457
458 /* Find largest intersection */
459 for (i = 0; i < cMonitors; i++)
460 {
461 ULONG Area = (prcMonitorList[i].right - prcMonitorList[i].left) *
462 (prcMonitorList[i].bottom - prcMonitorList[i].top);
463 if (Area >= LargestArea)
464 {
465 hMonitor = phMonitorList[i];
466 LargestArea = Area;
467 }
468 }
469
470 cleanup:
471 if (phMonitorList)
472 ExFreePoolWithTag(phMonitorList, USERTAG_MONITORRECTS);
473 if (prcMonitorList)
474 ExFreePoolWithTag(prcMonitorList, USERTAG_MONITORRECTS);
475
476 return UserGetMonitorObject(hMonitor);
477 }
478
479 PMONITOR
480 FASTCALL
481 UserMonitorFromPoint(
482 IN POINT pt,
483 IN DWORD dwFlags)
484 {
485 RECTL rc;
486 HMONITOR hMonitor = NULL;
487
488 /* Check if flags are valid */
489 if (dwFlags != MONITOR_DEFAULTTONULL &&
490 dwFlags != MONITOR_DEFAULTTOPRIMARY &&
491 dwFlags != MONITOR_DEFAULTTONEAREST)
492 {
493 EngSetLastError(ERROR_INVALID_FLAGS);
494 return NULL;
495 }
496
497 /* Fill rect (bottom-right exclusive) */
498 rc.left = pt.x;
499 rc.right = pt.x + 1;
500 rc.top = pt.y;
501 rc.bottom = pt.y + 1;
502
503 /* Find intersecting monitor */
504 IntGetMonitorsFromRect(&rc, &hMonitor, NULL, 1, dwFlags);
505
506 return UserGetMonitorObject(hMonitor);
507 }
508
509 /* PUBLIC FUNCTIONS ***********************************************************/
510
511 /* NtUserEnumDisplayMonitors
512 *
513 * Enumerates display monitors which intersect the given HDC/cliprect
514 *
515 * Arguments
516 *
517 * hdc
518 * Handle to a DC for which to enum intersecting monitors. If this is NULL
519 * it returns all monitors which are part of the current virtual screen.
520 *
521 * pUnsafeRect
522 * Clipping rectangle with coordinate system origin at the DCs origin if the
523 * given HDC is not NULL or in virtual screen coordinated if it is NULL.
524 * Can be NULL
525 *
526 * phUnsafeMonitorList
527 * Pointer to an array of HMONITOR which is filled with monitor handles.
528 * Can be NULL
529 *
530 * prcUnsafeMonitorList
531 * Pointer to an array of RECT which is filled with intersection rectangles.
532 * Can be NULL
533 *
534 * dwListSize
535 * Size of the hMonitorList and monitorRectList arguments. If this is zero
536 * hMonitorList and monitorRectList are ignored.
537 *
538 * Returns
539 * The number of monitors which intersect the specified region or -1 on failure.
540 */
541 INT
542 APIENTRY
543 NtUserEnumDisplayMonitors(
544 OPTIONAL IN HDC hdc,
545 OPTIONAL IN LPCRECTL pUnsafeRect,
546 OPTIONAL OUT HMONITOR *phUnsafeMonitorList,
547 OPTIONAL OUT PRECTL prcUnsafeMonitorList,
548 OPTIONAL IN DWORD dwListSize)
549 {
550 UINT cMonitors, i;
551 INT iRet = -1;
552 HMONITOR *phMonitorList = NULL;
553 PRECTL prcMonitorList = NULL;
554 RECTL rc, *pRect;
555 RECTL DcRect = {0};
556 NTSTATUS Status;
557
558 /* Get rectangle */
559 if (pUnsafeRect != NULL)
560 {
561 Status = MmCopyFromCaller(&rc, pUnsafeRect, sizeof(RECT));
562 if (!NT_SUCCESS(Status))
563 {
564 TRACE("MmCopyFromCaller() failed!\n");
565 SetLastNtError(Status);
566 return -1;
567 }
568 }
569
570 if (hdc != NULL)
571 {
572 PDC pDc;
573 INT iRgnType;
574
575 /* Get visible region bounding rect */
576 pDc = DC_LockDc(hdc);
577 if (pDc == NULL)
578 {
579 TRACE("DC_LockDc() failed!\n");
580 /* FIXME: setlasterror? */
581 return -1;
582 }
583 iRgnType = REGION_GetRgnBox(pDc->prgnVis, &DcRect);
584 DC_UnlockDc(pDc);
585
586 if (iRgnType == 0)
587 {
588 TRACE("NtGdiGetRgnBox() failed!\n");
589 return -1;
590 }
591 if (iRgnType == NULLREGION)
592 return 0;
593 if (iRgnType == COMPLEXREGION)
594 {
595 /* TODO: Warning */
596 }
597
598 /* If hdc and pRect are given the area of interest is pRect with
599 coordinate origin at the DC position */
600 if (pUnsafeRect != NULL)
601 {
602 rc.left += DcRect.left;
603 rc.right += DcRect.left;
604 rc.top += DcRect.top;
605 rc.bottom += DcRect.top;
606 }
607 /* If hdc is given and pRect is not the area of interest is the
608 bounding rect of hdc */
609 else
610 {
611 rc = DcRect;
612 }
613 }
614
615 if (hdc == NULL && pUnsafeRect == NULL)
616 pRect = NULL;
617 else
618 pRect = &rc;
619
620 UserEnterShared();
621
622 /* Find intersecting monitors */
623 cMonitors = IntGetMonitorsFromRect(pRect, NULL, NULL, 0, MONITOR_DEFAULTTONULL);
624 if (cMonitors == 0 || dwListSize == 0 ||
625 (phUnsafeMonitorList == NULL && prcUnsafeMonitorList == NULL))
626 {
627 /* Simple case - just return monitors count */
628 TRACE("cMonitors = %u\n", cMonitors);
629 iRet = cMonitors;
630 goto cleanup;
631 }
632
633 /* Allocate safe buffers */
634 if (phUnsafeMonitorList != NULL && dwListSize != 0)
635 {
636 phMonitorList = ExAllocatePoolWithTag(PagedPool, sizeof (HMONITOR) * dwListSize, USERTAG_MONITORRECTS);
637 if (phMonitorList == NULL)
638 {
639 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
640 goto cleanup;
641 }
642 }
643 if (prcUnsafeMonitorList != NULL && dwListSize != 0)
644 {
645 prcMonitorList = ExAllocatePoolWithTag(PagedPool, sizeof(RECT) * dwListSize,USERTAG_MONITORRECTS);
646 if (prcMonitorList == NULL)
647 {
648 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
649 goto cleanup;
650 }
651 }
652
653 /* Get intersecting monitors */
654 cMonitors = IntGetMonitorsFromRect(pRect, phMonitorList, prcMonitorList,
655 dwListSize, MONITOR_DEFAULTTONULL);
656
657 if (hdc != NULL && pRect != NULL && prcMonitorList != NULL)
658 {
659 for (i = 0; i < min(cMonitors, dwListSize); i++)
660 {
661 _Analysis_assume_(i < dwListSize);
662 prcMonitorList[i].left -= DcRect.left;
663 prcMonitorList[i].right -= DcRect.left;
664 prcMonitorList[i].top -= DcRect.top;
665 prcMonitorList[i].bottom -= DcRect.top;
666 }
667 }
668
669 /* Output result */
670 if (phUnsafeMonitorList != NULL && dwListSize != 0)
671 {
672 Status = MmCopyToCaller(phUnsafeMonitorList, phMonitorList, sizeof(HMONITOR) * dwListSize);
673 if (!NT_SUCCESS(Status))
674 {
675 SetLastNtError(Status);
676 goto cleanup;
677 }
678 }
679 if (prcUnsafeMonitorList != NULL && dwListSize != 0)
680 {
681 Status = MmCopyToCaller(prcUnsafeMonitorList, prcMonitorList, sizeof(RECT) * dwListSize);
682 if (!NT_SUCCESS(Status))
683 {
684 SetLastNtError(Status);
685 goto cleanup;
686 }
687 }
688
689 /* Return monitors count on success */
690 iRet = cMonitors;
691
692 cleanup:
693 if (phMonitorList)
694 ExFreePoolWithTag(phMonitorList, USERTAG_MONITORRECTS);
695 if (prcMonitorList)
696 ExFreePoolWithTag(prcMonitorList, USERTAG_MONITORRECTS);
697
698 UserLeave();
699 return iRet;
700 }
701
702 /* NtUserGetMonitorInfo
703 *
704 * Retrieves information about a given monitor
705 *
706 * Arguments
707 *
708 * hMonitor
709 * Handle to a monitor for which to get information
710 *
711 * pMonitorInfoUnsafe
712 * Pointer to a MONITORINFO struct which is filled with the information.
713 * The cbSize member must be set to sizeof(MONITORINFO) or
714 * sizeof(MONITORINFOEX). Even if set to sizeof(MONITORINFOEX) only parts
715 * from MONITORINFO will be filled.
716 *
717 * pDevice
718 * Pointer to a UNICODE_STRING which will receive the device's name. The
719 * length should be CCHDEVICENAME
720 * Can be NULL
721 *
722 * Return value
723 * TRUE on success; FALSE on failure (calls SetLastNtError())
724 *
725 */
726 BOOL
727 APIENTRY
728 NtUserGetMonitorInfo(
729 IN HMONITOR hMonitor,
730 OUT LPMONITORINFO pMonitorInfoUnsafe)
731 {
732 PMONITOR pMonitor;
733 MONITORINFOEXW MonitorInfo;
734 NTSTATUS Status;
735 BOOL bRet = FALSE;
736 PWCHAR pwstrDeviceName;
737
738 TRACE("Enter NtUserGetMonitorInfo\n");
739 UserEnterShared();
740
741 /* Get monitor object */
742 pMonitor = UserGetMonitorObject(hMonitor);
743 if (!pMonitor)
744 {
745 TRACE("Couldnt find monitor %p\n", hMonitor);
746 goto cleanup;
747 }
748
749 /* Check if pMonitorInfoUnsafe is valid */
750 if(pMonitorInfoUnsafe == NULL)
751 {
752 SetLastNtError(STATUS_INVALID_PARAMETER);
753 goto cleanup;
754 }
755
756 pwstrDeviceName = ((PPDEVOBJ)(pMonitor->hDev))->pGraphicsDevice->szWinDeviceName;
757
758 /* Get size of pMonitorInfoUnsafe */
759 Status = MmCopyFromCaller(&MonitorInfo.cbSize, &pMonitorInfoUnsafe->cbSize, sizeof(MonitorInfo.cbSize));
760 if (!NT_SUCCESS(Status))
761 {
762 SetLastNtError(Status);
763 goto cleanup;
764 }
765
766 /* Check if size of struct is valid */
767 if (MonitorInfo.cbSize != sizeof(MONITORINFO) &&
768 MonitorInfo.cbSize != sizeof(MONITORINFOEXW))
769 {
770 SetLastNtError(STATUS_INVALID_PARAMETER);
771 goto cleanup;
772 }
773
774 /* Fill monitor info */
775 MonitorInfo.rcMonitor = pMonitor->rcMonitor;
776 MonitorInfo.rcWork = pMonitor->rcWork;
777 MonitorInfo.dwFlags = 0;
778 if (pMonitor->IsPrimary)
779 MonitorInfo.dwFlags |= MONITORINFOF_PRIMARY;
780
781 /* Fill device name */
782 if (MonitorInfo.cbSize == sizeof(MONITORINFOEXW))
783 {
784 RtlStringCbCopyNExW(MonitorInfo.szDevice,
785 sizeof(MonitorInfo.szDevice),
786 pwstrDeviceName,
787 (wcslen(pwstrDeviceName)+1) * sizeof(WCHAR),
788 NULL, NULL, STRSAFE_FILL_BEHIND_NULL);
789 }
790
791 /* Output data */
792 Status = MmCopyToCaller(pMonitorInfoUnsafe, &MonitorInfo, MonitorInfo.cbSize);
793 if (!NT_SUCCESS(Status))
794 {
795 TRACE("GetMonitorInfo: MmCopyToCaller failed\n");
796 SetLastNtError(Status);
797 goto cleanup;
798 }
799
800 TRACE("GetMonitorInfo: success\n");
801 bRet = TRUE;
802
803 cleanup:
804 TRACE("Leave NtUserGetMonitorInfo, ret=%i\n", bRet);
805 UserLeave();
806 return bRet;
807 }
808
809 /* NtUserMonitorFromPoint
810 *
811 * Returns a handle to the monitor containing the given point.
812 *
813 * Arguments
814 *
815 * pt
816 * Point for which to find monitor
817 *
818 * dwFlags
819 * Specifies the behaviour if the point isn't on any of the monitors.
820 *
821 * Return value
822 * If the point is found a handle to the monitor is returned; if not the
823 * return value depends on dwFlags
824 */
825 HMONITOR
826 APIENTRY
827 NtUserMonitorFromPoint(
828 IN POINT pt,
829 IN DWORD dwFlags)
830 {
831 RECTL rc;
832 HMONITOR hMonitor = NULL;
833
834 /* Check if flags are valid */
835 if (dwFlags != MONITOR_DEFAULTTONULL &&
836 dwFlags != MONITOR_DEFAULTTOPRIMARY &&
837 dwFlags != MONITOR_DEFAULTTONEAREST)
838 {
839 EngSetLastError(ERROR_INVALID_FLAGS);
840 return NULL;
841 }
842
843 /* Fill rect (bottom-right exclusive) */
844 rc.left = pt.x;
845 rc.right = pt.x + 1;
846 rc.top = pt.y;
847 rc.bottom = pt.y + 1;
848
849 UserEnterShared();
850
851 /* Find intersecting monitor */
852 IntGetMonitorsFromRect(&rc, &hMonitor, NULL, 1, dwFlags);
853
854 UserLeave();
855 return hMonitor;
856 }
857
858 /* NtUserMonitorFromRect
859 *
860 * Returns a handle to the monitor having the largest intersection with a
861 * given rectangle
862 *
863 * Arguments
864 *
865 * pRectUnsafe
866 * Pointer to a RECT for which to find monitor
867 *
868 * dwFlags
869 * Specifies the behaviour if no monitor intersects the given rect
870 *
871 * Return value
872 * If a monitor intersects the rect a handle to it is returned; if not the
873 * return value depends on dwFlags
874 */
875 HMONITOR
876 APIENTRY
877 NtUserMonitorFromRect(
878 IN LPCRECTL pRectUnsafe,
879 IN DWORD dwFlags)
880 {
881 ULONG cMonitors, LargestArea = 0, i;
882 PRECTL prcMonitorList = NULL;
883 HMONITOR *phMonitorList = NULL;
884 HMONITOR hMonitor = NULL;
885 RECTL Rect;
886 NTSTATUS Status;
887
888 /* Check if flags are valid */
889 if (dwFlags != MONITOR_DEFAULTTONULL &&
890 dwFlags != MONITOR_DEFAULTTOPRIMARY &&
891 dwFlags != MONITOR_DEFAULTTONEAREST)
892 {
893 EngSetLastError(ERROR_INVALID_FLAGS);
894 return NULL;
895 }
896
897 /* Copy rectangle to safe buffer */
898 Status = MmCopyFromCaller(&Rect, pRectUnsafe, sizeof (RECT));
899 if (!NT_SUCCESS(Status))
900 {
901 SetLastNtError(Status);
902 return NULL;
903 }
904
905 UserEnterShared();
906
907 /* Find intersecting monitors */
908 cMonitors = IntGetMonitorsFromRect(&Rect, &hMonitor, NULL, 1, dwFlags);
909 if (cMonitors <= 1)
910 {
911 /* No or one monitor found. Just return handle. */
912 goto cleanup;
913 }
914
915 /* There is more than one monitor. Find monitor with largest intersection.
916 Temporary reset hMonitor */
917 hMonitor = NULL;
918
919 /* Allocate helper buffers */
920 phMonitorList = ExAllocatePoolWithTag(PagedPool,
921 sizeof(HMONITOR) * cMonitors,
922 USERTAG_MONITORRECTS);
923 if (phMonitorList == NULL)
924 {
925 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
926 goto cleanup;
927 }
928
929 prcMonitorList = ExAllocatePoolWithTag(PagedPool,
930 sizeof(RECT) * cMonitors,
931 USERTAG_MONITORRECTS);
932 if (prcMonitorList == NULL)
933 {
934 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
935 goto cleanup;
936 }
937
938 /* Get intersecting monitors again but now with rectangle list */
939 cMonitors = IntGetMonitorsFromRect(&Rect, phMonitorList, prcMonitorList,
940 cMonitors, 0);
941
942 /* Find largest intersection */
943 for (i = 0; i < cMonitors; i++)
944 {
945 ULONG Area = (prcMonitorList[i].right - prcMonitorList[i].left) *
946 (prcMonitorList[i].bottom - prcMonitorList[i].top);
947 if (Area >= LargestArea)
948 {
949 hMonitor = phMonitorList[i];
950 LargestArea = Area;
951 }
952 }
953
954 cleanup:
955 if (phMonitorList)
956 ExFreePoolWithTag(phMonitorList, USERTAG_MONITORRECTS);
957 if (prcMonitorList)
958 ExFreePoolWithTag(prcMonitorList, USERTAG_MONITORRECTS);
959 UserLeave();
960
961 return hMonitor;
962 }
963
964
965 HMONITOR
966 APIENTRY
967 NtUserMonitorFromWindow(
968 IN HWND hWnd,
969 IN DWORD dwFlags)
970 {
971 PWND pWnd;
972 HMONITOR hMonitor = NULL;
973 RECTL Rect = {0, 0, 0, 0};
974
975 TRACE("Enter NtUserMonitorFromWindow\n");
976
977 /* Check if flags are valid */
978 if (dwFlags != MONITOR_DEFAULTTONULL &&
979 dwFlags != MONITOR_DEFAULTTOPRIMARY &&
980 dwFlags != MONITOR_DEFAULTTONEAREST)
981 {
982 EngSetLastError(ERROR_INVALID_FLAGS);
983 return NULL;
984 }
985
986 UserEnterShared();
987
988 /* If window is given, use it first */
989 if (hWnd)
990 {
991 /* Get window object */
992 pWnd = UserGetWindowObject(hWnd);
993 if (!pWnd)
994 goto cleanup;
995
996 /* Find only monitors which have intersection with given window */
997 Rect.left = Rect.right = pWnd->rcWindow.left;
998 Rect.top = Rect.bottom = pWnd->rcWindow.bottom;
999 }
1000
1001 /* Find monitors now */
1002 IntGetMonitorsFromRect(&Rect, &hMonitor, NULL, 1, dwFlags);
1003
1004 cleanup:
1005 TRACE("Leave NtUserMonitorFromWindow, ret=%p\n", hMonitor);
1006 UserLeave();
1007 return hMonitor;
1008 }