Updated lib_ui sources to TDesktop version 2.9.3
This commit is contained in:
commit
3bc35a74ec
26 changed files with 672 additions and 164 deletions
|
|
@ -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()
|
||||
|
||||
|
|
|
|||
250
qt_conf/gpu_driver_bug_list.json
Normal file
250
qt_conf/gpu_driver_bug_list.json
Normal 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"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -134,8 +134,6 @@ private:
|
|||
|
||||
};
|
||||
|
||||
[[nodiscard]] GLint CurrentSingleComponentFormat();
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
inline constexpr auto kFormatRGBA = GL_BGRA_EXT;
|
||||
inline constexpr auto kSwizzleRedBlue = false;
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -36,6 +36,8 @@ public:
|
|||
void raise();
|
||||
bool setFocus();
|
||||
|
||||
const LayerWidget *topShownLayer() const;
|
||||
|
||||
private:
|
||||
void ensureLayerCreated();
|
||||
void destroyLayer();
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -144,6 +144,7 @@ public:
|
|||
const ::Window::SectionShow ¶ms);
|
||||
|
||||
bool layerShown() const;
|
||||
const LayerWidget *topShownLayer() const;
|
||||
|
||||
~LayerStackWidget();
|
||||
|
||||
|
|
|
|||
|
|
@ -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*>(
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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))) {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
|
|
@ -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);
|
||||
Loading…
Add table
Reference in a new issue