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);