diff --git a/applets/notifications/package/contents/ui/NotificationItem.qml b/applets/notifications/package/contents/ui/NotificationItem.qml --- a/applets/notifications/package/contents/ui/NotificationItem.qml +++ b/applets/notifications/package/contents/ui/NotificationItem.qml @@ -30,7 +30,7 @@ MouseArea { id: notificationItem width: parent.width - implicitHeight: Math.max(appIconItem.visible || imageItem.visible ? units.iconSizes.large : 0, mainLayout.height) + implicitHeight: Math.max(appIconItem.valid || imageItem.nativeWidth > 0 ? units.iconSizes.large : 0, mainLayout.height) // We need to clip here because we support displaying images through // and if we don't clip, they will be painted over the borders of the dialog/item @@ -153,7 +153,7 @@ left: parent.left } - visible: !imageItem.visible && valid + visible: imageItem.nativeWidth == 0 && valid animated: false } @@ -170,7 +170,7 @@ anchors { top: parent.top - left: appIconItem.visible || imageItem.visible ? appIconItem.right : parent.left + left: appIconItem.valid || imageItem.nativeWidth > 0 ? appIconItem.right : parent.left right: parent.right leftMargin: units.smallSpacing } @@ -244,7 +244,7 @@ // If there is a big notification followed by a small one, the height // of the popup does not always shrink back, so this forces it to // height=0 when those are invisible. -1 means "default to implicitHeight" - Layout.maximumHeight: bodyText.visible || actionsColumn.visible ? -1 : 0 + Layout.maximumHeight: bodyText.length > 0 || notificationItem.actions.count > 0 ? -1 : 0 PlasmaExtras.ScrollArea { id: bodyTextScrollArea diff --git a/applets/notifications/package/contents/ui/NotificationPopup.qml b/applets/notifications/package/contents/ui/NotificationPopup.qml --- a/applets/notifications/package/contents/ui/NotificationPopup.qml +++ b/applets/notifications/package/contents/ui/NotificationPopup.qml @@ -53,33 +53,34 @@ function populatePopup(notification) { notificationProperties = notification notificationTimer.interval = notification.expireTimeout - notificationTimer.restart() - + notificationTimer.restart(); + //temporarly disable height binding, avoids an useless window resize when removing the old actions + heightBinding.when = false; // notification.actions is a JS array, but we can easily append that to our model notificationItem.actions.clear() notificationItem.actions.append(notificationProperties.actions) + //enable height binding again, finally do the resize + heightBinding.when = true; } function clearPopup() { notificationProperties = {} notificationItem.actions.clear() } - Behavior on y { - NumberAnimation { - duration: units.longDuration - easing.type: Easing.OutQuad - } - } - mainItem: NotificationItem { id: notificationItem hoverEnabled: true LayoutMirroring.enabled: Qt.application.layoutDirection === Qt.RightToLeft LayoutMirroring.childrenInherit: true - height: implicitHeight + //the binding needs to be disabled when re-populating actions, to minimize resizes + Binding on height { + id: heightBinding + value: notificationItem.implicitHeight + when: true + } Timer { id: notificationTimer diff --git a/applets/notifications/plugin/notificationshelper.h b/applets/notifications/plugin/notificationshelper.h --- a/applets/notifications/plugin/notificationshelper.h +++ b/applets/notifications/plugin/notificationshelper.h @@ -71,7 +71,6 @@ // void plasmoidScreenChanged(); private Q_SLOTS: - void onPopupShown(); void onPopupClosed(); void processQueues(); void processShow(); diff --git a/applets/notifications/plugin/notificationshelper.cpp b/applets/notifications/plugin/notificationshelper.cpp --- a/applets/notifications/plugin/notificationshelper.cpp +++ b/applets/notifications/plugin/notificationshelper.cpp @@ -76,23 +76,10 @@ this, SLOT(onPopupClosed())); connect(popup, &QWindow::heightChanged, this, &NotificationsHelper::repositionPopups, Qt::UniqueConnection); - connect(popup, &QWindow::visibleChanged, this, &NotificationsHelper::onPopupShown, Qt::UniqueConnection); - popup->setProperty("initialPositionSet", false); -} - -void NotificationsHelper::onPopupShown() -{ - QWindow *popup = qobject_cast(sender()); - if (!popup || !popup->isVisible()) { - return; - } - - // Make sure Dialog lays everything out and gets proper geometry - QMetaObject::invokeMethod(popup, "updateVisibility", Qt::DirectConnection, Q_ARG(bool, true)); - - // Now we can position the popups properly as the geometry is now known - repositionPopups(); + //We are sure that after visibleChanged the size is final + //and the first expose event didn't arrive yet + connect(popup, &QQuickWindow::visibleChanged, this, &NotificationsHelper::repositionPopups); } void NotificationsHelper::processQueues() @@ -151,7 +138,8 @@ QMetaObject::invokeMethod(popup, "populatePopup", Qt::DirectConnection, Q_ARG(QVariant, notificationData)); Q_EMIT popupShown(popup); - QTimer::singleShot(300, popup, &QWindow::show); + //use setproperty so the Dialog reimplementation will be used + popup->setProperty("visible", true); if (!m_dispatchTimer->isActive()) { m_dispatchTimer->start(); @@ -177,10 +165,6 @@ popup->hide(); - // Make sure the popup gets placed correctly - // next time it's put on screen - popup->setProperty("initialPositionSet", false); - QMetaObject::invokeMethod(popup, "clearPopup", Qt::DirectConnection); } @@ -298,30 +282,17 @@ m_mutex->lockForWrite(); + QPoint pos; + for (int i = 0; i < m_popupsOnScreen.size(); ++i) { if (m_popupLocation == NotificationsHelper::TopLeft || m_popupLocation == NotificationsHelper::TopCenter || m_popupLocation == NotificationsHelper::TopRight) { - int posY = m_plasmoidScreen.top() + cumulativeHeight; + pos.setY(m_plasmoidScreen.top() + cumulativeHeight); - if (m_popupsOnScreen[i]->isVisible() && m_popupsOnScreen[i]->property("initialPositionSet").toBool() == true && m_popupsOnScreen[i]->y() != 0) { - //if it's visible, go through setProperty which animates it - m_popupsOnScreen[i]->setProperty("y", posY); - } else { - // ...otherwise just set it directly - m_popupsOnScreen[i]->setY(posY); - m_popupsOnScreen[i]->setProperty("initialPositionSet", true); - } } else { - int posY = m_plasmoidScreen.bottom() - cumulativeHeight - m_popupsOnScreen[i]->contentItem()->height(); - - if (m_popupsOnScreen[i]->isVisible() && m_popupsOnScreen[i]->property("initialPositionSet").toBool() == true && m_popupsOnScreen[i]->y() != 0) { - m_popupsOnScreen[i]->setProperty("y", posY); - } else { - m_popupsOnScreen[i]->setY(posY); - m_popupsOnScreen[i]->setProperty("initialPositionSet", true); - } + pos.setY(m_plasmoidScreen.bottom() - cumulativeHeight - m_popupsOnScreen[i]->height()); } switch (m_popupLocation) { @@ -332,24 +303,24 @@ //fall through to top right case TopRight: case BottomRight: - m_popupsOnScreen[i]->setX(m_plasmoidScreen.right() - m_popupsOnScreen[i]->contentItem()->width() - m_offset); + pos.setX(m_plasmoidScreen.right() - m_popupsOnScreen[i]->width() - m_offset); break; case TopCenter: case BottomCenter: - m_popupsOnScreen[i]->setX(m_plasmoidScreen.x() + (m_plasmoidScreen.width() / 2) - (m_popupsOnScreen[i]->contentItem()->width() / 2)); + pos.setX(m_plasmoidScreen.x() + (m_plasmoidScreen.width() / 2) - (m_popupsOnScreen[i]->width() / 2)); break; case TopLeft: case BottomLeft: - m_popupsOnScreen[i]->setX(m_plasmoidScreen.left() + m_offset); + pos.setX(m_plasmoidScreen.left() + m_offset); break; case Left: case Center: case Right: // Fall-through to make the compiler happy break; } - - cumulativeHeight += (m_popupsOnScreen[i]->contentItem()->height() + m_offset); + m_popupsOnScreen[i]->setPosition(pos); + cumulativeHeight += (m_popupsOnScreen[i]->height() + m_offset); } m_mutex->unlock();