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