diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..72a237f --- /dev/null +++ b/.gitignore @@ -0,0 +1,11 @@ +debian/*.debhelper +debian/*.log +debian/*.mangled +debian/*.substvars +debian/debhelper-build-stamp +debian/files + +debian/libqtermwidget5-0-dev/ +debian/libqtermwidget5-0/ +debian/qtermwidget5-data/ +debian/tmp/ diff --git a/CHANGELOG b/CHANGELOG index cdc3f17..ae1c154 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,7 +1,40 @@ -qtermwidget-0.8.0 / 2017-10-21 +qtermwidget-0.9.0 / 2018-05-21 ============================== + * Bumped minor version to 9 + * Take transient scrollbars into account + * CMake: Prevent in-source builds + * Refactor and fixes Python binding + * kptyprocess: Try to terminate the shell process + * New color scheme: Ubuntu inspired + * Fixed some github pathes in uris + * Add a comment for potential future breakage + * Use wstring in TerminalCharacterDecoder for UCS-4 compatibility + * Support UTF-32 characters correctly + * Fix "bold and intensive" colors + * New color scheme: Tango (#167) + * Finish SGR mouse protocol (1006) + * Fix build of example with latest lxqt-build-tools + * Expose bracket text function + * Drop Qt foreach. + * Revert deletions in .sip file + * fix python bindings + * Expose terminal size hint API + * Remove class name + * Return something + * Expose bidi option + * Add an example for remote terminal + * Makes the use of libutempter optional + * Fix behavior of scroll up (SU) + * Install cmake files in LIBDIR as they are architecture dependend + * Check if utempter.h header exists (mainly for FreeBSD) + * Need lxqt-build-tools 0.4.0 + +0.8.0 / 2017-10-21 +================== + + * Release 0.8.0: Update changelog * FIX: #46 fix vertical font truncation * bump versions * Really fallback to /bin/sh when $SHELL is missing or invalid diff --git a/CMakeLists.txt b/CMakeLists.txt index c5930c6..462e841 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,15 +6,19 @@ include(GNUInstallDirs) include(GenerateExportHeader) include(CMakePackageConfigHelpers) include(CheckFunctionExists) +include(CheckIncludeFile) -set(REQUIRED_QT_VERSION "5.6") -set(LXQTBT_MINIMUM_VERSION "0.4.0") +set(REQUIRED_QT_VERSION "5.7.1") +set(LXQTBT_MINIMUM_VERSION "0.5.0") option(UPDATE_TRANSLATIONS "Update source translation translations/*.ts files" OFF) option(BUILD_EXAMPLE "Build example application. Default OFF." OFF) +option(QTERMWIDGET_USE_UTEMPTER "Uses the libutempter library. Mainly for FreeBSD" OFF) +option(QTERMWIDGET_BUILD_PYTHON_BINDING "Build python binding" OFF) + # just change version for releases set(QTERMWIDGET_VERSION_MAJOR "0") -set(QTERMWIDGET_VERSION_MINOR "8") +set(QTERMWIDGET_VERSION_MINOR "9") set(QTERMWIDGET_VERSION_PATCH "0") set(QTERMWIDGET_VERSION "${QTERMWIDGET_VERSION_MAJOR}.${QTERMWIDGET_VERSION_MINOR}.${QTERMWIDGET_VERSION_PATCH}") @@ -31,6 +35,8 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON) find_package(Qt5Widgets "${REQUIRED_QT_VERSION}" REQUIRED) find_package(Qt5LinguistTools "${REQUIRED_QT_VERSION}" REQUIRED) find_package(lxqt-build-tools ${LXQTBT_MINIMUM_VERSION} REQUIRED) + +include(LXQtPreventInSourceBuilds) include(LXQtTranslateTs) include(LXQtCompilerSettings NO_POLICY_SCOPE) include(LXQtCreatePkgConfigFile) @@ -160,6 +166,16 @@ if(HAVE_UPDWTMPX) ) endif() +if (QTERMWIDGET_USE_UTEMPTER) + CHECK_INCLUDE_FILE(utempter.h HAVE_UTEMPTER) + if (HAVE_UTEMPTER) + target_compile_definitions(${QTERMWIDGET_LIBRARY_NAME} PRIVATE + "HAVE_UTEMPTER" + ) + target_link_libraries(${QTERMWIDGET_LIBRARY_NAME} ulog) + endif() +endif() + if (UTF8PROC_FOUND) target_compile_definitions(${QTERMWIDGET_LIBRARY_NAME} PRIVATE @@ -188,6 +204,7 @@ target_compile_definitions(${QTERMWIDGET_LIBRARY_NAME} "TRANSLATIONS_DIR=\"${TRANSLATIONS_DIR}\"" "HAVE_POSIX_OPENPT" "HAVE_SYS_TIME_H" + "QT_NO_FOREACH" ) @@ -213,13 +230,13 @@ write_basic_package_version_file( install(FILES "${CMAKE_BINARY_DIR}/${QTERMWIDGET_LIBRARY_NAME}-config-version.cmake" - DESTINATION "${CMAKE_INSTALL_DATADIR}/cmake/${QTERMWIDGET_LIBRARY_NAME}" + DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${QTERMWIDGET_LIBRARY_NAME}" COMPONENT Devel ) install(EXPORT "${QTERMWIDGET_LIBRARY_NAME}-targets" - DESTINATION "${CMAKE_INSTALL_DATADIR}/cmake/${QTERMWIDGET_LIBRARY_NAME}" + DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${QTERMWIDGET_LIBRARY_NAME}" COMPONENT Devel ) @@ -263,7 +280,7 @@ configure_file( install(FILES "${CMAKE_BINARY_DIR}/${QTERMWIDGET_LIBRARY_NAME}-config.cmake" - DESTINATION "${CMAKE_INSTALL_DATADIR}/cmake/${QTERMWIDGET_LIBRARY_NAME}" + DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${QTERMWIDGET_LIBRARY_NAME}" COMPONENT Devel ) @@ -290,6 +307,12 @@ if(BUILD_EXAMPLE) endif() # end of example application +# python binding +if (QTERMWIDGET_BUILD_PYTHON_BINDING) + add_subdirectory(pyqt) +endif() +# end of python binding + CONFIGURE_FILE( "${CMAKE_CURRENT_SOURCE_DIR}/cmake/cmake_uninstall.cmake.in" diff --git a/README.md b/README.md index ce35585..edeea07 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ This project is licensed under the terms of the [GPLv2](https://www.gnu.org/lice ### Compiling sources The only runtime dependency is qtbase ≥ 5.6. -In order to build CMake ≥ 3.0.2 and [lxqt-build-tools](https://github.com/lxde/lxqt-build-tools/) >= 0.3 are needed as well as Git to pull translations and optionally latest VCS checkouts. +In order to build CMake ≥ 3.0.2 and [lxqt-build-tools](https://github.com/lxqt/lxqt-build-tools/) >= 0.4.0 are needed as well as Git to pull translations and optionally latest VCS checkouts. Code configuration is handled by CMake. CMake variable `CMAKE_INSTALL_PREFIX` will normally have to be set to `/usr`, depending on the way library paths are dealt with on 64bit systems variables like `CMAKE_INSTALL_LIBDIR` may have to be set as well. diff --git a/debian/.gitignore b/debian/.gitignore deleted file mode 100644 index 43d929b..0000000 --- a/debian/.gitignore +++ /dev/null @@ -1,11 +0,0 @@ -/*.debhelper -/*.log -/*.mangled -/*.substvars -/debhelper-build-stamp -/files - -/libqtermwidget5-0-dev/ -/libqtermwidget5-0/ -/qtermwidget5-data/ -/tmp/ diff --git a/debian/changelog b/debian/changelog index ca0e53d..0b83c21 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,14 @@ +qtermwidget (0.9.0-1) unstable; urgency=medium + + * Cherry-picking upstream release: 0.9.0. + * Moved debian/.gitignore to ./.gitignore + * Bumped build dependency lxqt-build-tools to >= 0.5.0~ + * Removed cmake fix, applied upstream + * Added some options to rules + * Added some new symbols + + -- Alf Gaida Thu, 24 May 2018 01:11:06 +0200 + qtermwidget (0.8.0-6) unstable; urgency=medium * Bumped compat to 11 diff --git a/debian/control b/debian/control index 2358d8f..8e957a3 100644 --- a/debian/control +++ b/debian/control @@ -8,7 +8,7 @@ Priority: optional Build-Depends: debhelper (>= 11~), cmake, libutf8proc-dev, - lxqt-build-tools (>= 0.4.0), + lxqt-build-tools (>= 0.5.0~), qtbase5-dev Standards-Version: 4.1.4 Vcs-Browser: https://salsa.debian.org/lxqt-team/qtermwidget diff --git a/debian/libqtermwidget5-0.symbols b/debian/libqtermwidget5-0.symbols index c8cd8c1..ca54632 100644 --- a/debian/libqtermwidget5-0.symbols +++ b/debian/libqtermwidget5-0.symbols @@ -6,6 +6,7 @@ libqtermwidget5.so.0 libqtermwidget5-0 #MINVER# (c++)"QTermWidget::availableColorSchemes()@Base" 0.6.0 (c++)"QTermWidget::availableKeyBindings()@Base" 0.6.0 (c++)"QTermWidget::bell(QString const&)@Base" 0.6.0 + (c++)"QTermWidget::bracketText(QString&)@Base" 0.9.0~ (c++)"QTermWidget::changeDir(QString const&)@Base" 0.6.0 (c++)"QTermWidget::clear()@Base" 0.6.0 (c++)"QTermWidget::copyAvailable(bool)@Base" 0.6.0 @@ -27,6 +28,7 @@ libqtermwidget5.so.0 libqtermwidget5-0 #MINVER# (c++)"QTermWidget::historyLinesCount()@Base" 0.6.0 (c++)"QTermWidget::icon() const@Base" 0.7.0 (c++)"QTermWidget::init(int)@Base" 0.6.0 + (c++)"QTermWidget::isBidiEnabled()@Base" 0.9.0~ (c++)"QTermWidget::isTitleChanged() const@Base" 0.7.0 (c++)"QTermWidget::keyBindings()@Base" 0.6.0 (c++)"QTermWidget::matchFound(int, int, int, int)@Base" 0.6.0 @@ -50,6 +52,7 @@ libqtermwidget5.so.0 libqtermwidget5-0 #MINVER# (c++)"QTermWidget::sessionFinished()@Base" 0.6.0 (c++)"QTermWidget::setArgs(QStringList const&)@Base" 0.6.0 (c++)"QTermWidget::setAutoClose(bool)@Base" 0.8.0 + (c++)"QTermWidget::setBidiEnabled(bool)@Base" 0.9.0~ (c++)"QTermWidget::setBlinkingCursor(bool)@Base" 0.8.0 (c++)"QTermWidget::setColorScheme(QString const&)@Base" 0.6.0 (c++)"QTermWidget::setEnvironment(QStringList const&)@Base" 0.6.0 @@ -70,6 +73,7 @@ libqtermwidget5.so.0 libqtermwidget5-0 #MINVER# (c++)"QTermWidget::setTerminalBackgroundImage(QString)@Base" 0.7.1 (c++)"QTermWidget::setTerminalFont(QFont const&)@Base" 0.6.0 (c++)"QTermWidget::setTerminalOpacity(double)@Base" 0.6.0 + (c++)"QTermWidget::setTerminalSizeHint(bool)@Base" 0.9.0~ (c++)"QTermWidget::setTextCodec(QTextCodec*)@Base" 0.6.0 (c++)"QTermWidget::setWorkingDirectory(QString const&)@Base" 0.6.0 (c++)"QTermWidget::setZoom(int)@Base" 0.6.0 @@ -81,6 +85,7 @@ libqtermwidget5.so.0 libqtermwidget5-0 #MINVER# (c++)"QTermWidget::termGetFocus()@Base" 0.6.0 (c++)"QTermWidget::termKeyPressed(QKeyEvent*)@Base" 0.6.0 (c++)"QTermWidget::termLostFocus()@Base" 0.6.0 + (c++)"QTermWidget::terminalSizeHint()@Base" 0.9.0~ (c++)"QTermWidget::title() const@Base" 0.7.0 (c++)"QTermWidget::titleChanged()@Base" 0.7.0 (c++)"QTermWidget::toggleShowSearchBar()@Base" 0.6.0 @@ -92,4 +97,5 @@ libqtermwidget5.so.0 libqtermwidget5-0 #MINVER# (c++)"non-virtual thunk to QTermWidget::~QTermWidget()@Base" 0.6.0 (c++)"typeinfo for QTermWidget@Base" 0.6.0 (c++)"typeinfo name for QTermWidget@Base" 0.6.0 + (c++)"void std::__cxx11::basic_string, std::allocator >::_M_construct(wchar_t const*, wchar_t const*, std::forward_iterator_tag)@Base" 0.9.0~ (c++)"vtable for QTermWidget@Base" 0.6.0 diff --git a/debian/patches/fix-cmake-installdir.patch b/debian/patches/fix-cmake-installdir.patch deleted file mode 100644 index 4b9f35c..0000000 --- a/debian/patches/fix-cmake-installdir.patch +++ /dev/null @@ -1,33 +0,0 @@ -Description: Install cmake files arch-dependend - That will prevent file conflicts described at #880389 -Author: Alf Gaida - -Last-Update: 2017-10-31 - ---- a/CMakeLists.txt -+++ b/CMakeLists.txt -@@ -213,13 +213,13 @@ - - install(FILES - "${CMAKE_BINARY_DIR}/${QTERMWIDGET_LIBRARY_NAME}-config-version.cmake" -- DESTINATION "${CMAKE_INSTALL_DATADIR}/cmake/${QTERMWIDGET_LIBRARY_NAME}" -+ DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${QTERMWIDGET_LIBRARY_NAME}" - COMPONENT Devel - ) - - install(EXPORT - "${QTERMWIDGET_LIBRARY_NAME}-targets" -- DESTINATION "${CMAKE_INSTALL_DATADIR}/cmake/${QTERMWIDGET_LIBRARY_NAME}" -+ DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${QTERMWIDGET_LIBRARY_NAME}" - COMPONENT Devel - ) - -@@ -263,7 +263,7 @@ - - install(FILES - "${CMAKE_BINARY_DIR}/${QTERMWIDGET_LIBRARY_NAME}-config.cmake" -- DESTINATION "${CMAKE_INSTALL_DATADIR}/cmake/${QTERMWIDGET_LIBRARY_NAME}" -+ DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${QTERMWIDGET_LIBRARY_NAME}" - COMPONENT Devel - ) - diff --git a/debian/patches/series b/debian/patches/series deleted file mode 100644 index 3cb6402..0000000 --- a/debian/patches/series +++ /dev/null @@ -1 +0,0 @@ -fix-cmake-installdir.patch diff --git a/debian/rules b/debian/rules index aeeb6f6..5e1668f 100755 --- a/debian/rules +++ b/debian/rules @@ -14,5 +14,9 @@ override_dh_missing: override_dh_auto_configure: dh_auto_configure -- \ -DPULL_TRANSLATIONS=OFF \ + -DUPDATE_TRANSLATIONS=OFF \ + -DBUILD_EXAMPLE=OFF \ + -DQTERMWIDGET_USE_UTEMPTER=OFF \ + -DQTERMWIDGET_BUILD_PYTHON_BINDING=OFF \ -DUSE_UTF8PROC=ON \ -DCMAKE_BUILD_TYPE=RelWithDebInfo diff --git a/example/RemoteTerm/README.md b/example/RemoteTerm/README.md new file mode 100644 index 0000000..78cc885 --- /dev/null +++ b/example/RemoteTerm/README.md @@ -0,0 +1,8 @@ +A simple example showing how to use QTermWidget to control and display a remote terminal. + +To run this example, you should: +1. Build client-side program. In my PC, I use 'apt-get' to install the QTermWidget library. +2. Start the shell-srv.py with specific paramenters.This will expose a shell via socket. +3. Start the client-side program from commandline with specific paramenters. + +Now you will get your own remote terminal work with QTermWidget. \ No newline at end of file diff --git a/example/RemoteTerm/RemoteTerm.pro b/example/RemoteTerm/RemoteTerm.pro new file mode 100644 index 0000000..21c36f7 --- /dev/null +++ b/example/RemoteTerm/RemoteTerm.pro @@ -0,0 +1,34 @@ +#------------------------------------------------- +# +# Project created by QtCreator 2017-10-31T00:37:59 +# +#------------------------------------------------- + +QT += core gui network + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +TARGET = RemoteTerm +TEMPLATE = app + +# The following define makes your compiler emit warnings if you use +# any feature of Qt which as been marked as deprecated (the exact warnings +# depend on your compiler). Please consult the documentation of the +# deprecated API in order to know how to port your code away from it. +DEFINES += QT_DEPRECATED_WARNINGS + +# You can also make your code fail to compile if you use deprecated APIs. +# In order to do so, uncomment the following line. +# You can also select to disable deprecated APIs only up to a certain version of Qt. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + +CONFIG += c++11 + +SOURCES += \ + main.cpp \ + remoteterm.cpp + +HEADERS += \ + remoteterm.h + +unix:!macx: LIBS += -lqtermwidget5 diff --git a/example/RemoteTerm/main.cpp b/example/RemoteTerm/main.cpp new file mode 100644 index 0000000..f51df3a --- /dev/null +++ b/example/RemoteTerm/main.cpp @@ -0,0 +1,19 @@ +#include "remoteterm.h" +#include +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + if(a.arguments().size() != 3){ + qDebug() << "Example(client-side) for remote terminal of QTermWidget."; + qDebug() << QString("Usage: %1 ipaddr port").arg(a.arguments()[0]); + return 1; + } + QString ipaddr = a.arguments().at(1); + quint16 port = a.arguments().at(2).toUShort(); + RemoteTerm w(ipaddr,port); + w.show(); + + return a.exec(); +} diff --git a/example/RemoteTerm/remoteterm.cpp b/example/RemoteTerm/remoteterm.cpp new file mode 100644 index 0000000..551ac25 --- /dev/null +++ b/example/RemoteTerm/remoteterm.cpp @@ -0,0 +1,32 @@ +#include "remoteterm.h" +#include +#include +#include + +RemoteTerm::RemoteTerm(const QString &ipaddr, quint16 port, QWidget *parent) + : QTermWidget(0,parent) +{ + socket = new QTcpSocket(this); + + // Write what we input to remote terminal via socket + connect(this, &RemoteTerm::sendData,[this](const char *data, int size){ + this->socket->write(data, size); + }); + + // Read anything from remote terminal via socket and show it on widget. + connect(socket,&QTcpSocket::readyRead,[this](){ + QByteArray data = socket->readAll(); + write(this->getPtySlaveFd(), data.data(), data.size()); + }); + connect(socket, SIGNAL(error(QAbstractSocket::SocketError)),this,SLOT(atError())); + + // Here we start an empty pty. + this->startTerminalTeletype(); + + socket->connectToHost(ipaddr, port); +} + +void RemoteTerm::atError() +{ + qDebug() << socket->errorString(); +} diff --git a/example/RemoteTerm/remoteterm.h b/example/RemoteTerm/remoteterm.h new file mode 100644 index 0000000..c591ec4 --- /dev/null +++ b/example/RemoteTerm/remoteterm.h @@ -0,0 +1,19 @@ +#ifndef WIDGET_H +#define WIDGET_H + +#include + +class QTcpSocket; + +class RemoteTerm : public QTermWidget +{ + Q_OBJECT +public: + RemoteTerm(const QString &ipaddr, quint16 port, QWidget *parent = 0); +public slots: + void atError(); +private: + QTcpSocket *socket; +}; + +#endif // WIDGET_H diff --git a/example/RemoteTerm/shell-srv.py b/example/RemoteTerm/shell-srv.py new file mode 100644 index 0000000..dc0cb62 --- /dev/null +++ b/example/RemoteTerm/shell-srv.py @@ -0,0 +1,37 @@ +#!/usr/bin/env python + +import sys +import os +import socket +import pty + +def usage(program): + print "Example(server-side) for remote terminal of QTermWidget." + print "Usage: %s ipaddr port" %program + + +def main(): + if len(sys.argv) != 3: + usage(sys.argv[0]) + sys.exit(1) + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + try: + s.bind((sys.argv[1], int(sys.argv[2]))) + s.listen(0) + print "[+]Start Server." + except Exception as e: + print "[-]Error Happened: %s" %e.message + sys.exit(2) + + while True: + c = s.accept() + os.dup2(c[0].fileno(), 0) + os.dup2(c[0].fileno(), 1) + os.dup2(c[0].fileno(), 2) + + # It's important to use pty to spawn the shell. + pty.spawn("/bin/sh") + c[0].close() + +if __name__ == "__main__": + main() diff --git a/example/main.cpp b/example/main.cpp index 509617a..07851ed 100644 --- a/example/main.cpp +++ b/example/main.cpp @@ -55,7 +55,8 @@ int main(int argc, char *argv[]) // console->setColorScheme(COLOR_SCHEME_BLACK_ON_LIGHT_YELLOW); console->setScrollBarPosition(QTermWidget::ScrollBarRight); - foreach (QString arg, QApplication::arguments()) + const auto arguments = QApplication::arguments(); + for (const QString& arg : arguments) { if (console->availableColorSchemes().contains(arg)) console->setColorScheme(arg); diff --git a/lib/Character.h b/lib/Character.h index 0777a7e..9c9fae2 100644 --- a/lib/Character.h +++ b/lib/Character.h @@ -78,7 +78,7 @@ public: union { /** The unicode character value for this character. */ - quint16 character; + wchar_t character; /** * Experimental addition which allows a single Character instance to contain more than * one unicode character. diff --git a/lib/CharacterColor.h b/lib/CharacterColor.h index 2373783..8974929 100644 --- a/lib/CharacterColor.h +++ b/lib/CharacterColor.h @@ -205,13 +205,13 @@ public: } /** - * Toggles the value of this color between a normal system color and the corresponding intensive - * system color. + * Set the value of this color from a normal system color to the corresponding intensive + * system color if it's not already an intensive system color. * * This is only applicable if the color is using the COLOR_SPACE_DEFAULT or COLOR_SPACE_SYSTEM * color spaces. */ - void toggleIntensive(); + void setIntensive(); /** * Returns the color within the specified color @p palette @@ -287,11 +287,11 @@ inline QColor CharacterColor::color(const ColorEntry* base) const return QColor(); } -inline void CharacterColor::toggleIntensive() +inline void CharacterColor::setIntensive() { if (_colorSpace == COLOR_SPACE_SYSTEM || _colorSpace == COLOR_SPACE_DEFAULT) { - _v = !_v; + _v = 1; } } diff --git a/lib/Emulation.cpp b/lib/Emulation.cpp index 2dfb956..babf8b6 100644 --- a/lib/Emulation.cpp +++ b/lib/Emulation.cpp @@ -26,6 +26,7 @@ #include #include #include +#include // Qt #include @@ -132,7 +133,7 @@ void Emulation::setScreen(int n) if (_currentScreen != old) { // tell all windows onto this emulation to switch to the newly active screen - foreach(ScreenWindow* window,_windows) + for(ScreenWindow* window : const_cast&>(_windows)) window->setScreen(_currentScreen); } } @@ -188,7 +189,7 @@ QString Emulation::keyBindings() const return _keyTranslator->name(); } -void Emulation::receiveChar(int c) +void Emulation::receiveChar(wchar_t c) // process application unicode input to terminal // this is a trivial scanner { @@ -238,11 +239,17 @@ void Emulation::receiveData(const char* text, int length) bufferedUpdate(); - QString unicodeText = _decoder->toUnicode(text,length); + /* XXX: the following code involves encoding & decoding of "UTF-16 + * surrogate pairs", which does not work with characters higher than + * U+10FFFF + * https://unicodebook.readthedocs.io/unicode_encodings.html#surrogates + */ + QString utf16Text = _decoder->toUnicode(text,length); + std::wstring unicodeText = utf16Text.toStdWString(); //send characters to terminal emulator - for (int i=0;ivalue(i) <= position && position < nextLine ) { startLine = i; - startColumn = string_width(buffer()->mid(_linePositions->value(i),position - _linePositions->value(i))); + startColumn = string_width(buffer()->mid(_linePositions->value(i),position - _linePositions->value(i)).toStdWString()); return; } } diff --git a/lib/Screen.cpp b/lib/Screen.cpp index 6104764..ea635e5 100644 --- a/lib/Screen.cpp +++ b/lib/Screen.cpp @@ -419,7 +419,7 @@ void Screen::updateEffectiveRendition() } if (currentRendition & RE_BOLD) - effectiveForeground.toggleIntensive(); + effectiveForeground.setIntensive(); } void Screen::copyFromHistory(Character* dest, int startLine, int count) const @@ -644,7 +644,7 @@ void Screen::checkSelection(int from, int to) clearSelection(); } -void Screen::displayCharacter(unsigned short c) +void Screen::displayCharacter(wchar_t c) { // Note that VT100 does wrapping BEFORE putting the character. // This has impact on the assumption of valid cursor positions. @@ -751,13 +751,18 @@ QRect Screen::lastScrolledRegion() const void Screen::scrollUp(int from, int n) { - if (n <= 0 || from + n > _bottomMargin) return; + if (n <= 0) + return; + if (from > _bottomMargin) + return; + if (from + n > _bottomMargin) + n = _bottomMargin + 1 - from; _scrolledLines -= n; _lastScrolledRegion = QRect(0,_topMargin,columns-1,(_bottomMargin-_topMargin)); //FIXME: make sure `topMargin', `bottomMargin', `from', `n' is in bounds. - moveImage(loc(0,from),loc(0,from+n),loc(columns-1,_bottomMargin)); + moveImage(loc(0,from),loc(0,from+n),loc(columns,_bottomMargin)); clearImage(loc(0,_bottomMargin-n+1),loc(columns-1,_bottomMargin),' '); } diff --git a/lib/Screen.h b/lib/Screen.h index ea526ac..c4baf0e 100644 --- a/lib/Screen.h +++ b/lib/Screen.h @@ -346,7 +346,7 @@ public: * is inserted at the current cursor position, otherwise it will replace the * character already at the current cursor position. */ - void displayCharacter(unsigned short c); + void displayCharacter(wchar_t c); // Do composition with last shown character FIXME: Not implemented yet for KDE 4 void compose(const QString& compose); diff --git a/lib/ShellCommand.cpp b/lib/ShellCommand.cpp index 210285c..ee7104e 100644 --- a/lib/ShellCommand.cpp +++ b/lib/ShellCommand.cpp @@ -96,7 +96,7 @@ QStringList ShellCommand::expand(const QStringList & items) { QStringList result; - foreach(const QString &item, items ) { + for(const QString &item : items) { result << expand(item); } diff --git a/lib/TerminalCharacterDecoder.cpp b/lib/TerminalCharacterDecoder.cpp index b267b37..4cf458b 100644 --- a/lib/TerminalCharacterDecoder.cpp +++ b/lib/TerminalCharacterDecoder.cpp @@ -82,7 +82,7 @@ void PlainTextDecoder::decodeLine(const Character* const characters, int count, //note: we build up a QString and send it to the text stream rather writing into the text //stream a character at a time because it is more efficient. //(since QTextStream always deals with QStrings internally anyway) - QString plainText; + std::wstring plainText; plainText.reserve(count); int outputCount = count; @@ -93,7 +93,7 @@ void PlainTextDecoder::decodeLine(const Character* const characters, int count, { for (int i = count-1 ; i >= 0 ; i--) { - if ( characters[i].character != ' ' ) + if ( characters[i].character != L' ' ) break; else outputCount--; @@ -102,10 +102,10 @@ void PlainTextDecoder::decodeLine(const Character* const characters, int count, for (int i=0;i') - text.append(">"); + text.append(L">"); else - text.append(ch); + text.push_back(ch); } else { - text.append(" "); //HTML truncates multiple spaces, so use a space marker instead + text.append(L" "); //HTML truncates multiple spaces, so use a space marker instead } } @@ -231,18 +231,18 @@ void HTMLDecoder::decodeLine(const Character* const characters, int count, LineP closeSpan(text); //start new line - text.append("
"); + text.append(L"
"); - *_output << text; + *_output << QString::fromStdWString(text); } -void HTMLDecoder::openSpan(QString& text , const QString& style) +void HTMLDecoder::openSpan(std::wstring& text , const QString& style) { - text.append( QString("").arg(style) ); + text.append( QString("").arg(style).toStdWString() ); } -void HTMLDecoder::closeSpan(QString& text) +void HTMLDecoder::closeSpan(std::wstring& text) { - text.append(""); + text.append(L""); } void HTMLDecoder::setColorTable(const ColorEntry* table) diff --git a/lib/TerminalCharacterDecoder.h b/lib/TerminalCharacterDecoder.h index 75d40c3..a73e9a1 100644 --- a/lib/TerminalCharacterDecoder.h +++ b/lib/TerminalCharacterDecoder.h @@ -133,8 +133,8 @@ public: virtual void end(); private: - void openSpan(QString& text , const QString& style); - void closeSpan(QString& text); + void openSpan(std::wstring& text , const QString& style); + void closeSpan(std::wstring& text); QTextStream* _output; const ColorEntry* _colorTable; diff --git a/lib/TerminalDisplay.cpp b/lib/TerminalDisplay.cpp index 3e93f13..8ecdfab 100644 --- a/lib/TerminalDisplay.cpp +++ b/lib/TerminalDisplay.cpp @@ -194,10 +194,10 @@ void TerminalDisplay::setColorTable(const ColorEntry table[]) QCodec. */ -static inline bool isLineChar(quint16 c) { return ((c & 0xFF80) == 0x2500);} -static inline bool isLineCharString(const QString& string) +static inline bool isLineChar(wchar_t c) { return ((c & 0xFF80) == 0x2500);} +static inline bool isLineCharString(const std::wstring& string) { - return (string.length() > 0) && (isLineChar(string.at(0).unicode())); + return (string.length() > 0) && (isLineChar(string[0])); } @@ -377,6 +377,10 @@ TerminalDisplay::TerminalDisplay(QWidget *parent) // create scroll bar for scrolling output up and down // set the scroll bar's slider to occupy the whole area of the scroll bar initially _scrollBar = new QScrollBar(this); + // since the contrast with the terminal background may not be enough, + // the scrollbar should be auto-filled if not transient + if (!_scrollBar->style()->styleHint(QStyle::SH_ScrollBar_Transient, nullptr, _scrollBar)) + _scrollBar->setAutoFillBackground(true); setScroll(0,0); _scrollBar->setCursor( Qt::ArrowCursor ); connect(_scrollBar, SIGNAL(valueChanged(int)), this, @@ -488,7 +492,7 @@ enum LineEncode #include "LineFont.h" -static void drawLineChar(QPainter& paint, int x, int y, int w, int h, uchar code) +static void drawLineChar(QPainter& paint, int x, int y, int w, int h, uint8_t code) { //Calculate cell midpoints, end points. int cx = x + w/2; @@ -635,7 +639,7 @@ static void drawOtherChar(QPainter& paint, int x, int y, int w, int h, uchar cod } } -void TerminalDisplay::drawLineCharString( QPainter& painter, int x, int y, const QString& str, +void TerminalDisplay::drawLineCharString( QPainter& painter, int x, int y, const std::wstring& str, const Character* attributes) { const QPen& currentPen = painter.pen(); @@ -647,9 +651,9 @@ void TerminalDisplay::drawLineCharString( QPainter& painter, int x, int y, co painter.setPen( boldPen ); } - for (int i=0 ; i < str.length(); i++) + for (size_t i=0 ; i < str.length(); i++) { - uchar code = str[i].cell(); + uint8_t code = static_cast(str[i] & 0xffU); if (LineChars[code]) drawLineChar(painter, x + (_fontWidth*i), y, _fontWidth, _fontHeight, code); else @@ -718,20 +722,9 @@ void TerminalDisplay::setBackgroundImage(QString backgroundImage) void TerminalDisplay::drawBackground(QPainter& painter, const QRect& rect, const QColor& backgroundColor, bool useOpacitySetting ) { - // the area of the widget showing the contents of the terminal display is drawn - // using the background color from the color scheme set with setColorTable() - // - // the area of the widget behind the scroll-bar is drawn using the background - // brush from the scroll-bar's palette, to give the effect of the scroll-bar - // being outside of the terminal display and visual consistency with other KDE - // applications. - // - QRect scrollBarArea = _scrollBar->isVisible() ? - rect.intersected(_scrollBar->geometry()) : - QRect(); - QRegion contentsRegion = QRegion(rect).subtracted(scrollBarArea); - QRect contentsRect = contentsRegion.boundingRect(); - + // The whole widget rectangle is filled by the background color from + // the color scheme set in setColorTable(), while the scrollbar is + // left to the widget style for a consistent look. if ( HAVE_TRANSPARENCY && qAlpha(_blendColor) < 0xff && useOpacitySetting ) { if (_backgroundImage.isNull()) { @@ -740,14 +733,12 @@ void TerminalDisplay::drawBackground(QPainter& painter, const QRect& rect, const painter.save(); painter.setCompositionMode(QPainter::CompositionMode_Source); - painter.fillRect(contentsRect, color); + painter.fillRect(rect, color); painter.restore(); } } else - painter.fillRect(contentsRect, backgroundColor); - - painter.fillRect(scrollBarArea,_scrollBar->palette().background()); + painter.fillRect(rect, backgroundColor); } void TerminalDisplay::drawCursor(QPainter& painter, @@ -804,7 +795,7 @@ void TerminalDisplay::drawCursor(QPainter& painter, void TerminalDisplay::drawCharacters(QPainter& painter, const QRect& rect, - const QString& text, + const std::wstring& text, const Character* style, bool invertCharacterColor) { @@ -859,12 +850,12 @@ void TerminalDisplay::drawCharacters(QPainter& painter, painter.setLayoutDirection(Qt::LeftToRight); if (_bidiEnabled) { - painter.drawText(rect.x(), rect.y() + _fontAscent + _lineSpacing, text); + painter.drawText(rect.x(), rect.y() + _fontAscent + _lineSpacing, QString::fromStdWString(text)); } else { { QRect drawRect(rect.topLeft(), rect.size()); drawRect.setHeight(rect.height() + _drawTextAdditionHeight); - painter.drawText(drawRect, Qt::AlignBottom, LTR_OVERRIDE_CHAR + text); + painter.drawText(drawRect, Qt::AlignBottom, LTR_OVERRIDE_CHAR + QString::fromStdWString(text)); } } } @@ -872,7 +863,7 @@ void TerminalDisplay::drawCharacters(QPainter& painter, void TerminalDisplay::drawTextFragment(QPainter& painter , const QRect& rect, - const QString& text, + const std::wstring& text, const Character* style) { painter.save(); @@ -1028,7 +1019,8 @@ void TerminalDisplay::scrollImage(int lines , const QRect& screenWindowRegion) QRegion TerminalDisplay::hotSpotRegion() const { QRegion region; - foreach( Filter::HotSpot* hotSpot , _filterChain->hotSpots() ) + const auto hotSpots = _filterChain->hotSpots(); + for( Filter::HotSpot* const hotSpot : hotSpots ) { QRect r; if (hotSpot->startLine()==hotSpot->endLine()) { @@ -1124,7 +1116,7 @@ void TerminalDisplay::updateImage() const int linesToUpdate = qMin(this->_lines, qMax(0,lines )); const int columnsToUpdate = qMin(this->_columns,qMax(0,columns)); - QChar *disstrU = new QChar[columnsToUpdate]; + wchar_t *disstrU = new wchar_t[columnsToUpdate]; char *dirtyMask = new char[columnsToUpdate+2]; QRegion dirtyRegion; @@ -1163,7 +1155,7 @@ void TerminalDisplay::updateImage() // where characters exceed their cell width. if (dirtyMask[x]) { - quint16 c = newLine[x+0].character; + wchar_t c = newLine[x+0].character; if ( !c ) continue; int p = 0; @@ -1194,7 +1186,7 @@ void TerminalDisplay::updateImage() disstrU[p++] = c; //fontMap(c); } - QString unistr(disstrU, p); + std::wstring unistr(disstrU, p); bool saveFixedFont = _fixedFont; if (lineDraw) @@ -1377,7 +1369,8 @@ void TerminalDisplay::paintEvent( QPaintEvent* pe ) } else { - foreach (const QRect &rect, (pe->region() & contentsRect()).rects()) + const auto rects = (pe->region() & contentsRect()).rects(); + for (const QRect &rect : rects) { drawBackground(paint,rect,palette().background().color(), true /* use opacity setting */); @@ -1411,7 +1404,7 @@ QRect TerminalDisplay::preeditRect() const void TerminalDisplay::drawInputMethodPreeditString(QPainter& painter , const QRect& rect) { - if ( _inputMethodData.preeditString.isEmpty() ) + if ( _inputMethodData.preeditString.empty() ) return; const QPoint cursorPos = cursorPosition(); @@ -1440,7 +1433,9 @@ void TerminalDisplay::paintFilters(QPainter& painter) QPoint cursorPos = mapFromGlobal(QCursor::pos()); int cursorLine; int cursorColumn; - int scrollBarWidth = (_scrollbarLocation == QTermWidget::ScrollBarLeft) ? _scrollBar->width() : 0; + int scrollBarWidth = (_scrollbarLocation == QTermWidget::ScrollBarLeft + && !_scrollBar->style()->styleHint(QStyle::SH_ScrollBar_Transient, nullptr, _scrollBar)) + ? _scrollBar->width() : 0; getCharacterPosition( cursorPos , cursorLine , cursorColumn ); Character cursorCharacter = _image[loc(cursorColumn,cursorLine)]; @@ -1578,11 +1573,11 @@ void TerminalDisplay::drawContents(QPainter &paint, const QRect &rect) int rly = qMin(_usedLines-1, qMax(0,(rect.bottom() - tLy - _topMargin ) / _fontHeight)); const int bufferSize = _usedColumns; - QString unistr; + std::wstring unistr; unistr.reserve(bufferSize); for (int y = luy; y <= rly; y++) { - quint16 c = _image[loc(lux,y)].character; + quint32 c = _image[loc(lux,y)].character; int x = lux; if(!c && x) x--; // Search for start of multi-column character @@ -1593,7 +1588,6 @@ void TerminalDisplay::drawContents(QPainter &paint, const QRect &rect) // reset our buffer to the maximal size unistr.resize(bufferSize); - QChar *disstrU = unistr.data(); // is this a single character or a sequence of characters ? if ( _image[loc(x,y)].rendition & RE_EXTENDED_CHAR ) @@ -1605,7 +1599,7 @@ void TerminalDisplay::drawContents(QPainter &paint, const QRect &rect) for ( int index = 0 ; index < extendedCharLength ; index++ ) { Q_ASSERT( p < bufferSize ); - disstrU[p++] = chars[index]; + unistr[p++] = chars[index]; } } else @@ -1615,7 +1609,7 @@ void TerminalDisplay::drawContents(QPainter &paint, const QRect &rect) if (c) { Q_ASSERT( p < bufferSize ); - disstrU[p++] = c; //fontMap(c); + unistr[p++] = c; //fontMap(c); } } @@ -1633,7 +1627,7 @@ void TerminalDisplay::drawContents(QPainter &paint, const QRect &rect) isLineChar( c = _image[loc(x+len,y)].character) == lineDraw) // Assignment! { if (c) - disstrU[p++] = c; //fontMap(c); + unistr[p++] = c; //fontMap(c); if (doubleWidth) // assert((_image[loc(x+len,y)+1].character == 0)), see above if condition len++; // Skip trailing part of multi-column character len++; @@ -1977,7 +1971,9 @@ void TerminalDisplay::mouseMoveEvent(QMouseEvent* ev) { int charLine = 0; int charColumn = 0; - int scrollBarWidth = (_scrollbarLocation == QTermWidget::ScrollBarLeft) ? _scrollBar->width() : 0; + int scrollBarWidth = (_scrollbarLocation == QTermWidget::ScrollBarLeft + && !_scrollBar->style()->styleHint(QStyle::SH_ScrollBar_Transient, nullptr, _scrollBar)) + ? _scrollBar->width() : 0; getCharacterPosition(ev->pos(),charLine,charColumn); @@ -2322,9 +2318,9 @@ void TerminalDisplay::mouseReleaseEvent(QMouseEvent* ev) // applies here, too. if (!_mouseMarks && !(ev->modifiers() & Qt::ShiftModifier)) - emit mouseSignal( 3, // release + emit mouseSignal( 0, charColumn + 1, - charLine + 1 +_scrollBar->value() -_scrollBar->maximum() , 0); + charLine + 1 +_scrollBar->value() -_scrollBar->maximum() , 2); } dragInfo.state = diNone; } @@ -2334,10 +2330,10 @@ void TerminalDisplay::mouseReleaseEvent(QMouseEvent* ev) ((ev->button() == Qt::RightButton && !(ev->modifiers() & Qt::ShiftModifier)) || ev->button() == Qt::MidButton) ) { - emit mouseSignal( 3, + emit mouseSignal( ev->button() == Qt::MidButton ? 1 : 2, charColumn + 1, charLine + 1 +_scrollBar->value() -_scrollBar->maximum() , - 0); + 2); } } @@ -2660,11 +2656,7 @@ void TerminalDisplay::emitSelection(bool useXselection,bool appendReturn) if ( ! text.isEmpty() ) { text.replace('\n', '\r'); - if ( bracketedPasteMode() ) - { - text.prepend("\e[200~"); - text.append("\e[201~"); - } + bracketText(text); QKeyEvent e(QEvent::KeyPress, 0, Qt::NoModifier, text); emit keyPressedSignal(&e); // expose as a big fat keypress event @@ -2672,6 +2664,15 @@ void TerminalDisplay::emitSelection(bool useXselection,bool appendReturn) } } +void TerminalDisplay::bracketText(QString& text) +{ + if (bracketedPasteMode()) + { + text.prepend("\033[200~"); + text.append("\033[201~"); + } +} + void TerminalDisplay::setSelection(const QString& t) { QApplication::clipboard()->setText(t, QClipboard::Selection); @@ -2817,7 +2818,7 @@ void TerminalDisplay::inputMethodEvent( QInputMethodEvent* event ) QKeyEvent keyEvent(QEvent::KeyPress,0,Qt::NoModifier,event->commitString()); emit keyPressedSignal(&keyEvent); - _inputMethodData.preeditString = event->preeditString(); + _inputMethodData.preeditString = event->preeditString().toStdWString(); update(preeditRect() | _inputMethodData.previousPreeditRect); event->accept(); @@ -2996,6 +2997,8 @@ void TerminalDisplay::clearImage() void TerminalDisplay::calcGeometry() { _scrollBar->resize(_scrollBar->sizeHint().width(), contentsRect().height()); + int scrollBarWidth = _scrollBar->style()->styleHint(QStyle::SH_ScrollBar_Transient, nullptr, _scrollBar) + ? 0 : _scrollBar->width(); switch(_scrollbarLocation) { case QTermWidget::NoScrollBar : @@ -3003,14 +3006,14 @@ void TerminalDisplay::calcGeometry() _contentWidth = contentsRect().width() - 2 * DEFAULT_LEFT_MARGIN; break; case QTermWidget::ScrollBarLeft : - _leftMargin = DEFAULT_LEFT_MARGIN + _scrollBar->width(); - _contentWidth = contentsRect().width() - 2 * DEFAULT_LEFT_MARGIN - _scrollBar->width(); + _leftMargin = DEFAULT_LEFT_MARGIN + scrollBarWidth; + _contentWidth = contentsRect().width() - 2 * DEFAULT_LEFT_MARGIN - scrollBarWidth; _scrollBar->move(contentsRect().topLeft()); break; case QTermWidget::ScrollBarRight: _leftMargin = DEFAULT_LEFT_MARGIN; - _contentWidth = contentsRect().width() - 2 * DEFAULT_LEFT_MARGIN - _scrollBar->width(); - _scrollBar->move(contentsRect().topRight() - QPoint(_scrollBar->width()-1,0)); + _contentWidth = contentsRect().width() - 2 * DEFAULT_LEFT_MARGIN - scrollBarWidth; + _scrollBar->move(contentsRect().topRight() - QPoint(_scrollBar->width()-1, 0)); break; } @@ -3050,7 +3053,9 @@ void TerminalDisplay::makeImage() // calculate the needed size, this must be synced with calcGeometry() void TerminalDisplay::setSize(int columns, int lines) { - int scrollBarWidth = _scrollBar->isHidden() ? 0 : _scrollBar->sizeHint().width(); + int scrollBarWidth = (_scrollBar->isHidden() + || _scrollBar->style()->styleHint(QStyle::SH_ScrollBar_Transient, nullptr, _scrollBar)) + ? 0 : _scrollBar->sizeHint().width(); int horizontalMargin = 2 * DEFAULT_LEFT_MARGIN; int verticalMargin = 2 * DEFAULT_TOP_MARGIN; diff --git a/lib/TerminalDisplay.h b/lib/TerminalDisplay.h index ea0dc27..9498de9 100644 --- a/lib/TerminalDisplay.h +++ b/lib/TerminalDisplay.h @@ -192,6 +192,9 @@ public: void emitSelection(bool useXselection,bool appendReturn); + /** change and wrap text corresponding to paste mode **/ + void bracketText(QString& text); + /** * Sets the shape of the keyboard cursor. This is the cursor drawn * at the position in the terminal where keyboard input will appear. @@ -630,7 +633,7 @@ private: // draws a section of text, all the text in this section // has a common color and style void drawTextFragment(QPainter& painter, const QRect& rect, - const QString& text, const Character* style); + const std::wstring& text, const Character* style); // draws the background for a text fragment // if useOpacitySetting is true then the color's alpha value will be set to // the display's transparency (set with setOpacity()), otherwise the background @@ -641,11 +644,11 @@ private: void drawCursor(QPainter& painter, const QRect& rect , const QColor& foregroundColor, const QColor& backgroundColor , bool& invertColors); // draws the characters or line graphics in a text fragment - void drawCharacters(QPainter& painter, const QRect& rect, const QString& text, + void drawCharacters(QPainter& painter, const QRect& rect, const std::wstring& text, const Character* style, bool invertCharacterColor); // draws a string of line graphics void drawLineCharString(QPainter& painter, int x, int y, - const QString& str, const Character* attributes); + const std::wstring& str, const Character* attributes); // draws the preedit string for input methods void drawInputMethodPreeditString(QPainter& painter , const QRect& rect); @@ -808,7 +811,7 @@ private: struct InputMethodData { - QString preeditString; + std::wstring preeditString; QRect previousPreeditRect; }; InputMethodData _inputMethodData; diff --git a/lib/Vt102Emulation.cpp b/lib/Vt102Emulation.cpp index 077ad9f..be5a886 100644 --- a/lib/Vt102Emulation.cpp +++ b/lib/Vt102Emulation.cpp @@ -198,7 +198,7 @@ void Vt102Emulation::addArgument() argv[argc] = 0; } -void Vt102Emulation::addToCurrentToken(int cc) +void Vt102Emulation::addToCurrentToken(wchar_t cc) { tokenBuffer[tokenBufferPos] = cc; tokenBufferPos = qMin(tokenBufferPos+1,MAX_TOKEN_LENGTH-1); @@ -277,7 +277,7 @@ void Vt102Emulation::initTokenizer() #define DEL 127 // process an incoming unicode character -void Vt102Emulation::receiveChar(int cc) +void Vt102Emulation::receiveChar(wchar_t cc) { if (cc == DEL) return; //VT100: ignore. @@ -299,7 +299,7 @@ void Vt102Emulation::receiveChar(int cc) // advance the state addToCurrentToken(cc); - int* s = tokenBuffer; + wchar_t* s = tokenBuffer; int p = tokenBufferPos; if (getMode(MODE_Ansi)) @@ -441,7 +441,7 @@ void Vt102Emulation::updateTitle() about this mapping. */ -void Vt102Emulation::processToken(int token, int p, int q) +void Vt102Emulation::processToken(int token, wchar_t p, int q) { switch (token) { @@ -922,17 +922,22 @@ void Vt102Emulation::reportAnswerBack() void Vt102Emulation::sendMouseEvent( int cb, int cx, int cy , int eventType ) { - if (cx < 1 || cy < 1) - return; + if (cx < 1 || cy < 1) + return; + + // With the exception of the 1006 mode, button release is encoded in cb. + // Note that if multiple extensions are enabled, the 1006 is used, so it's okay to check for only that. + if (eventType == 2 && !getMode(MODE_Mouse1006)) + cb = 3; - // normal buttons are passed as 0x20 + button, - // mouse wheel (buttons 4,5) as 0x5c + button - if (cb >= 4) - cb += 0x3c; + // normal buttons are passed as 0x20 + button, + // mouse wheel (buttons 4,5) as 0x5c + button + if (cb >= 4) + cb += 0x3c; - //Mouse motion handling - if ((getMode(MODE_Mouse1002) || getMode(MODE_Mouse1003)) && eventType == 1) - cb += 0x20; //add 32 to signify motion event + //Mouse motion handling + if ((getMode(MODE_Mouse1002) || getMode(MODE_Mouse1003)) && eventType == 1) + cb += 0x20; //add 32 to signify motion event char command[32]; command[0] = '\0'; @@ -1125,7 +1130,7 @@ void Vt102Emulation::sendKeyEvent( QKeyEvent* event ) // Apply current character map. -unsigned short Vt102Emulation::applyCharset(unsigned short c) +wchar_t Vt102Emulation::applyCharset(wchar_t c) { if (CHARSET.graphic && 0x5f <= c && c <= 0x7e) return vt100_graphics[c-0x5f]; if (CHARSET.pound && c == '#' ) return 0xa3; //This mode is obsolete @@ -1336,7 +1341,7 @@ char Vt102Emulation::eraseChar() const } // print contents of the scan buffer -static void hexdump(int* s, int len) +static void hexdump(wchar_t* s, int len) { int i; for (i = 0; i < len; i++) { diff --git a/lib/Vt102Emulation.h b/lib/Vt102Emulation.h index 22a9104..02b865b 100644 --- a/lib/Vt102Emulation.h +++ b/lib/Vt102Emulation.h @@ -102,7 +102,7 @@ protected: // reimplemented from Emulation virtual void setMode(int mode); virtual void resetMode(int mode); - virtual void receiveChar(int cc); + virtual void receiveChar(wchar_t cc); private slots: //causes changeTitle() to be emitted for each (int,QString) pair in pendingTitleUpdates @@ -110,7 +110,7 @@ private slots: void updateTitle(); private: - unsigned short applyCharset(unsigned short c); + wchar_t applyCharset(wchar_t c); void setCharset(int n, int cs); void useCharset(int n); void setAndUseCharset(int n, int cs); @@ -134,8 +134,8 @@ private: void resetTokenizer(); #define MAX_TOKEN_LENGTH 256 // Max length of tokens (e.g. window title) - void addToCurrentToken(int cc); - int tokenBuffer[MAX_TOKEN_LENGTH]; //FIXME: overflow? + void addToCurrentToken(wchar_t cc); + wchar_t tokenBuffer[MAX_TOKEN_LENGTH]; //FIXME: overflow? int tokenBufferPos; #define MAXARGS 15 void addDigit(int dig); @@ -151,7 +151,7 @@ private: void reportDecodingError(); - void processToken(int code, int p, int q); + void processToken(int code, wchar_t p, int q); void processWindowAttributeChange(); void requestWindowAttribute(int); diff --git a/lib/color-schemes/Tango.colorscheme b/lib/color-schemes/Tango.colorscheme new file mode 100644 index 0000000..0a23d4c --- /dev/null +++ b/lib/color-schemes/Tango.colorscheme @@ -0,0 +1,71 @@ +[General] +Description=Tango + +[Background] +Color=0,0,0 + +[BackgroundIntense] +Color=104,104,104 + +[Foreground] +;Color=211,215,207 +Color=255,255,255 + +[ForegroundIntense] +Color=255,255,255 + +; black +[Color0] +Color=0,0,0 + +[Color0Intense] +Color=85,87,83 + +; red +[Color1] +Color=204,0,0 + +[Color1Intense] +Color=239,41,41 + +; green +[Color2] +Color=78,154,6 + +[Color2Intense] +Color=138,226,52 + +; yellow +[Color3] +Color=196,160,0 + +[Color3Intense] +Color=252,233,79 + +; blue +[Color4] +Color=52,101,164 + +[Color4Intense] +Color=114,159,207 + +; magenta +[Color5] +Color=117,80,123 + +[Color5Intense] +Color=173,127,168 + +; aqua +[Color6] +Color=6,152,154 + +[Color6Intense] +Color=52,226,226 + +; grey +[Color7] +Color=211,215,207 + +[Color7Intense] +Color=238,238,236 diff --git a/lib/color-schemes/Ubuntu.colorscheme b/lib/color-schemes/Ubuntu.colorscheme new file mode 100644 index 0000000..3652506 --- /dev/null +++ b/lib/color-schemes/Ubuntu.colorscheme @@ -0,0 +1,67 @@ +[General] +Description=Ubuntu +Opacity=1 +Wallpaper= + +[Background] +Color=48,10,36 +MaxRandomHue=0 +MaxRandomSaturation=0 +MaxRandomValue=0 + +[BackgroundIntense] +Color=48,10,36 + +[Color0] +Color=46,52,54 + +[Color0Intense] +Color=85,87,83 + +[Color1] +Color=204,0,0 + +[Color1Intense] +Color=239,41,41 + +[Color2] +Color=78,154,6 + +[Color2Intense] +Color=138,226,52 + +[Color3] +Color=196,160,0 + +[Color3Intense] +Color=252,233,79 + +[Color4] +Color=52,101,164 + +[Color4Intense] +Color=114,159,207 + +[Color5] +Color=117,80,123 + +[Color5Intense] +Color=173,127,168 + +[Color6] +Color=6,152,154 + +[Color6Intense] +Color=52,226,226 + +[Color7] +Color=211,215,207 + +[Color7Intense] +Color=238,238,236 + +[Foreground] +Color=238,238,236 + +[ForegroundIntense] +Color=238,238,236 \ No newline at end of file diff --git a/lib/konsole_wcwidth.cpp b/lib/konsole_wcwidth.cpp index 64dbdac..cfb6c07 100644 --- a/lib/konsole_wcwidth.cpp +++ b/lib/konsole_wcwidth.cpp @@ -33,10 +33,9 @@ int konsole_wcwidth(wchar_t ucs) } // single byte char: +1, multi byte char: +2 -int string_width( const QString & txt ) +int string_width( const std::wstring & wstr ) { int w = 0; - std::wstring wstr = txt.toStdWString(); for ( size_t i = 0; i < wstr.length(); ++i ) { w += konsole_wcwidth( wstr[ i ] ); } diff --git a/lib/konsole_wcwidth.h b/lib/konsole_wcwidth.h index fdc2324..32aa882 100644 --- a/lib/konsole_wcwidth.h +++ b/lib/konsole_wcwidth.h @@ -10,11 +10,11 @@ #ifndef _KONSOLE_WCWIDTH_H_ #define _KONSOLE_WCWIDTH_H_ -// Qt -class QString; +// Standard +#include int konsole_wcwidth(wchar_t ucs); -int string_width( const QString & txt ); +int string_width( const std::wstring & wstr ); #endif diff --git a/lib/kptyprocess.cpp b/lib/kptyprocess.cpp index 078770b..f9a9672 100644 --- a/lib/kptyprocess.cpp +++ b/lib/kptyprocess.cpp @@ -34,6 +34,8 @@ #include #include +#include +#include KPtyProcess::KPtyProcess(QObject *parent) : KProcess(new KPtyProcessPrivate, parent) @@ -61,10 +63,20 @@ KPtyProcess::~KPtyProcess() { Q_D(KPtyProcess); - if (state() != QProcess::NotRunning && d->addUtmp) { - d->pty->logout(); - disconnect(SIGNAL(stateChanged(QProcess::ProcessState)), - this, SLOT(_k_onStateChanged(QProcess::ProcessState))); + if (state() != QProcess::NotRunning) + { + if (d->addUtmp) + { + d->pty->logout(); + disconnect(SIGNAL(stateChanged(QProcess::ProcessState)), + this, SLOT(_k_onStateChanged(QProcess::ProcessState))); + } + + qWarning() << Q_FUNC_INFO << "the terminal process is still running, trying to stop it by SIGHUP"; + ::kill(pid(), SIGHUP); + waitForFinished(300); + if (state() != QProcess::NotRunning) + qCritical() << Q_FUNC_INFO << "process didn't stop upon SIGHUP and will be SIGKILL-ed"; } delete d->pty; } diff --git a/lib/qtermwidget.cpp b/lib/qtermwidget.cpp index e3fa23d..c389acc 100644 --- a/lib/qtermwidget.cpp +++ b/lib/qtermwidget.cpp @@ -219,6 +219,20 @@ QSize QTermWidget::sizeHint() const return size; } +void QTermWidget::setTerminalSizeHint(bool on) +{ + if (!m_impl->m_terminalDisplay) + return; + m_impl->m_terminalDisplay->setTerminalSizeHint(on); +} + +bool QTermWidget::terminalSizeHint() +{ + if (!m_impl->m_terminalDisplay) + return true; + return m_impl->m_terminalDisplay->terminalSizeHint(); +} + void QTermWidget::startShellProgram() { if ( m_impl->m_session->isRunning() ) { @@ -460,7 +474,8 @@ void QTermWidget::setColorScheme(const QString& origName) QStringList QTermWidget::availableColorSchemes() { QStringList ret; - foreach (const ColorScheme* cs, ColorSchemeManager::instance()->allColorSchemes()) + const auto allColorSchemes = ColorSchemeManager::instance()->allColorSchemes(); + for (const ColorScheme* cs : allColorSchemes) ret.append(cs->name()); return ret; } @@ -516,6 +531,11 @@ void QTermWidget::sessionFinished() emit finished(); } +void QTermWidget::bracketText(QString& text) +{ + m_impl->m_terminalDisplay->bracketText(text); +} + void QTermWidget::copyClipboard() { m_impl->m_terminalDisplay->copyClipboard(); @@ -698,6 +718,20 @@ void QTermWidget::setBlinkingCursor(bool blink) m_impl->m_terminalDisplay->setBlinkingCursor(blink); } +void QTermWidget::setBidiEnabled(bool enabled) +{ + if (!m_impl->m_terminalDisplay) + return; + m_impl->m_terminalDisplay->setBidiEnabled(enabled); +} + +bool QTermWidget::isBidiEnabled() +{ + if (!m_impl->m_terminalDisplay) + return false; // Default value + return m_impl->m_terminalDisplay->isBidiEnabled(); +} + QString QTermWidget::title() const { QString title = m_impl->m_session->userTitle(); diff --git a/lib/qtermwidget.h b/lib/qtermwidget.h index ce10c45..04c84b4 100644 --- a/lib/qtermwidget.h +++ b/lib/qtermwidget.h @@ -60,6 +60,10 @@ public: //Initial size QSize sizeHint() const; + // expose TerminalDisplay::TerminalSizeHint, setTerminalSizeHint + void setTerminalSizeHint(bool on); + bool terminalSizeHint(); + //start shell program if it was not started in constructor void startShellProgram(); @@ -199,6 +203,9 @@ public: void setBlinkingCursor(bool blink); + /** Enables or disables bidi text in the terminal. */ + void setBidiEnabled(bool enabled); + bool isBidiEnabled(); /** * Automatically close the terminal session after the shell process exits or @@ -212,6 +219,8 @@ public: /** True if the title() or icon() was (ever) changed by the session. */ bool isTitleChanged() const; + /** change and wrap text corresponding to paste mode **/ + void bracketText(QString& text); signals: void finished(); void copyAvailable(bool); diff --git a/pyqt/CMakeLists.txt b/pyqt/CMakeLists.txt new file mode 100644 index 0000000..3ebaf5e --- /dev/null +++ b/pyqt/CMakeLists.txt @@ -0,0 +1,61 @@ +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake) + +# Match what's used in the main macros +cmake_policy(SET CMP0002 OLD) +find_package(PythonLibrary) + +include(PythonMacros) + +find_package(SIP) +include(SIPMacros) + +if(SIP_VERSION STRLESS "040f03") # These version numbers also appear in ../CMakeLists.txt + message(FATAL_ERROR "The version of SIP found is too old. 4.15.3 or later is needed.") +endif() + +find_package(PyQt5) +if(PYQT5_VERSION STRLESS "050101") # These version numbers also appear in ../CMakeLists.txt + message(FATAL_ERROR "The version of PyQt found is too old. 5.1.1 or later is required.") +endif() + +set(SIP_INCLUDES ${PYQT5_SIP_DIR} sip) +set(SIP_CONCAT_PARTS 8) +set(SIP_TAGS ALL WS_X11 ${PYQT5_VERSION_TAG}) +set(SIP_DISABLE_FEATURES VendorID PyQt_NoPrintRangeBug) + +# Use an extra option when compiling on Python 3. +if (PYTHON_VERSION_MAJOR GREATER 2) + if(PYQT5_VERSION STRGREATER "040904") + # Disable for newer PyQt + set(SIP_EXTRA_OPTIONS -P -g) + else () + set(SIP_EXTRA_OPTIONS -g) + endif() +else (PYTHON_VERSION_MAJOR GREATER 2) + if(PYQT5_VERSION STRGREATER "040904") + # Disable for newer PyQt + set(SIP_EXTRA_OPTIONS -P -g -x Py_v3) + else () + set(SIP_EXTRA_OPTIONS -g -x Py_v3) + endif() +endif () + +include_directories( + "${SIP_INCLUDE_DIR}" +) + +add_definitions(-D_REENTRANT -DSIP_PROTECTED_IS_PUBLIC -Dprotected=public) + +file(GLOB qtermwidget_files_sip sip/*.sip) +set(SIP_EXTRA_FILES_DEPEND "${qtermwidget_files_sip}") +add_sip_python_module(QTermWidget sip/qtermwidget.sip qtermwidget5) + +python_install(__init__.py "${PYTHON_SITE_PACKAGES_INSTALL_DIR}/PyQt5/qtermwidget") + +set (SIP_FILES_INSTALL_DIR "${CMAKE_INSTALL_DATAROOTDIR}/sip") + +install(DIRECTORY sip/ DESTINATION "${SIP_FILES_INSTALL_DIR}/PyQt5/qtermwidget" + PATTERN "*~" EXCLUDE # This sucks, why can't I just whitelist what I _do_ want? + PATTERN ".svn" EXCLUDE + PATTERN "*.in" EXCLUDE +) diff --git a/pyqt/README.md b/pyqt/README.md deleted file mode 100644 index 4f45e97..0000000 --- a/pyqt/README.md +++ /dev/null @@ -1,36 +0,0 @@ -PyQt5 Bindings for QTermWidget -============================== - - -INSTALL: ------------- - -####1. Download, compile and install QTermWidget: - $ git clone https://github.com/lxde/qtermwidget.git - $ cd qtermwidget && mkdir build && cd build - $ cmake .. - $ make - $ sudo make install -If `make install` command will not work just copy the `qtermwidget.so*` files to /usr/lib directory. -####2. Install PyQt5 and PyQt5-devel if not yet installed. -####3. Configure, compile and install Python bindings. Execute in terminal in the qtermwidget bindings folder: - $ cd pyqt/ - $ QT_SELECT=5 python config.py - $ make - $ sudo make install - -####4. You can run ./test.py to test the installed module. - - -ABOUT: ---------- -Curently maintained by: -- Pawel Koston - -Based on previous PyQt4 bindings by: -- Piotr "Riklaunim" Maliński , -- Alexander Slesarev - -PyQt5 QTermWidget Bindings -License: GPL3 - diff --git a/pyqt/config.py.in b/pyqt/__init__.py similarity index 100% rename from pyqt/config.py.in rename to pyqt/__init__.py diff --git a/pyqt/cmake/COPYING-CMAKE-SCRIPTS b/pyqt/cmake/COPYING-CMAKE-SCRIPTS new file mode 100644 index 0000000..6fc1e7e --- /dev/null +++ b/pyqt/cmake/COPYING-CMAKE-SCRIPTS @@ -0,0 +1,22 @@ + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/pyqt/cmake/FindPyQt5.cmake b/pyqt/cmake/FindPyQt5.cmake new file mode 100644 index 0000000..b4a52e1 --- /dev/null +++ b/pyqt/cmake/FindPyQt5.cmake @@ -0,0 +1,53 @@ +# Find PyQt5 +# ~~~~~~~~~~ +# Copyright (c) 2014, Simon Edwards +# Redistribution and use is allowed according to the terms of the BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. +# +# PyQt5 website: http://www.riverbankcomputing.co.uk/pyqt/index.php +# +# Find the installed version of PyQt5. FindPyQt5 should only be called after +# Python has been found. +# +# This file defines the following variables: +# +# PYQT5_VERSION - The version of PyQt5 found expressed as a 6 digit hex number +# suitable for comparison as a string +# +# PYQT5_VERSION_STR - The version of PyQt5 as a human readable string. +# +# PYQT5_VERSION_TAG - The PyQt version tag using by PyQt's sip files. +# +# PYQT5_SIP_DIR - The directory holding the PyQt5 .sip files. +# +# PYQT5_SIP_FLAGS - The SIP flags used to build PyQt. + +IF(EXISTS PYQT5_VERSION) + # Already in cache, be silent + SET(PYQT5_FOUND TRUE) +ELSE(EXISTS PYQT5_VERSION) + + FIND_FILE(_find_pyqt5_py FindPyQt5.py PATHS ${CMAKE_MODULE_PATH}) + + EXECUTE_PROCESS(COMMAND ${PYTHON_EXECUTABLE} ${_find_pyqt5_py} OUTPUT_VARIABLE pyqt5_config) + IF(pyqt5_config) + STRING(REGEX REPLACE "^pyqt_version:([^\n]+).*$" "\\1" PYQT5_VERSION ${pyqt5_config}) + STRING(REGEX REPLACE ".*\npyqt_version_str:([^\n]+).*$" "\\1" PYQT5_VERSION_STR ${pyqt5_config}) + STRING(REGEX REPLACE ".*\npyqt_version_tag:([^\n]+).*$" "\\1" PYQT5_VERSION_TAG ${pyqt5_config}) + STRING(REGEX REPLACE ".*\npyqt_sip_dir:([^\n]+).*$" "\\1" PYQT5_SIP_DIR ${pyqt5_config}) + STRING(REGEX REPLACE ".*\npyqt_sip_flags:([^\n]+).*$" "\\1" PYQT5_SIP_FLAGS ${pyqt5_config}) + + SET(PYQT5_FOUND TRUE) + ENDIF(pyqt5_config) + + IF(PYQT5_FOUND) + IF(NOT PYQT5_FIND_QUIETLY) + MESSAGE(STATUS "Found PyQt5 version: ${PYQT5_VERSION_STR}") + ENDIF(NOT PYQT5_FIND_QUIETLY) + ELSE(PYQT5_FOUND) + IF(PYQT5_FIND_REQUIRED) + MESSAGE(FATAL_ERROR "Could not find PyQt5.") + ENDIF(PYQT5_FIND_REQUIRED) + ENDIF(PYQT5_FOUND) + +ENDIF(EXISTS PYQT5_VERSION) diff --git a/pyqt/cmake/FindPyQt5.py b/pyqt/cmake/FindPyQt5.py new file mode 100644 index 0000000..318b9a3 --- /dev/null +++ b/pyqt/cmake/FindPyQt5.py @@ -0,0 +1,28 @@ +# Copyright (c) 2014, Simon Edwards +# Redistribution and use is allowed according to the terms of the BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. + +import PyQt5.Qt +import sys +import os.path + +print("pyqt_version:%06.0x" % PyQt5.Qt.PYQT_VERSION) +print("pyqt_version_str:%s" % PyQt5.Qt.PYQT_VERSION_STR) + +pyqt_version_tag = "" +in_t = False +for item in PyQt5.Qt.PYQT_CONFIGURATION["sip_flags"].split(' '): + if item=="-t": + in_t = True + elif in_t: + if item.startswith("Qt_5"): + pyqt_version_tag = item + else: + in_t = False +print("pyqt_version_tag:%s" % pyqt_version_tag) + +# FIXME This next line is just a little bit too crude. +pyqt_sip_dir = os.path.join(sys.prefix, "share", "sip", "PyQt5") +print("pyqt_sip_dir:%s" % pyqt_sip_dir) + +print("pyqt_sip_flags:%s" % PyQt5.Qt.PYQT_CONFIGURATION["sip_flags"]) diff --git a/pyqt/cmake/FindPythonLibrary.cmake b/pyqt/cmake/FindPythonLibrary.cmake new file mode 100644 index 0000000..78309b7 --- /dev/null +++ b/pyqt/cmake/FindPythonLibrary.cmake @@ -0,0 +1,73 @@ +# Find Python +# ~~~~~~~~~~~ +# Find the Python interpreter and related Python directories. +# +# This file defines the following variables: +# +# PYTHON_EXECUTABLE - The path and filename of the Python interpreter. +# +# PYTHON_SHORT_VERSION - The version of the Python interpreter found, +# excluding the patch version number. (e.g. 2.5 and not 2.5.1)) +# +# PYTHON_LONG_VERSION - The version of the Python interpreter found as a human +# readable string. +# +# PYTHON_SITE_PACKAGES_INSTALL_DIR - this cache variable can be used for installing +# own python modules. You may want to adjust this to be the +# same as ${PYTHON_SITE_PACKAGES_DIR}, but then admin +# privileges may be required for installation. +# +# PYTHON_SITE_PACKAGES_DIR - Location of the Python site-packages directory. +# +# PYTHON_INCLUDE_PATH - Directory holding the python.h include file. +# +# PYTHON_LIBRARY, PYTHON_LIBRARIES- Location of the Python library. + +# Copyright (c) 2007, Simon Edwards +# Copyright (c) 2012, Luca Beltrame +# Redistribution and use is allowed according to the terms of the BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. + +include(FindPackageHandleStandardArgs) + +find_package(PythonInterp) + +if (PYTHONINTERP_FOUND) + + option(INSTALL_PYTHON_FILES_IN_PYTHON_PREFIX "Install the Python files in the Python packages dir" FALSE) + + # Set the Python libraries to what we actually found for interpreters + set(Python_ADDITIONAL_VERSIONS "${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}") + # These are kept for compatibility + set(PYTHON_SHORT_VERSION "${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}") + set(PYTHON_LONG_VERSION ${PYTHON_VERSION_STRING}) + + find_package(PythonLibs QUIET) + + if(PYTHONLIBS_FOUND) + set(PYTHON_LIBRARY ${PYTHON_LIBRARIES}) + endif(PYTHONLIBS_FOUND) + + # Auto detect Python site-packages directory + execute_process(COMMAND ${PYTHON_EXECUTABLE} -c "from distutils.sysconfig import get_python_lib; print(get_python_lib(True))" + OUTPUT_VARIABLE PYTHON_SITE_PACKAGES_DIR + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + + message(STATUS "Python system site-packages directory: ${PYTHON_SITE_PACKAGES_DIR}") + if(INSTALL_PYTHON_FILES_IN_PYTHON_PREFIX) + set(PYTHON_SITE_PACKAGES_INSTALL_DIR ${PYTHON_SITE_PACKAGES_DIR}) + else() + execute_process(COMMAND ${PYTHON_EXECUTABLE} -c "from distutils.sysconfig import get_python_lib; print(get_python_lib(True, prefix='${CMAKE_INSTALL_PREFIX}'))" + OUTPUT_VARIABLE PYTHON_SITE_PACKAGES_INSTALL_DIR + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + endif() + + if(NOT PYTHON_SITE_PACKAGES_INSTALL_DIR STREQUAL PYTHON_SITE_PACKAGES_DIR) + message(STATUS "The Python files will be installed to ${PYTHON_SITE_PACKAGES_INSTALL_DIR}. Make sure to add them to the Python search path (e.g. by setting PYTHONPATH)") + endif() + +endif(PYTHONINTERP_FOUND) + +find_package_handle_standard_args(PythonLibrary DEFAULT_MSG PYTHON_LIBRARY) diff --git a/pyqt/cmake/FindSIP.cmake b/pyqt/cmake/FindSIP.cmake new file mode 100644 index 0000000..954e50d --- /dev/null +++ b/pyqt/cmake/FindSIP.cmake @@ -0,0 +1,64 @@ +# Find SIP +# ~~~~~~~~ +# +# SIP website: http://www.riverbankcomputing.co.uk/sip/index.php +# +# Find the installed version of SIP. FindSIP should be called after Python +# has been found. +# +# This file defines the following variables: +# +# SIP_VERSION - The version of SIP found expressed as a 6 digit hex number +# suitable for comparison as a string. +# +# SIP_VERSION_STR - The version of SIP found as a human readable string. +# +# SIP_EXECUTABLE - Path and filename of the SIP command line executable. +# +# SIP_INCLUDE_DIR - Directory holding the SIP C++ header file. +# +# SIP_DEFAULT_SIP_DIR - Default directory where .sip files should be installed +# into. + +# Copyright (c) 2007, Simon Edwards +# Redistribution and use is allowed according to the terms of the BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. + + + +IF(SIP_VERSION) + # Already in cache, be silent + SET(SIP_FOUND TRUE) +ELSE(SIP_VERSION) + + FIND_FILE(_find_sip_py FindSIP.py PATHS ${CMAKE_MODULE_PATH}) + + EXECUTE_PROCESS(COMMAND ${PYTHON_EXECUTABLE} ${_find_sip_py} OUTPUT_VARIABLE sip_config) + IF(sip_config) + STRING(REGEX REPLACE "^sip_version:([^\n]+).*$" "\\1" SIP_VERSION ${sip_config}) + STRING(REGEX REPLACE ".*\nsip_version_str:([^\n]+).*$" "\\1" SIP_VERSION_STR ${sip_config}) + STRING(REGEX REPLACE ".*\nsip_bin:([^\n]+).*$" "\\1" SIP_EXECUTABLE ${sip_config}) + IF(NOT SIP_DEFAULT_SIP_DIR) + STRING(REGEX REPLACE ".*\ndefault_sip_dir:([^\n]+).*$" "\\1" SIP_DEFAULT_SIP_DIR ${sip_config}) + ENDIF(NOT SIP_DEFAULT_SIP_DIR) + STRING(REGEX REPLACE ".*\nsip_inc_dir:([^\n]+).*$" "\\1" SIP_INCLUDE_DIR ${sip_config}) + FILE(TO_CMAKE_PATH ${SIP_DEFAULT_SIP_DIR} SIP_DEFAULT_SIP_DIR) + FILE(TO_CMAKE_PATH ${SIP_INCLUDE_DIR} SIP_INCLUDE_DIR) + IF(EXISTS ${SIP_EXECUTABLE}) + SET(SIP_FOUND TRUE) + ELSE() + MESSAGE(STATUS "Found SIP configuration but the sip executable could not be found.") + ENDIF() + ENDIF(sip_config) + + IF(SIP_FOUND) + IF(NOT SIP_FIND_QUIETLY) + MESSAGE(STATUS "Found SIP version: ${SIP_VERSION_STR}") + ENDIF(NOT SIP_FIND_QUIETLY) + ELSE(SIP_FOUND) + IF(SIP_FIND_REQUIRED) + MESSAGE(FATAL_ERROR "Could not find SIP") + ENDIF(SIP_FIND_REQUIRED) + ENDIF(SIP_FOUND) + +ENDIF(SIP_VERSION) diff --git a/pyqt/cmake/FindSIP.py b/pyqt/cmake/FindSIP.py new file mode 100644 index 0000000..ecb734f --- /dev/null +++ b/pyqt/cmake/FindSIP.py @@ -0,0 +1,15 @@ +# FindSIP.py +# +# Copyright (c) 2007, Simon Edwards +# Redistribution and use is allowed according to the terms of the BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. + +import sys +import sipconfig + +sipcfg = sipconfig.Configuration() +print("sip_version:%06.0x" % sipcfg.sip_version) +print("sip_version_str:%s" % sipcfg.sip_version_str) +print("sip_bin:%s" % sipcfg.sip_bin) +print("default_sip_dir:%s" % sipcfg.default_sip_dir) +print("sip_inc_dir:%s" % sipcfg.sip_inc_dir) diff --git a/pyqt/cmake/PythonCompile.py b/pyqt/cmake/PythonCompile.py new file mode 100644 index 0000000..156fea2 --- /dev/null +++ b/pyqt/cmake/PythonCompile.py @@ -0,0 +1,4 @@ +# By Simon Edwards +# This file is in the public domain. +import py_compile, sys +sys.exit(py_compile.main()) diff --git a/pyqt/cmake/PythonMacros.cmake b/pyqt/cmake/PythonMacros.cmake new file mode 100644 index 0000000..6a82d88 --- /dev/null +++ b/pyqt/cmake/PythonMacros.cmake @@ -0,0 +1,82 @@ +# Python macros +# ~~~~~~~~~~~~~ +# Copyright (c) 2007, Simon Edwards +# Copyright (c) 2012, Luca Beltrame +# Copyright (c) 2012, Rolf Eike Beer +# +# Redistribution and use is allowed according to the terms of the BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. +# +# This file defines the following macros: +# +# PYTHON_INSTALL (SOURCE_FILE DESTINATION_DIR) +# Install the SOURCE_FILE, which is a Python .py file, into the +# destination directory during install. The file will be byte compiled +# and both the .py file and .pyc file will be installed. + +set(PYTHON_MACROS_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}) + +macro(PYTHON_INSTALL SOURCE_FILE DESTINATION_DIR) + + find_file(_python_compile_py PythonCompile.py PATHS ${CMAKE_MODULE_PATH}) + + # Install the source file. + install(FILES ${SOURCE_FILE} DESTINATION ${DESTINATION_DIR}) + + # Byte compile and install the .pyc file, unless explicitly prevented by env.. + if("$ENV{PYTHONDONTWRITEBYTECODE}" STREQUAL "") + get_filename_component(_absfilename ${SOURCE_FILE} ABSOLUTE) + get_filename_component(_filename ${SOURCE_FILE} NAME) + get_filename_component(_filenamebase ${SOURCE_FILE} NAME_WE) + get_filename_component(_basepath ${SOURCE_FILE} PATH) + + if(WIN32) + # remove drive letter + string(REGEX REPLACE "^[a-zA-Z]:/" "/" _basepath "${_basepath}") + endif(WIN32) + + set(_bin_py ${CMAKE_CURRENT_BINARY_DIR}/${_basepath}/${_filename}) + + # Python 3.2 changed the pyc file location + if(PYTHON_VERSION_STRING VERSION_GREATER 3.1) + # To get the right version for suffix + set(_bin_pyc "${CMAKE_CURRENT_BINARY_DIR}/${_basepath}/__pycache__/${_filenamebase}.cpython-${PYTHON_VERSION_MAJOR}${PYTHON_VERSION_MINOR}.pyc") + set(_py_install_dir "${DESTINATION_DIR}/__pycache__/") + else() + set(_bin_pyc "${CMAKE_CURRENT_BINARY_DIR}/${_basepath}/${_filenamebase}.pyc") + set(_py_install_dir "${DESTINATION_DIR}") + endif() + + file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${_basepath}) + + # Setting because it will be displayed later, in compile_python_files + set(_message "Byte-compiling ${_bin_py} to ${_bin_pyc}") + + string(REPLACE "/" "_" _rule_name "${_basepath}/${_bin_pyc}") + add_custom_target("${_rule_name}" ALL) + + get_filename_component(_abs_bin_py ${_bin_py} ABSOLUTE) + if(_abs_bin_py STREQUAL _absfilename) # Don't copy the file onto itself. + add_custom_command( + TARGET "${_rule_name}" + COMMAND "${CMAKE_COMMAND}" -E echo "${_message}" + COMMAND "${PYTHON_EXECUTABLE}" "${_python_compile_py}" "${_bin_py}" + DEPENDS "${_absfilename}" + ) + else() + add_custom_command( + TARGET "${_rule_name}" + COMMAND "${CMAKE_COMMAND}" -E echo "${_message}" + COMMAND "${CMAKE_COMMAND}" -E copy "${_absfilename}" "${_bin_py}" + COMMAND "${PYTHON_EXECUTABLE}" "${_python_compile_py}" "${_bin_py}" + DEPENDS "${_absfilename}" + ) + endif() + + install(FILES ${_bin_pyc} DESTINATION "${_py_install_dir}") + unset(_py_install_dir) + unset(_message) + + endif("$ENV{PYTHONDONTWRITEBYTECODE}" STREQUAL "") + +endmacro(PYTHON_INSTALL) diff --git a/pyqt/cmake/SIPMacros.cmake b/pyqt/cmake/SIPMacros.cmake new file mode 100644 index 0000000..86c2607 --- /dev/null +++ b/pyqt/cmake/SIPMacros.cmake @@ -0,0 +1,124 @@ +# Macros for SIP +# ~~~~~~~~~~~~~~ +# Copyright (c) 2007, Simon Edwards +# Redistribution and use is allowed according to the terms of the BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. +# +# SIP website: http://www.riverbankcomputing.co.uk/sip/index.php +# +# This file defines the following macros: +# +# ADD_SIP_PYTHON_MODULE (MODULE_NAME MODULE_SIP [library1, libaray2, ...]) +# Specifies a SIP file to be built into a Python module and installed. +# MODULE_NAME is the name of Python module including any path name. (e.g. +# os.sys, Foo.bar etc). MODULE_SIP the path and filename of the .sip file +# to process and compile. libraryN are libraries that the Python module, +# which is typically a shared library, should be linked to. The built +# module will also be install into Python's site-packages directory. +# +# The behaviour of the ADD_SIP_PYTHON_MODULE macro can be controlled by a +# number of variables: +# +# SIP_INCLUDES - List of directories which SIP will scan through when looking +# for included .sip files. (Corresponds to the -I option for SIP.) +# +# SIP_TAGS - List of tags to define when running SIP. (Corresponds to the -t +# option for SIP.) +# +# SIP_CONCAT_PARTS - An integer which defines the number of parts the C++ code +# of each module should be split into. Defaults to 8. (Corresponds to the +# -j option for SIP.) +# +# SIP_DISABLE_FEATURES - List of feature names which should be disabled +# running SIP. (Corresponds to the -x option for SIP.) +# +# SIP_EXTRA_OPTIONS - Extra command line options which should be passed on to +# SIP. + +SET(SIP_INCLUDES) +SET(SIP_TAGS) +SET(SIP_CONCAT_PARTS 8) +SET(SIP_DISABLE_FEATURES) +SET(SIP_EXTRA_OPTIONS) + +MACRO(ADD_SIP_PYTHON_MODULE MODULE_NAME MODULE_SIP) + + SET(EXTRA_LINK_LIBRARIES ${ARGN}) + + STRING(REPLACE "." "/" _x ${MODULE_NAME}) + GET_FILENAME_COMPONENT(_parent_module_path ${_x} PATH) + GET_FILENAME_COMPONENT(_child_module_name ${_x} NAME) + + GET_FILENAME_COMPONENT(_module_path ${MODULE_SIP} PATH) + + if(_module_path STREQUAL "") + set(CMAKE_CURRENT_SIP_OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}") + else(_module_path STREQUAL "") + set(CMAKE_CURRENT_SIP_OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/${_module_path}") + endif(_module_path STREQUAL "") + + GET_FILENAME_COMPONENT(_abs_module_sip ${MODULE_SIP} ABSOLUTE) + + # We give this target a long logical target name. + # (This is to avoid having the library name clash with any already + # install library names. If that happens then cmake dependancy + # tracking get confused.) + STRING(REPLACE "." "_" _logical_name ${MODULE_NAME}) + SET(_logical_name "python_module_${_logical_name}") + + FILE(MAKE_DIRECTORY ${CMAKE_CURRENT_SIP_OUTPUT_DIR}) # Output goes in this dir. + + SET(_sip_includes) + FOREACH (_inc ${SIP_INCLUDES}) + GET_FILENAME_COMPONENT(_abs_inc ${_inc} ABSOLUTE) + LIST(APPEND _sip_includes -I ${_abs_inc}) + ENDFOREACH (_inc ) + + SET(_sip_tags) + FOREACH (_tag ${SIP_TAGS}) + LIST(APPEND _sip_tags -t ${_tag}) + ENDFOREACH (_tag) + + SET(_sip_x) + FOREACH (_x ${SIP_DISABLE_FEATURES}) + LIST(APPEND _sip_x -x ${_x}) + ENDFOREACH (_x ${SIP_DISABLE_FEATURES}) + + SET(_message "-DMESSAGE=Generating CPP code for module ${MODULE_NAME}") + SET(_sip_output_files) + FOREACH(CONCAT_NUM RANGE 0 ${SIP_CONCAT_PARTS} ) + IF( ${CONCAT_NUM} LESS ${SIP_CONCAT_PARTS} ) + SET(_sip_output_files ${_sip_output_files} ${CMAKE_CURRENT_SIP_OUTPUT_DIR}/sip${_child_module_name}part${CONCAT_NUM}.cpp ) + ENDIF( ${CONCAT_NUM} LESS ${SIP_CONCAT_PARTS} ) + ENDFOREACH(CONCAT_NUM RANGE 0 ${SIP_CONCAT_PARTS} ) + + IF(NOT WIN32) + SET(TOUCH_COMMAND touch) + ELSE(NOT WIN32) + SET(TOUCH_COMMAND echo) + # instead of a touch command, give out the name and append to the files + # this is basically what the touch command does. + FOREACH(filename ${_sip_output_files}) + FILE(APPEND filename "") + ENDFOREACH(filename ${_sip_output_files}) + ENDIF(NOT WIN32) + ADD_CUSTOM_COMMAND( + OUTPUT ${_sip_output_files} + COMMAND ${CMAKE_COMMAND} -E echo ${message} + COMMAND ${TOUCH_COMMAND} ${_sip_output_files} + COMMAND ${SIP_EXECUTABLE} ${_sip_tags} ${_sip_x} ${SIP_EXTRA_OPTIONS} -j ${SIP_CONCAT_PARTS} -c ${CMAKE_CURRENT_SIP_OUTPUT_DIR} ${_sip_includes} ${_abs_module_sip} + DEPENDS ${_abs_module_sip} ${SIP_EXTRA_FILES_DEPEND} + ) + # not sure if type MODULE could be uses anywhere, limit to cygwin for now + IF (CYGWIN) + ADD_LIBRARY(${_logical_name} MODULE ${_sip_output_files} ) + ELSE (CYGWIN) + ADD_LIBRARY(${_logical_name} SHARED ${_sip_output_files} ) + ENDIF (CYGWIN) + TARGET_LINK_LIBRARIES(${_logical_name} ${PYTHON_LIBRARY}) + TARGET_LINK_LIBRARIES(${_logical_name} ${EXTRA_LINK_LIBRARIES}) + SET_TARGET_PROPERTIES(${_logical_name} PROPERTIES PREFIX "" OUTPUT_NAME ${_child_module_name}) + + INSTALL(TARGETS ${_logical_name} DESTINATION "${PYTHON_SITE_PACKAGES_INSTALL_DIR}/${_parent_module_path}") + +ENDMACRO(ADD_SIP_PYTHON_MODULE) diff --git a/pyqt/config-old.py b/pyqt/config-old.py deleted file mode 100755 index b5eb76e..0000000 --- a/pyqt/config-old.py +++ /dev/null @@ -1,85 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -# PyQt4 bindings for th QTermWidget project. -# -# Copyright (C) 2009 Piotr "Riklaunim" Maliński , -# Alexander Slesarev -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -import os -import sipconfig -from PyQt4 import pyqtconfig - -# The name of the SIP build file generated by SIP and used by the build -# system. -build_file = "qtermwidget.sbf" - -# Get the PyQt configuration information. -config = pyqtconfig.Configuration() - -# Get the extra SIP flags needed by the imported qt module. Note that -# this normally only includes those flags (-x and -t) that relate to SIP's -# versioning system. -qt_sip_flags = config.pyqt_sip_flags - -# Run SIP to generate the code. Note that we tell SIP where to find the qt -# module's specification files using the -I flag. -os.system(" ".join([config.sip_bin, "-c", ".", "-b", build_file, "-I", - config.pyqt_sip_dir, qt_sip_flags, "qtermwidget.sip"])) - -# We are going to install the SIP specification file for this module and -# its configuration module. -installs = [] - -installs.append(["qtermwidget.sip", os.path.join(config.default_sip_dir, - "qtermwidget")]) - -installs.append(["qtermwidgetconfig.py", config.default_mod_dir]) - -# Create the Makefile. The QtModuleMakefile class provided by the -# pyqtconfig module takes care of all the extra preprocessor, compiler and -# linker flags needed by the Qt library. -makefile = pyqtconfig.QtGuiModuleMakefile( - configuration = config, - build_file = build_file, - installs = installs) - -# Add the library we are wrapping. The name doesn't include any platform -# specific prefixes or extensions (e.g. the "lib" prefix on UNIX, or the -# ".dll" extension on Windows). -makefile.extra_lib_dirs.append("..") -makefile.extra_libs = ["qtermwidget4"] - -# Generate the Makefile itself. -makefile.generate() - -# Now we create the configuration module. This is done by merging a Python -# dictionary (whose values are normally determined dynamically) with a -# (static) template. -content = { - # Publish where the SIP specifications for this module will be - # installed. - "qtermwidget_sip_dir": config.default_sip_dir, - - # Publish the set of SIP flags needed by this module. As these are the - # same flags needed by the qt module we could leave it out, but this - # allows us to change the flags at a later date without breaking - # scripts that import the configuration module. - "qtermwidget_sip_flags": qt_sip_flags} - -# This creates the qtermwidgetconfig.py module from the qtermwidgetconfig.py.in -# template and the dictionary. -sipconfig.create_config_module("qtermwidgetconfig.py", "config.py.in", content) diff --git a/pyqt/config.py b/pyqt/config.py deleted file mode 100755 index 5925213..0000000 --- a/pyqt/config.py +++ /dev/null @@ -1,104 +0,0 @@ -import os -import sipconfig -import subprocess -import os -import site -import pprint -from distutils import sysconfig -from PyQt5 import QtCore -import PyQt5 - - -class Configuration(sipconfig.Configuration): - """The class that represents PyQt configuration values. - """ - - def getEnv(self, name, default): - return os.environ.get(name) or default - - def __init__(self): - qmake_bin = subprocess.check_output( - ["which", "qmake"], universal_newlines=True).strip(' \t\n\r') - qtconfig = subprocess.check_output( - [qmake_bin, "-query"], universal_newlines=True) - qtconfig = dict(x.split(":", 1) for x in qtconfig.splitlines()) - - self.pyQtIncludePath = self.getEnv( - 'PYQT_INCLUDE_PATH', '/usr/share/sip/PyQt5') - - pyqtconfig = { - "pyqt_config_args": "--confirm-license -v " + str(self.pyQtIncludePath) + " --qsci-api -q " + qmake_bin, - "pyqt_version": QtCore.PYQT_VERSION, - "pyqt_version_str": QtCore.PYQT_VERSION_STR, - "pyqt_bin_dir": PyQt5.__path__[0], - "pyqt_mod_dir": PyQt5.__path__[0], - "pyqt_sip_dir": str(self.pyQtIncludePath), - "pyqt_modules": "QtCore QtGui QtWidgets", # ... and many more - "pyqt_sip_flags": QtCore.PYQT_CONFIGURATION['sip_flags'], - "qt_version": QtCore.QT_VERSION, - "qt_edition": "free", - "qt_winconfig": "shared", - "qt_framework": 0, - "qt_threaded": 1, - "qt_dir": qtconfig['QT_INSTALL_PREFIX'], - "qt_data_dir": qtconfig['QT_INSTALL_DATA'], - "qt_archdata_dir": qtconfig['QT_INSTALL_DATA'], - "qt_inc_dir": qtconfig['QT_INSTALL_HEADERS'], - "qt_lib_dir": qtconfig['QT_INSTALL_LIBS'] - } - - macros = sipconfig._default_macros.copy() - macros['INCDIR_QT'] = qtconfig['QT_INSTALL_HEADERS'] - macros['LIBDIR_QT'] = qtconfig['QT_INSTALL_LIBS'] - macros['MOC'] = os.path.join(qtconfig['QT_INSTALL_BINS'], 'moc') - - sipconfig.Configuration.__init__(self, [pyqtconfig]) - self.set_build_macros(macros) - - -# The name of the SIP build file generated by SIP and used by the build system. -build_file = "qtermwidget.sbf" - -# Get the SIP configuration information. -config = Configuration() - -# Run SIP to generate the build_file -os.system(" ".join([config.sip_bin, '-I', str(config.pyQtIncludePath), str( - config.pyqt_sip_flags), "-b", build_file, "-o", "-c", ". " " qtermwidget.sip"])) - -installs = [] -installs.append(["qtermwidget.sip", os.path.join( - config.pyqt_sip_dir, "qtermwidget")]) -installs.append(["qtermwidgetconfig.py", config.pyqt_mod_dir]) - -makefile = sipconfig.SIPModuleMakefile( - configuration=config, build_file=build_file, installs=installs, qt=["QtCore", "QtGui", "QtWidgets"]) - -# Add the library we are wrapping. The name doesn't include any platform -# specific prefixes or extensions (e.g. the "lib" prefix on UNIX, or the -# ".dll" extension on Windows). -makefile.extra_lib_dirs.append("../lib/") -makefile.extra_lib_dirs.append("..") -makefile.extra_libs = ["qtermwidget5"] - -# Support for C++11 -makefile.extra_cxxflags.append('-std=c++11') - -# Generate the Makefile itself. -makefile.generate() - -content = { - # Publish where the SIP specifications for this module will be - # installed. - "qtermwidget_sip_dir": config.pyqt_sip_dir, - - # Publish the set of SIP flags needed by this module. As these are the - # same flags needed by the qt module we could leave it out, but this - # allows us to change the flags at a later date without breaking - # scripts that import the configuration module. - "qtermwidget_sip_flags": config.pyqt_sip_flags -} - -# This creates the qtermwidgetconfig.py module from the qtermwidgetconfig.py.in -# template and the dictionary. -sipconfig.create_config_module("qtermwidgetconfig.py", "config.py.in", content) diff --git a/pyqt/qtermwidgetconfig.py b/pyqt/qtermwidgetconfig.py deleted file mode 100644 index e69de29..0000000 diff --git a/pyqt/qtermwidget.sip b/pyqt/sip/qtermwidget.sip similarity index 95% rename from pyqt/qtermwidget.sip rename to pyqt/sip/qtermwidget.sip index 444e2f8..dccf076 100644 --- a/pyqt/qtermwidget.sip +++ b/pyqt/sip/qtermwidget.sip @@ -1,5 +1,8 @@ %Module QTermWidget +%ModuleHeaderCode +#pragma GCC visibility push(default) +%End %Import QtGui/QtGuimod.sip %Import QtCore/QtCoremod.sip @@ -19,7 +22,7 @@ public: ScrollBarRight=2 }; - enum KeyboardCursorShape + enum class KeyboardCursorShape { BlockCursor=0, UnderlineCursor=1, @@ -30,6 +33,8 @@ public: ~QTermWidget(); void startTerminalTeletype(); QSize sizeHint() const; + void setTerminalSizeHint(bool on); + bool terminalSizeHint(); void startShellProgram(); int getShellPID(); void changeDir(const QString & dir);