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_dlls.h
platform/win/windows_event_filter.cpp platform/win/windows_event_filter.cpp
platform/win/windows_event_filter.h platform/win/windows_event_filter.h
platform/win/wrapper_wrl_implements_h.h
platform/platform_audio.h platform/platform_audio.h
platform/platform_file_utilities.h platform/platform_file_utilities.h
platform/platform_launcher.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 "window/notifications_manager.h"
#include "mainwindow.h" #include "mainwindow.h"
#include "base/crc32hash.h" #include "base/crc32hash.h"
#include "base/platform/win/base_windows_wrl.h"
#include "core/application.h" #include "core/application.h"
#include "lang/lang_keys.h" #include "lang/lang_keys.h"
#include "storage/localstorage.h" #include "storage/localstorage.h"
@ -27,24 +28,25 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include <QtWidgets/QStyleFactory> #include <QtWidgets/QStyleFactory>
#include <QtWidgets/QApplication> #include <QtWidgets/QApplication>
#include <QtGui/QWindow> #include <QtGui/QWindow>
#include <QtGui/QScreen>
#include <qpa/qplatformnativeinterface.h> #include <qpa/qplatformnativeinterface.h>
#include <Shobjidl.h> #include <Shobjidl.h>
#include <shellapi.h> #include <shellapi.h>
#include <WtsApi32.h> #include <WtsApi32.h>
#include <roapi.h> #include <windows.ui.viewmanagement.h>
#include <wrl/client.h> #include <UIViewSettingsInterop.h>
#include <Windowsx.h> #include <Windowsx.h>
#include <VersionHelpers.h> #include <VersionHelpers.h>
HICON qt_pixmapToWinHICON(const QPixmap &); HICON qt_pixmapToWinHICON(const QPixmap &);
using namespace Microsoft::WRL;
Q_DECLARE_METATYPE(QMargins); Q_DECLARE_METATYPE(QMargins);
namespace ViewManagement = ABI::Windows::UI::ViewManagement;
namespace Platform { namespace Platform {
namespace { namespace {
@ -55,6 +57,8 @@ namespace {
// icon click (both left or right button) was made from the active app. // icon click (both left or right button) was made from the active app.
constexpr auto kKeepActiveForTrayIcon = crl::time(500); constexpr auto kKeepActiveForTrayIcon = crl::time(500);
using namespace Microsoft::WRL;
HICON createHIconFromQIcon(const QIcon &icon, int xSize, int ySize) { HICON createHIconFromQIcon(const QIcon &icon, int xSize, int ySize) {
if (!icon.isNull()) { if (!icon.isNull()) {
const QPixmap pm = icon.pixmap(icon.actualSize(QSize(xSize, ySize))); const QPixmap pm = icon.pixmap(icon.actualSize(QSize(xSize, ySize)));
@ -99,21 +103,24 @@ HWND createTaskbarHider() {
} }
ComPtr<ITaskbarList3> taskbarList; ComPtr<ITaskbarList3> taskbarList;
bool handleSessionNotification = false; bool handleSessionNotification = false;
uint32 kTaskbarCreatedMsgId = 0;
} // namespace } // namespace
UINT MainWindow::_taskbarCreatedMsgId = 0; struct MainWindow::Private {
ComPtr<ViewManagement::IUIViewSettings> viewSettings;
};
MainWindow::MainWindow(not_null<Window::Controller*> controller) MainWindow::MainWindow(not_null<Window::Controller*> controller)
: Window::MainWindow(controller) : Window::MainWindow(controller)
, _private(std::make_unique<Private>())
, ps_tbHider_hWnd(createTaskbarHider()) { , ps_tbHider_hWnd(createTaskbarHider()) {
QCoreApplication::instance()->installNativeEventFilter( QCoreApplication::instance()->installNativeEventFilter(
EventFilter::CreateInstance(this)); EventFilter::CreateInstance(this));
if (!_taskbarCreatedMsgId) { if (!kTaskbarCreatedMsgId) {
_taskbarCreatedMsgId = RegisterWindowMessage(L"TaskbarButtonCreated"); kTaskbarCreatedMsgId = RegisterWindowMessage(L"TaskbarButtonCreated");
} }
subscribe(Window::Theme::Background(), [this](const Window::Theme::BackgroundUpdate &update) { subscribe(Window::Theme::Background(), [this](const Window::Theme::BackgroundUpdate &update) {
if (_shadow && update.paletteChanged()) { if (_shadow && update.paletteChanged()) {
@ -168,6 +175,10 @@ void MainWindow::setupNativeWindowFrame() {
}, lifetime()); }, lifetime());
} }
uint32 MainWindow::TaskbarCreatedMsgId() {
return kTaskbarCreatedMsgId;
}
void MainWindow::TaskbarCreated() { void MainWindow::TaskbarCreated() {
HRESULT hr = CoCreateInstance(CLSID_TaskbarList, nullptr, CLSCTX_ALL, IID_PPV_ARGS(&taskbarList)); HRESULT hr = CoCreateInstance(CLSID_TaskbarList, nullptr, CLSCTX_ALL, IID_PPV_ARGS(&taskbarList));
if (!SUCCEEDED(hr)) { 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() { void MainWindow::updateWindowIcon() {
updateIconCounters(); updateIconCounters();
} }
@ -362,6 +399,20 @@ void MainWindow::initHook() {
Dlls::WTSRegisterSessionNotification(ps_hWnd, NOTIFY_FOR_THIS_SESSION); 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(); psInitSysMenu();
} }
@ -662,6 +713,7 @@ MainWindow::~MainWindow() {
if (handleSessionNotification) { if (handleSessionNotification) {
Dlls::WTSUnRegisterSessionNotification(ps_hWnd); Dlls::WTSUnRegisterSessionNotification(ps_hWnd);
} }
_private->viewSettings.Reset();
if (taskbarList) { if (taskbarList) {
taskbarList.Reset(); 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; virtual QImage iconWithCounter(int size, int count, style::color bg, style::color fg, bool smallIcon) = 0;
static UINT TaskbarCreatedMsgId() { [[nodiscard]] static uint32 TaskbarCreatedMsgId();
return _taskbarCreatedMsgId;
}
static void TaskbarCreated(); static void TaskbarCreated();
// Custom shadows. // Custom shadows.
@ -59,6 +57,8 @@ public:
return _deltaTop; return _deltaTop;
} }
[[nodiscard]] bool hasTabletView() const;
void psShowTrayMenu(); void psShowTrayMenu();
~MainWindow(); ~MainWindow();
@ -87,9 +87,13 @@ protected:
void workmodeUpdated(DBIWorkMode mode) override; void workmodeUpdated(DBIWorkMode mode) override;
bool initSizeFromSystem() override;
QTimer psUpdatedPositionTimer; QTimer psUpdatedPositionTimer;
private: private:
struct Private;
void setupNativeWindowFrame(); void setupNativeWindowFrame();
void updateIconCounters(); void updateIconCounters();
QMargins computeCustomMargins(); QMargins computeCustomMargins();
@ -97,7 +101,7 @@ private:
void psDestroyIcons(); void psDestroyIcons();
void fixMaximizedWindow(); void fixMaximizedWindow();
static UINT _taskbarCreatedMsgId; const std::unique_ptr<Private> _private;
std::optional<Ui::Platform::WindowShadow> _shadow; 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 "platform/win/notifications_manager_win.h"
#include "window/notifications_utilities.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_app_user_model_id.h"
#include "platform/win/windows_event_filter.h" #include "platform/win/windows_event_filter.h"
#include "platform/win/windows_dlls.h" #include "platform/win/windows_dlls.h"
@ -20,16 +22,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include <Shobjidl.h> #include <Shobjidl.h>
#include <shellapi.h> #include <shellapi.h>
#include <roapi.h>
#include <wrl/client.h>
#ifndef __MINGW32__ #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 <windows.ui.notifications.h>
#include <strsafe.h>
#include <intsafe.h>
HICON qt_pixmapToWinHICON(const QPixmap &); HICON qt_pixmapToWinHICON(const QPixmap &);
using namespace Microsoft::WRL; using namespace Microsoft::WRL;
@ -44,68 +40,16 @@ namespace Notifications {
#ifndef __MINGW32__ #ifndef __MINGW32__
namespace { namespace {
class StringReferenceWrapper { using base::Platform::GetActivationFactory;
public: using base::Platform::StringReferenceWrapper;
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());
}
bool init() { bool init() {
if (QSysInfo::windowsVersion() < QSysInfo::WV_WINDOWS8) { if (!IsWindows8OrGreater()) {
return false; return false;
} }
if ((Dlls::SetCurrentProcessExplicitAppUserModelID == nullptr) if ((Dlls::SetCurrentProcessExplicitAppUserModelID == nullptr)
|| (Dlls::PropVariantToString == nullptr) || (Dlls::PropVariantToString == nullptr)
|| (Dlls::RoGetActivationFactory == nullptr) || !base::Platform::SupportsWRL()) {
|| (Dlls::WindowsCreateStringReference == nullptr)
|| (Dlls::WindowsDeleteString == nullptr)) {
return false; return false;
} }
@ -395,7 +339,7 @@ Manager::Private::Private(Manager *instance, Type type)
} }
bool Manager::Private::init() { 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; return false;
} }
@ -404,7 +348,7 @@ bool Manager::Private::init() {
return false; 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 false;
} }
return true; return true;

View file

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

View file

@ -126,25 +126,6 @@ using f_PSStringFromPropertyKey = HRESULT(FAR STDAPICALLTYPE*)(
_In_ UINT cch); _In_ UINT cch);
extern f_PSStringFromPropertyKey PSStringFromPropertyKey; 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 // DWMAPI.DLL
using f_DwmIsCompositionEnabled = HRESULT(FAR STDAPICALLTYPE*)( using f_DwmIsCompositionEnabled = HRESULT(FAR STDAPICALLTYPE*)(

View file

@ -268,7 +268,10 @@ bool EventFilter::mainWindowEvent(
case WM_WINDOWPOSCHANGED: { case WM_WINDOWPOSCHANGED: {
WINDOWPLACEMENT wp; WINDOWPLACEMENT wp;
wp.length = sizeof(WINDOWPLACEMENT); 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); _window->shadowsUpdate(Change::Hidden);
} else { } else {
_window->shadowsUpdate(Change::Moved | Change::Resized, (WINDOWPOS*)lParam); _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() { void MainWindow::initSize() {
updateMinimumSize(); updateMinimumSize();
if (initSizeFromSystem()) {
return;
}
auto position = cWindowPos(); 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))); 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 void firstShadowsUpdate() {
} }
virtual bool initSizeFromSystem() {
return false;
}
// This one is overriden in Windows for historical reasons. // This one is overriden in Windows for historical reasons.
virtual int32 screenNameChecksum(const QString &name) const; virtual int32 screenNameChecksum(const QString &name) const;