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