Open-source project
lxqt/qtermwidget avatar
lxqt/qtermwidget

QTermWidget, embedding a terminal emulator inside a Qt application

The terminal widget for QTerminal

607 stars317 forksC++GPL-2.0

At a glance

What is it?
QTermWidget is a Qt 6 widget that embeds a full terminal emulator in your own application, descended from the KDE Konsole codebase and still carrying the pty and character-decoding code from that era. It gives you a console in a dialog, but it also hands you a GPLv2 dependency and a C++ API shaped by twenty years of inheritance.
Who is it for?
QTermWidget suits a Qt 6 application that needs to show the user a real shell, a serial console or a live log view, and it suits a maintainer of an existing Konsole-derived tool that wants to drop the old KDE4 dependency. It does not suit a project that is merely looking for a terminal emulator to run, since it is a widget and not an application, and it does not suit a commercial product that needs a permissive licence, because the library is GPLv2 or later.
Can I use it commercially?
Yes, with conditions. GPL-2.0 is a copyleft licence: if you distribute software that includes it, you must release that software's source code under the same licence. Running it internally without distributing it does not trigger that obligation.
Is it still maintained?
Yes. The repository last received commits 5 days ago.
What is it written in?
Mainly C++, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A Konsole descendant that took its own direction

QTermWidget is a terminal emulator widget for Qt 6, and the project describes it as an open source project originally based on the KDE4 Konsole application, but that took its own direction later on.

That lineage is visible in the repository layout, and it explains a lot about the code. The `lib/` directory contains files named `kpty.cpp`, `kptydevice.cpp`, `kptyprocess.cpp` and `kprocess.cpp`, alongside `qtermwidget.cpp` and `TerminalCharacterDecoder.cpp`. The `k` prefixes and the file names come straight from the KDE tree, and the API in the documentation still uses the KDE naming conventions, with arguments written as `_startnow_`, `_parent_` and `_program_` in that italic form.

The stated main goal is to provide a Unicode-enabled, embeddable Qt widget for using as a built-in console, or terminal emulation widget. The distinction from a terminal emulator application is the point: this is a QWidget you place in your own window, and it is compatible with BSD, Linux and OS X.

The audience is therefore an application developer building a device configurator, a build console, a remote shell panel or a live log view into a Qt application, and the second audience is a maintainer of a Konsole-derived tool looking to modernize it away from KDE4.

The last push to the repository was on 2026-10-18, the project is not archived, and the recorded releases are 2.4.0 from 2026-04-20, 2.3.0 from 2025-11-05 and 2.2.0 from 2025-04-17. It is part of the LXQt project, and its homepage points at the LXQt site.

The public API is a shell program and a pty

The API documentation in the repository is a full class reference, and reading it tells you what the widget actually is: a pty running a shell, wrapped in a widget.

The public functions are the clearest statement of that.

cpp
void | setShellProgram(const QString &_program_)
void | setArgs(QStringList &_args_)
void | setEnvironment(const QStringList &_environment_)
void | setWorkingDirectory(const QString &_dir_)
void | changeDir(const QString _&dir_)
void | setAutoClose(bool _enabled_)
void | startShellProgram()
void | startTerminalTeletype()

You set the program, the arguments, the environment and the working directory, then start it. `startTerminalTeletype` is the older entry point and is kept alongside the shell-oriented one. `setAutoClose` decides whether the widget dies with the child process, which matters for a panel that shows a command that exits.

The properties expose the state of the session, and several of them are the ones you cannot get anywhere else.

cpp
* getPtySlaveFd : const int
* getShellPID : int
* getForegroundProcessId : int
* historyLinesCount : int
* screenColumnsCount : int
* workingDirectory : QString
* keyBindings : QString
* wordCharacters : QString

`getPtySlaveFd` gives you the file descriptor of the pty slave, which is how you pipe the session's input and output to something else. `getShellPID` and `getForegroundProcessId` tell you the shell and the process currently in the foreground, which is what you need to know when a user asks you to kill the running job.

`historyLinesCount` and `screenColumnsCount` are read/write, so the buffer size is configurable, and `keyBindings` exposes the binding set as a string, which is what the `setKeyBindings` slot and the `availableKeyBindings` static member are for.

The signals are the other half of the contract, and they are the ones an application actually uses.

cpp
void | activity()
void | silence()
void | bell(const QString &_message_)
void | receivedData(const QString &_text_)
void | sendData(const char*, int)
void | titleChanged()
void | urlActivated(const QUrl &, bool _fromContextMenu_)
void | copyAvailable(bool)

`activity` and `silence` are the pair you use to implement a heartbeat: pair them with `setMonitorActivity` and `setMonitorSilence` plus `setSilenceTimeout` to know when the child has gone quiet for a given number of seconds. `bell` reports the terminal bell so your application can flash or beep. `urlActivated` reports a clicked URL with a flag saying whether it came from a context menu, which lets you decide whether to open it in an embedded browser.

That is a genuinely useful API for a host application, and it is much wider than a plain terminal widget would offer.

Building it, and what it needs on the machine

The build documentation is short and the dependency list is small, which is the pleasant surprise in a project with this much inherited code.

The only runtime dependency is qtbase at version 6.6.0 or newer. That floor is the real constraint of the modern Qt 6 port, and it is worth checking against your project before anything else. The build dependencies are CMake at 3.16.0 or newer as the build system, lxqt-build-tools at 2.0.0 or newer, and Git if you want to pull the latest VCS checkouts.

Code configuration is handled by CMake, and the documentation names the variables you will have to set. `CMAKE_INSTALL_PREFIX` will normally have to be set to `/usr`, depending on how library paths are dealt with on 64-bit systems, and variables like `CMAKE_INSTALL_LIBDIR` may have to be set as well.

The build itself is the usual CMake pair of targets: to build, run `make`, and to install, run `make install`, which accepts the variable `DESTDIR` as usual. That is the `DESTDIR` convention for packaging, and it is what a distribution package build would use.

Binary packages are the normal route for most people. The library is provided by all major Linux distributions, including Arch Linux, Debian, Fedora, openSUSE and all of their children, given they use the same package repositories, and the documentation tells you to search for the string `qtermwidget` in the distribution's package manager.

There is also a PyQt binding path, and it is more involved than a normal binding. To build PyQt bindings you build this library first and then invoke `sip-wheel` in the `pyqt/` directory. Environment variables `CXXFLAGS` and `LDFLAGS` can be used to specify non-installed or non-standard directories for headers and shared libraries, and the built Python wheel can be installed by standard tools like `pip`. The repository has a `pyqt/` directory and an `examples/pyqt/` directory, and points at a CI script for a complete example.

The `examples/` directory also holds `cpp/` examples and a README, which is the fastest way to see a widget wired into a window.

The licence is the GPL with an LGPL tail

The licensing is more nuanced than a single label, and it is the part to read carefully before you embed this in a product.

The project itself is licensed under the terms of the GPLv2 or any later version, and the LICENSE file at the root carries the full text. That is the copyleft licence, so linking this library into your application means your application must also comply with the GPL when distributed.

But the documentation also lists specific files published under compatible licences, and the list is long enough to matter.

text
Files: example/main.cpp
       lib/TerminalCharacterDecoder.cpp
       lib/TerminalCharacterDecoder.h
       lib/kprocess.cpp
       lib/kprocess.h
       lib/kpty.cpp
       lib/kpty.h
       lib/kpty_p.h
       lib/kptydevice.cpp
       lib/kptydevice.h
       lib/kptyprocess.cpp
       lib/kptyprocess.h
       lib/qtermwidget.cpp
       lib/qtermwidget.h
       lib/qtermwidget_interface.h

Those files are LGPL-2+, with the copyright holders listed as Adriaan de Groot and KDE e.V for the earlier work, Oswald Buddenhagen, Robert Knight, Waldo Bastian, e_k, and Francesc Martinez for the 2022 contribution. There is a separate LICENSE.LGPL2+ file at the root of the repository, along with a LICENSE.BSD-3-clause file.

The third licence in the picture is BSD-3-clause, applied to `cmake/FindUtf8Proc.cmake`, credited to Kitware and to Philip Lowman, which is a vendored CMake module for finding the utf8proc library.

The top-level tree also contains a `COPYING-CMAKE-SCRIPTS` file and a `qtermwidget.spec` file, the latter being a RPM spec, so the packaging side is set up for distribution use.

For an adopter, the practical question is not which file is which licence but whether the whole of your application ends up under the GPL as a consequence of using this widget. The LGPL components inside the library give some flexibility for the library's own files, but the GPLv2 grant on the project is the term that governs your application, and this is not legal advice, it is the reason to read the LICENSE file and consult whoever handles that in your organisation.

Where the widget stops and a full terminal takes over

QTermWidget is a widget, and the boundary is worth being explicit about before you adopt it.

It is not a terminal emulator application. If you want a terminal for users to run, you use a terminal emulator, and this library is the piece you would embed if you were building one, or if you wanted a console panel inside an existing application. A device configuration screen with a shell at the bottom, a build log view that is actually a terminal, a serial console for embedded hardware: those are the shapes this fits.

What it does not do is the modern conveniences users now expect from a terminal. There is no tabbed interface, no split panes, no search across the scrollback, no configuration file format, no profiles beyond a colour scheme and a key binding set, and no unified clipboard handling beyond the `copyClipboard` and `pasteClipboard` slots. The feature set in the API is a single session with a scrollback buffer.

The `selectedText` property with its `preserveLineBreaks` argument, the `wordCharacters` property for double-click word selection, and the `toggleShowSearchBar` slot show that it implements the selection model and a simple search bar, but this is a widget in the Konsole tradition, not a modern terminal feature set.

There is also a platform constraint on the pty back end. The project states compatibility with BSD, Linux and OS X, and the kpty implementation is POSIX-oriented, with a `kpty_p.h` header and a `kptydevice.cpp` and `kptyprocess.cpp` pair. Windows is not in the list of supported platforms for this library, which is a sharp difference from the general-purpose terminal emulators available there.

The second limit is the age of the code. The Konsole4 lineage means the character decoding and pty handling predate most of modern terminal feature work, and the Java 22 style of API churn in Qt 6 means this library tracks a specific Qt 6 floor rather than the newest one. The `TerminalCharacterDecoder` and the `kpty` files are where a modern reimplementation would differ most.

Colour schemes, custom bindings and a static API

The customisation surface is small and mostly about appearance.

Colour schemes are handled through `setColorScheme`, with `availableColorSchemes` as a static member so you can populate a menu. There is also `addCustomColorSchemeDir` to point the library at a directory of your own schemes, and `setCustomKeyBindingsDir` with a matching `clearCustomKeyBindingsDir` for custom key bindings, plus `availableKeyBindings` to enumerate them.

The `profileChanged` signal reports when the active profile changes, and the `title` property plus the `titleChanged` signal let the host application follow the shell prompt title, which is the usual way to build a tab title in a shell host.

A few options are about behaviour rather than looks and are worth knowing. `setMotionAfterPasting` controls what happens after a paste, `setTerminalOpacity` sets the background transparency, `setFlowControlEnabled` and `setFlowControlWarningEnabled` handle the XON/XOFF flow control behaviour, and `terminalSizeHint` with `setTerminalSizeHint` lets the widget advertise the size it would prefer.

There is a `setKeyboardCursorShape` with the `KeyboardCursorShape` enum offering a block cursor, an underline cursor and an I-beam cursor, and a `ScrollBarPosition` enum with no scroll bar, left or right.

The `static` nature of some of this is a design point rather than an oversight. The available schemes and key bindings are class-level, not per-instance, which is fine for an application that has one terminal panel and awkward for a multi-pane host that wants two widgets with different colour schemes.

For a project watching the LXQt project, the Weblate integration is the way to contribute translations, and the repository has a `.translation-update` file and a `docs/` directory for the developer documentation.

Editorial conclusion

QTermWidget suits a Qt 6 application that needs to show the user a real shell, a serial console or a live log view, and it suits a maintainer of an existing Konsole-derived tool that wants to drop the old KDE4 dependency. It does not suit a project that is merely looking for a terminal emulator to run, since it is a widget and not an application, and it does not suit a commercial product that needs a permissive licence, because the library is GPLv2 or later. Verify first that your Qt version is 6.6 or newer, since that is the stated runtime dependency, that the pty back end works on your target platform, since the library is documented as compatible with BSD, Linux and OS X, and that the GPLv2 terms are acceptable for how you intend to ship the application.

Frequently asked questions

What is QTermWidget and what is it for?

It is a terminal emulator widget for Qt 6, described as an open source project originally based on the KDE4 Konsole application that took its own direction later. The main goal is to provide a Unicode-enabled, embeddable Qt widget for use as a built-in console, and it is compatible with BSD, Linux and OS X.

What are the build requirements for QTermWidget?

The only runtime dependency is qtbase 6.6.0 or newer. Building needs CMake 3.16.0 or newer, lxqt-build-tools 2.0.0 or newer, and Git if you want to pull the latest VCS checkouts. CMAKE_INSTALL_PREFIX will normally have to be set to /usr, and variables such as CMAKE_INSTALL_LIBDIR may also need setting.

How do I run a shell inside a QTermWidget?

Set the program with setShellProgram, the arguments with setArgs, the environment with setEnvironment and the working directory with setWorkingDirectory, then call startShellProgram. setAutoClose controls whether the widget closes with the child process.

Can I use QTermWidget from Python?

There are PyQt bindings. To build them you build the library first and then invoke sip-wheel in the pyqt/ directory, with CXXFLAGS and LDFLAGS available to point at non-standard header and library directories, and the resulting wheel can be installed with pip. The repository has an examples/pyqt directory.

What licence does QTermWidget use?

The project is licensed under the GPLv2 or any later version, with some individual files published under compatible licences, specifically the LGPL-2+ for files such as lib/qtermwidget.cpp, lib/kpty.cpp and lib/TerminalCharacterDecoder.cpp, and BSD-3-clause for cmake/FindUtf8Proc.cmake. The repository holds LICENSE, LICENSE.LGPL2+ and LICENSE.BSD-3-clause files.

Official sources

  1. License: GPL-2.0
  2. lxqt/qtermwidget on GitHub
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/lxqt-qtermwidget.svg)](https://hysenlabs.com/projects/lxqt-qtermwidget)

Was this useful?