Git commit 92af472f0e9dc59baf00e41279e150e5047ff0a5 by Markus Hoffmann.
Committed on 28/08/2026 at 16:54.
Pushed by akselmo into branch 'master'.

Add per-indicator settings for container tab color and terminal footer

Introduces two independent settings under Tab Bar → Appearance:

- ShowContainerTabColor (default: on): color-codes the tab with a
  per-container color when the foreground process is inside a container
  such as Distrobox or Toolbox.
- ShowContainerStatusBar (default: on): shows a label at the bottom of
  the terminal area with the container type and name.

Both settings take effect immediately when toggled; no restart needed.
User-explicitly-set tab colors are never suppressed: when the container
indicator is off its auto-assigned color is skipped rather than
invalidated, so a sibling pane's explicit color survives in a split.

Adds two unit tests to ViewManagerTest covering the suppression of
auto-container colors and the preservation of user-set colors.

Documents the container awareness feature in the handbook.

M  +78   -0    doc/manual/index.docbook
M  +64   -0    src/autotests/ViewManagerTest.cpp
M  +2    -0    src/autotests/ViewManagerTest.h
M  +56   -2    src/settings/TabBarSettings.ui
M  +10   -0    src/settings/konsole.kcfg
M  +22   -1    src/widgets/ViewContainer.cpp

https://invent.kde.org/utilities/konsole/-/commit/92af472f0e9dc59baf00e41279e150e5047ff0a5

diff --git a/doc/manual/index.docbook b/doc/manual/index.docbook
index 511dde2b2..7fc5c2f7c 100644
--- a/doc/manual/index.docbook
+++ b/doc/manual/index.docbook
@@ -520,6 +520,84 @@ Cycling between the three displayed modes can also be done 
by a keyboard shortcu
 </itemizedlist>
 </sect1>
 
+<sect1 id="container-awareness">
+<title>Container Awareness</title>
+
+<para>
+&konsole; can detect when the foreground process is running inside a Linux 
container such as
+<application>Distrobox</application>, <application>Toolbox</application>, or
+<application>Kapsule</application>, and provides visual feedback to help you 
keep track of
+which terminal is running inside which container.
+</para>
+
+<sect2 id="container-indicators">
+<title>Visual Indicators</title>
+
+<para>When a container is detected, &konsole; shows two indicators:</para>
+
+<itemizedlist>
+<listitem><para>
+<emphasis>Colored tab</emphasis> — the tab receives a unique color derived 
from the container
+identity. Each container consistently gets the same color across sessions, so 
you can tell at a
+glance which tab belongs to which container.
+</para></listitem>
+
+<listitem><para>
+<emphasis>Container label</emphasis> — a small bar appears at the bottom of 
the terminal area
+showing the container type and name (for example, <guilabel>Distrobox: 
fedora-41</guilabel>).
+The label disappears automatically when the foreground process returns to the 
host.
+</para></listitem>
+</itemizedlist>
+
+<para>
+Both indicators can be enabled or disabled independently in
+<menuchoice><guimenu>Settings</guimenu><guimenuitem>Configure 
&konsole;…</guimenuitem>
+<guimenuitem>Tab Bar / Splitters</guimenuitem></menuchoice>:
+</para>
+
+<itemizedlist>
+<listitem><para>
+<guilabel>Color-code tab when inside a container</guilabel> — toggles the 
colored tab. On by default.
+</para></listitem>
+<listitem><para>
+<guilabel>Show container label in terminal footer</guilabel> — toggles the 
footer label. On by default.
+</para></listitem>
+</itemizedlist>
+</sect2>
+
+<sect2 id="container-new-tab">
+<title>Opening a Tab Inside a Container</title>
+
+<para>
+The <guimenu>File</guimenu> menu and the <guibutton>New Tab</guibutton> button 
offer a
+submenu listing all available containers. Selecting a container opens a new 
tab that
+enters that container immediately. A <guilabel>Host</guilabel> entry is also 
provided
+to explicitly open a tab on the host system regardless of any profile default.
+</para>
+</sect2>
+
+<sect2 id="container-profile">
+<title>Profile Settings</title>
+
+<para>
+Two container-related options are available per profile in the
+<guilabel>General</guilabel> tab of <guilabel>Edit Profile</guilabel>:
+</para>
+
+<itemizedlist>
+<listitem><para>
+<guilabel>Always start in container</guilabel> — choose a specific container 
that new sessions
+using this profile will always enter automatically.
+</para></listitem>
+<listitem><para>
+<guilabel>Enter same container as current session</guilabel> — new tabs opened 
from an existing
+container session will enter the same container instead of starting on the 
host.
+</para></listitem>
+</itemizedlist>
+</sect2>
+
+</sect1>
+
 </chapter>
 
 <chapter id="commandreference">
diff --git a/src/autotests/ViewManagerTest.cpp 
b/src/autotests/ViewManagerTest.cpp
index 1ce355bc9..50205de07 100644
--- a/src/autotests/ViewManagerTest.cpp
+++ b/src/autotests/ViewManagerTest.cpp
@@ -15,6 +15,8 @@
 #include "../session/Session.h"
 #include "../session/SessionController.h"
 #include "../widgets/ViewContainer.h"
+#include "../KonsoleSettings.h"
+#include <QSignalSpy>
 #include <QStandardPaths>
 
 using namespace Konsole;
@@ -134,6 +136,68 @@ void 
ViewManagerTest::testContainerMenuLaunchKeepsPendingColor()
     QCOMPARE(session->color(), 
ContainerSessionState::colorForContainerKey(key));
 }
 
+void ViewManagerTest::testContainerTabColorSettingHidesAutoColor()
+{
+    auto mw = MainWindow();
+
+    TestContainerDetector detector;
+    ContainerInfo container;
+    container.detector = &detector;
+    container.name = QStringLiteral("fedora-41");
+    container.displayName = QStringLiteral("fedora-41");
+    container.iconName = QStringLiteral("distrobox");
+
+    const bool invoked = QMetaObject::invokeMethod(&mw, "newInContainer", 
Qt::DirectConnection, Q_ARG(Konsole::ContainerInfo, container));
+    QVERIFY(invoked);
+
+    Session *session = mw.viewManager()->activeViewController()->session();
+    auto *viewContainer = mw.viewManager()->activeContainer();
+
+    QVERIFY(!session->isTabColorSetByUser());
+    QVERIFY(session->color().isValid());
+
+    QSignalSpy colorSpy(viewContainer, &TabbedViewContainer::setColor);
+
+    // Setting ON: config refresh must emit the container color
+    KonsoleSettings::setShowContainerTabColor(true);
+    Q_EMIT KonsoleSettings::self()->configChanged();
+    QVERIFY(!colorSpy.isEmpty());
+    QVERIFY(colorSpy.last().at(1).value<QColor>().isValid());
+
+    colorSpy.clear();
+
+    // Setting OFF: config refresh must suppress the auto color
+    KonsoleSettings::setShowContainerTabColor(false);
+    Q_EMIT KonsoleSettings::self()->configChanged();
+    QVERIFY(!colorSpy.isEmpty());
+    QVERIFY(!colorSpy.last().at(1).value<QColor>().isValid());
+
+    KonsoleSettings::setShowContainerTabColor(true);
+}
+
+void ViewManagerTest::testContainerTabColorSettingPreservesUserColor()
+{
+    auto mw = MainWindow();
+    mw.viewManager()->newSession(mw.viewManager()->defaultProfile(), 
m_testDir->path());
+
+    Session *session = mw.viewManager()->activeViewController()->session();
+    auto *viewContainer = mw.viewManager()->activeContainer();
+
+    session->setColor(QColor(Qt::red));
+    session->tabColorSetByUser(true);
+
+    QSignalSpy colorSpy(viewContainer, &TabbedViewContainer::setColor);
+
+    // Setting OFF must NOT suppress a user-explicitly-set color
+    KonsoleSettings::setShowContainerTabColor(false);
+    Q_EMIT KonsoleSettings::self()->configChanged();
+    QVERIFY(!colorSpy.isEmpty());
+    QCOMPARE(colorSpy.last().at(1).value<QColor>(), QColor(Qt::red));
+
+    KonsoleSettings::setShowContainerTabColor(true);
+    session->tabColorSetByUser(false);
+}
+
 QTEST_MAIN(ViewManagerTest)
 
 #include "moc_ViewManagerTest.cpp"
diff --git a/src/autotests/ViewManagerTest.h b/src/autotests/ViewManagerTest.h
index 48879405d..febee30e8 100644
--- a/src/autotests/ViewManagerTest.h
+++ b/src/autotests/ViewManagerTest.h
@@ -21,6 +21,8 @@ private Q_SLOTS:
     void testSaveLayout();
     void testLoadLayout();
     void testContainerMenuLaunchKeepsPendingColor();
+    void testContainerTabColorSettingHidesAutoColor();
+    void testContainerTabColorSettingPreservesUserColor();
 
 private:
     QTemporaryDir *m_testDir;
diff --git a/src/settings/TabBarSettings.ui b/src/settings/TabBarSettings.ui
index 13bfaed7f..ddcb56ea1 100644
--- a/src/settings/TabBarSettings.ui
+++ b/src/settings/TabBarSettings.ui
@@ -296,13 +296,33 @@
           </widget>
          </item>
          <item row="18" column="1" colspan="2">
+          <widget class="QCheckBox" name="kcfg_ShowContainerTabColor">
+           <property name="toolTip">
+            <string>When running inside a container (e.g. Distrobox or 
Toolbox), color-code the tab with a container-specific color</string>
+           </property>
+           <property name="text">
+            <string>Color-code tab when inside a container</string>
+           </property>
+          </widget>
+         </item>
+         <item row="19" column="1" colspan="2">
+          <widget class="QCheckBox" name="kcfg_ShowContainerStatusBar">
+           <property name="toolTip">
+            <string>When running inside a container (e.g. Distrobox or 
Toolbox), show a label with the container name at the bottom of the 
terminal</string>
+           </property>
+           <property name="text">
+            <string>Show container label in terminal footer</string>
+           </property>
+          </widget>
+         </item>
+         <item row="20" column="1" colspan="2">
           <widget class="QCheckBox" name="kcfg_TabBarUseUserStyleSheet">
            <property name="text">
             <string>Use user-defined stylesheet:</string>
            </property>
           </widget>
          </item>
-         <item row="19" column="1">
+         <item row="21" column="1">
           <spacer>
            <property name="orientation">
             <enum>Qt::Orientation::Horizontal</enum>
@@ -318,7 +338,7 @@
            </property>
           </spacer>
          </item>
-         <item row="19" column="2">
+         <item row="21" column="2">
           <widget class="KUrlRequester" name="kcfg_TabBarUserStyleSheetFile">
            <property name="enabled">
             <bool>false</bool>
@@ -579,6 +599,8 @@
   <tabstop>HideSearchTabsButton</tabstop>
   <tabstop>kcfg_NewTabButton</tabstop>
   <tabstop>kcfg_ExpandTabWidth</tabstop>
+  <tabstop>kcfg_ShowContainerTabColor</tabstop>
+  <tabstop>kcfg_ShowContainerStatusBar</tabstop>
   <tabstop>kcfg_TabBarUseUserStyleSheet</tabstop>
   <tabstop>kcfg_TabBarUserStyleSheetFile</tabstop>
   <tabstop>kcfg_CloseTabOnMiddleMouseButton</tabstop>
@@ -609,6 +631,38 @@
     </hint>
    </hints>
   </connection>
+  <connection>
+   <sender>AlwaysHideTabBar</sender>
+   <signal>toggled(bool)</signal>
+   <receiver>kcfg_ShowContainerTabColor</receiver>
+   <slot>setDisabled(bool)</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>20</x>
+     <y>20</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>20</x>
+     <y>20</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>AlwaysHideTabBar</sender>
+   <signal>toggled(bool)</signal>
+   <receiver>kcfg_ShowContainerStatusBar</receiver>
+   <slot>setDisabled(bool)</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>20</x>
+     <y>20</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>20</x>
+     <y>20</y>
+    </hint>
+   </hints>
+  </connection>
   <connection>
    <sender>AlwaysHideTabBar</sender>
    <signal>toggled(bool)</signal>
diff --git a/src/settings/konsole.kcfg b/src/settings/konsole.kcfg
index adcb67a29..8ddc29b10 100644
--- a/src/settings/konsole.kcfg
+++ b/src/settings/konsole.kcfg
@@ -204,6 +204,16 @@
       <label>Expand the tab widths</label>
       <default>false</default>
     </entry>
+    <entry name="ShowContainerTabColor" type="Bool">
+      <label>Color-code tab when running inside a container</label>
+      <tooltip>When running inside a container (e.g. Distrobox or Toolbox), 
color-code the tab with a container-specific color</tooltip>
+      <default>true</default>
+    </entry>
+    <entry name="ShowContainerStatusBar" type="Bool">
+      <label>Show container label in terminal footer</label>
+      <tooltip>When running inside a container (e.g. Distrobox or Toolbox), 
show a label with the container name at the bottom of the terminal</tooltip>
+      <default>true</default>
+    </entry>
   </group>
   <group name="PrintOptions">
     <entry name="PrinterFriendly" type="Bool">
diff --git a/src/widgets/ViewContainer.cpp b/src/widgets/ViewContainer.cpp
index 86ef4e4ef..d9884ccba 100644
--- a/src/widgets/ViewContainer.cpp
+++ b/src/widgets/ViewContainer.cpp
@@ -300,6 +300,13 @@ void TabbedViewContainer::konsoleConfigChanged()
     tabBar()->setExpanding(KonsoleSettings::expandTabWidth());
     tabBar()->update();
 
+    for (int i = 0; i < count(); ++i) {
+        if (auto *splitter = viewSplitterAt(i)) {
+            Q_EMIT setColor(i, effectiveTabColor(splitter));
+        }
+    }
+    updateActiveContainerBadge();
+
     if (KonsoleSettings::tabBarUseUserStyleSheet()) {
         setCssFromFile(KonsoleSettings::tabBarUserStyleSheetFile());
         _stylesheetSet = true;
@@ -688,10 +695,17 @@ QColor 
TabbedViewContainer::effectiveTabColor(ViewSplitter *splitter) const
     bool hasChosen = false;
     bool mixed = false;
 
+    const bool indicatorEnabled = KonsoleSettings::showContainerTabColor();
     for (TerminalDisplay *display : displays) {
         auto *controller = display != nullptr ? display->sessionController() : 
nullptr;
         auto session = controller != nullptr ? controller->session() : 
QPointer<Session>{};
-        const QColor color = session != nullptr ? session->color() : QColor();
+        QColor color = session != nullptr ? session->color() : QColor();
+
+        // When the container tab-color indicator is disabled, skip 
auto-assigned
+        // container colors so a sibling pane's user-set color is preserved.
+        if (color.isValid() && session != nullptr && 
!session->isTabColorSetByUser() && !indicatorEnabled) {
+            continue;
+        }
 
         if (!hasChosen) {
             chosen = color;
@@ -944,6 +958,13 @@ void 
TabbedViewContainer::updateContainerBadgeForDisplay(TerminalDisplay *displa
         return;
     }
 
+    if (!KonsoleSettings::showContainerStatusBar()) {
+        if (_containerBadgeWidgets.contains(display)) {
+            _containerBadgeWidgets.value(display)->setVisible(false);
+        }
+        return;
+    }
+
     ensureContainerBadge(display);
 
     auto *badgeWidget = _containerBadgeWidgets.value(display, nullptr);

Reply via email to