API review:
isImmutable(), setIsImmutable() and isKioskImmutable() of applet and corona are merged in one property so they becamed immutability() and setImmutability() using the new type ImmutabilityType defined in plasma.h as: NotImmutable: normal behaviour UserImmutable: the user locked the desktop, can unlock it SystemImmutable: the system locked the desktop and the user can't unlock it svn path=/trunk/KDE/kdebase/workspace/libs/plasma/; revision=800724
This commit is contained in:
parent
ab377f4f18
commit
7d057a2bc2
50
applet.cpp
50
applet.cpp
@ -112,8 +112,7 @@ public:
|
|||||||
mainConfig(0),
|
mainConfig(0),
|
||||||
pendingConstraints(NoConstraint),
|
pendingConstraints(NoConstraint),
|
||||||
aspectRatioMode(Qt::KeepAspectRatio),
|
aspectRatioMode(Qt::KeepAspectRatio),
|
||||||
kioskImmutable(false),
|
immutability(NotImmutable),
|
||||||
immutable(false),
|
|
||||||
hasConfigurationInterface(false),
|
hasConfigurationInterface(false),
|
||||||
failed(false),
|
failed(false),
|
||||||
isContainment(false),
|
isContainment(false),
|
||||||
@ -333,8 +332,7 @@ public:
|
|||||||
KConfigGroup *mainConfig;
|
KConfigGroup *mainConfig;
|
||||||
Plasma::Constraints pendingConstraints;
|
Plasma::Constraints pendingConstraints;
|
||||||
Qt::AspectRatioMode aspectRatioMode;
|
Qt::AspectRatioMode aspectRatioMode;
|
||||||
bool kioskImmutable : 1;
|
ImmutabilityType immutability;
|
||||||
bool immutable : 1;
|
|
||||||
bool hasConfigurationInterface : 1;
|
bool hasConfigurationInterface : 1;
|
||||||
bool failed : 1;
|
bool failed : 1;
|
||||||
bool isContainment : 1;
|
bool isContainment : 1;
|
||||||
@ -410,7 +408,7 @@ void Applet::save(KConfigGroup* group) const
|
|||||||
{
|
{
|
||||||
// we call the dptr member directly for locked since isImmutable()
|
// we call the dptr member directly for locked since isImmutable()
|
||||||
// also checks kiosk and parent containers
|
// also checks kiosk and parent containers
|
||||||
group->writeEntry("locked", d->immutable);
|
group->writeEntry("immutability", (int)d->immutability);
|
||||||
group->writeEntry("plugin", pluginName());
|
group->writeEntry("plugin", pluginName());
|
||||||
//FIXME: for containments, we need to have some special values here w/regards to
|
//FIXME: for containments, we need to have some special values here w/regards to
|
||||||
// screen affinity (e.g. "bottom of screen 0")
|
// screen affinity (e.g. "bottom of screen 0")
|
||||||
@ -449,9 +447,7 @@ void Applet::restore(KConfigGroup *c)
|
|||||||
|
|
||||||
setZValue(z);
|
setZValue(z);
|
||||||
|
|
||||||
if (c->readEntry("locked", false)) {
|
setImmutability((ImmutabilityType)c->readEntry("immutability", (int)NotImmutable));
|
||||||
setImmutable(true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Applet::setFailedToLaunch(bool failed, const QString& reason)
|
void Applet::setFailedToLaunch(bool failed, const QString& reason)
|
||||||
@ -751,27 +747,31 @@ QString Applet::category(const QString& appletName)
|
|||||||
return offers.first()->property("X-KDE-PluginInfo-Category").toString();
|
return offers.first()->property("X-KDE-PluginInfo-Category").toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Applet::isImmutable() const
|
ImmutabilityType Applet::immutability() const
|
||||||
{
|
{
|
||||||
return d->immutable || d->kioskImmutable ||
|
//Returning the more strict immutability between the applet immutability and Corona one
|
||||||
(containment() && containment()->isImmutable()) ||
|
ImmutabilityType coronaImmutability = NotImmutable;
|
||||||
(dynamic_cast<Corona*>(scene()) && static_cast<Corona*>(scene())->isImmutable());
|
|
||||||
|
if (dynamic_cast<Corona*>(scene())) {
|
||||||
|
coronaImmutability = static_cast<Corona*>(scene())->immutability();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Applet::isKioskImmutable() const
|
if (coronaImmutability == SystemImmutable) {
|
||||||
{
|
return SystemImmutable;
|
||||||
Corona *c = dynamic_cast<Corona*>(scene());
|
} else if (coronaImmutability == UserImmutable && d->immutability != SystemImmutable) {
|
||||||
return d->kioskImmutable || (c && c->isImmutable());
|
return UserImmutable;
|
||||||
|
} else {
|
||||||
|
return d->immutability;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Applet::setImmutable(bool immutable)
|
void Applet::setImmutability(const ImmutabilityType immutable)
|
||||||
{
|
{
|
||||||
if (d->immutable == immutable ||
|
if (d->immutability == immutable) {
|
||||||
(immutable && d->kioskImmutable)) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
d->immutable = immutable;
|
d->immutability = immutable;
|
||||||
updateConstraints(ImmutableConstraint);
|
updateConstraints(ImmutableConstraint);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -866,11 +866,11 @@ void Applet::setNeedsConfiguring(bool needsConfig)
|
|||||||
|
|
||||||
void Applet::checkImmutability()
|
void Applet::checkImmutability()
|
||||||
{
|
{
|
||||||
d->kioskImmutable = globalConfig().isImmutable() || config().isImmutable() ||
|
const bool systemImmutable = globalConfig().isImmutable() || config().isImmutable() ||
|
||||||
(containment() && containment()->isKioskImmutable()) ||
|
(containment() && containment()->immutability() == SystemImmutable) ||
|
||||||
(dynamic_cast<Corona*>(scene()) && static_cast<Corona*>(scene())->isImmutable());
|
(dynamic_cast<Corona*>(scene()) && static_cast<Corona*>(scene())->immutability() == SystemImmutable);
|
||||||
|
|
||||||
if (d->kioskImmutable) {
|
if (systemImmutable) {
|
||||||
updateConstraints(ImmutableConstraint);
|
updateConstraints(ImmutableConstraint);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1218,7 +1218,7 @@ bool Applet::sceneEventFilter( QGraphicsItem * watched, QEvent * event )
|
|||||||
|
|
||||||
void Applet::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
|
void Applet::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
|
||||||
{
|
{
|
||||||
if (!isImmutable() && formFactor() == Plasma::Planar) {
|
if (d->immutability == NotImmutable && formFactor() == Plasma::Planar) {
|
||||||
QGraphicsItem *parent = parentItem();
|
QGraphicsItem *parent = parentItem();
|
||||||
Plasma::Applet *applet = qgraphicsitem_cast<Plasma::Applet*>(parent);
|
Plasma::Applet *applet = qgraphicsitem_cast<Plasma::Applet*>(parent);
|
||||||
|
|
||||||
|
25
applet.h
25
applet.h
@ -65,7 +65,7 @@ class PLASMA_EXPORT Applet : public QGraphicsWidget
|
|||||||
Q_PROPERTY(bool hasConfigurationInterface READ hasConfigurationInterface)
|
Q_PROPERTY(bool hasConfigurationInterface READ hasConfigurationInterface)
|
||||||
Q_PROPERTY(QString name READ name)
|
Q_PROPERTY(QString name READ name)
|
||||||
Q_PROPERTY(QString category READ category)
|
Q_PROPERTY(QString category READ category)
|
||||||
Q_PROPERTY(bool immutable READ isImmutable WRITE setImmutable)
|
Q_PROPERTY(ImmutabilityType immutability READ immutability WRITE setImmutability)
|
||||||
Q_PROPERTY(bool drawStandardBackground READ drawStandardBackground WRITE setDrawStandardBackground)
|
Q_PROPERTY(bool drawStandardBackground READ drawStandardBackground WRITE setDrawStandardBackground)
|
||||||
Q_PROPERTY(bool hasFailedToLaunch READ hasFailedToLaunch WRITE setFailedToLaunch)
|
Q_PROPERTY(bool hasFailedToLaunch READ hasFailedToLaunch WRITE setFailedToLaunch)
|
||||||
Q_PROPERTY(bool needsConfiguring READ needsConfiguring WRITE setNeedsConfiguring)
|
Q_PROPERTY(bool needsConfiguring READ needsConfiguring WRITE setNeedsConfiguring)
|
||||||
@ -411,9 +411,9 @@ class PLASMA_EXPORT Applet : public QGraphicsWidget
|
|||||||
QColor color() const;
|
QColor color() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return true if this applet is immutable
|
* @return The type of immutability of this applet
|
||||||
**/
|
*/
|
||||||
bool isImmutable() const;
|
ImmutabilityType immutability() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return returns whether or not the applet is using the standard
|
* @return returns whether or not the applet is using the standard
|
||||||
@ -556,11 +556,10 @@ class PLASMA_EXPORT Applet : public QGraphicsWidget
|
|||||||
|
|
||||||
public Q_SLOTS:
|
public Q_SLOTS:
|
||||||
/**
|
/**
|
||||||
* Sets whether or not this applet is immutable or not.
|
* Sets the immutability type for this applet (not immutable, user immutable or system immutable)
|
||||||
*
|
* @arg immutable the new immutability type of this applet
|
||||||
* @param immutable true if this applet should not be changeable
|
*/
|
||||||
**/
|
void setImmutability(const ImmutabilityType immutable);
|
||||||
void setImmutable(bool immutable);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Destroys the applet; it will be deleted and configurations reset.
|
* Destroys the applet; it will be deleted and configurations reset.
|
||||||
@ -654,14 +653,6 @@ class PLASMA_EXPORT Applet : public QGraphicsWidget
|
|||||||
**/
|
**/
|
||||||
void setHasConfigurationInterface(bool hasInterface);
|
void setHasConfigurationInterface(bool hasInterface);
|
||||||
|
|
||||||
//TODO: remove from API?
|
|
||||||
//At the moment is still needed by Containment because it needs the difference between a state
|
|
||||||
//that can be unlocked and one that can't (Kiosk) to display or not unlock buttons
|
|
||||||
/**
|
|
||||||
* @return true if this applet is immutable due to Kiosk settings
|
|
||||||
*/
|
|
||||||
bool isKioskImmutable() const;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the name of the applet.
|
* Returns the name of the applet.
|
||||||
*
|
*
|
||||||
|
@ -124,7 +124,7 @@ void Containment::Private::setLockToolText()
|
|||||||
Icon *icon = dynamic_cast<Plasma::Icon*>(toolbox->tool("lockWidgets"));
|
Icon *icon = dynamic_cast<Plasma::Icon*>(toolbox->tool("lockWidgets"));
|
||||||
if (icon) {
|
if (icon) {
|
||||||
// we know it's an icon becase we made it
|
// we know it's an icon becase we made it
|
||||||
icon->setText(q->isImmutable() ? i18n("Unlock Widgets") :
|
icon->setText(q->immutability() != NotImmutable ? i18n("Unlock Widgets") :
|
||||||
i18n("Lock Widgets"));
|
i18n("Lock Widgets"));
|
||||||
QSizeF iconSize = icon->sizeFromIconSize(22);
|
QSizeF iconSize = icon->sizeFromIconSize(22);
|
||||||
icon->setMinimumSize(iconSize);
|
icon->setMinimumSize(iconSize);
|
||||||
@ -262,7 +262,7 @@ void Containment::containmentConstraintsUpdated(Plasma::Constraints constraints)
|
|||||||
} else {
|
} else {
|
||||||
d->toolbox->setPos(geometry().right() - qAbs(d->toolbox->boundingRect().width()), 0);
|
d->toolbox->setPos(geometry().right() - qAbs(d->toolbox->boundingRect().width()), 0);
|
||||||
}
|
}
|
||||||
d->toolbox->enableTool("addwidgets", !isImmutable());
|
d->toolbox->enableTool("addwidgets", immutability() == NotImmutable);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (constraints & Plasma::FormFactorConstraint && d->toolbox) {
|
if (constraints & Plasma::FormFactorConstraint && d->toolbox) {
|
||||||
@ -306,9 +306,9 @@ void Containment::setContainmentType(Containment::Type type)
|
|||||||
QGraphicsWidget *zoomOutTool = addToolBoxTool("zoomOut", "zoom-out", i18n("Zoom Out"));
|
QGraphicsWidget *zoomOutTool = addToolBoxTool("zoomOut", "zoom-out", i18n("Zoom Out"));
|
||||||
connect(zoomOutTool, SIGNAL(clicked()), this, SIGNAL(zoomOut()));
|
connect(zoomOutTool, SIGNAL(clicked()), this, SIGNAL(zoomOut()));
|
||||||
|
|
||||||
if (!isKioskImmutable()) {
|
if (immutability() != SystemImmutable) {
|
||||||
QGraphicsWidget *lockTool = addToolBoxTool("lockWidgets", "object-locked",
|
QGraphicsWidget *lockTool = addToolBoxTool("lockWidgets", "object-locked",
|
||||||
isImmutable() ? i18n("Unlock Widgets") :
|
immutability() == UserImmutable ? i18n("Unlock Widgets") :
|
||||||
i18n("Lock Widgets"));
|
i18n("Lock Widgets"));
|
||||||
connect(lockTool, SIGNAL(clicked()), this, SLOT(toggleDesktopImmutability()));
|
connect(lockTool, SIGNAL(clicked()), this, SLOT(toggleDesktopImmutability()));
|
||||||
}
|
}
|
||||||
@ -401,7 +401,7 @@ void Containment::contextMenuEvent(QGraphicsSceneContextMenuEvent* event)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (scene() && !static_cast<Corona*>(scene())->isImmutable()) {
|
if (scene() && !static_cast<Corona*>(scene())->immutability() != NotImmutable) {
|
||||||
if (hasEntries) {
|
if (hasEntries) {
|
||||||
desktopMenu.addSeparator();
|
desktopMenu.addSeparator();
|
||||||
}
|
}
|
||||||
@ -423,7 +423,7 @@ void Containment::contextMenuEvent(QGraphicsSceneContextMenuEvent* event)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!scene() || (static_cast<Corona*>(scene())->isImmutable() && !KAuthorized::authorizeKAction("unlock_desktop"))) {
|
if (!scene() || (static_cast<Corona*>(scene())->immutability() != NotImmutable && !KAuthorized::authorizeKAction("unlock_desktop"))) {
|
||||||
//kDebug() << "immutability";
|
//kDebug() << "immutability";
|
||||||
Applet::contextMenuEvent(event);
|
Applet::contextMenuEvent(event);
|
||||||
return;
|
return;
|
||||||
@ -594,9 +594,17 @@ Location Containment::location() const
|
|||||||
void Containment::toggleDesktopImmutability()
|
void Containment::toggleDesktopImmutability()
|
||||||
{
|
{
|
||||||
if (corona()) {
|
if (corona()) {
|
||||||
corona()->setImmutable(!corona()->isImmutable());
|
if (corona()->immutability() == NotImmutable) {
|
||||||
|
corona()->setImmutability(UserImmutable);
|
||||||
|
} else if (corona()->immutability() == UserImmutable) {
|
||||||
|
corona()->setImmutability(NotImmutable);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
setImmutable(!isImmutable());
|
if (immutability() == NotImmutable) {
|
||||||
|
setImmutability(UserImmutable);
|
||||||
|
} else if (immutability() == UserImmutable) {
|
||||||
|
setImmutability(NotImmutable);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
d->setLockToolText();
|
d->setLockToolText();
|
||||||
@ -620,7 +628,7 @@ void Containment::clearApplets()
|
|||||||
|
|
||||||
Applet* Containment::addApplet(const QString& name, const QVariantList& args, uint id, const QRectF& appletGeometry, bool delayInit)
|
Applet* Containment::addApplet(const QString& name, const QVariantList& args, uint id, const QRectF& appletGeometry, bool delayInit)
|
||||||
{
|
{
|
||||||
if (!delayInit && isImmutable()) {
|
if (!delayInit && immutability() != NotImmutable) {
|
||||||
kDebug() << "addApplet for" << name << "requested, but we're currently immutable!";
|
kDebug() << "addApplet for" << name << "requested, but we're currently immutable!";
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -672,7 +680,7 @@ Applet* Containment::addApplet(const QString& name, const QVariantList& args, ui
|
|||||||
//there.
|
//there.
|
||||||
void Containment::addApplet(Applet *applet, const QPointF &pos, bool delayInit)
|
void Containment::addApplet(Applet *applet, const QPointF &pos, bool delayInit)
|
||||||
{
|
{
|
||||||
if (!delayInit && isImmutable()) {
|
if (!delayInit && immutability() != NotImmutable) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1227,8 +1235,8 @@ bool Containment::sceneEventFilter(QGraphicsItem *watched, QEvent *event)
|
|||||||
|
|
||||||
switch (event->type()) {
|
switch (event->type()) {
|
||||||
case QEvent::GraphicsSceneHoverEnter:
|
case QEvent::GraphicsSceneHoverEnter:
|
||||||
//kDebug() << "got hoverenterEvent" << isImmutable() << " " << applet->isImmutable();
|
//kDebug() << "got hoverenterEvent" << immutability() << " " << applet->immutability();
|
||||||
if (!isImmutable() && !applet->isImmutable()) {
|
if (immutability() == NotImmutable && applet->immutability() == NotImmutable) {
|
||||||
if (d->handles.contains(applet)) {
|
if (d->handles.contains(applet)) {
|
||||||
d->handles[applet]->startFading(AppletHandle::FadeIn);
|
d->handles[applet]->startFading(AppletHandle::FadeIn);
|
||||||
} else {
|
} else {
|
||||||
|
25
corona.cpp
25
corona.cpp
@ -48,8 +48,7 @@ class Corona::Private
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Private()
|
Private()
|
||||||
: immutable(false),
|
: immutability(NotImmutable),
|
||||||
kioskImmutable(false),
|
|
||||||
mimetype("text/x-plasmoidservicename"),
|
mimetype("text/x-plasmoidservicename"),
|
||||||
config(0)
|
config(0)
|
||||||
{
|
{
|
||||||
@ -107,8 +106,7 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool immutable;
|
ImmutabilityType immutability;
|
||||||
bool kioskImmutable;
|
|
||||||
QString mimetype;
|
QString mimetype;
|
||||||
QString configName;
|
QString configName;
|
||||||
KSharedConfigPtr config;
|
KSharedConfigPtr config;
|
||||||
@ -130,7 +128,7 @@ Corona::~Corona()
|
|||||||
|
|
||||||
// we call the dptr member directly for locked since isImmutable()
|
// we call the dptr member directly for locked since isImmutable()
|
||||||
// also checks kiosk and parent containers
|
// also checks kiosk and parent containers
|
||||||
cg.writeEntry("locked", d->immutable);
|
cg.writeEntry("immutability", (int)d->immutability);
|
||||||
delete d;
|
delete d;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -255,13 +253,12 @@ void Corona::loadApplets(const QString& configName)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
d->kioskImmutable = config()->isImmutable();
|
if (config()->isImmutable()) {
|
||||||
if (d->kioskImmutable) {
|
|
||||||
d->updateContainmentImmutability();
|
d->updateContainmentImmutability();
|
||||||
}
|
}
|
||||||
|
|
||||||
KConfigGroup coronaConfig(config(), "General");
|
KConfigGroup coronaConfig(config(), "General");
|
||||||
setImmutable(coronaConfig.readEntry("locked", false));
|
setImmutability((ImmutabilityType)coronaConfig.readEntry("immutability", (int)NotImmutable));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Corona::loadDefaultSetup()
|
void Corona::loadDefaultSetup()
|
||||||
@ -419,20 +416,20 @@ void Corona::syncConfig()
|
|||||||
config()->sync();
|
config()->sync();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Corona::isImmutable() const
|
ImmutabilityType Corona::immutability() const
|
||||||
{
|
{
|
||||||
return d->kioskImmutable || d->immutable;
|
return d->immutability;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Corona::setImmutable(bool immutable)
|
void Corona::setImmutability(const ImmutabilityType immutable)
|
||||||
{
|
{
|
||||||
if (d->immutable == immutable ||
|
if (d->immutability == immutable ||
|
||||||
(!immutable && d->kioskImmutable)) {
|
d->immutability == SystemImmutable) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
kDebug() << "setting immutability to" << immutable;
|
kDebug() << "setting immutability to" << immutable;
|
||||||
d->immutable = immutable;
|
d->immutability = immutable;
|
||||||
d->updateContainmentImmutability();
|
d->updateContainmentImmutability();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
10
corona.h
10
corona.h
@ -133,9 +133,15 @@ public Q_SLOTS:
|
|||||||
QList<Containment*> containments() const;
|
QList<Containment*> containments() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets if the applets are Immutable
|
* @return The type of immutability of this applet
|
||||||
*/
|
*/
|
||||||
void setImmutable(bool immutable_);
|
ImmutabilityType immutability() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the immutability type for this applet (not immutable, user immutable or system immutable)
|
||||||
|
* @arg immutable the new immutability type of this applet
|
||||||
|
*/
|
||||||
|
void setImmutability(const ImmutabilityType immutable);
|
||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
/**
|
/**
|
||||||
|
10
plasma.h
10
plasma.h
@ -135,6 +135,16 @@ enum ItemTypes { AppletType = QGraphicsItem::UserType + 1,
|
|||||||
LineEditType = QGraphicsItem::UserType + 2
|
LineEditType = QGraphicsItem::UserType + 2
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines the immutability of items like applets, corona and containments
|
||||||
|
* they can be free to modify, locked down by the user or locked down by the system (e.g. kiosk setups)
|
||||||
|
*/
|
||||||
|
enum ImmutabilityType { NotImmutable = 1 /**The item can be modified in any way **/,
|
||||||
|
UserImmutable = 2 /**The user has requested a lock down, and can undo the lock down at any time **/,
|
||||||
|
SystemImmutable = 4 /** the item is locked down by the system, the user can't unlock it **/
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The ComonentType enumeration refers to the various types of components,
|
* The ComonentType enumeration refers to the various types of components,
|
||||||
* or plugins, supported by plasma.
|
* or plugins, supported by plasma.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user