diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..b37ec82 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,19 @@ +# remove files from deployment using `git archive` + +# git files +.gitattributes export-ignore +.github export-ignore +.gitignore export-ignore + + +# several files and directories we never want to export +# a little bit belt and braces as the most of these files +# should never ever be in the repository + +.*~ export-ignore +.kdev4 export-ignore +.translation-updates export-ignore + +/build export-ignore +/temp export-ignore +/tmp export-ignore diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md new file mode 100644 index 0000000..701426e --- /dev/null +++ b/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,34 @@ + + + +##### Expected Behavior + + + +##### Current Behavior + + + +##### Possible Solution + + + +##### Steps to Reproduce (for bugs) + + +1. +2. +3. +4. + +##### Context + + + +##### System Information + +* Distribution & Version: +* Kernel: +* Qt Version: +* liblxqt Version: +* Package version: diff --git a/.translation-update b/.translation-update new file mode 100644 index 0000000..8b818c9 --- /dev/null +++ b/.translation-update @@ -0,0 +1 @@ +translations='./lib' diff --git a/CHANGELOG b/CHANGELOG new file mode 100644 index 0000000..ae1c154 --- /dev/null +++ b/CHANGELOG @@ -0,0 +1,280 @@ + +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 + * README: don't recommend building from source + * Improve README + * Don't export github templates + * Support REP escape sequence defined in ECMA-48, section 8.3.103 + * Fix build issue related to utmpx in Mac OSX Sierra + * Remove the deprecation notice + * Handle DECSCUSR signals + * Copied issue template + * Update building instructions + * Require Qt 5.6+ + * This commit allows the consumer of qtermwidget to capture the (#111) + * Allow the terminal display to be smaller than the size hint (#123) + * Backport Vt102 emulation fixes (#113) + * Backport the default.keytab from Konsole + * Fixes (#122) + * Updated README, Added support for PyQT 5.7 + * Fix memory leak in hotspot (URLs & emails) detection + * Adds superbuild support + * Use target_compile_definitions() instead of add_definitions() + * Update find_package() documentation + * Use the lxqt_create_pkgconfig_file + * Improve lxqt_translate_ts() use + * Adds COMPONENT to the install files + * Renames test app to example. Make it work + * Drop include_directories() for in tree dirs + * Use the CMake Targets way + * Pack Utf8Proc stuff + * Adds export header + * Use LXQtCompilerSettings + * Packs compile definitions + * Adds package version file + * Removes Qt4 stuff + * Add translation mechanism + * Use const iterators when possible. + * Enable strict iterators for debug builds + * TerminalDisplay: Make resizing "Size" translatable + * Exposes receivedData signal to users of QTermWidget + * Exposes sessions autoClose property to QTermWidget + +0.7.1 / 2016-12-21 +================== + + * Release 0.7.1: Update changelog + * Bump patch version (#105) + * Added a modified Breeze color scheme (#104) + * Accept hex color strings as well (#101) + * Remove the stale lib/README (#102) + * Implement background images (#95) + * Implement other BOX DRAWING characters (#98) + * Preparations for context menu actions on URLs (#97) + * Drop the ancient wcwidth impl. and use utf8proc if possible (#99) + * Remove widget size checks in setVTFont() (#86) + * Delete unused tooltip code (#81) + * Fix size of the array passed to memset() (#79) + * Remove cpack (#93) + +0.7.0 / 2016-09-24 +================== + + * Release 0.7.0: Add changelog + * Bump version to 0.7.0 (#92) + * Add Solarized Color Schemes + * Update README.md + * qtermwidget: Unify title & icon propagation + * lib: Fix FTBFS (struct vs. class mismatch) + * Add 'const' decorators + * Expose titleChanged() signal + * Fix building instructions + * cmake support changes + * Make addCustomColorSchemeDir() static and check for duplicates + * Address review comments + * Allow app to add custom color sheme locations + * Avoid enums duplication + * Add support for setting keyboard cursor shape + * Remove assignment to self + * Backport konsole changes to fix memory leaks + * Remove __FILE__ macros + * Replace assert() with Q_ASSERT() + * Fix ASan error about delete size mismatch + * Add support for GNU/Hurd to kpty.cpp. + * fixes kfreebsd builds on debian and derivatives + * Fix indenations (misleading-indentation warning) + * Remove Q_DECL_OVERRIDE macros + * typo Higlight + * Remove noisy qDebugs + * Bracketed paste mode implementation + * Use function setWorldTranfer for Qpainter instead of setWorldMatrix + * Modify treatment drawing double width character + * pyqt5 bindings + * pyqt5 bindings + * Avoid checking uninitialized member + simplify condition + * Use markdown for README and improve it a bit + * Remove support for Qt <= 5.4 + * Remove Designer plugin + * Fix LICENSE text and name + * Remove Changelog + * Remove empty TODO file + * Remove PyQt4 bindings + * Sort out terminal resizing + * Rebase Vt102Emulation to Konsole + * Enable terminal resizing from the emulator + * Clean up trailing whitespaces + * implemented start TTY for external recipient; + * Fix: typo in TerminalDisplay + * add method for get pty slave fd; + * add method for get pty slave fd; + * Use GNUInstallDirs in CMakeLists.txt to stop hardcoding paths + * Set the '_notifiedActivity' flag early + * Also expose signals and slots to pyqt + * Get/set selection end in python bindings + * Avoid calling winId() on Qt5. + * Fix TerminalDisplay::getCharacterPosition for proportional fonts + * Handle proportional fonts a bit better + * Expose more functionality through the python bindings (#23) + * Allow stopping test.py with ctrl-C + * Fix 'getSelectionEnd' + * Make whitespace consistent (tabs->spaces) + * Fix python binding compile errors #23 + * Add event to notify the application that the shell application uses mouse. + * Change mouseMarks only when needed. This might be useful if an application wants to be notified of the event. + * Prevents deleting the last line when resizing. + +0.6.0 / 2014-10-21 +================== + + * Release 0.6.0 + * Update AUTHORS + * Update INSTALL instructions + * CMakeLists.txt cleanup + * osx: link fixes + * fixed #57 Linux emulation does not seem to support Ctrl+Arrows (warning: I have no clue what I did...) + * Fix Qt4 compilation + * qterminal #64 No drag & drop support + * fixed qterminal #71 qt5 version ignoring page up / down + * Fixed a typo in CMakeLists.txt. + +0.5.1 / 2014-07-14 +================== + + * fixed 'make dist'; version bump + * Url activation & filters #21 + * Proxy activity/silence methods to Session in QTermWidget. + * Emit activity() and silence() signals instead of KNotification. + * Support bells. + * Support bells. + * Added QTermWidget::urlActivated(QUrl) signal. + * Emit UrlFilter::activated() instead of QDesktopServices::openUrl(). + * Derive Filter from QObject. + * Add UrlFilter. + * Activate link filters on ctrl+click. + * Update filters on resize and screen events. + * Const-correctness for QTermWidget API. + * Load arbitrary schemes by path via setColorScheme(). + * ColorSchemeManager::loadCustomColorScheme(const QString& path). + * Unified schemeName() usage. + * fixed #17 lib/ShellCommand.cpp:66: possible =/== mixup + * Delete CMakeLists.txt.user + * new API selectedText() + * new API methods (thanks to William Brumley) + * fixed #11 compile against Qt 5 (Qt4 and Qt5 supported and waguely tested) + * build simplified: qtermwidget is versioned (libqtermwidget4 for Qt4, 5 for Qt5...). Better cmake support. + * fixed broken API for sendText() - const missing + * mail address change + * Current Working Directory for linux. Part of #8. More implementations welcomed... + * Add a method for get working directory in class QTermWidget + * Fix missing cleanup for temporary history files + * a potential improvement for #9 font fractional pixels causes spacing errors + * fix #2 update various documentations for debian packaging + * fix #10 Update FSF address + +0.4.0 / 2013-04-16 +================== + + * readme updated + * Added pasteSelection-slot and corrected two nonsense comments + * qt/embedded doesn't ship with a Monospace font (and it won't use system fonts even if they exist). Using 'fixed' instead works fine + * Without this, the terminal display area will permanently lose focus when consoleq's Find dialog is called up. + * This is only needed when using Qt/E built for DirectFB display. DirectFB blocks SIGINT and some other signals, so any terminal app (be it Qt or otherwise) must call sigprocmask() to unblock them. Without this, ^C doesn't work. + * The control and tab keys don't work in Qt/E. This fixes it, but maybe not in the most elegant way. The trouble seems to be that _codec->fromUnicode(event->text()) doesn't handle control characters in qt-embedded. + * Fix resize label + * Search code cleanup + * Change searchbar background color to red(ish) when no match found + * Fix search, find-next when selection is one character long + * Hotkeys for search: Return->find-next, Shift-Return->find-previous, Escape->hide searchbar + * Added search functionality + * Add zoom. Add choice action after paste clipboard + * Add zoom. Add choice action after paste clipboard + * Add zoom. Add choice action after paste clipboard + * Add zoom. Add choice action after paste clipboard + * Add zoom. Add choice action after paste clipboard + * Add zoom. Add choice action after paste clipboard + * Add zoom. Add choice action after paste clipboard + * Add zoom. Add choice action after paste clipboard + * Add zoom. Add choice action after paste clipboard + * Fix logical error + * Add zoom. Add choice action after paste clipboard + * Add zoom. Add choice action after paste clipboard + * Add Shift+KeyEnd and Shift+KeyHome to go line 0 and line end. No move screenwindow when copy and paste with keyboard + * fix for text drawing in qt>=4.8,x + * constructor for Qt Designer + * test commit + * clear() slot implemented + * fix the scroll at the end again + * The escape key is always needed for terminal programs like vim. + * Add resource files and the appropriate paths to enable bundling of color schemes and keyboard layouts into the actual executable. + * Add a define which will be used to bundle the color schemes and keyboard layouts as resource files with the executable itself instead of putting them on disk. + * scrollToEnd() method provided to trigger 'snapping' the terminal to cursor tracked position (typically the extreme value of the scrollbar, or the 'end') Some signal-fu particular to keyPressEvent(QKeyEvent *) done to make the above usable, no existing dependent implementations should be disturbed by this. + * revert workaround for key on end + * scroll to bottom on input + * scrollToEnd() method provided to trigger 'snapping' the terminal to cursor tracked position (typically the extreme value of the scrollbar, or the 'end') Some signal-fu particular to keyPressEvent(QKeyEvent *) done to make the above usable, no existing dependent implementations should be disturbed by this. + * improved sample app for testing + * macosx compile fix + * arguments work correctly for custom shells too + * lib has to be built first in any case + * merge changes from the experimental "bundle" repository + * fix for kb-layout location on mac (mainly) + * rpm builds + * mac universal build helper + * build cleanup; make dist; various readmes updated + * make availableKeyBindings static + * transparency support + * font display fix on mac (widths in int) + * qt designer plugin + * correct lib ID for mac + * remove the KDE legacy code + * code reformatted after resync + * display stuff synced from konsole again to improve color scheme handling + * focus in/out signals + * correct shell detection (BSD, Christopher VdoP) + * library location on BSD + * patches to build on BSD by Christopher VdoP + * K&R formatting + * K&R formatting + * merge with qscite + * fixed KB finding + sort + * key layouts can be read and provided to widget + * install keyboard bindings; handle KB in src code; allow to get and set KB + * fix for includes and 64bit builds + * port to macosx + * initial import diff --git a/COPYING b/LICENSE similarity index 84% rename from COPYING rename to LICENSE index d159169..d8cf7d4 100644 --- a/COPYING +++ b/LICENSE @@ -278,62 +278,3 @@ PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - 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 2 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, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. diff --git a/cmake/FindUtf8Proc.cmake b/cmake/FindUtf8Proc.cmake new file mode 100644 index 0000000..4081854 --- /dev/null +++ b/cmake/FindUtf8Proc.cmake @@ -0,0 +1,59 @@ +#.rst: +# FindUtf8Proc +# -------- +# +# Find utf8proc +# +# Find the UTF-8 processing library +# +# :: +# +# This module defines the following variables: +# UTF8PROC_FOUND - True if UTF8PROC_INCLUDE_DIR & UTF8PROC_LIBRARY are found +# UTF8PROC_LIBRARIES - Set when UTF8PROC_LIBRARY is found +# UTF8PROC_INCLUDE_DIRS - Set when UTF8PROC_INCLUDE_DIR is found +# +# +# +# :: +# +# UTF8PROC_INCLUDE_DIR - where to find utf8proc.h +# UTF8PROC_LIBRARY - the utf8proc library + +#============================================================================= +# This module is adapted from FindALSA.cmake. Below are the original license +# header. +#============================================================================= +# Copyright 2009-2011 Kitware, Inc. +# Copyright 2009-2011 Philip Lowman +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= + +find_path( + UTF8PROC_INCLUDE_DIR NAMES utf8proc.h DOC "The utf8proc include directory" +) + +find_library( + UTF8PROC_LIBRARY NAMES utf8proc DOC "The utf8proc library" +) + +# handle the QUIETLY and REQUIRED arguments and set UTF8PROC_FOUND to TRUE if +# all listed variables are TRUE +include(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS( + UTF8PROC + REQUIRED_VARS UTF8PROC_LIBRARY UTF8PROC_INCLUDE_DIR +) + +if(UTF8PROC_FOUND) + set( UTF8PROC_LIBRARIES ${UTF8PROC_LIBRARY} ) + set( UTF8PROC_INCLUDE_DIRS ${UTF8PROC_INCLUDE_DIR} ) +endif() + +mark_as_advanced(UTF8PROC_INCLUDE_DIR UTF8PROC_LIBRARY) 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/lib/BlockArray.cpp b/lib/BlockArray.cpp index 3f36390..e4ccf8d 100644 --- a/lib/BlockArray.cpp +++ b/lib/BlockArray.cpp @@ -27,7 +27,6 @@ #include "BlockArray.h" // System -#include #include #include #include @@ -57,7 +56,7 @@ BlockArray::BlockArray() BlockArray::~BlockArray() { setHistorySize(0); - assert(!lastblock); + Q_ASSERT(!lastblock); } size_t BlockArray::append(Block * block) @@ -149,7 +148,7 @@ const Block * BlockArray::at(size_t i) size_t j = i; // (current - (index - i) + (index/size+1)*size) % size ; - assert(j < size); + Q_ASSERT(j < size); unmap(); Block * block = (Block *)mmap(0, blocksize, PROT_READ, MAP_PRIVATE, ion, j * blocksize); @@ -218,7 +217,7 @@ bool BlockArray::setHistorySize(size_t newsize) return false; } - assert(!lastblock); + Q_ASSERT(!lastblock); lastblock = new Block(); size = newsize; diff --git a/lib/Character.h b/lib/Character.h index ce0f1b3..9c9fae2 100644 --- a/lib/Character.h +++ b/lib/Character.h @@ -1,6 +1,6 @@ /* This file is part of Konsole, KDE's terminal. - + Copyright 2007-2008 by Robert Knight Copyright 1997,1998 by Lars Doelle @@ -45,8 +45,13 @@ static const int LINE_DOUBLEHEIGHT = (1 << 2); #define RE_UNDERLINE (1 << 2) #define RE_REVERSE (1 << 3) // Screen only #define RE_INTENSIVE (1 << 3) // Widget only -#define RE_CURSOR (1 << 4) -#define RE_EXTENDED_CHAR (1 << 5) +#define RE_ITALIC (1 << 4) +#define RE_CURSOR (1 << 5) +#define RE_EXTENDED_CHAR (1 << 6) +#define RE_FAINT (1 << 7) +#define RE_STRIKEOUT (1 << 8) +#define RE_CONCEAL (1 << 9) +#define RE_OVERLINE (1 << 10) /** * A single character in the terminal which consists of a unicode character @@ -56,7 +61,7 @@ static const int LINE_DOUBLEHEIGHT = (1 << 2); class Character { public: - /** + /** * Constructs a new character. * * @param _c The unicode character value of this character. @@ -73,26 +78,26 @@ 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. * * charSequence is a hash code which can be used to look up the unicode * character sequence in the ExtendedCharTable used to create the sequence. */ - quint16 charSequence; + quint16 charSequence; }; /** A combination of RENDITION flags which specify options for drawing the character. */ quint8 rendition; /** The foreground color used to draw this character. */ - CharacterColor foregroundColor; + CharacterColor foregroundColor; /** The color used to draw this character's background. */ CharacterColor backgroundColor; - /** + /** * Returns true if this character has a transparent background when * it is drawn with the specified @p palette. */ @@ -100,16 +105,16 @@ public: /** * Returns true if this character should always be drawn in bold when * it is drawn with the specified @p palette, independent of whether - * or not the character has the RE_BOLD rendition flag. + * or not the character has the RE_BOLD rendition flag. */ ColorEntry::FontWeight fontWeight(const ColorEntry* base) const; - - /** + + /** * returns true if the format (color, rendition flag) of the compared characters is equal */ bool equalsFormat(const Character &other) const; - /** + /** * Compares two characters and returns true if they have the same unicode character value, * rendition and colors. */ @@ -122,36 +127,36 @@ public: }; inline bool operator == (const Character& a, const Character& b) -{ - return a.character == b.character && - a.rendition == b.rendition && - a.foregroundColor == b.foregroundColor && +{ + return a.character == b.character && + a.rendition == b.rendition && + a.foregroundColor == b.foregroundColor && a.backgroundColor == b.backgroundColor; } inline bool operator != (const Character& a, const Character& b) { - return a.character != b.character || - a.rendition != b.rendition || - a.foregroundColor != b.foregroundColor || + return a.character != b.character || + a.rendition != b.rendition || + a.foregroundColor != b.foregroundColor || a.backgroundColor != b.backgroundColor; } inline bool Character::isTransparent(const ColorEntry* base) const { - return ((backgroundColor._colorSpace == COLOR_SPACE_DEFAULT) && + return ((backgroundColor._colorSpace == COLOR_SPACE_DEFAULT) && base[backgroundColor._u+0+(backgroundColor._v?BASE_COLORS:0)].transparent) - || ((backgroundColor._colorSpace == COLOR_SPACE_SYSTEM) && + || ((backgroundColor._colorSpace == COLOR_SPACE_SYSTEM) && base[backgroundColor._u+2+(backgroundColor._v?BASE_COLORS:0)].transparent); } inline bool Character::equalsFormat(const Character& other) const { - return + return backgroundColor==other.backgroundColor && foregroundColor==other.foregroundColor && rendition==other.rendition; -} +} inline ColorEntry::FontWeight Character::fontWeight(const ColorEntry* base) const { @@ -196,7 +201,7 @@ public: * which was added to the table using createExtendedChar(). * * @param hash The hash key returned by createExtendedChar() - * @param length This variable is set to the length of the + * @param length This variable is set to the length of the * character sequence. * * @return A unicode character sequence of size @p length. @@ -208,7 +213,7 @@ public: private: // calculates the hash key of a sequence of unicode points of size 'length' ushort extendedCharHash(ushort* unicodePoints , ushort length) const; - // tests whether the entry in the table specified by 'hash' matches the + // tests whether the entry in the table specified by 'hash' matches the // character sequence 'unicodePoints' of size 'length' bool extendedCharMatch(ushort hash , ushort* unicodePoints , ushort length) const; // internal, maps hash keys to character sequence buffers. The first ushort diff --git a/lib/CharacterColor.h b/lib/CharacterColor.h index a17c5ce..a5a5e67 100644 --- a/lib/CharacterColor.h +++ b/lib/CharacterColor.h @@ -1,6 +1,6 @@ /* This file is part of Konsole, KDE's terminal. - + Copyright 2007-2008 by Robert Knight Copyright 1997,1998 by Lars Doelle @@ -32,14 +32,14 @@ namespace Konsole { -/** - * An entry in a terminal display's color palette. +/** + * An entry in a terminal display's color palette. * * A color palette is an array of 16 ColorEntry instances which map * system color indexes (from 0 to 15) into actual colors. * * Each entry can be set as bold, in which case any text - * drawn using the color should be drawn in bold. + * drawn using the color should be drawn in bold. * * Each entry can also be transparent, in which case the terminal * display should avoid drawing the background for any characters @@ -49,58 +49,58 @@ class ColorEntry { public: /** Specifies the weight to use when drawing text with this color. */ - enum FontWeight + enum FontWeight { /** Always draw text in this color with a bold weight. */ Bold, /** Always draw text in this color with a normal weight. */ Normal, - /** - * Use the current font weight set by the terminal application. + /** + * Use the current font weight set by the terminal application. * This is the default behavior. */ UseCurrentFormat }; - /** + /** * Constructs a new color palette entry. * * @param c The color value for this entry. * @param tr Specifies that the color should be transparent when used as a background color. - * @param weight Specifies the font weight to use when drawing text with this color. + * @param weight Specifies the font weight to use when drawing text with this color. */ - ColorEntry(QColor c, bool tr, FontWeight weight = UseCurrentFormat) + ColorEntry(QColor c, bool tr, FontWeight weight = UseCurrentFormat) : color(c), transparent(tr), fontWeight(weight) {} /** * Constructs a new color palette entry with an undefined color, and * with the transparent and bold flags set to false. - */ - ColorEntry() : transparent(false), fontWeight(UseCurrentFormat) {} - + */ + ColorEntry() : transparent(false), fontWeight(UseCurrentFormat) {} + /** * Sets the color, transparency and boldness of this color to those of @p rhs. - */ - void operator=(const ColorEntry& rhs) - { - color = rhs.color; - transparent = rhs.transparent; - fontWeight = rhs.fontWeight; + */ + void operator=(const ColorEntry& rhs) + { + color = rhs.color; + transparent = rhs.transparent; + fontWeight = rhs.fontWeight; } /** The color value of this entry for display. */ QColor color; - /** - * If true character backgrounds using this color should be transparent. + /** + * If true character backgrounds using this color should be transparent. * This is not applicable when the color is used to render text. */ bool transparent; /** - * Specifies the font weight to use when drawing text with this color. + * Specifies the font weight to use when drawing text with this color. * This is not applicable when the color is used to draw a character's background. */ - FontWeight fontWeight; + FontWeight fontWeight; }; @@ -151,15 +151,15 @@ class CharacterColor public: /** Constructs a new CharacterColor whoose color and color space are undefined. */ - CharacterColor() - : _colorSpace(COLOR_SPACE_UNDEFINED), - _u(0), - _v(0), - _w(0) + CharacterColor() + : _colorSpace(COLOR_SPACE_UNDEFINED), + _u(0), + _v(0), + _w(0) {} - /** - * Constructs a new CharacterColor using the specified @p colorSpace and with + /** + * Constructs a new CharacterColor using the specified @p colorSpace and with * color value @p co * * The meaning of @p co depends on the @p colorSpace used. @@ -168,10 +168,10 @@ public: * * TODO : Add documentation about available color spaces. */ - CharacterColor(quint8 colorSpace, int co) - : _colorSpace(colorSpace), - _u(0), - _v(0), + CharacterColor(quint8 colorSpace, int co) + : _colorSpace(colorSpace), + _u(0), + _v(0), _w(0) { switch (colorSpace) @@ -183,7 +183,7 @@ public: _u = co & 7; _v = (co >> 3) & 1; break; - case COLOR_SPACE_256: + case COLOR_SPACE_256: _u = co & 255; break; case COLOR_SPACE_RGB: @@ -196,32 +196,32 @@ public: } } - /** + /** * Returns true if this character color entry is valid. */ - bool isValid() + bool isValid() const { return _colorSpace != COLOR_SPACE_UNDEFINED; } - - /** - * 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 * * The @p palette is only used if this color is one of the 16 system colors, otherwise * it is ignored. */ QColor color(const ColorEntry* palette) const; - - /** + + /** * Compares two colors and returns true if they represent the same color value and * use the same color space. */ @@ -235,14 +235,14 @@ public: private: quint8 _colorSpace; - // bytes storing the character color - quint8 _u; - quint8 _v; - quint8 _w; + // bytes storing the character color + quint8 _u; + quint8 _v; + quint8 _w; }; inline bool operator == (const CharacterColor& a, const CharacterColor& b) -{ +{ return a._colorSpace == b._colorSpace && a._u == b._u && a._v == b._v && @@ -256,14 +256,17 @@ inline bool operator != (const CharacterColor& a, const CharacterColor& b) inline const QColor color256(quint8 u, const ColorEntry* base) { // 0.. 16: system colors - if (u < 8) return base[u+2 ].color; u -= 8; - if (u < 8) return base[u+2+BASE_COLORS].color; u -= 8; + if (u < 8) return base[u+2 ].color; + u -= 8; + if (u < 8) return base[u+2+BASE_COLORS].color; + u -= 8; // 16..231: 6x6x6 rgb color cube if (u < 216) return QColor(((u/36)%6) ? (40*((u/36)%6)+55) : 0, ((u/ 6)%6) ? (40*((u/ 6)%6)+55) : 0, - ((u/ 1)%6) ? (40*((u/ 1)%6)+55) : 0); u -= 216; - + ((u/ 1)%6) ? (40*((u/ 1)%6)+55) : 0); + u -= 216; + // 232..255: gray, leaving out black and white int gray = u*10+8; return QColor(gray,gray,gray); } @@ -284,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/ColorScheme.cpp b/lib/ColorScheme.cpp index fc17cad..ecf4a61 100644 --- a/lib/ColorScheme.cpp +++ b/lib/ColorScheme.cpp @@ -30,6 +30,7 @@ #include #include #include +#include // KDE @@ -164,15 +165,15 @@ void ColorScheme::setColorTableEntry(int index , const ColorEntry& entry) { Q_ASSERT( index >= 0 && index < TABLE_COLORS ); - if ( !_table ) + if ( !_table ) { _table = new ColorEntry[TABLE_COLORS]; for (int i=0;i= 0 && index < TABLE_COLORS ); - return QString(colorNames[index]); + return QString::fromLatin1(colorNames[index]); } -QString ColorScheme::translatedColorNameForIndex(int index) +QString ColorScheme::translatedColorNameForIndex(int index) { Q_ASSERT( index >= 0 && index < TABLE_COLORS ); - return translatedColorNames[index]; + return QString::fromLatin1(translatedColorNames[index]); } void ColorScheme::readColorEntry(QSettings * s , int index) { - s->beginGroup(colorNameForIndex(index)); - + QString colorName = colorNameForIndex(index); + + s->beginGroup(colorName); + ColorEntry entry; - QStringList rgbList = s->value("Color", QStringList()).toStringList(); - if (rgbList.count() != 3) - { - Q_ASSERT(0); - } + QVariant colorValue = s->value(QLatin1String("Color")); + QString colorStr; int r, g, b; - r = rgbList[0].toInt(); - g = rgbList[1].toInt(); - b = rgbList[2].toInt(); + bool ok = false; + // XXX: Undocumented(?) QSettings behavior: values with commas are parsed + // as QStringList and others QString + if (colorValue.type() == QVariant::StringList) + { + QStringList rgbList = colorValue.toStringList(); + colorStr = rgbList.join(QLatin1Char(',')); + if (rgbList.count() == 3) + { + bool parse_ok; + + ok = true; + r = rgbList[0].toInt(&parse_ok); + ok = ok && parse_ok && (r >= 0 && r <= 0xff); + g = rgbList[1].toInt(&parse_ok); + ok = ok && parse_ok && (g >= 0 && g <= 0xff); + b = rgbList[2].toInt(&parse_ok); + ok = ok && parse_ok && (b >= 0 && b <= 0xff); + } + } + else + { + colorStr = colorValue.toString(); + QRegularExpression hexColorPattern(QLatin1String("^#[0-9a-f]{6}$"), + QRegularExpression::CaseInsensitiveOption); + if (hexColorPattern.match(colorStr).hasMatch()) + { + // Parsing is always ok as already matched by the regexp + r = colorStr.midRef(1, 2).toInt(nullptr, 16); + g = colorStr.midRef(3, 2).toInt(nullptr, 16); + b = colorStr.midRef(5, 2).toInt(nullptr, 16); + ok = true; + } + } + if (!ok) + { + qWarning().nospace() << "Invalid color value " << colorStr + << " for " << colorName << ". Fallback to black."; + r = g = b = 0; + } entry.color = QColor(r, g, b); - - entry.transparent = s->value("Transparent",false).toBool(); + + entry.transparent = s->value(QLatin1String("Transparent"),false).toBool(); // Deprecated key from KDE 4.0 which set 'Bold' to true to force // a color to be bold or false to use the current format // // TODO - Add a new tri-state key which allows for bold, normal or // current format - if (s->contains("Bold")) - entry.fontWeight = s->value("Bold",false).toBool() ? ColorEntry::Bold : + if (s->contains(QLatin1String("Bold"))) + entry.fontWeight = s->value(QLatin1String("Bold"),false).toBool() ? ColorEntry::Bold : ColorEntry::UseCurrentFormat; - quint16 hue = s->value("MaxRandomHue",0).toInt(); - quint8 value = s->value("MaxRandomValue",0).toInt(); - quint8 saturation = s->value("MaxRandomSaturation",0).toInt(); + quint16 hue = s->value(QLatin1String("MaxRandomHue"),0).toInt(); + quint8 value = s->value(QLatin1String("MaxRandomValue"),0).toInt(); + quint8 saturation = s->value(QLatin1String("MaxRandomSaturation"),0).toInt(); setColorTableEntry( index , entry ); if ( hue != 0 || value != 0 || saturation != 0 ) - setRandomizationRange( index , hue , saturation , value ); + setRandomizationRange( index , hue , saturation , value ); s->endGroup(); } @@ -379,8 +416,8 @@ void ColorScheme::writeColorEntry(KConfig& config , const QString& colorName, co configGroup.writeEntry("Bold",entry.fontWeight == ColorEntry::Bold); } - // record randomization if this color has randomization or - // if one of the keys already exists + // record randomization if this color has randomization or + // if one of the keys already exists if ( !random.isNull() || configGroup.hasKey("MaxRandomHue") ) { configGroup.writeEntry("MaxRandomHue",(int)random.hue); @@ -390,28 +427,28 @@ void ColorScheme::writeColorEntry(KConfig& config , const QString& colorName, co } #endif -// +// // Work In Progress - A color scheme for use on KDE setups for users // with visual disabilities which means that they may have trouble // reading text with the supplied color schemes. // // This color scheme uses only the 'safe' colors defined by the -// KColorScheme class. +// KColorScheme class. // -// A complication this introduces is that each color provided by +// A complication this introduces is that each color provided by // KColorScheme is defined as a 'background' or 'foreground' color. -// Only foreground colors are allowed to be used to render text and +// Only foreground colors are allowed to be used to render text and // only background colors are allowed to be used for backgrounds. // // The ColorEntry and TerminalDisplay classes do not currently -// support this restriction. +// support this restriction. // // Requirements: // - A color scheme which uses only colors from the KColorScheme class -// - Ability to restrict which colors the TerminalDisplay widget +// - Ability to restrict which colors the TerminalDisplay widget // uses as foreground and background color // - Make use of KGlobalSettings::allowDefaultBackgroundImages() as -// a hint to determine whether this accessible color scheme should +// a hint to determine whether this accessible color scheme should // be used by default. // // @@ -444,13 +481,13 @@ AccessibleColorScheme::AccessibleColorScheme() colorScheme.foreground( colorScheme.NeutralText ) }; - for ( int i = 0 ; i < TABLE_COLORS ; i++ ) + for ( int i = 0 ; i < TABLE_COLORS ; i++ ) { ColorEntry entry; entry.color = colors[ i % ColorRoleCount ].color(); - setColorTableEntry( i , entry ); - } + setColorTableEntry( i , entry ); + } #endif } @@ -458,17 +495,17 @@ KDE3ColorSchemeReader::KDE3ColorSchemeReader( QIODevice* device ) : _device(device) { } -ColorScheme* KDE3ColorSchemeReader::read() +ColorScheme* KDE3ColorSchemeReader::read() { Q_ASSERT( _device->openMode() == QIODevice::ReadOnly || _device->openMode() == QIODevice::ReadWrite ); ColorScheme* scheme = new ColorScheme(); - QRegExp comment("#.*$"); + QRegExp comment(QLatin1String("#.*$")); while ( !_device->atEnd() ) { - QString line(_device->readLine()); + QString line(QString::fromUtf8(_device->readLine())); line.remove(comment); line = line.simplified(); @@ -489,20 +526,20 @@ ColorScheme* KDE3ColorSchemeReader::read() { qDebug() << "KDE 3 color scheme contains an unsupported feature, '" << line << "'"; - } + } } return scheme; } bool KDE3ColorSchemeReader::readColorLine(const QString& line,ColorScheme* scheme) { - QStringList list = line.split(QChar(' ')); + QStringList list = line.split(QLatin1Char(' ')); if (list.count() != 7) return false; - if (list.first() != "color") + if (list.first() != QLatin1String("color")) return false; - + int index = list[1].toInt(); int red = list[2].toInt(); int green = list[3].toInt(); @@ -533,13 +570,13 @@ bool KDE3ColorSchemeReader::readTitleLine(const QString& line,ColorScheme* schem if( !line.startsWith(QLatin1String("title")) ) return false; - int spacePos = line.indexOf(' '); + int spacePos = line.indexOf(QLatin1Char(' ')); if( spacePos == -1 ) return false; QString description = line.mid(spacePos+1); - scheme->setDescription(description.toUtf8()); + scheme->setDescription(description); return true; } ColorSchemeManager::ColorSchemeManager() @@ -558,17 +595,13 @@ ColorSchemeManager::~ColorSchemeManager() void ColorSchemeManager::loadAllColorSchemes() { qDebug() << "loadAllColorSchemes"; - int success = 0; int failed = 0; QList nativeColorSchemes = listColorSchemes(); - QListIterator nativeIter(nativeColorSchemes); while ( nativeIter.hasNext() ) { - if ( loadColorScheme( nativeIter.next() ) ) - success++; - else + if ( !loadColorScheme( nativeIter.next() ) ) failed++; } @@ -576,9 +609,7 @@ void ColorSchemeManager::loadAllColorSchemes() QListIterator kde3Iter(kde3ColorSchemes); while ( kde3Iter.hasNext() ) { - if ( loadKDE3ColorScheme( kde3Iter.next() ) ) - success++; - else + if ( !loadKDE3ColorScheme( kde3Iter.next() ) ) failed++; } @@ -613,7 +644,7 @@ bool ColorSchemeManager::loadKDE3ColorScheme(const QString& filePath) delete scheme; return false; } - + QFileInfo info(filePath); if ( !_colorSchemes.contains(info.baseName()) ) @@ -628,7 +659,7 @@ bool ColorSchemeManager::loadKDE3ColorScheme(const QString& filePath) return true; } #if 0 -void ColorSchemeManager::addColorScheme(ColorScheme* scheme) +void ColorSchemeManager::addColorScheme(ColorScheme* scheme) { _colorSchemes.insert(scheme->name(),scheme); @@ -650,6 +681,11 @@ bool ColorSchemeManager::loadCustomColorScheme(const QString& path) return false; } +void ColorSchemeManager::addCustomColorSchemeDir(const QString& custom_dir) +{ + add_custom_color_scheme_dir(custom_dir); +} + bool ColorSchemeManager::loadColorScheme(const QString& filePath) { if ( !filePath.endsWith(QLatin1String(".colorscheme")) || !QFile::exists(filePath) ) @@ -658,17 +694,17 @@ bool ColorSchemeManager::loadColorScheme(const QString& filePath) QFileInfo info(filePath); const QString& schemeName = info.baseName(); - + ColorScheme* scheme = new ColorScheme(); scheme->setName(schemeName); scheme->read(filePath); - if (scheme->name().isEmpty()) + if (scheme->name().isEmpty()) { qDebug() << "Color scheme in" << filePath << "does not have a valid name and was not loaded."; delete scheme; return false; - } + } if ( !_colorSchemes.contains(schemeName) ) { @@ -678,23 +714,26 @@ bool ColorSchemeManager::loadColorScheme(const QString& filePath) { qDebug() << "color scheme with name" << schemeName << "has already been" << "found, ignoring."; - + delete scheme; } - return true; + return true; } QList ColorSchemeManager::listKDE3ColorSchemes() { - QString dname(get_color_schemes_dir()); - QDir dir(dname); - QStringList filters; - filters << "*.schema"; - dir.setNameFilters(filters); - QStringList list = dir.entryList(filters); QStringList ret; - foreach(QString i, list) - ret << dname + "/" + i; + for (const QString &scheme_dir : get_color_schemes_dirs()) + { + const QString dname(scheme_dir); + QDir dir(dname); + QStringList filters; + filters << QLatin1String("*.schema"); + dir.setNameFilters(filters); + QStringList list = dir.entryList(filters); + for (const QString &i : list) + ret << dname + QLatin1Char('/') + i; + } return ret; //return KGlobal::dirs()->findAllResources("data", // "konsole/*.schema", @@ -703,15 +742,18 @@ QList ColorSchemeManager::listKDE3ColorSchemes() } QList ColorSchemeManager::listColorSchemes() { - QString dname(get_color_schemes_dir()); - QDir dir(dname); - QStringList filters; - filters << "*.colorscheme"; - dir.setNameFilters(filters); - QStringList list = dir.entryList(filters); QStringList ret; - foreach(QString i, list) - ret << dname + "/" + i; + for (const QString &scheme_dir : get_color_schemes_dirs()) + { + const QString dname(scheme_dir); + QDir dir(dname); + QStringList filters; + filters << QLatin1String("*.colorscheme"); + dir.setNameFilters(filters); + QStringList list = dir.entryList(filters); + for (const QString &i : list) + ret << dname + QLatin1Char('/') + i; + } return ret; // return KGlobal::dirs()->findAllResources("data", // "konsole/*.colorscheme", @@ -726,7 +768,7 @@ bool ColorSchemeManager::deleteColorScheme(const QString& name) { Q_ASSERT( _colorSchemes.contains(name) ); - // lookup the path and delete + // lookup the path and delete QString path = findColorSchemePath(name); if ( QFile::remove(path) ) { @@ -742,16 +784,21 @@ bool ColorSchemeManager::deleteColorScheme(const QString& name) QString ColorSchemeManager::findColorSchemePath(const QString& name) const { // QString path = KStandardDirs::locate("data","konsole/"+name+".colorscheme"); - QString path(get_color_schemes_dir() + "/"+ name + ".colorscheme"); + const QStringList dirs = get_color_schemes_dirs(); + if ( dirs.isEmpty() ) + return QString(); + + const QString dir = dirs.first(); + QString path(dir + QLatin1Char('/')+ name + QLatin1String(".colorscheme")); if ( !path.isEmpty() ) - return path; + return path; //path = KStandardDirs::locate("data","konsole/"+name+".schema"); - path = get_color_schemes_dir() + "/"+ name + ".schema"; + path = dir + QLatin1Char('/')+ name + QLatin1String(".schema"); return path; } -const ColorScheme* ColorSchemeManager::findColorScheme(const QString& name) +const ColorScheme* ColorSchemeManager::findColorScheme(const QString& name) { if ( name.isEmpty() ) return defaultColorScheme(); @@ -761,12 +808,12 @@ const ColorScheme* ColorSchemeManager::findColorScheme(const QString& name) else { // look for this color scheme - QString path = findColorSchemePath(name); + QString path = findColorSchemePath(name); if ( !path.isEmpty() && loadColorScheme(path) ) { - return findColorScheme(name); - } - else + return findColorScheme(name); + } + else { if (!path.isEmpty() && loadKDE3ColorScheme(path)) return findColorScheme(name); @@ -774,15 +821,11 @@ const ColorScheme* ColorSchemeManager::findColorScheme(const QString& name) qDebug() << "Could not find color scheme - " << name; - return 0; + return 0; } } - -ColorSchemeManager* ColorSchemeManager::theColorSchemeManager = 0; -//K_GLOBAL_STATIC( ColorSchemeManager , theColorSchemeManager ) +Q_GLOBAL_STATIC(ColorSchemeManager, theColorSchemeManager) ColorSchemeManager* ColorSchemeManager::instance() { - if (! theColorSchemeManager) - theColorSchemeManager = new ColorSchemeManager(); return theColorSchemeManager; } diff --git a/lib/ColorScheme.h b/lib/ColorScheme.h index 3b5c211..f9e619b 100644 --- a/lib/ColorScheme.h +++ b/lib/ColorScheme.h @@ -40,16 +40,16 @@ namespace Konsole { /** - * Represents a color scheme for a terminal display. + * Represents a color scheme for a terminal display. * * The color scheme includes the palette of colors used to draw the text and character backgrounds - * in the display and the opacity level of the display background. + * in the display and the opacity level of the display background. */ class ColorScheme { public: - /** - * Constructs a new color scheme which is initialised to the default color set + /** + * Constructs a new color scheme which is initialised to the default color set * for Konsole. */ ColorScheme(); @@ -78,7 +78,7 @@ public: /** Sets a single entry within the color palette. */ void setColorTableEntry(int index , const ColorEntry& entry); - /** + /** * Copies the color entries which form the palette for this color scheme * into @p table. @p table should be an array with TABLE_COLORS entries. * @@ -88,7 +88,7 @@ public: * palette to be randomized. The seed is used to pick the random color. */ void getColorTable(ColorEntry* table, uint randomSeed = 0) const; - + /** * Retrieves a single color entry from the table. * @@ -96,28 +96,28 @@ public: */ ColorEntry colorEntry(int index , uint randomSeed = 0) const; - /** - * Convenience method. Returns the - * foreground color for this scheme, - * this is the primary color used to draw the + /** + * Convenience method. Returns the + * foreground color for this scheme, + * this is the primary color used to draw the * text in this scheme. */ QColor foregroundColor() const; /** - * Convenience method. Returns the background color for - * this scheme, this is the primary color used to + * Convenience method. Returns the background color for + * this scheme, this is the primary color used to * draw the terminal background in this scheme. */ QColor backgroundColor() const; - /** + /** * Returns true if this color scheme has a dark background. * The background color is said to be dark if it has a value of less than 127 * in the HSV color space. */ bool hasDarkBackground() const; - /** + /** * Sets the opacity level of the display background. @p opacity ranges * between 0 (completely transparent background) and 1 (completely * opaque background). @@ -127,18 +127,18 @@ public: * TODO: More documentation */ void setOpacity(qreal opacity); - /** + /** * Returns the opacity level for this color scheme, see setOpacity() * TODO: More documentation */ qreal opacity() const; - /** + /** * Enables randomization of the background color. This will cause * the palette returned by getColorTable() and colorEntry() to * be adjusted depending on the value of the random seed argument * to them. - */ + */ void setRandomizedBackgroundColor(bool randomize); /** Returns true if the background color is randomized. */ @@ -154,7 +154,7 @@ private: public: RandomizationRange() : hue(0) , saturation(0) , value(0) {} - bool isNull() const + bool isNull() const { return ( hue == 0 && saturation == 0 && value == 0 ); } @@ -172,14 +172,14 @@ private: // implemented upstream - user apps // reads a single colour entry from a KConfig source // and sets the palette entry at 'index' to the entry read. - void readColorEntry(KConfig& config , int index); + void readColorEntry(KConfig& config , int index); // writes a single colour entry to a KConfig source void writeColorEntry(KConfig& config , const QString& colorName, const ColorEntry& entry,const RandomizationRange& range) const; #endif void readColorEntry(QSettings *s, int index); - // sets the amount of randomization allowed for a particular color - // in the palette. creates the randomization table if + // sets the amount of randomization allowed for a particular color + // in the palette. creates the randomization table if // it does not already exist void setRandomizationRange( int index , quint16 hue , quint8 saturation , quint8 value ); @@ -202,7 +202,7 @@ private: static const ColorEntry defaultTable[]; // table of default color entries }; -/** +/** * A color scheme which uses colors from the standard KDE color palette. * * This is designed primarily for the benefit of users who are using specially @@ -228,13 +228,13 @@ public: class KDE3ColorSchemeReader { public: - /** - * Constructs a new reader which reads from the specified device. - * The device should be open in read-only mode. + /** + * Constructs a new reader which reads from the specified device. + * The device should be open in read-only mode. */ KDE3ColorSchemeReader( QIODevice* device ); - /** + /** * Reads and parses the contents of the .schema file from the input * device and returns the ColorScheme defined within it. * @@ -277,7 +277,7 @@ public: * Returns the default color scheme for Konsole */ const ColorScheme* defaultColorScheme() const; - + /** * Returns the color scheme with the given name or 0 if no * scheme with that name exists. If @p name is empty, the @@ -298,18 +298,18 @@ public: void addColorScheme(ColorScheme* scheme); #endif /** - * Deletes a color scheme. Returns true on successful deletion or false otherwise. + * Deletes a color scheme. Returns true on successful deletion or false otherwise. */ bool deleteColorScheme(const QString& name); - /** - * Returns a list of the all the available color schemes. + /** + * Returns a list of the all the available color schemes. * This may be slow when first called because all of the color * scheme resources on disk must be located, read and parsed. * - * Subsequent calls will be inexpensive. + * Subsequent calls will be inexpensive. */ - QList allColorSchemes(); + QList allColorSchemes(); /** Returns the global color scheme manager instance. */ static ColorSchemeManager* instance(); @@ -327,6 +327,14 @@ public: * @return Whether the color scheme is loaded successfully. */ bool loadCustomColorScheme(const QString& path); + + /** + * @brief Allows to add a custom location of color schemes. + * + * @param[in] custom_dir Custom location of color schemes (must end with /). + */ + void addCustomColorSchemeDir(const QString& custom_dir); + private: // loads a color scheme from a KDE 4+ .colorscheme file bool loadColorScheme(const QString& path); @@ -348,8 +356,6 @@ private: bool _haveLoadedAll; static const ColorScheme _defaultColorScheme; - - static ColorSchemeManager * theColorSchemeManager; }; } diff --git a/lib/Emulation.cpp b/lib/Emulation.cpp index edfd7b2..a81a2e8 100644 --- a/lib/Emulation.cpp +++ b/lib/Emulation.cpp @@ -1,5 +1,5 @@ /* - Copyright 2007-2008 Robert Knight + Copyright 2007-2008 Robert Knight Copyright 1997,1998 by Lars Doelle Copyright 1996 by Matthias Ettrich @@ -23,10 +23,10 @@ #include "Emulation.h" // System -#include #include #include #include +#include // Qt #include @@ -55,7 +55,8 @@ Emulation::Emulation() : _codec(0), _decoder(0), _keyTranslator(0), - _usesMouse(false) + _usesMouse(false), + _bracketedPasteMode(false) { // create screens with a default size _screen[0] = new Screen(40,80); @@ -64,10 +65,17 @@ Emulation::Emulation() : QObject::connect(&_bulkTimer1, SIGNAL(timeout()), this, SLOT(showBulk()) ); QObject::connect(&_bulkTimer2, SIGNAL(timeout()), this, SLOT(showBulk()) ); - + // listen for mouse status changes - connect( this , SIGNAL(programUsesMouseChanged(bool)) , - SLOT(usesMouseChanged(bool)) ); + connect(this , SIGNAL(programUsesMouseChanged(bool)) , + SLOT(usesMouseChanged(bool))); + connect(this , SIGNAL(programBracketedPasteModeChanged(bool)) , + SLOT(bracketedPasteModeChanged(bool))); + + connect(this, &Emulation::cursorChanged, [this] (KeyboardCursorShape cursorShape, bool blinkingCursorEnabled) { + emit titleChanged( 50, QString(QLatin1String("CursorShape=%1;BlinkingCursorEnabled=%2")) + .arg(static_cast(cursorShape)).arg(blinkingCursorEnabled) ); + }); } bool Emulation::programUsesMouse() const @@ -80,6 +88,16 @@ void Emulation::usesMouseChanged(bool usesMouse) _usesMouse = usesMouse; } +bool Emulation::programBracketedPasteMode() const +{ + return _bracketedPasteMode; +} + +void Emulation::bracketedPasteModeChanged(bool bracketedPasteMode) +{ + _bracketedPasteMode = bracketedPasteMode; +} + ScreenWindow* Emulation::createWindow() { ScreenWindow* window = new ScreenWindow(); @@ -112,10 +130,10 @@ void Emulation::setScreen(int n) { Screen *old = _currentScreen; _currentScreen = _screen[n & 1]; - if (_currentScreen != old) + 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); } } @@ -171,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 { @@ -191,12 +209,12 @@ void Emulation::receiveChar(int c) void Emulation::sendKeyEvent( QKeyEvent* ev ) { emit stateSet(NOTIFYNORMAL); - + if (!ev->text().isEmpty()) { // A block of text // Note that the text is proper unicode. // We should do a conversion here - emit sendData(ev->text().toUtf8(),ev->text().length()); + emit sendData(ev->text().toUtf8().constData(),ev->text().length()); } } @@ -220,12 +238,18 @@ void Emulation::receiveData(const char* text, int length) emit stateSet(NOTIFYACTIVITY); 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;iwriteLinesToStream(_decoder,startLine,endLine); } @@ -339,7 +363,7 @@ char Emulation::eraseChar() const void Emulation::setImageSize(int lines, int columns) { - if ((lines < 1) || (columns < 1)) + if ((lines < 1) || (columns < 1)) return; QSize screenSize[2] = { QSize(_screen[0]->getColumns(), @@ -349,7 +373,7 @@ void Emulation::setImageSize(int lines, int columns) QSize newSize(columns,lines); if (newSize == screenSize[0] && newSize == screenSize[1]) - return; + return; _screen[0]->resizeImage(lines,columns); _screen[1]->resizeImage(lines,columns); @@ -377,17 +401,17 @@ bool ExtendedCharTable::extendedCharMatch(ushort hash , ushort* unicodePoints , { ushort* entry = extendedCharTable[hash]; - // compare given length with stored sequence length ( given as the first ushort in the - // stored buffer ) - if ( entry == 0 || entry[0] != length ) + // compare given length with stored sequence length ( given as the first ushort in the + // stored buffer ) + if ( entry == 0 || entry[0] != length ) return false; // if the lengths match, each character must be checked. the stored buffer starts at // entry[1] for ( int i = 0 ; i < length ; i++ ) { if ( entry[i+1] != unicodePoints[i] ) - return false; - } + return false; + } return true; } ushort ExtendedCharTable::createExtendedChar(ushort* unicodePoints , ushort length) @@ -400,7 +424,7 @@ ushort ExtendedCharTable::createExtendedChar(ushort* unicodePoints , ushort leng { if ( extendedCharMatch(hash,unicodePoints,length) ) { - // this sequence already has an entry in the table, + // this sequence already has an entry in the table, // return its hash return hash; } @@ -410,16 +434,16 @@ ushort ExtendedCharTable::createExtendedChar(ushort* unicodePoints , ushort leng // points then try next hash hash++; } - } + } + - // add the new sequence to the table and // return that index ushort* buffer = new ushort[length+1]; buffer[0] = length; for ( int i = 0 ; i < length ; i++ ) - buffer[i+1] = unicodePoints[i]; - + buffer[i+1] = unicodePoints[i]; + extendedCharTable.insert(hash,buffer); return hash; diff --git a/lib/Emulation.h b/lib/Emulation.h index 5c1383e..95581b9 100644 --- a/lib/Emulation.h +++ b/lib/Emulation.h @@ -1,6 +1,6 @@ /* This file is part of Konsole, an X terminal. - + Copyright 2007-2008 by Robert Knight Copyright 1997,1998 by Lars Doelle @@ -26,7 +26,7 @@ // System #include -// Qt +// Qt #include //#include #include @@ -46,56 +46,56 @@ class Screen; class ScreenWindow; class TerminalCharacterDecoder; -/** - * This enum describes the available states which +/** + * This enum describes the available states which * the terminal emulation may be set to. * - * These are the values used by Emulation::stateChanged() + * These are the values used by Emulation::stateChanged() */ -enum -{ +enum +{ /** The emulation is currently receiving user input. */ - NOTIFYNORMAL=0, - /** + NOTIFYNORMAL=0, + /** * The terminal program has triggered a bell event * to get the user's attention. */ - NOTIFYBELL=1, - /** - * The emulation is currently receiving data from its + NOTIFYBELL=1, + /** + * The emulation is currently receiving data from its * terminal input. */ NOTIFYACTIVITY=2, - // unused here? - NOTIFYSILENCE=3 + // unused here? + NOTIFYSILENCE=3 }; /** * Base class for terminal emulation back-ends. * - * The back-end is responsible for decoding an incoming character stream and + * The back-end is responsible for decoding an incoming character stream and * producing an output image of characters. * * When input from the terminal is received, the receiveData() slot should be called with - * the data which has arrived. The emulation will process the data and update the + * the data which has arrived. The emulation will process the data and update the * screen image accordingly. The codec used to decode the incoming character stream - * into the unicode characters used internally can be specified using setCodec() + * into the unicode characters used internally can be specified using setCodec() * - * The size of the screen image can be specified by calling setImageSize() with the + * The size of the screen image can be specified by calling setImageSize() with the * desired number of lines and columns. When new lines are added, old content - * is moved into a history store, which can be set by calling setHistory(). + * is moved into a history store, which can be set by calling setHistory(). * - * The screen image can be accessed by creating a ScreenWindow onto this emulation - * by calling createWindow(). Screen windows provide access to a section of the - * output. Each screen window covers the same number of lines and columns as the + * The screen image can be accessed by creating a ScreenWindow onto this emulation + * by calling createWindow(). Screen windows provide access to a section of the + * output. Each screen window covers the same number of lines and columns as the * image size returned by imageSize(). The screen window can be moved up and down - * and provides transparent access to both the current on-screen image and the + * and provides transparent access to both the current on-screen image and the * previous output. The screen windows emit an outputChanged signal * when the section of the image they are looking at changes. * Graphical views can then render the contents of a screen window, listening for notifications - * of output changes from the screen window which they are associated with and updating - * accordingly. + * of output changes from the screen window which they are associated with and updating + * accordingly. * * The emulation also is also responsible for converting input from the connected views such * as keypresses and mouse activity into a character string which can be sent @@ -108,9 +108,9 @@ enum * character sequences. The name of the key bindings set used can be specified using * setKeyBindings() * - * The emulation maintains certain state information which changes depending on the - * input received. The emulation can be reset back to its starting state by calling - * reset(). + * The emulation maintains certain state information which changes depending on the + * input received. The emulation can be reset back to its starting state by calling + * reset(). * * The emulation also maintains an activity state, which specifies whether * terminal is currently active ( when data is received ), normal @@ -121,12 +121,32 @@ enum * a 'bell' event in different ways. */ class KONSOLEPRIVATE_EXPORT Emulation : public QObject -{ +{ Q_OBJECT public: - - /** Constructs a new terminal emulation */ + + /** + * This enum describes the available shapes for the keyboard cursor. + * See setKeyboardCursorShape() + */ + enum class KeyboardCursorShape { + /** A rectangular block which covers the entire area of the cursor character. */ + BlockCursor = 0, + /** + * A single flat line which occupies the space at the bottom of the cursor + * character's area. + */ + UnderlineCursor = 1, + /** + * An cursor shaped like the capital letter 'I', similar to the IBeam + * cursor used in Qt/KDE text editors. + */ + IBeamCursor = 2 + }; + + + /** Constructs a new terminal emulation */ Emulation(); ~Emulation(); @@ -142,15 +162,15 @@ public: /** * Returns the total number of lines, including those stored in the history. - */ + */ int lineCount() const; - /** + /** * Sets the history store used by this emulation. When new lines * are added to the output, older lines at the top of the screen are transferred to a history - * store. + * store. * - * The number of lines which are kept and the storage location depend on the + * The number of lines which are kept and the storage location depend on the * type of store. */ void setHistory(const HistoryType&); @@ -159,12 +179,12 @@ public: /** Clears the history scroll. */ void clearHistory(); - /** - * Copies the output history from @p startLine to @p endLine + /** + * Copies the output history from @p startLine to @p endLine * into @p stream, using @p decoder to convert the terminal - * characters into text. + * characters into text. * - * @param decoder A decoder which converts lines of terminal characters with + * @param decoder A decoder which converts lines of terminal characters with * appearance attributes into output text. PlainTextDecoder is the most commonly * used decoder. * @param startLine Index of first line to copy @@ -187,31 +207,31 @@ public: /** Sets the codec used to decode incoming characters. */ void setCodec(const QTextCodec*); - /** - * Convenience method. + /** + * Convenience method. * Returns true if the current codec used to decode incoming * characters is UTF-8 */ bool utf8() const { Q_ASSERT(_codec); return _codec->mibEnum() == 106; } - + /** TODO Document me */ virtual char eraseChar() const; - /** + /** * Sets the key bindings used to key events * ( received through sendKeyEvent() ) into character * streams to send to the terminal. */ void setKeyBindings(const QString& name); - /** + /** * Returns the name of the emulation's current key bindings. * See setKeyBindings() */ QString keyBindings() const; - /** + /** * Copies the current image into the history and clears the screen. */ virtual void clearEntireScreen() =0; @@ -219,7 +239,7 @@ public: /** Resets the state of the terminal. */ virtual void reset() =0; - /** + /** * Returns true if the active terminal program wants * mouse input events. * @@ -228,42 +248,44 @@ public: */ bool programUsesMouse() const; -public slots: + bool programBracketedPasteMode() const; + +public slots: /** Change the size of the emulation's image */ virtual void setImageSize(int lines, int columns); - - /** + + /** * Interprets a sequence of characters and sends the result to the terminal. * This is equivalent to calling sendKeyEvent() for each character in @p text in succession. */ virtual void sendText(const QString& text) = 0; - /** + /** * Interprets a key press event and emits the sendData() signal with - * the resulting character stream. + * the resulting character stream. */ virtual void sendKeyEvent(QKeyEvent*); - - /** + + /** * Converts information about a mouse event into an xterm-compatible escape * sequence and emits the character sequence via sendData() */ virtual void sendMouseEvent(int buttons, int column, int line, int eventType); - + /** - * Sends a string of characters to the foreground terminal process. + * Sends a string of characters to the foreground terminal process. * - * @param string The characters to send. + * @param string The characters to send. * @param length Length of @p string or if set to a negative value, @p string will * be treated as a null-terminated string and its length will be determined automatically. */ virtual void sendString(const char* string, int length = -1) = 0; - /** + /** * Processes an incoming stream of characters. receiveData() decodes the incoming * character buffer using the current codec(), and then calls receiveChar() for - * each unicode character in the resulting buffer. + * each unicode character in the resulting buffer. * * receiveData() also starts a timer which causes the outputChanged() signal * to be emitted when it expires. The timer allows multiple updates in quick @@ -276,8 +298,8 @@ public slots: signals: - /** - * Emitted when a buffer of data is ready to send to the + /** + * Emitted when a buffer of data is ready to send to the * standard input of the terminal. * * @param data The buffer of data ready to be sent @@ -285,20 +307,20 @@ signals: */ void sendData(const char* data,int len); - /** + /** * Requests that sending of input to the emulation * from the terminal process be suspended or resumed. * - * @param suspend If true, requests that sending of - * input from the terminal process' stdout be + * @param suspend If true, requests that sending of + * input from the terminal process' stdout be * suspended. Otherwise requests that sending of - * input be resumed. + * input be resumed. */ void lockPtyRequest(bool suspend); /** * Requests that the pty used by the terminal process - * be set to UTF 8 mode. + * be set to UTF 8 mode. * * TODO: More documentation */ @@ -326,7 +348,7 @@ signals: */ void changeTabTextColorRequest(int color); - /** + /** * This is emitted when the program running in the shell indicates whether or * not it is interested in mouse events. * @@ -335,7 +357,9 @@ signals: */ void programUsesMouseChanged(bool usesMouse); - /** + void programBracketedPasteModeChanged(bool bracketedPasteMode); + + /** * Emitted when the contents of the screen image change. * The emulation buffers the updates from successive image changes, * and only emits outputChanged() at sensible intervals when @@ -345,14 +369,14 @@ signals: * created with createWindow() to listen for this signal. * * ScreenWindow objects created using createWindow() will emit their - * own outputChanged() signal in response to this signal. + * own outputChanged() signal in response to this signal. */ void outputChanged(); /** - * Emitted when the program running in the terminal wishes to update the + * Emitted when the program running in the terminal wishes to update the * session's title. This also allows terminal programs to customize other - * aspects of the terminal emulation display. + * aspects of the terminal emulation display. * * This signal is emitted when the escape sequence "\033]ARG;VALUE\007" * is received in the input string, where ARG is a number specifying what @@ -360,7 +384,7 @@ signals: * * TODO: The name of this method is not very accurate since this method * is used to perform a whole range of tasks besides just setting - * the user-title of the session. + * the user-title of the session. * * @param title Specifies what to change. *
    @@ -369,16 +393,16 @@ signals: *
  • 2 - Set session title to @p newTitle
  • *
  • 11 - Set the session's default background color to @p newTitle, * where @p newTitle can be an HTML-style string ("#RRGGBB") or a named - * color (eg 'red', 'blue'). + * color (eg 'red', 'blue'). * See http://doc.trolltech.com/4.2/qcolor.html#setNamedColor for more * details. *
  • *
  • 31 - Supposedly treats @p newTitle as a URL and opens it (NOT IMPLEMENTED)
  • - *
  • 32 - Sets the icon associated with the session. @p newTitle is the name + *
  • 32 - Sets the icon associated with the session. @p newTitle is the name * of the icon to use, which can be the name of any icon in the current KDE icon * theme (eg: 'konsole', 'kate', 'folder_home')
  • *
- * @param newTitle Specifies the new title + * @param newTitle Specifies the new title */ void titleChanged(int title,const QString& newTitle); @@ -389,9 +413,21 @@ signals: */ void imageSizeChanged(int lineCount , int columnCount); - /** + /** + * Emitted when the setImageSize() is called on this emulation for + * the first time. + */ + void imageSizeInitialized(); + + /** + * Emitted after receiving the escape sequence which asks to change + * the terminal emulator's size + */ + void imageResizeRequest(const QSize& sizz); + + /** * Emitted when the terminal program requests to change various properties - * of the terminal display. + * of the terminal display. * * A profile change command occurs when a special escape sequence, followed * by a string containing a series of name and value pairs is received. @@ -402,31 +438,40 @@ signals: */ void profileChangeCommandReceived(const QString& text); - /** + /** * Emitted when a flow control key combination ( Ctrl+S or Ctrl+Q ) is pressed. * @param suspendKeyPressed True if Ctrl+S was pressed to suspend output or Ctrl+Q to * resume output. */ void flowControlKeyPressed(bool suspendKeyPressed); + /** + * Emitted when the cursor shape or its blinking state is changed via + * DECSCUSR sequences. + * + * @param cursorShape One of 3 possible values in KeyboardCursorShape enum + * @param blinkingCursorEnabled Whether to enable blinking or not + */ + void cursorChanged(KeyboardCursorShape cursorShape, bool blinkingCursorEnabled); + protected: virtual void setMode(int mode) = 0; virtual void resetMode(int mode) = 0; - - /** - * Processes an incoming character. See receiveData() - * @p ch A unicode character code. - */ - virtual void receiveChar(int ch); - /** + /** + * Processes an incoming character. See receiveData() + * @p ch A unicode character code. + */ + virtual void receiveChar(wchar_t ch); + + /** * Sets the active screen. The terminal has two screens, primary and alternate. * The primary screen is used by default. When certain interactive programs such * as Vim are run, they trigger a switch to the alternate screen. * * @param index 0 to switch to the primary screen, or 1 to switch to the alternate screen */ - void setScreen(int index); + void setScreen(int index); enum EmulationCodec { @@ -437,43 +482,46 @@ protected: QList _windows; - - Screen* _currentScreen; // pointer to the screen which is currently active, + + Screen* _currentScreen; // pointer to the screen which is currently active, // this is one of the elements in the screen[] array Screen* _screen[2]; // 0 = primary screen ( used by most programs, including the shell // scrollbars are enabled in this mode ) // 1 = alternate ( used by vi , emacs etc. // scrollbars are not enabled in this mode ) - - - //decodes an incoming C-style character stream into a unicode QString using + + + //decodes an incoming C-style character stream into a unicode QString using //the current text codec. (this allows for rendering of non-ASCII characters in text files etc.) const QTextCodec* _codec; QTextDecoder* _decoder; const KeyboardTranslator* _keyTranslator; // the keyboard layout protected slots: - /** + /** * Schedules an update of attached views. * Repeated calls to bufferedUpdate() in close succession will result in only a single update, - * much like the Qt buffered update of widgets. + * much like the Qt buffered update of widgets. */ void bufferedUpdate(); -private slots: +private slots: // triggered by timer, causes the emulation to send an updated screen image to each // view - void showBulk(); + void showBulk(); void usesMouseChanged(bool usesMouse); + void bracketedPasteModeChanged(bool bracketedPasteMode); + private: bool _usesMouse; + bool _bracketedPasteMode; QTimer _bulkTimer1; QTimer _bulkTimer2; - + }; } diff --git a/lib/Filter.cpp b/lib/Filter.cpp index 93de72c..3ed2aff 100644 --- a/lib/Filter.cpp +++ b/lib/Filter.cpp @@ -22,10 +22,12 @@ // System #include +#include // Qt #include #include +#include #include #include #include @@ -47,7 +49,7 @@ using namespace Konsole; FilterChain::~FilterChain() { QMutableListIterator iter(*this); - + while ( iter.hasNext() ) { Filter* filter = iter.next(); @@ -141,7 +143,7 @@ void TerminalImageFilterChain::setImage(const Character* const image , int lines PlainTextDecoder decoder; decoder.setTrailingWhitespace(false); - + // setup new shared buffers for the filters to process on QString* newBuffer = new QString(); QList* newLinePositions = new QList(); @@ -167,13 +169,13 @@ void TerminalImageFilterChain::setImage(const Character* const image , int lines // being treated as part of a link that occurs at the start of the next line // // the downside is that links which are spread over more than one line are not - // highlighted. + // highlighted. // // TODO - Use the "line wrapped" attribute associated with lines in a // terminal image to avoid adding this imaginary character for wrapped // lines if ( !(lineProperties.value(i,LINE_DEFAULT) & LINE_WRAPPED) ) - lineStream << QChar('\n'); + lineStream << QLatin1Char('\n'); } decoder.end(); } @@ -194,6 +196,15 @@ Filter::~Filter() } void Filter::reset() { + QListIterator iter(_hotspotList); + while (iter.hasNext()) + { + HotSpot* currentHotSpot = iter.next(); + if (currentHotSpot->hasAnotherParent()) { + continue; + } + delete currentHotSpot; + } _hotspots.clear(); _hotspotList.clear(); } @@ -219,15 +230,15 @@ void Filter::getLineColumn(int position , int& startLine , int& startColumn) else nextLine = _linePositions->value(i+1); - if ( _linePositions->value(i) <= position && position < nextLine ) + if ( _linePositions->value(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; } } } - + /*void Filter::addLine(const QString& text) { @@ -249,7 +260,7 @@ void Filter::addHotSpot(HotSpot* spot) for (int line = spot->startLine() ; line <= spot->endLine() ; line++) { _hotspots.insert(line,spot); - } + } } QList Filter::hotSpots() const { @@ -267,12 +278,12 @@ Filter::HotSpot* Filter::hotSpotAt(int line , int column) const while (spotIter.hasNext()) { HotSpot* spot = spotIter.next(); - + if ( spot->startLine() == line && spot->startColumn() > column ) continue; if ( spot->endLine() == line && spot->endColumn() < column ) continue; - + return spot; } @@ -280,19 +291,18 @@ Filter::HotSpot* Filter::hotSpotAt(int line , int column) const } Filter::HotSpot::HotSpot(int startLine , int startColumn , int endLine , int endColumn) - : _startLine(startLine) + : _hasAnotherParent(false) + , _startLine(startLine) , _startColumn(startColumn) , _endLine(endLine) , _endColumn(endColumn) , _type(NotSpecified) { } -QString Filter::HotSpot::tooltip() const -{ - return QString(); -} -QList Filter::HotSpot::actions() +QList Filter::HotSpot::actions(QWidget* parent) { + Q_UNUSED(parent); + return QList(); } int Filter::HotSpot::startLine() const @@ -343,7 +353,7 @@ QStringList RegExpFilter::HotSpot::capturedTexts() const return _capturedTexts; } -void RegExpFilter::setRegExp(const QRegExp& regExp) +void RegExpFilter::setRegExp(const QRegExp& regExp) { _searchText = regExp; } @@ -364,7 +374,7 @@ void RegExpFilter::process() // ignore any regular expressions which match an empty string. // otherwise the while loop below will run indefinitely - static const QString emptyString(""); + static const QString emptyString; if ( _searchText.exactMatch(emptyString) ) return; @@ -386,14 +396,14 @@ void RegExpFilter::process() endLine,endColumn); spot->setCapturedTexts(_searchText.capturedTexts()); - addHotSpot( spot ); + addHotSpot( spot ); pos += _searchText.matchedLength(); // if matchedLength == 0, the program will get stuck in an infinite loop if ( _searchText.matchedLength() == 0 ) pos = -1; } - } + } } RegExpFilter::HotSpot* RegExpFilter::newHotSpot(int startLine,int startColumn, @@ -407,7 +417,7 @@ RegExpFilter::HotSpot* UrlFilter::newHotSpot(int startLine,int startColumn,int e { HotSpot *spot = new UrlFilter::HotSpot(startLine,startColumn, endLine,endColumn); - connect(spot->getUrlObject(), SIGNAL(activated(QUrl)), this, SIGNAL(activated(QUrl))); + connect(spot->getUrlObject(), &FilterObject::activated, this, &UrlFilter::activated); return spot; } @@ -418,23 +428,10 @@ UrlFilter::HotSpot::HotSpot(int startLine,int startColumn,int endLine,int endCol setType(Link); } -QString UrlFilter::HotSpot::tooltip() const -{ - QString url = capturedTexts().first(); - - const UrlType kind = urlType(); - - if ( kind == StandardUrl ) - return QString(); - else if ( kind == Email ) - return QString(); - else - return QString(); -} UrlFilter::HotSpot::UrlType UrlFilter::HotSpot::urlType() const { - QString url = capturedTexts().first(); - + QString url = capturedTexts().constFirst(); + if ( FullUrlRegExp.exactMatch(url) ) return StandardUrl; else if ( EmailAddressRegExp.exactMatch(url) ) @@ -445,52 +442,52 @@ UrlFilter::HotSpot::UrlType UrlFilter::HotSpot::urlType() const void UrlFilter::HotSpot::activate(const QString& actionName) { - QString url = capturedTexts().first(); + QString url = capturedTexts().constFirst(); const UrlType kind = urlType(); - if ( actionName == "copy-action" ) + if ( actionName == QLatin1String("copy-action") ) { QApplication::clipboard()->setText(url); return; } - if ( actionName.isEmpty() || actionName == "open-action" ) + if ( actionName.isEmpty() || actionName == QLatin1String("open-action") || actionName == QLatin1String("click-action") ) { if ( kind == StandardUrl ) { // if the URL path does not include the protocol ( eg. "www.kde.org" ) then // prepend http:// ( eg. "www.kde.org" --> "http://www.kde.org" ) - if (!url.contains("://")) + if (!url.contains(QLatin1String("://"))) { - url.prepend("http://"); + url.prepend(QLatin1String("http://")); } - } + } else if ( kind == Email ) { - url.prepend("mailto:"); + url.prepend(QLatin1String("mailto:")); } - - _urlObject->emitActivated(url); + + _urlObject->emitActivated(QUrl(url, QUrl::StrictMode), actionName != QLatin1String("click-action")); } } -// Note: Altering these regular expressions can have a major effect on the performance of the filters +// Note: Altering these regular expressions can have a major effect on the performance of the filters // used for finding URLs in the text, especially if they are very general and could match very long // pieces of text. // Please be careful when altering them. //regexp matches: -// full url: +// full url: // protocolname:// or www. followed by anything other than whitespaces, <, >, ' or ", and ends before whitespaces, <, >, ', ", ], !, comma and dot -const QRegExp UrlFilter::FullUrlRegExp("(www\\.(?!\\.)|[a-z][a-z0-9+.-]*://)[^\\s<>'\"]+[^!,\\.\\s<>'\"\\]]"); +const QRegExp UrlFilter::FullUrlRegExp(QLatin1String("(www\\.(?!\\.)|[a-z][a-z0-9+.-]*://)[^\\s<>'\"]+[^!,\\.\\s<>'\"\\]]")); // email address: // [word chars, dots or dashes]@[word chars, dots or dashes].[word chars] -const QRegExp UrlFilter::EmailAddressRegExp("\\b(\\w|\\.|-)+@(\\w|\\.|-)+\\.\\w+\\b"); +const QRegExp UrlFilter::EmailAddressRegExp(QLatin1String("\\b(\\w|\\.|-)+@(\\w|\\.|-)+\\.\\w+\\b")); // matches full url or email address -const QRegExp UrlFilter::CompleteUrlRegExp('('+FullUrlRegExp.pattern()+'|'+ - EmailAddressRegExp.pattern()+')'); +const QRegExp UrlFilter::CompleteUrlRegExp(QLatin1Char('(')+FullUrlRegExp.pattern()+QLatin1Char('|')+ + EmailAddressRegExp.pattern()+QLatin1Char(')')); UrlFilter::UrlFilter() { @@ -502,12 +499,12 @@ UrlFilter::HotSpot::~HotSpot() delete _urlObject; } -void FilterObject::emitActivated(const QUrl& url) +void FilterObject::emitActivated(const QUrl& url, bool fromContextMenu) { - emit activated(url); + emit activated(url, fromContextMenu); } -void FilterObject::activated() +void FilterObject::activate() { _filter->activate(sender()->objectName()); } @@ -517,14 +514,28 @@ FilterObject* UrlFilter::HotSpot::getUrlObject() const return _urlObject; } -QList UrlFilter::HotSpot::actions() +class UrlAction : public QAction { +public: + UrlAction(QWidget* parent, std::shared_ptr hotspotPtr) + : QAction(parent) + , _hotspotPtr(hotspotPtr) + { + } + +private: + std::shared_ptr _hotspotPtr; +}; + +QList UrlFilter::HotSpot::actions(QWidget* parent) { + this->_hasAnotherParent = true; QList list; const UrlType kind = urlType(); - QAction* openAction = new QAction(_urlObject); - QAction* copyAction = new QAction(_urlObject);; + std::shared_ptr hotspotPtr(this); + UrlAction* openAction = new UrlAction(parent, hotspotPtr); + UrlAction* copyAction = new UrlAction(parent, hotspotPtr); Q_ASSERT( kind == StandardUrl || kind == Email ); @@ -545,13 +556,13 @@ QList UrlFilter::HotSpot::actions() openAction->setObjectName( QLatin1String("open-action" )); copyAction->setObjectName( QLatin1String("copy-action" )); - QObject::connect( openAction , SIGNAL(triggered()) , _urlObject , SLOT(activated()) ); - QObject::connect( copyAction , SIGNAL(triggered()) , _urlObject , SLOT(activated()) ); + QObject::connect( openAction , &QAction::triggered , _urlObject , &FilterObject::activate ); + QObject::connect( copyAction , &QAction::triggered , _urlObject , &FilterObject::activate ); list << openAction; list << copyAction; - return list; + return list; } //#include "Filter.moc" diff --git a/lib/Filter.h b/lib/Filter.h index 161773b..bb411ef 100644 --- a/lib/Filter.h +++ b/lib/Filter.h @@ -46,7 +46,7 @@ class Character; * activate() method should be called. Depending on the type of hotspot this will trigger a suitable response. * * For example, if a hotspot represents a URL then a suitable action would be opening that URL in a web browser. - * Hotspots may have more than one action, in which case the list of actions can be obtained using the + * Hotspots may have more than one action, in which case the list of actions can be obtained using the * actions() method. * * Different subclasses of filter will return different types of hotspot. @@ -66,13 +66,13 @@ public: * activate() method should be called. Depending on the type of hotspot this will trigger a suitable response. * * For example, if a hotspot represents a URL then a suitable action would be opening that URL in a web browser. - * Hotspots may have more than one action, in which case the list of actions can be obtained using the - * actions() method. These actions may then be displayed in a popup menu or toolbar for example. + * Hotspots may have more than one action, in which case the list of actions can be obtained using the + * actions() method. These actions may then be displayed in a popup menu or toolbar for example. */ class HotSpot { public: - /** + /** * Constructs a new hotspot which covers the area from (@p startLine,@p startColumn) to (@p endLine,@p endColumn) * in a block of text. */ @@ -87,7 +87,7 @@ public: Link, // this hotspot represents a marker Marker - }; + }; /** Returns the line when the hotspot area starts */ int startLine() const; @@ -97,45 +97,40 @@ public: int startColumn() const; /** Returns the column on endLine() where the hotspot area ends */ int endColumn() const; - /** + /** * Returns the type of the hotspot. This is usually used as a hint for views on how to represent * the hotspot graphically. eg. Link hotspots are typically underlined when the user mouses over them */ Type type() const; - /** - * Causes the an action associated with a hotspot to be triggered. + /** + * Causes the an action associated with a hotspot to be triggered. * * @param action The action to trigger. This is * typically empty ( in which case the default action should be performed ) or * one of the object names from the actions() list. In which case the associated - * action should be performed. + * action should be performed. */ virtual void activate(const QString& action = QString()) = 0; - /** - * Returns a list of actions associated with the hotspot which can be used in a - * menu or toolbar + /** + * Returns a list of actions associated with the hotspot which can be used in a + * menu or toolbar */ - virtual QList actions(); + virtual QList actions(QWidget* parent); - /** - * Returns the text of a tooltip to be shown when the mouse moves over the hotspot, or - * an empty string if there is no tooltip associated with this hotspot. - * - * The default implementation returns an empty string. - */ - virtual QString tooltip() const; + bool hasAnotherParent() const { return _hasAnotherParent; } protected: /** Sets the type of a hotspot. This should only be set once */ void setType(Type type); + bool _hasAnotherParent; + private: int _startLine; int _startColumn; int _endLine; int _endColumn; Type _type; - }; /** Constructs a new filter. */ @@ -145,9 +140,9 @@ public: /** Causes the filter to process the block of text currently in its internal buffer */ virtual void process() = 0; - /** + /** * Empties the filters internal buffer and resets the line count back to 0. - * All hotspots are deleted. + * All hotspots are deleted. */ void reset(); @@ -163,7 +158,7 @@ public: /** Returns the list of hotspots identified by the filter which occur on a given line */ QList hotSpotsAtLine(int line) const; - /** + /** * TODO: Document me */ void setBuffer(const QString* buffer , const QList* linePositions); @@ -179,22 +174,22 @@ protected: private: QMultiHash _hotspots; QList _hotspotList; - + const QList* _linePositions; const QString* _buffer; }; -/** - * A filter which searches for sections of text matching a regular expression and creates a new RegExpFilter::HotSpot +/** + * A filter which searches for sections of text matching a regular expression and creates a new RegExpFilter::HotSpot * instance for them. * * Subclasses can reimplement newHotSpot() to return custom hotspot types when matches for the regular expression - * are found. + * are found. */ class RegExpFilter : public Filter { public: - /** + /** * Type of hotspot created by RegExpFilter. The capturedTexts() method can be used to find the text * matched by the filter's regular expression. */ @@ -215,26 +210,26 @@ public: /** Constructs a new regular expression filter */ RegExpFilter(); - /** - * Sets the regular expression which the filter searches for in blocks of text. + /** + * Sets the regular expression which the filter searches for in blocks of text. * * Regular expressions which match the empty string are treated as not matching - * anything. + * anything. */ void setRegExp(const QRegExp& text); /** Returns the regular expression which the filter searches for in blocks of text */ QRegExp regExp() const; - /** - * Reimplemented to search the filter's text buffer for text matching regExp() + /** + * Reimplemented to search the filter's text buffer for text matching regExp() * * If regexp matches the empty string, then process() will return immediately - * without finding results. + * without finding results. */ virtual void process(); protected: - /** + /** * Called when a match for the regular expression is encountered. Subclasses should reimplement this * to return custom hotspot types */ @@ -248,15 +243,15 @@ private: class FilterObject; /** A filter which matches URLs in blocks of text */ -class UrlFilter : public RegExpFilter +class UrlFilter : public RegExpFilter { Q_OBJECT public: - /** - * Hotspot type created by UrlFilter instances. The activate() method opens a web browser + /** + * Hotspot type created by UrlFilter instances. The activate() method opens a web browser * at the given URL when called. */ - class HotSpot : public RegExpFilter::HotSpot + class HotSpot : public RegExpFilter::HotSpot { public: HotSpot(int startLine,int startColumn,int endLine,int endColumn); @@ -264,15 +259,14 @@ public: FilterObject* getUrlObject() const; - virtual QList actions(); + virtual QList actions(QWidget* parent); - /** + /** * Open a web browser at the current URL. The url itself can be determined using * the capturedTexts() method. */ virtual void activate(const QString& action = QString()); - virtual QString tooltip() const; private: enum UrlType { @@ -291,14 +285,14 @@ protected: virtual RegExpFilter::HotSpot* newHotSpot(int,int,int,int); private: - + static const QRegExp FullUrlRegExp; static const QRegExp EmailAddressRegExp; // combined OR of FullUrlRegExp and EmailAddressRegExp - static const QRegExp CompleteUrlRegExp; + static const QRegExp CompleteUrlRegExp; signals: - void activated(const QUrl& url); + void activated(const QUrl& url, bool fromContextMenu); }; class FilterObject : public QObject @@ -307,20 +301,20 @@ class FilterObject : public QObject public: FilterObject(Filter::HotSpot* filter) : _filter(filter) {} - void emitActivated(const QUrl& url); -private slots: - void activated(); + void emitActivated(const QUrl& url, bool fromContextMenu); +public slots: + void activate(); private: Filter::HotSpot* _filter; signals: - void activated(const QUrl& url); + void activated(const QUrl& url, bool fromContextMenu); }; -/** - * A chain which allows a group of filters to be processed as one. +/** + * A chain which allows a group of filters to be processed as one. * The chain owns the filters added to it and deletes them when the chain itself is destroyed. * - * Use addFilter() to add a new filter to the chain. + * Use addFilter() to add a new filter to the chain. * When new text to be filtered arrives, use addLine() to add each additional * line of text which needs to be processed and then after adding the last line, use * process() to cause each filter in the chain to process the text. @@ -350,12 +344,12 @@ public: /** Resets each filter in the chain */ void reset(); /** - * Processes each filter in the chain + * Processes each filter in the chain */ void process(); /** Sets the buffer for each filter in the chain to process. */ - void setBuffer(const QString* buffer , const QList* linePositions); + void setBuffer(const QString* buffer , const QList* linePositions); /** Returns the first hotspot which occurs at @p line, @p column or 0 if no hotspot was found */ Filter::HotSpot* hotSpotAt(int line , int column) const; @@ -382,7 +376,7 @@ public: * @param lineProperties The line properties to set for image */ void setImage(const Character* const image , int lines , int columns, - const QVector& lineProperties); + const QVector& lineProperties); private: QString* _buffer; diff --git a/lib/History.cpp b/lib/History.cpp index 0f9c13f..b297b0e 100644 --- a/lib/History.cpp +++ b/lib/History.cpp @@ -24,7 +24,6 @@ // System #include #include -#include #include #include #include @@ -93,7 +92,7 @@ HistoryFile::HistoryFile() fileMap(0) { if (tmpFile.open()) - { + { tmpFile.setAutoRemove(true); ion = tmpFile.handle(); } @@ -110,28 +109,28 @@ HistoryFile::~HistoryFile() //to avoid this. void HistoryFile::map() { - assert( fileMap == 0 ); + Q_ASSERT( fileMap == 0 ); fileMap = (char*)mmap( 0 , length , PROT_READ , MAP_PRIVATE , ion , 0 ); //if mmap'ing fails, fall back to the read-lseek combination if ( fileMap == MAP_FAILED ) { - readWriteBalance = 0; + readWriteBalance = 0; fileMap = 0; - qDebug() << __FILE__ << __LINE__ << ": mmap'ing history failed. errno = " << errno; + //qDebug() << __FILE__ << __LINE__ << ": mmap'ing history failed. errno = " << errno; } } void HistoryFile::unmap() { int result = munmap( fileMap , length ); - assert( result == 0 ); Q_UNUSED( result ); + Q_ASSERT( result == 0 ); Q_UNUSED( result ); fileMap = 0; } -bool HistoryFile::isMapped() +bool HistoryFile::isMapped() const { return (fileMap != 0); } @@ -140,7 +139,7 @@ void HistoryFile::add(const unsigned char* bytes, int len) { if ( fileMap ) unmap(); - + readWriteBalance++; int rc = 0; @@ -152,8 +151,8 @@ void HistoryFile::add(const unsigned char* bytes, int len) void HistoryFile::get(unsigned char* bytes, int len, int loc) { - //count number of get() calls vs. number of add() calls. - //If there are many more get() calls compared with add() + //count number of get() calls vs. number of add() calls. + //If there are many more get() calls compared with add() //calls (decided by using MAP_THRESHOLD) then mmap the log //file to improve performance. readWriteBalance--; @@ -166,7 +165,7 @@ void HistoryFile::get(unsigned char* bytes, int len, int loc) bytes[i]=fileMap[loc+i]; } else - { + { int rc = 0; if (loc < 0 || len < 0 || loc + len > length) @@ -202,7 +201,7 @@ bool HistoryScroll::hasScroll() // History Scroll File ////////////////////////////////////// -/* +/* The history scroll makes a Row(Row(Cell)) from two history buffers. The index buffer contains start of line positions which refere to the cells @@ -222,7 +221,7 @@ HistoryScrollFile::HistoryScrollFile(const QString &logFileName) HistoryScrollFile::~HistoryScrollFile() { } - + int HistoryScrollFile::getLines() { return index.len() / sizeof(int); @@ -247,11 +246,11 @@ int HistoryScrollFile::startOfLine(int lineno) { if (lineno <= 0) return 0; if (lineno <= getLines()) - { - + { + if (!index.isMapped()) index.map(); - + int res; index.get((unsigned char*)&res,sizeof(int),(lineno-1)*sizeof(int)); return res; @@ -346,7 +345,7 @@ int HistoryScrollBuffer::getLineLen(int lineNumber) bool HistoryScrollBuffer::isWrappedLine(int lineNumber) { Q_ASSERT( lineNumber >= 0 && lineNumber < _maxLineCount ); - + if (lineNumber < _usedLines) { //kDebug() << "Line" << lineNumber << "wrapped is" << _wrappedLine[bufferIndex(lineNumber)]; @@ -362,12 +361,12 @@ void HistoryScrollBuffer::getCells(int lineNumber, int startColumn, int count, C Q_ASSERT( lineNumber < _maxLineCount ); - if (lineNumber >= _usedLines) + if (lineNumber >= _usedLines) { - memset(buffer, 0, count * sizeof(Character)); + memset(static_cast(buffer), 0, count * sizeof(Character)); return; } - + const HistoryLine& line = _historyBuffer[bufferIndex(lineNumber)]; //kDebug() << "startCol " << startColumn; @@ -375,7 +374,7 @@ void HistoryScrollBuffer::getCells(int lineNumber, int startColumn, int count, C //kDebug() << "count " << count; Q_ASSERT( startColumn <= line.size() - count ); - + memcpy(buffer, line.constData() + startColumn , count * sizeof(Character)); } @@ -383,12 +382,12 @@ void HistoryScrollBuffer::setMaxNbLines(unsigned int lineCount) { HistoryLine* oldBuffer = _historyBuffer; HistoryLine* newBuffer = new HistoryLine[lineCount]; - + for ( int i = 0 ; i < qMin(_usedLines,(int)lineCount) ; i++ ) { newBuffer[i] = oldBuffer[bufferIndex(i)]; } - + _usedLines = qMin(_usedLines,(int)lineCount); _maxLineCount = lineCount; _head = ( _usedLines == _maxLineCount ) ? 0 : _usedLines-1; @@ -411,7 +410,7 @@ int HistoryScrollBuffer::bufferIndex(int lineNumber) return (_head+lineNumber+1) % _maxLineCount; } else - { + { return lineNumber; } } @@ -498,30 +497,30 @@ void HistoryScrollBlockArray::getCells(int lineno, int colno, const Block *b = m_blockArray.at(lineno); if (!b) { - memset(res, 0, count * sizeof(Character)); // still better than random data + memset(static_cast(res), 0, count * sizeof(Character)); // still better than random data return; } - assert(((colno + count) * sizeof(Character)) < ENTRIES); + Q_ASSERT(((colno + count) * sizeof(Character)) < ENTRIES); memcpy(res, b->data + (colno * sizeof(Character)), count * sizeof(Character)); } void HistoryScrollBlockArray::addCells(const Character a[], int count) { Block *b = m_blockArray.lastBlock(); - + if (!b) return; // put cells in block's data - assert((count * sizeof(Character)) < ENTRIES); + Q_ASSERT((count * sizeof(Character)) < ENTRIES); - memset(b->data, 0, ENTRIES); + memset(b->data, 0, sizeof(b->data)); memcpy(b->data, a, count * sizeof(Character)); b->size = count * sizeof(Character); size_t res = m_blockArray.newBlock(); - assert (res > 0); + Q_ASSERT(res > 0); Q_UNUSED( res ); m_lineLengths.insert(m_blockArray.getCurrent(), count); @@ -573,17 +572,17 @@ void* CompactHistoryBlockList::allocate(size_t size) void CompactHistoryBlockList::deallocate(void* ptr) { Q_ASSERT( !list.isEmpty()); - - int i=0; + + int i=0; CompactHistoryBlock *block = list.at(i); while ( icontains(ptr) ) - { + { i++; block=list.at(i); } Q_ASSERT( ideallocate(); if (!block->isInUse()) @@ -605,16 +604,16 @@ void* CompactHistoryLine::operator new (size_t size, CompactHistoryBlockList& bl return blockList.allocate(size); } -CompactHistoryLine::CompactHistoryLine ( const TextLine& line, CompactHistoryBlockList& bList ) +CompactHistoryLine::CompactHistoryLine ( const TextLine& line, CompactHistoryBlockList& bList ) : blockList(bList), formatLength(0) { length=line.size(); - + if (line.size() > 0) { formatLength=1; int k=1; - + // count number of different formats in this text line Character c = line[0]; while ( k(old)) + if (dynamic_cast(old)) return old; // Unchanged. HistoryScroll *newScroll = new HistoryScrollFile(m_fileName); @@ -946,7 +944,7 @@ HistoryScroll* HistoryTypeFile::scroll(HistoryScroll *old) const } delete old; - return newScroll; + return newScroll; } int HistoryTypeFile::maximumLineCount() const diff --git a/lib/History.h b/lib/History.h index 3f2a134..d921a86 100644 --- a/lib/History.h +++ b/lib/History.h @@ -60,7 +60,7 @@ public: //un-mmaps the file void unmap(); //returns true if the file is mmap'ed - bool isMapped(); + bool isMapped() const; private: @@ -70,7 +70,7 @@ private: //pointer to start of mmap'ed file data, or 0 if the file is not mmap'ed char* fileMap; - + //incremented whenver 'add' is called and decremented whenever //'get' is called. //this is used to detect when a large number of lines are being read and processed from the history @@ -180,8 +180,8 @@ public: virtual void addLine(bool previousWrapped=false); void setMaxNbLines(unsigned int nbLines); - unsigned int maxNbLines() { return _maxLineCount; } - + unsigned int maxNbLines() const { return _maxLineCount; } + private: int bufferIndex(int lineNumber); @@ -189,9 +189,9 @@ private: HistoryLine* _historyBuffer; QBitArray _wrappedLine; int _maxLineCount; - int _usedLines; + int _usedLines; int _head; - + //QVector m_histBuffer; //QBitArray m_wrappedLine; //unsigned int m_maxNbLines; @@ -290,7 +290,7 @@ public: class CompactHistoryBlock { public: - + CompactHistoryBlock(){ blockLength = 4096*64; // 256kb head = (quint8*) mmap(0, blockLength, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0); @@ -299,12 +299,12 @@ public: tail = blockStart = head; allocCount=0; } - + virtual ~CompactHistoryBlock(){ //free(blockStart); munmap(blockStart, blockLength); } - + virtual unsigned int remaining(){ return blockStart+blockLength-tail;} virtual unsigned length() { return blockLength; } virtual void* allocate(size_t length); @@ -381,7 +381,7 @@ private: bool hasDifferentColors(const TextLine& line) const; HistoryArray lines; CompactHistoryBlockList blockList; - + unsigned int _maxLineCount; }; @@ -397,7 +397,7 @@ public: /** * Returns true if the history is enabled ( can store lines of output ) - * or false otherwise. + * or false otherwise. */ virtual bool isEnabled() const = 0; /** @@ -428,7 +428,7 @@ class HistoryTypeBlockArray : public HistoryType { public: HistoryTypeBlockArray(size_t size); - + virtual bool isEnabled() const; virtual int maximumLineCount() const; @@ -438,7 +438,7 @@ protected: size_t m_size; }; -#if 1 +#if 1 class HistoryTypeFile : public HistoryType { public: @@ -461,10 +461,10 @@ class HistoryTypeBuffer : public HistoryType public: HistoryTypeBuffer(unsigned int nbLines); - + virtual bool isEnabled() const; virtual int maximumLineCount() const; - + virtual HistoryScroll* scroll(HistoryScroll *) const; protected: @@ -475,7 +475,7 @@ class CompactHistoryType : public HistoryType { public: CompactHistoryType(unsigned int size); - + virtual bool isEnabled() const; virtual int maximumLineCount() const; diff --git a/lib/HistorySearch.cpp b/lib/HistorySearch.cpp index 05bedf3..41c514f 100644 --- a/lib/HistorySearch.cpp +++ b/lib/HistorySearch.cpp @@ -40,7 +40,7 @@ HistorySearch::~HistorySearch() { void HistorySearch::search() { bool found = false; - + if (! m_regExp.isEmpty()) { if (m_forwards) { @@ -48,10 +48,10 @@ void HistorySearch::search() { } else { found = search(0, 0, m_startColumn, m_startLine) || search(m_startColumn, m_startLine, -1, m_emulation->lineCount()); } - + if (found) { emit matchFound(m_foundStartColumn, m_foundStartLine, m_foundEndColumn, m_foundEndLine); - } + } else { emit noMatchFound(); } @@ -61,43 +61,43 @@ void HistorySearch::search() { } bool HistorySearch::search(int startColumn, int startLine, int endColumn, int endLine) { - qDebug() << "search from" << startColumn << "," << startLine + qDebug() << "search from" << startColumn << "," << startLine << "to" << endColumn << "," << endLine; - + int linesRead = 0; int linesToRead = endLine - startLine + 1; - + qDebug() << "linesToRead:" << linesToRead; - - // We read process history from (and including) startLine to (and including) endLine in + + // We read process history from (and including) startLine to (and including) endLine in // blocks of at most 10K lines so that we do not use unhealthy amounts of memory int blockSize; while ((blockSize = qMin(10000, linesToRead - linesRead)) > 0) { - + QString string; - QTextStream searchStream(&string); - PlainTextDecoder decoder; + QTextStream searchStream(&string); + PlainTextDecoder decoder; decoder.begin(&searchStream); decoder.setRecordLinePositions(true); - // Calculate lines to read and read them - int blockStartLine = m_forwards ? startLine + linesRead : endLine - linesRead - blockSize + 1; + // Calculate lines to read and read them + int blockStartLine = m_forwards ? startLine + linesRead : endLine - linesRead - blockSize + 1; int chunkEndLine = blockStartLine + blockSize - 1; m_emulation->writeToStream(&decoder, blockStartLine, chunkEndLine); - - // We search between startColumn in the first line of the string and endColumn in the last - // line of the string. First we calculate the position (in the string) of endColumn in the + + // We search between startColumn in the first line of the string and endColumn in the last + // line of the string. First we calculate the position (in the string) of endColumn in the // last line of the string int endPosition; - - // The String that Emulator.writeToStream produces has a newline at the end, and so ends with an + + // The String that Emulator.writeToStream produces has a newline at the end, and so ends with an // empty line - we ignore that. - int numberOfLinesInString = decoder.linePositions().size() - 1; + int numberOfLinesInString = decoder.linePositions().size() - 1; if (numberOfLinesInString > 0 && endColumn > -1 ) { endPosition = decoder.linePositions().at(numberOfLinesInString - 1) + endColumn; } - else + else { endPosition = string.size(); } @@ -116,12 +116,12 @@ bool HistorySearch::search(int startColumn, int startLine, int endColumn, int en if (matchStart < startColumn) matchStart = -1; } - - if (matchStart > -1) + + if (matchStart > -1) { int matchEnd = matchStart + m_regExp.matchedLength() - 1; qDebug() << "Found in string from" << matchStart << "to" << matchEnd; - + // Translate startPos and endPos to startColum, startLine, endColumn and endLine in history. int startLineNumberInString = findLineNumberInString(decoder.linePositions(), matchStart); m_foundStartColumn = matchStart - decoder.linePositions().at(startLineNumberInString); @@ -136,17 +136,17 @@ bool HistorySearch::search(int startColumn, int startLine, int endColumn, int en << "m_foundEndColumn" << m_foundEndColumn << "m_foundEndLine" << m_foundEndLine; - return true; + return true; } - - + + linesRead += blockSize; } - + qDebug() << "Not found"; return false; } - + int HistorySearch::findLineNumberInString(QList linePositions, int position) { int lineNum = 0; @@ -154,4 +154,4 @@ int HistorySearch::findLineNumberInString(QList linePositions, int position lineNum++; return lineNum; -} \ No newline at end of file +} diff --git a/lib/HistorySearch.h b/lib/HistorySearch.h index c315299..e019650 100644 --- a/lib/HistorySearch.h +++ b/lib/HistorySearch.h @@ -38,7 +38,7 @@ class HistorySearch : public QObject Q_OBJECT public: - explicit HistorySearch(EmulationPtr emulation, QRegExp regExp, bool forwards, + explicit HistorySearch(EmulationPtr emulation, QRegExp regExp, bool forwards, int startColumn, int startLine, QObject* parent); ~HistorySearch(); @@ -49,11 +49,11 @@ signals: void matchFound(int startColumn, int startLine, int endColumn, int endLine); void noMatchFound(); -private: +private: bool search(int startColumn, int startLine, int endColumn, int endLine); int findLineNumberInString(QList linePositions, int position); - - + + EmulationPtr m_emulation; QRegExp m_regExp; bool m_forwards; diff --git a/lib/KeyboardTranslator.cpp b/lib/KeyboardTranslator.cpp index 46f035c..6b555a1 100644 --- a/lib/KeyboardTranslator.cpp +++ b/lib/KeyboardTranslator.cpp @@ -60,7 +60,7 @@ KeyboardTranslatorManager::~KeyboardTranslatorManager() } QString KeyboardTranslatorManager::findTranslatorPath(const QString& name) { - return QString(get_kb_layout_dir() + name + ".keytab"); + return QString(get_kb_layout_dir() + name + QLatin1String(".keytab")); //return KGlobal::dirs()->findResource("data","konsole/"+name+".keytab"); } @@ -68,7 +68,7 @@ void KeyboardTranslatorManager::findTranslators() { QDir dir(get_kb_layout_dir()); QStringList filters; - filters << "*.keytab"; + filters << QLatin1String("*.keytab"); dir.setNameFilters(filters); QStringList list = dir.entryList(filters); list = dir.entryList(filters); @@ -85,8 +85,8 @@ void KeyboardTranslatorManager::findTranslators() QString translatorPath = listIter.next(); QString name = QFileInfo(translatorPath).baseName(); - - if ( !_translators.contains(name) ) + + if ( !_translators.contains(name) ) _translators.insert(name,0); } @@ -124,7 +124,7 @@ Q_UNUSED(translator); QFile destination(path); if (!destination.open(QIODevice::WriteOnly | QIODevice::Text)) { - qDebug() << "Unable to save keyboard translation:" + qDebug() << "Unable to save keyboard translation:" << destination.errorString(); return false; } @@ -132,7 +132,7 @@ Q_UNUSED(translator); { KeyboardTranslatorWriter writer(&destination); writer.writeHeader(translator->description()); - + QListIterator iter(translator->entries()); while ( iter.hasNext() ) writer.writeEntry(iter.next()); @@ -147,7 +147,7 @@ KeyboardTranslator* KeyboardTranslatorManager::loadTranslator(const QString& nam { const QString& path = findTranslatorPath(name); - QFile source(path); + QFile source(path); if (name.isEmpty() || !source.open(QIODevice::ReadOnly | QIODevice::Text)) return 0; @@ -158,13 +158,13 @@ const KeyboardTranslator* KeyboardTranslatorManager::defaultTranslator() { // Try to find the default.keytab file if it exists, otherwise // fall back to the hard-coded one - const KeyboardTranslator* translator = findTranslator("default"); + const KeyboardTranslator* translator = findTranslator(QLatin1String("default")); if (!translator) { QBuffer textBuffer; textBuffer.setData(defaultTranslatorText); textBuffer.open(QIODevice::ReadOnly); - translator = loadTranslator(&textBuffer,"fallback"); + translator = loadTranslator(&textBuffer,QLatin1String("fallback")); } return translator; } @@ -211,9 +211,9 @@ void KeyboardTranslatorWriter::writeEntry( const KeyboardTranslator::Entry& entr if ( entry.command() != KeyboardTranslator::NoCommand ) result = entry.resultToString(); else - result = '\"' + entry.resultToString() + '\"'; + result = QLatin1Char('\"') + entry.resultToString() + QLatin1Char('\"'); - *_writer << "key " << entry.conditionToString() << " : " << result << '\n'; + *_writer << QLatin1String("key ") << entry.conditionToString() << QLatin1String(" : ") << result << QLatin1Char('\n'); } @@ -226,7 +226,7 @@ void KeyboardTranslatorWriter::writeEntry( const KeyboardTranslator::Entry& entr // KeySequence begins with the name of the key ( taken from the Qt::Key enum ) // and is followed by the keyboard modifiers and state flags ( with + or - in front // of each modifier or flag to indicate whether it is required ). All keyboard modifiers -// and flags are optional, if a particular modifier or state is not specified it is +// and flags are optional, if a particular modifier or state is not specified it is // assumed not to be a part of the sequence. The key sequence may contain whitespace // // eg: "key Up+Shift : scrollLineUp" @@ -243,19 +243,19 @@ KeyboardTranslatorReader::KeyboardTranslatorReader( QIODevice* source ) // read input until we find the description while ( _description.isEmpty() && !source->atEnd() ) { - QList tokens = tokenize( QString(source->readLine()) ); + QList tokens = tokenize( QString::fromUtf8(source->readLine()) ); if ( !tokens.isEmpty() && tokens.first().type == Token::TitleKeyword ) - _description = tokens[1].text.toUtf8(); + _description = tokens[1].text; } // read first entry (if any) readNext(); } -void KeyboardTranslatorReader::readNext() +void KeyboardTranslatorReader::readNext() { // find next entry while ( !_source->atEnd() ) { - const QList& tokens = tokenize( QString(_source->readLine()) ); + const QList& tokens = tokenize( QString::fromUtf8(_source->readLine()) ); if ( !tokens.isEmpty() && tokens.first().type == Token::KeyKeyword ) { KeyboardTranslator::States flags = KeyboardTranslator::NoState; @@ -270,7 +270,7 @@ void KeyboardTranslatorReader::readNext() modifiers, modifierMask, flags, - flagMask); + flagMask); KeyboardTranslator::Command command = KeyboardTranslator::NoCommand; QByteArray text; @@ -302,25 +302,29 @@ void KeyboardTranslatorReader::readNext() return; } - } + } _hasNext = false; } -bool KeyboardTranslatorReader::parseAsCommand(const QString& text,KeyboardTranslator::Command& command) +bool KeyboardTranslatorReader::parseAsCommand(const QString& text,KeyboardTranslator::Command& command) { - if ( text.compare("erase",Qt::CaseInsensitive) == 0 ) + if ( text.compare(QLatin1String("erase"),Qt::CaseInsensitive) == 0 ) command = KeyboardTranslator::EraseCommand; - else if ( text.compare("scrollpageup",Qt::CaseInsensitive) == 0 ) + else if ( text.compare(QLatin1String("scrollpageup"),Qt::CaseInsensitive) == 0 ) command = KeyboardTranslator::ScrollPageUpCommand; - else if ( text.compare("scrollpagedown",Qt::CaseInsensitive) == 0 ) + else if ( text.compare(QLatin1String("scrollpagedown"),Qt::CaseInsensitive) == 0 ) command = KeyboardTranslator::ScrollPageDownCommand; - else if ( text.compare("scrolllineup",Qt::CaseInsensitive) == 0 ) + else if ( text.compare(QLatin1String("scrolllineup"),Qt::CaseInsensitive) == 0 ) command = KeyboardTranslator::ScrollLineUpCommand; - else if ( text.compare("scrolllinedown",Qt::CaseInsensitive) == 0 ) + else if ( text.compare(QLatin1String("scrolllinedown"),Qt::CaseInsensitive) == 0 ) command = KeyboardTranslator::ScrollLineDownCommand; - else if ( text.compare("scrolllock",Qt::CaseInsensitive) == 0 ) + else if ( text.compare(QLatin1String("scrolllock"),Qt::CaseInsensitive) == 0 ) command = KeyboardTranslator::ScrollLockCommand; + else if ( text.compare(QLatin1String("scrolluptotop"),Qt::CaseInsensitive) == 0) + command = KeyboardTranslator::ScrollUpToTopCommand; + else if ( text.compare(QLatin1String("scrolldowntobottom"),Qt::CaseInsensitive) == 0) + command = KeyboardTranslator::ScrollDownToBottomCommand; else return false; @@ -334,7 +338,7 @@ bool KeyboardTranslatorReader::decodeSequence(const QString& text, KeyboardTranslator::States& flags, KeyboardTranslator::States& flagMask) { - bool isWanted = true; + bool isWanted = true; bool endOfItem = false; QString buffer; @@ -386,13 +390,13 @@ bool KeyboardTranslatorReader::decodeSequence(const QString& text, buffer.clear(); } - // check if this is a wanted / not-wanted flag and update the + // check if this is a wanted / not-wanted flag and update the // state ready for the next item - if ( ch == '+' ) + if ( ch == QLatin1Char('+') ) isWanted = true; - else if ( ch == '-' ) - isWanted = false; - } + else if ( ch == QLatin1Char('-') ) + isWanted = false; + } modifiers = tempModifiers; modifierMask = tempModifierMask; @@ -404,15 +408,15 @@ bool KeyboardTranslatorReader::decodeSequence(const QString& text, bool KeyboardTranslatorReader::parseAsModifier(const QString& item , Qt::KeyboardModifier& modifier) { - if ( item == "shift" ) + if ( item == QLatin1String("shift") ) modifier = Qt::ShiftModifier; - else if ( item == "ctrl" || item == "control" ) + else if ( item == QLatin1String("ctrl") || item == QLatin1String("control") ) modifier = Qt::ControlModifier; - else if ( item == "alt" ) + else if ( item == QLatin1String("alt") ) modifier = Qt::AltModifier; - else if ( item == "meta" ) + else if ( item == QLatin1String("meta") ) modifier = Qt::MetaModifier; - else if ( item == "keypad" ) + else if ( item == QLatin1String("keypad") ) modifier = Qt::KeypadModifier; else return false; @@ -421,17 +425,17 @@ bool KeyboardTranslatorReader::parseAsModifier(const QString& item , Qt::Keyboar } bool KeyboardTranslatorReader::parseAsStateFlag(const QString& item , KeyboardTranslator::State& flag) { - if ( item == "appcukeys" || item == "appcursorkeys" ) + if ( item == QLatin1String("appcukeys") || item == QLatin1String("appcursorkeys") ) flag = KeyboardTranslator::CursorKeysState; - else if ( item == "ansi" ) + else if ( item == QLatin1String("ansi") ) flag = KeyboardTranslator::AnsiState; - else if ( item == "newline" ) + else if ( item == QLatin1String("newline") ) flag = KeyboardTranslator::NewLineState; - else if ( item == "appscreen" ) + else if ( item == QLatin1String("appscreen") ) flag = KeyboardTranslator::AlternateScreenState; - else if ( item == "anymod" || item == "anymodifier" ) + else if ( item == QLatin1String("anymod") || item == QLatin1String("anymodifier") ) flag = KeyboardTranslator::AnyModifierState; - else if ( item == "appkeypad" ) + else if ( item == QLatin1String("appkeypad") ) flag = KeyboardTranslator::ApplicationKeypadState; else return false; @@ -451,9 +455,9 @@ bool KeyboardTranslatorReader::parseAsKeyCode(const QString& item , int& keyCode } } // additional cases implemented for backwards compatibility with KDE 3 - else if ( item == "prior" ) + else if ( item == QLatin1String("prior") ) keyCode = Qt::Key_PageUp; - else if ( item == "next" ) + else if ( item == QLatin1String("next") ) keyCode = Qt::Key_PageDown; else return false; @@ -469,12 +473,12 @@ bool KeyboardTranslatorReader::hasNextEntry() { return _hasNext; } -KeyboardTranslator::Entry KeyboardTranslatorReader::createEntry( const QString& condition , +KeyboardTranslator::Entry KeyboardTranslatorReader::createEntry( const QString& condition , const QString& result ) { - QString entryString("keyboard \"temporary\"\nkey "); + QString entryString = QString::fromLatin1("keyboard \"temporary\"\nkey "); entryString.append(condition); - entryString.append(" : "); + entryString.append(QLatin1String(" : ")); // if 'result' is the name of a command then the entry result will be that command, // otherwise the result will be treated as a string to echo when the key sequence @@ -483,7 +487,7 @@ KeyboardTranslator::Entry KeyboardTranslatorReader::createEntry( const QString& if (parseAsCommand(result,command)) entryString.append(result); else - entryString.append('\"' + result + '\"'); + entryString.append(QLatin1Char('\"') + result + QLatin1Char('\"')); QByteArray array = entryString.toUtf8(); QBuffer buffer(&array); @@ -497,7 +501,7 @@ KeyboardTranslator::Entry KeyboardTranslatorReader::createEntry( const QString& return entry; } -KeyboardTranslator::Entry KeyboardTranslatorReader::nextEntry() +KeyboardTranslator::Entry KeyboardTranslatorReader::nextEntry() { Q_ASSERT( _hasNext ); KeyboardTranslator::Entry entry = _nextEntry; @@ -512,30 +516,30 @@ QList KeyboardTranslatorReader::tokenize(const { QString text = line; - // remove comments + // remove comments bool inQuotes = false; int commentPos = -1; for (int i=text.length()-1;i>=0;i--) { QChar ch = text[i]; - if (ch == '\"') + if (ch == QLatin1Char('\"')) inQuotes = !inQuotes; - else if (ch == '#' && !inQuotes) + else if (ch == QLatin1Char('#') && !inQuotes) commentPos = i; } if (commentPos != -1) text.remove(commentPos,text.length()); text = text.simplified(); - + // title line: keyboard "title" - static QRegExp title("keyboard\\s+\"(.*)\""); + static QRegExp title(QLatin1String("keyboard\\s+\"(.*)\"")); // key line: key KeySequence : "output" // key line: key KeySequence : command - static QRegExp key("key\\s+([\\w\\+\\s\\-\\*\\.]+)\\s*:\\s*(\"(.*)\"|\\w+)"); + static QRegExp key(QLatin1String("key\\s+([\\w\\+\\s\\-\\*\\.]+)\\s*:\\s*(\"(.*)\"|\\w+)")); QList list; - if ( text.isEmpty() ) + if ( text.isEmpty() ) { return list; } @@ -543,29 +547,29 @@ QList KeyboardTranslatorReader::tokenize(const if ( title.exactMatch(text) ) { Token titleToken = { Token::TitleKeyword , QString() }; - Token textToken = { Token::TitleText , title.capturedTexts()[1] }; - + Token textToken = { Token::TitleText , title.capturedTexts().at(1) }; + list << titleToken << textToken; } else if ( key.exactMatch(text) ) { Token keyToken = { Token::KeyKeyword , QString() }; - Token sequenceToken = { Token::KeySequence , key.capturedTexts()[1].remove(' ') }; + Token sequenceToken = { Token::KeySequence , key.capturedTexts().value(1).remove(QLatin1Char(' ')) }; list << keyToken << sequenceToken; - if ( key.capturedTexts()[3].isEmpty() ) + if ( key.capturedTexts().at(3).isEmpty() ) { // capturedTexts()[2] is a command - Token commandToken = { Token::Command , key.capturedTexts()[2] }; - list << commandToken; - } + Token commandToken = { Token::Command , key.capturedTexts().at(2) }; + list << commandToken; + } else { // capturedTexts()[3] is the output string - Token outputToken = { Token::OutputText , key.capturedTexts()[3] }; + Token outputToken = { Token::OutputText , key.capturedTexts().at(3) }; list << outputToken; - } + } } else { @@ -575,7 +579,7 @@ QList KeyboardTranslatorReader::tokenize(const return list; } -QList KeyboardTranslatorManager::allTranslators() +QList KeyboardTranslatorManager::allTranslators() { if ( !_haveLoadedAll ) { @@ -606,14 +610,14 @@ bool KeyboardTranslator::Entry::operator==(const Entry& rhs) const _text == rhs._text; } -bool KeyboardTranslator::Entry::matches(int keyCode , +bool KeyboardTranslator::Entry::matches(int keyCode , Qt::KeyboardModifiers modifiers, States testState) const { if ( _keyCode != keyCode ) return false; - if ( (modifiers & _modifierMask) != (_modifiers & _modifierMask) ) + if ( (modifiers & _modifierMask) != (_modifiers & _modifierMask) ) return false; // if modifiers is non-zero, the 'any modifier' state is implicit @@ -623,7 +627,7 @@ bool KeyboardTranslator::Entry::matches(int keyCode , if ( (testState & _stateMask) != (_state & _stateMask) ) return false; - // special handling for the 'Any Modifier' state, which checks for the presence of + // special handling for the 'Any Modifier' state, which checks for the presence of // any or no modifiers. In this context, the 'keypad' modifier does not count. bool anyModifiersSet = modifiers != 0 && modifiers != Qt::KeypadModifier; bool wantAnyModifier = _state & KeyboardTranslator::AnyModifierState; @@ -632,7 +636,7 @@ bool KeyboardTranslator::Entry::matches(int keyCode , if ( wantAnyModifier != anyModifiersSet ) return false; } - + return true; } QByteArray KeyboardTranslator::Entry::escapedText(bool expandWildCards,Qt::KeyboardModifiers modifiers) const @@ -655,13 +659,13 @@ QByteArray KeyboardTranslator::Entry::escapedText(bool expandWildCards,Qt::Keybo default: // any character which is not printable is replaced by an equivalent // \xhh escape sequence (where 'hh' are the corresponding hex digits) - if ( !QChar(ch).isPrint() ) + if ( !QChar(QLatin1Char(ch)).isPrint() ) replacement = 'x'; } if ( replacement == 'x' ) { - result.replace(i,1,"\\x"+QByteArray(1,ch).toHex()); + result.replace(i,1,"\\x"+QByteArray(1,ch).toHex()); } else if ( replacement != 0 ) { result.remove(i,1); @@ -709,7 +713,7 @@ QByteArray KeyboardTranslator::Entry::unescape(const QByteArray& input) const unsigned charValue = 0; sscanf(hexDigits,"%x",&charValue); - replacement[0] = (char)charValue; + replacement[0] = (char)charValue; charsToRemove = 2 + strlen(hexDigits); } break; @@ -731,20 +735,20 @@ void KeyboardTranslator::Entry::insertModifier( QString& item , int modifier ) c return; if ( modifier & _modifiers ) - item += '+'; + item += QLatin1Char('+'); else - item += '-'; + item += QLatin1Char('-'); if ( modifier == Qt::ShiftModifier ) - item += "Shift"; + item += QLatin1String("Shift"); else if ( modifier == Qt::ControlModifier ) - item += "Ctrl"; + item += QLatin1String("Ctrl"); else if ( modifier == Qt::AltModifier ) - item += "Alt"; + item += QLatin1String("Alt"); else if ( modifier == Qt::MetaModifier ) - item += "Meta"; + item += QLatin1String("Meta"); else if ( modifier == Qt::KeypadModifier ) - item += "KeyPad"; + item += QLatin1String("KeyPad"); } void KeyboardTranslator::Entry::insertState( QString& item , int state ) const { @@ -752,39 +756,43 @@ void KeyboardTranslator::Entry::insertState( QString& item , int state ) const return; if ( state & _state ) - item += '+' ; + item += QLatin1Char('+') ; else - item += '-' ; + item += QLatin1Char('-') ; if ( state == KeyboardTranslator::AlternateScreenState ) - item += "AppScreen"; + item += QLatin1String("AppScreen"); else if ( state == KeyboardTranslator::NewLineState ) - item += "NewLine"; + item += QLatin1String("NewLine"); else if ( state == KeyboardTranslator::AnsiState ) - item += "Ansi"; + item += QLatin1String("Ansi"); else if ( state == KeyboardTranslator::CursorKeysState ) - item += "AppCursorKeys"; + item += QLatin1String("AppCursorKeys"); else if ( state == KeyboardTranslator::AnyModifierState ) - item += "AnyModifier"; + item += QLatin1String("AnyModifier"); else if ( state == KeyboardTranslator::ApplicationKeypadState ) - item += "AppKeypad"; + item += QLatin1String("AppKeypad"); } QString KeyboardTranslator::Entry::resultToString(bool expandWildCards,Qt::KeyboardModifiers modifiers) const { if ( !_text.isEmpty() ) - return escapedText(expandWildCards,modifiers); + return QString::fromLatin1(escapedText(expandWildCards,modifiers)); else if ( _command == EraseCommand ) - return "Erase"; + return QLatin1String("Erase"); else if ( _command == ScrollPageUpCommand ) - return "ScrollPageUp"; + return QLatin1String("ScrollPageUp"); else if ( _command == ScrollPageDownCommand ) - return "ScrollPageDown"; + return QLatin1String("ScrollPageDown"); else if ( _command == ScrollLineUpCommand ) - return "ScrollLineUp"; + return QLatin1String("ScrollLineUp"); else if ( _command == ScrollLineDownCommand ) - return "ScrollLineDown"; + return QLatin1String("ScrollLineDown"); else if ( _command == ScrollLockCommand ) - return "ScrollLock"; + return QLatin1String("ScrollLock"); + else if (_command == ScrollUpToTopCommand) + return QLatin1String("ScrollUpToTop"); + else if (_command == ScrollDownToBottomCommand) + return QLatin1String("ScrollDownToBottom"); return QString(); } @@ -813,7 +821,7 @@ KeyboardTranslator::KeyboardTranslator(const QString& name) { } -void KeyboardTranslator::setDescription(const QString& description) +void KeyboardTranslator::setDescription(const QString& description) { _description = description; } @@ -852,10 +860,11 @@ void KeyboardTranslator::removeEntry(const Entry& entry) } KeyboardTranslator::Entry KeyboardTranslator::findEntry(int keyCode, Qt::KeyboardModifiers modifiers, States state) const { - foreach(const Entry& entry, _entries.values(keyCode)) + for (auto it = _entries.cbegin(), end = _entries.cend(); it != end; ++it) { - if ( entry.matches(keyCode,modifiers,state) ) - return entry; + if (it.key() == keyCode) + if ( it.value().matches(keyCode,modifiers,state) ) + return *it; } return Entry(); // entry not found } @@ -876,7 +885,7 @@ bool KeyboardTranslatorManager::deleteTranslator(const QString& name) if ( QFile::remove(path) ) { _translators.remove(name); - return true; + return true; } else { @@ -884,11 +893,8 @@ bool KeyboardTranslatorManager::deleteTranslator(const QString& name) return false; } } -//K_GLOBAL_STATIC( KeyboardTranslatorManager , theKeyboardTranslatorManager ) -KeyboardTranslatorManager* KeyboardTranslatorManager::theKeyboardTranslatorManager = 0; +Q_GLOBAL_STATIC( KeyboardTranslatorManager , theKeyboardTranslatorManager ) KeyboardTranslatorManager* KeyboardTranslatorManager::instance() { - if (! theKeyboardTranslatorManager) - theKeyboardTranslatorManager = new KeyboardTranslatorManager(); return theKeyboardTranslatorManager; } diff --git a/lib/KeyboardTranslator.h b/lib/KeyboardTranslator.h index 15a2980..a9614e4 100644 --- a/lib/KeyboardTranslator.h +++ b/lib/KeyboardTranslator.h @@ -39,7 +39,7 @@ class QTextStream; namespace Konsole { -/** +/** * A convertor which maps between key sequences pressed by the user and the * character strings which should be sent to the terminal and commands * which should be invoked when those character sequences are pressed. @@ -55,7 +55,7 @@ namespace Konsole class KeyboardTranslator { public: - /** + /** * The meaning of a particular key sequence may depend upon the state which * the terminal emulation is in. Therefore findEntry() may return a different * Entry depending upon the state flags supplied. @@ -71,7 +71,7 @@ public: * TODO More documentation */ NewLineState = 1, - /** + /** * Indicates that the terminal is in 'Ansi' mode. * TODO: More documentation */ @@ -82,10 +82,10 @@ public: CursorKeysState = 4, /** * Indicates that the alternate screen ( typically used by interactive programs - * such as screen or vim ) is active + * such as screen or vim ) is active */ AlternateScreenState = 8, - /** Indicates that any of the modifier keys is active. */ + /** Indicates that any of the modifier keys is active. */ AnyModifierState = 16, /** Indicates that the numpad is in application mode. */ ApplicationKeypadState = 32 @@ -111,8 +111,12 @@ public: ScrollLineDownCommand = 16, /** Toggles scroll lock mode */ ScrollLockCommand = 32, + /** Scroll the terminal display up to the start of history */ + ScrollUpToTopCommand = 64, + /** Scroll the terminal display down to the end of history */ + ScrollDownToBottomCommand = 128, /** Echos the operating system specific erase character. */ - EraseCommand = 64 + EraseCommand = 256 }; Q_DECLARE_FLAGS(Commands,Command) @@ -124,14 +128,14 @@ public: class Entry { public: - /** + /** * Constructs a new entry for a keyboard translator. */ Entry(); - /** + /** * Returns true if this entry is null. - * This is true for newly constructed entries which have no properties set. + * This is true for newly constructed entries which have no properties set. */ bool isNull() const; @@ -140,15 +144,15 @@ public: /** Sets the command associated with this entry. */ void setCommand(Command command); - /** - * Returns the character sequence associated with this entry, optionally replacing + /** + * Returns the character sequence associated with this entry, optionally replacing * wildcard '*' characters with numbers to indicate the keyboard modifiers being pressed. * * TODO: The numbers used to replace '*' characters are taken from the Konsole/KDE 3 code. - * Document them. + * Document them. * * @param expandWildCards Specifies whether wild cards (occurrences of the '*' character) in - * the entry should be replaced with a number to indicate the modifier keys being pressed. + * the entry should be replaced with a number to indicate the modifier keys being pressed. * * @param modifiers The keyboard modifiers being pressed. */ @@ -158,7 +162,7 @@ public: /** Sets the character sequence associated with this entry */ void setText(const QByteArray& text); - /** + /** * Returns the character sequence associated with this entry, * with any non-printable characters replaced with escape sequences. * @@ -175,13 +179,13 @@ public: /** Sets the character code associated with this entry */ void setKeyCode(int keyCode); - /** - * Returns a bitwise-OR of the enabled keyboard modifiers associated with this entry. + /** + * Returns a bitwise-OR of the enabled keyboard modifiers associated with this entry. * If a modifier is set in modifierMask() but not in modifiers(), this means that the entry * only matches when that modifier is NOT pressed. * * If a modifier is not set in modifierMask() then the entry matches whether the modifier - * is pressed or not. + * is pressed or not. */ Qt::KeyboardModifiers modifiers() const; @@ -193,13 +197,13 @@ public: /** See modifierMask() and modifiers() */ void setModifierMask( Qt::KeyboardModifiers modifiers ); - /** - * Returns a bitwise-OR of the enabled state flags associated with this entry. - * If flag is set in stateMask() but not in state(), this means that the entry only + /** + * Returns a bitwise-OR of the enabled state flags associated with this entry. + * If flag is set in stateMask() but not in state(), this means that the entry only * matches when the terminal is NOT in that state. * * If a state is not set in stateMask() then the entry matches whether the terminal - * is in that state or not. + * is in that state or not. */ States state() const; @@ -211,13 +215,13 @@ public: /** See stateMask() */ void setStateMask( States mask ); - /** - * Returns the key code and modifiers associated with this entry + /** + * Returns the key code and modifiers associated with this entry * as a QKeySequence */ //QKeySequence keySequence() const; - /** + /** * Returns this entry's conditions ( ie. its key code, modifier and state criteria ) * as a string. */ @@ -233,16 +237,16 @@ public: QString resultToString(bool expandWildCards = false, Qt::KeyboardModifiers modifiers = Qt::NoModifier) const; - /** + /** * Returns true if this entry matches the given key sequence, specified * as a combination of @p keyCode , @p modifiers and @p state. */ - bool matches( int keyCode , - Qt::KeyboardModifiers modifiers , + bool matches( int keyCode , + Qt::KeyboardModifiers modifiers , States flags ) const; bool operator==(const Entry& rhs) const; - + private: void insertModifier( QString& item , int modifier ) const; void insertState( QString& item , int state ) const; @@ -260,7 +264,7 @@ public: /** Constructs a new keyboard translator with the given @p name */ KeyboardTranslator(const QString& name); - + //KeyboardTranslator(const KeyboardTranslator& other); /** Returns the name of this keyboard translator */ @@ -278,7 +282,7 @@ public: /** * Looks for an entry in this keyboard translator which matches the given * key code, keyboard modifiers and state flags. - * + * * Returns the matching entry if found or a null Entry otherwise ( ie. * entry.isNull() will return true ) * @@ -286,11 +290,11 @@ public: * @param modifiers A combination of modifiers * @param state Optional flags which specify the current state of the terminal */ - Entry findEntry(int keyCode , - Qt::KeyboardModifiers modifiers , + Entry findEntry(int keyCode , + Qt::KeyboardModifiers modifiers , States state = NoState) const; - /** + /** * Adds an entry to this keyboard translator's table. Entries can be looked up according * to their key sequence using findEntry() */ @@ -321,8 +325,8 @@ private: Q_DECLARE_OPERATORS_FOR_FLAGS(KeyboardTranslator::States) Q_DECLARE_OPERATORS_FOR_FLAGS(KeyboardTranslator::Commands) -/** - * Parses the contents of a Keyboard Translator (.keytab) file and +/** + * Parses the contents of a Keyboard Translator (.keytab) file and * returns the entries found in it. * * Usage example: @@ -342,7 +346,7 @@ Q_DECLARE_OPERATORS_FOR_FLAGS(KeyboardTranslator::Commands) * if ( !reader.parseError() ) * { * // parsing succeeded, do something with the translator - * } + * } * else * { * // parsing failed @@ -355,18 +359,18 @@ public: /** Constructs a new reader which parses the given @p source */ KeyboardTranslatorReader( QIODevice* source ); - /** - * Returns the description text. - * TODO: More documentation + /** + * Returns the description text. + * TODO: More documentation */ QString description() const; /** Returns true if there is another entry in the source stream */ bool hasNextEntry(); /** Returns the next entry found in the source stream */ - KeyboardTranslator::Entry nextEntry(); + KeyboardTranslator::Entry nextEntry(); - /** + /** * Returns true if an error occurred whilst parsing the input or * false if no error occurred. */ @@ -376,7 +380,7 @@ public: * Parses a condition and result string for a translator entry * and produces a keyboard translator entry. * - * The condition and result strings are in the same format as in + * The condition and result strings are in the same format as in */ static KeyboardTranslator::Entry createEntry( const QString& condition , const QString& result ); @@ -397,7 +401,7 @@ private: }; QList tokenize(const QString&); void readNext(); - bool decodeSequence(const QString& , + bool decodeSequence(const QString& , int& keyCode, Qt::KeyboardModifiers& modifiers, Qt::KeyboardModifiers& modifierMask, @@ -419,23 +423,23 @@ private: class KeyboardTranslatorWriter { public: - /** + /** * Constructs a new writer which saves data into @p destination. * The caller is responsible for closing the device when writing is complete. */ KeyboardTranslatorWriter(QIODevice* destination); ~KeyboardTranslatorWriter(); - /** - * Writes the header for the keyboard translator. - * @param description Description of the keyboard translator. + /** + * Writes the header for the keyboard translator. + * @param description Description of the keyboard translator. */ void writeHeader( const QString& description ); /** Writes a translator entry. */ - void writeEntry( const KeyboardTranslator::Entry& entry ); + void writeEntry( const KeyboardTranslator::Entry& entry ); private: - QIODevice* _destination; + QIODevice* _destination; QTextStream* _writer; }; @@ -446,7 +450,7 @@ private: class KONSOLEPRIVATE_EXPORT KeyboardTranslatorManager { public: - /** + /** * Constructs a new KeyboardTranslatorManager and loads the list of * available keyboard translations. * @@ -456,8 +460,11 @@ public: KeyboardTranslatorManager(); ~KeyboardTranslatorManager(); + KeyboardTranslatorManager(const KeyboardTranslatorManager&) = delete; + KeyboardTranslatorManager& operator=(const KeyboardTranslatorManager&) = delete; + /** - * Adds a new translator. If a translator with the same name + * Adds a new translator. If a translator with the same name * already exists, it will be replaced by the new translator. * * TODO: More documentation. @@ -474,18 +481,18 @@ public: /** Returns the default translator for Konsole. */ const KeyboardTranslator* defaultTranslator(); - /** + /** * Returns the keyboard translator with the given name or 0 if no translator * with that name exists. * * The first time that a translator with a particular name is requested, - * the on-disk .keyboard file is loaded and parsed. + * the on-disk .keyboard file is loaded and parsed. */ const KeyboardTranslator* findTranslator(const QString& name); /** * Returns a list of the names of available keyboard translators. * - * The first time this is called, a search for available + * The first time this is called, a search for available * translators is started. */ QList allTranslators(); @@ -495,34 +502,32 @@ public: private: static const QByteArray defaultTranslatorText; - + void findTranslators(); // locate the available translators - KeyboardTranslator* loadTranslator(const QString& name); // loads the translator + KeyboardTranslator* loadTranslator(const QString& name); // loads the translator // with the given name KeyboardTranslator* loadTranslator(QIODevice* device,const QString& name); bool saveTranslator(const KeyboardTranslator* translator); QString findTranslatorPath(const QString& name); - + QHash _translators; // maps translator-name -> KeyboardTranslator // instance bool _haveLoadedAll; - - static KeyboardTranslatorManager * theKeyboardTranslatorManager; }; inline int KeyboardTranslator::Entry::keyCode() const { return _keyCode; } inline void KeyboardTranslator::Entry::setKeyCode(int keyCode) { _keyCode = keyCode; } -inline void KeyboardTranslator::Entry::setModifiers( Qt::KeyboardModifiers modifier ) -{ +inline void KeyboardTranslator::Entry::setModifiers( Qt::KeyboardModifiers modifier ) +{ _modifiers = modifier; } inline Qt::KeyboardModifiers KeyboardTranslator::Entry::modifiers() const { return _modifiers; } -inline void KeyboardTranslator::Entry::setModifierMask( Qt::KeyboardModifiers mask ) -{ - _modifierMask = mask; +inline void KeyboardTranslator::Entry::setModifierMask( Qt::KeyboardModifiers mask ) +{ + _modifierMask = mask; } inline Qt::KeyboardModifiers KeyboardTranslator::Entry::modifierMask() const { return _modifierMask; } @@ -532,23 +537,23 @@ inline bool KeyboardTranslator::Entry::isNull() const } inline void KeyboardTranslator::Entry::setCommand( Command command ) -{ - _command = command; +{ + _command = command; } inline KeyboardTranslator::Command KeyboardTranslator::Entry::command() const { return _command; } inline void KeyboardTranslator::Entry::setText( const QByteArray& text ) -{ +{ _text = unescape(text); } inline int oneOrZero(int value) { return value ? 1 : 0; } -inline QByteArray KeyboardTranslator::Entry::text(bool expandWildCards,Qt::KeyboardModifiers modifiers) const +inline QByteArray KeyboardTranslator::Entry::text(bool expandWildCards,Qt::KeyboardModifiers modifiers) const { QByteArray expandedText = _text; - + if (expandWildCards) { int modifierValue = 1; @@ -556,25 +561,25 @@ inline QByteArray KeyboardTranslator::Entry::text(bool expandWildCards,Qt::Keybo modifierValue += oneOrZero(modifiers & Qt::AltModifier) << 1; modifierValue += oneOrZero(modifiers & Qt::ControlModifier) << 2; - for (int i=0;i<_text.length();i++) + for (int i=0;i<_text.length();i++) { if (expandedText[i] == '*') expandedText[i] = '0' + modifierValue; } } - return expandedText; + return expandedText; } inline void KeyboardTranslator::Entry::setState( States state ) -{ - _state = state; +{ + _state = state; } inline KeyboardTranslator::States KeyboardTranslator::Entry::state() const { return _state; } inline void KeyboardTranslator::Entry::setStateMask( States stateMask ) -{ - _stateMask = stateMask; +{ + _stateMask = stateMask; } inline KeyboardTranslator::States KeyboardTranslator::Entry::stateMask() const { return _stateMask; } diff --git a/lib/Pty.cpp b/lib/Pty.cpp index c986d93..87484be 100644 --- a/lib/Pty.cpp +++ b/lib/Pty.cpp @@ -83,7 +83,7 @@ bool Pty::flowControlEnabled() const pty()->tcGetAttr(&ttmode); return ttmode.c_iflag & IXOFF && ttmode.c_iflag & IXON; - } + } qWarning() << "Unable to get flow control status, terminal not connected."; return false; } @@ -110,7 +110,7 @@ void Pty::setUtf8Mode(bool enable) void Pty::setErase(char erase) { _eraseChar = erase; - + if (pty()->masterFd() >= 0) { struct ::termios ttmode; @@ -141,8 +141,8 @@ void Pty::addEnvironmentVariables(const QStringList& environment) QString pair = iter.next(); // split on the first '=' character - int pos = pair.indexOf('='); - + int pos = pair.indexOf(QLatin1Char('=')); + if ( pos >= 0 ) { QString variable = pair.left(pos); @@ -153,10 +153,10 @@ void Pty::addEnvironmentVariables(const QStringList& environment) } } -int Pty::start(const QString& program, - const QStringList& programArguments, - const QStringList& environment, - ulong winid, +int Pty::start(const QString& program, + const QStringList& programArguments, + const QStringList& environment, + ulong winid, bool addToUtmp //const QString& dbusService, //const QString& dbusSession @@ -164,15 +164,15 @@ int Pty::start(const QString& program, { clearProgram(); - // For historical reasons, the first argument in programArguments is the + // For historical reasons, the first argument in programArguments is the // name of the program to execute, so create a list consisting of all // but the first argument to pass to setProgram() Q_ASSERT(programArguments.count() >= 1); - setProgram(program.toLatin1(),programArguments.mid(1)); + setProgram(program, programArguments.mid(1)); addEnvironmentVariables(environment); - setEnv("WINDOWID", QString::number(winid)); + setEnv(QLatin1String("WINDOWID"), QString::number(winid)); // unless the LANGUAGE environment variable has been set explicitly // set it to a null string @@ -185,7 +185,7 @@ int Pty::start(const QString& program, // does not have a translation for // // BR:149300 - setEnv("LANGUAGE",QString(),false /* do not overwrite existing value if any */); + setEnv(QLatin1String("LANGUAGE"),QString(),false /* do not overwrite existing value if any */); setUseUtmp(addToUtmp); @@ -204,10 +204,10 @@ int Pty::start(const QString& program, if (_eraseChar != 0) ttmode.c_cc[VERASE] = _eraseChar; - + if (!pty()->tcSetAttr(&ttmode)) qWarning() << "Unable to set terminal attributes."; - + pty()->setWinSize(_windowLines, _windowColumns); KProcess::start(); @@ -218,6 +218,28 @@ int Pty::start(const QString& program, return 0; } +void Pty::setEmptyPTYProperties() +{ + struct ::termios ttmode; + pty()->tcGetAttr(&ttmode); + if (!_xonXoff) + ttmode.c_iflag &= ~(IXOFF | IXON); + else + ttmode.c_iflag |= (IXOFF | IXON); + #ifdef IUTF8 // XXX not a reasonable place to check it. + if (!_utf8) + ttmode.c_iflag &= ~IUTF8; + else + ttmode.c_iflag |= IUTF8; + #endif + + if (_eraseChar != 0) + ttmode.c_cc[VERASE] = _eraseChar; + + if (!pty()->tcSetAttr(&ttmode)) + qWarning() << "Unable to set terminal attributes."; +} + void Pty::setWriteable(bool writeable) { struct stat sbuf; @@ -258,15 +280,15 @@ void Pty::sendData(const char* data, int length) { if (!length) return; - - if (!pty()->write(data,length)) + + if (!pty()->write(data,length)) { qWarning() << "Pty::doSendJobs - Could not send input data to terminal process."; return; } } -void Pty::dataReceived() +void Pty::dataReceived() { QByteArray data = pty()->readAll(); emit receivedData(data.constData(),data.count()); @@ -290,7 +312,7 @@ int Pty::foregroundProcessGroup() const if ( pid != -1 ) { return pid; - } + } return 0; } @@ -298,9 +320,9 @@ int Pty::foregroundProcessGroup() const void Pty::setupChildProcess() { KPtyProcess::setupChildProcess(); - + // reset all signal handlers - // this ensures that terminal applications respond to + // this ensures that terminal applications respond to // signals generated via key sequences such as Ctrl+C // (which sends SIGINT) struct sigaction action; diff --git a/lib/Pty.h b/lib/Pty.h index 0d28fe7..e5f6ceb 100644 --- a/lib/Pty.h +++ b/lib/Pty.h @@ -7,8 +7,8 @@ */ /* - This file is part of Konsole, KDE's terminal emulator. - + This file is part of Konsole, KDE's terminal emulator. + Copyright 2007-2008 by Robert Knight Copyright 1997,1998 by Lars Doelle @@ -43,8 +43,8 @@ namespace Konsole { /** - * The Pty class is used to start the terminal process, - * send data to it, receive data from it and manipulate + * The Pty class is used to start the terminal process, + * send data to it, receive data from it and manipulate * various properties of the pseudo-teletype interface * used to communicate with the process. * @@ -53,26 +53,26 @@ namespace Konsole { * send data to or receive data from the process. * * To start the terminal process, call the start() method - * with the program name and appropriate arguments. + * with the program name and appropriate arguments. */ class Pty: public KPtyProcess { Q_OBJECT public: - - /** + + /** * Constructs a new Pty. - * + * * Connect to the sendData() slot and receivedData() signal to prepare * for sending and receiving data from the terminal process. * - * To start the terminal process, call the run() method with the + * To start the terminal process, call the run() method with the * name of the program to start and appropriate arguments. */ explicit Pty(QObject* parent = 0); - /** + /** * Construct a process using an open pty master. * See KPtyProcess::KPtyProcess() */ @@ -81,7 +81,7 @@ Q_OBJECT ~Pty(); /** - * Starts the terminal process. + * Starts the terminal process. * * Returns 0 if the process was started successfully or non-zero * otherwise. @@ -94,23 +94,28 @@ Q_OBJECT * @param winid Specifies the value of the WINDOWID environment variable * in the process's environment. * @param addToUtmp Specifies whether a utmp entry should be created for - * the pty used. See K3Process::setUsePty() - * @param dbusService Specifies the value of the KONSOLE_DBUS_SERVICE + * the pty used. See K3Process::setUsePty() + * @param dbusService Specifies the value of the KONSOLE_DBUS_SERVICE * environment variable in the process's environment. * @param dbusSession Specifies the value of the KONSOLE_DBUS_SESSION - * environment variable in the process's environment. + * environment variable in the process's environment. */ - int start( const QString& program, - const QStringList& arguments, - const QStringList& environment, - ulong winid, + int start( const QString& program, + const QStringList& arguments, + const QStringList& environment, + ulong winid, bool addToUtmp ); + /** + * set properties for "EmptyPTY" + */ + void setEmptyPTYProperties(); + /** TODO: Document me */ void setWriteable(bool writeable); - /** + /** * Enables or disables Xon/Xoff flow control. The flow control setting * may be changed later by a terminal application, so flowControlEnabled() * may not equal the value of @p on in the previous call to setFlowControlEnabled() @@ -120,12 +125,12 @@ Q_OBJECT /** Queries the terminal state and returns true if Xon/Xoff flow control is enabled. */ bool flowControlEnabled() const; - /** - * Sets the size of the window (in lines and columns of characters) + /** + * Sets the size of the window (in lines and columns of characters) * used by this teletype. */ void setWindowSize(int lines, int cols); - + /** Returns the size of the window used by this teletype. See setWindowSize() */ QSize windowSize() const; @@ -144,7 +149,7 @@ Q_OBJECT * 0 will be returned. */ int foregroundProcessGroup() const; - + public slots: /** @@ -153,7 +158,7 @@ Q_OBJECT void setUtf8Mode(bool on); /** - * Suspend or resume processing of data from the standard + * Suspend or resume processing of data from the standard * output of the terminal process. * * See K3Process::suspend() and K3Process::resume() @@ -162,9 +167,9 @@ Q_OBJECT * otherwise processing is resumed. */ void lockPty(bool lock); - - /** - * Sends data to the process currently controlling the + + /** + * Sends data to the process currently controlling the * teletype ( whose id is returned by foregroundProcessGroup() ) * * @param buffer Pointer to the data to send. @@ -182,14 +187,14 @@ Q_OBJECT * @param length Length of @p buffer */ void receivedData(const char* buffer, int length); - + protected: void setupChildProcess(); private slots: - // called when data is received from the terminal process - void dataReceived(); - + // called when data is received from the terminal process + void dataReceived(); + private: void init(); @@ -197,7 +202,7 @@ Q_OBJECT // to the environment for the process void addEnvironmentVariables(const QStringList& environment); - int _windowColumns; + int _windowColumns; int _windowLines; char _eraseChar; bool _xonXoff; diff --git a/lib/README b/lib/README deleted file mode 100644 index 1801361..0000000 --- a/lib/README +++ /dev/null @@ -1,7 +0,0 @@ -lib.pro is a *.pro-file for qmake - -It produces static lib (libqtermwidget.a) only. -For creating shared lib (*.so) uncomment "dll" in "CONFIG" line in *.pro-file - -Library was tested both with HAVE_POSIX_OPENPT and HAVE_GETPT precompiler directives, -defined in "DEFINES" line. You should select variant which would be correct for your system. \ No newline at end of file diff --git a/lib/Screen.cpp b/lib/Screen.cpp index b3c5b60..ea635e5 100644 --- a/lib/Screen.cpp +++ b/lib/Screen.cpp @@ -27,7 +27,6 @@ #include #include #include -#include #include #include @@ -50,10 +49,10 @@ using namespace Konsole; //Macro to convert x,y position on screen to position within an image. // -//Originally the image was stored as one large contiguous block of +//Originally the image was stored as one large contiguous block of //memory, so a position within the image could be represented as an //offset from the beginning of the block. For efficiency reasons this -//is no longer the case. +//is no longer the case. //Many internal parts of this class still use this representation for parameters and so on, //notably moveImage() and clearImage(). //This macro converts from an X,Y position into an image offset. @@ -198,14 +197,14 @@ void Screen::deleteChars(int n) Q_ASSERT( n >= 0 ); // always delete at least one char - if (n == 0) - n = 1; + if (n == 0) + n = 1; // if cursor is beyond the end of the line there is nothing to do if ( cuX >= screenLines[cuY].count() ) return; - if ( cuX+n > screenLines[cuY].count() ) + if ( cuX+n > screenLines[cuY].count() ) n = screenLines[cuY].count() - cuX; Q_ASSERT( n >= 0 ); @@ -227,6 +226,28 @@ void Screen::insertChars(int n) screenLines[cuY].resize(columns); } +void Screen::repeatChars(int count) + //=REP +{ + if (count == 0) + { + count = 1; + } + /** + * From ECMA-48 version 5, section 8.3.103 + * If the character preceding REP is a control function or part of a + * control function, the effect of REP is not defined by this Standard. + * + * So, a "normal" program should always use REP immediately after a visible + * character (those other than escape sequences). So, lastDrawnChar can be + * safely used. + */ + for (int i = 0; i < count; i++) + { + displayCharacter(lastDrawnChar); + } +} + void Screen::deleteLines(int n) { if (n == 0) n = 1; // Default @@ -285,7 +306,7 @@ void Screen::restoreCursor() { cuX = qMin(savedState.cursorColumn,columns-1); cuY = qMin(savedState.cursorLine,lines-1); - currentRendition = savedState.rendition; + currentRendition = savedState.rendition; currentForeground = savedState.foreground; currentBackground = savedState.background; updateEffectiveRendition(); @@ -318,7 +339,7 @@ void Screen::resizeImage(int new_lines, int new_columns) clearSelection(); - delete[] screenLines; + delete[] screenLines; screenLines = newScreenLines; lines = new_lines; @@ -375,11 +396,11 @@ void Screen::setDefaultMargins() */ void Screen::reverseRendition(Character& p) const -{ - CharacterColor f = p.foregroundColor; +{ + CharacterColor f = p.foregroundColor; CharacterColor b = p.backgroundColor; - p.foregroundColor = b; + p.foregroundColor = b; p.backgroundColor = f; //p->r &= ~RE_TRANSPARENT; } @@ -398,21 +419,21 @@ void Screen::updateEffectiveRendition() } if (currentRendition & RE_BOLD) - effectiveForeground.toggleIntensive(); + effectiveForeground.setIntensive(); } void Screen::copyFromHistory(Character* dest, int startLine, int count) const { Q_ASSERT( startLine >= 0 && count > 0 && startLine + count <= history->getLines() ); - for (int line = startLine; line < startLine + count; line++) + for (int line = startLine; line < startLine + count; line++) { const int length = qMin(columns,history->getLineLen(line)); const int destLineOffset = (line-startLine)*columns; history->getCells(line,0,length,dest + destLineOffset); - for (int column = length; column < columns; column++) + for (int column = length; column < columns; column++) dest[destLineOffset+column] = defaultChar; // invert selected text @@ -420,9 +441,9 @@ void Screen::copyFromHistory(Character* dest, int startLine, int count) const { for (int column = 0; column < columns; column++) { - if (isSelected(column,line)) + if (isSelected(column,line)) { - reverseRendition(dest[destLineOffset + column]); + reverseRendition(dest[destLineOffset + column]); } } } @@ -439,15 +460,15 @@ void Screen::copyFromScreen(Character* dest , int startLine , int count) const int destLineStartIndex = (line-startLine)*columns; for (int column = 0; column < columns; column++) - { - int srcIndex = srcLineStartIndex + column; + { + int srcIndex = srcLineStartIndex + column; int destIndex = destLineStartIndex + column; dest[destIndex] = screenLines[srcIndex/columns].value(srcIndex%columns,defaultChar); // invert selected text if (selBegin != -1 && isSelected(column,line + history->getLines())) - reverseRendition(dest[destIndex]); + reverseRendition(dest[destIndex]); } } @@ -460,7 +481,7 @@ void Screen::getImage( Character* dest, int size, int startLine, int endLine ) c const int mergedLines = endLine - startLine + 1; - Q_ASSERT( size >= mergedLines * columns ); + Q_ASSERT( size >= mergedLines * columns ); Q_UNUSED( size ); const int linesInHistoryBuffer = qBound(0,history->getLines()-startLine,mergedLines); @@ -468,7 +489,7 @@ void Screen::getImage( Character* dest, int size, int startLine, int endLine ) c // copy lines from history buffer if (linesInHistoryBuffer > 0) - copyFromHistory(dest,startLine,linesInHistoryBuffer); + copyFromHistory(dest,startLine,linesInHistoryBuffer); // copy lines from screen buffer if (linesInScreenBuffer > 0) @@ -491,7 +512,7 @@ void Screen::getImage( Character* dest, int size, int startLine, int endLine ) c QVector Screen::getLineProperties( int startLine , int endLine ) const { - Q_ASSERT( startLine >= 0 ); + Q_ASSERT( startLine >= 0 ); Q_ASSERT( endLine >= startLine && endLine < history->getLines() + lines ); const int mergedLines = endLine-startLine+1; @@ -502,7 +523,7 @@ QVector Screen::getLineProperties( int startLine , int endLine ) c int index = 0; // copy properties for lines in history - for (int line = startLine; line < startLine + linesInHistory; line++) + for (int line = startLine; line < startLine + linesInHistory; line++) { //TODO Support for line properties other than wrapped lines if (history->isWrappedLine(line)) @@ -556,7 +577,7 @@ void Screen::backspace() if (screenLines[cuY].size() < cuX+1) screenLines[cuY].resize(cuX+1); - if (BS_CLEARS) + if (BS_CLEARS) screenLines[cuY][cuX].character = ' '; } @@ -566,8 +587,8 @@ void Screen::tab(int n) if (n == 0) n = 1; while((n > 0) && (cuX < columns-1)) { - cursorRight(1); - while((cuX < columns-1) && !tabStops[cuX]) + cursorRight(1); + while((cuX < columns-1) && !tabStops[cuX]) cursorRight(1); n--; } @@ -602,20 +623,20 @@ void Screen::initTabStops() // Arrg! The 1st tabstop has to be one longer than the other. // i.e. the kids start counting from 0 instead of 1. // Other programs might behave correctly. Be aware. - for (int i = 0; i < columns; i++) + for (int i = 0; i < columns; i++) tabStops[i] = (i%8 == 0 && i != 0); } void Screen::newLine() { - if (getMode(MODE_NewLine)) + if (getMode(MODE_NewLine)) toStartOfLine(); index(); } void Screen::checkSelection(int from, int to) { - if (selBegin == -1) + if (selBegin == -1) return; int scr_TL = loc(0, history->getLines()); //Clear entire selection if it overlaps region [from, to] @@ -623,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. @@ -664,6 +685,8 @@ void Screen::displayCharacter(unsigned short c) currentChar.backgroundColor = effectiveBackground; currentChar.rendition = effectiveRendition; + lastDrawnChar = c; + int i = 0; int newCursorX = cuX + w--; while(w) @@ -754,11 +777,11 @@ void Screen::scrollDown(int from, int n) _scrolledLines += n; //FIXME: make sure `topMargin', `bottomMargin', `from', `n' is in bounds. - if (n <= 0) + if (n <= 0) return; - if (from > _bottomMargin) + if (from > _bottomMargin) return; - if (from + n > _bottomMargin) + if (from + n > _bottomMargin) n = _bottomMargin - from; moveImage(loc(0,from+n),loc(0,from),loc(columns-1,_bottomMargin-n)); clearImage(loc(0,from),loc(columns-1,from+n-1),' '); @@ -805,7 +828,7 @@ int Screen::getCursorY() const } void Screen::clearImage(int loca, int loce, char c) -{ +{ int scr_TL=loc(0,history->getLines()); //FIXME: check positions @@ -856,8 +879,8 @@ void Screen::moveImage(int dest, int sourceBegin, int sourceEnd) int lines=(sourceEnd-sourceBegin)/columns; //move screen image and line properties: - //the source and destination areas of the image may overlap, - //so it matters that we do the copy in the right order - + //the source and destination areas of the image may overlap, + //so it matters that we do the copy in the right order - //forwards if dest < sourceBegin or backwards otherwise. //(search the web for 'memmove implementation' for details) if (dest < sourceBegin) @@ -992,9 +1015,9 @@ void Screen::setForeColor(int space, int color) { currentForeground = CharacterColor(space, color); - if ( currentForeground.isValid() ) + if ( currentForeground.isValid() ) updateEffectiveRendition(); - else + else setForeColor(COLOR_SPACE_DEFAULT,DEFAULT_FORE_COLOR); } @@ -1002,13 +1025,13 @@ void Screen::setBackColor(int space, int color) { currentBackground = CharacterColor(space, color); - if ( currentBackground.isValid() ) + if ( currentBackground.isValid() ) updateEffectiveRendition(); else setBackColor(COLOR_SPACE_DEFAULT,DEFAULT_BACK_COLOR); } -void Screen::clearSelection() +void Screen::clearSelection() { selBottomRight = -1; selTopLeft = -1; @@ -1020,7 +1043,7 @@ void Screen::getSelectionStart(int& column , int& line) const if ( selTopLeft != -1 ) { column = selTopLeft % columns; - line = selTopLeft / columns; + line = selTopLeft / columns; } else { @@ -1039,11 +1062,11 @@ void Screen::getSelectionEnd(int& column , int& line) const { column = cuX + getHistLines(); line = cuY + getHistLines(); - } + } } void Screen::setSelectionStart(const int x, const int y, const bool mode) { - selBegin = loc(x,y); + selBegin = loc(x,y); /* FIXME, HACK to correct for x too far to the right... */ if (x == columns) selBegin--; @@ -1054,10 +1077,10 @@ void Screen::setSelectionStart(const int x, const int y, const bool mode) void Screen::setSelectionEnd( const int x, const int y) { - if (selBegin == -1) + if (selBegin == -1) return; - int endPos = loc(x,y); + int endPos = loc(x,y); if (endPos < selBegin) { @@ -1067,7 +1090,7 @@ void Screen::setSelectionEnd( const int x, const int y) else { /* FIXME, HACK to correct for x too far to the right... */ - if (x == columns) + if (x == columns) endPos--; selTopLeft = selBegin; @@ -1118,7 +1141,7 @@ bool Screen::isSelectionValid() const return selTopLeft >= 0 && selBottomRight >= 0; } -void Screen::writeSelectionToStream(TerminalCharacterDecoder* decoder , +void Screen::writeSelectionToStream(TerminalCharacterDecoder* decoder , bool preserveLineBreaks) const { if (!isSelectionValid()) @@ -1126,11 +1149,11 @@ void Screen::writeSelectionToStream(TerminalCharacterDecoder* decoder , writeToStream(decoder,selTopLeft,selBottomRight,preserveLineBreaks); } -void Screen::writeToStream(TerminalCharacterDecoder* decoder, +void Screen::writeToStream(TerminalCharacterDecoder* decoder, int startIndex, int endIndex, bool preserveLineBreaks) const { - int top = startIndex / columns; + int top = startIndex / columns; int left = startIndex % columns; int bottom = endIndex / columns; @@ -1150,7 +1173,7 @@ void Screen::writeToStream(TerminalCharacterDecoder* decoder, int copied = copyLineToStream( y, start, count, - decoder, + decoder, appendNewLine, preserveLineBreaks ); @@ -1158,31 +1181,31 @@ void Screen::writeToStream(TerminalCharacterDecoder* decoder, // append a new line character. // // this makes it possible to 'select' a trailing new line character after - // the text on a line. - if ( y == bottom && + // the text on a line. + if ( y == bottom && copied < count ) { Character newLineChar('\n'); decoder->decodeLine(&newLineChar,1,0); } - } + } } -int Screen::copyLineToStream(int line , - int start, +int Screen::copyLineToStream(int line , + int start, int count, TerminalCharacterDecoder* decoder, bool appendNewLine, bool preserveLineBreaks) const { //buffer to hold characters for decoding - //the buffer is static to avoid initialising every + //the buffer is static to avoid initialising every //element on each call to copyLineToStream //(which is unnecessary since all elements will be overwritten anyway) static const int MAX_CHARS = 1024; static Character characterBuffer[MAX_CHARS]; - assert( count < MAX_CHARS ); + Q_ASSERT( count < MAX_CHARS ); LineProperty currentLineProperties = 0; @@ -1196,7 +1219,7 @@ int Screen::copyLineToStream(int line , // retrieve line from history buffer. It is assumed // that the history buffer does not store trailing white space - // at the end of the line, so it does not need to be trimmed here + // at the end of the line, so it does not need to be trimmed here if (count == -1) { count = lineLength-start; @@ -1207,9 +1230,9 @@ int Screen::copyLineToStream(int line , } // safety checks - assert( start >= 0 ); - assert( count >= 0 ); - assert( (start+count) <= history->getLineLen(line) ); + Q_ASSERT( start >= 0 ); + Q_ASSERT( count >= 0 ); + Q_ASSERT( (start+count) <= history->getLineLen(line) ); history->getCells(line,start,count,characterBuffer); @@ -1221,7 +1244,7 @@ int Screen::copyLineToStream(int line , if ( count == -1 ) count = columns - start; - assert( count >= 0 ); + Q_ASSERT( count >= 0 ); const int screenLine = line-history->getLines(); @@ -1238,7 +1261,7 @@ int Screen::copyLineToStream(int line , count = qBound(0,count,length-start); Q_ASSERT( screenLine < lineProperties.count() ); - currentLineProperties |= lineProperties[screenLine]; + currentLineProperties |= lineProperties[screenLine]; } // add new line character at end @@ -1251,8 +1274,8 @@ int Screen::copyLineToStream(int line , count++; } - //decode line and write to text stream - decoder->decodeLine( (Character*) characterBuffer , + //decode line and write to text stream + decoder->decodeLine( (Character*) characterBuffer , count, currentLineProperties ); return count; diff --git a/lib/Screen.h b/lib/Screen.h index b59c4bb..c4baf0e 100644 --- a/lib/Screen.h +++ b/lib/Screen.h @@ -52,21 +52,21 @@ class TerminalCharacterDecoder; characters from the program currently running in the terminal. From this stream it creates an image of characters which is ultimately rendered by the display widget ( TerminalDisplay ). Some types of emulation - may have more than one screen image. + may have more than one screen image. getImage() is used to retrieve the currently visible image which is then used by the display widget to draw the output from the - terminal. + terminal. The number of lines of output history which are kept in addition to the current - screen image depends on the history scroll being used to store the output. + screen image depends on the history scroll being used to store the output. The scroll is specified using setScroll() The output history can be retrieved using writeToStream() - The screen image has a selection associated with it, specified using + The screen image has a selection associated with it, specified using setSelectionStart() and setSelectionEnd(). The selected text can be retrieved using selectedText(). When getImage() is used to retrieve the visible image, - characters which are part of the selection have their colours inverted. + characters which are part of the selection have their colours inverted. */ class Screen { @@ -75,25 +75,25 @@ public: Screen(int lines, int columns); ~Screen(); - // VT100/2 Operations + // VT100/2 Operations // Cursor Movement - - /** - * Move the cursor up by @p n lines. The cursor will stop at the + + /** + * Move the cursor up by @p n lines. The cursor will stop at the * top margin. */ void cursorUp(int n); - /** + /** * Move the cursor down by @p n lines. The cursor will stop at the * bottom margin. */ void cursorDown(int n); - /** + /** * Move the cursor to the left by @p n columns. * The cursor will stop at the first column. */ void cursorLeft(int n); - /** + /** * Move the cursor to the right by @p n columns. * The cursor will stop at the right-most column. */ @@ -107,28 +107,28 @@ public: /** * Sets the margins for scrolling the screen. * - * @param topLine The top line of the new scrolling margin. - * @param bottomLine The bottom line of the new scrolling margin. + * @param topLine The top line of the new scrolling margin. + * @param bottomLine The bottom line of the new scrolling margin. */ void setMargins(int topLine , int bottomLine); - /** Returns the top line of the scrolling region. */ + /** Returns the top line of the scrolling region. */ int topMargin() const; /** Returns the bottom line of the scrolling region. */ int bottomMargin() const; - /** + /** * Resets the scrolling margins back to the top and bottom lines * of the screen. */ void setDefaultMargins(); - - /** - * Moves the cursor down one line, if the MODE_NewLine mode + + /** + * Moves the cursor down one line, if the MODE_NewLine mode * flag is enabled then the cursor is returned to the leftmost * column first. * * Equivalent to NextLine() if the MODE_NewLine flag is set - * or index() otherwise. + * or index() otherwise. */ void newLine(); /** @@ -137,7 +137,7 @@ public: */ void nextLine(); - /** + /** * Move the cursor down one line. If the cursor is on the bottom * line of the scrolling region (as returned by bottomMargin()) the * scrolling region is scrolled up by one line instead. @@ -149,12 +149,12 @@ public: * region is scrolled down by one line instead. */ void reverseIndex(); - - /** - * Scroll the scrolling region of the screen up by @p n lines. - * The scrolling region is initially the whole screen, but can be changed + + /** + * Scroll the scrolling region of the screen up by @p n lines. + * The scrolling region is initially the whole screen, but can be changed * using setMargins() - */ + */ void scrollUp(int n); /** * Scroll the scrolling region of the screen down by @p n lines. @@ -162,12 +162,12 @@ public: * using setMargins() */ void scrollDown(int n); - /** - * Moves the cursor to the beginning of the current line. + /** + * Moves the cursor to the beginning of the current line. * Equivalent to setCursorX(0) */ void toStartOfLine(); - /** + /** * Moves the cursor one column to the left and erases the character * at the new cursor position. */ @@ -176,28 +176,33 @@ public: void tab(int n = 1); /** Moves the cursor @p n tab-stops to the left. */ void backtab(int n); - + // Editing - - /** - * Erase @p n characters beginning from the current cursor position. + + /** + * Erase @p n characters beginning from the current cursor position. * This is equivalent to over-writing @p n characters starting with the current * cursor position with spaces. - * If @p n is 0 then one character is erased. + * If @p n is 0 then one character is erased. */ void eraseChars(int n); - /** - * Delete @p n characters beginning from the current cursor position. - * If @p n is 0 then one character is deleted. + /** + * Delete @p n characters beginning from the current cursor position. + * If @p n is 0 then one character is deleted. */ void deleteChars(int n); /** * Insert @p n blank characters beginning from the current cursor position. - * The position of the cursor is not altered. + * The position of the cursor is not altered. * If @p n is 0 then one character is inserted. */ void insertChars(int n); - /** + /** + * Repeat the preceeding graphic character @count times, including SPACE. + * If @count is 0 then the character is repeated once. + */ + void repeatChars(int count); + /** * Removes @p n lines beginning from the current cursor position. * The position of the cursor is not altered. * If @p n is 0 then one line is removed. @@ -211,14 +216,14 @@ public: void insertLines(int n); /** Clears all the tab stops. */ void clearTabStops(); - /** Sets or removes a tab stop at the cursor's current column. */ + /** Sets or removes a tab stop at the cursor's current column. */ void changeTabStop(bool set); - + /** Resets (clears) the specified screen @p mode. */ void resetMode(int mode); /** Sets (enables) the specified screen @p mode. */ void setMode(int mode); - /** + /** * Saves the state of the specified screen @p mode. It can be restored * using restoreMode() */ @@ -227,19 +232,19 @@ public: void restoreMode(int mode); /** Returns whether the specified screen @p mode is enabled or not .*/ bool getMode(int mode) const; - - /** - * Saves the current position and appearance (text color and style) of the cursor. - * It can be restored by calling restoreCursor() - */ + + /** + * Saves the current position and appearance (text color and style) of the cursor. + * It can be restored by calling restoreCursor() + */ void saveCursor(); /** Restores the position and appearance of the cursor. See saveCursor() */ void restoreCursor(); - - /** Clear the whole screen, moving the current screen contents into the history first. */ + + /** Clear the whole screen, moving the current screen contents into the history first. */ void clearEntireScreen(); - /** - * Clear the area of the screen from the current cursor position to the end of + /** + * Clear the area of the screen from the current cursor position to the end of * the screen. */ void clearToEndOfScreen(); @@ -254,16 +259,16 @@ public: void clearToEndOfLine(); /** Clears from the current cursor position to the beginning of the line. */ void clearToBeginOfLine(); - + /** Fills the entire screen with the letter 'E' */ void helpAlign(); - - /** - * Enables the given @p rendition flag. Rendition flags control the appearance + + /** + * Enables the given @p rendition flag. Rendition flags control the appearance * of characters on the screen. * * @see Character::rendition - */ + */ void setRendition(int rendition); /** * Disables the given @p rendition flag. Rendition flags control the appearance @@ -272,8 +277,8 @@ public: * @see Character::rendition */ void resetRendition(int rendition); - - /** + + /** * Sets the cursor's foreground color. * @param space The color space used by the @p color argument * @param color The new foreground color. The meaning of this depends on @@ -291,24 +296,24 @@ public: * @see CharacterColor */ void setBackColor(int space, int color); - /** - * Resets the cursor's color back to the default and sets the + /** + * Resets the cursor's color back to the default and sets the * character's rendition flags back to the default settings. */ void setDefaultRendition(); - + /** Returns the column which the cursor is positioned at. */ int getCursorX() const; /** Returns the line which the cursor is positioned on. */ int getCursorY() const; - + /** Clear the entire screen and move the cursor to the home position. * Equivalent to calling clearEntireScreen() followed by home(). */ void clear(); - /** + /** * Sets the position of the cursor to the 'home' position at the top-left - * corner of the screen (0,0) + * corner of the screen (0,0) */ void home(); /** @@ -325,41 +330,41 @@ public: *
  • New line mode is disabled. TODO Document me
  • * * - * If @p clearScreen is true then the screen contents are erased entirely, + * If @p clearScreen is true then the screen contents are erased entirely, * otherwise they are unaltered. */ void reset(bool clearScreen = true); - - /** - * Displays a new character at the current cursor position. - * + + /** + * Displays a new character at the current cursor position. + * * If the cursor is currently positioned at the right-edge of the screen and - * line wrapping is enabled then the character is added at the start of a new + * line wrapping is enabled then the character is added at the start of a new * line below the current one. * - * If the MODE_Insert screen mode is currently enabled then the character - * is inserted at the current cursor position, otherwise it will replace the - * character already at the current cursor position. - */ - void displayCharacter(unsigned short c); - + * If the MODE_Insert screen mode is currently enabled then the character + * is inserted at the current cursor position, otherwise it will replace the + * character already at the current cursor position. + */ + void displayCharacter(wchar_t c); + // Do composition with last shown character FIXME: Not implemented yet for KDE 4 void compose(const QString& compose); - - /** - * Resizes the image to a new fixed size of @p new_lines by @p new_columns. + + /** + * Resizes the image to a new fixed size of @p new_lines by @p new_columns. * In the case that @p new_columns is smaller than the current number of columns, * existing lines are not truncated. This prevents characters from being lost * if the terminal display is resized smaller and then larger again. * - * The top and bottom margins are reset to the top and bottom of the new + * The top and bottom margins are reset to the top and bottom of the new * screen size. Tab stops are also reset and the current selection is * cleared. */ void resizeImage(int new_lines, int new_columns); - + /** - * Returns the current screen image. + * Returns the current screen image. * The result is an array of Characters of size [getLines()][getColumns()] which * must be freed by the caller after use. * @@ -370,38 +375,38 @@ public: */ void getImage( Character* dest , int size , int startLine , int endLine ) const; - /** + /** * Returns the additional attributes associated with lines in the image. - * The most important attribute is LINE_WRAPPED which specifies that the + * The most important attribute is LINE_WRAPPED which specifies that the * line is wrapped, * other attributes control the size of characters in the line. */ QVector getLineProperties( int startLine , int endLine ) const; - + /** Return the number of lines. */ - int getLines() const + int getLines() const { return lines; } /** Return the number of columns. */ - int getColumns() const + int getColumns() const { return columns; } /** Return the number of lines in the history buffer. */ int getHistLines() const; - /** - * Sets the type of storage used to keep lines in the history. - * If @p copyPreviousScroll is true then the contents of the previous + /** + * Sets the type of storage used to keep lines in the history. + * If @p copyPreviousScroll is true then the contents of the previous * history buffer are copied into the new scroll. */ void setScroll(const HistoryType& , bool copyPreviousScroll = true); /** Returns the type of storage used to keep lines in the history. */ const HistoryType& getScroll() const; - /** + /** * Returns true if this screen keeps lines that are scrolled off the screen * in a history buffer. */ bool hasScroll() const; - /** + /** * Sets the start of the selection. * * @param column The column index of the first character in the selection. @@ -409,21 +414,21 @@ public: * @param blockSelectionMode True if the selection is in column mode. */ void setSelectionStart(const int column, const int line, const bool blockSelectionMode); - + /** * Sets the end of the current selection. * * @param column The column index of the last character in the selection. - * @param line The line index of the last character in the selection. - */ + * @param line The line index of the last character in the selection. + */ void setSelectionEnd(const int column, const int line); - + /** * Retrieves the start of the selection or the cursor position if there * is no selection. */ void getSelectionStart(int& column , int& line) const; - + /** * Retrieves the end of the selection or the cursor position if there * is no selection. @@ -433,19 +438,19 @@ public: /** Clears the current selection */ void clearSelection(); - /** + /** * Returns true if the character at (@p column, @p line) is part of the - * current selection. - */ + * current selection. + */ bool isSelected(const int column,const int line) const; - /** - * Convenience method. Returns the currently selected text. - * @param preserveLineBreaks Specifies whether new line characters should + /** + * Convenience method. Returns the currently selected text. + * @param preserveLineBreaks Specifies whether new line characters should * be inserted into the returned text at the end of each terminal line. */ QString selectedText(bool preserveLineBreaks) const; - + /** * Copies part of the output to a stream. * @@ -459,11 +464,11 @@ public: * Copies the selected characters, set using @see setSelBeginXY and @see setSelExtentXY * into a stream. * - * @param decoder A decoder which converts terminal characters into text. - * PlainTextDecoder is the most commonly used decoder which converts characters + * @param decoder A decoder which converts terminal characters into text. + * PlainTextDecoder is the most commonly used decoder which converts characters * into plain text with no formatting. - * @param preserveLineBreaks Specifies whether new line characters should - * be inserted into the returned text at the end of each terminal line. + * @param preserveLineBreaks Specifies whether new line characters should + * be inserted into the returned text at the end of each terminal line. */ void writeSelectionToStream(TerminalCharacterDecoder* decoder , bool preserveLineBreaks = true) const; @@ -480,15 +485,15 @@ public: */ void checkSelection(int from, int to); - /** + /** * Sets or clears an attribute of the current line. - * + * * @param property The attribute to set or clear * Possible properties are: * LINE_WRAPPED: Specifies that the line is wrapped. * LINE_DOUBLEWIDTH: Specifies that the characters in the current line * should be double the normal width. - * LINE_DOUBLEHEIGHT:Specifies that the characters in the current line + * LINE_DOUBLEHEIGHT:Specifies that the characters in the current line * should be double the normal height. * Double-height lines are formed of two lines containing the same characters, * with both having the LINE_DOUBLEHEIGHT attribute. @@ -499,24 +504,24 @@ public: */ void setLineProperty(LineProperty property , bool enable); - /** + /** * Returns the number of lines that the image has been scrolled up or down by, * since the last call to resetScrolledLines(). * * a positive return value indicates that the image has been scrolled up, - * a negative return value indicates that the image has been scrolled down. + * a negative return value indicates that the image has been scrolled down. */ int scrolledLines() const; /** * Returns the region of the image which was last scrolled. * - * This is the area of the image from the top margin to the + * This is the area of the image from the top margin to the * bottom margin when the last scroll occurred. */ QRect lastScrolledRegion() const; - /** + /** * Resets the count of the number of lines that the image has been scrolled up or down by, * see scrolledLines() */ @@ -529,7 +534,7 @@ public: * * If the history is not unlimited then it will drop * the oldest lines of output if new lines are added when - * it is full. + * it is full. */ int droppedLines() const; @@ -539,32 +544,32 @@ public: */ void resetDroppedLines(); - /** + /** * Fills the buffer @p dest with @p count instances of the default (ie. blank) * Character style. */ static void fillWithDefaultChar(Character* dest, int count); -private: +private: - //copies a line of text from the screen or history into a stream using a + //copies a line of text from the screen or history into a stream using a //specified character decoder. Returns the number of lines actually copied, //which may be less than 'count' if (start+count) is more than the number of characters on - //the line + //the line // - //line - the line number to copy, from 0 (the earliest line in the history) up to + //line - the line number to copy, from 0 (the earliest line in the history) up to // history->getLines() + lines - 1 //start - the first column on the line to copy //count - the number of characters on the line to copy //decoder - a decoder which converts terminal characters (an Character array) into text //appendNewLine - if true a new line character (\n) is appended to the end of the line - int copyLineToStream(int line, - int start, - int count, + int copyLineToStream(int line, + int start, + int count, TerminalCharacterDecoder* decoder, bool appendNewLine, bool preserveLineBreaks) const; - + //fills a section of the screen image with the character 'c' //the parameters are specified as offsets from the start of the screen image. //the loc(x,y) macro can be used to generate these values from a column,line pair. @@ -576,7 +581,7 @@ private: // //NOTE: moveImage() can only move whole lines void moveImage(int dest, int sourceBegin, int sourceEnd); - // scroll up 'i' lines in current region, clearing the bottom 'i' lines + // scroll up 'i' lines in current region, clearing the bottom 'i' lines void scrollUp(int from, int i); // scroll down 'i' lines in current region, clearing the top 'i' lines void scrollDown(int from, int i); @@ -591,7 +596,7 @@ private: bool isSelectionValid() const; // copies text from 'startIndex' to 'endIndex' to a stream // startIndex and endIndex are positions generated using the loc(x,y) macro - void writeToStream(TerminalCharacterDecoder* decoder, int startIndex, + void writeToStream(TerminalCharacterDecoder* decoder, int startIndex, int endIndex, bool preserveLineBreaks = true) const; // copies 'count' lines from the screen buffer into 'dest', // starting from 'startLine', where 0 is the first line in the screen buffer @@ -613,11 +618,11 @@ private: int _droppedLines; - QVarLengthArray lineProperties; - + QVarLengthArray lineProperties; + // history buffer --------------- HistoryScroll* history; - + // cursor location int cuX; int cuY; @@ -625,7 +630,7 @@ private: // cursor color and rendition info CharacterColor currentForeground; CharacterColor currentBackground; - quint8 currentRendition; + quint8 currentRendition; // margins ---------------- int _topMargin; @@ -650,7 +655,7 @@ private: CharacterColor effectiveBackground; // the cu_* variables above quint8 effectiveRendition; // to speed up operation - class SavedState + class SavedState { public: SavedState() @@ -663,10 +668,13 @@ private: CharacterColor background; }; SavedState savedState; - + // last position where we added a character int lastPos; + // used in REP (repeating char) + unsigned short lastDrawnChar; + static Character defaultChar; }; diff --git a/lib/ScreenWindow.cpp b/lib/ScreenWindow.cpp index 390ae3f..640465f 100644 --- a/lib/ScreenWindow.cpp +++ b/lib/ScreenWindow.cpp @@ -59,7 +59,7 @@ Character* ScreenWindow::getImage() { // reallocate internal buffer if the window size has changed int size = windowLines() * windowColumns(); - if (_windowBuffer == 0 || _windowBufferSize != size) + if (_windowBuffer == 0 || _windowBufferSize != size) { delete[] _windowBuffer; _windowBufferSize = size; @@ -73,7 +73,7 @@ Character* ScreenWindow::getImage() _screen->getImage(_windowBuffer,size, currentLine(),endWindowLine()); - // this window may look beyond the end of the screen, in which + // this window may look beyond the end of the screen, in which // case there will be an unused area which needs to be filled // with blank characters fillUnusedArea(); @@ -90,10 +90,10 @@ void ScreenWindow::fillUnusedArea() int unusedLines = windowEndLine - screenEndLine; int charsToFill = unusedLines * windowColumns(); - Screen::fillWithDefaultChar(_windowBuffer + _windowBufferSize - charsToFill,charsToFill); + Screen::fillWithDefaultChar(_windowBuffer + _windowBufferSize - charsToFill,charsToFill); } -// return the index of the line at the end of this window, or if this window +// return the index of the line at the end of this window, or if this window // goes beyond the end of the screen, the index of the line at the end // of the screen. // @@ -108,7 +108,7 @@ int ScreenWindow::endWindowLine() const QVector ScreenWindow::getLineProperties() { QVector result = _screen->getLineProperties(currentLine(),endWindowLine()); - + if (result.count() != windowLines()) result.resize(windowLines()); @@ -133,7 +133,7 @@ void ScreenWindow::getSelectionEnd( int& column , int& line ) void ScreenWindow::setSelectionStart( int column , int line , bool columnMode ) { _screen->setSelectionStart( column , qMin(line + currentLine(),endWindowLine()) , columnMode); - + _bufferNeedsUpdate = true; emit selectionChanged(); } @@ -165,7 +165,7 @@ void ScreenWindow::setWindowLines(int lines) } int ScreenWindow::windowLines() const { - return _windowLines; + return _windowLines; } int ScreenWindow::windowColumns() const @@ -186,11 +186,11 @@ int ScreenWindow::columnCount() const QPoint ScreenWindow::cursorPosition() const { QPoint position; - + position.setX( _screen->getCursorX() ); position.setY( _screen->getCursorY() ); - return position; + return position; } int ScreenWindow::currentLine() const @@ -206,7 +206,7 @@ void ScreenWindow::scrollBy( RelativeScrollMode mode , int amount ) } else if ( mode == ScrollPages ) { - scrollTo( currentLine() + amount * ( windowLines() / 2 ) ); + scrollTo( currentLine() + amount * ( windowLines() / 2 ) ); } } @@ -247,7 +247,7 @@ int ScreenWindow::scrollCount() const return _scrollCount; } -void ScreenWindow::resetScrollCount() +void ScreenWindow::resetScrollCount() { _scrollCount = 0; } @@ -267,18 +267,18 @@ void ScreenWindow::notifyOutputChanged() // move window to the bottom of the screen and update scroll count // if this window is currently tracking the bottom of the screen if ( _trackOutput ) - { + { _scrollCount -= _screen->scrolledLines(); _currentLine = qMax(0,_screen->getHistLines() - (windowLines()-_screen->getLines())); } else { - // if the history is not unlimited then it may + // if the history is not unlimited then it may // have run out of space and dropped the oldest // lines of output - in this case the screen - // window's current line number will need to + // window's current line number will need to // be adjusted - otherwise the output will scroll - _currentLine = qMax(0,_currentLine - + _currentLine = qMax(0,_currentLine - _screen->droppedLines()); // ensure that the screen window's current position does @@ -288,7 +288,7 @@ void ScreenWindow::notifyOutputChanged() _bufferNeedsUpdate = true; - emit outputChanged(); + emit outputChanged(); } //#include "ScreenWindow.moc" diff --git a/lib/ScreenWindow.h b/lib/ScreenWindow.h index 3ef2675..87d0840 100644 --- a/lib/ScreenWindow.h +++ b/lib/ScreenWindow.h @@ -35,7 +35,7 @@ class Screen; /** * Provides a window onto a section of a terminal screen. A terminal widget can then render - * the contents of the window and use the window to change the terminal screen's selection + * the contents of the window and use the window to change the terminal screen's selection * in response to mouse or keyboard input. * * A new ScreenWindow for a terminal session can be created by calling Emulation::createWindow() @@ -55,7 +55,7 @@ class ScreenWindow : public QObject Q_OBJECT public: - /** + /** * Constructs a new screen window with the given parent. * A screen must be specified by calling setScreen() before calling getImage() or getLineProperties(). * @@ -72,7 +72,7 @@ public: /** Returns the screen which this window looks onto */ Screen* screen() const; - /** + /** * Returns the image of characters which are currently visible through this window * onto the screen. * @@ -89,14 +89,14 @@ public: /** * Returns the number of lines which the region of the window - * specified by scrollRegion() has been scrolled by since the last call - * to resetScrollCount(). scrollRegion() is in most cases the + * specified by scrollRegion() has been scrolled by since the last call + * to resetScrollCount(). scrollRegion() is in most cases the * whole window, but will be a smaller area in, for example, applications * which provide split-screen facilities. * * This is not guaranteed to be accurate, but allows views to optimize * rendering by reducing the amount of costly text rendering that - * needs to be done when the output is scrolled. + * needs to be done when the output is scrolled. */ int scrollCount() const; @@ -106,7 +106,7 @@ public: void resetScrollCount(); /** - * Returns the area of the window which was last scrolled, this is + * Returns the area of the window which was last scrolled, this is * usually the whole window area. * * Like scrollCount(), this is not guaranteed to be accurate, @@ -114,8 +114,8 @@ public: */ QRect scrollRegion() const; - /** - * Sets the start of the selection to the given @p line and @p column within + /** + * Sets the start of the selection to the given @p line and @p column within * the window. */ void setSelectionStart( int column , int line , bool columnMode ); @@ -123,7 +123,7 @@ public: * Sets the end of the selection to the given @p line and @p column within * the window. */ - void setSelectionEnd( int column , int line ); + void setSelectionEnd( int column , int line ); /** * Retrieves the start of the selection within the window. */ @@ -136,7 +136,7 @@ public: * Returns true if the character at @p line , @p column is part of the selection. */ bool isSelected( int column , int line ); - /** + /** * Clears the current selection */ void clearSelection(); @@ -147,7 +147,7 @@ public: int windowLines() const; /** Returns the number of columns in the window */ int windowColumns() const; - + /** Returns the total number of lines in the screen */ int lineCount() const; /** Returns the total number of columns in the screen */ @@ -156,13 +156,13 @@ public: /** Returns the index of the line which is currently at the top of this window */ int currentLine() const; - /** - * Returns the position of the cursor + /** + * Returns the position of the cursor * within the window. */ QPoint cursorPosition() const; - /** + /** * Convenience method. Returns true if the window is currently at the bottom * of the screen. */ @@ -176,33 +176,33 @@ public: { /** Scroll the window down by a given number of lines. */ ScrollLines, - /** + /** * Scroll the window down by a given number of pages, where * one page is windowLines() lines */ ScrollPages }; - /** + /** * Scrolls the window relative to its current position on the screen. * * @param mode Specifies whether @p amount refers to the number of lines or the number - * of pages to scroll. + * of pages to scroll. * @param amount The number of lines or pages ( depending on @p mode ) to scroll by. If * this number is positive, the view is scrolled down. If this number is negative, the view * is scrolled up. */ void scrollBy( RelativeScrollMode mode , int amount ); - /** + /** * Specifies whether the window should automatically move to the bottom * of the screen when new output is added. * - * If this is set to true, the window will be moved to the bottom of the associated screen ( see + * If this is set to true, the window will be moved to the bottom of the associated screen ( see * screen() ) when the notifyOutputChanged() method is called. */ void setTrackOutput(bool trackOutput); - /** + /** * Returns whether the window automatically moves to the bottom of the screen as * new output is added. See setTrackOutput() */ @@ -216,7 +216,7 @@ public: QString selectedText( bool preserveLineBreaks ) const; public slots: - /** + /** * Notifies the window that the contents of the associated terminal screen have changed. * This moves the window to the bottom of the screen if trackOutput() is true and causes * the outputChanged() signal to be emitted. @@ -225,13 +225,13 @@ public slots: signals: /** - * Emitted when the contents of the associated terminal screen (see screen()) changes. + * Emitted when the contents of the associated terminal screen (see screen()) changes. */ void outputChanged(); /** * Emitted when the screen window is scrolled to a different position. - * + * * @param line The line which is now at the top of the window. */ void scrolled(int line); @@ -250,7 +250,7 @@ private: int _windowLines; int _currentLine; // see scrollTo() , currentLine() - bool _trackOutput; // see setTrackOutput() , trackOutput() + bool _trackOutput; // see setTrackOutput() , trackOutput() int _scrollCount; // count of lines which the window has been scrolled by since // the last call to resetScrollCount() }; diff --git a/lib/SearchBar.cpp b/lib/SearchBar.cpp index 21e7325..7a5e52b 100644 --- a/lib/SearchBar.cpp +++ b/lib/SearchBar.cpp @@ -26,27 +26,28 @@ SearchBar::SearchBar(QWidget *parent) : QWidget(parent) { widget.setupUi(this); + setAutoFillBackground(true); // make it always opaque, especially inside translucent windows connect(widget.closeButton, SIGNAL(clicked()), this, SLOT(hide())); connect(widget.searchTextEdit, SIGNAL(textChanged(QString)), this, SIGNAL(searchCriteriaChanged())); connect(widget.findPreviousButton, SIGNAL(clicked()), this, SIGNAL(findPrevious())); connect(widget.findNextButton, SIGNAL(clicked()), this, SIGNAL(findNext())); - + connect(this, SIGNAL(searchCriteriaChanged()), this, SLOT(clearBackgroundColor())); QMenu *optionsMenu = new QMenu(widget.optionsButton); widget.optionsButton->setMenu(optionsMenu); - + m_matchCaseMenuEntry = optionsMenu->addAction(tr("Match case")); m_matchCaseMenuEntry->setCheckable(true); m_matchCaseMenuEntry->setChecked(true); connect(m_matchCaseMenuEntry, SIGNAL(toggled(bool)), this, SIGNAL(searchCriteriaChanged())); - + m_useRegularExpressionMenuEntry = optionsMenu->addAction(tr("Regular expression")); m_useRegularExpressionMenuEntry->setCheckable(true); connect(m_useRegularExpressionMenuEntry, SIGNAL(toggled(bool)), this, SIGNAL(searchCriteriaChanged())); - m_highlightMatchesMenuEntry = optionsMenu->addAction(tr("Higlight all matches")); + m_highlightMatchesMenuEntry = optionsMenu->addAction(tr("Highlight all matches")); m_highlightMatchesMenuEntry->setCheckable(true); m_highlightMatchesMenuEntry->setChecked(true); connect(m_highlightMatchesMenuEntry, SIGNAL(toggled(bool)), this, SIGNAL(highlightMatchesChanged(bool))); @@ -92,20 +93,20 @@ void SearchBar::noMatchFound() void SearchBar::keyReleaseEvent(QKeyEvent* keyEvent) { - if (keyEvent->key() == Qt::Key_Return || keyEvent->key() == Qt::Key_Enter) + if (keyEvent->key() == Qt::Key_Return || keyEvent->key() == Qt::Key_Enter) { if (keyEvent->modifiers() == Qt::ShiftModifier) { findPrevious(); } - else + else { findNext(); } } else if (keyEvent->key() == Qt::Key_Escape) { - hide(); + hide(); } } @@ -115,4 +116,4 @@ void SearchBar::clearBackgroundColor() p.setColor(QPalette::Base, Qt::white); widget.searchTextEdit->setPalette(p); -} \ No newline at end of file +} diff --git a/lib/SearchBar.h b/lib/SearchBar.h index 3eb751f..0201173 100644 --- a/lib/SearchBar.h +++ b/lib/SearchBar.h @@ -33,7 +33,7 @@ public: QString searchText(); bool useRegularExpression(); bool matchCase(); - bool highlightAllMatches(); + bool highlightAllMatches(); public slots: void noMatchFound(); diff --git a/lib/SearchBar.ui b/lib/SearchBar.ui index 6e0c4e8..91947d9 100644 --- a/lib/SearchBar.ui +++ b/lib/SearchBar.ui @@ -66,16 +66,11 @@ ... - - - + QToolButton::InstantPopup - - Qt::DownArrow - diff --git a/lib/Session.cpp b/lib/Session.cpp index 0541394..b8e0595 100644 --- a/lib/Session.cpp +++ b/lib/Session.cpp @@ -26,7 +26,6 @@ #include "Session.h" // Standard -#include #include // Qt @@ -62,6 +61,7 @@ Session::Session(QObject* parent) : , _autoClose(true) , _wantedClose(false) , _silenceSeconds(10) + , _isTitleChanged(false) , _addToUtmp(false) // disabled by default because of a bug encountered on certain systems // which caused Konsole to hang when closing a tab and then opening a new // one. A 'QProcess destroyed while still running' warning was being @@ -84,6 +84,7 @@ Session::Session(QObject* parent) : //create teletype for I/O with shell process _shellProcess = new Pty(); + ptySlaveFd = _shellProcess->pty()->slaveFd(); //create emulation backend _emulation = new Vt102Emulation(); @@ -98,9 +99,13 @@ Session::Session(QObject* parent) : this, SIGNAL( changeTabTextColorRequest( int ) ) ); connect( _emulation, SIGNAL(profileChangeCommandReceived(const QString &)), this, SIGNAL( profileChangeCommandReceived(const QString &)) ); - // TODO - // connect( _emulation,SIGNAL(imageSizeChanged(int,int)) , this , - // SLOT(onEmulationSizeChange(int,int)) ); + + connect(_emulation, SIGNAL(imageResizeRequest(QSize)), + this, SLOT(onEmulationSizeChange(QSize))); + connect(_emulation, SIGNAL(imageSizeChanged(int, int)), + this, SLOT(onViewSizeChange(int, int))); + connect(_emulation, &Vt102Emulation::cursorChanged, + this, &Session::cursorChanged); //connect teletype to emulation backend _shellProcess->setUtf8Mode(_emulation->utf8()); @@ -123,24 +128,11 @@ Session::Session(QObject* parent) : WId Session::windowId() const { - // Returns a window ID for this session which is used - // to set the WINDOWID environment variable in the shell - // process. - // - // Sessions can have multiple views or no views, which means - // that a single ID is not always going to be accurate. - // - // If there are no views, the window ID is just 0. If - // there are multiple views, then the window ID for the - // top-level window which contains the first view is - // returned - - if ( _views.count() == 0 ) { - return 0; - } else { - QQuickWindow * window = _views.first()->window(); - return (window ? window->winId() : 0); - } + // On Qt5, requesting window IDs breaks QQuickWidget and the likes, + // for example, see the following bug reports: + // https://bugreports.qt.io/browse/QTBUG-40765 + // https://codereview.qt-project.org/#/c/94880/ + return 0; } void Session::setDarkBackground(bool darkBackground) @@ -201,6 +193,11 @@ void Session::addView(TerminalDisplay * widget) widget->setUsesMouse( _emulation->programUsesMouse() ); + connect( _emulation , SIGNAL(programBracketedPasteModeChanged(bool)) , + widget , SLOT(setBracketedPasteMode(bool)) ); + + widget->setBracketedPasteMode(_emulation->programBracketedPasteMode()); + widget->setScreenWindow(_emulation->createWindow()); } @@ -251,53 +248,40 @@ void Session::removeView(TerminalDisplay * widget) void Session::run() { - //check that everything is in place to run the session - if (_program.isEmpty()) { - qDebug() << "Session::run() - program to run not set."; - } - else { - qDebug() << "Session::run() - program:" << _program; - } - - if (_arguments.isEmpty()) { - qDebug() << "Session::run() - no command line arguments specified."; - } - else { - qDebug() << "Session::run() - arguments:" << _arguments; - } - // Upon a KPty error, there is no description on what that error was... // Check to see if the given program is executable. - /* ok iam not exactly sure where _program comes from - however it was set to /bin/bash on my system * Thats bad for BSD as its /usr/local/bin/bash there - its also bad for arch as its /usr/bin/bash there too! * So i added a check to see if /bin/bash exists - if no then we use $SHELL - if that does not exist either, we fall back to /bin/sh * As far as i know /bin/sh exists on every unix system.. You could also just put some ifdef __FREEBSD__ here but i think these 2 filechecks are worth * their computing time on any system - especially with the problem on arch linux beeing there too. */ - QString exec = QFile::encodeName(_program); + QString exec = QString::fromLocal8Bit(QFile::encodeName(_program)); // if 'exec' is not specified, fall back to default shell. if that // is not set then fall back to /bin/sh // here we expect full path. If there is no fullpath let's expect it's // a custom shell (eg. python, etc.) available in the PATH. - if (exec.startsWith("/")) + if (exec.startsWith(QLatin1Char('/')) || exec.isEmpty()) { + const QString defaultShell{QLatin1String("/bin/sh")}; + QFile excheck(exec); if ( exec.isEmpty() || !excheck.exists() ) { - exec = getenv("SHELL"); + exec = QString::fromLocal8Bit(qgetenv("SHELL")); } excheck.setFileName(exec); if ( exec.isEmpty() || !excheck.exists() ) { - exec = "/bin/sh"; + qWarning() << "Neither default shell nor $SHELL is set to a correct path. Fallback to" << defaultShell; + exec = defaultShell; } } // _arguments sometimes contain ("") so isEmpty() // or count() does not work as expected... - QString argsTmp(_arguments.join(" ").trimmed()); + QString argsTmp(_arguments.join(QLatin1Char(' ')).trimmed()); QStringList arguments; arguments << exec; if (argsTmp.length()) @@ -317,7 +301,7 @@ void Session::run() // tell the terminal exactly which colors are being used, but instead approximates // the color scheme as "black on white" or "white on black" depending on whether // the background color is deemed dark or not - QString backgroundColorHint = _hasDarkBackground ? "COLORFGBG=15;0" : "COLORFGBG=0;15"; + QString backgroundColorHint = _hasDarkBackground ? QLatin1String("COLORFGBG=15;0") : QLatin1String("COLORFGBG=0;15"); /* if we do all the checking if this shell exists then we use it ;) * Dont know about the arguments though.. maybe youll need some more checking im not sure @@ -335,7 +319,20 @@ void Session::run() } _shellProcess->setWriteable(false); // We are reachable via kwrited. - qDebug() << "started!"; + emit started(); +} + +void Session::runEmptyPTY() +{ + _shellProcess->setFlowControlEnabled(_flowControl); + _shellProcess->setErase(_emulation->eraseChar()); + _shellProcess->setWriteable(false); + + // disconnet send data from emulator to internal terminal process + disconnect( _emulation,SIGNAL(sendData(const char *,int)), + _shellProcess, SLOT(sendData(const char *,int)) ); + + _shellProcess->setEmptyPTYProperties(); emit started(); } @@ -346,6 +343,7 @@ void Session::setUserTitle( int what, const QString & caption ) // (btw: what=0 changes _userTitle and icon, what=1 only icon, what=2 only _nameTitle if ((what == 0) || (what == 2)) { + _isTitleChanged = true; if ( _userTitle != caption ) { _userTitle = caption; modified = true; @@ -353,6 +351,7 @@ void Session::setUserTitle( int what, const QString & caption ) } if ((what == 0) || (what == 1)) { + _isTitleChanged = true; if ( _iconText != caption ) { _iconText = caption; modified = true; @@ -360,8 +359,8 @@ void Session::setUserTitle( int what, const QString & caption ) } if (what == 11) { - QString colorString = caption.section(';',0,0); - qDebug() << __FILE__ << __LINE__ << ": setting background colour to " << colorString; + QString colorString = caption.section(QLatin1Char(';'),0,0); + //qDebug() << __FILE__ << __LINE__ << ": setting background colour to " << colorString; QColor backColor = QColor(colorString); if (backColor.isValid()) { // change color via \033]11;Color\007 if (backColor != _modifiedBackground) { @@ -378,6 +377,7 @@ void Session::setUserTitle( int what, const QString & caption ) } if (what == 30) { + _isTitleChanged = true; if ( _nameTitle != caption ) { setTitle(Session::NameRole,caption); return; @@ -386,12 +386,13 @@ void Session::setUserTitle( int what, const QString & caption ) if (what == 31) { QString cwd=caption; - cwd=cwd.replace( QRegExp("^~"), QDir::homePath() ); + cwd=cwd.replace( QRegExp(QLatin1String("^~")), QDir::homePath() ); emit openUrlRequest(cwd); } // change icon via \033]32;Icon\007 if (what == 32) { + _isTitleChanged = true; if ( _iconName != caption ) { _iconName = caption; @@ -467,8 +468,8 @@ void Session::activityStateSet(int state) if ( _monitorActivity ) { //FIXME: See comments in Session::monitorTimerDone() if (!_notifiedActivity) { - emit activity(); _notifiedActivity=true; + emit activity(); } } } @@ -487,9 +488,9 @@ void Session::onViewSizeChange(int /*height*/, int /*width*/) { updateTerminalSize(); } -void Session::onEmulationSizeChange(int lines , int columns) +void Session::onEmulationSizeChange(QSize size) { - setSize( QSize(lines,columns) ); + setSize(size); } void Session::updateTerminalSize() @@ -592,7 +593,7 @@ QString Session::profileKey() const void Session::done(int exitStatus) { if (!_autoClose) { - _userTitle = ("This session is done. Finished"); + _userTitle = QString::fromLatin1("This session is done. Finished"); emit titleChanged(); return; } @@ -695,6 +696,11 @@ QString Session::iconText() const return _iconText; } +bool Session::isTitleChanged() const +{ + return _isTitleChanged; +} + void Session::setHistoryType(const HistoryType & hType) { _emulation->setHistory(hType); @@ -961,6 +967,10 @@ int Session::processId() const { return _shellProcess->pid(); } +int Session::getPtySlaveFd() const +{ + return ptySlaveFd; +} SessionGroup::SessionGroup() : _masterMode(0) diff --git a/lib/Session.h b/lib/Session.h index f59f40d..59dfeb8 100644 --- a/lib/Session.h +++ b/lib/Session.h @@ -25,10 +25,10 @@ #ifndef SESSION_H #define SESSION_H - #include #include +#include "Emulation.h" #include "History.h" #include "ProcessInfo.h" @@ -284,6 +284,9 @@ public: /** Returns the text of the icon associated with this session. */ QString iconText() const; + /** Flag if the title/icon was changed by user/shell. */ + bool isTitleChanged() const; + /** Specifies whether a utmp entry should be created for the pty used by this session. */ void setAddToUtmp(bool); @@ -369,6 +372,13 @@ public: // void cancelZModem(); // bool isZModemBusy() { return _zmodemBusy; } + /** + * Returns a pty slave file descriptor. + * This can be used for display and control + * a remote terminal. + */ + int getPtySlaveFd() const; + public slots: /** @@ -378,6 +388,13 @@ public slots: */ void run(); + /** + * Starts the terminal session for "as is" PTY + * (without the direction a data to internal terminal process). + * It can be used for control or display a remote/external terminal. + */ + void runEmptyPTY(); + /** * Closes the terminal session. This sends a hangup signal * (SIGHUP) to the terminal process and causes the done(Session*) @@ -467,6 +484,11 @@ signals: */ void flowControlEnabledChanged(bool enabled); + /** + * Broker for Emulation::cursorChanged() signal + */ + void cursorChanged(Emulation::KeyboardCursorShape cursorShape, bool blinkingCursorEnabled); + void silence(); void activity(); @@ -479,7 +501,7 @@ private slots: void monitorTimerDone(); void onViewSizeChange(int height, int width); - void onEmulationSizeChange(int lines , int columns); + void onEmulationSizeChange(QSize); void activityStateSet(int); @@ -523,6 +545,7 @@ private: QString _iconName; QString _iconText; // as set by: echo -en '\033]1;IconText\007 + bool _isTitleChanged; ///< flag if the title/icon was changed by user bool _addToUtmp; bool _flowControl; bool _fullScripting; @@ -550,8 +573,8 @@ private: ProcessInfo *_foregroundProcessInfo; int _foregroundPid; - static int lastSessionId; + int ptySlaveFd; }; /** diff --git a/lib/ShellCommand.cpp b/lib/ShellCommand.cpp index 7440305..5b86537 100644 --- a/lib/ShellCommand.cpp +++ b/lib/ShellCommand.cpp @@ -42,7 +42,7 @@ ShellCommand::ShellCommand(const QString & fullCommand) QChar ch = fullCommand[i]; const bool isLastChar = ( i == fullCommand.count() - 1 ); - const bool isQuote = ( ch == '\'' || ch == '\"' ); + const bool isQuote = ( ch == QLatin1Char('\'') || ch == QLatin1Char('\"') ); if ( !isLastChar && isQuote ) { inQuotes = !inQuotes; @@ -68,7 +68,7 @@ ShellCommand::ShellCommand(const QString & command , const QStringList & argumen } QString ShellCommand::fullCommand() const { - return _arguments.join(QChar(' ')); + return _arguments.join(QLatin1Char(' ')); } QString ShellCommand::command() const { @@ -96,8 +96,9 @@ QStringList ShellCommand::expand(const QStringList & items) { QStringList result; - foreach( QString item , items ) - result << expand(item); + for(const QString &item : items) { + result << expand(item); + } return result; } @@ -152,7 +153,7 @@ static bool expandEnv( QString & text ) int len = pos2 - pos; QString key = text.mid( pos+1, len-1); QString value = - QString::fromLocal8Bit( ::getenv(key.toLocal8Bit()) ); + QString::fromLocal8Bit( qgetenv(key.toLocal8Bit().constData()) ); if ( !value.isEmpty() ) { expanded = true; diff --git a/lib/TerminalCharacterDecoder.cpp b/lib/TerminalCharacterDecoder.cpp index d5469f6..579dedf 100644 --- a/lib/TerminalCharacterDecoder.cpp +++ b/lib/TerminalCharacterDecoder.cpp @@ -1,8 +1,8 @@ /* This file is part of Konsole, an X terminal. - + Copyright 2006-2008 by Robert Knight - + This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or @@ -82,9 +82,9 @@ 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; // if inclusion of trailing whitespace is disabled then find the end of the @@ -93,19 +93,19 @@ 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--; } } - + for (int i=0;i') - text.append(">"); - else - text.append(ch); + text.append(L">"); + else + 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 } - + } //close any remaining open inner spans @@ -231,18 +231,18 @@ void HTMLDecoder::decodeLine(const Character* const characters, int count, LineP closeSpan(text); //start new line - text.append("
    "); - - *_output << text; + text.append(L"
    "); + + *_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(QLatin1String("")).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 5bdc035..a73e9a1 100644 --- a/lib/TerminalCharacterDecoder.h +++ b/lib/TerminalCharacterDecoder.h @@ -1,8 +1,8 @@ /* This file is part of Konsole, an X terminal. - + Copyright 2006-2008 by Robert Knight - + This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or @@ -38,7 +38,7 @@ namespace Konsole * and background colours and other appearance-related properties into text strings. * * Derived classes may produce either plain text with no other colour or appearance information, or - * they may produce text which incorporates these additional properties. + * they may produce text which incorporates these additional properties. */ class TerminalCharacterDecoder { @@ -58,9 +58,9 @@ public: * @param count The number of characters * @param properties Additional properties which affect all characters in the line */ - virtual void decodeLine(const Character* const characters, + virtual void decodeLine(const Character* const characters, int count, - LineProperty properties) = 0; + LineProperty properties) = 0; }; /** @@ -70,10 +70,10 @@ public: class PlainTextDecoder : public TerminalCharacterDecoder { public: - PlainTextDecoder(); + PlainTextDecoder(); - /** - * Set whether trailing whitespace at the end of lines should be included + /** + * Set whether trailing whitespace at the end of lines should be included * in the output. * Defaults to true. */ @@ -83,9 +83,9 @@ public: * in the output. */ bool trailingWhitespace() const; - /** + /** * Returns of character positions in the output stream - * at which new lines where added. Returns an empty if setTrackLinePositions() is false or if + * at which new lines where added. Returns an empty if setTrackLinePositions() is false or if * the output device is not a string. */ QList linePositions() const; @@ -97,9 +97,9 @@ public: virtual void decodeLine(const Character* const characters, int count, - LineProperty properties); + LineProperty properties); + - private: QTextStream* _output; bool _includeTrailingWhitespace; @@ -114,7 +114,7 @@ private: class HTMLDecoder : public TerminalCharacterDecoder { public: - /** + /** * Constructs an HTML decoder using a default black-on-white color scheme. */ HTMLDecoder(); @@ -124,7 +124,7 @@ public: * output */ void setColorTable( const ColorEntry* table ); - + virtual void decodeLine(const Character* const characters, int count, LineProperty properties); @@ -133,12 +133,12 @@ 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; - bool _innerSpanOpen; + bool _innerSpanOpen; quint8 _lastRendition; CharacterColor _lastForeColor; CharacterColor _lastBackColor; diff --git a/lib/TerminalDisplay.cpp b/lib/TerminalDisplay.cpp index 189a609..788cfab 100644 --- a/lib/TerminalDisplay.cpp +++ b/lib/TerminalDisplay.cpp @@ -1,9 +1,9 @@ /* This file is part of Konsole, a terminal emulator for KDE. - + Copyright 2006-2008 by Robert Knight Copyright 1997,1998 by Lars Doelle - + 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 2 of the License, or @@ -39,7 +39,6 @@ #include #include #include -#include #include #include #include @@ -103,7 +102,7 @@ bool TerminalDisplay::_antialiasText = true; bool TerminalDisplay::HAVE_TRANSPARENCY = false; // we use this to force QPainter to display text in LTR mode -// more information can be found in: http://unicode.org/reports/tr9/ +// more information can be found in: http://unicode.org/reports/tr9/ const QChar LTR_OVERRIDE_CHAR( 0x202D ); /* ------------------------------------------------------------------------- */ @@ -156,11 +155,11 @@ void TerminalDisplay::setBackgroundColor(const QColor& color) { _colorTable[DEFAULT_BACK_COLOR].color = color; QPalette p = palette(); - p.setColor( backgroundRole(), color ); + p.setColor( backgroundRole(), color ); setPalette( p ); - // Avoid propagating the palette change to the scroll bar - _scrollBar->setPalette( QApplication::palette() ); + // Avoid propagating the palette change to the scroll bar + _scrollBar->setPalette( QApplication::palette() ); update(); } @@ -196,12 +195,12 @@ 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])); } - + // assert for i in [0..31] : vt100extended(vt100_graphics[i]) == i. @@ -222,14 +221,14 @@ void TerminalDisplay::fontChange(const QFont&) // "Base character width on widest ASCII character. This prevents too wide // characters in the presence of double wide (e.g. Japanese) characters." // Get the width from representative normal width characters - _fontWidth = qRound((double)fm.width(REPCHAR)/(double)strlen(REPCHAR)); + _fontWidth = qRound((double)fm.width(QLatin1String(REPCHAR))/(double)qstrlen(REPCHAR)); _fixedFont = true; - int fw = fm.width(REPCHAR[0]); - for(unsigned int i=1; i< strlen(REPCHAR); i++) + int fw = fm.width(QLatin1Char(REPCHAR[0])); + for(unsigned int i=1; i< qstrlen(REPCHAR); i++) { - if (fw != fm.width(REPCHAR[i])) + if (fw != fm.width(QLatin1Char(REPCHAR[i]))) { _fixedFont = false; break; @@ -243,14 +242,37 @@ void TerminalDisplay::fontChange(const QFont&) emit changedFontMetricSignal( _fontHeight, _fontWidth ); propagateSize(); + + // We will run paint event testing procedure. + // Although this operation will destory the orignal content, + // the content will be drawn again after the test. + _drawTextTestFlag = true; update(); } +void TerminalDisplay::calDrawTextAdditionHeight(QPainter& painter) +{ + QRect test_rect, feedback_rect; + test_rect.setRect(1, 1, _fontWidth * 4, _fontHeight); + painter.drawText(test_rect, Qt::AlignBottom, LTR_OVERRIDE_CHAR + QLatin1String("Mq"), &feedback_rect); + + //qDebug() << "test_rect:" << test_rect << "feeback_rect:" << feedback_rect; + + _drawTextAdditionHeight = (feedback_rect.height() - _fontHeight) / 2; + if(_drawTextAdditionHeight < 0) { + _drawTextAdditionHeight = 0; + } + + // update the original content + _drawTextTestFlag = false; + update(); +} + void TerminalDisplay::setVTFont(const QFont& f) { QFont font = f; - // This was originally set for OS X only: + // This was originally set for OS X only: // mac uses floats for font width specification. // this ensures the same handling for all platforms // but then there was revealed that various Linux distros @@ -261,27 +283,22 @@ void TerminalDisplay::setVTFont(const QFont& f) if ( !QFontInfo(font).fixedPitch() ) { - qDebug() << "Using an unsupported variable-width font in the terminal. This may produce display errors."; + qDebug() << "Using a variable-width font in the terminal. This may cause performance degradation and display/alignment errors."; } - //TODO This if has been removed it would be better to understand if this is useful. - //if(font.pixelSize() > 0) { -// if ( metrics.height() < height() && metrics.maxWidth() < width() ) -// { - // hint that text should be drawn without anti-aliasing. - // depending on the user's font configuration, this may not be respected - if (!_antialiasText) - font.setStyleStrategy( QFont::NoAntialias ); - - // experimental optimization. Konsole assumes that the terminal is using a - // mono-spaced font, in which case kerning information should have an effect. - // Disabling kerning saves some computation when rendering text. - font.setKerning(false); + // hint that text should be drawn without anti-aliasing. + // depending on the user's font configuration, this may not be respected + if (!_antialiasText) + font.setStyleStrategy( QFont::NoAntialias ); - m_font = font; - fontChange(font); - emit vtFontChanged(); - //} + // experimental optimization. Konsole assumes that the terminal is using a + // mono-spaced font, in which case kerning information should have an effect. + // Disabling kerning saves some computation when rendering text. + font.setKerning(false); + + m_font = font; + fontChange(font); + emit vtFontChanged(); } void TerminalDisplay::setBoldIntense(bool value) @@ -325,13 +342,14 @@ TerminalDisplay::TerminalDisplay(QQuickItem *parent) ,_terminalSizeHint(false) ,_terminalSizeStartup(true) ,_bidiEnabled(false) +,_mouseMarks(false) ,_actSel(0) ,_wordSelectionMode(false) ,_lineSelectionMode(false) ,_preserveLineBreaks(false) ,_columnSelectionMode(false) -,_scrollbarLocation(NoScrollBar) -,_wordCharacters(":@-./_~") +,_scrollbarLocation(QTermWidget::NoScrollBar) +,_wordCharacters(QLatin1String(":@-./_~")) ,_bellMode(SystemBeepBell) ,_blinking(false) ,_hasBlinker(false) @@ -350,12 +368,18 @@ TerminalDisplay::TerminalDisplay(QQuickItem *parent) ,_colorsInverted(false) ,_blendColor(qRgba(0,0,0,0xff)) ,_filterChain(new TerminalImageFilterChain()) -,_cursorShape(BlockCursor) +,_cursorShape(Emulation::KeyboardCursorShape::BlockCursor) ,mMotionAfterPasting(NoMoveScreenWindow) ,m_font("Monospace", 12) ,m_color_role(QPalette::Background) ,m_full_cursor_height(false) +,_leftBaseMargin(1) +,_topBaseMargin(1) { + // variables for draw text + _drawTextAdditionHeight = 0; + _drawTextTestFlag = false; + // terminal applications are not designed with Right-To-Left in mind, // so the layout is forced to Left-To-Right //setLayoutDirection(Qt::LeftToRight); @@ -363,8 +387,8 @@ TerminalDisplay::TerminalDisplay(QQuickItem *parent) // The offsets are not yet calculated. // Do not calculate these too often to be more smoothly when resizing // konsole in opaque mode. - _topMargin = DEFAULT_TOP_MARGIN; - _leftMargin = DEFAULT_LEFT_MARGIN; + _topMargin = _topBaseMargin; + _leftMargin = _leftBaseMargin; m_palette = qApp->palette(); @@ -372,10 +396,12 @@ TerminalDisplay::TerminalDisplay(QQuickItem *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(); setScroll(0,0); + _scrollBar->setCursor( Qt::ArrowCursor ); - connect(_scrollBar, SIGNAL(valueChanged(int)), this, + connect(_scrollBar, SIGNAL(valueChanged(int)), this, SLOT(scrollBarPositionChanged(int))); // qtermwidget: we have to hide it here due the _scrollbarLocation==NoScrollBar // check in TerminalDisplay::setScrollBarPosition(ScrollBarPosition position) @@ -388,8 +414,9 @@ TerminalDisplay::TerminalDisplay(QQuickItem *parent) connect(_blinkCursorTimer, SIGNAL(timeout()), this, SLOT(blinkCursorEvent())); // KCursor::setAutoHideCursor( this, true ); - + setUsesMouse(true); + setBracketedPasteMode(false); setColorTable(base_color_table); //setMouseTracking(true); @@ -406,10 +433,6 @@ TerminalDisplay::TerminalDisplay(QQuickItem *parent) // always or if we need to make this customizable. setRenderTarget(QQuickPaintedItem::FramebufferObject); - // Enable drag and drop -// setAcceptDrops(true); // attempt -// dragInfo.state = diNone; - // setFocusPolicy( Qt::WheelFocus ); // enable input method support @@ -422,8 +445,6 @@ TerminalDisplay::TerminalDisplay(QQuickItem *parent) // _gridLayout = new QGridLayout(this); // _gridLayout->setContentsMargins(0, 0, 0, 0); -// setLayout( _gridLayout ); - // new AutoScrollHandler(this); } @@ -432,7 +453,7 @@ TerminalDisplay::~TerminalDisplay() disconnect(_blinkTimer); disconnect(_blinkCursorTimer); qApp->removeEventFilter( this ); - + delete[] _image; delete _gridLayout; @@ -496,7 +517,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; @@ -562,33 +583,118 @@ static void drawLineChar(QPainter& paint, int x, int y, int w, int h, uchar code } -void TerminalDisplay::drawLineCharString( QPainter& painter, int x, int y, const QString& str, +static void drawOtherChar(QPainter& paint, int x, int y, int w, int h, uchar code) +{ + //Calculate cell midpoints, end points. + const int cx = x + w / 2; + const int cy = y + h / 2; + const int ex = x + w - 1; + const int ey = y + h - 1; + + // Double dashes + if (0x4C <= code && code <= 0x4F) { + const int xHalfGap = qMax(w / 15, 1); + const int yHalfGap = qMax(h / 15, 1); + switch (code) { + case 0x4D: // BOX DRAWINGS HEAVY DOUBLE DASH HORIZONTAL + paint.drawLine(x, cy - 1, cx - xHalfGap - 1, cy - 1); + paint.drawLine(x, cy + 1, cx - xHalfGap - 1, cy + 1); + paint.drawLine(cx + xHalfGap, cy - 1, ex, cy - 1); + paint.drawLine(cx + xHalfGap, cy + 1, ex, cy + 1); + /* Falls through. */ + case 0x4C: // BOX DRAWINGS LIGHT DOUBLE DASH HORIZONTAL + paint.drawLine(x, cy, cx - xHalfGap - 1, cy); + paint.drawLine(cx + xHalfGap, cy, ex, cy); + break; + case 0x4F: // BOX DRAWINGS HEAVY DOUBLE DASH VERTICAL + paint.drawLine(cx - 1, y, cx - 1, cy - yHalfGap - 1); + paint.drawLine(cx + 1, y, cx + 1, cy - yHalfGap - 1); + paint.drawLine(cx - 1, cy + yHalfGap, cx - 1, ey); + paint.drawLine(cx + 1, cy + yHalfGap, cx + 1, ey); + /* Falls through. */ + case 0x4E: // BOX DRAWINGS LIGHT DOUBLE DASH VERTICAL + paint.drawLine(cx, y, cx, cy - yHalfGap - 1); + paint.drawLine(cx, cy + yHalfGap, cx, ey); + break; + } + } + + // Rounded corner characters + else if (0x6D <= code && code <= 0x70) { + const int r = w * 3 / 8; + const int d = 2 * r; + switch (code) { + case 0x6D: // BOX DRAWINGS LIGHT ARC DOWN AND RIGHT + paint.drawLine(cx, cy + r, cx, ey); + paint.drawLine(cx + r, cy, ex, cy); + paint.drawArc(cx, cy, d, d, 90 * 16, 90 * 16); + break; + case 0x6E: // BOX DRAWINGS LIGHT ARC DOWN AND LEFT + paint.drawLine(cx, cy + r, cx, ey); + paint.drawLine(x, cy, cx - r, cy); + paint.drawArc(cx - d, cy, d, d, 0 * 16, 90 * 16); + break; + case 0x6F: // BOX DRAWINGS LIGHT ARC UP AND LEFT + paint.drawLine(cx, y, cx, cy - r); + paint.drawLine(x, cy, cx - r, cy); + paint.drawArc(cx - d, cy - d, d, d, 270 * 16, 90 * 16); + break; + case 0x70: // BOX DRAWINGS LIGHT ARC UP AND RIGHT + paint.drawLine(cx, y, cx, cy - r); + paint.drawLine(cx + r, cy, ex, cy); + paint.drawArc(cx, cy - d, d, d, 180 * 16, 90 * 16); + break; + } + } + + // Diagonals + else if (0x71 <= code && code <= 0x73) { + switch (code) { + case 0x71: // BOX DRAWINGS LIGHT DIAGONAL UPPER RIGHT TO LOWER LEFT + paint.drawLine(ex, y, x, ey); + break; + case 0x72: // BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO LOWER RIGHT + paint.drawLine(x, y, ex, ey); + break; + case 0x73: // BOX DRAWINGS LIGHT DIAGONAL CROSS + paint.drawLine(ex, y, x, ey); + paint.drawLine(x, y, ex, ey); + break; + } + } +} + +void TerminalDisplay::drawLineCharString( QPainter& painter, int x, int y, const std::wstring& str, const Character* attributes) { const QPen& currentPen = painter.pen(); - + if ( (attributes->rendition & RE_BOLD) && _boldIntense ) { QPen boldPen(currentPen); boldPen.setWidth(3); 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 + drawOtherChar(painter, x + (_fontWidth * i), y, _fontWidth, _fontHeight, code); } painter.setPen( currentPen ); } -void TerminalDisplay::setKeyboardCursorShape(KeyboardCursorShape shape) +void TerminalDisplay::setKeyboardCursorShape(QTermWidget::KeyboardCursorShape shape) { _cursorShape = shape; + + updateCursor(); } -TerminalDisplay::KeyboardCursorShape TerminalDisplay::keyboardCursorShape() const +QTermWidget::KeyboardCursorShape TerminalDisplay::keyboardCursorShape() const { return _cursorShape; } @@ -615,7 +721,7 @@ void TerminalDisplay::setOpacity(qreal opacity) // enable automatic background filling to prevent the display // flickering if there is no transparency - /*if ( color.alpha() == 255 ) + /*if ( color.alpha() == 255 ) { setAutoFillBackground(true); } @@ -627,47 +733,51 @@ void TerminalDisplay::setOpacity(qreal opacity) _blendColor = color.rgba(); } -void TerminalDisplay::drawBackground(QPainter& painter, const QRect& rect, const QColor& backgroundColor, bool useOpacitySetting ) +void TerminalDisplay::setBackgroundImage(QString backgroundImage) { - // 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(); - - if ( HAVE_TRANSPARENCY && qAlpha(_blendColor) < 0xff && useOpacitySetting ) - { - QColor color(backgroundColor); - color.setAlpha(qAlpha(_blendColor)); - - painter.save(); - painter.setCompositionMode(QPainter::CompositionMode_Source); - painter.fillRect(contentsRect, color); - painter.restore(); - } - else - painter.fillRect(contentsRect, backgroundColor); - - painter.fillRect(scrollBarArea,_scrollBar->palette().background()); + if (!backgroundImage.isEmpty()) + { + _backgroundImage.load(backgroundImage); + //setAttribute(Qt::WA_OpaquePaintEvent, false); + } + else + { + _backgroundImage = QPixmap(); + //setAttribute(Qt::WA_OpaquePaintEvent, true); + } } -void TerminalDisplay::drawCursor(QPainter& painter, +void TerminalDisplay::drawBackground(QPainter& painter, const QRect& rect, const QColor& backgroundColor, bool useOpacitySetting ) +{ + // 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()) { + QColor color(backgroundColor); + color.setAlpha(qAlpha(_blendColor)); + + painter.save(); + painter.setCompositionMode(QPainter::CompositionMode_Source); + painter.fillRect(rect, color); + painter.restore(); + } + } + else + painter.fillRect(rect, backgroundColor); +} + +void TerminalDisplay::drawCursor(QPainter& painter, const QRect& rect, const QColor& foregroundColor, const QColor& /*backgroundColor*/, bool& invertCharacterColor) { QRect cursorRect = rect; + cursorRect.setHeight(_fontHeight - ((m_full_cursor_height) ? 0 : _lineSpacing) - 1); - + if (!_cursorBlinking) { if ( _cursorColor.isValid() ) @@ -675,7 +785,7 @@ void TerminalDisplay::drawCursor(QPainter& painter, else painter.setPen(foregroundColor); - if ( _cursorShape == BlockCursor ) + if ( _cursorShape == Emulation::KeyboardCursorShape::BlockCursor ) { // draw the cursor outline, adjusting the area so that // it is draw entirely inside 'rect' @@ -693,7 +803,7 @@ void TerminalDisplay::drawCursor(QPainter& painter, if ( true ) //QMLTermWidget: Always fill the cursor. Even when not in focus. { painter.fillRect(cursorRect, _cursorColor.isValid() ? _cursorColor : foregroundColor); - + if ( !_cursorColor.isValid() ) { // invert the colour used to draw the text to ensure that the character at @@ -702,47 +812,54 @@ void TerminalDisplay::drawCursor(QPainter& painter, } } } - else if ( _cursorShape == UnderlineCursor ) + else if ( _cursorShape == Emulation::KeyboardCursorShape::UnderlineCursor ) painter.drawLine(cursorRect.left(), cursorRect.bottom(), cursorRect.right(), cursorRect.bottom()); - else if ( _cursorShape == IBeamCursor ) + else if ( _cursorShape == Emulation::KeyboardCursorShape::IBeamCursor ) painter.drawLine(cursorRect.left(), cursorRect.top(), cursorRect.left(), cursorRect.bottom()); - + } } void TerminalDisplay::drawCharacters(QPainter& painter, const QRect& rect, - const QString& text, + const std::wstring& text, const Character* style, bool invertCharacterColor) { // don't draw text which is currently blinking if ( _blinking && (style->rendition & RE_BLINK) ) + return; + + // don't draw concealed characters + if (style->rendition & RE_CONCEAL) return; // setup bold and underline - bool useBold; - ColorEntry::FontWeight weight = style->fontWeight(_colorTable); - if (weight == ColorEntry::UseCurrentFormat) - useBold = ((style->rendition & RE_BOLD) && _boldIntense) || font().bold(); - else - useBold = (weight == ColorEntry::Bold) ? true : false; - bool useUnderline = style->rendition & RE_UNDERLINE || font().underline(); + bool useBold = ((style->rendition & RE_BOLD) && _boldIntense) || font().bold(); + const bool useUnderline = style->rendition & RE_UNDERLINE || font().underline(); + const bool useItalic = style->rendition & RE_ITALIC || font().italic(); + const bool useStrikeOut = style->rendition & RE_STRIKEOUT || font().strikeOut(); + const bool useOverline = style->rendition & RE_OVERLINE || font().overline(); painter.setFont(font()); QFont font = painter.font(); - if ( font.bold() != useBold - || font.underline() != useUnderline ) - { + if ( font.bold() != useBold + || font.underline() != useUnderline + || font.italic() != useItalic + || font.strikeOut() != useStrikeOut + || font.overline() != useOverline) { font.setBold(useBold); font.setUnderline(useUnderline); + font.setItalic(useItalic); + font.setStrikeOut(useStrikeOut); + font.setOverline(useOverline); painter.setFont(font); } @@ -761,34 +878,35 @@ void TerminalDisplay::drawCharacters(QPainter& painter, drawLineCharString(painter,rect.x(),rect.y(),text,style); else { - // the drawText(rect,flags,string) overload is used here with null flags - // instead of drawText(rect,string) because the (rect,string) overload causes - // the application's default layout direction to be used instead of - // the widget-specific layout direction, which should always be - // Qt::LeftToRight for this widget - // This was discussed in: http://lists.kde.org/?t=120552223600002&r=1&w=2 - if (_bidiEnabled) - painter.drawText(rect,0,text); - else -#if QT_VERSION >= 0x040800 - painter.drawText(rect, Qt::AlignBottom, LTR_OVERRIDE_CHAR + text); -#else - painter.drawText(rect, 0, LTR_OVERRIDE_CHAR + text); -#endif + // Force using LTR as the document layout for the terminal area, because + // there is no use cases for RTL emulator and RTL terminal application. + // + // This still allows RTL characters to be rendered in the RTL way. + painter.setLayoutDirection(Qt::LeftToRight); + + if (_bidiEnabled) { + 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 + QString::fromStdWString(text)); + } + } } } -void TerminalDisplay::drawTextFragment(QPainter& painter , +void TerminalDisplay::drawTextFragment(QPainter& painter , const QRect& rect, - const QString& text, + const std::wstring& text, const Character* style) { painter.save(); - // setup painter + // setup painter const QColor foregroundColor = style->foregroundColor.color(_colorTable); const QColor backgroundColor = style->backgroundColor.color(_colorTable); - + // draw background if different from the display's background color if ( backgroundColor != palette().background().color() ) drawBackground(painter,rect,backgroundColor, @@ -831,15 +949,15 @@ void TerminalDisplay::setCursorPos(const int curx, const int cury) // scrolls the image by 'lines', down if lines > 0 or up otherwise. // -// the terminal emulation keeps track of the scrolling of the character -// image as it receives input, and when the view is updated, it calls scrollImage() -// with the final scroll amount. this improves performance because scrolling the -// display is much cheaper than re-rendering all the text for the -// part of the image which has moved up or down. +// the terminal emulation keeps track of the scrolling of the character +// image as it receives input, and when the view is updated, it calls scrollImage() +// with the final scroll amount. this improves performance because scrolling the +// display is much cheaper than re-rendering all the text for the +// part of the image which has moved up or down. // Instead only new lines have to be drawn void TerminalDisplay::scrollImage(int lines , const QRect& screenWindowRegion) { - // if the flow control warning is enabled this will interfere with the + // if the flow control warning is enabled this will interfere with the // scrolling optimizations and cause artifacts. the simple solution here // is to just disable the optimization whilst it is visible if ( _outputSuspendedLabel && _outputSuspendedLabel->isVisible() ) @@ -850,13 +968,13 @@ void TerminalDisplay::scrollImage(int lines , const QRect& screenWindowRegion) // internal image - 2, so that the height of 'region' is strictly less // than the height of the internal image. QRect region = screenWindowRegion; - region.setBottom( qMin(region.bottom(),this->_lines-2) ); + region.setBottom( qMin(region.bottom(),this->_lines-2) ); // return if there is nothing to do - if ( lines == 0 + if ( lines == 0 || _image == 0 - || !region.isValid() - || (region.top() + abs(lines)) >= region.bottom() + || !region.isValid() + || (region.top() + abs(lines)) >= region.bottom() || this->_lines <= region.height() ) return; // hide terminal size label to prevent it being scrolled @@ -866,8 +984,8 @@ void TerminalDisplay::scrollImage(int lines , const QRect& screenWindowRegion) // Note: With Qt 4.4 the left edge of the scrolled area must be at 0 // to get the correct (newly exposed) part of the widget repainted. // - // The right edge must be before the left edge of the scroll bar to - // avoid triggering a repaint of the entire widget, the distance is + // The right edge must be before the left edge of the scroll bar to + // avoid triggering a repaint of the entire widget, the distance is // given by SCROLLBAR_CONTENT_GAP // // Set the QT_FLUSH_PAINT environment variable to '1' before starting the @@ -876,7 +994,7 @@ void TerminalDisplay::scrollImage(int lines , const QRect& screenWindowRegion) int scrollBarWidth = _scrollBar->isHidden() ? 0 : _scrollBar->width(); const int SCROLLBAR_CONTENT_GAP = 1; QRect scrollRect; - if ( _scrollbarLocation == ScrollBarLeft ) + if ( _scrollbarLocation == QTermWidget::ScrollBarLeft ) { scrollRect.setLeft(scrollBarWidth+SCROLLBAR_CONTENT_GAP); scrollRect.setRight(width()); @@ -891,7 +1009,7 @@ void TerminalDisplay::scrollImage(int lines , const QRect& screenWindowRegion) int top = _topMargin + (region.top() * _fontHeight); int linesToMove = region.height() - abs(lines); - int bytesToMove = linesToMove * + int bytesToMove = linesToMove * this->_columns * sizeof(Character); @@ -902,28 +1020,28 @@ void TerminalDisplay::scrollImage(int lines , const QRect& screenWindowRegion) if ( lines > 0 ) { // check that the memory areas that we are going to move are valid - Q_ASSERT( (char*)lastCharPos + bytesToMove < + Q_ASSERT( (char*)lastCharPos + bytesToMove < (char*)(_image + (this->_lines * this->_columns)) ); - - Q_ASSERT( (lines*this->_columns) < _imageSize ); + + Q_ASSERT( (lines*this->_columns) < _imageSize ); //scroll internal image down - memmove( firstCharPos , lastCharPos , bytesToMove ); - + memmove( firstCharPos , lastCharPos , bytesToMove ); + //set region of display to scroll scrollRect.setTop(top); } else { // check that the memory areas that we are going to move are valid - Q_ASSERT( (char*)firstCharPos + bytesToMove < + Q_ASSERT( (char*)firstCharPos + bytesToMove < (char*)(_image + (this->_lines * this->_columns)) ); //scroll internal image up - memmove( lastCharPos , firstCharPos , bytesToMove ); - + memmove( lastCharPos , firstCharPos , bytesToMove ); + //set region of the display to scroll - scrollRect.setTop(top + abs(lines) * _fontHeight); + scrollRect.setTop(top + abs(lines) * _fontHeight); } scrollRect.setHeight(linesToMove * _fontHeight ); @@ -933,10 +1051,11 @@ void TerminalDisplay::scrollImage(int lines , const QRect& screenWindowRegion) //scroll( 0 , _fontHeight * (-lines) , scrollRect ); } -QRegion TerminalDisplay::hotSpotRegion() const +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()) { @@ -968,7 +1087,7 @@ QRegion TerminalDisplay::hotSpotRegion() const return region; } -void TerminalDisplay::processFilters() +void TerminalDisplay::processFilters() { if (!_screenWindow) return; @@ -978,7 +1097,7 @@ void TerminalDisplay::processFilters() // use _screenWindow->getImage() here rather than _image because // other classes may call processFilters() when this display's // ScreenWindow emits a scrolled() signal - which will happen before - // updateImage() is called on the display and therefore _image is + // updateImage() is called on the display and therefore _image is // out of date at this point _filterChain->setImage( _screenWindow->getImage(), _screenWindow->windowLines(), @@ -1036,8 +1155,8 @@ 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]; - char *dirtyMask = new char[columnsToUpdate+2]; + wchar_t *disstrU = new wchar_t[columnsToUpdate]; + char *dirtyMask = new char[columnsToUpdate+2]; QRegion dirtyRegion; // debugging variable, this records the number of lines that are found to @@ -1051,12 +1170,12 @@ void TerminalDisplay::updateImage() const Character* const newLine = &newimg[y*columns]; bool updateLine = false; - + // The dirty mask indicates which characters need repainting. We also // mark surrounding neighbours dirty, in case the character exceeds // its cell boundaries memset(dirtyMask, 0, columnsToUpdate+2); - + for( x = 0 ; x < columnsToUpdate ; ++x) { if ( newLine[x] != currentLine[x] ) @@ -1069,13 +1188,13 @@ void TerminalDisplay::updateImage() for (x = 0; x < columnsToUpdate; ++x) { _hasBlinker |= (newLine[x].rendition & RE_BLINK); - + // Start drawing if this character or the next one differs. // We also take the next one into account to handle the situation // 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; @@ -1095,18 +1214,18 @@ void TerminalDisplay::updateImage() bool nextIsDoubleWidth = (x+len+1 == columnsToUpdate) ? false : (newLine[x+len+1].character == 0); - if ( ch.foregroundColor != cf || - ch.backgroundColor != _clipboard || + if ( ch.foregroundColor != cf || + ch.backgroundColor != _clipboard || ch.rendition != cr || - !dirtyMask[x+len] || - isLineChar(c) != lineDraw || + !dirtyMask[x+len] || + isLineChar(c) != lineDraw || nextIsDoubleWidth != doubleWidth ) break; disstrU[p++] = c; //fontMap(c); } - QString unistr(disstrU, p); + std::wstring unistr(disstrU, p); bool saveFixedFont = _fixedFont; if (lineDraw) @@ -1119,53 +1238,53 @@ void TerminalDisplay::updateImage() _fixedFont = saveFixedFont; x += len - 1; } - + } //both the top and bottom halves of double height _lines must always be redrawn - //although both top and bottom halves contain the same characters, only - //the top one is actually + //although both top and bottom halves contain the same characters, only + //the top one is actually //drawn. if (_lineProperties.count() > y) updateLine |= (_lineProperties[y] & LINE_DOUBLEHEIGHT); // if the characters on the line are different in the old and the new _image - // then this line must be repainted. + // then this line must be repainted. if (updateLine) { dirtyLineCount++; // add the area occupied by this line to the region which needs to be // repainted - QRect dirtyRect = QRect( _leftMargin+tLx , - _topMargin+tLy+_fontHeight*y , - _fontWidth * columnsToUpdate , - _fontHeight ); + QRect dirtyRect = QRect( _leftMargin+tLx , + _topMargin+tLy+_fontHeight*y , + _fontWidth * columnsToUpdate , + _fontHeight ); dirtyRegion |= dirtyRect; } - // replace the line of characters in the old _image with the - // current line of the new _image + // replace the line of characters in the old _image with the + // current line of the new _image memcpy((void*)currentLine,(const void*)newLine,columnsToUpdate*sizeof(Character)); } // if the new _image is smaller than the previous _image, then ensure that the area - // outside the new _image is cleared + // outside the new _image is cleared if ( linesToUpdate < _usedLines ) { - dirtyRegion |= QRect( _leftMargin+tLx , - _topMargin+tLy+_fontHeight*linesToUpdate , - _fontWidth * this->_columns , + dirtyRegion |= QRect( _leftMargin+tLx , + _topMargin+tLy+_fontHeight*linesToUpdate , + _fontWidth * this->_columns , _fontHeight * (_usedLines-linesToUpdate) ); } _usedLines = linesToUpdate; - + if ( columnsToUpdate < _usedColumns ) { - dirtyRegion |= QRect( _leftMargin+tLx+columnsToUpdate*_fontWidth , - _topMargin+tLy , - _fontWidth * (_usedColumns-columnsToUpdate) , + dirtyRegion |= QRect( _leftMargin+tLx+columnsToUpdate*_fontWidth , + _topMargin+tLy , + _fontWidth * (_usedColumns-columnsToUpdate) , _fontHeight * this->_lines ); } _usedColumns = columnsToUpdate; @@ -1175,7 +1294,7 @@ void TerminalDisplay::updateImage() // update the parts of the display which have changed update(dirtyRegion); - if ( _hasBlinker && !_blinkTimer->isActive()) _blinkTimer->start( TEXT_BLINK_DELAY ); + if ( _hasBlinker && !_blinkTimer->isActive()) _blinkTimer->start( TEXT_BLINK_DELAY ); if (!_hasBlinker && _blinkTimer->isActive()) { _blinkTimer->stop(); _blinking = false; } delete[] dirtyMask; delete[] disstrU; @@ -1215,11 +1334,11 @@ void TerminalDisplay::showResizeNotification() void TerminalDisplay::setBlinkingCursor(bool blink) { _hasBlinkingCursor=blink; - - if (blink && !_blinkCursorTimer->isActive()) + + if (blink && !_blinkCursorTimer->isActive()) _blinkCursorTimer->start(QApplication::cursorFlashTime() / 2); - - if (!blink && _blinkCursorTimer->isActive()) + + if (!blink && _blinkCursorTimer->isActive()) { _blinkCursorTimer->stop(); if (_cursorBlinking) @@ -1233,10 +1352,10 @@ void TerminalDisplay::setBlinkingTextEnabled(bool blink) { _allowBlinkingText = blink; - if (blink && !_blinkTimer->isActive()) + if (blink && !_blinkTimer->isActive()) _blinkTimer->start(TEXT_BLINK_DELAY); - - if (!blink && _blinkTimer->isActive()) + + if (!blink && _blinkTimer->isActive()) { _blinkTimer->stop(); _blinking = false; @@ -1271,19 +1390,60 @@ void TerminalDisplay::focusInEvent(QFocusEvent*) _blinkTimer->start(); } +// TODO QMLTERMWIDGET We should double check if we need this to fix the vertical truncation issue. + void TerminalDisplay::paint(QPainter *painter) { - //contentsBoundingRect() - // TODO This function might be optimized. - QRect clipRect = painter->clipBoundingRect().toAlignedRect(); - QRect dirtyRect = clipRect.isValid() ? clipRect : contentsRect(); - //drawBackground(*painter, rect, m_palette.background().color(), false /* use opacity setting */); - drawContents(*painter, dirtyRect); - - //drawInputMethodPreeditString(*painter, preeditRect()); - //paintFilters(painter); + if (_drawTextTestFlag) { + calDrawTextAdditionHeight(*painter); + } else { + QRect clipRect = painter->clipBoundingRect().toAlignedRect(); + QRect dirtyRect = clipRect.isValid() ? clipRect : contentsRect(); + drawContents(*painter, dirtyRect); + } } +//void TerminalDisplay::paint(QPainter *painter) +//{ +// //contentsBoundingRect() +// // TODO This function might be optimized. + +// QRect clipRect = painter->clipBoundingRect().toAlignedRect(); +// QRect dirtyRect = clipRect.isValid() ? clipRect : contentsRect(); +// //drawBackground(*painter, rect, m_palette.background().color(), false /* use opacity setting */); +// drawContents(*painter, dirtyRect); + +////<<<<<<< HEAD +//// //drawInputMethodPreeditString(*painter, preeditRect()); +//// //paintFilters(painter); +////======= +//// if ( !_backgroundImage.isNull() && qAlpha(_blendColor) < 0xff ) +//// { +//// paint.drawPixmap(0, 0, _backgroundImage); +//// QColor background = _colorTable[DEFAULT_BACK_COLOR].color; +//// background.setAlpha(qAlpha(_blendColor)); +//// paint.fillRect(contentsRect(), background); +//// } + +//// if(_drawTextTestFlag) +//// { +//// calDrawTextAdditionHeight(paint); +//// } +//// else +//// { +//// const auto rects = (pe->region() & contentsRect()).rects(); +//// for (const QRect &rect : rects) +//// { +//// drawBackground(paint,rect,palette().background().color(), +//// true /* use opacity setting */); +//// drawContents(paint, rect); +//// } +//// drawInputMethodPreeditString(paint,preeditRect()); +//// paintFilters(paint); +//// } +////>>>>>>> upstream/master +//} + //void TerminalDisplay::paintEvent( QPaintEvent* pe ) //{ // QPainter paint(this); @@ -1317,14 +1477,14 @@ QRect TerminalDisplay::preeditRect() const _topMargin + _fontHeight*cursorPosition().y(), _fontWidth*preeditLength, _fontHeight); -} +} void TerminalDisplay::drawInputMethodPreeditString(QPainter& painter , const QRect& rect) { - if ( _inputMethodData.preeditString.isEmpty() ) + if ( _inputMethodData.preeditString.empty() ) return; - const QPoint cursorPos = cursorPosition(); + const QPoint cursorPos = cursorPosition(); bool invertColors = false; const QColor background = _colorTable[DEFAULT_BACK_COLOR].color; @@ -1335,7 +1495,7 @@ void TerminalDisplay::drawInputMethodPreeditString(QPainter& painter , const QRe drawCursor(painter,rect,foreground,background,invertColors); drawCharacters(painter,rect,_inputMethodData.preeditString,style,invertColors); - _inputMethodData.previousPreeditRect = rect; + _inputMethodData.previousPreeditRect = rect; } FilterChain* TerminalDisplay::filterChain() const @@ -1350,14 +1510,17 @@ void TerminalDisplay::paintFilters(QPainter& painter) QPoint cursorPos = mapFromScene(QCursor::pos()).toPoint(); int cursorLine; int cursorColumn; - int scrollBarWidth = (_scrollbarLocation == ScrollBarLeft) ? _scrollBar->width() : 0; + int leftMargin = _leftBaseMargin + + ((_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)]; painter.setPen( QPen(cursorCharacter.foregroundColor.color(colorTable())) ); - // iterate over hotspots identified by the display's currently active filters + // iterate over hotspots identified by the display's currently active filters // and draw appropriate visuals to indicate the presence of the hotspot QList spots = _filterChain->hotSpots(); @@ -1370,28 +1533,28 @@ void TerminalDisplay::paintFilters(QPainter& painter) if ( spot->type() == Filter::HotSpot::Link ) { QRect r; if (spot->startLine()==spot->endLine()) { - r.setCoords( spot->startColumn()*_fontWidth + 1 + scrollBarWidth, - spot->startLine()*_fontHeight + 1, - (spot->endColumn()-1)*_fontWidth - 1 + scrollBarWidth, - (spot->endLine()+1)*_fontHeight - 1 ); + r.setCoords( spot->startColumn()*_fontWidth + 1 + leftMargin, + spot->startLine()*_fontHeight + 1 + _topBaseMargin, + spot->endColumn()*_fontWidth - 1 + leftMargin, + (spot->endLine()+1)*_fontHeight - 1 + _topBaseMargin ); region |= r; } else { - r.setCoords( spot->startColumn()*_fontWidth + 1 + scrollBarWidth, - spot->startLine()*_fontHeight + 1, - (_columns-1)*_fontWidth - 1 + scrollBarWidth, - (spot->startLine()+1)*_fontHeight - 1 ); + r.setCoords( spot->startColumn()*_fontWidth + 1 + leftMargin, + spot->startLine()*_fontHeight + 1 + _topBaseMargin, + _columns*_fontWidth - 1 + leftMargin, + (spot->startLine()+1)*_fontHeight - 1 + _topBaseMargin ); region |= r; for ( int line = spot->startLine()+1 ; line < spot->endLine() ; line++ ) { - r.setCoords( 0*_fontWidth + 1 + scrollBarWidth, - line*_fontHeight + 1, - (_columns-1)*_fontWidth - 1 + scrollBarWidth, - (line+1)*_fontHeight - 1 ); + r.setCoords( 0*_fontWidth + 1 + leftMargin, + line*_fontHeight + 1 + _topBaseMargin, + _columns*_fontWidth - 1 + leftMargin, + (line+1)*_fontHeight - 1 + _topBaseMargin ); region |= r; } - r.setCoords( 0*_fontWidth + 1 + scrollBarWidth, - spot->endLine()*_fontHeight + 1, - (spot->endColumn()-1)*_fontWidth - 1 + scrollBarWidth, - (spot->endLine()+1)*_fontHeight - 1 ); + r.setCoords( 0*_fontWidth + 1 + leftMargin, + spot->endLine()*_fontHeight + 1 + _topBaseMargin, + spot->endColumn()*_fontWidth - 1 + leftMargin, + (spot->endLine()+1)*_fontHeight - 1 + _topBaseMargin ); region |= r; } } @@ -1399,14 +1562,14 @@ void TerminalDisplay::paintFilters(QPainter& painter) for ( int line = spot->startLine() ; line <= spot->endLine() ; line++ ) { int startColumn = 0; - int endColumn = _columns-1; // TODO use number of _columns which are actually - // occupied on this line rather than the width of the + int endColumn = _columns-1; // TODO use number of _columns which are actually + // occupied on this line rather than the width of the // display in _columns // ignore whitespace at the end of the lines while ( QChar(_image[loc(endColumn,line)].character).isSpace() && endColumn > 0 ) endColumn--; - + // increment here because the column which we want to set 'endColumn' to // is the first whitespace character at the end of the line endColumn++; @@ -1422,27 +1585,27 @@ void TerminalDisplay::paintFilters(QPainter& painter) // hotspots // // subtracting one pixel from all sides also prevents an edge case where - // moving the mouse outside a link could still leave it underlined + // moving the mouse outside a link could still leave it underlined // because the check below for the position of the cursor // finds it on the border of the target area QRect r; - r.setCoords( startColumn*_fontWidth + 1 + scrollBarWidth, - line*_fontHeight + 1, - endColumn*_fontWidth - 1 + scrollBarWidth, - (line+1)*_fontHeight - 1 ); - // Underline link hotspots + r.setCoords( startColumn*_fontWidth + 1 + leftMargin, + line*_fontHeight + 1 + _topBaseMargin, + endColumn*_fontWidth - 1 + leftMargin, + (line+1)*_fontHeight - 1 + _topBaseMargin ); + // Underline link hotspots if ( spot->type() == Filter::HotSpot::Link ) { QFontMetrics metrics(font()); - + // find the baseline (which is the invisible line that the characters in the font sit on, // with some having tails dangling below) int baseline = r.bottom() - metrics.descent(); // find the position of the underline below that int underlinePos = baseline + metrics.underlinePos(); + if ( region.contains( mapFromScene(QCursor::pos()).toPoint() ) ){ - painter.drawLine( r.left() , underlinePos , - r.right() , underlinePos ); + painter.drawLine( r.left() , underlinePos , r.right() , underlinePos ); } } // Marker hotspots simply have a transparent rectanglular shape @@ -1455,6 +1618,27 @@ void TerminalDisplay::paintFilters(QPainter& painter) } } } + +int TerminalDisplay::textWidth(const int startColumn, const int length, const int line) const +{ + QFontMetrics fm(font()); + int result = 0; + for (int column = 0; column < length; column++) { + result += fm.width(_image[loc(startColumn + column, line)].character); + } + return result; +} + +QRect TerminalDisplay::calculateTextArea(int topLeftX, int topLeftY, int startColumn, int line, int length) { + int left = _fixedFont ? _fontWidth * startColumn : textWidth(0, startColumn, line); + int top = _fontHeight * line; + int width = _fixedFont ? _fontWidth * length : textWidth(startColumn, length, line); + return QRect(_leftMargin + topLeftX + left, + _topMargin + topLeftY + top, + width, + _fontHeight); +} + void TerminalDisplay::drawContents(QPainter &paint, const QRect &rect) { QPoint tL = contentsRect().topLeft(); @@ -1462,19 +1646,19 @@ void TerminalDisplay::drawContents(QPainter &paint, const QRect &rect) int tLy = tL.y(); int lux = qMin(_usedColumns-1, qMax(0,(rect.left() - tLx - _leftMargin ) / _fontWidth)); - int luy = qMin(_usedLines-1, qMax(0,(rect.top() - tLy - _topMargin ) / _fontHeight)); + int luy = qMin(_usedLines-1, qMax(0,(rect.top() - tLy - _topMargin ) / _fontHeight)); int rlx = qMin(_usedColumns-1, qMax(0,(rect.right() - tLx - _leftMargin ) / _fontWidth)); - int rly = qMin(_usedLines-1, qMax(0,(rect.bottom() - tLy - _topMargin ) / _fontHeight)); + int rly = qMin(_usedLines-1, qMax(0,(rect.bottom() - tLy - _topMargin ) / _fontHeight)); if(!_image) return; 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 @@ -1485,7 +1669,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 ) @@ -1494,10 +1677,10 @@ void TerminalDisplay::drawContents(QPainter &paint, const QRect &rect) ushort extendedCharLength = 0; ushort* chars = ExtendedCharTable::instance .lookupExtendedChar(_image[loc(x,y)].charSequence,extendedCharLength); - for ( int index = 0 ; index < extendedCharLength ; index++ ) + for ( int index = 0 ; index < extendedCharLength ; index++ ) { Q_ASSERT( p < bufferSize ); - disstrU[p++] = chars[index]; + unistr[p++] = chars[index]; } } else @@ -1507,7 +1690,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); } } @@ -1516,7 +1699,7 @@ void TerminalDisplay::drawContents(QPainter &paint, const QRect &rect) CharacterColor currentForeground = _image[loc(x,y)].foregroundColor; CharacterColor currentBackground = _image[loc(x,y)].backgroundColor; quint8 currentRendition = _image[loc(x,y)].rendition; - + while (x+len <= rlx && _image[loc(x+len,y)].foregroundColor == currentForeground && _image[loc(x+len,y)].backgroundColor == currentBackground && @@ -1525,7 +1708,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++; @@ -1536,12 +1719,10 @@ void TerminalDisplay::drawContents(QPainter &paint, const QRect &rect) bool save__fixedFont = _fixedFont; if (lineDraw) _fixedFont = false; - if (doubleWidth) - _fixedFont = false; unistr.resize(p); // Create a text scaling matrix for double width and double height lines. - QMatrix textScale; + QTransform textScale; if (y < _lineProperties.size()) { @@ -1553,43 +1734,43 @@ void TerminalDisplay::drawContents(QPainter &paint, const QRect &rect) } //Apply text scaling matrix. - paint.setWorldMatrix(textScale, true); + paint.setWorldTransform(textScale, true); //calculate the area in which the text will be drawn - QRect textArea = QRect( _leftMargin+tLx+_fontWidth*x , _topMargin+tLy+_fontHeight*y , _fontWidth*len , _fontHeight); - + QRect textArea = calculateTextArea(tLx, tLy, x, y, len); + //move the calculated area to take account of scaling applied to the painter. - //the position of the area from the origin (0,0) is scaled + //the position of the area from the origin (0,0) is scaled //by the opposite of whatever - //transformation has been applied to the painter. this ensures that - //painting does actually start from textArea.topLeft() - //(instead of textArea.topLeft() * painter-scale) + //transformation has been applied to the painter. this ensures that + //painting does actually start from textArea.topLeft() + //(instead of textArea.topLeft() * painter-scale) textArea.moveTopLeft( textScale.inverted().map(textArea.topLeft()) ); - + //paint text fragment drawTextFragment( paint, textArea, - unistr, - &_image[loc(x,y)] ); //, - //0, + unistr, + &_image[loc(x,y)] ); //, + //0, //!_isPrinting ); - + _fixedFont = save__fixedFont; - - //reset back to single-width, single-height _lines - paint.setWorldMatrix(textScale.inverted(), true); + + //reset back to single-width, single-height _lines + paint.setWorldTransform(textScale.inverted(), true); if (y < _lineProperties.size()-1) { - //double-height _lines are represented by two adjacent _lines + //double-height _lines are represented by two adjacent _lines //containing the same characters - //both _lines will have the LINE_DOUBLEHEIGHT attribute. - //If the current line has the LINE_DOUBLEHEIGHT attribute, + //both _lines will have the LINE_DOUBLEHEIGHT attribute. + //If the current line has the LINE_DOUBLEHEIGHT attribute, //we can therefore skip the next line if (_lineProperties[y] & LINE_DOUBLEHEIGHT) y++; } - + x += len - 1; } } @@ -1601,7 +1782,7 @@ void TerminalDisplay::blinkEvent() _blinking = !_blinking; - //TODO: Optimize to only repaint the areas of the widget + //TODO: Optimize to only repaint the areas of the widget // where there is blinking text // rather than repainting the whole widget. update(); @@ -1620,7 +1801,7 @@ QRect TerminalDisplay::imageToWidget(const QRect& imageArea) const void TerminalDisplay::updateCursor() { - QRect cursorRect = imageToWidget( QRect(cursorPosition(),QSize(1,1)) ); + QRect cursorRect = imageToWidget( QRect(cursorPosition(),QSize(1,1)) ); update(cursorRect); } @@ -1663,7 +1844,7 @@ void TerminalDisplay::updateImageSize() int oldcol = _columns; makeImage(); - + // copy the old image to reduce flicker int lines = qMin(oldlin,_lines); int columns = qMin(oldcol,_columns); @@ -1688,15 +1869,15 @@ void TerminalDisplay::updateImageSize() showResizeNotification(); emit changedContentSizeSignal(_contentHeight, _contentWidth); // expose resizeEvent } - + _resizing = false; } -//showEvent and hideEvent are reimplemented here so that it appears to other classes that the +//showEvent and hideEvent are reimplemented here so that it appears to other classes that the //display has been resized when the display is hidden or shown. // //TODO: Perhaps it would be better to have separate signals for show and hide instead of using -//the same signal as the one for a content size change +//the same signal as the one for a content size change void TerminalDisplay::showEvent(QShowEvent*) { emit changedContentSizeSignal(_contentHeight,_contentWidth); @@ -1714,13 +1895,13 @@ void TerminalDisplay::hideEvent(QHideEvent*) void TerminalDisplay::scrollBarPositionChanged(int) { - if ( !_screenWindow ) + if ( !_screenWindow ) return; _screenWindow->scrollTo( _scrollBar->value() ); // if the thumb has been moved to the bottom of the _scrollBar then set - // the display to automatically track new output, + // the display to automatically track new output, // that is, scroll down automatically // to how new _lines as they are added const bool atEndOfOutput = (_scrollBar->value() == _scrollBar->maximum()); @@ -1764,19 +1945,19 @@ void TerminalDisplay::scrollToEnd() _screenWindow->setTrackOutput( _screenWindow->atEndOfOutput() ); } -void TerminalDisplay::setScrollBarPosition(ScrollBarPosition position) +void TerminalDisplay::setScrollBarPosition(QTermWidget::ScrollBarPosition position) { - if (_scrollbarLocation == position) - return; - - if ( position == NoScrollBar ) + if (_scrollbarLocation == position) + return; + + if ( position == QTermWidget::NoScrollBar ) _scrollBar->hide(); - else - _scrollBar->show(); + else + _scrollBar->show(); _topMargin = _leftMargin = 1; _scrollbarLocation = position; - + propagateSize(); update(); } @@ -1789,7 +1970,7 @@ void TerminalDisplay::mousePressEvent(QMouseEvent* ev) } if ( !contentsRect().contains(ev->pos()) ) return; - + if ( !_screenWindow ) return; int charLine; @@ -1805,11 +1986,11 @@ void TerminalDisplay::mousePressEvent(QMouseEvent* ev) emit isBusySelecting(true); // Keep it steady... // Drag only when the Control key is hold bool selected = false; - + // The receiver of the testIsSelected() signal will adjust // 'selected' accordingly. //emit testIsSelected(pos.x(), pos.y(), selected); - + selected = _screenWindow->isSelected(pos.x(),pos.y()); if ((!_ctrlDrag || ev->modifiers() & Qt::ControlModifier) && selected ) { @@ -1832,7 +2013,7 @@ void TerminalDisplay::mousePressEvent(QMouseEvent* ev) pos.ry() += _scrollBar->value(); _iPntSel = _pntSel = pos; _actSel = 1; // left mouse button pressed but nothing selected yet. - + } else { @@ -1841,42 +2022,45 @@ void TerminalDisplay::mousePressEvent(QMouseEvent* ev) Filter::HotSpot *spot = _filterChain->hotSpotAt(charLine, charColumn); if (spot && spot->type() == Filter::HotSpot::Link) - spot->activate("open-action"); + spot->activate(QLatin1String("click-action")); } } else if ( ev->button() == Qt::MidButton ) { - if ( _mouseMarks || (!_mouseMarks && (ev->modifiers() & Qt::ShiftModifier)) ) + if ( _mouseMarks || (ev->modifiers() & Qt::ShiftModifier) ) emitSelection(true,ev->modifiers() & Qt::ControlModifier); else emit mouseSignal( 1, charColumn +1, charLine +1 +_scrollBar->value() -_scrollBar->maximum() , 0); } else if ( ev->button() == Qt::RightButton ) { - if (_mouseMarks || (ev->modifiers() & Qt::ShiftModifier)) + if (_mouseMarks || (ev->modifiers() & Qt::ShiftModifier)) emit configureRequest(ev->pos()); else emit mouseSignal( 2, charColumn +1, charLine +1 +_scrollBar->value() -_scrollBar->maximum() , 0); } } -QList TerminalDisplay::filterActions(const QPoint& position) +QList TerminalDisplay::filterActions(const QPoint& position, QWidget* parent) { int charLine, charColumn; getCharacterPosition(position,charLine,charColumn); Filter::HotSpot* spot = _filterChain->hotSpotAt(charLine,charColumn); - return spot ? spot->actions() : QList(); + return spot ? spot->actions(parent) : QList(); } void TerminalDisplay::mouseMoveEvent(QMouseEvent* ev) { int charLine = 0; int charColumn = 0; - int scrollBarWidth = (_scrollbarLocation == ScrollBarLeft) ? _scrollBar->width() : 0; + int leftMargin = _leftBaseMargin + + ((_scrollbarLocation == QTermWidget::ScrollBarLeft + && !_scrollBar->style()->styleHint(QStyle::SH_ScrollBar_Transient, nullptr, _scrollBar)) + ? _scrollBar->width() : 0); - getCharacterPosition(ev->pos(),charLine,charColumn); + getCharacterPosition(ev->pos(),charLine,charColumn); // handle filters // change link hot-spot appearance on mouse-over @@ -1887,38 +2071,30 @@ void TerminalDisplay::mouseMoveEvent(QMouseEvent* ev) _mouseOverHotspotArea = QRegion(); QRect r; if (spot->startLine()==spot->endLine()) { - r.setCoords( spot->startColumn()*_fontWidth + scrollBarWidth, - spot->startLine()*_fontHeight, - spot->endColumn()*_fontWidth + scrollBarWidth, - (spot->endLine()+1)*_fontHeight - 1 ); + r.setCoords( spot->startColumn()*_fontWidth + leftMargin, + spot->startLine()*_fontHeight + _topBaseMargin, + spot->endColumn()*_fontWidth + leftMargin, + (spot->endLine()+1)*_fontHeight - 1 + _topBaseMargin ); _mouseOverHotspotArea |= r; } else { - r.setCoords( spot->startColumn()*_fontWidth + scrollBarWidth, - spot->startLine()*_fontHeight, - _columns*_fontWidth - 1 + scrollBarWidth, - (spot->startLine()+1)*_fontHeight ); + r.setCoords( spot->startColumn()*_fontWidth + leftMargin, + spot->startLine()*_fontHeight + _topBaseMargin, + _columns*_fontWidth - 1 + leftMargin, + (spot->startLine()+1)*_fontHeight + _topBaseMargin ); _mouseOverHotspotArea |= r; for ( int line = spot->startLine()+1 ; line < spot->endLine() ; line++ ) { - r.setCoords( 0*_fontWidth + scrollBarWidth, - line*_fontHeight, - _columns*_fontWidth + scrollBarWidth, - (line+1)*_fontHeight ); + r.setCoords( 0*_fontWidth + leftMargin, + line*_fontHeight + _topBaseMargin, + _columns*_fontWidth + leftMargin, + (line+1)*_fontHeight + _topBaseMargin ); _mouseOverHotspotArea |= r; } - r.setCoords( 0*_fontWidth + scrollBarWidth, - spot->endLine()*_fontHeight, - spot->endColumn()*_fontWidth + scrollBarWidth, - (spot->endLine()+1)*_fontHeight ); + r.setCoords( 0*_fontWidth + leftMargin, + spot->endLine()*_fontHeight + _topBaseMargin, + spot->endColumn()*_fontWidth + leftMargin, + (spot->endLine()+1)*_fontHeight + _topBaseMargin ); _mouseOverHotspotArea |= r; } - // display tooltips when mousing over links - // TODO: Extend this to work with filter types other than links - const QString& tooltip = spot->tooltip(); - if ( !tooltip.isEmpty() ) - { - //QToolTip::showText( mapToScene(ev->pos()).toPoint() , tooltip , this , _mouseOverHotspotArea.boundingRect() ); - } - update( _mouseOverHotspotArea | previousHotspotArea ); } else if ( !_mouseOverHotspotArea.isEmpty() ) @@ -1927,11 +2103,11 @@ void TerminalDisplay::mouseMoveEvent(QMouseEvent* ev) // set hotspot area to an invalid rectangle _mouseOverHotspotArea = QRegion(); } - + // for auto-hiding the cursor, we need mouseTracking if (ev->buttons() == Qt::NoButton ) return; - // if the terminal is interested in mouse movements + // if the terminal is interested in mouse movements // then emit a mouse movement signal, unless the shift // key is being held down, which overrides this. if (!_mouseMarks && !(ev->modifiers() & Qt::ShiftModifier)) @@ -1944,16 +2120,16 @@ void TerminalDisplay::mouseMoveEvent(QMouseEvent* ev) if (ev->buttons() & Qt::RightButton) button = 2; - - emit mouseSignal( button, + + emit mouseSignal( button, charColumn + 1, charLine + 1 +_scrollBar->value() -_scrollBar->maximum(), 1 ); - + return; } - - if (dragInfo.state == diPending) + + if (dragInfo.state == diPending) { // we had a mouse down, but haven't confirmed a drag yet // if the mouse has moved sufficiently, we will confirm @@ -1961,17 +2137,17 @@ void TerminalDisplay::mouseMoveEvent(QMouseEvent* ev) // int distance = KGlobalSettings::dndEventDelay(); int distance = QApplication::startDragDistance(); if ( ev->x() > dragInfo.start.x() + distance || ev->x() < dragInfo.start.x() - distance || - ev->y() > dragInfo.start.y() + distance || ev->y() < dragInfo.start.y() - distance) + ev->y() > dragInfo.start.y() + distance || ev->y() < dragInfo.start.y() - distance) { // we've left the drag square, we can start a real drag operation now emit isBusySelecting(false); // Ok.. we can breath again. - + _screenWindow->clearSelection(); doDrag(); } return; - } - else if (dragInfo.state == diDragging) + } + else if (dragInfo.state == diDragging) { // this isn't technically needed because mouseMoveEvent is suppressed during // Qt drag operations, replaced by dragMoveEvent @@ -2012,11 +2188,11 @@ void TerminalDisplay::extendSelection( const QPoint& position ) // Adjust position within text area bounds. QPoint oldpos = pos; - + pos.setX( qBound(textBounds.left(),pos.x(),textBounds.right()) ); pos.setY( qBound(textBounds.top(),pos.y(),textBounds.bottom()) ); - if ( oldpos.y() > textBounds.bottom() ) + if ( oldpos.y() > textBounds.bottom() ) { linesBeyondWidget = (oldpos.y()-textBounds.bottom()) / _fontHeight; _scrollBar->setValue(_scrollBar->value()+linesBeyondWidget+1); // scrollforward @@ -2056,7 +2232,7 @@ void TerminalDisplay::extendSelection( const QPoint& position ) i = loc(left.x(),left.y()); if (i>=0 && i<=_imageSize) { selClass = charClass(_image[i].character); - while ( ((left.x()>0) || (left.y()>0 && (_lineProperties[left.y()-1] & LINE_WRAPPED) )) + while ( ((left.x()>0) || (left.y()>0 && (_lineProperties[left.y()-1] & LINE_WRAPPED) )) && charClass(_image[i-1].character) == selClass ) { i--; if (left.x()>0) left.rx()--; else {left.rx()=_usedColumns-1; left.ry()--;} } } @@ -2066,7 +2242,7 @@ void TerminalDisplay::extendSelection( const QPoint& position ) i = loc(right.x(),right.y()); if (i>=0 && i<=_imageSize) { selClass = charClass(_image[i].character); - while( ((right.x()<_usedColumns-1) || (right.y()<_usedLines-1 && (_lineProperties[right.y()] & LINE_WRAPPED) )) + while( ((right.x()<_usedColumns-1) || (right.y()<_usedLines-1 && (_lineProperties[right.y()] & LINE_WRAPPED) )) && charClass(_image[i+1].character) == selClass ) { i++; if (right.x()<_usedColumns-1) right.rx()++; else {right.rx()=0; right.ry()++; } } } @@ -2140,7 +2316,7 @@ void TerminalDisplay::extendSelection( const QPoint& position ) selClass = charClass(_image[i-1].character); /* if (selClass == ' ') { - while ( right.x() < _usedColumns-1 && charClass(_image[i+1].character) == selClass && (right.y()<_usedLines-1) && + while ( right.x() < _usedColumns-1 && charClass(_image[i+1].character) == selClass && (right.y()<_usedLines-1) && !(_lineProperties[right.y()] & LINE_WRAPPED)) { i++; right.rx()++; } if (right.x() < _usedColumns-1) @@ -2205,7 +2381,7 @@ void TerminalDisplay::mouseReleaseEvent(QMouseEvent* ev) if ( ev->button() == Qt::LeftButton) { - emit isBusySelecting(false); + emit isBusySelecting(false); if(dragInfo.state == diPending) { // We had a drag event pending but never confirmed. Kill selection @@ -2226,30 +2402,40 @@ 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; } - - - if ( !_mouseMarks && + + + if ( !_mouseMarks && ((ev->button() == Qt::RightButton && !(ev->modifiers() & Qt::ShiftModifier)) - || ev->button() == Qt::MidButton) ) + || ev->button() == Qt::MidButton) ) { - emit mouseSignal( 3, - charColumn + 1, - charLine + 1 +_scrollBar->value() -_scrollBar->maximum() , - 0); + emit mouseSignal( ev->button() == Qt::MidButton ? 1 : 2, + charColumn + 1, + charLine + 1 +_scrollBar->value() -_scrollBar->maximum() , + 2); } } void TerminalDisplay::getCharacterPosition(const QPoint& widgetPoint,int& line,int& column) const { - column = (widgetPoint.x() + _fontWidth/2 -contentsRect().left()-_leftMargin) / _fontWidth; line = (widgetPoint.y()-contentsRect().top()-_topMargin) / _fontHeight; + if ( _fixedFont ) + column = (widgetPoint.x() + _fontWidth/2 -contentsRect().left()-_leftMargin) / _fontWidth; + else + { + int x = contentsRect().left() + widgetPoint.x() - _fontWidth/2; + column = 0; + + while(x > textWidth(0, column, line)) + column++; + } + if ( line < 0 ) line = 0; if ( column < 0 ) @@ -2277,10 +2463,10 @@ void TerminalDisplay::updateFilters() void TerminalDisplay::updateLineProperties() { - if ( !_screenWindow ) + if ( !_screenWindow ) return; - _lineProperties = _screenWindow->getLineProperties(); + _lineProperties = _screenWindow->getLineProperties(); } void TerminalDisplay::mouseDoubleClickEvent(QMouseEvent* ev) @@ -2300,8 +2486,8 @@ void TerminalDisplay::mouseDoubleClickEvent(QMouseEvent* ev) { // Send just _ONE_ click event, since the first click of the double click // was already sent by the click handler - emit mouseSignal( 0, - pos.x()+1, + emit mouseSignal( 0, + pos.x()+1, pos.y()+1 +_scrollBar->value() -_scrollBar->maximum(), 0 ); // left button return; @@ -2321,17 +2507,17 @@ void TerminalDisplay::mouseDoubleClickEvent(QMouseEvent* ev) { // find the start of the word int x = bgnSel.x(); - while ( ((x>0) || (bgnSel.y()>0 && (_lineProperties[bgnSel.y()-1] & LINE_WRAPPED) )) + while ( ((x>0) || (bgnSel.y()>0 && (_lineProperties[bgnSel.y()-1] & LINE_WRAPPED) )) && charClass(_image[i-1].character) == selClass ) - { - i--; - if (x>0) - x--; - else + { + i--; + if (x>0) + x--; + else { - x=_usedColumns-1; + x=_usedColumns-1; bgnSel.ry()--; - } + } } bgnSel.setX(x); @@ -2340,31 +2526,31 @@ void TerminalDisplay::mouseDoubleClickEvent(QMouseEvent* ev) // find the end of the word i = loc( endSel.x(), endSel.y() ); x = endSel.x(); - while( ((x<_usedColumns-1) || (endSel.y()<_usedLines-1 && (_lineProperties[endSel.y()] & LINE_WRAPPED) )) + while( ((x<_usedColumns-1) || (endSel.y()<_usedLines-1 && (_lineProperties[endSel.y()] & LINE_WRAPPED) )) && charClass(_image[i+1].character) == selClass ) - { - i++; - if (x<_usedColumns-1) - x++; - else - { - x=0; - endSel.ry()++; - } + { + i++; + if (x<_usedColumns-1) + x++; + else + { + x=0; + endSel.ry()++; + } } endSel.setX(x); // In word selection mode don't select @ (64) if at end of word. - if ( ( QChar( _image[i].character ) == '@' ) && ( ( endSel.x() - bgnSel.x() ) > 0 ) ) + if ( ( QChar( _image[i].character ) == QLatin1Char('@') ) && ( ( endSel.x() - bgnSel.x() ) > 0 ) ) endSel.setX( x - 1 ); _actSel = 2; // within selection - + _screenWindow->setSelectionEnd( endSel.x() , endSel.y() ); - - setSelection( _screenWindow->selectedText(_preserveLineBreaks) ); + + setSelection( _screenWindow->selectedText(_preserveLineBreaks) ); } _possibleTripleClick=true; @@ -2390,7 +2576,7 @@ void TerminalDisplay::wheelEvent( QWheelEvent* ev ) else { // assume that each Up / Down key event will cause the terminal application - // to scroll by one line. + // to scroll by one line. // // to get a reasonable scrolling speed, scroll by one line for every 5 degrees // of mouse wheel rotation. Mouse wheels typically move in steps of 15 degrees, @@ -2410,14 +2596,14 @@ void TerminalDisplay::wheelEvent( QWheelEvent* ev ) else { // terminal program wants notification of mouse activity - + int charLine; int charColumn; getCharacterPosition( ev->pos() , charLine , charColumn ); - - emit mouseSignal( ev->delta() > 0 ? 4 : 5, - charColumn + 1, - charLine + 1 +_scrollBar->value() -_scrollBar->maximum() , + + emit mouseSignal( ev->delta() > 0 ? 4 : 5, + charColumn + 1, + charLine + 1 +_scrollBar->value() -_scrollBar->maximum() , 0); } } @@ -2446,26 +2632,26 @@ void TerminalDisplay::mouseTripleClickEvent(QMouseEvent* ev) while (_iPntSel.y()>0 && (_lineProperties[_iPntSel.y()-1] & LINE_WRAPPED) ) _iPntSel.ry()--; - + if (_tripleClickMode == SelectForwardsFromCursor) { // find word boundary start int i = loc(_iPntSel.x(),_iPntSel.y()); QChar selClass = charClass(_image[i].character); int x = _iPntSel.x(); - - while ( ((x>0) || + + while ( ((x>0) || (_iPntSel.y()>0 && (_lineProperties[_iPntSel.y()-1] & LINE_WRAPPED) ) - ) + ) && charClass(_image[i-1].character) == selClass ) { - i--; - if (x>0) - x--; - else + i--; + if (x>0) + x--; + else { - x=_columns-1; + x=_columns-1; _iPntSel.ry()--; - } + } } _screenWindow->setSelectionStart( x , _iPntSel.y() , false ); @@ -2478,7 +2664,7 @@ void TerminalDisplay::mouseTripleClickEvent(QMouseEvent* ev) while (_iPntSel.y()<_lines-1 && (_lineProperties[_iPntSel.y()] & LINE_WRAPPED) ) _iPntSel.ry()++; - + _screenWindow->setSelectionEnd( _columns - 1 , _iPntSel.y() ); setSelection(_screenWindow->selectedText(_preserveLineBreaks)); @@ -2499,10 +2685,10 @@ bool TerminalDisplay::focusNextPrevChild( bool next ) QChar TerminalDisplay::charClass(QChar qch) const { - if ( qch.isSpace() ) return ' '; + if ( qch.isSpace() ) return QLatin1Char(' '); if ( qch.isLetterOrNumber() || _wordCharacters.contains(qch, Qt::CaseInsensitive ) ) - return 'a'; + return QLatin1Char('a'); return qch; } @@ -2525,6 +2711,15 @@ bool TerminalDisplay::usesMouse() const return _mouseMarks; } +void TerminalDisplay::setBracketedPasteMode(bool on) +{ + _bracketedPasteMode = on; +} +bool TerminalDisplay::bracketedPasteMode() const +{ + return _bracketedPasteMode; +} + /* ------------------------------------------------------------------------- */ /* */ /* Clipboard */ @@ -2535,24 +2730,34 @@ bool TerminalDisplay::usesMouse() const void TerminalDisplay::emitSelection(bool useXselection,bool appendReturn) { - if ( !_screenWindow ) + if ( !_screenWindow ) return; // Paste Clipboard by simulating keypress events QString text = QApplication::clipboard()->text(useXselection ? QClipboard::Selection : QClipboard::Clipboard); if(appendReturn) - text.append("\r"); + text.append(QLatin1Char('\r')); if ( ! text.isEmpty() ) { - text.replace('\n', '\r'); + text.replace(QLatin1Char('\n'), QLatin1Char('\r')); + bracketText(text); QKeyEvent e(QEvent::KeyPress, 0, Qt::NoModifier, text); emit keyPressedSignal(&e); // expose as a big fat keypress event - + _screenWindow->clearSelection(); } } +void TerminalDisplay::bracketText(QString& text) +{ + if (bracketedPasteMode()) + { + text.prepend(QLatin1String("\033[200~")); + text.append(QLatin1String("\033[201~")); + } +} + void TerminalDisplay::setSelection(const QString& t) { QApplication::clipboard()->setText(t, QClipboard::Selection); @@ -2587,8 +2792,8 @@ void TerminalDisplay::pasteSelection() void TerminalDisplay::setFlowControlWarningEnabled( bool enable ) { _flowControlWarningEnabled = enable; - - // if the dialog is currently visible and the flow control warning has + + // if the dialog is currently visible and the flow control warning has // been disabled then hide the dialog if (!enable) outputSuspended(false); @@ -2643,7 +2848,7 @@ void TerminalDisplay::keyPressEvent( QKeyEvent* event ) if ( update ) { _screenWindow->setTrackOutput( _screenWindow->atEndOfOutput() ); - + updateLineProperties(); updateImage(); @@ -2655,7 +2860,7 @@ void TerminalDisplay::keyPressEvent( QKeyEvent* event ) _actSel=0; // Key stroke implies a screen update, so TerminalDisplay won't // know where the current selection is. - if (_hasBlinkingCursor) + if (_hasBlinkingCursor) { _blinkCursorTimer->start(QApplication::cursorFlashTime() / 2); if (_cursorBlinking) @@ -2698,9 +2903,9 @@ 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(); } @@ -2714,7 +2919,7 @@ void TerminalDisplay::inputMethodQuery(QInputMethodQueryEvent *event) QVariant TerminalDisplay::inputMethodQuery( Qt::InputMethodQuery query ) const { const QPoint cursorPos = _screenWindow ? _screenWindow->cursorPosition() : QPoint(0,0); - switch ( query ) + switch ( query ) { case Qt::ImMicroFocus: return imageToWidget(QRect(cursorPos.x(),cursorPos.y(),1,1)); @@ -2752,10 +2957,10 @@ bool TerminalDisplay::handleShortcutOverrideEvent(QKeyEvent* keyEvent) { int modifiers = keyEvent->modifiers(); - // When a possible shortcut combination is pressed, + // When a possible shortcut combination is pressed, // emit the overrideShortcutCheck() signal to allow the host // to decide whether the terminal should override it or not. - if (modifiers != Qt::NoModifier) + if (modifiers != Qt::NoModifier) { int modifierCount = 0; unsigned int currentModifier = Qt::ShiftModifier; @@ -2766,7 +2971,7 @@ bool TerminalDisplay::handleShortcutOverrideEvent(QKeyEvent* keyEvent) modifierCount++; currentModifier <<= 1; } - if (modifierCount < 2) + if (modifierCount < 2) { bool override = false; emit overrideShortcutCheck(keyEvent,override); @@ -2833,23 +3038,23 @@ void TerminalDisplay::bell(const QString& message) { if (_bellMode==NoBell) return; - //limit the rate at which bells can occur - //...mainly for sound effects where rapid bells in sequence + //limit the rate at which bells can occur + //...mainly for sound effects where rapid bells in sequence //produce a horrible noise if ( _allowBell ) { _allowBell = false; QTimer::singleShot(500,this,SLOT(enableBell())); - - if (_bellMode==SystemBeepBell) + + if (_bellMode==SystemBeepBell) { QApplication::beep(); - } - else if (_bellMode==NotifyBell) + } + else if (_bellMode==NotifyBell) { emit notifyBell(message); - } - else if (_bellMode==VisualBell) + } + else if (_bellMode==VisualBell) { swapColorTable(); QTimer::singleShot(200,this,SLOT(swapColorTable())); @@ -2888,33 +3093,35 @@ 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 NoScrollBar : - _leftMargin = DEFAULT_LEFT_MARGIN; - _contentWidth = contentsRect().width() - 2 * DEFAULT_LEFT_MARGIN; + case QTermWidget::NoScrollBar : + _leftMargin = _leftBaseMargin; + _contentWidth = contentsRect().width() - 2 * _leftBaseMargin; break; - case ScrollBarLeft : - _leftMargin = DEFAULT_LEFT_MARGIN + _scrollBar->width(); - _contentWidth = contentsRect().width() - 2 * DEFAULT_LEFT_MARGIN - _scrollBar->width(); + case QTermWidget::ScrollBarLeft : + _leftMargin = _leftBaseMargin + scrollBarWidth; + _contentWidth = contentsRect().width() - 2 * _leftBaseMargin - scrollBarWidth; _scrollBar->move(contentsRect().topLeft()); break; - case ScrollBarRight: - _leftMargin = DEFAULT_LEFT_MARGIN; - _contentWidth = contentsRect().width() - 2 * DEFAULT_LEFT_MARGIN - _scrollBar->width(); - _scrollBar->move(contentsRect().topRight() - QPoint(_scrollBar->width()-1,0)); + case QTermWidget::ScrollBarRight: + _leftMargin = _leftBaseMargin; + _contentWidth = contentsRect().width() - 2 * _leftBaseMargin - scrollBarWidth; + _scrollBar->move(contentsRect().topRight() - QPoint(_scrollBar->width()-1, 0)); break; } - _topMargin = DEFAULT_TOP_MARGIN; - _contentHeight = contentsRect().height() - 2 * DEFAULT_TOP_MARGIN + /* mysterious */ 1; - + _topMargin = _topBaseMargin; + _contentHeight = contentsRect().height() - 2 * _topBaseMargin + /* mysterious */ 1; + if (!_isFixedSize) { // ensure that display is always at least one column wide _columns = qMax(1,_contentWidth / _fontWidth); _usedColumns = qMin(_usedColumns,_columns); - + // ensure that display is always at least one line high _lines = qMax(1,_contentHeight / _fontHeight); _usedLines = qMin(_usedLines,_lines); @@ -2925,13 +3132,13 @@ void TerminalDisplay::makeImage() { calcGeometry(); - // confirm that array will be of non-zero size, since the painting code + // confirm that array will be of non-zero size, since the painting code // assumes a non-zero array length Q_ASSERT( _lines > 0 && _columns > 0 ); Q_ASSERT( _usedLines <= _lines && _usedColumns <= _columns ); _imageSize=_lines*_columns; - + // We over-commit one character so that we can be more relaxed in dealing with // certain boundary conditions: _image[_imageSize] is a valid but unused position _image = new Character[_imageSize+1]; @@ -2942,9 +3149,11 @@ 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 horizontalMargin = 2 * DEFAULT_LEFT_MARGIN; - int verticalMargin = 2 * DEFAULT_TOP_MARGIN; + int scrollBarWidth = (_scrollBar->isHidden() + || _scrollBar->style()->styleHint(QStyle::SH_ScrollBar_Transient, nullptr, _scrollBar)) + ? 0 : _scrollBar->sizeHint().width(); + int horizontalMargin = 2 * _leftBaseMargin; + int verticalMargin = 2 * _topBaseMargin; QSize newSize = QSize( horizontalMargin + scrollBarWidth + (columns * _fontWidth) , verticalMargin + (lines * _fontHeight) ); @@ -2961,7 +3170,7 @@ void TerminalDisplay::setSize(int columns, int lines) void TerminalDisplay::setFixedSize(int cols, int lins) { _isFixedSize = true; - + //ensure that display is at least one line by one column in size _columns = qMax(1,cols); _lines = qMax(1,lins); @@ -2991,7 +3200,7 @@ QSize TerminalDisplay::sizeHint() const void TerminalDisplay::dragEnterEvent(QDragEnterEvent* event) { - if (event->mimeData()->hasFormat("text/plain")) + if (event->mimeData()->hasFormat(QLatin1String("text/plain"))) event->acceptProposedAction(); if (event->mimeData()->urls().count()) event->acceptProposedAction(); @@ -3003,11 +3212,11 @@ void TerminalDisplay::dropEvent(QDropEvent* event) QList urls = event->mimeData()->urls(); QString dropText; - if (!urls.isEmpty()) + if (!urls.isEmpty()) { // TODO/FIXME: escape or quote pasted things if neccessary... qDebug() << "TerminalDisplay: handling urls. It can be broken. Report any errors, please"; - for ( int i = 0 ; i < urls.count() ; i++ ) + for ( int i = 0 ; i < urls.count() ; i++ ) { //KUrl url = KIO::NetAccess::mostLocalUrl( urls[i] , 0 ); QUrl url = urls[i]; @@ -3015,26 +3224,26 @@ void TerminalDisplay::dropEvent(QDropEvent* event) QString urlText; if (url.isLocalFile()) - urlText = url.path(); + urlText = url.path(); else urlText = url.toString(); - + // in future it may be useful to be able to insert file names with drag-and-drop - // without quoting them (this only affects paths with spaces in) + // without quoting them (this only affects paths with spaces in) //urlText = KShell::quoteArg(urlText); - + dropText += urlText; - if ( i != urls.count()-1 ) - dropText += ' '; + if ( i != urls.count()-1 ) + dropText += QLatin1Char(' '); } } - else + else { dropText = event->mimeData()->text(); } - emit sendStringToEmu(dropText.toLocal8Bit()); + emit sendStringToEmu(dropText.toLocal8Bit().constData()); } void TerminalDisplay::doDrag() @@ -3051,6 +3260,7 @@ void TerminalDisplay::doDrag() void TerminalDisplay::outputSuspended(bool suspended) { //create the label when this function is first called + // if (!_outputSuspendedLabel) // { // //This label includes a link to an English language website @@ -3102,6 +3312,17 @@ void TerminalDisplay::setLineSpacing(uint i) } } +int TerminalDisplay::margin() const +{ + return _topBaseMargin; +} + +void TerminalDisplay::setMargin(int i) +{ + _topBaseMargin = i; + _leftBaseMargin = i; +} + AutoScrollHandler::AutoScrollHandler(QWidget* parent) : QObject(parent) , _timerId(0) diff --git a/lib/TerminalDisplay.h b/lib/TerminalDisplay.h index 79357d1..3562345 100644 --- a/lib/TerminalDisplay.h +++ b/lib/TerminalDisplay.h @@ -30,6 +30,7 @@ // Konsole #include "Filter.h" #include "Character.h" +#include "qtermwidget.h" //#include "konsole_export.h" #define KONSOLEPRIVATE_EXPORT @@ -75,7 +76,7 @@ class ScreenWindow; * A widget which displays output from a terminal emulation and sends input keypresses and mouse activity * to the terminal. * - * When the terminal emulation receives new output from the program running in the terminal, + * When the terminal emulation receives new output from the program running in the terminal, * it will update the display by calling updateImage(). * * TODO More documentation @@ -124,7 +125,6 @@ public: /** Sets the opacity of the terminal display. */ void setOpacity(qreal opacity); - /** * This enum describes the location where the scroll bar is positioned in the display widget. */ @@ -138,12 +138,17 @@ public: ScrollBarRight=2 }; /** + + /** Sets the background image of the terminal display. */ + void setBackgroundImage(QString backgroundImage); + + /** * Specifies whether the terminal display has a vertical scroll bar, and if so whether it * is shown on the left or right side of the display. */ - void setScrollBarPosition(ScrollBarPosition position); + void setScrollBarPosition(QTermWidget::ScrollBarPosition position); - /** + /** * Sets the current position and range of the display's scroll bar. * * @param cursor The position of the scroll bar's thumb. @@ -156,7 +161,7 @@ public: */ void scrollToEnd(); - /** + /** * Returns the display's filter chain. When the image for the display is updated, * the text is passed through each filter in the chain. Each filter can define * hotspots which correspond to certain strings (such as URLs or particular words). @@ -169,11 +174,11 @@ public: */ FilterChain* filterChain() const; - /** + /** * Updates the filters in the display's filter chain. This will cause * the hotspots to be updated to match the current image. * - * WARNING: This function can be expensive depending on the + * WARNING: This function can be expensive depending on the * image size and number of filters in the filterChain() * * TODO - This API does not really allow efficient usage. Revise it so @@ -182,14 +187,14 @@ public: * eg: * - Area of interest may be known ( eg. mouse cursor hovering * over an area ) - */ + */ void processFilters(); - /** + /** * Returns a list of menu actions created by the filters for the content * at the given @p position. */ - QList filterActions(const QPoint& position); + QList filterActions(const QPoint& position, QWidget* parent); /** Returns true if the cursor is set to blink or false otherwise. */ bool blinkingCursor() { return _hasBlinkingCursor; } @@ -202,9 +207,9 @@ public: void setCtrlDrag(bool enable) { _ctrlDrag=enable; } bool ctrlDrag() { return _ctrlDrag; } - /** + /** * This enum describes the methods for selecting text when - * the user triple-clicks within the display. + * the user triple-clicks within the display. */ enum TripleClickMode { @@ -213,53 +218,40 @@ public: /** Select from the current cursor position to the end of the line. */ SelectForwardsFromCursor }; - /** Sets how the text is selected when the user triple clicks within the display. */ + /** Sets how the text is selected when the user triple clicks within the display. */ void setTripleClickMode(TripleClickMode mode) { _tripleClickMode = mode; } /** See setTripleClickSelectionMode() */ TripleClickMode tripleClickMode() { return _tripleClickMode; } void setLineSpacing(uint); + void setMargin(int); + + int margin() const; uint lineSpacing() const; void emitSelection(bool useXselection,bool appendReturn); + /** change and wrap text corresponding to paste mode **/ + void bracketText(QString& text); + /** - * This enum describes the available shapes for the keyboard cursor. - * See setKeyboardCursorShape() - */ - enum KeyboardCursorShape - { - /** A rectangular block which covers the entire area of the cursor character. */ - BlockCursor, - /** - * A single flat line which occupies the space at the bottom of the cursor - * character's area. - */ - UnderlineCursor, - /** - * An cursor shaped like the capital letter 'I', similar to the IBeam - * cursor used in Qt/KDE text editors. - */ - IBeamCursor - }; - /** - * Sets the shape of the keyboard cursor. This is the cursor drawn + * Sets the shape of the keyboard cursor. This is the cursor drawn * at the position in the terminal where keyboard input will appear. * - * In addition the terminal display widget also has a cursor for + * In addition the terminal display widget also has a cursor for * the mouse pointer, which can be set using the QWidget::setCursor() * method. * * Defaults to BlockCursor */ - void setKeyboardCursorShape(KeyboardCursorShape shape); + void setKeyboardCursorShape(QTermWidget::KeyboardCursorShape shape); /** * Returns the shape of the keyboard cursor. See setKeyboardCursorShape() */ - KeyboardCursorShape keyboardCursorShape() const; + QTermWidget::KeyboardCursorShape keyboardCursorShape() const; /** - * Sets the color used to draw the keyboard cursor. + * Sets the color used to draw the keyboard cursor. * * The keyboard cursor defaults to using the foreground color of the character * underneath it. @@ -273,10 +265,10 @@ public: */ void setKeyboardCursorColor(bool useForegroundColor , const QColor& color); - /** + /** * Returns the color of the keyboard cursor, or an invalid color if the keyboard * cursor color is set to change according to the foreground color of the character - * underneath it. + * underneath it. */ QColor keyboardCursorColor() const; @@ -301,19 +293,19 @@ public: */ int fontHeight() { return _fontHeight; } /** - * Returns the width of the characters in the display. + * Returns the width of the characters in the display. * This assumes the use of a fixed-width font. */ int fontWidth() { return _fontWidth; } void setSize(int cols, int lins); void setFixedSize(int cols, int lins); - + // reimplemented QSize sizeHint() const; /** - * Sets which characters, in addition to letters and numbers, + * Sets which characters, in addition to letters and numbers, * are regarded as being part of a word for the purposes * of selecting words in the display by double clicking on them. * @@ -324,26 +316,26 @@ public: * of a word ( in addition to letters and numbers ). */ void setWordCharacters(const QString& wc); - /** - * Returns the characters which are considered part of a word for the + /** + * Returns the characters which are considered part of a word for the * purpose of selecting words in the display with the mouse. * * @see setWordCharacters() */ QString wordCharacters() { return _wordCharacters; } - /** - * Sets the type of effect used to alert the user when a 'bell' occurs in the + /** + * Sets the type of effect used to alert the user when a 'bell' occurs in the * terminal session. * * The terminal session can trigger the bell effect by calling bell() with * the alert message. */ void setBellMode(int mode); - /** + /** * Returns the type of effect used to alert the user when a 'bell' occurs in * the terminal session. - * + * * See setBellMode() */ int bellMode() { return _bellMode; } @@ -354,23 +346,23 @@ public: * session. */ enum BellMode - { + { /** A system beep. */ - SystemBeepBell=0, - /** + SystemBeepBell=0, + /** * KDE notification. This may play a sound, show a passive popup * or perform some other action depending on the user's settings. */ - NotifyBell=1, + NotifyBell=1, /** A silent, visual bell (eg. inverting the display's colors briefly) */ - VisualBell=2, + VisualBell=2, /** No bell effects */ - NoBell=3 + NoBell=3 }; void setSelection(const QString &t); - /** + /** * Reimplemented. Has no effect. Use setVTFont() to change the font * used to draw characters in the display. */ @@ -379,9 +371,9 @@ public: /** Returns the font used to draw characters in the display */ QFont getVTFont() { return font(); } - /** + /** * Sets the font used to draw the display. Has no effect if @p font - * is larger than the size of the display itself. + * is larger than the size of the display itself. */ void setVTFont(const QFont& font); @@ -390,7 +382,7 @@ public: * is enabled or not. Defaults to enabled. */ static void setAntialias( bool antialias ) { _antialiasText = antialias; } - /** + /** * Returns true if anti-aliasing of text in the terminal is enabled. */ static bool antialias() { return _antialiasText; } @@ -404,20 +396,20 @@ public: * Returns true if characters with intense colors are rendered in bold. */ bool getBoldIntense() { return _boldIntense; } - + /** - * Sets whether or not the current height and width of the + * Sets whether or not the current height and width of the * terminal in lines and columns is displayed whilst the widget * is being resized. */ void setTerminalSizeHint(bool on) { _terminalSizeHint=on; } - /** + /** * Returns whether or not the current height and width of * the terminal in lines and columns is displayed whilst the widget * is being resized. */ bool terminalSizeHint() { return _terminalSizeHint; } - /** + /** * Sets whether the terminal size display is shown briefly * after the widget is first shown. * @@ -448,36 +440,37 @@ public: ScreenWindow* screenWindow() const; static bool HAVE_TRANSPARENCY; - + void setMotionAfterPasting(MotionAfterPasting action); int motionAfterPasting(); // maps a point on the widget to the position ( ie. line and column ) // of the character at that point. - void getCharacterPosition(const QPoint &widgetPoint, int& line, int& column) const; - + + void getCharacterPosition(const QPoint& widgetPoint,int& line,int& column) const; + public slots: - /** + /** * Causes the terminal display to fetch the latest character image from the associated * terminal screen ( see setScreenWindow() ) and redraw the display. */ - void updateImage(); + void updateImage(); /** Essentially calles processFilters(). */ void updateFilters(); /** - * Causes the terminal display to fetch the latest line status flags from the - * associated terminal screen ( see setScreenWindow() ). - */ + * Causes the terminal display to fetch the latest line status flags from the + * associated terminal screen ( see setScreenWindow() ). + */ void updateLineProperties(); /** Copies the selected text to the clipboard. */ void copyClipboard(); - /** - * Pastes the content of the clipboard into the + /** + * Pastes the content of the clipboard into the * display. */ void pasteClipboard(); @@ -487,26 +480,26 @@ public slots: */ void pasteSelection(); - /** + /** * Changes whether the flow control warning box should be shown when the flow control * stop key (Ctrl+S) are pressed. */ void setFlowControlWarningEnabled(bool enabled); - /** - * Returns true if the flow control warning box is enabled. + /** + * Returns true if the flow control warning box is enabled. * See outputSuspended() and setFlowControlWarningEnabled() */ bool flowControlWarningEnabled() const { return _flowControlWarningEnabled; } - /** + /** * Causes the widget to display or hide a message informing the user that terminal * output has been suspended (by using the flow control key combination Ctrl+S) * * @param suspended True if terminal output has been suspended and the warning message should * be shown or false to indicate that terminal output has been resumed and that * the warning message should disappear. - */ + */ void outputSuspended(bool suspended); /** @@ -516,7 +509,7 @@ public slots: * If this is set to true, mouse signals will be emitted by the view when the user clicks, drags * or otherwise moves the mouse inside the view. * The user interaction needed to create selections will also change, and the user will be required - * to hold down the shift key to create a selection or perform other mouse activities inside the + * to hold down the shift key to create a selection or perform other mouse activities inside the * view area - since the program running in the terminal is being allowed to handle normal mouse * events itself. * @@ -524,28 +517,31 @@ public slots: * or false otherwise. */ void setUsesMouse(bool usesMouse); - + /** See setUsesMouse() */ bool usesMouse() const; - /** + void setBracketedPasteMode(bool bracketedPasteMode); + bool bracketedPasteMode() const; + + /** * Shows a notification that a bell event has occurred in the terminal. * TODO: More documentation here */ void bell(const QString& message); - /** - * Sets the background of the display to the specified color. - * @see setColorTable(), setForegroundColor() + /** + * Sets the background of the display to the specified color. + * @see setColorTable(), setForegroundColor() */ void setBackgroundColor(const QColor& color); - /** - * Sets the text of the display to the specified color. + /** + * Sets the text of the display to the specified color. * @see setColorTable(), setBackgroundColor() */ void setForegroundColor(const QColor& color); - + void selectionChanged(); // QMLTermWidget @@ -567,7 +563,7 @@ signals: */ void keyPressedSignal(QKeyEvent *e); - /** + /** * A mouse event occurred. * @param button The mouse button (0 for left button, 1 for middle button, 2 for right button, 3 for release) * @param column The character column where the event occurred @@ -578,7 +574,7 @@ signals: void changedFontMetricSignal(int height, int width); void changedContentSizeSignal(int height, int width); - /** + /** * Emitted when the user right clicks on the display, or right-clicks with the Shift * key held down if usesMouse() is true. * @@ -587,9 +583,9 @@ signals: void configureRequest(const QPoint& position); /** - * When a shortcut which is also a valid terminal key sequence is pressed while - * the terminal widget has focus, this signal is emitted to allow the host to decide - * whether the shortcut should be overridden. + * When a shortcut which is also a valid terminal key sequence is pressed while + * the terminal widget has focus, this signal is emitted to allow the host to decide + * whether the shortcut should be overridden. * When the shortcut is overridden, the key sequence will be sent to the terminal emulation instead * and the action associated with the shortcut will not be triggered. * @@ -599,18 +595,18 @@ signals: void isBusySelecting(bool busy); void sendStringToEmu(const char*); - + // qtermwidget signals void copyAvailable(bool available); void termGetFocus(); void termLostFocus(); void notifyBell(const QString& bell); + void usesMouseChanged(); // QMLTermWidget void sessionChanged(); void sizeChanged(); - void usesMouseChanged(); void imagePainted(); void scrollbarValueChanged(); void scrollbarParamsChanged(int value); @@ -642,7 +638,7 @@ protected: virtual void wheelEvent( QWheelEvent* ); virtual bool focusNextPrevChild( bool next ); - + // drag and drop virtual void dragEnterEvent(QDragEnterEvent* event); virtual void dropEvent(QDropEvent* event); @@ -658,7 +654,7 @@ protected: // classifies the 'ch' into one of three categories // and returns a character to indicate which category it is in // - // - A space (returns ' ') + // - A space (returns ' ') // - Part of a word (returns 'a') // - Other characters (returns the input character) QChar charClass(QChar ch) const; @@ -682,7 +678,7 @@ protected slots: void scrollBarPositionChanged(int value); void blinkEvent(); void blinkCursorEvent(); - + //Renables bell noises and visuals. Used to disable further bells for a short period of time //after emitting the first in a sequence of bell events. void enableBell(); @@ -696,14 +692,19 @@ private: // -- Drawing helpers -- + // determine the width of this text + int textWidth(int startColumn, int length, int line) const; + // determine the area that encloses this series of characters + QRect calculateTextArea(int topLeftX, int topLeftY, int startColumn, int line, int length); + // divides the part of the display specified by 'rect' into // fragments according to their colors and styles and calls - // drawTextFragment() to draw the fragments + // drawTextFragment() to draw the fragments void drawContents(QPainter &paint, const QRect &rect); // 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); + void drawTextFragment(QPainter& painter, const QRect& rect, + 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 @@ -711,21 +712,21 @@ private: void drawBackground(QPainter& painter, const QRect& rect, const QColor& color, bool useOpacitySetting); // draws the cursor character - void drawCursor(QPainter& painter, const QRect& rect , const QColor& foregroundColor, + 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); + void drawLineCharString(QPainter& painter, int x, int y, + const std::wstring& str, const Character* attributes); // draws the preedit string for input methods void drawInputMethodPreeditString(QPainter& painter , const QRect& rect); // -- - // maps an area in the character image to an area on the widget + // maps an area in the character image to an area on the widget QRect imageToWidget(const QRect& imageArea) const; // the area where the preedit string for input methods will be draw @@ -735,8 +736,8 @@ private: // current size in columns and lines void showResizeNotification(); - // scrolls the image by a number of lines. - // 'lines' may be positive ( to scroll the image down ) + // scrolls the image by a number of lines. + // 'lines' may be positive ( to scroll the image down ) // or negative ( to scroll the image up ) // 'region' is the part of the image to scroll - currently only // the top, bottom and height of 'region' are taken into account, @@ -747,9 +748,11 @@ private: void propagateSize(); void updateImageSize(); void makeImage(); - + void paintFilters(QPainter& painter); + void calDrawTextAdditionHeight(QPainter& painter); + // returns a region covering all of the areas of the widget which contain // a hotspot QRegion hotSpotRegion() const; @@ -763,7 +766,7 @@ private: bool handleShortcutOverrideEvent(QKeyEvent* event); // the window onto the terminal screen which this display - // is currently showing. + // is currently showing. QPointer _screenWindow; bool _allowBell; @@ -775,13 +778,15 @@ private: int _fontWidth; // width int _fontAscent; // ascend bool _boldIntense; // Whether intense colors should be rendered with bold font + int _drawTextAdditionHeight; // additional height to prevent font trancation + bool _drawTextTestFlag; // indicate it is a testing or not int _leftMargin; // offset int _topMargin; // offset int _lines; // the number of lines that can be displayed in the widget int _columns; // the number of columns that can be displayed in the widget - + int _usedLines; // the number of lines that are actually being used, this will be less // than 'lines' if the character image provided with setImage() is smaller // than the maximum image size which can be displayed @@ -789,7 +794,7 @@ private: int _usedColumns; // the number of columns that are actually being used, this will be less // than 'columns' if the character image provided with setImage() is smaller // than the maximum image size which can be displayed - + int _contentHeight; int _contentWidth; Character* _image; // [lines][columns] @@ -806,6 +811,7 @@ private: bool _terminalSizeStartup; bool _bidiEnabled; bool _mouseMarks; + bool _bracketedPasteMode; QPoint _iPntSel; // initial selection point QPoint _pntSel; // current selection point @@ -818,7 +824,7 @@ private: QClipboard* _clipboard; QScrollBar* _scrollBar; - ScrollBarPosition _scrollbarLocation; + QTermWidget::ScrollBarPosition _scrollbarLocation; QString _wordCharacters; int _bellMode; @@ -848,33 +854,35 @@ private: //widgets related to the warning message that appears when the user presses Ctrl+S to suspend //terminal output - informing them what has happened and how to resume output - QLabel* _outputSuspendedLabel; - + QLabel* _outputSuspendedLabel; + uint _lineSpacing; QString _colorScheme; bool _colorsInverted; // true during visual bell QSize _size; - + QRgb _blendColor; + QPixmap _backgroundImage; + // list of filters currently applied to the display. used for links and // search highlight TerminalImageFilterChain* _filterChain; QRegion _mouseOverHotspotArea; - KeyboardCursorShape _cursorShape; + QTermWidget::KeyboardCursorShape _cursorShape; // custom cursor color. if this is invalid then the foreground // color of the character under the cursor is used - QColor _cursorColor; + QColor _cursorColor; MotionAfterPasting mMotionAfterPasting; struct InputMethodData { - QString preeditString; + std::wstring preeditString; QRect previousPreeditRect; }; InputMethodData _inputMethodData; @@ -883,8 +891,9 @@ private: //the delay in milliseconds between redrawing blinking text static const int TEXT_BLINK_DELAY = 500; - static const int DEFAULT_LEFT_MARGIN = 1; - static const int DEFAULT_TOP_MARGIN = 1; + + int _leftBaseMargin; + int _topBaseMargin; // QMLTermWidget port functions QFont m_font; diff --git a/lib/Vt102Emulation.cpp b/lib/Vt102Emulation.cpp index 9f544fa..89f49b9 100644 --- a/lib/Vt102Emulation.cpp +++ b/lib/Vt102Emulation.cpp @@ -41,7 +41,6 @@ // Standard #include #include -#include // Qt #include @@ -61,7 +60,9 @@ using namespace Konsole; Vt102Emulation::Vt102Emulation() : Emulation(), - _titleUpdateTimer(new QTimer(this)) + prevCC(0), + _titleUpdateTimer(new QTimer(this)), + _reportFocusEvents(false) { _titleUpdateTimer->setSingleShot(true); QObject::connect(_titleUpdateTimer , SIGNAL(timeout()) , this , SLOT(updateTitle())); @@ -134,6 +135,7 @@ void Vt102Emulation::reset() - ESC_DE - Escape codes of the form C - CSI_PN - Escape codes of the form '[' {Pn} ';' {Pn} C - CSI_PS - Escape codes of the form '[' {Pn} ';' ... C + - CSI_PS_SP - Escape codes of the form '[' {Pn} ';' ... {Space} C - CSI_PR - Escape codes of the form '[' '?' {Pn} ';' ... C - CSI_PE - Escape codes of the form '[' '!' {Pn} ';' ... C - VT52 - VT52 escape codes @@ -161,6 +163,7 @@ void Vt102Emulation::reset() #define TY_CSI_PS(A,N) TY_CONSTRUCT(5,A,N) #define TY_CSI_PN(A ) TY_CONSTRUCT(6,A,0) #define TY_CSI_PR(A,N) TY_CONSTRUCT(7,A,N) +#define TY_CSI_PS_SP(A,N) TY_CONSTRUCT(11,A,N) #define TY_VT52(A) TY_CONSTRUCT(8,A,0) #define TY_CSI_PG(A) TY_CONSTRUCT(9,A,0) @@ -183,6 +186,7 @@ void Vt102Emulation::resetTokenizer() argc = 0; argv[0] = 0; argv[1] = 0; + prevCC = 0; } void Vt102Emulation::addDigit(int digit) @@ -197,14 +201,13 @@ 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); } // Character Class flags used while decoding - #define CTL 1 // Control character #define CHR 2 // Printable character #define CPN 4 // TODO: Document me @@ -224,7 +227,7 @@ void Vt102Emulation::initTokenizer() charClass[i] |= CTL; for(i = 32;i < 256; ++i) charClass[i] |= CHR; - for(s = (quint8*)"@ABCDGHILMPSTXZcdfry"; *s; ++s) + for(s = (quint8*)"@ABCDGHILMPSTXZbcdfry"; *s; ++s) charClass[*s] |= CPN; // resize = \e[8;;t for(s = (quint8*)"t"; *s; ++s) @@ -267,21 +270,30 @@ void Vt102Emulation::initTokenizer() #define epp( ) (p >= 3 && s[2] == '?') #define epe( ) (p >= 3 && s[2] == '!') #define egt( ) (p >= 3 && s[2] == '>') +#define esp( ) (p == 4 && s[3] == ' ') #define Xpe (tokenBufferPos >= 2 && tokenBuffer[1] == ']') -#define Xte (Xpe && cc == 7 ) +#define Xte (Xpe && (cc == 7 || (prevCC == 27 && cc == 92) )) // 27, 92 => "\e\\" (ST, String Terminator) #define ces(C) (cc < 256 && (charClass[cc] & (C)) == (C) && !Xte) -#define ESC 27 #define CNTL(c) ((c)-'@') +#define ESC 27 +#define DEL 127 // process an incoming unicode character -void Vt102Emulation::receiveChar(int cc) +void Vt102Emulation::receiveChar(wchar_t cc) { - if (cc == 127) + if (cc == DEL) return; //VT100: ignore. if (ces(CTL)) { + // ignore control characters in the text part of Xpe (aka OSC) "ESC]" + // escape sequences; this matches what XTERM docs say + if (Xpe) { + prevCC = cc; + return; + } + // DEC HACK ALERT! Control Characters are allowed *within* esc sequences in VT100 // This means, they do neither a resetTokenizer() nor a pushToToken(). Some of them, do // of course. Guess this originates from a weakly layered handling of the X-on @@ -297,7 +309,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)) @@ -306,7 +318,7 @@ void Vt102Emulation::receiveChar(int cc) if (lec(1,0,ESC+128)) { s[0] = ESC; receiveChar('['); return; } if (les(2,1,GRP)) { return; } if (Xte ) { processWindowAttributeChange(); resetTokenizer(); return; } - if (Xpe ) { return; } + if (Xpe ) { prevCC = cc; return; } if (lec(3,2,'?')) { return; } if (lec(3,2,'>')) { return; } if (lec(3,2,'!')) { return; } @@ -315,6 +327,12 @@ void Vt102Emulation::receiveChar(int cc) if (les(3,1,SCS)) { processToken( TY_ESC_CS(s[1],s[2]), 0, 0); resetTokenizer(); return; } if (lec(3,1,'#')) { processToken( TY_ESC_DE(s[2]), 0, 0); resetTokenizer(); return; } if (eps( CPN)) { processToken( TY_CSI_PN(cc), argv[0],argv[1]); resetTokenizer(); return; } + if (esp( )) { return; } + if (lec(5, 4, 'q') && s[3] == ' ') { + processToken( TY_CSI_PS_SP(cc, argv[0]), argv[0], 0); + resetTokenizer(); + return; + } // resize = \e[8;;t if (eps(CPS)) @@ -364,8 +382,10 @@ void Vt102Emulation::receiveChar(int cc) } if (lec(2,1,'Y')) return; + if (lec(3,1,'Y')) return; + if (p < 4) { processToken( TY_VT52(s[1] ), 0, 0); @@ -433,7 +453,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) { @@ -532,7 +552,9 @@ void Vt102Emulation::processToken(int token, int p, int q) case TY_ESC_DE('8' ) : _currentScreen->helpAlign ( ); break; // resize = \e[8;;t - case TY_CSI_PS('t', 8) : setImageSize( q /* columns */, p /* lines */ ); break; + case TY_CSI_PS('t', 8) : setImageSize( p /*lines */, q /* columns */ ); + emit imageResizeRequest(QSize(q, p)); + break; // change tab text color : \e[28;t color: 0-16,777,215 case TY_CSI_PS('t', 28) : emit changeTabTextColorRequest ( p ); break; @@ -556,16 +578,27 @@ void Vt102Emulation::processToken(int token, int p, int q) case TY_CSI_PS('m', 0) : _currentScreen->setDefaultRendition ( ); break; case TY_CSI_PS('m', 1) : _currentScreen-> setRendition (RE_BOLD ); break; //VT100 + case TY_CSI_PS('m', 2) : _currentScreen-> setRendition (RE_FAINT ); break; + case TY_CSI_PS('m', 3) : _currentScreen-> setRendition (RE_ITALIC ); break; //VT100 case TY_CSI_PS('m', 4) : _currentScreen-> setRendition (RE_UNDERLINE); break; //VT100 case TY_CSI_PS('m', 5) : _currentScreen-> setRendition (RE_BLINK ); break; //VT100 case TY_CSI_PS('m', 7) : _currentScreen-> setRendition (RE_REVERSE ); break; + case TY_CSI_PS('m', 8) : _currentScreen-> setRendition (RE_CONCEAL ); break; + case TY_CSI_PS('m', 9) : _currentScreen-> setRendition (RE_STRIKEOUT); break; + case TY_CSI_PS('m', 53) : _currentScreen-> setRendition (RE_OVERLINE ); break; case TY_CSI_PS('m', 10) : /* IGNORED: mapping related */ break; //LINUX case TY_CSI_PS('m', 11) : /* IGNORED: mapping related */ break; //LINUX case TY_CSI_PS('m', 12) : /* IGNORED: mapping related */ break; //LINUX - case TY_CSI_PS('m', 22) : _currentScreen->resetRendition (RE_BOLD ); break; + case TY_CSI_PS('m', 21) : _currentScreen->resetRendition (RE_BOLD ); break; + case TY_CSI_PS('m', 22) : _currentScreen->resetRendition (RE_BOLD ); + _currentScreen->resetRendition (RE_FAINT ); break; + case TY_CSI_PS('m', 23) : _currentScreen->resetRendition (RE_ITALIC ); break; //VT100 case TY_CSI_PS('m', 24) : _currentScreen->resetRendition (RE_UNDERLINE); break; case TY_CSI_PS('m', 25) : _currentScreen->resetRendition (RE_BLINK ); break; case TY_CSI_PS('m', 27) : _currentScreen->resetRendition (RE_REVERSE ); break; + case TY_CSI_PS('m', 28) : _currentScreen->resetRendition (RE_CONCEAL ); break; + case TY_CSI_PS('m', 29) : _currentScreen->resetRendition (RE_STRIKEOUT); break; + case TY_CSI_PS('m', 55) : _currentScreen->resetRendition (RE_OVERLINE ); break; case TY_CSI_PS('m', 30) : _currentScreen->setForeColor (COLOR_SPACE_SYSTEM, 0); break; case TY_CSI_PS('m', 31) : _currentScreen->setForeColor (COLOR_SPACE_SYSTEM, 1); break; @@ -621,11 +654,21 @@ void Vt102Emulation::processToken(int token, int p, int q) case TY_CSI_PS('x', 0) : reportTerminalParms ( 2); break; //VT100 case TY_CSI_PS('x', 1) : reportTerminalParms ( 3); break; //VT100 + case TY_CSI_PS_SP('q', 0) : /* fall through */ + case TY_CSI_PS_SP('q', 1) : emit cursorChanged(KeyboardCursorShape::BlockCursor, true ); break; + case TY_CSI_PS_SP('q', 2) : emit cursorChanged(KeyboardCursorShape::BlockCursor, false); break; + case TY_CSI_PS_SP('q', 3) : emit cursorChanged(KeyboardCursorShape::UnderlineCursor, true ); break; + case TY_CSI_PS_SP('q', 4) : emit cursorChanged(KeyboardCursorShape::UnderlineCursor, false); break; + case TY_CSI_PS_SP('q', 5) : emit cursorChanged(KeyboardCursorShape::IBeamCursor, true ); break; + case TY_CSI_PS_SP('q', 6) : emit cursorChanged(KeyboardCursorShape::IBeamCursor, false); break; + case TY_CSI_PN('@' ) : _currentScreen->insertChars (p ); break; case TY_CSI_PN('A' ) : _currentScreen->cursorUp (p ); break; //VT100 case TY_CSI_PN('B' ) : _currentScreen->cursorDown (p ); break; //VT100 case TY_CSI_PN('C' ) : _currentScreen->cursorRight (p ); break; //VT100 case TY_CSI_PN('D' ) : _currentScreen->cursorLeft (p ); break; //VT100 + case TY_CSI_PN('E' ) : /* Not implemented: cursor next p lines */ break; //VT100 + case TY_CSI_PN('F' ) : /* Not implemented: cursor preceding p lines */ break; //VT100 case TY_CSI_PN('G' ) : _currentScreen->setCursorX (p ); break; //LINUX case TY_CSI_PN('H' ) : _currentScreen->setCursorYX (p, q); break; //VT100 case TY_CSI_PN('I' ) : _currentScreen->tab (p ); break; @@ -636,6 +679,7 @@ void Vt102Emulation::processToken(int token, int p, int q) case TY_CSI_PN('T' ) : _currentScreen->scrollDown (p ); break; case TY_CSI_PN('X' ) : _currentScreen->eraseChars (p ); break; case TY_CSI_PN('Z' ) : _currentScreen->backtab (p ); break; + case TY_CSI_PN('b' ) : _currentScreen->repeatChars (p ); break; case TY_CSI_PN('c' ) : reportTerminalType ( ); break; //VT100 case TY_CSI_PN('d' ) : _currentScreen->setCursorY (p ); break; //LINUX case TY_CSI_PN('f' ) : _currentScreen->setCursorYX (p, q); break; //VT100 @@ -740,6 +784,24 @@ void Vt102Emulation::processToken(int token, int p, int q) case TY_CSI_PR('s', 1003) : saveMode (MODE_Mouse1003); break; //XTERM case TY_CSI_PR('r', 1003) : restoreMode (MODE_Mouse1003); break; //XTERM + case TY_CSI_PR('h', 1004) : _reportFocusEvents = true; break; + case TY_CSI_PR('l', 1004) : _reportFocusEvents = false; break; + + case TY_CSI_PR('h', 1005) : setMode (MODE_Mouse1005); break; //XTERM + case TY_CSI_PR('l', 1005) : resetMode (MODE_Mouse1005); break; //XTERM + case TY_CSI_PR('s', 1005) : saveMode (MODE_Mouse1005); break; //XTERM + case TY_CSI_PR('r', 1005) : restoreMode (MODE_Mouse1005); break; //XTERM + + case TY_CSI_PR('h', 1006) : setMode (MODE_Mouse1006); break; //XTERM + case TY_CSI_PR('l', 1006) : resetMode (MODE_Mouse1006); break; //XTERM + case TY_CSI_PR('s', 1006) : saveMode (MODE_Mouse1006); break; //XTERM + case TY_CSI_PR('r', 1006) : restoreMode (MODE_Mouse1006); break; //XTERM + + case TY_CSI_PR('h', 1015) : setMode (MODE_Mouse1015); break; //URXVT + case TY_CSI_PR('l', 1015) : resetMode (MODE_Mouse1015); break; //URXVT + case TY_CSI_PR('s', 1015) : saveMode (MODE_Mouse1015); break; //URXVT + case TY_CSI_PR('r', 1015) : restoreMode (MODE_Mouse1015); break; //URXVT + case TY_CSI_PR('h', 1034) : /* IGNORED: 8bitinput activation */ break; //XTERM case TY_CSI_PR('h', 1047) : setMode (MODE_AppScreen); break; //XTERM @@ -758,6 +820,11 @@ void Vt102Emulation::processToken(int token, int p, int q) case TY_CSI_PR('h', 1049) : saveCursor(); _screen[1]->clearEntireScreen(); setMode(MODE_AppScreen); break; //XTERM case TY_CSI_PR('l', 1049) : resetMode(MODE_AppScreen); restoreCursor(); break; //XTERM + case TY_CSI_PR('h', 2004) : setMode (MODE_BracketedPaste); break; //XTERM + case TY_CSI_PR('l', 2004) : resetMode (MODE_BracketedPaste); break; //XTERM + case TY_CSI_PR('s', 2004) : saveMode (MODE_BracketedPaste); break; //XTERM + case TY_CSI_PR('r', 2004) : restoreMode (MODE_BracketedPaste); break; //XTERM + //FIXME: weird DEC reset sequence case TY_CSI_PE('p' ) : /* IGNORED: reset ( ) */ break; @@ -857,33 +924,85 @@ void Vt102Emulation::reportAnswerBack() /*! `cx',`cy' are 1-based. - `eventType' indicates the button pressed (0-2) - or a general mouse release (3). + `cb' indicates the button pressed or released (0-2) or scroll event (4-5). eventType represents the kind of mouse action that occurred: - 0 = Mouse button press or release + 0 = Mouse button press 1 = Mouse drag + 2 = Mouse button release */ void Vt102Emulation::sendMouseEvent( int cb, int cx, int cy , int eventType ) { - if (cx < 1 || cy < 1) - return; + if (cx < 1 || cy < 1) + return; - // normal buttons are passed as 0x20 + button, - // mouse wheel (buttons 4,5) as 0x5c + button - if (cb >= 4) - cb += 0x3c; + // 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; - //Mouse motion handling - if ((getMode(MODE_Mouse1002) || getMode(MODE_Mouse1003)) && eventType == 1) + // 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 - char command[20]; - sprintf(command,"\033[M%c%c%c",cb+0x20,cx+0x20,cy+0x20); + char command[32]; + command[0] = '\0'; + // Check the extensions in decreasing order of preference. Encoding the release event above assumes that 1006 comes first. + if (getMode(MODE_Mouse1006)) { + snprintf(command, sizeof(command), "\033[<%d;%d;%d%c", cb, cx, cy, eventType == 2 ? 'm' : 'M'); + } else if (getMode(MODE_Mouse1015)) { + snprintf(command, sizeof(command), "\033[%d;%d;%dM", cb + 0x20, cx, cy); + } else if (getMode(MODE_Mouse1005)) { + if (cx <= 2015 && cy <= 2015) { + // The xterm extension uses UTF-8 (up to 2 bytes) to encode + // coordinate+32, no matter what the locale is. We could easily + // convert manually, but QString can also do it for us. + QChar coords[2]; + coords[0] = cx + 0x20; + coords[1] = cy + 0x20; + QString coordsStr = QString(coords, 2); + QByteArray utf8 = coordsStr.toUtf8(); + snprintf(command, sizeof(command), "\033[M%c%s", cb + 0x20, utf8.constData()); + } + } else if (cx <= 223 && cy <= 223) { + snprintf(command, sizeof(command), "\033[M%c%c%c", cb + 0x20, cx + 0x20, cy + 0x20); + } + sendString(command); } +/** + * The focus lost event can be used by Vim (or other terminal applications) + * to recognize that the konsole window has lost focus. + * The escape sequence is also used by iTerm2. + * Vim needs the following plugin to be installed to convert the escape + * sequence into the FocusLost autocmd: https://github.com/sjl/vitality.vim + */ +void Vt102Emulation::focusLost(void) +{ + if (_reportFocusEvents) + sendString("\033[O"); +} + +/** + * The focus gained event can be used by Vim (or other terminal applications) + * to recognize that the konsole window has gained focus again. + * The escape sequence is also used by iTerm2. + * Vim needs the following plugin to be installed to convert the escape + * sequence into the FocusGained autocmd: https://github.com/sjl/vitality.vim + */ +void Vt102Emulation::focusGained(void) +{ + if (_reportFocusEvents) + sendString("\033[I"); +} + void Vt102Emulation::sendText( const QString& text ) { if (!text.isEmpty()) @@ -1060,11 +1179,15 @@ void Vt102Emulation::sendKeyEvent( QKeyEvent* origEvent ) // check flow control state if (modifiers & Qt::ControlModifier) { - qDebug("0x%x", event->key()); - if (event->key() == Qt::Key_S) + switch (event->key()) { + case Qt::Key_S: emit flowControlKeyPressed(true); - else if (event->key() == Qt::Key_Q) + break; + case Qt::Key_Q: + case Qt::Key_C: // cancel flow control emit flowControlKeyPressed(false); + break; + } } // lookup key binding @@ -1084,6 +1207,7 @@ void Vt102Emulation::sendKeyEvent( QKeyEvent* origEvent ) // in the keyboard modifier) bool wantsAltModifier = entry.modifiers() & entry.modifierMask() & Qt::AltModifier; + bool wantsMetaModifier = entry.modifiers() & entry.modifierMask() & Qt::MetaModifier; bool wantsAnyModifier = entry.state() & entry.stateMask() & KeyboardTranslator::AnyModifierState; @@ -1092,6 +1216,11 @@ void Vt102Emulation::sendKeyEvent( QKeyEvent* origEvent ) { textToSend.prepend("\033"); } + if ( modifiers & Qt::MetaModifier && !(wantsMetaModifier || wantsAnyModifier) + && !event->text().isEmpty() ) + { + textToSend.prepend("\030@s"); + } if ( entry.command() != KeyboardTranslator::NoCommand ) { @@ -1102,7 +1231,7 @@ void Vt102Emulation::sendKeyEvent( QKeyEvent* origEvent ) } else if ( !entry.text().isEmpty() ) { - textToSend += entry.text(true,modifiers); + textToSend += _codec->fromUnicode(QString::fromUtf8(entry.text(true,modifiers))); } else if((modifiers & Qt::ControlModifier) && event->key() >= 0x40 && event->key() < 0x5f) { textToSend += (event->key() & 0x1f); @@ -1163,7 +1292,7 @@ void Vt102Emulation::sendKeyEvent( QKeyEvent* origEvent ) // 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 @@ -1181,7 +1310,7 @@ unsigned short Vt102Emulation::applyCharset(unsigned short c) void Vt102Emulation::resetCharset(int scrno) { _charset[scrno].cu_cs = 0; - strncpy(_charset[scrno].charset,"BBBB",4); + qstrncpy(_charset[scrno].charset,"BBBB",4); _charset[scrno].sa_graphic = false; _charset[scrno].sa_pound = false; _charset[scrno].graphic = false; @@ -1266,6 +1395,10 @@ void Vt102Emulation::resetModes() resetMode(MODE_Mouse1001); saveMode(MODE_Mouse1001); resetMode(MODE_Mouse1002); saveMode(MODE_Mouse1002); resetMode(MODE_Mouse1003); saveMode(MODE_Mouse1003); + resetMode(MODE_Mouse1005); saveMode(MODE_Mouse1005); + resetMode(MODE_Mouse1006); saveMode(MODE_Mouse1006); + resetMode(MODE_Mouse1015); saveMode(MODE_Mouse1015); + resetMode(MODE_BracketedPaste); saveMode(MODE_BracketedPaste); resetMode(MODE_AppScreen); saveMode(MODE_AppScreen); resetMode(MODE_AppCuKeys); saveMode(MODE_AppCuKeys); @@ -1289,7 +1422,12 @@ void Vt102Emulation::setMode(int m) case MODE_Mouse1001: case MODE_Mouse1002: case MODE_Mouse1003: - emit programUsesMouseChanged(false); + emit programUsesMouseChanged(false); + break; + + case MODE_BracketedPaste: + emit programBracketedPasteModeChanged(true); + break; case MODE_AppScreen : _screen[1]->clearSelection(); @@ -1319,6 +1457,10 @@ void Vt102Emulation::resetMode(int m) emit programUsesMouseChanged(true); break; + case MODE_BracketedPaste: + emit programBracketedPasteModeChanged(false); + break; + case MODE_AppScreen : _screen[0]->clearSelection(); setScreen(0); @@ -1356,13 +1498,13 @@ char Vt102Emulation::eraseChar() const 0, 0); if ( entry.text().count() > 0 ) - return entry.text()[0]; + return entry.text().at(0); else return '\b'; } // 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 8010f35..dacaa1d 100644 --- a/lib/Vt102Emulation.h +++ b/lib/Vt102Emulation.h @@ -1,6 +1,6 @@ /* This file is part of Konsole, an X terminal. - + Copyright 2007-2008 by Robert Knight Copyright 1997,1998 by Lars Doelle @@ -26,7 +26,7 @@ // Standard Library #include -// Qt +// Qt #include #include #include @@ -37,15 +37,19 @@ #define MODE_AppScreen (MODES_SCREEN+0) // Mode #1 #define MODE_AppCuKeys (MODES_SCREEN+1) // Application cursor keys (DECCKM) -#define MODE_AppKeyPad (MODES_SCREEN+2) // +#define MODE_AppKeyPad (MODES_SCREEN+2) // #define MODE_Mouse1000 (MODES_SCREEN+3) // Send mouse X,Y position on press and release #define MODE_Mouse1001 (MODES_SCREEN+4) // Use Hilight mouse tracking #define MODE_Mouse1002 (MODES_SCREEN+5) // Use cell motion mouse tracking -#define MODE_Mouse1003 (MODES_SCREEN+6) // Use all motion mouse tracking -#define MODE_Ansi (MODES_SCREEN+7) // Use US Ascii for character sets G0-G3 (DECANM) -#define MODE_132Columns (MODES_SCREEN+8) // 80 <-> 132 column mode switch (DECCOLM) -#define MODE_Allow132Columns (MODES_SCREEN+9) // Allow DECCOLM mode -#define MODE_total (MODES_SCREEN+10) +#define MODE_Mouse1003 (MODES_SCREEN+6) // Use all motion mouse tracking +#define MODE_Mouse1005 (MODES_SCREEN+7) // Xterm-style extended coordinates +#define MODE_Mouse1006 (MODES_SCREEN+8) // 2nd Xterm-style extended coordinates +#define MODE_Mouse1015 (MODES_SCREEN+9) // Urxvt-style extended coordinates +#define MODE_Ansi (MODES_SCREEN+10) // Use US Ascii for character sets G0-G3 (DECANM) +#define MODE_132Columns (MODES_SCREEN+11) // 80 <-> 132 column mode switch (DECCOLM) +#define MODE_Allow132Columns (MODES_SCREEN+12) // Allow DECCOLM mode +#define MODE_BracketedPaste (MODES_SCREEN+13) // Xterm-style bracketed paste mode +#define MODE_total (MODES_SCREEN+14) namespace Konsole { @@ -64,47 +68,49 @@ struct CharCodes /** * Provides an xterm compatible terminal emulation based on the DEC VT102 terminal. * A full description of this terminal can be found at http://vt100.net/docs/vt102-ug/ - * - * In addition, various additional xterm escape sequences are supported to provide + * + * In addition, various additional xterm escape sequences are supported to provide * features such as mouse input handling. * See http://rtfm.etla.org/xterm/ctlseq.html for a description of xterm's escape - * sequences. + * sequences. * */ class Vt102Emulation : public Emulation -{ +{ Q_OBJECT public: /** Constructs a new emulation */ Vt102Emulation(); ~Vt102Emulation(); - + // reimplemented from Emulation virtual void clearEntireScreen(); virtual void reset(); virtual char eraseChar() const; - -public slots: - // reimplemented from Emulation + +public slots: + // reimplemented from Emulation virtual void sendString(const char*,int length = -1); virtual void sendText(const QString& text); virtual void sendKeyEvent(QKeyEvent*); virtual void sendMouseEvent(int buttons, int column, int line, int eventType); - + virtual void focusLost(); + virtual void focusGained(); + 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 //used to buffer multiple title updates 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); @@ -122,16 +128,16 @@ private: bool getMode (int mode); // saves the current boolean value of 'mode' void saveMode (int mode); - // restores the boolean value of 'mode' + // restores the boolean value of 'mode' void restoreMode(int mode); // resets all modes // (except MODE_Allow132Columns) void resetModes(); void resetTokenizer(); - #define MAX_TOKEN_LENGTH 80 - void addToCurrentToken(int cc); - int tokenBuffer[MAX_TOKEN_LENGTH]; //FIXME: overflow? + #define MAX_TOKEN_LENGTH 256 // Max length of tokens (e.g. window title) + void addToCurrentToken(wchar_t cc); + wchar_t tokenBuffer[MAX_TOKEN_LENGTH]; //FIXME: overflow? int tokenBufferPos; #define MAXARGS 15 void addDigit(int dig); @@ -139,16 +145,18 @@ private: int argv[MAXARGS]; int argc; void initTokenizer(); + int prevCC; // Set of flags for each of the ASCII characters which indicates // what category they fall into (printable character, control, digit etc.) // for the purposes of decoding terminal output int charClass[256]; - void reportDecodingError(); + void reportDecodingError(); - void processToken(int code, int p, int q); + void processToken(int code, wchar_t p, int q); void processWindowAttributeChange(); + void requestWindowAttribute(int); void reportTerminalType(); void reportSecondaryAttributes(); @@ -179,13 +187,15 @@ private: TerminalState _currentModes; TerminalState _savedModes; - //hash table and timer for buffering calls to the session instance + //hash table and timer for buffering calls to the session instance //to update the name of the session //or window title. - //these calls occur when certain escape sequences are seen in the + //these calls occur when certain escape sequences are seen in the //output from the terminal QHash _pendingTitleUpdates; QTimer* _titleUpdateTimer; + + bool _reportFocusEvents; }; } diff --git a/lib/color-schemes/BreezeModified.colorscheme b/lib/color-schemes/BreezeModified.colorscheme new file mode 100644 index 0000000..bb53443 --- /dev/null +++ b/lib/color-schemes/BreezeModified.colorscheme @@ -0,0 +1,95 @@ +[Background] +Color=49,54,59 + +[BackgroundFaint] +Color=49,54,59 + +[BackgroundIntense] +Color=35,38,41 + +[Color0] +Color=7,54,66 + +[Color0Faint] +Color=32,43,54 + +[Color0Intense] +Color=255,85,0 + +[Color1] +Color=237,21,21 + +[Color1Faint] +Color=120,50,40 + +[Color1Intense] +Color=192,57,43 + +[Color2] +Color=17,209,22 + +[Color2Faint] +Color=23,162,98 + +[Color2Intense] +Color=28,220,154 + +[Color3] +Color=246,116,0 + +[Color3Faint] +Color=182,86,25 + +[Color3Intense] +Color=253,188,75 + +[Color4] +Color=29,153,243 + +[Color4Faint] +Color=27,102,143 + +[Color4Intense] +Color=61,174,233 + +[Color5] +Color=155,89,182 + +[Color5Faint] +Color=97,74,115 + +[Color5Intense] +Color=142,68,173 + +[Color6] +Color=26,188,156 + +[Color6Faint] +Color=24,108,96 + +[Color6Intense] +Color=22,160,133 + +[Color7] +Color=239,240,241 + +[Color7Faint] +Color=99,104,109 + +[Color7Intense] +Color=252,252,252 + +[Foreground] +Color=239,240,241 + +[ForegroundFaint] +Color=220,230,231 + +[ForegroundIntense] +Color=252,252,252 + +[General] +Description=BreezeModified +Opacity=0.95 +Wallpaper= + diff --git a/lib/color-schemes/Solarized.colorscheme b/lib/color-schemes/Solarized.colorscheme new file mode 100644 index 0000000..36529dd --- /dev/null +++ b/lib/color-schemes/Solarized.colorscheme @@ -0,0 +1,93 @@ +[Color0] +Color=7,54,66 + +[Color0Intense] +Color=0,43,54 + +[Color0Faint] +Color=6,48,59 + +[Color1] +Color=220,50,47 + +[Color1Intense] +Color=203,75,22 + +[Color1Faint] +Color=147,33,31 + +[Color2] +Color=133,153,0 + +[Color2Intense] +Color=88,110,117 + +[Color2Faint] +Color=94,106,0 + +[Color3] +Color=181,137,0 + +[Color3Intense] +Color=101,123,131 + +[Color3Faint] +Color=138,103,0 + +[Color4] +Color=38,139,210 + +[Color4Intense] +Color=131,148,150 + +[Color4Faint] +Color=20,77,115 + +[Color5] +Color=211,54,130 + +[Color5Intense] +Color=108,113,196 + +[Color5Faint] +Color=120,30,75 + +[Color6] +Color=42,161,152 + +[Color6Intense] +Color=147,161,161 + +[Color6Faint] +Color=24,94,88 + +[Color7] +Color=238,232,213 + +[Color7Intense] +Color=253,246,227 + +[Color7Faint] +Color=171,167,154 + +[Background] +Color=0,43,54 + +[BackgroundIntense] +Color=7,54,66 + +[BackgroundFaint] +Color=0,43,54 + +[Foreground] +Color=131,148,150 + +[ForegroundIntense] +Color=147,161,161 + +[ForegroundFaint] +Color=106,119,121 + +[General] +Description=Solarized +Opacity=1 diff --git a/lib/color-schemes/SolarizedLight.colorscheme b/lib/color-schemes/SolarizedLight.colorscheme new file mode 100644 index 0000000..cd19002 --- /dev/null +++ b/lib/color-schemes/SolarizedLight.colorscheme @@ -0,0 +1,93 @@ +[Color0] +Color=7,54,66 + +[Color0Intense] +Color=0,43,54 + +[Color0Faint] +Color=8,65,80 + +[Color1] +Color=220,50,47 + +[Color1Intense] +Color=203,75,22 + +[Color1Faint] +Color=222,81,81 + +[Color2] +Color=133,153,0 + +[Color2Intense] +Color=88,110,117 + +[Color2Faint] +Color=153,168,39 + +[Color3] +Color=181,137,0 + +[Color3Intense] +Color=101,123,131 + +[Color3Faint] +Color=213,170,49 + +[Color4] +Color=38,139,210 + +[Color4Intense] +Color=131,148,150 + +[Color4Faint] +Color=80,173,226 + +[Color5] +Color=211,54,130 + +[Color5Intense] +Color=108,113,196 + +[Color5Faint] +Color=223,92,158 + +[Color6] +Color=42,161,152 + +[Color6Intense] +Color=147,161,161 + +[Color6Faint] +Color=78,211,200 + +[Color7] +Color=238,232,213 + +[Color7Intense] +Color=253,246,227 + +[Color7Faint] +Color=238,232,213 + +[Background] +Color=253,246,227 + +[BackgroundIntense] +Color=238,232,213 + +[BackgroundFaint] +Color=253,246,227 + +[Foreground] +Color=101,123,131 + +[ForegroundIntense] +Color=88,110,117 + +[ForegroundFaint] +Color=141,172,182 + +[General] +Description=Solarized Light +Opacity=1 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/color-schemes/color-schemes.qrc b/lib/color-schemes/color-schemes.qrc deleted file mode 100644 index a1be0f3..0000000 --- a/lib/color-schemes/color-schemes.qrc +++ /dev/null @@ -1,24 +0,0 @@ - - - BlackOnLightYellow.schema - BlackOnRandomLight.colorscheme - Linux.colorscheme - BlackOnWhite.schema - DarkPastels.colorscheme - GreenOnBlack.colorscheme - WhiteOnBlack.schema - historic/vim.schema - historic/Transparent.schema - historic/Transparent_MC.schema - historic/Linux.schema - historic/Transparent_darkbg.schema - historic/GreenTint.schema - historic/Transparent_lightbg.schema - historic/LightPicture.schema - historic/DarkPicture.schema - historic/syscolor.schema - historic/XTerm.schema - historic/BlackOnLightColor.schema - historic/GreenTint_MC.schema - historic/GreenOnBlack.schema - diff --git a/lib/designer/qtermwidget.png b/lib/designer/qtermwidget.png deleted file mode 100644 index 7b9abcc..0000000 Binary files a/lib/designer/qtermwidget.png and /dev/null differ diff --git a/lib/designer/qtermwidgetplugin.cpp b/lib/designer/qtermwidgetplugin.cpp deleted file mode 100644 index bb9ad91..0000000 --- a/lib/designer/qtermwidgetplugin.cpp +++ /dev/null @@ -1,102 +0,0 @@ - -#include "qtermwidgetplugin.h" - -#include - -#include "qtermwidget.h" - - -QTermWidgetPlugin::QTermWidgetPlugin(QObject *parent) - : QObject(parent), initialized(false) -{ - Q_INIT_RESOURCE(qtermwidgetplugin); -} - - -QTermWidgetPlugin::~QTermWidgetPlugin() -{ -} - - -void QTermWidgetPlugin::initialize(QDesignerFormEditorInterface * /* core */) -{ - initialized = true; -} - - -bool QTermWidgetPlugin::isInitialized() const -{ - return initialized; -} - - -QWidget *QTermWidgetPlugin::createWidget(QWidget *parent) -{ - return new QTermWidget(0, parent); -} - - -QString QTermWidgetPlugin::name() const -{ - return "QTermWidget"; -} - - -QString QTermWidgetPlugin::group() const -{ - return "Input Widgets"; -} - - -QIcon QTermWidgetPlugin::icon() const -{ - return QIcon(":qtermwidget.png"); -} - - -QString QTermWidgetPlugin::toolTip() const -{ - return "QTermWidget component/widget"; -} - - -QString QTermWidgetPlugin::whatsThis() const -{ - return "Qt based terminal emulator"; -} - - -bool QTermWidgetPlugin::isContainer() const -{ - return false; -} - - -QString QTermWidgetPlugin::domXml() const -{ - return "\n" - " \n" - " \n" - " 0\n" - " 0\n" - " 400\n" - " 200\n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - "\n"; -} - - -QString QTermWidgetPlugin::includeFile() const -{ - return "qtermwidget.h"; -} - - -Q_EXPORT_PLUGIN2(QTermWidgetPlugin, QTermWidgetPlugin) diff --git a/lib/designer/qtermwidgetplugin.h b/lib/designer/qtermwidgetplugin.h deleted file mode 100644 index 8a216de..0000000 --- a/lib/designer/qtermwidgetplugin.h +++ /dev/null @@ -1,33 +0,0 @@ - -#ifndef QTERMWIDGETPLUGIN_H -#define QTERMWIDGETPLUGIN_H - -#include - - -class QTermWidgetPlugin : public QObject, public QDesignerCustomWidgetInterface -{ - Q_OBJECT - Q_INTERFACES(QDesignerCustomWidgetInterface) - -public: - QTermWidgetPlugin(QObject *parent = 0); - virtual ~QTermWidgetPlugin(); - - bool isContainer() const; - bool isInitialized() const; - QIcon icon() const; - QString domXml() const; - QString group() const; - QString includeFile() const; - QString name() const; - QString toolTip() const; - QString whatsThis() const; - QWidget *createWidget(QWidget *parent); - void initialize(QDesignerFormEditorInterface *core); - -private: - bool initialized; -}; - -#endif diff --git a/lib/designer/qtermwidgetplugin.qrc b/lib/designer/qtermwidgetplugin.qrc deleted file mode 100644 index fbf222c..0000000 --- a/lib/designer/qtermwidgetplugin.qrc +++ /dev/null @@ -1,6 +0,0 @@ - - - - qtermwidget.png - - diff --git a/lib/kb-layouts/default.keytab b/lib/kb-layouts/default.keytab index aebd8cf..e8eacea 100644 --- a/lib/kb-layouts/default.keytab +++ b/lib/kb-layouts/default.keytab @@ -33,8 +33,13 @@ key Return-Shift+NewLine : "\r\n" key Return+Shift : "\EOM" # Backspace and Delete codes are preserving CTRL-H. +# +# Backspace without CTRL sends '^H'; this matches XTerm behaviour +# BS, hex \x08, \b +key Backspace -Control : "\b" -key Backspace : "\x7f" +# Match xterm behaviour: Backspace sends '^?' when Control is pressed +key Backspace +Control : "\x7f" # Arrow keys in VT52 mode # shift up/down are reserved for scrolling. @@ -62,6 +67,11 @@ key Down -Shift+AnyMod+Ansi : "\E[1;*B" key Right -Shift+AnyMod+Ansi : "\E[1;*C" key Left -Shift+AnyMod+Ansi : "\E[1;*D" +key Up +Shift+AppScreen : "\E[1;*A" +key Down +Shift+AppScreen : "\E[1;*B" +key Left +Shift+AppScreen : "\E[1;*D" +key Right +Shift+AppScreen : "\E[1;*C" + # Keypad keys with NumLock ON # (see "Numeric Keypad" section at http://www.nw.com/nw/WWW/products/wizcon/vt100.html ) # @@ -99,10 +109,10 @@ key End +AppCuKeys+KeyPad : "\EOF" key Home -AppCuKeys+KeyPad : "\E[H" key End -AppCuKeys+KeyPad : "\E[F" -key Insert +KeyPad : "\E[2~" -key Delete +KeyPad : "\E[3~" -key Prior -Shift+KeyPad : "\E[5~" -key Next -Shift+KeyPad : "\E[6~" +key Insert +KeyPad : "\E[2~" +key Delete +KeyPad : "\E[3~" +key PgUp -Shift+KeyPad : "\E[5~" +key PgDown -Shift+KeyPad : "\E[6~" # other grey PC keys @@ -121,10 +131,10 @@ key Delete -AnyMod : "\E[3~" key Insert +AnyMod : "\E[2;*~" key Delete +AnyMod : "\E[3;*~" -key Prior -Shift-AnyMod : "\E[5~" -key Next -Shift-AnyMod : "\E[6~" -key Prior -Shift+AnyMod : "\E[5;*~" -key Next -Shift+AnyMod : "\E[6;*~" +key PgUp -Shift-AnyMod : "\E[5~" +key PgDown -Shift-AnyMod : "\E[6~" +key PgUp -Shift+AnyMod : "\E[5;*~" +key PgDown -Shift+AnyMod : "\E[6;*~" # Function keys key F1 -AnyMod : "\EOP" @@ -160,10 +170,12 @@ key Space +Control : "\x00" # Some keys are used by konsole to cause operations. # The scroll* operations refer to the history buffer. -key Up +Shift-AppScreen : scrollLineUp -key Prior +Shift-AppScreen : scrollPageUp -key Down +Shift-AppScreen : scrollLineDown -key Next +Shift-AppScreen : scrollPageDown +key Up +Shift-AppScreen : scrollLineUp +key PgUp +Shift-AppScreen : scrollPageUp +key Home +Shift-AppScreen : scrollUpToTop +key Down +Shift-AppScreen : scrollLineDown +key PgDown +Shift-AppScreen : scrollPageDown +key End +Shift-AppScreen : scrollDownToBottom key ScrollLock : scrollLock diff --git a/lib/kb-layouts/historic/vt100.keytab b/lib/kb-layouts/historic/vt100.keytab index dec49ba..dc79b5f 100644 --- a/lib/kb-layouts/historic/vt100.keytab +++ b/lib/kb-layouts/historic/vt100.keytab @@ -102,9 +102,9 @@ key F12 : "\E[24~" key Home : "\E[H" key End : "\E[F" -key Prior -Shift : "\E[5~" -key Next -Shift : "\E[6~" -key Insert-Shift : "\E[2~" +key PgUp -Shift : "\E[5~" +key PgDown -Shift : "\E[6~" +key Insert -Shift : "\E[2~" # Keypad-Enter. See comment on Return above. @@ -115,10 +115,10 @@ key Space +Control : "\x00" # some of keys are used by konsole. -key Up +Shift : scrollLineUp -key Prior +Shift : scrollPageUp -key Down +Shift : scrollLineDown -key Next +Shift : scrollPageDown +key Up +Shift : scrollLineUp +key PgUp +Shift : scrollPageUp +key Down +Shift : scrollLineDown +key PgDown +Shift : scrollPageDown key ScrollLock : scrollLock diff --git a/lib/kb-layouts/historic/x11r5.keytab b/lib/kb-layouts/historic/x11r5.keytab index 75ba06e..e17da0d 100644 --- a/lib/kb-layouts/historic/x11r5.keytab +++ b/lib/kb-layouts/historic/x11r5.keytab @@ -36,8 +36,8 @@ key Home : "\E[1~" key Insert-Shift : "\E[2~" key Delete : "\E[3~" key End : "\E[4~" -key Prior -Shift : "\E[5~" -key Next -Shift : "\E[6~" +key PgUp -Shift : "\E[5~" +key PgDown -Shift : "\E[6~" # function keys @@ -61,10 +61,10 @@ key Space +Control : "\x00" # Some keys are used by konsole to cause operations. # The scroll* operations refer to the history buffer. -key Up +Shift : scrollLineUp -key Prior +Shift : scrollPageUp -key Down +Shift : scrollLineDown -key Next +Shift : scrollPageDown +key Up +Shift : scrollLineUp +key PgUp +Shift : scrollPageUp +key Down +Shift : scrollLineDown +key PgDown +Shift : scrollPageDown key ScrollLock : scrollLock diff --git a/lib/kb-layouts/kb-layouts.qrc b/lib/kb-layouts/kb-layouts.qrc deleted file mode 100644 index ce85691..0000000 --- a/lib/kb-layouts/kb-layouts.qrc +++ /dev/null @@ -1,10 +0,0 @@ - - - linux.keytab - solaris.keytab - macbook.keytab - default.keytab - vt420pc.keytab - historic/x11r5.keytab - historic/vt100.keytab - diff --git a/lib/kb-layouts/linux.keytab b/lib/kb-layouts/linux.keytab index 94a39fb..eefed09 100644 --- a/lib/kb-layouts/linux.keytab +++ b/lib/kb-layouts/linux.keytab @@ -108,9 +108,9 @@ key F12 : "\E[24~" key Home : "\E[1~" key End : "\E[4~" -key Prior -Shift : "\E[5~" -key Next -Shift : "\E[6~" -key Insert-Shift : "\E[2~" +key PgUp -Shift : "\E[5~" +key PgDown -Shift : "\E[6~" +key Insert -Shift : "\E[2~" # Keypad-Enter. See comment on Return above. @@ -121,10 +121,10 @@ key Space +Control : "\x00" # some of keys are used by konsole. -key Up +Shift : scrollLineUp -key Prior +Shift : scrollPageUp -key Down +Shift : scrollLineDown -key Next +Shift : scrollPageDown +key Up +Shift : scrollLineUp +key PgUp +Shift : scrollPageUp +key Down +Shift : scrollLineDown +key PgDown +Shift : scrollPageDown key ScrollLock : scrollLock diff --git a/lib/kb-layouts/macbook.keytab b/lib/kb-layouts/macbook.keytab index adbc784..71e61ae 100644 --- a/lib/kb-layouts/macbook.keytab +++ b/lib/kb-layouts/macbook.keytab @@ -99,10 +99,10 @@ key Delete -AnyMod : "\E[3~" key Insert +AnyMod : "\E[2;*~" key Delete +AnyMod : "\E[3;*~" -key Prior -Shift-AnyMod : "\E[5~" -key Next -Shift-AnyMod : "\E[6~" -key Prior -Shift+AnyMod : "\E[5;*~" -key Next -Shift+AnyMod : "\E[6;*~" +key PgUp -Shift-AnyMod : "\E[5~" +key PgDown -Shift-AnyMod : "\E[6~" +key PgUp -Shift+AnyMod : "\E[5;*~" +key PgDown -Shift+AnyMod : "\E[6;*~" # Function keys #key F1 -AnyMod : "\EOP" @@ -160,10 +160,10 @@ key Space +Control : "\x00" # Some keys are used by konsole to cause operations. # The scroll* operations refer to the history buffer. -key Up +Shift-AppScreen : scrollLineUp -key Prior +Shift-AppScreen : scrollPageUp -key Down +Shift-AppScreen : scrollLineDown -key Next +Shift-AppScreen : scrollPageDown +key Up +Shift-AppScreen : scrollLineUp +key PgUp +Shift-AppScreen : scrollPageUp +key Down +Shift-AppScreen : scrollLineDown +key PgDown +Shift-AppScreen : scrollPageDown #key Up +Shift : scrollLineUp #key Prior +Shift : scrollPageUp diff --git a/lib/kb-layouts/solaris.keytab b/lib/kb-layouts/solaris.keytab index 0739edf..30e8b8f 100644 --- a/lib/kb-layouts/solaris.keytab +++ b/lib/kb-layouts/solaris.keytab @@ -72,8 +72,8 @@ key Home : "\E[1~" key Insert-Shift : "\E[2~" key Delete : "\E[3~" key End : "\E[4~" -key Prior -Shift : "\E[5~" -key Next -Shift : "\E[6~" +key PgUp -Shift : "\E[5~" +key PgDown -Shift : "\E[6~" # function keys @@ -99,10 +99,10 @@ key Space +Control : "\x00" #key Left +Shift : prevSession #key Right +Shift : nextSession -key Up +Shift : scrollLineUp -key Prior +Shift : scrollPageUp -key Down +Shift : scrollLineDown -key Next +Shift : scrollPageDown +key Up +Shift : scrollLineUp +key PgUp +Shift : scrollPageUp +key Down +Shift : scrollLineDown +key PgDown +Shift : scrollPageDown #key Insert+Shift : emitSelection # keypad characters are not offered differently by Qt. diff --git a/lib/kb-layouts/vt420pc.keytab b/lib/kb-layouts/vt420pc.keytab index ee6aa9a..7ccb88b 100644 --- a/lib/kb-layouts/vt420pc.keytab +++ b/lib/kb-layouts/vt420pc.keytab @@ -138,9 +138,9 @@ key F12+Shift : "\E[24;2~" key Home : "\E[H" key End : "\E[F" -key Prior -Shift : "\E[5~" -key Next -Shift : "\E[6~" -key Insert-Shift : "\E[2~" +key PgUp -Shift : "\E[5~" +key PgDown -Shift : "\E[6~" +key Insert -Shift : "\E[2~" # Keypad-Enter. See comment on Return above. @@ -151,10 +151,10 @@ key Space +Control : "\x00" # some of keys are used by konsole. -key Up +Shift : scrollLineUp -key Prior +Shift : scrollPageUp -key Down +Shift : scrollLineDown -key Next +Shift : scrollPageDown +key Up +Shift : scrollLineUp +key PgUp +Shift : scrollPageUp +key Down +Shift : scrollLineDown +key PgDown +Shift : scrollPageDown key ScrollLock : scrollLock diff --git a/lib/konsole_wcwidth.cpp b/lib/konsole_wcwidth.cpp index 20162ea..cfb6c07 100644 --- a/lib/konsole_wcwidth.cpp +++ b/lib/konsole_wcwidth.cpp @@ -9,218 +9,35 @@ #include -#include "konsole_wcwidth.h" - -struct interval { - unsigned short first; - unsigned short last; -}; - -/* auxiliary function for binary search in interval table */ -static int bisearch(quint16 ucs, const struct interval * table, int max) -{ - int min = 0; - int mid; - - if (ucs < table[0].first || ucs > table[max].last) { - return 0; - } - while (max >= min) { - mid = (min + max) / 2; - if (ucs > table[mid].last) { - min = mid + 1; - } else if (ucs < table[mid].first) { - max = mid - 1; - } else { - return 1; - } - } - - return 0; -} - - -/* The following functions define the column width of an ISO 10646 - * character as follows: - * - * - The null character (U+0000) has a column width of 0. - * - * - Other C0/C1 control characters and DEL will lead to a return - * value of -1. - * - * - Non-spacing and enclosing combining characters (general - * category code Mn or Me in the Unicode database) have a - * column width of 0. - * - * - Other format characters (general category code Cf in the Unicode - * database) and ZERO WIDTH SPACE (U+200B) have a column width of 0. - * - * - Hangul Jamo medial vowels and final consonants (U+1160-U+11FF) - * have a column width of 0. - * - * - Spacing characters in the East Asian Wide (W) or East Asian - * FullWidth (F) category as defined in Unicode Technical - * Report #11 have a column width of 2. - * - * - All remaining characters (including all printable - * ISO 8859-1 and WGL4 characters, Unicode control characters, - * etc.) have a column width of 1. - * - * This implementation assumes that quint16 characters are encoded - * in ISO 10646. - */ - -int konsole_wcwidth(quint16 ucs) -{ - /* sorted list of non-overlapping intervals of non-spacing characters */ - static const struct interval combining[] = { - { 0x0300, 0x034E }, { 0x0360, 0x0362 }, { 0x0483, 0x0486 }, - { 0x0488, 0x0489 }, { 0x0591, 0x05A1 }, { 0x05A3, 0x05B9 }, - { 0x05BB, 0x05BD }, { 0x05BF, 0x05BF }, { 0x05C1, 0x05C2 }, - { 0x05C4, 0x05C4 }, { 0x064B, 0x0655 }, { 0x0670, 0x0670 }, - { 0x06D6, 0x06E4 }, { 0x06E7, 0x06E8 }, { 0x06EA, 0x06ED }, - { 0x070F, 0x070F }, { 0x0711, 0x0711 }, { 0x0730, 0x074A }, - { 0x07A6, 0x07B0 }, { 0x0901, 0x0902 }, { 0x093C, 0x093C }, - { 0x0941, 0x0948 }, { 0x094D, 0x094D }, { 0x0951, 0x0954 }, - { 0x0962, 0x0963 }, { 0x0981, 0x0981 }, { 0x09BC, 0x09BC }, - { 0x09C1, 0x09C4 }, { 0x09CD, 0x09CD }, { 0x09E2, 0x09E3 }, - { 0x0A02, 0x0A02 }, { 0x0A3C, 0x0A3C }, { 0x0A41, 0x0A42 }, - { 0x0A47, 0x0A48 }, { 0x0A4B, 0x0A4D }, { 0x0A70, 0x0A71 }, - { 0x0A81, 0x0A82 }, { 0x0ABC, 0x0ABC }, { 0x0AC1, 0x0AC5 }, - { 0x0AC7, 0x0AC8 }, { 0x0ACD, 0x0ACD }, { 0x0B01, 0x0B01 }, - { 0x0B3C, 0x0B3C }, { 0x0B3F, 0x0B3F }, { 0x0B41, 0x0B43 }, - { 0x0B4D, 0x0B4D }, { 0x0B56, 0x0B56 }, { 0x0B82, 0x0B82 }, - { 0x0BC0, 0x0BC0 }, { 0x0BCD, 0x0BCD }, { 0x0C3E, 0x0C40 }, - { 0x0C46, 0x0C48 }, { 0x0C4A, 0x0C4D }, { 0x0C55, 0x0C56 }, - { 0x0CBF, 0x0CBF }, { 0x0CC6, 0x0CC6 }, { 0x0CCC, 0x0CCD }, - { 0x0D41, 0x0D43 }, { 0x0D4D, 0x0D4D }, { 0x0DCA, 0x0DCA }, - { 0x0DD2, 0x0DD4 }, { 0x0DD6, 0x0DD6 }, { 0x0E31, 0x0E31 }, - { 0x0E34, 0x0E3A }, { 0x0E47, 0x0E4E }, { 0x0EB1, 0x0EB1 }, - { 0x0EB4, 0x0EB9 }, { 0x0EBB, 0x0EBC }, { 0x0EC8, 0x0ECD }, - { 0x0F18, 0x0F19 }, { 0x0F35, 0x0F35 }, { 0x0F37, 0x0F37 }, - { 0x0F39, 0x0F39 }, { 0x0F71, 0x0F7E }, { 0x0F80, 0x0F84 }, - { 0x0F86, 0x0F87 }, { 0x0F90, 0x0F97 }, { 0x0F99, 0x0FBC }, - { 0x0FC6, 0x0FC6 }, { 0x102D, 0x1030 }, { 0x1032, 0x1032 }, - { 0x1036, 0x1037 }, { 0x1039, 0x1039 }, { 0x1058, 0x1059 }, - { 0x1160, 0x11FF }, { 0x17B7, 0x17BD }, { 0x17C6, 0x17C6 }, - { 0x17C9, 0x17D3 }, { 0x180B, 0x180E }, { 0x18A9, 0x18A9 }, - { 0x200B, 0x200F }, { 0x202A, 0x202E }, { 0x206A, 0x206F }, - { 0x20D0, 0x20E3 }, { 0x302A, 0x302F }, { 0x3099, 0x309A }, - { 0xFB1E, 0xFB1E }, { 0xFE20, 0xFE23 }, { 0xFEFF, 0xFEFF }, - { 0xFFF9, 0xFFFB } - }; - - /* test for 8-bit control characters */ - if (ucs == 0) { - return 0; - } - if (ucs < 32 || (ucs >= 0x7f && ucs < 0xa0)) { - return -1; - } - - /* binary search in table of non-spacing characters */ - if (bisearch(ucs, combining, - sizeof(combining) / sizeof(struct interval) - 1)) { - return 0; - } - - /* if we arrive here, ucs is not a combining or C0/C1 control character */ - - return 1 + - (ucs >= 0x1100 && - (ucs <= 0x115f || /* Hangul Jamo init. consonants */ - (ucs >= 0x2e80 && ucs <= 0xa4cf && (ucs & ~0x0011) != 0x300a && - ucs != 0x303f) || /* CJK ... Yi */ - (ucs >= 0xac00 && ucs <= 0xd7a3) || /* Hangul Syllables */ - (ucs >= 0xf900 && ucs <= 0xfaff) || /* CJK Compatibility Ideographs */ - (ucs >= 0xfe30 && ucs <= 0xfe6f) || /* CJK Compatibility Forms */ - (ucs >= 0xff00 && ucs <= 0xff5f) || /* Fullwidth Forms */ - (ucs >= 0xffe0 && ucs <= 0xffe6) /* do not compare UINT16 with 0x20000 || - (ucs >= 0x20000 && ucs <= 0x2ffff) */)); -} - -#if 0 -/* - * The following function is the same as konsole_wcwidth(), except that - * spacing characters in the East Asian Ambiguous (A) category as - * defined in Unicode Technical Report #11 have a column width of 2. - * This experimental variant might be useful for users of CJK legacy - * encodings who want to migrate to UCS. It is not otherwise - * recommended for general use. - */ -int konsole_wcwidth_cjk(quint16 ucs) -{ - /* sorted list of non-overlapping intervals of East Asian Ambiguous - * characters */ - static const struct interval ambiguous[] = { - { 0x00A1, 0x00A1 }, { 0x00A4, 0x00A4 }, { 0x00A7, 0x00A8 }, - { 0x00AA, 0x00AA }, { 0x00AD, 0x00AD }, { 0x00B0, 0x00B4 }, - { 0x00B6, 0x00BA }, { 0x00BC, 0x00BF }, { 0x00C6, 0x00C6 }, - { 0x00D0, 0x00D0 }, { 0x00D7, 0x00D8 }, { 0x00DE, 0x00E1 }, - { 0x00E6, 0x00E6 }, { 0x00E8, 0x00EA }, { 0x00EC, 0x00ED }, - { 0x00F0, 0x00F0 }, { 0x00F2, 0x00F3 }, { 0x00F7, 0x00FA }, - { 0x00FC, 0x00FC }, { 0x00FE, 0x00FE }, { 0x0101, 0x0101 }, - { 0x0111, 0x0111 }, { 0x0113, 0x0113 }, { 0x011B, 0x011B }, - { 0x0126, 0x0127 }, { 0x012B, 0x012B }, { 0x0131, 0x0133 }, - { 0x0138, 0x0138 }, { 0x013F, 0x0142 }, { 0x0144, 0x0144 }, - { 0x0148, 0x014A }, { 0x014D, 0x014D }, { 0x0152, 0x0153 }, - { 0x0166, 0x0167 }, { 0x016B, 0x016B }, { 0x01CE, 0x01CE }, - { 0x01D0, 0x01D0 }, { 0x01D2, 0x01D2 }, { 0x01D4, 0x01D4 }, - { 0x01D6, 0x01D6 }, { 0x01D8, 0x01D8 }, { 0x01DA, 0x01DA }, - { 0x01DC, 0x01DC }, { 0x0251, 0x0251 }, { 0x0261, 0x0261 }, - { 0x02C7, 0x02C7 }, { 0x02C9, 0x02CB }, { 0x02CD, 0x02CD }, - { 0x02D0, 0x02D0 }, { 0x02D8, 0x02DB }, { 0x02DD, 0x02DD }, - { 0x0391, 0x03A1 }, { 0x03A3, 0x03A9 }, { 0x03B1, 0x03C1 }, - { 0x03C3, 0x03C9 }, { 0x0401, 0x0401 }, { 0x0410, 0x044F }, - { 0x0451, 0x0451 }, { 0x2010, 0x2010 }, { 0x2013, 0x2016 }, - { 0x2018, 0x2019 }, { 0x201C, 0x201D }, { 0x2020, 0x2021 }, - { 0x2025, 0x2027 }, { 0x2030, 0x2030 }, { 0x2032, 0x2033 }, - { 0x2035, 0x2035 }, { 0x203B, 0x203B }, { 0x2074, 0x2074 }, - { 0x207F, 0x207F }, { 0x2081, 0x2084 }, { 0x20AC, 0x20AC }, - { 0x2103, 0x2103 }, { 0x2105, 0x2105 }, { 0x2109, 0x2109 }, - { 0x2113, 0x2113 }, { 0x2121, 0x2122 }, { 0x2126, 0x2126 }, - { 0x212B, 0x212B }, { 0x2154, 0x2155 }, { 0x215B, 0x215B }, - { 0x215E, 0x215E }, { 0x2160, 0x216B }, { 0x2170, 0x2179 }, - { 0x2190, 0x2199 }, { 0x21D2, 0x21D2 }, { 0x21D4, 0x21D4 }, - { 0x2200, 0x2200 }, { 0x2202, 0x2203 }, { 0x2207, 0x2208 }, - { 0x220B, 0x220B }, { 0x220F, 0x220F }, { 0x2211, 0x2211 }, - { 0x2215, 0x2215 }, { 0x221A, 0x221A }, { 0x221D, 0x2220 }, - { 0x2223, 0x2223 }, { 0x2225, 0x2225 }, { 0x2227, 0x222C }, - { 0x222E, 0x222E }, { 0x2234, 0x2237 }, { 0x223C, 0x223D }, - { 0x2248, 0x2248 }, { 0x224C, 0x224C }, { 0x2252, 0x2252 }, - { 0x2260, 0x2261 }, { 0x2264, 0x2267 }, { 0x226A, 0x226B }, - { 0x226E, 0x226F }, { 0x2282, 0x2283 }, { 0x2286, 0x2287 }, - { 0x2295, 0x2295 }, { 0x2299, 0x2299 }, { 0x22A5, 0x22A5 }, - { 0x22BF, 0x22BF }, { 0x2312, 0x2312 }, { 0x2460, 0x24BF }, - { 0x24D0, 0x24E9 }, { 0x2500, 0x254B }, { 0x2550, 0x2574 }, - { 0x2580, 0x258F }, { 0x2592, 0x2595 }, { 0x25A0, 0x25A1 }, - { 0x25A3, 0x25A9 }, { 0x25B2, 0x25B3 }, { 0x25B6, 0x25B7 }, - { 0x25BC, 0x25BD }, { 0x25C0, 0x25C1 }, { 0x25C6, 0x25C8 }, - { 0x25CB, 0x25CB }, { 0x25CE, 0x25D1 }, { 0x25E2, 0x25E5 }, - { 0x25EF, 0x25EF }, { 0x2605, 0x2606 }, { 0x2609, 0x2609 }, - { 0x260E, 0x260F }, { 0x261C, 0x261C }, { 0x261E, 0x261E }, - { 0x2640, 0x2640 }, { 0x2642, 0x2642 }, { 0x2660, 0x2661 }, - { 0x2663, 0x2665 }, { 0x2667, 0x266A }, { 0x266C, 0x266D }, - { 0x266F, 0x266F }, { 0x300A, 0x300B }, { 0x301A, 0x301B }, - { 0xE000, 0xF8FF }, { 0xFFFD, 0xFFFD } - }; - - /* binary search in table of non-spacing characters */ - if (bisearch(ucs, ambiguous, - sizeof(ambiguous) / sizeof(struct interval) - 1)) { - return 2; - } - - return konsole_wcwidth(ucs); -} +#ifdef HAVE_UTF8PROC +#include +#else +#include #endif +#include "konsole_wcwidth.h" + +int konsole_wcwidth(wchar_t ucs) +{ +#ifdef HAVE_UTF8PROC + utf8proc_category_t cat = utf8proc_category( ucs ); + if (cat == UTF8PROC_CATEGORY_CO) { + // Co: Private use area. libutf8proc makes them zero width, while tmux + // assumes them to be width 1, and glibc's default width is also 1 + return 1; + } + return utf8proc_charwidth( ucs ); +#else + return wcwidth( ucs ); +#endif +} + // single byte char: +1, multi byte char: +2 -int string_width( const QString & txt ) +int string_width( const std::wstring & wstr ) { int w = 0; - for ( int i = 0; i < txt.length(); ++i ) { - w += konsole_wcwidth( txt[ i ].unicode() ); + for ( size_t i = 0; i < wstr.length(); ++i ) { + w += konsole_wcwidth( wstr[ i ] ); } return w; } diff --git a/lib/konsole_wcwidth.h b/lib/konsole_wcwidth.h index 30f30ef..32aa882 100644 --- a/lib/konsole_wcwidth.h +++ b/lib/konsole_wcwidth.h @@ -10,16 +10,11 @@ #ifndef _KONSOLE_WCWIDTH_H_ #define _KONSOLE_WCWIDTH_H_ -// Qt -#include +// Standard +#include -class QString; +int konsole_wcwidth(wchar_t ucs); -int konsole_wcwidth(quint16 ucs); -#if 0 -int konsole_wcwidth_cjk(Q_UINT16 ucs); -#endif - -int string_width( const QString & txt ); +int string_width( const std::wstring & wstr ); #endif diff --git a/lib/kprocess.h b/lib/kprocess.h index 2d3bcca..ec90721 100644 --- a/lib/kprocess.h +++ b/lib/kprocess.h @@ -38,7 +38,7 @@ class KProcessPrivate; /** * \class KProcess kprocess.h - * + * * Child process invocation, monitoring and control. * * This class extends QProcess by some useful functionality, overrides @@ -355,6 +355,9 @@ protected: openMode(QIODevice::ReadWrite) { } + virtual ~KProcessPrivate() + { + } void writeAll(const QByteArray &buf, int fd); void forwardStd(KProcess::ProcessChannel good, int fd); void _k_forwardStdout(); diff --git a/lib/kpty.cpp b/lib/kpty.cpp index 0baa640..542bde3 100644 --- a/lib/kpty.cpp +++ b/lib/kpty.cpp @@ -37,6 +37,11 @@ #define HAVE_UTIL_H #endif +#if defined(__APPLE__) +#define HAVE_OPENPTY +#define HAVE_UTIL_H +#endif + #ifdef __sgi #define __svr4__ #endif @@ -122,20 +127,20 @@ extern "C" { # define _NEW_TTY_CTRL #endif -#if defined (__FreeBSD__) || defined (__NetBSD__) || defined (__OpenBSD__) || defined (__bsdi__) || defined(__APPLE__) || defined (__DragonFly__) +#if defined (__FreeBSD__) || defined(__FreeBSD_kernel__) || defined (__NetBSD__) || defined (__OpenBSD__) || defined (__bsdi__) || defined(__APPLE__) || defined (__DragonFly__) # define _tcgetattr(fd, ttmode) ioctl(fd, TIOCGETA, (char *)ttmode) #else -# if defined(_HPUX_SOURCE) || defined(__Lynx__) || defined (__CYGWIN__) +# if defined(_HPUX_SOURCE) || defined(__Lynx__) || defined (__CYGWIN__) || defined(__GNU__) # define _tcgetattr(fd, ttmode) tcgetattr(fd, ttmode) # else # define _tcgetattr(fd, ttmode) ioctl(fd, TCGETS, (char *)ttmode) # endif #endif -#if defined (__FreeBSD__) || defined (__NetBSD__) || defined (__OpenBSD__) || defined (__bsdi__) || defined(__APPLE__) || defined (__DragonFly__) +#if defined (__FreeBSD__) || defined(__FreeBSD_kernel__) || defined (__NetBSD__) || defined (__OpenBSD__) || defined (__bsdi__) || defined(__APPLE__) || defined (__DragonFly__) # define _tcsetattr(fd, ttmode) ioctl(fd, TIOCSETA, (char *)ttmode) #else -# if defined(_HPUX_SOURCE) || defined(__CYGWIN__) +# if defined(_HPUX_SOURCE) || defined(__CYGWIN__) || defined(__GNU__) # define _tcsetattr(fd, ttmode) tcsetattr(fd, TCSANOW, ttmode) # else # define _tcsetattr(fd, ttmode) ioctl(fd, TCSETS, (char *)ttmode) @@ -169,12 +174,14 @@ KPtyPrivate::~KPtyPrivate() { } +#ifndef HAVE_OPENPTY bool KPtyPrivate::chownpty(bool) { // return !QProcess::execute(KStandardDirs::findExe("kgrantpty"), // QStringList() << (grant?"--grant":"--revoke") << QString::number(masterFd)); return true; } +#endif ///////////////////////////// // public member functions // @@ -221,7 +228,7 @@ bool KPty::open() if (::openpty( &d->masterFd, &d->slaveFd, ptsn, 0, 0)) { d->masterFd = -1; d->slaveFd = -1; - qWarning(175) << "Can't open a pseudo teletype"; + qWarning() << "Can't open a pseudo teletype"; return false; } d->ttyName = ptsn; @@ -496,7 +503,7 @@ void KPty::login(const char * user, const char * remotehost) #ifdef HAVE_UTEMPTER Q_D(KPty); - addToUtmp(d->ttyName, remotehost, d->masterFd); + addToUtmp(d->ttyName.constData(), remotehost, d->masterFd); Q_UNUSED(user); #else # ifdef HAVE_UTMPX @@ -508,7 +515,11 @@ void KPty::login(const char * user, const char * remotehost) // note: strncpy without terminators _is_ correct here. man 4 utmp if (user) { +# ifdef HAVE_UTMPX + strncpy(l_struct.ut_user, user, sizeof(l_struct.ut_user)); +# else strncpy(l_struct.ut_name, user, sizeof(l_struct.ut_name)); +# endif } if (remotehost) { @@ -578,7 +589,7 @@ void KPty::logout() #ifdef HAVE_UTEMPTER Q_D(KPty); - removeLineFromUtmp(d->ttyName, d->masterFd); + removeLineFromUtmp(d->ttyName.constData(), d->masterFd); #else Q_D(KPty); @@ -619,7 +630,11 @@ void KPty::logout() setutent(); if ((ut = getutline(&l_struct))) { # endif +# ifdef HAVE_UTMPX + memset(ut->ut_user, 0, sizeof(*ut->ut_user)); +# else memset(ut->ut_name, 0, sizeof(*ut->ut_name)); +# endif memset(ut->ut_host, 0, sizeof(*ut->ut_host)); # ifdef HAVE_STRUCT_UTMP_UT_SYSLEN ut->ut_syslen = 0; diff --git a/lib/kpty.h b/lib/kpty.h index 24457a5..ab34f6e 100644 --- a/lib/kpty.h +++ b/lib/kpty.h @@ -25,7 +25,7 @@ #include -struct KPtyPrivate; +class KPtyPrivate; struct termios; /** diff --git a/lib/kpty_p.h b/lib/kpty_p.h index 3f6bb88..4f865b8 100644 --- a/lib/kpty_p.h +++ b/lib/kpty_p.h @@ -27,7 +27,8 @@ #include -struct KPtyPrivate { +class KPtyPrivate { +public: Q_DECLARE_PUBLIC(KPty) diff --git a/lib/kptydevice.cpp b/lib/kptydevice.cpp index 37ecce8..90b4a58 100644 --- a/lib/kptydevice.cpp +++ b/lib/kptydevice.cpp @@ -130,7 +130,7 @@ bool KPtyDevicePrivate::_k_canRead() } if (readBytes < 0) { readBuffer.unreserve(available); - q->setErrorString("Error reading from PTY"); + q->setErrorString(QLatin1String("Error reading from PTY")); return false; } readBuffer.unreserve(available - readBytes); // *should* be a no-op @@ -164,7 +164,7 @@ bool KPtyDevicePrivate::_k_canWrite() write(q->masterFd(), writeBuffer.readPointer(), writeBuffer.readSize())); if (wroteBytes < 0) { - q->setErrorString("Error writing to PTY"); + q->setErrorString(QLatin1String("Error writing to PTY")); return false; } writeBuffer.free(wroteBytes); @@ -249,7 +249,7 @@ bool KPtyDevicePrivate::doWait(int msecs, bool reading) break; return false; case 0: - q->setErrorString("PTY operation timed out"); + q->setErrorString(QLatin1String("PTY operation timed out")); return false; default: if (FD_ISSET(q->masterFd(), &rfds)) { @@ -305,7 +305,7 @@ bool KPtyDevice::open(OpenMode mode) return true; if (!KPty::open()) { - setErrorString("Error opening PTY"); + setErrorString(QLatin1String("Error opening PTY")); return false; } @@ -319,7 +319,7 @@ bool KPtyDevice::open(int fd, OpenMode mode) Q_D(KPtyDevice); if (!KPty::open(fd)) { - setErrorString("Error opening PTY"); + setErrorString(QLatin1String("Error opening PTY")); return false; } diff --git a/lib/kptydevice.h b/lib/kptydevice.h index 3ef8d17..c398646 100644 --- a/lib/kptydevice.h +++ b/lib/kptydevice.h @@ -41,7 +41,7 @@ class QSocketNotifier; #define Q_DECLARE_PRIVATE_MI(Class, SuperClass) \ inline Class##Private* d_func() { return reinterpret_cast(SuperClass::d_ptr); } \ inline const Class##Private* d_func() const { return reinterpret_cast(SuperClass::d_ptr); } \ - friend class Class##Private; + friend struct Class##Private; /** * Encapsulates KPty into a QIODevice, so it can be used with Q*Stream, etc. @@ -278,7 +278,7 @@ public: { int index = 0; int start = head; - QLinkedList::ConstIterator it = buffers.begin(); + QLinkedList::ConstIterator it = buffers.constBegin(); forever { if (!maxLength) return index; diff --git a/lib/kptyprocess.cpp b/lib/kptyprocess.cpp index 078770b..ec8df33 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,12 +63,25 @@ 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))); + } } delete d->pty; + waitForFinished(300); // give it some time to finish + if (state() != QProcess::NotRunning) + { + 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"; + } } void KPtyProcess::setPtyChannels(PtyChannels channels) diff --git a/lib/kptyprocess.h b/lib/kptyprocess.h index 15e4de4..1270c47 100644 --- a/lib/kptyprocess.h +++ b/lib/kptyprocess.h @@ -37,7 +37,7 @@ class KPtyDevice; -struct KPtyProcessPrivate; +class KPtyProcessPrivate; /** * This class extends KProcess by support for PTYs (pseudo TTYs). @@ -155,7 +155,8 @@ private: // private data // ////////////////// -struct KPtyProcessPrivate : KProcessPrivate { +class KPtyProcessPrivate : public KProcessPrivate { +public: KPtyProcessPrivate() : ptyChannels(KPtyProcess::NoChannels), addUtmp(false) diff --git a/lib/qtermwidget.cpp b/lib/qtermwidget.cpp index dd8b867..a5b796d 100644 --- a/lib/qtermwidget.cpp +++ b/lib/qtermwidget.cpp @@ -64,7 +64,7 @@ Session *TermWidgetImpl::createSession(QWidget* parent) { Session *session = new Session(parent); - session->setTitle(Session::NameRole, "QTermWidget"); + session->setTitle(Session::NameRole, QLatin1String("QTermWidget")); /* Thats a freaking bad idea!!!! * /bin/bash is not there on every system @@ -75,11 +75,11 @@ Session *TermWidgetImpl::createSession(QWidget* parent) */ //session->setProgram("/bin/bash"); - session->setProgram(getenv("SHELL")); + session->setProgram(QString::fromLocal8Bit(qgetenv("SHELL"))); - QStringList args(""); + QStringList args = QStringList(QString()); session->setArguments(args); session->setAutoClose(true); @@ -90,7 +90,7 @@ Session *TermWidgetImpl::createSession(QWidget* parent) session->setDarkBackground(true); - session->setKeyBindings(""); + session->setKeyBindings(QString()); return session; } @@ -145,7 +145,7 @@ void QTermWidget::findPrevious() void QTermWidget::search(bool forwards, bool next) { int startColumn, startLine; - + if (next) // search from just after current selection { m_impl->m_terminalDisplay->screenWindow()->screen()->getSelectionEnd(startColumn, startLine); @@ -155,15 +155,15 @@ void QTermWidget::search(bool forwards, bool next) { m_impl->m_terminalDisplay->screenWindow()->screen()->getSelectionStart(startColumn, startLine); } - + qDebug() << "current selection starts at: " << startColumn << startLine; - qDebug() << "current cursor position: " << m_impl->m_terminalDisplay->screenWindow()->cursorPosition(); + qDebug() << "current cursor position: " << m_impl->m_terminalDisplay->screenWindow()->cursorPosition(); QRegExp regExp(m_searchBar->searchText()); regExp.setPatternSyntax(m_searchBar->useRegularExpression() ? QRegExp::RegExp : QRegExp::FixedString); regExp.setCaseSensitivity(m_searchBar->matchCase() ? Qt::CaseSensitive : Qt::CaseInsensitive); - HistorySearch *historySearch = + HistorySearch *historySearch = new HistorySearch(m_impl->m_session->emulation(), regExp, forwards, startColumn, startLine, this); connect(historySearch, SIGNAL(matchFound(int, int, int, int)), this, SLOT(matchFound(int, int, int, int))); connect(historySearch, SIGNAL(noMatchFound()), this, SLOT(noMatchFound())); @@ -183,7 +183,7 @@ void QTermWidget::matchFound(int startColumn, int startLine, int endColumn, int sw->setSelectionEnd(endColumn, endLine - sw->currentLine()); } -void QTermWidget::noMatchFound() +void QTermWidget::noMatchFound() { m_impl->m_terminalDisplay->screenWindow()->clearSelection(); } @@ -202,12 +202,12 @@ void QTermWidget::changeDir(const QString & dir) */ QString strCmd; strCmd.setNum(getShellPID()); - strCmd.prepend("ps -j "); - strCmd.append(" | tail -1 | awk '{ print $5 }' | grep -q \\+"); + strCmd.prepend(QLatin1String("ps -j ")); + strCmd.append(QLatin1String(" | tail -1 | awk '{ print $5 }' | grep -q \\+")); int retval = system(strCmd.toStdString().c_str()); if (!retval) { - QString cmd = "cd " + dir + "\n"; + QString cmd = QLatin1String("cd ") + dir + QLatin1Char('\n'); sendText(cmd); } } @@ -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() ) { @@ -228,14 +242,46 @@ void QTermWidget::startShellProgram() m_impl->m_session->run(); } +void QTermWidget::startTerminalTeletype() +{ + if ( m_impl->m_session->isRunning() ) { + return; + } + + m_impl->m_session->runEmptyPTY(); + // redirect data from TTY to external recipient + connect( m_impl->m_session->emulation(), SIGNAL(sendData(const char *,int)), + this, SIGNAL(sendData(const char *,int)) ); +} + void QTermWidget::init(int startnow) { m_layout = new QVBoxLayout(); m_layout->setMargin(0); setLayout(m_layout); - + + // translations + // First check $XDG_DATA_DIRS. This follows the implementation in libqtxdg + QString d = QFile::decodeName(qgetenv("XDG_DATA_DIRS")); + QStringList dirs = d.split(QLatin1Char(':'), QString::SkipEmptyParts); + if (dirs.isEmpty()) { + dirs.append(QString::fromLatin1("/usr/local/share")); + dirs.append(QString::fromLatin1("/usr/share")); + } + dirs.append(QFile::decodeName(TRANSLATIONS_DIR)); + + m_translator = new QTranslator(this); + + for (const QString& dir : dirs) { + qDebug() << "Trying to load translation file from dir" << dir; + if (m_translator->load(QLocale::system(), QLatin1String("qtermwidget"), QLatin1String(QLatin1String("_")), dir)) { + qApp->installTranslator(m_translator); + qDebug() << "Translations found in" << dir; + break; + } + } + m_impl = new TermWidgetImpl(this); - m_impl->m_terminalDisplay->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); m_layout->addWidget(m_impl->m_terminalDisplay); connect(m_impl->m_session, SIGNAL(bellRequest(QString)), m_impl->m_terminalDisplay, SLOT(bell(QString))); @@ -243,10 +289,12 @@ void QTermWidget::init(int startnow) connect(m_impl->m_session, SIGNAL(activity()), this, SIGNAL(activity())); connect(m_impl->m_session, SIGNAL(silence()), this, SIGNAL(silence())); + connect(m_impl->m_session, &Session::profileChangeCommandReceived, this, &QTermWidget::profileChanged); + connect(m_impl->m_session, &Session::receivedData, this, &QTermWidget::receivedData); // That's OK, FilterChain's dtor takes care of UrlFilter. UrlFilter *urlFilter = new UrlFilter(); - connect(urlFilter, SIGNAL(activated(QUrl)), this, SIGNAL(urlActivated(QUrl))); + connect(urlFilter, &UrlFilter::activated, this, &QTermWidget::urlActivated); m_impl->m_terminalDisplay->filterChain()->addFilter(urlFilter); m_searchBar = new SearchBar(this); @@ -277,17 +325,21 @@ void QTermWidget::init(int startnow) // m_impl->m_terminalDisplay->setSize(80, 40); QFont font = QApplication::font(); - font.setFamily("Monospace"); + font.setFamily(QLatin1String("Monospace")); font.setPointSize(10); font.setStyleHint(QFont::TypeWriter); setTerminalFont(font); m_searchBar->setFont(font); setScrollBarPosition(NoScrollBar); + setKeyboardCursorShape(Emulation::KeyboardCursorShape::BlockCursor); m_impl->m_session->addView(m_impl->m_terminalDisplay); + connect(m_impl->m_session, SIGNAL(resizeRequest(QSize)), this, SLOT(setSize(QSize))); connect(m_impl->m_session, SIGNAL(finished()), this, SLOT(sessionFinished())); + connect(m_impl->m_session, &Session::titleChanged, this, &QTermWidget::titleChanged); + connect(m_impl->m_session, &Session::cursorChanged, this, &QTermWidget::cursorChanged); } @@ -320,6 +372,14 @@ void QTermWidget::setTerminalOpacity(qreal level) m_impl->m_terminalDisplay->setOpacity(level); } +void QTermWidget::setTerminalBackgroundImage(QString backgroundImage) +{ + if (!m_impl->m_terminalDisplay) + return; + + m_impl->m_terminalDisplay->setBackgroundImage(backgroundImage); +} + void QTermWidget::setShellProgram(const QString &progname) { if (!m_impl->m_session) @@ -343,11 +403,11 @@ QString QTermWidget::workingDirectory() // Christian Surlykke: On linux we could look at /proc//cwd which should be a link to current // working directory (: process id of the shell). I don't know about BSD. // Maybe we could just offer it when running linux, for a start. - QDir d(QString("/proc/%1/cwd").arg(getShellPID())); + QDir d(QString::fromLatin1("/proc/%1/cwd").arg(getShellPID())); if (!d.exists()) { qDebug() << "Cannot find" << d.dirName(); - goto fallback; + goto fallback; } return d.canonicalPath(); #endif @@ -414,16 +474,22 @@ 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; } -void QTermWidget::setSize(int h, int v) +void QTermWidget::addCustomColorSchemeDir(const QString& custom_dir) +{ + ColorSchemeManager::instance()->addCustomColorSchemeDir(custom_dir); +} + +void QTermWidget::setSize(const QSize &size) { if (!m_impl->m_terminalDisplay) return; - m_impl->m_terminalDisplay->setSize(h, v); + m_impl->m_terminalDisplay->setSize(size.width(), size.height()); } void QTermWidget::setHistorySize(int lines) @@ -438,7 +504,7 @@ void QTermWidget::setScrollBarPosition(ScrollBarPosition pos) { if (!m_impl->m_terminalDisplay) return; - m_impl->m_terminalDisplay->setScrollBarPosition((TerminalDisplay::ScrollBarPosition)pos); + m_impl->m_terminalDisplay->setScrollBarPosition(pos); } void QTermWidget::scrollToEnd() @@ -465,6 +531,10 @@ void QTermWidget::sessionFinished() emit finished(); } +void QTermWidget::bracketText(QString& text) +{ + m_impl->m_terminalDisplay->bracketText(text); +} void QTermWidget::copyClipboard() { @@ -485,9 +555,9 @@ void QTermWidget::setZoom(int step) { if (!m_impl->m_terminalDisplay) return; - + QFont font = m_impl->m_terminalDisplay->getVTFont(); - + font.setPointSize(font.pointSize() + step); setTerminalFont(font); } @@ -567,6 +637,11 @@ int QTermWidget::screenColumnsCount() return m_impl->m_terminalDisplay->screenWindow()->screen()->getColumns(); } +int QTermWidget::screenLinesCount() +{ + return m_impl->m_terminalDisplay->screenWindow()->screen()->getLines(); +} + void QTermWidget::setSelectionStart(int row, int column) { m_impl->m_terminalDisplay->screenWindow()->screen()->setSelectionStart(column, row, true); @@ -582,9 +657,9 @@ void QTermWidget::getSelectionStart(int& row, int& column) m_impl->m_terminalDisplay->screenWindow()->screen()->getSelectionStart(column, row); } -void QTermWidget::setSelectionEnd(int& row, int& column) +void QTermWidget::getSelectionEnd(int& row, int& column) { - m_impl->m_terminalDisplay->screenWindow()->screen()->setSelectionEnd(column, row); + m_impl->m_terminalDisplay->screenWindow()->screen()->getSelectionEnd(column, row); } QString QTermWidget::selectedText(bool preserveLineBreaks) @@ -619,3 +694,83 @@ Filter::HotSpot* QTermWidget::getHotSpotAt(int row, int column) const return m_impl->m_terminalDisplay->filterChain()->hotSpotAt(row, column); } +QList QTermWidget::filterActions(const QPoint& position, QWidget* parent) +{ + return m_impl->m_terminalDisplay->filterActions(position, parent); +} + +int QTermWidget::getPtySlaveFd() const +{ + return m_impl->m_session->getPtySlaveFd(); +} + +void QTermWidget::setKeyboardCursorShape(KeyboardCursorShape shape) +{ + if (!m_impl->m_terminalDisplay) + return; + m_impl->m_terminalDisplay->setKeyboardCursorShape(shape); +} + +void QTermWidget::setBlinkingCursor(bool blink) +{ + if (!m_impl->m_terminalDisplay) + return; + 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(); + if (title.isEmpty()) + title = m_impl->m_session->title(Konsole::Session::NameRole); + return title; +} + +QString QTermWidget::icon() const +{ + QString icon = m_impl->m_session->iconText(); + if (icon.isEmpty()) + icon = m_impl->m_session->iconName(); + return icon; +} + +bool QTermWidget::isTitleChanged() const +{ + return m_impl->m_session->isTitleChanged(); +} + +void QTermWidget::setAutoClose(bool autoClose) +{ + m_impl->m_session->setAutoClose(autoClose); +} + +void QTermWidget::cursorChanged(Konsole::Emulation::KeyboardCursorShape cursorShape, bool blinkingCursorEnabled) +{ + // TODO: A switch to enable/disable DECSCUSR? + setKeyboardCursorShape(cursorShape); + setBlinkingCursor(blinkingCursorEnabled); +} + +void QTermWidget::setMargin(int margin) +{ + m_impl->m_terminalDisplay->setMargin(margin); +} + +int QTermWidget::getMargin() const +{ + return m_impl->m_terminalDisplay->margin(); +} diff --git a/lib/qtermwidget.h b/lib/qtermwidget.h index 9c550ee..08746ea 100644 --- a/lib/qtermwidget.h +++ b/lib/qtermwidget.h @@ -20,7 +20,9 @@ #ifndef _Q_TERM_WIDGET #define _Q_TERM_WIDGET +#include #include +#include "Emulation.h" #include "Filter.h" class QVBoxLayout; @@ -32,15 +34,20 @@ class QTermWidget : public QWidget { Q_OBJECT public: + /** + * This enum describes the location where the scroll bar is positioned in the display widget. + */ enum ScrollBarPosition { /** Do not show the scroll bar. */ - NoScrollBar=0, + NoScrollBar = 0, /** Show the scroll bar on the left side of the display. */ - ScrollBarLeft=1, + ScrollBarLeft = 1, /** Show the scroll bar on the right side of the display. */ - ScrollBarRight=2 + ScrollBarRight = 2 }; + using KeyboardCursorShape = Konsole::Emulation::KeyboardCursorShape; + //Creation of widget QTermWidget(int startnow, // 1 = start shell programm immediatelly QWidget * parent = 0); @@ -52,9 +59,20 @@ 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(); + /** + * Start terminal teletype as is + * and redirect data for external recipient. + * It can be used for display and control a remote terminal. + */ + void startTerminalTeletype(); + int getShellPID(); void changeDir(const QString & dir); @@ -63,11 +81,11 @@ public: // Terminal font // Default is application font with family Monospace, size 10 - // USE ONLY FIXED-PITCH FONT! - // otherwise symbols' position could be incorrect + // Beware of a performance penalty and display/alignment issues when using a proportional font. void setTerminalFont(const QFont & font); QFont getTerminalFont(); void setTerminalOpacity(qreal level); + void setTerminalBackgroundImage(QString backgroundImage); //environment void setEnvironment(const QStringList & environment); @@ -92,9 +110,7 @@ public: */ void setColorScheme(const QString & name); static QStringList availableColorSchemes(); - - //set size - void setSize(int h, int v); + static void addCustomColorSchemeDir(const QString& custom_dir); // History size for scrolling void setHistorySize(int lines); //infinite if lines < 0 @@ -126,18 +142,19 @@ public: //! Return current key bindings QString keyBindings(); - + void setMotionAfterPasting(int); /** Return the number of lines in the history buffer. */ int historyLinesCount(); int screenColumnsCount(); + int screenLinesCount(); void setSelectionStart(int row, int column); void setSelectionEnd(int row, int column); void getSelectionStart(int& row, int& column); - void setSelectionEnd(int& row, int& column); + void getSelectionEnd(int& row, int& column); /** * Returns the currently selected text. @@ -165,6 +182,50 @@ public: */ Filter::HotSpot* getHotSpotAt(int row, int column) const; + /* + * Proxy for TerminalDisplay::filterActions + * */ + QList filterActions(const QPoint& position, QWidget* parent); + + /** + * Returns a pty slave file descriptor. + * This can be used for display and control + * a remote terminal. + */ + int getPtySlaveFd() const; + + /** + * Sets the shape of the keyboard cursor. This is the cursor drawn + * at the position in the terminal where keyboard input will appear. + */ + void setKeyboardCursorShape(KeyboardCursorShape shape); + + 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 + * keep it running. + */ + void setAutoClose(bool); + + QString title() const; + QString icon() const; + + /** 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); + + /** Set the empty space outside the terminal */ + void setMargin(int); + + /** Get the empty space outside the terminal */ + int getMargin() const; signals: void finished(); void copyAvailable(bool); @@ -174,13 +235,30 @@ signals: void termKeyPressed(QKeyEvent *); - void urlActivated(const QUrl&); + void urlActivated(const QUrl&, bool fromContextMenu); void bell(const QString& message); void activity(); void silence(); + /** + * Emitted when emulator send data to the terminal process + * (redirected for external recipient). It can be used for + * control and display the remote terminal. + */ + void sendData(const char *,int); + + void profileChanged(const QString & profile); + + void titleChanged(); + + /** + * Signals that we received new data from the process running in the + * terminal emulator + */ + void receivedData(const QString &text); + public slots: // Copy selection to clipboard void copyClipboard(); @@ -188,13 +266,16 @@ public slots: // Paste clipboard to terminal void pasteClipboard(); - // Paste selection to terminal + // Paste selection to terminal void pasteSelection(); // Set zoom void zoomIn(); void zoomOut(); - + + // Set size + void setSize(const QSize &); + /*! Set named key binding for given widget */ void setKeyBindings(const QString & kb); @@ -218,6 +299,11 @@ private slots: void findPrevious(); void matchFound(int startColumn, int startLine, int endColumn, int endLine); void noMatchFound(); + /** + * Emulation::cursorChanged() signal propogates to here and QTermWidget + * sends the specified cursor states to the terminal display + */ + void cursorChanged(Konsole::Emulation::KeyboardCursorShape cursorShape, bool blinkingCursorEnabled); private: void search(bool forwards, bool next); @@ -226,6 +312,7 @@ private: TermWidgetImpl * m_impl; SearchBar* m_searchBar; QVBoxLayout *m_layout; + QTranslator *m_translator; }; diff --git a/lib/tools.cpp b/lib/tools.cpp index fef81c1..11ef9fa 100644 --- a/lib/tools.cpp +++ b/lib/tools.cpp @@ -11,12 +11,9 @@ But in some cases (apple bundle) there can be more locations). */ QString get_kb_layout_dir() { -#ifdef BUNDLE_KEYBOARDLAYOUTS - return QLatin1String(":/"); -#else // qDebug() << __FILE__ << __FUNCTION__; - QString rval = ""; + QString rval = QString(); QString k(qgetenv("KB_LAYOUT_DIR")); QDir d(k); @@ -24,15 +21,15 @@ QString get_kb_layout_dir() if (d.exists()) { - rval = k.append("/"); + rval = k.append(QLatin1Char('/')); return rval; } // subdir in the app location - d.setPath(QCoreApplication::applicationDirPath() + "/kb-layouts/"); + d.setPath(QCoreApplication::applicationDirPath() + QLatin1String("/kb-layouts/")); //qDebug() << d.path(); if (d.exists()) - return QCoreApplication::applicationDirPath() + "/kb-layouts/"; + return QCoreApplication::applicationDirPath() + QLatin1String("/kb-layouts/"); #ifdef Q_WS_MAC d.setPath(QCoreApplication::applicationDirPath() + "/../Resources/kb-layouts/"); if (d.exists()) @@ -40,39 +37,60 @@ QString get_kb_layout_dir() #endif qDebug() << "Cannot find KB_LAYOUT_DIR. Default:" << k; return QString(); -#endif // BUNDLE_KEYBOARDLAYOUTS } -/*! Helper function to get possible location of layout files. +/*! Helper function to add custom location of color schemes. +*/ +namespace { + QStringList custom_color_schemes_dirs; +} +void add_custom_color_scheme_dir(const QString& custom_dir) +{ + if (!custom_color_schemes_dirs.contains(custom_dir)) + custom_color_schemes_dirs << custom_dir; +} + +/*! Helper function to get possible locations of color schemes. By default the COLORSCHEMES_DIR is used (linux/BSD/macports). But in some cases (apple bundle) there can be more locations). */ -QString get_color_schemes_dir() +const QStringList get_color_schemes_dirs() { -#ifdef BUNDLE_COLORSCHEMES - return QLatin1String(":/"); -#else // qDebug() << __FILE__ << __FUNCTION__; - QString rval = ""; + QStringList rval; QString k(qgetenv("COLORSCHEMES_DIR")); QDir d(k); // qDebug() << "default COLORSCHEMES_DIR: " << k; if (d.exists()) - rval = k.append("/"); + rval << k.append(QLatin1Char('/')); // subdir in the app location - d.setPath(QCoreApplication::applicationDirPath() + "/color-schemes/"); + d.setPath(QCoreApplication::applicationDirPath() + QLatin1String("/color-schemes/")); //qDebug() << d.path(); if (d.exists()) - rval = QCoreApplication::applicationDirPath() + "/color-schemes/"; + { + if (!rval.isEmpty()) + rval.clear(); + rval << (QCoreApplication::applicationDirPath() + QLatin1String("/color-schemes/")); + } #ifdef Q_WS_MAC d.setPath(QCoreApplication::applicationDirPath() + "/../Resources/color-schemes/"); if (d.exists()) - rval = QCoreApplication::applicationDirPath() + "/../Resources/color-schemes/"; + { + if (!rval.isEmpty()) + rval.clear(); + rval << (QCoreApplication::applicationDirPath() + "/../Resources/color-schemes/"); + } #endif + for (const QString& custom_dir : const_cast(custom_color_schemes_dirs)) + { + d.setPath(custom_dir); + if (d.exists()) + rval << custom_dir; + } #ifdef QT_DEBUG if(!rval.isEmpty()) { qDebug() << "Using color-schemes: " << rval; @@ -81,5 +99,4 @@ QString get_color_schemes_dir() } #endif return rval; -#endif // BUNDLE_COLORSCHEMES } diff --git a/lib/tools.h b/lib/tools.h index b24d88f..455037e 100644 --- a/lib/tools.h +++ b/lib/tools.h @@ -2,9 +2,10 @@ #define TOOLS_H #include +#include QString get_kb_layout_dir(); -QString get_color_schemes_dir(); - +void add_custom_color_scheme_dir(const QString& custom_dir); +const QStringList get_color_schemes_dirs(); #endif diff --git a/lib/translations/CMakeLists.txt b/lib/translations/CMakeLists.txt new file mode 100644 index 0000000..ce40923 --- /dev/null +++ b/lib/translations/CMakeLists.txt @@ -0,0 +1,5 @@ +cmake_minimum_required(VERSION 3.0.2 FATAL_ERROR) + +project(qtermwidget) + +build_component("." "${CMAKE_INSTALL_FULL_DATADIR}/qtermwidget/translations") diff --git a/lib/translations/qtermwidget.ts b/lib/translations/qtermwidget.ts new file mode 100644 index 0000000..c099dcb --- /dev/null +++ b/lib/translations/qtermwidget.ts @@ -0,0 +1,125 @@ + + + + + Konsole::TerminalDisplay + + + Size: XXX x XXX + + + + + Size: %1 x %2 + + + + + <qt>Output has been <a href="http://en.wikipedia.org/wiki/Flow_control">suspended</a> by pressing Ctrl+S. Press <b>Ctrl+Q</b> to resume.</qt> + + + + + Konsole::Vt102Emulation + + + No keyboard translator available. The information needed to convert key presses into characters to send to the terminal is missing. + + + + + QObject + + + + Un-named Color Scheme + + + + + Accessible Color Scheme + + + + + Open Link + + + + + Copy Link Address + + + + + Send Email To... + + + + + Copy Email Address + + + + + QTermWidget + + + Color Scheme Error + + + + + Cannot load color scheme: %1 + + + + + SearchBar + + + Match case + + + + + Regular expression + + + + + Highlight all matches + + + + + SearchBar + + + + + X + + + + + Find: + + + + + < + + + + + > + + + + + ... + + + + diff --git a/lib/translations/qtermwidget_ca.ts b/lib/translations/qtermwidget_ca.ts new file mode 100644 index 0000000..573719b --- /dev/null +++ b/lib/translations/qtermwidget_ca.ts @@ -0,0 +1,125 @@ + + + + + Konsole::TerminalDisplay + + + Size: XXX x XXX + Mida: XXX x XXX + + + + Size: %1 x %2 + Mida: %1 x %2 + + + + <qt>Output has been <a href="http://en.wikipedia.org/wiki/Flow_control">suspended</a> by pressing Ctrl+S. Press <b>Ctrl+Q</b> to resume.</qt> + <qt>La sortida ha estat <a href="http://en.wikipedia.org/wiki/Flow_control">suspesa</a> en prémer Ctrl+S. Premeu <b>Ctrl+Q</b> per reprendre-la.</qt> + + + + Konsole::Vt102Emulation + + + No keyboard translator available. The information needed to convert key presses into characters to send to the terminal is missing. + No hi ha disponible cap traductor de teclat. No es disposa de la informació necessària per convertir la pressió de les tecles a caràcters al terminal. + + + + QObject + + + + Un-named Color Scheme + Esquema de color sense nom + + + + Accessible Color Scheme + Esquema de color accessible + + + + Open Link + Obre l'enllaç + + + + Copy Link Address + Copia l'adreça de l'enllaç + + + + Send Email To... + Envia un correu electrònic a... + + + + Copy Email Address + Copia l'adreça de correu electrònic + + + + QTermWidget + + + Color Scheme Error + Error de l'esquema de color + + + + Cannot load color scheme: %1 + No es pot carregar l'esquema de color: %1 + + + + SearchBar + + + Match case + Coincidència + + + + Regular expression + Expressió regular + + + + Highlight all matches + Ressalta totes les coincidències + + + + SearchBar + Barra de cerca + + + + X + X + + + + Find: + Troba: + + + + < + < + + + + > + > + + + + ... + ... + + + diff --git a/lib/translations/qtermwidget_cs.ts b/lib/translations/qtermwidget_cs.ts new file mode 100644 index 0000000..d420ba4 --- /dev/null +++ b/lib/translations/qtermwidget_cs.ts @@ -0,0 +1,125 @@ + + + + + Konsole::TerminalDisplay + + + Size: XXX x XXX + Velikost: XXX x XXX + + + + Size: %1 x %2 + Velikost: %1 x %2 + + + + <qt>Output has been <a href="http://en.wikipedia.org/wiki/Flow_control">suspended</a> by pressing Ctrl+S. Press <b>Ctrl+Q</b> to resume.</qt> + <qt>Výstup byl <a href="http://en.wikipedia.org/wiki/Flow_control">pozastaven</a> stisknutím Ctrl+S. Znovu ho spustíte stisknutím <b>Ctrl+Q</b>.</qt> + + + + Konsole::Vt102Emulation + + + No keyboard translator available. The information needed to convert key presses into characters to send to the terminal is missing. + Není k dispozici žádný překladač klávesnice. Chybí informace pro převod kódů stisknutých kláves na znaky posílané na terminál. + + + + QObject + + + + Un-named Color Scheme + Nepojmenované barevné schéma + + + + Accessible Color Scheme + Barevné schéma pro zrakově hendikepované uživatele + + + + Open Link + Otevřít odkaz + + + + Copy Link Address + Zkopírovat adresu odkazu + + + + Send Email To... + Poslat e-mail na… + + + + Copy Email Address + Zkopírovat e-mailovou adresu + + + + QTermWidget + + + Color Scheme Error + Chyba barevného schématu + + + + Cannot load color scheme: %1 + Nedaří se načíst barevné schéma: %1 + + + + SearchBar + + + Match case + Rozlišovat malá/VELKÁ písmena + + + + Regular expression + Regulární výraz + + + + Highlight all matches + Zvýraznit všechny shody + + + + SearchBar + Pruh hledání + + + + X + + + + + Find: + Najít: + + + + < + + + + + > + + + + + ... + + + + diff --git a/lib/translations/qtermwidget_cy.ts b/lib/translations/qtermwidget_cy.ts new file mode 100644 index 0000000..1562523 --- /dev/null +++ b/lib/translations/qtermwidget_cy.ts @@ -0,0 +1,125 @@ + + + + + Konsole::TerminalDisplay + + + Size: XXX x XXX + + + + + Size: %1 x %2 + + + + + <qt>Output has been <a href="http://en.wikipedia.org/wiki/Flow_control">suspended</a> by pressing Ctrl+S. Press <b>Ctrl+Q</b> to resume.</qt> + + + + + Konsole::Vt102Emulation + + + No keyboard translator available. The information needed to convert key presses into characters to send to the terminal is missing. + + + + + QObject + + + + Un-named Color Scheme + + + + + Accessible Color Scheme + + + + + Open Link + + + + + Copy Link Address + + + + + Send Email To... + + + + + Copy Email Address + + + + + QTermWidget + + + Color Scheme Error + + + + + Cannot load color scheme: %1 + + + + + SearchBar + + + Match case + + + + + Regular expression + + + + + Highlight all matches + + + + + SearchBar + + + + + X + + + + + Find: + + + + + < + + + + + > + + + + + ... + + + + diff --git a/lib/translations/qtermwidget_da.ts b/lib/translations/qtermwidget_da.ts new file mode 100644 index 0000000..aa1736f --- /dev/null +++ b/lib/translations/qtermwidget_da.ts @@ -0,0 +1,125 @@ + + + + + Konsole::TerminalDisplay + + + Size: XXX x XXX + Størrelse: XXX x XXX + + + + Size: %1 x %2 + Størrelse: %1 x %2 + + + + <qt>Output has been <a href="http://en.wikipedia.org/wiki/Flow_control">suspended</a> by pressing Ctrl+S. Press <b>Ctrl+Q</b> to resume.</qt> + <qt>Output er blevet <a href="http://en.wikipedia.org/wiki/Flow_control">suspenderet</a> ved tryk på Ctrl+S. Tryk på <b>Ctrl+Q</b> for at genoptage.</qt> + + + + Konsole::Vt102Emulation + + + No keyboard translator available. The information needed to convert key presses into characters to send to the terminal is missing. + Ingen tastaturoversætter tilgængelig. Informationen, som er nødvendig for at konvertere tastetryk til tegn, som sendes til terminalen, mangler. + + + + QObject + + + + Un-named Color Scheme + Unavngivet farveskema + + + + Accessible Color Scheme + Tilgængeligt farveskema + + + + Open Link + Åbn link + + + + Copy Link Address + Kopiér linkadresse + + + + Send Email To... + Send e-mail til... + + + + Copy Email Address + Kopiér e-mailadresse + + + + QTermWidget + + + Color Scheme Error + Fejl ved farveskema + + + + Cannot load color scheme: %1 + Kan ikke indlæse farveskema: %1 + + + + SearchBar + + + Match case + Der skelnes mellem store og små bogstaver + + + + Regular expression + Regulært udtryk + + + + Highlight all matches + Fremhæv alle match + + + + SearchBar + SøgeLinje + + + + X + X + + + + Find: + Find: + + + + < + < + + + + > + > + + + + ... + ... + + + diff --git a/lib/translations/qtermwidget_de.ts b/lib/translations/qtermwidget_de.ts new file mode 100644 index 0000000..c78f39c --- /dev/null +++ b/lib/translations/qtermwidget_de.ts @@ -0,0 +1,125 @@ + + + + + Konsole::TerminalDisplay + + + Size: XXX x XXX + Größe: XXX x XXX + + + + Size: %1 x %2 + Größe: %1 x %2 + + + + <qt>Output has been <a href="http://en.wikipedia.org/wiki/Flow_control">suspended</a> by pressing Ctrl+S. Press <b>Ctrl+Q</b> to resume.</qt> + <qt>Ausgabe wurde <a href="http://en.wikipedia.org/wiki/Flow_control">ausgesetzt</a> beim Drücken von Strg+S. Drücke <b>Strg+Q</b> um fortzufahren.</qt> + + + + Konsole::Vt102Emulation + + + No keyboard translator available. The information needed to convert key presses into characters to send to the terminal is missing. + Kein Tastaturinterpretierer verfügbar. Die benötigte Information, um Tastenbefehle in Zeichen umzuwandeln und anschließenfd zum Terminal zu schicken, fehlt. + + + + QObject + + + + Un-named Color Scheme + Unbenanntes Farbschema + + + + Accessible Color Scheme + Zugängliches Farbschema + + + + Open Link + Öffne Link + + + + Copy Link Address + Kopiere Verknüpfungsadresse + + + + Send Email To... + Sende Email an... + + + + Copy Email Address + Kopiere Emailadresse + + + + QTermWidget + + + Color Scheme Error + Farbschemafehler + + + + Cannot load color scheme: %1 + Kann Farbschema nicht laden: %1 + + + + SearchBar + + + Match case + Groß- / Kleinschreibung berücksichtigen + + + + Regular expression + Regulärer Ausdruck + + + + Highlight all matches + Markiere alle Treffer + + + + SearchBar + Suchleiste + + + + X + + + + + Find: + Finde: + + + + < + + + + + > + + + + + ... + + + + diff --git a/lib/translations/qtermwidget_el.ts b/lib/translations/qtermwidget_el.ts new file mode 100644 index 0000000..756a0cd --- /dev/null +++ b/lib/translations/qtermwidget_el.ts @@ -0,0 +1,125 @@ + + + + + Konsole::TerminalDisplay + + + Size: XXX x XXX + Μέγεθος: XXX x XXX + + + + Size: %1 x %2 + Μέγεθος: %1 x %2 + + + + <qt>Output has been <a href="http://en.wikipedia.org/wiki/Flow_control">suspended</a> by pressing Ctrl+S. Press <b>Ctrl+Q</b> to resume.</qt> + <qt>Η έξοδος έχει <a href="http://en.wikipedia.org/wiki/Flow_control">ανασταλεί</a> με τον συνδυασμό πλήκτρων Ctrl+S. Πιέστε <b>Ctrl+Q</b> για επαναφορά.</qt> + + + + Konsole::Vt102Emulation + + + No keyboard translator available. The information needed to convert key presses into characters to send to the terminal is missing. + Δεν υπάρχει κάποιος μεταφραστής πληκτρολογίου διαθέσιμος. Η απαιτούμενη πληροφορία για την μετατροπή των πατημάτων πλήκτρων σε χαρακτήρες στο τερματικό λείπει. + + + + QObject + + + + Un-named Color Scheme + Ανώνυμος χρωματικός συνδυασμός + + + + Accessible Color Scheme + Προσπελάσιμος χρωματικός σχηματισμός + + + + Open Link + Άνοιγμα του δεσμού + + + + Copy Link Address + Αντιγραφή διεύθυνσης του δεσμού + + + + Send Email To... + Αποστολή ηλ. αλληλογραφίας προς... + + + + Copy Email Address + Αντιγραφή της ηλ. διεύθυνσης + + + + QTermWidget + + + Color Scheme Error + Σφάλμα του χρωματικού συνδυασμού + + + + Cannot load color scheme: %1 + Αδύνατη η φόρτωση του χρωματικού συνδυασμού: %1 + + + + SearchBar + + + Match case + Ταίριασμα πεζών/κεφαλαίων + + + + Regular expression + Κανονική έκφραση + + + + Highlight all matches + Τονισμός όλων των ταιριαστών + + + + SearchBar + Γραμμή αναζήτησης + + + + X + X + + + + Find: + Εύρεση: + + + + < + < + + + + > + > + + + + ... + ... + + + diff --git a/lib/translations/qtermwidget_es.ts b/lib/translations/qtermwidget_es.ts new file mode 100644 index 0000000..0777122 --- /dev/null +++ b/lib/translations/qtermwidget_es.ts @@ -0,0 +1,125 @@ + + + + + Konsole::TerminalDisplay + + + Size: XXX x XXX + Tamaño: XXX x XXX + + + + Size: %1 x %2 + Tamaño: %1 x %2 + + + + <qt>Output has been <a href="http://en.wikipedia.org/wiki/Flow_control">suspended</a> by pressing Ctrl+S. Press <b>Ctrl+Q</b> to resume.</qt> + <qt>La salida ha sido <a href="http://en.wikipedia.org/wiki/Flow_control">suspendida</a> al pulsar Ctrl+S. Pulse <b>Ctrl+Q</b> para reanudarla.</qt> + + + + Konsole::Vt102Emulation + + + No keyboard translator available. The information needed to convert key presses into characters to send to the terminal is missing. + No hay traductor de teclado disponible. La información necesaria para convertir pulsaciones de tecla en caracteres para enviarlos a la terminal está ausente. + + + + QObject + + + + Un-named Color Scheme + Esquema de color sin nombre + + + + Accessible Color Scheme + Esquema de color accesible + + + + Open Link + Abrir el enlace + + + + Copy Link Address + Copiar la dirección del enlace + + + + Send Email To... + Enviar correo a... + + + + Copy Email Address + Copiar la dirección de correo + + + + QTermWidget + + + Color Scheme Error + Error del esquema de color + + + + Cannot load color scheme: %1 + No se puede cargar el esquema de color: %1 + + + + SearchBar + + + Match case + Distinguir mayúsculas de minúsculas + + + + Regular expression + Expresión regular + + + + Highlight all matches + Resaltar todas las coincidencias + + + + SearchBar + Barra de búsqueda + + + + X + X + + + + Find: + Buscar: + + + + < + < + + + + > + > + + + + ... + ... + + + diff --git a/lib/translations/qtermwidget_fr.ts b/lib/translations/qtermwidget_fr.ts new file mode 100644 index 0000000..e69c667 --- /dev/null +++ b/lib/translations/qtermwidget_fr.ts @@ -0,0 +1,125 @@ + + + + + Konsole::TerminalDisplay + + + Size: XXX x XXX + Taille : XXX x XXX + + + + Size: %1 x %2 + Taille : %1 x %2 + + + + <qt>Output has been <a href="http://en.wikipedia.org/wiki/Flow_control">suspended</a> by pressing Ctrl+S. Press <b>Ctrl+Q</b> to resume.</qt> + <qt>La sortie a été <a href="http://en.wikipedia.org/wiki/Flow_control">suspendue</a> en pressant Ctrl+S. Pressez <b>Ctrl+Q</b> pour reprendre.</qt> + + + + Konsole::Vt102Emulation + + + No keyboard translator available. The information needed to convert key presses into characters to send to the terminal is missing. + Aucun traducteur disponible. L'information nécessaire à la conversion des touches pressées en caractères à envoyer au terminal est absente. + + + + QObject + + + + Un-named Color Scheme + Schéma des couleurs non nommé + + + + Accessible Color Scheme + Schéma des couleur accessible + + + + Open Link + Ouvrir le lien + + + + Copy Link Address + Copier l'adresse du lien + + + + Send Email To... + Envoyer un courriel à ... + + + + Copy Email Address + Copier l'adresse du courriel + + + + QTermWidget + + + Color Scheme Error + Erreur du schéma des couleurs + + + + Cannot load color scheme: %1 + Impossible de charger le schéma de couleurs : %1 + + + + SearchBar + + + SearchBar + Barre de recherche + + + + X + X + + + + Find: + Trouver : + + + + < + < + + + + > + > + + + + ... + ... + + + + Match case + Sensible à la casse + + + + Regular expression + Expression régulière + + + + Highlight all matches + Surbrillance de toutes les concordances + + + diff --git a/lib/translations/qtermwidget_he.ts b/lib/translations/qtermwidget_he.ts new file mode 100644 index 0000000..87d5406 --- /dev/null +++ b/lib/translations/qtermwidget_he.ts @@ -0,0 +1,125 @@ + + + + + Konsole::TerminalDisplay + + + Size: XXX x XXX + גודל: XXX × XXX + + + + Size: %1 x %2 + גודל: %1 × %2 + + + + <qt>Output has been <a href="http://en.wikipedia.org/wiki/Flow_control">suspended</a> by pressing Ctrl+S. Press <b>Ctrl+Q</b> to resume.</qt> + <qt>הפלט <a href="http://en.wikipedia.org/wiki/Flow_control">הושהה</a> בלחיצה על Ctrl+S. יש ללחוץ על <b>Ctrl+Q</b> כדי להמשיך.</qt> + + + + Konsole::Vt102Emulation + + + No keyboard translator available. The information needed to convert key presses into characters to send to the terminal is missing. + אין מתרגם מקלדת זמין. המידע שנדרש לצורך המרת לחיצות מקשים לתווים לשליחה למסוף חסר. + + + + QObject + + + + Un-named Color Scheme + ערכת צבעים ללא שם + + + + Accessible Color Scheme + ערכת צבעים נגישה + + + + Open Link + פתיחת קישור + + + + Copy Link Address + העתקת כתובת קישור + + + + Send Email To... + שליחת דוא״ל אל… + + + + Copy Email Address + העתקת כתובת דוא״ל + + + + QTermWidget + + + Color Scheme Error + שגיאת ערכת צבעים + + + + Cannot load color scheme: %1 + לא ניתן לטעון ערכת צבעים: %1 + + + + SearchBar + + + Match case + התאמת רישיות + + + + Regular expression + ביטוי רגולרי + + + + Highlight all matches + הדגשת כל המופעים + + + + SearchBar + סרגל חיפוש + + + + X + + + + + Find: + חיפוש: + + + + < + + + + + > + + + + + ... + + + + diff --git a/lib/translations/qtermwidget_hu.ts b/lib/translations/qtermwidget_hu.ts new file mode 100644 index 0000000..cb706d9 --- /dev/null +++ b/lib/translations/qtermwidget_hu.ts @@ -0,0 +1,125 @@ + + + + + Konsole::TerminalDisplay + + + Size: XXX x XXX + Méret: XXX x XXX + + + + Size: %1 x %2 + Méret: %1 x %2 + + + + <qt>Output has been <a href="http://en.wikipedia.org/wiki/Flow_control">suspended</a> by pressing Ctrl+S. Press <b>Ctrl+Q</b> to resume.</qt> + <qt>A kimenet <a href="http://en.wikipedia.org/wiki/Flow_control">el van nyomva</a> a Ctrl+S megnyomásával. Nyomj <b>Ctrl+Q -t</b> a visszatéréshez.</qt> + + + + Konsole::Vt102Emulation + + + No keyboard translator available. The information needed to convert key presses into characters to send to the terminal is missing. + Nincs billentyűzet átalakító. Hiányzik az információ, ami a billentyű lenyomásnak a terminálhoz küldendő karakterekké alakításához szükséges. + + + + QObject + + + + Un-named Color Scheme + Névtelen Színséma + + + + Accessible Color Scheme + Elérhető színséma + + + + Open Link + Link megnyitás + + + + Copy Link Address + Link cím másolás + + + + Send Email To... + Email küldés ... + + + + Copy Email Address + Email cím másolás + + + + QTermWidget + + + Color Scheme Error + Színséma hiba + + + + Cannot load color scheme: %1 + A %1 színséma elérhetetlen + + + + SearchBar + + + Match case + Nagybetű érzékeny + + + + Regular expression + Szaabályos kifejezés + + + + Highlight all matches + Találatok kiemelése + + + + SearchBar + Keresősáv + + + + X + + + + + Find: + Keres: + + + + < + + + + + > + + + + + ... + + + + diff --git a/lib/translations/qtermwidget_ja.ts b/lib/translations/qtermwidget_ja.ts new file mode 100644 index 0000000..aed78d2 --- /dev/null +++ b/lib/translations/qtermwidget_ja.ts @@ -0,0 +1,125 @@ + + + + + Konsole::TerminalDisplay + + + Size: XXX x XXX + + + + + Size: %1 x %2 + + + + + <qt>Output has been <a href="http://en.wikipedia.org/wiki/Flow_control">suspended</a> by pressing Ctrl+S. Press <b>Ctrl+Q</b> to resume.</qt> + + + + + Konsole::Vt102Emulation + + + No keyboard translator available. The information needed to convert key presses into characters to send to the terminal is missing. + + + + + QObject + + + + Un-named Color Scheme + 名前のないカラースキーム + + + + Accessible Color Scheme + アクセス可能なカラースキーム + + + + Open Link + リンクを開く + + + + Copy Link Address + リンクのアドレスをコピー + + + + Send Email To... + メールを送信... + + + + Copy Email Address + メールアドレスをコピー + + + + QTermWidget + + + Color Scheme Error + カラースキームのエラー + + + + Cannot load color scheme: %1 + カラースキームをロードすることができません: %1 + + + + SearchBar + + + Match case + + + + + Regular expression + 正規表現 + + + + Highlight all matches + 一致するものをハイライト + + + + SearchBar + サーチバー + + + + X + + + + + Find: + 探す: + + + + < + + + + + > + + + + + ... + + + + diff --git a/lib/translations/qtermwidget_lt.ts b/lib/translations/qtermwidget_lt.ts new file mode 100644 index 0000000..e6d0eeb --- /dev/null +++ b/lib/translations/qtermwidget_lt.ts @@ -0,0 +1,125 @@ + + + + + Konsole::TerminalDisplay + + + Size: XXX x XXX + Dydis: XXX x XXX + + + + Size: %1 x %2 + Dydis: %1 x %2 + + + + <qt>Output has been <a href="http://en.wikipedia.org/wiki/Flow_control">suspended</a> by pressing Ctrl+S. Press <b>Ctrl+Q</b> to resume.</qt> + <qt>Išvestis buvo <a href="http://en.wikipedia.org/wiki/Flow_control">pristabdyta,</a> paspaudžiant Ctrl(Vald)+S. Paspauskite <b>Ctrl(Vald)+Q</b>, norėdami pratęsti.</qt> + + + + Konsole::Vt102Emulation + + + No keyboard translator available. The information needed to convert key presses into characters to send to the terminal is missing. + Nėra prieinamas joks klaviatūros vertėjas. Informacijos, kurios reikia, norint konvertuoti klavišų paspaudimus į simbolius ir siųsti į terminalą, nėra. + + + + QObject + + + + Un-named Color Scheme + Nepavadintas spalvų rinkinys + + + + Accessible Color Scheme + Pasiekiamas spalvų rinkinys + + + + Open Link + Atverti nuorodą + + + + Copy Link Address + Kopijuoti nuorodos adresą + + + + Send Email To... + Siųsti el. paštą... + + + + Copy Email Address + Kopijuoti el. pašto adresą + + + + QTermWidget + + + Color Scheme Error + Spalvų rinkinio klaida + + + + Cannot load color scheme: %1 + Nepavyksta įkelti spalvų rinkinio: %1 + + + + SearchBar + + + Match case + Skirti raidžių dydį + + + + Regular expression + Reguliarusis reiškinys + + + + Highlight all matches + Paryškinti visus atitikmenis + + + + SearchBar + Paieškos juosta + + + + X + X + + + + Find: + Rasti: + + + + < + < + + + + > + > + + + + ... + ... + + + diff --git a/lib/translations/qtermwidget_pl.ts b/lib/translations/qtermwidget_pl.ts new file mode 100644 index 0000000..dc23dc3 --- /dev/null +++ b/lib/translations/qtermwidget_pl.ts @@ -0,0 +1,125 @@ + + + + + Konsole::TerminalDisplay + + + Size: XXX x XXX + Rozmiar: XXX x XXX + + + + Size: %1 x %2 + Rozmiar: %1 x %2 + + + + <qt>Output has been <a href="http://en.wikipedia.org/wiki/Flow_control">suspended</a> by pressing Ctrl+S. Press <b>Ctrl+Q</b> to resume.</qt> + <qt>Wyjście zostało <a href="http://en.wikipedia.org/wiki/Flow_control">wstrzymane</a> skrótem Ctrl+S. Wciśnij <b>Ctrl+Q</b> aby wznowić.</qt> + + + + Konsole::Vt102Emulation + + + No keyboard translator available. The information needed to convert key presses into characters to send to the terminal is missing. + Brak sterownika klawiatury. Nie wiadomo jak przełożyć wciśniecia przycisków na znaki wysyłane do terminalu. + + + + QObject + + + + Un-named Color Scheme + Nienazwana paleta + + + + Accessible Color Scheme + Paleta o zwiększonej przystępności + + + + Open Link + Przejdź pod adres + + + + Copy Link Address + Kopiuj adres łącza + + + + Send Email To... + Wyślij e-mail do… + + + + Copy Email Address + Kopiuj adres e-mail + + + + QTermWidget + + + Color Scheme Error + Błąd w palecie + + + + Cannot load color scheme: %1 + Nie można wczytać palety: %1 + + + + SearchBar + + + Match case + Rozróżniaj wielkość liter + + + + Regular expression + Wyrażenie regularne + + + + Highlight all matches + Podświetl wszystkie dopasowania + + + + SearchBar + Pasek wyszukiwania + + + + X + X + + + + Find: + Znajdź: + + + + < + < + + + + > + > + + + + ... + + + + diff --git a/lib/translations/qtermwidget_pt.ts b/lib/translations/qtermwidget_pt.ts new file mode 100644 index 0000000..bf29a92 --- /dev/null +++ b/lib/translations/qtermwidget_pt.ts @@ -0,0 +1,125 @@ + + + + + Konsole::TerminalDisplay + + + Size: XXX x XXX + Tamanho: XXX x XXX + + + + Size: %1 x %2 + Tamanho: %1 x %2 + + + + <qt>Output has been <a href="http://en.wikipedia.org/wiki/Flow_control">suspended</a> by pressing Ctrl+S. Press <b>Ctrl+Q</b> to resume.</qt> + <qt>O resultado foi <a href="http://en.wikipedia.org/wiki/Flow_control">suspenso</a> através de Ctrl+S. Prima <b>Ctrl+Q</b> para continuar.</qt> + + + + Konsole::Vt102Emulation + + + No keyboard translator available. The information needed to convert key presses into characters to send to the terminal is missing. + Não há tradutores de teclado disponíveis. A informação necessária para converter os toques das teclas em caracteres enviados ao terminal não existem. + + + + QObject + + + + Un-named Color Scheme + Esquema de cores sem nome + + + + Accessible Color Scheme + Esquema de cores acessível + + + + Open Link + Abrir ligação + + + + Copy Link Address + Copiar endereço da ligação + + + + Send Email To... + Enviar e-mail para... + + + + Copy Email Address + Copiar endereço de e-mail + + + + QTermWidget + + + Color Scheme Error + Erro no esquema de cores + + + + Cannot load color scheme: %1 + Incapaz de carregar o esquema: %1 + + + + SearchBar + + + Match case + Diferenciar maiúsculas/minúsculas + + + + Regular expression + Expressão regular + + + + Highlight all matches + Realçar todas as ocorrências + + + + SearchBar + Barra de pesquisa + + + + X + X + + + + Find: + Localizar: + + + + < + < + + + + > + > + + + + ... + ... + + + diff --git a/lib/translations/qtermwidget_tr.ts b/lib/translations/qtermwidget_tr.ts new file mode 100644 index 0000000..be6546a --- /dev/null +++ b/lib/translations/qtermwidget_tr.ts @@ -0,0 +1,125 @@ + + + + + Konsole::TerminalDisplay + + + Size: XXX x XXX + Boyut: XXX x XXX + + + + Size: %1 x %2 + Boyut: %1 x %2 + + + + <qt>Output has been <a href="http://en.wikipedia.org/wiki/Flow_control">suspended</a> by pressing Ctrl+S. Press <b>Ctrl+Q</b> to resume.</qt> + <qt>Çıktı <a href="http://en.wikipedia.org/wiki/Flow_control">suspended</a> Ctrl+S basınız. <b>Ctrl+Q</b> bas devam etmek için.</qt> + + + + Konsole::Vt102Emulation + + + No keyboard translator available. The information needed to convert key presses into characters to send to the terminal is missing. + Hiçbir klavye çevirici yok. Tuş takımlarını terminale göndermek için karakterlere dönüştürmek için gereken bilgi eksik. + + + + QObject + + + + Un-named Color Scheme + İsimsiz renk şeması + + + + Accessible Color Scheme + Erişilebilir Renk Şeması + + + + Open Link + Bağlantıyı Aç + + + + Copy Link Address + Bağlantı adresini kopyala + + + + Send Email To... + Eposta gönder... + + + + Copy Email Address + Eposta adresini kopyala + + + + QTermWidget + + + Color Scheme Error + Renk Şema Hatası + + + + Cannot load color scheme: %1 + Renk şeması yüklenemedi + + + + SearchBar + + + Match case + Tam eşleştir + + + + Regular expression + Düzenli ifade + + + + Highlight all matches + Tüm eşleşenleri vurgula + + + + SearchBar + + + + + X + + + + + Find: + + + + + < + + + + + > + + + + + ... + + + + diff --git a/lib/translations/qtermwidget_zh_CN.ts b/lib/translations/qtermwidget_zh_CN.ts new file mode 100644 index 0000000..acbd5b1 --- /dev/null +++ b/lib/translations/qtermwidget_zh_CN.ts @@ -0,0 +1,125 @@ + + + + + Konsole::TerminalDisplay + + + Size: XXX x XXX + 大小: XXX x XXX + + + + Size: %1 x %2 + 大小: %1 x %2 + + + + <qt>Output has been <a href="http://en.wikipedia.org/wiki/Flow_control">suspended</a> by pressing Ctrl+S. Press <b>Ctrl+Q</b> to resume.</qt> + <qt>输出已被 Ctrl+S <a href="http://en.wikipedia.org/wiki/Flow_control">暂停</a>。按 <b>Ctrl+Q</b> 复原。</qt> + + + + Konsole::Vt102Emulation + + + No keyboard translator available. The information needed to convert key presses into characters to send to the terminal is missing. + 没有可用的键码转换表。找不到需要把按键转换至符号以传送至终端的信息。 + + + + QObject + + + + Un-named Color Scheme + 未命名配色 + + + + Accessible Color Scheme + 可用配色 + + + + Open Link + 打开链接 + + + + Copy Link Address + 复制链接地址 + + + + Send Email To... + 发送邮件至... + + + + Copy Email Address + 复制邮件地址 + + + + QTermWidget + + + Color Scheme Error + 配色错误 + + + + Cannot load color scheme: %1 + 无法加载配色: %1 + + + + SearchBar + + + Match case + 匹配大小写 + + + + Regular expression + 正则表达式 + + + + Highlight all matches + 高亮所有匹配项 + + + + SearchBar + 搜索栏 + + + + X + + + + + Find: + 寻找: + + + + < + + + + + > + + + + + ... + + + + diff --git a/lib/translations/qtermwidget_zh_TW.ts b/lib/translations/qtermwidget_zh_TW.ts new file mode 100644 index 0000000..6750d13 --- /dev/null +++ b/lib/translations/qtermwidget_zh_TW.ts @@ -0,0 +1,125 @@ + + + + + Konsole::TerminalDisplay + + + Size: XXX x XXX + 大小:XXX x XXX + + + + Size: %1 x %2 + 大小:%1 x %2 + + + + <qt>Output has been <a href="http://en.wikipedia.org/wiki/Flow_control">suspended</a> by pressing Ctrl+S. Press <b>Ctrl+Q</b> to resume.</qt> + <qt>輸出已被Ctrl+S<a href="http://en.wikipedia.org/wiki/Flow_control">暫停</a>。按<b>Ctrl+Q</b>復原。</qt> + + + + Konsole::Vt102Emulation + + + No keyboard translator available. The information needed to convert key presses into characters to send to the terminal is missing. + 沒有可用的鍵碼轉換表。用來將按鍵轉換成終端機字元的資訊遺失。 + + + + QObject + + + + Un-named Color Scheme + 未命名的配色 + + + + Accessible Color Scheme + 可用的配色 + + + + Open Link + 開啟連結 + + + + Copy Link Address + 複製網址 + + + + Send Email To... + 傳送郵件給… + + + + Copy Email Address + 複製信箱地址 + + + + QTermWidget + + + Color Scheme Error + 配色錯誤 + + + + Cannot load color scheme: %1 + 無法載入配色:%1 + + + + SearchBar + + + Match case + 符合大小寫 + + + + Regular expression + 正規表示式 + + + + Highlight all matches + 標亮所有相符的項目 + + + + SearchBar + 搜尋列 + + + + X + X + + + + Find: + 搜尋: + + + + < + < + + + + > + > + + + + ... + ... + + + 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/__init__.py b/pyqt/__init__.py new file mode 100644 index 0000000..e69de29 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..0e558b7 --- /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) + + 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/sip/qtermwidget.sip b/pyqt/sip/qtermwidget.sip new file mode 100644 index 0000000..dccf076 --- /dev/null +++ b/pyqt/sip/qtermwidget.sip @@ -0,0 +1,117 @@ +%Module QTermWidget + +%ModuleHeaderCode +#pragma GCC visibility push(default) +%End + +%Import QtGui/QtGuimod.sip +%Import QtCore/QtCoremod.sip +%Import QtWidgets/QtWidgetsmod.sip + +class QTermWidget : QWidget { + +%TypeHeaderCode +#include <../lib/qtermwidget.h> +%End + +public: + enum ScrollBarPosition + { + NoScrollBar=0, + ScrollBarLeft=1, + ScrollBarRight=2 + }; + + enum class KeyboardCursorShape + { + BlockCursor=0, + UnderlineCursor=1, + IBeamCursor=2 + }; + + QTermWidget(int startnow = 1, QWidget *parent = 0); + ~QTermWidget(); + void startTerminalTeletype(); + QSize sizeHint() const; + void setTerminalSizeHint(bool on); + bool terminalSizeHint(); + void startShellProgram(); + int getShellPID(); + void changeDir(const QString & dir); + void setTerminalFont(QFont &font); + QFont getTerminalFont(); + void setTerminalOpacity(qreal level); + void setEnvironment(const QStringList & environment); + void setShellProgram(const QString & progname); + void setWorkingDirectory(const QString & dir); + QString workingDirectory(); + void setArgs(QStringList & args); + void setTextCodec(QTextCodec *codec); + void setColorScheme(const QString & name); + static QStringList availableColorSchemes(); + static void addCustomColorSchemeDir(const QString& custom_dir); + void setHistorySize(int lines); + void setScrollBarPosition(ScrollBarPosition); + void scrollToEnd(); + void sendText(QString &text); + void setFlowControlEnabled(bool enabled); + bool flowControlEnabled(); + void setFlowControlWarningEnabled(bool enabled); + static QStringList availableKeyBindings(); + QString keyBindings(); + void setMotionAfterPasting(int); + int historyLinesCount(); + int screenColumnsCount(); + void setSelectionStart(int row, int column); + void setSelectionEnd(int row, int column); + void getSelectionStart(int& row, int& column); + void getSelectionEnd(int& row, int& column); + QString selectedText(bool preserveLineBreaks = true); + void setMonitorActivity(bool); + void setMonitorSilence(bool); + void setSilenceTimeout(int seconds); + int getPtySlaveFd() const; + void setKeyboardCursorShape(KeyboardCursorShape shape); + void setAutoClose(bool); + QString title() const; + QString icon() const; +signals: + void finished(); + void copyAvailable(bool); + void termGetFocus(); + void termLostFocus(); + void termKeyPressed(QKeyEvent *); + void urlActivated(const QUrl&, bool fromContextMenu); + void bell(const QString& message); + void activity(); + void silence(); + void sendData(const char *,int); + void titleChanged(); + void receivedData(const QString &text); + void profileChanged(const QString & profile); +public slots: + void copyClipboard(); + void pasteClipboard(); + void pasteSelection(); + void zoomIn(); + void zoomOut(); + void setSize(const QSize &); + void setKeyBindings(const QString & kb); + void clear(); + void toggleShowSearchBar(); +protected: + virtual void resizeEvent(QResizeEvent *); +protected slots: + void sessionFinished(); + void selectionChanged(bool textSelected); +private: + void search(bool forwards, bool next); + void setZoom(int step); + void init(int startnow); +private slots: + void find(); + void findNext(); + void findPrevious(); + void matchFound(int startColumn, int startLine, int endColumn, int endLine); + void noMatchFound(); +};