Fix Windows 11 title controls by additional padding.
This commit is contained in:
parent
9b5c939fd0
commit
220d683528
3 changed files with 182 additions and 10 deletions
|
|
@ -6,9 +6,13 @@
|
||||||
//
|
//
|
||||||
#include "ui/platform/win/ui_window_title_win.h"
|
#include "ui/platform/win/ui_window_title_win.h"
|
||||||
|
|
||||||
|
#include "ui/platform/win/ui_window_win.h"
|
||||||
#include "ui/widgets/buttons.h"
|
#include "ui/widgets/buttons.h"
|
||||||
#include "ui/widgets/shadow.h"
|
#include "ui/widgets/shadow.h"
|
||||||
#include "ui/ui_utility.h"
|
#include "ui/ui_utility.h"
|
||||||
|
#include "base/platform/base_platform_info.h"
|
||||||
|
#include "base/platform/win/base_windows_safe_library.h"
|
||||||
|
#include "base/debug_log.h"
|
||||||
#include "styles/style_widgets.h"
|
#include "styles/style_widgets.h"
|
||||||
#include "styles/palette.h"
|
#include "styles/palette.h"
|
||||||
|
|
||||||
|
|
@ -16,28 +20,75 @@
|
||||||
#include <QtGui/QtEvents>
|
#include <QtGui/QtEvents>
|
||||||
#include <QtGui/QWindow>
|
#include <QtGui/QWindow>
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
#include <shellscalingapi.h>
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
namespace Platform {
|
namespace Platform {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
HRESULT(__stdcall *GetScaleFactorForMonitor)(
|
||||||
|
_In_ HMONITOR hMon,
|
||||||
|
_Out_ DEVICE_SCALE_FACTOR *pScale);
|
||||||
|
|
||||||
|
[[nodiscard]] bool ScaleQuerySupported() {
|
||||||
|
static const auto Result = [&] {
|
||||||
|
#define LOAD_SYMBOL(lib, name) base::Platform::LoadMethod(lib, #name, name)
|
||||||
|
const auto shcore = base::Platform::SafeLoadLibrary(L"Shcore.dll");
|
||||||
|
return LOAD_SYMBOL(shcore, GetScaleFactorForMonitor);
|
||||||
|
#undef LOAD_SYMBOL
|
||||||
|
}();
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
struct TitleWidget::PaddingHelper {
|
||||||
|
explicit PaddingHelper(QWidget *parent) : controlsParent(parent) {
|
||||||
|
}
|
||||||
|
|
||||||
|
RpWidget controlsParent;
|
||||||
|
int padding = 0;
|
||||||
|
};
|
||||||
|
|
||||||
TitleWidget::TitleWidget(not_null<RpWidget*> parent)
|
TitleWidget::TitleWidget(not_null<RpWidget*> parent)
|
||||||
: RpWidget(parent)
|
: RpWidget(parent)
|
||||||
, _controls(this, st::defaultWindowTitle)
|
, _paddingHelper(CheckTitlePaddingRequired()
|
||||||
|
? std::make_unique<PaddingHelper>(this)
|
||||||
|
: nullptr)
|
||||||
|
, _controls(
|
||||||
|
_paddingHelper ? &_paddingHelper->controlsParent : this,
|
||||||
|
st::defaultWindowTitle)
|
||||||
, _shadow(this, st::titleShadow) {
|
, _shadow(this, st::titleShadow) {
|
||||||
setAttribute(Qt::WA_OpaquePaintEvent);
|
setAttribute(Qt::WA_OpaquePaintEvent);
|
||||||
|
|
||||||
parent->widthValue(
|
parent->widthValue(
|
||||||
) | rpl::start_with_next([=](int width) {
|
) | rpl::start_with_next([=](int width) {
|
||||||
setGeometry(0, 0, width, _controls.st()->height);
|
refreshGeometryWithWidth(width);
|
||||||
}, lifetime());
|
}, lifetime());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TitleWidget::~TitleWidget() = default;
|
||||||
|
|
||||||
void TitleWidget::setText(const QString &text) {
|
void TitleWidget::setText(const QString &text) {
|
||||||
window()->setWindowTitle(text);
|
window()->setWindowTitle(text);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TitleWidget::setStyle(const style::WindowTitle &st) {
|
void TitleWidget::setStyle(const style::WindowTitle &st) {
|
||||||
_controls.setStyle(st);
|
_controls.setStyle(st);
|
||||||
setGeometry(0, 0, window()->width(), _controls.st()->height);
|
refreshGeometryWithWidth(window()->width());
|
||||||
|
}
|
||||||
|
|
||||||
|
void TitleWidget::refreshGeometryWithWidth(int width) {
|
||||||
|
const auto add = _paddingHelper ? _paddingHelper->padding : 0;
|
||||||
|
setGeometry(0, 0, width, _controls.st()->height + add);
|
||||||
|
if (_paddingHelper) {
|
||||||
|
_paddingHelper->controlsParent.setGeometry(
|
||||||
|
add,
|
||||||
|
add,
|
||||||
|
width - 2 * add,
|
||||||
|
_controls.st()->height);
|
||||||
|
}
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -57,7 +108,8 @@ void TitleWidget::paintEvent(QPaintEvent *e) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void TitleWidget::resizeEvent(QResizeEvent *e) {
|
void TitleWidget::resizeEvent(QResizeEvent *e) {
|
||||||
_shadow->setGeometry(0, height() - st::lineWidth, width(), st::lineWidth);
|
const auto thickness = st::lineWidth;
|
||||||
|
_shadow->setGeometry(0, height() - thickness, width(), thickness);
|
||||||
}
|
}
|
||||||
|
|
||||||
HitTestResult TitleWidget::hitTest(QPoint point) const {
|
HitTestResult TitleWidget::hitTest(QPoint point) const {
|
||||||
|
|
@ -69,5 +121,99 @@ HitTestResult TitleWidget::hitTest(QPoint point) const {
|
||||||
return HitTestResult::None;
|
return HitTestResult::None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool TitleWidget::additionalPaddingRequired() const {
|
||||||
|
return _paddingHelper && !isHidden();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TitleWidget::refreshAdditionalPaddings() {
|
||||||
|
if (!additionalPaddingRequired()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto handle = GetWindowHandle(this);
|
||||||
|
if (!handle) {
|
||||||
|
LOG(("System Error: GetWindowHandle failed."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
refreshAdditionalPaddings(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TitleWidget::refreshAdditionalPaddings(HWND handle) {
|
||||||
|
if (!additionalPaddingRequired()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto placement = WINDOWPLACEMENT{
|
||||||
|
.length = sizeof(WINDOWPLACEMENT),
|
||||||
|
};
|
||||||
|
if (!GetWindowPlacement(handle, &placement)) {
|
||||||
|
LOG(("System Error: GetWindowPlacement failed."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
refreshAdditionalPaddings(handle, placement);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TitleWidget::refreshAdditionalPaddings(
|
||||||
|
HWND handle,
|
||||||
|
const WINDOWPLACEMENT &placement) {
|
||||||
|
auto geometry = RECT();
|
||||||
|
if (!GetWindowRect(handle, &geometry)) {
|
||||||
|
LOG(("System Error: GetWindowRect failed."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto normal = placement.rcNormalPosition;
|
||||||
|
const auto rounded = (normal.left == geometry.left)
|
||||||
|
&& (normal.right == geometry.right)
|
||||||
|
&& (normal.top == geometry.top)
|
||||||
|
&& (normal.bottom == geometry.bottom);
|
||||||
|
const auto padding = [&] {
|
||||||
|
if (!rounded) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
const auto monitor = MonitorFromWindow(
|
||||||
|
handle,
|
||||||
|
MONITOR_DEFAULTTONEAREST);
|
||||||
|
if (!monitor) {
|
||||||
|
LOG(("System Error: MonitorFromWindow failed."));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
auto factor = DEVICE_SCALE_FACTOR();
|
||||||
|
if (!SUCCEEDED(GetScaleFactorForMonitor(monitor, &factor))) {
|
||||||
|
LOG(("System Error: GetScaleFactorForMonitor failed."));
|
||||||
|
return -1;
|
||||||
|
} else if (factor < 100 || factor > 500) {
|
||||||
|
LOG(("System Error: Bad scale factor %1.").arg(int(factor)));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
const auto pixels = (factor + 50) / 100;
|
||||||
|
return int(base::SafeRound(pixels / window()->devicePixelRatioF()));
|
||||||
|
}();
|
||||||
|
if (padding < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setAdditionalPadding(padding);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TitleWidget::setAdditionalPadding(int padding) {
|
||||||
|
Expects(_paddingHelper != nullptr);
|
||||||
|
|
||||||
|
if (_paddingHelper->padding == padding) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_paddingHelper->padding = padding;
|
||||||
|
refreshGeometryWithWidth(window()->width());
|
||||||
|
}
|
||||||
|
|
||||||
|
void TitleWidget::setVisibleHook(bool visible) {
|
||||||
|
RpWidget::setVisibleHook(visible);
|
||||||
|
if (additionalPaddingRequired()) {
|
||||||
|
PostponeCall(this, [=] {
|
||||||
|
refreshAdditionalPaddings();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CheckTitlePaddingRequired() {
|
||||||
|
return ::Platform::IsWindows11OrGreater() && ScaleQuerySupported();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Platform
|
} // namespace Platform
|
||||||
} // namespace Ui
|
} // namespace Ui
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,8 @@
|
||||||
#include <QtCore/QRect>
|
#include <QtCore/QRect>
|
||||||
#include <QtCore/QPoint>
|
#include <QtCore/QPoint>
|
||||||
|
|
||||||
|
#include <Windows.h> // HWND, WINDOWPLACEMENT
|
||||||
|
|
||||||
namespace style {
|
namespace style {
|
||||||
struct WindowTitle;
|
struct WindowTitle;
|
||||||
} // namespace style
|
} // namespace style
|
||||||
|
|
@ -42,6 +44,7 @@ enum class HitTestResult {
|
||||||
class TitleWidget : public RpWidget {
|
class TitleWidget : public RpWidget {
|
||||||
public:
|
public:
|
||||||
explicit TitleWidget(not_null<RpWidget*> parent);
|
explicit TitleWidget(not_null<RpWidget*> parent);
|
||||||
|
~TitleWidget();
|
||||||
|
|
||||||
void setText(const QString &text);
|
void setText(const QString &text);
|
||||||
void setStyle(const style::WindowTitle &st);
|
void setStyle(const style::WindowTitle &st);
|
||||||
|
|
@ -49,15 +52,32 @@ public:
|
||||||
[[nodiscard]] HitTestResult hitTest(QPoint point) const;
|
[[nodiscard]] HitTestResult hitTest(QPoint point) const;
|
||||||
void setResizeEnabled(bool enabled);
|
void setResizeEnabled(bool enabled);
|
||||||
|
|
||||||
|
void refreshAdditionalPaddings();
|
||||||
|
void refreshAdditionalPaddings(HWND handle);
|
||||||
|
void refreshAdditionalPaddings(
|
||||||
|
HWND handle,
|
||||||
|
const WINDOWPLACEMENT &placement);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void paintEvent(QPaintEvent *e) override;
|
void paintEvent(QPaintEvent *e) override;
|
||||||
void resizeEvent(QResizeEvent *e) override;
|
void resizeEvent(QResizeEvent *e) override;
|
||||||
|
|
||||||
|
void setVisibleHook(bool visible) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
struct PaddingHelper;
|
||||||
|
|
||||||
|
[[nodiscard]] bool additionalPaddingRequired() const;
|
||||||
|
void refreshGeometryWithWidth(int width);
|
||||||
|
void setAdditionalPadding(int padding);
|
||||||
|
|
||||||
|
std::unique_ptr<PaddingHelper> _paddingHelper;
|
||||||
TitleControls _controls;
|
TitleControls _controls;
|
||||||
object_ptr<Ui::PlainShadow> _shadow;
|
object_ptr<Ui::PlainShadow> _shadow;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
[[nodiscard]] bool CheckTitlePaddingRequired();
|
||||||
|
|
||||||
} // namespace Platform
|
} // namespace Platform
|
||||||
} // namespace Ui
|
} // namespace Ui
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,6 @@
|
||||||
#include "ui/inactive_press.h"
|
#include "ui/inactive_press.h"
|
||||||
#include "ui/platform/win/ui_window_title_win.h"
|
#include "ui/platform/win/ui_window_title_win.h"
|
||||||
#include "base/platform/base_platform_info.h"
|
#include "base/platform/base_platform_info.h"
|
||||||
#include "base/platform/win/base_windows_safe_library.h"
|
|
||||||
#include "base/integration.h"
|
#include "base/integration.h"
|
||||||
#include "base/debug_log.h"
|
#include "base/debug_log.h"
|
||||||
#include "styles/palette.h"
|
#include "styles/palette.h"
|
||||||
|
|
@ -409,11 +408,16 @@ bool WindowHelper::handleNativeEvent(
|
||||||
case WM_WINDOWPOSCHANGING:
|
case WM_WINDOWPOSCHANGING:
|
||||||
case WM_WINDOWPOSCHANGED: {
|
case WM_WINDOWPOSCHANGED: {
|
||||||
if (_shadow) {
|
if (_shadow) {
|
||||||
WINDOWPLACEMENT wp;
|
auto placement = WINDOWPLACEMENT{
|
||||||
wp.length = sizeof(WINDOWPLACEMENT);
|
.length = sizeof(WINDOWPLACEMENT),
|
||||||
if (GetWindowPlacement(_handle, &wp)
|
};
|
||||||
&& (wp.showCmd == SW_SHOWMAXIMIZED
|
if (!GetWindowPlacement(_handle, &placement)) {
|
||||||
|| wp.showCmd == SW_SHOWMINIMIZED)) {
|
LOG(("System Error: GetWindowPlacement failed."));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
_title->refreshAdditionalPaddings(_handle, placement);
|
||||||
|
if (placement.showCmd == SW_SHOWMAXIMIZED
|
||||||
|
|| placement.showCmd == SW_SHOWMINIMIZED) {
|
||||||
_shadow->update(WindowShadow::Change::Hidden);
|
_shadow->update(WindowShadow::Change::Hidden);
|
||||||
} else {
|
} else {
|
||||||
_shadow->update(
|
_shadow->update(
|
||||||
|
|
@ -439,6 +443,7 @@ bool WindowHelper::handleNativeEvent(
|
||||||
}
|
}
|
||||||
updateMargins();
|
updateMargins();
|
||||||
if (_shadow) {
|
if (_shadow) {
|
||||||
|
_title->refreshAdditionalPaddings(_handle);
|
||||||
const auto changes = (wParam == SIZE_MINIMIZED
|
const auto changes = (wParam == SIZE_MINIMIZED
|
||||||
|| wParam == SIZE_MAXIMIZED)
|
|| wParam == SIZE_MAXIMIZED)
|
||||||
? WindowShadow::Change::Hidden
|
? WindowShadow::Change::Hidden
|
||||||
|
|
@ -462,6 +467,7 @@ bool WindowHelper::handleNativeEvent(
|
||||||
|
|
||||||
case WM_MOVE: {
|
case WM_MOVE: {
|
||||||
if (_shadow) {
|
if (_shadow) {
|
||||||
|
_title->refreshAdditionalPaddings(_handle);
|
||||||
_shadow->update(WindowShadow::Change::Moved);
|
_shadow->update(WindowShadow::Change::Moved);
|
||||||
}
|
}
|
||||||
} return false;
|
} return false;
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue