plugins/dialogparent: Disable darkening while picking colors

Integrate with colorpicker effect to disable window darkening while
color picker effect is active. Unfortunately, this solution has couple
of limitations:
- active state of effects is not an observable property, so a new
  property had to be added to the effects singleton;
- consequently, list of active effects is not an observable property, so
  the whole thing could not be implemented in pure QML in the dialog
  parent effects;
- actual isActive() state of the color picker for whatever reason
  required that m_scheduledPosition is not an invalid point,
  effectively making it always inactive except for a brief moment
  between addRepaintFull() call and paintScreen() callback. That check
  had to be removed.
- QColorDialog windows are still modal and darkened by default;
- QColorDialog on X11 does not use portals/KWin, so this trick does not
  apply at all;
- effects->isScreenLocked() which isActive() depends on is not an
  observable property either.

BUG: 172921
This commit is contained in:
ivan tkachenko 2024-04-11 02:17:37 +06:00
parent 99324c12fd
commit 344e56dd77
No known key found for this signature in database
GPG key ID: AF72731B7C654CB3
5 changed files with 54 additions and 29 deletions

View file

@ -432,6 +432,11 @@ bool EffectsHandler::hasActiveFullScreenEffect() const
return fullscreen_effect;
}
bool EffectsHandler::isColorPickerActive() const
{
return isEffectActive(QStringLiteral("colorpicker"));
}
bool EffectsHandler::grabKeyboard(Effect *effect)
{
if (keyboard_grab_effect != nullptr) {

View file

@ -146,6 +146,7 @@ class KWIN_EXPORT EffectsHandler : public QObject
Q_PROPERTY(QSize virtualScreenSize READ virtualScreenSize NOTIFY virtualScreenSizeChanged)
Q_PROPERTY(QRect virtualScreenGeometry READ virtualScreenGeometry NOTIFY virtualScreenGeometryChanged)
Q_PROPERTY(bool hasActiveFullScreenEffect READ hasActiveFullScreenEffect NOTIFY hasActiveFullScreenEffectChanged)
Q_PROPERTY(bool colorPickerActive READ isColorPickerActive NOTIFY colorPickerActiveChanged)
/**
* The status of the session i.e if the user is logging out
@ -699,10 +700,15 @@ public:
KSharedConfigPtr inputConfig() const;
/**
* Returns if activeFullScreenEffect is set
* Returns true if activeFullScreenEffect is set
*/
bool hasActiveFullScreenEffect() const;
/**
* Returns true if color picker effect is currently picking colors.
*/
bool isColorPickerActive() const;
/**
* Render the supplied OffscreenQuickView onto the scene
* It can be called at any point during the scene rendering
@ -1032,6 +1038,8 @@ Q_SIGNALS:
*/
void hasActiveFullScreenEffectChanged();
void colorPickerActiveChanged();
/**
* This signal is emitted when the session state was changed
* @since 5.18

View file

@ -51,7 +51,10 @@ ColorPickerEffect::ColorPickerEffect()
QDBusConnection::sessionBus().registerObject(QStringLiteral("/ColorPicker"), this, QDBusConnection::ExportScriptableContents);
}
ColorPickerEffect::~ColorPickerEffect() = default;
ColorPickerEffect::~ColorPickerEffect()
{
setPicking(false);
}
void ColorPickerEffect::paintScreen(const RenderTarget &renderTarget, const RenderViewport &viewport, int mask, const QRegion &region, Output *screen)
{
@ -67,7 +70,7 @@ void ColorPickerEffect::paintScreen(const RenderTarget &renderTarget, const Rend
glReadPixels(texturePosition.x(), renderTarget.size().height() - texturePosition.y() - PIXEL_SIZE, PIXEL_SIZE, PIXEL_SIZE, GL_RGBA, GL_FLOAT, data.data());
QVector3D sRGB = 255 * renderTarget.colorDescription().mapTo(QVector3D(data[0], data[1], data[2]), sRGBencoding);
QDBusConnection::sessionBus().send(m_replyMessage.createReply(QColor(sRGB.x(), sRGB.y(), sRGB.z())));
m_picking = false;
setPicking(false);
m_scheduledPosition = QPoint(-1, -1);
}
}
@ -81,7 +84,7 @@ QColor ColorPickerEffect::pick()
sendErrorReply(QDBusError::Failed, "Color picking is already in progress");
return QColor();
}
m_picking = true;
setPicking(true);
m_replyMessage = message();
setDelayedReply(true);
showInfoMessage();
@ -91,7 +94,7 @@ QColor ColorPickerEffect::pick()
if (p == QPointF(-1, -1)) {
// error condition
QDBusConnection::sessionBus().send(m_replyMessage.createErrorReply(QStringLiteral("org.kde.kwin.ColorPicker.Error.Cancelled"), "Color picking got cancelled"));
m_picking = false;
setPicking(false);
} else {
m_scheduledPosition = p;
effects->addRepaintFull();
@ -110,9 +113,17 @@ void ColorPickerEffect::hideInfoMessage()
effects->hideOnScreenMessage();
}
void ColorPickerEffect::setPicking(bool picking)
{
if (m_picking != picking) {
m_picking = picking;
Q_EMIT effects->colorPickerActiveChanged();
}
}
bool ColorPickerEffect::isActive() const
{
return m_picking && ((m_scheduledPosition != QPoint(-1, -1))) && !effects->isScreenLocked();
return m_picking && !effects->isScreenLocked();
}
} // namespace

View file

@ -41,6 +41,7 @@ public Q_SLOTS:
private:
void showInfoMessage();
void hideInfoMessage();
void setPicking(bool picking);
QDBusMessage m_replyMessage;
QPointF m_scheduledPosition;

View file

@ -20,7 +20,7 @@ var dialogParentEffect = {
dialogParentEffect.restartAnimation(window);
}
});
window.windowModalityChanged.connect(dialogParentEffect.modalDialogChanged);
window.windowModalityChanged.connect(dialogParentEffect.windowModalityChanged);
window.windowDesktopsChanged.connect(dialogParentEffect.cancelAnimationInstant);
window.windowDesktopsChanged.connect(dialogParentEffect.restartAnimation);
@ -97,23 +97,19 @@ var dialogParentEffect = {
// effect has to come after the full screen effect in the effect chain,
// otherwise this slot will be invoked before the full screen effect can mark
// itself as a full screen effect.
if (effects.hasActiveFullScreenEffect) {
if (dialogParentEffect.globallyInhibited()) {
return;
}
var windows = effects.stackingOrder;
for (var i = 0; i < windows.length; ++i) {
var window = windows[i];
const windows = effects.stackingOrder;
for (const window of windows) {
dialogParentEffect.cancelAnimationInstant(window);
dialogParentEffect.restartAnimation(window);
}
},
modalDialogChanged: function(dialog) {
windowModalityChanged: function (window) {
"use strict";
if (dialog.modal === false)
dialogParentEffect.dialogLostModality(dialog);
else if (dialog.modal === true)
dialogParentEffect.dialogGotModality(dialog);
dialogParentEffect.refreshWindowEffect(window);
},
restartAnimation: function (window) {
"use strict";
@ -125,19 +121,21 @@ var dialogParentEffect = {
complete(window.dialogParentAnimation);
}
},
activeFullScreenEffectChanged: function () {
activeFullScreenOrColorPickerChanged: function () {
"use strict";
var windows = effects.stackingOrder;
for (var i = 0; i < windows.length; ++i) {
var dialog = windows[i];
if (!dialog.modal) {
continue;
}
if (effects.hasActiveFullScreenEffect) {
dialogParentEffect.dialogLostModality(dialog);
} else {
dialogParentEffect.dialogGotModality(dialog);
}
const windows = effects.stackingOrder;
for (const window of windows) {
dialogParentEffect.refreshWindowEffect(window);
}
},
globallyInhibited: function () {
return effects.hasActiveFullScreenEffect || effects.colorPickerActive;
},
refreshWindowEffect: function (window) {
if (dialogParentEffect.globallyInhibited() || !window.modal) {
dialogParentEffect.dialogLostModality(window);
} else {
dialogParentEffect.dialogGotModality(window);
}
},
init: function () {
@ -147,7 +145,9 @@ var dialogParentEffect = {
effects.windowClosed.connect(dialogParentEffect.windowClosed);
effects.desktopChanged.connect(dialogParentEffect.desktopChanged);
effects.activeFullScreenEffectChanged.connect(
dialogParentEffect.activeFullScreenEffectChanged);
dialogParentEffect.activeFullScreenOrColorPickerChanged);
effects.colorPickerActiveChanged.connect(
dialogParentEffect.activeFullScreenOrColorPickerChanged);
windows = effects.stackingOrder;
for (i = 0; i < windows.length; i += 1) {