Detect tablet mode on Windows 10.

This commit is contained in:
John Preston 2021-01-16 16:33:09 +04:00
parent 7fa342b487
commit 40e90af76d
10 changed files with 89 additions and 122 deletions

View File

@ -902,7 +902,6 @@ PRIVATE
platform/win/windows_dlls.h
platform/win/windows_event_filter.cpp
platform/win/windows_event_filter.h
platform/win/wrapper_wrl_implements_h.h
platform/platform_audio.h
platform/platform_file_utilities.h
platform/platform_launcher.h

View File

@ -15,6 +15,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "window/notifications_manager.h"
#include "mainwindow.h"
#include "base/crc32hash.h"
#include "base/platform/win/base_windows_wrl.h"
#include "core/application.h"
#include "lang/lang_keys.h"
#include "storage/localstorage.h"
@ -27,24 +28,25 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include <QtWidgets/QStyleFactory>
#include <QtWidgets/QApplication>
#include <QtGui/QWindow>
#include <QtGui/QScreen>
#include <qpa/qplatformnativeinterface.h>
#include <Shobjidl.h>
#include <shellapi.h>
#include <WtsApi32.h>
#include <roapi.h>
#include <wrl/client.h>
#include <windows.ui.viewmanagement.h>
#include <UIViewSettingsInterop.h>
#include <Windowsx.h>
#include <VersionHelpers.h>
HICON qt_pixmapToWinHICON(const QPixmap &);
using namespace Microsoft::WRL;
Q_DECLARE_METATYPE(QMargins);
namespace ViewManagement = ABI::Windows::UI::ViewManagement;
namespace Platform {
namespace {
@ -55,6 +57,8 @@ namespace {
// icon click (both left or right button) was made from the active app.
constexpr auto kKeepActiveForTrayIcon = crl::time(500);
using namespace Microsoft::WRL;
HICON createHIconFromQIcon(const QIcon &icon, int xSize, int ySize) {
if (!icon.isNull()) {
const QPixmap pm = icon.pixmap(icon.actualSize(QSize(xSize, ySize)));
@ -99,21 +103,24 @@ HWND createTaskbarHider() {
}
ComPtr<ITaskbarList3> taskbarList;
bool handleSessionNotification = false;
uint32 kTaskbarCreatedMsgId = 0;
} // namespace
UINT MainWindow::_taskbarCreatedMsgId = 0;
struct MainWindow::Private {
ComPtr<ViewManagement::IUIViewSettings> viewSettings;
};
MainWindow::MainWindow(not_null<Window::Controller*> controller)
: Window::MainWindow(controller)
, _private(std::make_unique<Private>())
, ps_tbHider_hWnd(createTaskbarHider()) {
QCoreApplication::instance()->installNativeEventFilter(
EventFilter::CreateInstance(this));
if (!_taskbarCreatedMsgId) {
_taskbarCreatedMsgId = RegisterWindowMessage(L"TaskbarButtonCreated");
if (!kTaskbarCreatedMsgId) {
kTaskbarCreatedMsgId = RegisterWindowMessage(L"TaskbarButtonCreated");
}
subscribe(Window::Theme::Background(), [this](const Window::Theme::BackgroundUpdate &update) {
if (_shadow && update.paletteChanged()) {
@ -168,6 +175,10 @@ void MainWindow::setupNativeWindowFrame() {
}, lifetime());
}
uint32 MainWindow::TaskbarCreatedMsgId() {
return kTaskbarCreatedMsgId;
}
void MainWindow::TaskbarCreated() {
HRESULT hr = CoCreateInstance(CLSID_TaskbarList, nullptr, CLSCTX_ALL, IID_PPV_ARGS(&taskbarList));
if (!SUCCEEDED(hr)) {
@ -291,6 +302,32 @@ void MainWindow::workmodeUpdated(DBIWorkMode mode) {
}
}
bool MainWindow::hasTabletView() const {
if (!_private->viewSettings) {
return false;
}
auto mode = ViewManagement::UserInteractionMode();
_private->viewSettings->get_UserInteractionMode(&mode);
return (mode == ViewManagement::UserInteractionMode_Touch);
}
bool MainWindow::initSizeFromSystem() {
if (!hasTabletView()) {
return false;
}
const auto screen = [&] {
if (const auto result = windowHandle()->screen()) {
return result;
}
return QGuiApplication::primaryScreen();
}();
if (!screen) {
return false;
}
setGeometry(screen->geometry());
return true;
}
void MainWindow::updateWindowIcon() {
updateIconCounters();
}
@ -362,6 +399,20 @@ void MainWindow::initHook() {
Dlls::WTSRegisterSessionNotification(ps_hWnd, NOTIFY_FOR_THIS_SESSION);
}
using namespace base::Platform;
auto factory = ComPtr<IUIViewSettingsInterop>();
if (SupportsWRL()) {
GetActivationFactory(
StringReferenceWrapper(
RuntimeClass_Windows_UI_ViewManagement_UIViewSettings).Get(),
&factory);
if (factory) {
factory->GetForWindow(
ps_hWnd,
IID_PPV_ARGS(&_private->viewSettings));
}
}
psInitSysMenu();
}
@ -662,6 +713,7 @@ MainWindow::~MainWindow() {
if (handleSessionNotification) {
Dlls::WTSUnRegisterSessionNotification(ps_hWnd);
}
_private->viewSettings.Reset();
if (taskbarList) {
taskbarList.Reset();
}

View File

@ -40,9 +40,7 @@ public:
virtual QImage iconWithCounter(int size, int count, style::color bg, style::color fg, bool smallIcon) = 0;
static UINT TaskbarCreatedMsgId() {
return _taskbarCreatedMsgId;
}
[[nodiscard]] static uint32 TaskbarCreatedMsgId();
static void TaskbarCreated();
// Custom shadows.
@ -59,6 +57,8 @@ public:
return _deltaTop;
}
[[nodiscard]] bool hasTabletView() const;
void psShowTrayMenu();
~MainWindow();
@ -87,9 +87,13 @@ protected:
void workmodeUpdated(DBIWorkMode mode) override;
bool initSizeFromSystem() override;
QTimer psUpdatedPositionTimer;
private:
struct Private;
void setupNativeWindowFrame();
void updateIconCounters();
QMargins computeCustomMargins();
@ -97,7 +101,7 @@ private:
void psDestroyIcons();
void fixMaximizedWindow();
static UINT _taskbarCreatedMsgId;
const std::unique_ptr<Private> _private;
std::optional<Ui::Platform::WindowShadow> _shadow;

View File

@ -8,6 +8,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "platform/win/notifications_manager_win.h"
#include "window/notifications_utilities.h"
#include "base/platform/win/base_windows_wrl.h"
#include "base/platform/base_platform_info.h"
#include "platform/win/windows_app_user_model_id.h"
#include "platform/win/windows_event_filter.h"
#include "platform/win/windows_dlls.h"
@ -20,16 +22,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include <Shobjidl.h>
#include <shellapi.h>
#include <roapi.h>
#include <wrl/client.h>
#ifndef __MINGW32__
#include "platform/win/wrapper_wrl_implements_h.h"
#include "base/platform/win/wrl/wrl_implements_h.h"
#include <windows.ui.notifications.h>
#include <strsafe.h>
#include <intsafe.h>
HICON qt_pixmapToWinHICON(const QPixmap &);
using namespace Microsoft::WRL;
@ -44,68 +40,16 @@ namespace Notifications {
#ifndef __MINGW32__
namespace {
class StringReferenceWrapper {
public:
StringReferenceWrapper(_In_reads_(length) PCWSTR stringRef, _In_ UINT32 length) throw() {
HRESULT hr = Dlls::WindowsCreateStringReference(stringRef, length, &_header, &_hstring);
if (!SUCCEEDED(hr)) {
RaiseException(static_cast<DWORD>(STATUS_INVALID_PARAMETER), EXCEPTION_NONCONTINUABLE, 0, nullptr);
}
}
~StringReferenceWrapper() {
Dlls::WindowsDeleteString(_hstring);
}
template <size_t N>
StringReferenceWrapper(_In_reads_(N) wchar_t const (&stringRef)[N]) throw() {
UINT32 length = N - 1;
HRESULT hr = Dlls::WindowsCreateStringReference(stringRef, length, &_header, &_hstring);
if (!SUCCEEDED(hr)) {
RaiseException(static_cast<DWORD>(STATUS_INVALID_PARAMETER), EXCEPTION_NONCONTINUABLE, 0, nullptr);
}
}
template <size_t _>
StringReferenceWrapper(_In_reads_(_) wchar_t(&stringRef)[_]) throw() {
UINT32 length;
HRESULT hr = SizeTToUInt32(wcslen(stringRef), &length);
if (!SUCCEEDED(hr)) {
RaiseException(static_cast<DWORD>(STATUS_INVALID_PARAMETER), EXCEPTION_NONCONTINUABLE, 0, nullptr);
}
Dlls::WindowsCreateStringReference(stringRef, length, &_header, &_hstring);
}
HSTRING Get() const throw() {
return _hstring;
}
private:
HSTRING _hstring;
HSTRING_HEADER _header;
};
template<class T>
_Check_return_ __inline HRESULT _1_GetActivationFactory(_In_ HSTRING activatableClassId, _COM_Outptr_ T** factory) {
return Dlls::RoGetActivationFactory(activatableClassId, IID_INS_ARGS(factory));
}
template<typename T>
inline HRESULT wrap_GetActivationFactory(_In_ HSTRING activatableClassId, _Inout_ Details::ComPtrRef<T> factory) throw() {
return _1_GetActivationFactory(activatableClassId, factory.ReleaseAndGetAddressOf());
}
using base::Platform::GetActivationFactory;
using base::Platform::StringReferenceWrapper;
bool init() {
if (QSysInfo::windowsVersion() < QSysInfo::WV_WINDOWS8) {
if (!IsWindows8OrGreater()) {
return false;
}
if ((Dlls::SetCurrentProcessExplicitAppUserModelID == nullptr)
|| (Dlls::PropVariantToString == nullptr)
|| (Dlls::RoGetActivationFactory == nullptr)
|| (Dlls::WindowsCreateStringReference == nullptr)
|| (Dlls::WindowsDeleteString == nullptr)) {
|| !base::Platform::SupportsWRL()) {
return false;
}
@ -395,7 +339,7 @@ Manager::Private::Private(Manager *instance, Type type)
}
bool Manager::Private::init() {
if (!SUCCEEDED(wrap_GetActivationFactory(StringReferenceWrapper(RuntimeClass_Windows_UI_Notifications_ToastNotificationManager).Get(), &_notificationManager))) {
if (!SUCCEEDED(GetActivationFactory(StringReferenceWrapper(RuntimeClass_Windows_UI_Notifications_ToastNotificationManager).Get(), &_notificationManager))) {
return false;
}
@ -404,7 +348,7 @@ bool Manager::Private::init() {
return false;
}
if (!SUCCEEDED(wrap_GetActivationFactory(StringReferenceWrapper(RuntimeClass_Windows_UI_Notifications_ToastNotification).Get(), &_notificationFactory))) {
if (!SUCCEEDED(GetActivationFactory(StringReferenceWrapper(RuntimeClass_Windows_UI_Notifications_ToastNotification).Get(), &_notificationFactory))) {
return false;
}
return true;

View File

@ -63,9 +63,6 @@ f_WTSUnRegisterSessionNotification WTSUnRegisterSessionNotification;
f_SHQueryUserNotificationState SHQueryUserNotificationState;
f_SHChangeNotify SHChangeNotify;
f_SetCurrentProcessExplicitAppUserModelID SetCurrentProcessExplicitAppUserModelID;
f_RoGetActivationFactory RoGetActivationFactory;
f_WindowsCreateStringReference WindowsCreateStringReference;
f_WindowsDeleteString WindowsDeleteString;
f_PropVariantToString PropVariantToString;
f_PSStringFromPropertyKey PSStringFromPropertyKey;
f_DwmIsCompositionEnabled DwmIsCompositionEnabled;
@ -112,13 +109,6 @@ void start() {
LoadMethod(LibPropSys, "PropVariantToString", PropVariantToString);
LoadMethod(LibPropSys, "PSStringFromPropertyKey", PSStringFromPropertyKey);
if (IsWindows8OrGreater()) {
const auto LibComBase = SafeLoadLibrary(u"combase.dll"_q);
LoadMethod(LibComBase, "RoGetActivationFactory", RoGetActivationFactory);
LoadMethod(LibComBase, "WindowsCreateStringReference", WindowsCreateStringReference);
LoadMethod(LibComBase, "WindowsDeleteString", WindowsDeleteString);
}
const auto LibDwmApi = SafeLoadLibrary(u"dwmapi.dll"_q);
LoadMethod(LibDwmApi, "DwmIsCompositionEnabled", DwmIsCompositionEnabled);
LoadMethod(LibDwmApi, "DwmSetWindowAttribute", DwmSetWindowAttribute);

View File

@ -126,25 +126,6 @@ using f_PSStringFromPropertyKey = HRESULT(FAR STDAPICALLTYPE*)(
_In_ UINT cch);
extern f_PSStringFromPropertyKey PSStringFromPropertyKey;
// COMBASE.DLL
using f_RoGetActivationFactory = HRESULT(FAR STDAPICALLTYPE*)(
_In_ HSTRING activatableClassId,
_In_ REFIID iid,
_COM_Outptr_ void ** factory);
extern f_RoGetActivationFactory RoGetActivationFactory;
using f_WindowsCreateStringReference = HRESULT(FAR STDAPICALLTYPE*)(
_In_reads_opt_(length + 1) PCWSTR sourceString,
UINT32 length,
_Out_ HSTRING_HEADER * hstringHeader,
_Outptr_result_maybenull_ _Result_nullonfailure_ HSTRING * string);
extern f_WindowsCreateStringReference WindowsCreateStringReference;
using f_WindowsDeleteString = HRESULT(FAR STDAPICALLTYPE*)(
_In_opt_ HSTRING string);
extern f_WindowsDeleteString WindowsDeleteString;
// DWMAPI.DLL
using f_DwmIsCompositionEnabled = HRESULT(FAR STDAPICALLTYPE*)(

View File

@ -268,7 +268,10 @@ bool EventFilter::mainWindowEvent(
case WM_WINDOWPOSCHANGED: {
WINDOWPLACEMENT wp;
wp.length = sizeof(WINDOWPLACEMENT);
if (GetWindowPlacement(hWnd, &wp) && (wp.showCmd == SW_SHOWMAXIMIZED || wp.showCmd == SW_SHOWMINIMIZED)) {
if (_window->hasTabletView()
|| (GetWindowPlacement(hWnd, &wp)
&& (wp.showCmd == SW_SHOWMAXIMIZED
|| wp.showCmd == SW_SHOWMINIMIZED))) {
_window->shadowsUpdate(Change::Hidden);
} else {
_window->shadowsUpdate(Change::Moved | Change::Resized, (WINDOWPOS*)lParam);

View File

@ -1,14 +0,0 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
#pragma warning(push)
// class has virtual functions, but destructor is not virtual
#pragma warning(disable:4265)
#include <wrl/implements.h>
#pragma warning(pop)

View File

@ -420,6 +420,10 @@ void MainWindow::recountGeometryConstraints() {
void MainWindow::initSize() {
updateMinimumSize();
if (initSizeFromSystem()) {
return;
}
auto position = cWindowPos();
DEBUG_LOG(("Window Pos: Initializing first %1, %2, %3, %4 (maximized %5)").arg(position.x).arg(position.y).arg(position.w).arg(position.h).arg(Logs::b(position.maximized)));

View File

@ -186,6 +186,10 @@ protected:
virtual void firstShadowsUpdate() {
}
virtual bool initSizeFromSystem() {
return false;
}
// This one is overriden in Windows for historical reasons.
virtual int32 screenNameChecksum(const QString &name) const;