Updated lib_ui sources to TDesktop version 2.9.3

This commit is contained in:
Eric Kotato 2021-09-16 09:58:42 +03:00
commit 3bc35a74ec
26 changed files with 672 additions and 164 deletions

View file

@ -180,6 +180,8 @@ PRIVATE
ui/widgets/menu/menu_toggle.h
ui/widgets/popup_menu.cpp
ui/widgets/popup_menu.h
ui/widgets/rp_window.cpp
ui/widgets/rp_window.h
ui/widgets/scroll_area.cpp
ui/widgets/scroll_area.h
ui/widgets/side_bar_button.cpp
@ -188,8 +190,6 @@ PRIVATE
ui/widgets/shadow.h
ui/widgets/tooltip.cpp
ui/widgets/tooltip.h
ui/widgets/window.cpp
ui/widgets/window.h
ui/wrap/fade_wrap.cpp
ui/wrap/fade_wrap.h
ui/wrap/padding_wrap.cpp
@ -253,6 +253,7 @@ elseif(LINUX)
target_link_libraries(lib_ui
PUBLIC
desktop-app::lib_waylandshells
desktop-app::external_kwayland
)
endif()

View file

@ -0,0 +1,250 @@
{
"name": "Qt built-in + some Chromium GPU driver blacklist",
"version": "5.6",
"entries": [
{
"id": 1,
"description": "Desktop OpenGL is unreliable on some Intel HD laptops (QTBUG-43263)",
"vendor_id": "0x8086",
"device_id": [ "0x0A16" ],
"os": {
"type": "win"
},
"driver_version": {
"op": "<=",
"value": "10.18.10.3277"
},
"features": [
"disable_desktopgl"
]
},
{
"id": 2,
"description": "Intel Q965/Q963 - GMA 3000 has insufficient support of opengl and directx",
"vendor_id": "0x8086",
"device_id": [ "0x2992" ],
"os": {
"type": "win"
},
"features": [
"disable_desktopgl",
"disable_angle"
]
},
{
"id": 3,
"description": "No OpenGL on Intel G33/G31 (QTBUG-47522)",
"vendor_id": "0x8086",
"device_id": [ "0x29C2" ],
"os": {
"type": "win"
},
"features": [
"disable_desktopgl"
]
},
{
"id": 4,
"description": "Intel HD Graphics 3000 crashes when initializing the OpenGL driver (QTBUG-42240)",
"vendor_id": "0x8086",
"device_id": [ "0x0102", "0x0106", "0x010A", "0x0112", "0x0116", "0x0122", "0x0126" ],
"os": {
"type": "win"
},
"features": [
"disable_desktopgl"
]
},
{
"id": 5,
"description": "Intel GMA 3150 (QTBUG-43243), Mobile Intel 945GM (QTBUG-47435) crash",
"vendor_id": "0x8086",
"device_id": [ "0xA001", "0xA011", "0x27A0" ],
"os": {
"type": "win"
},
"features": [
"disable_desktopgl", "disable_angle"
]
},
{
"id": 6,
"description": "Intel(R) HD Graphics 4000 / 5500 cause crashes on orientation changes in fullscreen mode (QTBUG-49541)",
"vendor_id": "0x8086",
"device_id": [ "0x0166", "0x1616" ],
"os": {
"type": "win"
},
"features": [
"disable_rotation"
]
},
{
"id": 7,
"description": "AMD FirePro V5900 driver causes crashes in Direct3D on Windows.",
"vendor_id": "0x1002",
"device_id": ["0x6707"],
"os": {
"type": "win"
},
"features": [
"disable_angle"
]
},
{
"id": 8,
"description": "Standard VGA: Insufficent support for OpenGL, D3D9 and D3D11",
"vendor_id": "0x0000",
"device_id": ["0x0000"],
"os": {
"type": "win"
},
"features": [
"disable_desktopgl", "disable_d3d11", "disable_d3d9"
]
},
{
"id": 9,
"description": "Intel 945 crash (QTBUG-40991)",
"vendor_id": "0x8086",
"device_id": [ "0x27A2" ],
"os": {
"type": "win"
},
"features": [
"disable_desktopgl"
]
},
{
"id": 10,
"description": "Intel(R) HD Graphics IronLake (Arrandale) crashes on makeCurrent QTBUG-53888",
"vendor_id": "0x8086",
"device_id": [ "0x0046" ],
"os": {
"type": "win"
},
"features": [
"disable_desktopgl"
]
},
{
"id": 11,
"description": "Intel driver version 8.15.10.1749 causes GPU process hangs (QTBUG-56360)",
"vendor_id": "0x8086",
"os": {
"type": "win"
},
"driver_version": {
"op": "=",
"value": "8.15.10.1749"
},
"features": [
"disable_desktopgl", "disable_d3d11", "disable_d3d9"
]
},
{
"id": 12,
"description": "Intel HD Graphics crash in conjunction with shader caches (QTBUG-64697) - disable for all Intel GPUs",
"vendor_id": "0x8086",
"os": {
"type": "win"
},
"features": [
"disable_program_cache"
]
},
{
"id": 13,
"description": "Disable DesktopGL on Windows with Mobile Intel(R) 4 Series Express Chipset Family graphics card (QTBUG-58772)",
"vendor_id": "0x8086",
"device_id": [ "0x2A42" ],
"os": {
"type": "win"
},
"features": [
"disable_desktopgl"
]
},
{
"id": 70,
"description": "Disable D3D11 on older nVidia drivers",
"cr_bugs": [349929],
"os": {
"type": "win"
},
"vendor_id": "0x10de",
"driver_version": {
"op": "<=",
"value": "8.17.12.6973"
},
"features": [
"disable_d3d11"
]
},
{
"id": 86,
"description": "Disable use of Direct3D 11 on Matrox video cards",
"cr_bugs": [395861],
"os": {
"type": "win"
},
"vendor_id": "0x102b",
"features": [
"disable_d3d11"
]
},
{
"id": 87,
"description": "Disable use of Direct3D 11 on older AMD drivers",
"cr_bugs": [402134],
"os": {
"type": "win"
},
"vendor_id": "0x1002",
"driver_version": {
"op": "<",
"value": "8.17.10.1070"
},
"features": [
"disable_d3d11"
]
},
{
"id": 92,
"description": "Old Intel drivers cannot reliably support D3D11",
"cr_bugs": [363721],
"os": {
"type": "win"
},
"vendor_id": "0x8086",
"driver_version": {
"op": "<=",
"value": "9.18.0.0"
},
"features": [
"disable_d3d11"
]
},
{
"id": 100,
"description": "Disable Direct3D11 on systems with AMD switchable graphics",
"cr_bugs": [451420, 721121, 755722],
"os": {
"type": "win",
"version": {
"op": "<",
"value": "10"
}
},
"driver_version": {
"op": "<",
"value": "20.19.0.32837"
},
"multi_gpu_style": "amd_switchable",
"features": [
"disable_d3d11"
]
}
]
}

View file

@ -2,4 +2,7 @@
<qresource prefix="/qt/etc">
<file alias="qt.conf">qt_win.conf</file>
</qresource>
<qresource prefix="/misc">
<file alias="gpu_driver_bug_list.json">gpu_driver_bug_list.json</file>
</qresource>
</RCC>

View file

@ -17,6 +17,12 @@
#include <QtGui/QOpenGLFunctions>
#include <QtWidgets/QOpenGLWidget>
#ifdef Q_OS_WIN
#include <QtGui/QGuiApplication>
#include <qpa/qplatformnativeinterface.h>
#include <EGL/egl.h>
#endif // Q_OS_WIN
#define LOG_ONCE(x) [[maybe_unused]] static auto logged = [&] { LOG(x); return true; }();
namespace Ui::GL {
@ -43,8 +49,17 @@ Capabilities CheckCapabilities(QWidget *widget) {
LOG_ONCE(("OpenGL: Force-disabled."));
return {};
}
[[maybe_unused]] static const auto BugListInited = [] {
if (!QFile::exists(":/misc/gpu_driver_bug_list.json")) {
return false;
}
LOG(("OpenGL: Using custom 'gpu_driver_bug_list.json'."));
qputenv("QT_OPENGL_BUGLIST", ":/misc/gpu_driver_bug_list.json");
return true;
}();
auto format = QSurfaceFormat();
format.setAlphaBufferSize(8);
if (widget) {
if (!widget->window()->windowHandle()) {
widget->window()->createWinId();
@ -57,6 +72,11 @@ Capabilities CheckCapabilities(QWidget *widget) {
LOG_ONCE(("OpenGL: Not supported for window."));
return {};
}
format = widget->window()->windowHandle()->format();
format.setAlphaBufferSize(8);
widget->window()->windowHandle()->setFormat(format);
} else {
format.setAlphaBufferSize(8);
}
auto tester = QOpenGLWidget(widget);
tester.setFormat(format);
@ -104,6 +124,7 @@ Capabilities CheckCapabilities(QWidget *widget) {
return {};
}
}
const auto supported = context->format();
switch (supported.profile()) {
case QSurfaceFormat::NoProfile: {
@ -121,6 +142,7 @@ Capabilities CheckCapabilities(QWidget *widget) {
LOG_ONCE(("OpenGL Profile: Compatibility."));
} break;
}
[[maybe_unused]] static const auto extensionsLogged = [&] {
const auto renderer = reinterpret_cast<const char*>(
functions->glGetString(GL_RENDERER));
@ -136,8 +158,18 @@ Capabilities CheckCapabilities(QWidget *widget) {
list.append(QString::fromLatin1(extension));
}
LOG(("OpenGL Extensions: %1").arg(list.join(", ")));
#ifdef Q_OS_WIN
auto egllist = QStringList();
for (const auto &extension : EGLExtensions(context)) {
egllist.append(QString::fromLatin1(extension));
}
LOG(("EGL Extensions: %1").arg(egllist.join(", ")));
#endif // Q_OS_WIN
return true;
}();
const auto version = u"%1.%2"_q
.arg(supported.majorVersion())
.arg(supported.majorVersion());
@ -218,6 +250,19 @@ ANGLE CurrentANGLE() {
return ResolvedANGLE;
}
QList<QByteArray> EGLExtensions(not_null<QOpenGLContext*> context) {
const auto native = QGuiApplication::platformNativeInterface();
Assert(native != nullptr);
const auto display = static_cast<EGLDisplay>(
native->nativeResourceForContext(
QByteArrayLiteral("egldisplay"),
context));
return display
? QByteArray(eglQueryString(display, EGL_EXTENSIONS)).split(' ')
: QList<QByteArray>();
}
#endif // Q_OS_WIN
} // namespace Ui::GL

View file

@ -8,6 +8,8 @@
#include "base/flags.h"
class QOpenGLContext;
namespace Ui::GL {
enum class Backend {
@ -40,4 +42,7 @@ void ConfigureANGLE(); // Requires Ui::Integration being set.
void ChangeANGLE(ANGLE backend);
[[nodiscard]] ANGLE CurrentANGLE();
[[nodiscard]] QList<QByteArray> EGLExtensions(
not_null<QOpenGLContext*> context);
} // namespace Ui::GL

View file

@ -155,14 +155,4 @@ TexturedRect Image::texturedRect(
};
}
GLint CurrentSingleComponentFormat() {
const auto context = QOpenGLContext::currentContext();
Assert(context != nullptr);
const auto format = context->format();
return (format.renderableType() == QSurfaceFormat::OpenGLES)
? GL_LUMINANCE
: GL_RED;
}
} // namespace Ui::GL

View file

@ -134,8 +134,6 @@ private:
};
[[nodiscard]] GLint CurrentSingleComponentFormat();
#ifdef Q_OS_WIN
inline constexpr auto kFormatRGBA = GL_BGRA_EXT;
inline constexpr auto kSwizzleRedBlue = false;

View file

@ -89,9 +89,9 @@ uniform sampler2D u_texture;
uniform sampler2D v_texture;
)",
.body = R"(
float y = texture2D(y_texture, v_texcoord).r - 0.0625;
float u = texture2D(u_texture, v_texcoord).r - 0.5;
float v = texture2D(v_texture, v_texcoord).r - 0.5;
float y = texture2D(y_texture, v_texcoord).a - 0.0625;
float u = texture2D(u_texture, v_texcoord).a - 0.5;
float v = texture2D(v_texture, v_texcoord).a - 0.5;
result = vec4(
1.164 * y + 1.596 * v,
1.164 * y - 0.392 * u - 0.813 * v,

View file

@ -7,7 +7,7 @@
#include "ui/gl/gl_window.h"
#include "ui/gl/gl_detection.h"
#include "ui/widgets/window.h"
#include "ui/widgets/rp_window.h"
#include "base/event_filter.h"
#include "base/platform/base_platform_info.h"
#include "base/debug_log.h"
@ -38,40 +38,40 @@ Backend Window::backend() const {
return _backend;
}
not_null<Ui::Window*> Window::window() const {
not_null<RpWindow*> Window::window() const {
return _window.get();
}
not_null<Ui::RpWidget*> Window::widget() const {
not_null<RpWidget*> Window::widget() const {
return _body.get();
}
std::unique_ptr<Ui::Window> Window::createWindow() {
auto result = std::make_unique<Ui::Window>();
std::unique_ptr<RpWindow> Window::createWindow() {
auto result = std::make_unique<RpWindow>();
if constexpr (!kUseNativeChild) {
const auto capabilities = Ui::GL::CheckCapabilities(result.get());
const auto capabilities = CheckCapabilities(result.get());
const auto use = ::Platform::IsMac()
? true
: ::Platform::IsWindows()
? capabilities.supported
: capabilities.transparency;
LOG(("OpenGL: %1 (Ui::GL::Window)").arg(use ? "[TRUE]" : "[FALSE]"));
_backend = use ? Ui::GL::Backend::OpenGL : Ui::GL::Backend::Raster;
LOG(("OpenGL: %1 (Window)").arg(use ? "[TRUE]" : "[FALSE]"));
_backend = use ? Backend::OpenGL : Backend::Raster;
if (!use) {
// We have to create a new window, if OpenGL initialization failed.
result = std::make_unique<Ui::Window>();
result = std::make_unique<RpWindow>();
}
}
return result;
}
std::unique_ptr<Ui::RpWidget> Window::createNativeBodyWrap() {
std::unique_ptr<RpWidget> Window::createNativeBodyWrap() {
if constexpr (!kUseNativeChild) {
return nullptr;
}
const auto create = [] {
auto result = std::make_unique<Ui::RpWidget>();
auto result = std::make_unique<RpWidget>();
result->setWindowFlags(Qt::FramelessWindowHint | Qt::Window);
result->setAttribute(Qt::WA_NativeWindow);
result->setAttribute(Qt::WA_DontCreateNativeAncestors);
@ -81,14 +81,14 @@ std::unique_ptr<Ui::RpWidget> Window::createNativeBodyWrap() {
};
auto result = create();
const auto capabilities = Ui::GL::CheckCapabilities(result.get());
const auto capabilities = CheckCapabilities(result.get());
const auto use = ::Platform::IsMac()
? true
: ::Platform::IsWindows()
? capabilities.supported
: capabilities.transparency;
LOG(("OpenGL: %1 (Ui::GL::WindowBody)").arg(use ? "[TRUE]" : "[FALSE]"));
_backend = use ? Ui::GL::Backend::OpenGL : Ui::GL::Backend::Raster;
LOG(("OpenGL: %1 (WindowBody)").arg(use ? "[TRUE]" : "[FALSE]"));
_backend = use ? Backend::OpenGL : Backend::Raster;
if (!use) {
// We have to create a new window, if OpenGL initialization failed.
@ -117,7 +117,7 @@ std::unique_ptr<Ui::RpWidget> Window::createNativeBodyWrap() {
const auto childWindow = raw->windowHandle();
base::install_event_filter(childWindow, [=](not_null<QEvent*> event) {
if (event->type() == QEvent::Expose && childWindow->isExposed()) {
Ui::Platform::SendWMPaintForce(_window.get());
Platform::SendWMPaintForce(_window.get());
}
return base::EventFilterResult::Continue;
});

View file

@ -8,7 +8,7 @@
namespace Ui {
class Window;
class RpWindow;
class RpWidget;
} // namespace Ui
@ -22,17 +22,17 @@ public:
~Window();
[[nodiscard]] Backend backend() const;
[[nodiscard]] not_null<Ui::Window*> window() const;
[[nodiscard]] not_null<Ui::RpWidget*> widget() const;
[[nodiscard]] not_null<RpWindow*> window() const;
[[nodiscard]] not_null<RpWidget*> widget() const;
private:
[[nodiscard]] std::unique_ptr<Ui::Window> createWindow();
[[nodiscard]] std::unique_ptr<Ui::RpWidget> createNativeBodyWrap();
[[nodiscard]] std::unique_ptr<RpWindow> createWindow();
[[nodiscard]] std::unique_ptr<RpWidget> createNativeBodyWrap();
Ui::GL::Backend _backend = Ui::GL::Backend();
const std::unique_ptr<Ui::Window> _window;
const std::unique_ptr<Ui::RpWidget> _bodyNativeWrap;
const not_null<Ui::RpWidget*> _body;
Backend _backend = Backend();
const std::unique_ptr<RpWindow> _window;
const std::unique_ptr<RpWidget> _bodyNativeWrap;
const not_null<RpWidget*> _body;
};

View file

@ -59,6 +59,10 @@ bool LayerManager::setFocus() {
return true;
}
const LayerWidget *LayerManager::topShownLayer() const {
return _layer ? _layer->topShownLayer() : nullptr;
}
void LayerManager::ensureLayerCreated() {
if (_layer) {
return;

View file

@ -36,6 +36,8 @@ public:
void raise();
bool setFocus();
const LayerWidget *topShownLayer() const;
private:
void ensureLayerCreated();
void destroyLayer();

View file

@ -458,6 +458,17 @@ bool LayerStackWidget::layerShown() const {
return _specialLayer || currentLayer() || _mainMenu;
}
const LayerWidget *LayerStackWidget::topShownLayer() const {
if (const auto result = currentLayer()) {
return result;
} else if (const auto special = _specialLayer.data()) {
return special;
} else if (const auto menu = _mainMenu.data()) {
return menu;
}
return nullptr;
}
void LayerStackWidget::setStyleOverrides(
const style::Box *boxSt,
const style::Box *layerSt) {

View file

@ -144,6 +144,7 @@ public:
const ::Window::SectionShow &params);
bool layerShown() const;
const LayerWidget *topShownLayer() const;
~LayerStackWidget();

View file

@ -24,23 +24,71 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include <private/qwaylandwindow_p.h>
#include <private/qwaylandshellsurface_p.h>
#include <connection_thread.h>
#include <registry.h>
Q_DECLARE_METATYPE(QMargins);
using QtWaylandClient::QWaylandIntegration;
using QtWaylandClient::QWaylandWindow;
using namespace KWayland::Client;
namespace Ui {
namespace Platform {
WaylandIntegration::WaylandIntegration() {
struct WaylandIntegration::Private {
std::unique_ptr<ConnectionThread> connection;
Registry registry;
QEventLoop interfacesLoop;
bool interfacesAnnounced = false;
};
WaylandIntegration::WaylandIntegration()
: _private(std::make_unique<Private>()) {
_private->connection = std::unique_ptr<ConnectionThread>{
ConnectionThread::fromApplication(),
};
_private->registry.create(_private->connection.get());
_private->registry.setup();
QObject::connect(
_private->connection.get(),
&ConnectionThread::connectionDied,
&_private->registry,
&Registry::destroy);
QObject::connect(
&_private->registry,
&Registry::interfacesAnnounced,
[=] {
_private->interfacesAnnounced = true;
if (_private->interfacesLoop.isRunning()) {
_private->interfacesLoop.quit();
}
});
}
WaylandIntegration::~WaylandIntegration() = default;
WaylandIntegration *WaylandIntegration::Instance() {
if (!::Platform::IsWayland()) return nullptr;
static WaylandIntegration instance;
return &instance;
}
void WaylandIntegration::waitForInterfaceAnnounce() {
Expects(!_private->interfacesLoop.isRunning());
if (!_private->interfacesAnnounced) {
_private->interfacesLoop.exec();
}
}
bool WaylandIntegration::xdgDecorationSupported() {
return _private->registry.hasInterface(
Registry::Interface::XdgDecorationUnstableV1);
}
bool WaylandIntegration::windowExtentsSupported() {
// initialize shell integration before querying
if (const auto integration = static_cast<QWaylandIntegration*>(

View file

@ -14,15 +14,21 @@ namespace Platform {
class WaylandIntegration {
public:
static WaylandIntegration *Instance();
[[nodiscard]] static WaylandIntegration *Instance();
bool windowExtentsSupported();
void waitForInterfaceAnnounce();
[[nodiscard]] bool xdgDecorationSupported();
[[nodiscard]] bool windowExtentsSupported();
void setWindowExtents(QWindow *window, const QMargins &extents);
void unsetWindowExtents(QWindow *window);
bool showWindowMenu(QWindow *window);
private:
WaylandIntegration();
~WaylandIntegration();
struct Private;
const std::unique_ptr<Private> _private;
};
} // namespace Platform

View file

@ -12,8 +12,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace Ui {
namespace Platform {
struct WaylandIntegration::Private {
};
WaylandIntegration::WaylandIntegration() {
}
WaylandIntegration::~WaylandIntegration() = default;
WaylandIntegration *WaylandIntegration::Instance() {
if (!::Platform::IsWayland()) return nullptr;
@ -21,6 +26,13 @@ WaylandIntegration *WaylandIntegration::Instance() {
return &instance;
}
void WaylandIntegration::waitForInterfaceAnnounce() {
}
bool WaylandIntegration::xdgDecorationSupported() {
return false;
}
bool WaylandIntegration::windowExtentsSupported() {
return false;
}

View file

@ -6,6 +6,8 @@
//
#include "ui/platform/linux/ui_window_linux.h"
#include "ui/platform/linux/ui_linux_wayland_integration.h"
namespace Ui {
namespace Platform {
@ -14,5 +16,11 @@ std::unique_ptr<BasicWindowHelper> CreateSpecialWindowHelper(
return nullptr;
}
bool NativeWindowFrameSupported() {
const auto waylandIntegration = WaylandIntegration::Instance();
return !waylandIntegration
|| waylandIntegration->xdgDecorationSupported();
}
} // namespace Platform
} // namespace Ui

View file

@ -41,14 +41,6 @@ private:
const not_null<RpWidget*> _body;
bool _titleVisible = true;
#ifdef OS_OSX
struct WindowDrag {
QPoint windowStartPosition;
QPoint dragStartPosition;
};
std::optional<WindowDrag> _drag;
#endif // OS_OSX
};
} // namespace Platform

View file

@ -7,7 +7,7 @@
#include "ui/platform/mac/ui_window_mac.h"
#include "ui/platform/mac/ui_window_title_mac.h"
#include "ui/widgets/window.h"
#include "ui/widgets/rp_window.h"
#include "base/platform/base_platform_info.h"
#include "styles/palette.h"
@ -367,7 +367,6 @@ void WindowHelper::setGeometry(QRect rect) {
}
void WindowHelper::setupBodyTitleAreaEvents() {
#ifndef OS_OSX
const auto controls = _private->controlsRect();
qApp->installNativeEventFilter(new EventFilter(window(), [=](void *nswindow) {
const auto point = body()->mapFromGlobal(QCursor::pos());
@ -380,28 +379,6 @@ void WindowHelper::setupBodyTitleAreaEvents() {
}
return false;
}));
#else // OS_OSX
// OS X 10.10 doesn't have performWindowDragWithEvent yet.
body()->events() | rpl::start_with_next([=](not_null<QEvent*> e) {
const auto hitTest = [&] {
return bodyTitleAreaHit(
static_cast<QMouseEvent*>(e.get())->pos());
};
if (e->type() == QEvent::MouseButtonRelease
&& (static_cast<QMouseEvent*>(e.get())->button()
== Qt::LeftButton)) {
_drag = std::nullopt;
} else if (e->type() == QEvent::MouseButtonPress
&& hitTest()
&& (static_cast<QMouseEvent*>(e.get())->button()
== Qt::LeftButton)) {
_drag = { window()->pos(), static_cast<QMouseEvent*>(e.get())->globalPos() };
} else if (e->type() == QEvent::MouseMove && _drag && !window()->isFullScreen()) {
const auto delta = static_cast<QMouseEvent*>(e.get())->globalPos() - _drag->dragStartPosition;
window()->move(_drag->windowStartPosition + delta);
}
}, body()->lifetime());
#endif // OS_OSX
}
void WindowHelper::close() {
@ -435,5 +412,9 @@ std::unique_ptr<BasicWindowHelper> CreateSpecialWindowHelper(
return std::make_unique<WindowHelper>(window);
}
bool NativeWindowFrameSupported() {
return false;
}
} // namespace Platform
} // namespace Ui

View file

@ -8,7 +8,7 @@
#include "ui/platform/ui_platform_window_title.h"
#include "ui/platform/ui_platform_utility.h"
#include "ui/widgets/window.h"
#include "ui/widgets/rp_window.h"
#include "ui/widgets/shadow.h"
#include "ui/painter.h"
#include "styles/style_widgets.h"
@ -44,6 +44,9 @@ void BasicWindowHelper::setTitle(const QString &title) {
void BasicWindowHelper::setTitleStyle(const style::WindowTitle &st) {
}
void BasicWindowHelper::setNativeFrame(bool enabled) {
}
void BasicWindowHelper::setMinimumSize(QSize size) {
_window->setMinimumSize(size);
}
@ -143,14 +146,21 @@ DefaultWindowHelper::DefaultWindowHelper(not_null<RpWidget*> window)
}
void DefaultWindowHelper::init() {
_title->show();
window()->setWindowFlag(Qt::FramelessWindowHint);
if (WindowExtentsSupported()) {
window()->setAttribute(Qt::WA_TranslucentBackground);
}
window()->widthValue(
) | rpl::start_with_next([=](int width) {
rpl::combine(
window()->widthValue(),
_windowState.value(),
_title->shownValue()
) | rpl::start_with_next([=](
int width,
Qt::WindowStates windowState,
bool shown) {
const auto area = resizeArea();
_title->setGeometry(
area.left(),
@ -161,17 +171,23 @@ void DefaultWindowHelper::init() {
rpl::combine(
window()->sizeValue(),
_title->heightValue()
) | rpl::start_with_next([=](QSize size, int titleHeight) {
_windowState.value(),
_title->heightValue(),
_title->shownValue()
) | rpl::start_with_next([=](
QSize size,
Qt::WindowStates windowState,
int titleHeight,
bool titleShown) {
const auto area = resizeArea();
const auto sizeWithoutMargins = size
.shrunkBy({ 0, titleHeight, 0, 0 })
.shrunkBy({ 0, titleShown ? titleHeight : 0, 0, 0 })
.shrunkBy(area);
const auto topLeft = QPoint(
area.left(),
area.top() + titleHeight);
area.top() + (titleShown ? titleHeight : 0));
_body->setGeometry(QRect(topLeft, sizeWithoutMargins));
}, _body->lifetime());
@ -197,8 +213,10 @@ void DefaultWindowHelper::init() {
}
}, window()->lifetime());
window()->shownValue(
) | rpl::start_with_next([=](bool shown) {
rpl::combine(
window()->shownValue(),
_windowState.value()
) | rpl::start_with_next([=](bool shown, Qt::WindowStates windowState) {
if (shown) {
updateWindowExtents();
}
@ -213,10 +231,8 @@ void DefaultWindowHelper::init() {
if (mouseEvent->button() == Qt::LeftButton && edges) {
window()->windowHandle()->startSystemResize(edges);
}
} else if (e->type() == QEvent::Move
|| e->type() == QEvent::Resize
|| e->type() == QEvent::WindowStateChange) {
updateWindowExtents();
} else if (e->type() == QEvent::WindowStateChange) {
_windowState = window()->windowState();
}
}, window()->lifetime());
@ -233,7 +249,9 @@ bool DefaultWindowHelper::hasShadow() const {
}
QMargins DefaultWindowHelper::resizeArea() const {
if (window()->isMaximized() || window()->isFullScreen()) {
if (window()->isMaximized()
|| window()->isFullScreen()
|| _title->isHidden()) {
return QMargins();
}
@ -282,7 +300,7 @@ bool DefaultWindowHelper::eventFilter(QObject *obj, QEvent *e) {
// doesn't work with RpWidget::events() for some reason
if (e->type() == QEvent::MouseMove
&& obj->isWidgetType()
&& static_cast<QWidget*>(window()) == static_cast<QWidget*>(obj)) {
&& window()->isAncestorOf(static_cast<QWidget*>(obj))) {
const auto mouseEvent = static_cast<QMouseEvent*>(e);
const auto currentPoint = mouseEvent->windowPos().toPoint();
const auto edges = edgesFromPos(currentPoint);
@ -310,25 +328,25 @@ void DefaultWindowHelper::setTitleStyle(const style::WindowTitle &st) {
_title->st()->height);
}
void DefaultWindowHelper::setNativeFrame(bool enabled) {
window()->windowHandle()->setFlag(Qt::FramelessWindowHint, !enabled);
_title->setVisible(!enabled);
updateWindowExtents();
}
void DefaultWindowHelper::setMinimumSize(QSize size) {
const auto sizeWithMargins = size
.grownBy({ 0, _title->height(), 0, 0 })
.grownBy(resizeArea());
const auto sizeWithMargins = size.grownBy(bodyPadding());
window()->setMinimumSize(sizeWithMargins);
}
void DefaultWindowHelper::setFixedSize(QSize size) {
const auto sizeWithMargins = size
.grownBy({ 0, _title->height(), 0, 0 })
.grownBy(resizeArea());
const auto sizeWithMargins = size.grownBy(bodyPadding());
window()->setFixedSize(sizeWithMargins);
_title->setResizeEnabled(false);
}
void DefaultWindowHelper::setGeometry(QRect rect) {
window()->setGeometry(rect
.marginsAdded({ 0, _title->height(), 0, 0 })
.marginsAdded(resizeArea()));
window()->setGeometry(rect.marginsAdded(bodyPadding()));
}
void DefaultWindowHelper::paintBorders(QPainter &p) {
@ -376,7 +394,7 @@ void DefaultWindowHelper::paintBorders(QPainter &p) {
}
void DefaultWindowHelper::updateWindowExtents() {
if (hasShadow()) {
if (hasShadow() && !_title->isHidden()) {
Platform::SetWindowExtents(
window()->windowHandle(),
resizeArea());
@ -388,6 +406,14 @@ void DefaultWindowHelper::updateWindowExtents() {
}
}
int DefaultWindowHelper::titleHeight() const {
return _title->isHidden() ? 0 : _title->height();
}
QMargins DefaultWindowHelper::bodyPadding() const {
return resizeArea() + QMargins{ 0, titleHeight(), 0, 0 };
}
void DefaultWindowHelper::updateCursor(Qt::Edges edges) {
if (((edges & Qt::LeftEdge) && (edges & Qt::TopEdge))
|| ((edges & Qt::RightEdge) && (edges & Qt::BottomEdge))) {

View file

@ -30,6 +30,7 @@ public:
[[nodiscard]] virtual not_null<RpWidget*> body();
virtual void setTitle(const QString &title);
virtual void setTitleStyle(const style::WindowTitle &st);
virtual void setNativeFrame(bool enabled);
virtual void setMinimumSize(QSize size);
virtual void setFixedSize(QSize size);
virtual void setStaysOnTop(bool enabled);
@ -67,6 +68,7 @@ public:
not_null<RpWidget*> body() override;
void setTitle(const QString &title) override;
void setTitleStyle(const style::WindowTitle &st) override;
void setNativeFrame(bool enabled) override;
void setMinimumSize(QSize size) override;
void setFixedSize(QSize size) override;
void setGeometry(QRect rect) override;
@ -82,10 +84,13 @@ private:
void paintBorders(QPainter &p);
void updateWindowExtents();
void updateCursor(Qt::Edges edges);
[[nodiscard]] int titleHeight() const;
[[nodiscard]] QMargins bodyPadding() const;
const not_null<DefaultTitleWidget*> _title;
const not_null<RpWidget*> _body;
bool _extentsSet = false;
rpl::variable<Qt::WindowStates> _windowState = Qt::WindowNoState;
};
@ -100,5 +105,7 @@ private:
return std::make_unique<DefaultWindowHelper>(window);
}
bool NativeWindowFrameSupported();
} // namespace Platform
} // namespace Ui

View file

@ -101,6 +101,24 @@ HRESULT WinApiSetWindowTheme(
return method ? method(hWnd, pszSubAppName, pszSubIdList) : HRESULT();
}
void FixAeroSnap(HWND handle) {
SetWindowLongPtr(
handle,
GWL_STYLE,
GetWindowLongPtr(handle, GWL_STYLE) | WS_CAPTION | WS_THICKFRAME);
}
[[nodiscard]] HWND ResolveWindowHandle(not_null<QWidget*> widget) {
if (!::Platform::IsWindows8OrGreater()) {
widget->setWindowFlag(Qt::FramelessWindowHint);
}
const auto result = GetWindowHandle(widget);
if (!::Platform::IsWindows8OrGreater()) {
FixAeroSnap(result);
}
return result;
}
} // namespace
class WindowHelper::NativeFilter final : public QAbstractNativeEventFilter {
@ -145,13 +163,12 @@ bool WindowHelper::NativeFilter::nativeEventFilter(
WindowHelper::WindowHelper(not_null<RpWidget*> window)
: BasicWindowHelper(window)
, _handle(GetWindowHandle(window))
, _handle(ResolveWindowHandle(window))
, _title(Ui::CreateChild<TitleWidget>(window.get()))
, _body(Ui::CreateChild<RpWidget>(window.get()))
, _shadow(window, st::windowShadowFg->c) {
, _shadow(std::in_place, window, st::windowShadowFg->c) {
Expects(_handle != nullptr);
GetNativeFilter()->registerWindow(_handle, this);
init();
}
@ -172,18 +189,49 @@ void WindowHelper::setTitleStyle(const style::WindowTitle &st) {
_title->setStyle(st);
}
void WindowHelper::setNativeFrame(bool enabled) {
if (!::Platform::IsWindows8OrGreater()) {
window()->windowHandle()->setFlag(Qt::FramelessWindowHint, !enabled);
if (!enabled) {
FixAeroSnap(_handle);
}
}
_title->setVisible(!enabled);
if (enabled) {
_shadow.reset();
} else {
_shadow.emplace(window(), st::windowShadowFg->c);
_shadow->setResizeEnabled(!fixedSize());
initialShadowUpdate();
}
updateMargins();
fixMaximizedWindow();
}
void WindowHelper::initialShadowUpdate() {
using Change = WindowShadow::Change;
const auto noShadowStates = (Qt::WindowMinimized | Qt::WindowMaximized);
if ((window()->windowState() & noShadowStates) || window()->isHidden()) {
_shadow->update(Change::Hidden);
} else {
_shadow->update(Change::Moved | Change::Resized | Change::Shown);
}
}
void WindowHelper::setMinimumSize(QSize size) {
window()->setMinimumSize(size.width(), _title->height() + size.height());
window()->setMinimumSize(size.width(), titleHeight() + size.height());
}
void WindowHelper::setFixedSize(QSize size) {
window()->setFixedSize(size.width(), _title->height() + size.height());
window()->setFixedSize(size.width(), titleHeight() + size.height());
_title->setResizeEnabled(false);
_shadow.setResizeEnabled(false);
if (_shadow) {
_shadow->setResizeEnabled(false);
}
}
void WindowHelper::setGeometry(QRect rect) {
window()->setGeometry(rect.marginsAdded({ 0, _title->height(), 0, 0 }));
window()->setGeometry(rect.marginsAdded({ 0, titleHeight(), 0, 0 }));
}
void WindowHelper::showFullScreen() {
@ -203,21 +251,30 @@ void WindowHelper::showNormal() {
}
void WindowHelper::init() {
_title->show();
GetNativeFilter()->registerWindow(_handle, this);
style::PaletteChanged(
) | rpl::start_with_next([=] {
_shadow.setColor(st::windowShadowFg->c);
if (_shadow) {
_shadow->setColor(st::windowShadowFg->c);
}
Ui::ForceFullRepaint(window());
}, window()->lifetime());
rpl::combine(
window()->sizeValue(),
_title->heightValue()
) | rpl::start_with_next([=](QSize size, int titleHeight) {
_title->heightValue(),
_title->shownValue()
) | rpl::start_with_next([=](
QSize size,
int titleHeight,
bool titleShown) {
_body->setGeometry(
0,
titleHeight,
titleShown ? titleHeight : 0,
size.width(),
size.height() - titleHeight);
size.height() - (titleShown ? titleHeight : 0));
}, _body->lifetime());
updateMargins();
@ -243,6 +300,8 @@ void WindowHelper::init() {
window()->windowHandle(),
&QWindow::windowStateChanged,
handleStateChanged);
initialShadowUpdate();
}
bool WindowHelper::handleNativeEvent(
@ -256,22 +315,27 @@ bool WindowHelper::handleNativeEvent(
if (LOWORD(wParam) == WA_CLICKACTIVE) {
Ui::MarkInactivePress(window(), true);
}
if (LOWORD(wParam) != WA_INACTIVE) {
_shadow.update(WindowShadow::Change::Activate);
} else {
_shadow.update(WindowShadow::Change::Deactivate);
if (_shadow) {
if (LOWORD(wParam) != WA_INACTIVE) {
_shadow->update(WindowShadow::Change::Activate);
} else {
_shadow->update(WindowShadow::Change::Deactivate);
}
}
window()->update();
} return false;
case WM_NCPAINT: {
if (::Platform::IsWindows8OrGreater()) {
if (::Platform::IsWindows8OrGreater() || _title->isHidden()) {
return false;
}
if (result) *result = 0;
} return true;
case WM_NCCALCSIZE: {
if (_title->isHidden()) {
return false;
}
WINDOWPLACEMENT wp;
wp.length = sizeof(WINDOWPLACEMENT);
if (GetWindowPlacement(_handle, &wp)
@ -315,6 +379,9 @@ bool WindowHelper::handleNativeEvent(
} return true;
case WM_NCACTIVATE: {
if (_title->isHidden()) {
return false;
}
if (IsCompositionEnabled()) {
const auto res = DefWindowProc(_handle, msg, wParam, -1);
if (result) *result = res;
@ -326,16 +393,18 @@ bool WindowHelper::handleNativeEvent(
case WM_WINDOWPOSCHANGING:
case WM_WINDOWPOSCHANGED: {
WINDOWPLACEMENT wp;
wp.length = sizeof(WINDOWPLACEMENT);
if (GetWindowPlacement(_handle, &wp)
&& (wp.showCmd == SW_SHOWMAXIMIZED
|| wp.showCmd == SW_SHOWMINIMIZED)) {
_shadow.update(WindowShadow::Change::Hidden);
} else {
_shadow.update(
WindowShadow::Change::Moved | WindowShadow::Change::Resized,
(WINDOWPOS*)lParam);
if (_shadow) {
WINDOWPLACEMENT wp;
wp.length = sizeof(WINDOWPLACEMENT);
if (GetWindowPlacement(_handle, &wp)
&& (wp.showCmd == SW_SHOWMAXIMIZED
|| wp.showCmd == SW_SHOWMINIMIZED)) {
_shadow->update(WindowShadow::Change::Hidden);
} else {
_shadow->update(
WindowShadow::Change::Moved | WindowShadow::Change::Resized,
(WINDOWPOS*)lParam);
}
}
} return false;
@ -354,30 +423,36 @@ bool WindowHelper::handleNativeEvent(
window()->windowHandle()->windowStateChanged(state);
}
updateMargins();
const auto changes = (wParam == SIZE_MINIMIZED
|| wParam == SIZE_MAXIMIZED)
? WindowShadow::Change::Hidden
: (WindowShadow::Change::Resized
| WindowShadow::Change::Shown);
_shadow.update(changes);
if (_shadow) {
const auto changes = (wParam == SIZE_MINIMIZED
|| wParam == SIZE_MAXIMIZED)
? WindowShadow::Change::Hidden
: (WindowShadow::Change::Resized
| WindowShadow::Change::Shown);
_shadow->update(changes);
}
}
} return false;
case WM_SHOWWINDOW: {
const auto style = GetWindowLongPtr(_handle, GWL_STYLE);
const auto changes = WindowShadow::Change::Resized
| ((wParam && !(style & (WS_MAXIMIZE | WS_MINIMIZE)))
? WindowShadow::Change::Shown
: WindowShadow::Change::Hidden);
_shadow.update(changes);
if (_shadow) {
const auto style = GetWindowLongPtr(_handle, GWL_STYLE);
const auto changes = WindowShadow::Change::Resized
| ((wParam && !(style & (WS_MAXIMIZE | WS_MINIMIZE)))
? WindowShadow::Change::Shown
: WindowShadow::Change::Hidden);
_shadow->update(changes);
}
} return false;
case WM_MOVE: {
_shadow.update(WindowShadow::Change::Moved);
if (_shadow) {
_shadow->update(WindowShadow::Change::Moved);
}
} return false;
case WM_NCHITTEST: {
if (!result) {
if (!result || _title->isHidden()) {
return false;
}
@ -389,7 +464,8 @@ bool WindowHelper::handleNativeEvent(
p.y - r.top + _marginsDelta.top());
if (!window()->rect().contains(mapped)) {
*result = HTTRANSPARENT;
} else if (!_title->geometry().contains(mapped)) {
} else if (_title->isHidden()
|| !_title->geometry().contains(mapped)) {
*result = HTCLIENT;
} else switch (_title->hitTest(_title->pos() + mapped)) {
case HitTestResult::Client:
@ -409,6 +485,9 @@ bool WindowHelper::handleNativeEvent(
} return true;
case WM_NCRBUTTONUP: {
if (_title->isHidden()) {
return false;
}
SendMessage(_handle, WM_SYSCOMMAND, SC_MOUSEMENU, lParam);
} return true;
@ -459,6 +538,10 @@ bool WindowHelper::fixedSize() const {
return window()->minimumSize() == window()->maximumSize();
}
int WindowHelper::titleHeight() const {
return _title->isHidden() ? 0 : _title->height();
}
void WindowHelper::updateMargins() {
if (_updatingMargins) return;
@ -519,8 +602,11 @@ void WindowHelper::updateMargins() {
_marginsDelta = QMargins();
}
if (_isFullScreen) {
if (_isFullScreen || _title->isHidden()) {
margins = QMargins();
if (_title->isHidden()) {
_marginsDelta = QMargins();
}
}
if (const auto native = QGuiApplication::platformNativeInterface()) {
native->setWindowProperty(
@ -573,6 +659,25 @@ void WindowHelper::updateSystemMenu(Qt::WindowState state) {
}
}
void WindowHelper::fixMaximizedWindow() {
auto r = RECT();
GetClientRect(_handle, &r);
const auto style = GetWindowLongPtr(_handle, GWL_STYLE);
const auto styleEx = GetWindowLongPtr(_handle, GWL_EXSTYLE);
AdjustWindowRectEx(&r, style, false, styleEx);
if (style & WS_MAXIMIZE) {
auto w = RECT();
GetWindowRect(_handle, &w);
if (const auto hMonitor = MonitorFromRect(&w, MONITOR_DEFAULTTONEAREST)) {
MONITORINFO mi;
mi.cbSize = sizeof(mi);
GetMonitorInfo(hMonitor, &mi);
const auto m = mi.rcWork;
SetWindowPos(_handle, 0, 0, 0, m.right - m.left - _marginsDelta.left() - _marginsDelta.right(), m.bottom - m.top - _marginsDelta.top() - _marginsDelta.bottom(), SWP_NOMOVE | SWP_NOSENDCHANGING | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREPOSITION);
}
}
}
not_null<WindowHelper::NativeFilter*> WindowHelper::GetNativeFilter() {
Expects(QCoreApplication::instance() != nullptr);
@ -619,5 +724,9 @@ std::unique_ptr<BasicWindowHelper> CreateSpecialWindowHelper(
return std::make_unique<WindowHelper>(window);
}
bool NativeWindowFrameSupported() {
return true;
}
} // namespace Platform
} // namespace Ui

View file

@ -24,6 +24,7 @@ public:
not_null<RpWidget*> body() override;
void setTitle(const QString &title) override;
void setTitleStyle(const style::WindowTitle &st) override;
void setNativeFrame(bool enabled) override;
void setMinimumSize(QSize size) override;
void setFixedSize(QSize size) override;
void setGeometry(QRect rect) override;
@ -38,6 +39,8 @@ private:
void updateMargins();
void updateSystemMenu();
void updateSystemMenu(Qt::WindowState state);
void initialShadowUpdate();
void fixMaximizedWindow();
[[nodiscard]] bool handleNativeEvent(
UINT msg,
WPARAM wParam,
@ -45,12 +48,13 @@ private:
LRESULT *result);
[[nodiscard]] bool fixedSize() const;
[[nodiscard]] int titleHeight() const;
static not_null<NativeFilter*> GetNativeFilter();
const HWND _handle = nullptr;
const not_null<TitleWidget*> _title;
const not_null<RpWidget*> _body;
WindowShadow _shadow;
std::optional<WindowShadow> _shadow;
bool _updatingMargins = false;
QMargins _marginsDelta;
HMENU _menu = nullptr;

View file

@ -4,13 +4,13 @@
// For license and copyright information please follow this link:
// https://github.com/desktop-app/legal/blob/master/LEGAL
//
#include "ui/widgets/window.h"
#include "ui/widgets/rp_window.h"
#include "ui/platform/ui_platform_window.h"
namespace Ui {
Window::Window(QWidget *parent)
RpWindow::RpWindow(QWidget *parent)
: RpWidget(parent)
, _helper(Platform::CreateWindowHelper(this)) {
Expects(_helper != nullptr);
@ -18,53 +18,57 @@ Window::Window(QWidget *parent)
hide();
}
Window::~Window() = default;
RpWindow::~RpWindow() = default;
not_null<RpWidget*> Window::body() {
not_null<RpWidget*> RpWindow::body() {
return _helper->body();
}
not_null<const RpWidget*> Window::body() const {
not_null<const RpWidget*> RpWindow::body() const {
return _helper->body().get();
}
void Window::setTitle(const QString &title) {
void RpWindow::setTitle(const QString &title) {
_helper->setTitle(title);
}
void Window::setTitleStyle(const style::WindowTitle &st) {
void RpWindow::setTitleStyle(const style::WindowTitle &st) {
_helper->setTitleStyle(st);
}
void Window::setMinimumSize(QSize size) {
void RpWindow::setNativeFrame(bool enabled) {
_helper->setNativeFrame(enabled);
}
void RpWindow::setMinimumSize(QSize size) {
_helper->setMinimumSize(size);
}
void Window::setFixedSize(QSize size) {
void RpWindow::setFixedSize(QSize size) {
_helper->setFixedSize(size);
}
void Window::setStaysOnTop(bool enabled) {
void RpWindow::setStaysOnTop(bool enabled) {
_helper->setStaysOnTop(enabled);
}
void Window::setGeometry(QRect rect) {
void RpWindow::setGeometry(QRect rect) {
_helper->setGeometry(rect);
}
void Window::showFullScreen() {
void RpWindow::showFullScreen() {
_helper->showFullScreen();
}
void Window::showNormal() {
void RpWindow::showNormal() {
_helper->showNormal();
}
void Window::close() {
void RpWindow::close() {
_helper->close();
}
void Window::setBodyTitleArea(
void RpWindow::setBodyTitleArea(
Fn<WindowTitleHitTestFlags(QPoint)> testMethod) {
_helper->setBodyTitleArea(std::move(testMethod));
}

View file

@ -29,16 +29,17 @@ inline constexpr bool is_flag_type(WindowTitleHitTestFlag) {
}
using WindowTitleHitTestFlags = base::flags<WindowTitleHitTestFlag>;
class Window : public RpWidget {
class RpWindow : public RpWidget {
public:
explicit Window(QWidget *parent = nullptr);
~Window();
explicit RpWindow(QWidget *parent = nullptr);
~RpWindow();
[[nodiscard]] not_null<RpWidget*> body();
[[nodiscard]] not_null<const RpWidget*> body() const;
void setTitle(const QString &title);
void setTitleStyle(const style::WindowTitle &st);
void setNativeFrame(bool enabled);
void setMinimumSize(QSize size);
void setFixedSize(QSize size);
void setStaysOnTop(bool enabled);