From 04b43be9b261f36edc4b0300a9784ec5dcbe1c52 Mon Sep 17 00:00:00 2001
From: Alexander Golubev <fatzer2@gmail.com>
Date: Thu, 8 Jan 2026 16:33:18 +0300
Subject: twin: better rules when to set custom_opacity flag

This patch implements next peaces of logic:
- If opacity is not completely opaque by default, changing it to opaque
  won't result it resetting the flag anymore.
- Also in such a case the X11 property will be set for completely opaque
  windows as well. That way we can restore it in case of WM restart.
- On WM initialization we check if the X11 opacity property has value we
  would expectto be left behind by previous WM instance and if it does
  we won't set the custom_opacity flag.

Signed-off-by: Alexander Golubev <fatzer2@gmail.com>
---
 twin/client.cpp      | 21 +++++++++++++++++----
 twin/client.h        |  2 ++
 twin/useractions.cpp |  9 +++++----
 3 files changed, 24 insertions(+), 8 deletions(-)

diff --git a/twin/client.cpp b/twin/client.cpp
index e9e74e139..7cdf00a77 100644
--- a/twin/client.cpp
+++ b/twin/client.cpp
@@ -2801,8 +2801,8 @@ void Client::setOpacity(bool translucent, uint opacity)
         return; // xcompmgr does not like non solid desktops and the user could set it accidently by mouse scrolling
 //     tqWarning("setting opacity for %d",tqt_xdisplay());
     //rule out activated translulcency with 100% opacity
-    if (!translucent || opacity == Opacity::Opaque)
-        {
+    if ((!translucent || opacity == Opacity::Opaque) && !custom_opacity)
+        { // Note: if it is custom_opacity we want to keep the properties in case of WM restart
         opacity_ = Opacity::Opaque;
         XDeleteProperty (tqt_xdisplay(), frameId(), atoms->net_wm_window_opacity);
         XDeleteProperty (tqt_xdisplay(), window(), atoms->net_wm_window_opacity); // ??? frameId() is necessary for visible changes, window() is the winId() that would be set by apps - we set both to be sure the app knows what's currently displayd
@@ -2827,7 +2827,12 @@ void Client::setShadowSize(uint shadowSize)
 
 uint Client::defaultOpacity()
     {
-    if (isActive() || (keepAbove() && options->keepAboveAsActive))
+    return defaultOpacity(isActive() || (keepAbove() && options->keepAboveAsActive));
+    }
+
+uint Client::defaultOpacity(bool active)
+    {
+    if (active)
         {
         if( ruleOpacityActive() )
             return rule_opacity_active;
@@ -2941,7 +2946,15 @@ bool Client::getWindowOpacity() //query translucency settings from X, returns tr
     if (result == Success && data && format == 32 )
         {
         opacity_ = *reinterpret_cast< long* >( data );
-        custom_opacity = true;
+        // Don't set custom_opacity flag during initialization if the opacity looks like what it
+        // supposed to be for the given type of window. As in a such case it is likely set by us
+        // and the WM is just restarting
+        if ( !(Workspace::self()->initializing()
+               && (   opacity_ == defaultOpacity(/*active*/ false)
+                   || opacity_ == defaultOpacity(/*active*/ true) ) ) )
+            {
+            custom_opacity = true;
+            }
 //         setOpacity(opacity_ < 0xFFFFFFFF, opacity_);
         XFree ((char*)data);
         return true;
diff --git a/twin/client.h b/twin/client.h
index 4629dfb37..6ed72fcc8 100644
--- a/twin/client.h
+++ b/twin/client.h
@@ -332,6 +332,8 @@ class Client : public TQObject, public KDecorationDefines
         void setOpacity(bool translucent, uint opacity = 0);
         void setShadowSize(uint shadowSize);
         uint defaultOpacity();
+        /// Returns default opacity for an active or inactive window depending on the argument
+        uint defaultOpacity(bool active);
         void updateOpacity();
         void updateShadowSize();
         bool hasCustomOpacity(){return custom_opacity;}
diff --git a/twin/useractions.cpp b/twin/useractions.cpp
index c573e8214..8051c9574 100644
--- a/twin/useractions.cpp
+++ b/twin/useractions.cpp
@@ -652,21 +652,22 @@ bool Client::performMouseCommand( Options::MouseCommand command, TQPoint globalP
                 {
                 if (opacity_ < Opacity::Opaque - Opacity::MouseStep)
                     {
-                    setOpacity(true, opacity_ + Opacity::MouseStep);
                     custom_opacity = true;
+                    setOpacity(true, opacity_ + Opacity::MouseStep);
                     }
                 else
                     {
-                    setOpacity(false, Opacity::Opaque);
-                    custom_opacity = false;
+                    if (defaultOpacity() == Opacity::Opaque)
+                        custom_opacity = false;
+                    setOpacity(true, Opacity::Opaque);
                     }
                 }
             break;
         case Options::MouseOpacityLess:
             if (opacity_ > 0)
                 {
-                setOpacity(true, (opacity_ > Opacity::MouseStep) ? opacity_ - Opacity::MouseStep : Opacity::Transparent);
                 custom_opacity = true;
+                setOpacity(true, (opacity_ > Opacity::MouseStep) ? opacity_ - Opacity::MouseStep : Opacity::Transparent);
                 }
             break;
         case Options::MouseNothing:
-- 
cgit v1.2.3

