[USER32]
[reactos.git] / reactos / 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()
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()
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 = IntSysCreateRectRgnIndirect(&pMonitor->rcMonitor);
262 if (pMonitor->hrgnMonitor)
263 IntGdiSetRegionOwner(pMonitor->hrgnMonitor, GDI_OBJ_HMGR_PUBLIC);
264
265 return STATUS_SUCCESS;
266 }
267
268 /* IntGetMonitorsFromRect
269 *
270 * Returns a list of monitor handles/rectangles. The rectangles in the list are
271 * the areas of intersection with the monitors.
272 *
273 * Arguments
274 *
275 * pRect
276 * Rectangle in desktop coordinates. If this is NULL all monitors are
277 * returned and the rect list is filled with the sizes of the monitors.
278 *
279 * phMonitorList
280 * Pointer to an array of HMONITOR which is filled with monitor handles.
281 * Can be NULL
282 *
283 * prcMonitorList
284 * Pointer to an array of RECT which is filled with intersection rects in
285 * desktop coordinates.
286 * Can be NULL, will be ignored if no intersecting monitor is found and
287 * flags is MONITOR_DEFAULTTONEAREST
288 *
289 * dwListSize
290 * Size of the phMonitorList and prcMonitorList arguments. If this is zero
291 * phMonitorList and prcMonitorList are ignored.
292 *
293 * dwFlags
294 * Either 0 or MONITOR_DEFAULTTONEAREST (ignored if rect is NULL)
295 *
296 * Returns
297 * The number of monitors which intersect the specified region.
298 */
299 static
300 UINT
301 IntGetMonitorsFromRect(OPTIONAL IN LPCRECTL pRect,
302 OPTIONAL OUT HMONITOR *phMonitorList,
303 OPTIONAL OUT PRECTL prcMonitorList,
304 OPTIONAL IN DWORD dwListSize,
305 OPTIONAL IN DWORD dwFlags)
306 {
307 PMONITOR pMonitor, pNearestMonitor = NULL, pPrimaryMonitor = NULL;
308 UINT cMonitors = 0;
309 ULONG iNearestDistance = 0xffffffff;
310
311 /* Find monitors which intersects the rectangle */
312 for (pMonitor = gMonitorList; pMonitor != NULL; pMonitor = pMonitor->pMonitorNext)
313 {
314 RECTL MonitorRect, IntersectionRect;
315
316 MonitorRect = pMonitor->rcMonitor;
317
318 TRACE("MonitorRect: left = %d, top = %d, right = %d, bottom = %d\n",
319 MonitorRect.left, MonitorRect.top, MonitorRect.right, MonitorRect.bottom);
320
321 /* Save primary monitor for later usage */
322 if (dwFlags == MONITOR_DEFAULTTOPRIMARY && pMonitor->IsPrimary)
323 pPrimaryMonitor = pMonitor;
324
325 /* Check if a rect is given */
326 if (pRect == NULL)
327 {
328 /* No rect given, so use the full monitor rect */
329 IntersectionRect = MonitorRect;
330 }
331 /* We have a rect, calculate intersection */
332 else if (!RECTL_bIntersectRect(&IntersectionRect, &MonitorRect, pRect))
333 {
334 /* Rects did not intersect */
335 if (dwFlags == MONITOR_DEFAULTTONEAREST)
336 {
337 ULONG cx, cy, iDistance;
338
339 /* Get x and y distance */
340 cx = min(abs(MonitorRect.left - pRect->right),
341 abs(pRect->left - MonitorRect.right));
342 cy = min(abs(MonitorRect.top - pRect->bottom),
343 abs(pRect->top - MonitorRect.bottom));
344
345 /* Calculate distance square */
346 iDistance = cx * cx + cy * cy;
347
348 /* Check if this is the new nearest monitor */
349 if (iDistance < iNearestDistance)
350 {
351 iNearestDistance = iDistance;
352 pNearestMonitor = pMonitor;
353 }
354 }
355
356 continue;
357 }
358
359 /* Check if there's space in the buffer */
360 if (cMonitors < dwListSize)
361 {
362 /* Save monitor data */
363 if (phMonitorList != NULL)
364 phMonitorList[cMonitors] = UserHMGetHandle(pMonitor);
365 if (prcMonitorList != NULL)
366 prcMonitorList[cMonitors] = IntersectionRect;
367 }
368
369 /* Increase count of found monitors */
370 cMonitors++;
371 }
372
373 /* Nothing has been found? */
374 if (cMonitors == 0)
375 {
376 /* Check if we shall default to the nearest monitor */
377 if (dwFlags == MONITOR_DEFAULTTONEAREST && pNearestMonitor)
378 {
379 if (phMonitorList && dwListSize > 0)
380 phMonitorList[cMonitors] = UserHMGetHandle(pNearestMonitor);
381 cMonitors++;
382 }
383 /* Check if we shall default to the primary monitor */
384 else if (dwFlags == MONITOR_DEFAULTTOPRIMARY && pPrimaryMonitor)
385 {
386 if (phMonitorList != NULL && dwListSize > 0)
387 phMonitorList[cMonitors] = UserHMGetHandle(pPrimaryMonitor);
388 cMonitors++;
389 }
390 }
391
392 return cMonitors;
393 }
394
395 PMONITOR NTAPI
396 UserMonitorFromRect(
397 PRECTL pRect,
398 DWORD dwFlags)
399 {
400 ULONG cMonitors, LargestArea = 0, i;
401 PRECTL prcMonitorList = NULL;
402 HMONITOR *phMonitorList = NULL;
403 HMONITOR hMonitor = NULL;
404
405 /* Check if flags are valid */
406 if (dwFlags != MONITOR_DEFAULTTONULL &&
407 dwFlags != MONITOR_DEFAULTTOPRIMARY &&
408 dwFlags != MONITOR_DEFAULTTONEAREST)
409 {
410 EngSetLastError(ERROR_INVALID_FLAGS);
411 return NULL;
412 }
413
414 /* Find intersecting monitors */
415 cMonitors = IntGetMonitorsFromRect(pRect, &hMonitor, NULL, 1, dwFlags);
416 if (cMonitors <= 1)
417 {
418 /* No or one monitor found. Just return handle. */
419 goto cleanup;
420 }
421
422 /* There is more than one monitor. Find monitor with largest intersection.
423 Temporary reset hMonitor */
424 hMonitor = NULL;
425
426 /* Allocate helper buffers */
427 phMonitorList = ExAllocatePoolWithTag(PagedPool,
428 sizeof(HMONITOR) * cMonitors,
429 USERTAG_MONITORRECTS);
430 if (phMonitorList == NULL)
431 {
432 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
433 goto cleanup;
434 }
435
436 prcMonitorList = ExAllocatePoolWithTag(PagedPool,
437 sizeof(RECT) * cMonitors,
438 USERTAG_MONITORRECTS);
439 if (prcMonitorList == NULL)
440 {
441 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
442 goto cleanup;
443 }
444
445 /* Get intersecting monitors again but now with rectangle list */
446 cMonitors = IntGetMonitorsFromRect(pRect, phMonitorList, prcMonitorList,
447 cMonitors, 0);
448
449 /* Find largest intersection */
450 for (i = 0; i < cMonitors; i++)
451 {
452 ULONG Area = (prcMonitorList[i].right - prcMonitorList[i].left) *
453 (prcMonitorList[i].bottom - prcMonitorList[i].top);
454 if (Area >= LargestArea)
455 {
456 hMonitor = phMonitorList[i];
457 LargestArea = Area;
458 }
459 }
460
461 cleanup:
462 if (phMonitorList)
463 ExFreePoolWithTag(phMonitorList, USERTAG_MONITORRECTS);
464 if (prcMonitorList)
465 ExFreePoolWithTag(prcMonitorList, USERTAG_MONITORRECTS);
466
467 return UserGetMonitorObject(hMonitor);
468 }
469
470 PMONITOR
471 FASTCALL
472 UserMonitorFromPoint(
473 IN POINT pt,
474 IN DWORD dwFlags)
475 {
476 RECTL rc;
477 HMONITOR hMonitor = NULL;
478
479 /* Check if flags are valid */
480 if (dwFlags != MONITOR_DEFAULTTONULL &&
481 dwFlags != MONITOR_DEFAULTTOPRIMARY &&
482 dwFlags != MONITOR_DEFAULTTONEAREST)
483 {
484 EngSetLastError(ERROR_INVALID_FLAGS);
485 return NULL;
486 }
487
488 /* Fill rect (bottom-right exclusive) */
489 rc.left = pt.x;
490 rc.right = pt.x + 1;
491 rc.top = pt.y;
492 rc.bottom = pt.y + 1;
493
494 /* Find intersecting monitor */
495 IntGetMonitorsFromRect(&rc, &hMonitor, NULL, 1, dwFlags);
496
497 return UserGetMonitorObject(hMonitor);
498 }
499
500 /* PUBLIC FUNCTIONS ***********************************************************/
501
502 /* NtUserEnumDisplayMonitors
503 *
504 * Enumerates display monitors which intersect the given HDC/cliprect
505 *
506 * Arguments
507 *
508 * hdc
509 * Handle to a DC for which to enum intersecting monitors. If this is NULL
510 * it returns all monitors which are part of the current virtual screen.
511 *
512 * pUnsafeRect
513 * Clipping rectangle with coordinate system origin at the DCs origin if the
514 * given HDC is not NULL or in virtual screen coordinated if it is NULL.
515 * Can be NULL
516 *
517 * phUnsafeMonitorList
518 * Pointer to an array of HMONITOR which is filled with monitor handles.
519 * Can be NULL
520 *
521 * prcUnsafeMonitorList
522 * Pointer to an array of RECT which is filled with intersection rectangles.
523 * Can be NULL
524 *
525 * dwListSize
526 * Size of the hMonitorList and monitorRectList arguments. If this is zero
527 * hMonitorList and monitorRectList are ignored.
528 *
529 * Returns
530 * The number of monitors which intersect the specified region or -1 on failure.
531 */
532 INT
533 APIENTRY
534 NtUserEnumDisplayMonitors(
535 OPTIONAL IN HDC hdc,
536 OPTIONAL IN LPCRECTL pUnsafeRect,
537 OPTIONAL OUT HMONITOR *phUnsafeMonitorList,
538 OPTIONAL OUT PRECTL prcUnsafeMonitorList,
539 OPTIONAL IN DWORD dwListSize)
540 {
541 INT cMonitors, iRet = -1, i;
542 HMONITOR *phMonitorList = NULL;
543 PRECTL prcMonitorList = NULL;
544 RECTL rc, *pRect;
545 RECTL DcRect = {0};
546 NTSTATUS Status;
547
548 /* Get rectangle */
549 if (pUnsafeRect != NULL)
550 {
551 Status = MmCopyFromCaller(&rc, pUnsafeRect, sizeof(RECT));
552 if (!NT_SUCCESS(Status))
553 {
554 TRACE("MmCopyFromCaller() failed!\n");
555 SetLastNtError(Status);
556 return -1;
557 }
558 }
559
560 if (hdc != NULL)
561 {
562 PDC pDc;
563 INT iRgnType;
564
565 /* Get visible region bounding rect */
566 pDc = DC_LockDc(hdc);
567 if (pDc == NULL)
568 {
569 TRACE("DC_LockDc() failed!\n");
570 /* FIXME: setlasterror? */
571 return -1;
572 }
573 iRgnType = REGION_GetRgnBox(pDc->prgnVis, &DcRect);
574 DC_UnlockDc(pDc);
575
576 if (iRgnType == 0)
577 {
578 TRACE("NtGdiGetRgnBox() failed!\n");
579 return -1;
580 }
581 if (iRgnType == NULLREGION)
582 return 0;
583 if (iRgnType == COMPLEXREGION)
584 {
585 /* TODO: Warning */
586 }
587
588 /* If hdc and pRect are given the area of interest is pRect with
589 coordinate origin at the DC position */
590 if (pUnsafeRect != NULL)
591 {
592 rc.left += DcRect.left;
593 rc.right += DcRect.left;
594 rc.top += DcRect.top;
595 rc.bottom += DcRect.top;
596 }
597 /* If hdc is given and pRect is not the area of interest is the
598 bounding rect of hdc */
599 else
600 {
601 rc = DcRect;
602 }
603 }
604
605 if (hdc == NULL && pUnsafeRect == NULL)
606 pRect = NULL;
607 else
608 pRect = &rc;
609
610 UserEnterShared();
611
612 /* Find intersecting monitors */
613 cMonitors = IntGetMonitorsFromRect(pRect, NULL, NULL, 0, MONITOR_DEFAULTTONULL);
614 if (cMonitors == 0 || dwListSize == 0 ||
615 (phUnsafeMonitorList == NULL && prcUnsafeMonitorList == NULL))
616 {
617 /* Simple case - just return monitors count */
618 TRACE("cMonitors = %d\n", cMonitors);
619 iRet = cMonitors;
620 goto cleanup;
621 }
622
623 /* Allocate safe buffers */
624 if (phUnsafeMonitorList != NULL && dwListSize != 0)
625 {
626 phMonitorList = ExAllocatePoolWithTag(PagedPool, sizeof (HMONITOR) * dwListSize, USERTAG_MONITORRECTS);
627 if (phMonitorList == NULL)
628 {
629 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
630 goto cleanup;
631 }
632 }
633 if (prcUnsafeMonitorList != NULL && dwListSize != 0)
634 {
635 prcMonitorList = ExAllocatePoolWithTag(PagedPool, sizeof (RECT) * dwListSize, USERTAG_MONITORRECTS);
636 if (prcMonitorList == NULL)
637 {
638 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
639 goto cleanup;
640 }
641 }
642
643 /* Get intersecting monitors */
644 cMonitors = IntGetMonitorsFromRect(pRect, phMonitorList, prcMonitorList,
645 dwListSize, MONITOR_DEFAULTTONULL);
646
647 if (hdc != NULL && pRect != NULL && prcMonitorList != NULL)
648 for (i = 0; i < cMonitors; i++)
649 {
650 prcMonitorList[i].left -= DcRect.left;
651 prcMonitorList[i].right -= DcRect.left;
652 prcMonitorList[i].top -= DcRect.top;
653 prcMonitorList[i].bottom -= DcRect.top;
654 }
655
656 /* Output result */
657 if (phUnsafeMonitorList != NULL && dwListSize != 0)
658 {
659 Status = MmCopyToCaller(phUnsafeMonitorList, phMonitorList, sizeof(HMONITOR) * dwListSize);
660 if (!NT_SUCCESS(Status))
661 {
662 SetLastNtError(Status);
663 goto cleanup;
664 }
665 }
666 if (prcUnsafeMonitorList != NULL && dwListSize != 0)
667 {
668 Status = MmCopyToCaller(prcUnsafeMonitorList, prcMonitorList, sizeof(RECT) * dwListSize);
669 if (!NT_SUCCESS(Status))
670 {
671 SetLastNtError(Status);
672 goto cleanup;
673 }
674 }
675
676 /* Return monitors count on success */
677 iRet = cMonitors;
678
679 cleanup:
680 if (phMonitorList)
681 ExFreePoolWithTag(phMonitorList, USERTAG_MONITORRECTS);
682 if (prcMonitorList)
683 ExFreePoolWithTag(prcMonitorList, USERTAG_MONITORRECTS);
684
685 UserLeave();
686 return iRet;
687 }
688
689 /* NtUserGetMonitorInfo
690 *
691 * Retrieves information about a given monitor
692 *
693 * Arguments
694 *
695 * hMonitor
696 * Handle to a monitor for which to get information
697 *
698 * pMonitorInfoUnsafe
699 * Pointer to a MONITORINFO struct which is filled with the information.
700 * The cbSize member must be set to sizeof(MONITORINFO) or
701 * sizeof(MONITORINFOEX). Even if set to sizeof(MONITORINFOEX) only parts
702 * from MONITORINFO will be filled.
703 *
704 * pDevice
705 * Pointer to a UNICODE_STRING which will receive the device's name. The
706 * length should be CCHDEVICENAME
707 * Can be NULL
708 *
709 * Return value
710 * TRUE on success; FALSE on failure (calls SetLastNtError())
711 *
712 */
713 BOOL
714 APIENTRY
715 NtUserGetMonitorInfo(
716 IN HMONITOR hMonitor,
717 OUT LPMONITORINFO pMonitorInfoUnsafe)
718 {
719 PMONITOR pMonitor;
720 MONITORINFOEXW MonitorInfo;
721 NTSTATUS Status;
722 BOOL bRet = FALSE;
723 PWCHAR pwstrDeviceName;
724
725 TRACE("Enter NtUserGetMonitorInfo\n");
726 UserEnterShared();
727
728 /* Get monitor object */
729 pMonitor = UserGetMonitorObject(hMonitor);
730 if (!pMonitor)
731 {
732 TRACE("Couldnt find monitor %p\n", hMonitor);
733 goto cleanup;
734 }
735
736 /* Check if pMonitorInfoUnsafe is valid */
737 if(pMonitorInfoUnsafe == NULL)
738 {
739 SetLastNtError(STATUS_INVALID_PARAMETER);
740 goto cleanup;
741 }
742
743 pwstrDeviceName = ((PPDEVOBJ)(pMonitor->hDev))->pGraphicsDevice->szWinDeviceName;
744
745 /* Get size of pMonitorInfoUnsafe */
746 Status = MmCopyFromCaller(&MonitorInfo.cbSize, &pMonitorInfoUnsafe->cbSize, sizeof(MonitorInfo.cbSize));
747 if (!NT_SUCCESS(Status))
748 {
749 SetLastNtError(Status);
750 goto cleanup;
751 }
752
753 /* Check if size of struct is valid */
754 if (MonitorInfo.cbSize != sizeof(MONITORINFO) &&
755 MonitorInfo.cbSize != sizeof(MONITORINFOEXW))
756 {
757 SetLastNtError(STATUS_INVALID_PARAMETER);
758 goto cleanup;
759 }
760
761 /* Fill monitor info */
762 MonitorInfo.rcMonitor = pMonitor->rcMonitor;
763 MonitorInfo.rcWork = pMonitor->rcWork;
764 MonitorInfo.dwFlags = 0;
765 if (pMonitor->IsPrimary)
766 MonitorInfo.dwFlags |= MONITORINFOF_PRIMARY;
767
768 /* Fill device name */
769 if (MonitorInfo.cbSize == sizeof(MONITORINFOEXW))
770 {
771 RtlStringCbCopyNExW(MonitorInfo.szDevice,
772 sizeof(MonitorInfo.szDevice),
773 pwstrDeviceName,
774 (wcslen(pwstrDeviceName)+1) * sizeof(WCHAR),
775 NULL, NULL, STRSAFE_FILL_BEHIND_NULL);
776 }
777
778 /* Output data */
779 Status = MmCopyToCaller(pMonitorInfoUnsafe, &MonitorInfo, MonitorInfo.cbSize);
780 if (!NT_SUCCESS(Status))
781 {
782 TRACE("GetMonitorInfo: MmCopyToCaller failed\n");
783 SetLastNtError(Status);
784 goto cleanup;
785 }
786
787 TRACE("GetMonitorInfo: success\n");
788 bRet = TRUE;
789
790 cleanup:
791 TRACE("Leave NtUserGetMonitorInfo, ret=%i\n", bRet);
792 UserLeave();
793 return bRet;
794 }
795
796 /* NtUserMonitorFromPoint
797 *
798 * Returns a handle to the monitor containing the given point.
799 *
800 * Arguments
801 *
802 * pt
803 * Point for which to find monitor
804 *
805 * dwFlags
806 * Specifies the behaviour if the point isn't on any of the monitors.
807 *
808 * Return value
809 * If the point is found a handle to the monitor is returned; if not the
810 * return value depends on dwFlags
811 */
812 HMONITOR
813 APIENTRY
814 NtUserMonitorFromPoint(
815 IN POINT pt,
816 IN DWORD dwFlags)
817 {
818 RECTL rc;
819 HMONITOR hMonitor = NULL;
820
821 /* Check if flags are valid */
822 if (dwFlags != MONITOR_DEFAULTTONULL &&
823 dwFlags != MONITOR_DEFAULTTOPRIMARY &&
824 dwFlags != MONITOR_DEFAULTTONEAREST)
825 {
826 EngSetLastError(ERROR_INVALID_FLAGS);
827 return NULL;
828 }
829
830 /* Fill rect (bottom-right exclusive) */
831 rc.left = pt.x;
832 rc.right = pt.x + 1;
833 rc.top = pt.y;
834 rc.bottom = pt.y + 1;
835
836 UserEnterShared();
837
838 /* Find intersecting monitor */
839 IntGetMonitorsFromRect(&rc, &hMonitor, NULL, 1, dwFlags);
840
841 UserLeave();
842 return hMonitor;
843 }
844
845 /* NtUserMonitorFromRect
846 *
847 * Returns a handle to the monitor having the largest intersection with a
848 * given rectangle
849 *
850 * Arguments
851 *
852 * pRectUnsafe
853 * Pointer to a RECT for which to find monitor
854 *
855 * dwFlags
856 * Specifies the behaviour if no monitor intersects the given rect
857 *
858 * Return value
859 * If a monitor intersects the rect a handle to it is returned; if not the
860 * return value depends on dwFlags
861 */
862 HMONITOR
863 APIENTRY
864 NtUserMonitorFromRect(
865 IN LPCRECTL pRectUnsafe,
866 IN DWORD dwFlags)
867 {
868 ULONG cMonitors, LargestArea = 0, i;
869 PRECTL prcMonitorList = NULL;
870 HMONITOR *phMonitorList = NULL;
871 HMONITOR hMonitor = NULL;
872 RECTL Rect;
873 NTSTATUS Status;
874
875 /* Check if flags are valid */
876 if (dwFlags != MONITOR_DEFAULTTONULL &&
877 dwFlags != MONITOR_DEFAULTTOPRIMARY &&
878 dwFlags != MONITOR_DEFAULTTONEAREST)
879 {
880 EngSetLastError(ERROR_INVALID_FLAGS);
881 return NULL;
882 }
883
884 /* Copy rectangle to safe buffer */
885 Status = MmCopyFromCaller(&Rect, pRectUnsafe, sizeof (RECT));
886 if (!NT_SUCCESS(Status))
887 {
888 SetLastNtError(Status);
889 return NULL;
890 }
891
892 UserEnterShared();
893
894 /* Find intersecting monitors */
895 cMonitors = IntGetMonitorsFromRect(&Rect, &hMonitor, NULL, 1, dwFlags);
896 if (cMonitors <= 1)
897 {
898 /* No or one monitor found. Just return handle. */
899 goto cleanup;
900 }
901
902 /* There is more than one monitor. Find monitor with largest intersection.
903 Temporary reset hMonitor */
904 hMonitor = NULL;
905
906 /* Allocate helper buffers */
907 phMonitorList = ExAllocatePoolWithTag(PagedPool,
908 sizeof(HMONITOR) * cMonitors,
909 USERTAG_MONITORRECTS);
910 if (phMonitorList == NULL)
911 {
912 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
913 goto cleanup;
914 }
915
916 prcMonitorList = ExAllocatePoolWithTag(PagedPool,
917 sizeof(RECT) * cMonitors,
918 USERTAG_MONITORRECTS);
919 if (prcMonitorList == NULL)
920 {
921 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
922 goto cleanup;
923 }
924
925 /* Get intersecting monitors again but now with rectangle list */
926 cMonitors = IntGetMonitorsFromRect(&Rect, phMonitorList, prcMonitorList,
927 cMonitors, 0);
928
929 /* Find largest intersection */
930 for (i = 0; i < cMonitors; i++)
931 {
932 ULONG Area = (prcMonitorList[i].right - prcMonitorList[i].left) *
933 (prcMonitorList[i].bottom - prcMonitorList[i].top);
934 if (Area >= LargestArea)
935 {
936 hMonitor = phMonitorList[i];
937 LargestArea = Area;
938 }
939 }
940
941 cleanup:
942 if (phMonitorList)
943 ExFreePoolWithTag(phMonitorList, USERTAG_MONITORRECTS);
944 if (prcMonitorList)
945 ExFreePoolWithTag(prcMonitorList, USERTAG_MONITORRECTS);
946 UserLeave();
947
948 return hMonitor;
949 }
950
951
952 HMONITOR
953 APIENTRY
954 NtUserMonitorFromWindow(
955 IN HWND hWnd,
956 IN DWORD dwFlags)
957 {
958 PWND pWnd;
959 HMONITOR hMonitor = NULL;
960 RECTL Rect = {0, 0, 0, 0};
961
962 TRACE("Enter NtUserMonitorFromWindow\n");
963
964 /* Check if flags are valid */
965 if (dwFlags != MONITOR_DEFAULTTONULL &&
966 dwFlags != MONITOR_DEFAULTTOPRIMARY &&
967 dwFlags != MONITOR_DEFAULTTONEAREST)
968 {
969 EngSetLastError(ERROR_INVALID_FLAGS);
970 return NULL;
971 }
972
973 UserEnterShared();
974
975 /* If window is given, use it first */
976 if (hWnd)
977 {
978 /* Get window object */
979 pWnd = UserGetWindowObject(hWnd);
980 if (!pWnd)
981 goto cleanup;
982
983 /* Find only monitors which have intersection with given window */
984 Rect.left = Rect.right = pWnd->rcWindow.left;
985 Rect.top = Rect.bottom = pWnd->rcWindow.bottom;
986 }
987
988 /* Find monitors now */
989 IntGetMonitorsFromRect(&Rect, &hMonitor, NULL, 1, dwFlags);
990
991 cleanup:
992 TRACE("Leave NtUserMonitorFromWindow, ret=%p\n", hMonitor);
993 UserLeave();
994 return hMonitor;
995 }