File indexing completed on 2024-04-21 09:42:21

0001 /*
0002     SPDX-FileCopyrightText: 2007-2008 Robert Knight <robertknight@gmail.com>
0003     SPDX-FileCopyrightText: 1997, 1998 Lars Doelle <lars.doelle@on-line.de>
0004 
0005     SPDX-License-Identifier: GPL-2.0-or-later
0006 */
0007 
0008 #ifndef EMULATION_H
0009 #define EMULATION_H
0010 
0011 // Qt
0012 #include <QSize>
0013 #include <QTextCodec>
0014 #include <QTimer>
0015 
0016 // Konsole
0017 #include "Enumeration.h"
0018 #include "konsoleprivate_export.h"
0019 #include "terminalDisplay/TerminalDisplay.h"
0020 
0021 #include <memory>
0022 
0023 class QKeyEvent;
0024 
0025 namespace Konsole
0026 {
0027 class KeyboardTranslator;
0028 class HistoryType;
0029 class Screen;
0030 class ScreenWindow;
0031 class TerminalCharacterDecoder;
0032 
0033 /**
0034  * Base class for terminal emulation back-ends.
0035  *
0036  * The back-end is responsible for decoding an incoming character stream and
0037  * producing an output image of characters.
0038  *
0039  * When input from the terminal is received, the receiveData() slot should be called with
0040  * the data which has arrived.  The emulation will process the data and update the
0041  * screen image accordingly.  The codec used to decode the incoming character stream
0042  * into the unicode characters used internally can be specified using setCodec()
0043  *
0044  * The size of the screen image can be specified by calling setImageSize() with the
0045  * desired number of lines and columns.  When new lines are added, old content
0046  * is moved into a history store, which can be set by calling setHistory().
0047  *
0048  * The screen image can be accessed by creating a ScreenWindow onto this emulation
0049  * by calling createWindow().  Screen windows provide access to a section of the
0050  * output.  Each screen window covers the same number of lines and columns as the
0051  * image size returned by imageSize().  The screen window can be moved up and down
0052  * and provides transparent access to both the current on-screen image and the
0053  * previous output.  The screen windows emit an outputChanged signal
0054  * when the section of the image they are looking at changes.
0055  * Graphical views can then render the contents of a screen window, listening for notifications
0056  * of output changes from the screen window which they are associated with and updating
0057  * accordingly.
0058  *
0059  * The emulation also is also responsible for converting input from the connected views such
0060  * as keypresses and mouse activity into a character string which can be sent
0061  * to the terminal program.  Key presses can be processed by calling the sendKeyEvent() slot,
0062  * while mouse events can be processed using the sendMouseEvent() slot.  When the character
0063  * stream has been produced, the emulation will emit a sendData() signal with a pointer
0064  * to the character buffer.  This data should be fed to the standard input of the terminal
0065  * process.  The translation of key presses into an output character stream is performed
0066  * using a lookup in a set of key bindings which map key sequences to output
0067  * character sequences.  The name of the key bindings set used can be specified using
0068  * setKeyBindings()
0069  *
0070  * The emulation maintains certain state information which changes depending on the
0071  * input received.  The emulation can be reset back to its starting state by calling
0072  * reset().
0073  *
0074  * The emulation also maintains an activity state, which specifies whether
0075  * terminal is currently active ( when data is received ), normal
0076  * ( when the terminal is idle or receiving user input ) or trying
0077  * to alert the user ( also known as a "Bell" event ).  The stateSet() signal
0078  * is emitted whenever the activity state is set.  This can be used to determine
0079  * how long the emulation has been active/idle for and also respond to
0080  * a 'bell' event in different ways.
0081  */
0082 class KONSOLEPRIVATE_EXPORT Emulation : public QObject
0083 {
0084     Q_OBJECT
0085 
0086 public:
0087     /** Constructs a new terminal emulation */
0088     Emulation();
0089     ~Emulation() override;
0090 
0091     /**
0092      * Creates a new window onto the output from this emulation.  The contents
0093      * of the window are then rendered by views which are set to use this window using the
0094      * TerminalDisplay::setScreenWindow() method.
0095      */
0096     ScreenWindow *createWindow();
0097 
0098     /**
0099      * Associates a TerminalDisplay with this emulation.
0100      */
0101     void setCurrentTerminalDisplay(TerminalDisplay *display);
0102 
0103     /** Returns the size of the screen image which the emulation produces */
0104     QSize imageSize() const;
0105 
0106     /**
0107      * Returns the total number of lines, including those stored in the history.
0108      */
0109     int lineCount() const;
0110 
0111     /**
0112      * Sets the history store used by this emulation.  When new lines
0113      * are added to the output, older lines at the top of the screen are transferred to a history
0114      * store.
0115      *
0116      * The number of lines which are kept and the storage location depend on the
0117      * type of store.
0118      */
0119     void setHistory(const HistoryType &);
0120     /** Returns the history store used by this emulation.  See setHistory() */
0121     const HistoryType &history() const;
0122     /** Clears the history scroll. */
0123     virtual void clearHistory();
0124 
0125     /**
0126      * Copies the output history from @p startLine to @p endLine
0127      * into @p stream, using @p decoder to convert the terminal
0128      * characters into text.
0129      *
0130      * @param decoder A decoder which converts lines of terminal characters with
0131      * appearance attributes into output text.  PlainTextDecoder is the most commonly
0132      * used decoder.
0133      * @param startLine Index of first line to copy
0134      * @param endLine Index of last line to copy
0135      */
0136     virtual void writeToStream(TerminalCharacterDecoder *decoder, int startLine, int endLine);
0137 
0138     /** Returns the codec used to decode incoming characters.  See setCodec() */
0139     const QTextCodec *codec() const
0140     {
0141         return _codec;
0142     }
0143 
0144     /** Sets the codec used to decode incoming characters.  */
0145     void setCodec(const QTextCodec *);
0146 
0147     /**
0148      * Convenience method.
0149      * Returns true if the current codec used to decode incoming
0150      * characters is UTF-8
0151      */
0152     bool utf8() const
0153     {
0154         Q_ASSERT(_codec);
0155         return _codec->mibEnum() == 106;
0156     }
0157 
0158     /** Returns the special character used for erasing character. */
0159     virtual char eraseChar() const;
0160 
0161     /**
0162      * Sets the key bindings used to key events
0163      * ( received through sendKeyEvent() ) into character
0164      * streams to send to the terminal.
0165      */
0166     void setKeyBindings(const QString &name);
0167     /**
0168      * Returns the name of the emulation's current key bindings.
0169      * See setKeyBindings()
0170      */
0171     QString keyBindings() const;
0172 
0173     /**
0174      * Copies the current image into the history and clears the screen.
0175      */
0176     virtual void clearEntireScreen() = 0;
0177 
0178     /** Resets the state of the terminal.
0179      *
0180      * @param softReset The reset was initiated by DECSTR
0181      * @param preservePrompt Try to preserve the command prompt */
0182     virtual void reset(bool softReset = false, bool preservePrompt = false) = 0;
0183 
0184     /**
0185      * Returns true if the active terminal program is interested in Mouse
0186      * Tracking events.
0187      *
0188      * The programRequestsMouseTracking() signal is emitted when a program
0189      * indicates it's interested in Mouse Tracking events.
0190      *
0191      * See MODE_Mouse100{0,1,2,3} in Vt102Emulation.
0192      */
0193     bool programUsesMouseTracking() const;
0194 
0195     bool programBracketedPasteMode() const;
0196 
0197 public Q_SLOTS:
0198 
0199     /** Change the size of the emulation's image */
0200     virtual void setImageSize(int lines, int columns);
0201 
0202     /**
0203      * Interprets a sequence of characters and sends the result to the terminal.
0204      * This is equivalent to calling sendKeyEvent() for each character in @p text in succession.
0205      */
0206     virtual void sendText(const QString &text) = 0;
0207 
0208     /**
0209      * Interprets a key press event and emits the sendData() signal with
0210      * the resulting character stream.
0211      */
0212     virtual void sendKeyEvent(QKeyEvent *);
0213 
0214     /**
0215      * Converts information about a mouse event into an xterm-compatible escape
0216      * sequence and emits the character sequence via sendData()
0217      */
0218     virtual void sendMouseEvent(int buttons, int column, int line, int eventType) = 0;
0219 
0220     /**
0221      * Sends a string of characters to the foreground terminal process.
0222      *
0223      * @param string The characters to send.
0224      */
0225     virtual void sendString(const QByteArray &string) = 0;
0226 
0227     /**
0228      * Processes an incoming stream of characters.  receiveData() decodes the incoming
0229      * character buffer using the current codec(), and then calls receiveChar() for
0230      * each unicode character in the resulting buffer.
0231      *
0232      * receiveData() also starts a timer which causes the outputChanged() signal
0233      * to be emitted when it expires.  The timer allows multiple updates in quick
0234      * succession to be buffered into a single outputChanged() signal emission.
0235      *
0236      * @param text A string of characters received from the terminal program.
0237      * @param length The length of @p text
0238      */
0239     void receiveData(const char *text, int length);
0240 
0241     /**
0242      * Sends information about the focus event to the terminal.
0243      */
0244     virtual void focusChanged(bool focused) = 0;
0245 
0246     void setPeekPrimary(const bool doPeek);
0247 
0248 Q_SIGNALS:
0249 
0250     /**
0251      * Emitted when a buffer of data is ready to send to the
0252      * standard input of the terminal.
0253      *
0254      * @param data The buffer of data ready to be sent
0255      */
0256     void sendData(const QByteArray &data);
0257 
0258     /**
0259      * Requests that the pty used by the terminal process
0260      * be set to UTF 8 mode.
0261      *
0262      * Refer to the IUTF8 entry in termios(3) for more information.
0263      */
0264     void useUtf8Request(bool);
0265 
0266     /**
0267      * Emitted when bell appeared
0268      */
0269     void bell();
0270 
0271     /**
0272      * Emitted when the special sequence indicating the request for data
0273      * transmission through ZModem protocol is detected.
0274      */
0275     void zmodemDownloadDetected();
0276     void zmodemUploadDetected();
0277 
0278     /**
0279      * This is emitted when the program (typically editors and other full-screen
0280      * applications, ones that take up the whole terminal display), running in
0281      * the terminal indicates whether or not it is interested in Mouse Tracking
0282      * events. This is an XTerm extension, for more information have a look at:
0283      * https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Mouse-Tracking
0284      *
0285      * @param usesMouseTracking This will be true if the program is interested
0286      * in Mouse Tracking events or false otherwise.
0287      */
0288     void programRequestsMouseTracking(bool usesMouseTracking);
0289 
0290     void enableAlternateScrolling(bool enable);
0291 
0292     void programBracketedPasteModeChanged(bool bracketedPasteMode);
0293 
0294     /**
0295      * Emitted when the contents of the screen image change.
0296      * The emulation buffers the updates from successive image changes,
0297      * and only emits outputChanged() at sensible intervals when
0298      * there is a lot of terminal activity.
0299      *
0300      * Normally there is no need for objects other than the screen windows
0301      * created with createWindow() to listen for this signal.
0302      *
0303      * ScreenWindow objects created using createWindow() will emit their
0304      * own outputChanged() signal in response to this signal.
0305      */
0306     void outputChanged();
0307 
0308     /**
0309      * Emitted when the program running in the terminal wishes to update
0310      * certain session attributes. This allows terminal programs to customize
0311      * certain aspects of the terminal emulation display.
0312      *
0313      * This signal is emitted when the escape sequence "\033]ARG;VALUE\007"
0314      * is received in an input string, where ARG is a number specifying
0315      * what should be changed and VALUE is a string specifying the new value.
0316      *
0317      * @param attribute Specifies which session attribute to change:
0318      * <ul>
0319      * <li> 0  - Set window icon text and session title to @p newValue</li>
0320      * <li> 1  - Set window icon text to @p newValue</li>
0321      * <li> 2  - Set session title to @p newValue</li>
0322      * <li> 11 - Set the session's default background color to @p newValue,
0323      *      where @p newValue can be an HTML-style string ("#RRGGBB") or a
0324      *      named color (e.g. 'red', 'blue'). For more details see:
0325      *      https://doc.qt.io/qt-5/qcolor.html#setNamedColor
0326      * </li>
0327      * <li> 31 - Supposedly treats @p newValue as a URL and opens it (NOT
0328      *      IMPLEMENTED)
0329      * </li>
0330      * <li> 32 - Sets the icon associated with the session. @p newValue
0331      *      is the name of the icon to use, which can be the name of any
0332      *      icon in the current KDE icon theme (eg: 'konsole', 'kate',
0333      *      'folder_home')
0334      * </li>
0335      * </ul>
0336      * @param newValue Specifies the new value of the session attribute
0337      */
0338     void sessionAttributeChanged(int attribute, const QString &newValue);
0339 
0340     /**
0341      * Emitted when the terminal emulator's size has changed
0342      */
0343     void imageSizeChanged(int lineCount, int columnCount);
0344 
0345     /**
0346      * Emitted when the setImageSize() is called on this emulation for
0347      * the first time.
0348      */
0349     void imageSizeInitialized();
0350 
0351     /**
0352      * Emitted after receiving the escape sequence which asks to change
0353      * the terminal emulator's size
0354      */
0355     void imageResizeRequest(const QSize &sizz);
0356 
0357     /**
0358      * Emitted when the terminal program requests to change various properties
0359      * of the terminal display.
0360      *
0361      * A profile change command occurs when a special escape sequence, followed
0362      * by a string containing a series of name and value pairs is received.
0363      * This string can be parsed using a ProfileCommandParser instance.
0364      *
0365      * @param text A string expected to contain a series of key and value pairs in
0366      * the form:  name=value;name2=value2 ...
0367      */
0368     void profileChangeCommandReceived(const QString &text);
0369 
0370     /**
0371      * Emitted when a flow control key combination ( Ctrl+S or Ctrl+Q ) is pressed.
0372      * @param suspendKeyPressed True if Ctrl+S was pressed to suspend output or Ctrl+Q to
0373      * resume output.
0374      */
0375     void flowControlKeyPressed(bool suspendKeyPressed);
0376 
0377     /**
0378      * Emitted when the active screen is switched, to indicate whether the primary
0379      * screen is in use.
0380      */
0381     void primaryScreenInUse(bool use);
0382 
0383     /**
0384      * Emitted when the text selection is changed
0385      */
0386     void selectionChanged(const bool selectionEmpty);
0387 
0388     /**
0389      * Emitted when terminal code requiring terminal's response received.
0390      */
0391     void sessionAttributeRequest(int id, uint terminator);
0392 
0393     /**
0394      * Emitted when Set Cursor Style (DECSCUSR) escape sequences are sent
0395      * to the terminal.
0396      * @p shape cursor shape
0397      * @p isBlinking if true, the cursor will be set to blink
0398      * @p customColor custom cursor color
0399      */
0400     void setCursorStyleRequest(Enum::CursorShapeEnum shape = Enum::BlockCursor, bool isBlinking = false, const QColor &customColor = {});
0401 
0402     /**
0403      * Emitted when reset() is called to reset the cursor style to the
0404      * current profile cursor shape and blinking settings.
0405      */
0406     void resetCursorStyleRequest();
0407 
0408     void toggleUrlExtractionRequest();
0409 
0410 protected:
0411     virtual void setMode(int mode) = 0;
0412     virtual void resetMode(int mode) = 0;
0413 
0414     /**
0415      * Processes an incoming character.  See receiveData()
0416      * @p c A unicode character code.
0417      */
0418     virtual void receiveChars(const QVector<uint> &c);
0419 
0420     /**
0421      * Sets the active screen.  The terminal has two screens, primary and alternate.
0422      * The primary screen is used by default.  When certain interactive programs such
0423      * as Vim are run, they trigger a switch to the alternate screen.
0424      *
0425      * @param index 0 to switch to the primary screen, or 1 to switch to the alternate screen
0426      */
0427     void setScreen(int index);
0428 
0429     enum EmulationCodec {
0430         LocaleCodec = 0,
0431         Utf8Codec = 1,
0432     };
0433 
0434     void setCodec(EmulationCodec codec);
0435 
0436     QList<ScreenWindow *> _windows;
0437 
0438     Screen *_currentScreen = nullptr; // pointer to the screen which is currently active,
0439     // this is one of the elements in the screen[] array
0440 
0441     Screen *_screen[2]; // 0 = primary screen ( used by most programs, including the shell
0442     //                      scrollbars are enabled in this mode )
0443     // 1 = alternate      ( used by vi , emacs etc.
0444     //                      scrollbars are not enabled in this mode )
0445 
0446     // decodes an incoming C-style character stream into a unicode QString using
0447     // the current text codec.  (this allows for rendering of non-ASCII characters in text files etc.)
0448     const QTextCodec *_codec = nullptr;
0449     std::unique_ptr<QTextDecoder> _decoder;
0450     const KeyboardTranslator *_keyTranslator = nullptr; // the keyboard layout
0451 
0452 protected Q_SLOTS:
0453     /**
0454      * Schedules an update of attached views.
0455      * Repeated calls to bufferedUpdate() in close succession will result in only a single update,
0456      * much like the Qt buffered update of widgets.
0457      */
0458     void bufferedUpdate();
0459 
0460     // used to emit the primaryScreenInUse(bool) signal
0461     void checkScreenInUse();
0462 
0463     // used to emit the selectionChanged(QString) signal
0464     void checkSelectedText();
0465 
0466 private Q_SLOTS:
0467     // triggered by timer, causes the emulation to send an updated screen image to each
0468     // view
0469     void showBulk();
0470 
0471     void setUsesMouseTracking(bool usesMouseTracking);
0472 
0473     void bracketedPasteModeChanged(bool bracketedPasteMode);
0474 
0475 private:
0476     void setScreenInternal(int index);
0477     Q_DISABLE_COPY(Emulation)
0478 
0479     bool _usesMouseTracking = false;
0480     bool _bracketedPasteMode = false;
0481     QTimer _bulkTimer1{this};
0482     QTimer _bulkTimer2{this};
0483     bool _imageSizeInitialized = false;
0484     bool _peekingPrimary = false;
0485     int _activeScreenIndex = 0;
0486 };
0487 }
0488 
0489 #endif // ifndef EMULATION_H