File indexing completed on 2024-05-19 05:28:15

0001 /*
0002     This file is part of Konsole, an X terminal.
0003 
0004     SPDX-FileCopyrightText: 2007-2008 Robert Knight <robertknight@gmail.com>
0005     SPDX-FileCopyrightText: 1997, 1998 Lars Doelle <lars.doelle@on-line.de>
0006 
0007     SPDX-License-Identifier: GPL-2.0-or-later
0008 
0009     This program is distributed in the hope that it will be useful,
0010     but WITHOUT ANY WARRANTY; without even the implied warranty of
0011     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0012     GNU General Public License for more details.
0013 
0014     You should have received a copy of the GNU General Public License
0015     along with this program; if not, write to the Free Software
0016     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
0017     02110-1301  USA.
0018 */
0019 
0020 #ifndef EMULATION_H
0021 #define EMULATION_H
0022 
0023 // System
0024 #include <cstdio>
0025 
0026 // Qt
0027 #include <QKeyEvent>
0028 // #include <QPointer>
0029 #include <QTextCodec>
0030 #include <QTextStream>
0031 #include <QTimer>
0032 
0033 // std
0034 #include <memory>
0035 
0036 #include "KeyboardTranslator.h"
0037 
0038 namespace Konsole
0039 {
0040 
0041 class HistoryType;
0042 class Screen;
0043 class ScreenWindow;
0044 class TerminalCharacterDecoder;
0045 
0046 /**
0047  * This enum describes the available states which
0048  * the terminal emulation may be set to.
0049  *
0050  * These are the values used by Emulation::stateChanged()
0051  */
0052 enum {
0053     /** The emulation is currently receiving user input. */
0054     NOTIFYNORMAL = 0,
0055     /**
0056      * The terminal program has triggered a bell event
0057      * to get the user's attention.
0058      */
0059     NOTIFYBELL = 1,
0060     /**
0061      * The emulation is currently receiving data from its
0062      * terminal input.
0063      */
0064     NOTIFYACTIVITY = 2,
0065 
0066     // unused here?
0067     NOTIFYSILENCE = 3
0068 };
0069 
0070 /**
0071  * Base class for terminal emulation back-ends.
0072  *
0073  * The back-end is responsible for decoding an incoming character stream and
0074  * producing an output image of characters.
0075  *
0076  * When input from the terminal is received, the receiveData() slot should be called with
0077  * the data which has arrived.  The emulation will process the data and update the
0078  * screen image accordingly.  The codec used to decode the incoming character stream
0079  * into the unicode characters used internally can be specified using setCodec()
0080  *
0081  * The size of the screen image can be specified by calling setImageSize() with the
0082  * desired number of lines and columns.  When new lines are added, old content
0083  * is moved into a history store, which can be set by calling setHistory().
0084  *
0085  * The screen image can be accessed by creating a ScreenWindow onto this emulation
0086  * by calling createWindow().  Screen windows provide access to a section of the
0087  * output.  Each screen window covers the same number of lines and columns as the
0088  * image size returned by imageSize().  The screen window can be moved up and down
0089  * and provides transparent access to both the current on-screen image and the
0090  * previous output.  The screen windows Q_EMIT an outputChanged signal
0091  * when the section of the image they are looking at changes.
0092  * Graphical views can then render the contents of a screen window, listening for notifications
0093  * of output changes from the screen window which they are associated with and updating
0094  * accordingly.
0095  *
0096  * The emulation also is also responsible for converting input from the connected views such
0097  * as keypresses and mouse activity into a character string which can be sent
0098  * to the terminal program.  Key presses can be processed by calling the sendKeyEvent() slot,
0099  * while mouse events can be processed using the sendMouseEvent() slot.  When the character
0100  * stream has been produced, the emulation will Q_EMIT a sendData() signal with a pointer
0101  * to the character buffer.  This data should be fed to the standard input of the terminal
0102  * process.  The translation of key presses into an output character stream is performed
0103  * using a lookup in a set of key bindings which map key sequences to output
0104  * character sequences.  The name of the key bindings set used can be specified using
0105  * setKeyBindings()
0106  *
0107  * The emulation maintains certain state information which changes depending on the
0108  * input received.  The emulation can be reset back to its starting state by calling
0109  * reset().
0110  *
0111  * The emulation also maintains an activity state, which specifies whether
0112  * terminal is currently active ( when data is received ), normal
0113  * ( when the terminal is idle or receiving user input ) or trying
0114  * to alert the user ( also known as a "Bell" event ).  The stateSet() signal
0115  * is emitted whenever the activity state is set.  This can be used to determine
0116  * how long the emulation has been active/idle for and also respond to
0117  * a 'bell' event in different ways.
0118  */
0119 class Emulation : public QObject
0120 {
0121     Q_OBJECT
0122 
0123 public:
0124     /**
0125      * This enum describes the available shapes for the keyboard cursor.
0126      * See setKeyboardCursorShape()
0127      */
0128     enum class KeyboardCursorShape {
0129         /** A rectangular block which covers the entire area of the cursor character. */
0130         BlockCursor = 0,
0131         /**
0132          * A single flat line which occupies the space at the bottom of the cursor
0133          * character's area.
0134          */
0135         UnderlineCursor = 1,
0136         /**
0137          * An cursor shaped like the capital letter 'I', similar to the IBeam
0138          * cursor used in Qt/KDE text editors.
0139          */
0140         IBeamCursor = 2
0141     };
0142 
0143     /** Constructs a new terminal emulation */
0144     Emulation();
0145     ~Emulation() override;
0146 
0147     /**
0148      * Creates a new window onto the output from this emulation.  The contents
0149      * of the window are then rendered by views which are set to use this window using the
0150      * TerminalDisplay::setScreenWindow() method.
0151      */
0152     ScreenWindow *createWindow();
0153 
0154     /** Returns the size of the screen image which the emulation produces */
0155     QSize imageSize() const;
0156 
0157     /**
0158      * Returns the total number of lines, including those stored in the history.
0159      */
0160     int lineCount() const;
0161 
0162     /**
0163      * Sets the history store used by this emulation.  When new lines
0164      * are added to the output, older lines at the top of the screen are transferred to a history
0165      * store.
0166      *
0167      * The number of lines which are kept and the storage location depend on the
0168      * type of store.
0169      */
0170     void setHistory(const HistoryType &);
0171     /** Returns the history store used by this emulation.  See setHistory() */
0172     const HistoryType &history() const;
0173     /** Clears the history scroll. */
0174     void clearHistory();
0175 
0176     /**
0177      * Copies the output history from @p startLine to @p endLine
0178      * into @p stream, using @p decoder to convert the terminal
0179      * characters into text.
0180      *
0181      * @param decoder A decoder which converts lines of terminal characters with
0182      * appearance attributes into output text.  PlainTextDecoder is the most commonly
0183      * used decoder.
0184      * @param startLine Index of first line to copy
0185      * @param endLine Index of last line to copy
0186      */
0187     virtual void writeToStream(TerminalCharacterDecoder *decoder, int startLine, int endLine);
0188 
0189     /**
0190      * Copies the complete output history into @p stream, using @p decoder to convert
0191      * the terminal characters into text.
0192      *
0193      * @param decoder A decoder which converts lines of terminal characters with
0194      * appearance attributes into output text.  PlainTextDecoder is the most commonly
0195      * used decoder.
0196      */
0197     virtual void writeToStream(TerminalCharacterDecoder *decoder);
0198 
0199     /** Returns the codec used to decode incoming characters.  See setCodec() */
0200     const QTextCodec *codec() const
0201     {
0202         return _codec;
0203     }
0204     /** Sets the codec used to decode incoming characters.  */
0205     void setCodec(const QTextCodec *);
0206 
0207     /**
0208      * Convenience method.
0209      * Returns true if the current codec used to decode incoming
0210      * characters is UTF-8
0211      */
0212     bool utf8() const
0213     {
0214         Q_ASSERT(_codec);
0215         return _codec->mibEnum() == 106;
0216     }
0217 
0218     /** TODO Document me */
0219     virtual char eraseChar() const;
0220 
0221     /**
0222      * Sets the key bindings used to key events
0223      * ( received through sendKeyEvent() ) into character
0224      * streams to send to the terminal.
0225      */
0226     void setKeyBindings(const QString &name);
0227     /**
0228      * Returns the name of the emulation's current key bindings.
0229      * See setKeyBindings()
0230      */
0231     QString keyBindings() const;
0232 
0233     /**
0234      * Copies the current image into the history and clears the screen.
0235      */
0236     virtual void clearEntireScreen() = 0;
0237 
0238     /** Resets the state of the terminal. */
0239     virtual void reset() = 0;
0240 
0241     /**
0242      * Returns true if the active terminal program wants
0243      * mouse input events.
0244      *
0245      * The programUsesMouseChanged() signal is emitted when this
0246      * changes.
0247      */
0248     bool programUsesMouse() const;
0249 
0250     bool programBracketedPasteMode() const;
0251 
0252 public Q_SLOTS:
0253 
0254     /** Change the size of the emulation's image */
0255     virtual void setImageSize(int lines, int columns);
0256 
0257     /**
0258      * Interprets a sequence of characters and sends the result to the terminal.
0259      * This is equivalent to calling sendKeyEvent() for each character in @p text in succession.
0260      */
0261     virtual void sendText(const QString &text) = 0;
0262 
0263     /**
0264      * Interprets a key press event and emits the sendData() signal with
0265      * the resulting character stream.
0266      */
0267     virtual void sendKeyEvent(QKeyEvent *, bool fromPaste);
0268 
0269     /**
0270      * Converts information about a mouse event into an xterm-compatible escape
0271      * sequence and emits the character sequence via sendData()
0272      */
0273     virtual void sendMouseEvent(int buttons, int column, int line, int eventType);
0274 
0275     /**
0276      * Sends a string of characters to the foreground terminal process.
0277      *
0278      * @param string The characters to send.
0279      * @param length Length of @p string or if set to a negative value, @p string will
0280      * be treated as a null-terminated string and its length will be determined automatically.
0281      */
0282     virtual void sendString(const char *string, int length = -1) = 0;
0283 
0284     /**
0285      * Processes an incoming stream of characters.  receiveData() decodes the incoming
0286      * character buffer using the current codec(), and then calls receiveChar() for
0287      * each unicode character in the resulting buffer.
0288      *
0289      * receiveData() also starts a timer which causes the outputChanged() signal
0290      * to be emitted when it expires.  The timer allows multiple updates in quick
0291      * succession to be buffered into a single outputChanged() signal emission.
0292      *
0293      * @param buffer A string of characters received from the terminal program.
0294      * @param len The length of @p buffer
0295      */
0296     void receiveData(const char *buffer, int len);
0297 
0298 Q_SIGNALS:
0299 
0300     /**
0301      * Emitted when a buffer of data is ready to send to the
0302      * standard input of the terminal.
0303      *
0304      * @param data The buffer of data ready to be sent
0305      * @param len The length of @p data in bytes
0306      */
0307     void sendData(const char *data, int len);
0308 
0309     /**
0310      * Requests that the pty used by the terminal process
0311      * be set to UTF 8 mode.
0312      *
0313      * TODO: More documentation
0314      */
0315     void useUtf8Request(bool);
0316 
0317     /**
0318      * Emitted when the activity state of the emulation is set.
0319      *
0320      * @param state The new activity state, one of NOTIFYNORMAL, NOTIFYACTIVITY
0321      * or NOTIFYBELL
0322      */
0323     void stateSet(int state);
0324 
0325     /** TODO Document me */
0326     void zmodemDetected();
0327 
0328     /**
0329      * Requests that the color of the text used
0330      * to represent the tabs associated with this
0331      * emulation be changed.  This is a Konsole-specific
0332      * extension from pre-KDE 4 times.
0333      *
0334      * TODO: Document how the parameter works.
0335      */
0336     void changeTabTextColorRequest(int color);
0337 
0338     /**
0339      * This is emitted when the program running in the shell indicates whether or
0340      * not it is interested in mouse events.
0341      *
0342      * @param usesMouse This will be true if the program wants to be informed about
0343      * mouse events or false otherwise.
0344      */
0345     void programUsesMouseChanged(bool usesMouse);
0346 
0347     void programBracketedPasteModeChanged(bool bracketedPasteMode);
0348 
0349     /**
0350      * Emitted when the contents of the screen image change.
0351      * The emulation buffers the updates from successive image changes,
0352      * and only emits outputChanged() at sensible intervals when
0353      * there is a lot of terminal activity.
0354      *
0355      * Normally there is no need for objects other than the screen windows
0356      * created with createWindow() to listen for this signal.
0357      *
0358      * ScreenWindow objects created using createWindow() will Q_EMIT their
0359      * own outputChanged() signal in response to this signal.
0360      */
0361     void outputChanged();
0362 
0363     /**
0364      * Emitted when the program running in the terminal wishes to update the
0365      * session's title.  This also allows terminal programs to customize other
0366      * aspects of the terminal emulation display.
0367      *
0368      * This signal is emitted when the escape sequence "\033]ARG;VALUE\007"
0369      * is received in the input string, where ARG is a number specifying what
0370      * should change and VALUE is a string specifying the new value.
0371      *
0372      * TODO:  The name of this method is not very accurate since this method
0373      * is used to perform a whole range of tasks besides just setting
0374      * the user-title of the session.
0375      *
0376      * @param title Specifies what to change.
0377      * <ul>
0378      * <li>0 - Set window icon text and session title to @p newTitle</li>
0379      * <li>1 - Set window icon text to @p newTitle</li>
0380      * <li>2 - Set session title to @p newTitle</li>
0381      * <li>11 - Set the session's default background color to @p newTitle,
0382      *         where @p newTitle can be an HTML-style string ("#RRGGBB") or a named
0383      *         color (eg 'red', 'blue').
0384      *         See http://doc.trolltech.com/4.2/qcolor.html#setNamedColor for more
0385      *         details.
0386      * </li>
0387      * <li>31 - Supposedly treats @p newTitle as a URL and opens it (NOT IMPLEMENTED)</li>
0388      * <li>32 - Sets the icon associated with the session.  @p newTitle is the name
0389      *    of the icon to use, which can be the name of any icon in the current KDE icon
0390      *    theme (eg: 'konsole', 'kate', 'folder_home')</li>
0391      * </ul>
0392      * @param newTitle Specifies the new title
0393      */
0394 
0395     void titleChanged(int title, const QString &newTitle);
0396 
0397     /**
0398      * Emitted when the program running in the terminal changes the
0399      * screen size.
0400      */
0401     void imageSizeChanged(int lineCount, int columnCount);
0402 
0403     /**
0404      * Emitted when the setImageSize() is called on this emulation for
0405      * the first time.
0406      */
0407     void imageSizeInitialized();
0408 
0409     /**
0410      * Emitted after receiving the escape sequence which asks to change
0411      * the terminal emulator's size
0412      */
0413     void imageResizeRequest(const QSize &sizz);
0414 
0415     /**
0416      * Emitted when the terminal program requests to change various properties
0417      * of the terminal display.
0418      *
0419      * A profile change command occurs when a special escape sequence, followed
0420      * by a string containing a series of name and value pairs is received.
0421      * This string can be parsed using a ProfileCommandParser instance.
0422      *
0423      * @param text A string expected to contain a series of key and value pairs in
0424      * the form:  name=value;name2=value2 ...
0425      */
0426     void profileChangeCommandReceived(const QString &text);
0427 
0428     /**
0429      * Emitted when a flow control key combination ( Ctrl+S or Ctrl+Q ) is pressed.
0430      * @param suspendKeyPressed True if Ctrl+S was pressed to suspend output or Ctrl+Q to
0431      * resume output.
0432      */
0433     void flowControlKeyPressed(bool suspendKeyPressed);
0434 
0435     /**
0436      * Emitted when the cursor shape or its blinking state is changed via
0437      * DECSCUSR sequences.
0438      *
0439      * @param cursorShape One of 3 possible values in KeyboardCursorShape enum
0440      * @param blinkingCursorEnabled Whether to enable blinking or not
0441      */
0442     void cursorChanged(KeyboardCursorShape cursorShape, bool blinkingCursorEnabled);
0443 
0444     void handleCommandFromKeyboard(KeyboardTranslator::Command command);
0445     void outputFromKeypressEvent(void);
0446 
0447 protected:
0448     virtual void setMode(int mode) = 0;
0449     virtual void resetMode(int mode) = 0;
0450 
0451     /**
0452      * Processes an incoming character.  See receiveData()
0453      * @p ch A unicode character code.
0454      */
0455     virtual void receiveChar(QChar ch);
0456 
0457     /**
0458      * Sets the active screen.  The terminal has two screens, primary and alternate.
0459      * The primary screen is used by default.  When certain interactive programs such
0460      * as Vim are run, they trigger a switch to the alternate screen.
0461      *
0462      * @param index 0 to switch to the primary screen, or 1 to switch to the alternate screen
0463      */
0464     void setScreen(int index);
0465 
0466     enum EmulationCodec { LocaleCodec = 0, Utf8Codec = 1 };
0467     void setCodec(EmulationCodec codec); // codec number, 0 = locale, 1=utf8
0468 
0469     std::vector<std::unique_ptr<ScreenWindow>> _windows;
0470 
0471     Screen *_currentScreen; // pointer to the screen which is currently active,
0472                             // this is one of the elements in the screen[] array
0473 
0474     std::unique_ptr<Screen> _primaryScreen; // 0 = primary screen ( used by most programs, including the shell
0475                                             //                      scrollbars are enabled in this mode )
0476     std::unique_ptr<Screen> _alternateScreen; // 1 = alternate      ( used by vi , emacs etc.
0477                                               //                      scrollbars are not enabled in this mode )
0478 
0479     // decodes an incoming C-style character stream into a unicode QString using
0480     // the current text codec.  (this allows for rendering of non-ASCII characters in text files etc.)
0481     const QTextCodec *_codec;
0482     std::unique_ptr<QTextDecoder> _decoder;
0483     const KeyboardTranslator *_keyTranslator; // the keyboard layout
0484 
0485 protected Q_SLOTS:
0486     /**
0487      * Schedules an update of attached views.
0488      * Repeated calls to bufferedUpdate() in close succession will result in only a single update,
0489      * much like the Qt buffered update of widgets.
0490      */
0491     void bufferedUpdate();
0492 
0493 private Q_SLOTS:
0494 
0495     // triggered by timer, causes the emulation to send an updated screen image to each
0496     // view
0497     void showBulk();
0498 
0499     void usesMouseChanged(bool usesMouse);
0500 
0501     void bracketedPasteModeChanged(bool bracketedPasteMode);
0502 
0503 private:
0504     bool _usesMouse;
0505     bool _bracketedPasteMode;
0506     QTimer _bulkTimer1;
0507     QTimer _bulkTimer2;
0508 };
0509 
0510 }
0511 
0512 #endif // ifndef EMULATION_H