diff --git a/CMakeLists.txt b/CMakeLists.txt index 55310c8..f463fed 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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() diff --git a/qt_conf/gpu_driver_bug_list.json b/qt_conf/gpu_driver_bug_list.json new file mode 100644 index 0000000..9f4b7da --- /dev/null +++ b/qt_conf/gpu_driver_bug_list.json @@ -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" + ] + } + ] +} diff --git a/qt_conf/win.qrc b/qt_conf/win.qrc index df8db39..fcc0acf 100644 --- a/qt_conf/win.qrc +++ b/qt_conf/win.qrc @@ -2,4 +2,7 @@ qt_win.conf + + gpu_driver_bug_list.json + diff --git a/ui/gl/gl_detection.cpp b/ui/gl/gl_detection.cpp index 10a47ed..33c929a 100644 --- a/ui/gl/gl_detection.cpp +++ b/ui/gl/gl_detection.cpp @@ -17,6 +17,12 @@ #include #include +#ifdef Q_OS_WIN +#include +#include +#include +#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( 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 EGLExtensions(not_null context) { + const auto native = QGuiApplication::platformNativeInterface(); + Assert(native != nullptr); + + const auto display = static_cast( + native->nativeResourceForContext( + QByteArrayLiteral("egldisplay"), + context)); + return display + ? QByteArray(eglQueryString(display, EGL_EXTENSIONS)).split(' ') + : QList(); +} + #endif // Q_OS_WIN } // namespace Ui::GL diff --git a/ui/gl/gl_detection.h b/ui/gl/gl_detection.h index c50cab7..b197bcc 100644 --- a/ui/gl/gl_detection.h +++ b/ui/gl/gl_detection.h @@ -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 EGLExtensions( + not_null context); + } // namespace Ui::GL diff --git a/ui/gl/gl_image.cpp b/ui/gl/gl_image.cpp index 633d108..3db6653 100644 --- a/ui/gl/gl_image.cpp +++ b/ui/gl/gl_image.cpp @@ -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 diff --git a/ui/gl/gl_image.h b/ui/gl/gl_image.h index fe8fd3e..75c24ec 100644 --- a/ui/gl/gl_image.h +++ b/ui/gl/gl_image.h @@ -134,8 +134,6 @@ private: }; -[[nodiscard]] GLint CurrentSingleComponentFormat(); - #ifdef Q_OS_WIN inline constexpr auto kFormatRGBA = GL_BGRA_EXT; inline constexpr auto kSwizzleRedBlue = false; diff --git a/ui/gl/gl_shader.cpp b/ui/gl/gl_shader.cpp index 3079a52..2f47edd 100644 --- a/ui/gl/gl_shader.cpp +++ b/ui/gl/gl_shader.cpp @@ -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, diff --git a/ui/gl/gl_window.cpp b/ui/gl/gl_window.cpp index 2cc0f86..f2cc816 100644 --- a/ui/gl/gl_window.cpp +++ b/ui/gl/gl_window.cpp @@ -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 Window::window() const { +not_null Window::window() const { return _window.get(); } -not_null Window::widget() const { +not_null Window::widget() const { return _body.get(); } -std::unique_ptr Window::createWindow() { - auto result = std::make_unique(); +std::unique_ptr Window::createWindow() { + auto result = std::make_unique(); 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(); + result = std::make_unique(); } } return result; } -std::unique_ptr Window::createNativeBodyWrap() { +std::unique_ptr Window::createNativeBodyWrap() { if constexpr (!kUseNativeChild) { return nullptr; } const auto create = [] { - auto result = std::make_unique(); + auto result = std::make_unique(); result->setWindowFlags(Qt::FramelessWindowHint | Qt::Window); result->setAttribute(Qt::WA_NativeWindow); result->setAttribute(Qt::WA_DontCreateNativeAncestors); @@ -81,14 +81,14 @@ std::unique_ptr 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 Window::createNativeBodyWrap() { const auto childWindow = raw->windowHandle(); base::install_event_filter(childWindow, [=](not_null event) { if (event->type() == QEvent::Expose && childWindow->isExposed()) { - Ui::Platform::SendWMPaintForce(_window.get()); + Platform::SendWMPaintForce(_window.get()); } return base::EventFilterResult::Continue; }); diff --git a/ui/gl/gl_window.h b/ui/gl/gl_window.h index bfa4199..797fcdf 100644 --- a/ui/gl/gl_window.h +++ b/ui/gl/gl_window.h @@ -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 window() const; - [[nodiscard]] not_null widget() const; + [[nodiscard]] not_null window() const; + [[nodiscard]] not_null widget() const; private: - [[nodiscard]] std::unique_ptr createWindow(); - [[nodiscard]] std::unique_ptr createNativeBodyWrap(); + [[nodiscard]] std::unique_ptr createWindow(); + [[nodiscard]] std::unique_ptr createNativeBodyWrap(); - Ui::GL::Backend _backend = Ui::GL::Backend(); - const std::unique_ptr _window; - const std::unique_ptr _bodyNativeWrap; - const not_null _body; + Backend _backend = Backend(); + const std::unique_ptr _window; + const std::unique_ptr _bodyNativeWrap; + const not_null _body; }; diff --git a/ui/layers/layer_manager.cpp b/ui/layers/layer_manager.cpp index b5ca389..91e3e9e 100644 --- a/ui/layers/layer_manager.cpp +++ b/ui/layers/layer_manager.cpp @@ -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; diff --git a/ui/layers/layer_manager.h b/ui/layers/layer_manager.h index 4f53169..cce68dc 100644 --- a/ui/layers/layer_manager.h +++ b/ui/layers/layer_manager.h @@ -36,6 +36,8 @@ public: void raise(); bool setFocus(); + const LayerWidget *topShownLayer() const; + private: void ensureLayerCreated(); void destroyLayer(); diff --git a/ui/layers/layer_widget.cpp b/ui/layers/layer_widget.cpp index 5eb99f7..8e70249 100644 --- a/ui/layers/layer_widget.cpp +++ b/ui/layers/layer_widget.cpp @@ -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) { diff --git a/ui/layers/layer_widget.h b/ui/layers/layer_widget.h index f45f16e..7d7e337 100644 --- a/ui/layers/layer_widget.h +++ b/ui/layers/layer_widget.h @@ -144,6 +144,7 @@ public: const ::Window::SectionShow ¶ms); bool layerShown() const; + const LayerWidget *topShownLayer() const; ~LayerStackWidget(); diff --git a/ui/platform/linux/ui_linux_wayland_integration.cpp b/ui/platform/linux/ui_linux_wayland_integration.cpp index 4d78307..01f1e80 100644 --- a/ui/platform/linux/ui_linux_wayland_integration.cpp +++ b/ui/platform/linux/ui_linux_wayland_integration.cpp @@ -24,23 +24,71 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include #include +#include +#include + 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 connection; + Registry registry; + QEventLoop interfacesLoop; + bool interfacesAnnounced = false; +}; + +WaylandIntegration::WaylandIntegration() +: _private(std::make_unique()) { + _private->connection = std::unique_ptr{ + 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( diff --git a/ui/platform/linux/ui_linux_wayland_integration.h b/ui/platform/linux/ui_linux_wayland_integration.h index ed877f2..c975539 100644 --- a/ui/platform/linux/ui_linux_wayland_integration.h +++ b/ui/platform/linux/ui_linux_wayland_integration.h @@ -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; }; } // namespace Platform diff --git a/ui/platform/linux/ui_linux_wayland_integration_dummy.cpp b/ui/platform/linux/ui_linux_wayland_integration_dummy.cpp index 972b09c..0239433 100644 --- a/ui/platform/linux/ui_linux_wayland_integration_dummy.cpp +++ b/ui/platform/linux/ui_linux_wayland_integration_dummy.cpp @@ -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; } diff --git a/ui/platform/linux/ui_window_linux.cpp b/ui/platform/linux/ui_window_linux.cpp index c98869a..a353c32 100644 --- a/ui/platform/linux/ui_window_linux.cpp +++ b/ui/platform/linux/ui_window_linux.cpp @@ -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 CreateSpecialWindowHelper( return nullptr; } +bool NativeWindowFrameSupported() { + const auto waylandIntegration = WaylandIntegration::Instance(); + return !waylandIntegration + || waylandIntegration->xdgDecorationSupported(); +} + } // namespace Platform } // namespace Ui diff --git a/ui/platform/mac/ui_window_mac.h b/ui/platform/mac/ui_window_mac.h index f4c9622..31dda13 100644 --- a/ui/platform/mac/ui_window_mac.h +++ b/ui/platform/mac/ui_window_mac.h @@ -41,14 +41,6 @@ private: const not_null _body; bool _titleVisible = true; -#ifdef OS_OSX - struct WindowDrag { - QPoint windowStartPosition; - QPoint dragStartPosition; - }; - std::optional _drag; -#endif // OS_OSX - }; } // namespace Platform diff --git a/ui/platform/mac/ui_window_mac.mm b/ui/platform/mac/ui_window_mac.mm index fe297a2..3bea72e 100644 --- a/ui/platform/mac/ui_window_mac.mm +++ b/ui/platform/mac/ui_window_mac.mm @@ -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 e) { - const auto hitTest = [&] { - return bodyTitleAreaHit( - static_cast(e.get())->pos()); - }; - if (e->type() == QEvent::MouseButtonRelease - && (static_cast(e.get())->button() - == Qt::LeftButton)) { - _drag = std::nullopt; - } else if (e->type() == QEvent::MouseButtonPress - && hitTest() - && (static_cast(e.get())->button() - == Qt::LeftButton)) { - _drag = { window()->pos(), static_cast(e.get())->globalPos() }; - } else if (e->type() == QEvent::MouseMove && _drag && !window()->isFullScreen()) { - const auto delta = static_cast(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 CreateSpecialWindowHelper( return std::make_unique(window); } +bool NativeWindowFrameSupported() { + return false; +} + } // namespace Platform } // namespace Ui diff --git a/ui/platform/ui_platform_window.cpp b/ui/platform/ui_platform_window.cpp index 42949a3..c2f5fc4 100644 --- a/ui/platform/ui_platform_window.cpp +++ b/ui/platform/ui_platform_window.cpp @@ -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 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(window()) == static_cast(obj)) { + && window()->isAncestorOf(static_cast(obj))) { const auto mouseEvent = static_cast(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))) { diff --git a/ui/platform/ui_platform_window.h b/ui/platform/ui_platform_window.h index 58a1c8a..3580b11 100644 --- a/ui/platform/ui_platform_window.h +++ b/ui/platform/ui_platform_window.h @@ -30,6 +30,7 @@ public: [[nodiscard]] virtual not_null 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 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 _title; const not_null _body; bool _extentsSet = false; + rpl::variable _windowState = Qt::WindowNoState; }; @@ -100,5 +105,7 @@ private: return std::make_unique(window); } +bool NativeWindowFrameSupported(); + } // namespace Platform } // namespace Ui diff --git a/ui/platform/win/ui_window_win.cpp b/ui/platform/win/ui_window_win.cpp index 2f853c3..2c72ddb 100644 --- a/ui/platform/win/ui_window_win.cpp +++ b/ui/platform/win/ui_window_win.cpp @@ -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 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 window) : BasicWindowHelper(window) -, _handle(GetWindowHandle(window)) +, _handle(ResolveWindowHandle(window)) , _title(Ui::CreateChild(window.get())) , _body(Ui::CreateChild(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::GetNativeFilter() { Expects(QCoreApplication::instance() != nullptr); @@ -619,5 +724,9 @@ std::unique_ptr CreateSpecialWindowHelper( return std::make_unique(window); } +bool NativeWindowFrameSupported() { + return true; +} + } // namespace Platform } // namespace Ui diff --git a/ui/platform/win/ui_window_win.h b/ui/platform/win/ui_window_win.h index 9abfe60..955e156 100644 --- a/ui/platform/win/ui_window_win.h +++ b/ui/platform/win/ui_window_win.h @@ -24,6 +24,7 @@ public: not_null 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 GetNativeFilter(); const HWND _handle = nullptr; const not_null _title; const not_null _body; - WindowShadow _shadow; + std::optional _shadow; bool _updatingMargins = false; QMargins _marginsDelta; HMENU _menu = nullptr; diff --git a/ui/widgets/window.cpp b/ui/widgets/rp_window.cpp similarity index 56% rename from ui/widgets/window.cpp rename to ui/widgets/rp_window.cpp index 3423701..7adad8f 100644 --- a/ui/widgets/window.cpp +++ b/ui/widgets/rp_window.cpp @@ -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 Window::body() { +not_null RpWindow::body() { return _helper->body(); } -not_null Window::body() const { +not_null 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 testMethod) { _helper->setBodyTitleArea(std::move(testMethod)); } diff --git a/ui/widgets/window.h b/ui/widgets/rp_window.h similarity index 90% rename from ui/widgets/window.h rename to ui/widgets/rp_window.h index 336ff4f..49524fd 100644 --- a/ui/widgets/window.h +++ b/ui/widgets/rp_window.h @@ -29,16 +29,17 @@ inline constexpr bool is_flag_type(WindowTitleHitTestFlag) { } using WindowTitleHitTestFlags = base::flags; -class Window : public RpWidget { +class RpWindow : public RpWidget { public: - explicit Window(QWidget *parent = nullptr); - ~Window(); + explicit RpWindow(QWidget *parent = nullptr); + ~RpWindow(); [[nodiscard]] not_null body(); [[nodiscard]] not_null 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);