Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

316 lines
9.6 KiB

  1. /****************************** Module Header ******************************\
  2. * Module Name: multimon.c
  3. *
  4. * Copyright (c) 1985 - 1999, Microsoft Corporation
  5. *
  6. * Multimonitor APIs.
  7. *
  8. * History:
  9. * 27-Sep-1996 adams Stub implementation for NT 5.
  10. * 20-Feb-1997 adams Port from NT4 SP3.
  11. \***************************************************************************/
  12. #include "precomp.h"
  13. #pragma hdrstop
  14. /* last monitor the cursor was clipped to */
  15. PMONITOR gpMonitorMouse;
  16. /***************************************************************************\
  17. * ClipPointToDesktop
  18. *
  19. * Clips the point the nearest monitor on the desktop.
  20. *
  21. * Arguments:
  22. * lppt - The point to clip.
  23. *
  24. * History:
  25. * 22-Sep-1996 adams Created.
  26. * 04-Sep-1998 MCostea Use _MonitorFromPoint()
  27. \***************************************************************************/
  28. void
  29. ClipPointToDesktop(LPPOINT lppt)
  30. {
  31. PMONITOR pMonitor;
  32. UserAssert(!gpDispInfo->fDesktopIsRect &&
  33. "You shouldn't call this function if the desktop is a rectangle.\n"
  34. "Just clip to gpsi->rcScreen instead.");
  35. /*
  36. * Optimization: The cursor is likely to be on the monitor it was last on,
  37. * so check for that case.
  38. */
  39. if (gpMonitorMouse != NULL && PtInRect(&gpMonitorMouse->rcMonitor, *lppt)) {
  40. return;
  41. }
  42. pMonitor = _MonitorFromPoint(*lppt, MONITOR_DEFAULTTONEAREST);
  43. /*
  44. * Remember the monitor the cursor is on.
  45. */
  46. gpMonitorMouse = pMonitor;
  47. if (lppt->x < pMonitor->rcMonitor.left) {
  48. lppt->x = pMonitor->rcMonitor.left;
  49. } else if (lppt->x >= pMonitor->rcMonitor.right) {
  50. lppt->x = pMonitor->rcMonitor.right-1;
  51. }
  52. if (lppt->y < pMonitor->rcMonitor.top) {
  53. lppt->y = pMonitor->rcMonitor.top;
  54. } else if (lppt->y >= pMonitor->rcMonitor.bottom) {
  55. lppt->y = pMonitor->rcMonitor.bottom-1;
  56. }
  57. }
  58. /***************************************************************************\
  59. * xxxEnumDisplayMonitors
  60. *
  61. * Enumerates the monitors in a display.
  62. *
  63. * Arguments:
  64. * hdcPaint - An HDC with a particular visible region. The HDC
  65. * passed to lpfnEnum will have the capabilities of that monitor,
  66. * with its visible region clipped to the monitor and hdcPaint.
  67. * If hdcPaint is NULL, the hdcMonitor passed to lpfnEnum will be NULL.
  68. *
  69. * lprcClip - A rectangle to clip the area to. If hdcPaint is non-NULL,
  70. * the coordinates have the origin of hdcPaint. If hdcPaint is NULL,
  71. * the coordinates are virtual screen coordinates. If lprcClip is NULL,
  72. * no clipping is performed.
  73. *
  74. * lpfnEnum - The enumeration function.
  75. *
  76. * dwData - Application-defined data that is passed through to the
  77. * enumeration function.
  78. *
  79. * fInternal - TRUE if the callback is in the kernel, FALSE otherwise.
  80. *
  81. * History:
  82. * 22-Sep-1996 adams Created.
  83. \***************************************************************************/
  84. BOOL
  85. xxxEnumDisplayMonitors(
  86. HDC hdcPaint,
  87. LPRECT lprcPaint,
  88. MONITORENUMPROC lpfnEnum,
  89. LPARAM lData,
  90. BOOL fInternal)
  91. {
  92. RECT rcPaint;
  93. POINT ptOrg;
  94. RECT rcMonitorPaint;
  95. BOOL fReturn;
  96. PMONITOR pMonitor;
  97. TL tlpMonitor;
  98. PTHREADINFO ptiCurrent = PtiCurrent();
  99. PDCE pdcePaint;
  100. HDC hdcMonitor;
  101. PWND pwndOrg;
  102. /*
  103. * Validate the DC passed in.
  104. */
  105. if (hdcPaint) {
  106. if ((pdcePaint = LookupDC(hdcPaint)) == NULL) {
  107. RIPMSG0(RIP_WARNING, "EnumDisplayMonitors: LookupDC failed");
  108. return FALSE;
  109. }
  110. pwndOrg = pdcePaint->pwndOrg;
  111. /*
  112. * Intersect the painting area with the clipbox. If there
  113. * isn't anything, bail out now.
  114. */
  115. if (GreGetClipBox(hdcPaint, &rcPaint, FALSE) == NULLREGION)
  116. return TRUE;
  117. if (lprcPaint && !IntersectRect(&rcPaint, &rcPaint, lprcPaint))
  118. return TRUE;
  119. /*
  120. * rcPaint is in dc coordinates. We must convert to screen
  121. * coords so we can intersect with monitors.
  122. */
  123. GreGetDCOrg(hdcPaint, &ptOrg);
  124. OffsetRect(&rcPaint, ptOrg.x, ptOrg.y);
  125. } else {
  126. CopyRect(&rcPaint, &gpDispInfo->rcScreen);
  127. if (lprcPaint && !IntersectRect(&rcPaint, &rcPaint, lprcPaint))
  128. return TRUE;
  129. }
  130. fReturn = TRUE;
  131. for (pMonitor = gpDispInfo->pMonitorFirst; pMonitor != NULL;
  132. pMonitor = pMonitor->pMonitorNext) {
  133. /*
  134. * Note: the check for MONF_VISIBLE was removed to allow mirror drivers
  135. * to see monitor specific updates.
  136. */
  137. if (!IntersectRect(&rcMonitorPaint, &rcPaint, &pMonitor->rcMonitor)) {
  138. continue;
  139. }
  140. if (hdcPaint) {
  141. if ((hdcMonitor = GetMonitorDC(pdcePaint, pMonitor)) == NULL) {
  142. RIPMSG0(RIP_WARNING, "EnumDisplayMonitors: GetMonitorDC failed");
  143. return FALSE;
  144. }
  145. OffsetRect(&rcMonitorPaint, -ptOrg.x, -ptOrg.y);
  146. GreIntersectClipRect(
  147. hdcMonitor,
  148. rcMonitorPaint.left,
  149. rcMonitorPaint.top,
  150. rcMonitorPaint.right,
  151. rcMonitorPaint.bottom);
  152. } else {
  153. hdcMonitor = NULL;
  154. }
  155. ThreadLockAlwaysWithPti(ptiCurrent, pMonitor, &tlpMonitor);
  156. if (fInternal) {
  157. fReturn = (*lpfnEnum) (
  158. (HMONITOR) pMonitor,
  159. hdcMonitor,
  160. &rcMonitorPaint,
  161. lData);
  162. } else {
  163. fReturn = xxxClientMonitorEnumProc(
  164. PtoH(pMonitor),
  165. hdcMonitor,
  166. &rcMonitorPaint,
  167. lData,
  168. lpfnEnum);
  169. }
  170. /*
  171. * We just called back and the monitor has been freed if
  172. * ThreadUnlock returns NULL. The entire monitor configuration may
  173. * have changed, the monitors may have been rearranged, so just stop
  174. * enumerating at this point.
  175. */
  176. if (ThreadUnlock(&tlpMonitor) == NULL || HMIsMarkDestroy(pMonitor)) {
  177. /*
  178. * During the callback, pMonitor was destroyed
  179. * so we have to bail out. pMonitor->pNext may also
  180. * have been ruined.
  181. * Windows Bug #488330.
  182. */
  183. RIPMSGF1(RIP_WARNING, "pMonitor %p has been destroyed during the callback",
  184. pMonitor);
  185. #if DBG
  186. {
  187. /*
  188. * Double check to see pMonitor does not
  189. * appear in the monitor list.
  190. */
  191. PMONITOR pMonitorTmp = gpDispInfo->pMonitorFirst;
  192. while (pMonitorTmp) {
  193. UserAssert(pMonitorTmp != pMonitor);
  194. pMonitorTmp = pMonitorTmp->pMonitorNext;
  195. }
  196. }
  197. #endif
  198. fReturn = FALSE;
  199. }
  200. if (hdcMonitor)
  201. ReleaseCacheDC(hdcMonitor, FALSE);
  202. if (!fReturn) {
  203. /*
  204. * Something went wrong, we have to bail out.
  205. */
  206. break;
  207. }
  208. /*
  209. * Revalidate hdcPaint, since it could have been messed with
  210. * in the callback.
  211. */
  212. if (hdcPaint) {
  213. if ((pdcePaint = LookupDC(hdcPaint)) == NULL) {
  214. RIPMSG0(RIP_WARNING, "EnumDisplayMonitors: LookupDC failed");
  215. return FALSE;
  216. }
  217. if (pdcePaint->pwndOrg != pwndOrg) {
  218. RIPMSG0(RIP_WARNING, "EnumDisplayMonitors: wrong window");
  219. return FALSE;
  220. }
  221. }
  222. }
  223. return fReturn;
  224. }
  225. /***************************************************************************\
  226. * DestroyMonitor
  227. *
  228. * This function doesn't keep track of the visible monitors count because
  229. * it assumes that after it was called the count will be recalculated, such
  230. * as the case during mode changes. For a final unlock the monitor will have
  231. * been removed from the monitor list already, so the count doesn't need to
  232. * be recalculated.
  233. *
  234. * 5-May-1998 vadimg created
  235. \***************************************************************************/
  236. void DestroyMonitor(PMONITOR pMonitor)
  237. {
  238. UserAssert(pMonitor);
  239. /*
  240. * Remove references to this monitor from the global data.
  241. */
  242. if (pMonitor == gpMonitorMouse) {
  243. gpMonitorMouse = NULL;
  244. }
  245. /*
  246. * Remove from the monitor list.
  247. */
  248. REMOVE_FROM_LIST(MONITOR, gpDispInfo->pMonitorFirst, pMonitor, pMonitorNext);
  249. /*
  250. * Make sure the primary monitor points to a valid monitor. During the
  251. * mode changes the primary monitor will be recalculated as appropriate.
  252. */
  253. if (pMonitor == gpDispInfo->pMonitorPrimary) {
  254. gpDispInfo->pMonitorPrimary = gpDispInfo->pMonitorFirst;
  255. }
  256. /*
  257. * Clean up the next link here...
  258. */
  259. pMonitor->pMonitorNext = NULL;
  260. /*
  261. * To make sure memory write operations are retired
  262. * before really destroying the monitor object:
  263. */
  264. Win32MemoryBarrier();
  265. if (HMMarkObjectDestroy(pMonitor)) {
  266. if (pMonitor->hrgnMonitor) {
  267. GreDeleteObject(pMonitor->hrgnMonitor);
  268. }
  269. HMFreeObject(pMonitor);
  270. }
  271. }