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.

545 lines
25 KiB

  1. /****************************** Module Header ******************************\
  2. * Module Name: mmrtl.c
  3. *
  4. * Copyright (c) 1985 - 1999, Microsoft Corporation
  5. *
  6. * Multimonitor APIs.
  7. *
  8. * History:
  9. * 29-Mar-1997 adams Created.
  10. \***************************************************************************/
  11. #define Int32x32To32(x, y) ((x) * (y))
  12. /*
  13. * There is no object locking in the client, so the monitor object can
  14. * go away at any time. Therefore to be safe, we need an exception handler.
  15. */
  16. #ifdef _USERK_
  17. #define BEGIN_EXCEPTION_HANDLER
  18. #define END_EXCEPTION_HANDLER
  19. #define END_EXCEPTION_HANDLER_EMPTY
  20. #else // _USERK_
  21. #define BEGIN_EXCEPTION_HANDLER try {
  22. #define END_EXCEPTION_HANDLER \
  23. } except (W32ExceptionHandler(TRUE, RIP_WARNING)) { \
  24. pMonitorResult = NULL; \
  25. }
  26. #define END_EXCEPTION_HANDLER_EMPTY \
  27. } except (W32ExceptionHandler(TRUE, RIP_WARNING)) { \
  28. }
  29. #endif // _USERK_
  30. /***************************************************************************\
  31. * _MonitorFromPoint
  32. *
  33. * Calculate the monitor that a point is in or is nearest to.
  34. *
  35. * Arguments:
  36. * pt - The point.
  37. * dwFlags - One of:
  38. * MONITOR_DEFAULTTONULL - If the point isn't in a monitor,
  39. * return NULL.
  40. *
  41. * MONITOR_DEFAULTTOPRIMARY - If the point isn't in a monitor,
  42. * return the primary monitor.
  43. *
  44. * MONITOR_DEFAULTTONEAREST - Return the monitor nearest the point.
  45. *
  46. * History:
  47. * 22-Sep-1996 adams Created.
  48. * 29-Mar-1997 adams Moved to rtl.
  49. \***************************************************************************/
  50. PMONITOR
  51. _MonitorFromPoint(POINT pt, DWORD dwFlags)
  52. {
  53. PMONITOR pMonitor, pMonitorResult;
  54. int dx;
  55. int dy;
  56. UserAssert(dwFlags == MONITOR_DEFAULTTONULL ||
  57. dwFlags == MONITOR_DEFAULTTOPRIMARY ||
  58. dwFlags == MONITOR_DEFAULTTONEAREST);
  59. if (GetDispInfo()->cMonitors == 1 && dwFlags != MONITOR_DEFAULTTONULL)
  60. return GetPrimaryMonitor();
  61. switch (dwFlags) {
  62. case MONITOR_DEFAULTTONULL:
  63. case MONITOR_DEFAULTTOPRIMARY:
  64. /*
  65. * Return the monitor the point is in.
  66. */
  67. BEGIN_EXCEPTION_HANDLER
  68. for ( pMonitor = REBASESHAREDPTRALWAYS(GetDispInfo()->pMonitorFirst);
  69. pMonitor;
  70. pMonitor = REBASESHAREDPTR(pMonitor->pMonitorNext)) {
  71. if (!(pMonitor->dwMONFlags & MONF_VISIBLE))
  72. continue;
  73. if (PtInRect(KPRECT_TO_PRECT(&pMonitor->rcMonitor), pt)) {
  74. return pMonitor;
  75. }
  76. }
  77. END_EXCEPTION_HANDLER_EMPTY
  78. /*
  79. * Return what the user wants if it's not found.
  80. */
  81. switch (dwFlags) {
  82. case MONITOR_DEFAULTTONULL:
  83. return NULL;
  84. case MONITOR_DEFAULTTOPRIMARY:
  85. return GetPrimaryMonitor();
  86. default:
  87. UserAssertMsg0(FALSE, "Logic error in _MonitorFromPoint");
  88. break;
  89. }
  90. case MONITOR_DEFAULTTONEAREST:
  91. #define MONITORFROMPOINTALGORITHM(SUMSQUARESMAX, SUMSQUARESTYPE, POINTMULTIPLY) \
  92. SUMSQUARESTYPE sumsquare; \
  93. SUMSQUARESTYPE leastsumsquare; \
  94. leastsumsquare = SUMSQUARESMAX; \
  95. for ( pMonitor = REBASESHAREDPTRALWAYS(GetDispInfo()->pMonitorFirst); \
  96. pMonitor; \
  97. pMonitor = REBASESHAREDPTR(pMonitor->pMonitorNext)) { \
  98. \
  99. if (!(pMonitor->dwMONFlags & MONF_VISIBLE)) \
  100. continue; \
  101. \
  102. /* \
  103. * Determine distance from monitor along x axis. \
  104. */ \
  105. if (pt.x < pMonitor->rcMonitor.left) { \
  106. dx = pMonitor->rcMonitor.left - pt.x; \
  107. } else if (pt.x < pMonitor->rcMonitor.right) { \
  108. dx = 0; \
  109. } else { \
  110. /* \
  111. * Monitor rectangles do not include the rightmost edge. \
  112. */ \
  113. dx = pt.x - (pMonitor->rcMonitor.right - 1); \
  114. } \
  115. \
  116. /* \
  117. * Skip this monitor if dx is greater than dx^2 + dy^2. \
  118. * We do this check to avoid multiplication operations. \
  119. */ \
  120. if ((SUMSQUARESTYPE) dx >= leastsumsquare) \
  121. continue; \
  122. \
  123. /* \
  124. * Determine distance from monitor along y axis. \
  125. */ \
  126. if (pt.y < pMonitor->rcMonitor.top) { \
  127. dy = pMonitor->rcMonitor.top - pt.y; \
  128. } else if (pt.y < pMonitor->rcMonitor.bottom) { \
  129. /* \
  130. * The point is in the monitor and we're done \
  131. * if both dx and dy are zero. \
  132. */ \
  133. if (dx == 0) \
  134. return pMonitor; \
  135. \
  136. dy = 0; \
  137. } else { \
  138. dy = pt.y - (pMonitor->rcMonitor.bottom - 1); \
  139. } \
  140. \
  141. /* \
  142. * Calculate dx^2. Skip this monitor if dx is greater \
  143. * than dx^2 + dy^2. We do this check to avoid \
  144. * multiplication operations. \
  145. */ \
  146. sumsquare = POINTMULTIPLY(dx, dx); \
  147. if (sumsquare >= leastsumsquare) \
  148. continue; \
  149. \
  150. /* \
  151. * Skip this monitor if dx^2 + y is greater than dx^2 + dy^2. \
  152. * We do this check to avoid multiplication operations. \
  153. */ \
  154. if (sumsquare + (SUMSQUARESTYPE) dy >= leastsumsquare) \
  155. continue; \
  156. \
  157. /* \
  158. * Compute dx^2 + dy^2. Skip this monitor if it's not the least. \
  159. */ \
  160. sumsquare += (SUMSQUARESTYPE) POINTMULTIPLY(dy, dy); \
  161. if (sumsquare >= leastsumsquare) \
  162. continue; \
  163. \
  164. /* \
  165. * This is the closest monitor so far. \
  166. */ \
  167. leastsumsquare = sumsquare; \
  168. pMonitorResult = pMonitor; \
  169. }
  170. #if DBG
  171. pMonitorResult = (PMONITOR) -1;
  172. #endif
  173. if ( pt.x < SHRT_MIN || SHRT_MAX < pt.x ||
  174. pt.y < SHRT_MIN || SHRT_MAX < pt.y) {
  175. BEGIN_EXCEPTION_HANDLER
  176. MONITORFROMPOINTALGORITHM(_UI64_MAX, ULONGLONG, Int32x32To64)
  177. END_EXCEPTION_HANDLER
  178. } else {
  179. BEGIN_EXCEPTION_HANDLER
  180. MONITORFROMPOINTALGORITHM(UINT_MAX, UINT, Int32x32To32)
  181. END_EXCEPTION_HANDLER
  182. }
  183. UserAssert(pMonitorResult != (PMONITOR) -1);
  184. return pMonitorResult;
  185. default:
  186. UserAssert(0 && "Logic error in _MonitorFromPoint, shouldn't have gotten here.");
  187. break;
  188. }
  189. UserAssert(0 && "Logic error in _MonitorFromPoint, shouldn't have gotten here.");
  190. return NULL;
  191. }
  192. /***************************************************************************\
  193. * _MonitorFromRect
  194. *
  195. * Calculate the monitor that a rect is in or is nearest to.
  196. *
  197. * Arguments:
  198. * lprc - The rect.
  199. * dwFlags - One of:
  200. * MONITOR_DEFAULTTONULL - If the rect doesn't intersect a monitor,
  201. * return NULL.
  202. *
  203. * MONITOR_DEFAULTTOPRIMARY - If the rect doesn't intersect a monitor,
  204. * return the primary monitor.
  205. *
  206. * MONITOR_DEFAULTTONEAREST - Return the monitor nearest the rect.
  207. *
  208. * History:
  209. * 22-Sep-1996 adams Created.
  210. * 29-Mar-1997 adams Moved to rtl.
  211. \***************************************************************************/
  212. PMONITOR
  213. _MonitorFromRect(LPCRECT lprc, DWORD dwFlags)
  214. {
  215. PDISPLAYINFO pDispInfo;
  216. PMONITOR pMonitor, pMonitorResult;
  217. RECT rc;
  218. int area, areaMost;
  219. UserAssert(dwFlags == MONITOR_DEFAULTTONULL ||
  220. dwFlags == MONITOR_DEFAULTTOPRIMARY ||
  221. dwFlags == MONITOR_DEFAULTTONEAREST);
  222. /*
  223. * Special case the most common case - 1 monitor.
  224. */
  225. pDispInfo = GetDispInfo();
  226. if (pDispInfo->cMonitors == 1 && dwFlags != MONITOR_DEFAULTTONULL)
  227. return GetPrimaryMonitor();
  228. /*
  229. * If rect is empty, use topleft point.
  230. */
  231. if (IsRectEmpty(lprc)) {
  232. return _MonitorFromPoint(*(LPPOINT)lprc, dwFlags);
  233. }
  234. /*
  235. * Return the primary monitor if the rectangle covers the desktop.
  236. */
  237. if ( lprc->left <= pDispInfo->rcScreen.left &&
  238. lprc->top <= pDispInfo->rcScreen.top &&
  239. lprc->right >= pDispInfo->rcScreen.right &&
  240. lprc->bottom >= pDispInfo->rcScreen.bottom) {
  241. return GetPrimaryMonitor();
  242. }
  243. /*
  244. * Calculate the nearest rectangle by determining which
  245. * monitor has the greatest intersection with the rectangle.
  246. */
  247. BEGIN_EXCEPTION_HANDLER
  248. areaMost = 0;
  249. for ( pMonitor = REBASESHAREDPTRALWAYS(GetDispInfo()->pMonitorFirst);
  250. pMonitor;
  251. pMonitor = REBASESHAREDPTR(pMonitor->pMonitorNext)) {
  252. if (!(pMonitor->dwMONFlags & MONF_VISIBLE))
  253. continue;
  254. if (IntersectRect(&rc, lprc, KPRECT_TO_PRECT(&pMonitor->rcMonitor))) {
  255. if (EqualRect(&rc, lprc))
  256. return pMonitor;
  257. /*
  258. * Calculate the area of the intersection. Note that
  259. * the intersection must be in 16bit coordinats, since
  260. * we limit monitor rects to 16bit coordinate space.
  261. * So the result of any area calculation will fit in
  262. * in an int.
  263. */
  264. area = (rc.right - rc.left) * (rc.bottom - rc.top);
  265. if (area > areaMost) {
  266. areaMost = area;
  267. pMonitorResult = pMonitor;
  268. }
  269. }
  270. }
  271. END_EXCEPTION_HANDLER
  272. UserAssert(areaMost >= 0);
  273. if (areaMost > 0)
  274. return pMonitorResult;
  275. switch (dwFlags) {
  276. case MONITOR_DEFAULTTONULL:
  277. return NULL;
  278. case MONITOR_DEFAULTTOPRIMARY:
  279. return GetPrimaryMonitor();
  280. case MONITOR_DEFAULTTONEAREST:
  281. {
  282. int dx, dy;
  283. #define MONITORFROMRECTALGORITHM(SUMSQUARESMAX, SUMSQUARESTYPE, POINTMULTIPLY) \
  284. SUMSQUARESTYPE sumsquare; \
  285. SUMSQUARESTYPE leastsumsquare; \
  286. leastsumsquare = SUMSQUARESMAX; \
  287. for ( pMonitor = REBASESHAREDPTRALWAYS(GetDispInfo()->pMonitorFirst); \
  288. pMonitor; \
  289. pMonitor = REBASESHAREDPTR(pMonitor->pMonitorNext)) { \
  290. \
  291. if (!(pMonitor->dwMONFlags & MONF_VISIBLE)) \
  292. continue; \
  293. \
  294. /* \
  295. * Determine distance from monitor along x axis. \
  296. */ \
  297. if (lprc->right <= pMonitor->rcMonitor.left) { \
  298. /* \
  299. * Add 1 because rectangles do not include the rightmost edge. \
  300. */ \
  301. dx = pMonitor->rcMonitor.left - lprc->right + 1; \
  302. } else if (lprc->left < pMonitor->rcMonitor.right) { \
  303. dx = 0; \
  304. } else { \
  305. /* \
  306. * Add 1 because rectangles do not include the rightmost edge. \
  307. */ \
  308. dx = lprc->left - (pMonitor->rcMonitor.right - 1); \
  309. } \
  310. \
  311. /* \
  312. * Skip this monitor if dx is greater than dx^2 + dy^2. \
  313. * We do this check to avoid multiplication operations. \
  314. */ \
  315. if ((SUMSQUARESTYPE) dx >= leastsumsquare) \
  316. continue; \
  317. \
  318. /* \
  319. * Determine distance from monitor along y axis. \
  320. */ \
  321. if (lprc->bottom <= pMonitor->rcMonitor.top) { \
  322. /* \
  323. * Add 1 because rectangles do not include the bottommost edge. \
  324. */ \
  325. dy = pMonitor->rcMonitor.top - lprc->bottom + 1; \
  326. } else if (lprc->top < pMonitor->rcMonitor.bottom) { \
  327. UserAssert(dx != 0 && "This rectangle intersects a monitor, so we shouldn't be here."); \
  328. dy = 0; \
  329. } else { \
  330. /* \
  331. * Add 1 because rectangles do not include the bottommost edge. \
  332. */ \
  333. dy = lprc->top - pMonitor->rcMonitor.bottom + 1; \
  334. } \
  335. \
  336. /* \
  337. * Calculate dx^2. Skip this monitor if dx is greater \
  338. * than dx^2 + dy^2. We do this check to avoid \
  339. * multiplication operations. \
  340. */ \
  341. sumsquare = POINTMULTIPLY(dx, dx); \
  342. if (sumsquare >= leastsumsquare) \
  343. continue; \
  344. \
  345. /* \
  346. * Skip this monitor if dx^2 + y is greater than dx^2 + dy^2. \
  347. * We do this check to avoid multiplication operations. \
  348. */ \
  349. if (sumsquare + (SUMSQUARESTYPE) dy >= leastsumsquare) \
  350. continue; \
  351. \
  352. /* \
  353. * Compute dx^2 + dy^2. Skip this monitor if it's not the least. \
  354. */ \
  355. sumsquare += (SUMSQUARESTYPE) POINTMULTIPLY(dy, dy); \
  356. if (sumsquare >= leastsumsquare) \
  357. continue; \
  358. \
  359. /* \
  360. * This is the closest monitor so far. \
  361. */ \
  362. leastsumsquare = sumsquare; \
  363. pMonitorResult = pMonitor; \
  364. }
  365. #if DBG
  366. pMonitorResult = (PMONITOR) -1;
  367. #endif
  368. if ( lprc->left < SHRT_MIN || SHRT_MAX < lprc->left ||
  369. lprc->top < SHRT_MIN || SHRT_MAX < lprc->top ||
  370. lprc->right < SHRT_MIN || SHRT_MAX < lprc->right ||
  371. lprc->bottom < SHRT_MIN || SHRT_MAX < lprc->bottom) {
  372. BEGIN_EXCEPTION_HANDLER
  373. MONITORFROMRECTALGORITHM(_UI64_MAX, ULONGLONG, Int32x32To64)
  374. END_EXCEPTION_HANDLER
  375. } else {
  376. BEGIN_EXCEPTION_HANDLER
  377. MONITORFROMRECTALGORITHM(UINT_MAX, UINT, Int32x32To32)
  378. END_EXCEPTION_HANDLER
  379. }
  380. UserAssert(pMonitorResult != (PMONITOR) -1);
  381. return pMonitorResult;
  382. }
  383. default:
  384. UserAssertMsg0(0, "Logic error in _MonitorFromWindow, shouldn't have gotten here.");
  385. break;
  386. }
  387. UserAssertMsg0(0, "Logic error in _MonitorFromWindow, shouldn't have gotten here.");
  388. return NULL;
  389. }
  390. /***************************************************************************\
  391. * _MonitorFromWindow
  392. *
  393. * Calculate the monitor that a window is in or is nearest to. We use
  394. * the center of the window to determine its location. If the window
  395. * is minimized, use its normal position.
  396. *
  397. * Arguments:
  398. * pwnd - The window.
  399. * dwFlags - One of:
  400. * MONITOR_DEFAULTTONULL - If the window doesn't intersect a monitor,
  401. * return NULL.
  402. *
  403. * MONITOR_DEFAULTTOPRIMARY - If the window doesn't intersect a monitor,
  404. * return the primary monitor.
  405. *
  406. * MONITOR_DEFAULTTONEAREST - Return the monitor nearest the window.
  407. *
  408. * History:
  409. * 22-Sep-1996 adams Created.
  410. * 29-Mar-1997 adams Moved to rtl.
  411. \***************************************************************************/
  412. PMONITOR
  413. _MonitorFromWindow(PWND pwnd, DWORD dwFlags)
  414. {
  415. PWND pwndParent;
  416. UserAssert(dwFlags == MONITOR_DEFAULTTONULL ||
  417. dwFlags == MONITOR_DEFAULTTOPRIMARY ||
  418. dwFlags == MONITOR_DEFAULTTONEAREST);
  419. if (GetDispInfo()->cMonitors == 1 && dwFlags != MONITOR_DEFAULTTONULL) {
  420. return GetPrimaryMonitor();
  421. }
  422. if (!pwnd)
  423. goto NoWindow;
  424. /*
  425. * Handle minimized windows.
  426. */
  427. if (TestWF(pwnd, WFMINIMIZED))
  428. {
  429. #ifdef _USERK_
  430. CHECKPOINT * pcp;
  431. pcp = (CHECKPOINT *)_GetProp(pwnd, PROP_CHECKPOINT, PROPF_INTERNAL);
  432. if (pcp) {
  433. return _MonitorFromRect(&pcp->rcNormal, dwFlags);
  434. }
  435. #else
  436. WINDOWPLACEMENT wp;
  437. HWND hwnd;
  438. wp.length = sizeof(wp);
  439. hwnd = (HWND)PtoH(pwnd);
  440. if (GetWindowPlacement(hwnd, &wp)) {
  441. return _MonitorFromRect(&wp.rcNormalPosition, dwFlags);
  442. }
  443. /*
  444. * (adams) If GetWindowPlacement fails, then either there was not enough
  445. * memory to allocate a CHECKPOINT, or the window was destroyed
  446. * and the API failed. If the later, the following code my be
  447. * playing with invalid memory. Although on the client side we
  448. * can never guarantee that a window is valid, it seems especially
  449. * likely that it is invalid here. So do another revalidation
  450. * by calling IsWindow.
  451. */
  452. if (!IsWindow(hwnd))
  453. goto NoWindow;
  454. #endif
  455. UserAssert(GETFNID(pwnd) != FNID_DESKTOP);
  456. pwndParent = REBASEPWND(pwnd, spwndParent);
  457. if (GETFNID(pwndParent) == FNID_DESKTOP) {
  458. return GetPrimaryMonitor();
  459. }
  460. /*
  461. * Otherwise, if we are a child window, fall thru below to use the
  462. * window rect, which actually means something for non-toplevel dudes.
  463. */
  464. }
  465. return _MonitorFromRect(KPRECT_TO_PRECT(&pwnd->rcWindow), dwFlags);
  466. NoWindow:
  467. if (dwFlags & (MONITOR_DEFAULTTOPRIMARY | MONITOR_DEFAULTTONEAREST)) {
  468. return GetPrimaryMonitor();
  469. }
  470. return NULL;
  471. }