Compare commits

...

6 commits

Author SHA1 Message Date
a408fe0f29
widgets/cliprect: set default background color to white
Matches Rectangle.
2025-05-25 18:09:51 -07:00
33c3881c31
wayland/screencopy: use all dmabuf planes and modifiers in egl image
Fixes black texture on nvidia
2025-05-25 18:09:51 -07:00
4b690ffe2f
wayland/layershell: ensure bridge is nulled on layer destruction
Fixes rare race condition crashes.
2025-05-25 18:09:51 -07:00
e5a31693c4
widgets/wrapper: default resizeChild to true
Better reflects how wrapper types are used 99% of the time.
2025-05-25 18:09:51 -07:00
d797e63215
widgets/wrapper: set WrapperRectangle border.width to 0
Works around the implicit 1px border applied to Rectangles
when border is accessed, and works around QTBUG-137166.
2025-05-25 18:09:50 -07:00
846dfc51a1
widgets/wrapper: apply implicit size override on componentComplete 2025-05-25 18:09:46 -07:00
12 changed files with 124 additions and 16 deletions

View file

@ -118,6 +118,7 @@ PanelWindow {
anchors.fill: parent
color: palette.active.window
border.color: root.failed ? "#b53030" : palette.active.accent
border.width: 1
radius: 10
margin: 10

View file

@ -6,6 +6,7 @@
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include <EGL/egl.h>
#include <EGL/eglext.h>
@ -555,23 +556,88 @@ WlBufferQSGTexture* WlDmaBuffer::createQsgTexture(QQuickWindow* window) const {
auto* display = qEglContext->display();
// Ref https://github.com/hyprwm/hyprlock/blob/da1d076d849fc0f298c1d287bddd04802bf7d0f9/src/renderer/Screencopy.cpp#L194
struct AttribNameSet {
EGLAttrib fd;
EGLAttrib offset;
EGLAttrib pitch;
EGLAttrib modlo;
EGLAttrib modhi;
};
static auto attribNames = std::array<AttribNameSet, 4> {
AttribNameSet {
.fd = EGL_DMA_BUF_PLANE0_FD_EXT,
.offset = EGL_DMA_BUF_PLANE0_OFFSET_EXT,
.pitch = EGL_DMA_BUF_PLANE0_PITCH_EXT,
.modlo = EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT,
.modhi = EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT
},
AttribNameSet {
.fd = EGL_DMA_BUF_PLANE1_FD_EXT,
.offset = EGL_DMA_BUF_PLANE1_OFFSET_EXT,
.pitch = EGL_DMA_BUF_PLANE1_PITCH_EXT,
.modlo = EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT,
.modhi = EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT
},
AttribNameSet {
.fd = EGL_DMA_BUF_PLANE2_FD_EXT,
.offset = EGL_DMA_BUF_PLANE2_OFFSET_EXT,
.pitch = EGL_DMA_BUF_PLANE2_PITCH_EXT,
.modlo = EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT,
.modhi = EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT
},
AttribNameSet {
.fd = EGL_DMA_BUF_PLANE3_FD_EXT,
.offset = EGL_DMA_BUF_PLANE3_OFFSET_EXT,
.pitch = EGL_DMA_BUF_PLANE3_PITCH_EXT,
.modlo = EGL_DMA_BUF_PLANE3_MODIFIER_LO_EXT,
.modhi = EGL_DMA_BUF_PLANE3_MODIFIER_HI_EXT
}
};
// clang-format off
auto attribs = std::array<EGLAttrib, 6 * 2 + 1> {
auto attribs = std::vector<EGLAttrib> {
EGL_WIDTH, this->width,
EGL_HEIGHT, this->height,
EGL_LINUX_DRM_FOURCC_EXT, this->format,
EGL_DMA_BUF_PLANE0_FD_EXT, this->planes[0].fd, // NOLINT
EGL_DMA_BUF_PLANE0_OFFSET_EXT, this->planes[0].offset, // NOLINT
EGL_DMA_BUF_PLANE0_PITCH_EXT, this->planes[0].stride, // NOLINT
EGL_NONE
};
// clang-format on
if (this->planeCount > 4) {
qFatal(logDmabuf) << "Could not create EGL attrib array with more than 4 planes. Count:"
<< this->planeCount;
}
for (auto i = 0; i != this->planeCount; i++) {
const auto& names = attribNames[i];
const auto& plane = this->planes[i]; // NOLINT
// clang-format off
attribs.insert(attribs.end(), {
names.fd, plane.fd,
names.offset, plane.offset,
names.pitch, plane.stride,
});
// clang-format on
// clang-format off
if (this->modifier != DRM_FORMAT_MOD_INVALID) {
attribs.insert(attribs.end(), {
names.modlo, static_cast<EGLAttrib>(this->modifier & 0xFFFFFFFF),
names.modhi, static_cast<EGLAttrib>(this->modifier >> 32),
});
}
// clang-format on
}
attribs.emplace_back(EGL_NONE);
auto* eglImage =
eglCreateImage(display, EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, nullptr, attribs.data());
if (eglImage == EGL_NO_IMAGE) {
qFatal() << "failed to make egl image" << eglGetError();
qFatal() << "Failed to create egl image" << eglGetError();
return nullptr;
}

View file

@ -173,7 +173,10 @@ LayerSurface::LayerSurface(LayerShellIntegration* shell, QtWaylandClient::QWayla
this->bridge->surface = this;
}
LayerSurface::~LayerSurface() { this->destroy(); }
LayerSurface::~LayerSurface() {
delete this->bridge;
this->destroy();
}
void LayerSurface::zwlr_layer_surface_v1_configure(quint32 serial, quint32 width, quint32 height) {
this->ack_configure(serial);

View file

@ -34,7 +34,8 @@ ProxiedWindow* WlrLayershell::retrieveWindow(QObject* oldInstance) {
auto* window = old == nullptr ? nullptr : old->disownWindow();
if (window != nullptr) {
this->bridge = LayerSurfaceBridge::init(window, this->computeState());
this->connectBridge(LayerSurfaceBridge::init(window, this->computeState()));
if (this->bridge) {
return window;
} else {
@ -48,7 +49,7 @@ ProxiedWindow* WlrLayershell::retrieveWindow(QObject* oldInstance) {
ProxiedWindow* WlrLayershell::createQQuickWindow() {
auto* window = this->ProxyWindowBase::createQQuickWindow();
this->bridge = LayerSurfaceBridge::init(window, this->computeState());
this->connectBridge(LayerSurfaceBridge::init(window, this->computeState()));
if (!this->bridge) {
qWarning() << "Could not attach Layershell extension to new QQuickWindow. Layer will not "
"behave correctly.";
@ -72,6 +73,32 @@ void WlrLayershell::connectWindow() {
this->updateAutoExclusion();
}
ProxiedWindow* WlrLayershell::disownWindow(bool keepItemOwnership) {
auto* window = this->ProxyWindowBase::disownWindow(keepItemOwnership);
if (this->bridge) {
this->connectBridge(nullptr);
}
return window;
}
void WlrLayershell::connectBridge(LayerSurfaceBridge* bridge) {
if (this->bridge) {
QObject::disconnect(this->bridge, nullptr, this, nullptr);
}
this->bridge = bridge;
if (bridge) {
QObject::connect(this->bridge, &QObject::destroyed, this, &WlrLayershell::onBridgeDestroyed);
}
}
void WlrLayershell::onBridgeDestroyed() {
this->bridge = nullptr;
}
bool WlrLayershell::deleteOnInvisible() const {
// Qt windows behave weirdly when geometry is modified and setVisible(false)
// is subsequently called in the same frame.

View file

@ -122,6 +122,7 @@ public:
ProxiedWindow* retrieveWindow(QObject* oldInstance) override;
ProxiedWindow* createQQuickWindow() override;
void connectWindow() override;
ProxiedWindow* disownWindow(bool keepItemOwnership = false) override;
[[nodiscard]] bool deleteOnInvisible() const override;
void onPolished() override;
@ -175,10 +176,12 @@ signals:
private slots:
void updateAutoExclusion();
void onBridgeDestroyed();
private:
[[nodiscard]] LayerSurfaceState computeState() const;
void connectBridge(LayerSurfaceBridge* bridge);
void onStateChanged();
bool compositorPicksScreen = true;

View file

@ -77,7 +77,7 @@ Item {
anchors.fill: root
fragmentShader: `qrc:/Quickshell/Widgets/shaders/cliprect${root.contentUnderBorder ? "-ub" : ""}.frag.qsb`
property Rectangle rect: rectangle
property color backgroundColor
property color backgroundColor: "white"
property color borderColor: root.border.color
property ShaderEffectSource content: ShaderEffectSource {

View file

@ -39,7 +39,7 @@ ClippingRectangle {
/// Defaults to @@margin, and may be reset by assigning `undefined`.
property /*real*/alias rightMargin: manager.rightMargin
/// Determines if child item should be resized larger than its implicit size if
/// the parent is resized larger than its implicit size. Defaults to false.
/// the parent is resized larger than its implicit size. Defaults to true.
property /*bool*/alias resizeChild: manager.resizeChild
/// Overrides the implicit width of the wrapper.
///

View file

@ -53,7 +53,7 @@ Item {
/// Defaults to @@margin, and may be reset by assigning `undefined`.
property /*real*/alias rightMargin: manager.rightMargin
/// Determines if child item should be resized larger than its implicit size if
/// the parent is resized larger than its implicit size. Defaults to false.
/// the parent is resized larger than its implicit size. Defaults to true.
property /*bool*/alias resizeChild: manager.resizeChild
/// Overrides the implicit width of the wrapper.
///

View file

@ -41,7 +41,7 @@ MouseArea {
/// Defaults to @@margin, and may be reset by assigning `undefined`.
property /*real*/alias rightMargin: manager.rightMargin
/// Determines if child item should be resized larger than its implicit size if
/// the parent is resized larger than its implicit size. Defaults to false.
/// the parent is resized larger than its implicit size. Defaults to true.
property /*bool*/alias resizeChild: manager.resizeChild
/// Overrides the implicit width of the wrapper.
///

View file

@ -43,7 +43,7 @@ Rectangle {
/// Defaults to @@margin, and may be reset by assigning `undefined`.
property /*real*/alias rightMargin: manager.rightMargin
/// Determines if child item should be resized larger than its implicit size if
/// the parent is resized larger than its implicit size. Defaults to false.
/// the parent is resized larger than its implicit size. Defaults to true.
property /*bool*/alias resizeChild: manager.resizeChild
/// Overrides the implicit width of the wrapper.
///
@ -58,6 +58,12 @@ Rectangle {
/// See @@WrapperManager.child for details.
property alias child: manager.child
// Reading the border property implicitly sets border width to 1.
// Setting it to 0 here means the user will also have to set border.width
// even if they just want 1, but it prevents adding unexpected padding
// and works around QTBUG-137166 otherwise.
border.width: 0
MarginWrapperManager {
id: manager
extraMargin: (root.contentInsideBorder ? root.border.width : 0) + root.extraMargin

View file

@ -90,6 +90,8 @@ void MarginWrapperManager::componentComplete() {
if (this->mWrapper) {
this->bWrapperWidth.setBinding([this] { return this->mWrapper->bindableWidth().value(); });
this->bWrapperHeight.setBinding([this] { return this->mWrapper->bindableHeight().value(); });
this->setWrapperImplicitWidth();
this->setWrapperImplicitHeight();
}
}

View file

@ -68,7 +68,7 @@ class MarginWrapperManager: public WrapperManager {
/// Defaults to @@margin, and may be reset by assigning `undefined`.
Q_PROPERTY(qreal rightMargin READ rightMargin WRITE setRightMargin RESET resetRightMargin NOTIFY rightMarginChanged FINAL);
/// Determines if child item should be resized larger than its implicit size if
/// the parent is resized larger than its implicit size. Defaults to false.
/// the parent is resized larger than its implicit size. Defaults to true.
Q_PROPERTY(bool resizeChild READ default WRITE default BINDABLE bindableResizeChild NOTIFY resizeChildChanged FINAL);
/// Overrides the implicit width of the wrapper.
///
@ -170,7 +170,7 @@ protected:
private:
// clang-format off
Q_OBJECT_BINDABLE_PROPERTY(MarginWrapperManager, bool, bResizeChild);
Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(MarginWrapperManager, bool, bResizeChild, true);
Q_OBJECT_BINDABLE_PROPERTY(MarginWrapperManager, qreal, bMargin, &MarginWrapperManager::marginChanged);
Q_OBJECT_BINDABLE_PROPERTY(MarginWrapperManager, qreal, bExtraMargin, &MarginWrapperManager::baseMarginChanged);