Skip to content

Commit

Permalink
feat: 使消息窗口显示在源窗口上方
Browse files Browse the repository at this point in the history
  • Loading branch information
Blinue committed Oct 16, 2024
1 parent 7792afd commit 7e0a118
Show file tree
Hide file tree
Showing 9 changed files with 77 additions and 19 deletions.
18 changes: 12 additions & 6 deletions src/Magpie.App/ScalingService.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "EffectsService.h"
#include <Magpie.Core.h>
#include "TouchHelper.h"
#include "ToastService.h"

using namespace ::Magpie::Core;
using namespace winrt;
Expand Down Expand Up @@ -223,20 +224,26 @@ fire_and_forget ScalingService::_ScalingRuntime_IsRunningChanged(bool isRunning)
IsRunningChanged.Invoke(isRunning);
}

bool ScalingService::_StartScale(HWND hWnd, const Profile& profile) {
static void ShowError(HWND hWnd, ScalingError error) noexcept {
ToastService::Get().ShowMessageOnWindow(L"缩放模式无效", hWnd);
Logger::Get().Error(fmt::format("缩放失败\n\t错误码: {}", (int)error));
}

void ScalingService::_StartScale(HWND hWnd, const Profile& profile) {
if (profile.scalingMode < 0) {
return false;
ShowError(hWnd, ScalingError::InvalidScalingMode);
return;
}

ScalingOptions options;
options.effects = ScalingModesService::Get().GetScalingMode(profile.scalingMode).effects;
if (options.effects.empty()) {
return false;
return;
} else {
for (EffectOption& effect : options.effects) {
if (!EffectsService::Get().GetEffect(effect.name)) {
// 存在无法解析的效果
return false;
return;
}
}
}
Expand All @@ -245,7 +252,7 @@ bool ScalingService::_StartScale(HWND hWnd, const Profile& profile) {
bool isTouchSupportEnabled;
if (!TouchHelper::TryLaunchTouchHelper(isTouchSupportEnabled)) {
Logger::Get().Error("TryLaunchTouchHelper 失败");
return false;
return;
}

options.graphicsCard = profile.graphicsCard;
Expand Down Expand Up @@ -316,7 +323,6 @@ bool ScalingService::_StartScale(HWND hWnd, const Profile& profile) {
_isAutoScaling = profile.isAutoScale;
_scalingRuntime->Start(hWnd, std::move(options));
_hwndCurSrc = hWnd;
return true;
}

void ScalingService::_ScaleForegroundWindow() {
Expand Down
3 changes: 2 additions & 1 deletion src/Magpie.App/ScalingService.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once
#include <winrt/Magpie.App.h>
#include "WinRTUtils.h"
#include "ScalingError.h"

namespace Magpie::Core {
class ScalingRuntime;
Expand Down Expand Up @@ -69,7 +70,7 @@ class ScalingService {

fire_and_forget _ScalingRuntime_IsRunningChanged(bool isRunning);

bool _StartScale(HWND hWnd, const Profile& profile);
void _StartScale(HWND hWnd, const Profile& profile);

void _ScaleForegroundWindow();

Expand Down
2 changes: 1 addition & 1 deletion src/Magpie.App/ToastPage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ using namespace Windows::UI::Xaml::Controls;

namespace winrt::Magpie::App::implementation {

IAsyncAction ToastPage::ShowMessage(const hstring& message) {
fire_and_forget ToastPage::ShowMessage(const hstring& message) {
// !!! HACK !!!
// 重用 TeachingTip 有一个 bug: 前一个 Toast 正在消失时新的 Toast 不会显示。为了
// 规避它,我们每次都创建新的 TeachingTip,但要保留旧对象的引用,因为播放动画时销毁
Expand Down
2 changes: 1 addition & 1 deletion src/Magpie.App/ToastPage.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
namespace winrt::Magpie::App::implementation {

struct ToastPage : ToastPageT<ToastPage> {
IAsyncAction ShowMessage(const hstring& message);
fire_and_forget ShowMessage(const hstring& message);
};

}
Expand Down
2 changes: 1 addition & 1 deletion src/Magpie.App/ToastPage.idl
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ namespace Magpie.App {
runtimeclass ToastPage : Windows.UI.Xaml.Controls.Page {
ToastPage();

Windows.Foundation.IAsyncAction ShowMessage(String message);
void ShowMessage(String message);

// https://github.com/microsoft/microsoft-ui-xaml/issues/7579
void UnloadObject(Windows.UI.Xaml.DependencyObject object);
Expand Down
40 changes: 33 additions & 7 deletions src/Magpie.App/ToastService.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "Utils.h"
#include <windows.ui.xaml.hosting.desktopwindowxamlsource.h>
#include <winrt/Windows.UI.Xaml.Hosting.h>
#include "Win32Utils.h"

using namespace winrt;
using namespace Windows::UI::Xaml::Controls;
Expand Down Expand Up @@ -36,9 +37,34 @@ void ToastService::Uninitialize() noexcept {
_toastThread.join();
}

void ToastService::ShowMessage(std::wstring_view message) noexcept {
_Dispatcher().TryRunAsync(CoreDispatcherPriority::Normal, [this, captured(std::wstring(message))]() {
_toastPage.ShowMessage(captured);
void ToastService::ShowMessageOnWindow(std::wstring_view message, HWND hWnd) noexcept {
_Dispatcher().TryRunAsync(CoreDispatcherPriority::Normal, [this, capturedMessage(std::wstring(message)), hWnd]() {
RECT frameRect;
if (!Win32Utils::GetWindowFrameRect(hWnd, frameRect)) {
return;
}

// 更改所有者关系使弹窗始终在 hWnd 上方
SetWindowLongPtr(_hwndToast, GWLP_HWNDPARENT, (LONG_PTR)hWnd);
// _hwndToast 的输入已被附加到了 hWnd 上,这是所有者窗口的默认行为,但我们不需要。
// 见 https://devblogs.microsoft.com/oldnewthing/20130412-00/?p=4683
AttachThreadInput(
GetCurrentThreadId(),
GetWindowThreadProcessId(hWnd, nullptr),
FALSE
);

SetWindowPos(
_hwndToast,
NULL,
(frameRect.left + frameRect.right) / 2,
(frameRect.top + frameRect.bottom * 4) / 5,
0,
0,
SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOCOPYBITS | SWP_NOREDRAW
);

_toastPage.ShowMessage(capturedMessage);
});
}

Expand All @@ -63,8 +89,8 @@ void ToastService::_ToastThreadProc() noexcept {

// 创建窗口失败也应进入消息循环。Win10 中关闭任意线程的 DesktopWindowXamlSource 都会使主线程会崩溃,
// 在程序退出前,xamlSource 不能析构。见 https://github.com/microsoft/terminal/pull/15397
HWND hwndToast = CreateWindowEx(
WS_EX_TOPMOST | WS_EX_NOREDIRECTIONBITMAP | WS_EX_TOOLWINDOW,
_hwndToast = CreateWindowEx(
WS_EX_NOREDIRECTIONBITMAP | WS_EX_TOOLWINDOW | WS_EX_TRANSPARENT,
CommonSharedConstants::TOAST_WINDOW_CLASS_NAME,
L"Toast",
WS_POPUP | WS_VISIBLE,
Expand All @@ -80,7 +106,7 @@ void ToastService::_ToastThreadProc() noexcept {
com_ptr<IDesktopWindowXamlSourceNative2> xamlSourceNative2 =
xamlSource.try_as<IDesktopWindowXamlSourceNative2>();

xamlSourceNative2->AttachToWindow(hwndToast);
xamlSourceNative2->AttachToWindow(_hwndToast);

HWND hwndXamlIsland;
xamlSourceNative2->get_WindowHandle(&hwndXamlIsland);
Expand All @@ -97,7 +123,7 @@ void ToastService::_ToastThreadProc() noexcept {
MSG msg;
while (GetMessage(&msg, nullptr, 0, 0)) {
if (msg.message == CommonSharedConstants::WM_TOAST_QUIT) {
DestroyWindow(hwndToast);
DestroyWindow(_hwndToast);
break;
}

Expand Down
7 changes: 5 additions & 2 deletions src/Magpie.App/ToastService.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class ToastService {

void Uninitialize() noexcept;

void ShowMessage(std::wstring_view message) noexcept;
void ShowMessageOnWindow(std::wstring_view message, HWND hWnd) noexcept;

private:
ToastService() = default;
Expand All @@ -29,11 +29,14 @@ class ToastService {

std::thread _toastThread;

ToastPage _toastPage{ nullptr };
CoreDispatcher _dispatcher{ nullptr };
std::atomic<bool> _dispatcherInitialized = false;
// 只能在主线程访问,省下检查 _dispatcherInitialized 的开销
bool _dispatcherInitializedCache = false;

// 只能在 toast 线程访问
ToastPage _toastPage{ nullptr };
HWND _hwndToast = NULL;
};

}
21 changes: 21 additions & 0 deletions src/Shared/ScalingError.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#pragma once

enum class ScalingError {
/////////////////////////////////////
//
// 先决条件错误
//
/////////////////////////////////////

// 未配置缩放模式或者缩放模式不合法
InvalidScalingMode,

/////////////////////////////////////
//
// 初始化错误
//
/////////////////////////////////////

// 检测到其他缩放窗口。由于不支持多实例,这个错误不应该出现
AlreadyScaling
};
1 change: 1 addition & 0 deletions src/Shared/Shared.vcxitems
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
<ClInclude Include="$(MSBuildThisFileDirectory)CommonPch.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)CommonSharedConstants.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)Logger.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)ScalingError.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)SmallVector.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)StrUtils.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)Utils.h" />
Expand Down

0 comments on commit 7e0a118

Please sign in to comment.