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