Blob Blame History Raw
From c8c6609164fc8b789171f881929da64bb34b136f Mon Sep 17 00:00:00 2001
From: Pavel Raiskup <praiskup@redhat.com>
Date: Sun, 20 Sep 2015 13:44:32 +0200
Subject: [PATCH] Implement background color request/response

---
 src/Emulation.h           |  6 ++++++
 src/Session.cpp           | 24 ++++++++++++++++++++++++
 src/Session.h             | 13 +++++++++++++
 src/SessionController.cpp | 11 +++++++++++
 src/SessionController.h   |  1 +
 src/Vt102Emulation.cpp    | 22 ++++++++++++++--------
 src/Vt102Emulation.h      |  3 ++-
 7 files changed, 71 insertions(+), 9 deletions(-)

diff --git a/src/Emulation.h b/src/Emulation.h
index 52a34b4..3cf8f76 100644
--- a/src/Emulation.h
+++ b/src/Emulation.h
@@ -414,6 +414,12 @@ signals:
      */
     void selectionChanged(const QString& text);
 
+    /**
+     * Emitted when terminal code requiring terminal's response received.
+     * (currently only background color request implemented)
+     */
+    void sessionAttrRequest(int);
+
 protected:
     virtual void setMode(int mode) = 0;
     virtual void resetMode(int mode) = 0;
diff --git a/src/Session.cpp b/src/Session.cpp
index 522f68e..1654a81 100644
--- a/src/Session.cpp
+++ b/src/Session.cpp
@@ -144,6 +144,8 @@ Session::Session(QObject* parent) :
             this, SIGNAL(selectionChanged(QString)));
     connect(_emulation, SIGNAL(imageResizeRequest(QSize)),
             this, SIGNAL(resizeRequest(QSize)));
+    connect(_emulation, SIGNAL(sessionAttrRequest(int)),
+            this, SLOT(sessionAttrRequest(int)));
 
     //create new teletype for I/O with shell process
     openTeletype(-1);
@@ -647,6 +649,17 @@ void Session::onPrimaryScreenInUse(bool use)
     emit primaryScreenInUse(use);
 }
 
+void Session::sessionAttrRequest(int id)
+{
+    switch (id) {
+        case BackgroundColor:
+            // we need to ask 'TerminalDisplay' (_view) about
+            // its background color
+            emit getBackgroundColor();
+            break;
+    }
+}
+
 void Session::activityStateSet(int state)
 {
     // TODO: should this hardcoded interval be user configurable?
@@ -750,6 +763,17 @@ void Session::sendSignal(int signal)
     }
 }
 
+void Session::reportBackgroundColor(const QColor& c)
+{
+    #define to65k(a) (QString("%1").arg((int)(a*0xFFFF), 4, 16, QChar('0')))
+    QString msg = "\033]11;rgb:"
+                + to65k(c.redF())   + "/"
+                + to65k(c.greenF()) + "/"
+                + to65k(c.blueF())  + "\a";
+    _emulation->sendString(msg.toUtf8());
+    #undef to65k
+}
+
 bool Session::kill(int signal)
 {
     if (_shellProcess->pid() <= 0)
diff --git a/src/Session.h b/src/Session.h
index 9053191..7781f37 100644
--- a/src/Session.h
+++ b/src/Session.h
@@ -369,6 +369,8 @@ public:
 
     void sendSignal(int signal);
 
+    void reportBackgroundColor(const QColor& c);
+
 public slots:
 
     /**
@@ -662,6 +664,15 @@ signals:
      */
     void selectionChanged(const QString& text);
 
+    /**
+     * Emitted when background request ('\033]11;?\a') terminal code received.
+     * Terminal is expected send '\033]11;rgb:RRRR/GGGG/BBBB\a' response.
+     *
+     * Originally implemented to support vim's background detection feature
+     * (without explictly setting 'bg=dark' within local/remote vimrc)
+     */
+    void getBackgroundColor();
+
 private slots:
     void done(int, QProcess::ExitStatus);
 
@@ -689,6 +700,8 @@ private slots:
     // signal relayer
     void onPrimaryScreenInUse(bool use);
 
+    void sessionAttrRequest(int id);
+
 private:
     // checks that the binary 'program' is available and can be executed
     // returns the binary name if available or an empty string otherwise
diff --git a/src/SessionController.cpp b/src/SessionController.cpp
index b098d4c..2bca0f9 100644
--- a/src/SessionController.cpp
+++ b/src/SessionController.cpp
@@ -186,6 +186,11 @@ SessionController::SessionController(Session* session , TerminalDisplay* view, Q
     // listen for flow control status changes
     connect(_session, SIGNAL(flowControlEnabledChanged(bool)), _view,
             SLOT(setFlowControlWarningEnabled(bool)));
+
+    // xterm '11;?' request
+    connect(_session, SIGNAL(getBackgroundColor()),
+            this, SLOT(sendBackgroundColor()));
+
     _view->setFlowControlWarningEnabled(_session->flowControlEnabled());
 
     // take a snapshot of the session state every so often when
@@ -457,6 +462,12 @@ void SessionController::sendSignal(QAction* action)
     _session->sendSignal(signal);
 }
 
+void SessionController::sendBackgroundColor()
+{
+    QColor c = _view->getBackgroundColor();
+    _session->reportBackgroundColor(c);
+}
+
 bool SessionController::eventFilter(QObject* watched , QEvent* event)
 {
     if (watched == _view) {
diff --git a/src/SessionController.h b/src/SessionController.h
index dd1f60f..d33f079 100644
--- a/src/SessionController.h
+++ b/src/SessionController.h
@@ -252,6 +252,7 @@ private slots:
     void handleWebShortcutAction();
     void configureWebShortcuts();
     void sendSignal(QAction* action);
+    void sendBackgroundColor();
 
     // other
     void prepareSwitchProfileMenu();
diff --git a/src/Vt102Emulation.cpp b/src/Vt102Emulation.cpp
index a5f19eb..389d4b9 100644
--- a/src/Vt102Emulation.cpp
+++ b/src/Vt102Emulation.cpp
@@ -318,7 +318,7 @@ void Vt102Emulation::receiveChar(int cc)
     if (lec(1,0,ESC)) { return; }
     if (lec(1,0,ESC+128)) { s[0] = ESC; receiveChar('['); return; }
     if (les(2,1,GRP)) { return; }
-    if (Xte         ) { processWindowAttributeChange(); resetTokenizer(); return; }
+    if (Xte         ) { processWinAttrRequest(); resetTokenizer(); return; }
     if (Xpe         ) { return; }
     if (lec(3,2,'?')) { return; }
     if (lec(3,2,'>')) { return; }
@@ -390,17 +390,18 @@ void Vt102Emulation::receiveChar(int cc)
     return;
   }
 }
-void Vt102Emulation::processWindowAttributeChange()
+
+void Vt102Emulation::processWinAttrRequest()
 {
   // Describes the window or terminal session attribute to change
   // See Session::UserTitleChange for possible values
-  int attributeToChange = 0;
+  int attribute = 0;
   int i;
   for (i = 2; i < tokenBufferPos     &&
               tokenBuffer[i] >= '0'  &&
               tokenBuffer[i] <= '9'; i++)
   {
-    attributeToChange = 10 * attributeToChange + (tokenBuffer[i]-'0');
+    attribute = 10 * attribute + (tokenBuffer[i]-'0');
   }
 
   if (tokenBuffer[i] != ';')
@@ -409,12 +410,17 @@ void Vt102Emulation::processWindowAttributeChange()
     return;
   }
 
-  QString newValue;
-  newValue.reserve(tokenBufferPos-i-2);
+  QString value;
+  value.reserve(tokenBufferPos-i-2);
   for (int j = 0; j < tokenBufferPos-i-2; j++)
-    newValue[j] = tokenBuffer[i+1+j];
+    value[j] = tokenBuffer[i+1+j];
 
-  _pendingTitleUpdates[attributeToChange] = newValue;
+  if (value == "?") {
+      emit sessionAttrRequest(attribute);
+      return;
+  }
+
+  _pendingTitleUpdates[attribute] = value;
   _titleUpdateTimer->start(20);
 }
 
diff --git a/src/Vt102Emulation.h b/src/Vt102Emulation.h
index 8d678e0..6c32ea1 100644
--- a/src/Vt102Emulation.h
+++ b/src/Vt102Emulation.h
@@ -148,7 +148,8 @@ private:
     void reportDecodingError();
 
     void processToken(int code, int p, int q);
-    void processWindowAttributeChange();
+    void processWinAttrRequest();
+    void requestWinAttr(int);
 
     void reportTerminalType();
     void reportSecondaryAttributes();
-- 
2.1.0