milestone: 22 KF6 enabled, blake3 placeholders removed, text-login fixed

- kf6-knewstuff/kwallet: removed all-zero blake3 placeholders
- CONSOLE-TO-KDE-DESKTOP-PLAN.md: 20→22 KF6 enabled count
- BOOT-PROCESS-IMPROVEMENT-PLAN.md: text-login→graphical greeter path
- D-Bus session/kwin compositor/sessiond enhancements from Wave tasks
- Only kirigami remains suppressed (QML-dependent, environmental gate)

Zero warnings. 24 commits total.
This commit is contained in:
2026-04-29 14:48:47 +01:00
parent cb2e75e640
commit edb68153e3
621 changed files with 1034826 additions and 223 deletions
@@ -0,0 +1,128 @@
# SPDX-FileCopyrightText: Alexander Lohnau <alexander.lohnau@gmx.de>
# SPDX-License-Identifier: BSD-2-Clause
set(KNEWSTUFFWIDGETS_INSTALL_INCLUDEDIR "${KDE_INSTALL_INCLUDEDIR_KF}/KNewStuffWidgets")
add_library(KF6NewStuffWidgets)
add_library(KF6::NewStuffWidgets ALIAS KF6NewStuffWidgets)
set_target_properties(KF6NewStuffWidgets PROPERTIES
VERSION ${KNEWSTUFF_VERSION}
SOVERSION ${KNEWSTUFF_SOVERSION}
EXPORT_NAME NewStuffWidgets
)
ecm_qt_declare_logging_category(KF6NewStuffWidgets
HEADER knewstuffwidgets_debug.h
IDENTIFIER KNEWSTUFFWIDGETS
CATEGORY_NAME kf.newstuff.widgets
DESCRIPTION "knewstuff (Widgets Lib)"
EXPORT KNEWSTUFF
)
ecm_generate_export_header(KF6NewStuffWidgets
EXPORT_FILE_NAME knewstuffwidgets_export.h
BASE_NAME KNewStuffWidgets
GROUP_BASE_NAME KF
VERSION ${KF_VERSION}
USE_VERSION_HEADER
VERSION_BASE_NAME KNewStuff
DEPRECATED_BASE_VERSION 0
DEPRECATION_VERSIONS
EXCLUDE_DEPRECATED_BEFORE_AND_AT ${EXCLUDE_DEPRECATED_BEFORE_AND_AT}
)
target_sources(KF6NewStuffWidgets PRIVATE
action.cpp button.cpp dialog.cpp resources.qrc
)
target_link_libraries(KF6NewStuffWidgets
PUBLIC
KF6::NewStuffCore
Qt6::Widgets
PRIVATE
KF6::I18n
KF6::ConfigCore
KF6::WidgetsAddons
# QtQuickDialogWrapper
Qt6::Qml
Qt6::Quick
Qt6::QuickWidgets
)
target_link_libraries(KF6NewStuffWidgets PRIVATE
KF6::I18nQml
)
target_include_directories(KF6NewStuffWidgets
PUBLIC "$<BUILD_INTERFACE:${KNewStuff_BINARY_DIR};${CMAKE_CURRENT_BINARY_DIR}>"
INTERFACE
"$<INSTALL_INTERFACE:${KNEWSTUFFWIDGETS_INSTALL_INCLUDEDIR}>"
"$<INSTALL_INTERFACE:${KDE_INSTALL_INCLUDEDIR_KF}/KNewStuff>" # module version header
)
ecm_generate_headers(KNewStuffWidgets_CamelCase_HEADERS
HEADER_NAMES
Action
Button
Dialog
REQUIRED_HEADERS KNewStuffWidgets_HEADERS
OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR}/KNSWidgets
)
install(
FILES
${KNewStuffWidgets_CamelCase_HEADERS}
${KNewStuffWidgets_HEADERS}
${CMAKE_CURRENT_BINARY_DIR}/knewstuffwidgets_export.h
DESTINATION ${KNEWSTUFFWIDGETS_INSTALL_INCLUDEDIR}/KNSWidgets
COMPONENT Devel
)
install(TARGETS KF6NewStuffWidgets EXPORT KF6NewStuffTargets ${KF_INSTALL_TARGETS_DEFAULT_ARGS})
if (BUILD_DESIGNERPLUGIN)
include(ECMAddQtDesignerPlugin)
ecm_qtdesignerplugin_widget(KNSWidgets::Button
INCLUDE_FILE "KNSWidgets/Button"
TOOLTIP "KHotNewStuff push button that encapsulats most of the details involved in using KHotNewStuff in it."
GROUP "Buttons (KF6)"
)
ecm_add_qtdesignerplugin(knewstuffwidgets
NAME KNewStuffWidgets
OUTPUT_NAME knewstuff6widgets
WIDGETS
KNSWidgets::Button
LINK_LIBRARIES
KF6::NewStuffWidgets
INSTALL_DESTINATION "${KDE_INSTALL_QTPLUGINDIR}/designer"
COMPONENT Devel
)
endif()
if(BUILD_QCH)
ecm_add_qch(
KF6NewStuffWidgets_QCH
NAME KNewStuffWidgets
BASE_NAME KF6NewStuffWidgets
VERSION ${KF_VERSION}
ORG_DOMAIN org.kde
SOURCES ${KNewStuffWidgets_HEADERS}
LINK_QCHS
KF6NewStuffCore_QCH
KF6NewStuff_QCH
INCLUDE_DIRS
${CMAKE_CURRENT_BINARY_DIR}
${KNewStuff_BINARY_DIR}
BLANK_MACROS
KNEWSTUFFWIDGETS_EXPORT
"KNEWSTUFFWIDGETS_DEPRECATED_VERSION(x, y, t)"
TAGFILE_INSTALL_DESTINATION ${KDE_INSTALL_QTQCHDIR}
QCH_INSTALL_DESTINATION ${KDE_INSTALL_QTQCHDIR}
COMPONENT Devel
)
endif()
@@ -0,0 +1,60 @@
/*
SPDX-FileCopyrightText: 2021 Oleg Solovyov <mcpain@altlinux.org>
SPDX-FileCopyrightText: 2021 Alexander Lohnau <alexander.lohnau@gmx.de>
SPDX-License-Identifier: LGPL-2.1-or-later
*/
#include "action.h"
#include "dialog.h"
#include <KAuthorized>
#include <KLocalizedString>
namespace KNSWidgets
{
class ActionPrivate
{
public:
QString configFile;
std::unique_ptr<Dialog> dialog;
};
Action::Action(const QString &text, const QString &configFile, QObject *parent)
: QAction(parent)
, d(new ActionPrivate)
{
if (text.isEmpty()) {
setText(i18nc("@action", "Download New Stuff…"));
} else {
setText(text);
}
d->configFile = configFile;
const bool authorized = KAuthorized::authorize(KAuthorized::GHNS);
if (!authorized) {
setEnabled(false);
setVisible(false);
}
setIcon(QIcon::fromTheme(QStringLiteral("get-hot-new-stuff")));
connect(this, &QAction::triggered, this, [this]() {
if (!KAuthorized::authorize(KAuthorized::GHNS)) {
return;
}
if (!d->dialog) {
d->dialog.reset(new KNSWidgets::Dialog(d->configFile));
d->dialog->setWindowTitle(this->text().remove(QLatin1Char('&')));
connect(d->dialog.get(), &KNSWidgets::Dialog::finished, this, [this]() {
Q_EMIT dialogFinished(d->dialog->changedEntries());
});
}
d->dialog->open();
});
}
Action::~Action() = default;
}
#include "moc_action.cpp"
@@ -0,0 +1,57 @@
/*
SPDX-FileCopyrightText: 2021 Oleg Solovyov <mcpain@altlinux.org>
SPDX-FileCopyrightText: 2021 Alexander Lohnau <alexander.lohnau@gmx.de>
SPDX-License-Identifier: LGPL-2.1-or-later
*/
#ifndef KNEWSTUFF3ACTION_H
#define KNEWSTUFF3ACTION_H
#include <KNSCore/Entry>
#include <QAction>
#include "knewstuffwidgets_export.h"
namespace KNSWidgets
{
class ActionPrivate;
/**
* @class Action action.h <KNSWidgets/Action>
*
* QAction subclass that encapsulates the logic for showing the KNewStuff dialog.
* If KNewStuff is disabled using KAuthorized, the action is hidden.
* @see KAuthorized::GenericRestriction::GHNS
*
* @since 5.90
*/
class KNEWSTUFFWIDGETS_EXPORT Action : public QAction
{
Q_OBJECT
public:
/**
* Constrcuts a KNSWidgets::Action instance
*
* @param text describing what is being downloaded.
* It should be a text beginning with "Download New ..." for consistency
* @param configFile the name of the .knsrc file
* @param parent the parent object
*/
explicit Action(const QString &text, const QString &configFile, QObject *parent);
~Action();
Q_SIGNALS:
/**
* Emitted when the dialog has been closed.
*/
void dialogFinished(const QList<KNSCore::Entry> &changedEntries);
private:
std::unique_ptr<ActionPrivate> d;
};
}
#endif // KNEWSTUFFACTION_H
@@ -0,0 +1,83 @@
/*
SPDX-FileCopyrightText: 2004 Aaron J. Seigo <aseigo@kde.org>
SPDX-FileCopyrightText: 2021 Alexander Lohnau <alexander.lohnau@gmx.de>
SPDX-License-Identifier: LGPL-2.1-or-later
*/
#include "button.h"
#include "dialog.h"
#include <KAuthorized>
#include <KLocalizedString>
#include <KMessageBox>
#include <QPointer>
namespace KNSWidgets
{
class ButtonPrivate
{
public:
explicit ButtonPrivate(Button *qq)
: q(qq)
{
}
void showDialog()
{
if (!KAuthorized::authorize(KAuthorized::GHNS)) {
KMessageBox::information(q, QStringLiteral("Get Hot New Stuff is disabled by the administrator"), QStringLiteral("Get Hot New Stuff disabled"));
return;
}
Q_ASSERT_X(!configFile.isEmpty(), Q_FUNC_INFO, "The configFile for the KNSWidgets::Button must be explicitly set");
if (!dialog) {
dialog.reset(new KNSWidgets::Dialog(configFile, q));
dialog->setWindowTitle(q->text().remove(QLatin1Char('&')));
QObject::connect(dialog.get(), &KNSWidgets::Dialog::finished, q, [this]() {
Q_EMIT q->dialogFinished(dialog->changedEntries());
});
}
dialog->open();
}
Button *q;
QString configFile;
std::unique_ptr<KNSWidgets::Dialog> dialog;
};
Button::Button(const QString &text, const QString &configFile, QWidget *parent)
: QPushButton(parent)
, d(new ButtonPrivate(this))
{
setText(text);
d->configFile = configFile;
const bool authorized = KAuthorized::authorize(KAuthorized::GHNS);
if (!authorized) {
setEnabled(false);
setVisible(false);
}
setIcon(QIcon::fromTheme(QStringLiteral("get-hot-new-stuff")));
connect(this, &QAbstractButton::clicked, this, [this]() {
d->showDialog();
});
}
Button::Button(QWidget *parent)
: Button(i18nc("@action", "Download New Stuff…"), QString(), parent)
{
}
Button::~Button() = default;
void Button::setConfigFile(const QString &configFile)
{
Q_ASSERT_X(!d->dialog, Q_FUNC_INFO, "the configFile property must be set before the dialog is first shown");
d->configFile = configFile;
}
}
#include "moc_button.cpp"
@@ -0,0 +1,70 @@
/*
SPDX-FileCopyrightText: 2004 Aaron J. Seigo <aseigo@kde.org>
SPDX-FileCopyrightText: 2021 Alexander Lohnau <alexander.lohnau@gmx.de>
SPDX-License-Identifier: LGPL-2.1-or-later
*/
#ifndef KNEWSTUFFWIDGETSBUTTON_H
#define KNEWSTUFFWIDGETSBUTTON_H
#include <KNSCore/Entry>
#include <QPushButton>
#include <memory>
#include "knewstuffwidgets_export.h"
namespace KNSWidgets
{
class ButtonPrivate;
/**
* @class Button button.h <KNSWidgets/Button>
*
* QPushButton subclass that encapsulates the logic for showing the KNewStuff dialog.
* If KNewStuff is disabled using KAuthorized, the button is hidden.
* @see KAuthorized::GenericRestriction::GHNS
*
* @since 5.91
*/
class KNEWSTUFFWIDGETS_EXPORT Button : public QPushButton
{
Q_OBJECT
public:
/**
* Constructor used when the details of the KHotNewStuff
* download is known when the button is created.
*
* @param text describing what is being downloaded.
* It should be a text beginning with "Download New ..." for consistency
* @param configFile the name of the .knsrc file
* @param parent the parent widget
*/
explicit Button(const QString &text, const QString &configFile, QWidget *parent);
/**
* Constructor used when the code is generated from a .ui file
* After the UI is set up, you must call setConfigFile(QString)
*/
explicit Button(QWidget *parent);
~Button() override;
/**
* @note This should only be used when crating the button from a UI-file
*/
void setConfigFile(const QString &configFile);
Q_SIGNALS:
/**
* emitted when the dialog has been closed
*/
void dialogFinished(const QList<KNSCore::Entry> &changedEntries);
private:
const std::unique_ptr<ButtonPrivate> d;
};
}
#endif // KNEWSTUFFBUTTON_H
@@ -0,0 +1,123 @@
/*
SPDX-FileCopyrightText: 2020-2023 Alexander Lohnau <alexander.lohnau@gmx.de>
SPDX-License-Identifier: LGPL-2.1-or-later
*/
#include "dialog.h"
#include <QQmlContext>
#include <QQmlEngine>
#include <QQmlIncubationController>
#include <QQuickItem>
#include <QQuickWidget>
#include <QVBoxLayout>
#include <KLocalizedQmlContext>
#include "core/enginebase.h"
#include "knewstuffwidgets_debug.h"
using namespace KNSWidgets;
class KNSWidgets::DialogPrivate
{
public:
KNSCore::EngineBase *engine = nullptr;
QQuickItem *item = nullptr;
QList<KNSCore::Entry> changedEntries;
void onEntryEvent(const KNSCore::Entry &entry, KNSCore::Entry::EntryEvent event)
{
if (event == KNSCore::Entry::StatusChangedEvent) {
if (entry.status() == KNSCore::Entry::Installing || entry.status() == KNSCore::Entry::Updating) {
return; // We do not care about intermediate states
}
// To make sure we have no duplicates and always the latest entry
changedEntries.removeOne(entry);
changedEntries.append(entry);
}
}
};
class PeriodicIncubationController : public QObject, public QQmlIncubationController
{
public:
explicit PeriodicIncubationController()
: QObject()
{
startTimer(16);
}
protected:
void timerEvent(QTimerEvent *) override
{
incubateFor(5);
}
};
Dialog::Dialog(const QString &configFile, QWidget *parent)
: QDialog(parent)
, d(new DialogPrivate())
{
auto engine = new QQmlEngine(this);
auto context = new KLocalizedQmlContext(engine);
engine->setIncubationController(new PeriodicIncubationController());
setMinimumSize(600, 400);
// Keep in sync with the sizes in Dialog.qml and DialogContent.qml
// (reminder that a default gridUnit is 18px).
// TODO: It would be best to use a Kirigami.ApplicationWindow and use
// a multiple of gridUnit directly!
resize(792, 540);
context->setTranslationDomain(QStringLiteral("knewstuff6"));
engine->rootContext()->setContextObject(context);
engine->rootContext()->setContextProperty(QStringLiteral("knsrcfile"), configFile);
auto page = new QQuickWidget(engine, this);
page->setSource(QUrl(QStringLiteral("qrc:/knswidgets/page.qml")));
page->setResizeMode(QQuickWidget::SizeRootObjectToView);
auto layout = new QVBoxLayout(this);
layout->addWidget(page);
layout->setContentsMargins(0, 0, 0, 0);
if (QQuickItem *root = page->rootObject()) {
d->item = root;
d->engine = qvariant_cast<KNSCore::EngineBase *>(root->property("engine"));
Q_ASSERT(d->engine);
// clang-format off
// Old-style connect, because we don't want the QML engine to be exported
connect(d->engine,
SIGNAL(entryEvent(KNSCore::Entry,KNSCore::Entry::EntryEvent)),
this,
SLOT(onEntryEvent(KNSCore::Entry,KNSCore::Entry::EntryEvent)));
// clang-format on
} else {
qWarning(KNEWSTUFFWIDGETS) << "Error creating QtQuickDialogWrapper component:" << page->errors();
}
}
Dialog::~Dialog()
{
delete d->item;
}
KNSCore::EngineBase *Dialog::engine()
{
return d->engine;
}
QList<KNSCore::Entry> Dialog::changedEntries() const
{
return d->changedEntries;
}
void Dialog::open()
{
QDialog::open();
d->changedEntries.clear();
}
#include "moc_dialog.cpp"
@@ -0,0 +1,66 @@
/*
SPDX-FileCopyrightText: 2020-2023 Alexander Lohnau <alexander.lohnau@gmx.de>
SPDX-License-Identifier: LGPL-2.1-or-later
*/
#ifndef KNEWSTUFF_QTQUICKDIALOGWRAPPER_H
#define KNEWSTUFF_QTQUICKDIALOGWRAPPER_H
#include <KNSCore/Entry>
#include <KNSCore/ErrorCode>
#include <QDialog>
#include "knewstuffwidgets_export.h"
namespace KNSCore
{
class EngineBase;
};
namespace KNSWidgets
{
class DialogPrivate;
/**
* @class Dialog dialog.h <KNSWidgets/Dialog>
*
* This class is a wrapper around the QtQuick QML dialog. This dialog content is loaded QQuickWidget.
* It is recommended to reuse an instance of this class if it is expected that the user reopens the dialog.
* For most usecases, you should use KNSWidgets::Button or KNSWidgets::Action directly.
*
* @since 6.0
*/
class KNEWSTUFFWIDGETS_EXPORT Dialog : public QDialog
{
Q_OBJECT
public:
/**
* Constructs a new Dialog for the given config file and parent widget
*/
explicit Dialog(const QString &configFile, QWidget *parent = nullptr);
~Dialog() override;
/**
* Engine that is used by the dialog, might be null if the engine failed to initialize.
* @return KNSCore::EngineBase used by the dialog
*/
KNSCore::EngineBase *engine();
/**
* Entries that were changed while the user interacted with the dialog
* @since 5.94
*/
QList<KNSCore::Entry> changedEntries() const;
void open() override;
private:
Q_PRIVATE_SLOT(d, void onEntryEvent(const KNSCore::Entry &entry, KNSCore::Entry::EntryEvent event))
const std::unique_ptr<DialogPrivate> d;
Q_DISABLE_COPY(Dialog)
};
}
#endif // KNEWSTUFF_QTQUICKDIALOGWRAPPER_H
@@ -0,0 +1,6 @@
import org.kde.newstuff as NewStuff
NewStuff.DialogContent {
id: component
configFile: knsrcfile
}
@@ -0,0 +1,9 @@
<RCC>
<!--
SPDX-FileCopyrightText: Alexander Lohnau <alexander.lohnau@gmx.de>
SPDX-License-Identifier: CC0-1.0
-->
<qresource prefix="/knswidgets">
<file>page.qml</file>
</qresource>
</RCC>