diff --git a/COPYING.DOC b/COPYING.DOC index 4a0fe1c..71ec2c4 100644 --- a/COPYING.DOC +++ b/COPYING.DOC @@ -1,397 +1,397 @@ GNU Free Documentation License Version 1.2, November 2002 Copyright (C) 2000,2001,2002 Free Software Foundation, Inc. 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. 0. PREAMBLE The purpose of this License is to make a manual, textbook, or other functional and useful document "free" in the sense of freedom: to assure everyone the effective freedom to copy and redistribute it, with or without modifying it, either commercially or noncommercially. Secondarily, this License preserves for the author and publisher a way to get credit for their work, while not being considered responsible for modifications made by others. This License is a kind of "copyleft", which means that derivative works of the document must themselves be free in the same sense. It complements the GNU General Public License, which is a copyleft license designed for free software. We have designed this License in order to use it for manuals for free software, because free software needs free documentation: a free program should come with manuals providing the same freedoms that the software does. But this License is not limited to software manuals; it can be used for any textual work, regardless of subject matter or whether it is published as a printed book. We recommend this License principally for works whose purpose is instruction or reference. 1. APPLICABILITY AND DEFINITIONS This License applies to any manual or other work, in any medium, that contains a notice placed by the copyright holder saying it can be distributed under the terms of this License. Such a notice grants a world-wide, royalty-free license, unlimited in duration, to use that work under the conditions stated herein. The "Document", below, refers to any such manual or work. Any member of the public is a licensee, and is addressed as "you". You accept the license if you copy, modify or distribute the work in a way requiring permission under copyright law. A "Modified Version" of the Document means any work containing the Document or a portion of it, either copied verbatim, or with modifications and/or translated into another language. A "Secondary Section" is a named appendix or a front-matter section of the Document that deals exclusively with the relationship of the publishers or authors of the Document to the Document's overall subject (or to related matters) and contains nothing that could fall directly within that overall subject. (Thus, if the Document is in part a textbook of mathematics, a Secondary Section may not explain any mathematics.) The relationship could be a matter of historical connection with the subject or with related matters, or of legal, commercial, philosophical, ethical or political position regarding them. The "Invariant Sections" are certain Secondary Sections whose titles are designated, as being those of Invariant Sections, in the notice that says that the Document is released under this License. If a section does not fit the above definition of Secondary then it is not allowed to be designated as Invariant. The Document may contain zero Invariant Sections. If the Document does not identify any Invariant Sections then there are none. The "Cover Texts" are certain short passages of text that are listed, as Front-Cover Texts or Back-Cover Texts, in the notice that says that the Document is released under this License. A Front-Cover Text may be at most 5 words, and a Back-Cover Text may be at most 25 words. A "Transparent" copy of the Document means a machine-readable copy, represented in a format whose specification is available to the general public, that is suitable for revising the document straightforwardly with generic text editors or (for images composed of pixels) generic paint programs or (for drawings) some widely available drawing editor, and that is suitable for input to text formatters or for automatic translation to a variety of formats suitable for input to text formatters. A copy made in an otherwise Transparent file format whose markup, or absence of markup, has been arranged to thwart or discourage subsequent modification by readers is not Transparent. An image format is not Transparent if used for any substantial amount of text. A copy that is not "Transparent" is called "Opaque". Examples of suitable formats for Transparent copies include plain ASCII without markup, Texinfo input format, LaTeX input format, SGML or XML using a publicly available DTD, and standard-conforming simple HTML, PostScript or PDF designed for human modification. Examples of transparent image formats include PNG, XCF and JPG. Opaque formats include proprietary formats that can be read and edited only by proprietary word processors, SGML or XML for which the DTD and/or processing tools are not generally available, and the machine-generated HTML, PostScript or PDF produced by some word processors for output purposes only. The "Title Page" means, for a printed book, the title page itself, plus such following pages as are needed to hold, legibly, the material this License requires to appear in the title page. For works in formats which do not have any title page as such, "Title Page" means the text near the most prominent appearance of the work's title, preceding the beginning of the body of the text. A section "Entitled XYZ" means a named subunit of the Document whose title either is precisely XYZ or contains XYZ in parentheses following text that translates XYZ in another language. (Here XYZ stands for a specific section name mentioned below, such as "Acknowledgements", "Dedications", "Endorsements", or "History".) To "Preserve the Title" of such a section when you modify the Document means that it remains a section "Entitled XYZ" according to this definition. The Document may include Warranty Disclaimers next to the notice which states that this License applies to the Document. These Warranty Disclaimers are considered to be included by reference in this License, but only as regards disclaiming warranties: any other implication that these Warranty Disclaimers may have is void and has no effect on the meaning of this License. 2. VERBATIM COPYING You may copy and distribute the Document in any medium, either commercially or noncommercially, provided that this License, the copyright notices, and the license notice saying this License applies to the Document are reproduced in all copies, and that you add no other conditions whatsoever to those of this License. You may not use technical measures to obstruct or control the reading or further copying of the copies you make or distribute. However, you may accept compensation in exchange for copies. If you distribute a large enough number of copies you must also follow the conditions in section 3. You may also lend copies, under the same conditions stated above, and you may publicly display copies. 3. COPYING IN QUANTITY If you publish printed copies (or copies in media that commonly have printed covers) of the Document, numbering more than 100, and the Document's license notice requires Cover Texts, you must enclose the copies in covers that carry, clearly and legibly, all these Cover Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on the back cover. Both covers must also clearly and legibly identify you as the publisher of these copies. The front cover must present the full title with all words of the title equally prominent and visible. You may add other material on the covers in addition. Copying with changes limited to the covers, as long as they preserve the title of the Document and satisfy these conditions, can be treated as verbatim copying in other respects. If the required texts for either cover are too voluminous to fit legibly, you should put the first ones listed (as many as fit reasonably) on the actual cover, and continue the rest onto adjacent pages. If you publish or distribute Opaque copies of the Document numbering more than 100, you must either include a machine-readable Transparent copy along with each Opaque copy, or state in or with each Opaque copy a computer-network location from which the general network-using public has access to download using public-standard network protocols a complete Transparent copy of the Document, free of added material. If you use the latter option, you must take reasonably prudent steps, when you begin distribution of Opaque copies in quantity, to ensure that this Transparent copy will remain thus accessible at the stated location until at least one year after the last time you distribute an Opaque copy (directly or through your agents or retailers) of that edition to the public. It is requested, but not required, that you contact the authors of the Document well before redistributing any large number of copies, to give them a chance to provide you with an updated version of the Document. 4. MODIFICATIONS You may copy and distribute a Modified Version of the Document under the conditions of sections 2 and 3 above, provided that you release the Modified Version under precisely this License, with the Modified Version filling the role of the Document, thus licensing distribution and modification of the Modified Version to whoever possesses a copy of it. In addition, you must do these things in the Modified Version: A. Use in the Title Page (and on the covers, if any) a title distinct from that of the Document, and from those of previous versions (which should, if there were any, be listed in the History section of the Document). You may use the same title as a previous version if the original publisher of that version gives permission. B. List on the Title Page, as authors, one or more persons or entities responsible for authorship of the modifications in the Modified Version, together with at least five of the principal authors of the Document (all of its principal authors, if it has fewer than five), unless they release you from this requirement. C. State on the Title page the name of the publisher of the Modified Version, as the publisher. D. Preserve all the copyright notices of the Document. E. Add an appropriate copyright notice for your modifications adjacent to the other copyright notices. F. Include, immediately after the copyright notices, a license notice giving the public permission to use the Modified Version under the terms of this License, in the form shown in the Addendum below. G. Preserve in that license notice the full lists of Invariant Sections and required Cover Texts given in the Document's license notice. H. Include an unaltered copy of this License. I. Preserve the section Entitled "History", Preserve its Title, and add to it an item stating at least the title, year, new authors, and publisher of the Modified Version as given on the Title Page. If there is no section Entitled "History" in the Document, create one stating the title, year, authors, and publisher of the Document as given on its Title Page, then add an item describing the Modified Version as stated in the previous sentence. J. Preserve the network location, if any, given in the Document for public access to a Transparent copy of the Document, and likewise the network locations given in the Document for previous versions it was based on. These may be placed in the "History" section. You may omit a network location for a work that was published at least four years before the Document itself, or if the original publisher of the version it refers to gives permission. K. For any section Entitled "Acknowledgements" or "Dedications", Preserve the Title of the section, and preserve in the section all the substance and tone of each of the contributor acknowledgements and/or dedications given therein. L. Preserve all the Invariant Sections of the Document, unaltered in their text and in their titles. Section numbers or the equivalent are not considered part of the section titles. M. Delete any section Entitled "Endorsements". Such a section may not be included in the Modified Version. N. Do not retitle any existing section to be Entitled "Endorsements" or to conflict in title with any Invariant Section. O. Preserve any Warranty Disclaimers. If the Modified Version includes new front-matter sections or appendices that qualify as Secondary Sections and contain no material copied from the Document, you may at your option designate some or all of these sections as invariant. To do this, add their titles to the list of Invariant Sections in the Modified Version's license notice. These titles must be distinct from any other section titles. You may add a section Entitled "Endorsements", provided it contains nothing but endorsements of your Modified Version by various parties--for example, statements of peer review or that the text has been approved by an organization as the authoritative definition of a standard. You may add a passage of up to five words as a Front-Cover Text, and a passage of up to 25 words as a Back-Cover Text, to the end of the list of Cover Texts in the Modified Version. Only one passage of Front-Cover Text and one of Back-Cover Text may be added by (or through arrangements made by) any one entity. If the Document already includes a cover text for the same cover, previously added by you or by arrangement made by the same entity you are acting on behalf of, you may not add another; but you may replace the old one, on explicit permission from the previous publisher that added the old one. The author(s) and publisher(s) of the Document do not by this License give permission to use their names for publicity for or to assert or imply endorsement of any Modified Version. 5. COMBINING DOCUMENTS You may combine the Document with other documents released under this License, under the terms defined in section 4 above for modified versions, provided that you include in the combination all of the Invariant Sections of all of the original documents, unmodified, and list them all as Invariant Sections of your combined work in its license notice, and that you preserve all their Warranty Disclaimers. The combined work need only contain one copy of this License, and multiple identical Invariant Sections may be replaced with a single copy. If there are multiple Invariant Sections with the same name but different contents, make the title of each such section unique by adding at the end of it, in parentheses, the name of the original author or publisher of that section if known, or else a unique number. Make the same adjustment to the section titles in the list of Invariant Sections in the license notice of the combined work. In the combination, you must combine any sections Entitled "History" in the various original documents, forming one section Entitled "History"; likewise combine any sections Entitled "Acknowledgements", and any sections Entitled "Dedications". You must delete all sections Entitled "Endorsements". 6. COLLECTIONS OF DOCUMENTS You may make a collection consisting of the Document and other documents released under this License, and replace the individual copies of this License in the various documents with a single copy that is included in the collection, provided that you follow the rules of this License for verbatim copying of each of the documents in all other respects. You may extract a single document from such a collection, and distribute it individually under this License, provided you insert a copy of this License into the extracted document, and follow this License in all other respects regarding verbatim copying of that document. 7. AGGREGATION WITH INDEPENDENT WORKS A compilation of the Document or its derivatives with other separate and independent documents or works, in or on a volume of a storage or distribution medium, is called an "aggregate" if the copyright resulting from the compilation is not used to limit the legal rights of the compilation's users beyond what the individual works permit. When the Document is included in an aggregate, this License does not apply to the other works in the aggregate which are not themselves derivative works of the Document. If the Cover Text requirement of section 3 is applicable to these copies of the Document, then if the Document is less than one half of the entire aggregate, the Document's Cover Texts may be placed on covers that bracket the Document within the aggregate, or the electronic equivalent of covers if the Document is in electronic form. Otherwise they must appear on printed covers that bracket the whole aggregate. 8. TRANSLATION Translation is considered a kind of modification, so you may distribute translations of the Document under the terms of section 4. Replacing Invariant Sections with translations requires special permission from their copyright holders, but you may include translations of some or all Invariant Sections in addition to the original versions of these Invariant Sections. You may include a translation of this License, and all the license notices in the Document, and any Warranty Disclaimers, provided that you also include the original English version of this License and the original versions of those notices and disclaimers. In case of a disagreement between the translation and the original version of this License or a notice or disclaimer, the original version will prevail. If a section in the Document is Entitled "Acknowledgements", "Dedications", or "History", the requirement (section 4) to Preserve its Title (section 1) will typically require changing the actual title. 9. TERMINATION You may not copy, modify, sublicense, or distribute the Document except as expressly provided for under this License. Any other attempt to copy, modify, sublicense or distribute the Document is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 10. FUTURE REVISIONS OF THIS LICENSE The Free Software Foundation may publish new, revised versions of the GNU Free Documentation License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. See -http://www.gnu.org/copyleft/. +https://www.gnu.org/copyleft/. Each version of the License is given a distinguishing version number. If the Document specifies that a particular numbered version of this License "or any later version" applies to it, you have the option of following the terms and conditions either of that specified version or of any later version that has been published (not as a draft) by the Free Software Foundation. If the Document does not specify a version number of this License, you may choose any version ever published (not as a draft) by the Free Software Foundation. ADDENDUM: How to use this License for your documents To use this License in a document you have written, include a copy of the License in the document and put the following copyright and license notices just after the title page: Copyright (c) YEAR YOUR NAME. Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the section entitled "GNU Free Documentation License". If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts, replace the "with...Texts." line with this: with the Invariant Sections being LIST THEIR TITLES, with the Front-Cover Texts being LIST, and with the Back-Cover Texts being LIST. If you have Invariant Sections without Cover Texts, or some other combination of the three, merge those two alternatives to suit the situation. If your document contains nontrivial examples of program code, we recommend releasing these examples in parallel under your choice of free software license, such as the GNU General Public License, to permit their use in free software. diff --git a/README b/README index 4a20e2d..c02c76c 100644 --- a/README +++ b/README @@ -1,29 +1,29 @@ Yakuake is a drop-down terminal emulator based on KDE Konsole technology. It's a KDE Extragear application released under GPL v2, GPL v3 or any later version accepted by the membership of KDE e.V. The current maintainer of Yakuake is Eike Hein . -The Yakuake website is located at: http://yakuake.kde.org/ +The Yakuake website is located at: https://kde.org/applications/system/org.kde.yakuake -Report bugs and wishes at: http://bugs.kde.org/ +Report bugs and wishes at: https://bugs.kde.org/ You can browse the latest and older sources at: https://cgit.kde.org/yakuake.git Basic build and installation instructions: 1. tar xfvj yakuake-.tar.bz2 2. cd yakuake- 3. mkdir build 4. cd build 5. cmake -DCMAKE_INSTALL_PREFIX= ../ 6. make 7. sudo make install -For more, please see the KDE Techbase wiki (http://techbase.kde.org/) and -the CMake documentation (at http://www.cmake.org/). +For more, please see the KDE Techbase wiki (https://techbase.kde.org/) and +the CMake documentation (at https://www.cmake.org/). diff --git a/app/config/appearancesettings.cpp b/app/config/appearancesettings.cpp index ced6cf6..073611e 100644 --- a/app/config/appearancesettings.cpp +++ b/app/config/appearancesettings.cpp @@ -1,553 +1,553 @@ /* Copyright (C) 2008-2009 by Eike Hein This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor appro- ved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program. If not, see http://www.gnu.org/licenses/. + along with this program. If not, see https://www.gnu.org/licenses/. */ #include "appearancesettings.h" #include "settings.h" #include "skinlistdelegate.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include AppearanceSettings::AppearanceSettings(QWidget* parent) : QWidget(parent) { setupUi(this); kcfg_Skin->hide(); kcfg_SkinInstalledWithKns->hide(); m_skins = new QStandardItemModel(this); m_skinListDelegate = new SkinListDelegate(this); skinList->setModel(m_skins); skinList->setItemDelegate(m_skinListDelegate); connect(skinList->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)), this, SLOT(updateSkinSetting())); connect(skinList->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)), this, SLOT(updateRemoveSkinButton())); connect(installButton, SIGNAL(clicked()), this, SLOT(installSkin())); connect(removeButton, SIGNAL(clicked()), this, SLOT(removeSelectedSkin())); installButton->setIcon(QIcon::fromTheme(QStringLiteral("folder"))); removeButton->setIcon(QIcon::fromTheme(QStringLiteral("edit-delete"))); ghnsButton->setIcon(QIcon::fromTheme(QStringLiteral("get-hot-new-stuff"))); m_knsConfigFileName = QLatin1String("yakuake.knsrc"); m_knsDownloadManager = new KNSCore::DownloadManager(m_knsConfigFileName); connect(ghnsButton, &QPushButton::clicked, this, &AppearanceSettings::getNewSkins); m_selectedSkinId = Settings::skin(); // Get all local skin directories. // One for manually installed skins, one for skins installed // through KNS3. m_localSkinsDir = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QStringLiteral("/yakuake/skins/"); m_knsSkinDir = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QStringLiteral("/yakuake/kns_skins/"); populateSkinList(); } AppearanceSettings::~AppearanceSettings() { } void AppearanceSettings::showEvent(QShowEvent* event) { populateSkinList(); if (skinList->currentIndex().isValid()) skinList->scrollTo(skinList->currentIndex()); QWidget::showEvent(event); } void AppearanceSettings::populateSkinList() { m_skins->clear(); QStringList allSkinLocations; allSkinLocations << QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral("/yakuake/skins/"), QStandardPaths::LocateDirectory); allSkinLocations << QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral("/yakuake/kns_skins/"), QStandardPaths::LocateDirectory); Q_FOREACH (const QString& skinLocation, allSkinLocations) { populateSkinList(skinLocation); } m_skins->sort(0); updateRemoveSkinButton(); } void AppearanceSettings::populateSkinList(const QString& installLocation) { QDirIterator it(installLocation, QDir::Dirs | QDir::NoDotAndDotDot); while (it.hasNext()) { const QDir& skinDir(it.next()); if (skinDir.exists(QStringLiteral("title.skin")) && skinDir.exists(QStringLiteral("tabs.skin"))) { QStandardItem* skin = createSkinItem(skinDir.absolutePath()); if (!skin) continue; m_skins->appendRow(skin); if (skin->data(SkinId).toString() == m_selectedSkinId) skinList->setCurrentIndex(skin->index()); } } } QStandardItem* AppearanceSettings::createSkinItem(const QString& skinDir) { QString skinId = skinDir.section(QLatin1Char('/'), -1, -1); QString titleName, tabName, skinName; QString titleAuthor, tabAuthor, skinAuthor; QString titleIcon, tabIcon; QIcon skinIcon; // Check if the skin dir starts with the path where all // KNS3 skins are found in. bool isKnsSkin = skinDir.startsWith(m_knsSkinDir); KConfig titleConfig(skinDir + QStringLiteral("/title.skin"), KConfig::SimpleConfig); KConfigGroup titleDescription = titleConfig.group("Description"); KConfig tabConfig(skinDir + QStringLiteral("/tabs.skin"), KConfig::SimpleConfig); KConfigGroup tabDescription = tabConfig.group("Description"); titleName = titleDescription.readEntry("Skin", ""); titleAuthor = titleDescription.readEntry("Author", ""); titleIcon = skinDir + titleDescription.readEntry("Icon", ""); tabName = tabDescription.readEntry("Skin", ""); tabAuthor = tabDescription.readEntry("Author", ""); tabIcon = skinDir + tabDescription.readEntry("Icon", ""); skinName = titleName.isEmpty() ? tabName : titleName; skinAuthor = titleAuthor.isEmpty() ? tabAuthor : titleAuthor; titleIcon.isEmpty() ? skinIcon.addPixmap(tabIcon) : skinIcon.addPixmap(titleIcon); if (skinName.isEmpty() || skinAuthor.isEmpty()) skinName = skinId; if (skinAuthor.isEmpty()) skinAuthor = xi18nc("@item:inlistbox Unknown skin author", "Unknown"); QStandardItem* skin = new QStandardItem(skinName); skin->setData(skinId, SkinId); skin->setData(skinDir, SkinDir); skin->setData(skinName, SkinName); skin->setData(skinAuthor, SkinAuthor); skin->setData(skinIcon, SkinIcon); skin->setData(isKnsSkin, SkinInstalledWithKns); return skin; } void AppearanceSettings::updateSkinSetting() { QString skinId = skinList->currentIndex().data(SkinId).toString(); if (!skinId.isEmpty()) { m_selectedSkinId = skinId; kcfg_Skin->setText(skinId); kcfg_SkinInstalledWithKns->setChecked(skinList->currentIndex().data(SkinInstalledWithKns).toBool()); } } void AppearanceSettings::resetSelection() { m_selectedSkinId = Settings::skin(); QModelIndexList skins = m_skins->match(m_skins->index(0, 0), SkinId, Settings::skin(), 1, Qt::MatchExactly | Qt::MatchWrap); if (skins.count() > 0) skinList->setCurrentIndex(skins.at(0)); } void AppearanceSettings::installSkin() { QStringList mimeTypes; mimeTypes << QStringLiteral("application/x-compressed-tar"); mimeTypes << QStringLiteral("application/x-xz-compressed-tar"); mimeTypes << QStringLiteral("application/x-bzip-compressed-tar"); mimeTypes << QStringLiteral("application/zip"); mimeTypes << QStringLiteral("application/x-tar"); QFileDialog fileDialog(parentWidget()); fileDialog.setWindowTitle(i18nc("@title:window", "Select the skin archive to install")); fileDialog.setMimeTypeFilters(mimeTypes); fileDialog.setFileMode(QFileDialog::ExistingFile); QUrl skinUrl; if (fileDialog.exec() && !fileDialog.selectedUrls().isEmpty()) skinUrl = fileDialog.selectedUrls().at(0); else return; m_installSkinFile.open(); KIO::CopyJob *job = KIO::copy(skinUrl, QUrl::fromLocalFile(m_installSkinFile.fileName()), KIO::JobFlag::HideProgressInfo | KIO::JobFlag::Overwrite); connect(job, &KIO::CopyJob::result, [=](KJob *job) { if (job->error()) { job->uiDelegate()->showErrorMessage(); job->kill(); cleanupAfterInstall(); return; } installSkin(static_cast(job)->destUrl()); }); } void AppearanceSettings::installSkin(const QUrl& skinUrl) { QUrl skinArchiveUrl = QUrl(skinUrl); skinArchiveUrl.setScheme(QStringLiteral("tar")); KIO::ListJob* job = KIO::listRecursive(skinArchiveUrl, KIO::HideProgressInfo, false); connect(job, &KIO::ListJob::entries, [=](KIO::Job* /* job */, const KIO::UDSEntryList& list) { if (list.isEmpty()) return; QListIterator i(list); while (i.hasNext()) m_installSkinFileList.append(i.next().stringValue(KIO::UDSEntry::UDS_NAME)); }); connect(job, &KIO::ListJob::result, [=](KJob *job) { if (!job->error()) checkForExistingSkin(); else failInstall(xi18nc("@info", "Unable to list the skin archive contents.") + QStringLiteral("\n\n") + job->errorString()); }); } bool AppearanceSettings::validateSkin(const QString& skinId, bool kns) { QString dir = kns ? QStringLiteral("kns_skins/") : QStringLiteral("skins/"); QString titlePath = QStandardPaths::locate(QStandardPaths::DataLocation, dir + skinId + QStringLiteral("/title.skin")); QString tabsPath = QStandardPaths::locate(QStandardPaths::DataLocation, dir + skinId + QStringLiteral("/tabs.skin")); return !titlePath.isEmpty() && !tabsPath.isEmpty(); } void AppearanceSettings::checkForExistingSkin() { m_installSkinId = m_installSkinFileList.at(0); QModelIndexList skins = m_skins->match(m_skins->index(0, 0), SkinId, m_installSkinId, 1, Qt::MatchExactly | Qt::MatchWrap); int exists = skins.count(); foreach (const QModelIndex& skin, skins) { if (m_skins->item(skin.row())->data(SkinInstalledWithKns).toBool()) --exists; } if (exists > 0) { QString skinDir = skins.at(0).data(SkinDir).toString(); QFile skin(skinDir + QStringLiteral("titles.skin")); if (!skin.open(QIODevice::ReadWrite)) { failInstall(xi18nc("@info", "This skin appears to be already installed and you lack the required permissions to overwrite it.")); } else { skin.close(); int remove = KMessageBox::warningContinueCancel(parentWidget(), xi18nc("@info", "This skin appears to be already installed. Do you want to overwrite it?"), xi18nc("@title:window", "Skin Already Exists"), KGuiItem(xi18nc("@action:button", "Reinstall Skin"))); if (remove == KMessageBox::Continue) removeSkin(skinDir, [=](){ installSkinArchive(); }); else cleanupAfterInstall(); } } else installSkinArchive(); } void AppearanceSettings::removeSkin(const QString& skinDir, std::function successCallback) { KIO::DeleteJob* job = KIO::del(QUrl::fromLocalFile(skinDir), KIO::HideProgressInfo); connect(job, &KIO::DeleteJob::result, [=](KJob* deleteJob) { if (deleteJob->error()) { KMessageBox::error(parentWidget(), deleteJob->errorString(), xi18nc("@title:Window", "Could Not Delete Skin")); } else if (successCallback) { successCallback(); } }); } void AppearanceSettings::installSkinArchive() { KTar skinArchive(m_installSkinFile.fileName()); if (skinArchive.open(QIODevice::ReadOnly)) { const KArchiveDirectory* skinDir = skinArchive.directory(); skinDir->copyTo(m_localSkinsDir); skinArchive.close(); if (validateSkin(m_installSkinId, false)) { populateSkinList(); if (Settings::skin() == m_installSkinId) emit settingsChanged(); cleanupAfterInstall(); } else { removeSkin(m_localSkinsDir + m_installSkinId); failInstall(xi18nc("@info", "Unable to locate required files in the skin archive.The archive appears to be invalid.")); } } else failInstall(xi18nc("@info", "The skin archive file could not be opened.")); } void AppearanceSettings::failInstall(const QString& error) { KMessageBox::error(parentWidget(), error, xi18nc("@title:window", "Cannot Install Skin")); cleanupAfterInstall(); } void AppearanceSettings::cleanupAfterInstall() { m_installSkinId.clear(); m_installSkinFileList.clear(); if (m_installSkinFile.exists()) { m_installSkinFile.close(); m_installSkinFile.remove(); } } void AppearanceSettings::updateRemoveSkinButton() { if (m_skins->rowCount() <= 1) { removeButton->setEnabled(false); return; } QString skinDir; QVariant value = skinList->currentIndex().data(SkinDir); if (value.isValid()) skinDir = value.toString(); value = skinList->currentIndex().data(SkinInstalledWithKns); bool isKnsSkin = value.toBool(); // We don't allow the user to remove the default skin // or any skin which was installed through KNS3. if (skinDir.isEmpty() || isKnsSkin) { removeButton->setEnabled(false); return; } QFile titleSkin(skinDir + QStringLiteral("/title.skin")); if (!titleSkin.open(QIODevice::ReadWrite)) removeButton->setEnabled(false); else removeButton->setEnabled(true); titleSkin.close(); } void AppearanceSettings::removeSelectedSkin() { if (m_skins->rowCount() <= 1) return; QString skinDir = skinList->currentIndex().data(SkinDir).toString(); QString skinName = skinList->currentIndex().data(SkinName).toString(); QString skinAuthor = skinList->currentIndex().data(SkinAuthor).toString(); if (skinDir.isEmpty()) return; int remove = KMessageBox::warningContinueCancel(parentWidget(), xi18nc("@info", "Do you want to remove \"%1\" by %2?", skinName, skinAuthor), xi18nc("@title:window", "Remove Skin"), KStandardGuiItem::del()); if (remove == KMessageBox::Continue) removeSkin(skinDir, [=](){ QString skinId = skinList->currentIndex().data(SkinId).toString(); if (skinId == Settings::skin()) { Settings::setSkin(QStringLiteral("default")); Settings::setSkinInstalledWithKns(false); Settings::self()->save(); emit settingsChanged(); } resetSelection(); populateSkinList(); }); } QSet AppearanceSettings::extractKnsSkinIds(const QStringList& fileList) { QSet skinIdList; foreach (const QString& file, fileList) { // We only care about files/directories which are subdirectories of our KNS skins dir. if (file.startsWith(m_knsSkinDir, Qt::CaseInsensitive)) { // Get the relative filename (this removes the KNS install dir from the filename). QString relativeName = QString(file).remove(m_knsSkinDir, Qt::CaseInsensitive); // Get everything before the first slash - that should be our skins ID. QString skinId = relativeName.section(QLatin1Char('/'), 0, 0, QString::SectionSkipEmpty); // Skip all other entries in the file list if we found what we were searching for. if (!skinId.isEmpty()) { // First remove all remaining slashes (as there could be leading or trailing ones). skinId.remove(QStringLiteral("/")); skinIdList.insert(skinId); } } } return skinIdList; } void AppearanceSettings::getNewSkins() { QPointer dialog = new KNS3::DownloadDialog(m_knsConfigFileName, this); // Show the KNS dialog. NOTE: We are NOT supposed to check the dialog's result, // because the actions are asynchronous (items are installed or uninstalled, // regardless whether the dialog's result is Accepted or Rejected)! dialog->exec(); if (dialog.isNull()) { return; } if (!dialog->installedEntries().empty()) { quint32 invalidEntryCount = 0; QString invalidSkinText; foreach (const KNS3::Entry &entry3, dialog->installedEntries()) { KNSCore::EntryInternal entry = KNSCore::EntryInternal::fromEntry(entry3); bool isValid = true; const QSet& skinIdList = extractKnsSkinIds(entry.installedFiles()); // Validate all skin IDs as each archive can contain multiple skins. foreach (const QString& skinId, skinIdList) { // Validate the current skin. if (!validateSkin(skinId, true)) { isValid = false; } } // We'll add an error message for the whole KNS entry if // the current skin is marked as invalid. // We should not do this per skin as the user does not know that // there are more skins inside one archive. if (!isValid) { invalidEntryCount++; // The user needs to know the name of the skin which // was removed. invalidSkinText += QString(QStringLiteral("
  • %1
  • ")).arg(entry.name()); // Then remove the skin. m_knsDownloadManager->uninstallEntry(entry); } } // Are there any invalid entries? if (invalidEntryCount > 0) { failInstall(xi18ncp("@info", "The following skin is missing required files. Thus it was removed:
      %2
    ", "The following skins are missing required files. Thus they were removed:
      %2
    ", invalidEntryCount, invalidSkinText)); } } if (!dialog->changedEntries().isEmpty()) { // Reset the selection in case the currently selected // skin was removed. resetSelection(); // Re-populate the list of skins if the user changed something. populateSkinList(); } delete dialog; } diff --git a/app/config/appearancesettings.h b/app/config/appearancesettings.h index 2fd4937..804af6f 100644 --- a/app/config/appearancesettings.h +++ b/app/config/appearancesettings.h @@ -1,141 +1,141 @@ /* Copyright (C) 2008 by Eike Hein This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor appro- ved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program. If not, see http://www.gnu.org/licenses/. + along with this program. If not, see https://www.gnu.org/licenses/. */ #ifndef APPEARANCESETTINGS_H #define APPEARANCESETTINGS_H #include "ui_appearancesettings.h" #include #include class SkinListDelegate; class QStandardItem; class QStandardItemModel; namespace KNSCore { class DownloadManager; } class AppearanceSettings : public QWidget, private Ui::AppearanceSettings { Q_OBJECT public: explicit AppearanceSettings(QWidget* parent = 0); ~AppearanceSettings(); enum DataRole { SkinId = Qt::UserRole + 1, SkinDir = Qt::UserRole + 2, SkinName = Qt::UserRole + 3, SkinAuthor = Qt::UserRole + 4, SkinIcon = Qt::UserRole + 5, SkinInstalledWithKns = Qt::UserRole + 6 }; public Q_SLOTS: void resetSelection(); Q_SIGNALS: void settingsChanged(); protected: void showEvent(QShowEvent* event) Q_DECL_OVERRIDE; private Q_SLOTS: void populateSkinList(); void updateSkinSetting(); void installSkin(); void installSkinArchive(); /** * Validates the given skin. * This method checks if the fileList of the skin * contains all required files. * * @param skinId The SkinID of the skin which will be validated. * @param kns The skin has been installed from kns. * * @return True if the skin is valid, otherwise false. */ bool validateSkin(const QString &skinId, bool kns); /** * Extracts the skin IDs from the given fileList. * There can be multiple skins, but only one skin per directory. * The files need to be located in the m_knsSkinDir. * * @param fileList All files which were installed. * * @return The list of skin IDs which were extracted from the * given fileList. */ QSet extractKnsSkinIds(const QStringList& fileList); /** * Shows the KNS3 dialog where the user can download new skins. */ void getNewSkins(); void updateRemoveSkinButton(); void removeSelectedSkin(); private: QStandardItem* createSkinItem(const QString& skinDir); void populateSkinList(const QString& installationDirectory); void checkForExistingSkin(); void removeSkin(const QString& skinDir, std::function successCallback = 0); void installSkin(const QUrl& skinUrl); void failInstall(const QString& error); void cleanupAfterInstall(); QString m_selectedSkinId; QStandardItemModel* m_skins; SkinListDelegate* m_skinListDelegate; QString m_localSkinsDir; QString m_knsSkinDir; QString m_installSkinId; QTemporaryFile m_installSkinFile; QStringList m_installSkinFileList; QString m_knsConfigFileName; KNSCore::DownloadManager* m_knsDownloadManager; }; #endif diff --git a/app/config/skinlistdelegate.cpp b/app/config/skinlistdelegate.cpp index d511c10..3693380 100644 --- a/app/config/skinlistdelegate.cpp +++ b/app/config/skinlistdelegate.cpp @@ -1,203 +1,203 @@ /* Copyright (C) 2008 by Eike Hein This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor appro- ved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program. If not, see http://www.gnu.org/licenses/. + along with this program. If not, see https://www.gnu.org/licenses/. */ #include "skinlistdelegate.h" #include "appearancesettings.h" #include #include #include #include #define MARGIN 3 #define ICON 32 #define KNS_ICON_SIZE (ICON / 2) SkinListDelegate::SkinListDelegate(QObject* parent) : QAbstractItemDelegate(parent) { } SkinListDelegate::~SkinListDelegate() { } void SkinListDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex &index) const { painter->save(); paintBackground(painter, option); paintIcon(painter, option, index); paintText(painter, option, index); painter->restore(); } void SkinListDelegate::paintBackground(QPainter* painter, const QStyleOptionViewItem& option) const { QStyleOptionViewItem opt = option; QStyle* style = opt.widget ? opt.widget->style() : QApplication::style(); style->drawPrimitive(QStyle::PE_PanelItemViewItem, &opt, painter, opt.widget); } void SkinListDelegate::paintIcon(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex &index) const { QVariant value; value = index.data(AppearanceSettings::SkinIcon); if (value.isValid() && value.type() == QVariant::Icon) { int x = option.rect.x() + MARGIN; int y = option.rect.y() + (option.rect.height() / 2) - (ICON / 2); if (option.direction == Qt::RightToLeft) x = option.rect.right() - ICON - MARGIN; qvariant_cast(value).paint(painter, x, y, ICON, ICON); } } void SkinListDelegate::paintText(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex &index) const { QFont font = option.font; int initialY = option.rect.y(); int x = option.rect.x() + ICON + (3 * MARGIN); int y = initialY; int textWidth = 0; int width = option.rect.width() - ICON - (3 * MARGIN); if (option.state & QStyle::State_Selected) painter->setPen(option.palette.color(QPalette::HighlightedText)); QVariant value; value = index.data(AppearanceSettings::SkinName); if (value.isValid()) { font.setBold(true); painter->setFont(font); QFontMetrics fontMetrics(font); QRect textRect = fontMetrics.boundingRect(value.toString()); textWidth = textRect.width(); if (option.direction == Qt::RightToLeft) { if (width < textWidth) x = option.rect.x() + MARGIN; else x = option.rect.right() - ICON - (3 * MARGIN) - textWidth; } y += textRect.height(); painter->drawText(x, y, fontMetrics.elidedText(value.toString(), option.textElideMode, width)); value = index.data(AppearanceSettings::SkinInstalledWithKns); if (value.isValid() && value.toBool()) { QIcon ghnsIcon(QStringLiteral("get-hot-new-stuff")); int knsIconX = x; int iconSize = qMin(textRect.height(), KNS_ICON_SIZE); if (option.direction == Qt::RightToLeft) // In RTL mode we have to correct our position // so there's room for the icon and enough space // between the text and the icon. knsIconX -= (iconSize + MARGIN); else // Otherwise we just have to make sure that we // start painting after the text and add some margin. knsIconX += textWidth + MARGIN; ghnsIcon.paint(painter, knsIconX, initialY + MARGIN, iconSize, iconSize); } } value = index.data(AppearanceSettings::SkinAuthor); if (value.isValid()) { QString skinAuthor = xi18nc("@item:intext", "by %1", value.toString()); font.setBold(false); painter->setFont(font); QFontMetrics fontMetrics(font); QRect textRect = fontMetrics.boundingRect(skinAuthor); if (option.direction == Qt::RightToLeft) { if (width < textRect.width()) x = option.rect.x() + MARGIN; else x = option.rect.right() - ICON - (3 * MARGIN) - textRect.width(); } y += textRect.height(); painter->drawText(x, y, fontMetrics.elidedText(skinAuthor, option.textElideMode, width)); } } QSize SkinListDelegate::sizeHint(const QStyleOptionViewItem&option, const QModelIndex& index) const { QFont font = option.font; QRect name, author; int width, height; QVariant value; value = index.data(AppearanceSettings::SkinName); if (value.isValid()) { font.setBold(true); QFontMetrics fontMetrics(font); name = fontMetrics.boundingRect(value.toString()); } value = index.data(Qt::UserRole + 1); if (value.isValid()) { QString skinAuthor = xi18nc("@item:intext", "by %1", value.toString()); font.setBold(false); QFontMetrics fontMetrics(font); author = fontMetrics.boundingRect(skinAuthor); } width = qMax(name.width(), author.width()); QRect textRect(0, 0, width, name.height() + author.height()); width = ICON + (3 * MARGIN) + textRect.width() + MARGIN;; height = qMax(ICON + (2 * MARGIN), textRect.height() + (2 * MARGIN)); return QSize(width, height); } diff --git a/app/config/skinlistdelegate.h b/app/config/skinlistdelegate.h index ac59eab..397ddf1 100644 --- a/app/config/skinlistdelegate.h +++ b/app/config/skinlistdelegate.h @@ -1,45 +1,45 @@ /* Copyright (C) 2008 by Eike Hein This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor appro- ved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program. If not, see http://www.gnu.org/licenses/. + along with this program. If not, see https://www.gnu.org/licenses/. */ #ifndef SKINLISTDELEGATE_H #define SKINLISTDELEGATE_H #include class SkinListDelegate : public QAbstractItemDelegate { public: explicit SkinListDelegate(QObject* parent = 0); ~SkinListDelegate(); void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex &index) const Q_DECL_OVERRIDE; QSize sizeHint (const QStyleOptionViewItem& option, const QModelIndex& index) const Q_DECL_OVERRIDE; private: void paintBackground(QPainter* painter, const QStyleOptionViewItem& option) const; void paintIcon(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex &index) const; void paintText(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex &index) const; }; #endif diff --git a/app/config/windowsettings.cpp b/app/config/windowsettings.cpp index c3d16ad..31372b3 100644 --- a/app/config/windowsettings.cpp +++ b/app/config/windowsettings.cpp @@ -1,97 +1,97 @@ /* Copyright (C) 2008-2009 by Eike Hein This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor appro- ved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program. If not, see http://www.gnu.org/licenses/. + along with this program. If not, see https://www.gnu.org/licenses/. */ #include "windowsettings.h" #include "settings.h" #include #include WindowSettings::WindowSettings(QWidget* parent) : QWidget(parent) { setupUi(this); for (int i = 2; i <= QGuiApplication::screens().count(); i++) kcfg_Screen->insertItem(i, xi18nc("@item:inlistbox", "Screen %1", i)); if (QGuiApplication::screens().count() > 1) { screenLabel->setEnabled(true); kcfg_Screen->setEnabled(true); } connect(kcfg_Width, SIGNAL(valueChanged(int)), this, SLOT(updateWidthSlider(int))); connect(widthSlider, SIGNAL(valueChanged(int)), this, SLOT(updateWidthSpinBox(int))); connect(kcfg_Height, SIGNAL(valueChanged(int)), this, SLOT(updateHeightSlider(int))); connect(heightSlider, SIGNAL(valueChanged(int)), this, SLOT(updateHeightSpinBox(int))); connect(kcfg_Frames, SIGNAL(valueChanged(int)), this, SLOT(updateFramesSpinBox(int))); connect(framesSpinBox, SIGNAL(valueChanged(int)), this, SLOT(updateFramesSlider(int))); connect(kcfg_Position, SIGNAL(valueChanged(int)), this, SLOT(updatePosition(int))); updateFramesSpinBox(Settings::frames() * 10); } WindowSettings::~WindowSettings() { } void WindowSettings::updateWidthSlider(int width) { widthSlider->setValue(width/10); emit updateWindowGeometry(width, kcfg_Height->value(), kcfg_Position->value()); } void WindowSettings::updateWidthSpinBox(int width) { kcfg_Width->setValue(width*10); } void WindowSettings::updateHeightSlider(int height) { heightSlider->setValue(height/10); emit updateWindowGeometry(kcfg_Width->value(), height, kcfg_Position->value()); } void WindowSettings::updateHeightSpinBox(int height) { kcfg_Height->setValue(height*10); } void WindowSettings::updateFramesSlider(int speed) { kcfg_Frames->setValue(speed/10); } void WindowSettings::updateFramesSpinBox(int speed) { framesSpinBox->setValue(speed*10); } void WindowSettings::updatePosition(int position) { emit updateWindowGeometry(kcfg_Width->value(), kcfg_Height->value(), position); } diff --git a/app/config/windowsettings.h b/app/config/windowsettings.h index 586cd33..976fc99 100644 --- a/app/config/windowsettings.h +++ b/app/config/windowsettings.h @@ -1,55 +1,55 @@ /* Copyright (C) 2008 by Eike Hein This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor appro- ved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program. If not, see http://www.gnu.org/licenses/. + along with this program. If not, see https://www.gnu.org/licenses/. */ #ifndef WINDOWSETTINGS_H #define WINDOWSETTINGS_H #include "ui_windowsettings.h" class WindowSettings : public QWidget, private Ui::WindowSettings { Q_OBJECT public: explicit WindowSettings(QWidget* parent = 0); ~WindowSettings(); Q_SIGNALS: void updateWindowGeometry(int width, int height, int position); private Q_SLOTS: void updateWidthSlider(int width); void updateWidthSpinBox(int width); void updateHeightSlider(int height); void updateHeightSpinBox(int height); void updateFramesSlider(int height); void updateFramesSpinBox(int height); void updatePosition(int position); }; #endif diff --git a/app/firstrundialog.cpp b/app/firstrundialog.cpp index b1d4203..6fa48da 100644 --- a/app/firstrundialog.cpp +++ b/app/firstrundialog.cpp @@ -1,98 +1,98 @@ /* Copyright (C) 2008-2009 by Eike Hein This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor appro- ved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program. If not, see http://www.gnu.org/licenses/. + along with this program. If not, see https://www.gnu.org/licenses/. */ #include "firstrundialog.h" #include "mainwindow.h" #include "ui_firstrundialog.h" #include #include #include #include #include FirstRunDialog::FirstRunDialog(MainWindow* mainWindow) : QDialog(mainWindow) { m_mainWindow = mainWindow; setWindowTitle(xi18nc("@title:window", "First Run")); QVBoxLayout *mainLayout = new QVBoxLayout; setLayout(mainLayout); QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel); QPushButton *okButton = buttonBox->button(QDialogButtonBox::Ok); okButton->setDefault(true); okButton->setShortcut(Qt::CTRL | Qt::Key_Return); connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); QWidget* widget = new QWidget(this); mainLayout->addWidget(widget); mainLayout->addWidget(buttonBox); m_ui = new Ui::FirstRunDialog(); m_ui->setupUi(widget); m_ui->titleWidget->setPixmap(QIcon::fromTheme(QStringLiteral("yakuake")).pixmap(22, 22)); widget->setMinimumSize(widget->sizeHint()); initKeyButton(); connect(m_ui->keyButton, SIGNAL(keySequenceChanged(QKeySequence)), this, SLOT(validateKeySequence(QKeySequence))); } FirstRunDialog::~FirstRunDialog() { } void FirstRunDialog::initKeyButton() { m_ui->keyButton->setMultiKeyShortcutsAllowed(false); m_ui->keyButton->blockSignals(true); QAction* action = static_cast(m_mainWindow->actionCollection()->action(QStringLiteral("toggle-window-state"))); m_keySequence = KGlobalAccel::self()->shortcut(action).first(); m_ui->keyButton->setKeySequence(m_keySequence); m_ui->keyButton->blockSignals(false); } void FirstRunDialog::validateKeySequence(const QKeySequence& keySequence) { if (!KGlobalAccel::isGlobalShortcutAvailable(keySequence)) { bool steal = KGlobalAccel::promptStealShortcutSystemwide(this, KGlobalAccel::getGlobalShortcutsByKey(keySequence), keySequence); if (!steal) initKeyButton(); else { KGlobalAccel::stealShortcutSystemwide(keySequence); m_keySequence = m_ui->keyButton->keySequence(); } } else m_keySequence = m_ui->keyButton->keySequence(); } diff --git a/app/firstrundialog.h b/app/firstrundialog.h index 8de1598..cadee14 100644 --- a/app/firstrundialog.h +++ b/app/firstrundialog.h @@ -1,57 +1,57 @@ /* Copyright (C) 2008 by Eike Hein This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor appro- ved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program. If not, see http://www.gnu.org/licenses/. + along with this program. If not, see https://www.gnu.org/licenses/. */ #ifndef FIRSTRUNDIALOG_H #define FIRSTRUNDIALOG_H #include class MainWindow; class Ui_FirstRunDialog; class FirstRunDialog : public QDialog { Q_OBJECT public: explicit FirstRunDialog(MainWindow* mainWindow); ~FirstRunDialog(); QKeySequence keySequence() { return m_keySequence; } private Q_SLOTS: void validateKeySequence(const QKeySequence& keySequence); private: void initKeyButton(); Ui_FirstRunDialog* m_ui; MainWindow* m_mainWindow; QKeySequence m_keySequence; }; #endif diff --git a/app/main.cpp b/app/main.cpp index e6ca2f7..4c5b7b7 100644 --- a/app/main.cpp +++ b/app/main.cpp @@ -1,89 +1,89 @@ /* Copyright (C) 2008-2014 by Eike Hein This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor appro- ved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program. If not, see http://www.gnu.org/licenses/. + along with this program. If not, see https://www.gnu.org/licenses/. */ #include "mainwindow.h" #include #include #include #include #include #include int main (int argc, char *argv[]) { QApplication app(argc, argv); app.setQuitOnLastWindowClosed(false); KLocalizedString::setApplicationDomain("yakuake"); KAboutData aboutData(QStringLiteral("yakuake"), xi18nc("@title", "Yakuake"), QStringLiteral("3.0.5+"), xi18nc("@title", "A drop-down terminal emulator based on KDE Konsole technology."), KAboutLicense::GPL, xi18nc("@info:credit", "(c) 2008-2018 The Yakuake Team"), QString(), - QStringLiteral("http://yakuake.kde.org/")); + QStringLiteral("https://kde.org/applications/system/org.kde.yakuake")); aboutData.setOrganizationDomain(QByteArray("kde.org")); aboutData.setProductName(QByteArray("yakuake")); aboutData.addAuthor(xi18nc("@info:credit", "Eike Hein"), xi18nc("@info:credit", "Maintainer, Lead Developer"), QStringLiteral("hein@kde.org")); aboutData.addAuthor(xi18nc("@info:credit", "Francois Chazal"), xi18nc("@info:credit", "Project Founder, Legacy skin (Inactive)")); aboutData.addCredit(xi18nc("@info:credit", "Daniel 'suslik' D."), xi18nc("@info:credit", "Plastik skin"), QStringLiteral("dd@accentsolution.com")); aboutData.addCredit(xi18nc("@info:credit", "Juan Carlos Torres"), xi18nc("@info:credit", "Tab bar drag and drop support, Prevent Closing toggle"), QStringLiteral("carlosdgtorres@gmail.com")); aboutData.addCredit(xi18nc("@info:credit", "Gustavo Ribeiro Croscato"), xi18nc("@info:credit", "Icon on tabs with Prevent Closing enabled"), QStringLiteral("croscato@gmail.com")); aboutData.addCredit(xi18nc("@info:credit", "Danilo Cesar Lemes de Paula"), xi18nc("@info:credit", "Actions to grow terminals"), QStringLiteral("danilo.eu@gmail.com")); aboutData.setTranslator(i18nc("NAME OF TRANSLATORS", "Your names"), i18nc("EMAIL OF TRANSLATORS", "Your emails")); KAboutData::setApplicationData(aboutData); QCommandLineParser parser; parser.addHelpOption(); parser.addVersionOption(); aboutData.setupCommandLine(&parser); parser.process(app); aboutData.processCommandLine(&parser); app.setApplicationName(aboutData.componentName()); app.setApplicationDisplayName(aboutData.displayName()); app.setOrganizationDomain(aboutData.organizationDomain()); app.setApplicationVersion(aboutData.version()); app.setWindowIcon(QIcon::fromTheme(QStringLiteral("yakuake"))); KDBusService service(KDBusService::Unique); KCrash::initialize(); MainWindow mainWindow; mainWindow.hide(); QObject::connect(&service, SIGNAL(activateRequested(QStringList,QString)), &mainWindow, SLOT(toggleWindowState())); return app.exec(); } diff --git a/app/mainwindow.cpp b/app/mainwindow.cpp index 7a58bb8..4d9811b 100644 --- a/app/mainwindow.cpp +++ b/app/mainwindow.cpp @@ -1,1558 +1,1558 @@ /* Copyright (C) 2008-2014 by Eike Hein Copyright (C) 2009 by Juan Carlos Torres This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor appro- ved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program. If not, see http://www.gnu.org/licenses/. + along with this program. If not, see https://www.gnu.org/licenses/. */ #include "mainwindow.h" #include "settings.h" #include "config/appearancesettings.h" #include "config/windowsettings.h" #include "firstrundialog.h" #include "sessionstack.h" #include "skin.h" #include "tabbar.h" #include "terminal.h" #include "titlebar.h" #include "ui_behaviorsettings.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if HAVE_X11 #include #include #include #endif #if HAVE_KWAYLAND #include #include #include #include #endif MainWindow::MainWindow(QWidget* parent) : KMainWindow(parent, Qt::CustomizeWindowHint | Qt::FramelessWindowHint) { QDBusConnection::sessionBus().registerObject(QStringLiteral("/yakuake/window"), this, QDBusConnection::ExportScriptableSlots); setAttribute(Qt::WA_TranslucentBackground, true); setAttribute(Qt::WA_DeleteOnClose, false); setAttribute(Qt::WA_QuitOnClose, true); m_skin = new Skin(); m_menu = new QMenu(this); m_helpMenu = new KHelpMenu(this, KAboutData::applicationData()); m_sessionStack = new SessionStack(this); m_titleBar = new TitleBar(this); m_tabBar = new TabBar(this); m_firstRunDialog = NULL; m_isFullscreen = false; #if HAVE_X11 m_kwinAssistPropSet = false; m_isX11 = KWindowSystem::isPlatformX11(); #else m_isX11 = false; #endif m_isWayland = KWindowSystem::isPlatformWayland(); #if HAVE_KWAYLAND m_plasmaShell = Q_NULLPTR; m_plasmaShellSurface = Q_NULLPTR; initWayland(); #endif m_toggleLock = false; setupActions(); setupMenu(); connect(m_tabBar, SIGNAL(newTabRequested()), m_sessionStack, SLOT(addSession())); connect(m_tabBar, SIGNAL(lastTabClosed()), m_tabBar, SIGNAL(newTabRequested())); connect(m_tabBar, SIGNAL(lastTabClosed()), this, SLOT(handleLastTabClosed())); connect(m_tabBar, SIGNAL(tabSelected(int)), m_sessionStack, SLOT(raiseSession(int))); connect(m_tabBar, SIGNAL(tabClosed(int)), m_sessionStack, SLOT(removeSession(int))); connect(m_tabBar, SIGNAL(requestTerminalHighlight(int)), m_sessionStack, SLOT(handleTerminalHighlightRequest(int))); connect(m_tabBar, SIGNAL(requestRemoveTerminalHighlight()), m_sessionStack, SIGNAL(removeTerminalHighlight())); connect(m_tabBar, SIGNAL(tabContextMenuClosed()), m_sessionStack, SIGNAL(removeTerminalHighlight())); connect(m_sessionStack, SIGNAL(sessionAdded(int,QString)), m_tabBar, SLOT(addTab(int,QString))); connect(m_sessionStack, SIGNAL(sessionRaised(int)), m_tabBar, SLOT(selectTab(int))); connect(m_sessionStack, SIGNAL(sessionRemoved(int)), m_tabBar, SLOT(removeTab(int))); connect(m_sessionStack, SIGNAL(activeTitleChanged(QString)), m_titleBar, SLOT(setTitle(QString))); connect(m_sessionStack, SIGNAL(activeTitleChanged(QString)), this, SLOT(setWindowTitle(QString))); connect(&m_mousePoller, SIGNAL(timeout()), this, SLOT(pollMouse())); connect(KWindowSystem::self(), SIGNAL(workAreaChanged()), this, SLOT(applyWindowGeometry())); connect(QApplication::desktop(), SIGNAL(screenCountChanged(int)), this, SLOT(updateScreenMenu())); applySettings(); m_sessionStack->addSession(); if (Settings::firstRun()) { QMetaObject::invokeMethod(this, "toggleWindowState", Qt::QueuedConnection); QMetaObject::invokeMethod(this, "showFirstRunDialog", Qt::QueuedConnection); } else { showStartupPopup(); if (Settings::pollMouse()) toggleMousePoll(true); } if (Settings::openAfterStart()) QMetaObject::invokeMethod(this, "toggleWindowState", Qt::QueuedConnection); } MainWindow::~MainWindow() { Settings::self()->save(); delete m_skin; } #if HAVE_KWAYLAND void MainWindow::initWayland() { if (!m_isWayland) { return; } using namespace KWayland::Client; auto connection = ConnectionThread::fromApplication(this); if (!connection) { return; } Registry *registry = new Registry(this); registry->create(connection); QObject::connect(registry, &Registry::interfacesAnnounced, this, [registry, this] { const auto interface = registry->interface(Registry::Interface::PlasmaShell); if (interface.name != 0) { m_plasmaShell = registry->createPlasmaShell(interface.name, interface.version, this); } } ); registry->setup(); connection->roundtrip(); } void MainWindow::initWaylandSurface() { if (m_plasmaShellSurface) { return; } if (!m_plasmaShell) { return; } if (auto surface = KWayland::Client::Surface::fromWindow(windowHandle())) { m_plasmaShellSurface = m_plasmaShell->createSurface(surface, this); m_plasmaShellSurface->setPosition(pos()); } } #endif bool MainWindow::queryClose() { bool confirmQuit = Settings::confirmQuit(); bool hasUnclosableSessions = m_sessionStack->hasUnclosableSessions(); QString closeQuestion = xi18nc("@info","Are you sure you want to quit?"); QString warningMessage; if ((confirmQuit && m_sessionStack->count() > 1) || hasUnclosableSessions) { if (confirmQuit && m_sessionStack->count() > 1) { if (hasUnclosableSessions) warningMessage = xi18nc("@info", "There are multiple open sessions, some of which you have locked to prevent closing them accidentally. These will be killed if you continue."); else warningMessage = xi18nc("@info", "There are multiple open sessions. These will be killed if you continue."); } else if (hasUnclosableSessions) { warningMessage = xi18nc("@info", "There are one or more open sessions that you have locked to prevent closing them accidentally. These will be killed if you continue."); } int result = KMessageBox::warningContinueCancel(this, warningMessage + QStringLiteral("

    ") + closeQuestion, xi18nc("@title:window", "Really Quit?"), KStandardGuiItem::quit(), KStandardGuiItem::cancel()); return result != KMessageBox::Cancel; } return true; } void MainWindow::setupActions() { m_actionCollection = new KActionCollection(this); KToggleFullScreenAction* fullScreenAction = new KToggleFullScreenAction(this); fullScreenAction->setWindow(this); actionCollection()->setDefaultShortcut(fullScreenAction, QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_F11)); m_actionCollection->addAction(QStringLiteral("view-full-screen"), fullScreenAction); connect(fullScreenAction, SIGNAL(toggled(bool)), this, SLOT(setFullScreen(bool))); QAction* action = KStandardAction::quit(this, SLOT(close()), actionCollection()); actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_Q)); action = KStandardAction::aboutApp(m_helpMenu, SLOT(aboutApplication()), actionCollection()); action = KStandardAction::reportBug(m_helpMenu, SLOT(reportBug()), actionCollection()); action = KStandardAction::aboutKDE(m_helpMenu, SLOT(aboutKDE()), actionCollection()); action = KStandardAction::keyBindings(this, SLOT(configureKeys()), actionCollection()); action = KStandardAction::configureNotifications(this, SLOT(configureNotifications()), actionCollection()); action = KStandardAction::preferences(this, SLOT(configureApp()), actionCollection()); action = KStandardAction::whatsThis(this, SLOT(whatsThis()), actionCollection()); action = actionCollection()->addAction(QStringLiteral("toggle-window-state")); action->setText(xi18nc("@action", "Open/Retract Yakuake")); action->setIcon(QIcon::fromTheme(QStringLiteral("yakuake"))); #ifndef Q_OS_WIN /* PORT */ KGlobalAccel::self()->setGlobalShortcut(action, QList() << QKeySequence(Qt::Key_F12)); #else KGlobalAccel::self()->setGlobalShortcut(action, QList() << QKeySequence(Qt::Key_F11)); #endif connect(action, SIGNAL(triggered()), this, SLOT(toggleWindowState())); action = actionCollection()->addAction(QStringLiteral("keep-open")); action->setText(xi18nc("@action", "Keep window open when it loses focus")); action->setCheckable(true); connect(action, SIGNAL(toggled(bool)), this, SLOT(setKeepOpen(bool))); action = actionCollection()->addAction(QStringLiteral("manage-profiles")); action->setText(xi18nc("@action", "Manage Profiles...")); action->setIcon(QIcon::fromTheme(QStringLiteral("configure"))); connect(action, SIGNAL(triggered()), m_sessionStack, SIGNAL(manageProfiles())); action = actionCollection()->addAction(QStringLiteral("edit-profile")); action->setText(xi18nc("@action", "Edit Current Profile...")); action->setIcon(QIcon::fromTheme(QStringLiteral("document-properties"))); connect(action, SIGNAL(triggered()), this, SLOT(handleContextDependentAction())); m_contextDependentActions << action; action = actionCollection()->addAction(QStringLiteral("increase-window-width")); action->setText(xi18nc("@action", "Increase Window Width")); actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::ALT + Qt::SHIFT + Qt::Key_Right)); connect(action, SIGNAL(triggered()), this, SLOT(increaseWindowWidth())); action = actionCollection()->addAction(QStringLiteral("decrease-window-width")); action->setText(xi18nc("@action", "Decrease Window Width")); actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::ALT + Qt::SHIFT + Qt::Key_Left)); connect(action, SIGNAL(triggered()), this, SLOT(decreaseWindowWidth())); action = actionCollection()->addAction(QStringLiteral("increase-window-height")); action->setText(xi18nc("@action", "Increase Window Height")); actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::ALT + Qt::SHIFT + Qt::Key_Down)); connect(action, SIGNAL(triggered()), this, SLOT(increaseWindowHeight())); action = actionCollection()->addAction(QStringLiteral("decrease-window-height")); action->setText(xi18nc("@action", "Decrease Window Height")); actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::ALT + Qt::SHIFT + Qt::Key_Up)); connect(action, SIGNAL(triggered()), this, SLOT(decreaseWindowHeight())); action = actionCollection()->addAction(QStringLiteral("new-session")); action->setText(xi18nc("@action", "New Session")); action->setIcon(QIcon::fromTheme(QStringLiteral("tab-new"))); actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_T)); connect(action, SIGNAL(triggered()), m_sessionStack, SLOT(addSession())); action = actionCollection()->addAction(QStringLiteral("new-session-two-horizontal")); action->setText(xi18nc("@action", "Two Terminals, Horizontally")); action->setIcon(QIcon::fromTheme(QStringLiteral("tab-new"))); connect(action, SIGNAL(triggered()), m_sessionStack, SLOT(addSessionTwoHorizontal())); action = actionCollection()->addAction(QStringLiteral("new-session-two-vertical")); action->setText(xi18nc("@action", "Two Terminals, Vertically")); action->setIcon(QIcon::fromTheme(QStringLiteral("tab-new"))); connect(action, SIGNAL(triggered()), m_sessionStack, SLOT(addSessionTwoVertical())); action = actionCollection()->addAction(QStringLiteral("new-session-quad")); action->setText(xi18nc("@action", "Four Terminals, Grid")); action->setIcon(QIcon::fromTheme(QStringLiteral("tab-new"))); connect(action, SIGNAL(triggered()), m_sessionStack, SLOT(addSessionQuad())); action = actionCollection()->addAction(QStringLiteral("close-session")); action->setText(xi18nc("@action", "Close Session")); action->setIcon(QIcon::fromTheme(QStringLiteral("tab-close"))); actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_W)); connect(action, SIGNAL(triggered()), this, SLOT(handleContextDependentAction())); m_contextDependentActions << action; action = actionCollection()->addAction(QStringLiteral("previous-session")); action->setText(xi18nc("@action", "Previous Session")); action->setIcon(QIcon::fromTheme(QStringLiteral("go-previous"))); actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::SHIFT + Qt::Key_Left)); connect(action, SIGNAL(triggered()), m_tabBar, SLOT(selectPreviousTab())); action = actionCollection()->addAction(QStringLiteral("next-session")); action->setText(xi18nc("@action", "Next Session")); action->setIcon(QIcon::fromTheme(QStringLiteral("go-next"))); actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::SHIFT + Qt::Key_Right)); connect(action, SIGNAL(triggered()), m_tabBar, SLOT(selectNextTab())); action = actionCollection()->addAction(QStringLiteral("move-session-left")); action->setText(xi18nc("@action", "Move Session Left")); action->setIcon(QIcon::fromTheme(QStringLiteral("arrow-left"))); actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_Left)); connect(action, SIGNAL(triggered()), this, SLOT(handleContextDependentAction())); m_contextDependentActions << action; action = actionCollection()->addAction(QStringLiteral("move-session-right")); action->setText(xi18nc("@action", "Move Session Right")); action->setIcon(QIcon::fromTheme(QStringLiteral("arrow-right"))); actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_Right)); connect(action, SIGNAL(triggered()), this, SLOT(handleContextDependentAction())); m_contextDependentActions << action; action = actionCollection()->addAction(QStringLiteral("grow-terminal-right")); action->setText(xi18nc("@action", "Grow Terminal to the Right")); action->setIcon(QIcon::fromTheme(QStringLiteral("arrow-right"))); actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::CTRL + Qt::ALT + Qt::Key_Right)); connect(action, SIGNAL(triggered()), this, SLOT(handleContextDependentAction())); m_contextDependentActions << action; action = actionCollection()->addAction(QStringLiteral("grow-terminal-left")); action->setText(xi18nc("@action", "Grow Terminal to the Left")); action->setIcon(QIcon::fromTheme(QStringLiteral("arrow-left"))); actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::CTRL + Qt::ALT + Qt::Key_Left)); connect(action, SIGNAL(triggered()), this, SLOT(handleContextDependentAction())); m_contextDependentActions << action; action = actionCollection()->addAction(QStringLiteral("grow-terminal-top")); action->setText(xi18nc("@action", "Grow Terminal to the Top")); action->setIcon(QIcon::fromTheme(QStringLiteral("arrow-up"))); actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::CTRL + Qt::ALT + Qt::Key_Up)); connect(action, SIGNAL(triggered()), this, SLOT(handleContextDependentAction())); m_contextDependentActions << action; action = actionCollection()->addAction(QStringLiteral("grow-terminal-bottom")); action->setText(xi18nc("@action", "Grow Terminal to the Bottom")); action->setIcon(QIcon::fromTheme(QStringLiteral("arrow-down"))); actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::CTRL + Qt::ALT + Qt::Key_Down)); connect(action, SIGNAL(triggered()), this, SLOT(handleContextDependentAction())); m_contextDependentActions << action; action = actionCollection()->addAction(QStringLiteral("rename-session")); action->setText(xi18nc("@action", "Rename Session...")); action->setIcon(QIcon::fromTheme(QStringLiteral("edit-rename"))); actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::CTRL + Qt::ALT + Qt::Key_S)); connect(action, SIGNAL(triggered()), this, SLOT(handleContextDependentAction())); m_contextDependentActions << action; action = actionCollection()->addAction(QStringLiteral("previous-terminal")); action->setText(xi18nc("@action", "Previous Terminal")); action->setIcon(QIcon::fromTheme(QStringLiteral("go-previous"))); actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_Up)); connect(action, SIGNAL(triggered()), m_sessionStack, SIGNAL(previousTerminal())); action = actionCollection()->addAction(QStringLiteral("next-terminal")); action->setText(xi18nc("@action", "Next Terminal")); action->setIcon(QIcon::fromTheme(QStringLiteral("go-next"))); actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_Down)); connect(action, SIGNAL(triggered()), m_sessionStack, SIGNAL(nextTerminal())); action = actionCollection()->addAction(QStringLiteral("close-active-terminal")); action->setText(xi18nc("@action", "Close Active Terminal")); action->setIcon(QIcon::fromTheme(QStringLiteral("view-close"))); actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_R)); connect(action, SIGNAL(triggered()), this, SLOT(handleContextDependentAction())); m_contextDependentActions << action; action = actionCollection()->addAction(QStringLiteral("split-left-right")); action->setText(xi18nc("@action", "Split Left/Right")); action->setIcon(QIcon::fromTheme(QStringLiteral("view-split-left-right"))); actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::CTRL+ Qt::Key_ParenLeft)); connect(action, SIGNAL(triggered()), this, SLOT(handleContextDependentAction())); m_contextDependentActions << action; action = actionCollection()->addAction(QStringLiteral("split-top-bottom")); action->setText(xi18nc("@action", "Split Top/Bottom")); action->setIcon(QIcon::fromTheme(QStringLiteral("view-split-top-bottom"))); actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::CTRL + Qt::Key_ParenRight)); connect(action, SIGNAL(triggered()), this, SLOT(handleContextDependentAction())); m_contextDependentActions << action; action = actionCollection()->addAction(QStringLiteral("toggle-session-prevent-closing")); action->setText(xi18nc("@action", "Prevent Closing")); action->setCheckable(true); connect(action, SIGNAL(triggered(bool)), this, SLOT(handleContextDependentToggleAction(bool))); m_contextDependentActions << action; action = actionCollection()->addAction(QStringLiteral("toggle-session-keyboard-input")); action->setText(xi18nc("@action", "Disable Keyboard Input")); action->setCheckable(true); connect(action, SIGNAL(triggered(bool)), this, SLOT(handleContextDependentToggleAction(bool))); m_contextDependentActions << action; action = actionCollection()->addAction(QStringLiteral("toggle-session-monitor-activity")); action->setText(xi18nc("@action", "Monitor for Activity")); actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_A)); action->setCheckable(true); connect(action, SIGNAL(triggered(bool)), this, SLOT(handleContextDependentToggleAction(bool))); m_contextDependentActions << action; action = actionCollection()->addAction(QStringLiteral("toggle-session-monitor-silence")); action->setText(xi18nc("@action", "Monitor for Silence")); actionCollection()->setDefaultShortcut(action, QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_I)); action->setCheckable(true); connect(action, SIGNAL(triggered(bool)), this, SLOT(handleContextDependentToggleAction(bool))); m_contextDependentActions << action; for (uint i = 1; i <= 10; ++i) { action = actionCollection()->addAction(QString(QStringLiteral("switch-to-session-%1")).arg(i)); action->setText(xi18nc("@action", "Switch to Session %1", i)); action->setData(i); connect(action, SIGNAL(triggered()), this, SLOT(handleSwitchToAction())); } m_actionCollection->associateWidget(this); m_actionCollection->readSettings(); } void MainWindow::handleContextDependentAction(QAction* action, int sessionId) { if (sessionId == -1) sessionId = m_sessionStack->activeSessionId(); if (sessionId == -1) return; if (!action) action = qobject_cast(QObject::sender()); if (action == actionCollection()->action(QStringLiteral("edit-profile"))) m_sessionStack->editProfile(sessionId); if (action == actionCollection()->action(QStringLiteral("close-session"))) m_sessionStack->removeSession(sessionId); if (action == actionCollection()->action(QStringLiteral("move-session-left"))) m_tabBar->moveTabLeft(sessionId); if (action == actionCollection()->action(QStringLiteral("move-session-right"))) m_tabBar->moveTabRight(sessionId); if (action == actionCollection()->action(QStringLiteral("rename-session"))) m_tabBar->interactiveRename(sessionId); if (action == actionCollection()->action(QStringLiteral("close-active-terminal"))) m_sessionStack->closeActiveTerminal(sessionId); if (action == actionCollection()->action(QStringLiteral("split-left-right"))) m_sessionStack->splitSessionLeftRight(sessionId); if (action == actionCollection()->action(QStringLiteral("split-top-bottom"))) m_sessionStack->splitSessionTopBottom(sessionId); if (action == actionCollection()->action(QStringLiteral("grow-terminal-right"))) m_sessionStack->tryGrowTerminalRight(m_sessionStack->activeTerminalId()); if (action == actionCollection()->action(QStringLiteral("grow-terminal-left"))) m_sessionStack->tryGrowTerminalLeft(m_sessionStack->activeTerminalId()); if (action == actionCollection()->action(QStringLiteral("grow-terminal-top"))) m_sessionStack->tryGrowTerminalTop(m_sessionStack->activeTerminalId()); if (action == actionCollection()->action(QStringLiteral("grow-terminal-bottom"))) m_sessionStack->tryGrowTerminalBottom(m_sessionStack->activeTerminalId()); } void MainWindow::handleContextDependentToggleAction(bool checked, QAction* action, int sessionId) { if (sessionId == -1) sessionId = m_sessionStack->activeSessionId(); if (sessionId == -1) return; if (!action) action = qobject_cast(QObject::sender()); if (action == actionCollection()->action(QStringLiteral("toggle-session-prevent-closing"))) { m_sessionStack->setSessionClosable(sessionId, !checked); // Repaint the tab bar when the Prevent Closing action is toggled // so the lock icon is added to or removed from the tab label. m_tabBar->repaint(); } if (action == actionCollection()->action(QStringLiteral("toggle-session-keyboard-input"))) m_sessionStack->setSessionKeyboardInputEnabled(sessionId, !checked); if (action == actionCollection()->action(QStringLiteral("toggle-session-monitor-activity"))) m_sessionStack->setSessionMonitorActivityEnabled(sessionId, checked); if (action == actionCollection()->action(QStringLiteral("toggle-session-monitor-silence"))) m_sessionStack->setSessionMonitorSilenceEnabled(sessionId, checked); } void MainWindow::setContextDependentActionsQuiet(bool quiet) { QListIterator i(m_contextDependentActions); while (i.hasNext()) i.next()->blockSignals(quiet); } void MainWindow::handleToggleTerminalKeyboardInput(bool checked) { QAction* action = qobject_cast(QObject::sender()); if (!action || action->data().isNull()) return; bool ok = false; int terminalId = action->data().toInt(&ok); if (!ok) return; m_sessionStack->setTerminalKeyboardInputEnabled(terminalId, !checked); } void MainWindow::handleToggleTerminalMonitorActivity(bool checked) { QAction* action = qobject_cast(QObject::sender()); if (!action || action->data().isNull()) return; bool ok = false; int terminalId = action->data().toInt(&ok); if (!ok) return; m_sessionStack->setTerminalMonitorActivityEnabled(terminalId, checked); } void MainWindow::handleToggleTerminalMonitorSilence(bool checked) { QAction* action = qobject_cast(QObject::sender()); if (!action || action->data().isNull()) return; bool ok = false; int terminalId = action->data().toInt(&ok); if (!ok) return; m_sessionStack->setTerminalMonitorSilenceEnabled(terminalId, checked); } void MainWindow::handleTerminalActivity(Terminal* terminal) { Session* session = qobject_cast(sender()); if (session) { disconnect(terminal, SIGNAL(activityDetected(Terminal*)), session, SIGNAL(activityDetected(Terminal*))); QString message(xi18nc("@info", "Activity detected in monitored terminal in session \"%1\".", m_tabBar->tabTitle(session->id()))); KNotification::event(QLatin1String("activity"), message, QPixmap(), terminal->partWidget(), KNotification::CloseWhenWidgetActivated); } } void MainWindow::handleTerminalSilence(Terminal* terminal) { Session* session = qobject_cast(sender()); if (session) { QString message(xi18nc("@info", "Silence detected in monitored terminal in session \"%1\".", m_tabBar->tabTitle(session->id()))); KNotification::event(QLatin1String("silence"), message, QPixmap(), terminal->partWidget(), KNotification::CloseWhenWidgetActivated); } } void MainWindow::handleLastTabClosed() { if (isVisible() && !Settings::keepOpenAfterLastSessionCloses()) toggleWindowState(); } void MainWindow::handleSwitchToAction() { QAction* action = qobject_cast(QObject::sender()); if (action && !action->data().isNull()) m_sessionStack->raiseSession(m_tabBar->sessionAtTab(action->data().toInt()-1)); } void MainWindow::setupMenu() { m_menu->insertSection(0, xi18nc("@title:menu", "Help")); m_menu->addAction(actionCollection()->action(QLatin1String(KStandardAction::name(KStandardAction::WhatsThis)))); m_menu->addAction(actionCollection()->action(QLatin1String(KStandardAction::name(KStandardAction::ReportBug)))); m_menu->addAction(actionCollection()->action(QLatin1String(KStandardAction::name(KStandardAction::AboutApp)))); m_menu->addAction(actionCollection()->action(QLatin1String(KStandardAction::name(KStandardAction::AboutKDE)))); m_menu->insertSection(0, xi18nc("@title:menu", "Quick Options")); m_menu->addAction(actionCollection()->action(QStringLiteral("view-full-screen"))); m_menu->addAction(actionCollection()->action(QStringLiteral("keep-open"))); m_screenMenu = new QMenu(this); connect(m_screenMenu, SIGNAL(triggered(QAction*)), this, SLOT(setScreen(QAction*))); m_screenMenu->setTitle(xi18nc("@title:menu", "Screen")); m_menu->addMenu(m_screenMenu); m_windowWidthMenu = new QMenu(this); connect(m_windowWidthMenu, SIGNAL(triggered(QAction*)), this, SLOT(setWindowWidth(QAction*))); m_windowWidthMenu->setTitle(xi18nc("@title:menu", "Width")); m_menu->addMenu(m_windowWidthMenu); m_windowHeightMenu = new QMenu(this); connect(m_windowHeightMenu, SIGNAL(triggered(QAction*)), this, SLOT(setWindowHeight(QAction*))); m_windowHeightMenu->setTitle(xi18nc("@title:menu", "Height")); m_menu->addMenu(m_windowHeightMenu); m_menu->insertSection(0, xi18nc("@title:menu", "Settings")); m_menu->addAction(actionCollection()->action(QStringLiteral("manage-profiles"))); m_menu->addAction(actionCollection()->action(QLatin1String(KStandardAction::name(KStandardAction::KeyBindings)))); m_menu->addAction(actionCollection()->action(QLatin1String(KStandardAction::name(KStandardAction::ConfigureNotifications)))); m_menu->addAction(actionCollection()->action(QLatin1String(KStandardAction::name(KStandardAction::Preferences)))); m_menu->addSeparator(); m_menu->addAction(actionCollection()->action(QLatin1String(KStandardAction::name(KStandardAction::Quit)))); } void MainWindow::updateScreenMenu() { QAction* action; m_screenMenu->clear(); action = m_screenMenu->addAction(xi18nc("@item:inmenu", "At mouse location")); action->setCheckable(true); action->setData(0); action->setChecked(Settings::screen() == 0); for (int i = 1; i <= QGuiApplication::screens().count(); i++) { action = m_screenMenu->addAction(xi18nc("@item:inmenu", "Screen %1", i)); action->setCheckable(true); action->setData(i); action->setChecked(i == Settings::screen()); } action = m_screenMenu->menuAction(); action->setVisible(QGuiApplication::screens().count() > 1); } void MainWindow::updateWindowSizeMenus() { updateWindowWidthMenu(); updateWindowHeightMenu(); } void MainWindow::updateWindowWidthMenu() { QAction* action = 0; if (m_windowWidthMenu->isEmpty()) { for (int i = 10; i <= 100; i += 10) { action = m_windowWidthMenu->addAction(QString::number(i) + QStringLiteral("%")); action->setCheckable(true); action->setData(i); action->setChecked(i == Settings::width()); } } else { QListIterator i(m_windowWidthMenu->actions()); while (i.hasNext()) { action = i.next(); action->setChecked(action->data().toInt() == Settings::width()); } } } void MainWindow::updateWindowHeightMenu() { QAction* action = 0; if (m_windowHeightMenu->isEmpty()) { for (int i = 10; i <= 100; i += 10) { action = m_windowHeightMenu->addAction(QString::number(i) + QStringLiteral("%")); action->setCheckable(true); action->setData(i); action->setChecked(i == Settings::height()); } } else { QListIterator i(m_windowHeightMenu->actions()); while (i.hasNext()) { action = i.next(); action->setChecked(action->data().toInt() == Settings::height()); } } } void MainWindow::configureKeys() { KShortcutsDialog::configure(actionCollection()); } void MainWindow::configureNotifications() { KNotifyConfigWidget::configure(this); } void MainWindow::configureApp() { if (KConfigDialog::showDialog(QStringLiteral("settings"))) return; KConfigDialog* settingsDialog = new KConfigDialog(this, QStringLiteral("settings"), Settings::self()); settingsDialog->setMinimumHeight(560); settingsDialog->setFaceType(KPageDialog::List); connect(settingsDialog, &KConfigDialog::settingsChanged, this, &MainWindow::applySettings); WindowSettings* windowSettings = new WindowSettings(settingsDialog); settingsDialog->addPage(windowSettings, xi18nc("@title Preferences page name", "Window"), QStringLiteral("preferences-system-windows-move")); connect(windowSettings, SIGNAL(updateWindowGeometry(int,int,int)), this, SLOT(setWindowGeometry(int,int,int))); QWidget* behaviorSettings = new QWidget(settingsDialog); Ui::BehaviorSettings behaviorSettingsUi; behaviorSettingsUi.setupUi(behaviorSettings); settingsDialog->addPage(behaviorSettings, xi18nc("@title Preferences page name", "Behavior"), QStringLiteral("preferences-system-windows-actions")); AppearanceSettings* appearanceSettings = new AppearanceSettings(settingsDialog); settingsDialog->addPage(appearanceSettings, xi18nc("@title Preferences page name", "Appearance"), QStringLiteral("preferences-desktop-theme")); connect(settingsDialog, &QDialog::rejected, appearanceSettings, &AppearanceSettings::resetSelection); settingsDialog->button(QDialogButtonBox::Help)->hide(); settingsDialog->button(QDialogButtonBox::Cancel)->setFocus(); connect(settingsDialog, &QDialog::finished, [=]() { m_toggleLock = true; KWindowSystem::activateWindow(winId()); KWindowSystem::forceActiveWindow(winId()); }); settingsDialog->show(); } void MainWindow::applySettings() { if (Settings::dynamicTabTitles()) { connect(m_sessionStack, SIGNAL(titleChanged(int,QString)), m_tabBar, SLOT(setTabTitle(int,QString))); m_sessionStack->emitTitles(); } else { disconnect(m_sessionStack, SIGNAL(titleChanged(int,QString)), m_tabBar, SLOT(setTabTitle(int,QString))); } m_animationTimer.setInterval(Settings::frames() ? 10 : 0); m_tabBar->setVisible(Settings::showTabBar()); setKeepOpen(Settings::keepOpen()); updateScreenMenu(); updateWindowSizeMenus(); updateUseTranslucency(); applySkin(); applyWindowGeometry(); applyWindowProperties(); } void MainWindow::applySkin() { bool gotSkin = m_skin->load(Settings::skin(), Settings::skinInstalledWithKns()); if (!gotSkin) { Settings::setSkin(QStringLiteral("default")); gotSkin = m_skin->load(Settings::skin()); } if (!gotSkin) { KMessageBox::error(parentWidget(), xi18nc("@info", "Yakuake was unable to load a skin. It is likely that it was installed incorrectly." "The application will now quit."), xi18nc("@title:window", "Cannot Load Skin")); QMetaObject::invokeMethod(qApp, "quit", Qt::QueuedConnection); } m_titleBar->applySkin(); m_tabBar->applySkin(); } void MainWindow::applyWindowProperties() { if (Settings::keepOpen() && !Settings::keepAbove()) { KWindowSystem::clearState(winId(), NET::KeepAbove); KWindowSystem::setState(winId(), NET::Sticky | NET::SkipTaskbar | NET::SkipPager); } else KWindowSystem::setState(winId(), NET::KeepAbove | NET::Sticky | NET::SkipTaskbar | NET::SkipPager); KWindowSystem::setOnAllDesktops(winId(), Settings::showOnAllDesktops()); KWindowEffects::enableBlurBehind(winId(), Settings::blur()); } void MainWindow::applyWindowGeometry() { int width, height; QAction* action = actionCollection()->action(QStringLiteral("view-full-screen")); if (action->isChecked()) { width = 100; height = 100; } else { width = Settings::width(); height = Settings::height(); } setWindowGeometry(width, height, Settings::position()); } void MainWindow::setWindowGeometry(int newWidth, int newHeight, int newPosition) { QRect workArea = getDesktopGeometry(); int maxHeight = workArea.height() * newHeight / 100; int targetWidth = workArea.width() * newWidth / 100; setGeometry(workArea.x() + workArea.width() * newPosition * (100 - newWidth) / 10000, workArea.y(), targetWidth, maxHeight); #if HAVE_KWAYLAND initWaylandSurface(); #endif maxHeight -= m_titleBar->height(); m_titleBar->setGeometry(0, maxHeight, targetWidth, m_titleBar->height()); if (!isVisible()) m_titleBar->updateMask(); if (Settings::frames() > 0) m_animationStepSize = maxHeight / Settings::frames(); else m_animationStepSize = maxHeight; if (Settings::showTabBar()) { if (m_skin->tabBarCompact()) { m_tabBar->setGeometry(m_skin->tabBarLeft(), maxHeight, width() - m_skin->tabBarLeft() - m_skin->tabBarRight(), m_tabBar->height()); } else { maxHeight -= m_tabBar->height(); m_tabBar->setGeometry(m_skin->borderWidth(), maxHeight, width() - 2 * m_skin->borderWidth(), m_tabBar->height()); } } m_sessionStack->setGeometry(m_skin->borderWidth(), 0, width() - 2 * m_skin->borderWidth(), maxHeight); updateMask(); } void MainWindow::setScreen(QAction* action) { Settings::setScreen(action->data().toInt()); Settings::self()->save(); applyWindowGeometry(); updateScreenMenu(); } void MainWindow::setWindowWidth(int width) { Settings::setWidth(width); Settings::self()->save(); applyWindowGeometry(); updateWindowWidthMenu(); } void MainWindow::setWindowHeight(int height) { Settings::setHeight(height); Settings::self()->save(); applyWindowGeometry(); updateWindowHeightMenu(); } void MainWindow::setWindowWidth(QAction* action) { setWindowWidth(action->data().toInt()); } void MainWindow::setWindowHeight(QAction* action) { setWindowHeight(action->data().toInt()); } void MainWindow::increaseWindowWidth() { if (Settings::width() <= 90) setWindowWidth(Settings::width() + 10); } void MainWindow:: decreaseWindowWidth() { if (Settings::width() >= 20) setWindowWidth(Settings::width() - 10); } void MainWindow::increaseWindowHeight() { if (Settings::height() <= 90) setWindowHeight(Settings::height() + 10); } void MainWindow::decreaseWindowHeight() { if (Settings::height() >= 20) setWindowHeight(Settings::height() - 10); } void MainWindow::updateMask() { QRegion region = m_titleBar->mask(); region.translate(0, m_titleBar->y()); region += QRegion(0, 0, width(), m_titleBar->y()); setMask(region); } void MainWindow::paintEvent(QPaintEvent* event) { QPainter painter(this); if (useTranslucency()) { painter.setOpacity(qreal(Settings::backgroundColorOpacity()) / 100); painter.fillRect(rect(), Settings::backgroundColor()); painter.setOpacity(1.0); } else painter.fillRect(rect(), Settings::backgroundColor()); QRect leftBorder(0, 0, m_skin->borderWidth(), height() - m_titleBar->height()); painter.fillRect(leftBorder, m_skin->borderColor()); QRect rightBorder(width() - m_skin->borderWidth(), 0, m_skin->borderWidth(), height() - m_titleBar->height()); painter.fillRect(rightBorder, m_skin->borderColor()); KMainWindow::paintEvent(event); } void MainWindow::moveEvent(QMoveEvent* event) { if (Settings::screen() && QApplication::desktop()->screenNumber(this) != getScreen()) { Settings::setScreen(QApplication::desktop()->screenNumber(this)+1); updateScreenMenu(); applyWindowGeometry(); } KMainWindow::moveEvent(event); } void MainWindow::closeEvent(QCloseEvent *event) { KMainWindow::closeEvent(event); if (event->isAccepted()) { QApplication::quit(); } } void MainWindow::wmActiveWindowChanged() { if (m_toggleLock) { m_toggleLock = false; return; } KWindowInfo info(KWindowSystem::activeWindow(), 0, NET::WM2TransientFor); if (info.valid() && info.transientFor() == winId()) { return; } if (m_isX11) { if (!Settings::keepOpen() && isVisible() && KWindowSystem::activeWindow() != winId()) { toggleWindowState(); } } else { if (!Settings::keepOpen() && hasFocus()) { toggleWindowState(); } } } void MainWindow::changeEvent(QEvent* event) { if (event->type() == QEvent::WindowStateChange && (windowState() & Qt::WindowMaximized) && Settings::width() != 100 && Settings::height() != 100) { Settings::setWidth(100); Settings::setHeight(100); applyWindowGeometry(); updateWindowWidthMenu(); updateWindowHeightMenu(); } KMainWindow::changeEvent(event); } bool MainWindow::event(QEvent* event) { if (event->type() == QEvent::Expose) { // FIXME TODO: We can remove this once we depend on Qt 5.6.1+. // See: https://bugreports.qt.io/browse/QTBUG-26978 applyWindowProperties(); #if (QT_VERSION > QT_VERSION_CHECK(5, 5, 0)) } else if (event->type() == QEvent::PlatformSurface) { const QPlatformSurfaceEvent *pSEvent = static_cast(event); if (pSEvent->surfaceEventType() == QPlatformSurfaceEvent::SurfaceCreated) { applyWindowProperties(); } #endif } return KMainWindow::event(event); } void MainWindow::toggleWindowState() { bool visible = isVisible(); if (visible && KWindowSystem::activeWindow() != winId() && Settings::keepOpen()) { // Window is open but doesn't have focus; it's set to stay open // regardless of focus loss. if (Settings::toggleToFocus()) { // The open/retract action is set to focus the window when it's // open but lacks focus. The following will cause it to receive // focus, and in an environment with multiple virtual desktops // will also cause the window manager to switch to the virtual // desktop the window resides on. KWindowSystem::activateWindow(winId()); KWindowSystem::forceActiveWindow(winId()); return; } else if (!Settings::showOnAllDesktops() && KWindowInfo(winId(), NET::WMDesktop).desktop() != KWindowSystem::currentDesktop()) { // The open/restrict action isn't set to focus the window, but // the window is currently on another virtual desktop (the option // to show it on all of them is disabled), so closing it doesn't // make sense and we're opting to show it instead to avoid // requiring the user to invoke the action twice to get to see // Yakuake. Just forcing focus would cause the window manager to // switch to the virtual desktop the window currently resides on, // so move the window to the current desktop before doing so. KWindowSystem::setOnDesktop(winId(), KWindowSystem::currentDesktop()); KWindowSystem::activateWindow(winId()); KWindowSystem::forceActiveWindow(winId()); return; } } #if HAVE_X11 if (!Settings::useWMAssist() && m_kwinAssistPropSet) kwinAssistPropCleanup(); if (m_isX11 && Settings::useWMAssist() && KWindowSystem::compositingActive()) kwinAssistToggleWindowState(visible); else #endif if (!m_isWayland) { xshapeToggleWindowState(visible); } else { if (visible) { sharedPreHideWindow(); hide(); sharedAfterHideWindow(); } else { sharedPreOpenWindow(); if (KWindowEffects::isEffectAvailable(KWindowEffects::Slide)) { KWindowEffects::slideWindow(this, KWindowEffects::TopEdge); } show(); sharedAfterOpenWindow(); } } } #if HAVE_X11 void MainWindow::kwinAssistToggleWindowState(bool visible) { bool gotEffect = false; Display* display = QX11Info::display(); Atom atom = XInternAtom(display, "_KDE_SLIDE", false); int count; Atom* list = XListProperties(display, DefaultRootWindow(display), &count); if (list != NULL) { gotEffect = (std::find(list, list + count, atom) != list + count); XFree(list); } if (gotEffect) { Atom atom = XInternAtom(display, "_KDE_SLIDE", false); if (Settings::frames() > 0) { QVarLengthArray data(4); data[0] = 0; data[1] = 1; data[2] = Settings::frames() * 10; data[3] = Settings::frames() * 10; XChangeProperty(display, winId(), atom, atom, 32, PropModeReplace, reinterpret_cast(data.data()), data.size()); m_kwinAssistPropSet = true; } else XDeleteProperty(display, winId(), atom); if (visible) { sharedPreHideWindow(); hide(); sharedAfterHideWindow(); } else { sharedPreOpenWindow(); show(); sharedAfterOpenWindow(); } return; } // Fall back to legacy animation strategy if kwin doesn't have the // effect loaded. xshapeToggleWindowState(visible); } void MainWindow::kwinAssistPropCleanup() { if (!QX11Info::isPlatformX11()) return; Display* display = QX11Info::display(); Atom atom = XInternAtom(display, "_KDE_SLIDE", false); XDeleteProperty(display, winId(), atom); m_kwinAssistPropSet = false; } #endif void MainWindow::xshapeToggleWindowState(bool visible) { if (m_animationTimer.isActive()) return; if (visible) { sharedPreHideWindow(); m_animationFrame = Settings::frames(); connect(&m_animationTimer, SIGNAL(timeout()), this, SLOT(xshapeRetractWindow())); m_animationTimer.start(); } else { m_animationFrame = 0; connect(&m_animationTimer, SIGNAL(timeout()), this, SLOT(xshapeOpenWindow())); m_animationTimer.start(); } } void MainWindow::xshapeOpenWindow() { if (m_animationFrame == 0) { sharedPreOpenWindow(); show(); sharedAfterOpenWindow(); } if (m_animationFrame == Settings::frames()) { m_animationTimer.stop(); m_animationTimer.disconnect(); m_titleBar->move(0, height() - m_titleBar->height()); updateMask(); } else { int maskHeight = m_animationStepSize * m_animationFrame; QRegion newMask = m_titleBar->mask(); newMask.translate(0, maskHeight); newMask += QRegion(0, 0, width(), maskHeight); m_titleBar->move(0, maskHeight); setMask(newMask); m_animationFrame++; } } void MainWindow::xshapeRetractWindow() { if (m_animationFrame == 0) { m_animationTimer.stop(); m_animationTimer.disconnect(); hide(); sharedAfterHideWindow(); } else { m_titleBar->move(0,m_titleBar->y() - m_animationStepSize); setMask(QRegion(mask()).translated(0, -m_animationStepSize)); --m_animationFrame; } } void MainWindow::sharedPreOpenWindow() { applyWindowGeometry(); updateUseTranslucency(); if (Settings::pollMouse()) toggleMousePoll(false); if (Settings::rememberFullscreen()) setFullScreen(m_isFullscreen); } void MainWindow::sharedAfterOpenWindow() { if (!Settings::firstRun()) KWindowSystem::forceActiveWindow(winId()); connect(KWindowSystem::self(), &KWindowSystem::activeWindowChanged, this, &MainWindow::wmActiveWindowChanged); applyWindowProperties(); #if HAVE_KWAYLAND initWaylandSurface(); #endif emit windowOpened(); } void MainWindow::sharedPreHideWindow() { disconnect(KWindowSystem::self(), &KWindowSystem::activeWindowChanged, this, &MainWindow::wmActiveWindowChanged); } void MainWindow::sharedAfterHideWindow() { if (Settings::pollMouse()) toggleMousePoll(true); #if HAVE_KWAYLAND delete m_plasmaShellSurface; m_plasmaShellSurface = Q_NULLPTR; #endif emit windowClosed(); } void MainWindow::activate() { KWindowSystem::activateWindow(winId()); } void MainWindow::toggleMousePoll(bool poll) { if (poll) m_mousePoller.start(Settings::pollInterval()); else m_mousePoller.stop(); } void MainWindow::pollMouse() { QPoint pos = QCursor::pos(); QRect workArea = getDesktopGeometry(); int windowX = workArea.x() + workArea.width() * Settings::position() * (100 - Settings::width()) / 10000; int windowWidth = workArea.width() * Settings::width() / 100; if (pos.y() == 0 && pos.x() >= windowX && pos.x() <= (windowX + windowWidth)) toggleWindowState(); } void MainWindow::setKeepOpen(bool keepOpen) { if (Settings::keepOpen() != keepOpen) { Settings::setKeepOpen(keepOpen); Settings::self()->save(); applyWindowProperties(); } actionCollection()->action(QStringLiteral("keep-open"))->setChecked(keepOpen); m_titleBar->setFocusButtonState(keepOpen); } void MainWindow::setFullScreen(bool state) { if (isVisible()) m_isFullscreen = state; if (state) { setWindowState(windowState() | Qt::WindowFullScreen); setWindowGeometry(100, 100, Settings::position()); } else { setWindowState(windowState() & ~Qt::WindowFullScreen); setWindowGeometry(Settings::width(), Settings::height(), Settings::position()); } } int MainWindow::getScreen() { if (!Settings::screen()) return QApplication::desktop()->screenNumber(QCursor::pos()); else return Settings::screen() - 1; } QRect MainWindow::getDesktopGeometry() { QRect screenGeometry = QApplication::desktop()->screenGeometry(getScreen()); QAction* action = actionCollection()->action(QStringLiteral("view-full-screen")); if (action->isChecked()) return screenGeometry; if (m_isWayland) { // on Wayland it's not possible to get the work area return screenGeometry; } if (QGuiApplication::screens().count() > 1) { const QList allWindows = KWindowSystem::windows(); QList offScreenWindows; QListIterator i(allWindows); while (i.hasNext()) { WId windowId = i.next(); if (KWindowSystem::hasWId(windowId)) { KWindowInfo windowInfo = KWindowInfo(windowId, NET::WMDesktop, NET::WM2ExtendedStrut); // If windowInfo is valid and the window is located at the same (current) // desktop with the yakuake window... if (windowInfo.valid() && windowInfo.isOnCurrentDesktop()) { NETExtendedStrut strut = windowInfo.extendedStrut(); // Get the area covered by each strut. QRect topStrut(strut.top_start, 0, strut.top_end - strut.top_start, strut.top_width); QRect bottomStrut(strut.bottom_start, screenGeometry.bottom() - strut.bottom_width, strut.bottom_end - strut.bottom_start, strut.bottom_width); QRect leftStrut(0, strut.left_width, strut.left_start, strut.left_end - strut.left_start); QRect rightStrut(screenGeometry.right() - strut.right_width, strut.right_start, strut.right_end - strut.right_start, strut.right_width); // If the window has no strut, no need to bother further. if (topStrut.isEmpty() && bottomStrut.isEmpty() && leftStrut.isEmpty() && rightStrut.isEmpty()) continue; // If any of the strut intersects with our screen geometry, it will be correctly handled // by workArea(). if (topStrut.intersects(screenGeometry) || bottomStrut.intersects(screenGeometry) || leftStrut.intersects(screenGeometry) || rightStrut.intersects(screenGeometry)) continue; // This window has a strut on the same desktop as us but which does not cover our screen // geometry. It should be ignored, otherwise the returned work area will wrongly include // the strut. offScreenWindows << windowId; } } } return KWindowSystem::workArea(offScreenWindows).intersected(screenGeometry); } return KWindowSystem::workArea(); } void MainWindow::whatsThis() { QWhatsThis::enterWhatsThisMode(); } void MainWindow::showStartupPopup() { QAction* action = static_cast(actionCollection()->action(QStringLiteral("toggle-window-state"))); const QList &shortcuts = KGlobalAccel::self()->shortcut(action); if (shortcuts.isEmpty()) return; QString shortcut(shortcuts.first().toString(QKeySequence::NativeText)); QString message(xi18nc("@info", "Application successfully started." "Press %1 to use it ...", shortcut)); KNotification::event(QLatin1String("startup"), message, QPixmap(), this); } void MainWindow::showFirstRunDialog() { if (!m_firstRunDialog) { m_firstRunDialog = new FirstRunDialog(this); connect(m_firstRunDialog, &QDialog::finished, this, &MainWindow::firstRunDialogFinished); connect(m_firstRunDialog, &QDialog::accepted, this, &MainWindow::firstRunDialogOk); } m_firstRunDialog->show(); } void MainWindow::firstRunDialogFinished() { Settings::setFirstRun(false); Settings::self()->save(); m_firstRunDialog->deleteLater(); KWindowSystem::forceActiveWindow(winId()); } void MainWindow::firstRunDialogOk() { QAction* action = static_cast(actionCollection()->action(QStringLiteral("toggle-window-state"))); KGlobalAccel::self()->setShortcut(action, QList() << m_firstRunDialog->keySequence(), KGlobalAccel::NoAutoloading); actionCollection()->writeSettings(); } void MainWindow::updateUseTranslucency() { m_useTranslucency = (Settings::translucency() && KWindowSystem::compositingActive()); } diff --git a/app/mainwindow.h b/app/mainwindow.h index 8a00d38..b6edc8a 100644 --- a/app/mainwindow.h +++ b/app/mainwindow.h @@ -1,215 +1,215 @@ /* Copyright (C) 2008-2014 by Eike Hein Copyright (C) 2009 by Juan Carlos Torres This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor appro- ved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program. If not, see http://www.gnu.org/licenses/. + along with this program. If not, see https://www.gnu.org/licenses/. */ #ifndef MAINWINDOW_H #define MAINWINDOW_H #include #include #include class FirstRunDialog; class SessionStack; class Skin; class TabBar; class Terminal; class TitleBar; class KHelpMenu; class KActionCollection; #if HAVE_KWAYLAND namespace KWayland { namespace Client { class PlasmaShell; class PlasmaShellSurface; } } #endif class MainWindow : public KMainWindow { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "org.kde.yakuake") public: explicit MainWindow(QWidget* parent = 0); ~MainWindow(); KActionCollection* actionCollection() { return m_actionCollection; } SessionStack* sessionStack() { return m_sessionStack; } Skin* skin() { return m_skin; } QMenu* menu() { return m_menu; } bool useTranslucency() { return m_useTranslucency; } void setContextDependentActionsQuiet(bool quiet); public Q_SLOTS: Q_SCRIPTABLE void toggleWindowState(); void handleContextDependentAction(QAction* action = 0, int sessionId = -1); void handleContextDependentToggleAction(bool checked, QAction* action = 0, int sessionId = -1); void handleToggleTerminalKeyboardInput(bool checked); void handleToggleTerminalMonitorActivity(bool checked); void handleToggleTerminalMonitorSilence(bool checked); void handleTerminalActivity(Terminal* terminal); void handleTerminalSilence(Terminal* terminal); void handleLastTabClosed(); Q_SIGNALS: void windowOpened(); void windowClosed(); protected: void paintEvent(QPaintEvent*) override; void moveEvent(QMoveEvent*) override; void changeEvent(QEvent* event) override; void closeEvent(QCloseEvent *event) override; bool event(QEvent* event) override; virtual bool queryClose() override; private Q_SLOTS: void applySettings(); void applySkin(); void applyWindowProperties(); void applyWindowGeometry(); void setWindowGeometry(int width, int height, int position); void updateScreenMenu(); void setScreen(QAction* action); void setWindowWidth(int width); void setWindowHeight(int height); void setWindowWidth(QAction* action); void setWindowHeight(QAction* action); void increaseWindowWidth(); void decreaseWindowWidth(); void increaseWindowHeight(); void decreaseWindowHeight(); void wmActiveWindowChanged(); void xshapeOpenWindow(); void xshapeRetractWindow(); void activate(); void toggleMousePoll(bool poll); void pollMouse(); void setKeepOpen(bool keepOpen); void setFullScreen(bool state); void handleSwitchToAction(); void whatsThis(); void configureKeys(); void configureNotifications(); void configureApp(); void showFirstRunDialog(); void firstRunDialogFinished(); void firstRunDialogOk(); private: void setupActions(); void setupMenu(); void updateWindowSizeMenus(); void updateWindowHeightMenu(); void updateWindowWidthMenu(); #if HAVE_X11 void kwinAssistToggleWindowState(bool visible); void kwinAssistPropCleanup(); bool m_kwinAssistPropSet; #endif void xshapeToggleWindowState(bool visible); void sharedPreOpenWindow(); void sharedAfterOpenWindow(); void sharedPreHideWindow(); void sharedAfterHideWindow(); void updateMask(); int getScreen(); QRect getDesktopGeometry(); void showStartupPopup(); void updateUseTranslucency(); bool m_useTranslucency; bool m_isFullscreen; KActionCollection* m_actionCollection; QList m_contextDependentActions; Skin* m_skin; TitleBar* m_titleBar; TabBar* m_tabBar; SessionStack* m_sessionStack; QMenu* m_menu; KHelpMenu* m_helpMenu; QMenu* m_screenMenu; QMenu* m_windowWidthMenu; QMenu* m_windowHeightMenu; FirstRunDialog* m_firstRunDialog; QTimer m_animationTimer; QTimer m_mousePoller; int m_animationFrame; int m_animationStepSize; bool m_toggleLock; bool m_isX11; bool m_isWayland; #if HAVE_KWAYLAND void initWayland(); void initWaylandSurface(); KWayland::Client::PlasmaShell *m_plasmaShell; KWayland::Client::PlasmaShellSurface *m_plasmaShellSurface; #endif }; #endif diff --git a/app/session.cpp b/app/session.cpp index d2e1d22..806f705 100644 --- a/app/session.cpp +++ b/app/session.cpp @@ -1,654 +1,654 @@ /* Copyright (C) 2008-2014 by Eike Hein Copyright (C) 2009 by Juan Carlos Torres This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor appro- ved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program. If not, see http://www.gnu.org/licenses/. + along with this program. If not, see https://www.gnu.org/licenses/. */ #include "session.h" #include "terminal.h" int Session::m_availableSessionId = 0; Session::Session(SessionType type, QWidget* parent) : QObject(parent) { m_sessionId = m_availableSessionId; m_availableSessionId++; m_activeTerminalId = -1; m_closable = true; m_baseSplitter = new Splitter(Qt::Horizontal, parent); connect(m_baseSplitter, SIGNAL(destroyed()), this, SLOT(prepareShutdown())); setupSession(type); } Session::~Session() { if (m_baseSplitter) delete m_baseSplitter; emit destroyed(m_sessionId); } void Session::setupSession(SessionType type) { switch (type) { case Single: { Terminal* terminal = addTerminal(m_baseSplitter); setActiveTerminal(terminal->id()); break; } case TwoHorizontal: { int splitterWidth = m_baseSplitter->width(); Terminal* terminal = addTerminal(m_baseSplitter); addTerminal(m_baseSplitter); QList newSplitterSizes; newSplitterSizes << (splitterWidth / 2) << (splitterWidth / 2); m_baseSplitter->setSizes(newSplitterSizes); QWidget* terminalWidget = terminal->terminalWidget(); if (terminalWidget) { terminalWidget->setFocus(); setActiveTerminal(terminal->id()); } break; } case TwoVertical: { m_baseSplitter->setOrientation(Qt::Vertical); int splitterHeight = m_baseSplitter->height(); Terminal* terminal = addTerminal(m_baseSplitter); addTerminal(m_baseSplitter); QList newSplitterSizes; newSplitterSizes << (splitterHeight / 2) << (splitterHeight / 2); m_baseSplitter->setSizes(newSplitterSizes); QWidget* terminalWidget = terminal->terminalWidget(); if (terminalWidget) { terminalWidget->setFocus(); setActiveTerminal(terminal->id()); } break; } case Quad: { int splitterWidth = m_baseSplitter->width(); int splitterHeight = m_baseSplitter->height(); m_baseSplitter->setOrientation(Qt::Vertical); Splitter* upperSplitter = new Splitter(Qt::Horizontal, m_baseSplitter); connect(upperSplitter, SIGNAL(destroyed()), this, SLOT(cleanup())); Splitter* lowerSplitter = new Splitter(Qt::Horizontal, m_baseSplitter); connect(lowerSplitter, SIGNAL(destroyed()), this, SLOT(cleanup())); Terminal* terminal = addTerminal(upperSplitter); addTerminal(upperSplitter); addTerminal(lowerSplitter); addTerminal(lowerSplitter); QList newSplitterSizes; newSplitterSizes << (splitterHeight / 2) << (splitterHeight / 2); m_baseSplitter->setSizes(newSplitterSizes); newSplitterSizes.clear(); newSplitterSizes << (splitterWidth / 2) << (splitterWidth / 2); upperSplitter->setSizes(newSplitterSizes); lowerSplitter->setSizes(newSplitterSizes); QWidget* terminalWidget = terminal->terminalWidget(); if (terminalWidget) { terminalWidget->setFocus(); setActiveTerminal(terminal->id()); } break; } default: { addTerminal(m_baseSplitter); break; } } } Terminal* Session::addTerminal(QWidget* parent) { Terminal* terminal = new Terminal(parent); connect(terminal, SIGNAL(activated(int)), this, SLOT(setActiveTerminal(int))); connect(terminal, SIGNAL(manuallyActivated(Terminal*)), this, SIGNAL(terminalManuallyActivated(Terminal*))); connect(terminal, SIGNAL(titleChanged(int,QString)), this, SLOT(setTitle(int,QString))); connect(terminal, SIGNAL(keyboardInputBlocked(Terminal*)), this, SIGNAL(keyboardInputBlocked(Terminal*))); connect(terminal, SIGNAL(silenceDetected(Terminal*)), this, SIGNAL(silenceDetected(Terminal*))); connect(terminal, SIGNAL(destroyed(int)), this, SLOT(cleanup(int))); m_terminals.insert(terminal->id(), terminal); QWidget* terminalWidget = terminal->terminalWidget(); if (terminalWidget) terminalWidget->setFocus(); return terminal; } void Session::closeTerminal(int terminalId) { if (terminalId == -1) terminalId = m_activeTerminalId; if (terminalId == -1) return; if (!m_terminals.contains(terminalId)) return; m_terminals.value(terminalId)->deletePart(); } void Session::focusPreviousTerminal() { if (m_activeTerminalId == -1) return; if (!m_terminals.contains(m_activeTerminalId)) return; QMapIterator it(m_terminals); it.toBack(); while (it.hasPrevious()) { it.previous(); if (it.key() == m_activeTerminalId) { if (it.hasPrevious()) { QWidget* terminalWidget = it.peekPrevious().value()->terminalWidget(); if (terminalWidget) terminalWidget->setFocus(); } else { it.toBack(); QWidget* terminalWidget = it.peekPrevious().value()->terminalWidget(); if (terminalWidget) terminalWidget->setFocus(); } break; } } } void Session::focusNextTerminal() { if (m_activeTerminalId == -1) return; if (!m_terminals.contains(m_activeTerminalId)) return; QMapIterator it(m_terminals); while (it.hasNext()) { it.next(); if (it.key() == m_activeTerminalId) { if (it.hasNext()) { QWidget* terminalWidget = it.peekNext().value()->terminalWidget(); if (terminalWidget) terminalWidget->setFocus(); } else { it.toFront(); QWidget* terminalWidget = it.peekNext().value()->terminalWidget(); if (terminalWidget) terminalWidget->setFocus(); } break; } } } int Session::splitLeftRight(int terminalId) { if (terminalId == -1) terminalId = m_activeTerminalId; if (terminalId == -1) return -1; if (!m_terminals.contains(terminalId)) return -1; Terminal* terminal = m_terminals.value(terminalId); if (terminal) return split(terminal, Qt::Horizontal); else return -1; } int Session::splitTopBottom(int terminalId) { if (terminalId == -1) terminalId = m_activeTerminalId; if (terminalId == -1) return -1; if (!m_terminals.contains(terminalId)) return -1; Terminal* terminal = m_terminals.value(terminalId); if (terminal) return split(terminal, Qt::Vertical); else return -1; } int Session::split(Terminal* terminal, Qt::Orientation orientation) { Splitter* splitter = static_cast(terminal->splitter()); if (splitter->count() == 1) { int splitterWidth = splitter->width(); if (splitter->orientation() != orientation) splitter->setOrientation(orientation); terminal = addTerminal(splitter); QList newSplitterSizes; newSplitterSizes << (splitterWidth / 2) << (splitterWidth / 2); splitter->setSizes(newSplitterSizes); QWidget* partWidget = terminal->partWidget(); if (partWidget) partWidget->show(); m_activeTerminalId = terminal->id(); } else { QList splitterSizes = splitter->sizes(); Splitter* newSplitter = new Splitter(orientation, splitter); connect(newSplitter, SIGNAL(destroyed()), this, SLOT(cleanup())); if (splitter->indexOf(terminal->partWidget()) == 0) splitter->insertWidget(0, newSplitter); QWidget* partWidget = terminal->partWidget(); if (partWidget) partWidget->setParent(newSplitter); terminal->setSplitter(newSplitter); terminal = addTerminal(newSplitter); splitter->setSizes(splitterSizes); QList newSplitterSizes; newSplitterSizes << (splitterSizes[1] / 2) << (splitterSizes[1] / 2); newSplitter->setSizes(newSplitterSizes); newSplitter->show(); partWidget = terminal->partWidget(); if (partWidget) partWidget->show(); m_activeTerminalId = terminal->id(); } return m_activeTerminalId; } int Session::tryGrowTerminal(int terminalId, GrowthDirection direction, uint pixels) { Terminal* terminal = getTerminal(terminalId); Splitter* splitter = static_cast(terminal->splitter()); QWidget* child = terminal->partWidget(); while (splitter) { bool isHorizontal = (direction == Right || direction == Left); bool isForward = (direction == Down || direction == Right); // Detecting correct orientation. if ((splitter->orientation() == Qt::Horizontal && isHorizontal) || (splitter->orientation() == Qt::Vertical && !isHorizontal)) { int currentPos = splitter->indexOf(child); if (currentPos != -1 // Next/Prev movable element detection. && (currentPos != 0 || isForward) && (currentPos != splitter->count() - 1 || !isForward)) { QList currentSizes = splitter->sizes(); int oldSize = currentSizes[currentPos]; int affected = isForward ? currentPos + 1: currentPos -1; currentSizes[currentPos] += pixels; currentSizes[affected] -= pixels; splitter->setSizes(currentSizes); return splitter->sizes()[currentPos] - oldSize; } } // Try with a higher level. child = splitter; splitter = static_cast(splitter->parentWidget()); } return -1; } void Session::setActiveTerminal(int terminalId) { m_activeTerminalId = terminalId; setTitle(m_activeTerminalId, m_terminals.value(m_activeTerminalId)->title()); } void Session::setTitle(int terminalId, const QString& title) { if (terminalId == m_activeTerminalId) { m_title = title; emit titleChanged(m_title); emit titleChanged(m_sessionId, m_title); } } void Session::cleanup(int terminalId) { if (m_activeTerminalId == terminalId && m_terminals.count() > 1) focusPreviousTerminal(); m_terminals.remove(terminalId); cleanup(); } void Session::cleanup() { if (!m_baseSplitter) return; m_baseSplitter->recursiveCleanup(); if (m_terminals.isEmpty()) m_baseSplitter->deleteLater(); } void Session::prepareShutdown() { m_baseSplitter = NULL; deleteLater(); } const QString Session::terminalIdList() { QList keyList = m_terminals.uniqueKeys(); QStringList idList; QListIterator i(keyList); while (i.hasNext()) idList << QString::number(i.next()); return idList.join(QLatin1Char(',')); } bool Session::hasTerminal(int terminalId) { return m_terminals.contains(terminalId); } Terminal* Session::getTerminal(int terminalId) { if (!m_terminals.contains(terminalId)) return 0; return m_terminals.value(terminalId); } void Session::runCommand(const QString& command, int terminalId) { if (terminalId == -1) terminalId = m_activeTerminalId; if (terminalId == -1) return; if (!m_terminals.contains(terminalId)) return; m_terminals.value(terminalId)->runCommand(command); } void Session::manageProfiles() { if ( m_activeTerminalId == -1) return; if (!m_terminals.contains(m_activeTerminalId)) return; m_terminals.value(m_activeTerminalId)->manageProfiles(); } void Session::editProfile() { if ( m_activeTerminalId == -1) return; if (!m_terminals.contains(m_activeTerminalId)) return; m_terminals.value(m_activeTerminalId)->editProfile(); } bool Session::keyboardInputEnabled() { int keyboardInputEnabledCount = 0; QMapIterator i(m_terminals); while (i.hasNext()) if (i.next().value()->keyboardInputEnabled()) ++keyboardInputEnabledCount; return m_terminals.count() == keyboardInputEnabledCount; } void Session::setKeyboardInputEnabled(bool enabled) { QMapIterator i(m_terminals); while (i.hasNext()) setKeyboardInputEnabled(i.next().key(), enabled); } bool Session::keyboardInputEnabled(int terminalId) { if (!m_terminals.contains(terminalId)) return false; return m_terminals.value(terminalId)->keyboardInputEnabled(); } void Session::setKeyboardInputEnabled(int terminalId, bool enabled) { if (!m_terminals.contains(terminalId)) return; m_terminals.value(terminalId)->setKeyboardInputEnabled(enabled); } bool Session::hasTerminalsWithKeyboardInputEnabled() { QMapIterator i(m_terminals); while (i.hasNext()) if (i.next().value()->keyboardInputEnabled()) return true; return false; } bool Session::hasTerminalsWithKeyboardInputDisabled() { QMapIterator i(m_terminals); while (i.hasNext()) if (!i.next().value()->keyboardInputEnabled()) return true; return false; } bool Session::monitorActivityEnabled() { int monitorActivityEnabledCount = 0; QMapIterator i(m_terminals); while (i.hasNext()) if (i.next().value()->monitorActivityEnabled()) ++monitorActivityEnabledCount; return m_terminals.count() == monitorActivityEnabledCount; } void Session::setMonitorActivityEnabled(bool enabled) { QMapIterator i(m_terminals); while (i.hasNext()) setMonitorActivityEnabled(i.next().key(), enabled); } bool Session::monitorActivityEnabled(int terminalId) { if (!m_terminals.contains(terminalId)) return false; return m_terminals.value(terminalId)->monitorActivityEnabled(); } void Session::setMonitorActivityEnabled(int terminalId, bool enabled) { if (!m_terminals.contains(terminalId)) return; Terminal* terminal = m_terminals.value(terminalId); connect(terminal, SIGNAL(activityDetected(Terminal*)), this, SIGNAL(activityDetected(Terminal*)), Qt::UniqueConnection); terminal->setMonitorActivityEnabled(enabled); } bool Session::hasTerminalsWithMonitorActivityEnabled() { QMapIterator i(m_terminals); while (i.hasNext()) if (i.next().value()->monitorActivityEnabled()) return true; return false; } bool Session::hasTerminalsWithMonitorActivityDisabled() { QMapIterator i(m_terminals); while (i.hasNext()) if (!i.next().value()->monitorActivityEnabled()) return true; return false; } void Session::reconnectMonitorActivitySignals() { QMapIterator i(m_terminals); while (i.hasNext()) { i.next(); connect(i.value(), SIGNAL(activityDetected(Terminal*)), this, SIGNAL(activityDetected(Terminal*)), Qt::UniqueConnection); } } bool Session::monitorSilenceEnabled() { int monitorSilenceEnabledCount = 0; QMapIterator i(m_terminals); while (i.hasNext()) if (i.next().value()->monitorSilenceEnabled()) ++monitorSilenceEnabledCount; return m_terminals.count() == monitorSilenceEnabledCount; } void Session::setMonitorSilenceEnabled(bool enabled) { QMapIterator i(m_terminals); while (i.hasNext()) setMonitorSilenceEnabled(i.next().key(), enabled); } bool Session::monitorSilenceEnabled(int terminalId) { if (!m_terminals.contains(terminalId)) return false; return m_terminals.value(terminalId)->monitorSilenceEnabled(); } void Session::setMonitorSilenceEnabled(int terminalId, bool enabled) { if (!m_terminals.contains(terminalId)) return; m_terminals.value(terminalId)->setMonitorSilenceEnabled(enabled); } bool Session::hasTerminalsWithMonitorSilenceDisabled() { QMapIterator i(m_terminals); while (i.hasNext()) if (!i.next().value()->monitorSilenceEnabled()) return true; return false; } bool Session::hasTerminalsWithMonitorSilenceEnabled() { QMapIterator i(m_terminals); while (i.hasNext()) if (i.next().value()->monitorSilenceEnabled()) return true; return false; } diff --git a/app/session.h b/app/session.h index 6b6588a..797234b 100644 --- a/app/session.h +++ b/app/session.h @@ -1,139 +1,139 @@ /* Copyright (C) 2008-2009 by Eike Hein Copyright (C) 2009 by Juan Carlos Torres This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor appro- ved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program. If not, see http://www.gnu.org/licenses/. + along with this program. If not, see https://www.gnu.org/licenses/. */ #ifndef SESSION_H #define SESSION_H #include "splitter.h" #include #include class Terminal; class Session : public QObject { Q_OBJECT public: enum SessionType { Single, TwoHorizontal, TwoVertical, Quad }; enum GrowthDirection { Up, Right, Down, Left }; explicit Session(SessionType type = Single, QWidget* parent = 0); ~Session(); int id() { return m_sessionId; } const QString title() { return m_title; } QWidget* widget() { return m_baseSplitter; } int activeTerminalId() { return m_activeTerminalId; } const QString terminalIdList(); int terminalCount() { return m_terminals.count(); } bool hasTerminal(int terminalId); Terminal* getTerminal(int terminalId); bool closable() { return m_closable; } void setClosable(bool closable) { m_closable = closable; } bool keyboardInputEnabled(); void setKeyboardInputEnabled(bool enabled); bool keyboardInputEnabled(int terminalId); void setKeyboardInputEnabled(int terminalId, bool enabled); bool hasTerminalsWithKeyboardInputEnabled(); bool hasTerminalsWithKeyboardInputDisabled(); bool monitorActivityEnabled(); void setMonitorActivityEnabled(bool enabled); bool monitorActivityEnabled(int terminalId); void setMonitorActivityEnabled(int terminalId, bool enabled); bool hasTerminalsWithMonitorActivityEnabled(); bool hasTerminalsWithMonitorActivityDisabled(); bool monitorSilenceEnabled(); void setMonitorSilenceEnabled(bool enabled); bool monitorSilenceEnabled(int terminalId); void setMonitorSilenceEnabled(int terminalId, bool enabled); bool hasTerminalsWithMonitorSilenceEnabled(); bool hasTerminalsWithMonitorSilenceDisabled(); public Q_SLOTS: void closeTerminal(int terminalId = -1); void focusNextTerminal(); void focusPreviousTerminal(); int splitLeftRight(int terminalId = -1); int splitTopBottom(int terminalId = -1); int tryGrowTerminal(int terminalId, GrowthDirection direction, uint pixels); void runCommand(const QString& command, int terminalId = -1); void manageProfiles(); void editProfile(); void reconnectMonitorActivitySignals(); Q_SIGNALS: void titleChanged(const QString& title); void titleChanged(int sessionId, const QString& title); void terminalManuallyActivated(Terminal* terminal); void keyboardInputBlocked(Terminal* terminal); void activityDetected(Terminal* terminal); void silenceDetected(Terminal* terminal); void destroyed(int sessionId); private Q_SLOTS: void setActiveTerminal(int terminalId); void setTitle(int terminalId, const QString& title); void cleanup(int terminalId); void cleanup(); void prepareShutdown(); private: void setupSession(SessionType type); Terminal* addTerminal(QWidget* parent); int split(Terminal* terminal, Qt::Orientation orientation); static int m_availableSessionId; int m_sessionId; Splitter* m_baseSplitter; int m_activeTerminalId; QMap m_terminals; QString m_title; bool m_closable; }; #endif diff --git a/app/sessionstack.cpp b/app/sessionstack.cpp index 73ba02b..0945d22 100644 --- a/app/sessionstack.cpp +++ b/app/sessionstack.cpp @@ -1,671 +1,671 @@ /* Copyright (C) 2008-2014 by Eike Hein Copyright (C) 2009 by Juan Carlos Torres This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor appro- ved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program. If not, see http://www.gnu.org/licenses/. + along with this program. If not, see https://www.gnu.org/licenses/. */ #include "sessionstack.h" #include "settings.h" #include "terminal.h" #include "visualeventoverlay.h" #include #include #include #include #include static bool show_disallow_certain_dbus_methods_message = true; SessionStack::SessionStack(QWidget* parent) : QStackedWidget(parent) { QDBusConnection::sessionBus().registerObject(QStringLiteral("/yakuake/sessions"), this, QDBusConnection::ExportScriptableSlots); m_activeSessionId = -1; m_visualEventOverlay = new VisualEventOverlay(this); connect(this, SIGNAL(removeTerminalHighlight()), m_visualEventOverlay, SLOT(removeTerminalHighlight())); } SessionStack::~SessionStack() { } int SessionStack::addSessionImpl(Session::SessionType type) { Session* session = new Session(type, this); connect(session, SIGNAL(titleChanged(int,QString)), this, SIGNAL(titleChanged(int,QString))); connect(session, SIGNAL(terminalManuallyActivated(Terminal*)), this, SLOT(handleManualTerminalActivation(Terminal*))); connect(session, SIGNAL(keyboardInputBlocked(Terminal*)), m_visualEventOverlay, SLOT(indicateKeyboardInputBlocked(Terminal*))); connect(session, SIGNAL(activityDetected(Terminal*)), parentWidget(), SLOT(handleTerminalActivity(Terminal*))); connect(session, SIGNAL(silenceDetected(Terminal*)), parentWidget(), SLOT(handleTerminalSilence(Terminal*))); connect(parentWidget(), SIGNAL(windowClosed()), session, SLOT(reconnectMonitorActivitySignals())); connect(session, SIGNAL(destroyed(int)), this, SLOT(cleanup(int))); addWidget(session->widget()); m_sessions.insert(session->id(), session); if (Settings::dynamicTabTitles()) emit sessionAdded(session->id(), session->title()); else emit sessionAdded(session->id(), QString()); return session->id(); } int SessionStack::addSession() { return addSessionImpl(Session::Single); } int SessionStack::addSessionTwoHorizontal() { return addSessionImpl(Session::TwoHorizontal); } int SessionStack::addSessionTwoVertical() { return addSessionImpl(Session::TwoVertical); } int SessionStack::addSessionQuad() { return addSessionImpl(Session::Quad); } void SessionStack::raiseSession(int sessionId) { if (sessionId == -1 || !m_sessions.contains(sessionId)) return; Session* session = m_sessions.value(sessionId); if (!m_visualEventOverlay->isHidden()) m_visualEventOverlay->hide(); if (m_activeSessionId != -1 && m_sessions.contains(m_activeSessionId)) { Session* oldActiveSession = m_sessions.value(m_activeSessionId); disconnect(oldActiveSession, SLOT(closeTerminal())); disconnect(oldActiveSession, SLOT(focusPreviousTerminal())); disconnect(oldActiveSession, SLOT(focusNextTerminal())); disconnect(oldActiveSession, SLOT(manageProfiles())); disconnect(oldActiveSession, SIGNAL(titleChanged(QString)), this, SIGNAL(activeTitleChanged(QString))); oldActiveSession->reconnectMonitorActivitySignals(); } m_activeSessionId = sessionId; setCurrentWidget(session->widget()); if (session->widget()->focusWidget()) session->widget()->focusWidget()->setFocus(); if (session->hasTerminalsWithKeyboardInputDisabled()) m_visualEventOverlay->show(); connect(this, SIGNAL(closeTerminal()), session, SLOT(closeTerminal())); connect(this, SIGNAL(previousTerminal()), session, SLOT(focusPreviousTerminal())); connect(this, SIGNAL(nextTerminal()), session, SLOT(focusNextTerminal())); connect(this, SIGNAL(manageProfiles()), session, SLOT(manageProfiles())); connect(session, SIGNAL(titleChanged(QString)), this, SIGNAL(activeTitleChanged(QString))); emit sessionRaised(sessionId); emit activeTitleChanged(session->title()); } void SessionStack::removeSession(int sessionId) { if (sessionId == -1) sessionId = m_activeSessionId; if (sessionId == -1) return; if (!m_sessions.contains(sessionId)) return; if (queryClose(sessionId, QueryCloseSession)) m_sessions.value(sessionId)->deleteLater(); } void SessionStack::removeTerminal(int terminalId) { int sessionId = sessionIdForTerminalId(terminalId); if (terminalId == -1) { if (m_activeSessionId == -1) return; if (!m_sessions.contains(m_activeSessionId)) return; if (m_sessions.value(m_activeSessionId)->closable()) m_sessions.value(m_activeSessionId)->closeTerminal(); } else { if (m_sessions.value(sessionId)->closable()) m_sessions.value(sessionId)->closeTerminal(terminalId); } } void SessionStack::closeActiveTerminal(int sessionId) { if (sessionId == -1) sessionId = m_activeSessionId; if (sessionId == -1) return; if (!m_sessions.contains(sessionId)) return; if (queryClose(sessionId, QueryCloseTerminal)) m_sessions.value(sessionId)->closeTerminal(); } void SessionStack::cleanup(int sessionId) { if (sessionId == m_activeSessionId) m_activeSessionId = -1; m_sessions.remove(sessionId); emit sessionRemoved(sessionId); } int SessionStack::activeTerminalId() { if (!m_sessions.contains(m_activeSessionId)) return -1; return m_sessions.value(m_activeSessionId)->activeTerminalId(); } const QString SessionStack::sessionIdList() { QList keyList = m_sessions.uniqueKeys(); QStringList idList; QListIterator i(keyList); while (i.hasNext()) idList << QString::number(i.next()); return idList.join(QLatin1Char(',')); } const QString SessionStack::terminalIdList() { QStringList idList; QHashIterator it(m_sessions); while (it.hasNext()) { it.next(); idList << it.value()->terminalIdList(); } return idList.join(QLatin1Char(',')); } const QString SessionStack::terminalIdsForSessionId(int sessionId) { if (!m_sessions.contains(sessionId)) return QString::number(-1); return m_sessions.value(sessionId)->terminalIdList(); } int SessionStack::sessionIdForTerminalId(int terminalId) { int sessionId = -1; QHashIterator it(m_sessions); while (it.hasNext()) { it.next(); if (it.value()->hasTerminal(terminalId)) { sessionId = it.key(); break; } } return sessionId; } static void warnAboutDBus() { #if !defined(REMOVE_SENDTEXT_RUNCOMMAND_DBUS_METHODS) if (show_disallow_certain_dbus_methods_message) { KNotification::event(KNotification::Warning, QStringLiteral("Yakuake D-Bus Warning"), i18n("The D-Bus method runCommand was just used. There are security concerns about allowing these methods to be public. If desired, these methods can be changed to internal use only by re-compiling Yakuake.

    This warning will only show once for this Yakuake instance.

    ")); show_disallow_certain_dbus_methods_message = false; } #endif } void SessionStack::runCommand(const QString& command) { warnAboutDBus(); if (m_activeSessionId == -1) return; if (!m_sessions.contains(m_activeSessionId)) return; m_sessions.value(m_activeSessionId)->runCommand(command); } void SessionStack::runCommandInTerminal(int terminalId, const QString& command) { warnAboutDBus(); QHashIterator it(m_sessions); while (it.hasNext()) { it.next(); it.value()->runCommand(command, terminalId); } } bool SessionStack::isSessionClosable(int sessionId) { if (sessionId == -1) sessionId = m_activeSessionId; if (sessionId == -1) return false; if (!m_sessions.contains(sessionId)) return false; return m_sessions.value(sessionId)->closable(); } void SessionStack::setSessionClosable(int sessionId, bool closable) { if (sessionId == -1) sessionId = m_activeSessionId; if (sessionId == -1) return; if (!m_sessions.contains(sessionId)) return; m_sessions.value(sessionId)->setClosable(closable); } bool SessionStack::hasUnclosableSessions() const { QHashIterator it(m_sessions); while (it.hasNext()) { it.next(); if (!it.value()->closable()) return true; } return false; } bool SessionStack::isSessionKeyboardInputEnabled(int sessionId) { if (sessionId == -1) sessionId = m_activeSessionId; if (sessionId == -1) return false; if (!m_sessions.contains(sessionId)) return false; return m_sessions.value(sessionId)->keyboardInputEnabled(); } void SessionStack::setSessionKeyboardInputEnabled(int sessionId, bool enabled) { if (sessionId == -1) sessionId = m_activeSessionId; if (sessionId == -1) return; if (!m_sessions.contains(sessionId)) return; m_sessions.value(sessionId)->setKeyboardInputEnabled(enabled); if (sessionId == m_activeSessionId) { if (enabled) m_visualEventOverlay->hide(); else m_visualEventOverlay->show(); } } bool SessionStack::isTerminalKeyboardInputEnabled(int terminalId) { int sessionId = sessionIdForTerminalId(terminalId); if (sessionId == -1) return false; if (!m_sessions.contains(sessionId)) return false; return m_sessions.value(sessionId)->keyboardInputEnabled(terminalId); } void SessionStack::setTerminalKeyboardInputEnabled(int terminalId, bool enabled) { int sessionId = sessionIdForTerminalId(terminalId); if (sessionId == -1) return; if (!m_sessions.contains(sessionId)) return; m_sessions.value(sessionId)->setKeyboardInputEnabled(terminalId, enabled); if (sessionId == m_activeSessionId) { if (enabled) m_visualEventOverlay->hide(); else m_visualEventOverlay->show(); } } bool SessionStack::hasTerminalsWithKeyboardInputEnabled(int sessionId) { if (sessionId == -1) sessionId = m_activeSessionId; if (sessionId == -1) return false; if (!m_sessions.contains(sessionId)) return false; return m_sessions.value(sessionId)->hasTerminalsWithKeyboardInputEnabled(); } bool SessionStack::hasTerminalsWithKeyboardInputDisabled(int sessionId) { if (sessionId == -1) sessionId = m_activeSessionId; if (sessionId == -1) return false; if (!m_sessions.contains(sessionId)) return false; return m_sessions.value(sessionId)->hasTerminalsWithKeyboardInputDisabled(); } bool SessionStack::isSessionMonitorActivityEnabled(int sessionId) { if (sessionId == -1) sessionId = m_activeSessionId; if (sessionId == -1) return false; if (!m_sessions.contains(sessionId)) return false; return m_sessions.value(sessionId)->monitorActivityEnabled(); } void SessionStack::setSessionMonitorActivityEnabled(int sessionId, bool enabled) { if (sessionId == -1) sessionId = m_activeSessionId; if (sessionId == -1) return; if (!m_sessions.contains(sessionId)) return; m_sessions.value(sessionId)->setMonitorActivityEnabled(enabled); } bool SessionStack::isTerminalMonitorActivityEnabled(int terminalId) { int sessionId = sessionIdForTerminalId(terminalId); if (sessionId == -1) return false; if (!m_sessions.contains(sessionId)) return false; return m_sessions.value(sessionId)->monitorActivityEnabled(terminalId); } void SessionStack::setTerminalMonitorActivityEnabled(int terminalId, bool enabled) { int sessionId = sessionIdForTerminalId(terminalId); if (sessionId == -1) return; if (!m_sessions.contains(sessionId)) return; m_sessions.value(sessionId)->setMonitorActivityEnabled(terminalId, enabled); } bool SessionStack::hasTerminalsWithMonitorActivityEnabled(int sessionId) { if (sessionId == -1) sessionId = m_activeSessionId; if (sessionId == -1) return false; if (!m_sessions.contains(sessionId)) return false; return m_sessions.value(sessionId)->hasTerminalsWithMonitorActivityEnabled(); } bool SessionStack::hasTerminalsWithMonitorActivityDisabled(int sessionId) { if (sessionId == -1) sessionId = m_activeSessionId; if (sessionId == -1) return false; if (!m_sessions.contains(sessionId)) return false; return m_sessions.value(sessionId)->hasTerminalsWithMonitorActivityDisabled(); } bool SessionStack::isSessionMonitorSilenceEnabled(int sessionId) { if (sessionId == -1) sessionId = m_activeSessionId; if (sessionId == -1) return false; if (!m_sessions.contains(sessionId)) return false; return m_sessions.value(sessionId)->monitorSilenceEnabled(); } void SessionStack::setSessionMonitorSilenceEnabled(int sessionId, bool enabled) { if (sessionId == -1) sessionId = m_activeSessionId; if (sessionId == -1) return; if (!m_sessions.contains(sessionId)) return; m_sessions.value(sessionId)->setMonitorSilenceEnabled(enabled); } bool SessionStack::isTerminalMonitorSilenceEnabled(int terminalId) { int sessionId = sessionIdForTerminalId(terminalId); if (sessionId == -1) return false; if (!m_sessions.contains(sessionId)) return false; return m_sessions.value(sessionId)->monitorSilenceEnabled(terminalId); } void SessionStack::setTerminalMonitorSilenceEnabled(int terminalId, bool enabled) { int sessionId = sessionIdForTerminalId(terminalId); if (sessionId == -1) return; if (!m_sessions.contains(sessionId)) return; m_sessions.value(sessionId)->setMonitorSilenceEnabled(terminalId, enabled); } bool SessionStack::hasTerminalsWithMonitorSilenceEnabled(int sessionId) { if (sessionId == -1) sessionId = m_activeSessionId; if (sessionId == -1) return false; if (!m_sessions.contains(sessionId)) return false; return m_sessions.value(sessionId)->hasTerminalsWithMonitorSilenceEnabled(); } bool SessionStack::hasTerminalsWithMonitorSilenceDisabled(int sessionId) { if (sessionId == -1) sessionId = m_activeSessionId; if (sessionId == -1) return false; if (!m_sessions.contains(sessionId)) return false; return m_sessions.value(sessionId)->hasTerminalsWithMonitorSilenceDisabled(); } void SessionStack::editProfile(int sessionId) { if (sessionId == -1) sessionId = m_activeSessionId; if (sessionId == -1) return; if (!m_sessions.contains(sessionId)) return; m_sessions.value(sessionId)->editProfile(); } int SessionStack::splitSessionLeftRight(int sessionId) { if (sessionId == -1) return -1; if (!m_sessions.contains(sessionId)) return -1; return m_sessions.value(sessionId)->splitLeftRight(); } int SessionStack::splitSessionTopBottom(int sessionId) { if (sessionId == -1) return -1; if (!m_sessions.contains(sessionId)) return -1; return m_sessions.value(sessionId)->splitTopBottom(); } int SessionStack::splitTerminalLeftRight(int terminalId) { int sessionId = sessionIdForTerminalId(terminalId); if (sessionId == -1) return -1; return m_sessions.value(sessionId)->splitLeftRight(terminalId); } int SessionStack::splitTerminalTopBottom(int terminalId) { int sessionId = sessionIdForTerminalId(terminalId); if (sessionId == -1) return -1; return m_sessions.value(sessionId)->splitTopBottom(terminalId); } int SessionStack::tryGrowTerminalRight(int terminalId, uint pixels) { int sessionId = sessionIdForTerminalId(terminalId); if (sessionId == -1) return -1; return m_sessions.value(sessionId)->tryGrowTerminal(terminalId, Session::Right, pixels); } int SessionStack::tryGrowTerminalLeft(int terminalId, uint pixels) { int sessionId = sessionIdForTerminalId(terminalId); if (sessionId == -1) return -1; return m_sessions.value(sessionId)->tryGrowTerminal(terminalId, Session::Left, pixels); } int SessionStack::tryGrowTerminalTop(int terminalId, uint pixels) { int sessionId = sessionIdForTerminalId(terminalId); if (sessionId == -1) return -1; return m_sessions.value(sessionId)->tryGrowTerminal(terminalId, Session::Up, pixels); } int SessionStack::tryGrowTerminalBottom(int terminalId, uint pixels) { int sessionId = sessionIdForTerminalId(terminalId); if (sessionId == -1) return -1; return m_sessions.value(sessionId)->tryGrowTerminal(terminalId, Session::Down, pixels); } void SessionStack::emitTitles() { QString title; QHashIterator it(m_sessions); while (it.hasNext()) { it.next(); title = it.value()->title(); if (!title.isEmpty()) emit titleChanged(it.value()->id(), title); } } bool SessionStack::requiresVisualEventOverlay() { if (m_activeSessionId == -1) return false; if (!m_sessions.contains(m_activeSessionId)) return false; return m_sessions.value(m_activeSessionId)->hasTerminalsWithKeyboardInputDisabled(); } void SessionStack::handleTerminalHighlightRequest(int terminalId) { Terminal* terminal = 0; QHashIterator it(m_sessions); while (it.hasNext()) { it.next(); terminal = it.value()->getTerminal(terminalId); if (terminal && it.value()->id() == m_activeSessionId) { m_visualEventOverlay->highlightTerminal(terminal, true); break; } } } void SessionStack::showEvent(QShowEvent *event) { Q_UNUSED(event) if (m_activeSessionId == -1) return; if (!m_sessions.contains(m_activeSessionId)) return; Terminal *terminal = m_sessions.value(m_activeSessionId)->getTerminal(activeTerminalId()); if (terminal) { QWidget* terminalWidget = terminal->terminalWidget(); if (terminalWidget) terminalWidget->setFocus(); } } void SessionStack::handleManualTerminalActivation(Terminal* terminal) { if (!Settings::terminalHighlightOnManualActivation()) return; Session* session = qobject_cast(QObject::sender()); if (session->terminalCount() > 1) m_visualEventOverlay->highlightTerminal(terminal, false); } bool SessionStack::queryClose(int sessionId, QueryCloseType type) { if (!m_sessions.contains(sessionId)) return false; if (!m_sessions.value(sessionId)->closable()) { QString closeQuestionIntro = xi18nc("@info", "You have locked this session to prevent accidental closing of terminals."); QString closeQuestion; if (type == QueryCloseSession) closeQuestion = xi18nc("@info", "Are you sure you want to close this session?"); else if (type == QueryCloseTerminal) closeQuestion = xi18nc("@info", "Are you sure you want to close this terminal?"); int result = KMessageBox::warningContinueCancel(this, closeQuestionIntro + QStringLiteral("

    ") + closeQuestion, xi18nc("@title:window", "Really Close?"), KStandardGuiItem::close(), KStandardGuiItem::cancel()); if (result != KMessageBox::Continue) return false; } return true; } diff --git a/app/sessionstack.h b/app/sessionstack.h index bd8a8cd..95cd99c 100644 --- a/app/sessionstack.h +++ b/app/sessionstack.h @@ -1,161 +1,161 @@ /* Copyright (C) 2008-2014 by Eike Hein Copyright (C) 2009 by Juan Carlos Torres This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor appro- ved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program. If not, see http://www.gnu.org/licenses/. + along with this program. If not, see https://www.gnu.org/licenses/. */ #ifndef SESSIONSTACK_H #define SESSIONSTACK_H #include "session.h" #include #include #include class Session; class VisualEventOverlay; class SessionStack : public QStackedWidget { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "org.kde.yakuake") public: explicit SessionStack(QWidget* parent = 0); ~SessionStack(); void closeActiveTerminal(int sessionId = -1); void editProfile(int sessionId = -1); void emitTitles(); bool requiresVisualEventOverlay(); public Q_SLOTS: int addSessionImpl(Session::SessionType type = Session::Single); Q_SCRIPTABLE int addSession(); Q_SCRIPTABLE int addSessionTwoHorizontal(); Q_SCRIPTABLE int addSessionTwoVertical(); Q_SCRIPTABLE int addSessionQuad(); Q_SCRIPTABLE void raiseSession(int sessionId); Q_SCRIPTABLE void removeSession(int sessionId); Q_SCRIPTABLE void removeTerminal(int terminalId); Q_SCRIPTABLE int splitSessionLeftRight(int sessionId); Q_SCRIPTABLE int splitSessionTopBottom(int sessionId); Q_SCRIPTABLE int splitTerminalLeftRight(int terminalId); Q_SCRIPTABLE int splitTerminalTopBottom(int terminalId); Q_SCRIPTABLE int tryGrowTerminalRight(int terminalId, uint pixels = 10); Q_SCRIPTABLE int tryGrowTerminalLeft(int terminalId, uint pixels = 10); Q_SCRIPTABLE int tryGrowTerminalTop(int terminalId, uint pixels = 10); Q_SCRIPTABLE int tryGrowTerminalBottom(int terminalId, uint pixels = 10); Q_SCRIPTABLE int activeSessionId() { return m_activeSessionId; } Q_SCRIPTABLE int activeTerminalId(); Q_SCRIPTABLE const QString sessionIdList(); Q_SCRIPTABLE const QString terminalIdList(); Q_SCRIPTABLE const QString terminalIdsForSessionId(int sessionId); Q_SCRIPTABLE int sessionIdForTerminalId(int terminalId); #if defined(REMOVE_SENDTEXT_RUNCOMMAND_DBUS_METHODS) void runCommand(const QString& command); void runCommandInTerminal(int terminalId, const QString& command); #else Q_SCRIPTABLE void runCommand(const QString& command); Q_SCRIPTABLE void runCommandInTerminal(int terminalId, const QString& command); #endif Q_SCRIPTABLE bool isSessionClosable(int sessionId); Q_SCRIPTABLE void setSessionClosable(int sessionId, bool closable); Q_SCRIPTABLE bool hasUnclosableSessions() const; Q_SCRIPTABLE bool isSessionKeyboardInputEnabled(int sessionId); Q_SCRIPTABLE void setSessionKeyboardInputEnabled(int sessionId, bool enabled); Q_SCRIPTABLE bool isTerminalKeyboardInputEnabled(int terminalId); Q_SCRIPTABLE void setTerminalKeyboardInputEnabled(int terminalId, bool enabled); Q_SCRIPTABLE bool hasTerminalsWithKeyboardInputEnabled(int sessionId); Q_SCRIPTABLE bool hasTerminalsWithKeyboardInputDisabled(int sessionId); Q_SCRIPTABLE bool isSessionMonitorActivityEnabled(int sessionId); Q_SCRIPTABLE void setSessionMonitorActivityEnabled(int sessionId, bool enabled); Q_SCRIPTABLE bool isTerminalMonitorActivityEnabled(int terminalId); Q_SCRIPTABLE void setTerminalMonitorActivityEnabled(int terminalId, bool enabled); Q_SCRIPTABLE bool hasTerminalsWithMonitorActivityEnabled(int sessionId); Q_SCRIPTABLE bool hasTerminalsWithMonitorActivityDisabled(int sessionId); Q_SCRIPTABLE bool isSessionMonitorSilenceEnabled(int sessionId); Q_SCRIPTABLE void setSessionMonitorSilenceEnabled(int sessionId, bool enabled); Q_SCRIPTABLE bool isTerminalMonitorSilenceEnabled(int terminalId); Q_SCRIPTABLE void setTerminalMonitorSilenceEnabled(int terminalId, bool enabled); Q_SCRIPTABLE bool hasTerminalsWithMonitorSilenceEnabled(int sessionId); Q_SCRIPTABLE bool hasTerminalsWithMonitorSilenceDisabled(int sessionId); void handleTerminalHighlightRequest(int terminalId); Q_SIGNALS: void sessionAdded(int sessionId, const QString& title); void sessionRaised(int sessionId); void sessionRemoved(int sessionId); void activeTitleChanged(const QString& title); void titleChanged(int sessionId, const QString& title); void closeTerminal(); void previousTerminal(); void nextTerminal(); void manageProfiles(); void removeTerminalHighlight(); protected: virtual void showEvent(QShowEvent *event) override; private Q_SLOTS: void handleManualTerminalActivation(Terminal*); void cleanup(int sessionId); private: enum QueryCloseType { QueryCloseSession, QueryCloseTerminal }; bool queryClose(int sessionId, QueryCloseType type); VisualEventOverlay* m_visualEventOverlay; int m_activeSessionId; QHash m_sessions; }; #endif diff --git a/app/skin.cpp b/app/skin.cpp index 50545f9..7f067e5 100644 --- a/app/skin.cpp +++ b/app/skin.cpp @@ -1,287 +1,287 @@ /* Copyright (C) 2008-2014 by Eike Hein This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor appro- ved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program. If not, see http://www.gnu.org/licenses/. + along with this program. If not, see https://www.gnu.org/licenses/. */ #include "skin.h" #include #include #include #include #include Skin::Skin() { m_borderWidth = 0; } Skin::~Skin() { } bool Skin::load(const QString& name, bool kns) { QString dir = kns ? QStringLiteral("kns_skins/") : QStringLiteral("skins/"); QString titlePath = QStandardPaths::locate(QStandardPaths::DataLocation, dir + name + QStringLiteral("/title.skin")); QString tabPath = QStandardPaths::locate(QStandardPaths::DataLocation, dir + name + QStringLiteral("/tabs.skin")); if (!QFile::exists(titlePath) || !QFile::exists(tabPath)) return false; connect(KIconLoader::global(), SIGNAL(iconChanged(int)), this, SLOT(systemIconsChanged(int)), Qt::UniqueConnection); QString titleDir(QFileInfo(titlePath).absolutePath()); QString tabDir(QFileInfo(tabPath).absolutePath()); KConfig titleConfig(titlePath, KConfig::SimpleConfig); KConfig tabConfig(tabPath, KConfig::SimpleConfig); KConfigGroup border = titleConfig.group("Border"); m_borderColor = QColor(border.readEntry("red", 0), border.readEntry("green", 0), border.readEntry("blue", 0)); m_borderWidth = border.readEntry("width", 1); KConfigGroup titleBarBackground = titleConfig.group("Background"); m_titleBarBackgroundImage.load(titleDir + titleBarBackground.readEntry("back_image", "")); m_titleBarLeftCornerImage.load(titleDir + titleBarBackground.readEntry("left_corner", "")); m_titleBarRightCornerImage.load(titleDir + titleBarBackground.readEntry("right_corner", "")); KConfigGroup titleBarFocusButton = titleConfig.group("FocusButton"); m_titleBarFocusButtonPosition.setX(titleBarFocusButton.readEntry("x", 0)); m_titleBarFocusButtonPosition.setY(titleBarFocusButton.readEntry("y", 0)); m_titleBarFocusButtonStyleSheet = buttonStyleSheet(titleDir + titleBarFocusButton.readEntry("up_image", ""), titleDir + titleBarFocusButton.readEntry("over_image", ""), titleDir + titleBarFocusButton.readEntry("down_image", "")); m_titleBarFocusButtonAnchor = titleBarFocusButton.readEntry("anchor", "") == QLatin1String("left") ? Qt::AnchorLeft : Qt::AnchorRight; KConfigGroup titleBarMenuButton = titleConfig.group("ConfigButton"); m_titleBarMenuButtonPosition.setX(titleBarMenuButton.readEntry("x", 0)); m_titleBarMenuButtonPosition.setY(titleBarMenuButton.readEntry("y", 0)); m_titleBarMenuButtonStyleSheet = buttonStyleSheet(titleDir + titleBarMenuButton.readEntry("up_image", ""), titleDir + titleBarMenuButton.readEntry("over_image", ""), titleDir + titleBarMenuButton.readEntry("down_image", "")); m_titleBarMenuButtonAnchor = titleBarMenuButton.readEntry("anchor", "") == QLatin1String("left") ? Qt::AnchorLeft : Qt::AnchorRight; KConfigGroup titleBarQuitButton = titleConfig.group("QuitButton"); m_titleBarQuitButtonPosition.setX(titleBarQuitButton.readEntry("x", 0)); m_titleBarQuitButtonPosition.setY(titleBarQuitButton.readEntry("y", 0)); m_titleBarQuitButtonStyleSheet = buttonStyleSheet(titleDir + titleBarQuitButton.readEntry("up_image", ""), titleDir + titleBarQuitButton.readEntry("over_image", ""), titleDir + titleBarQuitButton.readEntry("down_image", "")); m_titleBarQuitButtonAnchor = titleBarQuitButton.readEntry("anchor", "") == QLatin1String("left") ? Qt::AnchorLeft : Qt::AnchorRight; KConfigGroup titleBarText = titleConfig.group("Text"); m_titleBarText = titleBarText.readEntry("text", ""); m_titleBarTextPosition.setX(titleBarText.readEntry("x", 0)); m_titleBarTextPosition.setY(titleBarText.readEntry("y", 0)); m_titleBarTextColor = QColor(titleBarText.readEntry("red", 0), titleBarText.readEntry("green", 0), titleBarText.readEntry("blue", 0)); m_titleBarTextBold = titleBarText.readEntry("bold", true); m_titleBarTextCentered = titleBarText.readEntry("centered", false); KConfigGroup tabBar = tabConfig.group("Tabs"); m_tabBarPosition.setX(tabBar.readEntry("x", 0)); m_tabBarPosition.setY(tabBar.readEntry("y", 0)); m_tabBarTextColor = QColor(tabBar.readEntry("red", 0), tabBar.readEntry("green", 0), tabBar.readEntry("blue", 0)); m_tabBarSeparatorImage.load(tabDir + tabBar.readEntry("separator_image", "")); m_tabBarUnselectedBackgroundImage.load(tabDir + tabBar.readEntry("unselected_background", "")); m_tabBarSelectedBackgroundImage.load(tabDir + tabBar.readEntry("selected_background", "")); m_tabBarUnselectedLeftCornerImage.load(tabDir + tabBar.readEntry("unselected_left_corner", "")); m_tabBarUnselectedRightCornerImage.load(tabDir + tabBar.readEntry("unselected_right_corner", "")); m_tabBarSelectedLeftCornerImage.load(tabDir + tabBar.readEntry("selected_left_corner", "")); m_tabBarSelectedRightCornerImage.load(tabDir + tabBar.readEntry("selected_right_corner", "")); m_tabBarSelectedTextBold = tabBar.readEntry("selected_text_bold", true); m_tabBarPreventClosingImage.load(tabDir + tabBar.readEntry("prevent_closing_image", "")); m_tabBarPreventClosingImagePosition.setX(tabBar.readEntry("prevent_closing_image_x", 0)); m_tabBarPreventClosingImagePosition.setY(tabBar.readEntry("prevent_closing_image_y", 0)); m_tabBarCompact = tabBar.readEntry("compact", false); KConfigGroup tabBarBackground = tabConfig.group("Background"); m_tabBarBackgroundImage.load(tabDir + tabBarBackground.readEntry("back_image", "")); m_tabBarLeftCornerImage.load(tabDir + tabBarBackground.readEntry("left_corner", "")); m_tabBarRightCornerImage.load(tabDir + tabBarBackground.readEntry("right_corner", "")); KConfigGroup tabBarNewTabButton = tabConfig.group("PlusButton"); m_tabBarNewTabButtonPosition.setX(tabBarNewTabButton.readEntry("x", 0)); m_tabBarNewTabButtonPosition.setY(tabBarNewTabButton.readEntry("y", 0)); m_tabBarNewTabButtonStyleSheet = buttonStyleSheet(tabDir + tabBarNewTabButton.readEntry("up_image", ""), tabDir + tabBarNewTabButton.readEntry("over_image", ""), tabDir + tabBarNewTabButton.readEntry("down_image", "")); m_tabBarNewTabButtonIsAtEndOfTabs = tabBarNewTabButton.readEntry("at_end_of_tabs", false); KConfigGroup tabBarCloseTabButton = tabConfig.group("MinusButton"); m_tabBarCloseTabButtonPosition.setX(tabBarCloseTabButton.readEntry("x", 0)); m_tabBarCloseTabButtonPosition.setY(tabBarCloseTabButton.readEntry("y", 0)); m_tabBarCloseTabButtonStyleSheet = buttonStyleSheet(tabDir + tabBarCloseTabButton.readEntry("up_image", ""), tabDir + tabBarCloseTabButton.readEntry("over_image", ""), tabDir + tabBarCloseTabButton.readEntry("down_image", "")); if (m_tabBarCompact) { if (m_tabBarNewTabButtonIsAtEndOfTabs) { m_tabBarLeft = m_tabBarPosition.x(); m_tabBarPosition.setX(0); } else { if (m_tabBarNewTabButtonPosition.x() < m_tabBarPosition.x()) m_tabBarLeft = m_tabBarNewTabButtonPosition.x(); else m_tabBarLeft = m_tabBarPosition.x(); m_tabBarPosition.setX(m_tabBarPosition.x() - m_tabBarLeft); m_tabBarNewTabButtonPosition.setX(m_tabBarNewTabButtonPosition.x() - m_tabBarLeft); } int closeButtonWidth = QPixmap(tabDir + tabBarCloseTabButton.readEntry("up_image", "")).width(); m_tabBarRight = m_tabBarCloseTabButtonPosition.x() - closeButtonWidth; m_tabBarCloseTabButtonPosition.setX(closeButtonWidth); } if (m_tabBarPreventClosingImage.isNull()) updateTabBarPreventClosingImageCache(); return true; } const QString Skin::buttonStyleSheet(const QString& up, const QString& over, const QString& down) { QString styleSheet; QString borderBit(QStringLiteral("border: none;")); QPixmap buttonImage(up); QString w(QString::number(buttonImage.width())); QString h(QString::number(buttonImage.height())); QString sizeBit(QStringLiteral("min-width:") + w + QStringLiteral("; min-height:") + h + QStringLiteral("; max-width:") + w + QStringLiteral("; max-height:") + h + QStringLiteral(";")); styleSheet.append(QStringLiteral("QPushButton {") + borderBit + QStringLiteral("image:url(") + up + QStringLiteral(");") + sizeBit + QStringLiteral("}")); styleSheet.append(QStringLiteral("QPushButton::hover {") + borderBit + QStringLiteral("image:url(") + over + QStringLiteral(");") + sizeBit + QStringLiteral("}")); styleSheet.append(QStringLiteral("QPushButton::pressed {") + borderBit + QStringLiteral("image:url(") + down + QStringLiteral(");") + sizeBit + QStringLiteral("}")); styleSheet.append(QStringLiteral("QPushButton::checked {") + borderBit + QStringLiteral("image:url(") + down + QStringLiteral(");") + sizeBit + QStringLiteral("}")); styleSheet.append(QStringLiteral("QPushButton::open {") + borderBit + QStringLiteral("image:url(") + down + QStringLiteral(");") + sizeBit + QStringLiteral("}")); styleSheet.append(QStringLiteral("QPushButton::menu-indicator { left: ") + w + QStringLiteral(" }")); styleSheet.append(QStringLiteral("QToolButton {") + borderBit + QStringLiteral("image:url(") + up + QStringLiteral(");") + sizeBit + QStringLiteral("}")); styleSheet.append(QStringLiteral("QToolButton::hover {") + borderBit + QStringLiteral("image:url(") + over + QStringLiteral(");") + sizeBit + QStringLiteral("}")); styleSheet.append(QStringLiteral("QToolButton::pressed {") + borderBit + QStringLiteral("image:url(") + down + QStringLiteral(");") + sizeBit + QStringLiteral("}")); styleSheet.append(QStringLiteral("QToolButton::checked {") + borderBit + QStringLiteral("image:url(") + down + QStringLiteral(");") + sizeBit + QStringLiteral("}")); styleSheet.append(QStringLiteral("QToolButton::open {") + borderBit + QStringLiteral("image:url(") + down + QStringLiteral(");") + sizeBit + QStringLiteral("}")); styleSheet.append(QStringLiteral("QToolButton::menu-indicator { left: ") + w + QStringLiteral(" }")); return styleSheet; } const QPixmap Skin::tabBarPreventClosingImage() { if (m_tabBarPreventClosingImage.isNull()) return m_tabBarPreventClosingImageCached; return m_tabBarPreventClosingImage; } void Skin::updateTabBarPreventClosingImageCache() { // Get the target image size from the tabBar height, acquired from // background image, minus (2 * y position) of the lock icon. int m_IconSize = m_tabBarBackgroundImage.height() - (2 * m_tabBarPreventClosingImagePosition.y()); // Get the system lock icon in a generous size. m_tabBarPreventClosingImageCached = QIcon::fromTheme(QStringLiteral("object-locked.png")).pixmap(48, 48); // Resize the image if it's too tall. if (m_IconSize < m_tabBarPreventClosingImageCached.height()) { m_tabBarPreventClosingImageCached = m_tabBarPreventClosingImageCached.scaled(m_IconSize, m_IconSize, Qt::KeepAspectRatio, Qt::SmoothTransformation); } } void Skin::systemIconsChanged(int group) { Q_UNUSED(group); if (m_tabBarPreventClosingImage.isNull()) { updateTabBarPreventClosingImageCache(); emit iconChanged(); } } diff --git a/app/skin.h b/app/skin.h index e82d77f..6b7f916 100644 --- a/app/skin.h +++ b/app/skin.h @@ -1,169 +1,169 @@ /* Copyright (C) 2008 by Eike Hein This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor appro- ved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program. If not, see http://www.gnu.org/licenses/. + along with this program. If not, see https://www.gnu.org/licenses/. */ #ifndef SKIN_H #define SKIN_H #include #include #include class Skin : public QObject { Q_OBJECT public: explicit Skin(); ~Skin(); bool load(const QString& name, bool kns = false); const QColor& borderColor() { return m_borderColor; } int borderWidth() { return m_borderWidth; } const QPixmap& titleBarBackgroundImage() { return m_titleBarBackgroundImage; } const QPixmap& titleBarLeftCornerImage() { return m_titleBarLeftCornerImage; } const QPixmap& titleBarRightCornerImage() { return m_titleBarRightCornerImage; } const QPoint& titleBarFocusButtonPosition() { return m_titleBarFocusButtonPosition; } const Qt::AnchorPoint& titleBarFocusButtonAnchor() { return m_titleBarFocusButtonAnchor; } const QString titleBarFocusButtonStyleSheet() { return m_titleBarFocusButtonStyleSheet; } const QPoint& titleBarMenuButtonPosition() { return m_titleBarMenuButtonPosition; } const Qt::AnchorPoint& titleBarMenuButtonAnchor() { return m_titleBarMenuButtonAnchor; } const QString titleBarMenuButtonStyleSheet() { return m_titleBarMenuButtonStyleSheet; } const QPoint& titleBarQuitButtonPosition() { return m_titleBarQuitButtonPosition; } const Qt::AnchorPoint& titleBarQuitButtonAnchor() { return m_titleBarQuitButtonAnchor; } const QString titleBarQuitButtonStyleSheet() { return m_titleBarQuitButtonStyleSheet; } const QString titleBarText() { return m_titleBarText; } const QPoint& titleBarTextPosition() { return m_titleBarTextPosition; } const QColor& titleBarTextColor() { return m_titleBarTextColor; } bool titleBarTextBold() { return m_titleBarTextBold; } bool titleBarTextCentered() { return m_titleBarTextCentered; } const QPoint& tabBarPosition() { return m_tabBarPosition; } const QColor& tabBarTextColor() { return m_tabBarTextColor; } const QPixmap& tabBarSeparatorImage() { return m_tabBarSeparatorImage; } const QPixmap& tabBarUnselectedBackgroundImage() { return m_tabBarUnselectedBackgroundImage; } const QPixmap& tabBarSelectedBackgroundImage() { return m_tabBarSelectedBackgroundImage; } const QPixmap& tabBarUnselectedLeftCornerImage() { return m_tabBarUnselectedLeftCornerImage; } const QPixmap& tabBarUnselectedRightCornerImage() { return m_tabBarUnselectedRightCornerImage; } const QPixmap& tabBarSelectedLeftCornerImage() { return m_tabBarSelectedLeftCornerImage; } const QPixmap& tabBarSelectedRightCornerImage() { return m_tabBarSelectedRightCornerImage; } bool tabBarSelectedTextBold() { return m_tabBarSelectedTextBold; } bool tabBarCompact() { return m_tabBarCompact; } int tabBarLeft() { return m_tabBarLeft; } int tabBarRight() { return m_tabBarRight; } const QPixmap tabBarPreventClosingImage(); const QPoint& tabBarPreventClosingImagePosition() { return m_tabBarPreventClosingImagePosition; } const QPixmap& tabBarBackgroundImage() { return m_tabBarBackgroundImage; } const QPixmap& tabBarLeftCornerImage() { return m_tabBarLeftCornerImage; } const QPixmap& tabBarRightCornerImage() { return m_tabBarRightCornerImage; } const QPoint& tabBarNewTabButtonPosition() { return m_tabBarNewTabButtonPosition; } const QString tabBarNewTabButtonStyleSheet() { return m_tabBarNewTabButtonStyleSheet; } bool tabBarNewTabButtonIsAtEndOfTabs() { return m_tabBarNewTabButtonIsAtEndOfTabs; } const QPoint& tabBarCloseTabButtonPosition() { return m_tabBarCloseTabButtonPosition; } const QString tabBarCloseTabButtonStyleSheet() { return m_tabBarCloseTabButtonStyleSheet; } Q_SIGNALS: void iconChanged(); private Q_SLOTS: void systemIconsChanged(int group); private: const QString buttonStyleSheet(const QString& up, const QString& over, const QString& down); void updateTabBarPreventClosingImageCache(); QColor m_borderColor; int m_borderWidth; QPixmap m_titleBarBackgroundImage; QPixmap m_titleBarLeftCornerImage; QPixmap m_titleBarRightCornerImage; QPoint m_titleBarFocusButtonPosition; Qt::AnchorPoint m_titleBarFocusButtonAnchor; QString m_titleBarFocusButtonStyleSheet; QPoint m_titleBarMenuButtonPosition; Qt::AnchorPoint m_titleBarMenuButtonAnchor; QString m_titleBarMenuButtonStyleSheet; QPoint m_titleBarQuitButtonPosition; Qt::AnchorPoint m_titleBarQuitButtonAnchor; QString m_titleBarQuitButtonStyleSheet; QString m_titleBarText; QPoint m_titleBarTextPosition; QColor m_titleBarTextColor; bool m_titleBarTextBold; bool m_titleBarTextCentered; QPoint m_tabBarPosition; QColor m_tabBarTextColor; QPixmap m_tabBarSeparatorImage; QPixmap m_tabBarUnselectedBackgroundImage; QPixmap m_tabBarSelectedBackgroundImage; QPixmap m_tabBarUnselectedLeftCornerImage; QPixmap m_tabBarUnselectedRightCornerImage; QPixmap m_tabBarSelectedLeftCornerImage; QPixmap m_tabBarSelectedRightCornerImage; bool m_tabBarSelectedTextBold; QPixmap m_tabBarPreventClosingImage; QPixmap m_tabBarPreventClosingImageCached; QPoint m_tabBarPreventClosingImagePosition; QPixmap m_tabBarBackgroundImage; QPixmap m_tabBarLeftCornerImage; QPixmap m_tabBarRightCornerImage; QPoint m_tabBarNewTabButtonPosition; QString m_tabBarNewTabButtonStyleSheet; bool m_tabBarNewTabButtonIsAtEndOfTabs; bool m_tabBarCompact; int m_tabBarLeft; int m_tabBarRight; QPoint m_tabBarCloseTabButtonPosition; QString m_tabBarCloseTabButtonStyleSheet; }; #endif diff --git a/app/splitter.cpp b/app/splitter.cpp index 9200e4d..a47fa15 100644 --- a/app/splitter.cpp +++ b/app/splitter.cpp @@ -1,53 +1,53 @@ /* Copyright (C) 2008-2009 by Eike Hein This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor appro- ved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program. If not, see http://www.gnu.org/licenses/. + along with this program. If not, see https://www.gnu.org/licenses/. */ #include "splitter.h" Splitter::Splitter(Qt::Orientation orientation, QWidget* parent) : QSplitter(orientation, parent) { setAutoFillBackground(true); setOpaqueResize(false); } Splitter::~Splitter() { } void Splitter::recursiveCleanup() { if (count() == 0) deleteLater(); else { QList list = findChildren(); QListIterator i(list); while (i.hasNext()) { Splitter* splitter = i.next(); if (splitter->parent() == this) splitter->recursiveCleanup(); } } } diff --git a/app/splitter.h b/app/splitter.h index 09f9f23..d621884 100644 --- a/app/splitter.h +++ b/app/splitter.h @@ -1,39 +1,39 @@ /* Copyright (C) 2008 by Eike Hein This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor appro- ved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program. If not, see http://www.gnu.org/licenses/. + along with this program. If not, see https://www.gnu.org/licenses/. */ #ifndef SPLITTER_H #define SPLITTER_H #include class Splitter: public QSplitter { Q_OBJECT public: explicit Splitter(Qt::Orientation orientation, QWidget* parent = 0); ~Splitter(); void recursiveCleanup(); }; #endif diff --git a/app/tabbar.cpp b/app/tabbar.cpp index 3c4bb0f..b76cd42 100644 --- a/app/tabbar.cpp +++ b/app/tabbar.cpp @@ -1,1095 +1,1095 @@ /* Copyright (C) 2008-2014 by Eike Hein Copyright (C) 2009 by Juan Carlos Torres This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor appro- ved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program. If not, see http://www.gnu.org/licenses/. + along with this program. If not, see https://www.gnu.org/licenses/. */ #include "tabbar.h" #include "mainwindow.h" #include "skin.h" #include "session.h" #include "sessionstack.h" #include "settings.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include TabBar::TabBar(MainWindow* mainWindow) : QWidget(mainWindow) { QDBusConnection::sessionBus().registerObject(QStringLiteral("/yakuake/tabs"), this, QDBusConnection::ExportScriptableSlots); setWhatsThis(xi18nc("@info:whatsthis", "Tab Bar" "The tab bar allows you to switch between sessions. You can double-click a tab to edit its label.")); m_selectedSessionId = -1; m_renamingSessionId = -1; m_mousePressed = false; m_mousePressedIndex = -1; m_dropIndicator = 0; m_mainWindow = mainWindow; m_skin = mainWindow->skin(); connect(m_skin, SIGNAL(iconChanged()), this, SLOT(repaint())); m_tabContextMenu = new QMenu(this); connect(m_tabContextMenu, SIGNAL(hovered(QAction*)), this, SLOT(contextMenuActionHovered(QAction*))); m_toggleKeyboardInputMenu = new QMenu(xi18nc("@title:menu", "Disable Keyboard Input"), this); m_toggleMonitorActivityMenu = new QMenu(xi18nc("@title:menu", "Monitor for Activity"), this); m_toggleMonitorSilenceMenu = new QMenu(xi18nc("@title:menu", "Monitor for Silence"), this); m_sessionMenu = new QMenu(this); connect(m_sessionMenu, SIGNAL(aboutToShow()), this, SLOT(readySessionMenu())); m_newTabButton = new QToolButton(this); m_newTabButton->setFocusPolicy(Qt::NoFocus); m_newTabButton->setMenu(m_sessionMenu); m_newTabButton->setPopupMode(QToolButton::DelayedPopup); m_newTabButton->setToolTip(xi18nc("@info:tooltip", "New Session")); m_newTabButton->setWhatsThis(xi18nc("@info:whatsthis", "Adds a new session. Press and hold to select session type from menu.")); connect(m_newTabButton, SIGNAL(clicked()), this, SIGNAL(newTabRequested())); m_closeTabButton = new QPushButton(this); m_closeTabButton->setFocusPolicy(Qt::NoFocus); m_closeTabButton->setToolTip(xi18nc("@info:tooltip", "Close Session")); m_closeTabButton->setWhatsThis(xi18nc("@info:whatsthis", "Closes the active session.")); connect(m_closeTabButton, SIGNAL(clicked()), this, SLOT(closeTabButtonClicked())); m_lineEdit = new QLineEdit(this); m_lineEdit->setFrame(false); m_lineEdit->setClearButtonEnabled(false); m_lineEdit->setAlignment(Qt::AlignHCenter); m_lineEdit->hide(); connect(m_lineEdit, SIGNAL(editingFinished()), m_lineEdit, SLOT(hide())); connect(m_lineEdit, SIGNAL(returnPressed()), this, SLOT(interactiveRenameDone())); setAcceptDrops(true); } TabBar::~TabBar() { } void TabBar::applySkin() { resize(width(), m_skin->tabBarBackgroundImage().height()); m_newTabButton->setStyleSheet(m_skin->tabBarNewTabButtonStyleSheet()); m_closeTabButton->setStyleSheet(m_skin->tabBarCloseTabButtonStyleSheet()); moveNewTabButton(); m_closeTabButton->move(width() - m_skin->tabBarCloseTabButtonPosition().x(), m_skin->tabBarCloseTabButtonPosition().y()); repaint(); } void TabBar::readyTabContextMenu() { if (m_tabContextMenu->isEmpty()) { m_tabContextMenu->addAction(m_mainWindow->actionCollection()->action(QStringLiteral("split-left-right"))); m_tabContextMenu->addAction(m_mainWindow->actionCollection()->action(QStringLiteral("split-top-bottom"))); m_tabContextMenu->addSeparator(); m_tabContextMenu->addAction(m_mainWindow->actionCollection()->action(QStringLiteral("edit-profile"))); m_tabContextMenu->addAction(m_mainWindow->actionCollection()->action(QStringLiteral("rename-session"))); m_tabContextMenu->addAction(m_mainWindow->actionCollection()->action(QStringLiteral("toggle-session-prevent-closing"))); m_tabContextMenu->addMenu(m_toggleKeyboardInputMenu); m_tabContextMenu->addMenu(m_toggleMonitorActivityMenu); m_tabContextMenu->addMenu(m_toggleMonitorSilenceMenu); m_tabContextMenu->addSeparator(); m_tabContextMenu->addAction(m_mainWindow->actionCollection()->action(QStringLiteral("move-session-left"))); m_tabContextMenu->addAction(m_mainWindow->actionCollection()->action(QStringLiteral("move-session-right"))); m_tabContextMenu->addSeparator(); m_tabContextMenu->addAction(m_mainWindow->actionCollection()->action(QStringLiteral("close-active-terminal"))); m_tabContextMenu->addAction(m_mainWindow->actionCollection()->action(QStringLiteral("close-session"))); } } void TabBar::readySessionMenu() { if (m_sessionMenu->isEmpty()) { m_sessionMenu->addAction(m_mainWindow->actionCollection()->action(QStringLiteral("new-session"))); m_sessionMenu->addSeparator(); m_sessionMenu->addAction(m_mainWindow->actionCollection()->action(QStringLiteral("new-session-two-horizontal"))); m_sessionMenu->addAction(m_mainWindow->actionCollection()->action(QStringLiteral("new-session-two-vertical"))); m_sessionMenu->addAction(m_mainWindow->actionCollection()->action(QStringLiteral("new-session-quad"))); } } void TabBar::updateMoveActions(int index) { if (index == -1) return; m_mainWindow->actionCollection()->action(QStringLiteral("move-session-left"))->setEnabled(false); m_mainWindow->actionCollection()->action(QStringLiteral("move-session-right"))->setEnabled(false); if (index != m_tabs.indexOf(m_tabs.first())) m_mainWindow->actionCollection()->action(QStringLiteral("move-session-left"))->setEnabled(true); if (index != m_tabs.indexOf(m_tabs.last())) m_mainWindow->actionCollection()->action(QStringLiteral("move-session-right"))->setEnabled(true); } void TabBar::updateToggleActions(int sessionId) { if (sessionId == -1) return; KActionCollection* actionCollection = m_mainWindow->actionCollection(); SessionStack* sessionStack = m_mainWindow->sessionStack(); QAction* toggleAction = actionCollection->action(QStringLiteral("toggle-session-prevent-closing")); toggleAction->setChecked(!sessionStack->isSessionClosable(sessionId)); toggleAction = actionCollection->action(QStringLiteral("toggle-session-keyboard-input")); toggleAction->setChecked(!sessionStack->hasTerminalsWithKeyboardInputEnabled(sessionId)); toggleAction = actionCollection->action(QStringLiteral("toggle-session-monitor-activity")); toggleAction->setChecked(!sessionStack->hasTerminalsWithMonitorActivityDisabled(sessionId)); toggleAction = actionCollection->action(QStringLiteral("toggle-session-monitor-silence")); toggleAction->setChecked(!sessionStack->hasTerminalsWithMonitorSilenceDisabled(sessionId)); } void TabBar::updateToggleKeyboardInputMenu(int sessionId) { if (!m_tabs.contains(sessionId)) return; QAction* toggleKeyboardInputAction = m_mainWindow->actionCollection()->action(QStringLiteral("toggle-session-keyboard-input")); QAction* anchor = m_toggleKeyboardInputMenu->menuAction(); SessionStack* sessionStack = m_mainWindow->sessionStack(); QStringList terminalIds = sessionStack->terminalIdsForSessionId(sessionId).split(QLatin1Char(','), QString::SkipEmptyParts); m_toggleKeyboardInputMenu->clear(); if (terminalIds.count() <= 1) { toggleKeyboardInputAction->setText(xi18nc("@action", "Disable Keyboard Input")); m_tabContextMenu->insertAction(anchor, toggleKeyboardInputAction); m_toggleKeyboardInputMenu->menuAction()->setVisible(false); } else { toggleKeyboardInputAction->setText(xi18nc("@action", "For This Session")); m_toggleKeyboardInputMenu->menuAction()->setVisible(true); m_tabContextMenu->removeAction(toggleKeyboardInputAction); m_toggleKeyboardInputMenu->addAction(toggleKeyboardInputAction); m_toggleKeyboardInputMenu->addSeparator(); int count = 0; QStringListIterator i(terminalIds); while (i.hasNext()) { int terminalId = i.next().toInt(); ++count; QAction* action = m_toggleKeyboardInputMenu->addAction(xi18nc("@action", "For Terminal %1", count)); action->setCheckable(true); action->setChecked(!sessionStack->isTerminalKeyboardInputEnabled(terminalId)); action->setData(terminalId); connect(action, SIGNAL(triggered(bool)), m_mainWindow, SLOT(handleToggleTerminalKeyboardInput(bool))); } } } void TabBar::updateToggleMonitorActivityMenu(int sessionId) { if (!m_tabs.contains(sessionId)) return; QAction* toggleMonitorActivityAction = m_mainWindow->actionCollection()->action(QStringLiteral("toggle-session-monitor-activity")); QAction* anchor = m_toggleMonitorActivityMenu->menuAction(); SessionStack* sessionStack = m_mainWindow->sessionStack(); QStringList terminalIds = sessionStack->terminalIdsForSessionId(sessionId).split(QLatin1Char(','), QString::SkipEmptyParts); m_toggleMonitorActivityMenu->clear(); if (terminalIds.count() <= 1) { toggleMonitorActivityAction->setText(xi18nc("@action", "Monitor for Activity")); m_tabContextMenu->insertAction(anchor, toggleMonitorActivityAction); m_toggleMonitorActivityMenu->menuAction()->setVisible(false); } else { toggleMonitorActivityAction->setText(xi18nc("@action", "In This Session")); m_toggleMonitorActivityMenu->menuAction()->setVisible(true); m_tabContextMenu->removeAction(toggleMonitorActivityAction); m_toggleMonitorActivityMenu->addAction(toggleMonitorActivityAction); m_toggleMonitorActivityMenu->addSeparator(); int count = 0; QStringListIterator i(terminalIds); while (i.hasNext()) { int terminalId = i.next().toInt(); ++count; QAction* action = m_toggleMonitorActivityMenu->addAction(xi18nc("@action", "In Terminal %1", count)); action->setCheckable(true); action->setChecked(sessionStack->isTerminalMonitorActivityEnabled(terminalId)); action->setData(terminalId); connect(action, SIGNAL(triggered(bool)), m_mainWindow, SLOT(handleToggleTerminalMonitorActivity(bool))); } } } void TabBar::updateToggleMonitorSilenceMenu(int sessionId) { if (!m_tabs.contains(sessionId)) return; QAction* toggleMonitorSilenceAction = m_mainWindow->actionCollection()->action(QStringLiteral("toggle-session-monitor-silence")); QAction* anchor = m_toggleMonitorSilenceMenu->menuAction(); SessionStack* sessionStack = m_mainWindow->sessionStack(); QStringList terminalIds = sessionStack->terminalIdsForSessionId(sessionId).split(QLatin1Char(','), QString::SkipEmptyParts); m_toggleMonitorSilenceMenu->clear(); if (terminalIds.count() <= 1) { toggleMonitorSilenceAction->setText(xi18nc("@action", "Monitor for Silence")); m_tabContextMenu->insertAction(anchor, toggleMonitorSilenceAction); m_toggleMonitorSilenceMenu->menuAction()->setVisible(false); } else { toggleMonitorSilenceAction->setText(xi18nc("@action", "In This Session")); m_toggleMonitorSilenceMenu->menuAction()->setVisible(true); m_tabContextMenu->removeAction(toggleMonitorSilenceAction); m_toggleMonitorSilenceMenu->addAction(toggleMonitorSilenceAction); m_toggleMonitorSilenceMenu->addSeparator(); int count = 0; QStringListIterator i(terminalIds); while (i.hasNext()) { int terminalId = i.next().toInt(); ++count; QAction* action = m_toggleMonitorSilenceMenu->addAction(xi18nc("@action", "In Terminal %1", count)); action->setCheckable(true); action->setChecked(sessionStack->isTerminalMonitorSilenceEnabled(terminalId)); action->setData(terminalId); connect(action, SIGNAL(triggered(bool)), m_mainWindow, SLOT(handleToggleTerminalMonitorSilence(bool))); } } } void TabBar::contextMenuActionHovered(QAction* action) { bool ok = false; if (!action->data().isNull()) { int terminalId = action->data().toInt(&ok); if (ok) emit requestTerminalHighlight(terminalId); } else if (!ok) emit requestRemoveTerminalHighlight(); } void TabBar::contextMenuEvent(QContextMenuEvent* event) { if (event->x() < 0) return; int index = tabAt(event->x()); if (index == -1) m_sessionMenu->exec(QCursor::pos()); else { readyTabContextMenu(); updateMoveActions(index); int sessionId = sessionAtTab(index); updateToggleActions(sessionId); updateToggleKeyboardInputMenu(sessionId); updateToggleMonitorActivityMenu(sessionId); updateToggleMonitorSilenceMenu(sessionId); m_mainWindow->setContextDependentActionsQuiet(true); QAction* action = m_tabContextMenu->exec(QCursor::pos()); emit tabContextMenuClosed(); if (action) { if (action->isCheckable()) m_mainWindow->handleContextDependentToggleAction(action->isChecked(), action, sessionId); else m_mainWindow->handleContextDependentAction(action, sessionId); } m_mainWindow->setContextDependentActionsQuiet(false); updateMoveActions(m_tabs.indexOf(m_selectedSessionId)); updateToggleActions(m_selectedSessionId); updateToggleKeyboardInputMenu(m_selectedSessionId); updateToggleMonitorActivityMenu(m_selectedSessionId); updateToggleMonitorSilenceMenu(m_selectedSessionId); } QWidget::contextMenuEvent(event); } void TabBar::resizeEvent(QResizeEvent* event) { moveNewTabButton(); m_closeTabButton->move(width() - m_skin->tabBarCloseTabButtonPosition().x(), m_skin->tabBarCloseTabButtonPosition().y()); QWidget::resizeEvent(event); } void TabBar::moveNewTabButton() { int newTabButtonX = m_skin->tabBarNewTabButtonPosition().x(); if (m_skin->tabBarNewTabButtonIsAtEndOfTabs()) { newTabButtonX += m_tabWidths.last(); } m_newTabButton->move(newTabButtonX, m_skin->tabBarNewTabButtonPosition().y()); } void TabBar::paintEvent(QPaintEvent*) { QPainter painter(this); painter.setPen(m_skin->tabBarTextColor()); int x = m_skin->tabBarPosition().x(); int y = m_skin->tabBarPosition().y(); m_tabWidths.clear(); QRect tabsClipRect(x, y, m_closeTabButton->x() - x, height() - y); painter.setClipRect(tabsClipRect); for (int index = 0; index < m_tabs.count(); ++index) { x = drawTab(x, y, index, painter); m_tabWidths << x; } const QPixmap& backgroundImage = m_skin->tabBarBackgroundImage(); const QPixmap& leftCornerImage = m_skin->tabBarLeftCornerImage(); const QPixmap& rightCornerImage = m_skin->tabBarRightCornerImage(); x = x > tabsClipRect.right() ? tabsClipRect.right() + 1 : x; QRegion backgroundClipRegion(rect()); backgroundClipRegion = backgroundClipRegion.subtracted(m_newTabButton->geometry()); backgroundClipRegion = backgroundClipRegion.subtracted(m_closeTabButton->geometry()); QRect tabsRect(m_skin->tabBarPosition().x(), y, x - m_skin->tabBarPosition().x(), height() - m_skin->tabBarPosition().y()); backgroundClipRegion = backgroundClipRegion.subtracted(tabsRect); painter.setClipRegion(backgroundClipRegion); painter.drawImage(0, 0, leftCornerImage.toImage()); QRect leftCornerImageRect(0, 0, leftCornerImage.width(), height()); backgroundClipRegion = backgroundClipRegion.subtracted(leftCornerImageRect); painter.drawImage(width() - rightCornerImage.width(), 0, rightCornerImage.toImage()); QRect rightCornerImageRect(width() - rightCornerImage.width(), 0, rightCornerImage.width(), height()); backgroundClipRegion = backgroundClipRegion.subtracted(rightCornerImageRect); painter.setClipRegion(backgroundClipRegion); painter.drawTiledPixmap(0, 0, width(), height(), backgroundImage); painter.end(); if (m_skin->tabBarNewTabButtonIsAtEndOfTabs()) { moveNewTabButton(); } } int TabBar::drawTab(int x, int y, int index, QPainter& painter) { QString title; int sessionId; bool selected; QFont font = QFontDatabase::systemFont(QFontDatabase::GeneralFont); int textWidth = 0; sessionId = m_tabs.at(index); selected = (sessionId == m_selectedSessionId); title = m_tabTitles[sessionId]; if (selected) { painter.drawPixmap(x, y, m_skin->tabBarSelectedLeftCornerImage()); x += m_skin->tabBarSelectedLeftCornerImage().width(); } else if (!m_skin->tabBarUnselectedLeftCornerImage().isNull()) { painter.drawPixmap(x, y, m_skin->tabBarUnselectedLeftCornerImage()); x += m_skin->tabBarUnselectedLeftCornerImage().width(); } else if (index != m_tabs.indexOf(m_selectedSessionId) + 1) { painter.drawPixmap(x, y, m_skin->tabBarSeparatorImage()); x += m_skin->tabBarSeparatorImage().width(); } if (selected) font.setBold(m_skin->tabBarSelectedTextBold()); else font.setBold(false); painter.setFont(font); QFontMetrics fontMetrics(font); textWidth = fontMetrics.width(title) + 10; // Draw the Prevent Closing image in the tab button. if (m_mainWindow->sessionStack()->isSessionClosable(sessionId) == false) { if (selected) painter.drawTiledPixmap(x, y, m_skin->tabBarPreventClosingImagePosition().x() + m_skin->tabBarPreventClosingImage().width(), height(), m_skin->tabBarSelectedBackgroundImage()); else painter.drawTiledPixmap(x, y, m_skin->tabBarPreventClosingImagePosition().x() + m_skin->tabBarPreventClosingImage().width(), height(), m_skin->tabBarUnselectedBackgroundImage()); painter.drawPixmap(x + m_skin->tabBarPreventClosingImagePosition().x(), m_skin->tabBarPreventClosingImagePosition().y(), m_skin->tabBarPreventClosingImage()); x += m_skin->tabBarPreventClosingImagePosition().x(); x += m_skin->tabBarPreventClosingImage().width(); } if (selected) painter.drawTiledPixmap(x, y, textWidth, height(), m_skin->tabBarSelectedBackgroundImage()); else painter.drawTiledPixmap(x, y, textWidth, height(), m_skin->tabBarUnselectedBackgroundImage()); painter.drawText(x, y, textWidth + 1, height() + 2, Qt::AlignHCenter | Qt::AlignVCenter, title); x += textWidth; if (selected) { painter.drawPixmap(x, m_skin->tabBarPosition().y(), m_skin->tabBarSelectedRightCornerImage()); x += m_skin->tabBarSelectedRightCornerImage().width(); } else if (!m_skin->tabBarUnselectedRightCornerImage().isNull()) { painter.drawPixmap(x, m_skin->tabBarPosition().y(), m_skin->tabBarUnselectedRightCornerImage()); x += m_skin->tabBarUnselectedRightCornerImage().width(); } else if (index != m_tabs.indexOf(m_selectedSessionId) - 1) { painter.drawPixmap(x, m_skin->tabBarPosition().y(), m_skin->tabBarSeparatorImage()); x += m_skin->tabBarSeparatorImage().width(); } return x; } int TabBar::tabAt(int x) { for (int index = 0; index < m_tabWidths.count(); ++index) { if (x > m_skin->tabBarPosition().x() && x < m_tabWidths.at(index)) return index; } return -1; } void TabBar::wheelEvent(QWheelEvent* event) { if (event->delta() < 0) selectNextTab(); else selectPreviousTab(); } void TabBar::keyPressEvent(QKeyEvent* event) { if (event->key() == Qt::Key_Escape && m_lineEdit->isVisible()) m_lineEdit->hide(); QWidget::keyPressEvent(event); } void TabBar::mousePressEvent(QMouseEvent* event) { if (QWhatsThis::inWhatsThisMode()) return; if (event->x() < m_skin->tabBarPosition().x()) return; int index = tabAt(event->x()); if (index == -1) return; if (event->button() == Qt::LeftButton || event->button() == Qt::MidButton) { m_startPos = event->pos(); if (index != m_tabs.indexOf(m_selectedSessionId) || event->button() == Qt::MidButton) { m_mousePressed = true; m_mousePressedIndex = index; } return; } QWidget::mousePressEvent(event); } void TabBar::mouseReleaseEvent(QMouseEvent* event) { if (QWhatsThis::inWhatsThisMode()) return; if (event->x() < m_skin->tabBarPosition().x()) return; int index = tabAt(event->x()); if (m_mousePressed && m_mousePressedIndex == index) { if (event->button() == Qt::LeftButton && index != m_tabs.indexOf(m_selectedSessionId)) emit tabSelected(m_tabs.at(index)); if (event->button() == Qt::MidButton) emit tabClosed(m_tabs.at(index)); } m_mousePressed = false; m_startPos.setX(0); m_startPos.setY(0); QWidget::mouseReleaseEvent(event); } void TabBar::mouseMoveEvent(QMouseEvent* event) { if (!m_startPos.isNull() && ((event->buttons() & Qt::LeftButton) || (event->buttons() & Qt::MidButton))) { int distance = (event->pos() - m_startPos).manhattanLength(); if (distance >= QApplication::startDragDistance()) { int index = tabAt(m_startPos.x()); if (index >= 0 && !m_lineEdit->isVisible()) startDrag(index); } } QWidget::mouseMoveEvent(event); } void TabBar::dragEnterEvent(QDragEnterEvent* event) { TabBar* eventSource = qobject_cast(event->source()); if (eventSource) { event->setDropAction(Qt::MoveAction); event->acceptProposedAction(); } else { drawDropIndicator(-1); event->ignore(); } return; } void TabBar::dragMoveEvent(QDragMoveEvent* event) { TabBar* eventSource = qobject_cast(event->source()); if (eventSource && event->pos().x() > m_skin->tabBarPosition().x() && event->pos().x() < m_closeTabButton->x()) { int index = dropIndex(event->pos()); if (index == -1) index = m_tabs.count(); drawDropIndicator(index, isSameTab(event)); event->setDropAction(Qt::MoveAction); event->accept(); } else { drawDropIndicator(-1); event->ignore(); } return; } void TabBar::dragLeaveEvent(QDragLeaveEvent* event) { drawDropIndicator(-1); event->ignore(); return; } void TabBar::dropEvent(QDropEvent* event) { drawDropIndicator(-1); int x = event->pos().x(); if (isSameTab(event) || x < m_skin->tabBarPosition().x() || x > m_closeTabButton->x()) event->ignore(); else { int targetIndex = dropIndex(event->pos()); int sourceSessionId = event->mimeData()->text().toInt(); int sourceIndex = m_tabs.indexOf(sourceSessionId); if (targetIndex == -1) targetIndex = m_tabs.count() - 1; else if (targetIndex < 0) targetIndex = 0; else if (sourceIndex < targetIndex) --targetIndex; m_tabs.move(sourceIndex, targetIndex); emit tabSelected(m_tabs.at(targetIndex)); event->accept(); } return; } void TabBar::mouseDoubleClickEvent(QMouseEvent* event) { if (QWhatsThis::inWhatsThisMode()) return; m_lineEdit->hide(); if (event->x() < 0) return; int index = tabAt(event->x()); if (event->button() == Qt::LeftButton) { if (event->x() <= m_tabWidths.last()) interactiveRename(m_tabs.at(index)); else if (event->x() > m_tabWidths.last()) emit newTabRequested(); } QWidget::mouseDoubleClickEvent(event); } void TabBar::leaveEvent(QEvent* event) { m_mousePressed = false; drawDropIndicator(-1); event->ignore(); QWidget::leaveEvent(event); } void TabBar::addTab(int sessionId, const QString& title) { m_tabs.append(sessionId); if (title.isEmpty()) m_tabTitles.insert(sessionId, standardTabTitle()); else m_tabTitles.insert(sessionId, title); emit tabSelected(sessionId); } void TabBar::removeTab(int sessionId) { if (sessionId == -1) sessionId = m_selectedSessionId; if (sessionId == -1) return; if (!m_tabs.contains(sessionId)) return; int index = m_tabs.indexOf(sessionId); if (m_lineEdit->isVisible() && sessionId == m_renamingSessionId) m_lineEdit->hide(); m_tabs.removeAt(index); m_tabTitles.remove(sessionId); if (m_tabs.isEmpty()) emit lastTabClosed(); else emit tabSelected(m_tabs.last()); } void TabBar::interactiveRename(int sessionId) { if (sessionId == -1) return; if (!m_tabs.contains(sessionId)) return; m_renamingSessionId = sessionId; int index = m_tabs.indexOf(sessionId); int x = index ? m_tabWidths.at(index - 1) : m_skin->tabBarPosition().x(); int y = m_skin->tabBarPosition().y(); int width = m_tabWidths.at(index) - x; m_lineEdit->setText(m_tabTitles[sessionId]); m_lineEdit->setGeometry(x-1, y-1, width+3, height()+2); m_lineEdit->selectAll(); m_lineEdit->setFocus(); m_lineEdit->show(); } void TabBar::interactiveRenameDone() { int sessionId = m_renamingSessionId; m_renamingSessionId = -1; setTabTitleInteractive(sessionId, m_lineEdit->text().trimmed()); } void TabBar::selectTab(int sessionId) { if (!m_tabs.contains(sessionId)) return; m_selectedSessionId = sessionId; updateMoveActions(m_tabs.indexOf(sessionId)); updateToggleActions(sessionId); repaint(); } void TabBar::selectNextTab() { int index = m_tabs.indexOf(m_selectedSessionId); int newSelectedSessionId = m_selectedSessionId; if (index == -1) return; else if (index == m_tabs.count() - 1) newSelectedSessionId = m_tabs.at(0); else newSelectedSessionId = m_tabs.at(index + 1); emit tabSelected(newSelectedSessionId); } void TabBar::selectPreviousTab() { int index = m_tabs.indexOf(m_selectedSessionId); int newSelectedSessionId = m_selectedSessionId; if (index == -1) return; else if (index == 0) newSelectedSessionId = m_tabs.at(m_tabs.count() - 1); else newSelectedSessionId = m_tabs.at(index - 1); emit tabSelected(newSelectedSessionId); } void TabBar::moveTabLeft(int sessionId) { if (sessionId == -1) sessionId = m_selectedSessionId; int index = m_tabs.indexOf(sessionId); if (index < 1) return; m_tabs.swap(index, index - 1); repaint(); updateMoveActions(index - 1); } void TabBar::moveTabRight(int sessionId) { if (sessionId == -1) sessionId = m_selectedSessionId; int index = m_tabs.indexOf(sessionId); if (index == -1 || index == m_tabs.count() - 1) return; m_tabs.swap(index, index + 1); repaint(); updateMoveActions(index + 1); } void TabBar::closeTabButtonClicked() { emit tabClosed(m_selectedSessionId); } QString TabBar::tabTitle(int sessionId) { if (m_tabTitles.contains(sessionId)) return m_tabTitles[sessionId]; else return QString(); } void TabBar::setTabTitle(int sessionId, const QString& newTitle) { if (sessionId == -1) return; if (!m_tabTitles.contains(sessionId)) return; if (m_tabTitlesSetInteractive.value(sessionId, false)) return; if (!newTitle.isEmpty()) m_tabTitles[sessionId] = newTitle; update(); } void TabBar::setTabTitleInteractive(int sessionId, const QString& newTitle) { if (sessionId == -1) return; if (!m_tabTitles.contains(sessionId)) return; if (!newTitle.isEmpty()) { m_tabTitles[sessionId] = newTitle; m_tabTitlesSetInteractive[sessionId] = true; } else m_tabTitlesSetInteractive.remove(sessionId); update(); } int TabBar::sessionAtTab(int index) { if (index < 0 || index > m_tabs.count() - 1) return -1; else return m_tabs.at(index); } QString TabBar::standardTabTitle() { QString newTitle = makeTabTitle(0); bool nameOk; int count = 0; do { nameOk = true; QHashIterator it(m_tabTitles); while (it.hasNext()) { it.next(); if (newTitle == it.value()) { nameOk = false; break; } } if (!nameOk) { count++; newTitle = makeTabTitle(count); } } while (!nameOk); return newTitle; } QString TabBar::makeTabTitle(int id) { if (id == 0) { return xi18nc("@title:tab", "Shell"); } else { return xi18nc("@title:tab", "Shell No. %1", id+1); } } void TabBar::startDrag(int index) { int sessionId = sessionAtTab(index); m_startPos.setX(0); m_startPos.setY(0); int x = index ? m_tabWidths.at(index - 1) : m_skin->tabBarPosition().x(); int tabWidth = m_tabWidths.at(index) - x; QString title = tabTitle(sessionId); QPixmap tab(tabWidth, height()); QColor fillColor(Settings::backgroundColor()); if (m_mainWindow->useTranslucency()) fillColor.setAlphaF(qreal(Settings::backgroundColorOpacity()) / 100); tab.fill(fillColor); QPainter painter(&tab); painter.initFrom(this); painter.setPen(m_skin->tabBarTextColor()); drawTab(0, 0, index, painter); painter.end(); QMimeData* mimeData = new QMimeData; mimeData->setText(QVariant(sessionId).toString()); QDrag* drag = new QDrag(this); drag->setMimeData(mimeData); drag->setPixmap(tab); drag->exec(Qt::MoveAction); return; } void TabBar::drawDropIndicator(int index, bool disabled) { const int arrowSize = 16; if (!m_dropIndicator) { m_dropIndicator = new QLabel(parentWidget()); m_dropIndicator->resize(arrowSize, arrowSize); } QIcon::Mode drawMode = disabled ? QIcon::Disabled : QIcon::Normal; m_dropIndicator->setPixmap(QIcon::fromTheme(QStringLiteral("arrow-down")).pixmap(arrowSize, arrowSize, drawMode)); if (index < 0) { m_dropIndicator->hide(); return; } int temp_index; if (index == m_tabs.count()) temp_index = index - 1; else temp_index = index; int x = temp_index ? m_tabWidths.at(temp_index - 1) : m_skin->tabBarPosition().x(); int tabWidth = m_tabWidths.at(temp_index) - x; int y = m_skin->tabBarPosition().y(); m_dropRect = QRect(x, y - height(), tabWidth, height() - y); QPoint pos; if (index < m_tabs.count()) pos = m_dropRect.topLeft(); else pos = m_dropRect.topRight(); pos.rx() -= arrowSize/2; m_dropIndicator->move(mapTo(parentWidget(),pos)); m_dropIndicator->show(); return; } int TabBar::dropIndex(const QPoint pos) { int index = tabAt(pos.x()); if (index < 0) return index; int x = index ? m_tabWidths.at(index - 1) : m_skin->tabBarPosition().x(); int tabWidth = m_tabWidths.at(index) - x; int y = m_skin->tabBarPosition().y(); m_dropRect = QRect(x, y - height(), tabWidth, height() - y); if ((pos.x()-m_dropRect.left()) > (m_dropRect.width()/2)) ++index; if (index == m_tabs.count()) return -1; return index; } bool TabBar::isSameTab(const QDropEvent* event) { int index = dropIndex(event->pos()); int sourceSessionId = event->mimeData()->text().toInt(); int sourceIndex = m_tabs.indexOf(sourceSessionId); bool isLastTab = (sourceIndex == m_tabs.count()-1) && (index == -1); if ((sourceIndex == index) || (sourceIndex == index-1) || isLastTab) return true; else return false; } diff --git a/app/tabbar.h b/app/tabbar.h index fc0cbaa..916705b 100644 --- a/app/tabbar.h +++ b/app/tabbar.h @@ -1,163 +1,163 @@ /* Copyright (C) 2008-2014 by Eike Hein Copyright (C) 2009 by Juan Carlos Torres This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor appro- ved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program. If not, see http://www.gnu.org/licenses/. + along with this program. If not, see https://www.gnu.org/licenses/. */ #ifndef TABBAR_H #define TABBAR_H #include #include #include class MainWindow; class Skin; class QLineEdit; class QMenu; class QPushButton; class QToolButton; class QLabel; class TabBar : public QWidget { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "org.kde.yakuake") public: explicit TabBar(MainWindow* mainWindow); ~TabBar(); void applySkin(); public Q_SLOTS: void addTab(int sessionId, const QString& title); void removeTab(int sessionId = -1); void interactiveRename(int sessionId); void selectTab(int sessionId); void selectNextTab(); void selectPreviousTab(); void moveTabLeft(int sessionId = -1); void moveTabRight(int sessionId = -1); Q_SCRIPTABLE QString tabTitle(int sessionId); Q_SCRIPTABLE void setTabTitle(int sessionId, const QString& newTitle); Q_SCRIPTABLE int sessionAtTab(int index); Q_SIGNALS: void newTabRequested(); void tabSelected(int sessionId); void tabClosed(int sessionId); void requestTerminalHighlight(int terminalId); void requestRemoveTerminalHighlight(); void tabContextMenuClosed(); void lastTabClosed(); protected: void resizeEvent(QResizeEvent*) override; void paintEvent(QPaintEvent*) override; void wheelEvent(QWheelEvent*) override; void keyPressEvent(QKeyEvent*) override; void mousePressEvent(QMouseEvent*) override; void mouseReleaseEvent(QMouseEvent*) override; void mouseMoveEvent(QMouseEvent*) override; void dragMoveEvent(QDragMoveEvent*) override; void dragEnterEvent(QDragEnterEvent*) override; void dragLeaveEvent(QDragLeaveEvent*) override; void dropEvent(QDropEvent*) override; void mouseDoubleClickEvent(QMouseEvent*) override; void contextMenuEvent(QContextMenuEvent*) override; void leaveEvent(QEvent*) override; void setTabTitleInteractive(int sessionId, const QString& newTitle); private Q_SLOTS: void readySessionMenu(); void contextMenuActionHovered(QAction* action); void closeTabButtonClicked(); void interactiveRenameDone(); private: QString standardTabTitle(); QString makeTabTitle(int number); int tabAt(int x); void readyTabContextMenu(); void updateMoveActions(int index); void updateToggleActions(int sessionId); void updateToggleKeyboardInputMenu(int sessionId = -1); void updateToggleMonitorSilenceMenu(int sessionId = -1); void updateToggleMonitorActivityMenu(int sessionId = -1); int drawTab(int x, int y, int index, QPainter& painter); void moveNewTabButton(); void startDrag(int index); void drawDropIndicator(int index, bool disabled = false); int dropIndex(const QPoint pos); bool isSameTab(const QDropEvent*); MainWindow* m_mainWindow; Skin* m_skin; QToolButton* m_newTabButton; QPushButton* m_closeTabButton; QMenu* m_tabContextMenu; QMenu* m_toggleKeyboardInputMenu; QMenu* m_toggleMonitorActivityMenu; QMenu* m_toggleMonitorSilenceMenu; QMenu* m_sessionMenu; QLineEdit* m_lineEdit; int m_renamingSessionId; QList m_tabs; QHash m_tabTitles; QHash m_tabTitlesSetInteractive; QList m_tabWidths; int m_selectedSessionId; bool m_mousePressed; int m_mousePressedIndex; QPoint m_startPos; QLabel* m_dropIndicator; QRect m_dropRect; }; #endif diff --git a/app/terminal.cpp b/app/terminal.cpp index d0a901e..353fee0 100644 --- a/app/terminal.cpp +++ b/app/terminal.cpp @@ -1,301 +1,301 @@ /* Copyright (C) 2008-2014 by Eike Hein This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor appro- ved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program. If not, see http://www.gnu.org/licenses/. + along with this program. If not, see https://www.gnu.org/licenses/. */ #include "terminal.h" #include "settings.h" #include #include #include #include #include #include #include #include #include #include #include #include #include int Terminal::m_availableTerminalId = 0; Terminal::Terminal(QWidget* parent) : QObject(parent) { m_terminalId = m_availableTerminalId; m_availableTerminalId++; m_keyboardInputEnabled = true; m_monitorActivityEnabled = false; m_monitorSilenceEnabled = false; m_part = NULL; m_terminalInterface = NULL; m_partWidget = NULL; m_terminalWidget = NULL; m_parentSplitter = parent; KPluginFactory* factory = 0; KService::Ptr service = KService::serviceByDesktopName(QStringLiteral("konsolepart")); if( service ) { factory = KPluginLoader(service->library()).factory(); } m_part = factory ? (factory->create(parent)) : 0; if (m_part) { connect(m_part, SIGNAL(setWindowCaption(QString)), this, SLOT(setTitle(QString))); connect(m_part, SIGNAL(overrideShortcut(QKeyEvent*,bool&)), this, SLOT(overrideShortcut(QKeyEvent*,bool&))); connect(m_part, SIGNAL(destroyed()), this, SLOT(deleteLater())); m_partWidget = m_part->widget(); m_terminalWidget = m_part->widget()->focusWidget(); if (m_terminalWidget) { m_terminalWidget->setFocusPolicy(Qt::WheelFocus); m_terminalWidget->installEventFilter(this); } disableOffendingPartActions(); m_terminalInterface = qobject_cast(m_part); } else displayKPartLoadError(); } Terminal::~Terminal() { emit destroyed(m_terminalId); } void Terminal::deletePart() { if (m_part) m_part->deleteLater(); else deleteLater(); } bool Terminal::eventFilter(QObject* /* watched */, QEvent* event) { if (event->type() == QEvent::FocusIn) { emit activated(m_terminalId); QFocusEvent* focusEvent = static_cast(event); if (focusEvent->reason() == Qt::MouseFocusReason || focusEvent->reason() == Qt::OtherFocusReason || focusEvent->reason() == Qt::BacktabFocusReason) emit manuallyActivated(this); } else if (event->type() == QEvent::MouseMove) { if (Settings::focusFollowsMouse() && m_terminalWidget && !m_terminalWidget->hasFocus()) m_terminalWidget->setFocus(); } if (!m_keyboardInputEnabled) { if (event->type() == QEvent::KeyPress) { QKeyEvent* keyEvent = static_cast(event); if (keyEvent->modifiers() == Qt::NoModifier) emit keyboardInputBlocked(this); return true; } else if (event->type() == QEvent::KeyRelease) return true; } return false; } void Terminal::displayKPartLoadError() { KColorScheme colorScheme(QPalette::Active); QColor warningColor = colorScheme.background(KColorScheme::NeutralBackground).color(); QColor warningColorLight = KColorScheme::shade(warningColor, KColorScheme::LightShade, 0.1); QString gradient = QStringLiteral("qlineargradient(x1:0, y1:0, x2:0, y2:1,stop: 0 %1, stop: 0.6 %1, stop: 1.0 %2)"); gradient = gradient.arg(warningColor.name()).arg(warningColorLight.name()); QString styleSheet = QStringLiteral("QLabel { background: %1; }"); QWidget* widget = new QWidget(m_parentSplitter); widget->setStyleSheet(styleSheet.arg(gradient)); m_partWidget = widget; m_terminalWidget = widget; m_terminalWidget->setFocusPolicy(Qt::WheelFocus); m_terminalWidget->installEventFilter(this); QLabel* label = new QLabel(widget); label->setMargin(10); label->setWordWrap(false); label->setAlignment(Qt::AlignLeft | Qt::AlignVCenter); label->setTextInteractionFlags(Qt::TextSelectableByMouse); label->setText(xi18nc("@info", "Yakuake was unable to load " "the Konsole component. " "A Konsole installation is " "required to use Yakuake.")); QLabel* icon = new QLabel(widget); icon->setMargin(10); icon->setPixmap(QIcon::fromTheme(QStringLiteral("dialog-warning")).pixmap(QSize(48, 48))); icon->setAlignment(Qt::AlignRight | Qt::AlignVCenter); QHBoxLayout* layout = new QHBoxLayout(widget); layout->addWidget(icon); layout->addWidget(label); layout->setSpacing(0); layout->setMargin(0); layout->setStretchFactor(icon, 1); layout->setStretchFactor(label,5); } void Terminal::disableOffendingPartActions() { // This is an unwelcome stop-gap that will be removed once we can // count on a Konsole version that doesn't pollute a KPart user's // shortcut "namespace". if (!m_part) return; KActionCollection* actionCollection = m_part->actionCollection(); if (actionCollection) { QAction* action = 0; action = actionCollection->action(QStringLiteral("next-view")); if (action) action->setEnabled(false); action = actionCollection->action(QStringLiteral("previous-view")); if (action) action->setEnabled(false); action = actionCollection->action(QStringLiteral("close-active-view")); if (action) action->setEnabled(false); action = actionCollection->action(QStringLiteral("split-view-left-right")); if (action) action->setEnabled(false); action = actionCollection->action(QStringLiteral("split-view-top-bottom")); if (action) action->setEnabled(false); action = actionCollection->action(QStringLiteral("rename-session")); if (action) action->setEnabled(false); action = actionCollection->action(QStringLiteral("enlarge-font")); if (action) action->setEnabled(false); action = actionCollection->action(QStringLiteral("shrink-font")); if (action) action->setEnabled(false); } } void Terminal::setTitle(const QString& title) { m_title = title; emit titleChanged(m_terminalId, m_title); } void Terminal::runCommand(const QString& command) { m_terminalInterface->sendInput(command + QStringLiteral("\n")); } void Terminal::manageProfiles() { QMetaObject::invokeMethod(m_part, "showManageProfilesDialog", Qt::QueuedConnection, Q_ARG(QWidget*, QApplication::activeWindow())); } void Terminal::editProfile() { QMetaObject::invokeMethod(m_part, "showEditCurrentProfileDialog", Qt::QueuedConnection, Q_ARG(QWidget*, QApplication::activeWindow())); } void Terminal::overrideShortcut(QKeyEvent* /* event */, bool& override) { override = false; } void Terminal::setMonitorActivityEnabled(bool enabled) { m_monitorActivityEnabled = enabled; if (enabled) { connect(m_part, SIGNAL(activityDetected()), this, SLOT(activityDetected()), Qt::UniqueConnection); QMetaObject::invokeMethod(m_part, "setMonitorActivityEnabled", Qt::QueuedConnection, Q_ARG(bool, true)); } else { disconnect(m_part, SIGNAL(activityDetected()), this, SLOT(activityDetected())); QMetaObject::invokeMethod(m_part, "setMonitorActivityEnabled", Qt::QueuedConnection, Q_ARG(bool, false)); } } void Terminal::setMonitorSilenceEnabled(bool enabled) { m_monitorSilenceEnabled = enabled; if (enabled) { connect(m_part, SIGNAL(silenceDetected()), this, SLOT(silenceDetected()), Qt::UniqueConnection); QMetaObject::invokeMethod(m_part, "setMonitorSilenceEnabled", Qt::QueuedConnection, Q_ARG(bool, true)); } else { disconnect(m_part, SIGNAL(silenceDetected()), this, SLOT(silenceDetected())); QMetaObject::invokeMethod(m_part, "setMonitorSilenceEnabled", Qt::QueuedConnection, Q_ARG(bool, false)); } } void Terminal::activityDetected() { emit activityDetected(this); } void Terminal::silenceDetected() { emit silenceDetected(this); } diff --git a/app/terminal.h b/app/terminal.h index b0a3f9b..874be29 100644 --- a/app/terminal.h +++ b/app/terminal.h @@ -1,110 +1,110 @@ /* Copyright (C) 2008-2014 by Eike Hein This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor appro- ved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program. If not, see http://www.gnu.org/licenses/. + along with this program. If not, see https://www.gnu.org/licenses/. */ #ifndef TERMINAL_H #define TERMINAL_H #include #include class QKeyEvent; class TerminalInterface; class Terminal : public QObject { Q_OBJECT public: explicit Terminal(QWidget* parent = 0); ~Terminal(); bool eventFilter(QObject* watched, QEvent* event) override; int id() { return m_terminalId; } const QString title() { return m_title; } QWidget* partWidget() { return m_partWidget; } QWidget* terminalWidget() { return m_terminalWidget; } QWidget* splitter() { return m_parentSplitter; } void setSplitter(QWidget* splitter) { m_parentSplitter = splitter; } void runCommand(const QString& command); void manageProfiles(); void editProfile(); bool keyboardInputEnabled() { return m_keyboardInputEnabled; } void setKeyboardInputEnabled(bool enabled) { m_keyboardInputEnabled = enabled; } bool monitorActivityEnabled() { return m_monitorActivityEnabled; } void setMonitorActivityEnabled(bool enabled); bool monitorSilenceEnabled() { return m_monitorSilenceEnabled; } void setMonitorSilenceEnabled(bool enabled); void deletePart(); Q_SIGNALS: void titleChanged(int terminalId, const QString& title); void activated(int terminalId); void manuallyActivated(Terminal* terminal); void keyboardInputBlocked(Terminal* terminal); void activityDetected(Terminal* terminal); void silenceDetected(Terminal* terminal); void destroyed(int terminalId); private Q_SLOTS: void setTitle(const QString& title); void overrideShortcut(QKeyEvent* event, bool& override); void silenceDetected(); void activityDetected(); private: void disableOffendingPartActions(); void displayKPartLoadError(); static int m_availableTerminalId; int m_terminalId; KParts::Part* m_part; TerminalInterface* m_terminalInterface; QWidget* m_partWidget; QPointer m_terminalWidget; QWidget* m_parentSplitter; QString m_title; bool m_keyboardInputEnabled; bool m_monitorActivityEnabled; bool m_monitorSilenceEnabled; }; #endif diff --git a/app/titlebar.cpp b/app/titlebar.cpp index cd7fa39..cf52be4 100644 --- a/app/titlebar.cpp +++ b/app/titlebar.cpp @@ -1,179 +1,179 @@ /* Copyright (C) 2008-2014 by Eike Hein This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor appro- ved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program. If not, see http://www.gnu.org/licenses/. + along with this program. If not, see https://www.gnu.org/licenses/. */ #include "titlebar.h" #include "mainwindow.h" #include "skin.h" #include #include #include #include #include #include #include TitleBar::TitleBar(MainWindow* mainWindow) : QWidget(mainWindow) { setWhatsThis(xi18nc("@info:whatsthis", "Title Bar" "The title bar displays the session title if available.")); setAttribute(Qt::WA_OpaquePaintEvent); m_mainWindow = mainWindow; m_skin = mainWindow->skin(); m_focusButton = new QPushButton(this); m_focusButton->setFocusPolicy(Qt::NoFocus); m_focusButton->setCheckable(true); m_focusButton->setToolTip(xi18nc("@info:tooltip", "Keep window open when it loses focus")); m_focusButton->setWhatsThis(xi18nc("@info:whatsthis", "If this is checked, the window will stay open when it loses focus.")); connect(m_focusButton, SIGNAL(toggled(bool)), mainWindow, SLOT(setKeepOpen(bool))); m_menuButton = new QPushButton(this); m_menuButton->setFocusPolicy(Qt::NoFocus); m_menuButton->setMenu(mainWindow->menu()); m_menuButton->setToolTip(xi18nc("@info:tooltip", "Open Menu")); m_menuButton->setWhatsThis(xi18nc("@info:whatsthis", "Opens the main menu.")); m_quitButton = new QPushButton(this); m_quitButton->setFocusPolicy(Qt::NoFocus); m_quitButton->setToolTip(xi18nc("@info:tooltip Quits the application", "Quit")); m_quitButton->setWhatsThis(xi18nc("@info:whatsthis", "Quits the application.")); connect(m_quitButton, SIGNAL(clicked()), mainWindow, SLOT(close())); } TitleBar::~TitleBar() { } void TitleBar::applySkin() { resize(width(), m_skin->titleBarBackgroundImage().height()); m_focusButton->setStyleSheet(m_skin->titleBarFocusButtonStyleSheet()); m_menuButton->setStyleSheet(m_skin->titleBarMenuButtonStyleSheet()); m_quitButton->setStyleSheet(m_skin->titleBarQuitButtonStyleSheet()); moveButtons(); repaint(); updateMask(); } void TitleBar::moveButtons() { if (m_skin->titleBarFocusButtonAnchor() == Qt::AnchorLeft) m_focusButton->move(m_skin->titleBarFocusButtonPosition().x(), m_skin->titleBarFocusButtonPosition().y()); else if (m_skin->titleBarFocusButtonAnchor() == Qt::AnchorRight) m_focusButton->move(width() - m_skin->titleBarFocusButtonPosition().x(), m_skin->titleBarFocusButtonPosition().y()); if (m_skin->titleBarMenuButtonAnchor() == Qt::AnchorLeft) m_menuButton->move(m_skin->titleBarMenuButtonPosition().x(), m_skin->titleBarMenuButtonPosition().y()); else if (m_skin->titleBarMenuButtonAnchor() == Qt::AnchorRight) m_menuButton->move(width() - m_skin->titleBarMenuButtonPosition().x(), m_skin->titleBarMenuButtonPosition().y()); if (m_skin->titleBarQuitButtonAnchor() == Qt::AnchorLeft) m_quitButton->move(m_skin->titleBarQuitButtonPosition().x(), m_skin->titleBarQuitButtonPosition().y()); else if (m_skin->titleBarQuitButtonAnchor() == Qt::AnchorRight) m_quitButton->move(width() - m_skin->titleBarQuitButtonPosition().x(), m_skin->titleBarQuitButtonPosition().y()); } void TitleBar::resizeEvent(QResizeEvent* event) { moveButtons(); updateMask(); QWidget::resizeEvent(event); } void TitleBar::paintEvent(QPaintEvent*) { QPainter painter(this); painter.setPen(m_skin->titleBarTextColor()); const QPixmap& backgroundImage = m_skin->titleBarBackgroundImage(); const QPixmap& leftCornerImage = m_skin->titleBarLeftCornerImage(); const QPixmap& rightCornerImage = m_skin->titleBarRightCornerImage(); painter.drawTiledPixmap(leftCornerImage.width(), 0, width() - leftCornerImage.width() - rightCornerImage.width(), height(), backgroundImage); painter.drawPixmap(0, 0, leftCornerImage); painter.drawPixmap(width() - rightCornerImage.width(), 0, rightCornerImage); QFont font = QFontDatabase::systemFont(QFontDatabase::TitleFont); font.setBold(m_skin->titleBarTextBold()); painter.setFont(font); const QString title = this->title(); if (m_skin->titleBarTextCentered() && width() > m_skin->titleBarTextPosition().x() + painter.fontMetrics().width(title) + m_focusButton->width() + m_quitButton->width() + m_menuButton->width()) painter.drawText(0, 0, width(), height(), Qt::AlignCenter, title); else painter.drawText(m_skin->titleBarTextPosition(), title); painter.end(); } void TitleBar::updateMask() { const QPixmap& leftCornerImage = m_skin->titleBarLeftCornerImage(); const QPixmap& rightCornerImage = m_skin->titleBarRightCornerImage(); QRegion leftCornerRegion = leftCornerImage.hasAlpha() ? QRegion(leftCornerImage.mask()) : QRegion(leftCornerImage.rect()); QRegion rightCornerRegion = rightCornerImage.hasAlpha() ? QRegion(rightCornerImage.mask()) : QRegion(rightCornerImage.rect()); QRegion mask = leftCornerRegion; mask += QRegion(QRect(0, 0, width() - leftCornerImage.width() - rightCornerImage.width(), height())).translated(leftCornerImage.width(), 0); mask += rightCornerRegion.translated(width() - rightCornerImage.width(), 0); setMask(mask); } void TitleBar::setFocusButtonState(bool checked) { m_focusButton->setChecked(checked); } QString TitleBar::title() { if (!m_skin->titleBarText().isEmpty() && !m_title.isEmpty()) return m_title + QStringLiteral(" - ") + m_skin->titleBarText(); else if (!m_skin->titleBarText().isEmpty() && m_title.isEmpty()) return m_skin->titleBarText(); else return m_title; } void TitleBar::setTitle(const QString& title) { m_title = title; repaint(); } diff --git a/app/titlebar.h b/app/titlebar.h index da21667..7e6e0a0 100644 --- a/app/titlebar.h +++ b/app/titlebar.h @@ -1,73 +1,73 @@ /* Copyright (C) 2008-2014 by Eike Hein This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor appro- ved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program. If not, see http://www.gnu.org/licenses/. + along with this program. If not, see https://www.gnu.org/licenses/. */ #ifndef TITLEBAR_H #define TITLEBAR_H #include class MainWindow; class Skin; class QPushButton; class TitleBar : public QWidget { Q_OBJECT public: explicit TitleBar(MainWindow* mainWindow); ~TitleBar(); void applySkin(); void updateMask(); QString title(); void setFocusButtonState(bool checked); public Q_SLOTS: void setTitle(const QString& title); protected: void resizeEvent(QResizeEvent*) override; void paintEvent(QPaintEvent*) override; private: void moveButtons(); MainWindow* m_mainWindow; Skin* m_skin; QPushButton* m_focusButton; QPushButton* m_menuButton; QPushButton* m_quitButton; QString m_title; }; #endif diff --git a/app/visualeventoverlay.cpp b/app/visualeventoverlay.cpp index 5ade76b..0ae21a1 100644 --- a/app/visualeventoverlay.cpp +++ b/app/visualeventoverlay.cpp @@ -1,261 +1,261 @@ /* Copyright (C) 2009 by Eike Hein This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor appro- ved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program. If not, see http://www.gnu.org/licenses/. + along with this program. If not, see https://www.gnu.org/licenses/. */ #include "visualeventoverlay.h" #include "sessionstack.h" #include "settings.h" #include "terminal.h" #include #include #include EventRect::EventRect(const QPoint& topLeft, const QPoint& bottomRight, EventType type, EventFlags flags) : QRect(topLeft, bottomRight) { m_eventType = type; m_eventFlags = flags; m_timeStamp.start(); } EventRect::~EventRect() { } bool EventRect::operator==(const EventRect& eventRect) const { if (m_eventType == eventRect.eventType() && eventRect.testFlag(EventRect::Singleton)) return true; if (m_eventType != eventRect.eventType()) return false; return ::operator==(*this, eventRect); } bool EventRect::operator<(const EventRect& eventRect) const { if (!testFlag(EventRect::Exclusive) && eventRect.testFlag(EventRect::Exclusive)) return false; if (m_eventType < eventRect.eventType()) return true; else if (m_timeStamp < eventRect.timeStamp()) return true; return false; } VisualEventOverlay::VisualEventOverlay(SessionStack* parent) : QWidget(parent) { m_sessionStack = parent; setAutoFillBackground(false); setAttribute(Qt::WA_TranslucentBackground, true); setFocusPolicy(Qt::NoFocus); setAttribute(Qt::WA_TransparentForMouseEvents, true); m_cleanupTimer = new QTimer(this); m_cleanupTimer->setSingleShot(true); connect(m_cleanupTimer, SIGNAL(timeout()), this, SLOT(cleanupOverlay())); m_cleanupTimerCeiling = 0; hide(); } VisualEventOverlay::~VisualEventOverlay() { } void VisualEventOverlay::highlightTerminal(Terminal* terminal, bool persistent) { if (!persistent && Settings::terminalHighlightDuration() == 0) return; if (isHidden()) show(); EventRect::EventFlags flags = EventRect::Singleton | EventRect::Exclusive; if (persistent) flags |= EventRect::Persistent; terminalEvent(terminal, EventRect::TerminalHighlight, flags); if (!persistent) scheduleCleanup(Settings::terminalHighlightDuration()); } void VisualEventOverlay::removeTerminalHighlight() { if (!m_eventRects.count()) return; QMutableListIterator i(m_eventRects); while (i.hasNext()) { if (i.next().eventType() == EventRect::TerminalHighlight) i.remove(); } if (m_sessionStack->requiresVisualEventOverlay()) update(); else hide(); } void VisualEventOverlay::indicateKeyboardInputBlocked(Terminal* terminal) { if (Settings::keyboardInputBlockIndicatorDuration() == 0) return; terminalEvent(terminal, EventRect::KeyboardInputBlocked); scheduleCleanup(Settings::keyboardInputBlockIndicatorDuration()); } void VisualEventOverlay::terminalEvent(Terminal* terminal, EventRect::EventType type, EventRect::EventFlags flags) { QRect partRect(terminal->partWidget()->rect()); const QWidget* partWidget = terminal->partWidget(); QPoint topLeft(partWidget->mapTo(parentWidget(), partRect.topLeft())); QPoint bottomRight(partWidget->mapTo(parentWidget(), partRect.bottomRight())); EventRect eventRect(topLeft, bottomRight, type, flags); m_eventRects.removeAll(eventRect); m_eventRects.append(eventRect); std::sort(m_eventRects.begin(), m_eventRects.end()); update(); } void VisualEventOverlay::paintEvent(QPaintEvent*) { if (!m_eventRects.count()) return; QPainter painter(this); m_time.start(); bool painted = false; QListIterator i(m_eventRects); while (i.hasNext()) { const EventRect& eventRect = i.next(); painted = false; if (eventRect.eventType() == EventRect::TerminalHighlight && (eventRect.timeStamp().msecsTo(m_time) <= Settings::terminalHighlightDuration() || eventRect.testFlag(EventRect::Persistent))) { KStatefulBrush terminalHighlightBrush(KColorScheme::View, KColorScheme::HoverColor); painter.setOpacity(Settings::terminalHighlightOpacity()); painter.fillRect(eventRect, terminalHighlightBrush.brush(this)); painted = true; } else if (eventRect.eventType() == EventRect::KeyboardInputBlocked && eventRect.timeStamp().msecsTo(m_time) <= Settings::keyboardInputBlockIndicatorDuration()) { painter.setOpacity(Settings::keyboardInputBlockIndicatorOpacity()); painter.fillRect(eventRect, Settings::keyboardInputBlockIndicatorColor()); painted = true; } if (painted && i.hasNext() && eventRect.testFlag(EventRect::Exclusive)) { if (!painter.hasClipping()) painter.setClipRect(rect()); painter.setClipRegion(painter.clipRegion().subtracted(eventRect)); } } } void VisualEventOverlay::showEvent(QShowEvent*) { resize(parentWidget()->rect().size()); raise(); } void VisualEventOverlay::hideEvent(QHideEvent*) { m_cleanupTimer->stop(); m_eventRects.clear(); } void VisualEventOverlay::scheduleCleanup(int in) { int left = m_cleanupTimerCeiling - m_cleanupTimerStarted.elapsed(); if (in > left) { m_cleanupTimerCeiling = in; m_cleanupTimerStarted.start(); m_cleanupTimer->start(in); } } void VisualEventOverlay::cleanupOverlay() { if (m_eventRects.count()) { m_time.start(); QMutableListIterator i(m_eventRects); while (i.hasNext()) { const EventRect& eventRect = i.next(); if (eventRect.eventType() == EventRect::TerminalHighlight && eventRect.timeStamp().msecsTo(m_time) >= Settings::terminalHighlightDuration() && !eventRect.testFlag(EventRect::Persistent)) { i.remove(); } else if (eventRect.eventType() == EventRect::KeyboardInputBlocked && eventRect.timeStamp().msecsTo(m_time) >= Settings::keyboardInputBlockIndicatorDuration()) { i.remove(); } } } if (m_sessionStack->requiresVisualEventOverlay()) update(); else hide(); } diff --git a/app/visualeventoverlay.h b/app/visualeventoverlay.h index 173087b..a33f8ae 100644 --- a/app/visualeventoverlay.h +++ b/app/visualeventoverlay.h @@ -1,118 +1,118 @@ /* Copyright (C) 2009 by Eike Hein This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor appro- ved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program. If not, see http://www.gnu.org/licenses/. + along with this program. If not, see https://www.gnu.org/licenses/. */ #ifndef VISUALEVENTOVERLAY_H #define VISUALEVENTOVERLAY_H #include #include #include class SessionStack; class Terminal; class QTimer; class EventRect : public QRect { public: enum EventType { TerminalHighlight, KeyboardInputBlocked }; enum EventFlag { NoFlags = 0x00000000, Singleton = 0x00000001, Exclusive = 0x00000002, Persistent = 0x00000004 }; Q_DECLARE_FLAGS(EventFlags, EventFlag) EventRect(const QPoint& topLeft, const QPoint& bottomRight, EventType type, EventFlags flags = EventRect::NoFlags); ~EventRect(); EventType eventType() const { return m_eventType; } const QTime& timeStamp() const { return m_timeStamp; } EventFlags eventFlags() const { return m_eventFlags; } void setEventFlags(EventFlags flags) { m_eventFlags = flags; } inline bool testFlag(EventFlag flag) const { return m_eventFlags & flag; } bool operator==(const EventRect& eventRect) const; bool operator<(const EventRect& eventRect) const; private: EventType m_eventType; EventFlags m_eventFlags; QTime m_timeStamp; }; Q_DECLARE_OPERATORS_FOR_FLAGS(EventRect::EventFlags) class VisualEventOverlay : public QWidget { Q_OBJECT public: explicit VisualEventOverlay(SessionStack* parent = 0); ~VisualEventOverlay(); public Q_SLOTS: void highlightTerminal(Terminal* terminal, bool persistent = false); void removeTerminalHighlight(); void indicateKeyboardInputBlocked(Terminal* terminal); void terminalEvent(Terminal* terminal, EventRect::EventType type, EventRect::EventFlags flags = EventRect::NoFlags); protected: void showEvent(QShowEvent*) override; void hideEvent(QHideEvent*) override; void paintEvent(QPaintEvent*) override; private Q_SLOTS: void cleanupOverlay(); private: void scheduleCleanup(int in); QList m_eventRects; QTimer* m_cleanupTimer; QTime m_cleanupTimerStarted; int m_cleanupTimerCeiling; QTime m_time; SessionStack* m_sessionStack; }; #endif diff --git a/data/org.kde.yakuake.appdata.xml b/data/org.kde.yakuake.appdata.xml index 5eecd89..7d5418e 100644 --- a/data/org.kde.yakuake.appdata.xml +++ b/data/org.kde.yakuake.appdata.xml @@ -1,357 +1,357 @@ org.kde.yakuake.desktop CC0-1.0 GPL-2.0+ Yakuake ياكواكي Yakuake Yakuake Yakuake Yakuake Yakuake Yakuake Yakuake Yakuake Yakuake Yakuake Yakuake Yakuake Yakuake Yakuake Yakuake Yakuake Yakuake Yakuake Yakuake Yakuake Yakuake Yakuake ਯਾਕੁਕੀ Yakuake Yakuake Yakuake Yakuake Yakuake Јакуаке Yakuake Јакуаке Yakuake Yakuake Yakuake Yakuake xxYakuakexx Yakuake Yakuake Drop-down Terminal طرفيّة منسدلة Terminal estenderexable Padajući terminal Terminal desplegable Terminal desplegable Vysouvací terminál Rul-ned terminal Aufklapp-Terminal Τερματικό καθοδικής κύλισης Drop-down Terminal Terminal desplegable Lahtikeritav terminal Goitik-behera zabaltzen den terminala Alas putoava pääte Terminal à liste déroulante Terminal despregábel Terminal Bentangturun Terminale a discesa 위에서 내려오는 터미널 Išskleidžiamasis terminalas Uitvouwbare terminalemulator Nedtrekksterminal ਲਟਕਦਾ ਟਰਮੀਨਲ Rozwijany terminal Terminal Acoplável Terminal suspenso Выпадающий терминал Rozbaľovací terminál Падајући терминал Padajući terminal Падајући терминал Padajući terminal Rullgardinsterminal Açılır Uçbirim Спадний термінал xxDrop-down Terminalxx 拉幕式终端 下拉式終端機

    Yakuake is a drop-down terminal emulator based on KDE Konsole technology.

    «ياكواكي» هو محاكي طرفيّة منسدل مبنيّ على تقنيّة «طرفيّة كدي».

    Yakuake ye un emulador de terminal estenderexable basáu na teunoloxía de KDE Konsole.

    El Yakuake és un emulador de terminal desplegable basat en la tecnologia del Konsole del KDE.

    El Yakuake és un emulador de terminal desplegable basat en la tecnologia del Konsole del KDE.

    Yakuake je vysouvací emulátor terminálu založený na technologii KDE Konsole.

    Yakuake er en rul-ned terminalemulator baseret på KDE Konsole-teknologi.

    Yakuake ist ein Aufklapp-Terminalemulator basierend auf der KDE-Konsole.

    Το Yakuake είναι ένας εξομοιωτής τερματικού καθοδικής κύλισης με βάση την τεχνολογία του KDE Konsole.

    Yakuake is a drop-down terminal emulator based on KDE Konsole technology.

    Yakuake en un emulador de terminal desplegable basado en la tecnología de Konsole de KDE.

    Yakuake on KDE Konsooli tehnoloogial põhinev lahtikeritav terminaliemulaator.

    Yakuake KDE Konsole teknologian oinarritzen den goitik-behera zabaltzen den terminal emulatzaile bat da.

    Yakuake on KDE:n Konsolen tekniikkaan perustuva alas putoava pääte.

    Yakuake est un émulateur de terminal à liste déroulante reposant sur la technologie de l'application Konsole de KDE.

    Yakuake é un emulador despregábel de terminal baseado en Konsole.

    Yakuake adalah emulator terminal bentangturun berdasarkan pada teknologi Konsole KDE

    Yakuake è un emulatore di terminale a discesa basato sulla tecnologia di Konsole di KDE

    Yakuake는 KDE Konsole을 기반으로 한 드롭다운 터미널 에뮬레이터jd3hduf.

    Yakuake yra nusileidžiantis terminalo emuliatorius paremtas KDE Konsole technologija.

    Yakuake is een uitvouwbare terminalemulator, gebaseerd op de technologie van KDE Konsole.

    Rullegardinbasert terminalemulator basert på KDE Konsoll-teknologien.

    Yakuake jest rozwijanym emulatorem terminala opartym na technologii KDE Konsole.

    O Yakuake é um emulador de terminal acoplável que se baseia na tecnologia do Konsole para o KDE.

    Yakuake é um emulador de terminal baseado na tecnologia do Konsole do KDE.

    Yakuake — выпадающий эмулятор терминала, основанный на библиотеке приложения Konsole от KDE.

    Yakuake je drop-down emulátor terminálu založený na KDE technológii Konsole.

    Јакуаке је падајући емулатор терминала над технологијом КДЕ‑ове Конзоле.

    Yakuake je padajući emulator terminala nad tehnologijom KDE‑ove Konsole.

    Јакуаке је падајући емулатор терминала над технологијом КДЕ‑ове Конзоле.

    Yakuake je padajući emulator terminala nad tehnologijom KDE‑ove Konsole.

    Yakuake är en nerfällbar terminalemulator baserad på teknologi från KDE:s Terminal.

    Yakuake KDE Konsole teknolojisi üzerine kurulu, yukarıdan aşağı açılabilen bir uç birim öykünücüsüdür.

    Yakuake — спадний замінник термінала, заснований на технології KDE Konsole.

    xxYakuake is a drop-down terminal emulator based on KDE Konsole technology.xx

    Yakuake 是一个基于 KDE Konsole 技术的拉幕式终端仿真器。

    Yakuake 是一套基於 KDE 的 Konsole 開發出來的下拉式終端模擬器。

    Features:

    الميزات:

    Carauterístiques:

    Svojstva:

    Característiques:

    Característiques:

    Vlastnosti:

    Funktioner:

    Funktionen:

    Λειτουργίες:

    Features:

    Funcionalidades:

    Omadused:

    Eginbideak:

    Ominaisuuksia:

    Fonctionnalités :

    Funcionalidades:

    Characteristicas:

    Fitur:

    Funzionalità:

    기능:

    Ypatybės:

    Mogelijkheden:

    Funksjonar:

    ਫੀਚਰ:

    Możliwości:

    Funcionalidades:

    Funcionalidades:

    Возможности:

    Funkcie:

    Могућности:

    Mogućnosti:

    Могућности:

    Mogućnosti:

    Funktioner:

    Özellikler:

    Можливості:

    xxFeatures:xx

    功能:

    功能:

    • Smoothly rolls down from the top of your screen
    • ينسدل انسيابيًّا من أعلى شاشتك
    • Estenderéxase dende lo cimero de la pantalla
    • S'estén suaument des de la part superior de la pantalla
    • S'estén suaument des de la part superior de la pantalla
    • Ruller blødt ned fra toppen af skærmen
    • Rollt geschmeidig von der oberen Kante des Bildschirms herab
    • Ομαλή καθοδική κύλιση από την κορυφή της οθόνης σας
    • Smoothly rolls down from the top of your screen
    • Se despliega suavemente desde la parte superior de la pantalla
    • Sujuv lahtikerimine ekraani ülaservast
    • Zure pantaila goitik leunki beherantz biraka agertzen da
    • Rullaa sulavasti alas näytön ylälaidasta
    • Se déroule progressivement depuis le haut de votre écran
    • Desprégase suavemente desde a parte superior da pantalla.
    • Membentang turun secara lembut dari atas layarmu
    • Si srotola dolcemente dalla parte alta del tuo schermo
    • 화면 위에서 부드럽게 펼쳐져 내려오기
    • Sklandžiai nusileidžia žemyn nuo jūsų ekrano viršaus
    • Rolt langzaam naar beneden vanaf de bovenkant van uw scherm
    • Rullar jamt ned frå toppen av skjermen
    • Płynnie rozwija się z góry ekranu
    • Desenrola-se suavemente a partir do topo do seu ecrã
    • Desenrola-se suavemente a partir do topo da sua tela
    • Плавное появление из верхней части экрана;
    • Plynulé rolovanie dolu z vrchu obrazovky
    • глатко одмотавање са врха екрана
    • glatko odmotavanje sa vrha ekrana
    • глатко одмотавање са врха екрана
    • glatko odmotavanje sa vrha ekrana
    • Rullar ner mjukt från skärmens överkant
    • Ekranınızın üst bölümünden düzgünce aşağı iner
    • Плавно розгортається з верхньої частини вашого екрана.
    • xxSmoothly rolls down from the top of your screenxx
    • 平滑从屏幕顶端下滑
    • 平滑地從螢幕頂端拉下來
    • Tabbed interface
    • واجهة ألسنة
    • Interfaz per llingüetes
    • Interfície amb pestanyes
    • Interfície amb pestanyes
    • Grænseflade med faneblade
    • Bedienungsoberfläche mit Unterfenstern
    • Περιβάλλον χρήσης με καρτέλες
    • Tabbed interface
    • Interfaz con pestañas
    • Kaartidega liides
    • Fitxa bidezko interfazea
    • Välilehdet
    • Interface à onglets
    • Interface con lapelas
    • Antarmuka bertab
    • Interfaccia a schede
    • 탭 인터페이스
    • Kortelės sąsajoje
    • Interface met tabbladen
    • Brukargrensesnitt med faner
    • ਟੈਬਾਂ ਵਾਲਾ ਇੰਟਰਫੇਸ
    • Interfejs z kartami
    • Interface por páginas
    • Interface por abas
    • Поддержка вкладок;
    • Kartové rozhranie
    • сучеље са језичцима
    • sučelje sa jezičcima
    • сучеље са језичцима
    • sučelje sa jezičcima
    • Flikgränssnitt
    • Sekmeli arayüz
    • Інтерфейс із вкладками.
    • xxTabbed interfacexx
    • 标签式界面
    • 分頁介面
    • Configurable dimensions and animation speed
    • Dimensiones y velocidá d'animaciones configurables
    • Les dimensions i la velocitat de l'animació es poden configurar
    • Les dimensions i la velocitat de l'animació es poden configurar
    • Dimensioner og animationshastighed kan indstilles
    • Benutzerdefinierte Abmessungen und Animationsgeschwindigkeit
    • Διαμορφώσιμες διαστάσεις και ταχύτητα με εφέ κίνησης
    • Configurable dimensions and animation speed
    • Se pueden configurar las dimensiones y la velocidad de animación
    • Seadistatavad mõõtmed ja animatsiooni kiirus
    • Dimentsioak eta animazio-abiadura konfiguragarriak
    • Muutettavissa olevat mitat ja animointinopeus
    • Dimensions et vitesse d'animation configurables
    • Tanto as súas dimensións como a velocidade da animación de despregamento poden configurarse.
    • Kecepatan animasi dan dimensi yang dapat dikonfigurasi
    • Dimensioni e velocità dell'animazione configurabili
    • 크기와 애니메이션 속도 설정
    • Konfigūruojami dydi ir animacijos greitis
    • Instelbare afmetingen en animatiesnelheid
    • Tilpassbar storleik og animasjonsfart
    • Ustawialny rozmiar i szybkość animacji
    • Dimensões e velocidade de animação configuráveis
    • Dimensões e velocidade de animação configuráveis
    • Настраиваемые размеры и скорость анимации;
    • Nastaviteľné rozmery a rýchlosť animácií
    • подесиве димензије и брзина анимације
    • podesive dimenzije i brzina animacije
    • подесиве димензије и брзина анимације
    • podesive dimenzije i brzina animacije
    • Anpassningsbara dimensioner och animeringshastighet
    • Yapılandırılabilir boyutlar ve canlandırma hızı
    • Можливість налаштовування розмірів та швидкості анімації.
    • xxConfigurable dimensions and animation speedxx
    • 可配置位置和动画速度
    • 設定動畫速度與大小
    • Skinnable
    • L'aspeutu ye personalizable
    • Es pot canviar l'aparença
    • Es pot canviar l'aparença
    • Kan bruge skins
    • Anpassung der Oberfläche über Skin/Design
    • Διαμορφώσιμα θέματα
    • Skinnable
    • Admite el uso de pieles
    • Nahkade kasutamine
    • «Azal» aldagarriak onartzen ditu
    • Vaihdettava teema
    • Thèmes disponibles
    • O seu aspecto pode modificarse con temas.
    • Dapat di-skin
    • Aspetto personalizzabile
    • 스킨
    • Keičiama išvaizda
    • Te voorzien van een skin
    • Støtte for fleire grafiske tema
    • Możliwość używania skórek
    • Visual personalizável
    • Visual personalizável
    • Поддержка стилей оформления;
    • Skinovateľné
    • подршка за маске
    • podrška za maske
    • подршка за маске
    • podrška za maske
    • Kan använda skal
    • Katlanabilir
    • Можливість використання різних обрамлень («шкірок»).
    • xxSkinnablexx
    • 可更换主题
    • Skinnable
    • Sophisticated D-Bus interface
    • Interfaz de D-Bus sofisticada
    • Interfície de D-Bus sofisticada
    • Interfície de D-Bus sofisticada
    • Sofistikeret D-Bus-grænseflade
    • Hoch entwickelte D-Bus-Schnittstelle
    • Εκλεπτυσμένη D-Bus διεπαφή
    • Sophisticated D-Bus interface
    • Interfaz D-Bus sofisticado
    • Võimas D-Busi liides
    • D-Bus interfaze sofistikatua
    • Kehittynyt D-Bus-liittymä
    • Interface « D-Bus » sophistiquée
    • Sofisticada interface de D-Bus
    • Antarmuka D-Bus yang njlimet
    • Interfaccia D-Bus sofisticata
    • D-Bus 인터페이스
    • Įmantri D-Bus sąsaja
    • Intelligent D-Bus-interface
    • Avansert D-Bus-grensesnitt
    • Zaawansowany interfejs D-Bus
    • Interface de D-Bus sofisticada
    • Interface D-Bus sofisticada
    • Поддержка интерфейса D-Bus.
    • Sofistikované rozhranie
    • свеобухватно д‑бус сучеље
    • sveobuhvatno D‑Bus sučelje
    • свеобухватно д‑бус сучеље
    • sveobuhvatno D‑Bus sučelje
    • Sofistikerat D-Bus gränssnitt
    • Gelişmiş D-Bus arayüzü
    • Продуманий інтерфейс D-Bus.
    • xxSophisticated D-Bus interfacexx
    • 复杂的 D-Bus 接口
    • 複雜的 D-Bus 介面
    https://kde.org/applications/system/org.kde.yakuake https://bugs.kde.org/enter_bug.cgi?format=guided&product=yakuake - http://kde.org/images/screenshots/yakuake.png + https://kde.org/images/screenshots/yakuake.png KDE yakuake