├── AUTHORS ├── CHANGELOG ├── CMakeLists.txt ├── CONTRIBUTING.md ├── Doxyfile ├── LICENSE ├── README.QTerminal.md ├── README.md ├── qterminal.appdata.xml ├── qterminal.desktop ├── qterminal.pro ├── qterminal_drop.desktop └── src ├── bookmarkswidget.cpp ├── bookmarkswidget.h ├── config.h ├── dbusaddressable.cpp ├── dbusaddressable.h ├── fontdialog.cpp ├── fontdialog.h ├── forms ├── bookmarkswidget.ui ├── fontdialog.ui ├── propertiesdialog.ui └── qterminal.ui ├── getopt └── getopt.h ├── icons.qrc ├── icons ├── application-exit.png ├── document-close.png ├── edit-copy.png ├── edit-paste.png ├── index.theme ├── list-add.png ├── list-remove.png ├── locked.png ├── notlocked.png ├── qterminal.ico ├── qterminal.png ├── zoom-in.png └── zoom-out.png ├── macosx ├── bundle.cmake.in └── qterminal.icns ├── main.cpp ├── mainwindow.cpp ├── mainwindow.h ├── org.lxqt.QTerminal.Process.xml ├── org.lxqt.QTerminal.Tab.xml ├── org.lxqt.QTerminal.Terminal.xml ├── org.lxqt.QTerminal.Window.xml ├── properties.cpp ├── properties.h ├── propertiesdialog.cpp ├── propertiesdialog.h ├── qterminal.rc ├── qterminalapp.h ├── tab-switcher.cpp ├── tab-switcher.h ├── tabbar.cpp ├── tabbar.h ├── tabwidget.cpp ├── tabwidget.h ├── terminalconfig.cpp ├── terminalconfig.h ├── termwidget.cpp ├── termwidget.h ├── termwidgetholder.cpp ├── termwidgetholder.h ├── third-party ├── qxtglobal.h ├── qxtglobalshortcut.cpp ├── qxtglobalshortcut.h ├── qxtglobalshortcut_mac.cpp ├── qxtglobalshortcut_p.h ├── qxtglobalshortcut_win.cpp └── qxtglobalshortcut_x11.cpp └── translations ├── CMakeLists.txt ├── qterminal.ts ├── qterminal_ar.ts ├── qterminal_ca.ts ├── qterminal_cs.ts ├── qterminal_cy.ts ├── qterminal_da.ts ├── qterminal_de.ts ├── qterminal_el.ts ├── qterminal_es.ts ├── qterminal_et.ts ├── qterminal_fi.ts ├── qterminal_fr.ts ├── qterminal_gl.ts ├── qterminal_he.ts ├── qterminal_hu.ts ├── qterminal_id.ts ├── qterminal_it.ts ├── qterminal_ja.ts ├── qterminal_ko_KR.ts ├── qterminal_lt.ts ├── qterminal_nb_NO.ts ├── qterminal_nl.ts ├── qterminal_pl.ts ├── qterminal_pt.ts ├── qterminal_pt_BR.ts ├── qterminal_ru.ts ├── qterminal_tr.ts ├── qterminal_uk.ts ├── qterminal_zh_CN.ts └── qterminal_zh_TW.ts /AUTHORS: -------------------------------------------------------------------------------- 1 | Project maintainer: Petr Vanek 2 | 3 | Contributors: 4 | 5 | Alexander Sokolov 6 | Alf Gaida 7 | Christian Surlykke 8 | Daniel O'Neill 9 | Erik Ridderby 10 | Felix Schnizlein 11 | Francisco Ballina 12 | Ilya87 13 | Jerome Leclanche 14 | Johannes Jordan 15 | Ludger Krämer 16 | Maxim Bourmitrov 17 | Mikhail Ivchenko 18 | Sweet Tea Dorminy 19 | Vladimir Kuznetsov 20 | Matteo Pasotti 21 | @kulti 22 | 23 | 24 | Translators: 25 | 26 | @pisculichi 27 | Sérgio Marques 28 | Valter Nazianzeno 29 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.1.0 FATAL_ERROR) 2 | # CMP0000: Call the cmake_minimum_required() command at the beginning of the top-level 3 | # CMakeLists.txt file even before calling the project() command. 4 | # The cmake_minimum_required(VERSION) command implicitly invokes the cmake_policy(VERSION) 5 | # command to specify that the current project code is written for the given range of CMake 6 | # versions. 7 | project(qterminal) 8 | 9 | include(GNUInstallDirs) 10 | include(CheckFunctionExists) 11 | 12 | # qterminal version 13 | set(QTERMINAL_VERSION "0.14.1") 14 | 15 | option(UPDATE_TRANSLATIONS "Update source translation translations/*.ts files" OFF) 16 | 17 | # we need qpa/qplatformnativeinterface.h for global shortcut 18 | 19 | # Minimum Versions 20 | set(LXQTBT_MINIMUM_VERSION "0.6.0") 21 | set(QTERMWIDGET_MINIMUM_VERSION "0.14.1") 22 | set(QT_MINIMUM_VERSION "5.7.1") 23 | 24 | find_package(Qt5Gui ${QT_MINIMUM_VERSION} REQUIRED) 25 | find_package(Qt5LinguistTools ${QT_MINIMUM_VERSION} REQUIRED) 26 | find_package(Qt5Widgets ${QT_MINIMUM_VERSION} REQUIRED) 27 | find_package(Qt5Network ${QT_MINIMUM_VERSION} REQUIRED) 28 | if(UNIX) 29 | find_package(Qt5DBus ${QT_MINIMUM_VERSION} REQUIRED) 30 | find_package(Qt5X11Extras ${QT_MINIMUM_VERSION} REQUIRED) 31 | endif() 32 | find_package(QTermWidget5 ${QTERMWIDGET_MINIMUM_VERSION} REQUIRED) 33 | find_package(lxqt-build-tools ${LXQTBT_MINIMUM_VERSION} REQUIRED) 34 | 35 | include(LXQtPreventInSourceBuilds) 36 | include(LXQtTranslateTs) 37 | include(LXQtCompilerSettings NO_POLICY_SCOPE) 38 | message(STATUS "Qt version: ${Qt5Core_VERSION}") 39 | 40 | # TODO remove Qxt 41 | message(STATUS "Using bundled Qxt...") 42 | set(QXT_INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/src/third-party") 43 | 44 | CHECK_FUNCTION_EXISTS(setenv HAVE_F_SETENV) 45 | 46 | if(APPLE) 47 | find_library(CARBON_LIBRARY Carbon REQUIRED) 48 | message(STATUS "CARBON_LIBRARY: ${CARBON_LIBRARY}") 49 | elseif(UNIX) 50 | find_package(X11 REQUIRED) 51 | message(STATUS "X11_X11_LIB: ${X11_X11_LIB}") 52 | endif() 53 | 54 | add_definitions( 55 | -DQTERMINAL_VERSION=\"${QTERMINAL_VERSION}\" 56 | ) 57 | 58 | set(EXE_NAME qterminal) 59 | 60 | set(QTERM_SRC 61 | src/main.cpp 62 | src/mainwindow.cpp 63 | src/tabbar.cpp 64 | src/tabwidget.cpp 65 | src/termwidget.cpp 66 | src/termwidgetholder.cpp 67 | src/terminalconfig.cpp 68 | src/properties.cpp 69 | src/propertiesdialog.cpp 70 | src/bookmarkswidget.cpp 71 | src/fontdialog.cpp 72 | src/dbusaddressable.cpp 73 | src/tab-switcher.cpp 74 | ) 75 | 76 | set(QTERM_MOC_SRC 77 | src/qterminalapp.h 78 | src/mainwindow.h 79 | src/tabbar.h 80 | src/tabwidget.h 81 | src/termwidget.h 82 | src/termwidgetholder.h 83 | src/propertiesdialog.h 84 | src/bookmarkswidget.h 85 | src/fontdialog.h 86 | src/tab-switcher.h 87 | ) 88 | 89 | if (Qt5DBus_FOUND) 90 | add_definitions(-DHAVE_QDBUS) 91 | QT5_ADD_DBUS_ADAPTOR(QTERM_SRC src/org.lxqt.QTerminal.Window.xml mainwindow.h MainWindow) 92 | QT5_ADD_DBUS_ADAPTOR(QTERM_SRC src/org.lxqt.QTerminal.Tab.xml termwidgetholder.h TermWidgetHolder) 93 | QT5_ADD_DBUS_ADAPTOR(QTERM_SRC src/org.lxqt.QTerminal.Terminal.xml termwidget.h TermWidget) 94 | QT5_ADD_DBUS_ADAPTOR(QTERM_SRC src/org.lxqt.QTerminal.Process.xml qterminalapp.h QTerminalApp) 95 | set(QTERM_MOC_SRC ${QTERM_MOC_SRC} src/dbusaddressable.h) 96 | message(STATUS "Building with Qt5DBus support") 97 | endif() 98 | 99 | if(NOT QXT_FOUND) 100 | set(QTERM_SRC ${QTERM_SRC} src/third-party/qxtglobalshortcut.cpp) 101 | set(QTERM_MOC_SRC ${QTERM_MOC_SRC} src/third-party/qxtglobalshortcut.h) 102 | 103 | if(WIN32) 104 | set(QTERM_SRC ${QTERM_SRC} src/third-party/qxtglobalshortcut_win.cpp) 105 | elseif(APPLE) 106 | set(QTERM_SRC ${QTERM_SRC} src/third-party/qxtglobalshortcut_mac.cpp) 107 | else() 108 | set(QTERM_SRC ${QTERM_SRC} src/third-party/qxtglobalshortcut_x11.cpp) 109 | endif() 110 | endif() 111 | 112 | if(WIN32) 113 | set(QTERM_RC src/qterminal.rc) 114 | else() 115 | set(QTERM_RC "") 116 | endif() 117 | 118 | set(QTERM_UI_SRC 119 | src/forms/qterminal.ui 120 | src/forms/propertiesdialog.ui 121 | src/forms/bookmarkswidget.ui 122 | src/forms/fontdialog.ui 123 | ) 124 | 125 | set(QTERM_RCC_SRC 126 | src/icons.qrc 127 | ) 128 | 129 | qt5_wrap_ui( QTERM_UI ${QTERM_UI_SRC} ) 130 | qt5_wrap_cpp( QTERM_MOC ${QTERM_MOC_SRC} ) 131 | qt5_add_resources( QTERM_RCC ${QTERM_RCC_SRC} ) 132 | lxqt_translate_ts(QTERM_QM 133 | UPDATE_TRANSLATIONS 134 | ${UPDATE_TRANSLATIONS} 135 | SOURCES 136 | ${QTERM_SRC} 137 | ${QTERM_UI_SRC} 138 | ${QTERM_MOC_SRC} 139 | TRANSLATION_DIR "src/translations" 140 | ) 141 | 142 | include_directories( 143 | "${PROJECT_SOURCE_DIR}" 144 | "${PROJECT_SOURCE_DIR}/src" 145 | "${PROJECT_BINARY_DIR}" 146 | ${QXT_INCLUDE_DIRS} 147 | ) 148 | if(X11_FOUND) 149 | include_directories("${X11_INCLUDE_DIR}") 150 | endif() 151 | 152 | 153 | # TODO/FIXME: apple bundle 154 | set(GUI_TYPE "") 155 | set(APPLE_BUNDLE_SOURCES "") 156 | if(APPLEBUNDLE) 157 | add_definitions(-DAPPLE_BUNDLE) 158 | set(GUI_TYPE MACOSX_BUNDLE) 159 | 160 | # create Info.plist file 161 | set(MACOSX_BUNDLE_ICON_FILE qterminal.icns) 162 | set(MACOSX_BUNDLE_INFO_STRING "QTerminal ${QTERMINAL_VERSION}") 163 | set(MACOSX_BUNDLE_GUI_IDENTIFIER "com.qterminal") 164 | set(MACOSX_BUNDLE_LONG_VERSION_STRING "${QTERMINAL_VERSION}") 165 | set(MACOSX_BUNDLE_BUNDLE_NAME "${EXE_NAME}") 166 | set(MACOSX_BUNDLE_SHORT_VERSION_STRING "${QTERMINAL_VERSION}") 167 | set(MACOSX_BUNDLE_BUNDLE_VERSION "${QTERMINAL_VERSION}") 168 | set(MACOSX_BUNDLE_COPYRIGHT "(c) Petr Vanek <petr@yarpen.cz>") 169 | 170 | set_source_files_properties("${CMAKE_CURRENT_SOURCE_DIR}/macosx/qterminal.icns" 171 | PROPERTIES MACOSX_PACKAGE_LOCATION Resources 172 | ) 173 | # use icon for app bundle to be visible in finder 174 | set(APPLE_BUNDLE_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/macosx/qterminal.icns") 175 | else() 176 | set(TRANSLATIONS_DIR "${CMAKE_INSTALL_FULL_DATADIR}/qterminal/translations") 177 | add_definitions(-DTRANSLATIONS_DIR=\"${TRANSLATIONS_DIR}\") 178 | endif() 179 | 180 | if(MSVC) 181 | set(GUI_TYPE WIN32) 182 | endif() 183 | 184 | add_executable(${EXE_NAME} ${GUI_TYPE} 185 | ${QTERM_SRC} 186 | ${QTERM_UI} 187 | ${QTERM_MOC} 188 | ${QTERM_RCC} 189 | ${QTERM_RC} 190 | ${APPLE_BUNDLE_SOURCES} 191 | ${QTERM_QM} 192 | ) 193 | 194 | set_property(TARGET ${EXE_NAME} PROPERTY CXX_STANDARD 17) 195 | # force Unicode over Multi-byte 196 | if(MSVC) 197 | set_property(TARGET ${EXE_NAME} PROPERTY LINK_FLAGS_RELEASE "/SUBSYSTEM:WINDOWS") 198 | target_compile_definitions(${EXE_NAME} 199 | PRIVATE 200 | "-D_UNICODE" 201 | "-DUNICODE" 202 | ) 203 | endif() 204 | 205 | if(HAVE_F_SETENV) 206 | target_compile_definitions(${EXE_NAME} 207 | PRIVATE 208 | "HAVE_F_SETENV" 209 | ) 210 | endif() 211 | 212 | target_compile_definitions(${EXE_NAME} 213 | PRIVATE 214 | "QT_USE_QSTRINGBUILDER" 215 | "QT_NO_CAST_FROM_ASCII" 216 | "QT_NO_CAST_TO_ASCII" 217 | "QT_NO_URL_CAST_FROM_STRING" 218 | "QT_NO_CAST_FROM_BYTEARRAY" 219 | ) 220 | 221 | target_link_libraries(${EXE_NAME} 222 | Qt5::Gui 223 | qtermwidget5 224 | ) 225 | if(QXT_FOUND) 226 | target_link_libraries(${EXE_NAME} ${QXT_CORE_LIB} ${QXT_GUI_LIB}) 227 | else() 228 | target_compile_definitions(${EXE_NAME} 229 | PRIVATE 230 | "BUILD_QXT_GUI" 231 | ) 232 | endif() 233 | 234 | if (Qt5DBus_FOUND) 235 | target_link_libraries(${EXE_NAME} ${Qt5DBus_LIBRARIES}) 236 | endif() 237 | 238 | if(APPLE) 239 | target_link_libraries(${EXE_NAME} ${CARBON_LIBRARY}) 240 | elseif(UNIX) 241 | target_link_libraries(${EXE_NAME} Qt5::X11Extras) 242 | endif() 243 | 244 | if(X11_FOUND) 245 | target_link_libraries(${EXE_NAME} ${X11_X11_LIB}) 246 | endif() 247 | 248 | 249 | install(FILES 250 | qterminal.desktop 251 | qterminal_drop.desktop 252 | DESTINATION "${CMAKE_INSTALL_DATADIR}/applications" 253 | ) 254 | 255 | install(FILES 256 | qterminal.appdata.xml 257 | DESTINATION "${CMAKE_INSTALL_DATADIR}/appdata" 258 | ) 259 | 260 | if(NOT APPLEBUNDLE) 261 | install(TARGETS ${EXE_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}") 262 | install(FILES ${QTERM_QM} DESTINATION ${TRANSLATIONS_DIR}) 263 | install(FILES src/icons/qterminal.png DESTINATION "${CMAKE_INSTALL_DATADIR}/icons/hicolor/64x64/apps") 264 | else() 265 | message(STATUS "APPLEBUNDLE") 266 | 267 | install(CODE "message(STATUS \"Cleaning previously installed bundle (rm -r)\")") 268 | install(CODE "execute_process(COMMAND rm -r ${CMAKE_INSTALL_PREFIX}/${EXE_NAME}.app)") 269 | 270 | install(TARGETS ${EXE_NAME} DESTINATION "${CMAKE_INSTALL_PREFIX}") 271 | 272 | # helper stuff to create real apple bundle. 273 | # Black magic is summoned here... 274 | if(APPLEBUNDLE_STANDALONE) 275 | message(STATUS "APPLEBUNDLE_STANDALONE") 276 | configure_file("${CMAKE_SOURCE_DIR}/bundle.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/bundle.cmake" @ONLY) 277 | install(SCRIPT "${CMAKE_SOURCE_DIR}/bundle.cmake") 278 | endif() 279 | 280 | # bundle required keytabs from the qtermwidget package as well 281 | install(CODE "message(STATUS \"Bundling (cp) keytab files from ${QTERMWIDGET_SHARE}/qtermwidget/\")") 282 | install(CODE "execute_process(COMMAND cp -r ${QTERMWIDGET_SHARE}/qtermwidget/ ${CMAKE_INSTALL_PREFIX}/${EXE_NAME}.app/Contents/Resources)") 283 | 284 | install(FILES ${QTERM_QM} DESTINATION ${CMAKE_INSTALL_PREFIX}/${EXE_NAME}.app/Contents/translations) 285 | endif() 286 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Bug reports 2 | 3 | Please file bugs on the qterminal github tracker: 4 | https://github.com/lxqt/qterminal/issues 5 | 6 | Please file qtermwidget-related bugs on the qtermwidget github tracker: 7 | https://github.com/lxqt/qtermwidget/issues 8 | 9 | 10 | # Code contributions 11 | 12 | For all code contributions, please open a pull request on Github: 13 | https://github.com/lxde/qterminal/ 14 | 15 | Make sure your code is clean, devoid of debug statements and respects the style 16 | of the rest of the file (including line length and indentation). 17 | 18 | Do not pollute the git history with unnecessary commits! Make sure each of your 19 | commits compiles to ensure ease of bisection and have clear separation of one 20 | feature or bugfix per commit. 21 | 22 | Please also make sure you set your `git.name` and `git.email` options properly: 23 | https://help.github.com/articles/setting-your-email-in-git/ 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | -------------------------------------------------------------------------------- /README.QTerminal.md: -------------------------------------------------------------------------------- 1 | # QTerminal 2 | 3 | ## Overview 4 | 5 | QTerminal is a lightweight Qt terminal emulator based on [QTermWidget](https://github.com/lxqt/qtermwidget). 6 | 7 | It is maintained by the LXQt project but can be used independently from this desktop environment. The only bonds are [lxqt-build-tools](https://github.com/lxqt/lxqt-build-tools) representing a build dependency and the localization files which were outsourced to LXQt repository [lxqt-l10n](https://github.com/lxqt/lxqt-l10n). 8 | 9 | This project is licensed under the terms of the [GPLv2](https://www.gnu.org/licenses/gpl-2.0.en.html) or any later version. See the LICENSE file for the full text of the license. 10 | 11 | ## Installation 12 | 13 | ### Compiling sources 14 | 15 | Dependencies are qtx11extras ≥ 5.2 and [QTermWidget](https://github.com/lxqt/qtermwidget). 16 | In order to build CMake ≥ 3.0.2 and [lxqt-build-tools](https://github.com/lxqt/lxqt-build-tools) are needed as well as optionally Git to pull latest VCS checkouts. The localization files were outsourced to repository [lxqt-l10n](https://github.com/lxqt/lxqt-l10n) so the corresponding dependencies are needed, too. Please refer to this repository's `README.md` for further information. 17 | 18 | Code configuration is handled by CMake. Building out of source is required. CMake variable `CMAKE_INSTALL_PREFIX` will normally have to be set to `/usr`. 19 | 20 | To build run `make`, to install `make install` which accepts variable `DESTDIR` as usual. 21 | 22 | ### Binary packages 23 | 24 | QTerminal is provided by all major Linux distributions like [Arch Linux](https://www.archlinux.org/packages/?q=qterminal), Debian (as of Debian stretch), Fedora and openSUSE. 25 | Just use the distributions' package managers to search for string `qterminal`. 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # QTerminal for WSL 2 | 3 | ## Overview 4 | 5 | This is a WSL port of [QTerminal](https://github.com/lxde/qterminal). 6 | 7 | This project is licensed under the terms of the [GPLv2](https://www.gnu.org/licenses/gpl-2.0.en.html) or any later version. See the LICENSE file for the full text of the license. 8 | 9 | [Screen shots](https://imgur.com/a/VMXp1) 10 | 11 | ## Download 12 | 13 | See [Releases](https://github.com/kghost/qterminal/releases) 14 | 15 | ## Features 16 | 17 | * Multiple window 18 | * Multiple tab 19 | * Multiple panel (verticl/horizontal split) 20 | 21 | XTerm features comapre to CMD or any CMD based terminal: 22 | 23 | * Bracketed paste: let the application know you are pasting not typing to prevent it doing something stupid. 24 | 25 | ![Paste](https://raw.githubusercontent.com/kghost/qterminal/assets/paste.gif) 26 | 27 | * Cursor styles: the application can change cursor styles (BLOCK/BAR/UNDERLINE) 28 | 29 | ![Cursor](https://raw.githubusercontent.com/kghost/qterminal/assets/cursor.gif) 30 | 31 | ### TODO 32 | 33 | * Multiple WSL instance support 34 | 35 | ## Build 36 | 37 | Dependencies: 38 | 39 | * [Qt](https://www.qt.io) 40 | * [lxqt-build-tools](https://github.com/kghost/lxqt-build-tools) 41 | * [QTermWidget for WSL](https://github.com/kghost/qtermwidget) 42 | * [utf8proc](https://github.com/kghost/utf8proc) 43 | * [tcppty](https://github.com/kghost/tcppty), a wsl backend act as a bridge. 44 | 45 | ## FAQ 46 | 47 | ### Why I am getting "The publisher could not be verified" warning ? 48 | 49 | To avoid the message, the exe file must be properly signed, it will take about $200-$300 per year for the certification to sign the exe file. Currently I don't think it is worth to sign the file, at least at this stage. Also you are free to download the source code and compile it yourself. 50 | 51 | ### Where the user setting is stored ? 52 | 53 | User setting is stored under per user roaming directory, eg: C:\\Users\\${username}\\AppData\\Roaming\\qterminal.org 54 | 55 | ### My Home/End key doesn't work. 56 | 57 | Ensure that default kaytab is used (File -> Preferences -> Behavior -> Emulation), or try other key maps, even modify kaytab define files, located \share\qtermwidget5\kb-layouts\ inside program directory. 58 | 59 | ### Can I run CMD inside QTerminal ? 60 | 61 | No, you can't. You can try run CMD.exe under WSL, it kinda works. But I won't put any work on it. 62 | 63 | ## Bug Report 64 | 65 | Please use github [issue tracker](https://github.com/kghost/qterminal/issues) 66 | -------------------------------------------------------------------------------- /qterminal.appdata.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | qterminal.desktop 4 | CC0-1.0 5 | GPL-2 6 | QTerminal 7 | A lightweight multiplatform terminal emulator. 8 | 9 |

10 | QTerminal is a lightweight multiplatform terminal emulator. 11 |

12 |

13 | Its main features are: 14 |

15 |
    16 |
  • Multiple tabs
  • 17 |
  • Layout terminals side-by-side
  • 18 |
  • Dropdown mode
  • 19 |
  • Text search
  • 20 |
  • Configurable uster interface
  • 21 |
  • Integration of system clipboard
  • 22 |
23 |
24 | 25 | 26 | http://worblehat.github.io/storage/qterminal_1.png 27 | The default QTerminal window. 28 | 29 | 30 | 31 | 32 | http://worblehat.github.io/storage/qterminal_2.png 33 | QTerminal with multiple tabs, splitted terminals and highlighted text. 34 | 35 | 36 | 37 | 38 | http://worblehat.github.io/storage/qterminal_3.png 39 | Find bar and highlighted match. 40 | 41 | 42 | https://github.com/lxqt/qterminal 43 |
44 | -------------------------------------------------------------------------------- /qterminal.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Name=QTerminal 3 | Type=Application 4 | GenericName=Terminal emulator 5 | GenericName[ca]=Emulador de terminal 6 | GenericName[cs]=Emulátor terminálu 7 | GenericName[es]=Emulador de terminal 8 | 9 | 10 | Comment=Terminal emulator 11 | Comment[ca]=Emulador de terminal 12 | Comment[cs]=Emulátor terminálu 13 | Comment[de]=Befehlszeile verwenden 14 | Comment[el]=Προσομοιωτής τερματικού 15 | Comment[es]=Emulador de terminal 16 | Comment[fr]=Terminal 17 | Comment[lt]=Terminalo emuliatorius 18 | Comment[pl]=Emulator terminala 19 | Comment[pt]=Emulador de terminal 20 | Comment[pt_BR]=Emulador de terminal 21 | Comment[ru_RU]=Эмулятор терминала 22 | Comment[ja]=ターミナル エミュレータ 23 | 24 | Icon=utilities-terminal 25 | Exec=qterminal 26 | Terminal=false 27 | Categories=Qt;System;TerminalEmulator; 28 | Actions=Dropdown; 29 | 30 | [Desktop Action Dropdown] 31 | Name=Drop-down terminal 32 | Exec=qterminal --drop 33 | Icon=utilities-terminal 34 | 35 | Name[en_GB]=Drop-down Terminal 36 | Name[bg]=Падащ терминал 37 | Name[ca]=Terminal desplegable 38 | Name[ca@valencia]=Terminal desplegable 39 | Name[cs]=Vysouvací terminál 40 | Name[da]=Terminal der ruller ned 41 | Name[de]=Aufklapp-Terminal 42 | Name[el]=Αναπτυσσόμενο τερματικό 43 | Name[es]=Terminal desplegable 44 | Name[et]=Lahtikeriv terminal 45 | Name[fr]=Terminal déroulant 46 | Name[hr]=Spuštajući terminal 47 | Name[hu]=Legördülő terminál 48 | Name[it]=Terminale a discesa 49 | Name[ja]=ドロップダウン式ターミナル 50 | Name[km]=ស្ថានីយ​ទម្លាក់​ចុះ 51 | Name[ko]=위에서 내려오는 터미널 52 | Name[lt]=Išskleidžiamasis terminalas 53 | Name[nb]=Nedtrekksterminal 54 | Name[nds]=Utklapp-Konsool 55 | Name[nl]=Uitvouwbare terminalemulator 56 | Name[pa]=ਲਟਕਦਾ ਟਰਮੀਨਲ 57 | Name[pl]=Rozwijany emulator terminala 58 | Name[pt]=Terminal suspenso 59 | Name[pt_BR]=Terminal suspenso 60 | Name[ro]=Terminal derulant 61 | Name[ru]=Выпадающий терминал 62 | Name[sk]=Rozbaľovací terminál 63 | Name[sv]=Rullgardinsterminal 64 | Name[th]=เทอร์มินัลแบบหย่อนลง 65 | Name[tr]=Yukarıdan Açılan Uçbirim 66 | Name[uk]=Спадний термінал 67 | Name[x-test]=xxDrop-down Terminalxx 68 | Name[zh_CN]=拉幕式终端 69 | Name[zh_TW]=下拉式終端機 70 | -------------------------------------------------------------------------------- /qterminal.pro: -------------------------------------------------------------------------------- 1 | TARGET = qterminal 2 | TEMPLATE = app 3 | # qt5 only. Please use cmake - it's an official build tool for this software 4 | QT += widgets 5 | 6 | CONFIG += link_pkgconfig \ 7 | depend_includepath 8 | 9 | PKGCONFIG += qtermwidget5 10 | 11 | DEFINES += QTERMINAL_VERSION=\\\"0.9.0\\\" 12 | 13 | SOURCES += $$files(src/*.cpp) 14 | HEADERS += $$files(src/*.h) 15 | 16 | INCLUDEPATH += src 17 | INCLUDEPATH += src/third-party 18 | 19 | SOURCES += src/third-party/qxtglobalshortcut.cpp 20 | HEADERS += src/third-party/qxtglobalshortcut.h 21 | HEADERS += src/third-party/qxtglobalshortcut_p.h 22 | 23 | win32 { 24 | SOURCES += src/third-party/qxtglobalshortcut_win.cpp 25 | } 26 | 27 | unix:!macx { 28 | SOURCES += src/third-party/qxtglobalshortcut_x11.cpp 29 | LIBS += -L/usr/X11/lib -lX11 30 | QT += x11extras 31 | } 32 | 33 | macx: { 34 | SOURCES += src/third-party/qxtglobalshortcut_mac.cpp 35 | } 36 | 37 | RESOURCES += src/icons.qrc 38 | FORMS += $$files(src/forms/*.ui) 39 | 40 | unix { 41 | isEmpty(PREFIX) { 42 | PREFIX = /usr/local 43 | } 44 | BINDIR = $$PREFIX/bin 45 | 46 | INSTALLS += target shortcut 47 | target.path = $$BINDIR 48 | 49 | DATADIR = $$PREFIX/share 50 | shortcut.path = $$DATADIR/applications 51 | shortcut.files = qterminal.desktop 52 | } 53 | 54 | -------------------------------------------------------------------------------- /qterminal_drop.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Type=Application 3 | Exec=qterminal --drop 4 | Terminal=false 5 | Categories=Qt;System;TerminalEmulator; 6 | Icon=utilities-terminal 7 | 8 | Name=QTerminal drop down 9 | Name[ca]=QTerminal desplegable 10 | Name[cs]=Rozbalovací QTerminál 11 | Name[de]=QTerminal herabhängend 12 | Name[el]=QTerminal αναπτυσσόμενο 13 | Name[es]=QTerminal desplegable 14 | Name[lt]=QTerminal išskleidžiamasis 15 | Name[pl]=QTerminal (tryb rozwijany) 16 | Name[pt]=QTerminal suspenso 17 | Name[pt_BR]=QTerminal suspenso 18 | Name[ja]=QTerminal ドロップダウン 19 | 20 | GenericName=Drop-down Terminal 21 | GenericName[bg]=Падащ терминал 22 | GenericName[ca]=Terminal desplegable 23 | GenericName[ca@valencia]=Terminal desplegable 24 | GenericName[cs]=Vysouvací terminál 25 | GenericName[da]=Terminal der ruller ned 26 | GenericName[de]=Aufklapp-Terminal 27 | GenericName[el]=Αναπτυσσόμενο τερματικό 28 | GenericName[en_GB]=Drop-down Terminal 29 | GenericName[es]=Terminal desplegable 30 | GenericName[et]=Lahtikeriv terminal 31 | GenericName[fr]=Terminal déroulant 32 | GenericName[hr]=Spuštajući terminal 33 | GenericName[hu]=Legördülő terminál 34 | GenericName[it]=Terminale a discesa 35 | GenericName[ja]=ドロップダウン式ターミナル 36 | GenericName[km]=ស្ថានីយ​ទម្លាក់​ចុះ 37 | GenericName[ko]=위에서 내려오는 터미널 38 | GenericName[lt]=Išskleidžiamasis terminalas 39 | GenericName[nb]=Nedtrekksterminal 40 | GenericName[nds]=Utklapp-Konsool 41 | GenericName[nl]=Uitvouwbare terminalemulator 42 | GenericName[pa]=ਲਟਕਦਾ ਟਰਮੀਨਲ 43 | GenericName[pl]=Rozwijany emulator terminala 44 | GenericName[pt]=Terminal suspenso 45 | GenericName[pt_BR]=Terminal suspenso 46 | GenericName[ro]=Terminal derulant 47 | GenericName[ru]=Выпадающий терминал 48 | GenericName[sk]=Rozbaľovací terminál 49 | GenericName[sv]=Rullgardinsterminal 50 | GenericName[th]=เทอร์มินัลแบบหย่อนลง 51 | GenericName[tr]=Yukarıdan Açılan Uçbirim 52 | GenericName[uk]=Спадний термінал 53 | GenericName[x-test]=xxDrop-down Terminalxx 54 | GenericName[zh_CN]=拉幕式终端 55 | GenericName[zh_TW]=下拉式終端機 56 | 57 | Comment=A drop-down terminal emulator. 58 | Comment[ca]=Un emulador de terminal desplegable. 59 | Comment[cs]=Vysouvací emulátor terminálu. 60 | Comment[de]=Ein Ausklapp-Terminalemulator. 61 | Comment[el]=Ένας αναπτυσσόμενος προσομοιωτής τερματικού. 62 | Comment[es]=Un emulador de terminal desplegable. 63 | Comment[lt]=Išskleidžiamasis terminalo emuliatorius. 64 | Comment[pt]=Um emulador de terminal suspenso. 65 | Comment[pt_BR]=Um emulador de terminal suspenso. 66 | Comment[ru]=Выпадающий эмулятор терминала. 67 | Comment[ja]=ドロップダウン式 ターミナルエミュレータ 68 | 69 | -------------------------------------------------------------------------------- /src/bookmarkswidget.cpp: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | * Copyright (C) 2014 by Petr Vanek * 3 | * petr@scribus.info * 4 | * * 5 | * This program is free software; you can redistribute it and/or modify * 6 | * it under the terms of the GNU General Public License as published by * 7 | * the Free Software Foundation; either version 2 of the License, or * 8 | * (at your option) any later version. * 9 | * * 10 | * This program is distributed in the hope that it will be useful, * 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 13 | * GNU General Public License for more details. * 14 | * * 15 | * You should have received a copy of the GNU General Public License * 16 | * along with this program. If not, see . * 17 | ***************************************************************************/ 18 | 19 | #include 20 | #include 21 | 22 | #include "bookmarkswidget.h" 23 | #include "properties.h" 24 | #include "config.h" 25 | 26 | 27 | class AbstractBookmarkItem 28 | { 29 | public: 30 | enum ItemType { 31 | Root = 0, 32 | Group = 1, 33 | Command = 2 34 | }; 35 | 36 | AbstractBookmarkItem(AbstractBookmarkItem* parent = 0) 37 | { 38 | m_parent = parent; 39 | } 40 | ~AbstractBookmarkItem() 41 | { 42 | qDeleteAll(m_children); 43 | } 44 | 45 | ItemType type() { return m_type; } 46 | QString value() { return m_value; } 47 | QString display() { return m_display; } 48 | 49 | void addChild(AbstractBookmarkItem* item) { m_children << item; } 50 | int childCount() { return m_children.count(); } 51 | QList children() { return m_children; } 52 | AbstractBookmarkItem *child(int number) { return m_children.value(number); } 53 | AbstractBookmarkItem *parent() { return m_parent; } 54 | 55 | int childNumber() const 56 | { 57 | if (m_parent) 58 | return m_parent->children().indexOf(const_cast(this)); 59 | 60 | return 0; 61 | } 62 | 63 | protected: 64 | ItemType m_type; 65 | AbstractBookmarkItem *m_parent; 66 | QList m_children; 67 | QString m_value; 68 | QString m_display; 69 | }; 70 | 71 | class BookmarkRootItem : public AbstractBookmarkItem 72 | { 73 | public: 74 | BookmarkRootItem() 75 | : AbstractBookmarkItem() 76 | { 77 | m_type = AbstractBookmarkItem::Root; 78 | m_value = m_display = QStringLiteral("root"); 79 | } 80 | }; 81 | 82 | class BookmarkCommandItem : public AbstractBookmarkItem 83 | { 84 | public: 85 | BookmarkCommandItem(const QString &name, const QString &command, AbstractBookmarkItem *parent) 86 | : AbstractBookmarkItem(parent) 87 | { 88 | m_type = AbstractBookmarkItem::Command; 89 | m_value = command; 90 | m_display = name; 91 | } 92 | }; 93 | 94 | 95 | class BookmarkGroupItem : public AbstractBookmarkItem 96 | { 97 | public: 98 | BookmarkGroupItem(const QString &name, AbstractBookmarkItem *parent) 99 | : AbstractBookmarkItem(parent) 100 | { 101 | m_type = AbstractBookmarkItem::Group; 102 | m_display = name; 103 | } 104 | }; 105 | 106 | class BookmarkLocalGroupItem : public BookmarkGroupItem 107 | { 108 | public: 109 | BookmarkLocalGroupItem(AbstractBookmarkItem *parent) 110 | : BookmarkGroupItem(QObject::tr("Local Bookmarks"), parent) 111 | { 112 | QList locations; 113 | locations << QStandardPaths::DesktopLocation 114 | << QStandardPaths::DocumentsLocation 115 | << QStandardPaths::TempLocation 116 | << QStandardPaths::HomeLocation 117 | << QStandardPaths::MusicLocation 118 | << QStandardPaths::PicturesLocation; 119 | 120 | QString path; 121 | QString name; 122 | QString cmd; 123 | QDir d; 124 | 125 | // standard $HOME subdirs 126 | for (const QStandardPaths::StandardLocation i : qAsConst(locations)) 127 | { 128 | path = QStandardPaths::writableLocation(i); 129 | if (!d.exists(path)) 130 | { 131 | continue; 132 | } 133 | name = QStandardPaths::displayName(i); 134 | 135 | path.replace(QLatin1String(" "), QLatin1String("\\ ")); 136 | cmd = QLatin1String("cd ") + path; 137 | 138 | addChild(new BookmarkCommandItem(name, cmd, this)); 139 | } 140 | 141 | // system env - include dirs in the tree 142 | QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); 143 | const auto keys = env.keys(); 144 | for (const QString &i : keys) 145 | { 146 | path = env.value(i); 147 | if (!d.exists(path) || !QFileInfo(path).isDir()) 148 | { 149 | continue; 150 | } 151 | path.replace(QLatin1String(" "), QLatin1String("\\ ")); 152 | cmd = QLatin1String("cd ") + path; 153 | addChild(new BookmarkCommandItem(i, cmd, this)); 154 | } 155 | } 156 | }; 157 | 158 | class BookmarkFileGroupItem : public BookmarkGroupItem 159 | { 160 | // hierarchy handling 161 | // m_pos to group map. Example: group1.group2=item 162 | QHash m_map; 163 | // current position level. Example "group1", "group2" 164 | QStringList m_pos; 165 | 166 | public: 167 | BookmarkFileGroupItem(AbstractBookmarkItem *parent, const QString &fname) 168 | : BookmarkGroupItem(QObject::tr("Synchronized Bookmarks"), parent) 169 | { 170 | QFile f(fname); 171 | if (!f.open(QIODevice::ReadOnly)) 172 | { 173 | qDebug() << "Canot open file" << fname; 174 | // TODO/FIXME: message box 175 | return; 176 | } 177 | 178 | QXmlStreamReader xml; 179 | xml.setDevice(&f); 180 | 181 | while (true) 182 | { 183 | xml.readNext(); 184 | 185 | switch (xml.tokenType()) 186 | { 187 | case QXmlStreamReader::StartElement: 188 | { 189 | AbstractBookmarkItem *parent = m_map.contains(xmlPos()) ? m_map[xmlPos()] : this; 190 | QString tag = xml.name().toString(); 191 | if (tag == QLatin1String("group")) 192 | { 193 | QString name = xml.attributes().value(QLatin1String("name")).toString(); 194 | m_pos.append(name); 195 | 196 | BookmarkGroupItem *i = new BookmarkGroupItem(name, parent); 197 | parent->addChild(i); 198 | 199 | m_map[xmlPos()] = i; 200 | } 201 | else if (tag == QLatin1String("command")) 202 | { 203 | QString name = xml.attributes().value(QLatin1String("name")).toString(); 204 | QString cmd = xml.attributes().value(QLatin1String("value")).toString(); 205 | 206 | BookmarkCommandItem *i = new BookmarkCommandItem(name, cmd, parent); 207 | parent->addChild(i); 208 | } 209 | break; 210 | } 211 | case QXmlStreamReader::EndElement: 212 | { 213 | QString tag = xml.name().toString(); 214 | if (tag == QLatin1String("group")) 215 | { 216 | m_pos.removeLast(); 217 | } 218 | break; 219 | } 220 | case QXmlStreamReader::Invalid: 221 | qDebug() << "XML error: " << xml.errorString().constData() 222 | << xml.lineNumber() << xml.columnNumber(); 223 | m_map.clear(); 224 | return; 225 | case QXmlStreamReader::EndDocument: 226 | m_map.clear(); 227 | return; 228 | default: 229 | break; 230 | } // switch 231 | } // while 232 | } // constructor 233 | 234 | QString xmlPos() 235 | { 236 | return m_pos.join(QLatin1Char('.')); 237 | } 238 | }; 239 | 240 | 241 | BookmarksModel::BookmarksModel(QObject *parent) 242 | : QAbstractItemModel(parent), 243 | m_root(0) 244 | { 245 | setup(); 246 | } 247 | 248 | void BookmarksModel::setup() 249 | { 250 | if (m_root) 251 | delete m_root; 252 | m_root = new BookmarkRootItem(); 253 | m_root->addChild(new BookmarkLocalGroupItem(m_root)); 254 | m_root->addChild(new BookmarkFileGroupItem(m_root, Properties::Instance()->bookmarksFile)); 255 | beginResetModel(); 256 | endResetModel(); 257 | } 258 | 259 | BookmarksModel::~BookmarksModel() 260 | { 261 | if (m_root) 262 | delete m_root; 263 | } 264 | 265 | int BookmarksModel::columnCount(const QModelIndex & /* parent */) const 266 | { 267 | return 2; 268 | } 269 | 270 | QVariant BookmarksModel::data(const QModelIndex &index, int role) const 271 | { 272 | if (!index.isValid()) 273 | return QVariant(); 274 | 275 | switch (role) 276 | { 277 | case Qt::DisplayRole: 278 | case Qt::EditRole: 279 | return index.column() == 0 ? getItem(index)->display() : getItem(index)->value(); 280 | case Qt::FontRole: 281 | { 282 | QFont f; 283 | if (static_cast(index.internalPointer())->type() == AbstractBookmarkItem::Group) 284 | { 285 | f.setBold(true); 286 | } 287 | return f; 288 | } 289 | default: 290 | return QVariant(); 291 | } 292 | } 293 | 294 | AbstractBookmarkItem *BookmarksModel::getItem(const QModelIndex &index) const 295 | { 296 | if (index.isValid()) 297 | { 298 | AbstractBookmarkItem *item = static_cast(index.internalPointer()); 299 | if (item) 300 | return item; 301 | } 302 | return m_root; 303 | } 304 | 305 | QVariant BookmarksModel::headerData(int /*section*/, Qt::Orientation /*orientation*/, 306 | int /*role*/) const 307 | { 308 | return QVariant(); 309 | } 310 | 311 | QModelIndex BookmarksModel::index(int row, int column, const QModelIndex &parent) const 312 | { 313 | if (parent.isValid() && parent.column() != 0) 314 | return QModelIndex(); 315 | 316 | AbstractBookmarkItem *parentItem = getItem(parent); 317 | 318 | AbstractBookmarkItem *childItem = parentItem->child(row); 319 | if (childItem) 320 | return createIndex(row, column, childItem); 321 | else 322 | return QModelIndex(); 323 | } 324 | 325 | 326 | QModelIndex BookmarksModel::parent(const QModelIndex &index) const 327 | { 328 | if (!index.isValid()) 329 | return QModelIndex(); 330 | 331 | AbstractBookmarkItem *childItem = getItem(index); 332 | AbstractBookmarkItem *parentItem = childItem->parent(); 333 | 334 | if (parentItem == m_root) 335 | return QModelIndex(); 336 | 337 | return createIndex(parentItem->childNumber(), 0, parentItem); 338 | } 339 | 340 | int BookmarksModel::rowCount(const QModelIndex &parent) const 341 | { 342 | AbstractBookmarkItem *parentItem = getItem(parent); 343 | return parentItem->childCount(); 344 | } 345 | 346 | #if 0 347 | bool BookmarksModel::setData(const QModelIndex &index, const QVariant &value, 348 | int role) 349 | { 350 | if (role != Qt::EditRole) 351 | return false; 352 | 353 | AbstractBookmarkItem *item = getItem(index); 354 | bool result = item->setData(index.column(), value); 355 | 356 | if (result) 357 | emit dataChanged(index, index); 358 | 359 | return result; 360 | } 361 | #endif 362 | 363 | 364 | BookmarksWidget::BookmarksWidget(QWidget *parent) 365 | : QWidget(parent) 366 | { 367 | setupUi(this); 368 | 369 | m_model = new BookmarksModel(this); 370 | treeView->setModel(m_model); 371 | treeView->header()->hide(); 372 | 373 | connect(treeView, &QTreeView::doubleClicked, 374 | this, &BookmarksWidget::handleCommand); 375 | } 376 | 377 | BookmarksWidget::~BookmarksWidget() 378 | { 379 | } 380 | 381 | void BookmarksWidget::setup() 382 | { 383 | m_model->setup(); 384 | 385 | treeView->expandAll(); 386 | treeView->resizeColumnToContents(0); 387 | treeView->resizeColumnToContents(1); 388 | } 389 | 390 | void BookmarksWidget::handleCommand(const QModelIndex& index) 391 | { 392 | AbstractBookmarkItem *item = static_cast(index.internalPointer()); 393 | if (!item || item->type() != AbstractBookmarkItem::Command) 394 | return; 395 | 396 | emit callCommand(item->value() + QLatin1Char('\n')); // TODO/FIXME: decide how to handle EOL 397 | } 398 | -------------------------------------------------------------------------------- /src/bookmarkswidget.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | * Copyright (C) 2014 by Petr Vanek * 3 | * petr@scribus.info * 4 | * * 5 | * This program is free software; you can redistribute it and/or modify * 6 | * it under the terms of the GNU General Public License as published by * 7 | * the Free Software Foundation; either version 2 of the License, or * 8 | * (at your option) any later version. * 9 | * * 10 | * This program is distributed in the hope that it will be useful, * 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 13 | * GNU General Public License for more details. * 14 | * * 15 | * You should have received a copy of the GNU General Public License * 16 | * along with this program. If not, see . * 17 | ***************************************************************************/ 18 | 19 | #ifndef BOOKMARKSWIDGET_H 20 | #define BOOKMARKSWIDGET_H 21 | 22 | #include "ui_bookmarkswidget.h" 23 | 24 | class AbstractBookmarkItem; 25 | class BookmarksModel; 26 | 27 | 28 | class BookmarksWidget : public QWidget, Ui::BookmarksWidget 29 | { 30 | Q_OBJECT 31 | 32 | public: 33 | BookmarksWidget(QWidget *parent=NULL); 34 | ~BookmarksWidget(); 35 | 36 | void setup(); 37 | 38 | signals: 39 | void callCommand(const QString &cmd); 40 | 41 | private: 42 | BookmarksModel *m_model; 43 | 44 | private slots: 45 | void handleCommand(const QModelIndex& index); 46 | }; 47 | 48 | 49 | class BookmarksModel : public QAbstractItemModel 50 | { 51 | Q_OBJECT 52 | 53 | public: 54 | BookmarksModel(QObject *parent = 0); 55 | ~BookmarksModel(); 56 | 57 | void setup(); 58 | 59 | QVariant data(const QModelIndex &index, int role) const; 60 | QVariant headerData(int section, Qt::Orientation orientation, 61 | int role = Qt::DisplayRole) const; 62 | 63 | QModelIndex index(int row, int column, 64 | const QModelIndex &parent = QModelIndex()) const; 65 | QModelIndex parent(const QModelIndex &index) const; 66 | 67 | int rowCount(const QModelIndex &parent = QModelIndex()) const; 68 | int columnCount(const QModelIndex &parent = QModelIndex()) const; 69 | 70 | private: 71 | AbstractBookmarkItem *getItem(const QModelIndex &index) const; 72 | AbstractBookmarkItem *m_root; 73 | }; 74 | 75 | #endif 76 | 77 | -------------------------------------------------------------------------------- /src/config.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | * Copyright (C) 2006 by Vladimir Kuznetsov * 3 | * vovanec@gmail.com * 4 | * * 5 | * This program is free software; you can redistribute it and/or modify * 6 | * it under the terms of the GNU General Public License as published by * 7 | * the Free Software Foundation; either version 2 of the License, or * 8 | * (at your option) any later version. * 9 | * * 10 | * This program is distributed in the hope that it will be useful, * 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 13 | * GNU General Public License for more details. * 14 | * * 15 | * You should have received a copy of the GNU General Public License * 16 | * along with this program. If not, see . * 17 | ***************************************************************************/ 18 | 19 | 20 | #ifndef CONFIG_H 21 | #define CONFIG_H 22 | 23 | #define ADD_TAB "Add Tab" 24 | #define RENAME_TAB "Rename Tab" 25 | #define CLOSE_TAB "Close Tab" 26 | #define NEW_WINDOW "New Window" 27 | 28 | #define QUIT "Quit" 29 | #define PREFERENCES "Preferences..." 30 | 31 | #define TAB_PREV_HISTORY "Previous Tab in History" 32 | #define TAB_NEXT_HISTORY "Next Tab in History" 33 | #define TAB_NEXT "Next Tab" 34 | #define TAB_PREV "Previous Tab" 35 | 36 | #define CLEAR_TERMINAL "Clear Active Terminal" 37 | 38 | #define SPLIT_HORIZONTAL "Split Terminal Horizontally" 39 | #define SPLIT_VERTICAL "Split Terminal Vertically" 40 | 41 | #define SUB_COLLAPSE "Collapse Subterminal" 42 | #define SUB_LEFT "Left Subterminal" 43 | #define SUB_RIGHT "Right Subterminal" 44 | #define SUB_TOP "Top Subterminal" 45 | #define SUB_BOTTOM "Bottom Subterminal" 46 | 47 | #define MOVE_LEFT "Move Tab Left" 48 | #define MOVE_RIGHT "Move Tab Right" 49 | 50 | #define COPY_SELECTION "Copy Selection" 51 | #define PASTE_CLIPBOARD "Paste Clipboard" 52 | #define PASTE_SELECTION "Paste Selection" 53 | 54 | #define ZOOM_IN "Zoom in" 55 | #define ZOOM_OUT "Zoom out" 56 | #define ZOOM_RESET "Zoom reset" 57 | 58 | #define FIND "Find" 59 | 60 | #define TOGGLE_MENU "Toggle Menu" 61 | #define TOGGLE_BOOKMARKS "Toggle Bookmarks" 62 | 63 | #define HIDE_WINDOW_BORDERS "Hide Window Borders" 64 | #define SHOW_TAB_BAR "Show Tab Bar" 65 | #define RENAME_SESSION "Rename Session" 66 | #define FULLSCREEN "Fullscreen" 67 | 68 | /* Some defaults for QTerminal application */ 69 | 70 | #define DEFAULT_WIDTH 800 71 | #define DEFAULT_HEIGHT 600 72 | #define DEFAULT_FONT "Consolas" 73 | 74 | // ACTIONS 75 | #define CLEAR_TERMINAL_SHORTCUT "Ctrl+Shift+X" 76 | 77 | #define TAB_PREV_HISTORY_SHORTCUT "Ctrl+Tab" 78 | #define TAB_NEXT_HISTORY_SHORTCUT "Ctrl+Shift+Tab" 79 | #define TAB_PREV_SHORTCUT "Ctrl+PgUp" 80 | #define TAB_NEXT_SHORTCUT "Ctrl+PgDown" 81 | #define SUB_BOTTOM_SHORTCUT "Alt+Down" 82 | #define SUB_TOP_SHORTCUT "Alt+Up" 83 | #define SUB_LEFT_SHORTCUT "Alt+Left" 84 | #define SUB_RIGHT_SHORTCUT "Alt+Right" 85 | 86 | #ifdef Q_WS_MAC 87 | // It's tricky - Ctrl is "command" key on mac's keyboards 88 | #define COPY_SELECTION_SHORTCUT "Ctrl+C" 89 | #define PASTE_CLIPBOARD_SHORTCUT "Ctrl+V" 90 | #define FIND_SHORTCUT "Ctrl+F" 91 | #define NEW_WINDOW_SHORTCUT "Ctrl+N" 92 | #define ADD_TAB_SHORTCUT "Ctrl+T" 93 | #define CLOSE_TAB_SHORTCUT "Ctrl+W" 94 | #define TOGGLE_MENU_SHORTCUT "Ctrl+M" 95 | #define TOGGLE_BOOKMARKS_SHORTCUT "Ctrl+B" 96 | #else 97 | #define COPY_SELECTION_SHORTCUT "Ctrl+Shift+C" 98 | #define PASTE_CLIPBOARD_SHORTCUT "Ctrl+Shift+V" 99 | #define PASTE_SELECTION_SHORTCUT "Shift+Ins" 100 | #define FIND_SHORTCUT "Ctrl+Shift+F" 101 | #define NEW_WINDOW_SHORTCUT "Ctrl+Shift+N" 102 | #define ADD_TAB_SHORTCUT "Ctrl+Shift+T" 103 | #define CLOSE_TAB_SHORTCUT "Ctrl+Shift+W" 104 | #define TOGGLE_MENU_SHORTCUT "Ctrl+Shift+M" 105 | #define TOGGLE_BOOKMARKS_SHORTCUT "Ctrl+Shift+B" 106 | #endif 107 | 108 | #define ZOOM_IN_SHORTCUT "Ctrl++" 109 | #define ZOOM_OUT_SHORTCUT "Ctrl+-" 110 | #define ZOOM_RESET_SHORTCUT "Ctrl+0" 111 | 112 | #define MOVE_LEFT_SHORTCUT "Shift+Alt+Left|Ctrl+Shift+PgUp" 113 | #define MOVE_RIGHT_SHORTCUT "Shift+Alt+Right|Ctrl+Shift+PgDown" 114 | 115 | #define RENAME_SESSION_SHORTCUT "Shift+Alt+S" 116 | 117 | #define FULLSCREEN_SHORTCUT "F11" 118 | 119 | // XON/XOFF features: 120 | 121 | #define FLOW_CONTROL_ENABLED false 122 | #define FLOW_CONTROL_WARNING_ENABLED false 123 | 124 | #endif 125 | -------------------------------------------------------------------------------- /src/dbusaddressable.cpp: -------------------------------------------------------------------------------- 1 | 2 | 3 | #include "dbusaddressable.h" 4 | 5 | #ifdef HAVE_QDBUS 6 | Q_DECLARE_METATYPE(QList) 7 | 8 | QString DBusAddressable::getDbusPathString() 9 | { 10 | return m_path; 11 | } 12 | 13 | QDBusObjectPath DBusAddressable::getDbusPath() 14 | { 15 | return QDBusObjectPath(m_path); 16 | } 17 | #endif 18 | 19 | DBusAddressable::DBusAddressable(QString prefix) 20 | { 21 | #ifdef HAVE_QDBUS 22 | QString uuidString = QUuid::createUuid().toString(); 23 | m_path = prefix + QLatin1Char('/') + uuidString.replace(QRegExp(QStringLiteral("[\\{\\}\\-]")), QString()); 24 | #endif 25 | } 26 | -------------------------------------------------------------------------------- /src/dbusaddressable.h: -------------------------------------------------------------------------------- 1 | #ifndef DBUSADDRESSABLE_H 2 | #define DBUSADDRESSABLE_H 3 | 4 | #include 5 | #ifdef HAVE_QDBUS 6 | #include 7 | #include 8 | #endif 9 | 10 | class DBusAddressable 11 | { 12 | #ifdef HAVE_QDBUS 13 | private: 14 | QString m_path; 15 | #endif 16 | public: 17 | #ifdef HAVE_QDBUS 18 | QDBusObjectPath getDbusPath(); 19 | QString getDbusPathString(); 20 | #endif 21 | DBusAddressable(QString prefix); 22 | }; 23 | 24 | #ifdef HAVE_QDBUS 25 | template void registerAdapter(WClass *obj) 26 | { 27 | new AClass(obj); 28 | QString path = dynamic_cast(obj)->getDbusPathString(); 29 | QDBusConnection::sessionBus().registerObject(path, obj); 30 | } 31 | #endif 32 | 33 | 34 | #endif -------------------------------------------------------------------------------- /src/fontdialog.cpp: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | * Copyright (C) 2014 by Petr Vanek * 3 | * petr@scribus.info * 4 | * * 5 | * This program is free software; you can redistribute it and/or modify * 6 | * it under the terms of the GNU General Public License as published by * 7 | * the Free Software Foundation; either version 2 of the License, or * 8 | * (at your option) any later version. * 9 | * * 10 | * This program is distributed in the hope that it will be useful, * 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 13 | * GNU General Public License for more details. * 14 | * * 15 | * You should have received a copy of the GNU General Public License * 16 | * along with this program. If not, see . * 17 | ***************************************************************************/ 18 | 19 | #include "fontdialog.h" 20 | 21 | FontDialog::FontDialog(const QFont &f) 22 | : QDialog(0) 23 | { 24 | setupUi(this); 25 | 26 | fontComboBox->setFontFilters(QFontComboBox::MonospacedFonts 27 | | QFontComboBox::NonScalableFonts 28 | | QFontComboBox::ScalableFonts); 29 | 30 | fontComboBox->setCurrentFont(f); 31 | fontComboBox->setEditable(false); 32 | 33 | sizeSpinBox->setValue(f.pointSize()); 34 | 35 | setFontSample(f); 36 | 37 | connect(fontComboBox, &QFontComboBox::currentFontChanged, 38 | this, &FontDialog::setFontSample); 39 | connect(sizeSpinBox, static_cast(&QSpinBox::valueChanged), 40 | this, &FontDialog::setFontSize); 41 | } 42 | 43 | QFont FontDialog::getFont() 44 | { 45 | QFont f = fontComboBox->currentFont(); 46 | f.setPointSize(sizeSpinBox->value()); 47 | return f; 48 | } 49 | 50 | void FontDialog::setFontSample(const QFont &f) 51 | { 52 | previewLabel->setFont(f); 53 | QString sample(QLatin1String("%1 %2 pt")); 54 | previewLabel->setText(sample.arg(f.family()).arg(f.pointSize())); 55 | } 56 | 57 | void FontDialog::setFontSize() 58 | { 59 | const QFont &f = getFont(); 60 | previewLabel->setFont(f); 61 | QString sample(QLatin1String("%1 %2 pt")); 62 | previewLabel->setText(sample.arg(f.family()).arg(f.pointSize())); 63 | } 64 | -------------------------------------------------------------------------------- /src/fontdialog.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | * Copyright (C) 2014 by Petr Vanek * 3 | * petr@scribus.info * 4 | * * 5 | * This program is free software; you can redistribute it and/or modify * 6 | * it under the terms of the GNU General Public License as published by * 7 | * the Free Software Foundation; either version 2 of the License, or * 8 | * (at your option) any later version. * 9 | * * 10 | * This program is distributed in the hope that it will be useful, * 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 13 | * GNU General Public License for more details. * 14 | * * 15 | * You should have received a copy of the GNU General Public License * 16 | * along with this program. If not, see . * 17 | ***************************************************************************/ 18 | 19 | #ifndef FONT_DIALOG 20 | #define FONT_DIALOG 21 | 22 | #include "ui_fontdialog.h" 23 | #include "properties.h" 24 | 25 | 26 | 27 | class FontDialog : public QDialog, public Ui::FontDialog 28 | { 29 | Q_OBJECT 30 | public: 31 | FontDialog(const QFont &f); 32 | QFont getFont(); 33 | 34 | private slots: 35 | void setFontSample(const QFont &f); 36 | void setFontSize(); 37 | 38 | }; 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /src/forms/bookmarkswidget.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | BookmarksWidget 4 | 5 | 6 | 7 | 0 8 | 0 9 | 323 10 | 450 11 | 12 | 13 | 14 | 15 | 1 16 | 17 | 18 | 1 19 | 20 | 21 | 1 22 | 23 | 24 | 1 25 | 26 | 27 | 1 28 | 29 | 30 | 31 | 32 | Filter: 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | true 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /src/forms/fontdialog.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | FontDialog 4 | 5 | 6 | 7 | 0 8 | 0 9 | 296 10 | 187 11 | 12 | 13 | 14 | Select Terminal Font 15 | 16 | 17 | 18 | 19 | 20 | Qt::Horizontal 21 | 22 | 23 | QDialogButtonBox::Cancel|QDialogButtonBox::Ok 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | Font: 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | Size: 43 | 44 | 45 | 46 | 47 | 48 | 49 | 6 50 | 51 | 52 | 10 53 | 54 | 55 | 56 | 57 | 58 | 59 | Preview 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | Select Terminal Font 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | buttonBox 83 | accepted() 84 | FontDialog 85 | accept() 86 | 87 | 88 | 248 89 | 254 90 | 91 | 92 | 157 93 | 274 94 | 95 | 96 | 97 | 98 | buttonBox 99 | rejected() 100 | FontDialog 101 | reject() 102 | 103 | 104 | 316 105 | 260 106 | 107 | 108 | 286 109 | 274 110 | 111 | 112 | 113 | 114 | 115 | -------------------------------------------------------------------------------- /src/forms/qterminal.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | mainWindow 4 | 5 | 6 | 7 | 0 8 | 0 9 | 600 10 | 420 11 | 12 | 13 | 14 | MainWindow 15 | 16 | 17 | 18 | 19 | 0 20 | 21 | 22 | 0 23 | 24 | 25 | 0 26 | 27 | 28 | 0 29 | 30 | 31 | 32 | 33 | QTabWidget::South 34 | 35 | 36 | QTabWidget::Rounded 37 | 38 | 39 | -1 40 | 41 | 42 | Qt::ElideNone 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 0 52 | 0 53 | 600 54 | 26 55 | 56 | 57 | 58 | 59 | &File 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | &Actions 68 | 69 | 70 | 71 | 72 | &Help 73 | 74 | 75 | 76 | 77 | 78 | 79 | &View 80 | 81 | 82 | 83 | 84 | &Edit 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | &About... 101 | 102 | 103 | 104 | 105 | About &Qt... 106 | 107 | 108 | 109 | 110 | 111 | TabWidget 112 | QTabWidget 113 |
tabwidget.h
114 | 1 115 |
116 |
117 | 118 | 119 |
120 | -------------------------------------------------------------------------------- /src/icons.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | icons/index.theme 4 | icons/qterminal.png 5 | icons/list-add.png 6 | icons/list-remove.png 7 | icons/edit-copy.png 8 | icons/edit-paste.png 9 | icons/document-close.png 10 | icons/application-exit.png 11 | icons/locked.png 12 | icons/notlocked.png 13 | icons/zoom-in.png 14 | icons/zoom-out.png 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/icons/application-exit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kghost/qterminal/8a74f14078d80b05c8e2a167ac947c7b55cedfe0/src/icons/application-exit.png -------------------------------------------------------------------------------- /src/icons/document-close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kghost/qterminal/8a74f14078d80b05c8e2a167ac947c7b55cedfe0/src/icons/document-close.png -------------------------------------------------------------------------------- /src/icons/edit-copy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kghost/qterminal/8a74f14078d80b05c8e2a167ac947c7b55cedfe0/src/icons/edit-copy.png -------------------------------------------------------------------------------- /src/icons/edit-paste.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kghost/qterminal/8a74f14078d80b05c8e2a167ac947c7b55cedfe0/src/icons/edit-paste.png -------------------------------------------------------------------------------- /src/icons/index.theme: -------------------------------------------------------------------------------- 1 | [Icon Theme] 2 | Name=QTerminal 3 | Comment=Default Icons used in QTerminal 4 | Inherits=default 5 | Directories=16x16,22x22,24x24,32x32,scalable 6 | 7 | [16x16] 8 | Size=16 9 | Type=Fixed 10 | 11 | [22x22] 12 | Size=22 13 | Type=Fixed 14 | 15 | [24x24] 16 | Size=24 17 | Type=Fixed 18 | 19 | [32x32] 20 | Size=32 21 | Type=Fixed 22 | 23 | [64x64] 24 | Size=64 25 | Type=Fixed 26 | 27 | [scalable] 28 | Size=48 29 | Type=Scalable 30 | MinSize=32 31 | MaxSize=256 32 | -------------------------------------------------------------------------------- /src/icons/list-add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kghost/qterminal/8a74f14078d80b05c8e2a167ac947c7b55cedfe0/src/icons/list-add.png -------------------------------------------------------------------------------- /src/icons/list-remove.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kghost/qterminal/8a74f14078d80b05c8e2a167ac947c7b55cedfe0/src/icons/list-remove.png -------------------------------------------------------------------------------- /src/icons/locked.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kghost/qterminal/8a74f14078d80b05c8e2a167ac947c7b55cedfe0/src/icons/locked.png -------------------------------------------------------------------------------- /src/icons/notlocked.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kghost/qterminal/8a74f14078d80b05c8e2a167ac947c7b55cedfe0/src/icons/notlocked.png -------------------------------------------------------------------------------- /src/icons/qterminal.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kghost/qterminal/8a74f14078d80b05c8e2a167ac947c7b55cedfe0/src/icons/qterminal.ico -------------------------------------------------------------------------------- /src/icons/qterminal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kghost/qterminal/8a74f14078d80b05c8e2a167ac947c7b55cedfe0/src/icons/qterminal.png -------------------------------------------------------------------------------- /src/icons/zoom-in.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kghost/qterminal/8a74f14078d80b05c8e2a167ac947c7b55cedfe0/src/icons/zoom-in.png -------------------------------------------------------------------------------- /src/icons/zoom-out.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kghost/qterminal/8a74f14078d80b05c8e2a167ac947c7b55cedfe0/src/icons/zoom-out.png -------------------------------------------------------------------------------- /src/macosx/bundle.cmake.in: -------------------------------------------------------------------------------- 1 | # 2 | # This is evil! I don't know why it works this way. 3 | # But it works. 4 | # 5 | # First - collect all Qt and App plugins. Then call that bloody 6 | # cmake FIXUP_BUNDLE macro which copis all files into MacOS directory. 7 | # So it's moved back to plugins tree where its expected by a) Qt b) application 8 | # 9 | # I hate it. 10 | # 11 | 12 | # Dunno what id this var for... 13 | SET(DIRS @QT_LIBRARY_DIRS@;@QT_PLUGINS_DIR@;@CMAKE_INSTALL_PREFIX@/Contents/plugins/) 14 | 15 | # qt_menu.nib is mandatory for mac 16 | if (@QT_USE_FRAMEWORKS@) 17 | file(COPY @QT_LIBRARY_DIR@/QtGui.framework/Resources/qt_menu.nib 18 | DESTINATION @CMAKE_INSTALL_PREFIX@/@EXE_NAME@.app/Contents/Resources) 19 | else () 20 | file(COPY @QT_LIBRARY_DIR@/Resources/qt_menu.nib 21 | DESTINATION @CMAKE_INSTALL_PREFIX@/@EXE_NAME@.app/Contents/Resources) 22 | endif () 23 | 24 | # the qt.conf is mandatory too 25 | file(WRITE @CMAKE_INSTALL_PREFIX@/@EXE_NAME@.app/Contents/Resources/qt.conf "[Paths] 26 | Plugins = plugins") 27 | 28 | # copy all (required) Qt plugs into bundle 29 | message(STATUS "Searching for Qt plugs in: @QT_PLUGINS_DIR@/*@CMAKE_SHARED_LIBRARY_SUFFIX@") 30 | file(COPY @QT_PLUGINS_DIR@/ 31 | DESTINATION @CMAKE_INSTALL_PREFIX@/@EXE_NAME@.app/Contents/plugins/ 32 | REGEX "(designer|script|debug|sql|odbc|phonon|svg|mng|tiff|gif|bearer|accessible|)" EXCLUDE) 33 | #REGEX "(.*)" EXCLUDE) 34 | 35 | # try to FIXUP_BUNDLE - to change otool -L paths 36 | # currently it creates lots of false warnings when plugins are compiled as dylibs 37 | # warning: cannot resolve item 'libfoobar.dylib' 38 | # etc. Ignore it. 39 | message(STATUS "Searching for plugs in bundle: @CMAKE_INSTALL_PREFIX@/@EXE_NAME@.app/Contents/plugins/*@CMAKE_SHARED_LIBRARY_SUFFIX@") 40 | file(GLOB_RECURSE inplugs 41 | @CMAKE_INSTALL_PREFIX@/@EXE_NAME@.app/Contents/plugins/*@CMAKE_SHARED_LIBRARY_SUFFIX@) 42 | 43 | #message(STATUS "Dylibs: ${inplugs}") 44 | #message(STATUS "DIR: ${DIRS}") 45 | 46 | include(BundleUtilities) 47 | fixup_bundle(@CMAKE_INSTALL_PREFIX@/@EXE_NAME@.app "${inplugs}" @CMAKE_INSTALL_PREFIX@/Contents/plugins/)#${DIRS} ) 48 | 49 | # FIXUP_BUNDLE copies it into MacOS dir. But we need it in plugins *tree*, 50 | # not a flat dir. 51 | foreach (item IN LISTS inplugs) 52 | #message(STATUS "IN: ${item}") 53 | get_filename_component(fname ${item} NAME) 54 | message(STATUS "Moving ${fname} back to plugins tree: ${item}") 55 | #message(STATUS " ${fname}") 56 | #message(STATUS " src: @CMAKE_INSTALL_PREFIX@/@EXE_NAME@.app/Contents/MacOS/${fname}") 57 | #message(STATUS " tgt: ${item}") 58 | execute_process(COMMAND mv @CMAKE_INSTALL_PREFIX@/@EXE_NAME@.app/Contents/MacOS/${fname} ${item}) 59 | endforeach() 60 | 61 | -------------------------------------------------------------------------------- /src/macosx/qterminal.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kghost/qterminal/8a74f14078d80b05c8e2a167ac947c7b55cedfe0/src/macosx/qterminal.icns -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | * Copyright (C) 2006 by Vladimir Kuznetsov * 3 | * vovanec@gmail.com * 4 | * * 5 | * This program is free software; you can redistribute it and/or modify * 6 | * it under the terms of the GNU General Public License as published by * 7 | * the Free Software Foundation; either version 2 of the License, or * 8 | * (at your option) any later version. * 9 | * * 10 | * This program is distributed in the hope that it will be useful, * 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 13 | * GNU General Public License for more details. * 14 | * * 15 | * You should have received a copy of the GNU General Public License * 16 | * along with this program. If not, see . * 17 | ***************************************************************************/ 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | #include 24 | #include 25 | #ifdef HAVE_GETOPT_H 26 | #include 27 | #else 28 | #include "getopt/getopt.h" 29 | #endif // HAVE_GETOPT_H 30 | #include 31 | #ifdef HAVE_QDBUS 32 | #include 33 | #include 34 | #include "processadaptor.h" 35 | #endif 36 | 37 | 38 | #include "mainwindow.h" 39 | #include "qterminalapp.h" 40 | #include "terminalconfig.h" 41 | 42 | #define out 43 | 44 | const char* const short_options = "vhw:e:dp:"; 45 | 46 | const struct option long_options[] = { 47 | {"version", 0, NULL, 'v'}, 48 | {"help", 0, NULL, 'h'}, 49 | {"profile", 1, NULL, 'p'}, 50 | {NULL, 0, NULL, 0} 51 | }; 52 | 53 | QTerminalApp * QTerminalApp::m_instance = NULL; 54 | 55 | void print_usage_and_exit(int code) 56 | { 57 | printf("QTerminal %s\n", QTERMINAL_VERSION); 58 | puts("Usage: qterminal [OPTION]...\n"); 59 | puts(" -h, --help Print this help"); 60 | puts(" -p, --profile Load qterminal with specific options"); 61 | puts(" -v, --version Prints application version and exits"); 62 | puts("\nHomepage: "); 63 | puts("Report bugs to "); 64 | exit(code); 65 | } 66 | 67 | void print_version_and_exit(int code=0) 68 | { 69 | printf("%s\n", QTERMINAL_VERSION); 70 | exit(code); 71 | } 72 | 73 | void parse_args(int argc, char* argv[]) 74 | { 75 | int next_option; 76 | do{ 77 | next_option = getopt_long(argc, argv, short_options, long_options, NULL); 78 | switch(next_option) 79 | { 80 | case 'h': 81 | print_usage_and_exit(0); 82 | break; 83 | case 'p': 84 | Properties::Instance(QString::fromLocal8Bit(optarg)); 85 | break; 86 | case '?': 87 | print_usage_and_exit(1); 88 | break; 89 | case 'v': 90 | print_version_and_exit(); 91 | break; 92 | } 93 | } 94 | while(next_option != -1); 95 | } 96 | 97 | int main(int argc, char *argv[]) 98 | { 99 | QApplication::setApplicationName(QStringLiteral("qterminal")); 100 | QApplication::setApplicationVersion(QStringLiteral(QTERMINAL_VERSION)); 101 | QApplication::setOrganizationDomain(QStringLiteral("qterminal.org")); 102 | #if QT_VERSION >= QT_VERSION_CHECK(5, 7, 0) 103 | QApplication::setDesktopFileName(QLatin1String("qterminal.desktop")); 104 | #endif 105 | // Warning: do not change settings format. It can screw bookmarks later. 106 | QSettings::setDefaultFormat(QSettings::IniFormat); 107 | 108 | QTerminalApp *app = QTerminalApp::Instance(argc, argv); 109 | #ifdef HAVE_QDBUS 110 | app->registerOnDbus(); 111 | #endif 112 | 113 | parse_args(argc, argv); 114 | 115 | const QSettings settings; 116 | const QFileInfo customStyle = QFileInfo( 117 | QFileInfo(settings.fileName()).canonicalPath() + 118 | QStringLiteral("/style.qss") 119 | ); 120 | if (customStyle.isFile() && customStyle.isReadable()) 121 | { 122 | QFile style(customStyle.canonicalFilePath()); 123 | style.open(QFile::ReadOnly); 124 | QString styleString = QLatin1String(style.readAll()); 125 | app->setStyleSheet(styleString); 126 | } 127 | 128 | // icons 129 | /* setup our custom icon theme if there is no system theme (OS X, Windows) */ 130 | QCoreApplication::instance()->setAttribute(Qt::AA_UseHighDpiPixmaps); //Fix for High-DPI systems 131 | if (QIcon::themeName().isEmpty()) 132 | QIcon::setThemeName(QStringLiteral("QTerminal")); 133 | 134 | // translations 135 | QString fname = QString::fromLatin1("qterminal_%1.qm").arg(QLocale::system().name().left(5)); 136 | QTranslator translator; 137 | #ifdef TRANSLATIONS_DIR 138 | qDebug() << "TRANSLATIONS_DIR: Loading translation file" << fname << "from dir" << TRANSLATIONS_DIR; 139 | qDebug() << "load success:" << translator.load(fname, QString::fromUtf8(TRANSLATIONS_DIR), QStringLiteral("_")); 140 | #endif 141 | #ifdef APPLE_BUNDLE 142 | qDebug() << "APPLE_BUNDLE: Loading translator file" << fname << "from dir" << QApplication::applicationDirPath()+"../translations"; 143 | qDebug() << "load success:" << translator.load(fname, QApplication::applicationDirPath()+"../translations", "_"); 144 | #endif 145 | app->installTranslator(&translator); 146 | 147 | int ret = app->exec(); 148 | delete Properties::Instance(); 149 | app->cleanup(); 150 | 151 | return ret; 152 | } 153 | 154 | MainWindow *QTerminalApp::newWindow(TerminalConfig &cfg) 155 | { 156 | MainWindow *window = new MainWindow(cfg, false); 157 | if (Properties::Instance()->windowMaximized) 158 | window->setWindowState(Qt::WindowMaximized); 159 | window->show(); 160 | return window; 161 | } 162 | 163 | QTerminalApp *QTerminalApp::Instance() 164 | { 165 | assert(m_instance != NULL); 166 | return m_instance; 167 | } 168 | 169 | QTerminalApp *QTerminalApp::Instance(int &argc, char **argv) 170 | { 171 | assert(m_instance == NULL); 172 | m_instance = new QTerminalApp(argc, argv); 173 | return m_instance; 174 | } 175 | 176 | namespace Konsole { 177 | __declspec(dllimport) short TargetPtyTcpPort; 178 | } 179 | 180 | QTerminalApp::QTerminalApp(int &argc, char **argv) 181 | :QApplication(argc, argv) 182 | { 183 | bridge = new QProcess(); 184 | connect(bridge, SIGNAL(errorOccurred(QProcess::ProcessError)), this, SLOT(bridgeErrorOccurred(QProcess::ProcessError))); // connect process signals with your code 185 | connect(bridge, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(bridgeFinished(int, QProcess::ExitStatus))); // connect process signals with your code 186 | connect(bridge, SIGNAL(readyReadStandardOutput()), this, SLOT(bridgeOutput())); // connect process signals with your code 187 | bridge->start(QString::fromUtf8("WSL.exe"), {QString::fromUtf8("./tcppty")}); 188 | } 189 | 190 | QTerminalApp::~QTerminalApp() { 191 | bridge->disconnect(); 192 | bridge->close(); 193 | delete bridge; 194 | } 195 | 196 | void QTerminalApp::bridgeErrorOccurred(QProcess::ProcessError error) { 197 | QMessageBox msgBox; 198 | QString msg; 199 | msg.sprintf("Bridge failed (%d), Check your WSL installation.\n\n", error); 200 | msgBox.setIcon(QMessageBox::Critical); 201 | msgBox.setText(msg + QString::fromUtf8(bridge->readAllStandardError())); 202 | msgBox.exec(); 203 | } 204 | 205 | void QTerminalApp::bridgeFinished(int exitCode, QProcess::ExitStatus exitStatus) { 206 | QMessageBox msgBox; 207 | QString msg; 208 | msg.sprintf("Bridge exited (%d/%d), Check your WSL installation.\n\n", exitCode, exitStatus); 209 | msgBox.setIcon(QMessageBox::Critical); 210 | msgBox.setText(msg + QString::fromUtf8(bridge->readAllStandardError())); 211 | msgBox.exec(); 212 | } 213 | 214 | void QTerminalApp::bridgeOutput() { 215 | auto port = bridge->readLine().trimmed().toInt(); 216 | if (port > 0) { 217 | Konsole::TargetPtyTcpPort = port; 218 | newWindow(TerminalConfig()); 219 | } 220 | } 221 | 222 | QString &QTerminalApp::getWorkingDirectory() 223 | { 224 | return m_workDir; 225 | } 226 | 227 | void QTerminalApp::setWorkingDirectory(const QString &wd) 228 | { 229 | m_workDir = wd; 230 | } 231 | 232 | void QTerminalApp::cleanup() { 233 | delete m_instance; 234 | m_instance = NULL; 235 | } 236 | 237 | 238 | void QTerminalApp::addWindow(MainWindow *window) 239 | { 240 | m_windowList.append(window); 241 | } 242 | 243 | void QTerminalApp::removeWindow(MainWindow *window) 244 | { 245 | m_windowList.removeOne(window); 246 | } 247 | 248 | QList QTerminalApp::getWindowList() 249 | { 250 | return m_windowList; 251 | } 252 | 253 | #ifdef HAVE_QDBUS 254 | void QTerminalApp::registerOnDbus() 255 | { 256 | if (!QDBusConnection::sessionBus().isConnected()) 257 | { 258 | fprintf(stderr, "Cannot connect to the D-Bus session bus.\n" 259 | "To start it, run:\n" 260 | "\teval `dbus-launch --auto-syntax`\n"); 261 | return; 262 | } 263 | QString serviceName = QStringLiteral("org.lxqt.QTerminal-%1").arg(getpid()); 264 | if (!QDBusConnection::sessionBus().registerService(serviceName)) 265 | { 266 | fprintf(stderr, "%s\n", qPrintable(QDBusConnection::sessionBus().lastError().message())); 267 | return; 268 | } 269 | new ProcessAdaptor(this); 270 | QDBusConnection::sessionBus().registerObject(QStringLiteral("/"), this); 271 | } 272 | 273 | QList QTerminalApp::getWindows() 274 | { 275 | QList windows; 276 | for (MainWindow *wnd : qAsConst(m_windowList)) 277 | { 278 | windows.push_back(wnd->getDbusPath()); 279 | } 280 | return windows; 281 | } 282 | 283 | QDBusObjectPath QTerminalApp::newWindow(const QHash &termArgs) 284 | { 285 | TerminalConfig cfg = TerminalConfig::fromDbus(termArgs); 286 | MainWindow *wnd = newWindow(false, cfg); 287 | assert(wnd != NULL); 288 | return wnd->getDbusPath(); 289 | } 290 | 291 | QDBusObjectPath QTerminalApp::getActiveWindow() 292 | { 293 | QWidget *aw = activeWindow(); 294 | if (aw == NULL) 295 | return QDBusObjectPath("/"); 296 | return qobject_cast(aw)->getDbusPath(); 297 | } 298 | 299 | #endif 300 | -------------------------------------------------------------------------------- /src/mainwindow.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | * Copyright (C) 2006 by Vladimir Kuznetsov * 3 | * vovanec@gmail.com * 4 | * * 5 | * This program is free software; you can redistribute it and/or modify * 6 | * it under the terms of the GNU General Public License as published by * 7 | * the Free Software Foundation; either version 2 of the License, or * 8 | * (at your option) any later version. * 9 | * * 10 | * This program is distributed in the hope that it will be useful, * 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 13 | * GNU General Public License for more details. * 14 | * * 15 | * You should have received a copy of the GNU General Public License * 16 | * along with this program. If not, see . * 17 | ***************************************************************************/ 18 | 19 | #ifndef MAINWINDOW_H 20 | #define MAINWINDOW_H 21 | 22 | #include "ui_qterminal.h" 23 | 24 | #include 25 | #include 26 | 27 | #include "qxtglobalshortcut.h" 28 | #include "terminalconfig.h" 29 | #include "dbusaddressable.h" 30 | 31 | 32 | class QToolButton; 33 | 34 | class MainWindow : public QMainWindow, private Ui::mainWindow, public DBusAddressable 35 | { 36 | Q_OBJECT 37 | 38 | public: 39 | MainWindow(TerminalConfig& cfg, 40 | bool dropMode, 41 | QWidget * parent = 0, Qt::WindowFlags f = 0); 42 | ~MainWindow(); 43 | 44 | bool dropMode() { return m_dropMode; } 45 | QMap & leaseActions(); 46 | 47 | #ifdef HAVE_QDBUS 48 | QDBusObjectPath getActiveTab(); 49 | QList getTabs(); 50 | QDBusObjectPath newTab(const QHash &termArgs); 51 | void closeWindow(); 52 | #endif 53 | 54 | protected: 55 | bool event(QEvent* event); 56 | 57 | private: 58 | QActionGroup *tabPosition, *scrollBarPosition, *keyboardCursorShape; 59 | QMenu *tabPosMenu, *scrollPosMenu, *keyboardCursorShapeMenu; 60 | 61 | // A parent object for QObjects that are created dynamically based on settings 62 | // Used to simplify the setting cleanup on reconfiguration: deleting settingOwner frees all related QObjects 63 | QWidget *settingOwner; 64 | 65 | QMenu *presetsMenu; 66 | bool m_removeFinished; 67 | TerminalConfig m_config; 68 | 69 | QDockWidget *m_bookmarksDock; 70 | 71 | void setup_Action(const char *name, QAction *action, const char *defaultShortcut, const QObject *receiver, 72 | const char *slot, QMenu *menu = NULL, const QVariant &data = QVariant()); 73 | QMap< QString, QAction * > actions; 74 | 75 | void rebuildActions(); 76 | 77 | void setup_FileMenu_Actions(); 78 | void setup_ActionsMenu_Actions(); 79 | void setup_ViewMenu_Actions(); 80 | void setup_ContextMenu_Actions(); 81 | void setupCustomDirs(); 82 | 83 | void closeEvent(QCloseEvent*); 84 | 85 | void enableDropMode(); 86 | QToolButton *m_dropLockButton; 87 | bool m_dropMode; 88 | QxtGlobalShortcut m_dropShortcut; 89 | void realign(); 90 | void setDropShortcut(QKeySequence dropShortCut); 91 | 92 | bool hasMultipleTabs(); 93 | bool hasMultipleSubterminals(); 94 | 95 | public slots: 96 | void showHide(); 97 | void updateDisabledActions(); 98 | 99 | private slots: 100 | void on_consoleTabulator_currentChanged(int); 101 | void propertiesChanged(); 102 | void actAbout_triggered(); 103 | void actProperties_triggered(); 104 | void updateActionGroup(QAction *); 105 | void testClose(bool removeFinished); 106 | void toggleBookmarks(); 107 | void toggleBorderless(); 108 | void toggleTabBar(); 109 | void toggleMenu(); 110 | 111 | void showFullscreen(bool fullscreen); 112 | void setKeepOpen(bool value); 113 | void find(); 114 | 115 | void newTerminalWindow(); 116 | void bookmarksWidget_callCommand(const QString&); 117 | void bookmarksDock_visibilityChanged(bool visible); 118 | 119 | void addNewTab(); 120 | void onCurrentTitleChanged(int index); 121 | 122 | }; 123 | #endif //MAINWINDOW_H 124 | -------------------------------------------------------------------------------- /src/org.lxqt.QTerminal.Process.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/org.lxqt.QTerminal.Tab.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/org.lxqt.QTerminal.Terminal.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /src/org.lxqt.QTerminal.Window.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/properties.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | * Copyright (C) 2010 by Petr Vanek * 3 | * petr@scribus.info * 4 | * * 5 | * This program is free software; you can redistribute it and/or modify * 6 | * it under the terms of the GNU General Public License as published by * 7 | * the Free Software Foundation; either version 2 of the License, or * 8 | * (at your option) any later version. * 9 | * * 10 | * This program is distributed in the hope that it will be useful, * 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 13 | * GNU General Public License for more details. * 14 | * * 15 | * You should have received a copy of the GNU General Public License * 16 | * along with this program. If not, see . * 17 | ***************************************************************************/ 18 | 19 | #ifndef PROPERTIES_H 20 | #define PROPERTIES_H 21 | 22 | #include 23 | #include 24 | #include 25 | 26 | typedef QString Session; 27 | 28 | typedef QMap Sessions; 29 | 30 | typedef QMap ShortcutMap; 31 | 32 | 33 | class Properties 34 | { 35 | public: 36 | static Properties *Instance(const QString& filename = QString()); 37 | ~Properties(); 38 | 39 | QFont defaultFont(); 40 | void saveSettings(); 41 | void loadSettings(); 42 | void migrate_settings(); 43 | 44 | QSize mainWindowSize; 45 | QPoint mainWindowPosition; 46 | QByteArray mainWindowState; 47 | //ShortcutMap shortcuts; 48 | QString shell; 49 | QFont font; 50 | QString colorScheme; 51 | QString guiStyle; 52 | bool highlightCurrentTerminal; 53 | bool showTerminalSizeHint; 54 | 55 | bool historyLimited; 56 | unsigned historyLimitedTo; 57 | 58 | QString emulation; 59 | 60 | Sessions sessions; 61 | 62 | int terminalMargin; 63 | int appTransparency; 64 | int termTransparency; 65 | QString backgroundImage; 66 | 67 | int scrollBarPos; 68 | int tabsPos; 69 | int keyboardCursorShape; 70 | bool hideTabBarWithOneTab; 71 | int m_motionAfterPaste; 72 | 73 | bool fixedTabWidth; 74 | int fixedTabWidthValue; 75 | 76 | bool showCloseTabButton; 77 | 78 | bool borderless; 79 | bool tabBarless; 80 | bool menuVisible; 81 | 82 | bool askOnExit; 83 | 84 | bool saveSizeOnExit; 85 | bool savePosOnExit; 86 | 87 | bool useCWD; 88 | 89 | QString term; 90 | 91 | bool useBookmarks; 92 | bool bookmarksVisible; 93 | QString bookmarksFile; 94 | 95 | int terminalsPreset; 96 | 97 | QKeySequence dropShortCut; 98 | bool dropKeepOpen; 99 | bool dropShowOnStart; 100 | int dropWidht; 101 | int dropHeight; 102 | 103 | bool changeWindowTitle; 104 | bool changeWindowIcon; 105 | bool enabledBidiSupport; 106 | 107 | bool confirmMultilinePaste; 108 | bool trimPastedTrailingNewlines; 109 | 110 | bool windowMaximized; 111 | 112 | 113 | private: 114 | 115 | // Singleton handling 116 | static Properties *m_instance; 117 | QString filename; 118 | 119 | explicit Properties(const QString& filename); 120 | Properties(const Properties &) {}; 121 | 122 | QSettings *m_settings; 123 | 124 | }; 125 | 126 | #endif 127 | 128 | -------------------------------------------------------------------------------- /src/propertiesdialog.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | * Copyright (C) 2010 by Petr Vanek * 3 | * petr@scribus.info * 4 | * * 5 | * This program is free software; you can redistribute it and/or modify * 6 | * it under the terms of the GNU General Public License as published by * 7 | * the Free Software Foundation; either version 2 of the License, or * 8 | * (at your option) any later version. * 9 | * * 10 | * This program is distributed in the hope that it will be useful, * 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 13 | * GNU General Public License for more details. * 14 | * * 15 | * You should have received a copy of the GNU General Public License * 16 | * along with this program. If not, see . * 17 | ***************************************************************************/ 18 | 19 | #ifndef PROPERTIESDIALOG_H 20 | #define PROPERTIESDIALOG_H 21 | 22 | #include 23 | #include 24 | #include "ui_propertiesdialog.h" 25 | 26 | class KeySequenceEdit : public QKeySequenceEdit 27 | { 28 | Q_OBJECT 29 | 30 | public: 31 | KeySequenceEdit(QWidget *parent = nullptr) : QKeySequenceEdit(parent) {} 32 | 33 | // to be used with Tab and Backtab 34 | void pressKey(QKeyEvent *event) { 35 | QKeySequenceEdit::keyPressEvent(event); 36 | } 37 | }; 38 | 39 | class Delegate : public QStyledItemDelegate 40 | { 41 | Q_OBJECT 42 | 43 | public: 44 | Delegate (QObject *parent = 0); 45 | 46 | virtual QWidget* createEditor(QWidget *parent, 47 | const QStyleOptionViewItem&, 48 | const QModelIndex&) const; 49 | virtual bool eventFilter(QObject *object, QEvent *event); 50 | }; 51 | 52 | class PropertiesDialog : public QDialog, Ui::PropertiesDialog 53 | { 54 | Q_OBJECT 55 | 56 | QString oldAccelText; // Placeholder when editing shortcut 57 | 58 | public: 59 | PropertiesDialog(QWidget *parent=NULL); 60 | ~PropertiesDialog(); 61 | 62 | signals: 63 | void propertiesChanged(); 64 | 65 | private: 66 | void setFontSample(const QFont & f); 67 | void openBookmarksFile(const QString &fname); 68 | void saveBookmarksFile(const QString &fname); 69 | 70 | private slots: 71 | void apply(); 72 | void accept(); 73 | 74 | void changeFontButton_clicked(); 75 | void chooseBackgroundImageButton_clicked(); 76 | void bookmarksButton_clicked(); 77 | 78 | protected: 79 | void setupShortcuts(); 80 | void saveShortcuts(); 81 | }; 82 | 83 | 84 | #endif 85 | 86 | -------------------------------------------------------------------------------- /src/qterminal.rc: -------------------------------------------------------------------------------- 1 | IDI_ICON1 ICON DISCARDABLE "icons/qterminal.ico" 2 | -------------------------------------------------------------------------------- /src/qterminalapp.h: -------------------------------------------------------------------------------- 1 | #ifndef QTERMINALAPP_H 2 | #define QTERMINALAPP_H 3 | 4 | #include 5 | #ifdef HAVE_QDBUS 6 | #include 7 | #endif 8 | 9 | 10 | #include "mainwindow.h" 11 | 12 | class QProcess; 13 | class QTerminalApp : public QApplication 14 | { 15 | Q_OBJECT 16 | 17 | public: 18 | MainWindow *newWindow(TerminalConfig &cfg); 19 | QList getWindowList(); 20 | void addWindow(MainWindow *window); 21 | void removeWindow(MainWindow *window); 22 | static QTerminalApp *Instance(int &argc, char **argv); 23 | static QTerminalApp *Instance(); 24 | QString &getWorkingDirectory(); 25 | void setWorkingDirectory(const QString &wd); 26 | 27 | #ifdef HAVE_QDBUS 28 | void registerOnDbus(); 29 | QList getWindows(); 30 | QDBusObjectPath newWindow(const QHash &termArgs); 31 | QDBusObjectPath getActiveWindow(); 32 | #endif 33 | 34 | static void cleanup(); 35 | 36 | private: 37 | QProcess *bridge; 38 | QString m_workDir; 39 | QList m_windowList; 40 | static QTerminalApp *m_instance; 41 | QTerminalApp(int &argc, char **argv); 42 | ~QTerminalApp(); 43 | 44 | private slots: 45 | void bridgeErrorOccurred(QProcess::ProcessError error); 46 | void bridgeFinished(int exitCode, QProcess::ExitStatus exitStatus); 47 | void bridgeOutput(); 48 | }; 49 | 50 | template T* findParent(QObject *child) 51 | { 52 | QObject *maybeT = child; 53 | while (true) 54 | { 55 | if (maybeT == NULL) 56 | { 57 | return NULL; 58 | } 59 | T *holder = qobject_cast(maybeT); 60 | if (holder) 61 | return holder; 62 | maybeT = maybeT->parent(); 63 | } 64 | } 65 | 66 | #endif -------------------------------------------------------------------------------- /src/tab-switcher.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "tab-switcher.h" 7 | #include "tabwidget.h" 8 | 9 | // ----------------------------------------------------------------------------------------------------------- 10 | 11 | enum class AppRole { 12 | Display = Qt::DisplayRole, 13 | Index = Qt::UserRole +1 14 | }; 15 | 16 | // ----------------------------------------------------------------------------------------------------------- 17 | 18 | AppModel::AppModel(QObject* parent, TabWidget* tabs): 19 | QAbstractListModel(parent) 20 | { 21 | for(QWidget* w: tabs->history()) { 22 | int index = w->property("tab_index").toInt(); 23 | m_list.append({tabs->tabText(index), index}); 24 | } 25 | } 26 | 27 | int AppModel::rowCount(const QModelIndex& /*parent*/) const 28 | { 29 | return m_list.size(); 30 | } 31 | 32 | QVariant AppModel::data(const QModelIndex &index, int role) const 33 | { 34 | if (!index.isValid() || index.row() >= m_list.size()) 35 | return QVariant(); 36 | 37 | switch(static_cast(role)) { 38 | case AppRole::Display: 39 | return m_list[index.row()].name; 40 | case AppRole::Index: 41 | return m_list[index.row()].index; 42 | } 43 | 44 | return {}; 45 | } 46 | 47 | // ----------------------------------------------------------------------------------------------------------- 48 | 49 | class AppItemDelegate: public QStyledItemDelegate 50 | { 51 | public: 52 | AppItemDelegate(int frameWidth = 0, QWidget* parent = nullptr) : 53 | QStyledItemDelegate(parent), 54 | mParent(parent), 55 | mFrameWidth(frameWidth) {} 56 | 57 | protected: 58 | void paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const override 59 | { 60 | QStyle *style = option.widget ? option.widget->style() : QApplication::style(); 61 | 62 | QString text = index.model()->data(index, static_cast(AppRole::Display)).toString(); 63 | 64 | QStyleOptionViewItem opt = option; 65 | initStyleOption(&opt, index); 66 | opt.text = text; 67 | style->drawControl(QStyle::CE_ItemViewItem, &opt, painter, option.widget); 68 | } 69 | 70 | QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override 71 | { 72 | QStyleOptionViewItem opt = option; 73 | initStyleOption(&opt, index); 74 | opt.decorationSize = QSize(0, 0); 75 | opt.text = index.model()->data(index, static_cast(AppRole::Display)).toString();; 76 | const QWidget* widget = option.widget; 77 | QStyle* style = widget ? widget->style() : QApplication::style(); 78 | QSize contSize = style->sizeFromContents(QStyle::CT_ItemViewItem, &opt, QSize(), widget); 79 | 80 | return QSize( 81 | mParent ? qMin(mParent->width() - 2 * mFrameWidth, contSize.width()) : contSize.width(), 82 | contSize.height() 83 | ); 84 | } 85 | private: 86 | QWidget* mParent; 87 | int mFrameWidth; 88 | }; 89 | 90 | // ----------------------------------------------------------------------------------------------------------- 91 | 92 | TabSwitcher::TabSwitcher(TabWidget* tabs): 93 | QListView(tabs), 94 | m_tabs(tabs) 95 | { 96 | setWindowFlags(Qt::Widget | Qt::Popup | Qt::WindowStaysOnTopHint); 97 | setItemDelegate(new AppItemDelegate(frameWidth(), tabs)); 98 | setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); 99 | 100 | m_timer = new QTimer(this); 101 | m_timer->setInterval(100); 102 | m_timer->setSingleShot(true); 103 | 104 | connect(m_timer, &QTimer::timeout, this, &TabSwitcher::timer); 105 | } 106 | 107 | TabSwitcher::~TabSwitcher() 108 | {} 109 | 110 | void TabSwitcher::showSwitcher() 111 | { 112 | setModel(new AppModel(this, m_tabs)); 113 | 114 | if (!model()->rowCount()) 115 | return; 116 | 117 | QStyleOptionViewItem option; 118 | 119 | int w = 0; 120 | int h = 0; 121 | int maxApp = 15; 122 | 123 | for(int i = 0; i < model()->rowCount(); ++i){ 124 | QSize siz = itemDelegate()->sizeHint(option, model()->index(i, 0)); 125 | w = qMax(w, siz.width()); 126 | h += siz.height(); 127 | if (i > maxApp) 128 | break; 129 | } 130 | 131 | 132 | w += 2 * frameWidth(); 133 | h += 2 * frameWidth(); 134 | resize(w, h); 135 | 136 | QPoint pos = m_tabs->mapToGlobal(m_tabs->geometry().topLeft()); 137 | move(pos.x()+m_tabs->geometry().width()/2 - w / 2, pos.y()+m_tabs->geometry().height()/2 - h / 2); 138 | 139 | show(); 140 | } 141 | 142 | void TabSwitcher::selectItem(bool forward) 143 | { 144 | if (!isVisible()) 145 | showSwitcher(); 146 | 147 | int current = currentIndex().row(); 148 | current = (current < 0) ? 0 : current; 149 | 150 | m_timer->start(); 151 | current += forward ? 1 : -1; 152 | 153 | if(current >= model()->rowCount()) 154 | current = 0; 155 | 156 | if(current < 0) 157 | current = model()->rowCount()-1; 158 | 159 | setCurrentIndex(model()->index(current, 0)); 160 | } 161 | 162 | void TabSwitcher::keyReleaseEvent(QKeyEvent *event) 163 | { 164 | if (event->modifiers() == 0) 165 | close(); 166 | 167 | QWidget::keyReleaseEvent(event); 168 | } 169 | 170 | void TabSwitcher::timer() 171 | { 172 | if (QApplication::queryKeyboardModifiers() == Qt::NoModifier) 173 | close(); 174 | else 175 | m_timer->start(); 176 | } 177 | 178 | void TabSwitcher::closeEvent(QCloseEvent *) 179 | { 180 | m_timer->stop(); 181 | activateTab(model()->data(model()->index(currentIndex().row(), 0), static_cast(AppRole::Index)).value()); 182 | } 183 | 184 | // ----------------------------------------------------------------------------------------------------------- 185 | 186 | -------------------------------------------------------------------------------- /src/tab-switcher.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | class TabWidget; 7 | 8 | // ----------------------------------------------------------------------------------------------------------- 9 | 10 | class AppModel : public QAbstractListModel 11 | { 12 | Q_OBJECT 13 | public: 14 | AppModel(QObject* parent, TabWidget* tabs); 15 | 16 | protected: 17 | int rowCount(const QModelIndex& parent = QModelIndex()) const override; 18 | QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; 19 | 20 | private: 21 | struct AppInfo { 22 | QString name; 23 | int index; 24 | }; 25 | 26 | QList m_list; 27 | }; 28 | 29 | // ----------------------------------------------------------------------------------------------------------- 30 | 31 | class TabSwitcher: public QListView 32 | { 33 | Q_OBJECT 34 | 35 | public: 36 | TabSwitcher(TabWidget* tabs); 37 | ~TabSwitcher() override; 38 | void selectItem(bool forward = true); 39 | 40 | signals: 41 | void activateTab(int index) const; 42 | 43 | protected: 44 | void keyReleaseEvent(QKeyEvent *event) override; 45 | void closeEvent(QCloseEvent *) override; 46 | 47 | private: 48 | void showSwitcher(); 49 | void timer(); 50 | 51 | private: 52 | QTimer *m_timer; 53 | TabWidget* m_tabs; 54 | }; 55 | 56 | // ----------------------------------------------------------------------------------------------------------- 57 | 58 | -------------------------------------------------------------------------------- /src/tabbar.cpp: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | * Copyright (C) 2017 by Nathan Osman * 3 | * nathan@quickmediasolutions.com * 4 | * * 5 | * This program is free software; you can redistribute it and/or modify * 6 | * it under the terms of the GNU General Public License as published by * 7 | * the Free Software Foundation; either version 2 of the License, or * 8 | * (at your option) any later version. * 9 | * * 10 | * This program is distributed in the hope that it will be useful, * 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 13 | * GNU General Public License for more details. * 14 | * * 15 | * You should have received a copy of the GNU General Public License * 16 | * along with this program. If not, see . * 17 | ***************************************************************************/ 18 | 19 | #include "tabbar.h" 20 | 21 | TabBar::TabBar(QWidget *parent) 22 | : QTabBar(parent), 23 | mFixedWidth(false), 24 | mFixedWidthValue(0) 25 | { 26 | // To make the selected tab text bold, first give a bold font to the tabbar 27 | // for QStyle::sizeFromContents(QStyle::CT_TabBarTab, ...) to make room 28 | // for the bold text, and then, set the non-selected tab text to normal. 29 | QFont f = font(); 30 | f.setBold(true); 31 | setFont(f); 32 | setStyleSheet(QStringLiteral("QTabBar::tab:!selected { font-weight: normal; }")); 33 | } 34 | 35 | void TabBar::setFixedWidth(bool fixedWidth) 36 | { 37 | mFixedWidth = fixedWidth; 38 | } 39 | 40 | void TabBar::setFixedWidthValue(int value) 41 | { 42 | mFixedWidthValue = value; 43 | } 44 | 45 | void TabBar::updateWidth() 46 | { 47 | // This seems to be the only way to trigger an update 48 | setIconSize(iconSize()); 49 | setElideMode(Qt::ElideMiddle); 50 | } 51 | 52 | QSize TabBar::tabSizeHint(int index) const 53 | { 54 | QSize size = QTabBar::tabSizeHint(index); 55 | 56 | // If the width is fixed, use that for the width hint 57 | if (mFixedWidth) { 58 | if (shape() == QTabBar::RoundedEast || shape() == QTabBar::TriangularEast 59 | || shape() == QTabBar::RoundedWest || shape() == QTabBar::TriangularWest) { 60 | size.setHeight(mFixedWidthValue); 61 | } 62 | else { 63 | size.setWidth(mFixedWidthValue); 64 | } 65 | } 66 | 67 | return size; 68 | } 69 | -------------------------------------------------------------------------------- /src/tabbar.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | * Copyright (C) 2017 by Nathan Osman * 3 | * nathan@quickmediasolutions.com * 4 | * * 5 | * This program is free software; you can redistribute it and/or modify * 6 | * it under the terms of the GNU General Public License as published by * 7 | * the Free Software Foundation; either version 2 of the License, or * 8 | * (at your option) any later version. * 9 | * * 10 | * This program is distributed in the hope that it will be useful, * 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 13 | * GNU General Public License for more details. * 14 | * * 15 | * You should have received a copy of the GNU General Public License * 16 | * along with this program. If not, see . * 17 | ***************************************************************************/ 18 | 19 | #ifndef TABBAR_H 20 | #define TABBAR_H 21 | 22 | #include 23 | #include 24 | 25 | class TabBar : public QTabBar 26 | { 27 | Q_OBJECT 28 | 29 | public: 30 | 31 | explicit TabBar(QWidget *parent); 32 | 33 | void setFixedWidth(bool fixedWidth); 34 | void setFixedWidthValue(int value); 35 | void updateWidth(); 36 | 37 | protected: 38 | 39 | virtual QSize tabSizeHint(int index) const; 40 | 41 | private: 42 | 43 | bool mFixedWidth; 44 | int mFixedWidthValue; 45 | }; 46 | 47 | #endif // TABBAR_H 48 | -------------------------------------------------------------------------------- /src/tabwidget.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | * Copyright (C) 2006 by Vladimir Kuznetsov * 3 | * vovanec@gmail.com * 4 | * * 5 | * This program is free software; you can redistribute it and/or modify * 6 | * it under the terms of the GNU General Public License as published by * 7 | * the Free Software Foundation; either version 2 of the License, or * 8 | * (at your option) any later version. * 9 | * * 10 | * This program is distributed in the hope that it will be useful, * 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 13 | * GNU General Public License for more details. * 14 | * * 15 | * You should have received a copy of the GNU General Public License * 16 | * along with this program. If not, see . * 17 | ***************************************************************************/ 18 | 19 | #ifndef TAB_WIDGET 20 | #define TAB_WIDGET 21 | 22 | #include 23 | #include 24 | #include 25 | 26 | #ifdef HAVE_QDBUS 27 | #include 28 | #include "dbusaddressable.h" 29 | #endif 30 | 31 | #include "terminalconfig.h" 32 | #include "properties.h" 33 | 34 | class TabBar; 35 | class TermWidgetHolder; 36 | class QAction; 37 | class QActionGroup; 38 | class TabSwitcher; 39 | 40 | class TabWidget : public QTabWidget 41 | { 42 | Q_OBJECT 43 | public: 44 | TabWidget(QWidget* parent = 0); 45 | ~TabWidget() override; 46 | 47 | TermWidgetHolder * terminalHolder(); 48 | 49 | void showHideTabBar(); 50 | const QList& history() const; 51 | 52 | public slots: 53 | int addNewTab(TerminalConfig cfg); 54 | void removeTab(int); 55 | void switchTab(int); 56 | void saveCurrentChanged(int); 57 | void removeCurrentTab(); 58 | int switchToRight(); 59 | int switchToLeft(); 60 | void removeFinished(); 61 | void moveLeft(); 62 | void moveRight(); 63 | void renameSession(int); 64 | void renameCurrentSession(); 65 | void setTitleColor(int); 66 | 67 | void switchLeftSubterminal(); 68 | void switchRightSubterminal(); 69 | void switchTopSubterminal(); 70 | void switchBottomSubterminal(); 71 | 72 | void splitHorizontally(); 73 | void splitVertically(); 74 | void splitCollapse(); 75 | 76 | void copySelection(); 77 | void pasteClipboard(); 78 | void pasteSelection(); 79 | void zoomIn(); 80 | void zoomOut(); 81 | void zoomReset(); 82 | 83 | void changeTabPosition(QAction *); 84 | void changeScrollPosition(QAction *); 85 | void changeKeyboardCursorShape(QAction *); 86 | void propertiesChanged(); 87 | 88 | void clearActiveTerminal(); 89 | 90 | void saveSession(); 91 | void loadSession(); 92 | 93 | void preset2Horizontal(); 94 | void preset2Vertical(); 95 | void preset4Terminals(); 96 | 97 | void switchToNext(); 98 | void switchToPrev(); 99 | signals: 100 | void closeTabNotification(bool); 101 | void tabRenameRequested(int); 102 | void tabTitleColorChangeRequested(int); 103 | void currentTitleChanged(int); 104 | 105 | protected: 106 | enum Direction{Left = 1, Right}; 107 | void contextMenuEvent(QContextMenuEvent * event); 108 | void move(Direction); 109 | /*! Event filter for TabWidget's QTabBar. It's installed on tabBar() 110 | in the constructor. 111 | It's purpose is to handle doubleclicks on QTabBar for session 112 | renaming or new tab opening 113 | */ 114 | bool eventFilter(QObject *obj, QEvent *event); 115 | protected slots: 116 | void updateTabIndices(); 117 | void onTermTitleChanged(QString title, QString icon); 118 | 119 | private: 120 | int tabNumerator; 121 | /* re-order naming of the tabs then removeCurrentTab() */ 122 | void renameTabsAfterRemove(); 123 | 124 | TabBar *mTabBar; 125 | QScopedPointer mSwitcher; 126 | QList mHistory; 127 | }; 128 | 129 | #endif 130 | -------------------------------------------------------------------------------- /src/terminalconfig.cpp: -------------------------------------------------------------------------------- 1 | 2 | 3 | #include 4 | #include 5 | 6 | #include "qterminalapp.h" 7 | #include "terminalconfig.h" 8 | #include "properties.h" 9 | #include "termwidget.h" 10 | 11 | TerminalConfig::TerminalConfig(const QString & wdir, const QString & shell) 12 | { 13 | m_workingDirectory = wdir; 14 | m_shell = shell; 15 | } 16 | 17 | TerminalConfig::TerminalConfig() 18 | { 19 | } 20 | 21 | TerminalConfig::TerminalConfig(const TerminalConfig &cfg) 22 | : m_currentDirectory(cfg.m_currentDirectory), 23 | m_workingDirectory(cfg.m_workingDirectory), 24 | m_shell(cfg.m_shell) {} 25 | 26 | QString TerminalConfig::getWorkingDirectory() 27 | { 28 | if (!m_workingDirectory.isEmpty()) 29 | return m_workingDirectory; 30 | if (Properties::Instance()->useCWD && !m_currentDirectory.isEmpty()) 31 | return m_currentDirectory; 32 | return QTerminalApp::Instance()->getWorkingDirectory(); 33 | } 34 | 35 | QString TerminalConfig::getShell() 36 | { 37 | if (!m_shell.isEmpty()) 38 | return m_shell; 39 | if (!Properties::Instance()->shell.isEmpty()) 40 | return Properties::Instance()->shell; 41 | QByteArray envShell = qgetenv("SHELL"); 42 | if (envShell.constData() != NULL) 43 | { 44 | QString shellString = QString::fromLocal8Bit(envShell); 45 | if (!shellString.isEmpty()) 46 | return shellString; 47 | } 48 | return QString(); 49 | } 50 | 51 | void TerminalConfig::setWorkingDirectory(const QString &val) 52 | { 53 | m_workingDirectory = val; 54 | } 55 | 56 | void TerminalConfig::setShell(const QString &val) 57 | { 58 | m_shell = val; 59 | } 60 | 61 | void TerminalConfig::provideCurrentDirectory(const QString &val) 62 | { 63 | m_currentDirectory = val; 64 | } 65 | 66 | 67 | 68 | #if HAVE_QDBUS 69 | 70 | #define DBUS_ARG_WORKDIR "workingDirectory" 71 | #define DBUS_ARG_SHELL "shell" 72 | 73 | TerminalConfig TerminalConfig::fromDbus(const QHash &termArgsConst, TermWidget *toSplit) 74 | { 75 | QHash termArgs(termArgsConst); 76 | if (toSplit != NULL && !termArgs.contains(QLatin1String(DBUS_ARG_WORKDIR))) 77 | { 78 | termArgs[QLatin1String(DBUS_ARG_WORKDIR)] = QVariant(toSplit->impl()->workingDirectory()); 79 | } 80 | return TerminalConfig::fromDbus(termArgs); 81 | } 82 | 83 | static QString variantToString(QVariant variant, QString &defaultVal) 84 | { 85 | if (variant.type() == QVariant::String) 86 | return qvariant_cast(variant); 87 | return defaultVal; 88 | } 89 | 90 | TerminalConfig TerminalConfig::fromDbus(const QHash &termArgs) 91 | { 92 | QString wdir = QString(); 93 | QString shell(Properties::Instance()->shell); 94 | if (termArgs.contains(QLatin1String(DBUS_ARG_WORKDIR))) 95 | { 96 | wdir = variantToString(termArgs[QLatin1String(DBUS_ARG_WORKDIR)], wdir); 97 | } 98 | if (termArgs.contains(QLatin1String(DBUS_ARG_SHELL))) { 99 | shell = variantToString(termArgs[QLatin1String(DBUS_ARG_SHELL)], shell); 100 | } 101 | return TerminalConfig(wdir, shell); 102 | } 103 | 104 | #endif 105 | 106 | -------------------------------------------------------------------------------- /src/terminalconfig.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef TERMINALCONFIG_H 3 | #define TERMINALCONFIG_H 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | class TermWidget; 10 | 11 | class TerminalConfig 12 | { 13 | public: 14 | TerminalConfig(const QString & wdir, const QString & shell); 15 | TerminalConfig(const TerminalConfig &cfg); 16 | TerminalConfig(); 17 | 18 | QString getWorkingDirectory(); 19 | QString getShell(); 20 | 21 | void setWorkingDirectory(const QString &val); 22 | void setShell(const QString &val); 23 | void provideCurrentDirectory(const QString &val); 24 | 25 | #ifdef HAVE_QDBUS 26 | static TerminalConfig fromDbus(const QHash &termArgs); 27 | static TerminalConfig fromDbus(const QHash &termArgs, TermWidget *toSplit); 28 | #endif 29 | 30 | 31 | private: 32 | // True when 33 | QString m_currentDirectory; 34 | QString m_workingDirectory; 35 | QString m_shell; 36 | }; 37 | 38 | #endif -------------------------------------------------------------------------------- /src/termwidget.cpp: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | * Copyright (C) 2010 by Petr Vanek * 3 | * petr@scribus.info * 4 | * * 5 | * This program is free software; you can redistribute it and/or modify * 6 | * it under the terms of the GNU General Public License as published by * 7 | * the Free Software Foundation; either version 2 of the License, or * 8 | * (at your option) any later version. * 9 | * * 10 | * This program is distributed in the hope that it will be useful, * 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 13 | * GNU General Public License for more details. * 14 | * * 15 | * You should have received a copy of the GNU General Public License * 16 | * along with this program. If not, see . * 17 | ***************************************************************************/ 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #ifdef HAVE_QDBUS 29 | #include 30 | #include "termwidgetholder.h" 31 | #include "terminaladaptor.h" 32 | #endif 33 | 34 | 35 | #include "mainwindow.h" 36 | #include "termwidget.h" 37 | #include "config.h" 38 | #include "properties.h" 39 | #include "qterminalapp.h" 40 | 41 | static int TermWidgetCount = 0; 42 | 43 | 44 | TermWidgetImpl::TermWidgetImpl(TerminalConfig &cfg, QWidget * parent) 45 | : QTermWidget(0, parent) 46 | { 47 | TermWidgetCount++; 48 | QString name(QStringLiteral("TermWidget_%1")); 49 | setObjectName(name.arg(TermWidgetCount)); 50 | 51 | setFlowControlEnabled(FLOW_CONTROL_ENABLED); 52 | setFlowControlWarningEnabled(FLOW_CONTROL_WARNING_ENABLED); 53 | 54 | propertiesChanged(); 55 | 56 | setHistorySize(5000); 57 | 58 | setWorkingDirectory(cfg.getWorkingDirectory()); 59 | 60 | QString shell = cfg.getShell(); 61 | if (!shell.isEmpty()) 62 | { 63 | qDebug() << "Shell program:" << shell; 64 | QStringList parts = shell.split(QRegExp(QStringLiteral("\\s+")), QString::SkipEmptyParts); 65 | qDebug() << parts; 66 | setShellProgram(parts.at(0)); 67 | parts.removeAt(0); 68 | if (parts.count()) 69 | setArgs(parts); 70 | } 71 | 72 | setMotionAfterPasting(Properties::Instance()->m_motionAfterPaste); 73 | 74 | setContextMenuPolicy(Qt::CustomContextMenu); 75 | connect(this, &QWidget::customContextMenuRequested, 76 | this, &TermWidgetImpl::customContextMenuCall); 77 | 78 | connect(this, &QTermWidget::urlActivated, this, &TermWidgetImpl::activateUrl); 79 | 80 | startShellProgram(); 81 | } 82 | 83 | void TermWidgetImpl::propertiesChanged() 84 | { 85 | setMargin(Properties::Instance()->terminalMargin); 86 | setColorScheme(Properties::Instance()->colorScheme); 87 | setTerminalFont(Properties::Instance()->font); 88 | setMotionAfterPasting(Properties::Instance()->m_motionAfterPaste); 89 | setTerminalSizeHint(Properties::Instance()->showTerminalSizeHint); 90 | 91 | if (Properties::Instance()->historyLimited) 92 | { 93 | setHistorySize(Properties::Instance()->historyLimitedTo); 94 | } 95 | else 96 | { 97 | // Unlimited history 98 | setHistorySize(-1); 99 | } 100 | 101 | setKeyBindings(Properties::Instance()->emulation); 102 | setTerminalOpacity(1.0 - Properties::Instance()->termTransparency/100.0); 103 | setTerminalBackgroundImage(Properties::Instance()->backgroundImage); 104 | setBidiEnabled(Properties::Instance()->enabledBidiSupport); 105 | 106 | /* be consequent with qtermwidget.h here */ 107 | switch(Properties::Instance()->scrollBarPos) { 108 | case 0: 109 | setScrollBarPosition(QTermWidget::NoScrollBar); 110 | break; 111 | case 1: 112 | setScrollBarPosition(QTermWidget::ScrollBarLeft); 113 | break; 114 | case 2: 115 | default: 116 | setScrollBarPosition(QTermWidget::ScrollBarRight); 117 | break; 118 | } 119 | 120 | switch(Properties::Instance()->keyboardCursorShape) { 121 | case 1: 122 | setKeyboardCursorShape(QTermWidget::KeyboardCursorShape::UnderlineCursor); 123 | break; 124 | case 2: 125 | setKeyboardCursorShape(QTermWidget::KeyboardCursorShape::IBeamCursor); 126 | break; 127 | default: 128 | case 0: 129 | setKeyboardCursorShape(QTermWidget::KeyboardCursorShape::BlockCursor); 130 | break; 131 | } 132 | 133 | update(); 134 | } 135 | 136 | void TermWidgetImpl::customContextMenuCall(const QPoint & pos) 137 | { 138 | QMenu menu; 139 | QMap actions = findParent(this)->leaseActions(); 140 | 141 | QList extraActions = filterActions(pos); 142 | for (auto& action : extraActions) 143 | { 144 | menu.addAction(action); 145 | } 146 | 147 | if (!actions.isEmpty()) 148 | { 149 | menu.addSeparator(); 150 | } 151 | 152 | menu.addAction(actions[QStringLiteral(COPY_SELECTION)]); 153 | menu.addAction(actions[QStringLiteral(PASTE_CLIPBOARD)]); 154 | menu.addAction(actions[QStringLiteral(PASTE_SELECTION)]); 155 | menu.addAction(actions[QStringLiteral(ZOOM_IN)]); 156 | menu.addAction(actions[QStringLiteral(ZOOM_OUT)]); 157 | menu.addAction(actions[QStringLiteral(ZOOM_RESET)]); 158 | menu.addSeparator(); 159 | menu.addAction(actions[QStringLiteral(CLEAR_TERMINAL)]); 160 | menu.addAction(actions[QStringLiteral(SPLIT_HORIZONTAL)]); 161 | menu.addAction(actions[QStringLiteral(SPLIT_VERTICAL)]); 162 | // warning TODO/FIXME: disable the action when there is only one terminal 163 | menu.addAction(actions[QStringLiteral(SUB_COLLAPSE)]); 164 | menu.addSeparator(); 165 | menu.addAction(actions[QStringLiteral(TOGGLE_MENU)]); 166 | menu.addAction(actions[QStringLiteral(PREFERENCES)]); 167 | menu.exec(mapToGlobal(pos)); 168 | } 169 | 170 | void TermWidgetImpl::zoomIn() 171 | { 172 | emit QTermWidget::zoomIn(); 173 | // note: do not save zoom here due the #74 Zoom reset option resets font back to Monospace 174 | // Properties::Instance()->font = getTerminalFont(); 175 | // Properties::Instance()->saveSettings(); 176 | } 177 | 178 | void TermWidgetImpl::zoomOut() 179 | { 180 | emit QTermWidget::zoomOut(); 181 | // note: do not save zoom here due the #74 Zoom reset option resets font back to Monospace 182 | // Properties::Instance()->font = getTerminalFont(); 183 | // Properties::Instance()->saveSettings(); 184 | } 185 | 186 | void TermWidgetImpl::zoomReset() 187 | { 188 | // note: do not save zoom here due the #74 Zoom reset option resets font back to Monospace 189 | // Properties::Instance()->font = Properties::Instance()->font; 190 | setTerminalFont(Properties::Instance()->font); 191 | // Properties::Instance()->saveSettings(); 192 | } 193 | 194 | void TermWidgetImpl::activateUrl(const QUrl & url, bool fromContextMenu) { 195 | if (QApplication::keyboardModifiers() & Qt::ControlModifier || fromContextMenu) { 196 | QDesktopServices::openUrl(url); 197 | } 198 | } 199 | 200 | void TermWidgetImpl::pasteSelection() 201 | { 202 | paste(QClipboard::Selection); 203 | } 204 | 205 | void TermWidgetImpl::pasteClipboard() 206 | { 207 | paste(QClipboard::Clipboard); 208 | } 209 | 210 | void TermWidgetImpl::paste(QClipboard::Mode mode) 211 | { 212 | // Paste Clipboard by simulating keypress events 213 | QString text = QApplication::clipboard()->text(mode); 214 | if ( ! text.isEmpty() ) 215 | { 216 | text.replace(QLatin1String("\r\n"), QLatin1String("\n")); 217 | text.replace(QLatin1Char('\n'), QLatin1Char('\r')); 218 | QString trimmedTrailingNl(text); 219 | trimmedTrailingNl.replace(QRegExp(QStringLiteral("\\r+$")), QString()); 220 | bool isMultiline = trimmedTrailingNl.contains(QLatin1Char('\r')); 221 | if (!isMultiline && Properties::Instance()->trimPastedTrailingNewlines) 222 | { 223 | text = trimmedTrailingNl; 224 | } 225 | if (Properties::Instance()->confirmMultilinePaste) 226 | { 227 | if (text.contains(QLatin1Char('\r')) && Properties::Instance()->confirmMultilinePaste) 228 | { 229 | QMessageBox confirmation(this); 230 | confirmation.setWindowTitle(tr("Paste multiline text")); 231 | confirmation.setText(tr("Are you sure you want to paste this text?")); 232 | confirmation.setDetailedText(text); 233 | confirmation.setStandardButtons(QMessageBox::Yes | QMessageBox::No); 234 | // Click "Show details..." to show those by default 235 | const auto buttons = confirmation.buttons(); 236 | for( QAbstractButton * btn : buttons ) 237 | { 238 | if (confirmation.buttonRole(btn) == QMessageBox::ActionRole && btn->text() == QMessageBox::tr("Show Details...")) 239 | { 240 | btn->clicked(); 241 | break; 242 | } 243 | } 244 | confirmation.setDefaultButton(QMessageBox::Yes); 245 | confirmation.exec(); 246 | if (confirmation.standardButton(confirmation.clickedButton()) != QMessageBox::Yes) 247 | { 248 | return; 249 | } 250 | } 251 | } 252 | 253 | bracketText(text); 254 | sendText(text); 255 | } 256 | } 257 | 258 | bool TermWidget::eventFilter(QObject * /*obj*/, QEvent * ev) 259 | { 260 | if (ev->type() == QEvent::MouseButtonPress) 261 | { 262 | QMouseEvent *mev = (QMouseEvent *)ev; 263 | if ( mev->button() == Qt::MidButton ) 264 | { 265 | impl()->pasteSelection(); 266 | return true; 267 | } 268 | } 269 | return false; 270 | } 271 | 272 | TermWidget::TermWidget(TerminalConfig &cfg, QWidget * parent) 273 | : QWidget(parent), 274 | DBusAddressable(QStringLiteral("/terminals")) 275 | { 276 | 277 | #ifdef HAVE_QDBUS 278 | registerAdapter(this); 279 | #endif 280 | m_border = palette().color(QPalette::Window); 281 | m_term = new TermWidgetImpl(cfg, this); 282 | setFocusProxy(m_term); 283 | 284 | m_layout = new QVBoxLayout; 285 | setLayout(m_layout); 286 | 287 | m_layout->addWidget(m_term); 288 | const auto objs = m_term->children(); 289 | for (QObject *o : objs) 290 | { 291 | // Find TerminalDisplay 292 | if (!o->isWidgetType() || qobject_cast(o)->isHidden()) 293 | continue; 294 | o->installEventFilter(this); 295 | } 296 | 297 | 298 | propertiesChanged(); 299 | 300 | connect(m_term, &QTermWidget::finished, this, &TermWidget::finished); 301 | connect(m_term, &QTermWidget::termGetFocus, this, &TermWidget::term_termGetFocus); 302 | connect(m_term, &QTermWidget::termLostFocus, this, &TermWidget::term_termLostFocus); 303 | connect(m_term, &QTermWidget::titleChanged, this, [this] { emit termTitleChanged(m_term->title(), m_term->icon()); }); 304 | } 305 | 306 | void TermWidget::propertiesChanged() 307 | { 308 | if (Properties::Instance()->highlightCurrentTerminal) 309 | m_layout->setContentsMargins(2, 2, 2, 2); 310 | else 311 | m_layout->setContentsMargins(0, 0, 0, 0); 312 | 313 | m_term->propertiesChanged(); 314 | } 315 | 316 | void TermWidget::term_termGetFocus() 317 | { 318 | m_border = palette().color(QPalette::Highlight); 319 | emit termGetFocus(this); 320 | update(); 321 | } 322 | 323 | void TermWidget::term_termLostFocus() 324 | { 325 | m_border = palette().color(QPalette::Window); 326 | update(); 327 | } 328 | 329 | void TermWidget::paintEvent (QPaintEvent *) 330 | { 331 | if (Properties::Instance()->highlightCurrentTerminal) 332 | { 333 | QPainter p(this); 334 | QPen pen(m_border); 335 | pen.setWidth(3); 336 | pen.setBrush(m_border); 337 | p.setPen(pen); 338 | p.drawRect(0, 0, width()-1, height()-1); 339 | } 340 | } 341 | 342 | #if HAVE_QDBUS 343 | 344 | QDBusObjectPath TermWidget::splitHorizontal(const QHash &termArgs) 345 | { 346 | TermWidgetHolder *holder = findParent(this); 347 | assert(holder != NULL); 348 | TerminalConfig cfg = TerminalConfig::fromDbus(termArgs, this); 349 | return holder->split(this, Qt::Horizontal, cfg)->getDbusPath(); 350 | } 351 | 352 | QDBusObjectPath TermWidget::splitVertical(const QHash &termArgs) 353 | { 354 | TermWidgetHolder *holder = findParent(this); 355 | assert(holder != NULL); 356 | TerminalConfig cfg = TerminalConfig::fromDbus(termArgs, this); 357 | return holder->split(this, Qt::Vertical, cfg)->getDbusPath(); 358 | } 359 | 360 | QDBusObjectPath TermWidget::getTab() 361 | { 362 | return findParent(this)->getDbusPath(); 363 | } 364 | 365 | void TermWidget::closeTerminal() 366 | { 367 | TermWidgetHolder *holder = findParent(this); 368 | holder->splitCollapse(this); 369 | } 370 | 371 | void TermWidget::sendText(const QString text) 372 | { 373 | if (impl()) 374 | { 375 | impl()->sendText(text); 376 | } 377 | } 378 | 379 | #endif 380 | -------------------------------------------------------------------------------- /src/termwidget.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | * Copyright (C) 2010 by Petr Vanek * 3 | * petr@scribus.info * 4 | * * 5 | * This program is free software; you can redistribute it and/or modify * 6 | * it under the terms of the GNU General Public License as published by * 7 | * the Free Software Foundation; either version 2 of the License, or * 8 | * (at your option) any later version. * 9 | * * 10 | * This program is distributed in the hope that it will be useful, * 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 13 | * GNU General Public License for more details. * 14 | * * 15 | * You should have received a copy of the GNU General Public License * 16 | * along with this program. If not, see . * 17 | ***************************************************************************/ 18 | 19 | #ifndef TERMWIDGET_H 20 | #define TERMWIDGET_H 21 | 22 | #include 23 | #include "terminalconfig.h" 24 | 25 | #include 26 | #include 27 | #include "dbusaddressable.h" 28 | 29 | class TermWidgetImpl : public QTermWidget 30 | { 31 | Q_OBJECT 32 | 33 | // QMap< QString, QAction * > actionMap; 34 | 35 | public: 36 | 37 | TermWidgetImpl(TerminalConfig &cfg, QWidget * parent=0); 38 | void propertiesChanged(); 39 | void paste(QClipboard::Mode mode); 40 | 41 | signals: 42 | void renameSession(); 43 | void removeCurrentSession(); 44 | 45 | public slots: 46 | void zoomIn(); 47 | void zoomOut(); 48 | void zoomReset(); 49 | void pasteSelection(); 50 | void pasteClipboard(); 51 | 52 | private slots: 53 | void customContextMenuCall(const QPoint & pos); 54 | void activateUrl(const QUrl& url, bool fromContextMenu); 55 | }; 56 | 57 | 58 | class TermWidget : public QWidget, public DBusAddressable 59 | { 60 | Q_OBJECT 61 | 62 | TermWidgetImpl * m_term; 63 | QVBoxLayout * m_layout; 64 | QColor m_border; 65 | 66 | public: 67 | TermWidget(TerminalConfig &cfg, QWidget * parent=0); 68 | 69 | void propertiesChanged(); 70 | QStringList availableKeyBindings() { return m_term->availableKeyBindings(); } 71 | 72 | TermWidgetImpl * impl() { return m_term; } 73 | 74 | #ifdef HAVE_QDBUS 75 | QDBusObjectPath splitHorizontal(const QHash &termArgs); 76 | QDBusObjectPath splitVertical(const QHash &termArgs); 77 | QDBusObjectPath getTab(); 78 | void sendText(const QString text); 79 | void closeTerminal(); 80 | #endif 81 | 82 | signals: 83 | void finished(); 84 | void renameSession(); 85 | void removeCurrentSession(); 86 | void splitHorizontal(TermWidget * self); 87 | void splitVertical(TermWidget * self); 88 | void splitCollapse(TermWidget * self); 89 | void termGetFocus(TermWidget * self); 90 | void termTitleChanged(QString titleText, QString icon); 91 | 92 | public slots: 93 | 94 | protected: 95 | void paintEvent (QPaintEvent * event); 96 | bool eventFilter(QObject * obj, QEvent * evt) override; 97 | 98 | private slots: 99 | void term_termGetFocus(); 100 | void term_termLostFocus(); 101 | }; 102 | 103 | #endif 104 | 105 | -------------------------------------------------------------------------------- /src/termwidgetholder.cpp: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | * Copyright (C) 2010 by Petr Vanek * 3 | * petr@scribus.info * 4 | * * 5 | * This program is free software; you can redistribute it and/or modify * 6 | * it under the terms of the GNU General Public License as published by * 7 | * the Free Software Foundation; either version 2 of the License, or * 8 | * (at your option) any later version. * 9 | * * 10 | * This program is distributed in the hope that it will be useful, * 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 13 | * GNU General Public License for more details. * 14 | * * 15 | * You should have received a copy of the GNU General Public License * 16 | * along with this program. If not, see . * 17 | ***************************************************************************/ 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | #ifdef HAVE_QDBUS 24 | #include 25 | #include "tabadaptor.h" 26 | #endif 27 | 28 | #include "qterminalapp.h" 29 | #include "mainwindow.h" 30 | #include "termwidgetholder.h" 31 | #include "termwidget.h" 32 | #include "properties.h" 33 | #include 34 | #include 35 | #include 36 | 37 | 38 | TermWidgetHolder::TermWidgetHolder(TerminalConfig &config, QWidget * parent) 39 | : QWidget(parent) 40 | #ifdef HAVE_QDBUS 41 | , DBusAddressable(QStringLiteral("/tabs")) 42 | #endif 43 | { 44 | #ifdef HAVE_QDBUS 45 | new TabAdaptor(this); 46 | QDBusConnection::sessionBus().registerObject(getDbusPathString(), this); 47 | #endif 48 | setFocusPolicy(Qt::NoFocus); 49 | QGridLayout * lay = new QGridLayout(this); 50 | lay->setSpacing(0); 51 | lay->setContentsMargins(0, 0, 0, 0); 52 | 53 | QSplitter *s = new QSplitter(this); 54 | s->setFocusPolicy(Qt::NoFocus); 55 | TermWidget *w = newTerm(config); 56 | s->addWidget(w); 57 | lay->addWidget(s); 58 | m_currentTerm = w; 59 | 60 | setLayout(lay); 61 | } 62 | 63 | TermWidgetHolder::~TermWidgetHolder() 64 | { 65 | } 66 | 67 | void TermWidgetHolder::setInitialFocus() 68 | { 69 | QList list = findChildren(); 70 | TermWidget * w = list.count() == 0 ? 0 : list.at(0); 71 | if (w) 72 | w->setFocus(Qt::OtherFocusReason); 73 | } 74 | 75 | void TermWidgetHolder::loadSession() 76 | { 77 | bool ok; 78 | QString name = QInputDialog::getItem(this, tr("Load Session"), 79 | tr("List of saved sessions:"), 80 | Properties::Instance()->sessions.keys(), 81 | 0, false, &ok); 82 | if (!ok || name.isEmpty()) 83 | return; 84 | #if 0 85 | foreach (QWidget * w, findChildren()) 86 | { 87 | if (w) 88 | { 89 | delete w; 90 | w = 0; 91 | } 92 | } 93 | 94 | qDebug() << "load" << name << QString(Properties::Instance()->sessions[name]); 95 | QStringList splitters = QString(Properties::Instance()->sessions[name]).split("|", QString::SkipEmptyParts); 96 | foreach (QString splitter, splitters) 97 | { 98 | QStringList components = splitter.split(","); 99 | qDebug() << "comp" << components; 100 | // orientation 101 | Qt::Orientation orientation; 102 | if (components.size() > 0) 103 | orientation = components.takeAt(0).toInt(); 104 | // sizes 105 | QList sizes; 106 | QList widgets; 107 | foreach (QString s, components) 108 | { 109 | sizes << s.toInt(); 110 | widgets << newTerm(); 111 | } 112 | // new terms 113 | } 114 | #endif 115 | } 116 | 117 | void TermWidgetHolder::saveSession(const QString & name) 118 | { 119 | Session dump; 120 | QString num(QLatin1String("%1")); 121 | const auto ws = findChildren(); 122 | for(QSplitter *w : ws) 123 | { 124 | dump += QLatin1Char('|') + num.arg(w->orientation()); 125 | const auto sizes = w->sizes(); 126 | for (const int i : sizes) 127 | dump += QLatin1Char(',') + num.arg(i); 128 | } 129 | Properties::Instance()->sessions[name] = dump; 130 | qDebug() << "dump" << dump; 131 | } 132 | 133 | TermWidget* TermWidgetHolder::currentTerminal() 134 | { 135 | return m_currentTerm; 136 | } 137 | 138 | void TermWidgetHolder::setWDir(const QString & wdir) 139 | { 140 | m_wdir = wdir; 141 | } 142 | 143 | typedef struct { 144 | QPoint topLeft; 145 | QPoint middle; 146 | QPoint bottomRight; 147 | } NavigationData; 148 | 149 | static void transpose(QPoint *point) { 150 | int x = point->x(); 151 | point->setX(point->y()); 152 | point->setY(x); 153 | } 154 | 155 | static void transposeTransform(NavigationData *point) { 156 | transpose(&point->topLeft); 157 | transpose(&point->middle); 158 | transpose(&point->bottomRight); 159 | } 160 | 161 | static void flipTransform(NavigationData *point) { 162 | QPoint oldTopLeft = point->topLeft; 163 | point->topLeft = -(point->bottomRight); 164 | point->bottomRight = -(oldTopLeft); 165 | point->middle = -(point->middle); 166 | } 167 | 168 | static void normalizeToRight(NavigationData *point, NavigationDirection dir) { 169 | switch (dir) { 170 | case Left: 171 | flipTransform(point); 172 | break; 173 | case Right: 174 | // No-op 175 | break; 176 | case Top: 177 | flipTransform(point); 178 | transposeTransform(point); 179 | break; 180 | case Bottom: 181 | transposeTransform(point); 182 | break; 183 | default: 184 | assert("Invalid navigation"); 185 | return; 186 | } 187 | } 188 | 189 | static NavigationData getNormalizedDimensions(QWidget *w, NavigationDirection dir) { 190 | NavigationData nd; 191 | nd.topLeft = w->mapTo(w->window(), QPoint(0, 0)); 192 | nd.middle = w->mapTo(w->window(), QPoint(w->width() / 2, w->height() / 2)); 193 | nd.bottomRight = w->mapTo(w->window(), QPoint(w->width(), w->height())); 194 | normalizeToRight(&nd, dir); 195 | return nd; 196 | } 197 | 198 | 199 | void TermWidgetHolder::directionalNavigation(NavigationDirection dir) { 200 | // Find an active widget 201 | QList l = findChildren(); 202 | int ix = -1; 203 | for (TermWidget * w : qAsConst(l)) 204 | { 205 | ++ix; 206 | if (w->impl()->hasFocus()) 207 | { 208 | break; 209 | } 210 | } 211 | if (ix > l.count()) 212 | { 213 | l.at(0)->impl()->setFocus(Qt::OtherFocusReason); 214 | return; 215 | } 216 | 217 | // Found an active widget 218 | TermWidget *w = l.at(ix); 219 | NavigationData from = getNormalizedDimensions(w, dir); 220 | 221 | // Search parent that contains point of interest (right edge middlepoint) 222 | QPoint poi = QPoint(from.bottomRight.x(), from.middle.y()); 223 | 224 | // Perform a search for a TermWidget, where x() is strictly higher than 225 | // poi.x(), y() is strictly less than poi.y(), and prioritizing, in order, 226 | // lower x(), and lower distance between poi.y() and corners. 227 | 228 | // Only "Right navigation" implementation is necessary -- other cases 229 | // are normalized to this one. 230 | 231 | l = findChildren(); 232 | int lowestX = INT_MAX; 233 | int lowestMidpointDistance = INT_MAX; 234 | TermWidget *fittest = NULL; 235 | for (TermWidget * w : qAsConst(l)) 236 | { 237 | NavigationData contenderDims = getNormalizedDimensions(w, dir); 238 | int midpointDistance = std::min( 239 | abs(poi.y() - contenderDims.topLeft.y()), 240 | abs(poi.y() - contenderDims.bottomRight.y()) 241 | ); 242 | if (contenderDims.topLeft.x() > poi.x()) 243 | { 244 | if (contenderDims.topLeft.x() > lowestX) 245 | continue; 246 | if (midpointDistance > lowestMidpointDistance) 247 | continue; 248 | lowestX = contenderDims.topLeft.x(); 249 | lowestMidpointDistance = midpointDistance; 250 | fittest = w; 251 | } 252 | } 253 | if (fittest != NULL) { 254 | fittest->impl()->setFocus(Qt::OtherFocusReason); 255 | } 256 | } 257 | 258 | void TermWidgetHolder::clearActiveTerminal() 259 | { 260 | currentTerminal()->impl()->clear(); 261 | } 262 | 263 | void TermWidgetHolder::propertiesChanged() 264 | { 265 | const auto ws = findChildren(); 266 | for(TermWidget *w : ws) 267 | w->propertiesChanged(); 268 | } 269 | 270 | void TermWidgetHolder::splitHorizontal(TermWidget * term) 271 | { 272 | TerminalConfig defaultConfig; 273 | split(term, Qt::Vertical, defaultConfig); 274 | } 275 | 276 | void TermWidgetHolder::splitVertical(TermWidget * term) 277 | { 278 | TerminalConfig defaultConfig; 279 | split(term, Qt::Horizontal, defaultConfig); 280 | } 281 | 282 | void TermWidgetHolder::splitCollapse(TermWidget * term) 283 | { 284 | QSplitter * parent = qobject_cast(term->parent()); 285 | assert(parent); 286 | term->setParent(0); 287 | delete term; 288 | 289 | QWidget *nextFocus = Q_NULLPTR; 290 | 291 | // Collapse splitters containing a single element, excluding the top one. 292 | if (parent->count() == 1) 293 | { 294 | QSplitter *uselessSplitterParent = qobject_cast(parent->parent()); 295 | if (uselessSplitterParent != Q_NULLPTR) { 296 | int idx = uselessSplitterParent->indexOf(parent); 297 | assert(idx != -1); 298 | QWidget *singleHeir = parent->widget(0); 299 | uselessSplitterParent->insertWidget(idx, singleHeir); 300 | if (qobject_cast(singleHeir)) 301 | { 302 | nextFocus = singleHeir; 303 | } 304 | else 305 | { 306 | nextFocus = singleHeir->findChild(); 307 | } 308 | parent->setParent(0); 309 | delete parent; 310 | // Make sure there's no access to the removed parent 311 | parent = uselessSplitterParent; 312 | } 313 | } 314 | 315 | if (parent->count() > 0) 316 | { 317 | if (nextFocus) 318 | { 319 | nextFocus->setFocus(Qt::OtherFocusReason); 320 | } 321 | else 322 | { 323 | parent->widget(0)->setFocus(Qt::OtherFocusReason); 324 | } 325 | parent->update(); 326 | } 327 | else 328 | emit finished(); 329 | } 330 | 331 | TermWidget * TermWidgetHolder::split(TermWidget *term, Qt::Orientation orientation, TerminalConfig cfg) 332 | { 333 | QSplitter *parent = qobject_cast(term->parent()); 334 | assert(parent); 335 | 336 | int ix = parent->indexOf(term); 337 | QList parentSizes = parent->sizes(); 338 | 339 | QList sizes; 340 | sizes << 1 << 1; 341 | 342 | QSplitter *s = new QSplitter(orientation, this); 343 | s->setFocusPolicy(Qt::NoFocus); 344 | s->insertWidget(0, term); 345 | 346 | cfg.provideCurrentDirectory(term->impl()->workingDirectory()); 347 | 348 | TermWidget * w = newTerm(cfg); 349 | s->insertWidget(1, w); 350 | s->setSizes(sizes); 351 | 352 | parent->insertWidget(ix, s); 353 | parent->setSizes(parentSizes); 354 | 355 | w->setFocus(Qt::OtherFocusReason); 356 | return w; 357 | } 358 | 359 | TermWidget *TermWidgetHolder::newTerm(TerminalConfig &cfg) 360 | { 361 | TermWidget *w = new TermWidget(cfg, this); 362 | // proxy signals 363 | connect(w, &TermWidget::renameSession, this, &TermWidgetHolder::renameSession); 364 | connect(w, &TermWidget::removeCurrentSession, this, &TermWidgetHolder::lastTerminalClosed); 365 | connect(w, &TermWidget::finished, this, &TermWidgetHolder::handle_finished); 366 | // consume signals 367 | 368 | connect(w, static_cast(&TermWidget::splitHorizontal), 369 | this, &TermWidgetHolder::splitHorizontal); 370 | connect(w, static_cast(&TermWidget::splitVertical), 371 | this, &TermWidgetHolder::splitVertical); 372 | connect(w, &TermWidget::splitCollapse, this, &TermWidgetHolder::splitCollapse); 373 | connect(w, &TermWidget::termGetFocus, this, &TermWidgetHolder::setCurrentTerminal); 374 | connect(w, &TermWidget::termTitleChanged, this, &TermWidgetHolder::onTermTitleChanged); 375 | 376 | return w; 377 | } 378 | 379 | void TermWidgetHolder::setCurrentTerminal(TermWidget* term) 380 | { 381 | TermWidget * old_current = m_currentTerm; 382 | m_currentTerm = term; 383 | if (old_current != m_currentTerm) 384 | { 385 | if (m_currentTerm->impl()->isTitleChanged()) 386 | { 387 | emit termTitleChanged(m_currentTerm->impl()->title(), m_currentTerm->impl()->icon()); 388 | } else 389 | { 390 | emit termTitleChanged(windowTitle(), QString{}); 391 | } 392 | } 393 | } 394 | 395 | void TermWidgetHolder::handle_finished() 396 | { 397 | TermWidget * w = qobject_cast(sender()); 398 | if (!w) 399 | { 400 | qDebug() << "TermWidgetHolder::handle_finished: Unknown object to handle" << w; 401 | assert(0); 402 | } 403 | splitCollapse(w); 404 | } 405 | 406 | void TermWidgetHolder::onTermTitleChanged(QString title, QString icon) const 407 | { 408 | TermWidget * term = qobject_cast(sender()); 409 | if (m_currentTerm == term) 410 | emit termTitleChanged(title, icon); 411 | } 412 | 413 | #ifdef HAVE_QDBUS 414 | 415 | QDBusObjectPath TermWidgetHolder::getActiveTerminal() 416 | { 417 | if (m_currentTerm != NULL) 418 | { 419 | return m_currentTerm->getDbusPath(); 420 | } 421 | return QDBusObjectPath(); 422 | } 423 | 424 | QList TermWidgetHolder::getTerminals() 425 | { 426 | QList terminals; 427 | const auto ws = findChildren(); 428 | for (TermWidget* w : ws) 429 | { 430 | terminals.push_back(w->getDbusPath()); 431 | } 432 | return terminals; 433 | } 434 | 435 | QDBusObjectPath TermWidgetHolder::getWindow() 436 | { 437 | return findParent(this)->getDbusPath(); 438 | } 439 | 440 | void TermWidgetHolder::closeTab() 441 | { 442 | QTabWidget *parent = findParent(this); 443 | int idx = parent->indexOf(this); 444 | assert(idx != -1); 445 | parent->tabCloseRequested(idx); 446 | } 447 | 448 | #endif 449 | 450 | -------------------------------------------------------------------------------- /src/termwidgetholder.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | * Copyright (C) 2010 by Petr Vanek * 3 | * petr@scribus.info * 4 | * * 5 | * This program is free software; you can redistribute it and/or modify * 6 | * it under the terms of the GNU General Public License as published by * 7 | * the Free Software Foundation; either version 2 of the License, or * 8 | * (at your option) any later version. * 9 | * * 10 | * This program is distributed in the hope that it will be useful, * 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 13 | * GNU General Public License for more details. * 14 | * * 15 | * You should have received a copy of the GNU General Public License * 16 | * along with this program. If not, see . * 17 | ***************************************************************************/ 18 | 19 | #ifndef TERMWIDGETHOLDER_H 20 | #define TERMWIDGETHOLDER_H 21 | 22 | #include 23 | #include "termwidget.h" 24 | #include "terminalconfig.h" 25 | #include "dbusaddressable.h" 26 | class QSplitter; 27 | 28 | 29 | 30 | typedef enum NavigationDirection { 31 | Left, 32 | Right, 33 | Top, 34 | Bottom 35 | } NavigationDirection; 36 | 37 | 38 | /*! \brief TermWidget group/session manager. 39 | 40 | This widget (one per TabWidget tab) is a "proxy" widget beetween TabWidget and 41 | unspecified count of TermWidgets. Basically it should look like a single TermWidget 42 | for TabWidget - with its signals and slots. 43 | 44 | Splitting and collapsing of TermWidgets is done here. 45 | */ 46 | class TermWidgetHolder : public QWidget 47 | #ifdef HAVE_QDBUS 48 | , public DBusAddressable 49 | #endif 50 | { 51 | Q_OBJECT 52 | 53 | public: 54 | TermWidgetHolder(TerminalConfig &cfg, QWidget * parent=0); 55 | ~TermWidgetHolder(); 56 | 57 | void propertiesChanged(); 58 | void setInitialFocus(); 59 | 60 | void loadSession(); 61 | void saveSession(const QString & name); 62 | void zoomIn(uint step); 63 | void zoomOut(uint step); 64 | 65 | TermWidget* currentTerminal(); 66 | TermWidget* split(TermWidget * term, Qt::Orientation orientation, TerminalConfig cfg); 67 | 68 | #ifdef HAVE_QDBUS 69 | QDBusObjectPath getActiveTerminal(); 70 | QList getTerminals(); 71 | QDBusObjectPath getWindow(); 72 | void closeTab(); 73 | #endif 74 | 75 | 76 | public slots: 77 | void splitHorizontal(TermWidget * term); 78 | void splitVertical(TermWidget * term); 79 | void splitCollapse(TermWidget * term); 80 | void setWDir(const QString & wdir); 81 | void directionalNavigation(NavigationDirection dir); 82 | void clearActiveTerminal(); 83 | void onTermTitleChanged(QString title, QString icon) const; 84 | 85 | signals: 86 | void finished(); 87 | void lastTerminalClosed(); 88 | void renameSession(); 89 | void termTitleChanged(QString title, QString icon) const; 90 | 91 | private: 92 | QString m_wdir; 93 | QString m_shell; 94 | TermWidget * m_currentTerm; 95 | 96 | void split(TermWidget * term, Qt::Orientation orientation); 97 | TermWidget * newTerm(TerminalConfig &cfg); 98 | 99 | private slots: 100 | void setCurrentTerminal(TermWidget* term); 101 | void handle_finished(); 102 | }; 103 | 104 | #endif 105 | 106 | -------------------------------------------------------------------------------- /src/third-party/qxtglobal.h: -------------------------------------------------------------------------------- 1 | 2 | /**************************************************************************** 3 | ** Copyright (c) 2006 - 2011, the LibQxt project. 4 | ** See the Qxt AUTHORS file for a list of authors and copyright holders. 5 | ** All rights reserved. 6 | ** 7 | ** Redistribution and use in source and binary forms, with or without 8 | ** modification, are permitted provided that the following conditions are met: 9 | ** * Redistributions of source code must retain the above copyright 10 | ** notice, this list of conditions and the following disclaimer. 11 | ** * Redistributions in binary form must reproduce the above copyright 12 | ** notice, this list of conditions and the following disclaimer in the 13 | ** documentation and/or other materials provided with the distribution. 14 | ** * Neither the name of the LibQxt project nor the 15 | ** names of its contributors may be used to endorse or promote products 16 | ** derived from this software without specific prior written permission. 17 | ** 18 | ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 19 | ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 | ** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | ** DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 22 | ** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 | ** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 | ** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 25 | ** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 27 | ** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | ** 29 | ** 30 | *****************************************************************************/ 31 | 32 | #ifndef QXTGLOBAL_H 33 | #define QXTGLOBAL_H 34 | 35 | #include 36 | 37 | #define QXT_VERSION 0x000700 38 | #define QXT_VERSION_STR "0.7.0" 39 | 40 | //--------------------------global macros------------------------------ 41 | 42 | #ifndef QXT_NO_MACROS 43 | 44 | #ifndef _countof 45 | #define _countof(x) (sizeof(x)/sizeof(*x)) 46 | #endif 47 | 48 | #endif // QXT_NO_MACROS 49 | 50 | //--------------------------export macros------------------------------ 51 | 52 | #define QXT_DLLEXPORT DO_NOT_USE_THIS_ANYMORE 53 | 54 | #if !defined(QXT_STATIC) && !defined(QXT_DOXYGEN_RUN) 55 | # if defined(BUILD_QXT_CORE) 56 | # define QXT_CORE_EXPORT Q_DECL_EXPORT 57 | # else 58 | # define QXT_CORE_EXPORT Q_DECL_IMPORT 59 | # endif 60 | #else 61 | # define QXT_CORE_EXPORT 62 | #endif // BUILD_QXT_CORE 63 | 64 | #if !defined(QXT_STATIC) && !defined(QXT_DOXYGEN_RUN) 65 | # if defined(BUILD_QXT_GUI) 66 | # define QXT_GUI_EXPORT Q_DECL_EXPORT 67 | # else 68 | # define QXT_GUI_EXPORT Q_DECL_IMPORT 69 | # endif 70 | #else 71 | # define QXT_GUI_EXPORT 72 | #endif // BUILD_QXT_GUI 73 | 74 | #if !defined(QXT_STATIC) && !defined(QXT_DOXYGEN_RUN) 75 | # if defined(BUILD_QXT_NETWORK) 76 | # define QXT_NETWORK_EXPORT Q_DECL_EXPORT 77 | # else 78 | # define QXT_NETWORK_EXPORT Q_DECL_IMPORT 79 | # endif 80 | #else 81 | # define QXT_NETWORK_EXPORT 82 | #endif // BUILD_QXT_NETWORK 83 | 84 | #if !defined(QXT_STATIC) && !defined(QXT_DOXYGEN_RUN) 85 | # if defined(BUILD_QXT_SQL) 86 | # define QXT_SQL_EXPORT Q_DECL_EXPORT 87 | # else 88 | # define QXT_SQL_EXPORT Q_DECL_IMPORT 89 | # endif 90 | #else 91 | # define QXT_SQL_EXPORT 92 | #endif // BUILD_QXT_SQL 93 | 94 | #if !defined(QXT_STATIC) && !defined(QXT_DOXYGEN_RUN) 95 | # if defined(BUILD_QXT_WEB) 96 | # define QXT_WEB_EXPORT Q_DECL_EXPORT 97 | # else 98 | # define QXT_WEB_EXPORT Q_DECL_IMPORT 99 | # endif 100 | #else 101 | # define QXT_WEB_EXPORT 102 | #endif // BUILD_QXT_WEB 103 | 104 | #if !defined(QXT_STATIC) && !defined(QXT_DOXYGEN_RUN) 105 | # if defined(BUILD_QXT_BERKELEY) 106 | # define QXT_BERKELEY_EXPORT Q_DECL_EXPORT 107 | # else 108 | # define QXT_BERKELEY_EXPORT Q_DECL_IMPORT 109 | # endif 110 | #else 111 | # define QXT_BERKELEY_EXPORT 112 | #endif // BUILD_QXT_BERKELEY 113 | 114 | #if !defined(QXT_STATIC) && !defined(QXT_DOXYGEN_RUN) 115 | # if defined(BUILD_QXT_ZEROCONF) 116 | # define QXT_ZEROCONF_EXPORT Q_DECL_EXPORT 117 | # else 118 | # define QXT_ZEROCONF_EXPORT Q_DECL_IMPORT 119 | # endif 120 | #else 121 | # define QXT_ZEROCONF_EXPORT 122 | #endif // QXT_ZEROCONF_EXPORT 123 | 124 | #if defined(BUILD_QXT_CORE) || defined(BUILD_QXT_GUI) || defined(BUILD_QXT_SQL) || defined(BUILD_QXT_NETWORK) || defined(BUILD_QXT_WEB) || defined(BUILD_QXT_BERKELEY) || defined(BUILD_QXT_ZEROCONF) 125 | # define BUILD_QXT 126 | #endif 127 | 128 | QXT_CORE_EXPORT const char* qxtVersion(); 129 | 130 | #ifndef QT_BEGIN_NAMESPACE 131 | #define QT_BEGIN_NAMESPACE 132 | #endif 133 | 134 | #ifndef QT_END_NAMESPACE 135 | #define QT_END_NAMESPACE 136 | #endif 137 | 138 | #ifndef QT_FORWARD_DECLARE_CLASS 139 | #define QT_FORWARD_DECLARE_CLASS(Class) class Class; 140 | #endif 141 | 142 | /**************************************************************************** 143 | ** This file is derived from code bearing the following notice: 144 | ** The sole author of this file, Adam Higerd, has explicitly disclaimed all 145 | ** copyright interest and protection for the content within. This file has 146 | ** been placed in the public domain according to United States copyright 147 | ** statute and case law. In jurisdictions where this public domain dedication 148 | ** is not legally recognized, anyone who receives a copy of this file is 149 | ** permitted to use, modify, duplicate, and redistribute this file, in whole 150 | ** or in part, with no restrictions or conditions. In these jurisdictions, 151 | ** this file shall be copyright (C) 2006-2008 by Adam Higerd. 152 | ****************************************************************************/ 153 | 154 | #define QXT_DECLARE_PRIVATE(PUB) friend class PUB##Private; QxtPrivateInterface qxt_d; 155 | #define QXT_DECLARE_PUBLIC(PUB) friend class PUB; 156 | #define QXT_INIT_PRIVATE(PUB) qxt_d.setPublic(this); 157 | #define QXT_D(PUB) PUB##Private& d = qxt_d() 158 | #define QXT_P(PUB) PUB& p = qxt_p() 159 | 160 | template 161 | class QxtPrivate 162 | { 163 | public: 164 | virtual ~QxtPrivate() 165 | {} 166 | inline void QXT_setPublic(PUB* pub) 167 | { 168 | qxt_p_ptr = pub; 169 | } 170 | 171 | protected: 172 | inline PUB& qxt_p() 173 | { 174 | return *qxt_p_ptr; 175 | } 176 | inline const PUB& qxt_p() const 177 | { 178 | return *qxt_p_ptr; 179 | } 180 | inline PUB* qxt_ptr() 181 | { 182 | return qxt_p_ptr; 183 | } 184 | inline const PUB* qxt_ptr() const 185 | { 186 | return qxt_p_ptr; 187 | } 188 | 189 | private: 190 | PUB* qxt_p_ptr; 191 | }; 192 | 193 | template 194 | class QxtPrivateInterface 195 | { 196 | friend class QxtPrivate; 197 | public: 198 | QxtPrivateInterface() 199 | { 200 | pvt = new PVT; 201 | } 202 | ~QxtPrivateInterface() 203 | { 204 | delete pvt; 205 | } 206 | 207 | inline void setPublic(PUB* pub) 208 | { 209 | pvt->QXT_setPublic(pub); 210 | } 211 | inline PVT& operator()() 212 | { 213 | return *static_cast(pvt); 214 | } 215 | inline const PVT& operator()() const 216 | { 217 | return *static_cast(pvt); 218 | } 219 | inline PVT * operator->() 220 | { 221 | return static_cast(pvt); 222 | } 223 | inline const PVT * operator->() const 224 | { 225 | return static_cast(pvt); 226 | } 227 | private: 228 | QxtPrivateInterface(const QxtPrivateInterface&) { } 229 | QxtPrivateInterface& operator=(const QxtPrivateInterface&) { } 230 | QxtPrivate* pvt; 231 | }; 232 | 233 | #endif // QXT_GLOBAL 234 | -------------------------------------------------------------------------------- /src/third-party/qxtglobalshortcut.cpp: -------------------------------------------------------------------------------- 1 | #include "qxtglobalshortcut.h" 2 | /**************************************************************************** 3 | ** Copyright (c) 2006 - 2011, the LibQxt project. 4 | ** See the Qxt AUTHORS file for a list of authors and copyright holders. 5 | ** All rights reserved. 6 | ** 7 | ** Redistribution and use in source and binary forms, with or without 8 | ** modification, are permitted provided that the following conditions are met: 9 | ** * Redistributions of source code must retain the above copyright 10 | ** notice, this list of conditions and the following disclaimer. 11 | ** * Redistributions in binary form must reproduce the above copyright 12 | ** notice, this list of conditions and the following disclaimer in the 13 | ** documentation and/or other materials provided with the distribution. 14 | ** * Neither the name of the LibQxt project nor the 15 | ** names of its contributors may be used to endorse or promote products 16 | ** derived from this software without specific prior written permission. 17 | ** 18 | ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 19 | ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 | ** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | ** DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 22 | ** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 | ** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 | ** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 25 | ** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 27 | ** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | ** 29 | ** 30 | *****************************************************************************/ 31 | 32 | #include "qxtglobalshortcut_p.h" 33 | #include 34 | #include 35 | 36 | #ifndef Q_OS_MAC 37 | int QxtGlobalShortcutPrivate::ref = 0; 38 | #endif 39 | QHash, QxtGlobalShortcut*> QxtGlobalShortcutPrivate::shortcuts; 40 | 41 | QxtGlobalShortcutPrivate::QxtGlobalShortcutPrivate() : enabled(true), key(Qt::Key(0)), mods(Qt::NoModifier) 42 | { 43 | #ifndef Q_OS_MAC 44 | if (ref == 0) { 45 | QAbstractEventDispatcher::instance()->installNativeEventFilter(this); 46 | } 47 | ++ref; 48 | #endif 49 | } 50 | 51 | QxtGlobalShortcutPrivate::~QxtGlobalShortcutPrivate() 52 | { 53 | #ifndef Q_OS_MAC 54 | --ref; 55 | if (ref == 0) { 56 | QAbstractEventDispatcher *ed = QAbstractEventDispatcher::instance(); 57 | if (ed != 0) { 58 | ed->removeNativeEventFilter(this); 59 | } 60 | } 61 | #endif 62 | } 63 | 64 | bool QxtGlobalShortcutPrivate::setShortcut(const QKeySequence& shortcut) 65 | { 66 | Qt::KeyboardModifiers allMods = Qt::ShiftModifier | Qt::ControlModifier | Qt::AltModifier | Qt::MetaModifier; 67 | key = shortcut.isEmpty() ? Qt::Key(0) : Qt::Key((shortcut[0] ^ allMods) & shortcut[0]); 68 | mods = shortcut.isEmpty() ? Qt::KeyboardModifiers(0) : Qt::KeyboardModifiers(shortcut[0] & allMods); 69 | const quint32 nativeKey = nativeKeycode(key); 70 | const quint32 nativeMods = nativeModifiers(mods); 71 | const bool res = registerShortcut(nativeKey, nativeMods); 72 | if (res) 73 | shortcuts.insert(qMakePair(nativeKey, nativeMods), &qxt_p()); 74 | else 75 | qWarning() << "QxtGlobalShortcut failed to register:" << QKeySequence(key + mods).toString(); 76 | return res; 77 | } 78 | 79 | bool QxtGlobalShortcutPrivate::unsetShortcut() 80 | { 81 | bool res = false; 82 | const quint32 nativeKey = nativeKeycode(key); 83 | const quint32 nativeMods = nativeModifiers(mods); 84 | if (shortcuts.value(qMakePair(nativeKey, nativeMods)) == &qxt_p()) 85 | res = unregisterShortcut(nativeKey, nativeMods); 86 | if (res) 87 | shortcuts.remove(qMakePair(nativeKey, nativeMods)); 88 | else 89 | qWarning() << "QxtGlobalShortcut failed to unregister:" << QKeySequence(key + mods).toString(); 90 | key = Qt::Key(0); 91 | mods = Qt::KeyboardModifiers(0); 92 | return res; 93 | } 94 | 95 | void QxtGlobalShortcutPrivate::activateShortcut(quint32 nativeKey, quint32 nativeMods) 96 | { 97 | QxtGlobalShortcut* shortcut = shortcuts.value(qMakePair(nativeKey, nativeMods)); 98 | if (shortcut && shortcut->isEnabled()) 99 | emit shortcut->activated(); 100 | } 101 | 102 | /*! 103 | \class QxtGlobalShortcut 104 | \inmodule QxtWidgets 105 | \brief The QxtGlobalShortcut class provides a global shortcut aka "hotkey". 106 | 107 | A global shortcut triggers even if the application is not active. This 108 | makes it easy to implement applications that react to certain shortcuts 109 | still if some other application is active or if the application is for 110 | example minimized to the system tray. 111 | 112 | Example usage: 113 | \code 114 | QxtGlobalShortcut* shortcut = new QxtGlobalShortcut(window); 115 | connect(shortcut, SIGNAL(activated()), window, SLOT(toggleVisibility())); 116 | shortcut->setShortcut(QKeySequence("Ctrl+Shift+F12")); 117 | \endcode 118 | 119 | \bold {Note:} Since Qxt 0.6 QxtGlobalShortcut no more requires QxtApplication. 120 | */ 121 | 122 | /*! 123 | \fn QxtGlobalShortcut::activated() 124 | 125 | This signal is emitted when the user types the shortcut's key sequence. 126 | 127 | \sa shortcut 128 | */ 129 | 130 | /*! 131 | Constructs a new QxtGlobalShortcut with \a parent. 132 | */ 133 | QxtGlobalShortcut::QxtGlobalShortcut(QObject* parent) 134 | : QObject(parent) 135 | { 136 | QXT_INIT_PRIVATE(QxtGlobalShortcut); 137 | } 138 | 139 | /*! 140 | Constructs a new QxtGlobalShortcut with \a shortcut and \a parent. 141 | */ 142 | QxtGlobalShortcut::QxtGlobalShortcut(const QKeySequence& shortcut, QObject* parent) 143 | : QObject(parent) 144 | { 145 | QXT_INIT_PRIVATE(QxtGlobalShortcut); 146 | setShortcut(shortcut); 147 | } 148 | 149 | /*! 150 | Destructs the QxtGlobalShortcut. 151 | */ 152 | QxtGlobalShortcut::~QxtGlobalShortcut() 153 | { 154 | if (qxt_d().key != 0) 155 | qxt_d().unsetShortcut(); 156 | } 157 | 158 | /*! 159 | \property QxtGlobalShortcut::shortcut 160 | \brief the shortcut key sequence 161 | 162 | \bold {Note:} Notice that corresponding key press and release events are not 163 | delivered for registered global shortcuts even if they are disabled. 164 | Also, comma separated key sequences are not supported. 165 | Only the first part is used: 166 | 167 | \code 168 | qxtShortcut->setShortcut(QKeySequence("Ctrl+Alt+A,Ctrl+Alt+B")); 169 | Q_ASSERT(qxtShortcut->shortcut() == QKeySequence("Ctrl+Alt+A")); 170 | \endcode 171 | */ 172 | QKeySequence QxtGlobalShortcut::shortcut() const 173 | { 174 | return QKeySequence(qxt_d().key | qxt_d().mods); 175 | } 176 | 177 | bool QxtGlobalShortcut::setShortcut(const QKeySequence& shortcut) 178 | { 179 | if (qxt_d().key != 0) 180 | qxt_d().unsetShortcut(); 181 | return qxt_d().setShortcut(shortcut); 182 | } 183 | 184 | /*! 185 | \property QxtGlobalShortcut::enabled 186 | \brief whether the shortcut is enabled 187 | 188 | A disabled shortcut does not get activated. 189 | 190 | The default value is \c true. 191 | 192 | \sa setDisabled() 193 | */ 194 | bool QxtGlobalShortcut::isEnabled() const 195 | { 196 | return qxt_d().enabled; 197 | } 198 | 199 | void QxtGlobalShortcut::setEnabled(bool enabled) 200 | { 201 | qxt_d().enabled = enabled; 202 | } 203 | 204 | /*! 205 | Sets the shortcut \a disabled. 206 | 207 | \sa enabled 208 | */ 209 | void QxtGlobalShortcut::setDisabled(bool disabled) 210 | { 211 | qxt_d().enabled = !disabled; 212 | } 213 | -------------------------------------------------------------------------------- /src/third-party/qxtglobalshortcut.h: -------------------------------------------------------------------------------- 1 | #ifndef QXTGLOBALSHORTCUT_H 2 | /**************************************************************************** 3 | ** Copyright (c) 2006 - 2011, the LibQxt project. 4 | ** See the Qxt AUTHORS file for a list of authors and copyright holders. 5 | ** All rights reserved. 6 | ** 7 | ** Redistribution and use in source and binary forms, with or without 8 | ** modification, are permitted provided that the following conditions are met: 9 | ** * Redistributions of source code must retain the above copyright 10 | ** notice, this list of conditions and the following disclaimer. 11 | ** * Redistributions in binary form must reproduce the above copyright 12 | ** notice, this list of conditions and the following disclaimer in the 13 | ** documentation and/or other materials provided with the distribution. 14 | ** * Neither the name of the LibQxt project nor the 15 | ** names of its contributors may be used to endorse or promote products 16 | ** derived from this software without specific prior written permission. 17 | ** 18 | ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 19 | ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 | ** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | ** DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 22 | ** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 | ** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 | ** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 25 | ** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 27 | ** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | ** 29 | ** 30 | *****************************************************************************/ 31 | 32 | #define QXTGLOBALSHORTCUT_H 33 | 34 | #include "qxtglobal.h" 35 | #include 36 | #include 37 | class QxtGlobalShortcutPrivate; 38 | 39 | class QXT_GUI_EXPORT QxtGlobalShortcut : public QObject 40 | { 41 | Q_OBJECT 42 | QXT_DECLARE_PRIVATE(QxtGlobalShortcut) 43 | Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled) 44 | Q_PROPERTY(QKeySequence shortcut READ shortcut WRITE setShortcut) 45 | 46 | public: 47 | explicit QxtGlobalShortcut(QObject* parent = 0); 48 | explicit QxtGlobalShortcut(const QKeySequence& shortcut, QObject* parent = 0); 49 | virtual ~QxtGlobalShortcut(); 50 | 51 | QKeySequence shortcut() const; 52 | bool setShortcut(const QKeySequence& shortcut); 53 | 54 | bool isEnabled() const; 55 | 56 | public Q_SLOTS: 57 | void setEnabled(bool enabled = true); 58 | void setDisabled(bool disabled = true); 59 | 60 | Q_SIGNALS: 61 | void activated(); 62 | }; 63 | 64 | #endif // QXTGLOBALSHORTCUT_H 65 | -------------------------------------------------------------------------------- /src/third-party/qxtglobalshortcut_mac.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | /**************************************************************************** 3 | ** Copyright (c) 2006 - 2011, the LibQxt project. 4 | ** See the Qxt AUTHORS file for a list of authors and copyright holders. 5 | ** All rights reserved. 6 | ** 7 | ** Redistribution and use in source and binary forms, with or without 8 | ** modification, are permitted provided that the following conditions are met: 9 | ** * Redistributions of source code must retain the above copyright 10 | ** notice, this list of conditions and the following disclaimer. 11 | ** * Redistributions in binary form must reproduce the above copyright 12 | ** notice, this list of conditions and the following disclaimer in the 13 | ** documentation and/or other materials provided with the distribution. 14 | ** * Neither the name of the LibQxt project nor the 15 | ** names of its contributors may be used to endorse or promote products 16 | ** derived from this software without specific prior written permission. 17 | ** 18 | ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 19 | ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 | ** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | ** DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 22 | ** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 | ** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 | ** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 25 | ** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 27 | ** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | ** 29 | ** 30 | *****************************************************************************/ 31 | 32 | #include "qxtglobalshortcut_p.h" 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | typedef QPair Identifier; 39 | static QMap keyRefs; 40 | static QHash keyIDs; 41 | static quint32 hotKeySerial = 0; 42 | static bool qxt_mac_handler_installed = false; 43 | 44 | OSStatus qxt_mac_handle_hot_key(EventHandlerCallRef nextHandler, EventRef event, void* data) 45 | { 46 | Q_UNUSED(nextHandler); 47 | Q_UNUSED(data); 48 | if (GetEventClass(event) == kEventClassKeyboard && GetEventKind(event) == kEventHotKeyPressed) 49 | { 50 | EventHotKeyID keyID; 51 | GetEventParameter(event, kEventParamDirectObject, typeEventHotKeyID, NULL, sizeof(keyID), NULL, &keyID); 52 | Identifier id = keyIDs.key(keyID.id); 53 | QxtGlobalShortcutPrivate::activateShortcut(id.second, id.first); 54 | } 55 | return noErr; 56 | } 57 | 58 | quint32 QxtGlobalShortcutPrivate::nativeModifiers(Qt::KeyboardModifiers modifiers) 59 | { 60 | quint32 native = 0; 61 | if (modifiers & Qt::ShiftModifier) 62 | native |= shiftKey; 63 | if (modifiers & Qt::ControlModifier) 64 | native |= cmdKey; 65 | if (modifiers & Qt::AltModifier) 66 | native |= optionKey; 67 | if (modifiers & Qt::MetaModifier) 68 | native |= controlKey; 69 | if (modifiers & Qt::KeypadModifier) 70 | native |= kEventKeyModifierNumLockMask; 71 | return native; 72 | } 73 | 74 | quint32 QxtGlobalShortcutPrivate::nativeKeycode(Qt::Key key) 75 | { 76 | UTF16Char ch; 77 | // Constants found in NSEvent.h from AppKit.framework 78 | switch (key) 79 | { 80 | case Qt::Key_Return: 81 | return kVK_Return; 82 | case Qt::Key_Enter: 83 | return kVK_ANSI_KeypadEnter; 84 | case Qt::Key_Tab: 85 | return kVK_Tab; 86 | case Qt::Key_Space: 87 | return kVK_Space; 88 | case Qt::Key_Backspace: 89 | return kVK_Delete; 90 | case Qt::Key_Control: 91 | return kVK_Command; 92 | case Qt::Key_Shift: 93 | return kVK_Shift; 94 | case Qt::Key_CapsLock: 95 | return kVK_CapsLock; 96 | case Qt::Key_Option: 97 | return kVK_Option; 98 | case Qt::Key_Meta: 99 | return kVK_Control; 100 | case Qt::Key_F17: 101 | return kVK_F17; 102 | case Qt::Key_VolumeUp: 103 | return kVK_VolumeUp; 104 | case Qt::Key_VolumeDown: 105 | return kVK_VolumeDown; 106 | case Qt::Key_F18: 107 | return kVK_F18; 108 | case Qt::Key_F19: 109 | return kVK_F19; 110 | case Qt::Key_F20: 111 | return kVK_F20; 112 | case Qt::Key_F5: 113 | return kVK_F5; 114 | case Qt::Key_F6: 115 | return kVK_F6; 116 | case Qt::Key_F7: 117 | return kVK_F7; 118 | case Qt::Key_F3: 119 | return kVK_F3; 120 | case Qt::Key_F8: 121 | return kVK_F8; 122 | case Qt::Key_F9: 123 | return kVK_F9; 124 | case Qt::Key_F11: 125 | return kVK_F11; 126 | case Qt::Key_F13: 127 | return kVK_F13; 128 | case Qt::Key_F16: 129 | return kVK_F16; 130 | case Qt::Key_F14: 131 | return kVK_F14; 132 | case Qt::Key_F10: 133 | return kVK_F10; 134 | case Qt::Key_F12: 135 | return kVK_F12; 136 | case Qt::Key_F15: 137 | return kVK_F15; 138 | case Qt::Key_Help: 139 | return kVK_Help; 140 | case Qt::Key_Home: 141 | return kVK_Home; 142 | case Qt::Key_PageUp: 143 | return kVK_PageUp; 144 | case Qt::Key_Delete: 145 | return kVK_ForwardDelete; 146 | case Qt::Key_F4: 147 | return kVK_F4; 148 | case Qt::Key_End: 149 | return kVK_End; 150 | case Qt::Key_F2: 151 | return kVK_F2; 152 | case Qt::Key_PageDown: 153 | return kVK_PageDown; 154 | case Qt::Key_F1: 155 | return kVK_F1; 156 | case Qt::Key_Left: 157 | return kVK_LeftArrow; 158 | case Qt::Key_Right: 159 | return kVK_RightArrow; 160 | case Qt::Key_Down: 161 | return kVK_DownArrow; 162 | case Qt::Key_Up: 163 | return kVK_UpArrow; 164 | default: 165 | ; 166 | } 167 | 168 | if (key == Qt::Key_Escape) ch = 27; 169 | else if (key == Qt::Key_Return) ch = 13; 170 | else if (key == Qt::Key_Enter) ch = 3; 171 | else if (key == Qt::Key_Tab) ch = 9; 172 | else ch = key; 173 | 174 | CFDataRef currentLayoutData; 175 | TISInputSourceRef currentKeyboard = TISCopyCurrentKeyboardInputSource(); 176 | 177 | if (currentKeyboard == NULL) 178 | return 0; 179 | 180 | currentLayoutData = (CFDataRef)TISGetInputSourceProperty(currentKeyboard, kTISPropertyUnicodeKeyLayoutData); 181 | CFRelease(currentKeyboard); 182 | if (currentLayoutData == NULL) 183 | return 0; 184 | 185 | UCKeyboardLayout* header = (UCKeyboardLayout*)CFDataGetBytePtr(currentLayoutData); 186 | UCKeyboardTypeHeader* table = header->keyboardTypeList; 187 | 188 | uint8_t *data = (uint8_t*)header; 189 | // God, would a little documentation for this shit kill you... 190 | for (quint32 i=0; i < header->keyboardTypeCount; i++) 191 | { 192 | UCKeyStateRecordsIndex* stateRec = 0; 193 | if (table[i].keyStateRecordsIndexOffset != 0) 194 | { 195 | stateRec = reinterpret_cast(data + table[i].keyStateRecordsIndexOffset); 196 | if (stateRec->keyStateRecordsIndexFormat != kUCKeyStateRecordsIndexFormat) stateRec = 0; 197 | } 198 | 199 | UCKeyToCharTableIndex* charTable = reinterpret_cast(data + table[i].keyToCharTableIndexOffset); 200 | if (charTable->keyToCharTableIndexFormat != kUCKeyToCharTableIndexFormat) continue; 201 | 202 | for (quint32 j=0; j < charTable->keyToCharTableCount; j++) 203 | { 204 | UCKeyOutput* keyToChar = reinterpret_cast(data + charTable->keyToCharTableOffsets[j]); 205 | for (quint32 k=0; k < charTable->keyToCharTableSize; k++) 206 | { 207 | if (keyToChar[k] & kUCKeyOutputTestForIndexMask) 208 | { 209 | long idx = keyToChar[k] & kUCKeyOutputGetIndexMask; 210 | if (stateRec && idx < stateRec->keyStateRecordCount) 211 | { 212 | UCKeyStateRecord* rec = reinterpret_cast(data + stateRec->keyStateRecordOffsets[idx]); 213 | if (rec->stateZeroCharData == ch) return k; 214 | } 215 | } 216 | else if (!(keyToChar[k] & kUCKeyOutputSequenceIndexMask) && keyToChar[k] < 0xFFFE) 217 | { 218 | if (keyToChar[k] == ch) return k; 219 | } 220 | } // for k 221 | } // for j 222 | } // for i 223 | return 0; 224 | } 225 | 226 | bool QxtGlobalShortcutPrivate::registerShortcut(quint32 nativeKey, quint32 nativeMods) 227 | { 228 | if (!qxt_mac_handler_installed) 229 | { 230 | EventTypeSpec t; 231 | t.eventClass = kEventClassKeyboard; 232 | t.eventKind = kEventHotKeyPressed; 233 | InstallApplicationEventHandler(&qxt_mac_handle_hot_key, 1, &t, NULL, NULL); 234 | } 235 | 236 | EventHotKeyID keyID; 237 | keyID.signature = 'cute'; 238 | keyID.id = ++hotKeySerial; 239 | 240 | EventHotKeyRef ref = 0; 241 | bool rv = !RegisterEventHotKey(nativeKey, nativeMods, keyID, GetApplicationEventTarget(), 0, &ref); 242 | if (rv) 243 | { 244 | keyIDs.insert(Identifier(nativeMods, nativeKey), keyID.id); 245 | keyRefs.insert(keyID.id, ref); 246 | } 247 | return rv; 248 | } 249 | 250 | bool QxtGlobalShortcutPrivate::unregisterShortcut(quint32 nativeKey, quint32 nativeMods) 251 | { 252 | Identifier id(nativeMods, nativeKey); 253 | if (!keyIDs.contains(id)) return false; 254 | 255 | EventHotKeyRef ref = keyRefs.take(keyIDs[id]); 256 | keyIDs.remove(id); 257 | return !UnregisterEventHotKey(ref); 258 | } 259 | -------------------------------------------------------------------------------- /src/third-party/qxtglobalshortcut_p.h: -------------------------------------------------------------------------------- 1 | #ifndef QXTGLOBALSHORTCUT_P_H 2 | /**************************************************************************** 3 | ** Copyright (c) 2006 - 2011, the LibQxt project. 4 | ** See the Qxt AUTHORS file for a list of authors and copyright holders. 5 | ** All rights reserved. 6 | ** 7 | ** Redistribution and use in source and binary forms, with or without 8 | ** modification, are permitted provided that the following conditions are met: 9 | ** * Redistributions of source code must retain the above copyright 10 | ** notice, this list of conditions and the following disclaimer. 11 | ** * Redistributions in binary form must reproduce the above copyright 12 | ** notice, this list of conditions and the following disclaimer in the 13 | ** documentation and/or other materials provided with the distribution. 14 | ** * Neither the name of the LibQxt project nor the 15 | ** names of its contributors may be used to endorse or promote products 16 | ** derived from this software without specific prior written permission. 17 | ** 18 | ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 19 | ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 | ** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | ** DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 22 | ** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 | ** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 | ** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 25 | ** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 27 | ** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | ** 29 | ** 30 | *****************************************************************************/ 31 | 32 | #define QXTGLOBALSHORTCUT_P_H 33 | 34 | #include "qxtglobalshortcut.h" 35 | #include 36 | #include 37 | #include 38 | #include 39 | 40 | 41 | class QxtGlobalShortcutPrivate : public QxtPrivate 42 | #if !defined(Q_OS_MAC) 43 | ,public QAbstractNativeEventFilter 44 | #endif 45 | { 46 | public: 47 | QXT_DECLARE_PUBLIC(QxtGlobalShortcut) 48 | QxtGlobalShortcutPrivate(); 49 | ~QxtGlobalShortcutPrivate(); 50 | 51 | bool enabled; 52 | Qt::Key key; 53 | Qt::KeyboardModifiers mods; 54 | 55 | bool setShortcut(const QKeySequence& shortcut); 56 | bool unsetShortcut(); 57 | 58 | static bool error; 59 | #ifndef Q_OS_MAC 60 | static int ref; 61 | virtual bool nativeEventFilter(const QByteArray & eventType, void * message, long * result); 62 | #endif 63 | 64 | static void activateShortcut(quint32 nativeKey, quint32 nativeMods); 65 | 66 | private: 67 | static quint32 nativeKeycode(Qt::Key keycode); 68 | static quint32 nativeModifiers(Qt::KeyboardModifiers modifiers); 69 | 70 | static bool registerShortcut(quint32 nativeKey, quint32 nativeMods); 71 | static bool unregisterShortcut(quint32 nativeKey, quint32 nativeMods); 72 | 73 | static QHash, QxtGlobalShortcut*> shortcuts; 74 | }; 75 | 76 | #endif // QXTGLOBALSHORTCUT_P_H 77 | -------------------------------------------------------------------------------- /src/third-party/qxtglobalshortcut_win.cpp: -------------------------------------------------------------------------------- 1 | #include "qxtglobalshortcut_p.h" 2 | /**************************************************************************** 3 | ** Copyright (c) 2006 - 2011, the LibQxt project. 4 | ** See the Qxt AUTHORS file for a list of authors and copyright holders. 5 | ** All rights reserved. 6 | ** 7 | ** Redistribution and use in source and binary forms, with or without 8 | ** modification, are permitted provided that the following conditions are met: 9 | ** * Redistributions of source code must retain the above copyright 10 | ** notice, this list of conditions and the following disclaimer. 11 | ** * Redistributions in binary form must reproduce the above copyright 12 | ** notice, this list of conditions and the following disclaimer in the 13 | ** documentation and/or other materials provided with the distribution. 14 | ** * Neither the name of the LibQxt project nor the 15 | ** names of its contributors may be used to endorse or promote products 16 | ** derived from this software without specific prior written permission. 17 | ** 18 | ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 19 | ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 | ** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | ** DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 22 | ** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 | ** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 | ** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 25 | ** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 27 | ** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | ** 29 | ** 30 | *****************************************************************************/ 31 | 32 | #include 33 | 34 | 35 | bool QxtGlobalShortcutPrivate::nativeEventFilter(const QByteArray & eventType, 36 | void * message, long * result) 37 | { 38 | Q_UNUSED(eventType); 39 | Q_UNUSED(result); 40 | MSG* msg = static_cast(message); 41 | if (msg->message == WM_HOTKEY) 42 | { 43 | const quint32 keycode = HIWORD(msg->lParam); 44 | const quint32 modifiers = LOWORD(msg->lParam); 45 | activateShortcut(keycode, modifiers); 46 | } 47 | 48 | return false; 49 | } 50 | 51 | 52 | quint32 QxtGlobalShortcutPrivate::nativeModifiers(Qt::KeyboardModifiers modifiers) 53 | { 54 | // MOD_ALT, MOD_CONTROL, (MOD_KEYUP), MOD_SHIFT, MOD_WIN 55 | quint32 native = 0; 56 | if (modifiers & Qt::ShiftModifier) 57 | native |= MOD_SHIFT; 58 | if (modifiers & Qt::ControlModifier) 59 | native |= MOD_CONTROL; 60 | if (modifiers & Qt::AltModifier) 61 | native |= MOD_ALT; 62 | if (modifiers & Qt::MetaModifier) 63 | native |= MOD_WIN; 64 | // TODO: resolve these? 65 | //if (modifiers & Qt::KeypadModifier) 66 | //if (modifiers & Qt::GroupSwitchModifier) 67 | return native; 68 | } 69 | 70 | quint32 QxtGlobalShortcutPrivate::nativeKeycode(Qt::Key key) 71 | { 72 | switch (key) 73 | { 74 | case Qt::Key_Escape: 75 | return VK_ESCAPE; 76 | case Qt::Key_Tab: 77 | case Qt::Key_Backtab: 78 | return VK_TAB; 79 | case Qt::Key_Backspace: 80 | return VK_BACK; 81 | case Qt::Key_Return: 82 | case Qt::Key_Enter: 83 | return VK_RETURN; 84 | case Qt::Key_Insert: 85 | return VK_INSERT; 86 | case Qt::Key_Delete: 87 | return VK_DELETE; 88 | case Qt::Key_Pause: 89 | return VK_PAUSE; 90 | case Qt::Key_Print: 91 | return VK_PRINT; 92 | case Qt::Key_Clear: 93 | return VK_CLEAR; 94 | case Qt::Key_Home: 95 | return VK_HOME; 96 | case Qt::Key_End: 97 | return VK_END; 98 | case Qt::Key_Left: 99 | return VK_LEFT; 100 | case Qt::Key_Up: 101 | return VK_UP; 102 | case Qt::Key_Right: 103 | return VK_RIGHT; 104 | case Qt::Key_Down: 105 | return VK_DOWN; 106 | case Qt::Key_PageUp: 107 | return VK_PRIOR; 108 | case Qt::Key_PageDown: 109 | return VK_NEXT; 110 | case Qt::Key_F1: 111 | return VK_F1; 112 | case Qt::Key_F2: 113 | return VK_F2; 114 | case Qt::Key_F3: 115 | return VK_F3; 116 | case Qt::Key_F4: 117 | return VK_F4; 118 | case Qt::Key_F5: 119 | return VK_F5; 120 | case Qt::Key_F6: 121 | return VK_F6; 122 | case Qt::Key_F7: 123 | return VK_F7; 124 | case Qt::Key_F8: 125 | return VK_F8; 126 | case Qt::Key_F9: 127 | return VK_F9; 128 | case Qt::Key_F10: 129 | return VK_F10; 130 | case Qt::Key_F11: 131 | return VK_F11; 132 | case Qt::Key_F12: 133 | return VK_F12; 134 | case Qt::Key_F13: 135 | return VK_F13; 136 | case Qt::Key_F14: 137 | return VK_F14; 138 | case Qt::Key_F15: 139 | return VK_F15; 140 | case Qt::Key_F16: 141 | return VK_F16; 142 | case Qt::Key_F17: 143 | return VK_F17; 144 | case Qt::Key_F18: 145 | return VK_F18; 146 | case Qt::Key_F19: 147 | return VK_F19; 148 | case Qt::Key_F20: 149 | return VK_F20; 150 | case Qt::Key_F21: 151 | return VK_F21; 152 | case Qt::Key_F22: 153 | return VK_F22; 154 | case Qt::Key_F23: 155 | return VK_F23; 156 | case Qt::Key_F24: 157 | return VK_F24; 158 | case Qt::Key_Space: 159 | return VK_SPACE; 160 | case Qt::Key_Asterisk: 161 | return VK_MULTIPLY; 162 | case Qt::Key_Plus: 163 | return VK_ADD; 164 | case Qt::Key_Comma: 165 | return VK_SEPARATOR; 166 | case Qt::Key_Minus: 167 | return VK_SUBTRACT; 168 | case Qt::Key_Slash: 169 | return VK_DIVIDE; 170 | case Qt::Key_MediaNext: 171 | return VK_MEDIA_NEXT_TRACK; 172 | case Qt::Key_MediaPrevious: 173 | return VK_MEDIA_PREV_TRACK; 174 | case Qt::Key_MediaPlay: 175 | return VK_MEDIA_PLAY_PAUSE; 176 | case Qt::Key_MediaStop: 177 | return VK_MEDIA_STOP; 178 | // couldn't find those in VK_* 179 | //case Qt::Key_MediaLast: 180 | //case Qt::Key_MediaRecord: 181 | case Qt::Key_VolumeDown: 182 | return VK_VOLUME_DOWN; 183 | case Qt::Key_VolumeUp: 184 | return VK_VOLUME_UP; 185 | case Qt::Key_VolumeMute: 186 | return VK_VOLUME_MUTE; 187 | 188 | // numbers 189 | case Qt::Key_0: 190 | case Qt::Key_1: 191 | case Qt::Key_2: 192 | case Qt::Key_3: 193 | case Qt::Key_4: 194 | case Qt::Key_5: 195 | case Qt::Key_6: 196 | case Qt::Key_7: 197 | case Qt::Key_8: 198 | case Qt::Key_9: 199 | return key; 200 | 201 | // letters 202 | case Qt::Key_A: 203 | case Qt::Key_B: 204 | case Qt::Key_C: 205 | case Qt::Key_D: 206 | case Qt::Key_E: 207 | case Qt::Key_F: 208 | case Qt::Key_G: 209 | case Qt::Key_H: 210 | case Qt::Key_I: 211 | case Qt::Key_J: 212 | case Qt::Key_K: 213 | case Qt::Key_L: 214 | case Qt::Key_M: 215 | case Qt::Key_N: 216 | case Qt::Key_O: 217 | case Qt::Key_P: 218 | case Qt::Key_Q: 219 | case Qt::Key_R: 220 | case Qt::Key_S: 221 | case Qt::Key_T: 222 | case Qt::Key_U: 223 | case Qt::Key_V: 224 | case Qt::Key_W: 225 | case Qt::Key_X: 226 | case Qt::Key_Y: 227 | case Qt::Key_Z: 228 | return key; 229 | 230 | default: 231 | return 0; 232 | } 233 | } 234 | 235 | bool QxtGlobalShortcutPrivate::registerShortcut(quint32 nativeKey, quint32 nativeMods) 236 | { 237 | return RegisterHotKey(0, nativeMods ^ nativeKey, nativeMods, nativeKey); 238 | } 239 | 240 | bool QxtGlobalShortcutPrivate::unregisterShortcut(quint32 nativeKey, quint32 nativeMods) 241 | { 242 | return UnregisterHotKey(0, nativeMods ^ nativeKey); 243 | } 244 | -------------------------------------------------------------------------------- /src/third-party/qxtglobalshortcut_x11.cpp: -------------------------------------------------------------------------------- 1 | #include "qxtglobalshortcut_p.h" 2 | /**************************************************************************** 3 | ** Copyright (c) 2006 - 2011, the LibQxt project. 4 | ** See the Qxt AUTHORS file for a list of authors and copyright holders. 5 | ** All rights reserved. 6 | ** 7 | ** Redistribution and use in source and binary forms, with or without 8 | ** modification, are permitted provided that the following conditions are met: 9 | ** * Redistributions of source code must retain the above copyright 10 | ** notice, this list of conditions and the following disclaimer. 11 | ** * Redistributions in binary form must reproduce the above copyright 12 | ** notice, this list of conditions and the following disclaimer in the 13 | ** documentation and/or other materials provided with the distribution. 14 | ** * Neither the name of the LibQxt project nor the 15 | ** names of its contributors may be used to endorse or promote products 16 | ** derived from this software without specific prior written permission. 17 | ** 18 | ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 19 | ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 | ** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | ** DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 22 | ** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 | ** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 | ** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 25 | ** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 27 | ** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | ** 29 | ** 30 | *****************************************************************************/ 31 | 32 | 33 | /**************************************************************************** 34 | * 35 | * Note: This file is a modified version for QTerminal! 36 | * 37 | ****************************************************************************/ 38 | 39 | #include 40 | #include 41 | 42 | #include 43 | #include 44 | 45 | namespace { 46 | 47 | const QVector maskModifiers = QVector() 48 | << 0 << Mod2Mask << LockMask << (Mod2Mask | LockMask); 49 | 50 | typedef int (*X11ErrorHandler)(Display *display, XErrorEvent *event); 51 | 52 | class QxtX11ErrorHandler { 53 | public: 54 | static bool error; 55 | 56 | static int qxtX11ErrorHandler(Display *display, XErrorEvent *event) 57 | { 58 | Q_UNUSED(display); 59 | switch (event->error_code) 60 | { 61 | case BadAccess: 62 | case BadValue: 63 | case BadWindow: 64 | if (event->request_code == 33 /* X_GrabKey */ || 65 | event->request_code == 34 /* X_UngrabKey */) 66 | { 67 | error = true; 68 | //TODO: 69 | //char errstr[256]; 70 | //XGetErrorText(dpy, err->error_code, errstr, 256); 71 | } 72 | } 73 | return 0; 74 | } 75 | 76 | QxtX11ErrorHandler() 77 | { 78 | error = false; 79 | m_previousErrorHandler = XSetErrorHandler(qxtX11ErrorHandler); 80 | } 81 | 82 | ~QxtX11ErrorHandler() 83 | { 84 | XSetErrorHandler(m_previousErrorHandler); 85 | } 86 | 87 | private: 88 | X11ErrorHandler m_previousErrorHandler; 89 | }; 90 | 91 | bool QxtX11ErrorHandler::error = false; 92 | 93 | class QxtX11Data { 94 | public: 95 | QxtX11Data() 96 | { 97 | m_display = QX11Info::display(); 98 | } 99 | 100 | bool isValid() 101 | { 102 | return m_display != 0; 103 | } 104 | 105 | Display *display() 106 | { 107 | Q_ASSERT(isValid()); 108 | return m_display; 109 | } 110 | 111 | Window rootWindow() 112 | { 113 | return DefaultRootWindow(display()); 114 | } 115 | 116 | bool grabKey(quint32 keycode, quint32 modifiers, Window window) 117 | { 118 | QxtX11ErrorHandler errorHandler; 119 | 120 | for (int i = 0; !errorHandler.error && i < maskModifiers.size(); ++i) { 121 | XGrabKey(display(), keycode, modifiers | maskModifiers[i], window, True, 122 | GrabModeAsync, GrabModeAsync); 123 | } 124 | 125 | if (errorHandler.error) { 126 | ungrabKey(keycode, modifiers, window); 127 | return false; 128 | } 129 | 130 | return true; 131 | } 132 | 133 | bool ungrabKey(quint32 keycode, quint32 modifiers, Window window) 134 | { 135 | QxtX11ErrorHandler errorHandler; 136 | 137 | for (const quint32& maskMods : qAsConst(maskModifiers)) { 138 | XUngrabKey(display(), keycode, modifiers | maskMods, window); 139 | } 140 | 141 | return !errorHandler.error; 142 | } 143 | 144 | private: 145 | Display *m_display; 146 | }; 147 | 148 | } // namespace 149 | 150 | bool QxtGlobalShortcutPrivate::nativeEventFilter(const QByteArray & eventType, 151 | void *message, long *result) 152 | { 153 | Q_UNUSED(result); 154 | 155 | xcb_key_press_event_t *kev = 0; 156 | if (eventType == "xcb_generic_event_t") { 157 | xcb_generic_event_t *ev = static_cast(message); 158 | if ((ev->response_type & 127) == XCB_KEY_PRESS) 159 | kev = static_cast(message); 160 | } 161 | 162 | if (kev != 0) { 163 | unsigned int keycode = kev->detail; 164 | unsigned int keystate = 0; 165 | if(kev->state & XCB_MOD_MASK_1) 166 | keystate |= Mod1Mask; 167 | if(kev->state & XCB_MOD_MASK_CONTROL) 168 | keystate |= ControlMask; 169 | if(kev->state & XCB_MOD_MASK_4) 170 | keystate |= Mod4Mask; 171 | if(kev->state & XCB_MOD_MASK_SHIFT) 172 | keystate |= ShiftMask; 173 | activateShortcut(keycode, 174 | // Mod1Mask == Alt, Mod4Mask == Meta 175 | keystate & (ShiftMask | ControlMask | Mod1Mask | Mod4Mask)); 176 | } 177 | 178 | return false; 179 | } 180 | 181 | quint32 QxtGlobalShortcutPrivate::nativeModifiers(Qt::KeyboardModifiers modifiers) 182 | { 183 | // ShiftMask, LockMask, ControlMask, Mod1Mask, Mod2Mask, Mod3Mask, Mod4Mask, and Mod5Mask 184 | quint32 native = 0; 185 | if (modifiers & Qt::ShiftModifier) 186 | native |= ShiftMask; 187 | if (modifiers & Qt::ControlModifier) 188 | native |= ControlMask; 189 | if (modifiers & Qt::AltModifier) 190 | native |= Mod1Mask; 191 | if (modifiers & Qt::MetaModifier) 192 | native |= Mod4Mask; 193 | 194 | // TODO: resolve these? 195 | //if (modifiers & Qt::MetaModifier) 196 | //if (modifiers & Qt::KeypadModifier) 197 | //if (modifiers & Qt::GroupSwitchModifier) 198 | return native; 199 | } 200 | 201 | quint32 QxtGlobalShortcutPrivate::nativeKeycode(Qt::Key key) 202 | { 203 | QxtX11Data x11; 204 | if (!x11.isValid()) 205 | return 0; 206 | 207 | KeySym keysym = XStringToKeysym(QKeySequence(key).toString().toLatin1().data()); 208 | if (keysym == NoSymbol) 209 | keysym = static_cast(key); 210 | 211 | return XKeysymToKeycode(x11.display(), keysym); 212 | } 213 | 214 | bool QxtGlobalShortcutPrivate::registerShortcut(quint32 nativeKey, quint32 nativeMods) 215 | { 216 | QxtX11Data x11; 217 | return x11.isValid() && x11.grabKey(nativeKey, nativeMods, x11.rootWindow()); 218 | } 219 | 220 | bool QxtGlobalShortcutPrivate::unregisterShortcut(quint32 nativeKey, quint32 nativeMods) 221 | { 222 | QxtX11Data x11; 223 | return x11.isValid() && x11.ungrabKey(nativeKey, nativeMods, x11.rootWindow()); 224 | } 225 | -------------------------------------------------------------------------------- /src/translations/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | project(qterminal) 2 | 3 | build_component("." "${CMAKE_INSTALL_FULL_DATADIR}/qterminal/translations") 4 | --------------------------------------------------------------------------------