| 1 | /* |
| 2 | *Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved. |
| 3 | *Copyright (C) Colin Harrison 2005-2008 |
| 4 | * |
| 5 | *Permission is hereby granted, free of charge, to any person obtaining |
| 6 | * a copy of this software and associated documentation files (the |
| 7 | *"Software"), to deal in the Software without restriction, including |
| 8 | *without limitation the rights to use, copy, modify, merge, publish, |
| 9 | *distribute, sublicense, and/or sell copies of the Software, and to |
| 10 | *permit persons to whom the Software is furnished to do so, subject to |
| 11 | *the following conditions: |
| 12 | * |
| 13 | *The above copyright notice and this permission notice shall be |
| 14 | *included in all copies or substantial portions of the Software. |
| 15 | * |
| 16 | *THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
| 17 | *EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
| 18 | *MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
| 19 | *NONINFRINGEMENT. IN NO EVENT SHALL THE XFREE86 PROJECT BE LIABLE FOR |
| 20 | *ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF |
| 21 | *CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
| 22 | *WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
| 23 | * |
| 24 | *Except as contained in this notice, the name of the XFree86 Project |
| 25 | *shall not be used in advertising or otherwise to promote the sale, use |
| 26 | *or other dealings in this Software without prior written authorization |
| 27 | *from the XFree86 Project. |
| 28 | * |
| 29 | * Authors: Kensuke Matsuzaki |
| 30 | * Earle F. Philhower, III |
| 31 | * Harold L Hunt II |
| 32 | * Colin Harrison |
| 33 | */ |
| 34 | |
| 35 | #ifdef HAVE_XWIN_CONFIG_H |
| 36 | #include <xwin-config.h> |
| 37 | #endif |
| 38 | #include "win.h" |
| 39 | #include "dixevents.h" |
| 40 | #include "winmultiwindowclass.h" |
| 41 | |
| 42 | /* |
| 43 | * Prototypes for local functions |
| 44 | */ |
| 45 | |
| 46 | void |
| 47 | winCreateWindowsWindow(WindowPtr pWin); |
| 48 | |
| 49 | static void |
| 50 | winDestroyWindowsWindow(WindowPtr pWin); |
| 51 | |
| 52 | static void |
| 53 | winUpdateWindowsWindow(WindowPtr pWin); |
| 54 | |
| 55 | static void |
| 56 | winFindWindow(pointer value, XID id, pointer cdata); |
| 57 | |
| 58 | static |
| 59 | void |
| 60 | winInitMultiWindowClass(void) |
| 61 | { |
| 62 | static wATOM atomXWinClass = 0; |
| 63 | WNDCLASSEX wcx; |
| 64 | |
| 65 | if (atomXWinClass == 0) { |
| 66 | HICON hIcon, hIconSmall; |
| 67 | |
| 68 | /* Load the default icons */ |
| 69 | winSelectIcons(&hIcon, &hIconSmall); |
| 70 | |
| 71 | /* Setup our window class */ |
| 72 | wcx.cbSize = sizeof(WNDCLASSEX); |
| 73 | wcx.style = CS_HREDRAW | CS_VREDRAW | (g_fNativeGl ? CS_OWNDC : 0); |
| 74 | wcx.lpfnWndProc = winTopLevelWindowProc; |
| 75 | wcx.cbClsExtra = 0; |
| 76 | wcx.cbWndExtra = 0; |
| 77 | wcx.hInstance = g_hInstance; |
| 78 | wcx.hIcon = hIcon; |
| 79 | wcx.hCursor = 0; |
| 80 | wcx.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH); |
| 81 | wcx.lpszMenuName = NULL; |
| 82 | wcx.lpszClassName = WINDOW_CLASS_X; |
| 83 | wcx.hIconSm = hIconSmall; |
| 84 | |
| 85 | #if CYGMULTIWINDOW_DEBUG |
| 86 | ErrorF("winCreateWindowsWindow - Creating class: %s\n", WINDOW_CLASS_X); |
| 87 | #endif |
| 88 | |
| 89 | atomXWinClass = RegisterClassEx(&wcx); |
| 90 | } |
| 91 | } |
| 92 | |
| 93 | /* |
| 94 | * CreateWindow - See Porting Layer Definition - p. 37 |
| 95 | */ |
| 96 | |
| 97 | Bool |
| 98 | winCreateWindowMultiWindow(WindowPtr pWin) |
| 99 | { |
| 100 | Bool fResult = TRUE; |
| 101 | ScreenPtr pScreen = pWin->drawable.pScreen; |
| 102 | |
| 103 | winWindowPriv(pWin); |
| 104 | winScreenPriv(pScreen); |
| 105 | |
| 106 | #if CYGMULTIWINDOW_DEBUG |
| 107 | winTrace("winCreateWindowMultiWindow - pWin: %p\n", pWin); |
| 108 | #endif |
| 109 | |
| 110 | WIN_UNWRAP(CreateWindow); |
| 111 | fResult = (*pScreen->CreateWindow) (pWin); |
| 112 | WIN_WRAP(CreateWindow, winCreateWindowMultiWindow); |
| 113 | |
| 114 | /* Initialize some privates values */ |
| 115 | pWinPriv->hRgn = NULL; |
| 116 | pWinPriv->hWnd = NULL; |
| 117 | pWinPriv->pScreenPriv = winGetScreenPriv(pWin->drawable.pScreen); |
| 118 | pWinPriv->fXKilled = FALSE; |
| 119 | #ifdef XWIN_GLX_WINDOWS |
| 120 | pWinPriv->fWglUsed = FALSE; |
| 121 | #endif |
| 122 | |
| 123 | return fResult; |
| 124 | } |
| 125 | |
| 126 | /* |
| 127 | * DestroyWindow - See Porting Layer Definition - p. 37 |
| 128 | */ |
| 129 | |
| 130 | Bool |
| 131 | winDestroyWindowMultiWindow(WindowPtr pWin) |
| 132 | { |
| 133 | Bool fResult = TRUE; |
| 134 | ScreenPtr pScreen = pWin->drawable.pScreen; |
| 135 | |
| 136 | winWindowPriv(pWin); |
| 137 | winScreenPriv(pScreen); |
| 138 | |
| 139 | #if CYGMULTIWINDOW_DEBUG |
| 140 | ErrorF("winDestroyWindowMultiWindow - pWin: %p\n", pWin); |
| 141 | #endif |
| 142 | |
| 143 | WIN_UNWRAP(DestroyWindow); |
| 144 | fResult = (*pScreen->DestroyWindow) (pWin); |
| 145 | WIN_WRAP(DestroyWindow, winDestroyWindowMultiWindow); |
| 146 | |
| 147 | /* Flag that the window has been destroyed */ |
| 148 | pWinPriv->fXKilled = TRUE; |
| 149 | |
| 150 | /* Kill the MS Windows window associated with this window */ |
| 151 | winDestroyWindowsWindow(pWin); |
| 152 | |
| 153 | return fResult; |
| 154 | } |
| 155 | |
| 156 | /* |
| 157 | * PositionWindow - See Porting Layer Definition - p. 37 |
| 158 | * |
| 159 | * This function adjusts the position and size of Windows window |
| 160 | * with respect to the underlying X window. This is the inverse |
| 161 | * of winAdjustXWindow, which adjusts X window to Windows window. |
| 162 | */ |
| 163 | |
| 164 | Bool |
| 165 | winPositionWindowMultiWindow(WindowPtr pWin, int x, int y) |
| 166 | { |
| 167 | Bool fResult = TRUE; |
| 168 | int iX, iY, iWidth, iHeight; |
| 169 | ScreenPtr pScreen = pWin->drawable.pScreen; |
| 170 | |
| 171 | winWindowPriv(pWin); |
| 172 | winScreenPriv(pScreen); |
| 173 | |
| 174 | HWND hWnd = pWinPriv->hWnd; |
| 175 | RECT rcNew; |
| 176 | RECT rcOld; |
| 177 | |
| 178 | #if CYGMULTIWINDOW_DEBUG |
| 179 | RECT rcClient; |
| 180 | RECT *lpRc; |
| 181 | #endif |
| 182 | DWORD dwExStyle; |
| 183 | DWORD dwStyle; |
| 184 | |
| 185 | #if CYGMULTIWINDOW_DEBUG |
| 186 | winTrace("winPositionWindowMultiWindow - pWin: %p\n", pWin); |
| 187 | #endif |
| 188 | |
| 189 | WIN_UNWRAP(PositionWindow); |
| 190 | fResult = (*pScreen->PositionWindow) (pWin, x, y); |
| 191 | WIN_WRAP(PositionWindow, winPositionWindowMultiWindow); |
| 192 | |
| 193 | #if CYGWINDOWING_DEBUG |
| 194 | ErrorF("winPositionWindowMultiWindow: (x, y) = (%d, %d)\n", x, y); |
| 195 | #endif |
| 196 | |
| 197 | /* Bail out if the Windows window handle is bad */ |
| 198 | if (!hWnd) { |
| 199 | #if CYGWINDOWING_DEBUG |
| 200 | ErrorF("\timmediately return since hWnd is NULL\n"); |
| 201 | #endif |
| 202 | return fResult; |
| 203 | } |
| 204 | |
| 205 | /* Get the Windows window style and extended style */ |
| 206 | dwExStyle = GetWindowLongPtr(hWnd, GWL_EXSTYLE); |
| 207 | dwStyle = GetWindowLongPtr(hWnd, GWL_STYLE); |
| 208 | |
| 209 | /* Get the X and Y location of the X window */ |
| 210 | iX = pWin->drawable.x + GetSystemMetrics(SM_XVIRTUALSCREEN); |
| 211 | iY = pWin->drawable.y + GetSystemMetrics(SM_YVIRTUALSCREEN); |
| 212 | |
| 213 | /* Get the height and width of the X window */ |
| 214 | iWidth = pWin->drawable.width; |
| 215 | iHeight = pWin->drawable.height; |
| 216 | |
| 217 | /* Store the origin, height, and width in a rectangle structure */ |
| 218 | SetRect(&rcNew, iX, iY, iX + iWidth, iY + iHeight); |
| 219 | |
| 220 | #if CYGMULTIWINDOW_DEBUG |
| 221 | lpRc = &rcNew; |
| 222 | ErrorF("winPositionWindowMultiWindow - (%d ms)drawable (%d, %d)-(%d, %d)\n", |
| 223 | GetTickCount(), lpRc->left, lpRc->top, lpRc->right, lpRc->bottom); |
| 224 | #endif |
| 225 | |
| 226 | /* |
| 227 | * Calculate the required size of the Windows window rectangle, |
| 228 | * given the size of the Windows window client area. |
| 229 | */ |
| 230 | AdjustWindowRectEx(&rcNew, dwStyle, FALSE, dwExStyle); |
| 231 | |
| 232 | /* Get a rectangle describing the old Windows window */ |
| 233 | GetWindowRect(hWnd, &rcOld); |
| 234 | |
| 235 | #if CYGMULTIWINDOW_DEBUG |
| 236 | /* Get a rectangle describing the Windows window client area */ |
| 237 | GetClientRect(hWnd, &rcClient); |
| 238 | |
| 239 | lpRc = &rcNew; |
| 240 | ErrorF("winPositionWindowMultiWindow - (%d ms)rcNew (%d, %d)-(%d, %d)\n", |
| 241 | GetTickCount(), lpRc->left, lpRc->top, lpRc->right, lpRc->bottom); |
| 242 | |
| 243 | lpRc = &rcOld; |
| 244 | ErrorF("winPositionWindowMultiWindow - (%d ms)rcOld (%d, %d)-(%d, %d)\n", |
| 245 | GetTickCount(), lpRc->left, lpRc->top, lpRc->right, lpRc->bottom); |
| 246 | |
| 247 | lpRc = &rcClient; |
| 248 | ErrorF("(%d ms)rcClient (%d, %d)-(%d, %d)\n", |
| 249 | GetTickCount(), lpRc->left, lpRc->top, lpRc->right, lpRc->bottom); |
| 250 | #endif |
| 251 | |
| 252 | /* Check if the old rectangle and new rectangle are the same */ |
| 253 | if (!EqualRect(&rcNew, &rcOld)) { |
| 254 | #if CYGMULTIWINDOW_DEBUG |
| 255 | ErrorF("winPositionWindowMultiWindow - Need to move\n"); |
| 256 | #endif |
| 257 | |
| 258 | #if CYGWINDOWING_DEBUG |
| 259 | ErrorF("\tMoveWindow to (%ld, %ld) - %ldx%ld\n", rcNew.left, rcNew.top, |
| 260 | rcNew.right - rcNew.left, rcNew.bottom - rcNew.top); |
| 261 | #endif |
| 262 | /* Change the position and dimensions of the Windows window */ |
| 263 | MoveWindow(hWnd, |
| 264 | rcNew.left, rcNew.top, |
| 265 | rcNew.right - rcNew.left, rcNew.bottom - rcNew.top, TRUE); |
| 266 | } |
| 267 | else { |
| 268 | #if CYGMULTIWINDOW_DEBUG |
| 269 | ErrorF("winPositionWindowMultiWindow - Not need to move\n"); |
| 270 | #endif |
| 271 | } |
| 272 | |
| 273 | return fResult; |
| 274 | } |
| 275 | |
| 276 | /* |
| 277 | * ChangeWindowAttributes - See Porting Layer Definition - p. 37 |
| 278 | */ |
| 279 | |
| 280 | Bool |
| 281 | winChangeWindowAttributesMultiWindow(WindowPtr pWin, unsigned long mask) |
| 282 | { |
| 283 | Bool fResult = TRUE; |
| 284 | ScreenPtr pScreen = pWin->drawable.pScreen; |
| 285 | |
| 286 | winScreenPriv(pScreen); |
| 287 | |
| 288 | #if CYGMULTIWINDOW_DEBUG |
| 289 | ErrorF("winChangeWindowAttributesMultiWindow - pWin: %08x\n", pWin); |
| 290 | #endif |
| 291 | |
| 292 | WIN_UNWRAP(ChangeWindowAttributes); |
| 293 | fResult = (*pScreen->ChangeWindowAttributes) (pWin, mask); |
| 294 | WIN_WRAP(ChangeWindowAttributes, winChangeWindowAttributesMultiWindow); |
| 295 | |
| 296 | /* |
| 297 | * NOTE: We do not currently need to do anything here. |
| 298 | */ |
| 299 | |
| 300 | return fResult; |
| 301 | } |
| 302 | |
| 303 | /* |
| 304 | * UnmapWindow - See Porting Layer Definition - p. 37 |
| 305 | * Also referred to as UnrealizeWindow |
| 306 | */ |
| 307 | |
| 308 | Bool |
| 309 | winUnmapWindowMultiWindow(WindowPtr pWin) |
| 310 | { |
| 311 | Bool fResult = TRUE; |
| 312 | ScreenPtr pScreen = pWin->drawable.pScreen; |
| 313 | |
| 314 | winWindowPriv(pWin); |
| 315 | winScreenPriv(pScreen); |
| 316 | |
| 317 | #if CYGMULTIWINDOW_DEBUG |
| 318 | ErrorF("winUnmapWindowMultiWindow - pWin: %08x\n", pWin); |
| 319 | #endif |
| 320 | |
| 321 | WIN_UNWRAP(UnrealizeWindow); |
| 322 | fResult = (*pScreen->UnrealizeWindow) (pWin); |
| 323 | WIN_WRAP(UnrealizeWindow, winUnmapWindowMultiWindow); |
| 324 | |
| 325 | /* Flag that the window has been killed */ |
| 326 | pWinPriv->fXKilled = TRUE; |
| 327 | |
| 328 | /* Destroy the Windows window associated with this X window */ |
| 329 | winDestroyWindowsWindow(pWin); |
| 330 | |
| 331 | return fResult; |
| 332 | } |
| 333 | |
| 334 | /* |
| 335 | * MapWindow - See Porting Layer Definition - p. 37 |
| 336 | * Also referred to as RealizeWindow |
| 337 | */ |
| 338 | |
| 339 | Bool |
| 340 | winMapWindowMultiWindow(WindowPtr pWin) |
| 341 | { |
| 342 | Bool fResult = TRUE; |
| 343 | ScreenPtr pScreen = pWin->drawable.pScreen; |
| 344 | |
| 345 | winWindowPriv(pWin); |
| 346 | winScreenPriv(pScreen); |
| 347 | |
| 348 | #if CYGMULTIWINDOW_DEBUG |
| 349 | ErrorF("winMapWindowMultiWindow - pWin: %08x\n", pWin); |
| 350 | #endif |
| 351 | |
| 352 | WIN_UNWRAP(RealizeWindow); |
| 353 | fResult = (*pScreen->RealizeWindow) (pWin); |
| 354 | WIN_WRAP(RealizeWindow, winMapWindowMultiWindow); |
| 355 | |
| 356 | /* Flag that this window has not been destroyed */ |
| 357 | pWinPriv->fXKilled = FALSE; |
| 358 | |
| 359 | /* Refresh/redisplay the Windows window associated with this X window */ |
| 360 | winUpdateWindowsWindow(pWin); |
| 361 | |
| 362 | /* Update the Windows window's shape */ |
| 363 | winReshapeMultiWindow(pWin); |
| 364 | winUpdateRgnMultiWindow(pWin); |
| 365 | |
| 366 | return fResult; |
| 367 | } |
| 368 | |
| 369 | /* |
| 370 | * ReparentWindow - See Porting Layer Definition - p. 42 |
| 371 | */ |
| 372 | |
| 373 | void |
| 374 | winReparentWindowMultiWindow(WindowPtr pWin, WindowPtr pPriorParent) |
| 375 | { |
| 376 | ScreenPtr pScreen = pWin->drawable.pScreen; |
| 377 | |
| 378 | winScreenPriv(pScreen); |
| 379 | |
| 380 | winDebug |
| 381 | ("winReparentMultiWindow - pWin:%08x XID:0x%x, reparent from pWin:%08x XID:0x%x to pWin:%08x XID:0x%x\n", |
| 382 | pWin, pWin->drawable.id, pPriorParent, pPriorParent->drawable.id, |
| 383 | pWin->parent, pWin->parent->drawable.id); |
| 384 | |
| 385 | WIN_UNWRAP(ReparentWindow); |
| 386 | if (pScreen->ReparentWindow) |
| 387 | (*pScreen->ReparentWindow) (pWin, pPriorParent); |
| 388 | WIN_WRAP(ReparentWindow, winReparentWindowMultiWindow); |
| 389 | |
| 390 | /* Update the Windows window associated with this X window */ |
| 391 | winUpdateWindowsWindow(pWin); |
| 392 | } |
| 393 | |
| 394 | /* |
| 395 | * RestackWindow - Shuffle the z-order of a window |
| 396 | */ |
| 397 | |
| 398 | void |
| 399 | winRestackWindowMultiWindow(WindowPtr pWin, WindowPtr pOldNextSib) |
| 400 | { |
| 401 | #if 0 |
| 402 | WindowPtr pPrevWin; |
| 403 | UINT uFlags; |
| 404 | HWND hInsertAfter; |
| 405 | HWND hWnd = NULL; |
| 406 | #endif |
| 407 | ScreenPtr pScreen = pWin->drawable.pScreen; |
| 408 | |
| 409 | winScreenPriv(pScreen); |
| 410 | |
| 411 | #if CYGMULTIWINDOW_DEBUG || CYGWINDOWING_DEBUG |
| 412 | winTrace("winRestackMultiWindow - %08x\n", pWin); |
| 413 | #endif |
| 414 | |
| 415 | WIN_UNWRAP(RestackWindow); |
| 416 | if (pScreen->RestackWindow) |
| 417 | (*pScreen->RestackWindow) (pWin, pOldNextSib); |
| 418 | WIN_WRAP(RestackWindow, winRestackWindowMultiWindow); |
| 419 | |
| 420 | #if 1 |
| 421 | /* |
| 422 | * Calling winReorderWindowsMultiWindow here means our window manager |
| 423 | * (i.e. Windows Explorer) has initiative to determine Z order. |
| 424 | */ |
| 425 | if (pWin->nextSib != pOldNextSib) |
| 426 | winReorderWindowsMultiWindow(); |
| 427 | #else |
| 428 | /* Bail out if no window privates or window handle is invalid */ |
| 429 | if (!pWinPriv || !pWinPriv->hWnd) |
| 430 | return; |
| 431 | |
| 432 | /* Get a pointer to our previous sibling window */ |
| 433 | pPrevWin = pWin->prevSib; |
| 434 | |
| 435 | /* |
| 436 | * Look for a sibling window with |
| 437 | * valid privates and window handle |
| 438 | */ |
| 439 | while (pPrevWin && !winGetWindowPriv(pPrevWin) |
| 440 | && !winGetWindowPriv(pPrevWin)->hWnd) |
| 441 | pPrevWin = pPrevWin->prevSib; |
| 442 | |
| 443 | /* Check if we found a valid sibling */ |
| 444 | if (pPrevWin) { |
| 445 | /* Valid sibling - get handle to insert window after */ |
| 446 | hInsertAfter = winGetWindowPriv(pPrevWin)->hWnd; |
| 447 | uFlags = SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE; |
| 448 | |
| 449 | hWnd = GetNextWindow(pWinPriv->hWnd, GW_HWNDPREV); |
| 450 | |
| 451 | do { |
| 452 | if (GetProp(hWnd, WIN_WINDOW_PROP)) { |
| 453 | if (hWnd == winGetWindowPriv(pPrevWin)->hWnd) { |
| 454 | uFlags |= SWP_NOZORDER; |
| 455 | } |
| 456 | break; |
| 457 | } |
| 458 | hWnd = GetNextWindow(hWnd, GW_HWNDPREV); |
| 459 | } |
| 460 | while (hWnd); |
| 461 | } |
| 462 | else { |
| 463 | /* No valid sibling - make this window the top window */ |
| 464 | hInsertAfter = HWND_TOP; |
| 465 | uFlags = SWP_NOMOVE | SWP_NOSIZE; |
| 466 | } |
| 467 | |
| 468 | /* Perform the restacking operation in Windows */ |
| 469 | SetWindowPos(pWinPriv->hWnd, hInsertAfter, 0, 0, 0, 0, uFlags); |
| 470 | #endif |
| 471 | } |
| 472 | |
| 473 | /* |
| 474 | * winCreateWindowsWindow - Create a Windows window associated with an X window |
| 475 | */ |
| 476 | |
| 477 | void |
| 478 | winCreateWindowsWindow(WindowPtr pWin) |
| 479 | { |
| 480 | int iX, iY; |
| 481 | int iWidth; |
| 482 | int iHeight; |
| 483 | HWND hWnd; |
| 484 | HWND hFore = NULL; |
| 485 | |
| 486 | winWindowPriv(pWin); |
| 487 | winPrivScreenPtr pScreenPriv = pWinPriv->pScreenPriv; |
| 488 | WinXSizeHints hints; |
| 489 | Window daddyId; |
| 490 | DWORD dwStyle, dwExStyle; |
| 491 | RECT rc; |
| 492 | |
| 493 | winInitMultiWindowClass(); |
| 494 | |
| 495 | winDebug("winCreateWindowsTopLevelWindow - pWin:%08x XID:0x%x \n", pWin, |
| 496 | pWin->drawable.id); |
| 497 | |
| 498 | iX = pWin->drawable.x + GetSystemMetrics(SM_XVIRTUALSCREEN); |
| 499 | iY = pWin->drawable.y + GetSystemMetrics(SM_YVIRTUALSCREEN); |
| 500 | |
| 501 | iWidth = pWin->drawable.width; |
| 502 | iHeight = pWin->drawable.height; |
| 503 | |
| 504 | /* If it's an InputOutput window, and so is going to end up being made visible, |
| 505 | make sure the window actually ends up somewhere where it will be visible */ |
| 506 | if (pWin->drawable.class != InputOnly) { |
| 507 | if ((iX < GetSystemMetrics(SM_XVIRTUALSCREEN)) || |
| 508 | (iX > GetSystemMetrics(SM_CXVIRTUALSCREEN))) |
| 509 | iX = CW_USEDEFAULT; |
| 510 | |
| 511 | if ((iY < GetSystemMetrics(SM_YVIRTUALSCREEN)) || |
| 512 | (iY > GetSystemMetrics(SM_CYVIRTUALSCREEN))) |
| 513 | iY = CW_USEDEFAULT; |
| 514 | } |
| 515 | |
| 516 | winDebug("winCreateWindowsWindow - %dx%d @ %dx%d\n", iWidth, iHeight, iX, |
| 517 | iY); |
| 518 | |
| 519 | if (winMultiWindowGetTransientFor(pWin, &daddyId)) { |
| 520 | if (daddyId) { |
| 521 | hFore = GetForegroundWindow(); |
| 522 | if (hFore && (daddyId != (Window) (INT_PTR) GetProp(hFore, WIN_WID_PROP))) |
| 523 | hFore = NULL; |
| 524 | } |
| 525 | } |
| 526 | else { |
| 527 | /* Default positions if none specified */ |
| 528 | if (!winMultiWindowGetWMNormalHints(pWin, &hints)) |
| 529 | hints.flags = 0; |
| 530 | if (!(hints.flags & (USPosition | PPosition)) && |
| 531 | !pWin->overrideRedirect) { |
| 532 | iX = CW_USEDEFAULT; |
| 533 | iY = CW_USEDEFAULT; |
| 534 | } |
| 535 | } |
| 536 | |
| 537 | /* Make it WS_OVERLAPPED in create call since WS_POPUP doesn't support */ |
| 538 | /* CW_USEDEFAULT, change back to popup after creation */ |
| 539 | dwStyle = WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS; |
| 540 | dwExStyle = WS_EX_TOOLWINDOW; |
| 541 | |
| 542 | /* |
| 543 | Calculate the window coordinates containing the requested client area, |
| 544 | being careful to preseve CW_USEDEFAULT |
| 545 | */ |
| 546 | rc.top = (iY != CW_USEDEFAULT) ? iY : 0; |
| 547 | rc.left = (iX != CW_USEDEFAULT) ? iX : 0; |
| 548 | rc.bottom = rc.top + iHeight; |
| 549 | rc.right = rc.left + iWidth; |
| 550 | AdjustWindowRectEx(&rc, dwStyle, FALSE, dwExStyle); |
| 551 | if (iY != CW_USEDEFAULT) |
| 552 | iY = rc.top; |
| 553 | if (iX != CW_USEDEFAULT) |
| 554 | iX = rc.left; |
| 555 | iHeight = rc.bottom - rc.top; |
| 556 | iWidth = rc.right - rc.left; |
| 557 | |
| 558 | winDebug("winCreateWindowsWindow - %dx%d @ %dx%d\n", iWidth, iHeight, iX, |
| 559 | iY); |
| 560 | |
| 561 | /* Create the window */ |
| 562 | hWnd = CreateWindowExA(dwExStyle, /* Extended styles */ |
| 563 | WINDOW_CLASS_X, /* Class name */ |
| 564 | WINDOW_TITLE_X, /* Window name */ |
| 565 | dwStyle, /* Styles */ |
| 566 | iX, /* Horizontal position */ |
| 567 | iY, /* Vertical position */ |
| 568 | iWidth, /* Right edge */ |
| 569 | iHeight, /* Bottom edge */ |
| 570 | hFore, /* Null or Parent window if transient */ |
| 571 | (HMENU) NULL, /* No menu */ |
| 572 | GetModuleHandle(NULL), /* Instance handle */ |
| 573 | pWin); /* ScreenPrivates */ |
| 574 | if (hWnd == NULL) { |
| 575 | ErrorF("winCreateWindowsWindow - CreateWindowExA () failed: %d\n", |
| 576 | (int) GetLastError()); |
| 577 | } |
| 578 | pWinPriv->hWnd = hWnd; |
| 579 | |
| 580 | /* Change style back to popup, already placed... */ |
| 581 | SetWindowLongPtr(hWnd, GWL_STYLE, |
| 582 | WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS); |
| 583 | SetWindowPos(hWnd, 0, 0, 0, 0, 0, |
| 584 | SWP_FRAMECHANGED | SWP_NOZORDER | SWP_NOMOVE | SWP_NOSIZE | |
| 585 | SWP_NOACTIVATE); |
| 586 | |
| 587 | /* Adjust the X window to match the window placement we actually got... */ |
| 588 | winAdjustXWindow(pWin, hWnd); |
| 589 | |
| 590 | /* Make sure it gets the proper system menu for a WS_POPUP, too */ |
| 591 | GetSystemMenu(hWnd, TRUE); |
| 592 | |
| 593 | /* Cause any .XWinrc menus to be added in main WNDPROC */ |
| 594 | PostMessage(hWnd, WM_INIT_SYS_MENU, 0, 0); |
| 595 | |
| 596 | SetProp(hWnd, WIN_WID_PROP, (HANDLE) (INT_PTR) winGetWindowID(pWin)); |
| 597 | |
| 598 | /* Flag that this Windows window handles its own activation */ |
| 599 | SetProp(hWnd, WIN_NEEDMANAGE_PROP, (HANDLE) 0); |
| 600 | |
| 601 | /* Call engine-specific create window procedure */ |
| 602 | (*pScreenPriv->pwinFinishCreateWindowsWindow) (pWin); |
| 603 | } |
| 604 | |
| 605 | Bool winInDestroyWindowsWindow = FALSE; |
| 606 | |
| 607 | /* |
| 608 | * winDestroyWindowsWindow - Destroy a Windows window associated |
| 609 | * with an X window |
| 610 | */ |
| 611 | static void |
| 612 | winDestroyWindowsWindow(WindowPtr pWin) |
| 613 | { |
| 614 | MSG msg; |
| 615 | |
| 616 | winWindowPriv(pWin); |
| 617 | BOOL oldstate = winInDestroyWindowsWindow; |
| 618 | HICON hIcon; |
| 619 | HICON hIconSm; |
| 620 | |
| 621 | winDebug("winDestroyWindowsWindow - pWin:%08x XID:0x%x \n", pWin, |
| 622 | pWin->drawable.id); |
| 623 | |
| 624 | /* Bail out if the Windows window handle is invalid */ |
| 625 | if (pWinPriv->hWnd == NULL) |
| 626 | return; |
| 627 | |
| 628 | winInDestroyWindowsWindow = TRUE; |
| 629 | |
| 630 | /* Store the info we need to destroy after this window is gone */ |
| 631 | hIcon = (HICON) SendMessage(pWinPriv->hWnd, WM_GETICON, ICON_BIG, 0); |
| 632 | hIconSm = (HICON) SendMessage(pWinPriv->hWnd, WM_GETICON, ICON_SMALL, 0); |
| 633 | |
| 634 | /* Destroy the Windows window */ |
| 635 | DestroyWindow(pWinPriv->hWnd); |
| 636 | |
| 637 | /* Null our handle to the Window so referencing it will cause an error */ |
| 638 | pWinPriv->hWnd = NULL; |
| 639 | |
| 640 | /* Destroy any icons we created for this window */ |
| 641 | winDestroyIcon(hIcon); |
| 642 | winDestroyIcon(hIconSm); |
| 643 | |
| 644 | #ifdef XWIN_GLX_WINDOWS |
| 645 | /* No longer note WGL used on this window */ |
| 646 | pWinPriv->fWglUsed = FALSE; |
| 647 | #endif |
| 648 | |
| 649 | /* Process all messages on our queue */ |
| 650 | while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { |
| 651 | if (g_hDlgDepthChange == 0 || !IsDialogMessage(g_hDlgDepthChange, &msg)) { |
| 652 | DispatchMessage(&msg); |
| 653 | } |
| 654 | } |
| 655 | |
| 656 | winInDestroyWindowsWindow = oldstate; |
| 657 | |
| 658 | winDebug("winDestroyWindowsWindow - done\n"); |
| 659 | } |
| 660 | |
| 661 | /* |
| 662 | * winUpdateWindowsWindow - Redisplay/redraw a Windows window |
| 663 | * associated with an X window |
| 664 | */ |
| 665 | |
| 666 | static void |
| 667 | winUpdateWindowsWindow(WindowPtr pWin) |
| 668 | { |
| 669 | winWindowPriv(pWin); |
| 670 | HWND hWnd = pWinPriv->hWnd; |
| 671 | |
| 672 | #if CYGMULTIWINDOW_DEBUG |
| 673 | ErrorF("winUpdateWindowsWindow\n"); |
| 674 | #endif |
| 675 | |
| 676 | /* Check if the Windows window's parents have been destroyed */ |
| 677 | if (pWin->parent != NULL && pWin->parent->parent == NULL && pWin->mapped) { |
| 678 | /* Create the Windows window if it has been destroyed */ |
| 679 | if (hWnd == NULL) { |
| 680 | winCreateWindowsWindow(pWin); |
| 681 | assert(pWinPriv->hWnd != NULL); |
| 682 | } |
| 683 | |
| 684 | /* Display the window without activating it */ |
| 685 | if (pWin->drawable.class != InputOnly) |
| 686 | ShowWindow(pWinPriv->hWnd, SW_SHOWNOACTIVATE); |
| 687 | |
| 688 | /* Send first paint message */ |
| 689 | UpdateWindow(pWinPriv->hWnd); |
| 690 | } |
| 691 | else if (hWnd != NULL) { |
| 692 | /* Destroy the Windows window if its parents are destroyed */ |
| 693 | winDestroyWindowsWindow(pWin); |
| 694 | assert(pWinPriv->hWnd == NULL); |
| 695 | } |
| 696 | |
| 697 | #if CYGMULTIWINDOW_DEBUG |
| 698 | ErrorF("-winUpdateWindowsWindow\n"); |
| 699 | #endif |
| 700 | } |
| 701 | |
| 702 | /* |
| 703 | * winGetWindowID - |
| 704 | */ |
| 705 | |
| 706 | XID |
| 707 | winGetWindowID(WindowPtr pWin) |
| 708 | { |
| 709 | WindowIDPairRec wi = { pWin, 0 }; |
| 710 | ClientPtr c = wClient(pWin); |
| 711 | |
| 712 | /* */ |
| 713 | FindClientResourcesByType(c, RT_WINDOW, winFindWindow, &wi); |
| 714 | |
| 715 | #if CYGMULTIWINDOW_DEBUG |
| 716 | ErrorF("winGetWindowID - Window ID: %d\n", wi.id); |
| 717 | #endif |
| 718 | |
| 719 | return wi.id; |
| 720 | } |
| 721 | |
| 722 | /* |
| 723 | * winFindWindow - |
| 724 | */ |
| 725 | |
| 726 | static void |
| 727 | winFindWindow(pointer value, XID id, pointer cdata) |
| 728 | { |
| 729 | WindowIDPairPtr wi = (WindowIDPairPtr) cdata; |
| 730 | |
| 731 | if (value == wi->value) { |
| 732 | wi->id = id; |
| 733 | } |
| 734 | } |
| 735 | |
| 736 | /* |
| 737 | * winReorderWindowsMultiWindow - |
| 738 | */ |
| 739 | |
| 740 | void |
| 741 | winReorderWindowsMultiWindow(void) |
| 742 | { |
| 743 | HWND hwnd = NULL; |
| 744 | WindowPtr pWin = NULL; |
| 745 | WindowPtr pWinSib = NULL; |
| 746 | XID vlist[2]; |
| 747 | static Bool fRestacking = FALSE; /* Avoid recusive calls to this function */ |
| 748 | DWORD dwCurrentProcessID = GetCurrentProcessId(); |
| 749 | DWORD dwWindowProcessID = 0; |
| 750 | |
| 751 | #if CYGMULTIWINDOW_DEBUG || CYGWINDOWING_DEBUG |
| 752 | winTrace("winReorderWindowsMultiWindow\n"); |
| 753 | #endif |
| 754 | |
| 755 | if (fRestacking) { |
| 756 | /* It is a recusive call so immediately exit */ |
| 757 | #if CYGWINDOWING_DEBUG |
| 758 | ErrorF("winReorderWindowsMultiWindow - " |
| 759 | "exit because fRestacking == TRUE\n"); |
| 760 | #endif |
| 761 | return; |
| 762 | } |
| 763 | fRestacking = TRUE; |
| 764 | |
| 765 | /* Loop through top level Window windows, descending in Z order */ |
| 766 | for (hwnd = GetTopWindow(NULL); |
| 767 | hwnd; hwnd = GetNextWindow(hwnd, GW_HWNDNEXT)) { |
| 768 | /* Don't take care of other Cygwin/X process's windows */ |
| 769 | GetWindowThreadProcessId(hwnd, &dwWindowProcessID); |
| 770 | |
| 771 | if (GetProp(hwnd, WIN_WINDOW_PROP) |
| 772 | && (dwWindowProcessID == dwCurrentProcessID) |
| 773 | && !IsIconic(hwnd)) { /* ignore minimized windows */ |
| 774 | pWinSib = pWin; |
| 775 | pWin = GetProp(hwnd, WIN_WINDOW_PROP); |
| 776 | |
| 777 | if (!pWinSib) { /* 1st window - raise to the top */ |
| 778 | vlist[0] = Above; |
| 779 | |
| 780 | ConfigureWindow(pWin, CWStackMode, vlist, wClient(pWin)); |
| 781 | } |
| 782 | else { /* 2nd or deeper windows - just below the previous one */ |
| 783 | vlist[0] = winGetWindowID(pWinSib); |
| 784 | vlist[1] = Below; |
| 785 | |
| 786 | ConfigureWindow(pWin, CWSibling | CWStackMode, |
| 787 | vlist, wClient(pWin)); |
| 788 | } |
| 789 | } |
| 790 | } |
| 791 | |
| 792 | fRestacking = FALSE; |
| 793 | } |
| 794 | |
| 795 | /* |
| 796 | * winMinimizeWindow - Minimize in response to WM_CHANGE_STATE |
| 797 | */ |
| 798 | |
| 799 | void |
| 800 | winMinimizeWindow(Window id) |
| 801 | { |
| 802 | WindowPtr pWin; |
| 803 | winPrivWinPtr pWinPriv; |
| 804 | |
| 805 | #ifdef XWIN_MULTIWINDOWEXTWM |
| 806 | win32RootlessWindowPtr pRLWinPriv; |
| 807 | #endif |
| 808 | HWND hWnd; |
| 809 | ScreenPtr pScreen = NULL; |
| 810 | winPrivScreenPtr pScreenPriv = NULL; |
| 811 | |
| 812 | #if CYGWINDOWING_DEBUG |
| 813 | ErrorF("winMinimizeWindow\n"); |
| 814 | #endif |
| 815 | |
| 816 | dixLookupResourceByType((pointer) &pWin, id, RT_WINDOW, NullClient, |
| 817 | DixUnknownAccess); |
| 818 | if (!pWin) { |
| 819 | ErrorF("%s: NULL pWin. Leaving\n", __FUNCTION__); |
| 820 | return; |
| 821 | } |
| 822 | |
| 823 | pScreen = pWin->drawable.pScreen; |
| 824 | if (pScreen) |
| 825 | pScreenPriv = winGetScreenPriv(pScreen); |
| 826 | |
| 827 | #ifdef XWIN_MULTIWINDOWEXTWM |
| 828 | if (pScreenPriv && pScreenPriv->pScreenInfo->fInternalWM) { |
| 829 | pRLWinPriv = |
| 830 | (win32RootlessWindowPtr) RootlessFrameForWindow(pWin, FALSE); |
| 831 | hWnd = pRLWinPriv->hWnd; |
| 832 | } |
| 833 | else |
| 834 | #else |
| 835 | if (pScreenPriv) |
| 836 | #endif |
| 837 | { |
| 838 | pWinPriv = winGetWindowPriv(pWin); |
| 839 | hWnd = pWinPriv->hWnd; |
| 840 | } |
| 841 | |
| 842 | ShowWindow(hWnd, SW_MINIMIZE); |
| 843 | } |
| 844 | |
| 845 | /* |
| 846 | * CopyWindow - See Porting Layer Definition - p. 39 |
| 847 | */ |
| 848 | void |
| 849 | winCopyWindowMultiWindow(WindowPtr pWin, DDXPointRec oldpt, RegionPtr oldRegion) |
| 850 | { |
| 851 | ScreenPtr pScreen = pWin->drawable.pScreen; |
| 852 | |
| 853 | winScreenPriv(pScreen); |
| 854 | |
| 855 | #if CYGWINDOWING_DEBUG |
| 856 | ErrorF("CopyWindowMultiWindow\n"); |
| 857 | #endif |
| 858 | WIN_UNWRAP(CopyWindow); |
| 859 | (*pScreen->CopyWindow) (pWin, oldpt, oldRegion); |
| 860 | WIN_WRAP(CopyWindow, winCopyWindowMultiWindow); |
| 861 | } |
| 862 | |
| 863 | /* |
| 864 | * MoveWindow - See Porting Layer Definition - p. 42 |
| 865 | */ |
| 866 | void |
| 867 | winMoveWindowMultiWindow(WindowPtr pWin, int x, int y, |
| 868 | WindowPtr pSib, VTKind kind) |
| 869 | { |
| 870 | ScreenPtr pScreen = pWin->drawable.pScreen; |
| 871 | |
| 872 | winScreenPriv(pScreen); |
| 873 | |
| 874 | #if CYGWINDOWING_DEBUG |
| 875 | ErrorF("MoveWindowMultiWindow to (%d, %d)\n", x, y); |
| 876 | #endif |
| 877 | |
| 878 | WIN_UNWRAP(MoveWindow); |
| 879 | (*pScreen->MoveWindow) (pWin, x, y, pSib, kind); |
| 880 | WIN_WRAP(MoveWindow, winMoveWindowMultiWindow); |
| 881 | } |
| 882 | |
| 883 | /* |
| 884 | * ResizeWindow - See Porting Layer Definition - p. 42 |
| 885 | */ |
| 886 | void |
| 887 | winResizeWindowMultiWindow(WindowPtr pWin, int x, int y, unsigned int w, |
| 888 | unsigned int h, WindowPtr pSib) |
| 889 | { |
| 890 | ScreenPtr pScreen = pWin->drawable.pScreen; |
| 891 | |
| 892 | winScreenPriv(pScreen); |
| 893 | |
| 894 | #if CYGWINDOWING_DEBUG |
| 895 | ErrorF("ResizeWindowMultiWindow to (%d, %d) - %dx%d\n", x, y, w, h); |
| 896 | #endif |
| 897 | WIN_UNWRAP(ResizeWindow); |
| 898 | (*pScreen->ResizeWindow) (pWin, x, y, w, h, pSib); |
| 899 | WIN_WRAP(ResizeWindow, winResizeWindowMultiWindow); |
| 900 | } |
| 901 | |
| 902 | /* |
| 903 | * winAdjustXWindow |
| 904 | * |
| 905 | * Move and resize X window with respect to corresponding Windows window. |
| 906 | * This is called from WM_MOVE/WM_SIZE handlers when the user performs |
| 907 | * any windowing operation (move, resize, minimize, maximize, restore). |
| 908 | * |
| 909 | * The functionality is the inverse of winPositionWindowMultiWindow, which |
| 910 | * adjusts Windows window with respect to X window. |
| 911 | */ |
| 912 | int |
| 913 | winAdjustXWindow(WindowPtr pWin, HWND hwnd) |
| 914 | { |
| 915 | RECT rcDraw; /* Rect made from pWin->drawable to be adjusted */ |
| 916 | RECT rcWin; /* The source: WindowRect from hwnd */ |
| 917 | DrawablePtr pDraw; |
| 918 | XID vlist[4]; |
| 919 | LONG dX, dY, dW, dH, x, y; |
| 920 | DWORD dwStyle, dwExStyle; |
| 921 | |
| 922 | #define WIDTH(rc) (rc.right - rc.left) |
| 923 | #define HEIGHT(rc) (rc.bottom - rc.top) |
| 924 | |
| 925 | #if CYGWINDOWING_DEBUG |
| 926 | ErrorF("winAdjustXWindow\n"); |
| 927 | #endif |
| 928 | |
| 929 | if (IsIconic(hwnd)) { |
| 930 | #if CYGWINDOWING_DEBUG |
| 931 | ErrorF("\timmediately return because the window is iconized\n"); |
| 932 | #endif |
| 933 | /* |
| 934 | * If the Windows window is minimized, its WindowRect has |
| 935 | * meaningless values so we don't adjust X window to it. |
| 936 | */ |
| 937 | vlist[0] = 0; |
| 938 | vlist[1] = 0; |
| 939 | return ConfigureWindow(pWin, CWX | CWY, vlist, wClient(pWin)); |
| 940 | } |
| 941 | |
| 942 | pDraw = &pWin->drawable; |
| 943 | |
| 944 | /* Calculate the window rect from the drawable */ |
| 945 | x = pDraw->x + GetSystemMetrics(SM_XVIRTUALSCREEN); |
| 946 | y = pDraw->y + GetSystemMetrics(SM_YVIRTUALSCREEN); |
| 947 | SetRect(&rcDraw, x, y, x + pDraw->width, y + pDraw->height); |
| 948 | #ifdef CYGMULTIWINDOW_DEBUG |
| 949 | winDebug("\tDrawable extend {%d, %d, %d, %d}, {%d, %d}\n", |
| 950 | rcDraw.left, rcDraw.top, rcDraw.right, rcDraw.bottom, |
| 951 | rcDraw.right - rcDraw.left, rcDraw.bottom - rcDraw.top); |
| 952 | #endif |
| 953 | dwExStyle = GetWindowLongPtr(hwnd, GWL_EXSTYLE); |
| 954 | dwStyle = GetWindowLongPtr(hwnd, GWL_STYLE); |
| 955 | #ifdef CYGMULTIWINDOW_DEBUG |
| 956 | winDebug("\tWindowStyle: %08x %08x\n", dwStyle, dwExStyle); |
| 957 | #endif |
| 958 | AdjustWindowRectEx(&rcDraw, dwStyle, FALSE, dwExStyle); |
| 959 | |
| 960 | /* The source of adjust */ |
| 961 | GetWindowRect(hwnd, &rcWin); |
| 962 | #ifdef CYGMULTIWINDOW_DEBUG |
| 963 | winDebug("\tWindow extend {%d, %d, %d, %d}, {%d, %d}\n", |
| 964 | rcWin.left, rcWin.top, rcWin.right, rcWin.bottom, |
| 965 | rcWin.right - rcWin.left, rcWin.bottom - rcWin.top); |
| 966 | winDebug("\tDraw extend {%d, %d, %d, %d}, {%d, %d}\n", |
| 967 | rcDraw.left, rcDraw.top, rcDraw.right, rcDraw.bottom, |
| 968 | rcDraw.right - rcDraw.left, rcDraw.bottom - rcDraw.top); |
| 969 | #endif |
| 970 | |
| 971 | if (EqualRect(&rcDraw, &rcWin)) { |
| 972 | /* Bail if no adjust is needed */ |
| 973 | #if CYGWINDOWING_DEBUG |
| 974 | ErrorF("\treturn because already adjusted\n"); |
| 975 | #endif |
| 976 | return 0; |
| 977 | } |
| 978 | |
| 979 | /* Calculate delta values */ |
| 980 | dX = rcWin.left - rcDraw.left; |
| 981 | dY = rcWin.top - rcDraw.top; |
| 982 | dW = WIDTH(rcWin) - WIDTH(rcDraw); |
| 983 | dH = HEIGHT(rcWin) - HEIGHT(rcDraw); |
| 984 | |
| 985 | /* |
| 986 | * Adjust. |
| 987 | * We may only need to move (vlist[0] and [1]), or only resize |
| 988 | * ([2] and [3]) but currently we set all the parameters and leave |
| 989 | * the decision to ConfigureWindow. The reason is code simplicity. |
| 990 | */ |
| 991 | vlist[0] = pDraw->x + dX - wBorderWidth(pWin); |
| 992 | vlist[1] = pDraw->y + dY - wBorderWidth(pWin); |
| 993 | vlist[2] = pDraw->width + dW; |
| 994 | vlist[3] = pDraw->height + dH; |
| 995 | #if CYGWINDOWING_DEBUG |
| 996 | ErrorF("\tConfigureWindow to (%ld, %ld) - %ldx%ld\n", vlist[0], vlist[1], |
| 997 | vlist[2], vlist[3]); |
| 998 | #endif |
| 999 | return ConfigureWindow(pWin, CWX | CWY | CWWidth | CWHeight, |
| 1000 | vlist, wClient(pWin)); |
| 1001 | |
| 1002 | #undef WIDTH |
| 1003 | #undef HEIGHT |
| 1004 | } |