1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS Win32k subsystem 4 * PURPOSE: Focus functions 5 * FILE: win32ss/user/ntuser/focus.c 6 * PROGRAMER: ReactOS Team 7 */ 8 9 #include <win32k.h> 10 #include <immdev.h> 11 DBG_DEFAULT_CHANNEL(UserFocus); 12 13 PUSER_MESSAGE_QUEUE gpqForeground = NULL; 14 PUSER_MESSAGE_QUEUE gpqForegroundPrev = NULL; 15 PTHREADINFO gptiForeground = NULL; 16 PPROCESSINFO gppiLockSFW = NULL; 17 ULONG guSFWLockCount = 0; // Rule #8, No menus are active. So should be zero. 18 PTHREADINFO ptiLastInput = NULL; 19 HWND ghwndOldFullscreen = NULL; 20 21 /* 22 Check locking of a process or one or more menus are active. 23 */ 24 BOOL FASTCALL 25 IsFGLocked(VOID) 26 { 27 return (gppiLockSFW || guSFWLockCount); 28 } 29 30 /* 31 Get capture window via foreground Queue. 32 */ 33 HWND FASTCALL 34 IntGetCaptureWindow(VOID) 35 { 36 PUSER_MESSAGE_QUEUE ForegroundQueue = IntGetFocusMessageQueue(); 37 return ( ForegroundQueue ? (ForegroundQueue->spwndCapture ? UserHMGetHandle(ForegroundQueue->spwndCapture) : 0) : 0); 38 } 39 40 HWND FASTCALL 41 IntGetThreadFocusWindow(VOID) 42 { 43 PTHREADINFO pti; 44 PUSER_MESSAGE_QUEUE ThreadQueue; 45 46 pti = PsGetCurrentThreadWin32Thread(); 47 ThreadQueue = pti->MessageQueue; 48 if (!ThreadQueue) 49 return NULL; 50 return ThreadQueue->spwndFocus ? UserHMGetHandle(ThreadQueue->spwndFocus) : 0; 51 } 52 53 BOOL FASTCALL IntIsWindowFullscreen(PWND Window) 54 { 55 RECTL rclAnd, rclMonitor, rclWindow; 56 PMONITOR pMonitor; 57 58 if (!Window || !(Window->style & WS_VISIBLE) || (Window->style & WS_CHILD) || 59 (Window->ExStyle & WS_EX_TOOLWINDOW) || !IntGetWindowRect(Window, &rclWindow)) 60 { 61 return FALSE; 62 } 63 64 pMonitor = UserGetPrimaryMonitor(); 65 if (!pMonitor) 66 { 67 RECTL_vSetRect(&rclMonitor, 0, 0, 68 UserGetSystemMetrics(SM_CXSCREEN), UserGetSystemMetrics(SM_CYSCREEN)); 69 } 70 else 71 { 72 rclMonitor = *(LPRECTL)&pMonitor->rcMonitor; 73 } 74 75 RECTL_bIntersectRect(&rclAnd, &rclMonitor, &rclWindow); 76 return RtlEqualMemory(&rclAnd, &rclMonitor, sizeof(RECTL)); 77 } 78 79 BOOL FASTCALL IntCheckFullscreen(PWND Window) 80 { 81 HWND hWnd; 82 83 if (ghwndOldFullscreen && !IntIsWindowFullscreen(ValidateHwndNoErr(ghwndOldFullscreen))) 84 ghwndOldFullscreen = NULL; 85 86 if (!IntIsWindowFullscreen(Window)) 87 return FALSE; 88 89 hWnd = UserHMGetHandle(Window); 90 if (ghwndOldFullscreen != hWnd) 91 { 92 co_IntShellHookNotify(HSHELL_RUDEAPPACTIVATED, (WPARAM)hWnd, TRUE); 93 ghwndOldFullscreen = hWnd; 94 } 95 return TRUE; 96 } 97 98 VOID FASTCALL 99 UpdateShellHook(PWND Window) 100 { 101 if (IntCheckFullscreen(Window)) 102 return; 103 104 if ( Window->spwndParent == UserGetDesktopWindow() && 105 (!(Window->ExStyle & WS_EX_TOOLWINDOW) || 106 (Window->ExStyle & WS_EX_APPWINDOW))) 107 { 108 // FIXME lParam; The value is TRUE if the window is in full-screen mode, or FALSE otherwise. 109 co_IntShellHookNotify(HSHELL_WINDOWACTIVATED, (WPARAM) UserHMGetHandle(Window), FALSE); 110 } 111 else 112 { 113 co_IntShellHookNotify(HSHELL_WINDOWACTIVATED, 0, FALSE); 114 } 115 } 116 117 BOOL FASTCALL 118 co_IntSendDeactivateMessages(HWND hWndPrev, HWND hWnd, BOOL Clear) 119 { 120 USER_REFERENCE_ENTRY RefPrev; 121 PWND WndPrev; 122 BOOL Ret = TRUE; 123 LPARAM lParam = hWnd ? (LPARAM)hWnd : 0; 124 125 if (hWndPrev && (WndPrev = ValidateHwndNoErr(hWndPrev))) 126 { 127 UserRefObjectCo(WndPrev, &RefPrev); 128 129 if (co_IntSendMessage(hWndPrev, WM_NCACTIVATE, FALSE, lParam)) 130 { 131 co_IntSendMessage(hWndPrev, WM_ACTIVATE, 132 MAKEWPARAM(WA_INACTIVE, (WndPrev->style & WS_MINIMIZE) != 0), 133 (LPARAM)hWnd); 134 135 if (WndPrev && Clear) 136 WndPrev->state &= ~(WNDS_ACTIVEFRAME|WNDS_HASCAPTION); 137 } 138 else 139 { 140 ERR("Application is keeping itself Active to prevent the change!\n"); 141 Ret = FALSE; 142 } 143 144 UserDerefObjectCo(WndPrev); 145 } 146 return Ret; 147 } 148 149 // Win: xxxFocusSetInputContext 150 VOID IntFocusSetInputContext(PWND pWnd, BOOL bActivate, BOOL bCallback) 151 { 152 PTHREADINFO pti; 153 PWND pImeWnd; 154 USER_REFERENCE_ENTRY Ref; 155 HWND hImeWnd; 156 WPARAM wParam; 157 LPARAM lParam; 158 159 if (!pWnd || !pWnd->pcls || IS_WND_IMELIKE(pWnd)) 160 return; 161 162 pti = pWnd->head.pti; 163 if (!pti || (pti->TIF_flags & TIF_INCLEANUP)) 164 return; 165 166 pImeWnd = pti->spwndDefaultIme; 167 if (!pImeWnd) 168 return; 169 170 UserRefObjectCo(pImeWnd, &Ref); 171 172 hImeWnd = UserHMGetHandle(pImeWnd); 173 wParam = (bActivate ? IMS_IMEACTIVATE : IMS_IMEDEACTIVATE); 174 lParam = (LPARAM)UserHMGetHandle(pWnd); 175 176 if (bCallback) 177 co_IntSendMessageWithCallBack(hImeWnd, WM_IME_SYSTEM, wParam, lParam, NULL, 0, NULL); 178 else 179 co_IntSendMessage(hImeWnd, WM_IME_SYSTEM, wParam, lParam); 180 181 UserDerefObjectCo(pImeWnd); 182 } 183 184 // 185 // Deactivating the foreground message queue. 186 // 187 // Release Active, Capture and Focus Windows associated with this message queue. 188 // 189 // Win: xxxDeactivate 190 BOOL FASTCALL 191 IntDeactivateWindow(PTHREADINFO pti, HANDLE tid) 192 { 193 USER_REFERENCE_ENTRY Ref; 194 PTHREADINFO ptiPrev; 195 PWND pwndPrev; 196 BOOL InAAPM = FALSE; 197 PTHREADINFO ptiCurrent = PsGetCurrentThreadWin32Thread(); 198 199 if ( !pti->MessageQueue->spwndActive ) 200 { 201 TRACE("IDAW E : Nothing to do, Active is NULL! pti 0x%p tid 0x%p\n",pti,tid); 202 return TRUE; 203 } 204 205 TRACE("IDAW : pti 0x%p tid 0x%p\n",pti,tid); 206 207 if (ptiCurrent != pti) 208 { 209 IntReferenceThreadInfo(pti); 210 IntReferenceThreadInfo(ptiCurrent); 211 } 212 213 if (!(pti->TIF_flags & TIF_INACTIVATEAPPMSG) ) 214 { 215 pti->TIF_flags |= TIF_INACTIVATEAPPMSG; 216 InAAPM = TRUE; 217 } 218 219 // 220 // Check for Capture and release it. 221 // 222 if ( pti->MessageQueue->spwndCapture ) 223 { 224 MSG msg; 225 PWND pwndCapture = pti->MessageQueue->spwndCapture; 226 227 UserRefObjectCo(pwndCapture, &Ref); 228 co_IntSendMessage(UserHMGetHandle(pwndCapture), WM_CANCELMODE, 0, 0); 229 UserDerefObjectCo(pwndCapture); 230 231 /* Generate mouse move message */ 232 msg.message = WM_MOUSEMOVE; 233 msg.wParam = UserGetMouseButtonsState(); 234 msg.lParam = MAKELPARAM(gpsi->ptCursor.x, gpsi->ptCursor.y); 235 msg.pt = gpsi->ptCursor; 236 co_MsqInsertMouseMessage(&msg, 0, 0, TRUE); 237 } 238 239 // 240 // Check for Active and release it. 241 // 242 if ( pti->MessageQueue->spwndActive ) 243 { 244 pwndPrev = pti->MessageQueue->spwndActive; 245 ptiPrev = pwndPrev->head.pti; 246 247 if (!co_IntSendDeactivateMessages(UserHMGetHandle(pwndPrev), 0, TRUE)) 248 { 249 if (InAAPM) pti->TIF_flags &= ~TIF_INACTIVATEAPPMSG; 250 if (ptiCurrent != pti) 251 { 252 IntDereferenceThreadInfo(pti); 253 IntDereferenceThreadInfo(ptiCurrent); 254 } 255 return FALSE; 256 } 257 258 if ( pti->MessageQueue->spwndActive == pwndPrev ) 259 { 260 pti->MessageQueue->spwndActivePrev = pwndPrev; 261 pti->MessageQueue->spwndActive = NULL; 262 } 263 264 if (ptiPrev->TIF_flags & TIF_INCLEANUP) ptiPrev = NULL; 265 } 266 else 267 { 268 ptiPrev = pti; 269 pwndPrev = (PWND)-1; // Avoid zero Active window. 270 } 271 272 if ( ptiPrev ) 273 { 274 HANDLE OldTID = PsGetThreadId(ptiPrev->pEThread); 275 PWND cWindow; 276 HWND *List, *phWnd; 277 278 List = IntWinListChildren(UserGetDesktopWindow()); 279 if ( List ) 280 { 281 if ( OldTID ) 282 { 283 for (phWnd = List; *phWnd; ++phWnd) 284 { 285 cWindow = ValidateHwndNoErr(*phWnd); 286 if ( cWindow && cWindow->head.pti == ptiPrev ) 287 { // FALSE if the window is being deactivated, 288 // ThreadId that owns the window being activated. 289 //ERR("IDW : WM_ACTIVATEAPP(0) hwnd %p tid Old %p New %p\n",UserHMGetHandle(cWindow),OldTID,tid); 290 UserRefObjectCo(cWindow, &Ref); 291 co_IntSendMessage(*phWnd, WM_ACTIVATEAPP, FALSE, (LPARAM)tid); 292 UserDerefObjectCo(cWindow); 293 } 294 } 295 } 296 ExFreePoolWithTag(List, USERTAG_WINDOWLIST); 297 } 298 } 299 300 // 301 // Now check for a change (Bounce), if Active same as previous window, release it too. 302 // 303 if ( pti->MessageQueue->spwndActive == pwndPrev ) 304 { 305 if (!co_IntSendDeactivateMessages(UserHMGetHandle(pwndPrev), 0, FALSE)) 306 { 307 if (InAAPM) pti->TIF_flags &= ~TIF_INACTIVATEAPPMSG; 308 if (ptiCurrent != pti) 309 { 310 IntDereferenceThreadInfo(pti); 311 IntDereferenceThreadInfo(ptiCurrent); 312 } 313 return FALSE; 314 } 315 316 if ( pti->MessageQueue->spwndActive == pwndPrev ) 317 { 318 pti->MessageQueue->spwndActivePrev = pwndPrev; 319 pti->MessageQueue->spwndActive = NULL; 320 } 321 } 322 323 // 324 // Check for Focus and release it. 325 // 326 if ( pti->MessageQueue->spwndFocus ) 327 { 328 PWND pwndFocus = pti->MessageQueue->spwndFocus; 329 330 // 331 // Fix win.c:test_SetForegroundWindow:SetActiveWindow(0)! 332 // 333 pti->MessageQueue->spwndFocus = NULL; // Null out Focus. 334 335 UserRefObjectCo(pwndFocus, &Ref); 336 co_IntSendMessage(UserHMGetHandle(pwndFocus), WM_KILLFOCUS, 0, 0); 337 if (IS_IMM_MODE()) 338 { 339 IntFocusSetInputContext(pwndFocus, FALSE, FALSE); 340 } 341 UserDerefObjectCo(pwndFocus); 342 } 343 344 /* Check for keyboard modifiers and release them (CORE-14768) */ 345 MsqReleaseModifierKeys(pti->MessageQueue); 346 347 if (InAAPM) pti->TIF_flags &= ~TIF_INACTIVATEAPPMSG; 348 if (ptiCurrent != pti) 349 { 350 IntDereferenceThreadInfo(pti); 351 IntDereferenceThreadInfo(ptiCurrent); 352 } 353 return TRUE; 354 } 355 356 // 357 // Activating another threads foreground window after a switch. 358 // 359 VOID FASTCALL 360 IntActivateWindow(PWND Wnd, PTHREADINFO pti, HANDLE tid, DWORD Type) 361 { 362 USER_REFERENCE_ENTRY Ref; 363 PUSER_MESSAGE_QUEUE pmq = pti->MessageQueue; 364 365 if (Wnd) 366 { 367 Wnd = VerifyWnd(Wnd); 368 369 if (!Wnd) return; 370 371 UserRefObjectCo(Wnd, &Ref); 372 373 if (!gpqForeground) 374 { 375 // No foreground queue set. 376 co_IntSetForegroundMessageQueue( Wnd, pti, (BOOL)Type, 0); 377 } 378 else 379 { 380 // Same Active and Wnd. 381 if ( pmq->spwndActive == Wnd ) 382 { 383 WPARAM wParam = (Wnd->head.pti->MessageQueue == gpqForeground); 384 385 co_IntSendMessage( UserHMGetHandle(Wnd), WM_NCACTIVATE, wParam, 0); 386 387 if (wParam) 388 { 389 UpdateShellHook(Wnd); 390 391 co_WinPosSetWindowPos(Wnd, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE); 392 } 393 } 394 else // Not the same, set the active Wnd. 395 { 396 co_IntSetActiveWindow(Wnd,(BOOL)Type,TRUE,TRUE); 397 } 398 } 399 UserDerefObjectCo(Wnd); 400 } 401 else // Handle no Wnd! 402 { 403 if ( tid && // TID, 404 pmq->spwndActive && // Active WND not zero, 405 gpqForeground == pmq ) // Same message queues. 406 { 407 Wnd = pmq->spwndActive; // Use active window from current queue. 408 409 UserRefObjectCo(Wnd, &Ref); 410 411 co_IntSendMessage( UserHMGetHandle(Wnd), WM_NCACTIVATE, TRUE, 0); 412 413 UpdateShellHook(Wnd); 414 415 co_WinPosSetWindowPos(Wnd, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE); 416 417 UserDerefObjectCo(Wnd); 418 } 419 else if (gpqForeground != pmq) 420 { 421 // Not the same message queue so clear flags for foreground switching. 422 pti->TIF_flags &= ~TIF_ALLOWFOREGROUNDACTIVATE; 423 pti->ppi->W32PF_flags &= ~W32PF_ALLOWFOREGROUNDACTIVATE; 424 } 425 } 426 } 427 428 BOOL FASTCALL 429 co_IntMakeWindowActive(PWND Window) 430 { 431 PWND spwndOwner; 432 if (VerifyWnd(Window)) 433 { // Set last active for window and it's owner. 434 spwndOwner = Window; 435 while (spwndOwner->spwndOwner) 436 { 437 spwndOwner = spwndOwner->spwndOwner; 438 } 439 WndSetLastActive(spwndOwner, Window); 440 return TRUE; 441 } 442 ERR("MakeWindowActive Failed!\n"); 443 return FALSE; 444 } 445 446 BOOL FASTCALL 447 co_IntSendActivateMessages(PWND WindowPrev, PWND Window, BOOL MouseActivate, BOOL Async) 448 { 449 USER_REFERENCE_ENTRY Ref, RefPrev, RefCall; 450 HANDLE OldTID, NewTID; 451 PTHREADINFO pti, ptiOld, ptiNew; 452 BOOL InAAPM = FALSE; 453 454 //ERR("SendActivateMessages\n"); 455 456 pti = PsGetCurrentThreadWin32Thread(); 457 458 if (Window) 459 { 460 UserRefObjectCo(Window, &Ref); 461 462 if (WindowPrev) UserRefObjectCo(WindowPrev, &RefPrev); 463 464 pti->MessageQueue->QF_flags &= ~QF_EVENTDEACTIVATEREMOVED; 465 466 /* Send palette messages */ 467 if (gpsi->PUSIFlags & PUSIF_PALETTEDISPLAY && 468 //co_IntPostOrSendMessage(UserHMGetHandle(Window), WM_QUERYNEWPALETTE, 0, 0)) 469 co_IntSendMessage(UserHMGetHandle(Window), WM_QUERYNEWPALETTE, 0, 0)) 470 { 471 UserSendNotifyMessage( HWND_BROADCAST, 472 WM_PALETTEISCHANGING, 473 (WPARAM)UserHMGetHandle(Window), 474 0); 475 } 476 //// Fixes CORE-6434. 477 if (!(Window->style & WS_CHILD)) 478 { 479 PWND pwndTemp = co_GetDesktopWindow(Window)->spwndChild; 480 481 while (pwndTemp && !(pwndTemp->style & WS_VISIBLE)) pwndTemp = pwndTemp->spwndNext; 482 483 if (Window != pwndTemp || (WindowPrev && !IntIsWindowVisible(WindowPrev))) 484 { 485 if (!Async || pti->MessageQueue == gpqForeground) 486 { 487 UINT flags = SWP_NOSIZE | SWP_NOMOVE; 488 if (Window == pwndTemp) flags |= SWP_NOACTIVATE; 489 //ERR("co_IntSendActivateMessages SetWindowPos! Async %d pti Q == FGQ %d\n",Async,pti->MessageQueue == gpqForeground); 490 co_WinPosSetWindowPos(Window, HWND_TOP, 0, 0, 0, 0, flags); 491 } 492 } 493 } 494 //// 495 //// CORE-1161 and CORE-6651 496 if (Window->spwndPrev) 497 { 498 HWND *phwndTopLevel, *phwndCurrent; 499 PWND pwndCurrent, pwndDesktop; 500 501 pwndDesktop = co_GetDesktopWindow(Window);//UserGetDesktopWindow(); 502 if (Window->spwndParent == pwndDesktop ) 503 { 504 phwndTopLevel = IntWinListChildren(pwndDesktop); 505 phwndCurrent = phwndTopLevel; 506 while(*phwndCurrent) 507 { 508 pwndCurrent = UserGetWindowObject(*phwndCurrent); 509 510 if (pwndCurrent && pwndCurrent->spwndOwner == Window ) 511 { 512 co_WinPosSetWindowPos(pwndCurrent, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE); 513 } 514 phwndCurrent++; 515 } 516 ExFreePoolWithTag(phwndTopLevel, USERTAG_WINDOWLIST); 517 } 518 } 519 //// 520 } 521 522 OldTID = WindowPrev ? IntGetWndThreadId(WindowPrev) : NULL; 523 NewTID = Window ? IntGetWndThreadId(Window) : NULL; 524 ptiOld = WindowPrev ? WindowPrev->head.pti : NULL; 525 ptiNew = Window ? Window->head.pti : NULL; 526 527 //ERR("SendActivateMessage Old -> %x, New -> %x\n", OldTID, NewTID); 528 529 if (!(pti->TIF_flags & TIF_INACTIVATEAPPMSG) && 530 (OldTID != NewTID) ) 531 { 532 PWND cWindow; 533 HWND *List, *phWnd; 534 535 List = IntWinListChildren(UserGetDesktopWindow()); 536 if ( List ) 537 { 538 if ( OldTID ) 539 { 540 ptiOld->TIF_flags |= TIF_INACTIVATEAPPMSG; 541 // Note: Do not set pci flags, this does crash! 542 for (phWnd = List; *phWnd; ++phWnd) 543 { 544 cWindow = ValidateHwndNoErr(*phWnd); 545 if (cWindow && cWindow->head.pti == ptiOld) 546 { // FALSE if the window is being deactivated, 547 // ThreadId that owns the window being activated. 548 //ERR("SAM : WM_ACTIVATEAPP(0) tid Old %p New %p\n",OldTID,NewTID); 549 UserRefObjectCo(cWindow, &RefCall); 550 co_IntSendMessage(*phWnd, WM_ACTIVATEAPP, FALSE, (LPARAM)NewTID); 551 UserDerefObjectCo(cWindow); 552 } 553 } 554 ptiOld->TIF_flags &= ~TIF_INACTIVATEAPPMSG; 555 } 556 if ( NewTID ) 557 { //// Prevents a resource crash due to reentrance! 558 InAAPM = TRUE; 559 pti->TIF_flags |= TIF_INACTIVATEAPPMSG; 560 //// 561 for (phWnd = List; *phWnd; ++phWnd) 562 { 563 cWindow = ValidateHwndNoErr(*phWnd); 564 if (cWindow && cWindow->head.pti == ptiNew) 565 { // TRUE if the window is being activated, 566 // ThreadId that owns the window being deactivated. 567 //ERR("SAM : WM_ACTIVATEAPP(1) hwnd %p tid New %p Old %p\n",UserHMGetHandle(cWindow),NewTID,OldTID); 568 UserRefObjectCo(cWindow, &RefCall); 569 co_IntSendMessage(*phWnd, WM_ACTIVATEAPP, TRUE, (LPARAM)OldTID); 570 UserDerefObjectCo(cWindow); 571 } 572 } 573 } 574 ExFreePoolWithTag(List, USERTAG_WINDOWLIST); 575 } 576 } 577 578 if (Window) 579 { 580 if (WindowPrev) 581 UserDerefObjectCo(WindowPrev); // Now allow the previous window to die. 582 583 if (Window->state & WNDS_ACTIVEFRAME) 584 { // If already active frame do not allow NCPaint. 585 //ERR("SendActivateMessage Is Active Frame!\n"); 586 Window->state |= WNDS_NONCPAINT; 587 } 588 589 if (Window->style & WS_MINIMIZE) 590 { 591 TRACE("Widow was minimized\n"); 592 } 593 594 co_IntMakeWindowActive(Window); 595 596 co_IntSendMessage( UserHMGetHandle(Window), 597 WM_NCACTIVATE, 598 (WPARAM)(Window == (gpqForeground ? gpqForeground->spwndActive : NULL)), 599 0); 600 601 co_IntSendMessage( UserHMGetHandle(Window), 602 WM_ACTIVATE, 603 MAKEWPARAM(MouseActivate ? WA_CLICKACTIVE : WA_ACTIVE, (Window->style & WS_MINIMIZE) != 0), 604 (LPARAM)(WindowPrev ? UserHMGetHandle(WindowPrev) : 0)); 605 606 if (Window->style & WS_VISIBLE) 607 UpdateShellHook(Window); 608 609 Window->state &= ~WNDS_NONCPAINT; 610 611 UserDerefObjectCo(Window); 612 } 613 return InAAPM; 614 } 615 616 // Win: xxxSendFocusMessages 617 VOID FASTCALL 618 IntSendFocusMessages( PTHREADINFO pti, PWND pWnd) 619 { 620 PWND pWndPrev; 621 PUSER_MESSAGE_QUEUE ThreadQueue = pti->MessageQueue; // Queue can change... 622 HWND hwndPrev; 623 USER_REFERENCE_ENTRY Ref; 624 625 ThreadQueue->QF_flags &= ~QF_FOCUSNULLSINCEACTIVE; 626 if (!pWnd && ThreadQueue->spwndActive) 627 { 628 ThreadQueue->QF_flags |= QF_FOCUSNULLSINCEACTIVE; 629 } 630 631 pWndPrev = ThreadQueue->spwndFocus; 632 if (pWndPrev) 633 UserRefObjectCo(pWndPrev, &Ref); 634 635 /* check if the specified window can be set in the input data of a given queue */ 636 if (!pWnd || ThreadQueue == pWnd->head.pti->MessageQueue) 637 /* set the current thread focus window */ 638 ThreadQueue->spwndFocus = pWnd; 639 640 if (pWnd) 641 { 642 if (pWndPrev) 643 { 644 co_IntSendMessage(UserHMGetHandle(pWndPrev), WM_KILLFOCUS, (WPARAM)UserHMGetHandle(pWnd), 0); 645 if (IS_IMM_MODE()) 646 { 647 IntFocusSetInputContext(pWndPrev, FALSE, FALSE); 648 } 649 } 650 if (ThreadQueue->spwndFocus == pWnd) 651 { 652 if (IS_IMM_MODE()) 653 { 654 IntFocusSetInputContext(pWnd, TRUE, FALSE); 655 } 656 657 IntNotifyWinEvent(EVENT_OBJECT_FOCUS, pWnd, OBJID_CLIENT, CHILDID_SELF, 0); 658 659 hwndPrev = (pWndPrev ? UserHMGetHandle(pWndPrev) : NULL); 660 co_IntSendMessage(UserHMGetHandle(pWnd), WM_SETFOCUS, (WPARAM)hwndPrev, 0); 661 } 662 } 663 else 664 { 665 if (pWndPrev) 666 { 667 IntNotifyWinEvent(EVENT_OBJECT_FOCUS, NULL, OBJID_CLIENT, CHILDID_SELF, 0); 668 669 co_IntSendMessage(UserHMGetHandle(pWndPrev), WM_KILLFOCUS, 0, 0); 670 if (IS_IMM_MODE()) 671 { 672 IntFocusSetInputContext(pWndPrev, FALSE, FALSE); 673 } 674 } 675 } 676 677 if (pWndPrev) 678 UserDerefObjectCo(pWndPrev); 679 } 680 681 BOOL FASTCALL 682 FindRemoveEventMsg(PTHREADINFO pti, DWORD Event, DWORD EventLast) 683 { 684 PUSER_MESSAGE Message; 685 PLIST_ENTRY Entry; 686 BOOL Ret = FALSE; 687 688 Entry = pti->PostedMessagesListHead.Flink; 689 while (Entry != &pti->PostedMessagesListHead) 690 { 691 // Scan posted queue messages to see if we received async messages. 692 Message = CONTAINING_RECORD(Entry, USER_MESSAGE, ListEntry); 693 Entry = Entry->Flink; 694 695 if (Message->dwQEvent == EventLast) 696 { 697 //ERR("Event D/SAW: Last Activate/Deactivate %d\n", EventLast); 698 return Ret; 699 } 700 701 if (Message->dwQEvent == Event) 702 { 703 //ERR("Event D/SAW: Found one in the Post Msg Queue! Activate/Deactivate %d\n", Event); 704 ClearMsgBitsMask(pti, Message->QS_Flags); 705 MsqDestroyMessage(Message); 706 Ret = TRUE; 707 } 708 } 709 return Ret; 710 } 711 712 BOOL FASTCALL 713 ToggleFGActivate(PTHREADINFO pti) 714 { 715 BOOL Ret; 716 PPROCESSINFO ppi = pti->ppi; 717 718 Ret = !!(pti->TIF_flags & TIF_ALLOWFOREGROUNDACTIVATE); 719 if (Ret) 720 { 721 pti->TIF_flags &= ~TIF_ALLOWFOREGROUNDACTIVATE; 722 } 723 else 724 Ret = !!(ppi->W32PF_flags & W32PF_ALLOWFOREGROUNDACTIVATE); 725 726 if (Ret) 727 ppi->W32PF_flags &= ~W32PF_ALLOWFOREGROUNDACTIVATE; 728 //ERR("ToggleFGActivate is %d\n",Ret); 729 return Ret; 730 } 731 732 BOOL FASTCALL 733 IsAllowedFGActive(PTHREADINFO pti, PWND Wnd) 734 { 735 // Not allowed if one or more,, 736 if (!ToggleFGActivate(pti) || // bits not set, 737 pti->rpdesk != gpdeskInputDesktop || // not current Desktop, 738 pti->MessageQueue == gpqForeground || // if already the queue foreground, 739 IsFGLocked() || // foreground is locked, 740 (Wnd->ExStyle & WS_EX_NOACTIVATE)) // or, does not become the foreground window when the user clicks it. 741 { 742 return FALSE; 743 } 744 //ERR("IsAllowedFGActive is TRUE\n"); 745 return TRUE; 746 } 747 748 /* 749 Can the system force foreground from one or more conditions. 750 */ 751 BOOL FASTCALL 752 CanForceFG(PPROCESSINFO ppi) 753 { 754 if (!ptiLastInput || 755 ptiLastInput->ppi == ppi || 756 !gptiForeground || 757 gptiForeground->ppi == ppi || 758 ppi->W32PF_flags & (W32PF_ALLOWFOREGROUNDACTIVATE | W32PF_SETFOREGROUNDALLOWED) || 759 gppiInputProvider == ppi || 760 !gpqForeground 761 ) return TRUE; 762 //ERR("CanForceFG is FALSE\n"); 763 return FALSE; 764 } 765 766 // 767 // Switching out foreground message queues. 768 // 769 BOOL FASTCALL 770 co_IntSetForegroundMessageQueue( 771 _In_opt_ PWND Wnd, 772 _In_ PTHREADINFO pti, 773 _In_ BOOL MouseActivate, 774 _In_ DWORD Type ) 775 { 776 PTHREADINFO ptiChg, ptiPrev; 777 PUSER_MESSAGE_QUEUE pumq, pumqChg, pumqPrev; 778 BOOL Removed, Ret = TRUE; 779 780 if (Wnd && !VerifyWnd(Wnd)) 781 { 782 return FALSE; 783 } 784 785 if ( !gptiForeground || gptiForeground->TIF_flags & TIF_INCLEANUP ) 786 ptiPrev = NULL; 787 else 788 ptiPrev = gptiForeground; 789 790 if (Wnd) 791 { 792 ptiChg = Wnd->head.pti; 793 IntSetFocusMessageQueue(Wnd->head.pti->MessageQueue); 794 gptiForeground = Wnd->head.pti; 795 //ERR("Set Foreground pti 0x%p Q 0x%p hWnd 0x%p\n", Wnd->head.pti, Wnd->head.pti->MessageQueue, UserHMGetHandle(Wnd)); 796 } 797 else 798 { 799 ptiChg = NULL; 800 IntSetFocusMessageQueue(NULL); 801 gptiForeground = NULL; 802 //ERR("Set Foreground pti 0x0 Q 0x0 hWnd 0x0\n"); 803 } 804 805 // 806 // Process the changing out of the message queues. 807 // 808 if (gpqForegroundPrev != gpqForeground) 809 { 810 pumqPrev = NULL; 811 if ( ptiPrev && !(ptiPrev->TIF_flags & TIF_INCLEANUP) ) 812 { 813 pumqPrev = ptiPrev->MessageQueue; 814 } 815 816 pumq = pti ? pti->MessageQueue : NULL; 817 818 // Deactivate the previous message queue. 819 if (pumqPrev) 820 { 821 if ( pumq != pumqPrev ) 822 { 823 MSG Msg; 824 HWND hWndPrev = pumqPrev->spwndActive ? UserHMGetHandle(pumqPrev->spwndActive) : NULL; 825 HANDLE tid = gptiForeground ? PsGetThreadId(gptiForeground->pEThread) : NULL; // TID from changing Window PTI. 826 827 Msg.message = WM_ASYNC_SETACTIVEWINDOW; 828 Msg.hwnd = hWndPrev; 829 Msg.wParam = (WPARAM)pumqPrev->spwndActive; 830 Msg.lParam = 0; 831 Msg.time = 0; 832 //ERR("SFWAMQ : DAW P pti 0x%p tid 0x%p hWndPrev 0x%p\n",ptiPrev,tid,hWndPrev); 833 MsqPostMessage(ptiPrev, &Msg, FALSE, QS_EVENT, POSTEVENT_DAW, (LONG_PTR)tid); 834 } 835 } 836 837 pumqChg = NULL; 838 if ( ptiChg && !(ptiChg->TIF_flags & TIF_INCLEANUP) ) 839 { 840 pumqChg = ptiChg->MessageQueue; 841 } 842 843 pumq = pti ? pti->MessageQueue : NULL; 844 845 // Activate changing message queue. 846 if (pumqChg) 847 { 848 /* 849 Henri Verbeet, 850 What happens is that we get the WM_WINE_SETACTIVEWINDOW message sent by the 851 other thread after we already changed the foreground window back to our own 852 window. 853 */ 854 //ERR("SFWAMQ : 1\n"); 855 Removed = FindRemoveEventMsg(ptiChg, POSTEVENT_DAW, POSTEVENT_NONE); 856 857 if (pumqChg != pumq) 858 { 859 MSG Msg; 860 HWND hWnd = Wnd ? UserHMGetHandle(Wnd) : NULL; 861 HANDLE tid = ptiPrev ? PsGetThreadId(ptiPrev->pEThread) : NULL; 862 863 if (Removed) pumqChg->QF_flags |= QF_EVENTDEACTIVATEREMOVED; 864 865 Msg.message = WM_ASYNC_SETACTIVEWINDOW; 866 Msg.hwnd = hWnd; 867 Msg.wParam = (WPARAM)Wnd; 868 Msg.lParam = (LPARAM)tid; //// Fixme! Type flags? 869 Msg.time = 0; 870 //ERR("SFWAMQ : SAW P pti 0x%p tid 0x%p hWnd 0x%p\n",ptiChg,tid,hWnd); 871 MsqPostMessage(ptiChg, &Msg, FALSE, QS_EVENT, POSTEVENT_SAW, (LONG_PTR)Type|MouseActivate); 872 } 873 else // Current message queue same as changed message queue. 874 { 875 if (pumq->spwndActive == Wnd) 876 { 877 co_IntSendMessage( UserHMGetHandle(Wnd), WM_NCACTIVATE, TRUE, (LPARAM)UserHMGetHandle(Wnd)); 878 879 UpdateShellHook(Wnd); 880 881 co_WinPosSetWindowPos(Wnd, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE); 882 } 883 else 884 { 885 //ERR("SFWAMQ : SAW I pti 0x%p hWnd 0x%p\n", ptiChg, Wnd ? UserHMGetHandle(Wnd) : NULL); 886 Ret = co_IntSetActiveWindow(Wnd, MouseActivate, TRUE/*Type*/, FALSE); 887 //if (!Ret) ERR("SFWAMQ : ISAW : return error\n"); 888 return Ret; 889 } 890 } 891 } 892 893 // Handle same message queue after switch out. 894 pumqPrev = NULL; 895 if ( ptiPrev && !(ptiPrev->TIF_flags & TIF_INCLEANUP) ) 896 { 897 pumqPrev = ptiPrev->MessageQueue; 898 } 899 pumq = pti ? pti->MessageQueue : NULL; 900 901 if ( pumqPrev && pumq == pumqPrev ) 902 { 903 HANDLE tid = Wnd ? PsGetThreadId(Wnd->head.pti->pEThread) : NULL; 904 //ERR("SFWAMQ : DAW I pti 0x%p tid 0x%p hWnd 0x%p\n", ptiPrev, tid, Wnd ? UserHMGetHandle(Wnd) : NULL); 905 IntDeactivateWindow(pti, tid); 906 } 907 } 908 return Ret; 909 } 910 911 /* 912 MSDN: 913 The system restricts which processes can set the foreground window. A process 914 can set the foreground window only if one of the following conditions is true: 915 916 * The process is the foreground process. 917 * The process was started by the foreground process. 918 * The process received the last input event. 919 * There is no foreground process. 920 * The foreground process is being debugged. 921 * The foreground is not locked (see LockSetForegroundWindow). 922 * The foreground lock time-out has expired (see SPI_GETFOREGROUNDLOCKTIMEOUT in SystemParametersInfo). 923 * No menus are active. 924 */ 925 static 926 BOOL FASTCALL 927 co_IntSetForegroundAndFocusWindow( 928 _In_opt_ PWND Wnd, 929 _In_ BOOL MouseActivate, 930 _In_ BOOL bFlash ) 931 { 932 HWND hWnd = Wnd ? UserHMGetHandle(Wnd) : NULL; 933 PUSER_MESSAGE_QUEUE PrevForegroundQueue; 934 PTHREADINFO pti; 935 BOOL Ret = FALSE; 936 937 if (Wnd) ASSERT_REFS_CO(Wnd); 938 939 TRACE("SetForegroundAndFocusWindow(%x, %s)\n", hWnd, (MouseActivate ? "TRUE" : "FALSE")); 940 941 PrevForegroundQueue = IntGetFocusMessageQueue(); // Use this active desktop. 942 pti = PsGetCurrentThreadWin32Thread(); 943 944 if (Wnd && PrevForegroundQueue) 945 { // Same Window Q as foreground just do active. 946 if (Wnd->head.pti->MessageQueue == PrevForegroundQueue) 947 { 948 //ERR("Same Window Q as foreground just do active.\n"); 949 if (pti->MessageQueue == PrevForegroundQueue) 950 { // Same WQ and TQ go active. 951 //ERR("Same WQ and TQ go active.\n"); 952 Ret = IntUserSetActiveWindow(Wnd, MouseActivate, TRUE, FALSE); 953 } 954 else if (Wnd->head.pti->MessageQueue->spwndActive == Wnd) 955 { // Same WQ and it is active. 956 //ERR("Same WQ and it is active.\n"); 957 Ret = TRUE; 958 } 959 else 960 { // Same WQ as FG but not the same TQ send active. 961 //ERR("Same WQ as FG but not the same TQ send active.\n"); 962 MSG Msg; 963 PTHREADINFO ptiNew = Wnd->head.pti; 964 965 Msg.message = WM_ASYNC_SETACTIVEWINDOW; 966 Msg.hwnd = hWnd; 967 Msg.wParam = (WPARAM)Wnd; 968 Msg.lParam = 0; 969 Msg.time = 0; 970 //ERR("SFAFW 1 : SAW P pti 0x%p hWnd 0x%p\n",ptiNew,hWnd); 971 MsqPostMessage(ptiNew, &Msg, FALSE, QS_EVENT, POSTEVENT_SAW, (LONG_PTR)MouseActivate); 972 973 Ret = TRUE; 974 } 975 return Ret; 976 } 977 } 978 979 if ( (( !IsFGLocked() || pti->ppi == gppiInputProvider ) && 980 ( CanForceFG(pti->ppi) || pti->TIF_flags & (TIF_SYSTEMTHREAD|TIF_CSRSSTHREAD|TIF_ALLOWFOREGROUNDACTIVATE) )) || 981 pti->ppi == ppiScrnSaver 982 ) 983 { 984 985 ToggleFGActivate(pti); 986 987 return co_IntSetForegroundMessageQueue( Wnd, pti, MouseActivate, 0 ); 988 } 989 990 if (!Wnd) return FALSE; // No window, always return FALSE. 991 992 //// if (bFlash) FIXME : handle flash!!! 993 994 if (pti->MessageQueue == Wnd->head.pti->MessageQueue) 995 { 996 //ERR("Same PQ and WQ go active.\n"); 997 Ret = IntUserSetActiveWindow(Wnd, MouseActivate, TRUE, FALSE); 998 //if (!Ret) ERR("ISFAFW : IUSAW : return error\n"); 999 } 1000 else if (Wnd->head.pti->MessageQueue->spwndActive == Wnd) 1001 { 1002 TRACE("Same Active and Wnd.\n"); // Leave this for now. 1003 } 1004 else 1005 { 1006 //ERR("Activate Not same PQ and WQ and Wnd.\n"); 1007 //// CORE-10785 fix hang, ROSTESTS-208 allows test to run. 1008 MSG Msg; 1009 PTHREADINFO ptiNew = Wnd->head.pti; 1010 1011 Msg.message = WM_ASYNC_SETACTIVEWINDOW; 1012 Msg.hwnd = hWnd; 1013 Msg.wParam = (WPARAM)Wnd; 1014 Msg.lParam = 0; 1015 Msg.time = 0; 1016 //ERR("SFAFW 2 : SAW P pti 0x%p hWnd 0x%p\n",ptiNew,hWnd); 1017 MsqPostMessage(ptiNew, &Msg, FALSE, QS_EVENT, POSTEVENT_SAW, (LONG_PTR)MouseActivate); 1018 } 1019 // Always return FALSE. 1020 return FALSE; 1021 } 1022 1023 // 1024 // Set the Active Window. 1025 // 1026 BOOL FASTCALL 1027 co_IntSetActiveWindow( 1028 _In_ PWND Wnd, 1029 _In_ BOOL bMouse, 1030 _In_ BOOL bFocus, 1031 _In_ BOOL Async ) 1032 { 1033 PTHREADINFO pti; 1034 PUSER_MESSAGE_QUEUE ThreadQueue; 1035 PWND pWndChg, WndPrev; // State changes. 1036 HWND hWndPrev; 1037 HWND hWnd = 0; 1038 BOOL InAAPM; 1039 CBTACTIVATESTRUCT cbt; 1040 1041 //ERR("co_IntSetActiveWindow 1\n"); 1042 1043 pti = PsGetCurrentThreadWin32Thread(); 1044 ThreadQueue = pti->MessageQueue; 1045 ASSERT(ThreadQueue != 0); 1046 1047 pWndChg = ThreadQueue->spwndActive; // Keep to notify of a preemptive switch. 1048 hWndPrev = (pWndChg ? UserHMGetHandle(pWndChg) : NULL); 1049 1050 if ( !Wnd || Wnd == UserGetDesktopWindow() ) 1051 { 1052 //ERR("ISAW : NULL %p\n",Wnd); 1053 return FALSE; 1054 } 1055 1056 ASSERT_REFS_CO(Wnd); 1057 hWnd = UserHMGetHandle(Wnd); 1058 //ERR("co_IntSetActiveWindow 2 hWnd 0x%p\n",hWnd); 1059 1060 if (Wnd->ExStyle & WS_EX_NOACTIVATE) 1061 return TRUE; 1062 1063 /* check if the specified window can be set in the input data of a given queue */ 1064 if ( ThreadQueue != Wnd->head.pti->MessageQueue ) 1065 { 1066 //ERR("ISAW : Must have the same Message Queue\n"); 1067 return FALSE; 1068 } 1069 1070 if (!VerifyWnd(Wnd)) 1071 { 1072 //ERR("ISAW : Window is in Destroy!\n"); 1073 return FALSE; 1074 } 1075 1076 if ( Wnd == pWndChg ) 1077 { 1078 //ERR("ISAW : Nothing to do\n"); 1079 return TRUE; // Fix CORE-8780 and CORE-11979. See CORE-11324 for breakage. 1080 } 1081 1082 if ( Wnd->state & WNDS_BEINGACTIVATED ) return TRUE; 1083 1084 /* Call CBT hook chain */ 1085 cbt.fMouse = bMouse; 1086 cbt.hWndActive = hWndPrev; 1087 if (co_HOOK_CallHooks( WH_CBT, HCBT_ACTIVATE, (WPARAM)hWnd, (LPARAM)&cbt)) 1088 { 1089 ERR("SetActiveWindow: WH_CBT Call Hook return!\n"); 1090 return FALSE; 1091 } 1092 1093 ThreadQueue->QF_flags &= ~QF_EVENTDEACTIVATEREMOVED; 1094 1095 if ( ThreadQueue->spwndActive && ThreadQueue->spwndActive->state & WNDS_DESTROYED ) 1096 ThreadQueue->spwndActive = NULL; 1097 else 1098 ThreadQueue->spwndActivePrev = ThreadQueue->spwndActive; 1099 1100 WndPrev = ThreadQueue->spwndActive; // Keep to save changing active. 1101 1102 if (WndPrev) 1103 { 1104 if (ThreadQueue == gpqForeground) gpqForegroundPrev = ThreadQueue; 1105 if (!co_IntSendDeactivateMessages(UserHMGetHandle(WndPrev), hWnd, TRUE)) return FALSE; 1106 } 1107 1108 WndPrev = ThreadQueue->spwndActive; // Again keep to save changing active. 1109 1110 // While in calling message proc or hook: 1111 // Fail if a preemptive switch was made, current active not made previous, 1112 // focus window is dead or no longer the same thread queue. 1113 if ( ThreadQueue->spwndActivePrev != ThreadQueue->spwndActive || 1114 pWndChg != WndPrev || 1115 (Wnd && !VerifyWnd(Wnd)) || 1116 ThreadQueue != pti->MessageQueue ) 1117 { 1118 ERR("SetActiveWindow: Summary ERROR, active state changed!\n"); 1119 return FALSE; 1120 } 1121 1122 if (!WndPrev) ThreadQueue->QF_flags &= ~QF_FOCUSNULLSINCEACTIVE; 1123 1124 /* set the current thread active window */ 1125 ThreadQueue->spwndActive = Wnd; 1126 1127 // Set state flag to prevent recursions. 1128 Wnd->state |= WNDS_BEINGACTIVATED; 1129 1130 IntNotifyWinEvent(EVENT_SYSTEM_FOREGROUND, Wnd, OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI); 1131 1132 // Clear out activate EVENT messages. 1133 FindRemoveEventMsg(pti, POSTEVENT_SAW, POSTEVENT_DAW); 1134 1135 WndPrev = VerifyWnd(ThreadQueue->spwndActivePrev); // Now should be set but verify it again. 1136 1137 InAAPM = co_IntSendActivateMessages(WndPrev, Wnd, bMouse, Async); 1138 1139 /* now change focus if necessary */ 1140 //// Fixes CORE-6452 allows setting focus on window. 1141 if (bFocus && !(ThreadQueue->QF_flags & QF_FOCUSNULLSINCEACTIVE)) 1142 { 1143 /* Do not change focus if the window is no longer active */ 1144 if (pti->MessageQueue->spwndActive != IntGetNonChildAncestor(pti->MessageQueue->spwndFocus)) 1145 { 1146 PWND pWndSend = pti->MessageQueue->spwndActive; 1147 // Clear focus if the active window is minimized. 1148 if (pWndSend && pti->MessageQueue->spwndActive->style & WS_MINIMIZE) pWndSend = NULL; 1149 // Send focus messages and if so, set the focus. 1150 IntSendFocusMessages( pti, pWndSend); 1151 } 1152 } 1153 //// 1154 if (InAAPM) 1155 { 1156 pti->TIF_flags &= ~TIF_INACTIVATEAPPMSG; 1157 } 1158 1159 // Checked in MENU_TrackMenu 1160 ThreadQueue->QF_flags |= QF_ACTIVATIONCHANGE; 1161 1162 //ERR("co_IntSetActiveWindow Exit\n"); 1163 Wnd->state &= ~WNDS_BEINGACTIVATED; 1164 return (ThreadQueue->spwndActive == Wnd); 1165 } 1166 1167 // 1168 // Set the Active Window. 1169 // 1170 // Window is not optional! 1171 // 1172 BOOL FASTCALL 1173 IntUserSetActiveWindow( 1174 _In_ PWND Wnd, 1175 _In_ BOOL bMouse, 1176 _In_ BOOL bFocus, 1177 _In_ BOOL Async) 1178 { 1179 PTHREADINFO pti; 1180 PUSER_MESSAGE_QUEUE ThreadQueue; 1181 1182 //ERR("IntUserSetActiveWindow 1\n"); 1183 ASSERT_REFS_CO(Wnd); 1184 if ((Wnd->style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return FALSE; 1185 //ERR("IntUserSetActiveWindow 1a hWnd 0x%p\n",UserHMGetHandle(Wnd)); 1186 1187 //ERR("IntUserSetActiveWindow 2\n"); 1188 pti = PsGetCurrentThreadWin32Thread(); 1189 ThreadQueue = pti->MessageQueue; 1190 ASSERT(ThreadQueue != 0); 1191 1192 while (Wnd) 1193 { 1194 BOOL Ret, DoFG, AllowFG; 1195 1196 if (ThreadQueue == Wnd->head.pti->MessageQueue) 1197 { 1198 if (IsAllowedFGActive(pti, Wnd)) 1199 { 1200 DoFG = TRUE; 1201 } 1202 else 1203 { 1204 //ERR("IntUserSetActiveWindow 3 Go Out!\n"); 1205 break; 1206 } 1207 AllowFG = !pti->cVisWindows; // Nothing is visable. 1208 //ERR("IntUserSetActiveWindow 3a DoFG = %d AllowFG = %d\n",DoFG,AllowFG); 1209 } 1210 else //if (ThreadQueue != Wnd->head.pti->MessageQueue) 1211 { 1212 //PUSER_MESSAGE_QUEUE ForegroundQueue = IntGetFocusMessageQueue(); 1213 // Rule 1 & 4, We are foreground so set this FG window or NULL foreground.... 1214 if (!gpqForeground || gpqForeground == ThreadQueue) 1215 { 1216 DoFG = TRUE; 1217 } 1218 else 1219 DoFG = FALSE; 1220 if (DoFG) 1221 { 1222 if (pti->TIF_flags & TIF_ALLOWFOREGROUNDACTIVATE || pti->cVisWindows) 1223 AllowFG = TRUE; 1224 else 1225 AllowFG = FALSE; 1226 } 1227 else 1228 AllowFG = FALSE; 1229 //ERR("IntUserSetActiveWindow 3b DoFG = %d AllowFG = %d\n",DoFG,AllowFG); 1230 } 1231 Ret = FALSE; 1232 if (DoFG) 1233 { 1234 pti->TIF_flags |= TIF_ALLOWFOREGROUNDACTIVATE; 1235 //ERR("IntUserSetActiveWindow 3c FG set\n"); 1236 Ret = co_IntSetForegroundAndFocusWindow(Wnd, bMouse, TRUE); 1237 if (AllowFG) 1238 { 1239 pti->TIF_flags |= TIF_ALLOWFOREGROUNDACTIVATE; 1240 } 1241 else 1242 { 1243 pti->TIF_flags &= ~TIF_ALLOWFOREGROUNDACTIVATE; 1244 } 1245 } 1246 return Ret; 1247 } 1248 1249 return co_IntSetActiveWindow(Wnd, bMouse, bFocus, Async); 1250 } 1251 1252 BOOL FASTCALL 1253 co_IntMouseActivateWindow(PWND Wnd) 1254 { 1255 TRACE("Mouse Active\n"); 1256 if (Wnd && (Wnd->ExStyle & WS_EX_NOACTIVATE)) 1257 return TRUE; 1258 return co_IntSetForegroundAndFocusWindow(Wnd, TRUE, TRUE); 1259 } 1260 1261 /* Win: PWND xxxSetActiveWindow(Wnd) */ 1262 BOOL FASTCALL 1263 UserSetActiveWindow( _In_opt_ PWND Wnd ) 1264 { 1265 PTHREADINFO pti = PsGetCurrentThreadWin32Thread(); 1266 1267 if (Wnd) 1268 { 1269 if ((Wnd->style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return FALSE; 1270 1271 return IntUserSetActiveWindow(Wnd, FALSE, TRUE, FALSE); 1272 } 1273 /* 1274 Yes your eye are not deceiving you~! 1275 1276 First part of wines Win.c test_SetActiveWindow: 1277 1278 flush_events( TRUE ); 1279 ShowWindow(hwnd, SW_HIDE); 1280 SetFocus(0); 1281 SetActiveWindow(0); 1282 check_wnd_state(0, 0, 0, 0); <-- This should pass if ShowWindow does it's job!!! As of 10/28/2012 it does! 1283 1284 Now Handle wines Msg.c test_SetActiveWindow( 0 )... 1285 */ 1286 TRACE("USAW: Previous active window\n"); 1287 if ( gpqForegroundPrev && 1288 gpqForegroundPrev->spwndActivePrev && 1289 (gpqForegroundPrev->spwndActivePrev->style & (WS_VISIBLE|WS_DISABLED)) == WS_VISIBLE && 1290 !(gpqForegroundPrev->spwndActivePrev->state2 & WNDS2_BOTTOMMOST) && 1291 (Wnd = VerifyWnd(gpqForegroundPrev->spwndActivePrev)) != NULL ) 1292 { 1293 TRACE("USAW:PAW hwnd %p\n", UserHMGetHandle(Wnd)); 1294 return IntUserSetActiveWindow(Wnd, FALSE, TRUE, FALSE); 1295 } 1296 1297 // Activate anyone but the active window. 1298 if ( pti->MessageQueue->spwndActive && 1299 (Wnd = VerifyWnd(pti->MessageQueue->spwndActive)) != NULL ) 1300 { 1301 //ERR("USAW:AOWM hwnd %p\n", UserHMGetHandle(Wnd)); 1302 if (!ActivateOtherWindowMin(Wnd)) 1303 { 1304 // Okay, now go find someone else to play with! 1305 //ERR("USAW: Going to WPAOW\n"); 1306 co_WinPosActivateOtherWindow(Wnd); 1307 } 1308 return TRUE; 1309 } 1310 1311 TRACE("USAW: Nothing\n"); 1312 return FALSE; 1313 } 1314 1315 // Win: PWND xxxSetFocus(Window) 1316 HWND FASTCALL 1317 co_UserSetFocus(PWND Window) 1318 { 1319 HWND hWndPrev = 0; 1320 PWND pwndTop; 1321 PTHREADINFO pti; 1322 PUSER_MESSAGE_QUEUE ThreadQueue; 1323 1324 if (Window) 1325 ASSERT_REFS_CO(Window); 1326 1327 pti = PsGetCurrentThreadWin32Thread(); 1328 ThreadQueue = pti->MessageQueue; 1329 ASSERT(ThreadQueue != 0); 1330 1331 TRACE("Enter SetFocus hWnd 0x%p pti 0x%p\n",Window ? UserHMGetHandle(Window) : 0, pti ); 1332 1333 hWndPrev = ThreadQueue->spwndFocus ? UserHMGetHandle(ThreadQueue->spwndFocus) : 0; 1334 1335 if (Window != 0) 1336 { 1337 if (hWndPrev == UserHMGetHandle(Window)) 1338 { 1339 return hWndPrev ? (IntIsWindow(hWndPrev) ? hWndPrev : 0) : 0; /* Nothing to do */ 1340 } 1341 1342 if (Window->head.pti->MessageQueue != ThreadQueue) 1343 { 1344 ERR("SetFocus Must have the same Q!\n"); 1345 return 0; 1346 } 1347 1348 /* Check if we can set the focus to this window */ 1349 //// Fixes wine win test_SetParent both "todo" line 3710 and 3720... 1350 for (pwndTop = Window; pwndTop; pwndTop = pwndTop->spwndParent) 1351 { 1352 if (pwndTop->style & (WS_MINIMIZED|WS_DISABLED)) return 0; 1353 if ((pwndTop->style & (WS_POPUP|WS_CHILD)) != WS_CHILD) break; 1354 if (pwndTop->spwndParent == NULL) break; 1355 } 1356 //// 1357 if (co_HOOK_CallHooks( WH_CBT, HCBT_SETFOCUS, (WPARAM)UserHMGetHandle(Window), (LPARAM)hWndPrev)) 1358 { 1359 ERR("SetFocus 1 WH_CBT Call Hook return!\n"); 1360 return 0; 1361 } 1362 1363 /* Activate pwndTop if needed. */ 1364 if (pwndTop != ThreadQueue->spwndActive) 1365 { 1366 PUSER_MESSAGE_QUEUE ForegroundQueue = IntGetFocusMessageQueue(); // Keep it based on desktop. 1367 if (ThreadQueue != ForegroundQueue && IsAllowedFGActive(pti, pwndTop)) // Rule 2 & 3. 1368 { 1369 //ERR("SetFocus: Set Foreground!\n"); 1370 if (!(pwndTop->style & WS_VISIBLE)) 1371 { 1372 pti->ppi->W32PF_flags |= W32PF_ALLOWFOREGROUNDACTIVATE; 1373 } 1374 if (!co_IntSetForegroundAndFocusWindow(pwndTop, FALSE, TRUE)) 1375 { 1376 ERR("SetFocus: Set Foreground and Focus Failed!\n"); 1377 return 0; 1378 } 1379 } 1380 1381 /* Set Active when it is needed. */ 1382 if (pwndTop != ThreadQueue->spwndActive) 1383 { 1384 //ERR("SetFocus: Set Active! %p\n",pwndTop?UserHMGetHandle(pwndTop):0); 1385 if (!co_IntSetActiveWindow(pwndTop, FALSE, FALSE, FALSE)) 1386 { 1387 ERR("SetFocus: Set Active Failed!\n"); 1388 return 0; 1389 } 1390 } 1391 1392 /* Abort if window destroyed */ 1393 if (Window->state2 & WNDS2_INDESTROY) return 0; 1394 /* Do not change focus if the window is no longer active */ 1395 if (pwndTop != ThreadQueue->spwndActive) 1396 { 1397 ERR("SetFocus: Top window did not go active!\n"); 1398 return 0; 1399 } 1400 } 1401 1402 // Check again! SetActiveWindow could have set the focus via WM_ACTIVATE. 1403 hWndPrev = ThreadQueue->spwndFocus ? UserHMGetHandle(ThreadQueue->spwndFocus) : 0; 1404 1405 IntSendFocusMessages( pti, Window); 1406 1407 TRACE("Focus: %p -> %p\n", hWndPrev, UserHMGetHandle(Window)); 1408 } 1409 else /* NULL hwnd passed in */ 1410 { 1411 if (co_HOOK_CallHooks( WH_CBT, HCBT_SETFOCUS, (WPARAM)0, (LPARAM)hWndPrev)) 1412 { 1413 ERR("SetFocus: 2 WH_CBT Call Hook return!\n"); 1414 return 0; 1415 } 1416 //ERR("SetFocus: Set Focus NULL\n"); 1417 /* set the current thread focus window null */ 1418 IntSendFocusMessages( pti, NULL); 1419 } 1420 return hWndPrev ? (IntIsWindow(hWndPrev) ? hWndPrev : 0) : 0; 1421 } 1422 1423 HWND FASTCALL 1424 UserGetForegroundWindow(VOID) 1425 { 1426 PUSER_MESSAGE_QUEUE ForegroundQueue; 1427 1428 ForegroundQueue = IntGetFocusMessageQueue(); 1429 return( ForegroundQueue ? (ForegroundQueue->spwndActive ? UserHMGetHandle(ForegroundQueue->spwndActive) : 0) : 0); 1430 } 1431 1432 HWND FASTCALL UserGetActiveWindow(VOID) 1433 { 1434 PTHREADINFO pti; 1435 PUSER_MESSAGE_QUEUE ThreadQueue; 1436 1437 pti = PsGetCurrentThreadWin32Thread(); 1438 ThreadQueue = pti->MessageQueue; 1439 return( ThreadQueue ? (ThreadQueue->spwndActive ? UserHMGetHandle(ThreadQueue->spwndActive) : 0) : 0); 1440 } 1441 1442 HWND APIENTRY 1443 IntGetCapture(VOID) 1444 { 1445 PTHREADINFO pti; 1446 PUSER_MESSAGE_QUEUE ThreadQueue; 1447 HWND Ret; 1448 1449 TRACE("Enter IntGetCapture\n"); 1450 1451 pti = PsGetCurrentThreadWin32Thread(); 1452 ThreadQueue = pti->MessageQueue; 1453 Ret = ((ThreadQueue && ThreadQueue->spwndCapture) ? UserHMGetHandle(ThreadQueue->spwndCapture) : NULL); 1454 1455 TRACE("Leave IntGetCapture, ret=%p\n", Ret); 1456 return Ret; 1457 } 1458 1459 HWND FASTCALL 1460 co_UserSetCapture(HWND hWnd) 1461 { 1462 PTHREADINFO pti; 1463 PUSER_MESSAGE_QUEUE ThreadQueue; 1464 PWND pWnd, Window = NULL; 1465 HWND hWndPrev; 1466 1467 pti = PsGetCurrentThreadWin32Thread(); 1468 ThreadQueue = pti->MessageQueue; 1469 1470 if (ThreadQueue->QF_flags & QF_CAPTURELOCKED) 1471 return NULL; 1472 1473 if (hWnd && (Window = UserGetWindowObject(hWnd))) 1474 { 1475 if (Window->head.pti->MessageQueue != ThreadQueue) 1476 { 1477 ERR("Window Thread does not match Current!\n"); 1478 return NULL; 1479 } 1480 } 1481 1482 hWndPrev = MsqSetStateWindow(pti, MSQ_STATE_CAPTURE, hWnd); 1483 1484 if (hWndPrev) 1485 { 1486 pWnd = UserGetWindowObject(hWndPrev); 1487 if (pWnd) 1488 IntNotifyWinEvent(EVENT_SYSTEM_CAPTUREEND, pWnd, OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI); 1489 } 1490 1491 if (Window) 1492 IntNotifyWinEvent(EVENT_SYSTEM_CAPTURESTART, Window, OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI); 1493 1494 // 1495 // Only send the message if we have a previous Window! 1496 // Fix msg_menu tracking popup menu and win test_capture_4!!!! 1497 // 1498 if (hWndPrev) 1499 { 1500 if (ThreadQueue->MenuOwner && Window) ThreadQueue->QF_flags |= QF_CAPTURELOCKED; 1501 1502 co_IntSendMessage(hWndPrev, WM_CAPTURECHANGED, 0, (LPARAM)hWnd); 1503 1504 ThreadQueue->QF_flags &= ~QF_CAPTURELOCKED; 1505 } 1506 1507 if (hWnd == NULL) // Release mode. 1508 { 1509 MOUSEINPUT mi; 1510 /// These are HACKS! 1511 /* Also remove other windows if not capturing anymore */ 1512 MsqSetStateWindow(pti, MSQ_STATE_MENUOWNER, NULL); 1513 MsqSetStateWindow(pti, MSQ_STATE_MOVESIZE, NULL); 1514 /// 1515 /* Somebody may have missed some mouse movements */ 1516 mi.dx = 0; 1517 mi.dy = 0; 1518 mi.mouseData = 0; 1519 mi.dwFlags = MOUSEEVENTF_MOVE; 1520 mi.time = 0; 1521 mi.dwExtraInfo = 0; 1522 UserSendMouseInput(&mi, FALSE); 1523 } 1524 return hWndPrev; 1525 } 1526 1527 /* 1528 API Call 1529 */ 1530 BOOL 1531 FASTCALL 1532 IntReleaseCapture(VOID) 1533 { 1534 PTHREADINFO pti; 1535 PUSER_MESSAGE_QUEUE ThreadQueue; 1536 1537 pti = PsGetCurrentThreadWin32Thread(); 1538 ThreadQueue = pti->MessageQueue; 1539 1540 // Can not release inside WM_CAPTURECHANGED!! 1541 if (ThreadQueue->QF_flags & QF_CAPTURELOCKED) return FALSE; 1542 1543 co_UserSetCapture(NULL); 1544 1545 return TRUE; 1546 } 1547 1548 /* 1549 API Call 1550 */ 1551 BOOL FASTCALL 1552 co_IntSetForegroundWindow(PWND Window) 1553 { 1554 if (Window) ASSERT_REFS_CO(Window); 1555 1556 return co_IntSetForegroundAndFocusWindow(Window, FALSE, TRUE); 1557 } 1558 1559 /* 1560 API Call 1561 */ 1562 BOOL FASTCALL 1563 co_IntSetForegroundWindowMouse(PWND Window) 1564 { 1565 if (Window) ASSERT_REFS_CO(Window); 1566 1567 return co_IntSetForegroundAndFocusWindow(Window, TRUE, FALSE); 1568 } 1569 1570 /* 1571 API Call 1572 */ 1573 BOOL FASTCALL 1574 IntLockSetForegroundWindow(UINT uLockCode) 1575 { 1576 ULONG Err = ERROR_ACCESS_DENIED; 1577 PPROCESSINFO ppi = PsGetCurrentProcessWin32Process(); 1578 switch (uLockCode) 1579 { 1580 case LSFW_LOCK: 1581 if ( CanForceFG(ppi) && !gppiLockSFW ) 1582 { 1583 gppiLockSFW = ppi; 1584 return TRUE; 1585 } 1586 break; 1587 case LSFW_UNLOCK: 1588 if ( gppiLockSFW == ppi) 1589 { 1590 gppiLockSFW = NULL; 1591 return TRUE; 1592 } 1593 break; 1594 default: 1595 Err = ERROR_INVALID_PARAMETER; 1596 } 1597 EngSetLastError(Err); 1598 return FALSE; 1599 } 1600 1601 /* 1602 API Call 1603 */ 1604 BOOL FASTCALL 1605 IntAllowSetForegroundWindow(DWORD dwProcessId) 1606 { 1607 PPROCESSINFO ppi, ppiCur; 1608 PEPROCESS Process = NULL; 1609 1610 ppi = NULL; 1611 if (dwProcessId != ASFW_ANY) 1612 { 1613 if (!NT_SUCCESS(PsLookupProcessByProcessId(UlongToHandle(dwProcessId), &Process))) 1614 { 1615 EngSetLastError(ERROR_INVALID_PARAMETER); 1616 return FALSE; 1617 } 1618 ppi = PsGetProcessWin32Process(Process); 1619 if (!ppi) 1620 { 1621 ObDereferenceObject(Process); 1622 return FALSE; 1623 } 1624 } 1625 ppiCur = PsGetCurrentProcessWin32Process(); 1626 if (!CanForceFG(ppiCur)) 1627 { 1628 if (Process) ObDereferenceObject(Process); 1629 EngSetLastError(ERROR_ACCESS_DENIED); 1630 return FALSE; 1631 } 1632 if (dwProcessId == ASFW_ANY) 1633 { // All processes will be enabled to set the foreground window. 1634 //ERR("ptiLastInput is CLEARED!!\n"); 1635 ptiLastInput = NULL; 1636 } 1637 else 1638 { // Rule #3, last input event in force. 1639 ERR("ptiLastInput is SET!!\n"); 1640 //ptiLastInput = ppi->ptiList; // See CORE-6384 & CORE-7030. 1641 ObDereferenceObject(Process); 1642 } 1643 return TRUE; 1644 } 1645 1646 /* 1647 * @implemented 1648 */ 1649 HWND APIENTRY 1650 NtUserGetForegroundWindow(VOID) 1651 { 1652 HWND Ret; 1653 1654 TRACE("Enter NtUserGetForegroundWindow\n"); 1655 UserEnterExclusive(); 1656 1657 Ret = UserGetForegroundWindow(); 1658 1659 TRACE("Leave NtUserGetForegroundWindow, ret=%p\n", Ret); 1660 UserLeave(); 1661 return Ret; 1662 } 1663 1664 HWND APIENTRY 1665 NtUserSetActiveWindow(HWND hWnd) 1666 { 1667 USER_REFERENCE_ENTRY Ref; 1668 HWND hWndPrev; 1669 PWND Window, pwndPrev; 1670 HWND Ret = NULL; 1671 1672 TRACE("Enter NtUserSetActiveWindow(%p)\n", hWnd); 1673 UserEnterExclusive(); 1674 1675 Window = NULL; 1676 if (hWnd) 1677 { 1678 if (!(Window = UserGetWindowObject(hWnd))) 1679 { 1680 ERR("NtUserSetActiveWindow: Invalid handle 0x%p!\n",hWnd); 1681 goto Exit; // Return NULL 1682 } 1683 } 1684 1685 if (!Window || 1686 Window->head.pti->MessageQueue == gptiCurrent->MessageQueue) 1687 { 1688 pwndPrev = gptiCurrent->MessageQueue->spwndActive; 1689 hWndPrev = (pwndPrev ? UserHMGetHandle(pwndPrev) : NULL); 1690 if (Window) UserRefObjectCo(Window, &Ref); 1691 UserSetActiveWindow(Window); 1692 if (Window) UserDerefObjectCo(Window); 1693 Ret = ((hWndPrev && IntIsWindow(hWndPrev)) ? hWndPrev : NULL); 1694 } 1695 1696 Exit: 1697 TRACE("Leave NtUserSetActiveWindow, ret=%p\n", Ret); 1698 UserLeave(); 1699 return Ret; 1700 } 1701 1702 /* 1703 * @implemented 1704 */ 1705 HWND APIENTRY 1706 NtUserSetCapture(HWND hWnd) 1707 { 1708 HWND Ret; 1709 1710 TRACE("Enter NtUserSetCapture(%p)\n", hWnd); 1711 UserEnterExclusive(); 1712 1713 Ret = co_UserSetCapture(hWnd); 1714 1715 TRACE("Leave NtUserSetCapture, ret=%p\n", Ret); 1716 UserLeave(); 1717 return Ret; 1718 } 1719 1720 /* 1721 * @implemented 1722 */ 1723 HWND APIENTRY 1724 NtUserSetFocus(HWND hWnd) 1725 { 1726 PWND Window; 1727 USER_REFERENCE_ENTRY Ref; 1728 HWND ret = NULL; 1729 1730 TRACE("Enter NtUserSetFocus(%p)\n", hWnd); 1731 UserEnterExclusive(); 1732 1733 if (hWnd) 1734 { 1735 if (!(Window = UserGetWindowObject(hWnd))) 1736 { 1737 ERR("NtUserSetFocus: Invalid handle 0x%p!\n",hWnd); 1738 goto Exit; // Return NULL 1739 } 1740 1741 UserRefObjectCo(Window, &Ref); 1742 ret = co_UserSetFocus(Window); 1743 UserDerefObjectCo(Window); 1744 } 1745 else 1746 { 1747 ret = co_UserSetFocus(NULL); 1748 } 1749 1750 Exit: 1751 TRACE("Leave NtUserSetFocus, ret=%p\n", ret); 1752 UserLeave(); 1753 return ret; 1754 } 1755 1756 /* EOF */ 1757