Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

mmrtl.c

Go to the documentation of this file.
00001 /****************************** Module Header ******************************\ 00002 * Module Name: mmrtl.c 00003 * 00004 * Copyright (c) 1985 - 1999, Microsoft Corporation 00005 * 00006 * Multimonitor APIs. 00007 * 00008 * History: 00009 * 29-Mar-1997 adams Created. 00010 \***************************************************************************/ 00011 00012 #define Int32x32To32(x, y) ((x) * (y)) 00013 00014 /* 00015 * There is no object locking in the client, so the monitor object can 00016 * go away at any time. Therefore to be safe, we need an exception handler. 00017 */ 00018 #ifdef _USERK_ 00019 #define BEGIN_EXCEPTION_HANDLER 00020 #define END_EXCEPTION_HANDLER 00021 #define END_EXCEPTION_HANDLER_EMPTY 00022 #else // _USERK_ 00023 #define BEGIN_EXCEPTION_HANDLER try { 00024 #define END_EXCEPTION_HANDLER \ 00025 } except (W32ExceptionHandler(TRUE, RIP_WARNING)) { \ 00026 pMonitorResult = NULL; \ 00027 } 00028 #define END_EXCEPTION_HANDLER_EMPTY \ 00029 } except (W32ExceptionHandler(TRUE, RIP_WARNING)) { \ 00030 } 00031 #endif // _USERK_ 00032 00033 00034 /***************************************************************************\ 00035 * _MonitorFromPoint 00036 * 00037 * Calculate the monitor that a point is in or is nearest to. 00038 * 00039 * Arguments: 00040 * pt - The point. 00041 * dwFlags - One of: 00042 * MONITOR_DEFAULTTONULL - If the point isn't in a monitor, 00043 * return NULL. 00044 * 00045 * MONITOR_DEFAULTTOPRIMARY - If the point isn't in a monitor, 00046 * return the primary monitor. 00047 * 00048 * MONITOR_DEFAULTTONEAREST - Return the monitor nearest the point. 00049 * 00050 * History: 00051 * 22-Sep-1996 adams Created. 00052 * 29-Mar-1997 adams Moved to rtl. 00053 \***************************************************************************/ 00054 00055 PMONITOR 00056 _MonitorFromPoint(POINT pt, DWORD dwFlags) 00057 { 00058 PMONITOR pMonitor, pMonitorResult; 00059 int dx; 00060 int dy; 00061 00062 UserAssert(dwFlags == MONITOR_DEFAULTTONULL || 00063 dwFlags == MONITOR_DEFAULTTOPRIMARY || 00064 dwFlags == MONITOR_DEFAULTTONEAREST); 00065 00066 if (GetDispInfo()->cMonitors == 1 && dwFlags != MONITOR_DEFAULTTONULL) 00067 return GetPrimaryMonitor(); 00068 00069 switch (dwFlags) { 00070 case MONITOR_DEFAULTTONULL: 00071 case MONITOR_DEFAULTTOPRIMARY: 00072 /* 00073 * Return the monitor the point is in. 00074 */ 00075 00076 BEGIN_EXCEPTION_HANDLER 00077 00078 for ( pMonitor = REBASESHAREDPTRALWAYS(GetDispInfo()->pMonitorFirst); 00079 pMonitor; 00080 pMonitor = REBASESHAREDPTR(pMonitor->pMonitorNext)) { 00081 00082 if (!(pMonitor->dwMONFlags & MONF_VISIBLE)) 00083 continue; 00084 00085 if (PtInRect(&((MONITOR *)pMonitor)->rcMonitor, pt)) { 00086 return pMonitor; 00087 } 00088 } 00089 00090 END_EXCEPTION_HANDLER_EMPTY 00091 00092 /* 00093 * Return what the user wants if it's not found. 00094 */ 00095 switch (dwFlags) { 00096 case MONITOR_DEFAULTTONULL: 00097 return NULL; 00098 00099 case MONITOR_DEFAULTTOPRIMARY: 00100 return GetPrimaryMonitor(); 00101 00102 default: 00103 UserAssertMsg0(FALSE, "Logic error in _MonitorFromPoint"); 00104 break; 00105 } 00106 00107 case MONITOR_DEFAULTTONEAREST: 00108 00109 #define MONITORFROMPOINTALGORITHM(SUMSQUARESMAX, SUMSQUARESTYPE, POINTMULTIPLY) \ 00110 SUMSQUARESTYPE sumsquare; \ 00111 SUMSQUARESTYPE leastsumsquare; \ 00112 leastsumsquare = SUMSQUARESMAX; \ 00113 for ( pMonitor = REBASESHAREDPTRALWAYS(GetDispInfo()->pMonitorFirst); \ 00114 pMonitor; \ 00115 pMonitor = REBASESHAREDPTR(pMonitor->pMonitorNext)) { \ 00116 \ 00117 if (!(pMonitor->dwMONFlags & MONF_VISIBLE)) \ 00118 continue; \ 00119 \ 00120 /* \ 00121 * Determine distance from monitor along x axis. \ 00122 */ \ 00123 if (pt.x < pMonitor->rcMonitor.left) { \ 00124 dx = pMonitor->rcMonitor.left - pt.x; \ 00125 } else if (pt.x < pMonitor->rcMonitor.right) { \ 00126 dx = 0; \ 00127 } else { \ 00128 /* \ 00129 * Monitor rectangles do not include the rightmost edge. \ 00130 */ \ 00131 dx = pt.x - (pMonitor->rcMonitor.right - 1); \ 00132 } \ 00133 \ 00134 /* \ 00135 * Skip this monitor if dx is greater than dx^2 + dy^2. \ 00136 * We do this check to avoid multiplication operations. \ 00137 */ \ 00138 if ((SUMSQUARESTYPE) dx >= leastsumsquare) \ 00139 continue; \ 00140 \ 00141 /* \ 00142 * Determine distance from monitor along y axis. \ 00143 */ \ 00144 if (pt.y < pMonitor->rcMonitor.top) { \ 00145 dy = pMonitor->rcMonitor.top - pt.y; \ 00146 } else if (pt.y < pMonitor->rcMonitor.bottom) { \ 00147 /* \ 00148 * The point is in the monitor and we're done \ 00149 * if both dx and dy are zero. \ 00150 */ \ 00151 if (dx == 0) \ 00152 return pMonitor; \ 00153 \ 00154 dy = 0; \ 00155 } else { \ 00156 dy = pt.y - (pMonitor->rcMonitor.bottom - 1); \ 00157 } \ 00158 \ 00159 /* \ 00160 * Calculate dx^2. Skip this monitor if dx is greater \ 00161 * than dx^2 + dy^2. We do this check to avoid \ 00162 * multiplication operations. \ 00163 */ \ 00164 sumsquare = POINTMULTIPLY(dx, dx); \ 00165 if (sumsquare >= leastsumsquare) \ 00166 continue; \ 00167 \ 00168 /* \ 00169 * Skip this monitor if dx^2 + y is greater than dx^2 + dy^2. \ 00170 * We do this check to avoid multiplication operations. \ 00171 */ \ 00172 if (sumsquare + (SUMSQUARESTYPE) dy >= leastsumsquare) \ 00173 continue; \ 00174 \ 00175 /* \ 00176 * Compute dx^2 + dy^2. Skip this monitor if it's not the least. \ 00177 */ \ 00178 sumsquare += (SUMSQUARESTYPE) POINTMULTIPLY(dy, dy); \ 00179 if (sumsquare >= leastsumsquare) \ 00180 continue; \ 00181 \ 00182 /* \ 00183 * This is the closest monitor so far. \ 00184 */ \ 00185 leastsumsquare = sumsquare; \ 00186 pMonitorResult = pMonitor; \ 00187 } 00188 00189 #if DBG 00190 pMonitorResult = (PMONITOR) -1; 00191 #endif 00192 00193 if ( pt.x < SHRT_MIN || SHRT_MAX < pt.x || 00194 pt.y < SHRT_MIN || SHRT_MAX < pt.y) { 00195 00196 BEGIN_EXCEPTION_HANDLER 00197 MONITORFROMPOINTALGORITHM(_UI64_MAX, ULONGLONG, Int32x32To64) 00198 END_EXCEPTION_HANDLER 00199 00200 } else { 00201 00202 BEGIN_EXCEPTION_HANDLER 00203 MONITORFROMPOINTALGORITHM(UINT_MAX, UINT, Int32x32To32) 00204 END_EXCEPTION_HANDLER 00205 00206 } 00207 00208 UserAssert(pMonitorResult != (PMONITOR) -1); 00209 return pMonitorResult; 00210 00211 default: 00212 UserAssert(0 && "Logic error in _MonitorFromPoint, shouldn't have gotten here."); 00213 break; 00214 } 00215 00216 UserAssert(0 && "Logic error in _MonitorFromPoint, shouldn't have gotten here."); 00217 return NULL; 00218 } 00219 00220 00221 00222 /***************************************************************************\ 00223 * _MonitorFromRect 00224 * 00225 * Calculate the monitor that a rect is in or is nearest to. 00226 * 00227 * Arguments: 00228 * lprc - The rect. 00229 * dwFlags - One of: 00230 * MONITOR_DEFAULTTONULL - If the rect doesn't intersect a monitor, 00231 * return NULL. 00232 * 00233 * MONITOR_DEFAULTTOPRIMARY - If the rect doesn't intersect a monitor, 00234 * return the primary monitor. 00235 * 00236 * MONITOR_DEFAULTTONEAREST - Return the monitor nearest the rect. 00237 * 00238 * History: 00239 * 22-Sep-1996 adams Created. 00240 * 29-Mar-1997 adams Moved to rtl. 00241 \***************************************************************************/ 00242 00243 PMONITOR 00244 _MonitorFromRect(LPCRECT lprc, DWORD dwFlags) 00245 { 00246 PDISPLAYINFO pDispInfo; 00247 PMONITOR pMonitor, pMonitorResult; 00248 RECT rc; 00249 int area, areaMost; 00250 00251 UserAssert(dwFlags == MONITOR_DEFAULTTONULL || 00252 dwFlags == MONITOR_DEFAULTTOPRIMARY || 00253 dwFlags == MONITOR_DEFAULTTONEAREST); 00254 00255 /* 00256 * Special case the most common case - 1 monitor. 00257 */ 00258 pDispInfo = GetDispInfo(); 00259 if (pDispInfo->cMonitors == 1 && dwFlags != MONITOR_DEFAULTTONULL) 00260 return GetPrimaryMonitor(); 00261 00262 /* 00263 * If rect is empty, use topleft point. 00264 */ 00265 if (IsRectEmpty(lprc)) { 00266 return _MonitorFromPoint(*(LPPOINT)lprc, dwFlags); 00267 } 00268 00269 /* 00270 * Return the primary monitor if the rectangle covers the desktop. 00271 */ 00272 if ( lprc->left <= pDispInfo->rcScreen.left && 00273 lprc->top <= pDispInfo->rcScreen.top && 00274 lprc->right >= pDispInfo->rcScreen.right && 00275 lprc->bottom >= pDispInfo->rcScreen.bottom) { 00276 00277 return GetPrimaryMonitor(); 00278 } 00279 00280 /* 00281 * Calculate the nearest rectangle by determining which 00282 * monitor has the greatest intersection with the rectangle. 00283 */ 00284 00285 BEGIN_EXCEPTION_HANDLER 00286 00287 areaMost = 0; 00288 for ( pMonitor = REBASESHAREDPTRALWAYS(GetDispInfo()->pMonitorFirst); 00289 pMonitor; 00290 pMonitor = REBASESHAREDPTR(pMonitor->pMonitorNext)) { 00291 00292 if (!(pMonitor->dwMONFlags & MONF_VISIBLE)) 00293 continue; 00294 00295 if (IntersectRect(&rc, lprc, &((MONITOR *)pMonitor)->rcMonitor)) { 00296 if (EqualRect(&rc, lprc)) 00297 return pMonitor; 00298 00299 /* 00300 * Calculate the area of the intersection. Note that 00301 * the intersection must be in 16bit coordinats, since 00302 * we limit monitor rects to 16bit coordinate space. 00303 * So the result of any area calculation will fit in 00304 * in an int. 00305 */ 00306 area = (rc.right - rc.left) * (rc.bottom - rc.top); 00307 if (area > areaMost) { 00308 areaMost = area; 00309 pMonitorResult = pMonitor; 00310 } 00311 } 00312 } 00313 00314 END_EXCEPTION_HANDLER 00315 00316 UserAssert(areaMost >= 0); 00317 if (areaMost > 0) 00318 return pMonitorResult; 00319 00320 00321 switch (dwFlags) { 00322 case MONITOR_DEFAULTTONULL: 00323 return NULL; 00324 00325 case MONITOR_DEFAULTTOPRIMARY: 00326 return GetPrimaryMonitor(); 00327 00328 case MONITOR_DEFAULTTONEAREST: 00329 { 00330 int dx, dy; 00331 00332 #define MONITORFROMRECTALGORITHM(SUMSQUARESMAX, SUMSQUARESTYPE, POINTMULTIPLY) \ 00333 SUMSQUARESTYPE sumsquare; \ 00334 SUMSQUARESTYPE leastsumsquare; \ 00335 leastsumsquare = SUMSQUARESMAX; \ 00336 for ( pMonitor = REBASESHAREDPTRALWAYS(GetDispInfo()->pMonitorFirst); \ 00337 pMonitor; \ 00338 pMonitor = REBASESHAREDPTR(pMonitor->pMonitorNext)) { \ 00339 \ 00340 if (!(pMonitor->dwMONFlags & MONF_VISIBLE)) \ 00341 continue; \ 00342 \ 00343 /* \ 00344 * Determine distance from monitor along x axis. \ 00345 */ \ 00346 if (lprc->right <= pMonitor->rcMonitor.left) { \ 00347 /* \ 00348 * Add 1 because rectangles do not include the rightmost edge. \ 00349 */ \ 00350 dx = pMonitor->rcMonitor.left - lprc->right + 1; \ 00351 } else if (lprc->left < pMonitor->rcMonitor.right) { \ 00352 dx = 0; \ 00353 } else { \ 00354 /* \ 00355 * Add 1 because rectangles do not include the rightmost edge. \ 00356 */ \ 00357 dx = lprc->left - (pMonitor->rcMonitor.right - 1); \ 00358 } \ 00359 \ 00360 /* \ 00361 * Skip this monitor if dx is greater than dx^2 + dy^2. \ 00362 * We do this check to avoid multiplication operations. \ 00363 */ \ 00364 if ((SUMSQUARESTYPE) dx >= leastsumsquare) \ 00365 continue; \ 00366 \ 00367 /* \ 00368 * Determine distance from monitor along y axis. \ 00369 */ \ 00370 if (lprc->bottom <= pMonitor->rcMonitor.top) { \ 00371 /* \ 00372 * Add 1 because rectangles do not include the bottommost edge. \ 00373 */ \ 00374 dy = pMonitor->rcMonitor.top - lprc->bottom + 1; \ 00375 } else if (lprc->top < pMonitor->rcMonitor.bottom) { \ 00376 UserAssert(dx != 0 && "This rectangle intersects a monitor, so we shouldn't be here."); \ 00377 dy = 0; \ 00378 } else { \ 00379 /* \ 00380 * Add 1 because rectangles do not include the bottommost edge. \ 00381 */ \ 00382 dy = lprc->top - pMonitor->rcMonitor.bottom + 1; \ 00383 } \ 00384 \ 00385 /* \ 00386 * Calculate dx^2. Skip this monitor if dx is greater \ 00387 * than dx^2 + dy^2. We do this check to avoid \ 00388 * multiplication operations. \ 00389 */ \ 00390 sumsquare = POINTMULTIPLY(dx, dx); \ 00391 if (sumsquare >= leastsumsquare) \ 00392 continue; \ 00393 \ 00394 /* \ 00395 * Skip this monitor if dx^2 + y is greater than dx^2 + dy^2. \ 00396 * We do this check to avoid multiplication operations. \ 00397 */ \ 00398 if (sumsquare + (SUMSQUARESTYPE) dy >= leastsumsquare) \ 00399 continue; \ 00400 \ 00401 /* \ 00402 * Compute dx^2 + dy^2. Skip this monitor if it's not the least. \ 00403 */ \ 00404 sumsquare += (SUMSQUARESTYPE) POINTMULTIPLY(dy, dy); \ 00405 if (sumsquare >= leastsumsquare) \ 00406 continue; \ 00407 \ 00408 /* \ 00409 * This is the closest monitor so far. \ 00410 */ \ 00411 leastsumsquare = sumsquare; \ 00412 pMonitorResult = pMonitor; \ 00413 } 00414 00415 #if DBG 00416 pMonitorResult = (PMONITOR) -1; 00417 #endif 00418 00419 if ( lprc->left < SHRT_MIN || SHRT_MAX < lprc->left || 00420 lprc->top < SHRT_MIN || SHRT_MAX < lprc->top || 00421 lprc->right < SHRT_MIN || SHRT_MAX < lprc->right || 00422 lprc->bottom < SHRT_MIN || SHRT_MAX < lprc->bottom) { 00423 00424 BEGIN_EXCEPTION_HANDLER 00425 MONITORFROMRECTALGORITHM(_UI64_MAX, ULONGLONG, Int32x32To64) 00426 END_EXCEPTION_HANDLER 00427 00428 } else { 00429 00430 BEGIN_EXCEPTION_HANDLER 00431 MONITORFROMRECTALGORITHM(UINT_MAX, UINT, Int32x32To32) 00432 END_EXCEPTION_HANDLER 00433 00434 } 00435 00436 UserAssert(pMonitorResult != (PMONITOR) -1); 00437 return pMonitorResult; 00438 } 00439 00440 default: 00441 UserAssertMsg0(0, "Logic error in _MonitorFromWindow, shouldn't have gotten here."); 00442 break; 00443 } 00444 00445 UserAssertMsg0(0, "Logic error in _MonitorFromWindow, shouldn't have gotten here."); 00446 return NULL; 00447 } 00448 00449 00450 00451 /***************************************************************************\ 00452 * _MonitorFromWindow 00453 * 00454 * Calculate the monitor that a window is in or is nearest to. We use 00455 * the center of the window to determine its location. If the window 00456 * is minimized, use its normal position. 00457 * 00458 * Arguments: 00459 * pwnd - The window. 00460 * dwFlags - One of: 00461 * MONITOR_DEFAULTTONULL - If the window doesn't intersect a monitor, 00462 * return NULL. 00463 * 00464 * MONITOR_DEFAULTTOPRIMARY - If the window doesn't intersect a monitor, 00465 * return the primary monitor. 00466 * 00467 * MONITOR_DEFAULTTONEAREST - Return the monitor nearest the window. 00468 * 00469 * History: 00470 * 22-Sep-1996 adams Created. 00471 * 29-Mar-1997 adams Moved to rtl. 00472 \***************************************************************************/ 00473 00474 PMONITOR 00475 _MonitorFromWindow(PWND pwnd, DWORD dwFlags) 00476 { 00477 PWND pwndParent; 00478 00479 UserAssert(dwFlags == MONITOR_DEFAULTTONULL || 00480 dwFlags == MONITOR_DEFAULTTOPRIMARY || 00481 dwFlags == MONITOR_DEFAULTTONEAREST); 00482 00483 if (GetDispInfo()->cMonitors == 1 && dwFlags != MONITOR_DEFAULTTONULL) { 00484 return GetPrimaryMonitor(); 00485 } 00486 00487 if (!pwnd) 00488 goto NoWindow; 00489 00490 /* 00491 * Handle minimized windows. 00492 */ 00493 if (TestWF(pwnd, WFMINIMIZED)) 00494 { 00495 #ifdef _USERK_ 00496 CHECKPOINT * pcp; 00497 00498 pcp = (CHECKPOINT *)_GetProp(pwnd, PROP_CHECKPOINT, PROPF_INTERNAL); 00499 if (pcp) { 00500 return _MonitorFromRect(&pcp->rcNormal, dwFlags); 00501 } 00502 #else 00503 WINDOWPLACEMENT wp; 00504 HWND hwnd; 00505 00506 wp.length = sizeof(wp); 00507 hwnd = (HWND)PtoH(pwnd); 00508 if (GetWindowPlacement(hwnd, &wp)) { 00509 return _MonitorFromRect(&wp.rcNormalPosition, dwFlags); 00510 } 00511 00512 /* 00513 * (adams) If GetWindowPlacement fails, then either there was not enough 00514 * memory to allocate a CHECKPOINT, or the window was destroyed 00515 * and the API failed. If the later, the following code my be 00516 * playing with invalid memory. Although on the client side we 00517 * can never guarantee that a window is valid, it seems especially 00518 * likely that it is invalid here. So do another revalidation 00519 * by calling IsWindow. 00520 */ 00521 if (!IsWindow(hwnd)) 00522 goto NoWindow; 00523 #endif 00524 00525 UserAssert(GETFNID(pwnd) != FNID_DESKTOP); 00526 pwndParent = REBASEPWND(pwnd, spwndParent); 00527 if (GETFNID(pwndParent) == FNID_DESKTOP) { 00528 return GetPrimaryMonitor(); 00529 } 00530 00531 /* 00532 * Otherwise, if we are a child window, fall thru below to use the 00533 * window rect, which actually means something for non-toplevel dudes. 00534 */ 00535 } 00536 00537 return _MonitorFromRect(&((WND *)pwnd)->rcWindow, dwFlags); 00538 00539 NoWindow: 00540 if (dwFlags & (MONITOR_DEFAULTTOPRIMARY | MONITOR_DEFAULTTONEAREST)) { 00541 return GetPrimaryMonitor(); 00542 } 00543 00544 return NULL; 00545 }

Generated on Sat May 15 19:40:50 2004 for test by doxygen 1.3.7