pax_global_header00006660000000000000000000000064147547265430014533gustar00rootroot0000000000000052 comment=456eecc8b8a7b68b1839e67e33c3d5e1c4540fae deepin-terminal-5.9.51+dfsg/000077500000000000000000000000001475472654300156305ustar00rootroot00000000000000deepin-terminal-5.9.51+dfsg/.github/000077500000000000000000000000001475472654300171705ustar00rootroot00000000000000deepin-terminal-5.9.51+dfsg/.github/workflows/000077500000000000000000000000001475472654300212255ustar00rootroot00000000000000deepin-terminal-5.9.51+dfsg/.github/workflows/backup-to-gitlab.yml000066400000000000000000000006651475472654300251040ustar00rootroot00000000000000name: backup to gitlab on: [push] concurrency: group: ${{ github.workflow }} cancel-in-progress: true jobs: backup-to-gitlabwh: uses: linuxdeepin/.github/.github/workflows/backup-to-gitlabwh.yml@master secrets: BRIDGETOKEN: ${{ secrets.BRIDGETOKEN }} backup-to-gitee: uses: linuxdeepin/.github/.github/workflows/backup-to-gitee.yml@master secrets: GITEE_SYNC_TOKEN: ${{ secrets.GITEE_SYNC_TOKEN }} deepin-terminal-5.9.51+dfsg/.github/workflows/call-auto-tag.yml000066400000000000000000000005171475472654300244050ustar00rootroot00000000000000name: auto tag on: pull_request_target: types: [opened, synchronize, closed] paths: - "debian/changelog" concurrency: group: ${{ github.workflow }}-pull/${{ github.event.number }} cancel-in-progress: true jobs: auto_tag: uses: linuxdeepin/.github/.github/workflows/auto-tag.yml@master secrets: inherit deepin-terminal-5.9.51+dfsg/.github/workflows/call-build-deb.yml000066400000000000000000000007251475472654300245140ustar00rootroot00000000000000name: Call build-deb on: pull_request_target: paths-ignore: - ".github/workflows/**" types: [ opened, closed, synchronize ] concurrency: group: ${{ github.workflow }}-pull/${{ github.event.number }} cancel-in-progress: true jobs: check_job: if: github.event.action != 'closed' || github.event.pull_request.merged uses: linuxdeepin/.github/.github/workflows/build-deb.yml@master secrets: BridgeToken: ${{ secrets.BridgeToken }} deepin-terminal-5.9.51+dfsg/.github/workflows/call-build-distribution.yml000066400000000000000000000007661475472654300265060ustar00rootroot00000000000000name: Call build-distribution on: push: paths-ignore: - ".github/workflows/**" pull_request_target: paths-ignore: - ".github/workflows/**" jobs: check_job: uses: linuxdeepin/.github/.github/workflows/build-distribution.yml@master secrets: BUILD_GPG_PRIVATE_KEY: ${{ secrets.BUILD_GPG_PRIVATE_KEY }} BUILD_SSH_PRIVATE_KEY: ${{ secrets.BUILD_SSH_PRIVATE_KEY }} WEBDAV_PASSWD: ${{ secrets.WEBDAV_PASSWD }} WEBDAV_USER: ${{ secrets.WEBDAV_USER }} deepin-terminal-5.9.51+dfsg/.github/workflows/call-chatOps.yml000066400000000000000000000003201475472654300242550ustar00rootroot00000000000000name: chatOps on: issue_comment: types: [created] jobs: chatopt: uses: linuxdeepin/.github/.github/workflows/chatOps.yml@master secrets: APP_PRIVATE_KEY: ${{ secrets.APP_PRIVATE_KEY }} deepin-terminal-5.9.51+dfsg/.github/workflows/call-clacheck.yml000066400000000000000000000005251475472654300244200ustar00rootroot00000000000000name: Call CLA check on: issue_comment: types: [created] pull_request_target: types: [opened, closed, synchronize] concurrency: group: ${{ github.workflow }}-pull/${{ github.event.number }} cancel-in-progress: true jobs: clacheck: uses: linuxdeepin/.github/.github/workflows/cla-check.yml@master secrets: inherit deepin-terminal-5.9.51+dfsg/.github/workflows/call-commitlint.yml000066400000000000000000000003641475472654300250430ustar00rootroot00000000000000name: Call commitlint on: pull_request_target: concurrency: group: ${{ github.workflow }}-pull/${{ github.event.number }} cancel-in-progress: true jobs: check_job: uses: linuxdeepin/.github/.github/workflows/commitlint.yml@master deepin-terminal-5.9.51+dfsg/.github/workflows/call-license-check.yml000066400000000000000000000005521475472654300253600ustar00rootroot00000000000000name: Call License and README Check on: pull_request_target: types: [opened, synchronize, reopened] permissions: pull-requests: write contents: read concurrency: group: ${{ github.workflow }}-pull/${{ github.event.number }} cancel-in-progress: true jobs: license-check: uses: linuxdeepin/.github/.github/workflows/license-check.yml@master deepin-terminal-5.9.51+dfsg/.github/workflows/cppcheck.yml000066400000000000000000000012651475472654300235340ustar00rootroot00000000000000name: cppcheck on: pull_request_target: paths-ignore: - ".github/workflows/**" concurrency: group: ${{ github.workflow }}-pull/${{ github.event.number }} cancel-in-progress: true jobs: cppchceck: name: cppcheck runs-on: ubuntu-latest steps: - run: export - uses: actions/checkout@v2 with: ref: ${{ github.event.pull_request.head.sha }} persist-credentials: false - uses: linuxdeepin/action-cppcheck@main with: github_token: ${{ secrets.GITHUB_TOKEN }} repository: ${{ github.repository }} pull_request_id: ${{ github.event.pull_request.number }} allow_approve: false deepin-terminal-5.9.51+dfsg/.gitignore000066400000000000000000000001631475472654300176200ustar00rootroot00000000000000# User config *.user moc_*.h moc_*.cpp *.moc build/ .vscode/ build-*/ CMakeLists.txt.user deepin-terminal.pro.user deepin-terminal-5.9.51+dfsg/.gitmodules000066400000000000000000000001421475472654300200020ustar00rootroot00000000000000[submodule "test/googletest"] path = test/googletest url = https://github.com/google/googletest deepin-terminal-5.9.51+dfsg/.project.json000066400000000000000000000006261475472654300202530ustar00rootroot00000000000000 { "type": "homebrew", "3rdparty": ["./3rdparty"], "ignore": [".git", "translations", "debian", "color-schemes", "kb-layouts", "LineFont.src", "CMakeLists.txt.user", "README", "README.md", "CHANGELOG", "COPYING-CMAKE-SCRIPTS", "LICENSE", "LICENSE.*", "*.keytab", "*.spec", "*.cmake", "*.desktop", "./.tx", "*.qrc", "*.svg", "*.png", "*.qm", "*.ts"], "license": ["GPLv3"] } deepin-terminal-5.9.51+dfsg/.reuse/000077500000000000000000000000001475472654300170315ustar00rootroot00000000000000deepin-terminal-5.9.51+dfsg/.reuse/dep5000066400000000000000000000035011475472654300176100ustar00rootroot00000000000000Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Name: deepin-terminal Upstream-Contact: UnionTech Software Technology Co., Ltd. <> Source: https://github.com/linuxdeepin/deepin-terminal # ci Files: .github/* Copyright: None License: CC0-1.0 # gitignore Files: .gitignore Copyright: None License: CC0-1.0 # xml toml json conf yaml sh Files: *.toml *.json *conf *.yaml *.sh Copyright: None License: CC0-1.0 # debian Files: debian/* Copyright: None License: CC0-1.0 # rpm Files: rpm/* Copyright: None License: CC0-1.0 # Project file Files: *.pro *.prf *.pri *.qrc *CMakeLists.txt .tx/* Copyright: None License: CC0-1.0 # README Files: README.md README.zh_CN.md Copyright: UnionTech Software Technology Co., Ltd. License: CC-BY-4.0 # assets Files: assets/* Copyright: None License: LGPL-3.0-or-later # translations Files: translations/* Copyright: UnionTech Software Technology Co., Ltd. License: LGPL-3.0-or-later # src Files: src/* Copyright: UnionTech Software Technology Co., Ltd. License: GPL-3.0-or-later # tests Files: tests/* Copyright: UnionTech Software Technology Co., Ltd. License: GPL-3.0-or-later # FuzzyTest/src Files: FuzzyTest/src/* Copyright: UnionTech Software Technology Co., Ltd. License: GPL-3.0-or-later # FuzzyTest/include Files: FuzzyTest/include/* Copyright: UnionTech Software Technology Co., Ltd. License: Apache-2.0 WITH LLVM-exception # FuzzyTest/thirdlib Files: FuzzyTest/thirdlib/* Copyright: UnionTech Software Technology Co., Ltd. License: GPL-3.0-or-later # .gitmodules Files: .gitmodules Copyright: UnionTech Software Technology Co., Ltd. License: GPL-3.0-or-later # 3rdparty/terminalwidget Files: 3rdparty/terminalwidget/* Copyright: 2007-2008 by Robert Knight 1997,1998 by Lars Doelle License: BSD-3-Clause deepin-terminal-5.9.51+dfsg/.tx/000077500000000000000000000000001475472654300163415ustar00rootroot00000000000000deepin-terminal-5.9.51+dfsg/.tx/config000066400000000000000000000011611475472654300175300ustar00rootroot00000000000000[main] host = https://www.transifex.com minimum_perc = 80 mode = developer [deepin-terminal.deepin-terminal] file_filter = translations/deepin-terminal_.ts source_file = translations/deepin-terminal.ts source_lang = en_US type = QT [deepin-terminal.terminalwidget] file_filter = 3rdparty/terminalwidget/lib/translations/terminalwidget_.ts source_file = 3rdparty/terminalwidget/lib/translations/terminalwidget.ts source_lang = en_US type = QT [deepin-terminal.deepin-terminal-desktop] file_filter = translations/desktop/desktop_.ts source_file = translations/desktop/desktop.ts source_lang = en type = QT deepin-terminal-5.9.51+dfsg/.tx/deepin.conf000066400000000000000000000000311475472654300204460ustar00rootroot00000000000000[transifex] branch = m20 deepin-terminal-5.9.51+dfsg/.tx/ts2desktop000066400000000000000000000002501475472654300203630ustar00rootroot00000000000000DESKTOP_TEMP_FILE=deepin-terminal.desktop.tmp DESKTOP_SOURCE_FILE=deepin-terminal.desktop DESKTOP_DEST_FILE=deepin-terminal.desktop DESKTOP_TS_DIR=translations/desktop deepin-terminal-5.9.51+dfsg/3rdparty/000077500000000000000000000000001475472654300174005ustar00rootroot00000000000000deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/000077500000000000000000000000001475472654300224175ustar00rootroot00000000000000deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/AUTHORS000066400000000000000000000007011475472654300234650ustar00rootroot00000000000000Originally forked from Konsole by Revived by Petr Vanek Contributors: Adam Treat Chris Mueller Christian Surlykke Daniel O'Neill Francisco Ballina Georg Rudoy <0xd34df00d@gmail.com> Jerome Leclanche Petr Vanek @kulti deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/CHANGELOG000066400000000000000000000333211475472654300236330ustar00rootroot00000000000000qtermwidget-0.14.1 / 2019-02-25 =============================== * Bumped version to 0.14.1 * Only translations was changed. qtermwidget-0.14.0 / 2019-01-25 =============================== * Bumped version to 0.14.0 The big bump was needed to prevent conflicts with translations that were former built out of lxqt-l10n and have version 0.13.0 * Clarify the licenses used in qtermwidget and added the missed root licenses * Implementation fixes: - kpty: use openpty() on mac - kpty: make it work on OpenBSD - kptyprocess: ensure .bash_history is correctly written out - kb-layouts: Make Backspace behaves the same as xterm - tools: Drop the ability to bundle kb-layouts and colorschemes - SearchBar: Fix visual glitches in search-bar - TerminalDisplay: Fixed link mouseover after recent changes - TerminalDisplay: Redraw cursor after cursor type changed - Vt102Emulation: Fix handling of ST (String Terminator) for OSC (Operating System Commands) - qterminal: Correct deleting of HotSpot list items - qterminal: Removed unnecessary checks - ColorScheme: Fixed local variable will be copied despite being returned by name - ColorScheme: Fixed error return-std-move - Removed unnecessary checks - Suppressed compilation warnings - Don't use automatic string conversions - Marked some functions const - Implemented terminal margins * Improved cmake scripting - Set cmake_minimum_required to 3.1.0 - Removed locale compile definitons - Removed QUIET from find_package * Moved translations from lxqt-l10n back to qtermwidget - Removed obsolete translation fuctionality - Added translation promo in README.md * Translation updates 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 qtermwidget-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 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) qtermwidget-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. qtermwidget-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. qtermwidget-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 qtermwidget-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 deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/CMakeLists.txt000066400000000000000000000242331475472654300251630ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.1.0 FATAL_ERROR) # CMP0000: Call the cmake_minimum_required() command at the beginning of the top-level # CMakeLists.txt file even before calling the project() command. # The cmake_minimum_required(VERSION) command implicitly invokes the cmake_policy(VERSION) # command to specify that the current project code is written for the given range of CMake # versions. project(terminalwidget) include(GNUInstallDirs) include(GenerateExportHeader) include(CMakePackageConfigHelpers) include(CheckFunctionExists) include(CheckIncludeFile) link_libraries(uchardet) link_libraries(chardet) pkg_check_modules(chardet REQUIRED chardet) include_directories(${chardet_INCLUDE_DIRS}) link_directories(${chardet_LIBRARY_DIRS}) option(UPDATE_TRANSLATIONS "Update source translation translations/*.ts files" OFF) option(BUILD_EXAMPLE "Build example application. Default OFF." OFF) option(TERMINALWIDGET_USE_UTEMPTER "Uses the libutempter library. Mainly for FreeBSD" OFF) option(TERMINALWIDGET_BUILD_PYTHON_BINDING "Build python binding" OFF) option(USE_UTF8PROC "Use libutf8proc for better Unicode support. Default OFF" OFF) # just change version for releases set(TERMINALWIDGET_VERSION_MAJOR "0") set(TERMINALWIDGET_VERSION_MINOR "14") set(TERMINALWIDGET_VERSION_PATCH "1") set(TERMINALWIDGET_VERSION "${TERMINALWIDGET_VERSION_MAJOR}.${TERMINALWIDGET_VERSION_MINOR}.${TERMINALWIDGET_VERSION_PATCH}") # additional cmake files set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PROJECT_SOURCE_DIR}/cmake") set(CMAKE_INCLUDE_CURRENT_DIR ON) set(CMAKE_INSTALL_PREFIX "/usr") # Minimum Versions set(QT_MINIMUM_VERSION "5.7.1") set(LXQTBT_MINIMUM_VERSION "0.6.0") find_package(Qt5Widgets "${QT_MINIMUM_VERSION}" REQUIRED) find_package(Qt5LinguistTools "${QT_MINIMUM_VERSION}" REQUIRED) find_package(lxqt-build-tools ${LXQTBT_MINIMUM_VERSION} REQUIRED) find_package(ICU COMPONENTS i18n uc REQUIRED) if(USE_UTF8PROC) find_package(Utf8Proc REQUIRED) endif() #注释掉下面这行,否则无法支持命令行cmake构建 #include(LXQtPreventInSourceBuilds) include(LXQtTranslateTs) include(LXQtCompilerSettings NO_POLICY_SCOPE) include(LXQtCreatePkgConfigFile) if(APPLE) if(CMAKE_VERSION VERSION_GREATER 3.9) cmake_policy(SET CMP0068 NEW) set(CMAKE_BUILD_WITH_INSTALL_NAME_DIR ON) endif() endif() set(TERMINALWIDGET_LIBRARY_NAME terminalwidget5) remove_definitions(-DQT_NO_CAST_FROM_ASCII -DQT_NO_CAST_TO_ASCII -DQT_NO_CAST_FROM_BYTEARRAY) # main library set(SRCS lib/BlockArray.cpp lib/ColorScheme.cpp lib/CharacterFormat.cpp lib/Emulation.cpp lib/Filter.cpp lib/history/HistoryFile.cpp lib/history/HistoryScroll.cpp lib/history/HistoryScrollFile.cpp lib/history/HistoryScrollNone.cpp lib/history/HistoryType.cpp lib/history/HistoryTypeFile.cpp lib/history/HistoryTypeNone.cpp lib/history/compact/CompactHistoryScroll.cpp lib/history/compact/CompactHistoryType.cpp lib/HistorySearch.cpp lib/KeyboardTranslator.cpp lib/konsole_wcwidth.cpp lib/kprocess.cpp lib/kpty.cpp lib/kptydevice.cpp lib/kptyprocess.cpp lib/ProcessInfo.cpp lib/Pty.cpp lib/qtermwidget.cpp lib/Screen.cpp lib/ScreenWindow.cpp lib/SearchBar.cpp lib/Session.cpp lib/SessionManager.cpp lib/ShellCommand.cpp lib/TerminalCharacterDecoder.cpp lib/TerminalDisplay.cpp lib/tools.cpp lib/Vt102Emulation.cpp lib/EscapeSequenceUrlExtractor.cpp lib/encodes/detectcode.cpp ) # Only the Headers that need to be moc'd go here set(HDRS lib/Emulation.h lib/Filter.h lib/history/HistoryFile.h lib/history/HistoryScroll.h lib/history/HistoryScrollFile.h lib/history/HistoryScrollNone.h lib/history/HistoryType.h lib/history/HistoryTypeFile.h lib/history/HistoryTypeNone.h lib/history/compact/CompactHistoryScroll.h lib/history/compact/CompactHistoryType.h lib/HistorySearch.h lib/kprocess.h lib/kptydevice.h lib/kptyprocess.h lib/ProcessInfo.h lib/Pty.h lib/qtermwidget.h lib/ScreenWindow.h lib/SearchBar.h lib/Session.h lib/SessionManager.h lib/TerminalDisplay.h lib/Vt102Emulation.h lib/EscapeSequenceUrlExtractor.h lib/encodes/detectcode.h ) set(UI lib/SearchBar.ui ) # for distribution set(HDRS_DISTRIB lib/qtermwidget.h lib/Emulation.h lib/Filter.h lib/Session.h lib/SessionManager.h lib/history/HistoryFile.h lib/history/HistoryScroll.h lib/history/HistoryScrollFile.h lib/history/HistoryScrollNone.h lib/history/HistoryType.h lib/history/HistoryTypeFile.h lib/history/HistoryTypeNone.h lib/history/compact/CompactHistoryScroll.h lib/history/compact/CompactHistoryType.h lib/BlockArray.h lib/Character.h lib/CharacterColor.h lib/TerminalDisplay.h ) # dirs set(KB_LAYOUT_DIR "${CMAKE_INSTALL_FULL_DATADIR}/${TERMINALWIDGET_LIBRARY_NAME}/kb-layouts") message(STATUS "Keyboard layouts will be installed in: ${KB_LAYOUT_DIR}") set(COLORSCHEMES_DIR "${CMAKE_INSTALL_FULL_DATADIR}/${TERMINALWIDGET_LIBRARY_NAME}/color-schemes") message(STATUS "Color schemes will be installed in: ${COLORSCHEMES_DIR}" ) set(TRANSLATIONS_DIR "${CMAKE_INSTALL_FULL_DATADIR}/${TERMINALWIDGET_LIBRARY_NAME}/translations") message(STATUS "Translations will be installed in: ${TRANSLATIONS_DIR}") set(TERMINALWIDGET_INCLUDE_DIR "${CMAKE_INSTALL_FULL_INCLUDEDIR}/${TERMINALWIDGET_LIBRARY_NAME}") CHECK_FUNCTION_EXISTS(updwtmpx HAVE_UPDWTMPX) qt5_wrap_cpp(MOCS ${HDRS}) qt5_wrap_ui(UI_SRCS ${UI}) set(PKG_CONFIG_REQ "Qt5Widgets") lxqt_translate_ts(TERMINALWIDGET_QM TRANSLATION_DIR "lib/translations" UPDATE_TRANSLATIONS ${UPDATE_TRANSLATIONS} SOURCES ${SRCS} ${HDRS} ${UI} INSTALL_DIR ${TRANSLATIONS_DIR} COMPONENT Runtime ) add_library(${TERMINALWIDGET_LIBRARY_NAME} SHARED ${SRCS} ${MOCS} ${UI_SRCS} ${TERMINALWIDGET_QM}) target_link_libraries(${TERMINALWIDGET_LIBRARY_NAME} Qt5::Widgets ICU::i18n ICU::uc -lm uchardet chardet ) if (USE_TEST) #仅在单元测试模式下设置fvisibility为default target_compile_options(${TERMINALWIDGET_LIBRARY_NAME} PUBLIC "-fvisibility=default") endif() set_target_properties( ${TERMINALWIDGET_LIBRARY_NAME} PROPERTIES SOVERSION ${TERMINALWIDGET_VERSION_MAJOR} VERSION ${TERMINALWIDGET_VERSION} ) if(APPLE) target_compile_definitions(${TERMINALWIDGET_LIBRARY_NAME} PRIVATE "HAVE_UTMPX" "UTMPX_COMPAT" ) endif() if(HAVE_UPDWTMPX) target_compile_definitions(${TERMINALWIDGET_LIBRARY_NAME} PRIVATE "HAVE_UPDWTMPX" ) endif() if (TERMINALWIDGET_USE_UTEMPTER) CHECK_INCLUDE_FILE(utempter.h HAVE_UTEMPTER) if (HAVE_UTEMPTER) target_compile_definitions(${TERMINALWIDGET_LIBRARY_NAME} PRIVATE "HAVE_UTEMPTER" ) target_link_libraries(${TERMINALWIDGET_LIBRARY_NAME} ulog) endif() endif() if (UTF8PROC_FOUND) target_compile_definitions(${TERMINALWIDGET_LIBRARY_NAME} PRIVATE "HAVE_UTF8PROC" ) target_include_directories(${TERMINALWIDGET_LIBRARY_NAME} INTERFACE ${UTF8PROC_INCLUDE_DIRS} ) target_link_libraries(${TERMINALWIDGET_LIBRARY_NAME} ${UTF8PROC_LIBRARIES} ) string(APPEND PKG_CONFIG_REQ ", libutf8proc") endif() if(APPLE) set (CMAKE_SKIP_RPATH 1) # this is a must to load the lib correctly set_target_properties(${TERMINALWIDGET_LIBRARY_NAME} PROPERTIES INSTALL_NAME_DIR ${CMAKE_INSTALL_FULL_LIBDIR}) endif() target_compile_definitions(${TERMINALWIDGET_LIBRARY_NAME} PRIVATE "KB_LAYOUT_DIR=\"${KB_LAYOUT_DIR}\"" "COLORSCHEMES_DIR=\"${COLORSCHEMES_DIR}\"" "TRANSLATIONS_DIR=\"${TRANSLATIONS_DIR}\"" "HAVE_POSIX_OPENPT" "HAVE_SYS_TIME_H" ) generate_export_header(${TERMINALWIDGET_LIBRARY_NAME} EXPORT_FILE_NAME "${CMAKE_CURRENT_BINARY_DIR}/lib/qtermwidget_export.h" EXPORT_MACRO_NAME TERMINALWIDGET_EXPORT ) target_include_directories(${TERMINALWIDGET_LIBRARY_NAME} PUBLIC "$" "$" INTERFACE "$" "$" ) write_basic_package_version_file( "${CMAKE_BINARY_DIR}/${TERMINALWIDGET_LIBRARY_NAME}-config-version.cmake" VERSION ${TERMINALWIDGET_VERSION} COMPATIBILITY AnyNewerVersion ) install(FILES "${CMAKE_BINARY_DIR}/${TERMINALWIDGET_LIBRARY_NAME}-config-version.cmake" DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${TERMINALWIDGET_LIBRARY_NAME}" COMPONENT Devel ) install(EXPORT "${TERMINALWIDGET_LIBRARY_NAME}-targets" DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${TERMINALWIDGET_LIBRARY_NAME}" COMPONENT Devel ) install(FILES ${HDRS_DISTRIB} "${CMAKE_CURRENT_BINARY_DIR}/lib/qtermwidget_export.h" DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/${TERMINALWIDGET_LIBRARY_NAME}" COMPONENT Devel ) # keyboard layouts install(DIRECTORY lib/kb-layouts/ DESTINATION "${KB_LAYOUT_DIR}" COMPONENT Runtime FILES_MATCHING PATTERN "*.keytab" ) # color schemes install(DIRECTORY lib/color-schemes/ DESTINATION "${COLORSCHEMES_DIR}" COMPONENT Runtime FILES_MATCHING PATTERN "*.*schem*" ) lxqt_create_pkgconfig_file( PACKAGE_NAME ${TERMINALWIDGET_LIBRARY_NAME} DESCRIPTIVE_NAME ${TERMINALWIDGET_LIBRARY_NAME} DESCRIPTION "TerminalWidget library for Qt ${TERMINALWIDGET_VERSION_MAJOR}.x" INCLUDEDIRS ${TERMINALWIDGET_LIBRARY_NAME} LIBS ${TERMINALWIDGET_LIBRARY_NAME} REQUIRES ${PKG_CONFIG_REQ} VERSION ${TERMINALWIDGET_VERSION} INSTALL COMPONENT Devel ) install(TARGETS ${TERMINALWIDGET_LIBRARY_NAME} DESTINATION "${CMAKE_INSTALL_LIBDIR}" EXPORT "${TERMINALWIDGET_LIBRARY_NAME}-targets" LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" PUBLIC_HEADER COMPONENT Runtime ) export(TARGETS ${TERMINALWIDGET_LIBRARY_NAME} FILE "${CMAKE_BINARY_DIR}/${TERMINALWIDGET_LIBRARY_NAME}-targets.cmake" EXPORT_LINK_INTERFACE_LIBRARIES ) # end of main library deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/COPYING-CMAKE-SCRIPTS000066400000000000000000000000241475472654300254110ustar00rootroot00000000000000LICENSE.BSD-3-clausedeepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/LICENSE000066400000000000000000000355641475472654300234410ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/LICENSE.BSD-3-clause000066400000000000000000000027331475472654300254520ustar00rootroot00000000000000Copyright (c) The Regents of the University of California. All rights reserved. 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 above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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. deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/LICENSE.LGPL2+000066400000000000000000000614471475472654300243320ustar00rootroot00000000000000 GNU LIBRARY GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1991 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the library GPL. It is numbered 2 because it goes with version 2 of the ordinary GPL.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Library General Public License, applies to some specially designated Free Software Foundation software, and to any other libraries whose authors decide to use it. You can use it for your libraries, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library, or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link a program with the library, you must provide complete object files to the recipients so that they can relink them with the library, after making changes to the library and recompiling it. And you must show them these terms so they know their rights. Our method of protecting your rights has two steps: (1) copyright the library, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the library. Also, for each distributor's protection, we want to make certain that everyone understands that there is no warranty for this free library. If the library is modified by someone else and passed on, we want its recipients to know that what they have is not the original version, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that companies distributing free software will individually obtain patent licenses, thus in effect transforming the program into proprietary software. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License, which was designed for utility programs. This license, the GNU Library General Public License, applies to certain designated libraries. This license is quite different from the ordinary one; be sure to read it in full, and don't assume that anything in it is the same as in the ordinary license. The reason we have a separate public license for some libraries is that they blur the distinction we usually make between modifying or adding to a program and simply using it. Linking a program with a library, without changing the library, is in some sense simply using the library, and is analogous to running a utility program or application program. However, in a textual and legal sense, the linked executable is a combined work, a derivative of the original library, and the ordinary General Public License treats it as such. Because of this blurred distinction, using the ordinary General Public License for libraries did not effectively promote software sharing, because most developers did not use the libraries. We concluded that weaker conditions might promote sharing better. However, unrestricted linking of non-free programs would deprive the users of those programs of all benefit from the free status of the libraries themselves. This Library General Public License is intended to permit developers of non-free programs to use free libraries, while preserving your freedom as a user of such programs to change the free libraries that are incorporated in them. (We have not seen how to achieve this as regards changes in header files, but we have achieved it as regards changes in the actual functions of the Library.) The hope is that this will lead to faster development of free libraries. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, while the latter only works together with the library. Note that it is possible for a library to be covered by the ordinary General Public License rather than by this special one. GNU LIBRARY GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Library General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also compile or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. c) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. d) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Library General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), 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 Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. 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 library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; 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. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/000077500000000000000000000000001475472654300231655ustar00rootroot00000000000000deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/BlockArray.cpp000066400000000000000000000176371475472654300257400ustar00rootroot00000000000000/* This file is part of Konsole, an X terminal. Copyright (C) 2000 by Stephan Kulow 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. Rewritten for QT4 by e_k , Copyright (C)2008 */ #include // Own #include "BlockArray.h" // System #include #include #include #include using namespace Konsole; static int blocksize = 0; BlockArray::BlockArray() : size(0), current(size_t(-1)), index(size_t(-1)), lastmap(nullptr), lastmap_index(size_t(-1)), lastblock(nullptr), ion(-1), length(0) { // lastmap_index = index = current = size_t(-1); if (blocksize == 0) { blocksize = ((sizeof(Block) / getpagesize()) + 1) * getpagesize(); } } BlockArray::~BlockArray() { setHistorySize(0); Q_ASSERT(!lastblock); } size_t BlockArray::append(Block * block) { if (!size) { return size_t(-1); } ++current; if (current >= size) { current = 0; } int rc; rc = lseek(ion, current * blocksize, SEEK_SET); if (rc < 0) { perror("HistoryBuffer::add.seek"); setHistorySize(0); return size_t(-1); } rc = write(ion, block, blocksize); if (rc < 0) { perror("HistoryBuffer::add.write"); setHistorySize(0); return size_t(-1); } length++; if (length > size) { length = size; } ++index; delete block; return current; } size_t BlockArray::newBlock() { if (!size) { return size_t(-1); } append(lastblock); lastblock = new Block(); return index + 1; } Block * BlockArray::lastBlock() const { return lastblock; } bool BlockArray::has(size_t i) const { if (i == index + 1) { return true; } if (i > index) { return false; } if (index - i >= length) { return false; } return true; } const Block * BlockArray::at(size_t i) { if (i == index + 1) { return lastblock; } if (i == lastmap_index) { return lastmap; } if (i > index) { return nullptr; } // if (index - i >= length) { // kDebug(1211) << "BlockArray::at() index - i >= length\n"; // return 0; // } size_t j = i; // (current - (index - i) + (index/size+1)*size) % size ; Q_ASSERT(j < size); unmap(); Block * block = (Block *)mmap(nullptr, blocksize, PROT_READ, MAP_PRIVATE, ion, j * blocksize); if (block == (Block *)-1) { perror("mmap"); return nullptr; } lastmap = block; lastmap_index = i; return block; } void BlockArray::unmap() { if (lastmap) { int res = munmap((char *)lastmap, blocksize); if (res < 0) { perror("munmap"); } } lastmap = nullptr; lastmap_index = size_t(-1); } bool BlockArray::setSize(size_t newsize) { return setHistorySize(newsize * 1024 / blocksize); } bool BlockArray::setHistorySize(size_t newsize) { // kDebug(1211) << "setHistorySize " << size << " " << newsize; if (size == newsize) { return false; } unmap(); if (!newsize) { delete lastblock; lastblock = nullptr; if (ion >= 0) { close(ion); } ion = -1; current = size_t(-1); return true; } if (!size) { FILE * tmp = tmpfile(); if (!tmp) { perror("konsole: cannot open temp file.\n"); } else { ion = dup(fileno(tmp)); if (ion<0) { perror("konsole: cannot dup temp file.\n"); fclose(tmp); } } if (ion < 0) { return false; } Q_ASSERT(!lastblock); lastblock = new Block(); size = newsize; return false; } if (newsize > size) { increaseBuffer(); size = newsize; return false; } else { decreaseBuffer(newsize); int status = ftruncate(ion, length*blocksize); if (status < 0) { perror("ftruncate"); } size = newsize; return true; } } void moveBlock(FILE * fion, int cursor, int newpos, char * buffer2) { int res = fseek(fion, cursor * blocksize, SEEK_SET); if (res) { perror("fseek"); } res = fread(buffer2, blocksize, 1, fion); if (res != 1) { perror("fread"); } res = fseek(fion, newpos * blocksize, SEEK_SET); if (res) { perror("fseek"); } res = fwrite(buffer2, blocksize, 1, fion); if (res != 1) { perror("fwrite"); } // printf("moving block %d to %d\n", cursor, newpos); } void BlockArray::decreaseBuffer(size_t newsize) { if (index < newsize) { // still fits in whole return; } int offset = (current - (newsize - 1) + size) % size; if (!offset) { return; } // The Block constructor could do somthing in future... char * buffer1 = new char[blocksize]; FILE * fion = fdopen(dup(ion), "w+b"); if (!fion) { delete [] buffer1; perror("fdopen/dup"); return; } int firstblock; if (current <= newsize) { firstblock = current + 1; } else { firstblock = 0; } //size_t oldpos; for (size_t i = 0, cursor=firstblock; i < newsize; i++) { size_t oldpos = (size + cursor + offset) % size; moveBlock(fion, oldpos, cursor, buffer1); if (oldpos < newsize) { cursor = oldpos; } else { cursor++; } } current = newsize - 1; length = newsize; delete [] buffer1; fclose(fion); } void BlockArray::increaseBuffer() { if (index < size) { // not even wrapped once return; } int offset = (current + size + 1) % size; if (!offset) { // no moving needed return; } // The Block constructor could do somthing in future... char * buffer1 = new char[blocksize]; char * buffer2 = new char[blocksize]; int runs = 1; int bpr = size; // blocks per run if (size % offset == 0) { bpr = size / offset; runs = offset; } FILE * fion = fdopen(dup(ion), "w+b"); if (!fion) { perror("fdopen/dup"); delete [] buffer1; delete [] buffer2; return; } //int res; for (int i = 0; i < runs; i++) { // free one block in chain int firstblock = (offset + i) % size; int res = fseek(fion, firstblock * blocksize, SEEK_SET); if (res) { perror("fseek"); } res = fread(buffer1, blocksize, 1, fion); if (res != 1) { perror("fread"); } //int newpos = 0; for (int j = 1, cursor=firstblock; j < bpr; j++) { cursor = (cursor + offset) % size; int newpos = (cursor - offset + size) % size; moveBlock(fion, cursor, newpos, buffer2); } res = fseek(fion, i * blocksize, SEEK_SET); if (res) { perror("fseek"); } res = fwrite(buffer1, blocksize, 1, fion); if (res != 1) { perror("fwrite"); } } current = size - 1; length = size; delete [] buffer1; delete [] buffer2; fclose(fion); } deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/BlockArray.h000066400000000000000000000062231475472654300253720ustar00rootroot00000000000000/* This file is part of Konsole, an X terminal. Copyright (C) 2000 by Stephan Kulow 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. Rewritten for QT4 by e_k , Copyright (C)2008 */ #ifndef BLOCKARRAY_H #define BLOCKARRAY_H #include //#error Do not use in KDE 2.1 #define QTERMWIDGET_BLOCKSIZE (1 << 12) #define ENTRIES ((QTERMWIDGET_BLOCKSIZE - sizeof(size_t) ) / sizeof(unsigned char)) namespace Konsole { struct Block { Block() { memset((void*)data, 0, sizeof(data)); size = 0; } unsigned char data[ENTRIES]; size_t size; }; // /////////////////////////////////////////////////////// class BlockArray { public: /** * Creates a history file for holding * maximal size blocks. If more blocks * are requested, then it drops earlier * added ones. */ BlockArray(); /// destructor ~BlockArray(); /** * adds the Block at the end of history. * This may drop other blocks. * * The ownership on the block is transfered. * An unique index number is returned for accessing * it later (if not yet dropped then) * * Note, that the block may be dropped completely * if history is turned off. */ size_t append(Block * block); /** * gets the block at the index. Function may return * 0 if the block isn't available any more. * * The returned block is strictly readonly as only * maped in memory - and will be invalid on the next * operation on this class. */ const Block * at(size_t index); /** * reorders blocks as needed. If newsize is null, * the history is emptied completely. The indices * returned on append won't change their semantic, * but they may not be valid after this call. */ bool setHistorySize(size_t newsize); size_t newBlock(); Block * lastBlock() const; /** * Convenient function to set the size in KBytes * instead of blocks */ bool setSize(size_t newsize); size_t len() const { return length; } bool has(size_t index) const; size_t getCurrent() const { return current; } private: void unmap(); void increaseBuffer(); void decreaseBuffer(size_t newsize); size_t size; // current always shows to the last inserted block size_t current; size_t index; Block * lastmap; size_t lastmap_index; Block * lastblock; int ion; size_t length; }; } #endif deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/Character.h000066400000000000000000000230701475472654300252340ustar00rootroot00000000000000/* This file is part of Konsole, KDE's terminal. Copyright 2007-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 (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. */ #ifndef CHARACTER_H #define CHARACTER_H // Qt #include #include // Local #include "CharacterColor.h" #include "konsole_wcwidth.h" namespace Konsole { typedef unsigned char LineProperty; static const int LINE_DEFAULT = 0; static const int LINE_WRAPPED = (1 << 0); static const int LINE_DOUBLEWIDTH = (1 << 1); static const int LINE_DOUBLEHEIGHT = (1 << 2); static const int LINE_DOUBLEHEIGHT_TOP = (1 << 2); static const int LINE_DOUBLEHEIGHT_BOTTOM = (1 << 3); #define DEFAULT_RENDITION 0 #define RE_BOLD (1 << 0) #define RE_BLINK (1 << 1) #define RE_UNDERLINE (1 << 2) #define RE_REVERSE (1 << 3) // Screen only #define RE_INTENSIVE (1 << 3) // Widget only #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) /** * Unicode character in the range of U+2500 ~ U+257F are known as line * characters, or box-drawing characters. Currently, konsole draws those * characters itself, instead of using the glyph provided by the font. * Unfortunately, the triple and quadruple dash lines (┄┅┆┇┈┉┊┋) are too * detailed too be drawn cleanly at normal font scales without anti * -aliasing, so those are drawn as regular characters. */ inline bool isSupportedLineChar(quint16 codePoint) { return (codePoint & 0xFF80) == 0x2500 // Unicode block: Mathematical Symbols - Box Drawing && !(0x2504 <= codePoint && codePoint <= 0x250B); // Triple and quadruple dash range } /** * A single character in the terminal which consists of a unicode character * value, foreground and background colors and a set of rendition attributes * which specify how it should be drawn. */ class Character { public: /** * Constructs a new character. * * @param _c The unicode character value of this character. * @param _f The foreground color used to draw the character. * @param _b The color used to draw the character's background. * @param _r A set of rendition flags which specify how this character is to be drawn. */ inline Character(quint16 _c = ' ', CharacterColor _f = CharacterColor(COLOR_SPACE_DEFAULT,DEFAULT_FORE_COLOR), CharacterColor _b = CharacterColor(COLOR_SPACE_DEFAULT,DEFAULT_BACK_COLOR), quint8 _r = DEFAULT_RENDITION) : character(_c), rendition(_r), foregroundColor(_f), backgroundColor(_b) {} union { /** The unicode character value for this character. */ uint 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; }; /** A combination of RENDITION flags which specify options for drawing the character. */ quint8 rendition; /** The foreground color used to draw this character. */ 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. */ bool isTransparent(const ColorEntry* palette) const; /** * 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. */ 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. */ friend bool operator == (const Character& a, const Character& b); /** * Compares two characters and returns true if they have different unicode character values, * renditions or colors. */ friend bool operator != (const Character& a, const Character& b); inline bool isLineChar() const { if (rendition & RE_EXTENDED_CHAR) { return false; } else { return isSupportedLineChar(character); } } inline bool isSpace() const { if (rendition & RE_EXTENDED_CHAR) { return false; } else { return QChar(character).isSpace(); } } inline int width() const { return width(character); } static int width(uint ucs4) { return characterWidth(ucs4); } static int stringWidth(const uint *ucs4Str, int len) { int w = 0; for (int i = 0; i < len; ++i) { w += width(ucs4Str[i]); } return w; } inline static int stringWidth(const QString &str) { QVector ucs4Str = str.toUcs4(); return stringWidth(ucs4Str.constData(), ucs4Str.length()); } }; inline bool operator == (const Character& a, const Character& b) { 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 !operator==(a, b); } inline bool Character::isTransparent(const ColorEntry* base) const { return ((backgroundColor._colorSpace == COLOR_SPACE_DEFAULT) && base[backgroundColor._u+0+(backgroundColor._v?BASE_COLORS:0)].transparent) || ((backgroundColor._colorSpace == COLOR_SPACE_SYSTEM) && base[backgroundColor._u+2+(backgroundColor._v?BASE_COLORS:0)].transparent); } inline bool Character::equalsFormat(const Character& other) const { return backgroundColor == other.backgroundColor && foregroundColor == other.foregroundColor && rendition == other.rendition; } inline ColorEntry::FontWeight Character::fontWeight(const ColorEntry* base) const { if (backgroundColor._colorSpace == COLOR_SPACE_DEFAULT) return base[backgroundColor._u+0+(backgroundColor._v?BASE_COLORS:0)].fontWeight; else if (backgroundColor._colorSpace == COLOR_SPACE_SYSTEM) return base[backgroundColor._u+2+(backgroundColor._v?BASE_COLORS:0)].fontWeight; else return ColorEntry::UseCurrentFormat; } extern unsigned short vt100_graphics[32]; /** * A table which stores sequences of unicode characters, referenced * by hash keys. The hash key itself is the same size as a unicode * character ( ushort ) so that it can occupy the same space in * a structure. */ class ExtendedCharTable { public: /** Constructs a new character table. */ ExtendedCharTable(); ~ExtendedCharTable(); /** * Adds a sequences of unicode characters to the table and returns * a hash code which can be used later to look up the sequence * using lookupExtendedChar() * * If the same sequence already exists in the table, the hash * of the existing sequence will be returned. * * @param unicodePoints An array of unicode character points * @param length Length of @p unicodePoints */ uint createExtendedChar(uint* unicodePoints , ushort length); /** * Looks up and returns a pointer to a sequence of unicode characters * 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 * character sequence. * * @return A unicode character sequence of size @p length. */ uint* lookupExtendedChar(uint hash , ushort& length) const; /** The global ExtendedCharTable instance. */ static ExtendedCharTable instance; private: // calculates the hash key of a sequence of unicode points of size 'length' uint extendedCharHash(uint* unicodePoints , ushort length) const; // tests whether the entry in the table specified by 'hash' matches the // character sequence 'unicodePoints' of size 'length' bool extendedCharMatch(uint hash , uint* unicodePoints , ushort length) const; // internal, maps hash keys to character sequence buffers. The first ushort // in each value is the length of the buffer, followed by the ushorts in the buffer // themselves. QHash extendedCharTable; }; } Q_DECLARE_TYPEINFO(Konsole::Character, Q_MOVABLE_TYPE); #endif // CHARACTER_H deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/CharacterColor.h000066400000000000000000000176761475472654300262520ustar00rootroot00000000000000/* This file is part of Konsole, KDE's terminal. Copyright 2007-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 (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. */ #ifndef CHARACTERCOLOR_H #define CHARACTERCOLOR_H // Qt #include //#include #define KDE_NO_EXPORT namespace Konsole { /** * 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. * * Each entry can also be transparent, in which case the terminal * display should avoid drawing the background for any characters * using the entry as a background. */ class ColorEntry { public: /** Specifies the weight to use when drawing text with this color. */ 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. * 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. */ 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) {} /** The color value of this entry for display. */ QColor color; /** * 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. * This is not applicable when the color is used to draw a character's background. */ FontWeight fontWeight; }; // Attributed Character Representations /////////////////////////////// // Colors #define BASE_COLORS (2+8) #define INTENSITIES 2 #define TABLE_COLORS (INTENSITIES*BASE_COLORS) #define DEFAULT_FORE_COLOR 0 #define DEFAULT_BACK_COLOR 1 //a standard set of colors using black text on a white background. //defined in TerminalDisplay.cpp extern const ColorEntry base_color_table[TABLE_COLORS] KDE_NO_EXPORT; /* CharacterColor is a union of the various color spaces. Assignment is as follows: Type - Space - Values 0 - Undefined - u: 0, v:0 w:0 1 - Default - u: 0..1 v:intense w:0 2 - System - u: 0..7 v:intense w:0 3 - Index(256) - u: 16..255 v:0 w:0 4 - RGB - u: 0..255 v:0..256 w:0..256 Default colour space has two separate colours, namely default foreground and default background colour. */ #define COLOR_SPACE_UNDEFINED 0 #define COLOR_SPACE_DEFAULT 1 #define COLOR_SPACE_SYSTEM 2 #define COLOR_SPACE_256 3 #define COLOR_SPACE_RGB 4 /** * Describes the color of a single character in the terminal. */ class CharacterColor { friend class Character; public: /** Constructs a new CharacterColor whoose color and color space are undefined. */ CharacterColor() : _colorSpace(COLOR_SPACE_UNDEFINED), _u(0), _v(0), _w(0) {} /** * 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. * * TODO : Document how @p co relates to @p colorSpace * * TODO : Add documentation about available color spaces. */ CharacterColor(quint8 colorSpace, int co) : _colorSpace(colorSpace), _u(0), _v(0), _w(0) { switch (colorSpace) { case COLOR_SPACE_DEFAULT: _u = co & 1; break; case COLOR_SPACE_SYSTEM: _u = co & 7; _v = (co >> 3) & 1; break; case COLOR_SPACE_256: _u = co & 255; break; case COLOR_SPACE_RGB: _u = co >> 16; _v = co >> 8; _w = co; break; default: _colorSpace = COLOR_SPACE_UNDEFINED; } } /** * Returns true if this character color entry is valid. */ bool isValid() const { return _colorSpace != COLOR_SPACE_UNDEFINED; } /** * 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 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. */ friend bool operator == (const CharacterColor& a, const CharacterColor& b); /** * Compares two colors and returns true if they represent different color values * or use different color spaces. */ friend bool operator != (const CharacterColor& a, const CharacterColor& b); private: quint8 _colorSpace; // 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 && a._w == b._w; } inline bool operator != (const CharacterColor& a, const CharacterColor& b) { return !operator==(a,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; // 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; // 232..255: gray, leaving out black and white int gray = u*10+8; return QColor(gray,gray,gray); } inline QColor CharacterColor::color(const ColorEntry* base) const { switch (_colorSpace) { case COLOR_SPACE_DEFAULT: return base[_u+0+(_v?BASE_COLORS:0)].color; case COLOR_SPACE_SYSTEM: return base[_u+2+(_v?BASE_COLORS:0)].color; case COLOR_SPACE_256: return color256(_u,base); case COLOR_SPACE_RGB: return {_u,_v,_w}; case COLOR_SPACE_UNDEFINED: return QColor(); } Q_ASSERT(false); // invalid color space return QColor(); } inline void CharacterColor::setIntensive() { if (_colorSpace == COLOR_SPACE_SYSTEM || _colorSpace == COLOR_SPACE_DEFAULT) { _v = 1; } } } #endif // CHARACTERCOLOR_H deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/CharacterFormat.cpp000066400000000000000000000027351475472654300267450ustar00rootroot00000000000000/* This file is part of Konsole, an X terminal. 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 (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. */ #include "CharacterFormat.h" using namespace Konsole; bool CharacterFormat::equalsFormat(const CharacterFormat &other) const { return (other.rendition & ~RE_EXTENDED_CHAR) == (rendition & ~RE_EXTENDED_CHAR) && other.fgColor == fgColor && other.bgColor == bgColor; } bool CharacterFormat::equalsFormat(const Character &c) const { return (c.rendition & ~RE_EXTENDED_CHAR) == (rendition & ~RE_EXTENDED_CHAR) && c.foregroundColor == fgColor && c.backgroundColor == bgColor; } void CharacterFormat::setFormat(const Character &c) { rendition = c.rendition; fgColor = c.foregroundColor; bgColor = c.backgroundColor; } deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/CharacterFormat.h000066400000000000000000000023561475472654300264110ustar00rootroot00000000000000/* This file is part of Konsole, an X terminal. 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 (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. */ #ifndef CHARACTERFORMAT_H #define CHARACTERFORMAT_H #include "Character.h" typedef quint16 RenditionFlags; namespace Konsole { class CharacterFormat { public: bool equalsFormat(const CharacterFormat &other) const; bool equalsFormat(const Character &c) const; void setFormat(const Character &c); CharacterColor fgColor, bgColor; quint16 startPos; RenditionFlags rendition; }; } #endif deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/ColorScheme.cpp000066400000000000000000000633021475472654300261000ustar00rootroot00000000000000/* This source file is part of Konsole, a terminal emulator. Copyright 2007-2008 by Robert Knight 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. */ // Own #include "ColorScheme.h" #include "tools.h" // Qt #include #include #include #include #include #include #include // KDE //#include //#include //#include //#include //#include //#include using namespace Konsole; const ColorEntry ColorScheme::defaultTable[TABLE_COLORS] = // The following are almost IBM standard color codes, with some slight // gamma correction for the dim colors to compensate for bright X screens. // It contains the 8 ansiterm/xterm colors in 2 intensities. { ColorEntry( QColor(0x00,0x00,0x00), false), ColorEntry( QColor(0xFF,0xFF,0xFF), true), // Dfore, Dback ColorEntry( QColor(0x00,0x00,0x00), false), ColorEntry( QColor(0xB2,0x18,0x18), false), // Black, Red ColorEntry( QColor(0x18,0xB2,0x18), false), ColorEntry( QColor(0xB2,0x68,0x18), false), // Green, Yellow ColorEntry( QColor(0x18,0x18,0xB2), false), ColorEntry( QColor(0xB2,0x18,0xB2), false), // Blue, Magenta ColorEntry( QColor(0x18,0xB2,0xB2), false), ColorEntry( QColor(0xB2,0xB2,0xB2), false), // Cyan, White // intensive ColorEntry( QColor(0x00,0x00,0x00), false), ColorEntry( QColor(0xFF,0xFF,0xFF), true), ColorEntry( QColor(0x68,0x68,0x68), false), ColorEntry( QColor(0xFF,0x54,0x54), false), ColorEntry( QColor(0x54,0xFF,0x54), false), ColorEntry( QColor(0xFF,0xFF,0x54), false), ColorEntry( QColor(0x54,0x54,0xFF), false), ColorEntry( QColor(0xFF,0x54,0xFF), false), ColorEntry( QColor(0x54,0xFF,0xFF), false), ColorEntry( QColor(0xFF,0xFF,0xFF), false) }; const char* const ColorScheme::colorNames[TABLE_COLORS] = { "Foreground", "Background", "Color0", "Color1", "Color2", "Color3", "Color4", "Color5", "Color6", "Color7", "ForegroundIntense", "BackgroundIntense", "Color0Intense", "Color1Intense", "Color2Intense", "Color3Intense", "Color4Intense", "Color5Intense", "Color6Intense", "Color7Intense" }; // dummy silently comment out the tr_NOOP #define tr_NOOP const char* const ColorScheme::translatedColorNames[TABLE_COLORS] = { tr_NOOP("Foreground"), tr_NOOP("Background"), tr_NOOP("Color 1"), tr_NOOP("Color 2"), tr_NOOP("Color 3"), tr_NOOP("Color 4"), tr_NOOP("Color 5"), tr_NOOP("Color 6"), tr_NOOP("Color 7"), tr_NOOP("Color 8"), tr_NOOP("Foreground (Intense)"), tr_NOOP("Background (Intense)"), tr_NOOP("Color 1 (Intense)"), tr_NOOP("Color 2 (Intense)"), tr_NOOP("Color 3 (Intense)"), tr_NOOP("Color 4 (Intense)"), tr_NOOP("Color 5 (Intense)"), tr_NOOP("Color 6 (Intense)"), tr_NOOP("Color 7 (Intense)"), tr_NOOP("Color 8 (Intense)") }; ColorScheme::ColorScheme() : _opacity(1.0) , _table(nullptr) , _randomTable(nullptr) { } ColorScheme::ColorScheme(const ColorScheme& other) : _opacity(other._opacity) , _table(nullptr) , _randomTable(nullptr) { setName(other.name()); setDescription(other.description()); if ( other._table != nullptr ) { for ( int i = 0 ; i < TABLE_COLORS ; i++ ) setColorTableEntry(i,other._table[i]); } if ( other._randomTable != nullptr ) { for ( int i = 0 ; i < TABLE_COLORS ; i++ ) { const RandomizationRange& range = other._randomTable[i]; setRandomizationRange(i,range.hue,range.saturation,range.value); } } } ColorScheme::~ColorScheme() { delete[] _table; delete[] _randomTable; } void ColorScheme::setDescription(const QString& description) { _description = description; } QString ColorScheme::description() const { return _description; } void ColorScheme::setName(const QString& name) { _name = name; } QString ColorScheme::name() const { return _name; } void ColorScheme::setColorTableEntry(int index , const ColorEntry& entry) { Q_ASSERT( index >= 0 && index < TABLE_COLORS ); if ( !_table ) { _table = new ColorEntry[TABLE_COLORS]; for (int i=0;i= 0 && index < TABLE_COLORS ); if ( randomSeed != 0 ) qsrand(randomSeed); ColorEntry entry = colorTable()[index]; if ( randomSeed != 0 && _randomTable != nullptr && !_randomTable[index].isNull() ) { const RandomizationRange& range = _randomTable[index]; int hueDifference = range.hue ? (qrand() % range.hue) - range.hue/2 : 0; int saturationDifference = range.saturation ? (qrand() % range.saturation) - range.saturation/2 : 0; int valueDifference = range.value ? (qrand() % range.value) - range.value/2 : 0; QColor& color = entry.color; int newHue = qAbs( (color.hue() + hueDifference) % MAX_HUE ); int newValue = qMin( qAbs(color.value() + valueDifference) , 255 ); int newSaturation = qMin( qAbs(color.saturation() + saturationDifference) , 255 ); color.setHsv(newHue,newSaturation,newValue); } return entry; } void ColorScheme::getColorTable(ColorEntry* table , uint randomSeed) const { for ( int i = 0 ; i < TABLE_COLORS ; i++ ) table[i] = colorEntry(i,randomSeed); } bool ColorScheme::randomizedBackgroundColor() const { return _randomTable == nullptr ? false : !_randomTable[1].isNull(); } void ColorScheme::setRandomizedBackgroundColor(bool randomize) { // the hue of the background colour is allowed to be randomly // adjusted as much as possible. // // the value and saturation are left alone to maintain read-ability if ( randomize ) { setRandomizationRange( 1 /* background color index */ , MAX_HUE , 255 , 0 ); } else { if ( _randomTable ) setRandomizationRange( 1 /* background color index */ , 0 , 0 , 0 ); } } void ColorScheme::setRandomizationRange( int index , quint16 hue , quint8 saturation , quint8 value ) { Q_ASSERT( hue <= MAX_HUE ); Q_ASSERT( index >= 0 && index < TABLE_COLORS ); if ( _randomTable == nullptr ) _randomTable = new RandomizationRange[TABLE_COLORS]; _randomTable[index].hue = hue; _randomTable[index].value = value; _randomTable[index].saturation = saturation; } const ColorEntry* ColorScheme::colorTable() const { if ( _table ) return _table; else return defaultTable; } QColor ColorScheme::foregroundColor() const { return colorTable()[0].color; } QColor ColorScheme::backgroundColor() const { return colorTable()[1].color; } bool ColorScheme::hasDarkBackground() const { // value can range from 0 - 255, with larger values indicating higher brightness. // so 127 is in the middle, anything less is deemed 'dark' return backgroundColor().value() < 127; } void ColorScheme::setOpacity(qreal opacity) { _opacity = opacity; } qreal ColorScheme::opacity() const { return _opacity; } void ColorScheme::read(const QString & fileName) { QSettings s(fileName, QSettings::IniFormat); s.beginGroup(QLatin1String("General")); _description = s.value(QLatin1String("Description"), QObject::tr("Un-named Color Scheme")).toString(); _opacity = s.value(QLatin1String("Opacity"),qreal(1.0)).toDouble(); s.endGroup(); for (int i=0 ; i < TABLE_COLORS ; i++) { readColorEntry(&s, i); } } #if 0 // implemented upstream - user apps void ColorScheme::read(KConfig& config) { KConfigGroup configGroup = config.group("General"); QString description = configGroup.readEntry("Description", QObject::tr("Un-named Color Scheme")); _description = tr(description.toUtf8()); _opacity = configGroup.readEntry("Opacity",qreal(1.0)); for (int i=0 ; i < TABLE_COLORS ; i++) { readColorEntry(config,i); } } void ColorScheme::write(KConfig& config) const { KConfigGroup configGroup = config.group("General"); configGroup.writeEntry("Description",_description); configGroup.writeEntry("Opacity",_opacity); for (int i=0 ; i < TABLE_COLORS ; i++) { RandomizationRange random = _randomTable != 0 ? _randomTable[i] : RandomizationRange(); writeColorEntry(config,colorNameForIndex(i),colorTable()[i],random); } } #endif QString ColorScheme::colorNameForIndex(int index) { Q_ASSERT( index >= 0 && index < TABLE_COLORS ); return QString::fromLatin1(colorNames[index]); } QString ColorScheme::translatedColorNameForIndex(int index) { Q_ASSERT( index >= 0 && index < TABLE_COLORS ); return QString::fromLatin1(translatedColorNames[index]); } void ColorScheme::readColorEntry(QSettings * s , int index) { QString colorName = colorNameForIndex(index); s->beginGroup(colorName); ColorEntry entry; QVariant colorValue = s->value(QLatin1String("Color")); QString colorStr; int r, g, b; 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(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(QLatin1String("Bold"))) entry.fontWeight = s->value(QLatin1String("Bold"),false).toBool() ? ColorEntry::Bold : ColorEntry::UseCurrentFormat; 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 ); s->endGroup(); } #if 0 // implemented upstream - user apps void ColorScheme::writeColorEntry(KConfig& config , const QString& colorName, const ColorEntry& entry , const RandomizationRange& random) const { KConfigGroup configGroup(&config,colorName); configGroup.writeEntry("Color",entry.color); configGroup.writeEntry("Transparency",(bool)entry.transparent); if (entry.fontWeight != ColorEntry::UseCurrentFormat) { configGroup.writeEntry("Bold",entry.fontWeight == ColorEntry::Bold); } // 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); configGroup.writeEntry("MaxRandomValue",(int)random.value); configGroup.writeEntry("MaxRandomSaturation",(int)random.saturation); } } #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. // // 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 background colors are allowed to be used for backgrounds. // // The ColorEntry and TerminalDisplay classes do not currently // support this restriction. // // Requirements: // - A color scheme which uses only colors from the KColorScheme class // - 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 // be used by default. // // // -- Robert Knight 21/07/2007 // AccessibleColorScheme::AccessibleColorScheme() : ColorScheme() { #if 0 // It's not finished in konsole and it breaks Qt4 compilation as well // basic attributes setName("accessible"); setDescription(QObject::tr("Accessible Color Scheme")); // setup colors const int ColorRoleCount = 8; const KColorScheme colorScheme(QPalette::Active); QBrush colors[ColorRoleCount] = { colorScheme.foreground( colorScheme.NormalText ), colorScheme.background( colorScheme.NormalBackground ), colorScheme.foreground( colorScheme.InactiveText ), colorScheme.foreground( colorScheme.ActiveText ), colorScheme.foreground( colorScheme.LinkText ), colorScheme.foreground( colorScheme.VisitedText ), colorScheme.foreground( colorScheme.NegativeText ), colorScheme.foreground( colorScheme.NeutralText ) }; for ( int i = 0 ; i < TABLE_COLORS ; i++ ) { ColorEntry entry; entry.color = colors[ i % ColorRoleCount ].color(); setColorTableEntry( i , entry ); } #endif } KDE3ColorSchemeReader::KDE3ColorSchemeReader( QIODevice* device ) : _device(device) { } ColorScheme* KDE3ColorSchemeReader::read() { Q_ASSERT( _device->openMode() == QIODevice::ReadOnly || _device->openMode() == QIODevice::ReadWrite ); ColorScheme* scheme = new ColorScheme(); QRegExp comment(QLatin1String("#.*$")); while ( !_device->atEnd() ) { QString line(QString::fromUtf8(_device->readLine())); line.remove(comment); line = line.simplified(); if ( line.isEmpty() ) continue; if ( line.startsWith(QLatin1String("color")) ) { if (!readColorLine(line,scheme)) qWarning() << "Failed to read KDE 3 color scheme line" << line; } else if ( line.startsWith(QLatin1String("title")) ) { if (!readTitleLine(line,scheme)) qWarning() << "Failed to read KDE 3 color scheme title line" << line; } else { qWarning() << "KDE 3 color scheme contains an unsupported feature, '" << line << "'"; } } return scheme; } bool KDE3ColorSchemeReader::readColorLine(const QString& line,ColorScheme* scheme) { QStringList list = line.split(QLatin1Char(' ')); if (list.count() != 7) return false; if (list.first() != QLatin1String("color")) return false; int index = list[1].toInt(); int red = list[2].toInt(); int green = list[3].toInt(); int blue = list[4].toInt(); int transparent = list[5].toInt(); int bold = list[6].toInt(); const int MAX_COLOR_VALUE = 255; if( (index < 0 || index >= TABLE_COLORS ) || (red < 0 || red > MAX_COLOR_VALUE ) || (blue < 0 || blue > MAX_COLOR_VALUE ) || (green < 0 || green > MAX_COLOR_VALUE ) || (transparent != 0 && transparent != 1 ) || (bold != 0 && bold != 1) ) return false; ColorEntry entry; entry.color = QColor(red,green,blue); entry.transparent = ( transparent != 0 ); entry.fontWeight = ( bold != 0 ) ? ColorEntry::Bold : ColorEntry::UseCurrentFormat; scheme->setColorTableEntry(index,entry); return true; } bool KDE3ColorSchemeReader::readTitleLine(const QString& line,ColorScheme* scheme) { if( !line.startsWith(QLatin1String("title")) ) return false; int spacePos = line.indexOf(QLatin1Char(' ')); if( spacePos == -1 ) return false; QString description = line.mid(spacePos+1); scheme->setDescription(description); return true; } ColorSchemeManager::ColorSchemeManager() : _haveLoadedAll(false) { } ColorSchemeManager::~ColorSchemeManager() { QHashIterator iter(_colorSchemes); while (iter.hasNext()) { iter.next(); delete iter.value(); } } void ColorSchemeManager::loadAllColorSchemes() { int failed = 0; QList nativeColorSchemes = listColorSchemes(); QListIterator nativeIter(nativeColorSchemes); while ( nativeIter.hasNext() ) { if ( !loadColorScheme( nativeIter.next() ) ) failed++; } QList kde3ColorSchemes = listKDE3ColorSchemes(); QListIterator kde3Iter(kde3ColorSchemes); while ( kde3Iter.hasNext() ) { if ( !loadKDE3ColorScheme( kde3Iter.next() ) ) failed++; } if ( failed > 0 ){ qWarning() << "failed to load " << failed << " color schemes."; } qInfo() << "load all color schemes"; //qDebug() << "nativeColorSchemes" << nativeColorSchemes ; //qDebug() << "kde3ColorSchemes" << kde3ColorSchemes; _haveLoadedAll = true; } QList ColorSchemeManager::allColorSchemes() { if ( !_haveLoadedAll ) { loadAllColorSchemes(); } return _colorSchemes.values(); } bool ColorSchemeManager::loadKDE3ColorScheme(const QString& filePath) { QFile file(filePath); if (!filePath.endsWith(QLatin1String(".schema")) || !file.open(QIODevice::ReadOnly)) return false; KDE3ColorSchemeReader reader(&file); ColorScheme* scheme = reader.read(); scheme->setName(QFileInfo(file).baseName()); file.close(); if (scheme->name().isEmpty()) { qWarning() << "color scheme name is not valid."; delete scheme; return false; } QFileInfo info(filePath); if ( !_colorSchemes.contains(info.baseName()) ) _colorSchemes.insert(scheme->name(),scheme); else { qWarning() << "color scheme with name" << scheme->name() << "has already been" << "found, ignoring."; delete scheme; } return true; } #if 0 void ColorSchemeManager::addColorScheme(ColorScheme* scheme) { _colorSchemes.insert(scheme->name(),scheme); // save changes to disk QString path = KGlobal::dirs()->saveLocation("data","konsole/") + scheme->name() + ".colorscheme"; KConfig config(path , KConfig::NoGlobals); scheme->write(config); } #endif bool ColorSchemeManager::loadCustomColorScheme(const QString& path) { if (path.endsWith(QLatin1String(".colorscheme"))) return loadColorScheme(path); else if (path.endsWith(QLatin1String(".schema"))) return loadKDE3ColorScheme(path); else 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) ) return false; QFileInfo info(filePath); const QString& schemeName = info.baseName(); ColorScheme* scheme = new ColorScheme(); scheme->setName(schemeName); scheme->read(filePath); if (scheme->name().isEmpty()) { qWarning() << "Color scheme in" << filePath << "does not have a valid name and was not loaded."; delete scheme; return false; } if ( !_colorSchemes.contains(schemeName) ) { _colorSchemes.insert(schemeName,scheme); } else { qWarning() << "color scheme with name" << schemeName << "has already been" << "found, ignoring."; delete scheme; } return true; } QList ColorSchemeManager::listKDE3ColorSchemes() { QList ret; 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); const QStringList list = dir.entryList(filters); for (const QString &i : list) ret << dname + QLatin1Char('/') + i; } return ret; //return KGlobal::dirs()->findAllResources("data", // "konsole/*.schema", // KStandardDirs::NoDuplicates); // } QList ColorSchemeManager::listColorSchemes() { QList ret; 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); const QStringList list = dir.entryList(filters); for (const QString &i : list) ret << dname + QLatin1Char('/') + i; } return ret; // return KGlobal::dirs()->findAllResources("data", // "konsole/*.colorscheme", // KStandardDirs::NoDuplicates); } const ColorScheme ColorSchemeManager::_defaultColorScheme; const ColorScheme* ColorSchemeManager::defaultColorScheme() const { return &_defaultColorScheme; } bool ColorSchemeManager::deleteColorScheme(const QString& name) { Q_ASSERT( _colorSchemes.contains(name) ); // lookup the path and delete QString path = findColorSchemePath(name); if ( QFile::remove(path) ) { _colorSchemes.remove(name); return true; } else { qWarning() << "Failed to remove color scheme -" << path; return false; } } /******************************************************************************* 1. @函数: realodColorScheme 2. @作者: ut000125 sunchengxi 3. @日期: 2020-12-01 4. @说明: 重新加载主题 *******************************************************************************/ void ColorSchemeManager::realodColorScheme(const QString &origName) { if (!origName.endsWith(QLatin1String(".colorscheme")) || !QFile::exists(origName)) { return; } QFileInfo info(origName); const QString &schemeName = info.baseName(); ColorScheme *scheme = new ColorScheme(); scheme->setName(schemeName); scheme->read(origName); if (scheme->name().isEmpty()) { qWarning() << "Color scheme in" << origName << "does not have a valid name and was not loaded."; delete scheme; return; } if (_colorSchemes.contains(schemeName)) { qDebug() << "(_colorSchemes.contains(schemeName))"; const ColorScheme *needDeletScheme = _colorSchemes[schemeName]; delete needDeletScheme; _colorSchemes[schemeName] = scheme; } } QString ColorSchemeManager::findColorSchemePath(const QString& name) const { // QString path = KStandardDirs::locate("data","konsole/"+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; //path = KStandardDirs::locate("data","konsole/"+name+".schema"); path = dir + QLatin1Char('/')+ name + QLatin1String(".schema"); return path; } const ColorScheme* ColorSchemeManager::findColorScheme(const QString& name) { if ( name.isEmpty() ) return defaultColorScheme(); if ( _colorSchemes.contains(name) ) return _colorSchemes[name]; else { // look for this color scheme QString path = findColorSchemePath(name); if ( !path.isEmpty() && loadColorScheme(path) ) { return findColorScheme(name); } else { if (!path.isEmpty() && loadKDE3ColorScheme(path)) return findColorScheme(name); } qDebug() << "Could not find color scheme - " << name; return nullptr; } } Q_GLOBAL_STATIC(ColorSchemeManager, theColorSchemeManager) ColorSchemeManager* ColorSchemeManager::instance() { return theColorSchemeManager; } deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/ColorScheme.h000066400000000000000000000270001475472654300255400ustar00rootroot00000000000000/* This source file is part of Konsole, a terminal emulator. Copyright 2007-2008 by Robert Knight 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. */ #ifndef COLORSCHEME_H #define COLORSCHEME_H // Qt #include #include #include #include #include #include // Konsole #include "CharacterColor.h" class QIODevice; //class KConfig; namespace Konsole { /** * 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. */ class ColorScheme { public: /** * Constructs a new color scheme which is initialised to the default color set * for Konsole. */ ColorScheme(); ColorScheme(const ColorScheme& other); ~ColorScheme(); /** Sets the descriptive name of the color scheme. */ void setDescription(const QString& description); /** Returns the descriptive name of the color scheme. */ QString description() const; /** Sets the name of the color scheme */ void setName(const QString& name); /** Returns the name of the color scheme */ QString name() const; #if 0 // Implemented upstream - in user apps /** Reads the color scheme from the specified configuration source */ void read(KConfig& config); /** Writes the color scheme to the specified configuration source */ void write(KConfig& config) const; #endif void read(const QString & filename); /** 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. * * @param table Array into which the color entries for this color scheme * are copied. * @param randomSeed Color schemes may allow certain colors in their * 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. * * See getColorTable() */ 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 * text in this scheme. */ QColor foregroundColor() const; /** * 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). * * Defaults to 1. * * 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. */ bool randomizedBackgroundColor() const; static QString colorNameForIndex(int index); static QString translatedColorNameForIndex(int index); private: // specifies how much a particular color can be randomized by class RandomizationRange { public: RandomizationRange() : hue(0) , saturation(0) , value(0) {} bool isNull() const { return ( hue == 0 && saturation == 0 && value == 0 ); } quint16 hue; quint8 saturation; quint8 value; }; // returns the active color table. if none has been set specifically, // this is the default color table. const ColorEntry* colorTable() const; #if 0 // 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); // 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 // it does not already exist void setRandomizationRange( int index , quint16 hue , quint8 saturation , quint8 value ); QString _description; QString _name; qreal _opacity; ColorEntry* _table; // pointer to custom color table or 0 if the default // color scheme is being used static const quint16 MAX_HUE = 340; RandomizationRange* _randomTable; // pointer to randomization table or 0 // if no colors in the color scheme support // randomization static const char* const colorNames[TABLE_COLORS]; static const char* const translatedColorNames[TABLE_COLORS]; 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 * designed colors. * * TODO Implement and make it the default on systems with specialized KDE * color schemes. */ class AccessibleColorScheme : public ColorScheme { public: AccessibleColorScheme(); }; /** * Reads a color scheme stored in the .schema format used in the KDE 3 incarnation * of Konsole * * Only the basic essentials ( title and color palette entries ) are currently * supported. Additional options such as background image and background * blend colors are ignored. */ class KDE3ColorSchemeReader { public: /** * Constructs a new reader which reads from the specified device. * The device should be open in read-only mode. */ explicit KDE3ColorSchemeReader( QIODevice* device ); /** * Reads and parses the contents of the .schema file from the input * device and returns the ColorScheme defined within it. * * Returns a null pointer if an error occurs whilst parsing * the contents of the file. */ ColorScheme* read(); private: // reads a line from the file specifying a colour palette entry // format is: color [index] [red] [green] [blue] [transparent] [bold] bool readColorLine(const QString& line , ColorScheme* scheme); bool readTitleLine(const QString& line , ColorScheme* scheme); QIODevice* _device; }; /** * Manages the color schemes available for use by terminal displays. * See ColorScheme */ class ColorSchemeManager { public: /** * Constructs a new ColorSchemeManager and loads the list * of available color schemes. * * The color schemes themselves are not loaded until they are first * requested via a call to findColorScheme() */ ColorSchemeManager(); /** * Destroys the ColorSchemeManager and saves any modified color schemes to disk. */ ~ColorSchemeManager(); /** * 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 * default color scheme is returned. * * The first time that a color scheme with a particular name is * requested, the configuration information is loaded from disk. */ const ColorScheme* findColorScheme(const QString& name); #if 0 /** * Adds a new color scheme to the manager. If @p scheme has the same name as * an existing color scheme, it replaces the existing scheme. * * TODO - Ensure the old color scheme gets deleted */ void addColorScheme(ColorScheme* scheme); #endif /** * Deletes a color scheme. Returns true on successful deletion or false otherwise. */ bool deleteColorScheme(const QString& name); //重新加载主题 void realodColorScheme(const QString &origName); /** * 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. */ QList allColorSchemes(); /** Returns the global color scheme manager instance. */ static ColorSchemeManager* instance(); /** @brief Loads a custom color scheme under given \em path. * * The \em path may refer to either KDE 4 .colorscheme or KDE 3 * .schema file * * The loaded color scheme is available under the name equal to * the base name of the \em path via the allColorSchemes() and * findColorScheme() methods after this call if loaded successfully. * * @param[in] path The path to KDE 4 .colorscheme or KDE 3 .schema. * @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); // loads a color scheme from a KDE 3 .schema file bool loadKDE3ColorScheme(const QString& path); // returns a list of paths of color schemes in the KDE 4+ .colorscheme file format QList listColorSchemes(); // returns a list of paths of color schemes in the .schema file format // used in KDE 3 QList listKDE3ColorSchemes(); // loads all of the color schemes void loadAllColorSchemes(); // finds the path of a color scheme QString findColorSchemePath(const QString& name) const; QHash _colorSchemes; QSet _modifiedSchemes; bool _haveLoadedAll; static const ColorScheme _defaultColorScheme; }; } Q_DECLARE_METATYPE(const Konsole::ColorScheme*) #endif //COLORSCHEME_H deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/ColorTables.h000066400000000000000000000100631475472654300255470ustar00rootroot00000000000000/* 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 (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 Lesser 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. */ #ifndef _COLOR_TABLE_H #define _COLOR_TABLE_H #include "CharacterColor.h" //using namespace Konsole; #if 0 static const ColorEntry whiteonblack_color_table[TABLE_COLORS] = { // normal ColorEntry(QColor(0xFF,0xFF,0xFF), false ), ColorEntry( QColor(0x00,0x00,0x00), true ), // Dfore, Dback ColorEntry(QColor(0x00,0x00,0x00), false ), ColorEntry( QColor(0xB2,0x18,0x18), false ), // Black, Red ColorEntry(QColor(0x18,0xB2,0x18), false ), ColorEntry( QColor(0xB2,0x68,0x18), false ), // Green, Yellow ColorEntry(QColor(0x18,0x18,0xB2), false ), ColorEntry( QColor(0xB2,0x18,0xB2), false ), // Blue, Magenta ColorEntry(QColor(0x18,0xB2,0xB2), false ), ColorEntry( QColor(0xB2,0xB2,0xB2), false ), // Cyan, White // intensiv ColorEntry(QColor(0x00,0x00,0x00), false ), ColorEntry( QColor(0xFF,0xFF,0xFF), true ), ColorEntry(QColor(0x68,0x68,0x68), false ), ColorEntry( QColor(0xFF,0x54,0x54), false ), ColorEntry(QColor(0x54,0xFF,0x54), false ), ColorEntry( QColor(0xFF,0xFF,0x54), false ), ColorEntry(QColor(0x54,0x54,0xFF), false ), ColorEntry( QColor(0xFF,0x54,0xFF), false ), ColorEntry(QColor(0x54,0xFF,0xFF), false ), ColorEntry( QColor(0xFF,0xFF,0xFF), false ) }; static const ColorEntry greenonblack_color_table[TABLE_COLORS] = { ColorEntry(QColor( 24, 240, 24), false), ColorEntry(QColor( 0, 0, 0), true), ColorEntry(QColor( 0, 0, 0), false), ColorEntry(QColor( 178, 24, 24), false), ColorEntry(QColor( 24, 178, 24), false), ColorEntry(QColor( 178, 104, 24), false), ColorEntry(QColor( 24, 24, 178), false), ColorEntry(QColor( 178, 24, 178), false), ColorEntry(QColor( 24, 178, 178), false), ColorEntry(QColor( 178, 178, 178), false), // intensive colors ColorEntry(QColor( 24, 240, 24), false ), ColorEntry(QColor( 0, 0, 0), true ), ColorEntry(QColor( 104, 104, 104), false ), ColorEntry(QColor( 255, 84, 84), false ), ColorEntry(QColor( 84, 255, 84), false ), ColorEntry(QColor( 255, 255, 84), false ), ColorEntry(QColor( 84, 84, 255), false ), ColorEntry(QColor( 255, 84, 255), false ), ColorEntry(QColor( 84, 255, 255), false ), ColorEntry(QColor( 255, 255, 255), false ) }; static const ColorEntry blackonlightyellow_color_table[TABLE_COLORS] = { ColorEntry(QColor( 0, 0, 0), false), ColorEntry(QColor( 255, 255, 221), true), ColorEntry(QColor( 0, 0, 0), false), ColorEntry(QColor( 178, 24, 24), false), ColorEntry(QColor( 24, 178, 24), false), ColorEntry(QColor( 178, 104, 24), false), ColorEntry(QColor( 24, 24, 178), false), ColorEntry(QColor( 178, 24, 178), false), ColorEntry(QColor( 24, 178, 178), false), ColorEntry(QColor( 178, 178, 178), false), ColorEntry(QColor( 0, 0, 0), false), ColorEntry(QColor( 255, 255, 221), true), ColorEntry(QColor(104, 104, 104), false), ColorEntry(QColor( 255, 84, 84), false), ColorEntry(QColor( 84, 255, 84), false), ColorEntry(QColor( 255, 255, 84), false), ColorEntry(QColor( 84, 84, 255), false), ColorEntry(QColor( 255, 84, 255), false), ColorEntry(QColor( 84, 255, 255), false), ColorEntry(QColor( 255, 255, 255), false) }; #endif #endif deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/DefaultTranslatorText.h000066400000000000000000000016431475472654300276450ustar00rootroot00000000000000/* 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 (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 Lesser 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. */ "keyboard \"Fallback Key Translator\"\n" "key Tab : \"\\t\" \0" deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/Emulation.cpp000066400000000000000000000475561475472654300256470ustar00rootroot00000000000000/* Copyright 2007-2008 Robert Knight Copyright 1997,1998 by Lars Doelle Copyright 1996 by Matthias Ettrich 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. */ // Own #include "Emulation.h" // System #include #include #include #include // Qt #include #include #include #include #include #include #include #include #include #include // KDE //#include // Konsole #include "KeyboardTranslator.h" #include "Screen.h" #include "TerminalCharacterDecoder.h" #include "ScreenWindow.h" #include "Session.h" #include "SessionManager.h" #include "TerminalDisplay.h" #include "encodes/detectcode.h" using namespace Konsole; Emulation::Emulation() : _currentScreen(nullptr), _codec(nullptr), _decoder(nullptr), _keyTranslator(nullptr), _usesMouse(false), _alternateScrolling(true), _bracketedPasteMode(false) { // create screens with a default size _screen[0] = new Screen(40, 80); _screen[1] = new Screen(40, 80); _currentScreen = _screen[0]; 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(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)); }); /******** Add by ut001000 renfeixiang 2020-07-16:增加初始化保存开始的屏幕行列数 Begin***************/ // _lastcol = _currentScreen->getColumns(); // _lastline = _currentScreen->getLines(); /******** Add by ut001000 renfeixiang 2020-07-16:增加 End***************/ } bool Emulation::programUsesMouse() const { return _usesMouse; } void Emulation::usesMouseChanged(bool usesMouse) { _usesMouse = usesMouse; } void Emulation::setAlternateScrolling(bool enable) { _alternateScrolling = enable; } bool Emulation::programBracketedPasteMode() const { return _bracketedPasteMode; } void Emulation::bracketedPasteModeChanged(bool bracketedPasteMode) { _bracketedPasteMode = bracketedPasteMode; } ScreenWindow *Emulation::createWindow() { ScreenWindow *window = new ScreenWindow(); window->setScreen(_currentScreen); _windows << window; connect(window, SIGNAL(selectionChanged()), this, SLOT(bufferedUpdate())); connect(this, SIGNAL(outputChanged()), window, SLOT(notifyOutputChanged())); return window; } void Emulation::checkScreenInUse() { emit primaryScreenInUse(_currentScreen == _screen[0]); } Emulation::~Emulation() { QListIterator windowIter(_windows); while (windowIter.hasNext()) { delete windowIter.next(); } delete _screen[0]; delete _screen[1]; delete _decoder; if (nullptr != _keyTranslator) { delete _keyTranslator; _keyTranslator = nullptr; } } void Emulation::setScreen(int n) { Screen *old = _currentScreen; _currentScreen = _screen[n & 1]; if (_currentScreen != old) { // tell all windows onto this emulation to switch to the newly active screen for (ScreenWindow *window : qAsConst(_windows)) window->setScreen(_currentScreen); checkScreenInUse(); } } void Emulation::clearHistory() { _screen[0]->setScroll(_screen[0]->getScroll(), false); } void Emulation::setHistory(const HistoryType &t) { _screen[0]->setScroll(t); showBulk(); } const HistoryType &Emulation::history() const { return _screen[0]->getScroll(); } void Emulation::setCodec(const QTextCodec *qtc) { if (qtc) _codec = qtc; else setCodec(LocaleCodec); delete _decoder; _decoder = _codec->makeDecoder(); emit useUtf8Request(utf8()); } void Emulation::setCodec(EmulationCodec codec) { if (codec == Utf8Codec) setCodec(QTextCodec::codecForName("utf8")); else if (codec == LocaleCodec) setCodec(QTextCodec::codecForLocale()); } void Emulation::setSessionId(int sessionId) { _sessionId = sessionId; } void Emulation::setBackspaceMode(char *key, int length) { KeyboardTranslator::Entry entry = _keyTranslator->findEntry( Qt::Key_Backspace, Qt::NoModifier, KeyboardTranslator::NoState); KeyboardTranslator::Entry newEntry; KeyboardTranslator::States flags = KeyboardTranslator::NoState; KeyboardTranslator::States flagMask = KeyboardTranslator::NoState; Qt::KeyboardModifiers modifiers = Qt::NoModifier; Qt::KeyboardModifiers modifierMask = Qt::NoModifier; KeyboardTranslator::Command command = KeyboardTranslator::NoCommand; newEntry.setKeyCode(Qt::Key_Backspace); newEntry.setState(flags); newEntry.setStateMask(flagMask); newEntry.setModifiers(modifiers); newEntry.setModifierMask(modifierMask); newEntry.setText(QByteArray(key, length)); newEntry.setCommand(command); _keyTranslator->replaceEntry(entry, newEntry); } void Emulation::setDeleteMode(char *key, int length) { KeyboardTranslator::Entry entry = _keyTranslator->findEntry( Qt::Key_Delete, Qt::NoModifier, KeyboardTranslator::NoState); KeyboardTranslator::Entry newEntry; KeyboardTranslator::States flags = KeyboardTranslator::NoState; KeyboardTranslator::States flagMask = KeyboardTranslator::NoState; Qt::KeyboardModifiers modifiers = Qt::NoModifier; Qt::KeyboardModifiers modifierMask = Qt::NoModifier; KeyboardTranslator::Command command = KeyboardTranslator::NoCommand; newEntry.setKeyCode(Qt::Key_Delete); newEntry.setState(flags); newEntry.setStateMask(flagMask); newEntry.setModifiers(modifiers); newEntry.setModifierMask(modifierMask); newEntry.setText(QByteArray(key, length)); newEntry.setCommand(command); _keyTranslator->replaceEntry(entry, newEntry); } void Emulation::setKeyBindings(const QString &name) { _keyTranslator = KeyboardTranslatorManager::instance()->getTranslator(name); } QString Emulation::keyBindings() const { return _keyTranslator->name(); } void Emulation::receiveChar(wchar_t c) // process application unicode input to terminal // this is a trivial scanner { c &= 0xff; switch (c) { case '\b' : _currentScreen->backspace(); break; case '\t' : _currentScreen->tab(); break; case '\n' : _currentScreen->newLine(); break; case '\r' : _currentScreen->toStartOfLine(); break; case 0x07 : emit stateSet(NOTIFYBELL); break; default : _currentScreen->displayCharacter(c); break; }; } 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().constData(), ev->text().length(), _codec); } } void Emulation::sendString(const char *, int) { // default implementation does nothing } void Emulation::sendMouseEvent(int /*buttons*/, int /*column*/, int /*row*/, int /*eventType*/) { // default implementation does nothing } static int isUse2005Standard = -1; /** @brief 检测当前iconv使用的GB18030编码是否为2005标准,2005标准强制使用上层补丁版本 通过检测2005和2022编码转的差异,以附录D中的编码为例验证 2005标准 0xFE51 --> \u20087 2022标准 0xFE51 --> \uE816 @return iconv使用GB18030编码是否为2005标准,默认返回true */ bool Emulation::detectIconvUse2005Standard() { iconv_t handle = iconv_open("UTF-8", "GB18030"); if (handle == reinterpret_cast(-1)) { return true; } QByteArray input("\xFE\x51"); QByteArray output(input.size() * 2, 0); char *inputData = input.data(); char *outputData = output.data(); size_t inputLen = static_cast(input.count()); size_t outputLen = static_cast(output.count()); const size_t ret = iconv(handle, &inputData, &inputLen, &outputData, &outputLen); iconv_close(handle); if (ret == static_cast(-1)) { return true; } if (!output.contains("\uE816")) { qInfo() << "Current iconv gb18030 standard is 2005."; return true; } qInfo() << "Current iconv gb18030 standard is 2022."; return false; } /* We are doing code conversion from locale to unicode first. TODO: Character composition from the old code. See #96536 */ void Emulation::receiveData(const char *text, int length, bool isCommandExec) { emit stateSet(NOTIFYACTIVITY); bufferedUpdate(); /* 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 = ""; if (QString(_codec->name()).toUpper().startsWith("GB") && !isCommandExec) { if (_decoder != nullptr) { delete _decoder; _decoder = nullptr; } QTextCodec *textCodec = QTextCodec::codecForName("UTF-8"); _decoder = textCodec->makeDecoder(); utf16Text = _decoder->toUnicode(text, length); QTextCodec* gbk = QTextCodec::codecForName(_codec->name()); QByteArray gbkarr = gbk->fromUnicode(utf16Text); if (_decoder != nullptr) { delete _decoder; _decoder = nullptr; } textCodec = QTextCodec::codecForName(_codec->name()); _decoder = textCodec->makeDecoder(); utf16Text = _decoder->toUnicode(gbkarr); //setIsCodecGB18030(false); } else { if(isUse2005Standard == -1){ isUse2005Standard = detectIconvUse2005Standard(); qInfo() << "Is Used 2005 standard's gb18030 iconv?" << isUse2005Standard; } if(_codec->name().toUpper().contains("GB18030") && isUse2005Standard == 1) { //setIsCodecGB18030(true); QByteArray gbkarr(text, length); QByteArray Outdata; DetectCode::ChangeFileEncodingFormat(gbkarr, Outdata, QString("GB18030"), QString("UTF-8")); utf16Text = QString(Outdata); } else { utf16Text = _decoder->toUnicode(text, length); //setIsCodecGB18030(false); } } //fix bug 67102 打开超长名称的文件夹,终端界面光标位置不在最后一位 //bash 提示符很长的情况下,会有较大概率以五个\b字符结尾,导致光标错位 if (utf16Text.startsWith("\u001B]0;") && utf16Text.endsWith("\b\b\b\b\b")) { Session *currSession = SessionManager::instance()->idToSession(_sessionId); if (currSession && (QStringLiteral("bash") == currSession->foregroundProcessName())) { utf16Text.replace("\b\b\b\b\b", ""); } } std::wstring unicodeText = utf16Text.toStdWString(); //send characters to terminal emulator for (size_t i = 0; i < unicodeText.length(); i++) receiveChar(unicodeText[i]); //look for z-modem indicator //-- someone who understands more about z-modems that I do may be able to move //this check into the above for loop? for (int i = 0; i < length; i++) { if (text[i] == '\030') { if ((length - i - 1 > 3) && (strncmp(text + i + 1, "B00", 3) == 0)) emit zmodemDetected(); } } } //OLDER VERSION //This version of onRcvBlock was commented out because // a) It decoded incoming characters one-by-one, which is slow in the current version of Qt (4.2 tech preview) // b) It messed up decoding of non-ASCII characters, with the result that (for example) chinese characters // were not printed properly. // //There is something about stopping the _decoder if "we get a control code halfway a multi-byte sequence" (see below) //which hasn't been ported into the newer function (above). Hopefully someone who understands this better //can find an alternative way of handling the check. /*void Emulation::onRcvBlock(const char *s, int len) { emit notifySessionState(NOTIFYACTIVITY); bufferedUpdate(); for (int i = 0; i < len; i++) { QString result = _decoder->toUnicode(&s[i],1); int reslen = result.length(); // If we get a control code halfway a multi-byte sequence // we flush the _decoder and continue with the control code. if ((s[i] < 32) && (s[i] > 0)) { // Flush _decoder while(!result.length()) result = _decoder->toUnicode(&s[i],1); reslen = 1; result.resize(reslen); result[0] = QChar(s[i]); } for (int j = 0; j < reslen; j++) { if (result[j].characterategory() == QChar::Mark_NonSpacing) _currentScreen->compose(result.mid(j,1)); else onRcvChar(result[j].unicode()); } if (s[i] == '\030') { if ((len-i-1 > 3) && (strncmp(s+i+1, "B00", 3) == 0)) emit zmodemDetected(); } } }*/ void Emulation::writeToStream(TerminalCharacterDecoder *_decoder, int startLine, int endLine) { _currentScreen->writeLinesToStream(_decoder, startLine, endLine); } int Emulation::lineCount() const { // sum number of lines currently on _screen plus number of lines in history return _currentScreen->getLines() + _currentScreen->getHistLines(); } int Emulation::columnCount() const { return _currentScreen->getColumns(); } #define BULK_TIMEOUT1 10 #define BULK_TIMEOUT2 40 void Emulation::showBulk() { _bulkTimer1.stop(); _bulkTimer2.stop(); emit outputChanged(); _currentScreen->resetScrolledLines(); _currentScreen->resetDroppedLines(); } void Emulation::bufferedUpdate() { _bulkTimer1.setSingleShot(true); _bulkTimer1.start(BULK_TIMEOUT1); if (!_bulkTimer2.isActive()) { _bulkTimer2.setSingleShot(true); _bulkTimer2.start(BULK_TIMEOUT2); } } char Emulation::eraseChar() const { return '\b'; } void Emulation::setImageSize(int lines, int columns) { if ((lines < 1) || (columns < 1)) return; QSize screenSize[2] = { QSize(_screen[0]->getColumns(), _screen[0]->getLines()), QSize(_screen[1]->getColumns(), _screen[1]->getLines()) }; QSize newSize(columns, lines); if (newSize == screenSize[0] && newSize == screenSize[1]) return; _screen[0]->resizeImage(lines, columns); _screen[1]->resizeImage(lines, columns); emit imageSizeChanged(lines, columns); bufferedUpdate(); } QSize Emulation::imageSize() const { return {_currentScreen->getColumns(), _currentScreen->getLines()}; } uint ExtendedCharTable::extendedCharHash(uint *unicodePoints, ushort length) const { uint hash = 0; for (ushort i = 0 ; i < length ; i++) { hash = 31 * hash + unicodePoints[i]; } return hash; } bool ExtendedCharTable::extendedCharMatch(uint hash, uint *unicodePoints, ushort length) const { uint *entry = extendedCharTable[hash]; // compare given length with stored sequence length ( given as the first ushort in the // stored buffer ) if (entry == nullptr || 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 true; } uint ExtendedCharTable::createExtendedChar(uint *unicodePoints, ushort length) { // look for this sequence of points in the table uint hash = extendedCharHash(unicodePoints, length); const uint initialHash = hash; bool triedCleaningSolution = false; // check existing entry for match while (extendedCharTable.contains(hash) && hash != 0) { // 0 has a special meaning for chars so we don't use it if (extendedCharMatch(hash, unicodePoints, length)) { // this sequence already has an entry in the table, // return its hash return hash; } // if hash is already used by another, different sequence of unicode character // points then try next hash hash++; if (hash == initialHash) { if (!triedCleaningSolution) { triedCleaningSolution = true; // All the hashes are full, go to all Screens and try to free any // This is slow but should happen very rarely QSet usedExtendedChars; const QList sessionsList = SessionManager::instance()->sessions(); for (const Session *s : sessionsList) { const QList displayList = s->views(); for (const TerminalDisplay *display : displayList) { usedExtendedChars += display->screenWindow()->screen()->usedExtendedChars(); } } QHash::iterator it = extendedCharTable.begin(); QHash::iterator itEnd = extendedCharTable.end(); while (it != itEnd) { if (usedExtendedChars.contains(it.key())) { ++it; } else { it = extendedCharTable.erase(it); } } } else { qDebug() << "Using all the extended char hashes, going to miss this extended character"; return 0; } } } // add the new sequence to the table and // return that index auto buffer = new uint[length + 1]; buffer[0] = length; for (int i = 0; i < length; i++) { buffer[i + 1] = unicodePoints[i]; } extendedCharTable.insert(hash, buffer); return hash; } uint *ExtendedCharTable::lookupExtendedChar(uint hash, ushort &length) const { // lookup index in table and if found, set the length // argument and return a pointer to the character sequence uint *buffer = extendedCharTable[hash]; if (buffer != nullptr) { length = ushort(buffer[0]); return buffer + 1; } length = 0; return nullptr; } ExtendedCharTable::ExtendedCharTable() { } ExtendedCharTable::~ExtendedCharTable() { // free all allocated character buffers QHashIterator iter(extendedCharTable); while (iter.hasNext()) { iter.next(); delete[] iter.value(); } } // global instance ExtendedCharTable ExtendedCharTable::instance; //#include "Emulation.moc" deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/Emulation.h000066400000000000000000000476701475472654300253110ustar00rootroot00000000000000/* This file is part of Konsole, an X terminal. Copyright 2007-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 (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. */ #ifndef EMULATION_H #define EMULATION_H // System #include // Qt #include //#include #include #include #include #include "qtermwidget_export.h" namespace Konsole { class KeyboardTranslator; class HistoryType; class Screen; class ScreenWindow; class TerminalCharacterDecoder; /** * This enum describes the available states which * the terminal emulation may be set to. * * These are the values used by Emulation::stateChanged() */ enum { /** The emulation is currently receiving user input. */ 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 * terminal input. */ NOTIFYACTIVITY = 2, // unused here? NOTIFYSILENCE = 3 }; /** * Base class for terminal emulation back-ends. * * 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 * screen image accordingly. The codec used to decode the incoming character stream * 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 * 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(). * * 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 * 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. * * 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 * to the terminal program. Key presses can be processed by calling the sendKeyEvent() slot, * while mouse events can be processed using the sendMouseEvent() slot. When the character * stream has been produced, the emulation will emit a sendData() signal with a pointer * to the character buffer. This data should be fed to the standard input of the terminal * process. The translation of key presses into an output character stream is performed * using a lookup in a set of key bindings which map key sequences to output * 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 also maintains an activity state, which specifies whether * terminal is currently active ( when data is received ), normal * ( when the terminal is idle or receiving user input ) or trying * to alert the user ( also known as a "Bell" event ). The stateSet() signal * is emitted whenever the activity state is set. This can be used to determine * how long the emulation has been active/idle for and also respond to * a 'bell' event in different ways. */ class TERMINALWIDGET_EXPORT Emulation : public QObject { Q_OBJECT public: /** * 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() override; /** * Creates a new window onto the output from this emulation. The contents * of the window are then rendered by views which are set to use this window using the * TerminalDisplay::setScreenWindow() method. */ ScreenWindow *createWindow(); /** Returns the size of the screen image which the emulation produces */ QSize imageSize() const; /** * Returns the total number of lines, including those stored in the history. */ int lineCount() const; /** * Returns the total number of columns. */ int columnCount() 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. * * The number of lines which are kept and the storage location depend on the * type of store. */ void setHistory(const HistoryType &); /** Returns the history store used by this emulation. See setHistory() */ const HistoryType &history() const; /** Clears the history scroll. */ void clearHistory(); /** * Copies the output history from @p startLine to @p endLine * into @p stream, using @p decoder to convert the terminal * characters into text. * * @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 * @param endLine Index of last line to copy */ virtual void writeToStream(TerminalCharacterDecoder *decoder, int startLine, int endLine); /** Returns the codec used to decode incoming characters. See setCodec() */ const QTextCodec *codec() const { return _codec; } /** Sets the codec used to decode incoming characters. */ void setCodec(const QTextCodec *); /** * 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; /** Resets the state of the terminal. */ virtual void reset() = 0; /** * Returns true if the active terminal program wants * mouse input events. * * The programUsesMouseChanged() signal is emitted when this * changes. */ bool programUsesMouse() const; bool programBracketedPasteMode() const; /******** Modify by ut000610 daizhengwen 2020-06-02: 重新设置键盘配置****************/ void setKeyTranslator(const KeyboardTranslator *keyTranslator); /********************* Modify by ut000610 daizhengwen End ************************/ /******** Modify by ut000610 daizhengwen 2020-06-02: 设置删除和退格按钮****************/ void setBackspaceMode(char *key, int length); void setDeleteMode(char *key, int length); /********************* Modify by ut000610 daizhengwen End ************************/ //用于保存当前Emulator对应的sessionId void setSessionId(int sessionId); 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. */ 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. * * @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. * * receiveData() also starts a timer which causes the outputChanged() signal * to be emitted when it expires. The timer allows multiple updates in quick * succession to be buffered into a single outputChanged() signal emission. * * @param buffer A string of characters received from the terminal program. * @param len The length of @p buffer */ void receiveData(const char *buffer, int len, bool isCommandExec); signals: /** * 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 * @param len The length of @p data in bytes */ void sendData(const char *data, int len, const QTextCodec *codec); /** * 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 * suspended. Otherwise requests that sending of * input be resumed. */ void lockPtyRequest(bool suspend); /** * Requests that the pty used by the terminal process * be set to UTF 8 mode. * * TODO: More documentation */ void useUtf8Request(bool); /** * Emitted when the activity state of the emulation is set. * * @param state The new activity state, one of NOTIFYNORMAL, NOTIFYACTIVITY * or NOTIFYBELL */ void stateSet(int state); /** TODO Document me */ void zmodemDetected(); /** * Requests that the color of the text used * to represent the tabs associated with this * emulation be changed. This is a Konsole-specific * extension from pre-KDE 4 times. * * TODO: Document how the parameter works. */ void changeTabTextColorRequest(int color); /** * This is emitted when the program running in the shell indicates whether or * not it is interested in mouse events. * * @param usesMouse This will be true if the program wants to be informed about * mouse events or false otherwise. */ void programUsesMouseChanged(bool usesMouse); void enableAlternateScrolling(bool enable); 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 * there is a lot of terminal activity. * * Normally there is no need for objects other than the screen windows * created with createWindow() to listen for this signal. * * ScreenWindow objects created using createWindow() will emit their * own outputChanged() signal in response to this signal. */ void outputChanged(); /** * 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. * * 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 * should change and VALUE is a string specifying the new value. * * 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. * * @param title Specifies what to change. *
    *
  • 0 - Set window icon text and session title to @p newTitle
  • *
  • 1 - Set window icon text to @p newTitle
  • *
  • 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'). * 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 * 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 */ void titleChanged(int title, const QString &newTitle); /** * Emitted when the program running in the terminal changes the * screen size. */ 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. * * A profile change command occurs when a special escape sequence, followed * by a string containing a series of name and value pairs is received. * This string can be parsed using a ProfileCommandParser instance. * * @param text A string expected to contain a series of key and value pairs in * the form: name=value;name2=value2 ... */ 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 active screen is switched, to indicate whether the primary * screen is in use. */ void primaryScreenInUse(bool use); /** * 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(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); enum EmulationCodec { LocaleCodec = 0, Utf8Codec = 1 }; void setCodec(EmulationCodec codec); // codec number, 0 = locale, 1=utf8 QList _windows; 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 //the current text codec. (this allows for rendering of non-ASCII characters in text files etc.) const QTextCodec *_codec; QTextDecoder *_decoder; /******** Modify by ut000610 daizhengwen 2020-06-02: 让这个值能被修改****************/ /*const */KeyboardTranslator *_keyTranslator; // the keyboard layout /********************* Modify by ut000610 daizhengwen End ************************/ /** @brief 检测当前iconv使用的GB18030编码是否为2005标准,2005标准强制使用上层补丁版本 通过检测2005和2022编码转的差异,以附录D中的编码为例验证 2005标准 0xFE51 --> \u20087 2022标准 0xFE51 --> \uE816 @return iconv使用GB18030编码是否为2005标准,默认返回true */ bool detectIconvUse2005Standard(); 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. */ void bufferedUpdate(); // used to emit the primaryScreenInUse(bool) signal void checkScreenInUse(); private slots: // triggered by timer, causes the emulation to send an updated screen image to each // view void showBulk(); void usesMouseChanged(bool usesMouse); void setAlternateScrolling(bool enable); void bracketedPasteModeChanged(bool bracketedPasteMode); private: bool _usesMouse; bool _alternateScrolling; bool _bracketedPasteMode; QTimer _bulkTimer1; QTimer _bulkTimer2; int _sessionId; /******** Add by ut001000 renfeixiang 2020-07-16:增加保存上一次的屏幕行列数,用于比较终端屏宽是否发生变化 Begin***************/ // int _lastcol = 0; // int _lastline = 0; /******** Add by ut001000 renfeixiang 2020-07-16:增加 End***************/ }; } #endif // ifndef EMULATION_H deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/EscapeSequenceUrlExtractor.cpp000066400000000000000000000052561475472654300311510ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2007-2008 Robert Knight SPDX-FileCopyrightText: 1997, 1998 Lars Doelle SPDX-License-Identifier: GPL-2.0-or-later */ #include "EscapeSequenceUrlExtractor.h" #include namespace Konsole { EscapeSequenceUrlExtractor::EscapeSequenceUrlExtractor() = default; void Konsole::EscapeSequenceUrlExtractor::setScreen(Konsole::Screen* screen) { _screen = screen; clear(); } bool EscapeSequenceUrlExtractor::reading() const { return _reading; } void EscapeSequenceUrlExtractor::beginUrlInput() { _reading = true; } void EscapeSequenceUrlExtractor::appendUrlText(QChar c) { if (!reading()) { return; } if (_currentUrl.text.isEmpty()) { // We need to on getCursorX because we want the position of the // last printed character, not the cursor. const int realCcolumn = _screen->getCursorY() + _screen->getHistLines(); _currentUrl.begin = Coordinate{realCcolumn, _screen->getCursorX() - 1}; } _currentUrl.text += c; } void EscapeSequenceUrlExtractor::setUrl(const QString& url) { if (_allowedUriSchemas.contains(QUrl(url).scheme() + QLatin1String("://"))) { _currentUrl.url = url; } else { abortUrlInput(); } } void EscapeSequenceUrlExtractor::abortUrlInput() { _reading = false; _currentUrl = ExtractedUrl{}; _ignoreNextUrlInput = true; } void EscapeSequenceUrlExtractor::endUrlInput() { Q_ASSERT(reading()); _reading = false; const int realCcolumn = _screen->getCursorY() + _screen->getHistLines(); const auto currentPos = Coordinate{realCcolumn, _screen->getCursorX()}; _currentUrl.end = currentPos; _history.append(_currentUrl); _currentUrl = ExtractedUrl{}; } void EscapeSequenceUrlExtractor::clear() { _history.clear(); } void EscapeSequenceUrlExtractor::setAllowedLinkSchema(const QStringList& schema) { _allowedUriSchemas = schema; } void EscapeSequenceUrlExtractor::historyLinesRemoved(int lines) { for (auto &url : _history) { url.begin.row -= lines; url.end.row -= lines; } _history.erase( std::remove_if(std::begin(_history), std::end(_history), [](const ExtractedUrl& url) { const bool toRemove = url.begin.row < 0; return toRemove; }), std::end(_history)); } QVector EscapeSequenceUrlExtractor::history() const { return _history; } void Konsole::EscapeSequenceUrlExtractor::toggleUrlInput() { if (_ignoreNextUrlInput) { _ignoreNextUrlInput = false; return; } if (_reading) { endUrlInput(); } else { beginUrlInput(); } } } deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/EscapeSequenceUrlExtractor.h000066400000000000000000000057701475472654300306170ustar00rootroot00000000000000#ifndef ESCAPE_SEQUENCE_URL_EXTRACTOR_H #define ESCAPE_SEQUENCE_URL_EXTRACTOR_H /* SPDX-FileCopyrightText: 2007-2008 Robert Knight SPDX-FileCopyrightText: 1997, 1998 Lars Doelle SPDX-License-Identifier: GPL-2.0-or-later */ #include #include #include "Screen.h" namespace Konsole { /* Like QPoint, but with Row / Col * easier to read than x / y */ struct Coordinate { int row; int col; }; /* Represents a URL on the visual part of konsole, that has been escaped. * like a html url tag with a text value. */ struct ExtractedUrl { QString url; QString text; Coordinate begin; Coordinate end; }; /* Stored in Screen, but used in V10Emulation to * store extracted URL's. Perhaps this should be a Model? */ class EscapeSequenceUrlExtractor { private: /* Tell us if we are currently reading or not a URL. */ bool _reading = false; /* If we abort reading a URL input we enter in a invalid state, * and we need to ignore the next toggle. */ bool _ignoreNextUrlInput = false; /* The url / text pair being extracted currently */ ExtractedUrl _currentUrl; /* The maximum size of url to prevent a bomb * that will take over the history file. * TODO: make it configurable. */ //Not used ATM const int _maximumUrlHistory = 200; /* All of the extracted URL's. */ QVector _history; /* The URI schema format that's accepted */ QStringList _allowedUriSchemas; /* Pointer to the Screen, that actually holds the text data. */ Screen *_screen; public: /* This needs to have access to the Session * calculate the row / col of the current URL. */ EscapeSequenceUrlExtractor(); /* This is a list of URI schemas that are going to be supported, separated by semicolon. * like https://;file:// */ void setAllowedLinkSchema(const QStringList& allowedSchemas); void setScreen(Screen *screen); /* If we are parsing a URL */ bool reading() const; /* We found an URL, starting to parse */ void beginUrlInput(); /* We received the end byte to finish the Url. */ void endUrlInput(); /* We are not saving this URL, it's bogus. */ void abortUrlInput(); /* The URL is parsed at once, but not the text. We received * one character per time until we hit the end byte. */ void appendUrlText(QChar c); /* The URL is parsed at once, store it at once. */ void setUrl(const QString& url); /* All of the parsedURL's, used by TerminalDisplay to paint them * on screen. */ QVector history() const; /* Clear all the URL's, this is triggered when the Screen is cleared. */ void clear(); /* Iterates trough all the URL's and remove the ones that are currently * out of bounds because we removed lines in the History */ void historyLinesRemoved(int lines); /* starts / stops URL Processing */ void toggleUrlInput(); }; } #endif deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/ExtendedDefaultTranslator.h000066400000000000000000000117601475472654300304620ustar00rootroot00000000000000/* 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 (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 Lesser 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. */ "keyboard \"Default (XFree 4)\"" "key Escape : \"\\E\"" "key Tab -Shift : \"\\t\"\n" "key Tab +Shift+Ansi : \"\\E[Z\"\n" "key Tab +Shift-Ansi : \"\\t\"\n" "key Backtab +Ansi : \"\\E[Z\"\n" "key Backtab -Ansi : \"\\t\"\n" "key Return-Shift-NewLine : \"\\r\"\n" "key Return-Shift+NewLine : \"\\r\\n\"\n" "key Return+Shift : \"\\EOM\"\n" "key Backspace : \"\\x7f\"\n" "key Up -Shift-Ansi : \"\\EA\"\n" "key Down -Shift-Ansi : \"\\EB\"\n" "key Right-Shift-Ansi : \"\\EC\"\n" "key Left -Shift-Ansi : \"\\ED\"\n" "key Up -Shift-AnyMod+Ansi+AppCuKeys : \"\\EOA\"\n" "key Down -Shift-AnyMod+Ansi+AppCuKeys : \"\\EOB\"\n" "key Right -Shift-AnyMod+Ansi+AppCuKeys : \"\\EOC\"\n" "key Left -Shift-AnyMod+Ansi+AppCuKeys : \"\\EOD\"\n" "key Up -Shift-AnyMod+Ansi-AppCuKeys : \"\\E[A\"\n" "key Down -Shift-AnyMod+Ansi-AppCuKeys : \"\\E[B\"\n" "key Right -Shift-AnyMod+Ansi-AppCuKeys : \"\\E[C\"\n" "key Left -Shift-AnyMod+Ansi-AppCuKeys : \"\\E[D\"\n" "key Up -Shift+AnyMod+Ansi : \"\\E[1;*A\"\n" "key Down -Shift+AnyMod+Ansi : \"\\E[1;*B\"\n" "key Right -Shift+AnyMod+Ansi : \"\\E[1;*C\"\n" "key Left -Shift+AnyMod+Ansi : \"\\E[1;*D\"\n" "key Enter+NewLine : \"\\r\\n\"\n" "key Enter-NewLine : \"\\r\"\n" "key Home -AnyMod -AppCuKeys : \"\\E[H\" \n" "key End -AnyMod -AppCuKeys : \"\\E[F\" \n" "key Home -AnyMod +AppCuKeys : \"\\EOH\" \n" "key End -AnyMod +AppCuKeys : \"\\EOF\" \n" "key Home +AnyMod : \"\\E[1;*H\"\n" "key End +AnyMod : \"\\E[1;*F\"\n" "key Insert -AnyMod : \"\\E[2~\"\n" "key Delete -AnyMod : \"\\E[3~\"\n" "key Insert +AnyMod : \"\\E[2;*~\"\n" "key Delete +AnyMod : \"\\E[3;*~\"\n" "key Prior -Shift-AnyMod : \"\\E[5~\"\n" "key Next -Shift-AnyMod : \"\\E[6~\"\n" "key Prior -Shift+AnyMod : \"\\E[5;*~\"\n" "key Next -Shift+AnyMod : \"\\E[6;*~\"\n" "key F1 -AnyMod : \"\\EOP\"\n" "key F2 -AnyMod : \"\\EOQ\"\n" "key F3 -AnyMod : \"\\EOR\"\n" "key F4 -AnyMod : \"\\EOS\"\n" "key F5 -AnyMod : \"\\E[15~\"\n" "key F6 -AnyMod : \"\\E[17~\"\n" "key F7 -AnyMod : \"\\E[18~\"\n" "key F8 -AnyMod : \"\\E[19~\"\n" "key F9 -AnyMod : \"\\E[20~\"\n" "key F10 -AnyMod : \"\\E[21~\"\n" "key F11 -AnyMod : \"\\E[23~\"\n" "key F12 -AnyMod : \"\\E[24~\"\n" "key F1 +AnyMod : \"\\EO*P\"\n" "key F2 +AnyMod : \"\\EO*Q\"\n" "key F3 +AnyMod : \"\\EO*R\"\n" "key F4 +AnyMod : \"\\EO*S\"\n" "key F5 +AnyMod : \"\\E[15;*~\"\n" "key F6 +AnyMod : \"\\E[17;*~\"\n" "key F7 +AnyMod : \"\\E[18;*~\"\n" "key F8 +AnyMod : \"\\E[19;*~\"\n" "key F9 +AnyMod : \"\\E[20;*~\"\n" "key F10 +AnyMod : \"\\E[21;*~\"\n" "key F11 +AnyMod : \"\\E[23;*~\"\n" "key F12 +AnyMod : \"\\E[24;*~\"\n" "key Space +Control : \"\\x00\"\n" "key Up +Shift-AppScreen : scrollLineUp\n" "key Prior +Shift-AppScreen : scrollPageUp\n" "key Down +Shift-AppScreen : scrollLineDown\n" "key Next +Shift-AppScreen : scrollPageDown\n" "key ScrollLock : scrollLock\n" "\0" deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/Filter.cpp000066400000000000000000000411441475472654300251220ustar00rootroot00000000000000/* Copyright 2007-2008 by Robert Knight 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. */ // Own #include "Filter.h" #include "SessionManager.h" // System #include // Qt #include #include #include #include #include #include #include #include #include #include // KDE //#include //#include // Konsole #include "TerminalCharacterDecoder.h" #include "konsole_wcwidth.h" using namespace Konsole; FilterChain::~FilterChain() { QMutableListIterator iter(*this); while (iter.hasNext()) { Filter *filter = iter.next(); iter.remove(); delete filter; } } void FilterChain::addFilter(Filter *filter) { append(filter); } void FilterChain::removeFilter(Filter *filter) { removeAll(filter); } bool FilterChain::containsFilter(Filter *filter) { return contains(filter); } void FilterChain::reset() { QListIterator iter(*this); while (iter.hasNext()) iter.next()->reset(); } void FilterChain::setBuffer(const QString *buffer, const QList *linePositions) { QListIterator iter(*this); while (iter.hasNext()) iter.next()->setBuffer(buffer, linePositions); } void FilterChain::process() { QListIterator iter(*this); while (iter.hasNext()) iter.next()->process(); } void FilterChain::clear() { QList::clear(); } Filter::HotSpot *FilterChain::hotSpotAt(int line, int column) const { QListIterator iter(*this); while (iter.hasNext()) { Filter *filter = iter.next(); Filter::HotSpot *spot = filter->hotSpotAt(line, column); if (spot != nullptr) { return spot; } } return nullptr; } QList FilterChain::hotSpots() const { QList list; QListIterator iter(*this); while (iter.hasNext()) { Filter *filter = iter.next(); list << filter->hotSpots(); } return list; } //QList FilterChain::hotSpotsAtLine(int line) const; void FilterChain::setSessionId(int sessionId) { _sessionId = sessionId; } TerminalImageFilterChain::TerminalImageFilterChain() : _buffer(nullptr) , _linePositions(nullptr) { } TerminalImageFilterChain::~TerminalImageFilterChain() { delete _buffer; delete _linePositions; } //判断是否包含>=两种类型的提示符结尾字符(比如: root@zhangsan-PC# echo $ XXXXX 这种情况) //防止截取shell提示符出错,比如将'root@zhangsan-PC# echo $ XXXXX'中的'root@zhangsan-PC# echo '截取出来当作提示符 bool isContainOtherPromptEnd(QString promptLine, QString currPromptEnd) { //四不同类型的提示符结尾字符 QString promptEnds = QString("$#%>"); promptEnds.remove(currPromptEnd); for (int i=0; i &lineProperties) { if (empty()) return; // reset all filters and hotspots reset(); PlainTextDecoder decoder; decoder.setTrailingWhitespace(false); // setup new shared buffers for the filters to process on QString *newBuffer = new QString(); QList *newLinePositions = new QList(); setBuffer(newBuffer, newLinePositions); // free the old buffers delete _buffer; delete _linePositions; _buffer = newBuffer; _linePositions = newLinePositions; QTextStream lineStream(_buffer); decoder.begin(&lineStream); QString lastLine = ""; for (int i = 0 ; i < lines ; i++) { _linePositions->append(_buffer->length()); decoder.decodeLine(image + i * columns, columns, LINE_DEFAULT); // pretend that each line ends with a newline character. // this prevents a link that occurs at the end of one line // 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. // // 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 << QLatin1Char('\n'); QString tempLine = lineStream.readAll().trimmed(); if (tempLine.length() > 0) { lastLine = tempLine; } } decoder.end(); /* fix bug 33638 使用sudo apt-get install csh ksh zsh tcsh安装其它shell后,执行卸载终端未弹出卸载弹框 */ if (lastLine.length() > 0) { //优化了截取并保存当前shell提示符的判断,暂时没有考虑PS1被修改的情况(若考虑的话实现起来太复杂) //目前针对sh/bash/csh/tcsh/ksh/zsh这几种类型的shell做了处理 QString promptEnds = QString("$#%>"); for (int i=0; isaveCurrShellPrompt(_sessionId, lastLine); break; } } } QString strShellPrompt = SessionManager::instance()->getCurrShellPrompt(_sessionId); bool isRootUser = strShellPrompt.endsWith("#"); QString strCurrBuffer = (*_buffer).trimmed(); if (strCurrBuffer.length() > 0) { //获取并保存当前正在输入的命令 if (isRootUser) { QString strCommand = strCurrBuffer.split(strShellPrompt).last(); if (!strCommand.contains("sudo ")) { strCommand = QString("sudo %1").arg(strCommand); } SessionManager::instance()->saveCurrShellCommand(_sessionId, strCommand); } else { QString strCommand = strCurrBuffer.split(strShellPrompt).last(); SessionManager::instance()->saveCurrShellCommand(_sessionId, strCommand); } } } Filter::Filter() : _linePositions(nullptr), _buffer(nullptr) { } Filter::~Filter() { qDeleteAll(_hotspotList); _hotspotList.clear(); } void Filter::reset() { qDeleteAll(_hotspotList); _hotspots.clear(); _hotspotList.clear(); } void Filter::setBuffer(const QString *buffer, const QList *linePositions) { _buffer = buffer; _linePositions = linePositions; } void Filter::getLineColumn(int position, int &startLine, int &startColumn) { Q_ASSERT(_linePositions); Q_ASSERT(_buffer); for (int i = 0 ; i < _linePositions->count() ; i++) { int nextLine = 0; if (i == _linePositions->count() - 1) nextLine = _buffer->length() + 1; else nextLine = _linePositions->value(i + 1); if (_linePositions->value(i) <= position && position < nextLine) { startLine = i; startColumn = Character::stringWidth(buffer()->mid(_linePositions->value(i), position - _linePositions->value(i))); return; } } } /*void Filter::addLine(const QString& text) { _linePositions << _buffer.length(); _buffer.append(text); }*/ const QString *Filter::buffer() { return _buffer; } Filter::HotSpot::~HotSpot() { } void Filter::addHotSpot(HotSpot *spot) { _hotspotList << spot; for (int line = spot->startLine() ; line <= spot->endLine() ; line++) { _hotspots.insert(line, spot); } } QList Filter::hotSpots() const { return _hotspotList; } QList Filter::hotSpotsAtLine(int line) const { return _hotspots.values(line); } Filter::HotSpot *Filter::hotSpotAt(int line, int column) const { QListIterator spotIter(_hotspots.values(line)); 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; } return nullptr; } Filter::HotSpot::HotSpot(int startLine, int startColumn, int endLine, int endColumn) : _startLine(startLine) , _startColumn(startColumn) , _endLine(endLine) , _endColumn(endColumn) , _type(NotSpecified) { } QList Filter::HotSpot::actions() { return QList(); } int Filter::HotSpot::startLine() const { return _startLine; } int Filter::HotSpot::endLine() const { return _endLine; } int Filter::HotSpot::startColumn() const { return _startColumn; } int Filter::HotSpot::endColumn() const { return _endColumn; } Filter::HotSpot::Type Filter::HotSpot::type() const { return _type; } void Filter::HotSpot::setType(Type type) { _type = type; } RegExpFilter::RegExpFilter() { } RegExpFilter::HotSpot::HotSpot(int startLine, int startColumn, int endLine, int endColumn) : Filter::HotSpot(startLine, startColumn, endLine, endColumn) { setType(Marker); } void RegExpFilter::HotSpot::activate(const QString &) { } void RegExpFilter::HotSpot::setCapturedTexts(const QStringList &texts) { _capturedTexts = texts; } QStringList RegExpFilter::HotSpot::capturedTexts() const { return _capturedTexts; } void RegExpFilter::setRegExp(const QRegExp ®Exp) { _searchText = regExp; } QRegExp RegExpFilter::regExp() const { return _searchText; } /*void RegExpFilter::reset(int) { _buffer = QString(); }*/ void RegExpFilter::process() { int pos = 0; const QString *text = buffer(); Q_ASSERT(text); // ignore any regular expressions which match an empty string. // otherwise the while loop below will run indefinitely static const QString emptyString; if (_searchText.exactMatch(emptyString)) return; while (pos >= 0) { pos = _searchText.indexIn(*text, pos); if (pos >= 0) { int startLine = 0; int endLine = 0; int startColumn = 0; int endColumn = 0; getLineColumn(pos, startLine, startColumn); getLineColumn(pos + _searchText.matchedLength(), endLine, endColumn); RegExpFilter::HotSpot *spot = newHotSpot(startLine, startColumn, endLine, endColumn); spot->setCapturedTexts(_searchText.capturedTexts()); 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, int endLine, int endColumn) { return new RegExpFilter::HotSpot(startLine, startColumn, endLine, endColumn); } RegExpFilter::HotSpot *UrlFilter::newHotSpot(int startLine, int startColumn, int endLine, int endColumn) { HotSpot *spot = new UrlFilter::HotSpot(startLine, startColumn, endLine, endColumn); connect(spot->getUrlObject(), &FilterObject::activated, this, &UrlFilter::activated); return spot; } UrlFilter::HotSpot::HotSpot(int startLine, int startColumn, int endLine, int endColumn) : RegExpFilter::HotSpot(startLine, startColumn, endLine, endColumn) , _urlObject(new FilterObject(this)) { setType(Link); } UrlFilter::HotSpot::UrlType UrlFilter::HotSpot::urlType() const { QString url = capturedTexts().constFirst(); if (FullUrlRegExp.exactMatch(url)) return StandardUrl; else if (EmailAddressRegExp.exactMatch(url)) return Email; else return Unknown; } void UrlFilter::HotSpot::activate(const QString &actionName) { QString url = capturedTexts().constFirst(); const UrlType kind = urlType(); if (actionName == QLatin1String("copy-action")) { QApplication::clipboard()->setText(url); return; } 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(QLatin1String("://"))) { url.prepend(QLatin1String("http://")); } } else if (kind == Email) { url.prepend(QLatin1String("mailto:")); } _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 // 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: // protocolname:// or www. followed by anything other than whitespaces, <, >, ' or ", and ends before whitespaces, <, >, ', ", ], !, comma and dot /** modify begin by ut001121 zhangmeng 20201215 for 1040-4 Ctrl键+鼠标点击超链接打开网页 */ /** del const QRegExp UrlFilter::FullUrlRegExp(QLatin1String("(www\\.(?!\\.)|[a-z][a-z0-9+.-]*://)[^\\s<>'\"]+[^!,\\.\\s<>'\"\\]]"));*/ const QRegExp UrlFilter::FullUrlRegExp(QLatin1String("(www\\.(?!\\.)|[a-z][a-z0-9+.-]*://)[\\w-.@]+" "([:]((6553[0-5])|[655[0-2][0-9]|65[0-4][0-9]{2}|6[0-4][0-9]{3}|[1-5][0-9]{4}|[1-9][0-9]{3}|[1-9][0-9]{2}|[1-9][0-9]|[0-9])[^0-9])?" "([/][\\w\\-\\@?^=%&/~\\+#.]+)?")); /** modify end by ut001121 */ // email address: // [word chars, dots or dashes]@[word chars, dots or dashes].[word chars] const QRegExp UrlFilter::EmailAddressRegExp(QLatin1String("\\b(\\w|\\.|-)+@(\\w|\\.|-)+\\.\\w+\\b")); // matches full url or email address const QRegExp UrlFilter::CompleteUrlRegExp(QLatin1Char('(') + FullUrlRegExp.pattern() + QLatin1Char('|') + EmailAddressRegExp.pattern() + QLatin1Char(')')); UrlFilter::UrlFilter() { setRegExp(CompleteUrlRegExp); } UrlFilter::HotSpot::~HotSpot() { delete _urlObject; } void FilterObject::emitActivated(const QUrl &url, bool fromContextMenu) { emit activated(url, fromContextMenu); } void FilterObject::activate() { _filter->activate(sender()->objectName()); } FilterObject *UrlFilter::HotSpot::getUrlObject() const { return _urlObject; } QList UrlFilter::HotSpot::actions() { QList list; const UrlType kind = urlType(); QAction *openAction = new QAction(_urlObject); QAction *copyAction = new QAction(_urlObject);; Q_ASSERT(kind == StandardUrl || kind == Email); if (kind == StandardUrl) { openAction->setText(QObject::tr("Open link")); copyAction->setText(QObject::tr("Copy link")); } else if (kind == Email) { openAction->setText(QObject::tr("Send email to...")); copyAction->setText(QObject::tr("Copy email address")); } // object names are set here so that the hotspot performs the // correct action when activated() is called with the triggered // action passed as a parameter. openAction->setObjectName(QLatin1String("open-action")); copyAction->setObjectName(QLatin1String("copy-action")); QObject::connect(openAction, &QAction::triggered, _urlObject, &FilterObject::activate); QObject::connect(copyAction, &QAction::triggered, _urlObject, &FilterObject::activate); list << openAction; list << copyAction; return list; } //#include "Filter.moc" deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/Filter.h000066400000000000000000000325131475472654300245670ustar00rootroot00000000000000/* Copyright 2007-2008 by Robert Knight 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. */ #ifndef FILTER_H #define FILTER_H // Qt #include #include #include #include #include #include // Local #include "qtermwidget_export.h" namespace Konsole { typedef unsigned char LineProperty; class Character; /** * A filter processes blocks of text looking for certain patterns (such as URLs or keywords from a list) * and marks the areas which match the filter's patterns as 'hotspots'. * * Each hotspot has a type identifier associated with it ( such as a link or a highlighted section ), * and an action. When the user performs some activity such as a mouse-click in a hotspot area ( the exact * action will depend on what is displaying the block of text which the filter is processing ), the hotspot's * 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. * * Different subclasses of filter will return different types of hotspot. * Subclasses must reimplement the process() method to examine a block of text and identify sections of interest. * When processing the text they should create instances of Filter::HotSpot subclasses for sections of interest * and add them to the filter's list of hotspots using addHotSpot() */ class TERMINALWIDGET_EXPORT Filter : public QObject { public: /** * Represents an area of text which matched the pattern a particular filter has been looking for. * * Each hotspot has a type identifier associated with it ( such as a link or a highlighted section ), * and an action. When the user performs some activity such as a mouse-click in a hotspot area ( the exact * action will depend on what is displaying the block of text which the filter is processing ), the hotspot's * 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. */ 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. */ HotSpot(int startLine, int startColumn, int endLine, int endColumn); virtual ~HotSpot(); enum Type { // the type of the hotspot is not specified NotSpecified, // this hotspot represents a clickable link Link, // this hotspot represents a marker Marker }; /** Returns the line when the hotspot area starts */ int startLine() const; /** Returns the line where the hotspot area ends */ int endLine() const; /** Returns the column on startLine() where the hotspot area starts */ 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. * * @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. */ 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 */ virtual QList actions(); protected: /** Sets the type of a hotspot. This should only be set once */ void setType(Type type); private: int _startLine; int _startColumn; int _endLine; int _endColumn; Type _type; }; /** Constructs a new filter. */ Filter(); ~Filter() override; /** 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. */ void reset(); /** Adds a new line of text to the filter and increments the line count */ //void addLine(const QString& string); /** Returns the hotspot which covers the given @p line and @p column, or 0 if no hotspot covers that area */ HotSpot *hotSpotAt(int line, int column) const; /** Returns the list of hotspots identified by the filter */ QList hotSpots() const; /** 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); protected: /** Adds a new hotspot to the list */ void addHotSpot(HotSpot *); /** Returns the internal buffer */ const QString *buffer(); /** Converts a character position within buffer() to a line and column */ void getLineColumn(int position, int &startLine, int &startColumn); 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 * instance for them. * * Subclasses can reimplement newHotSpot() to return custom hotspot types when matches for the regular expression * are found. */ class TERMINALWIDGET_EXPORT 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. */ class HotSpot : public Filter::HotSpot { public: HotSpot(int startLine, int startColumn, int endLine, int endColumn); void activate(const QString &action = QString()) override; /** Sets the captured texts associated with this hotspot */ void setCapturedTexts(const QStringList &texts); /** Returns the texts found by the filter when matching the filter's regular expression */ QStringList capturedTexts() const; private: QStringList _capturedTexts; }; /** Constructs a new regular expression filter */ RegExpFilter(); /** * 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. */ 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() * * If regexp matches the empty string, then process() will return immediately * without finding results. */ void process() override; protected: /** * Called when a match for the regular expression is encountered. Subclasses should reimplement this * to return custom hotspot types */ virtual RegExpFilter::HotSpot *newHotSpot(int startLine, int startColumn, int endLine, int endColumn); private: QRegExp _searchText; }; class FilterObject; /** A filter which matches URLs in blocks of text */ class TERMINALWIDGET_EXPORT UrlFilter : public RegExpFilter { Q_OBJECT public: /** * Hotspot type created by UrlFilter instances. The activate() method opens a web browser * at the given URL when called. */ class HotSpot : public RegExpFilter::HotSpot { public: HotSpot(int startLine, int startColumn, int endLine, int endColumn); ~HotSpot() override; FilterObject *getUrlObject() const; QList actions() override; /** * Open a web browser at the current URL. The url itself can be determined using * the capturedTexts() method. */ void activate(const QString &action = QString()) override; private: enum UrlType { StandardUrl, Email, Unknown }; UrlType urlType() const; FilterObject *_urlObject; }; UrlFilter(); protected: RegExpFilter::HotSpot *newHotSpot(int, int, int, int) override; private: static const QRegExp FullUrlRegExp; static const QRegExp EmailAddressRegExp; // combined OR of FullUrlRegExp and EmailAddressRegExp static const QRegExp CompleteUrlRegExp; signals: void activated(const QUrl &url, bool fromContextMenu); }; class TERMINALWIDGET_EXPORT FilterObject : public QObject { Q_OBJECT public: explicit FilterObject(Filter::HotSpot *filter) : _filter(filter) {} void emitActivated(const QUrl &url, bool fromContextMenu); public slots: void activate(); private: Filter::HotSpot *_filter; signals: void activated(const QUrl &url, bool fromContextMenu); }; /** * 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. * 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. * * After processing a block of text, the reset() method can be used to set the filter chain's * internal cursor back to the first line. * * The hotSpotAt() method will return the first hotspot which covers a given position. * * The hotSpots() and hotSpotsAtLine() method return all of the hotspots in the text and on * a given line respectively. */ class TERMINALWIDGET_EXPORT FilterChain : protected QList { public: virtual ~FilterChain(); /** Adds a new filter to the chain. The chain will delete this filter when it is destroyed */ void addFilter(Filter *filter); /** Removes a filter from the chain. The chain will no longer delete the filter when destroyed */ void removeFilter(Filter *filter); /** Returns true if the chain contains @p filter */ bool containsFilter(Filter *filter); /** Removes all filters from the chain */ void clear(); /** Resets each filter in the chain */ void reset(); /** * 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); /** 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; /** Returns a list of all the hotspots in all the chain's filters */ QList hotSpots() const; /** Returns a list of all hotspots at the given line in all the chain's filters */ QList hotSpotsAtLine(int line) const; void setSessionId(int sessionId); protected: int _sessionId; }; /** A filter chain which processes character images from terminal displays */ class TERMINALWIDGET_EXPORT TerminalImageFilterChain : public FilterChain { public: TerminalImageFilterChain(); ~TerminalImageFilterChain() override; /** * Set the current terminal image to @p image. * * @param image The terminal image * @param lines The number of lines in the terminal image * @param columns The number of columns in the terminal image * @param lineProperties The line properties to set for image */ void setImage(const Character *const image, int lines, int columns, const QVector &lineProperties); private: QString *_buffer; QList *_linePositions; }; } typedef Konsole::Filter Filter; #endif //FILTER_H deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/HistorySearch.cpp000066400000000000000000000357061475472654300264730ustar00rootroot00000000000000/* Copyright 2013 Christian Surlykke 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. */ #include #include #include #include "TerminalCharacterDecoder.h" #include "Emulation.h" #include "HistorySearch.h" HistorySearch::HistorySearch(EmulationPtr emulation, QString searchText, bool forwards, bool isLastForwards, int startColumn, int startLine, QObject *parent) : QObject(parent), m_emulation(emulation), m_searchText(searchText), m_forwards(forwards), m_isLastForwards(isLastForwards), m_startColumn(startColumn), m_startLine(startLine), m_foundStartColumn(0), m_foundStartLine(0), m_foundEndColumn(0), m_foundEndLine(0), m_loseChinese(0), m_matchChinese(0), m_lastBackwardsPosition(-1) { } HistorySearch::~HistorySearch() { } void HistorySearch::search(int currBackwardsPosition, int lastFoundStartColumn, int lastFoundStartLine) { bool found = false; m_currBackwardsPosition = currBackwardsPosition; m_lastFoundStartColumn = lastFoundStartColumn; m_lastFoundStartLine = lastFoundStartLine; if (!m_searchText.isEmpty()) { if (m_forwards) { found = search(m_startColumn, m_startLine, -1, m_emulation->lineCount()) || search(0, 0, m_startColumn, m_startLine); } 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, m_lastBackwardsPosition, m_loseChinese, m_matchChinese); } else { emit noMatchFound(); } } deleteLater(); } bool HistorySearch::search(int startColumn, int startLine, int endColumn, int endLine) { qDebug() << "search from" << startColumn << "," << startLine << "to" << endColumn << "," << endLine; int linesRead = 0; int linesToRead = endLine - startLine + 1; QString stringBackwardsAfterForwards; QTextStream backwardsAfterForwardsStream(&stringBackwardsAfterForwards); QString string; QTextStream searchStream(&string); // 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) { 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; int blockEndLine = blockStartLine + blockSize - 1; m_emulation->writeToStream(&decoder, blockStartLine, blockEndLine); decoder.end(); // 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 // empty line - we ignore that. int numberOfLinesInString = decoder.linePositions().size() - 1; if (numberOfLinesInString > 0 && endColumn > -1) { endPosition = decoder.linePositions().at(numberOfLinesInString - 1) + endColumn; qDebug() << "endPosition 0:" << endPosition; if (!m_forwards) { qDebug() << "numberOfLinesInString string.size():" << string.size(); if ((endPosition - string.size()) > 0) { endPosition = string.size(); qDebug() << "endPosition 1:" << endPosition; } else { qDebug() << "m_currBackwardsPosition:" << m_currBackwardsPosition; //上次进行正向搜索,当前采用反向搜索 if (m_isLastForwards) { PlainTextDecoder decoder; decoder.begin(&backwardsAfterForwardsStream); decoder.setRecordLinePositions(false); int blockStartLine = 0; int blockEndLine = m_lastFoundStartLine-1; if (-1 == blockEndLine) { blockEndLine = m_emulation->lineCount(); } m_emulation->writeToStream(&decoder, blockStartLine, blockEndLine); decoder.end(); endPosition = stringBackwardsAfterForwards.length() + endColumn; qDebug() << "endPosition 2:" << endPosition; } else { qDebug() << "endPosition now is:" << endPosition; //endPosition值比上次搜索结果的位置还大,则重新计算endPosition if (m_currBackwardsPosition > -1) { if ((endPosition - m_currBackwardsPosition > m_searchText.length())) { endPosition = m_currBackwardsPosition - m_searchText.length(); qDebug() << "endPosition > m_currBackwardsPosition 111:" << endPosition; } else { endPosition = m_currBackwardsPosition; qDebug() << "endPosition < m_currBackwardsPosition 222:" << endPosition; } } qDebug() << "endPosition 3:" << endPosition; } } //保存上次反向搜索的结束位置 if (endPosition != -1) { m_lastBackwardsPosition = endPosition; qDebug() << "backwards save m_lastBackwardsPosition 1:" << m_lastBackwardsPosition; } } } else { if (m_forwards) { endPosition = string.size(); qDebug() << "endPosition 4:" << endPosition; } else { endPosition = endColumn; //保存上次反向搜索的结束位置 if (endPosition != -1) { m_lastBackwardsPosition = endPosition; qDebug() << "backwards save m_lastBackwardsPosition2:" << m_lastBackwardsPosition; } } } qDebug() << "At last, endPosition is:" << endPosition; // So now we can log for m_regExp in the string between startColumn and endPosition int matchStart = -1; if (m_forwards) { matchStart = string.indexOf(m_searchText, startColumn, Qt::CaseSensitive); qDebug() << "forwards matchStart:" << matchStart << ", startColumn:" << startColumn; if (matchStart >= endPosition) { matchStart = -1; } } else { qDebug() << "string length:" << string.length() << ", endPosition:" << endPosition; //考虑了查找结果在第一行的情况 if (0 == startLine && startLine == endLine && endPosition > endColumn) { endPosition = endColumn; } matchStart = string.lastIndexOf(m_searchText, endPosition - 1, Qt::CaseSensitive); if (matchStart != -1) { m_lastBackwardsPosition = matchStart; qDebug() << "backwards save m_lastBackwardsPosition3:" << m_lastBackwardsPosition; } qDebug() << "backwards matchStart:" << matchStart << ", startColumn:" << startColumn; // if (matchStart < startColumn) { // matchStart = -1; // qDebug() << "backwards matchStart == -1:" << matchStart; // } } if (matchStart > -1) { int matchEnd = matchStart + m_searchText.length() - 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); m_foundStartLine = startLineNumberInString + startLine + linesRead; int endLineNumberInString = findLineNumberInString(decoder.linePositions(), matchEnd); m_foundEndColumn = matchEnd - decoder.linePositions().at(endLineNumberInString); m_foundEndLine = endLineNumberInString + startLine + linesRead; //特殊情况, 反向查找需要重新计算下endPosition并保存到m_lastBackwardsPosition if (!m_forwards) { //考虑了查找结果在第一行的情况 if (0 == m_foundStartLine && m_foundStartLine == m_foundEndLine) { m_lastBackwardsPosition = m_foundStartColumn; qDebug() << "ready to change m_foundStartColumn: " << m_foundStartColumn; qDebug() << "ready to change m_foundEndColumn: " << m_foundEndColumn; qDebug() << "ready to change m_foundStartLine: " << m_foundStartLine; qDebug() << "ready to change m_foundEndLine: " << m_foundEndLine; } else if (-1 == endPosition || -1 == endColumn) { QString stringAfterSearch; QTextStream afterSearchStream(&stringAfterSearch); PlainTextDecoder decoder; decoder.begin(&afterSearchStream); decoder.setRecordLinePositions(false); int blockStartLine = 0; int blockEndLine = m_foundStartLine-1; if (-1 == blockEndLine) { blockEndLine = m_emulation->lineCount(); } m_emulation->writeToStream(&decoder, blockStartLine, blockEndLine); decoder.end(); m_lastBackwardsPosition = stringAfterSearch.length() + m_foundStartColumn; qDebug() << "ready to change m_lastBackwardsPosition: " << m_lastBackwardsPosition; } } //看看能不能从m_foundEndColumn m_foundEndLine和m_foundStartColumn m_foundStartLine推算出目前查找的字符串index //在正向查找的时候,保存当前indexOf(search, totalString) 到 m_lastBackwardsPosition // 总共读了多少行,记录下字符串总长度,加上当前偏移量 qDebug() << "changed m_foundStartColumn" << m_foundStartColumn << "changed m_foundStartLine" << m_foundStartLine << "changed m_foundEndColumn" << m_foundEndColumn << "changed m_foundEndLine" << m_foundEndLine; /***add begin by ut001121 zhangmeng 20200515 修复BUG22626***/ /** string: aaa-------------bbbbbbbbbbbbb-------ccc | || | match pos:| |matchStart matchEnd lose pos: loseStart loseEnd | line pos: lineStart lineEnd 存在特殊情况:一个完整的物理行显示在终端被分成多个逻辑行 */ //中文字符正则表达式 QRegExp regEx("[\u4E00-\u9FA5,《。》、?;:【】~!¥()]+"); //未匹配的串-物理行开始和结束位置 int loseEnd = matchStart; int loseStart = string.lastIndexOf('\n', loseEnd) + 1; //qDebug() << "loseStart" << loseStart << "loseEnd" << loseEnd ; // if (loseStart < 0 || loseStart > loseEnd) { // exit(-1); // } //未匹配的串-物理行字符串 QString loseStr = string.mid(loseStart, loseEnd - loseStart); //qDebug() << "loseStr" << loseStr << m_lineChinese; //未匹配的串-逻辑行字符串 int loseEndLineNumberInString = findLineNumberInString(decoder.linePositions(), loseEnd); int loseEndColumn = matchStart - decoder.linePositions().at(loseEndLineNumberInString); QString logicLoseStr = loseStr.right(loseEndColumn); m_loseChinese = logicLoseStr.count(regEx); //qDebug() << "logicLoseStr" << logicLoseStr << m_lineChinese << loseEndColumn; //匹配内容是否跨多个逻辑行 if (m_foundStartLine == m_foundEndLine) { /* * 单逻辑行匹配情况 * 匹配字符的当前逻辑行:(匹配字符-当前逻辑行-开始位置)--->(匹配字符-当前逻辑行-结束位置 */ //匹配字符包含中文字符数量 QString txt = m_searchText;//m_regExp.pattern(); m_matchChinese = txt.count(regEx); m_matchChinese += m_loseChinese; } else { /* * 多逻辑行匹配情况 * 匹配字符的尾行逻辑行:(匹配字符-尾行逻辑行-开始位置)--->(匹配字符-尾行逻辑行-结束位置) */ QString macthStr = string.mid(loseStart, matchEnd - loseStart + 1); QString tailMacthStr = macthStr.right(m_foundEndColumn + 1); //qDebug() << "tailMacthStr" << tailMacthStr; m_matchChinese = tailMacthStr.count(regEx) ; /* * 跨行匹配不计算m_loseChinese * m_matchChinese += m_loseChinese; */ } /***add end by ut001121***/ return true; } linesRead += blockSize; } qInfo() << "History Search Not found"; return false; } int HistorySearch::findLineNumberInString(QList linePositions, int position) { int lineNum = 0; while (lineNum + 1 < linePositions.size() && linePositions[lineNum + 1] <= position) lineNum++; return lineNum; } deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/HistorySearch.h000066400000000000000000000044451475472654300261340ustar00rootroot00000000000000/* Copyright 2013 Christian Surlykke 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. */ #ifndef TASK_H #define TASK_H #include #include #include #include #include #include "Emulation.h" #include "TerminalCharacterDecoder.h" using namespace Konsole; typedef QPointer EmulationPtr; class HistorySearch : public QObject { Q_OBJECT public: explicit HistorySearch(EmulationPtr emulation, QString searchText, bool forwards, bool isLastForwards, int startColumn, int startLine, QObject* parent); ~HistorySearch() override; void search(int currBackwardsPosition, int lastFoundStartColumn, int lastFoundStartLine); signals: void matchFound(int startColumn, int startLine, int endColumn, int endLine, int lastBackwardsPosition, int loseChinese, int matchChinese); void noMatchFound(); private: bool search(int startColumn, int startLine, int endColumn, int endLine); int findLineNumberInString(QList linePositions, int position); EmulationPtr m_emulation; QString m_searchText; bool m_forwards; bool m_isLastForwards; int m_startColumn; int m_startLine; int m_foundStartColumn; int m_foundStartLine; int m_foundEndColumn; int m_foundEndLine; int m_loseChinese; int m_matchChinese; int m_currBackwardsPosition; int m_lastBackwardsPosition; int m_lastFoundStartColumn; int m_lastFoundStartLine; }; #endif /* TASK_H */ deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/KeyboardTranslator.cpp000066400000000000000000000732271475472654300275160ustar00rootroot00000000000000/* This source file is part of Konsole, a terminal emulator. Copyright 2007-2008 by Robert Knight 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. */ // Own #include "KeyboardTranslator.h" // System #include #include // Qt #include #include #include #include #include #include #include #include "tools.h" // KDE //#include //#include //#include using namespace Konsole; const QByteArray KeyboardTranslatorManager::defaultTranslatorText( "keyboard \"Fallback Key Translator\"\n" "key Tab : \"\\t\"" ); #ifdef Q_OS_MAC // On Mac, Qt::ControlModifier means Cmd, and MetaModifier means Ctrl const Qt::KeyboardModifier KeyboardTranslator::CTRL_MOD = Qt::MetaModifier; #else const Qt::KeyboardModifier KeyboardTranslator::CTRL_MOD = Qt::ControlModifier; #endif KeyboardTranslatorManager::KeyboardTranslatorManager() : _haveLoadedAll(false) { } KeyboardTranslatorManager::~KeyboardTranslatorManager() { qDeleteAll(_translators); } QString KeyboardTranslatorManager::findTranslatorPath(const QString& name) { return QString(get_kb_layout_dir() + name + QLatin1String(".keytab")); //return KGlobal::dirs()->findResource("data","konsole/"+name+".keytab"); } void KeyboardTranslatorManager::findTranslators() { QDir dir(get_kb_layout_dir()); QStringList filters; filters << QLatin1String("*.keytab"); dir.setNameFilters(filters); QStringList list = dir.entryList(filters); // QStringList list = KGlobal::dirs()->findAllResources("data", // "konsole/*.keytab", // KStandardDirs::NoDuplicates); // add the name of each translator to the list and associated // the name with a null pointer to indicate that the translator // has not yet been loaded from disk QStringListIterator listIter(list); while (listIter.hasNext()) { QString translatorPath = listIter.next(); QString name = QFileInfo(translatorPath).baseName(); if ( !_translators.contains(name) ) _translators.insert(name,0); } _haveLoadedAll = true; } const KeyboardTranslator* KeyboardTranslatorManager::findTranslator(const QString& name) { if ( name.isEmpty() ) return defaultTranslator(); if ( _translators.contains(name) && _translators[name] != 0 ) return _translators[name]; KeyboardTranslator* translator = loadTranslator(name); if ( translator != nullptr ) _translators[name] = translator; else if ( !name.isEmpty() ) qDebug() << "Unable to load translator" << name; return translator; } bool KeyboardTranslatorManager::saveTranslator(const KeyboardTranslator* translator) { qDebug() << "KeyboardTranslatorManager::saveTranslator" << "unimplemented"; Q_UNUSED(translator); #if 0 const QString path = KGlobal::dirs()->saveLocation("data","konsole/")+translator->name() +".keytab"; //kDebug() << "Saving translator to" << path; QFile destination(path); if (!destination.open(QIODevice::WriteOnly | QIODevice::Text)) { qDebug() << "Unable to save keyboard translation:" << destination.errorString(); return false; } { KeyboardTranslatorWriter writer(&destination); writer.writeHeader(translator->description()); QListIterator iter(translator->entries()); while ( iter.hasNext() ) writer.writeEntry(iter.next()); } destination.close(); #endif return true; } KeyboardTranslator* KeyboardTranslatorManager::loadTranslator(const QString& name) { const QString& path = findTranslatorPath(name); QFile source(path); if (name.isEmpty() || !source.open(QIODevice::ReadOnly | QIODevice::Text)) return nullptr; return loadTranslator(&source,name); } 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(QLatin1String("default")); if (!translator) { QBuffer textBuffer; textBuffer.setData(defaultTranslatorText); textBuffer.open(QIODevice::ReadOnly); translator = loadTranslator(&textBuffer,QLatin1String("fallback")); } return translator; } KeyboardTranslator* KeyboardTranslatorManager::loadTranslator(QIODevice* source,const QString& name) { KeyboardTranslator* translator = new KeyboardTranslator(name); KeyboardTranslatorReader reader(source); translator->setDescription( reader.description() ); while ( reader.hasNextEntry() ) translator->addEntry(reader.nextEntry()); source->close(); if ( !reader.parseError() ) { return translator; } else { delete translator; return nullptr; } } KeyboardTranslatorWriter::KeyboardTranslatorWriter(QIODevice* destination) : _destination(destination) { Q_ASSERT( destination && destination->isWritable() ); _writer = new QTextStream(_destination); } KeyboardTranslatorWriter::~KeyboardTranslatorWriter() { delete _writer; } void KeyboardTranslatorWriter::writeHeader( const QString& description ) { *_writer << "keyboard \"" << description << '\"' << '\n'; } void KeyboardTranslatorWriter::writeEntry( const KeyboardTranslator::Entry& entry ) { QString result; if ( entry.command() != KeyboardTranslator::NoCommand ) result = entry.resultToString(); else result = QLatin1Char('\"') + entry.resultToString() + QLatin1Char('\"'); *_writer << QLatin1String("key ") << entry.conditionToString() << QLatin1String(" : ") << result << QLatin1Char('\n'); } // each line of the keyboard translation file is one of: // // - keyboard "name" // - key KeySequence : "characters" // - key KeySequence : CommandName // // 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 // assumed not to be a part of the sequence. The key sequence may contain whitespace // // eg: "key Up+Shift : scrollLineUp" // "key Next-Shift : "\E[6~" // // (lines containing only whitespace are ignored, parseLine assumes that comments have // already been removed) // KeyboardTranslatorReader::KeyboardTranslatorReader( QIODevice* source ) : _source(source) , _hasNext(false) { // read input until we find the description while ( _description.isEmpty() && !source->atEnd() ) { QList tokens = tokenize( QString::fromUtf8(source->readLine()) ); if ( !tokens.isEmpty() && tokens.first().type == Token::TitleKeyword ) _description = tokens[1].text; } // read first entry (if any) readNext(); } void KeyboardTranslatorReader::readNext() { // find next entry while ( !_source->atEnd() ) { const QList& tokens = tokenize( QString::fromUtf8(_source->readLine()) ); if ( !tokens.isEmpty() && tokens.first().type == Token::KeyKeyword ) { KeyboardTranslator::States flags = KeyboardTranslator::NoState; KeyboardTranslator::States flagMask = KeyboardTranslator::NoState; Qt::KeyboardModifiers modifiers = Qt::NoModifier; Qt::KeyboardModifiers modifierMask = Qt::NoModifier; int keyCode = Qt::Key_unknown; decodeSequence(tokens[1].text.toLower(), keyCode, modifiers, modifierMask, flags, flagMask); KeyboardTranslator::Command command = KeyboardTranslator::NoCommand; QByteArray text; // get text or command if ( tokens[2].type == Token::OutputText ) { text = tokens[2].text.toLocal8Bit(); } else if ( tokens[2].type == Token::Command ) { // identify command if (!parseAsCommand(tokens[2].text,command)) qDebug() << "Command" << tokens[2].text << "not understood."; } KeyboardTranslator::Entry newEntry; newEntry.setKeyCode( keyCode ); newEntry.setState( flags ); newEntry.setStateMask( flagMask ); newEntry.setModifiers( modifiers ); newEntry.setModifierMask( modifierMask ); newEntry.setText( text ); newEntry.setCommand( command ); _nextEntry = newEntry; _hasNext = true; return; } } _hasNext = false; } bool KeyboardTranslatorReader::parseAsCommand(const QString& text,KeyboardTranslator::Command& command) { if ( text.compare(QLatin1String("erase"),Qt::CaseInsensitive) == 0 ) command = KeyboardTranslator::EraseCommand; else if ( text.compare(QLatin1String("scrollpageup"),Qt::CaseInsensitive) == 0 ) command = KeyboardTranslator::ScrollPageUpCommand; else if ( text.compare(QLatin1String("scrollpagedown"),Qt::CaseInsensitive) == 0 ) command = KeyboardTranslator::ScrollPageDownCommand; else if ( text.compare(QLatin1String("scrolllineup"),Qt::CaseInsensitive) == 0 ) command = KeyboardTranslator::ScrollLineUpCommand; else if ( text.compare(QLatin1String("scrolllinedown"),Qt::CaseInsensitive) == 0 ) command = KeyboardTranslator::ScrollLineDownCommand; 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; return true; } bool KeyboardTranslatorReader::decodeSequence(const QString& text, int& keyCode, Qt::KeyboardModifiers& modifiers, Qt::KeyboardModifiers& modifierMask, KeyboardTranslator::States& flags, KeyboardTranslator::States& flagMask) { bool isWanted = true; //bool endOfItem = false; QString buffer; Qt::KeyboardModifiers tempModifiers = modifiers; Qt::KeyboardModifiers tempModifierMask = modifierMask; KeyboardTranslator::States tempFlags = flags; KeyboardTranslator::States tempFlagMask = flagMask; for ( int i = 0 ; i < text.count() ; i++ ) { const QChar& ch = text[i]; bool isFirstLetter = i == 0; bool isLastLetter = ( i == text.count()-1 ); bool endOfItem = true; if ( ch.isLetterOrNumber() ) { endOfItem = false; buffer.append(ch); } else if ( isFirstLetter ) { buffer.append(ch); } if ( (endOfItem || isLastLetter) && !buffer.isEmpty() ) { Qt::KeyboardModifier itemModifier = Qt::NoModifier; int itemKeyCode = 0; KeyboardTranslator::State itemFlag = KeyboardTranslator::NoState; if ( parseAsModifier(buffer,itemModifier) ) { tempModifierMask |= itemModifier; if ( isWanted ) tempModifiers |= itemModifier; } else if ( parseAsStateFlag(buffer,itemFlag) ) { tempFlagMask |= itemFlag; if ( isWanted ) tempFlags |= itemFlag; } else if ( parseAsKeyCode(buffer,itemKeyCode) ) keyCode = itemKeyCode; else qDebug() << "Unable to parse key binding item:" << buffer; buffer.clear(); } // check if this is a wanted / not-wanted flag and update the // state ready for the next item if ( ch == QLatin1Char('+') ) isWanted = true; else if ( ch == QLatin1Char('-') ) isWanted = false; } modifiers = tempModifiers; modifierMask = tempModifierMask; flags = tempFlags; flagMask = tempFlagMask; return true; } bool KeyboardTranslatorReader::parseAsModifier(const QString& item , Qt::KeyboardModifier& modifier) { if ( item == QLatin1String("shift") ) modifier = Qt::ShiftModifier; else if ( item == QLatin1String("ctrl") || item == QLatin1String("control") ) modifier = Qt::ControlModifier; else if ( item == QLatin1String("alt") ) modifier = Qt::AltModifier; else if ( item == QLatin1String("meta") ) modifier = Qt::MetaModifier; else if ( item == QLatin1String("keypad") ) modifier = Qt::KeypadModifier; else return false; return true; } bool KeyboardTranslatorReader::parseAsStateFlag(const QString& item , KeyboardTranslator::State& flag) { if ( item == QLatin1String("appcukeys") || item == QLatin1String("appcursorkeys") ) flag = KeyboardTranslator::CursorKeysState; else if ( item == QLatin1String("ansi") ) flag = KeyboardTranslator::AnsiState; else if ( item == QLatin1String("newline") ) flag = KeyboardTranslator::NewLineState; else if ( item == QLatin1String("appscreen") ) flag = KeyboardTranslator::AlternateScreenState; else if ( item == QLatin1String("anymod") || item == QLatin1String("anymodifier") ) flag = KeyboardTranslator::AnyModifierState; else if ( item == QLatin1String("appkeypad") ) flag = KeyboardTranslator::ApplicationKeypadState; else return false; return true; } bool KeyboardTranslatorReader::parseAsKeyCode(const QString& item , int& keyCode) { QKeySequence sequence = QKeySequence::fromString(item); if ( !sequence.isEmpty() ) { keyCode = sequence[0]; if ( sequence.count() > 1 ) { qDebug() << "Unhandled key codes in sequence: " << item; } } // additional cases implemented for backwards compatibility with KDE 3 else if ( item == QLatin1String("prior") ) keyCode = Qt::Key_PageUp; else if ( item == QLatin1String("next") ) keyCode = Qt::Key_PageDown; else return false; return true; } QString KeyboardTranslatorReader::description() const { return _description; } bool KeyboardTranslatorReader::hasNextEntry() { return _hasNext; } KeyboardTranslator::Entry KeyboardTranslatorReader::createEntry( const QString& condition , const QString& result ) { QString entryString = QString::fromLatin1("keyboard \"temporary\"\nkey "); entryString.append(condition); 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 // specified by 'condition' is pressed KeyboardTranslator::Command command; if (parseAsCommand(result,command)) entryString.append(result); else entryString.append(QLatin1Char('\"') + result + QLatin1Char('\"')); QByteArray array = entryString.toUtf8(); QBuffer buffer(&array); buffer.open(QIODevice::ReadOnly); KeyboardTranslatorReader reader(&buffer); KeyboardTranslator::Entry entry; if ( reader.hasNextEntry() ) entry = reader.nextEntry(); return entry; } KeyboardTranslator::Entry KeyboardTranslatorReader::nextEntry() { Q_ASSERT( _hasNext ); KeyboardTranslator::Entry entry = _nextEntry; readNext(); return entry; } bool KeyboardTranslatorReader::parseError() { return false; } QList KeyboardTranslatorReader::tokenize(const QString& line) { QString text = line; // remove comments bool inQuotes = false; int commentPos = -1; for (int i=text.length()-1;i>=0;i--) { QChar ch = text[i]; if (ch == QLatin1Char('\"')) inQuotes = !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(QLatin1String("keyboard\\s+\"(.*)\"")); // key line: key KeySequence : "output" // key line: key KeySequence : command static QRegExp key(QLatin1String("key\\s+([\\w\\+\\s\\-\\*\\.]+)\\s*:\\s*(\"(.*)\"|\\w+)")); QList list; if ( text.isEmpty() ) { return list; } if ( title.exactMatch(text) ) { Token titleToken = { Token::TitleKeyword , QString() }; 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().value(1).remove(QLatin1Char(' ')) }; list << keyToken << sequenceToken; if ( key.capturedTexts().at(3).isEmpty() ) { // capturedTexts()[2] is a command Token commandToken = { Token::Command , key.capturedTexts().at(2) }; list << commandToken; } else { // capturedTexts()[3] is the output string Token outputToken = { Token::OutputText , key.capturedTexts().at(3) }; list << outputToken; } } else { qDebug() << "Line in keyboard translator file could not be understood:" << text; } return list; } QList KeyboardTranslatorManager::allTranslators() { if ( !_haveLoadedAll ) { findTranslators(); } return _translators.keys(); } KeyboardTranslator *KeyboardTranslatorManager::getTranslator(const QString &name) { if ( name.isEmpty() ) { // Try to find the default.keytab file if it exists, otherwise // fall back to the hard-coded one KeyboardTranslator *translator = loadTranslator(QLatin1String("default")); if (!translator) { QBuffer textBuffer; textBuffer.setData(defaultTranslatorText); textBuffer.open(QIODevice::ReadOnly); translator = loadTranslator(&textBuffer, QLatin1String("fallback")); } return translator; } if ( _translators.contains(name) && _translators[name] != 0 ) return _translators[name]; KeyboardTranslator *translator = loadTranslator(name); if ( translator != 0 ) _translators[name] = translator; else if ( !name.isEmpty() ) qDebug() << "Unable to load translator" << name; return translator; } KeyboardTranslator::Entry::Entry() : _keyCode(0) , _modifiers(Qt::NoModifier) , _modifierMask(Qt::NoModifier) , _state(NoState) , _stateMask(NoState) , _command(NoCommand) { } bool KeyboardTranslator::Entry::operator==(const Entry& rhs) const { return _keyCode == rhs._keyCode && _modifiers == rhs._modifiers && _modifierMask == rhs._modifierMask && _state == rhs._state && _stateMask == rhs._stateMask && _command == rhs._command && _text == rhs._text; } bool KeyboardTranslator::Entry::matches(int keyCode , Qt::KeyboardModifiers modifiers, States testState) const { #ifdef Q_OS_MAC // On Mac, arrow keys are considered part of keypad. Ignore that. modifiers &= ~Qt::KeypadModifier; #endif if ( _keyCode != keyCode ) return false; if ( (modifiers & _modifierMask) != (_modifiers & _modifierMask) ) return false; // if modifiers is non-zero, the 'any modifier' state is implicit if ( (modifiers & ~Qt::KeypadModifier) != 0 ) testState |= AnyModifierState; if ( (testState & _stateMask) != (_state & _stateMask) ) return false; // 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; if ( _stateMask & KeyboardTranslator::AnyModifierState ) { if ( wantAnyModifier != anyModifiersSet ) return false; } return true; } QByteArray KeyboardTranslator::Entry::escapedText(bool expandWildCards,Qt::KeyboardModifiers modifiers) const { QByteArray result(text(expandWildCards,modifiers)); for ( int i = 0 ; i < result.count() ; i++ ) { char ch = result[i]; char replacement = 0; switch ( ch ) { case 27 : replacement = 'E'; break; case 8 : replacement = 'b'; break; case 12 : replacement = 'f'; break; case 9 : replacement = 't'; break; case 13 : replacement = 'r'; break; case 10 : replacement = 'n'; break; default: // any character which is not printable is replaced by an equivalent // \xhh escape sequence (where 'hh' are the corresponding hex digits) if ( !QChar(QLatin1Char(ch)).isPrint() ) replacement = 'x'; } if ( replacement == 'x' ) { result.replace(i,1,"\\x"+QByteArray(1,ch).toHex()); } else if ( replacement != 0 ) { result.remove(i,1); result.insert(i,'\\'); result.insert(i+1,replacement); } } return result; } QByteArray KeyboardTranslator::Entry::unescape(const QByteArray& input) const { QByteArray result(input); for ( int i = 0 ; i < result.count()-1 ; i++ ) { QByteRef ch = result[i]; if ( ch == '\\' ) { char replacement[2] = {0,0}; int charsToRemove = 2; bool escapedChar = true; switch ( result[i+1] ) { case 'E' : replacement[0] = 27; break; case 'b' : replacement[0] = 8 ; break; case 'f' : replacement[0] = 12; break; case 't' : replacement[0] = 9 ; break; case 'r' : replacement[0] = 13; break; case 'n' : replacement[0] = 10; break; case 'x' : { // format is \xh or \xhh where 'h' is a hexadecimal // digit from 0-9 or A-F which should be replaced // with the corresponding character value char hexDigits[3] = {0}; if ( (i < result.count()-2) && isxdigit(result[i+2]) ) hexDigits[0] = result[i+2]; if ( (i < result.count()-3) && isxdigit(result[i+3]) ) hexDigits[1] = result[i+3]; unsigned charValue = 0; sscanf(hexDigits,"%x",&charValue); replacement[0] = (char)charValue; charsToRemove = 2 + strlen(hexDigits); } break; default: escapedChar = false; } if ( escapedChar ) result.replace(i,charsToRemove,replacement); } } return result; } void KeyboardTranslator::Entry::insertModifier( QString& item , int modifier ) const { if ( !(modifier & _modifierMask) ) return; if ( modifier & _modifiers ) item += QLatin1Char('+'); else item += QLatin1Char('-'); if ( modifier == Qt::ShiftModifier ) item += QLatin1String("Shift"); else if ( modifier == Qt::ControlModifier ) item += QLatin1String("Ctrl"); else if ( modifier == Qt::AltModifier ) item += QLatin1String("Alt"); else if ( modifier == Qt::MetaModifier ) item += QLatin1String("Meta"); else if ( modifier == Qt::KeypadModifier ) item += QLatin1String("KeyPad"); } void KeyboardTranslator::Entry::insertState( QString& item , int state ) const { if ( !(state & _stateMask) ) return; if ( state & _state ) item += QLatin1Char('+') ; else item += QLatin1Char('-') ; if ( state == KeyboardTranslator::AlternateScreenState ) item += QLatin1String("AppScreen"); else if ( state == KeyboardTranslator::NewLineState ) item += QLatin1String("NewLine"); else if ( state == KeyboardTranslator::AnsiState ) item += QLatin1String("Ansi"); else if ( state == KeyboardTranslator::CursorKeysState ) item += QLatin1String("AppCursorKeys"); else if ( state == KeyboardTranslator::AnyModifierState ) item += QLatin1String("AnyModifier"); else if ( state == KeyboardTranslator::ApplicationKeypadState ) item += QLatin1String("AppKeypad"); } QString KeyboardTranslator::Entry::resultToString(bool expandWildCards,Qt::KeyboardModifiers modifiers) const { if ( !_text.isEmpty() ) return QString::fromLatin1(escapedText(expandWildCards,modifiers)); else if ( _command == EraseCommand ) return QLatin1String("Erase"); else if ( _command == ScrollPageUpCommand ) return QLatin1String("ScrollPageUp"); else if ( _command == ScrollPageDownCommand ) return QLatin1String("ScrollPageDown"); else if ( _command == ScrollLineUpCommand ) return QLatin1String("ScrollLineUp"); else if ( _command == ScrollLineDownCommand ) return QLatin1String("ScrollLineDown"); else if ( _command == ScrollLockCommand ) return QLatin1String("ScrollLock"); else if (_command == ScrollUpToTopCommand) return QLatin1String("ScrollUpToTop"); else if (_command == ScrollDownToBottomCommand) return QLatin1String("ScrollDownToBottom"); return QString(); } QString KeyboardTranslator::Entry::conditionToString() const { QString result = QKeySequence(_keyCode).toString(); insertModifier( result , Qt::ShiftModifier ); insertModifier( result , Qt::ControlModifier ); insertModifier( result , Qt::AltModifier ); insertModifier( result , Qt::MetaModifier ); insertModifier( result , Qt::KeypadModifier ); insertState( result , KeyboardTranslator::AlternateScreenState ); insertState( result , KeyboardTranslator::NewLineState ); insertState( result , KeyboardTranslator::AnsiState ); insertState( result , KeyboardTranslator::CursorKeysState ); insertState( result , KeyboardTranslator::AnyModifierState ); insertState( result , KeyboardTranslator::ApplicationKeypadState ); return result; } KeyboardTranslator::KeyboardTranslator(const QString& name) : _name(name) { } void KeyboardTranslator::setDescription(const QString& description) { _description = description; } QString KeyboardTranslator::description() const { return _description; } void KeyboardTranslator::setName(const QString& name) { _name = name; } QString KeyboardTranslator::name() const { return _name; } QList KeyboardTranslator::entries() const { return _entries.values(); } void KeyboardTranslator::addEntry(const Entry& entry) { const int keyCode = entry.keyCode(); _entries.insert(keyCode,entry); } void KeyboardTranslator::replaceEntry(const Entry& existing , const Entry& replacement) { if ( !existing.isNull() ) _entries.remove(existing.keyCode(),existing); _entries.insert(replacement.keyCode(),replacement); } void KeyboardTranslator::removeEntry(const Entry& entry) { _entries.remove(entry.keyCode(),entry); } KeyboardTranslator::Entry KeyboardTranslator::findEntry(int keyCode, Qt::KeyboardModifiers modifiers, States state) const { for (auto it = _entries.cbegin(), end = _entries.cend(); it != end; ++it) { if (it.key() == keyCode) if ( it.value().matches(keyCode,modifiers,state) ) return *it; } return Entry(); // entry not found } void KeyboardTranslatorManager::addTranslator(KeyboardTranslator* translator) { _translators.insert(translator->name(),translator); if ( !saveTranslator(translator) ) qDebug() << "Unable to save translator" << translator->name() << "to disk."; } bool KeyboardTranslatorManager::deleteTranslator(const QString& name) { Q_ASSERT( _translators.contains(name) ); // locate and delete QString path = findTranslatorPath(name); if ( QFile::remove(path) ) { _translators.remove(name); return true; } else { qDebug() << "Failed to remove translator - " << path; return false; } } Q_GLOBAL_STATIC( KeyboardTranslatorManager , theKeyboardTranslatorManager ) KeyboardTranslatorManager* KeyboardTranslatorManager::instance() { return theKeyboardTranslatorManager; } deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/KeyboardTranslator.h000066400000000000000000000475311475472654300271620ustar00rootroot00000000000000/* This source file is part of Konsole, a terminal emulator. Copyright 2007-2008 by Robert Knight 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. */ #ifndef KEYBOARDTRANSLATOR_H #define KEYBOARDTRANSLATOR_H // Qt #include #include #include #include #include // Konsole //#include "konsole_export.h" #define KONSOLEPRIVATE_EXPORT class QIODevice; 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. * * Konsole supports multiple keyboard translators, allowing the user to * specify the character sequences which are sent to the terminal * when particular key sequences are pressed. * * A key sequence is defined as a key code, associated keyboard modifiers * (Shift,Ctrl,Alt,Meta etc.) and state flags which indicate the state * which the terminal must be in for the key sequence to apply. */ 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. * * This enum describes the states which may be associated with with a particular * entry in the keyboard translation entry. */ enum State { /** Indicates that no special state is active */ NoState = 0, /** * TODO More documentation */ NewLineState = 1, /** * Indicates that the terminal is in 'Ansi' mode. * TODO: More documentation */ AnsiState = 2, /** * TODO More documentation */ CursorKeysState = 4, /** * Indicates that the alternate screen ( typically used by interactive programs * such as screen or vim ) is active */ AlternateScreenState = 8, /** Indicates that any of the modifier keys is active. */ AnyModifierState = 16, /** Indicates that the numpad is in application mode. */ ApplicationKeypadState = 32 }; Q_DECLARE_FLAGS(States,State) /** * This enum describes commands which are associated with particular key sequences. */ enum Command { /** Indicates that no command is associated with this command sequence */ NoCommand = 0, /** TODO Document me */ SendCommand = 1, /** Scroll the terminal display up one page */ ScrollPageUpCommand = 2, /** Scroll the terminal display down one page */ ScrollPageDownCommand = 4, /** Scroll the terminal display up one line */ ScrollLineUpCommand = 8, /** Scroll the terminal display down one line */ 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 = 256 }; Q_DECLARE_FLAGS(Commands,Command) /** * Represents an association between a key sequence pressed by the user * and the character sequence and commands associated with it for a particular * KeyboardTranslator. */ 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. */ bool isNull() const; /** Returns the commands associated with this entry */ Command command() const; /** Sets the command associated with this entry. */ void setCommand(Command command); /** * 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. * * @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. * * @param modifiers The keyboard modifiers being pressed. */ QByteArray text(bool expandWildCards = false, Qt::KeyboardModifiers modifiers = Qt::NoModifier) const; /** 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. * * eg. \\E for Escape, \\t for tab, \\n for new line. * * @param expandWildCards See text() * @param modifiers See text() */ QByteArray escapedText(bool expandWildCards = false, Qt::KeyboardModifiers modifiers = Qt::NoModifier) const; /** Returns the character code ( from the Qt::Key enum ) associated with this entry */ int keyCode() const; /** 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. * 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. */ Qt::KeyboardModifiers modifiers() const; /** Returns the keyboard modifiers which are valid in this entry. See modifiers() */ Qt::KeyboardModifiers modifierMask() const; /** See modifiers() */ void setModifiers( Qt::KeyboardModifiers modifiers ); /** 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 * 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. */ States state() const; /** Returns the state flags which are valid in this entry. See state() */ States stateMask() const; /** See state() */ void setState( States state ); /** See stateMask() */ void setStateMask( States mask ); /** * 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. */ QString conditionToString() const; /** * Returns this entry's result ( ie. its command or character sequence ) * as a string. * * @param expandWildCards See text() * @param modifiers See text() */ 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 , States flags ) const; bool operator==(const Entry& rhs) const; private: void insertModifier( QString& item , int modifier ) const; void insertState( QString& item , int state ) const; QByteArray unescape(const QByteArray& text) const; int _keyCode; Qt::KeyboardModifiers _modifiers; Qt::KeyboardModifiers _modifierMask; States _state; States _stateMask; Command _command; QByteArray _text; }; /** Constructs a new keyboard translator with the given @p name */ explicit KeyboardTranslator(const QString& name); //KeyboardTranslator(const KeyboardTranslator& other); /** Returns the name of this keyboard translator */ QString name() const; /** Sets the name of this keyboard translator */ void setName(const QString& name); /** Returns the descriptive name of this keyboard translator */ QString description() const; /** Sets the descriptive name of this keyboard translator */ void setDescription(const QString& description); /** * 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 ) * * @param keyCode A key code from the Qt::Key enum * @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 , 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() */ void addEntry(const Entry& entry); /** * Replaces an entry in the translator. If the @p existing entry is null, * then this is equivalent to calling addEntry(@p replacement) */ void replaceEntry(const Entry& existing , const Entry& replacement); /** * Removes an entry from the table. */ void removeEntry(const Entry& entry); /** Returns a list of all entries in the translator. */ QList entries() const; /** The modifier code for the actual Ctrl key on this OS. */ static const Qt::KeyboardModifier CTRL_MOD; private: QMultiHash _entries; // entries in this keyboard translation, // entries are indexed according to // their keycode QString _name; QString _description; }; Q_DECLARE_OPERATORS_FOR_FLAGS(KeyboardTranslator::States) Q_DECLARE_OPERATORS_FOR_FLAGS(KeyboardTranslator::Commands) /** * Parses the contents of a Keyboard Translator (.keytab) file and * returns the entries found in it. * * Usage example: * * @code * QFile source( "/path/to/keytab" ); * source.open( QIODevice::ReadOnly ); * * KeyboardTranslator* translator = new KeyboardTranslator( "name-of-translator" ); * * KeyboardTranslatorReader reader(source); * while ( reader.hasNextEntry() ) * translator->addEntry(reader.nextEntry()); * * source.close(); * * if ( !reader.parseError() ) * { * // parsing succeeded, do something with the translator * } * else * { * // parsing failed * } * @endcode */ class KeyboardTranslatorReader { public: /** Constructs a new reader which parses the given @p source */ KeyboardTranslatorReader( QIODevice* source ); /** * 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(); /** * Returns true if an error occurred whilst parsing the input or * false if no error occurred. */ bool parseError(); /** * 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 */ static KeyboardTranslator::Entry createEntry( const QString& condition , const QString& result ); private: struct Token { enum Type { TitleKeyword, TitleText, KeyKeyword, KeySequence, Command, OutputText }; Type type; QString text; }; QList tokenize(const QString&); void readNext(); bool decodeSequence(const QString& , int& keyCode, Qt::KeyboardModifiers& modifiers, Qt::KeyboardModifiers& modifierMask, KeyboardTranslator::States& state, KeyboardTranslator::States& stateFlags); static bool parseAsModifier(const QString& item , Qt::KeyboardModifier& modifier); static bool parseAsStateFlag(const QString& item , KeyboardTranslator::State& state); static bool parseAsKeyCode(const QString& item , int& keyCode); static bool parseAsCommand(const QString& text , KeyboardTranslator::Command& command); QIODevice* _source; QString _description; KeyboardTranslator::Entry _nextEntry; bool _hasNext; }; /** Writes a keyboard translation to disk. */ 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. */ explicit KeyboardTranslatorWriter(QIODevice* destination); ~KeyboardTranslatorWriter(); /** * 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 ); private: QIODevice* _destination; QTextStream* _writer; }; /** * Manages the keyboard translations available for use by terminal sessions, * see KeyboardTranslator. */ class KONSOLEPRIVATE_EXPORT KeyboardTranslatorManager { public: /** * Constructs a new KeyboardTranslatorManager and loads the list of * available keyboard translations. * * The keyboard translations themselves are not loaded until they are * first requested via a call to findTranslator() */ KeyboardTranslatorManager(); ~KeyboardTranslatorManager(); KeyboardTranslatorManager(const KeyboardTranslatorManager&) = delete; KeyboardTranslatorManager& operator=(const KeyboardTranslatorManager&) = delete; /** * Adds a new translator. If a translator with the same name * already exists, it will be replaced by the new translator. * * TODO: More documentation. */ void addTranslator(KeyboardTranslator* translator); /** * Deletes a translator. Returns true on successful deletion or false otherwise. * * TODO: More documentation */ bool deleteTranslator(const QString& name); /** 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. */ 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 * translators is started. */ QList allTranslators(); /******** Modify by ut000610 daizhengwen 2020-06-02: 用于修改数据****************/ KeyboardTranslator *getTranslator(const QString &name); /********************* Modify by ut000610 daizhengwen End ************************/ /** Returns the global KeyboardTranslatorManager instance. */ static KeyboardTranslatorManager* instance(); private: static const QByteArray defaultTranslatorText; void findTranslators(); // locate the available translators 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; }; 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 ) { _modifiers = modifier; } inline Qt::KeyboardModifiers KeyboardTranslator::Entry::modifiers() const { return _modifiers; } inline void KeyboardTranslator::Entry::setModifierMask( Qt::KeyboardModifiers mask ) { _modifierMask = mask; } inline Qt::KeyboardModifiers KeyboardTranslator::Entry::modifierMask() const { return _modifierMask; } inline bool KeyboardTranslator::Entry::isNull() const { return ( *this == Entry() ); } inline void KeyboardTranslator::Entry::setCommand( 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 { QByteArray expandedText = _text; if (expandWildCards) { int modifierValue = 1; modifierValue += oneOrZero(modifiers & Qt::ShiftModifier); modifierValue += oneOrZero(modifiers & Qt::AltModifier) << 1; modifierValue += oneOrZero(modifiers & KeyboardTranslator::CTRL_MOD) << 2; for (int i=0;i<_text.length();i++) { if (expandedText[i] == '*') expandedText[i] = '0' + modifierValue; } } return expandedText; } inline void KeyboardTranslator::Entry::setState( States state ) { _state = state; } inline KeyboardTranslator::States KeyboardTranslator::Entry::state() const { return _state; } inline void KeyboardTranslator::Entry::setStateMask( States stateMask ) { _stateMask = stateMask; } inline KeyboardTranslator::States KeyboardTranslator::Entry::stateMask() const { return _stateMask; } } Q_DECLARE_METATYPE(Konsole::KeyboardTranslator::Entry) Q_DECLARE_METATYPE(const Konsole::KeyboardTranslator*) #endif // KEYBOARDTRANSLATOR_H deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/LineFont.h000066400000000000000000000050651475472654300250620ustar00rootroot00000000000000/* 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 (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 Lesser 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. */ // WARNING: Autogenerated by "fontembedder ./linefont.src". // You probably do not want to hand-edit this! static const quint32 LineChars[] = { 0x00007c00, 0x000fffe0, 0x00421084, 0x00e739ce, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00427000, 0x004e7380, 0x00e77800, 0x00ef7bc0, 0x00421c00, 0x00439ce0, 0x00e73c00, 0x00e7bde0, 0x00007084, 0x000e7384, 0x000079ce, 0x000f7bce, 0x00001c84, 0x00039ce4, 0x00003dce, 0x0007bdee, 0x00427084, 0x004e7384, 0x004279ce, 0x00e77884, 0x00e779ce, 0x004f7bce, 0x00ef7bc4, 0x00ef7bce, 0x00421c84, 0x00439ce4, 0x00423dce, 0x00e73c84, 0x00e73dce, 0x0047bdee, 0x00e7bde4, 0x00e7bdee, 0x00427c00, 0x0043fce0, 0x004e7f80, 0x004fffe0, 0x004fffe0, 0x00e7fde0, 0x006f7fc0, 0x00efffe0, 0x00007c84, 0x0003fce4, 0x000e7f84, 0x000fffe4, 0x00007dce, 0x0007fdee, 0x000f7fce, 0x000fffee, 0x00427c84, 0x0043fce4, 0x004e7f84, 0x004fffe4, 0x00427dce, 0x00e77c84, 0x00e77dce, 0x0047fdee, 0x004e7fce, 0x00e7fde4, 0x00ef7f84, 0x004fffee, 0x00efffe4, 0x00e7fdee, 0x00ef7fce, 0x00efffee, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x000f83e0, 0x00a5294a, 0x004e1380, 0x00a57800, 0x00ad0bc0, 0x004390e0, 0x00a53c00, 0x00a5a1e0, 0x000e1384, 0x0000794a, 0x000f0b4a, 0x000390e4, 0x00003d4a, 0x0007a16a, 0x004e1384, 0x00a5694a, 0x00ad2b4a, 0x004390e4, 0x00a52d4a, 0x00a5a16a, 0x004f83e0, 0x00a57c00, 0x00ad83e0, 0x000f83e4, 0x00007d4a, 0x000f836a, 0x004f93e4, 0x00a57d4a, 0x00ad836a, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00001c00, 0x00001084, 0x00007000, 0x00421000, 0x00039ce0, 0x000039ce, 0x000e7380, 0x00e73800, 0x000e7f80, 0x00e73884, 0x0003fce0, 0x004239ce }; deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/LineFont.src000066400000000000000000000106211475472654300254140ustar00rootroot00000000000000#2500: single horizontal line 2500 ----- #2501: triple horizontal line 2501 ----- ----- ----- #2502: single vertical line 2502 | | | | | #2503: triple vertical line 2503 ||| ||| ||| ||| ||| #2504-250B are dashed - not handled #250C: top-left corner (lines on bottom + right) 250C .-- | | #250D: as above, but top line triple-width 250D .-- .-- |-- | #250E: now the vert line triple-width 250E ..-- ||| ||| #250F: and now both lines triple-width 250F .___ |.-- ||._ ||| #2510: top-right corner 2510 --. | | 2511 ==. ==. ==| | 2512 ==.. ||| ||| 2513 ===. ==.| =.|| ||| #2514: bottom-left corner 2514 | | .== 2515 | |== |== === 2516 ||| ||| |.== 2517 ||| ||.= |.== .=== #2518: bottm-right corner 2518 | | ==. 2519 | ==| ==| === 251A ||| ||| ==== 251B ||| =.|| ==.| ===. #251C: Join of vertical line and one from the right 251C | | |== | | 251D | |== |== |== | 251E ||| ||| ||== | | 251F | | ||== ||| ||| 2520 ||| ||| ||== ||| ||| 2521 ||| |||= ||== .|== | 2522 | .|== ||== |||= ||| 2523 ||| ||.= ||== ||.= ||| #2524: Join of vertical line and one from the left 2524 | | ==| | | 2525 | ==| ==| ==| | 2526 ||| ||| ==+| | | 2527 | | ==+| ||| ||| 2528 ||| ||| ==+| ||| ||| 2529 ||| =+|| ==+| ===+ | 252A | =+|| ==+| ===+ ||| 252B ||| =+|| ==+| =+|| ||| #252C: horizontal line joined to from below 252C ===== | | 252D === ==|== ==| | 252E === ==|== |== | 252F ==+== ==|== ==|== | 2530 ===== ===== ==|== | 2531 ===| ==||= =||| ||| 2532 |=== =||== ||== || 2533 ===== ==|== =+|+= ||| #2534: bottom line, connected to from top 2534 | | ===== 2535 | ==| ===== === 2536 | |== ===== === 2537 | ==|== ===== ===== 2538 ||| ||| ===== 2539 ||| ==|| ===== ===| 253A ||| ||== =|=== |=== 253B ||| ==|== ===== ===== #253C: vertical + horizontal lines intersecting 253C | | ===== | | 253D | ==| ===== ==| | 253E | |== ===== |== | 253F | ==|== ===== ==|== | 2540 ||| ||| ===== | | 2541 | | ===== ||| ||| 2542 ||| ||| ===== ||| ||| 2543 ||| =||| ===== ==|+ | 2544 ||| ||== ===== |== | 2545 | ==|+ ===== =||| ||| 2546 | |== ===== ||== ||| 2547 ||| =|||= ===== =|||= | 2548 | =|||= ===== =|||= ||| 2549 ||| =||| ===== =||| ||| 254A ||| |||= ===== |||= ||| 254B ||| =|||= ===== =|||= ||| #254C-254F are dashed 2550 _____ _____ 2551 | | | | | | | | | | 2552 |-- | |-- | 2553 ---- | | | | 2554 +--- | + +- | | 2555 --+ | --+ | 2556 -+-+ | | | | 2557 ---+ | -+ | | | 2558 | +-- | +-- 2559 | | | | +-+- 255A | | | +- | +--- 255B | --+ | --+ 255C | | | | -+-+ 255D | | -+ | | ---+ 255E | +-- | +-- | 255F | | | | | +- | | | | 2560 | | | +- | | | +- | | 2561 | --+ | --+ | 2562 | | | | -+ + | | | | 2563 | | -+ | | -+ | | | 2564 ----- --+-- | 2565 -+-+- | | | | 2566 ----- -+ +- | | 2567 | --+-- ----- 2568 | | | | -+-+- 2569 | | -+ +- ----- 256A | --+-- | --+-- | 256B | | | | -+-+- | | | | 256C | | -+ +- -+ +- | | #256F-2570 are curly, #2571-2573 are slashes and X 2574 ___ 2575 | | | 2576 ___ 2577 | | | 2578 ___ ___ ___ 2579 ||| ||| ||| 257A ___ ___ ___ 257B ||| ||| ||| 257C ___ _____ ___ 257D | | ||| ||| ||| 257E ___ _____ ___ 257F ||| ||| ||| | | deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/ProcessInfo.cpp000066400000000000000000000267011475472654300261310ustar00rootroot00000000000000/* Copyright 2007-2008 by Robert Knight 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. */ // Own #include "ProcessInfo.h" // Unix #include #include #include #include #include #include #include // Qt #include #include #include #include #include #include #include using namespace Konsole; ProcessInfo::ProcessInfo(int pid) : _fields(ARGUMENTS), // arguments // are currently always valid, // they just return an empty // vector / map respectively // if no arguments // have been explicitly set _pid(pid), _parentPid(0), _foregroundPid(0), _userId(0), _lastError(NoError), _name(QString()), _userName(QString()), _userHomeDir(QString()), _currentDir(QString()), _userNameRequired(true), _arguments(QVector()) { } ProcessInfo::~ProcessInfo() { } ProcessInfo::Error ProcessInfo::error() const { return _lastError; } void ProcessInfo::setError(Error error) { _lastError = error; } void ProcessInfo::update() { readCurrentDir(_pid); } QString ProcessInfo::validCurrentDir() const { bool ok = false; // read current dir, if an error occurs try the parent as the next // best option int currentPid = parentPid(&ok); QString dir = currentDir(&ok); while (!ok && currentPid != 0) { ProcessInfo *current = ProcessInfo::newInstance(currentPid, QString()); current->update(); currentPid = current->parentPid(&ok); dir = current->currentDir(&ok); delete current; } return dir; } QVector ProcessInfo::arguments(bool *ok) const { *ok = _fields.testFlag(ARGUMENTS); return _arguments; } bool ProcessInfo::isValid() const { return _fields.testFlag(PROCESS_ID); } int ProcessInfo::pid(bool *ok) const { *ok = _fields.testFlag(PROCESS_ID); return _pid; } int ProcessInfo::parentPid(bool *ok) const { *ok = _fields.testFlag(PARENT_PID); return _parentPid; } int ProcessInfo::foregroundPid(bool *ok) const { *ok = _fields.testFlag(FOREGROUND_PID); return _foregroundPid; } QString ProcessInfo::name(bool *ok) const { *ok = _fields.testFlag(NAME); return _name; } int ProcessInfo::userId(bool *ok) const { *ok = _fields.testFlag(UID); return _userId; } QString ProcessInfo::userName() const { return _userName; } QString ProcessInfo::userHomeDir() const { return _userHomeDir; } void ProcessInfo::setPid(int pid) { _pid = pid; _fields |= PROCESS_ID; } void ProcessInfo::setUserId(int uid) { _userId = uid; _fields |= UID; } void ProcessInfo::setUserName(const QString &name) { _userName = name; setUserHomeDir(); } void ProcessInfo::setUserHomeDir() { _userHomeDir = QDir::homePath(); } void ProcessInfo::setParentPid(int pid) { _parentPid = pid; _fields |= PARENT_PID; } void ProcessInfo::setForegroundPid(int pid) { _foregroundPid = pid; _fields |= FOREGROUND_PID; } void ProcessInfo::setUserNameRequired(bool need) { _userNameRequired = need; } bool ProcessInfo::userNameRequired() const { return _userNameRequired; } QString ProcessInfo::currentDir(bool *ok) const { if (ok != nullptr) { *ok = (_fields & CURRENT_DIR) != 0; } return _currentDir; } void ProcessInfo::setCurrentDir(const QString &dir) { _fields |= CURRENT_DIR; _currentDir = dir; } void ProcessInfo::setName(const QString &name) { _name = name; _fields |= NAME; } void ProcessInfo::addArgument(const QString &argument) { _arguments << argument; } void ProcessInfo::clearArguments() { _arguments.clear(); } void ProcessInfo::setFileError(QFile::FileError error) { switch (error) { case QFile::PermissionsError: setError(ProcessInfo::PermissionsError); break; case QFile::NoError: setError(ProcessInfo::NoError); break; default: setError(ProcessInfo::UnknownError); } } UnixProcessInfo::UnixProcessInfo(int pid, const QString &titleFormat) : ProcessInfo(pid) { // 目前的机制是需要用户名的,但是没有用到库里的titleFormat用的我们自己的机制 Q_UNUSED(titleFormat); // setUserNameRequired(titleFormat.contains(QLatin1String("%u"))); } void UnixProcessInfo::readProcessInfo(int pid) { // prevent _arguments from growing longer and longer each time this // method is called. clearArguments(); if (readProcInfo(pid)) { readArguments(pid); readCurrentDir(pid); } } void UnixProcessInfo::readUserName() { bool ok = false; const int uid = userId(&ok); if (!ok) { return; } struct passwd passwdStruct; struct passwd *getpwResult; char *getpwBuffer; long getpwBufferSize; int getpwStatus; getpwBufferSize = sysconf(_SC_GETPW_R_SIZE_MAX); if (getpwBufferSize == -1) { getpwBufferSize = 16384; } getpwBuffer = new char[static_cast(getpwBufferSize)]; if (getpwBuffer == nullptr) { return; } getpwStatus = getpwuid_r(static_cast<__uid_t>(uid), &passwdStruct, getpwBuffer, static_cast(getpwBufferSize), &getpwResult); if ((getpwStatus == 0) && (getpwResult != nullptr)) { setUserName(QLatin1String(passwdStruct.pw_name)); } else { setUserName(QString()); qWarning() << "getpwuid_r returned error : " << getpwStatus; } delete [] getpwBuffer; } LinuxProcessInfo::LinuxProcessInfo(int pid, const QString &titleFormat) : UnixProcessInfo(pid, titleFormat) { } bool LinuxProcessInfo::readCurrentDir(int pid) { char path_buffer[MAXPATHLEN + 1]; path_buffer[MAXPATHLEN] = 0; QByteArray procCwd = QFile::encodeName(QStringLiteral("/proc/%1/cwd").arg(pid)); const int length = static_cast(readlink(procCwd.constData(), path_buffer, MAXPATHLEN)); if (length == -1) { setError(UnknownError); return false; } path_buffer[length] = '\0'; QString path = QFile::decodeName(path_buffer); setCurrentDir(path); return true; } bool LinuxProcessInfo::readProcInfo(int pid) { // indicies of various fields within the process status file which // contain various information about the process const int PARENT_PID_FIELD = 3; const int PROCESS_NAME_FIELD = 1; const int GROUP_PROCESS_FIELD = 7; QString parentPidString; QString processNameString; QString foregroundPidString; QString uidLine; QString uidString; QStringList uidStrings; // For user id read process status file ( /proc//status ) // Can not use getuid() due to it does not work for 'su' QFile statusInfo(QStringLiteral("/proc/%1/status").arg(pid)); if (statusInfo.open(QIODevice::ReadOnly)) { QTextStream stream(&statusInfo); QString statusLine; do { statusLine = stream.readLine(); if (statusLine.startsWith(QLatin1String("Uid:"))) { uidLine = statusLine; } } while (!statusLine.isNull() && uidLine.isNull()); uidStrings << uidLine.split(QLatin1Char('\t'), QString::SkipEmptyParts); // Must be 5 entries: 'Uid: %d %d %d %d' and // uid string must be less than 5 chars (uint) if (uidStrings.size() == 5) { uidString = uidStrings[1]; } if (uidString.size() > 5) { uidString.clear(); } bool ok = false; const int uid = uidString.toInt(&ok); if (ok) { setUserId(uid); } // This will cause constant opening of /etc/passwd if (userNameRequired()) { readUserName(); } } else { setFileError(statusInfo.error()); return false; } // read process status file ( /proc//cmdline // the expected format is a list of strings delimited by null characters, // and ending in a double null character pair. QFile argumentsFile(QStringLiteral("/proc/%1/cmdline").arg(pid)); if (argumentsFile.open(QIODevice::ReadOnly)) { QTextStream stream(&argumentsFile); const QString &data = stream.readAll(); const QStringList &argList = data.split(QLatin1Char('\0')); for (int i = 0; i < argList.size(); i++) { const QString &entry = argList.at(i); if (!entry.isEmpty()) { addArgument(entry); } } } else { setFileError(argumentsFile.error()); } return true; } // // ProcessInfo::newInstance() is way at the bottom so it can see all of the // implementations of the UnixProcessInfo abstract class. // ProcessInfo *ProcessInfo::newInstance(int pid, const QString &titleFormat) { ProcessInfo *info; info = new LinuxProcessInfo(pid, titleFormat); info->readProcessInfo(pid); return info; } deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/ProcessInfo.h000066400000000000000000000243121475472654300255720ustar00rootroot00000000000000/* Copyright 2007-2008 by Robert Knight 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. */ #ifndef PROCESSINFO_H #define PROCESSINFO_H // Qt #include #include #include #include namespace Konsole { /** * Takes a snapshot of the state of a process and provides access to * information such as the process name, parent process, * the foreground process in the controlling terminal, * the arguments with which the process was started. * * To create a new snapshot, construct a new ProcessInfo instance, * using ProcessInfo::newInstance(), * passing the process identifier of the process you are interested in. * * After creating a new instance, call the update() method to take a * snapshot of the current state of the process. * * Before calling any additional methods, check that the process state * was read successfully using the isValid() method. * * Each accessor method which provides information about the process state ( such as pid(), * currentDir(), name() ) takes a pointer to a boolean as an argument. If the information * requested was read successfully then the boolean is set to true, otherwise it is set * to false, in which case the return value from the function should be ignored. * If this boolean is set to false, it may indicate an error reading the process information, * or it may indicate that the information is not available on the current platform. * * eg. * * @code * ProcessInfo* info = ProcessInfo::newInstance(pid); * info->update(); * * if ( info->isValid() ) * { * bool ok; * * QString name = info->name(&ok); * if ( ok ) qDebug() << "process name - " << name; * int parentPid = info->parentPid(&ok); * if ( ok ) qDebug() << "parent process - " << parentPid; * int foregroundPid = info->foregroundPid(&ok); * if ( ok ) qDebug() << "foreground process - " << foregroundPid; * } * @endcode */ class ProcessInfo : QObject { Q_OBJECT public: /** * Constructs a new instance of a suitable ProcessInfo sub-class for * the current platform which provides information about a given process. * * @param pid The pid of the process to examine * @param titleFormat The local title format - used to determine if it * contains %u which requires expensive prodecures to be used. */ static ProcessInfo *newInstance(int pid, const QString &titleFormat); virtual ~ProcessInfo(); /** * Updates the information about the process. This must * be called before attempting to use any of the accessor methods. */ void update(); /** Returns true if the process state was read successfully. */ bool isValid() const; /** * Returns the process id. * * @param ok Set to true if the process id was read successfully or false otherwise */ int pid(bool *ok) const; /** * Returns the id of the parent process id was read successfully or false otherwise * * @param ok Set to true if the parent process id */ int parentPid(bool *ok) const; /** * Returns the id of the current foreground process * * NOTE: Using the foregroundProcessGroup() method of the Pty * instance associated with the terminal of interest is preferred * over using this method. * * @param ok Set to true if the foreground process id was read successfully or false otherwise */ int foregroundPid(bool *ok) const; /* Returns the user id of the process */ int userId(bool *ok) const; /** Returns the user's name of the process */ QString userName() const; /** Returns the user's home directory of the process */ QString userHomeDir() const; /** Returns the name of the current process */ QString name(bool *ok) const; /** * Returns the command-line arguments which the process * was started with. * * The first argument is the name used to launch the process. * * @param ok Set to true if the arguments were read successfully or false otherwise. */ QVector arguments(bool *ok) const; /** * Returns the current working directory of the process * * @param ok Set to true if the current working directory was read successfully or false otherwise */ QString currentDir(bool *ok) const; /** * Returns the current working directory of the process (or its parent) */ QString validCurrentDir() const; /** Forces the user home directory to be calculated */ void setUserHomeDir(); /** * This enum describes the errors which can occur when trying to read * a process's information. */ enum Error { /** No error occurred. */ NoError, /** The nature of the error is unknown. */ UnknownError, /** Konsole does not have permission to obtain the process information. */ PermissionsError }; /** * Returns the last error which occurred. */ Error error() const; enum Field { PROCESS_ID = 1, PARENT_PID = 2, FOREGROUND_PID = 4, ARGUMENTS = 8, NAME = 16, CURRENT_DIR = 32, UID = 64 }; typedef QFlags Fields; // takes a full directory path and returns a // shortened version suitable for display in // space-constrained UI elements (eg. tabs) QString formatShortDir(const QString &dirPath) const; void setUserNameRequired(bool need); protected: /** * Constructs a new process instance. You should not call the constructor * of ProcessInfo or its subclasses directly. Instead use the * static ProcessInfo::newInstance() method which will return * a suitable ProcessInfo instance for the current platform. */ explicit ProcessInfo(int pid); /** * This is called on construction to read the process state * Subclasses should reimplement this function to provide * platform-specific process state reading functionality. * * When called, readProcessInfo() should attempt to read all * of the necessary state information. If the attempt is successful, * it should set the process id using setPid(), and update * the other relevant information using setParentPid(), setName(), * setArguments() etc. * * Calls to isValid() will return true only if the process id * has been set using setPid() * * @param pid The process id of the process to read */ virtual void readProcessInfo(int pid) = 0; /** * Determine the current directory of the process. * @param pid process ID to use * @return true on success */ virtual bool readCurrentDir(int pid) = 0; /* Read the user name */ virtual void readUserName(void) = 0; /** Sets the process id associated with this ProcessInfo instance */ void setPid(int pid); /** Sets the parent process id as returned by parentPid() */ void setParentPid(int pid); /** Sets the foreground process id as returned by foregroundPid() */ void setForegroundPid(int pid); /** Sets the user id associated with this ProcessInfo instance */ void setUserId(int uid); /** Sets the user name of the process as set by readUserName() */ void setUserName(const QString &name); /** Sets the name of the process as returned by name() */ void setName(const QString &name); /** Sets the current working directory for the process */ void setCurrentDir(const QString &dir); /** Sets the error */ void setError(Error error); /** Convenience method. Sets the error based on a QFile error code. */ void setFileError(QFile::FileError error); /** * Adds a commandline argument for the process, as returned * by arguments() */ void addArgument(const QString &argument); /** * clear the commandline arguments for the process, as returned * by arguments() */ void clearArguments(); bool userNameRequired() const; private: Fields _fields; int _pid; int _parentPid; int _foregroundPid; int _userId; Error _lastError; QString _name; QString _userName; QString _userHomeDir; QString _currentDir; bool _userNameRequired; QVector _arguments; }; Q_DECLARE_OPERATORS_FOR_FLAGS(ProcessInfo::Fields) /** * Implementation of ProcessInfo for Unix platforms which uses * the /proc filesystem */ class UnixProcessInfo : public ProcessInfo { public: /** * Constructs a new instance of UnixProcessInfo. * See ProcessInfo::newInstance() */ explicit UnixProcessInfo(int pid, const QString &titleFormat); protected: /** * Implementation of ProcessInfo::readProcessInfo(); calls the * four private methods below in turn. */ void readProcessInfo(int pid) Q_DECL_OVERRIDE; void readUserName(void) Q_DECL_OVERRIDE; private: /** * Read the standard process information -- PID, parent PID, foreground PID. * @param pid process ID to use * @return true on success */ virtual bool readProcInfo(int pid) = 0; /** * Determine what arguments were passed to the process. Sets _arguments. * @param pid process ID to use * @return true on success */ virtual bool readArguments(int pid) = 0; }; class LinuxProcessInfo : public UnixProcessInfo { public: LinuxProcessInfo(int pid, const QString &titleFormat); protected: bool readCurrentDir(int pid) Q_DECL_OVERRIDE; private: bool readProcInfo(int pid) Q_DECL_OVERRIDE; bool readArguments(int pid) Q_DECL_OVERRIDE; }; } #endif //PROCESSINFO_H deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/Pty.cpp000066400000000000000000000542551475472654300244600ustar00rootroot00000000000000/* * This file is a part of QTerminal - http://gitorious.org/qterminal * * This file was un-linked from KDE and modified * by Maxim Bourmistrov * */ /* This file is part of Konsole, an X terminal. 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 (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. */ // Own #include "Pty.h" #include "SessionManager.h" // System #include #include #include #include #include #include // Qt #include #include #include #include #include #include #include #include "kpty.h" #include "kptydevice.h" #include "encodes/detectcode.h" using namespace Konsole; void Pty::setWindowSize(int lines, int cols) { _windowColumns = cols; _windowLines = lines; if (pty()->masterFd() >= 0) pty()->setWinSize(lines, cols); } QSize Pty::windowSize() const { return {_windowColumns, _windowLines}; } void Pty::setFlowControlEnabled(bool enable) { _xonXoff = enable; if (pty()->masterFd() >= 0) { struct ::termios ttmode; pty()->tcGetAttr(&ttmode); if (!enable) ttmode.c_iflag &= ~(IXOFF | IXON); else ttmode.c_iflag |= (IXOFF | IXON); if (!pty()->tcSetAttr(&ttmode)) qWarning() << "Unable to set terminal attributes."; } } bool Pty::flowControlEnabled() const { if (pty()->masterFd() >= 0) { struct ::termios ttmode; pty()->tcGetAttr(&ttmode); return ttmode.c_iflag & IXOFF && ttmode.c_iflag & IXON; } qWarning() << "Unable to get flow control status, terminal not connected."; return false; } void Pty::setUtf8Mode(bool enable) { #ifdef IUTF8 // XXX not a reasonable place to check it. _utf8 = enable; if (pty()->masterFd() >= 0) { struct ::termios ttmode; pty()->tcGetAttr(&ttmode); if (!enable) ttmode.c_iflag &= ~IUTF8; else ttmode.c_iflag |= IUTF8; if (!pty()->tcSetAttr(&ttmode)) qWarning() << "Unable to set terminal attributes."; } #endif } void Pty::setErase(char erase) { _eraseChar = erase; if (pty()->masterFd() >= 0) { struct ::termios ttmode; pty()->tcGetAttr(&ttmode); ttmode.c_cc[VERASE] = erase; if (!pty()->tcSetAttr(&ttmode)) qWarning() << "Unable to set terminal attributes."; } } char Pty::erase() const { if (pty()->masterFd() >= 0) { struct ::termios ttyAttributes; pty()->tcGetAttr(&ttyAttributes); return ttyAttributes.c_cc[VERASE]; } return _eraseChar; } void Pty::addEnvironmentVariables(const QStringList &environment) { QListIterator iter(environment); while (iter.hasNext()) { QString pair = iter.next(); // split on the first '=' character int pos = pair.indexOf(QLatin1Char('=')); if (pos >= 0) { QString variable = pair.left(pos); QString value = pair.mid(pos + 1); setEnv(variable, value); } } } int Pty::start(const QString &program, const QStringList &programArguments, const QStringList &environment, ulong winid, bool addToUtmp //const QString& dbusService, //const QString& dbusSession ) { clearProgram(); // 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, programArguments.mid(1)); _program = program; addEnvironmentVariables(environment); setEnv(QLatin1String("WINDOWID"), QString::number(winid)); setEnv(QLatin1String("COLORTERM"), QLatin1String("truecolor")); // unless the LANGUAGE environment variable has been set explicitly // set it to a null string // this fixes the problem where KCatalog sets the LANGUAGE environment // variable during the application's startup to something which // differs from LANG,LC_* etc. and causes programs run from // the terminal to display messages in the wrong language // // this can happen if LANG contains a language which KDE // does not have a translation for // // BR:149300 setEnv(QLatin1String("LANGUAGE"), QString(), false /* do not overwrite existing value if any */); setUseUtmp(addToUtmp); 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."; pty()->setWinSize(_windowLines, _windowColumns); KProcess::start(); if (!waitForStarted()) return -1; 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; stat(pty()->ttyName(), &sbuf); if (writeable) chmod(pty()->ttyName(), sbuf.st_mode | S_IWGRP); else chmod(pty()->ttyName(), sbuf.st_mode & ~(S_IWGRP | S_IWOTH)); } Pty::Pty(int masterFd, QObject *parent) : KPtyProcess(masterFd, parent) { init(); } Pty::Pty(QObject *parent) : KPtyProcess(parent) { init(); } void Pty::init() { _windowColumns = 0; _windowLines = 0; _eraseChar = 0; _xonXoff = true; _utf8 = true; _bUninstall = false; connect(pty(), SIGNAL(readyRead()), this, SLOT(dataReceived())); setPtyChannels(KPtyProcess::AllChannels); } Pty::~Pty() { } bool Pty::isTerminalRemoved() { QFile terminalExecFile("/usr/bin/deepin-terminal"); if (terminalExecFile.exists()) { return false; } return true; } bool isPatternAcceptable(QString strCommand, QString strPattern) { QString strTrimmedCmd = strCommand.trimmed(); QRegExp cmdRegExp; cmdRegExp.setPattern(strPattern); QRegExpValidator cmdREValidator(cmdRegExp, nullptr); int pos = 0; QValidator::State validateState = cmdREValidator.validate(strTrimmedCmd, pos); return (validateState == QValidator::Acceptable); } //判断当前命令是否是要删除终端 bool Pty::bWillRemoveTerminal(QString strCommand) { QString packageName = "deepin-terminal"; QStringList strCommandList; strCommandList.append(strCommand); if (strCommand.contains("&&")) { QStringList cmdList = strCommand.split("&&"); for (int i = 0; i < cmdList.size(); i++) { QString currCmd = cmdList.at(i).trimmed(); if (currCmd.length() > 0 && currCmd.contains(packageName)) { strCommandList.append(currCmd); } } } if (strCommand.contains(";")) { QStringList cmdList = strCommand.split(";"); for (int i = 0; i < cmdList.size(); i++) { QString currCmd = cmdList.at(i).trimmed(); if (currCmd.length() > 0 && currCmd.contains(packageName)) { strCommandList.append(currCmd); } } } QList acceptableList; QStringList packageNameList; packageNameList << packageName; for (int i = 0; i < strCommandList.size(); i++) { QString strCurrCommand = strCommandList.at(i); for (int j = 0; j < packageNameList.size(); j++) { QString packageName = packageNameList.at(j); QString removePattern = QString("sudo\\s+apt-get\\s+remove\\s+%1").arg(packageName); acceptableList << isPatternAcceptable(strCurrCommand, removePattern); removePattern = QString("sudo\\s+apt\\s+remove\\s+%1").arg(packageName); acceptableList << isPatternAcceptable(strCurrCommand, removePattern); /******** Modify by nt001000 renfeixiang 2020-05-27:修改 放到bWillPurgeTerminal函数中 Begin***************/ // removePattern = QString("sudo\\s+dpkg\\s+-P\\s+%1").arg(packageName); // acceptableList << isPatternAcceptable(strCurrCommand, removePattern); /******** Modify by nt001000 renfeixiang 2020-05-27:修改 放到bWillPurgeTerminal函数中 End***************/ removePattern = QString("sudo\\s+dpkg\\s+-r\\s+%1").arg(packageName); acceptableList << isPatternAcceptable(strCurrCommand, removePattern); removePattern = QString("sudo\\s+rm\\s+.+\\s+/usr/bin/deepin-terminal"); acceptableList << isPatternAcceptable(strCurrCommand, removePattern); removePattern = QString("sudo\\s+rm\\s+/usr/bin/deepin-terminal"); acceptableList << isPatternAcceptable(strCurrCommand, removePattern); } } return acceptableList.contains(true); } /******** Add by nt001000 renfeixiang 2020-05-27:增加 Purge卸载命令的判断,显示不同的卸载提示框 Begin***************/ bool Pty::bWillPurgeTerminal(QString strCommand) { QString packageName = "deepin-terminal"; QStringList strCommandList; strCommandList.append(strCommand); if (strCommand.contains("&&")) { QStringList cmdList = strCommand.split("&&"); for (int i = 0; i < cmdList.size(); i++) { QString currCmd = cmdList.at(i).trimmed(); if (currCmd.length() > 0 && currCmd.contains(packageName)) { strCommandList.append(currCmd); } } } if (strCommand.contains(";")) { QStringList cmdList = strCommand.split(";"); for (int i = 0; i < cmdList.size(); i++) { QString currCmd = cmdList.at(i).trimmed(); if (currCmd.length() > 0 && currCmd.contains(packageName)) { strCommandList.append(currCmd); } } } QList acceptableList; QStringList packageNameList; packageNameList << packageName; for (int i = 0; i < strCommandList.size(); i++) { QString strCurrCommand = strCommandList.at(i); for (int j = 0; j < packageNameList.size(); j++) { QString packageName = packageNameList.at(j); QString removePattern = QString("sudo\\s+apt-get\\s+purge\\s+%1").arg(packageName); acceptableList << isPatternAcceptable(strCurrCommand, removePattern); removePattern = QString("sudo\\s+apt-get\\s+purge\\s+-y\\s+%1").arg(packageName); acceptableList << isPatternAcceptable(strCurrCommand, removePattern); removePattern = QString("sudo\\s+apt-get\\s+remove\\s+--purge\\s+%1").arg(packageName); acceptableList << isPatternAcceptable(strCurrCommand, removePattern); removePattern = QString("sudo\\s+apt-get\\s+--purge\\s+remove\\s+%1").arg(packageName); acceptableList << isPatternAcceptable(strCurrCommand, removePattern); removePattern = QString("sudo\\s+apt\\s+purge\\s+%1").arg(packageName); acceptableList << isPatternAcceptable(strCurrCommand, removePattern); removePattern = QString("sudo\\s+apt\\s+purge\\s+-y\\s+%1").arg(packageName); acceptableList << isPatternAcceptable(strCurrCommand, removePattern); removePattern = QString("sudo\\s+apt\\s+remove\\s+--purge\\s+%1").arg(packageName); acceptableList << isPatternAcceptable(strCurrCommand, removePattern); removePattern = QString("sudo\\s+apt\\s+--purge\\s+remove\\s+%1").arg(packageName); acceptableList << isPatternAcceptable(strCurrCommand, removePattern); removePattern = QString("sudo\\s+dpkg\\s+-P\\s+%1").arg(packageName); acceptableList << isPatternAcceptable(strCurrCommand, removePattern); } } return acceptableList.contains(true); } /******** Add by nt001000 renfeixiang 2020-05-27:增加 Purge卸载命令的判断,显示不同的卸载提示框 End***************/ void Pty::sendData(const char *data, int length, const QTextCodec *codec) { _textCodec = codec; if (!length) { return; } //判断是否是点了自定义命令面板列表项触发的命令 bool isCustomCommand = false; QString currCommand = QString::fromLatin1(data); if (currCommand.length() > 0 && currCommand.endsWith('\n')) { isCustomCommand = true; } _isCommandExec = false; _bNeedBlockCommand = false; //检测到按了回车键 if (((*data) == '\r' || isCustomCommand) && _bUninstall == false) { _isCommandExec = true; QString strCurrCommand = SessionManager::instance()->getCurrShellCommand(_sessionId); if (isCustomCommand) { strCurrCommand = currCommand; } //检测到当前命令是代码中通过sendText发给终端的(而不是用户手动输入的命令) bool isSendByRemoteManage = this->property("isSendByRemoteManage").toBool(); if (isSendByRemoteManage && strCurrCommand.startsWith("expect -f")) { _bNeedBlockCommand = true; //立即修改回false,防止误认其他命令 this->setProperty("isSendByRemoteManage", QVariant(false)); } /******** Modify by nt001000 renfeixiang 2020-05-27:修改 根据remove和purge卸载命令,发送信号不同参数值 Begin***************/ bool bPurgeTerminal = bWillPurgeTerminal(strCurrCommand); bool bRemoveTerminal = bWillRemoveTerminal(strCurrCommand); if (!isTerminalRemoved() && (bPurgeTerminal || bRemoveTerminal)) { QString strname = "remove"; if (bPurgeTerminal) { strname = "purge"; } QMetaObject::invokeMethod(this, "ptyUninstallTerminal", Qt::AutoConnection, Q_RETURN_ARG(bool, _bUninstall), Q_ARG(QString, strname)); /******** Modify by nt001000 renfeixiang 2020-05-27:修改 根据remove和purge卸载命令,发送信号不同参数值 End***************/ if (_bUninstall) { qDebug() << "确认卸载终端!" << _bUninstall << endl; connect(SessionManager::instance(), &SessionManager::sessionIdle, this, [ = ](bool isIdle) { //卸载完成,关闭所有终端窗口 if (isIdle) { if (isTerminalRemoved()) { pclose(popen("killall deepin-terminal", "r")); } } if (!isTerminalRemoved()) { _bUninstall = false; } }); } else { qDebug() << "不卸载终端!" << _bUninstall << endl; return; } } } //为GBK/GB2312/GB18030编码,且不是输入命令执行的情况(没有按回车) if (QString(codec->name()).toUpper().startsWith("GB") && !_isCommandExec) { QTextCodec *utf8Codec = QTextCodec::codecForName("UTF-8"); QString unicodeData = codec->toUnicode(data); QByteArray unicode = utf8Codec->fromUnicode(unicodeData); if (!pty()->write(unicode.constData(), unicode.length())) { qWarning() << "Pty::doSendJobs - Could not send input data to terminal process."; return; } } else { if (!pty()->write(data, length)) { qWarning() << "Pty::doSendJobs - Could not send input data to terminal process."; return; } } } void Pty::dataReceived() { QByteArray data = pty()->readAll(); QString recvData = QString(data); if (_bNeedBlockCommand) { QString judgeData = recvData; if (recvData.length() > 1) { judgeData = recvData.replace("\r", ""); judgeData = judgeData.replace("\n", ""); } //使用zsh的时候,发送过来的字符会残留一个字母"e",需要特殊处理下 if (_program.endsWith("/zsh") && 1 == judgeData.length() && judgeData.startsWith("e") && -1 == _receiveDataIndex) { _receiveDataIndex = 0; return; } //不显示远程登录时候的敏感信息(主要是expect -f命令跟随的明文密码) //同时考虑了zsh的情况 if (judgeData.startsWith("expect -f") || judgeData.startsWith("\bexpect") || judgeData.startsWith("\be") || judgeData.startsWith("e\bexpect") || judgeData.startsWith("e\be")) { _receiveDataIndex = 1; return; } if (_receiveDataIndex >= 1) { if (judgeData.contains("Press")) { //这里需要置回false,否则后面其他命令也会被拦截 _bNeedBlockCommand = false; _receiveDataIndex = -1; int pressStringIndex = recvData.indexOf("Press"); if (pressStringIndex > 0) { recvData = recvData.mid(pressStringIndex); } QString helpData = recvData.replace("\n", ""); recvData = "\r\n" + helpData + "\r\n"; data = recvData.toUtf8(); emit receivedData(data.constData(), data.count(), _textCodec); } else { ++_receiveDataIndex; } return; } } /******** Modify by m000714 daizhengwen 2020-04-30: 处理上传下载时乱码显示命令不执行****************/ // 乱码提示信息不显示 if (recvData.contains("bash: $'\\212") || recvData.contains("bash: **0800000000022d:") || recvData.contains("**^XB0800000000022d") || recvData.startsWith("**\u0018B0800000000022d\r\u008A")) { return; } // "\u008A"这个乱码不替换调会导致显示时有\b的效果导致命令错乱bug#23741 if (_utf8 && recvData.contains("\u008A")) { recvData.replace("\u008A", "\b \b #"); data = recvData.toUtf8(); } if (recvData == "rz waiting to receive.") { recvData += "\r\n"; data = recvData.toUtf8(); } // NOTE: 为处理编码截断的情况,需要缓存数据等待换行符 '\n' 或终端结束符 "\x1B[00m" // 此处理仅在非UTF8编码, 且命令输出时生效 if (!_utf8) { if (_isCommandExec) { // 命令输出数据 int index = data.lastIndexOf('\n'); if (-1 == index) { _waitLFBuffer.append(data); // 判断是否包含结束符 if (_waitLFBuffer.contains("\x1B[00m")) { emit receivedData(_waitLFBuffer.constData(), _waitLFBuffer.size(), true); _waitLFBuffer.clear(); } } else if (index != data.count() - 1) { int remainingCount = data.size() - index - 1; // 判断是否包含结束符 if (QByteArray::fromRawData(data.constData() + index + 1, remainingCount).contains("\x1B[00m")) { _waitLFBuffer.append(data); emit receivedData(_waitLFBuffer.constData(), _waitLFBuffer.count(), true); _waitLFBuffer.clear(); } else { data.prepend(_waitLFBuffer); emit receivedData(data.constData(), _waitLFBuffer.count() + index + 1, true); _waitLFBuffer = data.right(remainingCount); } } else { data.prepend(_waitLFBuffer); emit receivedData(data.constData(), data.count(), true); _waitLFBuffer.clear(); } // 缓存数据并跳出 return; } else { if (!_waitLFBuffer.isEmpty()) { emit receivedData(_waitLFBuffer.constData(), _waitLFBuffer.count(), _isCommandExec); _waitLFBuffer.clear(); } } } /********************* Modify by m000714 daizhengwen End ************************/ emit receivedData(data.constData(), data.count(), _isCommandExec); } void Pty::lockPty(bool lock) { Q_UNUSED(lock); // TODO: Support for locking the Pty //if (lock) //suspend(); //else //resume(); } int Pty::foregroundProcessGroup() const { int pid = tcgetpgrp(pty()->masterFd()); if (pid != -1) { return pid; } return 0; } void Pty::setSessionId(int sessionId) { _sessionId = sessionId; } void Pty::setupChildProcess() { KPtyProcess::setupChildProcess(); // reset all signal handlers // this ensures that terminal applications respond to // signals generated via key sequences such as Ctrl+C // (which sends SIGINT) struct sigaction action; sigset_t sigset; sigemptyset(&action.sa_mask); sigemptyset(&sigset); action.sa_handler = SIG_DFL; action.sa_flags = 0; for (int signal = 1; signal < NSIG; signal++) { sigaction(signal, &action, nullptr); sigaddset(&sigset, signal); } sigprocmask(SIG_UNBLOCK, &sigset, nullptr); } deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/Pty.h000066400000000000000000000165701475472654300241230ustar00rootroot00000000000000/* * This file is a part of QTerminal - http://gitorious.org/qterminal * * This file was un-linked from KDE and modified * by Maxim Bourmistrov * */ /* This file is part of Konsole, KDE's terminal emulator. Copyright 2007-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 (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. */ #ifndef PTY_H #define PTY_H // Qt #include #include #include #include // KDE #include "kptyprocess.h" namespace Konsole { /** * 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. * * To use this class, construct an instance and connect * to the sendData slot and receivedData signal to * 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. */ 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 * name of the program to start and appropriate arguments. */ explicit Pty(QObject* parent = nullptr); /** * Construct a process using an open pty master. * See KPtyProcess::KPtyProcess() */ explicit Pty(int ptyMasterFd, QObject* parent = nullptr); ~Pty() override; /** * Starts the terminal process. * * Returns 0 if the process was started successfully or non-zero * otherwise. * * @param program Path to the program to start * @param arguments Arguments to pass to the program being started * @param environment A list of key=value pairs which will be added * to the environment for the new process. At the very least this * should include an assignment for the TERM environment variable. * @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 * environment variable in the process's environment. * @param dbusSession Specifies the value of the KONSOLE_DBUS_SESSION * environment variable in the process's environment. */ 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() */ void setFlowControlEnabled(bool on); /** 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) * 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; /** TODO Document me */ void setErase(char erase); /** */ char erase() const; /** * Returns the process id of the teletype's current foreground * process. This is the process which is currently reading * input sent to the terminal via. sendData() * * If there is a problem reading the foreground process group, * 0 will be returned. */ int foregroundProcessGroup() const; void setSessionId(int sessionId); public slots: /** * Put the pty into UTF-8 mode on systems which support it. */ void setUtf8Mode(bool on); /** * Suspend or resume processing of data from the standard * output of the terminal process. * * See K3Process::suspend() and K3Process::resume() * * @param lock If true, processing of output is suspended, * otherwise processing is resumed. */ void lockPty(bool lock); /** * Sends data to the process currently controlling the * teletype ( whose id is returned by foregroundProcessGroup() ) * * @param buffer Pointer to the data to send. * @param length Length of @p buffer. */ void sendData(const char* buffer, int length, const QTextCodec *codec); signals: /** * Emitted when a new block of data is received from * the teletype. * * @param buffer Pointer to the data received. * @param length Length of @p buffer */ void receivedData(const char* buffer, int length, bool isCommandExec); /******** Modify by nt001000 renfeixiang 2020-05-27:修改 增加参数区别remove和purge卸载命令 Begin***************/ bool ptyUninstallTerminal(QString commandname); /******** Modify by nt001000 renfeixiang 2020-05-14:修改 增加参数区别remove和purge卸载命令 End***************/ protected: void setupChildProcess() override; private slots: // called when data is received from the terminal process void dataReceived(); private: void init(); bool isTerminalRemoved(); bool bWillRemoveTerminal(QString strCommand); /******** Add by nt001000 renfeixiang 2020-05-14:增加 Purge卸载命令的判断,显示不同的卸载提示框 Begin***************/ bool bWillPurgeTerminal(QString strCommand); /******** Add by nt001000 renfeixiang 2020-05-14:增加 Purge卸载命令的判断,显示不同的卸载提示框 End***************/ // takes a list of key=value pairs and adds them // to the environment for the process void addEnvironmentVariables(const QStringList& environment); int _windowColumns; int _windowLines; char _eraseChar; bool _xonXoff; bool _utf8; int _sessionId; bool _bUninstall; bool _bNeedBlockCommand = false;//是否为终端内部发送的命令(不是用户手动输入的命令),默认用户手动输入 int _receiveDataIndex = -1; const QTextCodec *_textCodec = nullptr; bool _isCommandExec = false; QString _program; QByteArray _waitLFBuffer; // 等待换行缓冲 }; } #endif // PTY_H deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/Screen.cpp000066400000000000000000001302051475472654300251110ustar00rootroot00000000000000/* This file is part of Konsole, an X terminal. Copyright 2007-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 (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. */ // Own #include "Screen.h" // Standard #include #include #include #include #include // Qt #include #include #include // KDE //#include // Konsole #include "konsole_wcwidth.h" #include "Session.h" #include "SessionManager.h" #include "TerminalCharacterDecoder.h" #include "TerminalDisplay.h" #include "history/HistoryType.h" #include "history/HistoryScrollNone.h" #include "EscapeSequenceUrlExtractor.h" using namespace Konsole; //FIXME: this is emulation specific. Use false for xterm, true for ANSI. //FIXME: see if we can get this from terminfo. #define BS_CLEARS false //Macro to convert x,y position on screen to position within an image. // //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. //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. #ifndef loc #define loc(X,Y) ((Y)*_columns+(X)) #endif const Character Screen::DefaultChar = Character(' ', CharacterColor(COLOR_SPACE_DEFAULT,DEFAULT_FORE_COLOR), CharacterColor(COLOR_SPACE_DEFAULT,DEFAULT_BACK_COLOR), DEFAULT_RENDITION); //#define REVERSE_WRAPPED_LINES // for wrapped line debug Screen::Screen(int l, int c) : _lines(l) , _columns(c) , _screenLines(_lines + 1) , _screenLinesSize(_lines) , _scrolledLines(0) , _droppedLines(0) , _history(new HistoryScrollNone()) , _cuX(0) , _cuY(0) , _currentRendition(0) , _topMargin(0) , _bottomMargin(0) , _selBegin(0) , _selTopLeft(0) , _selBottomRight(0) , _blockSelectionMode(false) , _effectiveForeground(CharacterColor()) , _effectiveBackground(CharacterColor()) , _effectiveRendition(0) , _lastPos(-1) , _lastDrawnChar(0) , _escapeSequenceUrlExtractor(new EscapeSequenceUrlExtractor) { _escapeSequenceUrlExtractor->setScreen(this); _lineProperties.resize(_lines + 1); std::fill(_lineProperties.begin(), _lineProperties.end(), LINE_DEFAULT); initTabStops(); clearSelection(); reset(); } /*! Destructor */ Screen::~Screen() { delete _history; delete _escapeSequenceUrlExtractor; } void Screen::cursorUp(int n) //=CUU { if (n < 1) { n = 1; // Default } const int stop = _cuY < _topMargin ? 0 : _topMargin; _cuY = qMax(stop, _cuY - n); } void Screen::cursorDown(int n) //=CUD { if (n < 1) { n = 1; // Default } if (n > MAX_SCREEN_ARGUMENT) { n = MAX_SCREEN_ARGUMENT; } const int stop = _cuY > _bottomMargin ? _lines - 1 : _bottomMargin; _cuY = qMin(stop, _cuY + n); } void Screen::cursorLeft(int n) //=CUB { if (n < 1) { n = 1; // Default } _cuX = qMax(0, _cuX - n); } void Screen::cursorRight(int n) //=CUF { if (n < 1) { n = 1; // Default } if (n > MAX_SCREEN_ARGUMENT) { n = MAX_SCREEN_ARGUMENT; } _cuX = qMin(getScreenLineColumns(_cuY) - 1, _cuX + n); } void Screen::setMargins(int top, int bot) //=STBM { if (top == 0) top = 1; // Default if (bot == 0) bot = _lines; // Default top = top - 1; // Adjust to internal lineno bot = bot - 1; // Adjust to internal lineno if ( !( 0 <= top && top < bot && bot < _lines ) ) { //Debug()<<" setRegion("< 0) _cuY -= 1; } void Screen::nextLine() //=NEL { toStartOfLine(); index(); } void Screen::eraseChars(int n) { if (n < 1) { n = 1; // Default } if (n > MAX_SCREEN_ARGUMENT) { n = MAX_SCREEN_ARGUMENT; } const int p = qBound(0, _cuX + n - 1, _columns - 1); clearImage(loc(_cuX, _cuY), loc(p, _cuY), ' ', false); } void Screen::deleteChars(int n) { Q_ASSERT( n >= 0 ); // always delete at least one char 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() ) n = _screenLines[_cuY].count() - _cuX; Q_ASSERT( n >= 0 ); Q_ASSERT( _cuX+n <= _screenLines[_cuY].count() ); _screenLines[_cuY].remove(_cuX,n); } void Screen::insertChars(int n) { if (n == 0) n = 1; // Default if ( _screenLines[_cuY].size() < _cuX ) _screenLines[_cuY].resize(_cuX); _screenLines[_cuY].insert(_cuX,n,' '); if ( _screenLines[_cuY].count() > _columns ) _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 scrollUp(_cuY,n); } void Screen::insertLines(int n) { if (n == 0) n = 1; // Default scrollDown(_cuY,n); } void Screen::setMode(int m) { _currentModes[m] = true; switch(m) { case MODE_Origin : _cuX = 0; _cuY = _topMargin; break; //FIXME: home } } void Screen::resetMode(int m) { _currentModes[m] = false; switch(m) { case MODE_Origin : _cuX = 0; _cuY = 0; break; //FIXME: home } } void Screen::saveMode(int m) { _savedModes[m] = _currentModes[m]; } void Screen::restoreMode(int m) { _currentModes[m] = _savedModes[m]; } bool Screen::getMode(int m) const { return _currentModes[m]; } void Screen::saveCursor() { _savedState.cursorColumn = _cuX; _savedState.cursorLine = _cuY; _savedState.rendition = _currentRendition; _savedState.foreground = _currentForeground; _savedState.background = _currentBackground; } void Screen::restoreCursor() { _cuX = qMin(_savedState.cursorColumn, _columns-1); _cuY = qMin(_savedState.cursorLine,_lines - 1); _currentRendition = _savedState.rendition; _currentForeground = _savedState.foreground; _currentBackground = _savedState.background; updateEffectiveRendition(); } void Screen::resizeImage(int new_lines, int new_columns) { if ((new_lines == _lines) && (new_columns == _columns)) { return; } // Adjust scroll position, and fix glitches _oldTotalLines = getLines() + getHistLines(); _isResize = true; int cursorLine = getCursorLine(); const int oldCursorLine = (cursorLine == _lines - 1 || cursorLine > new_lines - 1) ? new_lines - 1 : cursorLine; // Check if _history need to change if (_enableReflowLines && new_columns != _columns && _history->getLines() && _history->getMaxLines()) { // Join next line from _screenLine to _history while (_history->isWrappedLine(_history->getLines() - 1)) { fastAddHistLine(); cursorLine--; } auto removedLines = _history->reflowLines(new_columns); // If _history size > max _history size it will drop a line from _history. // We need to verify if we need to remove a URL. if (removedLines) { _escapeSequenceUrlExtractor->historyLinesRemoved(removedLines); } } if (_enableReflowLines && new_columns != _columns) { int cursorLineCorrection = 0; if (_currentTerminalDisplay) { // The 'zsh' works different from other shells when writting the command line. // It needs to identify the 'zsh' and calculate the new command line. auto currSession = SessionManager::instance()->idToSession(_sessionId); if (currSession && (QLatin1String("zsh") == currSession->foregroundProcessName()) && (cursorLine > 0) && ((_lineProperties[cursorLine - 1] & LINE_WRAPPED) != 0)) { while (cursorLine + cursorLineCorrection > 0 && (_lineProperties[cursorLine + cursorLineCorrection - 1] & LINE_WRAPPED) != 0) { cursorLineCorrection--; } } } // Analize the lines and move the data to lines below. int currentPos = 0; while (currentPos < (cursorLine + cursorLineCorrection) && currentPos < _screenLines.count() - 1) { // Join wrapped line in current position if ((_lineProperties[currentPos] & LINE_WRAPPED) != 0) { _screenLines[currentPos].append(std::move(_screenLines[currentPos + 1])); _screenLines.remove(currentPos + 1); _lineProperties.remove(currentPos); cursorLine--; continue; } // Ignore whitespaces at the end of the line int lineSize = _screenLines[currentPos].size(); while (lineSize > 0 && QChar(_screenLines[currentPos][lineSize - 1].character).isSpace()) { lineSize--; } // If need to move to line below, copy from the current line, to the next one. if (lineSize > new_columns) { auto values = _screenLines[currentPos].mid(new_columns); _screenLines[currentPos].resize(new_columns); _lineProperties.insert(currentPos + 1, _lineProperties[currentPos]); _screenLines.insert(currentPos + 1, std::move(values)); _lineProperties[currentPos] |= LINE_WRAPPED; cursorLine++; } currentPos += 1; } } // Check if it need to move from _screenLine to _history while (cursorLine > new_lines - 1) { fastAddHistLine(); cursorLine--; } if (_enableReflowLines) { // Check cursor position and send from _history to _screenLines ImageLine histLine; histLine.reserve(1024); while (cursorLine < oldCursorLine && _history->getLines()) { int histPos = _history->getLines() - 1; int histLineLen = _history->getLineLen(histPos); LineProperty lineProperty = _history->getLineProperty(histPos); histLine.resize(histLineLen); _history->getCells(histPos, 0, histLineLen, histLine.data()); _screenLines.insert(0, histLine); _lineProperties.insert(0, lineProperty); _history->removeCells(); cursorLine++; } } _lineProperties.resize(new_lines + 1); if (_lineProperties.size() > _screenLines.size()) { std::fill(_lineProperties.begin() + _screenLines.size(), _lineProperties.end(), LINE_DEFAULT); } _screenLines.resize(new_lines + 1); _screenLinesSize = new_lines; _lines = new_lines; _columns = new_columns; _cuX = qMin(_cuX, _columns - 1); cursorLine = qBound(0, cursorLine, _lines - 1); setCursorLine(cursorLine); // FIXME: try to keep values, evtl. setDefaultMargins(); initTabStops(); clearSelection(); } void Screen::setDefaultMargins() { _topMargin = 0; _bottomMargin = _lines - 1; } /* Clarifying rendition here and in the display. currently, the display's color table is 0 1 2 .. 9 10 .. 17 dft_fg, dft_bg, dim 0..7, intensive 0..7 _currentForeground, _currentBackground contain values 0..8; - 0 = default color - 1..8 = ansi specified color re_fg, re_bg contain values 0..17 due to the TerminalDisplay's color table rendition attributes are attr widget screen -------------- ------ ------ RE_UNDERLINE XX XX affects foreground only RE_BLINK XX XX affects foreground only RE_BOLD XX XX affects foreground only RE_REVERSE -- XX RE_TRANSPARENT XX -- affects background only RE_INTENSIVE XX -- affects foreground only Note that RE_BOLD is used in both widget and screen rendition. Since xterm/vt102 is to poor to distinguish between bold (which is a font attribute) and intensive (which is a color attribute), we translate this and RE_BOLD in falls eventually appart into RE_BOLD and RE_INTENSIVE. */ void Screen::reverseRendition(Character& p) const { CharacterColor f = p.foregroundColor; CharacterColor b = p.backgroundColor; p.foregroundColor = b; p.backgroundColor = f; //p->r &= ~RE_TRANSPARENT; } void Screen::updateEffectiveRendition() { _effectiveRendition = _currentRendition; if (_currentRendition & RE_REVERSE) { _effectiveForeground = _currentBackground; _effectiveBackground = _currentForeground; } else { _effectiveForeground = _currentForeground; _effectiveBackground = _currentBackground; } if (_currentRendition & RE_BOLD) _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++) { 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++) dest[destLineOffset+column] = DefaultChar; // invert selected text if (_selBegin !=-1) { for (int column = 0; column < _columns; column++) { if (isSelected(column,line)) { reverseRendition(dest[destLineOffset + column]); } } } } } void Screen::copyFromScreen(Character* dest , int startLine , int count) const { Q_ASSERT( startLine >= 0 && count > 0 && startLine + count <= _lines ); for (int line = startLine; line < (startLine+count) ; line++) { int srcLineStartIndex = line * _columns; int destLineStartIndex = (line - startLine) * _columns; for (int column = 0; column < _columns; 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]); } } } void Screen::getImage( Character* dest, int size, int startLine, int endLine ) const { Q_ASSERT( startLine >= 0 ); Q_ASSERT( endLine >= startLine && endLine < _history->getLines() + _lines ); const int mergedLines = endLine - startLine + 1; Q_ASSERT( size >= mergedLines * _columns ); Q_UNUSED( size ); const int linesInHistoryBuffer = qBound(0, _history->getLines()-startLine,mergedLines); const int linesInScreenBuffer = mergedLines - linesInHistoryBuffer; // copy _lines from _history buffer if (linesInHistoryBuffer > 0) copyFromHistory(dest,startLine,linesInHistoryBuffer); // copy _lines from screen buffer if (linesInScreenBuffer > 0) copyFromScreen(dest + linesInHistoryBuffer * _columns, startLine + linesInHistoryBuffer - _history->getLines(), linesInScreenBuffer); // invert display when in screen mode if (getMode(MODE_Screen)) { for (int i = 0; i < mergedLines * _columns; i++) reverseRendition(dest[i]); // for reverse display } // mark the character at the current cursor position int cursorIndex = loc(_cuX, _cuY + linesInHistoryBuffer); if(getMode(MODE_Cursor) && cursorIndex < _columns * mergedLines) dest[cursorIndex].rendition |= RE_CURSOR; } QVector Screen::getLineProperties( int startLine , int endLine ) const { Q_ASSERT( startLine >= 0 ); Q_ASSERT( endLine >= startLine && endLine < _history->getLines() + _lines ); const int mergedLines = endLine-startLine+1; const int linesInHistory = qBound(0, _history->getLines()-startLine,mergedLines); const int linesInScreen = mergedLines - linesInHistory; QVector result(mergedLines); int index = 0; // copy properties for _lines in _history for (int line = startLine; line < startLine + linesInHistory; line++) { result[index] = _history->getLineProperty(line); index++; } // copy properties for lines in screen buffer const int firstScreenLine = startLine + linesInHistory - _history->getLines(); for (int line = firstScreenLine; line < firstScreenLine+linesInScreen; line++) { result[index] = _lineProperties[line]; index++; } return result; } int Screen::getScreenLineColumns(const int line) const { const int doubleWidthLine = _lineProperties[line] & LINE_DOUBLEWIDTH; if (doubleWidthLine) { return _columns / 2; } return _columns; } void Screen::reset(bool clearScreen) { setMode(MODE_Wrap ); saveMode(MODE_Wrap ); // wrap at end of margin resetMode(MODE_Origin); saveMode(MODE_Origin); // position refere to [1,1] resetMode(MODE_Insert); saveMode(MODE_Insert); // overstroke setMode(MODE_Cursor); // cursor visible resetMode(MODE_Screen); // screen not inverse resetMode(MODE_NewLine); _topMargin=0; _bottomMargin=_lines - 1; setDefaultRendition(); saveCursor(); if ( clearScreen ) clear(); } void Screen::clear() { clearEntireScreen(); home(); } void Screen::backspace() { _cuX = qMin(_columns - 1, _cuX); // nowrap! _cuX = qMax(0, _cuX - 1); if (_screenLines[_cuY].size() < _cuX + 1) _screenLines[_cuY].resize(_cuX + 1); if (BS_CLEARS) _screenLines[_cuY][_cuX].character = ' '; } void Screen::tab(int n) { // note that TAB is a format effector (does not write ' '); if (n == 0) n = 1; while((n > 0) && (_cuX < _columns-1)) { cursorRight(1); while((_cuX < _columns - 1) && !_tabStops[_cuX]) { int oldXValue = _cuX; cursorRight(1); if (oldXValue == _cuX) { break; } } n--; } } void Screen::backtab(int n) { // note that TAB is a format effector (does not write ' '); if (n == 0) n = 1; while((n > 0) && (_cuX > 0)) { cursorLeft(1); while((_cuX > 0) && !_tabStops[_cuX]) cursorLeft(1); n--; } } void Screen::clearTabStops() { for (int i = 0; i < _columns; i++) _tabStops[i] = false; } void Screen::changeTabStop(bool set) { if (_cuX >= _columns) return; _tabStops[_cuX] = set; } void Screen::initTabStops() { _tabStops.resize(_columns); // 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++) _tabStops[i] = (i%8 == 0 && i != 0); } void Screen::newLine() { if (getMode(MODE_NewLine)) toStartOfLine(); index(); } void Screen::checkSelection(int from, int to) { if (_selBegin == -1) return; int scr_TL = loc(0, _history->getLines()); //Clear entire selection if it overlaps region [from, to] if ( (_selBottomRight >= (from+scr_TL)) && (_selTopLeft <= (to+scr_TL)) ) clearSelection(); } void Screen::displayCharacter(uint c) { // Note that VT100 does wrapping BEFORE putting the character. // This has impact on the assumption of valid cursor positions. // We indicate the fact that a newline has to be triggered by // putting the cursor one right to the last column of the screen. int w = Character::width(c); if (w <= 0) return; if (_cuX + w > _columns) { if (getMode(MODE_Wrap)) { _lineProperties[_cuY] = (LineProperty)(_lineProperties[_cuY] | LINE_WRAPPED); nextLine(); } else _cuX = _columns - w; } // ensure current line vector has enough elements if (_cuY >= _screenLines.size()) return; int size = _screenLines[_cuY].size(); if (size < _cuX+w) { _screenLines[_cuY].resize(_cuX+w); } if (getMode(MODE_Insert)) insertChars(w); _lastPos = loc(_cuX,_cuY); // check if selection is still valid. checkSelection(_lastPos, _lastPos); Character& currentChar = _screenLines[_cuY][_cuX]; currentChar.character = c; currentChar.foregroundColor = _effectiveForeground; currentChar.backgroundColor = _effectiveBackground; currentChar.rendition = _effectiveRendition; _lastDrawnChar = c; int i = 0; int newCursorX = _cuX + w--; while(w) { i++; if ( _screenLines[_cuY].size() < _cuX + i + 1 ) _screenLines[_cuY].resize(_cuX+i+1); Character& ch = _screenLines[_cuY][_cuX + i]; ch.character = 0; ch.foregroundColor = _effectiveForeground; ch.backgroundColor = _effectiveBackground; ch.rendition = _effectiveRendition; w--; } _cuX = newCursorX; _escapeSequenceUrlExtractor->appendUrlText(QChar(c)); } void Screen::compose(const QString& /*compose*/) { Q_ASSERT( 0 /*Not implemented yet*/ ); /* if (_lastPos == -1) return; QChar c(image[_lastPos].character); compose.prepend(c); //compose.compose(); ### FIXME! image[_lastPos].character = compose[0].unicode();*/ } int Screen::scrolledLines() const { return _scrolledLines; } int Screen::droppedLines() const { return _droppedLines; } void Screen::resetDroppedLines() { _droppedLines = 0; } void Screen::resetScrolledLines() { _scrolledLines = 0; } void Screen::scrollUp(int n) { if (n < 1) { n = 1; // Default } if (_topMargin == 0) { addHistLine(); // history.history } scrollUp(_topMargin, n); } QRect Screen::lastScrolledRegion() const { return _lastScrolledRegion; } void Screen::scrollUp(int from, int n) { if (n <= 0) return; if (from > _bottomMargin) return; if (from + n > _bottomMargin) n = _bottomMargin + 1 - from; _scrolledLines -= n; _lastScrolledRegion = QRect(0, _topMargin, _columns - 1,(_bottomMargin - _topMargin)); //FIXME: make sure `topMargin', `bottomMargin', `from', `n' is in bounds. moveImage(loc(0, from), loc(0,from + n), loc(_columns, _bottomMargin)); clearImage(loc(0, _bottomMargin - n + 1), loc(_columns - 1, _bottomMargin), ' '); } void Screen::scrollDown(int n) { if (n == 0) n = 1; // Default scrollDown(_topMargin, n); } void Screen::scrollDown(int from, int n) { _scrolledLines += n; //FIXME: make sure `topMargin', `bottomMargin', `from', `n' is in bounds. if (n <= 0) return; if (from > _bottomMargin) return; 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),' '); } void Screen::setCursorYX(int y, int x) { setCursorY(y); setCursorX(x); } void Screen::setCursorX(int x) { if (x == 0) x = 1; // Default x -= 1; // Adjust _cuX = qMax(0,qMin(_columns - 1, x)); } void Screen::setCursorY(int y) { if (y < 1) { y = 1; // Default } if (y > MAX_SCREEN_ARGUMENT) { y = MAX_SCREEN_ARGUMENT; } y += (getMode(MODE_Origin) ? _topMargin : 0); _cuY = qBound(0, y - 1, _lines - 1); } void Screen::home() { _cuX = 0; _cuY = 0; } void Screen::toStartOfLine() { _cuX = 0; } int Screen::getCursorX() const { return _cuX; } int Screen::getCursorY() const { return _cuY; } void Screen::clearImage(int loca, int loce, char c, bool resetLineRendition) { int scr_TL=loc(0, _history->getLines()); //FIXME: check positions //Clear entire selection if it overlaps region to be moved... if ( (_selBottomRight > (loca+scr_TL) )&&(_selTopLeft < (loce+scr_TL)) ) { clearSelection(); } int topLine = loca / _columns; int bottomLine = loce / _columns; Character clearCh(c, _currentForeground, _currentBackground, DEFAULT_RENDITION); //if the character being used to clear the area is the same as the //default character, the affected _lines can simply be shrunk. bool isDefaultCh = (clearCh == Character()); for (int y=topLine;y<=bottomLine;y++) { if(y >= _lineProperties.size()) break; _lineProperties[y] = 0; int endCol = ( y == bottomLine) ? loce % _columns : _columns - 1; int startCol = ( y == topLine ) ? loca % _columns : 0; QVector& line = _screenLines[y]; if ( isDefaultCh && endCol == _columns - 1 ) { line.resize(startCol); } else { if (line.size() < endCol + 1) line.resize(endCol+1); Character* data = line.data(); for (int i=startCol;i<=endCol;i++) data[i]=clearCh; } if (resetLineRendition && startCol == 0 && endCol == _columns - 1) { _lineProperties[y] &= ~(LINE_DOUBLEWIDTH | LINE_DOUBLEHEIGHT_TOP | LINE_DOUBLEHEIGHT_BOTTOM); } } } void Screen::moveImage(int dest, int sourceBegin, int sourceEnd) { Q_ASSERT( sourceBegin <= 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 - //forwards if dest < sourceBegin or backwards otherwise. //(search the web for 'memmove implementation' for details) if (dest < sourceBegin) { for (int i=0;i<=lines;i++) { _screenLines[(dest / _columns)+i ] = _screenLines[ (sourceBegin / _columns)+i ]; _lineProperties[(dest / _columns)+i] =_lineProperties[(sourceBegin / _columns)+i]; } } else { for (int i=lines;i>=0;i--) { _screenLines[(dest / _columns)+i ] = _screenLines[ (sourceBegin / _columns)+i ]; _lineProperties[(dest / _columns)+i] =_lineProperties[(sourceBegin / _columns)+i]; } } if (_lastPos != -1) { int diff = dest - sourceBegin; // Scroll by this amount _lastPos += diff; if ((_lastPos < 0) || (_lastPos >= (lines * _columns))) _lastPos = -1; } // Adjust selection to follow scroll. if (_selBegin != -1) { bool beginIsTL = (_selBegin == _selTopLeft); int diff = dest - sourceBegin; // Scroll by this amount int scr_TL=loc(0, _history->getLines()); int srca = sourceBegin+scr_TL; // Translate index from screen to global int srce = sourceEnd+scr_TL; // Translate index from screen to global int desta = srca+diff; int deste = srce+diff; if ((_selTopLeft >= srca) && (_selTopLeft <= srce)) _selTopLeft += diff; else if ((_selTopLeft >= desta) && (_selTopLeft <= deste)) _selBottomRight = -1; // Clear selection (see below) if ((_selBottomRight >= srca) && (_selBottomRight <= srce)) _selBottomRight += diff; else if ((_selBottomRight >= desta) && (_selBottomRight <= deste)) _selBottomRight = -1; // Clear selection (see below) if (_selBottomRight < 0) { clearSelection(); } else { if (_selTopLeft < 0) _selTopLeft = 0; } if (beginIsTL) _selBegin = _selTopLeft; else _selBegin = _selBottomRight; } } void Screen::clearToEndOfScreen() { clearImage(loc(_cuX,_cuY), loc(_columns - 1, _lines - 1), ' '); } void Screen::clearToBeginOfScreen() { clearImage(loc(0, 0), loc(_cuX, _cuY), ' '); } void Screen::clearEntireScreen() { clearImage(loc(0, 0), loc(_columns - 1, _lines - 1), ' '); } /*! fill screen with 'E' This is to aid screen alignment */ void Screen::helpAlign() { clearImage(loc(0, 0), loc(_columns - 1, _lines - 1), 'E'); } void Screen::clearToEndOfLine() { clearImage(loc(_cuX,_cuY),loc(_columns - 1,_cuY),' '); } void Screen::clearToBeginOfLine() { clearImage(loc(0,_cuY),loc(_cuX,_cuY),' '); } void Screen::clearEntireLine() { clearImage(loc(0, _cuY), loc(_columns - 1, _cuY), ' '); } void Screen::setRendition(int re) { _currentRendition |= re; updateEffectiveRendition(); } void Screen::resetRendition(int re) { _currentRendition &= ~re; updateEffectiveRendition(); } void Screen::setDefaultRendition() { setForeColor(COLOR_SPACE_DEFAULT,DEFAULT_FORE_COLOR); setBackColor(COLOR_SPACE_DEFAULT,DEFAULT_BACK_COLOR); _currentRendition = DEFAULT_RENDITION; updateEffectiveRendition(); } void Screen::setForeColor(int space, int color) { _currentForeground = CharacterColor(space, color); if ( _currentForeground.isValid() ) updateEffectiveRendition(); else setForeColor(COLOR_SPACE_DEFAULT,DEFAULT_FORE_COLOR); } void Screen::setBackColor(int space, int color) { _currentBackground = CharacterColor(space, color); if ( _currentBackground.isValid() ) updateEffectiveRendition(); else setBackColor(COLOR_SPACE_DEFAULT,DEFAULT_BACK_COLOR); } void Screen::clearSelection() { _selBottomRight = -1; _selTopLeft = -1; _selBegin = -1; } void Screen::getSelectionStart(int& column , int& line) const { if ( _selTopLeft != -1 ) { column = _selTopLeft % _columns; line = _selTopLeft / _columns; } else { column = _cuX + getHistLines(); line = _cuY + getHistLines(); } } void Screen::getSelectionEnd(int& column , int& line) const { if ( _selBottomRight != -1 ) { column = _selBottomRight % _columns; line = _selBottomRight / _columns; } else { column = _cuX + getHistLines(); line = _cuY + getHistLines(); } } void Screen::setSelectionStart(const int x, const int y, const bool mode) { _selBegin = loc(x,y); /* FIXME, HACK to correct for x too far to the right... */ if (x == _columns) _selBegin--; _selBottomRight = _selBegin; _selTopLeft = _selBegin; _blockSelectionMode = mode; } void Screen::setSelectionEnd( const int x, const int y) { if (_selBegin == -1) return; int endPos = loc(x,y); if (endPos < _selBegin) { _selTopLeft = endPos; _selBottomRight = _selBegin; } else { /* FIXME, HACK to correct for x too far to the right... */ if (x == _columns) endPos--; _selTopLeft = _selBegin; _selBottomRight = endPos; } // Normalize the selection in column mode if (_blockSelectionMode) { int topRow = _selTopLeft / _columns; int topColumn = _selTopLeft % _columns; int bottomRow = _selBottomRight / _columns; int bottomColumn = _selBottomRight % _columns; _selTopLeft = loc(qMin(topColumn, bottomColumn), topRow); _selBottomRight = loc(qMax(topColumn, bottomColumn), bottomRow); } } /******************************************************************** 1. @函数: setSelectionAll 2. @作者: 王培利 3. @日期: 2020-02-13 4. @说明: 屏幕全选功能 ********************************************************************/ void Screen::setSelectionAll() { _selBegin = 0; _selTopLeft = 0; int endPos = (getHistLines() + getCursorY() + 1) * _columns - 1; _selBottomRight = endPos; } bool Screen::isSelected(const int x, const int y) const { bool columnInSelection = true; if (_blockSelectionMode) { columnInSelection = x >= (_selTopLeft % _columns) && x <= (_selBottomRight % _columns); } int pos = loc(x,y); return pos >= _selTopLeft && pos <= _selBottomRight && columnInSelection; } QString Screen::selectedText(const DecodingOptions options) const { if (!isSelectionValid()) { return QString(); } return text(_selTopLeft, _selBottomRight, options); } QString Screen::text(int startIndex, int endIndex, const DecodingOptions options) const { QString result; QTextStream stream(&result, QIODevice::ReadWrite); HTMLDecoder htmlDecoder; PlainTextDecoder plainTextDecoder; TerminalCharacterDecoder *decoder; if((options & ConvertToHtml) != 0U) { decoder = &htmlDecoder; } else { decoder = &plainTextDecoder; } decoder->begin(&stream); writeToStream(decoder, startIndex, endIndex, options); decoder->end(); return result; } bool Screen::isSelectionValid() const { return _selTopLeft >= 0 && _selBottomRight >= 0; } void Screen::writeSelectionToStream(TerminalCharacterDecoder* decoder, const DecodingOptions options) const { if (!isSelectionValid()) return; writeToStream(decoder,_selTopLeft,_selBottomRight,options); } void Screen::writeToStream(TerminalCharacterDecoder* decoder, int startIndex, int endIndex, const DecodingOptions options) const { int top = startIndex / _columns; int left = startIndex % _columns; int bottom = endIndex / _columns; int right = endIndex % _columns; Q_ASSERT( top >= 0 && left >= 0 && bottom >= 0 && right >= 0 ); for (int y=top;y<=bottom;y++) { int start = 0; if ( y == top || _blockSelectionMode ) start = left; int count = -1; if ( y == bottom || _blockSelectionMode ) count = right - start + 1; const bool appendNewLine = ( y != bottom ); int copied = copyLineToStream( y, start, count, decoder, appendNewLine, options ); // if the selection goes beyond the end of the last line then // 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 && copied < count ) { Character newLineChar('\n'); decoder->decodeLine(&newLineChar,1,0); } } } int Screen::getLineLength(const int line) const { // determine if the line is in the history buffer or the screen image const bool isInHistoryBuffer = line < _history->getLines(); if (isInHistoryBuffer) { return _history->getLineLen(line); } return _columns; } Character *Screen::getCharacterBuffer(const int size) { // buffer to hold characters for decoding // the buffer is static to avoid initializing every // element on each call to copyLineToStream // (which is unnecessary since all elements will be overwritten anyway) static const int MAX_CHARS = 1024; static QVector characterBuffer(MAX_CHARS); if (characterBuffer.count() < size) { characterBuffer.resize(size); } return characterBuffer.data(); } int Screen::copyLineToStream(int line , int start, int count, TerminalCharacterDecoder* decoder, bool appendNewLine, const DecodingOptions options) const { const int lineLength = getLineLength(line); // ensure that this method, can append space or 'eol' character to // the selection Character *characterBuffer = getCharacterBuffer((count > -1 ? count : lineLength - start) + 1); LineProperty currentLineProperties = 0; // determine if the line is in the history buffer or the screen image if (line < _history->getLines()) { // ensure that start position is before end of line start = qBound(0, start, lineLength - 1); // 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 if (count == -1) { count = lineLength - start; } else { count = qMin(start + count, lineLength) - start; } // safety checks Q_ASSERT(start >= 0); Q_ASSERT(count >= 0); Q_ASSERT((start + count) <= _history->getLineLen(line)); _history->getCells(line, start, count, characterBuffer); if (_history->isWrappedLine(line)) { currentLineProperties |= LINE_WRAPPED; } } else { if (count == -1) { count = lineLength - start; } Q_ASSERT(count >= 0); int screenLine = line - _history->getLines(); Q_ASSERT(screenLine <= _screenLinesSize); screenLine = qMin(screenLine, _screenLinesSize); auto* data = _screenLines[screenLine].data(); int length = _screenLines[screenLine].count(); // Don't remove end spaces in lines that wrap if (options.testFlag(TrimTrailingWhitespace) && ((_lineProperties[screenLine] & LINE_WRAPPED) == 0)) { // ignore trailing white space at the end of the line while (length > 0 && QChar(data[length - 1].character).isSpace()) { length--; } } //retrieve line from screen image auto end = qMin(start + count, length); if (start < end) { std::copy(data + start, data + end, characterBuffer); } // count cannot be any greater than length count = qBound(0, count, length - start); Q_ASSERT(screenLine < _lineProperties.count()); currentLineProperties |= _lineProperties[screenLine]; } if (appendNewLine) { if ((currentLineProperties & LINE_WRAPPED) != 0) { // do nothing extra when this line is wrapped. } else { // When users ask not to preserve the linebreaks, they usually mean: // `treat LINEBREAK as SPACE, thus joining multiple _lines into // single line in the same way as 'J' does in VIM.` characterBuffer[count] = options.testFlag(PreserveLineBreaks) ? Character('\n') : Character(' '); count++; } } if ((options & TrimLeadingWhitespace) != 0U) { int spacesCount = 0; for (spacesCount = 0; spacesCount < count; spacesCount++) { if (QChar::category(characterBuffer[spacesCount].character) != QChar::Category::Separator_Space) { break; } } if (spacesCount >= count) { return 0; } std::copy(characterBuffer + spacesCount, characterBuffer + count, characterBuffer); count -= spacesCount; } //decode line and write to text stream decoder->decodeLine(characterBuffer, count, currentLineProperties); return count; } void Screen::writeLinesToStream(TerminalCharacterDecoder* decoder, int fromLine, int toLine) const { writeToStream(decoder, loc(0,fromLine), loc(_columns-1,toLine), PreserveLineBreaks); } void Screen::fastAddHistLine() { const bool removeLine = _history->getLines() == _history->getMaxLines(); _history->addCellsVector(_screenLines[0]); _history->addLine(_lineProperties[0]); // If history size > max history size it will drop a line from history. // We need to verify if we need to remove a URL. if (removeLine) { _escapeSequenceUrlExtractor->historyLinesRemoved(1); } _screenLines.pop_front(); _lineProperties.remove(0); } void Screen::addHistLine() { // add line to history buffer // we have to take care about scrolling, too... if (hasScroll()) { int oldHistLines = _history->getLines(); _history->addCellsVector(_screenLines[0]); _history->addLine(static_cast(_lineProperties[0] & LINE_WRAPPED )); int newHistLines = _history->getLines(); bool beginIsTL = (_selBegin == _selTopLeft); // If the history is full, increment the count // of dropped _lines if ( newHistLines == oldHistLines ) _droppedLines++; // Adjust selection for the new point of reference if (newHistLines > oldHistLines) { if (_selBegin != -1) { _selTopLeft += _columns; _selBottomRight += _columns; } } if (_selBegin != -1) { // Scroll selection in history up int top_BR = loc(0, 1+newHistLines); if (_selTopLeft < top_BR) _selTopLeft -= _columns; if (_selBottomRight < top_BR) _selBottomRight -= _columns; if (_selBottomRight < 0) clearSelection(); else { if (_selTopLeft < 0) _selTopLeft = 0; } if (beginIsTL) _selBegin = _selTopLeft; else _selBegin = _selBottomRight; } } } int Screen::getHistLines() const { return _history->getLines(); } void Screen::setScroll(const HistoryType& t , bool copyPreviousScroll) { clearSelection(); if ( copyPreviousScroll ) _history = t.scroll(_history); else { HistoryScroll* oldScroll = _history; _history = t.scroll(nullptr); delete oldScroll; } } bool Screen::hasScroll() const { return _history->hasScroll(); } const HistoryType& Screen::getScroll() const { return _history->getType(); } void Screen::setLineProperty(LineProperty property , bool enable) { if ( enable ) _lineProperties[_cuY] = (LineProperty)(_lineProperties[_cuY] | property); else _lineProperties[_cuY] = (LineProperty)(_lineProperties[_cuY] & ~property); } void Screen::fillWithDefaultChar(Character* dest, int count) { for (int i=0;i 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 (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. */ #ifndef SCREEN_H #define SCREEN_H // Qt #include #include #include #include #include // Konsole #include "Character.h" #define MODE_Origin 0 #define MODE_Wrap 1 #define MODE_Insert 2 #define MODE_Screen 3 #define MODE_Cursor 4 #define MODE_NewLine 5 #define MODE_AppScreen 6 #define MODES_SCREEN 7 namespace Konsole { class TerminalCharacterDecoder; class TerminalDisplay; class HistoryType; class HistoryScroll; class EscapeSequenceUrlExtractor; /** \brief An image of characters with associated attributes. The terminal emulation ( Emulation ) receives a serial stream of 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. getImage() is used to retrieve the currently visible image which is then used by the display widget to draw the output from the 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. 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 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. */ class Screen { public: /* PlainText: Return plain text (default) * ConvertToHtml: Specifies if returned text should have HTML tags. * PreserveLineBreaks: Specifies whether new line characters should be * inserted into the returned text at the end of each terminal line. * TrimLeadingWhitespace: Specifies whether leading spaces should be * trimmed in the returned text. * TrimTrailingWhitespace: Specifies whether trailing spaces should be * trimmed in the returned text. */ enum DecodingOption { PlainText = 0x0, ConvertToHtml = 0x1, PreserveLineBreaks = 0x2, TrimLeadingWhitespace = 0x4, TrimTrailingWhitespace = 0x8 }; Q_DECLARE_FLAGS(DecodingOptions, DecodingOption) /** Construct a new screen image of size @p lines by @p columns. */ Screen(int lines, int columns); ~Screen(); // VT100/2 Operations // Cursor Movement /** * 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. */ void cursorRight(int n); /** Position the cursor on line @p y. */ void setCursorY(int y); /** Position the cursor at column @p x. */ void setCursorX(int x); /** Position the cursor at line @p y, column @p x. */ void setCursorYX(int y, int x); /** * 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. */ void setMargins(int topLine , int bottomLine); /** 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 * 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. */ void newLine(); /** * Moves the cursor down one line and positions it at the beginning * of the line. Equivalent to calling Return() followed by index() */ 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. */ void index(); /** * Move the cursor up one line. If the cursor is on the top line * of the scrolling region (as returned by topMargin()) the scrolling * 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 * using setMargins() */ void scrollUp(int n); /** * Scroll the scrolling region of the screen down by @p n lines. * The scrolling region is initially the whole screen, but can be changed * using setMargins() */ void scrollDown(int n); /** * 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. */ void backspace(); /** Moves the cursor @p n tab-stops to the right. */ 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. * 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. */ void eraseChars(int n); /** * 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. * 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. */ void deleteLines(int n); /** * Inserts @p lines beginning from the current cursor position. * The position of the cursor is not altered. * If @p n is 0 then one line is inserted. */ void insertLines(int n); /** Clears all the tab stops. */ void clearTabStops(); /** 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() */ void saveMode(int mode); /** Restores the state of a screen @p mode saved by calling saveMode() */ 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() */ 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. */ void clearEntireScreen(); /** * Clear the area of the screen from the current cursor position to the end of * the screen. */ void clearToEndOfScreen(); /** * Clear the area of the screen from the current cursor position to the start * of the screen. */ void clearToBeginOfScreen(); /** Clears the whole of the line on which the cursor is currently positioned. */ void clearEntireLine(); /** Clears from the current cursor position to the end of the line. */ 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 * of characters on the screen. * * @see Character::rendition */ void setRendition(int rendition); /** * Disables the given @p rendition flag. Rendition flags control the appearance * of characters on the screen. * * @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 * the color @p space used. * * @see CharacterColor */ void setForeColor(int space, int color); /** * Sets the cursor's background color. * @param space The color space used by the @p color argumnet. * @param color The new background color. The meaning of this depends on * the color @p space used. * * @see CharacterColor */ void setBackColor(int space, int color); /** * 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) */ void home(); /** * Resets the state of the screen. This resets the various screen modes * back to their default states. The cursor style and colors are reset * (as if setDefaultRendition() had been called) * *
    *
  • Line wrapping is enabled.
  • *
  • Origin mode is disabled.
  • *
  • Insert mode is disabled.
  • *
  • Cursor mode is enabled. TODO Document me
  • *
  • Screen mode is disabled. TODO Document me
  • *
  • New line mode is disabled. TODO Document me
  • *
* * 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. * * 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 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(uint 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. * 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 * 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. * The result is an array of Characters of size [getLines()][getColumns()] which * must be freed by the caller after use. * * @param dest Buffer to copy the characters into * @param size Size of @p dest in Characters * @param startLine Index of first line to copy * @param endLine Index of last line to copy */ 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 * 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 { return _lines; } /** Return the number of columns. */ 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 * 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. * @param line The line index of the first character in the selection. * @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. */ void setSelectionEnd(const int column, const int line); /******** Modify by n014361 wangpeili 2020-02-13: 新增屏幕全选功能***********×****/ void setSelectionAll(); /***************** Modify by n014361 End *************************/ /** * 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. */ void getSelectionEnd(int& column , int& line) const; /** Clears the current selection */ void clearSelection(); /** * Returns true if the character at (@p column, @p line) is part of the * 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 * be inserted into the returned text at the end of each terminal line. */ QString selectedText(const DecodingOptions options) const; /** * Convenience method. Returns the text between two indices. * @param startIndex Specifies the starting text index * @param endIndex Specifies the ending text index * @param options See Screen::DecodingOptions */ QString text(int startIndex, int endIndex, const DecodingOptions options) const; /** * Copies part of the output to a stream. * * @param decoder A decoder which converts terminal characters into text * @param fromLine The first line in the history to retrieve * @param toLine The last line in the history to retrieve */ void writeLinesToStream(TerminalCharacterDecoder* decoder, int fromLine, int toLine) const; /** * 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 * 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. */ void writeSelectionToStream(TerminalCharacterDecoder* decoder, const DecodingOptions options) const; /** * Checks if the text between from and to is inside the current * selection. If this is the case, the selection is cleared. The * from and to are coordinates in the current viewable window. * The loc(x,y) macro can be used to generate these values from a * column,line pair. * * @param from The start of the area to check. * @param to The end of the area to check */ 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 * 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. * This allows other parts of the code to work on the * assumption that all lines are the same height. * * @param enable true to apply the attribute to the current line or false to remove it */ 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. */ 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 * 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() */ void resetScrolledLines(); /** * Returns the number of lines of output which have been * dropped from the history since the last call * to resetDroppedLines() * * If the history is not unlimited then it will drop * the oldest lines of output if new lines are added when * it is full. */ int droppedLines() const; /** * Resets the count of the number of lines dropped from * the history. */ 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); void setCurrentTerminalDisplay(TerminalDisplay *display) { _currentTerminalDisplay = display; } TerminalDisplay *currentTerminalDisplay() { return _currentTerminalDisplay; } QSet usedExtendedChars() const { QSet result; for (int i = 0; i < _lines; ++i) { const ImageLine &il = _screenLines[i]; for (int j = 0; j < il.length(); ++j) { if (il[j].rendition & RE_EXTENDED_CHAR) { result << il[j].character; } } } return result; } static const Character DefaultChar; // Return the total number of lines before resize (fix scroll glitch) int getOldTotalLines(); // Return if it was a resize signal (fix scroll glitch) bool isResize(); // Set reflow condition void setReflowLines(bool enable); // 设置sessionId void setSessionId(int sessionId); private: Screen(const Screen &) = delete; Screen &operator=(const Screen &) = delete; EscapeSequenceUrlExtractor *urlExtractor() const; //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 // //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, TerminalCharacterDecoder* decoder, bool appendNewLine, const DecodingOptions options) 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. void clearImage(int loca, int loce, char c, bool resetLineRendition = true); //move screen image between 'sourceBegin' and 'sourceEnd' to 'dest'. //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. // //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 void scrollUp(int from, int i); // scroll down 'i' lines in current region, clearing the top 'i' lines void scrollDown(int from, int i); void addHistLine(); // add lines from screen to history and remove from screen the added lines (used to resize lines and columns) void fastAddHistLine(); void initTabStops(); void updateEffectiveRendition(); void reverseRendition(Character& p) const; 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, int endIndex, const DecodingOptions options) const; // copies 'count' lines from the screen buffer into 'dest', // starting from 'startLine', where 0 is the first line in the screen buffer void copyFromScreen(Character* dest, int startLine, int count) const; // copies 'count' lines from the history buffer into 'dest', // starting from 'startLine', where 0 is the first line in the history void copyFromHistory(Character* dest, int startLine, int count) const; // returns a buffer that can hold at most 'count' characters, // where the number of reallocations and object reinitializations // should be as minimal as possible static Character *getCharacterBuffer(const int size); // Get the cursor line after checking if its app mode or not int getCursorLine(); // Set the cursor line after checking if its app mode or not void setCursorLine (int newLine); int getLineLength(const int line) const; // returns the width in columns of the specified screen line, // taking DECDWL/DECDHL (double width/height modes) into account. int getScreenLineColumns(const int line) const; // screen image ---------------- int _lines; int _columns; typedef QVector ImageLine; // [0..columns] QVector _screenLines; // [lines] int _screenLinesSize; // _screenLines.size() int _scrolledLines; QRect _lastScrolledRegion; int _droppedLines; int _oldTotalLines; bool _isResize; bool _enableReflowLines = true;//自动换行功能,默认为true QVarLengthArray _lineProperties; // history buffer --------------- HistoryScroll* _history; // cursor location int _cuX; int _cuY; // cursor color and rendition info CharacterColor _currentForeground; CharacterColor _currentBackground; quint8 _currentRendition; // margins ---------------- int _topMargin; int _bottomMargin; // states ---------------- bool _currentModes[MODES_SCREEN]; bool _savedModes[MODES_SCREEN]; // ---------------------------- QBitArray _tabStops; // selection ------------------- int _selBegin; // The first location selected. int _selTopLeft; // TopLeft Location. int _selBottomRight; // Bottom Right Location. bool _blockSelectionMode; // Column selection mode // effective colors and rendition ------------ CharacterColor _effectiveForeground; // These are derived from CharacterColor _effectiveBackground; // the cu_* variables above quint8 _effectiveRendition; // to speed up operation class SavedState { public: SavedState() : cursorColumn(0),cursorLine(0),rendition(0) {} int cursorColumn; int cursorLine; quint8 rendition; CharacterColor foreground; CharacterColor background; }; SavedState _savedState; // last position where we added a character int _lastPos; // used in REP (repeating char) quint32 _lastDrawnChar; EscapeSequenceUrlExtractor *_escapeSequenceUrlExtractor; //when we handle scroll commands, we need to know which screenwindow will scroll TerminalDisplay *_currentTerminalDisplay; //用于标识Session int _sessionId; // Vt102Emulation defined max argument value that can be passed to a Screen function const int MAX_SCREEN_ARGUMENT = 40960; }; } #endif // SCREEN_H deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/ScreenWindow.cpp000066400000000000000000000172421475472654300263060ustar00rootroot00000000000000/* Copyright (C) 2007 by Robert Knight 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. */ // Own #include "ScreenWindow.h" // Qt #include using namespace Konsole; ScreenWindow::ScreenWindow(QObject* parent) : QObject(parent) , _screen(nullptr) , _windowBuffer(nullptr) , _windowBufferSize(0) , _bufferNeedsUpdate(true) , _windowLines(1) , _currentLine(0) , _trackOutput(true) , _scrollCount(0) { } ScreenWindow::~ScreenWindow() { delete[] _windowBuffer; } void ScreenWindow::setScreen(Screen* screen) { Q_ASSERT( screen ); _screen = screen; } Screen* ScreenWindow::screen() const { return _screen; } Character* ScreenWindow::getImage() { // reallocate internal buffer if the window size has changed int size = windowLines() * windowColumns(); if (_windowBuffer == nullptr || _windowBufferSize != size) { delete[] _windowBuffer; _windowBufferSize = size; _windowBuffer = new Character[size]; _bufferNeedsUpdate = true; } if (!_bufferNeedsUpdate) return _windowBuffer; _screen->getImage(_windowBuffer,size, currentLine(),endWindowLine()); // 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(); _bufferNeedsUpdate = false; return _windowBuffer; } void ScreenWindow::fillUnusedArea() { int screenEndLine = _screen->getHistLines() + _screen->getLines() - 1; int windowEndLine = currentLine() + windowLines() - 1; int unusedLines = windowEndLine - screenEndLine; int charsToFill = unusedLines * windowColumns(); Screen::fillWithDefaultChar(_windowBuffer + _windowBufferSize - charsToFill,charsToFill); } // 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. // // when passing a line number to a Screen method, the line number should // never be more than endWindowLine() // int ScreenWindow::endWindowLine() const { return qMin(currentLine() + windowLines() - 1, lineCount() - 1); } QVector ScreenWindow::getLineProperties() { QVector result = _screen->getLineProperties(currentLine(),endWindowLine()); if (result.count() != windowLines()) result.resize(windowLines()); return result; } QString ScreenWindow::selectedText( const Screen::DecodingOptions options ) const { return _screen->selectedText( options ); } void ScreenWindow::getSelectionStart( int& column , int& line ) { _screen->getSelectionStart(column,line); line -= currentLine(); } void ScreenWindow::getSelectionEnd( int& column , int& line ) { _screen->getSelectionEnd(column,line); line -= currentLine(); } void ScreenWindow::setSelectionStart( int column , int line , bool columnMode ) { _screen->setSelectionStart( column , qMin(line + currentLine(),endWindowLine()) , columnMode); _bufferNeedsUpdate = true; emit selectionChanged(); } void ScreenWindow::setSelectionEnd( int column , int line ) { _screen->setSelectionEnd( column , qMin(line + currentLine(),endWindowLine()) ); _bufferNeedsUpdate = true; emit selectionChanged(); } /******************************************************************** 1. @函数: setSelectionAll 2. @作者: 王培利 3. @日期: 2020-02-13 4. @说明: 屏幕全选功能 ********************************************************************/ void ScreenWindow::setSelectionAll() { _screen->setSelectionAll(); _bufferNeedsUpdate = true; emit selectionChanged(); } bool ScreenWindow::isSelected(int column, int line) { return _screen->isSelected(column, qMin(line + currentLine(), endWindowLine())); } void ScreenWindow::clearSelection() { _screen->clearSelection(); emit selectionChanged(); emit selectionCleared(); } void ScreenWindow::setWindowLines(int lines) { Q_ASSERT(lines > 0); _windowLines = lines; } int ScreenWindow::windowLines() const { return _windowLines; } int ScreenWindow::windowColumns() const { return _screen->getColumns(); } int ScreenWindow::lineCount() const { return _screen->getHistLines() + _screen->getLines(); } int ScreenWindow::columnCount() const { return _screen->getColumns(); } QPoint ScreenWindow::cursorPosition() const { QPoint position; position.setX( _screen->getCursorX() ); position.setY( _screen->getCursorY() ); return position; } int ScreenWindow::currentLine() const { return qBound(0,_currentLine,lineCount()-windowLines()); } void ScreenWindow::scrollBy( RelativeScrollMode mode , int amount ) { if ( mode == ScrollLines ) { scrollTo( currentLine() + amount ); } else if ( mode == ScrollPages ) { scrollTo( currentLine() + amount * ( windowLines() / 2 ) ); } } bool ScreenWindow::atEndOfOutput() const { return currentLine() == (lineCount()-windowLines()); } void ScreenWindow::scrollTo( int line ) { int maxCurrentLineNumber = lineCount() - windowLines(); line = qBound(0,line,maxCurrentLineNumber); const int delta = line - _currentLine; _currentLine = line; // keep track of number of lines scrolled by, // this can be reset by calling resetScrollCount() _scrollCount += delta; _bufferNeedsUpdate = true; emit scrolled(_currentLine); } void ScreenWindow::setTrackOutput(bool trackOutput) { _trackOutput = trackOutput; } bool ScreenWindow::trackOutput() const { return _trackOutput; } int ScreenWindow::scrollCount() const { return _scrollCount; } void ScreenWindow::resetScrollCount() { _scrollCount = 0; } QRect ScreenWindow::scrollRegion() const { bool equalToScreenSize = windowLines() == _screen->getLines(); if ( atEndOfOutput() && equalToScreenSize ) return _screen->lastScrolledRegion(); else return {0,0,windowColumns(),windowLines()}; } 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 // 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 // be adjusted - otherwise the output will scroll _currentLine = qMax(0,_currentLine - _screen->droppedLines()); // ensure that the screen window's current position does // not go beyond the bottom of the screen _currentLine = qMin( _currentLine , _screen->getHistLines() ); } _bufferNeedsUpdate = true; emit outputChanged(); } //#include "ScreenWindow.moc" deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/ScreenWindow.h000066400000000000000000000215351475472654300257530ustar00rootroot00000000000000/* Copyright 2007-2008 by Robert Knight 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. */ #ifndef SCREENWINDOW_H #define SCREENWINDOW_H // Qt #include #include #include // Konsole #include "Character.h" #include "Screen.h" namespace Konsole { 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 * in response to mouse or keyboard input. * * A new ScreenWindow for a terminal session can be created by calling Emulation::createWindow() * * Use the scrollTo() method to scroll the window up and down on the screen. * Use the getImage() method to retrieve the character image which is currently visible in the window. * * setTrackOutput() controls whether the window moves to the bottom of the associated screen when new * lines are added to it. * * Whenever the output from the underlying screen is changed, the notifyOutputChanged() slot should * be called. This in turn will update the window's position and emit the outputChanged() signal * if necessary. */ 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(). * * You should not call this constructor directly, instead use the Emulation::createWindow() method * to create a window on the emulation which you wish to view. This allows the emulation * to notify the window when the associated screen has changed and synchronize selection updates * between all views on a session. */ explicit ScreenWindow(QObject* parent = nullptr); ~ScreenWindow() override; /** Sets the screen which this window looks onto */ void setScreen(Screen* screen); /** 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. * * The returned buffer is managed by the ScreenWindow instance and does not need to be * deleted by the caller. */ Character* getImage(); /** * Returns the line attributes associated with the lines of characters which * are currently visible through this window */ QVector getLineProperties(); /** * 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 * 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. */ int scrollCount() const; /** * Resets the count of scrolled lines returned by scrollCount() */ void resetScrollCount(); /** * 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, * but allows views to optimize rendering. */ QRect scrollRegion() const; /** * 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 ); /** * Sets the end of the selection to the given @p line and @p column within * the window. */ void setSelectionEnd( int column , int line ); /******** Modify by n014361 wangpeili 2020-02-13: 新增屏幕全选功能***********×****/ void setSelectionAll(); /***************** Modify by n014361 End *************************/ /** * Retrieves the start of the selection within the window. */ void getSelectionStart( int& column , int& line ); /** * Retrieves the end of the selection within the window. */ void getSelectionEnd( int& column , int& line ); /** * 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(); /** Sets the number of lines in the window */ void setWindowLines(int lines); /** Returns the number of lines in the window */ 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 */ int columnCount() const; /** Returns the index of the line which is currently at the top of this window */ int currentLine() const; /** * 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. */ bool atEndOfOutput() const; /** Scrolls the window so that @p line is at the top of the window */ void scrollTo( int line ); /** Describes the units which scrollBy() moves the window by. */ enum RelativeScrollMode { /** 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. * @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 * 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() */ bool trackOutput() const; /** * Returns the text which is currently selected. * * @param preserveLineBreaks See Screen::selectedText() */ QString selectedText( const Screen::DecodingOptions options ) 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. */ void notifyOutputChanged(); signals: /** * 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); /** Emitted when the selection is changed. */ void selectionChanged(); /** Emitted when the selection is cleared. */ void selectionCleared(); private: int endWindowLine() const; void fillUnusedArea(); Screen* _screen; // see setScreen() , screen() Character* _windowBuffer; int _windowBufferSize; bool _bufferNeedsUpdate; int _windowLines; int _currentLine; // see scrollTo() , currentLine() bool _trackOutput; // see setTrackOutput() , trackOutput() int _scrollCount; // count of lines which the window has been scrolled by since // the last call to resetScrollCount() }; } #endif // SCREENWINDOW_H deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/SearchBar.cpp000066400000000000000000000070501475472654300255250ustar00rootroot00000000000000/* Copyright 2013 Christian Surlykke 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. */ #include #include #include #include #include "SearchBar.h" 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("Highlight all matches")); m_highlightMatchesMenuEntry->setCheckable(true); m_highlightMatchesMenuEntry->setChecked(true); connect(m_highlightMatchesMenuEntry, SIGNAL(toggled(bool)), this, SIGNAL(highlightMatchesChanged(bool))); } SearchBar::~SearchBar() { } QString SearchBar::searchText() { return widget.searchTextEdit->text(); } bool SearchBar::useRegularExpression() { return m_useRegularExpressionMenuEntry->isChecked(); } bool SearchBar::matchCase() { return m_matchCaseMenuEntry->isChecked(); } bool SearchBar::highlightAllMatches() { return m_highlightMatchesMenuEntry->isChecked(); } void SearchBar::show() { QWidget::show(); widget.searchTextEdit->setFocus(); } void SearchBar::noMatchFound() { QPalette palette; palette.setColor(widget.searchTextEdit->backgroundRole(), QColor(255, 128, 128)); widget.searchTextEdit->setPalette(palette); } void SearchBar::keyReleaseEvent(QKeyEvent* keyEvent) { if (keyEvent->key() == Qt::Key_Return || keyEvent->key() == Qt::Key_Enter) { if (keyEvent->modifiers() == Qt::ShiftModifier) { Q_EMIT findPrevious(); } else { Q_EMIT findNext(); } } else if (keyEvent->key() == Qt::Key_Escape) { hide(); } } void SearchBar::clearBackgroundColor() { QPalette p; p.setColor(QPalette::Base, Qt::white); widget.searchTextEdit->setPalette(p); } deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/SearchBar.h000066400000000000000000000031551475472654300251740ustar00rootroot00000000000000/* Copyright 2013 Christian Surlykke 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. */ #ifndef _SEARCHBAR_H #define _SEARCHBAR_H #include #include "ui_SearchBar.h" #include "HistorySearch.h" class SearchBar : public QWidget { Q_OBJECT public: SearchBar(QWidget* parent = nullptr); virtual ~SearchBar(); virtual void show(); QString searchText(); bool useRegularExpression(); bool matchCase(); bool highlightAllMatches(); public slots: void noMatchFound(); signals: void searchCriteriaChanged(); void highlightMatchesChanged(bool highlightMatches); void findNext(); void findPrevious(); protected: virtual void keyReleaseEvent(QKeyEvent* keyEvent); private slots: void clearBackgroundColor(); private: Ui::SearchBar widget; QAction *m_matchCaseMenuEntry; QAction *m_useRegularExpressionMenuEntry; QAction *m_highlightMatchesMenuEntry; }; #endif /* _SEARCHBAR_H */ deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/SearchBar.ui000066400000000000000000000035121475472654300253570ustar00rootroot00000000000000 SearchBar 0 0 399 40 SearchBar X Find: < > ... QToolButton::InstantPopup deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/Session.cpp000066400000000000000000001173531475472654300253260ustar00rootroot00000000000000/* This file is part of Konsole Copyright (C) 2006-2007 by Robert Knight Copyright (C) 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 (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. Rewritten for QT4 by e_k , Copyright (C)2008 */ // Own #include "Session.h" // Standard #include // Qt #include #include #include #include #include #include #include #include #include "Pty.h" #include "ProcessInfo.h" //#include "kptyprocess.h" #include "TerminalDisplay.h" #include "ShellCommand.h" #include "Vt102Emulation.h" using namespace Konsole; int Session::lastSessionId = 0; Session::Session(QObject* parent) : QObject(parent), _shellProcess(nullptr) , _emulation(nullptr) , _monitorActivity(false) , _monitorSilence(false) , _notifiedActivity(false) , _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 // printed to the terminal. Likely a problem in KPty::logout() // or KPty::login() which uses a QProcess to start /usr/bin/utempter , _flowControl(true) , _fullScripting(false) , _sessionId(0) , _sessionProcessInfo(nullptr) , _foregroundProcessInfo(nullptr) // , _zmodemBusy(false) // , _zmodemProc(0) // , _zmodemProgress(0) , _hasDarkBackground(false) , _isPrimaryScreen(true) { //prepare DBus communication // new SessionAdaptor(this); _sessionId = ++lastSessionId; // QDBusConnection::sessionBus().registerObject(QLatin1String("/Sessions/")+QString::number(_sessionId), this); //create teletype for I/O with shell process _shellProcess = new Pty(); _shellProcess->setSessionId(_sessionId); ptySlaveFd = _shellProcess->pty()->slaveFd(); //create emulation backend _emulation = new Vt102Emulation(); _emulation->setSessionId(_sessionId); connect( _emulation, SIGNAL( titleChanged( int, const QString & ) ), this, SLOT( setUserTitle( int, const QString & ) ) ); connect( _emulation, SIGNAL( stateSet(int) ), this, SLOT( activityStateSet(int) ) ); // connect( _emulation, SIGNAL( zmodemDetected() ), this , // SLOT( fireZModemDetected() ) ); connect( _emulation, SIGNAL( changeTabTextColorRequest( int ) ), this, SIGNAL( changeTabTextColorRequest( int ) ) ); connect( _emulation, SIGNAL(profileChangeCommandReceived(const QString &)), this, SIGNAL( profileChangeCommandReceived(const QString &)) ); connect(_emulation, &Konsole::Emulation::primaryScreenInUse, this, &Session::onPrimaryScreenInUse); 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()); connect( _shellProcess,SIGNAL(receivedData(const char *,int,bool)),this, SLOT(onReceiveBlock(const char *,int,bool)) ); connect( _emulation,SIGNAL(sendData(const char *,int,const QTextCodec *)),_shellProcess, SLOT(sendData(const char *,int,const QTextCodec *)) ); connect( _emulation,SIGNAL(lockPtyRequest(bool)),_shellProcess,SLOT(lockPty(bool)) ); connect( _emulation,SIGNAL(useUtf8Request(bool)),_shellProcess,SLOT(setUtf8Mode(bool)) ); connect( _shellProcess,SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(done(int)) ); // not in kprocess anymore connect( _shellProcess,SIGNAL(done(int)), this, SLOT(done(int)) ); /******** Modify by nt001000 renfeixiang 2020-05-27:修改 增加参数区别remove和purge卸载命令 Begin***************/ // 用于卸载终端弹出框提示 connect( _shellProcess,SIGNAL(ptyUninstallTerminal(QString)), this, SIGNAL(sessionUninstallTerminal(QString)) ); /******** Modify by nt001000 renfeixiang 2020-05-27:修改 增加参数区别remove和purge卸载命令 Begin***************/ //setup timer for monitoring session activity _monitorTimer = new QTimer(this); _monitorTimer->setSingleShot(true); connect(_monitorTimer, SIGNAL(timeout()), this, SLOT(monitorTimerDone())); // 定时更新term信息 => 目前为了更新标签标题信息 _updateTimer = new QTimer(this); connect(_updateTimer, &QTimer::timeout, this, &Session::onUpdateTitleArgs); _updateTimer->start(500); } WId Session::windowId() const { // 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) { _hasDarkBackground = darkBackground; } bool Session::hasDarkBackground() const { return _hasDarkBackground; } bool Session::isRunning() const { return _shellProcess->state() == QProcess::Running; } void Session::setCodec(QTextCodec * codec) { emulation()->setCodec(codec); } void Session::setProgram(const QString & program) { _program = ShellCommand::expand(program); if (_program.endsWith(QStringLiteral("/dash")) || _program.endsWith(QStringLiteral("/sh"))) { _updateTimer->setInterval(10); //用于更改updateTimer的时间间隔,防止CPU占用太高 QTimer *monitorUpdateTimer = new QTimer(this); monitorUpdateTimer->setSingleShot(true); monitorUpdateTimer->start(500); connect(monitorUpdateTimer, &QTimer::timeout, this, [this] { if (_updateTimer->interval() < 500) { _updateTimer->setInterval(500); } }); } } void Session::setInitialWorkingDirectory(const QString & dir) { _initialWorkingDir = ShellCommand::expand(dir); } void Session::setArguments(const QStringList & arguments) { _arguments = ShellCommand::expand(arguments); } QList Session::views() const { return _views; } void Session::addView(TerminalDisplay * widget) { Q_ASSERT( !_views.contains(widget) ); _views.append(widget); if ( _emulation != nullptr ) { // connect emulation - view signals and slots connect( widget , SIGNAL(keyPressedSignal(QKeyEvent *)) , _emulation , SLOT(sendKeyEvent(QKeyEvent *)) ); connect( widget , SIGNAL(mouseSignal(int,int,int,int)) , _emulation , SLOT(sendMouseEvent(int,int,int,int)) ); // 先判断是否有远程连接,若有,则连接远程 // connect(widget, SIGNAL(sendStringToEmu(const char *)), _emulation, SLOT(sendString(const char *))); // allow emulation to notify view when the foreground process // indicates whether or not it is interested in mouse signals connect( _emulation , SIGNAL(programUsesMouseChanged(bool)) , widget , SLOT(setUsesMouse(bool)) ); connect( _emulation , &Konsole::Emulation::enableAlternateScrolling, widget, &Konsole::TerminalDisplay::setAlternateScrolling); widget->setUsesMouse( _emulation->programUsesMouse() ); connect( _emulation , SIGNAL(programBracketedPasteModeChanged(bool)) , widget , SLOT(setBracketedPasteMode(bool)) ); widget->setBracketedPasteMode(_emulation->programBracketedPasteMode()); widget->setScreenWindow(_emulation->createWindow()); } //connect view signals and slots QObject::connect( widget ,SIGNAL(changedContentSizeSignal(int,int)),this, SLOT(onViewSizeChange(int,int))); QObject::connect( widget ,SIGNAL(destroyed(QObject *)) , this , SLOT(viewDestroyed(QObject *)) ); //slot for close QObject::connect(this, SIGNAL(finished()), widget, SLOT(close())); } void Session::viewDestroyed(QObject * view) { TerminalDisplay * display = (TerminalDisplay *)view; Q_ASSERT( _views.contains(display) ); removeView(display); } /******************************************************************************* 1. @函数: onUpdateTitleArgs 2. @作者: ut000610 戴正文 3. @日期: 2020-12-02 4. @说明: 更新标签标题参数 *******************************************************************************/ void Session::onUpdateTitleArgs() { ProcessInfo *process = getProcessInfo(); // format tab titles using process info bool ok = false; // 用户名 %u QString userName = process->userName(); if (_userName != userName) { _userName = userName; emit titleArgsChange(QLatin1String("%u"), _userName); } //title.replace(QLatin1String("%h"), Konsole::ProcessInfo::localHost()); // 程序名 %n QString programName = process->name(&ok); if (_programName != programName) { _programName = programName; emit titleArgsChange(QLatin1String("%n"), _programName); } // 获取当前目录 %D QString dir = _reportedWorkingUrl.toLocalFile(); ok = true; if (dir.isEmpty()) { // update current directory from process updateWorkingDirectory(); // Previous process may have been freed in updateSessionProcessInfo() process = getProcessInfo(); dir = process->currentDir(&ok); } if (_currentDir != dir) { _currentDir = dir; emit titleArgsChange(QLatin1String("%D"), _currentDir); } } void Session::onPrimaryScreenInUse(bool use) { _isPrimaryScreen = use; emit primaryScreenInUse(use); } void Session::removeView(TerminalDisplay *widget) { _views.removeAll(widget); disconnect(widget,nullptr,this,nullptr); if ( _emulation != nullptr ) { // disconnect // - key presses signals from widget // - mouse activity signals from widget // - string sending signals from widget // // ... and any other signals connected in addView() disconnect( widget, nullptr, _emulation, nullptr); // disconnect state change signals emitted by emulation disconnect( _emulation , nullptr , widget , nullptr); } // close the session automatically when the last view is removed if ( _views.count() == 0 ) { close(); } } void Session::run() { // 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 = 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. QString programPath = exec; if (exec.startsWith(QLatin1Char('/')) || exec.isEmpty()) { const QString defaultShell{QLatin1String("/bin/bash")}; QFile excheck(exec); #if 0 // 下一期优化 // exec是空的,或者文件不存在,则替换exec为$SHELL if (exec.isEmpty() || !excheck.exists()) { exec = QString::fromLocal8Bit(qgetenv("SHELL")); } excheck.setFileName(exec); #endif // SHELL是空的,或者文件不存在,则替换exec为/bin/sh if (exec.isEmpty() || !excheck.exists()) { qWarning() << "Neither default shell nor $SHELL is set to a correct path. Fallback to" << defaultShell; exec = defaultShell; } } if (programPath != exec) { // 说明有文件不存在,取最后找到的文件进行替换 emit shellWarningMessage(exec, true); } // _arguments sometimes contain ("") so isEmpty() // or count() does not work as expected... QString argsTmp(_arguments.join(QLatin1Char(' ')).trimmed()); QStringList arguments; arguments << exec; if (argsTmp.length()) arguments << _arguments; if (!_initialWorkingDir.isEmpty() && QDir(_initialWorkingDir).exists()) { _shellProcess->setWorkingDirectory(_initialWorkingDir); } else { _shellProcess->setWorkingDirectory(QDir::homePath()); } _shellProcess->setFlowControlEnabled(_flowControl); _shellProcess->setErase(_emulation->eraseChar()); // this is not strictly accurate use of the COLORFGBG variable. This does not // 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 // fix bug#39147 终端使用vim编辑脚本,命令行终端的主题为跟随系统时无法清楚查看脚本内容 // 移除该环境变量,因为终端的主题颜色会实时变化,不能通过设置环境变量的方式 //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 * However this works on Arch and FreeBSD now. */ int result = _shellProcess->start(exec, arguments, _environment,// << backgroundColorHint, windowId(), _addToUtmp); if (result < 0) { //qDebug() << "CRASHED! result: " << result<errorString(); processError = processError.mid(processError.indexOf(":") + 1).trimmed(); if(!processError.isEmpty()) processError = "(" +processError + ")"; QString infoText = QString("There was an error creating the child process for this terminal. \n" "Failed to execute child process \"%1\"%2!") .arg(exec) .arg(processError); sendText(infoText); _userTitle = QString::fromLatin1("Session crashed"); emit titleChanged(); emit shellWarningMessage(exec, false); qWarning() << _shellProcess->errorString(); return; } _shellProcess->setWriteable(false); // We are reachable via kwrited. 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(); } void Session::setUserTitle( int what, const QString & caption ) { //set to true if anything is actually changed (eg. old _nameTitle != new _nameTitle ) bool modified = false; // (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; } } if ((what == 0) || (what == 1)) { _isTitleChanged = true; if ( _iconText != caption ) { _iconText = caption; modified = true; } } if (what == 11) { 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) { _modifiedBackground = backColor; // bail out here until the code to connect the terminal display // to the changeBackgroundColor() signal has been written // and tested - just so we don't forget to do this. Q_ASSERT( 0 ); emit changeBackgroundColorRequest(backColor); } } } if (what == 30) { _isTitleChanged = true; if ( _nameTitle != caption ) { setTitle(Session::NameRole,caption); return; } } if (what == 31) { QString cwd=caption; 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; modified = true; } } if (what == 50) { emit profileChangeCommandReceived(caption); return; } if (modified) { // 标签标题变化前更新标签标题参数 onUpdateTitleArgs(); // 标签标题有变化,发送信号通知terminal emit titleChanged(); } } QString Session::userTitle() const { return _userTitle; } void Session::setTabTitleFormat(TabTitleContext context , const QString & format) { if ( context == LocalTabTitle ) { _localTabTitleFormat = format; ProcessInfo *process = getProcessInfo(); process->setUserNameRequired(format.contains(QLatin1String("%u"))); } else if ( context == RemoteTabTitle ) { _remoteTabTitleFormat = format; } } QString Session::tabTitleFormat(TabTitleContext context) const { if ( context == LocalTabTitle ) { return _localTabTitleFormat; } else if ( context == RemoteTabTitle ) { return _remoteTabTitleFormat; } return QString(); } void Session::monitorTimerDone() { //FIXME: The idea here is that the notification popup will appear to tell the user than output from //the terminal has stopped and the popup will disappear when the user activates the session. // //This breaks with the addition of multiple views of a session. The popup should disappear //when any of the views of the session becomes active //FIXME: Make message text for this notification and the activity notification more descriptive. if (_monitorSilence) { emit silence(); emit stateChanged(NOTIFYSILENCE); } else { emit stateChanged(NOTIFYNORMAL); } _notifiedActivity=false; } bool Session::isPrimaryScreen() { return _isPrimaryScreen; } void Session::activityStateSet(int state) { if (state==NOTIFYBELL) { emit bellRequest(QString("Bell in session '%1'").arg(_nameTitle)); } else if (state==NOTIFYACTIVITY) { if (_monitorSilence) { _monitorTimer->start(_silenceSeconds*1000); } if ( _monitorActivity ) { //FIXME: See comments in Session::monitorTimerDone() if (!_notifiedActivity) { _notifiedActivity=true; emit activity(); } } } if ( state==NOTIFYACTIVITY && !_monitorActivity ) { state = NOTIFYNORMAL; } if ( state==NOTIFYSILENCE && !_monitorSilence ) { state = NOTIFYNORMAL; } emit stateChanged(state); } void Session::onViewSizeChange(int height, int width) { updateTerminalSize(height, width); } void Session::onEmulationSizeChange(QSize size) { setSize(size); } void Session::updateTerminalSize(int height, int width) { QListIterator viewIter(_views); int minLines = -1; int minColumns = -1; // minimum number of lines and columns that views require for // their size to be taken into consideration ( to avoid problems // with new view widgets which haven't yet been set to their correct size ) /***mod by ut001121 zhangmeng 20200615 窗口初始化完成之后修改终端显示内容为最小一行 修复BUG32779, BUG32778***/ const int VIEW_LINES_THRESHOLD = (height==1 || width==1) ? 2 : 1; const int VIEW_COLUMNS_THRESHOLD = 2; //select largest number of lines and columns that will fit in all visible views while ( viewIter.hasNext() ) { TerminalDisplay * view = viewIter.next(); if ( view->isHidden() == false && view->lines() >= VIEW_LINES_THRESHOLD && view->columns() >= VIEW_COLUMNS_THRESHOLD ) { minLines = (minLines == -1) ? view->lines() : qMin( minLines , view->lines() ); minColumns = (minColumns == -1) ? view->columns() : qMin( minColumns , view->columns() ); } } // backend emulation must have a _terminal of at least 1 column x 1 line in size if ( minLines > 0 && minColumns > 0 ) { _emulation->setImageSize( minLines , minColumns ); _shellProcess->setWindowSize( minLines , minColumns ); } } void Session::refresh() { // attempt to get the shell process to redraw the display // // this requires the program running in the shell // to cooperate by sending an update in response to // a window size change // // the window size is changed twice, first made slightly larger and then // resized back to its normal size so that there is actually a change // in the window size (some shells do nothing if the // new and old sizes are the same) // // if there is a more 'correct' way to do this, please // send an email with method or patches to konsole-devel@kde.org const QSize existingSize = _shellProcess->windowSize(); _shellProcess->setWindowSize(existingSize.height(),existingSize.width()+1); _shellProcess->setWindowSize(existingSize.height(),existingSize.width()); } bool Session::sendSignal(int signal) { int result = ::kill(static_cast(_shellProcess->processId()),signal); if ( result == 0 ) { _shellProcess->waitForFinished(); return true; } else return false; } void Session::close() { _autoClose = true; _wantedClose = true; if (!_shellProcess->isRunning() || !sendSignal(SIGHUP)) { // Forced close. QTimer::singleShot(1, this, SIGNAL(finished())); } } void Session::sendText(const QString & text) const { //检测到当前命令是代码中通过sendText发给终端的(而不是用户手动输入的命令) bool isSendByRemoteManage = this->property("isSendByRemoteManage").toBool(); if (isSendByRemoteManage) { //将isSendByRemoteManage标记同步给Pty _shellProcess->setProperty("isSendByRemoteManage", QVariant(true)); } _emulation->sendText(text); } void Session::sendKeyEvent(QKeyEvent* e) const { _emulation->sendKeyEvent(e); } Session::~Session() { _wantedClose = true; if(nullptr != _foregroundProcessInfo){ delete _foregroundProcessInfo; } if(nullptr != _sessionProcessInfo){ delete _sessionProcessInfo; } if(nullptr != _emulation){ delete _emulation; } if(nullptr != _shellProcess){ delete _shellProcess; } // delete _zmodemProc; } void Session::setProfileKey(const QString & key) { _profileKey = key; emit profileChanged(key); } QString Session::profileKey() const { return _profileKey; } void Session::done(int exitStatus) { /** 相关说明如下: 1._wantedClose :session是否正常结束,当session.close 或 session.析构时 为true,默认false 2._autoClose :是否自动关闭 由传参控制,当传参含--keep-open 或 含-e 时 为false,默认true 3.当【运行脚本命令-C】且【_autoClose=false】时,命令最后会补上exit,命令结束会触发process.finished-》session.done */ qDebug()<<"done exitStatus:"<exitStatus(); if (_autoClose || _wantedClose) { emit finished(); return; } /************************ Add by sunchengxi 2020-09-15:Bug#42864 无法同时打开多个终端 Begin************************/ if (false == _autoClose && false == _wantedClose && _shellProcess->exitStatus() == QProcess::NormalExit) { qDebug() << "autoClose is false."; emit titleChanged(); emit finished(); return; } /************************ Add by sunchengxi 2020-09-15:Bug#42864 无法同时打开多个终端 End ************************/ if(exitStatus != 0) { QString message; QString infoText; if (exitStatus == -1){ infoText.sprintf("There was an error creating the child process for this terminal. \n" "Failed to execute child process \"%s\"(No such file or directory)!", _program.toUtf8().data()); message = "Session crashed."; } else { infoText.sprintf("The child process exited normally with status %d.", exitStatus); message.sprintf("Session '%s' exited with status %d.", _nameTitle.toUtf8().data(), exitStatus); } _userTitle = message; //sendText(infoText); emit titleChanged(); } } Emulation * Session::emulation() const { return _emulation; } QString Session::keyBindings() const { return _emulation->keyBindings(); } void Session::setBackspaceMode(char *key, int length) { _emulation->setBackspaceMode(key, length); } void Session::setDeleteMode(char *key, int length) { _emulation->setDeleteMode(key, length); } QStringList Session::environment() const { return _environment; } void Session::setEnvironment(const QStringList & environment) { _environment = environment; } int Session::sessionId() const { return _sessionId; } void Session::setKeyBindings(const QString & id) { _emulation->setKeyBindings(id); } void Session::setTitle(TitleRole role , const QString & newTitle) { if ( title(role) != newTitle ) { if ( role == NameRole ) { _nameTitle = newTitle; } else if ( role == DisplayedTitleRole ) { _displayTitle = newTitle; // without these, that title will be overridden by the expansion of // title format shortly after, which will confuses users. _localTabTitleFormat = newTitle; _remoteTabTitleFormat = newTitle; // qDebug() << "curr running process:" << newTitle << endl; } emit titleChanged(); } } QString Session::title(TitleRole role) const { if ( role == NameRole ) { return _nameTitle; } else if ( role == DisplayedTitleRole ) { return _displayTitle; } else { return QString(); } } void Session::setIconName(const QString & iconName) { if ( iconName != _iconName ) { _iconName = iconName; emit titleChanged(); } } void Session::setIconText(const QString & iconText) { _iconText = iconText; //kDebug(1211)<<"Session setIconText " << _iconText; } QString Session::iconName() const { return _iconName; } QString Session::iconText() const { return _iconText; } bool Session::isTitleChanged() const { return _isTitleChanged; } void Session::setHistoryType(const HistoryType & hType) { _emulation->setHistory(hType); } const HistoryType & Session::historyType() const { return _emulation->history(); } void Session::clearHistory() { _emulation->clearHistory(); } QStringList Session::arguments() const { return _arguments; } QString Session::program() const { return _program; } // unused currently bool Session::isMonitorActivity() const { return _monitorActivity; } // unused currently bool Session::isMonitorSilence() const { return _monitorSilence; } void Session::setMonitorActivity(bool _monitor) { _monitorActivity=_monitor; _notifiedActivity=false; activityStateSet(NOTIFYNORMAL); } void Session::setMonitorSilence(bool _monitor) { if (_monitorSilence==_monitor) { return; } _monitorSilence=_monitor; if (_monitorSilence) { _monitorTimer->start(_silenceSeconds*1000); } else { _monitorTimer->stop(); } activityStateSet(NOTIFYNORMAL); } void Session::setMonitorSilenceSeconds(int seconds) { _silenceSeconds=seconds; if (_monitorSilence) { _monitorTimer->start(_silenceSeconds*1000); } } void Session::setAddToUtmp(bool set) { _addToUtmp = set; } void Session::setFlowControlEnabled(bool enabled) { if (_flowControl == enabled) { return; } _flowControl = enabled; if (_shellProcess) { _shellProcess->setFlowControlEnabled(_flowControl); } emit flowControlEnabledChanged(enabled); } bool Session::flowControlEnabled() const { return _flowControl; } //void Session::fireZModemDetected() //{ // if (!_zmodemBusy) // { // QTimer::singleShot(10, this, SIGNAL(zmodemDetected())); // _zmodemBusy = true; // } //} //void Session::cancelZModem() //{ // _shellProcess->sendData("\030\030\030\030", 4); // Abort // _zmodemBusy = false; //} //void Session::startZModem(const QString &zmodem, const QString &dir, const QStringList &list) //{ // _zmodemBusy = true; // _zmodemProc = new KProcess(); // _zmodemProc->setOutputChannelMode( KProcess::SeparateChannels ); // // *_zmodemProc << zmodem << "-v" << list; // // if (!dir.isEmpty()) // _zmodemProc->setWorkingDirectory(dir); // // _zmodemProc->start(); // // connect(_zmodemProc,SIGNAL (readyReadStandardOutput()), // this, SLOT(zmodemReadAndSendBlock())); // connect(_zmodemProc,SIGNAL (readyReadStandardError()), // this, SLOT(zmodemReadStatus())); // connect(_zmodemProc,SIGNAL (finished(int,QProcess::ExitStatus)), // this, SLOT(zmodemFinished())); // // disconnect( _shellProcess,SIGNAL(block_in(const char*,int)), this, SLOT(onReceiveBlock(const char*,int)) ); // connect( _shellProcess,SIGNAL(block_in(const char*,int)), this, SLOT(zmodemRcvBlock(const char*,int)) ); // // _zmodemProgress = new ZModemDialog(QApplication::activeWindow(), false, // i18n("ZModem Progress")); // // connect(_zmodemProgress, SIGNAL(user1Clicked()), // this, SLOT(zmodemDone())); // // _zmodemProgress->show(); //} /*void Session::zmodemReadAndSendBlock() { _zmodemProc->setReadChannel( QProcess::StandardOutput ); QByteArray data = _zmodemProc->readAll(); if ( data.count() == 0 ) return; _shellProcess->sendData(data.constData(),data.count()); } */ /* void Session::zmodemReadStatus() { _zmodemProc->setReadChannel( QProcess::StandardError ); QByteArray msg = _zmodemProc->readAll(); while(!msg.isEmpty()) { int i = msg.indexOf('\015'); int j = msg.indexOf('\012'); QByteArray txt; if ((i != -1) && ((j == -1) || (i < j))) { msg = msg.mid(i+1); } else if (j != -1) { txt = msg.left(j); msg = msg.mid(j+1); } else { txt = msg; msg.truncate(0); } if (!txt.isEmpty()) _zmodemProgress->addProgressText(QString::fromLocal8Bit(txt)); } } */ /* void Session::zmodemRcvBlock(const char *data, int len) { QByteArray ba( data, len ); _zmodemProc->write( ba ); } */ /* void Session::zmodemFinished() { if (_zmodemProc) { delete _zmodemProc; _zmodemProc = 0; _zmodemBusy = false; disconnect( _shellProcess,SIGNAL(block_in(const char*,int)), this ,SLOT(zmodemRcvBlock(const char*,int)) ); connect( _shellProcess,SIGNAL(block_in(const char*,int)), this, SLOT(onReceiveBlock(const char*,int)) ); _shellProcess->sendData("\030\030\030\030", 4); // Abort _shellProcess->sendData("\001\013\n", 3); // Try to get prompt back _zmodemProgress->transferDone(); } } */ void Session::onReceiveBlock(const char * buf, int len, bool isCommandExec) { _emulation->receiveData(buf, len, isCommandExec); emit receivedData( QString::fromLatin1( buf, len ) ); } QSize Session::size() { return _emulation->imageSize(); } void Session::setSize(const QSize & size) { if ((size.width() <= 1) || (size.height() <= 1)) { return; } emit resizeRequest(size); } QString Session::getDynamicProcessName() { bool ok = false; QString processName = getProcessInfo()->name(&ok); if (ok) { return processName; } return QString::fromLocal8Bit(qgetenv("SHELL")); } int Session::getDynamicProcessId() { bool ok = false; int pid = getProcessInfo()->pid(&ok); if (ok) { if (this->isForegroundProcessActive()) { return pid; } } return 0; } void Session::updateWorkingDirectory() { updateSessionProcessInfo(); const QString currentDir = _sessionProcessInfo->validCurrentDir(); if (currentDir != _currentWorkingDir) { _currentWorkingDir = currentDir; emit currentDirectoryChanged(_currentWorkingDir); } } int Session::foregroundProcessId() { int pid; bool ok = false; pid = getProcessInfo()->pid(&ok); if (!ok) { pid = -1; } return pid; } bool Session::isForegroundProcessActive() { // foreground process info is always updated after this return (_shellProcess->processId() != _shellProcess->foregroundProcessGroup()); } QString Session::foregroundProcessName() { QString name; if (updateForegroundProcessInfo()) { bool ok = false; name = _foregroundProcessInfo->name(&ok); if (!ok) { name.clear(); } } return name; } int Session::processId() const { return static_cast(_shellProcess->processId()); } ProcessInfo *Session::getProcessInfo() { ProcessInfo *process = nullptr; if (isForegroundProcessActive() && updateForegroundProcessInfo()) { process = _foregroundProcessInfo; } else { updateSessionProcessInfo(); process = _sessionProcessInfo; } return process; } void Session::updateSessionProcessInfo() { Q_ASSERT(_shellProcess); bool ok; // The checking for pid changing looks stupid, but it is needed // at the moment to workaround the problem that processId() might // return 0 if ((_sessionProcessInfo == nullptr) || (processId() != 0 && processId() != _sessionProcessInfo->pid(&ok))) { delete _sessionProcessInfo; _sessionProcessInfo = ProcessInfo::newInstance(processId(), tabTitleFormat(Session::LocalTabTitle)); _sessionProcessInfo->setUserHomeDir(); } _sessionProcessInfo->update(); } bool Session::updateForegroundProcessInfo() { Q_ASSERT(_shellProcess); const int foregroundPid = _shellProcess->foregroundProcessGroup(); if (foregroundPid != _foregroundPid) { if(nullptr != _foregroundProcessInfo){ delete _foregroundProcessInfo; } _foregroundProcessInfo = ProcessInfo::newInstance(foregroundPid, tabTitleFormat(Session::LocalTabTitle)); _foregroundPid = foregroundPid; } if (_foregroundProcessInfo != nullptr) { _foregroundProcessInfo->update(); return _foregroundProcessInfo->isValid(); } else { return false; } } int Session::getPtySlaveFd() const { return ptySlaveFd; } /******************************************************************************* 1. @函数: getEraseChar 2. @作者: ut000610 戴正文 3. @日期: 2020-06-02 4. @说明: 获取tty的erase的字符 *******************************************************************************/ char Session::getEraseChar() { return _shellProcess->erase(); } SessionGroup::SessionGroup() : _masterMode(0) { } SessionGroup::~SessionGroup() { // disconnect all connectAll(false); } int SessionGroup::masterMode() const { return _masterMode; } QList SessionGroup::sessions() const { return _sessions.keys(); } bool SessionGroup::masterStatus(Session * session) const { return _sessions[session]; } void SessionGroup::addSession(Session * session) { _sessions.insert(session,false); QListIterator masterIter(masters()); while ( masterIter.hasNext() ) { connectPair(masterIter.next(),session); } } void SessionGroup::removeSession(Session * session) { setMasterStatus(session,false); QListIterator masterIter(masters()); while ( masterIter.hasNext() ) { disconnectPair(masterIter.next(),session); } _sessions.remove(session); } void SessionGroup::setMasterMode(int mode) { _masterMode = mode; connectAll(false); connectAll(true); } QList SessionGroup::masters() const { return _sessions.keys(true); } void SessionGroup::connectAll(bool connect) { QListIterator masterIter(masters()); while ( masterIter.hasNext() ) { Session * master = masterIter.next(); QListIterator otherIter(_sessions.keys()); while ( otherIter.hasNext() ) { Session * other = otherIter.next(); if ( other != master ) { if ( connect ) { connectPair(master,other); } else { disconnectPair(master,other); } } } } } void SessionGroup::setMasterStatus(Session * session, bool master) { bool wasMaster = _sessions[session]; _sessions[session] = master; if ((!wasMaster && !master) || (wasMaster && master)) { return; } QListIterator iter(_sessions.keys()); while (iter.hasNext()) { Session * other = iter.next(); if (other != session) { if (master) { connectPair(session, other); } else { disconnectPair(session, other); } } } } void SessionGroup::connectPair(Session * master , Session * other) { // qDebug() << k_funcinfo; if ( _masterMode & CopyInputToAll ) { qDebug() << "Connection session " << master->nameTitle() << "to" << other->nameTitle(); connect( master->emulation() , SIGNAL(sendData(const char *, int, const QTextCodec *)) , other->emulation() , SLOT(sendString(const char *, int, const QTextCodec *)) ); } } void SessionGroup::disconnectPair(Session * master , Session * other) { // qDebug() << k_funcinfo; if ( _masterMode & CopyInputToAll ) { qDebug() << "Disconnecting session " << master->nameTitle() << "from" << other->nameTitle(); disconnect( master->emulation() , SIGNAL(sendData(const char *, int, const QTextCodec *)) , other->emulation() , SLOT(sendString(const char *, int, const QTextCodec *)) ); } } //#include "moc_Session.cpp" deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/Session.h000066400000000000000000000553471475472654300247770ustar00rootroot00000000000000/* This file is part of Konsole, an X terminal. Copyright (C) 2007 by Robert Knight Copyright (C) 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 (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. Rewritten for QT4 by e_k , Copyright (C)2008 */ #ifndef SESSION_H #define SESSION_H #include #include #include "Emulation.h" #include "history/HistoryType.h" #include "history/HistoryScrollNone.h" class KProcess; namespace Konsole { class Emulation; class Pty; class TerminalDisplay; class ProcessInfo; //class ZModemDialog; /** * Represents a terminal session consisting of a pseudo-teletype and a terminal emulation. * The pseudo-teletype (or PTY) handles I/O between the terminal process and Konsole. * The terminal emulation ( Emulation and subclasses ) processes the output stream from the * PTY and produces a character image which is then shown on views connected to the session. * * Each Session can be connected to one or more views by using the addView() method. * The attached views can then display output from the program running in the terminal * or send input to the program in the terminal in the form of keypresses and mouse * activity. */ class Session : public QObject { Q_OBJECT public: Q_PROPERTY(QString name READ nameTitle) Q_PROPERTY(int processId READ processId) Q_PROPERTY(QString keyBindings READ keyBindings WRITE setKeyBindings) Q_PROPERTY(QSize size READ size WRITE setSize) /** * Constructs a new session. * * To start the terminal process, call the run() method, * after specifying the program and arguments * using setProgram() and setArguments() * * If no program or arguments are specified explicitly, the Session * falls back to using the program specified in the SHELL environment * variable. */ Session(QObject* parent = nullptr); ~Session() override; /** * Returns true if the session is currently running. This will be true * after run() has been called successfully. */ bool isRunning() const; /** * Sets the profile associated with this session. * * @param profileKey A key which can be used to obtain the current * profile settings from the SessionManager */ void setProfileKey(const QString & profileKey); /** * Returns the profile key associated with this session. * This can be passed to the SessionManager to obtain the current * profile settings. */ QString profileKey() const; /** * Adds a new view for this session. * * The viewing widget will display the output from the terminal and * input from the viewing widget (key presses, mouse activity etc.) * will be sent to the terminal. * * Views can be removed using removeView(). The session is automatically * closed when the last view is removed. */ void addView(TerminalDisplay * widget); /** * Removes a view from this session. When the last view is removed, * the session will be closed automatically. * * @p widget will no longer display output from or send input * to the terminal */ void removeView(TerminalDisplay * widget); /** * Returns the views connected to this session */ QList views() const; /** * Returns the terminal emulation instance being used to encode / decode * characters to / from the process. */ Emulation * emulation() const; /** * Returns the environment of this session as a list of strings like * VARIABLE=VALUE */ QStringList environment() const; /** * Sets the environment for this session. * @p environment should be a list of strings like * VARIABLE=VALUE */ void setEnvironment(const QStringList & environment); /** Returns the unique ID for this session. */ int sessionId() const; /** * Return the session title set by the user (ie. the program running * in the terminal), or an empty string if the user has not set a custom title */ QString userTitle() const; /** * This enum describes the contexts for which separate * tab title formats may be specified. */ enum TabTitleContext { /** Default tab title format */ LocalTabTitle, /** * Tab title format used session currently contains * a connection to a remote computer (via SSH) */ RemoteTabTitle }; /** * Sets the format used by this session for tab titles. * * @param context The context whoose format should be set. * @param format The tab title format. This may be a mixture * of plain text and dynamic elements denoted by a '%' character * followed by a letter. (eg. %d for directory). The dynamic * elements available depend on the @p context */ void setTabTitleFormat(TabTitleContext context , const QString & format); /** Returns the format used by this session for tab titles. */ QString tabTitleFormat(TabTitleContext context) const; /** Returns the arguments passed to the shell process when run() is called. */ QStringList arguments() const; /** Returns the program name of the shell process started when run() is called. */ QString program() const; /** * Sets the command line arguments which the session's program will be passed when * run() is called. */ void setArguments(const QStringList & arguments); /** Sets the program to be executed when run() is called. */ void setProgram(const QString & program); /** Returns the session's current working directory. */ QString initialWorkingDirectory() { return _initialWorkingDir; } /** * Sets the initial working directory for the session when it is run * This has no effect once the session has been started. */ void setInitialWorkingDirectory( const QString & dir ); /** * Sets the type of history store used by this session. * Lines of output produced by the terminal are added * to the history store. The type of history store * used affects the number of lines which can be * remembered before they are lost and the storage * (in memory, on-disk etc.) used. */ void setHistoryType(const HistoryType & type); /** * Returns the type of history store used by this session. */ const HistoryType & historyType() const; /** * Clears the history store used by this session. */ void clearHistory(); /** * Enables monitoring for activity in the session. * This will cause notifySessionState() to be emitted * with the NOTIFYACTIVITY state flag when output is * received from the terminal. */ void setMonitorActivity(bool); /** Returns true if monitoring for activity is enabled. */ bool isMonitorActivity() const; /** * Enables monitoring for silence in the session. * This will cause notifySessionState() to be emitted * with the NOTIFYSILENCE state flag when output is not * received from the terminal for a certain period of * time, specified with setMonitorSilenceSeconds() */ void setMonitorSilence(bool); /** * Returns true if monitoring for inactivity (silence) * in the session is enabled. */ bool isMonitorSilence() const; /** See setMonitorSilence() */ void setMonitorSilenceSeconds(int seconds); /** * Sets the key bindings used by this session. The bindings * specify how input key sequences are translated into * the character stream which is sent to the terminal. * * @param id The name of the key bindings to use. The * names of available key bindings can be determined using the * KeyboardTranslatorManager class. */ void setKeyBindings(const QString & id); /** Returns the name of the key bindings used by this session. */ QString keyBindings() const; /******** Modify by ut000610 daizhengwen 2020-06-02: 设置删除和退格按钮****************/ void setBackspaceMode(char *key, int length); void setDeleteMode(char *key, int length); /********************* Modify by ut000610 daizhengwen End ************************/ /** * This enum describes the available title roles. */ enum TitleRole { /** The name of the session. */ NameRole, /** The title of the session which is displayed in tabs etc. */ DisplayedTitleRole }; /** Sets the session's title for the specified @p role to @p title. */ void setTitle(TitleRole role , const QString & title); /** Returns the session's title for the specified @p role. */ QString title(TitleRole role) const; /** Convenience method used to read the name property. Returns title(Session::NameRole). */ QString nameTitle() const { return title(Session::NameRole); } /** Sets the name of the icon associated with this session. */ void setIconName(const QString & iconName); /** Returns the name of the icon associated with this session. */ QString iconName() const; /** Sets the text of the icon associated with this session. */ void setIconText(const QString & iconText); /** 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); /** Sends the specified @p signal to the terminal process. */ bool sendSignal(int signal); /** * Specifies whether to close the session automatically when the terminal * process terminates. */ void setAutoClose(bool b) { _autoClose = b; } /** * Sets whether flow control is enabled for this terminal * session. */ void setFlowControlEnabled(bool enabled); /** Returns whether flow control is enabled for this terminal session. */ bool flowControlEnabled() const; /** * Sends @p text to the current foreground terminal program. */ void sendText(const QString & text) const; void sendKeyEvent(QKeyEvent* e) const; /** Returns dynamic process name. */ QString getDynamicProcessName(); /** Returns dynamic process id */ int getDynamicProcessId(); /** * Returns the process id of the terminal process. * This is the id used by the system API to refer to the process. */ int processId() const; /** * Returns foreground process's name */ QString foregroundProcessName(); /** * Get process info of current Session */ ProcessInfo *getProcessInfo(); void updateSessionProcessInfo(); bool updateForegroundProcessInfo(); void updateWorkingDirectory(); /** * Returns the process id of the terminal's foreground process. * This is initially the same as processId() but can change * as the user starts other programs inside the terminal. */ int foregroundProcessId(); /** Returns true if the user has started a program in the session. */ bool isForegroundProcessActive(); /** Returns the terminal session's window size in lines and columns. */ QSize size(); /** * Emits a request to resize the session to accommodate * the specified window size. * * @param size The size in lines and columns to request. */ void setSize(const QSize & size); /** Sets the text codec used by this session's terminal emulation. */ void setCodec(QTextCodec * codec); /** * Sets whether the session has a dark background or not. The session * uses this information to set the COLORFGBG variable in the process's * environment, which allows the programs running in the terminal to determine * whether the background is light or dark and use appropriate colors by default. * * This has no effect once the session is running. */ void setDarkBackground(bool darkBackground); /** * Returns true if the session has a dark background. * See setDarkBackground() */ bool hasDarkBackground() const; /** * Attempts to get the shell program to redraw the current display area. * This can be used after clearing the screen, for example, to get the * shell to redraw the prompt line. */ void refresh(); // void startZModem(const QString &rz, const QString &dir, const QStringList &list); // 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; // 获取此时tty的eraseChar char getEraseChar(); // Returns true if the current screen is the secondary/alternate one // or false if it's the primary/normal buffer bool isPrimaryScreen(); public slots: /** * Starts the terminal session. * * This creates the terminal process and connects the teletype to it. */ 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*) * signal to be emitted. */ void close(); /** * Changes the session title or other customizable aspects of the terminal * emulation display. For a list of what may be changed see the * Emulation::titleChanged() signal. */ void setUserTitle( int, const QString & caption ); signals: /** Emitted when the terminal process starts. */ void started(); /** * Emitted when the terminal process exits. */ void finished(); /** * Emitted when output is received from the terminal process. */ void receivedData( const QString & text ); /** Emitted when the session's title has changed. */ void titleChanged(); /** Emitted when the session's profile has changed. */ void profileChanged(const QString & profile); /** * Emitted when the activity state of this session changes. * * @param state The new state of the session. This may be one * of NOTIFYNORMAL, NOTIFYSILENCE or NOTIFYACTIVITY */ void stateChanged(int state); /** * Emitted when the current working directory of this session changes. * * @param dir The new current working directory of the session. */ void currentDirectoryChanged(const QString &dir); /** Emitted when a bell event occurs in the session. */ void bellRequest( const QString & message ); /** * Requests that the color the text for any tabs associated with * this session should be changed; * * TODO: Document what the parameter does */ void changeTabTextColorRequest(int); /** * Requests that the background color of views on this session * should be changed. */ void changeBackgroundColorRequest(const QColor &); /** TODO: Document me. */ void openUrlRequest(const QString & url); /** TODO: Document me. */ // void zmodemDetected(); /** * Emitted when the terminal process requests a change * in the size of the terminal window. * * @param size The requested window size in terms of lines and columns. */ void resizeRequest(const QSize & size); /** * Emitted when a profile change command is received from the terminal. * * @param text The text of the command. This is a string of the form * "PropertyName=Value;PropertyName=Value ..." */ void profileChangeCommandReceived(const QString & text); /** * Emitted when the flow control state changes. * * @param enabled True if flow control is enabled or false otherwise. */ void flowControlEnabledChanged(bool enabled); /** * Emitted when the active screen is switched, to indicate whether the primary * screen is in use. * * This signal serves as a relayer of Emulation::priamyScreenInUse(bool), * making it usable for higher level component. */ void primaryScreenInUse(bool use); /** * Broker for Emulation::cursorChanged() signal */ void cursorChanged(Emulation::KeyboardCursorShape cursorShape, bool blinkingCursorEnabled); void silence(); void activity(); /******** Modify by nt001000 renfeixiang 2020-05-27:修改 增加参数区别remove和purge卸载命令 Begin***************/ bool sessionUninstallTerminal(QString commandname); /******** Modify by nt001000 renfeixiang 2020-05-27:修改 增加参数区别remove和purge卸载命令 end***************/ // 标签标题参数改变 dzw 2020-12-2 void titleArgsChange(QString key, QString value); // warning提示信息 currentShell当前使用的shell, 启用shell是否成功 true 替换了shell false 替换shell但启动失败 void shellWarningMessage(QString currentShell, bool isSuccess); private slots: void done(int); // void fireZModemDetected(); void onReceiveBlock(const char * buffer, int len, bool isCommandExec); void monitorTimerDone(); void onViewSizeChange(int height, int width); void onEmulationSizeChange(QSize); void activityStateSet(int); //automatically detach views from sessions when view is destroyed void viewDestroyed(QObject * view); // void zmodemReadStatus(); // void zmodemReadAndSendBlock(); // void zmodemRcvBlock(const char *data, int len); // void zmodemFinished(); // 目前为了更新标签标题信息 void onUpdateTitleArgs(); // Relays the signal from Emulation and sets _isPrimaryScreen void onPrimaryScreenInUse(bool use); private: void updateTerminalSize(int height, int width); WId windowId() const; int _uniqueIdentifier; Pty *_shellProcess; Emulation * _emulation; QList _views; bool _monitorActivity; bool _monitorSilence; bool _notifiedActivity; bool _masterMode; bool _autoClose; bool _wantedClose; QTimer * _monitorTimer; int _silenceSeconds; QString _nameTitle; QString _displayTitle; QString _userTitle; QString _localTabTitleFormat; QString _remoteTabTitleFormat; 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; QString _program; QStringList _arguments; QStringList _environment; int _sessionId; QString _initialWorkingDir; QString _currentWorkingDir; QUrl _reportedWorkingUrl; ProcessInfo *_sessionProcessInfo = nullptr; ProcessInfo *_foregroundProcessInfo = nullptr; int _foregroundPid; // ZModem // bool _zmodemBusy; // KProcess* _zmodemProc; // ZModemDialog* _zmodemProgress; // Color/Font Changes by ESC Sequences QColor _modifiedBackground; // as set by: echo -en '\033]11;Color\007 QString _profileKey; bool _hasDarkBackground; static int lastSessionId; int ptySlaveFd; // title format args QString _userName; QString _currentDir; QString _programName; QTimer *_updateTimer = nullptr; bool _isPrimaryScreen; }; /** * Provides a group of sessions which is divided into master and slave sessions. * Activity in master sessions can be propagated to all sessions within the group. * The type of activity which is propagated and method of propagation is controlled * by the masterMode() flags. */ class SessionGroup : public QObject { Q_OBJECT public: /** Constructs an empty session group. */ SessionGroup(); /** Destroys the session group and removes all connections between master and slave sessions. */ ~SessionGroup() override; /** Adds a session to the group. */ void addSession( Session * session ); /** Removes a session from the group. */ void removeSession( Session * session ); /** Returns the list of sessions currently in the group. */ QList sessions() const; /** * Sets whether a particular session is a master within the group. * Changes or activity in the group's master sessions may be propagated * to all the sessions in the group, depending on the current masterMode() * * @param session The session whoose master status should be changed. * @param master True to make this session a master or false otherwise */ void setMasterStatus( Session * session , bool master ); /** Returns the master status of a session. See setMasterStatus() */ bool masterStatus( Session * session ) const; /** * This enum describes the options for propagating certain activity or * changes in the group's master sessions to all sessions in the group. */ enum MasterMode { /** * Any input key presses in the master sessions are sent to all * sessions in the group. */ CopyInputToAll = 1 }; /** * Specifies which activity in the group's master sessions is propagated * to all sessions in the group. * * @param mode A bitwise OR of MasterMode flags. */ void setMasterMode( int mode ); /** * Returns a bitwise OR of the active MasterMode flags for this group. * See setMasterMode() */ int masterMode() const; private: void connectPair(Session * master , Session * other); void disconnectPair(Session * master , Session * other); void connectAll(bool connect); QList masters() const; // maps sessions to their master status QHash _sessions; int _masterMode; }; } #endif deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/SessionManager.cpp000066400000000000000000000067541475472654300266230ustar00rootroot00000000000000/* This file is part of Konsole, KDE's terminal. Copyright 2007-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 (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. */ // Own #include "SessionManager.h" // Qt #include #include #include // Konsole #include "Session.h" using namespace Konsole; Q_GLOBAL_STATIC(SessionManager, theSessionManager) SessionManager *SessionManager::instance() { return theSessionManager; } SessionManager::SessionManager() { } SessionManager::~SessionManager() { } //void SessionManager::closeAllSessions() //{ // // close remaining sessions // for (int i = 0; i < _sessions.size(); i++) { // Session *session = _sessions.at(i); // session->close(); // } // _sessions.clear(); //} QList SessionManager::sessions() const { return _sessions; } void SessionManager::sessionTerminated(Session *session) { Q_ASSERT(session); _sessions.removeAll(session); session->deleteLater(); } void SessionManager::saveSession(Session *session) { _sessions << session; } bool SessionManager::removeSession(int id) { if (_sessions.count() == 0) { return false; } int removeIndex = -1; for (int i = 0; i < _sessions.size(); i++) { Session *session = _sessions.at(i); if (session->sessionId() == id) { removeIndex = i; break; } } if (removeIndex >= 0) { _sessions.removeAt(removeIndex); return true; } return false; } int SessionManager::getSessionId(Session *session) { return session->sessionId(); } Session *SessionManager::idToSession(int id) { for (int i = 0; i < _sessions.size(); i++) { Session *session = _sessions.at(i); if (session->sessionId() == id) { return session; } } // this should not happen qDebug() << "Failed to find session for ID" << id; return nullptr; } void SessionManager::saveCurrShellPrompt(int sessionId, QString strPrompt) { strPrompt = strPrompt.trimmed(); _shellPromptSessionMap.insert(sessionId, strPrompt); } QString SessionManager::getCurrShellPrompt(int sessionId) { return _shellPromptSessionMap.value(sessionId); } void SessionManager::saveCurrShellCommand(int sessionId, QString strCommand) { strCommand = strCommand.trimmed(); _shellCommandSessionMap.insert(sessionId, strCommand); } QString SessionManager::getCurrShellCommand(int sessionId) { return _shellCommandSessionMap.value(sessionId); } void SessionManager::setTerminalResizing(int sessionId, bool bTerminalResizing) { _terminalResizeStateMap.insert(sessionId, bTerminalResizing); } bool SessionManager::isTerminalResizing(int sessionId) { return _terminalResizeStateMap.value(sessionId); } deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/SessionManager.h000066400000000000000000000063421475472654300262610ustar00rootroot00000000000000/* This file is part of Konsole, KDE's terminal. Copyright 2007-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 (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. */ #ifndef SESSIONMANAGER_H #define SESSIONMANAGER_H // Qt #include #include #include #include namespace Konsole { class Session; /** * Manages running terminal sessions. */ class SessionManager : public QObject { Q_OBJECT public: /** * Constructs a new session manager and loads information about the available * profiles. */ SessionManager(); /** * Destroys the SessionManager. All running sessions should be closed * (via closeAllSessions()) before the SessionManager is destroyed. */ ~SessionManager() Q_DECL_OVERRIDE; /** * Returns the session manager instance. */ static SessionManager *instance(); /** Kill all running sessions. */ // void closeAllSessions(); /** * Returns a list of active sessions. */ QList sessions() const; // System session management void saveSession(Session *session); bool removeSession(int id); int getSessionId(Session *session); Session *idToSession(int id); //用于存储当前的命令提示符 void saveCurrShellPrompt(int sessionId, QString strPrompt); QString getCurrShellPrompt(int sessionId); //用于存储当前的执行的命令字符串 void saveCurrShellCommand(int sessionId, QString strCommand); QString getCurrShellCommand(int sessionId); //用于存储终端控件是否正在resize的状态值 true表示正在resize void setTerminalResizing(int sessionId, bool bTerminalResizing); bool isTerminalResizing(int sessionId); signals: void sessionIdle(bool isIdle); protected Q_SLOTS: /** * Called to inform the manager that a session has finished executing. * * @param session The Session which has finished executing. */ void sessionTerminated(Session *session); private: QList _sessions; // list of running sessions QHash _restoreMapping; //存储当前的命令提示符Map QMap _shellPromptSessionMap; //存储当前的执行的命令字符串Map QMap _shellCommandSessionMap; //存储终端控件是否正在resize的状态值Map QMap _terminalResizeStateMap; //存储当前shell提示符的路径深度Map QMap _terminalPathDepthMap; }; } #endif //SESSIONMANAGER_H deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/ShellCommand.cpp000066400000000000000000000107021475472654300262370ustar00rootroot00000000000000/* Copyright (C) 2007 by Robert Knight 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. Rewritten for QT4 by e_k , Copyright (C)2008 */ // Own #include "ShellCommand.h" //some versions of gcc(4.3) require explicit include #include using namespace Konsole; // expands environment variables in 'text' // function copied from kdelibs/kio/kio/kurlcompletion.cpp static bool expandEnv(QString & text); ShellCommand::ShellCommand(const QString & fullCommand) { bool inQuotes = false; QString builder; for ( int i = 0 ; i < fullCommand.count() ; i++ ) { QChar ch = fullCommand[i]; const bool isLastChar = ( i == fullCommand.count() - 1 ); const bool isQuote = ( ch == QLatin1Char('\'') || ch == QLatin1Char('\"') ); if ( !isLastChar && isQuote ) { inQuotes = !inQuotes; } else { if ( (!ch.isSpace() || inQuotes) && !isQuote ) { builder.append(ch); } if ( (ch.isSpace() && !inQuotes) || ( i == fullCommand.count()-1 ) ) { _arguments << builder; builder.clear(); } } } } ShellCommand::ShellCommand(const QString & command , const QStringList & arguments) : _arguments(arguments) { if ( !_arguments.isEmpty() ) { _arguments[0] = command; } } QString ShellCommand::fullCommand() const { return _arguments.join(QLatin1Char(' ')); } QString ShellCommand::command() const { if ( !_arguments.isEmpty() ) { return _arguments[0]; } else { return QString(); } } QStringList ShellCommand::arguments() const { return _arguments; } bool ShellCommand::isRootCommand() const { Q_ASSERT(0); // not implemented yet return false; } bool ShellCommand::isAvailable() const { Q_ASSERT(0); // not implemented yet return false; } QStringList ShellCommand::expand(const QStringList & items) { QStringList result; for(const QString &item : items) { result << expand(item); } return result; } QString ShellCommand::expand(const QString & text) { QString result = text; expandEnv(result); return result; } /* * expandEnv * * Expand environment variables in text. Escaped '$' characters are ignored. * Return true if any variables were expanded */ static bool expandEnv( QString & text ) { // Find all environment variables beginning with '$' // int pos = 0; bool expanded = false; while ( (pos = text.indexOf(QLatin1Char('$'), pos)) != -1 ) { // Skip escaped '$' // if ( pos > 0 && text.at(pos-1) == QLatin1Char('\\') ) { pos++; } // Variable found => expand // else { // Find the end of the variable = next '/' or ' ' // int pos2 = text.indexOf( QLatin1Char(' '), pos+1 ); int pos_tmp = text.indexOf( QLatin1Char('/'), pos+1 ); if ( pos2 == -1 || (pos_tmp != -1 && pos_tmp < pos2) ) { pos2 = pos_tmp; } if ( pos2 == -1 ) { pos2 = text.length(); } // Replace if the variable is terminated by '/' or ' ' // and defined // if ( pos2 >= 0 ) { int len = pos2 - pos; QString key = text.mid( pos+1, len-1); QString value = QString::fromLocal8Bit( qgetenv(key.toLocal8Bit().constData()) ); if ( !value.isEmpty() ) { expanded = true; text.replace( pos, len, value ); pos = pos + value.length(); } else { pos = pos2; } } } } return expanded; } deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/ShellCommand.h000066400000000000000000000053651475472654300257150ustar00rootroot00000000000000/* Copyright (C) 2007 by Robert Knight 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. Rewritten for QT4 by e_k , Copyright (C)2008 */ #ifndef SHELLCOMMAND_H #define SHELLCOMMAND_H // Qt #include namespace Konsole { /** * A class to parse and extract information about shell commands. * * ShellCommand can be used to: * *
    *
  • Take a command-line (eg "/bin/sh -c /path/to/my/script") and split it * into its component parts (eg. the command "/bin/sh" and the arguments * "-c","/path/to/my/script") *
  • *
  • Take a command and a list of arguments and combine them to * form a complete command line. *
  • *
  • Determine whether the binary specified by a command exists in the * user's PATH. *
  • *
  • Determine whether a command-line specifies the execution of * another command as the root user using su/sudo etc. *
  • *
*/ class ShellCommand { public: /** * Constructs a ShellCommand from a command line. * * @param fullCommand The command line to parse. */ ShellCommand(const QString & fullCommand); /** * Constructs a ShellCommand with the specified @p command and @p arguments. */ ShellCommand(const QString & command , const QStringList & arguments); /** Returns the command. */ QString command() const; /** Returns the arguments. */ QStringList arguments() const; /** * Returns the full command line. */ QString fullCommand() const; /** Returns true if this is a root command. */ bool isRootCommand() const; /** Returns true if the program specified by @p command() exists. */ bool isAvailable() const; /** Expands environment variables in @p text .*/ static QString expand(const QString & text); /** Expands environment variables in each string in @p list. */ static QStringList expand(const QStringList & items); private: QStringList _arguments; }; } #endif // SHELLCOMMAND_H deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/TerminalCharacterDecoder.cpp000066400000000000000000000152431475472654300305540ustar00rootroot00000000000000/* 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 (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 Lesser 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. */ // Own #include "TerminalCharacterDecoder.h" // std #include // Qt #include // KDE //#include // Konsole #include "konsole_wcwidth.h" #include using namespace Konsole; PlainTextDecoder::PlainTextDecoder() : _output(nullptr) , _includeTrailingWhitespace(true) , _recordLinePositions(false) { } void PlainTextDecoder::setTrailingWhitespace(bool enable) { _includeTrailingWhitespace = enable; } bool PlainTextDecoder::trailingWhitespace() const { return _includeTrailingWhitespace; } void PlainTextDecoder::begin(QTextStream* output) { _output = output; if (!_linePositions.isEmpty()) _linePositions.clear(); } void PlainTextDecoder::end() { _output = nullptr; } void PlainTextDecoder::setRecordLinePositions(bool record) { _recordLinePositions = record; } QList PlainTextDecoder::linePositions() const { return _linePositions; } void PlainTextDecoder::decodeLine(const Character* const characters, int count, LineProperty /*properties*/ ) { Q_ASSERT( _output ); if (_recordLinePositions && _output->string()) { int pos = _output->string()->count(); _linePositions << pos; } //TODO should we ignore or respect the LINE_WRAPPED line property? //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) std::wstring plainText; plainText.reserve(count); int outputCount = count; // if inclusion of trailing whitespace is disabled then find the end of the // line if ( !_includeTrailingWhitespace ) { for (int i = count-1 ; i >= 0 ; i--) { if ( characters[i].character != L' ' ) break; else outputCount--; } } for (int i=0;i') text.append(L">"); else text.push_back(ch); } else { text.append(L" "); //HTML truncates multiple spaces, so use a space marker instead } } //close any remaining open inner spans if ( _innerSpanOpen ) closeSpan(text); //start new line text.append(L"
"); *_output << QString::fromStdWString(text); } void HTMLDecoder::openSpan(std::wstring& text , const QString& style) { text.append( QString(QLatin1String("")).arg(style).toStdWString() ); } void HTMLDecoder::closeSpan(std::wstring& text) { text.append(L""); } void HTMLDecoder::setColorTable(const ColorEntry* table) { _colorTable = table; } deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/TerminalCharacterDecoder.h000066400000000000000000000107371475472654300302240ustar00rootroot00000000000000/* 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 (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 Lesser 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. */ #ifndef TERMINAL_CHARACTER_DECODER_H #define TERMINAL_CHARACTER_DECODER_H #include "Character.h" #include class QTextStream; namespace Konsole { /** * Base class for terminal character decoders * * The decoder converts lines of terminal characters which consist of a unicode character, foreground * 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. */ class TerminalCharacterDecoder { public: virtual ~TerminalCharacterDecoder() {} /** Begin decoding characters. The resulting text is appended to @p output. */ virtual void begin(QTextStream* output) = 0; /** End decoding. */ virtual void end() = 0; /** * Converts a line of terminal characters with associated properties into a text string * and writes the string into an output QTextStream. * * @param characters An array of characters of length @p count. * @param count The number of characters * @param properties Additional properties which affect all characters in the line */ virtual void decodeLine(const Character* const characters, int count, LineProperty properties) = 0; }; /** * A terminal character decoder which produces plain text, ignoring colours and other appearance-related * properties of the original characters. */ class PlainTextDecoder : public TerminalCharacterDecoder { public: PlainTextDecoder(); /** * Set whether trailing whitespace at the end of lines should be included * in the output. * Defaults to true. */ void setTrailingWhitespace(bool enable); /** * Returns whether trailing whitespace at the end of lines is included * 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 * the output device is not a string. */ QList linePositions() const; /** Enables recording of character positions at which new lines are added. See linePositions() */ void setRecordLinePositions(bool record); void begin(QTextStream* output) override; void end() override; void decodeLine(const Character* const characters, int count, LineProperty properties) override; private: QTextStream* _output; bool _includeTrailingWhitespace; bool _recordLinePositions; QList _linePositions; }; /** * A terminal character decoder which produces pretty HTML markup */ class HTMLDecoder : public TerminalCharacterDecoder { public: /** * Constructs an HTML decoder using a default black-on-white color scheme. */ HTMLDecoder(); /** * Sets the colour table which the decoder uses to produce the HTML colour codes in its * output */ void setColorTable( const ColorEntry* table ); void decodeLine(const Character* const characters, int count, LineProperty properties) override; void begin(QTextStream* output) override; void end() override; private: void openSpan(std::wstring& text , const QString& style); void closeSpan(std::wstring& text); QTextStream* _output; const ColorEntry* _colorTable; bool _innerSpanOpen; quint8 _lastRendition; CharacterColor _lastForeColor; CharacterColor _lastBackColor; }; } #endif deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/TerminalDisplay.cpp000066400000000000000000004167521475472654300270110ustar00rootroot00000000000000/* 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 (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. */ // Own #include "TerminalDisplay.h" #include "SessionManager.h" // Qt #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // KDE //#include //#include //#include //#include //#include //#include //#include //#include //#include //#include // Konsole //#include #include "Filter.h" #include "konsole_wcwidth.h" #include "ScreenWindow.h" #include "Screen.h" #include "TerminalCharacterDecoder.h" using namespace Konsole; typedef quint16 RenditionFlags; #ifndef loc #define loc(X,Y) ((Y)*_columns+(X)) #endif #define yMouseScroll 1 #define REPCHAR "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \ "abcdefgjijklmnopqrstuvwxyz" \ "0123456789./+@" const ColorEntry Konsole::base_color_table[TABLE_COLORS] = // The following are almost IBM standard color codes, with some slight // gamma correction for the dim colors to compensate for bright X screens. // It contains the 8 ansiterm/xterm colors in 2 intensities. { // Fixme: could add faint colors here, also. // normal ColorEntry(QColor(0x00,0x00,0x00), false), ColorEntry( QColor(0xB2,0xB2,0xB2), true), // Dfore, Dback ColorEntry(QColor(0x00,0x00,0x00), false), ColorEntry( QColor(0xB2,0x18,0x18), false), // Black, Red ColorEntry(QColor(0x18,0xB2,0x18), false), ColorEntry( QColor(0xB2,0x68,0x18), false), // Green, Yellow ColorEntry(QColor(0x18,0x18,0xB2), false), ColorEntry( QColor(0xB2,0x18,0xB2), false), // Blue, Magenta ColorEntry(QColor(0x18,0xB2,0xB2), false), ColorEntry( QColor(0xB2,0xB2,0xB2), false), // Cyan, White // intensiv ColorEntry(QColor(0x00,0x00,0x00), false), ColorEntry( QColor(0xFF,0xFF,0xFF), true), ColorEntry(QColor(0x68,0x68,0x68), false), ColorEntry( QColor(0xFF,0x54,0x54), false), ColorEntry(QColor(0x54,0xFF,0x54), false), ColorEntry( QColor(0xFF,0xFF,0x54), false), ColorEntry(QColor(0x54,0x54,0xFF), false), ColorEntry( QColor(0xFF,0x54,0xFF), false), ColorEntry(QColor(0x54,0xFF,0xFF), false), ColorEntry( QColor(0xFF,0xFF,0xFF), false) }; // scroll increment used when dragging selection at top/bottom of window. // static bool TerminalDisplay::_antialiasText = true; bool TerminalDisplay::HAVE_TRANSPARENCY = true; /***add begin by ut001121 zhangmeng 20200912 初始化字号限制 修复42250***/ int Konsole::__minFontSize = 0; int Konsole::__maxFontSize = 0x7fffffff; /***add end by ut001121***/ // we use this to force QPainter to display text in LTR mode // more information can be found in: http://unicode.org/reports/tr9/ const QChar LTR_OVERRIDE_CHAR( 0x202D ); /* ------------------------------------------------------------------------- */ /* */ /* Colors */ /* */ /* ------------------------------------------------------------------------- */ /* Note that we use ANSI color order (bgr), while IBMPC color order is (rgb) Code 0 1 2 3 4 5 6 7 ----------- ------- ------- ------- ------- ------- ------- ------- ------- ANSI (bgr) Black Red Green Yellow Blue Magenta Cyan White IBMPC (rgb) Black Blue Green Cyan Red Magenta Yellow White */ ScreenWindow* TerminalDisplay::screenWindow() const { return _screenWindow; } void TerminalDisplay::setScreenWindow(ScreenWindow* window) { // disconnect existing screen window if any if ( _screenWindow ) { disconnect( _screenWindow , nullptr , this , nullptr ); } _screenWindow = window; if ( window ) { // TODO: Determine if this is an issue. //#warning "The order here is not specified - does it matter whether updateImage or updateLineProperties comes first?" connect( _screenWindow , SIGNAL(outputChanged()) , this , SLOT(updateLineProperties()) ); connect( _screenWindow , SIGNAL(outputChanged()) , this , SLOT(updateImage()) ); connect( _screenWindow , SIGNAL(outputChanged()) , this , SLOT(updateFilters()) ); connect( _screenWindow , SIGNAL(scrolled(int)) , this , SLOT(updateFilters()) ); connect( _screenWindow, SIGNAL(selectionCleared()), this, SLOT(selectionCleared()) ); window->setWindowLines(_lines); window->screen()->setSessionId(_sessionId); window->screen()->setReflowLines(true); } } const ColorEntry* TerminalDisplay::colorTable() const { return _colorTable; } void TerminalDisplay::setBackgroundColor(const QColor& color) { _colorTable[DEFAULT_BACK_COLOR].color = color; QPalette p = palette(); p.setColor( backgroundRole(), color ); setPalette( p ); // Avoid propagating the palette change to the scroll bar _scrollBar->setPalette( QApplication::palette() ); update(); } void TerminalDisplay::setForegroundColor(const QColor& color) { _colorTable[DEFAULT_FORE_COLOR].color = color; update(); } void TerminalDisplay::setColorTable(const ColorEntry table[]) { for (int i = 0; i < TABLE_COLORS; i++) _colorTable[i] = table[i]; setBackgroundColor(_colorTable[DEFAULT_BACK_COLOR].color); } /* ------------------------------------------------------------------------- */ /* */ /* Font */ /* */ /* ------------------------------------------------------------------------- */ /* The VT100 has 32 special graphical characters. The usual vt100 extended xterm fonts have these at 0x00..0x1f. QT's iso mapping leaves 0x00..0x7f without any changes. But the graphicals come in here as proper unicode characters. We treat non-iso10646 fonts as VT100 extended and do the requiered mapping from unicode to 0x00..0x1f. The remaining translation is then left to the QCodec. */ bool TerminalDisplay::canDraw(uint ucs4cp) const { return (0x2500 <= ucs4cp && ucs4cp <= 0x259F); } bool TerminalDisplay::isLineCharString(const QString& string) const { if (string.length() == 0) { return false; } return canDraw(string.at(0).unicode()); } /******************************************************************************* 1. @函数: setIsAllowScroll 2. @作者: ut000610 戴正文 3. @日期: 2020-09-16 4. @说明: 设置是否允许滚动到最新的位置 当有输出且并不是在setZoom之后,此标志为true 允许滚动 当有输出且在setZoom之后,比标志位false 不允许滚动 *******************************************************************************/ void TerminalDisplay::setIsAllowScroll(bool isAllowScroll) { m_isAllowScroll = isAllowScroll; } /******************************************************************************* 1. @函数: getIsAllowScroll 2. @作者: ut000610 戴正文 3. @日期: 2020-09-16 4. @说明: 获取是否允许输出时滚动 *******************************************************************************/ bool TerminalDisplay::getIsAllowScroll() const { return m_isAllowScroll; } // assert for i in [0..31] : vt100extended(vt100_graphics[i]) == i. unsigned short Konsole::vt100_graphics[32] = { // 0/8 1/9 2/10 3/11 4/12 5/13 6/14 7/15 0x0020, 0x25C6, 0x2592, 0x2409, 0x240c, 0x240d, 0x240a, 0x00b0, 0x00b1, 0x2424, 0x240b, 0x2518, 0x2510, 0x250c, 0x2514, 0x253c, 0xF800, 0xF801, 0x2500, 0xF803, 0xF804, 0x251c, 0x2524, 0x2534, 0x252c, 0x2502, 0x2264, 0x2265, 0x03C0, 0x2260, 0x00A3, 0x00b7 }; void TerminalDisplay::fontChange(const QFont&) { QFontMetrics fm(font()); _fontHeight = fm.height() + _lineSpacing; Q_ASSERT(_fontHeight > 0); /* TODO: When changing the three deprecated width() below * consider the info in * https://phabricator.kde.org/D23144 comments * horizontalAdvance() was added in Qt 5.11 (which should be the * minimum for 20.04 or 20.08 KDE Applications release) */ // waba TerminalDisplay 1.123: // "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((static_cast(fm.horizontalAdvance(QStringLiteral(REPCHAR))) / static_cast(qstrlen(REPCHAR)))); _fixedFont = true; const int fw = fm.horizontalAdvance(QLatin1Char(REPCHAR[0])); for (unsigned int i = 1; i < qstrlen(REPCHAR); i++) { if (fw != fm.horizontalAdvance(QLatin1Char(REPCHAR[i]))) { _fixedFont = false; break; } } if (_fontWidth < 1) _fontWidth=1; _fontAscent = fm.ascent(); 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;// //----------add by nyq to slove the twinkle of the window-- _drawTextTestFlag = false; //--------------------------------------------------------- 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) { /***add begin by ut001121 zhangmeng 20200908 限制字体大小 修复BUG42250***/ /***add begin by ut001121 zhangmeng 20200908 限制字体大小 修复BUG42412***/ if(f.pointSize() < __minFontSize || f.pointSize() > __maxFontSize){ return; } /***add end by ut001121***/ // 放大缩小时需要一个标志位 // 该标志位负责取消输出时滚动 // 发送信号修改标志位 => 调整大小时,不允许接收输出时滚动的设置 m_isAllowScroll = false; QFont newFont(f); int strategy = 0; // hint that text should be drawn with- or without anti-aliasing. // depending on the user's font configuration, this may not be respected strategy |= _antialiasText ? QFont::PreferAntialias : QFont::NoAntialias; // Konsole cannot handle non-integer font metrics strategy |= QFont::ForceIntegerMetrics; // In case the provided font doesn't have some specific characters it should // fall back to a Monospace fonts. newFont.setStyleHint(QFont::TypeWriter, QFont::StyleStrategy(strategy)); // Try to check that a good font has been loaded. // For some fonts, ForceIntegerMetrics causes height() == 0 which // will cause Konsole to crash later. QFontMetrics fontMetrics2(newFont); if (fontMetrics2.height() < 1) { qDebug()<<"The font "<(fontInfo.styleHint()), fontInfo.weight(), static_cast(fontInfo.style()), static_cast(fontInfo.underline()), static_cast(fontInfo.strikeOut()), // Intentional newFont use - fixedPitch is bugged, see comment above static_cast(newFont.fixedPitch()), static_cast(fontInfo.rawMode())); qDebug() << "The font to use in the terminal can not be matched exactly on your system."; qDebug() << " Selected: " << newFont.toString(); qDebug() << " System : " << nonMatching; } QWidget::setFont(newFont); fontChange(newFont); } void TerminalDisplay::setFont(const QFont &) { // ignore font change request if not coming from konsole itself } /* ------------------------------------------------------------------------- */ /* */ /* Constructor / Destructor */ /* */ /* ------------------------------------------------------------------------- */ TerminalDisplay::TerminalDisplay(QWidget *parent) :QWidget(parent) ,_screenWindow(nullptr) ,_allowBell(true) ,_gridLayout(nullptr) ,_fontHeight(1) ,_fontWidth(1) ,_fontAscent(1) ,_boldIntense(true) ,_lines(1) ,_columns(1) ,_usedLines(1) ,_usedColumns(1) ,_contentRect(QRect()) ,_contentHeight(1) ,_contentWidth(1) ,_image(nullptr) ,_randomSeed(0) ,_resizing(false) ,_terminalSizeHint(false) ,_terminalSizeStartup(true) ,_bidiEnabled(true) //默认开启双向文本(Bi-directional text)mode,和konsole保持同步 ,_mouseMarks(false) , _alternateScrolling(true) ,_actSel(0) ,_wordSelectionMode(false) ,_lineSelectionMode(false) ,_preserveLineBreaks(false) ,_columnSelectionMode(false) ,_scrollbarLocation(QTermWidget::NoScrollBar) ,_wordCharacters(QLatin1String(":@-./_~")) ,_bellMode(SystemBeepBell) ,_blinking(false) ,_hasBlinker(false) ,_cursorBlinking(false) ,_hasBlinkingCursor(false) ,_allowBlinkingText(true) ,_ctrlDrag(false) ,_tripleClickMode(SelectWholeLine) ,_isFixedSize(false) ,_possibleTripleClick(false) ,_resizeWidget(nullptr) ,_resizeTimer(nullptr) ,_flowControlWarningEnabled(false) ,_hideCursor(false) ,_outputSuspendedLabel(nullptr) ,_lineSpacing(0) ,_colorsInverted(false) ,_blendColor(qRgba(0,0,0,0xff)) ,_filterChain(new TerminalImageFilterChain()) ,_cursorShape(Emulation::KeyboardCursorShape::BlockCursor) ,mMotionAfterPasting(NoMoveScreenWindow) ,_leftBaseMargin(1) ,_topBaseMargin(1) ,_drawLineChars(true) //,_headerBar(new TerminalHeaderBar(this)) { // 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); // The offsets are not yet calculated. // Do not calculate these too often to be more smoothly when resizing // konsole in opaque mode. _topMargin = _topBaseMargin; _leftMargin = _leftBaseMargin; // create scroll bar for scrolling output up and down // set the scroll bar's slider to occupy the whole area of the scroll bar initially _scrollBar = new QScrollBar(this); /******** Modify by ut000439 wangpeili 2020-06-24: 适应窗口特效圆角 ****************/ //qDebug()<<"_scrollBar->width()"<<_scrollBar->width(); // 设置15px宽度=6? _scrollBar->setStyleSheet("margin: 0px 0 15px 0;width: 15"); //qDebug()<<"_scrollBar->width()"<<_scrollBar->width(); /********************* Modify by n014361 wangpeili End ************************/ // since the contrast with the terminal background may not be enough, // the scrollbar should be auto-filled if not transient if (!_scrollBar->style()->styleHint(QStyle::SH_ScrollBar_Transient, nullptr, _scrollBar)) _scrollBar->setAutoFillBackground(true); setScroll(0,0); _scrollBar->setCursor( Qt::ArrowCursor ); connect(_scrollBar, SIGNAL(valueChanged(int)), this, SLOT(scrollBarPositionChanged(int))); // qtermwidget: we have to hide it here due the _scrollbarLocation==NoScrollBar // check in TerminalDisplay::setScrollBarPosition(ScrollBarPosition position) _scrollBar->hide(); // setup timers for blinking cursor and text _blinkTimer = new QTimer(this); connect(_blinkTimer, SIGNAL(timeout()), this, SLOT(blinkEvent())); _blinkCursorTimer = new QTimer(this); connect(_blinkCursorTimer, SIGNAL(timeout()), this, SLOT(blinkCursorEvent())); // KCursor::setAutoHideCursor( this, true ); setUsesMouse(true); setBracketedPasteMode(false); setColorTable(base_color_table); setMouseTracking(true); // Enable drag and drop setAcceptDrops(true); // attempt dragInfo.state = diNone; setFocusPolicy( Qt::WheelFocus ); // enable input method support setAttribute(Qt::WA_InputMethodEnabled, true); // this is an important optimization, it tells Qt // that TerminalDisplay will handle repainting its entire area. setAttribute(Qt::WA_OpaquePaintEvent); _gridLayout = new QGridLayout(this); _gridLayout->setContentsMargins(0, 0, 0, 0); //_gridLayout->addWidget(_headerBar); setLayout( _gridLayout ); new AutoScrollHandler(this); m_bUserIsResizing = false; // 隐藏QScrollBar默认的右键菜单 hideQScrollBarRightMenu(); } TerminalDisplay::~TerminalDisplay() { disconnect(_blinkTimer); disconnect(_blinkCursorTimer); qApp->removeEventFilter( this ); delete[] _image; delete _gridLayout; delete _outputSuspendedLabel; delete _filterChain; } /* ------------------------------------------------------------------------- */ /* */ /* Display Operations */ /* */ /* ------------------------------------------------------------------------- */ /** A table for emulating the simple (single width) unicode drawing chars. It represents the 250x - 257x glyphs. If it's zero, we can't use it. if it's not, it's encoded as follows: imagine a 5x5 grid where the points are numbered 0 to 24 left to top, top to bottom. Each point is represented by the corresponding bit. Then, the pixels basically have the following interpretation: _|||_ -...- -...- -...- _|||_ where _ = none | = vertical line. - = horizontal line. */ enum LineEncode { TopL = (1<<1), TopC = (1<<2), TopR = (1<<3), LeftT = (1<<5), Int11 = (1<<6), Int12 = (1<<7), Int13 = (1<<8), RightT = (1<<9), LeftC = (1<<10), Int21 = (1<<11), Int22 = (1<<12), Int23 = (1<<13), RightC = (1<<14), LeftB = (1<<15), Int31 = (1<<16), Int32 = (1<<17), Int33 = (1<<18), RightB = (1<<19), BotL = (1<<21), BotC = (1<<22), BotR = (1<<23) }; void TerminalDisplay::drawLineCharString(QPainter& painter, int x, int y, const QString& str, const Character* attributes) { // only turn on anti-aliasing during this short time for the "text" // for the normal text we have TextAntialiasing on demand on // otherwise we have rendering artifacts // set https://bugreports.qt.io/browse/QTBUG-66036 painter.setRenderHint(QPainter::Antialiasing, _antialiasText); const bool useBoldPen = (attributes->rendition & RE_BOLD) != 0 && _boldIntense; QRect cellRect = {x, y, _fontWidth, _fontHeight}; for (int i = 0 ; i < str.length(); i++) { LineBlockCharacters::draw(painter, cellRect.translated(i * _fontWidth, 0), str[i], useBoldPen); } painter.setRenderHint(QPainter::Antialiasing, false); } void TerminalDisplay::setKeyboardCursorShape(QTermWidget::KeyboardCursorShape shape) { _cursorShape = shape; updateCursor(); } QTermWidget::KeyboardCursorShape TerminalDisplay::keyboardCursorShape() const { return _cursorShape; } void TerminalDisplay::setKeyboardCursorColor(bool useForegroundColor, const QColor& color) { if (useForegroundColor) _cursorColor = QColor(); // an invalid color means that // the foreground color of the // current character should // be used else _cursorColor = color; } QColor TerminalDisplay::keyboardCursorColor() const { return _cursorColor; } void TerminalDisplay::setOpacity(qreal opacity) { QColor color(_blendColor); color.setAlphaF(opacity); // enable automatic background filling to prevent the display // flickering if there is no transparency /*if ( color.alpha() == 255 ) { setAutoFillBackground(true); } else { setAutoFillBackground(false); }*/ _blendColor = color.rgba(); } void TerminalDisplay::setBackgroundImage(QString backgroundImage) { if (!backgroundImage.isEmpty()) { _backgroundImage.load(backgroundImage); setAttribute(Qt::WA_OpaquePaintEvent, false); } else { _backgroundImage = QPixmap(); setAttribute(Qt::WA_OpaquePaintEvent, true); } } 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) { QRectF cursorRect = rect; cursorRect.setHeight(_fontHeight - _lineSpacing - 1); if (!_cursorBlinking) { if ( _cursorColor.isValid() ) painter.setPen(_cursorColor); else painter.setPen(foregroundColor); if ( _cursorShape == Emulation::KeyboardCursorShape::BlockCursor ) { if ( hasFocus() ) { painter.fillRect(cursorRect, _cursorColor.isValid() ? _cursorColor : foregroundColor); if ( !_cursorColor.isValid() ) { // invert the colour used to draw the text to ensure that the character at // the cursor position is readable invertCharacterColor = true; } } else { // draw the cursor outline, adjusting the area so that // it is draw entirely inside 'rect' float penWidth = qMax(1,painter.pen().width()); painter.drawRect(cursorRect.adjusted(penWidth/2, penWidth/2, - penWidth/2, - penWidth/2)); } } else if ( _cursorShape == Emulation::KeyboardCursorShape::UnderlineCursor ) painter.drawLine(QLineF( QPointF(cursorRect.left(), cursorRect.bottom()), QPointF(cursorRect.right(), cursorRect.bottom()))); else if ( _cursorShape == Emulation::KeyboardCursorShape::IBeamCursor ) painter.drawLine(QLineF( QPointF(cursorRect.left(), cursorRect.top()), QPointF(cursorRect.left(), cursorRect.bottom()))); } } void TerminalDisplay::drawCharacters(QPainter& painter, const QRect& rect, const QString& 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 = ((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(); QFont font = painter.font(); 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); } // setup pen const CharacterColor& textColor = ( invertCharacterColor ? style->backgroundColor : style->foregroundColor ); const QColor color = textColor.color(_colorTable); QPen pen = painter.pen(); if ( pen.color() != color ) { pen.setColor(color); painter.setPen(color); } // draw text if ( !IsCodecGB18030() && isLineCharString(text) ) drawLineCharString(painter,rect.x(),rect.y(),text,style); else { // 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(QPointF(rect.x(), rect.y() + _fontAscent + _lineSpacing), text); } else { { QRectF drawRect(rect.topLeft(), rect.size()); drawRect.setHeight(rect.height() + _drawTextAdditionHeight); painter.drawText(drawRect, Qt::AlignBottom, LTR_OVERRIDE_CHAR + text); } } } } void TerminalDisplay::drawTextFragment(QPainter& painter , const QRect& rect, const QString& text, const Character* style) { painter.save(); // 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, false /* do not use transparency */); // draw cursor shape if the current character is the cursor // this may alter the foreground and background colors bool invertCharacterColor = false; if (!_hideCursor) { if ( style->rendition & RE_CURSOR ) { const QColor cursorBackground = _colorTable[DEFAULT_BACK_COLOR].color; const QColor cursorForeground = _colorTable[DEFAULT_FORE_COLOR].color; drawCursor(painter,rect,cursorForeground,cursorBackground,invertCharacterColor); } } // draw text drawCharacters(painter,rect,text,style,invertCharacterColor); painter.restore(); } void TerminalDisplay::setRandomSeed(uint randomSeed) { _randomSeed = randomSeed; } uint TerminalDisplay::randomSeed() const { return _randomSeed; } #if 0 /*! Set XIM Position */ void TerminalDisplay::setCursorPos(const int curx, const int cury) { QPoint tL = contentsRect().topLeft(); int tLx = tL.x(); int tLy = tL.y(); int xpos, ypos; ypos = _topMargin + tLy + _fontHeight*(cury-1) + _fontAscent; xpos = _leftMargin + tLx + _fontWidth*curx; //setMicroFocusHint(xpos, ypos, 0, _fontHeight); //### ??? // fprintf(stderr, "x/y = %d/%d\txpos/ypos = %d/%d\n", curx, cury, xpos, ypos); _cursorLine = cury; _cursorCol = curx; } #endif // 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. // 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 // scrolling optimizations and cause artifacts. the simple solution here // is to just disable the optimization whilst it is visible if ( _outputSuspendedLabel && _outputSuspendedLabel->isVisible() ) return; // constrain the region to the display // the bottom of the region is capped to the number of lines in the display's // 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) ); // return if there is nothing to do if ( lines == 0 || _image == nullptr || !region.isValid() || (region.top() + abs(lines)) >= region.bottom() || this->_lines <= region.height() ) return; // hide terminal size label to prevent it being scrolled if (_resizeWidget && _resizeWidget->isVisible()) _resizeWidget->hide(); // 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 // given by SCROLLBAR_CONTENT_GAP // // Set the QT_FLUSH_PAINT environment variable to '1' before starting the // application to monitor repainting. // int scrollBarWidth = _scrollBar->isHidden() ? 0 : _scrollBar->style()->styleHint(QStyle::SH_ScrollBar_Transient, nullptr, _scrollBar) ? 0 : _scrollBar->width(); const int SCROLLBAR_CONTENT_GAP = scrollBarWidth == 0 ? 0 : 1; QRect scrollRect; if ( _scrollbarLocation == QTermWidget::ScrollBarLeft ) { scrollRect.setLeft(scrollBarWidth+SCROLLBAR_CONTENT_GAP); scrollRect.setRight(width()); } else { scrollRect.setLeft(0); scrollRect.setRight(width() - scrollBarWidth - SCROLLBAR_CONTENT_GAP); } void* firstCharPos = &_image[ region.top() * this->_columns ]; void* lastCharPos = &_image[ (region.top() + abs(lines)) * this->_columns ]; int top = _topMargin + (region.top() * _fontHeight); int linesToMove = region.height() - abs(lines); int bytesToMove = linesToMove * this->_columns * sizeof(Character); Q_ASSERT( linesToMove > 0 ); Q_ASSERT( bytesToMove > 0 ); //scroll internal image if ( lines > 0 ) { // check that the memory areas that we are going to move are valid Q_ASSERT( (char*)lastCharPos + bytesToMove < (char*)(_image + (this->_lines * this->_columns)) ); Q_ASSERT( (lines*this->_columns) < _imageSize ); //scroll internal image down 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 < (char*)(_image + (this->_lines * this->_columns)) ); //scroll internal image up memmove( lastCharPos , firstCharPos , bytesToMove ); //set region of the display to scroll scrollRect.setTop(top + abs(lines) * _fontHeight); } scrollRect.setHeight(linesToMove * _fontHeight ); Q_ASSERT(scrollRect.isValid() && !scrollRect.isEmpty()); //scroll the display vertically to match internal _image scroll( 0 , _fontHeight * (-lines) , scrollRect ); } QRegion TerminalDisplay::hotSpotRegion() const { QRegion region; const auto hotSpots = _filterChain->hotSpots(); for( Filter::HotSpot* const hotSpot : hotSpots ) { QRect r; if (hotSpot->startLine()==hotSpot->endLine()) { r.setLeft(hotSpot->startColumn()); r.setTop(hotSpot->startLine()); r.setRight(hotSpot->endColumn()); r.setBottom(hotSpot->endLine()); region |= imageToWidget(r);; } else { r.setLeft(hotSpot->startColumn()); r.setTop(hotSpot->startLine()); r.setRight(_columns); r.setBottom(hotSpot->startLine()); region |= imageToWidget(r);; for ( int line = hotSpot->startLine()+1 ; line < hotSpot->endLine() ; line++ ) { r.setLeft(0); r.setTop(line); r.setRight(_columns); r.setBottom(line); region |= imageToWidget(r);; } r.setLeft(0); r.setTop(hotSpot->endLine()); r.setRight(hotSpot->endColumn()); r.setBottom(hotSpot->endLine()); region |= imageToWidget(r);; } } return region; } void TerminalDisplay::processFilters() { if (!_screenWindow) return; QRegion preUpdateHotSpots = hotSpotRegion(); // 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 // out of date at this point _filterChain->setImage( _screenWindow->getImage(), _screenWindow->windowLines(), _screenWindow->windowColumns(), _screenWindow->getLineProperties() ); _filterChain->process(); QRegion postUpdateHotSpots = hotSpotRegion(); update( preUpdateHotSpots | postUpdateHotSpots ); } void TerminalDisplay::updateImage() { if ( !_screenWindow ) return; // optimization - scroll the existing image where possible and // avoid expensive text drawing for parts of the image that // can simply be moved up or down scrollImage( _screenWindow->scrollCount() , _screenWindow->scrollRegion() ); if (!_image) { // Create _image. // The emitted changedContentSizeSignal also leads to getImage being recreated, so do this first. updateImageSize(); } Character* const newimg = _screenWindow->getImage(); int lines = _screenWindow->windowLines(); int columns = _screenWindow->windowColumns(); setScroll( _screenWindow->currentLine() , _screenWindow->lineCount() ); //--added by qinyaning(nyq) to slove the problem of scroll init show--/ setScrollBarPosition(_lines > 1 && _screenWindow->lineCount() > _lines? QTermWidget::ScrollBarRight : QTermWidget::NoScrollBar); //--------------------------------------------------------------------/ Q_ASSERT( this->_usedLines <= this->_lines ); Q_ASSERT( this->_usedColumns <= this->_columns ); int y,x,len; QPoint tL = contentsRect().topLeft(); int tLx = tL.x(); int tLy = tL.y(); _hasBlinker = false; CharacterColor cf; // undefined const int linesToUpdate = qMin(this->_lines, qMax(0,lines )); const int columnsToUpdate = qMin(this->_columns,qMax(0,columns)); auto dirtyMask = new char[columnsToUpdate + 2]; QRegion dirtyRegion; // debugging variable, this records the number of lines that are found to // be 'dirty' ( ie. have changed from the old _image to the new _image ) and // which therefore need to be repainted int dirtyLineCount = 0; for (y = 0; y < linesToUpdate; ++y) { const Character* currentLine = &_image[y*this->_columns]; 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] ) { dirtyMask[x] = 1; } } if (!_resizing) // not while _resizing, we're expecting a paintEvent 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]) { if (newLine[x + 0].character == 0u) { continue; } bool lineDraw = canDraw(newLine[x + 0].character); bool doubleWidth = (x + 1 == columnsToUpdate) ? false : (newLine[x + 1].character == 0); RenditionFlags cr = newLine[x].rendition; CharacterColor clipboard = newLine[x].backgroundColor; if (newLine[x].foregroundColor != cf) { cf = newLine[x].foregroundColor; } const int lln = columnsToUpdate - x; for (len = 1; len < lln; ++len) { const Character& ch = newLine[x+len]; if (!ch.character) continue; // Skip trailing part of multi-col chars. bool nextIsDoubleWidth = (x + len + 1 == columnsToUpdate) ? false : (newLine[x + len + 1].character == 0); if (ch.foregroundColor != cf || ch.backgroundColor != clipboard || (ch.rendition & ~RE_EXTENDED_CHAR) != (cr & ~RE_EXTENDED_CHAR) || (dirtyMask[x + len] == 0) || canDraw(ch.character) != lineDraw || nextIsDoubleWidth != doubleWidth) { break; } } bool saveFixedFont = _fixedFont; if (lineDraw) _fixedFont = false; if (doubleWidth) _fixedFont = false; updateLine = true; _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 //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. 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 ); dirtyRegion |= dirtyRect; } // 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 if ( linesToUpdate < _usedLines ) { 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) , _fontHeight * this->_lines ); } _usedColumns = columnsToUpdate; dirtyRegion |= _inputMethodData.previousPreeditRect; _screenWindow->resetScrollCount(); // update the parts of the display which have changed //--modified and added by qinyaning(nyq) to solve When the screen zooms to 1.25 and 2.75, /*the terminal interface will display colored lines. time: 2020.4.10 14:18 * */ //update(dirtyRegion); update(); //------------------------------------------------- if ( _hasBlinker && !_blinkTimer->isActive()) _blinkTimer->start( TEXT_BLINK_DELAY ); if (!_hasBlinker && _blinkTimer->isActive()) { _blinkTimer->stop(); _blinking = false; } delete[] dirtyMask; } void TerminalDisplay::showResizeNotification() { if (_terminalSizeHint && isVisible()) { if (_terminalSizeStartup) { _terminalSizeStartup=false; return; } if (!_resizeWidget) { const QString label = tr("Size: XXX x XXX"); _resizeWidget = new QLabel(label, this); _resizeWidget->setMinimumWidth(_resizeWidget->fontMetrics().width(label)); _resizeWidget->setMinimumHeight(_resizeWidget->sizeHint().height()); _resizeWidget->setAlignment(Qt::AlignCenter); _resizeWidget->setStyleSheet(QLatin1String("background-color:palette(window);border-style:solid;border-width:1px;border-color:palette(dark)")); _resizeTimer = new QTimer(this); _resizeTimer->setSingleShot(true); connect(_resizeTimer, &QTimer::timeout, this, [this](){ //计时器timeout,终端控件结束调整大小 this->m_bUserIsResizing = false; SessionManager::instance()->setTerminalResizing(_sessionId, m_bUserIsResizing); }); } //显示resizeWidget的时候,标记当前session对应终端控件正在调整大小 SessionManager::instance()->setTerminalResizing(_sessionId, true); _resizeWidget->setText(tr("Size: %1 x %2").arg(_columns).arg(_lines)); _resizeWidget->move((width()-_resizeWidget->width())/2, (height()-_resizeWidget->height())/2+20); //fix bug 17684 在放大,正常窗口,最大化之间切换,终端窗口会显示size _resizeWidget->hide(); _resizeTimer->start(1000); } } void TerminalDisplay::setBlinkingCursor(bool blink) { _hasBlinkingCursor=blink; if (blink && !_blinkCursorTimer->isActive()) _blinkCursorTimer->start(QApplication::cursorFlashTime() / 2); if (!blink && _blinkCursorTimer->isActive()) { _blinkCursorTimer->stop(); if (_cursorBlinking) blinkCursorEvent(); else _cursorBlinking = false; } /******** Modify by n014361 wangpeili 2020-02-13: 修复“设置光标闪烁后,非焦点光标也在闪烁”***********×****/ if (hasFocus()) { focusInEvent(nullptr); } else { focusOutEvent(nullptr); } /***************** Modify by n014361 End *************************/ } void TerminalDisplay::setBlinkingTextEnabled(bool blink) { _allowBlinkingText = blink; if (blink && !_blinkTimer->isActive()) _blinkTimer->start(TEXT_BLINK_DELAY); if (!blink && _blinkTimer->isActive()) { _blinkTimer->stop(); _blinking = false; } } void TerminalDisplay::focusOutEvent(QFocusEvent*) { emit termLostFocus(); // trigger a repaint of the cursor so that it is both visible (in case // it was hidden during blinking) // and drawn in a focused out state _cursorBlinking = false; updateCursor(); _blinkCursorTimer->stop(); if (_blinking) blinkEvent(); _blinkTimer->stop(); } void TerminalDisplay::focusInEvent(QFocusEvent*) { //qDebug()<<"focusInEvent"; emit termGetFocus(); if (_hasBlinkingCursor) { _blinkCursorTimer->start(); } updateCursor(); if (_hasBlinker) _blinkTimer->start(); } void TerminalDisplay::paintEvent( QPaintEvent* pe ) { QPainter paint(this); 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); } // Determine which characters should be repainted (1 region unit = 1 character) QRegion dirtyImageRegion; const QRegion region = pe->region() & contentsRect(); for (const QRect &rect : region) { dirtyImageRegion += widgetToImage(rect); drawBackground(paint, rect, palette().background().color(), true /* use opacity setting */); } // only turn on text anti-aliasing, never turn on normal antialiasing // set https://bugreports.qt.io/browse/QTBUG-66036 paint.setRenderHint(QPainter::TextAntialiasing, _antialiasText); for (const QRect &rect : qAsConst(dirtyImageRegion)) { drawContents(paint, rect); } drawInputMethodPreeditString(paint, preeditRect()); paintFilters(paint); } QPoint TerminalDisplay::cursorPosition() const { if (_screenWindow) return _screenWindow->cursorPosition(); else return {0,0}; } QRect TerminalDisplay::preeditRect() const { const int preeditLength = Character::stringWidth(_inputMethodData.preeditString); if ( preeditLength == 0 ) return {}; return QRect(_leftMargin + _fontWidth*cursorPosition().x(), _topMargin + _fontHeight*cursorPosition().y(), _fontWidth*preeditLength, _fontHeight); } void TerminalDisplay::drawInputMethodPreeditString(QPainter& painter , const QRect& rect) { if ( _inputMethodData.preeditString.isEmpty() ) return; const QPoint cursorPos = cursorPosition(); bool invertColors = false; const QColor background = _colorTable[DEFAULT_BACK_COLOR].color; const QColor foreground = _colorTable[DEFAULT_FORE_COLOR].color; const Character* style = &_image[loc(cursorPos.x(),cursorPos.y())]; drawBackground(painter,rect,background,true); drawCursor(painter,rect,foreground,background,invertColors); drawCharacters(painter,rect,_inputMethodData.preeditString,style,invertColors); _inputMethodData.previousPreeditRect = rect; } FilterChain* TerminalDisplay::filterChain() const { return _filterChain; } void TerminalDisplay::paintFilters(QPainter& painter) { // get color of character under mouse and use it to draw // lines for filters QPoint cursorPos = mapFromGlobal(QCursor::pos()); int cursorLine; int cursorColumn; 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())) ); /***add begin by ut001121 zhangmeng 20200624 光标悬浮在链接上面时变成手形光标 修复BUG34676***/ bool bDrawLineForHotSpotLink = false; // 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(); QListIterator iter(spots); while (iter.hasNext()) { Filter::HotSpot* spot = iter.next(); QRegion region; if ( spot->type() == Filter::HotSpot::Link ) { QRect r; if (spot->startLine()==spot->endLine()) { 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 + 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 + leftMargin, line*_fontHeight + 1 + _topBaseMargin, _columns*_fontWidth - 1 + leftMargin, (line+1)*_fontHeight - 1 + _topBaseMargin ); region |= r; } r.setCoords( 0*_fontWidth + 1 + leftMargin, spot->endLine()*_fontHeight + 1 + _topBaseMargin, spot->endColumn()*_fontWidth - 1 + leftMargin, (spot->endLine()+1)*_fontHeight - 1 + _topBaseMargin ); region |= r; } } 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 // 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++; if ( line == spot->startLine() ) startColumn = spot->startColumn(); if ( line == spot->endLine() ) endColumn = spot->endColumn(); // subtract one pixel from // the right and bottom so that // we do not overdraw adjacent // hotspots // // subtracting one pixel from all sides also prevents an edge case where // 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 + 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( mapFromGlobal(QCursor::pos()) ) ){ painter.drawLine( r.left() , underlinePos , r.right() , underlinePos ); /***add begin by ut001121 zhangmeng 20200624 光标悬浮在链接上面时变成手形光标 修复BUG34676***/ bDrawLineForHotSpotLink = true; } } // Marker hotspots simply have a transparent rectanglular shape // drawn on top of them else if ( spot->type() == Filter::HotSpot::Marker ) { //TODO - Do not use a hardcoded colour for this painter.fillRect(r,QBrush(QColor(255,0,0,120))); } } } /***add begin by ut001121 zhangmeng 20200624 光标悬浮在链接上面时变成手形光标 修复BUG34676***/ /** modify by ut001121 zhangmeng 20201215 for 1040-4 Ctrl键+鼠标点击超链接打开网页 */ if(bDrawLineForHotSpotLink && (QApplication::queryKeyboardModifiers() & Qt::ControlModifier)){ if(cursor().shape() != Qt::PointingHandCursor) { setCursor(Qt::PointingHandCursor); } } else if(cursor().shape() != Qt::IBeamCursor){ setCursor(Qt::IBeamCursor); } /***add end by ut001121***/ } 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 {_leftMargin + topLeftX + left, _topMargin + topLeftY + top, width, _fontHeight}; } static uint baseCodePoint(const Character &ch) { if (ch.rendition & RE_EXTENDED_CHAR) { // sequence of characters ushort extendedCharLength = 0; const uint* chars = ExtendedCharTable::instance.lookupExtendedChar(ch.character, extendedCharLength); return chars[0]; } else { return ch.character; } } void TerminalDisplay::drawContents(QPainter &paint, const QRect &rect) { const int numberOfColumns = _usedColumns; QVector univec; univec.reserve(numberOfColumns); for (int y = rect.y(); y <= rect.bottom(); y++) { int x = rect.x(); if ((_image[loc(rect.x(), y)].character == 0u) && (x != 0)) { x--; // Search for start of multi-column character } int xOffset = 0; for (; x <= rect.right(); x++) { int len = 1; int p = 0; // reset our buffer to the number of columns int bufferSize = numberOfColumns; univec.resize(bufferSize); uint *disstrU = univec.data(); // is this a single character or a sequence of characters ? if ((_image[loc(x, y)].rendition & RE_EXTENDED_CHAR) != 0) { // sequence of characters ushort extendedCharLength = 0; const uint* chars = ExtendedCharTable::instance.lookupExtendedChar(_image[loc(x, y)].character, extendedCharLength); if (chars != nullptr) { Q_ASSERT(extendedCharLength > 1); bufferSize += extendedCharLength - 1; univec.resize(bufferSize); disstrU = univec.data(); for (int index = 0 ; index < extendedCharLength ; index++) { Q_ASSERT(p < bufferSize); disstrU[p++] = chars[index]; } } } else { // single character const uint c = _image[loc(x, y)].character; if (c != 0u) { Q_ASSERT(p < bufferSize); disstrU[p++] = c; } } const bool lineDraw = canDraw(_image[loc(x, y)].character); const bool doubleWidth = (_image[qMin(loc(x, y) + 1, _imageSize - 1)].character == 0); const CharacterColor currentForeground = _image[loc(x, y)].foregroundColor; const CharacterColor currentBackground = _image[loc(x, y)].backgroundColor; const RenditionFlags currentRendition = _image[loc(x, y)].rendition; const QChar::Script currentScript = QChar::script(baseCodePoint(_image[loc(x, y)])); const auto isInsideDrawArea = [&](int column) { return column <= rect.right(); }; const auto hasSameColors = [&](int column) { return _image[loc(column, y)].foregroundColor == currentForeground && _image[loc(column, y)].backgroundColor == currentBackground; }; const auto hasSameRendition = [&](int column) { return (_image[loc(column, y)].rendition & ~RE_EXTENDED_CHAR) == (currentRendition & ~RE_EXTENDED_CHAR); }; const auto hasSameWidth = [&](int column) { const int characterLoc = qMin(loc(column, y) + 1, _imageSize - 1); return (_image[characterLoc].character == 0) == doubleWidth; }; const auto hasSameLineDrawStatus = [&](int column) { return canDraw(_image[loc(column, y)].character) == lineDraw; }; const auto isSameScript = [&](int column) { const QChar::Script script = QChar::script(baseCodePoint(_image[loc(column, y)])); if (currentScript == QChar::Script_Common || script == QChar::Script_Common || currentScript == QChar::Script_Inherited || script == QChar::Script_Inherited) { return true; } return currentScript == script; }; const auto canBeGrouped = [&](int column) { return _image[loc(column, y)].character <= 0x7e || (_image[loc(column, y)].rendition & RE_EXTENDED_CHAR) || (_bidiEnabled && !doubleWidth); }; if (canBeGrouped(x)) { while (isInsideDrawArea(x + len) && hasSameColors(x + len) && hasSameRendition(x + len) && hasSameWidth(x + len) && hasSameLineDrawStatus(x + len) && isSameScript(x + len) && canBeGrouped(x + len)) { const uint c = _image[loc(x + len, y)].character; if ((_image[loc(x + len, y)].rendition & RE_EXTENDED_CHAR) != 0) { // sequence of characters ushort extendedCharLength = 0; const uint* chars = ExtendedCharTable::instance.lookupExtendedChar(c, extendedCharLength); if (chars != nullptr) { Q_ASSERT(extendedCharLength > 1); bufferSize += extendedCharLength - 1; univec.resize(bufferSize); disstrU = univec.data(); for (int index = 0 ; index < extendedCharLength ; index++) { Q_ASSERT(p < bufferSize); disstrU[p++] = chars[index]; } } } else { // single character if (c != 0u) { Q_ASSERT(p < bufferSize); disstrU[p++] = 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++; } } else { // Group spaces following any non-wide character with the character. This allows for // rendering ambiguous characters with wide glyphs without clipping them. while (!doubleWidth && isInsideDrawArea(x + len) && _image[loc(x + len, y)].character == ' ' && hasSameColors(x + len) && hasSameRendition(x + len)) { // disstrU intentionally not modified - trailing spaces are meaningless len++; } } if ((x + len < _usedColumns) && (_image[loc(x + len, y)].character == 0u)) { len++; // Adjust for trailing part of multi-column character } const bool save__fixedFont = _fixedFont; if (lineDraw) { _fixedFont = false; } if (doubleWidth) { _fixedFont = false; } univec.resize(p); // Create a text scaling matrix for double width and double height lines. QMatrix textScale; if (y < _lineProperties.size()) { if ((_lineProperties[y] & LINE_DOUBLEWIDTH) != 0) { textScale.scale(2, 1); } if ((_lineProperties[y] & LINE_DOUBLEHEIGHT) != 0) { textScale.scale(1, 2); } } //Apply text scaling matrix. paint.setWorldTransform(QTransform(textScale), true); //calculate the area in which the text will be drawn QString unistr = QString::fromUcs4(univec.data(), univec.length()); QRect textArea ; if(IsCodecGB18030()){ QFontMetrics fm(paint.font()); int textWidth = fm.size(Qt::TextSingleLine | Qt::TextExpandTabs,unistr).width(); textArea =QRect(contentsRect().left() + contentsRect().left() +xOffset, contentsRect().top() + contentsRect().top() + _fontHeight * y, textWidth, _fontHeight); xOffset += textWidth; }else{ textArea = QRect(contentsRect().left() + contentsRect().left() + _fontWidth * x, contentsRect().top() + contentsRect().top() + _fontHeight * y, _fontWidth * len, _fontHeight); } //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 //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) textArea.moveTopLeft(textScale.inverted().map(textArea.topLeft())); //paint text fragment drawTextFragment(paint, textArea, unistr, &_image[loc(x, y)]); _fixedFont = save__fixedFont; //reset back to single-width, single-height _lines paint.setWorldTransform(QTransform(textScale.inverted()), true); if (y < _lineProperties.size() - 1) { //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, //we can therefore skip the next line if ((_lineProperties[y] & LINE_DOUBLEHEIGHT) != 0) { y++; } } x += len - 1; } } } void TerminalDisplay::blinkEvent() { if (!_allowBlinkingText) return; _blinking = !_blinking; //TODO: Optimize to only repaint the areas of the widget // where there is blinking text // rather than repainting the whole widget. update(); } QRect TerminalDisplay::imageToWidget(const QRect& imageArea) const { QRect result; result.setLeft( _leftMargin + _fontWidth * imageArea.left() ); result.setTop( _topMargin + _fontHeight * imageArea.top() ); result.setWidth( _fontWidth * imageArea.width() ); result.setHeight( _fontHeight * imageArea.height() ); return result; } QRect TerminalDisplay::widgetToImage(const QRect &widgetArea) const { QRect result; result.setLeft(qMin(_usedColumns - 1, qMax(0, (widgetArea.left()) / _fontWidth ))); result.setTop(qMin(_usedLines - 1, qMax(0, (widgetArea.top()) / _fontHeight))); result.setRight(qMin(_usedColumns - 1, qMax(0, (widgetArea.right()) / _fontWidth ))); result.setBottom(qMin(_usedLines - 1, qMax(0, (widgetArea.bottom()) / _fontHeight))); return result; } void TerminalDisplay::updateCursor() { QRect cursorRect = imageToWidget( QRect(cursorPosition(),QSize(1,1)) ); update(cursorRect); } void TerminalDisplay::blinkCursorEvent() { _cursorBlinking = !_cursorBlinking; updateCursor(); } /* ------------------------------------------------------------------------- */ /* */ /* Resizing */ /* */ /* ------------------------------------------------------------------------- */ void TerminalDisplay::resizeEvent(QResizeEvent*) { initKeyBoardSelection(); updateImageSize(); processFilters(); } void TerminalDisplay::propagateSize() { if (_isFixedSize) { setSize(_columns, _lines); QWidget::setFixedSize(sizeHint()); parentWidget()->adjustSize(); parentWidget()->setFixedSize(parentWidget()->sizeHint()); return; } if (_image) updateImageSize(); } void TerminalDisplay::updateImageSize() { Character* oldimg = _image; int oldlin = _lines; int oldcol = _columns; makeImage(); // copy the old image to reduce flicker int lines = qMin(oldlin,_lines); int columns = qMin(oldcol,_columns); if (oldimg) { for (int line = 0; line < lines; line++) { memcpy((void*)&_image[_columns*line], (void*)&oldimg[oldcol*line],columns*sizeof(Character)); } delete[] oldimg; } if (_screenWindow) _screenWindow->setWindowLines(_lines); _resizing = (oldlin!=_lines) || (oldcol!=_columns); if ( _resizing ) { showResizeNotification(); emit changedContentSizeSignal(oldlin, oldcol); // expose resizeEvent } _resizing = false; } //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 void TerminalDisplay::showEvent(QShowEvent*) { emit changedContentSizeSignal(_contentHeight,_contentWidth); } void TerminalDisplay::hideEvent(QHideEvent*) { emit changedContentSizeSignal(_contentHeight,_contentWidth); } /* ------------------------------------------------------------------------- */ /* */ /* Scrollbar */ /* */ /* ------------------------------------------------------------------------- */ void TerminalDisplay::scrollBarPositionChanged(int) { 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, // that is, scroll down automatically // to how new _lines as they are added const bool atEndOfOutput = (_scrollBar->value() == _scrollBar->maximum()); _screenWindow->setTrackOutput( atEndOfOutput ); updateImage(); } void TerminalDisplay::setScroll(int cursor, int slines) { // update _scrollBar if the range or value has changed, // otherwise return // // setting the range or value of a _scrollBar will always trigger // a repaint, so it should be avoided if it is not necessary if ( _scrollBar->minimum() == 0 && _scrollBar->maximum() == (slines - _lines) && _scrollBar->value() == cursor ) { return; } disconnect(_scrollBar, SIGNAL(valueChanged(int)), this, SLOT(scrollBarPositionChanged(int))); _scrollBar->setRange(0,slines - _lines); _scrollBar->setSingleStep(1); _scrollBar->setPageStep(_lines); _scrollBar->setValue(cursor); connect(_scrollBar, SIGNAL(valueChanged(int)), this, SLOT(scrollBarPositionChanged(int))); } void TerminalDisplay::scrollToEnd() { disconnect(_scrollBar, SIGNAL(valueChanged(int)), this, SLOT(scrollBarPositionChanged(int))); _scrollBar->setValue( _scrollBar->maximum() ); connect(_scrollBar, SIGNAL(valueChanged(int)), this, SLOT(scrollBarPositionChanged(int))); _screenWindow->scrollTo( _scrollBar->value() + 1 ); _screenWindow->setTrackOutput( _screenWindow->atEndOfOutput() ); } void TerminalDisplay::setScrollBarPosition(QTermWidget::ScrollBarPosition position) { if (_scrollbarLocation == position) return; if ( position == QTermWidget::NoScrollBar ) _scrollBar->hide(); else _scrollBar->show(); _topMargin = _leftMargin = 1; _scrollbarLocation = position; propagateSize(); update(); } void TerminalDisplay::initSelectionStates() { if (!_screenWindow) { return; } _selStartColumn = _screenWindow->cursorPosition().x(); _selStartLine = _screenWindow->cursorPosition().y(); _selEndColumn = _selStartColumn; _selEndLine = _selStartLine; } void TerminalDisplay::initKeyBoardSelection() { _selBegin = false; initSelectionStates(); } void TerminalDisplay::mousePressEvent(QMouseEvent* ev) { //判断有鼠标点击的时候,初始化键盘选择状态 initKeyBoardSelection(); if ( _possibleTripleClick && (ev->button()==Qt::LeftButton) ) { mouseTripleClickEvent(ev); return; } if ( !contentsRect().contains(ev->pos()) ) return; if ( !_screenWindow ) return; int charLine; int charColumn; getCharacterPosition(ev->pos(),charLine,charColumn); QPoint pos = QPoint(charColumn,charLine); if ( ev->button() == Qt::LeftButton) { _lineSelectionMode = false; _wordSelectionMode = false; if(!hasFocus()) { setFocus(); } emit leftMouseClick(); 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 ) { // The user clicked inside selected text dragInfo.state = diPending; dragInfo.start = ev->pos(); } else { // No reason to ever start a drag event dragInfo.state = diNone; _preserveLineBreaks = !( ( ev->modifiers() & Qt::ControlModifier ) && !(ev->modifiers() & Qt::AltModifier) ); _columnSelectionMode = (ev->modifiers() & Qt::AltModifier) && (ev->modifiers() & Qt::ControlModifier); if (_mouseMarks || (ev->modifiers() & Qt::ShiftModifier)) { _screenWindow->clearSelection(); //emit clearSelectionSignal(); pos.ry() += _scrollBar->value(); _iPntSel = _pntSel = pos; _actSel = 1; // left mouse button pressed but nothing selected yet. } else { emit mouseSignal( 0, charColumn + 1, charLine + 1 +_scrollBar->value() -_scrollBar->maximum() , 0); } Filter::HotSpot *spot = _filterChain->hotSpotAt(charLine, charColumn); if (spot && spot->type() == Filter::HotSpot::Link) spot->activate(QLatin1String("click-action")); } } else if ( ev->button() == Qt::MidButton ) { 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)) emit configureRequest(ev->pos()); else emit mouseSignal( 2, charColumn +1, charLine +1 +_scrollBar->value() -_scrollBar->maximum() , 0); } /******** Modify by m000714 daizhengwen 2020-04-28: 调用父类的QMousePressEvent****************/ QWidget::mousePressEvent(ev); /********************* Modify by m000714 daizhengwen End ************************/ } QList TerminalDisplay::filterActions(const QPoint& position) { int charLine, charColumn; getCharacterPosition(position,charLine,charColumn); Filter::HotSpot* spot = _filterChain->hotSpotAt(charLine,charColumn); return spot ? spot->actions() : QList(); } void TerminalDisplay::mouseMoveEvent(QMouseEvent* ev) { int charLine = 0; int charColumn = 0; int leftMargin = _leftBaseMargin + ((_scrollbarLocation == QTermWidget::ScrollBarLeft && !_scrollBar->style()->styleHint(QStyle::SH_ScrollBar_Transient, nullptr, _scrollBar)) ? _scrollBar->width() : 0); getCharacterPosition(ev->pos(),charLine,charColumn); // handle filters // change link hot-spot appearance on mouse-over Filter::HotSpot* spot = _filterChain->hotSpotAt(charLine,charColumn); if ( spot && spot->type() == Filter::HotSpot::Link) { QRegion previousHotspotArea = _mouseOverHotspotArea; _mouseOverHotspotArea = QRegion(); QRect r; if (spot->startLine()==spot->endLine()) { 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 + 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 + leftMargin, line*_fontHeight + _topBaseMargin, _columns*_fontWidth + leftMargin, (line+1)*_fontHeight + _topBaseMargin ); _mouseOverHotspotArea |= r; } r.setCoords( 0*_fontWidth + leftMargin, spot->endLine()*_fontHeight + _topBaseMargin, spot->endColumn()*_fontWidth + leftMargin, (spot->endLine()+1)*_fontHeight + _topBaseMargin ); _mouseOverHotspotArea |= r; } update( _mouseOverHotspotArea | previousHotspotArea ); } else if ( !_mouseOverHotspotArea.isEmpty() ) { update( _mouseOverHotspotArea ); // 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 // then emit a mouse movement signal, unless the shift // key is being held down, which overrides this. if (!_mouseMarks && !(ev->modifiers() & Qt::ShiftModifier)) { int button = 3; if (ev->buttons() & Qt::LeftButton) button = 0; if (ev->buttons() & Qt::MidButton) button = 1; if (ev->buttons() & Qt::RightButton) button = 2; emit mouseSignal( button, charColumn + 1, charLine + 1 +_scrollBar->value() -_scrollBar->maximum(), 1 ); return; } 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 // 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) { // 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) { // this isn't technically needed because mouseMoveEvent is suppressed during // Qt drag operations, replaced by dragMoveEvent return; } if (_actSel == 0) return; // don't extend selection while pasting if (ev->buttons() & Qt::MidButton) return; extendSelection( ev->pos() ); } void TerminalDisplay::extendSelection( const QPoint& position ) { QPoint pos = position; if ( !_screenWindow ) return; //if ( !contentsRect().contains(ev->pos()) ) return; QPoint tL = contentsRect().topLeft(); int tLx = tL.x(); int tLy = tL.y(); int scroll = _scrollBar->value(); // we're in the process of moving the mouse with the left button pressed // the mouse cursor will kept caught within the bounds of the text in // this widget. int linesBeyondWidget = 0; QRect textBounds(tLx + _leftMargin, tLy + _topMargin, _usedColumns*_fontWidth-1, _usedLines*_fontHeight-1); // 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() ) { linesBeyondWidget = (oldpos.y()-textBounds.bottom()) / _fontHeight; _scrollBar->setValue(_scrollBar->value()+linesBeyondWidget+1); // scrollforward } if ( oldpos.y() < textBounds.top() ) { linesBeyondWidget = (textBounds.top()-oldpos.y()) / _fontHeight; _scrollBar->setValue(_scrollBar->value()-linesBeyondWidget-1); // history } int charColumn = 0; int charLine = 0; getCharacterPosition(pos,charLine,charColumn); QPoint here = QPoint(charColumn,charLine); //QPoint((pos.x()-tLx-_leftMargin+(_fontWidth/2))/_fontWidth,(pos.y()-tLy-_topMargin)/_fontHeight); QPoint ohere; QPoint _iPntSelCorr = _iPntSel; _iPntSelCorr.ry() -= _scrollBar->value(); QPoint _pntSelCorr = _pntSel; _pntSelCorr.ry() -= _scrollBar->value(); bool swapping = false; if ( _wordSelectionMode ) { // Extend to word boundaries int i; QChar selClass; bool left_not_right = ( here.y() < _iPntSelCorr.y() || ( here.y() == _iPntSelCorr.y() && here.x() < _iPntSelCorr.x() ) ); bool old_left_not_right = ( _pntSelCorr.y() < _iPntSelCorr.y() || ( _pntSelCorr.y() == _iPntSelCorr.y() && _pntSelCorr.x() < _iPntSelCorr.x() ) ); swapping = left_not_right != old_left_not_right; // Find left (left_not_right ? from here : from start) QPoint left = left_not_right ? here : _iPntSelCorr; 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) )) && charClass(_image[i-1].character) == selClass ) { i--; if (left.x()>0) left.rx()--; else {left.rx()=_usedColumns-1; left.ry()--;} } } // Find left (left_not_right ? from start : from here) QPoint right = left_not_right ? _iPntSelCorr : here; 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) )) && charClass(_image[i+1].character) == selClass ) { i++; if (right.x()<_usedColumns-1) right.rx()++; else {right.rx()=0; right.ry()++; } } } // Pick which is start (ohere) and which is extension (here) if ( left_not_right ) { here = left; ohere = right; } else { here = right; ohere = left; } ohere.rx()++; } if ( _lineSelectionMode ) { // Extend to complete line bool above_not_below = ( here.y() < _iPntSelCorr.y() ); QPoint above = above_not_below ? here : _iPntSelCorr; QPoint below = above_not_below ? _iPntSelCorr : here; while (above.y()>0 && (_lineProperties[above.y()-1] & LINE_WRAPPED) ) above.ry()--; while (below.y()<_usedLines-1 && (_lineProperties[below.y()] & LINE_WRAPPED) ) below.ry()++; above.setX(0); below.setX(_usedColumns-1); // Pick which is start (ohere) and which is extension (here) if ( above_not_below ) { here = above; ohere = below; } else { here = below; ohere = above; } QPoint newSelBegin = QPoint( ohere.x(), ohere.y() ); swapping = !(_tripleSelBegin==newSelBegin); _tripleSelBegin = newSelBegin; ohere.rx()++; } int offset = 0; if ( !_wordSelectionMode && !_lineSelectionMode ) { QChar selClass; bool left_not_right = ( here.y() < _iPntSelCorr.y() || ( here.y() == _iPntSelCorr.y() && here.x() < _iPntSelCorr.x() ) ); bool old_left_not_right = ( _pntSelCorr.y() < _iPntSelCorr.y() || ( _pntSelCorr.y() == _iPntSelCorr.y() && _pntSelCorr.x() < _iPntSelCorr.x() ) ); swapping = left_not_right != old_left_not_right; // Find left (left_not_right ? from here : from start) QPoint left = left_not_right ? here : _iPntSelCorr; // Find left (left_not_right ? from start : from here) QPoint right = left_not_right ? _iPntSelCorr : here; if ( right.x() > 0 && !_columnSelectionMode ) { int i = loc(right.x(),right.y()); if (i>=0 && i<=_imageSize) { selClass = charClass(_image[i-1].character); /* if (selClass == ' ') { 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) right = left_not_right ? _iPntSelCorr : here; else right.rx()++; // will be balanced later because of offset=-1; }*/ } } // Pick which is start (ohere) and which is extension (here) if ( left_not_right ) { here = left; ohere = right; offset = 0; } else { here = right; ohere = left; offset = -1; } } if ((here == _pntSelCorr) && (scroll == _scrollBar->value())) return; // not moved if (here == ohere) return; // It's not left, it's not right. if ( _actSel < 2 || swapping ) { if ( _columnSelectionMode && !_lineSelectionMode && !_wordSelectionMode ) { _screenWindow->setSelectionStart( ohere.x() , ohere.y() , true ); } else { _screenWindow->setSelectionStart( ohere.x()-1-offset , ohere.y() , false ); } } _actSel = 2; // within selection _pntSel = here; _pntSel.ry() += _scrollBar->value(); if ( _columnSelectionMode && !_lineSelectionMode && !_wordSelectionMode ) { _screenWindow->setSelectionEnd( here.x() , here.y() ); } else { _screenWindow->setSelectionEnd( here.x()+offset , here.y() ); } } void TerminalDisplay::mouseReleaseEvent(QMouseEvent* ev) { if ( !_screenWindow ) return; int charLine; int charColumn; getCharacterPosition(ev->pos(),charLine,charColumn); if ( ev->button() == Qt::LeftButton) { emit isBusySelecting(false); if(dragInfo.state == diPending) { // We had a drag event pending but never confirmed. Kill selection _screenWindow->clearSelection(); //emit clearSelectionSignal(); } else { if ( _actSel > 1 ) { setSelection( _screenWindow->selectedText(currentDecodingOptions()) ); } _actSel = 0; //FIXME: emits a release event even if the mouse is // outside the range. The procedure used in `mouseMoveEvent' // applies here, too. if (!_mouseMarks && !(ev->modifiers() & Qt::ShiftModifier)) emit mouseSignal( 0, charColumn + 1, charLine + 1 +_scrollBar->value() -_scrollBar->maximum() , 2); } dragInfo.state = diNone; } if ( !_mouseMarks && ((ev->button() == Qt::RightButton && !(ev->modifiers() & Qt::ShiftModifier)) || ev->button() == Qt::MidButton) ) { 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 { line = (widgetPoint.y()-contentsRect().top()-_topMargin) / _fontHeight; if (line < 0) line = 0; if (line >= _usedLines) line = _usedLines - 1; int x = widgetPoint.x() + _fontWidth / 2 - contentsRect().left() - _leftMargin; if ( _fixedFont ) column = x / _fontWidth; else { column = 0; while(column + 1 < _usedColumns && x > textWidth(0, column + 1, line)) column++; } if ( column < 0 ) column = 0; // the column value returned can be equal to _usedColumns, which // is the position just after the last character displayed in a line. // // this is required so that the user can select characters in the right-most // column (or left-most for right-to-left input) if ( column > _usedColumns ) column = _usedColumns; } void TerminalDisplay::setHideCursor(bool hideCursor) { _hideCursor = hideCursor; update(); } void TerminalDisplay::setSessionId(int sessionId) { _sessionId = sessionId; _filterChain->setSessionId(sessionId); } void TerminalDisplay::updateFilters() { if ( !_screenWindow ) return; processFilters(); } void TerminalDisplay::updateLineProperties() { if ( !_screenWindow ) return; _lineProperties = _screenWindow->getLineProperties(); } void TerminalDisplay::mouseDoubleClickEvent(QMouseEvent* ev) { if ( ev->button() != Qt::LeftButton) return; if ( !_screenWindow ) return; int charLine = 0; int charColumn = 0; getCharacterPosition(ev->pos(),charLine,charColumn); QPoint pos(charColumn,charLine); // pass on double click as two clicks. if (!_mouseMarks && !(ev->modifiers() & Qt::ShiftModifier)) { // 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, pos.y()+1 +_scrollBar->value() -_scrollBar->maximum(), 0 ); // left button return; } _screenWindow->clearSelection(); QPoint bgnSel = pos; QPoint endSel = pos; int i = loc(bgnSel.x(),bgnSel.y()); _iPntSel = bgnSel; _iPntSel.ry() += _scrollBar->value(); _wordSelectionMode = true; // find word boundaries... QChar selClass = charClass(_image[i].character); { // find the start of the word int x = bgnSel.x(); while ( ((x>0) || (bgnSel.y()>0 && (_lineProperties[bgnSel.y()-1] & LINE_WRAPPED) )) && charClass(_image[i-1].character) == selClass ) { i--; if (x>0) x--; else { x=_usedColumns-1; bgnSel.ry()--; } } bgnSel.setX(x); _screenWindow->setSelectionStart( bgnSel.x() , bgnSel.y() , false ); // 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) )) && charClass(_image[i+1].character) == selClass ) { 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 ) == QLatin1Char('@') ) && ( ( endSel.x() - bgnSel.x() ) > 0 ) ) endSel.setX( x - 1 ); _actSel = 2; // within selection _screenWindow->setSelectionEnd( endSel.x() , endSel.y() ); setSelection( _screenWindow->selectedText(currentDecodingOptions()) ); } _possibleTripleClick=true; QTimer::singleShot(QApplication::doubleClickInterval(),this, SLOT(tripleClickTimeout())); } void TerminalDisplay::wheelEvent( QWheelEvent* ev ) { // 当前窗口被激活,且有焦点,不处理Ctrl+滚轮事件 if (isActiveWindow() && hasFocus()) { if (ev->modifiers() == Qt::ControlModifier) { QWidget::wheelEvent(ev); return; } } //判断有鼠标滚轮滚动的时候,初始化键盘选择状态 initKeyBoardSelection(); if (ev->orientation() != Qt::Vertical) return; // if the terminal program is not interested mouse events // then send the event to the scrollbar if the slider has room to move // or otherwise send simulated up / down key presses to the terminal program // for the benefit of programs such as 'less' if ( _mouseMarks && _scrollBar->maximum() > 0) { _scrollBar->event(ev); } else if(_mouseMarks && !SessionManager::instance()->idToSession(_sessionId)->isPrimaryScreen() && _alternateScrolling) { // assume that each Up / Down key event will cause the terminal application // 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, // giving a scroll of 3 lines int key = ev->delta() > 0 ? Qt::Key_Up : Qt::Key_Down; // QWheelEvent::delta() gives rotation in eighths of a degree int wheelDegrees = ev->delta() / 8; int linesToScroll = abs(wheelDegrees) / 5; QKeyEvent keyScrollEvent(QEvent::KeyPress,key,Qt::NoModifier); for (int i=0;ipos() , charLine , charColumn ); emit mouseSignal( ev->delta() > 0 ? 4 : 5, charColumn + 1, charLine + 1 +_scrollBar->value() -_scrollBar->maximum() , 0); } } void TerminalDisplay::tripleClickTimeout() { _possibleTripleClick=false; } Screen::DecodingOptions TerminalDisplay::currentDecodingOptions() { Screen::DecodingOptions decodingOptions; if (_preserveLineBreaks) { decodingOptions |= Screen::PreserveLineBreaks; } return decodingOptions; } void TerminalDisplay::mouseTripleClickEvent(QMouseEvent* ev) { if ( !_screenWindow ) return; int charLine; int charColumn; getCharacterPosition(ev->pos(),charLine,charColumn); _iPntSel = QPoint(charColumn,charLine); _screenWindow->clearSelection(); _lineSelectionMode = true; _wordSelectionMode = false; _actSel = 2; // within selection emit isBusySelecting(true); // Keep it steady... 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) || (_iPntSel.y()>0 && (_lineProperties[_iPntSel.y()-1] & LINE_WRAPPED) ) ) && charClass(_image[i-1].character) == selClass ) { i--; if (x>0) x--; else { x=_columns-1; _iPntSel.ry()--; } } _screenWindow->setSelectionStart( x , _iPntSel.y() , false ); _tripleSelBegin = QPoint( x, _iPntSel.y() ); } else if (_tripleClickMode == SelectWholeLine) { _screenWindow->setSelectionStart( 0 , _iPntSel.y() , false ); _tripleSelBegin = QPoint( 0, _iPntSel.y() ); } while (_iPntSel.y()<_lines-1 && (_lineProperties[_iPntSel.y()] & LINE_WRAPPED) ) _iPntSel.ry()++; _screenWindow->setSelectionEnd( _columns - 1 , _iPntSel.y() ); setSelection(_screenWindow->selectedText(currentDecodingOptions())); _iPntSel.ry() += _scrollBar->value(); } bool TerminalDisplay::focusNextPrevChild( bool next ) { if (next) return false; // This disables changing the active part in konqueror // when pressing Tab return QWidget::focusNextPrevChild( next ); } QChar TerminalDisplay::charClass(QChar qch) const { if ( qch.isSpace() ) return QLatin1Char(' '); if ( qch.isLetterOrNumber() || _wordCharacters.contains(qch, Qt::CaseInsensitive ) ) return QLatin1Char('a'); return qch; } void TerminalDisplay::setWordCharacters(const QString& wc) { _wordCharacters = wc; } void TerminalDisplay::setUsesMouse(bool on) { if (_mouseMarks != on) { _mouseMarks = on; setCursor( _mouseMarks ? Qt::IBeamCursor : Qt::ArrowCursor ); emit usesMouseChanged(); } } void TerminalDisplay::setAlternateScrolling(bool enable) { _alternateScrolling = enable; } bool TerminalDisplay::usesMouse() const { return _mouseMarks; } void TerminalDisplay::setBracketedPasteMode(bool on) { _bracketedPasteMode = on; } bool TerminalDisplay::bracketedPasteMode() const { return _bracketedPasteMode; } /* ------------------------------------------------------------------------- */ /* */ /* Clipboard */ /* */ /* ------------------------------------------------------------------------- */ #undef KeyPress void TerminalDisplay::emitSelection(bool useXselection,bool appendReturn) { if ( !_screenWindow ) return; // Paste Clipboard by simulating keypress events QString text = QApplication::clipboard()->text(useXselection ? QClipboard::Selection : QClipboard::Clipboard); if(appendReturn) text.append(QLatin1Char('\r')); if ( ! text.isEmpty() ) { 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) { /******** Modify by n014361 wangpeili 2020-02-12: 自动拷贝功能,需发出可拷贝信号***********×****/ if(t != QApplication::clipboard()->text(QClipboard::Clipboard)) { selectionChanged(); } QApplication::clipboard()->setText(t, QClipboard::Selection); /***************** Modify by n014361 End *************************/ } /******************************************************************** 1. @函数: setSelectionAll 2. @作者: 王培利 3. @日期: 2020-02-13 4. @说明: 屏幕全选功能 ********************************************************************/ void TerminalDisplay::setSelectionAll() { _screenWindow->setSelectionAll(); setSelection(_screenWindow->selectedText(currentDecodingOptions())); } void TerminalDisplay::copyClipboard() { if ( !_screenWindow ) return; QString text = _screenWindow->selectedText(currentDecodingOptions()); if (!text.isEmpty()) QApplication::clipboard()->setText(text); } void TerminalDisplay::pasteClipboard() { emitSelection(false,false); } void TerminalDisplay::pasteSelection() { emitSelection(true,false); } /* ------------------------------------------------------------------------- */ /* */ /* Keyboard */ /* */ /* ------------------------------------------------------------------------- */ void TerminalDisplay::setFlowControlWarningEnabled( bool enable ) { _flowControlWarningEnabled = enable; // if the dialog is currently visible and the flow control warning has // been disabled then hide the dialog if (!enable) outputSuspended(false); } void TerminalDisplay::setMotionAfterPasting(MotionAfterPasting action) { mMotionAfterPasting = action; } int TerminalDisplay::motionAfterPasting() { return mMotionAfterPasting; } //在使用键盘选择文字之前,判断如果光标位置不是当前已选择区域的起点,则重新初始化选择状态 void TerminalDisplay::checkAndInitSelectionState() { if (_selStartColumn != _screenWindow->cursorPosition().x() || _selStartLine != _screenWindow->cursorPosition().y() ) { qDebug() << "checkAndInitSelectionState!" << endl; initKeyBoardSelection(); } } void TerminalDisplay::keyPressEvent( QKeyEvent* event ) { bool emitKeyPressSignal = true; // Keyboard-based navigation if ( event->modifiers() == Qt::ShiftModifier ) { bool update = true; //列的index从0开始,所以最大index需要减1 int maxColumnIndex = _screenWindow->windowColumns() - 1; if ( event->key() == Qt::Key_PageUp ) { if (_scrollBar->value() != _scrollBar->maximum()) { initKeyBoardSelection(); } _screenWindow->scrollBy( ScreenWindow::ScrollPages , -1 ); } else if ( event->key() == Qt::Key_PageDown ) { if (_scrollBar->value() != _scrollBar->maximum()) { initKeyBoardSelection(); } _screenWindow->scrollBy( ScreenWindow::ScrollPages , 1 ); } else if ( event->key() == Qt::Key_Left ) { if (!_selBegin) { checkAndInitSelectionState(); _selBegin = true; //键盘按下时设置--开始选择 //判断只有开始结束选择位置相等时,才允许开始选择 if (_selStartLine == _selEndLine && _selStartColumn == _selEndColumn) { _screenWindow->scrollTo(_scrollBar->maximum()); qDebug() << "left selection start"; _screenWindow->setSelectionStart(_selStartColumn, _selStartLine, false); } } else { //每一格设置一次选择结束状态,这样才能看到选择的区域;键盘一直按住则一直选 _screenWindow->setSelectionEnd(_selEndColumn, _selEndLine); } //向左选择 if (_selEndColumn >= 1) { _selEndColumn--; } //左键选择到最左边的时候,向上选中上一行末尾(如果当前没到第一行的话) else if (_selEndLine > 0) { _selEndColumn = maxColumnIndex; _selEndLine--; } qDebug() << "left: _selStartColumn" << _selStartColumn << "_selStartLine" << _selStartLine << "_selEndColumn" << _selEndColumn << "_selEndLine" << _selEndLine; } else if ( event->key() == Qt::Key_Right ) { if (!_selBegin) { checkAndInitSelectionState(); _selBegin = true; //键盘按下时设置--开始选择 if (_selStartLine == _selEndLine && _selStartColumn == _selEndColumn) { //滚动到光标所在位置开始选择 _screenWindow->scrollTo(_scrollBar->maximum()); //开始选择 qDebug() << "right selection start"; _screenWindow->setSelectionStart(_selStartColumn, _selStartLine, false); } } else { _screenWindow->setSelectionEnd(_selEndColumn, _selEndLine); } //向右选择,最大行数为屏幕当前显示的最大行数(即屏幕当前显示了多少行就算多少行,并不包含历史行的行数) int maxLineIndex = _screenWindow->windowLines() - 1; //向右选择 if (_selEndColumn < maxColumnIndex) { _selEndColumn++; } //右边到了最右边时,向下选中下一行的开头(如果当前没到最后一行的话) else if (_selEndLine < maxLineIndex) { _selEndColumn = 0; _selEndLine++; } qDebug() << "maxLineIndex: " << maxLineIndex << endl; qDebug() << "right: _selStartColumn" << _selStartColumn << "_selStartLine" << _selStartLine << "_selEndColumn" << _selEndColumn << "_selEndLine" << _selEndLine; } else if ( event->key() == Qt::Key_Up ) { //使用了Shift+上下键,由于屏幕发生滚动,会导致计算的行列位置不对,需要重新初始化选择状态 initKeyBoardSelection(); _screenWindow->scrollBy( ScreenWindow::ScrollLines , -1 ); } else if ( event->key() == Qt::Key_Down ) { //使用了Shift+上下键,由于屏幕发生滚动,会导致计算的行列位置不对,需要重新初始化选择状态 initKeyBoardSelection(); _screenWindow->scrollBy( ScreenWindow::ScrollLines , 1 ); } else if ( event->key() == Qt::Key_End) { scrollToEnd(); } else if ( event->key() == Qt::Key_Home) { //使用了Shift+Home键,由于屏幕发生滚动,会导致计算的行列位置不对,需要重新初始化选择状态 initKeyBoardSelection(); _screenWindow->scrollTo(0); } else { update = false; } if ( update ) { _screenWindow->setTrackOutput( _screenWindow->atEndOfOutput() ); updateLineProperties(); updateImage(); // do not send key press to terminal emitKeyPressSignal = false; } } else { initKeyBoardSelection(); } _actSel=0; // Key stroke implies a screen update, so TerminalDisplay won't // know where the current selection is. if (_hasBlinkingCursor) { _blinkCursorTimer->start(QApplication::cursorFlashTime() / 2); if (_cursorBlinking) blinkCursorEvent(); else _cursorBlinking = false; } if ( emitKeyPressSignal ) { emit keyPressedSignal(event); /******** Modify by wangpeili n014361 2020-02-14: 按键滚动功能***********/ // 按键滚动原为默认。现在修改为可以设置是否滚动 // 暂时取消了原系统shift/alt/ctrl键的单独跳转功能。 switch (mMotionAfterPasting) { case MoveStartScreenWindow: _screenWindow->scrollTo(0); break; case MoveEndScreenWindow: if (!(event->key() == Qt::Key_Control || event->key() == Qt::Key_Shift || event->key() == Qt::Key_Alt)) { scrollToEnd(); } break; case NoMoveScreenWindow: break; } /***************** Modify by wangpeili n014361 End *****************/ } event->accept(); } void TerminalDisplay::keyReleaseEvent(QKeyEvent *event) { //处理使用Shift+左右键选择文字,处理键盘释放的情况 if ( event->modifiers() == Qt::ShiftModifier ) { if ( event->key() == Qt::Key_Left ) { //由于会有一定概率出现,长按后再同时短按一次Shift+左或者右方向键,出现一次选择两个字符的情况 //这里做了一个数据纠正 if (2 == abs(_lastLeftEndColumn - _selEndColumn)) { _selEndColumn = _lastEndColumn; } _screenWindow->setSelectionEnd(_selEndColumn, _selEndLine); _lastLeftEndColumn = _selEndColumn; setSelection( _screenWindow->selectedText(currentDecodingOptions()) ); } else if ( event->key() == Qt::Key_Right) { //由于会有一定概率出现,长按后再短按Shift+左或者右方向键,出现一次选择两个字符的情况 //这里做了一个数据纠正 if (2 == abs(_lastRightEndColumn - _selEndColumn)) { _selEndColumn = _lastEndColumn; } _screenWindow->setSelectionEnd(_selEndColumn, _selEndLine); _lastRightEndColumn = _selEndColumn; setSelection( _screenWindow->selectedText(currentDecodingOptions()) ); } else { _selBegin = false; _lastEndColumn = _selEndColumn; } } event->accept(); } void TerminalDisplay::inputMethodEvent( QInputMethodEvent* event ) { QKeyEvent keyEvent(QEvent::KeyPress,0,Qt::NoModifier,event->commitString()); emit keyPressedSignal(&keyEvent); _inputMethodData.preeditString = event->preeditString(); update(preeditRect() | _inputMethodData.previousPreeditRect); event->accept(); } QVariant TerminalDisplay::inputMethodQuery( Qt::InputMethodQuery query ) const { const QPoint cursorPos = _screenWindow ? _screenWindow->cursorPosition() : QPoint(0,0); switch ( query ) { case Qt::ImMicroFocus: return imageToWidget(QRect(cursorPos.x(),cursorPos.y(),1,1)); break; case Qt::ImFont: return font(); break; case Qt::ImCursorPosition: // return the cursor position within the current line return cursorPos.x(); break; case Qt::ImSurroundingText: { // return the text from the current line QString lineText; QTextStream stream(&lineText); PlainTextDecoder decoder; decoder.begin(&stream); decoder.decodeLine(&_image[loc(0,cursorPos.y())],_usedColumns,_lineProperties[cursorPos.y()]); decoder.end(); return lineText; } break; case Qt::ImCurrentSelection: return QString(); break; default: break; } return QVariant(); } bool TerminalDisplay::handleShortcutOverrideEvent(QKeyEvent* keyEvent) { int modifiers = keyEvent->modifiers(); // 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) { int modifierCount = 0; unsigned int currentModifier = Qt::ShiftModifier; while (currentModifier <= Qt::KeypadModifier) { if (modifiers & currentModifier) modifierCount++; currentModifier <<= 1; } if (modifierCount < 2) { bool override = false; emit overrideShortcutCheck(keyEvent,override); if (override) { keyEvent->accept(); return true; } } } // Override any of the following shortcuts because // they are needed by the terminal int keyCode = keyEvent->key() | modifiers; switch ( keyCode ) { // list is taken from the QLineEdit::event() code case Qt::Key_Tab: case Qt::Key_Delete: case Qt::Key_Home: case Qt::Key_End: case Qt::Key_Backspace: case Qt::Key_Left: case Qt::Key_Right: case Qt::Key_Escape: keyEvent->accept(); return true; } return false; } bool TerminalDisplay::event(QEvent* event) { bool eventHandled = false; switch (event->type()) { case QEvent::ShortcutOverride: eventHandled = handleShortcutOverrideEvent((QKeyEvent*)event); break; case QEvent::PaletteChange: case QEvent::ApplicationPaletteChange: _scrollBar->setPalette( QApplication::palette() ); break; default: break; } return eventHandled ? true : QWidget::event(event); } void TerminalDisplay::setBellMode(int mode) { _bellMode=mode; } void TerminalDisplay::enableBell() { _allowBell = true; } 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 //produce a horrible noise if ( _allowBell ) { _allowBell = false; QTimer::singleShot(500,this,SLOT(enableBell())); if (_bellMode==SystemBeepBell) { QApplication::beep(); } else if (_bellMode==NotifyBell) { emit notifyBell(message); } else if (_bellMode==VisualBell) { swapColorTable(); QTimer::singleShot(200,this,SLOT(swapColorTable())); } } } void TerminalDisplay::selectionChanged() { emit copyAvailable(_screenWindow->selectedText(Screen::PlainText).isEmpty() == false); } void TerminalDisplay::selectionCleared() { initKeyBoardSelection(); } /******************************************************************************* 1. @函数: hideQScrollBarRightMenu 2. @作者: ut000438 王亮 3. @日期: 2021-02-07 4. @说明: 隐藏QScrollBar默认的右键菜单 *******************************************************************************/ void TerminalDisplay::hideQScrollBarRightMenu() { // fix bug 63308: 鼠标放置在右侧滚动条上点击鼠标右键,界面出现黑色长条 QWidgetList widgetList = qApp->allWidgets(); for(int i=0; i(widget); if(scrollBar) { scrollBar->setContextMenuPolicy(Qt::NoContextMenu); } } } void TerminalDisplay::swapColorTable() { ColorEntry color = _colorTable[1]; _colorTable[1]=_colorTable[0]; _colorTable[0]= color; _colorsInverted = !_colorsInverted; update(); } void TerminalDisplay::clearImage() { // We initialize _image[_imageSize] too. See makeImage() for (int i = 0; i <= _imageSize; i++) { _image[i].character = ' '; _image[i].foregroundColor = CharacterColor(COLOR_SPACE_DEFAULT, DEFAULT_FORE_COLOR); _image[i].backgroundColor = CharacterColor(COLOR_SPACE_DEFAULT, DEFAULT_BACK_COLOR); _image[i].rendition = DEFAULT_RENDITION; } } void TerminalDisplay::calcGeometry() { _scrollBar->resize(_scrollBar->sizeHint().width(), contentsRect().height()); int scrollBarWidth = _scrollBar->style()->styleHint(QStyle::SH_ScrollBar_Transient, nullptr, _scrollBar) ? 0 : _scrollBar->width(); switch(_scrollbarLocation) { case QTermWidget::NoScrollBar : _leftMargin = _leftBaseMargin; _contentWidth = contentsRect().width() - 2 * _leftBaseMargin; break; case QTermWidget::ScrollBarLeft : _leftMargin = _leftBaseMargin + scrollBarWidth; _contentWidth = contentsRect().width() - 2 * _leftBaseMargin - scrollBarWidth; _scrollBar->move(contentsRect().topLeft()); break; case QTermWidget::ScrollBarRight: _leftMargin = _leftBaseMargin; _contentWidth = contentsRect().width() - 2 * _leftBaseMargin - scrollBarWidth; _scrollBar->move(contentsRect().topRight() - QPoint(_scrollBar->width()-1, 0)); break; } _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); } } void TerminalDisplay::makeImage() { calcGeometry(); // 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]; clearImage(); } // calculate the needed size, this must be synced with calcGeometry() void TerminalDisplay::setSize(int columns, int lines) { 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) ); if ( newSize != size() ) { _size = newSize; updateGeometry(); } } 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); _usedColumns = qMin(_usedColumns,_columns); _usedLines = qMin(_usedLines,_lines); if (_image) { delete[] _image; makeImage(); } setSize(cols, lins); QWidget::setFixedSize(_size); } QSize TerminalDisplay::sizeHint() const { return _size; } /* --------------------------------------------------------------------- */ /* */ /* Drag & Drop */ /* */ /* --------------------------------------------------------------------- */ void TerminalDisplay::dragEnterEvent(QDragEnterEvent* event) { if (event->mimeData()->hasFormat(QLatin1String("text/plain"))) event->acceptProposedAction(); if (event->mimeData()->urls().count()) event->acceptProposedAction(); } void TerminalDisplay::dropEvent(QDropEvent* event) { //KUrl::List urls = KUrl::List::fromMimeData(event->mimeData()); QList urls = event->mimeData()->urls(); QString dropText; 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++ ) { //KUrl url = KIO::NetAccess::mostLocalUrl( urls[i] , 0 ); QUrl url = urls[i]; QString urlText; if (url.isLocalFile()) 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) //urlText = KShell::quoteArg(urlText); dropText += urlText; if ( i != urls.count()-1 ) dropText += QLatin1Char(' '); } } else { dropText = event->mimeData()->text(); } /***add begin by ut001121 zhangmeng 20201030 for SP4.1 拖拽文件到工作区文件路径加引号***/ dropText.insert(0, '\''); dropText.append('\''); /***add end ut001121***/ emit sendStringToEmu(dropText.toLocal8Bit().constData()); } void TerminalDisplay::doDrag() { dragInfo.state = diDragging; dragInfo.dragObject = new QDrag(this); QMimeData *mimeData = new QMimeData; mimeData->setText(QApplication::clipboard()->text(QClipboard::Selection)); dragInfo.dragObject->setMimeData(mimeData); dragInfo.dragObject->start(Qt::CopyAction); // Don't delete the QTextDrag object. Qt will delete it when it's done with it. } 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 //describing the 'flow control' (Xon/Xoff) feature found in almost //all terminal emulators. //If there isn't a suitable article available in the target language the link //can simply be removed. _outputSuspendedLabel = new QLabel( tr("Output has been " "suspended" " by pressing Ctrl+S." " Press Ctrl+Q to resume."), this ); QPalette palette(_outputSuspendedLabel->palette()); //KColorScheme::adjustBackground(palette,KColorScheme::NeutralBackground); _outputSuspendedLabel->setPalette(palette); _outputSuspendedLabel->setAutoFillBackground(true); _outputSuspendedLabel->setBackgroundRole(QPalette::Base); _outputSuspendedLabel->setFont(QApplication::font()); _outputSuspendedLabel->setContentsMargins(5, 5, 5, 5); //enable activation of "Xon/Xoff" link in label _outputSuspendedLabel->setTextInteractionFlags(Qt::LinksAccessibleByMouse | Qt::LinksAccessibleByKeyboard); _outputSuspendedLabel->setOpenExternalLinks(true); _outputSuspendedLabel->setVisible(false); _gridLayout->addWidget(_outputSuspendedLabel); _gridLayout->addItem( new QSpacerItem(0,0,QSizePolicy::Expanding, QSizePolicy::Expanding), 1,0); } _outputSuspendedLabel->setVisible(suspended); } uint TerminalDisplay::lineSpacing() const { return _lineSpacing; } void TerminalDisplay::setLineSpacing(uint i) { _lineSpacing = i; setVTFont(font()); // Trigger an update. } int TerminalDisplay::margin() const { return _topBaseMargin; } void TerminalDisplay::setMargin(int i) { _topBaseMargin = i; _leftBaseMargin = i; } AutoScrollHandler::AutoScrollHandler(QWidget* parent) : QObject(parent) , _timerId(0) { parent->installEventFilter(this); } void AutoScrollHandler::timerEvent(QTimerEvent* event) { if (event->timerId() != _timerId) return; QMouseEvent mouseEvent( QEvent::MouseMove, widget()->mapFromGlobal(QCursor::pos()), Qt::NoButton, Qt::LeftButton, Qt::NoModifier); QApplication::sendEvent(widget(),&mouseEvent); } bool AutoScrollHandler::eventFilter(QObject* watched,QEvent* event) { Q_ASSERT( watched == parent() ); Q_UNUSED( watched ); switch (event->type()) { case QEvent::MouseMove: { QMouseEvent* mouseEvent = static_cast(event); bool mouseInWidget = widget()->rect().contains(mouseEvent->pos()); if (mouseInWidget) { if (_timerId) killTimer(_timerId); _timerId = 0; } else { if (!_timerId && (mouseEvent->buttons() & Qt::LeftButton)) _timerId = startTimer(100); } break; } case QEvent::MouseButtonRelease: if (_timerId && (static_cast(event)->buttons() & ~Qt::LeftButton)) { killTimer(_timerId); _timerId = 0; } break; default: break; }; return false; } //#include "TerminalDisplay.moc" TerminalScreen::TerminalScreen(QWidget *parent):TerminalDisplay (parent) { setAttribute(Qt::WA_AcceptTouchEvents); grabGesture(Qt::TapGesture); grabGesture(Qt::TapAndHoldGesture); grabGesture(Qt::PanGesture); grabGesture(Qt::PinchGesture); grabGesture(Qt::SwipeGesture); } TerminalScreen::~TerminalScreen() { } /******************************************************************************* 1. @函数: gestureEvent 2. @作者: ut001121 zhangmeng 3. @日期: 2020-08-18 4. @说明: 手势事件 *******************************************************************************/ bool TerminalScreen::gestureEvent(QGestureEvent *event) { if (QGesture *tap = event->gesture(Qt::TapGesture)) tapGestureTriggered(static_cast(tap)); if (QGesture *tapAndHold = event->gesture(Qt::TapAndHoldGesture)) tapAndHoldGestureTriggered(static_cast(tapAndHold)); if (QGesture *pan = event->gesture(Qt::PanGesture)) panTriggered(static_cast(pan)); if (QGesture *pinch = event->gesture(Qt::PinchGesture)) pinchTriggered(static_cast(pinch)); if (QGesture *swipe = event->gesture(Qt::SwipeGesture)) swipeTriggered(static_cast(swipe)); return true; } /******************************************************************************* 1. @函数: tapGestureTriggered 2. @作者: ut001121 zhangmeng 3. @日期: 2020-08-18 4. @说明: 单指点击手势 *******************************************************************************/ void TerminalScreen::tapGestureTriggered(QTapGesture* tap) { //qDebug()<<"------"<<"tapGestureTriggered" << tap ; switch (tap->state()) { case Qt::GestureStarted: { m_gestureAction = GA_tap; m_tapBeginTime = QDateTime::currentDateTime().toMSecsSinceEpoch(); break; } case Qt::GestureUpdated: { break; } case Qt::GestureCanceled: { //根据时间长短区分轻触滑动 qint64 timeSpace = QDateTime::currentDateTime().toMSecsSinceEpoch() - m_tapBeginTime; if(timeSpace < TAP_MOVE_DELAY || m_slideContinue){ m_slideContinue = false; m_gestureAction = GA_slide; qDebug() << "slide start" << timeSpace; } else { qDebug() << "null start" << timeSpace; /***add by ut001121 zhangmeng 20200917 修复BUG48402***/ m_gestureAction = GA_null; } break; } case Qt::GestureFinished: { /***add by ut001121 zhangmeng 20200917 修复BUG48402***/ m_gestureAction = GA_null; break; } default: { Q_ASSERT(false); break; } } } /******************************************************************************* 1. @函数: tapAndHoldGestureTriggered 2. @作者: ut001121 zhangmeng 3. @日期: 2020-08-18 4. @说明: 单指长按手势 *******************************************************************************/ void TerminalScreen::tapAndHoldGestureTriggered(QTapAndHoldGesture* tapAndHold) { //qDebug()<<"------"<<"tapAndHoldGestureTriggered"<state()) { case Qt::GestureStarted: m_gestureAction = GA_hold; break; case Qt::GestureUpdated: Q_ASSERT(false); break; case Qt::GestureCanceled: Q_ASSERT(false); break; case Qt::GestureFinished: /***del by ut001121 zhangmeng 20200915 修复BUG46979 m_gestureAction = GA_null;***/ break; default: Q_ASSERT(false); break; } } /******************************************************************************* 1. @函数: panTriggered 2. @作者: ut001121 zhangmeng 3. @日期: 2020-08-18 4. @说明: 两指平移手势 *******************************************************************************/ void TerminalScreen::panTriggered(QPanGesture *pan) { //qDebug()<<"------"<<"panTriggered"<state()) { case Qt::GestureStarted: m_gestureAction = GA_pan; break; case Qt::GestureUpdated: break; case Qt::GestureCanceled: break; case Qt::GestureFinished: /***del by ut001121 zhangmeng 20200915 修复BUG46979 m_gestureAction = GA_null;***/ break; default: Q_ASSERT(false); break; } } /******************************************************************************* 1. @函数: pinchTriggered 2. @作者: ut001121 zhangmeng 3. @日期: 2020-08-18 4. @说明: 两指捏合手势 *******************************************************************************/ void TerminalScreen::pinchTriggered(QPinchGesture *pinch) { //qDebug()<<"------"<<"pinchTriggered"<state()) { case Qt::GestureStarted: { qDebug()<<"------"<<"pinchTriggered start"; m_gestureAction = GA_pinch; /**add begin by ut001121 zhangmeng 20200812 捏合手势触发时判断是否重新获取字体大小 修复BUG42424 */ QFont font = getVTFont(); if(static_cast(m_scaleFactor) != font.pointSize()){ m_scaleFactor = font.pointSize(); } /**add end by ut001121 */ break; } case Qt::GestureUpdated: { QPinchGesture::ChangeFlags changeFlags = pinch->changeFlags(); if (changeFlags & QPinchGesture::ScaleFactorChanged) { m_currentStepScaleFactor = pinch->totalScaleFactor(); } break; } case Qt::GestureCanceled: { Q_ASSERT(false); break; } case Qt::GestureFinished: { /***del by ut001121 zhangmeng 20200915 修复BUG46979 m_gestureAction = GA_null;***/ m_scaleFactor *= m_currentStepScaleFactor; m_currentStepScaleFactor = 1; qDebug()<<"------"<<"pinchTriggered over"; break; } default: { Q_ASSERT(false); break; } }//switch QFont font = getVTFont(); font.setPointSize(static_cast(m_scaleFactor*m_currentStepScaleFactor)); setVTFont(font); } /******************************************************************************* 1. @函数: swipeTriggered 2. @作者: ut001121 zhangmeng 3. @日期: 2020-08-18 4. @说明: 三指滑动手势 *******************************************************************************/ void TerminalScreen::swipeTriggered(QSwipeGesture* swipe) { //qDebug()<<"------"<<"swipeTriggered"<state()) { case Qt::GestureStarted: m_gestureAction = GA_swipe; break; case Qt::GestureUpdated: break; case Qt::GestureCanceled: /***del by ut001121 zhangmeng 20200915 修复BUG46979 m_gestureAction = GA_null;***/ break; case Qt::GestureFinished: /***del by ut001121 zhangmeng 20200915 修复BUG46979 m_gestureAction = GA_null;***/ break; default: Q_ASSERT(false); break; } } /******************************************************************************* 1. @函数: slideGesture 2. @作者: ut001121 zhangmeng 3. @日期: 2020-08-18 4. @说明: 单指滑动手势(通过原生触摸屏事件进行抽象模拟) *******************************************************************************/ void TerminalScreen::slideGesture(qreal diff) { static qreal delta = 0.0; int step = static_cast(diff+delta); delta = diff+delta - step; getScrollBar()->setValue(getScrollBar()->value()+step); } /******************************************************************************* 1. @函数: event 2. @作者: ut001121 zhangmeng 3. @日期: 2020-08-18 4. @说明: 事件处理 *******************************************************************************/ bool TerminalScreen::event(QEvent* event) { static FlashTween tween; static qreal change = 0.0; static qreal duration = 0.0; if (event->type() == QEvent::Gesture) return gestureEvent(static_cast(event)); if (event->type() == QEvent::MouseButtonRelease && static_cast(event)->source() == Qt::MouseEventSynthesizedByQt) { qDebug()<< "action is over" << m_gestureAction; if(m_gestureAction == GA_slide){ tween.start(0, 0, change, duration, std::bind(&TerminalScreen::slideGesture, this, std::placeholders::_1)); } m_gestureAction = GA_null; } if (event->type() == QEvent::MouseButtonPress && static_cast(event)->source() == Qt::MouseEventSynthesizedByQt) { QMouseEvent* mouseEvent = static_cast(event); m_lastMouseTime = mouseEvent->timestamp(); m_lastMouseYpos = mouseEvent->pos().y(); if(tween.active()) { m_slideContinue = true; tween.stop(); } } if (event->type() == QEvent::MouseMove && static_cast(event)->source() == Qt::MouseEventSynthesizedByQt) { QMouseEvent *mouseEvent = static_cast(event); const ulong diffTime = mouseEvent->timestamp() - m_lastMouseTime; const int diffYpos = mouseEvent->pos().y() - m_lastMouseYpos; m_lastMouseTime = mouseEvent->timestamp(); m_lastMouseYpos = mouseEvent->pos().y(); if(m_gestureAction == GA_slide) { QFont font = getVTFont(); /*开根号时数值越大衰减比例越大*/ qreal direction = diffYpos>0?1.0:-1.0; slideGesture(-direction*sqrt(abs(diffYpos))/font.pointSize()); /*预算惯性滑动时间*/ m_stepSpeed = static_cast(diffYpos)/static_cast(diffTime+0.000001); duration = sqrt(abs(m_stepSpeed))*1000; /*预算惯性滑动距离,4.0为调优数值*/ m_stepSpeed /= sqrt(font.pointSize()*4.0); change = m_stepSpeed*sqrt(abs(m_stepSpeed))*100; return true; } if(m_gestureAction != GA_null) { return true; } } /***add by ut001121 zhangmeng 20200915 修复BUG46979***/ if (event->type() == QEvent::MouseMove && static_cast(event)->source() != Qt::MouseEventSynthesizedByQt && m_gestureAction == GA_slide){ return true; } /***add end ut001121***/ /** 待删除 QTouchEvent *touchEvent = static_cast(event); switch (event->type()) { case QEvent::TouchBegin: { QList touchPoints = touchEvent->touchPoints(); qDebug()<<"========================================================"<type()<timestamp(); break;//不能return true; } default: break; }*/ return TerminalDisplay::event(event); } FlashTween::FlashTween() { m_timer = new QTimer(this); connect(m_timer, &QTimer::timeout, this ,&FlashTween::__run); } /******************************************************************************* 1. @函数: start 2. @作者: ut001121 zhangmeng 3. @日期: 2020-08-18 4. @说明: 开始惯性 *******************************************************************************/ void FlashTween::start(qreal t,qreal b,qreal c,qreal d, FunSlideInertial f) { if(c==0.0 || d==0.0) return; m_currentTime = t; m_beginValue = b; m_changeValue = c; m_durationTime = d; m_lastValue = 0; m_fSlideGesture = f; m_direction = m_changeValue<0?1:-1; m_timer->stop(); m_timer->start(CELL_TIME); } /******************************************************************************* 1. @函数: __run 2. @作者: ut001121 zhangmeng 3. @日期: 2020-08-18 4. @说明: 运行惯性 *******************************************************************************/ void FlashTween::__run() { qreal tempValue = m_lastValue; m_lastValue = FlashTween::sinusoidalEaseOut(m_currentTime, m_beginValue, abs(m_changeValue), m_durationTime); m_fSlideGesture(m_direction*(m_lastValue-tempValue)); //qDebug()<<"###############################"<stop(); } } deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/TerminalDisplay.h000066400000000000000000001060741475472654300264470ustar00rootroot00000000000000/* Copyright 2007-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 (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. */ #ifndef TERMINALDISPLAY_H #define TERMINALDISPLAY_H // Qt #include #include #include // Konsole #include "Filter.h" #include "Character.h" #include "qtermwidget.h" //#include "konsole_export.h" #include "tools.h" #include #include #include #include #include #include #include #define CELL_TIME 15 #define TAP_MOVE_DELAY 300 //#include "konsole_export.h" #define KONSOLEPRIVATE_EXPORT class QDrag; class QDragEnterEvent; class QDropEvent; class QLabel; class QTimer; class QEvent; class QGridLayout; class QKeyEvent; class QScrollBar; class QShowEvent; class QHideEvent; class QTimerEvent; class QWidget; //class KMenu; namespace Konsole { enum MotionAfterPasting { // No move screenwindow after pasting NoMoveScreenWindow = 0, // Move start of screenwindow after pasting MoveStartScreenWindow = 1, // Move end of screenwindow after pasting MoveEndScreenWindow = 2 }; /***add begin by ut001121 zhangmeng 20200912 声明字号限制 修复42250***/ extern __attribute__((visibility("default"))) int __minFontSize; extern __attribute__((visibility("default"))) int __maxFontSize; /***add end by ut001121***/ extern unsigned short vt100_graphics[32]; 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, * it will update the display by calling updateImage(). * * TODO More documentation */ class KONSOLEPRIVATE_EXPORT TerminalDisplay : public QWidget { Q_OBJECT public: /** Constructs a new terminal display widget with the specified parent. */ explicit TerminalDisplay(QWidget *parent=nullptr); ~TerminalDisplay() override; /** Returns the terminal color palette used by the display. */ const ColorEntry* colorTable() const; /** Sets the terminal color palette used by the display. */ void setColorTable(const ColorEntry table[]); /** * Sets the seed used to generate random colors for the display * (in color schemes that support them). */ void setRandomSeed(uint seed); /** * Returns the seed used to generate random colors for the display * (in color schemes that support them). */ uint randomSeed() const; /** Sets the opacity of the terminal display. */ void setOpacity(qreal opacity); /** 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(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. * @param lines The maximum value of the scroll bar. */ void setScroll(int cursor, int lines); /** * Scroll to the bottom of the terminal (reset scrolling). */ 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). * Depending on the type of the hotspots created by the filter ( returned by Filter::Hotspot::type() ) * the view will draw visual cues such as underlines on mouse-over for links or translucent * rectangles for markers. * * To add a new filter to the view, call: * viewWidget->filterChain()->addFilter( filterObject ); */ 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 * image size and number of filters in the filterChain() * * TODO - This API does not really allow efficient usage. Revise it so * that the processing can be done in a better way. * * 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); /** Returns true if the cursor is set to blink or false otherwise. */ bool blinkingCursor() { return _hasBlinkingCursor; } /** Specifies whether or not the cursor blinks. */ void setBlinkingCursor(bool blink); /** Specifies whether or not text can blink. */ void setBlinkingTextEnabled(bool blink); 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. */ enum TripleClickMode { /** Select the whole line underneath the cursor. */ SelectWholeLine, /** 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. */ 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); /** * 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 * the mouse pointer, which can be set using the QWidget::setCursor() * method. * * Defaults to BlockCursor */ void setKeyboardCursorShape(QTermWidget::KeyboardCursorShape shape); /** * Returns the shape of the keyboard cursor. See setKeyboardCursorShape() */ QTermWidget::KeyboardCursorShape keyboardCursorShape() const; /** * Sets the color used to draw the keyboard cursor. * * The keyboard cursor defaults to using the foreground color of the character * underneath it. * * @param useForegroundColor If true, the cursor color will change to match * the foreground color of the character underneath it as it is moved, in this * case, the @p color parameter is ignored and the color of the character * under the cursor is inverted to ensure that it is still readable. * @param color The color to use to draw the cursor. This is only taken into * account if @p useForegroundColor is false. */ 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. */ QColor keyboardCursorColor() const; /** * Returns the number of lines of text which can be displayed in the widget. * * This will depend upon the height of the widget and the current font. * See fontHeight() */ int lines() { return _lines; } /** * Returns the number of characters of text which can be displayed on * each line in the widget. * * This will depend upon the width of the widget and the current font. * See fontWidth() */ int columns() { return _columns; } /** * Returns the height of the characters in the font used to draw the text in the display. */ int fontHeight() { return _fontHeight; } /** * 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 override; /** * 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. * * The word boundaries occur at the first and last characters which * are either a letter, number, or a character in @p wc * * @param wc An array of characters which are to be considered parts * 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 * 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 * 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; } /** * This enum describes the different types of sounds and visual effects which * can be used to alert the user when a 'bell' occurs in the terminal * session. */ enum BellMode { /** A system beep. */ 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, /** A silent, visual bell (eg. inverting the display's colors briefly) */ VisualBell=2, /** No bell effects */ NoBell=3 }; void setSelection(const QString &t); void setSelectionAll(); /** * Reimplemented. Has no effect. Use setVTFont() to change the font * used to draw characters in the display. */ virtual void setFont(const QFont &); /** 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. */ void setVTFont(const QFont& font); /** * Specified whether anti-aliasing of text in the terminal display * 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; } /** * Specify whether line chars should be drawn by ourselves or left to * underlying font rendering libraries. */ void setDrawLineChars(bool drawLineChars) { _drawLineChars = drawLineChars; } /** * Specifies whether characters with intense colors should be rendered * as bold. Defaults to true. */ void setBoldIntense(bool value) { _boldIntense = value; } /** * 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 * 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. * * See setTerminalSizeHint() , isTerminalSizeHint() */ void setTerminalSizeStartup(bool on) { _terminalSizeStartup=on; } /** * Sets the status of the BiDi rendering inside the terminal display. * Defaults to disabled. */ void setBidiEnabled(bool set) { _bidiEnabled=set; } /** * Returns the status of the BiDi rendering in this widget. */ bool isBidiEnabled() { return _bidiEnabled; } /** * Sets the terminal screen section which is displayed in this widget. * When updateImage() is called, the display fetches the latest character image from the * the associated terminal screen window. * * In terms of the model-view paradigm, the ScreenWindow is the model which is rendered * by the TerminalDisplay. */ void setScreenWindow( ScreenWindow* window ); /** Returns the terminal screen section which is displayed in this widget. See setScreenWindow() */ 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 setHideCursor(bool hideCursor); void setSessionId(int sessionId); // 获取是否允许输出时滚动 bool getIsAllowScroll() const; // 设置是否允许输出时滚动 void setIsAllowScroll(bool isAllowScroll); 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(); /** Essentially calles processFilters(). */ void updateFilters(); /** * 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 * display. */ void pasteClipboard(); /** * Pastes the content of the selection into the * display. */ 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. * 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); /** * Sets whether the program whoose output is being displayed in the view * is interested in mouse events. * * 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 * view area - since the program running in the terminal is being allowed to handle normal mouse * events itself. * * @param usesMouse Set to true if the program running in the terminal is interested in mouse events * or false otherwise. */ void setUsesMouse(bool usesMouse); /** * Sets the AlternateScrolling profile property which controls whether * to emulate up/down key presses for mouse scroll wheel events. * For more details, check the documentation of that property in the * Profile header. * Enabled by default. */ void setAlternateScrolling(bool enable); /** 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() */ void setBackgroundColor(const QColor& color); /** * Sets the text of the display to the specified color. * @see setColorTable(), setBackgroundColor() */ void setForegroundColor(const QColor& color); void selectionChanged(); void selectionCleared(); // 隐藏QScrollBar默认的右键菜单 void hideQScrollBarRightMenu(); signals: /** * Emitted when the user presses a key whilst the terminal widget has focus. */ 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 * @param line The character row where the event occurred * @param eventType The type of event. 0 for a mouse press / release or 1 for mouse motion */ void mouseSignal(int button, int column, int line, int eventType); 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. * * This can be used to display a context menu. */ 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 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. * * @p override is set to false by default and the shortcut will be triggered as normal. */ void overrideShortcutCheck(QKeyEvent* keyEvent,bool& override); void isBusySelecting(bool); void sendStringToEmu(const char*); // qtermwidget signals void copyAvailable(bool); void termGetFocus(); void termLostFocus(); void leftMouseClick(); void notifyBell(const QString&); void usesMouseChanged(); protected: bool event( QEvent * ) override; void paintEvent( QPaintEvent * ) override; void showEvent(QShowEvent*) override; void hideEvent(QHideEvent*) override; void resizeEvent(QResizeEvent*) override; virtual void fontChange(const QFont &font); void focusInEvent(QFocusEvent* event) override; void focusOutEvent(QFocusEvent* event) override; void keyPressEvent(QKeyEvent* event) override; void keyReleaseEvent(QKeyEvent *event) override; void mouseDoubleClickEvent(QMouseEvent* ev) override; void mousePressEvent( QMouseEvent* ) override; void mouseReleaseEvent( QMouseEvent* ) override; void mouseMoveEvent( QMouseEvent* ) override; virtual void extendSelection( const QPoint& pos ); void wheelEvent( QWheelEvent* ) override; bool focusNextPrevChild( bool next ) override; // drag and drop void dragEnterEvent(QDragEnterEvent* event) override; void dropEvent(QDropEvent* event) override; void doDrag(); void initSelectionStates(); void initKeyBoardSelection(); void checkAndInitSelectionState(); enum DragState { diNone, diPending, diDragging }; struct _dragInfo { DragState state; QPoint start; QDrag *dragObject; } dragInfo; // classifies the 'ch' into one of three categories // and returns a character to indicate which category it is in // // - A space (returns ' ') // - Part of a word (returns 'a') // - Other characters (returns the input character) QChar charClass(QChar ch) const; void clearImage(); Screen::DecodingOptions currentDecodingOptions(); void mouseTripleClickEvent(QMouseEvent* ev); // reimplemented void inputMethodEvent ( QInputMethodEvent* event ) override; QVariant inputMethodQuery( Qt::InputMethodQuery query ) const override; 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(); private slots: void swapColorTable(); void tripleClickTimeout(); // resets possibleTripleClick 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 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); // 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 // will be drawn fully opaque 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, 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, 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); // 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 QRect imageToWidget(const QRect& imageArea) const; QRect widgetToImage(const QRect& widgetArea) const; // the area where the preedit string for input methods will be draw QRect preeditRect() const; // shows a notification window in the middle of the widget indicating the terminal's // 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 ) // 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, // the left and right are ignored. void scrollImage(int lines , const QRect& region); void calcGeometry(); 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; // returns the position of the cursor in columns and lines QPoint cursorPosition() const; // redraws the cursor void updateCursor(); bool handleShortcutOverrideEvent(QKeyEvent* event); bool canDraw(uint c) const; bool isLineCharString(const QString& string) const; // the window onto the terminal screen which this display // is currently showing. QPointer _screenWindow; bool _allowBell; QGridLayout* _gridLayout; bool _fixedFont; // has fixed pitch int _fontHeight; // height 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 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 QRect _contentRect; int _contentHeight; int _contentWidth; Character* _image; // [lines][columns] // only the area [usedLines][usedColumns] in the image contains valid data int _imageSize; QVector _lineProperties; ColorEntry _colorTable[TABLE_COLORS]; uint _randomSeed; bool _resizing; bool _terminalSizeHint; bool _terminalSizeStartup; bool _bidiEnabled; bool _mouseMarks; bool _alternateScrolling; bool _bracketedPasteMode; QPoint _iPntSel; // initial selection point QPoint _pntSel; // current selection point QPoint _tripleSelBegin; // help avoid flicker int _actSel; // selection state bool _wordSelectionMode; bool _lineSelectionMode; bool _preserveLineBreaks; bool _columnSelectionMode; QClipboard* _clipboard; QScrollBar* _scrollBar; QTermWidget::ScrollBarPosition _scrollbarLocation; QString _wordCharacters; int _bellMode; bool _blinking; // hide text in paintEvent bool _hasBlinker; // has characters to blink bool _cursorBlinking; // hide cursor in paintEvent bool _hasBlinkingCursor; // has blinking cursor enabled bool _allowBlinkingText; // allow text to blink bool _ctrlDrag; // require Ctrl key for drag TripleClickMode _tripleClickMode; bool _isFixedSize; //Columns / lines are locked. QTimer* _blinkTimer; // active when hasBlinker QTimer* _blinkCursorTimer; // active when hasBlinkingCursor //QMenu* _drop; QString _dropText; int _dndFileCount; bool _possibleTripleClick; // is set in mouseDoubleClickEvent and deleted // after QApplication::doubleClickInterval() delay bool m_bUserIsResizing; //用于判断当前控件是否正在resize QLabel* _resizeWidget; QTimer* _resizeTimer; bool _flowControlWarningEnabled; bool _hideCursor; //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; uint _lineSpacing; 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; QTermWidget::KeyboardCursorShape _cursorShape; // custom cursor color. if this is invalid then the foreground // color of the character under the cursor is used QColor _cursorColor; MotionAfterPasting mMotionAfterPasting; struct InputMethodData { QString preeditString; QRect previousPreeditRect; }; InputMethodData _inputMethodData; static bool _antialiasText; // do we antialias or not //the delay in milliseconds between redrawing blinking text static const int TEXT_BLINK_DELAY = 500; int _margin; // the contents margin bool _centerContents; // center the contents between margins int _leftBaseMargin; int _topBaseMargin; int _sessionId; bool _drawLineChars; //TerminalHeaderBar *_headerBar; int _selStartLine = 0; int _selStartColumn = 0; int _selEndLine = 0; int _selEndColumn = 0; int _lastLeftEndColumn = 0; int _lastLeftEndLine = 0; int _lastRightEndColumn = 0; int _lastRightEndLine = 0; int _lastEndColumn = 0; bool _selBegin = false; // 当前窗口是否允许输出时回滚的标志位 bool m_isAllowScroll = true; public: static void setTransparencyEnabled(bool enable) { HAVE_TRANSPARENCY = enable; } QScrollBar* getScrollBar() {return _scrollBar;} }; class AutoScrollHandler : public QObject { Q_OBJECT public: explicit AutoScrollHandler(QWidget* parent); protected: void timerEvent(QTimerEvent* event) override; bool eventFilter(QObject* watched,QEvent* event) override; private: QWidget* widget() const { return static_cast(parent()); } int _timerId; }; class KONSOLEPRIVATE_EXPORT TerminalScreen : public TerminalDisplay{ Q_OBJECT public: explicit TerminalScreen(QWidget *parent=nullptr); ~TerminalScreen() override; protected: bool event(QEvent* evt) override; private: bool gestureEvent(QGestureEvent *event); void tapGestureTriggered(QTapGesture*); void tapAndHoldGestureTriggered(QTapAndHoldGesture*); void panTriggered(QPanGesture*); void pinchTriggered(QPinchGesture*); void swipeTriggered(QSwipeGesture*); void slideGesture(qreal diff); enum GestureAction{ GA_null, GA_tap, GA_slide, GA_pinch, GA_hold, GA_pan, GA_swipe }; qreal m_scaleFactor = 1; qreal m_currentStepScaleFactor = 1; qint64 m_tapBeginTime = 0; bool m_slideContinue = false; int m_lastMouseYpos = 0; ulong m_lastMouseTime = 0; qreal m_stepSpeed = 0; Qt::GestureState m_tapStatus = Qt::NoGesture; GestureAction m_gestureAction = GA_null; }; // Tween算法(模拟惯性) typedef std::function FunSlideInertial; class FlashTween : public QObject { Q_OBJECT public: FlashTween(); ~FlashTween(){} public: void start(qreal t,qreal b,qreal c,qreal d, FunSlideInertial fSlideGesture); void stop(){m_timer->stop();} bool active(){return m_timer->isActive();} private slots: void __run(); private: QTimer* m_timer = nullptr; FunSlideInertial m_fSlideGesture = nullptr; qreal m_currentTime = 0; qreal m_beginValue = 0; qreal m_changeValue = 0; qreal m_durationTime = 0; qreal m_direction = 1; qreal m_lastValue = 0; private: /** 链接:https://www.cnblogs.com/cloudgamer/archive/2009/01/06/Tween.html 效果说明 Linear:无缓动效果; Quadratic:二次方的缓动(t^2); Cubic:三次方的缓动(t^3); Quartic:四次方的缓动(t^4); Quintic:五次方的缓动(t^5); Sinusoidal:正弦曲线的缓动(sin(t)); Exponential:指数曲线的缓动(2^t); Circular:圆形曲线的缓动(sqrt(1-t^2)); Elastic:指数衰减的正弦曲线缓动; Back:超过范围的三次方缓动((s+1)*t^3 - s*t^2); Bounce:指数衰减的反弹缓动。 每个效果都分三个缓动方式(方法),分别是: easeIn:从0开始加速的缓动; easeOut:减速到0的缓动; easeInOut:前半段从0开始加速,后半段减速到0的缓动。 其中Linear是无缓动效果,没有以上效果。 四个参数分别是: t: current time(当前时间); b: beginning value(初始值); c: change in value(变化量); d: duration(持续时间)。 */ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wsequence-point" static qreal quadraticEaseOut(qreal t,qreal b,qreal c,qreal d){ return -c *(t/=d)*(t-2) + b; } static qreal cubicEaseOut(qreal t,qreal b,qreal c,qreal d){ return c*((t=t/d-1)*t*t + 1) + b; } static qreal quarticEaseOut(qreal t,qreal b,qreal c,qreal d){ return -c * ((t=t/d-1)*t*t*t - 1) + b; } static qreal quinticEaseOut(qreal t,qreal b,qreal c,qreal d){ return c*((t=t/d-1)*t*t*t*t + 1) + b; } static qreal sinusoidalEaseOut(qreal t,qreal b,qreal c,qreal d){ return c * sin(t/d * (3.14/2)) + b; } static qreal circularEaseOut(qreal t,qreal b,qreal c,qreal d){ return c * sqrt(1 - (t=t/d-1)*t) + b; } static qreal bounceEaseOut(qreal t,qreal b,qreal c,qreal d){ if ((t/=d) < (1/2.75)) { return c*(7.5625*t*t) + b; } else if (t < (2/2.75)) { return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b; } else if (t < (2.5/2.75)) { return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b; } else { return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b; } } #pragma GCC diagnostic pop }; } #endif // TERMINALDISPLAY_H deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/Vt102Emulation.cpp000066400000000000000000001646241475472654300264000ustar00rootroot00000000000000/* This file is part of Konsole, an X terminal. Copyright 2007-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 (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. */ // Own #include "Vt102Emulation.h" // XKB //#include // this allows konsole to be compiled without XKB and XTEST extensions // even though it might be available on a particular system. #if defined(AVOID_XKB) #undef HAVE_XKB #endif #if defined(HAVE_XKB) void scrolllock_set_off(); void scrolllock_set_on(); #endif // Standard #include #include // Qt #include #include #include #include // KDE //#include //#include // Konsole #include "KeyboardTranslator.h" #include "Screen.h" using namespace Konsole; Vt102Emulation::Vt102Emulation() : Emulation(), prevCC(0), _titleUpdateTimer(new QTimer(this)), _reportFocusEvents(false) { _titleUpdateTimer->setSingleShot(true); QObject::connect(_titleUpdateTimer , SIGNAL(timeout()) , this , SLOT(updateTitle())); initTokenizer(); reset(); } Vt102Emulation::~Vt102Emulation() {} void Vt102Emulation::clearEntireScreen() { _currentScreen->clearEntireScreen(); bufferedUpdate(); } void Vt102Emulation::reset() { resetTokenizer(); resetModes(); resetCharset(0); _screen[0]->reset(); resetCharset(1); _screen[1]->reset(); setCodec(LocaleCodec); bufferedUpdate(); } /* ------------------------------------------------------------------------- */ /* */ /* Processing the incoming byte stream */ /* */ /* ------------------------------------------------------------------------- */ /* Incoming Bytes Event pipeline This section deals with decoding the incoming character stream. Decoding means here, that the stream is first separated into `tokens' which are then mapped to a `meaning' provided as operations by the `Screen' class or by the emulation class itself. The pipeline proceeds as follows: - Tokenizing the ESC codes (onReceiveChar) - VT100 code page translation of plain characters (applyCharset) - Interpretation of ESC codes (processToken) The escape codes and their meaning are described in the technical reference of this program. */ // Tokens ------------------------------------------------------------------ -- /* Since the tokens are the central notion if this section, we've put them in front. They provide the syntactical elements used to represent the terminals operations as byte sequences. They are encodes here into a single machine word, so that we can later switch over them easily. Depending on the token itself, additional argument variables are filled with parameter values. The tokens are defined below: - CHR - Printable characters (32..255 but DEL (=127)) - CTL - Control characters (0..31 but ESC (= 27), DEL) - ESC - Escape codes of the form - 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 - - 'Y'{Pc}{Pc} - XTE_HA - Xterm window/terminal attribute commands of the form `]' {Pn} `;' {Text} (Note that these are handled differently to the other formats) The last two forms allow list of arguments. Since the elements of the lists are treated individually the same way, they are passed as individual tokens to the interpretation. Further, because the meaning of the parameters are names (althought represented as numbers), they are includes within the token ('N'). */ #define TY_CONSTRUCT(T,A,N) ( (((static_cast(N)) & 0xffff) << 16) | (((static_cast(A)) & 0xff) << 8) | ((static_cast(T)) & 0xff) ) #define TY_CHR( ) TY_CONSTRUCT(0,0,0) #define TY_CTL(A ) TY_CONSTRUCT(1,A,0) #define TY_ESC(A ) TY_CONSTRUCT(2,A,0) #define TY_ESC_CS(A,B) TY_CONSTRUCT(3,A,B) #define TY_ESC_DE(A ) TY_CONSTRUCT(4,A,0) #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) #define TY_CSI_PE(A) TY_CONSTRUCT(10,A,0) #define MAX_ARGUMENT 4096 // Tokenizer --------------------------------------------------------------- -- /* The tokenizer's state The state is represented by the buffer (tokenBuffer, tokenBufferPos), and accompanied by decoded arguments kept in (argv,argc). Note that they are kept internal in the tokenizer. */ void Vt102Emulation::resetTokenizer() { tokenBufferPos = 0; argc = 0; argv[0] = 0; argv[1] = 0; prevCC = 0; } void Vt102Emulation::addDigit(int digit) { if (argv[argc] < MAX_ARGUMENT) argv[argc] = 10*argv[argc] + digit; } void Vt102Emulation::addArgument() { argc = qMin(argc+1,MAXARGS-1); argv[argc] = 0; } 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 #define DIG 8 // Digit #define SCS 16 // TODO: Document me #define GRP 32 // TODO: Document me #define CPS 64 // Character which indicates end of window resize // escape sequence '\e[8;;t' void Vt102Emulation::initTokenizer() { int i; const char* s; for(i = 0;i < 256; ++i) charClass[i] = 0; for(i = 0;i < 32; ++i) charClass[i] |= CTL; for(i = 32;i < 256; ++i) charClass[i] |= CHR; for(s = "@ABCDGHILMPSTXZbcdfry"; *s; ++s) charClass[static_cast(*s)] |= CPN; // resize = \e[8;;t for(s = "t"; *s; ++s) charClass[static_cast(*s)] |= CPS; for(s = "0123456789"; *s; ++s) charClass[static_cast(*s)] |= DIG; for(s = "()+*%"; *s; ++s) charClass[static_cast(*s)] |= SCS; for(s = "()+*#[]%"; *s; ++s) charClass[static_cast(*s)] |= GRP; resetTokenizer(); } /* Ok, here comes the nasty part of the decoder. Instead of keeping an explicit state, we deduce it from the token scanned so far. It is then immediately combined with the current character to form a scanning decision. This is done by the following defines. - P is the length of the token scanned so far. - L (often P-1) is the position on which contents we base a decision. - C is a character or a group of characters (taken from 'charClass'). - 'cc' is the current character - 's' is a pointer to the start of the token buffer - 'p' is the current position within the token buffer Note that they need to applied in proper order. */ #define lec(P,L,C) (p == (P) && s[(L)] == (C)) #define lun( ) (p == 1 && cc >= 32 ) #define les(P,L,C) (p == (P) && s[L] < 256 && (charClass[s[(L)]] & (C)) == (C)) #define eec(C) (p >= 3 && cc == (C)) #define ees(C) (p >= 3 && cc < 256 && (charClass[cc] & (C)) == (C)) #define eps(C) (p >= 3 && s[2] != '?' && s[2] != '!' && s[2] != '>' && cc < 256 && (charClass[cc] & (C)) == (C)) #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 || (prevCC == 27 && cc == 92) )) // 27, 92 => "\e\\" (ST, String Terminator) #define ces(C) (cc < 256 && (charClass[cc] & (C)) == (C) && !Xte) #define CNTL(c) ((c)-'@') #define ESC 27 #define DEL 127 // process an incoming unicode character void Vt102Emulation::receiveChar(wchar_t cc) { 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 // X-off protocol, which comes really below this level. if (cc == CNTL('X') || cc == CNTL('Z') || cc == ESC) resetTokenizer(); //VT100: CAN or SUB if (cc != ESC) { processToken(TY_CTL(cc+'@' ),0,0); return; } } // advance the state addToCurrentToken(cc); wchar_t* s = tokenBuffer; int p = tokenBufferPos; if (getMode(MODE_Ansi)) { if (lec(1,0,ESC)) { return; } if (lec(1,0,ESC+128)) { s[0] = ESC; receiveChar('['); return; } if (les(2,1,GRP)) { return; } if (Xte ) { processWindowAttributeChange(); resetTokenizer(); return; } if (Xpe ) { prevCC = cc; return; } if (lec(3,2,'?')) { return; } if (lec(3,2,'>')) { return; } if (lec(3,2,'!')) { return; } if (lun( )) { processToken( TY_CHR(), applyCharset(cc), 0); resetTokenizer(); return; } if (lec(2,0,ESC)) { processToken( TY_ESC(s[1]), 0, 0); resetTokenizer(); return; } 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)) { processToken( TY_CSI_PS(cc, argv[0]), argv[1], argv[2]); resetTokenizer(); return; } if (epe( )) { processToken( TY_CSI_PE(cc), 0, 0); resetTokenizer(); return; } if (ees(DIG)) { addDigit(cc-'0'); return; } if (eec(';') || eec(':')) { addArgument(); return; } for (int i=0;i<=argc;i++) { if (epp()) processToken( TY_CSI_PR(cc,argv[i]), 0, 0); else if (egt()) processToken( TY_CSI_PG(cc), 0, 0); // spec. case for ESC]>0c or ESC]>c else if (cc == 'm' && argc - i >= 4 && (argv[i] == 38 || argv[i] == 48) && argv[i+1] == 2) { // ESC[ ... 48;2;;; ... m -or- ESC[ ... 38;2;;; ... m i += 2; processToken( TY_CSI_PS(cc, argv[i-2]), COLOR_SPACE_RGB, (argv[i] << 16) | (argv[i+1] << 8) | argv[i+2]); i += 2; } else if (cc == 'm' && argc - i >= 2 && (argv[i] == 38 || argv[i] == 48) && argv[i+1] == 5) { // ESC[ ... 48;5; ... m -or- ESC[ ... 38;5; ... m i += 2; processToken( TY_CSI_PS(cc, argv[i-2]), COLOR_SPACE_256, argv[i]); } else processToken( TY_CSI_PS(cc,argv[i]), 0, 0); } resetTokenizer(); } else { // VT52 Mode if (lec(1,0,ESC)) return; if (les(1,0,CHR)) { processToken( TY_CHR(), s[0], 0); resetTokenizer(); return; } if (lec(2,1,'Y')) return; if (lec(3,1,'Y')) return; if (p < 4) { processToken( TY_VT52(s[1] ), 0, 0); resetTokenizer(); return; } processToken( TY_VT52(s[1]), s[2], s[3]); resetTokenizer(); return; } } void Vt102Emulation::processWindowAttributeChange() { // Describes the window or terminal session attribute to change // See Session::UserTitleChange for possible values int attributeToChange = 0; int i; for (i = 2; i < tokenBufferPos && tokenBuffer[i] >= '0' && tokenBuffer[i] <= '9'; i++) { attributeToChange = 10 * attributeToChange + (tokenBuffer[i]-'0'); } if (tokenBuffer[i] != ';') { reportDecodingError(); return; } // copy from the first char after ';', and skipping the ending delimiter // 0x07 or 0x92. Note that as control characters in OSC text parts are // ignored, only the second char in ST ("\e\\") is appended to tokenBuffer. QString newValue = QString::fromWCharArray(tokenBuffer + i + 1, tokenBufferPos-i-2); _pendingTitleUpdates[attributeToChange] = newValue; _titleUpdateTimer->start(20); } void Vt102Emulation::updateTitle() { QListIterator iter( _pendingTitleUpdates.keys() ); while (iter.hasNext()) { int arg = iter.next(); emit titleChanged( arg , _pendingTitleUpdates[arg] ); } _pendingTitleUpdates.clear(); } // Interpreting Codes --------------------------------------------------------- /* Now that the incoming character stream is properly tokenized, meaning is assigned to them. These are either operations of the current _screen, or of the emulation class itself. The token to be interpreteted comes in as a machine word possibly accompanied by two parameters. Likewise, the operations assigned to, come with up to two arguments. One could consider to make up a proper table from the function below. The technical reference manual provides more information about this mapping. */ void Vt102Emulation::processToken(int token, wchar_t p, int q) { switch (token) { case TY_CHR( ) : _currentScreen->displayCharacter (p ); break; //UTF16 // 127 DEL : ignored on input case TY_CTL('@' ) : /* NUL: ignored */ break; case TY_CTL('A' ) : /* SOH: ignored */ break; case TY_CTL('B' ) : /* STX: ignored */ break; case TY_CTL('C' ) : /* ETX: ignored */ break; case TY_CTL('D' ) : /* EOT: ignored */ break; case TY_CTL('E' ) : reportAnswerBack ( ); break; //VT100 case TY_CTL('F' ) : /* ACK: ignored */ break; case TY_CTL('G' ) : emit stateSet(NOTIFYBELL); break; //VT100 case TY_CTL('H' ) : _currentScreen->backspace ( ); break; //VT100 case TY_CTL('I' ) : _currentScreen->tab ( ); break; //VT100 case TY_CTL('J' ) : _currentScreen->newLine ( ); break; //VT100 case TY_CTL('K' ) : _currentScreen->newLine ( ); break; //VT100 case TY_CTL('L' ) : _currentScreen->newLine ( ); break; //VT100 case TY_CTL('M' ) : _currentScreen->toStartOfLine ( ); break; //VT100 case TY_CTL('N' ) : useCharset ( 1); break; //VT100 case TY_CTL('O' ) : useCharset ( 0); break; //VT100 case TY_CTL('P' ) : /* DLE: ignored */ break; case TY_CTL('Q' ) : /* DC1: XON continue */ break; //VT100 case TY_CTL('R' ) : /* DC2: ignored */ break; case TY_CTL('S' ) : /* DC3: XOFF halt */ break; //VT100 case TY_CTL('T' ) : /* DC4: ignored */ break; case TY_CTL('U' ) : /* NAK: ignored */ break; case TY_CTL('V' ) : /* SYN: ignored */ break; case TY_CTL('W' ) : /* ETB: ignored */ break; case TY_CTL('X' ) : _currentScreen->displayCharacter ( 0x2592); break; //VT100 case TY_CTL('Y' ) : /* EM : ignored */ break; case TY_CTL('Z' ) : _currentScreen->displayCharacter ( 0x2592); break; //VT100 case TY_CTL('[' ) : /* ESC: cannot be seen here. */ break; case TY_CTL('\\' ) : /* FS : ignored */ break; case TY_CTL(']' ) : /* GS : ignored */ break; case TY_CTL('^' ) : /* RS : ignored */ break; case TY_CTL('_' ) : /* US : ignored */ break; case TY_ESC('D' ) : _currentScreen->index ( ); break; //VT100 case TY_ESC('E' ) : _currentScreen->nextLine ( ); break; //VT100 case TY_ESC('H' ) : _currentScreen->changeTabStop (true ); break; //VT100 case TY_ESC('M' ) : _currentScreen->reverseIndex ( ); break; //VT100 case TY_ESC('Z' ) : reportTerminalType ( ); break; case TY_ESC('c' ) : reset ( ); break; case TY_ESC('n' ) : useCharset ( 2); break; case TY_ESC('o' ) : useCharset ( 3); break; case TY_ESC('7' ) : saveCursor ( ); break; case TY_ESC('8' ) : restoreCursor ( ); break; case TY_ESC('=' ) : setMode (MODE_AppKeyPad); break; case TY_ESC('>' ) : resetMode (MODE_AppKeyPad); break; case TY_ESC('<' ) : setMode (MODE_Ansi ); break; //VT100 case TY_ESC_CS('(', '0') : setCharset (0, '0'); break; //VT100 case TY_ESC_CS('(', 'A') : setCharset (0, 'A'); break; //VT100 case TY_ESC_CS('(', 'B') : setCharset (0, 'B'); break; //VT100 case TY_ESC_CS(')', '0') : setCharset (1, '0'); break; //VT100 case TY_ESC_CS(')', 'A') : setCharset (1, 'A'); break; //VT100 case TY_ESC_CS(')', 'B') : setCharset (1, 'B'); break; //VT100 case TY_ESC_CS('*', '0') : setCharset (2, '0'); break; //VT100 case TY_ESC_CS('*', 'A') : setCharset (2, 'A'); break; //VT100 case TY_ESC_CS('*', 'B') : setCharset (2, 'B'); break; //VT100 case TY_ESC_CS('+', '0') : setCharset (3, '0'); break; //VT100 case TY_ESC_CS('+', 'A') : setCharset (3, 'A'); break; //VT100 case TY_ESC_CS('+', 'B') : setCharset (3, 'B'); break; //VT100 case TY_ESC_CS('%', 'G') : setCodec (Utf8Codec ); break; //LINUX case TY_ESC_CS('%', '@') : setCodec (LocaleCodec ); break; //LINUX case TY_ESC_DE('3' ) : /* Double height line, top half */ _currentScreen->setLineProperty( LINE_DOUBLEWIDTH , true ); _currentScreen->setLineProperty( LINE_DOUBLEHEIGHT , true ); break; case TY_ESC_DE('4' ) : /* Double height line, bottom half */ _currentScreen->setLineProperty( LINE_DOUBLEWIDTH , true ); _currentScreen->setLineProperty( LINE_DOUBLEHEIGHT , true ); break; case TY_ESC_DE('5' ) : /* Single width, single height line*/ _currentScreen->setLineProperty( LINE_DOUBLEWIDTH , false); _currentScreen->setLineProperty( LINE_DOUBLEHEIGHT , false); break; case TY_ESC_DE('6' ) : /* Double width, single height line*/ _currentScreen->setLineProperty( LINE_DOUBLEWIDTH , true); _currentScreen->setLineProperty( LINE_DOUBLEHEIGHT , false); break; case TY_ESC_DE('8' ) : _currentScreen->helpAlign ( ); break; // resize = \e[8;;t 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; case TY_CSI_PS('K', 0) : _currentScreen->clearToEndOfLine ( ); break; case TY_CSI_PS('K', 1) : _currentScreen->clearToBeginOfLine ( ); break; case TY_CSI_PS('K', 2) : _currentScreen->clearEntireLine ( ); break; case TY_CSI_PS('J', 0) : _currentScreen->clearToEndOfScreen ( ); break; case TY_CSI_PS('J', 1) : _currentScreen->clearToBeginOfScreen ( ); break; case TY_CSI_PS('J', 2) : _currentScreen->clearEntireScreen ( ); break; case TY_CSI_PS('J', 3) : clearHistory(); break; case TY_CSI_PS('g', 0) : _currentScreen->changeTabStop (false ); break; //VT100 case TY_CSI_PS('g', 3) : _currentScreen->clearTabStops ( ); break; //VT100 case TY_CSI_PS('h', 4) : _currentScreen-> setMode (MODE_Insert ); break; case TY_CSI_PS('h', 20) : setMode (MODE_NewLine ); break; case TY_CSI_PS('i', 0) : /* IGNORE: attached printer */ break; //VT100 case TY_CSI_PS('l', 4) : _currentScreen-> resetMode (MODE_Insert ); break; case TY_CSI_PS('l', 20) : resetMode (MODE_NewLine ); break; case TY_CSI_PS('s', 0) : saveCursor ( ); break; case TY_CSI_PS('u', 0) : restoreCursor ( ); break; 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', 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; case TY_CSI_PS('m', 32) : _currentScreen->setForeColor (COLOR_SPACE_SYSTEM, 2); break; case TY_CSI_PS('m', 33) : _currentScreen->setForeColor (COLOR_SPACE_SYSTEM, 3); break; case TY_CSI_PS('m', 34) : _currentScreen->setForeColor (COLOR_SPACE_SYSTEM, 4); break; case TY_CSI_PS('m', 35) : _currentScreen->setForeColor (COLOR_SPACE_SYSTEM, 5); break; case TY_CSI_PS('m', 36) : _currentScreen->setForeColor (COLOR_SPACE_SYSTEM, 6); break; case TY_CSI_PS('m', 37) : _currentScreen->setForeColor (COLOR_SPACE_SYSTEM, 7); break; case TY_CSI_PS('m', 38) : _currentScreen->setForeColor (p, q); break; case TY_CSI_PS('m', 39) : _currentScreen->setForeColor (COLOR_SPACE_DEFAULT, 0); break; case TY_CSI_PS('m', 40) : _currentScreen->setBackColor (COLOR_SPACE_SYSTEM, 0); break; case TY_CSI_PS('m', 41) : _currentScreen->setBackColor (COLOR_SPACE_SYSTEM, 1); break; case TY_CSI_PS('m', 42) : _currentScreen->setBackColor (COLOR_SPACE_SYSTEM, 2); break; case TY_CSI_PS('m', 43) : _currentScreen->setBackColor (COLOR_SPACE_SYSTEM, 3); break; case TY_CSI_PS('m', 44) : _currentScreen->setBackColor (COLOR_SPACE_SYSTEM, 4); break; case TY_CSI_PS('m', 45) : _currentScreen->setBackColor (COLOR_SPACE_SYSTEM, 5); break; case TY_CSI_PS('m', 46) : _currentScreen->setBackColor (COLOR_SPACE_SYSTEM, 6); break; case TY_CSI_PS('m', 47) : _currentScreen->setBackColor (COLOR_SPACE_SYSTEM, 7); break; case TY_CSI_PS('m', 48) : _currentScreen->setBackColor (p, q); break; case TY_CSI_PS('m', 49) : _currentScreen->setBackColor (COLOR_SPACE_DEFAULT, 1); break; case TY_CSI_PS('m', 90) : _currentScreen->setForeColor (COLOR_SPACE_SYSTEM, 8); break; case TY_CSI_PS('m', 91) : _currentScreen->setForeColor (COLOR_SPACE_SYSTEM, 9); break; case TY_CSI_PS('m', 92) : _currentScreen->setForeColor (COLOR_SPACE_SYSTEM, 10); break; case TY_CSI_PS('m', 93) : _currentScreen->setForeColor (COLOR_SPACE_SYSTEM, 11); break; case TY_CSI_PS('m', 94) : _currentScreen->setForeColor (COLOR_SPACE_SYSTEM, 12); break; case TY_CSI_PS('m', 95) : _currentScreen->setForeColor (COLOR_SPACE_SYSTEM, 13); break; case TY_CSI_PS('m', 96) : _currentScreen->setForeColor (COLOR_SPACE_SYSTEM, 14); break; case TY_CSI_PS('m', 97) : _currentScreen->setForeColor (COLOR_SPACE_SYSTEM, 15); break; case TY_CSI_PS('m', 100) : _currentScreen->setBackColor (COLOR_SPACE_SYSTEM, 8); break; case TY_CSI_PS('m', 101) : _currentScreen->setBackColor (COLOR_SPACE_SYSTEM, 9); break; case TY_CSI_PS('m', 102) : _currentScreen->setBackColor (COLOR_SPACE_SYSTEM, 10); break; case TY_CSI_PS('m', 103) : _currentScreen->setBackColor (COLOR_SPACE_SYSTEM, 11); break; case TY_CSI_PS('m', 104) : _currentScreen->setBackColor (COLOR_SPACE_SYSTEM, 12); break; case TY_CSI_PS('m', 105) : _currentScreen->setBackColor (COLOR_SPACE_SYSTEM, 13); break; case TY_CSI_PS('m', 106) : _currentScreen->setBackColor (COLOR_SPACE_SYSTEM, 14); break; case TY_CSI_PS('m', 107) : _currentScreen->setBackColor (COLOR_SPACE_SYSTEM, 15); break; case TY_CSI_PS('n', 5) : reportStatus ( ); break; case TY_CSI_PS('n', 6) : reportCursorPosition ( ); break; case TY_CSI_PS('q', 0) : /* IGNORED: LEDs off */ break; //VT100 case TY_CSI_PS('q', 1) : /* IGNORED: LED1 on */ break; //VT100 case TY_CSI_PS('q', 2) : /* IGNORED: LED2 on */ break; //VT100 case TY_CSI_PS('q', 3) : /* IGNORED: LED3 on */ break; //VT100 case TY_CSI_PS('q', 4) : /* IGNORED: LED4 on */ break; //VT100 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; case TY_CSI_PN('L' ) : _currentScreen->insertLines (p ); break; case TY_CSI_PN('M' ) : _currentScreen->deleteLines (p ); break; case TY_CSI_PN('P' ) : _currentScreen->deleteChars (p ); break; case TY_CSI_PN('S' ) : _currentScreen->scrollUp (p ); break; 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 case TY_CSI_PN('r' ) : setMargins (p, q); break; //VT100 case TY_CSI_PN('y' ) : /* IGNORED: Confidence test */ break; //VT100 case TY_CSI_PR('h', 1) : setMode (MODE_AppCuKeys); break; //VT100 case TY_CSI_PR('l', 1) : resetMode (MODE_AppCuKeys); break; //VT100 case TY_CSI_PR('s', 1) : saveMode (MODE_AppCuKeys); break; //FIXME case TY_CSI_PR('r', 1) : restoreMode (MODE_AppCuKeys); break; //FIXME case TY_CSI_PR('l', 2) : resetMode (MODE_Ansi ); break; //VT100 case TY_CSI_PR('h', 3) : setMode (MODE_132Columns);break; //VT100 case TY_CSI_PR('l', 3) : resetMode (MODE_132Columns);break; //VT100 case TY_CSI_PR('h', 4) : /* IGNORED: soft scrolling */ break; //VT100 case TY_CSI_PR('l', 4) : /* IGNORED: soft scrolling */ break; //VT100 case TY_CSI_PR('h', 5) : _currentScreen-> setMode (MODE_Screen ); break; //VT100 case TY_CSI_PR('l', 5) : _currentScreen-> resetMode (MODE_Screen ); break; //VT100 case TY_CSI_PR('h', 6) : _currentScreen-> setMode (MODE_Origin ); break; //VT100 case TY_CSI_PR('l', 6) : _currentScreen-> resetMode (MODE_Origin ); break; //VT100 case TY_CSI_PR('s', 6) : _currentScreen-> saveMode (MODE_Origin ); break; //FIXME case TY_CSI_PR('r', 6) : _currentScreen->restoreMode (MODE_Origin ); break; //FIXME case TY_CSI_PR('h', 7) : _currentScreen-> setMode (MODE_Wrap ); break; //VT100 case TY_CSI_PR('l', 7) : _currentScreen-> resetMode (MODE_Wrap ); break; //VT100 case TY_CSI_PR('s', 7) : _currentScreen-> saveMode (MODE_Wrap ); break; //FIXME case TY_CSI_PR('r', 7) : _currentScreen->restoreMode (MODE_Wrap ); break; //FIXME case TY_CSI_PR('h', 8) : /* IGNORED: autorepeat on */ break; //VT100 case TY_CSI_PR('l', 8) : /* IGNORED: autorepeat off */ break; //VT100 case TY_CSI_PR('s', 8) : /* IGNORED: autorepeat on */ break; //VT100 case TY_CSI_PR('r', 8) : /* IGNORED: autorepeat off */ break; //VT100 case TY_CSI_PR('h', 9) : /* IGNORED: interlace */ break; //VT100 case TY_CSI_PR('l', 9) : /* IGNORED: interlace */ break; //VT100 case TY_CSI_PR('s', 9) : /* IGNORED: interlace */ break; //VT100 case TY_CSI_PR('r', 9) : /* IGNORED: interlace */ break; //VT100 case TY_CSI_PR('h', 12) : /* IGNORED: Cursor blink */ break; //att610 case TY_CSI_PR('l', 12) : /* IGNORED: Cursor blink */ break; //att610 case TY_CSI_PR('s', 12) : /* IGNORED: Cursor blink */ break; //att610 case TY_CSI_PR('r', 12) : /* IGNORED: Cursor blink */ break; //att610 case TY_CSI_PR('h', 25) : setMode (MODE_Cursor ); break; //VT100 case TY_CSI_PR('l', 25) : resetMode (MODE_Cursor ); break; //VT100 case TY_CSI_PR('s', 25) : saveMode (MODE_Cursor ); break; //VT100 case TY_CSI_PR('r', 25) : restoreMode (MODE_Cursor ); break; //VT100 case TY_CSI_PR('h', 40) : setMode(MODE_Allow132Columns ); break; // XTERM case TY_CSI_PR('l', 40) : resetMode(MODE_Allow132Columns ); break; // XTERM case TY_CSI_PR('h', 41) : /* IGNORED: obsolete more(1) fix */ break; //XTERM case TY_CSI_PR('l', 41) : /* IGNORED: obsolete more(1) fix */ break; //XTERM case TY_CSI_PR('s', 41) : /* IGNORED: obsolete more(1) fix */ break; //XTERM case TY_CSI_PR('r', 41) : /* IGNORED: obsolete more(1) fix */ break; //XTERM case TY_CSI_PR('h', 47) : setMode (MODE_AppScreen); break; //VT100 case TY_CSI_PR('l', 47) : resetMode (MODE_AppScreen); break; //VT100 case TY_CSI_PR('s', 47) : saveMode (MODE_AppScreen); break; //XTERM case TY_CSI_PR('r', 47) : restoreMode (MODE_AppScreen); break; //XTERM case TY_CSI_PR('h', 67) : /* IGNORED: DECBKM */ break; //XTERM case TY_CSI_PR('l', 67) : /* IGNORED: DECBKM */ break; //XTERM case TY_CSI_PR('s', 67) : /* IGNORED: DECBKM */ break; //XTERM case TY_CSI_PR('r', 67) : /* IGNORED: DECBKM */ break; //XTERM // XTerm defines the following modes: // SET_VT200_MOUSE 1000 // SET_VT200_HIGHLIGHT_MOUSE 1001 // SET_BTN_EVENT_MOUSE 1002 // SET_ANY_EVENT_MOUSE 1003 // //Note about mouse modes: //There are four mouse modes which xterm-compatible terminals can support - 1000,1001,1002,1003 //Konsole currently supports mode 1000 (basic mouse press and release) and mode 1002 (dragging the mouse). //TODO: Implementation of mouse modes 1001 (something called hilight tracking) and //1003 (a slight variation on dragging the mouse) // case TY_CSI_PR('h', 1000) : setMode (MODE_Mouse1000); break; //XTERM case TY_CSI_PR('l', 1000) : resetMode (MODE_Mouse1000); break; //XTERM case TY_CSI_PR('s', 1000) : saveMode (MODE_Mouse1000); break; //XTERM case TY_CSI_PR('r', 1000) : restoreMode (MODE_Mouse1000); break; //XTERM case TY_CSI_PR('h', 1001) : /* IGNORED: hilite mouse tracking */ break; //XTERM case TY_CSI_PR('l', 1001) : resetMode (MODE_Mouse1001); break; //XTERM case TY_CSI_PR('s', 1001) : /* IGNORED: hilite mouse tracking */ break; //XTERM case TY_CSI_PR('r', 1001) : /* IGNORED: hilite mouse tracking */ break; //XTERM case TY_CSI_PR('h', 1002) : setMode (MODE_Mouse1002); break; //XTERM case TY_CSI_PR('l', 1002) : resetMode (MODE_Mouse1002); break; //XTERM case TY_CSI_PR('s', 1002) : saveMode (MODE_Mouse1002); break; //XTERM case TY_CSI_PR('r', 1002) : restoreMode (MODE_Mouse1002); break; //XTERM case TY_CSI_PR('h', 1003) : setMode (MODE_Mouse1003); break; //XTERM case TY_CSI_PR('l', 1003) : resetMode (MODE_Mouse1003); break; //XTERM 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 case TY_CSI_PR('l', 1047) : _screen[1]->clearEntireScreen(); resetMode(MODE_AppScreen); break; //XTERM case TY_CSI_PR('s', 1047) : saveMode (MODE_AppScreen); break; //XTERM case TY_CSI_PR('r', 1047) : restoreMode (MODE_AppScreen); break; //XTERM //FIXME: Unitoken: save translations case TY_CSI_PR('h', 1048) : saveCursor ( ); break; //XTERM case TY_CSI_PR('l', 1048) : restoreCursor ( ); break; //XTERM case TY_CSI_PR('s', 1048) : saveCursor ( ); break; //XTERM case TY_CSI_PR('r', 1048) : restoreCursor ( ); break; //XTERM //FIXME: every once new sequences like this pop up in xterm. // Here's a guess of what they could mean. 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; //FIXME: when changing between vt52 and ansi mode evtl do some resetting. case TY_VT52('A' ) : _currentScreen->cursorUp ( 1); break; //VT52 case TY_VT52('B' ) : _currentScreen->cursorDown ( 1); break; //VT52 case TY_VT52('C' ) : _currentScreen->cursorRight ( 1); break; //VT52 case TY_VT52('D' ) : _currentScreen->cursorLeft ( 1); break; //VT52 case TY_VT52('F' ) : setAndUseCharset (0, '0'); break; //VT52 case TY_VT52('G' ) : setAndUseCharset (0, 'B'); break; //VT52 case TY_VT52('H' ) : _currentScreen->setCursorYX (1,1 ); break; //VT52 case TY_VT52('I' ) : _currentScreen->reverseIndex ( ); break; //VT52 case TY_VT52('J' ) : _currentScreen->clearToEndOfScreen ( ); break; //VT52 case TY_VT52('K' ) : _currentScreen->clearToEndOfLine ( ); break; //VT52 case TY_VT52('Y' ) : _currentScreen->setCursorYX (p-31,q-31 ); break; //VT52 case TY_VT52('Z' ) : reportTerminalType ( ); break; //VT52 case TY_VT52('<' ) : setMode (MODE_Ansi ); break; //VT52 case TY_VT52('=' ) : setMode (MODE_AppKeyPad); break; //VT52 case TY_VT52('>' ) : resetMode (MODE_AppKeyPad); break; //VT52 case TY_CSI_PG('c' ) : reportSecondaryAttributes( ); break; //VT100 default: reportDecodingError(); break; }; } void Vt102Emulation::clearScreenAndSetColumns(int columnCount) { setImageSize(_currentScreen->getLines(),columnCount); clearEntireScreen(); setDefaultMargins(); _currentScreen->setCursorYX(0,0); } void Vt102Emulation::sendString(const char* s , int length) { if ( length >= 0 ) emit sendData(s, length, _codec); else emit sendData(s, static_cast(strlen(s)), _codec); } void Vt102Emulation::reportCursorPosition() { const int sz = 20; char tmp[sz]; const int r = snprintf(tmp, sz, "\033[%d;%dR",_currentScreen->getCursorY()+1,_currentScreen->getCursorX()+1); if (sz <= r) { qWarning("Vt102Emulation::reportCursorPosition: Buffer too small\n"); } sendString(tmp); } void Vt102Emulation::reportTerminalType() { // Primary device attribute response (Request was: ^[[0c or ^[[c (from TT321 Users Guide)) // VT220: ^[[?63;1;2;3;6;7;8c (list deps on emul. capabilities) // VT100: ^[[?1;2c // VT101: ^[[?1;0c // VT102: ^[[?6v if (getMode(MODE_Ansi)) sendString("\033[?1;2c"); // I'm a VT100 else sendString("\033/Z"); // I'm a VT52 } void Vt102Emulation::reportSecondaryAttributes() { // Seconday device attribute response (Request was: ^[[>0c or ^[[>c) if (getMode(MODE_Ansi)) sendString("\033[>0;115;0c"); // Why 115? ;) else sendString("\033/Z"); // FIXME I don't think VT52 knows about it but kept for // konsoles backward compatibility. } void Vt102Emulation::reportTerminalParms(int p) // DECREPTPARM { const int sz = 100; char tmp[sz]; const int r = snprintf(tmp, sz, "\033[%d;1;1;112;112;1;0x",p); // not really true. if (sz <= r) { qWarning("Vt102Emulation::reportTerminalParms: Buffer too small\n"); } sendString(tmp); } void Vt102Emulation::reportStatus() { sendString("\033[0n"); //VT100. Device status report. 0 = Ready. } void Vt102Emulation::reportAnswerBack() { // FIXME - Test this with VTTEST // This is really obsolete VT100 stuff. const char* ANSWER_BACK = ""; sendString(ANSWER_BACK); } /*! `cx',`cy' are 1-based. `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 1 = Mouse drag 2 = Mouse button release */ void Vt102Emulation::sendMouseEvent( int cb, int cx, int cy , int eventType ) { if (cx < 1 || cy < 1) return; // With the exception of the 1006 mode, button release is encoded in cb. // Note that if multiple extensions are enabled, the 1006 is used, so it's okay to check for only that. if (eventType == 2 && !getMode(MODE_Mouse1006)) cb = 3; // normal buttons are passed as 0x20 + button, // mouse wheel (buttons 4,5) as 0x5c + button if (cb >= 4) cb += 0x3c; //Mouse motion handling if ((getMode(MODE_Mouse1002) || getMode(MODE_Mouse1003)) && eventType == 1) cb += 0x20; //add 32 to signify motion event char command[32]; command[0] = '\0'; // 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", static_cast(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()) { QKeyEvent event(QEvent::KeyPress, 0, Qt::NoModifier, text); sendKeyEvent(&event); // expose as a big fat keypress event } } void Vt102Emulation::sendKeyEvent( QKeyEvent* event ) { Qt::KeyboardModifiers modifiers = event->modifiers(); KeyboardTranslator::States states = KeyboardTranslator::NoState; // get current states if (getMode(MODE_NewLine) ) states |= KeyboardTranslator::NewLineState; if (getMode(MODE_Ansi) ) states |= KeyboardTranslator::AnsiState; if (getMode(MODE_AppCuKeys)) states |= KeyboardTranslator::CursorKeysState; if (getMode(MODE_AppScreen)) states |= KeyboardTranslator::AlternateScreenState; if (getMode(MODE_AppKeyPad) && (modifiers & Qt::KeypadModifier)) states |= KeyboardTranslator::ApplicationKeypadState; // check flow control state if (modifiers & KeyboardTranslator::CTRL_MOD) { switch (event->key()) { case Qt::Key_S: emit flowControlKeyPressed(true); break; case Qt::Key_Q: case Qt::Key_C: // cancel flow control emit flowControlKeyPressed(false); break; } } // lookup key binding if ( _keyTranslator ) { KeyboardTranslator::Entry entry = _keyTranslator->findEntry( event->key() , modifiers, states ); // send result to terminal QByteArray textToSend; // special handling for the Alt (aka. Meta) modifier. pressing // Alt+[Character] results in Esc+[Character] being sent // (unless there is an entry defined for this particular combination // 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; if ( modifiers & Qt::AltModifier && !(wantsAltModifier || wantsAnyModifier) && !event->text().isEmpty() ) { textToSend.prepend("\033"); } if ( modifiers & Qt::MetaModifier && !(wantsMetaModifier || wantsAnyModifier) && !event->text().isEmpty() ) { textToSend.prepend("\030@s"); } if ( entry.command() != KeyboardTranslator::NoCommand ) { if (entry.command() & KeyboardTranslator::EraseCommand) textToSend += eraseChar(); // TODO command handling } else if ( !entry.text().isEmpty() ) { textToSend += _codec->fromUnicode(QString::fromUtf8(entry.text(true,modifiers))); } else if((modifiers & KeyboardTranslator::CTRL_MOD) && event->key() >= 0x40 && event->key() < 0x5f) { textToSend += (event->key() & 0x1f); } else if(event->key() == Qt::Key_Tab) { textToSend += 0x09; } else if (event->key() == Qt::Key_PageUp) { textToSend += "\033[5~"; } else if (event->key() == Qt::Key_PageDown) { textToSend += "\033[6~"; } else { textToSend += _codec->fromUnicode(event->text()); } Q_EMIT sendData( textToSend.constData(), textToSend.length(), _codec ); } else { // print an error message to the terminal if no key translator has been // set QString translatorError = tr("No keyboard translator available. " "The information needed to convert key presses " "into characters to send to the terminal " "is missing."); reset(); receiveData(translatorError.toUtf8().constData() , translatorError.count(), false); } } /* ------------------------------------------------------------------------- */ /* */ /* VT100 Charsets */ /* */ /* ------------------------------------------------------------------------- */ // Character Set Conversion ------------------------------------------------ -- /* The processing contains a VT100 specific code translation layer. It's still in use and mainly responsible for the line drawing graphics. These and some other glyphs are assigned to codes (0x5f-0xfe) normally occupied by the latin letters. Since this codes also appear within control sequences, the extra code conversion does not permute with the tokenizer and is placed behind it in the pipeline. It only applies to tokens, which represent plain characters. This conversion it eventually continued in TerminalDisplay.C, since it might involve VT100 enhanced fonts, which have these particular glyphs allocated in (0x00-0x1f) in their code page. */ #define CHARSET _charset[_currentScreen==_screen[1]] // Apply current character map. 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 return c; } /* "Charset" related part of the emulation state. This configures the VT100 charset filter. While most operation work on the current _screen, the following two are different. */ void Vt102Emulation::resetCharset(int scrno) { _charset[scrno].cu_cs = 0; qstrncpy(_charset[scrno].charset,"BBBB",4); _charset[scrno].sa_graphic = false; _charset[scrno].sa_pound = false; _charset[scrno].graphic = false; _charset[scrno].pound = false; } void Vt102Emulation::setCharset(int n, int cs) // on both screens. { _charset[0].charset[n&3] = static_cast(cs); useCharset(_charset[0].cu_cs); _charset[1].charset[n&3] = static_cast(cs); useCharset(_charset[1].cu_cs); } void Vt102Emulation::setAndUseCharset(int n, int cs) { CHARSET.charset[n&3] = static_cast(cs); useCharset(n&3); } void Vt102Emulation::useCharset(int n) { CHARSET.cu_cs = n&3; CHARSET.graphic = (CHARSET.charset[n&3] == '0'); CHARSET.pound = (CHARSET.charset[n&3] == 'A'); //This mode is obsolete } void Vt102Emulation::setDefaultMargins() { _screen[0]->setDefaultMargins(); _screen[1]->setDefaultMargins(); } void Vt102Emulation::setMargins(int t, int b) { _screen[0]->setMargins(t, b); _screen[1]->setMargins(t, b); } void Vt102Emulation::saveCursor() { CHARSET.sa_graphic = CHARSET.graphic; CHARSET.sa_pound = CHARSET.pound; //This mode is obsolete // we are not clear about these //sa_charset = charsets[cScreen->_charset]; //sa_charset_num = cScreen->_charset; _currentScreen->saveCursor(); } void Vt102Emulation::restoreCursor() { CHARSET.graphic = CHARSET.sa_graphic; CHARSET.pound = CHARSET.sa_pound; //This mode is obsolete _currentScreen->restoreCursor(); } /* ------------------------------------------------------------------------- */ /* */ /* Mode Operations */ /* */ /* ------------------------------------------------------------------------- */ /* Some of the emulations state is either added to the state of the screens. This causes some scoping problems, since different emulations choose to located the mode either to the current _screen or to both. For strange reasons, the extend of the rendition attributes ranges over all screens and not over the actual _screen. We decided on the precise precise extend, somehow. */ // "Mode" related part of the state. These are all booleans. void Vt102Emulation::resetModes() { // MODE_Allow132Columns is not reset here // to match Xterm's behaviour (see Xterm's VTReset() function) resetMode(MODE_132Columns); saveMode(MODE_132Columns); resetMode(MODE_Mouse1000); saveMode(MODE_Mouse1000); 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); resetMode(MODE_AppKeyPad); saveMode(MODE_AppKeyPad); resetMode(MODE_NewLine); setMode(MODE_Ansi); } void Vt102Emulation::setMode(int m) { _currentModes.mode[m] = true; switch (m) { case MODE_132Columns: if (getMode(MODE_Allow132Columns)) clearScreenAndSetColumns(132); else _currentModes.mode[m] = false; break; case MODE_Mouse1000: case MODE_Mouse1001: case MODE_Mouse1002: case MODE_Mouse1003: emit programUsesMouseChanged(false); break; case MODE_Mouse1007: emit enableAlternateScrolling(true); break; case MODE_BracketedPaste: emit programBracketedPasteModeChanged(true); break; case MODE_AppScreen : _screen[1]->clearSelection(); setScreen(1); break; } if (m < MODES_SCREEN || m == MODE_NewLine) { _screen[0]->setMode(m); _screen[1]->setMode(m); } } void Vt102Emulation::resetMode(int m) { _currentModes.mode[m] = false; switch (m) { case MODE_132Columns: if (getMode(MODE_Allow132Columns)) clearScreenAndSetColumns(80); break; case MODE_Mouse1000 : case MODE_Mouse1001 : case MODE_Mouse1002 : case MODE_Mouse1003 : emit programUsesMouseChanged(true); break; case MODE_Mouse1007: emit enableAlternateScrolling(false); break; case MODE_BracketedPaste: emit programBracketedPasteModeChanged(false); break; case MODE_AppScreen : _screen[0]->clearSelection(); setScreen(0); break; } if (m < MODES_SCREEN || m == MODE_NewLine) { _screen[0]->resetMode(m); _screen[1]->resetMode(m); } } void Vt102Emulation::saveMode(int m) { _savedModes.mode[m] = _currentModes.mode[m]; } void Vt102Emulation::restoreMode(int m) { if (_savedModes.mode[m]) setMode(m); else resetMode(m); } bool Vt102Emulation::getMode(int m) { return _currentModes.mode[m]; } char Vt102Emulation::eraseChar() const { KeyboardTranslator::Entry entry = _keyTranslator->findEntry( Qt::Key_Backspace, Qt::NoModifier, KeyboardTranslator::NoState); if ( entry.text().count() > 0 ) return entry.text().at(0); else return '\b'; } void Vt102Emulation::reportDecodingError() { if (tokenBufferPos == 0 || ( tokenBufferPos == 1 && (tokenBuffer[0] & 0xff) >= 32) ) return; qDebug() << "Undecodable sequence:" << QString::fromWCharArray(tokenBuffer, tokenBufferPos); } //#include "Vt102Emulation.moc" deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/Vt102Emulation.h000066400000000000000000000143601475472654300260340ustar00rootroot00000000000000/* This file is part of Konsole, an X terminal. Copyright 2007-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 (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. */ #ifndef VT102EMULATION_H #define VT102EMULATION_H // Standard Library #include // Qt #include #include #include // Konsole #include "Emulation.h" #include "Screen.h" #define MODE_AppCuKeys (MODES_SCREEN+0) // Application cursor keys (DECCKM) #define MODE_AppKeyPad (MODES_SCREEN+1) // #define MODE_Mouse1000 (MODES_SCREEN+2) // Send mouse X,Y position on press and release #define MODE_Mouse1001 (MODES_SCREEN+3) // Use Hilight mouse tracking #define MODE_Mouse1002 (MODES_SCREEN+4) // Use cell motion mouse tracking #define MODE_Mouse1003 (MODES_SCREEN+5) // Use all motion mouse tracking #define MODE_Mouse1005 (MODES_SCREEN+6) // Xterm-style extended coordinates #define MODE_Mouse1006 (MODES_SCREEN+7) // 2nd Xterm-style extended coordinates #define MODE_Mouse1007 (MODES_SCREEN+8) // XTerm Alternate Scroll mode; also check AlternateScrolling profile property #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 { struct CharCodes { // coding info char charset[4]; // int cu_cs; // actual charset. bool graphic; // Some VT100 tricks bool pound ; // Some VT100 tricks bool sa_graphic; // saved graphic bool sa_pound; // saved pound }; /** * 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 * features such as mouse input handling. * See http://rtfm.etla.org/xterm/ctlseq.html for a description of xterm's escape * sequences. * */ class Vt102Emulation : public Emulation { Q_OBJECT public: /** Constructs a new emulation */ Vt102Emulation(); ~Vt102Emulation() override; // reimplemented from Emulation void clearEntireScreen() override; void reset() override; char eraseChar() const override; public slots: // reimplemented from Emulation void sendString(const char*,int length = -1) override; void sendText(const QString& text) override; void sendKeyEvent(QKeyEvent*) override; void sendMouseEvent(int buttons, int column, int line, int eventType) override; virtual void focusLost(); virtual void focusGained(); protected: // reimplemented from Emulation void setMode(int mode) override; void resetMode(int mode) override; void receiveChar(wchar_t cc) override; private slots: //causes changeTitle() to be emitted for each (int,QString) pair in pendingTitleUpdates //used to buffer multiple title updates void updateTitle(); private: wchar_t applyCharset(wchar_t c); void setCharset(int n, int cs); void useCharset(int n); void setAndUseCharset(int n, int cs); void saveCursor(); void restoreCursor(); void resetCharset(int scrno); void setMargins(int top, int bottom); //set margins for all screens back to their defaults void setDefaultMargins(); // returns true if 'mode' is set or false otherwise bool getMode (int mode); // saves the current boolean value of 'mode' void saveMode (int 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 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); void addArgument(); 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 processToken(int code, wchar_t p, int q); void processWindowAttributeChange(); void requestWindowAttribute(int); void reportTerminalType(); void reportSecondaryAttributes(); void reportStatus(); void reportAnswerBack(); void reportCursorPosition(); void reportTerminalParms(int p); void onScrollLock(); void scrollLock(const bool lock); // clears the screen and resizes it to the specified // number of columns void clearScreenAndSetColumns(int columnCount); CharCodes _charset[2]; class TerminalState { public: // Initializes all modes to false TerminalState() { memset(&mode,false,MODE_total * sizeof(bool)); } bool mode[MODE_total]; }; TerminalState _currentModes; TerminalState _savedModes; //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 //output from the terminal QHash _pendingTitleUpdates; QTimer* _titleUpdateTimer; bool _reportFocusEvents; }; } #endif // VT102EMULATION_H deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/color-schemes/000077500000000000000000000000001475472654300257305ustar00rootroot00000000000000deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/color-schemes/BlackOnLightYellow.schema000066400000000000000000000026451475472654300326160ustar00rootroot00000000000000# example scheme for konsole # the title is to appear in the menu. title Black on Light Yellow # foreground colors # note that the default background color is flagged # to become transparent when an image is present. # slot transparent bold # | | | # V V--color--V V V color 0 0 0 0 0 0 # regular foreground color (Black) color 1 255 255 221 1 0 # regular background color (Light Yellow) color 2 0 0 0 0 0 # regular color 0 Black color 3 178 24 24 0 0 # regular color 1 Red color 4 24 178 24 0 0 # regular color 2 Green color 5 178 104 24 0 0 # regular color 3 Yellow color 6 24 24 178 0 0 # regular color 4 Blue color 7 178 24 178 0 0 # regular color 5 Magenta color 8 24 178 178 0 0 # regular color 6 Cyan color 9 178 178 178 0 0 # regular color 7 White # intensive colors # instead of changing the colors, we've flaged the text to become bold color 10 0 0 0 0 1 # intensive foreground color color 11 255 255 221 1 0 # intensive background color color 12 104 104 104 0 0 # intensive color 0 color 13 255 84 84 0 0 # intensive color 1 color 14 84 255 84 0 0 # intensive color 2 color 15 255 255 84 0 0 # intensive color 3 color 16 84 84 255 0 0 # intensive color 4 color 17 255 84 255 0 0 # intensive color 5 color 18 84 255 255 0 0 # intensive color 6 color 19 255 255 255 0 0 # intensive color 7 deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/color-schemes/BlackOnRandomLight.colorscheme000066400000000000000000000023761475472654300336270ustar00rootroot00000000000000[Background] Bold=false Color=247,247,214 Transparency=true MaxRandomHue=340 [BackgroundIntense] Bold=false Color=255,255,221 Transparency=true [Color0] Bold=false Color=0,0,0 Transparency=false [Color0Intense] Bold=false Color=104,104,104 Transparency=false [Color1] Bold=false Color=178,24,24 Transparency=false [Color1Intense] Bold=false Color=255,84,84 Transparency=false [Color2] Bold=false Color=24,178,24 Transparency=false [Color2Intense] Bold=false Color=84,255,84 Transparency=false [Color3] Bold=false Color=178,104,24 Transparency=false [Color3Intense] Bold=false Color=255,255,84 Transparency=false [Color4] Bold=false Color=24,24,178 Transparency=false [Color4Intense] Bold=false Color=84,84,255 Transparency=false [Color5] Bold=false Color=178,24,178 Transparency=false [Color5Intense] Bold=false Color=255,84,255 Transparency=false [Color6] Bold=false Color=24,178,178 Transparency=false [Color6Intense] Bold=false Color=84,255,255 Transparency=false [Color7] Bold=false Color=178,178,178 Transparency=false [Color7Intense] Bold=false Color=255,255,255 Transparency=false [Foreground] Bold=false Color=0,0,0 Transparency=false [ForegroundIntense] Bold=true Color=0,0,0 Transparency=false [General] Description=Black on Random Light Opacity=1 deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/color-schemes/BlackOnWhite.schema000066400000000000000000000026271475472654300314330ustar00rootroot00000000000000# example scheme for konsole # the title is to appear in the menu. title Black on White # foreground colors # note that the default background color is flagged # to become transparent when an image is present. # slot transparent bold # | | | # V V--color--V V V color 0 0 0 0 0 0 # regular foreground color (Black) color 1 248 248 248 1 0 # regular background color (White) color 2 0 0 0 0 0 # regular color 0 Black color 3 178 24 24 0 0 # regular color 1 Red color 4 24 178 24 0 0 # regular color 2 Green color 5 178 104 24 0 0 # regular color 3 Yellow color 6 24 24 178 0 0 # regular color 4 Blue color 7 178 24 178 0 0 # regular color 5 Magenta color 8 24 178 178 0 0 # regular color 6 Cyan color 9 178 178 178 0 0 # regular color 7 White # intensive colors # instead of changing the colors, we've flaged the text to become bold color 10 0 0 0 0 1 # intensive foreground color color 11 255 255 255 1 0 # intensive background color color 12 104 104 104 0 0 # intensive color 0 color 13 255 84 84 0 0 # intensive color 1 color 14 84 255 84 0 0 # intensive color 2 color 15 255 255 84 0 0 # intensive color 3 color 16 84 84 255 0 0 # intensive color 4 color 17 255 84 255 0 0 # intensive color 5 color 18 84 255 255 0 0 # intensive color 6 color 19 255 255 255 0 0 # intensive color 7 deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/color-schemes/BreezeModified.colorscheme000066400000000000000000000017471475472654300330430ustar00rootroot00000000000000[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= deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/color-schemes/Dark.colorscheme000066400000000000000000000023241475472654300310370ustar00rootroot00000000000000 [Background] Bold=true Color=37,37,37 Transparency=false [BackgroundIntense] Bold=true Color=0,0,0 Transparency=false [Color0] Bold=true Color=0,0,0 Transparency=false [Color0Intense] Bold=true Color=104,104,104 Transparency=false [Color1] Bold=true Color=178,24,24 Transparency=false [Color1Intense] Bold=true Color=255,84,84 Transparency=false [Color2] Bold=true Color=24,178,24 Transparency=false [Color2Intense] Bold=true Color=133,153,0 Transparency=false [Color3] Bold=true Color=178,104,24 Transparency=false [Color3Intense] Bold=true Color=255,255,84 Transparency=false [Color4] Bold=true Color=52,101,164 Transparency=false [Color4Intense] Bold=true Color=52,101,164 Transparency=false [Color5] Bold=true Color=225,30,225 Transparency=false [Color5Intense] Bold=true Color=30,144,255 Transparency=false [Color6] Bold=true Color=24,178,178 Transparency=false [Color6Intense] Bold=true Color=253,246,227 Transparency=false [Color7] Bold=true Color=238,232,213 Transparency=false [Color7Intense] Bold=true Color=255,255,255 Transparency=false [Foreground] Bold=true Color=0,205,0 Transparency=false [ForegroundIntense] Bold=true Color=0,205,0 Transparency=false [General] Description=Green on Black Opacity=1 deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/color-schemes/DarkPastels.colorscheme000066400000000000000000000023651475472654300324000ustar00rootroot00000000000000[Background] Bold=false Color=44,44,44 Transparency=false [BackgroundIntense] Bold=true Color=44,44,44 Transparency=false [Color0] Bold=false Color=63,63,63 Transparency=false [Color0Intense] Bold=true Color=112,144,128 Transparency=false [Color1] Bold=false Color=112,80,80 Transparency=false [Color1Intense] Bold=true Color=220,163,163 Transparency=false [Color2] Bold=false Color=96,180,138 Transparency=false [Color2Intense] Bold=true Color=114,213,163 Transparency=false [Color3] Bold=false Color=223,175,143 Transparency=false [Color3Intense] Bold=true Color=240,223,175 Transparency=false [Color4] Bold=false Color=154,184,215 Transparency=false [Color4Intense] Bold=true Color=148,191,243 Transparency=false [Color5] Bold=false Color=220,140,195 Transparency=false [Color5Intense] Bold=true Color=236,147,211 Transparency=false [Color6] Bold=false Color=140,208,211 Transparency=false [Color6Intense] Bold=true Color=147,224,227 Transparency=false [Color7] Bold=false Color=220,220,204 Transparency=false [Color7Intense] Bold=true Color=255,255,255 Transparency=false [Foreground] Bold=false Color=220,220,204 Transparency=false [ForegroundIntense] Bold=true Color=220,220,204 Transparency=false [General] Description=Dark Pastels Opacity=1 deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/color-schemes/GreenOnBlack.colorscheme000066400000000000000000000023461475472654300324540ustar00rootroot00000000000000 [Background] Bold=false Color=0,0,0 Transparency=false [BackgroundIntense] Bold=false Color=0,0,0 Transparency=false [Color0] Bold=false Color=0,0,0 Transparency=false [Color0Intense] Bold=false Color=104,104,104 Transparency=false [Color1] Bold=false Color=250,75,75 Transparency=false [Color1Intense] Bold=false Color=255,84,84 Transparency=false [Color2] Bold=false Color=24,178,24 Transparency=false [Color2Intense] Bold=false Color=84,255,84 Transparency=false [Color3] Bold=false Color=178,104,24 Transparency=false [Color3Intense] Bold=false Color=255,255,84 Transparency=false [Color4] Bold=false Color=92,167,251 Transparency=false [Color4Intense] Bold=false Color=84,84,255 Transparency=false [Color5] Bold=false Color=225,30,225 Transparency=false [Color5Intense] Bold=false Color=255,84,255 Transparency=false [Color6] Bold=false Color=24,178,178 Transparency=false [Color6Intense] Bold=false Color=84,255,255 Transparency=false [Color7] Bold=false Color=178,178,178 Transparency=false [Color7Intense] Bold=false Color=255,255,255 Transparency=false [Foreground] Bold=false Color=24,240,24 Transparency=false [ForegroundIntense] Bold=true Color=24,240,24 Transparency=false [General] Description=Green on Black Opacity=1 deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/color-schemes/Light.colorscheme000066400000000000000000000023271475472654300312300ustar00rootroot00000000000000 [Background] Bold=true Color=248,248,248 Transparency=false [BackgroundIntense] Bold=true Color=255,255,255 Transparency=false [Color0] Bold=true Color=0,0,0 Transparency=false [Color0Intense] Bold=true Color=104,104,104 Transparency=false [Color1] Bold=true Color=178,24,24 Transparency=false [Color1Intense] Bold=true Color=255,84,84 Transparency=false [Color2] Bold=true Color=24,178,24 Transparency=false [Color2Intense] Bold=true Color=133,153,0 Transparency=false [Color3] Bold=true Color=178,104,24 Transparency=false [Color3Intense] Bold=true Color=233,233,79 Transparency=false [Color4] Bold=true Color=24,24,178 Transparency=false [Color4Intense] Bold=true Color=52,101,164 Transparency=false [Color5] Bold=true Color=225,30,225 Transparency=false [Color5Intense] Bold=true Color=30,144,255 Transparency=false [Color6] Bold=true Color=24,178,178 Transparency=false [Color6Intense] Bold=true Color=24,178,178 Transparency=false [Color7] Bold=true Color=238,232,213 Transparency=false [Color7Intense] Bold=true Color=238,232,213 Transparency=false [Foreground] Bold=true Color=0,0,0 Transparency=false [ForegroundIntense] Bold=true Color=0,0,0 Transparency=false [General] Description=Green on Black Opacity=1 deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/color-schemes/Linux.colorscheme000066400000000000000000000015711475472654300312600ustar00rootroot00000000000000[Background] Bold=false Color=0,0,0 [BackgroundIntense] Bold=false Color=104,104,104 [Color0] Bold=false Color=0,0,0 [Color0Intense] Bold=false Color=104,104,104 [Color1] Bold=false Color=178,24,24 [Color1Intense] Bold=false Color=255,84,84 [Color2] Bold=false Color=24,178,24 [Color2Intense] Bold=false Color=84,255,84 [Color3] Bold=false Color=178,104,24 [Color3Intense] Bold=false Color=255,255,84 [Color4] Bold=false Color=24,24,178 [Color4Intense] Bold=false Color=84,84,255 [Color5] Bold=false Color=178,24,178 [Color5Intense] Bold=false Color=255,84,255 [Color6] Bold=false Color=24,178,178 [Color6Intense] Bold=false Color=84,255,255 [Color7] Bold=false Color=178,178,178 [Color7Intense] Bold=false Color=255,255,255 [Foreground] Bold=false Color=178,178,178 [ForegroundIntense] Bold=false Color=255,255,255 [General] Description=Linux Colors deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/color-schemes/Solarized.colorscheme000066400000000000000000000017201475472654300321110ustar00rootroot00000000000000[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 deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/color-schemes/SolarizedLight.colorscheme000066400000000000000000000017501475472654300331040ustar00rootroot00000000000000[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 deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/color-schemes/Tango.colorscheme000066400000000000000000000013221475472654300312230ustar00rootroot00000000000000[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 deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/color-schemes/Theme1.colorscheme000066400000000000000000000024251475472654300313030ustar00rootroot00000000000000[General] Description=Deepin Terminal Dark Mode Color Name=elementary [Background] Bold=true Color=16, 16, 16 Transparency=false [BackgroundIntense] Bold=true Color=16, 16, 16 Transparency=false [Color0] Bold=true Color=48, 48, 48 Transparency=false [Color0Intense] Bold=true Color=48, 48, 48 Transparency=false [Color1] Bold=true Color=178, 24, 24 Transparency=false [Color1Intense] Bold=true Color=255, 84, 84 Transparency=false [Color2] Bold=true Color=24, 178, 24 Transparency=false [Color2Intense] Bold=true Color=106, 176, 23 Transparency=false [Color3] Bold=true Color=255, 192, 5 Transparency=false [Color3Intense] Bold=true Color=255, 192, 5 Transparency=false [Color4] Bold=true Color=24, 24, 178 Transparency=false [Color4Intense] Bold=true Color=0, 79, 158 Transparency=false [Color5] Bold=true Color=236, 0, 72 Transparency=false [Color5Intense] Bold=true Color=236, 0, 72 Transparency=false [Color6] Bold=true Color=42, 167, 231 Transparency=false [Color6Intense] Bold=true Color=42, 167, 231 Transparency=false [Color7] Bold=true Color=242, 242, 242 Transparency=false [Color7Intense] Bold=true Color=242, 242, 242 Transparency=false [Foreground] Bold=true Color=242, 242, 242 Transparency=false [ForegroundIntense] Bold=true Color=242, 242, 242 Transparency=false deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/color-schemes/Theme10.colorscheme000066400000000000000000000024111475472654300313560ustar00rootroot00000000000000[General] Description=Deepin Terminal Light Mode Color Name=one light [Background] Bold=true Color=248, 248, 248 Transparency=false [BackgroundIntense] Bold=true Color=248, 248, 248 Transparency=false [Color0] Bold=true Color=0, 0, 0 Transparency=false [Color0Intense] Bold=true Color=0, 0, 0 Transparency=false [Color1] Bold=true Color=178, 24, 24 Transparency=false [Color1Intense] Bold=true Color=255, 84, 84 Transparency=false [Color2] Bold=true Color=24, 178, 24 Transparency=false [Color2Intense] Bold=true Color=65, 147, 62 Transparency=false [Color3] Bold=true Color=133, 85, 4 Transparency=false [Color3Intense] Bold=true Color=133, 85, 4 Transparency=false [Color4] Bold=true Color=24, 24, 178 Transparency=false [Color4Intense] Bold=true Color=49, 94, 238 Transparency=false [Color5] Bold=true Color=147, 0, 146 Transparency=false [Color5Intense] Bold=true Color=147, 0, 146 Transparency=false [Color6] Bold=true Color=14, 111, 173 Transparency=false [Color6Intense] Bold=true Color=14, 111, 173 Transparency=false [Color7] Bold=true Color=142, 143, 150 Transparency=false [Color7Intense] Bold=true Color=142, 143, 150 Transparency=false [Foreground] Bold=true Color=0, 0, 0 Transparency=false [ForegroundIntense] Bold=true Color=0, 0, 0 Transparency=false deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/color-schemes/Theme2.colorscheme000066400000000000000000000024261475472654300313050ustar00rootroot00000000000000[General] Description=Deepin Terminal Dark Mode Color Name=empathy [Background] Bold=true Color=49, 9, 36 Transparency=false [BackgroundIntense] Bold=true Color=49, 9, 36 Transparency=false [Color0] Bold=true Color=46, 52, 54 Transparency=false [Color0Intense] Bold=true Color=46, 52, 54 Transparency=false [Color1] Bold=true Color=178, 24, 24 Transparency=false [Color1Intense] Bold=true Color=255, 84, 84 Transparency=false [Color2] Bold=true Color=24, 178, 24 Transparency=false [Color2Intense] Bold=true Color=78, 154, 6 Transparency=false [Color3] Bold=true Color=223, 216, 65 Transparency=false [Color3Intense] Bold=true Color=223, 216, 65 Transparency=false [Color4] Bold=true Color=24, 24, 178 Transparency=false [Color4Intense] Bold=true Color=46, 100, 166 Transparency=false [Color5] Bold=true Color=117, 80, 123 Transparency=false [Color5Intense] Bold=true Color=117, 80, 123 Transparency=false [Color6] Bold=true Color=134, 188, 38 Transparency=false [Color6Intense] Bold=true Color=134, 188, 38 Transparency=false [Color7] Bold=true Color=211, 215, 207 Transparency=false [Color7Intense] Bold=true Color=211, 215, 207 Transparency=false [Foreground] Bold=true Color=198, 174, 190 Transparency=false [ForegroundIntense] Bold=true Color=198, 174, 190 Transparency=false deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/color-schemes/Theme3.colorscheme000066400000000000000000000024501475472654300313030ustar00rootroot00000000000000[General] Description=Deepin Terminal Dark Mode Color Name=tomorrow night blue [Background] Bold=true Color=29, 31, 33 Transparency=false [BackgroundIntense] Bold=true Color=29, 31, 33 Transparency=false [Color0] Bold=true Color=0, 0, 0 Transparency=false [Color0Intense] Bold=true Color=0, 0, 0 Transparency=false [Color1] Bold=true Color=178, 24, 24 Transparency=false [Color1Intense] Bold=true Color=255, 84, 84 Transparency=false [Color2] Bold=true Color=24, 178, 24 Transparency=false [Color2Intense] Bold=true Color=181, 189, 104 Transparency=false [Color3] Bold=true Color=240, 198, 116 Transparency=false [Color3Intense] Bold=true Color=240, 198, 116 Transparency=false [Color4] Bold=true Color=24, 24, 178 Transparency=false [Color4Intense] Bold=true Color=129, 162, 190 Transparency=false [Color5] Bold=true Color=178, 147, 187 Transparency=false [Color5Intense] Bold=true Color=178, 147, 187 Transparency=false [Color6] Bold=true Color=138, 190, 183 Transparency=false [Color6Intense] Bold=true Color=138, 190, 183 Transparency=false [Color7] Bold=true Color=255, 254, 254 Transparency=false [Color7Intense] Bold=true Color=255, 254, 254 Transparency=false [Foreground] Bold=true Color=141, 178, 172 Transparency=false [ForegroundIntense] Bold=true Color=141, 178, 172 Transparency=false deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/color-schemes/Theme4.colorscheme000066400000000000000000000024201475472654300313010ustar00rootroot00000000000000[General] Description=Deepin Terminal Dark Mode Color Name=bim [Background] Bold=true Color=1, 40, 73 Transparency=false [BackgroundIntense] Bold=true Color=1, 40, 73 Transparency=false [Color0] Bold=true Color=44, 36, 35 Transparency=false [Color0Intense] Bold=true Color=44, 36, 35 Transparency=false [Color1] Bold=true Color=178, 24, 24 Transparency=false [Color1Intense] Bold=true Color=255, 84, 84 Transparency=false [Color2] Bold=true Color=24, 178, 24 Transparency=false [Color2Intense] Bold=true Color=169, 238, 85 Transparency=false [Color3] Bold=true Color=245, 162, 85 Transparency=false [Color3Intense] Bold=true Color=245, 162, 85 Transparency=false [Color4] Bold=true Color=24, 24, 178 Transparency=false [Color4Intense] Bold=true Color=94, 162, 236 Transparency=false [Color5] Bold=true Color=169, 87, 236 Transparency=false [Color5Intense] Bold=true Color=169, 87, 236 Transparency=false [Color6] Bold=true Color=94, 238, 160 Transparency=false [Color6Intense] Bold=true Color=94, 238, 160 Transparency=false [Color7] Bold=true Color=145, 137, 136 Transparency=false [Color7Intense] Bold=true Color=145, 137, 136 Transparency=false [Foreground] Bold=true Color=255, 213, 0 Transparency=false [ForegroundIntense] Bold=true Color=255, 213, 0 Transparency=false deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/color-schemes/Theme5.colorscheme000066400000000000000000000024071475472654300313070ustar00rootroot00000000000000[General] Description=Deepin Terminal Dark Mode Color Name=freya [Background] Bold=true Color=0, 0, 0 Transparency=false [BackgroundIntense] Bold=true Color=0, 0, 0 Transparency=false [Color0] Bold=true Color=7, 54, 66 Transparency=false [Color0Intense] Bold=true Color=7, 54, 66 Transparency=false [Color1] Bold=true Color=178, 24, 24 Transparency=false [Color1Intense] Bold=true Color=255, 84, 84 Transparency=false [Color2] Bold=true Color=24, 178, 24 Transparency=false [Color2Intense] Bold=true Color=133, 153, 0 Transparency=false [Color3] Bold=true Color=181, 137, 0 Transparency=false [Color3Intense] Bold=true Color=181, 137, 0 Transparency=false [Color4] Bold=true Color=24, 24, 178 Transparency=false [Color4Intense] Bold=true Color=38, 139, 210 Transparency=false [Color5] Bold=true Color=236, 0, 72 Transparency=false [Color5Intense] Bold=true Color=236, 0, 72 Transparency=false [Color6] Bold=true Color=42, 161, 152 Transparency=false [Color6Intense] Bold=true Color=42, 161, 152 Transparency=false [Color7] Bold=true Color=148, 163, 165 Transparency=false [Color7Intense] Bold=true Color=148, 163, 165 Transparency=false [Foreground] Bold=true Color=35, 181, 211 Transparency=false [ForegroundIntense] Bold=true Color=35, 181, 211 Transparency=false deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/color-schemes/Theme6.colorscheme000066400000000000000000000024271475472654300313120ustar00rootroot00000000000000[General] Description=Deepin Terminal Dark Mode Color Name=hybrid [Background] Bold=true Color=20, 20, 20 Transparency=false [BackgroundIntense] Bold=true Color=20, 20, 20 Transparency=false [Color0] Bold=true Color=40, 42, 46 Transparency=false [Color0Intense] Bold=true Color=40, 42, 46 Transparency=false [Color1] Bold=true Color=178, 24, 24 Transparency=false [Color1Intense] Bold=true Color=255, 84, 84 Transparency=false [Color2] Bold=true Color=24, 178, 24 Transparency=false [Color2Intense] Bold=true Color=140, 148, 64 Transparency=false [Color3] Bold=true Color=222, 147, 95 Transparency=false [Color3Intense] Bold=true Color=222, 147, 95 Transparency=false [Color4] Bold=true Color=24, 24, 178 Transparency=false [Color4Intense] Bold=true Color=95, 129, 157 Transparency=false [Color5] Bold=true Color=133, 103, 143 Transparency=false [Color5Intense] Bold=true Color=133, 103, 143 Transparency=false [Color6] Bold=true Color=94, 141, 135 Transparency=false [Color6Intense] Bold=true Color=94, 141, 135 Transparency=false [Color7] Bold=true Color=150, 152, 150 Transparency=false [Color7Intense] Bold=true Color=150, 152, 150 Transparency=false [Foreground] Bold=true Color=254, 144, 0 Transparency=false [ForegroundIntense] Bold=true Color=254, 144, 0 Transparency=false deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/color-schemes/Theme7.colorscheme000066400000000000000000000024431475472654300313110ustar00rootroot00000000000000[General] Description=Deepin Terminal Dark Mode Color Name=ocean dark [Background] Bold=true Color=28, 31, 39 Transparency=false [BackgroundIntense] Bold=true Color=28, 31, 39 Transparency=false [Color0] Bold=true Color=79, 79, 79 Transparency=false [Color0Intense] Bold=true Color=79, 79, 79 Transparency=false [Color1] Bold=true Color=178, 24, 24 Transparency=false [Color1Intense] Bold=true Color=255, 84, 84 Transparency=false [Color2] Bold=true Color=24, 178, 24 Transparency=false [Color2Intense] Bold=true Color=175, 211, 131 Transparency=false [Color3] Bold=true Color=229, 192, 121 Transparency=false [Color3Intense] Bold=true Color=229, 192, 121 Transparency=false [Color4] Bold=true Color=24, 24, 178 Transparency=false [Color4Intense] Bold=true Color=125, 144, 164 Transparency=false [Color5] Bold=true Color=164, 121, 157 Transparency=false [Color5Intense] Bold=true Color=164, 121, 157 Transparency=false [Color6] Bold=true Color=133, 166, 165 Transparency=false [Color6Intense] Bold=true Color=133, 166, 165 Transparency=false [Color7] Bold=true Color=238, 237, 238 Transparency=false [Color7Intense] Bold=true Color=238, 237, 238 Transparency=false [Foreground] Bold=true Color=99, 124, 206 Transparency=false [ForegroundIntense] Bold=true Color=99, 124, 206 Transparency=false deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/color-schemes/Theme8.colorscheme000066400000000000000000000024061475472654300313110ustar00rootroot00000000000000[General] Description=Deepin Terminal Dark Mode Color Name=deepin [Background] Bold=true Color=0, 0, 0 Transparency=false [BackgroundIntense] Bold=true Color=0, 0, 0 Transparency=false [Color0] Bold=true Color=7, 54, 66 Transparency=false [Color0Intense] Bold=true Color=7, 54, 66 Transparency=false [Color1] Bold=true Color=178, 24, 24 Transparency=false [Color1Intense] Bold=true Color=255, 84, 84 Transparency=false [Color2] Bold=true Color=24, 178, 24 Transparency=false [Color2Intense] Bold=true Color=133, 153, 0 Transparency=false [Color3] Bold=true Color=181, 137, 0 Transparency=false [Color3Intense] Bold=true Color=181, 137, 0 Transparency=false [Color4] Bold=true Color=24, 24, 178 Transparency=false [Color4Intense] Bold=true Color=52, 101, 164 Transparency=false [Color5] Bold=true Color=211, 54, 130 Transparency=false [Color5Intense] Bold=true Color=211, 54, 130 Transparency=false [Color6] Bold=true Color=42, 161, 152 Transparency=false [Color6Intense] Bold=true Color=42, 161, 152 Transparency=false [Color7] Bold=true Color=238, 232, 213 Transparency=false [Color7Intense] Bold=true Color=238, 232, 213 Transparency=false [Foreground] Bold=true Color=0, 205, 0 Transparency=false [ForegroundIntense] Bold=true Color=0, 205, 0 Transparency=false deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/color-schemes/Theme9.colorscheme000066400000000000000000000024211475472654300313070ustar00rootroot00000000000000[General] Description=Deepin Terminal Light Mode Color Name=ura [Background] Bold=true Color=254, 255, 238 Transparency=false [BackgroundIntense] Bold=true Color=254, 255, 238 Transparency=false [Color0] Bold=true Color=0, 0, 0 Transparency=false [Color0Intense] Bold=true Color=0, 0, 0 Transparency=false [Color1] Bold=true Color=178, 24, 24 Transparency=false [Color1Intense] Bold=true Color=255, 84, 84 Transparency=false [Color2] Bold=true Color=111, 194, 27 Transparency=false [Color2Intense] Bold=true Color=24, 178, 24 Transparency=false [Color3] Bold=true Color=194, 111, 27 Transparency=false [Color3Intense] Bold=true Color=194, 111, 27 Transparency=false [Color4] Bold=true Color=24, 24, 178 Transparency=false [Color4Intense] Bold=true Color=27, 111, 194 Transparency=false [Color5] Bold=true Color=111, 27, 194 Transparency=false [Color5Intense] Bold=true Color=111, 27, 194 Transparency=false [Color6] Bold=true Color=27, 194, 111 Transparency=false [Color6Intense] Bold=true Color=27, 194, 111 Transparency=false [Color7] Bold=true Color=128, 128, 128 Transparency=false [Color7Intense] Bold=true Color=128, 128, 128 Transparency=false [Foreground] Bold=true Color=57, 53, 44 Transparency=false [ForegroundIntense] Bold=true Color=57, 53, 44 Transparency=false deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/color-schemes/Ubuntu.colorscheme000066400000000000000000000013171475472654300314410ustar00rootroot00000000000000[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,236deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/color-schemes/WhiteOnBlack.schema000066400000000000000000000026271475472654300314330ustar00rootroot00000000000000# example scheme for konsole # the title is to appear in the menu. title White on Black # foreground colors # note that the default background color is flagged # to become transparent when an image is present. # slot transparent bold # | | | # V V--color--V V V color 0 255 255 255 0 0 # regular foreground color (White) color 1 0 0 0 1 0 # regular background color (Black) color 2 0 0 0 0 0 # regular color 0 Black color 3 178 24 24 0 0 # regular color 1 Red color 4 24 178 24 0 0 # regular color 2 Green color 5 178 104 24 0 0 # regular color 3 Yellow color 6 24 24 178 0 0 # regular color 4 Blue color 7 178 24 178 0 0 # regular color 5 Magenta color 8 24 178 178 0 0 # regular color 6 Cyan color 9 178 178 178 0 0 # regular color 7 White # intensive colors # instead of changing the colors, we've flaged the text to become bold color 10 255 255 255 0 1 # intensive foreground color color 11 0 0 0 1 0 # intensive background color color 12 104 104 104 0 0 # intensive color 0 color 13 255 84 84 0 0 # intensive color 1 color 14 84 255 84 0 0 # intensive color 2 color 15 255 255 84 0 0 # intensive color 3 color 16 84 84 255 0 0 # intensive color 4 color 17 255 84 255 0 0 # intensive color 5 color 18 84 255 255 0 0 # intensive color 6 color 19 255 255 255 0 0 # intensive color 7 deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/color-schemes/historic/000077500000000000000000000000001475472654300275545ustar00rootroot00000000000000BlackOnLightColor.schema000066400000000000000000000026431475472654300341640ustar00rootroot00000000000000deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/color-schemes/historic# example scheme for konsole # the title is to appear in the menu. title Black on Light Color # foreground colors # note that the default background color is flagged # to become transparent when an image is present. # slot transparent bold # | | | # V V--color--V V V color 0 0 0 0 0 0 # regular foreground color (Black) rcolor 1 30 255 1 0 # regular background color (Light Color) color 2 0 0 0 0 0 # regular color 0 Black color 3 178 24 24 0 0 # regular color 1 Red color 4 24 178 24 0 0 # regular color 2 Green color 5 178 104 24 0 0 # regular color 3 Yellow color 6 24 24 178 0 0 # regular color 4 Blue color 7 178 24 178 0 0 # regular color 5 Magenta color 8 24 178 178 0 0 # regular color 6 Cyan color 9 178 178 178 0 0 # regular color 7 White # intensive colors # instead of changing the colors, we've flaged the text to become bold color 10 0 0 0 0 1 # intensive foreground color color 11 255 255 221 1 0 # intensive background color color 12 104 104 104 0 0 # intensive color 0 color 13 255 84 84 0 0 # intensive color 1 color 14 84 255 84 0 0 # intensive color 2 color 15 255 255 84 0 0 # intensive color 3 color 16 84 84 255 0 0 # intensive color 4 color 17 255 84 255 0 0 # intensive color 5 color 18 84 255 255 0 0 # intensive color 6 color 19 255 255 255 0 0 # intensive color 7 deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/color-schemes/historic/DarkPicture.schema000066400000000000000000000026511475472654300331570ustar00rootroot00000000000000# example scheme for konsole # the title is to appear in the menu. title Marble image tile Blkmarble.jpg # foreground colors # note that the default background color is flagged # to become transparent when an image is present. # slot transparent bold # | | | # V V--color--V V V color 0 255 255 255 0 0 # regular foreground color (White) color 1 0 0 0 1 0 # regular background color (Black) color 2 0 0 0 0 0 # regular color 0 Black color 3 178 24 24 0 0 # regular color 1 Red color 4 24 178 24 0 0 # regular color 2 Green color 5 178 104 24 0 0 # regular color 3 Yellow color 6 24 24 178 0 0 # regular color 4 Blue color 7 178 24 178 0 0 # regular color 5 Magenta color 8 24 178 178 0 0 # regular color 6 Cyan color 9 178 178 178 0 0 # regular color 7 White # intensive colors # instead of changing the colors, we've flaged the text to become bold color 10 255 255 255 0 1 # intensive foreground color color 11 0 0 0 1 0 # intensive background color color 12 104 104 104 0 0 # intensive color 0 color 13 255 84 84 0 0 # intensive color 1 color 14 84 255 84 0 0 # intensive color 2 color 15 255 255 84 0 0 # intensive color 3 color 16 84 84 255 0 0 # intensive color 4 color 17 255 84 255 0 0 # intensive color 5 color 18 84 255 255 0 0 # intensive color 6 color 19 255 255 255 0 0 # intensive color 7 deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/color-schemes/historic/Example.Schema000066400000000000000000000031031475472654300322660ustar00rootroot00000000000000# example scheme for konsole # the title is to appear in the menu. title Ugly 1 # add a wallpaper, if you like. Second word one of { tile,center,full } image tile /opt/kde/share/wallpapers/dancy_pants.jpg # foreground colors # note that the default background color is flagged # to become transparent when an image is present. # slot transparent bold # | | | # V V--color--V V V color 0 0 0 0 0 0 # regular foreground color (Black) color 1 255 255 255 1 0 # regular background color (White) color 2 0 0 0 0 0 # regular color 0 Black color 3 255 0 0 0 0 # regular color 1 Red color 4 0 255 0 0 0 # regular color 2 Green color 5 255 255 0 0 0 # regular color 3 Yellow color 6 0 0 255 0 0 # regular color 4 Blue color 7 255 0 255 0 0 # regular color 5 Magenta color 8 0 255 255 0 0 # regular color 6 Cyan color 9 255 255 255 0 0 # regular color 7 White # intensive colors # instead of changing the colors, we've flaged the text to become bold color 10 0 0 0 0 1 # intensive foreground color color 11 255 255 255 1 1 # intensive background color color 12 0 0 0 0 1 # intensive color 0 color 13 255 0 0 0 1 # intensive color 1 color 14 0 255 0 0 1 # intensive color 2 color 15 255 255 0 0 1 # intensive color 3 color 16 0 0 255 0 1 # intensive color 4 color 17 255 0 255 0 1 # intensive color 5 color 18 0 255 255 0 1 # intensive color 6 color 19 255 255 255 0 1 # intensive color 7 deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/color-schemes/historic/GreenOnBlack.schema000066400000000000000000000026271475472654300332370ustar00rootroot00000000000000# example scheme for konsole # the title is to appear in the menu. title Green on Black # foreground colors # note that the default background color is flagged # to become transparent when an image is present. # slot transparent bold # | | | # V V--color--V V V color 0 24 240 24 0 0 # regular foreground color (Green) color 1 0 0 0 1 0 # regular background color (Black) color 2 0 0 0 0 0 # regular color 0 Black color 3 178 24 24 0 0 # regular color 1 Red color 4 24 178 24 0 0 # regular color 2 Green color 5 178 104 24 0 0 # regular color 3 Yellow color 6 24 24 178 0 0 # regular color 4 Blue color 7 178 24 178 0 0 # regular color 5 Magenta color 8 24 178 178 0 0 # regular color 6 Cyan color 9 178 178 178 0 0 # regular color 7 White # intensive colors # instead of changing the colors, we've flaged the text to become bold color 10 24 240 24 0 1 # intensive foreground color color 11 0 0 0 1 0 # intensive background color color 12 104 104 104 0 0 # intensive color 0 color 13 255 84 84 0 0 # intensive color 1 color 14 84 255 84 0 0 # intensive color 2 color 15 255 255 84 0 0 # intensive color 3 color 16 84 84 255 0 0 # intensive color 4 color 17 255 84 255 0 0 # intensive color 5 color 18 84 255 255 0 0 # intensive color 6 color 19 255 255 255 0 0 # intensive color 7 deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/color-schemes/historic/GreenTint.schema000066400000000000000000000031141475472654300326340ustar00rootroot00000000000000# linux color schema for konsole title Green Tint transparency 0.3 0 150 0 # FIXME # # The flaw in this schema is that "blick" comes out on the # Linux console as intensive background, really. # Since this is not used in clients you'll hardly notice # it in practice. # foreground colors # note that the default background color is flagged # to become transparent when an image is present. # slot transparent bold # | red grn blu | | # V V--color--V V V color 0 178 178 178 0 0 # regular foreground color (White) color 1 0 0 0 1 0 # regular background color (Black) color 2 0 0 0 0 0 # regular color 0 Black color 3 178 24 24 0 0 # regular color 1 Red color 4 24 178 24 0 0 # regular color 2 Green color 5 178 104 24 0 0 # regular color 3 Yellow color 6 24 24 178 0 0 # regular color 4 Blue color 7 178 24 178 0 0 # regular color 5 Magenta color 8 24 178 178 0 0 # regular color 6 Cyan color 9 178 178 178 0 0 # regular color 7 White # intensive colors # instead of changing the colors, we've flaged the text to become bold color 10 255 255 255 0 0 # intensive foreground color color 11 104 104 104 1 0 # intensive background color color 12 104 104 104 0 0 # intensive color 0 color 13 255 84 84 0 0 # intensive color 1 color 14 84 255 84 0 0 # intensive color 2 color 15 255 255 84 0 0 # intensive color 3 color 16 84 84 255 0 0 # intensive color 4 color 17 255 84 255 0 0 # intensive color 5 color 18 84 255 255 0 0 # intensive color 6 color 19 255 255 255 0 0 # intensive color 7 deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/color-schemes/historic/GreenTint_MC.schema000066400000000000000000000031401475472654300332120ustar00rootroot00000000000000# linux color schema for konsole title Green Tint with Transparent MC transparency 0.3 0 150 0 # FIXME # # The flaw in this schema is that "blick" comes out on the # Linux console as intensive background, really. # Since this is not used in clients you'll hardly notice # it in practice. # foreground colors # note that the default background color is flagged # to become transparent when an image is present. # slot transparent bold # | red grn blu | | # V V--color--V V V color 0 178 178 178 0 0 # regular foreground color (White) color 1 0 0 0 1 0 # regular background color (Black) color 2 0 0 0 0 0 # regular color 0 Black color 3 178 24 24 0 0 # regular color 1 Red color 4 24 178 24 0 0 # regular color 2 Green color 5 178 104 24 0 0 # regular color 3 Yellow color 6 0 0 0 1 0 # regular color 4 Blue color 7 178 24 178 0 0 # regular color 5 Magenta color 8 24 178 178 0 0 # regular color 6 Cyan color 9 178 178 178 0 0 # regular color 7 White # intensive colors # instead of changing the colors, we've flaged the text to become bold color 10 255 255 255 0 0 # intensive foreground color color 11 104 104 104 1 0 # intensive background color color 12 104 104 104 0 0 # intensive color 0 color 13 255 84 84 0 0 # intensive color 1 color 14 84 255 84 0 0 # intensive color 2 color 15 255 255 84 0 0 # intensive color 3 color 16 84 84 255 0 0 # intensive color 4 color 17 255 84 255 0 0 # intensive color 5 color 18 84 255 255 0 0 # intensive color 6 color 19 255 255 255 0 0 # intensive color 7 deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/color-schemes/historic/LightPicture.schema000066400000000000000000000026461475472654300333510ustar00rootroot00000000000000# example scheme for konsole # the title is to appear in the menu. title Paper image tile Paper01.jpg # foreground colors # note that the default background color is flagged # to become transparent when an image is present. # slot transparent bold # | | | # V V--color--V V V color 0 0 0 0 0 0 # regular foreground color (Black) color 1 255 255 255 1 0 # regular background color (White) color 2 0 0 0 0 0 # regular color 0 Black color 3 178 24 24 0 0 # regular color 1 Red color 4 24 178 24 0 0 # regular color 2 Green color 5 178 104 24 0 0 # regular color 3 Yellow color 6 24 24 178 0 0 # regular color 4 Blue color 7 178 24 178 0 0 # regular color 5 Magenta color 8 24 178 178 0 0 # regular color 6 Cyan color 9 178 178 178 0 0 # regular color 7 White # intensive colors # instead of changing the colors, we've flaged the text to become bold color 10 0 0 0 0 1 # intensive foreground color color 11 255 255 255 1 0 # intensive background color color 12 104 104 104 0 0 # intensive color 0 color 13 255 84 84 0 0 # intensive color 1 color 14 84 255 84 0 0 # intensive color 2 color 15 255 255 84 0 0 # intensive color 3 color 16 84 84 255 0 0 # intensive color 4 color 17 255 84 255 0 0 # intensive color 5 color 18 84 255 255 0 0 # intensive color 6 color 19 255 255 255 0 0 # intensive color 7 deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/color-schemes/historic/Linux.schema000066400000000000000000000030641475472654300320400ustar00rootroot00000000000000# linux color schema for konsole title Linux Colors # FIXME # # The flaw in this schema is that "blick" comes out on the # Linux console as intensive background, really. # Since this is not used in clients you'll hardly notice # it in practice. # foreground colors # note that the default background color is flagged # to become transparent when an image is present. # slot transparent bold # | red grn blu | | # V V--color--V V V color 0 178 178 178 0 0 # regular foreground color (White) color 1 0 0 0 1 0 # regular background color (Black) color 2 0 0 0 0 0 # regular color 0 Black color 3 178 24 24 0 0 # regular color 1 Red color 4 24 178 24 0 0 # regular color 2 Green color 5 178 104 24 0 0 # regular color 3 Yellow color 6 24 24 178 0 0 # regular color 4 Blue color 7 178 24 178 0 0 # regular color 5 Magenta color 8 24 178 178 0 0 # regular color 6 Cyan color 9 178 178 178 0 0 # regular color 7 White # intensive colors # instead of changing the colors, we've flaged the text to become bold color 10 255 255 255 0 0 # intensive foreground color color 11 104 104 104 1 0 # intensive background color color 12 104 104 104 0 0 # intensive color 0 color 13 255 84 84 0 0 # intensive color 1 color 14 84 255 84 0 0 # intensive color 2 color 15 255 255 84 0 0 # intensive color 3 color 16 84 84 255 0 0 # intensive color 4 color 17 255 84 255 0 0 # intensive color 5 color 18 84 255 255 0 0 # intensive color 6 color 19 255 255 255 0 0 # intensive color 7 deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/color-schemes/historic/README.Schema000066400000000000000000000102441475472654300316340ustar00rootroot00000000000000[README.Schema] The schemata offered in the Options/Schema menu are taken from from configurations files with a *.schema pattern either located in $KDEDIR/share/apps/konsole or ~/.kde/share/apps/konsole. Schemata allow to configure the color set that konsole uses, together with some more information on rendition processing. Syntax File :: { [Line] ['#' Comment] '\n' } Line :: "title" Title :: "image" Usage PathToPictureFile :: "transparency" Fade Red Green Blue :: "color" Slot Red Green Blue Transparent Bold :: "rcolor" Slot Saturation Value Transparent Bold :: "sysfg" Slot Transparent Bold :: "sysbg" Slot Transparent Bold Meaning - Title is the text to appear in the Option/Schema menu. It should be unique among all other schemata therefore. - The "image" clause allows to place an image on the konsole's background. - Usage can be either - "tile" - the image is tilewise replicated. - "center" - the image is centered. - "full" - the image is stretched to fit the window size. - The Path of the picture can both be relative (to kde wallpapers) or absolute. When a schema uses a background image (or transparency) one has to make at least one color slot transparent to achive any visible effect. Please read below about the "Transparent" field in color,sysbg,sysfg. - The "transparency" clause picks and uses the background of the desktop as if it where an image together with a fade effect. This effect will fade the background to the specified color. The "Fade" is a real value between 0 and 1, indicating the strength of the fade. A value of 0 will not change the image, a value of 1 will make it the fade color everywhere, and in between. This will make the "glas" of the window be of the color given in the clause and being more(1) or less(0) intransparent. - The remaining clauses (color,sysbg,sysfg) are used to setup konsoles rendition system. To this end, konsole offers 20 color slots. Slot Meaning ----- -------------------------- 0 regular foreground color 1 regular background color 2-9 regular bgr color 0-7 10 intensive foreground color 11 intensive background color 12-19 intensive bgr color 0-7 The traditional meaning of the "bgr" color codes has a bitwise interpretation of an additive three primary color scheme inherited from early EGA color terminals. Color Bits Colors ----- ---- ------- 0 000 Black 1 001 Red 2 010 Green 3 011 Yellow 4 100 Blue 5 101 Magenta 6 110 Cyan 7 111 White One may or may not stick to this tradition. Konsole allows to assign colors freely to slots. The slots fall apart into two groups, regular and intensive colors. The later are used when BOLD rendition is used by the client. Each of the groups have a default fore- and background color and the said bgr colors. Normal terminal processing will simply use the default colors. The color desired for a slot is indicated in the Red Green Blue fields of the color clause. Use the sysfg or the sysbg clause to indicate the default fore and background colors of the desktop. To specify randomized color for a slot use the clause rcolor. The two parameters to it being Saturation - the amount of colour, and Value, the darkness of the colour. To use transparency/images and to simulate the behavior of the xterm, one can supply two additional tags to each slot: - Transparent (0/1) meaning to show the background picture, if any. - Bold (0/1) to render characters bold. If you know about the escape codes, you might have noticed that intensive and bold rendition are sort of confused. This is inherited by the xterm which konsole is simulating. One can use the colortest.sh script supplied with the konsole source distribution to test a schema. The schema installed with konsole are more or less demonstrations and not really beauty, beside the Linux.schema, perhaps, which is made after the VGA colors. deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/color-schemes/historic/README.default.Schema000066400000000000000000000027621475472654300332650ustar00rootroot00000000000000# default scheme for konsole (only here for documentation purposes) # the title is to appear in the menu. title Konsole Defaults # image tile /opt/kde/share/wallpapers/gray2.jpg # foreground colors # note that the default background color is flagged # to become transparent when an image is present. # slot transparent bold # | | | # V V--color--V V V color 0 0 0 0 0 0 # regular foreground color (Black) color 1 255 255 255 1 0 # regular background color (White) color 2 0 0 0 0 0 # regular color 0 Black color 3 178 24 24 0 0 # regular color 1 Red color 4 24 178 24 0 0 # regular color 2 Green color 5 178 104 24 0 0 # regular color 3 Yellow color 6 24 24 178 0 0 # regular color 4 Blue color 7 178 24 178 0 0 # regular color 5 Magenta color 8 24 178 178 0 0 # regular color 6 Cyan color 9 178 178 178 0 0 # regular color 7 White # intensive colors # instead of changing the colors, we've flaged the text to become bold color 10 0 0 0 0 1 # intensive foreground color color 11 255 255 255 1 0 # intensive background color color 12 104 104 104 0 0 # intensive color 0 color 13 255 84 84 0 0 # intensive color 1 color 14 84 255 84 0 0 # intensive color 2 color 15 255 255 84 0 0 # intensive color 3 color 16 84 84 255 0 0 # intensive color 4 color 17 255 84 255 0 0 # intensive color 5 color 18 84 255 255 0 0 # intensive color 6 color 19 255 255 255 0 0 # intensive color 7 deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/color-schemes/historic/Transparent.schema000066400000000000000000000031241475472654300332370ustar00rootroot00000000000000# linux color schema for konsole title Transparent Konsole transparency 0.35 0 0 0 # FIXME # # The flaw in this schema is that "blick" comes out on the # Linux console as intensive background, really. # Since this is not used in clients you'll hardly notice # it in practice. # foreground colors # note that the default background color is flagged # to become transparent when an image is present. # slot transparent bold # | red grn blu | | # V V--color--V V V color 0 178 178 178 0 0 # regular foreground color (White) color 1 0 0 0 1 0 # regular background color (Black) color 2 0 0 0 0 0 # regular color 0 Black color 3 178 24 24 0 0 # regular color 1 Red color 4 24 178 24 0 0 # regular color 2 Green color 5 178 104 24 0 0 # regular color 3 Yellow color 6 24 24 178 0 0 # regular color 4 Blue color 7 178 24 178 0 0 # regular color 5 Magenta color 8 24 178 178 0 0 # regular color 6 Cyan color 9 178 178 178 0 0 # regular color 7 White # intensive colors # instead of changing the colors, we've flaged the text to become bold color 10 255 255 255 0 0 # intensive foreground color color 11 104 104 104 1 0 # intensive background color color 12 104 104 104 0 0 # intensive color 0 color 13 255 84 84 0 0 # intensive color 1 color 14 84 255 84 0 0 # intensive color 2 color 15 255 255 84 0 0 # intensive color 3 color 16 84 84 255 0 0 # intensive color 4 color 17 255 84 255 0 0 # intensive color 5 color 18 84 255 255 0 0 # intensive color 6 color 19 255 255 255 0 0 # intensive color 7 deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/color-schemes/historic/Transparent_MC.schema000066400000000000000000000032051475472654300336160ustar00rootroot00000000000000# linux color schema for konsole title Transparent for MC transparency 0.35 0 0 0 # FIXME # # The flaw in this schema is that "blick" comes out on the # Linux console as intensive background, really. # Since this is not used in clients you'll hardly notice # it in practice. # foreground colors # note that the default background color is flagged # to become transparent when an image is present. # slot transparent bold # | red grn blu | | # V V--color--V V V color 0 178 178 178 0 0 # regular foreground color (White) color 1 0 0 0 1 0 # regular background color (Black) color 2 0 0 0 0 0 # regular color 0 Black color 3 178 24 24 0 0 # regular color 1 Red color 4 24 178 24 0 0 # regular color 2 Green color 5 178 104 24 0 0 # regular color 3 Yellow #color 6 24 24 178 0 0 # regular color 4 Blue color 6 0 0 0 1 0 # regular color 4 Blue color 7 178 24 178 0 0 # regular color 5 Magenta color 8 24 178 178 0 0 # regular color 6 Cyan color 9 178 178 178 0 0 # regular color 7 White # intensive colors # instead of changing the colors, we've flaged the text to become bold color 10 255 255 255 0 0 # intensive foreground color color 11 104 104 104 1 0 # intensive background color color 12 104 104 104 0 0 # intensive color 0 color 13 255 84 84 0 0 # intensive color 1 color 14 84 255 84 0 0 # intensive color 2 color 15 255 255 84 0 0 # intensive color 3 color 16 84 84 255 0 0 # intensive color 4 color 17 255 84 255 0 0 # intensive color 5 color 18 84 255 255 0 0 # intensive color 6 color 19 255 255 255 0 0 # intensive color 7 Transparent_darkbg.schema000066400000000000000000000026331475472654300344760ustar00rootroot00000000000000deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/color-schemes/historic# linux color schema for konsole title Transparent, Dark Background transparency 0.75 0 0 0 # foreground colors # note that the default background color is flagged # to become transparent when an image is present. # slot transparent bold # | red grn blu | | # V V--color--V V V color 0 255 255 255 0 0 # regular foreground color (White) color 1 0 0 0 1 0 # regular background color (Black) color 2 0 0 0 0 0 # regular color 0 Black color 3 178 24 24 0 0 # regular color 1 Red color 4 24 178 24 0 0 # regular color 2 Green color 5 178 104 24 0 0 # regular color 3 Yellow color 6 24 24 178 0 0 # regular color 4 Blue color 7 178 24 178 0 0 # regular color 5 Magenta color 8 24 178 178 0 0 # regular color 6 Cyan color 9 178 178 178 0 0 # regular color 7 White # intensive colors # instead of changing the colors, we've flaged the text to become bold color 10 255 255 255 0 0 # intensive foreground color color 11 104 104 104 1 0 # intensive background color color 12 104 104 104 0 0 # intensive color 0 color 13 255 84 84 0 0 # intensive color 1 color 14 84 255 84 0 0 # intensive color 2 color 15 255 255 84 0 0 # intensive color 3 color 16 84 84 255 0 0 # intensive color 4 color 17 255 84 255 0 0 # intensive color 5 color 18 84 255 255 0 0 # intensive color 6 color 19 255 255 255 0 0 # intensive color 7 Transparent_lightbg.schema000066400000000000000000000034421475472654300346630ustar00rootroot00000000000000deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/color-schemes/historic# linux color schema for konsole title Transparent, Light Background transparency 0.1 0 0 0 # This is a schema for very light backgrounds. It makes some # hacks about the colors to make Midnight Commander transparent # and with suitable colors. # foreground colors # note that the default background color is flagged # to become transparent when an image is present. # slot transparent bold # | red grn blu | | # V V--color--V V V color 0 50 50 50 0 0 # regular foreground color (DarkGray) color 1 200 200 200 1 0 # regular background color (White) # color 2 0 0 0 0 0 # regular color 0 Black color 2 200 200 200 1 0 # regular background color (White) color 3 178 24 24 0 0 # regular color 1 Red color 4 24 178 24 0 0 # regular color 2 Green color 5 178 104 24 0 0 # regular color 3 Yellow #color 6 24 24 178 0 0 # regular color 4 Blue color 6 0 0 0 1 0 # regular color 4 Blue # Blue is transparent, to make MC transparent color 7 178 24 178 0 0 # regular color 5 Magenta color 8 24 178 178 0 0 # regular color 6 Cyan # color 9 178 178 178 0 0 # regular color 7 White color 9 50 50 50 0 0 # regular foreground color (DarkGray) # intensive colors # instead of changing the colors, we've flaged the text to become bold color 10 0 0 0 0 0 # intensive foreground color color 11 255 255 255 1 0 # intensive background color color 12 104 104 104 0 0 # intensive color 0 color 13 255 84 84 0 0 # intensive color 1 color 14 84 255 84 0 0 # intensive color 2 color 15 255 255 84 0 0 # intensive color 3 color 16 84 84 255 0 0 # intensive color 4 color 17 255 84 255 0 0 # intensive color 5 color 18 84 255 255 0 0 # intensive color 6 color 19 255 255 255 0 0 # intensive color 7 deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/color-schemes/historic/XTerm.schema000066400000000000000000000031551475472654300320010ustar00rootroot00000000000000# xterm color schema for konsole # xterm colors can be configured (almost) like # konsole colors can. This is the uncustomized # xterm schema. # Please refere to your local xterm setup files # if this schema differs. title XTerm Colors # foreground colors ------------------------------- # note that the default background color is flagged # to become transparent when an image is present. # slot transparent bold # | red grn blu | | # V V--color--V V V color 0 0 0 0 0 0 # regular foreground color (Black) color 1 255 255 255 1 0 # regular background color (White) color 2 0 0 0 0 0 # regular color 0 Black color 3 205 0 0 0 0 # regular color 1 Red color 4 0 205 0 0 0 # regular color 2 Green color 5 205 205 0 0 0 # regular color 3 Yellow color 6 0 0 205 0 0 # regular color 4 Blue color 7 205 0 205 0 0 # regular color 5 Magenta color 8 0 205 205 0 0 # regular color 6 Cyan color 9 229 229 229 0 0 # regular color 7 White # intensive colors ------------------------------------------- # for some strange reason, intensive colors are bold, also. color 10 77 77 77 0 1 # intensive foreground color color 11 255 255 255 1 1 # intensive background color color 12 77 77 77 0 1 # intensive color 0 color 13 255 0 0 0 1 # intensive color 1 color 14 0 255 0 0 1 # intensive color 2 color 15 255 255 0 0 1 # intensive color 3 color 16 0 0 255 0 1 # intensive color 4 color 17 255 0 255 0 1 # intensive color 5 color 18 0 255 255 0 1 # intensive color 6 color 19 255 255 255 0 1 # intensive color 7 deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/color-schemes/historic/syscolor.schema000066400000000000000000000026521475472654300326200ustar00rootroot00000000000000# schema that uses system colors # the title is to appear in the menu. title System Colors # image none # foreground colors # note that the default background color is flagged # to become transparent when an image is present. # slot transparent bold # | | | # V V--color--V V V sysfg 0 0 0 # regular foreground color (system) sysbg 1 1 0 # regular background color (system) color 2 0 0 0 0 0 # regular color 0 Black color 3 178 24 24 0 0 # regular color 1 Red color 4 24 178 24 0 0 # regular color 2 Green color 5 178 104 24 0 0 # regular color 3 Yellow color 6 24 24 178 0 0 # regular color 4 Blue color 7 178 24 178 0 0 # regular color 5 Magenta color 8 24 178 178 0 0 # regular color 6 Cyan color 9 178 178 178 0 0 # regular color 7 White # intensive colors # instead of changing the colors, we've flaged the text to become bold color 10 0 0 0 0 1 # intensive foreground color color 11 255 255 255 1 0 # intensive background color color 12 104 104 104 0 0 # intensive color 0 color 13 255 84 84 0 0 # intensive color 1 color 14 84 255 84 0 0 # intensive color 2 color 15 255 255 84 0 0 # intensive color 3 color 16 84 84 255 0 0 # intensive color 4 color 17 255 84 255 0 0 # intensive color 5 color 18 84 255 255 0 0 # intensive color 6 color 19 255 255 255 0 0 # intensive color 7 deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/color-schemes/historic/vim.schema000066400000000000000000000027071475472654300315370ustar00rootroot00000000000000# VIM-recommended color schema for konsole # VIM (VI improved) in "help xiterm" recommends these colors for xterm. title VIM Colors # foreground colors ------------------------------- # note that the default background color is flagged # to become transparent when an image is present. # slot transparent bold # | red grn blu | | # V V--color--V V V color 0 0 0 0 0 0 # regular foreground color (Black) color 1 255 255 255 1 0 # regular background color (White) color 2 0 0 0 0 0 # regular color 0 Black color 3 192 0 0 0 0 # regular color 1 Red color 4 0 128 0 0 0 # regular color 2 Green color 5 128 128 0 0 0 # regular color 3 Yellow color 6 0 0 192 0 0 # regular color 4 Blue color 7 192 0 192 0 0 # regular color 5 Magenta color 8 0 128 128 0 0 # regular color 6 Cyan color 9 192 192 192 0 0 # regular color 7 White # intensive colors ------------------------------------------- color 10 77 77 77 0 1 # intensive foreground color color 11 255 255 255 1 1 # intensive background color color 12 128 128 128 0 0 # intensive color 0 color 13 255 96 96 0 0 # intensive color 1 color 14 0 255 0 0 0 # intensive color 2 color 15 255 255 0 0 0 # intensive color 3 color 16 128 128 255 0 0 # intensive color 4 color 17 255 64 255 0 0 # intensive color 5 color 18 0 255 255 0 0 # intensive color 6 color 19 255 255 255 0 0 # intensive color 7 deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/default.keytab000066400000000000000000000114211475472654300260110ustar00rootroot00000000000000# [README.default.Keytab] Buildin Keyboard Table # # To customize your keyboard, copy this file to something # ending with .keytab and change it to meet you needs. # Please read the README.KeyTab and the README.keyboard # in this case. # # -------------------------------------------------------------- keyboard "Default (XFree 4)" # -------------------------------------------------------------- # # Note that this particular table is a "risc" version made to # ease customization without bothering with obsolete details. # See VT100.keytab for the more hairy stuff. # # -------------------------------------------------------------- # common keys key Escape : "\E" key Tab -Shift : "\t" key Tab +Shift+Ansi : "\E[Z" key Tab +Shift-Ansi : "\t" key Backtab +Ansi : "\E[Z" key Backtab -Ansi : "\t" key Return-Shift-NewLine : "\r" key Return-Shift+NewLine : "\r\n" key Return+Shift : "\EOM" # Backspace and Delete codes are preserving CTRL-H. key Backspace : "\x7f" # Arrow keys in VT52 mode # shift up/down are reserved for scrolling. # shift left/right are reserved for switching between tabs (this is hardcoded). key Up -Shift-Ansi : "\EA" key Down -Shift-Ansi : "\EB" key Right-Shift-Ansi : "\EC" key Left -Shift-Ansi : "\ED" # Arrow keys in ANSI mode with Application - and Normal Cursor Mode) key Up -Shift-AnyMod+Ansi+AppCuKeys : "\EOA" key Down -Shift-AnyMod+Ansi+AppCuKeys : "\EOB" key Right -Shift-AnyMod+Ansi+AppCuKeys : "\EOC" key Left -Shift-AnyMod+Ansi+AppCuKeys : "\EOD" key Up -Shift-AnyMod+Ansi-AppCuKeys : "\E[A" key Down -Shift-AnyMod+Ansi-AppCuKeys : "\E[B" key Right -Shift-AnyMod+Ansi-AppCuKeys : "\E[C" key Left -Shift-AnyMod+Ansi-AppCuKeys : "\E[D" key Up -Shift+AnyMod+Ansi : "\E[1;*A" key Down -Shift+AnyMod+Ansi : "\E[1;*B" key Right -Shift+AnyMod+Ansi : "\E[1;*C" key Left -Shift+AnyMod+Ansi : "\E[1;*D" # other grey PC keys key Enter+NewLine : "\r\n" key Enter-NewLine : "\r" key Home -AnyMod -AppCuKeys : "\E[H" key End -AnyMod -AppCuKeys : "\E[F" key Home -AnyMod +AppCuKeys : "\EOH" key End -AnyMod +AppCuKeys : "\EOF" key Home +AnyMod : "\E[1;*H" key End +AnyMod : "\E[1;*F" key Insert -AnyMod : "\E[2~" 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;*~" # Function keys key F1 -AnyMod : "\EOP" key F2 -AnyMod : "\EOQ" key F3 -AnyMod : "\EOR" key F4 -AnyMod : "\EOS" key F5 -AnyMod : "\E[15~" key F6 -AnyMod : "\E[17~" key F7 -AnyMod : "\E[18~" key F8 -AnyMod : "\E[19~" key F9 -AnyMod : "\E[20~" key F10 -AnyMod : "\E[21~" key F11 -AnyMod : "\E[23~" key F12 -AnyMod : "\E[24~" key F1 +AnyMod : "\EO*P" key F2 +AnyMod : "\EO*Q" key F3 +AnyMod : "\EO*R" key F4 +AnyMod : "\EO*S" key F5 +AnyMod : "\E[15;*~" key F6 +AnyMod : "\E[17;*~" key F7 +AnyMod : "\E[18;*~" key F8 +AnyMod : "\E[19;*~" key F9 +AnyMod : "\E[20;*~" key F10 +AnyMod : "\E[21;*~" key F11 +AnyMod : "\E[23;*~" key F12 +AnyMod : "\E[24;*~" # Work around dead keys 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 ScrollLock : scrollLock # keypad characters are not offered differently by Qt. deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/encodes/000077500000000000000000000000001475472654300246055ustar00rootroot00000000000000deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/encodes/detectcode.cpp000066400000000000000000000746251475472654300274320ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2019 - 2023 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: GPL-3.0-or-later #include "detectcode.h" //#include "../common/config.h" #include #include #include #include #include #include #include #include #define DISABLE_TEXTCODEC QMap DetectCode::sm_LangsMap; // 最低的检测准确度判断,低于90%需要调整策略 static const float gs_dMinConfidence = 0.9f; // 手动添加 UTF BOM 信息 static QMap gs_byteOrderMark = {{"UTF-16LE", QByteArray::fromHex("FFFE")}, {"UTF-16BE", QByteArray::fromHex("FEFF")}, {"UTF-32LE", QByteArray::fromHex("FFFE0000")}, {"UTF-32BE", QByteArray::fromHex("0000FEFF")}}; // GB18030-UTF8 PUA区域映射表 static QHash gs_UTF8MapGB18030Data{ {"\uE81E", 0x37903582}, {"\uE826", 0x38903582}, {"\uE82B", 0x39903582}, {"\uE82C", 0x30913582}, {"\uE832", 0x31913582}, {"\uE843", 0x32913582}, {"\uE854", 0x33913582}, {"\uE864", 0x34913582}, {"\uE78D", 0x36823184}, {"\uE78F", 0x37823184}, {"\uE78E", 0x38823184}, {"\uE790", 0x39823184}, {"\uE791", 0x30833184}, {"\uE792", 0x31833184}, {"\uE793", 0x32833184}, {"\uE794", 0x33833184}, {"\uE795", 0x34833184}, {"\uE796", 0x35833184}, /*{"\uE816", 0x31903295}, {"\uE817", 0x33903295}, {"\uE818", 0x30973295}, {"\uE831", 0x37B93695}, {"\uE83B", 0x35BA3096}, {"\uE855", 0x30B63596}*/}; // GB18030 -> UTF8 编码转换时需要特殊处理,保留GB18030特殊编码的字符 static QHash gs_ReplaceFromGB18030_2005Error{ {QByteArray::fromHex("FE51"), QByteArray::fromHex("FFFFFF01")}, {QByteArray::fromHex("FE52"), QByteArray::fromHex("FFFFFF02")}, {QByteArray::fromHex("FE53"), QByteArray::fromHex("FFFFFF03")}, {QByteArray::fromHex("FE6C"), QByteArray::fromHex("FFFFFF04")}, {QByteArray::fromHex("FE76"), QByteArray::fromHex("FFFFFF05")}, {QByteArray::fromHex("FE91"), QByteArray::fromHex("FFFFFF06")}}; static QHash gs_ReplaceToUTF8_2005Error{{"\uE816", QByteArray::fromHex("FFFFFF01")}, {"\uE817", QByteArray::fromHex("FFFFFF02")}, {"\uE818", QByteArray::fromHex("FFFFFF03")}, {"\uE831", QByteArray::fromHex("FFFFFF04")}, {"\uE83B", QByteArray::fromHex("FFFFFF05")}, {"\uE855", QByteArray::fromHex("FFFFFF06")}}; static QHash gs_ReplaceGB18030ToUTF8_2005Error{{"\uE816", QByteArray::fromHex("FE51")}, {"\uE817", QByteArray::fromHex("FE52")}, {"\uE818", QByteArray::fromHex("FE53")}, {"\uE831", QByteArray::fromHex("FE6C")}, {"\uE83B", QByteArray::fromHex("FE76")}, {"\uE855", QByteArray::fromHex("FE91")}}; static QHash gs_ReplaceFromUtf8_2020Error{ {QByteArray::fromHex("95329031"), QByteArray::fromHex("FFFF11")}, {QByteArray::fromHex("95329033"), QByteArray::fromHex("FFFF12")}, {QByteArray::fromHex("95329730"), QByteArray::fromHex("FFFF13")}, {QByteArray::fromHex("9536B937"), QByteArray::fromHex("FFFF14")}, {QByteArray::fromHex("9630BA35"), QByteArray::fromHex("FFFF15")}, {QByteArray::fromHex("9635B630"), QByteArray::fromHex("FFFF16")}, }; static QHash gs_ReplaceToGB18030_2020Error{ {QByteArray::fromHex("F0A08287"), QByteArray::fromHex("FFFF11")}, {QByteArray::fromHex("F0A08289"), QByteArray::fromHex("FFFF12")}, {QByteArray::fromHex("F0A0838C"), QByteArray::fromHex("FFFF13")}, {QByteArray::fromHex("F0A19797"), QByteArray::fromHex("FFFF14")}, {QByteArray::fromHex("F0A2A68F"), QByteArray::fromHex("FFFF15")}, {QByteArray::fromHex("F0A487BE"), QByteArray::fromHex("FFFF16")}, }; static QHash gs_ReplaceFromUtf8ToGB18030_2020Error{ {QByteArray::fromHex("95329031"), "\u20087"}, {QByteArray::fromHex("95329033"), "\u20089"}, {QByteArray::fromHex("95329730"), "\u200CC"}, {QByteArray::fromHex("9536B937"), "\u215D7"}, {QByteArray::fromHex("9630BA35"), "\u2298F"}, {QByteArray::fromHex("9635B630"), "\u241FE"}, }; // 见QTextCodec::mibEnum() enum MibEncoding { UnknownMib = 0, UTF_8 = 106, GB18030 = 114, UTF_16BE = 1013, UTF_16LE = 1014, UTF_16 = 1015, UTF_32 = 1017, UTF_32BE = 1018, UTF_32LE = 1019, }; DetectCode::DetectCode() {} /** * @brief 根据文件头内容 \a content 取得文件 \a filepath 字符编码格式 * @param filepath 待获取字符编码文件 * @param content 文件头内容 * @return 文件字符编码格式 * * @note 对于大文本文件,文件头内容 \a content 可能在文件中间截断,\a content 尾部带有被截断的字符, * 极大的降低字符编码识别率。为此,在识别率过低时裁剪尾部数据,重新检测以提高文本识别率。 */ QByteArray DetectCode::GetFileEncodingFormat(QString filepath, QByteArray content) { QString charDetectedResult; QByteArray ucharDetectdRet; QByteArrayList icuDetectRetList; QByteArray detectRet; float chardetconfidence = 0.0f; /* chardet识别编码 */ QString str(content); // 匹配的是中文(仅在UTF-8编码下) bool bFlag = str.contains(QRegExp("[\\x4e00-\\x9fa5]+")); if (bFlag) { const QByteArray suffix = "为增加探测率保留的中文"; QByteArray newContent = content; //手动添加中文字符,避免字符长度太短而导致判断编码错误 newContent += suffix; DetectCode::ChartDet_DetectingTextCoding(newContent, charDetectedResult, chardetconfidence); // 大文本数据存在从文档中间截断的可能,导致unicode中文字符被截断,解析为乱码,处理部分情况 // 根据文本中断的情况,每次尝试解析编码后移除尾部字符,直到识别率达到90%以上 int tryCount = 5; while (chardetconfidence < gs_dMinConfidence && newContent.size() > suffix.size() && tryCount-- > 0) { // 移除可能的乱码尾部字符 newContent.remove(newContent.size() - suffix.size(), 1); DetectCode::ChartDet_DetectingTextCoding(newContent, charDetectedResult, chardetconfidence); } } else { DetectCode::ChartDet_DetectingTextCoding(content, charDetectedResult, chardetconfidence); // 部分非unicode编码同为中文,例如 GB18030, BIG5 等中文编码,同样判断识别率,识别率较低手动干预多次检测 int tryCount = 5; QByteArray newContent = content; while (chardetconfidence < gs_dMinConfidence && !newContent.isEmpty() && tryCount-- > 0) { newContent.chop(1); DetectCode::ChartDet_DetectingTextCoding(newContent, charDetectedResult, chardetconfidence); } } ucharDetectdRet = charDetectedResult.toLatin1(); // uchardet识别编码 若识别率过低, 考虑是否非单字节编码格式。 if (ucharDetectdRet.contains("unknown") || ucharDetectdRet.contains("ASCII") || ucharDetectdRet.contains("???") || ucharDetectdRet.isEmpty() || chardetconfidence < gs_dMinConfidence) { ucharDetectdRet = DetectCode::UchardetCode(filepath); } // icu识别编码 icuDetectTextEncoding(filepath, icuDetectRetList); detectRet = selectCoding(ucharDetectdRet, icuDetectRetList, chardetconfidence); if (detectRet.contains("ASCII") || detectRet.isEmpty()) { detectRet = "UTF-8"; } return detectRet.toUpper(); } QByteArray DetectCode::UchardetCode(QString filepath) { FILE *fp; QByteArray charset; size_t buffer_size = 0x10000; char *buff = new char[buffer_size]; memset(buff, 0, buffer_size); /* 通过样本字符分析文本编码 */ uchardet_t handle = uchardet_new(); /* 打开被检测文本文件,并读取一定数量的样本字符 */ fp = fopen(filepath.toLocal8Bit().data(), "rb"); if (fp) { while (!feof(fp)) { size_t len = fread(buff, 1, buffer_size, fp); int retval = uchardet_handle_data(handle, buff, len); if (retval != 0) { continue; } break; } fclose(fp); uchardet_data_end(handle); charset = uchardet_get_charset(handle); } uchardet_delete(handle); delete[] buff; buff = nullptr; if (charset == "MAC-CENTRALEUROPE") charset = "MACCENTRALEUROPE"; if (charset == "MAC-CYRILLIC") charset = "MACCYRILLIC"; if (charset.contains("WINDOWS-")) charset = charset.replace("WINDOWS-", "CP"); return charset; } /** * @author guoshao * @brief icuDetectTextEncoding() icu库编码识别 * @param filePath:文件路径,listDetectRet:编码识别结果存在的变量 **/ void DetectCode::icuDetectTextEncoding(const QString &filePath, QByteArrayList &listDetectRet) { FILE *file; file = fopen(filePath.toLocal8Bit().data(), "rb"); if (file == nullptr) { qWarning() << "fopen file failed."; return; } size_t iBuffSize = 4096; char *detected = nullptr; char *buffer = new char[iBuffSize]; memset(buffer, 0, iBuffSize); int readed = 0; while (!feof(file)) { size_t len = fread(buffer, 1, iBuffSize, file); readed += len; if (readed > 1 * 1024 * 1024) { break; } if (detectTextEncoding(buffer, len, &detected, listDetectRet)) { break; } } delete[] buffer; buffer = nullptr; fclose(file); } /** * @author guoshao * @brief detectTextEncoding() icu库编码识别内层函数 * @param data:要识别的内容,len:要识别的内容的长度,detected:编码识别结果存在的变量, * listDetectRet:编码识别结果存在的list * @return true:识别成功,false:识别失败 **/ bool DetectCode::detectTextEncoding(const char *data, size_t len, char **detected, QByteArrayList &listDetectRet) { Q_UNUSED(detected); UCharsetDetector *csd; const UCharsetMatch **csm; int32_t matchCount = 0; UErrorCode status = U_ZERO_ERROR; csd = ucsdet_open(&status); if (status != U_ZERO_ERROR) { return false; } ucsdet_setText(csd, data, len, &status); if (status != U_ZERO_ERROR) { return false; } csm = ucsdet_detectAll(csd, &matchCount, &status); if (status != U_ZERO_ERROR) { return false; } int readMax = 0; // 提高GB18030识别率时,拓展允许读取的编码列表 readMax = qMin(6, matchCount); for (int i = 0; i < readMax; i++) { auto str = ucsdet_getName(csm[i], &status); if (status != U_ZERO_ERROR) { return false; } listDetectRet << QByteArray(str); } ucsdet_close(csd); return true; } /** * @author guoshao * @brief selectCoding() 筛选识别出来的编码 * @param ucharDetectdRet:chardet/uchardet识别的编码结果,icuDetectRetList:编码识别结果存在的list * @return 筛选编码的结果 **/ QByteArray DetectCode::selectCoding(QByteArray ucharDetectdRet, QByteArrayList icuDetectRetList, float confidence) { // 列表不允许为空 if (icuDetectRetList.isEmpty()) { return QByteArray(); } if (!ucharDetectdRet.isEmpty()) { // 获取是否允许提高GB18030编码的策略 // 中文环境优先匹配GB18030编码 if (QLocale::Chinese == QLocale::system().language()) { if (confidence < gs_dMinConfidence && icuDetectRetList.contains("GB18030")) { return QByteArray("GB18030"); } if (QByteArray("ASCII") == ucharDetectdRet) { return QByteArray("GB18030"); } } if (ucharDetectdRet.contains(icuDetectRetList[0])) { return ucharDetectdRet; } else { if (icuDetectRetList.contains("GB18030")) { return QByteArray("GB18030"); } else { // 筛选部分带后缀的编码格式,例如 UTF-16 BE 和 UTF-16 if (icuDetectRetList[0].contains(ucharDetectdRet)) { return icuDetectRetList[0]; } return ucharDetectdRet; } } } if (ucharDetectdRet.isEmpty()) { if (icuDetectRetList.contains("GB18030")) { return QByteArray("GB18030"); } else { return icuDetectRetList[0]; } } return QByteArray(); } #if 0 /* 因为开源协议存在法律冲突,停止使用libenca0编码识别库 */ QByteArray DetectCode::EncaDetectCode(QString filepath) { /* * 编码区域对应的简称 *"zh"中文 "be"俄罗斯 "bg"保加利亚 "cs"捷克文 "et"爱沙尼亚语 "hr"克罗地亚人[语]; "hu"匈牙利语 "lt"立陶宛 * "lv"拉脱维亚语 "pl"波兰语 "ru"俄语 "sk"斯洛伐克人(语) "sl"斯洛文尼亚人(语) "uk"乌克兰人(语) */ sm_LangsMap.clear(); const char *langArray[] = {"zh", "be", "bg", "cs", "et", "hr", "hu", "lt", "lv", "pl", "ru", "sk", "sl", "uk"}; #if 0 /* EncaAnalyserState */ size_t size; const char **lang = enca_get_languages(&size); QStringList langs; for (size_t i = 0; i < size; i++) { langs << lang[i]; } #endif QByteArray charset; for (size_t i = 0; i < sizeof(langArray) / sizeof(const char *); i++) { EncaAnalyser analyser = nullptr; analyser = enca_analyser_alloc(langArray[i]); enca_set_threshold(analyser, 1.38); enca_set_multibyte(analyser, 1); enca_set_ambiguity(analyser, 1); enca_set_garbage_test(analyser, 1); size_t buffer_size = 0x10000; unsigned char *buff = new unsigned char[buffer_size]; memset(buff, 0, buffer_size); /* 打开被检测文本文件,并读取一定数量的样本字符 */ FILE *fp; /* the processed file */ fp = fopen(filepath.toLocal8Bit().data(), "rb"); if (fp) { while (!feof(fp)) { size_t len = fread(buff, 1, buffer_size, fp); EncaEncoding encoding = enca_analyse(analyser, buff, len); charset = enca_charset_name(encoding.charset, EncaNameStyle::ENCA_NAME_STYLE_MIME); qDebug() << QStringLiteral("ENCA文本的编码方式是:") << charset; //识别文本编码识别 if (encoding.charset == -1) continue; break; } enca_analyser_free(analyser); analyser = nullptr; delete [] buff; buff = nullptr; fclose(fp); } else { qDebug() << QStringLiteral("ENCA打开失败:") << filepath; } if (charset == "US-ASCII") charset = "ASCII"; if (charset == "GB2312" || charset == "GBK") charset = "GB18030"; if (charset == "ISO-10646-UCS-2") charset = "UTF-16BE"; sm_LangsMap[langArray[i]] = charset; if (!charset.isEmpty()) { break; } } return charset; } #endif /** * @brief ChartDet_DetectingTextCoding libchardet1编码识别库识别编码 */ int DetectCode::ChartDet_DetectingTextCoding(const char *str, QString &encoding, float &confidence) { DetectObj *obj = detect_obj_init(); if (obj == nullptr) { qWarning() << "Code identification libarary memory allocation failed\n"; return CHARDET_MEM_ALLOCATED_FAIL; } /* 另一种编码识别逻辑,暂且保留*/ /*size_t buffer_size = 1024; char *buff = new char[buffer_size]; memset(buff, 0, buffer_size); FILE *fp; fp = fopen(filepath.toLocal8Bit().data(), "rb"); if (fp) { while (!feof(fp)) { size_t len = fread(buff, 1, buffer_size, fp); detect(buff, &obj); QString encoding = obj->encoding; if (encoding == "") { continue; } else if (!encoding.isEmpty()) { break; } fclose(fp); } } delete [] buff; buff = nullptr;*/ #ifndef CHARDET_BINARY_SAFE // before 1.0.5. This API is deprecated on 1.0.5 switch (detect(str, &obj)) #else // from 1.0.5 switch (detect_r(str, strlen(str), &obj)) #endif { case CHARDET_OUT_OF_MEMORY: qInfo() << "On handle processing, occured out of memory\n"; detect_obj_free(&obj); return CHARDET_OUT_OF_MEMORY; case CHARDET_NULL_OBJECT: qInfo() << "2st argument of chardet() is must memory allocation with detect_obj_init API\n"; return CHARDET_NULL_OBJECT; } #ifndef CHARDET_BOM_CHECK // qInfo() << "encoding:" << obj->encoding << "; confidence: " << obj->confidence; #else // from 1.0.6 support return whether exists BOM qInfo() << "encoding:" << obj->encoding << "; confidence: " << obj->confidence << "; bom: " << obj->bom; #endif encoding = obj->encoding; confidence = obj->confidence; detect_obj_free(&obj); return CHARDET_SUCCESS; } /** * @return 根据 UTF-8 字符编码,返回传入的字符串 \a buf 头部字符可能占用的字节数量 * @note 不同编码UTF-8字节划分示例,除首个字节为0外 * 如果一个字节的第一位是0,则这个字节单独就是一个字符;如果第一位是1,则连续有多少个1,就表示当前字符占用多少个字节。 * 0000 0000-0000 007F | 0xxxxxxx * 0000 0080-0000 07FF | 110xxxxx 10xxxxxx * 0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx * 0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx * * @link https://zh.wikipedia.org/wiki/UTF-8 */ int utf8MultiByteCount(char *buf, size_t size) { // UTF 字符类型,单字符,中间字符,双字节,三字节,四字节 enum UtfCharType { Single, Mid, DoubleBytes, ThreeBytes, FourBytes, }; // 取得 UTF-8 字节序数值 auto LeftBitFunc = [](char data) -> int { // 返回前导1的个数 int res = 0; while (data & 0x80) { res++; data <<= 1; } return res; }; int count = 0; while (size > 0 && count < FourBytes) { int leftBits = LeftBitFunc(*buf); switch (leftBits) { case Mid: count++; break; case DoubleBytes: case ThreeBytes: case FourBytes: return leftBits; default: // 超过4字节或单字节,均返回1 return 1; } buf++; size--; } return count; } /** @brief 检测 GB18030 转换 UTF-8 时PUA区域异常处理 @note GB18030 PUA区域编码转换各版本异同 iconv当前使用2022标志,遇到PUA区域将报错(2022不再支持),此处兼容2005设计, GB18030 - UTF-8 互转时,将PUA区域字符按2005标准转换 | GB18030 原始数据(HEX) | GB18030-2005 to UTF8 | GB18030-2022 toUtf8 | |------------------------|-----------------------|-----------------------| | 0x37903582 | \uE81E | \u9FB4 | | 0x38903582 | \uE826 | \u9FB5 | | 0x39903582 | \uE82B | \u9FB6 | | 0x30913582 | \uE82C | \u9FB7 | | 0x31913582 | \uE832 | \u9FB8 | | 0x32913582 | \uE843 | \u9FB9 | | 0x33913582 | \uE854 | \u9FBA | | 0x34913582 | \uE864 | \u9FBB | | 0x36823184 | \uE78D | \uFE10 | | 0x37823184 | \uE78F | \uFE11 | | 0x38823184 | \uE78E | \uFE12 | | 0x39823184 | \uE790 | \uFE13 | | 0x30833184 | \uE791 | \uFE14 | | 0x31833184 | \uE792 | \uFE15 | | 0x32833184 | \uE793 | \uFE16 | | 0x33833184 | \uE794 | \uFE17 | | 0x34833184 | \uE795 | \uFE18 | | 0x35833184 | \uE796 | \uFE19 | 以下为特殊字符,2005和2022转换后编码,映射Unicode编码,此次不做特殊处理 | GB18030 原始数据(HEX) | GB18030 to UTF8 | Unicode 4.1映射 | |------------------------|----------------------|------------------------| | 0x31903295 | U+E816 | \u20087 | | 0x33903295 | U+E817 | \u20089 | | 0x30973295 | U+E818 | \u200CC | | 0x37B93695 | U+E831 | \u215D7 | | 0x35BA3096 | U+E83B | \u2298F | | 0x30B63596 | U+E855 | \u241FE | */ bool checkGB18030ToUtf8Error(char *buf, size_t size, size_t &replaceLen, QByteArray &appendChar) { // 对于GB18030-2005编码规范PUA区域的字符,iconv报错,替换为对应的字符序。 static const int sc_minGB18030PUACharLen = 4; if (size < sc_minGB18030PUACharLen) { replaceLen = 1; appendChar = "?"; return false; } quint32 puaChar = *reinterpret_cast(buf); appendChar = gs_UTF8MapGB18030Data.key(puaChar); if (appendChar.isEmpty()) { // FFFFFF0X -> \uE816...\uE855 appendChar = gs_ReplaceToUTF8_2005Error.key(QByteArray(buf, sc_minGB18030PUACharLen)); } if (appendChar.isEmpty()) { replaceLen = 1; appendChar = "?"; return false; } else { replaceLen = sc_minGB18030PUACharLen; return true; } } /** @brief 检测 UTF-8 转换 GB18030 时PUA区域异常处理 */ bool checkUTF8ToGB18030Error(char *buf, size_t size, size_t &replaceLen, QByteArray &appendChar) { // 待转换的PUA字符均为3 static const int sc_minUTFPUACharLen = 3; if (size < sc_minUTFPUACharLen) { replaceLen = 1; appendChar = "?"; return false; } QByteArray puaChar(buf, sc_minUTFPUACharLen); quint32 gb18030char = gs_UTF8MapGB18030Data.value(puaChar, 0); if (!gb18030char) { appendChar = gs_ReplaceGB18030ToUTF8_2005Error.value(puaChar); if (appendChar.isEmpty()) { appendChar = gs_ReplaceFromUtf8_2020Error.key(puaChar); } if (!appendChar.isEmpty()) { replaceLen = sc_minUTFPUACharLen; return true; } } if (!gb18030char) { replaceLen = 1; appendChar = "?"; return false; } else { replaceLen = sc_minUTFPUACharLen; appendChar = QByteArray(reinterpret_cast(&gb18030char), sizeof(gb18030char)); return true; } } /** * @brief 将输入的字符序列 \a inputStr 从编码 \a fromCode 转换为编码 \a toCode, 并返回转换后的字符序列。 * @return 字符编码转换是否成功 */ bool DetectCode::ChangeFileEncodingFormat(QByteArray &inputStr, QByteArray &outStr, const QString &fromCode, const QString &toCode) { if (fromCode == toCode) { outStr = inputStr; return true; } if (inputStr.isEmpty()) { outStr.clear(); return true; } #ifndef DISABLE_TEXTCODEC // 使用QTextCodec对部分编码进行处理 static QStringList codecList{"GB18030"}; if (codecList.contains(fromCode) || codecList.contains(toCode)) { return convertEncodingTextCodec(inputStr, outStr, fromCode, toCode); } #endif iconv_t handle = iconv_open(toCode.toLocal8Bit().data(), fromCode.toLocal8Bit().data()); if (handle != reinterpret_cast(-1)) { MibEncoding fromMib = UnknownMib; MibEncoding toMib = UnknownMib; QTextCodec *fromCodec = QTextCodec::codecForName(fromCode.toUtf8()); if (fromCodec) { fromMib = static_cast(fromCodec->mibEnum()); } QTextCodec *toCodec = QTextCodec::codecForName(toCode.toUtf8()); if (toCodec) { toMib = static_cast(toCodec->mibEnum()); } if (GB18030 == fromMib && UTF_8 == toMib) { // \uE816...\uE855 -> FFFFFF0X for (auto itr = gs_ReplaceFromGB18030_2005Error.begin(); itr != gs_ReplaceFromGB18030_2005Error.end(); ++itr) { inputStr.replace(itr.key(), itr.value()); } } else if (UTF_8 == fromMib && GB18030 == toMib) { for (auto itr = gs_ReplaceToGB18030_2020Error.begin(); itr != gs_ReplaceToGB18030_2020Error.end(); ++itr) { inputStr.replace(itr.key(), itr.value()); } } char *inbuf = inputStr.data(); size_t inbytesleft = static_cast(inputStr.size()); size_t outbytesleft = 4 * inbytesleft; char *outbuf = new char[outbytesleft]; char *bufferHeader = outbuf; size_t maxBufferSize = outbytesleft; memset(outbuf, 0, outbytesleft); int errorNum = 0; size_t ret = 0; do { ret = iconv(handle, &inbuf, &inbytesleft, &outbuf, &outbytesleft); if (static_cast(-1) == ret) { // 记录错误信息 errorNum = errno; // 遇到错误的输入,错误码 EILSEQ (84),跳过当前位置并添加'?' if (EILSEQ == errorNum) { // 缓冲区不足跳出 if (outbytesleft == 0) { break; } size_t replaceLen = 1; // 跳过错误字符,设置错误字符为'?' QByteArray appendChar = "?"; switch (fromMib) { case UTF_8: { // 特殊处理,若为UTF-8 到 GB18030的转换,优先排查异常数据 if (GB18030 == toMib) { if (checkUTF8ToGB18030Error(inbuf, inbytesleft, replaceLen, appendChar)) { break; } } // 源编码为 UTF-8 时,可计算需跳过的字符数 replaceLen = static_cast(utf8MultiByteCount(inbuf, inbytesleft)); } break; case GB18030: // 特殊处理,若为GB18030 到 UTF-8 的转换,优先排查异常数据 if (UTF_8 == toMib) { if (checkGB18030ToUtf8Error(inbuf, inbytesleft, replaceLen, appendChar)) { break; } } break; default: break; } qWarning() << "------------replaced" << appendChar.toHex(); // 替换错误字符为对应字符 size_t appendSize = static_cast(appendChar.size()); if (outbytesleft < appendSize) { break; } outbytesleft -= appendSize; ::memcpy(outbuf, appendChar.data(), appendSize); outbuf += appendSize; if (inbytesleft <= replaceLen) { // 移动至末尾 inbuf += inbytesleft; inbytesleft = 0; break; } inbuf += replaceLen; inbytesleft -= replaceLen; } else { break; } } } while (static_cast(-1) == ret); if (errorNum) { qWarning() << Q_FUNC_INFO << qPrintable("iconv() convert text encoding error, errocode:") << errorNum; } iconv_close(handle); // 手动添加 UTF BOM 信息 outStr.append(gs_byteOrderMark.value(toCode)); // 计算 iconv() 实际转换的字节数 size_t realConvertSize = maxBufferSize - outbytesleft; outStr += QByteArray(bufferHeader, static_cast(realConvertSize)); delete[] bufferHeader; bufferHeader = nullptr; return true; } else { qWarning() << Q_FUNC_INFO << qPrintable("Text encoding convert error, iconv_open() failed."); // 尝试使用QTextCodec加载 return convertEncodingTextCodec(inputStr, outStr, fromCode, toCode); } } /** * @brief 使用QTextCodec将输入的字符序列 \a inputStr 从编码 \a fromCode 转换为编码 \a toCode, 并返回转换后的字符序列。 * @return 字符编码转换是否成功 */ bool DetectCode::convertEncodingTextCodec(QByteArray &inputStr, QByteArray &outStr, const QString &fromCode, const QString &toCode) { QString convertData; if (fromCode != "UTF-8") { QTextCodec *fromCodec = QTextCodec::codecForName(fromCode.toUtf8()); if (!fromCodec) { return false; } convertData = fromCodec->toUnicode(inputStr); } else { convertData = QString::fromUtf8(inputStr); } if (toCode != "UTF-8") { QTextCodec *toCodec = QTextCodec::codecForName(toCode.toUtf8()); if (!toCodec) { return false; } outStr = toCodec->fromUnicode(convertData); } else { outStr = convertData.toUtf8(); } // 手动添加 UTF BOM 信息 outStr.append(gs_byteOrderMark.value(toCode)); return true; } deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/encodes/detectcode.h000066400000000000000000000044071475472654300270660ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2019 - 2023 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: GPL-3.0-or-later #ifndef DETECTCODE_H #define DETECTCODE_H #include #include #include #include #include #include #include #include #include /* * * 文本编码识别引用第三库识别 chardet1 uchardet * chardet识别不了使用uchardet * 编码转换库使用iconv * * author:梁卫东 2020年10月15日16:56:11 * */ class QByteArray; class QString; class DetectCode { public: DetectCode(); // enca 识别文本编码 #if 0 /* 因为开源协议存在法律冲突,停止使用libenca0编码识别库 */ static QByteArray EncaDetectCode (QString filepath); #endif // libchardet1编码识别库识别编码 static int ChartDet_DetectingTextCoding(const char *str, QString &encoding, float &confidence); // uchardet 识别文编编码 static QByteArray UchardetCode(QString filepath); // icu库编码识别 static void icuDetectTextEncoding(const QString &filePath, QByteArrayList &listDetectRet); // icu库编码识别内层函数 static bool detectTextEncoding(const char *data, size_t len, char **detected, QByteArrayList &listDetectRet); // 筛选识别出来的编码 static QByteArray selectCoding(QByteArray ucharDetectdRet, QByteArrayList icuDetectRetList, float confidence); // 获取文件编码方式 static QByteArray GetFileEncodingFormat(QString filepath, QByteArray content = QByteArray("")); // 转换文本编码格式 static bool ChangeFileEncodingFormat(QByteArray &inputStr, QByteArray &outStr, const QString &fromCode, const QString &toCode = QString("UTF-8")); static bool convertEncodingTextCodec(QByteArray &inputStr, QByteArray &outStr, const QString &fromCode, const QString &toCode = QString("UTF-8")); private: static QMap sm_LangsMap; }; #endif // DETECTCODE_H deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/encodes/encodes.ini000066400000000000000000000014311475472654300267250ustar00rootroot00000000000000[Unicode] encodes=UTF-8,UTF-16BE,UTF-16LE,UTF-32BE,UTF-32LE [WesternEuropean] encodes=ISO-8859-1,ISO-8859-15,CP1252 [CentralEuropean] encodes=ISO-8859-2,ISO-8859-3,CP1125,CP1250,MACCENTRALEUROPE,IBM852 [Baltic] encodes=ISO-8859-4,ISO-8859-10,ISO-8859-13,CP1257,IBM775 [Cyrillic] encodes=ISO-8859-5,CP1251,KOI8-R,KOI8-U,MACCYRILLIC,IBM855,IBM866 [Arabic] encodes=ISO-8859-6,CP1256 [Greek] encodes=ISO-8859-7,CP1253 [Hebrew] encodes=ISO-8859-8,CP1255 [Turkish] encodes=ISO-8859-9,CP1254 [Thai] encodes=ISO-8859-11,TIS-620 [Celtic] encodes=ISO-8859-14 [SouthEasternEuropean] encodes=ISO-8859-16 [ChineseSimplified] encodes=GB18030,ISO-2022-CN [ChineseTraditional] encodes=BIG5,EUC-TW [Japanese] encodes=EUC-JP,SHIFT_JIS,ISO-2022-JP [Korean] encodes=EUC-KR,ISO-2022-KR [Vietnamese] encodes=CP1258 deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/encodes/encodes1.ini000066400000000000000000000034651475472654300270170ustar00rootroot00000000000000[Unicode] encodes=UTF-8,UTF-16BE,UTF-16LE,UTF-32BE,UTF-32LE [Arabic] encodes=ISO-8859-6,CP1256 [Belarussian] encodes=CP1251,IBM855,IBM866,ISO-8859-5,KOI8-U [Bulgarian] encodes=CP1251,ISO-8859-5,IBM855 [Chinese] encodes=GB18030,BIG5,HZ,EUC-TW,ISO-2022-CN [Czech] encodes=ISO-8859-2,CP1250,IBM852,MACCENTRALEUROPE [Croatian] encodes=ISO-8859-2,IBM852,ISO-8859-13,ISO-8859-16,MACCENTRALEUROPE,CP1250 [Danish] encodes=ISO-8859-1,ISO-8859-5,ISO-8859-15,CP1252 [Estonian] encodes=ISO-8859-4,ISO-8859-13,CP1252,CP1257,IBM775 [Finnish] encodes=ISO-8859-1,ISO-8859-4,ISO-8859-9,ISO-8859-13,ISO-8859-15,CP1252 [French] encodes=ISO-8859-1,ISO-8859-15,CP1252 [German] encodes=ISO-8859-1,CP1252 [Greek] encodes=ISO-8859-7,CP1253 [Hebrew] encodes=ISO-8859-8,CP1255 [Hungarian] encodes=ISO-8859-2,CP1250,IBM852 [Japanese] encodes=ISO-2022-JP,SHIFT_JIS,EUC-JP [Korean] encodes=ISO-2022-KR,EUC-KR,UHC [Irish Gaelic] encodes=ISO-8859-1,ISO-8859-9,ISO-8859-15,CP1252 [Italian] encodes=ISO-8859-1,ISO-8859-3,ISO-8859-9,ISO-8859-15,CP1252 [Lithuanian] encodes=ISO-8859-4,ISO-8859-10,ISO-8859-13,CP1257,IBM775 [Latvian] encodes=ISO-8859-4,ISO-8859-10,ISO-8859-13,CP1257,IBM775 [Polish] encodes=ISO-8859-2,ISO-8859-13,ISO-8859-16,CP1250,IBM852,MACCENTRALEUROPE [Portuguese] encodes=ISO-8859-1,ISO-8859-9,ISO-8859-15,CP1252 [Russian] encodes=CP1251,ISO-8859-5,MACCYRILLIC,IBM855,IBM866,KOI8-R [Romanian] encodes=ISO-8859-2,ISO-8859-16,CP1250,IBM852 [Slovak] encodes=ISO-8859-2,IBM852,MACCENTRALEUROPE,CP1250 [Slovenian] encodes=ISO-8859-2,ISO-8859-16,CP1250,IBM852,MACCENTRALEUROPE [Spanish] encodes=ISO-8859-1,ISO-8859-15,CP1252 [Swedish] encodes=ISO-8859-1,ISO-8859-4,ISO-8859-9,ISO-8859-15,CP1252 [Thai] encodes=TIS-620,ISO-8859-11 [Turkish] encodes=ISO-8859-3,ISO-8859-9 [Ukrainian] encodes=CP1251,CP1125,IBM855,ISO-8859-5,KOI8-U [Vietnamese] encodes=VISCII,CP1258 deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/history/000077500000000000000000000000001475472654300246665ustar00rootroot00000000000000deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/history/HistoryFile.cpp000066400000000000000000000132171475472654300276370ustar00rootroot00000000000000/* This file is part of Konsole, an X terminal. 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 (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. */ // Own #include "HistoryFile.h" #include #include // System #include #include // Qt #include #include #include using namespace Konsole; Q_GLOBAL_STATIC(QString, historyFileLocation) // History File /////////////////////////////////////////// HistoryFile::HistoryFile() : _length(0), _fileMap(nullptr), _readWriteBalance(0) { // Determine the temp directory once // This class is called 3 times for each "unlimited" scrollback. // This has the down-side that users must restart to // load changes. if (!historyFileLocation.exists()) { QString fileLocation; // Validate file location const QFileInfo fi(fileLocation); if (fileLocation.isEmpty() || !fi.exists() || !fi.isDir() || !fi.isWritable()) { qDebug()<<"Invalid scrollback folder "<applicationPid(), _tmpFile.handle()); #endif // On some systems QTemporaryFile creates unnamed file. // Do not interfere in such cases. if (_tmpFile.exists()) { // Remove file entry from filesystem. Since the file // is opened, it will still be available for reading // and writing. This guarantees the file won't remain // in filesystem after process termination, even when // there was a crash. unlink(QFile::encodeName(_tmpFile.fileName()).constData()); } } } HistoryFile::~HistoryFile() { if (_fileMap != nullptr) { unmap(); } } //TODO: Mapping the entire file in will cause problems if the history file becomes exceedingly large, //(ie. larger than available memory). HistoryFile::map() should only map in sections of the file at a time, //to avoid this. void HistoryFile::map() { Q_ASSERT(_fileMap == nullptr); if (_tmpFile.flush()) { Q_ASSERT(_tmpFile.size() >= _length); _fileMap = _tmpFile.map(0, _length); } //if mmap'ing fails, fall back to the read-lseek combination if (_fileMap == nullptr) { _readWriteBalance = 0; //qDebug() << "mmap'ing history failed. errno = " << errno; } } void HistoryFile::unmap() { Q_ASSERT(_fileMap != nullptr); if (_tmpFile.unmap(_fileMap)) { _fileMap = nullptr; } Q_ASSERT(_fileMap == nullptr); } void HistoryFile::add(const char *buffer, qint64 count) { if (_fileMap != nullptr) { unmap(); } if (_readWriteBalance < INT_MAX) { _readWriteBalance++; } qint64 rc = 0; if (!_tmpFile.seek(_length)) { perror("HistoryFile::add.seek"); return; } rc = _tmpFile.write(buffer, count); if (rc < 0) { perror("HistoryFile::add.write"); return; } _length += rc; } void HistoryFile::get(char *buffer, qint64 size, qint64 loc) { if (loc < 0 || size < 0 || loc + size > _length) { fprintf(stderr, "getHist(...,%lld,%lld): invalid args.\n", size, loc); return; } //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. if (_readWriteBalance > INT_MIN) { _readWriteBalance--; } if ((_fileMap == nullptr) && _readWriteBalance < MAP_THRESHOLD) { map(); } if (_fileMap != nullptr) { memcpy(buffer, _fileMap + loc, size); } else { qint64 rc = 0; if (!_tmpFile.seek(loc)) { perror("HistoryFile::get.seek"); return; } rc = _tmpFile.read(buffer, size); if (rc < 0) { perror("HistoryFile::get.read"); return; } } } void HistoryFile::removeLast(qint64 loc) { if (loc < 0 || loc > _length) { fprintf(stderr, "removeLast(%lld): invalid args.\n", loc); return; } _length = loc; } qint64 HistoryFile::len() const { return _length; } deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/history/HistoryFile.h000066400000000000000000000037211475472654300273030ustar00rootroot00000000000000/* This file is part of Konsole, an X terminal. 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 (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. */ #ifndef HISTORYFILE_H #define HISTORYFILE_H // Qt #include namespace Konsole { /* An extendable tmpfile(1) based buffer. */ class HistoryFile { public: HistoryFile(); virtual ~HistoryFile(); virtual void add(const char *buffer, qint64 count); virtual void get(char *buffer, qint64 size, qint64 loc); virtual void removeLast(qint64 loc); virtual qint64 len() const; //mmaps the file in read-only mode void map(); //un-mmaps the file void unmap(); private: qint64 _length; QTemporaryFile _tmpFile; //pointer to start of mmap'ed file data, or 0 if the file is not mmap'ed uchar *_fileMap; //incremented whenever '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 //and automatically mmap the file for better performance (saves the overhead of many lseek-read calls). int _readWriteBalance; //when _readWriteBalance goes below this threshold, the file will be mmap'ed automatically static const int MAP_THRESHOLD = -1000; }; } #endif deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/history/HistoryScroll.cpp000066400000000000000000000021441475472654300302130ustar00rootroot00000000000000/* This file is part of Konsole, an X terminal. 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 (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. */ // Own #include "HistoryScroll.h" #include "HistoryType.h" using namespace Konsole; HistoryScroll::HistoryScroll(HistoryType *t) : _historyType(t) { } HistoryScroll::~HistoryScroll() { delete _historyType; } bool HistoryScroll::hasScroll() { return true; } deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/history/HistoryScroll.h000066400000000000000000000050431475472654300276610ustar00rootroot00000000000000/* This file is part of Konsole, an X terminal. 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 (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. */ #ifndef HISTORYSCROLL_H #define HISTORYSCROLL_H // Konsole #include "../Character.h" // Qt #include //#include "konsole_export.h" #define KONSOLEPRIVATE_EXPORT namespace Konsole { ////////////////////////////////////////////////////////////////////// // Abstract base class for file and buffer versions ////////////////////////////////////////////////////////////////////// class HistoryType; class HistoryScroll { public: explicit HistoryScroll(HistoryType *); virtual ~HistoryScroll(); virtual bool hasScroll(); // access to history virtual int getLines() = 0; virtual int getMaxLines() = 0; virtual int getLineLen(int lineno) = 0; virtual void getCells(int lineno, int colno, int count, Character res[]) = 0; virtual bool isWrappedLine(int lineNumber) = 0; virtual LineProperty getLineProperty(int lineno) = 0; // adding lines. virtual void addCells(const Character a[], int count) = 0; // convenience method - this is virtual so that subclasses can take advantage // of QVector's implicit copying virtual void addCellsVector(const QVector &cells) { addCells(cells.data(), cells.size()); } virtual void addLine(LineProperty lineProperty = 0) = 0; // modify history virtual void removeCells() = 0; virtual int reflowLines(int columns) = 0; // // FIXME: Passing around constant references to HistoryType instances // is very unsafe, because those references will no longer // be valid if the history scroll is deleted. // const HistoryType &getType() const { return *_historyType; } protected: HistoryType *_historyType; const int MAX_REFLOW_LINES = 20000; }; } #endif deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/history/HistoryScrollFile.cpp000066400000000000000000000134051475472654300310150ustar00rootroot00000000000000/* This file is part of Konsole, an X terminal. 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 (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. */ #include "HistoryScrollFile.h" #include "HistoryTypeFile.h" /* The history scroll makes a Row(Row(Cell)) from two history buffers. The index buffer contains start of line positions which refer to the cells buffer. Note that index[0] addresses the second line (line #1), while the first line (line #0) starts at 0 in cells. */ using namespace Konsole; HistoryScrollFile::HistoryScrollFile() : HistoryScroll(new HistoryTypeFile()) { } HistoryScrollFile::~HistoryScrollFile() { } int HistoryScrollFile::getLines() { return _index.len() / sizeof(qint64); } int HistoryScrollFile::getMaxLines() { return getLines(); } int HistoryScrollFile::getLineLen(int lineno) { return (startOfLine(lineno + 1) - startOfLine(lineno)) / sizeof(Character); } bool HistoryScrollFile::isWrappedLine(int lineno) { if (lineno >= 0 && lineno <= getLines()) { unsigned char flag = 0; _lineflags.get(reinterpret_cast(&flag), sizeof(unsigned char), (lineno)*sizeof(unsigned char)); return flag != 0u; } return false; } LineProperty HistoryScrollFile::getLineProperty(int lineno) { if (lineno >= 0 && lineno <= getLines()) { LineProperty flag = 0; _lineflags.get(reinterpret_cast(&flag), sizeof(unsigned char), (lineno)*sizeof(unsigned char)); return flag; } return 0; } qint64 HistoryScrollFile::startOfLine(int lineno) { if (lineno <= 0) { return 0; } if (lineno <= getLines()) { qint64 res = 0; _index.get(reinterpret_cast(&res), sizeof(qint64), (lineno - 1)*sizeof(qint64)); return res; } return _cells.len(); } void HistoryScrollFile::getCells(int lineno, int colno, int count, Character res[]) { _cells.get(reinterpret_cast(res), count * sizeof(Character), startOfLine(lineno) + colno * sizeof(Character)); } void HistoryScrollFile::addCells(const Character text[], int count) { _cells.add(reinterpret_cast(text), count * sizeof(Character)); } void HistoryScrollFile::addLine(LineProperty lineProperty) { qint64 locn = _cells.len(); _index.add(reinterpret_cast(&locn), sizeof(qint64)); _lineflags.add(reinterpret_cast(&lineProperty), sizeof(char)); } void HistoryScrollFile::removeCells() { qint64 res = (getLines() - 2) * sizeof(qint64); if (getLines() < 2) { _cells.removeLast(0); } else { _index.get(reinterpret_cast(&res), sizeof(qint64), res); _cells.removeLast(res); } res = qMax(0, getLines() - 1); _index.removeLast(res * sizeof(qint64)); _lineflags.removeLast(res * sizeof(unsigned char)); } int HistoryScrollFile::reflowLines(int columns) { HistoryFile *reflowFile = new HistoryFile; reflowData newLine; auto reflowLineLen = [] (qint64 start, qint64 end) { return (int)((end - start) / sizeof(Character)); }; auto setNewLine = [] (reflowData &change, qint64 index, bool lineflag) { change.index = index; change.lineFlag = lineflag; }; // First all changes are saved on an auxiliary file, no real index is changed int currentPos = 0; if (getLines() > MAX_REFLOW_LINES) { currentPos = getLines() - MAX_REFLOW_LINES; } while (currentPos < getLines()) { qint64 startLine = startOfLine(currentPos); qint64 endLine = startOfLine(currentPos + 1); // Join the lines if they are wrapped while (isWrappedLine(currentPos)) { currentPos++; endLine = startOfLine(currentPos + 1); } // Now reflow the lines while (reflowLineLen(startLine, endLine) > columns) { startLine += (qint64)columns * sizeof(Character); setNewLine(newLine, startLine, true); reflowFile->add(reinterpret_cast(&newLine), sizeof(reflowData)); } setNewLine(newLine, endLine, false); reflowFile->add(reinterpret_cast(&newLine), sizeof(reflowData)); currentPos++; } // Erase data from index and flag data if (getLines() > MAX_REFLOW_LINES) { currentPos = getLines() - MAX_REFLOW_LINES; _index.removeLast(currentPos * sizeof(qint64)); _lineflags.removeLast(currentPos * sizeof(char)); } else { _index.removeLast(0); _lineflags.removeLast(0); } // Now save the new indexes and properties to proper files int totalLines = reflowFile->len() / sizeof(reflowData); currentPos = 0; while (currentPos < totalLines) { reflowFile->get(reinterpret_cast(&newLine), sizeof(reflowData), currentPos * sizeof(reflowData)); unsigned char flags = newLine.lineFlag ? 0x01 : 0x00; _lineflags.add(reinterpret_cast(&flags), sizeof(char)); _index.add(reinterpret_cast(&newLine.index), sizeof(qint64)); currentPos++; } delete reflowFile; return 0; } deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/history/HistoryScrollFile.h000066400000000000000000000041321475472654300304570ustar00rootroot00000000000000/* This file is part of Konsole, an X terminal. 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 (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. */ #ifndef HISTORYSCROLLFILE_H #define HISTORYSCROLLFILE_H // History #include "HistoryFile.h" #include "HistoryScroll.h" namespace Konsole { ////////////////////////////////////////////////////////////////////// // File-based history (e.g. file log, no limitation in length) ////////////////////////////////////////////////////////////////////// class HistoryScrollFile : public HistoryScroll { public: explicit HistoryScrollFile(); ~HistoryScrollFile() override; int getLines() override; int getMaxLines() override; int getLineLen(int lineno) override; void getCells(int lineno, int colno, int count, Character res[]) override; bool isWrappedLine(int lineno) override; LineProperty getLineProperty(int lineno) override; void addCells(const Character text[], int count) override; void addLine(LineProperty lineProperty = 0) override; // Modify history void removeCells() override; int reflowLines(int columns) override; private: qint64 startOfLine(int lineno); HistoryFile _index; // lines Row(qint64) HistoryFile _cells; // text Row(Character) HistoryFile _lineflags; // flags Row(unsigned char) struct reflowData { // data to reflow lines qint64 index; bool lineFlag; }; }; } #endif deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/history/HistoryScrollNone.cpp000066400000000000000000000033361475472654300310370ustar00rootroot00000000000000/* This file is part of Konsole, an X terminal. 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 (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. */ // Own #include "HistoryScrollNone.h" #include "HistoryTypeNone.h" using namespace Konsole; // History Scroll None ////////////////////////////////////// HistoryScrollNone::HistoryScrollNone() : HistoryScroll(new HistoryTypeNone()) { } HistoryScrollNone::~HistoryScrollNone() { } bool HistoryScrollNone::hasScroll() { return false; } int HistoryScrollNone::getLines() { return 0; } int HistoryScrollNone::getMaxLines() { return 0; } int HistoryScrollNone::getLineLen(int) { return 0; } bool HistoryScrollNone::isWrappedLine(int /*lineno*/) { return false; } LineProperty HistoryScrollNone::getLineProperty(int /*lineno*/) { return 0; } void HistoryScrollNone::getCells(int, int, int, Character []) { } void HistoryScrollNone::addCells(const Character [], int) { } void HistoryScrollNone::removeCells() { } int HistoryScrollNone::reflowLines(int) { return 0; } deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/history/HistoryScrollNone.h000066400000000000000000000034251475472654300305030ustar00rootroot00000000000000/* This file is part of Konsole, an X terminal. 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 (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. */ #ifndef HISTORYSCROLLNONE_H #define HISTORYSCROLLNONE_H #include "HistoryScroll.h" namespace Konsole { ////////////////////////////////////////////////////////////////////// // Nothing-based history (no history :-) ////////////////////////////////////////////////////////////////////// class HistoryScrollNone : public HistoryScroll { public: HistoryScrollNone(); ~HistoryScrollNone() override; bool hasScroll() override; int getLines() override; int getMaxLines() override; int getLineLen(int lineno) override; void getCells(int lineno, int colno, int count, Character res[]) override; bool isWrappedLine(int lineno) override; LineProperty getLineProperty(int lineno) override; void addCells(const Character a[], int count) override; void addLine(LineProperty lineProperty = 0)override {} // Modify history (do nothing here) void removeCells() override; int reflowLines(int) override; }; } #endif deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/history/HistoryType.cpp000066400000000000000000000020271475472654300276760ustar00rootroot00000000000000/* This file is part of Konsole, an X terminal. 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 (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. */ #include "HistoryType.h" using namespace Konsole; HistoryType::HistoryType() { } HistoryType::~HistoryType() { } bool HistoryType::isUnlimited() const { return maximumLineCount() == -1; } deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/history/HistoryType.h000066400000000000000000000032171475472654300273450ustar00rootroot00000000000000/* This file is part of Konsole, an X terminal. 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 (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. */ #ifndef HISTORYTYPE_H #define HISTORYTYPE_H #include "HistoryScroll.h" namespace Konsole { class HistoryType { public: HistoryType(); virtual ~HistoryType(); /** * Returns true if the history is enabled ( can store lines of output ) * or false otherwise. */ virtual bool isEnabled() const = 0; /** * Returns the maximum number of lines which this history type * can store or -1 if the history can store an unlimited number of lines. */ virtual int maximumLineCount() const = 0; /** * Converts from one type of HistoryScroll to another or if given the * same type, returns it. */ virtual HistoryScroll *scroll(HistoryScroll *) const = 0; /** * Returns true if the history size is unlimited. */ bool isUnlimited() const; }; } #endif deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/history/HistoryTypeFile.cpp000066400000000000000000000040131475472654300304730ustar00rootroot00000000000000/* This file is part of Konsole, an X terminal. 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 (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. */ #include "HistoryTypeFile.h" #include "HistoryFile.h" #include "HistoryScrollFile.h" using namespace Konsole; // Reasonable line size static const int LINE_SIZE = 1024; HistoryTypeFile::HistoryTypeFile() { } bool HistoryTypeFile::isEnabled() const { return true; } HistoryScroll *HistoryTypeFile::scroll(HistoryScroll *old) const { if (dynamic_cast(old) != nullptr) { return old; // Unchanged. } HistoryScroll *newScroll = new HistoryScrollFile(); Character line[LINE_SIZE]; int lines = (old != nullptr) ? old->getLines() : 0; for (int i = 0; i < lines; i++) { int size = old->getLineLen(i); if (size > LINE_SIZE) { auto tmp_line = new Character[size]; old->getCells(i, 0, size, tmp_line); newScroll->addCells(tmp_line, size); newScroll->addLine(old->isWrappedLine(i)); delete [] tmp_line; } else { old->getCells(i, 0, size, line); newScroll->addCells(line, size); newScroll->addLine(old->isWrappedLine(i)); } } delete old; return newScroll; } int HistoryTypeFile::maximumLineCount() const { return -1; } deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/history/HistoryTypeFile.h000066400000000000000000000022431475472654300301430ustar00rootroot00000000000000/* This file is part of Konsole, an X terminal. 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 (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. */ #ifndef HISTORYTYPEFILE_H #define HISTORYTYPEFILE_H #include "HistoryType.h" namespace Konsole { class HistoryTypeFile : public HistoryType { public: explicit HistoryTypeFile(); bool isEnabled() const override; int maximumLineCount() const override; HistoryScroll *scroll(HistoryScroll *) const override; }; } #endif deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/history/HistoryTypeNone.cpp000066400000000000000000000023131475472654300305140ustar00rootroot00000000000000/* This file is part of Konsole, an X terminal. 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 (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. */ #include "HistoryTypeNone.h" #include "HistoryScrollNone.h" using namespace Konsole; HistoryTypeNone::HistoryTypeNone() { } bool HistoryTypeNone::isEnabled() const { return false; } HistoryScroll *HistoryTypeNone::scroll(HistoryScroll *old) const { delete old; return new HistoryScrollNone(); } int HistoryTypeNone::maximumLineCount() const { return 0; } deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/history/HistoryTypeNone.h000066400000000000000000000022321475472654300301610ustar00rootroot00000000000000/* This file is part of Konsole, an X terminal. 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 (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. */ #ifndef HISTORYTYPENONE_H #define HISTORYTYPENONE_H #include "HistoryType.h" namespace Konsole { class HistoryTypeNone : public HistoryType { public: HistoryTypeNone(); bool isEnabled() const override; int maximumLineCount() const override; HistoryScroll *scroll(HistoryScroll *) const override; }; } #endif deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/history/compact/000077500000000000000000000000001475472654300263145ustar00rootroot00000000000000deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/history/compact/CompactHistoryScroll.cpp000066400000000000000000000104321475472654300331470ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 1997, 1998 Lars Doelle SPDX-License-Identifier: GPL-2.0-or-later */ // Own #include "CompactHistoryScroll.h" #include "CompactHistoryType.h" using namespace Konsole; struct reflowData { // data to reflow lines QList index; QList flags; }; CompactHistoryScroll::CompactHistoryScroll(unsigned int maxLineCount) : HistoryScroll(new CompactHistoryType(maxLineCount)), _cells(), _index(), _flags(), _maxLineCount(0) { setMaxNbLines(maxLineCount); } void CompactHistoryScroll::removeFirstLine() { _flags.pop_front(); auto removing = _index.first(); _index.pop_front(); std::transform(_index.begin(), _index.end(), _index.begin(), [removing](int i) { return i - removing; }); while (_cells.size() > _index.last()) { _cells.pop_front(); } } inline int CompactHistoryScroll::lineLen(int line) { return line == 0 ? _index[0] : _index[line] - _index[line - 1]; } inline int CompactHistoryScroll::startOfLine(int line) { return line == 0 ? 0 : _index[line - 1]; } void CompactHistoryScroll::addCells(const Character a[], int count) { std::copy(a, a + count, std::back_inserter(_cells)); _index.append(_cells.size()); _flags.append(LINE_DEFAULT); if (_index.size() > _maxLineCount) { removeFirstLine(); } } void CompactHistoryScroll::addLine(LineProperty lineProperty) { auto &flag = _flags.last(); flag = lineProperty; } int CompactHistoryScroll::getLines() { return _index.size(); } int CompactHistoryScroll::getMaxLines() { return _maxLineCount; } int CompactHistoryScroll::getLineLen(int lineNumber) { if (lineNumber < 0 || lineNumber >= _index.size()) { return 0; } return lineLen(lineNumber); } void CompactHistoryScroll::getCells(int lineNumber, int startColumn, int count, Character buffer[]) { if (count == 0) { return; } Q_ASSERT(lineNumber < _index.size()); Q_ASSERT(startColumn >= 0); Q_ASSERT(startColumn <= lineLen(lineNumber) - count); auto startCopy = _cells.begin() + startOfLine(lineNumber) + startColumn; auto endCopy = startCopy + count; std::copy(startCopy, endCopy, buffer); } void CompactHistoryScroll::setMaxNbLines(int lineCount) { Q_ASSERT(lineCount >= 0); _maxLineCount = lineCount; while (_index.size() > lineCount) { removeFirstLine(); } } void CompactHistoryScroll::removeCells() { if (_index.size() > 1) { _index.pop_back(); _flags.pop_back(); while (_cells.size() > _index.last()) { _cells.pop_back(); } } else { _cells.clear(); _index.clear(); _flags.clear(); } } bool CompactHistoryScroll::isWrappedLine(int lineNumber) { Q_ASSERT(lineNumber < _index.size()); return _flags[lineNumber] & LINE_WRAPPED; } LineProperty CompactHistoryScroll::getLineProperty(int lineNumber) { Q_ASSERT(lineNumber < _index.size()); return _flags[lineNumber]; } int CompactHistoryScroll::reflowLines(int columns) { reflowData newLine; auto reflowLineLen = [](int start, int end) { return end - start; }; auto setNewLine = [](reflowData &change, int index, LineProperty flag) { change.index.append(index); change.flags.append(flag); }; int currentPos = 0; while (currentPos < getLines()) { int startLine = startOfLine(currentPos); int endLine = startOfLine(currentPos + 1); LineProperty lineProperty = getLineProperty(currentPos); // Join the lines if they are wrapped while (isWrappedLine(currentPos)) { currentPos++; endLine = startOfLine(currentPos + 1); } // Now reflow the lines while (reflowLineLen(startLine, endLine) > columns && !(lineProperty & (LINE_DOUBLEHEIGHT_BOTTOM | LINE_DOUBLEHEIGHT_TOP))) { startLine += columns; setNewLine(newLine, startLine, lineProperty | LINE_WRAPPED); } setNewLine(newLine, endLine, lineProperty & ~LINE_WRAPPED); currentPos++; } _index = newLine.index; _flags = newLine.flags; int deletedLines = 0; while (getLines() > _maxLineCount) { removeFirstLine(); ++deletedLines; } return deletedLines; } deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/history/compact/CompactHistoryScroll.h000066400000000000000000000024151475472654300326160ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 1997, 1998 Lars Doelle SPDX-License-Identifier: GPL-2.0-or-later */ #ifndef COMPACTHISTORYSCROLL_H #define COMPACTHISTORYSCROLL_H // STD #include #include "history/HistoryScroll.h" namespace Konsole { class KONSOLEPRIVATE_EXPORT CompactHistoryScroll : public HistoryScroll { typedef QVector TextLine; public: explicit CompactHistoryScroll(unsigned int maxLineCount = 1000); ~CompactHistoryScroll() = default; int getLines() override; int getMaxLines() override; int getLineLen(int lineNumber) override; void getCells(int lineNumber, int startColumn, int count, Character buffer[]) override; bool isWrappedLine(int lineNumber) override; LineProperty getLineProperty(int lineNumber) override; void addCells(const Character a[], int count) override; void addLine(LineProperty lineProperty = 0) override; void removeCells() override; void setMaxNbLines(int lineCount); int reflowLines(int columns) override; private: QList _cells; QList _index; QList _flags; int _maxLineCount; void removeFirstLine(); inline int lineLen(const int line); inline int startOfLine(int line); }; } #endif deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/history/compact/CompactHistoryType.cpp000066400000000000000000000045361475472654300326420ustar00rootroot00000000000000/* This file is part of Konsole, an X terminal. 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 (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. */ // Own #include "CompactHistoryType.h" #include "CompactHistoryScroll.h" using namespace Konsole; // Reasonable line size static const int LINE_SIZE = 1024; CompactHistoryType::CompactHistoryType(unsigned int nbLines) : _maxLines(nbLines) { } bool CompactHistoryType::isEnabled() const { return true; } int CompactHistoryType::maximumLineCount() const { return _maxLines; } HistoryScroll *CompactHistoryType::scroll(HistoryScroll *old) const { if (old != nullptr) { auto *newBuffer = dynamic_cast(old); if (newBuffer != nullptr) { newBuffer->setMaxNbLines(_maxLines); return newBuffer; } newBuffer = new CompactHistoryScroll(_maxLines); Character line[LINE_SIZE]; int lines = old->getLines(); int i = qMax((lines - (int)_maxLines - 1), 0); for (; i < lines; i++) { int size = old->getLineLen(i); if (size > LINE_SIZE) { auto tmp_line = new Character[size]; old->getCells(i, 0, size, tmp_line); newBuffer->addCells(tmp_line, size); newBuffer->addLine(old->isWrappedLine(i)); delete[] tmp_line; } else { old->getCells(i, 0, size, line); newBuffer->addCells(line, size); newBuffer->addLine(old->isWrappedLine(i)); } } delete old; return newBuffer; } return new CompactHistoryScroll(_maxLines); } deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/history/compact/CompactHistoryType.h000066400000000000000000000023561475472654300323050ustar00rootroot00000000000000/* This file is part of Konsole, an X terminal. 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 (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. */ #ifndef COMPACTHISTORYTYPE_H #define COMPACTHISTORYTYPE_H #include "../HistoryType.h" namespace Konsole { class CompactHistoryType : public HistoryType { public: explicit CompactHistoryType(unsigned int nbLines); bool isEnabled() const override; int maximumLineCount() const override; HistoryScroll *scroll(HistoryScroll *) const override; protected: unsigned int _maxLines; }; } #endif deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/kb-layouts/000077500000000000000000000000001475472654300252575ustar00rootroot00000000000000deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/kb-layouts/README000066400000000000000000000044151475472654300261430ustar00rootroot00000000000000[README.KeyTab] The keytabs offered in the Options/Keyboard menu are taken from from configurations files with a *.keytab pattern either located in $KDEDIR/share/apps/konsole or ~/.kde/share/apps/konsole. Keytabs allow to configure the behavior of konsole on keyboard events, especially for functions keys. Please have a look into the README.keyboard file, too. The syntax is that each entry has the form : "key" Keyname { ("+"|"-") Modename } ":" (String|Operation) Keynames are those defined in with the "Qt::Key_" prefix removed. Mode names are: - Shift : Shift Key pressed - Alt : Alt Key pressed - Control : Control Key pressed ( The VT100 emulation has modes that can affect the sequences emitted by certain keys. These modes are under control of the client program. - Newline : effects Return and Enter key. - Application : effects Up and Down key. - Ansi : effects Up and Down key (This is for VT52, really). Since sending a state to a program that has set the state itself is positivly wrong and obsolete design, better forget about this nasty detail. I may well remove this "feature" in a future clean up round. ) A "+" preceeding a Modename means the Key is pressed. A "-" preceeding a Modename means the Key is not pressed. If no mode is given it means don't care. Note that the combination of Key and Modes (set/reset) has to be unique. This means, that key A + Shift : "A" key A : "a" will not accept the small letter "a" rule as expected, one has to add a "- Shift" to the last clause. Use the stdout/stderr dianostics of konsole when modifying keytabs to find problems like this. Operations are - scrollUpLine : scroll up one line in the history log - scrollUpPage : scroll up one page in the history log - scrollDownLine : scroll down one line in the history log - scrollDownPage : scroll down one page in the history log - emitClipboard : "paste" the current clipboard - emitSelection : "paste" the current selection Strings have the syntax of C strings, one may use the following escapes: - \E - escape - \\ - backslash - \" - double quote - \t - tab - \r - return - \n - newline - \b - backspace - \xHH - where HH are two hex digits deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/kb-layouts/default.keytab000066400000000000000000000130401475472654300301020ustar00rootroot00000000000000# [README.default.Keytab] Default Keyboard Table # # To customize your keyboard, copy this file to something # ending with .keytab and change it to meet you needs. # Please read the README.KeyTab and the README.keyboard # in this case. # # -------------------------------------------------------------- keyboard "Default (XFree 4)" # -------------------------------------------------------------- # # Note that this particular table is a "risc" version made to # ease customization without bothering with obsolete details. # See VT100.keytab for the more hairy stuff. # # -------------------------------------------------------------- # common keys key Escape : "\E" key Tab -Shift : "\t" key Tab +Shift+Ansi : "\E[Z" key Tab +Shift-Ansi : "\t" key Backtab +Ansi : "\E[Z" key Backtab -Ansi : "\t" key Return-Shift-NewLine : "\r" key Return-Shift+NewLine : "\r\n" key Return+Shift : "\EOM" # Backspace and Delete codes are preserving CTRL-H. # # old # Backspace without CTRL sends '^H'; this matches XTerm behaviour # BS, hex \x08, \b # new # Backspace without CTRL sends '^?'; this matches gnome-terminal key Backspace -Control : "\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. # shift left/right are reserved for switching between tabs (this is hardcoded). key Up -Shift-Ansi : "\EA" key Down -Shift-Ansi : "\EB" key Right-Shift-Ansi : "\EC" key Left -Shift-Ansi : "\ED" # Arrow keys in ANSI mode with Application - and Normal Cursor Mode) key Up -Shift-AnyMod+Ansi+AppCuKeys : "\EOA" key Down -Shift-AnyMod+Ansi+AppCuKeys : "\EOB" key Right -Shift-AnyMod+Ansi+AppCuKeys : "\EOC" key Left -Shift-AnyMod+Ansi+AppCuKeys : "\EOD" key Up -Shift-AnyMod+Ansi-AppCuKeys : "\E[A" key Down -Shift-AnyMod+Ansi-AppCuKeys : "\E[B" key Right -Shift-AnyMod+Ansi-AppCuKeys : "\E[C" key Left -Shift-AnyMod+Ansi-AppCuKeys : "\E[D" key Up -Shift+AnyMod+Ansi : "\E[1;*A" 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 ) # # Not enabled for now because it breaks the keypad in Vim. # #key 0 +KeyPad+AppKeyPad : "\EOp" #key 1 +KeyPad+AppKeyPad : "\EOq" #key 2 +KeyPad+AppKeyPad : "\EOr" #key 3 +KeyPad+AppKeyPad : "\EOs" #key 4 +KeyPad+AppKeyPad : "\EOt" #key 5 +KeyPad+AppKeyPad : "\EOu" #key 6 +KeyPad+AppKeyPad : "\EOv" #key 7 +KeyPad+AppKeyPad : "\EOw" #key 8 +KeyPad+AppKeyPad : "\EOx" #key 9 +KeyPad+AppKeyPad : "\EOy" #key + +KeyPad+AppKeyPad : "\EOl" #key - +KeyPad+AppKeyPad : "\EOm" #key . +KeyPad+AppKeyPad : "\EOn" #key * +KeyPad+AppKeyPad : "\EOM" #key Enter +KeyPad+AppKeyPad : "\r" # Keypad keys with NumLock Off key Up -Shift+Ansi+AppCuKeys+KeyPad : "\EOA" key Down -Shift+Ansi+AppCuKeys+KeyPad : "\EOB" key Right -Shift+Ansi+AppCuKeys+KeyPad : "\EOC" key Left -Shift+Ansi+AppCuKeys+KeyPad : "\EOD" key Up -Shift+Ansi-AppCuKeys+KeyPad : "\E[A" key Down -Shift+Ansi-AppCuKeys+KeyPad : "\E[B" key Right -Shift+Ansi-AppCuKeys+KeyPad : "\E[C" key Left -Shift+Ansi-AppCuKeys+KeyPad : "\E[D" key Home +AppCuKeys+KeyPad : "\EOH" 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 PgUp -Shift+KeyPad : "\E[5~" key PgDown -Shift+KeyPad : "\E[6~" # other grey PC keys key Enter+NewLine : "\r\n" key Enter-NewLine : "\r" key Home -AnyMod-AppCuKeys : "\E[H" key End -AnyMod-AppCuKeys : "\E[F" key Home -AnyMod+AppCuKeys : "\EOH" key End -AnyMod+AppCuKeys : "\EOF" key Home +AnyMod : "\E[1;*H" key End +AnyMod : "\E[1;*F" key Insert -AnyMod : "\E[2~" key Delete -AnyMod : "\E[3~" key Insert +AnyMod : "\E[2;*~" key Delete +AnyMod : "\E[3;*~" 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" key F2 -AnyMod : "\EOQ" key F3 -AnyMod : "\EOR" key F4 -AnyMod : "\EOS" key F5 -AnyMod : "\E[15~" key F6 -AnyMod : "\E[17~" key F7 -AnyMod : "\E[18~" key F8 -AnyMod : "\E[19~" key F9 -AnyMod : "\E[20~" key F10 -AnyMod : "\E[21~" key F11 -AnyMod : "\E[23~" key F12 -AnyMod : "\E[24~" key F1 +AnyMod : "\EO*P" key F2 +AnyMod : "\EO*Q" key F3 +AnyMod : "\EO*R" key F4 +AnyMod : "\EO*S" key F5 +AnyMod : "\E[15;*~" key F6 +AnyMod : "\E[17;*~" key F7 +AnyMod : "\E[18;*~" key F8 +AnyMod : "\E[19;*~" key F9 +AnyMod : "\E[20;*~" key F10 +AnyMod : "\E[21;*~" key F11 +AnyMod : "\E[23;*~" key F12 +AnyMod : "\E[24;*~" # Work around dead keys 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 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 deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/kb-layouts/historic/000077500000000000000000000000001475472654300271035ustar00rootroot00000000000000deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/kb-layouts/historic/vt100.keytab000066400000000000000000000061701475472654300311620ustar00rootroot00000000000000# [vt100.keytab] Konsole Keyboard Table (VT100 keys) # # -------------------------------------------------------------- keyboard "vt100 (historical)" # -------------------------------------------------------------- # # This configuration table allows to customize the # meaning of the keys. # # The syntax is that each entry has the form : # # "key" Keyname { ("+"|"-") Modename } ":" (String|Operation) # # Keynames are those defined in with the # "Qt::Key_" removed. (We'd better insert the list here) # # Mode names are : # # - Shift # - Alt # - Control # # The VT100 emulation has two modes that can affect the # sequences emitted by certain keys. These modes are # under control of the client program. # # - Newline : effects Return and Enter key. # - Application : effects Up and Down key. # # - Ansi : effects Up and Down key (This is for VT52, really). # # Operations are # # - scrollUpLine # - scrollUpPage # - scrollDownLine # - scrollDownPage # # - emitSelection # # If the key is not found here, the text of the # key event as provided by QT is emitted, possibly # preceeded by ESC if the Alt key is pressed. # # -------------------------------------------------------------- key Escape : "\E" key Tab : "\t" # VT100 can add an extra \n after return. # The NewLine mode is set by an escape sequence. key Return-NewLine : "\r" key Return+NewLine : "\r\n" # Some desperately try to save the ^H. key Backspace : "\x7f" key Delete : "\E[3~" # These codes are for the VT52 mode of VT100 # The Ansi mode (i.e. VT100 mode) is set by # an escape sequence key Up -Shift-Ansi : "\EA" key Down -Shift-Ansi : "\EB" key Right-Shift-Ansi : "\EC" key Left -Shift-Ansi : "\ED" # VT100 emits a mode bit together # with the arrow keys.The AppCuKeys # mode is set by an escape sequence. key Up -Shift+Ansi+AppCuKeys : "\EOA" key Down -Shift+Ansi+AppCuKeys : "\EOB" key Right-Shift+Ansi+AppCuKeys : "\EOC" key Left -Shift+Ansi+AppCuKeys : "\EOD" key Up -Shift+Ansi-AppCuKeys : "\E[A" key Down -Shift+Ansi-AppCuKeys : "\E[B" key Right-Shift+Ansi-AppCuKeys : "\E[C" key Left -Shift+Ansi-AppCuKeys : "\E[D" # function keys (FIXME: make pf1-pf4) key F1 : "\E[11~" key F2 : "\E[12~" key F3 : "\E[13~" key F4 : "\E[14~" key F5 : "\E[15~" key F6 : "\E[17~" key F7 : "\E[18~" key F8 : "\E[19~" key F9 : "\E[20~" key F10 : "\E[21~" key F11 : "\E[23~" key F12 : "\E[24~" key Home : "\E[H" key End : "\E[F" key PgUp -Shift : "\E[5~" key PgDown -Shift : "\E[6~" key Insert -Shift : "\E[2~" # Keypad-Enter. See comment on Return above. key Enter+NewLine : "\r\n" key Enter-NewLine : "\r" key Space +Control : "\x00" # some of keys are used by konsole. key Up +Shift : scrollLineUp key PgUp +Shift : scrollPageUp key Down +Shift : scrollLineDown key PgDown +Shift : scrollPageDown key ScrollLock : scrollLock #---------------------------------------------------------- # keypad characters as offered by Qt # cannot be recognized as such. #---------------------------------------------------------- # Following other strings as emitted by konsole. deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/kb-layouts/historic/x11r5.keytab000066400000000000000000000032161475472654300311660ustar00rootroot00000000000000# [x11r5.Keytab] Keyboard Table for X11 R5 keyboard "XTerm (XFree 3.x.x)" # -------------------------------------------------------------- # # Note that this particular table is a "risc" version made to # ease customization without bothering with obsolete details. # See VT100.keytab for the more hairy stuff. # # -------------------------------------------------------------- # common keys key Escape : "\E" key Tab : "\t" key Return : "\r" # Backspace and Delete codes are preserving CTRL-H. key Backspace : "\x7f" # cursor keys key Up -Shift : "\EOA" key Down -Shift : "\EOB" key Right -Shift : "\EOC" key Left -Shift : "\EOD" # other grey PC keys key Enter : "\r" key Home : "\E[1~" key Insert-Shift : "\E[2~" key Delete : "\E[3~" key End : "\E[4~" key PgUp -Shift : "\E[5~" key PgDown -Shift : "\E[6~" # function keys key F1 : "\E[11~" key F2 : "\E[12~" key F3 : "\E[13~" key F4 : "\E[14~" key F5 : "\E[15~" key F6 : "\E[17~" key F7 : "\E[18~" key F8 : "\E[19~" key F9 : "\E[20~" key F10 : "\E[21~" key F11 : "\E[23~" key F12 : "\E[24~" # Work around dead keys 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 PgUp +Shift : scrollPageUp key Down +Shift : scrollLineDown key PgDown +Shift : scrollPageDown key ScrollLock : scrollLock # keypad characters are not offered differently by Qt. deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/kb-layouts/linux.keytab000066400000000000000000000065471475472654300276330ustar00rootroot00000000000000# [linux.keytab] Konsole Keyboard Table (Linux console keys) # # -------------------------------------------------------------- # NOT TESTED, MAY NEED SOME CLEANUPS keyboard "Linux console" # -------------------------------------------------------------- # # This configuration table allows to customize the # meaning of the keys. # # The syntax is that each entry has the form : # # "key" Keyname { ("+"|"-") Modename } ":" (String|Operation) # # Keynames are those defined in with the # "Qt::Key_" removed. (We'd better insert the list here) # # Mode names are : # # - Shift # - Alt # - Control # # The VT100 emulation has two modes that can affect the # sequences emitted by certain keys. These modes are # under control of the client program. # # - Newline : effects Return and Enter key. # - Application : effects Up and Down key. # # - Ansi : effects Up and Down key (This is for VT52, really). # # Operations are # # - scrollUpLine # - scrollUpPage # - scrollDownLine # - scrollDownPage # # - emitSelection # # If the key is not found here, the text of the # key event as provided by QT is emitted, possibly # preceeded by ESC if the Alt key is pressed. # # -------------------------------------------------------------- key Escape : "\E" key Tab : "\t" # VT100 can add an extra \n after return. # The NewLine mode is set by an escape sequence. key Return-NewLine : "\r" key Return+NewLine : "\r\n" # Some desperately try to save the ^H. key Backspace : "\x7f" key Delete : "\E[3~" # These codes are for the VT52 mode of VT100 # The Ansi mode (i.e. VT100 mode) is set by # an escape sequence key Up -Shift-Ansi : "\EA" key Down -Shift-Ansi : "\EB" key Right-Shift-Ansi : "\EC" key Left -Shift-Ansi : "\ED" # VT100 emits a mode bit together # with the arrow keys.The AppCuKeys # mode is set by an escape sequence. key Up -Shift+Ansi+AppCuKeys : "\EOA" key Down -Shift+Ansi+AppCuKeys : "\EOB" key Right-Shift+Ansi+AppCuKeys : "\EOC" key Left -Shift+Ansi+AppCuKeys : "\EOD" key Up -Shift+Ansi-AppCuKeys : "\E[A" key Down -Shift+Ansi-AppCuKeys : "\E[B" key Right-Shift+Ansi-AppCuKeys : "\E[C" key Left -Shift+Ansi-AppCuKeys : "\E[D" key Up -Shift+AnyMod+Ansi : "\E[1;*A" key Down -Shift+AnyMod+Ansi : "\E[1;*B" key Right -Shift+AnyMod+Ansi : "\E[1;*C" key Left -Shift+AnyMod+Ansi : "\E[1;*D" # linux functions keys F1-F5 differ from xterm key F1 : "\E[[A" key F2 : "\E[[B" key F3 : "\E[[C" key F4 : "\E[[D" key F5 : "\E[[E" key F6 : "\E[17~" key F7 : "\E[18~" key F8 : "\E[19~" key F9 : "\E[20~" key F10 : "\E[21~" key F11 : "\E[23~" key F12 : "\E[24~" key Home : "\E[1~" key End : "\E[4~" key PgUp -Shift : "\E[5~" key PgDown -Shift : "\E[6~" key Insert -Shift : "\E[2~" # Keypad-Enter. See comment on Return above. key Enter+NewLine : "\r\n" key Enter-NewLine : "\r" key Space +Control : "\x00" # some of keys are used by konsole. key Up +Shift : scrollLineUp key PgUp +Shift : scrollPageUp key Down +Shift : scrollLineDown key PgDown +Shift : scrollPageDown key ScrollLock : scrollLock #---------------------------------------------------------- # keypad characters as offered by Qt # cannot be recognized as such. #---------------------------------------------------------- # Following other strings as emitted by konsole. deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/kb-layouts/macbook.keytab000066400000000000000000000144161475472654300301010ustar00rootroot00000000000000# [README.default.Keytab] Buildin Keyboard Table # # To customize your keyboard, copy this file to something # ending with .keytab and change it to meet you needs. # Please read the README.KeyTab and the README.keyboard # in this case. # # -------------------------------------------------------------- keyboard "Default (XFree 4)" # -------------------------------------------------------------- # # Note that this particular table is a "risc" version made to # ease customization without bothering with obsolete details. # See VT100.keytab for the more hairy stuff. # # -------------------------------------------------------------- # common keys key Escape : "\x1b" #key Control : "^" key Tab -Shift : "\t" key Tab +Shift+Ansi : "\E[Z" key Tab +Shift-Ansi : "\t" key Backtab +Ansi : "\E[Z" key Backtab -Ansi : "\t" key Return-Shift-NewLine : "\r" key Return-Shift+NewLine : "\r\n" key Return+Shift : "\EOM" # Backspace and Delete codes are preserving CTRL-H. key Backspace : "\x7f" # Arrow keys in VT52 mode # shift up/down are reserved for scrolling. # shift left/right are reserved for switching between tabs (this is hardcoded). # Command + C # on mac - Control=Command, Meta=Ctrl # do not use Control+C for interrupt signal - it's used for "Copy to clipboard" #key Control +C : "\x03" key Meta +C: "\x03" # Arrow keys in ANSI mode with Application - and Normal Cursor Mode) key Up -Shift+Ansi-AppCuKeys : "\E[A" key Down -Shift+Ansi-AppCuKeys : "\E[B" key Right-Shift+Ansi-AppCuKeys : "\E[C" key Left -Shift+Ansi-AppCuKeys : "\E[D" key Up -Ansi : "\E[1;*A" key Down -Ansi : "\E[1;*B" key Right -Ansi : "\E[1;*C" key Left -Ansi : "\E[1;*D" #key Up -Shift-Ansi : "\EA" #key Down -Shift-Ansi : "\EB" #key Right-Shift-Ansi : "\EC" #key Left -Shift-Ansi : "\ED" #key Up -Shift-AnyMod+Ansi-AppCuKeys : "\E[A" #key Down -Shift-AnyMod+Ansi-AppCuKeys : "\E[B" #key Right -Shift-AnyMod+Ansi-AppCuKeys : "\E[C" #key Left -Shift-AnyMod+Ansi-AppCuKeys : "\E[D" #key Up -Shift-AnyMod+Ansi-AppCuKeys : "\EOA" #key Down -Shift-AnyMod+Ansi-AppCuKeys : "\EOB" #key Right -Shift-AnyMod+Ansi-AppCuKeys : "\EOC" #key Left -Shift-AnyMod+Ansi-AppCuKeys : "\EOD" #key Up -Shift-AnyMod+Ansi : "\E[1;*A" #key Down -Shift-AnyMod+Ansi : "\E[1;*B" #key Right -Shift-AnyMod+Ansi : "\E[1;*C" #key Left -Shift-AnyMod+Ansi : "\E[1;*D" # other grey PC keys key Enter+NewLine : "\r\n" key Enter-NewLine : "\r" key Home -AnyMod -AppCuKeys : "\E[H" key End -AnyMod -AppCuKeys : "\E[F" key Home -AnyMod +AppCuKeys : "\EOH" key End -AnyMod +AppCuKeys : "\EOF" key Home +AnyMod : "\E[1;*H" key End +AnyMod : "\E[1;*F" key Insert -AnyMod : "\E[2~" key Delete -AnyMod : "\E[3~" key Insert +AnyMod : "\E[2;*~" key Delete +AnyMod : "\E[3;*~" 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" #key F2 -AnyMod : "\EOQ" #key F3 -AnyMod : "\EOR" #key F4 -AnyMod : "\EOS" #define ALT_KP_0 "\033Op" #define ALT_KP_1 "\033Oq" #define ALT_KP_2 "\033Or" #define ALT_KP_3 "\033Os" #define ALT_KP_4 "\033Ot" #define ALT_KP_5 "\033Ou" #define ALT_KP_6 "\033Ov" #define ALT_KP_7 "\033Ow" #define ALT_KP_8 "\033Ox" #define ALT_KP_9 "\033Oy" key F1 -AnyMod : "\EOP" key F2 -AnyMod : "\EOQ" key F3 -AnyMod : "\EOR" key F4 -AnyMod : "\EOS" key F5 -AnyMod : "\EOT" key F6 -AnyMod : "\EOU" key F7 -AnyMod : "\EOV" key F8 -AnyMod : "\EOW" key F9 -AnyMod : "\EOX" key F10 -AnyMod : "\EOY" #key F5 -AnyMod : "\E[15~" #key F6 -AnyMod : "\E[17~" #key F7 -AnyMod : "\E[18~" #key F8 -AnyMod : "\E[19~" #key F9 -AnyMod : "\E[20~" #key F10 -AnyMod : "\E[21~" #key F11 -AnyMod : "\E[23~" #key F12 -AnyMod : "\E[24~" #key F1 +AnyMod : "\EO*P" #key F2 +AnyMod : "\EO*Q" #key F3 +AnyMod : "\EO*R" #key F4 +AnyMod : "\EO*S" #key F5 +AnyMod : "\E[15;*~" #key F6 +AnyMod : "\E[17;*~" #key F7 +AnyMod : "\E[18;*~" #key F8 +AnyMod : "\E[19;*~" #key F9 +AnyMod : "\E[20;*~" #key F10 +AnyMod : "\E[21;*~" #key F11 +AnyMod : "\E[23;*~" #key F12 +AnyMod : "\E[24;*~" # Work around dead keys 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 PgUp +Shift-AppScreen : scrollPageUp key Down +Shift-AppScreen : scrollLineDown key PgDown +Shift-AppScreen : scrollPageDown #key Up +Shift : scrollLineUp #key Prior +Shift : scrollPageUp #key Down +Shift : scrollLineDown #key Next +Shift : scrollPageDown key ScrollLock : scrollLock # keypad characters are not offered differently by Qt. deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/kb-layouts/solaris.keytab000066400000000000000000000050601475472654300301350ustar00rootroot00000000000000# [solaris.keytab] Konsole Keyboard Table # keyboard "Solaris console" # -------------------------------------------------------------- # # This configuration table allows to customize the # meaning of the keys. # # The syntax is that each entry has the form : # # "key" Keyname { ("+"|"-") Modename } ":" (String|Operation) # # Keynames are those defined in with the # "Qt::Key_" removed. (We'd better insert the list here) # # Mode names are : # # - Shift # - Alt # - Control # # The VT100 emulation has two modes that can affect the # sequences emitted by certain keys. These modes are # under control of the client program. # # # - Newline : effects Return and Enter key. # - Application : effects Up and Down key. # # - Ansi : effects Up and Down key (This is for VT52, really). # # Operations are # # - scrollUpLine # - scrollUpPage # - scrollDownLine # - scrollDownPage # # - emitSelection # # If the key is not found here, the text of the # key event as provided by QT is emitted, possibly # preceeded by ESC if the Alt key is pressed. # # -------------------------------------------------------------- key Escape : "\E" key Tab : "\t" key Return-Alt : "\r" key Return+Alt : "\E\r" # Backspace and Delete codes are preserving CTRL-H. key Backspace : "\x08" #key Delete : "\x7F" # cursor keys key Up -Shift : "\EOA" key Down -Shift : "\EOB" key Right -Shift : "\EOC" key Left -Shift : "\EOD" # other grey PC keys key Enter : "\r" key Home : "\E[1~" key Insert-Shift : "\E[2~" key Delete : "\E[3~" key End : "\E[4~" key PgUp -Shift : "\E[5~" key PgDown -Shift : "\E[6~" # function keys key F1 : "\E[11~" key F2 : "\E[12~" key F3 : "\E[13~" key F4 : "\E[14~" key F5 : "\E[15~" key F6 : "\E[17~" key F7 : "\E[18~" key F8 : "\E[19~" key F9 : "\E[20~" key F10 : "\E[21~" key F11 : "\E[23~" key F12 : "\E[24~" # Work around dead keys key Space +Control : "\x00" # Some keys are used by konsole to cause operations. # The scroll* operations refer to the history buffer. #key Left +Shift : prevSession #key Right +Shift : nextSession 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. deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/kb-layouts/vt420pc.keytab000066400000000000000000000105501475472654300276630ustar00rootroot00000000000000# # NOTE: This keyboard binding is not installed because it # apparently doesn't work with actual VT420 systems # (see BUG:170220) # # [vt420pc.keytab] Konsole Keyboard Table (VT420pc keys) # adapted by ferdinand gassauer f.gassauer@aon.at # Nov 2000 # ################################################################ # # The escape sequences emmited by the # keys Shift+F1 to Shift+F12 might not fit your needs # ################# IMPORTANT NOTICE ############################# # the key bindings (Kcontrol -> look and feel -> keybindgs) # overrule the settings in this file. The key bindings might be # changed by the user WITHOUT notification of the maintainer of # the keytab file. Konsole will not work as expected by # the maintainer of the keytab file. ################################################################ # # -------------------------------------------------------------- keyboard "DEC VT420 Terminal" # -------------------------------------------------------------- # # This configuration table allows to customize the # meaning of the keys. # # The syntax is that each entry has the form : # # "key" Keyname { ("+"|"-") Modename } ":" (String|Operation) # # Keynames are those defined in with the # "Qt::Key_" removed. (We'd better insert the list here) # # Mode names are : # # - Shift # - Alt # - Control # # The VT100 emulation has two modes that can affect the # sequences emitted by certain keys. These modes are # under control of the client program. # # - Newline : effects Return and Enter key. # - Application : effects Up and Down key. # # - Ansi : effects Up and Down key (This is for VT52, really). # # Operations are # # - scrollUpLine # - scrollUpPage # - scrollDownLine # - scrollDownPage # # - emitSelection # # If the key is not found here, the text of the # key event as provided by QT is emitted, possibly # preceeded by ESC if the Alt key is pressed. # # -------------------------------------------------------------- key Escape : "\E" key Tab : "\t" key Backtab: "\E[Z" # VT100 can add an extra \n after return. # The NewLine mode is set by an escape sequence. key Return-NewLine : "\r" key Return+NewLine : "\r\n" # Some desperately try to save the ^H. # may be not everyone wants this key Backspace : "\x08" # Control H key Delete : "\x7f" # These codes are for the VT420pc # The Ansi mode (i.e. VT100 mode) is set by # an escape sequence key Up -Shift-Ansi : "\EA" key Down -Shift-Ansi : "\EB" key Right-Shift-Ansi : "\EC" key Left -Shift-Ansi : "\ED" # VT100 emits a mode bit together # with the arrow keys.The AppCuKeys # mode is set by an escape sequence. key Up -Shift+Ansi+AppCuKeys : "\EOA" key Down -Shift+Ansi+AppCuKeys : "\EOB" key Right-Shift+Ansi+AppCuKeys : "\EOC" key Left -Shift+Ansi+AppCuKeys : "\EOD" key Up -Shift+Ansi-AppCuKeys : "\E[A" key Down -Shift+Ansi-AppCuKeys : "\E[B" key Right-Shift+Ansi-AppCuKeys : "\E[C" key Left -Shift+Ansi-AppCuKeys : "\E[D" # function keys key F1 -Shift : "\E[11~" key F2 -Shift : "\E[12~" key F3 -Shift : "\E[13~" key F4 -Shift : "\E[14~" key F5 -Shift : "\E[15~" key F6 -Shift : "\E[17~" key F7 -Shift : "\E[18~" key F8 -Shift : "\E[19~" key F9 -Shift : "\E[20~" key F10-Shift : "\E[21~" key F11-Shift : "\E[23~" key F12-Shift : "\E[24~" # # Shift F1-F12 # key F1 +Shift : "\E[11;2~" key F2 +Shift : "\E[12;2~" key F3 +Shift : "\E[13;2~" key F4 +Shift : "\E[14;2~" key F5 +Shift : "\E[15;2~" key F6 +Shift : "\E[17;2~" key F7 +Shift : "\E[18;2~" key F8 +Shift : "\E[19;2~" key F9 +Shift : "\E[20;2~" key F10+Shift : "\E[21;2~" key F11+Shift : "\E[23;2~" key F12+Shift : "\E[24;2~" key Home : "\E[H" key End : "\E[F" key PgUp -Shift : "\E[5~" key PgDown -Shift : "\E[6~" key Insert -Shift : "\E[2~" # Keypad-Enter. See comment on Return above. key Enter+NewLine : "\r\n" key Enter-NewLine : "\r" key Space +Control : "\x00" # some of keys are used by konsole. key Up +Shift : scrollLineUp key PgUp +Shift : scrollPageUp key Down +Shift : scrollLineDown key PgDown +Shift : scrollPageDown key ScrollLock : scrollLock #---------------------------------------------------------- # keypad characters as offered by Qt # cannot be recognized as such. #---------------------------------------------------------- # Following other strings as emitted by konsole. deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/konsole_wcwidth.cpp000066400000000000000000001441661475472654300271100ustar00rootroot00000000000000/* 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 (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 Lesser 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. */ #include "konsole_wcwidth.h" #include #include #define USE_GB18030_FONT_WIDTH struct Range { uint first, last; }; struct RangeLut { int8_t width; const Range * const lut; int size; }; enum { InvalidWidth = INT8_MIN }; static constexpr const int8_t DIRECT_LUT[] = { 0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, }; // 调整GB18030字体ASCII字符宽度 static constexpr const int8_t DIRECT_LUT_GB18030[] = { 0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, 1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, 1, 1, 1, 1, 2, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 1, 1, 2, 2, 1, 1, 1, 2, 1, 2, 2, 1, 2, 1, 1, 1, }; static constexpr const Range LUT_NONPRINTABLE[] = { {0x00d800,0x00dfff}, }; static constexpr const Range LUT_2[] = { {0x001100,0x00115f},{0x00231a,0x00231b},{0x002329,0x00232a},{0x0023e9,0x0023ec},{0x0023f0,0x0023f0},{0x0023f3,0x0023f3},{0x0025fd,0x0025fe},{0x002614,0x002615}, {0x002648,0x002653},{0x00267f,0x00267f},{0x002693,0x002693},{0x0026a1,0x0026a1},{0x0026aa,0x0026ab},{0x0026bd,0x0026be},{0x0026c4,0x0026c5},{0x0026ce,0x0026ce}, {0x0026d4,0x0026d4},{0x0026ea,0x0026ea},{0x0026f2,0x0026f3},{0x0026f5,0x0026f5},{0x0026fa,0x0026fa},{0x0026fd,0x0026fd},{0x002705,0x002705},{0x00270a,0x00270b}, {0x002728,0x002728},{0x00274c,0x00274c},{0x00274e,0x00274e},{0x002753,0x002755},{0x002757,0x002757},{0x002795,0x002797},{0x0027b0,0x0027b0},{0x0027bf,0x0027bf}, {0x002b1b,0x002b1c},{0x002b50,0x002b50},{0x002b55,0x002b55},{0x002e80,0x002e99},{0x002e9b,0x002ef3},{0x002f00,0x002fd5},{0x002ff0,0x002ffb},{0x003000,0x003029}, {0x00302e,0x00303e},{0x003041,0x003096},{0x00309b,0x0030ff},{0x003105,0x00312f},{0x003131,0x00318e},{0x003190,0x0031ba},{0x0031c0,0x0031e3},{0x0031f0,0x00321e}, {0x003220,0x003247},{0x003250,0x0032fe},{0x003300,0x004dbf},{0x004e00,0x00a48c},{0x00a490,0x00a4c6},{0x00a960,0x00a97c},{0x00ac00,0x00d7a3},{0x00f900,0x00faff}, {0x00fe10,0x00fe19},{0x00fe30,0x00fe52},{0x00fe54,0x00fe66},{0x00fe68,0x00fe6b},{0x00ff01,0x00ff60},{0x00ffe0,0x00ffe6},{0x016fe0,0x016fe1},{0x017000,0x0187f1}, {0x018800,0x018af2},{0x01b000,0x01b11e},{0x01b170,0x01b2fb},{0x01f004,0x01f004},{0x01f0cf,0x01f0cf},{0x01f18e,0x01f18e},{0x01f191,0x01f19a},{0x01f1e6,0x01f202}, {0x01f210,0x01f23b},{0x01f240,0x01f248},{0x01f250,0x01f251},{0x01f260,0x01f265},{0x01f300,0x01f320},{0x01f32d,0x01f335},{0x01f337,0x01f37c},{0x01f37e,0x01f393}, {0x01f3a0,0x01f3ca},{0x01f3cf,0x01f3d3},{0x01f3e0,0x01f3f0},{0x01f3f4,0x01f3f4},{0x01f3f8,0x01f43e},{0x01f440,0x01f440},{0x01f442,0x01f4fc},{0x01f4ff,0x01f53d}, {0x01f54b,0x01f54e},{0x01f550,0x01f567},{0x01f57a,0x01f57a},{0x01f595,0x01f596},{0x01f5a4,0x01f5a4},{0x01f5fb,0x01f64f},{0x01f680,0x01f6c5},{0x01f6cc,0x01f6cc}, {0x01f6d0,0x01f6d2},{0x01f6eb,0x01f6ec},{0x01f6f4,0x01f6f9},{0x01f910,0x01f93e},{0x01f940,0x01f970},{0x01f973,0x01f976},{0x01f97a,0x01f97a},{0x01f97c,0x01f9a2}, {0x01f9b0,0x01f9b9},{0x01f9c0,0x01f9c2},{0x01f9d0,0x01f9ff},{0x020000,0x02fffd},{0x030000,0x03fffd}, }; // GB18030字体特定字符宽度 static constexpr const Range LUT_2_GB18030[] = { {0x000007, 0x000007}, {0x00000d, 0x00000d}, {0x00001b, 0x00001b}, {0x000020, 0x000020}, {0x000024, 0x000024}, {0x00002d, 0x00002d}, {0x00002f, 0x000034}, {0x00003a, 0x00003b}, {0x000040, 0x000040}, {0x000043, 0x000044}, {0x000050, 0x000050}, {0x00005b, 0x00005b}, {0x00005d, 0x00005d}, {0x000061, 0x000062}, {0x000064, 0x000065}, {0x000067, 0x000069}, {0x00006b, 0x000070}, {0x000072, 0x000075}, {0x000077, 0x000077}, {0x00007e, 0x00007e}, {0x0000a4, 0x0000a4}, {0x0000a7, 0x0000a8}, {0x0000b0, 0x0000b1}, {0x0000b7, 0x0000b7}, {0x0000d7, 0x0000d7}, {0x0000e0, 0x0000e1}, {0x0000e8, 0x0000ea}, {0x0000ec, 0x0000ed}, {0x0000f2, 0x0000f3}, {0x0000f7, 0x0000f7}, {0x0000f9, 0x0000fa}, {0x0000fc, 0x0000fc}, {0x000101, 0x000101}, {0x000113, 0x000113}, {0x00011b, 0x00011b}, {0x00012b, 0x00012b}, {0x000144, 0x000144}, {0x000148, 0x000148}, {0x00014d, 0x00014d}, {0x00016b, 0x00016b}, {0x0001ce, 0x0001ce}, {0x0001d0, 0x0001d0}, {0x0001d2, 0x0001d2}, {0x0001d4, 0x0001d4}, {0x0001d6, 0x0001d6}, {0x0001d8, 0x0001d8}, {0x0001da, 0x0001da}, {0x0001dc, 0x0001dc}, {0x0001f9, 0x0001f9}, {0x000251, 0x000251}, {0x000261, 0x000261}, {0x0002c7, 0x0002c7}, {0x0002c9, 0x0002cb}, {0x0002d9, 0x0002d9}, {0x000391, 0x0003a1}, {0x0003a3, 0x0003a9}, {0x0003b1, 0x0003c1}, {0x0003c3, 0x0003c9}, {0x000401, 0x000401}, {0x000410, 0x00044f}, {0x000451, 0x000451}, {0x001100, 0x00115f}, {0x001e3f, 0x001e3f}, {0x002010, 0x002010}, {0x002013, 0x002016}, {0x002018, 0x002019}, {0x00201c, 0x00201d}, {0x002025, 0x002026}, {0x002030, 0x002030}, {0x002032, 0x002033}, {0x002035, 0x002035}, {0x00203b, 0x00203b}, {0x0020ac, 0x0020ac}, {0x002103, 0x002103}, {0x002105, 0x002105}, {0x002109, 0x002109}, {0x002116, 0x002116}, {0x002121, 0x002121}, {0x002160, 0x00216b}, {0x002170, 0x002179}, {0x002190, 0x002193}, {0x002196, 0x002199}, {0x002208, 0x002208}, {0x00220f, 0x00220f}, {0x002211, 0x002211}, {0x002215, 0x002215}, {0x00221a, 0x00221a}, {0x00221d, 0x002220}, {0x002223, 0x002223}, {0x002225, 0x002225}, {0x002227, 0x00222b}, {0x00222e, 0x00222e}, {0x002234, 0x002237}, {0x00223d, 0x00223d}, {0x002248, 0x002248}, {0x00224c, 0x00224c}, {0x002252, 0x002252}, {0x002260, 0x002261}, {0x002264, 0x002267}, {0x00226e, 0x00226f}, {0x002295, 0x002295}, {0x002299, 0x002299}, {0x0022a5, 0x0022a5}, {0x0022bf, 0x0022bf}, {0x002312, 0x002312}, {0x00231a, 0x00231b}, {0x002329, 0x00232a}, {0x0023e9, 0x0023ec}, {0x0023f0, 0x0023f0}, {0x0023f3, 0x0023f3}, {0x002460, 0x002469}, {0x002474, 0x00249b}, {0x002500, 0x00254b}, {0x002550, 0x002573}, {0x002581, 0x00258f}, {0x002593, 0x002595}, {0x0025a0, 0x0025a1}, {0x0025b2, 0x0025b3}, {0x0025bc, 0x0025bd}, {0x0025c6, 0x0025c7}, {0x0025cb, 0x0025cb}, {0x0025ce, 0x0025cf}, {0x0025e2, 0x0025e5}, {0x0025fd, 0x0025fe}, {0x002605, 0x002606}, {0x002609, 0x002609}, {0x002614, 0x002615}, {0x002640, 0x002640}, {0x002642, 0x002642}, {0x002648, 0x002653}, {0x00267f, 0x00267f}, {0x002693, 0x002693}, {0x0026a1, 0x0026a1}, {0x0026aa, 0x0026ab}, {0x0026bd, 0x0026be}, {0x0026c4, 0x0026c5}, {0x0026ce, 0x0026ce}, {0x0026d4, 0x0026d4}, {0x0026ea, 0x0026ea}, {0x0026f2, 0x0026f3}, {0x0026f5, 0x0026f5}, {0x0026fa, 0x0026fa}, {0x0026fd, 0x0026fd}, {0x002705, 0x002705}, {0x00270a, 0x00270b}, {0x002728, 0x002728}, {0x00274c, 0x00274c}, {0x00274e, 0x00274e}, {0x002753, 0x002755}, {0x002757, 0x002757}, {0x002795, 0x002797}, {0x0027b0, 0x0027b0}, {0x0027bf, 0x0027bf}, {0x002b1b, 0x002b1c}, {0x002b50, 0x002b50}, {0x002b55, 0x002b55}, {0x002e80, 0x002e99}, {0x002e9b, 0x002ef3}, {0x002f00, 0x002fd5}, {0x002ff0, 0x002ffb}, {0x003000, 0x003029}, {0x00302e, 0x00303e}, {0x003041, 0x003096}, {0x00309b, 0x0030ff}, {0x003105, 0x00312f}, {0x003131, 0x00318e}, {0x003190, 0x0031ba}, {0x0031c0, 0x0031e3}, {0x0031f0, 0x00321e}, {0x003220, 0x003247}, {0x003250, 0x0032fe}, {0x003300, 0x004dbf}, {0x004e00, 0x00a48c}, {0x00a490, 0x00a4c6}, {0x00a960, 0x00a97c}, {0x00ac00, 0x00d7a3}, {0x00e766, 0x00e76b}, {0x00e76d, 0x00e78c}, {0x00e797, 0x00e7c6}, {0x00e7c9, 0x00e7e6}, {0x00e7f4, 0x00e80f}, {0x00f900, 0x00faff}, {0x00fe10, 0x00fe19}, {0x00fe30, 0x00fe52}, {0x00fe54, 0x00fe66}, {0x00fe68, 0x00fe6b}, {0x00ff01, 0x00ff60}, {0x00ffe0, 0x00ffe6}, {0x016fe0, 0x016fe1}, {0x017000, 0x0187f1}, {0x018800, 0x018af2}, {0x01b000, 0x01b11e}, {0x01b170, 0x01b2fb}, {0x01f004, 0x01f004}, {0x01f0cf, 0x01f0cf}, {0x01f18e, 0x01f18e}, {0x01f191, 0x01f19a}, {0x01f1e6, 0x01f202}, {0x01f210, 0x01f23b}, {0x01f240, 0x01f248}, {0x01f250, 0x01f251}, {0x01f260, 0x01f265}, {0x01f300, 0x01f320}, {0x01f32d, 0x01f335}, {0x01f337, 0x01f37c}, {0x01f37e, 0x01f393}, {0x01f3a0, 0x01f3ca}, {0x01f3cf, 0x01f3d3}, {0x01f3e0, 0x01f3f0}, {0x01f3f4, 0x01f3f4}, {0x01f3f8, 0x01f43e}, {0x01f440, 0x01f440}, {0x01f442, 0x01f4fc}, {0x01f4ff, 0x01f53d}, {0x01f54b, 0x01f54e}, {0x01f550, 0x01f567}, {0x01f57a, 0x01f57a}, {0x01f595, 0x01f596}, {0x01f5a4, 0x01f5a4}, {0x01f5fb, 0x01f64f}, {0x01f680, 0x01f6c5}, {0x01f6cc, 0x01f6cc}, {0x01f6d0, 0x01f6d2}, {0x01f6eb, 0x01f6ec}, {0x01f6f4, 0x01f6f9}, {0x01f910, 0x01f93e}, {0x01f940, 0x01f970}, {0x01f973, 0x01f976}, {0x01f97a, 0x01f97a}, {0x01f97c, 0x01f9a2}, {0x01f9b0, 0x01f9b9}, {0x01f9c0, 0x01f9c2}, {0x01f9d0, 0x01f9ff}, {0x020000, 0x029b46}, {0x029b48, 0x02fffd},{0x030000, 0x03fffd}, }; static constexpr const Range LUT_0[] = { {0x000300,0x00036f},{0x000483,0x000489},{0x000591,0x0005bd},{0x0005bf,0x0005bf},{0x0005c1,0x0005c2},{0x0005c4,0x0005c5},{0x0005c7,0x0005c7},{0x000600,0x000605}, {0x000610,0x00061a},{0x00061c,0x00061c},{0x00064b,0x00065f},{0x000670,0x000670},{0x0006d6,0x0006dd},{0x0006df,0x0006e4},{0x0006e7,0x0006e8},{0x0006ea,0x0006ed}, {0x00070f,0x00070f},{0x000711,0x000711},{0x000730,0x00074a},{0x0007a6,0x0007b0},{0x0007eb,0x0007f3},{0x0007fd,0x0007fd},{0x000816,0x000819},{0x00081b,0x000823}, {0x000825,0x000827},{0x000829,0x00082d},{0x000859,0x00085b},{0x0008d3,0x000902},{0x00093a,0x00093a},{0x00093c,0x00093c},{0x000941,0x000948},{0x00094d,0x00094d}, {0x000951,0x000957},{0x000962,0x000963},{0x000981,0x000981},{0x0009bc,0x0009bc},{0x0009c1,0x0009c4},{0x0009cd,0x0009cd},{0x0009e2,0x0009e3},{0x0009fe,0x0009fe}, {0x000a01,0x000a02},{0x000a3c,0x000a3c},{0x000a41,0x000a42},{0x000a47,0x000a48},{0x000a4b,0x000a4d},{0x000a51,0x000a51},{0x000a70,0x000a71},{0x000a75,0x000a75}, {0x000a81,0x000a82},{0x000abc,0x000abc},{0x000ac1,0x000ac5},{0x000ac7,0x000ac8},{0x000acd,0x000acd},{0x000ae2,0x000ae3},{0x000afa,0x000aff},{0x000b01,0x000b01}, {0x000b3c,0x000b3c},{0x000b3f,0x000b3f},{0x000b41,0x000b44},{0x000b4d,0x000b4d},{0x000b56,0x000b56},{0x000b62,0x000b63},{0x000b82,0x000b82},{0x000bc0,0x000bc0}, {0x000bcd,0x000bcd},{0x000c00,0x000c00},{0x000c04,0x000c04},{0x000c3e,0x000c40},{0x000c46,0x000c48},{0x000c4a,0x000c4d},{0x000c55,0x000c56},{0x000c62,0x000c63}, {0x000c81,0x000c81},{0x000cbc,0x000cbc},{0x000cbf,0x000cbf},{0x000cc6,0x000cc6},{0x000ccc,0x000ccd},{0x000ce2,0x000ce3},{0x000d00,0x000d01},{0x000d3b,0x000d3c}, {0x000d41,0x000d44},{0x000d4d,0x000d4d},{0x000d62,0x000d63},{0x000dca,0x000dca},{0x000dd2,0x000dd4},{0x000dd6,0x000dd6},{0x000e31,0x000e31},{0x000e34,0x000e3a}, {0x000e47,0x000e4e},{0x000eb1,0x000eb1},{0x000eb4,0x000eb9},{0x000ebb,0x000ebc},{0x000ec8,0x000ecd},{0x000f18,0x000f19},{0x000f35,0x000f35},{0x000f37,0x000f37}, {0x000f39,0x000f39},{0x000f71,0x000f7e},{0x000f80,0x000f84},{0x000f86,0x000f87},{0x000f8d,0x000f97},{0x000f99,0x000fbc},{0x000fc6,0x000fc6},{0x00102d,0x001030}, {0x001032,0x001037},{0x001039,0x00103a},{0x00103d,0x00103e},{0x001058,0x001059},{0x00105e,0x001060},{0x001071,0x001074},{0x001082,0x001082},{0x001085,0x001086}, {0x00108d,0x00108d},{0x00109d,0x00109d},{0x001160,0x001160},{0x00135d,0x00135f},{0x001712,0x001714},{0x001732,0x001734},{0x001752,0x001753},{0x001772,0x001773}, {0x0017b4,0x0017b5},{0x0017b7,0x0017bd},{0x0017c6,0x0017c6},{0x0017c9,0x0017d3},{0x0017dd,0x0017dd},{0x00180b,0x00180e},{0x001885,0x001886},{0x0018a9,0x0018a9}, {0x001920,0x001922},{0x001927,0x001928},{0x001932,0x001932},{0x001939,0x00193b},{0x001a17,0x001a18},{0x001a1b,0x001a1b},{0x001a56,0x001a56},{0x001a58,0x001a5e}, {0x001a60,0x001a60},{0x001a62,0x001a62},{0x001a65,0x001a6c},{0x001a73,0x001a7c},{0x001a7f,0x001a7f},{0x001ab0,0x001abe},{0x001b00,0x001b03},{0x001b34,0x001b34}, {0x001b36,0x001b3a},{0x001b3c,0x001b3c},{0x001b42,0x001b42},{0x001b6b,0x001b73},{0x001b80,0x001b81},{0x001ba2,0x001ba5},{0x001ba8,0x001ba9},{0x001bab,0x001bad}, {0x001be6,0x001be6},{0x001be8,0x001be9},{0x001bed,0x001bed},{0x001bef,0x001bf1},{0x001c2c,0x001c33},{0x001c36,0x001c37},{0x001cd0,0x001cd2},{0x001cd4,0x001ce0}, {0x001ce2,0x001ce8},{0x001ced,0x001ced},{0x001cf4,0x001cf4},{0x001cf8,0x001cf9},{0x001dc0,0x001df9},{0x001dfb,0x001dff},{0x00200b,0x00200f},{0x00202a,0x00202e}, {0x002060,0x002064},{0x002066,0x00206f},{0x0020d0,0x0020f0},{0x002cef,0x002cf1},{0x002d7f,0x002d7f},{0x002de0,0x002dff},{0x00302a,0x00302d},{0x003099,0x00309a}, {0x00a66f,0x00a672},{0x00a674,0x00a67d},{0x00a69e,0x00a69f},{0x00a6f0,0x00a6f1},{0x00a802,0x00a802},{0x00a806,0x00a806},{0x00a80b,0x00a80b},{0x00a825,0x00a826}, {0x00a8c4,0x00a8c5},{0x00a8e0,0x00a8f1},{0x00a8ff,0x00a8ff},{0x00a926,0x00a92d},{0x00a947,0x00a951},{0x00a980,0x00a982},{0x00a9b3,0x00a9b3},{0x00a9b6,0x00a9b9}, {0x00a9bc,0x00a9bc},{0x00a9e5,0x00a9e5},{0x00aa29,0x00aa2e},{0x00aa31,0x00aa32},{0x00aa35,0x00aa36},{0x00aa43,0x00aa43},{0x00aa4c,0x00aa4c},{0x00aa7c,0x00aa7c}, {0x00aab0,0x00aab0},{0x00aab2,0x00aab4},{0x00aab7,0x00aab8},{0x00aabe,0x00aabf},{0x00aac1,0x00aac1},{0x00aaec,0x00aaed},{0x00aaf6,0x00aaf6},{0x00abe5,0x00abe5}, {0x00abe8,0x00abe8},{0x00abed,0x00abed},{0x00fb1e,0x00fb1e},{0x00fe00,0x00fe0f},{0x00fe20,0x00fe2f},{0x00feff,0x00feff},{0x00fff9,0x00fffb},{0x0101fd,0x0101fd}, {0x0102e0,0x0102e0},{0x010376,0x01037a},{0x010a01,0x010a03},{0x010a05,0x010a06},{0x010a0c,0x010a0f},{0x010a38,0x010a3a},{0x010a3f,0x010a3f},{0x010ae5,0x010ae6}, {0x010d24,0x010d27},{0x010f46,0x010f50},{0x011001,0x011001},{0x011038,0x011046},{0x01107f,0x011081},{0x0110b3,0x0110b6},{0x0110b9,0x0110ba},{0x0110bd,0x0110bd}, {0x0110cd,0x0110cd},{0x011100,0x011102},{0x011127,0x01112b},{0x01112d,0x011134},{0x011173,0x011173},{0x011180,0x011181},{0x0111b6,0x0111be},{0x0111c9,0x0111cc}, {0x01122f,0x011231},{0x011234,0x011234},{0x011236,0x011237},{0x01123e,0x01123e},{0x0112df,0x0112df},{0x0112e3,0x0112ea},{0x011300,0x011301},{0x01133b,0x01133c}, {0x011340,0x011340},{0x011366,0x01136c},{0x011370,0x011374},{0x011438,0x01143f},{0x011442,0x011444},{0x011446,0x011446},{0x01145e,0x01145e},{0x0114b3,0x0114b8}, {0x0114ba,0x0114ba},{0x0114bf,0x0114c0},{0x0114c2,0x0114c3},{0x0115b2,0x0115b5},{0x0115bc,0x0115bd},{0x0115bf,0x0115c0},{0x0115dc,0x0115dd},{0x011633,0x01163a}, {0x01163d,0x01163d},{0x01163f,0x011640},{0x0116ab,0x0116ab},{0x0116ad,0x0116ad},{0x0116b0,0x0116b5},{0x0116b7,0x0116b7},{0x01171d,0x01171f},{0x011722,0x011725}, {0x011727,0x01172b},{0x01182f,0x011837},{0x011839,0x01183a},{0x011a01,0x011a0a},{0x011a33,0x011a38},{0x011a3b,0x011a3e},{0x011a47,0x011a47},{0x011a51,0x011a56}, {0x011a59,0x011a5b},{0x011a8a,0x011a96},{0x011a98,0x011a99},{0x011c30,0x011c36},{0x011c38,0x011c3d},{0x011c3f,0x011c3f},{0x011c92,0x011ca7},{0x011caa,0x011cb0}, {0x011cb2,0x011cb3},{0x011cb5,0x011cb6},{0x011d31,0x011d36},{0x011d3a,0x011d3a},{0x011d3c,0x011d3d},{0x011d3f,0x011d45},{0x011d47,0x011d47},{0x011d90,0x011d91}, {0x011d95,0x011d95},{0x011d97,0x011d97},{0x011ef3,0x011ef4},{0x016af0,0x016af4},{0x016b30,0x016b36},{0x016f8f,0x016f92},{0x01bc9d,0x01bc9e},{0x01bca0,0x01bca3}, {0x01d167,0x01d169},{0x01d173,0x01d182},{0x01d185,0x01d18b},{0x01d1aa,0x01d1ad},{0x01d242,0x01d244},{0x01da00,0x01da36},{0x01da3b,0x01da6c},{0x01da75,0x01da75}, {0x01da84,0x01da84},{0x01da9b,0x01da9f},{0x01daa1,0x01daaf},{0x01e000,0x01e006},{0x01e008,0x01e018},{0x01e01b,0x01e021},{0x01e023,0x01e024},{0x01e026,0x01e02a}, {0x01e8d0,0x01e8d6},{0x01e944,0x01e94a},{0x0e0001,0x0e0001},{0x0e0020,0x0e007f},{0x0e0100,0x0e01ef}, }; static constexpr const RangeLut RANGE_LUT_LIST[] = { {-1, LUT_NONPRINTABLE, 1}, // size is the range vector count. { 2, LUT_2 , 109}, { 0, LUT_0 , 325}, { 1, nullptr , 1}, }; static constexpr const RangeLut RANGE_LUT_LIST_GB18030[] = { {-1, LUT_NONPRINTABLE, 1}, // size is the range vector count. { 2, LUT_2_GB18030 , 234}, { 0, LUT_0 , 325}, { 1, nullptr , 1}, }; static constexpr const int RANGE_LUT_LIST_SIZE = 4; static bool m_isCodecGB18030 = false; void setIsCodecGB18030(bool isCodecGB18030) { m_isCodecGB18030 = isCodecGB18030; } bool IsCodecGB18030(){ return m_isCodecGB18030; } int characterWidth(uint ucs4) { if (m_isCodecGB18030) { if(Q_LIKELY(ucs4 < sizeof(DIRECT_LUT_GB18030))) { return DIRECT_LUT_GB18030[ucs4]; } for(auto rl = RANGE_LUT_LIST_GB18030; rl->lut != nullptr; ++rl) { int l = 0; int r = rl->size - 1; while(l <= r) { const int m = (l + r) / 2; if(rl->lut[m].last < ucs4) { l = m + 1; } else if(rl->lut[m].first > ucs4) { r = m - 1; } else { return rl->width; } } } return RANGE_LUT_LIST_GB18030[RANGE_LUT_LIST_SIZE - 1].width; }else{ if(Q_LIKELY(ucs4 < sizeof(DIRECT_LUT))) { return DIRECT_LUT[ucs4]; } for(auto rl = RANGE_LUT_LIST; rl->lut != nullptr; ++rl) { int l = 0; int r = rl->size - 1; while(l <= r) { const int m = (l + r) / 2; if(rl->lut[m].last < ucs4) { l = m + 1; } else if(rl->lut[m].first > ucs4) { r = m - 1; } else { return rl->width; } } } return RANGE_LUT_LIST[RANGE_LUT_LIST_SIZE - 1].width; } } namespace Konsole { namespace LineBlockCharacters { enum LineType { LtNone = 0, LtDouble = 1, LtLight = 2, LtHeavy = 3 }; // PackedLineTypes is an 8-bit number representing types of 4 line character's lines. Each line is // represented by 2 bits. Lines order, starting from MSB: top, right, bottom, left. static inline constexpr quint8 makePackedLineTypes(LineType top, LineType right, LineType bottom, LineType left) { return (int(top) & 3) << 6 | (int(right) & 3) << 4 | (int(bottom) & 3) << 2 | (int(left) & 3); } static constexpr const quint8 PackedLineTypesLut[] = { // top right bottom left makePackedLineTypes(LtNone , LtLight , LtNone , LtLight ), /* U+2500 ─ */ makePackedLineTypes(LtNone , LtHeavy , LtNone , LtHeavy ), /* U+2501 ━ */ makePackedLineTypes(LtLight , LtNone , LtLight , LtNone ), /* U+2502 │ */ makePackedLineTypes(LtHeavy , LtNone , LtHeavy , LtNone ), /* U+2503 ┃ */ 0, 0, 0, 0, 0, 0, 0, 0, /* U+2504-0x250b */ makePackedLineTypes(LtNone , LtLight , LtLight , LtNone ), /* U+250C ┌ */ makePackedLineTypes(LtNone , LtHeavy , LtLight , LtNone ), /* U+250D ┍ */ makePackedLineTypes(LtNone , LtLight , LtHeavy , LtNone ), /* U+250E ┎ */ makePackedLineTypes(LtNone , LtHeavy , LtHeavy , LtNone ), /* U+250F ┏ */ makePackedLineTypes(LtNone , LtNone , LtLight , LtLight ), /* U+2510 ┐ */ makePackedLineTypes(LtNone , LtNone , LtLight , LtHeavy ), /* U+2511 ┑ */ makePackedLineTypes(LtNone , LtNone , LtHeavy , LtLight ), /* U+2512 ┒ */ makePackedLineTypes(LtNone , LtNone , LtHeavy , LtHeavy ), /* U+2513 ┓ */ makePackedLineTypes(LtLight , LtLight , LtNone , LtNone ), /* U+2514 └ */ makePackedLineTypes(LtLight , LtHeavy , LtNone , LtNone ), /* U+2515 ┕ */ makePackedLineTypes(LtHeavy , LtLight , LtNone , LtNone ), /* U+2516 ┖ */ makePackedLineTypes(LtHeavy , LtHeavy , LtNone , LtNone ), /* U+2517 ┗ */ makePackedLineTypes(LtLight , LtNone , LtNone , LtLight ), /* U+2518 ┘ */ makePackedLineTypes(LtLight , LtNone , LtNone , LtHeavy ), /* U+2519 ┙ */ makePackedLineTypes(LtHeavy , LtNone , LtNone , LtLight ), /* U+251A ┚ */ makePackedLineTypes(LtHeavy , LtNone , LtNone , LtHeavy ), /* U+251B ┛ */ makePackedLineTypes(LtLight , LtLight , LtLight , LtNone ), /* U+251C ├ */ makePackedLineTypes(LtLight , LtHeavy , LtLight , LtNone ), /* U+251D ┝ */ makePackedLineTypes(LtHeavy , LtLight , LtLight , LtNone ), /* U+251E ┞ */ makePackedLineTypes(LtLight , LtLight , LtHeavy , LtNone ), /* U+251F ┟ */ makePackedLineTypes(LtHeavy , LtLight , LtHeavy , LtNone ), /* U+2520 ┠ */ makePackedLineTypes(LtHeavy , LtHeavy , LtLight , LtNone ), /* U+2521 ┡ */ makePackedLineTypes(LtLight , LtHeavy , LtHeavy , LtNone ), /* U+2522 ┢ */ makePackedLineTypes(LtHeavy , LtHeavy , LtHeavy , LtNone ), /* U+2523 ┣ */ makePackedLineTypes(LtLight , LtNone , LtLight , LtLight ), /* U+2524 ┤ */ makePackedLineTypes(LtLight , LtNone , LtLight , LtHeavy ), /* U+2525 ┥ */ makePackedLineTypes(LtHeavy , LtNone , LtLight , LtLight ), /* U+2526 ┦ */ makePackedLineTypes(LtLight , LtNone , LtHeavy , LtLight ), /* U+2527 ┧ */ makePackedLineTypes(LtHeavy , LtNone , LtHeavy , LtLight ), /* U+2528 ┨ */ makePackedLineTypes(LtHeavy , LtNone , LtLight , LtHeavy ), /* U+2529 ┩ */ makePackedLineTypes(LtLight , LtNone , LtHeavy , LtHeavy ), /* U+252A ┪ */ makePackedLineTypes(LtHeavy , LtNone , LtHeavy , LtHeavy ), /* U+252B ┫ */ makePackedLineTypes(LtNone , LtLight , LtLight , LtLight ), /* U+252C ┬ */ makePackedLineTypes(LtNone , LtLight , LtLight , LtHeavy ), /* U+252D ┭ */ makePackedLineTypes(LtNone , LtHeavy , LtLight , LtLight ), /* U+252E ┮ */ makePackedLineTypes(LtNone , LtHeavy , LtLight , LtHeavy ), /* U+252F ┯ */ makePackedLineTypes(LtNone , LtLight , LtHeavy , LtLight ), /* U+2530 ┰ */ makePackedLineTypes(LtNone , LtLight , LtHeavy , LtHeavy ), /* U+2531 ┱ */ makePackedLineTypes(LtNone , LtHeavy , LtHeavy , LtLight ), /* U+2532 ┲ */ makePackedLineTypes(LtNone , LtHeavy , LtHeavy , LtHeavy ), /* U+2533 ┳ */ makePackedLineTypes(LtLight , LtLight , LtNone , LtLight ), /* U+2534 ┴ */ makePackedLineTypes(LtLight , LtLight , LtNone , LtHeavy ), /* U+2535 ┵ */ makePackedLineTypes(LtLight , LtHeavy , LtNone , LtLight ), /* U+2536 ┶ */ makePackedLineTypes(LtLight , LtHeavy , LtNone , LtHeavy ), /* U+2537 ┷ */ makePackedLineTypes(LtHeavy , LtLight , LtNone , LtLight ), /* U+2538 ┸ */ makePackedLineTypes(LtHeavy , LtLight , LtNone , LtHeavy ), /* U+2539 ┹ */ makePackedLineTypes(LtHeavy , LtHeavy , LtNone , LtLight ), /* U+253A ┺ */ makePackedLineTypes(LtHeavy , LtHeavy , LtNone , LtHeavy ), /* U+253B ┻ */ makePackedLineTypes(LtLight , LtLight , LtLight , LtLight ), /* U+253C ┼ */ makePackedLineTypes(LtLight , LtLight , LtLight , LtHeavy ), /* U+253D ┽ */ makePackedLineTypes(LtLight , LtHeavy , LtLight , LtLight ), /* U+253E ┾ */ makePackedLineTypes(LtLight , LtHeavy , LtLight , LtHeavy ), /* U+253F ┿ */ makePackedLineTypes(LtHeavy , LtLight , LtLight , LtLight ), /* U+2540 ╀ */ makePackedLineTypes(LtLight , LtLight , LtHeavy , LtLight ), /* U+2541 ╁ */ makePackedLineTypes(LtHeavy , LtLight , LtHeavy , LtLight ), /* U+2542 ╂ */ makePackedLineTypes(LtHeavy , LtLight , LtLight , LtHeavy ), /* U+2543 ╃ */ makePackedLineTypes(LtHeavy , LtHeavy , LtLight , LtLight ), /* U+2544 ╄ */ makePackedLineTypes(LtLight , LtLight , LtHeavy , LtHeavy ), /* U+2545 ╅ */ makePackedLineTypes(LtLight , LtHeavy , LtHeavy , LtLight ), /* U+2546 ╆ */ makePackedLineTypes(LtHeavy , LtHeavy , LtLight , LtHeavy ), /* U+2547 ╇ */ makePackedLineTypes(LtLight , LtHeavy , LtHeavy , LtHeavy ), /* U+2548 ╈ */ makePackedLineTypes(LtHeavy , LtLight , LtHeavy , LtHeavy ), /* U+2549 ╉ */ makePackedLineTypes(LtHeavy , LtHeavy , LtHeavy , LtLight ), /* U+254A ╊ */ makePackedLineTypes(LtHeavy , LtHeavy , LtHeavy , LtHeavy ), /* U+254B ╋ */ 0, 0, 0, 0, /* U+254C - U+254F */ makePackedLineTypes(LtNone , LtDouble, LtNone , LtDouble), /* U+2550 ═ */ makePackedLineTypes(LtDouble, LtNone , LtDouble, LtNone ), /* U+2551 ║ */ makePackedLineTypes(LtNone , LtDouble, LtLight , LtNone ), /* U+2552 ╒ */ makePackedLineTypes(LtNone , LtLight , LtDouble, LtNone ), /* U+2553 ╓ */ makePackedLineTypes(LtNone , LtDouble, LtDouble, LtNone ), /* U+2554 ╔ */ makePackedLineTypes(LtNone , LtNone , LtLight , LtDouble), /* U+2555 ╕ */ makePackedLineTypes(LtNone , LtNone , LtDouble, LtLight ), /* U+2556 ╖ */ makePackedLineTypes(LtNone , LtNone , LtDouble, LtDouble), /* U+2557 ╗ */ makePackedLineTypes(LtLight , LtDouble, LtNone , LtNone ), /* U+2558 ╘ */ makePackedLineTypes(LtDouble, LtLight , LtNone , LtNone ), /* U+2559 ╙ */ makePackedLineTypes(LtDouble, LtDouble, LtNone , LtNone ), /* U+255A ╚ */ makePackedLineTypes(LtLight , LtNone , LtNone , LtDouble), /* U+255B ╛ */ makePackedLineTypes(LtDouble, LtNone , LtNone , LtLight ), /* U+255C ╜ */ makePackedLineTypes(LtDouble, LtNone , LtNone , LtDouble), /* U+255D ╝ */ makePackedLineTypes(LtLight , LtDouble, LtLight , LtNone ), /* U+255E ╞ */ makePackedLineTypes(LtDouble, LtLight , LtDouble, LtNone ), /* U+255F ╟ */ makePackedLineTypes(LtDouble, LtDouble, LtDouble, LtNone ), /* U+2560 ╠ */ makePackedLineTypes(LtLight , LtNone , LtLight , LtDouble), /* U+2561 ╡ */ makePackedLineTypes(LtDouble, LtNone , LtDouble, LtLight ), /* U+2562 ╢ */ makePackedLineTypes(LtDouble, LtNone , LtDouble, LtDouble), /* U+2563 ╣ */ makePackedLineTypes(LtNone , LtDouble, LtLight , LtDouble), /* U+2564 ╤ */ makePackedLineTypes(LtNone , LtLight , LtDouble, LtLight ), /* U+2565 ╥ */ makePackedLineTypes(LtNone , LtDouble, LtDouble, LtDouble), /* U+2566 ╦ */ makePackedLineTypes(LtLight , LtDouble, LtNone , LtDouble), /* U+2567 ╧ */ makePackedLineTypes(LtDouble, LtLight , LtNone , LtLight ), /* U+2568 ╨ */ makePackedLineTypes(LtDouble, LtDouble, LtNone , LtDouble), /* U+2569 ╩ */ makePackedLineTypes(LtLight , LtDouble, LtLight , LtDouble), /* U+256A ╪ */ makePackedLineTypes(LtDouble, LtLight , LtDouble, LtLight ), /* U+256B ╫ */ makePackedLineTypes(LtDouble, LtDouble, LtDouble, LtDouble), /* U+256C ╬ */ 0, 0, 0, 0, 0, 0, 0, /* U+256D - U+2573 */ makePackedLineTypes(LtNone , LtNone , LtNone , LtLight ), /* U+2574 ╴ */ makePackedLineTypes(LtLight , LtNone , LtNone , LtNone ), /* U+2575 ╵ */ makePackedLineTypes(LtNone , LtLight , LtNone , LtNone ), /* U+2576 ╶ */ makePackedLineTypes(LtNone , LtNone , LtLight , LtNone ), /* U+2577 ╷ */ makePackedLineTypes(LtNone , LtNone , LtNone , LtHeavy ), /* U+2578 ╸ */ makePackedLineTypes(LtHeavy , LtNone , LtNone , LtNone ), /* U+2579 ╹ */ makePackedLineTypes(LtNone , LtHeavy , LtNone , LtNone ), /* U+257A ╺ */ makePackedLineTypes(LtNone , LtNone , LtHeavy , LtNone ), /* U+257B ╻ */ makePackedLineTypes(LtNone , LtHeavy , LtNone , LtLight ), /* U+257C ╼ */ makePackedLineTypes(LtLight , LtNone , LtHeavy , LtNone ), /* U+257D ╽ */ makePackedLineTypes(LtNone , LtLight , LtNone , LtHeavy ), /* U+257E ╾ */ makePackedLineTypes(LtHeavy , LtNone , LtLight , LtNone ), /* U+257F ╿ */ }; // Bitwise rotate left template inline static T rotateBitsLeft(T value, quint8 amount) { static_assert (std::is_unsigned(), "T must be unsigned type"); Q_ASSERT(amount < sizeof(value) * 8); return value << amount | value >> (sizeof(value) * 8 - amount); } inline static const QPen pen(const QPainter &paint, uint lineWidth) { return QPen(paint.pen().brush(), lineWidth, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin); } STATIC_METHOD INLINE_METHOD uint lineWidth(uint fontWidth, bool heavy, bool bold) { static const qreal LightWidthToFontWidthRatio = 1.0 / 6.5; static const qreal HeavyHalfExtraToLightRatio = 1.0 / 3.0; static const qreal BoldCoefficient = 1.5; // ▄▄▄▄▄▄▄ } heavyHalfExtraWidth ⎫ // ██████████████ } lightWidth ⎬ heavyWidth // ▀▀▀▀▀▀▀ ⎭ // light heavy const qreal baseWidth = fontWidth * LightWidthToFontWidthRatio; const qreal boldCoeff = bold ? BoldCoefficient : 1.0; // Unless font size is too small, make bold lines at least 1px wider than regular lines const qreal minWidth = bold && fontWidth >= 7 ? baseWidth + 1.0 : 1.0; const uint lightWidth = qRound(qMax(baseWidth * boldCoeff, minWidth)); const uint heavyHalfExtraWidth = qRound(qMax(lightWidth * HeavyHalfExtraToLightRatio, 1.0)); return heavy ? lightWidth + 2 * heavyHalfExtraWidth : lightWidth; } // Draws characters composed of straight solid lines STATIC_METHOD INLINE_METHOD bool drawBasicLineCharacter(QPainter& paint, int x, int y, int w, int h, uchar code, bool bold) { quint8 packedLineTypes = code >= sizeof(PackedLineTypesLut) ? 0 : PackedLineTypesLut[code]; if (packedLineTypes == 0) { return false; } const uint lightLineWidth = lineWidth(w, false, bold); const uint heavyLineWidth = lineWidth(w, true, bold); // Distance from double line's parallel axis to each line's parallel axis const uint doubleLinesDistance = lightLineWidth; const QPen lightPen = pen(paint, lightLineWidth); const QPen heavyPen = pen(paint, heavyLineWidth); static constexpr const unsigned LinesNum = 4; // Pixel aligned center point const QPointF center = { x + int(w/2) + 0.5 * (lightLineWidth % 2), y + int(h/2) + 0.5 * (lightLineWidth % 2), }; // Lines starting points, on the cell edges const QPointF origin[] = { QPointF(center.x(), y ), QPointF(x+w , center.y() ), QPointF(center.x(), y+h ), QPointF(x , center.y() ), }; // Unit vectors with directions from center to the line's origin point static const QPointF dir[] = {{0, -1}, {1, 0}, {0, 1}, {-1, 0}}; const auto removeLineType = [&packedLineTypes](quint8 lineId)->void { lineId = LinesNum - 1 - lineId % LinesNum; packedLineTypes &= ~(3 << (2 * lineId)); }; const auto getLineType = [&packedLineTypes](quint8 lineId)->LineType { lineId = LinesNum - 1 - lineId % LinesNum; return LineType(packedLineTypes >> 2 * lineId & 3); }; QPainterPath lightPath; // PainterPath for light lines (Painter Path Light) QPainterPath heavyPath; // PainterPath for heavy lines (Painter Path Heavy) // Returns ppl or pph depending on line type const auto pathForLine = [&](quint8 lineId) -> QPainterPath& { Q_ASSERT(getLineType(lineId) != LtNone); return getLineType(lineId) == LtHeavy ? heavyPath : lightPath; }; // Process all single up-down/left-right lines for every character that has them. Doing it here // reduces amount of combinations below. // Fully draws: ╋ ╂ ┃ ┿ ┼ │ ━ ─ for (unsigned int topIndex = 0; topIndex < LinesNum/2; topIndex++) { unsigned iB = (topIndex + 2) % LinesNum; const bool isSingleLine = (getLineType(topIndex) == LtLight || getLineType(topIndex) == LtHeavy); if (isSingleLine && getLineType(topIndex) == getLineType(iB)) { pathForLine(topIndex).moveTo(origin[topIndex]); pathForLine(topIndex).lineTo(origin[iB]); removeLineType(topIndex); removeLineType(iB); } } // Find base rotation of a character and map rotated line indices to the original rotation's // indices. The base rotation is defined as the one with largest packedLineTypes value. This way // we can use the same code for drawing 4 possible character rotations (see switch() below) uint topIndex = 0; // index of an original top line in a base rotation quint8 basePackedLineTypes = packedLineTypes; for (uint i = 0; i < LinesNum; i++) { const quint8 rotatedPackedLineTypes = rotateBitsLeft(packedLineTypes, i * 2); if (rotatedPackedLineTypes > basePackedLineTypes) { topIndex = i; basePackedLineTypes = rotatedPackedLineTypes; } } uint rightIndex = (topIndex + 1) % LinesNum; uint bottomIndex = (topIndex + 2) % LinesNum; uint leftIndex = (topIndex + 3) % LinesNum; // Common paths const auto drawDoubleUpRightShorterLine = [&](quint8 top, quint8 right) { // ╚ lightPath.moveTo(origin[top] + dir[right] * doubleLinesDistance); lightPath.lineTo(center + (dir[right] + dir[top]) * doubleLinesDistance); lightPath.lineTo(origin[right] + dir[top] * doubleLinesDistance); }; const auto drawUpRight = [&](quint8 top, quint8 right) { // └┗ pathForLine(top).moveTo(origin[top]); pathForLine(top).lineTo(center); pathForLine(top).lineTo(origin[right]); }; switch (basePackedLineTypes) { case makePackedLineTypes(LtHeavy , LtNone , LtLight , LtNone ): // ╿ ; ╼ ╽ ╾ ╊ ╇ ╉ ╈ ╀ ┾ ╁ ┽ lightPath.moveTo(origin[bottomIndex]); lightPath.lineTo(center + dir[topIndex] * lightLineWidth / 2.0); Q_FALLTHROUGH(); case makePackedLineTypes(LtHeavy , LtNone , LtNone , LtNone ): // ╹ ; ╺ ╻ ╸ ┻ ┣ ┳ ┫ ┸ ┝ ┰ ┥ case makePackedLineTypes(LtLight , LtNone , LtNone , LtNone ): // ╵ ; ╶ ╷ ╴ ┷ ┠ ┯ ┨ ┴ ├ ┬ ┤ pathForLine(topIndex).moveTo(origin[topIndex]); pathForLine(topIndex).lineTo(center); break; case makePackedLineTypes(LtHeavy , LtHeavy , LtLight , LtLight ): // ╄ ; ╃ ╆ ╅ drawUpRight(bottomIndex, leftIndex); Q_FALLTHROUGH(); case makePackedLineTypes(LtHeavy , LtHeavy , LtNone , LtNone ): // ┗ ; ┛ ┏ ┓ case makePackedLineTypes(LtLight , LtLight , LtNone , LtNone ): // └ ; ┘ ┌ ┐ drawUpRight(topIndex, rightIndex); break; case makePackedLineTypes(LtHeavy , LtLight , LtNone , LtNone ): // ┖ ; ┙ ┍ ┒ qSwap(leftIndex, rightIndex); Q_FALLTHROUGH(); case makePackedLineTypes(LtHeavy , LtNone , LtNone , LtLight ): // ┚ ; ┕ ┎ ┑ lightPath.moveTo(origin[leftIndex]); lightPath.lineTo(center); heavyPath.moveTo(origin[topIndex]); heavyPath.lineTo(center + dir[bottomIndex] * lightLineWidth / 2.0); break; case makePackedLineTypes(LtLight , LtDouble, LtNone , LtNone ): // ╘ ; ╜ ╓ ╕ qSwap(leftIndex, rightIndex); Q_FALLTHROUGH(); case makePackedLineTypes(LtLight , LtNone , LtNone , LtDouble): // ╛ ; ╙ ╒ ╖ lightPath.moveTo(origin[topIndex]); lightPath.lineTo(center + dir[bottomIndex] * doubleLinesDistance); lightPath.lineTo(origin[leftIndex] + dir[bottomIndex] * doubleLinesDistance); lightPath.moveTo(origin[leftIndex] - dir[bottomIndex] * doubleLinesDistance); lightPath.lineTo(center - dir[bottomIndex] * doubleLinesDistance); break; case makePackedLineTypes(LtHeavy , LtHeavy , LtLight , LtNone ): // ┡ ; ┹ ┪ ┲ qSwap(leftIndex, bottomIndex); qSwap(rightIndex, topIndex); Q_FALLTHROUGH(); case makePackedLineTypes(LtHeavy , LtHeavy , LtNone , LtLight ): // ┺ ; ┩ ┢ ┱ drawUpRight(topIndex, rightIndex); lightPath.moveTo(origin[leftIndex]); lightPath.lineTo(center); break; case makePackedLineTypes(LtHeavy , LtLight , LtLight , LtNone ): // ┞ ; ┵ ┧ ┮ qSwap(leftIndex, rightIndex); Q_FALLTHROUGH(); case makePackedLineTypes(LtHeavy , LtNone , LtLight , LtLight ): // ┦ ; ┶ ┟ ┭ heavyPath.moveTo(origin[topIndex]); heavyPath.lineTo(center + dir[bottomIndex] * lightLineWidth / 2.0); drawUpRight(bottomIndex, leftIndex); break; case makePackedLineTypes(LtLight , LtDouble, LtNone , LtDouble): // ╧ ; ╟ ╢ ╤ lightPath.moveTo(origin[topIndex]); lightPath.lineTo(center - dir[bottomIndex] * doubleLinesDistance); qSwap(leftIndex, bottomIndex); qSwap(rightIndex, topIndex); Q_FALLTHROUGH(); case makePackedLineTypes(LtDouble, LtNone , LtDouble, LtNone ): // ║ ; ╫ ═ ╪ lightPath.moveTo(origin[topIndex] + dir[leftIndex] * doubleLinesDistance); lightPath.lineTo(origin[bottomIndex] + dir[leftIndex] * doubleLinesDistance); lightPath.moveTo(origin[topIndex] + dir[rightIndex] * doubleLinesDistance); lightPath.lineTo(origin[bottomIndex] + dir[rightIndex] * doubleLinesDistance); break; case makePackedLineTypes(LtDouble, LtNone , LtNone , LtNone ): // ╨ ; ╞ ╥ ╡ lightPath.moveTo(origin[topIndex] + dir[leftIndex] * doubleLinesDistance); lightPath.lineTo(center + dir[leftIndex] * doubleLinesDistance); lightPath.moveTo(origin[topIndex] + dir[rightIndex] * doubleLinesDistance); lightPath.lineTo(center + dir[rightIndex] * doubleLinesDistance); break; case makePackedLineTypes(LtDouble, LtDouble, LtDouble, LtDouble): // ╬ drawDoubleUpRightShorterLine(topIndex, rightIndex); drawDoubleUpRightShorterLine(bottomIndex, rightIndex); drawDoubleUpRightShorterLine(topIndex, leftIndex); drawDoubleUpRightShorterLine(bottomIndex, leftIndex); break; case makePackedLineTypes(LtDouble, LtDouble, LtDouble, LtNone ): // ╠ ; ╩ ╣ ╦ lightPath.moveTo(origin[topIndex] + dir[leftIndex] * doubleLinesDistance); lightPath.lineTo(origin[bottomIndex] + dir[leftIndex] * doubleLinesDistance); drawDoubleUpRightShorterLine(topIndex, rightIndex); drawDoubleUpRightShorterLine(bottomIndex, rightIndex); break; case makePackedLineTypes(LtDouble, LtDouble, LtNone , LtNone ): // ╚ ; ╝ ╔ ╗ lightPath.moveTo(origin[topIndex] + dir[leftIndex] * doubleLinesDistance); lightPath.lineTo(center + (dir[leftIndex] + dir[bottomIndex]) * doubleLinesDistance); lightPath.lineTo(origin[rightIndex] + dir[bottomIndex] * doubleLinesDistance); drawDoubleUpRightShorterLine(topIndex, rightIndex); break; } // Draw paths if (!lightPath.isEmpty()) { paint.strokePath(lightPath, lightPen); } if (!heavyPath.isEmpty()) { paint.strokePath(heavyPath, heavyPen); } return true; } STATIC_METHOD INLINE_METHOD bool drawDashedLineCharacter(QPainter &paint, int x, int y, int w, int h, uchar code, bool bold) { if (!((0x04 <= code && code <= 0x0B) || (0x4C <= code && code <= 0x4F))) { return false; } const uint lightLineWidth = lineWidth(w, false, bold); const uint heavyLineWidth = lineWidth(w, true, bold); const auto lightPen = pen(paint, lightLineWidth); const auto heavyPen = pen(paint, heavyLineWidth); // Pixel aligned center point const QPointF center = { int(x + w/2.0) + 0.5 * (lightLineWidth%2), int(y + h/2.0) + 0.5 * (lightLineWidth%2), }; const qreal halfGapH = qMax(w / 20.0, 0.5); const qreal halfGapV = qMax(h / 26.0, 0.5); // For some reason vertical double dash has bigger gap const qreal halfGapDDV = qMax(h / 14.0, 0.5); static const int LinesNumMax = 4; enum Orientation {Horizontal, Vertical}; struct { int linesNum; Orientation orientation; QPen pen; qreal halfGap; } lineProps; switch (code) { case 0x4C: lineProps = {2, Horizontal, lightPen, halfGapH }; break; // ╌ case 0x4D: lineProps = {2, Horizontal, heavyPen, halfGapH }; break; // ╍ case 0x4E: lineProps = {2, Vertical , lightPen, halfGapDDV}; break; // ╎ case 0x4F: lineProps = {2, Vertical , heavyPen, halfGapDDV}; break; // ╏ case 0x04: lineProps = {3, Horizontal, lightPen, halfGapH }; break; // ┄ case 0x05: lineProps = {3, Horizontal, heavyPen, halfGapH }; break; // ┅ case 0x06: lineProps = {3, Vertical , lightPen, halfGapV }; break; // ┆ case 0x07: lineProps = {3, Vertical , heavyPen, halfGapV }; break; // ┇ case 0x08: lineProps = {4, Horizontal, lightPen, halfGapH }; break; // ┈ case 0x09: lineProps = {4, Horizontal, heavyPen, halfGapH }; break; // ┉ case 0x0A: lineProps = {4, Vertical , lightPen, halfGapV }; break; // ┊ case 0x0B: lineProps = {4, Vertical , heavyPen, halfGapV }; break; // ┋ } Q_ASSERT(lineProps.linesNum <= LinesNumMax); const int size = (lineProps.orientation == Horizontal ? w : h); const int pos = (lineProps.orientation == Horizontal ? x : y); QLineF lines[LinesNumMax]; for (int i = 0; i < lineProps.linesNum; i++) { const qreal start = pos + qreal(size * (i )) / lineProps.linesNum; const qreal end = pos + qreal(size * (i+1)) / lineProps.linesNum; if (lineProps.orientation == Horizontal) { lines[i] = QLineF{start + lineProps.halfGap, center.y(), end - lineProps.halfGap, center.y()}; } else { lines[i] = QLineF{center.x(), start + lineProps.halfGap, center.x(), end - lineProps.halfGap}; } } const auto origPen = paint.pen(); paint.setPen(lineProps.pen); paint.drawLines(lines, lineProps.linesNum); paint.setPen(origPen); return true; } STATIC_METHOD INLINE_METHOD bool drawRoundedCornerLineCharacter(QPainter &paint, int x, int y, int w, int h, uchar code, bool bold) { if (!(0x6D <= code && code <= 0x70)) { return false; } const uint lightLineWidth = lineWidth(w, false, bold); const auto lightPen = pen(paint, lightLineWidth); // Pixel aligned center point const QPointF center = { int(x + w/2.0) + 0.5 * (lightLineWidth%2), int(y + h/2.0) + 0.5 * (lightLineWidth%2), }; const int r = w * 3 / 8; const int d = 2 * r; QPainterPath path; // lineTo() between moveTo and arcTo is redundant - arcTo() draws line // to the arc's starting point switch (code) { case 0x6D: // BOX DRAWINGS LIGHT ARC DOWN AND RIGHT path.moveTo(center.x(), y + h); path.arcTo(center.x(), center.y(), d, d, 180, -90); path.lineTo(x + w, center.y()); break; case 0x6E: // BOX DRAWINGS LIGHT ARC DOWN AND LEFT path.moveTo(center.x(), y + h); path.arcTo(center.x() - d, center.y(), d, d, 0, 90); path.lineTo(x, center.y()); break; case 0x6F: // BOX DRAWINGS LIGHT ARC UP AND LEFT path.moveTo(center.x(), y); path.arcTo(center.x() - d, center.y() - d, d, d, 0, -90); path.lineTo(x, center.y()); break; case 0x70: // BOX DRAWINGS LIGHT ARC UP AND RIGHT path.moveTo(center.x(), y); path.arcTo(center.x(), center.y() - d, d, d, 180, 90); path.lineTo(x + w, center.y()); break; } paint.strokePath(path, lightPen); return true; } STATIC_METHOD INLINE_METHOD bool drawDiagonalLineCharacter(QPainter &paint, int x, int y, int w, int h, uchar code, bool bold) { if (!(0x71 <= code && code <= 0x73)) { return false; } const uint lightLineWidth = lineWidth(w, false, bold); const auto lightPen = pen(paint, lightLineWidth); const QLineF lines[] = { QLineF(x+w, y, x , y+h), // '/' QLineF(x , y, x+w, y+h), // '\' }; const auto origPen = paint.pen(); paint.setPen(lightPen); switch (code) { case 0x71: // BOX DRAWINGS LIGHT DIAGONAL UPPER RIGHT TO LOWER LEFT paint.drawLine(lines[0]); break; case 0x72: // BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO LOWER RIGHT paint.drawLine(lines[1]); break; case 0x73: // BOX DRAWINGS LIGHT DIAGONAL CROSS paint.drawLines(lines, 2); break; } paint.setPen(origPen); return true; } STATIC_METHOD INLINE_METHOD bool drawBlockCharacter(QPainter &paint, int x, int y, int w, int h, uchar code, bool bold) { Q_UNUSED(bold) const QColor color = paint.pen().color(); // Center point const QPointF center = { x + w/2.0, y + h/2.0, }; // Default rect fills entire cell QRectF rect(x, y, w, h); // LOWER ONE EIGHTH BLOCK to LEFT ONE EIGHTH BLOCK if (code >= 0x81 && code <= 0x8f) { if (code < 0x88) { // Horizontal const qreal height = h * (0x88 - code) / 8.0; rect.setY(y + height); rect.setHeight(h - height); } else if (code > 0x88) { // Vertical const qreal width = w * (0x90 - code) / 8.0; rect.setWidth(width); } paint.fillRect(rect, color); return true; } // Combinations of quarter squares // LEFT ONE EIGHTH BLOCK to QUADRANT UPPER RIGHT AND LOWER LEFT AND LOWER RIGHT if (code >= 0x96 && code <= 0x9F) { const QRectF upperLeft (x , y , w/2.0, h/2.0); const QRectF upperRight(center.x(), y , w/2.0, h/2.0); const QRectF lowerLeft (x , center.y(), w/2.0, h/2.0); const QRectF lowerRight(center.x(), center.y(), w/2.0, h/2.0); QPainterPath path; switch (code) { case 0x96: // ▖ path.addRect(lowerLeft); break; case 0x97: // ▗ path.addRect(lowerRight); break; case 0x98: // ▘ path.addRect(upperLeft); break; case 0x99: // ▙ path.addRect(upperLeft); path.addRect(lowerLeft); path.addRect(lowerRight); break; case 0x9a: // ▚ path.addRect(upperLeft); path.addRect(lowerRight); break; case 0x9b: // ▛ path.addRect(upperLeft); path.addRect(upperRight); path.addRect(lowerLeft); break; case 0x9c: // ▜ path.addRect(upperLeft); path.addRect(upperRight); path.addRect(lowerRight); break; case 0x9d: // ▝ path.addRect(upperRight); break; case 0x9e: // ▞ path.addRect(upperRight); path.addRect(lowerLeft); break; case 0x9f: // ▟ path.addRect(upperRight); path.addRect(lowerLeft); path.addRect(lowerRight); break; } paint.fillPath(path, color); return true; } QBrush lightShade; QBrush mediumShade; QBrush darkShade; if (paint.testRenderHint(QPainter::Antialiasing)) { lightShade = QColor(color.red(), color.green(), color.blue(), 64); mediumShade = QColor(color.red(), color.green(), color.blue(), 128); darkShade = QColor(color.red(), color.green(), color.blue(), 192); } else { lightShade = QBrush(color, Qt::Dense6Pattern); mediumShade = QBrush(color, Qt::Dense4Pattern); darkShade = QBrush(color, Qt::Dense2Pattern); } // And the random stuff switch (code) { case 0x80: // Top half block rect.setHeight(h/2.0); paint.fillRect(rect, color); return true; case 0x90: // Right half block rect.moveLeft(center.x()); paint.fillRect(rect, color); return true; case 0x94: // Top one eighth block rect.setHeight(h/8.0); paint.fillRect(rect, color); return true; case 0x95: { // Right one eighth block const qreal width = 7 * w / 8.0; rect.moveLeft(x + width); paint.fillRect(rect, color); return true; } case 0x91: // Light shade paint.fillRect(rect, lightShade); return true; case 0x92: // Medium shade paint.fillRect(rect, mediumShade); return true; case 0x93: // Dark shade paint.fillRect(rect, darkShade); return true; default: return false; } } void draw(QPainter &paint, const QRect &cellRect, const QChar &chr, bool bold) { static const ushort FirstBoxDrawingCharacterCodePoint = 0x2500; const uchar code = chr.unicode() - FirstBoxDrawingCharacterCodePoint; int x = cellRect.x(); int y = cellRect.y(); int w = cellRect.width(); int h = cellRect.height(); // Each function below returns true when it has drawn the character, false otherwise. drawBasicLineCharacter(paint, x, y, w, h, code, bold) || drawDashedLineCharacter(paint, x, y, w, h, code, bold) || drawRoundedCornerLineCharacter(paint, x, y, w, h, code, bold) || drawDiagonalLineCharacter(paint, x, y, w, h, code, bold) || drawBlockCharacter(paint, x, y, w, h, code, bold); } } // namespace LineBlockCharacters } // namespace Konsole deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/konsole_wcwidth.h000066400000000000000000000056251475472654300265510ustar00rootroot00000000000000/* 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 (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 Lesser 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. */ #ifndef _KONSOLE_WCWIDTH_H_ #define _KONSOLE_WCWIDTH_H_ // Standard #include // Qt #include #include #ifdef UNIT_TEST #define STATIC_METHOD #define INLINE_METHOD #else #define STATIC_METHOD static #define INLINE_METHOD inline #endif int konsole_wcwidth(wchar_t ucs); int string_width( const std::wstring & wstr ); namespace Konsole { /** * Helper functions for drawing characters from "Box Drawing" and "Block Elements" Unicode blocks. */ namespace LineBlockCharacters { #ifdef UNIT_TEST bool drawBasicLineCharacter(QPainter& paint, int x, int y, int w, int h, uchar code, bool bold); uint lineWidth(uint fontWidth, bool heavy, bool bold); bool drawDashedLineCharacter(QPainter &paint, int x, int y, int w, int h, uchar code, bool bold); bool drawRoundedCornerLineCharacter(QPainter &paint, int x, int y, int w, int h, uchar code, bool bold); bool drawDiagonalLineCharacter(QPainter &paint, int x, int y, int w, int h, uchar code, bool bold); bool drawBlockCharacter(QPainter &paint, int x, int y, int w, int h, uchar code, bool bold); #endif /** * Returns true if the character can be drawn by draw() function. * * @param ucs4cp Character to test's UCS4 code point */ inline static bool canDraw(uint ucs4cp) { return (0x2500 <= ucs4cp && ucs4cp <= 0x259F); } /** * Draws character. * * @param paint QPainter to draw on * @param cellRect Rectangle to draw in * @param chr Character to be drawn * @param bold Whether the character should be boldface */ void draw(QPainter &paint, const QRect &cellRect, const QChar &chr, bool bold); } // namespace LineBlockCharacters } // namespace Konsole int characterWidth(uint ucs4); void setIsCodecGB18030(bool isCodecGB18030); bool IsCodecGB18030(); #endif deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/kprocess.cpp000066400000000000000000000234231475472654300255260ustar00rootroot00000000000000/* * This file is a part of QTerminal - http://gitorious.org/qterminal * * This file was un-linked from KDE and modified * by Maxim Bourmistrov * */ /* This file is part of the KDE libraries Copyright (C) 2007 Oswald Buddenhagen This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kprocess.h" #include #ifdef Q_OS_WIN # include #else # include # include #endif #ifndef Q_OS_WIN # define STD_OUTPUT_HANDLE 1 # define STD_ERROR_HANDLE 2 #endif #ifdef _WIN32_WCE #include #endif void KProcessPrivate::writeAll(const QByteArray &buf, int fd) { #ifdef Q_OS_WIN #ifndef _WIN32_WCE HANDLE h = GetStdHandle(fd); if (h) { DWORD wr; WriteFile(h, buf.data(), buf.size(), &wr, 0); } #else fwrite(buf.data(), 1, buf.size(), (FILE*)fd); #endif #else int off = 0; do { int ret = ::write(fd, buf.data() + off, buf.size() - off); if (ret < 0) { if (errno != EINTR) return; } else { off += ret; } } while (off < buf.size()); #endif } void KProcessPrivate::forwardStd(KProcess::ProcessChannel good, int fd) { Q_Q(KProcess); QProcess::ProcessChannel oc = q->readChannel(); q->setReadChannel(good); writeAll(q->readAll(), fd); q->setReadChannel(oc); } void KProcessPrivate::_k_forwardStdout() { #ifndef _WIN32_WCE forwardStd(KProcess::StandardOutput, STD_OUTPUT_HANDLE); #else forwardStd(KProcess::StandardOutput, (int)stdout); #endif } void KProcessPrivate::_k_forwardStderr() { #ifndef _WIN32_WCE forwardStd(KProcess::StandardError, STD_ERROR_HANDLE); #else forwardStd(KProcess::StandardError, (int)stderr); #endif } ///////////////////////////// // public member functions // ///////////////////////////// KProcess::KProcess(QObject *parent) : QProcess(parent), d_ptr(new KProcessPrivate) { d_ptr->q_ptr = this; setOutputChannelMode(ForwardedChannels); } KProcess::KProcess(KProcessPrivate *d, QObject *parent) : QProcess(parent), d_ptr(d) { d_ptr->q_ptr = this; setOutputChannelMode(ForwardedChannels); } KProcess::~KProcess() { delete d_ptr; } void KProcess::setOutputChannelMode(OutputChannelMode mode) { Q_D(KProcess); d->outputChannelMode = mode; disconnect(this, SIGNAL(readyReadStandardOutput())); disconnect(this, SIGNAL(readyReadStandardError())); switch (mode) { case OnlyStdoutChannel: connect(this, SIGNAL(readyReadStandardError()), SLOT(_k_forwardStderr())); break; case OnlyStderrChannel: connect(this, SIGNAL(readyReadStandardOutput()), SLOT(_k_forwardStdout())); break; default: QProcess::setProcessChannelMode((ProcessChannelMode)mode); return; } QProcess::setProcessChannelMode(QProcess::SeparateChannels); } KProcess::OutputChannelMode KProcess::outputChannelMode() const { Q_D(const KProcess); return d->outputChannelMode; } void KProcess::setNextOpenMode(QIODevice::OpenMode mode) { Q_D(KProcess); d->openMode = mode; } #define DUMMYENV "_KPROCESS_DUMMY_=" void KProcess::clearEnvironment() { setEnvironment(QStringList() << QString::fromLatin1(DUMMYENV)); } void KProcess::setEnv(const QString &name, const QString &value, bool overwrite) { QStringList env = environment(); if (env.isEmpty()) { env = systemEnvironment(); env.removeAll(QString::fromLatin1(DUMMYENV)); } QString fname(name); fname.append(QLatin1Char('=')); for (QStringList::Iterator it = env.begin(); it != env.end(); ++it) if ((*it).startsWith(fname)) { if (overwrite) { *it = fname.append(value); setEnvironment(env); } return; } env.append(fname.append(value)); setEnvironment(env); } void KProcess::unsetEnv(const QString &name) { QStringList env = environment(); if (env.isEmpty()) { env = systemEnvironment(); env.removeAll(QString::fromLatin1(DUMMYENV)); } QString fname(name); fname.append(QLatin1Char('=')); for (QStringList::Iterator it = env.begin(); it != env.end(); ++it) if ((*it).startsWith(fname)) { env.erase(it); if (env.isEmpty()) env.append(QString::fromLatin1(DUMMYENV)); setEnvironment(env); return; } } void KProcess::setProgram(const QString &exe, const QStringList &args) { Q_D(KProcess); d->prog = exe; d->args = args; #ifdef Q_OS_WIN setNativeArguments(QString()); #endif } void KProcess::setProgram(const QStringList &argv) { Q_D(KProcess); Q_ASSERT( !argv.isEmpty() ); d->args = argv; d->prog = d->args.takeFirst(); #ifdef Q_OS_WIN setNativeArguments(QString()); #endif } KProcess &KProcess::operator<<(const QString &arg) { Q_D(KProcess); if (d->prog.isEmpty()) d->prog = arg; else d->args << arg; return *this; } KProcess &KProcess::operator<<(const QStringList &args) { Q_D(KProcess); if (d->prog.isEmpty()) setProgram(args); else d->args << args; return *this; } void KProcess::clearProgram() { Q_D(KProcess); d->prog.clear(); d->args.clear(); #ifdef Q_OS_WIN setNativeArguments(QString()); #endif } #if 0 void KProcess::setShellCommand(const QString &cmd) { Q_D(KProcess); KShell::Errors err; d->args = KShell::splitArgs( cmd, KShell::AbortOnMeta | KShell::TildeExpand, &err); if (err == KShell::NoError && !d->args.isEmpty()) { d->prog = KStandardDirs::findExe(d->args[0]); if (!d->prog.isEmpty()) { d->args.removeFirst(); #ifdef Q_OS_WIN setNativeArguments(QString()); #endif return; } } d->args.clear(); #ifdef Q_OS_UNIX // #ifdef NON_FREE // ... as they ship non-POSIX /bin/sh # if !defined(__linux__) && !defined(__FreeBSD__) && !defined(__NetBSD__) && !defined(__OpenBSD__) && !defined(__DragonFly__) && !defined(__GNU__) // If /bin/sh is a symlink, we can be pretty sure that it points to a // POSIX shell - the original bourne shell is about the only non-POSIX // shell still in use and it is always installed natively as /bin/sh. d->prog = QFile::symLinkTarget(QString::fromLatin1("/bin/sh")); if (d->prog.isEmpty()) { // Try some known POSIX shells. d->prog = KStandardDirs::findExe(QString::fromLatin1("ksh")); if (d->prog.isEmpty()) { d->prog = KStandardDirs::findExe(QString::fromLatin1("ash")); if (d->prog.isEmpty()) { d->prog = KStandardDirs::findExe(QString::fromLatin1("bash")); if (d->prog.isEmpty()) { d->prog = KStandardDirs::findExe(QString::fromLatin1("zsh")); if (d->prog.isEmpty()) // We're pretty much screwed, to be honest ... d->prog = QString::fromLatin1("/bin/sh"); } } } } # else d->prog = QString::fromLatin1("/bin/sh"); # endif d->args << QString::fromLatin1("-c") << cmd; #else // Q_OS_UNIX // KMacroExpander::expandMacrosShellQuote(), KShell::quoteArg() and // KShell::joinArgs() may generate these for security reasons. setEnv(PERCENT_VARIABLE, QLatin1String("%")); #ifndef _WIN32_WCE WCHAR sysdir[MAX_PATH + 1]; UINT size = GetSystemDirectoryW(sysdir, MAX_PATH + 1); d->prog = QString::fromUtf16((const ushort *) sysdir, size); d->prog += QLatin1String("\\cmd.exe"); setNativeArguments(QLatin1String("/V:OFF /S /C \"") + cmd + QLatin1Char('"')); #else d->prog = QLatin1String("\\windows\\cmd.exe"); setNativeArguments(QLatin1String("/S /C \"") + cmd + QLatin1Char('"')); #endif #endif } #endif QStringList KProcess::program() const { Q_D(const KProcess); QStringList argv = d->args; argv.prepend(d->prog); return argv; } void KProcess::start() { Q_D(KProcess); QProcess::start(d->prog, d->args, d->openMode); } int KProcess::execute(int msecs) { start(); if (!waitForFinished(msecs)) { kill(); waitForFinished(-1); return -2; } return (exitStatus() == QProcess::NormalExit) ? exitCode() : -1; } // static int KProcess::execute(const QString &exe, const QStringList &args, int msecs) { KProcess p; p.setProgram(exe, args); return p.execute(msecs); } // static int KProcess::execute(const QStringList &argv, int msecs) { KProcess p; p.setProgram(argv); return p.execute(msecs); } int KProcess::startDetached() { Q_D(KProcess); qint64 pid; if (!QProcess::startDetached(d->prog, d->args, workingDirectory(), &pid)) return 0; return (int) pid; } // static int KProcess::startDetached(const QString &exe, const QStringList &args) { qint64 pid; if (!QProcess::startDetached(exe, args, QString(), &pid)) return 0; return (int) pid; } // static int KProcess::startDetached(const QStringList &argv) { QStringList args = argv; QString prog = args.takeFirst(); return startDetached(prog, args); } deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/kprocess.h000066400000000000000000000260161475472654300251740ustar00rootroot00000000000000/* * This file is a part of QTerminal - http://gitorious.org/qterminal * * This file was un-linked from KDE and modified * by Maxim Bourmistrov * */ /* This file is part of the KDE libraries Copyright (C) 2007 Oswald Buddenhagen This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KPROCESS_H #define KPROCESS_H //#include #include class KProcessPrivate; /** * \class KProcess kprocess.h * * Child process invocation, monitoring and control. * * This class extends QProcess by some useful functionality, overrides * some defaults with saner values and wraps parts of the API into a more * accessible one. * This is the preferred way of spawning child processes in KDE; don't * use QProcess directly. * * @author Oswald Buddenhagen **/ class KProcess : public QProcess { Q_OBJECT Q_DECLARE_PRIVATE(KProcess) public: /** * Modes in which the output channels can be opened. */ enum OutputChannelMode { SeparateChannels = QProcess::SeparateChannels, /**< Standard output and standard error are handled by KProcess as separate channels */ MergedChannels = QProcess::MergedChannels, /**< Standard output and standard error are handled by KProcess as one channel */ ForwardedChannels = QProcess::ForwardedChannels, /**< Both standard output and standard error are forwarded to the parent process' respective channel */ OnlyStdoutChannel, /**< Only standard output is handled; standard error is forwarded */ OnlyStderrChannel /**< Only standard error is handled; standard output is forwarded */ }; /** * Constructor */ explicit KProcess(QObject *parent = nullptr); /** * Destructor */ ~KProcess() override; /** * Set how to handle the output channels of the child process. * * The default is ForwardedChannels, which is unlike in QProcess. * Do not request more than you actually handle, as this output is * simply lost otherwise. * * This function must be called before starting the process. * * @param mode the output channel handling mode */ void setOutputChannelMode(OutputChannelMode mode); /** * Query how the output channels of the child process are handled. * * @return the output channel handling mode */ OutputChannelMode outputChannelMode() const; /** * Set the QIODevice open mode the process will be opened in. * * This function must be called before starting the process, obviously. * * @param mode the open mode. Note that this mode is automatically * "reduced" according to the channel modes and redirections. * The default is QIODevice::ReadWrite. */ void setNextOpenMode(QIODevice::OpenMode mode); /** * Adds the variable @p name to the process' environment. * * This function must be called before starting the process. * * @param name the name of the environment variable * @param value the new value for the environment variable * @param overwrite if @c false and the environment variable is already * set, the old value will be preserved */ void setEnv(const QString &name, const QString &value, bool overwrite = true); /** * Removes the variable @p name from the process' environment. * * This function must be called before starting the process. * * @param name the name of the environment variable */ void unsetEnv(const QString &name); /** * Empties the process' environment. * * Note that LD_LIBRARY_PATH/DYLD_LIBRARY_PATH is automatically added * on *NIX. * * This function must be called before starting the process. */ void clearEnvironment(); /** * Set the program and the command line arguments. * * This function must be called before starting the process, obviously. * * @param exe the program to execute * @param args the command line arguments for the program, * one per list element */ void setProgram(const QString &exe, const QStringList &args = QStringList()); /** * @overload * * @param argv the program to execute and the command line arguments * for the program, one per list element */ void setProgram(const QStringList &argv); /** * Append an element to the command line argument list for this process. * * If no executable is set yet, it will be set instead. * * For example, doing an "ls -l /usr/local/bin" can be achieved by: * \code * KProcess p; * p << "ls" << "-l" << "/usr/local/bin"; * ... * \endcode * * This function must be called before starting the process, obviously. * * @param arg the argument to add * @return a reference to this KProcess */ KProcess &operator<<(const QString& arg); /** * @overload * * @param args the arguments to add * @return a reference to this KProcess */ KProcess &operator<<(const QStringList& args); /** * Clear the program and command line argument list. */ void clearProgram(); /** * Set a command to execute through a shell (a POSIX sh on *NIX * and cmd.exe on Windows). * * Using this for anything but user-supplied commands is usually a bad * idea, as the command's syntax depends on the platform. * Redirections including pipes, etc. are better handled by the * respective functions provided by QProcess. * * If KProcess determines that the command does not really need a * shell, it will trasparently execute it without one for performance * reasons. * * This function must be called before starting the process, obviously. * * @param cmd the command to execute through a shell. * The caller must make sure that all filenames etc. are properly * quoted when passed as argument. Failure to do so often results in * serious security holes. See KShell::quoteArg(). */ void setShellCommand(const QString &cmd); /** * Obtain the currently set program and arguments. * * @return a list, the first element being the program, the remaining ones * being command line arguments to the program. */ QStringList program() const; /** * Start the process. * * @see QProcess::start(const QString &, const QStringList &, OpenMode) */ void start(); /** * Start the process, wait for it to finish, and return the exit code. * * This method is roughly equivalent to the sequence: * * start(); * waitForFinished(msecs); * return exitCode(); * * * Unlike the other execute() variants this method is not static, * so the process can be parametrized properly and talked to. * * @param msecs time to wait for process to exit before killing it * @return -2 if the process could not be started, -1 if it crashed, * otherwise its exit code */ int execute(int msecs = -1); /** * @overload * * @param exe the program to execute * @param args the command line arguments for the program, * one per list element * @param msecs time to wait for process to exit before killing it * @return -2 if the process could not be started, -1 if it crashed, * otherwise its exit code */ static int execute(const QString &exe, const QStringList &args = QStringList(), int msecs = -1); /** * @overload * * @param argv the program to execute and the command line arguments * for the program, one per list element * @param msecs time to wait for process to exit before killing it * @return -2 if the process could not be started, -1 if it crashed, * otherwise its exit code */ static int execute(const QStringList &argv, int msecs = -1); /** * Start the process and detach from it. See QProcess::startDetached() * for details. * * Unlike the other startDetached() variants this method is not static, * so the process can be parametrized properly. * @note Currently, only the setProgram()/setShellCommand() and * setWorkingDirectory() parametrizations are supported. * * The KProcess object may be re-used immediately after calling this * function. * * @return the PID of the started process or 0 on error */ int startDetached(); /** * @overload * * @param exe the program to start * @param args the command line arguments for the program, * one per list element * @return the PID of the started process or 0 on error */ static int startDetached(const QString &exe, const QStringList &args = QStringList()); /** * @overload * * @param argv the program to start and the command line arguments * for the program, one per list element * @return the PID of the started process or 0 on error */ static int startDetached(const QStringList &argv); protected: /** * @internal */ KProcess(KProcessPrivate *d, QObject *parent); /** * @internal */ KProcessPrivate * const d_ptr; private: // hide those using QProcess::setReadChannelMode; using QProcess::readChannelMode; using QProcess::setProcessChannelMode; using QProcess::processChannelMode; Q_PRIVATE_SLOT(d_func(), void _k_forwardStdout()) Q_PRIVATE_SLOT(d_func(), void _k_forwardStderr()) }; /* ----------- kprocess_p.h ---------------- */ class KProcessPrivate { Q_DECLARE_PUBLIC(KProcess) protected: KProcessPrivate() : outputChannelMode(KProcess::ForwardedChannels), openMode(QIODevice::ReadWrite), q_ptr(nullptr) { } virtual ~KProcessPrivate() { } void writeAll(const QByteArray &buf, int fd); void forwardStd(KProcess::ProcessChannel good, int fd); void _k_forwardStdout(); void _k_forwardStderr(); QString prog; QStringList args; KProcess::OutputChannelMode outputChannelMode; QIODevice::OpenMode openMode; KProcess *q_ptr; }; /* ------------------------------------------- */ #endif deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/kpty.cpp000066400000000000000000000421241475472654300246630ustar00rootroot00000000000000/* This file is part of the KDE libraries Copyright (C) 2002 Waldo Bastian Copyright (C) 2002-2003,2007 Oswald Buddenhagen This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Rewritten for QT4 by e_k , Copyright (C)2008 */ #include "kpty_p.h" #include #if defined(__FreeBSD__) || defined(__DragonFly__) #define HAVE_LOGIN #define HAVE_LIBUTIL_H #endif #if defined(__OpenBSD__) #define HAVE_LOGIN #define HAVE_UTIL_H #endif #if defined(__NetBSD__) #define HAVE_LOGIN #define HAVE_UTIL_H #define HAVE_OPENPTY #endif #if defined(__APPLE__) #define HAVE_OPENPTY #define HAVE_UTIL_H #endif #ifdef __sgi #define __svr4__ #endif #ifdef __osf__ #define _OSF_SOURCE #include #endif #ifdef _AIX #define _ALL_SOURCE #endif // __USE_XOPEN isn't defined by default in ICC // (needed for ptsname(), grantpt() and unlockpt()) #ifdef __INTEL_COMPILER # ifndef __USE_XOPEN # define __USE_XOPEN # endif #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if defined(HAVE_PTY_H) # include #endif #ifdef HAVE_LIBUTIL_H # include #elif defined(HAVE_UTIL_H) # include #endif #ifdef HAVE_UTEMPTER extern "C" { # include } #else # include # ifdef HAVE_UTMPX # include # endif # if !defined(_PATH_UTMPX) && defined(_UTMPX_FILE) # define _PATH_UTMPX _UTMPX_FILE # endif # ifdef HAVE_UPDWTMPX # if !defined(_PATH_WTMPX) && defined(_WTMPX_FILE) # define _PATH_WTMPX _WTMPX_FILE # endif # endif #endif /* for HP-UX (some versions) the extern C is needed, and for other platforms it doesn't hurt */ extern "C" { #include #if defined(HAVE_TERMIO_H) # include // struct winsize on some systems #endif } #if defined (_HPUX_SOURCE) # define _TERMIOS_INCLUDED # include #endif #ifdef HAVE_SYS_STROPTS_H # include // Defines I_PUSH # define _NEW_TTY_CTRL #endif #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__) || 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(__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__) || defined(__GNU__) # define _tcsetattr(fd, ttmode) tcsetattr(fd, TCSANOW, ttmode) # else # define _tcsetattr(fd, ttmode) ioctl(fd, TCSETS, (char *)ttmode) # endif #endif //#include //#include // findExe // not defined on HP-UX for example #ifndef CTRL # define CTRL(x) ((x) & 037) #endif #define TTY_GROUP "tty" /////////////////////// // private functions // /////////////////////// ////////////////// // private data // ////////////////// KPtyPrivate::KPtyPrivate(KPty* parent) : masterFd(-1), slaveFd(-1), ownMaster(true), q_ptr(parent) { } KPtyPrivate::~KPtyPrivate() { } bool KPtyPrivate::chownpty(bool) { // return !QProcess::execute(KStandardDirs::findExe("kgrantpty"), // QStringList() << (grant?"--grant":"--revoke") << QString::number(masterFd)); return true; } ///////////////////////////// // public member functions // ///////////////////////////// KPty::KPty() : d_ptr(new KPtyPrivate(this)) { } KPty::KPty(KPtyPrivate *d) : d_ptr(d) { d_ptr->q_ptr = this; } KPty::~KPty() { close(); delete d_ptr; } bool KPty::open() { Q_D(KPty); if (d->masterFd >= 0) return true; d->ownMaster = true; QByteArray ptyName; // Find a master pty that we can open //////////////////////////////// // Because not all the pty animals are created equal, they want to // be opened by several different methods. // We try, as we know them, one by one. #ifdef HAVE_OPENPTY char ptsn[PATH_MAX]; if (::openpty( &d->masterFd, &d->slaveFd, ptsn, 0, 0)) { d->masterFd = -1; d->slaveFd = -1; qWarning() << "Can't open a pseudo teletype"; return false; } d->ttyName = ptsn; #else #ifdef HAVE__GETPTY // irix char *ptsn = _getpty(&d->masterFd, O_RDWR|O_NOCTTY, S_IRUSR|S_IWUSR, 0); if (ptsn) { d->ttyName = ptsn; goto grantedpt; } #elif defined(HAVE_PTSNAME) || defined(TIOCGPTN) #ifdef HAVE_POSIX_OPENPT d->masterFd = ::posix_openpt(O_RDWR|O_NOCTTY); #elif defined(HAVE_GETPT) d->masterFd = ::getpt(); #elif defined(PTM_DEVICE) d->masterFd = ::open(PTM_DEVICE, O_RDWR|O_NOCTTY); #else # error No method to open a PTY master detected. #endif if (d->masterFd >= 0) { #ifdef HAVE_PTSNAME char *ptsn = ptsname(d->masterFd); if (ptsn) { d->ttyName = ptsn; #else int ptyno; if (ioctl(d->masterFd, TIOCGPTN, &ptyno) != -1) { d->ttyName = QByteArray("/dev/pts/") + QByteArray::number(ptyno); #endif #ifdef HAVE_GRANTPT if (!grantpt(d->masterFd)) { goto grantedpt; } #else goto gotpty; #endif } ::close(d->masterFd); d->masterFd = -1; } #endif // HAVE_PTSNAME || TIOCGPTN // Linux device names, FIXME: Trouble on other systems? for (const char * s3 = "pqrstuvwxyzabcde"; *s3; s3++) { for (const char * s4 = "0123456789abcdef"; *s4; s4++) { ptyName = QByteArrayLiteral("/dev/pty") + *s3 + *s4; d->ttyName = QByteArrayLiteral("/dev/tty") + *s3 + *s4; d->masterFd = ::open(ptyName.data(), O_RDWR); if (d->masterFd >= 0) { #ifdef Q_OS_SOLARIS /* Need to check the process group of the pty. * If it exists, then the slave pty is in use, * and we need to get another one. */ int pgrp_rtn; if (ioctl(d->masterFd, TIOCGPGRP, &pgrp_rtn) != -1 || errno != EIO) { ::close(d->masterFd); d->masterFd = -1; continue; } #endif /* Q_OS_SOLARIS */ if (!access(d->ttyName.data(),R_OK|W_OK)) { // checks availability based on permission bits if (!geteuid()) { struct group * p = getgrnam(TTY_GROUP); if (!p) { p = getgrnam("wheel"); } gid_t gid = p ? p->gr_gid : getgid (); if (!chown(d->ttyName.data(), getuid(), gid)) { chmod(d->ttyName.data(), S_IRUSR|S_IWUSR|S_IWGRP); } } goto gotpty; } ::close(d->masterFd); d->masterFd = -1; } } } qWarning() << "Can't open a pseudo teletype"; return false; gotpty: struct stat st; if (stat(d->ttyName.data(), &st)) { return false; // this just cannot happen ... *cough* Yeah right, I just // had it happen when pty #349 was allocated. I guess // there was some sort of leak? I only had a few open. } if (((st.st_uid != getuid()) || (st.st_mode & (S_IRGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH))) && !d->chownpty(true)) { qWarning() << "chownpty failed for device " << ptyName << "::" << d->ttyName << "\nThis means the communication can be eavesdropped." #if (QT_VERSION >= QT_VERSION_CHECK(5,15,0)) << Qt::endl; #else << endl; #endif } #if defined (HAVE__GETPTY) || defined (HAVE_GRANTPT) grantedpt: #endif #ifdef HAVE_REVOKE revoke(d->ttyName.data()); #endif #ifdef HAVE_UNLOCKPT unlockpt(d->masterFd); #elif defined(TIOCSPTLCK) int flag = 0; ioctl(d->masterFd, TIOCSPTLCK, &flag); #endif d->slaveFd = ::open(d->ttyName.data(), O_RDWR | O_NOCTTY); if (d->slaveFd < 0) { qWarning() << "Can't open slave pseudo teletype"; ::close(d->masterFd); d->masterFd = -1; return false; } #if (defined(__svr4__) || defined(__sgi__)) // Solaris ioctl(d->slaveFd, I_PUSH, "ptem"); ioctl(d->slaveFd, I_PUSH, "ldterm"); #endif #endif /* HAVE_OPENPTY */ fcntl(d->masterFd, F_SETFD, FD_CLOEXEC); fcntl(d->slaveFd, F_SETFD, FD_CLOEXEC); return true; } bool KPty::open(int fd) { #if !defined(HAVE_PTSNAME) && !defined(TIOCGPTN) qWarning() << "Unsupported attempt to open pty with fd" << fd; return false; #else Q_D(KPty); if (d->masterFd >= 0) { qWarning() << "Attempting to open an already open pty"; return false; } d->ownMaster = false; # ifdef HAVE_PTSNAME char *ptsn = ptsname(fd); if (ptsn) { d->ttyName = ptsn; # else int ptyno; if (ioctl(fd, TIOCGPTN, &ptyno) != -1) { const size_t sz = 32; char buf[sz]; const size_t r = snprintf(buf, sz, "/dev/pts/%d", ptyno); if (sz <= r) { qWarning("KPty::open: Buffer too small\n"); } d->ttyName = buf; # endif } else { qWarning() << "Failed to determine pty slave device for fd" << fd; return false; } d->masterFd = fd; if (!openSlave()) { d->masterFd = -1; return false; } return true; #endif } void KPty::closeSlave() { Q_D(KPty); if (d->slaveFd < 0) { return; } ::close(d->slaveFd); d->slaveFd = -1; } bool KPty::openSlave() { Q_D(KPty); if (d->slaveFd >= 0) return true; if (d->masterFd < 0) { qDebug() << "Attempting to open pty slave while master is closed"; return false; } //d->slaveFd = KDE_open(d->ttyName.data(), O_RDWR | O_NOCTTY); d->slaveFd = ::open(d->ttyName.data(), O_RDWR | O_NOCTTY); if (d->slaveFd < 0) { qDebug() << "Can't open slave pseudo teletype"; return false; } fcntl(d->slaveFd, F_SETFD, FD_CLOEXEC); return true; } void KPty::close() { Q_D(KPty); if (d->masterFd < 0) { return; } closeSlave(); // don't bother resetting unix98 pty, it will go away after closing master anyway. if (memcmp(d->ttyName.data(), "/dev/pts/", 9)) { if (!geteuid()) { struct stat st; if (!stat(d->ttyName.data(), &st)) { int status = chown(d->ttyName.data(), 0, st.st_gid == getgid() ? 0 : -1); if (status < 0) { perror("chown"); } chmod(d->ttyName.data(), S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH); } } else { fcntl(d->masterFd, F_SETFD, 0); d->chownpty(false); } } ::close(d->masterFd); d->masterFd = -1; } void KPty::setCTty() { Q_D(KPty); // Setup job control ////////////////////////////////// // Become session leader, process group leader, // and get rid of the old controlling terminal. setsid(); // make our slave pty the new controlling terminal. #ifdef TIOCSCTTY ioctl(d->slaveFd, TIOCSCTTY, 0); #else // __svr4__ hack: the first tty opened after setsid() becomes controlling tty ::close(::open(d->ttyName, O_WRONLY, 0)); #endif // make our new process group the foreground group on the pty int pgrp = getpid(); #if defined(_POSIX_VERSION) || defined(__svr4__) tcsetpgrp(d->slaveFd, pgrp); #elif defined(TIOCSPGRP) ioctl(d->slaveFd, TIOCSPGRP, (char *)&pgrp); #endif } void KPty::login(const char * user, const char * remotehost) { #ifdef HAVE_UTEMPTER Q_D(KPty); addToUtmp(d->ttyName.constData(), remotehost, d->masterFd); Q_UNUSED(user); #else # ifdef HAVE_UTMPX struct utmpx l_struct; # else struct utmp l_struct; # endif memset(&l_struct, 0, sizeof(l_struct)); // 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) { strncpy(l_struct.ut_host, remotehost, sizeof(l_struct.ut_host)); # ifdef HAVE_STRUCT_UTMP_UT_SYSLEN l_struct.ut_syslen = qMin(strlen(remotehost), sizeof(l_struct.ut_host)); # endif } # ifndef __GLIBC__ Q_D(KPty); const char * str_ptr = d->ttyName.data(); if (!memcmp(str_ptr, "/dev/", 5)) { str_ptr += 5; } strncpy(l_struct.ut_line, str_ptr, sizeof(l_struct.ut_line)); # ifdef HAVE_STRUCT_UTMP_UT_ID strncpy(l_struct.ut_id, str_ptr + strlen(str_ptr) - sizeof(l_struct.ut_id), sizeof(l_struct.ut_id)); # endif # endif # ifdef HAVE_UTMPX gettimeofday(&l_struct.ut_tv, 0); # else l_struct.ut_time = time(nullptr); # endif # ifdef HAVE_LOGIN # ifdef HAVE_LOGINX ::loginx(&l_struct); # else ::login(&l_struct); # endif # else # ifdef HAVE_STRUCT_UTMP_UT_TYPE l_struct.ut_type = USER_PROCESS; # endif # ifdef HAVE_STRUCT_UTMP_UT_PID l_struct.ut_pid = getpid(); # ifdef HAVE_STRUCT_UTMP_UT_SESSION l_struct.ut_session = getsid(0); # endif # endif # ifdef HAVE_UTMPX utmpxname(_PATH_UTMPX); setutxent(); pututxline(&l_struct); endutxent(); # ifdef HAVE_UPDWTMPX updwtmpx(_PATH_WTMPX, &l_struct); # endif # else utmpname(_PATH_UTMP); setutent(); pututline(&l_struct); endutent(); updwtmp(_PATH_WTMP, &l_struct); # endif # endif #endif } void KPty::logout() { #ifdef HAVE_UTEMPTER Q_D(KPty); removeLineFromUtmp(d->ttyName.constData(), d->masterFd); #else Q_D(KPty); const char *str_ptr = d->ttyName.data(); if (!memcmp(str_ptr, "/dev/", 5)) { str_ptr += 5; } # ifdef __GLIBC__ else { const char * sl_ptr = strrchr(str_ptr, '/'); if (sl_ptr) { str_ptr = sl_ptr + 1; } } # endif # ifdef HAVE_LOGIN # ifdef HAVE_LOGINX ::logoutx(str_ptr, 0, DEAD_PROCESS); # else ::logout(str_ptr); # endif # else # ifdef HAVE_UTMPX struct utmpx l_struct, *ut; # else struct utmp l_struct, *ut; # endif memset(&l_struct, 0, sizeof(l_struct)); strncpy(l_struct.ut_line, str_ptr, sizeof(l_struct.ut_line)); # ifdef HAVE_UTMPX utmpxname(_PATH_UTMPX); setutxent(); if ((ut = getutxline(&l_struct))) { # else utmpname(_PATH_UTMP); 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; # endif # ifdef HAVE_STRUCT_UTMP_UT_TYPE ut->ut_type = DEAD_PROCESS; # endif # ifdef HAVE_UTMPX gettimeofday(&ut->ut_tv, 0); pututxline(ut); } endutxent(); # else ut->ut_time = time(nullptr); pututline(ut); } endutent(); # endif # endif #endif } // XXX Supposedly, tc[gs]etattr do not work with the master on Solaris. // Please verify. bool KPty::tcGetAttr(struct ::termios * ttmode) const { Q_D(const KPty); return _tcgetattr(d->masterFd, ttmode) == 0; } bool KPty::tcSetAttr(struct ::termios * ttmode) { Q_D(KPty); return _tcsetattr(d->masterFd, ttmode) == 0; } bool KPty::setWinSize(int lines, int columns) { Q_D(KPty); struct winsize winSize; memset(&winSize, 0, sizeof(winSize)); winSize.ws_row = (unsigned short)lines; winSize.ws_col = (unsigned short)columns; return ioctl(d->masterFd, TIOCSWINSZ, (char *)&winSize) != -1; } bool KPty::setEcho(bool echo) { struct ::termios ttmode; if (!tcGetAttr(&ttmode)) { return false; } if (!echo) { ttmode.c_lflag &= ~ECHO; } else { ttmode.c_lflag |= ECHO; } return tcSetAttr(&ttmode); } const char * KPty::ttyName() const { Q_D(const KPty); return d->ttyName.data(); } int KPty::masterFd() const { Q_D(const KPty); return d->masterFd; } int KPty::slaveFd() const { Q_D(const KPty); return d->slaveFd; } deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/kpty.h000066400000000000000000000127051475472654300243320ustar00rootroot00000000000000/* This file is part of the KDE libraries Copyright (C) 2003,2007 Oswald Buddenhagen This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Rewritten for QT4 by e_k , Copyright (C)2008 */ #ifndef kpty_h #define kpty_h #include class KPtyPrivate; struct termios; /** * Provides primitives for opening & closing a pseudo TTY pair, assigning the * controlling TTY, utmp registration and setting various terminal attributes. */ class KPty { Q_DECLARE_PRIVATE(KPty) public: /** * Constructor */ KPty(); /** * Destructor: * * If the pty is still open, it will be closed. Note, however, that * an utmp registration is @em not undone. */ ~KPty(); KPty(const KPty &) = delete; KPty &operator=(const KPty &) = delete; /** * Create a pty master/slave pair. * * @return true if a pty pair was successfully opened */ bool open(); bool open(int fd); /** * Close the pty master/slave pair. */ void close(); /** * Close the pty slave descriptor. * * When creating the pty, KPty also opens the slave and keeps it open. * Consequently the master will never receive an EOF notification. * Usually this is the desired behavior, as a closed pty slave can be * reopened any time - unlike a pipe or socket. However, in some cases * pipe-alike behavior might be desired. * * After this function was called, slaveFd() and setCTty() cannot be * used. */ void closeSlave(); bool openSlave(); /** * Creates a new session and process group and makes this pty the * controlling tty. */ void setCTty(); /** * Creates an utmp entry for the tty. * This function must be called after calling setCTty and * making this pty the stdin. * @param user the user to be logged on * @param remotehost the host from which the login is coming. This is * @em not the local host. For remote logins it should be the hostname * of the client. For local logins from inside an X session it should * be the name of the X display. Otherwise it should be empty. */ void login(const char * user = nullptr, const char * remotehost = nullptr); /** * Removes the utmp entry for this tty. */ void logout(); /** * Wrapper around tcgetattr(3). * * This function can be used only while the PTY is open. * You will need an #include <termios.h> to do anything useful * with it. * * @param ttmode a pointer to a termios structure. * Note: when declaring ttmode, @c struct @c ::termios must be used - * without the '::' some version of HP-UX thinks, this declares * the struct in your class, in your method. * @return @c true on success, false otherwise */ bool tcGetAttr(struct ::termios * ttmode) const; /** * Wrapper around tcsetattr(3) with mode TCSANOW. * * This function can be used only while the PTY is open. * * @param ttmode a pointer to a termios structure. * @return @c true on success, false otherwise. Note that success means * that @em at @em least @em one attribute could be set. */ bool tcSetAttr(struct ::termios * ttmode); /** * Change the logical (screen) size of the pty. * The default is 24 lines by 80 columns. * * This function can be used only while the PTY is open. * * @param lines the number of rows * @param columns the number of columns * @return @c true on success, false otherwise */ bool setWinSize(int lines, int columns); /** * Set whether the pty should echo input. * * Echo is on by default. * If the output of automatically fed (non-interactive) PTY clients * needs to be parsed, disabling echo often makes it much simpler. * * This function can be used only while the PTY is open. * * @param echo true if input should be echoed. * @return @c true on success, false otherwise */ bool setEcho(bool echo); /** * @return the name of the slave pty device. * * This function should be called only while the pty is open. */ const char * ttyName() const; /** * @return the file descriptor of the master pty * * This function should be called only while the pty is open. */ int masterFd() const; /** * @return the file descriptor of the slave pty * * This function should be called only while the pty slave is open. */ int slaveFd() const; protected: /** * @internal */ KPty(KPtyPrivate * d); /** * @internal */ KPtyPrivate * const d_ptr; }; #endif deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/kpty_p.h000066400000000000000000000024331475472654300246460ustar00rootroot00000000000000/* This file is part of the KDE libraries Copyright (C) 2003,2007 Oswald Buddenhagen This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Rewritten for QT4 by e_k , Copyright (C)2008 */ #ifndef kpty_p_h #define kpty_p_h #include "kpty.h" #include class KPtyPrivate { public: Q_DECLARE_PUBLIC(KPty) KPtyPrivate(KPty* parent); virtual ~KPtyPrivate(); bool chownpty(bool grant); int masterFd; int slaveFd; bool ownMaster:1; QByteArray ttyName; KPty *q_ptr; }; #endif deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/kptydevice.cpp000066400000000000000000000252601475472654300260450ustar00rootroot00000000000000/* * This file is a part of QTerminal - http://gitorious.org/qterminal * * This file was un-linked from KDE and modified * by Maxim Bourmistrov * */ /* This file is part of the KDE libraries Copyright (C) 2007 Oswald Buddenhagen Copyright (C) 2010 KDE e.V. Author Adriaan de Groot This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kptydevice.h" #include "kpty_p.h" #include #include #include #include #include #include #include #ifdef HAVE_SYS_FILIO_H # include #endif #ifdef HAVE_SYS_TIME_H # include #endif #if defined(Q_OS_FREEBSD) || defined(Q_OS_MAC) // "the other end's output queue size" - kinda braindead, huh? # define PTY_BYTES_AVAILABLE TIOCOUTQ #elif defined(TIOCINQ) // "our end's input queue size" # define PTY_BYTES_AVAILABLE TIOCINQ #else // likewise. more generic ioctl (theoretically) # define PTY_BYTES_AVAILABLE FIONREAD #endif ////////////////// // private data // ////////////////// // Lifted from Qt. I don't think they would mind. ;) // Re-lift again from Qt whenever a proper replacement for pthread_once appears static void qt_ignore_sigpipe() { static QBasicAtomicInt atom = Q_BASIC_ATOMIC_INITIALIZER(0); if (atom.testAndSetRelaxed(0, 1)) { struct sigaction noaction; memset(&noaction, 0, sizeof(noaction)); noaction.sa_handler = SIG_IGN; sigaction(SIGPIPE, &noaction, nullptr); } } #define NO_INTR(ret,func) do { ret = func; } while (ret < 0 && errno == EINTR) bool KPtyDevicePrivate::_k_canRead() { Q_Q(KPtyDevice); qint64 readBytes = 0; #ifdef Q_OS_IRIX // this should use a config define, but how to check it? size_t available; #else int available; #endif if (::ioctl(q->masterFd(), PTY_BYTES_AVAILABLE, (char *) &available) != -1) { #ifdef Q_OS_SOLARIS // A Pty is a STREAMS module, and those can be activated // with 0 bytes available. This happens either when ^C is // pressed, or when an application does an explicit write(a,b,0) // which happens in experiments fairly often. When 0 bytes are // available, you must read those 0 bytes to clear the STREAMS // module, but we don't want to hit the !readBytes case further down. if (!available) { char c; // Read the 0-byte STREAMS message NO_INTR(readBytes, read(q->masterFd(), &c, 0)); // Should return 0 bytes read; -1 is error if (readBytes < 0) { readNotifier->setEnabled(false); emit q->readEof(); return false; } return true; } #endif char *ptr = readBuffer.reserve(available); #ifdef Q_OS_SOLARIS // Even if available > 0, it is possible for read() // to return 0 on Solaris, due to 0-byte writes in the stream. // Ignore them and keep reading until we hit *some* data. // In Solaris it is possible to have 15 bytes available // and to (say) get 0, 0, 6, 0 and 9 bytes in subsequent reads. // Because the stream is set to O_NONBLOCK in finishOpen(), // an EOF read will return -1. readBytes = 0; while (!readBytes) #endif // Useless block braces except in Solaris { NO_INTR(readBytes, read(q->masterFd(), ptr, available)); } if (readBytes < 0) { readBuffer.unreserve(available); q->setErrorString(QLatin1String("Error reading from PTY")); return false; } readBuffer.unreserve(available - readBytes); // *should* be a no-op } if (!readBytes) { readNotifier->setEnabled(false); emit q->readEof(); return false; } else { if (!emittedReadyRead) { emittedReadyRead = true; emit q->readyRead(); emittedReadyRead = false; } return true; } } bool KPtyDevicePrivate::_k_canWrite() { Q_Q(KPtyDevice); writeNotifier->setEnabled(false); if (writeBuffer.isEmpty()) return false; qt_ignore_sigpipe(); int wroteBytes; NO_INTR(wroteBytes, write(q->masterFd(), writeBuffer.readPointer(), writeBuffer.readSize())); if (wroteBytes < 0) { q->setErrorString(QLatin1String("Error writing to PTY")); return false; } writeBuffer.free(wroteBytes); if (!emittedBytesWritten) { emittedBytesWritten = true; emit q->bytesWritten(wroteBytes); emittedBytesWritten = false; } if (!writeBuffer.isEmpty()) writeNotifier->setEnabled(true); return true; } #ifndef timeradd // Lifted from GLIBC # define timeradd(a, b, result) \ do { \ (result)->tv_sec = (a)->tv_sec + (b)->tv_sec; \ (result)->tv_usec = (a)->tv_usec + (b)->tv_usec; \ if ((result)->tv_usec >= 1000000) { \ ++(result)->tv_sec; \ (result)->tv_usec -= 1000000; \ } \ } while (0) # define timersub(a, b, result) \ do { \ (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \ (result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \ if ((result)->tv_usec < 0) { \ --(result)->tv_sec; \ (result)->tv_usec += 1000000; \ } \ } while (0) #endif bool KPtyDevicePrivate::doWait(int msecs, bool reading) { Q_Q(KPtyDevice); #ifndef __linux__ struct timeval etv; #endif struct timeval tv, *tvp; if (msecs < 0) tvp = nullptr; else { tv.tv_sec = msecs / 1000; tv.tv_usec = (msecs % 1000) * 1000; #ifndef __linux__ gettimeofday(&etv, 0); timeradd(&tv, &etv, &etv); #endif tvp = &tv; } while (reading ? readNotifier->isEnabled() : !writeBuffer.isEmpty()) { fd_set rfds; fd_set wfds; FD_ZERO(&rfds); FD_ZERO(&wfds); if (readNotifier->isEnabled()) FD_SET(q->masterFd(), &rfds); if (!writeBuffer.isEmpty()) FD_SET(q->masterFd(), &wfds); #ifndef __linux__ if (tvp) { gettimeofday(&tv, 0); timersub(&etv, &tv, &tv); if (tv.tv_sec < 0) tv.tv_sec = tv.tv_usec = 0; } #endif switch (select(q->masterFd() + 1, &rfds, &wfds, nullptr, tvp)) { case -1: if (errno == EINTR) break; return false; case 0: q->setErrorString(QLatin1String("PTY operation timed out")); return false; default: if (FD_ISSET(q->masterFd(), &rfds)) { bool canRead = _k_canRead(); if (reading && canRead) return true; } if (FD_ISSET(q->masterFd(), &wfds)) { bool canWrite = _k_canWrite(); if (!reading) return canWrite; } break; } } return false; } void KPtyDevicePrivate::finishOpen(QIODevice::OpenMode mode) { Q_Q(KPtyDevice); q->QIODevice::open(mode); fcntl(q->masterFd(), F_SETFL, O_NONBLOCK); readBuffer.clear(); readNotifier = new QSocketNotifier(q->masterFd(), QSocketNotifier::Read, q); writeNotifier = new QSocketNotifier(q->masterFd(), QSocketNotifier::Write, q); QObject::connect(readNotifier, SIGNAL(activated(int)), q, SLOT(_k_canRead())); QObject::connect(writeNotifier, SIGNAL(activated(int)), q, SLOT(_k_canWrite())); readNotifier->setEnabled(true); } ///////////////////////////// // public member functions // ///////////////////////////// KPtyDevice::KPtyDevice(QObject *parent) : QIODevice(parent), KPty(new KPtyDevicePrivate(this)) { } KPtyDevice::~KPtyDevice() { close(); } bool KPtyDevice::open(OpenMode mode) { Q_D(KPtyDevice); if (masterFd() >= 0) return true; if (!KPty::open()) { setErrorString(QLatin1String("Error opening PTY")); return false; } d->finishOpen(mode); return true; } bool KPtyDevice::open(int fd, OpenMode mode) { Q_D(KPtyDevice); if (!KPty::open(fd)) { setErrorString(QLatin1String("Error opening PTY")); return false; } d->finishOpen(mode); return true; } void KPtyDevice::close() { Q_D(KPtyDevice); if (masterFd() < 0) return; delete d->readNotifier; delete d->writeNotifier; QIODevice::close(); KPty::close(); } bool KPtyDevice::isSequential() const { return true; } bool KPtyDevice::canReadLine() const { Q_D(const KPtyDevice); return QIODevice::canReadLine() || d->readBuffer.canReadLine(); } bool KPtyDevice::atEnd() const { Q_D(const KPtyDevice); return QIODevice::atEnd() && d->readBuffer.isEmpty(); } qint64 KPtyDevice::bytesAvailable() const { Q_D(const KPtyDevice); return QIODevice::bytesAvailable() + d->readBuffer.size(); } qint64 KPtyDevice::bytesToWrite() const { Q_D(const KPtyDevice); return d->writeBuffer.size(); } bool KPtyDevice::waitForReadyRead(int msecs) { Q_D(KPtyDevice); return d->doWait(msecs, true); } bool KPtyDevice::waitForBytesWritten(int msecs) { Q_D(KPtyDevice); return d->doWait(msecs, false); } void KPtyDevice::setSuspended(bool suspended) { Q_D(KPtyDevice); d->readNotifier->setEnabled(!suspended); } bool KPtyDevice::isSuspended() const { Q_D(const KPtyDevice); return !d->readNotifier->isEnabled(); } // protected qint64 KPtyDevice::readData(char *data, qint64 maxlen) { Q_D(KPtyDevice); return d->readBuffer.read(data, (int)qMin(maxlen, KMAXINT)); } // protected qint64 KPtyDevice::readLineData(char *data, qint64 maxlen) { Q_D(KPtyDevice); return d->readBuffer.readLine(data, (int)qMin(maxlen, KMAXINT)); } // protected qint64 KPtyDevice::writeData(const char *data, qint64 len) { Q_D(KPtyDevice); Q_ASSERT(len <= KMAXINT); d->writeBuffer.write(data, len); d->writeNotifier->setEnabled(true); return len; } deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/kptydevice.h000066400000000000000000000222131475472654300255050ustar00rootroot00000000000000/* * This file is a part of QTerminal - http://gitorious.org/qterminal * * This file was un-linked from KDE and modified * by Maxim Bourmistrov * */ /* This file is part of the KDE libraries Copyright (C) 2007 Oswald Buddenhagen This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef kptydev_h #define kptydev_h #include "kpty_p.h" #include #define KMAXINT ((int)(~0U >> 1)) struct KPtyDevicePrivate; 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 struct Class##Private; /** * Encapsulates KPty into a QIODevice, so it can be used with Q*Stream, etc. */ class KPtyDevice : public QIODevice, public KPty { Q_OBJECT Q_DECLARE_PRIVATE_MI(KPtyDevice, KPty) public: /** * Constructor */ KPtyDevice(QObject *parent = nullptr); /** * Destructor: * * If the pty is still open, it will be closed. Note, however, that * an utmp registration is @em not undone. */ ~KPtyDevice() override; /** * Create a pty master/slave pair. * * @return true if a pty pair was successfully opened */ bool open(OpenMode mode = ReadWrite | Unbuffered) override; /** * Open using an existing pty master. The ownership of the fd * remains with the caller, i.e., close() will not close the fd. * * This is useful if you wish to attach a secondary "controller" to an * existing pty device such as a terminal widget. * Note that you will need to use setSuspended() on both devices to * control which one gets the incoming data from the pty. * * @param fd an open pty master file descriptor. * @param mode the device mode to open the pty with. * @return true if a pty pair was successfully opened */ bool open(int fd, OpenMode mode = ReadWrite | Unbuffered); /** * Close the pty master/slave pair. */ void close() override; /** * Sets whether the KPtyDevice monitors the pty for incoming data. * * When the KPtyDevice is suspended, it will no longer attempt to buffer * data that becomes available from the pty and it will not emit any * signals. * * Do not use on closed ptys. * After a call to open(), the pty is not suspended. If you need to * ensure that no data is read, call this function before the main loop * is entered again (i.e., immediately after opening the pty). */ void setSuspended(bool suspended); /** * Returns true if the KPtyDevice is not monitoring the pty for incoming * data. * * Do not use on closed ptys. * * See setSuspended() */ bool isSuspended() const; /** * @return always true */ bool isSequential() const override; /** * @reimp */ bool canReadLine() const override; /** * @reimp */ bool atEnd() const override; /** * @reimp */ qint64 bytesAvailable() const override; /** * @reimp */ qint64 bytesToWrite() const override; bool waitForBytesWritten(int msecs = -1) override; bool waitForReadyRead(int msecs = -1) override; Q_SIGNALS: /** * Emitted when EOF is read from the PTY. * * Data may still remain in the buffers. */ void readEof(); protected: qint64 readData(char *data, qint64 maxSize) override; qint64 readLineData(char *data, qint64 maxSize) override; qint64 writeData(const char *data, qint64 maxSize) override; private: Q_PRIVATE_SLOT(d_func(), bool _k_canRead()) Q_PRIVATE_SLOT(d_func(), bool _k_canWrite()) }; ///////////////////////////////////////////////////// // Helper. Remove when QRingBuffer becomes public. // ///////////////////////////////////////////////////// #include #include #define CHUNKSIZE 4096 class KRingBuffer { public: KRingBuffer() { clear(); } void clear() { buffers.clear(); QByteArray tmp; tmp.resize(CHUNKSIZE); buffers.push_back(tmp); head = tail = 0; totalSize = 0; } inline bool isEmpty() const { return buffers.size() == 1 && !tail; } inline int size() const { return totalSize; } inline int readSize() const { return (buffers.size() == 1 ? tail : buffers.front().size()) - head; } inline const char *readPointer() const { Q_ASSERT(totalSize > 0); return buffers.front().constData() + head; } void free(int bytes) { totalSize -= bytes; Q_ASSERT(totalSize >= 0); forever { int nbs = readSize(); if (bytes < nbs) { head += bytes; if (head == tail && buffers.size() == 1) { buffers.front().resize(CHUNKSIZE); head = tail = 0; } break; } bytes -= nbs; if (buffers.size() == 1) { buffers.front().resize(CHUNKSIZE); head = tail = 0; break; } buffers.pop_front(); head = 0; } } char *reserve(int bytes) { totalSize += bytes; char *ptr; if (tail + bytes <= buffers.back().size()) { ptr = buffers.back().data() + tail; tail += bytes; } else { buffers.back().resize(tail); QByteArray tmp; tmp.resize(qMax(CHUNKSIZE, bytes)); ptr = tmp.data(); buffers.push_back(tmp); tail = bytes; } return ptr; } // release a trailing part of the last reservation inline void unreserve(int bytes) { totalSize -= bytes; tail -= bytes; } inline void write(const char *data, int len) { memcpy(reserve(len), data, len); } // Find the first occurrence of c and return the index after it. // If c is not found until maxLength, maxLength is returned, provided // it is smaller than the buffer size. Otherwise -1 is returned. int indexAfter(char c, int maxLength = KMAXINT) const { int index = 0; int start = head; std::list::const_iterator it = buffers.cbegin(); forever { if (!maxLength) return index; if (index == size()) return -1; const QByteArray &buf = *it; ++it; int len = qMin((it == buffers.cend() ? tail : buf.size()) - start, maxLength); const char *ptr = buf.data() + start; if (const char *rptr = (const char *)memchr(ptr, c, len)) return index + (rptr - ptr) + 1; index += len; maxLength -= len; start = 0; } } inline int lineSize(int maxLength = KMAXINT) const { return indexAfter('\n', maxLength); } inline bool canReadLine() const { return lineSize() != -1; } int read(char *data, int maxLength) { int bytesToRead = qMin(size(), maxLength); int readSoFar = 0; while (readSoFar < bytesToRead) { const char *ptr = readPointer(); int bs = qMin(bytesToRead - readSoFar, readSize()); memcpy(data + readSoFar, ptr, bs); readSoFar += bs; free(bs); } return readSoFar; } int readLine(char *data, int maxLength) { return read(data, lineSize(qMin(maxLength, size()))); } private: std::list buffers; int head, tail; int totalSize; }; struct KPtyDevicePrivate : public KPtyPrivate { Q_DECLARE_PUBLIC(KPtyDevice) KPtyDevicePrivate(KPty* parent) : KPtyPrivate(parent), emittedReadyRead(false), emittedBytesWritten(false), readNotifier(nullptr), writeNotifier(nullptr) { } bool _k_canRead(); bool _k_canWrite(); bool doWait(int msecs, bool reading); void finishOpen(QIODevice::OpenMode mode); bool emittedReadyRead; bool emittedBytesWritten; QSocketNotifier *readNotifier; QSocketNotifier *writeNotifier; KRingBuffer readBuffer; KRingBuffer writeBuffer; }; #endif deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/kptyprocess.cpp000066400000000000000000000071231475472654300262620ustar00rootroot00000000000000/* * This file is a part of QTerminal - http://gitorious.org/qterminal * * This file was un-linked from KDE and modified * by Maxim Bourmistrov * */ /* This file is part of the KDE libraries Copyright (C) 2007 Oswald Buddenhagen This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kptyprocess.h" #include "kprocess.h" #include "kptydevice.h" #include #include #include #include KPtyProcess::KPtyProcess(QObject *parent) : KProcess(new KPtyProcessPrivate, parent) { Q_D(KPtyProcess); d->pty = new KPtyDevice(this); d->pty->open(); connect(this, SIGNAL(stateChanged(QProcess::ProcessState)), SLOT(_k_onStateChanged(QProcess::ProcessState))); } KPtyProcess::KPtyProcess(int ptyMasterFd, QObject *parent) : KProcess(new KPtyProcessPrivate, parent) { Q_D(KPtyProcess); d->pty = new KPtyDevice(this); d->pty->open(ptyMasterFd); connect(this, SIGNAL(stateChanged(QProcess::ProcessState)), SLOT(_k_onStateChanged(QProcess::ProcessState))); } KPtyProcess::~KPtyProcess() { Q_D(KPtyProcess); 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(static_cast(processId()), 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) { Q_D(KPtyProcess); d->ptyChannels = channels; } KPtyProcess::PtyChannels KPtyProcess::ptyChannels() const { Q_D(const KPtyProcess); return d->ptyChannels; } void KPtyProcess::setUseUtmp(bool value) { Q_D(KPtyProcess); d->addUtmp = value; } bool KPtyProcess::isUseUtmp() const { Q_D(const KPtyProcess); return d->addUtmp; } KPtyDevice *KPtyProcess::pty() const { Q_D(const KPtyProcess); return d->pty; } void KPtyProcess::setupChildProcess() { Q_D(KPtyProcess); d->pty->setCTty(); #if 0 if (d->addUtmp) d->pty->login(KUser(KUser::UseRealUserID).loginName().toLocal8Bit().data(), qgetenv("DISPLAY")); #endif if (d->ptyChannels & StdinChannel) dup2(d->pty->slaveFd(), 0); if (d->ptyChannels & StdoutChannel) dup2(d->pty->slaveFd(), 1); if (d->ptyChannels & StderrChannel) dup2(d->pty->slaveFd(), 2); KProcess::setupChildProcess(); } //#include "kptyprocess.moc" deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/kptyprocess.h000066400000000000000000000113261475472654300257270ustar00rootroot00000000000000/* * This file is a part of QTerminal - http://gitorious.org/qterminal * * This file was un-linked from KDE and modified * by Maxim Bourmistrov * */ /* This file is part of the KDE libraries Copyright (C) 2007 Oswald Buddenhagen This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KPTYPROCESS_H #define KPTYPROCESS_H #include "kprocess.h" #include "kptydevice.h" #include class KPtyDevice; class KPtyProcessPrivate; /** * This class extends KProcess by support for PTYs (pseudo TTYs). * * The PTY is opened as soon as the class is instantiated. Verify that * it was opened successfully by checking that pty()->masterFd() is not -1. * * The PTY is always made the process' controlling TTY. * Utmp registration and connecting the stdio handles to the PTY are optional. * * No attempt to integrate with QProcess' waitFor*() functions was made, * for it is impossible. Note that execute() does not work with the PTY, too. * Use the PTY device's waitFor*() functions or use it asynchronously. * * @author Oswald Buddenhagen */ class KPtyProcess : public KProcess { Q_OBJECT Q_DECLARE_PRIVATE(KPtyProcess) public: enum PtyChannelFlag { NoChannels = 0, /**< The PTY is not connected to any channel. */ StdinChannel = 1, /**< Connect PTY to stdin. */ StdoutChannel = 2, /**< Connect PTY to stdout. */ StderrChannel = 4, /**< Connect PTY to stderr. */ AllOutputChannels = 6, /**< Connect PTY to all output channels. */ AllChannels = 7 /**< Connect PTY to all channels. */ }; Q_DECLARE_FLAGS(PtyChannels, PtyChannelFlag) /** * Constructor */ explicit KPtyProcess(QObject *parent = nullptr); /** * Construct a process using an open pty master. * * @param ptyMasterFd an open pty master file descriptor. * The process does not take ownership of the descriptor; * it will not be automatically closed at any point. */ KPtyProcess(int ptyMasterFd, QObject *parent = nullptr); /** * Destructor */ ~KPtyProcess() override; /** * Set to which channels the PTY should be assigned. * * This function must be called before starting the process. * * @param channels the output channel handling mode */ void setPtyChannels(PtyChannels channels); bool isRunning() const { bool rval; (processId() > 0) ? rval= true : rval= false; return rval; } /** * Query to which channels the PTY is assigned. * * @return the output channel handling mode */ PtyChannels ptyChannels() const; /** * Set whether to register the process as a TTY login in utmp. * * Utmp is disabled by default. * It should enabled for interactively fed processes, like terminal * emulations. * * This function must be called before starting the process. * * @param value whether to register in utmp. */ void setUseUtmp(bool value); /** * Get whether to register the process as a TTY login in utmp. * * @return whether to register in utmp */ bool isUseUtmp() const; /** * Get the PTY device of this process. * * @return the PTY device */ KPtyDevice *pty() const; protected: /** * @reimp */ void setupChildProcess() override; private: Q_PRIVATE_SLOT(d_func(), void _k_onStateChanged(QProcess::ProcessState)) }; ////////////////// // private data // ////////////////// class KPtyProcessPrivate : public KProcessPrivate { public: KPtyProcessPrivate() : ptyChannels(KPtyProcess::NoChannels), addUtmp(false) { } void _k_onStateChanged(QProcess::ProcessState newState) { if (newState == QProcess::NotRunning && addUtmp) pty->logout(); } KPtyDevice *pty; KPtyProcess::PtyChannels ptyChannels; bool addUtmp : 1; }; Q_DECLARE_OPERATORS_FOR_FLAGS(KPtyProcess::PtyChannels) #endif deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/qtermwidget.cpp000066400000000000000000000775221475472654300262420ustar00rootroot00000000000000/* Copyright (C) 2008 e_k (e_k@users.sourceforge.net) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include "ColorTables.h" #include "Session.h" #include "SessionManager.h" #include "Screen.h" #include "ScreenWindow.h" #include "Emulation.h" #include "TerminalDisplay.h" #include "KeyboardTranslator.h" #include "ColorScheme.h" #include "SearchBar.h" #include "qtermwidget.h" #include "history/compact/CompactHistoryType.h" #include "history/HistoryTypeFile.h" #ifdef Q_OS_MACOS // Qt does not support fontconfig on macOS, so we need to use a "real" font name. #define DEFAULT_FONT_FAMILY "Menlo" #else #define DEFAULT_FONT_FAMILY "Monospace" #endif #define STEP_ZOOM 1 using namespace Konsole; // 翻译文件加载 QTranslator *QTermWidget::m_translator = nullptr; void *createTermWidget(int startnow, void *parent) { return (void *) new QTermWidget(startnow, (QWidget *)parent); } struct TermWidgetImpl { explicit TermWidgetImpl(QWidget *parent = 0); TerminalDisplay *m_terminalDisplay; Session *m_session; Session *createSession(QWidget *parent); TerminalDisplay *createTerminalDisplay(Session *session, QWidget *parent); }; TermWidgetImpl::TermWidgetImpl(QWidget *parent) { this->m_session = createSession(parent); SessionManager::instance()->saveSession(this->m_session); this->m_terminalDisplay = createTerminalDisplay(this->m_session, parent); this->m_terminalDisplay->setSessionId(this->m_session->sessionId()); } Session *TermWidgetImpl::createSession(QWidget *parent) { Session *session = new Session(parent); session->setTitle(Session::NameRole, QLatin1String("Terminal")); /* Thats a freaking bad idea!!!! * /bin/bash is not there on every system * better set it to the current $SHELL * Maybe you can also make a list available and then let the widget-owner decide what to use. * By setting it to $SHELL right away we actually make the first filecheck obsolete. * But as iam not sure if you want to do anything else ill just let both checks in and set this to $SHELL anyway. */ //session->setProgram("/bin/bash"); session->setProgram(QString::fromLocal8Bit(qgetenv("SHELL"))); QStringList args = QStringList(QString()); session->setArguments(args); session->setAutoClose(true); session->setCodec(QTextCodec::codecForName("UTF-8")); session->setFlowControlEnabled(true); session->setHistoryType(CompactHistoryType(10000)); session->setDarkBackground(true); session->setKeyBindings(QString()); return session; } TerminalDisplay *TermWidgetImpl::createTerminalDisplay(Session *session, QWidget *parent) { //TerminalDisplay* display = new TerminalDisplay(this); TerminalDisplay *display = new TerminalScreen(parent); display->setBellMode(TerminalDisplay::NotifyBell); display->setTerminalSizeHint(true); display->setTripleClickMode(TerminalDisplay::SelectWholeLine); display->setTerminalSizeStartup(true); display->setHideCursor(true); display->setRandomSeed(session->sessionId() * 31); return display; } QTermWidget::QTermWidget(int startnow, QWidget *parent) : QWidget(parent) { init(startnow); } QTermWidget::QTermWidget(QWidget *parent) : QWidget(parent) { init(1); } void QTermWidget::selectionChanged(bool textSelected) { emit copyAvailable(textSelected); } void QTermWidget::search(QString txt, bool forwards, bool next) { /***mod begin by ut001121 zhangmeng 20200515 修复BUG22626***/ int startColumn, startLine; if (m_bHasSelect) { /***mod begin by ut001121 zhangmeng 20200814 修复BUG40895***/ if (next) { startColumn = m_endColumn + 1; startLine = m_endLine; } else { if (m_startColumn == 0) { startColumn = -1; startLine = m_startLine > 0 ? m_startLine - 1 : m_impl->m_session->emulation()->lineCount(); } else { startColumn = m_startColumn; startLine = m_startLine; } } /***mod end by ut001121 zhangmeng 20200814***/ } else if (next) { // search from just after current selection m_impl->m_terminalDisplay->screenWindow()->screen()->getSelectionEnd(startColumn, startLine); startColumn++; } else { // search from start of current selection 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 backwardsPosition" << m_lastBackwardsPosition << endl; QString searchText(txt); // qDebug() << "regExp??????" << regExp.isEmpty(); //regExp.setPatternSyntax(QRegExp::FixedString); //regExp.setCaseSensitivity(Qt::CaseSensitive); HistorySearch *historySearch = new HistorySearch(m_impl->m_session->emulation(), searchText, forwards, m_isLastForwards, startColumn, startLine, this); connect(historySearch, SIGNAL(matchFound(int, int, int, int, int, int, int)), this, SLOT(matchFound(int, int, int, int, int, int, int))); connect(this, SIGNAL(sig_noMatchFound()), this, SLOT(clearSelection())); connect(historySearch, &HistorySearch::noMatchFound, this, [this]() { emit sig_noMatchFound(); }); // connect(historySearch, SIGNAL(noMatchFound()), m_searchBar, SLOT(noMatchFound())); historySearch->search(m_lastBackwardsPosition, m_startColumn, m_startLine); /***mod end by ut001121***/ m_isLastForwards = forwards; } void QTermWidget::matchFound(int startColumn, int startLine, int endColumn, int endLine, int lastBackwardsPosition, int loseChinese, int matchChinese) { /***mod begin by ut001121 zhangmeng 20200515 修复BUG22626***/ m_bHasSelect = true; m_startColumn = startColumn; m_startLine = startLine; m_endColumn = endColumn; m_endLine = endLine; if (lastBackwardsPosition != -1) { m_lastBackwardsPosition = lastBackwardsPosition; } ScreenWindow *sw = m_impl->m_terminalDisplay->screenWindow(); qDebug() << "Scroll to" << startLine; sw->scrollTo(startLine); sw->setTrackOutput(false); sw->setSelectionStart(startColumn + loseChinese, startLine - sw->currentLine(), false); sw->setSelectionEnd(endColumn + matchChinese, endLine - sw->currentLine()); sw->notifyOutputChanged(); /***mod end by ut001121***/ // 结束查找 emit sig_matchFound(); } void QTermWidget::clearSelection() { /***add by ut001121 zhangmeng 20200515 修复BUG22626***/ m_bHasSelect = false; m_impl->m_terminalDisplay->screenWindow()->clearSelection(); } void QTermWidget::noMatchFound() { /***add by ut001121 zhangmeng 20200515 修复BUG22626***/ m_bHasSelect = false; m_impl->m_terminalDisplay->screenWindow()->clearSelection(); } int QTermWidget::getShellPID() { return m_impl->m_session->processId(); } int QTermWidget::getSessionId() { int currSessionId = m_impl->m_session->sessionId(); return currSessionId; } void QTermWidget::snapshot() { Q_ASSERT(m_impl->m_session != nullptr); Session *currSession = m_impl->m_session; // use process name as tab title, which not for display QString title = currSession->getDynamicProcessName(); title = title.simplified(); // use the fallback title if needed if (title.isEmpty()) { title = currSession->title(Session::NameRole); } // apply new title currSession->setTitle(Session::DisplayedTitleRole, title); if (currSession->isForegroundProcessActive()) { emit isTermIdle(false); } else { emit isTermIdle(true); } } void QTermWidget::changeDir(const QString &dir) { /* this is a very hackish way of trying to determine if the shell is in the foreground before attempting to change the directory. It may not be portable to anything other than Linux. */ QString strCmd; strCmd.setNum(getShellPID()); 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 = QLatin1String("cd ") + dir + QLatin1Char('\n'); sendText(cmd); } } QSize QTermWidget::sizeHint() const { QSize size = m_impl->m_terminalDisplay->sizeHint(); size.rheight() = 150; return size; } void QTermWidget::setTerminalSizeHint(bool on) { m_impl->m_terminalDisplay->setTerminalSizeHint(on); } bool QTermWidget::terminalSizeHint() { return m_impl->m_terminalDisplay->terminalSizeHint(); } void QTermWidget::startShellProgram() { if (m_impl->m_session->isRunning()) { return; } m_impl->m_session->run(); // add snapshot timer when session start running addSnapShotTimer(); } // take a snapshot of the session state every so often when // user activity occurs void QTermWidget::addSnapShotTimer() { // the timer is owned by the session so that it will be destroyed along // with the session Session *currSession = m_impl->m_session; m_interactionTimer = new QTimer(currSession); m_interactionTimer->setSingleShot(true); m_interactionTimer->setInterval(500); m_termDisplay = m_impl->m_terminalDisplay; connect(m_interactionTimer, &QTimer::timeout, this, &QTermWidget::snapshot); connect(m_termDisplay.data(), &Konsole::TerminalDisplay::keyPressedSignal, this, &QTermWidget::interactionHandler); // take a snapshot of the session state periodically in the background auto backgroundTimer = new QTimer(currSession); backgroundTimer->setSingleShot(false); backgroundTimer->setInterval(2000); connect(backgroundTimer, &QTimer::timeout, this, &QTermWidget::snapshot); backgroundTimer->start(); } void QTermWidget::interactionHandler() { m_interactionTimer->start(); } /******************************************************************************* 1. @函数: setisAllowScroll 2. @作者: ut000610 戴正文 3. @日期: 2020-09-14 4. @说明: 设置是否允许滚动到最新的位置 当有输出且并不是在setZoom之后,此标志为true 允许滚动 当有输出且在setZoom之后,比标志位false 不允许滚动 *******************************************************************************/ void QTermWidget::setIsAllowScroll(bool isAllowScroll) { m_impl->m_terminalDisplay->setIsAllowScroll(isAllowScroll); } /******************************************************************************* 1. @函数: setNoHasSelect 2. @作者: ut001000 任飞翔 3. @日期: 2020-12-02 4. @说明: 当搜索框出现时,设置m_bHasSelect为false,避免搜索框隐藏再显示之后,继续走m_bHasSelect为true流程,导致崩溃 *******************************************************************************/ void QTermWidget::setNoHasSelect() { if(m_bHasSelect) { //清除搜索状态 m_lastBackwardsPosition = -1; m_isLastForwards = false; m_startColumn = 0; m_startLine = 0; m_endColumn = 0; m_endLine = 0; } m_bHasSelect = false; } /******************************************************************************* 1. @函数: getisAllowScroll 2. @作者: ut000610 戴正文 3. @日期: 2020-09-14 4. @说明: 获取是否允许输出时滚动 *******************************************************************************/ bool QTermWidget::getIsAllowScroll() const { return m_impl->m_terminalDisplay->getIsAllowScroll(); } 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, const QTextCodec *)), this, SIGNAL(sendData(const char *, int, const QTextCodec *))); } 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")); #if (QT_VERSION >= QT_VERSION_CHECK(5,15,0)) QStringList dirs = d.split(QLatin1Char(':'), Qt::SkipEmptyParts); #else QStringList dirs = d.split(QLatin1Char(':'), QString::SkipEmptyParts); #endif if (dirs.isEmpty()) { dirs.append(QString::fromLatin1("/usr/local/share")); dirs.append(QString::fromLatin1("/usr/share")); } dirs.append(QFile::decodeName(TRANSLATIONS_DIR)); // 语言,整个应用程序只需要设置一次 if (nullptr == m_translator) { // 绑定的父类需要是全局的,不能是this防止窗口被关闭后翻译也随之消失 m_translator = new QTranslator(qApp); for (const QString &dir : qAsConst(dirs)) { qDebug() << "Trying to load translation file from dir" << dir; if (m_translator->load( QLocale::system(), QLatin1String("terminalwidget"), QLatin1String(QLatin1String("_")), dir)) { qApp->installTranslator(m_translator); qDebug() << "Translations found in" << dir; break; } } } m_impl = new TermWidgetImpl(this); m_layout->addWidget(m_impl->m_terminalDisplay); connect(m_impl->m_session, SIGNAL(bellRequest(QString)), m_impl->m_terminalDisplay, SLOT(bell(QString))); connect(m_impl->m_terminalDisplay, SIGNAL(notifyBell(QString)), this, SIGNAL(bell(QString))); 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); connect(m_impl->m_session, &Session::started, this, &QTermWidget::processStarted); // 标签标题参数变化 connect(m_impl->m_session, &Session::titleArgsChange, this, &QTermWidget::titleArgsChange); /******** Modify by nt001000 renfeixiang 2020-05-27:修改 增加参数区别remove和purge卸载命令 Begin***************/ // 用于卸载终端弹出框提示 connect(m_impl->m_session, SIGNAL(sessionUninstallTerminal(QString)), this, SIGNAL(uninstallTerminal(QString))); /******** Modify by nt001000 renfeixiang 2020-05-27:修改 增加参数区别remove和purge卸载命令 Begin***************/ connect(m_impl->m_session, &Session::titleChanged, this, [ = ] { m_impl->m_terminalDisplay->setHideCursor(false); }); // That's OK, FilterChain's dtor takes care of UrlFilter. UrlFilter *urlFilter = new UrlFilter(); connect(urlFilter, &UrlFilter::activated, this, &QTermWidget::urlActivated); m_impl->m_terminalDisplay->filterChain()->addFilter(urlFilter); m_impl->m_terminalDisplay->filterChain()->setSessionId(m_impl->m_session->sessionId()); // m_searchBar = new SearchBar(this); // m_searchBar->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Maximum); // connect(m_searchBar, SIGNAL(searchCriteriaChanged()), this, SLOT(find())); // connect(m_searchBar, SIGNAL(findNext()), this, SLOT(findNext())); // connect(m_searchBar, SIGNAL(findPrevious()), this, SLOT(findPrevious())); // m_layout->addWidget(m_searchBar); // m_searchBar->hide(); if (startnow && m_impl->m_session) { m_impl->m_session->run(); } this->setFocus(Qt::OtherFocusReason); this->setFocusPolicy(Qt::WheelFocus); m_impl->m_terminalDisplay->resize(this->size()); this->setFocusProxy(m_impl->m_terminalDisplay); connect(m_impl->m_terminalDisplay, SIGNAL(copyAvailable(bool)), this, SLOT(selectionChanged(bool))); connect(m_impl->m_terminalDisplay, SIGNAL(termGetFocus()), this, SIGNAL(termGetFocus())); connect(m_impl->m_terminalDisplay, SIGNAL(leftMouseClick()), this, SIGNAL(leftMouseClick())); connect(m_impl->m_terminalDisplay, SIGNAL(termLostFocus()), this, SIGNAL(termLostFocus())); // 将拖拽进入的urls名返回给终端 将要转发给Emu的数据 connect(m_impl->m_terminalDisplay, SIGNAL(sendStringToEmu(const char *)), this, SIGNAL(sendUrlsToTerm(const char *))); connect( m_impl->m_terminalDisplay, SIGNAL(keyPressedSignal(QKeyEvent *)), this, SIGNAL(termKeyPressed(QKeyEvent *))); // m_impl->m_terminalDisplay->setSize(80, 40); QFont font = QApplication::font(); font.setFamily(QLatin1String(DEFAULT_FONT_FAMILY)); 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); connect(m_impl->m_session, &Session::shellWarningMessage, this, &QTermWidget::shellWarningMessage); //将终端活动状态传给SessionManager单例 connect(this, SIGNAL(isTermIdle(bool)), SessionManager::instance(), SIGNAL(sessionIdle(bool))); } QTermWidget::~QTermWidget() { SessionManager::instance()->removeSession(m_impl->m_session->sessionId()); delete m_impl; emit destroyed(); } QList QTermWidget::getRunningSessionIdList() { SessionManager *sessionMgr = SessionManager::instance(); QList sessionList = sessionMgr->sessions(); QList sessionIdList; for (int i = 0; i < sessionList.size(); i++) { Session *session = sessionList.at(i); if ((session == nullptr) || !session->isForegroundProcessActive()) { continue; } sessionIdList.append(session->sessionId()); } return sessionIdList; } bool QTermWidget::hasRunningProcess() { QList sessionIdList = getRunningSessionIdList(); for (int i = 0; i < sessionIdList.size(); i++) { int sessionId = sessionIdList.at(i); int currSessionId = m_impl->m_session->sessionId(); if (sessionId == currSessionId) { return true; } } return false; } void QTermWidget::setTerminalFont(const QFont &font) { m_impl->m_terminalDisplay->setVTFont(font); } QFont QTermWidget::getTerminalFont() { return m_impl->m_terminalDisplay->getVTFont(); } void QTermWidget::setTerminalOpacity(qreal level) { m_impl->m_terminalDisplay->setOpacity(level); } void QTermWidget::setTerminalBackgroundImage(QString backgroundImage) { m_impl->m_terminalDisplay->setBackgroundImage(backgroundImage); } void QTermWidget::setShellProgram(const QString &progname) { if (!m_impl->m_session) return; m_impl->m_session->setProgram(progname); qDebug() << "set Program" << progname; } void QTermWidget::setWorkingDirectory(const QString &dir) { if (!m_impl->m_session) return; m_impl->m_session->setInitialWorkingDirectory(dir); } QString QTermWidget::workingDirectory() { if (!m_impl->m_session) return QString(); #ifdef Q_OS_LINUX // 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::fromLatin1("/proc/%1/cwd").arg(getShellPID())); if (!d.exists()) { qDebug() << "Cannot find" << d.dirName(); goto fallback; } return d.canonicalPath(); fallback: #endif // fallback, initial WD return m_impl->m_session->initialWorkingDirectory(); } void QTermWidget::setArgs(const QStringList &args) { if (!m_impl->m_session) return; m_impl->m_session->setArguments(args); qDebug() << "set Arguments" << args; } void QTermWidget::setTextCodec(QTextCodec *codec) { if (!m_impl->m_session) return; m_impl->m_session->setCodec(codec); QString str(codec->name()); if(str == "GB18030"){ setIsCodecGB18030(true); }else{ setIsCodecGB18030(false); } } /******************************************************************************* 1. @函数: setColorScheme 2. @作者: ut000125 sunchengxi 3. @日期: 2020-12-01 4. @说明: 设置主题的配色方案,根据参数 needReloadTheme 判断是否需要重新加载 *******************************************************************************/ void QTermWidget::setColorScheme(const QString &origName, bool needReloadTheme) { const ColorScheme *cs = nullptr; const bool isFile = QFile::exists(origName); const QString &name = isFile ? QFileInfo(origName).baseName() : origName; // avoid legacy (int) solution if (!availableColorSchemes().contains(name)) { if (isFile) { if (ColorSchemeManager::instance()->loadCustomColorScheme(origName)) { cs = ColorSchemeManager::instance()->findColorScheme(name); } else { qWarning() << Q_FUNC_INFO << "cannot load color scheme from" << origName; } } if (!cs) { cs = ColorSchemeManager::instance()->defaultColorScheme(); } } else { if (name == "customTheme" && needReloadTheme) { ColorSchemeManager::instance()->realodColorScheme(origName); } cs = ColorSchemeManager::instance()->findColorScheme(name); } if (!cs) { QMessageBox::information(this, tr("Color Scheme Error"), tr("Cannot load color scheme: %1").arg(name)); return; } ColorEntry table[TABLE_COLORS]; cs->getColorTable(table); m_impl->m_terminalDisplay->setColorTable(table); } QStringList QTermWidget::availableColorSchemes() { QStringList ret; const auto allColorSchemes = ColorSchemeManager::instance()->allColorSchemes(); for (const ColorScheme *cs : allColorSchemes) ret.append(cs->name()); return ret; } void QTermWidget::addCustomColorSchemeDir(const QString &custom_dir) { ColorSchemeManager::instance()->addCustomColorSchemeDir(custom_dir); } void QTermWidget::setSize(const QSize &size) { m_impl->m_terminalDisplay->setSize(size.width(), size.height()); } void QTermWidget::setHistorySize(int lines) { if (lines < 0) m_impl->m_session->setHistoryType(HistoryTypeFile()); else m_impl->m_session->setHistoryType(CompactHistoryType(lines)); } void QTermWidget::setScrollBarPosition(ScrollBarPosition pos) { m_impl->m_terminalDisplay->setScrollBarPosition(pos); } void QTermWidget::scrollToEnd() { m_impl->m_terminalDisplay->scrollToEnd(); } /******************************************************************************* 1. @函数: setTrackOutput 2. @作者: n014361 王培利 3. @日期: 2020-02-17 4. @说明: 设置当前屏幕是否滚动 *******************************************************************************/ void QTermWidget::setTrackOutput(bool enable) { m_impl->m_terminalDisplay->screenWindow()->setTrackOutput(enable); } void QTermWidget::sendText(const QString &text) { //标记当前命令是代码中通过sendText发给终端的(而不是用户手动输入的命令) bool isSendByRemoteManage = this->property("isSendByRemoteManage").toBool(); if (isSendByRemoteManage) { //将isSendByRemoteManage标记同步给Session m_impl->m_session->setProperty("isSendByRemoteManage", QVariant(true)); //立即修改回false,防止误认其他命令 this->setProperty("isSendByRemoteManage", QVariant(false)); } m_impl->m_session->sendText(text); //标记后立即修改回false,防止误认其他命令 m_impl->m_session->setProperty("isSendByRemoteManage", QVariant(false)); } void QTermWidget::sendKeyEvent(QKeyEvent *e) { m_impl->m_session->sendKeyEvent(e); } void QTermWidget::resizeEvent(QResizeEvent *) { // qDebug("global window resizing...with %d %d", this->size().width(), this->size().height()); m_impl->m_terminalDisplay->resize(this->size()); } void QTermWidget::sessionFinished() { emit finished(); } void QTermWidget::bracketText(QString &text) { m_impl->m_terminalDisplay->bracketText(text); } void QTermWidget::copyClipboard() { m_impl->m_terminalDisplay->copyClipboard(); } void QTermWidget::pasteClipboard() { if (m_impl->m_terminalDisplay->hasFocus()) { m_impl->m_terminalDisplay->pasteClipboard(); } } void QTermWidget::pasteSelection() { m_impl->m_terminalDisplay->pasteSelection(); } void QTermWidget::setZoom(int step) { // 获取字体 QFont font = m_impl->m_terminalDisplay->getVTFont(); // 设置字体 font.setPointSize(font.pointSize() + step); setTerminalFont(font); } void QTermWidget::zoomIn() { setZoom(STEP_ZOOM); } void QTermWidget::zoomOut() { setZoom(-STEP_ZOOM); } void QTermWidget::setKeyBindings(const QString &kb) { m_impl->m_session->setKeyBindings(kb); } void QTermWidget::clear() { m_impl->m_session->emulation()->reset(); m_impl->m_session->refresh(); m_impl->m_session->clearHistory(); } void QTermWidget::setFlowControlEnabled(bool enabled) { m_impl->m_session->setFlowControlEnabled(enabled); } QStringList QTermWidget::availableKeyBindings() { return KeyboardTranslatorManager::instance()->allTranslators(); } QString QTermWidget::keyBindings() { return m_impl->m_session->keyBindings(); } void QTermWidget::toggleShowSearchBar() { m_searchBar->isHidden() ? m_searchBar->show() : m_searchBar->hide(); } bool QTermWidget::flowControlEnabled(void) { return m_impl->m_session->flowControlEnabled(); } void QTermWidget::setFlowControlWarningEnabled(bool enabled) { if (flowControlEnabled()) { // Do not show warning label if flow control is disabled m_impl->m_terminalDisplay->setFlowControlWarningEnabled(enabled); } } void QTermWidget::setEnvironment(const QStringList &environment) { m_impl->m_session->setEnvironment(environment); } void QTermWidget::setMotionAfterPasting(int action) { m_impl->m_terminalDisplay->setMotionAfterPasting((Konsole::MotionAfterPasting)action); } int QTermWidget::historyLinesCount() { return m_impl->m_terminalDisplay->screenWindow()->screen()->getHistLines(); } 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); } void QTermWidget::setSelectionEnd(int row, int column) { m_impl->m_terminalDisplay->screenWindow()->screen()->setSelectionEnd(column, row); } /******************************************************************** 1. @函数: setSelectionAll 2. @作者: 王培利 3. @日期: 2020-02-13 4. @说明: 屏幕全选功能 ********************************************************************/ void QTermWidget::setSelectionAll() { m_impl->m_terminalDisplay->setSelectionAll(); } void QTermWidget::getSelectionStart(int &row, int &column) { m_impl->m_terminalDisplay->screenWindow()->screen()->getSelectionStart(column, row); } void QTermWidget::getSelectionEnd(int &row, int &column) { m_impl->m_terminalDisplay->screenWindow()->screen()->getSelectionEnd(column, row); } char QTermWidget::getErase() { return m_impl->m_session->getEraseChar(); } void QTermWidget::setDeleteMode(char *key, int length) { m_impl->m_session->setDeleteMode(key, length); } void QTermWidget::setBackspaceMode(char *key, int length) { m_impl->m_session->setBackspaceMode(key, length); } QString QTermWidget::selectedText(const Screen::DecodingOptions options) { return m_impl->m_terminalDisplay->screenWindow()->screen()->selectedText(options); } void QTermWidget::setMonitorActivity(bool monitor) { m_impl->m_session->setMonitorActivity(monitor); } void QTermWidget::setMonitorSilence(bool monitor) { m_impl->m_session->setMonitorSilence(monitor); } void QTermWidget::setSilenceTimeout(int seconds) { m_impl->m_session->setMonitorSilenceSeconds(seconds); } Filter::HotSpot *QTermWidget::getHotSpotAt(const QPoint &pos) const { int row = 0, column = 0; m_impl->m_terminalDisplay->getCharacterPosition(pos, row, column); return getHotSpotAt(row, column); } Filter::HotSpot *QTermWidget::getHotSpotAt(int row, int column) const { return m_impl->m_terminalDisplay->filterChain()->hotSpotAt(row, column); } QList QTermWidget::filterActions(const QPoint &position) { return m_impl->m_terminalDisplay->filterActions(position); } int QTermWidget::getPtySlaveFd() const { return m_impl->m_session->getPtySlaveFd(); } void QTermWidget::setKeyboardCursorShape(KeyboardCursorShape shape) { m_impl->m_terminalDisplay->setKeyboardCursorShape(shape); } void QTermWidget::setBlinkingCursor(bool blink) { m_impl->m_terminalDisplay->setBlinkingCursor(blink); } void QTermWidget::setBidiEnabled(bool enabled) { m_impl->m_terminalDisplay->setBidiEnabled(enabled); } bool QTermWidget::isBidiEnabled() { 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(); } void QTermWidget::saveHistory(QIODevice *device) { QTextStream stream(device); PlainTextDecoder decoder; decoder.begin(&stream); m_impl->m_session->emulation()->writeToStream(&decoder, 0, m_impl->m_session->emulation()->lineCount()); } void QTermWidget::setDrawLineChars(bool drawLineChars) { m_impl->m_terminalDisplay->setDrawLineChars(drawLineChars); } void QTermWidget::setBoldIntense(bool boldIntense) { m_impl->m_terminalDisplay->setBoldIntense(boldIntense); } int QTermWidget::getForegroundProcessId() const { return m_impl->m_session->foregroundProcessId(); } QString QTermWidget::getForegroundProcessName() const { return m_impl->m_session->foregroundProcessName(); } deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/qtermwidget.h000066400000000000000000000325331475472654300257000ustar00rootroot00000000000000/* Copyright (C) 2008 e_k (e_k@users.sourceforge.net) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _Q_TERM_WIDGET #define _Q_TERM_WIDGET #include #include #include #include "Emulation.h" #include "Filter.h" #include "HistorySearch.h" #include "qtermwidget_export.h" class QVBoxLayout; class TermWidgetImpl; class SearchBar; class QUrl; namespace Konsole { class TerminalDisplay; } class TERMINALWIDGET_EXPORT 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, /** Show the scroll bar on the left side of the display. */ ScrollBarLeft = 1, /** Show the scroll bar on the right side of the display. */ ScrollBarRight = 2 }; using KeyboardCursorShape = Konsole::Emulation::KeyboardCursorShape; //Creation of widget QTermWidget(int startnow, // 1 = start shell programm immediatelly QWidget *parent = nullptr); // A dummy constructor for Qt Designer. startnow is 1 by default explicit QTermWidget(QWidget *parent = nullptr); ~QTermWidget() override; //Initial size QSize sizeHint() const override; // expose TerminalDisplay::TerminalSizeHint, setTerminalSizeHint void setTerminalSizeHint(bool on); bool terminalSizeHint(); //start shell program if it was not started in constructor void startShellProgram(); // Returns session id list of processes running in the terminal window QList getRunningSessionIdList(); // Determine whether the terminal control has running process bool hasRunningProcess(); /** * 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(); // Get current terminal's session id int getSessionId(); void changeDir(const QString &dir); // look-n-feel, if you don`t like defaults // Terminal font // Default is application font with family Monospace, size 10 // 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); // Shell program, default is /bin/bash void setShellProgram(const QString &progname); // working directory void setWorkingDirectory(const QString &dir); QString workingDirectory(); // Shell program args, default is none void setArgs(const QStringList &args); // Text codec, default is UTF-8 void setTextCodec(QTextCodec *codec); /** @brief Sets the color scheme, default is white on black * * @param[in] name The name of the color scheme, either returned from * availableColorSchemes() or a full path to a color scheme. */ //设置主题的配色方案 void setColorScheme(const QString &name, bool needReloadTheme = false); static QStringList availableColorSchemes(); static void addCustomColorSchemeDir(const QString &custom_dir); // History size for scrolling void setHistorySize(int lines); // infinite if lines < 0 // Presence of scrollbar void setScrollBarPosition(ScrollBarPosition); // Wrapped, scroll to end. void scrollToEnd(); /******** Modify by n014361 wangpeili 2020-02-17:设置当前屏幕是否滚动****************/ void setTrackOutput(bool enable); /********************* Modify by n014361 wangpeili End ************************/ // Send some text to terminal void sendText(const QString &text); // Send key event to terminal void sendKeyEvent(QKeyEvent *e); // Sets whether flow control is enabled void setFlowControlEnabled(bool enabled); // Returns whether flow control is enabled bool flowControlEnabled(void); /** * Sets whether the flow control warning box should be shown * when the flow control stop key (Ctrl+S) is pressed. */ void setFlowControlWarningEnabled(bool enabled); /*! Get all available keyboard bindings */ static QStringList availableKeyBindings(); //! 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); /******** Modify by n014361 wangpeili 2020-02-13: 新增屏幕全选功能***********×****/ void setSelectionAll(); /***************** Modify by n014361 End *************************/ void getSelectionStart(int &row, int &column); void getSelectionEnd(int &row, int &column); /******** Modify by ut000610 daizhengwen 2020-06-02: 获得pty erase模式****************/ char getErase(); /********************* Modify by ut000610 daizhengwen End ************************/ // 设置删除键模式(修改内存接口) void setDeleteMode(char *key, int length); // 设置退格按键模式(用户选择接口) void setBackspaceMode(char *key, int length); /** * 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(const Screen::DecodingOptions options=Screen::PreserveLineBreaks); void setMonitorActivity(bool); void setMonitorSilence(bool); void setSilenceTimeout(int seconds); /** Returns the available hotspot for the given point \em pos. * * This method may return a nullptr if no hotspot is available. * * @param[in] pos The point of interest in the QTermWidget coordinates. * @return Hotspot for the given position, or nullptr if no hotspot. */ Filter::HotSpot *getHotSpotAt(const QPoint &pos) const; /** Returns the available hotspots for the given row and column. * * @return Hotspot for the given position, or nullptr if no hotspot. */ Filter::HotSpot *getHotSpotAt(int row, int column) const; /* * Proxy for TerminalDisplay::filterActions * */ QList filterActions(const QPoint &position); /** * 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; /** Get the foreground pid in terminal */ int getForegroundProcessId() const; // 获取foreground名称 QString getForegroundProcessName() const; void setDrawLineChars(bool drawLineChars); void setBoldIntense(bool boldIntense); // 获取是否允许输出时滚动 bool getIsAllowScroll() const; // 设置是否允许输出时滚动 void setIsAllowScroll(bool isAllowScroll); //Add by ut001000 renfeixiang 2020-12-02 当搜索框出现时,设置m_bHasSelect为false, //避免搜索框隐藏再显示之后,继续走m_bHasSelect为true流程,导致崩溃 void setNoHasSelect(); signals: void finished(); void copyAvailable(bool); void termGetFocus(); void termLostFocus(); void leftMouseClick(); void termKeyPressed(QKeyEvent *); void urlActivated(const QUrl &, bool fromContextMenu); void bell(const QString &message); void activity(); void silence(); /******** Modify by nt001000 renfeixiang 2020-05-27:修改 增加参数区别remove和purge卸载命令 Begin***************/ bool uninstallTerminal(QString commandname); /******** Modify by nt001000 renfeixiang 2020-05-27:修改 增加参数区别remove和purge卸载命令 Begin***************/ /******** Modify by ut000610 daizhengwen 2020-06-11: QProcess start finished signal****************/ void processStarted(); /********************* Modify by ut000610 daizhengwen End ************************/ /******** Modify by ut000610 daizhengwen 2020-09-03:将拖拽过来的数据传送给终端 Begin***************/ void sendUrlsToTerm(const char *); /********************* Modify by ut000610 daizhengwen End ************************/ /** * 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, const QTextCodec *); void profileChanged(const QString &profile); void titleChanged(); // warning提示信息 currentShell当前使用的shell, 启用shell是否成功 true 替换了shell false 替换shell但启动失败 void shellWarningMessage(QString currentShell, bool isSuccess); /** * Signals that we received new data from the process running in the * terminal emulator */ void receivedData(const QString &text); /** * Signals for dynamically determine whether current terminal is busy or idle */ void isTermIdle(bool bIdle); // 将库里返回信号透传出来。原来的noMatchFound方法改名为clearSelection void sig_noMatchFound(); // 找到的信号 void sig_matchFound(); // 标签标题参数改变 dzw 2020-12-2 void titleArgsChange(QString key, QString value); public slots: // Copy selection to clipboard void copyClipboard(); // Paste clipboard to terminal void pasteClipboard(); // 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); /*! Clear the terminal content and move to home position */ void clear(); void toggleShowSearchBar(); /******** Modify by n014361 wangpeili 2020-02-24: ****************/ // 新增外部搜索接口,不用qterminal内置的搜索接口 void search(QString txt, bool forwards, bool next); // 清除选中框 void clearSelection(); void noMatchFound(); /********************* Modify by n014361 wangpeili End ************************/ void saveHistory(QIODevice *device); protected: void resizeEvent(QResizeEvent *) override; protected slots: void sessionFinished(); void selectionChanged(bool textSelected); private slots: void matchFound(int startColumn, int startLine, int endColumn, int endLine, int lastBackwardsPosition, int loseChinese, int matchChinese); /** * 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); void snapshot(); private: void setZoom(int step); void init(int startnow); void addSnapShotTimer(); void interactionHandler(); TermWidgetImpl *m_impl; SearchBar *m_searchBar; QVBoxLayout *m_layout; static QTranslator *m_translator; QPointer m_termDisplay; QTimer *m_interactionTimer = nullptr; bool m_bHasSelect = false; int m_startColumn = 0; int m_startLine = 0; int m_endColumn = 0; int m_endLine = 0; int m_lastBackwardsPosition = -1; //上一次是正向搜索还是反向搜索 bool m_isLastForwards = false; }; // Maybe useful, maybe not #ifdef __cplusplus extern "C" #endif void *createTermWidget(int startnow, void *parent); #endif deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/tools.cpp000066400000000000000000000074061475472654300250400ustar00rootroot00000000000000/* Copyright (C) 2008 e_k (e_k@users.sourceforge.net) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "tools.h" #include #include #include #include /*! Helper function to get possible location of layout files. By default the KB_LAYOUT_DIR is used (linux/BSD/macports). But in some cases (apple bundle) there can be more locations). */ QString get_kb_layout_dir() { // qDebug() << __FILE__ << __FUNCTION__; QString rval = QString(); QString k(QLatin1String(KB_LAYOUT_DIR)); QDir d(k); //qDebug() << "default KB_LAYOUT_DIR: " << k; if (d.exists()) { rval = k.append(QLatin1Char('/')); return rval; } #ifdef Q_OS_MAC // subdir in the app location d.setPath(QCoreApplication::applicationDirPath() + QLatin1String("/kb-layouts/")); //qDebug() << d.path(); if (d.exists()) return QCoreApplication::applicationDirPath() + QLatin1String("/kb-layouts/"); d.setPath(QCoreApplication::applicationDirPath() + QLatin1String("/../Resources/kb-layouts/")); if (d.exists()) return QCoreApplication::applicationDirPath() + QLatin1String("/../Resources/kb-layouts/"); #endif //qDebug() << "Cannot find KB_LAYOUT_DIR. Default:" << k; return QString(); } /*! 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). */ const QStringList get_color_schemes_dirs() { // qDebug() << __FILE__ << __FUNCTION__; QStringList rval; QString k(QLatin1String(COLORSCHEMES_DIR)); QDir d(k); // qDebug() << "default COLORSCHEMES_DIR: " << k; if (d.exists()) rval << k.append(QLatin1Char('/')); #ifdef Q_OS_MAC // subdir in the app location d.setPath(QCoreApplication::applicationDirPath() + QLatin1String("/color-schemes/")); //qDebug() << d.path(); if (d.exists()) { if (!rval.isEmpty()) rval.clear(); rval << (QCoreApplication::applicationDirPath() + QLatin1String("/color-schemes/")); } d.setPath(QCoreApplication::applicationDirPath() + QLatin1String("/../Resources/color-schemes/")); if (d.exists()) { if (!rval.isEmpty()) rval.clear(); rval << (QCoreApplication::applicationDirPath() + QLatin1String("/../Resources/color-schemes/")); } #endif for (const QString& custom_dir : qAsConst(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; } else { qDebug() << "Cannot find color-schemes in any location!"; } #endif return rval; } deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/tools.h000066400000000000000000000021141475472654300244740ustar00rootroot00000000000000/* Copyright (C) 2008 e_k (e_k@users.sourceforge.net) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef TOOLS_H #define TOOLS_H #include #include #include #include QString get_kb_layout_dir(); void add_custom_color_scheme_dir(const QString& custom_dir); const QStringList get_color_schemes_dirs(); #endif deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/translations/000077500000000000000000000000001475472654300257065ustar00rootroot00000000000000deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/translations/CMakeLists.txt000066400000000000000000000001441475472654300304450ustar00rootroot00000000000000project(qtermwidget) build_component("." "${CMAKE_INSTALL_FULL_DATADIR}/qtermwidget/translations") deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/translations/terminalwidget.ts000066400000000000000000000106351475472654300313020ustar00rootroot00000000000000 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 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: < > ... deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/translations/terminalwidget_arn.ts000066400000000000000000000106641475472654300321440ustar00rootroot00000000000000 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: < > ... deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/translations/terminalwidget_ast.ts000066400000000000000000000106641475472654300321530ustar00rootroot00000000000000 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: < > ... deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/translations/terminalwidget_az.ts000066400000000000000000000113571475472654300317760ustar00rootroot00000000000000 Konsole::TerminalDisplay Size: XXX x XXX Ölçü: XXX x XXX Size: %1 x %2 Ölçü: %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>Çıxış Ctrl+S vurmaqla <a href="http://en.wikipedia.org/wiki/Flow_control">dayandırldı</a>. Davam etmək üçün <b>Ctrl+Q</b> vurun.</qt> Konsole::Vt102Emulation No keyboard translator available. The information needed to convert key presses into characters to send to the terminal is missing. Klaviatura tərcüməçisi yoxdur. Terminala göndərmək məqsədi ilə düymələrə basılmanın simvollara çevrilməsi üçün lazım olan məlumatlar çatışmır. QObject Un-named Color Scheme Adlandırılmamış Rəng Sxemi Accessible Color Scheme Əlçatan Rəng Sxemi Open link Keçidi açmaq Copy link Keçidi kopyalamaq Send email to... E-poçtu buraya göndərmək... Copy email address E-poçt ünvanını kopyalamaq QTermWidget Color Scheme Error Rəng Sxemi Xətası Cannot load color scheme: %1 Rəng sxemi yüklənə bilmədi: %1 SearchBar Match case Böyük/kiçik hərf nəzərə almaqla Regular expression Müntəzəm ifadə Highlight all matches Bütün oxşarları vurğulamaq SearchBar Axtarış çubuğu X X Find: Tapmaq: < < > > ... ... deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/translations/terminalwidget_bo.ts000066400000000000000000000132211475472654300317540ustar00rootroot00000000000000 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 སྦྲེལ་མཐུད་པར་སློག 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: འཚོལ་བ། < < > > ... ... deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/translations/terminalwidget_br.ts000066400000000000000000000113221475472654300317570ustar00rootroot00000000000000 Konsole::TerminalDisplay Size: XXX x XXX Ment: XXX x XXX Size: %1 x %2 Ment: %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>An ezvont a zo bet <a href="http://en.wikipedia.org/wiki/Flow_control">paouezet</a> en ur bouezañ Ktrl+S. Pouezit war <b>Ktrl+Q</b> evit kregiñ e-barzh en-dro, eta.</qt> Konsole::Vt102Emulation No keyboard translator available. The information needed to convert key presses into characters to send to the terminal is missing. N'eus troer hegerz ebet. An titour ret evit koñvertisañ ar boutonioù pouezet en arouezennoù da gas d'an terminal a vank. QObject Un-named Color Scheme Chema livioù hep anv Accessible Color Scheme Chema livioù hegerz Open link Digeriñ al liamm Copy link Eilañ al liamm Send email to... Kas ur postel da... Copy email address Eilañ ar chomlec'h postel QTermWidget Color Scheme Error Fazi gant ar chema livioù Cannot load color scheme: %1 N'heller ket kargañ chema al livioù: %1 SearchBar Match case Kizidik ouzh al log Regular expression Troienn-reoliata Highlight all matches Sklaerijennañ an holl genglotadennoù SearchBar Barrenn an enklaskoù X X Find: Kavout: < < > > ... ... deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/translations/terminalwidget_ca.ts000066400000000000000000000113251475472654300317420ustar00rootroot00000000000000 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 Copia l'enllaç Send email to... Envia un correu a... Copy email address Copia l'adreça de correu 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: < < > > ... ... deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/translations/terminalwidget_cs.ts000066400000000000000000000113511475472654300317630ustar00rootroot00000000000000 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. Pokud chcete pokračovat, stiskněte <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řeklad klávesnice. Informace, potřebné pro převádění stisků kláves na znaky, odesílané do terminálu chybí. QObject Un-named Color Scheme Nenazvané schéma barev Accessible Color Scheme Schéma barev pro zpřístupnění hendikepovaným Open link Otevřít odkaz Copy link Zkopírovat odkaz Send email to... Odeslat e-mail na… Copy email address Zkopírovat e-mailovou adresu QTermWidget Color Scheme Error Chyba schématu barev Cannot load color scheme: %1 Nedaří se načíst schéma barev: %1 SearchBar Match case Rozlišovat VELKÁ/malá písmena Regular expression Regulární výraz Highlight all matches Zvýraznit všechny shody SearchBar Lišta hledání X X Find: Najít: < < > > ... deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/translations/terminalwidget_cy.ts000066400000000000000000000100711475472654300317670ustar00rootroot00000000000000 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: < > ... deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/translations/terminalwidget_da.ts000066400000000000000000000112101475472654300317340ustar00rootroot00000000000000 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 Kopiér link Send email to... Copy email address 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: < < > > ... ... deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/translations/terminalwidget_de.ts000066400000000000000000000112601475472654300317450ustar00rootroot00000000000000 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 Link öffnen Copy link Link kopieren Send email to... E-Mail senden an ... Copy email address E-Mail-Adresse kopieren QTermWidget Color Scheme Error Farbschemafehler Cannot load color scheme: %1 Kann Farbschema nicht laden: %1 SearchBar Match case Groß-/Kleinschreibung beachten Regular expression Regulärer Ausdruck Highlight all matches Alle Treffer hervorheben SearchBar Suchleiste X X Find: Finde: < < > > ... ... deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/translations/terminalwidget_el.ts000066400000000000000000000123341475472654300317600ustar00rootroot00000000000000 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 Αντιγραφή συνδέσμου Send email to... Αποστολή email ... Copy email address Αντιγραφή διεύθυνσης email QTermWidget Color Scheme Error Σφάλμα του χρωματικού συνδυασμού Cannot load color scheme: %1 Αδύνατη η φόρτωση του χρωματικού συνδυασμού: %1 SearchBar Match case Ταίριασμα πεζών/κεφαλαίων Regular expression Κανονική έκφραση Highlight all matches Τονισμός όλων των ταιριαστών SearchBar Γραμμή αναζήτησης X X Find: Εύρεση: < < > > ... ... deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/translations/terminalwidget_en.ts000066400000000000000000000111231475472654300317550ustar00rootroot00000000000000 Konsole::TerminalDisplay Size: XXX x XXX Size: XXX x XXX Size: %1 x %2 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> <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. 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 Un-named Color Scheme Accessible Color Scheme Accessible Color Scheme Open link Open link Copy link Copy link Send email to... Send email to... Copy email address Copy email address QTermWidget Color Scheme Error Color Scheme Error Cannot load color scheme: %1 Cannot load color scheme: %1 SearchBar Match case Match case Regular expression Regular expression Highlight all matches Highlight all matches SearchBar SearchBar X X Find: Find: < < > > ... ... deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/translations/terminalwidget_es.ts000066400000000000000000000113321475472654300317640ustar00rootroot00000000000000 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 se ha <a href="http://en.wikipedia.org/wiki/Flow_control">suspendido</a> por presionar Ctrl+S. Presione <b>Ctrl+Q</b> para reanudar.</qt> Konsole::Vt102Emulation No keyboard translator available. The information needed to convert key presses into characters to send to the terminal is missing. El traductor de teclado no está disponible. Falta la información necesaria para convertir las pulsaciones de las teclas en caracteres para introducirlos en la terminal. QObject Un-named Color Scheme Esquema de color sin nombre Accessible Color Scheme Esquema de color accesible Open link Abrir enlace Copy link Copiar enlace Send email to... Enviar correo a... Copy email address Copiar dirección de correo QTermWidget Color Scheme Error Error de esquema de color Cannot load color scheme: %1 No se puede cargar el esquema de color: %1 SearchBar Match case Coincidir mayúsculas Regular expression Expresión regular Highlight all matches Resaltar todas las coincidencias SearchBar Barra de búsqueda X X Find: Buscar: < < > > ... ... deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/translations/terminalwidget_fi.ts000066400000000000000000000112061475472654300317530ustar00rootroot00000000000000 Konsole::TerminalDisplay Size: XXX x XXX Koko: XXX x XXX Size: %1 x %2 Koko: %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>Tulostus <a href="http://en.wikipedia.org/wiki/Flow_control">keskeytyy</a> painamalla Ctrl+S. Paina <b>Ctrl+Q</b> jatkaaksesi.</qt> Konsole::Vt102Emulation No keyboard translator available. The information needed to convert key presses into characters to send to the terminal is missing. Kääntäjää ei ole saatavana. Tietoja joita tarvitaan näppäinpainalluksien muuntamiseksi ja terminaaliin lähetettäviksi merkeiksi, puuttuu. QObject Un-named Color Scheme Nimeämätön värimalli Accessible Color Scheme Saatavilla oleva värimalli Open link Avaa linkki Copy link Kopioi linkki Send email to... Lähetä sähköpostia... Copy email address Kopioi sähköpostiosoite QTermWidget Color Scheme Error Värimallissa virhe Cannot load color scheme: %1 Värimallia ei voi ladata: %1 SearchBar Match case Sama kirjainkoko Regular expression Säännöllinen lauseke Highlight all matches Korosta kaikki samat SearchBar Etsi-palkki X X Find: Etsi: < < > > ... ... deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/translations/terminalwidget_fr.ts000066400000000000000000000113511475472654300317650ustar00rootroot00000000000000 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 de couleurs non nommé Accessible Color Scheme Schéma des couleurs accessible Open link Ouvrir le lien Copy link Copier le lien Send email to... Envoyer un mail à... Copy email address Copier l'adresse mail 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 Match case Sensible à la casse Regular expression Expression régulière Highlight all matches Surbrillance de toutes les concordances SearchBar Barre de recherche X X Find: Trouver : < < > > ... ... deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/translations/terminalwidget_gl.ts000066400000000000000000000114121475472654300317560ustar00rootroot00000000000000 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>A saída foi <a href="http://en.wikipedia.org/wiki/Flow_control">suspendida</a> ao premer Ctrl+S. Prema <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. Non hai dispoñíbel ningún tradutor de teclado. Non está dispoñíbel a información necesaria para converter pulsacións de tecla en caracteres para envialos o terminal. QObject Un-named Color Scheme Esquema de cor sen nome Accessible Color Scheme Esquema de cor accesíbel Open Link Abrir a ligazón Copy Link Address Copiar o enderezo da ligazón Send Email To... Enviar correo a... Copy Email Address Copiar o enderezo de correo QTermWidget Color Scheme Error Produciuse un erro no esquema de cor Cannot load color scheme: %1 Non é posíbel cargar o esquema de cor: %1 SearchBar Match case Distinguir maiúsculas de minúsculas Regular expression Expresión regular Highlight all matches Resaltar todas as coincidencias SearchBar Barra de buscas X Find: Atopar: < > ... deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/translations/terminalwidget_gl_ES.ts000066400000000000000000000113771475472654300323570ustar00rootroot00000000000000 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>A saída foi <a href="http://en.wikipedia.org/wiki/Flow_control">suspendida</a> ao premer Ctrl+S. Prema <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. Non hai dispoñíbel ningún tradutor de teclado. Non está dispoñíbel a información necesaria para converter pulsacións de tecla en caracteres para envialos o terminal. QObject Un-named Color Scheme Esquema de cor sen nome Accessible Color Scheme Esquema de cor accesíbel Open link Abrir ligazón Copy link Copiar ligazón Send email to... Enviar un correo electrónico a... Copy email address Copiar enderezo electrónico QTermWidget Color Scheme Error Produciuse un erro no esquema de cor Cannot load color scheme: %1 Non é posíbel cargar o esquema de cor: %1 SearchBar Match case Distinguir maiúsculas de minúsculas Regular expression Expresión regular Highlight all matches Resaltar todas as coincidencias SearchBar Barra de buscas X X Find: Atopar: < < > > ... ... deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/translations/terminalwidget_he.ts000066400000000000000000000114641475472654300317570ustar00rootroot00000000000000 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: חיפוש: < > ... deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/translations/terminalwidget_hi_IN.ts000066400000000000000000000124711475472654300323500ustar00rootroot00000000000000 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</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 लिंक कॉपी करें 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: खोज : < < > > ... ... deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/translations/terminalwidget_hu.ts000066400000000000000000000113131475472654300317700ustar00rootroot00000000000000 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 Hivatkozás megnyitása Copy link Hivatkozás másolása Send email to... E-mail küldése ide... Copy email address E-mail cím másolása QTermWidget Color Scheme Error Színséma hiba Cannot load color scheme: %1 A %1 színséma betöltése nem lehetséges SearchBar Match case Nagybetű érzékeny Regular expression Szabályos kifejezés Highlight all matches Összes találat kiemelése SearchBar Keresősáv X X Find: Találat: < < > > ... ... deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/translations/terminalwidget_id.ts000066400000000000000000000112401475472654300317470ustar00rootroot00000000000000 Konsole::TerminalDisplay Size: XXX x XXX Ukuran: XXX x XXX Size: %1 x %2 Ukuran: %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 telah <a href="http://en.wikipedia.org/wiki/Flow_control">ditangguhkan</a> dengan menekan Ctrl+S. Tekan <b>Ctrl+Q</b> untuk melanjutkan.</qt> Konsole::Vt102Emulation No keyboard translator available. The information needed to convert key presses into characters to send to the terminal is missing. Tidak ada penerjemah papan ketik yang tersedia. Informasi yang diperlukan untuk mengubah penekanan tombol menjadi karakter untuk dikirim ke terminal tidak ada. QObject Un-named Color Scheme Skema warna belum bernama Accessible Color Scheme Skema Warna yang bisa diakses Open link Buka tautan: Copy link Salin tautan Send email to... Kirim surel ke... Copy email address Salin alamat surel QTermWidget Color Scheme Error Galat Skema Warna Cannot load color scheme: %1 Tidak dapat memuat Skema Warna: %1 SearchBar Match case Hal yang cocok Regular expression Regular ekspresi Highlight all matches Sorot semua yang cocok SearchBar Papan pencarian X X Find: Temukan: < < > > ... ... deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/translations/terminalwidget_it.ts000066400000000000000000000112721475472654300317740ustar00rootroot00000000000000 Konsole::TerminalDisplay Size: XXX x XXX Dimensione: XXX x XXX Size: %1 x %2 Dimensione: %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>L'Output è stato <a href="http://en.wikipedia.org/wiki/Flow_control">sospeso</a> premendo Ctrl+S. Premi <b>Ctrl+Q</b> per ripristinarlo.</qt> Konsole::Vt102Emulation No keyboard translator available. The information needed to convert key presses into characters to send to the terminal is missing. Nessun traduttore di tastiera disponibile. Mancano le informazioni necessarie per convertire i tasti premuti in caratteri da inviare al terminale. QObject Un-named Color Scheme Combinazione di colori senza nome Accessible Color Scheme Schema colori accessibile Open link Apri link Copy link Copia link Send email to... Invia email a... Copy email address Copia indirizzo email QTermWidget Color Scheme Error Errore schema colori Cannot load color scheme: %1 Impossibile caricare lo schema colori: %1 SearchBar Match case Casi di corrispondenza Regular expression Espressione regolare Highlight all matches Evidenzia tutte le corrispondenze SearchBar Barra di ricerca X X Find: Trova: < < > > ... ... deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/translations/terminalwidget_ja.ts000066400000000000000000000110551475472654300317510ustar00rootroot00000000000000 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: 探す: < > ... deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/translations/terminalwidget_ko.ts000066400000000000000000000113201475472654300317630ustar00rootroot00000000000000 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 링크 복사 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: 찾기: < < > > ... ... deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/translations/terminalwidget_lt.ts000066400000000000000000000113111475472654300317710ustar00rootroot00000000000000 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 Kopijuoti nuorodą Send email to... Copy email address 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: < < > > ... ... deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/translations/terminalwidget_ms.ts000066400000000000000000000112031475472654300317710ustar00rootroot00000000000000 Konsole::TerminalDisplay Size: XXX x XXX Saiz: XXX x XXX Size: %1 x %2 Saiz: %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 telah <a href="http://en.wikipedia.org/wiki/Flow_control">ditangguh</a> dengan menekan Ctrl+S. Tekan<b>Ctrl+Q</b> untuk sambung semula.</qt> Konsole::Vt102Emulation No keyboard translator available. The information needed to convert key presses into characters to send to the terminal is missing. Tiada penterjemah papan kekunci tersedia. Maklumat diperlukan untuk menukar ketukan kekunci menjadi aksara yang perlu dihantar ke terminal telah hilang. QObject Un-named Color Scheme Skema Warna Tanpa Nama Accessible Color Scheme Skema Warna Boleh Capai Open link Buka pautan Copy link Salin pautan Send email to... Hantar emel kepada... Copy email address Salin alamat emel QTermWidget Color Scheme Error Ralat Skema Warna Cannot load color scheme: %1 Tidak dapat memuatkan skema warna: %1 SearchBar Match case Padan kata Regular expression Ungkapan nalar Highlight all matches Sorot semua padanan SearchBar Palang Gelintar X X Find: Cari: < < > > ... ... deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/translations/terminalwidget_nb_NO.ts000066400000000000000000000113011475472654300323440ustar00rootroot00000000000000 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>Utgangssignalet ble <a href="http://en.wikipedia.org/wiki/Flow_control">stoppet</a> da Ctrl+S ble trykket. Trykk <b>Ctrl+Q</b> for å fortsette.</qt> Konsole::Vt102Emulation No keyboard translator available. The information needed to convert key presses into characters to send to the terminal is missing. Ingen tastaturoversetter er tilgjengelig. Informasjonen som trengs for å gjøre tastetrykk om til tegn å sende til terminalen mangler. QObject Un-named Color Scheme Fargemønster uten navn Accessible Color Scheme Fargemønster for funksjonshemmede Open Link Åpne lenke Copy Link Address Kopier lenkeadresse Send Email To... Send epost til... Copy Email Address Kopier epostadressen QTermWidget Color Scheme Error Feil med fargemønster Cannot load color scheme: %1 Kan ikke åpne fargemønster: %1 SearchBar Match case Bruk STORE og små bokstaver Regular expression Bokstavmønstre (regex) Highlight all matches Lys opp alle søkeresultat SearchBar Søkefelt X Find: Finn: < > ... deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/translations/terminalwidget_nl.ts000066400000000000000000000112611475472654300317670ustar00rootroot00000000000000 Konsole::TerminalDisplay Size: XXX x XXX Afmetingen: XXX x XXX Size: %1 x %2 Afmetingen: %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>Door op Ctrl+S te drukken is de uitvoer <a href="http://en.wikipedia.org/wiki/Flow_control">onderbroken</a>. Druk op <b>Ctrl+Q</b> om te hervatten.</qt> Konsole::Vt102Emulation No keyboard translator available. The information needed to convert key presses into characters to send to the terminal is missing. Geen toetsenbordvertaling beschikbaar. De informatie die nodig is voor het omzetten van toetsaanslagen naar tekens in de terminal ontbreekt. QObject Un-named Color Scheme Naamloos kleurenschema Accessible Color Scheme Toegankelijk kleurenschema Open link Link openen Copy link Link kopiëren Send email to... E-mail versturen naar… Copy email address E-mailadres kopiëren QTermWidget Color Scheme Error Kleurenschemafout Cannot load color scheme: %1 Het kleurenschema kan niet worden geladen: %1 SearchBar Match case Hoofdlettergevoelig Regular expression Reguliere uitdrukking Highlight all matches Alle overeenkomsten markeren SearchBar Zoekbalk X X Find: Zoeken: < < > > ... deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/translations/terminalwidget_pl.ts000066400000000000000000000112401475472654300317660ustar00rootroot00000000000000 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śnięcia przycisków na znaki wysyłane do terminala. QObject Un-named Color Scheme Nienazwana paleta Accessible Color Scheme Paleta o zwiększonej przystępności Open link Otwórz odnośnik Copy link Kopiuj odnośnik Send email to... Wyślij email 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ć schematu kolorów: %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ź: < < > > ... deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/translations/terminalwidget_pt.ts000066400000000000000000000113251475472654300320020ustar00rootroot00000000000000 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>A saída foi <a href="http://en.wikipedia.org/wiki/Flow_control"> suspensa</a> ao premir 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. Nenhum tradutor de teclado disponível. A informação necessária para converter a pressão da tecla nos caracteres a enviar ao terminal não existe. 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 Copiar ligação Send email to... Enviar um email a... Copy email address Copiar endereço de email QTermWidget Color Scheme Error Erro no esquema de cores Cannot load color scheme: %1 Não foi possível carregar o esquema de cores: %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: < < > > ... ... deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/translations/terminalwidget_pt_BR.ts000066400000000000000000000113441475472654300323660ustar00rootroot00000000000000 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>A saída foi <a href="http://en.wikipedia.org/wiki/Flow_control">suspensa </a> ao pressionar Ctrl+S. Pressione <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. Nenhum tradutor de teclado está disponível. As informações necessárias para converter as teclas pressionadas, em caracteres a serem enviadas ao terminal, está ausente. QObject Un-named Color Scheme Esquema de Cor sem nome Accessible Color Scheme Esquema de Cores Acessível Open link Abrir link Copy link Copiar link Send email to... Enviar e-mail para... Copy email address Copiar endereço de e-mail QTermWidget Color Scheme Error Erro de Esquema de Cor Cannot load color scheme: %1 Não é possível carregar o esquema de cores: %1 SearchBar Match case Caso de correspondência Regular expression Expressão regular Highlight all matches Destacar todas as correspondências SearchBar Barra de Pesquisa X X Find: Localizar: < < > > ... ... deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/translations/terminalwidget_ru.ts000066400000000000000000000121301475472654300320000ustar00rootroot00000000000000 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 Копировать ссылку 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: Найти: < < > > ... ... deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/translations/terminalwidget_sq.ts000066400000000000000000000113121475472654300317760ustar00rootroot00000000000000 Konsole::TerminalDisplay Size: XXX x XXX Madhësi: XXX x XXX Size: %1 x %2 Madhësi: %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>Shfaqja e përfundimit është <a href="http://en.wikipedia.org/wiki/Flow_control">pezulluar</a> duke shtypur Ctrl+S. Që të vazhdohet sërish, shtypni <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. S’ka përkthyes aktesh tastiere. Mungojnë të dhënat e nevojshme për shndërrim shtypjesh tastesh në shenja për t’u dërguar në terminal. QObject Un-named Color Scheme Skemë Ngjyrash e Paemër Accessible Color Scheme Skemë Ngjyrash e Përdorshme Open link Hap lidhje Copy link Kopjoji lidhjen Send email to... Dërgoni email te… Copy email address Kopjo adresën email QTermWidget Color Scheme Error Gabim Skeme Ngjyrash Cannot load color scheme: %1 S’ngarkohet dot skemë ngjyrash: %1 SearchBar Match case Siç është shkruar Regular expression Shprehje e rregullt Highlight all matches Theksoji krejt përputhjet SearchBar Shtyllë Kërkimi X X Find: Gjej: < < > > ... deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/translations/terminalwidget_sr.ts000066400000000000000000000117221475472654300320040ustar00rootroot00000000000000 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 Копирај везу 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: Пронађи: < < > > ... ... deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/translations/terminalwidget_te.ts000066400000000000000000000126341475472654300317730ustar00rootroot00000000000000 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 లింక్ను కాపీ చేయి 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: కనుగొను: < < > > ... ... deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/translations/terminalwidget_tr.ts000066400000000000000000000112011475472654300317750ustar00rootroot00000000000000 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">askıya alındı</a> Ctrl+S tuşlarına basarak. Bas <b>Ctrl+Q</b> devam et.</qt> Konsole::Vt102Emulation No keyboard translator available. The information needed to convert key presses into characters to send to the terminal is missing. Klavye tercümanı yok. Tuşa basmaları uçbirime göndermek ve karakterlere dönüştürmek için gereken bilgiler eksik. QObject Un-named Color Scheme İsimsiz Renk Düzeni Accessible Color Scheme Erişilebilir Renk Düzeni Open link Bağlantıyı aç Copy link Bağlantıyı kopyala Send email to... E-posta gönder... Copy email address E-posta adresini kopyala QTermWidget Color Scheme Error Renk Düzeni Hatası Cannot load color scheme: %1 Renk şeması yüklenemiyor: %1 SearchBar Match case Durum eşleşmesi Regular expression Düzenli ifade Highlight all matches Tüm eşleşmeleri vurgula SearchBar AramaÇubuğu X X Find: Bul: < < > > ... ... deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/translations/terminalwidget_ug.ts000066400000000000000000000120711475472654300317710ustar00rootroot00000000000000 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 ئۇلىنىشنى كۆچۈرۈش 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: ئىزدەش: < < > > ... ... deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/translations/terminalwidget_uk.ts000066400000000000000000000121521475472654300317750ustar00rootroot00000000000000 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 Копіювати посилання 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: Знайти: < < > > ... ... deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/translations/terminalwidget_vi.ts000066400000000000000000000114661475472654300320030ustar00rootroot00000000000000 Konsole::TerminalDisplay Size: XXX x XXX Kích thước: XXX x XXX Size: %1 x %2 Kích thước: %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>đầu ra đã <a href="http://en.wikipedia.org/wiki/Flow_control">dừng</a> bằng cách bấm Ctrl+S. Bấm <b>Ctrl+Q</b> đẻ tiếp tục.</qt> Konsole::Vt102Emulation No keyboard translator available. The information needed to convert key presses into characters to send to the terminal is missing. Không có trình dịch bàn phím nào có sẵn. Thông tin cần thiết để chuyển đổi các lần nhấn phím thành ký tự để gửi đến thiết bị đầu cuối bị thiếu. QObject Un-named Color Scheme Phối màu chưa đặt tên Accessible Color Scheme Lược đồ màu có thể truy cập Open link Mở đường dẫn Copy link Sao chép đường dẫn Send email to... Gửi email đến Copy email address Sao chép địa chỉ email QTermWidget Color Scheme Error Chủ đề màu sắc lỗi Cannot load color scheme: %1 Không thể tải chủ đề màu sắc SearchBar Match case Trường hợp phù hợp Regular expression Biểu thức chính quy Highlight all matches Làm nổi bật các kết quả SearchBar Thanh tìm kiếm X X Find: Tìm: < < > > ... ... deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/translations/terminalwidget_zh_CN.ts000066400000000000000000000110261475472654300323560ustar00rootroot00000000000000 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 复制链接 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: 寻找: < < > > ... ... deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/translations/terminalwidget_zh_HK.ts000066400000000000000000000111361475472654300323620ustar00rootroot00000000000000 Konsole::TerminalDisplay Size: XXX x XXX Size: XXX x XXX Size: %1 x %2 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> <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. 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 Un-named Color Scheme Accessible Color Scheme Accessible Color Scheme Open link 打開鏈接 Copy link 複製鏈接 Send email to... 發送郵件至... Copy email address 複製郵件地址 QTermWidget Color Scheme Error Color Scheme Error Cannot load color scheme: %1 Cannot load color scheme: %1 SearchBar Match case Match case Regular expression Regular expression Highlight all matches Highlight all matches SearchBar SearchBar X X Find: Find: < < > > ... ... deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/lib/translations/terminalwidget_zh_TW.ts000066400000000000000000000110271475472654300324110ustar00rootroot00000000000000 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 複製連結 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: 搜尋: < < > > ... ... deepin-terminal-5.9.51+dfsg/3rdparty/terminalwidget/qtermwidget.spec000066400000000000000000000056001475472654300256300ustar00rootroot00000000000000# norootforbuild %define libname libqtermwidget0 Name: qtermwidget Summary: Qt4 terminal widget Version: 0.2.0 Release: 1 License: GPL Source: %{name}-%{version}.tar.bz2 Group: Utility URL: https://github.com/qterminal Vendor: petr@yarpen.cz %if 0%{?fedora_version} %define breq qt4-devel %define pref %{buildroot}/usr %endif %if 0%{?mandriva_version} %define breq libqt4-devel %define pref %{buildroot}/usr %endif %if 0%{?suse_version} %define breq libqt4-devel %define pref %{_prefix} %endif BuildRequires: gcc-c++, %{breq}, cmake BuildRoot: %{_tmppath}/%{name}-%{version}-build Prefix: %{_prefix} %description QTermWidget is an opensource project based on KDE4 Konsole application. The main goal of this project is to provide unicode-enabled, embeddable QT4 widget for using as a built-in console (or terminal emulation widget). Of course I`m aware about embedding abilities of original Konsole, but once I had Qt without KDE, and it was a serious problem. I decided not to rely on a chance. I could not find any interesting related project, so I had to write it. The original Konsole`s code was rewritten entirely with QT4 only; also I have to include in the project some parts of code from kde core library. All code dealing with user interface parts and session management was removed (maybe later I bring it back somehow), and the result is quite useful, I suppose. This library was compiled and tested on three linux systems, based on 2.4.32, 2.6.20, 2.6.23 kernels, x86 and amd64. Ther is also a sample application provided for quick start. %package -n %{libname} Summary: Qt4 terminal widget - base package Group: "Development/Libraries/C and C++" %description -n %{libname} QTermWidget is an opensource project based on KDE4 Konsole application. The main goal of this project is to provide unicode-enabled, embeddable QT4 widget for using as a built-in console (or terminal emulation widget). %package devel Summary: Qt4 terminal widget - development package Group: "Development/Libraries/C and C++" Requires: %{libname} %description devel Development package for QTermWidget. Contains headers and dev-libs. %prep %setup %build cmake \ -DCMAKE_C_FLAGS="%{optflags}" \ -DCMAKE_CXX_FLAGS="%{optflags}" \ -DCMAKE_BUILD_TYPE=Debug \ -DCMAKE_INSTALL_PREFIX=%{pref} \ %{_builddir}/%{name}-%{version} %{__make} %{?jobs:-j%jobs} %install %makeinstall %clean %{__rm} -rf %{buildroot} %post -n %{libname} ldconfig %postun -n %{libname} ldconfig %files -n %{libname} %defattr(-,root,root,-) %doc AUTHORS LICENSE Changelog INSTALL README %{_libdir}/lib%{name}.so.%{version} %{_datadir}/%{name} %{_datadir}/%{name}/* %files devel %defattr(-,root,root,-) %{_includedir}/*.h %{_libdir}/*.so %{_libdir}/*.so.0 %changelog * Mon Oct 29 2010 Petr Vanek 0.2 - version bump, cmake builds * Sat Jul 26 2008 TI_Eugene 0.100 - Initial build deepin-terminal-5.9.51+dfsg/CMakeLists.txt000066400000000000000000000247221475472654300203770ustar00rootroot00000000000000project(deepin-terminal) cmake_minimum_required(VERSION 3.9.5) list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}) include (src/DtkSettingsToolsMacros) option(TERM_RPATH "Do you want to use compiled libraries" ON) if(TERM_RPATH) set(CMAKE_SKIP_INSTALL_RPATH YES) set(CMAKE_SKIP_RPATH YES) endif() set(CMAKE_C_STANDARD 11) set(CMAKE_C_STANDARD_REQUIRED ON) set(CMAKE_CXX_STANDARD 11) # Find includes in corresponding build directories set(CMAKE_INCLUDE_CURRENT_DIR ON) # Instruct CMake to run moc automatically when needed set(CMAKE_AUTOMOC ON) set(CMAKE_AUTORCC ON) set(QT_MINIMUM_VERSION "5.7.1") if (${CMAKE_SYSTEM_PROCESSOR} MATCHES "sw_64") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mieee") endif () #compile flags if (CMAKE_BUILD_TYPE MATCHES Debug) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -Wall -Wextra") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -Wall -Wextra") # Enable Qt builtin debug mode add_definitions("-DQT_MESSAGELOGCONTEXT") else() # -Wl, -O2 Enable linker optimizations # -Wl, --gc-sections set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -O2 -Wl,-O1 -Wl,--gc-sections") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -O2 -Wl,-O1 -Wl,--gc-sections") endif() #Use deepin-turbo for Performance optimization set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -Wl,--as-needed -fPIE") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pie") #安全编译参数 set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fstack-protector-strong -D_FORTITY_SOURCE=1 -z noexecstack -pie -fPIC -z lazy") configure_file(src/environments.h.in environments.h @ONLY) #代码覆盖率开关 if(CMAKE_COVERAGE_ARG STREQUAL "CMAKE_COVERAGE_ARG_ON") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -Wall -fprofile-arcs -ftest-coverage") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -Wall -fprofile-arcs -ftest-coverage") endif() # Find the QtWidgets library find_package(PkgConfig REQUIRED) find_package(Qt5Core REQUIRED) find_package(Qt5DBus REQUIRED) find_package(Qt5Gui REQUIRED) find_package(Qt5Widgets REQUIRED) find_package(Qt5LinguistTools REQUIRED) find_package(Qt5Network REQUIRED) find_package(Qt5X11Extras REQUIRED) find_package(DtkWidget REQUIRED) #find_package(DtkCore REQUIRED) #find_package(DtkGui REQUIRED) include(FindPkgConfig) pkg_search_module(DtkWidget REQUIRED dtkwidget) pkg_search_module(DtkGui REQUIRED dtkgui) pkg_search_module(DtkCore REQUIRED dtkcore) pkg_search_module(GOBJECT REQUIRED gobject-2.0) pkg_check_modules(DFrameworkDBus REQUIRED dframeworkdbus) pkg_check_modules(LIBSECRET REQUIRED libsecret-1) pkg_check_modules(XCB_EWMH REQUIRED xcb-ewmh x11) # Compile definitions for TerminalWidget # So we can use QT_VERSION_CHECK set(TERMINALWIDGET_VERSION_MAJOR "0") set(TERMINALWIDGET_VERSION_MINOR "14") set(TERMINALWIDGET_VERSION_PATCH "1") add_subdirectory(3rdparty/terminalwidget) include_directories(${DtkWidget_INCLUDE_DIRS}) include_directories(${DtkGui_INCLUDE_DIRS}) include_directories(${DtkCore_INCLUDE_DIRS}) include_directories("src/common") include_directories("src/customcommand") include_directories("src/encodeplugin") include_directories("src/main") include_directories("src/remotemanage") include_directories("src/settings") include_directories("src/views") include_directories("3rdparty/terminalwidget/lib") set(LINK_LIBS Qt5::Core Qt5::DBus Qt5::Widgets Qt5::WidgetsPrivate Qt5::Network ${DtkWidget_LIBRARIES} ${DtkCore_LIBRARIES} ${DtkGUI_LIBRARIES} ${DFrameworkDBus_LIBRARIES} ${GOBJECT_LIBRARIES} ${LIBSECRET_LIBRARIES} ${XCB_EWMH_LIBRARIES} ${Qt5X11Extras_LIBRARIES} ) # Populate a CMake variable with the sources # TODO: portable headers? set (DTNG_CPP_FILES src/common/utils.cpp src/common/settingio.cpp src/common/eventlogutils.cpp src/customcommand/customcommandoptdlg.cpp src/customcommand/customcommandpanel.cpp src/customcommand/customcommandplugin.cpp src/customcommand/customcommandsearchrstpanel.cpp src/customcommand/customcommandtoppanel.cpp src/encodeplugin/encodepanelplugin.cpp src/encodeplugin/encodepanel.cpp src/encodeplugin/encodelistview.cpp src/encodeplugin/encodelistmodel.cpp src/main/main.cpp src/main/service.cpp src/main/windowsmanager.cpp src/main/mainwindow.cpp src/main/terminalapplication.cpp src/main/termproperties.cpp src/main/dbusmanager.cpp src/remotemanage/remotemanagementpanel.cpp src/remotemanage/remotemanagementplugn.cpp src/remotemanage/remotemanagementsearchpanel.cpp src/remotemanage/remotemanagementtoppanel.cpp src/remotemanage/serverconfiggrouppanel.cpp src/remotemanage/serverconfigmanager.cpp src/remotemanage/serverconfigoptdlg.cpp src/settings/newdspinbox.cpp src/settings/settings.cpp src/settings/settings_translation.cpp src/settings/shortcutmanager.cpp src/views/commonpanel.cpp src/views/pagesearchbar.cpp src/views/rightpanel.cpp src/views/tabbar.cpp src/views/tabrenamedlg.cpp src/views/tabrenamewidget.cpp src/views/termwidget.cpp src/views/termwidgetpage.cpp src/views/termbasedialog.cpp src/views/termcommandlinkbutton.cpp src/views/titlebar.cpp src/views/itemwidget.cpp src/views/focusframe.cpp src/views/iconbutton.cpp src/views/listview.cpp src/views/customthemesettingdialog.cpp src/views/themepreviewarea.cpp ) set (DTNG_HEADER_FILES src/common/define.h src/common/utils.h src/common/settingio.h src/common/eventlogutils.h src/customcommand/customcommandoptdlg.h src/customcommand/customcommandpanel.h src/customcommand/customcommandplugin.h src/customcommand/customcommandsearchrstpanel.h src/customcommand/customcommandtoppanel.h src/encodeplugin/encodepanelplugin.h src/encodeplugin/encodepanel.h src/encodeplugin/encodelistview.h src/encodeplugin/encodelistmodel.h src/main/windowsmanager.h src/main/mainwindow.h src/main/mainwindowplugininterface.h src/main/service.h src/main/terminalapplication.h src/main/termproperties.h src/main/dbusmanager.h src/remotemanage/remotemanagementpanel.h src/remotemanage/remotemanagementplugn.h src/remotemanage/remotemanagementsearchpanel.h src/remotemanage/remotemanagementtoppanel.h src/remotemanage/serverconfiggrouppanel.h src/remotemanage/serverconfigmanager.h src/remotemanage/serverconfigoptdlg.h src/settings/newdspinbox.h src/settings/settings.h src/settings/shortcutmanager.h src/views/commonpanel.h src/views/pagesearchbar.h src/views/rightpanel.h src/views/tabbar.h src/views/tabrenamedlg.h src/views/tabrenamewidget.h src/views/termwidget.h src/views/termwidgetpage.h src/views/titlebar.h src/views/termbasedialog.h src/views/termcommandlinkbutton.h src/views/itemwidget.h src/views/focusframe.h src/views/iconbutton.h src/views/listview.h src/views/customthemesettingdialog.h src/views/themepreviewarea.h ) set (DTNG_QRC_FILES src/assets/resources.qrc ) # Program set (EXE_NAME deepin-terminal) # Translation file (GLOB DTNG_TS_FILES translations/*.ts) set (DTNG_CPP_FILES_FOR_I18N ${DTNG_CPP_FILES}) dtk_create_i18n_from_json(DTNG_SETTINGS_I18N_FILES default-config.json settings_translation.cpp) list (APPEND DTNG_CPP_FILES_FOR_I18N ${DTNG_SETTINGS_I18N_FILES}) qt5_create_translation(DTNG_QM_FILES ${DTNG_CPP_FILES_FOR_I18N} ${DTNG_TS_FILES}) add_executable (${EXE_NAME} ${DTNG_HEADER_FILES} ${DTNG_CPP_FILES} ${DTNG_QRC_FILES} ${DTNG_QM_FILES} ) target_include_directories(${EXE_NAME} PUBLIC ${Qt5Widgets_LIBRARIES} ${Qt5DBus_LIBRARIES} ${Qt5Widgets_PRIVATE_INCLUDE_DIRS} ${Qt5Core_PRIVATE_INCLUDE_DIRS} ${Qt5Gui_PRIVATE_INCLUDE_DIRS} ${PROJECT_BINARY_DIR} ${DtkWidget_INCLUDE_DIRS} ${DtkCore_LIBRARIES} ${DtkGUI_INCLUDE_DIRS} ${DFrameworkDBus_INCLUDE_DIRS} ${ATSPI2_INCLUDE_DIRS} ${GOBJECT_INCLUDE_DIRS} ${LIBSECRET_INCLUDE_DIRS} ${XCB_EWMH_INCLUDE_DIRS}) target_link_libraries (deepin-terminal ${LINK_LIBS} terminalwidget5) # Install settings if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) set(CMAKE_INSTALL_PREFIX /usr) endif () # Installation #install(TARGETS deepin-terminal DESTINATION ${CMAKE_INSTALL_PREFIX}/share/deepin-terminal) install(FILES src/deepin-terminal.desktop DESTINATION ${CMAKE_INSTALL_PREFIX}/share/applications/) install(FILES src/assets/logo/deepin-terminal.svg DESTINATION ${CMAKE_INSTALL_PREFIX}/share/icons/hicolor/scalable/apps/) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/deepin-terminal DESTINATION ${CMAKE_INSTALL_PREFIX}/bin PERMISSIONS OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) install(FILES ${DTNG_QM_FILES} DESTINATION ${CMAKE_INSTALL_PREFIX}/share/deepin-terminal/translations) install(DIRECTORY src/assets/deepin-terminal DESTINATION /usr/share/deepin-manual/manual-assets/application/) message("CMAKE_INSTALL_PREFIX: " ${CMAKE_INSTALL_PREFIX}) #安装日志调试模式配置文件 install(FILES src/assets/config/debugconfig/org.deepin.terminal.json DESTINATION ${CMAKE_INSTALL_PREFIX}/share/deepin-debug-config/deepin-debug-config.d/) #install(FILES src/assets/config/debugconfig/deepin-terminal_debug.sh # DESTINATION ${CMAKE_INSTALL_PREFIX}/share/deepin-debug-config/shell/) #安装DConfig配置 set(APPID org.deepin.terminal) set(configFile ${PROJECT_SOURCE_DIR}/src/assets/config/dconfig/org.deepin.terminal.json) if (DEFINED DSG_DATA_DIR) message("-- DConfig is supported by DTK") dconfig_meta_files(APPID ${APPID} FILES ${configFile}) else() message("-- DConfig is not supported by DTK") install(FILES ${configFile} DESTINATION ${CMAKE_INSTALL_PREFIX}/share/dsg/config/org.deepin.terminal/) endif() #安装日志收集工具配置文件 install(FILES src/assets/config/logconfig/org.deepin.terminal.json DESTINATION ${CMAKE_INSTALL_PREFIX}/share/deepin-log-viewer/deepin-log.conf.d/) # Unit Test if (CMAKE_BUILD_TYPE MATCHES Debug) add_subdirectory(tests) endif() deepin-terminal-5.9.51+dfsg/LICENSE000066400000000000000000001045131475472654300166410ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. 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 state 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 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program 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, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU 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. But first, please read . deepin-terminal-5.9.51+dfsg/LICENSES/000077500000000000000000000000001475472654300170355ustar00rootroot00000000000000deepin-terminal-5.9.51+dfsg/LICENSES/Apache-2.0.txt000066400000000000000000000240501475472654300212550ustar00rootroot00000000000000Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. deepin-terminal-5.9.51+dfsg/LICENSES/BSD-3-Clause.txt000066400000000000000000000026641475472654300215700ustar00rootroot00000000000000Copyright (c) . 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 above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT HOLDER OR CONTRIBUTORS 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. deepin-terminal-5.9.51+dfsg/LICENSES/CC-BY-4.0.txt000066400000000000000000000411771475472654300207040ustar00rootroot00000000000000Creative Commons Attribution 4.0 International Creative Commons Corporation (“Creative Commons”) is not a law firm and does not provide legal services or legal advice. Distribution of Creative Commons public licenses does not create a lawyer-client or other relationship. Creative Commons makes its licenses and related information available on an “as-is” basis. Creative Commons gives no warranties regarding its licenses, any material licensed under their terms and conditions, or any related information. Creative Commons disclaims all liability for damages resulting from their use to the fullest extent possible. Using Creative Commons Public Licenses Creative Commons public licenses provide a standard set of terms and conditions that creators and other rights holders may use to share original works of authorship and other material subject to copyright and certain other rights specified in the public license below. The following considerations are for informational purposes only, are not exhaustive, and do not form part of our licenses. Considerations for licensors: Our public licenses are intended for use by those authorized to give the public permission to use material in ways otherwise restricted by copyright and certain other rights. Our licenses are irrevocable. Licensors should read and understand the terms and conditions of the license they choose before applying it. Licensors should also secure all rights necessary before applying our licenses so that the public can reuse the material as expected. Licensors should clearly mark any material not subject to the license. This includes other CC-licensed material, or material used under an exception or limitation to copyright. More considerations for licensors. Considerations for the public: By using one of our public licenses, a licensor grants the public permission to use the licensed material under specified terms and conditions. If the licensor’s permission is not necessary for any reason–for example, because of any applicable exception or limitation to copyright–then that use is not regulated by the license. Our licenses grant only permissions under copyright and certain other rights that a licensor has authority to grant. Use of the licensed material may still be restricted for other reasons, including because others have copyright or other rights in the material. A licensor may make special requests, such as asking that all changes be marked or described. Although not required by our licenses, you are encouraged to respect those requests where reasonable. More considerations for the public. Creative Commons Attribution 4.0 International Public License By exercising the Licensed Rights (defined below), You accept and agree to be bound by the terms and conditions of this Creative Commons Attribution 4.0 International Public License ("Public License"). To the extent this Public License may be interpreted as a contract, You are granted the Licensed Rights in consideration of Your acceptance of these terms and conditions, and the Licensor grants You such rights in consideration of benefits the Licensor receives from making the Licensed Material available under these terms and conditions. Section 1 – Definitions. a. Adapted Material means material subject to Copyright and Similar Rights that is derived from or based upon the Licensed Material and in which the Licensed Material is translated, altered, arranged, transformed, or otherwise modified in a manner requiring permission under the Copyright and Similar Rights held by the Licensor. For purposes of this Public License, where the Licensed Material is a musical work, performance, or sound recording, Adapted Material is always produced where the Licensed Material is synched in timed relation with a moving image. b. Adapter's License means the license You apply to Your Copyright and Similar Rights in Your contributions to Adapted Material in accordance with the terms and conditions of this Public License. c. Copyright and Similar Rights means copyright and/or similar rights closely related to copyright including, without limitation, performance, broadcast, sound recording, and Sui Generis Database Rights, without regard to how the rights are labeled or categorized. For purposes of this Public License, the rights specified in Section 2(b)(1)-(2) are not Copyright and Similar Rights. d. Effective Technological Measures means those measures that, in the absence of proper authority, may not be circumvented under laws fulfilling obligations under Article 11 of the WIPO Copyright Treaty adopted on December 20, 1996, and/or similar international agreements. e. Exceptions and Limitations means fair use, fair dealing, and/or any other exception or limitation to Copyright and Similar Rights that applies to Your use of the Licensed Material. f. Licensed Material means the artistic or literary work, database, or other material to which the Licensor applied this Public License. g. Licensed Rights means the rights granted to You subject to the terms and conditions of this Public License, which are limited to all Copyright and Similar Rights that apply to Your use of the Licensed Material and that the Licensor has authority to license. h. Licensor means the individual(s) or entity(ies) granting rights under this Public License. i. Share means to provide material to the public by any means or process that requires permission under the Licensed Rights, such as reproduction, public display, public performance, distribution, dissemination, communication, or importation, and to make material available to the public including in ways that members of the public may access the material from a place and at a time individually chosen by them. j. Sui Generis Database Rights means rights other than copyright resulting from Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, as amended and/or succeeded, as well as other essentially equivalent rights anywhere in the world. k. You means the individual or entity exercising the Licensed Rights under this Public License. Your has a corresponding meaning. Section 2 – Scope. a. License grant. 1. Subject to the terms and conditions of this Public License, the Licensor hereby grants You a worldwide, royalty-free, non-sublicensable, non-exclusive, irrevocable license to exercise the Licensed Rights in the Licensed Material to: A. reproduce and Share the Licensed Material, in whole or in part; and B. produce, reproduce, and Share Adapted Material. 2. Exceptions and Limitations. For the avoidance of doubt, where Exceptions and Limitations apply to Your use, this Public License does not apply, and You do not need to comply with its terms and conditions. 3. Term. The term of this Public License is specified in Section 6(a). 4. Media and formats; technical modifications allowed. The Licensor authorizes You to exercise the Licensed Rights in all media and formats whether now known or hereafter created, and to make technical modifications necessary to do so. The Licensor waives and/or agrees not to assert any right or authority to forbid You from making technical modifications necessary to exercise the Licensed Rights, including technical modifications necessary to circumvent Effective Technological Measures. For purposes of this Public License, simply making modifications authorized by this Section 2(a)(4) never produces Adapted Material. 5. Downstream recipients. A. Offer from the Licensor – Licensed Material. Every recipient of the Licensed Material automatically receives an offer from the Licensor to exercise the Licensed Rights under the terms and conditions of this Public License. B. No downstream restrictions. You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, the Licensed Material if doing so restricts exercise of the Licensed Rights by any recipient of the Licensed Material. 6. No endorsement. Nothing in this Public License constitutes or may be construed as permission to assert or imply that You are, or that Your use of the Licensed Material is, connected with, or sponsored, endorsed, or granted official status by, the Licensor or others designated to receive attribution as provided in Section 3(a)(1)(A)(i). b. Other rights. 1. Moral rights, such as the right of integrity, are not licensed under this Public License, nor are publicity, privacy, and/or other similar personality rights; however, to the extent possible, the Licensor waives and/or agrees not to assert any such rights held by the Licensor to the limited extent necessary to allow You to exercise the Licensed Rights, but not otherwise. 2. Patent and trademark rights are not licensed under this Public License. 3. To the extent possible, the Licensor waives any right to collect royalties from You for the exercise of the Licensed Rights, whether directly or through a collecting society under any voluntary or waivable statutory or compulsory licensing scheme. In all other cases the Licensor expressly reserves any right to collect such royalties. Section 3 – License Conditions. Your exercise of the Licensed Rights is expressly made subject to the following conditions. a. Attribution. 1. If You Share the Licensed Material (including in modified form), You must: A. retain the following if it is supplied by the Licensor with the Licensed Material: i. identification of the creator(s) of the Licensed Material and any others designated to receive attribution, in any reasonable manner requested by the Licensor (including by pseudonym if designated); ii. a copyright notice; iii. a notice that refers to this Public License; iv. a notice that refers to the disclaimer of warranties; v. a URI or hyperlink to the Licensed Material to the extent reasonably practicable; B. indicate if You modified the Licensed Material and retain an indication of any previous modifications; and C. indicate the Licensed Material is licensed under this Public License, and include the text of, or the URI or hyperlink to, this Public License. 2. You may satisfy the conditions in Section 3(a)(1) in any reasonable manner based on the medium, means, and context in which You Share the Licensed Material. For example, it may be reasonable to satisfy the conditions by providing a URI or hyperlink to a resource that includes the required information. 3. If requested by the Licensor, You must remove any of the information required by Section 3(a)(1)(A) to the extent reasonably practicable. 4. If You Share Adapted Material You produce, the Adapter's License You apply must not prevent recipients of the Adapted Material from complying with this Public License. Section 4 – Sui Generis Database Rights. Where the Licensed Rights include Sui Generis Database Rights that apply to Your use of the Licensed Material: a. for the avoidance of doubt, Section 2(a)(1) grants You the right to extract, reuse, reproduce, and Share all or a substantial portion of the contents of the database; b. if You include all or a substantial portion of the database contents in a database in which You have Sui Generis Database Rights, then the database in which You have Sui Generis Database Rights (but not its individual contents) is Adapted Material; and c. You must comply with the conditions in Section 3(a) if You Share all or a substantial portion of the contents of the database. For the avoidance of doubt, this Section 4 supplements and does not replace Your obligations under this Public License where the Licensed Rights include other Copyright and Similar Rights. Section 5 – Disclaimer of Warranties and Limitation of Liability. a. Unless otherwise separately undertaken by the Licensor, to the extent possible, the Licensor offers the Licensed Material as-is and as-available, and makes no representations or warranties of any kind concerning the Licensed Material, whether express, implied, statutory, or other. This includes, without limitation, warranties of title, merchantability, fitness for a particular purpose, non-infringement, absence of latent or other defects, accuracy, or the presence or absence of errors, whether or not known or discoverable. Where disclaimers of warranties are not allowed in full or in part, this disclaimer may not apply to You. b. To the extent possible, in no event will the Licensor be liable to You on any legal theory (including, without limitation, negligence) or otherwise for any direct, special, indirect, incidental, consequential, punitive, exemplary, or other losses, costs, expenses, or damages arising out of this Public License or use of the Licensed Material, even if the Licensor has been advised of the possibility of such losses, costs, expenses, or damages. Where a limitation of liability is not allowed in full or in part, this limitation may not apply to You. c. The disclaimer of warranties and limitation of liability provided above shall be interpreted in a manner that, to the extent possible, most closely approximates an absolute disclaimer and waiver of all liability. Section 6 – Term and Termination. a. This Public License applies for the term of the Copyright and Similar Rights licensed here. However, if You fail to comply with this Public License, then Your rights under this Public License terminate automatically. b. Where Your right to use the Licensed Material has terminated under Section 6(a), it reinstates: 1. automatically as of the date the violation is cured, provided it is cured within 30 days of Your discovery of the violation; or 2. upon express reinstatement by the Licensor. c. For the avoidance of doubt, this Section 6(b) does not affect any right the Licensor may have to seek remedies for Your violations of this Public License. d. For the avoidance of doubt, the Licensor may also offer the Licensed Material under separate terms or conditions or stop distributing the Licensed Material at any time; however, doing so will not terminate this Public License. e. Sections 1, 5, 6, 7, and 8 survive termination of this Public License. Section 7 – Other Terms and Conditions. a. The Licensor shall not be bound by any additional or different terms or conditions communicated by You unless expressly agreed. b. Any arrangements, understandings, or agreements regarding the Licensed Material not stated herein are separate from and independent of the terms and conditions of this Public License. Section 8 – Interpretation. a. For the avoidance of doubt, this Public License does not, and shall not be interpreted to, reduce, limit, restrict, or impose conditions on any use of the Licensed Material that could lawfully be made without permission under this Public License. b. To the extent possible, if any provision of this Public License is deemed unenforceable, it shall be automatically reformed to the minimum extent necessary to make it enforceable. If the provision cannot be reformed, it shall be severed from this Public License without affecting the enforceability of the remaining terms and conditions. c. No term or condition of this Public License will be waived and no failure to comply consented to unless expressly agreed to by the Licensor. d. Nothing in this Public License constitutes or may be interpreted as a limitation upon, or waiver of, any privileges and immunities that apply to the Licensor or You, including from the legal processes of any jurisdiction or authority. Creative Commons is not a party to its public licenses. Notwithstanding, Creative Commons may elect to apply one of its public licenses to material it publishes and in those instances will be considered the “Licensor.” Except for the limited purpose of indicating that material is shared under a Creative Commons public license or as otherwise permitted by the Creative Commons policies published at creativecommons.org/policies, Creative Commons does not authorize the use of the trademark “Creative Commons” or any other trademark or logo of Creative Commons without its prior written consent including, without limitation, in connection with any unauthorized modifications to any of its public licenses or any other arrangements, understandings, or agreements concerning use of licensed material. For the avoidance of doubt, this paragraph does not form part of the public licenses. Creative Commons may be contacted at creativecommons.org. deepin-terminal-5.9.51+dfsg/LICENSES/CC0-1.0.txt000066400000000000000000000156101475472654300204420ustar00rootroot00000000000000Creative Commons Legal Code CC0 1.0 Universal CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED HEREUNDER. Statement of Purpose The laws of most jurisdictions throughout the world automatically confer exclusive Copyright and Related Rights (defined below) upon the creator and subsequent owner(s) (each and all, an "owner") of an original work of authorship and/or a database (each, a "Work"). Certain owners wish to permanently relinquish those rights to a Work for the purpose of contributing to a commons of creative, cultural and scientific works ("Commons") that the public can reliably and without fear of later claims of infringement build upon, modify, incorporate in other works, reuse and redistribute as freely as possible in any form whatsoever and for any purposes, including without limitation commercial purposes. These owners may contribute to the Commons to promote the ideal of a free culture and the further production of creative, cultural and scientific works, or to gain reputation or greater distribution for their Work in part through the use and efforts of others. For these and/or other purposes and motivations, and without any expectation of additional consideration or compensation, the person associating CC0 with a Work (the "Affirmer"), to the extent that he or she is an owner of Copyright and Related Rights in the Work, voluntarily elects to apply CC0 to the Work and publicly distribute the Work under its terms, with knowledge of his or her Copyright and Related Rights in the Work and the meaning and intended legal effect of CC0 on those rights. 1. Copyright and Related Rights. A Work made available under CC0 may be protected by copyright and related or neighboring rights ("Copyright and Related Rights"). Copyright and Related Rights include, but are not limited to, the following: i. the right to reproduce, adapt, distribute, perform, display, communicate, and translate a Work; ii. moral rights retained by the original author(s) and/or performer(s); iii. publicity and privacy rights pertaining to a person's image or likeness depicted in a Work; iv. rights protecting against unfair competition in regards to a Work, subject to the limitations in paragraph 4(a), below; v. rights protecting the extraction, dissemination, use and reuse of data in a Work; vi. database rights (such as those arising under Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, and under any national implementation thereof, including any amended or successor version of such directive); and vii. other similar, equivalent or corresponding rights throughout the world based on applicable law or treaty, and any national implementations thereof. 2. Waiver. To the greatest extent permitted by, but not in contravention of, applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and unconditionally waives, abandons, and surrenders all of Affirmer's Copyright and Related Rights and associated claims and causes of action, whether now known or unknown (including existing as well as future claims and causes of action), in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each member of the public at large and to the detriment of Affirmer's heirs and successors, fully intending that such Waiver shall not be subject to revocation, rescission, cancellation, termination, or any other legal or equitable action to disrupt the quiet enjoyment of the Work by the public as contemplated by Affirmer's express Statement of Purpose. 3. Public License Fallback. Should any part of the Waiver for any reason be judged legally invalid or ineffective under applicable law, then the Waiver shall be preserved to the maximum extent permitted taking into account Affirmer's express Statement of Purpose. In addition, to the extent the Waiver is so judged Affirmer hereby grants to each affected person a royalty-free, non transferable, non sublicensable, non exclusive, irrevocable and unconditional license to exercise Affirmer's Copyright and Related Rights in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "License"). The License shall be deemed effective as of the date CC0 was applied by Affirmer to the Work. Should any part of the License for any reason be judged legally invalid or ineffective under applicable law, such partial invalidity or ineffectiveness shall not invalidate the remainder of the License, and in such case Affirmer hereby affirms that he or she will not (i) exercise any of his or her remaining Copyright and Related Rights in the Work or (ii) assert any associated claims and causes of action with respect to the Work, in either case contrary to Affirmer's express Statement of Purpose. 4. Limitations and Disclaimers. a. No trademark or patent rights held by Affirmer are waived, abandoned, surrendered, licensed or otherwise affected by this document. b. Affirmer offers the Work as-is and makes no representations or warranties of any kind concerning the Work, express, implied, statutory or otherwise, including without limitation warranties of title, merchantability, fitness for a particular purpose, non infringement, or the absence of latent or other defects, accuracy, or the present or absence of errors, whether or not discoverable, all to the greatest extent permissible under applicable law. c. Affirmer disclaims responsibility for clearing rights of other persons that may apply to the Work or any use thereof, including without limitation any person's Copyright and Related Rights in the Work. Further, Affirmer disclaims responsibility for obtaining any necessary consents, permissions or other rights required for any use of the Work. d. Affirmer understands and acknowledges that Creative Commons is not a party to this document and has no duty or obligation with respect to this CC0 or use of the Work. deepin-terminal-5.9.51+dfsg/LICENSES/GPL-2.0-or-later.txt000066400000000000000000000416711475472654300222510ustar00rootroot00000000000000GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 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. one line to give the program's name and an idea of what it does. Copyright (C) yyyy name of author 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. signature of Ty Coon, 1 April 1989 Ty Coon, President of Vice deepin-terminal-5.9.51+dfsg/LICENSES/GPL-3.0-or-later.txt000066400000000000000000001035561475472654300222530ustar00rootroot00000000000000GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright © 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. “This License” refers to version 3 of the GNU General Public License. “Copyright” also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. “The Program” refers to any copyrightable work licensed under this License. Each licensee is addressed as “you”. “Licensees” and “recipients” may be individuals or organizations. To “modify” a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a “modified version” of the earlier work or a work “based on” the earlier work. A “covered work” means either the unmodified Program or a work based on the Program. To “propagate” a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To “convey” a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays “Appropriate Legal Notices” to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The “source code” for a work means the preferred form of the work for making modifications to it. “Object code” means any non-source form of a work. A “Standard Interface” means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The “System Libraries” of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A “Major Component”, in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The “Corresponding Source” for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to “keep intact all notices”. c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an “aggregate” if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A “User Product” is either (1) a “consumer product”, which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, “normally used” refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. “Installation Information” for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. “Additional permissions” are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered “further restrictions” within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An “entity transaction” is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A “contributor” is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's “contributor version”. A contributor's “essential patent claims” are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, “control” includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a “patent license” is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To “grant” such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. “Knowingly relying” means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is “discriminatory” if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License “or any later version” applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM “AS IS” WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. 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 state 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 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program 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, your program's commands might be different; for a GUI interface, you would use an “about box”. You should also get your employer (if you work as a programmer) or school, if any, to sign a “copyright disclaimer” for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU 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. But first, please read . deepin-terminal-5.9.51+dfsg/LICENSES/LGPL-3.0-or-later.txt000066400000000000000000001221621475472654300223610ustar00rootroot00000000000000GNU LESSER GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. This version of the GNU Lesser General Public License incorporates the terms and conditions of version 3 of the GNU General Public License, supplemented by the additional permissions listed below. 0. Additional Definitions. As used herein, "this License" refers to version 3 of the GNU Lesser General Public License, and the "GNU GPL" refers to version 3 of the GNU General Public License. "The Library" refers to a covered work governed by this License, other than an Application or a Combined Work as defined below. An "Application" is any work that makes use of an interface provided by the Library, but which is not otherwise based on the Library. Defining a subclass of a class defined by the Library is deemed a mode of using an interface provided by the Library. A "Combined Work" is a work produced by combining or linking an Application with the Library. The particular version of the Library with which the Combined Work was made is also called the "Linked Version". The "Minimal Corresponding Source" for a Combined Work means the Corresponding Source for the Combined Work, excluding any source code for portions of the Combined Work that, considered in isolation, are based on the Application, and not on the Linked Version. The "Corresponding Application Code" for a Combined Work means the object code and/or source code for the Application, including any data and utility programs needed for reproducing the Combined Work from the Application, but excluding the System Libraries of the Combined Work. 1. Exception to Section 3 of the GNU GPL. You may convey a covered work under sections 3 and 4 of this License without being bound by section 3 of the GNU GPL. 2. Conveying Modified Versions. If you modify a copy of the Library, and, in your modifications, a facility refers to a function or data to be supplied by an Application that uses the facility (other than as an argument passed when the facility is invoked), then you may convey a copy of the modified version: a) under this License, provided that you make a good faith effort to ensure that, in the event an Application does not supply the function or data, the facility still operates, and performs whatever part of its purpose remains meaningful, or b) under the GNU GPL, with none of the additional permissions of this License applicable to that copy. 3. Object Code Incorporating Material from Library Header Files. The object code form of an Application may incorporate material from a header file that is part of the Library. You may convey such object code under terms of your choice, provided that, if the incorporated material is not limited to numerical parameters, data structure layouts and accessors, or small macros, inline functions and templates (ten or fewer lines in length), you do both of the following: a) Give prominent notice with each copy of the object code that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the object code with a copy of the GNU GPL and this license document. 4. Combined Works. You may convey a Combined Work under terms of your choice that, taken together, effectively do not restrict modification of the portions of the Library contained in the Combined Work and reverse engineering for debugging such modifications, if you also do each of the following: a) Give prominent notice with each copy of the Combined Work that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the Combined Work with a copy of the GNU GPL and this license document. c) For a Combined Work that displays copyright notices during execution, include the copyright notice for the Library among these notices, as well as a reference directing the user to the copies of the GNU GPL and this license document. d) Do one of the following: 0) Convey the Minimal Corresponding Source under the terms of this License, and the Corresponding Application Code in a form suitable for, and under terms that permit, the user to recombine or relink the Application with a modified version of the Linked Version to produce a modified Combined Work, in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source. 1) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (a) uses at run time a copy of the Library already present on the user's computer system, and (b) will operate properly with a modified version of the Library that is interface-compatible with the Linked Version. e) Provide Installation Information, but only if you would otherwise be required to provide such information under section 6 of the GNU GPL, and only to the extent that such information is necessary to install and execute a modified version of the Combined Work produced by recombining or relinking the Application with a modified version of the Linked Version. (If you use option 4d0, the Installation Information must accompany the Minimal Corresponding Source and Corresponding Application Code. If you use option 4d1, you must provide the Installation Information in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source.) 5. Combined Libraries. You may place library facilities that are a work based on the Library side by side in a single library together with other library facilities that are not Applications and are not covered by this License, and convey such a combined library under terms of your choice, if you do both of the following: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities, conveyed under the terms of this License. b) Give prominent notice with the combined library that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 6. Revised Versions of the GNU Lesser General Public License. The Free Software Foundation may publish revised and/or new versions of the GNU Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library as you received it specifies that a certain numbered version of the GNU Lesser General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that published version or of any later version published by the Free Software Foundation. If the Library as you received it does not specify a version number of the GNU Lesser General Public License, you may choose any version of the GNU Lesser General Public License ever published by the Free Software Foundation. If the Library as you received it specifies that a proxy can decide whether future versions of the GNU Lesser General Public License shall apply, that proxy's public statement of acceptance of any version is permanent authorization for you to choose that version for the Library. GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright © 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. “This License” refers to version 3 of the GNU General Public License. “Copyright” also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. “The Program” refers to any copyrightable work licensed under this License. Each licensee is addressed as “you”. “Licensees” and “recipients” may be individuals or organizations. To “modify” a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a “modified version” of the earlier work or a work “based on” the earlier work. A “covered work” means either the unmodified Program or a work based on the Program. To “propagate” a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To “convey” a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays “Appropriate Legal Notices” to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The “source code” for a work means the preferred form of the work for making modifications to it. “Object code” means any non-source form of a work. A “Standard Interface” means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The “System Libraries” of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A “Major Component”, in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The “Corresponding Source” for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to “keep intact all notices”. c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an “aggregate” if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A “User Product” is either (1) a “consumer product”, which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, “normally used” refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. “Installation Information” for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. “Additional permissions” are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered “further restrictions” within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An “entity transaction” is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A “contributor” is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's “contributor version”. A contributor's “essential patent claims” are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, “control” includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a “patent license” is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To “grant” such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. “Knowingly relying” means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is “discriminatory” if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License “or any later version” applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM “AS IS” WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. 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 state 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 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program 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, your program's commands might be different; for a GUI interface, you would use an “about box”. You should also get your employer (if you work as a programmer) or school, if any, to sign a “copyright disclaimer” for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU 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. But first, please read . deepin-terminal-5.9.51+dfsg/LICENSES/LLVM-exception.txt000066400000000000000000000016271475472654300223520ustar00rootroot00000000000000---- LLVM Exceptions to the Apache 2.0 License ---- As an exception, if, as a result of your compiling your source code, portions of this Software are embedded into an Object form of such source code, you may redistribute such embedded portions in such Object form without complying with the conditions of Sections 4(a), 4(b) and 4(d) of the License. In addition, if you combine or link compiled forms of this Software with software that is licensed under the GPLv2 ("Combined Software") and if a court of competent jurisdiction determines that the patent provision (Section 3), the indemnity provision (Section 9) or other Section of the License conflicts with the conditions of the GPLv2, you may retroactively and prospectively choose to deem waived or otherwise exclude such Section(s) of the License, but only in their entirety and only with respect to the Combined Software. deepin-terminal-5.9.51+dfsg/README.md000066400000000000000000000037771475472654300171250ustar00rootroot00000000000000# Deepin Terminal Deepin Terminal is an advanced terminal emulator with workspace , multiple windows, remote management, quake mode and other features. ## Dependencies ### Build dependencies * cmake * pkg-config * Qt5(>= 5.7.1) with modules: - qtbase5-dev - qtbase5-private-dev - qttools5-dev-tools * libdtkwidget-dev(>=5.2.2) with modules: - dtkcore-dev - dtkwidget-dev - dtkgui-dev * lxqt-build-tools(>= 0.6.0) * libdframeworkdbus-dev * libutf8proc-dev * libatspi2.0-dev * libglib2.0-dev * libsecret-1-dev ## Installation ### Build from source code 1. Make sure you have installed all dependencies, you can use the following command. ``` $ cd deepin-terminal $ sudo apt build-dep . ``` 2. Build: ``` $ cd deepin-terminal $ mkdir build $ cd build $ cmake .. $ make ``` 3. Install: ``` $ sudo make install ``` The executable binary file could be found at `/usr/bin/deepin-terminal` after the installation is finished. ### Other distro CMake will tell you which package you are missing. ## Config file * Terminal Settings's configure save at:
~/.config/deepin/deepin-terminal/config.conf * Remote Servers' configure save at:
~/.config/deepin/deepin-terminal/server-config.conf * Custom Command's configure save at:
~/.config/deepin/deepin-terminal/command-config.conf ## Usage Execute `deepin-terminal -h` to get more details. ## Getting help Any usage issues can ask for help via * [Gitter](https://gitter.im/orgs/linuxdeepin/rooms) * [IRC channel](https://webchat.freenode.net/?channels=deepin) * [Forum](https://bbs.deepin.org) * [WiKi](https://wiki.deepin.org/) ## Getting involved We encourage you to report issues and contribute changes * [Contribution guide for developers](https://github.com/linuxdeepin/developer-center/wiki/Contribution-Guidelines-for-Developers-en). (English) * [开发者代码贡献指南](https://github.com/linuxdeepin/developer-center/wiki/Contribution-Guidelines-for-Developers) (中文) ## License Deepin Terminal is licensed under [GPL-3.0-or-later](LICENSE). deepin-terminal-5.9.51+dfsg/README.zh_CN.md000066400000000000000000000037471475472654300201220ustar00rootroot00000000000000# Deepin Terminal 深度终端是一款高级终端仿真器,具有工作区、多窗口、远程管理、震动模式等功能. ## 依赖关系 ### 建立依赖关系 * cmake * pkg-config * Qt5(>= 5.7.1) with modules: - qtbase5-dev - qtbase5-private-dev - qttools5-dev-tools * libdtkwidget-dev(>=5.2.2) with modules: - dtkcore-dev - dtkwidget-dev - dtkgui-dev * lxqt-build-tools(>= 0.6.0) * libdframeworkdbus-dev * libutf8proc-dev * libatspi2.0-dev * libglib2.0-dev * libsecret-1-dev ## 安装 ### 从源代码构建 1. Make sure you have installed all dependencies, you can use the following command. ``` $ cd deepin-terminal $ sudo apt build-dep . ``` 2. 构建: ``` $ cd deepin-terminal $ mkdir build $ cd build $ cmake .. $ make ``` 3. 依赖: ``` $ sudo make install ``` The executable binary file could be found at `/usr/bin/deepin-terminal` after the installation is finished. ### 其他发行版 CMake will tell you which package you are missing. ## 配置文件 * Terminal Settings's configure save at:
~/.config/deepin/deepin-terminal/config.conf * Remote Servers' configure save at:
~/.config/deepin/deepin-terminal/server-config.conf * Custom Command's configure save at:
~/.config/deepin/deepin-terminal/command-config.conf ## 用法 Execute `deepin-terminal -h` to get more details. ## 寻求帮助 Any usage issues can ask for help via * [Gitter](https://gitter.im/orgs/linuxdeepin/rooms) * [IRC channel](https://webchat.freenode.net/?channels=deepin) * [Forum](https://bbs.deepin.org) * [WiKi](https://wiki.deepin.org/) ## 参与贡献 We encourage you to report issues and contribute changes * [Contribution guide for developers](https://github.com/linuxdeepin/developer-center/wiki/Contribution-Guidelines-for-Developers-en). (English) * [开发者代码贡献指南](https://github.com/linuxdeepin/developer-center/wiki/Contribution-Guidelines-for-Developers) (中文) ## 协议 Deepin Terminal 根据 [GPL-3.0-or-later](许可证)获得许可. deepin-terminal-5.9.51+dfsg/debian/000077500000000000000000000000001475472654300170525ustar00rootroot00000000000000deepin-terminal-5.9.51+dfsg/debian/changelog000066400000000000000000000043531475472654300207310ustar00rootroot00000000000000deepin-terminal (5.9.51) unstable; urgency=medium * New version 5.9.51. -- xiepengfei Sat, 14 Dec 2024 14:23:55 +0800 deepin-terminal (5.9.50) unstable; urgency=medium * New version 5.9.50. -- xiepengfei Sat, 30 Nov 2024 13:13:27 +0800 deepin-terminal (5.9.49) unstable; urgency=medium * New version 5.9.49. -- wangcong Mon, 15 Jan 2024 21:18:00 +0800 deepin-terminal (5.9.48) unstable; urgency=medium * fix: Changes the default value of the debug mode configuration file. * fix: Crash when show/close setting dialog. (#325) (Bug: 28636) * feat: Debug mode log adaptation -- wangcong Tue, 9 Jan 2024 21:18:00 +0800 deepin-terminal (5.9.47) unstable; urgency=medium * fix: Fixed the issue of high CPU usage due to cursor flickering. (#317) (Bug: 231445) * Revert "fix: Supplementary 2 character width character set (#284)". (#321) (Bug: 272385) -- renbin Mon, 25 Dec 2023 15:54:39 +0800 deepin-terminal (5.9.46) unstable; urgency=medium * fix: Roll back gb18030 midification. -- renbin Fri, 03 Nov 2023 10:55:01 +0800 deepin-terminal (5.9.45) unstable; urgency=medium * fix: Tab height error under low version dtk. -- renbin Wed, 25 Oct 2023 13:31:59 +0800 deepin-terminal (5.9.44) unstable; urgency=medium * fix: Add 2 character width charset. * feat: Improve debug log and add log category. * feat: [UI] Adapt compact mode.(Task: 292067)(Influence: UI) -- renbin Mon, 16 Oct 2023 15:54:30 +0800 deepin-terminal (5.9.43) unstable; urgency=medium * New version 5.9.43. -- muyuankai Fri, 16 Jun 2023 15:48:31 +0800 deepin-terminal (5.9.42) unstable; urgency=medium * New version 5.9.42 * -- muyuankai Thu, 13 Apr 2023 15:20:11 +0800 deepin-terminal (5.9.40) unstable; urgency=medium * New version 5.9.40 -- hemingyang Mon, 03 Jan 2023 11:23:05 +0800 deepin-terminal (5.2.0) unstable; urgency=medium * Initial Release. -- Deepin Packages Builder Mon, 13 Jan 2020 16:13:35 +0800 deepin-terminal-5.9.51+dfsg/debian/compat000066400000000000000000000000031475472654300202510ustar00rootroot0000000000000011 deepin-terminal-5.9.51+dfsg/debian/control000066400000000000000000000021771475472654300204640ustar00rootroot00000000000000Source: deepin-terminal Section: utils Priority: optional Maintainer: Deepin Packages Builder Build-Depends: debhelper(>= 11), cmake, pkg-config, qtbase5-dev, qttools5-dev-tools, qtbase5-private-dev, libdtkwidget-dev, libdframeworkdbus-dev, lxqt-build-tools(>= 0.6.0~), libutf8proc-dev, libglib2.0-dev, libsecret-1-dev, libgtest-dev, libgmock-dev, libxcb-ewmh-dev, libchardet-dev, libuchardet-dev (>= 0.0.6), libicu-dev Standards-Version: 4.5.1 Homepage: https://www.deepin.com/ Package: deepin-terminal Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends}, expect, zssh, libuchardet0 (>= 0.0.6), libchardet1 Recommends: uos-reporter, deepin-event-log Description: Terminal is an advanced terminal emulator with workspace, multiple windows, remote management, quake mode and other features. Terminal is a terminal emulator with simple interface, rich and powerful functions such as multi-windows, workspace, remote management, Quake mode and etc. You can instantly start and close Terminal smoothly like normal file window, allowing you to input commands with facility and no distractions. deepin-terminal-5.9.51+dfsg/debian/copyright000066400000000000000000000263321475472654300210130ustar00rootroot00000000000000Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Name: deepin-terminal Source: https://github.com/linuxdeepin/deepin-terminal Files: * Copyright: 2019 ~ 2020 Uniontech Software Technology Co.,Ltd. License: GPL-3+ Files: tests/src/stub/addr_pri.h tests/src/stub/stub.h Copyright: 2019 coolxv License: Expat Files: src/assets/other/ssh_login.sh Copyright: 2011 ~ 2016 Deepin, Inc. 2011 ~ 2016 Wang Yong License: GPL-3+ Files: src/DtkSettingsToolsMacros.cmake Copyright: 2019 Gary Wang License: BSD-3-Clause Files: 3rdparty/terminalwidget/lib/BlockArray.cpp 3rdparty/terminalwidget/lib/BlockArray.h 3rdparty/terminalwidget/lib/Character.h 3rdparty/terminalwidget/lib/CharacterColor.h 3rdparty/terminalwidget/lib/CharacterFormat.cpp 3rdparty/terminalwidget/lib/CharacterFormat.h 3rdparty/terminalwidget/lib/ColorScheme.h 3rdparty/terminalwidget/lib/Emulation.h 3rdparty/terminalwidget/lib/Filter.h 3rdparty/terminalwidget/lib/HistorySearch.cpp 3rdparty/terminalwidget/lib/HistorySearch.h 3rdparty/terminalwidget/lib/KeyboardTranslator.h 3rdparty/terminalwidget/lib/ProcessInfo.h 3rdparty/terminalwidget/lib/Pty.h 3rdparty/terminalwidget/lib/Screen.h 3rdparty/terminalwidget/lib/ScreenWindow.h 3rdparty/terminalwidget/lib/SearchBar.cpp 3rdparty/terminalwidget/lib/SearchBar.h 3rdparty/terminalwidget/lib/Session.cpp 3rdparty/terminalwidget/lib/Session.h 3rdparty/terminalwidget/lib/SessionManager.h 3rdparty/terminalwidget/lib/ShellCommand.cpp 3rdparty/terminalwidget/lib/ShellCommand.h 3rdparty/terminalwidget/lib/TerminalDisplay.h 3rdparty/terminalwidget/lib/Vt102Emulation.h 3rdparty/terminalwidget/lib/history/HistoryFile.h 3rdparty/terminalwidget/lib/history/HistoryScroll.h 3rdparty/terminalwidget/lib/history/HistoryScrollFile.cpp 3rdparty/terminalwidget/lib/history/HistoryScrollFile.h 3rdparty/terminalwidget/lib/history/HistoryScrollNone.h 3rdparty/terminalwidget/lib/history/HistoryType.cpp 3rdparty/terminalwidget/lib/history/HistoryType.h 3rdparty/terminalwidget/lib/history/HistoryTypeFile.cpp 3rdparty/terminalwidget/lib/history/HistoryTypeFile.h 3rdparty/terminalwidget/lib/history/HistoryTypeNone.cpp 3rdparty/terminalwidget/lib/history/HistoryTypeNone.h 3rdparty/terminalwidget/lib/history/compact/CompactHistoryBlock.h 3rdparty/terminalwidget/lib/history/compact/CompactHistoryBlockList.h 3rdparty/terminalwidget/lib/history/compact/CompactHistoryLine.cpp 3rdparty/terminalwidget/lib/history/compact/CompactHistoryLine.h 3rdparty/terminalwidget/lib/history/compact/CompactHistoryScroll.h 3rdparty/terminalwidget/lib/history/compact/CompactHistoryType.h Copyright: 1997-1998 Lars Doelle 2000 Stephan Kulow 2006-2008 Robert Knight 2013 Christian Surlykke License: GPL-2+ Files: 3rdparty/terminalwidget/lib/ColorScheme.cpp 3rdparty/terminalwidget/lib/Emulation.cpp 3rdparty/terminalwidget/lib/Filter.cpp 3rdparty/terminalwidget/lib/KeyboardTranslator.cpp 3rdparty/terminalwidget/lib/ProcessInfo.cpp 3rdparty/terminalwidget/lib/Pty.cpp 3rdparty/terminalwidget/lib/Screen.cpp 3rdparty/terminalwidget/lib/ScreenWindow.cpp 3rdparty/terminalwidget/lib/SessionManager.cpp 3rdparty/terminalwidget/lib/TerminalDisplay.cpp 3rdparty/terminalwidget/lib/Vt102Emulation.cpp 3rdparty/terminalwidget/lib/history/HistoryFile.cpp 3rdparty/terminalwidget/lib/history/HistoryScroll.cpp 3rdparty/terminalwidget/lib/history/HistoryScrollNone.cpp 3rdparty/terminalwidget/lib/history/compact/CompactHistoryBlock.cpp 3rdparty/terminalwidget/lib/history/compact/CompactHistoryBlockList.cpp 3rdparty/terminalwidget/lib/history/compact/CompactHistoryScroll.cpp 3rdparty/terminalwidget/lib/history/compact/CompactHistoryType.cpp Copyright: 1996 Matthias Ettrich 1997-1998 Lars Doelle 2006-2008 Robert Knight 2007-2008 Robert Knight 2007-2008 Robert Knight License: GPL-2+ Files: 3rdparty/terminalwidget/lib/LineFont.h 3rdparty/terminalwidget/lib/TerminalCharacterDecoder.cpp Copyright: 2006-2008 Robert Knight License: LGPL-2+ Files: 3rdparty/terminalwidget/lib/kprocess.cpp 3rdparty/terminalwidget/lib/kprocess.h 3rdparty/terminalwidget/lib/kpty.cpp 3rdparty/terminalwidget/lib/kpty.h 3rdparty/terminalwidget/lib/kpty_p.h 3rdparty/terminalwidget/lib/kptydevice.cpp 3rdparty/terminalwidget/lib/kptydevice.h 3rdparty/terminalwidget/lib/kptyprocess.cpp 3rdparty/terminalwidget/lib/kptyprocess.h 3rdparty/terminalwidget/lib/qtermwidget.cpp 3rdparty/terminalwidget/lib/qtermwidget.h 3rdparty/terminalwidget/lib/tools.cpp 3rdparty/terminalwidget/lib/tools.h Copyright: 2002 Waldo Bastian 2002-2007 Oswald Buddenhagen 2008 e_k (e_k@users.sourceforge.net) 2010 KDE e.V. License: LGPL-2+ Files: 3rdparty/terminalwidget/lib/ColorTables.h 3rdparty/terminalwidget/lib/DefaultTranslatorText.h 3rdparty/terminalwidget/lib/ExtendedDefaultTranslator.h 3rdparty/terminalwidget/lib/TerminalCharacterDecoder.h 3rdparty/terminalwidget/lib/konsole_wcwidth.cpp 3rdparty/terminalwidget/lib/konsole_wcwidth.h Copyright: 2006-2008 Robert Knight License: LGPL-2+ License: GPL-3+ This package is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. . This package is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. . You should have received a copy of the GNU General Public License along with this program. If not, see . On Debian systems, the complete text of the GNU General Public License version 3 can be found in "/usr/share/common-licenses/GPL-3". License: Expat Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: . The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. . THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFT License: GPL-2+ 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 package; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA . On Debian systems, the full text of the GNU General Public License version 2 can be found in the file "/usr/share/common-licenses/GPL-2". License: LGPL-2+ This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. . This library 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 Library General Public License for more details. . You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. . On Debian systems, the full text of the GNU General Public License version 2 can be found in the file "/usr/share/common-licenses/LGPL-2". License: BSD-3-Clause 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 above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. . THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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. . On Debian systems, the full text of the GNU General Public License version 2 can be found in the file "/usr/share/common-licenses/BSD". deepin-terminal-5.9.51+dfsg/debian/deepin-terminal.1000066400000000000000000000042741475472654300222200ustar00rootroot00000000000000.\" Hey, EMACS: -*- nroff -*- .\" (C) Copyright 2021 UnionTech Software Technology Co., Ltd, .\" .TH "deepin-terminal" "1" "2021-1-28" "Deepin" .\" Please adjust this date whenever revising the manpage. .\" .\" Some roff macros, for reference: .\" .nh disable hyphenation .\" .hy enable hyphenation .\" .ad l left justify .\" .ad b justify to both left and right margins .\" .nf disable filling .\" .fi enable filling .\" .br insert line break .\" .sp insert n+1 empty lines .\" for manpage-specific macros, see man(7) .SH NAME deepin-terminal \- an advanced terminal emulator for deepin. .SH SYNOPSIS .PP \fBdeepin-terminal\fR [\fB-v, \-\-version\fP] [\fB-w, \-\-work-directory \f\\fR\fP] [\fB\-e, \-\-execute \f\\fR\fP] [\fB-q, \-\-quake-mode\fP] [\fB\-m, \-\-window-mode \f\\fR\fP] [\fB\-\-keep-open\fP] [\fB-C, \-\-run-script \f\\fR\fP] [\fB\-h, \-\-help\fP] .SH DESCRIPTION Terminal is a terminal emulator with simple interface, rich and powerful functions such as multi-windows, workspace, remote management, Quake mode and etc. You can instantly start and close Terminal smoothly like normal file window, allowing you to input commands with facility and no distractions. .SH OPTIONS .IP "\fB\-v, \-\-version\fP" 10 Display version. .IP "\fB\-w, \-\-work-directory \f\\fR\fP" 10 Set the work directory of the terminal. .IP "\fB\-e, \-\-execute \f\\fR\fP" 10 Execute a command in the terminal. .IP "\fB-q, \-\-quake-mode\fP" 10 Run terminal in quake mode. .IP "\fB\-m, \-\-window-mode \f\\fR\fP" 10 Set the window mode on starting, window mode options are normal, maximum, fullscreen and splitscreen. .IP "\fB\-\-keep-open\fP" 10 Keep terminal open when command finishes. .IP "\fB-C, \-\-run-script \f\\fR\fP" 10 Run script string in the terminal. .IP "\fB\-h, \-\-help\fP" 10 Show help message. .SH SEE ALSO https://github.com/linuxdeepin/deepin-terminal .SH AUTHOR .PP .B deepin-terminal is written by Deepin Technology Co., Ltd. .PP This manual page was written by .MT wangliang@\:uniontech.com Wang Liang .ME for the Debian Project (but may be used by others) deepin-terminal-5.9.51+dfsg/debian/deepin-terminal.postinst000066400000000000000000000011301475472654300237270ustar00rootroot00000000000000#!/bin/sh # postinst script # see: dh_installdeb(1) #DEBHELPER# if [ $1 = "configure" ]; then #解决安装终端后/nonexistent目录下会残留install_flag配置文件的问题 if [ -f /nonexistent/.config/deepin/deepin-terminal/install_flag ] then rm -f /nonexistent/.config/deepin/deepin-terminal/install_flag fi #如果/nonexistent目录下不存在任何文件(也可能包含空目录),则删除/nonexistent整个文件夹 if [ -d /nonexistent ] then existFileCount=`find /nonexistent -type f | wc -l` if [ $existFileCount -eq 0 ] then rm -rf /nonexistent fi fi fi deepin-terminal-5.9.51+dfsg/debian/deepin-terminal.postrm000066400000000000000000000012441475472654300233760ustar00rootroot00000000000000#!/bin/sh # postinst script # see: dh_installdeb(1) #DEBHELPER# userName=$(who) if [ $1 = "purge" ]; then rm -rf /home/${userName%% *}/.config/deepin/deepin-terminal/* #解决安装终端后/nonexistent目录下会残留install_flag配置文件的问题 if [ -f /nonexistent/.config/deepin/deepin-terminal/install_flag ] then rm -f /nonexistent/.config/deepin/deepin-terminal/install_flag fi #如果/nonexistent目录下不存在任何文件(也可能包含空目录),则删除/nonexistent整个文件夹 if [ -d /nonexistent ] then existFileCount=`find /nonexistent -type f | wc -l` if [ $existFileCount -eq 0 ] then rm -rf /nonexistent fi fi fi deepin-terminal-5.9.51+dfsg/debian/manpages000066400000000000000000000000311475472654300205620ustar00rootroot00000000000000debian/deepin-terminal.1 deepin-terminal-5.9.51+dfsg/debian/rules000077500000000000000000000010671475472654300201360ustar00rootroot00000000000000#!/usr/bin/make -f export QT_SELECT=5 export DH_VERBOSE=1 include /usr/share/dpkg/default.mk DEB_BUILD_ARCH ?= $(shell dpkg-architecture -qDEB_BUILD_ARCH) %: dh $@ --parallel override_dh_shlibdeps: dh_shlibdeps --dpkg-shlibdeps-params=--ignore-missing-info -l/usr/lib override_dh_auto_configure: dh_auto_configure -- \ -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_SAFETYTEST_ARG="CMAKE_SAFETYTEST_ARG_OFF" \ -DCMAKE_INSTALL_PREFIX=/usr \ -DAPP_VERSION=$(DEB_VERSION_UPSTREAM) \ -DVERSION=$(DEB_VERSION_UPSTREAM) \ LIB_INSTALL_DIR=/usr/lib/$(DEB_HOST_MULTIARCH) deepin-terminal-5.9.51+dfsg/rpm/000077500000000000000000000000001475472654300164265ustar00rootroot00000000000000deepin-terminal-5.9.51+dfsg/rpm/deepin-terminal.spec000066400000000000000000000075251475472654300223700ustar00rootroot00000000000000%define specrelease 1%{?dist} %if 0%{?openeuler} %define specrelease 1 %endif %define libname libqtermwidget5 Name: deepin-terminal Version: 5.4.1.1 Release: %{specrelease} Summary: Default terminal emulation application for Deepin License: GPLv3+ URL: https://github.com/linuxdeepin/%{name} Source0: %{url}/archive/%{version}/%{name}-%{version}.tar.gz Provides: deepin-terminal-data Obsoletes: deepin-terminal-data BuildRequires: gcc-c++ BuildRequires: cmake3 BuildRequires: qt5-linguist BuildRequires: pkgconfig(dtkcore) BuildRequires: pkgconfig(dtkwidget) BuildRequires: pkgconfig(dtkgui) BuildRequires: pkgconfig(dframeworkdbus) BuildRequires: pkgconfig(gobject-2.0) BuildRequires: pkgconfig(atspi-2) BuildRequires: pkgconfig(libsecret-1) BuildRequires: pkgconfig(Qt5Widgets) BuildRequires: pkgconfig(Qt5Core) BuildRequires: pkgconfig(Qt5Gui) BuildRequires: pkgconfig(Qt5DBus) BuildRequires: pkgconfig(Qt5Network) BuildRequires: lxqt-build-tools >= 0.6.0~ BuildRequires: utf8proc-devel BuildRequires: gtest-devel BuildRequires: gmock-devel BuildRequires: qt5-qtx11extras-devel BuildRequires: xcb-util-wm-devel BuildRequires: qt5-qtbase-private-devel Requires: libqtermwidget5 Requires: libqtermwidget5-data Requires: expect Requires: zssh Requires: qt-at-spi Requires: at-spi2-core %description %{summary}. %package -n %{libname} Summary: Terminal emulator widget for Qt 5 %description -n %{libname} Terminal emulator widget for Qt 5 (shared libraries) QTermWidget is a Unicode-enabled, embeddable Qt widget that can be used as built-in console or terminal emulation widget. %package -n %{libname}-devel Summary: Terminal emulator widget for Qt 5 %description -n %{libname}-devel Terminal emulator widget for Qt 5 (shared libraries) QTermWidget is a Unicode-enabled, embeddable Qt widget that can be used as built-in console or terminal emulation widget. %package -n %{libname}-data Summary: Terminal emulator widget for Qt 5 %description -n %{libname}-data Terminal emulator widget for Qt 5 (shared libraries) QTermWidget is a Unicode-enabled, embeddable Qt widget that can be used as built-in console or terminal emulation widget. %prep %autosetup %build # help find (and prefer) qt5 utilities, e.g. qmake, lrelease export PATH=%{_qt5_bindir}:$PATH # cmake_minimum_required version is too high sed -i "s|^cmake_minimum_required.*|cmake_minimum_required(VERSION 3.0)|" $(find . -name "CMakeLists.txt") mkdir build && pushd build %cmake -DCMAKE_BUILD_TYPE=Release -DAPP_VERSION=%{version} -DVERSION=%{version} ../ %make_build popd %install %make_install -C build INSTALL_ROOT="%buildroot" %post -n %{libname} ldconfig %postun -n %{libname} ldconfig %files %doc README.md %license LICENSE %{_bindir}/%{name} %{_datadir}/%{name}/translations/*.qm %{_datadir}/icons/hicolor/scalable/apps/%{name}.svg %{_datadir}/applications/%{name}.desktop %{_datadir}/deepin-manual/manual-assets/application/deepin-terminal/terminal/ %files -n %{libname} %{_libdir}/libterminalwidget5.so.0.14.1 %files -n %{libname}-devel %{_includedir}/terminalwidget5/*.h %{_libdir}/cmake/terminalwidget5/*.cmake %{_libdir}/libterminalwidget5.so %{_libdir}/libterminalwidget5.so.0 %{_libdir}/pkgconfig/terminalwidget5.pc %files -n %{libname}-data %{_datadir}/terminalwidget5/color-schemes/*.schema %{_datadir}/terminalwidget5/color-schemes/*.colorscheme %{_datadir}/terminalwidget5/color-schemes/historic/*.schema %{_datadir}/terminalwidget5/kb-layouts/*.keytab %{_datadir}/terminalwidget5/kb-layouts/historic/*.keytab %{_datadir}/terminalwidget5/translations/*.qm %changelog * Mon Apr 19 2021 zhangdingwen - 5.4.1.1-1 - init spec for euler * Tue Oct 20 2020 guoqinglan - 5.2.36-1 - update to 5.2.36 * Tue Sep 29 2020 guoqinglan - 5.2.35-1 - update to 5.2.35 deepin-terminal-5.9.51+dfsg/src/000077500000000000000000000000001475472654300164175ustar00rootroot00000000000000deepin-terminal-5.9.51+dfsg/src/DtkSettingsToolsMacros.cmake000066400000000000000000000022071475472654300240530ustar00rootroot00000000000000# SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. # # SPDX-License-Identifier: GPL-3.0-or-later function(DTK_CREATE_I18N_FROM_JSON _generated_file_list _input_json_file _output_cpp_file_name) set (DTK_SETTINGS_TOOLS_EXECUTABLE ${DTKCORE_TOOL_DIR}/dtk-settings) set (generated_file_list) # 0(failed) or 1(successed) files in the list. get_filename_component(_input_json_abs_path ${_input_json_file} ABSOLUTE) get_filename_component(_input_json_abs_dir ${_input_json_abs_path} DIRECTORY) set (_output_cpp_abs_path ${_input_json_abs_dir}/${_output_cpp_file_name}) if (EXISTS ${DTK_SETTINGS_TOOLS_EXECUTABLE}) add_custom_command(OUTPUT ${_output_cpp_abs_path} COMMAND ${DTK_SETTINGS_TOOLS_EXECUTABLE} ARGS ${_input_json_abs_path} -o ${_output_cpp_abs_path} DEPENDS ${_input_json_abs_path} VERBATIM) list(APPEND generated_file_list ${_output_cpp_abs_path}) else () message ("dtk-settings-tools could not be found at ${DTK_SETTINGS_TOOLS_EXECUTABLE}") endif () set(${_generated_file_list} ${generated_file_list} PARENT_SCOPE) endfunction() deepin-terminal-5.9.51+dfsg/src/assets/000077500000000000000000000000001475472654300177215ustar00rootroot00000000000000deepin-terminal-5.9.51+dfsg/src/assets/config/000077500000000000000000000000001475472654300211665ustar00rootroot00000000000000deepin-terminal-5.9.51+dfsg/src/assets/config/dconfig/000077500000000000000000000000001475472654300225775ustar00rootroot00000000000000deepin-terminal-5.9.51+dfsg/src/assets/config/dconfig/org.deepin.terminal.json000066400000000000000000000007041475472654300273370ustar00rootroot00000000000000{ "magic": "dsg.config.meta", "version": "1.0", "contents": { "log_rules": { "value": "*terminal*.debug=false;*terminal*.info=false;*terminal*.warning=true", "serial": 0, "flags": [ "global" ], "name": "log rules", "name[zh_CN]": "日志规则", "description": "log rules", "description[zh_CN]": "日志规则", "permissions": "readwrite", "visibility": "public" } } }deepin-terminal-5.9.51+dfsg/src/assets/config/debugconfig/000077500000000000000000000000001475472654300234425ustar00rootroot00000000000000deepin-terminal-5.9.51+dfsg/src/assets/config/debugconfig/org.deepin.terminal.json000066400000000000000000000003001475472654300301720ustar00rootroot00000000000000{ "name": "deepin-terminal", "group": "", "submodules": [ { "name": "deepin-terminal", "exec": "deepin-terminal_debug.sh" } ], "reboot": 0, "version": "V1.0" } deepin-terminal-5.9.51+dfsg/src/assets/config/logconfig/000077500000000000000000000000001475472654300231355ustar00rootroot00000000000000deepin-terminal-5.9.51+dfsg/src/assets/config/logconfig/org.deepin.terminal.json000066400000000000000000000032471475472654300277020ustar00rootroot00000000000000{ "name": "deepin-terminal", "group": "", "submodules": [ { "name": "main", "filter": "org.deepin.terminal", "exec": "/usr/bin/deepin-terminal", "logType": "journal", "logPath": "~/.cache/deepin/deepin-terminal/deepin-terminal.log" }, { "name": "common", "filter": "org.deepin.terminal.common", "exec": "/usr/bin/deepin-terminal", "logType": "journal", "logPath": "~/.cache/deepin/deepin-terminal/deepin-terminal.log" }, { "name": "customcom", "filter": "org.deepin.terminal.customcommand", "exec": "/usr/bin/deepin-terminal", "logType": "journal", "logPath": "~/.cache/deepin/deepin-terminal/deepin-terminal.log" }, { "name": "remotemanage", "filter": "org.deepin.terminal.remotemanage", "exec": "/usr/bin/deepin-terminal", "logType": "journal", "logPath": "~/.cache/deepin/deepin-terminal/deepin-terminal.log" }, { "name": "tsettings", "filter": "org.deepin.terminal.tsettings", "exec": "/usr/bin/deepin-terminal", "logType": "journal", "logPath": "~/.cache/deepin/deepin-terminal/deepin-terminal.log" }, { "name": "views", "filter": "org.deepin.terminal.views", "exec": "/usr/bin/deepin-terminal", "logType": "journal", "logPath": "~/.cache/deepin/deepin-terminal/deepin-terminal.log" }, { "name": "encodeplugin", "filter": "org.deepin.terminal.encodeplugin", "exec": "/usr/bin/deepin-terminal", "logType": "journal", "logPath": "~/.cache/deepin/deepin-terminal/deepin-terminal.log" } ], "visible": 1, "version": "V1.0" } deepin-terminal-5.9.51+dfsg/src/assets/deepin-terminal/000077500000000000000000000000001475472654300227765ustar00rootroot00000000000000deepin-terminal-5.9.51+dfsg/src/assets/deepin-terminal/terminal/000077500000000000000000000000001475472654300246115ustar00rootroot00000000000000deepin-terminal-5.9.51+dfsg/src/assets/deepin-terminal/terminal/common/000077500000000000000000000000001475472654300261015ustar00rootroot00000000000000deepin-terminal-5.9.51+dfsg/src/assets/deepin-terminal/terminal/common/+.svg000077500000000000000000000020701475472654300267560ustar00rootroot00000000000000 + Created with Sketch. deepin-terminal-5.9.51+dfsg/src/assets/deepin-terminal/terminal/common/Ctrl.svg000077500000000000000000000040711475472654300275330ustar00rootroot00000000000000 Ctrl Created with Sketch. deepin-terminal-5.9.51+dfsg/src/assets/deepin-terminal/terminal/common/QM.svg000077500000000000000000000040111475472654300271360ustar00rootroot00000000000000 QM Created with Sketch. deepin-terminal-5.9.51+dfsg/src/assets/deepin-terminal/terminal/common/Shift.svg000077500000000000000000000067711475472654300277150ustar00rootroot00000000000000 Shift Created with Sketch. deepin-terminal-5.9.51+dfsg/src/assets/deepin-terminal/terminal/common/attention.svg000077500000000000000000000020421475472654300306300ustar00rootroot00000000000000 attention deepin-terminal-5.9.51+dfsg/src/assets/deepin-terminal/terminal/common/close_icon.svg000077500000000000000000000023671475472654300307520ustar00rootroot00000000000000 Rectangle 9 Created with Sketch. deepin-terminal-5.9.51+dfsg/src/assets/deepin-terminal/terminal/common/deepin-terminal.svg000077500000000000000000000036741475472654300317140ustar00rootroot00000000000000 deepin-terminal-5.9.51+dfsg/src/assets/deepin-terminal/terminal/common/deepin_launcher.svg000077500000000000000000000076341475472654300317640ustar00rootroot00000000000000 deepin-terminal-5.9.51+dfsg/src/assets/deepin-terminal/terminal/common/deepin_terminal.svg000077500000000000000000000035041475472654300317660ustar00rootroot00000000000000 deepin-terminal-5.9.51+dfsg/src/assets/deepin-terminal/terminal/common/down.svg000077500000000000000000000051171475472654300276000ustar00rootroot00000000000000 image/svg+xml next Created with Sketch. deepin-terminal-5.9.51+dfsg/src/assets/deepin-terminal/terminal/common/edit.svg000077500000000000000000000011061475472654300275500ustar00rootroot00000000000000 deepin-terminal-5.9.51+dfsg/src/assets/deepin-terminal/terminal/common/edit_icon.svg000077500000000000000000000004541475472654300305650ustar00rootroot00000000000000 deepin-terminal-5.9.51+dfsg/src/assets/deepin-terminal/terminal/common/icon_menu.svg000077500000000000000000000047771475472654300306200ustar00rootroot00000000000000 image/svg+xml img_upload img_upload Created with Sketch. deepin-terminal-5.9.51+dfsg/src/assets/deepin-terminal/terminal/common/notes.svg000077500000000000000000000031531475472654300277570ustar00rootroot00000000000000 notes deepin-terminal-5.9.51+dfsg/src/assets/deepin-terminal/terminal/common/plus_icon.svg000077500000000000000000000012551475472654300306230ustar00rootroot00000000000000 deepin-terminal-5.9.51+dfsg/src/assets/deepin-terminal/terminal/common/tips.svg000077500000000000000000000030731475472654300276070ustar00rootroot00000000000000 tips deepin-terminal-5.9.51+dfsg/src/assets/deepin-terminal/terminal/common/up.svg000077500000000000000000000050421475472654300272520ustar00rootroot00000000000000 image/svg+xml previous Created with Sketch. deepin-terminal-5.9.51+dfsg/src/assets/deepin-terminal/terminal/en_US/000077500000000000000000000000001475472654300256225ustar00rootroot00000000000000deepin-terminal-5.9.51+dfsg/src/assets/deepin-terminal/terminal/en_US/fig/000077500000000000000000000000001475472654300263675ustar00rootroot00000000000000deepin-terminal-5.9.51+dfsg/src/assets/deepin-terminal/terminal/en_US/fig/addsshall.png000066400000000000000000001460501475472654300310420ustar00rootroot00000000000000PNG  IHDR?|z pHYs   MiCCPPhotoshop ICC profilexڝSwX>eVBl"#Ya@Ņ VHUĂ H(gAZU\8ܧ}zy&j9R<:OHɽH gyx~t?op.$P&W " R.TSd ly|B" I>ةآ(G$@`UR,@".Y2GvX@`B, 8C L0ҿ_pH˕͗K3w!lBa)f "#HL 8?flŢko">!N_puk[Vh]3 Z zy8@P< %b0>3o~@zq@qanvRB1n#Dž)4\,XP"MyRD!ɕ2 w ONl~Xv@~- g42y@+͗\LD*A aD@ $<B AT:18 \p` Aa!:b""aH4 Q"rBj]H#-r9\@ 2G1Qu@Ơst4]k=Kut}c1fa\E`X&cX5V5cX7va$^lGXLXC%#W 1'"O%zxb:XF&!!%^'_H$ɒN !%2I IkHH-S>iL&m O:ňL $RJ5e?2BQͩ:ZImvP/S4u%͛Cˤ-Кigih/t ݃EЗkw Hb(k{/LӗT02goUX**|:V~TUsU?y TU^V}FUP թU6RwRPQ__c FHTc!2eXBrV,kMb[Lvv/{LSCsfffqƱ9ٜJ! {--?-jf~7zھbrup@,:m:u 6Qu>cy Gm7046l18c̐ckihhI'&g5x>fob4ekVyVV׬I\,mWlPW :˶vm))Sn1 9a%m;t;|rtuvlp4éĩWggs5KvSmnz˕ҵܭm=}M.]=AXq㝧/^v^Y^O&0m[{`:>=e>>z"=#~~~;yN`k5/ >B Yroc3g,Z0&L~oL̶Gli})*2.QStqt,֬Yg񏩌;jrvgjlRlc웸xEt$ =sl3Ttcܢ˞w|/%ҟ3 cHRMz%u0`:o_FUIDATxw\ugl/MPBoҥ WEkCEX ATAz/!^v)lJIB#l633s}s>_)Ax{&N^%aÆbAޛT14UA ؂ MY o3C $ׅ   4`A(—}eYlkAAlA]Ke$PEQĠ<ϣP(YŠ "` ®#`DD"9 x\A-mX;.lGAx3؂+Bۦ\.m QUmՒK;XҾ5~"P "` 3'rHDow/<oWlI| CQ0Rx"հK@ ,Q""ai:A4ge3Q]S'A;_γH:?B>OqHU3<4@XF!RHKT P(8důILGP ̰   |!Ǭ9q#}tr$3iL, \%yǟɄjK vHa"fOhF rr)'RcJQc&q3S.c%*ٔ|i駜HUJ+6    ujjfBa@bۖMTṯ >mɃ<>= rL9t@da2(9f-?3$UperCTW6QW5F+ŖADa IȒBs |p]Xjx rn= * W45ADa_DY%[8p]ux߉2nV,A xE-tEP*rf{u2tn\7Ve9.g.|ddYQB $UU$U( ʼnu/JA}""aGȘsYf͝dzO=L\N +*Pfz67(I =m?C~l510zlƢ@1Bat3el1?:7-cu$먒aH lAa_#bQ AxۦLmV Gs+O>O 8T5eL3R5+W2+͌Y3_\93)nWFd2g [ݬ&RH b&~\I٫[ɲؙk&;DAlAރ{G<*$a!J"d%z _zlfU Y 2h CSpBh,(he;0kѐm;gQݑ"` "` o:t۶Mf[AxD ? M}sr &." 뺸ږvNBEc6/:v "` . ؞ey k|>A=N. Z\UUI&("{ P(PE   *;t*\.E9CXT*m- -+d˲LXX,":7TUFAa.1) "` ^e3#!>"1VlAaohbAGD^"` .艼Qo/ )A}h% N*HDۏ,q$IYA[vgD"DQq{`[y؂ ؂;xG8&HAُIs[yq@% -RȲL8xSA>٢ a)JA   ʰip*m(heY"` "` »< RYmr,VDADwY躎a73 (J"d ؂ REQ$MȲLPX,b&SAielCQ CW%I&  *1dI2J`3<4@Y SUU]q PT MUNAlAO蛜H$hmm4My9JR)z{{$ ]_s$EJO$\,  43oAv%wI":B壩+2k呓/%nrÔ("9\2YWa*#AŖLQ%|&z*}$8bD Se!o+؂u\fĉL<6՝n",Y˲0 9%µ㙘Yx-3fS)gYLg=M& EϦ8dm?+FDZʔ{T<o_:v~L|2!)Ixﱃ"ZYx>xGP-,{Z?LPpl/PTMӐ*`2 2"Bc[%\_(ضH(Z؎/z.U̜}{d$ g V,}p$* m2Ǐ N^wweyg/ p]vhYinnFUU{9<{e]vS$&9D"+Wt01frd i_B!6  sG8LIa6f@XDTSYzEeb=NX*۹~9') m9S.6_Wsb( :L6OF'jP Z"$ʮjj# %0 d/k8A1a&BƘ}'%2`%orw~U˹u{8K_Z@ay\v_T[? '>M~¹\ͯpd7/\[ W?2Go~> /]7. d58qWPUrO]>#?2klλb~ lܰ]""6 &mSSSca0hoogڵ,X;{o+V(Z۶MmmkCSFʼ) a܃ZS/1\_l A<@XŃa9P*]NMbSP|;OΊs'.&]biOx2;Gg>xr1'`z樃ңt_\Lw>_a[H;Cinn/&شirԧ,Gya+D+/楶De*Kqj s!z3aS%Zc5ӗ^D5Z4~&FyIsO`Vm^̘ҊT,ywG"'d`/ ٺnͤy9sI lkqɼނ8e"wuD[o/!t]3/K.~ &PWWG\~M]if%<,dE!#%dz2Ǵ/"HwC)sDSL?d z$cX^ ?HH 4 -@384+ޝfBz+7ygW?5-Q}bf?]h'#LQHwze;"Y܃=p>dZ q$n!OcNB B~oqaGr>=wLuM؂P(DGGRt:9 /eY Yx1Gu՜zD" *++Q.\_:}e8/-x*1(bCe68'P9;ȋ-̘qɛ7 Iv&p)sۤ%O`Rk~s+z%y' +yxvK|X_ 5yop]GSIg*`NXG3Bhj] 3e/aE7Ff`,FL-9sJۆ5 uO9;U3WlA Ȳ \{+ ,Nࢋ.blܸX,G ' 3ge ä0ma*t@3ق85Ip.z&wOq7G}ⵣ^O,\'Gg:PC=7mZL @Vum|̄b\#JߊΣ.?@F}嫔P8DX.{#uጳ[mm?*.8X0iz +#-oooA`X5юP]]M]]Rp8̚5k?L]]W^y%BY4̟?n+W\瞝6jeYlݺUɻit987Xl#ڥR ^]o}ŷꫯ&`xMr$j =i55聋R x 9*aw]ӫg]&6gK_X$`C7Ћk wjJ(~ޮm_`Ӓ~meb'K-&NR]'c]oD2= *hEP$P=}'?ǬR^[P][jl,\с Ylcb$ UXz=TVT+B_ Ƕq]5ݿ^GK_O_bE#AxL}?iP(0ydf̘A*"rJ']𩨭#, \Ec`尕(ՕIpdiG(CvK=j4$dɧϐ+|p4N$B* J($3FC*kj~ #58ŨBFrm ͌QQ ( ?#\QKE{ <U^w]*AUK4w`6R.ѣGŋ8^{-RUUz3VjyFRJQj{‰Z$ۻ +k?(!$H#|43JezUCZAD=Gu(D"22w\fΜI.#앝H$0Mq(;:*(P@" ]>!Q!ۻ> j®E&Or2u5?G{:ۑGM$>{;dAA[$Y)ˬ\C=x===G4Bp'힕AD A@>GuE5ԯp }EQĠ "` ®( e1<OTZA[vwȶm0>+l3ׂ ؂'zs3qxR!A9$Kb؂ @J$Cv<0"u8 rג|+E5PTmEA\P2U5u(RTYC#![qVGOFA1:bblA=FrT1k ꣙7Э pr0y8KWh 3 ()[vQ>}9p>qC\qWzA%Ҍ>u]4M&wsprLjQEZDE}!XK("xGs}[ƫDg߇ٷr,a|m˲L(\.i׌!772H:x@ƅ}~H`'EgHV[pm&$$II\![ȸ*BQRUulBTU}KKq]]+ o"۰+Ƒt-)4 ";Voq@cp7ڔ y "Zbl|$uQEy+ym8y5wΚa5VTGݷ_3؂ –,(wΎEo˲yb5Zµ XD7}6 bTH "f< f s4Dt ``m(ظih>2m[($I x(븮9{ȒVstMDZ)J50u"K/-8twzk|8;w9ae\cw1O:}->J K:ѰUQv<4"["W1B!0Hp( B*Qx"8toi4Xޞ. HPU]GEeUX,[PD"w2\qR$1{'lDC⏱Lja(˧~yT))^cIO=8* $z?ƽ- ·>y<s xRv60MzVt0sN:ik0/<<Ŵ#NctYЍ<$-qd$ϳdͬÏ{n[34N;3O?P.*/ {md[#gˠX(ݽr@NuMu 0j4,4e&lX<ɤѼ8iF.֍y,4iYi? ==47(smφu #0n*ju-»AL nAL&yA#Ihj4M{ &fdQg4E193ȆU+Os9O1)鐘v:g1ՏŒnC?rsܡCu8g7j8 L|G9r=LOCdM91,,Nq9gQg^ϤИt9p=cG<)GZ9). 7>#>t) _v{ya2i f=*18Gq{D1kꩩq,V,]ȖJEdylu$Y=l$=EX,bK i2R9TVR][GUM\]۶,U4wtQN;~ 8VbjϘgY7SQ(E@44q|쾅7N: >cXy3MfMRKTLڽ<[x酨[LŚDsSͣu|3NF@XQ4=CWk "[,|쟼h1 &*2)<MhFaRobML^" _|mMҜdfRGr< U$bn+yǧMm(rhAX$ݹFCTD4<ϡ\,"#Ho흳UAP(d P88mXCjp U r ױJ؂^&IPhg@O}ywJkKE HO`ڗџkfH nl!pAfwC}A9d dYguħ?^|>64*ؚMrPr K`cن!I4b );R~r#{IEfXB8E_/DظɄLR&K38#yo,~_ttUu=@Ʉ4SS<_ CEO\%LU"\EQp=Ä'ˠH27`!JMc0xh<:B' \Kq EQG³kcYe:c"xesfkE/^^Mc=044;87,qݯHtÎ?Z&ȁG!LFү|ָOf޴&P~ %_>LtlΚz4ʴ)0(ƪID @"nx=bfTXi5/Q'r!1z &6#."iA(VI2w}d=J2GFf)zfΞ <"*b! ūHLcYeB04FiZdECb9twm#b會c[Fwt`C0!2!YxHYQ|uTVpG1q4 ӤmpG 3؂n2|4袋x'Xr%eQ[[̙3ٴiB7pg"2:ez7k+Ԁmc8lV~bO,֎E䀖rۊ7Mmdn+zнqtJ[=iZ#w6-$CxެrqqVd3 G1`%:=MHıְdiUOQj}g\@ҒO@WXLc=Q׽K!L/3Nc'ѵt젼liU\*q* 3Ħ#mXvpmEԾP(L4C7aI\=TMc;iCfYj)Pu<?Yf9pry;[d [ {㋀-\.Gkk+W]u6l#͒L&+8Yd O>$O?4xMxTL?S< `-ys>[w7xg7ub͈ ,YsG]ȨQ0 UV188Hee%s /dѢE8V >8E"E$IF?Yf|( $µ jbR_өͮڂG7Gf=ϣp8a7.%R$#Ew2lafƴ_XvC-{P(㗿%_= XE8O';dʔ)\zՍ>Ciiix<G~j;>de$6 'ȊBT`lMm^lflmx#nM$,Kطy`&6#՞;QzcIav'؂O}}=7|3r HD6 ӦMcƌ} g466ʖ-[@ rLO;S_S,j [ 7̳^IXZ Ndm Z*즳'N Q'VzÆ 0=$y<imy{Zf_60c bHA1EV(!+iI_NH=$] Q ]w3gg%vZ**++I$m ® Kh! |$_ c–p${#Q-{=.b .28~_`YE2fH$h8oǶIQ5E <˲Q0Uq=DWe(eN !tU.UijZE|I0 |¶,Ut3]fW pm q0% Ca$.[zMEK0Ax1y-U 9xv.28W\q.iN/SYYIEExMkI)S.q]w 05'8vcZm!4OF,$Q*9D3yT' OvL&9Dh# hc=nVƬ9 c9P3nf!3>TNcc5nhd#himAlhgqh繸n@Is<.inmEqKZHDU\W >1-{P裏2fǡjdYu]ZƏ=C2dܸr]iAfUUQ aXºjxG԰6aVy\[;o0i~W'[ WH:kJChDc8Gsjm$gPrilHib,_ƈR: yphN)Gf4E^wf Mɥ3T5N/ ':Q4minEWpE ؂"I555/T*1i$ 2j(nV|gTTTyY%||H٫i z*ɔY7c3#JT 9iW.g'KEeE9(۾ }T>*F¦c$18ЃS9V@F4|?6:26zb 26'DGjj~XU-P9j rLU FVmmXQ3dY~j W(e]dE ޸$!H狝{?$I3׶mԄi;V>|d0t<$uȕ!eNTdKvUSl3` CKF6"o |I $460nDmVTU7S]w$2>0j[;ARirQ9֭]HXRSg cz4%V[K8L"@}mp]UU㨪*Rgmőwà^u&I?IP.rAj40yDu kl@0PYVlUM7sN)];ay$>#IPhwhu-n@Ssa4àXT12h~tBעNivT6`yI8yx霅&1mTTMGťFDl%^ ^:xLBu]It!::5a0[lCftƎNйf)*SmEmL fRlKHbNBDpMnd mf ' G~6=~tft?j: qϣki9pq}4LCav"S[ 훰 *Ů_L !{c' $AYVEQ(J ykwȒD9Hx^,KTԍ"K3d39d)P4TE<<YEAVT$Yi(;#4)ppw}72+ !K;/U $EAV|wE)?}$YwmddYFRdI"=\CՍ *{t[$J$vڤxu---Èw(=4U"MHRtww >uuuTWW۳IlmN ® 鎎d^"EbR g|⥤Y(uާq rQuXl'Meopgg>ͺ>/19ȇOG\9as .1=cg:4.[Gc'r9\?5եfQK~އٕa[N3![^%_h>b\gFg^UԮ o0SfqH$Af) Gn$hW:!ж~{Z# Yq|sUe@$UW^u; Uhh7?Y7_g4]DDLb񪽀yDQLӤ\.ﳥ"RUUEuu[0T׳u7Evy+TFy_#ٚ!J^4.ĖǞrH{Y52cD4:49и8[W?G[KUĒ%sAL>pjAu|AHa.xWGd~s-6w&1K_/?ks/DY|u? rӝ+ȴV1kth3DŽ/T$DY$"rmwȲcf^ą]}1`뺾4DxwiOvDb~P(D<'J?("6߿t8wF,ɺze4qxᮿpJO0>޲'^ڗ,aG-aC?o{x\U%/\F!@`}%k14OII2)Fʥ ֱh]'z11KWfZ.jSmtd|𢳰-zx߅3MOlj3":b7cfbqZW\8ӒAxz# eo P({^dUUOqhPo0o|R_ߔ >L<?GYdr,Jxiyy?nc8iͳpE7P4@yhn͛i}!kfpT<8|c1iy,_8#_}/w=1g\H'ץ G4Akd9孂a$8_ {D\rEGޱ$+Nc^ެ;krb@Ts]Zp8o9(B(/J \CtwwG`$G1wl ro~AW~o=pS#<mإpֶͨ! wa.vtR.u]؎@`Y~qtJ9 v@$C{yx!``]-Fpā tYF_)@ߛƎ@8\{2hU,+IE# E=$Pwp5eA(Ȋۦq'z2<}O<'wƹSX#,^G8jbmE7 &2.>g) '辍hF2SkmXB}<5ae\ m?[,{PU]9)bT0Bs6MS) ;Xj9) 2= 5ͣ :w^LYASmmd*cF9lQU@T.П%k+ע;YlENf]g/ݛ"8cBnR[ځIXI </OwT$#'EW2eJH<|ɲ,lyiZtyvM +Oq!anU3$B0%c6?t#3:el&ͺ5)~KEZM=kٺb1Rh,Ϊ4sٰnMcohbՊEj@?,3i  YQEۆF)Sgx,܋/sHFVuJOs@̚>pg. T*z߱hrוHI2zHwl[<̖/6'ĽFq_⣇M& x dJ ǓG`LqHZ0yDBQvTFb|43J}|0q˾(F WN  Bؤ3*/%~"Op ^Y\򙋰W?Bi S5bh򩏝@3R7XƍJsP/2oγ'YpևN&ܷ}힥u'a}l ,9|34xṵD!?wd=i: \H1ndTUa5̚{0MǒNa,$Ɋjf͝7Ur;V|c!-|۶8xQb˦10r/=DŽI4 [5j9SЭI̮-CygQ| XǨC_q#;c%',sk)>|Apt_ IcaY&ʸê6.X%$6u$`ӈAAa9#7yaIJPf3)؃*\u-6Q8{ch~w϶ N< LPxILW.T&5>t#O,o dB*u#gi}xQUFΘ`/HYQi7R@?H\6 DX I(K;oAJ gDcȊJ 1jRApAdY%=*R ,p-P-s&8wV^ 3Ҷ|y {ֱhRJjX4iWQWٲyoA֌0V!駿exS꒷vE4;yZh6xy  ϱ*1{t&|6f1i$fLE&=4˘4a=DDuBWJM7s[',Q["c\{YӶg7S?Q>,|>Yg}Y7^ںF|CbDdǢY#_+8EwZMCdڌɖMI&8hhh {d5^Y!2*jH&n7/:q/EeݚI!eeTU8R ǶYvUյK%tC4 tHMq\M7ұDZ$tzhgέs9 JAgYf9*a\w@"S1tȥ4틨D",Jwr>7$sϿ01C6ӯ2{kY+P]C>WQttLM70 8DWF16}~F{WDiWSvUE) B)8D*WF<6!j몰d>i #o/D$#*\㡛Qb0VTˆĈFc`?bb(cx6}H?/YU5dY~`g9:HkHj*&t728?R."I:Ȳ}5TUwJ;y(}]DZ\EQAUx{mFFJ8*$\Ȑ/٨FX,M.WD 0T H)bI.-M$!>B#K#AEW|"HH E'n;IA=udEEfCZV5|×4!|$MQ0@dtM {ŘG*~9P9@Y-*e3BrrHHzCE(/Mʽ6z0뗇 P (*bw3N|y@V^Qi:+[U*TmȸH$m>>*X|MFBqv\S-,\`ׯ~-H|<hsN* O$Y~UwrQ^g8IV^w5#I#+ ʑV{̎Y Vm_QČ7-6%I²,2htg \ X,V"ǽ(x ø(Ȣ KBeYi5RaP۶qg)e޹JUU{,EK&|\x,7Թk+(SSWK"$,ŨIj v-{ cq1yw=&5aehajjkʎ[iq&~JNMCQCTBha QIP]rTLɗ<5nt3VE}M+;L8 AMm;;H:Ʒ +{ k+i2E-+ĪND+3`Dg*QPHQ5R l}z{{inn0 <){8*B:fhhh=AeRrx:f}&c?5^Oߊ"̲WRt7 ٧sD]-7źLt(UUq0Gno䶿IG"! t*GS" nobUs?yc35[5V2 㧰;hukTMdo~|#[V];@qgi按?/Q9q.6$>ji }?f^~̻'wQ;>S?(iHG~||2_0J>+ؔo]I gg|\*i:?=|\+ag*MD(7}Os֘Ӹ:.gg;)V,Oqǿ TywO+‡>MC_ 'q2=}XwSSC <AT˲4"+ql9=_EYj[YzbFyAKlbUxHM[ڛ%|/ 6./(LYɃ7grCa>xWOSy~Q!_>u0c+Ȋ7Ĺ W  /8.H|am+ toXu|b&p_Pmɓ?^Ok~UmO3%‹7ӝOs2kdʄf\?'3˘1&?g8.?E,|5BUT9*Ge% rY,?ɲO\!uJJ)3:LzqDS,*2+<G1“?l/^ >a@#q՛ I`l m:H.H%mh3"$u#m0Сc3~KqsTV8t'p yʾ)j">[׭#T5 C z|k?in(z*!L϶-de"D> W{n`>RKrOjшAqׂvV ߶V9\+9uJ%f։0yd*Fq䱇Qa4mkا 8JrR1c1fN&ssB6h -8dU/gECv g?|n8zլHzlECa/C@/ﯙ/smy$g}JȽ\72IHL_  u׫8qb  |b܄V:C R,ttjPPODuزa#YOC=ic.oLjW=CQ5)v\dEEU$\!@BdBKI0qhT;KOoCMi5غ~-CJ"Au|4Mw<TMŗT)q\PT4YuIASU|+O0j$j 7f2H2`V73)FdC0uU)m+H{| {xÆ m/SLI 1«d֮]ֵ b+ la;Z;::*xs Y0tsm`RcGBt4m$8[E kض 28M 蚂ظh@ ܑ烬`2>ek*x.: "kz< %pq| ]sMӑqQtwl@RPd YQ]אvUUmUAQUϱp\IVuM,#؂"` AȲ, 8/0}݀G.a Y0)b} F(!fheE i;PV5_Kx/{>j; &TVueh #׌<ۏsҿ M7^}k@^9 vyiTUUDPUUla>,K׻*\A{0 Bx'JD,DQ( 9"` {$Im[ .,S[[K\&~{ZOlAAyG,#ຮ=}dY&LR(FʉwCѧ-  iر4bo{8v!?/ )q1^h61-@ὑBp\g::`ۮ 8o'Abiwa'!A$#6ews"3)r%Y{o:d% 5 罣 p=cZ| y&L$/63]Dd iw 7񖤑UuA#<ׂp#G͛H*}*ۆ,""!|RI(!S.\Y7Q<ױdp$&VR/#Q U\.m!aBDX "cQ(%p$ PC ]n.XgS.@od5ض$I:#5繨FHm EQ}3I&5<{8((;ڞ:y>$#2X\ jb*D@B1.E$d_YeY ﱀ ͜xƹ,+;xJO<11!Ll&[;HZ6.e0gP[_U=0dYމeD׶2e,Ja+W"B2w,#%ol>21lLjh%|ġqƬIydAs$JDY9{f 圓xQٲqS=k0c|3;sg8k^3A~&1 rϔn&ϛÌJ'2y\w8(>H{.ĘkQ癛~ 22PZ93"X{m1$i:r-u+0m\F5!NQUK GL>- #x}Hh,Ax$K%TUcԨ1[pQ(ضuS!EDZc&F>=T) v3|I|<~u;Z~L%uOW樃jT{W1)GXmTci y E K ug e}V?G& eK\H7r'ZEcT9Lx(gA\~j }ڭ]{@a>1zꤍM>s _=Fq㴗泡BwW}1iM8ҫ8?)oU1d%L RQ(;=ql@uG$zٺdE%hYQu$ C7v E8A呉8AK%kl*CG%6Or*i[= _;3Q\6ť)kƳXxJ.;ĥ4cq pc{`SsQ|uSTO囇ޜgM#S@؂ g4 "aKmp1<~U<7oaœD[X} HDlVi3E*wvf@d(W <3/c?jR8^7mbX$ +&kI44Ԣ.u3O >C/֝EeYƶl6o IjH,mZV.[掍Ȳ2Ь(Vh A`YedI^( IƵ,yi><Ȼ N]*8s|DZ95Qjc:QiVIK}>œTMDr]I:2޽^~2g͍ز/Uҿ,'#qN(i:k*VfqqHU'}4?Z|dMTTUAU5TUCUT\2\?]Sf!YSG,cʌaRHi˻y(i%֭YAy,:3fÖq ʶ(*"5 EBSdܐ_y?6`o/Qȕ}P .#] JM2@/g=d<\ b*a Nb*TPYtU550W̭U͸kgڙz9Z&W}䞙y)n.ʮ)fhLȪN4g:l/48H)N#Ży|g?\"u>޽? [( eյIpMtޭ(BUU 3 $Im r9 k gε(q/N ZJo[wRJKH).R\$!Btvᒍx#ٻ;g>g>ˢmTklۡs=bYZ-cZ8rFOb!atom|'  ،]:7m ս# k8;|mEkqD#; rL59,o'hu9zJMx^ n3?4l&U0 ƴMZ&6 MԬ!j Ʒpxn-&eW]/g 3 -aRW2+f)|K1=Ɠs`Rt܂CПIl6m,O3m~z-ZUTܦ`F B' V̫_$);eHXuk ̜w3s-bEX3z1)z12W Md/j,ϬU6<]})OV6_mZZu;p8BoO=؆:ױn*R8NP8@/46`򐎕K7vBtmXaOzA8!hYj9a&P;bUYӬmǑ-FxVܚa׀ǥdI&V{54+ 9,1XU)>,T2XwclKrsX\\o_ {d4(*<ʣl}_ȨoK/MT};жU=R/ z[m77Ng`Slجo~#lk@;|33HXϗ-!CuHsmڨcƿwߦCݶ Khf3gfxŋ^'vu]immumE$VnZ8FaϪUp]]xQf>*!r7_᱁a(PSO /,5C+F͏[~g"֋c7= 91e 'bH"ȗb^)K7I&cT T(FxXiN;xPp Sel\\&LH$d>jJ&R E>t8?8KB ph;؁[ :T>|\ 3ʧ>>YrexyLn4gp277Pg|~9 F/]| c=sç5Nrz*u\?X!7p Gӗp cjFZkNkM" JI.:d+]dM9Sk NƊh.'U#4 +Bq3e旟$ˮO5>I~1 \.cͤ39<ϧG8t^;/<~6߸ko.}],9{_0M+n|/ۺa"X!@rLJSSZMDlwm3vXV^MTT.]RC!&(C%  'tkEO`V#T0ʌuo|DKi>.~:{?ab866ossAi?_x 3eo6</6;ԕ=ߞ02n}SP1ӆ WnrHiô^jӦMo~ʯ280@RD)ҩ8V`` KV&"T顢45 }檤 EpS{LQo"͌nY|1}%z39Lh  $c!\ti[=K}${Rk>dx' oS_uTRP;hR.>m ,/u]immu]<꟢^J4i=zBS%W.jGkj5 pK'PO_N}O#<#m44mn(+BSkdgc6fs$ЗнQZ[M( M:_ȯcg~IkSVZzQu~vYjRo8yٓνSñ|Lڦ̔q˞{u𦹟RF/OV& ݿzh e (A"P1 8$k R/̏_P hpg 4!K&rXTn,G#_H̦w3[_nHa" Bc*p˔43 N8nxH"%2|+Ud2WUՀX2|W SԪ.64 bHQe0[DZp)8bN@.CSv@qU[\ 2R-{ms/jT{d?9);ÝKJLyr?MK|^6t "kwxp[Kʞ ijN6c BcJ8Nakj;`Y9icZ:p͟Bog2=Av\{L8lv,A'?<͓`]dNm6_,׹a^~,Ol]=Ovx8jQMϹ;VD8c43J|f?MOHFe/#:z HW}A{e'{n;MQ/ޏ}Lj͇+6v{{:PVQ[HǔI6-e[V3V{8d},:O*1y"ؗ6:CL'Z8S2=kdGa7ytr,~6ni݌YÏᴶ8w=]s9DhXbNr}{<VU8kc48sVVx`yqL8nzz!blnw{H$"/rLǔ^O:RY=~Cw>hnl~u|ߥ}ݳ0W=${rE4#7JwHj4Q!wqMAs)jē)lx2ch-ZK`r]~{N;??ܫMd,{-~s7DD.r5(M ShM`I@`Q)"mcؓ3cfB*=Cc9=wSKcO>+gs<[ejϯ{'{?<_d/Sϡ1`6ԲS9}_BM\oٟܧ)ٓW?ÆH /8ġL*qܯVsI.:8c8}KA./ԧꋚ/Ppc\U!1 ԍtvo_P"bts5bMf|].y9&}K 5?` Y>hӠWsqI'11̂ͤpOW DswYLȃWj±0sq[gq] }l~bu"&X~Kt_q.4#v7K.mfl̙dbŋ7H3~b#1 @ c0C9lpL~\ "FLb3#Ր&jk2}=-\%McS3! JL&C-H$*~JE2@2"8vd"?o$6 s,4#v/L+w&A-k4v8F?yW !ۓ&n :0Cq/: 6ljZmmE=Ŋi>vƖaGSefQ/<ϓll?t,(x 7WTj5`+5vl* 53FS:}٣v9Ioz̈́B쾔R[h)3} -/JW4azB1R9ډ ƀ܀X(&7'2Va( <%7|*h ]ԃ͉Z' /w:2|ʹ23?Ou0=hXv-^OCa]t bL/Pjxѩ'w R˸u48/}LkrUrͽ 9 8hrPUenRnxh/|}F̹2{A,eNjjT /dYɤd !nJ)Eoo/aN7.L␃G̦T񌟼79uɼ( ?y+kV&5BQGE\駟&˛BRa ږ[>K'KN@&j1!#`Ԩ&6,~LcVhlV$EsSFʉJf<{9J66Yī) ̞=/}Kfܹ$Ii!B7``+3ԅ"D"9Qj+j`r3X0I<~s~n 򉿦8R#xK|&/<#GRR%B잴քB!7=A@V#HWWצ*YN T Vξ 9Teȓx۰M; ɫ/B|ߧqdJVCyG<q(|ixb}7hDu1ebvl_R!25ea^b_4Mu :}0nPޖU (QM#?ko. !B0L|'P/<3rb)K4/B:@M}35۴֠ ,СɘE1OX G0 X"4VߦBήB Y> R "b:9j)O5phlnQ>r/xөy 9dO'2㘳9=Zby?H㘯I=|?@&5HE|Ⱦ_76́=|]z/5`l/U#J[cߗ 0BF j~d"C]F_ "n"bT@Vѡqx1M3C8Ƣ.LjֱbjBcSߊQ9Y):_Jc&zjc睧Nv ֲpS19싙f.{g.ҨPƴbhOH؜4SPc刽ڧs6%0$*c4S$[ɭYu+ywr,{X˳L+'!Ϯ1Ko"MbboB-n[5{<˜e<H)_uN屎2>X[ yv`5z2EfN=S1LfM3$>O3#?? MUj1Ghq_Y|}K*j'bsv㤏-ep};aQzcaʽkX߃8.))RF8cv,> 2 BNxڧN4؎"l1k;: jշX~ N4DZ#d [tZom)X^ J1sg^i߯f~1fYUiZ qf {y5:^w]|0j&CwA҂ccƐ-`(eѽ1O_ƒm~TyB"wybU?-vО`sk>Mi ^YâeװH&ӄm@)b36=߇D$L8%b+1t"44)[Ly̜q3~:r矾Y>s9]5;ASCp7?^ h:ד`UÈB!^cAnܿ6)SeʁGr=Xz6o;d!/sXNĦY^7%60 "QkρA8x&M$bOfHPln:5T$VEm6z )PɽxUCf;HAߠ*ډ[Y6|$٣>fbB7MkMww7mF}_JFv)!n a'~ bO;Z*z靋45;m+% hK!vVf[!sW.d2dY ?t@`09"q7uɯ7+E]9+#i#0` !bxCtww300i(bl<;u:@["XUл aJP mB~b#[! x\וm{OLX1co<п8o([!R/^:B!BHB!b$lGR@) Qr^G)E{x?k !Bl46D#(%t>pO>&㠴L'B!FBV 7Ihsx6"AhǞ|t3i xs?Q)~ s.8GW0q t$QE!B > |ߦ4Dl?Xe2攏fR{|ٯ)1cc,pc93he,nIfGB!;0jEaƬ !>"N9 nKo97]}7߾~G6?s|Gdn g8]EW_m^)uu>,?6) -B!Aw[{68l?ZK{je[Jk=^457Bʧ\ Bp4r+Fj\9 XZ EҥK69sfHIK.^A8q m'Ud:::^"G(-d!gc0~DrN3D!4EhmB!eH!B![!B B!BHB!BHB!.B4:߄-BF0kyKEeR%he PmF0ȼeBB!v 8ʍS t 4*(aU)ԊQ+hu0xCyVa76o_mY*pF͡08L<][g77ߥ p)M `[=JMd?ch'DB!NLBl: ʯ n4;)|'J6lP~d4n$ @!~xn$k(Ƌ EQ^e$qcm7Nh@bx>~t_'q7@eT#cpc-htFkƞI"& w2 @5'1B]Y=5{Y(~q L; *}'z0&X'hy?f+O8Z,Ahuz5IP'w\NCgQll"0R{Mzţ'lL&ЫQA *c ;f/_q9gNsN E&?d|w d&6TʵMK:p)1ygy! ZZG7jHB!ĮInj6XĆT[gN2k1`W&RSmv+H+UTŵś..-˗PKA~‰#}W,04*j?izOG_7 nVMxVӨXh}D=N8 Ҏ[ޓ,]Ip=B R>ي?ΛVB/dɚ^ FT}M(̃P[Y'?ĝH!BlC>UFS4T6858%scs/v Ŗv:@+'\ň`qqos8RM^)!bW y$gF_0*jmGPnޛR,{ƺS؇N6p7{)R䊟{l[^)!bQ‹q!Ƿ "=O5 w߉?BuaIy/[zغyv6 6w"wl8㠇. 6ch@mE7~Fo| w$NyGY]@K4˽wh7߻" 4%z歀'>o~")B!/)(!v $ 1`+*qm78dN80t%To|V6m4 ӻi(PMqvt$+DU &=dʚV"63\ti4f3g)i ŋ7H3~'NLGGNj2hEiDB~g4 CNB!Į&B!BB!B!-B!-B!l!B!$` !B!^-`ǥiB!-4YIKXF@! KNB!l!B!$` !B![!B B!B B!C4ZkiXB!v54R(0M4_g20Mʏ \T5^tg &ډ8(s~ B!v#a$I, ٵZ~2̦RZkL"S(^~Q Bh'>钀-b?)\% 1eZM712 ---a_~F7=ߧi "9 !¶1jC,Ff}CR`9@ Rzgdwh)-B rhEm:zH":Q%/HPͥ#ehO 1oÆ= Z@aJL`kRΗl!;S V{;GYQR.цC,"d 'b*j%"D |R#6:}Y_1)VlyG5q];-BĨ.OS\}sw~s@ ЌB}^ϸCx9+؇)jB0V=&c`3,[KP3>FEϲ4<μ9j?/95b!; C9.8mk(Ta&/Yys$xB IM>&X_TOVihhjp]:cb>z|'x>w $gu~-{ݝc@{7Qxv5FjԃY~*޳O=P"65ojBwY<61myX3=&ƒ wԆ Mm6iBs][cG:#jy:v@ɠmDX_z3zڡLp̕u,mfukM>fDJ{aDL=}MΘl|N.5'ͱ13gGx.}y'.vjMBX\aG Qe&b*eێڏe|JrlNzrgjQY@ UKSxfi)%noc`+AsDёf 3AWI28ruHL5C k[ D@iD`@FB EY|d2'p$a(aEeZ+L;c(e`ҳYLC9q^lH_'bD8!smSN>}p+''G>MXe(CS0 jUeһ^6.2Gy[9?_> }wN!_x]|7vgn'V\/w>]#኷$轮͍3amOq=VDr,K3}JV⍛9sfHIK.^A8q |'0m4n|JkfT{ 'nͨ])z Ki^ aS)i1{7 qՂ_`mU@揹w\D"T*/^8/eلB![+F֑/dCkDB:`WU2xu%`µ4ohBpaN_))-߈Lljs%` !vtvv2sL0r0$hKFkM*T*ׇiC ¿ps7kj-zȞu< W%BK!FZVJq" MS-Md0:ИN5 Y=81rXr`b4ǜxGG,%9`"f}iGS#aU>q'?0]Y˶Bˑl!]\ Q̘9/K|lf<ؓgfɭYO=ʴ=IO` R0neaGsOJ&Qapsxl|:UNgC!dXh{VL~:p%OR[]DqyυB#@ {t(Ni=XM4Ѷ0M_HCXIF1t2Gi4 #7kxr,+3PE88NpԻ']YŢ4 Y7[ヌA/N4LC!ĮIFI:Qv&sUTf9y ,t \Q*k>)KiՍ6Mj sL:lNJ|^YyߤZ & Xr9! vx{8')Gn#,!kE+Yv\!ĮKo̙33@Z{)J;u2LLj~ ePAoDaJ`aejDhoo8C՛F2&RB&=x =H#M ~JU4ARA}K Jo1F!3@c KAH$麟q6~+x9Bbdl!FxTeX:j`؆GOW'aT#8GO熡Z) =4㘀Mܐ0mLb&Z+ C{ʴ0Q"1Zvx4-@:B!$` 1b)vzaiK06(آXrL>DzdB!DRxdž ?~f!0 ,˒p-BibwB,9C!B![FR@~!bKR""ěN”x 9i!\#B!Ķ#%"B!BHB!BB!B!B!-B!ĮHU_IENDB`deepin-terminal-5.9.51+dfsg/src/assets/deepin-terminal/terminal/en_US/fig/closesplitscreen.png000066400000000000000000000730641475472654300324700ustar00rootroot00000000000000PNG  IHDRX~|[r pHYs+ IDATxwxUlzot(JSl|*kîXE`ADtB% $fݙ9 B! ܿ+r%3glr=NвID4|ֲe˄4 @4@4@4@j\ K3f3 32^`{ S9.',&W*2e^dX $I,8,;BT8?sAW?]IV]v;gJ':C#:L;MUR?9\Fj:sestqn$000$$S{m,6UjLp,A)Scyr]~}ϽB`0gLUHu/02T) SReRt<g\eߓ^>.3]cJEQ׮*9 ,8É96ÝlѲ;p.MJͲ5)֢(J+{k7)Ocn1pƖʨ2&e$٭f{8I#D.շd:~5{]~PaNZܽ}ruz<ï_2}E_[ZoMO7ޘ|ل 9w9cy+wOz@؄>u&Uͷ{JӿMԁݰc ЯweI4se8\G)Z[|JƥvQu]WChuq\["$|_YPyN1S#H%"w ص}Уޕ;V-+%Z]P]ΏWgꮖ9jzcM>BinٌߎO%b=o*הiɳJG;yU^ҧ[Gqؙ%GU"7&f`kW:m=^a"wlwxDA,/Y%V\40WLJT݁G7=b䝔V"fxNs ;Q%2|?5")麛n٫}D?nd*NJe^8~Qo;?<-ӓՓ2ܷ eWC\mf8Z de56,S,ZM*@h~]*D2RP@#} t|k殑a^'׺{~]aתR^%?p8_C5O˶uGًm̺}.8,^ȩ0i'}]K R/K q񐠙z)}>&) "Ӹaysb02w6ȐryesOVH |4g[79& W. I,hK/,NfPwyTԘ)ߕܩJ4xYuds_K⼕(JC=^sZ"[־SRk1/]"Ft_r!{RIٽIR;5rƽVP_?S.)[RP@I5SҽfGrxQk&[ũ}Vknƶ$7C{XZ i>C|m_m=۲K1QNjѯӋeIr_Z7Q ⎙9ؠ[J:*gpdF.w/>tKL7%55?_5+WT྅ gP6է/g{qigybhHӦv:Ue8D Tb"cv^} :zI~ b.Rk++Ԣ`zc3hD~Mεn J:f)Dc XK9tm(sSJvVއ:ODDJHu$/tBwVc^SՃa7~k˓YaW2ŝw"zKm\V9yy`> ¹aS%jWwWoD$AxXm]r]%YQվԢ)%㡶\5ӻmVQ+l۴xO971_̯#η[f5y 2fURYJL""b1@L%bL66`-}YZaO͝ꙀWUvegZ˫k¢}6ND&_;ebU\& 4EU-_ReyaN΍K\*m,93HEz{KsG ;Kf\uW/S1߸fgŌyG7ˤlDD>Sy֍}V}V2hX?lI0ߙW }HD$㭈DDVGJKLry~Ɛ{CK?;ISϊS.9٣rhi{ˆe /oRϋQ%$!ބٽq2LUHHUd"wQDxњEkȽLu{MzMJDr%jb52q%5^ʬDU,k|TvV֔Â| ?(D|QA9rJ|Vڥ^W aDDpBqΣwdҌI͍~'xelɧW,C UN=m]0?}JD+SiV?SZ.2xT9Tљ1@E؞^q<+(bjZˬ/o gwАzSeF9UUU9~-w~}TSQʞGj.?UwlWiawNu[8CwqҬulUfMU*KV :SuBD%,SLU'‚Vs{%hu |]{nk._@Ϣ:n;\oszo)!JD\Q_v}S3e56COV hվ1z""ƘN`g&mR{(R^驰Fts .Yuftwv?ǖYzzj\aLL"HhDrq'wB^JJwb\&E%s}^"~KL'>}E#-..$>>yyyԩQTVU1̏'cN+Sn T-Q+&Un2%݈󴂒1GEw.T25L/@d;7n rx\壣"ʽۖun %Y*NUvF#Sv4~tFpIuԭCm61_oUPDk#EYN袲^P4Uok{%;cvjgzqjٞ˫teL9^${ +&oۢ_uc˯aG+޹Qƈ9 VI.(kYRNcKAkoNh+өF;DvyM_:-3}Y*kӝ<.`Oc;UϸsKLin@J]QO;Vק]ٶz0`|RN$Tu+aAY^5>?jnUi箶 U('qoҾ}%"&UF$*3ך1uݨs#nܔH~GvGH%Z_Qڛr-Ϸ3"3Jy'*_E' SѲ.rUe)d>z4@P*դc;@5wpg.#"Tr\ֹ0ЛاSyO"[Bk}~*ʉ|UËzwSvfFFܪL9#”;x[:Uz:Hm͸<)RIBpB62@0׽c* EU'rb+ 11 #ݑ~bI&gԾ.BxZ|Hr3sxP_ev/ٖY,)l"MԹcknH>6W}/ cĘqEm$n7?DL ~*ć %"6CԒTa{V) KmZT wݩjAL "DžT1ױT+G_kxK_3 sAګR UF30)VQS̭J{ 5*\~`>L~D"WvӠ}Mn ]e:1H8^7H@LejD^Җ"u A>完MFTѸ*8b1 ]2UޛUD8whP؎.ȫő.csLIz* >Rk*dNB;CDc2+X%2Ȑ-! Hv d.]~.xڽ6]V}$f+*Nޢ׏_cL'"r9SӜuo\_A>3]K/@50vj ?=Q.K>')jdĎsx)n&}jؾ$,J'pZ&~_=th%_%)AUR+Wn%CEGMCAOaUu,.j{H˪:nn5喰 G|~%N"+W)`P{E:,bO.7Vv\1bWX qRtV+D΋ .Cq1$:g_Oґe ݁=FrAA*Q={5y7P37sc*( IDATd諸jQ$>琹3Of-:v|ؗ>D}g<}sU' c;,==}С򐂏8 ^9"Y;),7mƵ;:vG^Ov +WJ ore7f+\E SoRh؅0סIvj5U/ܥ{U7g@)`^@Ca]O)ܵ'x \.6RswR׶ml^i!4Ç7w(**A  h; h; h; h; h; h; h;/^g3߃\%[#Ci11_%,}x I@#t9&]s7Σ[,V3b/NO<⾝U^ֱ@)?wKsǧ?M,y)$M]ėxsKrtP?<Q=N+p~V""v>:5(0a5vU<'41_d x_PsqّmWFř˟gOlޤMg<䀭4}7ԝb{ZQ_K޿x}GO;6Rgj73~Gye&X׷%l㣱v,]Ǿ$Kزtք+g}f1aޭ|=qPHG:qew&۹v;9tݱFy|:Y颇=7kɦ={w_C}v7:oݞOuB  wK+M;~YЂ]3;bxfb 2Ս~:H??nzИu:sb?wbNC׎?i\^G lv .*-^`>KVnQMϟ0%~g޼gWNc3yʭq{YƮoy7O\pUGi˧1lmSy핃,KofD$=GM1lģnxΞ̽'or~tE C 8m=cpݧ p"wi,:vRZ^VΙcy9V|8}ayQ/힞IuoNiql OyYY^t8Cn_zsX'+e禭fNє4w]?m"rt݂e;畖ۼhUz`Xogrܛr]E" -\YTV%Ԙv"q˒ysu>-ާk%¼7pqܪ}҄wK@=w<楥Y=?9%ZG T6Nr?#̺ 9=gW*I?%@ltqynR 22lSUv%1"{÷\d UKbuɊr,%=5^we97~6z`Ԕ#Hog[fz>/ПQɇl?_ gf2c=YLD E18DL`T^6 *p'ˮZlC9PrCqU9BzLqO)pq-XЫS{j;q'?y4іߜ\YWV't.ۊ<Qz9pVP*p p\[jOq/n%WvOM !xfСk2k4?ݼysx4Uo^h[6^eδ oFNZe?s3vz&LY{B]W_\y.r ekWtpFcÆ kn@SJs;pڶm{=k݃$Lx׼ͪ ^jx%***33{u[bfM@ok,*(Š1԰ 9†k)Nc^/ȏSqS%hrWU?Yt#~x6w/nxȏpC; h; h;`Ug6 a@0*++ ]`@4@4@4΂WY6B*a鳝shC l&b7}rp)_3mk=7ή!-Ko͐oSs [l_H'Ɵ&+9G&p{{&zIJe.^#f$TAW 7T_"7;]=&`?_.ٝ'*D~阕]_I;b[8Q>|}iLD< e-: rOnP߲h҅˒MHijI2k5DD$;[Dn#oՇ  ڷ}Uѯ_vWĴC?~uhA>&HDlrt _yͪ)חq"!MKֶ,/Mڗe].#m^i$+Rw[|afƙ9P+i?~hKV [OW?dUD0چRKZr(=95:2NؒMSS[{xuKk9ޒ,NR͑{cKk Ý_ 7~tϰI{_ _aΈ #jpSJ˺Tע.K 6bޜz]-HI)ߓ_QS.t*{1 ٘eW`V߮DDTcO<ᖱM<ئKGcfzJbuZ.wKx_ۦ<;,>4 4~س/~Ifq[饉׿9}Ml;t㯌Wwl[=7+tЫ[sy.]ycq~^)ͫDDnsc/ku%O.DʡNmoB| 5K׼qkϼw[[YNZ }u/ xhaYʜU_)?\I;}(?ִ[^o}P};,̖|N:"M>)ЕgI=`3>u/}-nʛK4!>lذ4?ǭ{gm۶n^\7wЌ;Bx=$Ζ"sg؏-83cGJ?Zz\Y5z+/8SqS o=3ڊ{G=ȿO`-me뻪D3)zRwKK*,?*ȯu#Bo2ۂWoJSR{Q"2uIoOVXʿ<0bx ԬfP8cL5,^-t72R|Hܯ}L_lcRǘv'^ŬM-|쿊9y ~0v`V"" #;L%eoI޳h2mEz{}[vk`_R8*DŽ|x{Ǯ'[}Ԯj̴v1:+ܩ A)HDUجm_+?9Uͩ"Ee:x;ʔ~YLLׯB.^="_S.t5c|)!_.ʴ/..+D{"ϓ[bgߣ $7IJ*Ƶhpy?*\LfDܗ'.c!‘҆9Tm5I9'ӏkےce΄7#lH@VX{/QX>!3s_j˲ɩrfH{X:bM3 aq%em}zD w|O᏿2~<./_yӊ[g2Ŝs ,uO:1TY>ߙ_Ѣ[#)e8T&YNr}1C?Perm^k\xq$0"^A`lL7ڝyR]kh̷bugV( vQ^to3C:#Q$Z7W_JwmVl޻C6CqB5=YKaF/Uߣ'P}fkޕ2>::FDīɥB>MLCu&FQ'#H 0eUsگEgp!\ gS& Gtgu 9}:'i~=W}lF{ ^RVw+ץӋv>iy++G 21'<[U'0ExtkG9}"υ W[[: k:z4|vJe.rŲd!=PSz֩IȯJ$}QO_J約,VgvYM=1*[R}GseA[e#S*9)EC{X}@}H)#׀:LXt=w8~"'u .xu;R.҇'[(%UdQ;\h./'{wGZ=-=gT_?z_FauN?q⣜"3ަ2g1{olT``}D!cOGaDT.O9QqJYbD= G\*~E醨;>[=jj]DV,9!tu 1vo  8286xA6WʜْWȈDžO*me_?m};:P*pIpzŽ)ޟ1i Jl/N}eF7G} J.@rCJ8QQ_k7lkddः*MVU|J\/c/,̯ ~)X5c"xFG#yc;e=.J~FkݢlQ7D=}OTS4ҝgpvKOO6lXswRПVܽ3նmeo6w/.1{tP۠233P+VCq-!h;T8Ǽܝ80XUBsw.uQj^@}St͏t͏q-;@t͏q q 4?f;Y<056A7|Z;zֺo'4?܀ R!t?_fw[ݛ5/3Fz74 3!x:?bӪKH^',,̸\ |'M-%'m_9o[ [1?[lZ:LǍmG- 'l][bD""}ܴykv$$l[>QqSo}ݤ/lLؗmŏoŇ=ژ IDATis{ yogr哺De1vZs_uM S-]-a5ˈH?״y$,~Xu?{fĈVO:dB7~c=%"?[}o |̐H{6KDb+6P'oΏ۹/Hi0{Ĥ=Lś9tLܷswn7Vڗ:篍{Y`?FDaZi~p`+y;?ڞ?iƥ>?$ _;%s]zRR? /t:7 q)_aѯ';x}o_} O!"oNAcủ'6h?ek <~ǽ)%(9G&p{{"b7{O~{7卻ۊD>٨fׄ=٫ݡ<`woS/k>8Pmaһ* b@HDν;w}C!^;|'}o>^O,gw\7ɯޝ՘s*Td6 Xk 2vƒc};>e]QQT"(YZ,?*cMcs>c t/mh%/zBɬ(w]C]1zՑs2ڴKwqBBazƭS,?FV-tKeggkP1¹_6lgO¼|9{m5O9pX|b|ءӷe|շB( Br?GgtгNت^W&?[L6m0Ty&ϝrl❈'S/_81Io}۪FB(~fy>Qru+h[m5^ic4/+ /<ٕKZ*&UmR%Bi[ipLe%nbMYy2Nb쥝=;;ciZȮ낅mf8#yp˪}|ta!{f-5tIa!65aqRV 7=[o:}g`͈~>5Hn{, %1d]:UCCI$\9d '$IhytۅJ OvɺzMɡRsrE_[Mu2Vu(W΍>۠iB<0ʮ2jTz5yёwr6#=C244BUbJU3e†ŋ*B/"ڴX)#4y윿kܠȶu#RY]~3C#)D51hu#fw;{HVi~wǶswpRSշn=}%ooKi_vy@}՜;7{osz ݓDI>Q̔/ϗRě>de$IYs;O8|g5Z4ٛ :;N͒7K<"΀/Zs5$ei*}}h 1Bu)N٨}ރ:}{/d!BJ $BXQNS9/'BڥBRHYakّZՓj¢ֺm@O=0|*xQKpi.±z.+K7s:YC.թͺ)̸obgc\brƋaR{=2bʹK*,T1.h4BT]_))F+"߱ODu>0J]ƵNVGOeDȌ~p媖[v Uno4m3&Yr6''[76XjmW(mɴJ 1 ºNmNS 0/U V8Vs|qsvd]'|i_2s[vknKO=M9sV5sj7js4w=`a0gRK988To5lenjja_Rg u e{ϚZۦLi+mzV5SӰq˚[Th<`Rߊ7 W WTmy1bޞA565t<[,+rڡ~we֬wh?qU-ɳRE.<B{ۀ,Vw?%cߦcyuU',hT7KP:Tb&E~V@RBS5"-uTDj4b zAusKn\ǘG_8i hOaC:RiL ƴrcY1̼qkBnO>pfRz|uS7feNt3uRر56Ũ$EKy}rL]֪I`4dd߹^ 3#m}5ҹ_Ww%K!>>l0p) 2ͩ:fuu]>mt 2@pd*ut@/^\% /t 2@pd; wG*:jJ]}`#Z/ln0|M ?l^Ep@Oh35u.5d>Vqj>iw*r*Acږz5{l=|\ If/['E_鬳Be_/Bm&,""lu]>Bb VeRsg/A M@OHyιPcŤWSXvѮ!m643 KG| :wDݺJ!Qf &N!!d:֑>o?;/=ѯCkc5BsPZ{N$dwԲc,`I ލ' P=s~xQC~)+;jוc=SMZU[$4m:V 0URy-g@ĝG)w/:VBŒ=gg?)9;wu*C"ݧO$3}Q8yA[r>{cBƆ ouWMha1+)/׫,p5UAT.m,i%cs;]s/֓UQQol"^1>3 !_q;/ky|=Nkr²DI>̔ϔ.RR/K]30Qy/l2 ^4E$VS׌/cHg3~»/%!q*/Fuudeq3*$) xpT/]t< Mr۴W٠WӶVQ(ٙ\i_34B(Jx!+JV,slhWVGx';Gqz;gu e{ϚZۦLi+mzV@탠sn*8'+uTW&!>P-(jxN|f ,V/n^|A>#\[[Th2hwfw%Dp@eE5êTN[yHa=~pGZ!:\ГR'O%i{o+y|k7olgB#σs+}悫=|m^zuhyO}Lc~{=Z>cwI111κ.!pbEU lmmt] t]LJ; w@  2@pd; .ccc]࿎; tнt]ŋ䅎; w@  2@pd^%u[|pX5¨g u]x;JR&y{'tYBp@_쬮U%t\V&-!f[IZf{43y_8x_% W6ka9eIB(K58x+F=nY^e_ BZ;_}Kv-ro`Y⋁vxUÝ B**hYF==.4 [u: _f p|Wa@#Dj?X}ĊĪBYq7΃ۏY531^zR̈́ŋ=nttaX<iiZ@acN=/V4u a.&|G4~ $z|xBwb8cIZ!"B !76|Ź !(u7nf `]ݶu*uSnݬ>x=]CK6}{J+ÄB{aݬB$pĪ^Ilɇ^#/2fvw.;jfp 37tg E L]}Z/ųrVPZ;ؙZ6YmYQy1Y~4xvx6^MbdTJΤFF;BzFDij^x5 (¢ֺm@O= [X={UI!e?dG&w*Փ"u$P羬H骫T*6/!YYYJGU*Wꝏȼk~!1uk@LlefRlhUgO/xҳ7J[k|BX@T:2,BQmk+#! ,>wiYiӬczeL \ӮHjBb6#`ێ; OʲBy-\hSnؓbM+Y*cSI.M,iQ5{uVtrlegkt[3Uߋٸzy_FU*m*=I3 ˬmK(S7𵁏z:)*z}aBg|:rȈʚjSb}W ȟ2 -]t]6**JU*..NU|||*; w@  2@pd; w@  2@pdRVe6Ťc3Ɔ(oaf+݊>Ƈ_:eeH?6{ϳYB!&:. @~U}IK#VR֠hem Z֭QOO/KAG7Mnkkrˉgt] ! 46K]ZG  9m yK8im>{|(wI%9m fm IL_ڱڵߋ>ǜm{~3;]v7㕷5Q)9`TO ˗Lv5^֍WAp@_hR܈x JZc-NUi"%s"¢u!V+;ȃ*dj}vmi^\.#VuI"d.<Ƨp8pSsքu]ggg]n8m*_QQQVVVqqqoC; w@  2@pd]K_G:^zzKDu]B; w@  2@pQs3 ؚsF[2qtwMla& !ʷ?84Ϧ]mZ5zWB.<}9,ǮB乖Dz tbg/{ ZqwT񰱟]Ҳ=NpPXDŽqkԾ)jiñk<_;mݧ);hV !Aesfmu}qLz|7sq;|պ+ukd} /L- }᜗f)cU[gS qbF*ڼ{{u96NĉCJaP]{Zx3޼w yy,A[4jn;yHs?Mt_>m}$6;GERqKԲ㘿KvY.Eiߦԏӥy&_Xx6w>} LDDd`h(i$'ܼ}.Rۛ=wƮ˱w"N,GL:W1K׶rVb| GMR|8y|kE-^J! ozH>u|.&j>:Ms/`;R^u8`%sVQDl?2틛}߶̚}B:p8Hi`ԔqWO=z=}~$|wۅ"+`ŴC>ko-NaeWAz-3XjrۜfuzLtbvffdcnef CCCŹmk_ iR*ncn=x*;\oFik33$C#7Þuv9;,kIژO0>>ǯ4ȍS:h7jGR:k)TR^ADhw&f|ͨ%nѬy/y3+Ki%Ih4VnѦ]^;ũ@vz/t"lCziF.?+;ZUV0,`s.oݔ'Nomı2;7B2;LkbGfUV9wRe*fw## 51 _z͟}Zv(Qr͝[b%ܫf`mSLu?Q.߬{ܝЦ}9~+˹^Uj`$4VtjWB(+CvT:Tb&E~V@R= wܩn3scn{4lkԷ;1ձ[t86]:~w'A[zu3P G~{N(:ޢx)G!-sv(v +[Z׮TYbB{XT77~6u:~ō̠VOwo_J_! ?֢&#sF S !.ܳpJߞ:deNt3uRر56oZswhwѣgiq"͟ұg.1'@d$G\8c]y?ϥ&O{5{.ʝGfU0~sʥS7x \')J .VݛMzNϮUsJ4o>o_˧,Sz=:u9$|7S/K_ x;zHhj ˎ25mf~6a9yנ=\\-6|Ůmtu nS~jP@,u%ON:x}Ӝ5#hnUvp>pO07bմvoO^.=;[CԄ}:hKv&|`ۖIl8vjJ!>~p3|wCֵRh KGTUG-u@/I_Pތ gWΤiz [51~֞)ѦmÜ3m­$.\q22!!׊;Z([Z1리<q'1鞇td&h= YwAJbeku*ZyBͽ="^1I)|?Q HR7kX|b3}=˿&y [@>䛅_iҨp}M[r>{s 6/(S!DzLtF!63#Cs;(3SJ@;˴W9KdF*{;S䗖VZ;ؙZ6YV!ddjh^Lq/ WvРNM*6]77#䔢Hϐ  lԱ)f(FEK)PX(nn3jk!(I\!a@_dqYۼ%2njBG&u=MXC!JҾ0^j_R$!^mk_;MI!e?dG&,ՓWONJf_fǐ#gh-:YYחVVl[:27ge񜹄g~J~^뿺&y c@U}ssS6>4ip]c!Dͨx;3-3#.\en˻Pv!4P(Svd]',s?MJi_34B(Jxm[ˤ5TLٰZJQdncb6r(-dyM/]+m++mStSBBB޳&ֶ)SʾnT^k-{6q ]ǏpطXV̄J~Tyae {[ݿi%Rel5إC4$hWnb5zVO?צݽxT󰾍 f縢ͯh^¾/Z.^ҵb;ކIZ:coS~VPyHa=~pG߰4wv{m;z~%O7?M+P]XGJߓ&,&=>w؞,)^1p3\pog|m2NީtË.{BÓ/k0uS޿wxɩ_^ʵR/RLL|H7vu/[[ۨ(]W6mץƻwi{y:BuR=}lɠF!5 MQm:xx+2t]VwRG.jY ~#ֈ.;O^x ; w@ TtX%wt/==]%x.y; w@  SIа PȮާ/^ h^5 qa% ٭n>n^`@l0r̦a &9 ,m٤>| |iCuߋ~z;>E*Uͣv-x]kV !TfwǃY}!!U7^ˤ GFϔF=Lol(05oQ.G9|JXK-h:e !W^3ҥCê)JW|5<$Utwa9ORK7.hy]aq^ =WfsHpEm{ӄB]C/έmM6.̟10լ]2kM,R۸I]=Z'#=y$R5*fg]@2_G-KtгNت^W&?[L6m/>t=Q%*W.׮%Ӷ\vx=ws0( B0>"ڼ>> \޿seM]:ix#sIu(WΝ?Ǧ776-n^=VDT笒$] E L⯆r19.2Y*?G>ul@o.^Qͨx;3BF#JEmALlFG{Ӝ!ʲ^ GM=ܪGO^ֶJCZxlY\k۔)me_Mv !4Ϳ3/fQa~Vg>w@a~|}p<0ہK?٣WZBhI'}|0_+fyEa^=6h Th3f6j?qX;RLL|H7vu/[[ۨ(]WqIEV!պoeee*f>>>tGg`PAz:n(\j*z}u,~qމ<G4k-Lux@p&𴞇 w@  2@pd; w@  2@pd@>}jee*б8]@*; w@  2@pd; w@  2@pd; w@  2@pd; w@  2@pd; w@  2@pd; w@  2@pd; w@  2@pd; w@  2@pd; w@  2@pd; w@  2@pd@u ٪?)IENDB`deepin-terminal-5.9.51+dfsg/src/assets/deepin-terminal/terminal/en_US/fig/delete.png000066400000000000000000001656711475472654300303570ustar00rootroot00000000000000PNG  IHDR/j pHYs+ MiCCPPhotoshop ICC profilexڝSwX>eVBl"#Ya@Ņ VHUĂ H(gAZU\8ܧ}zy&j9R<:OHɽH gyx~t?op.$P&W " R.TSd ly|B" I>ةآ(G$@`UR,@".Y2GvX@`B, 8C L0ҿ_pH˕͗K3w!lBa)f "#HL 8?flŢko">!N_puk[Vh]3 Z zy8@P< %b0>3o~@zq@qanvRB1n#Dž)4\,XP"MyRD!ɕ2 w ONl~Xv@~- g42y@+͗\LD*A aD@ $<B AT:18 \p` Aa!:b""aH4 Q"rBj]H#-r9\@ 2G1Qu@Ơst4]k=Kut}c1fa\E`X&cX5V5cX7va$^lGXLXC%#W 1'"O%zxb:XF&!!%^'_H$ɒN !%2I IkHH-S>iL&m O:ňL $RJ5e?2BQͩ:ZImvP/S4u%͛Cˤ-Кigih/t ݃EЗkw Hb(k{/LӗT02goUX**|:V~TUsU?y TU^V}FUP թU6RwRPQ__c FHTc!2eXBrV,kMb[Lvv/{LSCsfffqƱ9ٜJ! {--?-jf~7zھbrup@,:m:u 6Qu>cy Gm7046l18c̐ckihhI'&g5x>fob4ekVyVV׬I\,mWlPW :˶vm))Sn1 9a%m;t;|rtuvlp4éĩWggs5KvSmnz˕ҵܭm=}M.]=AXq㝧/^v^Y^O&0m[{`:>=e>>z"=#~~~;yN`k5/ >B Yroc3g,Z0&L~oL̶Gli})*2.QStqt,֬Yg񏩌;jrvgjlRlc웸xEt$ =sl3Ttcܢ˞w|/%ҟ3 cHRMz%u0`:o_FIDATxg|lS I&轹P\pnljĉs礞$c'q8c܍+jD j-3 I$@돌;;;3sò,DDDD (((‹‹‹(((‹‹‹(((‹‹‹(((‹‹‹(\d `Y3ި7peYSA@*n Tj0O03mްμ[;v9eYv.D˲3r[>""rh@N}3&;uSKrr˥{bY OVBa{oVyٳgy]QSi%Z4șiR__al6vN@@AAAlIJa,jYw è/Y0RSSCMM iK\\vv%癦磲"l6CL0FZuaEeu}eltւ*`r"##tlDDDμYx<SVVFdd$.&T0?6--MR9te5`˲㛿O4)--r- ,""rñcpDEEL3 1{64Mx,i˲7Caa!)eit:IKK#11B<O}d~K5i~SRRB~ k!\nC0lj'oi3N.fcYͲ,`Pz2`GRgbiK1 ޽{O0 ׿n.f-Tq|8q}p8m0?"""mo8ˉ'|Meݥf.2MFv2RRR TX+V`` )))5lt9ޖeMjt7!(Hgt62Ѳ> /i7Xe4u@*//'%% =]2\}OJJ M]- ˲Wx,˚Tu#,,. 2Y҆!MUjnAEMB""ҕ$%%Q]]T}riKJSxx<\"""xK%dfiwIÃtUaG]]i*\Be\/DDiRx #uњVDDq:xn7pr 4z-"r:p82î"r~/ /PSvZPh K ?0Sz}wof_'e}E MLKwXe[yBE.L<e Yә;kz(-ޭ@"'x_sЯ>/Xʋ O/~"8~>׏\$W &\7qMEw2yC v.|'l۵V7Xgz-1C/ҵ:.~ g3!nthY7f&e܍L).);mںz?6&yd=bʪjnⷉθ_ާ˸cL?ג4:>\??b:/Y{-n;!x}jZLďNʸYn3'OG)1O{"`.VpiT奋T_D$s9KWtv: O𙼷p9館߶{A8ćW_~Cjφ{?=}'Jٽ/&=9J+k񛿼Dm]=a1/}RYq+n6nSﻲMwaYёL3|W*QP\²uٰ-? jn9gm;,A/tJKwg^Fi^pE*s_OϠ~?Ǯlھy*k_?MӦYS[ЁXsr\ kP(n1cxyRU]CDX( fNnŝ_;sX iF>Geqۮ仧,ΪtwrY*-r%,RWЄ2sx&?>&NQaf̽xǿkw%7RW&Yq8=ÇBC֞q9|w.Mnql6*ٸ5 hfƭILdF7,Gܳ˲>$1_CxX(\J+N{?xTE:MoKw+ɵӿ8F>In~l}.0_ OtFDxz<|mRW&x뭫wAYEiUɰA6N70N|9(eGc6($Q]!w-|kMMmiL$>6Z_Pr1*0ݱⲬHʋx/k6y/|9D54+O>ck*k^m14$]/-3E%bl6&yXֹrNEK\tfFt5HH]v"BCy|>v{Wm3{/ҙFҝmXŲٽ-Y))+o|k:%s7sWތax^ K\5a4ˋޥ6Woh:wr6o@Fz_JO7'}SS_li }EKgV`2 /"]IkJ7oUF1m8z% 1rGQVY[[q@4$v [-´L"Ø}5 >Cʪjny52rw>^쯊 LY%[2oqאGsn<N雚°Yn3-^EUM-6k'mo(*"/3]rG|ū72aP>M^A|/tVTTyË.rhTi\5aSc_⇿#UIRByO}ܳj^zcajxٕCMm=ռGGv;>cF߱ak9Gԋxo/X7Nkw@Oϊ [8_S[ܛSTRʓ}j|t8xj|l}岦ËHwuM3H7\5az>]v/GgQ޽x篿?%ٵ?GzT4/y ё,NTD%e U}zO Ö==OBl YL?R_.QxbmG'XeQPPٳ"""W{f͚mvPEDDg^g5WDDDνTxQQQxQ>2n6˓*/"""W0U^ȇ_9~SE / ."""rV^DDDD[QEDDo"""" /J"""O*l /"""/6[j6QxQxQxQxt-LXr=^6Jj_lILmîҁ‹HGZ}%^ M- `_b^roWL"r, O{,`qiNƒv-(i3GEC%3x}Ŷٯk<:Ǝah9)l?˼;-nᄄxx<|>-(i3EbHN!弿K ~-:(Rx9tyCpywŨd'Q^^$",88Dt72 5!\|&n>ǃme&DFFp!iy+漆'&[SVV"r3Ahh(vӀhveY->ZԳ0ؔFEW6Ht"WBpi)z$00Hjkk)))p4FCjC"&M#)\^PR| jjXl#7젨ؘHOHNDN'AAA>ߠ NEK?ƿ g2!!!gm.`*gevl>X;ƳdKQ奃-^ڱ6蛖ʵXr33)/\WLN}uس0?$E=p p1CmYؖEx),.%PSINҼXsOeUc((*s8o~e.kRT\Frb3t~: n( =yiGf(v=o HȎ]+  t ͮx>ZC17Ys̘(.)bN/Ǟқr]z)l23F^bc@ cGgj 27o9>  i 0uMjRzn@*̹Qx2Cy,_/=׌ePzZ@Ρl7=<<6oݦQUyvcFdȁ-ÅkXaO=s#ODZEx>~M~Ax}'/DDx)cgܨAl|'۳1Ee?K>)H¢R+Oiչ[NP)].'6lTǖ{Yn;RV^eAXh0M^1#bq9zz%ȈP]ԻgD;Zv=DUU-G tRgscۈ޹3 n4 zv>e]RV_|#\w8z-!ϯqyͳhatg.![C2{4yW<|6ycPq: ´ެ*"fQ]]M``9WpZH9t?v?G ^:d^Qx^6qwj"QTTTS_WrM2< .w/'C ;pÂx ػsߘY*k4= y􌵁-dƉ*2VOd۩$**!릶z4i+jtj~WMAaIRth"=b !,ZܼVVkdtւa0v`Ld-e`z*1 agҸ <^}fG՝Ln%8v›5{+˨a8vK6t]_Jq[H8J fQ~:EGu,b8C# 0B2>Eo!Yͬ.PG+ȅt|kjjVҸ^a OOrRe@zB ޹3yiG7g̈DEsX{[mz޾i$em8Ǝbc@. ma8v;LEe ?yFu t1*?e~;C``@%q97_MBZz1$kE=]aoce~䁑PêG)7 &06^[ȟ} WH"ͻ90_k,:9Aqq1AAAV%|ph G#Xb3{&xq1\;e81MMZJ"Yw{HNc-W7];bh:9򈍍d@^-w9Kdhh77xOg$tZH=A3nG"l a~9h#fNJ G&0p܍;}Hl)**">>IQQ8N"}>˭g ,4)..fΜ9EҗuTW(Z("S5dDFFw1M2 fal՝0Y@ɏ/1MٳO EIAAnv7!55KӼOW^D:*"[h68N˩!>>sVaLӤB<i\\v;s ! /" qB*j=$㊳"ryN󑛛K@@aaaRvUUUTVVRWWD8Nʪ!Qxi0KLx蕨-XNeٰlIII -4l 6VhWYNm6jKq:.b‹H{I%jՂLK(lt0uiKh  ӌMgzrś=!ÿӢHuLk?M3Mw;f#<ntt:|?\bP_Ls2 /"c YLYNj`+"v)*pom _LsmS^D.acc K0xbm& #"r^[ClrC3e_t{lʃ&-igxRc*׮>. /"nڸ. "MBf%""" /"""" /QxQxQxQx |>|>vKA®‹t>ۭuOa"QQp 0uO4MH-?S2MS _EFEy^-,t]A>/"Q龡L5:K6fYv[M=.)w‹H}nMχ 44`v?4_SSCMM ^!|K zZ /"" M78xJ$00Hjkk)))p4l -7Jtt4vMlHii)b`Dun\<Ĵ94gۉ&22s‹HKXX4rf#""p^‹H˲p8DGGwȐ6(v{#" /cNj|^Osjffsh\Q=}\no>Rza Zz >Y#ƌkƞu}_^cҸ ;Աw|l-7PT^=bl9%y;Yl[vPˆQaJεY* s {7maky?;r|âpſkG9H ~90:…y Cc8t7JjH#9N:|AAA8N}E^,n'}[0y0ȝ8v-nn¢PqǶo5qs|32R1i4AE{Ykl/agɘf&5VƯr䭿ئrk8wéPhq\+ڃ+y5mw#(+?)w :?ks W+9-nߞ͑crVtREEENW88X1?>>X)JhLԉ  <[.f!L8.=Ϋ#Gc&p>D;;(܋˕*w JHJӂj†^UgzO/w2>?Xv_o\k C_7>c4fyճŏ{g`xA[׶ra{$z*&D }: _`! OZǂmp:z 94xWޣ1rfc!!!vhTGꓖؑL**ٳ0{mCxXH=׉rgOj%}Vm>xlL>ûX<6{x(Ѷ rڱk?nӯٹPK6j%Y-op&147!d|Uf^U)glf=!?|pʮ˘I_ɘHiBe-*f=eƉZ,:.4r`1<#'}o?rǷjiټX/ik8^Ϛ ݘ 'ts xoz">\p+R}-۳dcڝÖ{z\eyGu,d56eQU]KNM°\ ߺh:_gR<|xk7eqIq8c"f7E%rg'-Weȁl6|>k6du;^LLt83s S ʛkAf2L?m gf/mZ:'eQw:hFl ezHs e\ZdpjpiKТ s8-te.񣇰vc&o/)Wc~kHՃY3'1jXy>k{çKֳvc&=1 >pk.w!z&]NG=5/7KH)EJWyLAZDNfw! J3?ݾGy7(-dЀT"ٓ}cNjNk/-d瞃~8_Ļ.}x{3/"#Èg^x9G=b #'{Q׷)(,aMWQ^Q{cNj<~(s}DbB z&xfIM(:Q[xf=(c{־7xؽ+d{ -a-w "" *,ұvnbq%*x<9S&qӨ@6AU3@$tMWhn ]ߤCL֞s S-ډ [W2_/RMPP [eؐ~ NO"**ˬ t^^mYw3<.Cq.v/"+yq à|w؀~p ;dcx辛pNj^^ K7eDFwq`._hWM4[,Z2=Vġ#\;u_}V 3)":2z7>EPGx)=&fWǘq6)|91H;AMу 8;'Xt^ Hg\ce[sAhp%%ӈ줓$w1TtMHcF :gp|]Kk٦ƠTkjyO_k|h2f@)L?d"&:zUlپȈPnn.WCӓfG| Vζ0 1lp_m%lGZDF7`\N2a+"<<'{f_N.}SmDG7|iv"BYSǚDآa91#^d'oOMX_.'6{ZĖFW3Sˎ]^\z`dᕗyP*_dϦ|xs73{:*zJlpJݦ&^|>_n*:|$_iYUEL71#wc)%*"맍{5v0repع)-t{s]QAP,Iu\p/ /ݑ9OlL$Wo0 >N=^Dߴd KwӫgAAg/URV^ERb?@{=Z:ZRZAeu E%<F]}= oշ?'|Ɍ>În;+Yl#WOM3'uE|V!Cԧp7echAaRZQI#A_ e"lt(;!6-S.{0os=rD3x 3o!+6j|ѼBȡx9WpRUU!vqбSCII;cܨ8vG@@GpP Eջ h< r$FwSĊWs0bl(܋Kw=sh>O0 goZ24}Tm84M 9lMKVlM0 4#r6>^iS"6&pƽOٲ,^맍˫=͂pf|uץ18Hwnabꉡ)K!OZ:(QOigd\)eycyJblP$gBF^֜c]_v;DEE1d|] H?kp1M.d4|s,ӿ^vp㟦lV7xyq_)KE[!szGؘH}{-0cQa8vKq{<\xX.**#$X '<,Y i~^{O.'5oNn=:U|i+?{/{ør؍L[>g:Ԓv;nظ♔Á ?-rapJq[.bVr=.aBCC;t555rw51>Es3չI&0I0f{>x Єwf%܋K7sYhAD zG҃9G9rD{ahcߔ ؘDEѷw2aLnaJC^36BtT8 ӥXdw͞?z}))hn!`p8 ǟ˲رIqFG4l(bÁCp=lge8;m0Fr-#~?&S *â$^s7Ӛ=ُ3zr =e&'رf#`˔!1;xZ|'7*Jk1 BOD 'x8"UYV쯎%Z_uXQ\\ѽ73=هٚC nL;ݎ{mHHp`PQUs}}=7xne%ooߜFq^^Ϸ2<S4 p1tP2w`Kf6͝ɭ7L>ɿƨap8l߹u96*QƋ//hhSw{o3^wT\B|{,Zϗ66Iw] Sz4#aS1VV/Yw&E,{w!ˀ w2~HWs4 / BZ+#,Z6QCޣco8C"/iQ__͟a 0, AYY.0iRVVFYYesQAii1H]DFFp3)G_ʊ5HNe /z99mݼS3d$[W@C'r ,4)..fΜ9|䤫4_jkk/Bn(݄TTZZ꯸44!`Wzw4?>̞=Tysx04m/Iyy9555|ΰa&555xN|:Qx0ߠ9|>rss  ,,AjܮJp8Ҽ"""TM;iRRRBqqq,65=l6vtUE!FDE/_W<`v֚ҞD띾/ /"f+scꎰ;kV^%ue /""4`Nr9Zš‹vnZby`zK'~wD\.}!>;|-$w(hC*;}_:DZِ*rw:]jEEҳl:2z']E """ /"""" /"""" /""""""""""""""" /"""" /"""" /"""""""""""Ҍ.( ]UZD:,"in7>O BD:eY|>|>v]Wо~" ."r|>n‹(\ l$BC+[[ѡ4Mi'--j!\aOg?N۟ʋ m5mNqÆV= n͍G)'F u&trۚMg5fYv[KcϷ"Ӗ(ic顥eXi:x5F9l67vOZMj+''4Ցn7UO|>P0tMM 555x^ 0AES7z=Z 9s4OVF,b5!Xpdb^;ߛH\\AAAg{t: $22ZJJJz8U 0"I )oSNhoi[wo44Y,*aYXo2E4. K^/DGGc4FHHRYY0M!FFEkU^‰u<X,jZbu̴VkAjmJYFcaXW_PÑtx"""SZZl\`^DdQ NZuQ^ۙřK2a6\f7=O4"ݰvf#""((tɊK$[ĴX2dV; !rb4w0Zntf/ qE.m, Atttbو:.T\NE߹EʰZxўhbrͦi #Fc梦4O2U_ t\ԣG6qi NLL 8f֑΢A:囸>n7[]e>@j ´LƿLlcvO;m̆i>34)ݑ$(("*/"]*<4nZiu Z4҆ , sg57VYl|iwx?ks W+9-nߞ͑cr+g!UTTʋH^1[Th߆F}so~?TL Mʋu5>=i9-۳ye/wj"qzx|xk7eqIq8c"fZ-ả\?m%9i> VZoR9m4fős ҾK8yJt ̆c觫IN՗&2<#'}o?rǷj̩[g)\+sopx1%88{ҼHLWn/>g`T_5z)9WibVHNcxF㨬b TTVŰ!})賵D2o/ y_cah&**INc@^{.뇥uG6i铖C<[_"1!ry-e􈁌ڟG_ߦ7]e=;^-v( On[UeN}lút覆SOƳ9y&n\(gGGc|aQx,9ơ#\;u_}V 3)":2v|Vn1/u p9r3rGr oLnarU5|[:q8k7ffL0ΤCb԰8 ϵj6|VƐ[lkڗf3a,_‡ װk!݌g?b6v9HbB >w?X΁|9\5ingob zp3H$-M'Ks.x!q$^:9e"7t ! ɞ}ٗxt`zu )Z!ٳpyݓ׌kSZƠ>L?wrbAUTQθQ 2"'E%չ[s4ƍ?蛖f0"?#2SdD-si=drd CYy%NJ蝚w^OߴKkڐ''C:>XVs.Yfd͛PEۦ-+Tcsؼmw-53]4[bԿOOf^}3~Hۋ[nq8QXTJYy%30NP`۪.a`ʪndݦ,9N}χ,53ٻ0}ҒHnU=k?>_tASq;exTԞܙXk)-$88@d8Jm]6DG3j/f -ڊ^55u{K8x8RfPWhZh&)Bqmm:d|>MɧE˒RtSt|kjjܪȹp<|VzGSXTDFq0M>[ˇ ЯOOY1S'`!;ex/0rX:SQYOiJZj";v$Wuz%)(-*5ܣ"wpP\\LPPPUI|>8ڥ*tczw?\A6oCtT83Ü!6:¿oLRYn+VoŴ,Nч0(= CĐA}lV݊ -5[nBtT5/Ƽw-3 ҏ/}/QwF  n`L.HDD(}S5c?αE>|m aP7染!٢9di2Niw 3Nbo3%_9Y-rԲ>IQQ8N"}>˭g ,4)..fΜ9EP[[{i-/ pk5?ij!f|-c6?PZ6! fkofa 2 jKy4M(,,u駭՝θXd[󉍍efʋyYz5oSc`xbqjf#Y4k9W1r)3i:Yh-+*+0uhѷGo3@N'n݄TTZZ.' C /"]/s1XF+57*V`2dѶih4;͹Yh_yikkrzJwZoKIyy9555|*iPXX9‹H /-rK q`,f5f6nZz:rRyi^ vJ?!F 󑛛K@@aaaRvUUUTVVRWWSQx*.MEVe-c4])4Ҭ ӎAv3U[hViiYi%8^Z{Ӽm͛n6?ٰlIII -4lv\.iUS~(\۹::>B`fuZ47N3>K3%z]3SsiIFkQllaZDE#s]Pɦ")4;n-\y95ش[]R@EVv6m_Ei .MrՎҎ 4NM%N= i"9Zu9 ȅet E‹Y|va4ܼVL,4S[M^03&voR uҚ+H -]yy`Qxi7˅>c1N=Uul\Y=Mfg jcHi)BOShqzљkaYhi,FNsο")a?~qZi[.3ݼJᯂXu`N5VI40^(Sm^.E\^Dm1MJ_!;| ƙAfL"W8uUxx6MGE""]uE """ /"""" /"""" /""""""""""""""" /"""" /"""" /"""""""tm#VvaF:tCiv D0˲||>v."""݇vW.nyv+-jF[-= &%kEz3 /" ." 00Wx}v`͎&(LV8Xn]& vĄz65K+'4\D:ƾbath1M}`w /""^P b !00R*++)ttɫtba'­/‹\x"""FSZZl\:2z-puZKvED伃%,,켃gdAxx8^[ʋ\2ir1jj'Y[fK/@1130>+\p, Attt\_fEMM?tt‹‹yxbro~K Qmrsه+z >ٸ"ڈ GB4S& gjA]. Xys{g]Vߣ3W&KRet j\:<(GZtpC_I B4 A}^:I$397]͘o|oyj-og.7Qykk%+߬ 9ks W=+۷geUg15| K5<<= n% ?%pxF|}4>]JӹwLOcʄa{3 [YǫJkjf/ZSx9^ V+1_a:BnX}ir.3yyW#pyy|{~6wG*֜\ş]- 5~?~~ ' sނ{MrɎTVʒ ~?/,!o G||%<\NɿFŵSGVo?@ɿ^k3z&¡#ys"C7j0)=؝}{!</y'(*.#5{t޷ߤCL֞s S-62'J*xoQV^ɀ~HH`%+6>0 agɊ͔WѼBv^rّ>ύE`D -bxF:{>zn{>FpqZ^2C`@MW3=' 8lo}o^:VT7ERb5uٞyMKf]TVoI#zn!`[~Ry iؔVnc`Tfc\9DGPSSG5RW)>QvrЛ4:o݈WQ>)҄ J1<=n[O~sS:7m5 ٨$Ky%Om{0&1#ȡۈzlt>IQN>0寠L~ l߃P݉ noxO% G|(-'WMNDx4MO_XBjJ"Bw зWXa*-7Nm()`a=<,>\Nn>Y3'[^/l7=<<6oݦ)}^nG6w oւi5zMms|hEc8tTPR7j0ݿre-dΡ 21M 9QRΧK6x1#q! "]ͷ!B^lܺcyE>DTd=IC+bϾЯOC02JkB6vsl,TN /I L:SIUo]l6yܪyCcs4ᥪCFP팆1^~?+4u*Il}k~ÙGrPxL\6p̹sV$b#Ʃ<׷Xz+Æc،y#2z@nI&((A}XaqKxh}S0M=9'.6 Nǎv{p5k9^p:7 q8x$c1X\F[FL9ko&3 0jnnSYYITTCMmg .iRUUա#멩P_9c!Y)_c=?kg9 cwޢK0(=ϖnws^-;wTo.dO!gOZU5ZԞ ԇϷ{g#*";S^QOHzİk8FLxhiYvva*,4﹑?>&zmVAxX0r((*aI> 5x&~3lH_kuzE]{W?2-b#ZtrRibVmc&]WapP\\LPPPUI|>8=K3f@ټJVNZD;1@ƽ|tG%00qqIlL$Qa|l#[vdSYYCrR>-xi1H]DFFЦ/?p3)=Xr36e҃/?p3ti?4II+y}]Y Wo.rY0 z>*iRTTD}}=NS:wūJr=2;|i3gΜ _.g^ضk,4F'3I̚N }:ZCi.Oddy4)++\l6aZ9"{<WhZ*siMd2{nRE#c6MbNPHPfn-s:vkwRSSQii?4/Tà4", 6 /"t$">x- g4Mjjj(,,ϥ @b(TE‹#1\-aƿCq8|@XX-4]UUp8y3Qg4ONrsuε֗IEDD.V`9ffa&%%%ofaq\-{jpPwXlK0M_v}^DڿAtu4v'FkQllaZ&?˿3}p;zk?dhF}Rx96S.'r9 4_kr~6a/ c*p] O-z é/V{Z"h@,v4\?g4BMB{Vdscy|,˼xc {V ."H$]EoA5bձWBs05`rim rp 0"PοYGqtiTaXQxR4M^sZ8 (\l6DD6Z@DDD^DDDD^DDDD^DDDDEDDDDEDDDDEDDD^DDDD^DDDD^DDDDEDDDF"ЅE6]QEDq|>-.̲,|>>ݮ *(Hp`K`mJVˀ`A0II>d‹L;4^i`c: j->yu=<1M /"4M y>0૟ E3c<ײj9X̋(r^.r} vp_Ї"r~LBR;eY ƂK3y;^(N2vX6ǥR.}n /"""g.]ac1u?m/-1bUX }NJհW"""ҺZ.`بٺl$""WؽM]O˘磨H K[ ٹ'PmfP|4̶\ꂯI^|>VmaUy䋳mԻ=cއy c@lt ny'-' aZ"r&9:L. Gv;^D#FPPIյu$E ˣ Qa5{ZJE V|Mr-š#lj OZ2nec{~l&!zٗKBޓ7NGhH.ɏtF&ӖImm=;v 5%A%RQxJ+y/[W2 Jdx>jjڞpsqK][C%w>}^Cm&BAy&QxV΁ǘy# q|Y-7M52Y|GƔ Ùu$COWF{K/fUYf5uXW]5o|y.?\k.{n&Ky׻Yy'w= Ϗ}?Ys_^cܨ|wa4˲غ#O'p. 웮"!.˲ڝ5[ٟKEe5)=kKW}N}[pcک>p>ZI#\ ]Ktd8'x_cLb"evLk70$^p{hX`Ce8PpO`g1|}0M)Յ-dv{xiG,]921K972揅Ŋ5[)*.#91F@+7̼f,h1D+l%G, G| UW%2"xٰӴꃷD2o/ y0"?kɔ pIk@-\WLN}uس0?$Es4s,8|4_ED:O}ao-,5AHynPFN_2Txj(,*%<4sNzʍ3&򅻮+1#?[}sgr S|< M[vxIDG*!6f#ok,>]>I<{m %pؙ4~(qQ6VƳʵ27cF$$8H7_6Poir0&'2+?޹327s#i2tp_}D*/h6:r&Q+z=Ȧ]4H]w{x\9])@2E2=xL=q8pLn52)MHpё5E&2"'E%՝}[vQY]ƴ8=wj"1ɥލ5dsHK;~~ >,z@SuPV|rK`A6jM;0-\*.'vۋSkk(,*V9uNP@M~ B3VVհvc&6eqq=x}>^Y)L"^O&Oi%"^ZY| 'o_I<}_‰HTrš#yqim6v;АARK~[fr&ox9ջ^:sntrSHx4-yp95Z^ /LPP#2g!m"o/p  $!.e$'3x@y=i%p K8vĸӦo,n;0 z%dzvc&!!AL/tYtn<^={xf|qe<›|p 6qx>x%5V.ʶ *` P[Wa#dܨL>[KyS\RNn^!UյVHpPg8zk t۩o=b !,ZSYUPr{<,^K7v{E ]GTyb#x97"DZJ"uɥ!.6 Ӵ?fp agTTǿH\Z b|j^|y}Ӓ&]{zHa<6/n۳#=ziع^=8p9%1>Ԕ_^@XH021f@;}Owƌ@Td8GgϮ=ǫa11P_6(}{''eڝC JOc̉ ү! \AZj"0嬧=71 ٳ[vqG l\<:/KWna杄2n ftQ|틷1El&Æ wK~,/o|DЧgѤ$'؞z8r5}SHNc`TL$%9^_29ʋ. u``4M3gY;i]q咨BLO;ڵ^\p4?>̞=Ty+Fà4"]>- KvED䊑 L_kvQEDD(stCw)n}0ʋ\1jebK,"~-reC O!&hW"r>+Mȕ.ϧ2!ŎU_ZꪘϧIE8%r9p:}@'U&Xz,2;2S>7 52BgE tL;>ڞE+*FDH 0oU8^ 5,iSoa .W>4 rp 0"4\v{Z KaY5pantHEDFDu^5 + /"]*4M.Kh\ fp8^EDDD6Z@DDD^DDDD^DDDD^DDDDEDDDDEDDDDEDDD^DDDD^DDDD^DDDDEDDDF"ЅEb /"v DCYau '""vkA((‹4M$4M-zZ"‹H#GE["‹‹‹(t]ֱr6gԒkr8v-$Hnz->Ndx()=ps~̫}tcx뽥eҸ׻tzlȤĄ4Wtϒf o7_ʃM_^#/o?r'ogԻ= JOۦ5̚9맍0 }""rIncˎ0ul,,Vʳ$%QRV WIҼy79ך_xٴe7z$91 wy6mñElۣܲYDD.9U^:2QT\FxX01z;[nf4M^z#v=-7LᾹ3=,Z>[=8jYpQ{L,շWr9L` 5u`kּlPTy@a!A! KodN:/|4_%+?#Y먩c̈ |o @l"#Csx7yU\ީr$ IL!:*m̽Z2^ #g]ܗ>Y'|d8J\l$%Ϳ;HJeN.c~0}nWZm{ػ?EDDr҃?UL9Ø~h"#9~xZmb${nkj$&ͯ󗐹<|M^?mv8;ۦq SDNFK"F y~] C""H;^`e&̙3炿ۗiݬ=9<4 Mkv|Z"rv\K3i̟?XfϞmvx"8*Bȥt9^E|V͗s(v]F /"r)E .SJv~ `ED\^D]1M׋i: ID:al6:v"al6DD6Z@DDD^DDDD^DDDD^DDDDEDDDDEDDDDEDDD^DDDD^DDDD^DDDDEDDDF"ЅEŒ /"v DCYau '""vkA((‹4M$4M-zZ"‹H#GE["‹‹K7VPX–{)*.n7O†-0DD䊡tBo5mD#!)3upIEe5{o|MY|{B<^/rr=V׫ADDD^:IZD=ṗfC&k7fr m룦N TDDDr=39x8jĎ8z@ aʵ+PS[eY|`UƗ綘Uu+9fOcxFoO0kD60HQӵsv;%,`Dq=$sݴqYWq1a<- xaa ۋyŷ!i/bݸ}""mrֱz(O+oZ2alڲMM":*|-"4$蛖eY'|Zv:@$\.'>Ԟ LA@K(HKK1-ҲJ2wI2f FMoamD/(EeMK>lӯ0 N0?]$z&i݁C8pXéᡤ$s1n`;P5ٟ˲[ڝCQqeb_et`CDDD Zn~s!VoaҸ RSzXt>:㊈‹t붱p=97_}ƳCDDDZFȱXDEKIYGvu|Gr x%3DDD+U^.A|t|lّM}EА ŗ7-PnnR[ ټm{GyStK\"cF k_Mhp ox ;/7Ea̞u3Kn^!7져]q]N'#èp9YOADD۟n̬m XiR\\̜9s.K/Օvv;.ץ4MϟOll,g6;t(˲||>v.zD\D"|n-QQxB""$"~^W ADQx>t#"(t+:ZDQxQxQx.">߾eZ"""]߲[_a[>- :IuMKVn&sò`4fϺDDD^#<׷8t8QaIKͶ}lͤqCDDD^.J{i>yNjkqE "" /o8x׌ۮnKKj1i߼ϖm|B5,97_MxX]3rIIJrh>=i9-۳ye/wj"qz1h%?/(OPV^ɀLXtu w\GlL,Y;pX!.&ܛ!88Ǔyb_`պm,_zHほn 1!r((*ر0,iʛkAf2NDDE.D]-d-Kk/)-HbB  Di.|{HMbѲMTTVǀ~ع ]Kglz%'-هx"(Ի)) _/Bٖ¢Rz$D(R\Rƪu۩oK` ~?/,!o G||%<*r~W%o elܲ*Qz J*4 pd"l}+*ٴu'؞OEDDE.TUU EundɊ ԇ>z7a,^C^}k!^\'}i6 ,'|p ⻏͈|&s>+lcמ-‹gb?BjJjjMBC 1TTV'\/oZ2Q|H")1h^f{~7dgë( $ &bA޻nquoյwQ, "%$RH;uGBAUr]p=gwIK;$>6廊d7yY46yTr-3vD_ ܅[>/1!{n@q.ƎהN> `ˁ8ne\6Π~a\D}uKVlhNr2;諶kw1-ص{4\M[OQ#>wŚͼ,jjcҘ,)!o9==/Cf:>A1M!Se^/~;RYU5$&quS@rE "|fI6JJCyy䟯һ{g;Qxk+U Sس _ MW_t0 M`""W.c[~}|"n(fm\z wa8smWŴh5Q՟ ',sEߞ]yYҹ'cG#9)eŚ$&r$'ёamkl6­,"rz=+ie6LbIEE&M:DD`&~_ !"gʶ5i2yd8qySi9EDN7ݮdr`D˥PxQ %I(4M$"al6*~6M{E""j&QxQxQxQx9to#,:,"cYn("'0 ncQQQQx9}-`E䔘I84Mjjjp\DDDa^DN]}}=>׫""fkS0XEdddSM ҤGdd1vH|> jʋM%]χ9+n7~ǣjkk@D9֪1^DNeY ."r76 /"''+W^BE;; /"mEDCgI">.i-ﭨ"::ۥFjָ MߎO^Şϟ'1pwA=gqJlgQѿJe?xs0k6mK QH\vQ#"" /r(ܲG*{0 Z3/Ovw+B8< ^ʲXAa[,n8fÀA LBH1?摿Σ*?W^ofO}_o[KED^kۿ_'6CKϛII'59vi#AC:6,gYm"G chܗ '4,hE~tEF0LYٛ"rc{^^I2R)}0ڹy5=sxhOFjH|ؓN;JU7b"rwij{jx/&)+C r蔕]7_~U.r'k[؋;Gb2Q" c[zww<~p+)I-´H~^G;Uc)\X*󋇟&}nvo?6p/kMdlYλfca @L&B^n SHzwe#>_ >L˂%koSǶtlvxY~ z%zffpX:)Qe'q\2v ~pFzh6b_ab#ŏ$'';oYlY Zƥ4gܖ[Mɶ qXL֏>m\]eOe .a+~trSt5c,}xUG_ /;noiM# /畍%ӵsKJ`< w<iycu6skII{lms|b5͜(Y=(MrRSg,`kKa.s2$q `wKTD-UK?-SE^ş{nS/OnvRyx'ϾAmA qs\;q4.{_cbjjHar^~s.~F쯭'ɬyeo]rVЌϗK7r9`weU'ɵL<| ,~E=fԲqb>>:]E:]t[e}FSpQx9mY=6zx#KZJ"ٴ'CRbe{*k$!.%+6PY]e%}{ ,XÀ 8t 5o S8D\l6D'p, (hd"q8씕0]EMuu-@I|\4^9Yq<\E]cc#$s{v#nh4WpE Lqb@aM?N絷WU[Gӣm>'>ap1MӲ0M1 ̣""CÞ&-E;(Sa6I$Ŝyv 3lrZ%iX=TSSG ny|I)d9,֖lOʡŪggI aG{21]I=qRjM1Δv[wQK"rLߞ]g~k+8"ű¼e{J[-" cYiqF}a:+sL>dSa5<ʏ /F|6󜄷,aj-τZ7ֆJX㬯ұDX5-8dl-3''Ժ&"șl&bv1zHJ|oe{*46]^"91_OC3N7Ejre|32wons~X_u+w|̧O=CQA.yN{tMq;_A9H'£3S<>Yg\yO_2"" /r&مO>[y+Ч+ڶ{`P|V+bEtiJ@֝崧}fvmYb# a?d"5՛Yd-ߺk}U]Sgs.#_q>gjot\;_'25qɘ|2#`wL_wTJ$;gևT"Ҿ(+xmӓ; }V &]>ޞ,h:Uzb? Н-;t2~StܑʪV)$11iÕh.^}{6n%9)M%ڽi>gsAtT2n1}^) |%Jy·E3pU p"=UO濧r {$~2LT#(;v@ܖkH*bPr:fP -k4lۮ ?/i33oj"7?/N\ltfgɛ}ƆM[Q9~Nk;*ȥk\[ȶeG׀>]ڹ2R$66//vREDl4 ڕLbIEE&M:ryR>S>{ yM& MvW S(*Ofz|ZYYa:GDߏeY$$|54Mɓ'ĉϛ */rֳp:RSZ6pNp낯Bdd$uuuBnm "raL$22R"v+xw֥#ITW26kѱ]W>. ÁSG""gv"ԏaΛ.#C>'J(&)1vӱ}sbZ P__QFDΈp8rz5c /"b |tz99*+6 ˲x< . /"tTb,RpS0a`q::T"rf:t _DDD^DDDD^DDDD^DDDDEDDDDEDDDDEDDD^DDDD^DDDD^DDDeYaYo$"ATTm"rz544[:ۍͦ"<4 ØIMM .5‹ȩzXD䴱l-}J8˲TL{ D444Tp3n磡A rTyx<""gxtZ"@mm-v]5Z5‹ȉ,KEDFfSWEaJK8VC(|'rΆj5؉WRe; 3?/}ƪj5\‹9\.Zۃ?{֗>vL l {㳅+\ϹJg]@n(fŚG 7xx/LDDE7[vsIZ }Ȏ\?sqQx2 l6"&2t@wF MDG %F0BU p:'(r2ЧeQW?bb"`sal`"6mAQAZV'F^>! Xæp E2޷cds*Xy';1ƃkߌ!0v0gBN-<730vJ˨Ң<<$%|ž|tP)?23Rt76y_bu!6ӿwW5yˢj[`RiOlkycr, at7RtVnM\#_oһ{.{y~[IIoyn_e E:ݱKiƪE44Z[%7PmI.걤$kyoVLUu-mS;/Ctn?tJK5Lnv& >>> WS$ (`~x.֬ŸkEJR<3>_֒R=cG8t3>_ʦv#91q0zXæ˲,Vǟ.ELl8 -!o_}5dI撱/n!_3[G,Fu7ENd͓56ŃXG w0rR{|dkf bnC`_ϫ.։t#R5vXV`hjN:c_:s,xcU0[{ v0_seK0܅J7/!Y&v'88 'v"eY<<-$ųj?=yYq%-Gk91:U,ihQ\RJŤԦP'}=;jz)+_[=ɠ~46xᵩ~w>쭨Λ.#7;P(};Nf.=ޘ)KWl8`{²g~.kxxBM[d0_> >?ϼ8?wp??ODrzݡ-?' SQY"oMDƌaSo[3F`p#.6vX#Dpfog5r(ͭordԃÓ@ZLw#7pteArN c- GCdPEmlh}1 >=rcp;?" rKNhgKTy9g,eBvUp1tl;W\2G s i+2mbV)d̈444Bţ`@=UdI9C0o7p핣/jV-CtuU-co*ugDrWLފ* ̞۩:[wM"?/Jv{V3jX"Xt-m7T!SITÀwޟŖ;杓>gKed% D5X}Y_ǂlRF {:{u`Όh#zfgg!ENS[>O=u.} ҈?fjQw/ErLJGyӏ/hќDkaYG_࢑q . /篍%l,,9챴DniqࢊYh@[(@awɈZV yb.3lP.xH{Qc Wa'!>ؾ sڵ?9)>=9l(,!S;\.gK0: &6:Zjkq[ ㇶԔC;{+YӳI~^Wmb箽 /_3)g5/CVD0q(F_Jg~6ŇΕύt-5s!?Ss[h&ٰjggxɹJ7E7C`|ʕfÆ.GdD6Bȡѵs{r~=}5tc|0mϾqu[ƃ+Xr#JbZI l# ># 6mcƭB!Ғp9USJyq ?oGh)ITTTVXzsbTbYA01@ٞ}DFxh|*S[@JnoxnOhs39'xIBvOE y5ߓĴdV;+1sO8ܮuñڠzo duO񦦒fDU(jUiU{N(\""՟ei Oh^%C6ȌTGvB>Xy\ܦyPpc9 k8F6]3|2mXF^"4"" / q1|k֔7k>=Чg/^ÿSa]AfaޙAaN~YTijez=$P]6=i!&:`(D.I9|1tu2{yǀvNnbΆ:l3+ZSO,63zd6֠b>o؃[n*ᑗ?Ur@'2\ >e9 K/-Z"cw" #;n;kywBl9ry`m<l[Z)rkɨrر|@}YW"6&6)$%1Z011YW}Շc#<gĐ^l.Μx{l &-mL|;wa򇟳~Vj]mӓQ|(4[}{z#-îaxC "trqED|5+=g\ǎվ7 i#{ySw;Ƅۓq돻qVwfAQXDFx.6?G -錙6|kx,]Ԕx˧[^>k6}߼MEi7_:i)\>n0Ͼ}4o/~'-f6жM2ߺkCޞ9dge`Z|v`#ZƞUf̚ /?F,Yâ ߾* e3sr.]Gdxp""5>áIPEÃ^o%x<|\.^6Rxӡk6/W_v\-hApDDNiI8Ʋ,n7. ˥Qx95^N t8֋9PYlXQpQx9\.NcYr1 ݎԡ"3hHDܤ""""""""""""""" /"""" /"""" /"""""""""""""""'@(,ˢ˲t#9%0 to#ӫѸnl6)E䙦I84Mjjjp\DDDa^DN]}}=>׫""fkS0XEdddSM ҤGdd1vH|> jʋM%]χ9+n7~ǣjkk@D9֪1^DNeY ."r76 /"''+W^BE;; /"mEDCg'()վ /^ǴOa7zK HDD^pX%0cR\N#Vx`08E2 M"hL4Ig}yթEsv-(TT'}#W}o5NYj0GV6хںzveּ|:{)Icq8^hlzgCQ1c6YtQ%e byZ@$;u߰ ɉAao]ɴYY[ucܘtn*aɢ-ɦux37j$J)殹9$Mn+yXGv2K=l,|ed*oMUD2y=|\VT5l? PTa!}1O1-=KKhFWHˠ{A\>$F(_nbv;2`ToSC#VwYR>$V^|į3,{@%n[´1wc$eرL蓌?joC_һ{.{y~[IIoyn_e E:ݱKҡ]:7\5;yx$EsEڴB1]w1yI=FUx6|;=iOk ;Fv[K%꧓k>|&{o; ۇ`9f̓VgBO)Jw2ٱr%<wwb¬}Yi߳3}ij}﹁]ټ!6ٷ#ynm;r0Q,| \[Ə]yϸF6 H4Fuf>{]c^059 -| ,:ߒGX l|UqVZGSW? 2k+Fq1};ɟrϭWЫ '3lͻ&.[OMn09/>c-`}{H?;.h`Mbc7mi8?P:4W.SAmTRSH-SEr"kh_Ǣk);d'n 5w̔3Y6F%XUkxUTGzsO0GlZԋG%}̟pI +6mO[%mCf^̡9\сp6VF(~d69&]ړ Vd`Bh쀿4~_ku۪պFW}0 n",,+wz}zp˵q_:U,jFvb` /Lϼa}i̛OMh+3?ar:ipUcTΜ6s˳ڽ{н[6 _Vz/? /aoݕؘ(Lm56Yn qet6~6Jv} ҿs+10:y`Dn vآHwuX]iؘzX?50-BWB`p01'wasvʣOsp0"2<0{[j0ٳj= ݣeLϢgMAG4I,\jNQM:-XO#qCrFbnY-Ϧk)'1m .O:yt̥ֆv \^mȅ`nv=;G_G~'U^.<.DV/l> V3k .;[e0>ff}1}{u9/YKzZ"W]>eMR|w&DtTq}y䟯0s2n׶e<ʇ$%qmZ>5׫{y,Z;U }({N$'Ƒm7\itJYSFPt~th.&Fr/___^\6s@%A,G6msƖgϖM,Z5lb,0B`s%&>{({[>y|r!ʏ25~Zipst. ^wF$ Քa6=:+(\>?@K0jhꖗ{S簱T{Z 8:O')18_xP(}]GZJ OߐYl GNl6n؂_.a1ϑʎg`sij'.$tǶ+>}1R %e >fͧ}'28r,Ǔ<[ܚ)nb.Gtlآ~ M= o" 6@|7pl 6J:su̚{)Ha,no2Õ*N̳N q!}˫ Lߞ] /.0PCc={?Sy/4ٵ{/PǞ|Ǟ|xnBal#?ȋOeSvڦ'sR%2X}Udպ"㾒SˏQ%>`~,W0pDѡ0՟gޞHkWFIy>:)/⺟e_fU(-)#d8i ;)8]4zR9K66X$!'Wewx<ϣm;Tp$t /KRMr=5&{nl A+8YΤk<:3َN!" /: \Ni)l6v1xEDEFۤ%=xnr:⒡th~kbzRuHlۼv"# ۍWߞ tl߆eٙsoA:384?X9|gt1zH XCNN.M 6%fzO]{Ӧr'!:L#胫N;f7\Y>?7@J>{1(iJ{?fuK{0\"@UGjs3u4Ud۵{!% > H^)=In0 a""\`Dӽ̚[Ĉ;ckzMea1[x;(py!-i `&+ Qx9_lVʖmHKI}f*^ T쫦mz ];whg{C)_H/x05\7 VѷW rOx‡tFݴĎS;0 n-y/+ɠ<*\úKG'W=$98w)ev?;r=1GY-)cw{1/Ϻb랈QQe}I|d.eyg]g9^F Υ},/ʼE\݃hO=ڌ IXuK1f[|rC~UQ^mIt(+]O/ h_\ʋs WVrq{`|g0㡢ud:XsyOu+i׊FWb4,BN j6mk˲hhh //'p::K-o.ΓϿGuMW_1,l6ehzk#lYu -Mbޢդ&2_>vﭭo`Uxn/hduD׳}g9ݻf2u 8q_ٜDG&>6D.Y;;P}QZuEUex`.x'ڦ744`[d)Gb};tfk sz1ilm\euc`GYb n߃oǐ6gnҺug`;'}e_YHQv=sU؉iMFJ7lK-aSA1pXۙ5_g+ֱxkԮ =Љ7%}҈hnIёؑ=qVez(.=_{9z%4]p{KYbw6Ja(zndm,T=% 7&fFz3zh{b ;Yham.m02KY\݆#~mu\Vp5XB1YIњe@*i)ș&P-bƍDDDХKߜ7B8Δ)S,4`ҤIg==@̴+ص;L+.ʵWn9' Ә"R=Φ6NrR<[KJ=Λ.o.~oc?=3o7##߉=0s2{C\N'}{v&>.Xw =sq9ClL$e{3yY\s(bPUwL?oW)˴wn<*++q88o15_a_7pO^MWЄB!B _Yxn[qtHR >>>},ZOaxMsU`lmp~\ϸS\`0>˅U_E7Ux uu ԓ&>Umr9 l-""'4ML$cYn˅R(&M }{x^v;@n[/"'@eGEEr\8ΖJeY ."r͝N)F{E""&QxQxQxQxQx9n(r'$J5‹o8P uh.jGOW^ qDNyQxQxiSENa^QZB7b6*/"_#E8/P*/"bhl _(Z ew`%NoG0;c"tK}E?J JD^DpC`ḧhe8oƱjySwtVVUc2Z8"""GrziKH1>3-"_~o36MB!-Qxֱ\ވz/E3q.m{|:΍!'1iU0̚klUy^C¾eF8L/ XQ~peq.gT%q 0j"KZ6)wb%12֍x>y rқZfяP|_GĔb߼WY~N(za[7R7Q+q%Oo#Jć/c۳[@pHE 9AP, `߲G~k|]z7[vs3Dxߐ`D/>yNFe@(7 n1c ''|Q7b̔x?zyӈ|1 )(ef^8 v7`^%?VQvD7:w'[@@`eZrۋgfNhhtWXAǯظ`yn/7~pێM[WTٱo/"⣗ ϡaE4u\COwm74?Vp5ږϰƨ!9yv|c&ͮ*/"rt͎C8}F컶:3.pNKK0W~fFCM0*컷y&ǽ|' HXU=T± hoX,pu%t٘ )8mjj8ږ`& ]K6= Z+*P'5fC/QpQEDZ9X`w`S a'&=G /*ʈGnOc_9*b~lG{݁;?y䕘`wbD>g"D@8|p>QqG|O \+XPnCF%0;t&K:,$‹׀ձ 'v `a{92XIiG0 p^V|c/l`cF6̈##k%Rwϰ(dܳ?3c&IpeMt8j‡T ecjgw#s* ؋b`8]ƓQx0!\gC8L 7I8-ÉeZz ²;G$̨Ppn zmy"ҰU!I()ى;~}D>{ إlVD4Nͬ=p/}G 1v?m "gƼO!ܮ^C6:sk&_ᇌP<0cv뇭|'?C En?X'1!<8ea}^, džU{NKJ[6XFO`ft,1ƨ=1Ëa14q-d3nX )4"ʋ|Q{GWݍc_6Ʋ4!?ܟq'zuKMFq-A8=Vd4Q'o,ZK0+Fs ̴L Mcg\K>k /5gH_~@[_,gz]8Cwc35kJ85\.7$o%8SwuӺNBmq-ᤱ*T'3"""_N||eE82 rƹcjioܸφIm>hض U+ GFc&P_!+:`.F^r5}GZ& 7|G/^) bqr{!31NBYL:s-ӛ֎wqŶjV|2_ԕ|Qqf M32iynK+*P׾ط58O|D+-˺fhʔ)iTTT0i$ ؝E)\rGUeC)i2yd8qyӘ9(‹‹‹(A΋Xі-S u^""r>q?$'TC(ta2Kc^DDDDEDDDDEDDDDEDDD^DDDD^DDDD^DDDDEDDDDEDDDDEDDD^DDDD^DDDD^D+QU_ "Lw>G(" aYeQk0 pp8x<M*;ol0_j֢!dahˀAZ6a˳ȍ+|fSJL$x^nYiB7 1\Z/kS4Z&[Zc&7tu@?N#+|茶׫"lu!SWWeYx<\$0^`޼.a^]<=k`^'22R!rvH[gC ,( `tH A(B7Sx:ihh!D؈:c`6Wyueqzye]fl6 \8444Jk 9*."c_gUY( 0ݻˎiu1oPk^"{xg;Jk-,]-NimMfe"rLb-p鐑 M'ȹޘ:h$r? /"rnwگQx'10x5js*/"V;a+ԢQhQxӿ)߰K(,*;i9 5pD=ŀl-kBT ‹\ЂX{^%D%97 l۴[ϲnƶs&;tCL3FgF50k~o_ӃBBY?s1{$):sH\;q_ך/pPhݵ(*\7?wnI$G ]Ǎ= f;׬fbW nݙpy?rm-h_׿Kplޟ-u^+1}|>slgsEjv ͫl=L_򍻩H&/'+ ëpϋ^X[&= U\_0䃇>9:7!/F@U%̘? >ʑ\رφC{u3aRy3Bu'<9^ײQz91:HNIڵV@q#p#k^=e݇y.ϝC}F.jV}R'+Y?=݇ XszGLe\cFvM^,g&V~oRpY8*MW`c]wzv0D;A1^;v}M=0*wL_M̆Co˲! ]#`F^GZ6OK'iYP](-GG4/XqVGMidDt`6&Cx{cztx|*OZF5}ZZ,'McͣOijЕn)v71wm7u?2bp.caV-jd $$ٰocݤKǫ%|n5izv?Zdg@̂V@K@Ad$AṬ,Fv @jx+x}adCB"os߆|D9[_CT+On~wƴžs=}F&y Wwq6/g^ ݽX[SW:a7gȁ YcX:;U\Ia:k@n Օ¿^K~:^.G ͅGC /<2ep+{@^$,ީ#'|]dʔ)iTTT0i$ u***/BדWU'>.կO (5ȉԱ{V4M&OLRR'Ns[ e[O?3 XܚX(:^Tyj0 #f؈i՛N'n2-r>{KAM]C& n2-rLFn7)Hm}]͆aUyj?PIٵkWR__ ȗT\[˙kȠvvԁRfu δZ/wu`'W0TIٺu+˥\.v;^`0H   g\pi A^/uV?K%߄p+ ,S ̦ p[ L^([t:O҅xhaaeY'|ZI0IJ,,K00 ݎfk -g+#%W6ZhhAz k禼S \. }FCCeѼ͜vŖe7 cHDD6l_~'<\.N`0i .`NWvAGE AaKzٲ^Njܰa8n@?!.R뉌<0 \.+r}^ȩ8 Ǽl4 (/_=4,/_NTTallf*&lw pP]]Mii(""WZZJuu50y!eaDGGdjkk`DDkk,Yh x~`۩CBw Xdو?+""_;~ٳgf[tS6:`06~өoRFDD.uuu|'x^vmc!Ks$kp09N"##1ceee5Ͳ,ʘ1cQQQ8eĽ_^*[010v;qqq,^ Ua c,^8vSa m&r h4 albccgԩ^ϧ_,ˢիW3uTd5o}_<\W=K øvr ܽ{uVv;rp8v ""rN Äa~?eeel޼p8!!!aA^عWx9 @xx0^3Բ.[nmq˲pX7esfn vGEEm4 caS zvB /<+"""UhS‹‹‹(((‹‹‹(((‹‹‹(((‹‹‹(((‹‹‹(((‹‹‹(((‹‹‹(((‹‹‹(((‹‹‹(((‹‹‹(((‹‹‹(((‹9u"|IENDB`deepin-terminal-5.9.51+dfsg/src/assets/deepin-terminal/terminal/en_US/fig/deletessh.png000066400000000000000000001142721475472654300310640ustar00rootroot00000000000000PNG  IHDR5m^ pHYs+ IDATxw\eيVpѺ;uowk~~oZjkVk8Q@ \rw? @'O>QQQB}ȶBu4!f!f!f!f!f!f!f!f!f!f!f!f!f!fȍx W\uշ!ՇQm]7Z+8snQ_/EV.R>:RGM&nQ;n}G(EB}Tf݇/-{:l"a{W{|5U]7. (P1j ɋ<`-bEM~"ȺٛbsƓ;מ4<͈{)$8{A_񕡱]v5ɩn9 TٓV:w5)0XQp˹wCG8tqb<ҋǜ[KO}zބ 7~5gjuJJD8/aG8wZ$5aDrt.?kos m(Ǣ7cttQ!}Eo1pT}4>ts8rĤ{&t1Ӈ|~gY08b7W>8EWsʶ{eFz; n=/659Z) '8ooC0-~қ+swOUݯ}?剏͹+)W9a^Z뤢z &x\UaR~=BTpLؙ/hb.R ύt}?#O eުcCl6S0XQSgem]9 <§}; 1Y?fGXPpr[<Ҏ2xٓy*pU'Rw2!2ůq+$͘90s-z_31G;'g-<ϭ?et[J'%>}#͚#$u3ztGe^͒}tTޱ}ƣZ ֎&[o?U*kW1䖕N]<+n/Zl?V#DA=gUϗvd׎Vh&uM\_e+۸9Cɾ!L$! ;~z1G{tl幝/3@$&DRȖd|euzom.cEMbytWJW*.i[-%=h){]-e$H=rX>r)qٴ첚v%[':Jܳw7INArNpә,$|ZkdR指3N1P;V4$({B[LܹjAکSL6K٪!4 .*2!sqHu_zf=5|ޤ~ 8P8T@HO{htB@RB*G6_tp^Q3?xt;OL,H74qĻ)wfhqͅ-V4TgSZ-[p~3V`(1ΖO$F=(f](8;% 5^kptA4ܙ_wd,ݘQz`z)3dgJt﫩fު#;[Ŋn/ؕJ,<;KGX6|`8 IU_7e)4T Wj/޼W~;k3x肦`JG֕[BUke;yω%2PɷھyU6!W xxTb ipp۬#̙-D\/vW&'xX7Vvkz+N  KeפFά4 _^y$J;sso #LV|ѐ2hLNR]'s0~ILJ7rƂ;'Txa*o?~΋y鉢5]{WMϨ`" ypTɁBV3O~ ~,`ʢ]eH<Կ_gg׽~AJ8Iy⧟_Q͟zEYӖhי!O| ձ_ om>s*ñIJgg/;4Oৣ/[JHdqd-[p}p((~i(`jA!exڼ7~:%:sL`+;_ްnŤ;~)eDWkQg.rL~Ɣ~K L/fUd%fKɹmp-?e_lw+ E[b(GYtUUE]=UrCm;/R+3tƲiGa!@eߜҪc5'-MNC\*P$Ԛ3>"Ir`Wiё"٨@~ًfv":6Ӫ?2e샩†JzD/{aWt<廗/x*Lzt7 QB1裸3U<.߮:d(bN1UyW2\>~l` b<*ߓ%LIԡk_/lzj(-pA) k2 UTс/@+p,g1<9.M_k82?^ JglqVW%j齵5^yV!?{c~ʣ3N. _N|9\ @jt!}L^E /:\ H^Ի!_GmqR fc믺ʴ Oݣ]&*q]&E)dYH#áj֏d!q?g9B3($19Y0d\Nnmqab9^qܣsTY'QPiV $Vsef$^KsLqB,7uj8zp6 Vmä)\#JAr~a&%͗Kq}t.Ń YA2oT\HSS4p2;t0ӐyCf.+ޑz&36AqjUo): 6wNjk2TԄ,yej)Dkx~!DH|ȋ=xQԜaγ4oj s }[y59)닥3&͹ m(:ϯ-"}l~=S;ׯ>dRbC!($[{XS]=O0˔ 1B${:"PKrG83rN\:%5Ņz]$IF J*Rν rb8m jf_?x j--\6VǕ54qYa[`j0 B^iN͙t:]ӧnI0X@ $$B^ 1(V MUӹ[5J4O>eꥄL0b/GdFUUZl) l6Z+qN)k2Ok^y)|+>>l6[Cx u AӴVRT"0f36un4jJ$ a( J4SMP(lUjwjBfғ$I<xbYd2]'圇gKO˜eJ*//SJY'.YvTm/ *}{STKAuPzăSZAl` fP&suKm`@&WKL0;͛ ;BJA[ΉOULp +BB!7`E!7`E!7`E!7`E!7`E!7`E!7`E!7`E!7`E!7`E!7X@P(b1 xeNf3w6yp6PPuEPL&OG=joNt Jm]T"H,ܱӝ ol#zX,hZx\9[ `Rj B!t oj;.m]; $IPYb-N`x<|khT-S 6t@|1Kgkxy`%=*t#@{` JB'v[PbuR%O9C?}-"ΙҏgsH_ak 1e>( /B?|LxeƖL_&rܬv^+ y__V N7Di8jlnfSEiIq͒0҅ӵ1 &3Tʐn| ¥%M!*_p*̓l0fnΓY ]9}WK=gHH }ZqG}پ+7V *%YWAXO=/ nh+CbJvJM|-R֐W1H=xXʪZ~\噍\ޜ^'u@('O?>a^nM6_d2YFCʠ19KuE2@upg)=x돖2~ha7I TOk*bԬgK=V63x;SU{Ⅹ>|=Dϼ>|g>`EFx|]۔' #R8k8mkvCG9-:=%å̷plil82P샩)G@k8|Da=ڟn +R߳/9٫ެRIBP0F?!9u:Z?Xyqc]ܙe2uM.1a)#,P˸ *T~=յ~2S@*Lzt7bI%n?ݙj Γ[L_/wǟ7QA$8#}u朢qFG3'򅝇5wڜ[ʷǬV4ey-< [v@zsZ#UM]2L4Q\UѭsThW.hr>;2*=s޵bͼ7 U5iy`%@;_O W=]nG?~nDguq/.R姒;&(e'4v^0\\9(6e;k gC%tB*;OzbƟw~8u_ ik,p81`ج]:5`ج;u:hvWYZm 5Lt}"bIvM_:$I-K7r΃qs^Ԇw n>A@2{u=ԅE"u][C*g;u(2i#~: 2;klb\0qVz#FŅ:u8u`Ac{Ą($bYHHXnd~cĆdѝr#K]'чw\J=zlo穜BkP_>tj'GÓ%9cf/[Qj^rLH/<ޟv,   Sw,nnXZ]%gOCl]?LyOwqr䡙o.C/Mo~d` /!lvC=A2\|!˕ZbzΞ=+B)ed[>$EQdG{oĖ{r Lŧ6" 6oHWiRqqqm]vjXXXfhlO"hb`[B9=$,# Aʚ;QuVP#0XѝiN͙t:][ _E+#:jt:a+lf`E\M&nTUUjڛ"f:'=R,v+ y WܠiZՊbT*H( l6lj[FSɠVvNOA^t [CT6͕$I.p8|ZDu:;::7}t`5-&#N\,kv{#܄Z`fVvNOA^d2u: jo$+^!-dvNOA^z:Лi3L4ݑHwVx0X^PS-kj-W{~wy(l7X,EDHPső &ss@.K$Bں:,:NZYYٱ{nw6y0XBͼ!5 Vr3 Vr3 Vr3 Vr3 Vr3 Vr3 Vr3 Vr3 Vr3 Vr34K;  X,y.rXl6[̖P(m]7$b2zG'""44S!R(9 m] : Xcz)oBBE1X*B&=ffᨨfvVO~zWEw8H)]$IJe4 v{6O~zBޅ8B(JY0L&KJJR*vq VwQ*PJk} V8N(FGG3 ӔTuaY6::Z(zO!\Mki׬͹;X З6.y }g-oA;+R"2L*wd+XBϯѪ$U`h%И:mgpU"|<6kbh1c\:wd9 &>4TNbZ{~7f9y7vbLAG.ajb(̭+W؉gK K۵MaZ{yŀG% }:bΜ B՚bw~5/'=PX9uY'xX7Vn՗YaౣFd"?c-mP dJ!eИݥ" O8:`j2*z+dg_W>Aq"3?)˗x =CY:O^PO֗ $;sn/.(v&?Y| Z[tVsQ]ɏՇ}yEYa[;C=)kL)_9w9QޚUR潺੪l+~V4E7fKx=<~SjOEQE?DWs05eИCYi,˦ }(+DWT= ]m^N^uK@xLb(s%LxhӺtlRou)tN>ZRI|Cy/80mzc陴3*l3Rr"F&r6qPtz΋`ʌ*Q[QoؔN>گȔj *Y6Ԫ-V`˺]}өْqBIWx"C'sE?[^EuN.N'XR˻D]LS^MWvSPAa"U qA<\NB [VO䐡C<`I*0WQ{TM]2m1, Iݰ(8Θ۫ٝ2fEhɪCA;W|Z`rlŕ@;7RO>;ora~fZrrlǓ\%醚6SHU aͯ'_m]'Zp4A!2̀!r2wk 8px{YQj 4er.=~?:Lͯ+7 Y -;PJ_ellP]q>rȐpܑ r6WQ;ŲlM>`ج]V+e%ivW꼔0j3)8sϻ}bo=ZDN>UFsg=OK 6jlJfU3b; )͜h-٩޳+:/ (߰1 *j[k<[ԼWUq 3/8,H@b Ibl6׏K73}GM03}L[bigpX?9}^BJѦC^t @?b6˟N ﯥ:f͙T1[Ur˛5U#;Y+Y抪'k=B5(bl?roa⬴9wl:!"F\^y.XBM$F#\BvjXXXfyl561^Z[3Bm&9+++kh(U\¶"4Mt:h<,Z<ݵ'`"AcPZ<Nsjj VP۫D׍*Zm\Q{SAl6Z]'U!^W^eY2MZV,KRDBQO;bffV:7s^1Xm] FMl6Wz$p 7QNm0Xf`EwEQ ]##?$6s0[.Dz`8s0<<ɤ).Ip `z-@ֵ@D"ba4DM-I3gJe9М_Ph)izdL._H+bx-b*ϭ?8S(ReY d$RK|a+ KMVj_Je||<4@llxU9ŃF ha.,FGG B7[[z㟧`~6;+#""im:f=Zc'O0qj.;t!<@J>>>lsdRbpGH3G TyZGo?otĸiO P}]s*CM>' `zABib󫟪M%5Kd KN.0bJ4!W Ngo+rM04F<5gj;w}MV3?'峝,]"9YD*֢CW~#B8m; Z&جŌYs?t}mϿr_OWH-!O;H;O~`QdU}km;Ȱ oֹ^ fۿ%{聱Hӥ}[s7?avK_ϗn{އVEŏoTrJPx?[Op( d+Acr2w 084*3/lS)N'|%'%Y3V7oo-Z8aXfn^*Mc'|s6ɩᄊD(ƑSv|s_\qJL >݃F蕤ZwEb8s8ɠIO8_Ӿ'?Ewt5n;3U!rGTlx 1j㳥Ğuu{Eq3B;WrR"~1(-]QԔAce,2p]Qf vjyo@ARj!WHv] ftY:EފR #DzJ`Hhc 7i'ϵp kk_‹rjx hsOWU֔dKv=9 o#0 Q`6+ڇozob͊4wd#k|Ē^戩mo]߽^i0ӮSѓ:D7-N*^tWsϤ!ml 6cogwRʘ-{%rLOLS&;^>o9%//56砯)$u~p tӳrn jGCИ, 2.'s~1۞:ѮM'+,j]Gi/7ה{C[lc[ct:\@kZIdl'$/u$ʫ A<+ڛ/a Wl Xڂ KSTӪ2v ^$M-u[_5; zʞ\[݋\ M =dd7} YSL0Aiz \wPQ ; F N޿[XL$ SUn9p^<{^mD yP!\:K5Pre0=sU̝;X5tǪv΂}%1 W&L>6]γT*nb9qǚ)ngGP1RLQӯ-.L!S/醱VФS'ٸ_ C3\24^/_AEybS^k8,[Wh3R^EMqhu[~ IDATZr)). Ih4r{v41.gV # DQæ?NU]j< zjlzuV\|$&k^^^%;TeB<^8_>sI k95paYp09NdR$8#ںH$X, s߿% ufW`9М_Ph)izdL._H+bx-b=}1ACK%G+b<1XvL"_vf ͰNخy bz)l릻3L@=sp*n{>*۾KS8 |T[?+B+|#9 =~ VW hy +BK.<Sc~z3*8Od=kvozuD6:Xoc<S!Fbm/뒟M$8k،Ү˖dlMJ Y JtlBqr> c__Bֲ79SU⤲ćILk]Ƭ2'z/Z61o{䪥yc^x0FBo{Mq g5TOpY=≪O]s @H'͘5wt^~%:='>8k@@%Zth/w\^)}E/e C'<`Qon 49H=guuzgJT#z'I̩B]`*s5I0et\++|bC7P#FȻ_5fpf&*KO)W9RQP]֚F$Vj+* t5&di)ktlAյo&oql'?{BOl\ޝw[1U z]ʻcU m8ٛ==f{ChqOY3 ~^~~i'&%N1Ak67#i cc۾^ՋeHnׅTչmmVuԪqe ((;ZYlk15Bׇ0S)a}E6i{s>:[O7;MfwNL0H U,w(9ڳO% e v5B $U\\|yĤ*92b'*XV(ʰC_1 vxKkP#L&XV\9(>]=1>!5F0JClR祮R0\_$5(0XoJRkZDE].f|r IDj p|fs B> %+BI !$B`E!a"0XBHb!$1 VyuP*A- jnjj6 ֠ Ts (@ ԴFYKG5ATEHB!..N0Xdh4 Fc2d5HN[jMATW>kTEHVz^1X $+V+_ApB2#p*B#^+BI !$B纘*ս#vja|ŌC-Y"RB郕h{{6"MDu S!tg`F*S`|Clr[YII~fELlMW8dyHc%9Ԓy&%G?}ݫfHD獏سB2}\HvxW}ѱ};pΕx`e\s+v,L%K=ƪh֥)c͢#d1437l_ogSk#ÎxoovPsuյP?/:XĀ'u7RJg]}B,;U _7Y;iy.0:OfP`?8 `+ 66Or߸wSg5JKZԶ5Eg<ǃB7O+!k g~&O%2? N+@,fgjh),pUῐKMUBqD%] E 7;s`}K"@]pҥYr;ש%%koQUP]!u??q(ոU/?@[?t817H<(8EhMeB+U *B(HHyuLzZ$'7jb!gC:hH5.ҝ¬ޤ=UФ~#:_ce 59J]Gv/H=iJ|L!tS*ldKa#}{QCx47k3e)y?F}条Q wޙS$Myo?9i#}Vsݰ݄-r?ŸoUSgl/@e} BU$%%vn 3aPmQJJJm7:.##CZ:BI !$BX8Ɗp#81!` RŻ3zdi4BIC1V*"P*PY?;I ' ? %>Oggxm ON=(Z L|F?> @Er/B5'Dio9tHG\upKڑnBXɎԲyٲ}eo@NZUǬ!$YUwc3ʏm5SC7P#zebaERJ,=-8;`+ou-ɛs<^MTf+B2Z>O1Xl$rfUFQ PM8ej\y!iXbE\.᠔2 C!A戢v{qqn5h$' BHB8ƊB`E!a"0XBHb!$1 V+BI !$B;nJ`0h4"tsDQyv˽eAb2 Cm70J2AZfYEX!qqqI`0ɽk2L[P]hL&U`iKm`0(J` RJW8kAdj+5HqN@HF~0XWEHV~ӋB`E!a"0XEB2klm7!to}Ƈkusgl !J&L~oתͳژMLrAB(8I#DN:dezÏlQ?^d޲SVKxX0{#P|zfoHќ=sO_ۙWw3 ݱQ(•e8iV@a=T /gT}0cr`>ףb7$$mG~Q !TgI=ƪh־>cSο%~ndywĊ`gcNd]O~8XĠ7{s{<6GڅoFւg}'-84lXr-O#o|83;aCj1gՉ{mfJ)PTM8X!6Rc)b\=c3ܧ٥uJ,_^`1_;GEOlRKβ̟up˞2-Ўt[tb Qe[Rza˚9ʦ:>s%gﯿl-h=uէހU͐|(t YbKЖx'KJw'D#% z>(p<>`9blƚ7|hFjd_!d_ Iu{X XUɱK  VҾ(;JmE^c|.&] vuKLAb*.]flAյo&oql'?{p/TPMH=?y7Ϡk~@s/:#SU Mn˵Hkg9nseX©؎ٽ:B/OsҚOLJJmֳcSS&i\v)E]fPa2ӈA\wr~g!cI0ZqR}iE 2``NA=egWݵk><'{ѵӾX嗺z_ԡg~Yx?c&< '<{kȊakHRRRmU"%%P!SxB`E!a"0XBHbAJ6d$G 5H<._da)]M@.s\Vkm7fW8k|j|O% e6q@!ɹ\.,khTeYZ] AZŕ.-! `raB%aI(~^\\loA<I}"0XBHb!$1 V+BI !$B`E!a"ΫۀR4 8Qywr/jukP#L&@QJeYeqR* >OR j6^5xBU^<^ڂPqDz,qaaa6`0(|YW ^FT| B7%0A0 >/pڇfUZVVTj2Ȳl*_]A*0n!v^'zj` RFR~"$!APTZVZ0Xq GT dt0y^ ty^R:%{a@Hr<} k». V\Wx9Ǐ>BI~J/w]8ճS=THmYY6(U\"!-NT8.^=&?H/=JרkpR_-;`Z9ׄ-bQpy IDAT喌.O>FY_Y-e4TGܖkx#,Lb{ PGys/8 @4?ʼp|z߆/s͈֟n5Ӻt<!eafθIҦ]ÇB%Je[xښT#KR ?N* ԎG><6bٙ=K]3IARٓSElO "F/{݂7g:)ȣM51̭+?1ծ>Y[7dscVs/Bgn{->Ż3zxEj*+v qಔ/'c-5_/(]ޱ?:~_˄p%7YQp0E3aJe\,{zI)3ϔY̵Ҽ[7JmFK=Lzav': 1v|Gxu{M~x_ko.89׻G`|ٞ3^Vf@FUWWx`<ä7řM<*BUwT5MXcvʹ珝ő<,%k8bDx9URd걪_ӿzߛ=?l9]NV~SI6ý^Y@B9wdxl5;eOY1}ln[i*+gK淖XV l.dD;bێ?#,T:,ĒKzp-w?j#e5@K6 ôZwf\Zc$%%vj %_-AjBvN TwzNd|k|6MEVjrJfd15jvkZe^oHHqgխ{9 JR*VRxe[5BdtRJreYV#T7PJA\ z5|[NJB)-))Zz,08zEQ#eg6{B7 ?!$1 V+BI !$B`E!a"0XBHb!$16T* F8oiEfZxK+X`0BjRdYaAT*`Z+pDžl6T*eV\5xEFFrg4G Rq1VnJ` `0|>_r' R {eeeFe@U0XT`\Un Bun^/_-AJѨT*ҋНyAT*V xP"$9 YAa^BJWD^RoAvXEhEY'7- yyКR:7^ glҟtS~#i=PI,۪MCvwyl="s 4y>> $`Tkwq+61zlg劂?"{ㅻS4vh;o^kHIS;X1#ZƩ=y7}r @->>ӟ9ѱ$AA'ᣯ3<ygOY]R_+D>kZ|o~jKi-CS&c}r8JJ:ܥ9-rr FĽB[ ߠxy9!a$백.=FE՚ɥL5zd_.=Po;`TCQ qsw%3d{l^燡[b?kG1z/f Br.}m*NoLKXNIˏ,6mE69`~x-9iڿW%/9\Nr/5e"?p;3w,DZp:%wSg5JKZԶ5EԟupKڑnB>po醴l=@~}ʷ=ۘ֬:Y$^Q}=P}Vﷅ{;^k21m:l?X(8z/5:b |y钶"aYr;nGi!ۺke6[D(*`,KJkrf}N 6T`tK8E'8`s!BQT`Ό>3b@^ykm>X P/3Dh{7KSфq,bMPhk04w,{omV`o!<i7l\ΓKW ٹ]t4E`j{Ňr\Cs]ճbǫ#~m^@)Dz=% \$bHIy⛴~(V ubۛ][6pĵnpqV ߵ[QzDFgby[><򥦹G۽' riVD)E1tOsE.1s$,*"LCz}P,Fb3BYzE7}ݜ‚숇&dKJY8gFz[^nKqQߎ̼OL=c0*>W!dg }7[D'f >2k$0`+ou-ɛs<^3S`€)-»Ix,ͽT8x.lWqֆg:?o_c!c[S'=^X,ݠݽF4r8tO-z48cQW|}'n7|Mwh#kNev.&>Z4ׅo0V$x{ z ywLxxxljta'=M.jjvƊCs =HK0b5<^!ա!tS sf|qA~Nm7<^< R[^xvOQj_>G^S._`.=υ>zQppηY3?L٩k7ic޿滹ǽ !{˺}1.>[p`K)@ԡg~YEۿ~l?2i?x\'L9a)CT-܎yǮwxW4~##Eg8J,ܱ7oS/=3 Hxy~sٴv߽-2}C5^|~ϊ. PeOLjάF3.7h/=(X{綾aypO>#yHC{WIA&IJJ6 3a4@R1eM͏Y,Н.<<,##Ctkغ̮xu;LZS$X(j]b=ۿk\EN*=>>D Dm?ZWzӉ@HZDžl6XDQ `!i1 eE< IL`y v^/qI8e}>咯 eZ !v]v[;zn'l6j` R>fhZ°ߊP q^^^N)l>K[FQQMnV˲ 8.rWPݺP8NPT*RiZ)XJqUP#L&NG)UT!We~*:BuT`^3ͷzH*Ғժ~?˲ 7QAxOR Պ!qqq^B>^ ,q\XXf3 J2??_lXWdddhh(qFp"cE~ N,wj UʰP <_VVf4Y [ 5HUu:n Twv^OՂ4J!ixARiZj` R*By^PN8=/; *J)c ^ 8By^m0XLpa"Ă#X}Ra|LCb_R|zuRk+9koKd;kz cS>%RWܟ,Yz߾cg3`:>հFkJ>m6 V ,˶MRW)n)7%ۗ9˗&:g\LO=(3ʟ,=U~TM2p7{g|ȷyIaB])u3u2.t"'UoR @"ŰO?n ͷLAIlD{hdشzSCEtú6O S<֟V)@4]{ʋ/Z<~džS{W7LdǞ7Xlk6mp֕wfu.z/.sAmSbT~56+!شvnW#~㸝^wGETZA67wC~/3)C߿~D|u|v\|.WF1:ў}b-ced3c{֬8wǜ a= lh9p[ea>Z/)|2V'XS5?b-yEXB(]?^ykDz=7U%ĩ=&ͪ4QU鉶cϴ;{Gv۝5CˊUzZ*/^1HUXZTj5< R#ޓQLFO~NpUI^=֋԰VǞTXVR쯨STPBZFxbB4 '5(UqBM;'iwdݿ{ HH;sE.1P_oS8+ (@%%=gYRZٱ3Q&Et싓TSsEZ PvYoLޡU-e6usry@T[?d;@KΠ& DE-l"]lfڮbG6?yvtka) *RG( 0*R$*RQW_ɱ%%fh`2m+{eC\cj)2:*ajڠo|x?uݰz̤M u.ބeو!=+%Y/ӐN [ UZ^S2WG1rp趣4)=7+p:u9Ar?pؕzΩF1rhTç=$ޤכ5;H"niQщ1jOO#uऻqBCM;l[1X bIAIj4`C阪&7:L;{m3b`LԨ}ZvU3㛏 sj!d鱪۽0Qwتog~(p:` 'Nlv;vbQ!]nj[-K{b_[KUY|\ O;@}V%~ԛ% ˲a\X~N):s6 h԰~{=+V(@?1}{?0[.n{:{嗻^[ƾ?~?;,R|]V<>,s^ú3.>g~{=à3[Ҫ.#zUܽdUEK 噇j=uqz<^c?/d:n}:o-kñIj A7'}ZY,Zkwdn˭stxzZ ,<<,##Cc@"۷Iڷ'?ӵ(O&\S ut֎BUP``ؿn=i[A3W`AH&rp5HzӉ@HZDžl6XDQ `!i1 eE< IL`y v^/qI8e}>%*AjBvN TwzNlՂ|>fEja8.<_]htTn[ղ,zCBB8 ,T!8S(*JTZVJ)..Rn!&IQJU*U`ȕeZ|BJ K^70f6zoXV^YeA戢({2 ۀ3k=+BI !$B`E!a"0XBHb!$1 V+BI !$B`E!a"0XBHb!$1 V+BI !$B`E!a"ūuinB>UZc@EO%ׄ6;V5.K}+aNdƹ+([ 1P0`EGh>CNh]"UѨRBpk2ԚJ6 mr{(;Tہ!bh @Nu[Qx]_S VX-vv*-!agB[>BaqWICMPwWZ)Qq'>FӖ.ZV`E;i`v{E`CBTȱ{c=O؜Sg+<`h,oݥk˶"!ڦg;dZ0* 太5 L$u / 4Z[ey lc\Uv֪ !\bD!"4\[`(h ;XbQ{&דݍt+JvyyF#IQ$$Sw,_ymn*$79oQ^~U챎,tq3evNH7߰>8m|/=eޠ#Aႉu$*nyj/k̃'ͦmgZ3I.|w=Uòys`mpl ^IWjJH+姪?2jSg&*2BHKo;Ucctl Y_E+׽,Fly݁:{Ci#u.6U7m̹i hݒEꏇU/ae'%J|ƹU'^fs` ˿<ÿZ]u{@K8 í[ $q؅#x6Ouo )7eRUen+تr%*ŵU3; '`1L=5Fm"<@gݹs&qʐM(r/T4v&Vt <n>?D GlA+5`hyP) 0qf0 Gtƥ9'x"6x{Qw .~c 8t8p?Qkk_R9׳[Oig^(ԦL(?vwH 0˭f$vق%9Oq47,T14~Emdib kK6G3= {l-8 XlqCh:97U\m ~FF3c| f87dPyi`7KIIOLMZ 8AM,5 7[6xM—f'hcSLڲ~^2 s'ÑG׼BSX/˝Z⶧O)x9{isKwVMjܬE )Kp9s4?[ c=B-V` 42:4W7ǵO-XX,-O\P}WvxL U}Opuxm7wLϑcHHW_f)9c"@՘v2|N01s:L?L=Bu)rb]&mMN f, 6:q>64 V~0D챢 XfXXc @cD 4He=V4-XvEД`I>/Gs".{P/̺ 4McM)AȮ))1q[B UX].N|! 4I,ZֈM4X޺0mBl3zGaYa1-er4`MCq4annh- A^ojj\.Wؖ R l1~hRpV45jF*xXy>H&+eZd2ci? rs#:[7dyq KWGC약)a +8NQu:˲5aEƲ,qr\&uuuXX)=L̔CHxMP RrCCB:q^WrH-fB(>r8D-!:U[ḶhƌE'"}cezЭ2W3vLuuWxg X4yq:B7ު XB(°"PaaEŠB!" +BEV>wIENDB`deepin-terminal-5.9.51+dfsg/src/assets/deepin-terminal/terminal/en_US/fig/download.png000066400000000000000000000412211475472654300307040ustar00rootroot00000000000000PNG  IHDR pHYs+ IDATxwXIgw:қDA(bC+ÊQ"b " 4ґdE*=wc773455 $,P@B@ $,P@B@ $,@af8oK`=/?` 8D.<٬C >q6,:C\32X!ۋ;-i1VSF֒Z:2^pE=sF+Yq ~9]/9owRgguP1 >^9`.!ygW"*)%)}UN㷯)&bv)N{&Ƽ:f$pvw#bb^c۟y[Or Myubطѷm;ڮ mKON^OIXKX0oxVf7^ypkDeyDŽx\GSPxDŽ>q1gdž=U_[ytL_cV.occ#g6~`N*nq~.6iaRDcAj.>Px4n$}&o'=x':֠gxٴrlȬ8c7S򳎟_n9e}mm`p6sw7LX`H[ondz4QV궢c ZZA⓷ܳ40ucّw754^zp y@2sX9m)[jlNfL`E7 YYܖyF/r,j 4:6r5Nt:܊ou:8Gu睱saut!x`xw(,\B^$# $+g`=Φ$wbj(Bk N\c J]^KLȑ"{?)(/#]R[[Ntfh5/UO/|y-OnSuZ^>Dʲx<ϒPSΡdMG9E)N Y=8!8;H@jrM=?%V27(g2Jqm9RXQ0X?M̬侪ONH%qPNSj4l7J~+ J~Ț=9ZX8ZvqNN5kd-"H-) ؄%h\X٩ɝf4FʯjdaA_!$j] \eRbkԌE!9mcRi[qNfף>Kw'+"*~7n\<'giVwX  Vm'W|rn0ٝ,;+Vܕ}JBC\^ Y m^o^>:80Hdi'bx{Gߨ{gIUooh0'+#jOX/L)xE)'=ʶRB ]y:_IqI" !ZT/3{RZ-=; Y[oaBԺҌ6:etխ{,L$HX( a! nXC ~4c!@ hB@ $,P@B@ CX7:p_0'5P3.WrʝR8V\lF/I3t\+n^wfEï f6 x$UmP/?}R&@fTT*̪ʲ,Kc=4 @ӡkM־t"G7ADI]sy7gRPɷԐMS#@.Uf7۳I֗$PdYB|( i<8m=}ݺ٣e0懷<oVqȃoxq 2m Yk( ]eS[87hRWג- .7ffCp9XKMm`FwK?rҸflrr4EgXa8j}{,VFrm *MWLlN+>qbVh7z@b}tZ"l:( E] c%eή-p?~檻isnoܬܖfAlx ]:z!MF\fyl޹kkM|޼ݞ%%߳aX;au^Go0FYL\JZ_H*[jkiYkѣ^Kk޶TFݹP)ӻRvQ^?ACBLJW7^",۷iצkBuyOW8<)&[+ef3QbLjU.kװwnsx](K}u[X]viC>w/0Ҟ:t ZתV]tyӉW @?ryMz}c]Z}bg[= ޑyy] 9ۇm;0{v~ =AB@ B@X( a! HX( a! HX( a! ~PYs{O= s, T] p; \wm|5^z5U.fLߥ W _ytO ^C4XYO'6Q0anѳQߎ痵..gQN~WIC4ްs})i &ih-I@t`޻b6ͱahj* jٸ<y6}8Q `B}rd˽k1yqeCcc^{]3*>/@ 1K]yISQ *&ZNb[۱:͙3fopVG5Z/N*.JK9[Qrۨ LdPcݸCmTm.RRI$ 9Q\N/YqU7{_\g&^TYGO4lR6mtxÅ}ڝ+1]u?9>n"MC4׌]8BbI?>qFT衿Ȍp&(wѝ>`AON$mAאږx\S2RlCOd:,, 5U/gzg5fj\Dg NػW 15CS5,y}p*I}XPiɏ2 xxb(0CC[OaBY]Lf 84%y-@gfVrRI#eEMX%^xXO|jBc +- D2KSF]mK MϴsZr\pû:\s۠r[rrA&̗}{Ӣa1 Ûx@ :i,O;Q_6۷ `e25zV l>BY9V}Jٯnߌ.# d$kPKrZIo!wXqW]*1v br{X"&6hgo"x7./+Q?p;,-( SSN&ni:d) a!c!f,P@B@ $,P@B@ $,P@B@ 4ׅ_&|fc8HCF!!>""¥ :aT؆=id%!yE?Kȍn84>9%!_'9`f,4&'.jsSOhLbbLC*~ FļTDMG=9&)I=7z<[ GhE~G͍ڃW:>y$UX~{Po60}7w׎}ULBg 9Q(l#8*66⥗z,pY/q2F6RY,9h";rਁ\z@ŴRRh؏.릌uu'f)pǁPﰳ5 OT}4⚳kfPt,vN9hܴV%VN3rqS?;.չ\`:cs mp e%V3& k\Iȣ%<=f{1aT 5s_y>Of@h\<0klAYiVkI) (B{pv-!R?iώrMOyq~!G`P-|#8O&I 6jrnl`Iw쯇f3^9N6Y-8J`=-4zfgsURFjKlV°63  U|+Ѯ!9=9F:yQ]s Ϊ&:MӰm$J =Xa‘PwED ֫𞉫k7:h P&4@̔cEp<:+1 !1FIf%pEucE0[ط-(+#9 hj4]m,35{1y}D`d j~}(c|TG&2ZIV(41MD% i j:ڍ1{մ`smU$",f6W‹e$ ޼H5kvNX8 Yp^杦=%TGڻ\I]!˂w{-? Al`^-$%2j΅JIY-9J~\7j cw p33n\yu[k.UdYe57]}s[$U[_>DVm'W|rnw8VfXDTvb6]ꃘxmtxQ'Wn~&jE-,oeqix}l]|#DG.i[z\yK (AZ}-m~u#d(X{z ;}ۺcw;m;oCjP@B@P@3 HX( a! V2į PԴt $,P@B@ $, a&6P3.}̽U&ً~Va<-ԡ6mG2g,j%HΘه6iB"\Kߙ.WkHtNHIIL T ӽBc+|4WHL|kkIbAz6sv4R}h>s\ـUQ~ݬq#,\YSY r&4fo={u3v39s., (>|"ipᯤլJmŴZ. MT^&8gտq9(>cq3n!eU$`x؞xjY'UmŴژp-+5?QW좬0trZXBЅŁfhr{REsz D8s\u?_L^.]T`<67 %s6bdqh_(JH .)+DKP5zcyrt.f0oγlm: `Qʺ8 k"eҭRm!_`øîAvK.o  "(tƍ HX( a! HX( a!rA@X( Ќ HX( a! zۇ>~[ h&9 ]b ҿ 5ڿhdUɌc+ 33d~(f$J`}v,ibs}9mŹS&Vx%xGn9x616 +]Q*]XSL ~+OR0(/, ;t<.Y IDATnr!=&-2xZ h侣S z޽`b~'5?={kB^rnx %S\іG.,F8o`yTU K,n.zmPiɏ2s#C#45%D ̓ svlzZzy#MMM-> ]Ro?+ UIcņw3_~bMp U__] WZ6ғV+mK)$QƝL&Z:c OAYɯ-p?4h+ O=ʮ-%vNZ&sFjgdTh* nhctRVZB >dD(RC-jC%TΚ8Xv?Zz-؆KGUu ޜ,~ãlѕczȩ茞5o<BM`XGIVVpFȧMx蠮XU%tz{p+Nj ZתV]tyӉW @[X;=ro$Qz V[jd%'Wm겤Y!V_b  o? $,P@B@ $,P@B@ $,P@B@ $,P@B@Egڷrz]IOjP:M{7//*zJ~1SڰK*N66.2iJpݼyxGnmon<~{S) @Ѷ80κI7\:Q%V@Գ1I\bL1,:=3KVu ԓ(e{iDt.м]tDioxưOvf:x):u*۬ L&_Oj p U"Zkv^bbM]dב <=yzЂ }?i`+dim RD9ɯtkhQz/9AMGl[ -'i99}ͯ(NpaYU5.R|zl;!=f>YOE^6x z`NSݞR#W]$O:Ұ}u놕;vN X՘=;Dx1>C`X(= HX( a! HX( a! HX( a!oK_Q<}vf4:Eh@įp)ÃN=s:aOZ)CIwl^QG*%DX#7F_䔄pn1+7A<ƧcmS$Zryqz.n )%%iТk q : lq׷qhga_Ht|lucsqfnG?߇)[rA𻸘V|+=W}Bcc|o2UxVnC!ʐuGͅ5gg"?Tnjȼ8CF]QѲkuX"cu\p?eRtb u{sh;UQ~ݬq#,\YSY 6_0)'.w>H7wnfgx&`A_΂˚?$aѓD[%KRRmFR1v}eyyYaFwXw[vsw"? VXx}M-:1߮E^) }Tդ)wDݾz->9u'1/Å5o,AYSQ^17Ra$;dzS>w?ii'ߌL:Gd-i|U[ TWYf"~ 6qQ qHN:$Qy(WQ c'pa?t8;^1*B-DaKj%55%n4J温Vnź=k9PQjXV1a]Ϯ4n'"544c70 _ge `P8oa<HfC6R MvdW4 p*l6aq:ѹ E] c%eژhZ/Q(l5|rjs.4Q;LaZq%дt8ˀEIIjSDp M[3BhA?5A>}x X|j0HNTBBh͡t-saʺ8 kچOA/I6hJhZZ瞭2æO !$$9d=[(̸~nъ/8hCU13^/Pq~%]gJ 2޿trN<7ڦ.Ϯ̉uD{uq=-9tEt*O ']鹪{P& L9u iپBjǔ׮[mw/+D@7y?$,P@B@ $,P@B@ $,P@B@ $,P@B@ k>å!\Ա>c11`lx M `6)4D$ta?|J s1CD0&ojrzXrn@xl\+OM`b͸aϣ=WI[`l`z!\ou:8Gu睱],@Vd^en2j xM{`"lmN_`0)쫦 E!9Iv]B _N-+5?5TGD+?/efƤG-0:)ov#C p ٮ- za|;=5>XCJKϞ5$,ȹY:AJq,V;1y,Yoc_z7Ǎ'Ǥſ7.wCB9x͂do :MYS肳BPY?]a=-C;$.aLvn8YxrgnfB@P@B@ $,Ptw ?4c!@gy hB@ $,P@B@ _QX٥'u:pQ.'O4` "bK?Laab3c}gBq0$~LV-k.oi4rWbcW5vy)TQ܏Lp<qtRHb7C7<.]B]f)/kkBc޽~kFC}eX)73xS^v/1%\)61DrAB0Q+ !MHo=0wyrgR|PEas477u-̥#QLm ͼ8Cc~ v9 Z{zxIB=/)M4Y_zOB=/1{ ˧*%$^{0lND t,TINh[ 45ڿJ|ya˸jjH`ש0El' ٟ=85q 4k,5ʴla_Vn.N5:dH|i#hE 5꭫*lٱ2Ӏn/tLVK/:9-M!qEswS_ Ta1ݿ޹u5T5]t22Mz[ɸNKZ߇/+V.ryLiِ&#.C3ܼsP \v/aO+F1MGN\Jm S~4{,Vڵ+n\bwscz=WwjW-{{tm@9Yx`پM6]Uˋ~bI1 @'FYړS\)Qrt}odG8v_u^n ongdFz LhBe]ϱ^&yn1H~rP@B@ f,P@B@ $,0&c@ $,P@B@ $,,a|-?$\}8tCʎ] vvgCJ>q(&cFsL I..B|k -w| y)V dJkJ@z^aU 8!)!`8LWRSם@qWN}#E.,SZ_Ȕp^wgz:a@jc/;/\7GWĝ]ziTKSzv(hBdQ k \͵0ۦUM6Q;|˲Y $ud|S,~ (|S'2>\[(7(Ox40P5ޤJYYܧ"k0C['~j*Id$A`},[\,-P'%3*=!O)z/j1I$ߏ.n0l6 $4˟S wy]|̲,l?5~y4^V\X!\WV1#[eTӔ)e4\d\I)UP1Q)ـ@JWSe\??/9M0^ZE럕pR]"H@֛B1bKNCjr}a|A̪܂$lh0 ..ui,/}j:6) d8̧0UsRƍ/VU]]i$J?H&)/3RVS$Rd{X+CMSkdKm~%uE(}wKr`؟kRpvӴ >-e/^H|U*tkS[G57?;8U׀Uć>$9-W.erJ=*qJ݌ʪ?λ&%C=fJ]:CZgVՆFPE5R  HX( a! HX( a! ^wǀA3 rRB~6(8c@P06> DHBt>r G}c3@טb}UT|b|TǗr4A[w4_ Ag 0tms:<& JEi}+(Ii%+ٙsEt.+-55x֌s)kb"XXn-Φx;tHmqF`e]>p痗L<-q$P16(?>H<fZWځNHɺ̼n)kM;"mܽl8Q]>> @))Juo+ob:~~II)V;vnkЋxzC5@d 7}ɣߴn\uk6Vb xv+M{_s|OW@pjeϋydhzjy" \`!'\~YT8mZ3Lp:[PVZd@ju}IyEy^ڒ82c̛D|N( P,+/K }3SbnOWp|'d|֖S)~۷o K]W0R2 ,YS]xxTUKLj +#5{Li>ba%Ցn+IDATBm8sۮ7oڮ~ax@ޙjlm&YMԦn4lrKXZ2cAˮcռad j~^ l6h˶ade34EJ M*O}~e tifr"Ow$כ=͏ؘPUdb>U.+}'hHIc߼lOaO>\}efq=L䙣uTzaE/YP9c5P&=ѭ5ޟZ~o[8vKI@{>e0ei/⛗jzlmA!.=#yUMv8yxtsb]w'?1,aIYwVPiXIq ?k Kh[&]f Sbģ.YuHF'V+K ⌢+m ;XnOc!$,P@B@ $,P@B@ $,PO IENDB`deepin-terminal-5.9.51+dfsg/src/assets/deepin-terminal/terminal/en_US/fig/editserver.png000066400000000000000000000605061475472654300312600ustar00rootroot00000000000000PNG  IHDRқL pHYs+ IDATxw|e7#iK7eU nE~WWDEN*" K=l%mi4i\rw?tё)>|BnEwB6يBيBيBيBيBيBيBيBيBيBيBيBيBيBي܋U붭ٞ< =~_}t_eCڻ>Z:/ W걾1=dBʧw@=JcOobpk.NO߿Ee6VQvoߵ._ V2lk~~1sm>1RJU=̟wWWV|n[m[Q1y)_2[2 [Z,{bxjS5PCFQ@7q S#gK[RRӵ_WӞJΝm N{WC˛5g-}vQ~8?B:~{[8B1j=FS;l>W3.D\𛫃pXEWʴ{eFmxmM tW R yiX/,ЧPtOrO'>yw% 9?bs?[VcTd{}~ѴO;Tڧҵ)W }1# fo,4KtBȁw?:5/=32>HB*jdF+^o2X5϶nۏ˪y<§}c; 1]}MrXPvreۖ=br)  =xSʓ)Kuーppč fHAߗ|nsYq\R@1zfj#/- 9 «XfWt+s#b}I\fi78GgYrGisr]Ec#-يZQa@@uR+8Jt& h%|rGZE{Z8`H%]Vjd!ڴcUuPmI0=&'~XY,EpXزb˅PLORWn´IPlnݣ0Wq@NypBN̽ox`*[ CFF'v93ދOO;W>G._A,1+GY Cg<86B! )TgC#o\rpޑ38ttE; O,HWm̤;G1Z@sa59cݸ6rϽ ~?8Nk` Sx\ٔ@2h#|1bg)zO^y)S pg[ӣ#{{sﶤ-ߘ{P{)3df^kw.fꣻH5WֱeZA;Gg;4}~Ç,DN`e.mS|C%ͰN{ͫ}sV8^|/U CWd3f*ʏsPcXcf\;8C4-n "##[HB z+Bf+Bf+Bf+Bf+Bf+Bf+Bf+Bf+Bf+Bf+Bf+Bf+Bf+Bf+Bf+Bf+Bf+Bf+Bf+Bf+Bf+Bf+Bf+Bf+Bf+Bf+B D *eҮ&N0 P@qTEs3&#MӞ)} " ~Q1SwqdΦd^qvVFZZ0b!jk/]@0L{!oGQ%0brAX$Brf?P-H+**\RJCFRʂF^R8gwcr}l酊arntZ-Ԯas%2Q^-~Lj~b9Y KJlEE*Y~$`%Ⱦ)CmXo^~ճh',Ơ >B}$)|>˲-8>>>R,%8 ?0zCUWz*fJNkm KJj5A](ښL&STJfpzM$ W}TB{@iJʤ]@m6}}} ֔eWҥZK$EDDrW-[WJT*јoۛM$}}}r AH4^V<L5E"wqj;)nݺIRW @d J"׮ CO{)le@wR jMSGAx<׿e\#ڊН8P0LSՅe٨(Pګ@ pVUo'`z;a(j ߪW_ _p%cxx84ZVQ7x.m<8!7reT*aY[dRbpj+sO}<`']~~p`َ/^`[ ~;_Z=nÏQLͫ>ܢ^o+A(ι%N {foC@4P)݋ћ֜\09 e_@ƋԚ>C"HrpWiђ"٘@hKf6":Uj28:qC)~5hF.{I}Ůo9>jJht'V&62[rt.B,_btQBV5!-o8 ՝\3^Rhs揽 ۶f"C)Gѽ ͱ+ƒ窎oH^](QUi9:cԔШ h0Lo}q6**G⏼#cr-|DzjgN˥qB%SsYO'IO9lOaja#Kyȵ%N);{z"1W2 'g!pPNy+ XWZ)ϧV"bU;0Ole Ek16;MyT@ߓ%TI?2liQhWlyIIյJLThiE{$O+DqQVas}QPo "q|r8 cPH!IYY4l|Vnma~8s8`9 W27^{_~d֩%$XVZG(pՏd2M7`C,f"pG+Z kq::QQ2L7h,N*_PToq5rlM7T&r,vu//OӕsI]#:k#NXu8u'& 4t\F?Ϡ2i5֤iec4s_]WP, SLzڿr^u|ߤqzM): h}7ꭡP\>qL{G[_UV\w%z TeتKlj+~F#7;}0撢kFK\&9yf$tEQѵ=(޾C9{⥋}[Y7 ÑW<}׆qϗϚ7+x[ZDU){Uew z (lns_rN vk̗ˮ/c=[1Y[mm""$Al6"[pb}D ^{X/KӴoCor' ]S 4FlmRDH%O nyvu|D+y^1Z# չb_@z0 vA/*Fy.Bm5”F+%gzGk'@ ex Nxڿf(2 r^Tvdj8!~ء!!!!!!!!!B<p6,:NfjClvZ E{5$I@3Lu^ ZݲkvP(AQQѝP.8WSTRKSeZۻ GJ DEy0(J$) ʞ#\\Ձ.j WKYU(j ~0[Wv\$IbXCZ\MyZ%<lo^ہd2JT*]Wuq8zl6f^uѣmދwSD"QDD\.wqyO$U*hϷ-u`uzs6坧\;: EnݤR)˲\d Jego68#TRR&4urO?Vt8N(FEE1 Ӕ`uaY6**J(9U6{)tp%cxx84ZV=+4/癍WZw,1|q.EH(ߞIcŚC7| UsR4>iptˋMٙVTU7/Hi]L#}kwz+G\*9iY==36TƣMi;:Y| "^ИO97\e]I9 reT*aY[dRbp׆=2\s*u;+dԷ-=Cx# 0&});ظV<ž,{_sgJyS{2LBc'Y7 0i0ka7Fv>oj"k T@ϩ/*4X^#yȤ?81O0|YS)}_?F M[0Liϯntn6V/ )|s/0ŝj#_'Tt4s;/O)nzQA{Q,`ÄуFwwڴvKC;xʌ +74JWe+!9r W?g2b*l2[5c<'FUJ2@VN9 `=}윾Wȹ *guhҫn,e y`PZ*neGf~,^-#46ef؅Y簪uk*VB5dFC␤% 0xl֡kd27b'\a;]Էtw#Ι:,6@XUr.cw]]ǂ&K.5;͙-"cS69|VSk|bZ=;ߤ*b梧Foxմ"*|̜J=7>г;x;SUi?x-XwcO6l/gɾsd%FX\(]'v"GER%6$j3?Ps eDh{uߴ IDAToeS=T%m_m>el <:,mͪ ,Rq|uai} N70T`<|>]dJI<2k5n8>D6~I+X?2sEϤQ٬RIg|@ݼN'ۡ^CH.l?Q".H?ueŌB8+zAyCǨ5[~ydН{j7)3Zcrv>jJht'V&٭Yw.=-Qi Eg:m\W*Db1Xq{#R@*cbNHs*=fjPQ3M3yϦ)k wk\!9aJ͛.U[є\ Yh+5o?ߴmVpW7G;5Wم=^ ^|eeAg]8' c^z%n<5𦚃8z7u.dYunHeɏOPKϙOr,|T]$oHl˲nwACe+ i :..][8^-)p"y鮟!^xtݩXH$/=kwE Oyygxy&!*udO.RQZlE(C(oޮ+(E&p_ZZk.3:#OOY*tZ9H`8gdqϼ5^oo&WߓM|4ɇ3K4\ܼ!eʘ,SqnY $>ڤ7}ql]L˿O>= obH|er^[V93rV|Zki Ih4_Z8񯗯Z0oIsYk=-gܷiӀG~ɼ<(l'AE 짖)sKc=u)DDFFwcrAv{*;5LY)Y3W~Р=iogЉo}/MN9{J`V<򂤮A2\x1ؘ•Zz~ۓ[׳εyk?Elc mN6&&lNNN !NAV.8PR4nwEjӫ^ΣoՂ 4Mt:ht-ګ[jz駀يANIiZh:u;ZZF=0[mP5ձRl6W֋ ͦhjk~2鋜}:(y_͸bZX,Jn efhAmQkd̪1[flꜵl%IuWQOWM:^=}W6of2ڻ)Y+1Yv`mnzZz}mZ« YZ P%5w: j7M_^&l6bpQTRRy~VfbpKh]VkII{VR7$IGmf0%%%mcAa˛5^yiYLL&^"0[;@ %k. ˲NjVTTx (@@t#k@!~!~!~!~!~!~!~!~!~8.c B,WZ54f䭀p܂$I@દ:XjAj VKPjΈbq{ېX,1[ॽKmKPxt Hb؍sr6U ^d2JT*k^pV^E"l^<;&"""r>0w$RFc~~no.<-6X8Bѭ[7Tʲ,ad2YBBRlY*}ۋ:J2..J՚ &&.Yي" ¨(a.,FEE B.f+B[1<<VcU{ []WpeT*aY[dRbp1WMz+!eQ5z,% >!ϯɫUU::.j 3뭷B6t*.k8,Bd2Y݃ !qHRV] <6PJ5e2YV<[ GL/fEL#ILk/]ƌR'Ҥ>ML}zI]^_{UGo["J!4w^rvǺoמ1q@N|si-4]Q!3}2 T)}2xbfϯ ϜM9--+w\Tc',z^ZsB1p=XNg~Ya7q+;߭zN7Ƥg9U,zeKcFps' ?/PڿJD\z{WEdJI<2k5n8>nJxLRid ?iL5Kh63azLuqԵfX}iw#\iGvg\ɣ w]c窴 ԔS @/HLKh"'q)c7`Grio_f#|" > *PʩBj'뽷j:[뒻>Τޱ5l "'\;|v!SsUEeUvǧw4m؄0_>b_^nuENU4[^RRu" zf/rJoڳw"Cao'_]&Zp4A!$effаY黵uW8pxlnZHQrgNHL6aɊq>\0Alɮo,[eq!/4dj/l^09{Fr5rlǓ`C]N+!1a?3,NrVZQŲ;58$|qi芮@F?8KWer;Oѱ_q^HLS˲_;{ITuRqehiO=;|(Y–\1ju@U F[LjVf^phEMي:.\w\L~ Y[ﺩ-O?,S]b3Mݚ9&ֹ]<>7;y2xȁCd"I@p2#9S'  >f\bf3b: )Ϟh-)}>7wT_@PtI *rk=GԼWM{v4w}%/>w03Us!~83|K gF/irH{+S3gN}ǥm*>MK9q *C_|9-1g̗Ƕ\l/oykWb*ڰvڀ7VV>4_29 EwW9˕=~ƂK'ۯ0A6blbb}D e@m" v\MBkJh4vݕMO؜pwiZAskN Za"ASRZ<Nslf^ҕQ?*++5Tuj4Zܷ j^NsE bZX,JngffVZ4t_ol6f+cUfs(IK:Z7XV~&L&S{V3%k%&˲vn7 ي0[MDDFkd24r6ի$(jw&Zz=emEX,D"ovG4*ڂ*LqY@ 5z{eYiZ+**<P t 4M{!^XB!lE!lE!lE!lE!lE!lE!lE!lE!qY@ P(bǼ5fyt)oP(]Z$I@L&^ߔIRhE mS=|qkdr:lWtde}km;ЉoWSŷu Mec~/~WmmLxj怀km/z~ߟ(_4WJREQTzk PJ␤,&{8#XWPw;/YmU@ )qaHk'?a.z,xoS E3zI`XhV ;baX8ٛWoJzхO>iᄎQT#æ>4;'~~#-0;.T?j'|2wjUˋ>$&?Lngy3//gPt\ٝ?\3=5|{Qc<6WJV\OϿ.nD_'uHbĩ伎\P'ji5RC)ZM[8x(A-5tsb٤ժ19jjr Τޱ5l U^̾@i"zb>ȶp k^nWߞD`٧U~kMǞ k՞ms8 cPH!IYY4l|Vnma~8s8Z=#jmNU(X1="!ԲGGeWWVæ[c<߽^a,7ӮSQ2L7h,N*_p3WsrK°wM?]͘+ٝ4m’}lubegr'ʦ"Di/o _V_: j=yPx֡j+,:PC *d3h踌tuZhnYݢ.q,3zɲږ~qPIO SN{g&S<&YZmaz.Ն{4'|krU3)}GutYKp1|b/)PyD8S [x,[ϱ ]J"b?'adg5[PX\v$ak A,2nvű 5l{/SHnj $utC,FVrby,':{#v?@8QX5۫+kWiqYUo):E 1u?iPG$ $0Y2xȁCd"I@p2#́ҹ Ӈ&T6k`ɥShlV3j`?f̜i9G;g\20~q1wgEvMkw_)5;ikNmuXkEMqhf糏\RT>xh4ɵI.gLm> IDATUC1 #|%#5omYm8.>yUʣ?gU]c{ιِ'NScggW퇼|@O?pm(_<8eH}[~Z3 AROqMۻC"fY,lXl6[Fd@vTck<Ebccۻor' ]S 4FlmzZbh!rEODU6c#oGD@@Bh;N\[j2z-rG:1w3}?)rK9k;NX0[;@ %kv.BZ>[MTsVeZ t 4M.BmэBيBيBيBيBيBيBيBيB:@P(b1yEk̫f3Lڡaz;ut$I Wsap@/&[1u8K 0y)j2ūV[vxf+**j$^9ot'sz:@>|Q yzڍ6 oj*J*w)r'>OQTt䗍L?hp \yX gwr%ƾ# .B', S5$~z, RWrQ!76VtuҊh^{*Y83TT}"sO{a3+I$ ٮi k dz ^<;UdWh 뽰+&|Tjq綏ي$_N =}V hJky f+BkQ{@yLVA'YgTx?Њٙ*Y9g{!zOz*[Iyi3G'&G@A<Sil) 5w0f0LG>DϿeKJrWӶܝx$[ x?}ߖ\hb%]fԿgz&[kۖ 2^W`P߷ظDyTARXʨsSǃꉹZ=3>y㛳N*{OzpᘞĴ5l(uϒO&,3Z<'%$L$s|x  *gO#+5g4n9SDeWS>]GCksuTw29gOWDZOoyo(,:mOYtDWrk[HNNN%h+Dw ?a {8UA󻯻4^!rJ>xOH'ٴ\`^%I[ɿOTL_iw zcdV4(}{6^ZR_{{s)\m2xS/~y,~Lͫ7^Yf‰ptҟo6Q\Tʷm/)!ܧoܫI:Kx0wV?1g(nŚ [z_Wt"ji{(ԸfCa"~6}-ԦWpg]_׏%pr pthK31""SQcSl1u Q<nEV|3پm@>yJ+J_M3u5󧏭,kAҚJKYw?;LJ~S $wY|?tVyɆ;Dto.x8_#7';7|۟+ZOlю@UYUvh8cL|YzPr=^;(ʀ 3%clbݢ_۝@ZX< X_q;KZb Vy?qȟpźm̘9W8r2ikIKx wBx:'A8&A{/sS\ʖJDbv&L<>“jU0N!Z_}*+o<綻6LV[;sdR-_6vmiQvx%ӫ{m ÜܟUZr ϭ)--|Y, GL3vEp6M8wL O^&=#?gZ1#k/gzq[ ʗo^σ]`M?CPǔWkruUOtj|uW5{-=o.Db[Xtϕn9ӹ_e+xzdly DDZFrRwާ߽kBDDLg s\Ex [hNWTq?8{ͫ~j81z6% F"ӳՏl=y麎GJ<%[+uPU`<ޕ{RU8N[voѷAhpVH J J&GPܳ$rYB~.^D"P7 _?4(^+ e?MrW; i(Z,vN7H$kS-j\'$1o;h#CdI-JYVY!I&zni]'lIb@db)YdYe*g5.(ځcvSM$9o9:zf+Lf:z6ÓѷAhZa5OSdr:6M$,̂S몪&h4f- j7o=5dY?ԭTxV![l0xV![l0xV![l0xV![l0xV![l0xV![l0xV![l0xV![l0N0)p/#ABF ƪ_ymp> 1ӊg͌b9!npL9+IT6+{:uI6u&֚37 NGP7NZrb́,YշGMQ)bnP9y*M?t;>hqsӶBw>n1aYrS:9A1iRǒ+eHc;L׃]󂋂MYbk ^{dcD'zl "Z ]Z#jN'\TE '?l۞9f UVXQ Wv9> DI^[~3lc'$J:)ъz.t&nkN; $*e z-mk<7ʌ"ύ~R'Ϲ+\QIW/)]$x5$aLx׵W҆;2ǯHΣړϔNdž+{oفN")[9=b~wǤ5Kl(^6iDxb[aR#K-<ׄlJ]DBoN{`$s~*Ɩ5&) g޵KO߱hD%"Vl;wZ#aF,Kn6ہuN찅2I'TдFV5m/>.lmcHm)~@( [/DNi*#"bw b)yUQCmG$AȝeWeDv6-)!:+¸zHUN/)d{DDunq"'VItd ]^C+׾*ZU[,3gZIF8Sf)UD@Jt@g-rٿY(/0YUbwy.u~( 0[>FDC]r"A$3}6'>b*2E>Y1I?~WQѠ DhM(q""^<;Y53 (!9k8f-f"ML43 [QXy̲gxvM*gR=WbQrUak}hCQ%)u|dKN<"m~tmuZ9˝{cGºa}}_!'=>"Hvjcl)tQSM&-ngrKC˲Ԡ3̂^ڡn@>ʈ_tXl 00'7* d+0'`<[l0xV![l0xV![l0xV![l0xV![l0xV![l0xV![l0xV![lS=M/EfsYYX,$1,8]qUUMhe2+[8R5x*9J;u¶L~njkksblذajii.$IEQY[ZZ|>?P?% G)uMV#U#E6FLI$I$uO3]ɹr.LFUU] j3t]WUUQMӼ^,ˑH?Zt:EfRz*@:)Ϩ\ѸjB5zMsZ^^^YY `,]QU5,lLn/ )Ҋഴ}wj6GH$'z<@ i9>'[#? 8$|۷R̄(#[+++fs65y=t]$I3V{\JPE$2I `_CkN'Fo:Nc*jB~)W˧]&,ٜJ5.QUjR(*'X'E#f/Ll$ ˭ TUXjA6+|҂R4.X}ѡq zV9/E1fpDV9$"W,~q.":a0(ru9?S2^8)=6IMG|͛xg"'sN<3ƭ=ނ}pay ].2ɡnia*躋;־(^#)Ξd}{涅cjiTJ(DϘ{AyumWW];gjN;{qEcJb_NVӹԏtI@Ӫ7NsI ʤQ+O?[dɖ0g1]zQef߼a+1` +0M."-XY]}Z'y$~1xDE{k{_c=8eIT떵MD*=סsm|-HmǛ:2q$ˎ75ټw۞Nb̩EW3wl\ɥ_a)^ s̟վ7I9J+Eؔ٧K[ɗviZ-/W>i>Όd( ,]zΝ޺5U,q͔(~l&C(p\^б=󅺘[fV]y縞fI X<O9,}$:sJ޻Xۣq&]ql ~NCb\QkU5vtRjyn[0C̚a8r GBa6#RKKnzĎW_xx?ͥ375[/&/߻'8Ϧ0e |4n 6n yNղEok8˥go]GItwko$NS*tW-fvZDb"-QU^":#͜>_86ӟD^X PߋZpWSVfᇗ3(/⑦藪 =3ƭGӶOGfJ"Z9Ğl Be;tƴ6%؂wj:uveNS W׽49&zwz+oU%e5cU[x<՜KfU<ɭ*^S_[**;}4k_xJ)0 cgNu< %G?aٟ\a-V"&Nv$F]`OlU8+ ddt#9aji=RWcjړUŵ9 T¹\mojlMaᬥ/6ʯߔ.q.YaU+ w?~79wzL{jp ׿~5gk JJD8/!9ݻwk$3qԀ@U]w⟭o60T[ |`Rƍ !?/y} !/#&39k19s=Aɕ 2gUd5L^f G*` jA{^xuڀ('‚aI$nr&o0:8*.^.wWBs>#>SeIEMK񸪂C }z*];Q{R3 bf?ƒIHI+x<;&~gFI([fɨrkͯTTE6?m?j^<wNc GWs|\!5\e\p>2wyPQdR#D]&{/,qYRPu%k֢:n^{:]n#Y N߲m H }(әG9"hĜb`JRV<7G|= >]-yXҷoRIEޑ䝛7bޞj ]pS[Wm:s6h]'g;;Gx+^OI/O_8/Y9S8ڵ[,*}򻍛ӊyYW $^})g7qw8LMGVߵ2Oْm|J&Xo av}"jf: H+%X+W3G5uKW{SV }L}yu[}IxfՈw |RLWse55J(枨Hq>%YzwI?l' ^f:"'J4gŜ7SRu PS68foGG>lI[1yP{)3dfVJkw)fꣻD5VVeRI;Gg;4M}~Ç˅P IR$|e[p}||***YJq~`'XWR<.j ڻP5LRJe*ᨨf"I_өTTSKKښm4V6)qZXI^jAr/H!]5ݳ|TTFn7$IjriܟL5҅E"wqj;)nݺIR~d Jm"׮ TRv([@ѝET@cyZ4 dzڧ0UkC[ 98 QQQ 4'R]X ͬ gu\Wcܑz%0B+áy:5ְ4(Nުg>VQdԜ<˕RLJeA&IRq\q BGM7c`Pa.;{Ea[ޅ@ՏԘͦҒ-A2o3wcbEAAY/.K%o[ &@I]Oݧ^#Fv=ܙ |[t;{'jˎ d2YJa౪PׯV d ^W%|c"аp%d->̿o5͆W>K>={ﴨ !v@]e~؈󦍌';|;/v:XU~™C~|k4OT{F(ي XV &=0gP@%Zxx/s82tKCvИnum7obquq_~;D __uڽXtf拂2GoLe-[5-WE bl{'Uy!:GILzmuOQEQ%¬C)Cg,8x]ax<$]ڱuUΘ_Xs`gx?x_Mtꉏ=5wǽ*bsݙ04`f+sO}<`']~~p`/^`[ ~;_Z=nÏQLͫ>ܢ^o@(ι%N {foC@4R]MkNY.rvUH^wjv!$9h~lL `%^wuF鴚C)N<6P=ǎ['6~:evR`Mu{.,&ɧCɄ:vgMyu_w1%|l)9}Qn'/~8{)XW* ۶f"C)GѽJͱ+ƒvs7y$PxfK(窴\jQ{hT@4R&7澸XWT@#G^Z?Gy0hY?Hy>c {5qJ3TMҸ n\[řϯwX]&<\;QB1eQ4>q? w\YRՂNQ}>ŵ)e||U#/%k(.\i=.RO_naˊ\Μf+JKnwPbB)Lc,O#r'XU$O c + 珄k.X?L;-h]8ƒ1($|, 6>+}n9ߏ㙑UC^Ƽ̿|GfZ A%k;qkYsO8@a}v04,(^X}"99k߽w5y+ô+?cEa'[,?tciPi"W'@_1=]>YN/.ޥx ^ /9⬷7BeYQACe+i :..VSgO[6*˽<: Zs>*u%0Ȥ7L"Vu%߀s*"-,[.Ն{4'|%Ԩ´cy!DH\ =yL9*y9 1T}/:c<@Ͼ7@rM[ @L[OoVnOU*| {w4{0c9v`ﶋ^0&6$Oթi+4l`#pO=4:_7i\|Uo):E 1ϭYk0T7,{ej){V?G߉( $Ur:(ޟhu8h4{Nj jo).*8}n`4i-8`Ar!AW]ߓ9+>g-^؇Oq{c0ٟ7ӟ:53e|?֤1_ gw"7JytG.?k'HXa"69%OaQ|6vړ6+"BBfX,bwX,6!kz+`wiml7\_\uLBk)[hv+U֊ @:DEm (J *4Mt:V@5jy")s;LU/%d{HAN'V ^_Uӹsqt ڧ0U. A͆뤠\M ~h4vhDjjZ%I0tQ{-紒bIB"PX`(ZX,JB l6\Shf,k2KP,LU/%*?#Y)щTtyy&am6+:Itw8u7ߟe@K X(DRͿ jKNCj%EQKKK)x0v!Oޮ>8aוWylz> *V ݸ\|i,= y$`VW?j ]yg0 CӴQCu.߹rYzCll6[0erQt8N/}|""8 9A|WYbFs往҃ Ct `_T2T] WZԊQ suK`v@&WzKMP;+"t8ZT)"yQJ3k0UBȝpB*B*B*B*B*B*B*B*BYB!y<.mXu:6CTjU E{5$I@3L]uދ ZݲkvP(Aqq"'RTRKn ϧ(jwA< J$(KTAQH$R(E5*@{ޥ,׉T{* Z/LU/ޯIbX,V.P) M >z@d2JR*+w8 ^o6[spDz~"W\+O)"(""B.j_e$IJe4 v{uHuzC/ݩq [nReY dRٲwHydv#TR6A25q>LUtG8N(FEE1 ӜHuaY6**J(9O6{)tWrebxx84ZVsnj4/+x癍yLx}|g8lu$oϤYmb͡z_QGӿ9)I48:HNL+4{e~>՛Ea=Gܕ#.@JVNݴib{-G*&͉, 4fÓ|?WX&B:xνcC/y/9VP*,ۂ#d2TjX8kñ^Oqj.9ٕdԷ-=x# 0&});ڸƷ><ž,{_sכJyS{2oIBc'Y7 0i0ka7FBv>oj!k ۊT@ϩ/.4 ^+yȤʴ?81O0|YS})}_?V M[0Li;ϯ~tn6Ul )|s/0ŝj#_'Tt4s;/O)i~QA{Q,`уFwwڴvKC;xʌ +746UϤ*!9r W?g2<>ADHCcyV?ptɾ+7|r?SAXO;/ rn%CJY*[YCw?d^x0B(nlrg7~r/Gf~,^-#46ef؅YvukVBdFC␤ݥB 0xl֡{d27Te%N())c;]Էtw#Ι:,6@X]z.cw]]&K.5;͙-"cS6)S X:}۲ẉ U<{1U_|ˢIs7BglfÁ+v* ޅ u Qw$%)6cI=: ;}d|۽<3۾741Lf 8 v+±gsL ߗS-OsK{7\§w|jt4w{-\4V^[Tm_A}ן8u_j(UKtYR$HeY6q%q-N9aX {*7V]MY; g;l:OYۏחy|{"j!J KGnl{T%TC:qACJ9npaw4@E\Ԩ zVL\)>zv}gа??e{f/,wsl?|$ ˜@u4w_]V HƁUm=Tn_wV,Ć IDATrϿ5ͧB,O[sni#kTr_cB9qZ_? xŸ5|>N<8x,dJ)j<q|>œZ(C{3m V7>zϫd:?IjJht'V&٭Y.=-Qe g:m\W7`9{ђ*ӒxQ[dH!269y uϩ\g}BExlʷ}{62^ !_6:Y S/nt-nmPDC^^VymKߧ(:+˿\cՑ!e糋Z^ ^|Uw|b]ڕe2mШMryPڧ).2 *-z~Ɩh4Zmk+P ,!P;Cձ ?\h&gkw‚Զ<ϖܛe &zyUk'\F };_ٴ|;w/ kޜq#kWO smB0k@Ȳg_xr㲟{`h,BIJ2̠awk qTㆇO|v{L_+~MןpxSA=rރ%xC ~co nOUQ#T߹n #ஷlLQm2~ۉK֊w~=Shs5WۗC7og|䖄a7tm芫b#dLP~*h"0_vz˗+v&<>dYunZHeɏOPKϙOrZyT]$oHl7˲ACe+i :..]v[6*8^-዆)r"y/ ^xtݩmXH$/=آkw崱 7Oyygxy&!*Ktd,R> P^P >]WX" SLz ՜\tt>K^\҈XW='.??yT?ͮ9XQ)!}ƎG X0gD~}C/[Qj2? -r}ۢMyY?Y Q*EDo#nesZ>Q x= $i4ۯr̛eA\ڷ~0p m4ѹ}2hn )"IP%bʜXO{o]}n<܄rŷ\tD`ų6޶Nw}(S} o/ocЃt#mbB? :zz5# ؉3gOC '^^5Hw.v~3[RY.o{rzݹ5~V]AЖ-dيhf:?S`8N(Un´ULU/?4Mt:V@ӵ0U.wѧA:Z-4{}UNUotv6P>LU/uTDM ~h46͕ "fi4:l|mpgOF~f\ZMZV,KRDBQ'v2 cfsMp Rᶨ5d2uKWUVVz^fazBMl6Wt$̪SlGB펦*` 2L]J|,vDjz* z}mZ ;N P%(QA>o"(gL&lnq9; ޢ&Z9fb)r:55s3YRYVׅgHlOpa6KKKgx5 :n7kҲ0LzU!0U;@ %kE.˲NjVVVzu8i!wB*B*B*B*B*B*B*B*BέB8cqM,l^\0U[$)\O/EZHEȽ Zܺ+ @,w)  SKNUڻݶ . 0R$IX,a+uڰK?B T*R}!QQQ[yD6SKxAw4H!] DJ2veOx)X)nݺIReF0 #JeˆIyS]wQ*qqqX111^uhLU8N(FEE1 ӜHuaY6**J(zm1UB^мZjkXXmDBϕRLJeA&IRqM5몄|G7z'??Sq @u-@ut\BmguՎ 7vpdJ&+vmy'AL& _i4$IJ]+fJL&k6mSJztΤQb\{~4r@*{OzpᘞĴ5l(s!Mzw>EuşLW51~JU+Rq̤G}ҳ;}2tKCvИnum7obquq_~;o(*>mOYtDWnӗp MI/|& -9B( $I:ʲlే3RKtZ*UmF6MU2lCCO|W>A1B3?+>JY鋗Vy(%qXJ:v05e% Rcblv`KpN-9TB5p7y$0luicr,RSNy<* 1i$/u'}kT߀e1|Z6|@9XR(lGjw7xkݚާ}i2[%w}IٽckREX'O죟Z |vSՅNvǧw4m؄0_>b_^nMeEN4[QZZ}" zf/rnxdD(L7Ú ,NB5rɿ"ڻLh,1BIJ2̠awk q|Ioݩ1, Iݰ(8Θ+ٝ4m’}la ]+Xx--9 B_b{ Մ_?`r. dk݃'6ST Cb¸f[@I2eYQipH2_ qp^;M-^n`/+1*c?ܼXaYqٵ'Kg\w'Xc _rK_7TdXjy[JQ+`0:Fg0C,znRLUq#e ڢׯڢ2o=-K{?37ukA伧#SpX^w=$=Z#v $}ʍ48cOq{\0 :/$qnXILO}Dŭݒrgs{GEߟ"'fك}D )h΃f3vfje4qF>^\TP{KqQuv MoWe|s̩MEهW`@!N!N!N!N!N!N!N!N!N8 B,UḦl6ϭm0UA P $)\5ɤ뛳 ap@/nYXgr[~UAjeFG;l&#zLp2`9S'  7*`=hp%@RRi{!wE5vi䗏L?hpn^˂Np`yꂛ^J w)r?HdX*%cufڧ, RWrQ!<ZؖIbX,T.H+y-bK>{3_qwQjs4J>>>M6A&IRq\ XkQ'S$Hzrh3:z۟glf楧bώ8ҜSؙ] w< F;Fϯ~tn6Ul )|s/0p5z6  QuW G%LKy.ߏɨ< 6H]o9 !'͜SJA_ܨ WIxT ܱTI G;L& _i4$IJ]+fJL&sG)nRW ɟwu([gUJ$bxt*j$|zwTj %%yl.zMz`Π.JU_&Tq@Ȼ͘?wRN|u_?oD%=:g(1c.=Y]_|%jso7q@3E/WɈE?hui)ϝ'җ*A1BSBXv·o z']ѱN2hS/yo){w~9S BLQ{5 3籹Rbz6=!;M§ĈS빠vki5RC)%ZMG8xR@#5vsk"rbv[K/]&}O_+lHas/ȡcԚ-tu]rG^~;-ٗ(MD3?aO'T\d- .‚HF}x4_WUP'[tʹF6:>X2eAgߍ8+6TӃ)j?L-~?|ZWN>οf?6<#j?{kO 3*95y+ô+?cךL>s;'$ |ӥk/ڌٿ I&,Y1ЇVg..-V_~fKQw|j.rKd_K9PjVqh e>LcpΓg EWl²?48$|qi芯@F?8KW閍ʺMꏿ7R!9,mn U4=edwv?ohyGZ8^-*5\TB֥p4ySZ{&O^]~W.>~ O%%b:g=vaeWu9W4}5ZIDL'$f Je%IXjePf Sq"lTEd6E_Ee {aX@Lkm9]9 pJ`=~`r (7kg*Ϊ7@ϘGກ4(F#Duʍ,<`2$S\OUyAQ {*5fҩ`4{6g?OR3fC鴿WiJ3[\?i渘k7;΍Uq&;qZSa93TQpg4E>^g70hZm֌Y?j|A'IQ IDAT5H _qj2 ;V7JytG.?k'Hʯܹs•Zv躏1$Ĭ1T 3vˑ L?~ |45vxAvv5p~ț= ۊ. m\fpro,G/릀WcY4for fXZblUtG5[k3j^*66:&qBеh4vݕ֜:[󓵕m7mIp2SK9N@ޥ@w:JӴVRT"P11 l6lj[p:h?ty1j"#=t\J6 Sl$IuUQZ#]y"(Orԥ:>cz)vU|,vDjVVV(08n!=ݨC:nXRrż1 CQH$j;AO d6IXv$ ӷL#O CLUeb Qڠwn&ZZZ+*:`8GRi(>EODu6c# ,FD@@Bh;NӣV[֢j2zMrG:1w3}?)rK9k9;NeX0U;@ %k.BeYiZ+++]#,C*h] TGa! S! S! S! S! S! S! S! S! Vu@Pb:׌Uf2nijDžpuё$)\5f"6é@HIlŜUa,?ܖypuEZn%N6`Hsi 8XEIG鍊##XGk8\_{T*Tޥ@ȝ|>EQ ^a8_>3I k95rA[ò`8s0<,%.EpjF w)r?HdX*%cuf`9М_y1p ¶Tt7Ҋh^{˫X83TT}"CSKas*I$ٮi  dzR<im3BWop\*5&|T:q $_T|'G:8*B+MEy*B;Oo:BԖ/z"B}\IOH'ٴ\H^%I_ɿOTL_iw zcfV,8}{^ZR_{{s\sl2xS/~,~Lͫ7^Yf‰ptҟoQ\Tɪm/9K!ܧOܫI:Kxd;ۃ_:="-qLE6vv&L3>“hU0N!T^ *pF*}六w k֎o*-K{wC_z^w:4|b0'[=+wkJKKk'wNKae21S鴯]Uo) cEUp:BwWoC=nO)ΚR̈+bܹ{^yazUj> g}`XO5'FϦdQVVYdz6ʑ(]88S=ǻdkH ǻT9~oOQ-I ̷@1OGT=ERx0?w-1\p_&d;萪H$2Mȗh4zM}ʖ7BvAOS9OG'\&L_8CnJ'5(&MXTyɣcozzвWޖv^pIp3KvmcA<~l[2]XZ/޵N2cKxRk]uD1ɸ ħy3Ǭj+*]( {+toxaF,ᐪq\8GxN۝q!;>`._xc@R֠wѢK,ز}~o!"kaʧ%q|{%tɱIWNF'~]`.m=s0WL#r+5?*?bs]IܮED*Lt=l]\er_x&]K4=FD\|~Z"bI־Qz5fֺ{o[#D6[(Y$MxBMdUcv)iI6F^2Kq`Nlwݖ-2""x "JZ i1z{:" "E\/*#J)qoN 9։8ƪp4Gr:&"K:qd"zD8Q3[d՚:/))+DZ2/\;IQۺ71Qq:1$./l4Kfȩ$ ɩ LH@\PgZ5~ǬAўmƘ@D,Gut}sEǨ^HU8yjܹ?u f_yjۻԭΞ2̦wۢfSY'2_0/<8Iv^2@Uc/T5oz?ztu*`%ֳ[E"NL799#"I䮁]^CˊW*UG,3gZ%' `L-W)`FeFdNLdVL\4;\l{IwɉNi[m~O|TUd$+V|lg3U5:#bvY~d0>AQњ:QDDxfi%fk.Og[:QBP]Y;lhZ41OD0T#a c削2ˮުΦŞw>Da7 "{ 7,4"дGJRĖE[S}kjE+ U@sҕwJmk-"MيQ!Cii|s$I( Ȳ8U)92n):Wk4ddI"DR7-.|!ӕܛ.+یx>'UE? 82$| ۳\̄U&WVVVl6$ <@RU5R0|87LHjUNT7UUN1UOV5R!Srȵl6R~~E pbTUZT% =IшKrȕ$a䛪uӹ Y䗢qjQ WoRF40r_Tb0ru3BuQ_[\t8&Ua@fRs~~Uerx{l7,]D>O眈Yyʍ;fU{X?j#@(rMdݪ3ƪT6} w~g{Q:GRm=!Tɖnn T+^ӈ1PΓT=+6:y=ziu}v?/ҁo$'"3UHf$ƙבv>x$~yYnKO䂭W8vD$[Ŗ/I| m-LmVɟeLk:KfkWZzSV7oCc x\N`6u#n谗W0"),뚦@g-B:5'm]X2ޱ~s'a8^$x9/oγ0z}wo3ZksV6#\]!iO8L_.}::b}=>^C;U^۪#5CuivY&)^)ZLDQncm{Ku1n1=?͒w6r·U ^XtR;|p?KL8NA v޻d^M׊&6cm|?ý&̽(5pz:8ldGđ5~mvKλo75$Ч8Ϧ0]e|4n 6n yVՒEk+_l]KItwko&NS*xGɣ-fv(ZDb"-/QU^"_YuVC;/>u{86|ݟD^X P*z+++3QDxߙvHSEClѴ{ӑRHh<+DPY1 6ҝluND]٨TÕwuWMn#+<>;aXUEIYu)2F5g@d.?}浛-uU՝Sacꞏ5οrLkh[K1mK:xsP˸ӹ MJŖz+L|&ѥGc"N,~J)88؇v cգeO3}ʕMw5nޞeVBl"#Ya@Ņ VHUĂ H(gAZU\8ܧ}zy&j9R<:OHɽH gyx~t?op.$P&W " R.TSd ly|B" I>ةآ(G$@`UR,@".Y2GvX@`B, 8C L0ҿ_pH˕͗K3w!lBa)f "#HL 8?flŢko">!N_puk[Vh]3 Z zy8@P< %b0>3o~@zq@qanvRB1n#Dž)4\,XP"MyRD!ɕ2 w ONl~Xv@~- g42y@+͗\LD*A aD@ $<B AT:18 \p` Aa!:b""aH4 Q"rBj]H#-r9\@ 2G1Qu@Ơst4]k=Kut}c1fa\E`X&cX5V5cX7va$^lGXLXC%#W 1'"O%zxb:XF&!!%^'_H$ɒN !%2I IkHH-S>iL&m O:ňL $RJ5e?2BQͩ:ZImvP/S4u%͛Cˤ-Кigih/t ݃EЗkw Hb(k{/LӗT02goUX**|:V~TUsU?y TU^V}FUP թU6RwRPQ__c FHTc!2eXBrV,kMb[Lvv/{LSCsfffqƱ9ٜJ! {--?-jf~7zھbrup@,:m:u 6Qu>cy Gm7046l18c̐ckihhI'&g5x>fob4ekVyVV׬I\,mWlPW :˶vm))Sn1 9a%m;t;|rtuvlp4éĩWggs5KvSmnz˕ҵܭm=}M.]=AXq㝧/^v^Y^O&0m[{`:>=e>>z"=#~~~;yN`k5/ >B Yroc3g,Z0&L~oL̶Gli})*2.QStqt,֬Yg񏩌;jrvgjlRlc웸xEt$ =sl3Ttcܢ˞w|/%ҟ3 cHRMz%u0`:o_FIDATxgX߆=*4TQ{˫$kb1ĒDc-Ć7 JQڡ}?'i>&ffg%Y*R[ $$$'$$$$'$$$$'$$$$'$$$$'$$$$'$$$'$$$$'$$$$'$$$$'$$$$'$$$$'$$$'$$$$'$$$$'$$$$'$$$$'$$$$'$$$'$$$$'$$$$'$$$$'$$$$'$$$$'$$$$'$$$'$$$$'$$$$'$$$$'$$$  ,\Pwv1113=SSSE. ttt011QZXX\-UԌ˗/xpQ͚5M={vիeYcccQڄYɼxŋޒ$mwttfmmeSަ={fihhH5(_<9GW e=79JG$*ݻwx">xpPDDDгg,˔)CӦM122zg *ZN- 勌V˗gϞ=<{q\Cw2xxx葇ap)t|^9NTH@עE xaիˢbbbe5jn$^lGz:#gk&ڄ 5k"2111_eQʕ+W@gPX Pқ:x\\\!9@]M&e39 QI4 ">,f;###ˢT*:::D;PɂWvT*UE0d{)a{( PIAi W^w>έ"8H~BBp49e:tR9okqzBB%Ue}9BBisg&eso/ڄȌهjQj9 57po4!wC MFŊqsso!%%ǏS9GEEȑ#)y/eH9Z?{Iy#\QrN'ɲ駟hذ!UT\r9sΝ;֭[Y&꒘HR *2.֫ Uh܅\^\9hkKg0~vÇ155^z @z a׮]XYY1w\*W ;w\2XYY{_'py5m 4JӦMy wfΝ?qơwoȹRŋbnn^_B8'*![2gĈDFF2k :===Ξ=СC3g+ϞR.WIB\**Qe\z57odРA 6L 7U?3,\W5:t[[[e>#\\\g$%%IԩSt Vȑ# S裏F,^t}Ν;ܺu *T@HHTXooo>}=z#Gjժҭ{wΝ;8].IIIt҅5kr NJrprr" >}ѣqqq͍/8t_΄ _>ԭ[~&UһwoܹСCqvvbŊL0hcFDD?ҪU+Z*SNMӱȢE]6J 066?L71bF9>}p%ڷo%ƍ+:B3)MqԽql ߏ};{WF jԨ[rzJb̙ :Yi֬O>e̘1L:U 9YYt)mڴ!88={ҤI5CBB4xbviܸ1Ϟ=c_>!C(]4VVV7cRtlM6e۶m4i҄=z|ڵcϞ=[n[___0`۷gΝԫWYf?+ѣGXf e˖K.|ѣGylْcǎѠA?>_|aaanݚ3gСC7o#F !!x݁ӧ3aTO6mե^zYYd [ƍCڵ޽{x:w̽{hذ!$r.ex9>>s$ rB`YP|]9>mC:::… 億yΝ\bEy߾}rbb(UV---CɉrPPlkk+7jH~(LNHL['OqL+++?Dy͚5ܾ}{ŋrbRޛ&߿_͛\jUrbb|=B rʕۆu֕ӧOJRV*͛7ʕ+-Z###,/_۵k'+ K.rXXT*/ʎܯ_?9""BV*e+++KmttfJR>{lgg'תUKy'Ncbb4rssݻ'+ώ;˗/^z| YTG---֭[QQQR?~,ʮ͛7eR)8qB5jq:߾$ݻw?er``\(\M-疕d 陘K`FsvvM6,ر(J===qttǫѸqc:w~⻹annӧOIHz$I>}˗/Ӻuk<<<sttۛׯ1>|GGGJ.ͧ~䄭-Ϟ=SFFFtI yFZ|֋/a$IhтJ*ɉ߿Çr٤K*Ey%Ϟ=Sadd$ 8ό֖qajj*di{Gbb"鴛ʾxIx̀0}3h_{%CCCtttHNNγv;wۢ-Zﶶ.KJW/'xoVTgV^ӧ@Raiin{fziT*6;Jٳg?>,RTԔ{T*144$66PJ. *JTRi@W-]ڂrqEBCCqppHm\\oԔJ*3JBWCJ$ === LSn-#H( tBǎ5ӛ^aaa  {ˀXnsN0aB+A.DZc6lM6%$$T*՝;م{zXx13fٳ$%%{n4ARʶmHJJB9+VaÆplْ?;;;^JPP;͚5 ^p2oko޶ˁ d?ӬY3hذaҴiSjժ͛y&LN:Я_?<==;w.#!!ʕ+3i$֭זTtiδiӧԮ]2{lǁpuuO>3KyݫP(?]]]VXʕ+Wk֬alݺ5GwM6̟?yn:<==ꫯ6lz;777>cfϞo칻~za||<+Wf-TR#.\(Э[46w|Ԗ[,ޗڵ+-[?DGG'Wjn5;ڶm#Gdĉ :]]]dY,Z/' RվK@@@Br[YJ}NP,r?sŢ ֯_Byꪝ-RlYA5v69Wsי RեiӦܹCҶm[IHH`޽lܸ?Ν;%KIR.|V(*(}l#_ASlY.]J`` QzuVZEfNHH+;ٳ|~<Ҷ ZUVf777i߾=۶mS36{llmmٵk?3ɉm۲gϞL;d<{&55kRR%?ν{puu& !X_8p Gnݺtܙ3n8ϢEToӹu>>>ۗ&q]\\2eTIIIZpڵk!aaa=vXǢEpfcƌÇԪU kkk9 Aؾc4o\ ݻwGOO///=J.]///ϨQx%F݌o߾ܼy]bnnοqssjժ~CFprrٓӫW,YjU ²eHNNfРA)&+9p;ucƌI̙3OT~G9ѣ/CT2qDWҧM@IIIܽ{UVѴi3ҤѣտYOҮ];z&3fGbbFӧOWJb׮]xyyR2e ?3阮g ڶRJqF*Vȸq ,\ƍ}ڶm˺uӧߧӧOsE? )))<}{{+ ۷?yѬY3lll'l۶$>S d\~ׯ+=zĮ]([, @OO֭[ٱcÇL2+It֍ƍ?ܾ}okkkO1O77!i[[[}xyyF$E:###:uꤱyygmm ǎ̙3Ԯ]]]4$VZ燷7'OYh+pFB~HHH$1QzI$11iӧk.,,HT2{{{x | ifCoy!'OJ*8i?}j``II [Rdǎ777<<<~:aФILFFFؐqo%Wz3B$ Y&J;"^sÆ lٲ:н{w-],ر#~)lڴ۷oSv6^zq͛GTT=zuC___c,ܻwOݛRXv-׮]חʕ+g055%!!/^B\T; _WW'r5~Gٳ:uf͚1r8m͚5l߾;;;BBB={z2eЭ[\*V'N`ԨQXYYѨQ#8vÆ iӦpAJ%&&&k222ʒ`֭]W?55 ~aLLL޽F/p1իٿ?|`ee1ϟg׮]m6k+U5FVZ'D tpp`۶m|DEErJJ%3gdڵ9rol߾DBBBꫯ:uz駟1ݴ{֮]ԔyѸqcv͞={gܸqL4ϟrJT*k֬?}-]4ÇԔ;l:::̘1Kbnnʕ+Yd +Vd4jHnT^[rezݻYz*Uпٻwom 1c0h _κu M30ZͽpBT1=+-Dy,%@Kٳg_3bQC ֮]Kll,E9r\;kCBB"D-JR@NHHN@NHH\ƍǸqDQ.TE89!!rRd S=ޤtݻ 'YO!!8Bbmm'$T<( Z)8OHH.Tpxyr͙&$$$BTB`-94~un"N ND~ qy脄Dp`g[!@!\ +,A& k]|%e! =b@.'^KQ8+],ZFKD.'~ѫR6X**%70ccc %gx}JIIgҧ\v5_'22FIttz'Ox䉨yBpچKaӧOi޼9իWgٲeZ?J̙3ٳ|D__׫N>kٳ }ǏkTCDV^uԩS5k[4>{l9x ?nnn/_ 2p@1c888pyҥ =z4MX;h TBr֭ǏW=""֭[Bj՘6m111پ!!! >777\\\С۷o'55bccüyزe }xLFjըQO?ҥKTV_~X>C ϷB![988˖-[x"ju1S ٳnݚ-[r ݻ33Wϋ>snݺ666ԪU +++vMӦM_>gl֬YرcQT4i ɓٸq#|Gܻw:uСC.^ȼy eѢEe^&MRO\~ӧc``ʕ+_>511kkkdYᆪ\rMN8x 7n+K̙\x~1o< )))DDDPlٷ L߿OǎYj;w7Ki1rHΜ9޽;͚5R򻰓ە7|}}DEEpq^|IV000ÇٳZnȈ>nܸ%u4yرǏӣGի^omm:-Z#111ܿe011رc9sY} nFjg L6m!((H*! !@ڵ{.ׯ_'11beeKxx8QQQ8q;;; ȑ#IJJ"..Np˗GGG'G甚իWQ(CR8}4#GF888m6RSSQ*Y2|P?M&Mhڴ)۶mR$I8;;#I<`e!b,Oiݺz`jhh(.]F+WMR(P(xyyzjeժU4lP$I[BB'Nm۶HHHFfP(ի.\`ܹDEEѳgOڴiChhhT*dYR[i"g6>>>ƍ111{;vգy$&&{nRRR5k֫^122ʊ`֭[tR_͛n:[ν~]k*UJP(ӆEPЬy348hggdž P*,Y]vQN&Nq[+WٙիWs)umzaȑ#پ};d/!wyR6PwLwOHp>Vf)w(Y+e%a1 Lʦ ڜ_@Zr'! (W@(i2.ȥwE\eb%D΢ߒsyF^1AY*+I>@BOt3%a+z^!*lJ>ׅ /1;fTB [t{`|)ƄTX1)ʝ\aQї(CKޝ!dp~RHR= %Ԋ;ɜprsq}c$>:A\^\||̜9sP(4ߣ{ w+,zXxbb""((H3bT.,Mz#$U=ݻwsyTJ] ɀZ_2WIV4u[=~!C0vX^|5"|0|:vHrpuuwޜ;w.W0SfIj:JY ŅrQzu ])er?Jv!B̤[ Ϧk׮1p@\-^^^s:ԩS,M6-OBBpYi[yUDD~)ofɌ;VdBBBXhޢML؇9 es6n:Ξ=K>}0aF̙3quu8Νw޸QJȵklDNpqqJ* < .hlFʕG kGGGN>^]*WLrpʕK.Cjj*vvv,\ ڷo^^^,Y$MAJJ +WI&899ѤI6mڤaoڋRSSٲe mڴZ2el4h)))!|嗘1azY;v,666ݻWh|qqqܹccct邞^Ӗe-[F6m8v7^zݻ-ZyfOW^ܼy}Ҷm[?ΤIQyl۶>=zLӭFFFKPڵk<}H ^zh|}}RXd ݺu#22ƍ3&L )J&M'|BXXZ‚Yf#u(.#߿?o-ZD-r reuG||<'O$55ӧO׋/pvvvTZUhk"$$++,tk,--Y~=9s={SF ʗ/_ETT=ݻw૯BTRT)"##2e ;vz >۳`1668___ 8qDGGǏcnnNjj*Gk׮H100N:^۳gϘ;w.]tA$lٱc]tE__ݻvl2|||Xz5>|^zio,[ |r,--e˗3n8Oʕ+ӓÇslll TXw=ݻbmmRXY"\Qsy (J ρ{{NEDDн{wU^Mǎ H#[n%44,--˴jJXoׯqppҥKDFFӧnݺ?h^xŋqpprʙ^[ƍԩ ID%Jxٴy*5122R͛Q(%Icǎxyyq)^ũ]KHJJw$''CK.?9*,jfeRx> GFFF鑘HRrrRSS~: OOOf 5kT,ӧOF_~9sFݞtYx1cllk׮%))4aee=֭[}?-ZP~}طo|טTR:tOOOʗ+,TP>5^^^ź8\3͒ԪU{2uT9z(.\^zlܸӧO*U߿?QQQ۷J$I 2:ukn:DFعs'{@F܌+V0ed \];֬^#}j~ȍ7Xp!.\O>$);I~PT)<====nG{֖3zhbbbؼySAi?.]ׯ'88Aw^uwww$Iz~jeeԩX"%Dg{ z &&&t5.Oj=W;\뉋# HTbы*]r+B mKJžBgPa41 vrR\TODԍb?EIdu{,ߤZ(D*!j!lƏWc k 6mڤ^CӦM鄄PJ|}}yz?͛7ŋ6lt|ua|6f 5jG۳{n֭>>>\vQFHV}+^SJ9s(]FT* :uꄋ UTaA\8^9s([,wf4lڵk޽{5tBBVGTR *Я_?޽&?Yd |gFÃrѣGΞ=+( **UСCv?mhѢ۶m>GӾ}{ۇ$)C__Ǐ@xx8$''sQ5`=zݻwZ*666iڪw5@P*ܺuPzzzԩS'OҴiSVXAʕi۶-wޥ{|W$''kپ};cdd_̙3 2c 8uz͛ۗmr<(I'7660k,_>ΝwެYR ѣG4k֌ZjczGNjgϞ3:w5se˖->erYҥKDGGS^= 4322Ϗ{r|}}888ŋ &&coo;L2gϞ/ХK559so>Ï? *7nPbE?ɓy*φ}<311Dxͭ\ȾUp-9IIITR!CpUt;Μ9Õ+Whժxլy)xzzƝ;we'NPlY:wLHHCRqI]v닱1AAA$''#ܹCϞ=ȑ#Cݻ'eʔ\|uj@֖aÆ͛@__QF?~ѣQ*O/_u*֭[ծKKוU $IlR 7?__{.7nf͚ǛɲLeׯ#2aaaܹ;;;FBjժgg|+ϊYۭ\UO5߸z*:ܹCbb"/LLL033cu$%%>'..gÙ3gZ*|III;w.\@ٲeqssKprrʕ+DFFrEJ%7J*\p(^JLL q]pwwOfVT 333޽K\\z!om3m4N<ӧGx{{ӯ_?Μ9~P[042ƆD"cFڵkiӦ ͛73f0rH ĪUhҤI7֭[¥K6m:,_\@utt4`oo9>lܹS#3m)kG .Z* X_T); AX߲%U =|pƏ4he8}4={Toȓ'ORN4!һSƱcǰKzzzn:tuuiР:Tᆪ <-[RL:DHHj*DOOO~<==4h?/fL6 4i7]jժѨQ# ?~???߿ρpttd#6mBT;44T#c„ \z r)jժEhh(̜93gҿ D-qwBXX[y6Όt@%$\$I 0@=ma} 87n\p>}гgON OOOѡ^zMǁ$Ix{{STXSSS|}}$I# B%5jϏӳgO.^ȦMppp`ժU|9 z,Z;wrJ&OLTTl߾vڱzju} [nʕ+Ջ;w͍~ ooovɑ#Gԩ6mJVʎ;:u*J5kCƍǴiLJg y'jA zw/s &&&tUݢ,)_$8Oj;gK;>SQ֯_O\\E5gX?J^sV&ZHHPMGebF) ,glBpiZr~wM)[4Ǵ Ɩgl:R\ypYF s!έƎرc5NZz_V!.%Oÿ)\r\ IŰD`W؞5VE%$$]$IKnέBBp O\Cm9_;QpnBBpZ 2-pfxic+mEUYŹBfjSXM~_Rݸ$@Xx a\*''9]݋N%KR^ M)ѿ]p9 rtJ^d^'|ȑ#p]igbZ܄+hGV\;D_tuu_nOophBBܹeoڴ ss3066XLLL4ivlazMn'\!Zn*wժUiҤIpԯ_?}Y ӇnIWlBܾSìY 劀PQ߼}H e\+-Z$..N^XXԬYǏge@JpqqCl߾]cέD,Y|#ugE Ɔc|}})S 7n 66~:u@fؼy3*J\ٳeakkKƍٷoMBp%-!ߟ[ҺukCdd$Ǐ'88XM=ψs0g6oެ>Jb4i҄J*C:vD$ܹszv Jw;8Ǝ˘1cnݺ\xs%QDp47!Z`;wSNHf͚t7.̙3\x~1w\ )))<}{2{G߾}={6&&&T*_]_|Q!99cryٳ' 8KҩS'5kϟg…#ʗ/@JJ *;wJbԩ߿OOOQ [ӕ+WrwN]$2e`bb±c8s kFWW{{{us?1j(LLL^Ynjժ9TOHCك[Qogdd|ݻ~: B]V2   K7$,ˢCH.[֝W߾}_4IYLJ~/MRNFE֭',Ϟ=Ãefz<ԿEHHvvigK%>>pD:,wR(Ջ>5k/гgOիn$ BT(( 3f YC:u vBBpZ[!I)))$''׫T* e$ :t(믿f޼y,\Cbnny1+V֕8::beeR?C턄 i/CߖNJ‚3U#ܹs R0OJJ ԫW}}}^x#M6ѣG,^Rիo KI:iݺ5nbɒ%`V*dk5 pʓv))SFtRz聗ϟ'111"88u1lذ4J`` ٸq#&&&t}}}&L+W ɓp~(d|^cǎڵk9rٳg+Wfٲeg122EH8Rnߥ{_uuu1cDEEk.jժŶmۨQƶ 6 ҬKHH`ƌ,Y333V\ɒ%KP֭QF+WST*Yz5>`ܸqL6-Oٱa;J%/f׮]ԩS'eggƍ3P")}/.\(Э[G=\@yuK@@@h(ʹRަW8&&T2TI)sΜ947#مEQunBBSD+WrRʝC,^!2ċT`3(\pNUH.v*\+yěBpYʼn,*Mځ0lBpI_zԄ ,-1g\x̄ K,4̊j(*s?E+vHr<5!j"({Iyz<3"&C񇛶R7!/HDP!QKbp*ހ+$mmEǹ AWhX[]P!$Ijk^1b?7!Prp?ig|pnBBXLx;&e ܿBs[n{n>|e+&$T'LO>yxzzl2,b :w޽{3P1'c mڴSSS ,FFFyzzꊫk9-{ᨀPNTfhy9jժ4m4 Xׯ-ZX*&$$I00v%Ӧgޡ> U~kA-7GIJJK.rQu^^^ܾ}o*U@ݹ}vQR%(P NMFz[HYܹ3Ԯ]O_n݊OO><~ʖ-ǹy& "_&k BBpYWZo_&$Ξ=˔)S4 SfMuqsscKvt 6$..3fܹs߿? xذaPq*Z.er W\Mڥ{333cٽݔ*Up1< ))P!a@r= I_ٙ'O^cN>[3 O !M fmSGGGF͸qݻ7-[}Y2ppYtnv6~zػw/gϞa!,XQyeU .MMM֭[ 'Wr؛"m]XD*_Rϴ[\5A!8QTJ Yu_HHH.&d-cQK_O)\w]~BBpByHג([/$'T\%\P>&qBpBrNNP MMMǹr"-͓ u14+2_}h08IA8!L:::o $TtSWPRHHHNHHHH.!\;o&>!}Jfͨ^:G?]vqydaS^6mCCC 166___[^oYPMk;'k,yk׮ѭ[7֬YOOO\]])Wzmҥ ϟ5L@%zQ_ˋmٳg9;6mƍ)_Buxy ߇~5֛x4_r2l0Q <==:u*ߓ6m ,`ժUL6 ch%gI9|ŋ$%%eLd(QDZ|>7oR7?RNh֬[lh43g>|իW燭-7fT*:Đ!C֭[sa: 4iؾ};?4h{{{Zlɉ''44#F ݺu̙3HZjINN/eryҥ 666=zK.QjU~bcci۶-ԫWSNѭ[7\\\pwwgĈo5 i]ᤤ`iYBGС3g͍A!I `޼yc̘13KKK֭ŋ4h.]RoG}u\t=zJbҥB/7n` 2!C`jjJ͚5 bܾ}[iڴ)۶mI&у7nGw4oddDnhҤ $ѬY3K&N}mll:t(*UB__>}_2tP2t|K,uܸq=zФIlBvw(B"DZڹ߿3gbnnNIIIf֬Y? ңGO0`K,cǎ/_T*;w JԩS9pt҅rѢE Xv-Æ c͚5ԯ_Ptt4 .䣏>BeL?Ç?iڴ))))|'^cǎQbE"##244dƲw^4hĉONNָw1ӧOs}zAӦMӽo7PV-֬Y%:uW^,_?<ᵐppB122GRRחGg<<"""q7V`xyyF$qc|jɲܽ{_>~!$P(hٲ%M4yKʲӧ|2[C}<v0믿djiuttippԛ^gϞrJرcEHHvvio.qqqM4 QQQlڴM6q%HNNFTc;˪˺}6,ZE֖|*7nL߿m8E!!lM/Z-[0rH[R(xyy1ftu5ouz43N:E166f?PBst)ߍquu{.Izzzgwkjj* 6ψ#ؿ? Zr8::beeRߟefx[hhIdd$}:::lܸQ ׯk*V!~!zzz>PPZ56mDҥر(B-c;ѣG$%%aooO֭uK,J%111@}oJDFFJRmN"66VC͚5ٽ{7HLLpҥK#IϞ=+B+3=֭[cmm͒%KҀ=***]HH8Ng۶mlܸ;ҬY3Ǝ˵k9rdzg*W̲e4z!߯W 5jxr뇧'gϞZdR9s&clْUΝ; `V֮];;;֮]JRw{Zhuoԯk?KKKpwM6TV/ &ЪU+ڶm=W^%((=ݞX!!r!ƌCrr2?#ٱa;J%/f׮]ԩS'f8+#2|vʅ غu+nnn%1tPo5kK^qvv5HP%^Of„ =%ڵkӵkW"##5j'OА`ڶmˁlٲ\~?}}}V\IW:f,[ bii,,[q1m4VZ ,ȑ# 8YfaddDjj* .dԩYgϞ1w\v$IlٲAcv튾>7n$((I&1yd$II&mۖH:w(0BpEI׮]ڵk۷/]thsuue`kkw%::e_c>SիD6mڄB`ذaXZZԩVԩS\zv܉ |.:::TP!M>5nܘN;VtO#GWW;w IUVU;W{{{x k/Yl#A5c]ׯ$$$@||ӧ888`ll,AW/ާY*N*w!}dYFRxP:vȆ X`zzz899tROK{N~˥798{2x2GBB rt Dll,w[\\7ogggXĄbbb,yVdtorpLMMաoƨQcڵ4h@Ԙ:^7B-Dʹh֖IM6.]5kh бcGRRR_BFF%ؾ};ϟVZxzzbgk<`˖-RSAE˖rabccٶm]v4oނƾ}pppocrYK93'N͛Zϩ0{lN::::.]իSvmtuET׀tJJ#$?tqȖ{7oN^Ҧ_)1b̟?Cޖ5j5blذ2e0h Ǝ>>>̜9#Gp57oz[l?ИMݮ];-Zyj'ڮz+sB> &&&tM< X|wZŋMIIΝ;5sαf4mz/ ̹֯_O\\E6XD9ѳgؼy3x{{tuuqttTeeegћ]D%hzuEe" 6lȊ+>|8 6ٙ'Oi&N<_d>CfQPN("gb=5j`ժU|嗤舯[GJ'N|j.?+ S1p@(j2&3۟P1M+/ !/Vf`E( Y(N *|+[C;1ĝ+*0> 3=ӐN: ,y JEguYCYf퍣#M4!00/_2vXo@DDҥ-177gʕc;w޽{SR%8p ׮]8p<==ӧGGGUܹsQ*\rݻ@ݺuYf3Jbpӓ#G&..DFXhm޽;>>>3}t*V+#Fӧ<{cR|y믉5^~I&ѨQ#WFCg/DpptۛKiJHMMeʕ4i'''4i͛ӽAAAtWWW̨Q(UmڴIܓ/_y$&&qFdYfΜ9<s1ԩCΝ9<&L/]c\c֭zzzŁ3f 1BK,ӧҸqc/&Lؘ^zԩSYd jՊHf͚Ell,c>}޽{cbbB>}HHH`Ν։'d{{{U>yz+;88˗/]$ɷoߖ+T ӦM丸8yŊljj*4,X }_|5._\622ԩ#_zU~ yᲮ 2:upBbbb޻_jj*ׯ_GPPF ͺ7I!:::iJJ˗ܽ{sss s40{{{x1744DReNkT*_ݛ*UPfM_NjjjO/ddY˗`nn{?fԨQ>>={:t߿_====<<<8y$cƌʊFѺukL´ih۶--[$%%={ܹsqss~Zݻwɓ[MҤųo>ذaǏڵk̙3'NQgqi6mˆP7ФIBBB8tIII踽{f׮]lٲPjժEpp0Nh}%ӧO'((&METTk׮Zj4jHPH8UZسgSNٙcǎqիdž >}:XZZh"Zn͵k8u `e}l۶ ooovͼyP*,XC"I̞=F{nݫvC v޽CѰaCvEs鄩&._ޞM6s)ڵŋQ9l޼ӧʕP*|ݷZ&gڦ\`رL0HVZJbժU;ǡ-ׯgԨQİyfXf 4PogffƊ+ۓD)HgBp96 -d4-e+w~w?NTXJ䄐+׻{ (r%4LhB?E+_ @ߌH=3X( `+LC·K|*yb e؊vh\L\^\px%+L EnEpүT*Q|U'S%Y=7mjŽa"E }:+VՕ#FӧO3f ˗ݝ8DDD0gڶmKrdĨ ӓ>}p]Nr\2&MӧM{nڶmKٲe155LMM>|>}={R|yWѣ5%L>}pppjժ̙3Rɕ+W֭ԩSիWqNlذ-Z䄯/s!!!A͡Cc…Ѿ}{bɒ%$''J*|P&&& 6u,Z$Izb5..<<J.BѣG 4sѪU+Zlɉ'}u#6l@TT+V'O2h >}Jƍٓ#G2eVY|9 8333<==$  Dbb"~!޽:ӬY ٓ8֭˕+W?>QQQDFFǹseӧ#Iaaatؑ{Qvm:tŋ駟x FFF괂hݺ5ԯ_/HRR?ӡC,sÆ 9ի3m4ndXYYSL=z˖-[ bݺusU['OQvӰaC9_͕+W8veʔA>|QFaaaA6mHHH`ҤIԭ[pfΜɅ Xhj8/YgϞJƍ9|0&LĄ^z}ٲe̲Q]e˖/_,%V?e]]]O>ߗY+GEEɃMMM~McccO:t]]]K.ɱW_}%+ z'X9,,Lnذ,I\n]ŋrll"{{{˖G嗱Çe???T^l:;woذArʲ|-r:udggg9((Hڵkrʕ͛oȨHm۶B;u$ޗsܷo_9,,L>,[ZZ5k֔CCC常8966V޺u|9..N=z$eʔ=*ɷnݒ+T Ǐ?| >c丸8\|yիr\\KdSSSy۶mr\\|1Vnذ1w![XX'Nc^ *Ȇih9>>^^blhh(? 9>>^ }ʱr\|˯FFFȑ#嘘9>>^kT޸q/?lee%/_\UVFFFr߻wOwܑZ^- -.˗/FV%Z+V`ff... 8Rɜ9sNk߾}TV-[322qDDD_P+WFGGSBJ.M HLL$a˗S._[[[Jrr27o&%%%+;s W\e˖TVM5kru"""2̔XYY28::baa)UNNNs_;͛;:: BCC5ruueذaNWi1uuu|#2$%%Pb``JJssαr4|ӓhee-DEFajb,ܼye`uX?p4`ffnJOYo`hBGGA:u: ޤ1\]Cp;/ 緪WΤIHIIATfmƧ~$I(  5kd'=y\ڢt "ͼ"k[WWBANСCxW~}>Y9 VXAΝ?>ժUoI~VBB3f?TÃoŋ+S Çg3޽{suV\I۶mW$F3Mvvveh* ttt/ti=wddEprcLѮO8x -ETTeRLJ%9+WCCCILLpqw!66WWWQ*邧B ꐯM6*?n:.]ʔ)S3f "{sɒ%Y:f屰 44#F`iiI@@|TZ͛7ciiPÇ\2}k׮1w\; ۷J*os#+++[Ȑ!ChѢeʔ%$$Ç;:,,,hذ!?3cƌ>iѢsN ƸqX`$ ???.]W_}ŹsHNNf!{ϓ1ߴ}]|O>J*Mɉ bkkKժUϙ4i[m۶q5hڴVS9{,/>e˖pq"##ٲe i.HOo~bԪU >tΊW{^d3ښѣG3l0̙CZeݺulܸKbmmM:u:t:цػw/gСCDGG7|C˖-.FP0j(^|۹}6۷GT޽{;w.ӣG\cu㧟~bxzz2c >?3֭f| 4͛79%+m۶o߾xzz2o5j`є-[6PQ(|g|m۶qm:t@bb"&&R zX傽؅ &&&t9ӁR1^͛???~uutt4[laĉ4jԈUV_0ozfK@@@(de{q}7o1,;;;$IU/RC=N-j+\2IInrBQpQG=GWn]J.ӹtqiOW΄ Yi+hŦPTx6a۶m,\ 6`ͩ\2ӦM{jg{+ [t˨x, mժU#00P5ks$\b Q+x&K*!l>IQoze;+*HN/Y:j9l%$ i9/pfTw><-'$T\ EF¡ U6pZ9tKD(Ep<~8 Y.Wqޫ˓{s_n/ #P"D.ݏgkq # -æ uq[]QB!B-u,Bo+D W ^j™:@`B5޳}i1<1#`gWBS}t3('WKl׀`zL7a:Io# >u!Ón,%o `!^! |!sx{9S!lM@ mv`pD<T 'Te` fwzL0T GH88B!ˠK6oX>< u{Y;T0T.x om> *؀;w6.""`}H!~ +@*g?pU]T^ 2`TX _= -¤!W3SSf {~H*Cx׀jv?q :߃&P<|Tak^>3 >ny\Tg@YP@@\ҮiIE%gxM5J[fݲۭìe.}1"5"*+.&"0s~# ~GY}~_SPPСCoQF@ZZZӧ5k=С޽Zzd.2)YݻIvv69sOÈ#h׮K,!66( }e˖/t:rrrʢ~ ^ٳg9~8aaa?55|TbbbprrW_5|fU__6l;v`ۗ-[J?3?IIIGaa!>,|u̝;3f<@֭y뭷8{l5ݝ'ҥK4i/";w*55!Ca^9r#Gd˖-~zSM'lQtQ-vٙoɓ'X~=+V,_OOOTUeʕ̞=j*`Á(**" ={'׏-oˌ3xprr"++#Fm6.\eT.MRR=z`׮]; гgOBBBfѢEooo2229r$֭cرxyyi&VXA^HLL~qZ[fԩϜ9sѣGs=PTTdrss7o_~%L6#Gh"Vmn)U$Y1nZ7TUʕ+F3ů%<F!""ʘFgϞdffז덌7na݈t:JKK),,ɓxxxf0CSc())aɒ%ꊫ+]k׮՜f{)9jKJJpqq!$$ ݘ1IKK_~?~8wN۶mٱcz </o*KjJhDZkemSy SLaΜ91vX;f*fF!..QFwWWWڵoH’V p #==:н{w<<<&;;ǏL\Ǔ=V; $$;r~'t:QQQҽ{w222رcW\!&&-L :uBqAFYEjk׮t:^{5v+rJЦM=JNNNn%NHH 68VUPj)'+f} ]T믿2k,HHHgggFEyy9K,1,PU{rw@Vܹs_:te˖ۗqss#**,GhEQ6l|dee~֯_OPPLIi)'Na.͙ 0R)..6?h9teNzɦMHIIeXzM8po.]"33{9s&Ǐ7Ge׮]ZXbbb8w[n%00W_}[lgŊܹ'x/O/ÄBZZwu!ggg8r}SNgϞ̛7_|Ç3dt:7oڵkۄ׫Ov_ ɓ'پ};׮]=cǎeӦM_l_ڵk񡸸O?nݺ… y'yꩧڵ+9990m4\Ҵ+≟$ 曬X3g0bkӢE*i7K.ӓuq&O̷632Yxx8>>>888ЧO %88EQUV nOOON)))( lܸ޽{yfo=7))=}ٳgի$&&2f̘*cڵ̜9|֯_k֬f/rSƔ8I"K988T[ V:ۤgeKXBl!WYy^gMrvSq وbSqn?ό55،LKN" Lf FwdlMgeM˖[.YO'21X"8^ͲfNҬQg32U@қm1cNRljMI57I7 cgMDpv(0ZsUCkOm_>t/،" .k;bVY{UUK#E vE޽뮻سgM&6EQqΛݨe>m5VP)((w&((}sqȑ}W_}ѣIOO|ff&]mڴk׮eC ה6Fݳ2"&ઑ˸q?>zʕ+HNNgfdd}v.]Tgϲm6N:U۳i&RRRh߾uv= )7{VRv&GBBo&-[ѣ,[z}\|ƿ]rk׮L:3gwIm..rgwz~7 r e…$;wOǎ g֬Y`DDDRXXȈ#j׏!C@YY Z`!""hun<7~xN8iС]taܹWٮR.]J߾} VVÃDRSS}@zzzd֐tVwfSMڧ k4DEEݻ7]tqGYl#00x Y~=]?__HLLѣ<㄄퍪yf DLL kTxa߾},ZR@yy9/2K.eL4͛7ӻwoӧ;wdرhZOOqQ1)))={$ZnH[KvIT5n8Gbb"111 6Fs3۷_hV^m 5jǏgʕK̘1]vq)F͠AfϞmx>''gaܹ899pݻDȇ~ GG!''XY`yyy+PZZjݺx b#"KEiU% j?!))^z_0tPkTUEUU6nH^^&M2APPvҾ}{M~~~O(;wٳ㏌3-Z^޽{ ETt4:EE4z^6^WP&L$Y{[('֭',,Ν;ᅮ<=[Ӻu+^~e̙СC6lm۶%33T>c(|g,\pֳ>K^h۶-IIIz4 &MӤ}t:6l@ii)u 44GK/ʠA&77$wWnҍr;MuGˋK2f/_Ύ;"((3бcGC#0alݺ"t /@޽ ;l0^~e,YŠ+ӧW\sμ{YN:1rHשS'ƍo'|r\Xf |G|hZz!y 5 HG@M+ٻ䔦F^xjyLv"+fΜٳ2e ׿Œ%Kx饗kJea}'5Y$nۚ5k(,,d6>٣ZЕn:4 w燗HcnLyE.a,^dڧnёAOFII 7o&99cgQcMLlśĉ ?fӶm[zUn);oEՓ׍WT}Vk4bcc5ǑƢ lk`dlOkL+KfqٓT}OrSDr.ۉv2VlRM"7s6V^A\E,UNJS`M]mrR>\] NѠnY}SYObZ5[ٟ&A'NXnaUcw_Io ܍GU?~֭[ǫ^%5^kSn-/ی6ސ\II {EQZjH222 ())a˖-fwդuDetd(2~_FW5@$7sRTTDJJ e߿ \=a233)--j~؃+ZcbhucDM ?hӦM^6>}mbHzzzaddd;gggΜ OKK#-- b$Y(//7E!888ǧ={ Ep >2??A^^^Wl;U PiժUi֭yxxr/N>m{o+&BE#E NA' A ADp ADp "8A NA'NA' A ADp ADp "8A NA' A' A ADp "8ADp "8A NA' A'м?IEIENDB`deepin-terminal-5.9.51+dfsg/src/assets/deepin-terminal/terminal/en_US/fig/groupssh.png000066400000000000000000001165571475472654300307660ustar00rootroot00000000000000PNG  IHDRvS pHYs+ IDATxy\gf ; u{R.vַZ֪ZVVDQ}!$YfGM@>I2̙3'TNN F@)))n: P'9BœE!~a"0gB_!/Y,B s!9BœE!~a"0gB_!/Y,B s!9 1ͪW|Pޏݦo>|vj!]QP>?^2{ ~bƽ_7-"M6a``]9sG/-{lϢ6iVm{Ǟ sZAYg7U/ XgCs)1[|-a{5t#ZWnZL;]cΤw50gQ3ʢ+k9p#G uM['ާ6Ng̛%ad=W?Ry{QKoܝb"ǒ؞@=nQ1a>r0?~ߒa`^}$^u^?tSg'&{ON}tGi_y[ $!&7)gk*8{d-s>!ԩ#b"&ˌ^Q{! oZ}/65&L%dA'4oGC2X[Kvtws;cx:>?©rM9T%ٿYׇbz@@17O]-3tO}.76M C?+ύ+e,F3jmYl9_l[~jn>pژ."c‡.QR}/.{ϙ4#75fTJ[ʭ}q!7V(~`V~_ܿX7'L s|;4%1̳2۷$d8eu_F0 ֗b;vP#f [YO?>p>uV?ifi񽥥Gwڲss YE SB޶jP˙U˖̩$r?-e@ RN)AfX#d72bvzΐmŨŜED, Yu΃!z); زɿ+bna#c3ા(Nk9a7{0-{NH{Ԁ E*4HEa\ʆ)Uk+F-,}2c%RFo?[IjrW*ekf$8=?fʤȁe=yɧǫm%Xr4-yzeR]fބxxf3jԨYB$%%a{!9BœE!~a"0gB_!/Y,B s!9BœE!~a"0gB_!/Y,B s!9BœE!~a"0gB_!/Y,B s!9BœE!~a"0gB_!/Y◠+A$)JD"h#j6b1L6m691PVJe{WiHlL&^O}|o>0dj]J2 (79jD޵@H$j`κ:N{NKTD"^790dBuxaB54-jr*J`κ:#@.{{{T*PXnz|;+SaWd-$$DP8`,[}M^^^F177jl|3rQR%8# `YV.GGGT6 !Rv %lMRڻEBX, cY)!q\XXX,vV-lg>7uΔ dkjW"x<& 5}(Uw]la75j1ʙee.!g>d2ww ے26o9+ˋf]I(&;_C kNմw%jOOϺ!ѭTZTXP7PȺtf1e=<<ۢMWRM[Oqp5T=g?tg廍WM}q{/+ NEsZroV9A䜯3-Xp,χtҋZR}'><{H2ȮU_ά t]^:Q>ҡ_5w^*M_7 6%#r>ycձ*^^rq]cąyE=[v])' }Fd'{g!Z<Ԋ]bZb-eFC{t7&PBݒr*4|ucN~onS8Upן~ Qnת0ɇ{fIJN):ƒi<;.ZyB=eӃ2g\W>\\zN xI&{bb1i3^ _Xw%t ׃R}0q[}{X0lǯ?}bKy g=4VM@e=$߾}o~$5~xXwrL aQ#  \ ޜaZO?7?706n̑B]~ݒ4H/-oG'7}r~~g2&wqKrĆgTwE9Ք9mGegkLG 4{v}\^xacdp\s{_zrv]ҎI J ۷B{α,]iEY'|}gyRubӟGsJ gw̸Z3OL8f g*朗Wo,1?qE_Va1\:}]VK+|%H n:u0G-\MY|%%vH@(6tKK;0hݱqc%h r*Yvy0baً {DoM/ٻ|ɦ3րqK{YKUB;Xϟ|=Ԃq=n2KNڊ| 񗓝hDpU! 앓* Π)(vkQw}eLk ΧaqEEUn C0 TJr6|xLB-V0MYmArGݒ.5 k'f 1e+d[K@Y,ZȝؽfGC0==3NGĔ'‡o> vvUز*ቇ>>GUə=֜|*YOP Cm=:+ط5U&JoBl~NhP9VNe6|</c@.b4 E6酌Jj r5u h6e.R*''gԨQ] ԠBmfl```&X,7ehbfff`[M#\Eu&B8k}a"\ftМd@ӵxo`"\EQYZ8" QZ}fiZD"ɤR)0%YX,fbT?֍{-欫s8"Q"iTgbq)Mι v{|lqBYWgX0gѝ:^k=U3d-fS3L]EQ5;ΦlHYYY*DfaԢ;VVj-t&fw@Ww#tiJeX-W3`vFZt'k1ɤj yy5dR(Rg9Bqᨬ,++㻻lGb!ԺMBœE!~a"0gB_!/Y,B s!9BœE!~a"p~D$)JDȸ % 3uAs91PVJe{W5iHɤ`=WQvv|\kBQT@@ǨR pߵO9 œjD"iZH$jks9꜇9] JsVqG9 œuuz?F Ns\]=(h`Z9kuJVYk;gۼAN _r[R vTכYy~:k_N5"vnnn!!! 9eh6Veo_'xvm:˄P BJeTTL&84eY\RNRv %lMRڻ֨œEwBX, cY)!q\XXX,V-jYJxaLݻsgJCZZAAA+Ax0q疾4 ֞fhKGoC7r@c̨aB=$tՙGď U0Rͅ])A"ohOܯv[PU%g7'ӳ,Aw>r͔w2e_ o:$=籉GUQ 9l|d-%e2Yyy9! }G)BXG(t?ve5+)o/]rZ6L1bA^"֤?a| ixy'sR>#RǠ8jwcw,FmSʛwRJF O.)P@3q08ʵs}#d]ϝ2H`cI{x33eyUşCkd:2>,eۏ&uf _os\/iy/8u0ӳnFte6T/ +=.YeY֬PTꝵ'XkYo./$$XÇqzEvYd3&Vl>S%j`ygLZ~sR޷$;@r+XࣳDx?Os7^Yw̼GMMoO.:p[օ~ g \q88Å-mLj`Աϟ7,*HTصzYBC59{wJ5wfE7׺)RHU3},rad>XMG[E$g*?%2ojI} Y6K9C?]x0B̓"(jhsOѤ~OSyREMtqCc#?B-*aڊOW&\^h~xo.|bƤJ[R.beʨ/.t@aa~6ee{ 1ajqU-?r@_<{/.J]ntO;~f)?\vpAxRg4 -z𚳔n&}8l=E}f.~&-?btȢ^BS0!3>3thѳ#]_לLy/N E]=3Kr0!?]fxu ;5婩n{maL;:|&=*[[?u 2v)yߡwչNǜD'MGR_:XL5&W:sVYUr8eg( (@uψ%*!TcE |6)=={s8g'#Ӓvo{vOt n ߻Xr$8w8M9tL{*91[mxSK/ k`<̞>")kkp,;%3~r?_hOX[Xeژ !Ƿ/Y_O$׎+ݡ _(p=-|ĬrI;r-joǜϷ[NEk IDATGn[}j[bIuAӗ=U$?f'߸w]S[Mgu:i͚;VXl"ZmڤnW73Jđ3qO̟qMP2}+=n4Zu‚KRD_:Y(xOmZӅV=dP_CXvȰqj r#uzםZˌfۍAOfN. 9΅d1 O}񏌪k ==c{vL( 4\!*ꔞC=}dV]~[7SR^O4g.8eW^v҈ȽgHl*m4!=&a4Y@#,>:wjʕ1]T~eSvsgf]uք5Ъn>y>R|j+2a<kް1劑qv%~CNsRSrԃ{tuzl6[kM,R哱aί$Apxݥ#)3is,ذn繛z`Zu*vl]˹϶T̰*}G*N{wRŒ׾9) =6JP8slDgs_ؼёjO.ƅr:OR*w%F ?$"M+29J=v׫Ŀ+L/~oҿgs!jUȑ=|%BH:pTGaVAx{72k༹}$$ |r[Ͼ /hU)OO w,q"?]Ya+F+o:\pnmA_mArGݒ2~Dw2scB=^A1f}@_KǕ _LB)SmKy_}$6UnT;#ڳCFFXsR/aoXݜG~eB$5f:87|BȬ7ΥWouzW w,fz`ђE$5;ă/ K)_J;g`T_:,x Н=+>Jz OĻSMlK[6&L=ERn*J>=E4KB{V1/Xm+VD E9Q ѿX;~"/Wi!!h4*Zm 'jj4m4oA-ķ7-׽{ԭ1߼99_,[7τ  QgwMoM׿~-n:pRNsԱ)*j&f8jZFB[YkNs9L&S{W(f'@# )++kY%;Ns9l6['؛]PVj-t&f?w6{0g;^ \PS-k@ee^oQ:s9B4Mn8-NX0LZthT9 OɤP(RSڻR&9ʲ]PKG9 œHl6۝p(:"9_;!ԙ`"0gB_!/Y,B s!9BœE!~a"0gB_8AG"JD"q٩:rqd,K[91PVJe{WiHlL&^#b(* C֥T*W1g;Z-HڻuBDVYWd2wwwErL&WZl"\g_]}j. ]˲ nN('fO%a͚?k7tش),c'`ß<^h?"“1_=}*J1qzxEv~Y:p[K./(t/vT;wB/I&ܛ] 8c#{+4oiy#L䷖UǪj Jt1q~r4;eϖ]W]fu[eFC{t7&PBݒr*4퓳tДGg\W|3NX؜dEޟW8`M^JLZz1롊_|fk6j9b-]J\r^0rWrXg߷ǥot{(H߼&zhm5?Ȭ§+^uA@l%G7Vf<:~ow^iejO0 Խ֫P~(!vhDbIM,]sfg 㺥7P~蔆8yF)/y?Yw ߥU/~u$ʕb rQ7K;,02HMN;1 O^dRubӟGsJ gw̸Z3OL8f g#)?1V.3ۨj ؜ߜ.ܘ '3*,K/CلBaCtڼC 7&P 5/kwӞes7VƜMػs[ʹ"Pʠ. '-&purgRp lUTkJY@>q1AB%,zpŚk+-*@Z팄 ta;(DW(h(iˮr6|xLB-V0 ,jޚ/"xYrP4sBaG1fFOxC-]}(hϊ6_OU;lv/`뼒/=n_4٩?{{ 9W4Y;?\la1uJ5tq[G.WH{  er,;dظ{uBv;5m* ŅFUxFJ)._Q[I Kh'5|B_4y.ޤ`;Jz^x &;`Tf5踢:6 @]Uz1bh rXZN28:jk rԔ49:m^j?qc|ꖴl5W/gYrC>]=2vr@Ō+P-wt v(1ڈ}==/&?豱]U?b(2 DtP P59Vټ%$yaB07|ЈA^:᭵KּWMsY+`E0gQe6릧\q8ywu pnңn~7-凎3<c3dYE׉O=@!ί>k̿>y>{WzIKǷ^jly[輗Wbʲl\s\Q-C̖_> P C.\\]} 5qW=}ۻN!h4*Zm 'jj4m4k4prrrF@ l* Fjl{RPPPo633j$ !*3R\\И9Xk s!l6NL%:ų}s!r(rjgu: 4ca"\HuD:oTTTY,g֋(ŒW+d]'m\qa6MJ$L&JO,Z,lX[FS=s9H޵@}Tgbq)Mι v{|lqpvM9, ,Tkq\gjlsEl*< uu&P;(f'@# )++kY%sl6ZtǪJWd2lVk0g;^_͏Н)MԖ5cR׷^̀9B4 jѝlL&V%OV:Մ&IPHRrwx8s8eee|wTÜHl6[ ZB_!/Y,B s!9BœE!~a"0gB_x=XG"JD"nQbXsc(JV+B-DӴH$rL&^o.6e5C|h_pv )/hZfœ( H$]ZRD%4A6,neosBF$ U٤<osM9j YH$Z]\\\d,l`I%gt;2gzg޻L ЙY;KZ 0 wd2wwwZ\. !u;GMmc )KКgu]+<[a71n:pTꝵ'XkYo./$w#)5gݐl*-*,^(Wzd]:[˲[&,E1'g  Lv=&K-n!SArQ_\lˀzN|x!>*ae]ޝYARDxh]bxLAW߿n4uY#*v1ypl75mڿ= {"]>čI?P\.oZ"hb}Gwv ϋ+dbM0<1X$;tפ(tƪƛ=[aYŤزzE],W?5T)OMukK5 e,˞72Boʵ_#Rth~8AxpG;陗f_|uͣ'ow9[לLy2s3J7Z =92jߵ:{i4b33cΟ2n'_y1daB]~ءGR9s$5P_w=ΙCZuh4߿X,!vdIK0 vWv<0mFgnl[DS /9UI9ǒRtey( e(@@{Ey٠9wJ `(`+ YNiXǥ󗙈a P^Crw$fA=Ju:֣ ֧HorÞkvgd]7pw뮳&W~qS .C5f)ŀ^P=ƆNB\:m^ڡAv(A[Pɚ݆<ǯ:d3fP勣{CM,9+c&ݹ-\T\ʸfB(<(;hB>v+8QNс9Y%׿5 _f1^ȭ.uIi AR9آERs@,x۬H#acLs@Q]D-Z-Li7u'2c|.LؤůӮ}yǓ䜏էxa|d%1W7:6~ht3E"Uy={ZPLNL]aZt""jMO )C iǟk QgP_CXvȰqj r#=kOX>ZN-ĒKKlo.nGL=$zp=d(ync;@%J{6e}rkҨ׾l%7,y磝 }e[pbEDV?r3*n˸4yZiH3v ڋ Ҡյ P*_?ޯ[xU[@PpՂAꨭ/h]cSSy)ƍ [flLnqYo'L)r0|Aj^}.{DSCU7w䎻NT ep?!P"߸_ ?$"M+29/f^jTݥk{EFqEQQ#,u:;:Nz;ydxД~*WeKDEݗґ0c O3F\Km7_oNVK(?y(L'tz)WzN]'-=[[uA.z<+> OGz}:I>pjy_7`m?_ĖU O<9JٰSx3gvJD*/[l|]'>@ZU#;3CC_9y3<7# ~ f}|ɟLGWHҹnVϿvA s+%|p3ѝDŸV 8[n/ j&f8jZFB[YYYw!C! A+h҄YunYWg25zi6BDgK6B9~n;0/w~njs\faԢWZz 7dr@Ky~rFҪ1/g9'UZP@׋DBa IDAT]P9ӳQ-<Eg;&B_˶UMPBД3<3VLcvFVJe{qZeHl-&I74q|o%WןzR1}lVRYNYd| ćgVٵỲ_<=\->q ؏/'3?Bsj67rM~kɈOXu !TCW7n3E4:n{V;Py:A:abs/e-~{^:`“68G׃z=g?㉟?~/l)&¸u~yy /~̱=WbflY颮RO̟p͍V,\-ir_oG^Uޱ^]tKw4e7PU,CO|EN?L,^}2൱z2 mq|t5R{KLyu>G6O3My[ kx3}ȹlMyK;2jRnӪ əyW/6KJҕV?x7ؗPilHAʯOiL(6j67缼86fjC]/Zn/{KȾgbZF{6!}:NN!}eǭ.)eP{_\,pur6so'Dޕ9Y83N/{L #u^ߐ@7/3%  ?=?z%"uKEPVtYRVXbU) %EQ\ўlʿ*wAzF83a:L7;O~R}3`Q4Y;?\l~bEݪ=^'\,Q_{ *BɥS,0A9 s'ZSĤɳxv&% 7=zB84MSM±i ="SCw`8f_^D^RQvփ]ձJ3PE{#0o};SRq%euy/fL-Wy0(!cr^5מ+$84[QC`?s}Oϋ 5zllz _LB)78G]9ϟ6$7T`Qv %1mzGn^r.OKH6„~ajOo(&t[k>߭^Pc6aI9x Y-gY_c013K.$UK> ̿>y>{WzIKǷ^w ĸ'|lnoHW6o>gz?=֢[?:zĖU}GQlM%@BbJ DRD ػ׫^U,?/W^EA" %;HH)l9?6`lyxxRf|̙3gV?vSF~X>csc=̳X{d_&(lr+PXcYUt<٤n'},6Qd* Ab6F㤮Klylr\&,[D(~ee Py`Q>`5RWs6r1I]o:Y+݅EeeQQQzPxL'bޓ>erfjqA'tOf%&&TB JlJwaK۟6[+heeeF‰ bFRTah9;e1[붒~pW݇m !nB&&&Fd? t^1 6[Eb<<u/,Qҭg'_XYYVdjl!)͛h"**a`˴e˖ Z7r ˓_0gÝS.- &B)tZEBFӺuk^#!q>+;$9w| ~w3&=^-@m [_ \{]pl E7 JBHKKjB6HŴ4BqZeCv,B(S2%%%{Q699 uKvwЭ}jA+-gs,7wYXPCȈQh4#auu*6:%EYE.**ҐMlWIl\Fg8uPA0 U@~=n{Wo?q&;WxL}.?|F@"3=wSg.>b ~-|ޑUL$7 @"sɯZOd-DDy߳?% cޟ4N5n|Ym}pGF>͚խ_L\Rۘn6Kj4ރI=s^KG ѵ7_wm+ ޙ/FyRs__`'68׭s3+zŐ5_lݾk媼[FbzGvԱeKr=uPPӀeYe/MҒ[Vw/.!%&.s~;--)tIwO/TDϳw_Iߚ[!0몏fR`;8*,m=~;src˿tIvy=b7Qz|ΓJcas\xq{S???hؿpmK}N껢]L&;Q"%۷ܭl߲-PJe2瓶B,!pbGxɿS\ߴP|jYBR;T&/IIRDkIj3wu/5'l}U/ \,~GW:mYfP]TYj/15Drzh8pqa˰՗#p" ^] 8R"iP`~ʪ(NE}3>ee\BJwl]# Bמwl]S\b@ }Md?_but(R3¢R ՙJJI LdQ]g'LR;7rf ̱Sqi7x&=v|l{'vm]؉5<(+9yizjtW-.ߺqFgtpQ=ƿq^Ex0o5|P˚o>ƌ2OSo^׾ïN[L,ڬՄm_eSo,@eoK>1G/<saN/P쟻G׮8Ȉr"T+JfjI{ђ|% l6N7)ήj\җ#n ¼w@6_}Տ?N6P]'t} x"""11D~@dL١m,K|3!pRaوG g.WIz*կ.ZPPr@clSRսl@)5e'tyCPߕB̙P7ن!xCܾ9S{g<]c#"!ԯ\:Qt1eA0g_n1ewej*B?m"7@!ia"0gBHZ!$-Y,BI s!9BœE!i` \.t*8k%"ǎݢKBFN Ԁ1 #˃n <2&j!!NxM+^7h4BթT*0g]kPr'Ŝ wIJJ]l$V.s6q AHB!80gEHR!8F!ia"0gBHZa\Ƹle}!ntdmbo TβkⰣaФ?B(D{Q>͐c~"gKkIQ-+]v@ PI[3v{=BՁRARzŇç'=;iԑ'0ԼtwW<Kï]^Gd44!Ѝ ŽFDOj;bxٱ ;'*lǂIaEj]hюBaƻ;i#GB޲- AB.H 0K]{~8{Ǝw3sHԳ;kkTgK^8V"Y߾k>ap'lЗ^Yo+JQQA{!Im)..hg&Zw\WP&UTef+B } mztMˀ㺍i:EEuxĸ7WbIYY+u]2~˯"yޚˣRp73F}׆3_n;O|S$Ũ^|?|zҳN9aps'nƣ?#?y[mKO=e=\)@1bBA%V-XZ|s'տs~[j)ܹxkyюVӑ+OMckX,;g۩ `Ϧ״*rZ~&Mf:V}-qZ_۪jO]o,BIo@8.%&͇ΞkSg[~3e4>_(/- ^5~X,jcgDI[f^ IDATgwTe&yq,m\|\S~Юn_MHr>)YG_\JlZVVs0еEyp8B]plCCsC&B!ia"0gBHZ!$-Y,BI s!9BœE!i` \.t* E:x<<نb4u:!DTreY%wj(  NAU!fVyyχAqDz,qpt:\n2B h ^w:]@  x(l6Je4fEc_  +**z=˲V%bΆ`Fq:]өj !ZV0gÝJR(@[!AP(jZ0gq2LB 2$L0| @ABPtl6 `Bu9I$4,BI,ӟk0 ]}r֋5VSHHys<ń HDow+%>;Z^{*EF7_Z{ ՗d4,V+Lr֬b9H4 |{k`RU!\a:@+sWΕC,9C,QvDd_F8.?4aַ{y-=Fٷt%۳MjxW,ۮC=pis-ŦMX)]@;4ՋǷ-r"*cʈSf=g:zlDU3[Wn)b|F~jLwn3(˕o9;);zS6yM{}֌^I_en ~*喲sY-e&3v69JN-ZCe4_4eّ>$5VK}:?71鹩iG'Djm^?oϫn5GV|+6`w gEeG`o'7j5>pW:I棧zG0[wj>}vQaԔ&F}ej8yߐ۳o|ӽQKz"5`7vos$s^]_}) M;elLj8d5V沲:׽hY`pq!oIm_k؏S~{ǁkgϿcO{l6YVJK0}CO;y _=dMEg뻂RG?6EL\*U2MH+Td`bSg}USsGtJ c\ʫN҂F8Z2,Zi*uu`.\e(m֟UW'2|ɫ4 7=Y(j,}*().q'<=꾉.5l&s~Őm Y.75L?aPkY.X57$TE °UtP\V6.vQf̳5Ga΃0W  Ғ9?g&0̏3 RUfXRRFRXW$$6UV}Obi 0ZMU!Lqk,+I2[khmV&1at65.RZn)w.6Vf7[ XOvh BTpi>gi u1!19/>pS4m[/c7OnuXq̣=c6ÞxtSyח6{VF>ŐүZbG>?mh L~GX# f}654>lZLD߉7YpFpQ]ը_\ܔ{U0 V+P#UQQ+M999a?[HdbenymF -}TG{EI&YKo"Np~9jOCH"al[w-(#[DžM (@al"T !Zxy>Dfq\ "lx<>8Zq,~-uYnBNF xhZIq8$ lCEn0U 8.**fQJ/Ix6E.+ )j5,^)1gJd2p( J%˲y]QAz.8s!9A!l!0gBHZ!$-Y,BI s!9BœE!ia"~D.t:JqwеEyc[t1BhtR)YydJydA BvGljC>EDꝟ`08N'M&Ss0N%ͦRFlh w>;C|EE^gY6تDph4NPt:Z-!DJ]lST "4O?F|BPR98d(wEjlxd!x)^ w pB3 "Cѱ=0 9Csl7# $\!$pYKSze8u#anpKOl&Fdܽ[4M4(|eG͜Cv lT6M˸ʏ2mDyn=7;KZJpNm#O6Q-iK(Ѷخ͛e+f|2ERz=0fh85o?ms8)qw5V2_ jZJG*ݐ&_|)UǼt{.,s['iErm2;3##Ekh"2z>RFj/gV4G*I؉c}gq鑅A/kw}mU}q﮷PKܑ} $}_~(q﬏:YK {gBo?O7?5}VRjiϡi/=e9{j}0]Q(&R No<~OyE K]\rQ<>}řv#-1ťi+D9vKL:F(!ccG2wJeӎ4c+軎ۻrɷ DCPa=5jÿ^xCvެ7dAUv{ujrrj?oԵV X\dݦ~IjrjP߄C >]F LG2ѽy["q,[tUVnǖ餓}{dnv@ŞM{]RX0Ѹ.wt}c<ԝ6:wmuuw;Xya^Z%Ő;g `۟&vV5+rZ'e;tM(ظDp:~~k˓;6Q3e ~T0 {&[o^ϥf8fІ~(RLk9'~[֜9Y{P-JK0}CO;1CTt+(q 뚶^S?N6ȈȨ )%$+:/m:&x6Y][2weG65,|jbtZRZ?p&vcgDIgw2&$ӂظIʘ[_3"SqE]?U蒛h#2")e ޲Z϶u*wJ>}Kٵc:hڳWX-"вE PѶwf~U;n-pk* շHU$G3>eOy"fʢcO}hp[\F6y6%Ņ?ΜvG7$5cӯ:XJy(),,rB?*+ )tn@UG>]oNCG^ENvx믮iݹA/Mp8? S`ӆz⯿x{]A%϶xWt0@0 +{_Z%BXQ*z+ylQaǻtH:cG}뿛S~%ObpSmw;>O]u ex]%xIϑ3V:kwl*%EsfM3LzagN-1wp,0r,aSۤ=kW(7 b5$lΜci?|?Hm# Y,=-KJyfuu< bIIINKQ#- Z2UvS'I -?V̎m%YRuJ۴Ǝ$'cUjh礪S~qfti*df)-[]Zi-u 1 3}eVylpTsC%+1Ι9̙9-|B$YeKtQݻ PkM$o3UȊw?:MJ1::uӴyd0Y}I2jjc[R"\60'LR;7rfmztMˀ㺍ھjhڶz_D'toܲm) Z}FgqK3FuݿStM 8:SO=,!**!M0Ul(%{DVj޶HD>A:{')XM=[?lY6͒JEd|Jw>Pi?sp*B xg Vr -"""؞ w(aUPb&`|^ w<<Gr"t8.Ls6y<qF-Bu8e~햺,pg !NSw]j}W #Q?xXB18l@)5LFQ8BqRdY64OG&<ϻ\`_bi ϢB)5v]e|6( zC]plCCsC&B!ia"0gBHZ!$-Y,BI s!9BœE!i` \.t*8k%"n}bѨ!JR., t N8 !$111،j9|>΋;?/`p8:N.LD-l`4!N'+B!J6MRF,u}wFEE,B7 ^ϲlU+u.'hNg}tjZBV,pR Eh~#'BV. s6q'DQ 9@)sٲ]7z5i:nqI=J)^CH 9mzw} ?0w?{ەl\ےٺB#t5g˲zuyms)`.9{S?1qw5V2_ ."J"2Mض`Y>uo>Ld|qhO?%^M~_蜏*.ݾ)yWX?S=,=̛˟Ȃ?כɿ?A߀Qb*@ 'yO)W 5oM=;2So5ͶuQ.t0U@dc.~^? #Gzf"9(l^..M[i$w_b1@)>ge9V:aCzj @D,CzNǧMv߃-qyFKDb s[P«RUe. (ϸ}贂Tv<:~={\;|kM_WAF=35;Q}_?΅;9p 硫QceP5|Λu,:h.(bc8Pw߇?ϲ,}gbc'SrjP76hgNӣYFk1W F87̘0 wث! TCJN-Z䤔^wˁNx/ݾ!odq7_4Bg=K!oۜ&־kaO}. 0I=MlkYJ:Y__Z֚P?ʻ LYc_|`eGj^QH[^k{3̹+ p\!B,;z^'lSZR4g'<̤qSa}WJst5QyD3Ƚ WJ KړT0 [|o7#^}E'ج"e9g5{DkI-Fs\zGpݴѲ.`NEC$YǜLU7M1:/U@)f @IԺ!RR$? o-s]X>cy3X9eQ55jQcDj:=F!WR^3@k[uӢםtݲ;Vuh..&[862L%^_eiߩlQCbt杻4UM- U` "=Nʊ3}9cɁٙȜvM# Qxr+. s>A<{W\Զ~ѢE|“5/V#3wx}OP'xyںaY6=_g{k䢫`STC*6,;mn P'f@ֳf;u||޼ϑ%'F2m݃{ @-+hp`;/gs^Z'νLvn:vge5;<\vP?| lY}[A- '%yyy]0$ ~.{'zedd Ze3{j u}[L@YTTTEEEnntEtc[!(O&88eBT1qi#AQ˿6C{p$ g]FFVu\HqCYlφ;Q0تEn1 B0>;y#9pBp9<8:q˲~|Lpg !NSw]j+`CUd0lLцpU L{pT}߹}h+Z$ !?6&ɴ۔v&Lx:Mt::iֵ]7-{01l!*!XV>}!WbD3w4B:{G=:{X$nQZmxLg岼1#U͵FVzY~v˖%`@F9V>ES.tU)~""# gaQaU}/:cC@&fUhO%MDeveF_jRR(k3H67czsCYMRDک 61Af> B 9 `.,B 9 `.,B 9 `.,B 9 `.,B 9 `.,B 9 `.,B 9 gGV\.&Ičӂsj& lּc劖+WֳB tX>q%5ݧ1_YYitZUi-8IDQt>7 r{.{;w4R5RTdnh *啖Eb(gVkEEE"T"Fy-9҉<0&ҝuĻ,l(g}>(.M|M_+7_r*W%A^HZrt]̥OUeT #Y0qlF t,UUv{^bRE fR4bR#% $I4*I^=!A*YR4.حFJָfGzYo{ñfn˞c_㘜YaY&Ža}kk<{n:~!ifcpΉ8ݖMkxv[5VGs'["y?볚G0Y=O>t?i-#c+w˦#?[סw~0;])vP|-?FN=,)2]'ў'"< _cȹc̹쾯~mRU 9|X{ s%"/^}74HDwm jהj">q8|zA+\k:_9"k_ڟ֗,EއgM^EGMaWe&Z vx+9W6XݥD$ڹ3xnő+:|ecK|;!y,Nbٽ^ v?ѨogB%>Lɏa}q0=x<TyOz;WJ~xG رCa&}qSႂQˊX質7c P\Phmo?50L'g[{SIK67?:DjtdKg՗}ֿؚ۾GlGt6u%q"nqlSo^,ծ?w)q. &TvjG0חvl}Ɍ>.* -\0^LkclDQ{^^_6lvlr`7Z7.m~H.k ָPX p"8ҝU]lc];?n{}O9D)c0o0ؗ<"%?+\_l_|ןpigw|MMӿgDKQZ#7Wڱ_=MsYIͧ8qN䁋=l2:F2y KsZTKDu]%=z3]?%TVBg_g8s t2z,w_{ ee xkż^ /:L$Vms r.ʼn}bZ$Y%V@'Pne;񹾂[nI'~0o~~qR.b|tdDs-t DֲUl,Sv(+ZS+^௨saSokm+=.Ƿ~78ǜu}>U~i N@L;OwIuHv$N+D2]B^./tu]yEK60Ou7JxvmpY5?JwE;N%| NU%/;yjR{O/ꖯ>'<zٹۀៀyTSWTt2Agx;^Nʲ_|)~=i/x)7V:75/gz~cKy?aX hhhqH$S!r2 ܱ1#x%Y_r2¼,C 9 sdn\ WO1Yq<;{I0UM˂Odٴr6Q-JL&x2,"gTx2lM$n;N]`$IKUbd!T@bPI#BG$QCP^j/,Y i$/2R`\b1>\~E,J8UۼJ;hit]W(l^7H`T y$I`vLQǿF +U#)-@X$VR &ms/eg{{{tyyi}yO} ᰡ>x)mm= >d"&lK}SBX:N.D\Ql6DE1# \-n1hlkXAP`cat\03;e?U fZ7ej 3K3̮)"E0Ys!g̅0r\Ys!g̅0r\Ys@ 00?D+ً;IENDB`deepin-terminal-5.9.51+dfsg/src/assets/deepin-terminal/terminal/en_US/fig/hotkey.png000066400000000000000000002046171475472654300304120ustar00rootroot00000000000000PNG  IHDR4 pHYs+ IDATxy\G8I " 7B#TPAKAjZ)"mQ[A>ZERtuuCu8ٳg#K D BR b@ $"!)1IAH D BR b@ $"!)1IAH D BR b@ $"!)1IAH D BR b@ $"!)1IAH D BR b@ $"!)1IAH D BR b@ $"!) UUUC?N|qq񑝑`ܻwo}#+.WWnG1L##!!!ۦɫVlG`60v=x`Ϟ=)~~~CHӦMswwOHH`X!}}SLବ$___uuA2{{{msYZZ&&&ZZZN0aYf|wt_iiiWWMLL6mݱcǰ5-///ʎk1رBGGgTJp8RWX,+!!`aa1ï_e˖}{I {?F\% ޽{444B'O(iiɓ'4b}&MufBd2ݻBOjH:k֬}ƌRRR_~P>}:7V~>xׯ_+++ `({CZt߆w Eb/)222#0`T~xw͚5---;vx񢡡!11N#tzqq˗/={v̙u֝={lܸQ0𨩩ioo$SNr!!!T*u*>y㕗߿!`0BBB.\P___^^~$tYtǭ9ίNnٿcdd *++;:: W;BP^v 666&&f̙D~~)''w/\=Ac2-믿p7嵵oRZZ*bdd޿ʕdr -jhh`7o$f,q\"OEE. ]cc#BHd BΝ;/_䔕|˗0g7nX`O/wwwkF@'BgAff&~DSSq; ͛7G~~К:;;{zz;w,^xeg/$ݱcGDDDEEŞ={W^!ɓ޽{Y<v횥寿zQ ۷onڴٙJ.Zh.^811455FWT-[hkkGGGoW]]]aaaց8߾_[[IJHH$$$'%% Rzggg--W^QŴ:FK}}}IIIOW#1113#r?~uV[WWWQQсwkjj6D*++<\>+ P0FPDPŁAȜ;w.<<;vxzz%K\~Vh!^PP駟N2O~8 ,]Od[]]abb3ʷ^vMQQq8% 888&&g&}xs^zU3,,|auu3h4Zff&J矝ɓ'7;曁-YBBwmmmwxʸ+qڴi111vBKKKEEmmm3f̘={vxxp yu{{ӹ\.D_Cdee=KNNN]]}{{г<OMMMEEwXj۷o a0BXnn.Dڵkzbb⻼C:㺡M4i֬Yٝk֬9ppOތ^e˖ʆ-''Kpn>7nx!{L&mUp>ebG-$Jb`dX,VWWW||<UD%$$888---~m:u>x7oL?tPnnnnnnSSgCCáC.]4PMN:rlٲk.:ӧO߸qc_zu…a,XrEJb@@iRRʕ+Zȃ?&L?DDD8;;oYYY#ۅ \\\∷A!d|711b4-;;!?UUU[YY)XnnnXXXAAAnnp /\`ddT[[|EERRxŊ˖-3h oڴ)***99y߾}?_5'c{Al6[p8; .9.''?.OVK*8!|۪Ç:::|ݻ{b0g&MNl>q?=_?{L0J eb&L`X?[ZZt: كQ\1 HHHDFF4Ǝ1+W]q 3!VVVo޼uEc8KvAi_jj'`|[/UeƝqK_|yii;v|R*** ii8:njj*3q`$B8!)1IAH D BR b@ $"!)1IAH D BR>pUUUgҥ .^B~w=dM 7o655LNN^j?%wk @H (f Kٿ{{p٣R[ߺu ooܸF#ӦMswwOHH`X!}}SLବ$___uuA2{{{msYZZ&&&ZZZN0ayzz Yf5-t:ϯ&&&N6mرcXn~>|ӧ<!㺡!,,,\<:k Ҝ[HO"Ο?!K.2 KKÇ"I)--=ydbFyxxܸq|ӦM\.w322ZZZp9JJJyyy|>QRDc֬YzzzΝpr>~ѣG9N ضmە+W:::lmmt:766ĉ!*zĉd===\ñ{aSSÇ/^:s̺uΞ=p6n܈rvv.**zӧOW\9P=nܸQ]]]WWbtcccɓӧ pqqquu,3.š122… O>[l!255o{N;5<<\LLL&8'++KIIJ9sbbb!$))!$//fP,wɒ{xxd2900SL,d)(( vyu"O}errr!*fN700Ձ aʕϟ?q~faa!&&&''s|s Ϸ!Hւ&$$>}ŋ{{CSVV̴~zddUgL(0O5[nrʃ|~RR$>ݻk$%%^z<iggwĉW^uwwdKKK PBFFozoT\\lllfftooׯ_>}gyyyЫWޚJ>}S07>>$>>>>>аw݅^^^/_^p!?<<! Q'/}D?*))<AK999b \v|ʕ+6l>>~~~+W𰷷AYݸ?{:B(88ƍĮЋ}BMMM!{{{/z4~ 7'hGUUU ER322m,,,}ҥKy㽡͙3ۻ;<T!Xׯ_pBݻ6lpss[d N4mҤIUUU;'?H}}}II 1n( 퍉&yC6#^'gO1,\.[nŻuuuxwƂ a嗐HHH566666)Ԉɓ'WWW s%%%z?1ZEE ޥR}In݊ZXX^:((h;vBD!... ɩ===}Bx<ܹsBd2YEEٳg\.D" .՜9sB"{UUUsss{@]]]---xzzZ[[x&BO `yyy*:wٳgӈyqeooWW׏>B(((y{h㩩;?4-33t "tuu `2B(::ZQQ' ,Xv-|Ww_i\7{9;;KHH())Y[[D ߩ$ww7%ߪW?WUUennnee.ȩS>3ys}GEEE?d` 77>|͛1118ڵk)))<oƌ7n{>>>:::o/ ,NIIx"^& 4))i5<L0a?oeeeng$B'-,,,X^\\LѲKnnnXXXAA^$hX:v%"ۅ jkk/^.XHkkU6mt={ೃ2+D dX#Scј}~ܹnr/^pppuFV[C~ ($555w޵ H ek[ Bc1x'|o9::zJOO& BCCϝ;W__?e?bggAथfZ111222syZD9Bko۶m R ZnT26{I|2 ;p"Q IDATs#|Gk֬>>'/VD"1CRMMͦf[ZZJ&qHw/_~&&&_~x_+wx"P\.ɓ'B}8q"1Nrcgggmmx_+x`,!)BСC駟tttN?<33ԩSRRRnnn!!!2obhhhkk и^+x`L7a+VHMMmjjp8ׯG)++544TVV*ɓ' )))WUYY9_/__ߴ,&\dΜ9nJJJRWWgقzuI^vZ..&J| !iӦظ~O܏ kn_z= }~dO׭[GuᄤB?~յm۶k ItPJmm(g>q= $"!)1IAH D BR b8~k!zt:狺4`ܻwOԵ6f({ڂBBB͛MMM###WZOk9@H bŊܮ.:eʔQ,\QQqڵX x8C&f_YYY6Lɱl99ѬBJKK\nbbiӆx;u+44Μ9BMb"""lmmBSNq&&&YYYIIId......ΝLLL0a nذG\w BR.;wx{{͜9st/t\R+Vx|IWtۅKƥYfXYY͝;LJ ӧ>|xbA^ݼy3oRRRCx+K.2 KKÇ"JKKO<إh7n077ߴiShh(\R^^qtt INt֭bccr;]ׯ_訩yfww7BHUUΝ;uuu{IvvvCCãG.]544n޼accsqkkk믿 H춶 :TXXfat 믿x<)))N/..633{gψ_OO!$&&dhh}qSSӣG>s`} ~~~{BEEE7nTWWձX,)plllAҏ?b'LziNLKKё&b``JPprssq8hll\[[K&,YR[[;|dii҂߯ ˽rʤIϟ?@d"8NVVJ=sǏBzzzJZZZ!www6#))ץKx<}}}2|?sˇҩO(-ZtCvܹyfbw{WWd]]]daabU};v,++KEEBƆD"ikkD*((U02l6ߙVVVx[]]bNXzIz{{-,,lvbbbffeB:::-͛/_޺uKlڵEEEUVV.[LWWwohhhll@d_>7o|իI߶m۩S~w{}E{{;QÇ[[[ddd>S777jaaۻu+W+Wlذÿ II7n@B^zkN*z銊Nt__xwww {{{˗.\HG w***ZYY O\ ѣǎۼy;w֬YwpTRqqqhhh]))'!ApPpSEEgo˗q'VTT$t>dUU쨨K.)**.Yի!MMͼ<"ii)1eŋİ.ˋL&\__|ǏD ꫯF|eeeO Ѣm\UUUfff3ċC؈RVVzv܉?͛8@\>'' wwwwq!Dݽ{FiQ===AAAIIIfffo޼骪 666srrT6qD///.;qDYYY-$V(+++8.]UU5HzMM5~O`fff͚[nuvv]vѢE8ꪩcN/++411ŋݻw7ldjhI&UUU999-\ؘjkk555R]]}y> ƂA'KL}葻+fΜIP***233É?Kk׮]`BZOO/**j􀀀_~=M4i֬Y_o||YDDBd߿3֭x.իڳg:gܽW\\\__O{UUUsss{QQQJcccAABhժU8gXX؏?)..ڵĄD"III ˗/e~~>oL&ShH?5QtppեR:::QQQ碙kY|)S222Epuu裏(*BqrrjooOOO<㩩>4-33t "tuu FC...D F~jiiox_ZZZ ,RsΝ={v~~p yu{{;.Л<iLǛkCAsss{{{~~>JHHHCCCsss~~ŋ.ohhА'O2%::ԩS!ee匌zbSRRy Ǜ.\TPP@ NPN8QQQpك^^\YC=>VUUuww'^+**jll|F}\*Μ9---/޶m[YYp8nnn899=y򤡡!%%Rk׮X,77sss4~깭,lRPPr}P <|}555ݑHG&%%RvsŊ޷o1iiiaaa/탷hѢ躺nD^+M\\ɓ555111}"H<0n~gg쐐777WWW=pkk+eee1LaΜ9nJJJRWWgق]z5===33344XOOSSMM6 NNN611G Iccc{zz޼y񒒒-Z4awak5$wBRSSSbݻ$BuWnܸQ0o`Xp83&wg?q,..>mڴwsGݸ^+8::Zp&JդGfƬqZ n!)VWWNѴBEEE^z)^L&pɎ?hvqSYY9q;v .u]qVZQQQx'g^&޵TÇ~w[\\СC+WP( p*..^x#G~ǀ#G.Ǎ^wpu[}kgdd9rdӦM+**o]}999_~ .\v̙-rqqA\[o˗/[ Hf<***Ϟ=r$`D---wmm˗/ ؂ u]q0ZQQQM5)$=wG}TTTc<H@ $"!)1IAH D BR b8~X+}p8梮蹺~w ޽{5C&idd7=$$d޼yx422299yժUc i+VxSL׮];111droCeX٩.]Zrhq~~~]]]\.711qڴiC䓾۷ %*)))((%2 ##7޾}:k֬+++99sp8;}Ç\C;ȫ3gtwwꫯշlreMM͡KJKK ÇsssBvvvCI'OLh47noڴ)44rxFFFKK .GII)//8:: B'"Hwm+++[[[ +V 3I%%%_QSSsn;w***@솆G-]'jhhܼy_uuu...$o!Ě B;vxECCCbb"NGb33/_>{(ȨE\\!={bbbB`} ~~~u^`AUU… nܸQ]]]WWbBɓ'ӧOG^:''8QBBã=33w0:QYlYQQ͛7ׯ_/ٳgՙLK/b~PuդI㓓=*###&&6k,|HLLɓ'֭[ϝ;b2VVV׮]KKKvڜ9sFooﰰݻwtttTVVwuu!T'JJJ=aƌL&Ns8<>SNr!!!T*򪭭-//?r'vvv!?~EFcdd *++;:: occC"M&H>,))ԩS>DUUkhht>?s̾ ;rB޽{7nlnn0a¢EB``p8[l)++[f N-//_n:l8; IDAT[n&LxP@*++OBUUUBsK;rȮ]pz!)FHOO۸oHlkkC jiiegg|嗸ۻwo@@xFFL&qӴE'I`` xxx>/H b 1_P``O?b0%%%D„2sܒٳgPPH3X,cii]vݽ{ .G vt"ee;wdddcEߞ :G=vܹ͛f|8kjllD)++ W`;wD͟? }||V\aooAD~~~/^:uɓ'i4Z10%%%UWWyN*((fQĉ\ĉeees[SS0:c335kܺu3%%eڵ-Quu ???==t' 1>~Dӵ;::"D"1> IIIKjjjɓ s#sݻwN,#V___RRB ۾Fz{{cbb5F̝;3 A0vZXX())IHHX✜gh4D#6PDDČ3oNP &LGHIIZ7sL 2в t:NLLL[[x###33ܿe@@]LLLzbLj eeen߾KX`Abb uWUUեKI$Ҝ9sBֽ{=zHEE!j*UUU3,,Ǐ ޑ˗|2??7&a< CYL&}WGšÇ'!!!--wׯ_#߿ugϞQ(Kfee}8GQ(bEUUB899 TTT V~iiittuu ƍ7 )((ZZZfffv?'Ix؈瘎`Y%-- SԹsΞ=;??~qzp444f̘Zd 166m"O>2%aolJ)V[Hk$jc.){Y7EI${d#48t&f:^Գ9z;44TFKX0GGlCO|S[$w.@ h{G(q8'Oˑܐ{[nO{s环/BD"=\]]}ڴibk<|pEѣGsss=pB>T]]yӦM=ҥKoݺedd$!%??ӳd…ׯ$N H?Bsu@XWWh̙---<ĉǎ}Z)++#޻'Jv???:.---##QšQQQ/>{lW+((०9B/GL$7$=v{"5 &2 s}HrCҺnwZJKK5Oc>Q%W099}u.iGyyy{P(ko9r\裾?BpIIIO}U\\\&NxӧOt <::EG,Yd2Ew`2&M}z^NNNTTԍ71??So!<dp,%}AH zAH zAH zAH z|% LU2227oO>$-v̘1s5ٻwM>G:::.]ٵkt蘔۽㾆L&Ĥcy@@kssИ^JIhs}qss3Ϗ:t'\MM#tpp隚u>aٶm[xx8/|,а'm999={KIIiڴi>N;w=x~w|w^zUSS4v^!c``bܹcoo2446lGijjzh???MMnv}%~~qKKXZZ߿ /]<{!)KEE۾JJJFr~BRÇ=BRΝNq+N_vX!FSQQ PKKˬYOqHѣGgdd[YY)))7ٳ'~w n>}zʕAAA =x/##:::ZZZڵ!rrr&*((xyyݼysƌ˗/ xXWWhBU,$k_~Ǐ 1c޽{ѣGܿ0I\jjj222ׯ_oll,-- nmmEihhܾ}nٲてUUUf…ZZZ555555^^^vvvﷵp8G:pu93ɤGtxĤNZZ!w 7Mᮮ!cc㄄"wwwrtt`۷~yyy644<|b\n]^^^UUՃtG|^_ٳsss,Y"IWWرcL&D?o޼lccsΝXMMM rر͍d~6m={6' rvv~ycccqq7BT*555111#F=pȑb߅ذar</ J=}||ˋvލ)۷o"N<.\97544ԩSōYYY...3fpqqa2n?~|hhhHHHJFuV⭒JlnnikkÛtz```llk׈{x@_WW!tӧO={F1 & vlh̘1 33Ν;-L^:A&SSS޽+,))[ZZZWWEPVYYikkÿ.^CÇ}oUǏ?uy޼y^ SSSǏBҵGVUUXjLB<ҥK\ґ#Gr\ ޽{oܸ!%%E&q'99FQԣG>{LJJ !4b<*mddڪdzzz2228x5k744$=ϟޗp 998uuu\HLb333}!NNN+W-8pobbK&K.KKKz>I"Phdd}%''S(۷~ľ ҫWBBΎD"#agϞ%ކٳ?\/l6ә  dX~~~AN0ˋxK&O8!6d^|c899]~(dz fBT*fh +Vi8H.@`aafkkw W9R ?xxeeed2;ĴWWWX,"Xp8׮] .]ZtQ111/ח^lٜ9sEBeeeݓJzxxp\ijjw9++… &M"qFee%BCk:m(''GYYy$`ŊdS__gϞ}\ .;8BQehhXZZ***jhh!jӪzxldd+Ν;7z谰ٳg9V[[عɗGaa BW^ܱclj'O޾}[]]=hР+V_^AAA(8ѫEۇo߾UQQ).. K.URRDQ(su5ﰶvΜ9!''nj8p3F}***B˂ںuӧt=ZPXTTDvC711qss -FyFl oLL̟ymO;W]]8p ~=*Bh„ +WܶmQps͛7k֭iiiHnmmC==UC۶mۼy۳bcc :0I/_?L>ʕ+mmmt:{!%%%iii梅ÇWTT0`# *1]Uyĉŋ߿dZ[[:Gx _B777YY@###4ܻw޽{{Ull,BSSsΙgdd;kkk:ę8qD̟?ɉoԩ >|]>]$xϞ=[zݻѻ[h D!~h1kA/**… BڵkĦAL|||p0>ʂ++/^m/@ 5kqHjcb B0p׷h377755eX/_LKK;v옂D颱BΝ;#G\v-B622߿NNNff,;GEPJ!iUbAUk./ܺu !d2-,,&N\3Nwppo޼9|BB?D;vB˗rrrxYCCCJJϟ?G͟?_CCkkkKKK 㧟~255%HhiΜ9O>d2ņtTTT| wd2\dɘ1cH$R~Fj===iiV޷lݺu۶m{2dBQQQB/^twwРP(nnn ߅_NNNAAÇBNI/ڵko޼)gpȐ!7o޼v]mmm7l؀hkk#젏 L8QYYJ7n̘1㹥φ[& j߿\TTԇ6&l݋K0aBzzzmmmCCӧOtjkk>}:euuuUUUxСC޽[WWW[[{a+++!BU.o"H/^N(oof"%MVV @bjjj^|BK NʗŎ;֬Ykp<p8nnnUUUJvׯY,qUrrrx ۷o(aժUϟ?x( ClSRR D|H$Ҟ={gXl&L@YYY%&&FEE7E7111;w,g{޽[QQڊ:\i҇*---//Hر(555 {E9::z{{VVVr܎+B999幹;w)LMM㓓cdžDGG[YYijjlq1ʕ+ > $&w ]߿N111=y_,*!e˄s}V t!$_ ~ɄcQIw*88B׊'N܍tFFFN <~xeeСCDݓSQQ3f 9@B흣Gl]s85kdeeǏ=֭[կ_kTt888EB5kL]]&Gjϔ+ӧq2I&mmǏ;;;uv9r`xAII޽{DIMMҟ)--!%%fee܌|B ...k׮]jJǎ+**b0{챶)]Lzzzzz0^q@ Ǣ0 zAH zAH zAH zAH z|% ?Go޼f3k֬z7po޽6mGDDt411 !)mܹ?nnnqqqCؼw-[444|DcƌAm۶-<_fSSS###>zɔ)SBG]xc8βeˈ=w܉__rD"!LLLT jjjbbbFiLj dr@@@`` L?~Çx<ޕ+Wp_~a.[QQﯠܱcGnnnYYYNNμy:P! rȑR>YYYُL?ٳg/YDlc455L8SQ444Gl6[JJ 񉍍 3gNdd$qN vرcB...3fpqqa2_'}}}}}d2955ݻDL%%%y{{KKKx#4!dmm]WW7p@PZZŋt:Bwv Fii͛OREC'NP( G!)a={dff򔔔UVտe˖#ʞ={$ܹ388!o߾duuu }ׯ_(Pc\3g΄Q(P\\o=z4Bǧ_~ʉ'l޼9//vPgXOSpႅ\\\Hd.۷qrrZrh 244D 8ȑ#wH*--z%"$e2/_\_ ;kWbQIdgqqÇgϞJJJx3gΜ;wׯ1QCNN@ PTT͛["$-+V!I ߾}KPf͚b>àH'''PAA5ޙD"q\Vc#%&&N8Q:::yxzAp,*t~Ϟ=[r۷.\ֆ;PT|ǑehhHx$v,4hPuuumm-~+6hiiTUUU5iҤE{{{_SLٰaBH[[, [b3227n\rrrss3.ٸqիWmۖˉ0h4Ý;wΛ7BP(}… CBBX,.]ZTTTXX*--%njH$ׯ_wZaIIqI{{ӧ N:IVKK ܖ,YdɒI&װ UZZjkk'FdȐ܇>{Bݻ7666))>==ӌK_ؒ%KLh ɜ4i*DEEݸqgFE]paȐ!3AB;Fi]a0ѝ.Ie˖ 'uv(OOϨ(u~͛M0033$)J]`;jjj\.ĉ)qÇ7ZFFFϟ/,,tttܵk?rbI$<_̜94RUUussCīG066{G$B흣GK.!ʞU9YfMVVV]]]||ѣoݺU]]k gjjj233-Z ]]]ˆ}¶l2rH&I9NRR544ԩSōYYYb9555oݺ5~А1b֭_233KKK,**ڽ{wo|vcƌ|rBB|||zG/^\VVFۮgwUpRRRTUUeeeqZG{{:Q3gO0D"YZZ't"͛ի/u%z2[& dX~~~s'LI=FΞ=aÆr\pVOOO2VU9B׷1""l mn՗.]JOO L&˞RVVFwO*rD"##===MMMqncc]5*ݻDIWٳɪ]RR_tFa322z6$$w3a„+Wn۶ :::/x I׬Y3nܸ1cƈOH"7 ŋb:^_`0{Iǝ[ZZddddddpVŮgbĈ#//Kϟ/ g̘! p, wItƍ xyyy...# AmN&wƦ',[, )))&&ɓF}Kχggg 2dݺu={0LPllP( DҲlٲǏ766={VUUU*oxK.ihhjkk333B***'Op8MMMo޼9s|y ѦN;yd555[[T*uܹ|>ԩk׊h4ђ͛7[ٳ֫VJOO3fg[`BҥK7ݼyG7nػw/B_577777ohhM6+((hƍ6l $*Ynݝ;w\ƍ===,Xؿb߻wO__رc>>>][[ۓ'O:::?~L&w}  ӽ;?{&33sѢEDavv6/**ڲe .\n]^^^UUՃm߾=""B#BRRR555]5`0֬YsҥF{{{с{gg第,55?|]r!D_~a.[QQﯠڱcGnnnYYYNNμypVpppMMMMMBB9r={VVV\fދ-:~8Quuuoݺ#&yybʕ+Ǐ@?r]mMOOp8e:U\" Ryyڠ bP(ܼy3~& p J$gdXBR$F ƍ븉IgΜY^^>adiiYWW7vX*АL&{xx>>SVVNLL=1778p Bhyyy0--ŋJJJ8޿?RVV߿\\g$݅ ,,,q!1bs̉(--J~ξK쮶])))%P(s!{Pdw t sXX@ !''ʊD"}S@@H 344 jjj7!ŋ9B9rL&._|QZCCC(x#HSL7r-[rww!y&QNϟ_XXCa_bbjeݛ7o;G]]]@[+Vxewko޽~坆 5JDoal6[l7"==uW!EK𘃑Bh۶mJJJ500HII /^puu%jXTGiii СCVVV?Їi$vppfR[x&Brǎ:::eeeW^E8qByyy5} 455ؘᠧBbYLcӧO:u*22RNNIܦxmmmnnnK,YdɤI련8`Bш!##3|''';;;;;e˖-rI6L0Ap֬Yl6w/Gu[t\hh(~<Ƥ&v*>>HFFf4}  lll===99aÆ}wHdҒiaaQ[[;|p*jfftBgx$IVVvҤIbm 4Gׯ'ONB1 ?\Ryy;v L(**.\ ++ѣSN!?'HC)CԠW[R7BRF|Ν;bG=z… qmuuug6 IDATgM6NxW!H87BRPqq1Nf͚ÇWUU}̙3xژj5tشu KbիW)k֬ǎ311MH)++#޻'JrMMM~~~8G "뿵ِ̨!CpV611qss >>>/_N2eݿ;ؽ{XC ={6úOHIŽNNN &\r۶mp'&4b}.ٳ߿z_~QQQ'O> BR dddtBGGGKK]v=~!TNNn[//7oΘ1c偁<p=4-##C(b !N啘hgggccsҥ[:88>~=@{{{w,YMMMffEl>_TTe\nݺt:T jjjbbbF:zhsssyy9YlNomm]jUaaaee 755MMM$pY,VKK6.АL&{xxP(͛7#}||dddBBBnܸAh8$0`@ZZswtt d2а w!dee%+++%%tyFmm*B())[ZZZWW͟?ӆeee6m``q¯555Y,eddBR2ĉCd2/_rrr" 0f+))!T*&NRQQazzz䔔 ':vu(  h4B}V^}ҥtPd2 ~g|К5kcLLLDrpp8p@YYYkk'L4777551Ç#lll8TŠgϞw D ŋxbڴi eԩ2dΝ;jkkwܹdFXRRRxU͡CB;Bի ++ŋK.ፍ8yՙ3g***燄,Y eeePYY{R\.I/22422222X 8;;gee\paҤI7nܨDuz6׊ =AeeB+""""vًۛ-!D"֭[*6zȐ!@H !QhZXX.̪lvpp0ç?fdd}*PXTTiEKK ehhXΠA277c SLR- {… MLL_x]SSS[[KLVSS7;GKN!$:' IIIy葻;LFihh6?|v˗/瑱/!$v'+b999͙3-99yΜ9sag.X͛^^^'NUJJ]!|@&UTTر򎇇GvH'ONzҥK }]{{nsyMo񲳳_QZZC_FUVVرCGGի'Nh#//UU$IGGW%zwb%%%%iiiD劊>>>xSB^±FcXL&'DPKiӦ޽{ʔ)㹣GP(3f̘4i'iٵt|v***vvv]5eTVV:^N? T"S ?}ϟ†>@ h{G(XXXX7;^aÆ/^455 6N|r/^@]TP(G)--gϞųh^S^^Ϝ9^ 樨(www޾}?}( vܹy?COOONNnذa}/^\z5Kjaa`˗/ST333))O" 㧟~255%HcDU ͭ!!!!|nݹsgȑk׮P(FFF};w *?իW><|<i=o޼yٶmUUU;=wG)))uɩMMMrrr+V{1ёB"--رc $NtmkkaglBBBEEś7ojժϟx[!iiCLWZ%*ïꪪn5K. o}||Z[[; *..>s̀pX޽+''ccc}}}{ _/^ddd"){CNrwqɽ{,,,H$BaRnжma蘘۽]׏?)( E,${nW!)BHEEÃӋcbb~7&x6Bhڴi+++]jooO\qttdXDUW\s駟T}v䮸WQQ}ҨQ9d?`}=)7BJΝ;O:_nFA{⅛}AuuuD*H۩Ӌ;NMƈ ]T.--Ņ4i'hhhxՒĐTMMMFF덍 :ԭ\SSSSSegg~[[[sÇ v}.T8پ544ԩSōYYY...3fpqq*)#FlݺxDR###+**bbb:N&)7^7sӧO={F1 Ѥb ag ;11iiifffn펈7nκenngvAAA&M"C% TF1 RUU=z;G$w^zv5WWl͛󏺺NJJJnn{4ݻ7n~[x<۷={J8رc~Gv<<<([[˗/slÇ믿ʏ=:f̘pMpqܬ?~@t… 7mTYYNd5Go޼966޾JX,GG".]zʕ[$#j0 ۽}|~AAޝBƏf0#I$D"M[:VMۦ.mRhQZt0>J|mII7cf\Er|~<;P-|y>癏=~Uӧ'ORXXyf͛7ՃTTTJKKϟyͭXLLlݺO&''xya_~A.)B!MMM D#82J޼ysdd,̬$2ԛtwqEEEٷ#G?p8W^ǎ[f۷,Yt?+h4Y ܩJII1BYYO梆 HhSngmʍ9s5kGM}}}\]]ݛoS./|rYY٘īW|}}!% $iH_zuŊ_kp3HxnB--#F >/5ZRR266Ϗ f@xWgapSn ===~`qȐ! ,#̙3o 77M8LQQQRR855pR;u?ɓ'...Æ Ax)SHHHo$---##BN')eaaǏbX#0cH:|pZOO9zkk#Fׇlr--- @ qwwD}wꕕ֭C]zÃ<СC'Ot${{{DOOO411'7b͚5\M'dp,:GIBR0 $ BR0 $ BR0 $ BR0 $ BR@0?''m۶,ehhع<00POO611 OHHX`偐NpܸI&Ok,^3ΤI\\\bccSSS֮]љ0aB466HKKQQQ kGGdzgϚř:3fם[gBRSfgg/\PVVvƌ7jii>|eޥP(lj'{i.]*..f0B>$VSS#edd\]]CCCMMMW\yu.o0]p!88x˖-O>mnn.// iiiAh'N'$$hkk 8ydE9jk &DGGq@k{yyԔ9rBCijgfϞ->͹Ϟ=755gX***n yfFKh>ֆߢׯ_OLL >}:.^^^Wzzzz{{+**2L5jԨ./zӧO?|z&N8qā AvcҔ$$$8PRR"%%%\˗/##cff&&&&++K[[[ b ESSƦ#''fL`2 .įUTTRSS}||Ԇ :Μ9Օ- 999Puu;kh4gg粲7oĸwttlٲ%77o֬Yd<G{./cQQQA!߿_tD '|_|P@B ʉ'D}~#޽{uuuSRRpzii)~ Rv CBB>|neeEɅG!˿]YZZ߿?--Ғf#-Zj``?V11w ZP(ǏsΰaGHG?޹|XΝ+W>~o]`ׯ(0xqܜuC>_VV܌444k QRR"|:A‡}/))edddddO%UVV  za"?.Kީ#"""##em@>l0MMM۷={p&yȑ;;;\e6UUU;vXvmAAA}}ݻwG566Ȩ}䉅p:'| ~ǂھo^744Ǐ7n;Am޽srr3f՗III!N7l &&6qDomll6mڄD544Buuu8ǔ= 9996c2 IDATƌiӦ=~}IKK !$"##PPP  sutt$^ݿo6bĈ)+++88ӧxo>կ=tPlllFFɓ'/]DV044IHH Odooo``~b2&&&VVVlѣG#{ă;w.--}nɍD.4:u͛7uuu&&&|MKK˸qfϞ}Ѷ›7oZ[[ǣ󰋋:::޽vK.p88psNyyy糬_?77PUU}2mڴ)_gii>}{rpp@m۶-''G\\!4w܎  ;vl߾ݽNZJy~~~Aൻ"*++333MLL]Zpw啕GgMMMx)ѣ;99)**gffP(:N쬇HJJnnnt:JرC tuuwء*%%:u… ;KdTZZZMM>>]EN8QTTT__ }O ʸ\n`` FC1D//#GP(:/''Gٵk8 RhoobUTTnݺ~M)$9s+yf;pX+W^~=111((hd&dwe, LE.$"((hѢEq30I cǎ)))IHH8pDJJJ˗/]_FFLLLLVV˗!Aի)fiiMwo9 B2d***>>>jjjC A ITرcdXW^Ńvvv7YGOfeeeB4f˧3w׳8ŇN'f?HŸ /%%%PQQ>x<![['NTWWPTssZkT2Fp8AAAA^re]|ܹM6utt㳃!YF9;;yF'&&8&&&&&F__c˖-^^^~~~f"뇄P\\N}Wӵk׊{ӟ̓|2iO6<3&m/_NNN>իWL&s{Bp޽))) uuRA8N_<|0==ʊrdѣGw>WYY9>>رcOB"#2ڳܿZZ%F555y{{/Z(44'bbbjwBн{__d?u.]*..f0B>$휴jjjSb_EEl DBR ;::~7;w駟Ə!)&3нrsrr֭[|~YYYss3>"4)FIIAdlllTTQ||

_ZZ舓tz~~_]XXŋ?sssp8=B諯JOOonnիW0>#rbwsQ^^ܜ3{{{SSS{{Ehkkݻ?!! E{HB]z[QQd 'm\@ZZ#ݥb0棜={ڽ{8_ {޹sÇz˗/;::fff{655xGVRRS}iii tY^^aq1={72~=44tذao߾}#ޣ/睝_~F&Mя,^ %%/_~zӦM k#o߾mjjr ˀxȐ!gϞI---}VSSoaaHڵ 555 ]v͝;ӡӧOooo'Ϫvvv>λvZ}}ҥKoܸY`www)))r|K\\tĉ ֭[;wTPP޽{w``رc#""===Bǎ7o^eeeSSٳ=<tǺA_${{ 64㹹2_uŮ=7ѣGCݽ{Xiis7ȑ#?N7|UIsrr F?Lwoܸqɒ%,LB@]p!t]vM4)77|'g#l |||6nx iie˖͙3GB/^SSS333}k׮ 'z꯿Z~ӧO[ZZJKKO:%<dɒ666溺&pQQQ%7nܸx"G-X޽{ś6m%ʊ<{l.9rׯV^-cbbb۷oEFF~^qOQ駟ݻoݺE8|b_~> 700"'vy>Kl60Idk 6-B[[T… q6222olm>w>`%홎^```~~ 92zh_dɅ -,,:4vUV!LMMo߾} .HKKO6M]]u> K]]}޼y"########_|RUU(((TTTqrAAAAݾ}{͚5s!'H힞^^^111 Xp8BN g Nr"M /_NI|~Ȥ/^-,,233G}/2GBsySn޼9k֬'N8q⯿233^q1wǏ\|haaAPlmm/^k. SRRbccp'i#GD /پ}2Fɓ'd5Bsr6UΝ ҇JJJ 6-&&Ü^XXNıo5y<ތ3BT*Ν; CBBBAA핗G6o݁mll6mڄ7qT'">|(4'\INNB9w<@9;;=zw"#LYYY\.q^ JLLx'OϪ'ONNJJ ^Y_YY~\SS3[e݅O^x1[fMYYٷ~sΆ\yɽ{"##ɑ?%m``~b2&&& yѾ}CxLڎ&7~Bhȑfm%>}իW޼yJƫW= gCGGׯ_\~]$'#&&p,--?xT|OoMOO9s/2w\]]]2ٜ$2|y'OpttAwO:t*'nܸqȐ!˗/ ~9,I8!X^^N|WWI&_6myGtR>ommmccӏ1|f>8|8B?H---ox8J%{¶lBa p InzOOO;w /lž?~}// 33UV]~}q--Ttݻwsܔ(_={;v ,i #77ɓfffݫmII˗EK8x|l8Ė7`AH `AH `AH `AH <нm۶b ;&&& ,x^<0t__▖.7iҤ^?Z}رc\RSSSWWeaa L4%666555,,lڵ! &Mcc x*_p!??vtt<{y\\СC{8QZZz֭IIIWwA{pSN믿&O,%%b IIޜE >HJJꡂ]B֭kll}@&''رCUUUJJJGGG[[!tԩ vw(y(##l2III333qqq(p;l6[^^!DR###G%RABÆ ۺu*Bh|7,99ǧ˷h4ډ'p8B---..bܺuKOO/<<͛SH:sLWWWPCCfwdX+W~zbbbPPrCCCMMM&f޽f#""X,\HD``Ef>a0ѱcҔ$$$8PRR"2iee~ח133}򥭭-B`zj YZZjcceFC MNNfwd2QRT55!CwT*}رmXWAP;;,ǣÇgٲ!fEFI I%%%###q30gΜG׿l%B.)Bx<wa'[[[]\\Ty~CCCBBB{{{]]]jj*p8 \|rjjjfΜg }@wBIќ޼y#\bllѱe˖\///??YfCBBB(..N]^lgg f̘qM.\PP`ooߧGtҏ70PAv5'sΤ}& $`!eee|w^]]ݔ<^ZZ"k}CCÐ[YYs\NEEѣENLOO:t)S#^CDvs,-----l6B{ѢE>somm}WBa׮]˖-}Ϝ9s򌌌Ficcs>b I?34m<oΜ9ߥ6l)TTT?|BBBXXؕ+W>n_?e0xqܜuC>_VV܌4M QRR"|dKJJFEEǓo Ǡjjj]v)888??Ĥ/@ (**rSa~ TwttDDDddd{}ŋ2d͛7CBBp9IOOWPP~ssyBk׮mll^h@ i4ɓTTqoߎb0k׮R-joo>|=zt <==i4:ԤR&&&x~ΝdTUU)ʱc?~P(YYYΝhFJOOǹ]ޟO{%Wiٷo9N䟴Ӟ={k0j( e˖ׯ#fΜb$o_Xaw|>?55O :u&""V </;; ccc痢X,333o޼pw"]rur!ʕ+qٴi߿|֭~,A#GV! jkk3|ppH:f̘28qb{{;ģéAx{,R``)\~zÇ >GyvvvEcƌ'Oį,Xy'8MMMrᐻ贶"ƍA^]ޟOθq㢢/ё#G6oތ˻ Ieddpk]HHJrijj>|!fii#<IoԨQA3„CR"tttx<ޙ3gpH:gΜZIII ƍp8d@4A, KHHؽ{p?|-p8S`-6eǙL&7$qBΝ;ddaapp7~fee?~<.3g4'III"%522¯ijj?~<>>~Ϟ=K+>{ w&BxQp:unnڵkL2{lGGG3wFA􎎎2|\.+2,[&S{lommmmm=k,'Ing+<|Z `;;իW^"m*/,,W\9mڴK>{СC;w_ƍ'--=a„#p^F#n544pLMMMaa!oxSLR/_LII9}O<^3YfQԱcʆt[[[111MMM{{{??x^xr) rAA'O$$$vڅ˻?KKǏsbDv9r{&(++x#/ ]`2xxOIG eLLL,X/],++666vڴi]v\ɓ'݋c ox%%%NB]z!|rϟos7oAAAMMM111555ߺu@ !ٳgnjC&*t +W$''{zz.ϧښb XYf ?<666$$ڵkdO`` y}ofҥ*1̙3wޥh/_S08sI}݁K&MrqqMMM [v-BHGG*;CRcc x}HjbbBGFFQ( ss?vmv'!X=TBB7|ӳߧKWWҥK YYY![[BRjjj䡌khh)~|=x𠱱MD{{HH*r!5k֬7xz 7$=vʕ+qcc㌌'OXXXדJKK/8pΝ;䉓'OfXxdТE233+++ml\\@ ]xGpgϞۛ۳X,sss[n酇߼ys#xDLVVFĴ6N~zbb"0wTSS !tUOOOoooEEE&b'و\]5A;qocciӦ<FN+** ŋGum{__߂'N/]0Ν;͋}ݝ;w^x1w\ 9sDGGpgϞ"+++ɭsrrBYYY_@)~Fuu;kh4gg粲7oĸ㭃;::lْ7k,~HH...Nduyޟ!>x~ &;UUUuttmxFsnݺyɒ%o޼yEZjƍ222A5A8Bxm5jTϋ.΅vvv3gYf߾}dySS޽{333 7ƾ&&&񉕕[1ڽ{> v;o܏M;::""",,,pH /'n߾M}\PPjbbIV;xQ__\|P+)) 11d2MLL㭬ȣG'Ӈ{ă;w.--}ptt&7~9 ^ns%E?QR 0I 0I #99y{i۶m}=bv. ïMLL,X|y $`龾---\.7..?7~>]{ ++[RR_}Ag&MrqqMMM [v-BHGGo?iii>>>***=TpB~~>~xYss8ssspssqF; <@H 6u Θ1ۛ\--ÇZǽz{{_K ÇBIgL ddd\]]CCCMMMW\yu.!!A[[[ɓ'X,:pT{_O0!::h4\˫ȑ#]>Ǖ`1b}B͹Ϟ=755gX***n yfFKh>ֆߢׯ_OLL >}:.^^^Wzzzz{{+**2L5jԨ./;vڵ~~~>='Něyyy tuu|رciiiJJJ())`ee~ח133}򥭭-B`zj YZZjcc#ұq(++?~&?9996e \p!~㣦6d)t̙!Jwww;vp,ի!;;,9Çgٲ!f` !$$$ a|r{K,tkP(0x ͢"|x<^=qDuuukk J577ohhHHHhooKMM%cDDaa+W/_.|kv]UU>LNN!T]]Κ4ٹ͛7>>>111...111111[l5kY?$$D  tzB;v}S( ?҅Ftҏkޖ}EDDP]GMsjj*޽K.YYY}>~ $`¹p޽)))8KO]]EDiii9y}ohht+++bŠѣG 믿>zΝ;}B"#)..\hgggii4KKKKKK6jjj^hQhhO[[[z./dhhS(GFF޹sgذa*+VF͟?͙3t:}Æ "xVA044oݺeooQY?E0xqܜuC>_VV܌444k QRR"|:A‡}/))edddddO%UVV 7o߾UVUUUUUUٳgݺuyyy'&s:::"""222=z~1cܽ{7&&111I 6 JYYwpϞ=?9sljڵ999O~ 5lwQVVg``??dj򪫫?Nq8[[ꫯpyw|>ŋ/^ܲe . jkka^8##ɓ';rHddd}}}II]e7o^^^ލ7EtssSQQaX˖-nݹsȑ# TPPpuuMHHXf 0YXXyi̘1QQQǏGiii874??_RRRܙ3g~ZII pAZZZ!:^]]%ݰaĉ+**V\)܈ܮ\ˑ}ŋulD h|>???_SSJz{{GDDj&&&mΝdeeR(cǎ=~w,h".;e*~z pHjaatttTÇ{+EEE@3/^؈{d2ꌌp㭭xF ~~~fff#'_ٳg߾}[;;;255UGGG$&&fѢEK.8p@LLLUU566vrIM\\AVVVSSS~~ Nݻ]QQajjpBS7P:t(666##ɓ3zxx$$$xzz7R]]]ׯ_777跤${{{DOOO411MڣGG:taaaJKK!C/^۷ӟ,D߿IQQ1???33MFFBt(g/_^n%533[hիWB<oʔ)T*}')))xR(seiii t:9Sn:aذawܹ>bwЮ1c͛7\nsssAA=8!io6慐WpHmR wkII;vN>y%==}Ŋ +̙gdd4rHkrc'ߧ= `dHjhhdjj) 1^lٲS?3HCRwww??Ç~f?zHN͇qgx<^ii)9y_Ry-ZYYYY^^~l\\@ ]xN> ƍcƌAM0AZZU`@HIIr\@fo|tp^QQ 3ft~ra҂w!VTTďr_a"jkkluuu[[[q9yʔ)755#S{dddHǏGG`1x'B=3rᶶ۷khh6zKϞ=EeggWVV999謬/m\QQQVVf``MP={ #7>q_RRUU/g>x ~ݻʺ෼WZqF FE.~MEEj/+Ç|>?99{\U?33p E]6 JДV+XWۊBRYT$0rG``QBEp}r4 IDAT~y̙sa_/ܹsǼv͇y<ҥK9˗46UܘիUV)nWEuakk/L .//755}稷B<==ǯߑxݽgxxX,SOy+K[[[]QQA&VUU-**lnn>UsƍW^oooW|_\\,Jy<މ'nݺUZZ j#ksss{{{OǏY<E###&gNJ_BxzU`(ʣ׮]cz<Cez~?Ia0DR`")0 H C$!I^TTԞ={SSQQQIII| 흕(~<==9( ")rww(((x{ʱcΜ9Coٲ󍍍,YMݗ YX.khh>`jׯ K_W2`F899%%%]p!77766i駟YbCQ0L[[{ppp۶mk׮r?^~3KQ:ujƍӬ !IIIׯˍ˗/Brz{fϞ]ZZ?QYYYGGUIIIwl6p8[lY,<==؞*bBtuuUTTN:588?[[[@dɒno>t>/ܩ:00PRRf !###ᆪ i߲eˆ bUx<{zz򬬬j[ ȠL+))ikkkoo?~b__o7߈uB틊:;;3&ܽ{͛N_1vtttttB$b5|ٲe/^lkk&8qU*;vLSSB];v444twwggg=Q̙3 μ{B:qzz{JJJAAAll,ϧutt"""}<<<׿Z466>dr>633Νۿ?'L#l2ar0K @aeee׿GMQRRjkk_[!!!?#!+W޸q>1<<\$YZZ ???Le6mddܼv1co{^p޽֭[sӧ !|>_.;vLMMMMMM(8p`¿f"##,";vLKK&''S8rݻ9ɹs+& }||TUU}~~~Ա8{ի !"ݝbg>fI?L*rrrJJJ/_N uqq$RQu26lػwo]]ЯJ666=zT&? ݿ[[5f&kyB׮][n+WQ__qLVWWy1uJKK !555RT[[5((h޽Ա;w.]D)))///7n|w_244oRogϞUS ɶo^]]}QGG522ra>MMM,XpѦ|WWWrUU5+?22  B:u0;wd˗/Pr)##YėD<+?쳽{_ٳyyy]]]k֬lٲm۶MєACCئ&ݻSU533kllryccd-+رcIIIݻv*..N_HRCCCBHXXXww~;E1 nj̬fꎎBn߾M= 111qqq+Wعsgyy>]]]^?5NQRRx"u,:t!BHAA6666m244&&&&H$;; ,)MLL}W !Ν{W===Ϝ9SZZjjjv1J.+~H$fffcZdFkk9uboݺ5a###H/=t󣢢BdV󩾞1ommԤE|L&]'D& 2*ݻw^XSOO:PWWԔH$+VXb4w Nj.--SNJ#ק>CI!d޼yzzzNNNԭjjpuuhfffhhFFFTXINNO̔رc{144r@QQф-.ZHKKlkkKl2UUU\.8Θ)ƎEBlvjj*p8G}1OGFF7n())/TUU544>~axx `x<ޢE,X@@rc{{{쀀7n444ܺuz׮],ؘ`~8***.]W^^^l6377{a3Ib믿VX?r_OZXXgO!?@߆pvvNKKS|JQhhhuuu:thT?k477!$Gp!$<<|N)))Qo^nnݻ)ޠYfedd~S/pqqރFGG'$$_%''|w999EΜ9>88XWWHn$UC1u͞={ 36Ο??<<ܹs6l X[[ϝ;wSI'܂xH쬡AgffX,.榮>E/_0bbb;F|뭷8`:&LmF?q+?_),,|c㏧Ziv:RfEGihhsss |}}cgϞ})N/..ӫ壣AAAc"阎.^H?&aeemG!Js` G y;wD"2E6l_zzz\f)m˖-ԍzZڄ{C޽{xɩʕ+ X,/--{.[II)??… bԔ&&&bDR\\laaAollH$ TNIIiii,--U|[S488X]]]SSfllO?٥ѯSdeesNd[B|ɓ'O8AiaaMILLAEEE.+N^ZUU$''9r+**Κ5+;;z\XXӧ9?---H4_SBKKKcccMMMUTTȸ/?Nqzzzbb"SrꆈH$3g!D1}LG4ju}}}?R-[YY?]E2soS((n6ަMVTTt__{K$gnBBBuuL&o,YBo*Kl/?<<<44No%̔DmL9x`~~~mAYYY,<<|dd?<-J !NlOaŽ!?%K8ҥKD"n=CCv211bK-33*cCCL&[tippH$*..裏n߾mbbfwVܬxǣϢw511nmmUUUmjkkK>S;;;CFWU677)))%%%I}ݷǥOLm !/^~]ɶ k~۷/\7w.Sf,i{{{MMu&ԗ mmmmIIIH3k֬1/Ul/9jii)//Ԥ9Nxx%u_kUMMM% 233eڵk6yRi}}=}^9lAL]eee˗/_^RXXpB,$`L>/ܹsy ǎ۴iCbb"[t)|2qrrbX_P;^Ċ{O6T͛7s\%%%[[۩w#룚eXCCCjjjobPMMB… 3\~]*y ǓvAm۶QDͩǶ5S\L{Bq555t$-**rss|4Ǜ(===b7$/ommmwwwEE6XUUբSn7nzj{{?#%%ﭭD [-[cƍc ݺukAAuloo_XXUXXH=3---?kתrrrlB+**vI?q޺u],Sį')66… 鮮 9s&77w BSޗEEE%%%'Ou333Nx!;+++;;{رPq״O>!.<.TeQyڵkL~w,:Co")0 H C$!Ia0DR`")0 H C$!Ia0DR`")0wI:>>~߾}t=3IJ/_.˻/]駟>tkqx]]ݥK=goݺV]]]"$'''%%Y[[\~!<{Bww1^xfY`%%gff?tS---yyyqlzd2c鳵=rHCC[hhhee%!wܹlDMMM1曎u?;>_$ P---H4_ǯ^:666.--555UQQ!ր.^8""b|#/usYXXB͛?RYZZBJJJrxQYtΒz]]] !uuu^^^bԩS˗8qΎ46lHOOW\EQ__qLVWWy)p_~ӓbD\SSS]]MjiiTyZZ/Bή|'J!mmm۷o ) p'''P( G|J}}͛7 !׮]066 !.\_1Q [2Co"R7ǨLLL[[[R4--mƍ{]~mbBYcc#`||BHRRT* ܷo_\\~{ٳgr}}}6~{{;]辿}&SSkhh_OYxw5+Vx7rH$]] 0H:\N-Yڪxߜߺu222prԘiooyƍ#!8999;;WUUQc5SSӂ̒JW*RL߂ >䓭[Regg_)fP}}f{RSSmll6or͉!|Ibb")|>חXXX=z"l!ޢ/\JBׯ_Jjjjutt\.ftww_zj*ŕ^^^/fXO<ٶmŇM1gv?u~ҥ:::Wmeeb};!H޾b ???T*H"## !k֬9vؘS$;RivvvLL I{zzoߞPYYyxmeee{{K~G@ZbbH[[[TT@ 8|]]]iisff&]-88ꫯygNQQQ``CRRR~~C㝝sssW\yF***k_RRRUUzE)nF{?? loz~ Y'ʢ,)6 Ia0DR`")0 H C$!Ia0DR`")0 H C$!I'ryzVzz%KƗvvvԱsZZZ^^ުUu <==9阡+++_Jlmm7n@[N(N0[ڪK$䤤$kk둑oIDATׯ?\NNNӟ,,,š'|a={+))]xΝ;xYSS17lxf,) 8NddٳY>L&{9r-44;wi6 gϞ})N/..ӫ壣AAASto::::::{dytoFҽ{z{{ɩʕ+:!䫯gX 6kkk_pA,EIIiL9MLL‚922(HaÂҢkjj]\\܌';;3gΌojΝ9sx'N,\*n[XXDGGB:?aG2ltttttT<**J ;wn\.#lB y͛7Qm۶:j,((===TCx?C##W^y"߱_zjUUUL-%֒FEEqYfegg>|FKKK$͟?WWKKKcccMMMUTTȸ/?섄{NDmmmBSrjH$3g!D":N^lٳg_)Y,@ Xb^-xT\.7..n^^^b)MMM˗/{ >丸?P_`ppptt4++K1]g!5y<ޗ_~y!XP$ BL&۾}{uuuttѣGOJ>?Nф5ܹS^^.._lbbB777ggg򦦦 񚡏7Ѷnzҥdzukk+QUUUSSR]]oԅѧ~jggbtttn߾ME/mlnnSRR,twwB544/',^xvbbbV\srpGFF8:YGlڴP..D"'gΒRnݺ|zI_KKKyyԤV8;;|7TM\>ac\SSSḌTZ__OߠW4"Ov٧ AYY3F</::Ϗ]]]X__㉎̏ƀcjj͛\'ќ9sol2jp__ߢE!)700RSS{ UQQ NIIyzy9x Z'jnnnffF֘%sss---hѢ \|A{ /@<5uuK.rcccś^^^l6377A[sW+VJ$22RYY9:::77755/:: L111--- *VUU%&&u*+++++n޼4LSTT!jxggܕ+W޷ ś}Qjjj~~~pp.\cڳgOvv6ژ=x`tttBBB@@@jj*UrrMNNw}C¢v#*>H C$!Ia0DR`")0 H C$!Ia0DR`")0 H C$!Ia0DR`")0 H C$!Ia0DR`")0 H C$!Ia0DR`")0 H C$!Ia0DR`")05o<k%?aɗTIENDB`deepin-terminal-5.9.51+dfsg/src/assets/deepin-terminal/terminal/en_US/fig/interface.png000066400000000000000000000456661475472654300310560ustar00rootroot00000000000000PNG  IHDRZ7A*D pHYs+ IDATxwxչ?wލ 0 z\ B%7!7\j*iM11nl^$[Km>s]ɲd{y;s3wϾsUTTB! ^zB!ҋUVIg:B!BH_QN!BHʠB!A;!B!)wB!BRB! J !BIʙ4&ݠ͗yjbLD@XMTw@l0l6hT!4-Dс B!g黐 ޹?PLiQ:Tɤچ)n y͹Lceffhz(4-vEetfeeչ\.!D#B$wm^1lr$Y!+HdEH$*$0p\59]СkEPCp>@/OȆK~o15FiJ,ctebEQ C}}=eBlԾ3`PF*I8!i 8:o_LG@*IsͶdkr Tmw#6(wOy1# F233srrnw?s4Ms999&!BHwIߋd2[M9:Cĸ;oߎ!8:3y5PR(Snh %rp!M!>&u C~~|0B!tH&}Xd!#< uu \ x*τ`H|bH6NR-mbѸM0mIpܽx%= B!d%Snd& C00pp `u\ 8⹻?m\Sר?ơĊ6A0if !B\.C`1!Dw^.1p@Yyb|]XQ#;Ry&Ą=/6(#LXh4T4e5"BA2Y2:bd=c)3[0ud2:t'55Lי5prw&8k| r,I5QLH|;:8$ՔdYʙ8MdY !BđBHs $h.O= .0Z6s$A0cwx_QH#؉s$͔E8vd/r/V!VF.LnϞ꽙MB!K.]BBph.w~;w1/s1hw﨟'\0Q&YO!E%Zմ0mjaٟ.6?"BK&7Jqt ?ھG}oM^fC׎p:w:`BgIiD(za{^<u)@>1qitQuމZUW&6 /LqC!2x-I_D2,;oźtYd FNǮUǫsvdg/=eЛ"Xs㮱4;-x-? ТjJڃ\8t[vɯ( !x "x)BuXB!_r/{6g{d ΀s@$նRjnˣ5_(xlU ;:nz|>w#̌G ~ 5Ñk8v)&̙'_n O_:xFO2wydAxТh]Z:Rt)!/f'#ͽw]]IS7&MSewe"^){BWc3yQpMYiŋR7\x ɿ~kp}%.ߎTLNca<U`b,0k޹ 2"!<׹΅&sy87y**jG$p}=]W} _x'Ól>9c@+wbCaT |(mb,gZ1O㙷˦b[WϹ|Q4]k- ?n9kOkjӤ!(M>t8#eIp(Y^X|^HonXju*ӭc:+Q[Qyx} OkPB-C!hbQrBż,l|\PM[)u >⩯!GFm ĕ  hK,,Z%yyx >\x hlƯKLJQx<| £\ UM],챯(X3s;~`vlcզ4!Bs錤2ݑ{<qgL|λC% Izw 癉׻'rwMg+'~a4 ZP6y As0CǫPK~3nN Qw a@YAK 896݃yz wv ocW bLnEր,I,r`>}WM8wnvO%pm]-eƟ`0|aZ> W}V9Aox9|0|!w?B!CGw_0!#Ip @ xMeLNL$9h}I1L|ΙĄ8~3M޹XZ BFnPyeBhF7J4րL&a `1)`W SQda `0<2 3`b PO `K rǢX¤a( >. x(b6! C+,%㥷F8*/"̓WEשOPp^X#*Nw±y>nREtg|@}svHB!}1֤ѯgtH`8̘c8ju4IU@-;;3wqV7qZW֊ 6 *، H! +㕕xA[6Ρ>zLpq O4Cr๥зФcl|XxbMYV,(Q < ƦsEJ|.ůƝy"AC(q180$▻"DڽPa|r3p&i@]'~o]u:'i}h﨟 Xy6tCDQ\ Z g , kF?PL30fLōiOY~W][oZmh1# k[|ulÏ'@+^I0a GBcÁS鄚xn_mXوC^D#y1\}b8ڭ;e:~=j~aĩDJ!rV8!_ >ɻr]+M9CĠB'jlxTJbYvU Ze|/CfuTKʬU v`Odf<3Zyܚ15nϸ8IOߓ@;!BժU}hgDbw bx&_*ghUl=rzili `rZB!3(L$U9L0 g &k; TT|b %cyBhz`ω{r{4S;!B[R{ \KdVBKT IEu'Wt]]zx,JfxgAH_qwUؠi,kZץ(5N!L$Duu@|x0ݧ@bw 1Yd"qwn˩O5NjF+QEÀGcO[$ oHbkHdPwY# 5N!đAIIBp < 8s>kc1t)x}rIx;@TIkk6)T2}K\|R ]a7&@ (IfoE >!BKߏ(mrbQg Aנ:t. pΡGNO\CC&9rT4H* {+? EʾגXUQAEer FB!m OMN"^AuI?G!b]O͍(BP%ڞ2o-2wzJXWӴ>Qp8>B! HIa879LXDA!%S;۩^7\>1@:9e4oi0{B!ˠ9+b7 );PYGz'Oekx8k}?4n0m531xLnkٚyN?$Y#gzF 8\e2W)9DWA|%^skVI@y &aB!zzwWΧDyHQ\ͳ7}CXӺ-oUHb93r4jAp]<.M=G!)`DƖq?wDm9aSk/cB!/軰 LΌŶUWcgsrYC-^K@ Onøo%i_s2C<rb!Uػ;7Tng`jT |b6 z',԰pS9vc݄pA^vOlezSB5sSb\KAwG5uVkRcTe.@4l8_ζbB!OYLSv8oRK}#(+w5[V87S W|’5.*QM ¯ т<=ĖL[nK ˆKʚޝB9n{Ո^A[[r @j-q-3G9-C",3fZ#0a(@Na uTJRZԡqCkpf?i5]q=b]ku0KLuiO5~R/AHLvj (j}"B!gDug\~v1 )ofmRdfXXR#VnXWeg<~Vqq.dE.#+Pa9E%ILtZ20 4LD)ӵP2&@*JH!I` GZc̚`pb՛pٴ6`mj w L2 'ҙ"cӾG=B!meZ9P'\ &`)t؜3.#YZ5[V+qukc$ L`١l ovMݮ5a0G2rwMX%~T Gۺ*as}&Mъ&GGt)JfZHqM Unq6skB!,4f9$M X"nL6saÑ#&8w^* ̇wښ8ǐ w%Wo3[a;[^kH,Y>\ע0_onpȘyi(ä1!wlb[c2I``ZL0} (1 ok&t˧rW+B!awν^sˆY` Pbrbai_ћL-~C##/"vW } _zfQ,q0*)SC6a=nɐ5D cn0z͌ %:턱dc^Ǩ%܁65j]B^e|bs7厶Bn"x*dږU!TvbY>P,G Jp$=4$!Bhs|id9mltU6nFt+cfnԨ~?2w=1IC(wl_?ߟnYY73s}ytLÌMb]ze$[5kzU|AY[kEYQ,k3ԗY|⸕9d+mnh5җ4kZ'A5G0gz*/s{4n2Z׏B!,***.ӹIt~!B! !BIB!2(}'B!$ePN!BHʠB!A;!B!)cwf7>S`y޻*뮒:l؁>|ܾ޴T-{}n?Ȼ%[roE^yߕ_۸xLᙝ, >6y>$ 2hzݰ= IDATxm卿.i} -8?5_rq]/x%ӇG?V6~&$m˕7vZtkE?mgMoUx{"^v{4nULKk=,:iAɝ "wl,d8'A"Y|3yN. >kT~;-/83\x%1w]w޺MM2y/X,+tȼ|ubι|a_\>QQBtz,R,޵,lO%q}nLp`b\n/#{o^?Yz F13"ϴߋ:0Ί lEgXqra \m+f74\]?"\ThLIk[]}[`œ.̻GUmo7u*yDK>7?ݤw0CWOyhH*"Q,I3>"@ΚrI;+{їïεW?M3F UO݂e~clQ 6mj:_Sq bGY/07r뛶cș3߽xg[|ߊ#.irԽ`_in1+97} Ї})Q:CP#DM>_Jy{z]=mcCD<nܽ K˅+Wya{_{yG3r.i_\*Go 'OŶ4TOV<=o1=W5{fzczY2 >tY}y#t`۪?U5|1| k*Օ)`w/6{Ʝ~(뾻T}CkS_[5 =ϺuQȖky?WuA5_8Vrg h'F'ZorsZ_ټQ6:oB7+~;\8$oQ w}nڋ w{")c~Qݻk_a05-[^QCk㞲՛rm{xCyO;0noiz򯾜νgv_o[z >)|isu: MR:/aӹwn! V/|U4n BR?jkYmg~I*gomgB̑; Ky" [#́@C i?nDˮwUÍ6ޗ6"5ўV]MMm4P@2ȷÐGVs升.9KRQCyy=/JlpW޺ de(Fq}`O6vA(cU6M;oZ d@|~En畾f5g~eo7ǹ*ڿaw|zvjbʎ,-ƚ-zjtۨ4HOq5(- oـ|o.)zW\.r]/n̰Wc[ (\N֭mI_T~^qƁZO^E/h,N=jt.>}S CՅd8zp`?mu@іT?1oc!@KC\䦴/lxu V-E7Oah({FmyJ^t>~/3s`Bu.98PSk?~suHn}ۇ' {˧ӏ~U~U=3-5v}qӾSTdMW F$䁽IJ@m_- !pbMYEw{y=KGq9s:ݰA|IA`z)9ׯ}҅;wWkwE @/_sW=@1gb}jPz! tnԵU4VWs ),t_e@_x,jm| 87i8 H{_< WkzNBډqEּ߯,xs![nmI>ɐ]`Z[xms-+*tocG@cȜtzGCG$O=mKck8\ۥ iGz|1kk9rOڌeU({kզc?r(q7=-{Ƶ|znm`C1 +o4VSΜ j A}D@@ųvwWy@g~[ۼ^_Ms^0X#[]_\bqoḷ-[N/2dgUU-/)5rw_a䡷wԦoٰgܜܝaZŅ +z=˽/,J9^ǩɦ"s\n c^n/9޽V ^ȳ0}|#0CuFa1 2f: <ֶ]kONu%*=>dЙe4:}S6xŔVt߹S'},e:{L9˞{)CeooZg& q9Z6zfY5SdDn6k\GfLCr?>!_Խ{)8U%`\a[463 |U{2$30x{ؖhl sU9,}𙿘1wM9c18 u߻m0-(:nۃv=m}*//Оqͳx/N -juF/N۳az7s'2o~~[}w A2$8X?#miQ43C+>{ !˚wQ4] 厫hDp]\l_e cT? 9N,ANENe֘eW/eن-4E[:ps_uF/?}ٞe+fV?{Ľ nZa)>ofտz`g d2ZMTE:aO՛,4;OOm4ۮ>Pw`1m[G_ay<'nJ^䳲ӯp ai<BqQrgihU'/偲}}GO-4 ;B #oҽ9FGkw>[}eyWw4@Tλn ʟ|ﳕaD]k9d35aQY]>kI46=f[?QrթhUT቟wz {vul֌^= ێTQmU߿\zyʢ1C>N9ItTi[jK94WNe^s᫳ qp4a* t-Qqh>GJ~i_څkxbڅVڗ\D BGu_zjVHj2c,=pn?_̫O=|I5S+DC+6|ȣ6 ?iX`l95352$1˻]luY0~l5 쥂 XͲBk0khߢ_Vlc=N.᯲[܂49X~ ]oزxg֟0>9t%}zo}G>%A> o}'i]Sj[Du37o7>1mG- 5yc-+Tb ]?6Eǻp혩_XvMSG|xUw4zwp$D5Xg^⩧nöOoyk6_tQ떏tp>a/p?gQBHgbg:ްI0鶷?I*!gw;7QӃ~b{zi ԰f͚Ժ3Yp=B@CD `GL/[rwBH*o!Ϲ5^Wn;~` dtbթ u_v7ބrQN9s{70\*[i󂿭){'ekΟKokBN}'B!K/j !BRB!A;!B!)wB!BRF_wӨuƛ[A'5x6_4!BQ_FsvnRvة7i|9)JǞ ՞>ݒi@Mrvab&1֒YjsI#i.i޺o]do)enlq9EŀZiI9QM7"B!]kޞ'lXܢȜS{ɹ1a9:l^ˢ#_?a.2PѴbk4`N;tͭrE0l[noh}Ni)w'B!]>=uF[nVb<9wmHk Ö`LPtS{p @ ϼfӴE;nտ CBiCVpmy1YRܵ>1)=~5; Ss^7`idk x} խ/ukͤPQ~ȋa5shm+2  :5(&6W}7`~nHΎ>&1=2DSpʣ~)UfKY_b#B!_RHa5` Oiδo;ޣ]e:UptYX ZNgoM «ӕhahprsxaM8}TU4ugΣ葁Lz-g<\` 3~h2|F EjIxu-L鈸 .WA !BHo3Cyof\10;[rي3cٛC_w@0lY}CFp]vtC̣ùo7|`(ԣՖţؑ:xIU3Khr-6a(ζX= \>Gң3DZQ%IiQ FWs-@ЯgPq&#/[KEvB;V`w } 4?*m3Ht oB!ҕDu{|_AN1,x0U&[$+GDCɰr#c~P옱^Ymi9caøE$IIf-6N*D4Դ)3l.ؐYO-{U޽\-R 5L40_r=7eM_CS/*ZnwB!r2spjՊ|555&挐` ,9XG9K]CTjc*ESuE%4GN(&!VSk xqHfn{%˥#>;r\-J.GP҇M-oXY,ZbQպ"!GF !BIRZ$nkPM%]^/(hdߚW2י8!B!).$B!$ePN!BHʠB!A;!B!)wB!BRB! J !BIB!2(}'B!$ePN!BHʠB!A;!B!)wB!BRB! J !BIB!2(}'B!$ePN!BHʠB!A;!B!)wB!BRB! J !BIB!2(}'B!$ePN!BHʠB!A;!B!)wB!BRB! J !BIB!2(}'B!$ePN!BHʠB!A;!B!)wB!BRB! J !BIB!2(}'B!$ePN!BHʠB!A;!B!)wB![%Ø'eDAȰa þ@} 2;dwȰa þ@} 2;dwȰa þ@} 2;dwȰa þ@} 2;dwȰa þ@} 2;dwȰa þ@} 2;dwȰa þ@} 2;dwȰa þ@} 2;dwȰa þ@} 2;dwȰa þ@} 2;dwȰa þ@} 2;dwȰa þ@} 2;dwȰa þ@} 2;dwȰa þ@} 2;dwȰa þ@} 2;dwȰa þ@} 2;dwȰa þ@} 2;dwȰa þ@} 2;dwȰa þ@} 2;dwȰa þ@} 2;dwȰa þ@} 2;dwȰa þ@} 2;dwȰa þ@} 2;dwȰa þ@} 2;dwȰa þ@} 2;dwȰa þ@} 2;dwȰa þ@} 2;dwȰa þ@} 2;dwȰa þ@} 2;dwȰa þ@} 2;dwȰa þ@} 2;dwȰa þ@} 2;dwȰa þ@} 2;dwȰa þ@} 2;dwȰa þ@} 2;dwȰa þ@} 2;dwȰa þ@} 2;dwȰa þ@} 2;dwȰa þ@} 2;dwȰa þ@} 2;dwȰa þ@} 2;dwȰa þ@} 2;dwȰa þ@} 2;dwȰa þ@} 2;dwȰa þ@} 2;dwȰa þ@} 2;dwȰa þ@} 2;dwȰa þ@} 2;dwȰa þ@} 2;dwȰa þ@} 2;dwȰa þ@} 2;dwȰa þ@} 2;dwȰa þ@} 2;dwȰa þ@} 2;dwȰa þ@} 2;dwȰa þ@} 2;dm')}IENDB`deepin-terminal-5.9.51+dfsg/src/assets/deepin-terminal/terminal/en_US/fig/newwindow.png000066400000000000000000000205311475472654300311170ustar00rootroot00000000000000PNG  IHDR pHYs+ IDATxy\ g,}7QnkQεﮛ}sf)BR$h)8wR,Ei}߯{_/fy<3g:Fv@X@,=o>F, `X@, `ёExyфuHefw;~iv 1|i˔: -Lwiʑ'^PTAD2́}ehrڭ] .ia=tRxCEeW3w餩ptIu{IGۊBi~ΌBf%s%uq6]?4/]`Y0STkGWg5!|tg6v6[vt{:Sw-"bvNn傅Kei&#4jь,BɯHQbuGȝ 5ʷX]]Y OQ[\D$>  Vϧ5~Y[\G" ȬRQ =&]*'7 zϦfq|B"v0<2UR~nθgs?k]or𞥘L"\-֒\Y]^^-$fNfK-IW#)jO -(ҕɨ9fO>f4:$bHZH,![M4[Ҫ؂w?BAUD@ԔǟU[P~vV`2(*-Z)sQMo`!OfJM}礡ZfӴ-i[g1KU JR"%aLIK*ѫq7,+$MAd(e+do#&QɯACU.d#ĐDљ5@[!EyjS-M w%'f !aMױb6$>d +_'B"zi9T5RL"#1g<"Dcҳ3B,P\bIaUGQK _uv?6ͳ|y~lAɌJΩW/, ,)e/PRL $iJ&9ftLWvZE@R/ |C*;H2MU#(j)۩IYTE5j#*fHU$|*Nx~LDŽI+-V]a:M-IQR}L.UIjc&O.4]TFzTSoeiHvc r0BF%'%2Zih0ELJ,8aw9ʉo|GfhO,ob `, X `, X Bekt@Lo$/@1 >Tv@$(@c"0 >1]7rYn<~xo2dOȘ!~g]|`o[8bĜS9}oC!crd~ S:[نTwl{GrAbN[[ `b8&\ZL*K Sg[2Vޞmޯ2r29n>{bך(teosq78o7ϖT>둜TNTyߨŨ0[â: 5K;=BSsEyՐN%sn>`2I//.*75) DMYv|]ٿnyw3xT{S&$*ּrHWxnGb}3cIIl7f1B#<~^, VY3мrb3R?wez쾿ǦZ ˭חy fm\ㆎYs-dٻ{KQV_GY@5lކi?_4|˩ 7j!C{m*w6KƄXK^y,?RlN_vjmPyp(iDWU!!C]SMW=P6ќEQd26:Jبvj.RRCw!뛟5e&P.BS@Ce"z{ʏsl̈́)GOޱ. `g7ϰqG4`#*71S):TɖuĤԺv TU۲r'YY F3W>ZDEV^Mst^]_.W~B%'l\kcn`n=@n7̦5ML:!m:/{d.y|wbcɊ,W]bOܹ͙n]'/@s`{ g;GVT8-?z۵ /;.NeX@tZǓ7UŪrb/yʛo 5qu~mn0΁mU7OEצI=9{=7mM\n$"k6P8<A, `X@, `X@, `X@, `X {[kyY}0<4}w*ti5nө =q!ߑ`WxEe}ri;妃̥!}ϣ#9WOjtS;/?z{t* !B;UXV+O=}}>1Y`ȘWO|.Q=0cWѡ/3 U5>z}ZS@@!D{lq!us:OhL攃B\Z[-=Wh*s1^V+i4֋ɇvMTtY@.vf̑8.w@tdQ&o R]~T>ipz=$""z͚?zi 07gm^1YӃz<9gͬџW=`tj~z{'3'u]gZv7SrL݇S?^=cJ狡B} N+&7􃺮1q+A[}?!f"lD-)kݾ95n # 5ꁐjIBv/1.1@D4P7W:zgJ]ldKLh$JЄ,+3: !9KgYԒf!- &"uT>&gBHIëmp{[L#@\(*EU ;<}AU9^\}7u9[ˣ'zNY`t^x}| ߜl /ۧ~u4+A`"OmP9a^!^X^g9F?$"]Lo3Uޥ5Tr4__*D7!cS'yB>BHDAQMϠ_`+W_'ao-s^s|rb3$HBe'ZJjFc,mU<݆Uּu<)fAU}PfNZ+8S}}ƥ<d;tWO>Ej̾tkLx#:3Sׯci$CDݺ'˂K疙J2 u=7:~~xr∃;BU.iVz4\]4-OD!a=[mLd܈k?'`]q}]FYvR.k.7r pXTS1B򫢯>#Y]exBsdU0ɳ%9o B1$~INκ,X_-#/c- ʑ4)BHjMlE}u^֑j\qv o`e1aSCnT!Z bcG|G{&ӎ/q׷.p/ ien3}`O^UmѿYTNZZIMpMuA39ڇ,BGAI[ۇV22f@v[e>k}7U9+؉ς` UmqaRl'^:䪝hf)!s/h&k뷅 ڮ,NAm k0b, X `, X `, X h`R'0f|Ӡ` jaa[6st.9̾C\ !7̡7 ;X|=uVht\ D3v^~r UB!f5ck;SEXJ31/8Ā am`62o߹~ʗzTObڢ )+L[zrUb?n@>y[^FvgFI~i۷MG|P*y{kv$btj~z{'3'u]gZv `j{G!A]$];ۮe5WY77TK/1.gD|VEۨ n߀B$oGb}Bi]" @u7|\WSm`~mmvPTՑK.}B)IuU H= UUUͮ;PEQ tٶ` `0YhN k2DUV^{U"nϢൗGLeUL6ݼF#mEĐ26obMϩ\n:dī,}W¿*%C=Ua ; ÿK]ϤBT5sr}B;BKhPI O9L;gH:X57B=fud[  `X@, `X@, `X@, `X@,ECNM8CERĎA,KzPicVo(h~_a͓v=NhZPrtQQ6O /ޓUZ#mKEBszLe w˻㵹] NȀ/Tm wu^u|yQK˱ǧM#:o7**ˣIDAT=yRqgt739:?%%)>!"/B$4S6Ц1!7|1岢DY4EP,RBI[Kط'cG战YҔ=`t˿],aO>I! .' m]V:Z+{dcpYNA܀X@, `X@, `X@, `X@c Ȑ!IENDB`deepin-terminal-5.9.51+dfsg/src/assets/deepin-terminal/terminal/en_US/fig/openfile.png000066400000000000000000004161041475472654300307040ustar00rootroot00000000000000PNG  IHDRX~|[r pHYs+ IDATxw[Օ8s+Ҍc61:%$B_% i KHB !$ĐP15bSl3꽽r̨h4|?bxwHoo/ B!6N9!B!TSO=E;B!Pu#B! !B]&!B0qG!Bh;B!BLB!X5{1$SB;"T㜫 Odr:C|^-˲vV`ELxkdW^!BO9˿@h1*\Mi*I$CKU^&iSg !rkz*ҴZQAp8n{xx8pgB!Pe5&jJ.SA" RDNEN)P( t`:*0L#FA S'#7qNǩ4]+ ]1:Ͼp@\{B!vsP$m9.|e:%(h.ύ30wNx~FƁM@B.P@g.!cl]Riy9 7?Ռ=9Orasx<񹽠,gN|@OI^:]mO=x?B!&T#f $1ToOAp\˙gg6mv|jd;5;֞srϫѪj,ahnJ`VS'CUG ;;6L~ĝpn_)_0JX2./fWV0?nhX;/˴-W-VxRrۖ9K.'=ʃ~#&EV{X-kz}^hv%u*%wG!;}g9s+0klA d`ɸ W/[wE<[Pؠ;!5w&N!:JH6A2y&䔓b'0!e_-3nYTw2~(qʼn;tRjґGX,6 erHZ.B0Arr 3K3ڡR2,3 ot\4?-^+sώs2v@n=S @A&DBK?%O :V'\2h 8–_ scJ6 w #ŅhC}GWJZ$xzN!BR2brdPɩDPGUǟ}R8! s{aȝk ?BT&7 + ɩ$?N zXH ){~JzB^|7DR>t I!Sm\(q|jl6~_Ĵ z7%_ۦœv}ڸ*ᬃ^ q+IXW=WX!Q*˞Zнh_⹪!B^j.aPpHnٹs p"uKTr"'&Rmt5_*C(O|./&2u>s`2 {~=?>-~\?s x z;ntM~Hg>-6+Oo_W>Blf)e'kGBe<~}#ܧXfO?=9!|iK) *=hֲJ\6Yls]6Y,6G4 !}z+#B *uk+!L*c@ @]疃k }k jZUFN-Sp8 Dz s \`D\`GaR0>qeSWˑV>oxa` 5oe7\i8\#N{.mdÔLohCX$q7cB]ȄL^{#:r'`ܠ{}Bat<# U!X;v)IM-‰;H'5tMnwB!d^ܽ 0qL#Dܸ;,_ "C6ԋzJw \fS3V'ז6ף\';ڀ' C?\EIg@O C&Ԭ2d?>^/s"WA+Zt.B! 'N{P|gu!==SrY DNxnvh2L:k3rR(:p9 8 F;Ȱ$ !h$B!jLсPr2 '"8ϚP*[Ξp<Ӡ01,8^Uts:?X:k핝tqG!)qWik@8(@OZ7S.ܠ{rMp" c.0 };:H.q(KR4MAӴ](8B!P-;#+RB B~w'OrE) s)gvgЂV4NX5%*d$de2YMAd28B!P-W9JR]s`0,{NL]SA0]^域}4ێByV%pd&٨\a _]DWÖ(gfɒDQL$>B!vs$qYοRkt0:Ɓ1Е+zHgtu5`)`ؐWlɽd$sOY$r (R. @-_ BME-~M l{v\-[ 0:T$՟<:|. eaӆ` j6::jvǣu!BF)}I3~dգEWK␻Rt!^BILQ> qke0+dbmH($vbzh۽^o(K!B%X6-fRJIv LmxS 'i:>m@$H([j܉ϵz躮iZg dkc?LB!z_B  @=c>eܗ|FYtҴ/1$Y#9W Ⱦg 4 Ѩ6fY~sM2L4B!U~b67Qx !B B! !B]8*D?$F@S4@>WQRUd8uUGG7w0ׯ]N1>~(UxB0q'ޘ GN;d˩$C%$$z4Vٟ' 7_ HF#;-; 88 ϸ\ =98)qr7Xֹ]˄WR;rKi^KC_)z~a~Ue?+94X g U{/ ~;>r:{L' u<9moN}VPxj bUv"ɩu}5N޷Tԫ[=9j2@2'wisx@x$^XWBŇ@?3zj~ŵ!E#,Tq-qHDHfuR>}qLϸ.G&]fhˣώzXg?]ӓ8 8t\ӌ_T"Aswwx6hH+[>X,ьz 1ekQUm"Ϯk_Sٽ\ҵl^ѹRMb#10B Fĝ 7-nĥ#}[1)9DrXFڦ #o={5D @t^G4R瓂~ E.z# $ (ӭP!QIwQF #K+CRlA;0XH ձN\x1>g{MujBcj=3)} Ra)sDZ2 80O:ooQ"O8B,ӎ ܱ'uK|hIy{#3\_X?d8`nrw۵Nv+!WmLR=r<05K;z[nOhK%KK tYweq٢S*Qm-pH(+;>e@i#'fQ)Հ%}YiDfU\9*<+UmiD]G -&^Pt dɩim4(1Q.U)*] aT K`0!K'ĵMEAuK 5qhFxbP w̡|7PKѪIwfYƗ]ηgZ"u۽NS 6XĘb`- &rf*ڝ\]1a]s/Znhyݯ jBa{F"#y70 HTH_j3$(Jƫt@x5hTT (VmqB`\Ulp*᡻- ~bwH:*yZ7AHQU ( 3-UXB|wE+O?f8 MYtdT_1gJiK[G(ѣ_o#w8*7XehF5Fre|73=oVbge 1`J>0aLWŴPՇ!:ߗ9; Ȅ咚ł/D`$ &a FE5 @-*=TVR_ úƝ$fTV+Lլ}90̍oN}qiS.&-} xBҹJkP2/G0$9,vviJP"nP=lr~FO{<χSɢh% MBЄ*;Eusbi  ny:D}g2HLZo8[\!{'\e2&,$n3ub Cr W`zU֚k4 o3J=OXK&k-AJ8O~`YP@qȿ$-MΧCiAPuȀo.1 TLhzp"#io}B$$Zm|4K/Jć>/ƖjZ9z T݊L|M̘@hg&ZoK(R[E[RCέ}T {\xyhx-4dg2m/_q+njHE?H6qƫ54$&A! +*C<.d;"A]=( MF}$>jQIN4Zs`mޫ+f9p@ftE7{jJj93=RV+{8, =,13\9;YWs<wB.ʔ6d5_6%~HFxl)Ϝ2=$e :JWE:*LxTOt!Y!Ԟ/$Uz4ݦNDO J|f2Gk0oUFd9w HBʖʻ,j~a߷=1nw4nx_/|N$Zlxu2(Yy$T?c5Ggc5!@D[emVIj~ xe2diQr-w-;N Smg=F! )AnB'T@( (;I-XrA)ɝ _z|2y֯ѾA2,v- dUiLoڎ16ɸWKi628&3!ݭ$d0JxUīO%_o̚ͺ6{4*2ˇ2bO oɕ`M`ͤgC;O$GSxTp7o 8Hn#X߭~)4|sygShgv10GOJ"$/I^.;(N"lt6wiyи6m/iz#C3ΝF͙|`xG>zLY?6?t@D6K̲vJlLM@ò-gǣcl&&l >tQiW2LE zl 6~h]tcVEO-Zq~~x9'%+8op_S6>_KVXv"zǬϔ&7nc8`lz.\곔|El%.Yy\\\ Oc玖ίj w|@db!>QHoo'8av4K<l$7F:(pob lPO?vYm+ou`xx|ABhW31$&g #T_yG Gg b"!4NNEsj;z|PW'{dZ=qvP˂ΔCkP~M4ox6>Ru}:[w5D8j|IBi{T%q"Y3` D_uQt*P6yHN\~II+"BS<O;{b>#Ըc|G(B0qoq!B}L3 ۚwBcBʾ N$!B+LI9N܋GB!(Z)h^w gT~@֖o.'VB]mw'$E4BM4N҂4* Urf5Xgr(ChmK2pE;ՓFG[ lI{hrH񑎖$}7$3v6;+Rሪ`V*R{VVG!vmޡ~!cjw8z1 ̅==7ۅrexZ*Nm`ƶk]Gz.=>~= _dvwXꝕzޕ\QmDdӋ-Rc ~Z0 [ m'cT,Jt հͤV_&4HXjʷw6k=A<"ˆl,[!7Frx0pF,٩CR2U·G{*Q*}*k _to:y6 .DXGһ+i-{W\'Q W ~)uh:\lv觏)a穿f5 ^u0ʁXkg~-rMO7C!3{K%=~EoV[2%>\^os]dZM|5A*ʣD3)')d}mFJˉ4TѼ( ;1Ⱦr#ˠ E]Y~p(j40!(o3\X|\De w&]p*^wۉ)ЗUm%N K>3w|Vg-9 }#Ze:tV/J=w"a[)їk@ _!~4 ? _(_)וԧ;}Lz[R+~GE$ >"gp-vͿnnNx8H?Ic#QB͍}'R7 v S6$J998] fàA\{31dR>'S2.["ROOs G )z,1ίGu gnysǤƨ=-!iWi{>oi5 5{ AV-t~8j.L䬄d/E0[3Z|y6g$3={l(d? "h124B" |?|_/?g{u+[H8@" ,9Az 'gS!wEKȦ80Ɉ,:2YV-}꣒a @ȵ;Ɔ VYk>E|2/sw*=oD DL+@b:E;>0WQWW~ҸOlU8aly~dWʄ 'ڝ 0o#ȅ!mnKp1esQɴr嬁L4j6 6j?aUʽ(qtٖoɎ)F`KNg+:`{e#?{Qᅦ>t 1 -ùe'qē醍CNd?BZ.X6GH!-(R2*ːPHڌ;-{*mnn5/ %>~`B^|lk2 S_vNa۫BUDy@6d<- _G-vz l4Clw=MXm+G萦sG1?մ =RG}PmHպt8V|HXqm%pWGϜŹU7*i/W!'\a>yzSc(ՃSʠ4bԇ-,/0DHp 8! ܥ2 =OԞG?S[uhj<q0*8I^7 gLfyU T/stѼI!iSjS2bir+JpD&#P/:j:^ZHhK`4%.$ g_n~_x%F>~AE 5Gµf(RRXnBjjU2 "cƢ;]GYjUFluɴEHb#T D\0q X[ =Et7WLCx[ sFIT}6>)[6]]SU=> ƠwF=#ӭ֬? Kv52X؊4yc|}wz+̠{ȮOk2]~~=؉{F[gcK7/+;!'lVN R“[V;ww%{cN0BQTKl߽~4" A̲I&@ F)e4X7X3)}4n.r5v:nlK~\^;G.~>@&Э~˦g]͏#]3޵{z2%|a$PEtDOlS=K;E< !FSö)Ky} 5Xr~ŗ[;ӡ5TϺ_ƶ#D,lU7Uሚ6`\4^ڻ7RNĩQ7ğ/EY߇­׉o%&٣]c Jߡh!Gc_ ~KݴʩͣD.; ^|ÓNoI~וˬi5>!B0qgdB!} en  !Bh7k+f[N!BLKHѤ5⎉;B!6yQݕL'd TfDB!yRT0#,?-pqG!Z`0q_H;B!W%Kexs} `!tw/;Wg1(1^6a 4H޿Ѓ9Bq6LEO OH0 F>?-vq3Zor?c&f'lɼ2k;uL&>-Ȯs8E-KDַqb=/[ܶ m#~چqVe-Π\~MGx__uЪ3ZToDn;BH ,aA]^\B0{K%=~EoV[2%>\^os]dȍjJ}9񤤝%oh4(PJas`E(O(#t75=j$~!^KtF)SA/)XzeѢr" ymF)LXwը'QbY(o3\X_SBScid`H)ժR*SE?S:x]"2n'ڧ԰:ᗋR7 v S6$J998] fàA"൷ܝLXRUww9FI\1 `I(P2q|wd\D=2ڟ4ACe so{>oi5 UJ;YcCNkMω3*3fZyİ7gZxnKJ¨,DJnzA&yY453Dv%)b0ke{c$݋.wOQMcH R}иvg^cP?{Pݰmӆ6鄦k~g ~zw~XǦ>8m[־ 8WڂG!Cp*(w濸炡OeJ̦pYtdT-/Z$G%-ùYxu #{o'6 ipʒ=qlR<|l˜w7g" 1N3zQ ]O;O:B3 o$8_7ѥf :DKz`ޯFXR=uS&ʕv^x3Ѩ2v*`*]W>}zc皐j}l^;Fv4t=]M&9,t@hnwy&* p}'$l)'!BsIEoID/5斡ţedT!LwZb%&U#ЊA֤Jo tL'BK +GJޠk\i$@{)zˇ|Ͷ[[,<ža;ZQ!x` p 8niR}[f@QR@QZTB 4t2KޞQ@rp 6S!TXO {ZҨO\(uTOG'G}/~ йr躓-U; =R2IB3 (It%WtL<,EzpJ4F?ue9}+z|{o&zN7vNj2aEK 9oQ4EAjS2biK'JpD&#iPP7A+Eש{Qbad_vd?Ntyku;zCh^m ԏQa)kXBhAi1u/ ^㇨dDƌEeyVefQL[~)6"K -Yno5Ʀ}X4X\78]\>euR5ӝII,lp`V)pc;+<E?dVGͺޜ_0\1a^^6aҰ,n aITyAW;UII~w4MkMlNxNM*M*lR|a|&qҞIcлxoA ZsVMkVFN%^J,ULzXl ( [뻫׻_sZ\d'3|8Tv79gp;]76 wp{Ӌ &dns[y.9mR. ꇸlz>Uqʥ铃吞0fR@CMW_+1ɦZl5xsHMCė[;ӡ5TϺ&llϏxn0BVi+P`4 T5t'9v&wCKvoeB(_}V>NL}oxWpĕ'm>g|p|c*a|\U___ TlG?BBYfhܗ<{F*8${Tԉ.rPsSe/;"B̓uSIaHLͼi!B^5B!Bh<|~)s{_*B! & c^‰!Bhw|Sx|߿i>.9 ܖ2B] oHEEVNF˓nSFfRg Bl6?EMk/r4aL [>߲hKO871jPbCG+PpYXfg#SKnV;"$!Xuڷ ܙ ;=`\ިAZhBwvT|ϳxp|UFq2u55 q1nxs%6{ >_톻BLgN[L 6D[]4,j{LVGLC&q^瘅+nL,&SbIqǭ~g"`{ eG/bE @eC]/h{E| lSFFӰH)Tb|e35A ̭MJ|WFa$.RQcMOX2e{wR []5Iq.0;&8?LW52B.>jD?VDzJ ȏ73~{k\34v j.1Ů:wr vu<- SRBߙzص(V ᯘgޙIQ]ں}ga`WE (hԀ$y_Fb|5!W0 DAEq{޷YY*fz9! *׭V0U$^$C忴Xq͇20d5\jÛX갩A A$8.K8Uľ[>1Rm|֤4qJ39`޽tWE2Nr'r}~|\uLpŨ¦quW>S/`t癚ăn~pUyʷ4Rf,ńѓ8]+OZ=`/'TGS_ӕ@Ǽqި;oĵM.wY>~Ӆ__5z=/*+fս@ }آ:| E3=ZfbJth0_%I*FV"*(G,8E`wZ8 r{p=+p{Gpe&Y )RdБRhpsg|s|ْ WZj9bk{hh_fH)܁OszEOklj##'4w.nH_F8|ֲJ%‥L!*qz[âTJ (_;kGȨ1Y;gw Lk7ꘇcIk*j_-("kaJVk(\yfSZ.D'p.$LI0MX6I XlPSѯhdc2@zXTRrZ lQv"G'wMI {R -:WH۵bW̗uv{7^st@ }~OJE>ٹ75L MGc~͘csK Uvx7[Eb(9p˷T<ݼpʛ,vxw[TSزfwgezi?Zsg*{xk9?]4@ t @OUk}dOly孷)Jsy/yE96ZHa"?](W"+uwFAat;R iJCت2lNTB:A;|BmXX&pvS"x=ԫ2rkt7I-|u/ ̈́qmQmC3HJtVXڨB) |4E1rq,$ ͍6Tk qE=kUq*++-67i;v<^\N5W;lpg}oZȟ"ǻOY^ګe3s!_NF Թ@ı꼌]Lm)J3u R'ޭmDFMsQc;n4bk~㓥c4-t_tky*d L yt:+4HаqJWA~Е;SF/ Hfmoz?EZ{,C=ap" f@Uγʚ+6sz6TZ[kGm vȜi./γHriVB@Sw QT5ve#}@I.9h4(Z ({@ }$p)](x=x^Bz\KL Wc w0oL㞣.Sqל-K\u?ԫ[ܦ97͸<%$)?-* )b;Fcjl)pD2rJq/_ScJ2PǓup2p,N 0˱#I<^``/Ё9[tUb+Ё92VZٴF=~Ϥh*ռs"Ա6kYJkoYہv]Qͧ[dPPݱesۏk,hXg˪eee4GeRTMMgntS7k@<!?Sd(j sq.%<&l332JU qZrnx(`N`WAry]{^xC1ʴ=4iS0WƐ( :1 Qpʊ#,ΚVT2hKAk5(RQ"`hhT[ %c-Uhw#\H J5F*)q_]nPl}bY+yeE_,:YG/]pShmGGO7R2]9tU$e Xi?BS! cE rGe^yty ;A/M?ve .@*EEE-@ |?h-Kip:OOE{MַTF\tGU>s:Fh շj<'LQ@- / mi[zZ9pI"276/Sl{ۛnƟNx`AUZN?1k\eh}QbX/pq5'T3csyvUDAmKKӸoT7̖BrU/T Nľ89ZDXշtMb%|uH P[܂3jL+{_Ao\s?늪391Iscgd3)Z7V+[{U6Y=)J7VYRkrZ>-c]*K/cwuF<`„~: ׿zP?癡э s{hZ}/ mzu$6豙Oo;*|9_k.@ ]:uj̙-?I#54e# Fo'Λ%ӧ9() €BPO]cк+_7Wk7&=ަٸq#yrYC\~I2+@#ȁN O%@ }q?k@Yje9d'@ -$p'9~FwT<[@ ]CZ3mr_0WZ5%d8' v:Fmg<45u. @ HO ܶB:dO_! |ZFt}@ q3% @ 22ɛ*{< Z :[U'6T[9#%Vvrڸoƍ<XE)@ ֐k(wG>≯6_AUulƘ:b${[^ R;E&Su ֣rNZ%: kS>S4"佥Υ8`MyGCFj_PPgJ~бVx"^qKl=%9na70Jw}aW;; @ Tf_`RRT#мT+ zj8)(&lS7TՔJ?XH؊2 "wW{Ƣf`q6LV=P+>tVa^E]f_j2PN| oTqZB,@7qB^9vy=@ ! Rb<8ņSHs/h+]ݞJ|$2Ye ݑÂSk9JL/˽Y4YTd5Kؗs"2 8S4_^7@#@ْ WZj9bk{hh_fH)܁O{#zZF'^FHPZ5糖U-,` QRjP%DYS?ZTDF8S`ZQ<XH]SQjA>Yc Ku,UZC=z+7۞r$eo':{`; *@DzIg Z~% /P xhMD\Kf8 @eQ0#*"+K 1mFAB v@vbg}dx*O@CKtW-Ph =P֫=;X?4?e;PԦ=/#l%am[}x,aY 5'Kk6PHb*'gװo]C%+TWcqXJJl9!;kt)(ϚWl=afj]4R>}Ҋb! ؞qoi-NyՈ5W]m?y9R7 zL])@L]6w &R_c)Q#JcdmrT\\ Vk]6꺻N Ym  9Iئ%:b+},i>w.Kx\:d٪߽5x^ M F U)Z{/Ab0oDݖXd15>_OkSeJd:3e#qp .I@6vO0ĜUXaԒ by][/4Lp-bCz{ΘW+k4eyu5Vb1fIGW@IN6;˲#Af.YO_~˾k1zz,͈@ ? gfu"9S[J-C.08(P^G# IDATAHszbE bezZoـ7{Ã%i`u1ω'Km293s@0:=$4gsy;kviF'U֙s)Ga#1j, Ge&{Ѵ }I#Γ%L31Y묜"ӈN *_@8R(*-_YNH<@W"KL M55oStegbl71USHPbϸ557E9kj/;~P.vg:qa;O=>G9jםcÞXS77A3F;_yu  @ P,ѦwePjΗLKA7n`.~=G]3!kA'̅[T7b,ǧ Mp<%$)?-* )b;L,Θfhw2˽J}J̌jV]qFJm B{[!DuhX |-yj4ֱZD0TU.Դٕ;B~쨥/>smnC%κ^n^Q7>0o#<*y?meEƏ? bKKz @ Hj _1HQ6K"EQ-9Υ$ƤFftr\BX@/V <ҁ"l5M,C:NeᦩmJI)+J p.dtaxy;!/dd${1D4ET|}٤o<"Q Ao\a`[#P8zr}E\˜8gZ Tr|w_gkZeR_⮿6̗$<70;.#@.Y 3 ?P[Tx+z3.ƜORb;e-g^`SiOv[`f/rÆ@~Hy㋇j.7&|3ggXޑ߃P%Z@ܤo,o_q:>sO~2y?xrכ_jeGÓfȄ.d|ZIv@ИMip:OOE{MַTF\tG*WPLkibyCTߪ0 Ga}̷4(oul[vhӗ9?Ϻj ƣjNDp\]9oӥe@iJx`AUZN?1k\eh}QbX/<7\P[2z͹UTw--uNߺRQ2[ UPov8;k*ETU}k8OW!f[~Q2WwEU-˭1@Ce~!گҾspvh(Z7V+[5?bm&fV? wiWǡx2]'{Ɵh/ǏvP'r$gM!4% H\CiԖ:NUT6'9֎.蓆_d^Ad̲6T@ ~(SN͜9e![JS(mswΗ%ӧ9( f|ON弽+@8(++6ԗ>O?θPT7]㦹>|C;~0gq^׽:j[qGd5Xsn^]}& U7Sɖҿ?ԮoKLc6+oyypS45(Z]SR S:dP`6jt~*A>n]~o?PKv@@a OO.`hl1m>C C;^|E3':l̾~Pox/bxe\h+W]춢~snu/.~hz3+^N.TiՏ6-UA044 k&U@ ҉7q?iX/W}w="q;@ {?frL}'c$p'ĩܳv˕]*Gʵw]ϸpŅIN ?(HY@j=~ Z%; & }yKJ>Kilk6 !;=ATKƓ MQp9G l|v|򾧷u9@8K!{Ъ@KZ3TNmzzq'F+fkTGOȘC7U~x@ S<i`CuܳXO5LS m9EW/Cx=w"c(E`tLJcPi>hlPPW+JҬ#%Um@yA8C$/&-u۬TM~U } (Zb\XXХ4&&eδ] L\mXQD@8h2x#vTGa g[o${a`t RtXvSMZ87gF.sTӧ(oկbs%ݭ{3ʐ); OU 33CL|h:6{XTJ[1;fE,V\m߹& P'\󏢊k?筻`⨋z#}=~"r(@ آ:| E3=ZfbJth0_%I*FV"*(G,8E`wZ8 r{p=+p{Gpen[T.1n=eK +\i刭y r} "$[rJ>e7ضu6qeȉ4_1Bת<=oI8`)SJޖ(?R*!&lΚѢ"2oLNٝڍ:XĢ@҅ڟW JkXc !C^< ){;I/2 8SLfo{jLR:#C>/k?OK>q oٷK >n&հfۖ_&eIz fSiNSZHVdPlg1oKٶ$U9+k \JMT #y$GjaXTYg%a1Fa#^-dS . K@c OڎѴ }I#Γ%L31Y묜"ӈN *_@8R(*-_YNH<@WwL ҼYlۛOс?n9 e )2'; 3i OzEjSK?6rE.\sN͛6Iw@ 0 ,+HB GRޅN3X/%WudZ r\ Wycuᇧ)ez:s0 @a-[<%$)?-Z/3ftH:a."*9c2MH*)33Y]btƥ*@/]6 R𸤲o:v]z$%E.Fm-TnƸXJqpF3tQg&2M+Kf+#d!W=09֚G8Jm+CQ@o#`6YHI>'m'F=?#@ &@RcIGAL^ h}Y(:mq.%1&02J=*|In8ó4A@ )DYJ(MDt{.U_V,tS0W p.dtaxS)O DFF㸦ec4W)>32MQb$q_)i6CeHlBr|WX1ΰ^\v_l0&1l1Cdg*9>仯352dYe@/q_MK]Hj VZ, љJDA>uo-G5Vg\گCH K󌧺&8sO/:~Ȃ>1rؑ)#'xޱp'ީCL?pQ%_.qxht$qAz;;L$y@ 1Ҽt`Jbo+1 U~1E-U9aoiQhMT]?ІmW{LQ! Zi֪2i2M5>ƕ/,PTk{ig^W*[>W+Ϻj ƣjNDp\)sU'螣NyWU  ! Y?r%MdWvzQYTߺl>wZqyNS7vYwzG@ HOPSʨ]$p'k,kV|pd#d;|5=@I=9{ڗN2/[3-~_l_WOx@CrTb BϣHW~SaÔ{}r-׿T[u.J 36~}ƭw;(h&{c+~'#n{*/@ !{?Zϣ.-e [`0a2Ql^yo|TkzmdP#{2^_Yt]/(ɓ\Q;20Ȼ5Gv1mGp˿?q{?/ ЍJw'1/Үc@ /H{k !S~vV<=ԴWYGGz9@_ʰ-(C54`hRe^ߕѤS^cu)K_%D.H:jzsuK?RkBE2gZ^b.m&y6dbPы:9"4?+ A@vBEo[_%y>yOo+J?2^?MD?[voKqK@ ΘS:Ո=h4t?QBjp>tڣAUqQMGx#ӤqꆪRS [SV@RjXܬ,.f ʠ=O"?4QUZ*FW6ho EwG}24Жa :2%1 q-֎BFVyrt'~fbd IDATFTh#$f XR"/uSkh. @X Pv{ȢUor^v[~` ߵ_}WjM?Z@  Rb<8ņSHs/h+]ݞJ|$2Ye ݑÂSk9JL/˽Y4YTd5Kؗ{Ju@G:#c<%rf<lѾFR-u%EFgB C/ i,j {g-[)XJ=,OԠJ"%~qvvy8-+tՂ},Xd{W8n=" HN"ù3u gF7 b$`ݳABLF֒wic2@>A' #b/.1=amٓO)>iL{b&Xk2tڤ _|mm=fm)o#[ԗ'}u$ᣯm_u[N"g /B4R@ -0xxzn-obǥm%R^2 QJ- "E>Ui^X^ni7 Fm!Mi[UyTY-voqL<Ph =P֫=;X?4?e;طvLdZ+z[FΠ&T>D^ZEٷǢFA^sR O(k )<$qrF9 ,u:TRKu%8% ThnĶC2Xߏ#F©BqQ_YxQηZVot RwFj11绯VZQl;tg[iAgܫDND : Quˏ+X;KLu@1B2k[[2FS1@'q`9rܙ#훽@ g YZ}=U4 i)igDT1Ɣ1v69*.e+5]6꺻N Ym  9Iئs;:b+},i>!ߞPYc#P-m#"`d_W_xVFhԅkΉy&/W7lkwϹfYM]yl@ :$XM)Ba' ,B ׫:_b2-9.޸ WycuFҠ|yb0;XUcAȱ)mq80EWE E̗qN{-j<&StRR<3%F`al\ѫһVmyl%=1duq{7w41LƅSw}Mw.p<(mSC: pVA$5\op(',NUӖRcRa #Q:9.s mp͗t+zziwqN%첰Ti(  "<9S+NNl9ŊIPκ=M6$Kewa w~y1y{>$yF@-H_d!~d24IaİDb v̌pINO kdLecg E,g4Hn j7a@nAYe&"HМ|e$RdluZe3cOJ)[J4 I}ΐ3ȜnJ>:?&Skn٠=h-]J&޻l )YّD(ZqbبSjJ!eM&&ãN8<KT$_%\'#=gߑo^D+Kuі9g1i-2/Q1Xi)rة ]1nIZ [ 3h,vȤ $Ldi ?t^>SJ&_י)WU8Ie#UJKΗ@ !M޴azbwVΩ;ux{QTm˪bt!@=J|a06]_@4kt,KR]3CՐt2<3.1;g\+g?.fdPKsQ}]Ǫ?~.rOǍ_4cb)xx2PX<:辦}S'9rMN5Iy1\oړn>p(} %@\Vc҉R@ f̘1nUqnvn&L>B$#) 60GՃf@vZ2r 1sDn+ٳ$r|<@ h)V"gj: ȩ _ U5.DZk] ~&e-H@ /"v2+sMe;@ 0H>HtnSIdOrv3@ a`!(uypۼ"Զ @  DH6Jv}yw*<@ >8֐v{2-N 0`(CBV3ЄЖWjg{۩ z,?v[$/ qKpaW?O_nɫjjG=ArHˆ)RٴNB ʥԬ6+'jw 7wmț=K7oY!C/7jht}к/$3 fWj2Aw3𗌝p75{A,`u?=L`rUYI:U!_ F3g#@sl[U,zGѭ^++XFx3-TzyU3?Wa屋.2R0rmcNu_ 0wzϹ9:F ;.sURdAt^oY\EIbe=+Hhdf8`&. &pN$>L'APyS gNj9b|fUJ6w/}q(YNGDZT ⒀ci@Ӥ~h4.efI4RnTV#TW )?Kd)rR審(z\! Ӄ }+J<)~@WLj2B?T"is"k\\HrR2?-fQq2E$79=qCiՖӧ'U0ϻ! Q1_z*,ut/v}'hbX|mRc`mΪjp eѢCBW7jILa珢ķWySmh@\ruiC^*4r%]IxՕ3@O)ac Ժ{UّEH'@g3EQ`3\{)*a6`I(,L.N0JggW?+>c-ydޕl;wX,F:8JRlZiZgz_%)'c)yifkR5#t[DKF>?(14P|+, H Ϋj̐QL2^Ӑm~1z%._GgjG;OHi s5v"ea7MkF,e`?w%wUK&ʞCxt׹%68W(8Glwx'T)2YtQƞh9g[)*yisq̩Z"˟jm{RʛI_^@/'qGbpI{lT@9=O7@!hOrr`D1lKxR_#4r>)59.yY)9h1q?{F'^G>g3dbr6܎Xw(רiH?S#c=܈{;зnX8|V$.$ V2yYnRYw< daj2lutĥvwAU :=#z\,Lv"7-P4c3{2o4'n@`4{@իۡ`!rB+sG֗IʤFyv:C#/O1޹5'[:MC-410㋡@R%hF+4=m30@쿏%#ܐ9$WH,NLۓN  }nANșESyYn}1x!yB(a$K"22 !ɨөs~Cdha0AT 1r70%H&GEJN'K dbR{=-X^$5><;(E8.r^LBuJM}?Z)Ąpxh4IJQ sth>2MQdy26@TfDp :6w xOsݺȅ!qA_;}n.ȉ$u^amEzU*LSŨi(ZCܧ!5WSp _«FLz??ҧ_86tH H7TAoM( AN]]YtE*d?mso-(z3g-kS_6@ zNwUea糮or/-wYu~@{8HG/ -)Ӎâ 6lԵQf0kΫ 涒 Arȡ{:~`NC"j=VǬ~Y/D8~\m[s?q\Gln@KJtL)Zm|dG݊g#**芗4Ml.%Y^% R@'SWWT0[{=9_~jސPƼ"*^pqHgatP,jvW駺}:zJr܍ĘM~ KQC2D[^qZ@9ۇ-+!$- Mo=k~?莫-*&]R/TgÛo1IM? IAuuu3fl7~qoИGaܪt쀩m;r-"χ>:> q?=EBo9s]v/kגS4r4[8N[;lIf |@ ?pEMJ@}Y@ Ї~Ԑ+{Sځw@ "v)(&{CSةa1}@ "½OjΩTw9@ 0X>HtS2C 0ʾR9p'@8: ; IDAT}Tp{@GMm#D@ 6DUqrSton0:N 0t:"N\U~pgU{6~hxhK+5R NN~t@ q3!\`b盂z (*;Y\_چD=[uxtҼ]#"ɔ#Bh^b2xYޖb U*Fk:+_St]kb70I˷3.Qfl/D89( >${9!%t wM2C[3gY_D߿gerf:q7׏"Gca溕[%|l&92x HP+SA\p֯)͑P`O/R,-L˦dlFXyg4ωq:pm"KɘBTжEɤq!zBۛǥC:G`ZV,Fʍj$j!gI,2E[nr9X5^p 4$!yzpm $1g%Ϫ3U:Y܅e82*t)U3 1VE0-c5kzϓSyg<2cMܵ`pݺ{It` ~m7jjX]'#{j@X@  2:IRpBԛL;EQ`3\ȷGM,JQM.L =HEo\js+ez'o!2) ]Z̕2sTG@E(F-!6Ǖ̶ IϓIP&pK7[D|VxQbhe@:®(ARxU8іd@L%qbzx߸TMJ5rr,Fd(Ik@Pgz?Z{c(JiXJ[PhR5hl=7u|Or. IPšOf?<;(Ip_;H0R!0ua ߼KֶkQ}.qUpSY{81( KY 8bԄ3/ZuPzT@ ~(DVfcZQOÈFYl}2J%ubl,!+hΑ{7[nt¬Zv kϿ+60Y!5i7q[6pEbFKwdr_𸄠ǀXЍ1`J̮a6ɏ?VwhUX%L0 e^ T% IAYK+^ws(ŹH_Lcƚ [WaQZ$lVi@{ X) cC-7(+DZ.A ++-kkh)Y4NǙuNzvF e,?Ędc) :`¿زeIĝ@ G d "3rq%JKjP86OќUII dsJBI ALk|t,o`xca^YZ.o:oG0B :zh)R7u.`F#G} 9@c }'+hZӽ)~=+6H"(rkLhL,ш#avׯbcE|,ME7[zO2ܜnWb4#_.gFU<_6r8\/StvBOz7@F蠩9,` AUD9Z)C- hnΖ)haYA$؟IyJ{_O`9<߬IXz5wy5ݮ u7(J5j($%7oL=kO߿$޷n.ҷ*ĥvwAU C *u{FDZ XZE(ԱY)$f941!As\$F{%ύHzu(.Jck1N&}ՉO׼T8RJ(l9TQ5 ֳ=^#cUnJUbR&Ś@D!6Hjn%b g#LݟR/DW͉}[EJJ?폫-tnx* ~K&6ܸY&w*7LbOK%Ǵ^q`dYqN9>>U1r3ּL+^򍖻16[~Cdha0A"9]qu HF LF`^[cyZ3'I$"s-珞 C:v! yhqe4`$f4kT<v] i!RʖBbR}3$̫x2[vΏ 0>c6(K dbR{=-X^$5><;(E8.r^LBuJM}?Z)Ąpx$q4oyu9JN+BE[)bEzon߹>@ H1P7E㻣ޫs*g]am:_EQ.u0z)(![ڨwUjNTѱ/)RKy v@ VC̸@l#67_nL+휊`*;AKsQ}]mڵ#9k_IM>nišX"ss'\kǶ3GvSqq͘XmE=j#KF|}?j%Uw~_~T[zkOo8@8 P]]݌3ۍ_53C5GI ` ʑhm;_g=ҟ̚'l]qK[1ny߆egnöwa|zz^9W/7ʮSLO>vىeH>|m3'ӖlJu==vZ{rɜ5gWs[62]17M)?}Խf-Sj"_f¼{01>ް_&_٧/aDw=~߳_9%tΟ>axiYzC+&w>r哋)O7| oN{c]=fyڵk_(p6U#$ētn A:0@:~ʪ.pci?,93ΞE7>PWo59ힰE'z;t9W?w-4)oM7K1;VZV8v1ps)۵?^z.9;>e.uK8wxJ)`>܅QW=eTįߋGSZ@C A3.'rމ@ 5T髩m..B:Ma-;\>/QB=k߳Oh ˿1?L?ۺ}M4f)}oGp8k7r;yU;DJ@߰ծ@a˪/Æj3KO~Se3}A?A^F\t騃=ʖ:eu k.e>|]+^xuܬ9F;yoO:2Hv~"MJiuA#>:Y$Fo\*U[, TC(T,,^Wĺ5X1Ecq.ʟ5%{M}%dOcc4}j8O2je<~- fOaRLk.:[Uj1V, ۔95QUt_<;}li8A3[I@ }>H.'ک[Mq㰡7GSƊp=AQ]ҕ 揗?]kmFsMxo9s(,KL}zB=Ij•+'rʢW[g K܌g{9U,Φ2άBbԗɄ@"( )]l_ǣߜIׁCŝN #}+.F]~Du;ҡi2|X&ic&D: & ي+/js$yo$1m.?]vq檏6,P"S&*lsFd~KQ͖N F]| ApϖL@i <*€0PD \gw̞:nİOΗ^mǟߜ-ž.PjyݗZ,7[K.96b_4#>Gr5'T#`,'/yfa7??KƎ7Ӏ#/󚉙qՌ=W[7Nsf\ ~ƪYw?1Ңq_qW@ ݐTAdShwdxBfnI [xonue6R7-Yw^9 Dk7|n@jxaѝ7= (ִok='GH^{|?sŸw{O?[V?艏P/=r}n[[L|kN1Od㿹#t‡޼}?|vaJ >8R@9i~{6\ܿ3I!fFh3ܳ v@8:݁.pyzpgq(CW@T;?l@*g`CWv9{kLn|ݳ:9:oV"=F"*.LN^I1Qj>5)2 !|J\RjVM땇:hKZ'%rys?`@QV_PWM1mțJԳUg0M'5-8Li1+TU*&-(16rV,a_ѼJSr+x @Nk_Gztѿx?-hGּ D K!½ə@oX^!q3) U[o195m%up:E's2m~=B-6׭4'*1c[7ɑ![h@R&w\ ☠ZS.~ŤMyh0{~reifZ6%c3Z<Ē;Y䉞G93:& h3,xivXf ub 2'\w6E6քXز7tiWo{|K2:T"$o1屷ȱ횕m/Ϙ4d0Cqo:}I7NzsEL.,^"c7.U|XuQr~Pm&ӂdi:}s&+!6&xfS+WɎdSۖW%C%= b@aF FVRa3kau`J]厸e_(=Ĺ_(xyQ.SJ($gE/x͡؛jM3"}K|2Yk.l]eF)j Pg{2i@{ X) cC-7(+DZ.A ++-kkh)Y4NǙuNzvF1XGh ,%'kk<`@ 'نǒ$俁p,@ lE:Sj6Б * Kpl9U3j"$@6$1]Vm ^㽎zeiP2@wԉOZIM"u#0_W(rX{O#}F~+C8zu $tod k_ʀ i& #'K4HGQ2E Kqp֤ރRUfޑOѭ*qo%ywwҏ3\#*/ 9 .pGk˗i s!['=ۛF #t0 "ʡCprjnwMXM53.E  eg,r>)59.yY)9h1qj, -kb]*K?:o$ui|,tJPf+]Nή 0ANǐ!Vޙ<-O Q2QӐ齐*p}p;(sVzO7j K[%_R!:=#z\,Lv"W  XLެ EwϋQ`hoܢYnRYwl-d:Q)7dFBTJ(l9TQ5 ֳb7Frܲ;\e토QU@(ێ(iZ D$jQĂw"P7> G@  }8.LZ;N`MdIȲJ8)'ͅddeydrQDwV/7S e $g77_R4qLc$#F29rYȘ2 TZiy0^JӲk᧼qއm{?fq,E4`)FeLRrY^ M_@K%hh ɺU<ӭVntw,G}sc+هվt)*E9h M怩peU4F:9>MS5ǒIH *J 4>/-̾M 9aWiZAߙb*7%D[.S-VnBcvY"}ΟؤУ=tŔC!RUZGj^v?D.\H↳(%Q97RcJQ3Ϥ)՛"QUP 9a糮or/-wYu~@{8HG/ rF Rv蝦u~IZck`Ng%bs7%rcMgpdˀ` JY~`NC"j=VǬ~Y/D8~Ԝtwӄ69@`.z.r6^##Bռi+mϗP\ >,g<u|pr{lDY])ؖfy2PKZoLߡ!{A{EOF)nF]K%`j .伫`h_S, L)ƩTc5~@KVy]j@~\X&}DAH4պ@۹`xǤ_>mڵCnU\%k7;Q_ͳ T2wN8E`x !On=ms$@ iP]]݌3ۍ_5ӕ1j?͜E {I>G_] yhz c< `ڵdAN(S\f`zǵv̭JS@ ApGiŎl wp& D@ >Ht,pV>[e" @ :p$ b38`Τ%{L~@  "½j@ G#DdΫ'9 @ a8Gȡ 7 s4@{pXϗ"dL1f,2^캕;"k bDU@#4` cfwg_"sGI`OƝK/{gH>􍝲GOgbhOVpazV,A'Q@T}Ѫ18=}hMmi|qV\ SЏn#Fjڥ)qӦZ qGF;@ d 9}l/D'SZ zyj0y*[s3I2PxA urt:W P*ǝ77zRl(6IJH/!u23&B|zlfwfΜ9{7ssϭFM]'Jjd$*PwļGF\&qK@wㄯ;=hr3o}YLJ,ۓ[nGn:3s`/<`D}0_.S⼼.? AV㯎oUEDZ3R'61Q (O?t{T_U|7.ixό2nJ_o<]gH9~y޴Ǽ%L}tE3bo)!=Z`wߪPaj5=PadbaޡW ʔ6TN^{0OElSsC_reԲ*|'_>G Vgvʯ4 9Mg̑ɔ!fRvL*6eDi0ؚ2IMOO j{Xi۷4C&fJg;Љxq Y#4TW'5āAb"A/x*m‡&+z^Tcߖm yo>xg\ٛsryɓ>8~o^yx+_OQv}|wׁOp57tGr =$ZD=gknBey KįIVo-$SlkmqonBGfi֎7O1e ی/ޞ*mϟ鿨_q"]ъt:si.W=rMrTL_vg_f!R0]Z=`71CȠz6EvK{ =׾@+@ek]0@<̓o=myC>}o\]\*֕J_4;g9{mAޛsi`Ͼsö'ݏ+Onj꘾@x`U뺭gQKCaOF lotş(_dwS5@  `?^f|`6LC1ls Q`,Vj祈g%#t d9(\Zֱ&`2 oaLX?^q;ʮG F:ĿL5H-G.1f.*% Y,*+㧘cLsgP1E2'"Cy( XL1Ur0(O;A)>5/ǸU ~P?I`Z]!Zrf$(pA_Ij ]3 ZF֦o.$i^೽ Az 7Ӱ5bWjj__տt+2tNp~&S.i(R=q'0Q;t)bp'-W C4veP\q=6n)2LŔG ǟfםЅ9y4+CH @ 4 qۯI'Xn$\8R6$,@Oan2bôߟlBhp/'[ˀ㾆k.^PW>/^[@IZRcHIK]ĞJH8J"[u6U#iV}TRO.4h@|U"xB9IeSA }){bFx4PKF,7hH-*W7b!6?N,IqN_+9S}Z#3T gsk!G= :Ѓt1|љ.x29acE%/(,JلVKҙjW`/xKeְ'Pm"8|>E޵?$φÒU#)7E ß_˦/Coh5ؼ)|tեmZP _PM䂢Px@ CD0b:ʤ))}~?Ћɽ= >)-R=-@DVm ÷Dsz+gpg#Uc$c uiX^Oy9% XLw!ExFl_*9-M#)}iPedP{Ɂf0˓J\Lļ@xsv@~)z\4@4|)ru$E ҆կֈA b5^Vk$F6$TY*ު'՜g+ [< ~u 8J<ԍJu_zue60]zuCk PS)]D׼~Gŋ3Уg1z@GwWq|:)ƿUoőuKlWO?c4zwt^%e;Q{~ M@  c"㩈o2, .ۓ*@s;J4+@Rjx4~Aͱ[%hxDlL\q(;?mQ6C/jpٙXGsΤK^,/ƞ˓ 0##\+qo]5bkw :Lc0^Ԣ\9ObvbT 8`Z@Fxč+1W7KQEE CӞJwQ&VslVt7/d)J>2|tp{uf=*r֋Onů^o?ƽ}}^zuX/mKup 5E\3?||>0ê_<*s歺aƷe*\9m9@ !eqeR CY^D ,x ^>$HAAbK~B@,5-_)m\PZsLtRya Q+ԉpW)RA` X1,D"38ڽg{Z*b-v,`PELyut.R-g(bk\e7E}Yj}l@Tp m.ħ"-24Uf e-K66pKd*kW&D1brLCUD$ ;QnKgԛjκ  IDAT5d,kлY #2%]Q5mQ),MF]CRg/e.l流.Z<ԇvNE eJW^bt"8 ̑b>@Gu~u+Ҽp??5ܧp+6R0l[7ϺZvx#|v8PyxW8pa}"}2'X1e>טkܼ-&}b¯޳:DJͼ@ NRӒ2,}ܡÀ\ʌ\riUr_f i msgU隣4Lr{]jۂ)J,j^H/MS px jBTL,)Sy*Miny(Wiifp]*&"Q#umS5 }LlUߤi뜺2XaU:$Ey)`1їNJ$}'mB{'COYЅOVYƘhXK׏S_CmE!"6>;2,;%E(< AaR '_5ʯߝnCqo] !L#yߐ}ۼDmr%G柾yѻn R_Ƞ~jnl0]^PW\{MR Pw-@  ***6lX{# xQ1XRf̘.gy X=4g*:s*M؜6.5/eqʺ'brss uBCvהQ 222ߏ@ پ};9""(27R-zduĝq' iBb6xޖ&6M %>Q@AOډ `.),w9?4N \Ugݪ3{8e֬p}Msd!{;Q'驣C D̖*ǝ{uƵdy9z5&t,@ \1qo'"=cU뜮[hh@xgtSzj¹rss[@ ⸷e1814k=8@  qۉ;ԫLu5LP:zq @ ⸷k?6\9D.[u@ Յ8Dd=G䫴B(^ZGO ;@ B{rs!ZY1`5 Ce巶l%ubt ڀK@C@" NGVYosٟKbx 52TY]j> :K3zvU+n݃jD3mF'W~_@(la%w2ƿ$x0G9*L$MqsU7y8PbJKB5yO]5gws?"} {!1v ѽkNɓ(5]0(S(P: zw6tRn&KV%J,(г4hN{v\ 6DoӓӂViZ-䷉YoQre4Wh(פQµ:+ wNsdw2Ft녬M\_曷 I 3U-,5w!4jK(ge&GjJY))IYOGzErL4lBILb >ڸNEc;î<"~%x9sva,˫\IU>F6V|#g蚠{u=ZĽlhq?"C<Ŕ5;2^{x{kP;V(O@nq3xp3}* 6,P`L:x 5iQw>htӨ9SErj;nwQ;ҵۤFq eZT W)8,+'?=+Rܐ X;bg$î9MlyLቀtlSi Nw@4J/92Sb1@i@ ZwM|.73Jq d~1K :6y.E)$uR5ԩZL5H-G.]4sQ]/aHrg UY?EF%e舭un 5+v4T=W.gJR7t埤f`U9PPYehm&Bu9>˛٢E2i!"ΛEI7HbQ[x},0)Dyj J$ vU_,>b+QuMV}k/t Č:$J{J޹ ei@$:v&u?p|D[X@Y]g'zV-لGlTvǻ9(GG0l@ nGQ#tKC9/*E,T*F Ve@/^'p70f){<[`#G6$ǡ€1 t_| [?/Ā q q [Y6ax#^PVwjM$k0qT~, R0wW՛ |(AxU`|U3洤GT0BUNa@`%fK,O:(r1k5Zd0fЁˮ_&I`ԥ;< pN֪eU~jgvH5zWS/;SWr tny'zOV ;tLJ,'I{)()fNq(MA!ٚLȜ^o8nt(-4`E8Gs*{in1;1JF0-r BB 8tJb8y6i Тљa'zǗ3V*K̠v@,)ÜYJ=`;P't8:HbkFyt\lAJJhE1Q]e= &S#`G)ɫ+拶l<3kˆ;28qǨ^Ɵkrsr _mּzVG=@ 4帳/ $dz^D<#=G{x iʭA-52$ T0X*CbXDf {<:'+6b`@ZKP= h+{N^oG#mIP]Asi>o_2c&qUVC87%r~n(lƙU\Οv8 r - BrقEq"(/h `iޟh8o_i]׬z?*2y7F ehbD$An7:w MdS^I+eqI`g0.*;NUo(Ftˏ/ Eɳ: THʶm:qa;Fv/ߺ1d򍿜uo͸^C9ӿtڼ?>~ϼ ?I3a NPQ9=i$fU8h& @ޓ_^aׁS6/7s+_<|7۴ ~-ogq٣AL&)vS @ ~O4VUFпipa@`.^eF.ɴ*@L/OӇbiD`hu͆q"{]0)DLB Γ*& )흳+f|nܰFM^]5}ǜ/xˊ y>~y޴,=/6wbWНkNj`p*>ewO9jF(/L`Y؁OoYE NV[=B}222 'l߾̜> !#FPb\w*wTԈ;ΒK0G2[vx?sF[rpw~ktfN[>?.TUU" 8`l zNOnjq7vVAI:'g/5~.TI0]yxxv&Z@ M8DU, 3\1PuNq'322SGu:4tF7 [;`}S^ixnw%BTu!!?3dP;!4zKSg(}Uz@FWt@쩢W6扆wДU ^* dwJsa fGzNPRTJ]IkE}qКdusoőuK1ᑵԸCQ:PܭwTVT?Dpǝ@ //-?:c=֩uqgҏĺ:C'nIo}oQk>K6~?~;tAܩO9YOqsrqݮoBEjm;V~`{4pǽ-4 8P++,76}`.]/YϷ`zcM7:gwG?lkS%!g?ܹwʯz<~=oi]}/޹g}GW@ W*>ZedpL%]L+3Uedz9V@qUZsfҘ7O`:B @h Lv1 AwhA_SJ l[7Ϻւ@ ǽnUz[81jzhNӰg&JOj?@2emUP{M{T.!w[f8PI-7'q5spm~NpfJtLl)z!+m((ʴiS&N( )n%|>J"oi&M"1v ɛ'0DCN6 .%48|# Qrli@  ߡ%>ds _Jeex;U-,5w!4jK(ge&GjJY))IySbWZd(]jLRf$D-zrQ oӦT%t0V(G˹P!>ڋHIvƖمQ-8V,}8l4OFĨ@A(I&-CcL㺃Se#mFS@AF͙*?;nwQ;ҵۤFq eZT W#V}'e'x䩣& 6}KΓ=uPfϑ?\5YR1uhe`kSw}j`8/{*@ B `?^f|`6LC1ls Q`,Vj祈g%#t d9(\Zֱ&`2 oaLXD1QR5q;ʮG1FʄdW@8wf5}Dj9bt-\4sQ]/aHrg UY?EFSSe"ߴM 0hHY${"|6͢$c1]ǨVɭS>J<5F|{8@t^V/ECj&ivh˙C~'Y'vU43TjZ~y]:&"Vx\?g%Ʀ fޚEG=n|bZ˗Y t ߢtbo>:c,#ކ˝ 1ʇIN+]~{Wɽ6Ě8y`x6wެ {Jxq~Wt[|TC]_cty&UHyڤ jl^~KلR~ !fh?#ɿ YJs/'[o IDATԣ* l ;Oe%^-!&=-оZ+OLkj4@)Rx"HnߝיNVPnW*Y)qNb)@KۭR3H|P@Y+ԕdO#=`{@P7filuiv2eI`/BwGưZ Z﨨>:{Q<oNI;i $~fkS-#9щvy` mحkG'Ju]_;%l\s$=;JDs;\m@ "$. %йT&F`EJ_yroéi<頔Ŕ@ 47'kwJ헞G OC D#yϗJ/ބ$E Ҧ'\eb1yXv2$([pNŵfV-+M*!YnכK\|D]lg+ '9DA':| ' h} @h"U" F"=˂J?R?*PG@ @L-ϒJw+#bKE (eFٹI I Q(tey;LڸRay<)BZyFj?(h4sB%#NQ~AfFqJU2 R@Q*д' 8``_djGStUWX=XH)mR g+kZ]0X BUwϾD B@%p.sw. 8L*ftʲf̍4:I+ܳђ'|G@Y-MQ$tPm߃pbX<үT 7aF E::#F, /'?6w|111c %EqS:Kvđ.G w[r# +{p\p2DJԢ;|Rt^MZ;cA*(ZXysiems{9[E .Z&0%S.[M,x'7"ev~mnoD gYxFz,#]* qqKW1sks8ZD/<#>ZHP,ꁝ1,E"3ڽZz]1+ vj4G3,ZƅK "8OSߗsn4 v!м?p޾VzY/E [dmH7s{ݢ<׸.8ϥ}m'ˌ=Ub+[ ޔ@@y*GyH7^gVr9 ;J z?*2h(:qY[rYVyע6yq0b!Q2tMKߘnLunmg/&yofDM}zV4bMgRiZT&jd%ceNYL1_ @пipa@`.^eF.ɴ*@L/OӇX Ĺ̳tQ|uY&d9C`t@{ )J,j^H/MS5aI ᐺP; CK kJSZ[3UnZntJȌ9]-K {N@Ӥ2/}@@Ub7i:n *VzXN) tK' `{Ӿ6 eecħS$(tDS2U1( R-S_CmE!"wK¸ N `=.CP|"+zO{*lٙ<hB1$+^+ {o@ -hذaƟ,<'?n #\+5Gi%x S/f_BL7rss [ ւ@ پ};9}h`i(j|֮0@D!FCc!\-M@ !{;!鬣.G&d)ǝ@ uNTNN1F ~mT 8256׆@ D?jqۉGSeP텪^;@h%(Ͱ,iR%u]{J $U@ y` :"ᚒ2tS,"EWCO '?t XlqHo|Ӂ'~ټv M -뢏?s&/^C vC>]490r#ʯg=*7X9QO~qC׼4W|]gS Cy{TʦҞ3u+ôTCvm_v_铇~ZA-Wou Tu:|{g{ۑ?.N5ruDž8,!7 껇m 'D}-O iF|xsڅ+B@_uKz-Wx*7]1CN|T>qF9x^=`@& l\;/Jۯ楃+y+^yccnq=b[qҒ}.ﬖ+)enQOrzל7ޞօ챕w y>H_hpߺ~wL/4ruDž8"0]k#6W@A &¢FN׷tW;kHDAmegmy@_3aJ_ keE=rLFPqPYn fY߁]  ʡ%֝(1_+{q(ItSEV 1$S8 |ş(.[']ݍ8ۭG Vkɯw:vCoW|勿zo qۉzwh:" -Ce62K{H j4B_7par9dlWt}kA0/s:u·]:BK*[W=3uHHrdIrСCP"IYx>-77wp P:yC3g]rcD!yˋڻGAł]uR3=iY"Jg=?ޱ"ɳj ښ$}d67ޙ$o'LBao1vf,h.V(܎jd7sjxi35ZᬺaT%RiDBgKJdr%kU/gf.tEn:r1srIm5ڢ_W,d0e(6i;ġZ96W@$-*. G,uH6@R͜Ibs:Wݹ:l~a@ǎfCawOچ>g&,96gɃEߵupя[GTn$_@ .qC-힎Lfʇ9hXХ (JN|TY~; ԠƯ@ ǽJg;Љxqa' w +Վ;(S(Pک2@=5Z`wߪPaj5=PadhrenRh_RIцqU}K34mb[TFC$N&U}O _i@sΘ#S)7B4\/dnj5SAbFEfh#?,߿qeK@~Knpma|jst:-9rӏVq9p&y;8`^FoM>5`ʋJo=J> WG L1S\RsWbH:1n~^fr欔E8;wOIYNbQfokVb l.ԙy*րs:5qeP^;ŵ- cY^Lrv0<9ʖVg[|x6.16#-AR s5gH9O$Foa+DPJNVUK p7TZ8<>k˅:-k8^($~Mx#FZT늮qڑ&Ew p@pw$0cV,* դJ6_JpSɿ]wGkGT2fkoOr\P>dX|P~WoDPJ `e4m9Y}^?|!ItKq򨡚o~NYOq&j|ct6T~@ǯvvIw]-c.w6B!V"X$]kԶb.-\' tpN$RI gU;(کYμrĶ2( k";@½̯*ݍBLrܞAڊj]bLĕ֗2nSJ=YeEk:$jYмSYEjRS` 9gx&s.Ҁ)!H_*p^ad ZD(x‥dL!*/KYTJ)A˝, MN)nH:m|xW㦉M-!S(>R׎7Uyʻ.ZE ׺&AU@",ټ;2t}SwaO VyO 9KE3wWo-<~4#'Ž?Yo?>wЦZ6.zgy0Pv?M{ܡgޝ n?Qewo=~Fcw]z{Gٽ껆X.}I>W?(y.{sSsvsë{yo>yw_Su]Y==,svK??W y==y?1??#e?pv?Ii8M*?p)@atw*Ԛy T^te8.V*融P;=Pb4n M (s?7\: ƁG KPE)AU UW,oǴFJ!q{8ںgrr,f1r@Ho$Vk8Z©3BqAWI-^^+|^QC+(Qh% @P†z"4*S w26A1zC)| : ؆@2fY zYb-nK$d!ZE5%20Hn7a9S1ˬ#nЌ* 4jI]=K^nF}{QS~T=d'Yd'{8y}H'HiGnC\'y`8kغ.vKqrGO`{}߿t۸Y]\M o{gG d;Cu$OԪU1đf&9".,dy ͵TJ[>f,n`/Uz€1 ]nz^ OI yBR@C9\avL3bďn߮\ L EvS;,Q˽Q|[t=S%U*U\ۄeF)R 8xkTu?4W!0BW.s,J2Yëol/Jx5*SSJsC V)^,6V@BHŀXˆ /#8`hI:BsBp4ҖqGE#@VI 9 Aq-@ J%+1}FHROQ90q'*5H|J9uJͮQ妳Kuo`VŹqvAYy$EoktϗkhqↆVSqOd@,cH{`&Ty|_ebkDqPS$1 ni2($RlO<0 j{i'IӼğ62`$b /mlR@b8.כ(#ovGZֆ*Pbc"I]` ?@p@ \ =\Jc,瓄|JզZi1q{qE tI}/h7@<BYו+8\VˬmL? a1F0Tp?n<0 @a1UgȝJfwYZI"˔%FΏJmM (.TIbUg8Y89Fg9[y#*{eب0T\l)K x,YoUg. \ c3=:hɖ[e2 H$DQfLH4Ӗb{p 9C)]J Bɒe%ޗ*qSL1LĪvr-FGnNb ƘBS8#Z SUXEz1c:Y>0 ?gb ^tcȤԠRiZ!Yb$mݍb)@Es,H^Jb 3)%O.y0lVBa&<W2,:rHRp ,YxWvoIy~OPAxQ.%RF),:+aY_<l;ݺEaqٰg_Iakk)F5u'ɭaqYI4V{7B \:t'5 o/il@l+#+krb_(ZRA7߰1ΨG IDAT0=cԛ+ ڗ~gW@mX =Y+y/D92s#,cFe2v: Nd`"ɘbJ͇vWάIтY$,Slj6mEfr'¡I<^t Y1zufi00k9NeQN pA{?qD3wLmLVmߓ@ Ot)q?G#8&̅'`2B7?߯/c{ŕ1@LĽLg P u9kɿO7kڵ|E@ =D#8tef5SH\+cʄ10(INtR Shtv%Z;kn<|7HN&͘([-KV+S(RٲLi6k̻>V`WZB (*vh M:N skǀMg0M[b<%'xgǓfojF*.-;A~y[@ = AoV6aAumn=Lg0f!ڳJ:&`h2T F)Fn-kKqGz@yũІ]mh`=kq" HJ9;ٴ uモE 76_Ѯ=swz7EiOaB_BE)N-u e h@iЅs۾]WͪD[(14}7Eُl_$ @B¼ @.ʔ,X!U]'UoW 1rr,E3 ]?.W![>QK 3BqAg}٤ݡZmsOZ*]*ؽ#Y6ж/tS?YoӁG8ͽ3@9yM365']WVmb~lviԻv wm] 4œP?6,a4;u;6C0G?x3g@rQ;dd9@ wx L+hqWԤV^q!%qYI YBs>zնv?n_EV@H Mw}Ƚ:1#{}of4#VJFʕy99pˮ4T7=N'B$y ǢN"gX[rٍⰩ^d7ա}ufdj84ۋR^iT @!4(۾fi(DbTT/nړABaQ:U'1E; ]_. &h1H]kdN3l1'ig0Vc?@$a@%:YD\7X&&1gxf%to%L ǵNhD'i7fE|,M'D@O;x` ss):[$;uB]^XMq+jfkh Ufl͟ R :uᦠOL Kio# 6a:@>sd^}مq.qOmTg}Us_2OןzĠJضi_fH_/'C ϲWgYb[9<0B+l֊rFJ|$܊LG;K i_Iz}Y0oyvè?{N'G+ 'pYrCw~/㎫u)gӎUe;ks_9~[G :bFsy٧2O޵Ї]>ɾtsκl^zzbU%B ֯f{G^H o8YR0{_8bUrPs}Ӧߩ։|n  \ OԦx,I` ^r *$@e;ZSUKO-aN$ɖNru!`0md{ <Ͷr\fa$͵t 3/uDSIuƋꥺu$8'G:ò޺@@_s\ UG]WƙU{_^flNB|hBm|)Vڐ{j V THdء4HfGz)rKr<$$ {.JP[N?x5KNv:oBFaҚwF=9zZi3:n?e/6 w(&|MՖZp[Vy6E;rб]1-V_v~O}'ڵK>cڂ߾:g ~h|ܱOeӎbԣ sCSΖkg@m'_nUly--^O8p%VN *J{|4x<4 o/il@l+#+krb_( yoh7[ʗ6Q=T,L_ WGb"ɘbJ͇vWʠQT6=&1PmX =Y+y/D92st5!c@(d.W'h_dq?Zs8Q@g9{qE@8:22+*lZZ^n.ETUlW zcVV8w፿9R}lⰭW1˷b:ե-.sPfXw9H]6_6(.3.Ye:.70Ip@{.Rw`Mgޗ |7Nj|>v+ ~oc+=2U5~40Uv̢_ʖ|a1O/Y[?;wY g?9oٷ >v@8T 9Le~ qw~*yr7J{e#te} p'9_;$ǝ@ ’%Kt!QG^+: w@ BA{;>vG8Sӆʬg^|3O@ !½2)Jrd $@u @ } C;N+pOvLy@ зtYU'jD'%gz /@Ѐi 4`0]z[e:iҋne}5"@Dؘ_IFL/,/xo4 %iё޺JGq6ܞT"3X;kn<|7HN&͘([-K3P+S(RٲL;9Ц—CcYWxywQiݯ PUuXi skǀMg0M[ \L : 2uoã!gBLטsxh׫Cg >v6Y|檖cĢ7nJ_G@ ; `SrqN҇#[ݡ OgPg"<h2TۢATVhD*CkS |AHXӳ2#w7M&X`ub,WIW EE8D VwVEsbʦgE< .zgѻ 3z]t8 u4K.Nct raܛBʶXcQk29k_!`VZ+| B©ᨹi#CPh[7tXI~߄H!AU}g|岗<(KJD9喍cj[Yt3ɒ7Aݛ4SRc۰U,Uh)ӝE $Tד{rr87g<ܦ1ԑ^O7E eش1#β HF|6zbOD-.!E[[g|תY mص~چ&ᐅ@rVj^$u]-@\٣eYC*495O8`)SJۗv"R"mmG ((3{. LkhbZn4Tlb%jeB~4 )yJ @Rd,ԽNPH+iY_HO%2rPӢ-4bӼyNl]쨮6|&Zt{eN–6Zx<}7&y7\Ώ:յ? 8Fkt"$@ 2 2>QR|l3mbjry{ VqƿT~(S "U5@n#/3t$oVncx?lQW) Z̋g2dѼ0P;=PPfb4n MBAts[=J?WJ@"ߊJZ}7Eُ D# /i*u61Qd(Y IDAT*p S[\ZTvCNa 78FVc]!-o WkS8uF(.*_6iw-|^ۿtT26KhW}aʣ6h7eؑbQ};}4R s[Y-~/ik9ʒզm J8@c 3"/$bǏ.r]Zt+@0yZ]@ : ZY}piE C:Ԫ_D1đf&9".,dy ͵f~V}MY  )4}T7m|dq!ݒPu`ۯbkYMϫSቾ1Iހ28S aSnC#)9~;2W" 1ȬrqiZUBiP,*}8 {oh]9P.R _ܴ&,3JQ^>HvavL3bďn߮\D3ֹ7*qU8y;NAbyƨ WDZdUz\ o{owK} P9!uHJ0`$rrJu ~4hN݆rVDVABE ALfרTvUY`;UKb\^5c02 BTy$EoktϗkhqↆVS1F 1HeZuE~P( AMu{3<3 M7zk~ʀi&ZZ 'K4PqdWA> 'S< H=ں1?矢J⾣Xn.`&Ty|_e׎ov55rk h:?*<_p #N]ptKҒ%%E ?&$&?"_-L;_Ux=|p\oVڔR7q"-9. ]TǴݮUɃr\[ky[ 9w{FIZyO.e6Rf ۖPV #g+Ad73J^.+sC ^=6~uH*OVR(𨤼Qr^6(1r~Tj3hZ@pAJb:􌓅S)TkAXLgvl@2e UGma 9.b >0-ڑ7g_5om[3M B_A$LbOA s<`9YR0{_8bUrPs}Ӧߩ։|n  $%.ki9~j1Hdr0/Jf;-B2 @DHBHDH@V`,"Ez3RcI$ْIN:gHFHB Q(OYX6 Is,K#%jRsݮz.}- AAΰ.P!9j8oAוqfAx{*9:使=-S$aj4E<& .!@z6=<*v("ݛEixc{Tw#W')~`":>KR|$$F/O'Rǂj9×Gk%71ݠjJeMGrqW9DΦRMH]a!5<'vSVo8V5~pD Ctb7~^={ XfHv WDa4 5[9HU/ ?pżw7U 4Л-KZ*HE / #Td\Bb ~ekE&OFɀ) 2 0Q;&5](N|{9VV^refR[u1Ǒ0(ϯVoWH>:yv\ӸWT TS3;>1(/ | ΦepJP89RDXV}CFmK fU#M^"@.za\V9 yfdhBJW`cQ%`{"7U?VE7XS'|ITj>J?hALv,)Nce1ܪgl=1-;Ev^9kh #Ƕ- d6v v#M!c\{$%[p/1Ybc>9OFw7lP.۠{;!*Nk@Lwo()s8)7Sfu95uuu\@ ,Y̜?r1dw$!k#WH;@ !½*c!-IrvP, +5M;@ ¡A]$4 127Tʬ'v=,UnAؼ#izf'N=) _fC6ꓙ} k;U̐O9er29@ C{?9%2*K;ė=z3ߧ:"N +&&f-J hV䈳~OOsg>O-D~קL8T;>z۶nZ?cS>?u?/gx8 Y|~Z:z콳?[駍+?yqʉ̌´/~ǟ6l:XdlW9g}q˖_}d@C };܂ze2-RySQr$N Cn=۷G2dőwiZ#jMF |3|_k5Ec~%Ӯ1f^z&r-7Co}n{qe3K^3RzsFtؤC[6Cn !½W(pFS:y:/@ʷ N 1߼:ZҳYA FáP$7{@qUW \õvL̚{}}m@?˘S^vOp¹\sM޸8狗^{}V᭧>\7]y#jyO N'jlYꔊhwwZ.Ae8:';M^-B Pǟmrݤ;[o/kW%zx'e{|w$PA4-k;uU7fZ:.M8-2!C=3#|)Pv exl'ACvD#SBl]f S8nO(;JҬ#5!}À) 4܋w(ya?sgo<M1Qj?Z*2g#Wx$x-P. erm*|?4&%,qeטw}ݯ PUutC lJ/ ωS64]toa]OeP5[=%B!h5Fr荄R)U ?s~P#[w{fWzwU7](||*.3 1?IMs;G!}@ w@ Gą7+Ұ6o}y=@86lxЋT{f,`u(RKBMv*j̭[耊i@R@j!N 6 LoZ*E"Uhْ{fS;{[Q#h^Oi f{ Ss]ow{J3Uc7ESzg>EoNR}yUs ͺtԔw{ɶۢATVhD*C&76,2<)V?ge$Fnr M Ņs0X>0 * R,U^ΉF"9: t*oɽDxׇ/ҧ#G/iswu zDJaT+yH3i` e{($EopwX-<97F--V!$X"#LDڗmmJ%pA(¬p|o8j~+f685F27!wHgUߙ-i$ &QN~nec7VV9̹p`Mg@f#) 71@h_^=* X]8!4Bky |W(U8ڰk MM:kvMGpꚛO)Ӥ#Gݥnލhq/Ax TȡZr\[wRpcfz”ԢyئͻZ#Ï>Lv8_u7^(;lru.̺-wX1#aVúw=G߬y`t-sM' a},gzZ 'y]W 2Whm+E48Ow  Q$V6AF@ǂ'Zvn(+{͚xuyse  ,З<-6+kd pVgTvxǵS+=yþR1@fwl l5NWUH'Sp{$e9nx3H[1S ad ZD(x‥dL!*/Yv"R"mmG ((3{. LkhbZn4Tlb%jeB~4 )yJ @h-i }'@4qX4XQOST*B L6`1KxpERvUb'FHEЧьH,)q)V4 9e9ݐNV3!::;M",9 &KSB+:b%G:ut[w2_RzrXFQRp Ҭ7i a`IhtAVVJ7k};7RWn&uf $FUd{1s1gj%>%Nad`;j[ 'X~Pgj:tǍcmh GznGY``i1BP(H&=&/ZRi}3Q#b?9LA@|'N١%E؏:fحU7;j3FH0X ]XULέտh*&bG3EfPOHR@19P7/I7tCLXo] GLB< }Af炂T8Om~1 jKu: o=10AAdqfܺ:b jǿA $K:Z/BL0Yapemq9  X2zQGeiس0bˢ^{uǴ@8B&w읍`_U=.jhkє8 gz Ƕ%Fvȷo1q3,YcT5eczv ctmJb{Z7ocge1@Ts'(6oy'W5; 9Uљ).G ۋm+(ʡʕ+̩C{FlpNɿ BP( C^(v$A!!>6PN: IDATP( 2zP>J -GXd !@!BP( P ѡ`2TYIL2iTS( B*$ BP( etѡ'I0YesG@2eUBP( 2p%rQ#枩V* ( BP(}}t =S*N`z${;qP( B97ǝls_P e0-lpmlw3{;O+[Jfҥ>2A $NWWW+rӜ6_G=) F܇ /Ŧe#AAnŶTL0)9-A)w llwQX;CͼϮ-x|4x\ni[aNA8un,e!Okxf]F^ xm\>.)YT 6Xv\+l fz-d`Y󼶯qxc$;,y2zwPw Uw5Xr&?iO%2 BP>\yRB,1N 8 &+3 f"b\F%-'s˶MeB̋^^Ugy:Jj|T:npyuֿ뽠] LW]JcJW][ӉݾNֲOE4]T[獑차qw13I0Ag$o.v,yKo{'8E~';ߧ( H MGgd-ⷙݹ?B{,䝓:_o1I_X6=cDoiVVi>iVk\cQB_# !L.q%#Dvύq.Dq}E=Z⁹ؤl$(,,%z^-axN;Gq\.3RczlVUPgVW$YQycMF%GZzv8΢QI{HR@pV/tq%h넟 ojeh©B߷X_5. &H1nj1vE~tv([dqMg P+Ub {t@#yZhV@@?~-ط8gY]):}ٹSDZȞ|g }`Ó?%~ŖoIS( eT_.T=^ojALg ʻ*y56}j/(q2FTC3% C' I-ysn9!XV~sU{o4J`Ģ1})c$,8h/Lpo_{]>C @wK|ᆨf'Odb=%=cgַn3r7PPhNJ502-P|-kRix1pX/ji-hR8Y|OueNq=:{PV5XH9^?WNixV=OuLJ "H/sQ P| u> \:2KEnb _;7kt![ìfT~P{SOyCƃ{IEf~D\Q B9`f3 ⻶ݽF" OV~ |.@d\Bk~Ơ\>9B=[mv={_ؽ\?9Jd=-8 !xP&Ơ^1ˁ<Ԛ6pLz|#(k@6UTv3f [Gsbz"&{Hʱ\@0ƿj7ɱnD\\ "/kHꌐ>g3&t8>(M/oj05# )l=Zeإ\@gۢ([hu̍-iީq<쨽޹Iwywg./nߠ9쒺 Q 2Uu?ZyWK1 TH98޷7˾V_pGj>yY[od Ә;t_-^6y4MP(o0@pv_=a5,SԮCoΜu2Eկӧ&'ede쥝f_yS7X}ީ xOGUC8 ZU龥M{}E0u%1)L|Z (9fO;fD N\y,ydD̛V۟4__4& Q1 w9RHyjgNv@LktA洊 S 7FF-ۻt-k l7 k1J-2Xb qSUߍ4'bAw_6te=wx᎘xf+7-mc) R.8/![a -O$k'h0Qf]XUPdAw k|Aݲ졶j$9n7v6Ts  BA@W=Jy]>j};I^YUd0@dD jx( iDW͗Kx#`^he%U:[2H z*`ElI:> 0 f|Y66q%>zۖœ 旇GcCiols!v*;v8^8 #a{Tj?v{&ucaGv֟]֙?OdySxk-#Ͽ˿M*or W B)8n^]ٔwn$^ICj?y<!YMs:/\Vc  QU @2w-W#S܆*N]lhF,<ݗ(GkM_x_9S:1R*j,bir8pYj(VFF3l^g^0@Dy`2WGqF䩁>/i9N 7[.X3'j <5vd9݀!y*b&3;MKEX0-ׅnxv&j+:b%S3|僕4C-L&y: z̀w>g}[/$jdIg5"Q_GGJҡzXQMBŋAZ9~sZ{ϑ&Lg;ޛ\Mwn[pyw4ivɝ1s1g$uX ?8ҹ ˲SG_ Bk{QM|_5 *v}'j$ߺ؏zmSɩӱ~ivhyc!Ƹ yζvzU{>j}dRpbpne?E@Gy0ɾfr͛R@19P7/I7tCLXo] GB(/ zf**ͱ;~5FA~ö._4'&(,ȭ}. v[$K:Z/BL0Yapemq9  X@"aF h/9G1-{g#WUO ,\}k3o[]q?W>3o~3iu7|q՜!fɿ^'Gڋ.cn?|: 1v ʕ++8j!PRRzorkhbʀ ArP(旔=Pkr 9P(! ja;HD T,s~BrzP(_ڦ-Ĉ;S(rJFGNgdd,NP( BIpPA~PN]Hnm+( B]p%H`a$+pP( B9Ġ}دw>AAT?d;͔s/^nc( BP(Š}t 3pG#QAm32P( BP@(q'9̈́~b2BP( 2J[ls_Pea+h|A6JF3X \oc26hBP( $4>ld`TAVj}Wfk|S3ˀX-ѲEeIessgN͐Qo# 踫[V}CSNKY޶YWiG'$%0aźFsptqIɢU.}6@q^Ko~\Fd`Y󼶯qxCv@oFegoq"~O BP(ApAgCbJm)G}s;1QuyE "A !Z5wh7"=wKumF[yQUgy:Jj|T:npyuֿ뽠] LW]Jc!7ؚN-Lvڶ-x(̤Jݢ?o`fD"q'QNthBBP(J?䮵t*pFJ"~ܝ[H1 $B9 Yˈ3OEk+;$}y[Gce#Ȃ`V[ev[FG }~L*=)M>+ q^S _ 8g8v˾_db-`lRZ6u=_bt'ޓ-SDw-ˌص.UuU?gęUu"Bj,(8vVTXkcQy'nV+NhT??P!U( ]t :'mۭZ4;0'p-W Bc#KB E[kzںeY쬬]`<$r{ޯ7J=4GeM&~ko ;mTdYY+eNMZ{wك2Z'qSF3UN=N2jtCBP(@8~mwPx32*nؼVoپF(c3S͔* Dr(K`$>Yںrw`]XU}`jDbI~ ʉО w<n}!3"L=ݞQ9 a6c('y}c 5 upyA'q5< d϶G54I)~,'n:R2=(_i,fq]/럫mGx|O'4y{&QfvG b\q*u67H- K-!ZrmvC]?|qKwP8:vp}yTL,ETTFc/cQNR!Qϊ$xE1XPt IެY#KGNjxF?n@n'В_gjMn$^$}J8!kgıKs`kEQ9*'NC1"ٵN}t[g./[ox%u'5&tWD%`&Moҏ?;Y8>U`8d)wpG x-wlɽ1%5B)IUUh@PpU±}մ0nMQN,.3eLQ y/YY3d?׶wͭt86d 5`wjV/lTpPZup]?Jj^pVt(CgCx^\ɧ%E[~Q>$8+K N\y,ydD̛V۟4__4& Q1 w9RHy!ٟ8J"]о*9bH씠B?Q) Qm i+b.%F%Yf T'+QpOʩ/=2 gz-17|6V\YI&;'맙Dq B dK\E65-O$k'h0Qf]XUPdAw k|Aݲ졶jeUB)B"0,%<؍.XpE$m,AT@yWjFiHS$rmo XBFۗ,+ r@*T\y { V,bH a0䫠ϲIE8Ni x{޶0a촄7?RCrAyQTcÁ3Ls@PDz tهLR:+_rҘ N>qQ]GWT=o_}W{(xX0NP(ptH*ʦKu'B@MJإU;Y%$ً=x=iaPCdՐ iHg A8l2_P{)3Rr_ژn&0 L@elFIު[yݛ[Y P4=`v&PI DTĦUMLK-b&hN%E8^L2]x Zr+ľ4ìtZ,7J04G)ș(rm@ :4Q2a̶"}[}#u}f|`P( eaR:\_h/V5ڂUAp4SǩMMK.x|Qg\7 &/vu\߰VaaaR,YE=M. ]F B2L "}%yܱw6}UT Cz@' A?|ݨX8#ۻp$=̴[/8^񽷿x̔[gO  @T9ɮ?q%Hˮ_1kY߿7l@P( Lٳg:C};`ӦLqk:OT>3):>r(ʰUW]2ڶP(o4>:􊸫1 bVvKHf R\ HkӖodi*>i<]_lݸgYծ Q?x>ٺXxl;^ywm7_2^ w߸#/_[?u 'x{> >u(؋}q;uul\.׃>ODP(AB({7ZMaB{m e 7)Lݥk?sʩݿ}ꝏzD}_~WyW?2djϹyW߽y5]|ͭ\\wu'N+G ́ aOE4]8@ !eSk4^%==k^lE.vTfaa.w,O\IBuv_±151rsF3HJ J͌+?~8D`^ W\H6{A9"컦Ӎ ԳYQ,b6 v-y4}. IC{n79qV(ݲuW]şrc~W/t/}y77.HG>q6R_ZH?dզ %G]]_eFB|K@---g.w'b@HxasYg6MWp&:+bjhu+1^,!u˕rf'5Ti;-Jy &e#AaA\g-+9*z$_|[&pe2 Z:f:m/!95n?E : ){ o ✩ Ҽ_2 ,ꈿzBI]1pg89v7prR0iɚ̪!Mf|]UdzKxCz<:zsv:X4?ke\|g?lWb9P Kpʴ; Ӎ=({Oz[U$^8yu&r}R3-N$LsI`'tU0D3p,r9<*0N@~677pʷڮlt:;::mBrʁ"aXWcZ'{f*<'cLu<4S?0tɡ. !#sd򤧪L6 _4ͯ={xWIY~پTˇnov{ F!ڹl]Ȟ[όyh#RZj`eZN [Cפ#F}S"z:}Gxgoԥy_mrT8 h{8kY/ 1ɞmY/ji-h@I KTHmfY*>[8Ժ}_~1j-cYMG牭`")̸#~SgbP}q{[L"Wvn[ {A}rO1 dwg3: o)T 2xF" OV~ |.@d\B?p~:<T_aHn/^ؘz<Ԛ6pLz|nqUE?3f3sl;uڷ2r,'?_r,/E΍k+9gb75ia3x>Y>>U־a&paNjx\AW)፤ۇcgE$0m:FBˑÎꝋ͞tm.xD:JHR)jgh+$Mc[ZMHI ϭ;Ld5hGYS{ 8*I~IV1-%* Y))KP(ʐEܑ;9{B;퟼ubA08sZUN:Nu谌siU=x^\ɧ%-0XO`pq{qʬۍMA͟napJoc_#+ B#)PO%穎Ecj 'zXU+U$-F&!h>$8Q70o~Zoʏ~}G"D4mYkI]k̸e@(' ҩ ph$zWmAdXTѠ *) #'&kxA>N$^5 ݂qDVkzBO&eVueƧ|.=p|kT:,loiA !!ڇRGjFn~Z"B׶vV2 #PgZ|pV3}5 OY ؼ||e%U:[2H~]M5&&}'ԝ{wfHU3dD}AŠIS$rmo XBFVY&tQ?d'3ĩ,؂`5WMBP(_kQ@"B@MJإU;Y%$=0vo"8+_PV `ȪTN 3Rr_2=\sb@% W:~P}2,a6{ߥr:%f^h[wvLl DP:,i &rK0R4&9e Phq Rܴ9AAHR;2Dv#(ު[Rwx++3xa@*qش43~%Cpu: 3:z}IJ`)Ѧ  yh6CP('˵0\TAp4SǩMMK.L~;<204T*!@AH6l"bY>.==qZ+CFԙhUy|w^ٮӪ3kTatC:qs[e9E;/0 NP:czΰƠivAhXl ״2Ptlܷ:z>5=URLJzRj/"| dXgKgNYIC߸#d[*:O>VFJЌD1h![CkwrH2T5L!ܭpz!578vW0gӕ: /W:4ty> rLP(CG3 LO8\Z=z@AAVĘ Wc8l pdqpcH385jHd[$|HdD` @2p?xbc8tVQYĺ:X ' BP(*G{}gP{}`+V_oRKm\:JN$=rTUi M Ql a}Mm/2BP( ed}د^{-wm BP( T%IV.\)+C / fP( B 7Tl>=Wv|H%Ԃ,*) BP(DTu}A]--a gv&˒jg0k}Z̠PT也_t%5뿺 wrӜ6J BP "0>.)U&/Zղ}2w ֎a0R,h ?j̩rv>:E @]Ҷ2epLXBͺJ=V1`b7$o.ijjŇ$©6N)w~f)+m{BP(+6f6w3RvD  o8챐wNB2?̓:|ƿ I_X6=cDoiVVib׭K_TC ԏɽѴZc['~`T=iLBV/@sc3c+E& &e#AaA\g-# N8B؜|upw-ɌAص.UuU?gęUu"Bj,(8vVTXkcQy'nV+NhT??P!U( ]t :'mۭZ4;0'p-W Btc#KB E[kzںe}쬬]`<$r{(5UC{sɾ_{] {M~ WXԡ),U,WU9A PCHkww#gRgz9b/9/zcZ}\|"@?e)Mjn6nZTJN_vq,BڵɃC؜w{ ֖;1 wzSsR(B${ XWcZ'{f*<'cLu<4S?0tɡ.ʿڒcGr>lq}8჆kc3tS;ڍV ںk8JNAEa`1@öEY7DPשׁ=WF3ͰAg Lk6j>oAY,շ 諛caj 2\GltRaP"I/0IiJU3( '@jn0 186(t; ;5lߐbG8gZ[01rˉb&=|똜2~On-N=K׼ǪF \y͏M_K%~[o@ t*)ezV)x%*;Es,d:p IDAT)ӂ\\YF8-yL%5ؒ]lչ VE"&R:i)n}e w 5u7JQC8q4@l7nΩ$2!TЌ@w~?Ќ$i*I;ͫ,cWdY ,SOz2/w mc(k*˴EɺhDg\.sCBtWPmkr$۶mW8d,[ƞS%?>RNV_+^ٙݔ\Ti\{3/c_G`nS%[]~DzbT=B^\1,pS/u8+MizOY{ÚGG" =䫭۹qS3bS|hن߽E U>KAcQơs_j۾{|. @ `y'/1(穛J>Zч 4Ś`4W=ӿ2TUlLU):0rDMOŮ7>;yU7[#peyj˜dܛʨ":\y= 8iJ-"i LL/<7Z 9879%ԒedMVŐ=0 72ʷ(`פPQE ($73f}ǁ5@s$"|KP( *K2SB Pj}QK$-NJﮛW8[wQѩQSעdP&z BO[78g?䏜;.kipfV7cPΙˏ/8U6dwtԼgp؍A;lg.Z}&zis-/}L?TʾW r۾P"=ܡI\ZI CT|32ssl- ~hN]bVD&AB@5 `:*H@v6^ܬMIycnQHcՔ@$U)}.Y?:WOsE]@ 4PDzKp$R"ųC. U*URb=ë1?b;G?jFEºx(;㉳`b0?\3W.Mn j2 w-pPsfDe'm>%HĨ/8s)tAc/8ʚu 2:֫^^7ŪE|>@3@H݃U8i3ygX_[ܢDxTTBaOlP53 B:y,mӱP%F}÷yZϞNTut*EaUїi8iMz_%@){rlL~|z ;—쭍\DIE?p]XT~p8jN|t$ZG>t>WJ 3GUGNZ*?^icU.lv@ t:@P& N967r`dY\8bUr-r:TQ4Cw,v8#`0)]m )0 1Z {=xQ`{)nD" @DO!2ZSUK#&'3B49"D-SP3ro+%cF(M.@ vSs2q_]A{ҌK@1d`@`/_fG>M9:' ˚8׸R|NCi7 >cʚ6ՂL`bҠ]CqBKP̽Q=<Nh›U 0@^#q1_fZWj!kebȀ# 1¨aD`qпrmך+oSYc*s/x@99.C22YO4WΐédV$N*(8Zl :5׉2PEl@Ue?7, 2BCYjY>kf0qұN?IW`+8/LQ2_adL1ffe;ʑg*h99NS㑝 Psڴy>r\Rxo.fdPծEfW]G) 6Yk!9Fe5 ~ߏTBPJ/7{eGOSp/v ?*m32P|X'+=oJ|c=1lرgڍ?BJb 6 ͊DIARJ .Q#6 pQTTTRRxfK/7Myo xXʞ珘Z{[ XOfE}aĞ;oGו/+{1)_ι|r;WՄWc}cݼ|a+ < =w<|/?yyyUUIz3 7S q=x_oJ[Eߛ@  ɸjh="1F;DWžoR&C g"MKPTƽbDL [vδ@ Lf${|21Ѝ݃nuA[K ^"xϫ3V-{ ~I޿V[k un19?0aS^>}y( ֨_,7s+-CuЋy}yr)jVjͅ71X굆X/n: s0 \iud.Zs(?+6Byϗ ~#,;T/ȼg$cJJM !zV7۝%bu|G/r2։~AIWedw{W'vpƊni^RW:u DϼJk>t`~5,| 1(R~_CQn.,͋XhX + yç#{L:spz\`Zag:q,NcLcLGE|ĽSNrU ;?b2ؠHQr36|x,qa{* x.20?|UPA!xk&kWr rjoۜ):D?O?`TE/'1ۛ2+u+2{Zԡ΂[}7 oOzAC!#+EuZh'G Bҷ+i `OOޖ#bpC0;.w:6UjLJ3R|;%S.H}(} O}gn?w—y -;zfds({c5N?9@ b$fXsoʐ0n!@9\cEi]na3g)DQXY=Ƴ;R5j⹴7M'lq8b)xHh0BW(YSM;0).m{כ bGh>cGr>lq}8˜jg34:ڍV ںkƸL( (:%9le[!XJ*)h+B!%(oYU{ rgaunl2 |Yo4geW7RRd̏c5 dkE^`83N}|U & o"5zQNAۡ@HS ))v}|VH)uN[(K]YT(.;XZ ,̥ʹ:&0W/כQr-OqXۨHݪHdgܩ;BbG>ԭWF=W&<7Gi t%pN&Q|*x+*Qbh@w~?0WOqnI=9W7+SPgLZ"K,Pm)@fnPrM_p\:ɿ!R_Kׄ"m;$Qk_@0= 46]Ϸ-Q@ԩ䤗Fv~7gYT %͛y;է+~ ;vԜ_|:䋜'y$`Ҩ)ﭶ߶>NY|yJ  Zy2ӊrz)T}HP IS XHs53)cKe]uƜTbI'# 6u{< 7>;yU7Eih @aLiw":\y= dcCXF !'&')b0%oz-Yd1տ)ζWmG!&}*T@!4(03>Ѷc{TP'U (y<:Hޖ@G ybwͫ᭻(PtTǨk^;cqi?qn'K() a2 0 c\r[+='f@ g) @.Sj!*>> [{K{Sע(I4ll)oT Ft6^ܬM-qSs$#S$->1h+($ YNZ0!@PԟS$N绑T{>&SiiyjYQ,cz3`~_JQ< HդB EIsɋ<%z{Z xr%fi3 Bdm E|mv*1%z[ GnHo ~Js(eZO5irK@8{j6&0VOtBpٷqZ%#ʸǙsHHk9V{ՙڥc)S)GIjmI)U/RG0# 7I$ĸ!!޶"͸;/?^i=//*IoqF2rWq4.Cd_[€Fj{i3-4eĊDž{/ IDATrv]F4{t^,zڴ0]xǧ>07}?, ų_^巃.^dź+YEW>vl[+;oO 1x}[|3{Mylujzg@S,zvQ Κ[}ϣcϾbʢ7`O3#ϛm9Sb-E.|ڷcGO]׭Yg$Ŧdo 4NDFH ٌ':!(p 7sަMdؘro݆]C5`Z7h_ewO}'ܽM2̾gn?K[k^`]2=%=(2]Ի .Z6oڤ<ݸ#n3mou٫>ѱoΙ8;Z4J{{{zژ7<]7ʚN>wa#l>l!5E)93#E*gpOEs"m'<gڋ0@8zچ lİ,yUpf.mnș45{`ysѻ#_|ǻ+e17V #S6Q۪ru۞\:~ݐ~~ͷ#Ա]L0ӿ7'WL/{ /f0~s\u@ qH !&ҩ3v$qL;g?%AxV#lk^A20T9GRՇg*$e'-aeT]V+m<]XT~8~ߚPJ)?]t_z&4Tn<(=s,Pr2\sTzsu44w@8uAcϞ;D}lk6_y`m@N5(?*Hr'z-oR=畼vգ9jꋻz,7,hA ]6g[_ڥu_|]?308IcnFB50U Lŵľ?z)oΞyE,,@1a䊣'rK=q劲JF:~22fZH5У9Ѩ1rt7o>8m+fN($S  " 8i4`&JJ+#w &Sty;C yeoجC}^uØ^ÇzvJc]S{&{Mc둩,PV huf\NPWv?Wb銿M+zϾXr3si)7y2;~n"4goՋ.8o&/TſFo/ywͫ¾t=+ڧ~o?~ @OvO~lܾOSOp lz^~q 'u}o|޵s3N (9o+Xڱ S뜮!>Sf2SLEf}pt|^m)t%N JAlȩ\L'z䞎G=EWW{LٔگMM(x v^ E]o0nVN!uu! aK{p"[xo}ڥ|Fy ~}^ʦ5$;P-qiXlD龼Tkkm6VKFo8V0 َݝUJ3CFN%ځ8{}*uYҁs5VWaU_q3S@>kt:*f{dv=u+]bkVdPyu۪eoa/4 jk7|ľ.ۭ5f &lʶҧ/OS0՚N&̭l C/uJXAyWݢh$jnS2pC88RsBQJOru?tb@ "zU7۝%b|;! ou_PRU+^JSx~QU5Xڹn/J?q`ҨS: @`t^dh{L+iyꦨR+QE jA i5~ai&rk5el٘S  5u`DænblR{Ŋ$mb2Vt{j% pSAB!T ǀX["⻔9%ܜ&X7Z 9879%`JdZ ߳(< g+߶]CEa*ddf|r?h9.B,O,& ˌRLCYB$Ih_N y@}}2fZv8hqBn8>6F7D ޫQR3˜e\`AN_u@ "!ҺHj&{@f?Խy=TͩkQ̊h@$H顢AL]Bt^Y``{\/Yn&.RI5Oy$yזּedƁY5I]Fq3n$bʒ1kn4Kb𨞕J"jOh,ш ~rݩfEW,MD@[; m0 |Ӟv۠[8hhH|atk<+Kg3O,5[ջRć2hd>d9^@ 6Ա,/hdzC. U*URb=En`x\g\"aH<_sL Gkfy?- A0€1Bc !*>)I"O޲@%uHO)e|7JstopJ5--]-@ *euW@oU)y~$jRJ!Vv {T9Ea}(3+5PX+1TMŘY$ݭ3I$/P.;0@lk_4GnHo .6^o{ef@ t$@P& N96-r`dY\8bUr-r:TQ4Cw,v8#`0)]m )0 1Z {=xQhs0MBd2d9ִ/I1!4̐wOKdd@@DDԉn$L,C`Fm #% B1VբzSJ:Zϯu*2[G[,I[b*yqH8`: wgӖ)$I\GYj'{Y/p] O:eBN(8s=$F2([;eAq@x(U_ֶ'b&߼񒼔&P^c\QL- )9{W ҤRȿ$Q6W<'S vSs2q_]A{ҌK@1d`@`/_fG>M9:' ˚8׸R|NCi7 >cʚ6ՂL`bҠ]CqBKP\,V @E *d @@ji%7jL#Y2׺T _KI=!BB |8 L9k͕ȩЬ19Yjj!o^~\p'+gT[2sVZI8N*(8Zl :5׉2PEl@ᡫҲE\!ڡЬT5M`}^%`UcLâ/P g.s]R6?QQєwt ,&iW \/F{zm['hvTB#N95ddqWTunnq`LD%\S ]9@ 2rQ!B c@(I#$0d D @8S~ @2%RpjXI @8s~f˸~d00PjxpC @h" w CRd?ɸ@ ~f@ FkθZ3D@ ip?C'tVN pAc EcZ!;)&ƨA@ ӡC:LF OLC״ 2MNw@3]̮ǎ;vl2w;4_|HCo*?'cO0FuKKkF H!LBu Zek[M\E.zֵsRh]M 'ru>7^QЙk/y/AbE "60pju[M%'V(O媠X:4$iLaf" Ҭc=M! v)>ĦNt=?;GM98R+N\ecW5ooIA9Kц3k+_)-J[?񏏟XZVy]ԹC8=YSD n Lx#ywWUrbʼn*kBIWJO|xbK˔ͺ{eN?0q`>D] {od?7A_G|f۷s n_>k*޳/_^S[~C"_J`ֳ+7}o?{ѹ,Jٯ^U4{cuxm{ӚWf5m959,Gv}ŔEnڵՋgWG\4 ‡_{^_K 5?ݿo뗯5gKA$MT&jjY L:=-{q+ wDwFm3K,53Wy6S۪C%$yZmD_vo~:.4|3e[X(dus}ukHY^}y4߶69o7VvDa*8\V^ص/RnkPdA$T /9[sGN{?4wz[Əs֚'X̾zuoIC@xee/yA;7~v2 NB6:M:uT{W՟?18ݘ$=p 7:K#_Wav @+Jc%r\1?K!zV)L_0ݑ|&y% IDATHWsϥi p$D4 186(t;)wj>!%Ŏpϗj7([x'w9ol&FG7z0H׼ǪF \Jݴ-[?M=t{`Đȹ(M*vEU ?oci0>?ͥ0Mx-_@>uܽ֔IuG]W@sUO: ^@xFf6(B/;i 8HeѿA`Y9CNз*p{d78-g1!jbG@)&}}#󗞨b9q2~p40dnTGGR>b|=$@wee֔:g(Rj. kV֬! =,.sirΧ LK{wEy?̵&{ڄ@@PRjUVWjZj-UKk?/TP+DE9sg=5;3=6H3})Vm7Y,zK7aPe/Lh3 &q0FBkC d$$[ NJ}"\X=@HkU#V:{VLeU g4JerXy 1=3ixmq{bua$ΐ‰fI>{Ҍ͗赝A{ ۽=&]n:i.0tk+[r;3_ڝu\LWsVnRMt~eC-;;!TʤBowԴ)?$޽[GfbfL|c 6tg׮S6t(@s/\pE΍׵go{4Rc#ιCnOvG(@ߞO "T8, Et tf!͏]~ 5T}U-|75/\uu~޲Vf2wX_u˷d[V2@_TVB'v2Bړp̱bk~lv ܔtE4G.#Rk ^Bw3xܪڏ Q7zg$[wZ 3"w2sYR5F#1Bw::z^(JEKDžP0FfQʨ 1m؀d7?T%_|O~}Z2iy66;N4xBo'oMtFgiUTDS6ݬDl:oPQfFzU_>Au;H)>/M;Rsw[70{]c#\%Ktl0W@of+xVP1 ,l z!Lw}U/=ek7L;xVlh~jTӲJ_u=ɖfFv,Wcgֱ)fMU_PTUcYu|ڸgCxWvڡs /ZWjgr!S|\-$Qef2:Y3 Nu5_]쓝ؽ__!rw) 9J)$nA45Mmt=ЊlS@՞Q 1ٿAi.NKlQ!+c uիK 1c%z(]>jq%&/n,2*r $LɝK)x[0he%E:;jUE, ^.MPI"0*իϲIY 0ĝ֦%>z5 ,<mJM#+IN@CۻV 4onxDR05Ʈr_7<8hm}~ReulN*UվTs?,>g  _,z&Mx_Ởc_9'>=?ywcj;~yS_kow5]}Ϯ;9߉P'8;ִ퐔p,o_`V&gFlSb4;!w%M'B'Jz559'ULh$KMX=9.FN|<_X,CC:-)սAlF1wpmLI#T=c뎫3ojmdž&ڣreEEahdTg DXٞb}/I{u~/Fg[BԖ/nU[fJSW-\i}{.ceXjK7\ѷ=_Xs?R?]vr嬿^o]Abs53']7w;-߳կ_$v}7<7nC]GҚ_y/lE}2UBGvⲎC6cdx~tYnyDh*}jVˮVHUuY3]jWgW 8mWC7Xnp ݱP>~Cu<0 O.NQRC3؊{\ּhPTUv&U K:Vkz!ItmͭIͭ']Yb50{Y_ƵK__fQ]񲬢J3Ásr% !rxBeԚx徸1A#;re|[s^7?ou[}s6I9 ?YsoKP6NO1,eS8Y |e u-?H`=So~m`;OW.OkI\mEm\̊V|=`ot:JV"U݌* \0TDۗI\︾ws!~@h6N`(12H߭jug>-UzD۝ eϞC ߝ Ba>A#ȏu-n/aB!  2`V E_wB=&xږ)&"{Aa =$y[qB!40q蓮Ey3 t`x̠L&:B`|hwahQZXxJyJ'v>}Rf$w%qZ/ ♳|lyKBhD+So'IO%*iqRP|T]˻6:nX )V'˒:~G0So1c#fSvqme;e%npΪ^*@ ɾUi-* .'|0$ uUkYՖNݖH/vڿn'J\%+G{/Oض1AK\jlR,%mZwQ[m}1:nҾ *>B @T ?{`z㩾˓h }]X+B5FH[;3T Dx yOOdDF:]hM?tEhƊL#\~1[*jn !4b^4MJCo_J`3;IΕL5vukc3FJ‚v ~Y;Kb#u0ƉROiem= M?ЍǑ/p#t;ܗ7 Qӣ  ^?9 R'Ggb%E$[4=Ye|߾~؛fI~'άs%DϗG3Yx1=8[pkDpzUљkڥ O]B6|*rHFF+N:Ͼѱv[B M59F$6z;Rb+i]]h#pZV4u6=} GL^BwUWbWx͎5(jiS%[ TYP'(NpSՒL({qJ>woZT]TZNxWɞcȇ_oCFvOߋ ̎u*2 u/ \: KnwèQV5Xf"q]?^Ӱ'x"O74S#O^i_/DAR|eO|7P}+R vH9u>tQ*-Ϩ!Lo[˓tZMf (1-/ `Ĩw}ӎ\1h>eo^QC]1WFlNvU[zR%m ',]_>@V2SKo}_|7Z!И)r:0P`{0!Ń#at? 8^l&S B\ .+S קK)]CeK#|R44j;x. ,O~R]};^1qA4W.y_ٓ?pP iLkG]6AOe gW|Muʱhp"c/4l.k4- y.M[ɲg r}"rHjujl~DY1QUmQ[l.ot|_`{}w;,W{t^=U7%R ܫ4u#IP%,I($%)~B&{]«BA݈;3wlv4mvE%G.#Rk ^B7@ͭWZJ{iZfPB4BґSUYHr',GsKNc8itxZnܺX~*3=%5O:-]o?ېMtFgiUTDS6vKçf2PFM\yoR *o~JʏLeJY^PNxԵeckZ-0U:Q Jc-0 a kXg!,SpV̿bLqq ĥdhzXO&h3‡5>Ҡ-إWB oٯlc tĽD%v0V-w%+${a~286݁rB'CB w_c_^-DGkf Dd "MTY|.}MÿJt?vo̫@-LY.@]*,aD:%'S)+ "GO'&qXJy&_H?逅ۚ?Id$ 3'[axR79=A!$ϓ FW+B@Q'd 3~a{qWE =HY#Vh+U (EjI؆EU?WC:#Ib1ǬwFh½tZ]:T]g.|R @7!k6;/g Tba@(qbɋ 6B38m11`r 7@3Źm*hbtt~)W#rLD07+G)l~=~BwAU4E~ApYinSx665'%hd]dBS2@ZDSCHʡ(T\w2&P|1.?tD"՘NO.4 7 %uifq))ԔTj$kFn2Rm:57쿾;XVQ%==sV,U-)upBh7wQ0$ejө]aGbnA-<'bn-QSXɤ҉x=ߓu_XV83]J y㎨&~g ,_m9E#Aiy6X4O~ZQc3kzs$Wi"AH{0>]-ᘆi򇣩Rm^0Ս|L4{\-o5NqSOW٦->[?]pHof㏛>=SͿ.xBM6o޼c1 r?нxwC,Үrn!qTs|AhO<`.}9K7]+U>t_=PqӋzUk'[]pU?8^>I8̛YVٵ?]ue3oRغW ldmkq Ol*o>յW#-V;N]%JT (Ω㌨Jr!\oT 0B{շ}{g=cC ?WV栅߿:w} .5ϔtEm5?N,n[_-u_.EgxK۩2Xy^_Vouy]^ylymm h>\rӟuz\X|ܗ DZpkG!>"ОAAK.qKTȝB sqо?-|h;_|kkqʏ׭[nݺw>QgXMnޒ+x6y޵ek>)WZv嶉~ܵrSbt(%BhaQ`@rZ$_'@P*P!d`n}۸+z'{{d0C McnAs}SE."#ZpeTw\ @Iyxl?6G0#_sxp.!TUVai~fs8J9,\~XKIVP`(e;"?hɿ>a &״dpl!t8:he2rj0}9 DiC[byF+w \ \s*rP躵WX5另\h91IG4 Pvś0񵬵_d_>8.] (8٦7Tij>ٙة4L E2r7vvW~KZ~}NgzϏS#О1u^%LDjĭپ؀WdTگ\}yfJ-O쟌o>r+(.ozþjCD/Wq#42񅺪jK'nK;_KLotfYj1o&4ŋ&L^}.pG=H)xk /:b!鉌hSg>i1MXxn-57[1qˌI>qg'L.q}|sev|X]Z錑]c?KT\֞J-xK:%3^aӇD]Ml$_OUE1=8[pkDpzU0|з;ѬJPbHz8M:KlbTфSA7NŦKHhz};;۠ROa7:qm\i48:\_ |kEכZT`U7^RS9M"[OezGY:SR|]3R{V-^KuqEo5a wUWbWx͎5(jiS%[ TY{Y;@D,䷡LNPBe3ܽiQ^wQi9]%{>;̎""jClp9iш;(e{!J8rP>lMǨ!L˓tZMʡQxoJ*Ux*6XҌ <{yy:a}Jz! ʤ+c~'zc'JLkBKB*C8θjm$7oX58*jbm3g5:r[OQ=u)FW ~hnkvu(0BK>٧=Eu5;65,W*~F!VygF,.dJNNyT9"^$rELAw&Ɛ~K|R4}ig4}so 0Rʖec!jmkZ]1$޳b*#Zĝ"ߋ9=0t b)w:)G 2e]˦T W't!X'D杙CH6;6sN9eY~>53YK6Vf;;V{㝖\{ ?]J :DNTuف)L*d$fHYT6e q }&* #~+?2MIjV(T'V<8ïY6Ut5l9(ҐqJfю|CyJNits кwMƝOǼAPo_]Pb=u~1}҈u`27̤YO Z&faeTO!BG>qm~REiDF4=wDSVlG¾E vBf'ua|>d^sW;YBiRi[4 e9QmDs-ko"ke 6I:A(ڟӢI?m jf Dd Y]7Pjv Rh b}Me6umң?挦9{}C&_>,JJ 4fB=QT>atScHP2&.GT#Y9$ 0]Ѥ2}ˠiXgtUБCT+!ZVQi\Ԃ.oE>PİONvBX Lg%V'ǔu 7<N Pů#*7vT2~nNeǦAfRʹ ч6>mDqw*ڮ?n;/<[R-v4:^W555J!*kAU4ExApYinSx665'<)Vu@L@( !2!2! Q *ejUpdaCQع#JDA3.$q)Vl:*gFK!od_^=%vZDb1 kK5etjn}w&_B(KzzXZRp) Ѽo a`IԦSpҽ?tD"՘NO.4 7:|폶y]F%~O+$F54?tw~t3mɢ`5&SJ*+U5]' VQ7^W2B!;tq>~5R o_'qZS),"}uJ%tfW<wV 9%jcط7֨@Lоc)7tf+s;o5yʛ٥lהҳbP*U/ 0F߇}ĄvOLLP~buh#Ek¡O!.`(jX4uvWY ͦ[,W.V;S3e֣ѽc$骨 {n qzc' l UYofzZ%0$7!jiw룽  =۩lz](p6- Fg_=̝;nV~X;:(T OG^ūF!8!mmm͛0Є2@}Hoijjjnn(7(B{UVSuRBJ5*B!`S@>kLB!8Xit !B #!Bp}ív B!m0qGai9Q B#P 8IB=ָ#B!(7qz_k9H0ƞ!o?@!BKR[kz)%ep'@@ː;/6 ާSkO5-LUmiʙaT?G":^_kW̪|k48(?iߙ?@O4G%)ӺcZvnk6PWj|A{dYљև|05LyQUj$˵U.B!H[[ۼy!^>wq*OOVQLke; e3D\#oa2*B!gXjUL2r٥2R!xt#'e34A B=W_@Xji}I)-!B!՗}ƁB!*yBvB}N<B!^wB!#B!!B&!B0qG!Bh/;B!B{LB! !B!47vIENDB`deepin-terminal-5.9.51+dfsg/src/assets/deepin-terminal/terminal/en_US/fig/rename.png000066400000000000000000001064521475472654300303540ustar00rootroot00000000000000PNG  IHDRZ7A*D pHYs+ IDATxw|?l~ދ"ml^B  $'!?H&!%!)Pmܻ%YNKtO_jss HDlٲ] ի]/w0;@@|H C:8E–@P$MLLOw?Q!20~ ZzIA;ci(J8>Տ\c /H҈i$h!q^0"_ن%3-:2u:`sUUU%Bc1Yu:](D"@ Q.R$Q'0&c/#&pƈ #ƈ8'iD8'1K;*Qm^ԑ#'Ώ[BS^F^F2oKD3L(q&lQ7`Δ$=w{w-s"V˔sV' =i$SGڋN# wG"^ q ЛxBEdX)RǏ+@fldb| 8DD–8e htcozF k4 0d既dݑS{o}` i544ώr; 4 b0K4U;;uz}爗AV^:œe&tclCg!1ڒqKe]Ftd6;:I#~h$&DZ$IC:E \ׂWJn%vc)9ij݇t]!fidth$h8Vcȓ9o0,16ɪîTS86f1⌈;U޽QF|O]w|L4H@dqO}S 6(pXq8\jUT{ WնFt]؅ԭ[;An3q+ER(]MJ%SeR9>={ n7P's"҈ 8gD<UBzRZ#;2Mg|41Ȑ|]l}Yb]X`\5QEm7oVT $bA!g;8i'dMJe,0'o/ԟy+0\&^nٚܪj]\WXNʈp2r3rOzP]N#ĈkDqETUc"<^SLvڳ{&{R B}Ey[g&/ȑS$r;^±A@{5̏?t9Fzk:i)]ԝuFsdFMmlX[H\ uLHS{>{mLdqL'+-#?.]rVvV>#Y.]l2u65}GwViDLwݕEg&2]oy╣ZyyJ4f[guZіS/QG.tߖ%b9 g?YO#2PnK~^)'ǧJ m`O/6T*5|^UY BBu>1|ۘ.to )e?z=Pc|蒌][NbsGd" >9c$FDzэG*qGz﬿ٕ((dǽk G8p{F=V6gKTmCE5W~'*>1gaԉJwStF@Dvnzb[ʈHW`q"?k"g_ϗ#iĉIK.lwtyu1Ll4g9qu?Bl {wo֪GAđwZmEIHe 8c#dX;vHs\;Q.)uUGWL3Hgb`LWj;'M[-_:يuo-_x6LY$m[` ʶDf5{H I_ׁGl謞__e&MoyZZ:V];bn%]klorATF^Zg2,"*3IA_y,wBS秌"<ѵ/hafW'"0)ؽ^?= }ӶnN7 U&Ӊ67՟W@g`ewđDDHqy=k7]֛9cC㻯H PZkX۲8RNy^% i"qIbʽߴ3ฤ5o_;6Ov52[T8uv& jˉ Ra Vjp"bz]Q;Ĥ4 e9geFFA[,=R(7־&=Κ;o! .dsqtګI998g@>w"bK.t^L#ܭ%c7JKHlZutuoǍH9?nv0`hMNt|BV IV93O)Lu ᏻtNJ3Ɵ|o5<]7nJws(}A&lׯSGS ?uqJZź^-$ ['DDDFH i~6ْZϚ2Y+̞q!5/d+.ߤ zBwwS[Йk׆+vi~FndÇEyW}ԬR~Y@DJK5O: DDl~d몒(`)mHr & zrOxqNDe_$ȱь;n,XmZ"m|c sc9pNЇ(anXwncg:Ӑhnjd˫#cwծFټ 3;~ND$9C dN3VeQIi9yF5bFY ϖDH5۽+W,fևl=v3oTmVHg=7o7)DDY6ĶQi /5ry> /R6r ;?jVU"Y9VHDK[OFɕ7fԯW];Ոl5E:n4[lXٷlXm&yL탘8qޖc]Pe=Q(?vB׻F< IS KK~l',n- X?ʉþ3#5r"jpEhiًsdv""~tOkYWpO;NJvG%-8S%U77Y9XW#2dcENEkLv{q+:sz!9/n>beǑjYwFD-|ޝ*QŖ,|ZCMn}`[jow-1̴41F$iL6tnWj,zIzmGi)싃~ثJ{|^"ʻլJi1*N#߽xG3)z9g%鈈cN*`LڤT9bR^xo.pԏ&>rٲe'XX[w{2uh?]7̱"ۮtՈsUBs_ i,(퇋+2UjQۃti)q煘$H$]GS(ݪfF_>,{< .]a8"zfB*c$>/mCy)#ODQ4\sJě*T98u#A<1<ږ]ga9Y6 ApU8oU*'T5ƉqqCzKjhx૩cQv5z u@Y*$Ą/w` GR;7#ypI\:Ro_z`-DJr-R^g=={܌ '31FĎccw6MFQ}F$>x&tv\9SvH#$w416t 1VC!)Y{;v)jl:ݩXv &01=(cݎcz(&]ql  gԙe8{tN3]l}-YiGcHC끈)gP8>}}@89۩*IC8%cfC<=n kW9{ ?=9[p~]j>{_O_UυMfn2ݛH䪱ؒTWj)/IfSִ#BC)4zkTQ8ɪ m4ڐV7?"Kᨍ ȵƤ[b&Xi8 Qu87 wg~ nSmxW K)})۶BBpn[ʮU#ƈ[0IhRwf[!y\2InY3(Lx+Ã63^2zoX EWiLX_mR<͟5}[ZD UhtGW=8vM$~y%[.~s~0iiBȵ쨴ۜ$!5o^Ĺ)=:G$]8}vsy*WOL 橥1ʣ )V4ڥ@>^{g=EgTE}\jk-tñIxXU^ΰOX;,-76!#=ٞfe}` pTTŒJ2ZE}$``i:{egVCNVdOr0:fFqDT$瞌=葁Ty-a:~Hdc\emٝX4(v[3҈+_Ε3hGP>".Ea]VNzug \?3KW>b`j.zi#fs{##/.٪u8}a5\@!#ZhoHM~jHuaNjisk d\U3gffs6lY1 Z?ՐlhFar֟7#V񠩺N#6k};;VpWZ[%"Qh25lkUbsryi万?KNڡbV _ .0!˭"$7(Ϙ\3ys2ήdKG0F]r3dBK$-GCN1kzܲFd*t\I;/U(& 䜰H9\;A9SHj8/Z]bH Ԉ2ޜZ'ƴk""<9w>}lj/D k3r~K(pc] ;/~$ÈqU%e7j[d+ć$""oZ$fsZI.vfw1d; %15(XcpF(3w䛻5_kdT)0LƈH D2(֌` hNrTk9 5h+ÐN*A/mׁ m8m< 8YhR2QGHe3Q"RV)y)ۤHN:n rnqړJ3z] c Idtd50bǂlnǸG7M++3;eK^ $tD~㑝f܎5”s=yΕ&̊Z{^kЫѾX4Xbݣd u"(sBpG'.O$p-/+ubfj1TQb^,5f{ZDDUu¨^ ""6~GwX< NiI95j͚5RK 6cyNX2GjÌϖs {Q/L<*{[?H< 0;@@|H  a Q|g/pNi9n䦛Jn3 # oKJocYϕ_R~I%eQ+څ/v㲱ywbaR H,8l|CL""Z|zHU U<_fw,˞͏ u%7:V|5/yН6< 8 F&̸_C=AYr՜~xNKʀ;7(kݝc60NRk M}DCzC#ϼɭGV.:bzjPyϟLjGg{?_=VxqOCD0/9˷B\_5IM IDATtjէo.3x!h+ptuUi >2p _ڭu,˳YN{ϼҼ<`_鵛kVv6W5N$x*B4'5-nyio [Ie`| Ĉ/n*HzT|Kk <5>ୁ'/?{G:uؙ/9};KN0+Wy_Y63:TUyܟNPBR{F9lшȘϲO~[/_?5DmiW}FDBff;+lP|jJٱK_HSř9:qT>e;NM qYFhOTf2Vs aCF.0/|Ǜh f~KoG-z)̲d[FLujO[vm[[<#gX䐷#G̠7Lw_B'unNJ^yi/R"E.{ͥ5DrknJzԪ)-B\᭴UzFge} g~r FcfůH{;D$4+GHzJ$&]7Ζes ݒkRoxg)qg_Y{ougƪ.咿/Է;JT"|/-ЃHYk*:pXQ%" 4:Uu>}/zC(c' 77Wojn^<}o[6Gԛϛߺ+aKM XF?KްB"nZNϽW+wq-Ј|xŭϸrp^HΙzcgm3:em\vh:%)O4ۥ`+#MAgSg}}$a)K]N.)Gn_ި/nT򻻝H;'uwZϜ5>8ц)CPz]=m Ι8rUn-)'誈bm7ֱ.o?6 dɛE5{_~91 YC%-oi(+v9@~aӯnuOZ6=~)ѭx cқ-w]gx9;MѽrUJyD"a?t^2}o!B|]^(qo#Bƙ?|ohkbvg/mP{,OjWvd?k;'EF̓C[ܿr1h'gn^Ck q̩o&co(ZYwH~?|&/w.Uwaqf٣֏%߻:\zŋn=tKmOs)ןqVȜRSYfު$K#btg9`hd3,興FXE1w6!l(>CC|N43G㦎Dn )DA""ךߩMұZMdaQMt:*Eb^ d>ujY|ϱbc#hk8ou>%Ti#PjO1&~)sN\@g\r$bjќ]83)?([݁Ro1}Oݘ;"m)=V~_!NG{[M#f67sk͖߹Oo_}Sow*6p궆]IKw<|^fBsP@ozBX4"N5.GTg92qĸ&-zo/w].-v}lH ֤*)65Uב֤ #'t>sFEc|fz}g'y8 sW=}VǓPHmul|al80jMh$麽miMjy4sb,mjFz]]wQ{%cF/2oqχ5~YX ""GpӚns|s_kŇjV6-K_QUq>}/Ltj΢]穄YߙYU6ԈGieزMֱߙ1i鲮&TRE5]/R{?w<–U~V,Ǿ ?z]?櫗DR3[-FN?Qд]y-͗/*ηx2(z}*<$Y$1&IYC%jxr$(`K]<;gd)9R4/+im2[TRf"DD^wmKRRMgN7$fc:bSb&ӂ&Ig5,ܶo?=V0s=wY>]G_x"3T/k/!}Č+RT鰉q>c!³(tyfqH$T^r |MQ =P甚=)LEv޳.`3Z "U6o\d&QǥRnJ]k}EYgjnXZ15o-]A?8O6v_ a""v9OQOT_ca֕F&o㯲_d-|ﺙڰem {k/"ww?%mPs䛦]:d5q]?~.Hmzx=+XpsuϾuqmtxem1ۨV-># gi,S򵫛;ɇY}U{'V "v^ Or͏OZ!N]o|böHk7/\rNO:lbcSzXeeeNw5 &r'a$暧ew}T85XJßhİzĺ30 &p\Hn|.Ӏ.5H:$0u٥]tnE+Xᛴ&?&S$I;3Jt@78Ҿ}GwF*f [JN)SZ JԿ:;) cV^SFioO_U|*k{B1LjՐX3|!$wØK~Tv5'11,1703BV=2BI2z n+vNT$ErVnHqLZ^褫$EDodcSxxt(٦ i0,- aUvP4^U3m5Aݹ={+sC"O[wQԍ!1R{Oe5r[qmy)YQDvwn6ӗ5I7$7]x]iDBh֍S [3v%?l, &/龑i3|QkA^{}rSL…/ Vi74H W {^kЫBueNN TtfKGR?]`D\gҔ.I-f$ yRjTm4n5YTekC}#39S[Ҭl;I~NI%bw7Qj0rs}ޤhHe/gQCNiIYS1˫fHԺ3kQx?M0{^+7H:쉚$r" QT/ڲ;H0|H%Һ˗F ܭ:*(1C :2U*bK췎0cĒ=3?!%y c'_eTuH5bO(M(C#Y)(M-YyLFjL ưf ZFش@Hf(PSkII2ZrCJf$0WV Br&zGK[OP~ DD4]e v)ڐ2Ya9!OBgk;?ۧrI:V D̼M'aROp"mG,Wm9T#)e}rQ2%kQ>O}GzY08QDbI jD1j/T2JtAM3T1?dvwHO"}3Ûn=tÖ%#|ee˖M 6%zH Dk47d-}?_ W]W1YaާS,VMPGj}e;ݕ46ZD8Ni0o6$|!' p  a $ wo= IDAT0;@@|H  a $ w0;@@|H  a $ w0;@@|H  a $ w0;@@|H  a $ w0;@@|H  a $ w0;@@|H  a $ w0;@@|H  a $ w0;@@|H  a $ w0;@@|H  a $ w! $իW*|-[tW a >tW+??UH$<0;@@|H  a $ w0t+Ք&J F1F1bS/?sZ#ƃ*/ [Ut dޝ7Uo{o5]ʾ" (0Qgt\}fA "Y[MڦMl#m)- }ܐ&oNܤ~h&H$J$hHHTQK""U%E&UT_%Wɴjau*Ի`KV'N5'H 򏵫*9WkۉJu7aE lp1Ct P`L.UR9* L\s+LiݜI#cBgz}HND j@\%'2b5#5TʸʸRkJĉu&h|`"g53qw2"bL%Ή]!ΙZ63PsVWΙ˾cǪTY H$&0ߤ_B]Y;ջaOcUꯘWW{%V3WU!Y]W^cMI;Қ2j|ݸ⯆g5u;k v S*Uș92)>R}zPUR*PoOt}n~M+B|2F%2u[ó"[\~{]O ;U՚i0!wP`\!U%H3OwdYY2os*1V'N*'.'k? p'0`5K@Wptݕ~YaF&GLBG'VfTv;(F<;@H` ĉ$bDGfD~WK?s4"v#'  $P<`\Ƛj_b5ꉣ SdnR|'&* j|QڛXfH*D*1@SzQNڣ*GcU>n@5q<@C0TIUڕݽHQIQk}9]RF91UUP<!wʤ1xV`\%*tئ=ZSݩך5gD%UasXBQv$xքgtq9cg*g@L%zg:缶x猫f"B*kxt gZ ;@q"DbDLe1&pFĈI!:yȚrĸB%h8LoU8; %)$($bD3Rc@8'"_UD\&v2*ZyW༃` 㪗#&idPMLC;M{MpJWs#p&@|BPL\&AvyOz|\=S5DžV< @m;<4RwC+N u22o/ݙ!犯zp,ܘuNM7Ϗt٥""/YEݜ3_w!"@dJ[[̴&u#yczW]/+ Uw J{aU%k^nIlA{P&ҥ}Ƶ M?,|#\HgW61Ey~_;å[JU"RF};G#[W&ߐ΄8%qEVxí0?OC1Tnr˛\G?k\Y8-w O]-R-_w2rkk_H}Rb+Kwy7>mIڣw{8knQǚW(EW6W9]rb)Ws hfm ]題0</޼2Ku/LK9`츞t(SrNzF1&\Yk9kr|lBî%623 FcI)^K]L&}D 7 wVW5eYyIs˴ ?qI[ɦn[Ϻξxъ -oh7Nh*پrېqW'\~uG^E@bƍ u7CffѣC 6eڵ"͔6;@@|a l  w6;@@|a lH@;a4q}K#R5?UEDfV>`65M݅>nŠ8cL6jw,FUU["˲h u/w*H!(Q-?/B`t;FJEQ!...!!ptCNUq#RXպ\=SPA @pyh"<IˆIqM&S޽z4E1 }1-ג$I^qeO{C|.qUՃʙ3ݺu#(##l671AP~v >ιVܹ(~vYն/wzz:5oܽ|ZZZFB d.GzI:w쩑,۔?U r|z㟞|.37fn^) O o/=K)1ų%!'6q;罭""}yiIyB=I̘:^X=hڜYzf\v%\?&ڱ`Իhw!!_Jҽ{l_40nk]%"<#wˁśDќZy!.'Wr sFң8o9DaS:.qrU\*DD="q {@D$DUl^<{޷^7Yu ^M>Adz*wUG6eݡw&'䐉?-Y~Ɖ~\/c6&5d(iËwD\uSįXyy8t}Ld<qAN_ىH0{<9>IDDG-]~Ӗi/m 㛍&vNOL/%xɞߊF e<.+F e1igh" @s(.oN8'^nU\x(7,1e\緬uT*$13qLҊQb?zBgfM0u\>zkY7ϼoTN>&DvUC|>mڠI7=!R$k?E/OaMx-"[|-Su Yxi;&RNY1%%ef׆k91N"ىH؛-=eMsǣ lzH57pZN5s^ODDᢌizOHf>> ] 3>tYْ>[6*ŗ߲8>_N9J]P{?wxm G sk.!_`mxv\qf<>%ٸ  "zzks~+R5f}OVў@H9)ۖ*o#)jyOwrBvN-E=+^[}fSo:4cW6)q"`cϖQU BI!Zp6d^<|\Jh^o~t˗Gw:eLܓO)s΄Tݮ ޚ~,"Z-dwև1 w[oU*3ƙRj Nc\$)\9WI_*))R{ij"+yy:[ 9vP\۳Ew1ƥ y+>O˧ߝvOӿcƜvUw5'yfCs.3nq<>q58Ӂ s_Rs`͈pn 7sӽ7 3H}'UjpiwxUv߶͆DzǍnѣGfGID=<-?/B`#\զrss=?1 u[<,^bccntk"4Sff&g]zV#yFDdZC;IK^"R-B1柁ZXXHKDdZVY99WE-9Rh' КP\ZZfY5.ugrss⢢N %%%^e3xY3i3vx.$I zm;@pRL!fj^oaaadd^*rN媻m3MpƾDd柱i]E;@pU/^LEꢼgtA|>_gq++(w:m;JTRR^5}.]ls;/(//uwکAA(WUx<&{sr(3_w0l&k%""&I$q4IDQl@[\k4j.++d`կi"7缬b1k+9 fA1}6hw;SH{ZxO(p8 CddF d8>񔖖|p 86-|CwO|}TPw ΒȽZ͏<+]Q^̚c,׬5S#Z4a;@z%vWkiub;RIte"ϨE @{g;@@|a l  w6;@@|aC uڑ)I `-PUUeU^^zChZc,>>d2#` DDD?vyK7jFN$1\e]QQaZ=O{f!c,%%%2222LOtYEq\,#I(%77j'8#wGvo'"##m6[s3:udXNg:>$I;vtHKUzcidX@vO岲2bXB6 !x6Z6--tBBtkPwA|.͜A Z@QQQglcX|>_w_͏xC;@pI^iG!!!l6k4 }>_YYn?AFUU^,7hw?t;FJEQ!...!!pOj.me>TL޽{zUUi(b0c6%IjÕ3~,'C|l6w֍N# ΄㱙B;Mքm\vYQdw?UU;wjv w85CoǾ-ޛGzIs6/,zwg=rUFLGoج5NOO捻7OKK@ȡ" 4ќFȞu}%tCH篟]zH9s["":Nzjg7VK=g^[~-=wl{㱹c"/㨞FDˠ N1@~ g|za#~&n$!))s-VGIQIe fH W6׉m )/IHLҭOfĴny%|)-iһf FJ e*eNCxa_N΢N:Y_/=DR^?C;D;X1Trh{-RʉOi;Uy-ZfbxFK&Wj)i N/Q[U >_o_4oOݿKqMW )ۏ?oBD)m'\(llM=yE=/>s;%石-yqݼrիt;N #_W|o#oyҥ]Y_ن^";!c饻kf7rizG&X㑧$'ǔsUǎy{}ս^ry`Ą+Jc$% M9δ]'wNW7Yr򛟎Wto0pdM?[(1)m˷l\ո`hN;Pʘ= 3g꥙l Nc.䫰ߔyf)ghܶW/_]0Y6RY_} I_d{v5Jp퍫~,;@WU"0?_[ǷEtZ2}n"3N-çD6g֟ɡ.zv,,d*_s;???޳?/׿}/36 Cf>ପ_^Wds=Oזꒃx O⮇wu3_DifUO?,.vo̥7o`LDL߇mDxk͙zkubtoIzy*My?oyoH>qv|w_^ZR^Pf=Dʩv#Ӻ8D8i: tOʚ9'ƈ1"NBˆ]׽Su}4q䑷~8V(ظrȚe!ݚZU!.ߚȚx;$ R*RWxV֚2?`k&[:)##;E'&'eN0Sw|oln25o1}7'Jն֡tTzb.^sܺ}!{׆ڣ.?XTRrDVe}ͶR{ol<!>ꮅ_}yC-uubDԐ K,pTUeGo:mpǾY{KC&%ռ4Z`QYy~>zhs-iiYCkl{iQWM]s ?l=|Ϲg|0Qsq; ]Fa]u(a]?3%qZZhۥK9fgfiYP[b+[VQn߼Hyh4Ln޸jˆ |U9kY!s7}[YQ|l/GyJR@$qrUU؏p't+]w0o&bW˳*|Ϳo۽x۪LmVddBN7Ql 0xa1XeBwt'/so#j#]f <5C({D #Mr:HI'PpmEʓZtL%{d1Md7~hEwqӤ1;F "R(),rԌO%QcTR))EM;vوH->%Q Yk)߬6U jqNfPxeQ9nXcćhoYɩTH0''hc2f゚2I+GEwpN n??˵裷f̜u/xK[chMdwL]8wxP;wVP͉1*%{&:D")R NU1bNRx_J뮔]Mn3ww{(fwIw>OfjqOuؗNS3̦w9t֬""M{-W{\9SlTZ@UI?!Ք(_˰;F~"6mnx(>));]V$dM?rl0?q3ιׂ4ձyvp1vFJަ<1AT|h;Cz=Y7ϼɢo6:U랥 czwyyE]TV@Q3kdyE*W91fT->nURReuwp5\$?=zb'bb^tuE%BBTmqQ1rιS^p 6Y=O;6H]: 9gwG&dXѽmWUNU1"R2R#CjQ\b}]!Ͽh9Z$]<|\ֆ̂lkanֆ!.$5nznV咷?>h1ZKQ{rzN'9gBKno/^;@C|ѯYǮ9c&&t>a]%wW{eR$9.c7 n~{'ٝ1}.g0ͫ~q>:[ 9vPojYq)e\48h5hUGw3W̸4Bnb6&ˤ5YO^:p`2wrʀcf^x3zxn񲻯)6xcvWN'?2! ,ǘyj6M%E$wDU^{ۈ],K^׭2kz#2ݻjs9EZʋg?NgPn0lee]{a~Φ_VL1[VVV>BBH9_jIITɵݯqITL|Fs""W(>*(&ޯ?Z3`ly#7MqggG3WI7Kӻn15yO8ېqW'޷艷xhCn)Ǻ/|_9_~ﳮyu1+>^"aBmC߮y tu0lV 1Q^w=򡥏s]ɲyVz[8=lo4oi/ݓ.HCZU#jݞӤ^(ϢE\B,;;{ܸq@x=zt{ak׮BU=55522,6r~mf?|p \ZZz /[nmڵkE)33@{P96tB6wh^jzHYV$;}1 Bj^'"ꟴAw>Do' К-K3UUU.O1rrssdxY%/ !Iҹ,3_8BNUUAXI(z[XX룢DagEq\Nrݶh"n[=8-u/we9"kCpEy h4"| bY7gtƶzIJJJB BU7 !T?7媪z<Dvoi>:ul6$Im~F$Qm6[; WyyyDD0M$<3zyyyF1??)Dpz&)z3Ԍ1+)//ziiٴZmbblKS<%I2VCtv="" M=jyyyn;55UQY?C_-Ӣ 8?c)rdl6HLL4 &9|^w9lF1**J$&6*ruuuEEE3kf`ɲ5|< LN)Hc?a l  w6;@@|a l  )h˴ZmRRht$1B#3sYnwEEjx$IرN`炦]T>v8>| 'iDC5B8wKJJX,eee),Y,eZsX+!`|2Y++dR`*@iڴ4@t:ӵZ[cbkʐM)V5Vs^SF;` ,C 6b9~oM5+sbz"\Mɔx@B|0Ѩ˄ eh4fSe!CPU<(ԽhkLպ\ PGȀlE'dNxBpb @[w$ 3T,KR`_Χ C.ht@[wñi&*ЎqT@ hB `F!4wcٙV"$ v0=xww֘TלO]%-Pw w c`ВYZˊw+4݌sGId*yъ'9-Ac 9m.ᐇB 5!@0C w)ܸjJOd.wUvQn-#?Uf% Jvu Vm(}DDk` ΝeSM|eV]h_Ŵ]~qǤC̯8Z)rȍsYv(eIՙw]6E_:f܈)1Qu5GeHhSBuw֊ͯW8 IDAT) 9טпEk`S$y[: 9wtjwwWI7jpUuz/kΙf6S۳E_lȕ_\ߵSJ7ΒXdu+M3/mm I]z[j>ͽ_+҆pUGU"z³֔S'_3zN.2 q˾-"XT7]W,orUo}玷))zbej=LoQ7]2F=<93MJΉ7\+oOM|xν}[;=\HӉk8MxQOT@Laݯ G|E=&.zMq3_=R)N&+?(?~wC|v8uEśbkz%vy6CTsNs7~-*|tIWPri%][JDV+r1;'ڸfh月S{1u%4ջc}UQF󄵮n"e&e7ޓ{>rtwJ3$D

(CExF\-U^]-N;Ƣ;^:bΉFTAkŚrv\zeQH.-_S $&k,zhxN*mL]5'a4\w Qѱ"pKڭj7.W#NDcz9'"UU%T5r hymO0VW z]/vxu ?ɩY¨Xw3EUN1 Nʙ{n,Wۯ}BTx51"_} ?)^^<58eOpUZU ?#GD4FHHmή974d++%86M GEͩOU\\zMB%Qw_(a.S?>r@B|sƫ^smSH$wk@)%ZDK{ߕ \=_Rlllr ۼ[pÄM&S|CvDL@g[ ?廩whw5wk隘GFu i4pȉʟH_jpPmigN]%"˧_re&;6J^/+vR֬X|խOPUY? O[";KMݟ,|-w^i}6d}#*yl鹙 rU~=:==eǻ3*8>yegg7.GnKKK[;~nݺ6XG[~,hz1sloڵkE)33J!0wv lx B+LE '@!EQ1E$MFNq,ЈLZ <;(' U6Md ;Fd^5t:ccc$$ ۥ.)\A"1  u/L]0&I$1$I(lg񔖖|`<.wAʸRԟE QZOWh s%up8^ Xc,e XcL[wOW8 4u OWa l  w6;@@|8*@ˬ]6]o׎i*? IZ [^~9@| 2;dwȐ! C@| 2;dwȐ! C@| 2;dwȐ! C@| 2;dwȐ! C@| 2;dwȐ! C@| 2;dwȐ! C@| 2;dwȐ! C@| 2;dwȐ! C@| 2;dwȐ! C@| 2;dwȐ! C@| 2;dwȐ! C@| 2;dwȐ! C@| 2;dwȐ! C@| 2;dwȐ! C@| 2;dwȐ! C@| 2;dwȐ! C@| 2;dwȐ! C@| 2;dwȐ! C@| 2;dwȐ! C@| 2;dwȐ! C@| 2;dwȐ! C@| 2;dwȐ! C@| 2;dwȐ! C@Ƴ7rP4SZIENDB`deepin-terminal-5.9.51+dfsg/src/assets/deepin-terminal/terminal/en_US/fig/rightclick.png000066400000000000000000001063651475472654300312330ustar00rootroot00000000000000PNG  IHDRX~|[r pHYs+ IDATxw|7[Iw*{ݸb6%t! !@Bj(BcpMm_w3?$˶$ɖw;oVһћYRQQ!BM/BB!ի B!B0qG!B!B~wB!LB!0qG!B!B~@']z03/hI4&"*8B.tD(c,d^@QV鮎V l6t:R)91&IR p---`0Z!Bu?qg26{iPP|҅ u21s1}Dh\:$LIdY|ԓAFlX,s !Bk=LyJ킘jAx88xq8Ex8T*JJD@%%`28awQ:<ƉcФx䐌yUYyb|Y&5= ! .gBP( )zB!{zRNf( ťNR NIWX0@e`u3d70rdq)Uh M>)a߅d4#,nq'&)!!fcޞ$I6-!!d2EOB$qOuq:?)f(@8;0 v߶ >gz/ƥr9t$R'Z³ze6Ҁ.m ErrzTr EotB!=KG4^2u"43BeBe`P !0)Hx0><iޚ֧܏-%&Q߃&) Eqp<#B]"DYF#(0P8 #PJ%v~0k6h)QׄdՃ:RxHzB]z#lXkZH>Sgϰց$ᣱ<јBALׄdF4=V*^JD/E!BI~Lk?X.f$/wrxFAIxY"T"Ld0T'v`Q5hdWDT`L}t%$3"^ $!BU0`c2b8Ev{@5bh=ݙ:l3%o݂wYϤL)[Ѭ#>p3MY\!%Dhw霤geo!B$ 8(c$gb'? }2nLֵU˄Svkc49/WLP4Kua4 !B"֓(R. K |zB*TSdA 'ک &Ȃ3 X^C={G|=MyR `tP|nWqȲLۑe95Z( w),XxÂ7\#B2(!\K\xϵ;;n.\8rT*/pk%Ӊ٨p{APJNYܽbVVB8eb=b&8-d( C?h&PPs}ǂӓd/YCe,|4nM%KfvYL o܃&!hݯ~~={zX*Cp%eR^?W\, Cx*eeZ'2F( ޛ`vk>ɻ:nN3t䑚M&qK'&SNC'#JϗUZ唉)3|:;x}Ke;r vgY;OCh : M}I91*;B!ݯ:|\>t;1k& dZ5j;y޻pCkE;;Q~M4\-s.}DhQYx*eƩ~rf**0 ffɿe {~y80:Aa{bm7d*)t]p+&,҅٫Ozc}F_0JQ%)hyimp2~5/Q>W5\R]P}tJ``Ub:9;w僕/Mc0(kEG÷ %3 (vv;7m|:>1vz<.j6Tqs Г["B&ٛ6dv{=.BF0Ǚn_dț()}w^kdHIt)<.ȉ}T⒦YWyMڗ=-y6W5awS ݚyHLڶ* s=_h~>̯$%{ˊ̄_X~_o´Wr?~dW@G39PE Mk`^op׎W*͂۲19a;Զ:yz ͡0̍/hatI-Opή)P`@ 7j;#c%0˲i?}6؉NI ) ;B!Nu]SrdvcFWX ۆYk{.,)CTɷ|Wxx:jy*mA2iG/qn.33z.>0Dc 'HkԗX o_aYR|G6=\~)C./O4"m @UrÖpcקG?RRIVG5w{vl0eٱ!̋( p*Q`ox]5D[V\L6>8X59Kymc ¹fΤp $'ou0^{3@\7:9p[|Tj />tKD3>HvFeidiҵ=ou~hl'vIE!qb,G9*#ǀ@xB”pк$wڮ]n]ٽ]}*q$֦[^01;OO=oRk<5C$C5*ꔛŢ,BAܨ+>;q s+$N! UBLGZ瓵$im{%24oȆӆW&C*fqMO n]͸r[pe, 1_:HͷdS0-jך%/T撚`2UNsGXp -x"uR5%'Fu:ĩswo_۽}}[rэ?Bj>oSu@D(rniOikbs;11jdٙ>89j&c9a61䴁UٻvԐ-o;bW~`rW^wQWsRTW;kP{O]M@zxށώei\#TmURu#?ldG|; ^Yfi`twK6c.^/qI߮^F>2`rI_ϲ;y\a[~9ﳍ BȑJe"ldFhdmˤG]ag\Z!BaϱgRQQq嗟UCIcD. @U4j]2Rn}6܏AcFΊ@K!vGۃ8h>ԃ=y<Aʒ^!$q/܍|dd12P2Pd ̀2)AA'\@HQV!cC!EZ R.KOB!=I&oAq.|}i   4͍((լxI˟ySOQzjzV^`0466rRB!ԡ>r>Ot)Sh؉̘AJauqKT/vF2}TIMJaA 1@LSu(wbDQ4.+Z  &B!:òʓCzAhܓ8Hv 4|y6K%B2 DD<8"<:jjj ,K܃~µ1ϵv\B!:Bxy|uS{!5G v2BA()*)Qf9N٬h4 g{1$I NE޻B!¢3Qg-Jw{: 'B(QyB!Ћ!ԗaB' B!3LB!0qG!B!B~wB!LB!: B!PWOB!B"2!B#B!N2Kaݼ$"jH Ӻ1lMW6e@SS) !B[ww9W2.o3fqJIW4:yF5Niȵi1nҔ2qx{vf̻4[MefΪZcB d`bY_uo,-ǀ ٟp!B?TMNq.+W?wd/ݽS3 2} +X15.A; 43yC*I 3`Ɩ!]wuLIpt7B[7"@p~1B!;eGěB5^Ra(il˸|FNsKc 󏾥nAԢ[pYSϸ'>b'Ҩ Cc8}m{|%@(77٨Vev*at?q ;RcnOI0`ec7m&ܮC6^iݘ?@`$u!7;کў϶XBqgǭ (a. i<BL@̔ eY;?-#@N_L2 sRq1^uLac( Z8no'~pXʐYvB!H{8qI bϿ5 3>.+N8YWz&8b\Cc- )xҐ"K9lC#E< w+B!ԇEJeq]!EĄk=v3qE*]ДB~Nj#nH4qS]搲mxA_$xKbŠ) rȈɬV<@(aD:/i6 )fz^T& @ Jq PBX̾sSŔ)J0)TvEཱི֛ pJN*KMTU CY @!B}uOš*;t=wuO0!^$=Jk L*d;k!q@8$}/^8E(9&D 6UFUl .5qdK\3=[KO; ~z>d~8k V4ʃ%"!Al5c|JpV'WHNζ襁iRB![s|R 'R؈Pwc)S}PTClIi"bFG}|!.Ȉ Cmn,j2y|Hyxov*aD%KrNɢIk !NN]I0MuԮ)BĦtT;4TTgLPZ'1t(R"QQB}|fQcB!o.G9M5!B(y;M 52IU{LRx(%H@oSjt`Jc/zd0]n-^ٔPs@(PUF2ޠ6NTN/!NZE=3䔂VLY͐u0L[Hl1K7«~#=;we[UΧぉ ȉt'hJBSqHB~O6:苷hWu@1ג6\ % u$ q[t-5E8=Z StQӦ}-զ@,L-lb?V6pVA噧VQ O0V=ٙXȭ/8IaTNv4>2> tx:B @jM` IDATsjͿK2@_a'ITE:toB!PE***ϟ>w<#f[f *Jפ(k9t?k  B!{֭['yhN IgLNfϼ\% ˁz[Ú7JZvK^]z5E3oo|g:| 5QbC:PŽ-0c~+-\_q%PnȸEߎ_sɶй̤:)$N^`x* m}u"q{D?kGUn3qG^q<|EA!NնԸnQ7"c}S̈[ZGo햤t|4^j:-eNQ;<}}S4muGBGm>?='ɔpṙX)n|b~v D8ˍ˿<~ΈZ^nP({|Ǭ7P˲!۟\;2hnՆ4_hc<3v5dǡ[@KHMZ..zu^@G,XVl駹 Ts76] &kzȳ'SZ<m;,>GLD͂"J O}Knv@nٻ`e5O_re?2XtI\o ೗`y*2?i#ZX7[|Iq_ixYeNyw+Q_\3a$j9=G~hq9h֛掞tj;{4YsNXu{r,K|t 6|{5.StvmݜJW*dq}+;N|jTXw}vmkloҥ7iӴk0U̶1k ~cⲍK?*_3&xJ_&c?eϖ[Z+.2Uffgɦ]CsR{մdyeOG}=+@8)aJZǀ;DgqMU&Kܰx.b"._!\e. <'vp,%nV\N9PS4em0CJ-޵ @~ocɁfi$a!-:X]7ڪ_ۖ8fib?Mzަ̾>Uh2Kx+3ynL *16G~PVAh_d%}kfl7 Rc\Bz >(6{6G6c~5~PK1pN{y8ucMﯨX La躤k#tȪ[H?ajnv^oUc ]]_=ַIwN31 D.wKoz^X_q*9c^n=06?&2ޮw2FU5*fg$(=ZQY};<]\l]K!PɝS O@8dPĎmO)EVŁҖw̝1w͵K ~TR[~%Oٰ"Ǚ ɉZ|0-VWݵm%Wf_ex!JyK֤ƏJmny@la&Ɵ.V$$HZMDPB,`-Nlۮ]F&|gmOe7ݲĦii[7՟7s& ܺsrr2݋@}3n5Oݺ nguN0d­m܏n=Édi 3'zBUxSv `K@ۣ3sOm!Jw3TnT9Y>{b;mou?=;8ܲ~'@MMMp懯A G|O7m~Lc cL:9Zoڡv'|?7fLƨso+4hyrYFt =B!usAuSsÎj烁T[CϿ9>ldM^G~ 봚gkgt>Jqv᣻kzu-ҝT&NP&"w2P@iiiFҺހ_ 7 | `~t}=@|1y潖u3w`΃uC/DžB@ Ti__!tc~wGs-bŒ6~ik۳C+gL[;wc x^lۃI 톺5QZR%ZpG/$%{**L1vc`ޖC!;F(f=d`! |6{˙M7dQpt;ku$nZ$@խƘN~WWHOj<\^YwQoKo=CLL"9SgB!Կ%WCoʂ(=v<=?KF_oH%8v4%Q$hD8}Z4(<^Whۓ9lw smFRj4s ,,,AUBL}Gtu䍘o8d^m'2yD_@6U㐄&}8-w2th5E^m Q|[ޫn)u:7ծ,klf⴮Z6uc`2xs9 ATB8(mDzff$ݜc0NH2;1D9X=瘒TġO K8)o'QsiB l.78*)u2 i{QYcg%PR?52/ ]9.BYۯF!qg׍ 7.O#1=RٸNU:Rw1K@d뮩WO{ql-p3)ZSzʟ]y{JZւFoLbeϮ}K c?nt0诲-ٴ?/Eiyk {mȱYp1?ww'[V-4*g2&<7| {V%2 i]{9@qT)0 lE^DgQ[cڜy֝xpKL۴iazAq)ުjUNǭF7pu[6na99q5x ShԮC6}ݘ?@@ԝhs1oD-Tޟ~u !BX8q'!1D}ͪP'G5d7FGHtds*:1Jʹ)-|wU*!`jopd@~eЏrz WVN$?q1qGǭ(atn! < T&dg˄śY;?i{F@'wH9-G%_*6xY`=_x #'%6DB!R*?qBh'- ix ۑG@Zwӕv!γLY\gF6EVE?xWE՜MP rZڔ7|Om`&[ Fwt MY`S j`^mE <4wZC|Cf @ΥHhxŷo Dm*d+C~f~RtdO9>qƽO=|XR@?szij/%uoՊp?|9wյ׿QoB!zOTFe8͙R 3wUA\6J0'qZ$e)fm gJ|HVE/3N:1)9qŐi p IV<@yvˆt(g̫Z~a׮kɯ\wtqnME@ܵ.Vuq%˗X9w~VwWbގB!Իb `.m^]1å:)u.i^ (T֤tPi'\L F̣)ܫkALk .' Yìy7s-j2ibHyhUÈXt6'uV<^]5Le wvc'F[e!XArٺ݅s~pnnsHɫRXبbj;ώ[=c~^αUk1oG!e0%yS/궁f!2̝dƦ9qNZ 75jꛝ qI׷(5> L]t7I-^ٜP3f-GqflJ]Q۬"6 (^Btz=F6; qqD%iDW+Z3W:W ݹ+-Za9=Z[7暸=9'pTbUÇ .1-7o^0oG!}0aC}:xeDN9e8gzL"<>zvsn<Yt: 1֢ xƼ+mؽP/LWYe盰1;tsU9yw_U*|j 2TjOg#ꋌs [{7nQSCc#g .-ّ"|.~$wU||ժyΚ=5 B(#yyys3reXN@ЀEefSZZ{o}󓧇W}+V:Μ.]ѧ4񿭮=,톗O|~2Z<\zѝa\(B!Ck׮S:K IyB'}˛Oo(doK~|߽>cx^_H+߆~s$|po-k+K|j{_=B$a4(8-j)_W^iSwݎ\Ú?߱ϧi8tni5!B7E96Nf^gD!BJUn>EzB!PaΎb3k_ j߷y.t4!B LQg>'&{B!tqwB!LB!0qG!B!B~wB!LB!0qG!B!B~wB!LB!0qG!B!B~wԋ3ꧧ*߂; d[7r@׾|B! :t2ON+zv4H`iugԃ_}~V8 D!70qX7Ӄ>xɗ }7?͏SW^;\77Z{qB!,8cރM}{^b¢x{߲{34x޼}]Z_okk<涿~k>xvq@+YБ_wb b {iحwy)m&zvO2箝W>Tw\1 y/_[-pu&܏nԭϽt;W/u˶><:')\åWoWpxr U.S?݇]ﯝ6@L{:;%o?\2p>|0c B!r_|Ul`W_dpУuOߔwOnץr|] IDATgfϸ qw=pqW=5Oߔwӛn9Zj.\#7_:c7LWsѯ\7n/Z5C+|h>t~90-vp{zgGEc]H9_+,+,Ƃ/^qS̛z_n;tg!B!q8t1)X^/xH1l@:AO~3Z#n5KDX1zP@lxB'm&הUa>6WW{‡pk嚕@y]PU?N0:{}4Ϙ*NUfNhm2/ ԥzs5}Nh%PRΝM5!B0q(PkMϔC9SfUV`B֢sB1Ӷ6 ;$)tVK2v%;Rozq\_}5]鑪&? <5]";:vbsF%-Бw~W :/z툉>%P'd»v8jWM|wB wH .CYYYũZAztZœ ߖ^y'g匰z:;0IIIG>>≯_PmJc;Se%+k?;p76͕͓R%n܁*Z95}pʙ~]{-;B5TY25 h;2u3`311Qw 0h; h;x3ͧ:8i=Ti]QCx L^}[Aܵ^+s=Ia;YGz k|Y-ta4Bmbr|70(-[N{,j2w+\Zr):Z4*axS̸C!dX 8jo'N.lbzs'}g|jV3]!3pt#͟4i6tǶ/I(:~S{;7*) 'sYm*ʄu^>>&;Xd=T̶-G#.D6eB֡m~2,*!m͟h፼ ?}xlBɬl ..ءm.כ {S)M?-߬A=~t w"|W5llllljЭ5t.]㾳Ľ?X5z*Y垓:ҩW=]/2 Allj};a{\ume;gOEi# _Tj٣*ؼi+ǟ<wK):Z,ݮ7vɝo šܯfƦWc,"},G!d;`T̪r;>I!7>4x_1]^eNj;nԉL,tK%Di˚ӻ響 !D%"yۮ~Mj>ݡF஽:5kr|!H"ޝ̻BȅR J!R~7_X(8]d0(OL_bi]Y\|KUlEBxE7̝~Y1'2UB̪T1J>Wlܺ"/!J*~{R֭EJ20ս+ lCM6 L~•zRO-tD$@TF(\ؤ$+I{JB }s}3ydUY3U=4̿=徠G#e׺ˢs/}~f>?Z^k]#d2IW #CŕKZµBצv )r+fee;OS_ 2;5JfɸŽ_R@T& n_BVB!rRz-ˏ[e3 uyzy5&%$R>RwLOQ6eL؏F珞mYS,cf?8U~c^䖭oTar5YBzU43l>tRѻ/SFreiIwb;c3LȿW2zug";#v%:zY#~?F.:-tPq?e3fïLs5==P{/]uN  vQr)wEJHHWwZ*..NU|:\f=ՔW=,,,]|||X*Owh<;T|j u1h; h; h; B2za7k&m.;=;S ![\@yë?e7k䝳ZPݿ|@hVfD=z3|zZ@pBE%wWk8/vRԶ\r.y-TVfT!{ϔ!he}jlWCrЭ`?z':71 !r6;L>l'sYm*K8 ?*dXiagyMim, ɨN9w ܿvDR/Ҥb=n9q!|?Ƿ)-R un1`w`S{.-|“qYOΫwS5C%!B-:TJB4vf &/aewz\BL7:h>7bc?9O5$\!Taa2lyt.F+;*μmqZl'9UU0ǟWk+_c3ۜT:}g,sϛ/%+ԤvPwrc_Vvtv_wVfZ+>Զ|U!7M>zg@xdLj {ݧu3fB(o?x..-### U*^Ѓ$LO??AQXtˎĴK>\4v/ 3ZBu:|6?8J{B^ȼŚo2LKJ"Ex㕋啬*.m~r̴Aj"B)72Ӊ4 lCM6 L.L[pKQU*Uz4][2{Lر{YDl9xM!\IQnGlO-L誼 <|Ȥge?,X;TrXȪݾx3`q ;t7p>#{O?v[!$IVص$I2R!6jױC{އSBJ痢JyKхJeτteb5Y5j?QfʓB)e2䤜Zsʾig, !u Ԩc#%%$/(SAp"Ny ߙ_wm}4X[Nv8jWM|wB:?`]sK5Gsp˼~Hrp 8egl8鳧.tc䢓#lp$y;^_\'BJHHWwZ*..NU|\Nk]iq{5XXX$%% 0㎏׳h-;92Rwf @p4w@ @p4w@ @p4w@ܵTi]Qrur:CQu.:.ܤ^!7.c(eݼ~4. -df37/j*^v7 2Z°ٯSQyk}b}zb/ɰwS:q~:[o/j?]tc\!zl=v6, ;V+cU!G&6hru,.B^Wt3ЫnȰ3>g]\Bgzzc&:{k}[gӇڗ=0=;[6gɰ3ƶ5ϯB2sG"ѬT_R+w=wGܵCmJlt z*?A2k?mBvhq1TNOo?]v4:M!̼U}FtjimNd+413՝AJ5lXA.Ы۪ɃԻ 7BJ֠BlPmQӉn.nԦ}Ys[բW1R%?(ޣ~u*~;EC-Lc8VVhx+&e;.s΂QiQږ2!ё;7.}Rj]4Z;3<%vJS:tjowʔ3IU6(! yM~mܼUO;s暲]o -u>1zUHhBJl>iՄrG}(s ouC`|jڕkgg5BUťed$u$JbhteW.8x|hq$T̶ !֕ť͗r ^^fSE9 W ٽ<DQ+O<46o}ݓE(l.֨nѝ)-;tGn ͪC }bʺ{W%bs(If^qJll |x|ŔY?`6dS !0b]*kMJHө٨Ǧ*!feJg{kʶψAyKkz_Fl~emmG}nmʘ5ѱIJY&vnZȬgK=LKP*=7+od,˕ڰCζE٠x.գP Uջvq-(8M)?n;jcf8u`vD )xnaB!jT̲I*FP%kc( M$Wsc߃vkdenaYuJ*_>(Ȼ~ٜTL{vmus艟*،B MckEmJQgdk{9f־TB1bТ(!+vҷng+/c"])P8yIι3q<;dQwV7ݜGlNxţUwN-mǜ1_P=0!*m)1ۻ뇞F*"bupwٙ*EOg  SظF_ww@ @p4w@TKGw@0QRw ęVq4w@ @p4w|PR uaG]!k V.öhؓu;j|Y-tQox]{r~}4]Զ_zRO .ȋ{mհ <.e뱳aagoݱd*S-瞎_B!5>G73v9ڬ[TLLԶeBq:/` ,}`PqހȰS{ԤW!+T侟suGnSRz=yׅyҮۜ:WSAp:Vv'aYI".qUN潇P޸ IDAT_TѼ̹?3BΚjN}0/D2n7rG s*9[et$$Ux5V(h!EB%J\az#i*ql2u;4z,^Xf5xٻOmR)3jF$g+*kXVR൮uu+)j/GpJyqo0mA~VD{n:WɎY+kQa~mu6(ƩK2TBqxtj\ N{:j+SmYY SUj6 yɺ}~qC(uXԬrac3>'rw-~l2ߊDEY Y~uTBE|eO+'49w&S-3K'.t*>s j{x'Nnx)!!^eh5++8uWOERR3 h; h;QwBu3`311Qw 0h; h;xӺlB=;S骻&sܵ^+5N%ʌ_N<ΚZ$\OgunjcQMR jzJ˙3. ޗW'R Kl{r$8BoSZ&2_Yy,8<<$~B>5 ^Lu,&nkO=Թ`H/,:~m-tB*ʞ_q <{dN,Zw.yվGU>6ƕlR Qv]oB(mer+Q!*=OUo]ghڙu|&z|˖uqMn3hŒ jpd_/g !"FMZ0Dɺی%3&GLW ]v^ui:H"ޝ̻B{wE?9".V!NѫxN:]+znԶ{7KYBX:T_%sn "m㉾SjYx$h/kaP~UM~ lCM6 LR+&]\ӡ#+XXm^^iIYժƵRkP5[ʴظ̂N==V!kcb,#Y{̀}6нx=$YG[%6xTeaWyo)7׶.FQYQ0ܵ*77Wn[xrQe^yrNYEgMعR} 95kKѷ^b.?|;=rn7z!/9@Tm5BOϝ2zIh[ھQƆըg]NjZ*;pM¼r{Reٸ+y[V7/SҶE-eAqutXlM~?b])vΞY{/;Ow#9gړSd LWt?#B,2Z1闹F߉;gg;2pԝqCo^F?V݋#W`1}2|WcpRBBjVVVqqq8 $uW#h; h; h; h; k3y_|t()A=;S龷<:.^+5N%Ete/=Rgexw-utsBwS'-QsQx-,"ʻW _MVR gW_hd#u,\[τG;1훊!3"FMϡMgLv4:5eXG_M kâ -hsn NHKpxBQ: nވ?m@۱]d0(nJSo+b2 Vee=BPo(^{!?Q޹~9&=g$JBw2xIҋT+]p*VWoEZˋ}նذ]6"r#WSC5|hk>RBBjVVVqqq8 $uW#f @p4w@ @p4w@  .5f G!++K%gbb[aw@ @p4w@ٹLWu|ZBߺu'C"/DXطK[$FU/`E];e)O cs+[;(˯_gϞ w̸kY隵L㼖u,btX5BH%rzlXؙ~wZ0 /3o;fŶ'ED6MQ!Щ?_~T eB^!<\ۯ\!TyN3= ڣӖco:iCW7}5)M&m%Ї%?o3/ !deJ=VBbyƬViӦnٲE݅w zK oޓu^9TM~5wY]3e-{n]O+W<>uܶ3Xr8>M[Z~W޽{wu;vխs_,L aGd#1=XJ>~P>`Vc{'>x|+nCmKYo>2mfnn>`nݺ䨻I .CYYYũ hrʥΞIII`'h; h; @G@! ]>j̸BVVK'D%Œ; h; ӳs >5r돺uxkƩTZˉs|*.z|Z$\OgunjRyq-@lJ8=}\=B##g]p _W 8wc79v`02ұd ]}*,"v9??345Nk?6FRv1LBf~&훮CuG%Ntsiu}X6{:U~ۢ2!N e;nѮ7`rY._7?oЧcGp"E[Mͪsn NHKpxBQݧu3fJЂ^Ӯ_5폄%: nވ?m/(c9|O%G.m.XXEZ]y/~VeZl\fͣyYYtW!ce֕qs ^+/\(gce(TT Ɋ7W/e?UQuiåeUq7a|ZDy嘘dz$yyy>E&=;-ITP)nT(^%=٩*/O#^,(ɪV}bۥ*5 ^k4NVjUt/Z5J*JT)w-"+Vr+$+6eu-+4vhismێXYf?NX m=>37-Ua=jAYăC~?&J([1?6Yiډ2ZĠԽ L/Ws#17M4 Y|j׮KuR3&,s;o {{{uլ]CY,n2|pbaa*R|d$c몥2o媻 Ke~_wwttVkr-g]\Omwـelo>r.">{I՜& 8vה[eZ;N]aQsVN6GDpQˠ.>"! EQοy00…-x'ڡH6%C6e^NaMvusW>r)M~P/Dp$TמmB3u͞w7º<.bNke l &þ*';[pUNՕK^ɪRxw&4aG1\^%JIsUvV#dJԣ².]Gy}IWtگZAy;99Tժyu #".;۞^{_h`L O& > =QA|'3_dnoغ].fnns$T](\{}C> ;т1N*Ã~ ;\[DॼB%Tݿzc`1GJRtaZx)6mNe5kf dl>2 n_BV+&ʕׯ&*խ ϚN*ތܿj\+nաwwT4l꿦oT˦g_FO(oDG߮Ҷs2!3O]l򃦼ZmU)S°E:PO6,gljZL~n5ɱvyS~:M;혊D-ŻMu]K 6Za/q=UUvmcʯڪvw9mU32G8)xڍLo;7aajddVf/sܵEޕ?pc/{t`Ⱥi^_svդu~[~3VsB-6L_yZcF)]w-mo{G~w+dQ9G7Xuy);;?bsܴMwˆN{⺳]|EvF%ח-T7sioU,+8eTfZ͹ss̬}ѭ/ %$$۫ fee*HJJRw?a  h; h; h; h;ZBK𥘘KΟ>1߹iiҰѵ x%W}ƯRyߨ]cs^E^MeYu[6.! !zl=v6, ;VBgz㧶? ػl@26N79ywe  9{6BH%۲V;cb"V;BV^K==#Z;N]aQsVN6GDpQˠDӦ 7yG?kIzŤju|DX?n^2ɋ?Ss3IT)J!d]5SKns"L^1IAթI!Rk~,?C[2wP'ˎ_] CvƬ^m; u_}gQŝ԰=úӴv͇NO^5SҚNѻ\!Tn] ~7nVd"B*z15\{:|}_'v,򜼴3ʞ=WAp>R NSwUj]4Z;3<%vJS:tj[m s4L%cSScm}xjf2!Գ~kc%zx~m-nIge~WneE+Nm?szD!F஽1L :Ur-bSo\ XUjzB!x%gގp\H[}¹{Ƚ^*xu%_)\ȃh9NS C+O<46}ݓEx JOS !Pdg+(R Ɋ!#cl*DC+XXJ!gfZRIOvذn-j5TU7YWbʖttB|;4,+Tz%ɄU]Sˉ BQ{7 wIDAT˛?BW"5hc;gpy줫wTBI&S+MyO]!D^^ JT$ ݄dRnS{ݿxzѸ m1x̩l?.wg<)'`Ŵ~ 5BCڏs;vjrF%AZ;N8v."ßoZOM.4ϚvE\gggggokܤ/:ʱ+ƌ]M1=}{C[Ǫ;]\6{BjnI8kÃ6]zu[֖Uugo}tERQWOoo-%Yv~au7>[<( @QXq'M=oLᆴJ zjQE}}c'oީ/75m_?|n/-P?֥W.h湟X|ώ}{֮KO ?pycG PiCBYq>\Goe(D1(% dAA(%N(pځ#!dT(820DQB!4K44"gd̟Wx흷X@9bиr^tt1֑a3LD߲qsʠ MZR"4V}B!vFw)pp9#H>;zW>8},$(2Ok-S'|d N%nGgľ,Z6 stq!Bhh$:N Ba{뾝~oe=Lf1 (P3 NЄ3xy >7^?vwD8;PZc(l J$w.?P; ~u:B!fF0` Ibr̓QtY>|LOˣ )aL}݉%bns+G`GCWTlUΗcod$MCsӿ_M-NoG2].z%9ANihO[Hb[$WD-K>9W1ð! 5rk_]Y@{N+'zs/o@9|GC79" \e7g 6CIR??KvJ}*Ҳ(tgݯ>i\du%0q~2nmfcf9 |!B;ܝ\r5)58Tq884x"~(ǂ ?8a>n3lҫUgls"ҹgd|z[K J>)UlC?>}@Q3eNny%#wҜ/s!vRnpS '$mA/i?PJ/n/Wb~< Xtɼc=ߜO97~8z^=fMPg6~p7rߦ?`&,$wpUM3/YpD>ΣhtN#O{G"ӏT)<-;B!T;m vsEC{y@ X`z^k.~ U{'PZxhǏrT\T[vOlfD䂹lt<9{K/x r{dkW9-qށm}|t~7q+W=污J3uq:iY-8=D:fu8.'|/})w/t0.p'ҡ{)/==^Z8 ݁_͵J5c:o8Cly1#.@GνvkYN wGu~WM:sĈFt.ݩ:\|$!W"Bڙ}C bQ;4]6ڑȽ|o*EBV=qt[?֪Ju:n|7\EzbWܟ r'l`yvpa^[+ Dž[-!CzhWst_'T8Gܹrv-QM O~r:!Iu=dapHA'ߠ˛Ԥ[CzQܸ{4 ̏>;b?[Ȧ,>/Aƾ)i6ځv#BVq)3'cMݧ%j{7Gȸ=O>bg 'dhN}˝tCea#TO<к;7m(4#d|ݹ_V<_/ =5,goW~Ulay@$̢+Gzf/sgO l"A\r7b?5.َH>2)q?]uKҢԒ <>Cȼ}擩D߯ lm4;8xF7rG= y&zkٿ=xxkٿ]+C63a£s?}2Bi1OW a0_ӵp"cH>y!2d4){]_>V\[ԄotXl#=݋z]mxkownx n8}[Tٺ '|P`uZh4Xv ƒl=ݲg:WxN`]+#/# c$)g-9r3|m{JDB#1,] h]CnZnECl/r5-ϹwE> Zk]aK񜮻>>jHE!sOiv"6*CA0 "!@?" zCwNgvì 7>=5*^1܌pfY1N쭮\B!gY:;suZˮr $+_~_Wp~T,yVɊص*Y(Mq~mІ:,u{{jUҘ'h,?2, sD~IۓOSWͽg#j[Ol:ad!s;C77@ \d]h9C+{Zf6FF7p o~oB6]jܵmgzBBqgp:"DQ\a#O_{oML u3zд38nhPت[I!ͿMnok/> i΀=m܆HiQjYy鞣?3gU}ܫt>˴y1qSF41M @PԂ_ݿJ$F,t| @,=zWK=f*5ԔOq9-,8|ޣݽSE။_:9K^ptUloGmv?Nw:*!i,BPk$^ؽ2Q$` (j@C?1Ptfx2 GTd5paELo-JwXE8R֢p/km4УCIoO^K|wo 'ɟ lX6e@gO>r o₩ (Sg}߂ħo)R׵Μsuf BFc7pÞ}Wj e />l9׿c6hy ͿP8W*/O~%Txr5.,>-zP/M/4( bx^hq˿)Ie25>!B OWh;0Bp8Pa}h;ر<^݇|;؝g$Mfnlp:շS@fC-w;덭7uιfO߷_V_Zй5<,򞝮#-{WM? g{|-t.;꒬7"ßBdT G;xt}~dcW~c_O;_:Qqӓ[J@"UKpxϟ8H}G7U^aI "On+>ë[zmxCC/S"> ^ Zr"dSkh; !IUѧ%v'ݧvZ]9tBN$sȈP?ya$<;;Cy |]tHw rm1H>z;ih)smVt'{ޟ}Ͷuvrfk?bwN5 a!~nu㵯9?s|+W7c!f'|8vp̽9uҥg[9CA`}䇡S9)ᔔ]?>;>`-ozybl_5!$A|o{y0<7wBht҆p ls@(p‡o' @zk !|xcg \imHÙ!>@dQ;B!Ў` H0<*#p"; 'l8gF5M36Áh\([}+kg娽wBhwP3n nD o-|7h𖣭mۡTBQvY#fԻS8fζn!somɁDi^p`WxyRXzo !Q|ZJo FVB(wwyEZhꐒn%b\>lzY.čEНI]B?lKh }Css>\\tJhPN;Ƕ5xQi;!3rr9 3k̵㢱 %;K)L=.umGCmOËx []/LC{ǵ#' eTRHkeu7ik+vP[7u繏2!AJA9/\ F"Wƕ6cG/Je@SRw|rN-ZWG[Ii'D3)wHCLSnxOC qTA⥏[7ؒ@J. ۩7/DŽct?oƷ+PE0B`$!ʛ>D<ʽ YQi;i( ɚ=aI>~m$ԕӬm[،Hqy)e/:AJ]UA,χ:gk7[۟RַVwڊMi = 2|r f5M rioz_[)}~4yFA^ ۚ{!Xj_ D|ov.7CIEBŮп%`%IoKWqAj|TPr?B1s,= {-t{ XS ~5,G7' vP9D|j <7Sl *OHRq>xWjq[z|xU,RJsS&w$po.DfΩu*է1?td:)+<6zIVNG0Wy3EƯ1;M*Kb`epo?O[r<_yatzʓ9Wh^Eo)sz:K6IC>Zg @؜TT =01=Uل(kV˨q\nzwCHPN7[<(Q(ViArsXLx QMyx&upWۦ07Z_A{vnkb뷋CΌɾ젶mZU9Α~eu_[匩; Y=lN3X8 IDATwMsl bd?N(]֒/rq*G.G7/k)m,ze&lR}sGo:{{V+)Soyq7+7nr^t'tq~MjKtOǍOSSN*lnEݹoFxZm!O f y9(WĨ,si 8HÃm̖WFXԬCfNB(5K- PB)LޢqYd\ĩ،%lEo䌂>*1.X>٢DTZY@V;r z0߽A "FT+!D 2Tl*I9,SPS0l9d u L5^ղkW)SWP!yMq^\y[-yQKbQi=|guC 1g2T L뿼j8VX BӜq`)qIKھt{~z\1q"$9 YX1j i]5Te;Z6Idl"\Thmnu6tMrt\V';ڗjd۽g|W()Α*{i~udv/W]"7S1*ڱ7;P8/<0riZOrhѨ2t6W4Vf*sy 4I]ѢR@*&I/`S%G kyպjz˶9Qj *|}C:۴rRi:)3yXd\ߖgd*-~^u^[kAqݺo5Rޏ#J%oX.LjMRԓQ6tt@qS$3ֿ8-ZX71%%QY*rCJly=Drts%H(O28&DCX Gkcr(%!XeN pBZ[P={J4BlY9* @X(8ȷO$Nf59{uED*YƛKLHBS1Op@ћJSER,{IScdSz5q['ӔFOJ*YenZnSwʓ #LgWԩ% %)!S' ΗZ溮\˭iU-VW-߸׻>[i>.JRSu B*\׺'J]5eK&0i}סF{Sg%6Q-N,p&Chl|HE:iզM0YX^uIƋ`2Ί7igg9'ۖy,zkrm !$hx: 8p(ګ 2(*6j'~u W`-p36_O|x] cV i|A&W"!ZV,5[^i~iM$ XP+jI~Vq=[X/ךBk\*~p"qf8$JWN \u\ZjS7S mpzPsmC )67b7:AHGB`^C}FӦn=aW\ ;Mw;xoo柍mmq7T0?dZ2TڮI:fj?&7 dB:)JݷŸ=&Qw L2s[JL?n(Z3hnZnUϋ;]92W`VO{G~>\ܯ:Cgh+pj4!4^~\٬X#Ӕ+jgbRnW4#)%)Øn͚eD,of 5YZ|wG6H* i 0(N GN-^>V?Pw]MLd~M8]]?^fc{u&mYyܤWdu^[v#\G\;`a]2HrH$@4=~0ۢ5ֻ >drdNybDf?@ǒw픧/?Qu~__s_]bGacIg#/_;[opŸs;:հwvU[~ޓ{=T}b4ݪG޲,+ȍcZ[^fn9DBL&@Qm)Fj=TlH~03IJ4`|_{Ӫ}g2b[ŨTJ%04#f\x(kHR :(Q;+ٮ:X>W[7JB!Am76bq!{^cMM{4%E:f ]gqʳ&aOu;:mp:U80VSӖ? /Qu_|>C<{eK  bԎ3Q~8ngoH.)|I6jڹۡ!Dz{v焅,)ig]x7g??L&^w֝,h M&i%w&oL3BY"5˩j7no32eX|>->P`"BJŸ(3ݎ}:B$I%>B$ 2EP-/˵$U;eƗ BQ L#BhwD)rv xgGE!Do}^*3o;E~aB!T½?3_|{+wXt@{{)gG|QmmfA򓸆L>%SKbumws.D#lBhwět;^5+',uчG[vH ЮK0gGcK~F$GdCH ʓX{J7|Mv*Eq$lPOH_lq{gS*z#桷 Ƿ轾ՙ;ж#GMf~ޞ|$:t;g 0pG]~jDkg&7d>vT_֎}#vb)y]$VURJ/}V*P{sTmIB=Г>_@;o+ eWT]$tHզB;Bj@|gIi^C$J}$ȸyn/y{6ku8?k E6]f+h߭7m,!#.b _CҒuW3(4Z_a9Xxh/_tGvǚB9 Bhe tZ4=r™O+$% B>+)$>7$:7rS ax2 ‘5>;WөE]p.?#:so-{Ǝmé!RjiFc7t8AH[C5Coo D\!0{k ,sθhy]-o >J-MɘwK=0ӽ1M0_{K!ڽO% ؔAh1R )?;ر}k";_u:MhO~8姦z8^L]MgAȀ}*V:<87e}pm-cE/IMK?;7Cgd}|TTf>JM $s>$cuD[ަ?-o|UN,RG=qntg)1| B5ϋ\AZ~0gZ}18 /&Ԙ&^rȴ6vח~k粋R/?oC {<F9/ d2 m='EǸW E-H{" ?jgy,X]@М[l;>.?Jh|K*{T9}z@М,@~.I;rb'X7ɧr䫯ߒtr&(6檦_a9|+bn#9ŋD?4[TkS)؏#f}Bf#; lnjxA^92SIDZܣbgB\Nؼdd.ĄMξsP0gGcK~F$)?ttpz {rPK (yn*m.YP&-d{yN+ 4Mq7%=PrmҩY=)#Ri?w׾zӟ7TE^Fw{A79J,@.a%,lX~9}=L֒P.Deb/ƯS$ȯ4y6xfGʆXvx:~8+\re:EB|ټV&j1q}iG-Uү}9ṋ'TCT~[&b)q]$VURJ/}V*P{sTmIr1hPM橱u-o@ ُҖm)/\dS=X9?QٶIM%$d6B gǏ2e]q%.72Wo6kH_3ʜUdd>vT_֎co*+`NRoL)~M+ #9p3sCQk5 *^Lssy4:7^qǥPZ ՚S\~I%t" }c,P ikP= I6 `g(_ct~Zȧ+1SHEr^:c |~O *-͝v2*maӽEK|eՔO:?i}hR^bg!l-#М1 bX)3"%+vil@ULJ@d7-F_i9ʴE\BlIֵ - ټs;- r97U2DW梺_5eBw.۳>5I8߰BP7F~=dy&Y' 8@6 N`]@`x{s%k&;qCEtӥ6BYL.*ݶOP+g@D-xW$g5 ìxۨp-k y"ж{ , WF 0kW7d;-+DQ;Y.90NV"!%I,kj6߯KÛ?H~.!c;~P -U_r $uS|Qv9t=toUO\uhgz?i}w6IKf57R&Tܾ'Y)RO$/ "6"ǝ0E K=lêd@'yI_I( 0s씕$ib1.a6\Ah:np9Mڄ +9ڨ{ *?ܔJ8Q M;]_2H4OH +8޶ep!Swzk4Tg,t]SIHӛ_?%Xrp_[Ǜ2r]V9;`89Z(lvor/}'g)!tziV1e()r`@83Kq^@\>fO}1S\b50>,|lՆ6?}ÿ!*Op??=p}@~nhYn B{X7? IDATPo$moȄ~֞yS_a9 +'ݿdy?fyV@Ғ +@|ÄvlEE 8mWǹ匈0^TސR {˩߁$v{<t<*ǥWPxfKsJoٕ*z}߈Jײ:. $h.$.\@z869=MҀ5vE$_2csn]]`uiDytw6~V0psvYvOy$:a|fC+tA*{?:E[u_D!*\-wIĬb:$-ο4y̦;)?Ws0Ehw>юBӧkNĎv=K.!}+>B!ЎD!Bh' j;:!6kBB!NwB!v8T!B/A$IBNfs3 F^,;B!vSHBh;)9,W4 C~Uv*Ch+]]em6;]L۷G 4mdb)񃮮ۻٰazSl&h%=;]_%rM$;8k;mgfwjʪ`ll T&y@xCy$@^xB'K0bIj{)$םV,cGh9ܲ瞹so`{tauk' <_UHK*L׹u}zLY>>_pi=u~ZWVnrsCyRt9t@f j0r ~ =9>yBnAnk6w8w Ge哾uuJZ7gfk\+޶L%ovNl]:j EZxicm "M W\yOgsGQM?hBQqU2H|u[[yuxC;!$g9:`QFҏCXi U]ծ)x9_O{FNZ7z~Sr˭./6vҔ_[.]* -Q|i%8M=X7;I]7hc)]s5Ye3}I~opC ޘǻ;jQ߶qgT@TҗD3.|.o5]|2r%iry`q x5 wYsNtkc +cUBTX6`#S9ؓO,g&Xg,ާ$ȑ$-ʩͮuQ|Ѐ|%ֲ`&\r*[Y@rn!,S/1G\)ؠO]އMDNYDג |8XٸJ'w.j~!kYdZf?F6a**8E,Xl߬W(fF\puәN7=mITqc=@n[*μcbt''4&sVg99q.{- vl[#F*]6F:wBևB)'yUXd~#5:=Ľh0bLO(@Y(K6Խ"dȋ;zΆ,2f6bdcpw cjcvu}n8#[-ΰm{?Im{cV`Ll8Xp<ڳ~0PVKh%~{15L67ϐ`.ʐ ¡CUq|厭On_/wq+8uY%VzEBsŽ\}d[.Lt|fc4I`J4-뺭RtKܔs6@zYp}.[+ @8 SoF.Wl*C5䘖;0%2V\¢yPhR:,/}`ZBX~xT BYPLݶs@R5U_@5PbuK׬rwK*ͱq#,Q .x ^XkrIÖHE=m9 J) -:-z¼ O['&~)z⹝8gAHxj.?`Z|6-c /)9;72ieKG5(d;#3+NNlvEH]꾢 >ZN.k 5?[RPyKb0b1rJ;g4U##СѸoaJ}0u`YgŠ B# aS|A%Xj^{o#0$Qt U U7)} juM嘔;$(?l4EP,B҉XR~eqR-+CX6r90\Vlte8R •WqE FɲfhC«(`1 )mIZւH,JkՐf8kT5xDZ NM#Nm9#8fzktɛ5]%4JX=\*7† `Dז{)V1=VMu]_{>tMOm#p熲!=g26T5;0r#rng-nːbG.=?9>T˪o΁8cǎ帡(P*o>r +Cs JtIpQ!Nz+0@ b9}1ȲPDn}^NDEEzݚӴJ$G\IzZ,Ep?D!Fנ1h;.KQ}W)2I 0vU*"sSP6"paL鰹9ֺlzD9(tө|@꽡*:E,Q69e_P_3|.N@o(Rq2is+e;l/R]Ɋ :29\9<]6<_QI/k$-uY 9S\j9MN'ɃGܐSsge6¾ fbu(0.}ːW}_dyNMgm@X:mh!unAbtW?D._W"=aa0 ؋cNqJFs7PLs"0`VZ&lŐL&c"ǰ􄨚1_hy hdyiz/혷s]۵̍tp:3}{[bh.{b؞mԧG{fY:E=Ɇ]U+g`!4a]RW KSCw)%%U|˺S*m\6l /*aFθ8#2׿Et[pྣ1Cdt] Ji} Nmޟy ǥ{ V m{ה\Xǽiwc}/Wƻ{+`**8ߒۡ1+dΊ&(AT]/.&~ړM7Rtk-#[]"?lM~G5@~}z]ݶ#N!C_}6_q\%$xu foU Hxb~~x`|!6$ΏOOF6>=^&Im>ٰ|h45.Y"sYL3}q̻ `AR,G!@ެz\wb)EFi,  ?7;4>ȿ55-r.wwB&6Lm,r ?jH@Yup_#٬E+s;>x+xϟ!18^H Ammm~hA0.Dխ=T@V#Pw7H,ۙ(Xejcm!K3Ñ.oHΚlbҸտIiSJZajh6| S;tIS{0Ȳo( B:\ !DӴ  ȲGE"wEABe.[Z6}&@ IcƷ;y}wn>'|뷿W@\wV$QkG$q'f<@ ?cƌX,6,BAUՙ3g oě.w[wޞBscv^ڇoLrP;@ nh>}z:>蚦e2iӦU-/qo^OSO>;W^zek7q'@M X, fg-nYv(7WSh7Wn|gva !_ ~Yh%5;cLMo|CCC0]0ƑH;ʲA:;]hdYPr6=1" ~3[vǯܑ9\rܭ%d 4"1I CJ.L gn:+9J #U}j)L~j ĩ5I3qɻ'+mY>TŕogUt$h]#3<9@ k/ tGkwK4|T_̂-r  D3mqsˀa cspK iFp~.kp~G̨ ۆ!շ =rn*P<`R矷=7Am۶ cZm먞zkn QyT)Pi]9@geD`T"򊁉|lY\}e }4{VH^M¢{kY@rn!,SDL^}>I7?l~\. qq8|bq<3Q:cY>%qE2~M$ߟ̢\Ik9<mȑɞ@CԖ@^F V~263d؜5Yq;[Vg[dѷ6iXͻ${nwTq.gR<6ѵ$8uF;N 3$ŭuyo{?w%ˏw.j~;!kY5Z-|AK5y./cs ;Η_~yĉ>SO=5a„͛7f7n܋/HӴ$Is駟^zf3cᎿsϟ]Mk>[YZq㿸x9T[Yd-&uE"SZ:~崩% #S 4)i4w1ؕ|[Ax)uG^j<S,$#љ5"9H#58MޖGQIĮ T)xSWql 5b. cQFg\ӯ$'$f䲮șBs ˥#6Ĩ*F8I,s^ZE\ғ.NI] ]J7>(f=XlA[l1񽘲Vv"7qz2(v($[°2 6  3:S9(JT9?3[ <.o0Bv tnGDŽ=&Iٮ챆} fݶ,hqJu3iovY=h;5_Og.Yw ЭoP>s[3{4^VO܉z5}MWd -?)/cs!oDI&k7xyEu'M?iƍ IDATvi---r \}o9sF[}ˆSW0#!PhR: oS*FZCRcS`5"Ei{+t bANU YH-̨4~tX9;Usݚisu T.팆cg)yew<]?U_~Xr֬b-2ч ^)tKܔs6"WZcr mXJ,Z@KGl'ŢO(s |4M\Vp=/2lq PZwD g7}D fxl^m ƲNdsp֭Onݾ+^',{AEB|nc,ݺR9liy\T"(++s9uǬPrVET)7SuR V+\T4C>,hv 7|'+V߫Vpgcm۶R `Ic!MuQ DN='Up[n?@qmB{4/Zܷ׈:ص X 0sm~WߴLr]P=<3=\kN;kT; / CmK@OQTd ](>.XM9FU&+.'y͊u]f(Ќ﹆\d a_ dmTyW _sP7[>[!؜ 'cޕ3sydrջύ5eNMg;}FNƶwJ:2M6]nuV'D `\/D8ܲe˙g?lP(\r%{8{7o^*r:Qkm_W}m g,ؒ$>0tt4`M벝w>,*|S=HvV;`wߪ2ݡ3:!c(βPlv`;? @Bt=oM_->˛0P =տ\~|t.(dh}}>A:o3&Y͵UCPCu.pr|i?Z\" ΎIGauʹ)3$N,ʀ2 -*}`>ds4͕t@0l#~p26jliev疝Y `p6njAn#I;i~wJ`(E%zGjl<_Yh >ţ @+5}|w}Գ/H?[}{{g0mڴx  n͛7šF-=}W~{Ƀ=13+!{ncZtaf#pDcz6akv;b|tj. IJ͔>( 9,qj`ڲ]Ak][pྣ@]˽ڕm 0oǏ=xYArml*lMEj09f&#Ab[=:]tRZqg^@$ s=]O Lm)n>:Xpk^vA;WrW$7{R ɱ=v}]5VzNs(~Ea_yG^ ükL椓N8q̙3ΝvZY'L~ /_xv?}釯zo5p#AN?tbkՠ,^צٛ0t>uQ6@ ւ0 =lg`ݛdӭJʞsG"}_xᅿoa?غu({~KQwߝdt]';;;/O<9k>[p9眳|sUQCO7wuK.[UkYTT߫:<;s ^A@  cb"$z~OclF]] 'zկ4w{nĉk׮eYJRmm!8UuPG:aΗ畽 ?u(ΐ#ԦnL(:gZ8;@P.]qO_T8nQÆOYpx<:pAC#M}y !aY]ABUU6lP;n#l6ƍ91cƜuY6mAP81S﷿t @ iم ,Xn݃>xI'mܸc#d2]Ï>f~!;@ B%8tUV=j{챡P7eÆ haHaK<.wǝ@ a$Izٟ c~wΜ9'O>S"n=SvJUH4!q'@s9gժU7xa7oNR[lٕ17f͚])4Msh-0XN /-vԡzNa$ojmmnIxH^ں$ _xk裏.0w{' E$:>x'Nȹ:G"q'+}O_ċg^\m߅۶0ru֖ni|L(BY>?衫֭h]32IFyl$s= __W ,?1cviZCCÕW^馦?¹|r꿿W&\--G]a@ $粝췺8^N\P=K_w`ܞ8!psݯh%f0ܒǎ%>bs@e"?ad&w44uPLثjԨ8ug}G cl۷oҥK#BhԩC,^j_ GJV$64O9F(;>ڸ%#9nFKc lQ%s#r y|O60sS?~mgR-o|0Rǝ@ _lԱA!*,z~9<^J3ݦCX#)EB }[6׽<..C6I[S ]3 > tO{?N1Y!#%<5v>˾U:+vj=xfuƲ}J⊕k^C4Dv$ŭuyt!~[OƯ3Y+ vOWN/ѼK/xO:{:9O(Ç5Hxݾb sNtkcN39Rn\᱉%)ũ4pq/5 vDQǝ@ [9C ^TU.>otv_5J1P1^zBofXL.늜)4>DZ!FU1Kb*G,Bx)x[ ovemwc'xcQ[}4՟Rs'k5]Ex4 s<j~jb7ESRׄBҍy;XUX.ϨC UW՝_ R๾cOw>﬽E1F$e)\>w۲UBn:XجB'`v tnGDŽ=jJ}*4iqp8%Ժv&G(< ?G1 cu(?ŋ:11p: K۝Kroc)Yw~.aX$LQ$ϻ 8q|I"{V 1*¨Bb ᰅa)R2a5cJ\ee L+1u ,-a@l'ŢO(s |4MySbu-Ԩ`f{>YaUT@?b Iy rɖFɚ\ EF-%4;#Wpo;j+8uY%VzEBsŽאn!` =F>)o Zҭ+E W/֊Ol\~h{]j\ A@Qv^&Ol8㌓N:IUղynƧ~#03f̘4iL1l׍6A^WvvsOp,,G;>cּsg;gr{#"}7Nº+Ft[wg`"*dŝ@ [|A%Xj^WR)?64EP}\:0Sa0K*^@ustLV N{]N{BD5vO@fzi&Wr#ro[ܖNh9*#zv Tr$]?6%Qtq2 fӷi% wZSY%qd_HY]+:!ĝ$?`evN{2m7`=D}PŸ2+ 5Tűc:?ϗV(zaf͞=vW(a]T 4O?i]%7.:?ص8kԉ\ʦО'Ia8c2\Uф8puN:gL&,kߣ;"t _ďW9)(|b.8s,+SX9/\O {;&zܢ{Cc:E{ XnuqS9(Тyt6|B). ;*&#I;i~C+ie `p׬Vh3T(}o?T$IǓf+x< ,شiS2i0^'at]w\'NLx XlLiB-"E3P\T!Yb&!%'9RE5θ6V›`pWFa6Nc%( y~ZeYY}}S\F\rn@eK:-^]'g 1ҧF_b8(4׿J0wȐ/>5nGԎ|[?rWe:Re ¬'VXEZpIYIc]2(?.Y2Kⷰ1c[OշUz[;! >Aids!K0 F|>߻j.j| 3X/KyIuNr>7?xyG&L:z(%#>` ]kpǷt,2 uqq&c)kbe0WF ǥ{ V m{68F=Ef69K4gshjw#2sQ5m$P%fJsR3dJ^f[_;-YƄDtsHasd~|Tghs?Aky_W50mY{Z}:=I.1{߬e{댋c;( y[XHw Qpnߑ ;j>YGpi8i `eVHXxvf_%~ړM7RtkU{2u.>6ϼVJ}+ 0lXm}8 h˻"mGBl*{q/,˂ *|eٺ!'B. ÕvxoٗXn[q>iJfOw왤kޙ _w{WF v駏@NrȑEjHAӕn<͙3'Wtx<+VF#ZPF]ꫯ]e@ "Y0rx֬YCv !2@ .~,bQ4| 7B歷T&cAђ _TTsW !#G~(4fD}>GcM#=4M?N`VJϋOõ5 S2z_M;<Ϟ֫jI2pa ;@ P2`WrCrh%'9\.2&n|Ppb/̖6>_q¡JRMc3|9=ZQ\ϋ [KhvF Z.o˻uoˢWN^v9+,ѓsK7H ߝ5B\5P IDATT"(++2^_Ϊ*f궕b$jkE'6~l.oB3#-(Q7%VA aEj~byƹ4DwD7ݢmK進E hC8Կe|76x}[.@(Yq'\-@kDyB.|wD-:26$C3.(ŸW*kLө4CӊxKw2cJ~9: za,ponە9կae<4ˇ4 WGvpEkv`beSN,| IYf\&+ea8p8 eAwL侽αsnc꽡oVheZT4 ݚ&`N}05g4][-U /q#pPJ>`}:,䦁M6S][v>}ZmOߢy[ ҏ7h:EIh}p50 :;Z"_wWAѺi}2~ʍ=$Va !.uAKlaӃ`޿4՗&u *Yc$]>eSjST :%&85  is+e;l/REdyNMgmUkxl.Xm:E)Ʋ;* +> RISY뇜rf,Ӭc wI 6׆Uȯ1{Jj8^Yq'G.qnAg!\7Eopƫcp|Y^e1koG-:%1DZvlto{PVOa{댋c;( y[wIHYys/k3ʄgi7@\m;?5g3]1|'SnPJq:nkU{9cE$Ҭ:z6akv;bahcV/$P[[駟>ja8:/m-Fg}{LhE 7* !11jN Ci#aAmƄsjᰠY] q @ P0 EQ!fc16 C4q'pq_p9W4Tzc]r*@ #N-yګN ሃ8"^a4(.!U@["9r_[쨃~#Gm~uIV;h1شևm۳`}0" j}# @ SvLjŴ;@܀׭-.H^fp0%aЌ҂;xX UݣQbxk !:w@ Ɋ@IZ'XLTXVOI\p<8 w ̬,}J"rQPc>uyryF&I?oQN-hv(|Fs:zy"4 )8>WDSǪmX/TT֠ڥRO/ѼK2xO:{@TҗD3.|~Վu]-:>`.lyouFì1w& rʵ'ZRA'RC 2i`>\#СHw@8lQwϣ=wثh @+%=́r5Хt"7#iiP-:i=˔M b"\9Sh|KjX(|#(kN3b[EڙiO9C ^TUb;Q_s,Ļ%mlWX>Kn[iovY=h;5AEr%5sugr &r*/>f-m7JvtL+9emw7\6N .7*cڏUaV_ִ߇C8CيF粵v4y)hNӥͥiYmf @ݢ%բa @[8jPKpUd4͵NӔa)bu~r n18i5;W(u}tyR@(%7K>.ROOe;,+Rbi'Q̋ŴeVzY{|ՙ0̙I#,ۑNB e]B oCz{S,-}-^(-PZڦ ,lK4.,eBB @n$$6qlKF3g;M4$}tgΈLC(6q66CلP>Lt>mOؑ EQQY)3jiՆPX# %0 bU4QF"u6ZhF8p g*p-J7tQ 7ӌx6Gbz>2I}<|92*bf{#?KKei.dwxo2Iܼ7;8Qаp)ՙ6m|f~&~Χy?wm!*JÏ&Sš7EΧh!f(TmԓHtxdR /^mYP[lD8)Q*ט<\[+Dl+Zg c|[A> Uݗ-fJ2llvHҚ6_P2|&cVص#UՏp>vvqO1,q !@`ٞEQDQfXqoU# %K4Udp+Xӣ@Gd/L@ˋ&U$Ɯ8H =ڸ }nwF-2x;W?t? tP+˓*bE:gܙij&Ƿ[QнVg10ae@2JVfgIhb@hPߘE=f;hV(&T8-oG%]@Ӵt[f #Br 6x;d.] #Bx~#E~vǝ& NoyI2k$@3􋯜 X#Br4x)s?۠|#8olnWS\xI @۞F7 X#BMе޳l2H&lV#>F̀}{}徱g^ל@B'.lbs:kAgmc^twB E>{PKK>r[ud?Bn#^wGŧS7»ߺ{\/:_~?{n)pG!X,vϝ;ZzuWWכo9ٳ߈v{u ŹbyٟPO|xixyݕk[bz62] BM@\͛~{kooojjzh{]^{5Ji{{Wz;JoR@yg{ 3,9co < +}wBJT~?p0?qK@:ՇڏPw3fuj- V@X}))#UG1cZ&o;\n]C_:o޼E͙3g[n7cܨoN%߸R޼sm=]oz/ZR|4Y4X#D#v^_Ϲj`j獘Ok;Z:P ^Qky~].WV={\|ŇwxG岦iԧ\.vIo^}Փ@gݯn^w?ۇ[=8Or0.[eB b1 c2C̃y}(c_Msܚ5k>я}SN?Ȫ}H(ˎ~h&wD-,]_1UQz S. |ϓ©[m7*d~fQ P9syLtlU|Ł{o{Y[Ւ2d\;SgqސktdvE 6-A~5~,X+2Y ԏc?o׿qY/u>}=b_Bhngj-T#S1Z=% m&0VL`K󜻽cT3u&@r0wa D+Dc:et]׮]G>vo営d2 (=\\^ts=7H$w]:>y wJ~IbVzW=w{g%yKP͚A '8uN2g[e.Q~#[2~"Lb?-b[BJ؏+#jQٕ}ɥ?:@fҷWR8+өlS`||K^4UN#kdI%z|j ^zD7| A=vxjxū3reeS7 _?WO}9 5<5hGy9[nX,|R?X,.]t޼y/>s^J HRzy=c:u4S!4sqAyZ]24Z.E]])'\۽JW`"÷Z%g4yyskI[ų]S0&mrOE4o޼[JZ-E44#`B3MRΜ%Fw#*(X١cv3h6>jmcW1W_# -#4 B$̾")Id{ l2u޴@K_xKϦznX:6[v7f*sv'PWųq(jK t4F"*W:%}n˪a!G?j&m \nϞ=^zЯ ̞= xqJhӴv5kp BgY]T5[ɝ_v8jGhhii!K׾~{-[{ ேߘ í2!t!8;`2:6itwА /.z'Gٵ,7RgϞŋsίW^y`1jWB8cIz/Ι󥎶P(=L%N'^|h4/|W^;wn>e#[wgAp;z'pG!i<8_~{o vtt1|f@ XzWB!иЖO}SK.=OOOoqc8w2E3qG!4o{' O_Z:r[_RF~#R`9nRW9x,ꏞN[6J?Qfu.:9sXZl ⟳-o[rKPbO;772v6a袮Y/vS"?ev䦖y [!PӒ;l]2mj(U/Yؒ!BJr-eܿ~/o}ppDQlmmţQtggUw)olS@\mO;٥i-'/V߼1KËOtAT.@/jW ΔeU4>uνsbm g-z _)OsX# EM=ɓ8p 5*(߄ݕXwW޲~D&jTn &!I%pH?*QM'~z37̤*tU#8ggU 'ixs6X߿v* ӽWwrEG}\b?hB ^Q5G໳켾sN2QV#fjx~N7ois"=uζo}9wa'۷u9-B"#%@B#ר,E8H-baoe+z@#nKE-T IDATk[ }}sBSi7vaZ|fۧhٜ5vcGgΩ+ >~OsX# F\9 +F#"1 r.eƐs(Z]67zI7nmvU`!hPNO]Usc,8Z+`+zs+ Y7kⱺ&%l|?u8R+uF& $nOλMM BjCЊP+|$=Nb 3S ( Y#ԙA\m7آLӅJ ?p`~SD*},uxl ov>tx]P27/d~fQ P9syLtl >^GԒ?kZ%4~j+T#S1Z=% m&0VL`K󜻽c`'s>r-Q߶`o3۹hV/[4vȘ \+A-0*H~~P}Yzvo>k{‰uik(v ? RǼcW3O<睵ߜM\` 'v * #jQٕ}ɥ?:p||Z޶n"4!VEH8}ja{Zw/sne7U(빫/+] _nkUE^j7]ו7zs9M{RϽ{{7=a]RC#3wTVH3xͨ9<.bwD8}Fݻ#?`evIYBS? 9@v~ؽnW2er^jK"P ¹4-y#g@D>!mx¢@ոQl? D%< h3KuBh+wvU}VWdU1< ]%(OE5IJN/UEffqY2I}<|9AŮp!7请śj)!HuX< jо1$j9- V+T<q$i<mPg)x_~  b.*|fy`W >t^So9 -}2⁽1$+RQgK'qz]m[4EQ@~n>Fbg_i 4M-Il}ۺ5P:*=R]s^bU;w5[ଡuƿ-*jS'ɺxi{O@f}>#sf>㥄I(or. I~?C V'^:?PɠΣ/ ESXcBdzA5m:[É )$W'Ζ$m_;WuU^EiΦUcytNҜp$ mn;LoQ/>] n'|,  kp0 %6O%2wtGRN2Qj_3>q<.:lyg{eL~0Fz[nOnjGx-zí2! mVt/U _!t? tP+U]DέRLs{ԇgѤz^\Cȝ!Rd|ͺvb*:9Q// Ĭ.&)po5 +NK[]Qȶy\:ĘS)` /Tq­`MZsyQ`<͋BE8 sGd/L@ˋ&UiwRqOX<fjZ8˽!Vٴ}K민qABǙh~૙J1ܹ7vj%պ$kt)Ȯ'ͻ$u 7:6#/ -fڵO.`",~%jTݲwPOQ*qm>zhAX\FҩݿZJk#;ljjx}Pc,uGw5ŝ*;X)yCw nopR5Hk4L֓TAK߶6f.oz].X9x&SM iG(lũcSa7Svq^WEVTf z}io jۉ|Yfʾr4 vW3ߎsfUU=zq]R! ===\pTBHڽs\1YZ2SXdXHΡ>=?CI%{:v͍R5}ǀhGfKhB(ȲL)}f3jxwȠxk֬wBS=sI#OڗזK}Mm/Og ]4BpTAdz }䂅;B >IL86 wBhL%ΩN]e ~܁,kaW-B!/{LՈ;B!/ea LwBFjڄ &8˲&z,B!tsB;UeBhdN_^N !daB3tkyuTB2!BMX#B!4 VL%ΩN!+!BMX#B!4 `B!4;B!B!BMX#B!4 `B!4;B!B!BMX#B!4 `B!4;B!B!BMX#B!4 `B!4;B!B!BMX#B!4 `B!4;B!B!BMX#B!4 `Bc`[<ĩN!1/M`TeJl wRs<뙦cnn.ʥ1,Ct>-2Κ'K?F~蠪j"ys~`dߕ˖-jr.J("ИpGKH9G7$T+K]+Ϧc-4'lR FFVp2B5} }%ǨTV٩f* ЃA%'d6Rl'u,6y3_)Ghֆڨ3>5lplXij)U+=_4Z NxT9召&mճ%oDcQsW_FW ~J-8ۥqNHWR*_JyeTJW?C (F59aF jzõGeU$dd9Jp)-nJnyG\H2xW~σ&Zvg絳BRIo_-++=. XTN7now: ZhBҢe3AY-.8׺œJ@0~v"Xr슶KF-B-jE44oJ*h6_EV.\TDHX;zO?c Eu3  jm9%DnKsA1[ g_9Bo]d[ #jJ^;?޿lRI %QiU15}掕ײFYw4)ņ(aVK&.ʧ>,߬&,?0x؋%Z-{Y^wjOͭn Pr|F"Y~_e`E8vyN4h׊s/;]wyPe퓪t? tP+c-.(]Xd<.7_,I5]-vR6l&d󨽕E)(z~yڤ*5s3ZnY ܹ"L8<p!f(x;Gq7^)=L$EOX͕[VR]/MŴZ]E;3ȁ/칮,*v2+e>^a$tډN\lW 2[P)0Ъg{V0nRy7 x|<o|ͧ]w֕O\7L@dN_^rnߦݒA#U]Yj.9\. ˁUQT SǦ`nD_T9xν+xW/ `:zqaFqĪ4ׁB .`@!t$^۹O}X?),2, $P vU#wQK[RiVuP/i4ӬYWBStlMu!&#B!4 ;B!4 JKSBwB!,B!pG!Bh!Bi wBahË8c>ؿ֬1Q&;pT~g摍z« EM=ɓ8p 5*(߄]ixej{Cch{zΝdӽWw5թ 4aB3qG'D$(B^ m%ϩÆ)SB3!4MRֺh P3u&@~gVҷ% &3ȯŠREؗYS ۹MK߈V)ᅩ߯ VmM*ۿkwEfҷWR8+`&O8vNb[Bj{%#jQٕ}ɥ?:lK;ଫ9˜Fly]K`(dtW`?ճ_k%Zf19FhZ/" +Wt=ҭȪSDC~g@MRKQ8``YR;]bR1OQiBҢe~mb+ZM[ . .(OK&ôkhIyklh0ovI-Z\pu'* JS"g$0 EaF͡yu2Q_W\RtU?T4P+2I}<|9Ppv z2d{]ї|S_*1Ͻ&NH{5X#(_o5'Kp0VڈƩD\cpiyp|y'.w2c7g2&Њ}_㒵YP[lD8>˸^'3m+[ Uޘ IDAT܅2q6ڴ]%J:sbq\rG3nALZ˭(^[3٥~@$V8y;U^a@.p`B.?o.I4@ p.D_T9xν+xW/iV37& 4 vu 7:6#/ ]æ6XMܰ8ul >&Qe\tQ3Ä&ݸCUp0#DO,ٽWV3N0VݗO氻jb@he-Ǻn%-)Ѵk&n!r_is#h^4k֬2!1tւLCmxU;1{+e [eBc.ajnL>7N%2_:h!z3ȗ::`#ǒ@MX#Bnvm{c BS wBMvG֏oDgn@ж t̾Xj!!!X#qr'ͳpREk[%/8{թ-_\nl%x:k֟dB,}6Z꫉Yk$mӓ}W/[:8ɹ@+SXĮPg5/1gk6hc  C=!B"~,Bhb2O*m[j YL>jSIܞ0w6sg'Eǟgu&pZ"hDTqQQB\^or2~=ԧlmɾ& rЦۈ†\~%C N반mk ߸4?x3I9)-sr0wa D+D+jUF3toH؜F[/u>}0C^]/!4 rta N-Qh6F~%Vj.Y{^),Ⱥ|)1&(}1aB3roHDfW%(WN՝/MKZhOpyObϾr2\Rߺ"iyAFԔv~ ٤h̓JIQYJӪck }+ey{9 .ωX_)I+YvoK$P)'# ? b.j(~va@MP7%-42@1M͊Tԙp `qEiFI!f(YK_6HllN<ӼNcRˡH<8ٴџ-o^E]A>b}HZbzjATtO@F vP>t1&ω_??TV9x[7BoMbB )$W'Ζ~0Nqg2&Њy#~v%VZ;^(BU^$ HAn:C0JgJ5&g!4 %1AJ8X-աUVrvU|9X=óhR CQ ìL\ -aO}X~YMriY~h aKnZpՊ([N"IZE$ ph6ɋѮs^2w%sҽ'U٥~@$V8<8K[]Qȶy\yo~{Yj6[rmNcqLȲQ{+ً4SPIUjvgܲ*˹sQGEvqH,t5+Ui]as{z@B $cF `{2)g\c'Le&vU*SSI%ēǙVfc¾[ BRzޝ-4 :߯T޹R͆u]_+TJu]9yq˥!b)[QW/6׏bYG,TʆIivTu]]|gkWd4,Fm6 a+}꼹ug}[5ۜGsyu#=_:4WBֶzX)_\<ݘ枯_lzcʡ̷g|Wпs4[xTgtTSXNʦl P¿>U66w_BR]?9Y/7tvvn۶mqw}1߮R6$嵷6>V&7vz Kx;ױ yq^6[S͝w;3VQ= D{=Xd"Tj3{c-%Se "  " !t\ŞǙY6Ş›}H'ޱozx|"<)e&qw=3潟?KN~4Yq/UTrw>?sΞ+O&kv=в-f8=exBHɾoJ6 !n[[ $3]oM82]W 7Z~[@*֚;=HvA[x|~Nn] >J+^U9S1z؅KǾ9j7w_}|&RTRhLL]gg?7{zebiŻ{Ҿ-L5gk7;p^sBCLo?M#i!Եiakꊹ4;z;[#W.Όu4شemG_Tsn+z/_yt{[5򉊹ǿb6OF|Pϲӿ^2P*~hfB(h#x=3-F^|0~~|[X)@TV$i,VԳj;eazl6dfHՋe6]Qnݲ S{*XqMfo=>mMt 2B(Bu:wC!SBUH6^e[SH[V|Xh tB41|wޕ MZ2UIsf2a|~pLtȌ gbeT{\}TK]Ey!|dk ln+mjχskL23$d3a7F!Ϻb)BDG'^ʩ[W;uR:^{'IV*07-T٪/:\vL%gAy>BU;Fo98aCq;Tf-NהICǾD BRHPLʲ$;MC/~0&TlVV5Benn ?u:n!ܪWB4y߆{R1鴐?X}-gC)!W^:b˛*ڽ;B{fLLi3l=+ܷ}~o !dV ^-Yxav]glB2~F!0Զz"-I2+h?+̞{CƪLP^׽rڡ.K+*]fjڣ-joQ襾BXzluuݓZ|-پ/'sf4azb\,Q Bȕ!fצٶ3Bд|e괪4$+{OcaSRh5i6\ttyچ4̆P*ʬ[;=U?S,Rnj6dN?uw`v׮-5gsi횿4)N7vߛXB<3WW c}ǚV哮x72!+O>W>W?~΅ O?!(+?U;=Wг1MGJi.et4?V  O*xxxӻ׆d?0򋧳δC8uwr6[q5CV,OvI>)ͮ\]|띧o<+~QQV|xw3by., lGp\aYN秺u,8",-y D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@;D@@r=Ŕ[ZZjjjs\$=#NYi ٷp$I/_^(TPXIqrlk`` MӅn{BgprJmllL󞙛 !r+W5R644YBahhyw`ccc=|>Xr\kg_XrjjjJbBP(,dS%|rrrOP(TUU-d+f$Q(BF w`)KT ) `\~ ̞/,h7KNKԲu3^_ܹw#Ґ>liyنʭgՕFz/ nj[6ܷwef5}*WcDj;wp%gU1qnY%|t+J{#f6~mώ|I /[4]?{B;Ilʳդv>{h.dWl |_u^S߯_BH*~ď[>L?ydȴ4[VL?߿~߁%}pI7_jٻw>\԰ѡ4_w7[{xo!̲kn±{g.VNg{6o\S{ű#:ix?{̭woU}˅M7^7ahbxf?RIՙ箛}撪77?M[.'nayn*f[_~g:8>ֳī=9i߼eEg ݻv-rQs&rgl=zϿⱮўԫӳ]sݏ4<>2{8ƽ_'.ݰpHf.bU=|~s6ך+wu7:6eBj3&r!i8}ɣ<|ϞM*\5=2w`9oNͮܺvҴS=ts(U7tLB_W鬐ikh?\83wDtomGm?xn8Rw>:?*/ϾXMBkO竇KkG.ڸu[V?4ikm);?~[*r=U!MP1Z:BnNXϸ†_!$n9!?IU#8y}>cdiui k6>>;B!?q'q ) IH B 8H1}*)$)|2jSYG][we[@yΈwC5[Uo-?~K wq~؜Zv kkfvsI1o|7ov]OM[&r_k~ߟ^hK/x3d;y˯|i/,&hW_/ v{uo21Z(Dr4> *!B ;,4w?^UF@(P|gfÏjP@+ș5fJt>ΉdZCoLeo_(~J}6գ,svYvJ7yƟ*ݷ|]V4xQ?cG-p|w˖~y㦌E{ڙb_&sΧ+/p'r3NI,1ltG!!E6|R>{GvhsĽp@}?:i}{>9 iAܧec(}zL}^{#kSa:<0EugV嶇+` #)<79zhg$ -|gKPKG3FdQ ;S?uob*F!٩y{?>>}X\j7ypA!jtީڞ*#, P>낫B$adF>{lVNj]H2L}=2HyXx嶶AGx3@* s<\ru\A͎x {o5i3_٩oA:rhTB+WqbHt6ko$@p@(!D:֮qoxUk@ٝO5͝O>+w q_o?Ykk;u}G^817צz{xj䕫Trup|q=}뿑ƠL۲NLMfMeõ65Nh Q"i֮2",eY1˲,l[,]!B˥]5I)! Zu w"% );߃I g{͙[W9:0q_eɜef&7!2"˩6*3 cIwƘaKT8B!ri"2&R@@@App nM= 5aM_^RBm:iɭʊ^"SCtgzc3 %SmT*3+K6(JTZB!E;N`Ap.AHxmGz 8n3Cإt ҆P)De s鴢(K+K*!BPNת'ʳe}{}ܜ~Ҝs)j{ܓ G:8#rnvE} Zǽ^oǣϗH$876!BF=)}ܕ jxr&3иR]c5Y~[ R:SOCKGi\8.]5 'w<ճ㦶 d2F"BЩ|L&ӑB!)mNW7l6{ Q!BڟgLa1Ơfw0Y߷daF{WmZxe %fMSSőd|$u]uEQ{H)-2 #'IҝH!B˫3ْ8x"H$WבB!AK*B 7B!B B!B !BwB!VLB!Z0qG!Bh!B@0; B4twEmCMК B谡J}BE;$,7jހ !G.;<N!K6.7<NbMn\z ?K/~`4B{ 288 _Pݮ]nU=u^U*Ov Tev1A@) &㩟r}{jbmy鮰$lqе[">yV<-qi6GdɛaԨǴvǏߣE'J2t+'zwG?zi8vow՜uΑşvTslח5Cy xiک O=/n틌pQm/NE>>CʪG=b9ʕ?Mb<џ;Ko>Eeߕ̞T㔪[epWr/5%4 }ogV]qml<81WOrr'[{[juug&[Kw*@Us&+ba=VVZIh'f&7\ n DnjM_[jޛ#O*`۟/YOrufr5?Nhw,e&S8ʔ\ D~Z/4V,a½\T\F}EˡUSBLǹG@Q]%c,5[}O~E?/?o~m ua^ޙ/O4_rk|(m*m*(Su3\t?1K\+w : O[]٢jeS-ԟSrA*PҼ{/3OO<d8Ag;5M0#X+c]<@O}=rQyhE^fW]9v畝^`F c歫ޓy~4itt]'}͏]Iׅ]{;՟DA\=ɣW{3jxsl6[:HBw?R<᰺bO9 w*",tdU6Lj b%[R]W,wRh%C~:w1azo>B&lϢ &7?6bs(35ʹNTXUpy"{X@RCZWO;M!?y1Ӣ힟cαMݑcŶwVR@Y$Dx5~vf,QP+.rQ@ǾeI-̨Bk?3W>Q\[\f?>䗌j ںd:< ]2B?UJ|uRA(B%XG:BԜRfT P~d>B5*AzS7iџ R.C.tyEQFIVajlfcgJV4yڵyV5۝s-knqw}۱$ T(A$9O\f # M)SC0IlUV \`>y|1I܂`$ٗ @f3*0z ^J'sL6/GX&t`ĢDL+U[*}_i:^쬮9*-VX (@q OՆ"Tr~i( IDATj Q=[!tId/h˷YH1|/~Dy}^SdeUwcML{xVxuK(M2y~QeQx\H'ڛyk ʞ_1ŏ֛>S81%Lzj1oS;S8{+纒k&M-auO5wj5\);$H8Z8Ө2%z|uhjU2Ve^QyC-f"6I$@DO1sZU~B˜,<P0MMq$h]UojA}FFD<\Qݴ/E<f dZMꝯ]WSٖ4}xi.Uno.io4^ _"󄎹L.FCJ Yr!dxcsWo}Qu~nom|FiCIwTy__ ?9m(P|FjI5Ij@b{HK/XqĘȫE(F!ٝ⹗YQ^iVpLkS\YTM KY|ǔL3f{/{だzvNxyd1ba}OiRZ۾X O8'KUnMqe$*GI֙*zi* Ye=ϵ-͓2jWȚ$"5s]c-ۍו^r9=sS fO{{1YկX-Oy$eXe٤U9 i(:?ԫNR6oqAFD%#lmهtWM?{! 53)M@Dm]'#JsS&Yp/|NgGu>3;Vse Ǚ:<" G [_bNZޱ'j5ŸiU |@+$~v> ?Y-u-ξɧe@PK{/+:>g 7qgk/^B/wuW\ NM==8i2Rwt[s%Sސ.{Ĭ(Q AQ sjܡZ>g);qF BVZޞ3KP:'BC?,i-x}5VY\oAuZTh cY *CYԥߨ]hsg8<,vB!B+&!t8v:`B%LBp;B!B+&!B#B!`B! ;B!B+&!B#B!`B! ;B!B+&!B#B!`B! ;B!B+&!B#B!`B! ;B!B+&!B#B!`Quc1rǁB!thPy]]gEȄ)K0Nf6f"&bQ4=&jgS#Ma*ñٲ^yb&1_( F! #ScL!`'~G\l/!4Sm{@?Bz[MB!B;e?(?qiOb~]:HrH5./ǫj76M󖓟NLCئ|-{8%%%ߗ(c0g5shUt؏ڔobgY{d4&oo-0VFB!^;?>=|KA- g\:ܻׄr(y<}Kq'%2gS*.zKm'g_tܞm4gJPkҼ|Zo,;*(Fxړ.0aw\@&Nvŷ޿;7y-I=_=иVo̾Jy4Cbp7r}X+}\ 5!,,vQPսwOG(IЮU?uB$?Ɣ\qlEժr"eq_P۫bOR:7yY4 osZAgG2t>BFNNޮ*qWWNܪV^f8.M?aIA:&A!IV 0hf1>{8Bi^MTʽӛdv?YɼLd&z ZGj9msO%9zk]Dxz_4XSyZ*|8w29_Z |!HQhe7LM:?v=jtת_;Zl;QǔD.LUŒ̕sfd?:6v1[rWsþu䙁ϭq$jIcKϪ/,P:.sT]&w!B0ȘٮR$=ݦ$܌P5[3". n!ZN ge.RΝn2Pn̛ 䜄So K/CWnWWd8[0o׿%ϕZX8~[Ifi rMxh**k@~[:s+/-Vd\ⰺ-ٲfۉWݦ r,Y1mʾbEW,lȗL'C" +ot;_2}Swן !B25U\|%&Ad 3,3( Iud g8yI|;IA2+3cW#zp~Q P;WU1'F]W4P|d|3 g]۹>U}`X(xlȥ7 _zo dHeg|znqL[,8͐XyYQSf\%f%7L]U !BG)ye~7J$oLؤ&>5Zy"g'9#׶l}/@<ra;>v }׿|T* 2 /|әH[ܹ-T79]|abo|I])|c^o,>7Fe[ >"?qDyuC-^%%8S6Dyޑ5d;kj\\o8|UYT2tr_p3b"cZkqB![@IIF$B(unS+*t @/=ޛW[D/,IIVhsl4] )B8'Ψ?]t{e.nWp^vZU-J'Pҫ*2˷sO^{u]^c//^VڲMJEJmƉ97:=Ro5Fumg%+i`dQm,Gz;Gt9{nSRtcN/;>z#B'R;|RrDX.RU5rmz슂[W@)+\0u;=f1 Wakʼnz+@}&:u03٦|A/drIN%?^&L=|mp ]2-|8"ofnw6dtKh!fk UR$@TPQe/^o]vifue\Z4_۪Q wL!PMn*sNWB;d/dS5= 6j}`|\I']{ɳ@Dm]!BE uY{Md_DѡF)O`yxzq`@!1wy|J4!B!;x?NB!V͋>z@!BGB!Z0qG!Bh!BwB!V^ЕT9Ōv-y }{h膝;;[:B!ZS1$S܁F;:KxS4f{CЃ[R;tGO_`5ICXPZ;t#B!^ܦ$Ť۬%>㪨l]D{ >Yj+%!Eb!8"B萰:hoNpp2s)ն? 8Kr"eq_P۫3T\N_ O^bIu}3J񦠄}cۉm92\J_cJ86?jU<_vxmY󏴚 V&/Kd\X]q6/E;kv=a=)6+}\ 5xٔӔ<2=zepȞv[/e\eE>@zzy*◽+AI']Ie/Uiq\yB!tMܥV:P8K*|p,{sV{FN+a_nd@ָR'Kx?5lxU˖>y62rRiwA͔˔ɖۥM9^(==phFccU?)(܉ށ/GT.*v΃ZM CRn: bZSe_t~+'xDʱ  >bűxgTʁGVUOJϓŚ{^I{Ihx g.m.Ɓd]-,#Bu¾sg?&W^4vItL\sgT)L p"A `;>0rc¡?;Övۛr^VTK2 S *\RiҺŕo[MmhFʌ2]滶8|m.1_I |zfed;c~AHNOyKōf"[b+BNh5.J\'ϒ @,"!ʶ@l?|D~⪱ꞇh͊+L7,'@}s✱ȘVZ#(߮ŕoWs#~s*ڵK+>7 lVܽ#kfqYy<9 >}ŝ/1g˦/20 u!ɼcB!tpxj O*GMWe# TlQwyGRt# ECFt9{nSRtQkzX2g(3\Y|S?qڵKIIF$bt<͏K[Cr U1 _ǯIMd=Yɾ=,[&'ΨabBj9Y*&LZN yh*΍:] qMB'a^ν\Pc{)D%6$_K|2n%XH4P}vrwL!PMnFd9F++pW9e?,6[GDMiyMYjP*{`?'r\x`=˲'jOTPQe/^VeSo3/=[]jy^]x(зo?$ns߈Q[W}+bKBdxxZ0=V<{*<8ι&<՞wukdžNs~ů8:8uw]Q ;8Ex͗1|Y;뫖@*3NB!Rtf-xɎ^6满m4_L|DooX&B!СÈ>zXま:PPv Be;:v|G޻ GB!`⎖9]6B!TB!VLB!Z0qG(]_̘!Bmo0= =xSػalE`!M4vS,i({"MniϦ6KGTc7z5e6HLjcC@FJǘB0ǣO6/.?HB3U۶d/ ĉB!2qgǻop2.OL/v8:~WgONTEUxVa[c`rӉ3w۔_>1za|lfչZ\l/ko,fnc:Z`ߍ B5w~|z=J/j[2ӹtwW% !P(x. }m-NJd*T]=×"Nܿr)=hϔ'֤yXvdUmD GSjOtY)+sK8zJ$y|Lasd.o Jh\7f\g{>.pZd(|f޻# $hת:!\J_cJ86?jUW]Ś7bunti@@:}v$A3!zj$4ڡw5}je@Ҕ}Ԭj tnjEA Jk1#z6Oմ|Oܫ9kJl/㐞{k Df"r5z[vʟ8]y EE9~)y)Łb_ ~$Ф3os*ѫF'qEͶuL1{LIdd)ݡ=\}\%\(==phFccU? a_nd@ָrvZMb@u3*@ N#ے-o{Um@)J̢Ʃ+z\[t(;xɆ|yD}=*T  Ho~M]^G&BTrkVb(̰̠02$խ^gN+%$?VɬRΈKB_6ÕG5@_)WU4s͏v ^@9Q/fxvq.6oTaa#86|-S"F7Rf _Ko9yok,b3_o<4C>N`eEN՛Qbc\ CQ*fistBi 2?xD%̷Hx lR<ųk[ 6ݾؗ| wd9d0;f>FR PDxŗhL-.>O갉s7_Xsrj7CnC-jl硖W[SVʩOe}U"ʪ,jH^aa9J/L8c|}1B15\}gk{4HRjDQ&R/@T5BUڦ4h\$"Wh `bX Ɨݵ;3s`k`~?׭,*VGV*YykYc[omm#_\sеpRYug)B~-}SdhK[h /B/vocCs+)u6~sXwG3ZX.Tn.]WWNjϿ:__杷::zYU4{OBk'߱^J)n+K7[cZN)81qơotVt=SL);~|l.Bo`ozKywO|],u>ߨi'MvڍZwoJ/i^Şi}xSXyzyJ]ZyXywGߙu^OzOfs᭝sxx;Obv'#WK{6]O1Oi{ˋozߵ_xRZIY24q%S+wl?rdgWyȝ~{}V٣N)fC=4~KMut /n./wLa||o^{w0[gh`ך_Mfq'_;v譣gr8kckUp{ァ;BG?*؜cw%#]?q^Kl8  w@@p;  w@@p;  w@@p;  w@@p;  w@@p;  w@@p;  w@@p;  w@@p;  w@@p;  w@@p;  w@@p;  w@@p;  w@@p;  w@@p;  w@@p;  w@@p;  w@@p;  w@@p;  w@@p;  w@@p;  w@@p;  w@@p;  w@@pJ)wu9vיRJie=v㣷+5O-%}w@@g۞'^_kas/k[y|d{]d?|e?z%jaк=ġp.=uw⮔R[T =\1O)wtkBx>4>gh]q.~OwDq_bV_9I~W6N,4y{eySttԷ_p ݇nyRurZ9ؓ--SWf?<}qȎC lzծv^c+/yqvϏ[l!e?/SJώ? +R|og=]'|GQ/_;XcyckV =>ܡRVλ+r,C Gd]fiM?7JǮ:e 4\_Zm 3<{l4xyauNJpY?'fiR~ YJ)K]{xwv8vvDQHIߪ]'FJ=g o^j!obRJ=?ӗho[p^*#W^ܷ],b%zZqaagힹLʆj!-橵#W]q^~׻tkvuyt[doeIϖ ?m:Sգ4}a{g7た7Z+TdxJ)TjS* ȋ/M~H}pCmSW W7U'Ts|ah8}9kVjwϧ./TGw穑R:q0۹m_z^,jTk삓?W󞅥={f\C/z(5*?s౟ZZx)I)Gjo;-L5t+ ,TT.y;9˝|SSS3<ƻ6R$8 !( A)HpJACP R$8/wh\RrjU.sdpM/3m$:/Կ 5OXaŴQr=j]8sUA}X.ۋ-vZVӖEVU*5eI%dByg\l\;k}<.޲nk휿;I9בlMyZW`_LO妡gW<*)%)]U ^xޡkM,`D6po+VN>a Cz~- n]\ur1صg3cÞUW32z[yx,:oc2zVξcc#g:q N8zFp?m1\hl"xUb^hPV|Lq-ًnbD _잣?q`ɕgf>~a)89ۜ:J md7i}"}mJhGIJ z?)ki5Nj}dҴiGnfCg@VfG9`>}hfW5ƃN^'k3O_MÛu¤g̟4Zw%0 V:6}r5L xPͱEu矱+741"gdᖻo[jddx3Z23z sFvݽ,f~eCM{@dp!!Fƃ9ש%ύrx+.vW:z| gO痜W[$pރ>'֋j*]O[fII+gbJB c.YxAl?;QreA 9EQlEU97ʹO[W̼ Gۛ Q]lJt8^Tʌ{ޝ9XOgBkpl|JAuGOk6Mb332&' r8Y? g*LIol=%x[X98U N \l3FS++5a2 +*#S2ذX Aծ*.OJm+/5 誂2c/഍q r3zboCCw:]p*1e%,C3bJ=sJI U@$cPwCx^.yT__ס-dGo6fMl 29e_hCLa MYo#~ 32Y'Cw~n|8ɮo .ҭQYd}EQ0kkjkH*3՚)}f ^ +c99lJ+(PXTxh dt]XC $R\(gb EMv&ޫmzrfvvZFts;2#K>.҅3Fj)iU=W55t62[LB=況z#R숍 Rj:Ff4;p%Wa1sQ225Ξ?V\"V7+Y}Ck+ [̷z4ڳRn_Ks3׽s/mV *y_pˎQw|wg^٭QgOV\`1aSǠ O&PCmWuL1CW ]vEߥ": \J|@_xZ!9{oP}1# ސՕ6/%USF7Xo` k8_R$84ZeeeWǀmzF8 !( A)HpJACP R~'u+ h?e7Ħs[1Q 8v5| )_;sCPo"0c;/G39uwN.wÆH«9nd/<. hrcǨmkS*&wޫOBq1!wMS |刳nbH&C$6ߤ&޼>kO?p;j8gj={VJrJHII\.UݟGdž?fc(Ƽ i.KsQKjKmV e2fx5_J4-vM9`"$V˝U=6NW۝S~M26F u+]I}|VcܵJUOw^MhZq=6(%{ؼyW^+" ;3w htOr03.G|]!}aOʽh9鎋A؀L Ke-4 PxS/A/:֔K_n,7TCW& Xmp=Yo}QJʂ\Rɒ\1ex ND&?\o9MvهtXa8iXk8Vzrj\k]KHhgDldk8 SSd4T1 MOoA#lhp #t F] έbRTGX?km|B] _YUa\$d.\6 E]-8vCY֛钢t;\iS&x{akWY#'..7x ó i\&@q =E% ZZ"8=cֶP?{5iT{0ImKH(Ys|w;IUDOBv]~, 8|ߦ]*F?_l>23 ׅ0S wZ^v {6%ԗwY}!ZXw7#=|RP*I{tUm|U_)A 1M'^V|BzmX]nidwߨsAn]`ۚww'.ew&__$85Ak8D$8 !( A)HpJACP R$8 !(zs ?M@(.@;}]M'1B^׆Ձ,=4V o1?#Mxd2{'Nn8\vOFn HdSvoQ7OĔMx6}'khјCO2ͨp P4x`A1 Mst!ga}Lm1^ &+xF#G%LrcMdx]3*& JmY[|_+  {;C:t" i#3gMWd.:jm%IRxy6fgP`:ukh]t$@VfG9o"͕'_p9u&kjE4E2~K{䦭sR[3vE&4ֆMGYx$IFPQ225Ξ?˲_84fey 1gڊ2r|,f.GU.׈k Da 5t62[LB=*CUKPo:WEӧWv+6{w,W+α F?zsTقũ~\ (/}AH'$85Ak8D$8 !( A)HpJACP R$8 !(+5OinoWg@Wf*)U~xtv{jGt#. '6I+&{k }n`Jqtum'$>w#L̽W2bB9yWeڞ|B0_C&OnD0}1Q* QϬs>L|㎼Jߔ@ [`%`F<ӛhUέk!UiZ= o10n]WNs%#!mz2(Zwf{jҊi84er_z>K Z28kl~Iqfyq#ҡsu c@S>tL.C2_f ..!,f^ |gB\􍌋,!HzyaGoOM.i-)tZhF3㡫oӧЊ c"'v6^&ƾ bۻ p֮S7ߐs;/<yUנ xU|ìmMz) ^J (3D~Bsݗ]~M=DuyML,MWjz]<@aq|^f"8#$Vֻ54'[tpou|jMi,h, 촻֍aӻ+ֵ8~wE Ct:h 2$8 !(܇A)nA ~ M$8 !( A)HpJACP_$Ĭq ø,67^Rk}۱Lv 5#Yj\N\x5Ǎ=~K\}]`u;%[j?=l+T%f9%$Y.Ocß^1m:Y/0``F<#ђ{@ x*"7m뜦̂Qc0,v[Akub~ ,\Y,u&TgΑ3Qڿ3vd("Ѹ'F[YBr- ОQ)^)yK}x{5q=PCMz#Q E=lOOslئe lLߌuUH_+/Qomߦ%*ۖB8rlZ%Mn,hU0NzYo ɭ"%:kf+CP +5 wΗe7!fԎїl6N-j:ݮVpq)f{(7Xj_,]ިLq/ߠfԎ r|)zW@*hi@^R1!˶hɈI(]uOਤ Vu)WܮlhZ3 j;+eq޹wLd44$)CWҚ ?z?naW@OEnq/RP=A. A)HpJACP R$8 !('!(pJAIN'! $8 !( A)HpJACPJ\s#n]ȤTvL%,FY?GWBQ"ty8#Ymf#`(R d+"۽~m7 yxkލ i.^LJ #^D0X[CZWxx0Λ.ϯ`qV7 wujŕr{*^E7@Ue^ 9 f$$D4oȻ/̴K54_ Lp첼Ԕ/|hmڱO.ѿc4lهK7-1haizñ'sKFKc0vۼrJ ɪ*iYt#,-~Au~ǁ;_Y{:afVL?u,U}2JW0cJT^.&~THkį.RƓeh,l&Ϟtf?tP>Mzz!mSg^RXEAb࿛Nӫvsq¿)݊eVk W_y2jϯ^]rRiA4wY}E4'!:䞄2$8 !( A)HpJACP R$8 !( A)HpJACPJW Qώ$ ?ٕ;+GetSԴNtmypM:6.etyE#oN4`<7[73hlrD[N^q6Od8Ce$583yd2N_hhӦ$wZx!:I&ZD=EZSU&1.mGMIݍݖ<0̊BKߝnk>b%6"OӝWNsA2b:-?Kwş߰KO^Bj;EAtHpJACP R$8 !( A)4~onNC : 4!(VYY1 pDEEA)HpJACP R?MpWi=*$u,c+#JeVt{R7IF< :DW'i 1q~x{ .y3<@GيhpY*mЄ_{;~%"o;\bKL>N9gaB #p^g\_Vh'VKlL2OVNM EÅPRk]eey 1gڊ2r|dw64ђPj X?񌖚kj\Oa~SVh)^ 9~Z=햗1nX=ʨ曫m6h+*Lw8r3 K7]z(:$Wbܶ$~`GyRs}nFtڀ폯ʞv VDTK :[nero}_%Vm_7)/Zv*09{v/b[w< MZ!:CtHpJACP R$8 !( A)HpJACP R~s{P'!:` ᱉qAWmgu(c[Dt_?xAc=䵆JhBPݡW;%DUP0 ޸{:~ѶKCSnZJ +2Ph O3l0aܟG%$Gy^Z;褣gfHXKJIhZuֵFoנ8Fי%o>}Էwap48:>65CYx}7⣃/h<,=v/(&}n`yU'u9d g`É=;~qm躣f^7{Yw}O ʸ4SNZQֺд,[lh[-Od1Eds|w~ ,\Y,uݭ{a+#,V&0Q}61ћ8{Ǔ^ LSC3;eف;InRR޳?ŅkKKK ңz|SuΟ9~+37u_@ߩAii JʽZSnuN+xr>܀19u'!7 dFáCNKg^y T -`]ŃDKLH| n#P䈔bff7>../9n&-ls&tǹۏm"ƙ2=-a"*0.n2Xl1s&\xl@tsso5JքiVnZ>m9X׺7F",vIo0LӮoϚO0^w¬RZC 6,VI86[r2\`QOS&ZIT\5xx~uuhF)6[^67{ܡ\l6pAn#cn&BMg`ە*6..%{ }UMNQX!9 }H:_pdNIxuR!>FMGbei8̢sN`eIaaY<Y{ -"&&D6q:fka+ Dp zj/T=S6mSoi1aK1mڠ̂,)p7{ fU~Ȉ#.ln*3^^w8΄S;a7tFyN" $8 !( A)HpJACP R$8 !( A)HpJACP R =.<9%%%%MB+_:9|?+FJ=F MlfqlXpPNOsEYe:xQ``0^^cInWLdңc^z4Q ق G-K|yDox&ļ8l' Z"&uvؙGo6Xn9i7x:pz6bp/,v4;p|s[7OA(,8}iU} L6\+sp:T u[4qZW|rS|@OE233fm|M{(s[NF) ~?wN,MӡVpO/e&тDYK'8r/) <"nd0PEӄ]UPf$M[)/CN.ŏW^x[> @b2= p9E<ݥ&=5%s-GH1YphW2T+#1(;!N.ʁa_g-`8VdnDW}> ,ͷVs5EgL3񦤞6%ц>O79ixN%TC!snM0KT%g k41|TYoS_de+JW0?7G~e> `§=ޔ_/IaĜE*~!dzsވ<'?PsEoc/߷v \oDJ1[JVMl&Ou4Jvu1۳jɮUn_>Q225Ξ?<;RI`W^m8QYLXBm?&ss_+ ;wy-޿?/+r<-ꈏ;ユrG,񥕽W .'>ރ5_Ѓ{b^٭QgOV\?2q|@= EЕvFG}Qc@p>gA/7O\}S?+o{4\z#H7W.[_TWt4څ^e6l1 uGK_\@VKNvn(/)/!O['pN]R$8:_Bcc@pJACP R$8t_abG4[ {;%GT4eCw)6X37F[l>0b@[= ɶOLg:v}2]sEvmH>W~:RG]_@W ݸN}-k]Q埽-ۭ1BsaݞCEOGUW`}u݋6"2w݃Rbg)U__9 wZ(mPƓnqsR\v{~BH"J~~}fP_q/x' ptPxSViOQ9Ij%6?q T 1U;9,-v¡1ڿ\~ǂvI~ɪtlDv-Q_յ1zJj8ob+R' PP?26*2P<6EFe(Y FWi0"״"\"6S؃QK3,2>!m'?V\+S{S*ɬix̊ϭ!w$W5.Ʉ*0>:lNoq_IXWP}U*Ghb}xV_q\VKb4 /8git M*7&,FZL_K]R[ \f47 ,&0V?[>!8L̢:)9Ϣ 38LQqkr/ LАk44թlL]YP(\Jm% q5QXTSՓO)!ʫCeUxd5+kP -}TBOWMJ`8ũ콻?@]K$k]В92 .~G% ?齰WҊ=*{X Iai C+}15y:0rhPg2^f3uaf2?ym yQX1D^iY^ʼn٦&#ԑ9.XkCmFܛ8jld͔~h-_WܫR?;W*3X C#~d`&+y7nP0E`wf[ʼGsC A)]}]}t.AhCP R$8vtu ?w +a캮A~DB ~4F8uc$O˯}kIo⧫{8xoiBhWS =9H6xch]}ӿG"/ c$8'.|]7niWOϪ+].}ݞTPH=9LZpp9\\A/ٓ,xulW@W[dEq^nnNfjg,`ߚA@nmOoZ\~m24bHN /Žnme8',6ubH ? Zzxl\K&p5.+xF#G :|t.q8o/) &6q&%3NN?w8-soq~~bLW|J\uKқAad7:㉓نHs:1[r @pP$]By7MZhH_ozW#6U-43pDiP4;Fo5ۿj o;Dy3 6dZ65dLUԑ}homVǃ:o-8p+>\9uW}yyQKN]4]ɱC1Y̼9t\ H 9Do8<ϛa#G+K ґM}03N/)}n[quu/:D5]80KA)y̬{>=f`zYRYL\ ٙyجCw)L`zQ)3yw c=i'bMgvnbbIo@ͳh>UFb( C ^;̔:YYQ _NlQ225Ξ?V-(RRfz\{o<۪Not0L@}Bh4ߢ*Xi/^UYVxB[sYsg ϧ+OqW])p^}Շxcv@E5m`}^cwVP?[j$2"=OPEZWǀÑ^"$8 !( A)HpJACP R??Wǀ@#Rh@M$8 !( A)HpJACPo&81{،8? S52*>1>*|mM=;]姵B²QoKgmxx\B @DFES?1jĭV9׹":N^4޺xswrf``0^^c@pq2P`CdJJ髛?ֵ֟m'w qfhd{&̄-c\O-n=pD#0%T~֍ +yIDATf 4رs[ L^F, 2?m^7f}Lwωv Dx7vFϘ=.ܹw+V-V-IVEvTk[.Yc9-}f-x5683so<ڣ%$3I:{VT63714ܔG>1! csc 2J ^<0a_~.on= WRMLj+=52v>s9baG9vT'=v{jyq J|roqե: h= eUDuiMte&Az(W&"hoIJH`@xWOۇ]UmKVi+ʹMZl?#SWMGEp햓#^T\oDJ1[JVMl&惆$U=~Oa>^X]BXTqM8^ :k@OE~KK~ 7=xc\](wO„M/-O7t2.$ ] +*,BcYO\4&k׾ (blѨ?Kn݂?QpdU'V+HUlCt9ѭ@CP R$8 !( A)HpJACP RlWǀ57@Pi܆C IENDB`deepin-terminal-5.9.51+dfsg/src/assets/deepin-terminal/terminal/en_US/fig/workspace.png000066400000000000000000000411521475472654300310760ustar00rootroot00000000000000PNG  IHDRq pHYs+ IDATxwxTU߽3 PBHGPPD@Eu+kokUtko uAp" JC 1B!|?O9L9skÆ `#55>w;` 0|A8N|>_FFF^^^AA8=˲l z+~ZSoR8}y?ĝBU<wiXiCk%}amذh^r;زJ-u݌={x<˲<m*8~?.UV;[r_Ms__^ɒŭu%rŸ`ynJzh=RRSS+>ՑleG V}yWG-Oll m+q$9>9~9>9r㗿PSqoxH#GiQYu]veddDDDP8Flܺ~] UVkg9 qX<$6?{UZ |%>NA|7#n^xߕxuJ+ו JtdeΜ{tWDFFFFFFTTDEEnumY)9 q<F#iXpj♬gxl)*\+fHx-?܋gegʀGym۶,Uq<nuիW?oR^qױsC>pj:|w]`Gsܶ8x_W_m$8؎[4s-Zr#`kG1//538!l+ϖ:'eR}TwJh)w'IG_k[=p[Nr +У8Rmg{x8?O1 b{6-9B^f/זF>3쏧8n]T% ӔO#ǕSFvp@h8;N۶\B ^_+ʕ-ۚœ0-b//pZSSNX.Ǒ0mwޢ1ÇGk\(x˖JE538vw>9~o_c2YYz9 ,;t]7;?yya-+ㄌPWِir߮އ\?zbO㓿P’:{h{1+޺f?vdشf i_-tsu7<VnЩ&E.jhNC,ˊ^9r_6 (,U PWr;x"Hr1}ֹs/q8e|m&pwݑTqOr(;gOm]W}U?yf9D+8)ݷg&0qr{fdm`ukU+.]/lOSa<{WR}{|>m[^[U_tٺvmf&-5g _㱳l9~d>FgmjC隆J_ײ%I!z5XUGu=VQzBvّm&ş6o 3}y@Őw?uoA ]w]0znmy]7o믓^|/x|iŃ9$z~w]sE W='Yƽ4 [zs$ٯ[uͣ7N*iƷ -Inƒ/L~iK/E΃tt4$ hG1ʹG[ջɊa5G{h`]Yޑ%~YUH[9w跡Y*OojΛS%\oQ35ֈT6SBMF%CZMR7Dnо{o_O_]-w*vXY2H#2ӥdU?-*UCW'>>S]NY[^LsNg}/853%~WYo_ɏk^5gff3{w]뾪mϾ7^g\?F\gz_4t@^DžcZ9MގYcoEjk};>J|ηi[6ztx[vu㐫ɤG}knGV\sΊE{Tka esq6;K~X}D99>^_&?yhܬg go_~Cte=r0 6矷`]T>C[;ʕc|BؒY? ܣC*8qw*{O{L(k}OIW'rGw?2qK VzoI+nm-uWNz/;zgOq~nHFmVm 9~ןsIc$wYsuo!;_Uv-kYŏNhUN3?^P};/^=#iĠONl5E5u%g錤KΠna?ߐEW-9oٴyUl:W߼~!|SwT_ѹo-m|is^-YCg]rOn9Wz8zWHݟ#IWkW{Wr>^$u_'%WtzZV%ipwFY2Ghb]wYEoT& ղ5˕,?To5>OwWm&M[EJebZ'zc$US]YڜeO$%h j^#5뱾J(Դ>\}7螽edڭ[lɣ%5.,˧ũv]zs䗺>իHw?9JLcܯ e[G<le!,1H+]W_d$o[T=tsை%+r_2 I:vO=2co#uܕnqV8KRd7uZMBRuULv?_j9$۰%ؒdEk<$sю]9bK6۱GRaw/mҭʟZoxd][Zi{]wQ㦡rӗ͟xUff]S$O [ݤHyg;C^?KBp*2FQOziKGt[ȁghVZ~ak{gMfm۫]:U,9ycy;?7oj; _n&v»Ψ7<M[_cf ireHҝl[ݮ&WS`Kb餑tqm}̑t}HRNS۪-&TIJn[k 3_-E$ KK %0W9"j"NVjF3Z(ү++IOTrEhkZFyکi-E!f]ϴӠ62G͜Uů%;uI լr}&0VGUbնjj=[&+,'uu=MI!z^FTbsutV[떞sHIw]w>v:Guvrɹ$h2tf{&$E{ }%'wIku?ghӺ歙;c_~=y,7c/?-Z[mɟ_P(I۰277i:vF-cf^ͧ!e'a%7cӚa-H*XpiUlIήT ׉ F=/_}DvaK4WN~y W,X \Qm%ZG୛,Y,u30# :nϑ{?ꛢr7[O /}%+&j }݄tdExdf+ŊrsjVͫ|}V48㲷/odK>[?:UkD:*ت?t~ 5*^,"-Vr,G+7˯e;5ՐfIRGԲ=/IWvQb^\ݒ̎>溑;vVTRWmtiXڵ[ƞqح6="D+W]ز>fJя>}r]0p"9(T VN|xQ8=56riU)da=ȇކnݥvrivgtԟٿ\ոźz(w+#ɣ'.T[KӃYYz5_VZҾjUM ;](WQ\8y@;6TK3!ɫu6=}X+U Uc[?JIjX MA6VJ\VZH҂'j^l/ո{5{Em|18\g|栥^)_YP9>*=_|j,y|c;lša_M*’X2j]kVsb;'L^5B$9˾CA~հj#rSvղjk?;t._?1EZ1 =~"E=HeݎLoR˕׬\v.',tҗ {\ݹ-ɗӤIk| l\soRї|s{o㭸R;#p2WO}gܖ^w]1O_=gv_ο *O[iDrSQ$EF~Lm*fDj2]Z[ԨX I*خ[m͒$^;5SR3dI ']="]G_:Ls8Bm'K%C~^tzJnA5ݏ\ߦ1 kg@w|{]nv[ՙ>ѳm/Vo~1 'ݼmk8[}9mjV{SJ|X]u߳{{#lէs+~^ݚ%m Ґڧ+ dWVWWrrp×Jj_9`B;[5z|1PQzK}5ry|^рUgS.ƻuT IDAT1gi&=1fjŚ|ݨk袋Tk*@d=0KmWuim#izlo#;&zoNm)jG*sH^=0DB֧StC#PV?Eѱen${Vݏ{s*Pz߫w̾+8.*W`O:sg >nѼI8.I=8I5*^mW;G^1韏Kiٻǹ/oG/Li7}8?n.\xΕ 7yiDžq=,dp]7]S]<;;nb=:_ y_Nô)_{w=Y61dExϿa+.<|s֋%na̯rnSgqbtUM+>"S:@J٤GTH%?E:ꎎjB\]W[ه-тnG?Է3EcJ}E`zaU`R>U-ջ6mӔo]rkVզz{=u>%j~ OVDu=zYsRԴ~LQ+NxM—<;mxt|GK~K jH6lؐT /|bIdZ6*3,_Ih{q}{:#DFF~roKȸ&Wf.ۦ^}#Z'N |MxqBzf`ʝ>v#&''I&z Kчݬj5ТR58Qܧ&>;!T|Ћiu#|y8v#7+r\7dDy}v%ik`}^YSlY,[-MdͯZw8Vt]%GųEkin[E-Z*Y?SoL|W],q%G^>9vVlŴg#xCg|@&ujՊߛ{ήv2au%nd8S?>Bl ѳts7%JS~v?g-յ?Go)ZUz:zWW8ȥtR^+ǝ%˖ܢ4v㙱qM2V|׉ Zw85Urr%Ɋ(w//8UTj>WJ^39ϝwYi*cdO|aOLd/zK%4jмUk5#)3f~m*؍l&qBBX*ջ*!QuQxNzlQW#D .:jKi^9`GPph.{_p[_9WklU O8ի^-EsZVyygqԭyJNӄ;Je+Oce=J>pjM~qo_`v/xrGBD6躉GivvmBBBݯ~aaaZjR ͭǑDN<Ӈ#)(55,+v*uTd`z`QMM7evBFDD~SFDDg6-\\ (?_+:GtSSEx<ݼգwKJaVZOr8cxŸSfVmߝPQ~>t'Էn.U3FF}x!{wP'K_Mٱ2#/ެnl? 6{{~U_FuJnh$YeK޶xl'>gvNf;X}qM%ZN=<7&4JUΛ7ᷩ[Ó=i+o9Ysزf/=WL;sŔ[;{WOuvȫq!.8U-t$67=fxa%OX|\:JxhNsͻaNAIU%/d]/$T3~ pg kޤeYMyzs/ʓӕ]{gnQz;|{34 uɰ}| 0g9{ mDz,-_:,iBC`u 6оʋ_<4Ց>Mp]IhMըy>$KlXhD@ԅ޺zc"ը?y驎$ܥ+VmRzmc#U[%o- (ת~YNU%N u{wJBf;,IvUXQ+4ogN= ~\︾W7+sy\#קg[Uۄ'uֳ˷xwo6u ܲJ̡eY J|,,[G'T{n! ,eYm'-;>S֣t>뉎f-nHq#8Suxے׬eNH{@,#_|k;Gz-8>!cdƣǾlʨhHt[vLkXKx9]bDE6̽KT"Vߝf5~/EAub$Ʒ URt1[!5]+tfmթ,y@`ŗo ,ߞHjvF_߉#=.k]vӿwj{Vƭտ8ֿjS d{=V- vbU͖]Jd8SZ#i~|m}˷;o`z+:eOR[:&#}Ŗ+g~72F uB2{G%E{[dϼۥKs[Mߴ{ϽuKېΡ3`rX-ɓO)[:vgMWm[>5٘y6BkV7SrO{hi=yqfs1&ͪ7ڻ4fO=0+왕K07Tҷs¨-g)߯'{ϖɣ{~1tK 6$&&/ެy>5*;x@w?/K{c٦SǝD{xR<*FFFS999W8vyn|Wg%FTb#J=]iVT‡2a  Nr]>L ![notes](../common/notes.svg) Notes: You can also press **Ctrl** + **Alt** + **T** to open Terminal. ### Exit Terminal 1. On the Terminal interface, click ![close_icon](../common/close_icon.svg) to exit. 2. Right-click ![deepin_terminal](../common/deepin_terminal.svg) in the Dock and select **Close All** to exit. 3. On the Terminal interface, click ![icon_menu](../common/icon_menu.svg) to select **Exit**. > ![notes](../common/notes.svg)Notes: A prompt will display when programs are still running in Terminal to avoid your data loss. ### View Shortcuts On the Terminal interface, press **Ctrl + Shift + ?** to view shortcuts. Proficiency in shortcuts will greatly improve your efficiency. ![1|shortcuts](fig/hotkey.png) ## Basic Operations You can right-click on the Terminal interface for daily operations. ![1|rightclick](fig/rightclick.png) ### Find You can use **Find** function to quickly search contents in terminal. 1. Right-click on the Terminal interface to select **Find** or click the **Ctrl** + **Alt** + **F** key on the keyboard. 2. Type the word in the search box. 3. Press the **Enter** key on the keyboard and the search results will be highlighted. 4. Press **Esc** on keyboard or click any blank area on the Terminal interface to hide search. > ![tips](../common/tips.svg)Tips: Press **Enter** to search down from the current location. You can also search by clicking ![up](../common/up.svg) and ![down](../common/down.svg) on the interface. ### Web Search You can use browser in Terminal for quick and convenient web search against selected content on the Terminal interface. 1. On the Terminal interface, select the content you want to search. 2. Right-click to select **Search**. 3. Select a search website. 4. Your browser will pop up and start searching based on the content selected on the Terminal interface. ### Copy/Paste - Copy - On the Terminal interface, select the content you want to copy and press **Ctrl** + **Shift** + **C**. - On the Terminal interface, select the content you want to copy, right-click and select **Copy**. - Paste - On the Terminal interface, press **Ctrl** + **Shift** + **V**. - On the Terminal interface, middle-click to paste. - On the Terminal interface, right-click and select **Paste**. > ![tips](../common/tips.svg) Tips: > - If you want to copy a hyperlink, you don't need to select any content. Just simply copy it with a right-click. > - Check **Copy on select** in **Settings** under the main menu to copy the selected text to clipboard automatically. ### Select Quake Mode Quake Mode is a unique function of Terminal. Press **Alt** + **F2** to open a quake window, and press again to hide it. > ![tips](../common/tips.svg) Tips: You can also right-click ![deepin_terminal](../common/deepin_terminal.svg) in the Dock to select **Quake Terminal** to open a quake window. ### Open Files and Applications On the Terminal interface, select the file in the current directory and right-click to **Open** it by system application. 1. On the Terminal interface, input **ls -al** to display files in current directory. 2. Double-click to select the file name. 3. Right-click and select **Open**. 4. The file will be opened with the proper application. ![1|openfile](fig/openfile.png) ### Adjust Encoding Methods When there is a messy code or display error, you may switch the encoding to solve it. 1. On the Terminal interface, right-click to select **Encoding**. 2. Select one encoding in the list to see if the content is correctly displayed. 3. Repeat Step 2 until you get correct display of content. > ![notes](../common/notes.svg)Notes: Usually, correct encoding methods are matched automatically in Terminal. Once any error appears under some special circumstances, you can adjust encoding methods manually. You can directly choose the correct encoding method if you are sure of it. If you are not sure, you can try multiple times. ## Window Operations Window serves as the foundation for your operations in Terminal. A window is created when you launch the terminal. You can create many tabs in one window and split one tab or window into multiple workspaces. ### Create Windows You can create a new window in the following ways: - Open Terminal and click ![icon_menu](../common/icon_menu.svg)> **New Window**. - Click ![deepin_terminal](../common/deepin_terminal.svg) in the Dock to select **New Window**. ![0|new_window](fig/newwindow.png) ### Display Windows in Fullscreen 1. Open Terminal in the launcher interface. 2. Press **F11** to display Terminal in fullscreen. 3. If you want to restore to the normal display, please press **F11**. > ![notes](../common/notes.svg)Notes: You can also right-click to select **Fullscreen** or **Exit fullscreen** on the Terminal interface. ### Split Windows 1. On the Terminal interface, right-click to: - Select **Vertical split** to split the interface into left and right columns. - Select **Horizontal split** to split the interface into top and bottom rows. 2. You can input commands in each terminal window, and view execution results of different commands in different windows simultaneously. > ![tips](../common/tips.svg)Tips: You can also press **Ctrl**+ **Shift** +**J** on the keyboard to split windows vertically, and press **Ctrl** + **Shift** + **H** to split windows horizontally. ![1|splitscreen](fig/splitscreen.png) ### Close Workspaces You can close multiple split workspaces in the following steps: 1. On the Terminal interface, move the cursor over one of the split workspaces. 2. Right-click to: - Select **Close workspace** to close this split workspace. - Select **Close other workspaces** to close other split workspaces except for the current one. ![1|closewindow](fig/closesplitscreen.png) ## Tab Operations ### Create Tabs You can create new tabs as follows: - On the Terminal interface, right-click and select **New tab** to create a new tab. - Click ![add](../common/+.svg) on the top to create a tab. - Press **Ctrl** + **Shift** + **T** on the keyboard to create a new tab. ### Switch/Adjust Tabs You can freely switch among multiple tabs via following methods: - Press **Ctrl** + **Tab** or scroll the mouse wheel on the tab title to switch in sequence. - Press **Ctrl** + **Shift** + **1~9** number keys to select the tab. When there are more than 9 tabs, the last tab will be selected rather the ninth one. - Drag one tab to switch sequence in the one window. - Drag one tab out of the current window to create a new window. - Drag one tab out of the current window to another window. ### Rename Tabs 1. On the Terminal interface, right-click a tab and select **Rename title**. - Tab title format: Select one format in the **Insert** drop-down list and you can customize the current tab title as needed. - Remote tab title format: Select one format in the **Insert** drop-down list and you can customize the remote tab title as needed. 2. Click **Confirm**. > ![tips](../common/tips.svg)Tips: You can also press **F2** to rename the window. ![1|rename](fig/rename.png) ### Close Tabs You can close tab as follows: 1. Select the tab to be closed and click ![add](../common/close_icon.svg) . 2. Right-click any tab to: - Select **Close tab** to close it. - Select **Close other tabs** to close other tabs other than the current one. > ![tips](../common/tips.svg)Tips: When there is only one tab in the workspace, you can also right-click and select **Close workspace** to close the tab. ## Remote Server Management You can open remote management panel to add remote servers via the main menu or right-click menu. Once a remote server is added into the management list, you can automatically login just by one click. ### Add Servers 1. On the Terminal interface, click ![icon_menu](../common/icon_menu.svg)> **Remote management**. 2. Click **Add Server** and a pop-up box will display. 3. Fill out **Server name**, **Address**, **Username** and **Password**. 4. Click **Add**. > ![notes](../common/notes.svg)Notes: If you need to set up more parameters, please click **Advanced options**. ![1|addssh](fig/addsshall.png) ### Edit Servers 1. On the Remote Management interface, click ![edit_icon](../common/edit_icon.svg) on the server. 2. Edit server information as needed. 3. Click **Save**. ![0|editssh](fig/editssh.png) ### Group Servers When you set a group for a server, it will be added in the corresponding group and displayed in the remote management panel on the right side. 1. On the terminal interface, click the **Add Server** icon to open the Add Server dialogue or click the ![edit_icon](../common/edit_icon.svg)icon beside an existing server to open the Edit Server dialogue. 2. Click **Advanced options**. 3. Input **Group** information. 4. Click **Save**. ![0|groupssh](fig/groupssh.png) ### Search Servers When there are multiple servers or groups, the search box will be displayed on the top, so you can quickly search all servers. 1. On the Terminal interface, right-click and select **Remote management**. 2. Input the keywords and press **Enter**. 3. The search results will be displayed. ![0|searchssh](fig/searchssh.png) ### Upload/Download Files You can upload and download files after logging into a remote server. #### Upload Files 1. On the Remote Management panel, select one server to log in. 2. On the Terminal interface, right-click to select **Upload file**. 3. Select the file to be uploaded in the pop-up window. 4. Click **Upload** and the file will be uploaded to the remote server. > ![tips](../common/tips.svg) Tips: You can drag the file directly into the terminal interface to upload after connecting the remote server. ![1|upload](fig/upload.png) #### Download Files 1. On the Remote Management panel, select one server to log in. 2. On the Terminal interface, right-click to select **Download file**. 3. Select the storage location. 4. Input the path of the file to be downloaded. The file will be downloaded to the specified location. ![1|download](fig/download.png) ### Delete Servers 1. Enter **Edit Server** interface. 2. Click **Advanced options**. 3. Select **Delete server**. 4. Click **Delete** on the pop-up window to confirm. ![0|groupssh](fig/deletessh.png) ## Main Menu In the Main Menu, you can create [New Window](#Create Window), customize commands, perform [Remote Management](#Remote Management), switch themes, view help manual and get more information about Album. ### Theme The window theme provides multiple themes. 1. On the Terminal interface, click ![main_menu](../common/icon_menu.svg). 2. Click **Theme** and you can: - choose one theme that comes with Terminal. - customize the theme in the **Custom Theme** window according to your need. ### Custom Commands 1. On the Terminal interface, click ![main_menu](../common/icon_menu.svg). 2. Select **Custom commands**. 3. Select **Add command**. 4. Input **Name**, **Command** and **Shortcuts**. 5. Click **Add**. ### Settings #### Basic Settings 1. On the Terminal interface, click ![main_menu](../common/icon_menu.svg)> **Settings**. 2. In the **Basic** options, you can: - Set the font type and size. - Click the "+" or "-" icon or scroll the mouse wheel in the Font Size edition box to adjust the font size. 3. In the **Tab titles** options, you can set the name for all the tabs and remote tabs in terminal. #### Shortcuts Settings 1. On the Terminal interface, click ![main_menu](../common/icon_menu.svg)> **Settings**. 2. In the **Shortcuts** options, you can: - Modify shortcuts: Click the shortcuts to be modified and input new shortcuts via the keyboard in the editable input box. - Disable shortcuts: Click the shortcuts to be modified and the input box will be editable. Press **Backspace** on the keyboard to disable the shortcut. #### Advanced Settings 1. On the Terminal interface, click ![main_menu](../common/icon_menu.svg)> **Settings**. 2. In the **Advanced** options, you can: - Set cursor style. - Enable or disable **Cursor blink**. - Enable or disable **Copy on select**. - Enable or disable **Scroll on keystroke**. - Enable or disable **Scroll on output**. - Set the window startup mode. - Enable or disable **Hide quake window after losing focus**. - Select **Shell profile**. - Enable or disable flow control by **Ctrl** + **S** and **Ctrl** + **Q**. ### Help 1. On the Terminal interface, click ![icon_menu](../common/icon_menu.svg). 2. Click **Help** to view the manual of Terminal. ### About 1. On the Terminal interface, click ![icon_menu](../common/icon_menu.svg). 2. Click **About** to view the version and introduction of Terminal. ### Exit 1. On the Terminal interface, click ![icon_menu](../common/icon_menu.svg). 2. Click **Exit** to exit Terminal. deepin-terminal-5.9.51+dfsg/src/assets/deepin-terminal/terminal/en_US/terminal.md000066400000000000000000000345631475472654300277720ustar00rootroot00000000000000# Terminal|deepin-terminal| ## Overview Terminal is a terminal emulator with simple interface providing diversified powerful functions including multi-windows, workspace, remote management, Quake mode, among others. You can instantly start and close Terminal smoothly like any normal file windows, refraining you from limitations and hassles while writing commands. Take a try of the Quake mode which enables you to browse other windows while inputting commands on one screen. When there are multiple tasks, you can add tabs in terminal to create more workspaces like in the browser or split the workspace into multiple windows. It's also a piece of cake to upload and download files with remote management. More powerful functions are waiting for you to explore! ![1|interface](fig/interface.png) ## Guide You can run, exit or create shortcuts for Terminal. ### Run Terminal 1. Click the Launcher icon ![deepin_launcher](../common/deepin_launcher.svg) in the Dock to enter launcher interface. 2. Locate Terminal ![deepin_terminal](../common/deepin_terminal.svg) by scrolling the mouse wheel or searching "terminal" in the Launcher interface and click it to run. 3. Right-click ![deepin_terminal](../common/deepin_terminal.svg) to: - Select **Send to desktop** to create a desktop shortcut. - Select **Send to dock** to fix it in the Dock. - Select **Add to startup** to add the application to startup and it will automatically run when the system starts up. > ![notes](../common/notes.svg)Notes: You can also press **Ctrl** + **Alt** + **T** to open Terminal. ### Exit Terminal 1. On the Terminal interface, click ![close_icon](../common/close_icon.svg) to exit. 2. Right-click ![deepin_terminal](../common/deepin_terminal.svg) in the Dock and select **Close All** to exit. 3. On the Terminal interface, click ![icon_menu](../common/icon_menu.svg) to select **Exit**. > ![notes](../common/notes.svg)Notes: A prompt will display when programs are still running in Terminal to avoid your data loss. ### View Shortcuts On the Terminal interface, press **Ctrl + Shift + ?** to view shortcuts. Proficiency in shortcuts will greatly improve your efficiency. ![1|shortcuts](fig/hotkey.png) ## Basic Operations You can right-click on the Terminal interface for daily operations. ![1|rightclick](fig/rightclick.png) ### Find You can use **Find** function to quickly search contents in terminal. 1. Right-click on the Terminal interface to select **Find** or click the **Ctrl** + **Alt** + **F** key on the keyboard. 2. Type the word in the search box. 3. Press the **Enter** key on the keyboard and the search results will be highlighted. 4. Press **Esc** on the keyboard or click any blank area on the Terminal interface to hide search. > ![tips](../common/tips.svg)Tips: Press **Enter** to search down from the current location. You can also search by clicking ![up](../common/up.svg) and ![down](../common/down.svg) on the interface. ### Web Search You can use browser in Terminal for quick and convenient web search against selected content on the Terminal interface. 1. On the Terminal interface, select the content you want to search. 2. Right-click to select **Search**. 3. Select a search website. 4. Your browser will pop up and start searching based on the content selected on the Terminal interface. ### Copy/Paste - Copy - On the Terminal interface, select the content you want to copy and press **Ctrl** + **Shift** + **C**. - On the Terminal interface, select the content you want to copy, right-click and select **Copy**. - Paste - On the Terminal interface, press **Ctrl** + **Shift** + **V**. - On the Terminal interface, middle-click to paste. - On the Terminal interface, right-click and select **Paste**. > ![tips](../common/tips.svg) Tips: > - If you want to copy a hyperlink, you don't need to select any content. Just simply copy it with a right-click. > - Check **Copy on select** in **Settings** under the main menu to copy the selected text to clipboard automatically. ### Select Quake Mode Quake Mode is a unique function of Terminal. Press **Alt** + **F2** to open a quake window, and press again to hide it. > ![tips](../common/tips.svg) Tips: You can also right-click ![deepin_terminal](../common/deepin_terminal.svg) in the Dock to select **Quake Terminal** to open a quake window. ### Open Files and Applications On the Terminal interface, select the file in the current directory and right-click to **Open** it by system application. 1. On the Terminal interface, input **ls -al** to display files in current directory. 2. Double-click to select the file name. 3. Right-click and select **Open**. 4. The file will be opened with the proper application. ![1|openfile](fig/openfile.png) ### Adjust Encoding Methods When there is a messy code or display error, you may switch the encoding to solve it. 1. On the Terminal interface, right-click to select **Encoding**. 2. Select one encoding in the list to see if the content is correctly displayed. 3. Repeat Step 2 until you get correct display of content. > ![notes](../common/notes.svg)Notes: Usually, correct encoding methods are matched automatically in Terminal. Once any error appears under some special circumstances, you can adjust encoding methods manually. You can directly choose the correct encoding method if you are sure of it. If you are not sure, you can try multiple times. ## Window Operations Window serves as the foundation for your operations in Terminal. A window is created when you launch the terminal. You can create many tabs in one window and split one tab or window into multiple workspaces. ### Create Windows You can create a new window in the following ways: - Open Terminal and click ![icon_menu](../common/icon_menu.svg)> **New Window**. - Click ![deepin_terminal](../common/deepin_terminal.svg) in the Dock to select **New Window**. ![0|new_window](fig/newwindow.png) ### Display Windows in Fullscreen 1. Open Terminal in the launcher interface. 2. Press **F11** to display Terminal in fullscreen. 3. If you want to restore to the normal display, please press **F11**. > ![notes](../common/notes.svg) Notes: You can also right-click to select **Fullscreen** or **Exit fullscreen** on the Terminal interface. ### Split Windows 1. On the Terminal interface, right-click to: - Select **Vertical split** to split the interface into left and right columns. - Select **Horizontal split** to split the interface into top and bottom rows. 2. You can input commands in each terminal window, and view execution results of different commands in different windows simultaneously. > ![tips](../common/tips.svg)Tips: You can also press **Ctrl**+ **Shift** +**J** on the keyboard to split windows vertically, and press **Ctrl** + **Shift** + **H** to split windows horizontally. ![1|splitscreen](fig/splitscreen.png) ### Close Workspaces You can close multiple split workspaces in the following steps: 1. On the Terminal interface, move the cursor over one of the split workspaces. 2. Right-click to: - Select **Close workspace** to close this split workspace. - Select **Close other workspaces** to close other split workspaces except for the current one. ![1|closewindow](fig/closesplitscreen.png) ## Tab Operations ### Create Tabs You can create new tabs as follows: - On the Terminal interface, right-click and select **New tab** to create a new tab. - Click ![add](../common/+.svg) on the top to create a tab. - Press **Ctrl** + **Shift** + **T** on the keyboard to create a new tab. ### Switch/Adjust Tabs You can freely switch among multiple tabs via following methods: - Press **Ctrl** + **Tab** or scroll the mouse wheel on the tab title to switch in sequence. - Press **Ctrl** + **Shift** + **1~9** number keys to select the tab. When there are more than 9 tabs, the last tab will be selected rather the ninth one. - Drag one tab to switch sequence in the one window. - Drag one tab out of the current window to create a new window. - Drag one tab out of the current window to another window. ### Rename Tabs 1. On the Terminal interface, right-click a tab and select **Rename title**. - Tab title format: Select one format in the **Insert** drop-down list and you can customize the current tab title as needed. - Remote tab title format: Select one format in the **Insert** drop-down list and you can customize the remote tab title as needed. 2. Click **Confirm**. > ![tips](../common/tips.svg)Tips: You can also press **F2** to rename the window. ![1|rename](fig/rename.png) ### Close Tabs You can close tab as follows: 1. Select the tab to be closed and click ![add](../common/close_icon.svg) . 2. Right-click any tab to: - Select **Close tab** to close it. - Select **Close other tabs** to close other tabs other than the current one. > ![tips](../common/tips.svg)Tips: When there is only one tab in the workspace, you can also right-click and select **Close workspace** to close the tab. ## Remote Management You can open remote management panel to add remote servers via the main menu or right-click menu. Once a remote server is added into the management list, you can automatically login just by one click. ### Add Servers 1. On the Terminal interface, click ![icon_menu](../common/icon_menu.svg)> **Remote management**. 2. Click **Add Server** and a pop-up box will display. 3. Fill out **Server name**, **Address**, **Username** and **Password**. 4. Click **Add**. > ![notes](../common/notes.svg)Notes: If you need to set up more parameters, please click **Advanced options**. ![1|addssh](fig/addsshall.png) ### Edit Servers 1. On the Remote Management interface, click ![edit_icon](../common/edit_icon.svg) on the server. 2. Edit server information as needed. 3. Click **Save**. ![0|editssh](fig/editssh.png) ### Group Servers When you set a group for a server, it will be added in the corresponding group and displayed in the remote management panel on the right side. 1. On the terminal interface, click the **Add Server** icon to open the Add Server dialogue or click the ![edit_icon](../common/edit_icon.svg)icon beside an existing server to open the Edit Server dialogue. 2. Click **Advanced options**. 3. Input **Group** information. 4. Click **Save**. ![0|groupssh](fig/groupssh.png) ### Search Servers When there are multiple servers or groups, the search box will be displayed on the top, so you can quickly search all servers. 1. On the Terminal interface, right-click and select **Remote management**. 2. Input the keywords and press **Enter**. 3. The search results will be displayed. ![0|searchssh](fig/searchssh.png) ### Upload/Download Files You can upload and download files after logging into a remote server. #### Upload Files 1. On the Remote Management panel, select one server to log in. 2. On the Terminal interface, right-click to select **Upload file**. 3. Select the file to be uploaded in the pop-up window. 4. Click **Upload** and the file will be uploaded to the remote server. > ![tips](../common/tips.svg)Tips: You can drag the file directly into the terminal interface to upload after connecting the remote server. ![1|upload](fig/upload.png) #### Download Files 1. On the Remote Management panel, select one server to log in. 2. On the Terminal interface, right-click to select **Download file**. 3. Select the storage location. 4. Input the path of the file to be downloaded. The file will be downloaded to the specified location. ![1|download](fig/download.png) ### Delete Servers 1. Enter **Edit Server** interface. 2. Click **Advanced options**. 3. Select **Delete server**. 4. Click **Delete** on the pop-up window to confirm. ![0|groupssh](fig/deletessh.png) ## Main Menu In the Main Menu, you can [Create Windows](#Create Windows), customize commands, perform [Remote Management](#Remote Management), switch themes, view help manual and get more information about Album. ### Theme The window theme provides multiple themes. 1. On the Terminal interface, click ![main_menu](../common/icon_menu.svg). 2. Click **Theme** and you can: - choose one theme that comes with Terminal. - customize the theme in the **Custom Theme** window according to your need. ### Custom Commands 1. On the Terminal interface, click ![main_menu](../common/icon_menu.svg). 2. Select **Custom commands**. 3. Select **Add command**. 4. Input **Name**, **Command** and **Shortcuts**. 5. Click **Add**. ### Settings #### Basic Settings 1. On the Terminal interface, click ![main_menu](../common/icon_menu.svg)> **Settings**. 2. In the **Basic** options, you can: - Set **Opacity** for the background. >![notes](../common/notes.svg)Notes: if Window Effect is turned off in Control Center, the **Opacity** scroll bar will be hidden. - Set the font type and size. - Click the "+" or "-" icon or scroll the mouse wheel in the Font Size edition box to adjust the font size. 3. In the **Tab titles** options, you can set the name for all the tabs and remote tabs in terminal. #### Shortcuts Settings 1. On the Terminal interface, click ![main_menu](../common/icon_menu.svg)> **Settings**. 2. In the **Shortcuts** options, you can: - Modify shortcuts: Click the shortcuts to be modified and input new shortcuts via the keyboard in the editable input box. - Disable shortcuts: Click the shortcuts to be modified and the input box will be editable. Press **Backspace** on the keyboard to disable the shortcut. #### Advanced Settings 1. On the Terminal interface, click ![main_menu](../common/icon_menu.svg)> **Settings**. 2. In the **Advanced** options, you can: - Set **Cursor style**. - Enable or disable **Cursor blink**. - Enable or disable **Copy on select**. - Enable or disable **Scroll on keystroke**. - Enable or disable **Scroll on output**. - Set the window startup mode. - Enable or disable **Blur background**. >![notes](../common/notes.svg)Notes: If Window Effect is turned off in Control Center, **Blur background** option will be hidden. - Enable or disable **Hide quake window after losing focus**. - Select **Shell profile**. - Enable or disable flow control by **Ctrl** + **S** and **Ctrl** + **Q**. ### Help 1. On the Terminal interface, click ![icon_menu](../common/icon_menu.svg). 2. Click **Help** to view the manual of Terminal. ### About 1. On the Terminal interface, click ![icon_menu](../common/icon_menu.svg). 2. Click **About** to view the version and introduction of Terminal. ### Exit 1. On the Terminal interface, click ![icon_menu](../common/icon_menu.svg). 2. Click **Exit** to exit Terminal. deepin-terminal-5.9.51+dfsg/src/assets/deepin-terminal/terminal/zh_CN/000077500000000000000000000000001475472654300256125ustar00rootroot00000000000000deepin-terminal-5.9.51+dfsg/src/assets/deepin-terminal/terminal/zh_CN/fig/000077500000000000000000000000001475472654300263575ustar00rootroot00000000000000deepin-terminal-5.9.51+dfsg/src/assets/deepin-terminal/terminal/zh_CN/fig/addssh_all.png000077500000000000000000001237321475472654300311760ustar00rootroot00000000000000PNG  IHDRo; pHYs   MiCCPPhotoshop ICC profilexڝSwX>eVBl"#Ya@Ņ VHUĂ H(gAZU\8ܧ}zy&j9R<:OHɽH gyx~t?op.$P&W " R.TSd ly|B" I>ةآ(G$@`UR,@".Y2GvX@`B, 8C L0ҿ_pH˕͗K3w!lBa)f "#HL 8?flŢko">!N_puk[Vh]3 Z zy8@P< %b0>3o~@zq@qanvRB1n#Dž)4\,XP"MyRD!ɕ2 w ONl~Xv@~- g42y@+͗\LD*A aD@ $<B AT:18 \p` Aa!:b""aH4 Q"rBj]H#-r9\@ 2G1Qu@Ơst4]k=Kut}c1fa\E`X&cX5V5cX7va$^lGXLXC%#W 1'"O%zxb:XF&!!%^'_H$ɒN !%2I IkHH-S>iL&m O:ňL $RJ5e?2BQͩ:ZImvP/S4u%͛Cˤ-Кigih/t ݃EЗkw Hb(k{/LӗT02goUX**|:V~TUsU?y TU^V}FUP թU6RwRPQ__c FHTc!2eXBrV,kMb[Lvv/{LSCsfffqƱ9ٜJ! {--?-jf~7zھbrup@,:m:u 6Qu>cy Gm7046l18c̐ckihhI'&g5x>fob4ekVyVV׬I\,mWlPW :˶vm))Sn1 9a%m;t;|rtuvlp4éĩWggs5KvSmnz˕ҵܭm=}M.]=AXq㝧/^v^Y^O&0m[{`:>=e>>z"=#~~~;yN`k5/ >B Yroc3g,Z0&L~oL̶Gli})*2.QStqt,֬Yg񏩌;jrvgjlRlc웸xEt$ =sl3Ttcܢ˞w|/%ҟ3 cHRMz%u0`:o_FIDATxw\UϹel/ɦwPB &MPP@D M)*"QzHBzlgn9?6T ZHə;3ssE˯[xII ``Xt0a|rヲB%C H/^\w9ߴ*e0ĀM7{2B![-_ TVV&**$|GcTFB!^ B!B!-B!-B!o!B!$| !B!$| !B![!B![!B BZB/.^^:36 ;O־Ʋ,%Aw0qdvX|>RJL!o!|>ԝwbmҩ$s}P_Pgd7ɞnL}ߧ`8y8"UzI&AKs#ruw-B· Qcd!:Z3{v55fQ(ga<#47n [|3κ?|9p_o#,B·]II;{C++-p8׏2|tK^U/uVrْ~ 2f2J)8nULmoC4{A!o!J%9ԯ1dpr ygXfHad2i M6x4=hE!?rZZ3n eb|DIJ_<ʪf2L󻴶4[~bqR!o!J)<ץp}*Oz8a4s h$(|;"pΎm)Tom~ϙB![,"}h}+*II(a48' gm35Z[i׾xIKs#>]vۋ?LnG<tuRIb!-@y.U5YʡX(gre q:֭YRCaL>`X,N(y_]w0&/ϠCL0}n~u;oi|pn'NaZV+B·Z6#O`S}/}ayNkmg1Xn5{Lߟ#Fc{&,O*|PdlT9b8op}?3X\h!(9*HnK/~r?MG|( xk9qB0@_{0Lr `YvNz'$6b<yj{!'y8kgQ*V!:ʷ8d yt^|uo/bo5iR,pG|#J/,(6CC!\ב-BHbK ޾y%x ! C@!B B!BHB!BHB!B·B!B!B!-B!-B!o!B!d{y񅢵<<ϓyhe B·[W#)B·[R_B S)@M!ؚIͷB!B!-B!HͷBQ 5bJIŷBld[!B B!Bl]D|();TJ: !VNVB!-B!EN|l !غʷB!B!-B!-B!o!B!$|!B![!B B!B B!BHB!B·B!B·B!B!B!-B!o!B!o!B!$| !B!$| !B![!B B!B B!BHB!BHB!B·B!B!B!-B!-B!o!B!$| !B!$| !B![!B![!B B!B|Y2B!dΚYf%B b=BlfΜ9sϵ b*tM1 B!hp8J $! iB!3"[!B B!BHB!BHB!B·B!eB!-Bp}Ph|/PP5y>Z~{atwuQ|ROD6B!5gRB3@{=!Zkh"ATDk1.A崦8FPX sȤ? <5WKDCd{0J1q\] dQ ZL; tuG! le)$d<B!>t۟eWeyH0Lo7r5Gr)âuUQU@B 0l|tVxn'Y jFOA4)yyu|?E[7z |g00|||l(ǜ]vY(fFFOړmжf<r a 1Ll:{$嵃h~/\+P5ͼ1C=wds.C,$|4t1&. KEeԝwqdaJB!VB)`ʗCxr)6.bEwFny٣t ᛗo]͊.,CWVеɌԣ&S u;ݷT&^͓ByTr.646uWUN}/0g#w:?yZѻz\9ٰfc<^BaMe0b h}4,\0Z92eK+[!;9#kZ5]wPov'L!:Kn}ssEkk_򋟟J뺟seK:ǜg_;C&,n-g\c\zR jl-xg.މc M=_;ZfrWpϓ31" \w\KK`&⤓6o-iH)X,ΚU+?qW}ޞ&| m7?UىB!Āj^\x=vAOW+݄O#dtA[Sv;}2.r<ya:r-|#~ B:x| !b3q^+,|ln!϶{Ociį5?KefTd[( "rQ(el,Dk|,!97U弹 ɞG+obQ,y}.fNCx Bvb dM=e(wӎeh}yO*b4$]xHGkMYy/dsqpͯ.!#O?c-BP&58ri_cİy1sXZ֮md= <]ŐCHu Upݙ$$\},Qpxw&ɰzje2kA'׳`8;ƤgwbDOS7r6teX?%漳2V443i4 g?7W3fW?cTԦ}\.^I1RAkk3'U2.Ŝ GY8]k2B!bFp78vfp%W=& kl^} Af| kͦ"l*a(4l~=hbU nxlAD"N$Ȃ'`^f,~|rw) n[ˊTٓ]FGxxsb:SvG#W1s8sQ7|[ߠZ%q"9鼟rQ );pRe[!O>S`AǰhŌ{2u4qϴmè5;Kedo&Vx0b{SA)*κv2nA#y_`i~=ABY D:tk/R@tpUp?cymzH4uaf>s/֤uSM}vt:ŤmP[7?;Buа{G}"mdiLGj B!ٻ@ޯ`՗u5~ sϷӚj$+m8cfC|3Xryw]7{VUA:&D+*ft>)լ|F⦒ Fy?5wÉ_6{49!^W&U<)=4&T;/Ը֢bO*ArK@HDin\"}J:Z;0M 4?JB!$||j~ŲXL&y殿#$(#_ABg >%8u'W;q;oqK H>51;CS'xY~ԵrF_-}Q6:u` v {=<>s-v86m+䡻3%3^s^ëޖzV<ar9LIJ]M|#y?tuJ4K|~ǝݗ^Dee p۹kzv2]wo|tРA2[oP>Lgű |zL0Ph4aa)|6 Z%_p #;x>JyexB}ac<Î(8F)<@$Jж@{8<|vmCkb+ȭ-+B!4V# a4ll5HE(Pt8J) нRؽ`jف0V@C(Z aq C·B!LJ>)k{`=sjIA!B!$| !B![!B![!B B!BH!B!B·B!B!B!-B!o!B!o!B!& B!> hAeP~L+2p  $| !P&k+bK?5#o%°l#˫E!DT1 =Dr~0A-FRuPk+C>?%| !}MD߁/".PIVcy.୕I*)貱Tλd@B_ nhXBr Q4lP(aH?qݵhDzpcR2V2.2KB!ߞK,h~,t)ko"(qhM!tuuQpUpeQp۴Yq+~U`_-SS!B)D݆ OR/P1xo {'heĖ7}#PZ,ȴZ'$C-BlNxx1@*>By-R(foSYXN{n6oqOuMp bY@PH920P~KB!C1$6|'N&\L6c,v=[ rWr}3R>RN9d ns/m"'S~ka%c"DB]q쨏J)<}֬Z1xp"mI< `Y6`0I1L'}%S}Il!zÞWmb-^BWӱp5OXBu V#6~~/V_?t-3Tŋ+d}d(dE=ݝttJvaVm9Wsor'{ 8AW']#2Cu)+~ƌȢshnl`4nXK>J+Db؁L|.KiY\בo8u\DzrnAs01M3K/ Be%65Mdr1W+mǮg2pyc"yi{CQj殄.<n|K^fS8ǞOdѝ\? b3ء#ƌǙ AkI[{`FCk*j)Yh[fe۶u]BDh[ϾԽ qNj=O~>|V^ZQb8Ҡelf ݿN3QCd45#b\3Yn?Wd{m翼I*+TB M<^̏ x KkKCfxw[L~*CijS}=׎h-ǡ÷R*cvBC)R*##!}Gkpyj&WGHKVͼW_ީzh+ږC[ddkA8ʃEV͞|Ĉ90_p?06ur͝=r.8&cɂ`p{oVuv m7m/J*MUtupBa:;~2hl6Keu-Lb@.%q [q!B!4oWҽEY͈ ]xq rϲmGSQ='|:w݋@Xۍ̼o]of/T(Zqp ~)ʢ$aً7r,߉o{"CKhm9.m`򣙦I>%ͰN:y8D) ̦AC 1`(iٸC8n0=]ELӔCSlu[!Q*ҳ)^~k6$d˸c9k2ճﺍ ~[g\]q>m$rϯ`rg Wۼ&jgKp%d[e f1w\ۺ42ir~#I&Sb#`atwuP(2lF~(粡a-ZkZyXn`d(àk8٠| !XA'5kn9SwޞҀO10=ΥSnn4_98"= G: ^u,ƌbk7ҔJ65VeOd;'սp(<&;<6w=X,J0^>'\L0 fǑ>(inXKG9 Ge,]2 1rxkE6ajetܴӰ(+`5ZS) ²=rǺo!1F-Z=qZW%S3Q?z2cm#1W7O MV#LX5aŲ_Cj:ZI ZMb(X3%]w25*:ch8ⴽõiƢKى\ fu˦@ a*7F|217!RoXM.4-֬" a4饇-|+BKKB!rxow[A^xx u} zí r\Ue5P4Ѝ6־ߕW,:V+}PPc |?ȴP6kb}+HmMo+BXxwp$\),laUA^G_ Cy)|+JI[$_{p6{z*2H}*,f$F6崔Bߡ4H96+"8L忧>P¢7g{,TJMlq\_QP,:̈nM:>OV <ɂM=kib>ɞnL#HEE@8U:[)B P( 2ls#]"I hc7ǤBB![!::Ԥje4EIv%ۘ*SVly_t Jɍw=E bZ}{6_·beTTofb|.c;1}R+~~#g^Ǝ /S>~o5xf*Vfs"Z~!umt8"pT++=K!EAּOڃ=i.; M6+ xI s#NRRi}~\Kvs='9Gns:N);(cxXde,=p;NGi?ds=~̜+xg)DԟGZf-ie`?qN*C @~k4,r!i(|3#z/0B'%|-4|1p RcD6xo!V={?X鹓;O9֗Bɫ8{@ٔWYrl`ACXPg!Fn3u2?_,^?^~)㪟`0SR4n2#5W_r Mv?oݕѕ6e9ƄB5(Pv|}Y-< mП˴ cNg +ąGcxr):U6G|k8t 3vٛ_#8t{j+K $*( hX/opxnA\{? ߹{DWʪ+2TFXlky'LGֈ !(Kbw~>߃jn{&XmT Sw{Wݏ.f{R\sn [Z6f<7*fV%0I) eyXa& ^ZJi"A" Q4TZjB!·0 +JS' ^f`؄t6n`_ m_ނK`iT*E{OfЦ} :t.ZZWS-B!~);1 EF&N}0C&<]I! Z'jq{o&6z$gm60(fL*zs?n$3o Yte'= VwT!Zy1MÐ͇$|nȰ)2>{t6>ׯc !O>E%3a mEӚǖb|浸dqE(kkv_?E >Tѻn i1h'PTޕg\!<4I$A~>L|>awz&qIR3~ `v.ǻ9专 K Y6wήnAx~}ty2-3V"!A 4Ճ(,!*2ЋPGˍ7F0JEE9557b]]Ieee.BO\%P[[K(4ugPǡv[*1`Mgs ޮx%|%x֮ݛhs&ςCݦ&UW?%9=1 ێi\yyٹ*[Ǖ.EY1!l:yzLA_^B!ħyH!Cp]qd`>eQSSRV[ DQ***D"*|g2XVl/}DPׯcGJIt?/&xK)r/F)y)`0e V+=tuB1)H(@,{^x5];%0B) @ee%@@B0ZS^^N&!lg<#1d,u]<4M444P(ea BkabޙeZDbq2P*@M8hM!0]}{XaL_k0-dky! Lph4S,x_2{Цi:eս 2 3x,4TG<{BIYit;ߋTR.X >|fO<' چH$}B!6M."Wp0 a(j^llػdx TYyorl1Ȩ ?aH }pt B(G&Tk&@_·%BQ +k {͸ JSS@XIsf֚ { %/aʥGWT>3vGDz.0ӧcx;HJp=(tWq%_e.#Wk: N4$Q;oBYy%#FeeYX֚@ @M :) N*ك8O26,醷yhi>"fԌM}-nY9~o<;vyЙ1Ȍ؝QVqS g"ZGQa>_aULhi7^<6t3ʔĞ{֘[y=V/k 4{CaZOBlݔaaםĊcRn5G0-t[wwmo3?=jkK:Kox3?KK|^}&`m1ZIUu-LTjƌȲ% }V._LPq=Cm}HI?0(䓔TP?>DyzL\ϼWs)AL_c% ,ŵ " 5V [Xo}0"e} n%Z7ë^2B X&m՛`Dl[ ca(~&e 1E ]:9Sxr<7rB ߖMy<իhh"2tO?Gs<5ͬ4X@^YX0nj^}^^@y%3Ε_VE,o󨪪0 l7eZYxm-׏ Nh_n IO.f!v[yo'J6^ش.OR 7Naj&2yQ L{ĴA)^x- V|'dWVe9Wr7Ӻ2$[׳v:/_Fxׯsӕj\ɲeYv-Y,ɥƨCz]-M<61x?ek:>xԠ]NZLA K^kuw&)6Cjɥ{p=s@|R~& 1/FThjlWҰv+-f0X 0|%aoi #`_=eYxmwڛݗʲvZTx4ێۑ]'!JJJ![p6ﱂ)r8NVxd{ 㹿 Bm݄B٬zsD{:`t"*e^_ +bCTL8-RXgև0n݈}wu\z-{呜yJN'ԯ}b*c]=sί!_p2t<;~qq x_Oq D,`{M![`N`)QRlpp [zND7u9v31uaXaJ+t)(Ęm<_'gtR7hَt*ɒȤS3Diga"&`6%% aƈDy#lb xteņVJbA&՚:ŷ 0O5h3X ᅷ< Rz72h\"Uͩ#װ- ߺ7X9`ìgC#`myH?|:SM9x-瞲 kzUO_ޕt_?#F;<8㌳y襹z{?]L:Bpݷ}og1S]5~&JӸx:7oDO6N۵m_<'w<2g=%UDa‘@ [vjҝdݽH8ʂ( 0u;:Al'˒N'YhgIG{+ixK:CP-&.jc\Wb0h4NTaj+!h8,bb@P`p=4ٜ}snGcZABF7yO=E2멿+wAPI%f&uCAE~0*^J"TvE"84 3_u=?zG\tYT9ŸQ s|nkWyѣp5,{6]b/e|:~_p_&w_iossȉwp/++Ay !!!~sR,ZY ^eÞ_SΠ=o1hPֿ~'ly|=)wsT&8^$|+Kg$Q2!~BDЄB5kLJP_7䮫S(z>D9:L1PNf[<%/!d+ՌZk,ܯMY Jm,%靌ZJ):Zh4-xҗϋa"WG{ǵ}>2z/HP5vcͰ#ZCAzыiUJQ,?60Z$$>p$[8NjP\:y6 bEkNO$hiTGzc\;ydxIfF s<` Be"_N[]3HRl\OKD,1O}h}N~{ٹt/? ~7)d1"A QȮSEy !)0ޏE߇@$[`4]aveAS[ke„6P叏y7ޠbYG4u[-mK5 ѨC9ņ{kcq O JQ^^eY 4fd2~ϷB>J318fx˪c߽3f[4f9ʱi^}7Y'\靬O5 4XAjX8ƵwX-|;kTW tjօ$"90g9r!taDV0 |X,8r|6MztƪgR>8jii~s(#J),qZZZ7,Dۊ k92adL΃K)xrO.)/ `T)~h=o{%>t#*_1E אjq$VGiQE/mnglWk|YQYn'B!{Bttt, ue`>Ph6-bT0A)Eyy9Ph{<#NF:Ʋ'&.Ĵ}fD>HLmH3+2hٓ\O~}QksE"&uCcY^\rme7=w׽yL-#o\ʻz:'ݕs30EĶ(^ƛe0M|SP_-B|00XdS[[mґ3}:::hnnƷ䉄ituuJD"ufo_÷F*kc-,Cs fB& o.墇{z-NmxN<7~ykY$rK~'qQ{.\>,-|Wkא(;L,E1{.XȟKґ<>nO<B2Md2IP  dPyd24V36v*I&4~ M ff&XB;2!{]\tұ9F(yy5mTsy=>啕 }c7QZ3Oה 'Ry&oDXESe2'9 Qo!cɦviR 00/~t2>e2t r+, La#wB:IN )d /t"+>V/QP Y(MDAzZ+JJKɶd 1|y+B!>aRr"@ ߾cc{ckK {%y(y_6Lp`J!M ޛo!x; B!?'2B!B|6,cg6`䢉-r ^BB!bK h=]wTүsKcSbBش3l/FZKΖ}OiRZ#!y(}H$BII `P&L<O÷ .-S 2B!>SS^^NMMt;[3HH$ذab7dB߸KYYuuu/ˋyDQ DCCd·j @%{Cz{>8z7 22 z#d~ߧ-L~B!'iͿbk8h:·+`14YTCmT(_)_.J˚4rMȻMyh&N,g;'=0qr&g;;+C },۠, 3Mlёr)xB!>q[ EFx8k\u?;@·@Wvp?;8dߡrZu'lae??SFpa:r4tpYhgY)G ez$N=;l1յxMB!ħiWOZnyGnu]`nZ\7^t9nWNgŜ|u7 hmcva}f-`|9cD"&e/&Y.OqOpޙἿ55 }U+IWWRN[U%! 6ٔ%2izE2~)#݅B#`[u !XA0bCXA\.RF_&@OSL5Y3g6vCyW5yE=ň%]1–Q a2"oGw0#?#j)"+[qb*s]j)X Ӽt!t]+HA MIB!>KQ,q\1<;P(B[Q,eG ;."  z!3L-(h4i>oa6l8m܄9/iA2EWgO<֯_CII)ՃvJ<%N($|*Yq6$oe]j8LӐ;j'knԦ6nM.a6 r zڲt'5K7J-Ss-1v1%uYp(ݸ}®T3BT[md+( =cR-K}Xb$ b %<,X!/!@kNvq\hknn3/EFLܗ{<ˤ .Fmc+ )j3cMF1w be(ckSQQEXH7:B'4Ygξ-Zk dQ˘&S(2cyqb ]k)GĜw͡eA"jL) 3r֤jxVZkk9e cX9; \Q!GEU>;&_PE>wハjޅ'yif#YGNrI'^ԓ"dWB*g3[ɛ7+KHnWc)OS6Zk Ӥ$QJI9"2nd֭#FS;h(zKMj\l7mm1)$|{U;s< qN۩utŢyžSam[Îʣ).z#ITjgMѣ;Ow(iCc>k"p$+-L;,5h9j0 Cc4봅B|BNa!l:"$b3|Zf/n|e2l|m 8GBdRͼw7n"|~t,7>Ddގ0f6AB0kV.$QmYXM,'&NxC twu 6Tdwo!S3zd8"YN{ľl}%Wiڐ(Rz#\'cAA1X'hbZAS"e __d CEg5>v:n0;-mt.?`kIB[G0"+ 9fյz M1`ܙ${)tu:M{<\6{Rn"$|j,p<6cn})UĊ.b1%X#)4ԛ̱pmMr 5PЬk3S 29![,\sRş'wF'v*np<Z8N(3QqSB "}oܻh(FW3{yzMG~m*PwWax<÷#:L?ALr泌?<&;t&~xe  }GsSSwN2w;3n+-<,;iYx纸qLoU E ;q0ͩW- 1#w̿0q d">\!m*mu98Aܽ&WPD|i@.wn_)񻯏!BEئW~Tُ4D,[Ȓ>mЙL>|C~V~ U1O;c-zdCcaSE/I&&aQDQf| k:|H&J GSRRJ $C!kjl-غwbvX鲲فY}f\&jBQp4mYmr3fHK!sGA)#&^֡#|ܷtkR/,ڒ"LTk?FГЦA"dC+,e#.8F-8 ?[ R$8h;j#߅ӿq*7̌=[tBtdMؖNs],;e ô5Ӹa-b#ǒɤYlt8B^6?5CHXA#N?63UB Nt2U],Z&lpřndgof]R/}o@T( &Bm X h6i[4NJ[iс҂2˗-$O \.C6! 8HqXd>T e(V,[D˲}_.BOcz(L.vk^ɺTD)YaC:WԑTf#f Iv`ئb _gI.4 c{P0 cƟ)47mm b Z`ǀƖ"P6BY6, ?m(PЁa[9hζBmCX60t vCT h]@8 Pn}Li &6 C.}A)žǖ氒+K(o:1) !+Z1G@oj H4@(oW5p$j0m"Qb%4tOؒyR}p2W` `Xl9'⳱`0H4u] b%><[!B-7vUY613Ue{qcT b^5^ bAӷeoadtix8;+!B![~)h\aې6O3W/eOĂU|`2dTFOZ=^O+_:j"?t7:xK\Bg B!E*[M+M6͸7;z-_qms>'q1 6,-}?#$.'2g!sU('wŹJ)t &@Wo?jD)ss|sPVr72z:ryxz}XvLMsk ,aĘA _gQQ?Y!ÐaTVVRRR"EN\%JсyW(7$~I'C(RӥFB{m1fk(Cgweju[܉|=Cgpn#{/w~M|$3jxXQV)Gnn;9hGK͉B}0dKoRA"Hom͢].&#Cq<4IB /z+#U ,z2n(/E7'"Is- @ ӤPBkjj(//q<<#S]]Mcc{¦.fz1=/#.[{w_>;L~Qy+Xt F_[9_s!ɮ+47?9Lc)MP))  'Is{2[!CP $x+))!yZӸC 9d;љ6Ɛ~dpZHN7o+%K֏.QZɣ'7fz׹#; vr3) YL9n*rj&XBϚ֚@ @ ~,÷eY2L^o![}W8l?BewRMWr ӱ|h Mүxpf+:~, W|m| YjJ3-KB!>4eOazkpJ1`?EkqmLb'T %O-A4X=99^)`"T:>>B(_Zc!ⱈt;B `CoҴ,|LRei}@ҲHez {.jz@AȀMP0}}Yq5}ao>r/#O aB!֠I0ADW3E&'Lj" a:Y ‘&.]+Yl_a{ָIPZd1鼨!aY1.tgnSuk`*-ՠBe};$S;ӎߎDQ0#T*ecwR}}6/x`~@0Vp9yppp! +@Ev҅ɅGq8!c Y~B.@UpؑۅB FnG)"z1\Ac%K2y{~uO/S]nO]LJE() i Yj'Qo,6 vj~D^;Fy[u[ \?I?o B! P72u4' s_~IS]7Bn!wc:jIvŮ%4uP,jGǠٌFYs)*^>{z`HYq@}*4Mb؇mv*)I@>2=Qvd;o'P3+LّA{S[' (a>Hx#fL-s0pƳ ՔFS~zj2d[]a@v1WktXWXےy~GZv|68X #@ldbnQN{ϸ5beݎ<:^cӼcTj!L$ҭ|O:/m5MC568E]Osw <~#no`?di>"Ez!a}`yZ$n!00obc0.La2,x&0Y\uM}g~Ã˳-^[9`)&LfLQKe63(@6) `YHA!t=/.WhbvCoU9FWڌ~B;NUfa8 o[%a\y  SȽLz%5U6m~y@v3v7 8rI4An~F"32AVZ98R~g#N!4}ojebQH=foݘqc{# BkXk|GbJW3`C9;)mGIj9U4~;XHdPJvbR66JY؁ԛ?ѻV=\%&KRt2ǟ>ma ;lL齭R(ջAffx<|9eчtB $NZ6c q%AjJ**(7gu:x5Tו쥛9iHD,-D w1[2 >X5_x+|_|=|R=D%nvMU"8EMz;àrk7P4]DY)Vr_3vƲ,&VSZebY>M+fjRƿ_&.F7c+}µ#@zի'dUpc[;Zk\Sf cAl:׃26.OV =;:Hzr0c6FsWrANGxhZ;esh_(  {"WӚ/n^#oYBȄh>ɿ2mB!Pw(4R 50cH)EXX,<4H|vLu] ޴\<1P E0Z쯨d:T:÷q8?\Cz(qݯxd{X'Ҵ.YxP[ZP2`?Zk$l/f @z+'E}g0ާ4M"===l>K+guuuu7K(VLކ?R ~|:("*Aafʤں(e 0ƕ1i|F2I\ASQ7S$LmQȽíySSvn,=oֿ x뭷85\C]]IB^b@lۦHmo0 LӤwS&*%4(bM8b|F?UL<' NPmΗeﵔqΰYr6nИɭ~ZKXyϕR hjj" ҪX 5BT*Eggݽs ($yP8J}ݛzkfiJR)Mg͏~#ؚojyU~J!c >ym:w%cy, s1匪G]F .IqK0 ̓jahIȎGL#\}  =,N.KYxD AY4귗}p8L(-b@V)0Ms_·aZx66ՒXDo*k|:NRv0B_B!rVJF 2 8C6uݏR)'h@ 1z7O5 +3@a,Cw(GB9s]P(DMM HDZ ~>lV2̇7efwɸalҟ&x+Xm =ٱ-9| !byPz"8 7J)b`}+ U=dGHUZƎzM8 \Ot^wZjl9By|TUU̎;qmj֭[[]ArԨ)_5Їނz@ tofrh˛ !DQ<ϓIXr2xN ;;}S"i&SQOpױ[Wo |b@}_67B2M˲p]WC|g^(.n| gb2@jX3HpTJt_o>] `$B>]TJQ̦)hX,v4u3b@G5޺[^*u1 ;69YIݲ·B>5~@*%O`yEGc" JxKI0KG['SD"Q!ѯd0u߹( MYB|9}F0jUMtl<-XH[WT!'\̑9 H'?]Wcl][>OCe&>.Do~?8iݯ&J)Bl'b}كRKpUx,e@!D3u=Iͯ{<&Nَzinb ,ZYʞ{ObDpєNGNۻ'cM|Y o+|m)z[L5t2 nBևa>TY:h|+gpET.CggzŢbP-VLakk23 !+B!C\J)ѭz/ fO&pYsӷic ^»Ɏ˙6pks4fy:!1zM FB`A"xWCh̔BBli|Q<;`'IR=z2h6 PO+Ժx/ƅO8URD>E9^#P4uylQ3v)2]Y"Nބ>X;zW+  ۴m2 hlwT,P(xNƵY@wt;^:Zm9(i5 c0>9ُ|bY[3!1n@kG9ҩ2Y)%%fV PE>$nPbbƛ2K;OĢ,~ ؕoZ::Lp >3:*YL6~J' V]ǡr& 6 e51`p׋v_8rڎoQH" x/w9\K*vƛ%R->5 ;Dgڴ^F 'AêzoIwpHU6П`*!M‘JLW+~I6Z@tM;`[~GuLQV?Uh3oJ2n |?4uQ7qOv2Lb|m)Y7_tSt4NϼgHB~L;X4?5mָHR(%q ӏn̽Ʊ~l6&x!w6 3ȮBÜ{eޯMVuݾUݏy[m-_F.>c߳2e̘AK0uT<}v% 2i o0NUOdhm/)h%[!D?FbDy則YٝgvGrӨ;]?>$V\E>v(F<")/ ϼKUUK^޿ϪM$ bBnY/kV "N͇VW CE k'2ozö/8Qy xjf3Zy(brN!D~!f|5M]T(wJ= T+x"ZW~:hpDIgsG$VB8 }2[ػ8:$ɾ ;} 7l]kmjmJ"."I{fKf3sv~LAAx$3sNys?פ$}iSDiy5,4G<>%z/ .ON=CKliR|:0kV3 ^\rhoyӷNe0mսlLZpcu5Ghnk%&M-.$Q(xs38j~F =?8[wNo{6̧v QqsxOy qD%x~G iZ"""" Ipsc|拟kgpV#r7aۣw@m|k>̏h2h)f(|?;cp"F6'?~=C\d$N!IH]rͣwZKaLKWsӺ4ut^T'"""" G[.e>BsL[||{|gi[JZ\BW[>q;_ZL yOLDDDD&鐋0/(MdfƏ|k N} CIjqp]1QLb=h@{5w𩯞Ey'GW0 i;wknIUv""""" ߿DOp~FJ=]u?rӸ iwIT6 Y\?njhcz[~mW8Ap;|b.x۹):nಿ~7k<1 Z938Øۑ#M5-"""" /HX)Ѵ\c?`fn>v97VsG.*t.KgWm-SgtuDDDD,e'b+`۪GEftu`0j}\ы{F\yT""""'zv2Ng\ljXl]A 8"O&M 31dEO[DDD^Ɓd'A+X066AR$U͐M@/`&rG6 [Rfhm,O bGeR, W wo70q SIs:Rc1 m6&k\MHC6A F q EҠ0Ƣ$#hEx r< N'm SkkoY 1tϨv>҂bhߡbJ>u?Ĝ%7^OvlpM (^vq({w <&Fb{pf1م(Cqɒ)a<Ku{50؟FmaD~lZ2c]3:} cd7bQoLdGt6zyB¶'v -8p',NiɅą&_)n¯mn1 #+ɍu,!cZ{-'#]Q<*Ndm#)tϴQ}4^ύ*x-L>r?-;Iw$0Dܱ fLRñᎭ!WM"?h<7|Hc5:t=8v6q6yLP7=v;1釐X|GӚ :c9t@)aˡep5 W8hycZt#T|+Q0[R:]DGR+dȭWWՀ#a ö,'nE5^}-_hkTJ&XlQF8<|w4~rլp%EDD1YHwSL^TqvtRs:ie%ZZv߀,BU n7P>k( өU+q+0 I8y5mn8Bg'E^DU*~|sy_c܃#2>_|yk_Ogt2nodِT!#"""/Dv26LdxX/Mɭ 6dX'M v\C ZI۟!vRrBLޓb&LI#H]L'I`qw݀gL)/Kv|KcƊ?u̥k.Er"32{Z b;4LT.Q}cyEz+"""/lP<: & Hs$AaςH N434y'O3Y\q8?0$'mDz`V -ϝ_54uokwxk[x5?ݜŤƌ ҳ}^(0cxBv,n>W07R~;\vSZ_FZ 39C}mOmg";%sM}֑'?8Y])y{YNBC^ÿ_u'?Cgصm3[*msLv^O!ssJ'7qQNՉ:[~zgF+&rKQ~V^I6Hpq\v|ckxۻf.&Ʒ1tV.` c㡮(|?+ q0iLj2Nr.>W{=Y^XJj .:88.`H(Qͷ4g8w{ ,1~ďo_'58[1c#yyg3L)gOPtԧ1Ϻu%|$AsgxgmjcXVn{.CK)3>1.Kws?C%k)CdgrQ>V$v*i;\Tn2u9@}J5Gl'z缻HIӔ\.G&^k[jr9 xѻcrKI*8[޼BT{λj[DD,8 =lRz~XqH*zJǦ)6l1$I<7p@icOx-x湧kS d{! z-i8X(l'1ZM4!qs\0M$YBs?XvN&iH6nۼbH&k}>ฐS\R]k8,Rm{ڦ;5drI>GoWo{j r1 ^3~~fr&4QbY39n;]V8Men!AwαB8m0R(0%R75u N`pۦ1v_,p9|+Ŭ(%4?o}FdLBoOMO>J'i9Q_3m n|7V˱Ded%Gp@f=cˎ835lOGҘOwE&z.~4XF 79?9gA;ߜޚO0d9t/> MߖEDD^abp'+.K9Lspӎ<\A?LXeq,q5_'8g n;m IZ4l E%CyLvsʱGrZI'L(ex8"s0?ܞB` '雀oy"wq1׾E \{UwS'ٓ@΁joYl =ԍSoԙo\-""S8#5xى4f:9i>vl߈Ww:n&Ce۽BIfH-ZHZ,:y ]6wv-Å<8mrÝYq>|4w?'gǜsar1v fEDD1uX 64lxr-2[mX bmO2Դd[`Zk ftv\ILr6K NkTY;hvO3 v>s![qO; W)MKmb'מB.EQj^h8m[ Ć1~-fnw(eEN},TnlY2/;^gnK޳Rz't)p54-""RrҘe'$4uΧcΐS.x#l}k?!=jNq:u?̜=ǘs"wt|RS30) =x3xl#ZrӠaYw./ϖXWf6|s{kOKNr)L&`ti3 """ Ȑgxp(}Q8hck[s?}\rY[#uc{Ki.:9מu*nԢD  |&G' :BIRU~x 9>vv7oίG#Z a4ygfZ@~WϧOp}r*ܿ6bQlhHo5|ڳ1︎NFM_\ŗֶ`Y~ 軗ܔB V=v{:*=yޜ5߁ap(~Dq27'[1y|֡{w\;F-1tܽ# O\M,4na -""SSNwkmC2[kq\1D޲^ ~%cri/[g4&7Q۽U;muLB.ӰXkq]7.E2M-&'6ADed]#nu<p`f@!*XD cc$yޟ5 ""ҐǡV!QqFgb1"S\Z ''kolfe{BWڰ)lv_x2(&IШ~9SmT}7&Qwj!B0;ޏqoZ\ץV1<<̬Yagofر$I}E|LuEAXշ$!Wh_}#NlC[DD#I2^$j)8d8 W-~ieD|q &Bš<-ȶ`F[DD:tlݺjJGG|^SzΦMw?%ܱmd|a|';yZjM&6?q ǯ³JED]\\N{ i ~=#b,ȮCaPJbp{ k·LqS* S8󂂷j4kƅ|'N\]+5=9ƀSr]u ex95ڔ_JDDDD䕡-""""-""""XT-""jj!j !j-""jGuTϗl6[Z#<-""j˗/|r5*[DDDDD[DDDDD[DDDDDEDDDDEDDDD""""" """"" """""-""""-""""-""""" """"" """""-""""-""""-""""" """"" """""-""""-""""-""""" """"" """""-""""-""""-""""" """"" """""-""""-""""-""""" """"" """""-""""-""""-""""" """"" """""-""""-""""-""""" """"" """""-""""-""""-""""" """"" """""-""""{S}:Bӷv\.344DEO"" "ԠT(;w.Ay! (m6·$IB>g…XkS޾i&*QDDEu8CTR8---twwyf""2EiޅB|>OR8y:JB@P I5o&g q8]N%oA%"-2÷8XkIӴaJN Ub{6}zೀ㸸IC**N@w% QX'N-Ƹ6%_@Q)Wp9YnaiL$X ƘkĤٞp)ػxwo_o)jp-Q2{ى;3A)GRl@\-S1gNu=/u&U,k \l9K^$֝D6XalBXPN0vpgo7 x> Cebz;(ZJF>&"" "-Ii_';wgs[(qf ߿z3e8y2>iXbU]x[LP`9:["ܻf;ȰߩKcit¦-,8pƱ }lr& n~x ~"(|4\^n~[cMӿPs5zvs[>J͟෴O 9<.= f7;֐l;\ob.n L?RjIc.|\p}~Vmw췰,/j=}:#|禭wQu []w#{GY&qÔh4Noy4*s'p;45%% Edzb-ǩ p=3﨓pٹ'sڬfxpKO|uu\m%l~Fvzv бP:udnV=8McnKk!ӊ\8ta+8uyGS2i>&"" "Pt}?"V52,SNcMٽ쮙|7ׁ 2*aD`n i۲/  l@k2{:kׯfqVFwR!Oٽy upߦ2N}3>}V'H]H'""ADX=Lh[ZN[sܲVFq `ϣ>aƷQERcXiZuFWo_ʞf+Y3wGXq'ccÔcZWNL_y9鼋Xb(X?),8$:`fϞ5E~%g1!5S,"" "̦NK0yZ͚C 8̼ŝ\N A1rY~i,R -n۷R7ΙOa/֓oVfsm;n;o<+ǘsdK!_7ʢOGU80o+K{'r0Y_K띭niL#'OR44Vpp}  ,`eZ{βuk@!%Ud}iJE8~ž\& lJp܀l~Z!_h4޾wP#"" "ST*(}z~'HOfXco>wWlO/<ǜ>q^ā8W3j#IӔL&CT*\W'wLEDp0 !㺮Bu󌌌a DDE̷388HQV4M72yȑCyzF(|LٰKVBNW[ɋQ·8Z)Jr9\U`8'IUԗDDE䩌1OD~8JMDDD[8Eq""" 5··x)% pB~ aA-!"-<˾|ysh }Fxcj +)YIENDB`deepin-terminal-5.9.51+dfsg/src/assets/deepin-terminal/terminal/zh_CN/fig/closesplitscreen.png000077500000000000000000002070101475472654300324510ustar00rootroot00000000000000PNG  IHDRZ7A*D pHYs+ IDATxw|Žle mB/IHH'$/HI^ IHB  q`*ے,eq$϶l~ߏ0og;KZ[[!B!t"/>@!BW_wB!B;B!B' B!:a`B! wB!N#B!t!Bpp̍rӅ{1(q}DQƘ"lD ZW핪Y$m6u: 071cLUBN,˕jB!P;)$S.UP)Sdݨ4E]uFpa5' UBB媫SUUӴ\.lbAxln30Ǝa!BWf,ԙ.;gV <ppqqTMJDS @UT`h*$e#%{7*=ƉwgF2a(6&(+n 'S,;'VUURކ)( BCC$I>#xB)t; fJR02"8n|LR-S>ilOAI83r'ˮrUUUb#RU5UUU\JՉB!T ti~1F1:ƀQw(0 }cy`!&g='a`n$S.d*5hVc/*(+IRmmm*x JJt4*G!*O9LXOX׈;-PP TMMS?(#b9)<̙"UUy?z#BrT01JƁ~`:W7/i"NhH}֝ޓ?S )#'* |RNӲ@?Z^Lou B!t8 R5qtT.e[|N8/ TMh4wܝja隔+>r/G< 8 Om?ɖu#4_k$ Mh9I:˦9~8~[+B!\Y]s j&+7V+9OmO|O;UqwZ̆/kR2`21w88o^ե3 /q6VάM=sL8sKK2EbZ?iߛ{٥ef&{qP z\g6p 4!B?Lώʀv(epf.PԳ+*zrUš;:uAel^˗JVif!gMuyMH@WglAiD{XV4Uߦ,1[ WEWpҷ?9kȁؚ趞|ϔ]:?Dyg4emG/LƉ#Bh^{[pg}gX=>ze DfA?{˷6Kv˶HqVLr&3Yo|h1H:ulh=M/QoNڕZ$mBڤdNHÅJz!5/O=Y¾eUn?)FC$zƪ=t2Id1$9+sUB#q0!##ݡg( Pt1ĞGv3\Wsﭚca^:g8cߜ1_^g_pʳrki߁s"~S>ؾ;7Y/ܗ Ind3'~{mZLnk0m}u]Z7Ls3Q֏#g1uEhUJ(X3g$Nq blms@4= w!ș 4My(_|{ަ_i<hU#Bȕ0SH +CŰ936aެK+_B!FH"]{;Vz/3Swݵ74ܕWxxt&jr "={f }Э;s]mt|YTE:M}Mصe[p">`3oKgY56j Dr7M"=5ڠIRG \I"qeӭs]3 M|GF+-IoJ%%,0Cf=2.T7~_~Ǧ1!+C3TN {Zu!]!;a]A{Uo g3]Jeok=vg6@  ?Xf o r Y}s5Xn_OVKjlh 즐MR\ah|S~0 ZTe g:r6nO"FY[M2o'ҢōwnO=%[~vŔ'Mzi_Z+t x*B1֜@*Cm@5P8 OBn⹜(tOoCr7O=|P@tmg'ζO!ٿn-$X\oc֥ |NX4^lMj䂷-bZtzQ0` >yI3h!RHБNef4;Z}E @r1臾h()hG2[o-vkI{W@Il]x׿XytoRO q@r4}\?BAc3@Yc}@I:" B&Mp~*lP6ܿѮxJ]b횚fۇ}r W,?L熺FN O?oitZ7A̬`[V=TlBNKy@Tyx߻kC\ZjYZ'0YLT E u߆hG7zϣmSg zƪ &u!uL[2Zi5c !B+y'e "sδLwi@{f[l!^ۚ&,Ckɩy?ue/ݰ:b?hN8]SGPavjPST"JG'!B'z"2J5Kh0we*ܧT,ژj._N=vIU ?`oO/֊>lTj'Xfվ=κG=6wp~kwov֜@Љץu8Z{{q-q9ybۥc^ >̱^4ER &oLf QŮiZXx&l"l\FwB/ầ%B!rgRQ#'_|aY\p<338 ΌK(#!K-6%7d/',d[jݸ#z@:;nMFj6Ѷ]Y!Ӌ*tر.!Bh^}rG5Ph' a]ӽ uݐS}*c( =2 X1u-{Ym`xfƜ>Ax:X.=4,:Tk ;B!P )рpt]J #@ـ䙮aL`vT-ܩ2ӱ̣q2&duSn̵tgM@쀆lnؽu 1!BcJYTĘ b7?l_ɀᆬ+D Sdm _lBqt^ץ+Rm,K&nh4FAwbZ(d84!Be5c?ѥu;?ޭ@G !R*r$YT!BUQtc nBʙy!B!t\`B! wB!N#B!t!B!B0( ǻ!*NX tZn N8-Ae7]B!tN'o8M3!t€3-ﺊP Ɔ~W ;6 N4#FawV ͏l|6Js}-? ?IЌ޼ź~?- =?8g_yjO΍3w݄/\uMstiJ^pn<|8iFR-9QY2Kbf$.:/xzՒ'D>韛,u4 ̑O]OckݭuJcl.3t6j':wy~e魓pDh_@+_eî jS+qQu ׳zrXԘ&R8xT>p!LWQo ][EhłdqR2)1knƣ oh&Fq+ڌauj6Utиkog׾'6li|oܽu0RΩSWG ~; -ޒ p4 !0>^*3zLSf#z1ô) Pv'l? 92*UDna3/]ǧo\C Іu^l4xnP ;,*\Qp Xai$Ye=eE:-J5lU$~$QCRũ p~؍_mUo'bQyy/%*|,V;7JyN(z5iK5BTbkHͫRꚓW[h|&!RjX읓<0nͿrMq2t "EOĝVk A72!+5L"|qNqkS;#qO|Uҥs_[D @ԗaIFAt==u¹t@([~Bq=~SÇn[UFXݿJ˝a'nczRcG^}S [BKcG<ֽ~aީqh¹fS<7ۙ;`ܗ*o?,UaR]fS_ml!$uyS l+,ۤ#>7@]:B'z%Öנ4"`ܸIgny՚+眿,9'@ nz8O:.^T; 8սApIYWv{B73X,c<_3H Ss/c.Q#A?wA6^xQr}׷sokIFd)>ǚ`jC%ɍbnSL: ƶ a Bh4B3抎[eQ$t@%좖=pf(nuWSUMMTJdqgJDN쏹sKuuD`T?7vORgS.!2 -b9xr 3A9hZ5s?\oۘoѠ Rhl@G||X$YHU4W~xa3O V1L~8R (9qT3CW'g+ Bo`JAI:f'o kB`X4 ]Uvߺb}ӆUn܅+>GHb9qgDme@-{Xź_S|k`Iv瞟1Qݾ r0l)晙g-o쁉6EU!ݳU4!˿p̚1:9 Sg@MM;~rWĪ&’4W+@tv=Rh4.Qn7Q"MαCumHRT`F>NWTŊ7"9B1bS5x94puI:{hy԰$|=Pe8}t5l#)JfU\9zc;/KYYl $j(D:jC򃿒ux .G`߇e@m?Fq ֝y=UBCĥ Ek#o涽ѽX[F/J\S2 IDATVmI#!k"kNaIhH3 bTq0-$n^u}[ݞwDŽյ5I%Zm]ad{mKOs5yj2r j|SSYzP28f"@RYqP7C84GF@xWMd\Q.j-A]sh:|`AhVoh"O祿ۼӘתq~f4C o-Ǟf%'2r=V5sj\]y=& 6Ӟ pVq@(-뙝;X/-ѹK֤Ҿm'--lM}݋ɼ!  ]Od H"Z&v:;d t$Tui@J eo~Ѡc@گ-KRF6} $G7eUԠteolWF;<)u4h$dr=hrI劎H zLMRզg BF?Iի2_ȟM QZW~= Sa0咘vZ zj#½9 $*|^5 <'\O4l)88eW{dMN`-Vo.3*< Pt@QN[\gW|cP)*sW-8I+4dc׌_zGYWOŦue y^ƒ0XPn (-yЯ"`zm䎹9%8& FAEU(ו /wgd8!RTSekH~&E)[|/'7Q=Q_^=+t]`X*)wܻD8ړ$r(pƒ_YRf`D|<3(Ɩ„Yifw$-]>b{kugNaK1!q%Ւ[z=i3i-9 4 4>wTyST ftNĤG|H+q>1ZUV/ )q?EBcP0Z7 qh|/FG@T B%)HS3 @EC3Xb4 \[cϛwG0r޽M5)AyӒ4 ̭AXL9_Z!g;یQ3R3@U3P`sÕ:q 5S볩kb)faG}=G|L0OڭMrnF^luCf:p KwPW6zvt?L~Yݧ&8S u1`0qn:>+5N[&uٹް3!8'罶C`p֯iJ(=;u5uϪׇ "s]VɫDŽyI`9=3^5)qncWNMWG}'Z0I0e/Z=mi= W&Ξ?Yq]d)%ǰp0RLML#:(r!vR657;kf$#FZ[<q60?#~!YZk yԴ["@t$E%R]UfKaLգqS%.':WbPM[ߓK3g5@2&h/٫ʷ&_<@G(5QYb&@ZgleGg# %g6̟婄Ug{gV2Gl~XQC# r}$-DXW]Ȋ@ ҒamUsQ'`#B 97 &&D2| Y$hƉlox*+~BJa\XbaN3.7vK#y^K|+5Q%/ŗf ^ʧSׅcgd3p7]*Nt|'*羽ckUopwU+] mH>O*(Fb:.J0ezjCV`.$&d4q8~! +c}3cwkqVm1*5qP)ͪe} Z`FSiЧ:t\ѽ#LȗR/V J^h2l)ӳJGL3mjP;ݢ|W.5) -B&}=ߌs&x_@e!BG 4|P(W $?'lUSSUMMSJOMvs'T+q'w(\_. I:N}jfS# -}9ܒ7Z3&5P>15RcG"H~CerA zeFR=;`njLѲ5}W՗N͟KtMKVXhP*7ہ3 :1L*~OtDb[o|7`&zNG6kB<z;b9?9;w:=t$ַM !B!&h竜$!.^ܳY8Ais\\SDP( GDΑ(5 uߛsbe6Gzz4Y)lbeOe˥P:#Q¥92d`Dϕ<V}XnQ5`K ^ &*M9J #T⁛T.Cn[#TGa=8Ts[Wh_9[okG2I{;Jfg Og}<Ƿyfok0--k~Q_:%g>/]rtxmk+9ӖSރkb=#/c|(睇2nTŧޖlj~`KK TzY!a*/xtfn4[A1*,ʹƔUe7/uv}[TUrgv?Bt"ͤ MiwM9׮<{ד-rOץSN9V0Fx.1NHB<Ɯ#/># }}m8% 2lVo}ľN4(dሦ5Ѐz@oY[g,X{|L-?S_4`6el -ܒ ZmJnQdxɺVH\lm1ތcnjDJ澏 'H cER~)(ҥx;(G9.{,C""T@;p~* } }SBWoٽǟg~3DŽ37hL^j؍'(9(,BQQUQ=]r(.E)) rrk^KRWKɆۃ/fpaI1TY|9:3Z*S ӈWOV2ݎ fr1ߌcNx0eO:a9_t8`#][[=5U0_Qc<XEFr%v(t>[ }U˪,#]rPwL1iD8HRIl0/]-jٻk~0s}N2Mk,vA4=TNW 3jk$^B!4z@h]/>OW4_M?-QM P&I~UvM4sr'__egYWB;:NpS@€@0ɘYg;m>5N=,o8`Ʉox෻_o-dv)yܺzt&@j;\#^8-ĕyYgto X1C6yE&?}mnp,5vQYb&kZL`lF 8sH@ /6 lԮHƭ:%M8F'չ=gJQ8_Mɷ" oW0I9B82?Zrߣݗ.gڼFi>ؤ/no\unۗ4s[/_7Ω K3 8kf:Z}-kݳgܺI@羟~AWRTοk;]yd/n*>UbY!a#^xnB'66/Zp>n,r꒘r''8җ?R@Ygʦ7D%./ONyxBGUp2*6Z]f |#ɒmY3f=2!! w*Q2+:&ُO1f76KUo-O-q-׮;A :YaP"il2mOڪ%OnowB0|GX/x }ϿwV d\B!N#B!t!B#tLG#CǿƹqB!t"}c4ֽ)<-\'}8l'C: q-klg(T5LTQV4'vϝLҾvB{%1g.yi,4h"7!y^K|Ҝ+514N^^ͻ(o<+B1t"4Q("w1.7q#e0;B5xlGXp[s+c9θw" _V *xPڐ},UP,t7]FP_íb:9u]8vfN6Л_qA5gÃˌ"Q%'U[g:@L7͞8!GCoOmV/`>[ͷmǨoP1u<~/46(vFZ΍o <$-UXoDԳu~+p`̡uf,`b|~)1jC!Y:QVIAa7~L F׽];T]%Vҟ_5NK>V"$hj](K4g4l :ɱﴇR Dz*^UzP>+p#+?7ذ6ֿVV~E+,Q{K kc?~Tk-ֻ,C{ǕF4a#(;Bscjԥ`3Ĕs97yvύT!JjY{5!ZfT^R6E;:|r[UkGX[nͭ,hN/} jj~GjZG9ѽVUaYNթ r ߯ fumaV/](q5_9k]溥 ԃGڂm1\9c-V~H^|ߟgDS7j$+2[%b ??gY`x=K4wȔqs(-0`ot7|=( ZP<BdJOrZKms6[=5:U4D:ELtYd7w2NRWXf*^aA~(oȱ 喤fD`Ԛ =WvyQ(o6 _d]K0g&(_8hs"E1SSb{k bIQ3 @p>z mG@Nώ%]:&]EnEqq>ERS(A)Yk[u Sd IDATӤXV~yNVbeOe˥P:sC Ȑ 4w?W4}9I U9 0e#IxALm[Y==tu"N |-+4/+(W ^ &*M9J G԰B鸬rqj^j^߱e_l+ :-(r[y<Д,e9Q{XV{O0UQzGH0W`:XG橞S !*K;Qn F"; H'3$VP:K31gdEKgwWtt#:,jzS~wtI2QWȆY}GfUd`Lrbb_MQFh`:j|C$n l`j2̥>=`SӀIU_-  Wv?6֮@f~nDEC폄I lrn2pW(]4zRt|tmQ}Nq?L^Nœ}lVSIzn|{3pis :|_7?<Π~8^f$AFSىGzF #W8BR12YgdcnIm-^fD2۪ox6 DI|)ig`}ǒR6q<˚|N8Xt}&R`vMe7IRn5\0u~4L}R֠B̎.`;]]AuH8#: 2TFzBffD59"_u(3Gv^BH$*2 waRTS[6ӳʀ *(K4J4 jq7dѨQ\c/7h41Db4zeDvk;83=38LWwު:uJo}5UF Bh@}r Cy!HDN׭U\VN0T Xia|;@f&1R_yu_t2ybNNyeNf>ucߏ0 U-FdX0dvDĢ;3?-滊nQl"L4jHXU0jccbʦdZpN B!}TEϱMZ9`sjS p$*p}&c&ss"5U*eT*EO4Bs(pgi "h3/ESMbR%9V  # E~M(%Iy63D]%ϯuZ¸|~\>?N5`syEßSˣy\SAl̥.Q4aE H3ٵZWνvbW1V*sWn1'"/2p5䳿&ѝWtM:[4x;40 O!g)?}qtwl'<7T[L-2B!tR#b Hs1@x?R {DWK$E;S"T<i-Pf_bm-HZVgiե}}){OS*O6ZZB@pZfPQzc$H\mwռb:~> _J+^>|MO\bi< -3ԥ9rv`(W%fupo e=QR h :9'ϰŖ-;h W-2b0ϗF]{ ?n0x8#m,ߟ9|_iS@mpCcR +OWs}OR♏Ҥ)7[c' ^QR⹏!9|Zs(|fw? !-^N3=7v>ݢr[)~7Kt/ՖAOpx6ygB֯_?tF߅-,FtN&B!T,:صurOM'#BưSO.= B!P9!tZ˯޳mB!4j!B!B6|G!B贁c]>LgtཊV|ׅ"B ɀ4CG"v͏X-^Ѩ,:t(;׀΀4NiwM~?/EM㯜<r{n-KgNMI׻C%d9t0 ғK=AИf}=,$XH铖AoQi++O!`m!yS$>'/i bΈ;#T DXu+2NU7NK :|':9W̼ @ԊΐR]#M~4y1~h&u Ѵ;c tXaR|{{JvWP _ eZe'fZW|J8!@ZK_#/'ҝ# H (lUl2NPuMk֏VE&U*Y-9뤻wTeLlE7%?|$4bVZO}xj BU&*Un.7\ٙg.aD:]Px8_J.x HU ̞gswcCn 0GFK:5-&ʙ6R? yM.}U¤2`!5;0Cp=6NXNc4R%Uyn YSD*]r'J dOY'h 3O* 0a^= lyBͺ*~FYr"Թ>aN9^c`+4g;SʀoBݺgKd_ff֒T 턵MWY_$Dbp!*2j[ 'J:D_Rl&G?(͑[sj3;L©Fze"ya r{kIch:- `qk3}` ފ/u^davE6s_9(10jό$ZV7hNFxjZR)>iw1$tS>Ld_רcPGS%Xu4X؄BP@^&@ǽӷc2lZk>ʎI";P@uI :5:] l'~!4jPV12vC}nnR)K2`\rj1j$Q&YEM_ė1l6o2$_탤ZcKȬ􅾩4FKAVN%Q9>Si|[lo[SoB^60VNN@^p9Z3K'@L%d4{1B20yy+:,)f)0?aPP >+PsS >=l~zNx@=;l|m>dr$_NRK,jQrtnk.0.ϏeMMl͉Ld߿,"T5Sy>A@؞r͡e}A]՘Ocu0<+$qj"dl=1(En4&"BҜAv?eFҚr=K.me"У;: i^%گ5[=/:n :eincU D#W:oT!%xkd¬n*oi-Pf_bmeUL,:2\@k2.+,IϫaXI/ F US'NWbT;{c{/gWCю߿wٽS +NҪP>,>{f{rԼۼ:osV!ڹ߼m3x7νH6>ᇭe/B!T&ֶx; NoLB1r[X}-:^ 7|Y [WVTN3~_FhaAwT0ku6aB `ڪȓzk!Bg&DB{\!B!P`B!iwB!NX#B!t!B>yctFޫ8kΗQ!Bg l_iԁQDϊ~`_mCeQWuAv2`3 k]e9*9*Hߴ/6h@\vA?!(\rigvNR&5teiő<65aNk5Ө0c!43;':GGHVN{<~jxkVLrKu璗 چyՉԂd$ѿpse"ťՠ-a`~~+O:;,[sË9oh%䜙W\7^tᛇD!Ј`^)pi$YiD4To`nKQj5Ө C6;c?o9SviFoOw_?/ʤ7Ý+RdYӝBY)atOSeR"Pn="+Gr4 aS?}oOb^~7Ǿ |@0ʐOI8VcBVM%{vF&@N'BWf%-ce/nρumOhusyȩ!F,`]͛Pޚ$?5EkM.ЭbIuFcsp۽y~_[Z 8\ Տ[4F-\IuYeM9=rnɓ,_jɟsa%: f>{Ty][ʹ0Hp2_׻?