1/* 2 *Copyright (C) 2001-2004 Harold L Hunt II All Rights Reserved. 3 * 4 *Permission is hereby granted, free of charge, to any person obtaining 5 * a copy of this software and associated documentation files (the 6 *"Software"), to deal in the Software without restriction, including 7 *without limitation the rights to use, copy, modify, merge, publish, 8 *distribute, sublicense, and/or sell copies of the Software, and to 9 *permit persons to whom the Software is furnished to do so, subject to 10 *the following conditions: 11 * 12 *The above copyright notice and this permission notice shall be 13 *included in all copies or substantial portions of the Software. 14 * 15 *THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 *EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 *MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 *NONINFRINGEMENT. IN NO EVENT SHALL HAROLD L HUNT II BE LIABLE FOR 19 *ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 20 *CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 *WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 * 23 *Except as contained in this notice, the name of Harold L Hunt II 24 *shall not be used in advertising or otherwise to promote the sale, use 25 *or other dealings in this Software without prior written authorization 26 *from Harold L Hunt II. 27 * 28 * Authors: Harold L Hunt II 29 */ 30 31#ifdef HAVE_XWIN_CONFIG_H 32#include <xwin-config.h> 33#endif 34#include "win.h" 35#include "shellapi.h" 36 37/* 38 * Local function prototypes 39 */ 40 41static Bool 42 winGetWorkArea(RECT * prcWorkArea, winScreenInfo * pScreenInfo); 43 44static Bool 45 winAdjustForAutoHide(RECT * prcWorkArea, winScreenInfo * pScreenInfo); 46 47/* 48 * Create a full screen window 49 */ 50 51Bool 52winCreateBoundingWindowFullScreen(ScreenPtr pScreen) 53{ 54 winScreenPriv(pScreen); 55 winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; 56 int iX = pScreenInfo->dwInitialX; 57 int iY = pScreenInfo->dwInitialY; 58 int iWidth = pScreenInfo->dwWidth; 59 int iHeight = pScreenInfo->dwHeight; 60 HWND *phwnd = &pScreenPriv->hwndScreen; 61 WNDCLASSEX wc; 62 char szTitle[256]; 63 64#if CYGDEBUG 65 winDebug("winCreateBoundingWindowFullScreen\n"); 66#endif 67 68 /* Setup our window class */ 69 wc.cbSize = sizeof(WNDCLASSEX); 70 wc.style = CS_HREDRAW | CS_VREDRAW; 71 wc.lpfnWndProc = winWindowProc; 72 wc.cbClsExtra = 0; 73 wc.cbWndExtra = 0; 74 wc.hInstance = g_hInstance; 75 wc.hIcon = pScreenInfo->hIcon; 76 wc.hCursor = 0; 77 wc.hbrBackground = 0; 78 wc.lpszMenuName = NULL; 79 wc.lpszClassName = WINDOW_CLASS; 80 wc.hIconSm = pScreenInfo->hIconSm; 81 RegisterClassEx(&wc); 82 83 /* Set display and screen-specific tooltip text */ 84 if (g_pszQueryHost != NULL) 85 snprintf(szTitle, 86 sizeof(szTitle), 87 WINDOW_TITLE_XDMCP, 88 g_pszQueryHost, display, (int) pScreenInfo->dwScreen); 89 else 90 snprintf(szTitle, 91 sizeof(szTitle), 92 WINDOW_TITLE, display, (int) pScreenInfo->dwScreen); 93 94 /* Create the window */ 95 *phwnd = CreateWindowExA(0, /* Extended styles */ 96 WINDOW_CLASS, /* Class name */ 97 szTitle, /* Window name */ 98 WS_POPUP, iX, /* Horizontal position */ 99 iY, /* Vertical position */ 100 iWidth, /* Right edge */ 101 iHeight, /* Bottom edge */ 102 (HWND) NULL, /* No parent or owner window */ 103 (HMENU) NULL, /* No menu */ 104 GetModuleHandle(NULL), /* Instance handle */ 105 pScreenPriv); /* ScreenPrivates */ 106 107 /* Hide the window */ 108 ShowWindow(*phwnd, SW_SHOWNORMAL); 109 110 /* Send first paint message */ 111 UpdateWindow(*phwnd); 112 113 /* Attempt to bring our window to the top of the display */ 114 BringWindowToTop(*phwnd); 115 116 return TRUE; 117} 118 119/* 120 * Create our primary Windows display window 121 */ 122 123Bool 124winCreateBoundingWindowWindowed(ScreenPtr pScreen) 125{ 126 winScreenPriv(pScreen); 127 winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; 128 int iWidth = pScreenInfo->dwUserWidth; 129 int iHeight = pScreenInfo->dwUserHeight; 130 int iPosX; 131 int iPosY; 132 HWND *phwnd = &pScreenPriv->hwndScreen; 133 WNDCLASSEX wc; 134 RECT rcClient, rcWorkArea; 135 DWORD dwWindowStyle; 136 BOOL fForceShowWindow = FALSE; 137 char szTitle[256]; 138 139 winDebug("winCreateBoundingWindowWindowed - User w: %d h: %d\n", 140 (int) pScreenInfo->dwUserWidth, (int) pScreenInfo->dwUserHeight); 141 winDebug("winCreateBoundingWindowWindowed - Current w: %d h: %d\n", 142 (int) pScreenInfo->dwWidth, (int) pScreenInfo->dwHeight); 143 144 /* Set the common window style flags */ 145 dwWindowStyle = WS_OVERLAPPED | WS_SYSMENU | WS_MINIMIZEBOX; 146 147 /* Decorated or undecorated window */ 148 if (pScreenInfo->fDecoration 149 && !pScreenInfo->fRootless 150 && !pScreenInfo->fMultiWindow 151 ) { 152 /* Try to handle startup via run.exe. run.exe instructs Windows to 153 * hide all created windows. Detect this case and make sure the 154 * window is shown nevertheless */ 155 STARTUPINFO startupInfo; 156 157 GetStartupInfo(&startupInfo); 158 if (startupInfo.dwFlags & STARTF_USESHOWWINDOW && 159 startupInfo.wShowWindow == SW_HIDE) { 160 fForceShowWindow = TRUE; 161 } 162 dwWindowStyle |= WS_CAPTION; 163 if (pScreenInfo->iResizeMode != resizeNotAllowed) 164 dwWindowStyle |= WS_THICKFRAME | WS_MAXIMIZEBOX; 165 } 166 else 167 dwWindowStyle |= WS_POPUP; 168 169 /* Setup our window class */ 170 wc.cbSize = sizeof(WNDCLASSEX); 171 wc.style = CS_HREDRAW | CS_VREDRAW; 172 wc.lpfnWndProc = winWindowProc; 173 wc.cbClsExtra = 0; 174 wc.cbWndExtra = 0; 175 wc.hInstance = g_hInstance; 176 wc.hIcon = pScreenInfo->hIcon; 177 wc.hCursor = 0; 178 wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH); 179 wc.lpszMenuName = NULL; 180 wc.lpszClassName = WINDOW_CLASS; 181 wc.hIconSm = pScreenInfo->hIconSm; 182 RegisterClassEx(&wc); 183 184 /* Get size of work area */ 185 winGetWorkArea(&rcWorkArea, pScreenInfo); 186 187 /* Adjust for auto-hide taskbars */ 188 winAdjustForAutoHide(&rcWorkArea, pScreenInfo); 189 190 /* Did the user specify a position? */ 191 if (pScreenInfo->fUserGavePosition) { 192 iPosX = pScreenInfo->dwInitialX; 193 iPosY = pScreenInfo->dwInitialY; 194 } 195 else { 196 iPosX = rcWorkArea.left; 197 iPosY = rcWorkArea.top; 198 } 199 200 /* Clean up the scrollbars flag, if necessary */ 201 if ((!pScreenInfo->fDecoration 202 || pScreenInfo->fRootless 203 || pScreenInfo->fMultiWindow 204 ) 205 && (pScreenInfo->iResizeMode == resizeWithScrollbars)) { 206 /* We cannot have scrollbars if we do not have a window border */ 207 pScreenInfo->iResizeMode = resizeNotAllowed; 208 } 209 210 /* Did the user specify a height and width? */ 211 if (pScreenInfo->fUserGaveHeightAndWidth) { 212 /* User gave a desired height and width, try to accommodate */ 213#if CYGDEBUG 214 winDebug("winCreateBoundingWindowWindowed - User gave height " 215 "and width\n"); 216#endif 217 218 /* Adjust the window width and height for borders and title bar */ 219 if (pScreenInfo->fDecoration 220 && !pScreenInfo->fRootless 221 && !pScreenInfo->fMultiWindow 222 ) { 223#if CYGDEBUG 224 winDebug 225 ("winCreateBoundingWindowWindowed - Window has decoration\n"); 226#endif 227 228 /* Are we resizable */ 229 if (pScreenInfo->iResizeMode != resizeNotAllowed) { 230#if CYGDEBUG 231 winDebug 232 ("winCreateBoundingWindowWindowed - Window is resizable\n"); 233#endif 234 235 iWidth += 2 * GetSystemMetrics(SM_CXSIZEFRAME); 236 iHeight += 2 * GetSystemMetrics(SM_CYSIZEFRAME) 237 + GetSystemMetrics(SM_CYCAPTION); 238 } 239 else { 240#if CYGDEBUG 241 winDebug 242 ("winCreateBoundingWindowWindowed - Window is not resizable\n"); 243#endif 244 245 iWidth += 2 * GetSystemMetrics(SM_CXFIXEDFRAME); 246 iHeight += 2 * GetSystemMetrics(SM_CYFIXEDFRAME) 247 + GetSystemMetrics(SM_CYCAPTION); 248 } 249 } 250 } 251 else { 252 /* By default, we are creating a window that is as large as possible */ 253#if CYGDEBUG 254 winDebug("winCreateBoundingWindowWindowed - User did not give " 255 "height and width\n"); 256#endif 257 /* Defaults are wrong if we have multiple monitors */ 258 if (pScreenInfo->fMultipleMonitors) { 259 iWidth = GetSystemMetrics(SM_CXVIRTUALSCREEN); 260 iHeight = GetSystemMetrics(SM_CYVIRTUALSCREEN); 261 } 262 } 263 264 /* Make sure window is no bigger than work area */ 265 if (TRUE 266 && !pScreenInfo->fMultiWindow 267 ) { 268 /* Trim window width to fit work area */ 269 if (iWidth > (rcWorkArea.right - rcWorkArea.left)) 270 iWidth = rcWorkArea.right - rcWorkArea.left; 271 272 /* Trim window height to fit work area */ 273 if (iHeight >= (rcWorkArea.bottom - rcWorkArea.top)) 274 iHeight = rcWorkArea.bottom - rcWorkArea.top; 275 276#if CYGDEBUG 277 winDebug("winCreateBoundingWindowWindowed - Adjusted width: %d " 278 "height: %d\n", iWidth, iHeight); 279#endif 280 } 281 282 /* Set display and screen-specific tooltip text */ 283 if (g_pszQueryHost != NULL) 284 snprintf(szTitle, 285 sizeof(szTitle), 286 WINDOW_TITLE_XDMCP, 287 g_pszQueryHost, display, (int) pScreenInfo->dwScreen); 288 else 289 snprintf(szTitle, 290 sizeof(szTitle), 291 WINDOW_TITLE, display, (int) pScreenInfo->dwScreen); 292 293 /* Create the window */ 294 *phwnd = CreateWindowExA(0, /* Extended styles */ 295 WINDOW_CLASS, /* Class name */ 296 szTitle, /* Window name */ 297 dwWindowStyle, iPosX, /* Horizontal position */ 298 iPosY, /* Vertical position */ 299 iWidth, /* Right edge */ 300 iHeight, /* Bottom edge */ 301 (HWND) NULL, /* No parent or owner window */ 302 (HMENU) NULL, /* No menu */ 303 GetModuleHandle(NULL), /* Instance handle */ 304 pScreenPriv); /* ScreenPrivates */ 305 if (*phwnd == NULL) { 306 ErrorF("winCreateBoundingWindowWindowed - CreateWindowEx () failed\n"); 307 return FALSE; 308 } 309 310#if CYGDEBUG 311 winDebug("winCreateBoundingWindowWindowed - CreateWindowEx () returned\n"); 312#endif 313 314 if (fForceShowWindow) { 315 ErrorF 316 ("winCreateBoundingWindowWindowed - Setting normal windowstyle\n"); 317 ShowWindow(*phwnd, SW_SHOW); 318 } 319 320 /* Get the client area coordinates */ 321 if (!GetClientRect(*phwnd, &rcClient)) { 322 ErrorF("winCreateBoundingWindowWindowed - GetClientRect () " 323 "failed\n"); 324 return FALSE; 325 } 326 327 winDebug("winCreateBoundingWindowWindowed - WindowClient " 328 "w %d h %d r %d l %d b %d t %d\n", 329 (int)(rcClient.right - rcClient.left), 330 (int)(rcClient.bottom - rcClient.top), 331 (int)rcClient.right, (int)rcClient.left, 332 (int)rcClient.bottom, (int)rcClient.top); 333 334 /* We adjust the visual size if the user did not specify it */ 335 if (! 336 ((pScreenInfo->iResizeMode == resizeWithScrollbars) && 337 pScreenInfo->fUserGaveHeightAndWidth)) { 338 /* 339 * User did not give a height and width with scrollbars enabled, 340 * so we will resize the underlying visual to be as large as 341 * the initial view port (page size). This way scrollbars will 342 * not appear until the user shrinks the window, if they ever do. 343 * 344 * NOTE: We have to store the viewport size here because 345 * the user may have an autohide taskbar, which would 346 * cause the viewport size to be one less in one dimension 347 * than the viewport size that we calculated by subtracting 348 * the size of the borders and caption. 349 */ 350 pScreenInfo->dwWidth = rcClient.right - rcClient.left; 351 pScreenInfo->dwHeight = rcClient.bottom - rcClient.top; 352 } 353 354#if 0 355 /* 356 * NOTE: For the uninitiated, the page size is the number of pixels 357 * that we can display in the x or y direction at a time and the 358 * range is the total number of pixels in the x or y direction that we 359 * have available to display. In other words, the page size is the 360 * size of the window area minus the space the caption, borders, and 361 * scrollbars (if any) occupy, and the range is the size of the 362 * underlying X visual. Notice that, contrary to what some of the 363 * MSDN Library arcticles lead you to believe, the windows 364 * ``client area'' size does not include the scrollbars. In other words, 365 * the whole client area size that is reported to you is drawable by 366 * you; you do not have to subtract the size of the scrollbars from 367 * the client area size, and if you did it would result in the size 368 * of the scrollbars being double counted. 369 */ 370 371 /* Setup scrollbar page and range, if scrollbars are enabled */ 372 if (pScreenInfo->fScrollbars) { 373 SCROLLINFO si; 374 375 /* Initialize the scrollbar info structure */ 376 si.cbSize = sizeof(si); 377 si.fMask = SIF_RANGE | SIF_PAGE; 378 si.nMin = 0; 379 380 /* Setup the width range and page size */ 381 si.nMax = pScreenInfo->dwWidth - 1; 382 si.nPage = rcClient.right - rcClient.left; 383 winDebug("winCreateBoundingWindowWindowed - HORZ nMax: %d nPage :%d\n", 384 si.nMax, si.nPage); 385 SetScrollInfo(*phwnd, SB_HORZ, &si, TRUE); 386 387 /* Setup the height range and page size */ 388 si.nMax = pScreenInfo->dwHeight - 1; 389 si.nPage = rcClient.bottom - rcClient.top; 390 winDebug("winCreateBoundingWindowWindowed - VERT nMax: %d nPage :%d\n", 391 si.nMax, si.nPage); 392 SetScrollInfo(*phwnd, SB_VERT, &si, TRUE); 393 } 394#endif 395 396 /* Show the window */ 397 if (FALSE 398 || pScreenInfo->fMultiWindow 399 ) { 400 pScreenPriv->fRootWindowShown = FALSE; 401 ShowWindow(*phwnd, SW_HIDE); 402 } 403 else 404 ShowWindow(*phwnd, SW_SHOWNORMAL); 405 if (!UpdateWindow(*phwnd)) { 406 ErrorF("winCreateBoundingWindowWindowed - UpdateWindow () failed\n"); 407 return FALSE; 408 } 409 410 /* Attempt to bring our window to the top of the display */ 411 if (TRUE 412 && !pScreenInfo->fRootless 413 && !pScreenInfo->fMultiWindow 414 ) { 415 if (!BringWindowToTop(*phwnd)) { 416 ErrorF("winCreateBoundingWindowWindowed - BringWindowToTop () " 417 "failed\n"); 418 return FALSE; 419 } 420 } 421 422 winDebug("winCreateBoundingWindowWindowed - Returning\n"); 423 424 return TRUE; 425} 426 427/* 428 * Find the work area of all attached monitors 429 */ 430 431static Bool 432winGetWorkArea(RECT * prcWorkArea, winScreenInfo * pScreenInfo) 433{ 434 int iPrimaryWidth, iPrimaryHeight; 435 int iWidth, iHeight; 436 int iLeft, iTop; 437 int iPrimaryNonWorkAreaWidth, iPrimaryNonWorkAreaHeight; 438 439 /* Use GetMonitorInfo to get work area for monitor */ 440 if (!pScreenInfo->fMultipleMonitors) { 441 MONITORINFO mi; 442 443 mi.cbSize = sizeof(MONITORINFO); 444 if (GetMonitorInfo(pScreenInfo->hMonitor, &mi)) { 445 *prcWorkArea = mi.rcWork; 446 447 winDebug("winGetWorkArea - Monitor %d WorkArea: %d %d %d %d\n", 448 pScreenInfo->iMonitor, 449 (int) prcWorkArea->top, (int) prcWorkArea->left, 450 (int) prcWorkArea->bottom, (int) prcWorkArea->right); 451 } 452 else { 453 ErrorF("winGetWorkArea - GetMonitorInfo() failed for monitor %d\n", 454 pScreenInfo->iMonitor); 455 } 456 457 /* Bail out here if we aren't using multiple monitors */ 458 return TRUE; 459 } 460 461 /* SPI_GETWORKAREA only gets the work area of the primary screen. */ 462 SystemParametersInfo(SPI_GETWORKAREA, 0, prcWorkArea, 0); 463 464 winDebug("winGetWorkArea - Primary Monitor WorkArea: %d %d %d %d\n", 465 (int) prcWorkArea->top, (int) prcWorkArea->left, 466 (int) prcWorkArea->bottom, (int) prcWorkArea->right); 467 468 /* Get size of full virtual screen */ 469 iWidth = GetSystemMetrics(SM_CXVIRTUALSCREEN); 470 iHeight = GetSystemMetrics(SM_CYVIRTUALSCREEN); 471 472 winDebug("winGetWorkArea - Virtual screen is %d x %d\n", iWidth, iHeight); 473 474 /* Get origin of full virtual screen */ 475 iLeft = GetSystemMetrics(SM_XVIRTUALSCREEN); 476 iTop = GetSystemMetrics(SM_YVIRTUALSCREEN); 477 478 winDebug("winGetWorkArea - Virtual screen origin is %d, %d\n", iLeft, iTop); 479 480 /* Get size of primary screen */ 481 iPrimaryWidth = GetSystemMetrics(SM_CXSCREEN); 482 iPrimaryHeight = GetSystemMetrics(SM_CYSCREEN); 483 484 winDebug("winGetWorkArea - Primary screen is %d x %d\n", 485 iPrimaryWidth, iPrimaryHeight); 486 487 /* Work out how much of the primary screen we aren't using */ 488 iPrimaryNonWorkAreaWidth = iPrimaryWidth - (prcWorkArea->right - 489 prcWorkArea->left); 490 iPrimaryNonWorkAreaHeight = iPrimaryHeight - (prcWorkArea->bottom 491 - prcWorkArea->top); 492 493 /* Update the rectangle to include all monitors */ 494 if (iLeft < 0) { 495 prcWorkArea->left = iLeft; 496 } 497 if (iTop < 0) { 498 prcWorkArea->top = iTop; 499 } 500 prcWorkArea->right = prcWorkArea->left + iWidth - iPrimaryNonWorkAreaWidth; 501 prcWorkArea->bottom = prcWorkArea->top + iHeight - 502 iPrimaryNonWorkAreaHeight; 503 504 winDebug("winGetWorkArea - Adjusted WorkArea for multiple " 505 "monitors: %d %d %d %d\n", 506 (int) prcWorkArea->top, (int) prcWorkArea->left, 507 (int) prcWorkArea->bottom, (int) prcWorkArea->right); 508 509 return TRUE; 510} 511 512static Bool 513winTaskbarOnScreenEdge(unsigned int uEdge, winScreenInfo * pScreenInfo) 514{ 515 APPBARDATA abd; 516 HWND hwndAutoHide; 517 518 ZeroMemory(&abd, sizeof(abd)); 519 abd.cbSize = sizeof(abd); 520 abd.uEdge = uEdge; 521 522 hwndAutoHide = (HWND) SHAppBarMessage(ABM_GETAUTOHIDEBAR, &abd); 523 if (hwndAutoHide != NULL) { 524 /* 525 Found an autohide taskbar on that edge, but is it on the 526 same monitor as the screen window? 527 */ 528 if (pScreenInfo->fMultipleMonitors || 529 (MonitorFromWindow(hwndAutoHide, MONITOR_DEFAULTTONULL) == 530 pScreenInfo->hMonitor)) 531 return TRUE; 532 } 533 return FALSE; 534} 535 536/* 537 * Adjust the client area so that any auto-hide toolbars 538 * will work correctly. 539 */ 540 541static Bool 542winAdjustForAutoHide(RECT * prcWorkArea, winScreenInfo * pScreenInfo) 543{ 544 APPBARDATA abd; 545 546 winDebug("winAdjustForAutoHide - Original WorkArea: %d %d %d %d\n", 547 (int) prcWorkArea->top, (int) prcWorkArea->left, 548 (int) prcWorkArea->bottom, (int) prcWorkArea->right); 549 550 /* Find out if the Windows taskbar is set to auto-hide */ 551 ZeroMemory(&abd, sizeof(abd)); 552 abd.cbSize = sizeof(abd); 553 if (SHAppBarMessage(ABM_GETSTATE, &abd) & ABS_AUTOHIDE) 554 winDebug("winAdjustForAutoHide - Taskbar is auto hide\n"); 555 556 /* 557 Despite the forgoing, we are checking for any AppBar 558 hiding along a monitor edge, not just the Windows TaskBar. 559 */ 560 561 /* Look for a TOP auto-hide taskbar */ 562 if (winTaskbarOnScreenEdge(ABE_TOP, pScreenInfo)) { 563 winDebug("winAdjustForAutoHide - Found TOP auto-hide taskbar\n"); 564 prcWorkArea->top += 1; 565 } 566 567 /* Look for a LEFT auto-hide taskbar */ 568 if (winTaskbarOnScreenEdge(ABE_LEFT, pScreenInfo)) { 569 winDebug("winAdjustForAutoHide - Found LEFT auto-hide taskbar\n"); 570 prcWorkArea->left += 1; 571 } 572 573 /* Look for a BOTTOM auto-hide taskbar */ 574 if (winTaskbarOnScreenEdge(ABE_BOTTOM, pScreenInfo)) { 575 winDebug("winAdjustForAutoHide - Found BOTTOM auto-hide taskbar\n"); 576 prcWorkArea->bottom -= 1; 577 } 578 579 /* Look for a RIGHT auto-hide taskbar */ 580 if (winTaskbarOnScreenEdge(ABE_RIGHT, pScreenInfo)) { 581 winDebug("winAdjustForAutoHide - Found RIGHT auto-hide taskbar\n"); 582 prcWorkArea->right -= 1; 583 } 584 585 winDebug("winAdjustForAutoHide - Adjusted WorkArea: %d %d %d %d\n", 586 (int) prcWorkArea->top, (int) prcWorkArea->left, 587 (int) prcWorkArea->bottom, (int) prcWorkArea->right); 588 589 return TRUE; 590} 591