mirror of
https://github.com/Blinue/Magpie.git
synced 2026-06-24 02:04:10 +00:00
修复源窗口被最小化时偶尔没有移出屏幕 (#1335)
* fix: 修复源窗口被最小化后没有移出屏幕的错误 * fix: 位于中间状态时不再继续检查 * fix: 修复切换窗口时偶尔源窗口不会被带到顶部 * refactor: 常用 SWP 组合定义为宏 * perf: 提高细粒度 * fix: 置顶窗口可能失败,需多次尝试
This commit is contained in:
parent
2eb70761c9
commit
15d3e392c4
5 changed files with 34 additions and 31 deletions
|
|
@ -1219,7 +1219,7 @@ void ScalingWindow::_Show() noexcept {
|
|||
Handle(),
|
||||
NULL,
|
||||
0, 0, 0, 0,
|
||||
SWP_SHOWWINDOW | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE
|
||||
SWP_SHOWWINDOW | SWP_NO_ACTIVATE_MOVE_SIZE
|
||||
);
|
||||
|
||||
// 广播开始缩放
|
||||
|
|
@ -1888,43 +1888,39 @@ void ScalingWindow::_UpdateFocusState() const noexcept {
|
|||
return;
|
||||
}
|
||||
|
||||
const bool topmost = _CalcTopmostState();
|
||||
if (IsTopmostWindow(Handle()) != topmost) {
|
||||
const bool oldTopmost = IsTopmostWindow(Handle());
|
||||
const bool newTopmost = _CalcTopmostState();
|
||||
if (oldTopmost != newTopmost) {
|
||||
// 由于同步问题可能需要尝试多次
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
SetWindowPos(Handle(), topmost ? HWND_TOPMOST : HWND_NOTOPMOST,
|
||||
0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOOWNERZORDER);
|
||||
// 切换到其他窗口时不要改变源窗口 Z 顺序,当前台窗口权限更高时需要依赖源窗口位置
|
||||
SetWindowPos(Handle(), newTopmost ? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0, 0, 0,
|
||||
SWP_NO_ACTIVATE_MOVE_SIZE | (_srcTracker.IsFocused() ? 0 : SWP_NOOWNERZORDER));
|
||||
|
||||
if (IsTopmostWindow(Handle()) == topmost) {
|
||||
if (IsTopmostWindow(Handle()) == newTopmost) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_srcTracker.IsFocused()) {
|
||||
if (!_options.IsWindowedMode()) {
|
||||
// 全屏模式缩放时确保缩放窗口在所有置顶窗口之上,这使不支持 MPO 的显卡更容易激
|
||||
// 活 DirectFlip。
|
||||
HDWP hDwp = BeginDeferWindowPos(2);
|
||||
if (hDwp) {
|
||||
hDwp = DeferWindowPos(hDwp, _srcTracker.Handle(), HWND_TOP, 0, 0, 0, 0,
|
||||
SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
|
||||
hDwp = DeferWindowPos(hDwp, Handle(), HWND_TOP, 0, 0, 0, 0,
|
||||
SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOOWNERZORDER);
|
||||
EndDeferWindowPos(hDwp);
|
||||
}
|
||||
// 全屏模式缩放时确保缩放窗口在所有置顶窗口之上,这使不支持 MPO 的显卡更容易激
|
||||
// 活 DirectFlip。
|
||||
if (!_options.IsWindowedMode() && newTopmost) {
|
||||
SetWindowPos(Handle(), HWND_TOP, 0, 0, 0, 0, SWP_NO_ACTIVATE_MOVE_SIZE);
|
||||
}
|
||||
} else {
|
||||
} else if (oldTopmost && !newTopmost) {
|
||||
// 如果缩放窗口之前是置顶的,此时会在前台窗口之上,应将前台窗口置于顶部
|
||||
if (const HWND hwndFore = GetForegroundWindow()) {
|
||||
if (!SetWindowPos(hwndFore, HWND_TOP, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE)) {
|
||||
if (!SetWindowPos(hwndFore, HWND_TOP, 0, 0, 0, 0, SWP_NO_ACTIVATE_MOVE_SIZE)) {
|
||||
// 如果前台窗口权限更高,SetWindowPos 会失败。这时用其他方法将缩放窗口放到
|
||||
// 前台窗口之后,缺点是偶尔会有一瞬间源窗口出现在缩放窗口前。
|
||||
HDWP hDwp = BeginDeferWindowPos(2);
|
||||
if (hDwp) {
|
||||
hDwp = DeferWindowPos(hDwp, Handle(), _srcTracker.Handle(),
|
||||
0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOOWNERZORDER);
|
||||
0, 0, 0, 0, SWP_NO_ACTIVATE_MOVE_SIZE | SWP_NOOWNERZORDER);
|
||||
hDwp = DeferWindowPos(hDwp, _srcTracker.Handle(), Handle(),
|
||||
0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOOWNERZORDER);
|
||||
0, 0, 0, 0, SWP_NO_ACTIVATE_MOVE_SIZE | SWP_NOOWNERZORDER);
|
||||
EndDeferWindowPos(hDwp);
|
||||
}
|
||||
}
|
||||
|
|
@ -2084,10 +2080,10 @@ void ScalingWindow::_UpdateWindowRectFromWindowPos(const WINDOWPOS& windowPos) n
|
|||
void ScalingWindow::_DelayedStop(bool onSrcHung, bool onSrcRepositioning) const noexcept {
|
||||
if (!onSrcHung) {
|
||||
const HWND hwndSrc = _srcTracker.Handle();
|
||||
if (!(IsWindow(hwndSrc) && Win32Helper::IsWindowHung(hwndSrc))) {
|
||||
if (IsTopmostWindow(Handle()) && !(IsWindow(hwndSrc) && Win32Helper::IsWindowHung(hwndSrc))) {
|
||||
// 提前取消置顶,这样销毁时出现问题不会影响和桌面环境交互
|
||||
SetWindowPos(Handle(), HWND_NOTOPMOST, 0, 0, 0, 0,
|
||||
SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOOWNERZORDER);
|
||||
SWP_NO_ACTIVATE_MOVE_SIZE | SWP_NOOWNERZORDER);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -234,6 +234,14 @@ bool SrcTracker::UpdateState(
|
|||
|
||||
RECT curWindowRect;
|
||||
if (wp.showCmd == SW_SHOWMINIMIZED) {
|
||||
// 窗口最小化有两步:先将窗口状态设为最小化,然后将窗口移出屏幕 (左上角坐标
|
||||
// (-32000,-32000))。如果我们刚好在两步之间停止缩放,第二步将无法执行,这和缩
|
||||
// 放窗口被源窗口所有有关,不确定是否是 OS 的 bug。这个检查确保第二步完成后再
|
||||
// 停止缩放。
|
||||
if (wp.rcNormalPosition.left == wp.ptMinPosition.x) {
|
||||
return true;
|
||||
}
|
||||
|
||||
isInvisibleOrMinimized = true;
|
||||
|
||||
// rcNormalPosition 使用工作区坐标,应转换为屏幕坐标
|
||||
|
|
|
|||
|
|
@ -134,12 +134,10 @@ fire_and_forget ToastPage::ShowMessageOnWindow(std::wstring title, std::wstring
|
|||
}
|
||||
|
||||
if (isTargetTopMost || !isOwned) {
|
||||
SetWindowPos(_hwndToast, HWND_TOPMOST, 0, 0, 0, 0,
|
||||
SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
|
||||
SetWindowPos(_hwndToast, HWND_TOPMOST, 0, 0, 0, 0, SWP_NO_ACTIVATE_MOVE_SIZE);
|
||||
}
|
||||
if (!isTargetTopMost) {
|
||||
SetWindowPos(_hwndToast, HWND_NOTOPMOST, 0, 0, 0, 0,
|
||||
SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
|
||||
SetWindowPos(_hwndToast, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NO_ACTIVATE_MOVE_SIZE);
|
||||
}
|
||||
|
||||
// 更改所有者后应更新 Z 轴顺序
|
||||
|
|
@ -268,11 +266,11 @@ fire_and_forget ToastPage::ShowMessageOnWindow(std::wstring title, std::wstring
|
|||
// 如果 hwndTarget 位于前台,定期将弹窗置顶。SWP_NOOWNERZORDER 可以避免修改 hwndTarget
|
||||
// 的 Z 顺序,理论上不需要这个标志,可能是 OS 的 bug。
|
||||
SetWindowPos(_hwndToast, HWND_TOPMOST, 0, 0, 0, 0,
|
||||
SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOOWNERZORDER);
|
||||
SWP_NO_ACTIVATE_MOVE_SIZE | SWP_NOOWNERZORDER);
|
||||
}
|
||||
if (!isTargetTopMost) {
|
||||
SetWindowPos(_hwndToast, HWND_NOTOPMOST, 0, 0, 0, 0,
|
||||
SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOOWNERZORDER);
|
||||
SWP_NO_ACTIVATE_MOVE_SIZE | SWP_NOOWNERZORDER);
|
||||
}
|
||||
|
||||
// 窗口没有移动则无需更新
|
||||
|
|
|
|||
|
|
@ -85,8 +85,7 @@ void ToastService::_ToastThreadProc() noexcept {
|
|||
wil::GetModuleInstanceHandle(),
|
||||
nullptr
|
||||
);
|
||||
SetWindowPos(_hwndToast, NULL, 0, 0, 0, 0,
|
||||
SWP_SHOWWINDOW | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
|
||||
SetWindowPos(_hwndToast, NULL, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NO_ACTIVATE_MOVE_SIZE);
|
||||
|
||||
// DesktopWindowXamlSource 在控件之前创建则无需调用 WindowsXamlManager::InitializeForCurrentThread
|
||||
DesktopWindowXamlSource xamlSource;
|
||||
|
|
|
|||
|
|
@ -19,6 +19,8 @@ using winrt::operator co_await;
|
|||
#define _STRING_HELPER(x) #x
|
||||
#define STRING(x) _STRING_HELPER(x)
|
||||
|
||||
#define SWP_NO_ACTIVATE_MOVE_SIZE (SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE)
|
||||
|
||||
struct Ignore {
|
||||
constexpr Ignore() noexcept = default;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue